Commit 0261b1d3 by Tim Van Patten Committed by Commit Bot

PPO: Fix updating sampler uniforms between draws

Updating sampler uniforms when using PPOs is currently broken, since the Context/State use the currently bound ProgramExecutable which belongs to the PPO, but the updates only happen to the Program's executable that the uniform belongs to. This change updates Program::updateSamplerUniform() to update any PPO ProgramExecutables with the updated texture information when a Program's sampler uniforms are updated, so the Context/State use the correct data. Bug: b/182409935 Test: ProgramPipelineTest31.SampleTextureAThenTextureB Test: SamplersTest31.SampleTextureAThenTextureB Change-Id: I3c4e156c6e0c781e706f321f0bd12baf484ff42a Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2797951 Commit-Queue: Tim Van Patten <timvp@google.com> Reviewed-by: 's avatarCody Northrop <cnorthrop@google.com> Reviewed-by: 's avatarShahbaz Youssefi <syoussefi@chromium.org>
parent 408c1512
......@@ -55,6 +55,8 @@ enum class SubjectMessage
// Indicates an external change to the default framebuffer.
SurfaceChanged,
// Indicates a separable program's textures or images changed in the ProgramExecutable.
ProgramTextureOrImageBindingChanged,
// Indicates a separable program was successfully re-linked.
ProgramRelinked,
// Indicates a separable program's sampler uniforms were updated.
......
......@@ -4445,6 +4445,14 @@ void Program::updateSamplerUniform(Context *context,
}
}
// Update the observing PPO's executable, if any.
// Do this before any of the Context work, since that uses the current ProgramExecutable,
// which will be the PPO's if this Program is bound to it, rather than this Program's.
if (isSeparable())
{
onStateChange(angle::SubjectMessage::ProgramTextureOrImageBindingChanged);
}
// Notify context.
if (context)
{
......
......@@ -660,8 +660,9 @@ void ProgramPipeline::onSubjectStateChange(angle::SubjectIndex index, angle::Sub
{
switch (message)
{
case angle::SubjectMessage::SubjectChanged:
case angle::SubjectMessage::ProgramTextureOrImageBindingChanged:
mState.mIsLinked = false;
mState.mExecutable->mActiveSamplerRefCounts.fill(0);
mState.updateExecutableTextures();
break;
case angle::SubjectMessage::ProgramRelinked:
......
......@@ -3581,7 +3581,7 @@ void State::onActiveTextureChange(const Context *context, size_t textureUnit)
: nullptr;
updateTextureBinding(context, textureUnit, activeTexture);
mExecutable->onStateChange(angle::SubjectMessage::SubjectChanged);
mExecutable->onStateChange(angle::SubjectMessage::ProgramTextureOrImageBindingChanged);
}
}
......@@ -3618,7 +3618,7 @@ void State::onImageStateChange(const Context *context, size_t unit)
mDirtyObjects.set(DIRTY_OBJECT_IMAGES_INIT);
}
mExecutable->onStateChange(angle::SubjectMessage::SubjectChanged);
mExecutable->onStateChange(angle::SubjectMessage::ProgramTextureOrImageBindingChanged);
}
}
......
......@@ -835,6 +835,85 @@ void main()
EXPECT_PIXEL_COLOR_EQ(w, h, GLColor::yellow);
}
// Test that updating a sampler uniform in a separable program behaves correctly with PPOs.
TEST_P(ProgramPipelineTest31, SampleTextureAThenTextureB)
{
ANGLE_SKIP_TEST_IF(!IsVulkan());
constexpr int kWidth = 2;
constexpr int kHeight = 2;
const GLchar *vertString = R"(#version 310 es
precision highp float;
in vec2 a_position;
out vec2 texCoord;
void main()
{
gl_Position = vec4(a_position, 0, 1);
texCoord = a_position * 0.5 + vec2(0.5);
})";
const GLchar *fragString = R"(#version 310 es
precision highp float;
in vec2 texCoord;
uniform sampler2D tex;
out vec4 my_FragColor;
void main()
{
my_FragColor = texture(tex, texCoord);
})";
std::array<GLColor, kWidth *kHeight> redColor = {
{GLColor::red, GLColor::red, GLColor::red, GLColor::red}};
std::array<GLColor, kWidth *kHeight> greenColor = {
{GLColor::green, GLColor::green, GLColor::green, GLColor::green}};
// Create a red texture and bind to texture unit 0
GLTexture redTex;
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, redTex);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kWidth, kHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE,
redColor.data());
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
ASSERT_GL_NO_ERROR();
// Create a green texture and bind to texture unit 1
GLTexture greenTex;
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, greenTex);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kWidth, kHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE,
greenColor.data());
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glActiveTexture(GL_TEXTURE0);
ASSERT_GL_NO_ERROR();
bindProgramPipeline(vertString, fragString);
GLint location1 = glGetUniformLocation(mFragProg, "tex");
ASSERT_NE(location1, -1);
glActiveShaderProgram(mPipeline, mFragProg);
ASSERT_GL_NO_ERROR();
glEnable(GL_BLEND);
glBlendEquation(GL_FUNC_ADD);
glBlendFunc(GL_ONE, GL_ONE);
// Draw red
glUniform1i(location1, 0);
ASSERT_GL_NO_ERROR();
drawQuadWithPPO("a_position", 0.5f, 1.0f);
ASSERT_GL_NO_ERROR();
// Draw green
glUniform1i(location1, 1);
ASSERT_GL_NO_ERROR();
drawQuadWithPPO("a_position", 0.5f, 1.0f);
ASSERT_GL_NO_ERROR();
EXPECT_PIXEL_RECT_EQ(0, 0, kWidth, kHeight, GLColor::yellow);
}
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(ProgramPipelineTest);
ANGLE_INSTANTIATE_TEST_ES3_AND_ES31(ProgramPipelineTest);
......
......@@ -37,6 +37,9 @@ class SamplersTest : public ANGLETest
}
};
class SamplersTest31 : public SamplersTest
{};
// Verify that samplerParameterf supports TEXTURE_MAX_ANISOTROPY_EXT valid values.
TEST_P(SamplersTest, ValidTextureSamplerMaxAnisotropyExt)
{
......@@ -85,7 +88,95 @@ TEST_P(SamplersTest, InvalidOverTextureSamplerMaxAnisotropyExt)
validateInvalidAnisotropy(sampler, maxValue);
}
// Test that updating a sampler uniform in a program behaves correctly.
TEST_P(SamplersTest31, SampleTextureAThenTextureB)
{
ANGLE_SKIP_TEST_IF(!IsVulkan());
constexpr int kWidth = 2;
constexpr int kHeight = 2;
const GLchar *vertString = R"(#version 310 es
precision highp float;
in vec2 a_position;
out vec2 texCoord;
void main()
{
gl_Position = vec4(a_position, 0, 1);
texCoord = a_position * 0.5 + vec2(0.5);
})";
const GLchar *fragString = R"(#version 310 es
precision highp float;
in vec2 texCoord;
uniform sampler2D tex;
out vec4 my_FragColor;
void main()
{
my_FragColor = texture(tex, texCoord);
})";
std::array<GLColor, kWidth *kHeight> redColor = {
{GLColor::red, GLColor::red, GLColor::red, GLColor::red}};
std::array<GLColor, kWidth *kHeight> greenColor = {
{GLColor::green, GLColor::green, GLColor::green, GLColor::green}};
// Create a red texture and bind to texture unit 0
GLTexture redTex;
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, redTex);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kWidth, kHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE,
redColor.data());
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
ASSERT_GL_NO_ERROR();
// Create a green texture and bind to texture unit 1
GLTexture greenTex;
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, greenTex);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kWidth, kHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE,
greenColor.data());
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glActiveTexture(GL_TEXTURE0);
ASSERT_GL_NO_ERROR();
GLProgram program;
program.makeRaster(vertString, fragString);
ASSERT_NE(0u, program.get());
glUseProgram(program);
GLint location = glGetUniformLocation(program, "tex");
ASSERT_NE(location, -1);
ASSERT_GL_NO_ERROR();
// Draw red
glUniform1i(location, 0);
ASSERT_GL_NO_ERROR();
drawQuad(program, "a_position", 0.5f);
ASSERT_GL_NO_ERROR();
glEnable(GL_BLEND);
glBlendEquation(GL_FUNC_ADD);
glBlendFunc(GL_ONE, GL_ONE);
// Draw green
glUniform1i(location, 1);
ASSERT_GL_NO_ERROR();
drawQuad(program, "a_position", 0.5f);
ASSERT_GL_NO_ERROR();
// Draw red
glUniform1i(location, 0);
ASSERT_GL_NO_ERROR();
drawQuad(program, "a_position", 0.5f);
ASSERT_GL_NO_ERROR();
EXPECT_PIXEL_RECT_EQ(0, 0, kWidth, kHeight, GLColor::yellow);
}
// Samplers are only supported on ES3.
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(SamplersTest);
ANGLE_INSTANTIATE_TEST_ES3(SamplersTest);
ANGLE_INSTANTIATE_TEST_ES31(SamplersTest31);
} // namespace angle
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