/* * 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_physical_device *pdev = container_of(device->vk.physical, struct dzn_physical_device, vk); VkFormat *compat_formats = NULL; uint32_t compat_format_count = 0; if (pdev->options12.RelaxedFormatCastingSupported) { VkResult ret = vk_image_create_get_format_list(&device->vk, pCreateInfo, pAllocator, &compat_formats, &compat_format_count); if (ret != VK_SUCCESS) return ret; } VK_MULTIALLOC(ma); VK_MULTIALLOC_DECL(&ma, struct dzn_image, image, 1); VK_MULTIALLOC_DECL(&ma, DXGI_FORMAT, castable_formats, compat_format_count); if (!vk_multialloc_zalloc2(&ma, &device->vk.alloc, pAllocator, VK_SYSTEM_ALLOCATION_SCOPE_OBJECT)) { vk_free2(&device->vk.alloc, pAllocator, compat_formats); 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); VkImageUsageFlags usage = image->vk.usage | image->vk.stencil_usage; image->castable_formats = castable_formats; image->castable_format_count = 0; for (uint32_t i = 0; i < compat_format_count; i++) { castable_formats[image->castable_format_count] = dzn_image_get_dxgi_format(pdev, compat_formats[i], usage, 0); if (castable_formats[image->castable_format_count] != DXGI_FORMAT_UNKNOWN) image->castable_format_count++; } vk_free2(&device->vk.alloc, pAllocator, compat_formats); image->valid_access = D3D12_BARRIER_ACCESS_COPY_SOURCE | D3D12_BARRIER_ACCESS_COPY_DEST; 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(!(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_POT(image->vk.extent.width, util_format_get_blockwidth(pfmt)), .Height = (UINT)ALIGN_POT(image->vk.extent.height, util_format_get_blockheight(pfmt)), .DepthOrArraySize = 1, .MipLevels = 1, .Format = dzn_image_get_dxgi_format(pdev, pCreateInfo->format, 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; image->castable_formats = NULL; image->castable_format_count = 0; } else { image->desc.Format = dzn_image_get_dxgi_format(pdev, pCreateInfo->format, 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; image->valid_access |= D3D12_BARRIER_ACCESS_RESOLVE_DEST | D3D12_BARRIER_ACCESS_SHADER_RESOURCE | (pCreateInfo->samples > 1 ? D3D12_BARRIER_ACCESS_RESOLVE_SOURCE : 0); } if ((image->vk.create_flags & VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT) && !pdev->options12.RelaxedFormatCastingSupported) 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 (usage & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT) { image->desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET; image->valid_access |= D3D12_BARRIER_ACCESS_RENDER_TARGET; } if (usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) { image->desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL; image->valid_access |= D3D12_BARRIER_ACCESS_DEPTH_STENCIL_READ | D3D12_BARRIER_ACCESS_DEPTH_STENCIL_WRITE; if (!(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; image->valid_access &= ~D3D12_BARRIER_ACCESS_SHADER_RESOURCE; } } else if (usage & VK_IMAGE_USAGE_STORAGE_BIT) { image->desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS; image->valid_access |= D3D12_BARRIER_ACCESS_UNORDERED_ACCESS; } /* Images with TRANSFER_DST can be cleared or passed as a blit/resolve * destination. Both operations require the RT or DS cap flags. */ if ((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, pCreateInfo->flags); if (dfmt_info.Support1 & D3D12_FORMAT_SUPPORT1_RENDER_TARGET) { image->desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET; image->valid_access |= D3D12_BARRIER_ACCESS_RENDER_TARGET; } else if ((dfmt_info.Support1 & D3D12_FORMAT_SUPPORT1_DEPTH_STENCIL) && (image->desc.Flags & (D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET | D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS)) == D3D12_RESOURCE_FLAG_NONE) { image->desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL; image->valid_access |= D3D12_BARRIER_ACCESS_DEPTH_STENCIL_WRITE; } else if (dfmt_info.Support1 & D3D12_FORMAT_SUPPORT1_TYPED_UNORDERED_ACCESS_VIEW) { image->desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS; image->valid_access |= D3D12_BARRIER_ACCESS_UNORDERED_ACCESS; } } if (pCreateInfo->sharingMode == VK_SHARING_MODE_CONCURRENT && !(image->desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL) && image->desc.SampleDesc.Count == 1) image->desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_SIMULTANEOUS_ACCESS; *out = dzn_image_to_handle(image); return VK_SUCCESS; } DXGI_FORMAT dzn_image_get_dxgi_format(const struct dzn_physical_device *pdev, VkFormat format, VkImageUsageFlags usage, VkImageAspectFlags aspects) { enum pipe_format pfmt = vk_format_to_pipe_format(format); if (pdev && !pdev->support_a4b4g4r4) { if (pfmt == PIPE_FORMAT_A4R4G4B4_UNORM) return DXGI_FORMAT_B4G4R4A4_UNORM; if (pfmt == PIPE_FORMAT_A4B4G4R4_UNORM) return DXGI_FORMAT_UNKNOWN; } 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: 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; return DXGI_FORMAT_R24G8_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 if (aspects & VK_IMAGE_ASPECT_STENCIL_BIT) return DXGI_FORMAT_X24_TYPELESS_G8_UINT; else return DXGI_FORMAT_R24G8_TYPELESS; case PIPE_FORMAT_X24S8_UINT: if (usage == VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) return DXGI_FORMAT_D24_UNORM_S8_UINT; if (aspects & VK_IMAGE_ASPECT_STENCIL_BIT) return DXGI_FORMAT_X24_TYPELESS_G8_UINT; return DXGI_FORMAT_R24G8_TYPELESS; 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_DEPTH_BIT) return DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS; else if (aspects & VK_IMAGE_ASPECT_STENCIL_BIT) return DXGI_FORMAT_X32_TYPELESS_G8X24_UINT; else return DXGI_FORMAT_R32G8X24_TYPELESS; default: return dzn_pipe_to_dxgi_format(pfmt); } } DXGI_FORMAT dzn_image_get_placed_footprint_format(const struct dzn_physical_device *pdev, VkFormat format, VkImageAspectFlags aspect) { DXGI_FORMAT out = dzn_image_get_dxgi_format(pdev, 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) { struct dzn_physical_device *pdev = container_of(image->vk.base.device->physical, struct dzn_physical_device, vk); 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); 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); loc.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT; loc.PlacedFootprint.Offset = 0; loc.PlacedFootprint.Footprint.Format = dzn_image_get_placed_footprint_format(pdev, image->vk.format, aspect); loc.PlacedFootprint.Footprint.Width = ALIGN_POT(image->vk.extent.width, blkw); loc.PlacedFootprint.Footprint.Height = ALIGN_POT(image->vk.extent.height, blkh); loc.PlacedFootprint.Footprint.Depth = ALIGN_POT(image->vk.extent.depth, blkd); 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) { struct dzn_physical_device *pdev = container_of(image->vk.base.device->physical, struct dzn_physical_device, vk); uint32_t layer_count = dzn_get_layer_count(image, range); D3D12_DEPTH_STENCIL_VIEW_DESC dsv_desc = { .Format = dzn_image_get_dxgi_format(pdev, 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) { struct dzn_physical_device *pdev = container_of(image->vk.base.device->physical, struct dzn_physical_device, vk); uint32_t layer_count = dzn_get_layer_count(image, range); D3D12_RENDER_TARGET_VIEW_DESC rtv_desc = { .Format = dzn_image_get_dxgi_format(pdev, 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_COMMAND_LIST_TYPE type) { D3D12_RESOURCE_STATES shaders_access = (image->desc.Flags & D3D12_RESOURCE_FLAG_DENY_SHADER_RESOURCE) ? 0 : (type == D3D12_COMMAND_LIST_TYPE_DIRECT ? D3D12_RESOURCE_STATE_ALL_SHADER_RESOURCE : D3D12_RESOURCE_STATE_NON_PIXEL_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 type == D3D12_COMMAND_LIST_TYPE_DIRECT ? D3D12_RESOURCE_STATE_RENDER_TARGET : D3D12_RESOURCE_STATE_COMMON; 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 shaders_access; case VK_IMAGE_LAYOUT_ATTACHMENT_FEEDBACK_LOOP_OPTIMAL_EXT: return D3D12_RESOURCE_STATE_COMMON; default: unreachable("not implemented"); } } D3D12_BARRIER_LAYOUT dzn_vk_layout_to_d3d_layout(VkImageLayout layout, D3D12_COMMAND_LIST_TYPE type, VkImageAspectFlags aspect) { if (type == D3D12_COMMAND_LIST_TYPE_COPY) return D3D12_BARRIER_LAYOUT_COMMON; switch (layout) { case VK_IMAGE_LAYOUT_UNDEFINED: return D3D12_BARRIER_LAYOUT_UNDEFINED; case VK_IMAGE_LAYOUT_PREINITIALIZED: return D3D12_BARRIER_LAYOUT_COMMON; case VK_IMAGE_LAYOUT_GENERAL: case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL: case VK_IMAGE_LAYOUT_ATTACHMENT_FEEDBACK_LOOP_OPTIMAL_EXT: switch (type) { case D3D12_COMMAND_LIST_TYPE_DIRECT: return D3D12_BARRIER_LAYOUT_DIRECT_QUEUE_COMMON; case D3D12_COMMAND_LIST_TYPE_COMPUTE: return D3D12_BARRIER_LAYOUT_COMPUTE_QUEUE_COMMON; default: return D3D12_BARRIER_LAYOUT_COMMON; } case VK_IMAGE_LAYOUT_READ_ONLY_OPTIMAL: case VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL: case VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_OPTIMAL: case VK_IMAGE_LAYOUT_STENCIL_READ_ONLY_OPTIMAL: case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL: case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL: switch (type) { case D3D12_COMMAND_LIST_TYPE_DIRECT: return D3D12_BARRIER_LAYOUT_DIRECT_QUEUE_GENERIC_READ; case D3D12_COMMAND_LIST_TYPE_COMPUTE: return D3D12_BARRIER_LAYOUT_COMPUTE_QUEUE_GENERIC_READ; default: return D3D12_BARRIER_LAYOUT_GENERIC_READ; } case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL: return D3D12_BARRIER_LAYOUT_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_BARRIER_LAYOUT_DEPTH_STENCIL_WRITE; case VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL: return aspect == VK_IMAGE_ASPECT_DEPTH_BIT ? dzn_vk_layout_to_d3d_layout(VK_IMAGE_LAYOUT_READ_ONLY_OPTIMAL, type, aspect) : D3D12_BARRIER_LAYOUT_DEPTH_STENCIL_WRITE; case VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL: return aspect == VK_IMAGE_ASPECT_DEPTH_BIT ? D3D12_BARRIER_LAYOUT_DEPTH_STENCIL_WRITE : dzn_vk_layout_to_d3d_layout(VK_IMAGE_LAYOUT_READ_ONLY_OPTIMAL, type, aspect); case VK_IMAGE_LAYOUT_ATTACHMENT_OPTIMAL: return aspect == VK_IMAGE_ASPECT_COLOR_BIT ? D3D12_BARRIER_LAYOUT_RENDER_TARGET : D3D12_BARRIER_LAYOUT_DEPTH_STENCIL_WRITE; case VK_IMAGE_LAYOUT_PRESENT_SRC_KHR: case VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR: return D3D12_BARRIER_LAYOUT_PRESENT; case VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR: return D3D12_BARRIER_LAYOUT_SHADING_RATE_SOURCE; default: assert(!"Unexpected layout"); return D3D12_BARRIER_LAYOUT_COMMON; } } 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(pdev, orig_fmt, usage, aspect); DXGI_FORMAT new_dxgi = dzn_image_get_dxgi_format(pdev, 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); #ifdef DZN_USE_WSI_PLATFORM const VkBindImageMemorySwapchainInfoKHR *swapchain_info = vk_find_struct_const(pBindInfos[i].pNext, BIND_IMAGE_MEMORY_SWAPCHAIN_INFO_KHR); if (swapchain_info && swapchain_info->swapchain != VK_NULL_HANDLE) { struct dzn_image *swapchain_img = dzn_image_from_handle(wsi_common_get_image(swapchain_info->swapchain, swapchain_info->imageIndex)); mem = swapchain_img->mem; } #endif image->mem = mem; HRESULT hres = S_OK; if (mem->dedicated_res) { assert(pBindInfos[i].memoryOffset == 0); image->res = mem->dedicated_res; ID3D12Resource_AddRef(image->res); } else if (device->dev10 && image->castable_format_count > 0) { D3D12_RESOURCE_DESC1 desc = { .Dimension = image->desc.Dimension, .Alignment = image->desc.Alignment, .Width = image->desc.Width, .Height = image->desc.Height, .DepthOrArraySize = image->desc.DepthOrArraySize, .MipLevels = image->desc.MipLevels, .Format = image->desc.Format, .SampleDesc = image->desc.SampleDesc, .Layout = image->desc.Layout, .Flags = image->desc.Flags | mem->res_flags, }; hres = ID3D12Device10_CreatePlacedResource2(device->dev10, mem->heap, bind_info->memoryOffset, &desc, D3D12_BARRIER_LAYOUT_COMMON, NULL, image->castable_format_count, image->castable_formats, &IID_ID3D12Resource, (void **)&image->res); } else { D3D12_RESOURCE_DESC desc = image->desc; desc.Flags |= mem->res_flags; hres = ID3D12Device1_CreatePlacedResource(device->dev, mem->heap, bind_info->memoryOffset, &desc, D3D12_RESOURCE_STATE_COMMON, NULL, &IID_ID3D12Resource, (void **)&image->res); } if (FAILED(hres)) return vk_error(device, VK_ERROR_OUT_OF_DEVICE_MEMORY); } 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) { vk_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; requirements->requiresDedicatedAllocation = image->vk.external_handle_types != 0; requirements->prefersDedicatedAllocation = requirements->requiresDedicatedAllocation || image->vk.tiling == VK_IMAGE_TILING_OPTIMAL; break; } default: vk_debug_ignored_stype(ext->sType); break; } } D3D12_RESOURCE_ALLOCATION_INFO info; if (device->dev12 && image->castable_format_count > 0) { D3D12_RESOURCE_DESC1 desc1; memcpy(&desc1, &image->desc, sizeof(image->desc)); memset(&desc1.SamplerFeedbackMipRegion, 0, sizeof(desc1.SamplerFeedbackMipRegion)); info = dzn_ID3D12Device12_GetResourceAllocationInfo3(device->dev12, 0, 1, &desc1, &image->castable_format_count, (const DXGI_FORMAT *const *) &image->castable_formats, NULL); } else { info = dzn_ID3D12Device4_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, image->vk.external_handle_types != 0), }; /* * 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) { struct dzn_physical_device *pdev = container_of(iview->vk.base.device->physical, struct dzn_physical_device, vk); uint32_t plane_slice = (iview->vk.aspects & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) == 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 from_3d_image = iview->vk.image->image_type == VK_IMAGE_TYPE_3D; bool use_array = iview->vk.base_array_layer > 0 || (iview->vk.layer_count / layers_per_elem) > 1; iview->srv_desc = (D3D12_SHADER_RESOURCE_VIEW_DESC) { .Format = dzn_image_get_dxgi_format(pdev, iview->vk.format, iview->vk.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) { if (pdev->support_a4b4g4r4) { static const D3D12_SHADER_COMPONENT_MAPPING bgra4_remap[] = { D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_2, 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_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]]; } else { 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]]; } } else if (iview->vk.aspects & VK_IMAGE_ASPECT_STENCIL_BIT) { /* D3D puts stencil in G, not R. Requests for R should be routed to G and vice versa. */ for (uint32_t i = 0; i < ARRAY_SIZE(swz); i++) { if (swz[i] == D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_0) swz[i] = D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_1; else if (swz[i] == D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_1) swz[i] = D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_0; } } else if (iview->vk.view_format == VK_FORMAT_BC1_RGB_SRGB_BLOCK || iview->vk.view_format == VK_FORMAT_BC1_RGB_UNORM_BLOCK) { /* D3D has no opaque version of these; force alpha to 1 */ for (uint32_t i = 0; i < ARRAY_SIZE(swz); i++) { if (swz[i] == D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_3) swz[i] = D3D12_SHADER_COMPONENT_MAPPING_FORCE_VALUE_1; } } 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; iview->srv_desc.Texture1DArray.ResourceMinLODClamp = 0.0f; } 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; iview->srv_desc.Texture1D.ResourceMinLODClamp = 0.0f; } break; case VK_IMAGE_VIEW_TYPE_2D_ARRAY: case VK_IMAGE_VIEW_TYPE_2D: if (from_3d_image) { 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; iview->srv_desc.Texture3D.ResourceMinLODClamp = 0.0f; } else 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; iview->srv_desc.Texture2DArray.ResourceMinLODClamp = 0.0f; } 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; iview->srv_desc.Texture2D.ResourceMinLODClamp = 0.0f; } 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; iview->srv_desc.TextureCubeArray.ResourceMinLODClamp = 0.0f; } 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; iview->srv_desc.TextureCube.ResourceMinLODClamp = 0.0f; } 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; iview->srv_desc.Texture3D.ResourceMinLODClamp = 0.0f; break; default: unreachable("Invalid view type"); } } static void dzn_image_view_prepare_uav_desc(struct dzn_image_view *iview) { struct dzn_physical_device *pdev = container_of(iview->vk.base.device->physical, struct dzn_physical_device, vk); 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(pdev, 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) { struct dzn_physical_device *pdev = container_of(iview->vk.base.device->physical, struct dzn_physical_device, vk); 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; iview->rtv_desc = (D3D12_RENDER_TARGET_VIEW_DESC) { .Format = dzn_image_get_dxgi_format(pdev, 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) { struct dzn_physical_device *pdev = container_of(iview->vk.base.device->physical, struct dzn_physical_device, vk); 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(pdev, 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)); /* We remove this bit on depth textures, so skip creating a UAV for those */ if ((iview->vk.usage & VK_IMAGE_USAGE_STORAGE_BIT) && !(image->desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS)) iview->vk.usage &= ~VK_IMAGE_USAGE_STORAGE_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); dzn_device_descriptor_heap_free_slot(device, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, iview->srv_bindless_slot); dzn_device_descriptor_heap_free_slot(device, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, iview->uav_bindless_slot); 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) { VK_FROM_HANDLE(dzn_image, image, pCreateInfo->image); 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); iview->srv_bindless_slot = iview->uav_bindless_slot = -1; if (device->bindless) { if (!(image->desc.Flags & D3D12_RESOURCE_FLAG_DENY_SHADER_RESOURCE)) { iview->srv_bindless_slot = dzn_device_descriptor_heap_alloc_slot(device, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); if (iview->srv_bindless_slot < 0) { dzn_image_view_destroy(iview, pAllocator); return vk_error(device, VK_ERROR_OUT_OF_DEVICE_MEMORY); } dzn_descriptor_heap_write_image_view_desc(device, &device->device_heaps[D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV].heap, iview->srv_bindless_slot, false, false, iview); } if (iview->vk.usage & VK_IMAGE_USAGE_STORAGE_BIT) { iview->uav_bindless_slot = dzn_device_descriptor_heap_alloc_slot(device, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); if (iview->uav_bindless_slot < 0) { dzn_image_view_destroy(iview, pAllocator); return vk_error(device, VK_ERROR_OUT_OF_DEVICE_MEMORY); } dzn_descriptor_heap_write_image_view_desc(device, &device->device_heaps[D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV].heap, iview->uav_bindless_slot, true, true, iview); } } *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); dzn_device_descriptor_heap_free_slot(device, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, bview->srv_bindless_slot); dzn_device_descriptor_heap_free_slot(device, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, bview->uav_bindless_slot); 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; bview->srv_bindless_slot = bview->uav_bindless_slot = -1; 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 (device->bindless) { bview->srv_bindless_slot = dzn_device_descriptor_heap_alloc_slot(device, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); if (bview->srv_bindless_slot < 0) { dzn_buffer_view_destroy(bview, pAllocator); return vk_error(device, VK_ERROR_OUT_OF_DEVICE_MEMORY); } dzn_descriptor_heap_write_buffer_view_desc(device, &device->device_heaps[D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV].heap, bview->srv_bindless_slot, false, bview); } } 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, }, }; if (device->bindless) { bview->uav_bindless_slot = dzn_device_descriptor_heap_alloc_slot(device, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); if (bview->uav_bindless_slot < 0) { dzn_buffer_view_destroy(bview, pAllocator); return vk_error(device, VK_ERROR_OUT_OF_DEVICE_MEMORY); } dzn_descriptor_heap_write_buffer_view_desc(device, &device->device_heaps[D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV].heap, bview->uav_bindless_slot, true, bview); } } *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); }