Implement GLSLstd450Interpolate* functions

This cl adds an implementation for: - GLSLstd450InterpolateAtCentroid - GLSLstd450InterpolateAtSample - GLSLstd450InterpolateAtOffset These functions essentially replicate the behavior of regular interpolants in the fragment shader processing. A specific extra difficulty encountered here is detecting which kind of pointer offset we are dealing with. Pointer offsets might be caused by [] operators being used on a vector or on an array (possibly an array of vectors). This distinction is important as it impacts what interpolant offsets point to. Note that there's missing coverage in dEQP-VK for interpolant arrays and this was caught with SwANGLE tests (a dEQP-VK issue will be logged shortly). Another issue was dealing with dynamic interpolant offsets, which was solved by looping over all of them and combining all plane equations into one before performing the interpolation. Bug: b/171415086 Change-Id: Id7c4c931918ba172d00da84655051445b110d3a9 Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/51737 Presubmit-Ready: Alexis Hétu <sugoi@google.com> Kokoro-Result: kokoro <noreply+kokoro@google.com> Tested-by: 's avatarAlexis Hétu <sugoi@google.com> Commit-Queue: Alexis Hétu <sugoi@google.com> Reviewed-by: 's avatarNicolas Capens <nicolascapens@google.com>
parent 673a7fe5
...@@ -192,7 +192,7 @@ void PixelProgram::applyShader(Int cMask[4], Int sMask[4], Int zMask[4], int sam ...@@ -192,7 +192,7 @@ void PixelProgram::applyShader(Int cMask[4], Int sMask[4], Int zMask[4], int sam
auto storesAndAtomicsMask = (sampleId >= 0) ? maskAny(cMask[sampleId], sMask[sampleId], zMask[sampleId]) : maskAny(cMask, sMask, zMask); auto storesAndAtomicsMask = (sampleId >= 0) ? maskAny(cMask[sampleId], sMask[sampleId], zMask[sampleId]) : maskAny(cMask, sMask, zMask);
routine.killMask = 0; routine.killMask = 0;
spirvShader->emit(&routine, activeLaneMask, storesAndAtomicsMask, descriptorSets); spirvShader->emit(&routine, activeLaneMask, storesAndAtomicsMask, descriptorSets, state.multiSampleCount);
spirvShader->emitEpilog(&routine); spirvShader->emitEpilog(&routine);
if((sampleId < 0) || (sampleId == static_cast<int>(state.multiSampleCount - 1))) if((sampleId < 0) || (sampleId == static_cast<int>(state.multiSampleCount - 1)))
{ {
......
...@@ -1629,9 +1629,9 @@ void SpirvShader::emitProlog(SpirvRoutine *routine) const ...@@ -1629,9 +1629,9 @@ void SpirvShader::emitProlog(SpirvRoutine *routine) const
} }
} }
void SpirvShader::emit(SpirvRoutine *routine, RValue<SIMD::Int> const &activeLaneMask, RValue<SIMD::Int> const &storesAndAtomicsMask, const vk::DescriptorSet::Bindings &descriptorSets) const void SpirvShader::emit(SpirvRoutine *routine, RValue<SIMD::Int> const &activeLaneMask, RValue<SIMD::Int> const &storesAndAtomicsMask, const vk::DescriptorSet::Bindings &descriptorSets, unsigned int multiSampleCount) const
{ {
EmitState state(routine, entryPoint, activeLaneMask, storesAndAtomicsMask, descriptorSets, robustBufferAccess, executionModel); EmitState state(routine, entryPoint, activeLaneMask, storesAndAtomicsMask, descriptorSets, robustBufferAccess, multiSampleCount, executionModel);
dbgBeginEmit(&state); dbgBeginEmit(&state);
defer(dbgEndEmit(&state)); defer(dbgEndEmit(&state));
......
...@@ -783,7 +783,7 @@ public: ...@@ -783,7 +783,7 @@ public:
std::vector<InterfaceComponent> outputs; std::vector<InterfaceComponent> outputs;
void emitProlog(SpirvRoutine *routine) const; void emitProlog(SpirvRoutine *routine) const;
void emit(SpirvRoutine *routine, RValue<SIMD::Int> const &activeLaneMask, RValue<SIMD::Int> const &storesAndAtomicsMask, const vk::DescriptorSet::Bindings &descriptorSets) const; void emit(SpirvRoutine *routine, RValue<SIMD::Int> const &activeLaneMask, RValue<SIMD::Int> const &storesAndAtomicsMask, const vk::DescriptorSet::Bindings &descriptorSets, unsigned int multiSampleCount = 0) const;
void emitEpilog(SpirvRoutine *routine) const; void emitEpilog(SpirvRoutine *routine) const;
void clearPhis(SpirvRoutine *routine) const; void clearPhis(SpirvRoutine *routine) const;
...@@ -917,6 +917,7 @@ private: ...@@ -917,6 +917,7 @@ private:
RValue<SIMD::Int> storesAndAtomicsMask, RValue<SIMD::Int> storesAndAtomicsMask,
const vk::DescriptorSet::Bindings &descriptorSets, const vk::DescriptorSet::Bindings &descriptorSets,
bool robustBufferAccess, bool robustBufferAccess,
unsigned int multiSampleCount,
spv::ExecutionModel executionModel) spv::ExecutionModel executionModel)
: routine(routine) : routine(routine)
, function(function) , function(function)
...@@ -924,6 +925,7 @@ private: ...@@ -924,6 +925,7 @@ private:
, storesAndAtomicsMaskValue(storesAndAtomicsMask.value()) , storesAndAtomicsMaskValue(storesAndAtomicsMask.value())
, descriptorSets(descriptorSets) , descriptorSets(descriptorSets)
, robustBufferAccess(robustBufferAccess) , robustBufferAccess(robustBufferAccess)
, multiSampleCount(multiSampleCount)
, executionModel(executionModel) , executionModel(executionModel)
{ {
ASSERT(executionModelToStage(executionModel) != VkShaderStageFlagBits(0)); // Must parse OpEntryPoint before emitting. ASSERT(executionModelToStage(executionModel) != VkShaderStageFlagBits(0)); // Must parse OpEntryPoint before emitting.
...@@ -985,6 +987,8 @@ private: ...@@ -985,6 +987,8 @@ private:
OutOfBoundsBehavior getOutOfBoundsBehavior(spv::StorageClass storageClass) const; OutOfBoundsBehavior getOutOfBoundsBehavior(spv::StorageClass storageClass) const;
unsigned int getMultiSampleCount() const { return multiSampleCount; }
Intermediate &createIntermediate(Object::ID id, uint32_t componentCount) Intermediate &createIntermediate(Object::ID id, uint32_t componentCount)
{ {
auto it = intermediates.emplace(std::piecewise_construct, auto it = intermediates.emplace(std::piecewise_construct,
...@@ -1019,6 +1023,7 @@ private: ...@@ -1019,6 +1023,7 @@ private:
std::unordered_map<Object::ID, SIMD::Pointer> pointers; std::unordered_map<Object::ID, SIMD::Pointer> pointers;
const bool robustBufferAccess = true; // Emit robustBufferAccess safe code. const bool robustBufferAccess = true; // Emit robustBufferAccess safe code.
const unsigned int multiSampleCount = 0;
const spv::ExecutionModel executionModel = spv::ExecutionModelMax; const spv::ExecutionModel executionModel = spv::ExecutionModelMax;
}; };
...@@ -1229,7 +1234,16 @@ private: ...@@ -1229,7 +1234,16 @@ private:
void EvalSpecConstantUnaryOp(InsnIterator insn); void EvalSpecConstantUnaryOp(InsnIterator insn);
void EvalSpecConstantBinaryOp(InsnIterator insn); void EvalSpecConstantBinaryOp(InsnIterator insn);
// Fragment input interpolation functions
uint32_t GetNumInputComponents(int32_t location) const; uint32_t GetNumInputComponents(int32_t location) const;
enum InterpolationType
{
Centroid,
AtSample,
AtOffset,
};
SIMD::Float Interpolate(SIMD::Pointer const &ptr, int32_t location, Object::ID paramId, uint32_t component,
uint32_t component_count, EmitState *state, InterpolationType type) const;
// Helper for implementing OpStore, which doesn't take an InsnIterator so it // Helper for implementing OpStore, which doesn't take an InsnIterator so it
// can also store independent operands. // can also store independent operands.
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include "ShaderCore.hpp" #include "ShaderCore.hpp"
#include "Device/Primitive.hpp" #include "Device/Primitive.hpp"
#include "Pipeline/Constants.hpp"
#include <spirv/unified1/GLSL.std.450.h> #include <spirv/unified1/GLSL.std.450.h>
#include <spirv/unified1/spirv.hpp> #include <spirv/unified1/spirv.hpp>
...@@ -42,6 +43,17 @@ sw::SIMD::Float Interpolate(const sw::SIMD::Float &x, const sw::SIMD::Float &y, ...@@ -42,6 +43,17 @@ sw::SIMD::Float Interpolate(const sw::SIMD::Float &x, const sw::SIMD::Float &y,
return interpolant; return interpolant;
} }
// TODO(b/179925303): Eliminate when interpolants are tightly packed.
uint32_t ComputeInterpolantOffset(uint32_t offset, uint32_t components_per_row, bool useArrayOffset)
{
if(useArrayOffset)
{
uint32_t interpolant_offset = offset / components_per_row;
offset = (interpolant_offset * 4) + (offset - interpolant_offset * components_per_row);
}
return offset;
}
} // namespace } // namespace
namespace sw { namespace sw {
...@@ -900,17 +912,35 @@ SpirvShader::EmitResult SpirvShader::EmitExtGLSLstd450(InsnIterator insn, EmitSt ...@@ -900,17 +912,35 @@ SpirvShader::EmitResult SpirvShader::EmitExtGLSLstd450(InsnIterator insn, EmitSt
} }
case GLSLstd450InterpolateAtCentroid: case GLSLstd450InterpolateAtCentroid:
{ {
UNSUPPORTED("SPIR-V SampleRateShading Capability (GLSLstd450InterpolateAtCentroid)"); Decorations d;
ApplyDecorationsForId(&d, insn.word(5));
auto ptr = state->getPointer(insn.word(5));
for(auto i = 0u; i < type.componentCount; i++)
{
dst.move(i, Interpolate(ptr, d.Location, 0, i, type.componentCount, state, SpirvShader::Centroid));
}
break; break;
} }
case GLSLstd450InterpolateAtSample: case GLSLstd450InterpolateAtSample:
{ {
UNSUPPORTED("SPIR-V SampleRateShading Capability (GLSLstd450InterpolateAtCentroid)"); Decorations d;
ApplyDecorationsForId(&d, insn.word(5));
auto ptr = state->getPointer(insn.word(5));
for(auto i = 0u; i < type.componentCount; i++)
{
dst.move(i, Interpolate(ptr, d.Location, insn.word(6), i, type.componentCount, state, SpirvShader::AtSample));
}
break; break;
} }
case GLSLstd450InterpolateAtOffset: case GLSLstd450InterpolateAtOffset:
{ {
UNSUPPORTED("SPIR-V SampleRateShading Capability (GLSLstd450InterpolateAtCentroid)"); Decorations d;
ApplyDecorationsForId(&d, insn.word(5));
auto ptr = state->getPointer(insn.word(5));
for(auto i = 0u; i < type.componentCount; i++)
{
dst.move(i, Interpolate(ptr, d.Location, insn.word(6), i, type.componentCount, state, SpirvShader::AtOffset));
}
break; break;
} }
case GLSLstd450NMin: case GLSLstd450NMin:
...@@ -953,6 +983,97 @@ SpirvShader::EmitResult SpirvShader::EmitExtGLSLstd450(InsnIterator insn, EmitSt ...@@ -953,6 +983,97 @@ SpirvShader::EmitResult SpirvShader::EmitExtGLSLstd450(InsnIterator insn, EmitSt
return EmitResult::Continue; return EmitResult::Continue;
} }
SIMD::Float SpirvShader::Interpolate(SIMD::Pointer const &ptr, int32_t location, Object::ID paramId, uint32_t component,
uint32_t component_count, EmitState *state, InterpolationType type) const
{
uint32_t interpolant = (location * 4);
uint32_t components_per_row = GetNumInputComponents(location);
if((location < 0) || (interpolant >= inputs.size()) || (components_per_row == 0))
{
return SIMD::Float(0.0f);
}
// Distinguish between the operator[] being used on a vector of on an array
// If the number of components of the interpolant is 1, then the operator[] automatically means this is an array.
// Otherwise, if the component_count is 1, than the operator[] can be the result of this operator being called
// from a vec2, vec3 or vec4, so a component_count greater than 1 means any offset is for an array
bool useArrayOffset = (components_per_row == 1) || (component_count > 1);
const auto &interpolationData = state->routine->interpolationData;
SIMD::Float x;
SIMD::Float y;
SIMD::Float rhw;
switch(type)
{
case Centroid:
x = interpolationData.xCentroid;
y = interpolationData.yCentroid;
rhw = interpolationData.rhwCentroid;
break;
case AtSample:
x = SIMD::Float(0.0f);
y = SIMD::Float(0.0f);
if(state->getMultiSampleCount() > 1)
{
static constexpr int NUM_SAMPLES = 4;
ASSERT(state->getMultiSampleCount() == NUM_SAMPLES);
Array<Float> sampleX(NUM_SAMPLES);
Array<Float> sampleY(NUM_SAMPLES);
for(int i = 0; i < NUM_SAMPLES; ++i)
{
sampleX[i] = Constants::SampleLocationsX[i];
sampleY[i] = Constants::SampleLocationsY[i];
}
auto sampleOperand = Operand(this, state, paramId);
ASSERT(sampleOperand.componentCount == 1);
// If sample does not exist, the position used to interpolate the
// input variable is undefined, so we just clamp to avoid OOB accesses.
SIMD::Int samples = sampleOperand.Int(0) & SIMD::Int(NUM_SAMPLES - 1);
for(int i = 0; i < SIMD::Width; ++i)
{
Int sample = Extract(samples, i);
x = Insert(x, sampleX[sample], i);
y = Insert(y, sampleY[sample], i);
}
}
x += interpolationData.x;
y += interpolationData.y;
rhw = interpolationData.rhw;
break;
case AtOffset:
{
// An offset of (0, 0) identifies the center of the pixel.
auto offset = Operand(this, state, paramId);
ASSERT(offset.componentCount == 2);
x = interpolationData.x + offset.Float(0);
y = interpolationData.y + offset.Float(1);
rhw = interpolationData.rhw;
}
break;
default:
UNREACHABLE("Unknown interpolation type: %d", (int)type);
return SIMD::Float(0.0f);
}
uint32_t offset = ComputeInterpolantOffset((ptr.staticOffsets[0] >> 2) + component, components_per_row, useArrayOffset);
if((interpolant + offset) >= inputs.size())
{
return SIMD::Float(0.0f);
}
Pointer<Byte> planeEquation = interpolationData.primitive + OFFSET(Primitive, V[interpolant]) + offset * sizeof(PlaneEquation);
return SpirvRoutine::interpolateAtXY(x, y, rhw, planeEquation, false, true);
}
SIMD::Float SpirvRoutine::interpolateAtXY(const SIMD::Float &x, const SIMD::Float &y, const SIMD::Float &rhw, Pointer<Byte> planeEquation, bool flat, bool perspective) SIMD::Float SpirvRoutine::interpolateAtXY(const SIMD::Float &x, const SIMD::Float &y, const SIMD::Float &rhw, Pointer<Byte> planeEquation, bool flat, bool perspective)
{ {
SIMD::Float A; SIMD::Float A;
......
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