1
0
mirror of https://github.com/doitsujin/dxvk.git synced 2025-03-21 13:29:26 +01:00

[dxvk] Use dynamic rendering for copies

Significantly reworks framebuffer copies as well. We'll no longer
create dummy samplers to work around glslang versions not supporting
texture descriptors without samplers, and copyImageFb was cleaned
up to factor out the part where a temporary image is created.
This commit is contained in:
Philip Rebohle 2022-07-02 03:32:31 +02:00
parent a450c88c72
commit 96e102beff
No known key found for this signature in database
GPG Key ID: C8CC613427A31C99
13 changed files with 387 additions and 602 deletions

View File

@ -3232,6 +3232,82 @@ namespace dxvk {
VkImageSubresourceLayers srcSubresource, VkImageSubresourceLayers srcSubresource,
VkOffset3D srcOffset, VkOffset3D srcOffset,
VkExtent3D extent) { VkExtent3D extent) {
VkFormat viewFormat = m_common->metaCopy().getCopyDestinationFormat(
dstSubresource.aspectMask,
srcSubresource.aspectMask,
srcImage->info().format);
if (!viewFormat) {
Logger::err("DxvkContext: copyImageFb: Unsupported format");
return;
}
// Usually we should be able to draw directly to the destination image,
// but in some cases this might not be possible, e.g. if when copying
// from something like D32_SFLOAT to RGBA8_UNORM. In those situations,
// create a temporary image to draw to, and then copy to the actual
// destination image using a regular Vulkan transfer function.
bool useDirectCopy = (dstImage->info().usage & (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT))
&& (dstImage->isViewCompatible(viewFormat));
if (useDirectCopy) {
this->copyImageFbDirect(
dstImage, dstSubresource, dstOffset, viewFormat,
srcImage, srcSubresource, srcOffset, extent);
} else {
DxvkImageCreateInfo imageInfo = dstImage->info();
imageInfo.format = viewFormat;
imageInfo.flags = 0;
imageInfo.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
imageInfo.extent = extent;
imageInfo.numLayers = dstSubresource.layerCount;
imageInfo.mipLevels = 1;
imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
imageInfo.layout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
imageInfo.stages = VK_PIPELINE_STAGE_TRANSFER_BIT;
imageInfo.access = VK_ACCESS_TRANSFER_READ_BIT;
imageInfo.viewFormatCount = 0;
if (dstImage->formatInfo()->aspectMask & VK_IMAGE_ASPECT_COLOR_BIT) {
imageInfo.usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
imageInfo.stages |= VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
imageInfo.access |= VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
} else {
imageInfo.usage |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
imageInfo.stages |= VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT
| VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
imageInfo.access |= VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
}
Rc<DxvkImage> tmpImage = m_device->createImage(imageInfo,
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
VkImageSubresourceLayers tmpSubresource = dstSubresource;
tmpSubresource.mipLevel = 0;
tmpSubresource.baseArrayLayer = 0;
VkOffset3D tmpOffset = { 0, 0, 0 };
this->copyImageFbDirect(
tmpImage, tmpSubresource, tmpOffset, viewFormat,
srcImage, srcSubresource, srcOffset, extent);
this->copyImageHw(
dstImage, dstSubresource, dstOffset,
tmpImage, tmpSubresource, tmpOffset, extent);
}
}
void DxvkContext::copyImageFbDirect(
const Rc<DxvkImage>& dstImage,
VkImageSubresourceLayers dstSubresource,
VkOffset3D dstOffset,
VkFormat dstFormat,
const Rc<DxvkImage>& srcImage,
VkImageSubresourceLayers srcSubresource,
VkOffset3D srcOffset,
VkExtent3D extent) {
this->invalidateState(); this->invalidateState();
auto dstSubresourceRange = vk::makeSubresourceRange(dstSubresource); auto dstSubresourceRange = vk::makeSubresourceRange(dstSubresource);
@ -3241,24 +3317,33 @@ namespace dxvk {
|| m_execBarriers.isImageDirty(srcImage, srcSubresourceRange, DxvkAccess::Write)) || m_execBarriers.isImageDirty(srcImage, srcSubresourceRange, DxvkAccess::Write))
m_execBarriers.recordCommands(m_cmd); m_execBarriers.recordCommands(m_cmd);
// Source image needs to be readable // Flag used to determine whether we can do an UNDEFINED transition
if (!(srcImage->info().usage & VK_IMAGE_USAGE_SAMPLED_BIT)) { bool doDiscard = dstImage->isFullSubresource(dstSubresource, extent);
Logger::err("DxvkContext: copyImageFb: Source image not readable");
return; // This function can process both color and depth-stencil images, so
// some things change a lot depending on the destination image type
VkPipelineStageFlags dstStages;
VkAccessFlags dstAccess;
VkImageLayout dstLayout;
if (dstSubresource.aspectMask & VK_IMAGE_ASPECT_COLOR_BIT) {
dstLayout = dstImage->pickLayout(VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
dstStages = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
dstAccess = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
if (!doDiscard)
dstAccess |= VK_ACCESS_COLOR_ATTACHMENT_READ_BIT;
} else {
dstLayout = dstImage->pickLayout(VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL);
dstStages = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT
| VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
dstAccess = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
if (!doDiscard)
dstAccess |= VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT;
} }
// Render target format to use for this copy // Might have to transition source image as well
VkFormat viewFormat = m_common->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) VkImageLayout srcLayout = (srcSubresource.aspectMask & VK_IMAGE_ASPECT_COLOR_BIT)
? srcImage->pickLayout(VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) ? srcImage->pickLayout(VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)
: srcImage->pickLayout(VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL); : srcImage->pickLayout(VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL);
@ -3271,183 +3356,131 @@ namespace dxvk {
srcLayout, srcLayout,
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
VK_ACCESS_SHADER_READ_BIT); VK_ACCESS_SHADER_READ_BIT);
}
if (dstImage->info().layout != dstLayout) {
m_execAcquires.accessImage(
dstImage, dstSubresourceRange,
doDiscard ? VK_IMAGE_LAYOUT_UNDEFINED
: dstImage->info().layout,
dstImage->info().stages, 0,
dstLayout, dstStages, dstAccess);
}
m_execAcquires.recordCommands(m_cmd); m_execAcquires.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;
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_TRANSFER_BIT;
info.access = VK_ACCESS_TRANSFER_READ_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 };
} else {
tgtImage = dstImage;
}
// Create source and destination image views // Create source and destination image views
VkImageViewType viewType = dstImage->info().type == VK_IMAGE_TYPE_1D Rc<DxvkMetaCopyViews> views = new DxvkMetaCopyViews(m_device->vkd(),
? VK_IMAGE_VIEW_TYPE_1D_ARRAY dstImage, dstSubresource, dstFormat,
: VK_IMAGE_VIEW_TYPE_2D_ARRAY; srcImage, srcSubresource);
DxvkImageViewCreateInfo tgtViewInfo; // Create pipeline for the copy operation
tgtViewInfo.type = viewType; DxvkMetaCopyPipeline pipeInfo = m_common->metaCopy().getPipeline(
tgtViewInfo.format = viewFormat; views->getSrcViewType(), dstFormat, dstImage->info().sampleCount);
tgtViewInfo.usage = tgtUsage;
tgtViewInfo.aspect = tgtSubresource.aspectMask;
tgtViewInfo.minLevel = tgtSubresource.mipLevel;
tgtViewInfo.numLevels = 1;
tgtViewInfo.minLayer = tgtSubresource.baseArrayLayer;
tgtViewInfo.numLayers = tgtSubresource.layerCount;
DxvkImageViewCreateInfo srcViewInfo; // Create and initialize descriptor set
srcViewInfo.type = viewType; VkDescriptorSet descriptorSet = m_descriptorPool->alloc(pipeInfo.dsetLayout);
srcViewInfo.format = srcImage->info().format;
srcViewInfo.usage = VK_IMAGE_USAGE_SAMPLED_BIT;
srcViewInfo.aspect = srcSubresource.aspectMask & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_COLOR_BIT);
srcViewInfo.minLevel = srcSubresource.mipLevel;
srcViewInfo.numLevels = 1;
srcViewInfo.minLayer = srcSubresource.baseArrayLayer;
srcViewInfo.numLayers = srcSubresource.layerCount;
Rc<DxvkImageView> tgtImageView = m_device->createImageView(tgtImage, tgtViewInfo); std::array<VkDescriptorImageInfo, 2> descriptorImages = {{
Rc<DxvkImageView> srcImageView = m_device->createImageView(srcImage, srcViewInfo); { VK_NULL_HANDLE, views->getSrcView(), srcLayout },
Rc<DxvkImageView> srcStencilView; { VK_NULL_HANDLE, views->getSrcStencilView(), srcLayout },
}};
if (srcSubresource.aspectMask & VK_IMAGE_ASPECT_STENCIL_BIT) { std::array<VkWriteDescriptorSet, 2> descriptorWrites;
srcViewInfo.aspect = VK_IMAGE_ASPECT_STENCIL_BIT;
srcStencilView = m_device->createImageView(srcImage, srcViewInfo); for (uint32_t i = 0; i < descriptorWrites.size(); i++) {
descriptorWrites[i] = { VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET };
descriptorWrites[i].dstSet = descriptorSet;
descriptorWrites[i].dstBinding = i;
descriptorWrites[i].descriptorCount = 1;
descriptorWrites[i].descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE;
descriptorWrites[i].pImageInfo = &descriptorImages[i];
} }
// Create framebuffer and pipeline for the copy m_cmd->updateDescriptorSets(
Rc<DxvkMetaCopyRenderPass> fb = new DxvkMetaCopyRenderPass( descriptorWrites.size(),
m_device->vkd(), tgtImageView, srcImageView, srcStencilView, descriptorWrites.data());
tgtImage->isFullSubresource(tgtSubresource, extent));
auto pipeInfo = m_common->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_descriptorPool->alloc(pipeInfo.dsetLayout);
m_cmd->updateDescriptorSets(1, &descriptorWrite);
if (srcSubresource.aspectMask & VK_IMAGE_ASPECT_STENCIL_BIT) {
descriptorImage.imageView = srcStencilView->handle();
descriptorWrite.dstBinding = 1;
m_cmd->updateDescriptorSets(1, &descriptorWrite);
}
// Set up render state
VkViewport viewport; VkViewport viewport;
viewport.x = float(tgtOffset.x); viewport.x = float(dstOffset.x);
viewport.y = float(tgtOffset.y); viewport.y = float(dstOffset.y);
viewport.width = float(extent.width); viewport.width = float(extent.width);
viewport.height = float(extent.height); viewport.height = float(extent.height);
viewport.minDepth = 0.0f; viewport.minDepth = 0.0f;
viewport.maxDepth = 1.0f; viewport.maxDepth = 1.0f;
VkRect2D scissor; VkRect2D scissor;
scissor.offset = { tgtOffset.x, tgtOffset.y }; scissor.offset = { dstOffset.x, dstOffset.y };
scissor.extent = { extent.width, extent.height }; scissor.extent = { extent.width, extent.height };
VkRenderPassBeginInfo info; VkExtent3D mipExtent = dstImage->mipLevelExtent(dstSubresource.mipLevel);
info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
info.pNext = nullptr; VkRenderingAttachmentInfoKHR attachmentInfo = { VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO_KHR };
info.renderPass = fb->renderPass(); attachmentInfo.imageView = views->getDstView();
info.framebuffer = fb->framebuffer(); attachmentInfo.imageLayout = dstLayout;
info.renderArea.offset = { 0, 0 }; attachmentInfo.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
info.renderArea.extent = { attachmentInfo.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
tgtImage->mipLevelExtent(tgtSubresource.mipLevel).width,
tgtImage->mipLevelExtent(tgtSubresource.mipLevel).height }; if (doDiscard)
info.clearValueCount = 0; attachmentInfo.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
info.pClearValues = nullptr;
VkRenderingInfoKHR renderingInfo = { VK_STRUCTURE_TYPE_RENDERING_INFO_KHR };
renderingInfo.renderArea.offset = VkOffset2D { 0, 0 };
renderingInfo.renderArea.extent = VkExtent2D { mipExtent.width, mipExtent.height };
renderingInfo.layerCount = dstSubresource.layerCount;
VkImageAspectFlags dstAspects = dstImage->formatInfo()->aspectMask;
if (dstAspects & VK_IMAGE_ASPECT_COLOR_BIT) {
renderingInfo.colorAttachmentCount = 1;
renderingInfo.pColorAttachments = &attachmentInfo;
} else {
if (dstAspects & VK_IMAGE_ASPECT_DEPTH_BIT)
renderingInfo.pDepthAttachment = &attachmentInfo;
if (dstAspects & VK_IMAGE_ASPECT_STENCIL_BIT)
renderingInfo.pStencilAttachment = &attachmentInfo;
}
// Perform the actual copy operation // Perform the actual copy operation
m_cmd->cmdBeginRenderPass(&info, VK_SUBPASS_CONTENTS_INLINE); m_cmd->cmdBeginRendering(&renderingInfo);
m_cmd->cmdBindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, pipeInfo.pipeHandle); m_cmd->cmdBindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, pipeInfo.pipeHandle);
m_cmd->cmdBindDescriptorSet(VK_PIPELINE_BIND_POINT_GRAPHICS, m_cmd->cmdBindDescriptorSet(VK_PIPELINE_BIND_POINT_GRAPHICS,
pipeInfo.pipeLayout, descriptorWrite.dstSet, 0, nullptr); pipeInfo.pipeLayout, descriptorSet, 0, nullptr);
m_cmd->cmdSetViewport(0, 1, &viewport); m_cmd->cmdSetViewport(0, 1, &viewport);
m_cmd->cmdSetScissor (0, 1, &scissor); m_cmd->cmdSetScissor (0, 1, &scissor);
VkOffset2D srcCoordOffset = { VkOffset2D srcCoordOffset = {
srcOffset.x - tgtOffset.x, srcOffset.x - dstOffset.x,
srcOffset.y - tgtOffset.y }; srcOffset.y - dstOffset.y };
m_cmd->cmdPushConstants(pipeInfo.pipeLayout, m_cmd->cmdPushConstants(pipeInfo.pipeLayout,
VK_SHADER_STAGE_FRAGMENT_BIT, VK_SHADER_STAGE_FRAGMENT_BIT,
0, sizeof(srcCoordOffset), 0, sizeof(srcCoordOffset),
&srcCoordOffset); &srcCoordOffset);
m_cmd->cmdDraw(3, tgtSubresource.layerCount, 0, 0); m_cmd->cmdDraw(3, dstSubresource.layerCount, 0, 0);
m_cmd->cmdEndRenderPass(); m_cmd->cmdEndRendering();
if (srcLayout != srcImage->info().layout) {
m_execBarriers.accessImage( m_execBarriers.accessImage(
srcImage, srcSubresourceRange, srcLayout, srcImage, srcSubresourceRange, srcLayout,
srcImage->info().stages, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
srcImage->info().access, VK_ACCESS_SHADER_READ_BIT,
srcImage->info().layout, srcImage->info().layout,
srcImage->info().stages, srcImage->info().stages,
srcImage->info().access); srcImage->info().access);
}
m_cmd->trackResource<DxvkAccess::Write>(tgtImage); m_execBarriers.accessImage(
dstImage, dstSubresourceRange,
dstLayout, dstStages, dstAccess,
dstImage->info().layout,
dstImage->info().stages,
dstImage->info().access);
m_cmd->trackResource<DxvkAccess::Write>(dstImage);
m_cmd->trackResource<DxvkAccess::Read>(srcImage); m_cmd->trackResource<DxvkAccess::Read>(srcImage);
m_cmd->trackResource<DxvkAccess::None>(fb); m_cmd->trackResource<DxvkAccess::None>(views);
// If necessary, copy the temporary image
// to the original destination image
if (!useDirectRender) {
this->copyImageHw(
dstImage, dstSubresource, dstOffset,
tgtImage, tgtSubresource, tgtOffset,
extent);
}
} }

