1221 lines
46 KiB
C++
1221 lines
46 KiB
C++
/*
|
||
* 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);
|
||
}
|