Commit 4e619f58 by Martin Radev Committed by Commit Bot

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: 's avatarOlli Etuaho <oetuaho@nvidia.com> Reviewed-by: 's avatarGeoff Lang <geofflang@chromium.org>
parent 3dfaf265
......@@ -234,8 +234,9 @@ const ShCompileOptions SH_INITIALIZE_BUILTINS_FOR_INSTANCED_MULTIVIEW = UINT64_C
// With the flag enabled the GLSL/ESSL vertex shader is modified to include code for viewport
// selection in the following way:
// - Code to enable the extension NV_viewport_array2 is included.
// - Code to select the viewport index is included at the beginning of main after ViewID_OVR's
// initialization: gl_ViewportIndex = int(ViewID_OVR)
// - Code to select the viewport index or layer is inserted at the beginning of main after
// ViewID_OVR's initialization.
// - A declaration of the uniform multiviewBaseViewLayerIndex.
// Note: The SH_INITIALIZE_BUILTINS_FOR_INSTANCED_MULTIVIEW flag also has to be enabled to have the
// temporary variable ViewID_OVR declared and initialized.
const ShCompileOptions SH_SELECT_VIEW_IN_NV_GLSL_VERTEX_SHADER = UINT64_C(1) << 34;
......
......@@ -576,6 +576,7 @@ enum TQualifier
// GLSL ES 3.1 extension OES_geometry_shader qualifiers
EvqGeometryIn,
EvqGeometryOut,
EvqLayer, // gl_Layer
// end of list
EvqLast
......@@ -807,6 +808,7 @@ inline const char *getQualifierString(TQualifier q)
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";
......
......@@ -109,23 +109,50 @@ void DeclareGlobalVariable(TIntermBlock *root, TIntermTyped *typedNode)
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 @@ void DeclareAndInitBuiltinsForInstancedMultiview(TIntermBlock *root,
// 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().
......
......@@ -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_
......
......@@ -483,6 +483,16 @@ GLenum FramebufferState::getMultiviewLayout() const
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 @@ GLsizei Framebuffer::getNumViews() const
return mState.getNumViews();
}
GLint Framebuffer::getBaseViewIndex() const
{
return mState.getBaseViewIndex();
}
const std::vector<Offset> *Framebuffer::getViewportOffsets() const
{
return mState.getViewportOffsets();
......
......@@ -95,6 +95,7 @@ class FramebufferState final : angle::NonCopyable
GLenum getMultiviewLayout() const;
GLsizei getNumViews() const;
const std::vector<Offset> *getViewportOffsets() const;
GLint getBaseViewIndex() const;
private:
friend class Framebuffer;
......@@ -185,6 +186,7 @@ class Framebuffer final : public LabeledObject, public OnAttachmentDirtyReceiver
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;
......
......@@ -280,6 +280,9 @@ class ProgramState final : angle::NonCopyable
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 @@ class Program final : angle::NonCopyable, public LabeledObject
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();
......
......@@ -95,12 +95,14 @@ void BindFramebufferAttachment(const FunctionsGL *functions,
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 @@ void FramebufferGL::syncState(const gl::Context *context, const Framebuffer::Dir
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 @@ void FramebufferGL::syncState(const gl::Context *context, const Framebuffer::Dir
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 @@ void FramebufferGL::syncState(const gl::Context *context, const Framebuffer::Dir
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 @@ void FramebufferGL::syncState(const gl::Context *context, const Framebuffer::Dir
mStateManager->setViewportOffsets(
FramebufferAttachment::GetDefaultViewportOffsetVector());
}
mStateManager->updateMultiviewBaseViewLayerIndexUniform(context->getGLState().getProgram(),
getState());
}
}
......
......@@ -35,6 +35,7 @@ ProgramGL::ProgramGL(const gl::ProgramState &data,
mWorkarounds(workarounds),
mStateManager(stateManager),
mEnablePathRendering(enablePathRendering),
mMultiviewBaseViewLayerIndexUniformLocation(-1),
mProgramID(0)
{
ASSERT(mFunctions);
......@@ -590,6 +591,8 @@ void ProgramGL::preLink()
mUniformRealLocationMap.clear();
mUniformBlockRealLocationMap.clear();
mPathRenderingFragmentInputs.clear();
mMultiviewBaseViewLayerIndexUniformLocation = -1;
}
bool ProgramGL::checkLinkStatus(gl::InfoLog &infoLog)
......@@ -658,6 +661,13 @@ void ProgramGL::postLink()
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::postLink()
}
}
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
......@@ -78,6 +78,9 @@ class ProgramGL : public ProgramImpl
GLuint getProgramID() const;
void enableSideBySideRenderingPath() const;
void enableLayeredRenderingPath(int baseViewIndex) const;
private:
void preLink();
bool checkLinkStatus(gl::InfoLog &infoLog);
......@@ -102,6 +105,7 @@ class ProgramGL : public ProgramImpl
std::vector<PathRenderingFragmentInput> mPathRenderingFragmentInputs;
bool mEnablePathRendering;
GLint mMultiviewBaseViewLayerIndexUniformLocation;
GLuint mProgramID;
};
......
......@@ -1885,8 +1885,13 @@ void StateManagerGL::syncState(const gl::Context *context, const gl::State::Dirt
// 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 @@ void StateManagerGL::syncState(const gl::Context *context, const gl::State::Dirt
// 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 @@ void StateManagerGL::propagateNumViewsToVAO(const gl::Program *program, VertexAr
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;
}
}
}
}
......@@ -22,6 +22,7 @@ namespace gl
struct Caps;
class ContextState;
class State;
class FramebufferState;
}
namespace rx
......@@ -180,6 +181,10 @@ class StateManagerGL final : angle::NonCopyable
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);
......
......@@ -931,4 +931,34 @@ TEST_F(WEBGLMultiviewVertexShaderOutputCodeTest, GlViewportIndexIsSet)
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
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