Only perform LOD computation when it is necessary If an image has a single mip level, and filtering isn't LOD dependent, as is the case when using FILTER_MIN_POINT_MAG_LINEAR or FILTER_MIN_LINEAR_MAG_POINT, LOD computation is not necessary in order to perform image sampling and can be bypassed entirely. Bug: b/179889245 Change-Id: Ic69fe0c45211ccbb66c88c502c2dba1c50630aa7 Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/52688 Presubmit-Ready: Alexis Hétu <sugoi@google.com> Kokoro-Result: kokoro <noreply+kokoro@google.com> Tested-by: Alexis Hétu <sugoi@google.com> Reviewed-by: Nicolas Capens <nicolascapens@google.com> Commit-Queue: Alexis Hétu <sugoi@google.com>
diff --git a/src/Pipeline/SamplerCore.cpp b/src/Pipeline/SamplerCore.cpp index 646d875..3d5521d 100644 --- a/src/Pipeline/SamplerCore.cpp +++ b/src/Pipeline/SamplerCore.cpp
@@ -54,7 +54,15 @@ w = As<Float4>(face); } - if(function == Implicit || function == Bias || function == Grad || function == Query) + bool singleMipLevel = (state.minLod == state.maxLod) && (function != Query) && (function != Fetch); + + // We can't skip the LOD computation for LOD query, where we have to return the proper value + if(singleMipLevel) + { + // Skip costly LOD computation if there's only 1 possible outcome + lod = state.minLod; + } + else if(function == Implicit || function == Bias || function == Grad || function == Query) { if(state.is1D()) { @@ -108,8 +116,11 @@ c.y = Float4(lod); // Unclamped LOD. } - lod = Max(lod, state.minLod); - lod = Min(lod, state.maxLod); + if (!singleMipLevel) + { + lod = Max(lod, state.minLod); + lod = Min(lod, state.maxLod); + } if(function == Query) {
diff --git a/src/Pipeline/SpirvShaderSampling.cpp b/src/Pipeline/SpirvShaderSampling.cpp index 44740b8..6aedc33 100644 --- a/src/Pipeline/SpirvShaderSampling.cpp +++ b/src/Pipeline/SpirvShaderSampling.cpp
@@ -78,6 +78,20 @@ samplerState.maxAnisotropy = vkSamplerState->maxAnisotropy; samplerState.minLod = vkSamplerState->minLod; samplerState.maxLod = vkSamplerState->maxLod; + + // If there's a single mip level and filtering doesn't depend on the LOD level, + // the sampler will need to compute the LOD to produce the proper result. + // Otherwise, it can be ignored. + // We can skip the LOD computation for all modes, except LOD query, + // where we have to return the proper value even if nothing else requires it. + if(imageViewState.singleMipLevel && + (samplerState.textureFilter != FILTER_MIN_POINT_MAG_LINEAR) && + (samplerState.textureFilter != FILTER_MIN_LINEAR_MAG_POINT) && + (samplerMethod != Query)) + { + samplerState.minLod = 0.0f; + samplerState.maxLod = 0.0f; + } } else {
diff --git a/src/Vulkan/VkImageView.cpp b/src/Vulkan/VkImageView.cpp index 0aa34f6..7b962ab 100644 --- a/src/Vulkan/VkImageView.cpp +++ b/src/Vulkan/VkImageView.cpp
@@ -87,14 +87,14 @@ const Image *sampledImage = image->getSampledImage(viewFormat); vk::Format samplingFormat = (image == sampledImage) ? viewFormat : sampledImage->getFormat().getAspectFormat(subresource.aspectMask); - pack({ pCreateInfo->viewType, samplingFormat, ResolveComponentMapping(pCreateInfo->components, viewFormat) }); + pack({ pCreateInfo->viewType, samplingFormat, ResolveComponentMapping(pCreateInfo->components, viewFormat), subresource.levelCount <= 1u }); } Identifier::Identifier(VkFormat bufferFormat) { static_assert(vk::VK_IMAGE_VIEW_TYPE_END_RANGE == 6, "VkImageViewType does not allow using 7 to indicate buffer view"); constexpr VkComponentMapping identityMapping = { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A }; - pack({ VK_IMAGE_VIEW_TYPE_1D, bufferFormat, ResolveComponentMapping(identityMapping, bufferFormat) }); + pack({ VK_IMAGE_VIEW_TYPE_1D, bufferFormat, ResolveComponentMapping(identityMapping, bufferFormat), true }); } void Identifier::pack(const State &state) @@ -105,6 +105,7 @@ g = static_cast<uint32_t>(state.mapping.g); b = static_cast<uint32_t>(state.mapping.b); a = static_cast<uint32_t>(state.mapping.a); + singleMipLevel = state.singleMipLevel; } Identifier::State Identifier::getState() const @@ -114,7 +115,8 @@ { static_cast<VkComponentSwizzle>(r), static_cast<VkComponentSwizzle>(g), static_cast<VkComponentSwizzle>(b), - static_cast<VkComponentSwizzle>(a) } }; + static_cast<VkComponentSwizzle>(a) }, + static_cast<bool>(singleMipLevel) }; } ImageView::ImageView(const VkImageViewCreateInfo *pCreateInfo, void *mem, const vk::SamplerYcbcrConversion *ycbcrConversion)
diff --git a/src/Vulkan/VkImageView.hpp b/src/Vulkan/VkImageView.hpp index 7efab9c..86bfd38 100644 --- a/src/Vulkan/VkImageView.hpp +++ b/src/Vulkan/VkImageView.hpp
@@ -53,6 +53,7 @@ VkImageViewType imageViewType; VkFormat format; VkComponentMapping mapping; + bool singleMipLevel; }; State getState() const; @@ -68,6 +69,7 @@ uint32_t g : 3; uint32_t b : 3; uint32_t a : 3; + uint32_t singleMipLevel : 1; }; uint32_t id = 0;