mirror of
https://github.com/EduApps-CDG/OpenDX
synced 2024-12-30 09:45:37 +01:00
Rather than creating just one image view per DxvkImageView, we create views for all compatible types in an attempt to work around game bugs in Diablo 3, Far Cry 5, Nier Automata, Dishonored 2, Trackmania etc., which bind incompatible resource views to some resource slots.
183 lines
7.1 KiB
C++
183 lines
7.1 KiB
C++
#include "dxvk_image.h"
|
|
|
|
namespace dxvk {
|
|
|
|
DxvkImage::DxvkImage(
|
|
const Rc<vk::DeviceFn>& vkd,
|
|
const DxvkImageCreateInfo& createInfo,
|
|
DxvkMemoryAllocator& memAlloc,
|
|
VkMemoryPropertyFlags memFlags)
|
|
: m_vkd(vkd), m_info(createInfo), m_memFlags(memFlags) {
|
|
|
|
VkImageCreateInfo info;
|
|
info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
|
|
info.pNext = nullptr;
|
|
info.flags = createInfo.flags;
|
|
info.imageType = createInfo.type;
|
|
info.format = createInfo.format;
|
|
info.extent = createInfo.extent;
|
|
info.mipLevels = createInfo.mipLevels;
|
|
info.arrayLayers = createInfo.numLayers;
|
|
info.samples = createInfo.sampleCount;
|
|
info.tiling = createInfo.tiling;
|
|
info.usage = createInfo.usage;
|
|
info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
|
info.queueFamilyIndexCount = 0;
|
|
info.pQueueFamilyIndices = nullptr;
|
|
info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
|
|
|
if (m_vkd->vkCreateImage(m_vkd->device(),
|
|
&info, nullptr, &m_image) != VK_SUCCESS) {
|
|
throw DxvkError(str::format(
|
|
"DxvkImage: Failed to create image:",
|
|
"\n Type: ", info.imageType,
|
|
"\n Format: ", info.format,
|
|
"\n Extent: ", "(", info.extent.width,
|
|
",", info.extent.height,
|
|
",", info.extent.depth, ")",
|
|
"\n Mip levels: ", info.mipLevels,
|
|
"\n Array layers: ", info.arrayLayers,
|
|
"\n Samples: ", info.samples,
|
|
"\n Usage: ", info.usage,
|
|
"\n Tiling: ", info.tiling));
|
|
}
|
|
|
|
// Get memory requirements for the image. We may enforce strict
|
|
// alignment on non-linear images in order not to violate the
|
|
// bufferImageGranularity limit, which may be greater than the
|
|
// required resource memory alignment on some GPUs.
|
|
VkMemoryRequirements memReq;
|
|
|
|
m_vkd->vkGetImageMemoryRequirements(
|
|
m_vkd->device(), m_image, &memReq);
|
|
|
|
if (info.tiling != VK_IMAGE_TILING_LINEAR) {
|
|
memReq.size = align(memReq.size, memAlloc.bufferImageGranularity());
|
|
memReq.alignment = align(memReq.alignment , memAlloc.bufferImageGranularity());
|
|
}
|
|
|
|
m_memory = memAlloc.alloc(memReq, memFlags);
|
|
|
|
// Try to bind the allocated memory slice to the image
|
|
if (m_vkd->vkBindImageMemory(m_vkd->device(),
|
|
m_image, m_memory.memory(), m_memory.offset()) != VK_SUCCESS)
|
|
throw DxvkError("DxvkImage::DxvkImage: Failed to bind device memory");
|
|
}
|
|
|
|
|
|
DxvkImage::DxvkImage(
|
|
const Rc<vk::DeviceFn>& vkd,
|
|
const DxvkImageCreateInfo& info,
|
|
VkImage image)
|
|
: m_vkd(vkd), m_info(info), m_image(image) {
|
|
|
|
}
|
|
|
|
|
|
DxvkImage::~DxvkImage() {
|
|
// This is a bit of a hack to determine whether
|
|
// the image is implementation-handled or not
|
|
if (m_memory.memory() != VK_NULL_HANDLE)
|
|
m_vkd->vkDestroyImage(m_vkd->device(), m_image, nullptr);
|
|
}
|
|
|
|
|
|
DxvkImageView::DxvkImageView(
|
|
const Rc<vk::DeviceFn>& vkd,
|
|
const Rc<DxvkImage>& image,
|
|
const DxvkImageViewCreateInfo& info)
|
|
: m_vkd(vkd), m_image(image), m_info(info) {
|
|
// Since applications tend to bind views
|
|
for (uint32_t i = 0; i < ViewCount; i++)
|
|
m_views[i] = VK_NULL_HANDLE;
|
|
|
|
switch (info.type) {
|
|
case VK_IMAGE_VIEW_TYPE_1D:
|
|
case VK_IMAGE_VIEW_TYPE_1D_ARRAY: {
|
|
this->createView(VK_IMAGE_VIEW_TYPE_1D, 1);
|
|
this->createView(VK_IMAGE_VIEW_TYPE_1D_ARRAY, info.numLayers);
|
|
} 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: {
|
|
this->createView(VK_IMAGE_VIEW_TYPE_2D, 1);
|
|
this->createView(VK_IMAGE_VIEW_TYPE_2D_ARRAY, info.numLayers);
|
|
|
|
if (m_image->info().flags & VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT) {
|
|
uint32_t cubeCount = info.numLayers / 6;
|
|
|
|
if (cubeCount > 0) {
|
|
this->createView(VK_IMAGE_VIEW_TYPE_CUBE, 6);
|
|
this->createView(VK_IMAGE_VIEW_TYPE_CUBE_ARRAY, 6 * cubeCount);
|
|
}
|
|
}
|
|
} break;
|
|
|
|
case VK_IMAGE_VIEW_TYPE_3D: {
|
|
this->createView(VK_IMAGE_VIEW_TYPE_3D, 1);
|
|
|
|
if (m_image->info().flags & VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT_KHR) {
|
|
this->createView(VK_IMAGE_VIEW_TYPE_2D, 1);
|
|
this->createView(VK_IMAGE_VIEW_TYPE_2D_ARRAY, m_image->info().extent.depth);
|
|
}
|
|
} break;
|
|
|
|
default:
|
|
throw DxvkError(str::format("DxvkImageView: Invalid view type: ", info.type));
|
|
}
|
|
}
|
|
|
|
|
|
DxvkImageView::~DxvkImageView() {
|
|
for (uint32_t i = 0; i < ViewCount; i++)
|
|
m_vkd->vkDestroyImageView(m_vkd->device(), m_views[i], nullptr);
|
|
}
|
|
|
|
|
|
void DxvkImageView::createView(VkImageViewType type, uint32_t numLayers) {
|
|
VkImageSubresourceRange subresourceRange;
|
|
subresourceRange.aspectMask = m_info.aspect;
|
|
subresourceRange.baseMipLevel = m_info.minLevel;
|
|
subresourceRange.levelCount = m_info.numLevels;
|
|
subresourceRange.baseArrayLayer = m_info.minLayer;
|
|
subresourceRange.layerCount = numLayers;
|
|
|
|
VkImageViewCreateInfo viewInfo;
|
|
viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
|
|
viewInfo.pNext = nullptr;
|
|
viewInfo.flags = 0;
|
|
viewInfo.image = m_image->handle();
|
|
viewInfo.viewType = type;
|
|
viewInfo.format = m_info.format;
|
|
viewInfo.components = m_info.swizzle;
|
|
viewInfo.subresourceRange = subresourceRange;
|
|
|
|
if (m_vkd->vkCreateImageView(m_vkd->device(),
|
|
&viewInfo, nullptr, &m_views[type]) != VK_SUCCESS) {
|
|
throw DxvkError(str::format(
|
|
"DxvkImageView: Failed to create image view:"
|
|
"\n View type: ", viewInfo.viewType,
|
|
"\n View format: ", viewInfo.format,
|
|
"\n Subresources: ",
|
|
"\n Aspect mask: ", std::hex, viewInfo.subresourceRange.aspectMask,
|
|
"\n Mip levels: ", viewInfo.subresourceRange.baseMipLevel, " - ",
|
|
viewInfo.subresourceRange.levelCount,
|
|
"\n Array layers: ", viewInfo.subresourceRange.baseArrayLayer, " - ",
|
|
viewInfo.subresourceRange.layerCount,
|
|
"\n Image properties:",
|
|
"\n Type: ", m_image->info().type,
|
|
"\n Format: ", m_image->info().format,
|
|
"\n Extent: ", "(", m_image->info().extent.width,
|
|
",", m_image->info().extent.height,
|
|
",", m_image->info().extent.depth, ")",
|
|
"\n Mip levels: ", m_image->info().mipLevels,
|
|
"\n Array layers: ", m_image->info().numLayers,
|
|
"\n Samples: ", m_image->info().sampleCount,
|
|
"\n Usage: ", std::hex, m_image->info().usage,
|
|
"\n Tiling: ", m_image->info().tiling));
|
|
}
|
|
}
|
|
|
|
} |