Commit 09b04a2f by Olli Etuaho Committed by Commit Bot

Add shader translator support for OVR_multiview

The OVR_multiview and OVR_multiview2 extensions add gl_ViewID_OVR to shaders. gl_ViewID_OVR can be translated either as is in GLSL output or as a uniform by setting the SH_TRANSLATE_VIEWID_OVR_AS_UNIFORM compiler flag. If WebGL output is selected, the shaders will be validated according to proposed rules in the WEBGL_multiview spec. BUG=angleproject:1669 TEST=angle_unittests Change-Id: I19ea3a6c8b4edb78be03f1a50a96bfef018870d0 Reviewed-on: https://chromium-review.googlesource.com/422848Reviewed-by: 's avatarCorentin Wallez <cwallez@chromium.org> Commit-Queue: Olli Etuaho <oetuaho@nvidia.com>
parent b58e9bac
...@@ -25,7 +25,7 @@ ...@@ -25,7 +25,7 @@
// Version number for shader translation API. // Version number for shader translation API.
// It is incremented every time the API changes. // It is incremented every time the API changes.
#define ANGLE_SH_VERSION 169 #define ANGLE_SH_VERSION 170
enum ShShaderSpec enum ShShaderSpec
{ {
...@@ -214,6 +214,10 @@ const ShCompileOptions SH_REWRITE_FLOAT_UNARY_MINUS_OPERATOR = UINT64_C(1) << 29 ...@@ -214,6 +214,10 @@ const ShCompileOptions SH_REWRITE_FLOAT_UNARY_MINUS_OPERATOR = UINT64_C(1) << 29
// It works by using an expression to emulate this function. // It works by using an expression to emulate this function.
const ShCompileOptions SH_EMULATE_ATAN2_FLOAT_FUNCTION = UINT64_C(1) << 30; const ShCompileOptions SH_EMULATE_ATAN2_FLOAT_FUNCTION = UINT64_C(1) << 30;
// Set to 1 to translate gl_ViewID_OVR to an uniform so that the extension can be emulated.
// "uniform highp uint webgl_angle_ViewID_OVR".
const ShCompileOptions SH_TRANSLATE_VIEWID_OVR_TO_UNIFORM = UINT64_C(1) << 31;
// Defines alternate strategies for implementing array index clamping. // Defines alternate strategies for implementing array index clamping.
enum ShArrayIndexClampingStrategy enum ShArrayIndexClampingStrategy
{ {
...@@ -259,6 +263,7 @@ struct ShBuiltInResources ...@@ -259,6 +263,7 @@ struct ShBuiltInResources
int EXT_shader_framebuffer_fetch; int EXT_shader_framebuffer_fetch;
int NV_shader_framebuffer_fetch; int NV_shader_framebuffer_fetch;
int ARM_shader_framebuffer_fetch; int ARM_shader_framebuffer_fetch;
int OVR_multiview;
// Set to 1 to enable replacing GL_EXT_draw_buffers #extension directives // Set to 1 to enable replacing GL_EXT_draw_buffers #extension directives
// with GL_NV_draw_buffers in ESSL output. This flag can be used to emulate // with GL_NV_draw_buffers in ESSL output. This flag can be used to emulate
...@@ -285,6 +290,9 @@ struct ShBuiltInResources ...@@ -285,6 +290,9 @@ struct ShBuiltInResources
// GLES SL version 100 gl_MaxDualSourceDrawBuffersEXT value for EXT_blend_func_extended. // GLES SL version 100 gl_MaxDualSourceDrawBuffersEXT value for EXT_blend_func_extended.
int MaxDualSourceDrawBuffers; int MaxDualSourceDrawBuffers;
// Value of GL_MAX_VIEWS_OVR.
int MaxViewsOVR;
// Name Hashing. // Name Hashing.
// Set a 64 bit hash function to enable user-defined name hashing. // Set a 64 bit hash function to enable user-defined name hashing.
// Default is NULL. // Default is NULL.
...@@ -488,6 +496,7 @@ const std::vector<sh::Attribute> *ShGetAttributes(const ShHandle handle); ...@@ -488,6 +496,7 @@ const std::vector<sh::Attribute> *ShGetAttributes(const ShHandle handle);
const std::vector<sh::OutputVariable> *ShGetOutputVariables(const ShHandle handle); const std::vector<sh::OutputVariable> *ShGetOutputVariables(const ShHandle handle);
const std::vector<sh::InterfaceBlock> *ShGetInterfaceBlocks(const ShHandle handle); const std::vector<sh::InterfaceBlock> *ShGetInterfaceBlocks(const ShHandle handle);
sh::WorkGroupSize ShGetComputeShaderLocalGroupSize(const ShHandle handle); sh::WorkGroupSize ShGetComputeShaderLocalGroupSize(const ShHandle handle);
int ShGetVertexShaderNumViews(const ShHandle handle);
// Returns true if the passed in variables pack in maxVectors following // Returns true if the passed in variables pack in maxVectors following
// the packing rules from the GLSL 1.017 spec, Appendix A, section 7. // the packing rules from the GLSL 1.017 spec, Appendix A, section 7.
...@@ -629,6 +638,7 @@ const std::vector<sh::Attribute> *GetAttributes(const ShHandle handle); ...@@ -629,6 +638,7 @@ const std::vector<sh::Attribute> *GetAttributes(const ShHandle handle);
const std::vector<sh::OutputVariable> *GetOutputVariables(const ShHandle handle); const std::vector<sh::OutputVariable> *GetOutputVariables(const ShHandle handle);
const std::vector<sh::InterfaceBlock> *GetInterfaceBlocks(const ShHandle handle); const std::vector<sh::InterfaceBlock> *GetInterfaceBlocks(const ShHandle handle);
sh::WorkGroupSize GetComputeShaderLocalGroupSize(const ShHandle handle); sh::WorkGroupSize GetComputeShaderLocalGroupSize(const ShHandle handle);
int GetVertexShaderNumViews(const ShHandle handle);
// Returns true if the passed in variables pack in maxVectors followingthe packing rules from the // Returns true if the passed in variables pack in maxVectors followingthe packing rules from the
// GLSL 1.017 spec, Appendix A, section 7. // GLSL 1.017 spec, Appendix A, section 7.
......
...@@ -205,6 +205,10 @@ int main(int argc, char *argv[]) ...@@ -205,6 +205,10 @@ int main(int argc, char *argv[])
case 'f': resources.EXT_shader_framebuffer_fetch = 1; break; case 'f': resources.EXT_shader_framebuffer_fetch = 1; break;
case 'n': resources.NV_shader_framebuffer_fetch = 1; break; case 'n': resources.NV_shader_framebuffer_fetch = 1; break;
case 'a': resources.ARM_shader_framebuffer_fetch = 1; break; case 'a': resources.ARM_shader_framebuffer_fetch = 1; break;
case 'm':
resources.OVR_multiview = 1;
compileOptions |= SH_TRANSLATE_VIEWID_OVR_TO_UNIFORM;
break;
default: failCode = EFailUsage; default: failCode = EFailUsage;
} }
// clang-format on // clang-format on
...@@ -339,7 +343,8 @@ void usage() ...@@ -339,7 +343,8 @@ void usage()
" -x=l : enable EXT_shader_texture_lod\n" " -x=l : enable EXT_shader_texture_lod\n"
" -x=f : enable EXT_shader_framebuffer_fetch\n" " -x=f : enable EXT_shader_framebuffer_fetch\n"
" -x=n : enable NV_shader_framebuffer_fetch\n" " -x=n : enable NV_shader_framebuffer_fetch\n"
" -x=a : enable ARM_shader_framebuffer_fetch\n"); " -x=a : enable ARM_shader_framebuffer_fetch\n"
" -x=m : enable OVR_multiview\n");
// clang-format on // clang-format on
} }
......
...@@ -52,6 +52,8 @@ ...@@ -52,6 +52,8 @@
'compiler/translator/ExpandIntegerPowExpressions.cpp', 'compiler/translator/ExpandIntegerPowExpressions.cpp',
'compiler/translator/ExpandIntegerPowExpressions.h', 'compiler/translator/ExpandIntegerPowExpressions.h',
'compiler/translator/ExtensionBehavior.h', 'compiler/translator/ExtensionBehavior.h',
'compiler/translator/FindSymbolNode.cpp',
'compiler/translator/FindSymbolNode.h',
'compiler/translator/FlagStd140Structs.cpp', 'compiler/translator/FlagStd140Structs.cpp',
'compiler/translator/FlagStd140Structs.h', 'compiler/translator/FlagStd140Structs.h',
'compiler/translator/HashNames.h', 'compiler/translator/HashNames.h',
...@@ -120,6 +122,8 @@ ...@@ -120,6 +122,8 @@
'compiler/translator/ValidateLimitations.h', 'compiler/translator/ValidateLimitations.h',
'compiler/translator/ValidateMaxParameters.h', 'compiler/translator/ValidateMaxParameters.h',
'compiler/translator/ValidateMaxParameters.cpp', 'compiler/translator/ValidateMaxParameters.cpp',
'compiler/translator/ValidateMultiviewWebGL.cpp',
'compiler/translator/ValidateMultiviewWebGL.h',
'compiler/translator/ValidateOutputs.cpp', 'compiler/translator/ValidateOutputs.cpp',
'compiler/translator/ValidateOutputs.h', 'compiler/translator/ValidateOutputs.h',
'compiler/translator/ValidateSwitch.cpp', 'compiler/translator/ValidateSwitch.cpp',
......
...@@ -488,6 +488,8 @@ enum TQualifier ...@@ -488,6 +488,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
// built-ins written by the shader_framebuffer_fetch extension(s) // built-ins written by the shader_framebuffer_fetch extension(s)
EvqLastFragColor, EvqLastFragColor,
EvqLastFragData, EvqLastFragData,
...@@ -575,6 +577,9 @@ struct TLayoutQualifier ...@@ -575,6 +577,9 @@ struct TLayoutQualifier
// Image format layout qualifier // Image format layout qualifier
TLayoutImageInternalFormat imageInternalFormat; TLayoutImageInternalFormat imageInternalFormat;
// OVR_multiview num_views.
int numViews;
static TLayoutQualifier create() static TLayoutQualifier create()
{ {
TLayoutQualifier layoutQualifier; TLayoutQualifier layoutQualifier;
...@@ -585,6 +590,7 @@ struct TLayoutQualifier ...@@ -585,6 +590,7 @@ struct TLayoutQualifier
layoutQualifier.blockStorage = EbsUnspecified; layoutQualifier.blockStorage = EbsUnspecified;
layoutQualifier.localSize.fill(-1); layoutQualifier.localSize.fill(-1);
layoutQualifier.numViews = -1;
layoutQualifier.imageInternalFormat = EiifUnspecified; layoutQualifier.imageInternalFormat = EiifUnspecified;
return layoutQualifier; return layoutQualifier;
...@@ -592,7 +598,7 @@ struct TLayoutQualifier ...@@ -592,7 +598,7 @@ struct TLayoutQualifier
bool isEmpty() const bool isEmpty() const
{ {
return location == -1 && matrixPacking == EmpUnspecified && return location == -1 && numViews == -1 && matrixPacking == EmpUnspecified &&
blockStorage == EbsUnspecified && !localSize.isAnyValueSet() && blockStorage == EbsUnspecified && !localSize.isAnyValueSet() &&
imageInternalFormat == EiifUnspecified; imageInternalFormat == EiifUnspecified;
} }
...@@ -600,12 +606,16 @@ struct TLayoutQualifier ...@@ -600,12 +606,16 @@ struct TLayoutQualifier
bool isCombinationValid() const bool isCombinationValid() const
{ {
bool workSizeSpecified = localSize.isAnyValueSet(); bool workSizeSpecified = localSize.isAnyValueSet();
bool numViewsSet = (numViews != -1);
bool otherLayoutQualifiersSpecified = bool otherLayoutQualifiersSpecified =
(location != -1 || matrixPacking != EmpUnspecified || blockStorage != EbsUnspecified || (location != -1 || matrixPacking != EmpUnspecified || blockStorage != EbsUnspecified ||
imageInternalFormat != EiifUnspecified); imageInternalFormat != EiifUnspecified);
// we can have either the work group size specified, or the other layout qualifiers // we can have either the work group size specified, or number of views, or the other layout
return !(workSizeSpecified && otherLayoutQualifiersSpecified); // qualifiers.
return (workSizeSpecified ? 1 : 0) + (numViewsSet ? 1 : 0) +
(otherLayoutQualifiersSpecified ? 1 : 0) <=
1;
} }
bool isLocalSizeEqual(const sh::WorkGroupSize &localSizeIn) const bool isLocalSizeEqual(const sh::WorkGroupSize &localSizeIn) const
...@@ -697,6 +707,7 @@ inline const char *getQualifierString(TQualifier q) ...@@ -697,6 +707,7 @@ inline const char *getQualifierString(TQualifier q)
case EvqFragDepth: return "FragDepth"; case EvqFragDepth: return "FragDepth";
case EvqSecondaryFragColorEXT: return "SecondaryFragColorEXT"; case EvqSecondaryFragColorEXT: return "SecondaryFragColorEXT";
case EvqSecondaryFragDataEXT: return "SecondaryFragDataEXT"; case EvqSecondaryFragDataEXT: return "SecondaryFragDataEXT";
case EvqViewIDOVR: return "ViewIDOVR";
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";
......
...@@ -30,6 +30,7 @@ ...@@ -30,6 +30,7 @@
#include "compiler/translator/UseInterfaceBlockFields.h" #include "compiler/translator/UseInterfaceBlockFields.h"
#include "compiler/translator/ValidateLimitations.h" #include "compiler/translator/ValidateLimitations.h"
#include "compiler/translator/ValidateMaxParameters.h" #include "compiler/translator/ValidateMaxParameters.h"
#include "compiler/translator/ValidateMultiviewWebGL.h"
#include "compiler/translator/ValidateOutputs.h" #include "compiler/translator/ValidateOutputs.h"
#include "compiler/translator/VariablePacker.h" #include "compiler/translator/VariablePacker.h"
#include "third_party/compiler/ArrayBoundsClamper.h" #include "third_party/compiler/ArrayBoundsClamper.h"
...@@ -320,11 +321,22 @@ TIntermBlock *TCompiler::compileTreeImpl(const char *const shaderStrings[], ...@@ -320,11 +321,22 @@ TIntermBlock *TCompiler::compileTreeImpl(const char *const shaderStrings[],
mComputeShaderLocalSizeDeclared = parseContext.isComputeShaderLocalSizeDeclared(); mComputeShaderLocalSizeDeclared = parseContext.isComputeShaderLocalSizeDeclared();
mComputeShaderLocalSize = parseContext.getComputeShaderLocalSize(); mComputeShaderLocalSize = parseContext.getComputeShaderLocalSize();
mNumViews = parseContext.getNumViews();
root = parseContext.getTreeRoot(); root = parseContext.getTreeRoot();
// Highp might have been auto-enabled based on shader version // Highp might have been auto-enabled based on shader version
fragmentPrecisionHigh = parseContext.getFragmentPrecisionHigh(); fragmentPrecisionHigh = parseContext.getFragmentPrecisionHigh();
if (success && (IsWebGLBasedSpec(shaderSpec) &&
IsExtensionEnabled(extensionBehavior, "GL_OVR_multiview") &&
IsExtensionEnabled(extensionBehavior, "GL_OVR_multiview2")))
{
// Can't enable both extensions at the same time.
mDiagnostics.globalError("Can't enable both OVR_multiview and OVR_multiview2");
success = false;
}
// Disallow expressions deemed too complex. // Disallow expressions deemed too complex.
if (success && (compileOptions & SH_LIMIT_EXPRESSION_COMPLEXITY)) if (success && (compileOptions & SH_LIMIT_EXPRESSION_COMPLEXITY))
success = limitExpressionComplexity(root); success = limitExpressionComplexity(root);
...@@ -358,6 +370,11 @@ TIntermBlock *TCompiler::compileTreeImpl(const char *const shaderStrings[], ...@@ -358,6 +370,11 @@ TIntermBlock *TCompiler::compileTreeImpl(const char *const shaderStrings[],
if (success && shouldRunLoopAndIndexingValidation(compileOptions)) if (success && shouldRunLoopAndIndexingValidation(compileOptions))
success = validateLimitations(root); success = validateLimitations(root);
bool multiview2 = IsExtensionEnabled(extensionBehavior, "GL_OVR_multiview2");
if (success && compileResources.OVR_multiview && IsWebGLBasedSpec(shaderSpec) &&
(IsExtensionEnabled(extensionBehavior, "GL_OVR_multiview") || multiview2))
success = ValidateMultiviewWebGL(root, shaderType, multiview2, &mDiagnostics);
// Fail compilation if precision emulation not supported. // Fail compilation if precision emulation not supported.
if (success && getResources().WEBGL_debug_shader_precision && if (success && getResources().WEBGL_debug_shader_precision &&
getPragma().debugShaderPrecision) getPragma().debugShaderPrecision)
...@@ -650,6 +667,8 @@ void TCompiler::clearResults() ...@@ -650,6 +667,8 @@ void TCompiler::clearResults()
interfaceBlocks.clear(); interfaceBlocks.clear();
variablesCollected = false; variablesCollected = false;
mNumViews = -1;
builtInFunctionEmulator.Cleanup(); builtInFunctionEmulator.Cleanup();
nameMap.clear(); nameMap.clear();
......
...@@ -101,7 +101,8 @@ class TCompiler : public TShHandleBase ...@@ -101,7 +101,8 @@ class TCompiler : public TShHandleBase
TInfoSink &getInfoSink() { return infoSink; } TInfoSink &getInfoSink() { return infoSink; }
bool isComputeShaderLocalSizeDeclared() const { return mComputeShaderLocalSizeDeclared; } bool isComputeShaderLocalSizeDeclared() const { return mComputeShaderLocalSizeDeclared; }
const sh::WorkGroupSize &getComputeShaderLocalSize() { return mComputeShaderLocalSize; } const sh::WorkGroupSize &getComputeShaderLocalSize() const { return mComputeShaderLocalSize; }
int getNumViews() const { return mNumViews; }
// Clears the results from the previous compilation. // Clears the results from the previous compilation.
void clearResults(); void clearResults();
...@@ -247,6 +248,9 @@ class TCompiler : public TShHandleBase ...@@ -247,6 +248,9 @@ class TCompiler : public TShHandleBase
bool mComputeShaderLocalSizeDeclared; bool mComputeShaderLocalSizeDeclared;
sh::WorkGroupSize mComputeShaderLocalSize; sh::WorkGroupSize mComputeShaderLocalSize;
// GL_OVR_multiview num_views.
int mNumViews;
// name hashing. // name hashing.
ShHashFunction64 hashFunction; ShHashFunction64 hashFunction;
NameMap nameMap; NameMap nameMap;
......
//
// Copyright (c) 2015 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// FindSymbol.cpp:
// Utility for finding a symbol node inside an AST tree.
#include "compiler/translator/FindSymbolNode.h"
#include "compiler/translator/IntermNode.h"
namespace sh
{
namespace
{
class SymbolFinder : public TIntermTraverser
{
public:
SymbolFinder(const TString &symbolName, TBasicType basicType)
: TIntermTraverser(true, false, false),
mSymbolName(symbolName),
mNodeFound(nullptr),
mBasicType(basicType)
{
}
void visitSymbol(TIntermSymbol *node)
{
if (node->getBasicType() == mBasicType && node->getSymbol() == mSymbolName)
{
mNodeFound = node;
}
}
bool isFound() const { return mNodeFound != nullptr; }
const TIntermSymbol *getNode() const { return mNodeFound; }
private:
TString mSymbolName;
TIntermSymbol *mNodeFound;
TBasicType mBasicType;
};
} // anonymous namespace
const TIntermSymbol *FindSymbolNode(TIntermNode *root,
const TString &symbolName,
TBasicType basicType)
{
SymbolFinder finder(symbolName, basicType);
root->traverse(&finder);
return finder.getNode();
}
} // namespace sh
//
// Copyright (c) 2015 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// FindSymbolNode.h:
// Utility for finding a symbol node inside an AST tree.
#ifndef COMPILER_TRANSLATOR_FIND_SYMBOL_H_
#define COMPILER_TRANSLATOR_FIND_SYMBOL_H_
#include "compiler/translator/BaseTypes.h"
#include "compiler/translator/Common.h"
namespace sh
{
class TIntermNode;
class TIntermSymbol;
const TIntermSymbol *FindSymbolNode(TIntermNode *root,
const TString &symbolName,
TBasicType basicType);
} // namespace sh
#endif // COMPILER_TRANSLATOR_FIND_SYMBOL_H_
\ No newline at end of file
...@@ -706,6 +706,14 @@ void IdentifyBuiltIns(sh::GLenum type, ...@@ -706,6 +706,14 @@ void IdentifyBuiltIns(sh::GLenum type,
// Insert some special built-in variables that are not in // Insert some special built-in variables that are not in
// the built-in header files. // the built-in header files.
// //
if (resources.OVR_multiview && type != GL_COMPUTE_SHADER)
{
symbolTable.insert(COMMON_BUILTINS, "GL_OVR_multiview",
new TVariable(NewPoolTString("gl_ViewID_OVR"),
TType(EbtUInt, EbpHigh, EvqViewIDOVR, 1)));
}
switch (type) switch (type)
{ {
case GL_FRAGMENT_SHADER: case GL_FRAGMENT_SHADER:
...@@ -858,6 +866,11 @@ void InitExtensionBehavior(const ShBuiltInResources &resources, TExtensionBehavi ...@@ -858,6 +866,11 @@ void InitExtensionBehavior(const ShBuiltInResources &resources, TExtensionBehavi
extBehavior["GL_NV_shader_framebuffer_fetch"] = EBhUndefined; extBehavior["GL_NV_shader_framebuffer_fetch"] = EBhUndefined;
if (resources.ARM_shader_framebuffer_fetch) if (resources.ARM_shader_framebuffer_fetch)
extBehavior["GL_ARM_shader_framebuffer_fetch"] = EBhUndefined; extBehavior["GL_ARM_shader_framebuffer_fetch"] = EBhUndefined;
if (resources.OVR_multiview)
{
extBehavior["GL_OVR_multiview"] = EBhUndefined;
extBehavior["GL_OVR_multiview2"] = EBhUndefined;
}
} }
void ResetExtensionBehavior(TExtensionBehavior &extBehavior) void ResetExtensionBehavior(TExtensionBehavior &extBehavior)
......
...@@ -838,6 +838,11 @@ bool TIntermSwizzle::hasDuplicateOffsets() const ...@@ -838,6 +838,11 @@ bool TIntermSwizzle::hasDuplicateOffsets() const
return false; return false;
} }
bool TIntermSwizzle::offsetsMatch(int offset) const
{
return mSwizzleOffsets.size() == 1 && mSwizzleOffsets[0] == offset;
}
void TIntermSwizzle::writeOffsetsAsXYZW(TInfoSinkBase *out) const void TIntermSwizzle::writeOffsetsAsXYZW(TInfoSinkBase *out) const
{ {
for (const int offset : mSwizzleOffsets) for (const int offset : mSwizzleOffsets)
......
...@@ -430,6 +430,7 @@ class TIntermSwizzle : public TIntermTyped ...@@ -430,6 +430,7 @@ class TIntermSwizzle : public TIntermTyped
void writeOffsetsAsXYZW(TInfoSinkBase *out) const; void writeOffsetsAsXYZW(TInfoSinkBase *out) const;
bool hasDuplicateOffsets() const; bool hasDuplicateOffsets() const;
bool offsetsMatch(int offset) const;
TIntermTyped *fold(); TIntermTyped *fold();
......
...@@ -1279,7 +1279,16 @@ TString TOutputGLSLBase::hashName(const TName &name) ...@@ -1279,7 +1279,16 @@ TString TOutputGLSLBase::hashName(const TName &name)
TString TOutputGLSLBase::hashVariableName(const TName &name) TString TOutputGLSLBase::hashVariableName(const TName &name)
{ {
if (mSymbolTable.findBuiltIn(name.getString(), mShaderVersion) != NULL) if (mSymbolTable.findBuiltIn(name.getString(), mShaderVersion) != NULL)
{
if (mCompileOptions & SH_TRANSLATE_VIEWID_OVR_TO_UNIFORM &&
name.getString() == "gl_ViewID_OVR")
{
TName uniformName(TString("ViewId_OVR"));
uniformName.setInternal(true);
return hashName(uniformName);
}
return name.getString(); return name.getString();
}
return hashName(name); return hashName(name);
} }
......
...@@ -30,6 +30,11 @@ class TOutputGLSLBase : public TIntermTraverser ...@@ -30,6 +30,11 @@ class TOutputGLSLBase : public TIntermTraverser
ShShaderOutput getShaderOutput() const { return mOutput; } ShShaderOutput getShaderOutput() const { return mOutput; }
// Return the original name if hash function pointer is NULL;
// otherwise return the hashed name. Has special handling for internal names, which are not
// hashed.
TString hashName(const TName &name);
protected: protected:
TInfoSinkBase &objSink() { return mObjSink; } TInfoSinkBase &objSink() { return mObjSink; }
void writeFloat(TInfoSinkBase &out, float f); void writeFloat(TInfoSinkBase &out, float f);
...@@ -62,9 +67,6 @@ class TOutputGLSLBase : public TIntermTraverser ...@@ -62,9 +67,6 @@ class TOutputGLSLBase : public TIntermTraverser
void visitCodeBlock(TIntermBlock *node); void visitCodeBlock(TIntermBlock *node);
// Return the original name if hash function pointer is NULL;
// otherwise return the hashed name.
TString hashName(const TName &name);
// Same as hashName(), but without hashing built-in variables. // Same as hashName(), but without hashing built-in variables.
TString hashVariableName(const TName &name); TString hashVariableName(const TName &name);
// Same as hashName(), but without hashing built-in functions and with unmangling. // Same as hashName(), but without hashing built-in functions and with unmangling.
......
...@@ -106,7 +106,10 @@ TParseContext::TParseContext(TSymbolTable &symt, ...@@ -106,7 +106,10 @@ TParseContext::TParseContext(TSymbolTable &symt,
mUsesSecondaryOutputs(false), mUsesSecondaryOutputs(false),
mMinProgramTexelOffset(resources.MinProgramTexelOffset), mMinProgramTexelOffset(resources.MinProgramTexelOffset),
mMaxProgramTexelOffset(resources.MaxProgramTexelOffset), mMaxProgramTexelOffset(resources.MaxProgramTexelOffset),
mMultiviewAvailable(resources.OVR_multiview == 1),
mComputeShaderLocalSizeDeclared(false), mComputeShaderLocalSizeDeclared(false),
mNumViews(-1),
mMaxNumViews(resources.MaxViewsOVR),
mDeclaringFunction(false) mDeclaringFunction(false)
{ {
mComputeShaderLocalSize.fill(-1); mComputeShaderLocalSize.fill(-1);
...@@ -1085,6 +1088,12 @@ bool TParseContext::checkCanUseExtension(const TSourceLoc &line, const TString & ...@@ -1085,6 +1088,12 @@ bool TParseContext::checkCanUseExtension(const TSourceLoc &line, const TString &
// In GLSL ES, an extension's default behavior is "disable". // In GLSL ES, an extension's default behavior is "disable".
if (iter->second == EBhDisable || iter->second == EBhUndefined) if (iter->second == EBhDisable || iter->second == EBhUndefined)
{ {
// TODO(oetuaho@nvidia.com): This is slightly hacky. Might be better if symbols could be
// associated with more than one extension.
if (extension == "GL_OVR_multiview")
{
return checkCanUseExtension(line, "GL_OVR_multiview2");
}
error(line, "extension is disabled", extension.c_str()); error(line, "extension is disabled", extension.c_str());
return false; return false;
} }
...@@ -1481,6 +1490,14 @@ TIntermTyped *TParseContext::parseVariableIdentifier(const TSourceLoc &location, ...@@ -1481,6 +1490,14 @@ TIntermTyped *TParseContext::parseVariableIdentifier(const TSourceLoc &location,
{ {
const TVariable *variable = getNamedVariable(location, name, symbol); const TVariable *variable = getNamedVariable(location, name, symbol);
if (variable->getType().getQualifier() == EvqViewIDOVR && IsWebGLBasedSpec(mShaderSpec) &&
mShaderType == GL_FRAGMENT_SHADER && !isExtensionEnabled("GL_OVR_multiview2"))
{
// WEBGL_multiview spec
error(location, "Need to enable OVR_multiview2 to use gl_ViewID_OVR in fragment shader",
"gl_ViewID_OVR");
}
if (variable->getConstPointer()) if (variable->getConstPointer())
{ {
const TConstantUnion *constArray = variable->getConstPointer(); const TConstantUnion *constArray = variable->getConstPointer();
...@@ -2315,10 +2332,37 @@ void TParseContext::parseGlobalLayoutQualifier(const TTypeQualifierBuilder &type ...@@ -2315,10 +2332,37 @@ void TParseContext::parseGlobalLayoutQualifier(const TTypeQualifierBuilder &type
mComputeShaderLocalSizeDeclared = true; mComputeShaderLocalSizeDeclared = true;
} }
else else if (mMultiviewAvailable &&
(isExtensionEnabled("GL_OVR_multiview") || isExtensionEnabled("GL_OVR_multiview2")) &&
typeQualifier.qualifier == EvqVertexIn)
{ {
// This error is only specified in WebGL, but tightens unspecified behavior in the native
// specification.
if (mNumViews != -1 && layoutQualifier.numViews != mNumViews)
{
error(typeQualifier.line, "Number of views does not match the previous declaration",
"layout");
return;
}
if (layoutQualifier.numViews == -1)
{
error(typeQualifier.line, "No num_views specified", "layout");
return;
}
if (layoutQualifier.numViews > mMaxNumViews)
{
error(typeQualifier.line, "num_views greater than the value of GL_MAX_VIEWS_OVR",
"layout");
return;
}
if (!checkWorkGroupSizeIsNotSpecified(typeQualifier.line, typeQualifier.layoutQualifier)) mNumViews = layoutQualifier.numViews;
}
else
{
if (!checkWorkGroupSizeIsNotSpecified(typeQualifier.line, layoutQualifier))
{ {
return; return;
} }
...@@ -2337,7 +2381,7 @@ void TParseContext::parseGlobalLayoutQualifier(const TTypeQualifierBuilder &type ...@@ -2337,7 +2381,7 @@ void TParseContext::parseGlobalLayoutQualifier(const TTypeQualifierBuilder &type
return; return;
} }
checkLocationIsNotSpecified(typeQualifier.line, typeQualifier.layoutQualifier); checkLocationIsNotSpecified(typeQualifier.line, layoutQualifier);
if (layoutQualifier.matrixPacking != EmpUnspecified) if (layoutQualifier.matrixPacking != EmpUnspecified)
{ {
...@@ -3348,6 +3392,20 @@ void TParseContext::parseLocalSize(const TString &qualifierType, ...@@ -3348,6 +3392,20 @@ void TParseContext::parseLocalSize(const TString &qualifierType,
(*localSize)[index] = intValue; (*localSize)[index] = intValue;
} }
void TParseContext::parseNumViews(int intValue,
const TSourceLoc &intValueLine,
const std::string &intValueString,
int *numViews)
{
// This error is only specified in WebGL, but tightens unspecified behavior in the native
// specification.
if (intValue < 1)
{
error(intValueLine, "out of range: num_views must be positive", intValueString.c_str());
}
*numViews = intValue;
}
TLayoutQualifier TParseContext::parseLayoutQualifier(const TString &qualifierType, TLayoutQualifier TParseContext::parseLayoutQualifier(const TString &qualifierType,
const TSourceLoc &qualifierTypeLine, const TSourceLoc &qualifierTypeLine,
int intValue, int intValue,
...@@ -3386,6 +3444,12 @@ TLayoutQualifier TParseContext::parseLayoutQualifier(const TString &qualifierTyp ...@@ -3386,6 +3444,12 @@ TLayoutQualifier TParseContext::parseLayoutQualifier(const TString &qualifierTyp
parseLocalSize(qualifierType, qualifierTypeLine, intValue, intValueLine, intValueString, 2u, parseLocalSize(qualifierType, qualifierTypeLine, intValue, intValueLine, intValueString, 2u,
&qualifier.localSize); &qualifier.localSize);
} }
else if (qualifierType == "num_views" && mMultiviewAvailable &&
(isExtensionEnabled("GL_OVR_multiview") || isExtensionEnabled("GL_OVR_multiview2")) &&
mShaderType == GL_VERTEX_SHADER)
{
parseNumViews(intValue, intValueLine, intValueString, &qualifier.numViews);
}
else else
{ {
error(qualifierTypeLine, "invalid layout qualifier", qualifierType.c_str()); error(qualifierTypeLine, "invalid layout qualifier", qualifierType.c_str());
......
...@@ -81,6 +81,8 @@ class TParseContext : angle::NonCopyable ...@@ -81,6 +81,8 @@ class TParseContext : angle::NonCopyable
bool isComputeShaderLocalSizeDeclared() const { return mComputeShaderLocalSizeDeclared; } bool isComputeShaderLocalSizeDeclared() const { return mComputeShaderLocalSizeDeclared; }
sh::WorkGroupSize getComputeShaderLocalSize() const; sh::WorkGroupSize getComputeShaderLocalSize() const;
int getNumViews() const { return mNumViews; }
void enterFunctionDeclaration() { mDeclaringFunction = true; } void enterFunctionDeclaration() { mDeclaringFunction = true; }
void exitFunctionDeclaration() { mDeclaringFunction = false; } void exitFunctionDeclaration() { mDeclaringFunction = false; }
...@@ -294,6 +296,10 @@ class TParseContext : angle::NonCopyable ...@@ -294,6 +296,10 @@ class TParseContext : angle::NonCopyable
const std::string &intValueString, const std::string &intValueString,
size_t index, size_t index,
sh::WorkGroupSize *localSize); sh::WorkGroupSize *localSize);
void parseNumViews(int intValue,
const TSourceLoc &intValueLine,
const std::string &intValueString,
int *numViews);
TLayoutQualifier parseLayoutQualifier(const TString &qualifierType, TLayoutQualifier parseLayoutQualifier(const TString &qualifierType,
const TSourceLoc &qualifierTypeLine); const TSourceLoc &qualifierTypeLine);
TLayoutQualifier parseLayoutQualifier(const TString &qualifierType, TLayoutQualifier parseLayoutQualifier(const TString &qualifierType,
...@@ -445,9 +451,14 @@ class TParseContext : angle::NonCopyable ...@@ -445,9 +451,14 @@ class TParseContext : angle::NonCopyable
int mMinProgramTexelOffset; int mMinProgramTexelOffset;
int mMaxProgramTexelOffset; int mMaxProgramTexelOffset;
bool mMultiviewAvailable;
// keep track of local group size declared in layout. It should be declared only once. // keep track of local group size declared in layout. It should be declared only once.
bool mComputeShaderLocalSizeDeclared; bool mComputeShaderLocalSizeDeclared;
sh::WorkGroupSize mComputeShaderLocalSize; sh::WorkGroupSize mComputeShaderLocalSize;
// keep track of number of views declared in layout.
int mNumViews;
int mMaxNumViews;
// keeps track whether we are declaring / defining a function // keeps track whether we are declaring / defining a function
bool mDeclaringFunction; bool mDeclaringFunction;
}; };
......
...@@ -584,6 +584,11 @@ TLayoutQualifier JoinLayoutQualifiers(TLayoutQualifier leftQualifier, ...@@ -584,6 +584,11 @@ TLayoutQualifier JoinLayoutQualifiers(TLayoutQualifier leftQualifier,
} }
} }
if (rightQualifier.numViews != -1)
{
joinedQualifier.numViews = rightQualifier.numViews;
}
if (rightQualifier.imageInternalFormat != EiifUnspecified) if (rightQualifier.imageInternalFormat != EiifUnspecified)
{ {
joinedQualifier.imageInternalFormat = rightQualifier.imageInternalFormat; joinedQualifier.imageInternalFormat = rightQualifier.imageInternalFormat;
......
...@@ -161,6 +161,7 @@ void ShInitBuiltInResources(ShBuiltInResources *resources) ...@@ -161,6 +161,7 @@ void ShInitBuiltInResources(ShBuiltInResources *resources)
resources->EXT_shader_framebuffer_fetch = 0; resources->EXT_shader_framebuffer_fetch = 0;
resources->NV_shader_framebuffer_fetch = 0; resources->NV_shader_framebuffer_fetch = 0;
resources->ARM_shader_framebuffer_fetch = 0; resources->ARM_shader_framebuffer_fetch = 0;
resources->OVR_multiview = 0;
resources->NV_draw_buffers = 0; resources->NV_draw_buffers = 0;
...@@ -176,6 +177,8 @@ void ShInitBuiltInResources(ShBuiltInResources *resources) ...@@ -176,6 +177,8 @@ void ShInitBuiltInResources(ShBuiltInResources *resources)
// Extensions constants. // Extensions constants.
resources->MaxDualSourceDrawBuffers = 0; resources->MaxDualSourceDrawBuffers = 0;
resources->MaxViewsOVR = 2;
// Disable name hashing by default. // Disable name hashing by default.
resources->HashFunction = NULL; resources->HashFunction = NULL;
...@@ -371,6 +374,16 @@ WorkGroupSize ShGetComputeShaderLocalGroupSize(const ShHandle handle) ...@@ -371,6 +374,16 @@ WorkGroupSize ShGetComputeShaderLocalGroupSize(const ShHandle handle)
return compiler->getComputeShaderLocalSize(); return compiler->getComputeShaderLocalSize();
} }
int ShGetVertexShaderNumViews(const ShHandle handle)
{
ASSERT(handle);
TShHandleBase *base = static_cast<TShHandleBase *>(handle);
TCompiler *compiler = base->getAsCompiler();
ASSERT(compiler);
return compiler->getNumViews();
}
bool ShCheckVariablesWithinPackingLimits(int maxVectors, bool ShCheckVariablesWithinPackingLimits(int maxVectors,
const std::vector<ShaderVariable> &variables) const std::vector<ShaderVariable> &variables)
{ {
...@@ -512,6 +525,11 @@ sh::WorkGroupSize GetComputeShaderLocalGroupSize(const ShHandle handle) ...@@ -512,6 +525,11 @@ sh::WorkGroupSize GetComputeShaderLocalGroupSize(const ShHandle handle)
return ShGetComputeShaderLocalGroupSize(handle); return ShGetComputeShaderLocalGroupSize(handle);
} }
int GetVertexShaderNumViews(const ShHandle handle)
{
return ShGetVertexShaderNumViews(handle);
}
bool CheckVariablesWithinPackingLimits(int maxVectors, bool CheckVariablesWithinPackingLimits(int maxVectors,
const std::vector<sh::ShaderVariable> &variables) const std::vector<sh::ShaderVariable> &variables)
{ {
......
...@@ -40,7 +40,7 @@ void TranslatorESSL::translate(TIntermNode *root, ShCompileOptions compileOption ...@@ -40,7 +40,7 @@ void TranslatorESSL::translate(TIntermNode *root, ShCompileOptions compileOption
} }
// Write built-in extension behaviors. // Write built-in extension behaviors.
writeExtensionBehavior(); writeExtensionBehavior(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.
...@@ -94,6 +94,14 @@ void TranslatorESSL::translate(TIntermNode *root, ShCompileOptions compileOption ...@@ -94,6 +94,14 @@ void TranslatorESSL::translate(TIntermNode *root, ShCompileOptions compileOption
TOutputESSL outputESSL(sink, getArrayIndexClampingStrategy(), getHashFunction(), getNameMap(), TOutputESSL outputESSL(sink, getArrayIndexClampingStrategy(), getHashFunction(), getNameMap(),
getSymbolTable(), getShaderType(), shaderVer, precisionEmulation, getSymbolTable(), getShaderType(), shaderVer, precisionEmulation,
compileOptions); compileOptions);
if (compileOptions & SH_TRANSLATE_VIEWID_OVR_TO_UNIFORM)
{
TName uniformName(TString("ViewId_OVR"));
uniformName.setInternal(true);
sink << "highp uniform int " << outputESSL.hashName(uniformName) << ";\n";
}
root->traverse(&outputESSL); root->traverse(&outputESSL);
} }
...@@ -103,7 +111,7 @@ bool TranslatorESSL::shouldFlattenPragmaStdglInvariantAll() ...@@ -103,7 +111,7 @@ bool TranslatorESSL::shouldFlattenPragmaStdglInvariantAll()
return false; return false;
} }
void TranslatorESSL::writeExtensionBehavior() void TranslatorESSL::writeExtensionBehavior(ShCompileOptions compileOptions)
{ {
TInfoSinkBase &sink = getInfoSink().obj; TInfoSinkBase &sink = getInfoSink().obj;
const TExtensionBehavior &extBehavior = getExtensionBehavior(); const TExtensionBehavior &extBehavior = getExtensionBehavior();
...@@ -123,6 +131,12 @@ void TranslatorESSL::writeExtensionBehavior() ...@@ -123,6 +131,12 @@ void TranslatorESSL::writeExtensionBehavior()
sink << "#extension GL_NV_draw_buffers : " << getBehaviorString(iter->second) sink << "#extension GL_NV_draw_buffers : " << getBehaviorString(iter->second)
<< "\n"; << "\n";
} }
else if (compileOptions & SH_TRANSLATE_VIEWID_OVR_TO_UNIFORM &&
(iter->first == "GL_OVR_multiview" || iter->first == "GL_OVR_multiview2"))
{
// No output
continue;
}
else else
{ {
sink << "#extension " << iter->first << " : " << getBehaviorString(iter->second) sink << "#extension " << iter->first << " : " << getBehaviorString(iter->second)
......
...@@ -25,7 +25,7 @@ class TranslatorESSL : public TCompiler ...@@ -25,7 +25,7 @@ class TranslatorESSL : public TCompiler
bool shouldFlattenPragmaStdglInvariantAll() override; bool shouldFlattenPragmaStdglInvariantAll() override;
private: private:
void writeExtensionBehavior(); void writeExtensionBehavior(ShCompileOptions compileOptions);
}; };
} // namespace sh } // namespace sh
......
...@@ -204,6 +204,14 @@ void TranslatorGLSL::translate(TIntermNode *root, ShCompileOptions compileOption ...@@ -204,6 +204,14 @@ void TranslatorGLSL::translate(TIntermNode *root, ShCompileOptions compileOption
TOutputGLSL outputGLSL(sink, getArrayIndexClampingStrategy(), getHashFunction(), getNameMap(), TOutputGLSL outputGLSL(sink, getArrayIndexClampingStrategy(), getHashFunction(), getNameMap(),
getSymbolTable(), getShaderType(), getShaderVersion(), getOutputType(), getSymbolTable(), getShaderType(), getShaderVersion(), getOutputType(),
compileOptions); compileOptions);
if (compileOptions & SH_TRANSLATE_VIEWID_OVR_TO_UNIFORM)
{
TName uniformName(TString("ViewId_OVR"));
uniformName.setInternal(true);
sink << "uniform int " << outputGLSL.hashName(uniformName) << ";\n";
}
root->traverse(&outputGLSL); root->traverse(&outputGLSL);
} }
......
//
// Copyright (c) 2002-2016 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// ValidateMultiviewWebGL.h:
// Validate the AST according to rules in the WEBGL_multiview extension spec. Only covers those
// rules not already covered in ParseContext.
//
#ifndef COMPILER_TRANSLATOR_VALIDATEMULTIVIEWWEBGL_H_
#define COMPILER_TRANSLATOR_VALIDATEMULTIVIEWWEBGL_H_
#include "GLSLANG/ShaderVars.h"
namespace sh
{
class TDiagnostics;
class TIntermBlock;
// Check for errors and output error messages with diagnostics.
// Returns true if there are no errors.
bool ValidateMultiviewWebGL(TIntermBlock *root,
sh::GLenum shaderType,
bool multiview2,
TDiagnostics *diagnostics);
} // namespace sh
#endif // COMPILER_TRANSLATOR_VALIDATEMULTIVIEWWEBGL_H_
...@@ -72,6 +72,7 @@ ...@@ -72,6 +72,7 @@
'<(angle_path)/src/tests/compiler_tests/ShCompile_test.cpp', '<(angle_path)/src/tests/compiler_tests/ShCompile_test.cpp',
'<(angle_path)/src/tests/compiler_tests/TypeTracking_test.cpp', '<(angle_path)/src/tests/compiler_tests/TypeTracking_test.cpp',
'<(angle_path)/src/tests/compiler_tests/VariablePacker_test.cpp', '<(angle_path)/src/tests/compiler_tests/VariablePacker_test.cpp',
'<(angle_path)/src/tests/compiler_tests/WEBGL_multiview_test.cpp',
'<(angle_path)/src/tests/compiler_tests/WorkGroupSize_test.cpp', '<(angle_path)/src/tests/compiler_tests/WorkGroupSize_test.cpp',
'<(angle_path)/src/tests/preprocessor_tests/char_test.cpp', '<(angle_path)/src/tests/preprocessor_tests/char_test.cpp',
'<(angle_path)/src/tests/preprocessor_tests/comment_test.cpp', '<(angle_path)/src/tests/preprocessor_tests/comment_test.cpp',
......
...@@ -3268,4 +3268,20 @@ TEST_F(FragmentShaderValidationTest, BuiltinESSL31FunctionDeclaredInESSL30Shader ...@@ -3268,4 +3268,20 @@ TEST_F(FragmentShaderValidationTest, BuiltinESSL31FunctionDeclaredInESSL30Shader
{ {
FAIL() << "Shader compilation failed, expecting success:\n" << mInfoLog; FAIL() << "Shader compilation failed, expecting success:\n" << mInfoLog;
} }
} }
\ No newline at end of file
// Attempting to declare num_views without enabling OVR_multiview.
TEST_F(VertexShaderValidationTest, InvalidNumViews)
{
const std::string &shaderString =
"#version 300 es\n"
"precision mediump float;\n"
"layout (num_views = 2) in;\n"
"void main() {\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
...@@ -17,34 +17,6 @@ namespace sh ...@@ -17,34 +17,6 @@ namespace sh
namespace namespace
{ {
class ShaderVariableFinder : public TIntermTraverser
{
public:
ShaderVariableFinder(const TString &variableName, TBasicType basicType)
: TIntermTraverser(true, false, false),
mVariableName(variableName),
mNodeFound(nullptr),
mBasicType(basicType)
{
}
void visitSymbol(TIntermSymbol *node)
{
if (node->getBasicType() == mBasicType && node->getSymbol() == mVariableName)
{
mNodeFound = node;
}
}
bool isFound() const { return mNodeFound != nullptr; }
const TIntermSymbol *getNode() const { return mNodeFound; }
private:
TString mVariableName;
TIntermSymbol *mNodeFound;
TBasicType mBasicType;
};
class FunctionCallFinder : public TIntermTraverser class FunctionCallFinder : public TIntermTraverser
{ {
public: public:
...@@ -237,15 +209,6 @@ bool MatchOutputCodeTest::notFoundInCode(const char *stringToFind) const ...@@ -237,15 +209,6 @@ bool MatchOutputCodeTest::notFoundInCode(const char *stringToFind) const
return true; return true;
} }
const TIntermSymbol *FindSymbolNode(TIntermNode *root,
const TString &symbolName,
TBasicType basicType)
{
ShaderVariableFinder finder(symbolName, basicType);
root->traverse(&finder);
return finder.getNode();
}
const TIntermAggregate *FindFunctionCallNode(TIntermNode *root, const TString &functionName) const TIntermAggregate *FindFunctionCallNode(TIntermNode *root, const TString &functionName)
{ {
FunctionCallFinder finder(functionName); FunctionCallFinder finder(functionName);
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include "angle_gl.h" #include "angle_gl.h"
#include "compiler/translator/TranslatorESSL.h" #include "compiler/translator/TranslatorESSL.h"
#include "GLSLANG/ShaderLang.h" #include "GLSLANG/ShaderLang.h"
#include "compiler/translator/FindSymbolNode.h"
namespace sh namespace sh
{ {
...@@ -92,10 +93,6 @@ class MatchOutputCodeTest : public testing::Test ...@@ -92,10 +93,6 @@ class MatchOutputCodeTest : public testing::Test
std::map<ShShaderOutput, std::string> mOutputCode; std::map<ShShaderOutput, std::string> mOutputCode;
}; };
const TIntermSymbol *FindSymbolNode(TIntermNode *root,
const TString &symbolName,
TBasicType basicType);
// Returns a pointer to a function call node with a mangled name functionName. // Returns a pointer to a function call node with a mangled name functionName.
const TIntermAggregate *FindFunctionCallNode(TIntermNode *root, const TString &functionName); const TIntermAggregate *FindFunctionCallNode(TIntermNode *root, const TString &functionName);
} }
......
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