diff --git a/src/dxvk/dxvk_context.cpp b/src/dxvk/dxvk_context.cpp index e5309ebb..f39c22ab 100644 --- a/src/dxvk/dxvk_context.cpp +++ b/src/dxvk/dxvk_context.cpp @@ -10,11 +10,13 @@ namespace dxvk { const Rc& device, const Rc& pipelineManager, const Rc& metaClearObjects, - const Rc& metaMipGenObjects) - : m_device (device), - m_pipeMgr (pipelineManager), - m_metaClear (metaClearObjects), - m_metaMipGen(metaMipGenObjects) { } + const Rc& metaMipGenObjects, + const Rc& metaResolveObjects) + : m_device (device), + m_pipeMgr (pipelineManager), + m_metaClear (metaClearObjects), + m_metaMipGen (metaMipGenObjects), + m_metaResolve (metaResolveObjects) { } DxvkContext::~DxvkContext() { @@ -1174,6 +1176,7 @@ namespace dxvk { const VkImageSubresourceLayers& srcSubresources, VkFormat format) { this->spillRenderPass(); + this->unbindGraphicsPipeline(); m_barriers.recordCommands(m_cmd); @@ -1246,27 +1249,93 @@ namespace dxvk { srcImage->info().stages, srcImage->info().access); } else { - // The trick here is to submit an empty render pass which - // performs the resolve op on properly typed image views. - const Rc fb = - new DxvkMetaResolveFramebuffer(m_device->vkd(), - dstImage, dstSubresources, - srcImage, srcSubresources, format); + // Create image views covering the requested subresourcs + DxvkImageViewCreateInfo dstViewInfo; + dstViewInfo.type = VK_IMAGE_VIEW_TYPE_2D_ARRAY; + dstViewInfo.format = format; + dstViewInfo.aspect = dstSubresources.aspectMask; + dstViewInfo.minLevel = dstSubresources.mipLevel; + dstViewInfo.numLevels = 1; + dstViewInfo.minLayer = dstSubresources.baseArrayLayer; + dstViewInfo.numLayers = dstSubresources.layerCount; + + DxvkImageViewCreateInfo srcViewInfo; + srcViewInfo.type = VK_IMAGE_VIEW_TYPE_2D_ARRAY; + srcViewInfo.format = format; + srcViewInfo.aspect = srcSubresources.aspectMask; + srcViewInfo.minLevel = srcSubresources.mipLevel; + srcViewInfo.numLevels = 1; + srcViewInfo.minLayer = srcSubresources.baseArrayLayer; + srcViewInfo.numLayers = srcSubresources.layerCount; + + Rc dstImageView = m_device->createImageView(dstImage, dstViewInfo); + Rc srcImageView = m_device->createImageView(srcImage, srcViewInfo); + + // Create a framebuffer and pipeline for the resolve op + DxvkMetaResolvePipeline pipeInfo = m_metaResolve->getPipeline(format); + + Rc fb = new DxvkMetaResolveRenderPass( + m_device->vkd(), dstImageView, srcImageView); + + // Create descriptor set pointing to the source image + VkDescriptorImageInfo descriptorImage; + descriptorImage.sampler = VK_NULL_HANDLE; + descriptorImage.imageView = srcImageView->handle(); + descriptorImage.imageLayout = srcImageView->imageInfo().layout; + + 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); + + // Set up viewport and scissor rect + VkExtent3D passExtent = dstImageView->mipLevelExtent(0); + passExtent.depth = dstSubresources.layerCount; + + VkViewport viewport; + viewport.x = 0.0f; + viewport.y = 0.0f; + viewport.width = float(passExtent.width); + viewport.height = float(passExtent.height); + viewport.minDepth = 0.0f; + viewport.maxDepth = 1.0f; + + VkRect2D scissor; + scissor.offset = { 0, 0 }; + scissor.extent = { passExtent.width, passExtent.height }; + + // Render pass info 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; + 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 = { passExtent.width, passExtent.height }; + info.clearValueCount = 0; + info.pClearValues = nullptr; + // Perform the actual resolve operation m_cmd->cmdBeginRenderPass(&info, VK_SUBPASS_CONTENTS_INLINE); - m_cmd->cmdEndRenderPass(); + 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, passExtent.depth, 0, 0); + m_cmd->cmdEndRenderPass(); + m_cmd->trackResource(fb); } diff --git a/src/dxvk/dxvk_context.h b/src/dxvk/dxvk_context.h index ed62c3a8..97a1c046 100644 --- a/src/dxvk/dxvk_context.h +++ b/src/dxvk/dxvk_context.h @@ -32,7 +32,8 @@ namespace dxvk { const Rc& device, const Rc& pipelineManager, const Rc& metaClearObjects, - const Rc& metaMipGenObjects); + const Rc& metaMipGenObjects, + const Rc& metaResolveObjects); ~DxvkContext(); /** @@ -621,10 +622,11 @@ namespace dxvk { private: - const Rc m_device; - const Rc m_pipeMgr; - const Rc m_metaClear; - const Rc m_metaMipGen; + const Rc m_device; + const Rc m_pipeMgr; + const Rc m_metaClear; + const Rc m_metaMipGen; + const Rc m_metaResolve; Rc m_cmd; DxvkContextFlags m_flags; diff --git a/src/dxvk/dxvk_device.cpp b/src/dxvk/dxvk_device.cpp index 7d6b395b..f5eef8d2 100644 --- a/src/dxvk/dxvk_device.cpp +++ b/src/dxvk/dxvk_device.cpp @@ -13,11 +13,12 @@ namespace dxvk { m_extensions (extensions), m_features (features), m_properties (adapter->deviceProperties()), - m_memory (new DxvkMemoryAllocator (adapter, vkd)), - m_renderPassPool (new DxvkRenderPassPool (vkd)), - m_pipelineManager (new DxvkPipelineManager (this)), - m_metaClearObjects (new DxvkMetaClearObjects (vkd)), - m_metaMipGenObjects (new DxvkMetaMipGenObjects(vkd)), + m_memory (new DxvkMemoryAllocator (adapter, vkd)), + m_renderPassPool (new DxvkRenderPassPool (vkd)), + m_pipelineManager (new DxvkPipelineManager (this)), + m_metaClearObjects (new DxvkMetaClearObjects (vkd)), + m_metaMipGenObjects (new DxvkMetaMipGenObjects (vkd)), + m_metaResolveObjects(new DxvkMetaResolveObjects (vkd)), m_unboundResources (this), m_submissionQueue (this) { m_graphicsQueue.queueFamily = m_adapter->graphicsQueueFamily(); @@ -116,7 +117,8 @@ namespace dxvk { return new DxvkContext(this, m_pipelineManager, m_metaClearObjects, - m_metaMipGenObjects); + m_metaMipGenObjects, + m_metaResolveObjects); } diff --git a/src/dxvk/dxvk_device.h b/src/dxvk/dxvk_device.h index 7da64143..c43e92db 100644 --- a/src/dxvk/dxvk_device.h +++ b/src/dxvk/dxvk_device.h @@ -382,6 +382,7 @@ namespace dxvk { Rc m_pipelineManager; Rc m_metaClearObjects; Rc m_metaMipGenObjects; + Rc m_metaResolveObjects; DxvkUnboundResources m_unboundResources; diff --git a/src/dxvk/dxvk_meta_resolve.cpp b/src/dxvk/dxvk_meta_resolve.cpp index 818a61ae..325f1c66 100644 --- a/src/dxvk/dxvk_meta_resolve.cpp +++ b/src/dxvk/dxvk_meta_resolve.cpp @@ -1,135 +1,449 @@ #include "dxvk_meta_resolve.h" +#include +#include +#include +#include +#include + namespace dxvk { - DxvkMetaResolveFramebuffer::DxvkMetaResolveFramebuffer( - const Rc& vkd, - const Rc& dstImage, - VkImageSubresourceLayers dstLayers, - const Rc& srcImage, - VkImageSubresourceLayers srcLayers, - VkFormat format) - : m_vkd(vkd) { - // Create a render pass with one render - // target and one resolve attachment. - std::array 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 + DxvkMetaResolveRenderPass::DxvkMetaResolveRenderPass( + const Rc& vkd, + const Rc& dstImageView, + const Rc& srcImageView) + : m_vkd(vkd), + m_dstImageView(dstImageView), + m_srcImageView(srcImageView), + m_renderPass (createRenderPass ()), + m_framebuffer (createFramebuffer()) { } + + + DxvkMetaResolveRenderPass::~DxvkMetaResolveRenderPass() { + m_vkd->vkDestroyFramebuffer(m_vkd->device(), m_framebuffer, nullptr); + m_vkd->vkDestroyRenderPass (m_vkd->device(), m_renderPass, nullptr); + } + + + VkRenderPass DxvkMetaResolveRenderPass::createRenderPass() const { std::array subpassDeps = {{ { VK_SUBPASS_EXTERNAL, 0, - srcImage->info().stages | dstImage->info().stages, + m_dstImageView->imageInfo().stages, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, - srcImage->info().access | dstImage->info().access, + m_dstImageView->imageInfo().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, + m_dstImageView->imageInfo().stages, VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, - srcImage->info().access | dstImage->info().access, 0 }, + m_dstImageView->imageInfo().access, 0 }, }}; - VkAttachmentReference dstAttachmentRef = { 0, dstImage->pickLayout(VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL) }; - VkAttachmentReference srcAttachmentRef = { 1, srcImage->pickLayout(VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL) }; + 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.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.finalLayout = m_dstImageView->imageInfo().layout; - VkSubpassDescription spInfo; - spInfo.flags = 0; - spInfo.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; - 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 attachments = {{ m_dstImageView, m_srcImageView }}; + VkAttachmentReference attachmentRef; + attachmentRef.attachment = 0; + attachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + VkSubpassDescription subpass; + subpass.flags = 0; + subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; + subpass.inputAttachmentCount = 0; + subpass.pInputAttachments = nullptr; + subpass.colorAttachmentCount = 1; + subpass.pColorAttachments = &attachmentRef; + subpass.pResolveAttachments = nullptr; + subpass.pDepthStencilAttachment = nullptr; + subpass.preserveAttachmentCount = 0; + subpass.pPreserveAttachments = nullptr; + + 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 = subpassDeps.size(); + info.pDependencies = subpassDeps.data(); + + VkRenderPass result = VK_NULL_HANDLE; + if (m_vkd->vkCreateRenderPass(m_vkd->device(), &info, nullptr, &result) != VK_SUCCESS) + throw DxvkError("DxvkMetaResolveRenderPass: Failed to create render pass"); + return result; + } + + + VkFramebuffer DxvkMetaResolveRenderPass::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 = attachments.size(); - fboInfo.pAttachments = attachments.data(); - fboInfo.width = dstImage->info().extent.width; - fboInfo.height = dstImage->info().extent.height; - fboInfo.layers = dstLayers.layerCount; + 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; - m_vkd->vkCreateFramebuffer(m_vkd->device(), &fboInfo, nullptr, &m_framebuffer); + VkFramebuffer result = VK_NULL_HANDLE; + if (m_vkd->vkCreateFramebuffer(m_vkd->device(), &fboInfo, nullptr, &result) != VK_SUCCESS) + throw DxvkError("DxvkMetaMipGenRenderPass: Failed to create target framebuffer"); + return result; + } + + + DxvkMetaResolveObjects::DxvkMetaResolveObjects(const Rc& vkd) + : m_vkd (vkd), + m_sampler (createSampler()), + m_shaderVert (createShaderModule(dxvk_resolve_vert)), + m_shaderGeom (createShaderModule(dxvk_resolve_geom)), + m_shaderFragF (createShaderModule(dxvk_resolve_frag_f)), + m_shaderFragI (createShaderModule(dxvk_resolve_frag_i)), + m_shaderFragU (createShaderModule(dxvk_resolve_frag_u)) { + + } + + + DxvkMetaResolveObjects::~DxvkMetaResolveObjects() { + for (const auto& pair : m_pipelines) { + m_vkd->vkDestroyPipeline(m_vkd->device(), pair.second.pipeHandle, nullptr); + m_vkd->vkDestroyPipelineLayout(m_vkd->device(), pair.second.pipeLayout, 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_shaderFragI, nullptr); + m_vkd->vkDestroyShaderModule(m_vkd->device(), m_shaderFragU, nullptr); + m_vkd->vkDestroyShaderModule(m_vkd->device(), m_shaderFragF, nullptr); + m_vkd->vkDestroyShaderModule(m_vkd->device(), m_shaderGeom, nullptr); + m_vkd->vkDestroyShaderModule(m_vkd->device(), m_shaderVert, nullptr); + + m_vkd->vkDestroySampler(m_vkd->device(), m_sampler, nullptr); + } + + + DxvkMetaResolvePipeline DxvkMetaResolveObjects::getPipeline(VkFormat format) { + std::lock_guard lock(m_mutex); + + auto entry = m_pipelines.find(format); + if (entry != m_pipelines.end()) + return entry->second; + + DxvkMetaResolvePipeline pipeline = this->createPipeline(format); + m_pipelines.insert({ format, pipeline }); + return pipeline; + } + + + VkSampler DxvkMetaResolveObjects::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("DxvkMetaResolveObjects: Failed to create sampler"); + return result; + } + + + VkShaderModule DxvkMetaResolveObjects::createShaderModule(const SpirvCodeBuffer& code) const { + VkShaderModuleCreateInfo info; + info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; + info.pNext = nullptr; + info.flags = 0; + info.codeSize = code.size(); + info.pCode = code.data(); + + VkShaderModule result = VK_NULL_HANDLE; + if (m_vkd->vkCreateShaderModule(m_vkd->device(), &info, nullptr, &result) != VK_SUCCESS) + throw DxvkError("DxvkMetaResolveObjects: Failed to create shader module"); + return result; + } + + + DxvkMetaResolvePipeline DxvkMetaResolveObjects::createPipeline(VkFormat format) { + DxvkMetaResolvePipeline pipeline; + pipeline.renderPass = this->createRenderPass(format); + pipeline.dsetLayout = this->createDescriptorSetLayout(); + pipeline.pipeLayout = this->createPipelineLayout(pipeline.dsetLayout); + pipeline.pipeHandle = this->createPipeline(pipeline.pipeLayout, pipeline.renderPass, format); + return pipeline; + } + + + VkRenderPass DxvkMetaResolveObjects::createRenderPass(VkFormat format) const { + VkAttachmentDescription attachment; + attachment.flags = 0; + attachment.format = format; + attachment.samples = VK_SAMPLE_COUNT_1_BIT; + attachment.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + 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.finalLayout = VK_IMAGE_LAYOUT_GENERAL; + + VkAttachmentReference attachmentRef; + attachmentRef.attachment = 0; + attachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + + VkSubpassDescription subpass; + subpass.flags = 0; + subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; + subpass.inputAttachmentCount = 0; + subpass.pInputAttachments = nullptr; + subpass.colorAttachmentCount = 1; + subpass.pColorAttachments = &attachmentRef; + subpass.pResolveAttachments = nullptr; + subpass.pDepthStencilAttachment = nullptr; + subpass.preserveAttachmentCount = 0; + subpass.pPreserveAttachments = nullptr; + + 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("DxvkMetaResolveObjects: Failed to create render pass"); + return result; + } + + + VkDescriptorSetLayout DxvkMetaResolveObjects::createDescriptorSetLayout() const { + VkDescriptorSetLayoutBinding binding; + binding.binding = 0; + binding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + binding.descriptorCount = 1; + binding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; + binding.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 = &binding; + + VkDescriptorSetLayout result = VK_NULL_HANDLE; + if (m_vkd->vkCreateDescriptorSetLayout(m_vkd->device(), &info, nullptr, &result) != VK_SUCCESS) + throw DxvkError("DxvkMetaMipGenObjects: Failed to create descriptor set layout"); + return result; + } + + + VkPipelineLayout DxvkMetaResolveObjects::createPipelineLayout( + VkDescriptorSetLayout descriptorSetLayout) const { + 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; + + VkPipelineLayout result = VK_NULL_HANDLE; + if (m_vkd->vkCreatePipelineLayout(m_vkd->device(), &info, nullptr, &result) != VK_SUCCESS) + throw DxvkError("DxvkMetaMipGenObjects: Failed to create pipeline layout"); + return result; } - - 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); + + VkPipeline DxvkMetaResolveObjects::createPipeline( + VkPipelineLayout pipelineLayout, + VkRenderPass renderPass, + VkFormat format) const { + std::array stages; + + VkPipelineShaderStageCreateInfo& vsStage = stages[0]; + vsStage.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + vsStage.pNext = nullptr; + vsStage.flags = 0; + vsStage.stage = VK_SHADER_STAGE_VERTEX_BIT; + vsStage.module = m_shaderVert; + vsStage.pName = "main"; + vsStage.pSpecializationInfo = nullptr; + + VkPipelineShaderStageCreateInfo& gsStage = stages[1]; + gsStage.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + gsStage.pNext = nullptr; + gsStage.flags = 0; + gsStage.stage = VK_SHADER_STAGE_GEOMETRY_BIT; + gsStage.module = m_shaderGeom; + gsStage.pName = "main"; + gsStage.pSpecializationInfo = nullptr; + + VkPipelineShaderStageCreateInfo& psStage = stages[2]; + 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 = m_shaderFragF; + psStage.pName = "main"; + psStage.pSpecializationInfo = nullptr; + + auto formatInfo = imageFormatInfo(format); + + if (formatInfo->flags.test(DxvkFormatFlag::SampledUInt)) + psStage.module = m_shaderFragU; + if (formatInfo->flags.test(DxvkFormatFlag::SampledSInt)) + psStage.module = m_shaderFragI; + + std::array dynStates = {{ + VK_DYNAMIC_STATE_VIEWPORT, + VK_DYNAMIC_STATE_SCISSOR, + }}; + + VkPipelineDynamicStateCreateInfo dynState; + dynState.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO; + dynState.pNext = nullptr; + dynState.flags = 0; + dynState.dynamicStateCount = dynStates.size(); + dynState.pDynamicStates = dynStates.data(); + + VkPipelineVertexInputStateCreateInfo viState; + 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; + iaState.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; + iaState.pNext = nullptr; + iaState.flags = 0; + iaState.topology = VK_PRIMITIVE_TOPOLOGY_POINT_LIST; + iaState.primitiveRestartEnable = VK_FALSE; + + VkPipelineViewportStateCreateInfo vpState; + vpState.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; + vpState.pNext = nullptr; + vpState.flags = 0; + vpState.viewportCount = 1; + vpState.pViewports = nullptr; + vpState.scissorCount = 1; + vpState.pScissors = nullptr; + + VkPipelineRasterizationStateCreateInfo rsState; + rsState.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; + rsState.pNext = nullptr; + rsState.flags = 0; + rsState.depthClampEnable = VK_TRUE; + rsState.rasterizerDiscardEnable = VK_FALSE; + rsState.polygonMode = VK_POLYGON_MODE_FILL; + rsState.cullMode = VK_CULL_MODE_NONE; + 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; + + uint32_t msMask = 0xFFFFFFFF; + VkPipelineMultisampleStateCreateInfo msState; + msState.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; + msState.pNext = nullptr; + msState.flags = 0; + msState.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT; + msState.sampleShadingEnable = VK_FALSE; + msState.minSampleShading = 1.0f; + msState.pSampleMask = &msMask; + msState.alphaToCoverageEnable = VK_FALSE; + msState.alphaToOneEnable = VK_FALSE; + + 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 = + VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | + VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; + + VkPipelineColorBlendStateCreateInfo cbState; + 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.pAttachments = &cbAttachment; + + for (uint32_t i = 0; i < 4; i++) + cbState.blendConstants[i] = 0.0f; + + VkGraphicsPipelineCreateInfo info; + info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; + info.pNext = nullptr; + info.flags = 0; + info.stageCount = stages.size(); + info.pStages = stages.data(); + info.pVertexInputState = &viState; + info.pInputAssemblyState = &iaState; + info.pTessellationState = nullptr; + info.pViewportState = &vpState; + info.pRasterizationState = &rsState; + info.pMultisampleState = &msState; + info.pColorBlendState = &cbState; + info.pDepthStencilState = nullptr; + info.pDynamicState = &dynState; + info.layout = pipelineLayout; + info.renderPass = renderPass; + info.subpass = 0; + info.basePipelineHandle = VK_NULL_HANDLE; + info.basePipelineIndex = -1; + + VkPipeline result = VK_NULL_HANDLE; + if (m_vkd->vkCreateGraphicsPipelines(m_vkd->device(), VK_NULL_HANDLE, 1, &info, nullptr, &result) != VK_SUCCESS) + throw DxvkError("DxvkMetaMipGenObjects: Failed to create graphics pipeline"); + return result; } - + } diff --git a/src/dxvk/dxvk_meta_resolve.h b/src/dxvk/dxvk_meta_resolve.h index fdd56750..05a7d9c0 100644 --- a/src/dxvk/dxvk_meta_resolve.h +++ b/src/dxvk/dxvk_meta_resolve.h @@ -1,50 +1,132 @@ #pragma once +#include #include +#include "../spirv/spirv_code_buffer.h" + #include "dxvk_barrier.h" #include "dxvk_cmdlist.h" #include "dxvk_resource.h" namespace dxvk { - + /** - * \brief Meta resolve framebuffer + * \brief Resolve pipeline + * + * Stores the objects for a single pipeline + * that is used for fragment shader resolve. + */ + struct DxvkMetaResolvePipeline { + VkRenderPass renderPass; + VkDescriptorSetLayout dsetLayout; + VkPipelineLayout pipeLayout; + VkPipeline pipeHandle; + }; + + /** + * \brief Meta resolve render pass * * Stores a framebuffer and image view objects * for a meta resolve operation. Can be tracked. */ - class DxvkMetaResolveFramebuffer : public DxvkResource { + class DxvkMetaResolveRenderPass : public DxvkResource { public: - DxvkMetaResolveFramebuffer( - const Rc& vkd, - const Rc& dstImage, - VkImageSubresourceLayers dstLayers, - const Rc& srcImage, - VkImageSubresourceLayers srcLayers, - VkFormat format); + DxvkMetaResolveRenderPass( + const Rc& vkd, + const Rc& dstImageView, + const Rc& srcImageView); - ~DxvkMetaResolveFramebuffer(); + ~DxvkMetaResolveRenderPass(); VkRenderPass renderPass() const { return m_renderPass; } - + VkFramebuffer framebuffer() const { return m_framebuffer; } - + private: - const Rc m_vkd; + const Rc m_vkd; + + const Rc m_dstImageView; + const Rc m_srcImageView; - VkRenderPass m_renderPass; - VkImageView m_dstImageView; - VkImageView m_srcImageView; - VkFramebuffer m_framebuffer; + VkRenderPass m_renderPass = VK_NULL_HANDLE; + VkFramebuffer m_framebuffer = VK_NULL_HANDLE; + + VkRenderPass createRenderPass() const; + + VkFramebuffer createFramebuffer() const; + + }; + + + /** + * \brief Meta resolve objects + * + * Stores render pass objects and pipelines used + * for shader-based resolve operations. Due to + * the Vulkan design, we have to create one render + * pass and pipeline object per image format used. + */ + class DxvkMetaResolveObjects : public RcObject { + + public: + + DxvkMetaResolveObjects(const Rc& vkd); + ~DxvkMetaResolveObjects(); + + /** + * \brief Creates a resolve pipeline + * + * \param [in] format Image view format + * \returns The pipeline handles to use + */ + DxvkMetaResolvePipeline getPipeline( + VkFormat format); + + private: + + Rc m_vkd; + + VkSampler m_sampler; + VkShaderModule m_shaderVert; + VkShaderModule m_shaderGeom; + VkShaderModule m_shaderFragF; + VkShaderModule m_shaderFragI; + VkShaderModule m_shaderFragU; + + std::mutex m_mutex; + + std::unordered_map m_pipelines; + + VkSampler createSampler() const; + + VkShaderModule createShaderModule( + const SpirvCodeBuffer& code) const; + + DxvkMetaResolvePipeline createPipeline( + VkFormat format); + + VkRenderPass createRenderPass( + VkFormat format) const; + + VkDescriptorSetLayout createDescriptorSetLayout() const; + + VkPipelineLayout createPipelineLayout( + VkDescriptorSetLayout descriptorSetLayout) const; + + VkPipeline createPipeline( + VkPipelineLayout pipelineLayout, + VkRenderPass renderPass, + VkFormat format) const; + }; -} +} \ No newline at end of file