[dxvk] Implemented typeless resolve

This should allow a large number of Unity-based games to
render at least a menu.
This commit is contained in:
Philip Rebohle 2018-02-21 01:04:28 +01:00
parent cb3daaf856
commit b419b3dfbd
No known key found for this signature in database
GPG Key ID: C8CC613427A31C99
5 changed files with 263 additions and 54 deletions

View File

@ -904,40 +904,42 @@ namespace dxvk {
if (format == VK_FORMAT_UNDEFINED)
format = srcImage->info().format;
VkImageSubresourceRange dstSubresourceRange = {
dstSubresources.aspectMask,
dstSubresources.mipLevel, 1,
dstSubresources.baseArrayLayer,
dstSubresources.layerCount };
VkImageSubresourceRange srcSubresourceRange = {
srcSubresources.aspectMask,
srcSubresources.mipLevel, 1,
srcSubresources.baseArrayLayer,
srcSubresources.layerCount };
// We only support resolving to the entire image
// area, so we might as well discard its contents
m_barriers.accessImage(
dstImage, dstSubresourceRange,
VK_IMAGE_LAYOUT_UNDEFINED,
dstImage->info().stages,
dstImage->info().access,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
VK_PIPELINE_STAGE_TRANSFER_BIT,
VK_ACCESS_TRANSFER_WRITE_BIT);
m_barriers.accessImage(
srcImage, srcSubresourceRange,
srcImage->info().layout,
srcImage->info().stages,
srcImage->info().access,
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
VK_PIPELINE_STAGE_TRANSFER_BIT,
VK_ACCESS_TRANSFER_READ_BIT);
m_barriers.recordCommands(m_cmd);
if (srcImage->info().format == format
&& dstImage->info().format == format) {
if (dstImage->info().format == format
&& srcImage->info().format == format) {
// Use the built-in Vulkan resolve function if the image
// formats both match the format of the resolve operation.
VkImageSubresourceRange dstSubresourceRange = {
dstSubresources.aspectMask,
dstSubresources.mipLevel, 1,
dstSubresources.baseArrayLayer,
dstSubresources.layerCount };
VkImageSubresourceRange srcSubresourceRange = {
srcSubresources.aspectMask,
srcSubresources.mipLevel, 1,
srcSubresources.baseArrayLayer,
srcSubresources.layerCount };
// We only support resolving to the entire image
// area, so we might as well discard its contents
m_barriers.accessImage(
dstImage, dstSubresourceRange,
VK_IMAGE_LAYOUT_UNDEFINED,
dstImage->info().stages,
dstImage->info().access,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
VK_PIPELINE_STAGE_TRANSFER_BIT,
VK_ACCESS_TRANSFER_WRITE_BIT);
m_barriers.accessImage(
srcImage, srcSubresourceRange,
srcImage->info().layout,
srcImage->info().stages,
srcImage->info().access,
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
VK_PIPELINE_STAGE_TRANSFER_BIT,
VK_ACCESS_TRANSFER_READ_BIT);
m_barriers.recordCommands(m_cmd);
VkImageResolve imageRegion;
imageRegion.srcSubresource = srcSubresources;
imageRegion.srcOffset = VkOffset3D { 0, 0, 0 };
@ -951,27 +953,48 @@ namespace dxvk {
dstImage->handle(),
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
1, &imageRegion);
} else {
// TODO implement
}
m_barriers.accessImage(
dstImage, dstSubresourceRange,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
VK_PIPELINE_STAGE_TRANSFER_BIT,
VK_ACCESS_TRANSFER_WRITE_BIT,
dstImage->info().layout,
dstImage->info().stages,
dstImage->info().access);
m_barriers.accessImage(
srcImage, srcSubresourceRange,
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
VK_PIPELINE_STAGE_TRANSFER_BIT,
VK_ACCESS_TRANSFER_READ_BIT,
srcImage->info().layout,
srcImage->info().stages,
srcImage->info().access);
m_barriers.recordCommands(m_cmd);
m_barriers.accessImage(
dstImage, dstSubresourceRange,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
VK_PIPELINE_STAGE_TRANSFER_BIT,
VK_ACCESS_TRANSFER_WRITE_BIT,
dstImage->info().layout,
dstImage->info().stages,
dstImage->info().access);
m_barriers.accessImage(
srcImage, srcSubresourceRange,
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
VK_PIPELINE_STAGE_TRANSFER_BIT,
VK_ACCESS_TRANSFER_READ_BIT,
srcImage->info().layout,
srcImage->info().stages,
srcImage->info().access);
m_barriers.recordCommands(m_cmd);
} else {
// The trick here is to submit an empty render pass which
// performs the resolve op on properly typed image views.
const Rc<DxvkMetaResolveFramebuffer> fb =
new DxvkMetaResolveFramebuffer(m_device->vkd(),
dstImage, dstSubresources,
srcImage, srcSubresources, format);
VkRenderPassBeginInfo info;
info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
info.pNext = nullptr;
info.renderPass = fb->renderPass();
info.framebuffer = fb->framebuffer();
info.renderArea = VkRect2D { { 0, 0 }, {
dstImage->info().extent.width,
dstImage->info().extent.height } };
info.clearValueCount = 0;
info.pClearValues = nullptr;
m_cmd->cmdBeginRenderPass(&info, VK_SUBPASS_CONTENTS_INLINE);
m_cmd->cmdEndRenderPass();
m_cmd->trackResource(fb);
}
}

