Optimize OpImageFetch for single-level mipmaps The initial implementation of single-level mipmap LOD optimization left out Fetch operations due to causing test failures. The root cause is that minLod == maxLod is being used to indicate during sampling routine generation that the image has only a single mipmap level, but this is also true when we have no sampler object, which leaves these fields both initialized at 0. This change changes their initial value to [-1000, 1000]. While any arbitrary non-equal values could be used, this is inspired by OpenGL's defaults for GL_TEXTURE_MIN_LOD and GL_TEXTURE_MAX_LOD. We then set them both to 0 for Fetch operations if the image view has a single level. Bug: b/151263485 Change-Id: I2ab565f5126cc8f8137f051704a6350853396e50 Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/56112 Tested-by: Nicolas Capens <nicolascapens@google.com> Kokoro-Result: kokoro <noreply+kokoro@google.com> Reviewed-by: Sean Risser <srisser@google.com>
diff --git a/src/Device/Sampler.hpp b/src/Device/Sampler.hpp index 712977d..e42fb30 100644 --- a/src/Device/Sampler.hpp +++ b/src/Device/Sampler.hpp
@@ -111,8 +111,8 @@ float mipLodBias = 0.0f; float maxAnisotropy = 0.0f; - float minLod = 0.0f; - float maxLod = 0.0f; + float minLod = -1000.0f; + float maxLod = 1000.0f; bool is1D() const {
diff --git a/src/Pipeline/SamplerCore.cpp b/src/Pipeline/SamplerCore.cpp index 2239ca9..655ec3f 100644 --- a/src/Pipeline/SamplerCore.cpp +++ b/src/Pipeline/SamplerCore.cpp
@@ -57,7 +57,7 @@ // Determine if we can skip the LOD computation. This is the case when the mipmap has only one level, except for LOD query, // where we have to return the computed value. Anisotropic filtering requires computing the anisotropy factor even for a single mipmap level. bool singleMipLevel = (state.minLod == state.maxLod); - bool requiresLodComputation = (function == Query) || (function == Fetch) || (state.textureFilter == FILTER_ANISOTROPIC); + bool requiresLodComputation = (function == Query) || (state.textureFilter == FILTER_ANISOTROPIC); bool skipLodComputation = singleMipLevel && !requiresLodComputation; if(skipLodComputation)
diff --git a/src/Pipeline/SpirvShaderSampling.cpp b/src/Pipeline/SpirvShaderSampling.cpp index beca443..fd6dc70 100644 --- a/src/Pipeline/SpirvShaderSampling.cpp +++ b/src/Pipeline/SpirvShaderSampling.cpp
@@ -93,12 +93,21 @@ samplerState.maxLod = 0.0f; } } - else + else // Fetch { + ASSERT(samplerMethod == Fetch); + // OpImageFetch does not take a sampler descriptor, but for VK_EXT_image_robustness // requires replacing invalid texels with zero. // TODO(b/162327166): Only perform bounds checks when VK_EXT_image_robustness is enabled. samplerState.border = VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK; + + // If there's a single mip level we can skip LOD computation. + if(imageViewState.singleMipLevel) + { + samplerState.minLod = 0.0f; + samplerState.maxLod = 0.0f; + } } return emitSamplerRoutine(instruction, samplerState);