Commit ae09e889 by Courtney Goeltzenleuchter Committed by Commit Bot

Fix mismatch issue with precision qualifiers.

GLSL allows varyings passed from one stage to another to not match in precision (e.g. float & half-float). Vulkan doesn't allow that so adjust those mismatches to use the higher precision. To fix we keep track of the precision of varyings and in the Vulkan backend if we see they are different patch up the SPIR-V to make them match. Bug: angleproject:3078 Change-Id: I385d31e082da46ccdd4817b6612f5f9d9cbce17c Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2337755 Commit-Queue: Courtney Goeltzenleuchter <courtneygo@google.com> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarTim Van Patten <timvp@google.com>
parent c5b5cf6c
...@@ -81,6 +81,13 @@ struct ShaderInterfaceVariableInfo ...@@ -81,6 +81,13 @@ struct ShaderInterfaceVariableInfo
uint32_t xfbBuffer = kInvalid; uint32_t xfbBuffer = kInvalid;
uint32_t xfbOffset = kInvalid; uint32_t xfbOffset = kInvalid;
uint32_t xfbStride = kInvalid; uint32_t xfbStride = kInvalid;
// Indicates that the precision needs to be modified in the generated SPIR-V
// to support only transferring medium precision data when there's a precision
// mismatch between the shaders. For example, either the VS casts highp->mediump
// or the FS casts mediump->highp.
bool useRelaxedPrecision = false;
// Indicate if varying is input or output
bool varyingIsOutput = false;
}; };
// TODO: http://anglebug.com/4524: Need a different hash key than a string, since // TODO: http://anglebug.com/4524: Need a different hash key than a string, since
......
...@@ -219,10 +219,12 @@ std::unique_ptr<rx::LinkEvent> ProgramExecutableVk::load(gl::BinaryInputStream * ...@@ -219,10 +219,12 @@ std::unique_ptr<rx::LinkEvent> ProgramExecutableVk::load(gl::BinaryInputStream *
info->location = stream->readInt<uint32_t>(); info->location = stream->readInt<uint32_t>();
info->component = stream->readInt<uint32_t>(); info->component = stream->readInt<uint32_t>();
// PackedEnumBitSet uses uint8_t // PackedEnumBitSet uses uint8_t
info->activeStages = gl::ShaderBitSet(stream->readInt<uint8_t>()); info->activeStages = gl::ShaderBitSet(stream->readInt<uint8_t>());
info->xfbBuffer = stream->readInt<uint32_t>(); info->xfbBuffer = stream->readInt<uint32_t>();
info->xfbOffset = stream->readInt<uint32_t>(); info->xfbOffset = stream->readInt<uint32_t>();
info->xfbStride = stream->readInt<uint32_t>(); info->xfbStride = stream->readInt<uint32_t>();
info->useRelaxedPrecision = stream->readBool();
info->varyingIsOutput = stream->readBool();
} }
} }
...@@ -246,6 +248,8 @@ void ProgramExecutableVk::save(gl::BinaryOutputStream *stream) ...@@ -246,6 +248,8 @@ void ProgramExecutableVk::save(gl::BinaryOutputStream *stream)
stream->writeInt<uint32_t>(it.second.xfbBuffer); stream->writeInt<uint32_t>(it.second.xfbBuffer);
stream->writeInt<uint32_t>(it.second.xfbOffset); stream->writeInt<uint32_t>(it.second.xfbOffset);
stream->writeInt<uint32_t>(it.second.xfbStride); stream->writeInt<uint32_t>(it.second.xfbStride);
stream->writeInt<uint8_t>(it.second.useRelaxedPrecision);
stream->writeInt<uint8_t>(it.second.varyingIsOutput);
} }
} }
} }
...@@ -866,6 +870,40 @@ angle::Result ProgramExecutableVk::createPipelineLayout(const gl::Context *glCon ...@@ -866,6 +870,40 @@ angle::Result ProgramExecutableVk::createPipelineLayout(const gl::Context *glCon
return angle::Result::Continue; return angle::Result::Continue;
} }
void ProgramExecutableVk::resolvePrecisionMismatch(const gl::ProgramMergedVaryings &mergedVaryings)
{
for (const gl::ProgramVaryingRef &mergedVarying : mergedVaryings)
{
if (mergedVarying.frontShader && mergedVarying.backShader)
{
GLenum frontPrecision = mergedVarying.frontShader->precision;
GLenum backPrecision = mergedVarying.backShader->precision;
if (frontPrecision != backPrecision)
{
ShaderInterfaceVariableInfo *info =
&mVariableInfoMap[mergedVarying.frontShaderStage]
[mergedVarying.frontShader->mappedName];
ASSERT(frontPrecision >= GL_LOW_FLOAT && frontPrecision <= GL_HIGH_INT);
ASSERT(backPrecision >= GL_LOW_FLOAT && backPrecision <= GL_HIGH_INT);
if (frontPrecision > backPrecision)
{
// The output is higher precision than the input
info->varyingIsOutput = true;
info->useRelaxedPrecision = true;
}
else if (backPrecision > frontPrecision)
{
// The output is lower precision than the input, adjust the input
info = &mVariableInfoMap[mergedVarying.backShaderStage]
[mergedVarying.backShader->mappedName];
info->varyingIsOutput = false;
info->useRelaxedPrecision = true;
}
}
}
}
}
void ProgramExecutableVk::updateDefaultUniformsDescriptorSet( void ProgramExecutableVk::updateDefaultUniformsDescriptorSet(
const gl::ShaderType shaderType, const gl::ShaderType shaderType,
const DefaultUniformBlock &defaultUniformBlock, const DefaultUniformBlock &defaultUniformBlock,
......
...@@ -197,6 +197,7 @@ class ProgramExecutableVk ...@@ -197,6 +197,7 @@ class ProgramExecutableVk
const gl::ActiveTextureArray<vk::TextureUnit> *activeTextures, const gl::ActiveTextureArray<vk::TextureUnit> *activeTextures,
vk::DescriptorSetLayoutDesc *descOut); vk::DescriptorSetLayoutDesc *descOut);
void resolvePrecisionMismatch(const gl::ProgramMergedVaryings &mergedVaryings);
void updateDefaultUniformsDescriptorSet(const gl::ShaderType shaderType, void updateDefaultUniformsDescriptorSet(const gl::ShaderType shaderType,
const DefaultUniformBlock &defaultUniformBlock, const DefaultUniformBlock &defaultUniformBlock,
vk::BufferHelper *defaultUniformBuffer, vk::BufferHelper *defaultUniformBuffer,
......
...@@ -53,7 +53,7 @@ void ProgramPipelineVk::fillProgramStateMap( ...@@ -53,7 +53,7 @@ void ProgramPipelineVk::fillProgramStateMap(
} }
angle::Result ProgramPipelineVk::link(const gl::Context *glContext, angle::Result ProgramPipelineVk::link(const gl::Context *glContext,
const gl::ProgramMergedVaryings & /*mergedVaryings*/) const gl::ProgramMergedVaryings &mergedVaryings)
{ {
ContextVk *contextVk = vk::GetImpl(glContext); ContextVk *contextVk = vk::GetImpl(glContext);
const gl::State &glState = glContext->getState(); const gl::State &glState = glContext->getState();
...@@ -87,6 +87,11 @@ angle::Result ProgramPipelineVk::link(const gl::Context *glContext, ...@@ -87,6 +87,11 @@ angle::Result ProgramPipelineVk::link(const gl::Context *glContext,
} }
} }
if (contextVk->getFeatures().enablePrecisionQualifiers.enabled)
{
mExecutable.resolvePrecisionMismatch(mergedVaryings);
}
return mExecutable.createPipelineLayout(glContext); return mExecutable.createPipelineLayout(glContext);
} }
......
...@@ -255,7 +255,7 @@ void ProgramVk::fillProgramStateMap(gl::ShaderMap<const gl::ProgramState *> *pro ...@@ -255,7 +255,7 @@ void ProgramVk::fillProgramStateMap(gl::ShaderMap<const gl::ProgramState *> *pro
std::unique_ptr<LinkEvent> ProgramVk::link(const gl::Context *context, std::unique_ptr<LinkEvent> ProgramVk::link(const gl::Context *context,
const gl::ProgramLinkedResources &resources, const gl::ProgramLinkedResources &resources,
gl::InfoLog &infoLog, gl::InfoLog &infoLog,
const gl::ProgramMergedVaryings & /*mergedVaryings*/) const gl::ProgramMergedVaryings &mergedVaryings)
{ {
ANGLE_TRACE_EVENT0("gpu.angle", "ProgramVk::link"); ANGLE_TRACE_EVENT0("gpu.angle", "ProgramVk::link");
...@@ -288,6 +288,11 @@ std::unique_ptr<LinkEvent> ProgramVk::link(const gl::Context *context, ...@@ -288,6 +288,11 @@ std::unique_ptr<LinkEvent> ProgramVk::link(const gl::Context *context,
return std::make_unique<LinkEventDone>(status); return std::make_unique<LinkEventDone>(status);
} }
if (contextVk->getFeatures().enablePrecisionQualifiers.enabled)
{
mExecutable.resolvePrecisionMismatch(mergedVaryings);
}
// TODO(jie.a.chen@intel.com): Parallelize linking. // TODO(jie.a.chen@intel.com): Parallelize linking.
// http://crbug.com/849576 // http://crbug.com/849576
status = mExecutable.createPipelineLayout(context); status = mExecutable.createPipelineLayout(context);
......
...@@ -5932,6 +5932,220 @@ void main() ...@@ -5932,6 +5932,220 @@ void main()
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green); EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
} }
// Test mismatched precision in varying is handled correctly.
TEST_P(GLSLTest_ES3, MismatchPrecisionFloat)
{
constexpr char kVS[] = R"(#version 300 es
in vec4 position;
uniform highp float inVal;
out highp float myVarying;
void main()
{
myVarying = inVal;
gl_Position = position;
})";
constexpr char kFS[] = R"(#version 300 es
precision highp float;
out vec4 my_FragColor;
in mediump float myVarying;
void main()
{
my_FragColor = vec4(1, 0, 0, 1);
if (myVarying > 1.0)
{
my_FragColor = vec4(0, 1, 0, 1);
}
})";
ANGLE_GL_PROGRAM(program, kVS, kFS);
glClearColor(1.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
glUseProgram(program.get());
GLint positionLocation = glGetAttribLocation(program.get(), "position");
std::array<Vector3, 6> quadVertices = GetQuadVertices();
for (Vector3 &vertex : quadVertices)
{
vertex.z() = 0.5f;
}
glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 0, quadVertices.data());
glEnableVertexAttribArray(positionLocation);
GLint inValLoc = glGetUniformLocation(program, "inVal");
ASSERT_NE(-1, inValLoc);
glUniform1f(inValLoc, static_cast<GLfloat>(1.003));
glDrawArrays(GL_TRIANGLES, 0, 6);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
}
// Test mismatched precision in varying is handled correctly.
TEST_P(GLSLTest_ES3, MismatchPrecisionlowpFloat)
{
// Note: SPIRV only has relaxed precision so both lowp and mediump turn into "relaxed
// precision", thus this is the same test as MismatchPrecisionFloat but including it for
// completeness in case something changes.
constexpr char kVS[] = R"(#version 300 es
in vec4 position;
uniform highp float inVal;
out highp float myVarying;
void main()
{
myVarying = inVal;
gl_Position = position;
})";
constexpr char kFS[] = R"(#version 300 es
precision highp float;
out vec4 my_FragColor;
in lowp float myVarying;
void main()
{
my_FragColor = vec4(1, 0, 0, 1);
if (myVarying > 1.0)
{
my_FragColor = vec4(0, 1, 0, 1);
}
})";
ANGLE_GL_PROGRAM(program, kVS, kFS);
glClearColor(1.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
glUseProgram(program.get());
GLint positionLocation = glGetAttribLocation(program.get(), "position");
std::array<Vector3, 6> quadVertices = GetQuadVertices();
for (Vector3 &vertex : quadVertices)
{
vertex.z() = 0.5f;
}
glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 0, quadVertices.data());
glEnableVertexAttribArray(positionLocation);
GLint inValLoc = glGetUniformLocation(program, "inVal");
ASSERT_NE(-1, inValLoc);
glUniform1f(inValLoc, static_cast<GLfloat>(1.003));
glDrawArrays(GL_TRIANGLES, 0, 6);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
}
// Test mismatched precision in varying is handled correctly.
TEST_P(GLSLTest_ES3, MismatchPrecisionVec2UnusedVarying)
{
constexpr char kVS[] = R"(#version 300 es
in vec2 position;
uniform highp float inVal;
out highp float myVarying;
out highp vec2 texCoord;
void main()
{
myVarying = inVal;
gl_Position = vec4(position, 0, 1);
texCoord = position * 0.5 + vec2(0.5);
})";
constexpr char kFS[] = R"(#version 300 es
precision highp float;
out vec4 my_FragColor;
in mediump float myVarying;
in mediump vec2 texCoord;
void main()
{
my_FragColor = vec4(1, 0, 0, 1);
if (myVarying > 1.0)
{
my_FragColor = vec4(0, 1, 0, 1);
}
})";
ANGLE_GL_PROGRAM(program, kVS, kFS);
glClearColor(1.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
glUseProgram(program.get());
GLint positionLocation = glGetAttribLocation(program.get(), "position");
std::array<Vector3, 6> quadVertices = GetQuadVertices();
for (Vector3 &vertex : quadVertices)
{
vertex.z() = 0.5f;
}
glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 0, quadVertices.data());
glEnableVertexAttribArray(positionLocation);
GLint inValLoc = glGetUniformLocation(program, "inVal");
ASSERT_NE(-1, inValLoc);
glUniform1f(inValLoc, static_cast<GLfloat>(1.003));
glDrawArrays(GL_TRIANGLES, 0, 6);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
}
// Test mismatched precision in varying is handled correctly.
TEST_P(GLSLTest_ES3, MismatchPrecisionMedToHigh)
{
constexpr char kVS[] = R"(#version 300 es
in vec2 position;
uniform highp float inVal;
out mediump float myVarying;
void main()
{
myVarying = inVal;
gl_Position = vec4(position, 0, 1);
})";
constexpr char kFS[] = R"(#version 300 es
precision highp float;
out vec4 my_FragColor;
in highp float myVarying;
void main()
{
my_FragColor = vec4(1, 0, 0, 1);
if (myVarying > 1.0)
{
my_FragColor = vec4(0, 1, 0, 1);
}
})";
ANGLE_GL_PROGRAM(program, kVS, kFS);
glClearColor(1.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
glUseProgram(program.get());
GLint positionLocation = glGetAttribLocation(program.get(), "position");
std::array<Vector3, 6> quadVertices = GetQuadVertices();
for (Vector3 &vertex : quadVertices)
{
vertex.z() = 0.5f;
}
glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 0, quadVertices.data());
glEnableVertexAttribArray(positionLocation);
GLint inValLoc = glGetUniformLocation(program, "inVal");
ASSERT_NE(-1, inValLoc);
glUniform1f(inValLoc, static_cast<GLfloat>(1.003));
glDrawArrays(GL_TRIANGLES, 0, 6);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
}
// Test vector/scalar arithmetic (in this case multiplication and addition). Meant to reproduce a // Test vector/scalar arithmetic (in this case multiplication and addition). Meant to reproduce a
// bug that appeared in NVIDIA OpenGL drivers and that is worked around by // bug that appeared in NVIDIA OpenGL drivers and that is worked around by
// VectorizeVectorScalarArithmetic AST transform. // VectorizeVectorScalarArithmetic AST transform.
......
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