View File

@ -6,6 +6,7 @@
#include "dxvk_context_state.h"
#include "dxvk_data.h"
#include "dxvk_event.h"
#include "dxvk_meta_resolve.h"
#include "dxvk_query.h"
#include "dxvk_query_pool.h"
#include "dxvk_util.h"

View File

@ -0,0 +1,134 @@
#include "dxvk_meta_resolve.h"
namespace dxvk {
DxvkMetaResolveFramebuffer::DxvkMetaResolveFramebuffer(
const Rc<vk::DeviceFn>& vkd,
const Rc<DxvkImage>& dstImage,
VkImageSubresourceLayers dstLayers,
const Rc<DxvkImage>& srcImage,
VkImageSubresourceLayers srcLayers,
VkFormat format)
: m_vkd(vkd) {
// Create a render pass with one render
// target and one resolve attachment.
std::array<VkAttachmentDescription, 2> attachmentInfos = {{
VkAttachmentDescription {
0, format, dstImage->info().sampleCount,
VK_ATTACHMENT_LOAD_OP_DONT_CARE,
VK_ATTACHMENT_STORE_OP_STORE,
VK_ATTACHMENT_LOAD_OP_DONT_CARE,
VK_ATTACHMENT_STORE_OP_STORE,
VK_IMAGE_LAYOUT_UNDEFINED,
dstImage->info().layout },
VkAttachmentDescription {
0, format, srcImage->info().sampleCount,
VK_ATTACHMENT_LOAD_OP_LOAD,
VK_ATTACHMENT_STORE_OP_STORE,
VK_ATTACHMENT_LOAD_OP_LOAD,
VK_ATTACHMENT_STORE_OP_STORE,
srcImage->info().layout,
srcImage->info().layout },
}};
// Make sure layout transitions are correctly ordered
std::array<VkSubpassDependency, 2> subpassDeps = {{
{ VK_SUBPASS_EXTERNAL, 0,
srcImage->info().stages | dstImage->info().stages,
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
srcImage->info().access | dstImage->info().access,
VK_ACCESS_COLOR_ATTACHMENT_READ_BIT |
VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, 0 },
{ 0, VK_SUBPASS_EXTERNAL,
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
srcImage->info().stages | dstImage->info().stages,
VK_ACCESS_COLOR_ATTACHMENT_READ_BIT |
VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
srcImage->info().access | dstImage->info().access, 0 },
}};
VkAttachmentReference dstAttachmentRef = { 0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL };
VkAttachmentReference srcAttachmentRef = { 1, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL };
VkSubpassDescription spInfo;
spInfo.flags = 0;
spInfo.inputAttachmentCount = 0;
spInfo.pInputAttachments = nullptr;
spInfo.colorAttachmentCount = 1;
spInfo.pColorAttachments = &srcAttachmentRef;
spInfo.pResolveAttachments = &dstAttachmentRef;
spInfo.pDepthStencilAttachment = nullptr;
spInfo.preserveAttachmentCount = 0;
spInfo.pPreserveAttachments = nullptr;
VkRenderPassCreateInfo rpInfo;
rpInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
rpInfo.pNext = nullptr;
rpInfo.flags = 0;
rpInfo.attachmentCount = attachmentInfos.size();
rpInfo.pAttachments = attachmentInfos.data();
rpInfo.subpassCount = 1;
rpInfo.pSubpasses = &spInfo;
rpInfo.dependencyCount = subpassDeps.size();
rpInfo.pDependencies = subpassDeps.data();
m_vkd->vkCreateRenderPass(m_vkd->device(), &rpInfo, nullptr, &m_renderPass);
// Create views for the destination and source image
VkImageViewCreateInfo dstInfo;
dstInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
dstInfo.pNext = nullptr;
dstInfo.flags = 0;
dstInfo.image = dstImage->handle();
dstInfo.viewType = VK_IMAGE_VIEW_TYPE_2D_ARRAY;
dstInfo.format = format;
dstInfo.components = VkComponentMapping {
VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY,
VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY };
dstInfo.subresourceRange = VkImageSubresourceRange {
dstLayers.aspectMask, dstLayers.mipLevel, 1,
dstLayers.baseArrayLayer, dstLayers.layerCount };
VkImageViewCreateInfo srcInfo;
srcInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
srcInfo.pNext = nullptr;
srcInfo.flags = 0;
srcInfo.image = srcImage->handle();
srcInfo.viewType = VK_IMAGE_VIEW_TYPE_2D_ARRAY;
srcInfo.format = format;
srcInfo.components = VkComponentMapping {
VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY,
VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY };
srcInfo.subresourceRange = VkImageSubresourceRange {
srcLayers.aspectMask, srcLayers.mipLevel, 1,
srcLayers.baseArrayLayer, srcLayers.layerCount };
m_vkd->vkCreateImageView(m_vkd->device(), &dstInfo, nullptr, &m_dstImageView);
m_vkd->vkCreateImageView(m_vkd->device(), &srcInfo, nullptr, &m_srcImageView);
// Create a framebuffer containing the two image views
std::array<VkImageView, 2> attachments = {{ m_dstImageView, m_srcImageView }};
VkFramebufferCreateInfo fboInfo;
fboInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
fboInfo.pNext = nullptr;
fboInfo.flags = 0;
fboInfo.renderPass = m_renderPass;
fboInfo.attachmentCount = attachments.size();
fboInfo.pAttachments = attachments.data();
fboInfo.width = dstImage->info().extent.width;
fboInfo.height = dstImage->info().extent.height;
fboInfo.layers = dstLayers.layerCount;
m_vkd->vkCreateFramebuffer(m_vkd->device(), &fboInfo, nullptr, &m_framebuffer);
}
DxvkMetaResolveFramebuffer::~DxvkMetaResolveFramebuffer() {
m_vkd->vkDestroyFramebuffer(m_vkd->device(), m_framebuffer, nullptr);
m_vkd->vkDestroyImageView (m_vkd->device(), m_srcImageView, nullptr);
m_vkd->vkDestroyImageView (m_vkd->device(), m_dstImageView, nullptr);
m_vkd->vkDestroyRenderPass (m_vkd->device(), m_renderPass, nullptr);
}
}

