mesa/src/microsoft/vulkan/dzn_image.cpp

1221 lines
46 KiB
C++
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* 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"
static void
dzn_image_destroy(dzn_image *image,
const VkAllocationCallbacks *pAllocator)
{
if (!image)
return;
dzn_device *device = container_of(image->vk.base.device, dzn_device, vk);
if (image->res)
image->res->Release();
vk_image_finish(&image->vk);
vk_free2(&device->vk.alloc, pAllocator, image);
}
static VkResult
dzn_image_create(dzn_device *device,
const VkImageCreateInfo *pCreateInfo,
const VkAllocationCallbacks *pAllocator,
VkImage *out)
{
dzn_image *image = (dzn_image *)
vk_zalloc2(&device->vk.alloc, pAllocator, sizeof(*image), 8,
VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
dzn_physical_device *pdev =
container_of(device->vk.physical, dzn_physical_device, vk);
if (!image)
return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
const VkExternalMemoryImageCreateInfo *create_info =
(const VkExternalMemoryImageCreateInfo *)
vk_find_struct_const(pCreateInfo->pNext, EXTERNAL_MEMORY_IMAGE_CREATE_INFO);
#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;
device->dev->GetCopyableFootprints(&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->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 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 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);
}
uint32_t
dzn_image_get_subresource_index(const 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 dzn_image *image,
const VkImageSubresourceLayers *subres,
VkImageAspectFlagBits aspect,
uint32_t layer)
{
D3D12_TEXTURE_COPY_LOCATION loc = {
.pResource = image->res,
};
assert((subres->aspectMask & aspect) != 0);
VkFormat format = dzn_image_get_plane_format(image->vk.format, aspect);
if (image->desc.Dimension == D3D12_RESOURCE_DIMENSION_BUFFER) {
VkImageUsageFlags usage =
VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
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 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;
}
return dsv_desc;
}
D3D12_RENDER_TARGET_VIEW_DESC
dzn_image_get_rtv_desc(const 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 = layer_count;
break;
}
return rtv_desc;
}
D3D12_RESOURCE_STATES
dzn_image_layout_to_state(VkImageLayout layout)
{
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:
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;
case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL:
return D3D12_RESOURCE_STATE_ALL_SHADER_RESOURCE;
default:
unreachable("not implemented");
}
}
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 dzn_image *
dzn_swapchain_get_image(dzn_device *device,
VkSwapchainKHR swapchain,
uint32_t index)
{
uint32_t n_images = index + 1;
STACK_ARRAY(VkImage, images, n_images);
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;
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(device->dev->CreatePlacedResource(mem->heap,
bind_info->memoryOffset,
&image->desc,
mem->initial_state,
NULL, IID_PPV_ARGS(&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);
dzn_physical_device *pdev =
container_of(device->vk.physical, 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 = device->dev->GetResourceAllocationInfo(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;
device->dev->GetCopyableFootprints(&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(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(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(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;
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 (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(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(dzn_image_view *iview)
{
vk_image_view_finish(&iview->vk);
}
void
dzn_image_view_init(dzn_device *device,
dzn_image_view *iview,
const VkImageViewCreateInfo *pCreateInfo)
{
VK_FROM_HANDLE(dzn_image, image, pCreateInfo->image);
const VkImageSubresourceRange *range = &pCreateInfo->subresourceRange;
uint32_t level_count = dzn_get_level_count(image, range);
uint32_t layer_count = dzn_get_layer_count(image, range);
uint32_t plane_slice =
pCreateInfo->subresourceRange.aspectMask & VK_IMAGE_ASPECT_STENCIL_BIT ? 1 : 0;
vk_image_view_init(&device->vk, &iview->vk, pCreateInfo);
assert(layer_count > 0);
assert(range->baseMipLevel < image->vk.mip_levels);
/* View usage should be a subset of image usage */
assert(image->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 (image->vk.usage & VK_IMAGE_USAGE_STORAGE_BIT)
dzn_image_view_prepare_uav_desc(iview);
if (image->vk.usage & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT)
dzn_image_view_prepare_rtv_desc(iview);
if (image->vk.usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)
dzn_image_view_prepare_dsv_desc(iview);
}
static void
dzn_image_view_destroy(dzn_image_view *iview,
const VkAllocationCallbacks *pAllocator)
{
if (!iview)
return;
dzn_device *device = container_of(iview->vk.base.device, dzn_device, vk);
vk_image_view_finish(&iview->vk);
vk_free2(&device->vk.alloc, pAllocator, iview);
}
static VkResult
dzn_image_view_create(dzn_device *device,
const VkImageViewCreateInfo *pCreateInfo,
const VkAllocationCallbacks *pAllocator,
VkImageView *out)
{
dzn_image_view *iview = (dzn_image_view *)
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(dzn_buffer_view *bview,
const VkAllocationCallbacks *pAllocator)
{
if (!bview)
return;
dzn_device *device = container_of(bview->base.device, dzn_device, vk);
vk_object_base_finish(&bview->base);
vk_free2(&device->vk.alloc, pAllocator, bview);
}
static VkResult
dzn_buffer_view_create(dzn_device *device,
const VkBufferViewCreateInfo *pCreateInfo,
const VkAllocationCallbacks *pAllocator,
VkBufferView *out)
{
VK_FROM_HANDLE(dzn_buffer, buf, pCreateInfo->buffer);
dzn_buffer_view *bview = (dzn_buffer_view *)
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);
}