View File

@ -1224,6 +1224,16 @@ namespace dxvk {
VkOffset3D srcOffset, VkOffset3D srcOffset,
VkExtent3D extent); VkExtent3D extent);
void copyImageFbDirect(
const Rc<DxvkImage>& dstImage,
VkImageSubresourceLayers dstSubresource,
VkOffset3D dstOffset,
VkFormat dstFormat,
const Rc<DxvkImage>& srcImage,
VkImageSubresourceLayers srcSubresource,
VkOffset3D srcOffset,
VkExtent3D extent);
bool copyImageClear( bool copyImageClear(
const Rc<DxvkImage>& dstImage, const Rc<DxvkImage>& dstImage,
VkImageSubresourceLayers dstSubresource, VkImageSubresourceLayers dstSubresource,

View File

@ -18,143 +18,68 @@
namespace dxvk { namespace dxvk {
DxvkMetaCopyRenderPass::DxvkMetaCopyRenderPass( DxvkMetaCopyViews::DxvkMetaCopyViews(
const Rc<vk::DeviceFn>& vkd, const Rc<vk::DeviceFn>& vkd,
const Rc<DxvkImageView>& dstImageView, const Rc<DxvkImage>& dstImage,
const Rc<DxvkImageView>& srcImageView, const VkImageSubresourceLayers& dstSubresources,
const Rc<DxvkImageView>& srcStencilView, VkFormat dstFormat,
bool discardDst) const Rc<DxvkImage>& srcImage,
: m_vkd (vkd), const VkImageSubresourceLayers& srcSubresources)
m_dstImageView (dstImageView), : m_vkd(vkd) {
m_srcImageView (srcImageView), VkImageAspectFlags dstAspects = dstImage->formatInfo()->aspectMask;
m_srcStencilView(srcStencilView), VkImageAspectFlags srcAspects = srcImage->formatInfo()->aspectMask;
m_renderPass (createRenderPass(discardDst)),
m_framebuffer (createFramebuffer()) {
// We don't support 3D here, so we can safely ignore that case
m_dstViewType = dstImage->info().type == VK_IMAGE_TYPE_1D
? VK_IMAGE_VIEW_TYPE_1D_ARRAY : VK_IMAGE_VIEW_TYPE_2D_ARRAY;
m_srcViewType = srcImage->info().type == VK_IMAGE_TYPE_1D
? VK_IMAGE_VIEW_TYPE_1D_ARRAY : VK_IMAGE_VIEW_TYPE_2D_ARRAY;
VkImageViewUsageCreateInfo usageInfo = { VK_STRUCTURE_TYPE_IMAGE_VIEW_USAGE_CREATE_INFO };
usageInfo.usage = (dstAspects & VK_IMAGE_ASPECT_COLOR_BIT)
? VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT
: VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
// Create destination view
VkImageViewCreateInfo info = { VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, &usageInfo };
info.image = dstImage->handle();
info.viewType = m_dstViewType;
info.format = dstFormat;
info.subresourceRange = vk::makeSubresourceRange(dstSubresources);
if ((m_vkd->vkCreateImageView(m_vkd->device(), &info, nullptr, &m_dstImageView)))
throw DxvkError("DxvkMetaCopyViews: Failed to create destination image view");
// Create source image views
usageInfo.usage = VK_IMAGE_USAGE_SAMPLED_BIT;
info.image = srcImage->handle();
info.viewType = m_srcViewType;
info.format = srcImage->info().format;
info.subresourceRange = vk::makeSubresourceRange(srcSubresources);
info.subresourceRange.aspectMask = srcAspects & (VK_IMAGE_ASPECT_COLOR_BIT | VK_IMAGE_ASPECT_DEPTH_BIT);
if ((m_vkd->vkCreateImageView(m_vkd->device(), &info, nullptr, &m_srcImageView)))
throw DxvkError("DxvkMetaCopyViews: Failed to create source image view");
if (srcAspects & VK_IMAGE_ASPECT_STENCIL_BIT) {
info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_STENCIL_BIT;
if ((m_vkd->vkCreateImageView(m_vkd->device(), &info, nullptr, &m_srcStencilView)))
throw DxvkError("DxvkMetaCopyViews: Failed to create source stencil view");
}
} }
DxvkMetaCopyRenderPass::~DxvkMetaCopyRenderPass() { DxvkMetaCopyViews::~DxvkMetaCopyViews() {
m_vkd->vkDestroyFramebuffer(m_vkd->device(), m_framebuffer, nullptr); m_vkd->vkDestroyImageView(m_vkd->device(), m_dstImageView, nullptr);
m_vkd->vkDestroyRenderPass (m_vkd->device(), m_renderPass, nullptr); m_vkd->vkDestroyImageView(m_vkd->device(), m_srcImageView, nullptr);
} m_vkd->vkDestroyImageView(m_vkd->device(), m_srcStencilView, nullptr);
VkRenderPass DxvkMetaCopyRenderPass::createRenderPass(bool discard) const {
auto aspect = m_dstImageView->info().aspect;
VkPipelineStageFlags cpyStages = 0;
VkAccessFlags cpyAccess = 0;
VkAttachmentDescription attachment;
attachment.flags = 0;
attachment.format = m_dstImageView->info().format;
attachment.samples = m_dstImageView->imageInfo().sampleCount;
attachment.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
attachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
attachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
attachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE;
attachment.initialLayout = m_dstImageView->imageInfo().layout;
attachment.finalLayout = m_dstImageView->imageInfo().layout;
if (discard) {
attachment.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
attachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
attachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
}
VkAttachmentReference attachmentRef;
attachmentRef.attachment = 0;
attachmentRef.layout = (aspect & VK_IMAGE_ASPECT_COLOR_BIT)
? m_dstImageView->pickLayout(VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL)
: m_dstImageView->pickLayout(VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL);
VkSubpassDescription subpass;
subpass.flags = 0;
subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
subpass.inputAttachmentCount = 0;
subpass.pInputAttachments = nullptr;
subpass.colorAttachmentCount = 0;
subpass.pColorAttachments = nullptr;
subpass.pResolveAttachments = nullptr;
subpass.pDepthStencilAttachment = nullptr;
subpass.preserveAttachmentCount = 0;
subpass.pPreserveAttachments = nullptr;
if (aspect & VK_IMAGE_ASPECT_COLOR_BIT) {
subpass.colorAttachmentCount = 1;
subpass.pColorAttachments = &attachmentRef;
cpyStages |= VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
cpyAccess |= VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
if (!discard)
cpyAccess |= VK_ACCESS_COLOR_ATTACHMENT_READ_BIT;
} else {
subpass.pDepthStencilAttachment = &attachmentRef;
cpyStages |= VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT
| VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
cpyAccess |= VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
if (!discard)
cpyAccess |= VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT;
}
// We have to be somewhat conservative here since we cannot assume
// that the backend blocks stages that are only used for meta ops
VkPipelineStageFlags extStages = m_dstImageView->imageInfo().stages | m_srcImageView->imageInfo().stages;
VkAccessFlags extAccess = m_dstImageView->imageInfo().access;
std::array<VkSubpassDependency, 2> dependencies = {{
{ VK_SUBPASS_EXTERNAL, 0, extStages, cpyStages, 0, cpyAccess, 0 },
{ 0, VK_SUBPASS_EXTERNAL, cpyStages, extStages, cpyAccess, extAccess, 0 },
}};
VkRenderPassCreateInfo info;
info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
info.pNext = nullptr;
info.flags = 0;
info.attachmentCount = 1;
info.pAttachments = &attachment;
info.subpassCount = 1;
info.pSubpasses = &subpass;
info.dependencyCount = dependencies.size();
info.pDependencies = dependencies.data();
VkRenderPass result = VK_NULL_HANDLE;
if (m_vkd->vkCreateRenderPass(m_vkd->device(), &info, nullptr, &result) != VK_SUCCESS)
throw DxvkError("DxvkMetaCopyRenderPass: Failed to create render pass");
return result;
}
VkFramebuffer DxvkMetaCopyRenderPass::createFramebuffer() const {
VkImageView dstViewHandle = m_dstImageView->handle();
VkImageSubresourceRange dstSubresources = m_dstImageView->subresources();
VkExtent3D dstExtent = m_dstImageView->mipLevelExtent(0);
VkFramebufferCreateInfo fboInfo;
fboInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
fboInfo.pNext = nullptr;
fboInfo.flags = 0;
fboInfo.renderPass = m_renderPass;
fboInfo.attachmentCount = 1;
fboInfo.pAttachments = &dstViewHandle;
fboInfo.width = dstExtent.width;
fboInfo.height = dstExtent.height;
fboInfo.layers = dstSubresources.layerCount;
VkFramebuffer result = VK_NULL_HANDLE;
if (m_vkd->vkCreateFramebuffer(m_vkd->device(), &fboInfo, nullptr, &result) != VK_SUCCESS)
throw DxvkError("DxvkMetaCopyRenderPass: Failed to create target framebuffer");
return result;
} }
DxvkMetaCopyObjects::DxvkMetaCopyObjects(const DxvkDevice* device) DxvkMetaCopyObjects::DxvkMetaCopyObjects(const DxvkDevice* device)
: m_vkd (device->vkd()), : m_vkd (device->vkd()),
m_sampler (createSampler()),
m_color { m_color {
createShaderModule(dxvk_copy_color_1d), createShaderModule(dxvk_copy_color_1d),
createShaderModule(dxvk_copy_color_2d), createShaderModule(dxvk_copy_color_2d),
@ -188,7 +113,6 @@ namespace dxvk {
m_vkd->vkDestroyPipeline(m_vkd->device(), pair.second.pipeHandle, nullptr); m_vkd->vkDestroyPipeline(m_vkd->device(), pair.second.pipeHandle, nullptr);
m_vkd->vkDestroyPipelineLayout(m_vkd->device(), pair.second.pipeLayout, nullptr); m_vkd->vkDestroyPipelineLayout(m_vkd->device(), pair.second.pipeLayout, nullptr);
m_vkd->vkDestroyDescriptorSetLayout (m_vkd->device(), pair.second.dsetLayout, nullptr); m_vkd->vkDestroyDescriptorSetLayout (m_vkd->device(), pair.second.dsetLayout, nullptr);
m_vkd->vkDestroyRenderPass(m_vkd->device(), pair.second.renderPass, nullptr);
} }
m_vkd->vkDestroyShaderModule(m_vkd->device(), m_depthStencil.fragMs, nullptr); m_vkd->vkDestroyShaderModule(m_vkd->device(), m_depthStencil.fragMs, nullptr);
@ -202,8 +126,6 @@ namespace dxvk {
m_vkd->vkDestroyShaderModule(m_vkd->device(), m_color.frag1D, nullptr); m_vkd->vkDestroyShaderModule(m_vkd->device(), m_color.frag1D, nullptr);
m_vkd->vkDestroyShaderModule(m_vkd->device(), m_shaderGeom, nullptr); m_vkd->vkDestroyShaderModule(m_vkd->device(), m_shaderGeom, nullptr);
m_vkd->vkDestroyShaderModule(m_vkd->device(), m_shaderVert, nullptr); m_vkd->vkDestroyShaderModule(m_vkd->device(), m_shaderVert, nullptr);
m_vkd->vkDestroySampler(m_vkd->device(), m_sampler, nullptr);
} }
@ -267,34 +189,6 @@ namespace dxvk {
} }
VkSampler DxvkMetaCopyObjects::createSampler() const {
VkSamplerCreateInfo info;
info.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
info.pNext = nullptr;
info.flags = 0;
info.magFilter = VK_FILTER_NEAREST;
info.minFilter = VK_FILTER_NEAREST;
info.mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST;
info.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
info.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
info.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
info.mipLodBias = 0.0f;
info.anisotropyEnable = VK_FALSE;
info.maxAnisotropy = 1.0f;
info.compareEnable = VK_FALSE;
info.compareOp = VK_COMPARE_OP_ALWAYS;
info.minLod = 0.0f;
info.maxLod = 0.0f;
info.borderColor = VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK;
info.unnormalizedCoordinates = VK_FALSE;
VkSampler result = VK_NULL_HANDLE;
if (m_vkd->vkCreateSampler(m_vkd->device(), &info, nullptr, &result) != VK_SUCCESS)
throw DxvkError("DxvkMetaCopyObjects: Failed to create sampler");
return result;
}
VkShaderModule DxvkMetaCopyObjects::createShaderModule( VkShaderModule DxvkMetaCopyObjects::createShaderModule(
const SpirvCodeBuffer& code) const { const SpirvCodeBuffer& code) const {
VkShaderModuleCreateInfo info; VkShaderModuleCreateInfo info;
@ -313,17 +207,13 @@ namespace dxvk {
DxvkMetaCopyPipeline DxvkMetaCopyObjects::createCopyBufferImagePipeline() { DxvkMetaCopyPipeline DxvkMetaCopyObjects::createCopyBufferImagePipeline() {
DxvkMetaCopyPipeline pipeline; DxvkMetaCopyPipeline pipeline;
pipeline.renderPass = VK_NULL_HANDLE;
std::array<VkDescriptorSetLayoutBinding, 2> bindings = {{ std::array<VkDescriptorSetLayoutBinding, 2> bindings = {{
{ 0, VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER, 1, VK_SHADER_STAGE_COMPUTE_BIT, nullptr }, { 0, VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER, 1, VK_SHADER_STAGE_COMPUTE_BIT, nullptr },
{ 1, VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER, 1, VK_SHADER_STAGE_COMPUTE_BIT, nullptr }, { 1, VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER, 1, VK_SHADER_STAGE_COMPUTE_BIT, nullptr },
}}; }};
VkDescriptorSetLayoutCreateInfo setLayoutInfo; VkDescriptorSetLayoutCreateInfo setLayoutInfo = { VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO };
setLayoutInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
setLayoutInfo.pNext = nullptr;
setLayoutInfo.flags = 0;
setLayoutInfo.bindingCount = bindings.size(); setLayoutInfo.bindingCount = bindings.size();
setLayoutInfo.pBindings = bindings.data(); setLayoutInfo.pBindings = bindings.data();
@ -332,10 +222,7 @@ namespace dxvk {
VkPushConstantRange pushRange = { VK_SHADER_STAGE_COMPUTE_BIT, 0, sizeof(DxvkCopyBufferImageArgs) }; VkPushConstantRange pushRange = { VK_SHADER_STAGE_COMPUTE_BIT, 0, sizeof(DxvkCopyBufferImageArgs) };
VkPipelineLayoutCreateInfo pipelineLayoutInfo; VkPipelineLayoutCreateInfo pipelineLayoutInfo = { VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO };
pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
pipelineLayoutInfo.pNext = nullptr;
pipelineLayoutInfo.flags = 0;
pipelineLayoutInfo.setLayoutCount = 1; pipelineLayoutInfo.setLayoutCount = 1;
pipelineLayoutInfo.pSetLayouts = &pipeline.dsetLayout; pipelineLayoutInfo.pSetLayouts = &pipeline.dsetLayout;
pipelineLayoutInfo.pushConstantRangeCount = 1; pipelineLayoutInfo.pushConstantRangeCount = 1;
@ -346,19 +233,12 @@ namespace dxvk {
VkShaderModule shaderModule = createShaderModule(dxvk_copy_buffer_image); VkShaderModule shaderModule = createShaderModule(dxvk_copy_buffer_image);
VkComputePipelineCreateInfo pipelineInfo; VkComputePipelineCreateInfo pipelineInfo = { VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO };
pipelineInfo.sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO;
pipelineInfo.pNext = nullptr;
pipelineInfo.flags = 0;
pipelineInfo.layout = pipeline.pipeLayout; pipelineInfo.layout = pipeline.pipeLayout;
pipelineInfo.stage.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; pipelineInfo.stage.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
pipelineInfo.stage.pNext = nullptr;
pipelineInfo.stage.flags = 0;
pipelineInfo.stage.stage = VK_SHADER_STAGE_COMPUTE_BIT; pipelineInfo.stage.stage = VK_SHADER_STAGE_COMPUTE_BIT;
pipelineInfo.stage.module = shaderModule; pipelineInfo.stage.module = shaderModule;
pipelineInfo.stage.pName = "main"; pipelineInfo.stage.pName = "main";
pipelineInfo.stage.pSpecializationInfo = nullptr;
pipelineInfo.basePipelineHandle = VK_NULL_HANDLE;
pipelineInfo.basePipelineIndex = -1; pipelineInfo.basePipelineIndex = -1;
if (m_vkd->vkCreateComputePipelines(m_vkd->device(), VK_NULL_HANDLE, if (m_vkd->vkCreateComputePipelines(m_vkd->device(), VK_NULL_HANDLE,
@ -373,96 +253,24 @@ namespace dxvk {
DxvkMetaCopyPipeline DxvkMetaCopyObjects::createPipeline( DxvkMetaCopyPipeline DxvkMetaCopyObjects::createPipeline(
const DxvkMetaCopyPipelineKey& key) { const DxvkMetaCopyPipelineKey& key) {
DxvkMetaCopyPipeline pipeline; DxvkMetaCopyPipeline pipeline;
pipeline.renderPass = this->createRenderPass(key);
pipeline.dsetLayout = this->createDescriptorSetLayout(key); pipeline.dsetLayout = this->createDescriptorSetLayout(key);
pipeline.pipeLayout = this->createPipelineLayout(pipeline.dsetLayout); pipeline.pipeLayout = this->createPipelineLayout(pipeline.dsetLayout);
pipeline.pipeHandle = this->createPipelineObject(key, pipeline.pipeLayout, pipeline.renderPass); pipeline.pipeHandle = this->createPipelineObject(key, pipeline.pipeLayout);
return pipeline; return pipeline;
} }
VkRenderPass DxvkMetaCopyObjects::createRenderPass(
const DxvkMetaCopyPipelineKey& key) const {
auto aspect = imageFormatInfo(key.format)->aspectMask;
VkAttachmentDescription attachment;
attachment.flags = 0;
attachment.format = key.format;
attachment.samples = key.samples;
attachment.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
attachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
attachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
attachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE;
attachment.initialLayout = VK_IMAGE_LAYOUT_GENERAL;
attachment.finalLayout = VK_IMAGE_LAYOUT_GENERAL;
VkAttachmentReference attachmentRef;
attachmentRef.attachment = 0;
attachmentRef.layout = (aspect & VK_IMAGE_ASPECT_COLOR_BIT)
? VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL
: VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
VkSubpassDescription subpass;
subpass.flags = 0;
subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
subpass.inputAttachmentCount = 0;
subpass.pInputAttachments = nullptr;
subpass.colorAttachmentCount = 0;
subpass.pColorAttachments = nullptr;
subpass.pResolveAttachments = nullptr;
subpass.pDepthStencilAttachment = nullptr;
subpass.preserveAttachmentCount = 0;
subpass.pPreserveAttachments = nullptr;
if (aspect & VK_IMAGE_ASPECT_COLOR_BIT) {
subpass.colorAttachmentCount = 1;
subpass.pColorAttachments = &attachmentRef;
} else {
subpass.pDepthStencilAttachment = &attachmentRef;
}
VkRenderPassCreateInfo info;
info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
info.pNext = nullptr;
info.flags = 0;
info.attachmentCount = 1;
info.pAttachments = &attachment;
info.subpassCount = 1;
info.pSubpasses = &subpass;
info.dependencyCount = 0;
info.pDependencies = nullptr;
VkRenderPass result = VK_NULL_HANDLE;
if (m_vkd->vkCreateRenderPass(m_vkd->device(), &info, nullptr, &result) != VK_SUCCESS)
throw DxvkError("DxvkMetaCopyObjects: Failed to create render pass");
return result;
}
VkDescriptorSetLayout DxvkMetaCopyObjects::createDescriptorSetLayout( VkDescriptorSetLayout DxvkMetaCopyObjects::createDescriptorSetLayout(
const DxvkMetaCopyPipelineKey& key) const { const DxvkMetaCopyPipelineKey& key) const {
std::array<VkDescriptorSetLayoutBinding, 2> bindings; std::array<VkDescriptorSetLayoutBinding, 2> bindings = {{
{ 0, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 1, VK_SHADER_STAGE_FRAGMENT_BIT },
{ 1, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 1, VK_SHADER_STAGE_FRAGMENT_BIT },
}};
for (uint32_t i = 0; i < 2; i++) { VkDescriptorSetLayoutCreateInfo info = { VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO };
bindings[i].binding = i; info.bindingCount = bindings.size();
bindings[i].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
bindings[i].descriptorCount = 1;
bindings[i].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
bindings[i].pImmutableSamplers = &m_sampler;
}
VkDescriptorSetLayoutCreateInfo info;
info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
info.pNext = nullptr;
info.flags = 0;
info.bindingCount = 1;
info.pBindings = bindings.data(); info.pBindings = bindings.data();
auto format = imageFormatInfo(key.format);
if (format->aspectMask == (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT))
info.bindingCount = 2;
VkDescriptorSetLayout result = VK_NULL_HANDLE; VkDescriptorSetLayout result = VK_NULL_HANDLE;
if (m_vkd->vkCreateDescriptorSetLayout(m_vkd->device(), &info, nullptr, &result) != VK_SUCCESS) if (m_vkd->vkCreateDescriptorSetLayout(m_vkd->device(), &info, nullptr, &result) != VK_SUCCESS)
throw DxvkError("DxvkMetaCopyObjects: Failed to create descriptor set layout"); throw DxvkError("DxvkMetaCopyObjects: Failed to create descriptor set layout");
@ -472,15 +280,9 @@ namespace dxvk {
VkPipelineLayout DxvkMetaCopyObjects::createPipelineLayout( VkPipelineLayout DxvkMetaCopyObjects::createPipelineLayout(
VkDescriptorSetLayout descriptorSetLayout) const { VkDescriptorSetLayout descriptorSetLayout) const {
VkPushConstantRange push; VkPushConstantRange push = { VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(VkOffset2D) };
push.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
push.offset = 0;
push.size = sizeof(VkOffset2D);
VkPipelineLayoutCreateInfo info; VkPipelineLayoutCreateInfo info = { VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO };
info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
info.pNext = nullptr;
info.flags = 0;
info.setLayoutCount = 1; info.setLayoutCount = 1;
info.pSetLayouts = &descriptorSetLayout; info.pSetLayouts = &descriptorSetLayout;
info.pushConstantRangeCount = 1; info.pushConstantRangeCount = 1;
@ -495,42 +297,22 @@ namespace dxvk {
VkPipeline DxvkMetaCopyObjects::createPipelineObject( VkPipeline DxvkMetaCopyObjects::createPipelineObject(
const DxvkMetaCopyPipelineKey& key, const DxvkMetaCopyPipelineKey& key,
VkPipelineLayout pipelineLayout, VkPipelineLayout pipelineLayout) {
VkRenderPass renderPass) {
auto aspect = imageFormatInfo(key.format)->aspectMask; auto aspect = imageFormatInfo(key.format)->aspectMask;
std::array<VkPipelineShaderStageCreateInfo, 3> stages; std::array<VkPipelineShaderStageCreateInfo, 3> stages;
uint32_t stageCount = 0; uint32_t stageCount = 0;
VkPipelineShaderStageCreateInfo& vsStage = stages[stageCount++]; stages[stageCount++] = VkPipelineShaderStageCreateInfo {
vsStage.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, nullptr, 0,
vsStage.pNext = nullptr; VK_SHADER_STAGE_VERTEX_BIT, m_shaderVert, "main" };
vsStage.flags = 0;
vsStage.stage = VK_SHADER_STAGE_VERTEX_BIT;
vsStage.module = m_shaderVert;
vsStage.pName = "main";
vsStage.pSpecializationInfo = nullptr;
if (m_shaderGeom) { if (m_shaderGeom) {
VkPipelineShaderStageCreateInfo& gsStage = stages[stageCount++]; stages[stageCount++] = VkPipelineShaderStageCreateInfo {
gsStage.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, nullptr, 0,
gsStage.pNext = nullptr; VK_SHADER_STAGE_GEOMETRY_BIT, m_shaderGeom, "main" };
gsStage.flags = 0;
gsStage.stage = VK_SHADER_STAGE_GEOMETRY_BIT;
gsStage.module = m_shaderGeom;
gsStage.pName = "main";
gsStage.pSpecializationInfo = nullptr;
} }
VkPipelineShaderStageCreateInfo& psStage = stages[stageCount++];
psStage.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
psStage.pNext = nullptr;
psStage.flags = 0;
psStage.stage = VK_SHADER_STAGE_FRAGMENT_BIT;
psStage.module = VK_NULL_HANDLE;
psStage.pName = "main";
psStage.pSpecializationInfo = nullptr;
std::array<std::pair<const FragShaders*, VkImageAspectFlags>, 3> shaderSets = {{ std::array<std::pair<const FragShaders*, VkImageAspectFlags>, 3> shaderSets = {{
{ &m_color, VK_IMAGE_ASPECT_COLOR_BIT }, { &m_color, VK_IMAGE_ASPECT_COLOR_BIT },
{ &m_depth, VK_IMAGE_ASPECT_DEPTH_BIT }, { &m_depth, VK_IMAGE_ASPECT_DEPTH_BIT },
@ -545,135 +327,95 @@ namespace dxvk {
} }
if (!shaderSet) if (!shaderSet)
throw DxvkError("DxvkMetaCopyObjects: Unsupported aspect mask"); throw DxvkError(str::format("DxvkMetaCopyObjects: Unsupported aspect mask: ", aspect));
VkShaderModule psModule = VK_NULL_HANDLE;
if (key.viewType == VK_IMAGE_VIEW_TYPE_1D_ARRAY) if (key.viewType == VK_IMAGE_VIEW_TYPE_1D_ARRAY)
psStage.module = shaderSet->frag1D; psModule = shaderSet->frag1D;
else if (key.samples == VK_SAMPLE_COUNT_1_BIT) else if (key.samples == VK_SAMPLE_COUNT_1_BIT)
psStage.module = shaderSet->frag2D; psModule = shaderSet->frag2D;
else else
psStage.module = shaderSet->fragMs; psModule = shaderSet->fragMs;
stages[stageCount++] = VkPipelineShaderStageCreateInfo {
VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, nullptr, 0,
VK_SHADER_STAGE_FRAGMENT_BIT, psModule, "main" };
std::array<VkDynamicState, 2> dynStates = {{ std::array<VkDynamicState, 2> dynStates = {{
VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_VIEWPORT,
VK_DYNAMIC_STATE_SCISSOR, VK_DYNAMIC_STATE_SCISSOR,
}}; }};
VkPipelineDynamicStateCreateInfo dynState; VkPipelineDynamicStateCreateInfo dynState = { VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO };
dynState.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
dynState.pNext = nullptr;
dynState.flags = 0;
dynState.dynamicStateCount = dynStates.size(); dynState.dynamicStateCount = dynStates.size();
dynState.pDynamicStates = dynStates.data(); dynState.pDynamicStates = dynStates.data();
VkPipelineVertexInputStateCreateInfo viState; VkPipelineVertexInputStateCreateInfo viState = { VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO };
viState.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
viState.pNext = nullptr;
viState.flags = 0;
viState.vertexBindingDescriptionCount = 0;
viState.pVertexBindingDescriptions = nullptr;
viState.vertexAttributeDescriptionCount = 0;
viState.pVertexAttributeDescriptions = nullptr;
VkPipelineInputAssemblyStateCreateInfo iaState; VkPipelineInputAssemblyStateCreateInfo iaState = { VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO };
iaState.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
iaState.pNext = nullptr;
iaState.flags = 0;
iaState.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; iaState.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
iaState.primitiveRestartEnable = VK_FALSE;
VkPipelineViewportStateCreateInfo vpState; VkPipelineViewportStateCreateInfo vpState = { VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO };
vpState.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
vpState.pNext = nullptr;
vpState.flags = 0;
vpState.viewportCount = 1; vpState.viewportCount = 1;
vpState.pViewports = nullptr;
vpState.scissorCount = 1; vpState.scissorCount = 1;
vpState.pScissors = nullptr;
VkPipelineRasterizationStateCreateInfo rsState; VkPipelineRasterizationStateCreateInfo rsState = { VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO };
rsState.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
rsState.pNext = nullptr;
rsState.flags = 0;
rsState.depthClampEnable = VK_TRUE; rsState.depthClampEnable = VK_TRUE;
rsState.rasterizerDiscardEnable = VK_FALSE;
rsState.polygonMode = VK_POLYGON_MODE_FILL; rsState.polygonMode = VK_POLYGON_MODE_FILL;
rsState.cullMode = VK_CULL_MODE_NONE; rsState.cullMode = VK_CULL_MODE_NONE;
rsState.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE; rsState.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE;
rsState.depthBiasEnable = VK_FALSE;
rsState.depthBiasConstantFactor = 0.0f;
rsState.depthBiasClamp = 0.0f;
rsState.depthBiasSlopeFactor = 0.0f;
rsState.lineWidth = 1.0f; rsState.lineWidth = 1.0f;
uint32_t msMask = 0xFFFFFFFF; uint32_t msMask = 0xFFFFFFFF;
VkPipelineMultisampleStateCreateInfo msState; VkPipelineMultisampleStateCreateInfo msState = { VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO };
msState.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
msState.pNext = nullptr;
msState.flags = 0;
msState.rasterizationSamples = key.samples; msState.rasterizationSamples = key.samples;
msState.sampleShadingEnable = key.samples != VK_SAMPLE_COUNT_1_BIT; msState.sampleShadingEnable = key.samples != VK_SAMPLE_COUNT_1_BIT;
msState.minSampleShading = 1.0f; msState.minSampleShading = 1.0f;
msState.pSampleMask = &msMask; msState.pSampleMask = &msMask;
msState.alphaToCoverageEnable = VK_FALSE;
msState.alphaToOneEnable = VK_FALSE;
VkPipelineColorBlendAttachmentState cbAttachment; VkPipelineColorBlendAttachmentState cbAttachment = { };
cbAttachment.blendEnable = VK_FALSE;
cbAttachment.srcColorBlendFactor = VK_BLEND_FACTOR_ONE;
cbAttachment.dstColorBlendFactor = VK_BLEND_FACTOR_ZERO;
cbAttachment.colorBlendOp = VK_BLEND_OP_ADD;
cbAttachment.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE;
cbAttachment.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO;
cbAttachment.alphaBlendOp = VK_BLEND_OP_ADD;
cbAttachment.colorWriteMask = cbAttachment.colorWriteMask =
VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT |
VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
VkPipelineColorBlendStateCreateInfo cbState; VkPipelineColorBlendStateCreateInfo cbState = { VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO };
cbState.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
cbState.pNext = nullptr;
cbState.flags = 0;
cbState.logicOpEnable = VK_FALSE;
cbState.logicOp = VK_LOGIC_OP_NO_OP;
cbState.attachmentCount = 1; cbState.attachmentCount = 1;
cbState.pAttachments = &cbAttachment; cbState.pAttachments = &cbAttachment;
for (uint32_t i = 0; i < 4; i++) VkStencilOpState stencilOp = { };
cbState.blendConstants[i] = 0.0f;
VkStencilOpState stencilOp;
stencilOp.failOp = VK_STENCIL_OP_REPLACE; stencilOp.failOp = VK_STENCIL_OP_REPLACE;
stencilOp.passOp = VK_STENCIL_OP_REPLACE; stencilOp.passOp = VK_STENCIL_OP_REPLACE;
stencilOp.depthFailOp = VK_STENCIL_OP_REPLACE; stencilOp.depthFailOp = VK_STENCIL_OP_REPLACE;
stencilOp.compareOp = VK_COMPARE_OP_ALWAYS; stencilOp.compareOp = VK_COMPARE_OP_ALWAYS;
stencilOp.compareMask = 0xFFFFFFFF; stencilOp.compareMask = 0xFFFFFFFF;
stencilOp.writeMask = 0xFFFFFFFF; stencilOp.writeMask = 0xFFFFFFFF;
stencilOp.reference = 0;
VkPipelineDepthStencilStateCreateInfo dsState; VkPipelineDepthStencilStateCreateInfo dsState = { VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO };
dsState.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
dsState.pNext = nullptr;
dsState.flags = 0;
dsState.depthTestEnable = VK_TRUE; dsState.depthTestEnable = VK_TRUE;
dsState.depthWriteEnable = VK_TRUE; dsState.depthWriteEnable = VK_TRUE;
dsState.depthCompareOp = VK_COMPARE_OP_ALWAYS; dsState.depthCompareOp = VK_COMPARE_OP_ALWAYS;
dsState.depthBoundsTestEnable = VK_FALSE;
dsState.stencilTestEnable = VK_TRUE; dsState.stencilTestEnable = VK_TRUE;
dsState.front = stencilOp; dsState.front = stencilOp;
dsState.back = stencilOp; dsState.back = stencilOp;
dsState.minDepthBounds = 0.0f;
dsState.maxDepthBounds = 1.0f;
VkGraphicsPipelineCreateInfo info; VkPipelineRenderingCreateInfoKHR rtState = { VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO_KHR };
info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
info.pNext = nullptr; if (aspect & VK_IMAGE_ASPECT_COLOR_BIT) {
info.flags = 0; rtState.colorAttachmentCount = 1;
rtState.pColorAttachmentFormats = &key.format;
} else {
if (aspect & VK_IMAGE_ASPECT_DEPTH_BIT)
rtState.depthAttachmentFormat = key.format;
if (aspect & VK_IMAGE_ASPECT_STENCIL_BIT)
rtState.stencilAttachmentFormat = key.format;
}
VkGraphicsPipelineCreateInfo info = { VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, &rtState };
info.stageCount = stageCount; info.stageCount = stageCount;
info.pStages = stages.data(); info.pStages = stages.data();
info.pVertexInputState = &viState; info.pVertexInputState = &viState;
info.pInputAssemblyState = &iaState; info.pInputAssemblyState = &iaState;
info.pTessellationState = nullptr;
info.pViewportState = &vpState; info.pViewportState = &vpState;
info.pRasterizationState = &rsState; info.pRasterizationState = &rsState;
info.pMultisampleState = &msState; info.pMultisampleState = &msState;
@ -681,9 +423,6 @@ namespace dxvk {
info.pDepthStencilState = (aspect & VK_IMAGE_ASPECT_COLOR_BIT) ? nullptr : &dsState; info.pDepthStencilState = (aspect & VK_IMAGE_ASPECT_COLOR_BIT) ? nullptr : &dsState;
info.pDynamicState = &dynState; info.pDynamicState = &dynState;
info.layout = pipelineLayout; info.layout = pipelineLayout;
info.renderPass = renderPass;
info.subpass = 0;
info.basePipelineHandle = VK_NULL_HANDLE;
info.basePipelineIndex = -1; info.basePipelineIndex = -1;
VkPipeline result = VK_NULL_HANDLE; VkPipeline result = VK_NULL_HANDLE;

View File

@ -32,7 +32,6 @@ namespace dxvk {
* that is used for fragment shader copies. * that is used for fragment shader copies.
*/ */
struct DxvkMetaCopyPipeline { struct DxvkMetaCopyPipeline {
VkRenderPass renderPass;
VkDescriptorSetLayout dsetLayout; VkDescriptorSetLayout dsetLayout;
VkPipelineLayout pipeLayout; VkPipelineLayout pipeLayout;
VkPipeline pipeHandle; VkPipeline pipeHandle;
@ -63,46 +62,43 @@ namespace dxvk {
}; };
/** /**
* \brief Copy framebuffer and render pass * \brief Copy view objects
* *
* Creates a framebuffer and render * Creates and manages views used in a
* pass object for an image view. * framebuffer-based copy operations.
*/ */
class DxvkMetaCopyRenderPass : public DxvkResource { class DxvkMetaCopyViews : public DxvkResource {
public: public:
DxvkMetaCopyRenderPass( DxvkMetaCopyViews(
const Rc<vk::DeviceFn>& vkd, const Rc<vk::DeviceFn>& vkd,
const Rc<DxvkImageView>& dstImageView, const Rc<DxvkImage>& dstImage,
const Rc<DxvkImageView>& srcImageView, const VkImageSubresourceLayers& dstSubresources,
const Rc<DxvkImageView>& srcStencilView, VkFormat dstFormat,
bool discardDst); const Rc<DxvkImage>& srcImage,
const VkImageSubresourceLayers& srcSubresources);
~DxvkMetaCopyRenderPass(); ~DxvkMetaCopyViews();
VkRenderPass renderPass() const { VkImageView getDstView() const { return m_dstImageView; }
return m_renderPass; VkImageView getSrcView() const { return m_srcImageView; }
} VkImageView getSrcStencilView() const { return m_srcStencilView; }
VkFramebuffer framebuffer() const { VkImageViewType getSrcViewType() const {
return m_framebuffer; return m_srcViewType;
} }
private: private:
Rc<vk::DeviceFn> m_vkd; Rc<vk::DeviceFn> m_vkd;
Rc<DxvkImageView> m_dstImageView; VkImageViewType m_srcViewType = VK_IMAGE_VIEW_TYPE_MAX_ENUM;
Rc<DxvkImageView> m_srcImageView; VkImageViewType m_dstViewType = VK_IMAGE_VIEW_TYPE_MAX_ENUM;
Rc<DxvkImageView> m_srcStencilView;
VkRenderPass m_renderPass = VK_NULL_HANDLE; VkImageView m_dstImageView = VK_NULL_HANDLE;
VkFramebuffer m_framebuffer = VK_NULL_HANDLE; VkImageView m_srcImageView = VK_NULL_HANDLE;
VkImageView m_srcStencilView = VK_NULL_HANDLE;
VkRenderPass createRenderPass(bool discard) const;
VkFramebuffer createFramebuffer() const;
}; };
@ -162,8 +158,6 @@ namespace dxvk {
Rc<vk::DeviceFn> m_vkd; Rc<vk::DeviceFn> m_vkd;
VkSampler m_sampler;
VkShaderModule m_shaderVert = VK_NULL_HANDLE; VkShaderModule m_shaderVert = VK_NULL_HANDLE;
VkShaderModule m_shaderGeom = VK_NULL_HANDLE; VkShaderModule m_shaderGeom = VK_NULL_HANDLE;
@ -180,8 +174,6 @@ namespace dxvk {
DxvkMetaCopyPipeline m_copyBufferImagePipeline = { }; DxvkMetaCopyPipeline m_copyBufferImagePipeline = { };
VkSampler createSampler() const;
VkShaderModule createShaderModule( VkShaderModule createShaderModule(
const SpirvCodeBuffer& code) const; const SpirvCodeBuffer& code) const;
@ -190,9 +182,6 @@ namespace dxvk {
DxvkMetaCopyPipeline createPipeline( DxvkMetaCopyPipeline createPipeline(
const DxvkMetaCopyPipelineKey& key); const DxvkMetaCopyPipelineKey& key);
VkRenderPass createRenderPass(
const DxvkMetaCopyPipelineKey& key) const;
VkDescriptorSetLayout createDescriptorSetLayout( VkDescriptorSetLayout createDescriptorSetLayout(
const DxvkMetaCopyPipelineKey& key) const; const DxvkMetaCopyPipelineKey& key) const;
@ -201,8 +190,7 @@ namespace dxvk {
VkPipeline createPipelineObject( VkPipeline createPipelineObject(
const DxvkMetaCopyPipelineKey& key, const DxvkMetaCopyPipelineKey& key,
VkPipelineLayout pipelineLayout, VkPipelineLayout pipelineLayout);
VkRenderPass renderPass);
}; };

View File

@ -1,7 +1,9 @@
#version 450 #version 450
#extension GL_EXT_samplerless_texture_functions : require
layout(set = 0, binding = 0) layout(set = 0, binding = 0)
uniform sampler1DArray s_image; uniform texture1DArray s_image;
layout(location = 0) out vec4 o_color; layout(location = 0) out vec4 o_color;

View File

@ -1,7 +1,9 @@
#version 450 #version 450
#extension GL_EXT_samplerless_texture_functions : require
layout(set = 0, binding = 0) layout(set = 0, binding = 0)
uniform sampler2DArray s_image; uniform texture2DArray s_image;
layout(location = 0) out vec4 o_color; layout(location = 0) out vec4 o_color;

View File

@ -1,7 +1,9 @@
#version 450 #version 450
#extension GL_EXT_samplerless_texture_functions : require
layout(set = 0, binding = 0) layout(set = 0, binding = 0)
uniform sampler2DMSArray s_image; uniform texture2DMSArray s_image;
layout(location = 0) out vec4 o_color; layout(location = 0) out vec4 o_color;

View File

@ -1,7 +1,9 @@
#version 450 #version 450
#extension GL_EXT_samplerless_texture_functions : require
layout(set = 0, binding = 0) layout(set = 0, binding = 0)
uniform sampler1DArray s_image; uniform texture1DArray s_image;
layout(push_constant) layout(push_constant)
uniform u_info_t { uniform u_info_t {

View File

@ -1,7 +1,9 @@
#version 450 #version 450
#extension GL_EXT_samplerless_texture_functions : require
layout(set = 0, binding = 0) layout(set = 0, binding = 0)
uniform sampler2DArray s_image; uniform texture2DArray s_image;
layout(push_constant) layout(push_constant)
uniform u_info_t { uniform u_info_t {

View File

@ -1,7 +1,9 @@
#version 450 #version 450
#extension GL_EXT_samplerless_texture_functions : require
layout(set = 0, binding = 0) layout(set = 0, binding = 0)
uniform sampler2DMSArray s_image; uniform texture2DMSArray s_image;
layout(push_constant) layout(push_constant)
uniform u_info_t { uniform u_info_t {

View File

@ -1,12 +1,13 @@
#version 450 #version 450
#extension GL_ARB_shader_stencil_export : enable #extension GL_ARB_shader_stencil_export : require
#extension GL_EXT_samplerless_texture_functions : require
layout(set = 0, binding = 0) layout(set = 0, binding = 0)
uniform sampler1DArray s_depth; uniform texture1DArray s_depth;
layout(set = 0, binding = 1) layout(set = 0, binding = 1)
uniform usampler1DArray s_stencil; uniform utexture1DArray s_stencil;
layout(push_constant) layout(push_constant)
uniform u_info_t { uniform u_info_t {

View File

@ -1,12 +1,13 @@
#version 450 #version 450
#extension GL_ARB_shader_stencil_export : enable #extension GL_ARB_shader_stencil_export : enable
#extension GL_EXT_samplerless_texture_functions : require
layout(set = 0, binding = 0) layout(set = 0, binding = 0)
uniform sampler2DArray s_depth; uniform texture2DArray s_depth;
layout(set = 0, binding = 1) layout(set = 0, binding = 1)
uniform usampler2DArray s_stencil; uniform utexture2DArray s_stencil;
layout(push_constant) layout(push_constant)
uniform u_info_t { uniform u_info_t {

View File

@ -1,12 +1,13 @@
#version 450 #version 450
#extension GL_ARB_shader_stencil_export : enable #extension GL_ARB_shader_stencil_export : enable
#extension GL_EXT_samplerless_texture_functions : require
layout(set = 0, binding = 0) layout(set = 0, binding = 0)
uniform sampler2DMSArray s_depth; uniform texture2DMSArray s_depth;
layout(set = 0, binding = 1) layout(set = 0, binding = 1)
uniform usampler2DMSArray s_stencil; uniform utexture2DMSArray s_stencil;
layout(push_constant) layout(push_constant)
uniform u_info_t { uniform u_info_t {