зеркало из https://github.com/AvaloniaUI/angle.git
Vulkan: SPIR-V Gen: Handle scalar(const) produced by index clamp
Normally scalar(const) is folded into a constant. The index clamp transformation may produce such a code where the index looks dynamic at first (for example `false ? uniform_value : constant`), but becomes constant after folding. This change makes SPIR-V generation robust in that case. A potential future change could avoid the clamp entirely by making FoldExpressions adjust the op of the EOpIndexIndirect node whose index is being replaced with a constant with EOpIndexDirect (and apply the clamp on the argument). Bug: chromium:1260651 Change-Id: I552b7527d821d1cb52e0e53212cc481285674861 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/3226311 Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org> Reviewed-by: Tim Van Patten <timvp@google.com>
This commit is contained in:
Родитель
ca127443c8
Коммит
066fb91b41
|
@ -1280,6 +1280,8 @@ spirv::IdRef OutputSPIRVTraverser::createComplexConstant(const TType &type,
|
|||
spirv::IdRef typeId,
|
||||
const spirv::IdRefList ¶meters)
|
||||
{
|
||||
ASSERT(!type.isScalar());
|
||||
|
||||
if (type.isMatrix() && !type.isArray())
|
||||
{
|
||||
// Matrices are constructed from their columns.
|
||||
|
@ -1309,9 +1311,9 @@ spirv::IdRef OutputSPIRVTraverser::createConstructor(TIntermAggregate *node, spi
|
|||
const TIntermSequence &arguments = *node->getSequence();
|
||||
const TType &arg0Type = arguments[0]->getAsTyped()->getType();
|
||||
|
||||
// In some cases, constructors with constant value are not folded. If the constructor is a null
|
||||
// value, use OpConstantNull to avoid creating a bunch of instructions. Otherwise, the constant
|
||||
// is created below.
|
||||
// In some cases, constructors-with-constant values are not folded. If the constructor is a
|
||||
// null value, use OpConstantNull to avoid creating a bunch of instructions. Otherwise, the
|
||||
// constant is created below.
|
||||
if (node->isConstantNullValue())
|
||||
{
|
||||
return mBuilder.getNullConstant(typeId);
|
||||
|
@ -1353,10 +1355,22 @@ spirv::IdRef OutputSPIRVTraverser::createConstructor(TIntermAggregate *node, spi
|
|||
// Additionally, array and structs are constructed by OpCompositeConstruct followed by ids of
|
||||
// each parameter which must enumerate every individual element / field.
|
||||
|
||||
// In some cases, constructors with constant value are not folded. That is handled here.
|
||||
// In some cases, constructors-with-constant values are not folded such as for large constants.
|
||||
// Some transformations may also produce constructors-with-constants instead of constants even
|
||||
// for basic types. These are handled here.
|
||||
if (node->hasConstantValue())
|
||||
{
|
||||
return createComplexConstant(node->getType(), typeId, parameters);
|
||||
if (!type.isScalar())
|
||||
{
|
||||
return createComplexConstant(node->getType(), typeId, parameters);
|
||||
}
|
||||
|
||||
// If a transformation creates scalar(constant), return the constant as-is.
|
||||
// visitConstantUnion has already cast it to the right type.
|
||||
if (arguments[0]->getAsConstantUnion() != nullptr)
|
||||
{
|
||||
return parameters[0];
|
||||
}
|
||||
}
|
||||
|
||||
if (type.isArray() || type.getStruct() != nullptr)
|
||||
|
|
|
@ -14222,6 +14222,36 @@ void main() {
|
|||
EXPECT_NE(compileResult, 0);
|
||||
}
|
||||
|
||||
// Regression test for a bug in SPIR-V output where a transformation creates float(constant) without
|
||||
// folding it into a TIntermConstantUnion. This transformation is clamping non-constant indices in
|
||||
// WebGL. The |false ? i : 5| as index caused the transformation to consider this a non-constant
|
||||
// index.
|
||||
TEST_P(WebGL2GLSLTest, IndexClampConstantIndexBug)
|
||||
{
|
||||
constexpr char kFS[] = R"(#version 300 es
|
||||
precision highp float;
|
||||
|
||||
layout(location=0) out float f;
|
||||
|
||||
uniform int i;
|
||||
|
||||
void main()
|
||||
{
|
||||
float data[10];
|
||||
f = data[false ? i : 5];
|
||||
})";
|
||||
|
||||
GLuint shader = glCreateShader(GL_FRAGMENT_SHADER);
|
||||
|
||||
const char *sourceArray[1] = {kFS};
|
||||
GLint lengths[1] = {static_cast<GLint>(sizeof(kFS) - 1)};
|
||||
glShaderSource(shader, 1, sourceArray, lengths);
|
||||
glCompileShader(shader);
|
||||
|
||||
GLint compileResult;
|
||||
glGetShaderiv(shader, GL_COMPILE_STATUS, &compileResult);
|
||||
EXPECT_NE(compileResult, 0);
|
||||
}
|
||||
} // anonymous namespace
|
||||
|
||||
ANGLE_INSTANTIATE_TEST_ES2_AND_ES3_AND(GLSLTest, WithGlslang(ES2_VULKAN()));
|
||||
|
|
Загрузка…
Ссылка в новой задаче