| /* |
| * Copyright © Microsoft Corporation |
| * |
| * Permission is hereby granted, free of charge, to any person obtaining a |
| * copy of this software and associated documentation files (the "Software"), |
| * to deal in the Software without restriction, including without limitation |
| * the rights to use, copy, modify, merge, publish, distribute, sublicense, |
| * and/or sell copies of the Software, and to permit persons to whom the |
| * Software is furnished to do so, subject to the following conditions: |
| * |
| * The above copyright notice and this permission notice (including the next |
| * paragraph) shall be included in all copies or substantial portions of the |
| * Software. |
| * |
| * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
| * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
| * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
| * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
| * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS |
| * IN THE SOFTWARE. |
| */ |
| |
| #include "dzn_private.h" |
| |
| #include "vk_alloc.h" |
| #include "vk_debug_report.h" |
| #include "vk_format.h" |
| #include "vk_util.h" |
| |
| void |
| dzn_image_align_extent(const struct dzn_image *image, |
| VkExtent3D *extent) |
| { |
| enum pipe_format pfmt = vk_format_to_pipe_format(image->vk.format); |
| uint32_t blkw = util_format_get_blockwidth(pfmt); |
| uint32_t blkh = util_format_get_blockheight(pfmt); |
| uint32_t blkd = util_format_get_blockdepth(pfmt); |
| |
| assert(util_is_power_of_two_nonzero(blkw) && |
| util_is_power_of_two_nonzero(blkh) && |
| util_is_power_of_two_nonzero(blkh)); |
| |
| extent->width = ALIGN_POT(extent->width, blkw); |
| extent->height = ALIGN_POT(extent->height, blkh); |
| extent->depth = ALIGN_POT(extent->depth, blkd); |
| } |
| |
| static void |
| dzn_image_destroy(struct dzn_image *image, |
| const VkAllocationCallbacks *pAllocator) |
| { |
| if (!image) |
| return; |
| |
| struct dzn_device *device = container_of(image->vk.base.device, struct dzn_device, vk); |
| |
| if (image->res) |
| ID3D12Resource_Release(image->res); |
| |
| vk_image_finish(&image->vk); |
| vk_free2(&device->vk.alloc, pAllocator, image); |
| } |
| |
| static VkResult |
| dzn_image_create(struct dzn_device *device, |
| const VkImageCreateInfo *pCreateInfo, |
| const VkAllocationCallbacks *pAllocator, |
| VkImage *out) |
| { |
| struct dzn_image *image = |
| vk_zalloc2(&device->vk.alloc, pAllocator, sizeof(*image), 8, |
| VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); |
| struct dzn_physical_device *pdev = |
| container_of(device->vk.physical, struct dzn_physical_device, vk); |
| |
| if (!image) |
| return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY); |
| |
| #if 0 |
| VkExternalMemoryHandleTypeFlags supported = |
| VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT | |
| VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT | |
| VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_BIT | |
| VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_KMT_BIT | |
| VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_HEAP_BIT | |
| VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_RESOURCE_BIT; |
| |
| if (create_info && (create_info->handleTypes & supported)) |
| return dzn_image_from_external(device, pCreateInfo, create_info, |
| pAllocator, pImage); |
| #endif |
| |
| #if 0 |
| const VkImageSwapchainCreateInfoKHR *swapchain_info = (const VkImageSwapchainCreateInfoKHR *) |
| vk_find_struct_const(pCreateInfo->pNext, IMAGE_SWAPCHAIN_CREATE_INFO_KHR); |
| if (swapchain_info && swapchain_info->swapchain != VK_NULL_HANDLE) |
| return dzn_image_from_swapchain(device, pCreateInfo, swapchain_info, |
| pAllocator, pImage); |
| #endif |
| |
| vk_image_init(&device->vk, &image->vk, pCreateInfo); |
| enum pipe_format pfmt = vk_format_to_pipe_format(image->vk.format); |
| |
| if (image->vk.tiling == VK_IMAGE_TILING_LINEAR) { |
| /* Treat linear images as buffers: they should only be used as copy |
| * src/dest, and CopyTextureResource() can manipulate buffers. |
| * We only support linear tiling on things strictly required by the spec: |
| * "Images created with tiling equal to VK_IMAGE_TILING_LINEAR have |
| * further restrictions on their limits and capabilities compared to |
| * images created with tiling equal to VK_IMAGE_TILING_OPTIMAL. Creation |
| * of images with tiling VK_IMAGE_TILING_LINEAR may not be supported |
| * unless other parameters meet all of the constraints: |
| * - imageType is VK_IMAGE_TYPE_2D |
| * - format is not a depth/stencil format |
| * - mipLevels is 1 |
| * - arrayLayers is 1 |
| * - samples is VK_SAMPLE_COUNT_1_BIT |
| * - usage only includes VK_IMAGE_USAGE_TRANSFER_SRC_BIT and/or VK_IMAGE_USAGE_TRANSFER_DST_BIT |
| * " |
| */ |
| assert(!vk_format_is_depth_or_stencil(pCreateInfo->format)); |
| assert(pCreateInfo->mipLevels == 1); |
| assert(pCreateInfo->arrayLayers == 1); |
| assert(pCreateInfo->samples == 1); |
| assert(pCreateInfo->imageType != VK_IMAGE_TYPE_3D); |
| assert(!(pCreateInfo->usage & ~(VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT))); |
| D3D12_RESOURCE_DESC tmp_desc = { |
| .Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D, |
| .Alignment = D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT, |
| .Width = ALIGN(image->vk.extent.width, util_format_get_blockwidth(pfmt)), |
| .Height = (UINT)ALIGN(image->vk.extent.height, util_format_get_blockheight(pfmt)), |
| .DepthOrArraySize = 1, |
| .MipLevels = 1, |
| .Format = |
| dzn_image_get_dxgi_format(pCreateInfo->format, pCreateInfo->usage, 0), |
| .SampleDesc = { .Count = 1, .Quality = 0 }, |
| .Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN, |
| .Flags = D3D12_RESOURCE_FLAG_NONE |
| }; |
| D3D12_PLACED_SUBRESOURCE_FOOTPRINT footprint; |
| uint64_t size = 0; |
| ID3D12Device1_GetCopyableFootprints(device->dev, &tmp_desc, 0, 1, 0, &footprint, NULL, NULL, &size); |
| |
| image->linear.row_stride = footprint.Footprint.RowPitch; |
| image->linear.size = size; |
| size *= pCreateInfo->arrayLayers; |
| image->desc.Format = DXGI_FORMAT_UNKNOWN; |
| image->desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER; |
| image->desc.Width = size; |
| image->desc.Height = 1; |
| image->desc.DepthOrArraySize = 1; |
| image->desc.MipLevels = 1; |
| image->desc.SampleDesc.Count = 1; |
| image->desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR; |
| } else { |
| image->desc.Format = |
| dzn_image_get_dxgi_format(pCreateInfo->format, |
| pCreateInfo->usage & ~VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, |
| 0), |
| image->desc.Dimension = (D3D12_RESOURCE_DIMENSION)(D3D12_RESOURCE_DIMENSION_TEXTURE1D + pCreateInfo->imageType); |
| image->desc.Width = image->vk.extent.width; |
| image->desc.Height = image->vk.extent.height; |
| image->desc.DepthOrArraySize = pCreateInfo->imageType == VK_IMAGE_TYPE_3D ? |
| image->vk.extent.depth : |
| pCreateInfo->arrayLayers; |
| image->desc.MipLevels = pCreateInfo->mipLevels; |
| image->desc.SampleDesc.Count = pCreateInfo->samples; |
| image->desc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN; |
| } |
| |
| if (image->vk.create_flags & VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT) |
| image->desc.Format = dzn_get_typeless_dxgi_format(image->desc.Format); |
| |
| if (image->desc.SampleDesc.Count > 1) |
| image->desc.Alignment = D3D12_DEFAULT_MSAA_RESOURCE_PLACEMENT_ALIGNMENT; |
| else |
| image->desc.Alignment = D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT; |
| |
| image->desc.SampleDesc.Quality = 0; |
| |
| image->desc.Flags = D3D12_RESOURCE_FLAG_NONE; |
| |
| if (image->vk.usage & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT) |
| image->desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET; |
| |
| if (image->vk.usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) { |
| image->desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL; |
| |
| if (!(image->vk.usage & (VK_IMAGE_USAGE_SAMPLED_BIT | |
| VK_IMAGE_USAGE_STORAGE_BIT | |
| VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT | |
| VK_IMAGE_USAGE_TRANSFER_SRC_BIT))) |
| image->desc.Flags |= D3D12_RESOURCE_FLAG_DENY_SHADER_RESOURCE; |
| } |
| |
| /* Images with TRANSFER_DST can be cleared or passed as a blit/resolve |
| * destination. Both operations require the RT or DS cap flags. |
| */ |
| if ((image->vk.usage & VK_IMAGE_USAGE_TRANSFER_DST_BIT) && |
| image->vk.tiling == VK_IMAGE_TILING_OPTIMAL) { |
| |
| D3D12_FEATURE_DATA_FORMAT_SUPPORT dfmt_info = |
| dzn_physical_device_get_format_support(pdev, pCreateInfo->format); |
| if (dfmt_info.Support1 & D3D12_FORMAT_SUPPORT1_RENDER_TARGET) { |
| image->desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET; |
| } else if (dfmt_info.Support1 & D3D12_FORMAT_SUPPORT1_DEPTH_STENCIL) { |
| image->desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL; |
| } else if (dfmt_info.Support1 & D3D12_FORMAT_SUPPORT1_TYPED_UNORDERED_ACCESS_VIEW) { |
| image->desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS; |
| } |
| } |
| |
| if (image->vk.usage & VK_IMAGE_USAGE_STORAGE_BIT) |
| image->desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS; |
| |
| *out = dzn_image_to_handle(image); |
| return VK_SUCCESS; |
| } |
| |
| DXGI_FORMAT |
| dzn_image_get_dxgi_format(VkFormat format, |
| VkImageUsageFlags usage, |
| VkImageAspectFlags aspects) |
| { |
| enum pipe_format pfmt = vk_format_to_pipe_format(format); |
| |
| if (!vk_format_is_depth_or_stencil(format)) |
| return dzn_pipe_to_dxgi_format(pfmt); |
| |
| switch (pfmt) { |
| case PIPE_FORMAT_Z16_UNORM: |
| return usage == VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT ? |
| DXGI_FORMAT_D16_UNORM : DXGI_FORMAT_R16_UNORM; |
| |
| case PIPE_FORMAT_Z32_FLOAT: |
| return usage == VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT ? |
| DXGI_FORMAT_D32_FLOAT : DXGI_FORMAT_R32_FLOAT; |
| |
| case PIPE_FORMAT_Z24X8_UNORM: |
| return usage == VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT ? |
| DXGI_FORMAT_D24_UNORM_S8_UINT : DXGI_FORMAT_R24_UNORM_X8_TYPELESS; |
| |
| case PIPE_FORMAT_Z24_UNORM_S8_UINT: |
| if (usage == VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) |
| return DXGI_FORMAT_D24_UNORM_S8_UINT; |
| |
| if (aspects & VK_IMAGE_ASPECT_DEPTH_BIT) |
| return DXGI_FORMAT_R24_UNORM_X8_TYPELESS; |
| else |
| return DXGI_FORMAT_X24_TYPELESS_G8_UINT; |
| |
| case PIPE_FORMAT_X24S8_UINT: |
| return usage == VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT ? |
| DXGI_FORMAT_D24_UNORM_S8_UINT : DXGI_FORMAT_X24_TYPELESS_G8_UINT; |
| |
| case PIPE_FORMAT_Z32_FLOAT_S8X24_UINT: |
| if (usage == VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) |
| return DXGI_FORMAT_D32_FLOAT_S8X24_UINT; |
| |
| if (aspects & VK_IMAGE_ASPECT_STENCIL_BIT) |
| return DXGI_FORMAT_X32_TYPELESS_G8X24_UINT; |
| else if (aspects & VK_IMAGE_ASPECT_DEPTH_BIT) |
| return DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS; |
| else |
| return DXGI_FORMAT_R32G8X24_TYPELESS; |
| |
| default: |
| return dzn_pipe_to_dxgi_format(pfmt); |
| } |
| } |
| |
| DXGI_FORMAT |
| dzn_image_get_placed_footprint_format(VkFormat format, |
| VkImageAspectFlags aspect) |
| { |
| DXGI_FORMAT out = |
| dzn_image_get_dxgi_format(format, |
| VK_IMAGE_USAGE_TRANSFER_SRC_BIT | |
| VK_IMAGE_USAGE_TRANSFER_DST_BIT, |
| aspect); |
| |
| switch (out) { |
| case DXGI_FORMAT_R24_UNORM_X8_TYPELESS: |
| case DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS: |
| return DXGI_FORMAT_R32_TYPELESS; |
| case DXGI_FORMAT_X24_TYPELESS_G8_UINT: |
| case DXGI_FORMAT_X32_TYPELESS_G8X24_UINT: |
| return DXGI_FORMAT_R8_TYPELESS; |
| default: |
| return out; |
| } |
| } |
| |
| VkFormat |
| dzn_image_get_plane_format(VkFormat format, |
| VkImageAspectFlags aspectMask) |
| { |
| if (aspectMask == VK_IMAGE_ASPECT_STENCIL_BIT) |
| return vk_format_stencil_only(format); |
| else if (aspectMask == VK_IMAGE_ASPECT_DEPTH_BIT) |
| return vk_format_depth_only(format); |
| else |
| return format; |
| } |
| |
| uint32_t |
| dzn_image_layers_get_subresource_index(const struct dzn_image *image, |
| const VkImageSubresourceLayers *subres, |
| VkImageAspectFlagBits aspect, |
| uint32_t layer) |
| { |
| int planeSlice = |
| aspect == VK_IMAGE_ASPECT_STENCIL_BIT ? 1 : 0; |
| |
| return subres->mipLevel + |
| ((subres->baseArrayLayer + layer) * image->desc.MipLevels) + |
| (planeSlice * image->desc.MipLevels * image->desc.DepthOrArraySize); |
| } |
| |
| uint32_t |
| dzn_image_range_get_subresource_index(const struct dzn_image *image, |
| const VkImageSubresourceRange *subres, |
| VkImageAspectFlagBits aspect, |
| uint32_t level, uint32_t layer) |
| { |
| int planeSlice = |
| aspect == VK_IMAGE_ASPECT_STENCIL_BIT ? 1 : 0; |
| |
| return subres->baseMipLevel + level + |
| ((subres->baseArrayLayer + layer) * image->desc.MipLevels) + |
| (planeSlice * image->desc.MipLevels * image->desc.DepthOrArraySize); |
| } |
| |
| static uint32_t |
| dzn_image_get_subresource_index(const struct dzn_image *image, |
| const VkImageSubresource *subres, |
| VkImageAspectFlagBits aspect) |
| { |
| int planeSlice = |
| aspect == VK_IMAGE_ASPECT_STENCIL_BIT ? 1 : 0; |
| |
| return subres->mipLevel + |
| (subres->arrayLayer * image->desc.MipLevels) + |
| (planeSlice * image->desc.MipLevels * image->desc.DepthOrArraySize); |
| } |
| |
| D3D12_TEXTURE_COPY_LOCATION |
| dzn_image_get_copy_loc(const struct dzn_image *image, |
| const VkImageSubresourceLayers *subres, |
| VkImageAspectFlagBits aspect, |
| uint32_t layer) |
| { |
| D3D12_TEXTURE_COPY_LOCATION loc = { |
| .pResource = image->res, |
| }; |
| |
| assert((subres->aspectMask & aspect) != 0); |
| |
| if (image->desc.Dimension == D3D12_RESOURCE_DIMENSION_BUFFER) { |
| assert((subres->baseArrayLayer + layer) == 0); |
| assert(subres->mipLevel == 0); |
| loc.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT; |
| loc.PlacedFootprint.Offset = 0; |
| loc.PlacedFootprint.Footprint.Format = |
| dzn_image_get_placed_footprint_format(image->vk.format, aspect); |
| loc.PlacedFootprint.Footprint.Width = image->vk.extent.width; |
| loc.PlacedFootprint.Footprint.Height = image->vk.extent.height; |
| loc.PlacedFootprint.Footprint.Depth = image->vk.extent.depth; |
| loc.PlacedFootprint.Footprint.RowPitch = image->linear.row_stride; |
| } else { |
| loc.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX; |
| loc.SubresourceIndex = dzn_image_layers_get_subresource_index(image, subres, aspect, layer); |
| } |
| |
| return loc; |
| } |
| |
| D3D12_DEPTH_STENCIL_VIEW_DESC |
| dzn_image_get_dsv_desc(const struct dzn_image *image, |
| const VkImageSubresourceRange *range, |
| uint32_t level) |
| { |
| uint32_t layer_count = dzn_get_layer_count(image, range); |
| D3D12_DEPTH_STENCIL_VIEW_DESC dsv_desc = { |
| .Format = |
| dzn_image_get_dxgi_format(image->vk.format, |
| VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, |
| range->aspectMask), |
| }; |
| |
| switch (image->vk.image_type) { |
| case VK_IMAGE_TYPE_1D: |
| dsv_desc.ViewDimension = |
| image->vk.array_layers > 1 ? |
| D3D12_DSV_DIMENSION_TEXTURE1DARRAY : |
| D3D12_DSV_DIMENSION_TEXTURE1D; |
| break; |
| case VK_IMAGE_TYPE_2D: |
| if (image->vk.array_layers > 1) { |
| dsv_desc.ViewDimension = |
| image->vk.samples > 1 ? |
| D3D12_DSV_DIMENSION_TEXTURE2DMSARRAY : |
| D3D12_DSV_DIMENSION_TEXTURE2DARRAY; |
| } else { |
| dsv_desc.ViewDimension = |
| image->vk.samples > 1 ? |
| D3D12_DSV_DIMENSION_TEXTURE2DMS : |
| D3D12_DSV_DIMENSION_TEXTURE2D; |
| } |
| break; |
| default: |
| unreachable("Invalid image type"); |
| } |
| |
| switch (dsv_desc.ViewDimension) { |
| case D3D12_DSV_DIMENSION_TEXTURE1D: |
| dsv_desc.Texture1D.MipSlice = range->baseMipLevel + level; |
| break; |
| case D3D12_DSV_DIMENSION_TEXTURE1DARRAY: |
| dsv_desc.Texture1DArray.MipSlice = range->baseMipLevel + level; |
| dsv_desc.Texture1DArray.FirstArraySlice = range->baseArrayLayer; |
| dsv_desc.Texture1DArray.ArraySize = layer_count; |
| break; |
| case D3D12_DSV_DIMENSION_TEXTURE2D: |
| dsv_desc.Texture2D.MipSlice = range->baseMipLevel + level; |
| break; |
| case D3D12_DSV_DIMENSION_TEXTURE2DMS: |
| break; |
| case D3D12_DSV_DIMENSION_TEXTURE2DARRAY: |
| dsv_desc.Texture2DArray.MipSlice = range->baseMipLevel + level; |
| dsv_desc.Texture2DArray.FirstArraySlice = range->baseArrayLayer; |
| dsv_desc.Texture2DArray.ArraySize = layer_count; |
| break; |
| case D3D12_DSV_DIMENSION_TEXTURE2DMSARRAY: |
| dsv_desc.Texture2DMSArray.FirstArraySlice = range->baseArrayLayer; |
| dsv_desc.Texture2DMSArray.ArraySize = layer_count; |
| break; |
| default: |
| unreachable("Invalid view dimension"); |
| } |
| |
| return dsv_desc; |
| } |
| |
| D3D12_RENDER_TARGET_VIEW_DESC |
| dzn_image_get_rtv_desc(const struct dzn_image *image, |
| const VkImageSubresourceRange *range, |
| uint32_t level) |
| { |
| uint32_t layer_count = dzn_get_layer_count(image, range); |
| D3D12_RENDER_TARGET_VIEW_DESC rtv_desc = { |
| .Format = |
| dzn_image_get_dxgi_format(image->vk.format, |
| VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, |
| VK_IMAGE_ASPECT_COLOR_BIT), |
| }; |
| |
| switch (image->vk.image_type) { |
| case VK_IMAGE_TYPE_1D: |
| rtv_desc.ViewDimension = |
| image->vk.array_layers > 1 ? |
| D3D12_RTV_DIMENSION_TEXTURE1DARRAY : D3D12_RTV_DIMENSION_TEXTURE1D; |
| break; |
| case VK_IMAGE_TYPE_2D: |
| if (image->vk.array_layers > 1) { |
| rtv_desc.ViewDimension = |
| image->vk.samples > 1 ? |
| D3D12_RTV_DIMENSION_TEXTURE2DMSARRAY : |
| D3D12_RTV_DIMENSION_TEXTURE2DARRAY; |
| } else { |
| rtv_desc.ViewDimension = |
| image->vk.samples > 1 ? |
| D3D12_RTV_DIMENSION_TEXTURE2DMS : |
| D3D12_RTV_DIMENSION_TEXTURE2D; |
| } |
| break; |
| case VK_IMAGE_TYPE_3D: |
| rtv_desc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE3D; |
| break; |
| default: unreachable("Invalid image type\n"); |
| } |
| |
| switch (rtv_desc.ViewDimension) { |
| case D3D12_RTV_DIMENSION_TEXTURE1D: |
| rtv_desc.Texture1D.MipSlice = range->baseMipLevel + level; |
| break; |
| case D3D12_RTV_DIMENSION_TEXTURE1DARRAY: |
| rtv_desc.Texture1DArray.MipSlice = range->baseMipLevel + level; |
| rtv_desc.Texture1DArray.FirstArraySlice = range->baseArrayLayer; |
| rtv_desc.Texture1DArray.ArraySize = layer_count; |
| break; |
| case D3D12_RTV_DIMENSION_TEXTURE2D: |
| rtv_desc.Texture2D.MipSlice = range->baseMipLevel + level; |
| if (range->aspectMask & VK_IMAGE_ASPECT_PLANE_1_BIT) |
| rtv_desc.Texture2D.PlaneSlice = 1; |
| else if (range->aspectMask & VK_IMAGE_ASPECT_PLANE_2_BIT) |
| rtv_desc.Texture2D.PlaneSlice = 2; |
| else |
| rtv_desc.Texture2D.PlaneSlice = 0; |
| break; |
| case D3D12_RTV_DIMENSION_TEXTURE2DMS: |
| break; |
| case D3D12_RTV_DIMENSION_TEXTURE2DARRAY: |
| rtv_desc.Texture2DArray.MipSlice = range->baseMipLevel + level; |
| rtv_desc.Texture2DArray.FirstArraySlice = range->baseArrayLayer; |
| rtv_desc.Texture2DArray.ArraySize = layer_count; |
| if (range->aspectMask & VK_IMAGE_ASPECT_PLANE_1_BIT) |
| rtv_desc.Texture2DArray.PlaneSlice = 1; |
| else if (range->aspectMask & VK_IMAGE_ASPECT_PLANE_2_BIT) |
| rtv_desc.Texture2DArray.PlaneSlice = 2; |
| else |
| rtv_desc.Texture2DArray.PlaneSlice = 0; |
| break; |
| case D3D12_RTV_DIMENSION_TEXTURE2DMSARRAY: |
| rtv_desc.Texture2DMSArray.FirstArraySlice = range->baseArrayLayer; |
| rtv_desc.Texture2DMSArray.ArraySize = layer_count; |
| break; |
| case D3D12_RTV_DIMENSION_TEXTURE3D: |
| rtv_desc.Texture3D.MipSlice = range->baseMipLevel + level; |
| rtv_desc.Texture3D.FirstWSlice = range->baseArrayLayer; |
| rtv_desc.Texture3D.WSize = |
| range->layerCount == VK_REMAINING_ARRAY_LAYERS ? -1 : layer_count; |
| break; |
| default: |
| unreachable("Invalid ViewDimension"); |
| } |
| |
| return rtv_desc; |
| } |
| |
| D3D12_RESOURCE_STATES |
| dzn_image_layout_to_state(const struct dzn_image *image, |
| VkImageLayout layout, |
| VkImageAspectFlagBits aspect) |
| { |
| D3D12_RESOURCE_STATES shaders_access = |
| (image->desc.Flags & D3D12_RESOURCE_FLAG_DENY_SHADER_RESOURCE) ? |
| 0 : D3D12_RESOURCE_STATE_ALL_SHADER_RESOURCE; |
| |
| switch (layout) { |
| case VK_IMAGE_LAYOUT_PREINITIALIZED: |
| case VK_IMAGE_LAYOUT_UNDEFINED: |
| case VK_IMAGE_LAYOUT_GENERAL: |
| /* YOLO! */ |
| case VK_IMAGE_LAYOUT_PRESENT_SRC_KHR: |
| return D3D12_RESOURCE_STATE_COMMON; |
| |
| case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL: |
| return D3D12_RESOURCE_STATE_COPY_DEST; |
| |
| case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL: |
| return D3D12_RESOURCE_STATE_COPY_SOURCE; |
| |
| case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL: |
| return D3D12_RESOURCE_STATE_RENDER_TARGET; |
| |
| case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL: |
| case VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL: |
| case VK_IMAGE_LAYOUT_STENCIL_ATTACHMENT_OPTIMAL: |
| return D3D12_RESOURCE_STATE_DEPTH_WRITE; |
| |
| case VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL: |
| case VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_OPTIMAL: |
| return D3D12_RESOURCE_STATE_DEPTH_READ | shaders_access; |
| |
| case VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL: |
| return aspect == VK_IMAGE_ASPECT_STENCIL_BIT ? |
| D3D12_RESOURCE_STATE_DEPTH_WRITE : |
| (D3D12_RESOURCE_STATE_DEPTH_READ | shaders_access); |
| |
| case VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL: |
| return aspect == VK_IMAGE_ASPECT_STENCIL_BIT ? |
| (D3D12_RESOURCE_STATE_DEPTH_READ | shaders_access) : |
| D3D12_RESOURCE_STATE_DEPTH_WRITE; |
| |
| case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL: |
| return D3D12_RESOURCE_STATE_ALL_SHADER_RESOURCE; |
| |
| case VK_IMAGE_LAYOUT_ATTACHMENT_FEEDBACK_LOOP_OPTIMAL_EXT: |
| return D3D12_RESOURCE_STATE_COMMON; |
| |
| default: |
| unreachable("not implemented"); |
| } |
| } |
| |
| bool |
| dzn_image_formats_are_compatible(const struct dzn_device *device, |
| VkFormat orig_fmt, VkFormat new_fmt, |
| VkImageUsageFlags usage, |
| VkImageAspectFlagBits aspect) |
| { |
| const struct dzn_physical_device *pdev = |
| container_of(device->vk.physical, struct dzn_physical_device, vk); |
| DXGI_FORMAT orig_dxgi = dzn_image_get_dxgi_format(orig_fmt, usage, aspect); |
| DXGI_FORMAT new_dxgi = dzn_image_get_dxgi_format(new_fmt, usage, aspect); |
| |
| if (orig_dxgi == new_dxgi) |
| return true; |
| |
| DXGI_FORMAT typeless_orig = dzn_get_typeless_dxgi_format(orig_dxgi); |
| DXGI_FORMAT typeless_new = dzn_get_typeless_dxgi_format(new_dxgi); |
| |
| if (!(usage & VK_IMAGE_USAGE_SAMPLED_BIT)) |
| return typeless_orig == typeless_new; |
| |
| if (pdev->options3.CastingFullyTypedFormatSupported) { |
| enum pipe_format orig_pfmt = vk_format_to_pipe_format(orig_fmt); |
| enum pipe_format new_pfmt = vk_format_to_pipe_format(new_fmt); |
| |
| /* Types don't belong to the same group, they're incompatible. */ |
| if (typeless_orig != typeless_new) |
| return false; |
| |
| /* FLOAT <-> non-FLOAT casting is disallowed. */ |
| if (util_format_is_float(orig_pfmt) != util_format_is_float(new_pfmt)) |
| return false; |
| |
| /* UNORM <-> SNORM casting is disallowed. */ |
| bool orig_is_norm = |
| util_format_is_unorm(orig_pfmt) || util_format_is_snorm(orig_pfmt); |
| bool new_is_norm = |
| util_format_is_unorm(new_pfmt) || util_format_is_snorm(new_pfmt); |
| if (orig_is_norm && new_is_norm && |
| util_format_is_unorm(orig_pfmt) != util_format_is_unorm(new_pfmt)) |
| return false; |
| |
| return true; |
| } |
| |
| return false; |
| } |
| |
| VKAPI_ATTR VkResult VKAPI_CALL |
| dzn_CreateImage(VkDevice device, |
| const VkImageCreateInfo *pCreateInfo, |
| const VkAllocationCallbacks *pAllocator, |
| VkImage *pImage) |
| { |
| return dzn_image_create(dzn_device_from_handle(device), |
| pCreateInfo, pAllocator, pImage); |
| } |
| |
| VKAPI_ATTR void VKAPI_CALL |
| dzn_DestroyImage(VkDevice device, VkImage image, |
| const VkAllocationCallbacks *pAllocator) |
| { |
| dzn_image_destroy(dzn_image_from_handle(image), pAllocator); |
| } |
| |
| static struct dzn_image * |
| dzn_swapchain_get_image(struct dzn_device *device, |
| VkSwapchainKHR swapchain, |
| uint32_t index) |
| { |
| uint32_t n_images = index + 1; |
| STACK_ARRAY(VkImage, images, n_images); |
| struct dzn_image *image = NULL; |
| |
| VkResult result = wsi_common_get_images(swapchain, &n_images, images); |
| |
| if (result == VK_SUCCESS || result == VK_INCOMPLETE) |
| image = dzn_image_from_handle(images[index]); |
| |
| STACK_ARRAY_FINISH(images); |
| return image; |
| } |
| |
| VKAPI_ATTR VkResult VKAPI_CALL |
| dzn_BindImageMemory2(VkDevice dev, |
| uint32_t bindInfoCount, |
| const VkBindImageMemoryInfo *pBindInfos) |
| { |
| VK_FROM_HANDLE(dzn_device, device, dev); |
| |
| for (uint32_t i = 0; i < bindInfoCount; i++) { |
| const VkBindImageMemoryInfo *bind_info = &pBindInfos[i]; |
| VK_FROM_HANDLE(dzn_device_memory, mem, bind_info->memory); |
| VK_FROM_HANDLE(dzn_image, image, bind_info->image); |
| bool did_bind = false; |
| |
| vk_foreach_struct_const(s, bind_info->pNext) { |
| switch (s->sType) { |
| case VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_SWAPCHAIN_INFO_KHR: { |
| const VkBindImageMemorySwapchainInfoKHR *swapchain_info = |
| (const VkBindImageMemorySwapchainInfoKHR *) s; |
| ASSERTED struct dzn_image *swapchain_image = |
| dzn_swapchain_get_image(device, |
| swapchain_info->swapchain, |
| swapchain_info->imageIndex); |
| assert(swapchain_image); |
| assert(image->vk.aspects == swapchain_image->vk.aspects); |
| assert(mem == NULL); |
| |
| /* TODO: something something binding the image memory */ |
| assert(false); |
| |
| did_bind = true; |
| break; |
| } |
| default: |
| dzn_debug_ignored_stype(s->sType); |
| break; |
| } |
| } |
| |
| if (!did_bind) { |
| image->mem = mem; |
| image->mem_offset = bind_info->memoryOffset; |
| if (FAILED(ID3D12Device1_CreatePlacedResource(device->dev, mem->heap, |
| bind_info->memoryOffset, |
| &image->desc, |
| mem->initial_state, |
| NULL, |
| &IID_ID3D12Resource, |
| (void **)&image->res))) |
| return vk_error(device, VK_ERROR_OUT_OF_DEVICE_MEMORY); |
| did_bind = true; |
| } |
| } |
| |
| return VK_SUCCESS; |
| } |
| |
| VKAPI_ATTR void VKAPI_CALL |
| dzn_GetImageMemoryRequirements2(VkDevice _device, |
| const VkImageMemoryRequirementsInfo2 *pInfo, |
| VkMemoryRequirements2 *pMemoryRequirements) |
| { |
| VK_FROM_HANDLE(dzn_device, device, _device); |
| VK_FROM_HANDLE(dzn_image, image, pInfo->image); |
| struct dzn_physical_device *pdev = |
| container_of(device->vk.physical, struct dzn_physical_device, vk); |
| |
| vk_foreach_struct_const(ext, pInfo->pNext) { |
| dzn_debug_ignored_stype(ext->sType); |
| } |
| |
| vk_foreach_struct(ext, pMemoryRequirements->pNext) { |
| switch (ext->sType) { |
| case VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS: { |
| VkMemoryDedicatedRequirements *requirements = |
| (VkMemoryDedicatedRequirements *)ext; |
| /* TODO: figure out dedicated allocations */ |
| requirements->prefersDedicatedAllocation = false; |
| requirements->requiresDedicatedAllocation = false; |
| break; |
| } |
| |
| default: |
| dzn_debug_ignored_stype(ext->sType); |
| break; |
| } |
| } |
| |
| D3D12_RESOURCE_ALLOCATION_INFO info = dzn_ID3D12Device2_GetResourceAllocationInfo(device->dev, 0, 1, &image->desc); |
| |
| pMemoryRequirements->memoryRequirements = (VkMemoryRequirements) { |
| .size = info.SizeInBytes, |
| .alignment = info.Alignment, |
| .memoryTypeBits = |
| dzn_physical_device_get_mem_type_mask_for_resource(pdev, &image->desc), |
| }; |
| |
| /* |
| * MSAA images need memory to be aligned on |
| * D3D12_DEFAULT_MSAA_RESOURCE_PLACEMENT_ALIGNMENT (4MB), but the memory |
| * allocation function doesn't know what the memory will be used for, |
| * and forcing all allocations to be 4MB-aligned has a cost, so let's |
| * force MSAA resources to be at least 4MB, such that the allocation |
| * logic can consider sub-4MB allocations to not require this 4MB alignment. |
| */ |
| if (image->vk.samples > 1 && |
| pMemoryRequirements->memoryRequirements.size < D3D12_DEFAULT_MSAA_RESOURCE_PLACEMENT_ALIGNMENT) |
| pMemoryRequirements->memoryRequirements.size = D3D12_DEFAULT_MSAA_RESOURCE_PLACEMENT_ALIGNMENT; |
| } |
| |
| VKAPI_ATTR void VKAPI_CALL |
| dzn_GetImageSubresourceLayout(VkDevice _device, |
| VkImage _image, |
| const VkImageSubresource *subresource, |
| VkSubresourceLayout *layout) |
| { |
| VK_FROM_HANDLE(dzn_device, device, _device); |
| VK_FROM_HANDLE(dzn_image, image, _image); |
| |
| if (image->desc.Dimension == D3D12_RESOURCE_DIMENSION_BUFFER) { |
| assert(subresource->arrayLayer == 0); |
| assert(subresource->mipLevel == 0); |
| layout->offset = 0; |
| layout->rowPitch = image->linear.row_stride; |
| layout->depthPitch = 0; |
| layout->arrayPitch = 0; |
| layout->size = image->linear.size; |
| } else { |
| UINT subres_index = |
| dzn_image_get_subresource_index(image, subresource, |
| (VkImageAspectFlagBits)subresource->aspectMask); |
| D3D12_PLACED_SUBRESOURCE_FOOTPRINT footprint; |
| UINT num_rows; |
| UINT64 row_size, total_size; |
| ID3D12Device1_GetCopyableFootprints(device->dev, &image->desc, |
| subres_index, 1, |
| 0, // base-offset? |
| &footprint, |
| &num_rows, &row_size, |
| &total_size); |
| |
| layout->offset = footprint.Offset; |
| layout->rowPitch = footprint.Footprint.RowPitch; |
| layout->depthPitch = layout->rowPitch * footprint.Footprint.Height; |
| layout->arrayPitch = layout->depthPitch; // uuuh... why is this even here? |
| layout->size = total_size; |
| } |
| } |
| |
| static D3D12_SHADER_COMPONENT_MAPPING |
| translate_swizzle(VkComponentSwizzle in, uint32_t comp) |
| { |
| switch (in) { |
| case VK_COMPONENT_SWIZZLE_IDENTITY: |
| return (D3D12_SHADER_COMPONENT_MAPPING) |
| (comp + D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_0); |
| case VK_COMPONENT_SWIZZLE_ZERO: |
| return D3D12_SHADER_COMPONENT_MAPPING_FORCE_VALUE_0; |
| case VK_COMPONENT_SWIZZLE_ONE: |
| return D3D12_SHADER_COMPONENT_MAPPING_FORCE_VALUE_1; |
| case VK_COMPONENT_SWIZZLE_R: |
| return D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_0; |
| case VK_COMPONENT_SWIZZLE_G: |
| return D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_1; |
| case VK_COMPONENT_SWIZZLE_B: |
| return D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_2; |
| case VK_COMPONENT_SWIZZLE_A: |
| return D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_3; |
| default: unreachable("Invalid swizzle"); |
| } |
| } |
| |
| static void |
| dzn_image_view_prepare_srv_desc(struct dzn_image_view *iview) |
| { |
| uint32_t plane_slice = (iview->vk.aspects & VK_IMAGE_ASPECT_STENCIL_BIT) ? 1 : 0; |
| bool ms = iview->vk.image->samples > 1; |
| uint32_t layers_per_elem = |
| (iview->vk.view_type == VK_IMAGE_VIEW_TYPE_CUBE || |
| iview->vk.view_type == VK_IMAGE_VIEW_TYPE_CUBE_ARRAY) ? |
| 6 : 1; |
| bool use_array = (iview->vk.base_array_layer / layers_per_elem) > 0 || |
| (iview->vk.layer_count / layers_per_elem) > 1; |
| |
| iview->srv_desc = (D3D12_SHADER_RESOURCE_VIEW_DESC) { |
| .Format = |
| dzn_image_get_dxgi_format(iview->vk.format, |
| iview->vk.image->usage & ~VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, |
| iview->vk.aspects), |
| }; |
| |
| D3D12_SHADER_COMPONENT_MAPPING swz[] = { |
| translate_swizzle(iview->vk.swizzle.r, 0), |
| translate_swizzle(iview->vk.swizzle.g, 1), |
| translate_swizzle(iview->vk.swizzle.b, 2), |
| translate_swizzle(iview->vk.swizzle.a, 3), |
| }; |
| |
| /* Swap components to fake B4G4R4A4 support. */ |
| if (iview->vk.format == VK_FORMAT_B4G4R4A4_UNORM_PACK16) { |
| static const D3D12_SHADER_COMPONENT_MAPPING bgra4_remap[] = { |
| D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_1, |
| D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_0, |
| D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_3, |
| D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_2, |
| D3D12_SHADER_COMPONENT_MAPPING_FORCE_VALUE_0, |
| D3D12_SHADER_COMPONENT_MAPPING_FORCE_VALUE_1, |
| }; |
| |
| for (uint32_t i = 0; i < ARRAY_SIZE(swz); i++) |
| swz[i] = bgra4_remap[swz[i]]; |
| } |
| |
| iview->srv_desc.Shader4ComponentMapping = |
| D3D12_ENCODE_SHADER_4_COMPONENT_MAPPING(swz[0], swz[1], swz[2], swz[3]); |
| |
| switch (iview->vk.view_type) { |
| case VK_IMAGE_VIEW_TYPE_1D_ARRAY: |
| case VK_IMAGE_VIEW_TYPE_1D: |
| if (use_array) { |
| iview->srv_desc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE1DARRAY; |
| iview->srv_desc.Texture1DArray.MostDetailedMip = iview->vk.base_mip_level; |
| iview->srv_desc.Texture1DArray.MipLevels = iview->vk.level_count; |
| iview->srv_desc.Texture1DArray.FirstArraySlice = iview->vk.base_array_layer; |
| iview->srv_desc.Texture1DArray.ArraySize = iview->vk.layer_count; |
| } else { |
| iview->srv_desc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE1D; |
| iview->srv_desc.Texture1D.MostDetailedMip = iview->vk.base_mip_level; |
| iview->srv_desc.Texture1D.MipLevels = iview->vk.level_count; |
| } |
| break; |
| |
| case VK_IMAGE_VIEW_TYPE_2D_ARRAY: |
| case VK_IMAGE_VIEW_TYPE_2D: |
| if (use_array && ms) { |
| iview->srv_desc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2DMSARRAY; |
| iview->srv_desc.Texture2DMSArray.FirstArraySlice = iview->vk.base_array_layer; |
| iview->srv_desc.Texture2DMSArray.ArraySize = iview->vk.layer_count; |
| } else if (use_array && !ms) { |
| iview->srv_desc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2DARRAY; |
| iview->srv_desc.Texture2DArray.MostDetailedMip = iview->vk.base_mip_level; |
| iview->srv_desc.Texture2DArray.MipLevels = iview->vk.level_count; |
| iview->srv_desc.Texture2DArray.FirstArraySlice = iview->vk.base_array_layer; |
| iview->srv_desc.Texture2DArray.ArraySize = iview->vk.layer_count; |
| iview->srv_desc.Texture2DArray.PlaneSlice = plane_slice; |
| } else if (!use_array && ms) { |
| iview->srv_desc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2DMS; |
| } else { |
| iview->srv_desc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D; |
| iview->srv_desc.Texture2D.MostDetailedMip = iview->vk.base_mip_level; |
| iview->srv_desc.Texture2D.MipLevels = iview->vk.level_count; |
| iview->srv_desc.Texture2D.PlaneSlice = plane_slice; |
| } |
| break; |
| |
| case VK_IMAGE_VIEW_TYPE_CUBE_ARRAY: |
| case VK_IMAGE_VIEW_TYPE_CUBE: |
| if (use_array) { |
| iview->srv_desc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURECUBEARRAY; |
| iview->srv_desc.TextureCubeArray.MostDetailedMip = iview->vk.base_mip_level; |
| iview->srv_desc.TextureCubeArray.MipLevels = iview->vk.level_count; |
| iview->srv_desc.TextureCubeArray.First2DArrayFace = iview->vk.base_array_layer; |
| iview->srv_desc.TextureCubeArray.NumCubes = iview->vk.layer_count / 6; |
| } else { |
| iview->srv_desc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURECUBE; |
| iview->srv_desc.TextureCube.MostDetailedMip = iview->vk.base_mip_level; |
| iview->srv_desc.TextureCube.MipLevels = iview->vk.level_count; |
| } |
| break; |
| |
| case VK_IMAGE_VIEW_TYPE_3D: |
| iview->srv_desc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE3D; |
| iview->srv_desc.Texture3D.MostDetailedMip = iview->vk.base_mip_level; |
| iview->srv_desc.Texture3D.MipLevels = iview->vk.level_count; |
| break; |
| |
| default: unreachable("Invalid view type"); |
| } |
| } |
| |
| static void |
| dzn_image_view_prepare_uav_desc(struct dzn_image_view *iview) |
| { |
| bool use_array = iview->vk.base_array_layer > 0 || iview->vk.layer_count > 1; |
| |
| assert(iview->vk.image->samples == 1); |
| |
| iview->uav_desc = (D3D12_UNORDERED_ACCESS_VIEW_DESC) { |
| .Format = |
| dzn_image_get_dxgi_format(iview->vk.format, |
| VK_IMAGE_USAGE_STORAGE_BIT, |
| iview->vk.aspects), |
| }; |
| |
| switch (iview->vk.view_type) { |
| case VK_IMAGE_VIEW_TYPE_1D: |
| case VK_IMAGE_VIEW_TYPE_1D_ARRAY: |
| if (use_array) { |
| iview->uav_desc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE1DARRAY; |
| iview->uav_desc.Texture1DArray.MipSlice = iview->vk.base_mip_level; |
| iview->uav_desc.Texture1DArray.FirstArraySlice = iview->vk.base_array_layer; |
| iview->uav_desc.Texture1DArray.ArraySize = iview->vk.layer_count; |
| } else { |
| iview->uav_desc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE1D; |
| iview->uav_desc.Texture1D.MipSlice = iview->vk.base_mip_level; |
| } |
| break; |
| |
| case VK_IMAGE_VIEW_TYPE_2D: |
| case VK_IMAGE_VIEW_TYPE_2D_ARRAY: |
| case VK_IMAGE_VIEW_TYPE_CUBE: |
| case VK_IMAGE_VIEW_TYPE_CUBE_ARRAY: |
| if (use_array) { |
| iview->uav_desc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE2DARRAY; |
| iview->uav_desc.Texture2DArray.PlaneSlice = 0; |
| iview->uav_desc.Texture2DArray.MipSlice = iview->vk.base_mip_level; |
| iview->uav_desc.Texture2DArray.FirstArraySlice = iview->vk.base_array_layer; |
| iview->uav_desc.Texture2DArray.ArraySize = iview->vk.layer_count; |
| } else { |
| iview->uav_desc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE2D; |
| iview->uav_desc.Texture2D.MipSlice = iview->vk.base_mip_level; |
| iview->uav_desc.Texture2D.PlaneSlice = 0; |
| } |
| break; |
| case VK_IMAGE_VIEW_TYPE_3D: |
| iview->uav_desc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE3D; |
| iview->uav_desc.Texture3D.MipSlice = iview->vk.base_mip_level; |
| iview->uav_desc.Texture3D.FirstWSlice = 0; |
| iview->uav_desc.Texture3D.WSize = iview->vk.extent.depth; |
| break; |
| default: unreachable("Invalid type"); |
| } |
| } |
| |
| static void |
| dzn_image_view_prepare_rtv_desc(struct dzn_image_view *iview) |
| { |
| bool use_array = iview->vk.base_array_layer > 0 || iview->vk.layer_count > 1; |
| bool from_3d_image = iview->vk.image->image_type == VK_IMAGE_TYPE_3D; |
| bool ms = iview->vk.image->samples > 1; |
| uint32_t plane_slice = |
| (iview->vk.aspects & VK_IMAGE_ASPECT_PLANE_2_BIT) ? 2 : |
| (iview->vk.aspects & VK_IMAGE_ASPECT_PLANE_1_BIT) ? 1 : 0; |
| |
| assert(iview->vk.level_count == 1); |
| |
| iview->rtv_desc = (D3D12_RENDER_TARGET_VIEW_DESC) { |
| .Format = |
| dzn_image_get_dxgi_format(iview->vk.format, |
| VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, |
| iview->vk.aspects), |
| }; |
| |
| switch (iview->vk.view_type) { |
| case VK_IMAGE_VIEW_TYPE_1D: |
| case VK_IMAGE_VIEW_TYPE_1D_ARRAY: |
| if (use_array) { |
| iview->rtv_desc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE1DARRAY; |
| iview->rtv_desc.Texture1DArray.MipSlice = iview->vk.base_mip_level; |
| iview->rtv_desc.Texture1DArray.FirstArraySlice = iview->vk.base_array_layer; |
| iview->rtv_desc.Texture1DArray.ArraySize = iview->vk.layer_count; |
| } else { |
| iview->rtv_desc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE1D; |
| iview->rtv_desc.Texture1D.MipSlice = iview->vk.base_mip_level; |
| } |
| break; |
| |
| case VK_IMAGE_VIEW_TYPE_2D: |
| case VK_IMAGE_VIEW_TYPE_2D_ARRAY: |
| case VK_IMAGE_VIEW_TYPE_CUBE: |
| case VK_IMAGE_VIEW_TYPE_CUBE_ARRAY: |
| if (from_3d_image) { |
| iview->rtv_desc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE3D; |
| iview->rtv_desc.Texture3D.MipSlice = iview->vk.base_mip_level; |
| iview->rtv_desc.Texture3D.FirstWSlice = iview->vk.base_array_layer; |
| iview->rtv_desc.Texture3D.WSize = iview->vk.layer_count; |
| } else if (use_array && ms) { |
| iview->rtv_desc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2DMSARRAY; |
| iview->rtv_desc.Texture2DMSArray.FirstArraySlice = iview->vk.base_array_layer; |
| iview->rtv_desc.Texture2DMSArray.ArraySize = iview->vk.layer_count; |
| } else if (use_array && !ms) { |
| iview->rtv_desc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2DARRAY; |
| iview->rtv_desc.Texture2DArray.MipSlice = iview->vk.base_mip_level; |
| iview->rtv_desc.Texture2DArray.FirstArraySlice = iview->vk.base_array_layer; |
| iview->rtv_desc.Texture2DArray.ArraySize = iview->vk.layer_count; |
| iview->rtv_desc.Texture2DArray.PlaneSlice = plane_slice; |
| } else if (!use_array && ms) { |
| iview->rtv_desc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2DMS; |
| } else { |
| iview->rtv_desc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2D; |
| iview->rtv_desc.Texture2D.MipSlice = iview->vk.base_mip_level; |
| iview->rtv_desc.Texture2D.PlaneSlice = plane_slice; |
| } |
| break; |
| |
| case VK_IMAGE_VIEW_TYPE_3D: |
| iview->rtv_desc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE3D; |
| iview->rtv_desc.Texture3D.MipSlice = iview->vk.base_mip_level; |
| iview->rtv_desc.Texture3D.FirstWSlice = 0; |
| iview->rtv_desc.Texture3D.WSize = iview->vk.extent.depth; |
| break; |
| |
| default: unreachable("Invalid view type"); |
| } |
| } |
| |
| static void |
| dzn_image_view_prepare_dsv_desc(struct dzn_image_view *iview) |
| { |
| bool use_array = iview->vk.base_array_layer > 0 || iview->vk.layer_count > 1; |
| bool ms = iview->vk.image->samples > 1; |
| |
| iview->dsv_desc = (D3D12_DEPTH_STENCIL_VIEW_DESC) { |
| .Format = |
| dzn_image_get_dxgi_format(iview->vk.format, |
| VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, |
| iview->vk.aspects), |
| }; |
| |
| switch (iview->vk.view_type) { |
| case VK_IMAGE_VIEW_TYPE_1D: |
| case VK_IMAGE_VIEW_TYPE_1D_ARRAY: |
| if (use_array) { |
| iview->dsv_desc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE1DARRAY; |
| iview->dsv_desc.Texture1DArray.MipSlice = iview->vk.base_mip_level; |
| iview->dsv_desc.Texture1DArray.FirstArraySlice = iview->vk.base_array_layer; |
| iview->dsv_desc.Texture1DArray.ArraySize = iview->vk.layer_count; |
| } else { |
| iview->dsv_desc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE1D; |
| iview->dsv_desc.Texture1D.MipSlice = iview->vk.base_mip_level; |
| } |
| break; |
| |
| case VK_IMAGE_VIEW_TYPE_2D: |
| case VK_IMAGE_VIEW_TYPE_2D_ARRAY: |
| case VK_IMAGE_VIEW_TYPE_CUBE: |
| case VK_IMAGE_VIEW_TYPE_CUBE_ARRAY: |
| if (use_array && ms) { |
| iview->dsv_desc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2DMSARRAY; |
| iview->dsv_desc.Texture2DMSArray.FirstArraySlice = iview->vk.base_array_layer; |
| iview->dsv_desc.Texture2DMSArray.ArraySize = iview->vk.layer_count; |
| } else if (use_array && !ms) { |
| iview->dsv_desc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2DARRAY; |
| iview->dsv_desc.Texture2DArray.MipSlice = iview->vk.base_mip_level; |
| iview->dsv_desc.Texture2DArray.FirstArraySlice = iview->vk.base_array_layer; |
| iview->dsv_desc.Texture2DArray.ArraySize = iview->vk.layer_count; |
| } else if (!use_array && ms) { |
| iview->dsv_desc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2DMS; |
| } else { |
| iview->dsv_desc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2D; |
| iview->dsv_desc.Texture2D.MipSlice = iview->vk.base_mip_level; |
| } |
| break; |
| |
| default: unreachable("Invalid view type"); |
| } |
| } |
| |
| void |
| dzn_image_view_finish(struct dzn_image_view *iview) |
| { |
| vk_image_view_finish(&iview->vk); |
| } |
| |
| void |
| dzn_image_view_init(struct dzn_device *device, |
| struct dzn_image_view *iview, |
| const VkImageViewCreateInfo *pCreateInfo) |
| { |
| VK_FROM_HANDLE(dzn_image, image, pCreateInfo->image); |
| |
| const VkImageSubresourceRange *range = &pCreateInfo->subresourceRange; |
| ASSERTED uint32_t layer_count = dzn_get_layer_count(image, range); |
| |
| vk_image_view_init(&device->vk, &iview->vk, false, pCreateInfo); |
| |
| assert(layer_count > 0); |
| assert(range->baseMipLevel < image->vk.mip_levels); |
| |
| /* View usage should be a subset of image usage */ |
| assert(iview->vk.usage & (VK_IMAGE_USAGE_TRANSFER_SRC_BIT | |
| VK_IMAGE_USAGE_SAMPLED_BIT | |
| VK_IMAGE_USAGE_STORAGE_BIT | |
| VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | |
| VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT | |
| VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)); |
| |
| switch (image->vk.image_type) { |
| default: |
| unreachable("bad VkImageType"); |
| case VK_IMAGE_TYPE_1D: |
| case VK_IMAGE_TYPE_2D: |
| assert(range->baseArrayLayer + dzn_get_layer_count(image, range) - 1 <= image->vk.array_layers); |
| break; |
| case VK_IMAGE_TYPE_3D: |
| assert(range->baseArrayLayer + dzn_get_layer_count(image, range) - 1 |
| <= u_minify(image->vk.extent.depth, range->baseMipLevel)); |
| break; |
| } |
| |
| dzn_image_view_prepare_srv_desc(iview); |
| |
| if (iview->vk.usage & VK_IMAGE_USAGE_STORAGE_BIT) |
| dzn_image_view_prepare_uav_desc(iview); |
| |
| if (iview->vk.usage & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT) |
| dzn_image_view_prepare_rtv_desc(iview); |
| |
| if (iview->vk.usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) |
| dzn_image_view_prepare_dsv_desc(iview); |
| } |
| |
| static void |
| dzn_image_view_destroy(struct dzn_image_view *iview, |
| const VkAllocationCallbacks *pAllocator) |
| { |
| if (!iview) |
| return; |
| |
| struct dzn_device *device = container_of(iview->vk.base.device, struct dzn_device, vk); |
| |
| vk_image_view_finish(&iview->vk); |
| vk_free2(&device->vk.alloc, pAllocator, iview); |
| } |
| |
| static VkResult |
| dzn_image_view_create(struct dzn_device *device, |
| const VkImageViewCreateInfo *pCreateInfo, |
| const VkAllocationCallbacks *pAllocator, |
| VkImageView *out) |
| { |
| struct dzn_image_view *iview = |
| vk_zalloc2(&device->vk.alloc, pAllocator, sizeof(*iview), 8, |
| VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); |
| if (!iview) |
| return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY); |
| |
| dzn_image_view_init(device, iview, pCreateInfo); |
| |
| *out = dzn_image_view_to_handle(iview); |
| return VK_SUCCESS; |
| } |
| |
| VKAPI_ATTR VkResult VKAPI_CALL |
| dzn_CreateImageView(VkDevice device, |
| const VkImageViewCreateInfo *pCreateInfo, |
| const VkAllocationCallbacks *pAllocator, |
| VkImageView *pView) |
| { |
| return dzn_image_view_create(dzn_device_from_handle(device), pCreateInfo, |
| pAllocator, pView); |
| } |
| |
| VKAPI_ATTR void VKAPI_CALL |
| dzn_DestroyImageView(VkDevice device, |
| VkImageView imageView, |
| const VkAllocationCallbacks *pAllocator) |
| { |
| dzn_image_view_destroy(dzn_image_view_from_handle(imageView), pAllocator); |
| } |
| |
| static void |
| dzn_buffer_view_destroy(struct dzn_buffer_view *bview, |
| const VkAllocationCallbacks *pAllocator) |
| { |
| if (!bview) |
| return; |
| |
| struct dzn_device *device = container_of(bview->base.device, struct dzn_device, vk); |
| |
| vk_object_base_finish(&bview->base); |
| vk_free2(&device->vk.alloc, pAllocator, bview); |
| } |
| |
| static VkResult |
| dzn_buffer_view_create(struct dzn_device *device, |
| const VkBufferViewCreateInfo *pCreateInfo, |
| const VkAllocationCallbacks *pAllocator, |
| VkBufferView *out) |
| { |
| VK_FROM_HANDLE(dzn_buffer, buf, pCreateInfo->buffer); |
| |
| struct dzn_buffer_view *bview = |
| vk_zalloc2(&device->vk.alloc, pAllocator, sizeof(*bview), 8, |
| VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); |
| if (!bview) |
| return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY); |
| |
| vk_object_base_init(&device->vk, &bview->base, VK_OBJECT_TYPE_BUFFER_VIEW); |
| |
| enum pipe_format pfmt = vk_format_to_pipe_format(pCreateInfo->format); |
| unsigned blksz = util_format_get_blocksize(pfmt); |
| VkDeviceSize size = |
| pCreateInfo->range == VK_WHOLE_SIZE ? |
| buf->size - pCreateInfo->offset : pCreateInfo->range; |
| |
| bview->buffer = buf; |
| if (buf->usage & |
| (VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT | |
| VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT)) { |
| bview->srv_desc = (D3D12_SHADER_RESOURCE_VIEW_DESC) { |
| .Format = dzn_buffer_get_dxgi_format(pCreateInfo->format), |
| .ViewDimension = D3D12_SRV_DIMENSION_BUFFER, |
| .Shader4ComponentMapping = |
| D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING, |
| .Buffer = { |
| .FirstElement = pCreateInfo->offset / blksz, |
| .NumElements = (UINT)(size / blksz), |
| .Flags = D3D12_BUFFER_SRV_FLAG_NONE, |
| }, |
| }; |
| } |
| |
| if (buf->usage & VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT) { |
| bview->uav_desc = (D3D12_UNORDERED_ACCESS_VIEW_DESC) { |
| .Format = dzn_buffer_get_dxgi_format(pCreateInfo->format), |
| .ViewDimension = D3D12_UAV_DIMENSION_BUFFER, |
| .Buffer = { |
| .FirstElement = pCreateInfo->offset / blksz, |
| .NumElements = (UINT)(size / blksz), |
| .Flags = D3D12_BUFFER_UAV_FLAG_NONE, |
| }, |
| }; |
| } |
| |
| *out = dzn_buffer_view_to_handle(bview); |
| return VK_SUCCESS; |
| } |
| |
| VKAPI_ATTR VkResult VKAPI_CALL |
| dzn_CreateBufferView(VkDevice device, |
| const VkBufferViewCreateInfo *pCreateInfo, |
| const VkAllocationCallbacks *pAllocator, |
| VkBufferView *pView) |
| { |
| return dzn_buffer_view_create(dzn_device_from_handle(device), |
| pCreateInfo, pAllocator, pView); |
| } |
| |
| VKAPI_ATTR void VKAPI_CALL |
| dzn_DestroyBufferView(VkDevice device, |
| VkBufferView bufferView, |
| const VkAllocationCallbacks *pAllocator) |
| { |
| dzn_buffer_view_destroy(dzn_buffer_view_from_handle(bufferView), pAllocator); |
| } |