View File

@ -0,0 +1,50 @@
#pragma once
#include <unordered_map>
#include "dxvk_barrier.h"
#include "dxvk_cmdlist.h"
#include "dxvk_resource.h"
namespace dxvk {
/**
* \brief Meta resolve framebuffer
*
* Stores a framebuffer and image view objects
* for a meta resolve operation. Can be tracked.
*/
class DxvkMetaResolveFramebuffer : public DxvkResource {
public:
DxvkMetaResolveFramebuffer(
const Rc<vk::DeviceFn>& vkd,
const Rc<DxvkImage>& dstImage,
VkImageSubresourceLayers dstLayers,
const Rc<DxvkImage>& srcImage,
VkImageSubresourceLayers srcLayers,
VkFormat format);
~DxvkMetaResolveFramebuffer();
VkRenderPass renderPass() const {
return m_renderPass;
}
VkFramebuffer framebuffer() const {
return m_framebuffer;
}
private:
const Rc<vk::DeviceFn> m_vkd;
VkRenderPass m_renderPass;
VkImageView m_dstImageView;
VkImageView m_srcImageView;
VkFramebuffer m_framebuffer;
};
}

View File

@ -26,6 +26,7 @@ dxvk_src = files([
'dxvk_lifetime.cpp',
'dxvk_main.cpp',
'dxvk_memory.cpp',
'dxvk_meta_resolve.cpp',
'dxvk_options.cpp',
'dxvk_pipecache.cpp',
'dxvk_pipelayout.cpp',