Select viewport index in the GLSL/ESSL vertex shader
The patch enables viewport selection for multiview rendering in the
GLSL/ESSL vertex shader through the use of the GL_NV_viewport_array2
extension. The AST is modified only for GLSL and ESSL to include the
viewport selection expression after ViewID_OVR's initialization.
BUG=angleproject:2062
TEST=angle_unittests
Change-Id: Iee05bb5a4b687ed53ddbdd466f1572227b1f0cde
diff --git a/src/compiler/fuzz/translator_fuzzer.cpp b/src/compiler/fuzz/translator_fuzzer.cpp
index dcc0562..910af8b 100644
--- a/src/compiler/fuzz/translator_fuzzer.cpp
+++ b/src/compiler/fuzz/translator_fuzzer.cpp
@@ -14,6 +14,7 @@
#include "angle_gl.h"
#include "compiler/translator/Compiler.h"
+#include "compiler/translator/util.h"
using namespace sh;
@@ -84,6 +85,14 @@
return 0;
}
+ ShShaderOutput shaderOutput = static_cast<ShShaderOutput>(output);
+ if (!(IsOutputGLSL(shaderOutput) || IsOutputESSL(shaderOutput)) &&
+ (options & SH_SELECT_VIEW_IN_NV_GLSL_VERTEX_SHADER) != 0u)
+ {
+ // This compiler option is only available in ESSL and GLSL.
+ return 0;
+ }
+
std::vector<uint32_t> validOutputs;
validOutputs.push_back(SH_ESSL_OUTPUT);
validOutputs.push_back(SH_GLSL_COMPATIBILITY_OUTPUT);
@@ -125,8 +134,8 @@
if (translators.find(key) == translators.end())
{
- UniqueTCompiler translator(ConstructCompiler(type, static_cast<ShShaderSpec>(spec),
- static_cast<ShShaderOutput>(output)));
+ UniqueTCompiler translator(
+ ConstructCompiler(type, static_cast<ShShaderSpec>(spec), shaderOutput));
if (translator == nullptr)
{
diff --git a/src/compiler/translator/BaseTypes.h b/src/compiler/translator/BaseTypes.h
index 0d9f415..a2955c4 100644
--- a/src/compiler/translator/BaseTypes.h
+++ b/src/compiler/translator/BaseTypes.h
@@ -537,7 +537,8 @@
EvqSecondaryFragColorEXT, // EXT_blend_func_extended
EvqSecondaryFragDataEXT, // EXT_blend_func_extended
- EvqViewIDOVR, // OVR_multiview
+ EvqViewIDOVR, // OVR_multiview
+ EvqViewportIndex, // gl_ViewportIndex
// built-ins written by the shader_framebuffer_fetch extension(s)
EvqLastFragColor,
@@ -774,6 +775,7 @@
case EvqSecondaryFragColorEXT: return "SecondaryFragColorEXT";
case EvqSecondaryFragDataEXT: return "SecondaryFragDataEXT";
case EvqViewIDOVR: return "ViewIDOVR";
+ case EvqViewportIndex: return "ViewportIndex";
case EvqLastFragColor: return "LastFragColor";
case EvqLastFragData: return "LastFragData";
case EvqSmoothOut: return "smooth out";
diff --git a/src/compiler/translator/Compiler.cpp b/src/compiler/translator/Compiler.cpp
index 6e76fe1..a194071 100644
--- a/src/compiler/translator/Compiler.cpp
+++ b/src/compiler/translator/Compiler.cpp
@@ -431,7 +431,8 @@
if (success && (compileOptions & SH_INITIALIZE_BUILTINS_FOR_INSTANCED_MULTIVIEW) &&
parseContext.isMultiviewExtensionEnabled() && getShaderType() != GL_COMPUTE_SHADER)
{
- DeclareAndInitBuiltinsForInstancedMultiview(root, getNumViews(), getShaderType());
+ DeclareAndInitBuiltinsForInstancedMultiview(root, mNumViews, shaderType, compileOptions,
+ outputType);
}
// This pass might emit short circuits so keep it before the short circuit unfolding
diff --git a/src/compiler/translator/DeclareAndInitBuiltinsForInstancedMultiview.cpp b/src/compiler/translator/DeclareAndInitBuiltinsForInstancedMultiview.cpp
index 83dec99..597ebbf 100644
--- a/src/compiler/translator/DeclareAndInitBuiltinsForInstancedMultiview.cpp
+++ b/src/compiler/translator/DeclareAndInitBuiltinsForInstancedMultiview.cpp
@@ -13,6 +13,7 @@
#include "compiler/translator/InitializeVariables.h"
#include "compiler/translator/IntermTraverse.h"
#include "compiler/translator/SymbolTable.h"
+#include "compiler/translator/util.h"
namespace sh
{
@@ -47,10 +48,11 @@
return new TIntermSymbol(0, "gl_InstanceID", TType(EbtInt, EbpHigh, EvqInstanceID));
}
-void InitializeViewIDAndInstanceID(TIntermBlock *root,
- TIntermTyped *viewIDSymbol,
+// Adds the InstanceID and ViewID_OVR initializers to the end of the initializers' sequence.
+void InitializeViewIDAndInstanceID(TIntermTyped *viewIDSymbol,
TIntermTyped *instanceIDSymbol,
- unsigned numberOfViews)
+ unsigned numberOfViews,
+ TIntermSequence *initializers)
{
// Create a signed numberOfViews node.
TConstantUnion *numberOfViewsConstant = new TConstantUnion();
@@ -65,6 +67,7 @@
// Create a InstanceID = gl_InstanceID / numberOfViews node.
TIntermBinary *instanceIDInitializer =
new TIntermBinary(EOpAssign, instanceIDSymbol->deepCopy(), normalizedInstanceID);
+ initializers->push_back(instanceIDInitializer);
// Create a uint(gl_InstanceID) node.
TIntermSequence *glInstanceIDSymbolCastArguments = new TIntermSequence();
@@ -85,11 +88,7 @@
// Create a ViewID_OVR = uint(gl_InstanceID) % numberOfViews node.
TIntermBinary *viewIDInitializer =
new TIntermBinary(EOpAssign, viewIDSymbol->deepCopy(), normalizedViewID);
-
- // Add initializers at the beginning of main().
- TIntermBlock *mainBody = FindMainBody(root);
- mainBody->getSequence()->insert(mainBody->getSequence()->begin(), instanceIDInitializer);
- mainBody->getSequence()->insert(mainBody->getSequence()->begin(), viewIDInitializer);
+ initializers->push_back(viewIDInitializer);
}
// Replaces every occurrence of a symbol with the name specified in symbolName with newSymbolNode.
@@ -108,11 +107,32 @@
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)
+{
+ // 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);
+}
+
} // namespace
void DeclareAndInitBuiltinsForInstancedMultiview(TIntermBlock *root,
unsigned numberOfViews,
- GLenum shaderType)
+ GLenum shaderType,
+ ShCompileOptions compileOptions,
+ ShShaderOutput shaderOutput)
{
ASSERT(shaderType == GL_VERTEX_SHADER || shaderType == GL_FRAGMENT_SHADER);
@@ -132,7 +152,28 @@
instanceIDSymbol->setInternal(true);
DeclareGlobalVariable(root, instanceIDSymbol);
ReplaceSymbol(root, "gl_InstanceID", instanceIDSymbol);
- InitializeViewIDAndInstanceID(root, viewIDSymbol, instanceIDSymbol, numberOfViews);
+
+ TIntermSequence *initializers = new TIntermSequence();
+ InitializeViewIDAndInstanceID(viewIDSymbol, instanceIDSymbol, numberOfViews, initializers);
+
+ // 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
+ // either GLSL or ESSL.
+ ASSERT(!selectViewport || IsOutputGLSL(shaderOutput) || IsOutputESSL(shaderOutput));
+ if (selectViewport)
+ {
+ // Setting a value to gl_ViewportIndex should happen after ViewID_OVR's initialization.
+ SelectViewportIndexInVertexShader(viewIDSymbol->deepCopy(), initializers);
+ }
+
+ // Insert initializers at the beginning of main().
+ TIntermBlock *initializersBlock = new TIntermBlock();
+ initializersBlock->getSequence()->swap(*initializers);
+ TIntermBlock *mainBody = FindMainBody(root);
+ mainBody->getSequence()->insert(mainBody->getSequence()->begin(), initializersBlock);
}
}
diff --git a/src/compiler/translator/DeclareAndInitBuiltinsForInstancedMultiview.h b/src/compiler/translator/DeclareAndInitBuiltinsForInstancedMultiview.h
index b72dc0a..e9dc8fa 100644
--- a/src/compiler/translator/DeclareAndInitBuiltinsForInstancedMultiview.h
+++ b/src/compiler/translator/DeclareAndInitBuiltinsForInstancedMultiview.h
@@ -7,16 +7,21 @@
// - Add declaration of View_ID_OVR.
// - Replace every occurrence of gl_ViewID_OVR with ViewID_OVR, mark ViewID_OVR as internal and
// declare it as a flat varying.
+//
// If the shader type is a vertex shader, the following AST transformations are applied:
// - Replace every occurrence of gl_InstanceID with InstanceID, mark InstanceID as internal and set
// its qualifier to EvqTemporary.
// - 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.
//
#ifndef COMPILER_TRANSLATOR_DECLAREANDINITBUILTINSFORINSTANCEDMULTIVIEW_H_
#define COMPILER_TRANSLATOR_DECLAREANDINITBUILTINSFORINSTANCEDMULTIVIEW_H_
+#include "GLSLANG/ShaderLang.h"
#include "angle_gl.h"
class TIntermBlock;
@@ -26,7 +31,9 @@
void DeclareAndInitBuiltinsForInstancedMultiview(TIntermBlock *root,
unsigned numberOfViews,
- GLenum shaderType);
+ GLenum shaderType,
+ ShCompileOptions compileOptions,
+ ShShaderOutput shaderOutput);
} // namespace sh
diff --git a/src/compiler/translator/TranslatorESSL.cpp b/src/compiler/translator/TranslatorESSL.cpp
index aef369f..b61805d 100644
--- a/src/compiler/translator/TranslatorESSL.cpp
+++ b/src/compiler/translator/TranslatorESSL.cpp
@@ -121,14 +121,16 @@
TInfoSinkBase &sink = getInfoSink().obj;
const TExtensionBehavior &extBehavior = getExtensionBehavior();
const bool isMultiviewExtEmulated =
- (compileOptions & (SH_TRANSLATE_VIEWID_OVR_TO_UNIFORM |
- SH_INITIALIZE_BUILTINS_FOR_INSTANCED_MULTIVIEW)) != 0u;
-
+ (compileOptions &
+ (SH_TRANSLATE_VIEWID_OVR_TO_UNIFORM | SH_INITIALIZE_BUILTINS_FOR_INSTANCED_MULTIVIEW |
+ SH_SELECT_VIEW_IN_NV_GLSL_VERTEX_SHADER)) != 0u;
for (TExtensionBehavior::const_iterator iter = extBehavior.begin(); iter != extBehavior.end();
++iter)
{
if (iter->second != EBhUndefined)
{
+ const bool isMultiview =
+ iter->first == "GL_OVR_multiview" || iter->first == "GL_OVR_multiview2";
if (getResources().NV_shader_framebuffer_fetch &&
iter->first == "GL_EXT_shader_framebuffer_fetch")
{
@@ -140,11 +142,16 @@
sink << "#extension GL_NV_draw_buffers : " << getBehaviorString(iter->second)
<< "\n";
}
- else if (isMultiviewExtEmulated &&
- (iter->first == "GL_OVR_multiview" || iter->first == "GL_OVR_multiview2"))
+ else if (isMultiview && isMultiviewExtEmulated)
{
- // No output
- continue;
+ if (getShaderType() == GL_VERTEX_SHADER &&
+ (compileOptions & SH_SELECT_VIEW_IN_NV_GLSL_VERTEX_SHADER) != 0u)
+ {
+ // Emit the NV_viewport_array2 extension in a vertex shader if the
+ // SH_SELECT_VIEW_IN_NV_GLSL_VERTEX_SHADER option is set and the
+ // OVR_multiview(2) extension is requested.
+ sink << "#extension GL_NV_viewport_array2 : require\n";
+ }
}
else
{
diff --git a/src/compiler/translator/TranslatorGLSL.cpp b/src/compiler/translator/TranslatorGLSL.cpp
index 41abbfc..e45e665 100644
--- a/src/compiler/translator/TranslatorGLSL.cpp
+++ b/src/compiler/translator/TranslatorGLSL.cpp
@@ -53,7 +53,7 @@
writeVersion(root);
// Write extension behaviour as needed
- writeExtensionBehavior(root);
+ writeExtensionBehavior(root, compileOptions);
// Write pragmas after extensions because some drivers consider pragmas
// like non-preprocessor tokens.
@@ -242,7 +242,7 @@
}
}
-void TranslatorGLSL::writeExtensionBehavior(TIntermNode *root)
+void TranslatorGLSL::writeExtensionBehavior(TIntermNode *root, ShCompileOptions compileOptions)
{
TInfoSinkBase &sink = getInfoSink().obj;
const TExtensionBehavior &extBehavior = getExtensionBehavior();
@@ -269,6 +269,17 @@
<< "\n";
}
}
+
+ const bool isMultiview =
+ iter.first == "GL_OVR_multiview" || iter.first == "GL_OVR_multiview2";
+ if (isMultiview && getShaderType() == GL_VERTEX_SHADER &&
+ (compileOptions & SH_SELECT_VIEW_IN_NV_GLSL_VERTEX_SHADER) != 0u)
+ {
+ // Emit the NV_viewport_array2 extension in a vertex shader if the
+ // SH_SELECT_VIEW_IN_NV_GLSL_VERTEX_SHADER option is set and the OVR_multiview(2)
+ // extension is requested.
+ sink << "#extension GL_NV_viewport_array2 : require\n";
+ }
}
// GLSL ES 3 explicit location qualifiers need to use an extension before GLSL 330
diff --git a/src/compiler/translator/TranslatorGLSL.h b/src/compiler/translator/TranslatorGLSL.h
index 9e47db9..335d543 100644
--- a/src/compiler/translator/TranslatorGLSL.h
+++ b/src/compiler/translator/TranslatorGLSL.h
@@ -27,7 +27,7 @@
private:
void writeVersion(TIntermNode *root);
- void writeExtensionBehavior(TIntermNode *root);
+ void writeExtensionBehavior(TIntermNode *root, ShCompileOptions compileOptions);
void conditionallyOutputInvariantDeclaration(const char *builtinVaryingName);
};