Commit 0abb7a2a by Martin Radev Committed by Commit Bot

Update multiview state on program executable change

Relinking the active program can change its number of views and the state has to be correspondingly adjusted. BUG=angleproject:2062 TEST=angle_end2end_tests Change-Id: I20102a428d7566a8cec5d81eeaa55980665812f4 Reviewed-on: https://chromium-review.googlesource.com/637994 Commit-Queue: Martin Radev <mradev@nvidia.com> Reviewed-by: 's avatarOlli Etuaho <oetuaho@nvidia.com> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org>
parent d28758de
...@@ -4603,6 +4603,7 @@ void Context::linkProgram(GLuint program) ...@@ -4603,6 +4603,7 @@ void Context::linkProgram(GLuint program)
Program *programObject = getProgram(program); Program *programObject = getProgram(program);
ASSERT(programObject); ASSERT(programObject);
handleError(programObject->link(this)); handleError(programObject->link(this));
mGLState.onProgramExecutableChange(programObject);
} }
void Context::releaseShaderCompiler() void Context::releaseShaderCompiler()
......
...@@ -1905,15 +1905,14 @@ void StateManagerGL::syncState(const gl::Context *context, const gl::State::Dirt ...@@ -1905,15 +1905,14 @@ void StateManagerGL::syncState(const gl::Context *context, const gl::State::Dirt
break; break;
case gl::State::DIRTY_BIT_PROGRAM_BINDING: case gl::State::DIRTY_BIT_PROGRAM_BINDING:
// TODO(jmadill): implement this // TODO(jmadill): implement this
break;
case gl::State::DIRTY_BIT_PROGRAM_EXECUTABLE:
propagateNumViewsToVAO(state.getProgram(), propagateNumViewsToVAO(state.getProgram(),
GetImplAs<VertexArrayGL>(state.getVertexArray())); GetImplAs<VertexArrayGL>(state.getVertexArray()));
updateMultiviewBaseViewLayerIndexUniform( updateMultiviewBaseViewLayerIndexUniform(
state.getProgram(), state.getProgram(),
state.getDrawFramebuffer()->getImplementation()->getState()); state.getDrawFramebuffer()->getImplementation()->getState());
break; break;
case gl::State::DIRTY_BIT_PROGRAM_EXECUTABLE:
// TODO(jmadill): implement this
break;
case gl::State::DIRTY_BIT_MULTISAMPLING: case gl::State::DIRTY_BIT_MULTISAMPLING:
setMultisamplingStateEnabled(state.isMultisamplingEnabled()); setMultisamplingStateEnabled(state.isMultisamplingEnabled());
break; break;
......
...@@ -176,6 +176,11 @@ class MultiviewRenderTestBase : public MultiviewDrawTest ...@@ -176,6 +176,11 @@ class MultiviewRenderTestBase : public MultiviewDrawTest
mViewHeight = height; mViewHeight = height;
mNumViews = numViews; mNumViews = numViews;
mColorTexture.reset();
mDepthTexture.reset();
mDrawFramebuffer.reset();
mReadFramebuffer.clear();
// Create color and depth textures. // Create color and depth textures.
switch (mMultiviewLayout) switch (mMultiviewLayout)
{ {
...@@ -890,7 +895,7 @@ TEST_P(MultiviewRenderTest, AttribDivisor) ...@@ -890,7 +895,7 @@ TEST_P(MultiviewRenderTest, AttribDivisor)
"void main()\n" "void main()\n"
"{\n" "{\n"
" vec4 p = vec4(vPosition, 1.);\n" " vec4 p = vec4(vPosition, 1.);\n"
" p.xy = p.xy * 0.25 - 0.75 + vec2(offsetX, offsetY);\n" " p.xy = p.xy * 0.25 - vec2(0.75) + vec2(offsetX, offsetY);\n"
" gl_Position.x = (gl_ViewID_OVR == 0u ? p.x : p.x + 1.0);\n" " gl_Position.x = (gl_ViewID_OVR == 0u ? p.x : p.x + 1.0);\n"
" gl_Position.yzw = p.yzw;\n" " gl_Position.yzw = p.yzw;\n"
"}\n"; "}\n";
...@@ -1621,6 +1626,140 @@ TEST_P(MultiviewSideBySideRenderTest, NoLeakingFragments) ...@@ -1621,6 +1626,140 @@ TEST_P(MultiviewSideBySideRenderTest, NoLeakingFragments)
} }
} }
// Verify that re-linking a program adjusts the attribute divisor.
// The test uses instacing to draw for each view a strips of two red quads and two blue quads next
// to each other. The quads' position and color depend on the corresponding attribute divisors.
TEST_P(MultiviewRenderTest, ProgramRelinkUpdatesAttribDivisor)
{
if (!requestMultiviewExtension())
{
return;
}
const int kViewWidth = 4;
const int kViewHeight = 1;
const int kNumViews = 2;
const std::string &fsSource =
"#version 300 es\n"
"#extension GL_OVR_multiview2 : require\n"
"precision mediump float;\n"
"in vec4 oColor;\n"
"out vec4 col;\n"
"void main()\n"
"{\n"
" col = oColor;\n"
"}\n";
auto generateVertexShaderSource = [](int numViews) -> std::string {
std::string source =
"#version 300 es\n"
"#extension GL_OVR_multiview2 : require\n"
"layout(num_views = " +
ToString(numViews) +
") in;\n"
"in vec3 vPosition;\n"
"in float vOffsetX;\n"
"in vec4 vColor;\n"
"out vec4 oColor;\n"
"void main()\n"
"{\n"
" vec4 p = vec4(vPosition, 1.);\n"
" p.x = p.x * 0.25 - 0.75 + vOffsetX;\n"
" oColor = vColor;\n"
" gl_Position = p;\n"
"}\n";
return source;
};
std::string vsSource = generateVertexShaderSource(kNumViews);
ANGLE_GL_PROGRAM(program, vsSource, fsSource);
glUseProgram(program);
GLint positionLoc;
GLBuffer xOffsetVBO;
GLint xOffsetLoc;
GLBuffer colorVBO;
GLint colorLoc;
{
// Initialize buffers and setup attributes.
glBindBuffer(GL_ARRAY_BUFFER, xOffsetVBO);
const GLfloat kXOffsetData[4] = {0.0f, 0.5f, 1.0f, 1.5f};
glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 4, kXOffsetData, GL_STATIC_DRAW);
xOffsetLoc = glGetAttribLocation(program, "vOffsetX");
glVertexAttribPointer(xOffsetLoc, 1, GL_FLOAT, GL_FALSE, 0, 0);
glVertexAttribDivisor(xOffsetLoc, 1);
glEnableVertexAttribArray(xOffsetLoc);
glBindBuffer(GL_ARRAY_BUFFER, colorVBO);
const GLColor kColors[2] = {GLColor::red, GLColor::blue};
glBufferData(GL_ARRAY_BUFFER, sizeof(GLColor) * 2, kColors, GL_STATIC_DRAW);
colorLoc = glGetAttribLocation(program, "vColor");
glVertexAttribDivisor(colorLoc, 2);
glVertexAttribPointer(colorLoc, 4, GL_UNSIGNED_BYTE, GL_FALSE, 0, 0);
glEnableVertexAttribArray(colorLoc);
positionLoc = glGetAttribLocation(program, "vPosition");
}
{
createFBO(kViewWidth, kViewHeight, kNumViews);
drawQuad(program, "vPosition", 0.0f, 1.0f, true, true, 4);
ASSERT_GL_NO_ERROR();
EXPECT_EQ(GLColor::red, GetViewColor(0, 0, 0));
EXPECT_EQ(GLColor::red, GetViewColor(1, 0, 0));
EXPECT_EQ(GLColor::blue, GetViewColor(2, 0, 0));
EXPECT_EQ(GLColor::blue, GetViewColor(3, 0, 0));
}
{
const int kNewNumViews = 3;
vsSource = generateVertexShaderSource(kNewNumViews);
createFBO(kViewWidth, kViewHeight, kNewNumViews);
GLuint vs = CompileShader(GL_VERTEX_SHADER, vsSource);
ASSERT_NE(0u, vs);
GLuint fs = CompileShader(GL_FRAGMENT_SHADER, fsSource);
ASSERT_NE(0u, fs);
GLint numAttachedShaders = 0;
glGetProgramiv(program, GL_ATTACHED_SHADERS, &numAttachedShaders);
GLuint attachedShaders[2] = {0u};
glGetAttachedShaders(program, numAttachedShaders, nullptr, attachedShaders);
for (int i = 0; i < 2; ++i)
{
glDetachShader(program, attachedShaders[i]);
}
glAttachShader(program, vs);
glDeleteShader(vs);
glAttachShader(program, fs);
glDeleteShader(fs);
glBindAttribLocation(program, positionLoc, "vPosition");
glBindAttribLocation(program, xOffsetLoc, "vOffsetX");
glBindAttribLocation(program, colorLoc, "vColor");
glLinkProgram(program);
drawQuad(program, "vPosition", 0.0f, 1.0f, true, true, 4);
ASSERT_GL_NO_ERROR();
for (int i = 0; i < kNewNumViews; ++i)
{
EXPECT_EQ(GLColor::red, GetViewColor(0, 0, i));
EXPECT_EQ(GLColor::red, GetViewColor(1, 0, i));
EXPECT_EQ(GLColor::blue, GetViewColor(2, 0, i));
EXPECT_EQ(GLColor::blue, GetViewColor(3, 0, i));
}
}
}
MultiviewTestParams SideBySideOpenGL() MultiviewTestParams SideBySideOpenGL()
{ {
return MultiviewTestParams(GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE, egl_platform::OPENGL()); return MultiviewTestParams(GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE, egl_platform::OPENGL());
......
...@@ -23,12 +23,33 @@ using GLGen = decltype(glGenBuffers); ...@@ -23,12 +23,33 @@ using GLGen = decltype(glGenBuffers);
using GLDelete = decltype(glDeleteBuffers); using GLDelete = decltype(glDeleteBuffers);
template <GLGen GenF, GLDelete DeleteF> template <GLGen GenF, GLDelete DeleteF>
class GLWrapper class GLWrapper : angle::NonCopyable
{ {
public: public:
GLWrapper() {} GLWrapper() {}
~GLWrapper() { DeleteF(1, &mHandle); } ~GLWrapper() { DeleteF(1, &mHandle); }
// The move-constructor and move-assignment operators are necessary so that the data within a
// GLWrapper object can be relocated.
GLWrapper(GLWrapper &&rht) : mHandle(rht.mHandle) { rht.mHandle = 0u; }
GLWrapper &operator=(GLWrapper &&rht)
{
if (this != &rht)
{
std::swap(mHandle, rht.mHandle);
}
return *this;
}
void reset()
{
if (mHandle != 0u)
{
DeleteF(1, &mHandle);
mHandle = 0u;
}
}
GLuint get() GLuint get()
{ {
if (!mHandle) if (!mHandle)
...@@ -41,7 +62,7 @@ class GLWrapper ...@@ -41,7 +62,7 @@ class GLWrapper
operator GLuint() { return get(); } operator GLuint() { return get(); }
private: private:
GLuint mHandle = 0; GLuint mHandle = 0u;
}; };
using GLVertexArray = GLWrapper<glGenVertexArrays, glDeleteVertexArrays>; using GLVertexArray = GLWrapper<glGenVertexArrays, glDeleteVertexArrays>;
......
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