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

[dxvk] Support image sub-regions for resolve operations

Required for legacy graphics APIs.
This commit is contained in:
Philip Rebohle 2019-04-19 11:19:14 +02:00
parent a3966b442b
commit 95bfac84f1
No known key found for this signature in database
GPG Key ID: C8CC613427A31C99
10 changed files with 113 additions and 75 deletions

View File

@ -1321,10 +1321,14 @@ namespace dxvk {
cSrcSubres = srcSubresourceLayers,
cFormat = format
] (DxvkContext* ctx) {
ctx->resolveImage(
cDstImage, cDstSubres,
cSrcImage, cSrcSubres,
cFormat);
VkImageResolve region;
region.srcSubresource = cSrcSubres;
region.srcOffset = VkOffset3D { 0, 0, 0 };
region.dstSubresource = cDstSubres;
region.dstOffset = VkOffset3D { 0, 0, 0 };
region.extent = cDstImage->mipLevelExtent(cDstSubres.mipLevel);
ctx->resolveImage(cDstImage, cSrcImage, region, cFormat);
});
}
}

View File

@ -213,16 +213,22 @@ namespace dxvk {
// Resolve back buffer if it is multisampled. We
// only have to do it only for the first frame.
if (m_swapImageResolve != nullptr && i == 0) {
VkImageSubresourceLayers resolveSubresources;
resolveSubresources.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
resolveSubresources.mipLevel = 0;
resolveSubresources.baseArrayLayer = 0;
resolveSubresources.layerCount = 1;
VkImageSubresourceLayers resolveSubresource;
resolveSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
resolveSubresource.mipLevel = 0;
resolveSubresource.baseArrayLayer = 0;
resolveSubresource.layerCount = 1;
VkImageResolve resolveRegion;
resolveRegion.srcSubresource = resolveSubresource;
resolveRegion.srcOffset = VkOffset3D { 0, 0, 0 };
resolveRegion.dstSubresource = resolveSubresource;
resolveRegion.dstOffset = VkOffset3D { 0, 0, 0 };
resolveRegion.extent = m_swapImage->info().extent;
m_context->resolveImage(
m_swapImageResolve, resolveSubresources,
m_swapImage, resolveSubresources,
VK_FORMAT_UNDEFINED);
m_swapImageResolve, m_swapImage,
resolveRegion, VK_FORMAT_UNDEFINED);
}
// Presentation semaphores and WSI swap chain image

View File

