From 464c6810b3ad07b2e96949a161fd446e8094a294 Mon Sep 17 00:00:00 2001 From: Philip Rebohle Date: Thu, 17 Feb 2022 15:17:58 +0100 Subject: [PATCH] [dxvk] Repurpose initImage method This is now supposed to clear images of any type, and only to be used for resource initialization after creation. --- src/dxvk/dxvk_context.cpp | 107 +++++++++++++++++++++++++++++++++----- src/dxvk/dxvk_context.h | 7 +-- src/dxvk/dxvk_unbound.cpp | 6 +-- 3 files changed, 102 insertions(+), 18 deletions(-) diff --git a/src/dxvk/dxvk_context.cpp b/src/dxvk/dxvk_context.cpp index 412eee1c8..cc2871063 100644 --- a/src/dxvk/dxvk_context.cpp +++ b/src/dxvk/dxvk_context.cpp @@ -1648,18 +1648,101 @@ namespace dxvk { void DxvkContext::initImage( - const Rc& image, - const VkImageSubresourceRange& subresources, - VkImageLayout initialLayout) { - m_execBarriers.accessImage(image, subresources, - initialLayout, 0, 0, - image->info().layout, - image->info().stages, - image->info().access); - - (initialLayout == VK_IMAGE_LAYOUT_PREINITIALIZED) - ? m_cmd->trackResource (image) - : m_cmd->trackResource(image); + const Rc& image, + const VkImageSubresourceRange& subresources, + VkImageLayout initialLayout) { + if (initialLayout == VK_IMAGE_LAYOUT_PREINITIALIZED) { + m_initBarriers.accessImage(image, subresources, + initialLayout, 0, 0, + image->info().layout, + image->info().stages, + image->info().access); + + m_cmd->trackResource(image); + } else { + VkImageLayout clearLayout = image->pickLayout(VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); + + m_execAcquires.accessImage(image, subresources, + initialLayout, 0, 0, clearLayout, + VK_PIPELINE_STAGE_TRANSFER_BIT, + VK_ACCESS_TRANSFER_WRITE_BIT); + m_execAcquires.recordCommands(m_cmd); + + auto formatInfo = image->formatInfo(); + + if (formatInfo->flags.any(DxvkFormatFlag::BlockCompressed, DxvkFormatFlag::MultiPlane)) { + for (auto aspects = formatInfo->aspectMask; aspects; ) { + auto aspect = vk::getNextAspect(aspects); + auto extent = image->mipLevelExtent(subresources.baseMipLevel); + auto elementSize = formatInfo->elementSize; + + if (formatInfo->flags.test(DxvkFormatFlag::MultiPlane)) { + auto plane = &formatInfo->planes[vk::getPlaneIndex(aspect)]; + extent.width /= plane->blockSize.width; + extent.height /= plane->blockSize.height; + elementSize = plane->elementSize; + } + + // Allocate enough staging buffer memory to fit one + // single subresource, then dispatch multiple copies + VkExtent3D blockCount = util::computeBlockCount(extent, formatInfo->blockSize); + VkDeviceSize dataSize = util::flattenImageExtent(blockCount) * elementSize; + + auto zeroBuffer = createZeroBuffer(dataSize); + auto zeroHandle = zeroBuffer->getSliceHandle(); + + for (uint32_t level = 0; level < subresources.levelCount; level++) { + VkOffset3D offset = VkOffset3D { 0, 0, 0 }; + VkExtent3D extent = image->mipLevelExtent(subresources.baseMipLevel + level); + + if (formatInfo->flags.test(DxvkFormatFlag::MultiPlane)) { + auto plane = &formatInfo->planes[vk::getPlaneIndex(aspect)]; + extent.width /= plane->blockSize.width; + extent.height /= plane->blockSize.height; + } + + for (uint32_t layer = 0; layer < subresources.layerCount; layer++) { + VkBufferImageCopy region; + region.bufferOffset = zeroHandle.offset; + region.bufferRowLength = 0; + region.bufferImageHeight = 0; + region.imageSubresource = vk::makeSubresourceLayers( + vk::pickSubresource(subresources, level, layer)); + region.imageSubresource.aspectMask = aspect; + region.imageOffset = offset; + region.imageExtent = extent; + + m_cmd->cmdCopyBufferToImage(DxvkCmdBuffer::ExecBuffer, + zeroHandle.handle, image->handle(), clearLayout, 1, ®ion); + } + } + + m_cmd->trackResource(zeroBuffer); + } + } else { + if (subresources.aspectMask & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) { + VkClearDepthStencilValue value = { }; + + m_cmd->cmdClearDepthStencilImage(image->handle(), + clearLayout, &value, 1, &subresources); + } else { + VkClearColorValue value = { }; + + m_cmd->cmdClearColorImage(image->handle(), + clearLayout, &value, 1, &subresources); + } + } + + m_execBarriers.accessImage(image, subresources, + clearLayout, + VK_PIPELINE_STAGE_TRANSFER_BIT, + VK_ACCESS_TRANSFER_WRITE_BIT, + image->info().layout, + image->info().stages, + image->info().access); + + m_cmd->trackResource(image); + } } diff --git a/src/dxvk/dxvk_context.h b/src/dxvk/dxvk_context.h index 9a4e74d97..6282750d4 100644 --- a/src/dxvk/dxvk_context.h +++ b/src/dxvk/dxvk_context.h @@ -674,10 +674,11 @@ namespace dxvk { VkFilter filter); /** - * \brief Initializes or invalidates an image + * \brief Initializes an image * - * Sets up the image layout for future operations - * while discarding any previous contents. + * Transitions the image into its default layout, and clears + * it to black unless the initial layout is preinitialized. + * Only safe to call if the image is not in use by the GPU. * \param [in] image The image to initialize * \param [in] subresources Image subresources * \param [in] initialLayout Initial image layout diff --git a/src/dxvk/dxvk_unbound.cpp b/src/dxvk/dxvk_unbound.cpp index 400ac2c19..eeb3f9b0b 100644 --- a/src/dxvk/dxvk_unbound.cpp +++ b/src/dxvk/dxvk_unbound.cpp @@ -186,12 +186,12 @@ namespace dxvk { void DxvkUnboundResources::clearImage( const Rc& ctx, const Rc& image) { - ctx->clearColorImage(image, - VkClearColorValue { }, + ctx->initImage(image, VkImageSubresourceRange { VK_IMAGE_ASPECT_COLOR_BIT, 0, image->info().mipLevels, - 0, image->info().numLayers }); + 0, image->info().numLayers }, + VK_IMAGE_LAYOUT_UNDEFINED); } } \ No newline at end of file