From cc9c01b1d06f6de86ef90ba2cdf4325e0499fe0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sat, 4 Mar 2023 09:54:27 +0100 Subject: [PATCH] Vulkan texture uploads: Take optimalBufferCopyRowPitchAlignment into account Might marginally increase texture upload performance on some GPUs, but mainly just the right thing to do. For example, on Intel, this is 64. --- Common/GPU/Vulkan/VulkanContext.h | 3 ++- Common/Math/math_util.h | 4 ++++ GPU/Vulkan/TextureCacheVulkan.cpp | 20 +++++++++++--------- 3 files changed, 17 insertions(+), 10 deletions(-) diff --git a/Common/GPU/Vulkan/VulkanContext.h b/Common/GPU/Vulkan/VulkanContext.h index 4cc097b758..21dbaad08e 100644 --- a/Common/GPU/Vulkan/VulkanContext.h +++ b/Common/GPU/Vulkan/VulkanContext.h @@ -222,7 +222,8 @@ public: // Simple workaround for the casting warning. template void SetDebugName(T handle, VkObjectType type, const char *name) { - if (extensionsLookup_.EXT_debug_utils) { + if (extensionsLookup_.EXT_debug_utils && handle != VK_NULL_HANDLE) { + _dbg_assert_(handle != VK_NULL_HANDLE); SetDebugNameImpl((uint64_t)handle, type, name); } } diff --git a/Common/Math/math_util.h b/Common/Math/math_util.h index fd47662b54..b76e1f3937 100644 --- a/Common/Math/math_util.h +++ b/Common/Math/math_util.h @@ -40,6 +40,10 @@ inline uint32_t RoundUpToPowerOf2(uint32_t v) { return v; } +inline uint32_t RoundUpToPowerOf2(uint32_t v, uint32_t power) { + return (v + power - 1) & ~(power - 1); +} + inline uint32_t log2i(uint32_t val) { unsigned int ret = -1; while (val != 0) { diff --git a/GPU/Vulkan/TextureCacheVulkan.cpp b/GPU/Vulkan/TextureCacheVulkan.cpp index 1444c6abca..108356cadc 100644 --- a/GPU/Vulkan/TextureCacheVulkan.cpp +++ b/GPU/Vulkan/TextureCacheVulkan.cpp @@ -541,8 +541,10 @@ void TextureCacheVulkan::BuildTexture(TexCacheEntry *const entry) { plan.GetMipSize(i, &mipWidth, &mipHeight); int bpp = VkFormatBytesPerPixel(actualFmt); - int stride = (mipWidth * bpp + 15) & ~15; // output stride - int uploadSize = stride * mipHeight; + int optimalStrideAlignment = std::max(4, (int)vulkan->GetPhysicalDeviceProperties().properties.limits.optimalBufferCopyRowPitchAlignment); + int byteStride = RoundUpToPowerOf2(mipWidth * bpp, optimalStrideAlignment); // output stride + int pixelStride = byteStride / bpp; + int uploadSize = byteStride * mipHeight; uint32_t bufferOffset; VkBuffer texBuf; @@ -568,17 +570,17 @@ void TextureCacheVulkan::BuildTexture(TexCacheEntry *const entry) { // Directly load the replaced image. data = drawEngine_->GetPushBufferForTextureData()->PushAligned(uploadSize, &bufferOffset, &texBuf, pushAlignment); double replaceStart = time_now_d(); - plan.replaced->Load(plan.baseLevelSrc + i, data, stride); // if it fails, it'll just be garbage data... OK for now. + plan.replaced->Load(plan.baseLevelSrc + i, data, byteStride); // if it fails, it'll just be garbage data... OK for now. replacementTimeThisFrame_ += time_now_d() - replaceStart; VK_PROFILE_BEGIN(vulkan, cmdInit, VK_PIPELINE_STAGE_TRANSFER_BIT, "Copy Upload (replaced): %dx%d", mipWidth, mipHeight); - entry->vkTex->UploadMip(cmdInit, i, mipWidth, mipHeight, 0, texBuf, bufferOffset, stride / bpp); + entry->vkTex->UploadMip(cmdInit, i, mipWidth, mipHeight, 0, texBuf, bufferOffset, pixelStride); VK_PROFILE_END(vulkan, cmdInit, VK_PIPELINE_STAGE_TRANSFER_BIT); } else { if (plan.depth != 1) { // 3D texturing. - loadLevel(uploadSize, i, stride, plan.scaleFactor); - entry->vkTex->UploadMip(cmdInit, 0, mipWidth, mipHeight, i, texBuf, bufferOffset, stride / bpp); + loadLevel(uploadSize, i, byteStride, plan.scaleFactor); + entry->vkTex->UploadMip(cmdInit, 0, mipWidth, mipHeight, i, texBuf, bufferOffset, pixelStride); } else if (computeUpload) { int srcBpp = VkFormatBytesPerPixel(dstFmt); int srcStride = mipUnscaledWidth * srcBpp; @@ -599,10 +601,10 @@ void TextureCacheVulkan::BuildTexture(TexCacheEntry *const entry) { VK_PROFILE_END(vulkan, cmdInit, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT); vulkan->Delete().QueueDeleteImageView(view); } else { - loadLevel(uploadSize, i == 0 ? plan.baseLevelSrc : i, stride, plan.scaleFactor); + loadLevel(uploadSize, i == 0 ? plan.baseLevelSrc : i, byteStride, plan.scaleFactor); VK_PROFILE_BEGIN(vulkan, cmdInit, VK_PIPELINE_STAGE_TRANSFER_BIT, "Copy Upload: %dx%d", mipWidth, mipHeight); - entry->vkTex->UploadMip(cmdInit, i, mipWidth, mipHeight, 0, texBuf, bufferOffset, stride / bpp); + entry->vkTex->UploadMip(cmdInit, i, mipWidth, mipHeight, 0, texBuf, bufferOffset, pixelStride); VK_PROFILE_END(vulkan, cmdInit, VK_PIPELINE_STAGE_TRANSFER_BIT); } // Format might be wrong in lowMemoryMode_, so don't save. @@ -620,7 +622,7 @@ void TextureCacheVulkan::BuildTexture(TexCacheEntry *const entry) { replacedInfo.scaleFactor = plan.scaleFactor; replacedInfo.fmt = FromVulkanFormat(actualFmt); - replacer_.NotifyTextureDecoded(replacedInfo, data, stride, plan.baseLevelSrc + i, w, h); + replacer_.NotifyTextureDecoded(replacedInfo, data, byteStride, plan.baseLevelSrc + i, w, h); } } }