Add branch for viewport or layer selection in VS
The patch extends the behavior of
SH_SELECT_VIEW_IN_NV_GLSL_VERTEX_SHADER so that either the viewport
or layer is selected based on the value of the internal uniform variable
MultiviewRenderPath.
BUG=angleproject:2062
TEST=angle_end2end_tests
TEST=angle_unittests
Change-Id: Ia311b12b1fed642dac78eba8732e2535242f34fd
Reviewed-on: https://chromium-review.googlesource.com/615260
Commit-Queue: Martin Radev <mradev@nvidia.com>
Reviewed-by: Olli Etuaho <oetuaho@nvidia.com>
Reviewed-by: Geoff Lang <geofflang@chromium.org>
diff --git a/src/compiler/translator/BaseTypes.h b/src/compiler/translator/BaseTypes.h
index b1974c1..336f3b7 100644
--- a/src/compiler/translator/BaseTypes.h
+++ b/src/compiler/translator/BaseTypes.h
@@ -576,6 +576,7 @@
// GLSL ES 3.1 extension OES_geometry_shader qualifiers
EvqGeometryIn,
EvqGeometryOut,
+ EvqLayer, // gl_Layer
// end of list
EvqLast
@@ -807,6 +808,7 @@
case EvqSecondaryFragDataEXT: return "SecondaryFragDataEXT";
case EvqViewIDOVR: return "ViewIDOVR";
case EvqViewportIndex: return "ViewportIndex";
+ case EvqLayer: return "Layer";
case EvqLastFragColor: return "LastFragColor";
case EvqLastFragData: return "LastFragData";
case EvqSmoothOut: return "smooth out";
diff --git a/src/compiler/translator/DeclareAndInitBuiltinsForInstancedMultiview.cpp b/src/compiler/translator/DeclareAndInitBuiltinsForInstancedMultiview.cpp
index 94fd6bf..68e5d35 100644
--- a/src/compiler/translator/DeclareAndInitBuiltinsForInstancedMultiview.cpp
+++ b/src/compiler/translator/DeclareAndInitBuiltinsForInstancedMultiview.cpp
@@ -109,23 +109,50 @@
globalSequence->insert(globalSequence->begin(), declaration);
}
-// Adds the expression gl_ViewportIndex = int(ViewID_OVR) to the end of the initializers' sequence.
-void SelectViewportIndexInVertexShader(TIntermTyped *viewIDSymbol, TIntermSequence *initializers)
+// Adds a branch to write int(ViewID_OVR) to either gl_ViewportIndex or gl_Layer. The branch is
+// added to the end of the initializers' sequence.
+void SelectViewIndexInVertexShader(TIntermTyped *viewIDSymbol,
+ TIntermTyped *multiviewBaseViewLayerIndexSymbol,
+ TIntermSequence *initializers)
{
- // Create a gl_ViewportIndex node.
- TIntermSymbol *viewportIndexSymbol =
- new TIntermSymbol(0, "gl_ViewportIndex", TType(EbtInt, EbpHigh, EvqViewportIndex));
-
// Create an int(ViewID_OVR) node.
TIntermSequence *viewIDSymbolCastArguments = new TIntermSequence();
viewIDSymbolCastArguments->push_back(viewIDSymbol);
TIntermAggregate *viewIDAsInt = TIntermAggregate::CreateConstructor(
TType(EbtInt, EbpHigh, EvqTemporary), viewIDSymbolCastArguments);
- // Create a gl_ViewportIndex = int(ViewID_OVR) node.
- TIntermBinary *viewIDInitializer =
- new TIntermBinary(EOpAssign, viewportIndexSymbol, viewIDAsInt);
- initializers->push_back(viewIDInitializer);
+ // Create a gl_ViewportIndex node.
+ TIntermSymbol *viewportIndexSymbol =
+ new TIntermSymbol(0, "gl_ViewportIndex", TType(EbtInt, EbpHigh, EvqViewportIndex));
+
+ // Create a { gl_ViewportIndex = int(ViewID_OVR) } node.
+ TIntermBlock *viewportIndexInitializerInBlock = new TIntermBlock();
+ viewportIndexInitializerInBlock->appendStatement(
+ new TIntermBinary(EOpAssign, viewportIndexSymbol, viewIDAsInt));
+
+ // Create a gl_Layer node.
+ TIntermSymbol *layerSymbol = new TIntermSymbol(0, "gl_Layer", TType(EbtInt, EbpHigh, EvqLayer));
+
+ // Create an int(ViewID_OVR) + multiviewBaseViewLayerIndex node
+ TIntermBinary *sumOfViewIDAndBaseViewIndex =
+ new TIntermBinary(EOpAdd, viewIDAsInt->deepCopy(), multiviewBaseViewLayerIndexSymbol);
+
+ // Create a { gl_Layer = int(ViewID_OVR) + multiviewBaseViewLayerIndex } node.
+ TIntermBlock *layerInitializerInBlock = new TIntermBlock();
+ layerInitializerInBlock->appendStatement(
+ new TIntermBinary(EOpAssign, layerSymbol, sumOfViewIDAndBaseViewIndex));
+
+ // Create a node to compare whether the base view index uniform is less than zero.
+ TIntermBinary *multiviewBaseViewLayerIndexZeroComparison =
+ new TIntermBinary(EOpLessThan, multiviewBaseViewLayerIndexSymbol->deepCopy(),
+ CreateZeroNode(TType(EbtInt, EbpHigh, EvqConst)));
+
+ // Create an if-else statement to select the code path.
+ TIntermIfElse *multiviewBranch =
+ new TIntermIfElse(multiviewBaseViewLayerIndexZeroComparison,
+ viewportIndexInitializerInBlock, layerInitializerInBlock);
+
+ initializers->push_back(multiviewBranch);
}
} // namespace
@@ -162,15 +189,24 @@
// The AST transformation which adds the expression to select the viewport index should
// be done only for the GLSL and ESSL output.
- const bool selectViewport =
- (compileOptions & SH_SELECT_VIEW_IN_NV_GLSL_VERTEX_SHADER) != 0u;
- // Assert that if the viewport is selected in the vertex shader, then the output is
+ const bool selectView = (compileOptions & SH_SELECT_VIEW_IN_NV_GLSL_VERTEX_SHADER) != 0u;
+ // Assert that if the view is selected in the vertex shader, then the output is
// either GLSL or ESSL.
- ASSERT(!selectViewport || IsOutputGLSL(shaderOutput) || IsOutputESSL(shaderOutput));
- if (selectViewport)
+ ASSERT(!selectView || IsOutputGLSL(shaderOutput) || IsOutputESSL(shaderOutput));
+ if (selectView)
{
- // Setting a value to gl_ViewportIndex should happen after ViewID_OVR's initialization.
- SelectViewportIndexInVertexShader(viewIDSymbol->deepCopy(), initializers);
+ // Add a uniform to switch between side-by-side and layered rendering.
+ TIntermSymbol *multiviewBaseViewLayerIndexSymbol =
+ new TIntermSymbol(symbolTable->nextUniqueId(), "multiviewBaseViewLayerIndex",
+ TType(EbtInt, EbpHigh, EvqUniform));
+ multiviewBaseViewLayerIndexSymbol->setInternal(true);
+ DeclareGlobalVariable(root, multiviewBaseViewLayerIndexSymbol);
+
+ // Setting a value to gl_ViewportIndex or gl_Layer should happen after ViewID_OVR's
+ // initialization.
+ SelectViewIndexInVertexShader(viewIDSymbol->deepCopy(),
+ multiviewBaseViewLayerIndexSymbol->deepCopy(),
+ initializers);
}
// Insert initializers at the beginning of main().
diff --git a/src/compiler/translator/DeclareAndInitBuiltinsForInstancedMultiview.h b/src/compiler/translator/DeclareAndInitBuiltinsForInstancedMultiview.h
index 201f2a2..b4ab05f 100644
--- a/src/compiler/translator/DeclareAndInitBuiltinsForInstancedMultiview.h
+++ b/src/compiler/translator/DeclareAndInitBuiltinsForInstancedMultiview.h
@@ -14,8 +14,14 @@
// - Add initializers of ViewID_OVR and InstanceID to the beginning of the body of main. The pass
// should be executed before any variables get collected so that usage of gl_InstanceID is recorded.
// - If the output is ESSL or GLSL and the SH_SELECT_VIEW_IN_NV_GLSL_VERTEX_SHADER option is
-// enabled, the expression "gl_ViewportIndex = int(ViewID_OVR)" is added after ViewID and InstanceID
-// are initialized.
+// enabled, the expression
+// "if (multiviewBaseViewLayerIndex < 0) {
+// gl_ViewportIndex = int(ViewID_OVR);
+// } else {
+// gl_Layer = int(ViewID_OVR) + multiviewBaseViewLayerIndex;
+// }"
+// is added after ViewID and InstanceID are initialized. Also, MultiviewRenderPath is added as a
+// uniform.
//
#ifndef COMPILER_TRANSLATOR_DECLAREANDINITBUILTINSFORINSTANCEDMULTIVIEW_H_
diff --git a/src/libANGLE/Framebuffer.cpp b/src/libANGLE/Framebuffer.cpp
index 202abbc..3892f1f 100644
--- a/src/libANGLE/Framebuffer.cpp
+++ b/src/libANGLE/Framebuffer.cpp
@@ -483,6 +483,16 @@
return attachment->getMultiviewLayout();
}
+int FramebufferState::getBaseViewIndex() const
+{
+ const FramebufferAttachment *attachment = getFirstNonNullAttachment();
+ if (attachment == nullptr)
+ {
+ return GL_NONE;
+ }
+ return attachment->getBaseViewIndex();
+}
+
Framebuffer::Framebuffer(const Caps &caps, rx::GLImplFactory *factory, GLuint id)
: mState(caps),
mImpl(factory->createFramebuffer(mState)),
@@ -1652,6 +1662,11 @@
return mState.getNumViews();
}
+GLint Framebuffer::getBaseViewIndex() const
+{
+ return mState.getBaseViewIndex();
+}
+
const std::vector<Offset> *Framebuffer::getViewportOffsets() const
{
return mState.getViewportOffsets();
diff --git a/src/libANGLE/Framebuffer.h b/src/libANGLE/Framebuffer.h
index cad55f0..1d0191c 100644
--- a/src/libANGLE/Framebuffer.h
+++ b/src/libANGLE/Framebuffer.h
@@ -95,6 +95,7 @@
GLenum getMultiviewLayout() const;
GLsizei getNumViews() const;
const std::vector<Offset> *getViewportOffsets() const;
+ GLint getBaseViewIndex() const;
private:
friend class Framebuffer;
@@ -185,6 +186,7 @@
const FramebufferAttachment *getAttachment(GLenum attachment) const;
GLenum getMultiviewLayout() const;
GLsizei getNumViews() const;
+ GLint getBaseViewIndex() const;
const std::vector<Offset> *getViewportOffsets() const;
size_t getDrawbufferStateCount() const;
diff --git a/src/libANGLE/Program.h b/src/libANGLE/Program.h
index 8d3db69..3690fb7 100644
--- a/src/libANGLE/Program.h
+++ b/src/libANGLE/Program.h
@@ -280,6 +280,9 @@
GLuint getSamplerIndexFromUniformIndex(GLuint uniformIndex) const;
GLuint getAttributeLocation(const std::string &name) const;
+ int getNumViews() const { return mNumViews; }
+ bool usesMultiview() const { return mNumViews != -1; }
+
private:
friend class MemoryProgramCache;
friend class Program;
@@ -537,8 +540,8 @@
const Bindings &getUniformLocationBindings() const { return mUniformLocationBindings; }
const Bindings &getFragmentInputBindings() const { return mFragmentInputBindings; }
- int getNumViews() const { return mState.mNumViews; }
- bool usesMultiview() const { return mState.mNumViews != -1; }
+ int getNumViews() const { return mState.getNumViews(); }
+ bool usesMultiview() const { return mState.usesMultiview(); }
private:
~Program();
diff --git a/src/libANGLE/renderer/gl/FramebufferGL.cpp b/src/libANGLE/renderer/gl/FramebufferGL.cpp
index 7b6a258..ffd1a60 100644
--- a/src/libANGLE/renderer/gl/FramebufferGL.cpp
+++ b/src/libANGLE/renderer/gl/FramebufferGL.cpp
@@ -95,12 +95,14 @@
void RetrieveMultiviewFieldsFromAttachment(const gl::FramebufferAttachment *attachment,
const std::vector<gl::Offset> **viewportOffsets,
- GLenum *multiviewLayout)
+ GLenum *multiviewLayout,
+ int *baseViewIndex)
{
if (attachment)
{
*viewportOffsets = &attachment->getMultiviewViewportOffsets();
*multiviewLayout = attachment->getMultiviewLayout();
+ *baseViewIndex = attachment->getBaseViewIndex();
}
}
@@ -596,6 +598,7 @@
const std::vector<gl::Offset> *attachmentViewportOffsets = nullptr;
GLenum multiviewLayout = GL_NONE;
+ int baseViewIndex = -1;
bool isAttachmentModified = false;
for (auto dirtyBit : dirtyBits)
@@ -606,14 +609,16 @@
BindFramebufferAttachment(mFunctions, GL_DEPTH_ATTACHMENT,
mState.getDepthAttachment());
RetrieveMultiviewFieldsFromAttachment(mState.getDepthAttachment(),
- &attachmentViewportOffsets, &multiviewLayout);
+ &attachmentViewportOffsets, &multiviewLayout,
+ &baseViewIndex);
isAttachmentModified = true;
break;
case Framebuffer::DIRTY_BIT_STENCIL_ATTACHMENT:
BindFramebufferAttachment(mFunctions, GL_STENCIL_ATTACHMENT,
mState.getStencilAttachment());
RetrieveMultiviewFieldsFromAttachment(mState.getStencilAttachment(),
- &attachmentViewportOffsets, &multiviewLayout);
+ &attachmentViewportOffsets, &multiviewLayout,
+ &baseViewIndex);
isAttachmentModified = true;
break;
case Framebuffer::DIRTY_BIT_DRAW_BUFFERS:
@@ -654,7 +659,8 @@
static_cast<GLenum>(GL_COLOR_ATTACHMENT0 + index),
mState.getColorAttachment(index));
RetrieveMultiviewFieldsFromAttachment(mState.getColorAttachment(index),
- &attachmentViewportOffsets, &multiviewLayout);
+ &attachmentViewportOffsets, &multiviewLayout,
+ &baseViewIndex);
isAttachmentModified = true;
break;
}
@@ -674,6 +680,9 @@
mStateManager->setViewportOffsets(
FramebufferAttachment::GetDefaultViewportOffsetVector());
}
+
+ mStateManager->updateMultiviewBaseViewLayerIndexUniform(context->getGLState().getProgram(),
+ getState());
}
}
diff --git a/src/libANGLE/renderer/gl/ProgramGL.cpp b/src/libANGLE/renderer/gl/ProgramGL.cpp
index 2ea74e2..3c1fe40 100644
--- a/src/libANGLE/renderer/gl/ProgramGL.cpp
+++ b/src/libANGLE/renderer/gl/ProgramGL.cpp
@@ -35,6 +35,7 @@
mWorkarounds(workarounds),
mStateManager(stateManager),
mEnablePathRendering(enablePathRendering),
+ mMultiviewBaseViewLayerIndexUniformLocation(-1),
mProgramID(0)
{
ASSERT(mFunctions);
@@ -590,6 +591,8 @@
mUniformRealLocationMap.clear();
mUniformBlockRealLocationMap.clear();
mPathRenderingFragmentInputs.clear();
+
+ mMultiviewBaseViewLayerIndexUniformLocation = -1;
}
bool ProgramGL::checkLinkStatus(gl::InfoLog &infoLog)
@@ -658,6 +661,13 @@
mUniformRealLocationMap[uniformLocation] = realLocation;
}
+ if (mState.usesMultiview())
+ {
+ mMultiviewBaseViewLayerIndexUniformLocation =
+ mFunctions->getUniformLocation(mProgramID, "webgl_angle_multiviewBaseViewLayerIndex");
+ ASSERT(mMultiviewBaseViewLayerIndexUniformLocation != -1);
+ }
+
// Discover CHROMIUM_path_rendering fragment inputs if enabled.
if (!mEnablePathRendering)
return;
@@ -724,4 +734,23 @@
}
}
+void ProgramGL::enableSideBySideRenderingPath() const
+{
+ ASSERT(mState.usesMultiview());
+ ASSERT(mMultiviewBaseViewLayerIndexUniformLocation != -1);
+
+ ASSERT(mFunctions->programUniform1i != nullptr);
+ mFunctions->programUniform1i(mProgramID, mMultiviewBaseViewLayerIndexUniformLocation, -1);
+}
+
+void ProgramGL::enableLayeredRenderingPath(int baseViewIndex) const
+{
+ ASSERT(mState.usesMultiview());
+ ASSERT(mMultiviewBaseViewLayerIndexUniformLocation != -1);
+
+ ASSERT(mFunctions->programUniform1i != nullptr);
+ mFunctions->programUniform1i(mProgramID, mMultiviewBaseViewLayerIndexUniformLocation,
+ baseViewIndex);
+}
+
} // namespace rx
diff --git a/src/libANGLE/renderer/gl/ProgramGL.h b/src/libANGLE/renderer/gl/ProgramGL.h
index 29ffb1d..ea8acf8 100644
--- a/src/libANGLE/renderer/gl/ProgramGL.h
+++ b/src/libANGLE/renderer/gl/ProgramGL.h
@@ -78,6 +78,9 @@
GLuint getProgramID() const;
+ void enableSideBySideRenderingPath() const;
+ void enableLayeredRenderingPath(int baseViewIndex) const;
+
private:
void preLink();
bool checkLinkStatus(gl::InfoLog &infoLog);
@@ -102,6 +105,7 @@
std::vector<PathRenderingFragmentInput> mPathRenderingFragmentInputs;
bool mEnablePathRendering;
+ GLint mMultiviewBaseViewLayerIndexUniformLocation;
GLuint mProgramID;
};
diff --git a/src/libANGLE/renderer/gl/StateManagerGL.cpp b/src/libANGLE/renderer/gl/StateManagerGL.cpp
index 9918f6f..72c816e 100644
--- a/src/libANGLE/renderer/gl/StateManagerGL.cpp
+++ b/src/libANGLE/renderer/gl/StateManagerGL.cpp
@@ -1885,8 +1885,13 @@
// TODO(jmadill): implement this
break;
case gl::State::DIRTY_BIT_DRAW_FRAMEBUFFER_BINDING:
+ {
// TODO(jmadill): implement this
+ updateMultiviewBaseViewLayerIndexUniform(
+ state.getProgram(),
+ state.getDrawFramebuffer()->getImplementation()->getState());
break;
+ }
case gl::State::DIRTY_BIT_RENDERBUFFER_BINDING:
// TODO(jmadill): implement this
break;
@@ -1902,6 +1907,9 @@
// TODO(jmadill): implement this
propagateNumViewsToVAO(state.getProgram(),
GetImplAs<VertexArrayGL>(state.getVertexArray()));
+ updateMultiviewBaseViewLayerIndexUniform(
+ state.getProgram(),
+ state.getDrawFramebuffer()->getImplementation()->getState());
break;
case gl::State::DIRTY_BIT_PROGRAM_EXECUTABLE:
// TODO(jmadill): implement this
@@ -2159,4 +2167,25 @@
vao->applyNumViewsToDivisor(programNumViews);
}
}
+
+void StateManagerGL::updateMultiviewBaseViewLayerIndexUniform(
+ const gl::Program *program,
+ const gl::FramebufferState &drawFramebufferState) const
+{
+ if (mIsMultiviewEnabled && program != nullptr && program->usesMultiview())
+ {
+ const ProgramGL *programGL = GetImplAs<ProgramGL>(program);
+ switch (drawFramebufferState.getMultiviewLayout())
+ {
+ case GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE:
+ programGL->enableSideBySideRenderingPath();
+ break;
+ case GL_FRAMEBUFFER_MULTIVIEW_LAYERED_ANGLE:
+ programGL->enableLayeredRenderingPath(drawFramebufferState.getBaseViewIndex());
+ break;
+ default:
+ break;
+ }
+ }
+}
}
diff --git a/src/libANGLE/renderer/gl/StateManagerGL.h b/src/libANGLE/renderer/gl/StateManagerGL.h
index 8fb9a7f..98a42be 100644
--- a/src/libANGLE/renderer/gl/StateManagerGL.h
+++ b/src/libANGLE/renderer/gl/StateManagerGL.h
@@ -22,6 +22,7 @@
struct Caps;
class ContextState;
class State;
+class FramebufferState;
}
namespace rx
@@ -180,6 +181,10 @@
void syncState(const gl::Context *context, const gl::State::DirtyBits &glDirtyBits);
+ void updateMultiviewBaseViewLayerIndexUniform(
+ const gl::Program *program,
+ const gl::FramebufferState &drawFramebufferState) const;
+
private:
// Set state that's common among draw commands and compute invocations.
void setGenericShaderState(const gl::Context *context);
diff --git a/src/tests/compiler_tests/WEBGL_multiview_test.cpp b/src/tests/compiler_tests/WEBGL_multiview_test.cpp
index 3175bbf..976f84e 100644
--- a/src/tests/compiler_tests/WEBGL_multiview_test.cpp
+++ b/src/tests/compiler_tests/WEBGL_multiview_test.cpp
@@ -931,4 +931,34 @@
EXPECT_LT(viewIDOVRAssignmentLoc, glViewportIndexAssignmentLoc);
}
+// The test checks that the layer is selected after the initialization of ViewID_OVR for
+// GLSL and ESSL ouputs.
+TEST_F(WEBGLMultiviewVertexShaderOutputCodeTest, GlLayerIsSet)
+{
+ const std::string &shaderString =
+ "#version 300 es\n"
+ "#extension GL_OVR_multiview : require\n"
+ "layout(num_views = 3) in;\n"
+ "void main()\n"
+ "{\n"
+ "}\n";
+ compile(shaderString, SH_INITIALIZE_BUILTINS_FOR_INSTANCED_MULTIVIEW |
+ SH_SELECT_VIEW_IN_NV_GLSL_VERTEX_SHADER);
+ const char glLayerAssignment[] =
+ "gl_Layer = (int(webgl_angle_ViewID_OVR) + webgl_angle_multiviewBaseViewLayerIndex)";
+
+ // Check that the layer is selected.
+ EXPECT_TRUE(foundInAllGLSLCode(glLayerAssignment));
+
+ // Setting gl_Layer must happen after ViewID_OVR's initialization.
+ const char viewIDOVRAssignment[] = "webgl_angle_ViewID_OVR = (uint(gl_InstanceID) % 3u)";
+ size_t viewIDOVRAssignmentLoc = findInCode(SH_GLSL_COMPATIBILITY_OUTPUT, viewIDOVRAssignment);
+ size_t glLayerAssignmentLoc = findInCode(SH_GLSL_COMPATIBILITY_OUTPUT, glLayerAssignment);
+ EXPECT_LT(viewIDOVRAssignmentLoc, glLayerAssignmentLoc);
+
+ viewIDOVRAssignmentLoc = findInCode(SH_ESSL_OUTPUT, viewIDOVRAssignment);
+ glLayerAssignmentLoc = findInCode(SH_ESSL_OUTPUT, glLayerAssignment);
+ EXPECT_LT(viewIDOVRAssignmentLoc, glLayerAssignmentLoc);
+}
+
} // namespace
\ No newline at end of file