Perform texel replacement on out-of-bounds OpImageFetch accesses
VK_EXT_image_robustness requires returning zero on out-of-bounds image
accesses. OpImageFetch was previously merely clamping the coordinates to
be in-bounds.
This change reuses some of the functionality for
VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER to perform texel replacement.
Bug: b/159329067
Tests: dEQP-VK.robustness.image_robustness.*
Change-Id: I8c00b8de2793b0b7028230cb180d308a4b9b60ec
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/47095
Presubmit-Ready: Nicolas Capens <nicolascapens@google.com>
Kokoro-Result: kokoro <noreply+kokoro@google.com>
Tested-by: Nicolas Capens <nicolascapens@google.com>
Reviewed-by: Alexis Hétu <sugoi@google.com>
diff --git a/src/Pipeline/SamplerCore.cpp b/src/Pipeline/SamplerCore.cpp
index ba17235..1a84042 100644
--- a/src/Pipeline/SamplerCore.cpp
+++ b/src/Pipeline/SamplerCore.cpp
@@ -1888,9 +1888,10 @@
{
// Valid texels have positive coordinates.
Int4 negative = Int4(0);
- if(state.addressingModeU == ADDRESSING_BORDER) negative |= uuuu;
- if(state.addressingModeV == ADDRESSING_BORDER) negative |= vvvv;
- if(state.addressingModeW == ADDRESSING_BORDER) negative |= wwww;
+ if(state.addressingModeU != ADDRESSING_UNUSED) negative |= uuuu;
+ if(state.addressingModeV != ADDRESSING_UNUSED) negative |= vvvv;
+ if(state.addressingModeW != ADDRESSING_UNUSED) negative |= wwww;
+ if(state.addressingModeY != ADDRESSING_UNUSED) negative |= cubeArrayId;
valid = CmpNLT(negative, Int4(0));
}
@@ -2123,7 +2124,7 @@
}
Vector4f out;
- out.x = As<Float4>((valid & As<Int4>(c.x)) | (~valid & borderRGB));
+ out.x = As<Float4>((valid & As<Int4>(c.x)) | (~valid & borderRGB)); // TODO: IfThenElse()
out.y = As<Float4>((valid & As<Int4>(c.y)) | (~valid & borderRGB));
out.z = As<Float4>((valid & As<Int4>(c.z)) | (~valid & borderRGB));
out.w = As<Float4>((valid & As<Int4>(c.w)) | (~valid & borderA));
@@ -2252,7 +2253,16 @@
if(function == Fetch)
{
- xyz0 = Min(Max(((function.offset != 0) && (addressingMode != ADDRESSING_LAYER)) ? As<Int4>(uvw) + As<Int4>(texOffset) : As<Int4>(uvw), Int4(0)), maxXYZ);
+ Int4 xyz = (function.offset && (addressingMode != ADDRESSING_LAYER)) ? As<Int4>(uvw) + As<Int4>(texOffset) : As<Int4>(uvw);
+ xyz0 = Min(Max(xyz, Int4(0)), maxXYZ);
+
+ // VK_EXT_image_robustness requires checking for out-of-bounds accesses.
+ // TODO(b/159329067): Claim VK_EXT_image_robustness
+ // TODO(b/162327166): Only perform bounds checks when VK_EXT_image_robustness is enabled.
+ // If the above clamping altered the result, the access is out-of-bounds.
+ // In that case set the coordinate to -1 to perform texel replacement later.
+ Int4 outOfBounds = CmpNEQ(xyz, xyz0);
+ xyz0 |= outOfBounds;
}
else if(addressingMode == ADDRESSING_LAYER) // Note: Offset does not apply to array layers
{
diff --git a/src/Pipeline/SpirvShaderSampling.cpp b/src/Pipeline/SpirvShaderSampling.cpp
index 1660da1..e9203ab 100644
--- a/src/Pipeline/SpirvShaderSampling.cpp
+++ b/src/Pipeline/SpirvShaderSampling.cpp
@@ -78,6 +78,14 @@
samplerState.minLod = sampler->minLod;
samplerState.maxLod = sampler->maxLod;
}
+ else
+ {
+ // OpImageFetch does not take a sampler descriptor, but for VK_EXT_image_robustness
+ // requires replacing invalid texels with zero.
+ // TODO(b/159329067): Claim VK_EXT_image_robustness
+ // TODO(b/162327166): Only perform bounds checks when VK_EXT_image_robustness is enabled.
+ samplerState.border = VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK;
+ }
return emitSamplerRoutine(instruction, samplerState);
};
@@ -349,14 +357,18 @@
if(!sampler)
{
- // OpImageFetch does not take a sampler descriptor, but still needs a valid,
- // arbitrary addressing mode that prevents out-of-bounds accesses:
+ // OpImageFetch does not take a sampler descriptor, but still needs a valid
+ // addressing mode that prevents out-of-bounds accesses:
// "The value returned by a read of an invalid texel is undefined, unless that
// read operation is from a buffer resource and the robustBufferAccess feature
// is enabled. In that case, an invalid texel is replaced as described by the
// robustBufferAccess feature." - Vulkan 1.1
- return ADDRESSING_WRAP;
+ // VK_EXT_image_robustness requires nullifying out-of-bounds accesses.
+ // ADDRESSING_BORDER causes texel replacement to be performed.
+ // TODO(b/159329067): Claim VK_EXT_image_robustness
+ // TODO(b/162327166): Only perform bounds checks when VK_EXT_image_robustness is enabled.
+ return ADDRESSING_BORDER;
}
VkSamplerAddressMode addressMode = VK_SAMPLER_ADDRESS_MODE_REPEAT;