Commit c39a19aa by Martin Radev

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
parent 56229f1b
...@@ -231,6 +231,15 @@ const ShCompileOptions SH_INITIALIZE_UNINITIALIZED_LOCALS = UINT64_C(1) << 32; ...@@ -231,6 +231,15 @@ const ShCompileOptions SH_INITIALIZE_UNINITIALIZED_LOCALS = UINT64_C(1) << 32;
// ViewID_OVR is added as a varying variable to both the vertex and fragment shaders. // ViewID_OVR is added as a varying variable to both the vertex and fragment shaders.
const ShCompileOptions SH_INITIALIZE_BUILTINS_FOR_INSTANCED_MULTIVIEW = UINT64_C(1) << 33; const ShCompileOptions SH_INITIALIZE_BUILTINS_FOR_INSTANCED_MULTIVIEW = UINT64_C(1) << 33;
// 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)
// 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;
// Defines alternate strategies for implementing array index clamping. // Defines alternate strategies for implementing array index clamping.
enum ShArrayIndexClampingStrategy enum ShArrayIndexClampingStrategy
{ {
......
...@@ -218,6 +218,7 @@ int main(int argc, char *argv[]) ...@@ -218,6 +218,7 @@ int main(int argc, char *argv[])
case 'm': case 'm':
resources.OVR_multiview = 1; resources.OVR_multiview = 1;
compileOptions |= SH_INITIALIZE_BUILTINS_FOR_INSTANCED_MULTIVIEW; compileOptions |= SH_INITIALIZE_BUILTINS_FOR_INSTANCED_MULTIVIEW;
compileOptions |= SH_SELECT_VIEW_IN_NV_GLSL_VERTEX_SHADER;
break; break;
case 'y': resources.EXT_YUV_target = 1; break; case 'y': resources.EXT_YUV_target = 1; break;
default: failCode = EFailUsage; default: failCode = EFailUsage;
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#include "angle_gl.h" #include "angle_gl.h"
#include "compiler/translator/Compiler.h" #include "compiler/translator/Compiler.h"
#include "compiler/translator/util.h"
using namespace sh; using namespace sh;
...@@ -84,6 +85,14 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) ...@@ -84,6 +85,14 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
return 0; 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; std::vector<uint32_t> validOutputs;
validOutputs.push_back(SH_ESSL_OUTPUT); validOutputs.push_back(SH_ESSL_OUTPUT);
validOutputs.push_back(SH_GLSL_COMPATIBILITY_OUTPUT); validOutputs.push_back(SH_GLSL_COMPATIBILITY_OUTPUT);
...@@ -125,8 +134,8 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) ...@@ -125,8 +134,8 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
if (translators.find(key) == translators.end()) if (translators.find(key) == translators.end())
{ {
UniqueTCompiler translator(ConstructCompiler(type, static_cast<ShShaderSpec>(spec), UniqueTCompiler translator(
static_cast<ShShaderOutput>(output))); ConstructCompiler(type, static_cast<ShShaderSpec>(spec), shaderOutput));
if (translator == nullptr) if (translator == nullptr)
{ {
......
...@@ -537,7 +537,8 @@ enum TQualifier ...@@ -537,7 +537,8 @@ enum TQualifier
EvqSecondaryFragColorEXT, // EXT_blend_func_extended EvqSecondaryFragColorEXT, // EXT_blend_func_extended
EvqSecondaryFragDataEXT, // 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) // built-ins written by the shader_framebuffer_fetch extension(s)
EvqLastFragColor, EvqLastFragColor,
...@@ -774,6 +775,7 @@ inline const char *getQualifierString(TQualifier q) ...@@ -774,6 +775,7 @@ inline const char *getQualifierString(TQualifier q)
case EvqSecondaryFragColorEXT: return "SecondaryFragColorEXT"; case EvqSecondaryFragColorEXT: return "SecondaryFragColorEXT";
case EvqSecondaryFragDataEXT: return "SecondaryFragDataEXT"; case EvqSecondaryFragDataEXT: return "SecondaryFragDataEXT";
case EvqViewIDOVR: return "ViewIDOVR"; case EvqViewIDOVR: return "ViewIDOVR";
case EvqViewportIndex: return "ViewportIndex";
case EvqLastFragColor: return "LastFragColor"; case EvqLastFragColor: return "LastFragColor";
case EvqLastFragData: return "LastFragData"; case EvqLastFragData: return "LastFragData";
case EvqSmoothOut: return "smooth out"; case EvqSmoothOut: return "smooth out";
......
...@@ -431,7 +431,8 @@ TIntermBlock *TCompiler::compileTreeImpl(const char *const shaderStrings[], ...@@ -431,7 +431,8 @@ TIntermBlock *TCompiler::compileTreeImpl(const char *const shaderStrings[],
if (success && (compileOptions & SH_INITIALIZE_BUILTINS_FOR_INSTANCED_MULTIVIEW) && if (success && (compileOptions & SH_INITIALIZE_BUILTINS_FOR_INSTANCED_MULTIVIEW) &&
parseContext.isMultiviewExtensionEnabled() && getShaderType() != GL_COMPUTE_SHADER) 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 // This pass might emit short circuits so keep it before the short circuit unfolding
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include "compiler/translator/InitializeVariables.h" #include "compiler/translator/InitializeVariables.h"
#include "compiler/translator/IntermTraverse.h" #include "compiler/translator/IntermTraverse.h"
#include "compiler/translator/SymbolTable.h" #include "compiler/translator/SymbolTable.h"
#include "compiler/translator/util.h"
namespace sh namespace sh
{ {
...@@ -47,10 +48,11 @@ TIntermSymbol *CreateGLInstanceIDSymbol() ...@@ -47,10 +48,11 @@ TIntermSymbol *CreateGLInstanceIDSymbol()
return new TIntermSymbol(0, "gl_InstanceID", TType(EbtInt, EbpHigh, EvqInstanceID)); return new TIntermSymbol(0, "gl_InstanceID", TType(EbtInt, EbpHigh, EvqInstanceID));
} }
void InitializeViewIDAndInstanceID(TIntermBlock *root, // Adds the InstanceID and ViewID_OVR initializers to the end of the initializers' sequence.
TIntermTyped *viewIDSymbol, void InitializeViewIDAndInstanceID(TIntermTyped *viewIDSymbol,
TIntermTyped *instanceIDSymbol, TIntermTyped *instanceIDSymbol,
unsigned numberOfViews) unsigned numberOfViews,
TIntermSequence *initializers)
{ {
// Create a signed numberOfViews node. // Create a signed numberOfViews node.
TConstantUnion *numberOfViewsConstant = new TConstantUnion(); TConstantUnion *numberOfViewsConstant = new TConstantUnion();
...@@ -65,6 +67,7 @@ void InitializeViewIDAndInstanceID(TIntermBlock *root, ...@@ -65,6 +67,7 @@ void InitializeViewIDAndInstanceID(TIntermBlock *root,
// Create a InstanceID = gl_InstanceID / numberOfViews node. // Create a InstanceID = gl_InstanceID / numberOfViews node.
TIntermBinary *instanceIDInitializer = TIntermBinary *instanceIDInitializer =
new TIntermBinary(EOpAssign, instanceIDSymbol->deepCopy(), normalizedInstanceID); new TIntermBinary(EOpAssign, instanceIDSymbol->deepCopy(), normalizedInstanceID);
initializers->push_back(instanceIDInitializer);
// Create a uint(gl_InstanceID) node. // Create a uint(gl_InstanceID) node.
TIntermSequence *glInstanceIDSymbolCastArguments = new TIntermSequence(); TIntermSequence *glInstanceIDSymbolCastArguments = new TIntermSequence();
...@@ -85,11 +88,7 @@ void InitializeViewIDAndInstanceID(TIntermBlock *root, ...@@ -85,11 +88,7 @@ void InitializeViewIDAndInstanceID(TIntermBlock *root,
// Create a ViewID_OVR = uint(gl_InstanceID) % numberOfViews node. // Create a ViewID_OVR = uint(gl_InstanceID) % numberOfViews node.
TIntermBinary *viewIDInitializer = TIntermBinary *viewIDInitializer =
new TIntermBinary(EOpAssign, viewIDSymbol->deepCopy(), normalizedViewID); new TIntermBinary(EOpAssign, viewIDSymbol->deepCopy(), normalizedViewID);
initializers->push_back(viewIDInitializer);
// 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);
} }
// Replaces every occurrence of a symbol with the name specified in symbolName with newSymbolNode. // Replaces every occurrence of a symbol with the name specified in symbolName with newSymbolNode.
...@@ -108,11 +107,32 @@ void DeclareGlobalVariable(TIntermBlock *root, TIntermTyped *typedNode) ...@@ -108,11 +107,32 @@ void DeclareGlobalVariable(TIntermBlock *root, TIntermTyped *typedNode)
globalSequence->insert(globalSequence->begin(), declaration); 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 } // namespace
void DeclareAndInitBuiltinsForInstancedMultiview(TIntermBlock *root, void DeclareAndInitBuiltinsForInstancedMultiview(TIntermBlock *root,
unsigned numberOfViews, unsigned numberOfViews,
GLenum shaderType) GLenum shaderType,
ShCompileOptions compileOptions,
ShShaderOutput shaderOutput)
{ {
ASSERT(shaderType == GL_VERTEX_SHADER || shaderType == GL_FRAGMENT_SHADER); ASSERT(shaderType == GL_VERTEX_SHADER || shaderType == GL_FRAGMENT_SHADER);
...@@ -132,7 +152,28 @@ void DeclareAndInitBuiltinsForInstancedMultiview(TIntermBlock *root, ...@@ -132,7 +152,28 @@ void DeclareAndInitBuiltinsForInstancedMultiview(TIntermBlock *root,
instanceIDSymbol->setInternal(true); instanceIDSymbol->setInternal(true);
DeclareGlobalVariable(root, instanceIDSymbol); DeclareGlobalVariable(root, instanceIDSymbol);
ReplaceSymbol(root, "gl_InstanceID", 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);
} }
} }
......
...@@ -7,16 +7,21 @@ ...@@ -7,16 +7,21 @@
// - Add declaration of View_ID_OVR. // - Add declaration of View_ID_OVR.
// - Replace every occurrence of gl_ViewID_OVR with ViewID_OVR, mark ViewID_OVR as internal and // - Replace every occurrence of gl_ViewID_OVR with ViewID_OVR, mark ViewID_OVR as internal and
// declare it as a flat varying. // declare it as a flat varying.
//
// If the shader type is a vertex shader, the following AST transformations are applied: // 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 // - Replace every occurrence of gl_InstanceID with InstanceID, mark InstanceID as internal and set
// its qualifier to EvqTemporary. // its qualifier to EvqTemporary.
// - Add initializers of ViewID_OVR and InstanceID to the beginning of the body of main. The pass // - 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. // 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_ #ifndef COMPILER_TRANSLATOR_DECLAREANDINITBUILTINSFORINSTANCEDMULTIVIEW_H_
#define COMPILER_TRANSLATOR_DECLAREANDINITBUILTINSFORINSTANCEDMULTIVIEW_H_ #define COMPILER_TRANSLATOR_DECLAREANDINITBUILTINSFORINSTANCEDMULTIVIEW_H_
#include "GLSLANG/ShaderLang.h"
#include "angle_gl.h" #include "angle_gl.h"
class TIntermBlock; class TIntermBlock;
...@@ -26,7 +31,9 @@ namespace sh ...@@ -26,7 +31,9 @@ namespace sh
void DeclareAndInitBuiltinsForInstancedMultiview(TIntermBlock *root, void DeclareAndInitBuiltinsForInstancedMultiview(TIntermBlock *root,
unsigned numberOfViews, unsigned numberOfViews,
GLenum shaderType); GLenum shaderType,
ShCompileOptions compileOptions,
ShShaderOutput shaderOutput);
} // namespace sh } // namespace sh
......
...@@ -121,14 +121,16 @@ void TranslatorESSL::writeExtensionBehavior(ShCompileOptions compileOptions) ...@@ -121,14 +121,16 @@ void TranslatorESSL::writeExtensionBehavior(ShCompileOptions compileOptions)
TInfoSinkBase &sink = getInfoSink().obj; TInfoSinkBase &sink = getInfoSink().obj;
const TExtensionBehavior &extBehavior = getExtensionBehavior(); const TExtensionBehavior &extBehavior = getExtensionBehavior();
const bool isMultiviewExtEmulated = const bool isMultiviewExtEmulated =
(compileOptions & (SH_TRANSLATE_VIEWID_OVR_TO_UNIFORM | (compileOptions &
SH_INITIALIZE_BUILTINS_FOR_INSTANCED_MULTIVIEW)) != 0u; (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(); for (TExtensionBehavior::const_iterator iter = extBehavior.begin(); iter != extBehavior.end();
++iter) ++iter)
{ {
if (iter->second != EBhUndefined) if (iter->second != EBhUndefined)
{ {
const bool isMultiview =
iter->first == "GL_OVR_multiview" || iter->first == "GL_OVR_multiview2";
if (getResources().NV_shader_framebuffer_fetch && if (getResources().NV_shader_framebuffer_fetch &&
iter->first == "GL_EXT_shader_framebuffer_fetch") iter->first == "GL_EXT_shader_framebuffer_fetch")
{ {
...@@ -140,11 +142,16 @@ void TranslatorESSL::writeExtensionBehavior(ShCompileOptions compileOptions) ...@@ -140,11 +142,16 @@ void TranslatorESSL::writeExtensionBehavior(ShCompileOptions compileOptions)
sink << "#extension GL_NV_draw_buffers : " << getBehaviorString(iter->second) sink << "#extension GL_NV_draw_buffers : " << getBehaviorString(iter->second)
<< "\n"; << "\n";
} }
else if (isMultiviewExtEmulated && else if (isMultiview && isMultiviewExtEmulated)
(iter->first == "GL_OVR_multiview" || iter->first == "GL_OVR_multiview2"))
{ {
// No output if (getShaderType() == GL_VERTEX_SHADER &&
continue; (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 else
{ {
......
...@@ -53,7 +53,7 @@ void TranslatorGLSL::translate(TIntermBlock *root, ShCompileOptions compileOptio ...@@ -53,7 +53,7 @@ void TranslatorGLSL::translate(TIntermBlock *root, ShCompileOptions compileOptio
writeVersion(root); writeVersion(root);
// Write extension behaviour as needed // Write extension behaviour as needed
writeExtensionBehavior(root); writeExtensionBehavior(root, compileOptions);
// Write pragmas after extensions because some drivers consider pragmas // Write pragmas after extensions because some drivers consider pragmas
// like non-preprocessor tokens. // like non-preprocessor tokens.
...@@ -242,7 +242,7 @@ void TranslatorGLSL::writeVersion(TIntermNode *root) ...@@ -242,7 +242,7 @@ void TranslatorGLSL::writeVersion(TIntermNode *root)
} }
} }
void TranslatorGLSL::writeExtensionBehavior(TIntermNode *root) void TranslatorGLSL::writeExtensionBehavior(TIntermNode *root, ShCompileOptions compileOptions)
{ {
TInfoSinkBase &sink = getInfoSink().obj; TInfoSinkBase &sink = getInfoSink().obj;
const TExtensionBehavior &extBehavior = getExtensionBehavior(); const TExtensionBehavior &extBehavior = getExtensionBehavior();
...@@ -269,6 +269,17 @@ void TranslatorGLSL::writeExtensionBehavior(TIntermNode *root) ...@@ -269,6 +269,17 @@ void TranslatorGLSL::writeExtensionBehavior(TIntermNode *root)
<< "\n"; << "\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 // GLSL ES 3 explicit location qualifiers need to use an extension before GLSL 330
......
...@@ -27,7 +27,7 @@ class TranslatorGLSL : public TCompiler ...@@ -27,7 +27,7 @@ class TranslatorGLSL : public TCompiler
private: private:
void writeVersion(TIntermNode *root); void writeVersion(TIntermNode *root);
void writeExtensionBehavior(TIntermNode *root); void writeExtensionBehavior(TIntermNode *root, ShCompileOptions compileOptions);
void conditionallyOutputInvariantDeclaration(const char *builtinVaryingName); void conditionallyOutputInvariantDeclaration(const char *builtinVaryingName);
}; };
......
...@@ -116,22 +116,28 @@ class WEBGLMultiviewFragmentShaderTest : public ShaderCompileTreeTest ...@@ -116,22 +116,28 @@ class WEBGLMultiviewFragmentShaderTest : public ShaderCompileTreeTest
} }
}; };
class WEBGLMultiviewVertexShaderOutputCodeTest : public MatchOutputCodeTest class WEBGLMultiviewOutputCodeTest : public MatchOutputCodeTest
{ {
public: public:
WEBGLMultiviewVertexShaderOutputCodeTest() WEBGLMultiviewOutputCodeTest(sh::GLenum shaderType)
: MatchOutputCodeTest(GL_VERTEX_SHADER, 0, SH_ESSL_OUTPUT) : MatchOutputCodeTest(shaderType, 0, SH_ESSL_OUTPUT)
{ {
addOutputType(SH_GLSL_COMPATIBILITY_OUTPUT); addOutputType(SH_GLSL_COMPATIBILITY_OUTPUT);
getResources()->OVR_multiview = 1;
getResources()->MaxViewsOVR = 4;
}
void requestHLSLOutput()
{
#if defined(ANGLE_ENABLE_HLSL) #if defined(ANGLE_ENABLE_HLSL)
addOutputType(SH_HLSL_4_1_OUTPUT); addOutputType(SH_HLSL_4_1_OUTPUT);
#endif #endif
getResources()->OVR_multiview = 1;
getResources()->MaxViewsOVR = 4;
} }
bool foundInAllGLSLCode(const char *str) bool foundInAllGLSLCode(const char *str)
{ {
return foundInCode(SH_GLSL_COMPATIBILITY_OUTPUT, str) && foundInCode(SH_ESSL_OUTPUT, str); return foundInGLSLCode(str) && foundInESSLCode(str);
} }
bool foundInHLSLCode(const char *stringToFind) const bool foundInHLSLCode(const char *stringToFind) const
...@@ -144,6 +150,26 @@ class WEBGLMultiviewVertexShaderOutputCodeTest : public MatchOutputCodeTest ...@@ -144,6 +150,26 @@ class WEBGLMultiviewVertexShaderOutputCodeTest : public MatchOutputCodeTest
} }
}; };
class WEBGLMultiviewVertexShaderOutputCodeTest : public WEBGLMultiviewOutputCodeTest
{
public:
WEBGLMultiviewVertexShaderOutputCodeTest() : WEBGLMultiviewOutputCodeTest(GL_VERTEX_SHADER) {}
};
class WEBGLMultiviewFragmentShaderOutputCodeTest : public WEBGLMultiviewOutputCodeTest
{
public:
WEBGLMultiviewFragmentShaderOutputCodeTest() : WEBGLMultiviewOutputCodeTest(GL_FRAGMENT_SHADER)
{
}
};
class WEBGLMultiviewComputeShaderOutputCodeTest : public WEBGLMultiviewOutputCodeTest
{
public:
WEBGLMultiviewComputeShaderOutputCodeTest() : WEBGLMultiviewOutputCodeTest(GL_COMPUTE_SHADER) {}
};
void VariableOccursNTimes(TIntermBlock *root, void VariableOccursNTimes(TIntermBlock *root,
const TString &varName, const TString &varName,
const TQualifier varQualifier, const TQualifier varQualifier,
...@@ -723,6 +749,7 @@ TEST_F(WEBGLMultiviewVertexShaderOutputCodeTest, ViewIDAndInstanceIDHaveCorrectV ...@@ -723,6 +749,7 @@ TEST_F(WEBGLMultiviewVertexShaderOutputCodeTest, ViewIDAndInstanceIDHaveCorrectV
" gl_Position.yzw = vec3(0., 0., 1.);\n" " gl_Position.yzw = vec3(0., 0., 1.);\n"
" myInstance = gl_InstanceID;\n" " myInstance = gl_InstanceID;\n"
"}\n"; "}\n";
requestHLSLOutput();
compile(shaderString, SH_INITIALIZE_BUILTINS_FOR_INSTANCED_MULTIVIEW); compile(shaderString, SH_INITIALIZE_BUILTINS_FOR_INSTANCED_MULTIVIEW);
EXPECT_TRUE(foundInAllGLSLCode("webgl_angle_ViewID_OVR = (uint(gl_InstanceID) % 3u)")); EXPECT_TRUE(foundInAllGLSLCode("webgl_angle_ViewID_OVR = (uint(gl_InstanceID) % 3u)"));
...@@ -810,4 +837,98 @@ TEST_F(WEBGLMultiviewVertexShaderTest, ViewIDDeclaredAsFlatOutput) ...@@ -810,4 +837,98 @@ TEST_F(WEBGLMultiviewVertexShaderTest, ViewIDDeclaredAsFlatOutput)
VariableOccursNTimes(mASTRoot, "ViewID_OVR", EvqFlatOut, 2u); VariableOccursNTimes(mASTRoot, "ViewID_OVR", EvqFlatOut, 2u);
} }
} // namespace // The test checks that the GL_NV_viewport_array2 extension is emitted in a vertex shader if the
// SH_SELECT_VIEW_IN_NV_GLSL_VERTEX_SHADER option is set.
TEST_F(WEBGLMultiviewVertexShaderOutputCodeTest, ViewportArray2IsEmitted)
{
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);
EXPECT_TRUE(foundInAllGLSLCode("#extension GL_NV_viewport_array2 : require"));
}
// The test checks that the GL_NV_viewport_array2 extension is not emitted in a vertex shader if the
// OVR_multiview extension is not requested in the shader source even if the
// SH_SELECT_VIEW_IN_NV_GLSL_VERTEX_SHADER option is set.
TEST_F(WEBGLMultiviewVertexShaderOutputCodeTest, ViewportArray2IsNotEmitted)
{
const std::string &shaderString =
"#version 300 es\n"
"void main()\n"
"{\n"
"}\n";
compile(shaderString, SH_INITIALIZE_BUILTINS_FOR_INSTANCED_MULTIVIEW |
SH_SELECT_VIEW_IN_NV_GLSL_VERTEX_SHADER);
EXPECT_FALSE(foundInGLSLCode("#extension GL_NV_viewport_array2"));
EXPECT_FALSE(foundInESSLCode("#extension GL_NV_viewport_array2"));
}
// The test checks that the GL_NV_viewport_array2 extension is not emitted in a fragment shader if
// the SH_SELECT_VIEW_IN_NV_GLSL_VERTEX_SHADER option is set.
TEST_F(WEBGLMultiviewFragmentShaderOutputCodeTest, ViewportArray2IsNotEmitted)
{
const std::string &shaderString =
"#version 300 es\n"
"#extension GL_OVR_multiview : require\n"
"void main()\n"
"{\n"
"}\n";
compile(shaderString, SH_INITIALIZE_BUILTINS_FOR_INSTANCED_MULTIVIEW |
SH_SELECT_VIEW_IN_NV_GLSL_VERTEX_SHADER);
EXPECT_FALSE(foundInGLSLCode("#extension GL_NV_viewport_array2"));
EXPECT_FALSE(foundInESSLCode("#extension GL_NV_viewport_array2"));
}
// The test checks that the GL_NV_viewport_array2 extension is not emitted in a compute shader if
// the SH_SELECT_VIEW_IN_NV_GLSL_VERTEX_SHADER option is set.
TEST_F(WEBGLMultiviewComputeShaderOutputCodeTest, ViewportArray2IsNotEmitted)
{
const std::string &shaderString =
"#version 300 es\n"
"#extension GL_OVR_multiview : require\n"
"void main()\n"
"{\n"
"}\n";
compile(shaderString, SH_INITIALIZE_BUILTINS_FOR_INSTANCED_MULTIVIEW |
SH_SELECT_VIEW_IN_NV_GLSL_VERTEX_SHADER);
EXPECT_FALSE(foundInGLSLCode("#extension GL_NV_viewport_array2"));
EXPECT_FALSE(foundInESSLCode("#extension GL_NV_viewport_array2"));
}
// The test checks that the viewport index is selected after the initialization of ViewID_OVR for
// GLSL and ESSL ouputs.
TEST_F(WEBGLMultiviewVertexShaderOutputCodeTest, GlViewportIndexIsSet)
{
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 glViewportIndexAssignment[] = "gl_ViewportIndex = int(webgl_angle_ViewID_OVR)";
// Check that the viewport index is selected.
EXPECT_TRUE(foundInAllGLSLCode(glViewportIndexAssignment));
// Setting gl_ViewportIndex 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 glViewportIndexAssignmentLoc =
findInCode(SH_GLSL_COMPATIBILITY_OUTPUT, glViewportIndexAssignment);
EXPECT_LT(viewIDOVRAssignmentLoc, glViewportIndexAssignmentLoc);
viewIDOVRAssignmentLoc = findInCode(SH_ESSL_OUTPUT, viewIDOVRAssignment);
glViewportIndexAssignmentLoc = findInCode(SH_ESSL_OUTPUT, glViewportIndexAssignment);
EXPECT_LT(viewIDOVRAssignmentLoc, glViewportIndexAssignmentLoc);
}
} // 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