Perform out-of-bounds checks on texel pointers
VK_EXT_image_robustness requires loads and stores using a pointer
produced by OpImageTexelPointer to be bounds checked. Out-of-bounds
reads must result in [0,0,0,0] or [0,0,0,1] values. We always return
all-zero. Out-of-bounds writes must be ignored.
This also includes the read-modify-write operations performed by atomic
instructions.
Bug: b/159329067
Tests: dEQP-VK.robustness.image_robustness.*
Change-Id: I4f5c2e8ae0bc89e61207fd1f7f1c449a35ca621e
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/47069
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/SpirvShader.cpp b/src/Pipeline/SpirvShader.cpp
index 848eefe..afcdbac 100644
--- a/src/Pipeline/SpirvShader.cpp
+++ b/src/Pipeline/SpirvShader.cpp
@@ -1510,7 +1510,10 @@
: OutOfBoundsBehavior::UndefinedBehavior;
case spv::StorageClassImage:
- return OutOfBoundsBehavior::UndefinedValue; // "The value returned by a read of an invalid texel is undefined"
+ // VK_EXT_image_robustness requires nullifying 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.
+ return OutOfBoundsBehavior::Nullify;
case spv::StorageClassInput:
if(executionModel == spv::ExecutionModelVertex)
@@ -2238,17 +2241,24 @@
{
auto &resultType = getType(Type::ID(insn.word(1)));
Object::ID resultId = insn.word(2);
+ Object::ID pointerId = insn.word(3);
Object::ID semanticsId = insn.word(5);
auto memorySemantics = static_cast<spv::MemorySemanticsMask>(getObject(semanticsId).constantValue[0]);
auto memoryOrder = MemoryOrder(memorySemantics);
// Where no value is provided (increment/decrement) use an implicit value of 1.
auto value = (insn.wordCount() == 7) ? Operand(this, state, insn.word(6)).UInt(0) : RValue<SIMD::UInt>(1);
auto &dst = state->createIntermediate(resultId, resultType.componentCount);
- auto ptr = state->getPointer(insn.word(3));
+ auto ptr = state->getPointer(pointerId);
auto ptrOffsets = ptr.offsets();
- SIMD::UInt x(0);
- auto mask = state->activeLaneMask() & state->storesAndAtomicsMask();
+ SIMD::Int mask = state->activeLaneMask() & state->storesAndAtomicsMask();
+
+ if(getObject(pointerId).opcode() == spv::OpImageTexelPointer)
+ {
+ mask &= ptr.isInBounds(sizeof(int32_t), OutOfBoundsBehavior::Nullify);
+ }
+
+ SIMD::UInt result(0);
for(int j = 0; j < SIMD::Width; j++)
{
If(Extract(mask, j) != 0)
@@ -2294,11 +2304,11 @@
UNREACHABLE("%s", OpcodeName(insn.opcode()).c_str());
break;
}
- x = Insert(x, v, j);
+ result = Insert(result, v, j);
}
}
- dst.move(0, x);
+ dst.move(0, result);
return EmitResult::Continue;
}
diff --git a/src/Pipeline/SpirvShaderImage.cpp b/src/Pipeline/SpirvShaderImage.cpp
index daa2a4b..e291fe8 100644
--- a/src/Pipeline/SpirvShaderImage.cpp
+++ b/src/Pipeline/SpirvShaderImage.cpp
@@ -656,6 +656,7 @@
// emulating the glsl function loadImage() requires that this function returns 0 when used with out of bounds
// coordinates, so we have to use OutOfBoundsBehavior::Nullify in that case.
// TODO(b/159329067): Claim VK_EXT_image_robustness
+ // TODO(b/162327166): Only perform bounds checks when VK_EXT_image_robustness is enabled.
auto robustness = OutOfBoundsBehavior::Nullify;
auto texelSize = vk::Format(vkFormat).bytes();
@@ -1182,6 +1183,7 @@
// Emulating the glsl function imageStore() requires that this function is noop when used with out of bounds
// coordinates, so we have to use OutOfBoundsBehavior::Nullify in that case.
// TODO(b/159329067): Claim VK_EXT_image_robustness
+ // TODO(b/162327166): Only perform bounds checks when VK_EXT_image_robustness is enabled.
auto robustness = OutOfBoundsBehavior::Nullify;
auto texelPtr = GetTexelAddress(state, imageBase, imageSizeInBytes, coordinate, imageType, binding, texelSize, 0, false, robustness);
@@ -1248,7 +1250,12 @@
Pointer<Byte> imageBase = *Pointer<Pointer<Byte>>(binding + OFFSET(vk::StorageImageDescriptor, ptr));
auto imageSizeInBytes = *Pointer<Int>(binding + OFFSET(vk::StorageImageDescriptor, sizeInBytes));
- auto ptr = GetTexelAddress(state, imageBase, imageSizeInBytes, coordinate, imageType, binding, sizeof(uint32_t), 0, false, OutOfBoundsBehavior::UndefinedValue);
+ // 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.
+ auto robustness = OutOfBoundsBehavior::Nullify;
+
+ auto ptr = GetTexelAddress(state, imageBase, imageSizeInBytes, coordinate, imageType, binding, sizeof(uint32_t), 0, false, robustness);
state->createPointer(resultId, ptr);
diff --git a/src/WSI/WaylandSurfaceKHR.cpp b/src/WSI/WaylandSurfaceKHR.cpp
index 09589c9..2431673 100644
--- a/src/WSI/WaylandSurfaceKHR.cpp
+++ b/src/WSI/WaylandSurfaceKHR.cpp
@@ -18,8 +18,8 @@
#include "Vulkan/VkImage.hpp"
#include <string.h>
-#include <unistd.h>
#include <sys/mman.h>
+#include <unistd.h>
namespace vk {
@@ -28,7 +28,7 @@
struct wl_shm **pshm = (struct wl_shm **)data;
if(!strcmp(interface, "wl_shm"))
{
- *pshm = static_cast<struct wl_shm*>(wl_registry_bind(registry, name, &wl_shm_interface, 1));
+ *pshm = static_cast<struct wl_shm *>(wl_registry_bind(registry, name, &wl_shm_interface, 1));
}
}