From 254676049ad9aba75d15621ddde8a6995ebbb154 Mon Sep 17 00:00:00 2001 From: Philip Rebohle Date: Thu, 24 May 2018 20:18:37 +0200 Subject: [PATCH 1/4] [dxvk] Added convenience equal checker for unordered maps --- src/dxvk/dxvk_hash.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/dxvk/dxvk_hash.h b/src/dxvk/dxvk_hash.h index 0ee55dcb7..a0fe561d7 100644 --- a/src/dxvk/dxvk_hash.h +++ b/src/dxvk/dxvk_hash.h @@ -4,6 +4,13 @@ namespace dxvk { + struct DxvkEq { + template + size_t operator () (const T& a, const T& b) const { + return a.eq(b); + } + }; + struct DxvkHash { template size_t operator () (const T& object) const { From 7ec93debf10cca759067a6a137f9730f0ca5adad Mon Sep 17 00:00:00 2001 From: Philip Rebohle Date: Fri, 25 May 2018 17:44:34 +0200 Subject: [PATCH 2/4] [dxvk] Add shaders for mip map generation --- src/dxvk/shaders/dxvk_mipgen_frag_1d.frag | 11 ++++++++++ src/dxvk/shaders/dxvk_mipgen_frag_2d.frag | 11 ++++++++++ src/dxvk/shaders/dxvk_mipgen_frag_3d.frag | 17 +++++++++++++++ src/dxvk/shaders/dxvk_mipgen_geom.geom | 25 +++++++++++++++++++++++ src/dxvk/shaders/dxvk_mipgen_vert.vert | 8 ++++++++ 5 files changed, 72 insertions(+) create mode 100644 src/dxvk/shaders/dxvk_mipgen_frag_1d.frag create mode 100644 src/dxvk/shaders/dxvk_mipgen_frag_2d.frag create mode 100644 src/dxvk/shaders/dxvk_mipgen_frag_3d.frag create mode 100644 src/dxvk/shaders/dxvk_mipgen_geom.geom create mode 100644 src/dxvk/shaders/dxvk_mipgen_vert.vert diff --git a/src/dxvk/shaders/dxvk_mipgen_frag_1d.frag b/src/dxvk/shaders/dxvk_mipgen_frag_1d.frag new file mode 100644 index 000000000..0e1819510 --- /dev/null +++ b/src/dxvk/shaders/dxvk_mipgen_frag_1d.frag @@ -0,0 +1,11 @@ +#version 450 + +layout(set = 0, binding = 0) +uniform sampler1DArray s_texture; + +layout(location = 0) in vec3 i_pos; +layout(location = 0) out vec4 o_color; + +void main() { + o_color = texture(s_texture, i_pos.xz); +} \ No newline at end of file diff --git a/src/dxvk/shaders/dxvk_mipgen_frag_2d.frag b/src/dxvk/shaders/dxvk_mipgen_frag_2d.frag new file mode 100644 index 000000000..e7a0b0820 --- /dev/null +++ b/src/dxvk/shaders/dxvk_mipgen_frag_2d.frag @@ -0,0 +1,11 @@ +#version 450 + +layout(set = 0, binding = 0) +uniform sampler2DArray s_texture; + +layout(location = 0) in vec3 i_pos; +layout(location = 0) out vec4 o_color; + +void main() { + o_color = texture(s_texture, i_pos); +} \ No newline at end of file diff --git a/src/dxvk/shaders/dxvk_mipgen_frag_3d.frag b/src/dxvk/shaders/dxvk_mipgen_frag_3d.frag new file mode 100644 index 000000000..42429cd91 --- /dev/null +++ b/src/dxvk/shaders/dxvk_mipgen_frag_3d.frag @@ -0,0 +1,17 @@ +#version 450 + +layout(set = 0, binding = 0) +uniform sampler3D s_texture; + +layout(location = 0) in vec3 i_pos; +layout(location = 0) out vec4 o_color; + +layout(push_constant) +uniform push_block { + uint p_layer_count; +}; + +void main() { + o_color = texture(s_texture, vec3(i_pos.xy, + (i_pos.z + 0.5f) / float(p_layer_count))); +} \ No newline at end of file diff --git a/src/dxvk/shaders/dxvk_mipgen_geom.geom b/src/dxvk/shaders/dxvk_mipgen_geom.geom new file mode 100644 index 000000000..c7413a434 --- /dev/null +++ b/src/dxvk/shaders/dxvk_mipgen_geom.geom @@ -0,0 +1,25 @@ +#version 450 + +layout(points) in; +layout(triangle_strip, max_vertices = 4) out; + +layout(location = 0) in int i_instance[1]; +layout(location = 0) out vec3 o_pos; + +const vec4 g_vpos[4] = { + vec4(-1.0f, -1.0f, 0.0f, 1.0f), + vec4(-1.0f, 1.0f, 0.0f, 1.0f), + vec4( 1.0f, -1.0f, 0.0f, 1.0f), + vec4( 1.0f, 1.0f, 0.0f, 1.0f), +}; + +void main() { + for (int i = 0; i < 4; i++) { + o_pos = vec3(0.5f + 0.5f * g_vpos[i].xy, float(i_instance[0])); + gl_Position = g_vpos[i]; + gl_Layer = i_instance[0]; + EmitVertex(); + } + + EndPrimitive(); +} \ No newline at end of file diff --git a/src/dxvk/shaders/dxvk_mipgen_vert.vert b/src/dxvk/shaders/dxvk_mipgen_vert.vert new file mode 100644 index 000000000..3009b809b --- /dev/null +++ b/src/dxvk/shaders/dxvk_mipgen_vert.vert @@ -0,0 +1,8 @@ +#version 450 + +layout(location = 0) out int o_instance; + +void main() { + o_instance = gl_InstanceIndex; + gl_Position = vec4(0.0f, 0.0f, 0.0f, 1.0f); +} \ No newline at end of file From 19b6a1617338ba094fa1461c32400b2a372520e4 Mon Sep 17 00:00:00 2001 From: Philip Rebohle Date: Fri, 25 May 2018 17:44:50 +0200 Subject: [PATCH 3/4] [dxvk] Add new mip map generator The current approach uses Vulkan blits, which does not work if the image view in question has a different format than the image itself. --- src/dxvk/dxvk_image.h | 12 +- src/dxvk/dxvk_meta_mipgen.cpp | 554 ++++++++++++++++++++++++++++++++++ src/dxvk/dxvk_meta_mipgen.h | 232 ++++++++++++++ src/dxvk/meson.build | 7 + 4 files changed, 803 insertions(+), 2 deletions(-) create mode 100644 src/dxvk/dxvk_meta_mipgen.cpp create mode 100644 src/dxvk/dxvk_meta_mipgen.h diff --git a/src/dxvk/dxvk_image.h b/src/dxvk/dxvk_image.h index 395213bcd..afbb574eb 100644 --- a/src/dxvk/dxvk_image.h +++ b/src/dxvk/dxvk_image.h @@ -285,6 +285,14 @@ namespace dxvk { return m_info; } + /** + * \brief Image handle + * \returns Image handle + */ + VkImage imageHandle() const { + return m_image->handle(); + } + /** * \brief Image properties * \returns Image properties @@ -302,8 +310,8 @@ namespace dxvk { } /** - * \brief Image - * \returns Image + * \brief Image object + * \returns Image object */ Rc image() const { return m_image; diff --git a/src/dxvk/dxvk_meta_mipgen.cpp b/src/dxvk/dxvk_meta_mipgen.cpp new file mode 100644 index 000000000..8d5d55ee7 --- /dev/null +++ b/src/dxvk/dxvk_meta_mipgen.cpp @@ -0,0 +1,554 @@ +#include "dxvk_meta_mipgen.h" + +#include +#include +#include +#include +#include + +namespace dxvk { + + DxvkMetaMipGenRenderPass::DxvkMetaMipGenRenderPass( + const Rc& vkd, + const Rc& view) + : m_vkd(vkd), m_view(view), m_renderPass(createRenderPass()) { + // Determine view type based on image type + const std::array, 3> viewTypes = {{ + { VK_IMAGE_VIEW_TYPE_1D_ARRAY, VK_IMAGE_VIEW_TYPE_1D_ARRAY }, + { VK_IMAGE_VIEW_TYPE_2D_ARRAY, VK_IMAGE_VIEW_TYPE_2D_ARRAY }, + { VK_IMAGE_VIEW_TYPE_3D, VK_IMAGE_VIEW_TYPE_2D_ARRAY }, + }}; + + m_srcViewType = viewTypes.at(uint32_t(view->imageInfo().type)).first; + m_dstViewType = viewTypes.at(uint32_t(view->imageInfo().type)).second; + + // Create image views and framebuffers + m_passes.resize(view->info().numLevels - 1); + + for (uint32_t i = 0; i < m_passes.size(); i++) + m_passes.at(i) = this->createFramebuffer(i); + } + + + DxvkMetaMipGenRenderPass::~DxvkMetaMipGenRenderPass() { + for (const auto& pass : m_passes) { + m_vkd->vkDestroyFramebuffer(m_vkd->device(), pass.framebuffer, nullptr); + m_vkd->vkDestroyImageView(m_vkd->device(), pass.dstView, nullptr); + m_vkd->vkDestroyImageView(m_vkd->device(), pass.srcView, nullptr); + } + + m_vkd->vkDestroyRenderPass(m_vkd->device(), m_renderPass, nullptr); + } + + + VkExtent3D DxvkMetaMipGenRenderPass::passExtent(uint32_t passId) const { + VkExtent3D extent = m_view->mipLevelExtent(passId + 1); + + if (m_view->imageInfo().type != VK_IMAGE_TYPE_3D) + extent.depth = m_view->info().numLayers; + + return extent; + } + + + VkRenderPass DxvkMetaMipGenRenderPass::createRenderPass() const { + std::array subpassDeps = {{ + { VK_SUBPASS_EXTERNAL, 0, + m_view->imageInfo().stages, + VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, + m_view->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, + m_view->imageInfo().stages, + VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | + VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, + m_view->imageInfo().access, 0 }, + }}; + + VkAttachmentDescription attachment; + attachment.flags = 0; + attachment.format = m_view->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_view->imageInfo().layout; + + 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("DxvkMetaMipGenRenderPass: Failed to create render pass"); + return result; + } + + + DxvkMetaMipGenPass DxvkMetaMipGenRenderPass::createFramebuffer(uint32_t pass) const { + DxvkMetaMipGenPass result; + result.srcView = VK_NULL_HANDLE; + result.dstView = VK_NULL_HANDLE; + result.framebuffer = VK_NULL_HANDLE; + + // Common image view info + VkImageViewCreateInfo viewInfo; + viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; + viewInfo.pNext = nullptr; + viewInfo.flags = 0; + viewInfo.image = m_view->imageHandle(); + viewInfo.format = m_view->info().format; + viewInfo.components = { + VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, + VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY }; + + // Create source image view, which points to + // the one mip level we're going to sample. + VkImageSubresourceRange srcSubresources; + srcSubresources.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + srcSubresources.baseMipLevel = m_view->info().minLevel + pass; + srcSubresources.levelCount = 1; + srcSubresources.baseArrayLayer = m_view->info().minLayer; + srcSubresources.layerCount = m_view->info().numLayers; + + viewInfo.viewType = m_srcViewType; + viewInfo.subresourceRange = srcSubresources; + + if (m_vkd->vkCreateImageView(m_vkd->device(), &viewInfo, nullptr, &result.srcView) != VK_SUCCESS) + throw DxvkError("DxvkMetaMipGenRenderPass: Failed to create source image view"); + + // Create destination image view, which points + // to the mip level we're going to render to. + VkExtent3D dstExtent = m_view->mipLevelExtent(pass + 1); + + VkImageSubresourceRange dstSubresources; + dstSubresources.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + dstSubresources.baseMipLevel = m_view->info().minLevel + pass + 1; + dstSubresources.levelCount = 1; + + if (m_view->imageInfo().type != VK_IMAGE_TYPE_3D) { + dstSubresources.baseArrayLayer = m_view->info().minLayer; + dstSubresources.layerCount = m_view->info().numLayers; + } else { + dstSubresources.baseArrayLayer = 0; + dstSubresources.layerCount = dstExtent.depth; + } + + viewInfo.viewType = m_dstViewType; + viewInfo.subresourceRange = dstSubresources; + + if (m_vkd->vkCreateImageView(m_vkd->device(), &viewInfo, nullptr, &result.dstView) != VK_SUCCESS) + throw DxvkError("DxvkMetaMipGenRenderPass: Failed to create target image view"); + + // Create framebuffer using the destination + // image view as its color attachment. + 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 = &result.dstView; + fboInfo.width = dstExtent.width; + fboInfo.height = dstExtent.height; + fboInfo.layers = dstSubresources.layerCount; + + if (m_vkd->vkCreateFramebuffer(m_vkd->device(), &fboInfo, nullptr, &result.framebuffer) != VK_SUCCESS) + throw DxvkError("DxvkMetaMipGenRenderPass: Failed to create target framebuffer"); + + return result; + } + + + DxvkMetaMipGenObjects::DxvkMetaMipGenObjects(const Rc& vkd) + : m_vkd (vkd), + m_sampler (createSampler()), + m_shaderVert (createShaderModule(dxvk_mipgen_vert)), + m_shaderGeom (createShaderModule(dxvk_mipgen_geom)), + m_shaderFrag1D(createShaderModule(dxvk_mipgen_frag_1d)), + m_shaderFrag2D(createShaderModule(dxvk_mipgen_frag_2d)), + m_shaderFrag3D(createShaderModule(dxvk_mipgen_frag_3d)) { + + } + + + DxvkMetaMipGenObjects::~DxvkMetaMipGenObjects() { + for (const auto& pair : m_renderPasses) + m_vkd->vkDestroyRenderPass(m_vkd->device(), pair.second, nullptr); + + 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->vkDestroyShaderModule(m_vkd->device(), m_shaderFrag3D, nullptr); + m_vkd->vkDestroyShaderModule(m_vkd->device(), m_shaderFrag2D, nullptr); + m_vkd->vkDestroyShaderModule(m_vkd->device(), m_shaderFrag1D, 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); + } + + + DxvkMetaMipGenPipeline DxvkMetaMipGenObjects::getPipeline( + VkImageViewType viewType, + VkFormat viewFormat) { + std::lock_guard lock(m_mutex); + + DxvkMetaMipGenPipelineKey key; + key.viewType = viewType; + key.viewFormat = viewFormat; + + auto entry = m_pipelines.find(key); + if (entry != m_pipelines.end()) + return entry->second; + + DxvkMetaMipGenPipeline pipeline = this->createPipeline(key); + m_pipelines.insert({ key, pipeline }); + return pipeline; + } + + + VkRenderPass DxvkMetaMipGenObjects::getRenderPass(VkFormat viewFormat) { + auto entry = m_renderPasses.find(viewFormat); + if (entry != m_renderPasses.end()) + return entry->second; + + VkRenderPass renderPass = this->createRenderPass(viewFormat); + m_renderPasses.insert({ viewFormat, renderPass }); + return renderPass; + } + + + VkSampler DxvkMetaMipGenObjects::createSampler() const { + VkSamplerCreateInfo info; + info.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; + info.pNext = nullptr; + info.flags = 0; + info.magFilter = VK_FILTER_LINEAR; + info.minFilter = VK_FILTER_LINEAR; + 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("DxvkMetaMipGenObjects: Failed to create sampler"); + return result; + } + + + VkShaderModule DxvkMetaMipGenObjects::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("DxvkMetaMipGenObjects: Failed to create shader module"); + return result; + } + + + DxvkMetaMipGenPipeline DxvkMetaMipGenObjects::createPipeline( + const DxvkMetaMipGenPipelineKey& key) { + DxvkMetaMipGenPipeline pipe; + pipe.dsetLayout = this->createDescriptorSetLayout(key.viewType); + pipe.pipeLayout = this->createPipelineLayout(pipe.dsetLayout); + pipe.pipeHandle = this->createPipeline(key.viewType, pipe.pipeLayout, + this->getRenderPass(key.viewFormat)); + return pipe; + } + + + VkRenderPass DxvkMetaMipGenObjects::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_SHADER_READ_ONLY_OPTIMAL; + + 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("DxvkMetaMipGenObjects: Failed to create render pass"); + return result; + } + + + VkDescriptorSetLayout DxvkMetaMipGenObjects::createDescriptorSetLayout( + VkImageViewType viewType) 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 DxvkMetaMipGenObjects::createPipelineLayout( + VkDescriptorSetLayout descriptorSetLayout) const { + VkPushConstantRange pushRange; + pushRange.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; + pushRange.offset = 0; + pushRange.size = sizeof(DxvkMetaMipGenPushConstants); + + 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 = 1; + info.pPushConstantRanges = &pushRange; + + 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; + } + + + VkPipeline DxvkMetaMipGenObjects::createPipeline( + VkImageViewType imageViewType, + VkPipelineLayout pipelineLayout, + VkRenderPass renderPass) 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 = VK_NULL_HANDLE; + psStage.pName = "main"; + psStage.pSpecializationInfo = nullptr; + + switch (imageViewType) { + case VK_IMAGE_VIEW_TYPE_1D_ARRAY: psStage.module = m_shaderFrag1D; break; + case VK_IMAGE_VIEW_TYPE_2D_ARRAY: psStage.module = m_shaderFrag2D; break; + case VK_IMAGE_VIEW_TYPE_3D: psStage.module = m_shaderFrag3D; break; + default: throw DxvkError("DxvkMetaMipGenObjects: Invalid view type"); + } + + 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_mipgen.h b/src/dxvk/dxvk_meta_mipgen.h new file mode 100644 index 000000000..9f6600ad3 --- /dev/null +++ b/src/dxvk/dxvk_meta_mipgen.h @@ -0,0 +1,232 @@ +#pragma once + +#include +#include + +#include "../spirv/spirv_code_buffer.h" + +#include "dxvk_hash.h" +#include "dxvk_image.h" + +namespace dxvk { + + /** + * \brief Push constant data + */ + struct DxvkMetaMipGenPushConstants { + uint32_t layerCount; + }; + + /** + * \brief Mip map generation pipeline key + * + * We have to create pipelines for each + * combination of source image view type + * and image format. + */ + struct DxvkMetaMipGenPipelineKey { + VkImageViewType viewType; + VkFormat viewFormat; + + bool eq(const DxvkMetaMipGenPipelineKey& other) const { + return this->viewType == other.viewType + && this->viewFormat == other.viewFormat; + } + + size_t hash() const { + DxvkHashState result; + result.add(uint32_t(this->viewType)); + result.add(uint32_t(this->viewFormat)); + return result; + } + }; + + + /** + * \brief Mip map generation pipeline + * + * Stores the objects for a single pipeline + * that is used for mipmap generation. + */ + struct DxvkMetaMipGenPipeline { + VkDescriptorSetLayout dsetLayout; + VkPipelineLayout pipeLayout; + VkPipeline pipeHandle; + }; + + + /** + * \brief Mip map generation framebuffer + * + * Stores the image views and framebuffer + * handle used to generate one mip level. + */ + struct DxvkMetaMipGenPass { + VkImageView srcView; + VkImageView dstView; + VkFramebuffer framebuffer; + }; + + + /** + * \brief Mip map generation render pass + * + * Stores image views, framebuffer objects and + * a render pass object for mip map generation. + * This must be created per image view. + */ + class DxvkMetaMipGenRenderPass : public DxvkResource { + + public: + + DxvkMetaMipGenRenderPass( + const Rc& vkd, + const Rc& view); + + ~DxvkMetaMipGenRenderPass(); + + /** + * \brief Render pass handle + * \returns Render pass handle + */ + VkRenderPass renderPass() const { + return m_renderPass; + } + + /** + * \brief Source image view type + * + * Use this to figure out which type the + * resource descriptor needs to have. + * \returns Source image view type + */ + VkImageViewType viewType() const { + return m_srcViewType; + } + + /** + * \brief Render pass count + * + * Number of mip levels to generate. + * \returns Render pass count + */ + uint32_t passCount() const { + return m_passes.size(); + } + + /** + * \brief Framebuffer handles + * + * Returns image view and framebuffer handles + * required to generate a single mip level. + * \param [in] pass Render pass index + * \returns Object handles for the given pass + */ + DxvkMetaMipGenPass pass(uint32_t passId) const { + return m_passes.at(passId); + } + + /** + * \brief Framebuffer size for a given pass + * + * Stores the width, height, and layer count + * of the framebuffer for the given pass ID. + */ + VkExtent3D passExtent(uint32_t passId) const; + + private: + + Rc m_vkd; + Rc m_view; + + VkRenderPass m_renderPass; + + VkImageViewType m_srcViewType; + VkImageViewType m_dstViewType; + + std::vector m_passes; + + VkRenderPass createRenderPass() const; + + DxvkMetaMipGenPass createFramebuffer(uint32_t pass) const; + + }; + + + /** + * \brief Mip map generation objects + * + * Stores render pass objects and pipelines used + * to generate mip maps. Due to Vulkan API design + * decisions, we have to create one render pass + * and pipeline object per image format used. + */ + class DxvkMetaMipGenObjects : public RcObject { + + public: + + DxvkMetaMipGenObjects(const Rc& vkd); + ~DxvkMetaMipGenObjects(); + + /** + * \brief Creates a mip map generation pipeline + * + * \param [in] viewType Source image view type + * \param [in] viewFormat Image view format + * \returns The mip map generation pipeline + */ + DxvkMetaMipGenPipeline getPipeline( + VkImageViewType viewType, + VkFormat viewFormat); + + private: + + Rc m_vkd; + + VkSampler m_sampler; + + VkShaderModule m_shaderVert; + VkShaderModule m_shaderGeom; + VkShaderModule m_shaderFrag1D; + VkShaderModule m_shaderFrag2D; + VkShaderModule m_shaderFrag3D; + + std::mutex m_mutex; + + std::unordered_map< + VkFormat, + VkRenderPass> m_renderPasses; + + std::unordered_map< + DxvkMetaMipGenPipelineKey, + DxvkMetaMipGenPipeline, + DxvkHash, DxvkEq> m_pipelines; + + VkRenderPass getRenderPass( + VkFormat viewFormat); + + VkSampler createSampler() const; + + VkShaderModule createShaderModule( + const SpirvCodeBuffer& code) const; + + DxvkMetaMipGenPipeline createPipeline( + const DxvkMetaMipGenPipelineKey& key); + + VkRenderPass createRenderPass( + VkFormat format) const; + + VkDescriptorSetLayout createDescriptorSetLayout( + VkImageViewType viewType) const; + + VkPipelineLayout createPipelineLayout( + VkDescriptorSetLayout descriptorSetLayout) const; + + VkPipeline createPipeline( + VkImageViewType imageViewType, + VkPipelineLayout pipelineLayout, + VkRenderPass renderPass) const; + + }; + +} diff --git a/src/dxvk/meson.build b/src/dxvk/meson.build index 1c563df91..e2a5fabfc 100644 --- a/src/dxvk/meson.build +++ b/src/dxvk/meson.build @@ -12,6 +12,12 @@ dxvk_shaders = files([ 'shaders/dxvk_clear_image3d_u.comp', 'shaders/dxvk_clear_image3d_f.comp', + 'shaders/dxvk_mipgen_vert.vert', + 'shaders/dxvk_mipgen_geom.geom', + 'shaders/dxvk_mipgen_frag_1d.frag', + 'shaders/dxvk_mipgen_frag_2d.frag', + 'shaders/dxvk_mipgen_frag_3d.frag', + 'hud/shaders/hud_line.frag', 'hud/shaders/hud_text.frag', 'hud/shaders/hud_vert.vert', @@ -41,6 +47,7 @@ dxvk_src = files([ 'dxvk_main.cpp', 'dxvk_memory.cpp', 'dxvk_meta_clear.cpp', + 'dxvk_meta_mipgen.cpp', 'dxvk_meta_resolve.cpp', 'dxvk_pipecache.cpp', 'dxvk_pipecompiler.cpp', From 4b37590e1419deb3e3ef242e5fbb8d3cfacb3b61 Mon Sep 17 00:00:00 2001 From: Philip Rebohle Date: Fri, 25 May 2018 17:45:41 +0200 Subject: [PATCH 4/4] [dxvk] Use new mip map generator --- src/d3d11/d3d11_context.cpp | 4 +- src/dxvk/dxvk_context.cpp | 209 +++++++++++++++++------------------- src/dxvk/dxvk_context.h | 17 +-- src/dxvk/dxvk_device.cpp | 26 ++--- src/dxvk/dxvk_device.h | 1 + 5 files changed, 126 insertions(+), 131 deletions(-) diff --git a/src/d3d11/d3d11_context.cpp b/src/d3d11/d3d11_context.cpp index 9e922901c..bf330af51 100644 --- a/src/d3d11/d3d11_context.cpp +++ b/src/d3d11/d3d11_context.cpp @@ -856,9 +856,7 @@ namespace dxvk { if (view->GetResourceType() != D3D11_RESOURCE_DIMENSION_BUFFER) { EmitCs([cDstImageView = view->GetImageView()] (DxvkContext* ctx) { - ctx->generateMipmaps( - cDstImageView->image(), - cDstImageView->subresources()); + ctx->generateMipmaps(cDstImageView); }); } else { Logger::err("D3D11: GenerateMips called on a buffer"); diff --git a/src/dxvk/dxvk_context.cpp b/src/dxvk/dxvk_context.cpp index afad97564..f440ef646 100644 --- a/src/dxvk/dxvk_context.cpp +++ b/src/dxvk/dxvk_context.cpp @@ -7,12 +7,14 @@ namespace dxvk { DxvkContext::DxvkContext( - const Rc& device, - const Rc& pipelineManager, - const Rc& metaClearObjects) + const Rc& device, + const Rc& pipelineManager, + const Rc& metaClearObjects, + const Rc& metaMipGenObjects) : m_device (device), m_pipeMgr (pipelineManager), - m_metaClear (metaClearObjects) { } + m_metaClear (metaClearObjects), + m_metaMipGen(metaMipGenObjects) { } DxvkContext::~DxvkContext() { @@ -976,123 +978,102 @@ namespace dxvk { void DxvkContext::generateMipmaps( - const Rc& image, - const VkImageSubresourceRange& subresources) { - if (subresources.levelCount <= 1) + const Rc& imageView) { + if (imageView->info().numLevels <= 1) return; this->spillRenderPass(); - - // The top-most level will only be read. We can - // discard the contents of all the lower levels - // since we're going to override them anyway. - m_barriers.accessImage(image, - VkImageSubresourceRange { - subresources.aspectMask, - subresources.baseMipLevel, 1, - subresources.baseArrayLayer, - subresources.layerCount }, - image->info().layout, - image->info().stages, - image->info().access, - image->pickLayout(VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL), - VK_PIPELINE_STAGE_TRANSFER_BIT, - VK_ACCESS_TRANSFER_READ_BIT); + this->unbindGraphicsPipeline(); - m_barriers.accessImage(image, - VkImageSubresourceRange { - subresources.aspectMask, - subresources.baseMipLevel + 1, - subresources.levelCount - 1, - subresources.baseArrayLayer, - subresources.layerCount }, - VK_IMAGE_LAYOUT_UNDEFINED, - image->info().stages, - image->info().access, - image->pickLayout(VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL), - VK_PIPELINE_STAGE_TRANSFER_BIT, - VK_ACCESS_TRANSFER_WRITE_BIT); + // Create the a set of framebuffers and image views + const Rc mipGenerator + = new DxvkMetaMipGenRenderPass(m_device->vkd(), imageView); - m_barriers.recordCommands(m_cmd); + // Common descriptor set properties that we use to + // bind the source image view to the fragment shader + VkDescriptorImageInfo descriptorImage; + descriptorImage.sampler = VK_NULL_HANDLE; + descriptorImage.imageView = VK_NULL_HANDLE; + descriptorImage.imageLayout = imageView->imageInfo().layout; - // Generate each individual mip level with a blit - for (uint32_t i = 1; i < subresources.levelCount; i++) { - const uint32_t mip = subresources.baseMipLevel + i; + VkWriteDescriptorSet descriptorWrite; + descriptorWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + descriptorWrite.pNext = nullptr; + descriptorWrite.dstSet = VK_NULL_HANDLE; + 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; + + // Common render pass info + VkRenderPassBeginInfo passInfo; + passInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; + passInfo.pNext = nullptr; + passInfo.renderPass = mipGenerator->renderPass(); + passInfo.framebuffer = VK_NULL_HANDLE; + passInfo.renderArea = VkRect2D { }; + passInfo.clearValueCount = 0; + passInfo.pClearValues = nullptr; + + // Retrieve a compatible pipeline to use for rendering + DxvkMetaMipGenPipeline pipeInfo = m_metaMipGen->getPipeline( + mipGenerator->viewType(), imageView->info().format); + + for (uint32_t i = 0; i < mipGenerator->passCount(); i++) { + DxvkMetaMipGenPass pass = mipGenerator->pass(i); - const VkExtent3D srcExtent = image->mipLevelExtent(mip - 1); - const VkExtent3D dstExtent = image->mipLevelExtent(mip); + // Width, height and layer count for the current pass + VkExtent3D passExtent = mipGenerator->passExtent(i); - VkImageBlit region; - region.srcSubresource = VkImageSubresourceLayers { - subresources.aspectMask, mip - 1, - subresources.baseArrayLayer, - subresources.layerCount }; - region.srcOffsets[0] = VkOffset3D { 0, 0, 0 }; - region.srcOffsets[1].x = srcExtent.width; - region.srcOffsets[1].y = srcExtent.height; - region.srcOffsets[1].z = srcExtent.depth; + // Create descriptor set with the current source view + descriptorImage.imageView = pass.srcView; + descriptorWrite.dstSet = m_cmd->allocateDescriptorSet(pipeInfo.dsetLayout); + m_cmd->updateDescriptorSets(1, &descriptorWrite); - region.dstSubresource = VkImageSubresourceLayers { - subresources.aspectMask, mip, - subresources.baseArrayLayer, - subresources.layerCount }; - region.dstOffsets[0] = VkOffset3D { 0, 0, 0 }; - region.dstOffsets[1].x = dstExtent.width; - region.dstOffsets[1].y = dstExtent.height; - region.dstOffsets[1].z = dstExtent.depth; + // Set up viewport and scissor rect + 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; - m_cmd->cmdBlitImage( - image->handle(), image->pickLayout(VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL), - image->handle(), image->pickLayout(VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL), - 1, ®ion, VK_FILTER_LINEAR); + VkRect2D scissor; + scissor.offset = { 0, 0 }; + scissor.extent = { passExtent.width, passExtent.height }; - if (i + 1 < subresources.levelCount) { - m_barriers.accessImage(image, - VkImageSubresourceRange { - subresources.aspectMask, mip, 1, - subresources.baseArrayLayer, - subresources.layerCount }, - image->pickLayout(VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL), - VK_PIPELINE_STAGE_TRANSFER_BIT, - VK_ACCESS_TRANSFER_WRITE_BIT, - image->pickLayout(VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL), - VK_PIPELINE_STAGE_TRANSFER_BIT, - VK_ACCESS_TRANSFER_READ_BIT); - m_barriers.recordCommands(m_cmd); - } + // Set up render pass info + passInfo.framebuffer = pass.framebuffer; + passInfo.renderArea = scissor; + + // Set up push constants + DxvkMetaMipGenPushConstants pushConstants; + pushConstants.layerCount = passExtent.depth; + + m_cmd->cmdBeginRenderPass(&passInfo, 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); + + m_cmd->cmdSetViewport(0, 1, &viewport); + m_cmd->cmdSetScissor (0, 1, &scissor); + + m_cmd->cmdPushConstants( + pipeInfo.pipeLayout, + VK_SHADER_STAGE_FRAGMENT_BIT, + 0, sizeof(pushConstants), + &pushConstants); + + m_cmd->cmdDraw(1, passExtent.depth, 0, 0); + m_cmd->cmdEndRenderPass(); } - // Transform mip levels back into their original layout. - // The last mip level is still in TRANSFER_DST_OPTIMAL. - m_barriers.accessImage(image, - VkImageSubresourceRange { - subresources.aspectMask, - subresources.baseMipLevel, - subresources.levelCount - 1, - subresources.baseArrayLayer, - subresources.layerCount }, - image->pickLayout(VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL), - VK_PIPELINE_STAGE_TRANSFER_BIT, - VK_ACCESS_TRANSFER_READ_BIT, - image->info().layout, - image->info().stages, - image->info().access); - - m_barriers.accessImage(image, - VkImageSubresourceRange { - subresources.aspectMask, - subresources.baseMipLevel - + subresources.levelCount - 1, 1, - subresources.baseArrayLayer, - subresources.layerCount }, - image->pickLayout(VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL), - VK_PIPELINE_STAGE_TRANSFER_BIT, - VK_ACCESS_TRANSFER_WRITE_BIT, - image->info().layout, - image->info().stages, - image->info().access); - - m_barriers.recordCommands(m_cmd); + m_cmd->trackResource(mipGenerator); + m_cmd->trackResource(imageView); } @@ -1680,6 +1661,18 @@ namespace dxvk { } + void DxvkContext::unbindGraphicsPipeline() { + m_flags.set( + DxvkContextFlag::GpDirtyPipeline, + DxvkContextFlag::GpDirtyPipelineState, + DxvkContextFlag::GpDirtyResources, + DxvkContextFlag::GpDirtyVertexBuffers, + DxvkContextFlag::GpDirtyIndexBuffer); + + m_gpActivePipeline = VK_NULL_HANDLE; + } + + void DxvkContext::updateGraphicsPipeline() { if (m_flags.test(DxvkContextFlag::GpDirtyPipeline)) { m_flags.clr(DxvkContextFlag::GpDirtyPipeline); diff --git a/src/dxvk/dxvk_context.h b/src/dxvk/dxvk_context.h index fc74bfe27..24f3ae818 100644 --- a/src/dxvk/dxvk_context.h +++ b/src/dxvk/dxvk_context.h @@ -7,6 +7,7 @@ #include "dxvk_data.h" #include "dxvk_event.h" #include "dxvk_meta_clear.h" +#include "dxvk_meta_mipgen.h" #include "dxvk_meta_resolve.h" #include "dxvk_pipecache.h" #include "dxvk_pipemanager.h" @@ -28,9 +29,10 @@ namespace dxvk { public: DxvkContext( - const Rc& device, - const Rc& pipelineManager, - const Rc& metaClearObjects); + const Rc& device, + const Rc& pipelineManager, + const Rc& metaClearObjects, + const Rc& metaMipGenObjects); ~DxvkContext(); /** @@ -403,12 +405,10 @@ namespace dxvk { * * Uses blitting to generate lower mip levels from * the top-most mip level passed to this method. - * \param [in] image The image to generate mips for - * \param [in] subresource The subresource range + * \param [in] imageView The image to generate mips for */ void generateMipmaps( - const Rc& image, - const VkImageSubresourceRange& subresources); + const Rc& imageView); /** * \brief Initializes or invalidates an image @@ -621,6 +621,7 @@ namespace dxvk { const Rc m_device; const Rc m_pipeMgr; const Rc m_metaClear; + const Rc m_metaMipGen; Rc m_cmd; DxvkContextFlags m_flags; @@ -654,10 +655,10 @@ namespace dxvk { DxvkRenderPassOps& renderPassOps); void unbindComputePipeline(); - void updateComputePipeline(); void updateComputePipelineState(); + void unbindGraphicsPipeline(); void updateGraphicsPipeline(); void updateGraphicsPipelineState(); diff --git a/src/dxvk/dxvk_device.cpp b/src/dxvk/dxvk_device.cpp index a38cb16b7..bbee94034 100644 --- a/src/dxvk/dxvk_device.cpp +++ b/src/dxvk/dxvk_device.cpp @@ -8,17 +8,18 @@ namespace dxvk { const Rc& vkd, const Rc& extensions, const VkPhysicalDeviceFeatures& features) - : m_adapter (adapter), - m_vkd (vkd), - 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_unboundResources(this), - m_submissionQueue (this) { + : m_adapter (adapter), + m_vkd (vkd), + 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_unboundResources (this), + m_submissionQueue (this) { m_graphicsQueue.queueFamily = m_adapter->graphicsQueueFamily(); m_presentQueue.queueFamily = m_adapter->presentQueueFamily(); @@ -106,7 +107,8 @@ namespace dxvk { Rc DxvkDevice::createContext() { return new DxvkContext(this, m_pipelineManager, - m_metaClearObjects); + m_metaClearObjects, + m_metaMipGenObjects); } diff --git a/src/dxvk/dxvk_device.h b/src/dxvk/dxvk_device.h index 9ce2f42fe..d7c606528 100644 --- a/src/dxvk/dxvk_device.h +++ b/src/dxvk/dxvk_device.h @@ -356,6 +356,7 @@ namespace dxvk { Rc m_renderPassPool; Rc m_pipelineManager; Rc m_metaClearObjects; + Rc m_metaMipGenObjects; DxvkUnboundResources m_unboundResources;