1
0
mirror of https://github.com/doitsujin/dxvk.git synced 2025-01-31 14:52:11 +01:00

[dxvk] Use new meta copy for depth <> color image copies

This commit is contained in:
Philip Rebohle 2018-09-27 11:31:53 +02:00
parent fad2e13882
commit 509e6f1abf
No known key found for this signature in database
GPG Key ID: C8CC613427A31C99
5 changed files with 358 additions and 130 deletions

View File

@ -10,11 +10,13 @@ namespace dxvk {
const Rc<DxvkDevice>& device,
const Rc<DxvkPipelineManager>& pipelineManager,
const Rc<DxvkMetaClearObjects>& metaClearObjects,
const Rc<DxvkMetaCopyObjects>& metaCopyObjects,
const Rc<DxvkMetaMipGenObjects>& metaMipGenObjects,
const Rc<DxvkMetaResolveObjects>& metaResolveObjects)
: m_device (device),
m_pipeMgr (pipelineManager),
m_metaClear (metaClearObjects),
m_metaCopy (metaCopyObjects),
m_metaMipGen (metaMipGenObjects),
m_metaResolve (metaResolveObjects),
m_queries (device->vkd()) { }
@ -683,139 +685,17 @@ namespace dxvk {
VkExtent3D extent) {
this->spillRenderPass();
VkImageSubresourceRange dstSubresourceRange = {
dstSubresource.aspectMask,
dstSubresource.mipLevel, 1,
dstSubresource.baseArrayLayer,
dstSubresource.layerCount };
VkImageSubresourceRange srcSubresourceRange = {
srcSubresource.aspectMask,
srcSubresource.mipLevel, 1,
srcSubresource.baseArrayLayer,
srcSubresource.layerCount };
if (m_barriers.isImageDirty(dstImage, dstSubresourceRange, DxvkAccess::Write)
|| m_barriers.isImageDirty(srcImage, srcSubresourceRange, DxvkAccess::Write))
m_barriers.recordCommands(m_cmd);
VkImageLayout dstImageLayout = dstImage->pickLayout(VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
VkImageLayout srcImageLayout = srcImage->pickLayout(VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
VkImageLayout dstInitImageLayout = dstImage->info().layout;
if (dstImage->isFullSubresource(dstSubresource, extent))
dstInitImageLayout = VK_IMAGE_LAYOUT_UNDEFINED;
m_transitions.accessImage(
dstImage, dstSubresourceRange,
dstInitImageLayout, 0, 0,
dstImageLayout,
VK_PIPELINE_STAGE_TRANSFER_BIT,
VK_ACCESS_TRANSFER_WRITE_BIT);
m_transitions.accessImage(
srcImage, srcSubresourceRange,
srcImage->info().layout, 0, 0,
srcImageLayout,
VK_PIPELINE_STAGE_TRANSFER_BIT,
VK_ACCESS_TRANSFER_READ_BIT);
m_transitions.recordCommands(m_cmd);
if (dstSubresource.aspectMask == srcSubresource.aspectMask) {
VkImageCopy imageRegion;
imageRegion.srcSubresource = srcSubresource;
imageRegion.srcOffset = srcOffset;
imageRegion.dstSubresource = dstSubresource;
imageRegion.dstOffset = dstOffset;
imageRegion.extent = extent;
m_cmd->cmdCopyImage(
srcImage->handle(), srcImageLayout,
dstImage->handle(), dstImageLayout,
1, &imageRegion);
this->copyImageHw(
dstImage, dstSubresource, dstOffset,
srcImage, srcSubresource, srcOffset,
extent);
} else {
// TODO handle this case correctly
if (dstImage->info().sampleCount != VK_SAMPLE_COUNT_1_BIT) {
Logger::err("DXVK: MSAA depth<>color copies not supported");
return;
}
const VkDeviceSize transferBufferSize = std::max(
util::computeImageDataSize(dstImage->info().format, extent),
util::computeImageDataSize(srcImage->info().format, extent));
// TODO optimize away buffer creation
DxvkBufferCreateInfo tmpBufferInfo;
tmpBufferInfo.size = transferBufferSize;
tmpBufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT
| VK_BUFFER_USAGE_TRANSFER_DST_BIT;
tmpBufferInfo.stages = VK_PIPELINE_STAGE_TRANSFER_BIT;
tmpBufferInfo.access = VK_ACCESS_TRANSFER_READ_BIT
| VK_ACCESS_TRANSFER_WRITE_BIT;
Rc<DxvkBuffer> tmpBuffer = m_device->createBuffer(
tmpBufferInfo, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
DxvkPhysicalBufferSlice tmpSlice = tmpBuffer->slice();
VkBufferImageCopy bufferImageCopy;
bufferImageCopy.bufferOffset = tmpSlice.offset();
bufferImageCopy.bufferRowLength = 0;
bufferImageCopy.bufferImageHeight = 0;
bufferImageCopy.imageSubresource = srcSubresource;
bufferImageCopy.imageOffset = srcOffset;
bufferImageCopy.imageExtent = extent;
m_cmd->cmdCopyImageToBuffer(
srcImage->handle(), srcImageLayout,
tmpSlice.handle(), 1, &bufferImageCopy);
m_barriers.accessBuffer(tmpSlice,
VK_PIPELINE_STAGE_TRANSFER_BIT,
VK_ACCESS_TRANSFER_WRITE_BIT,
VK_PIPELINE_STAGE_TRANSFER_BIT,
VK_ACCESS_TRANSFER_READ_BIT);
m_barriers.recordCommands(m_cmd);
bufferImageCopy.imageSubresource = dstSubresource;
bufferImageCopy.imageOffset = dstOffset;
m_cmd->cmdCopyBufferToImage(
tmpSlice.handle(), dstImage->handle(),
dstImageLayout, 1, &bufferImageCopy);
m_barriers.accessBuffer(tmpSlice,
VK_PIPELINE_STAGE_TRANSFER_BIT,
VK_ACCESS_TRANSFER_READ_BIT,
tmpBuffer->info().stages,
tmpBuffer->info().access);
m_cmd->trackResource(tmpSlice.resource());
this->copyImageFb(
dstImage, dstSubresource, dstOffset,
srcImage, srcSubresource, srcOffset,
extent);
}
m_barriers.accessImage(
dstImage, dstSubresourceRange,
dstImageLayout,
VK_PIPELINE_STAGE_TRANSFER_BIT,
VK_ACCESS_TRANSFER_WRITE_BIT,
dstImage->info().layout,
dstImage->info().stages,
dstImage->info().access);
m_barriers.accessImage(
srcImage, srcSubresourceRange,
srcImageLayout,
VK_PIPELINE_STAGE_TRANSFER_BIT,
VK_ACCESS_TRANSFER_READ_BIT,
srcImage->info().layout,
srcImage->info().stages,
srcImage->info().access);
m_cmd->trackResource(dstImage);
m_cmd->trackResource(srcImage);
}
@ -1879,6 +1759,314 @@ namespace dxvk {
}
void DxvkContext::copyImageHw(
const Rc<DxvkImage>& dstImage,
VkImageSubresourceLayers dstSubresource,
VkOffset3D dstOffset,
const Rc<DxvkImage>& srcImage,
VkImageSubresourceLayers srcSubresource,
VkOffset3D srcOffset,
VkExtent3D extent) {
VkImageSubresourceRange dstSubresourceRange = {
dstSubresource.aspectMask,
dstSubresource.mipLevel, 1,
dstSubresource.baseArrayLayer,
dstSubresource.layerCount };
VkImageSubresourceRange srcSubresourceRange = {
srcSubresource.aspectMask,
srcSubresource.mipLevel, 1,
srcSubresource.baseArrayLayer,
srcSubresource.layerCount };
if (m_barriers.isImageDirty(dstImage, dstSubresourceRange, DxvkAccess::Write)
|| m_barriers.isImageDirty(srcImage, srcSubresourceRange, DxvkAccess::Write))
m_barriers.recordCommands(m_cmd);
VkImageLayout dstImageLayout = dstImage->pickLayout(VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
VkImageLayout srcImageLayout = srcImage->pickLayout(VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
VkImageLayout dstInitImageLayout = dstImage->info().layout;
if (dstImage->isFullSubresource(dstSubresource, extent))
dstInitImageLayout = VK_IMAGE_LAYOUT_UNDEFINED;
m_transitions.accessImage(
dstImage, dstSubresourceRange,
dstInitImageLayout, 0, 0,
dstImageLayout,
VK_PIPELINE_STAGE_TRANSFER_BIT,
VK_ACCESS_TRANSFER_WRITE_BIT);
m_transitions.accessImage(
srcImage, srcSubresourceRange,
srcImage->info().layout, 0, 0,
srcImageLayout,
VK_PIPELINE_STAGE_TRANSFER_BIT,
VK_ACCESS_TRANSFER_READ_BIT);
m_transitions.recordCommands(m_cmd);
VkImageCopy imageRegion;
imageRegion.srcSubresource = srcSubresource;
imageRegion.srcOffset = srcOffset;
imageRegion.dstSubresource = dstSubresource;
imageRegion.dstOffset = dstOffset;
imageRegion.extent = extent;
m_cmd->cmdCopyImage(
srcImage->handle(), srcImageLayout,
dstImage->handle(), dstImageLayout,
1, &imageRegion);
m_barriers.accessImage(
dstImage, dstSubresourceRange,
dstImageLayout,
VK_PIPELINE_STAGE_TRANSFER_BIT,
VK_ACCESS_TRANSFER_WRITE_BIT,
dstImage->info().layout,
dstImage->info().stages,
dstImage->info().access);
m_barriers.accessImage(
srcImage, srcSubresourceRange,
srcImageLayout,
VK_PIPELINE_STAGE_TRANSFER_BIT,
VK_ACCESS_TRANSFER_READ_BIT,
srcImage->info().layout,
srcImage->info().stages,
srcImage->info().access);
m_cmd->trackResource(dstImage);
m_cmd->trackResource(srcImage);
}
void DxvkContext::copyImageFb(
const Rc<DxvkImage>& dstImage,
VkImageSubresourceLayers dstSubresource,
VkOffset3D dstOffset,
const Rc<DxvkImage>& srcImage,
VkImageSubresourceLayers srcSubresource,
VkOffset3D srcOffset,
VkExtent3D extent) {
this->unbindGraphicsPipeline();
VkImageSubresourceRange srcSubresourceRange = {
srcSubresource.aspectMask,
srcSubresource.mipLevel, 1,
srcSubresource.baseArrayLayer,
srcSubresource.layerCount };
VkImageSubresourceRange dstSubresourceRange = {
dstSubresource.aspectMask,
dstSubresource.mipLevel, 1,
dstSubresource.baseArrayLayer,
dstSubresource.layerCount };
if (m_barriers.isImageDirty(srcImage, srcSubresourceRange, DxvkAccess::Write)
|| m_barriers.isImageDirty(dstImage, dstSubresourceRange, DxvkAccess::Write))
m_barriers.recordCommands(m_cmd);
// Source image needs to be readable
if (!(srcImage->info().usage & VK_IMAGE_USAGE_SAMPLED_BIT)) {
Logger::err("DxvkContext: copyImageFb: Source image not readable");
return;
}
// Render target format to use for this copy
VkFormat viewFormat = m_metaCopy->getCopyDestinationFormat(
dstSubresource.aspectMask,
srcSubresource.aspectMask,
srcImage->info().format);
if (viewFormat == VK_FORMAT_UNDEFINED) {
Logger::err("DxvkContext: copyImageFb: Unsupported format");
return;
}
// We might have to transition the source image layout
VkImageLayout srcLayout = (srcSubresource.aspectMask & VK_IMAGE_ASPECT_COLOR_BIT)
? srcImage->pickLayout(VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)
: srcImage->pickLayout(VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL);
if (srcImage->info().layout != srcLayout) {
m_transitions.accessImage(
srcImage, srcSubresourceRange,
srcImage->info().layout,
srcImage->info().stages,
srcImage->info().access,
srcLayout,
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
VK_ACCESS_SHADER_READ_BIT);
m_transitions.recordCommands(m_cmd);
}
// In some cases, we may be able to render to the destination
// image directly, which is faster than using a temporary image
VkImageUsageFlagBits tgtUsage = (dstSubresource.aspectMask & VK_IMAGE_ASPECT_COLOR_BIT)
? VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT
: VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
bool useDirectRender = (dstImage->isViewCompatible(viewFormat))
&& (dstImage->info().usage & tgtUsage);
// If needed, create a temporary render target for the copy
Rc<DxvkImage> tgtImage = dstImage;
VkImageSubresourceLayers tgtSubresource = dstSubresource;
VkOffset3D tgtOffset = dstOffset;
if (!useDirectRender) {
DxvkImageCreateInfo info;
info.type = dstImage->info().type;
info.format = viewFormat;
info.flags = 0;
info.sampleCount = dstImage->info().sampleCount;
info.extent = extent;
info.numLayers = dstSubresource.layerCount;
info.mipLevels = 1;
info.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | tgtUsage;
info.stages = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT
| VK_PIPELINE_STAGE_TRANSFER_BIT;
info.access = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
info.tiling = VK_IMAGE_TILING_OPTIMAL;
info.layout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
tgtImage = m_device->createImage(info, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
tgtSubresource.mipLevel = 0;
tgtSubresource.baseArrayLayer = 0;
tgtOffset = { 0, 0, 0 };
}
// Create source and destination image views
VkImageViewType viewType = dstImage->info().type == VK_IMAGE_TYPE_1D
? VK_IMAGE_VIEW_TYPE_1D_ARRAY
: VK_IMAGE_VIEW_TYPE_2D_ARRAY;
DxvkImageViewCreateInfo tgtViewInfo;
tgtViewInfo.type = viewType;
tgtViewInfo.format = viewFormat;
tgtViewInfo.usage = tgtUsage;
tgtViewInfo.aspect = tgtSubresource.aspectMask;
tgtViewInfo.minLevel = tgtSubresource.mipLevel;
tgtViewInfo.numLevels = 1;
tgtViewInfo.minLayer = tgtSubresource.baseArrayLayer;
tgtViewInfo.numLayers = tgtSubresource.layerCount;
DxvkImageViewCreateInfo srcViewInfo;
srcViewInfo.type = viewType;
srcViewInfo.format = srcImage->info().format;
srcViewInfo.usage = VK_IMAGE_USAGE_SAMPLED_BIT;
srcViewInfo.aspect = srcSubresource.aspectMask;
srcViewInfo.minLevel = srcSubresource.mipLevel;
srcViewInfo.numLevels = 1;
srcViewInfo.minLayer = srcSubresource.baseArrayLayer;
srcViewInfo.numLayers = srcSubresource.layerCount;
auto tgtImageView = m_device->createImageView(tgtImage, tgtViewInfo);
auto srcImageView = m_device->createImageView(srcImage, srcViewInfo);
// Create framebuffer and pipeline for the copy
Rc<DxvkMetaCopyRenderPass> fb = new DxvkMetaCopyRenderPass(
m_device->vkd(), tgtImageView, srcImageView,
tgtImage->isFullSubresource(tgtSubresource, extent));
auto pipeInfo = m_metaCopy->getPipeline(
viewType, viewFormat, tgtImage->info().sampleCount);
VkDescriptorImageInfo descriptorImage;
descriptorImage.sampler = VK_NULL_HANDLE;
descriptorImage.imageView = srcImageView->handle();
descriptorImage.imageLayout = srcLayout;
VkWriteDescriptorSet descriptorWrite;
descriptorWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
descriptorWrite.pNext = nullptr;
descriptorWrite.dstBinding = 0;
descriptorWrite.dstArrayElement = 0;
descriptorWrite.descriptorCount = 1;
descriptorWrite.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
descriptorWrite.pImageInfo = &descriptorImage;
descriptorWrite.pBufferInfo = nullptr;
descriptorWrite.pTexelBufferView = nullptr;
descriptorWrite.dstSet = m_cmd->allocateDescriptorSet(pipeInfo.dsetLayout);
m_cmd->updateDescriptorSets(1, &descriptorWrite);
VkViewport viewport;
viewport.x = float(tgtOffset.x);
viewport.y = float(tgtOffset.y);
viewport.width = float(extent.width);
viewport.height = float(extent.height);
viewport.minDepth = 0.0f;
viewport.maxDepth = 1.0f;
VkRect2D scissor;
scissor.offset = { tgtOffset.x, tgtOffset.y };
scissor.extent = { extent.width, extent.height };
VkRenderPassBeginInfo info;
info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
info.pNext = nullptr;
info.renderPass = fb->renderPass();
info.framebuffer = fb->framebuffer();
info.renderArea.offset = { 0, 0 };
info.renderArea.extent = {
tgtImage->info().extent.width,
tgtImage->info().extent.height };
info.clearValueCount = 0;
info.pClearValues = nullptr;
// Perform the actual copy operation
m_cmd->cmdBeginRenderPass(&info, VK_SUBPASS_CONTENTS_INLINE);
m_cmd->cmdBindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, pipeInfo.pipeHandle);
m_cmd->cmdBindDescriptorSet(VK_PIPELINE_BIND_POINT_GRAPHICS,
pipeInfo.pipeLayout, descriptorWrite.dstSet, 0, nullptr);
m_cmd->cmdSetViewport(0, 1, &viewport);
m_cmd->cmdSetScissor (0, 1, &scissor);
VkOffset2D srcCoordOffset = {
srcOffset.x - tgtOffset.x,
srcOffset.y - tgtOffset.y };
m_cmd->cmdPushConstants(pipeInfo.pipeLayout,
VK_SHADER_STAGE_FRAGMENT_BIT,
0, sizeof(srcCoordOffset),
&srcCoordOffset);
m_cmd->cmdDraw(1, tgtSubresource.layerCount, 0, 0);
m_cmd->cmdEndRenderPass();
m_cmd->trackResource(tgtImage);
m_cmd->trackResource(srcImage);
m_cmd->trackResource(fb);
// If necessary, transition source image back
if (srcImage->info().layout != srcLayout) {
m_barriers.accessImage(
srcImage, srcSubresourceRange,
srcLayout,
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
VK_ACCESS_SHADER_READ_BIT,
srcImage->info().layout,
srcImage->info().stages,
srcImage->info().access);
}
// If necessary, copy the temporary image
// to the original destination image
if (!useDirectRender) {
this->copyImageHw(
dstImage, dstSubresource, dstOffset,
tgtImage, tgtSubresource, tgtOffset,
extent);
}
}
void DxvkContext::startRenderPass() {
if (!m_flags.test(DxvkContextFlag::GpRenderPassBound)
&& (m_state.om.framebuffer != nullptr)) {

View File

@ -7,6 +7,7 @@
#include "dxvk_data.h"
#include "dxvk_event.h"
#include "dxvk_meta_clear.h"
#include "dxvk_meta_copy.h"
#include "dxvk_meta_mipgen.h"
#include "dxvk_meta_resolve.h"
#include "dxvk_pipecache.h"
@ -33,6 +34,7 @@ namespace dxvk {
const Rc<DxvkDevice>& device,
const Rc<DxvkPipelineManager>& pipelineManager,
const Rc<DxvkMetaClearObjects>& metaClearObjects,
const Rc<DxvkMetaCopyObjects>& metaCopyObjects,
const Rc<DxvkMetaMipGenObjects>& metaMipGenObjects,
const Rc<DxvkMetaResolveObjects>& metaResolveObjects);
~DxvkContext();
@ -670,6 +672,7 @@ namespace dxvk {
const Rc<DxvkDevice> m_device;
const Rc<DxvkPipelineManager> m_pipeMgr;
const Rc<DxvkMetaClearObjects> m_metaClear;
const Rc<DxvkMetaCopyObjects> m_metaCopy;
const Rc<DxvkMetaMipGenObjects> m_metaMipGen;
const Rc<DxvkMetaResolveObjects> m_metaResolve;
@ -704,6 +707,24 @@ namespace dxvk {
VkExtent3D extent,
VkClearValue value);
void copyImageHw(
const Rc<DxvkImage>& dstImage,
VkImageSubresourceLayers dstSubresource,
VkOffset3D dstOffset,
const Rc<DxvkImage>& srcImage,
VkImageSubresourceLayers srcSubresource,
VkOffset3D srcOffset,
VkExtent3D extent);
void copyImageFb(
const Rc<DxvkImage>& dstImage,
VkImageSubresourceLayers dstSubresource,
VkOffset3D dstOffset,
const Rc<DxvkImage>& srcImage,
VkImageSubresourceLayers srcSubresource,
VkOffset3D srcOffset,
VkExtent3D extent);
void startRenderPass();
void spillRenderPass();

View File

@ -18,6 +18,7 @@ namespace dxvk {
m_renderPassPool (new DxvkRenderPassPool (vkd)),
m_pipelineManager (new DxvkPipelineManager (this, m_renderPassPool.ptr())),
m_metaClearObjects (new DxvkMetaClearObjects (vkd)),
m_metaCopyObjects (new DxvkMetaCopyObjects (vkd)),
m_metaMipGenObjects (new DxvkMetaMipGenObjects (vkd)),
m_metaResolveObjects(new DxvkMetaResolveObjects (vkd)),
m_unboundResources (this),
@ -118,6 +119,7 @@ namespace dxvk {
return new DxvkContext(this,
m_pipelineManager,
m_metaClearObjects,
m_metaCopyObjects,
m_metaMipGenObjects,
m_metaResolveObjects);
}

View File

@ -397,7 +397,9 @@ namespace dxvk {
Rc<DxvkMemoryAllocator> m_memory;
Rc<DxvkRenderPassPool> m_renderPassPool;
Rc<DxvkPipelineManager> m_pipelineManager;
Rc<DxvkMetaClearObjects> m_metaClearObjects;
Rc<DxvkMetaCopyObjects> m_metaCopyObjects;
Rc<DxvkMetaMipGenObjects> m_metaMipGenObjects;
Rc<DxvkMetaResolveObjects> m_metaResolveObjects;

View File

@ -240,6 +240,21 @@ namespace dxvk {
return subresource.aspectMask == this->formatInfo()->aspectMask
&& extent == this->mipLevelExtent(subresource.mipLevel);
}
/**
* \brief Checks view format compatibility
*
* If this returns true, a view with the given
* format can be safely created for this image.
* \param [in] format The format to check
* \returns \c true if the format is vompatible
*/
bool isViewCompatible(VkFormat format) const {
bool result = m_info.format == format;
for (uint32_t i = 0; i < m_viewFormats.size() && !result; i++)
result |= m_viewFormats[i] == format;
return result;
}
private: