Commit 7c84c9e5 by Nicolas Capens Committed by Nicolas Capens

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: 's avatarNicolas Capens <nicolascapens@google.com> Reviewed-by: 's avatarAlexis Hétu <sugoi@google.com>
parent 4e39779a
...@@ -1510,7 +1510,10 @@ OutOfBoundsBehavior SpirvShader::EmitState::getOutOfBoundsBehavior(spv::StorageC ...@@ -1510,7 +1510,10 @@ OutOfBoundsBehavior SpirvShader::EmitState::getOutOfBoundsBehavior(spv::StorageC
: OutOfBoundsBehavior::UndefinedBehavior; : OutOfBoundsBehavior::UndefinedBehavior;
case spv::StorageClassImage: 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: case spv::StorageClassInput:
if(executionModel == spv::ExecutionModelVertex) if(executionModel == spv::ExecutionModelVertex)
...@@ -2238,17 +2241,24 @@ SpirvShader::EmitResult SpirvShader::EmitAtomicOp(InsnIterator insn, EmitState * ...@@ -2238,17 +2241,24 @@ SpirvShader::EmitResult SpirvShader::EmitAtomicOp(InsnIterator insn, EmitState *
{ {
auto &resultType = getType(Type::ID(insn.word(1))); auto &resultType = getType(Type::ID(insn.word(1)));
Object::ID resultId = insn.word(2); Object::ID resultId = insn.word(2);
Object::ID pointerId = insn.word(3);
Object::ID semanticsId = insn.word(5); Object::ID semanticsId = insn.word(5);
auto memorySemantics = static_cast<spv::MemorySemanticsMask>(getObject(semanticsId).constantValue[0]); auto memorySemantics = static_cast<spv::MemorySemanticsMask>(getObject(semanticsId).constantValue[0]);
auto memoryOrder = MemoryOrder(memorySemantics); auto memoryOrder = MemoryOrder(memorySemantics);
// Where no value is provided (increment/decrement) use an implicit value of 1. // 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 value = (insn.wordCount() == 7) ? Operand(this, state, insn.word(6)).UInt(0) : RValue<SIMD::UInt>(1);
auto &dst = state->createIntermediate(resultId, resultType.componentCount); auto &dst = state->createIntermediate(resultId, resultType.componentCount);
auto ptr = state->getPointer(insn.word(3)); auto ptr = state->getPointer(pointerId);
auto ptrOffsets = ptr.offsets(); auto ptrOffsets = ptr.offsets();
SIMD::UInt x(0); SIMD::Int mask = state->activeLaneMask() & state->storesAndAtomicsMask();
auto 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++) for(int j = 0; j < SIMD::Width; j++)
{ {
If(Extract(mask, j) != 0) If(Extract(mask, j) != 0)
...@@ -2294,11 +2304,11 @@ SpirvShader::EmitResult SpirvShader::EmitAtomicOp(InsnIterator insn, EmitState * ...@@ -2294,11 +2304,11 @@ SpirvShader::EmitResult SpirvShader::EmitAtomicOp(InsnIterator insn, EmitState *
UNREACHABLE("%s", OpcodeName(insn.opcode()).c_str()); UNREACHABLE("%s", OpcodeName(insn.opcode()).c_str());
break; break;
} }
x = Insert(x, v, j); result = Insert(result, v, j);
} }
} }
dst.move(0, x); dst.move(0, result);
return EmitResult::Continue; return EmitResult::Continue;
} }
......
...@@ -656,6 +656,7 @@ SpirvShader::EmitResult SpirvShader::EmitImageRead(InsnIterator insn, EmitState ...@@ -656,6 +656,7 @@ SpirvShader::EmitResult SpirvShader::EmitImageRead(InsnIterator insn, EmitState
// emulating the glsl function loadImage() requires that this function returns 0 when used with out of bounds // 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. // coordinates, so we have to use OutOfBoundsBehavior::Nullify in that case.
// TODO(b/159329067): Claim VK_EXT_image_robustness // 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 robustness = OutOfBoundsBehavior::Nullify;
auto texelSize = vk::Format(vkFormat).bytes(); auto texelSize = vk::Format(vkFormat).bytes();
...@@ -1182,6 +1183,7 @@ SpirvShader::EmitResult SpirvShader::EmitImageWrite(InsnIterator insn, EmitState ...@@ -1182,6 +1183,7 @@ SpirvShader::EmitResult SpirvShader::EmitImageWrite(InsnIterator insn, EmitState
// Emulating the glsl function imageStore() requires that this function is noop when used with out of bounds // 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. // coordinates, so we have to use OutOfBoundsBehavior::Nullify in that case.
// TODO(b/159329067): Claim VK_EXT_image_robustness // 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 robustness = OutOfBoundsBehavior::Nullify;
auto texelPtr = GetTexelAddress(state, imageBase, imageSizeInBytes, coordinate, imageType, binding, texelSize, 0, false, robustness); auto texelPtr = GetTexelAddress(state, imageBase, imageSizeInBytes, coordinate, imageType, binding, texelSize, 0, false, robustness);
...@@ -1248,7 +1250,12 @@ SpirvShader::EmitResult SpirvShader::EmitImageTexelPointer(InsnIterator insn, Em ...@@ -1248,7 +1250,12 @@ SpirvShader::EmitResult SpirvShader::EmitImageTexelPointer(InsnIterator insn, Em
Pointer<Byte> imageBase = *Pointer<Pointer<Byte>>(binding + OFFSET(vk::StorageImageDescriptor, ptr)); Pointer<Byte> imageBase = *Pointer<Pointer<Byte>>(binding + OFFSET(vk::StorageImageDescriptor, ptr));
auto imageSizeInBytes = *Pointer<Int>(binding + OFFSET(vk::StorageImageDescriptor, sizeInBytes)); 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); state->createPointer(resultId, ptr);
......
...@@ -18,8 +18,8 @@ ...@@ -18,8 +18,8 @@
#include "Vulkan/VkImage.hpp" #include "Vulkan/VkImage.hpp"
#include <string.h> #include <string.h>
#include <unistd.h>
#include <sys/mman.h> #include <sys/mman.h>
#include <unistd.h>
namespace vk { namespace vk {
...@@ -28,7 +28,7 @@ static void wl_registry_handle_global(void *data, struct wl_registry *registry, ...@@ -28,7 +28,7 @@ static void wl_registry_handle_global(void *data, struct wl_registry *registry,
struct wl_shm **pshm = (struct wl_shm **)data; struct wl_shm **pshm = (struct wl_shm **)data;
if(!strcmp(interface, "wl_shm")) 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));
} }
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment