Commit 9b83ddb1 by Nicolas Capens Committed by Nicolas Capens

Skip image sampling if no SIMD lanes are active

Currently all conditional branches in SPIR-V shaders are 'flattened', resulting in the execution of all instructions in both code paths, even in the case where none of the SIMD lanes are active. If a logically never taken code path contains an image sampling instruction which accesses a sampler or image array out of bounds, this could lead to reading invalid descriptor data, or a page fault. This is fixed by checking if any SIMD lanes are active, and if not, jumping over the actual sampling operations which access the descriptor data. Bug: b/153380916 Change-Id: I8e0cf7ef855e1250ce6dce9ebf7a47e29da7814d Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/43549Tested-by: 's avatarNicolas Capens <nicolascapens@google.com> Kokoro-Result: kokoro <noreply+kokoro@google.com> Reviewed-by: 's avatarBen Clayton <bclayton@google.com>
parent d0851364
......@@ -1208,6 +1208,9 @@ private:
EmitResult EmitGroupNonUniform(InsnIterator insn, EmitState *state) const;
EmitResult EmitArrayLength(InsnIterator insn, EmitState *state) const;
// Emits code to sample an image, regardless of whether any SIMD lanes are active.
void EmitImageSampleUnconditional(Array<SIMD::Float> &out, ImageInstruction instruction, InsnIterator insn, EmitState *state) const;
void GetImageDimensions(EmitState const *state, Type const &resultTy, Object::ID imageId, Object::ID lodId, Intermediate &dst) const;
SIMD::Pointer GetTexelAddress(EmitState const *state, SIMD::Pointer base, Operand const &coordinate, Type const &imageType, Pointer<Byte> descriptor, int texelSize, Object::ID sampleId, bool useStencilAspect) const;
uint32_t GetConstScalarInt(Object::ID id) const;
......
......@@ -107,11 +107,28 @@ SpirvShader::EmitResult SpirvShader::EmitImageFetch(InsnIterator insn, EmitState
SpirvShader::EmitResult SpirvShader::EmitImageSample(ImageInstruction instruction, InsnIterator insn, EmitState *state) const
{
auto &resultType = getType(insn.resultTypeId());
auto &result = state->createIntermediate(insn.resultId(), resultType.componentCount);
Array<SIMD::Float> out(4);
// TODO(b/153380916): When we're in a code path that is always executed,
// i.e. post-dominators of the entry block, we don't have to dynamically
// check whether any lanes are active, and can elide the jump.
If(AnyTrue(state->activeLaneMask()))
{
EmitImageSampleUnconditional(out, instruction, insn, state);
}
for(auto i = 0u; i < resultType.componentCount; i++) { result.move(i, out[i]); }
return EmitResult::Continue;
}
void SpirvShader::EmitImageSampleUnconditional(Array<SIMD::Float> &out, ImageInstruction instruction, InsnIterator insn, EmitState *state) const
{
Object::ID sampledImageId = insn.word(3); // For OpImageFetch this is just an Image, not a SampledImage.
Object::ID coordinateId = insn.word(4);
auto &resultType = getType(insn.resultTypeId());
auto &result = state->createIntermediate(insn.resultId(), resultType.componentCount);
auto imageDescriptor = state->getPointer(sampledImageId).base; // vk::SampledImageDescriptor*
// If using a separate sampler, look through the OpSampledImage instruction to find the sampler descriptor
......@@ -297,12 +314,7 @@ SpirvShader::EmitResult SpirvShader::EmitImageSample(ImageInstruction instructio
cache.sampler = sampler;
}
Array<SIMD::Float> out(4);
Call<ImageSampler>(cache.function, texture, &in[0], &out[0], state->routine->constants);
for(auto i = 0u; i < resultType.componentCount; i++) { result.move(i, out[i]); }
return EmitResult::Continue;
}
SpirvShader::EmitResult SpirvShader::EmitImageQuerySizeLod(InsnIterator insn, EmitState *state) const
......
......@@ -35,11 +35,10 @@ SpirvShader::ImageSampler *SpirvShader::getImageSampler(uint32_t inst, vk::Sampl
ImageInstruction instruction(inst);
const auto samplerId = sampler ? sampler->id : 0;
ASSERT(imageDescriptor->imageViewId != 0 && (samplerId != 0 || instruction.samplerMethod == Fetch));
ASSERT(imageDescriptor->device);
vk::Device::SamplingRoutineCache::Key key = { inst, imageDescriptor->imageViewId, samplerId };
ASSERT(imageDescriptor->device);
vk::Device::SamplingRoutineCache *cache = imageDescriptor->device->getSamplingRoutineCache();
auto createSamplingRoutine = [&](const vk::Device::SamplingRoutineCache::Key &key) {
......
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