@ -1671,9 +1671,8 @@ namespace dxvk {
void DxvkContext::resolveImage(
const Rc<DxvkImage>& dstImage,
const VkImageSubresourceLayers& dstSubresources,
const Rc<DxvkImage>& srcImage,
const VkImageSubresourceLayers& srcSubresources,
const VkImageResolve& region,
VkFormat format) {
this->spillRenderPass();
@ -1683,13 +1682,10 @@ namespace dxvk {
if (srcImage->info().format == format
&& dstImage->info().format == format) {
this->resolveImageHw(
dstImage, dstSubresources,
srcImage, srcSubresources);
dstImage, srcImage, region);
} else {
this->resolveImageFb(
dstImage, dstSubresources,
srcImage, srcSubresources,
format);
dstImage, srcImage, region, format);
}
}
@ -2605,11 +2601,10 @@ namespace dxvk {
void DxvkContext::resolveImageHw(
const Rc<DxvkImage>& dstImage,
const VkImageSubresourceLayers& dstSubresources,
const Rc<DxvkImage>& srcImage,
const VkImageSubresourceLayers& srcSubresources) {
auto dstSubresourceRange = vk::makeSubresourceRange(dstSubresources);
auto srcSubresourceRange = vk::makeSubresourceRange(srcSubresources);
const VkImageResolve& region) {
auto dstSubresourceRange = vk::makeSubresourceRange(region.dstSubresource);
auto srcSubresourceRange = vk::makeSubresourceRange(region.srcSubresource);
if (m_barriers.isImageDirty(dstImage, dstSubresourceRange, DxvkAccess::Write)
|| m_barriers.isImageDirty(srcImage, srcSubresourceRange, DxvkAccess::Write))
@ -2617,9 +2612,14 @@ namespace dxvk {
// We only support resolving to the entire image
// area, so we might as well discard its contents
VkImageLayout initialLayout = dstImage->info().layout;
if (dstImage->isFullSubresource(region.dstSubresource, region.extent))
initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
m_transitions.accessImage(
dstImage, dstSubresourceRange,
VK_IMAGE_LAYOUT_UNDEFINED, 0, 0,
initialLayout, 0, 0,
dstImage->pickLayout(VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL),
VK_PIPELINE_STAGE_TRANSFER_BIT,
VK_ACCESS_TRANSFER_WRITE_BIT);
@ -2633,17 +2633,10 @@ namespace dxvk {
m_transitions.recordCommands(m_cmd);
VkImageResolve imageRegion;
imageRegion.srcSubresource = srcSubresources;
imageRegion.srcOffset = VkOffset3D { 0, 0, 0 };
imageRegion.dstSubresource = dstSubresources;
imageRegion.dstOffset = VkOffset3D { 0, 0, 0 };
imageRegion.extent = srcImage->mipLevelExtent(srcSubresources.mipLevel);
m_cmd->cmdResolveImage(
srcImage->handle(), srcImage->pickLayout(VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL),
dstImage->handle(), dstImage->pickLayout(VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL),
1, &imageRegion);
1, &region);
m_barriers.accessImage(
dstImage, dstSubresourceRange,
@ -2670,12 +2663,11 @@ namespace dxvk {
void DxvkContext::resolveImageFb(
const Rc<DxvkImage>& dstImage,
const VkImageSubresourceLayers& dstSubresources,
const Rc<DxvkImage>& srcImage,
const VkImageSubresourceLayers& srcSubresources,
const VkImageResolve& region,
VkFormat format) {
auto dstSubresourceRange = vk::makeSubresourceRange(dstSubresources);
auto srcSubresourceRange = vk::makeSubresourceRange(srcSubresources);
auto dstSubresourceRange = vk::makeSubresourceRange(region.dstSubresource);
auto srcSubresourceRange = vk::makeSubresourceRange(region.srcSubresource);
if (m_barriers.isImageDirty(dstImage, dstSubresourceRange, DxvkAccess::Write)
|| m_barriers.isImageDirty(srcImage, srcSubresourceRange, DxvkAccess::Write))
@ -2700,31 +2692,32 @@ namespace dxvk {
dstViewInfo.type = VK_IMAGE_VIEW_TYPE_2D_ARRAY;
dstViewInfo.format = format;
dstViewInfo.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
dstViewInfo.aspect = dstSubresources.aspectMask;
dstViewInfo.minLevel = dstSubresources.mipLevel;
dstViewInfo.aspect = region.dstSubresource.aspectMask;
dstViewInfo.minLevel = region.dstSubresource.mipLevel;
dstViewInfo.numLevels = 1;
dstViewInfo.minLayer = dstSubresources.baseArrayLayer;
dstViewInfo.numLayers = dstSubresources.layerCount;
dstViewInfo.minLayer = region.dstSubresource.baseArrayLayer;
dstViewInfo.numLayers = region.dstSubresource.layerCount;
DxvkImageViewCreateInfo srcViewInfo;
srcViewInfo.type = VK_IMAGE_VIEW_TYPE_2D_ARRAY;
srcViewInfo.format = format;
srcViewInfo.usage = VK_IMAGE_USAGE_SAMPLED_BIT;
srcViewInfo.aspect = srcSubresources.aspectMask;
srcViewInfo.minLevel = srcSubresources.mipLevel;
srcViewInfo.aspect = region.srcSubresource.aspectMask;
srcViewInfo.minLevel = region.srcSubresource.mipLevel;
srcViewInfo.numLevels = 1;
srcViewInfo.minLayer = srcSubresources.baseArrayLayer;
srcViewInfo.numLayers = srcSubresources.layerCount;
srcViewInfo.minLayer = region.srcSubresource.baseArrayLayer;
srcViewInfo.numLayers = region.srcSubresource.layerCount;
Rc<DxvkImageView> dstImageView = m_device->createImageView(dstImage, dstViewInfo);
Rc<DxvkImageView> srcImageView = m_device->createImageView(srcImage, srcViewInfo);
// Create a framebuffer and pipeline for the resolve op
Rc<DxvkMetaResolveRenderPass> fb = new DxvkMetaResolveRenderPass(
m_device->vkd(), dstImageView, srcImageView);
VkExtent3D passExtent = dstImageView->mipLevelExtent(0);
Rc<DxvkMetaResolveRenderPass> fb = new DxvkMetaResolveRenderPass(
m_device->vkd(), dstImageView, srcImageView,
dstImage->isFullSubresource(region.dstSubresource, region.extent));
auto pipeInfo = m_metaResolve->getPipeline(
format, srcImage->info().sampleCount);
@ -2748,16 +2741,16 @@ namespace dxvk {
m_cmd->updateDescriptorSets(1, &descriptorWrite);
VkViewport viewport;
viewport.x = 0.0f;
viewport.y = 0.0f;
viewport.width = float(passExtent.width);
viewport.height = float(passExtent.height);
viewport.x = float(region.dstOffset.x);
viewport.y = float(region.dstOffset.y);
viewport.width = float(region.extent.width);
viewport.height = float(region.extent.height);
viewport.minDepth = 0.0f;
viewport.maxDepth = 1.0f;
VkRect2D scissor;
scissor.offset = { 0, 0 };
scissor.extent = { passExtent.width, passExtent.height };
scissor.offset = { region.dstOffset.x, region.dstOffset.y };
scissor.extent = { region.extent.width, region.extent.height };
VkRenderPassBeginInfo info;
info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
@ -2770,13 +2763,20 @@ namespace dxvk {
info.pClearValues = nullptr;
// Perform the actual resolve operation
VkOffset2D srcOffset = {
region.srcOffset.x,
region.srcOffset.y };
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);
m_cmd->cmdDraw(1, dstSubresources.layerCount, 0, 0);
m_cmd->cmdPushConstants(pipeInfo.pipeLayout,
VK_SHADER_STAGE_FRAGMENT_BIT,
0, sizeof(srcOffset), &srcOffset);
m_cmd->cmdDraw(1, region.dstSubresource.layerCount, 0, 0);
m_cmd->cmdEndRenderPass();
m_barriers.accessImage(

View File

@ -629,16 +629,14 @@ namespace dxvk {
* If it is \c VK_FORMAT_UNDEFINED, the resolve operation
* will use the source image format.
* \param [in] dstImage Destination image
* \param [in] dstSubresources Subresources to write to
* \param [in] srcImage Source image
* \param [in] srcSubresources Subresources to read from
* \param [in] region Region to resolve
* \param [in] format Format for the resolve operation
*/
void resolveImage(
const Rc<DxvkImage>& dstImage,
const VkImageSubresourceLayers& dstSubresources,
const Rc<DxvkImage>& srcImage,
const VkImageSubresourceLayers& srcSubresources,
const VkImageResolve& region,
VkFormat format);
/**
@ -950,15 +948,13 @@ namespace dxvk {
void resolveImageHw(
const Rc<DxvkImage>& dstImage,
const VkImageSubresourceLayers& dstSubresources,
const Rc<DxvkImage>& srcImage,
const VkImageSubresourceLayers& srcSubresources);
const VkImageResolve& region);
void resolveImageFb(
const Rc<DxvkImage>& dstImage,
const VkImageSubresourceLayers& dstSubresources,
const Rc<DxvkImage>& srcImage,
const VkImageSubresourceLayers& srcSubresources,
const VkImageResolve& region,
VkFormat format);
void updatePredicate(

View File

@ -13,11 +13,12 @@ namespace dxvk {
DxvkMetaResolveRenderPass::DxvkMetaResolveRenderPass(
const Rc<vk::DeviceFn>& vkd,
const Rc<DxvkImageView>& dstImageView,
const Rc<DxvkImageView>& srcImageView)
const Rc<DxvkImageView>& srcImageView,
bool discardDst)
: m_vkd(vkd),
m_dstImageView(dstImageView),
m_srcImageView(srcImageView),
m_renderPass (createRenderPass ()),
m_renderPass (createRenderPass(discardDst)),
m_framebuffer (createFramebuffer()) { }
@ -27,17 +28,22 @@ namespace dxvk {
}
VkRenderPass DxvkMetaResolveRenderPass::createRenderPass() const {
VkRenderPass DxvkMetaResolveRenderPass::createRenderPass(bool discard) const {
VkAttachmentDescription attachment;
attachment.flags = 0;
attachment.format = m_dstImageView->info().format;
attachment.samples = VK_SAMPLE_COUNT_1_BIT;
attachment.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
attachment.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
attachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
attachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
attachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
attachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
attachment.initialLayout = m_dstImageView->imageInfo().layout;
attachment.finalLayout = m_dstImageView->imageInfo().layout;
if (discard) {
attachment.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
attachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
}
VkAttachmentReference dstRef;
dstRef.attachment = 0;
@ -274,14 +280,19 @@ namespace dxvk {
VkPipelineLayout DxvkMetaResolveObjects::createPipelineLayout(
VkDescriptorSetLayout descriptorSetLayout) const {
VkPushConstantRange push;
push.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
push.offset = 0;
push.size = sizeof(VkOffset2D);
VkPipelineLayoutCreateInfo info;
info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
info.pNext = nullptr;
info.flags = 0;
info.setLayoutCount = 1;
info.pSetLayouts = &descriptorSetLayout;
info.pushConstantRangeCount = 0;
info.pPushConstantRanges = nullptr;
info.pushConstantRangeCount = 1;
info.pPushConstantRanges = &push;
VkPipelineLayout result = VK_NULL_HANDLE;
if (m_vkd->vkCreatePipelineLayout(m_vkd->device(), &info, nullptr, &result) != VK_SUCCESS)

View File

@ -58,7 +58,8 @@ namespace dxvk {
DxvkMetaResolveRenderPass(
const Rc<vk::DeviceFn>& vkd,
const Rc<DxvkImageView>& dstImageView,
const Rc<DxvkImageView>& srcImageView);
const Rc<DxvkImageView>& srcImageView,
bool discardDst);
~DxvkMetaResolveRenderPass();
@ -80,7 +81,7 @@ namespace dxvk {
VkRenderPass m_renderPass = VK_NULL_HANDLE;
VkFramebuffer m_framebuffer = VK_NULL_HANDLE;
VkRenderPass createRenderPass() const;
VkRenderPass createRenderPass(bool discard) const;
VkFramebuffer createFramebuffer() const;

View File

@ -6,8 +6,13 @@ layout(binding = 0) uniform sampler2DMSArray s_image;
layout(location = 0) out vec4 o_color;
layout(push_constant)
uniform u_info_t {
ivec2 offset;
} u_info;
void main() {
ivec3 coord = ivec3(gl_FragCoord.xy, gl_Layer);
ivec3 coord = ivec3(gl_FragCoord.xy + u_info.offset, gl_Layer);
vec4 color = vec4(0.0f);
for (int i = 0; i < c_samples; i++)
color += texelFetch(s_image, coord, i);

View File

@ -9,8 +9,13 @@ uniform sampler2DMSArray s_image;
layout(location = 0) out vec4 o_color;
layout(push_constant)
uniform u_info_t {
ivec2 offset;
} u_info;
void main() {
ivec3 coord = ivec3(gl_FragCoord.xy, gl_Layer);
ivec3 coord = ivec3(gl_FragCoord.xy + u_info.offset, gl_Layer);
// get a four-bit fragment index for each sample
uint fragMask = fragmentMaskFetchAMD(s_image, coord);

View File

@ -4,7 +4,12 @@ layout(binding = 0) uniform isampler2DMSArray s_image;
layout(location = 0) out ivec4 o_color;
layout(push_constant)
uniform u_info_t {
ivec2 offset;
} u_info;
void main() {
ivec3 coord = ivec3(gl_FragCoord.xy, gl_Layer);
ivec3 coord = ivec3(gl_FragCoord.xy + u_info.offset, gl_Layer);
o_color = texelFetch(s_image, coord, 0);
}

View File

@ -4,7 +4,12 @@ layout(binding = 0) uniform usampler2DMSArray s_image;
layout(location = 0) out uvec4 o_color;
layout(push_constant)
uniform u_info_t {
ivec2 offset;
} u_info;
void main() {
ivec3 coord = ivec3(gl_FragCoord.xy, gl_Layer);
ivec3 coord = ivec3(gl_FragCoord.xy + u_info.offset, gl_Layer);
o_color = texelFetch(s_image, coord, 0);
}