From f88adc4e82a3761601398d2933df2786798dd67e Mon Sep 17 00:00:00 2001 From: Philip Rebohle Date: Sat, 20 Jan 2018 09:46:54 +0100 Subject: [PATCH] [d3d11] Implemented mipmap generation --- src/d3d11/d3d11_context.cpp | 11 +++- src/dxvk/dxvk_cmdlist.h | 15 +++++ src/dxvk/dxvk_context.cpp | 119 ++++++++++++++++++++++++++++++++++++ src/dxvk/dxvk_context.h | 12 ++++ 4 files changed, 156 insertions(+), 1 deletion(-) diff --git a/src/d3d11/d3d11_context.cpp b/src/d3d11/d3d11_context.cpp index b7ba95df9..d43c696d5 100644 --- a/src/d3d11/d3d11_context.cpp +++ b/src/d3d11/d3d11_context.cpp @@ -651,7 +651,16 @@ namespace dxvk { void STDMETHODCALLTYPE D3D11DeviceContext::GenerateMips(ID3D11ShaderResourceView* pShaderResourceView) { - Logger::err("D3D11DeviceContext::GenerateMips: Not implemented"); + auto view = static_cast(pShaderResourceView); + + if (view->GetResourceType() != D3D11_RESOURCE_DIMENSION_BUFFER) { + m_context->generateMipmaps( + view->GetImageView()->image(), + view->GetImageView()->subresources()); + } else { + Logger::err("D3D11DeviceContext: GenerateMips called on a buffer"); + } + } diff --git a/src/dxvk/dxvk_cmdlist.h b/src/dxvk/dxvk_cmdlist.h index 69b3f622b..cd9dedb6f 100644 --- a/src/dxvk/dxvk_cmdlist.h +++ b/src/dxvk/dxvk_cmdlist.h @@ -141,6 +141,21 @@ namespace dxvk { } + void cmdBlitImage( + VkImage srcImage, + VkImageLayout srcImageLayout, + VkImage dstImage, + VkImageLayout dstImageLayout, + uint32_t regionCount, + const VkImageBlit* pRegions, + VkFilter filter) { + m_vkd->vkCmdBlitImage(m_buffer, + srcImage, srcImageLayout, + dstImage, dstImageLayout, + regionCount, pRegions, filter); + } + + void cmdClearAttachments( uint32_t attachmentCount, const VkClearAttachment* pAttachments, diff --git a/src/dxvk/dxvk_context.cpp b/src/dxvk/dxvk_context.cpp index 141ba11d5..91e9d98d2 100644 --- a/src/dxvk/dxvk_context.cpp +++ b/src/dxvk/dxvk_context.cpp @@ -610,6 +610,125 @@ namespace dxvk { } + void DxvkContext::generateMipmaps( + const Rc& image, + const VkImageSubresourceRange& subresources) { + if (subresources.levelCount <= 1) + return; + + // 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, + VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + VK_PIPELINE_STAGE_TRANSFER_BIT, + VK_ACCESS_TRANSFER_READ_BIT); + + 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, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + VK_PIPELINE_STAGE_TRANSFER_BIT, + VK_ACCESS_TRANSFER_WRITE_BIT); + + m_barriers.recordCommands(m_cmd); + + // Generate each individual mip level with a blit + for (uint32_t i = 1; i < subresources.levelCount; i++) { + const uint32_t mip = subresources.baseMipLevel + i; + + const VkExtent3D srcExtent = image->mipLevelExtent(mip - 1); + const VkExtent3D dstExtent = image->mipLevelExtent(mip); + + 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; + + 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; + + m_cmd->cmdBlitImage( + image->handle(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + image->handle(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + 1, ®ion, VK_FILTER_LINEAR); + + if (i + 1 < subresources.levelCount) { + m_barriers.accessImage(image, + VkImageSubresourceRange { + subresources.aspectMask, mip, 1, + subresources.baseArrayLayer, + subresources.layerCount }, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + VK_PIPELINE_STAGE_TRANSFER_BIT, + VK_ACCESS_TRANSFER_WRITE_BIT, + VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + VK_PIPELINE_STAGE_TRANSFER_BIT, + VK_ACCESS_TRANSFER_READ_BIT); + m_barriers.recordCommands(m_cmd); + } + } + + // 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 }, + 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 }, + 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); + } + + void DxvkContext::invalidateBuffer(const Rc& buffer) { // Allocate new backing resource buffer->rename(buffer->allocPhysicalSlice()); diff --git a/src/dxvk/dxvk_context.h b/src/dxvk/dxvk_context.h index bfcba61b6..008b40b9c 100644 --- a/src/dxvk/dxvk_context.h +++ b/src/dxvk/dxvk_context.h @@ -325,6 +325,18 @@ namespace dxvk { uint32_t count, uint32_t stride); + /** + * \brief Generates mip maps + * + * 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 + */ + void generateMipmaps( + const Rc& image, + const VkImageSubresourceRange& subresources); + /** * \brief Initializes or invalidates an image *