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;