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 @@
// Version number for shader translation API.
// It is incremented every time the API changes.
#define ANGLE_SH_VERSION 169
#define ANGLE_SH_VERSION 170
enum ShShaderSpec
{
......@@ -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.
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.
enum ShArrayIndexClampingStrategy
{
......@@ -259,6 +263,7 @@ struct ShBuiltInResources
int EXT_shader_framebuffer_fetch;
int NV_shader_framebuffer_fetch;
int ARM_shader_framebuffer_fetch;
int OVR_multiview;
// 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
......@@ -285,6 +290,9 @@ struct ShBuiltInResources
// GLES SL version 100 gl_MaxDualSourceDrawBuffersEXT value for EXT_blend_func_extended.
int MaxDualSourceDrawBuffers;
// Value of GL_MAX_VIEWS_OVR.
int MaxViewsOVR;
// Name Hashing.
// Set a 64 bit hash function to enable user-defined name hashing.
// Default is NULL.
......@@ -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::InterfaceBlock> *ShGetInterfaceBlocks(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
// 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);
const std::vector<sh::OutputVariable> *GetOutputVariables(const ShHandle handle);
const std::vector<sh::InterfaceBlock> *GetInterfaceBlocks(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
// GLSL 1.017 spec, Appendix A, section 7.
......
......@@ -205,6 +205,10 @@ int main(int argc, char *argv[])
case 'f': resources.EXT_shader_framebuffer_fetch = 1; break;
case 'n': resources.NV_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;
}
// clang-format on
......@@ -339,7 +343,8 @@ void usage()
" -x=l : enable EXT_shader_texture_lod\n"
" -x=f : enable EXT_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
}
......
......@@ -52,6 +52,8 @@
'compiler/translator/ExpandIntegerPowExpressions.cpp',
'compiler/translator/ExpandIntegerPowExpressions.h',
'compiler/translator/ExtensionBehavior.h',
'compiler/translator/FindSymbolNode.cpp',
'compiler/translator/FindSymbolNode.h',
'compiler/translator/FlagStd140Structs.cpp',
'compiler/translator/FlagStd140Structs.h',
'compiler/translator/HashNames.h',
......@@ -120,6 +122,8 @@
'compiler/translator/ValidateLimitations.h',
'compiler/translator/ValidateMaxParameters.h',
'compiler/translator/ValidateMaxParameters.cpp',
'compiler/translator/ValidateMultiviewWebGL.cpp',
'compiler/translator/ValidateMultiviewWebGL.h',
'compiler/translator/ValidateOutputs.cpp',
'compiler/translator/ValidateOutputs.h',
'compiler/translator/ValidateSwitch.cpp',
......
......@@ -488,6 +488,8 @@ enum TQualifier
EvqSecondaryFragColorEXT, // EXT_blend_func_extended
EvqSecondaryFragDataEXT, // EXT_blend_func_extended
EvqViewIDOVR, // OVR_multiview
// built-ins written by the shader_framebuffer_fetch extension(s)
EvqLastFragColor,
EvqLastFragData,
......@@ -575,6 +577,9 @@ struct TLayoutQualifier
// Image format layout qualifier
TLayoutImageInternalFormat imageInternalFormat;
// OVR_multiview num_views.
int numViews;
static TLayoutQualifier create()
{
TLayoutQualifier layoutQualifier;
......@@ -585,6 +590,7 @@ struct TLayoutQualifier
layoutQualifier.blockStorage = EbsUnspecified;
layoutQualifier.localSize.fill(-1);
layoutQualifier.numViews = -1;
layoutQualifier.imageInternalFormat = EiifUnspecified;
return layoutQualifier;
......@@ -592,7 +598,7 @@ struct TLayoutQualifier
bool isEmpty() const
{
return location == -1 && matrixPacking == EmpUnspecified &&
return location == -1 && numViews == -1 && matrixPacking == EmpUnspecified &&
blockStorage == EbsUnspecified && !localSize.isAnyValueSet() &&
imageInternalFormat == EiifUnspecified;
}
......@@ -600,12 +606,16 @@ struct TLayoutQualifier
bool isCombinationValid() const
{
bool workSizeSpecified = localSize.isAnyValueSet();
bool numViewsSet = (numViews != -1);
bool otherLayoutQualifiersSpecified =
(location != -1 || matrixPacking != EmpUnspecified || blockStorage != EbsUnspecified ||
imageInternalFormat != EiifUnspecified);
// we can have either the work group size specified, or the other layout qualifiers
return !(workSizeSpecified && otherLayoutQualifiersSpecified);
// we can have either the work group size specified, or number of views, or the other layout
// qualifiers.
return (workSizeSpecified ? 1 : 0) + (numViewsSet ? 1 : 0) +
(otherLayoutQualifiersSpecified ? 1 : 0) <=
1;
}
bool isLocalSizeEqual(const sh::WorkGroupSize &localSizeIn) const
......@@ -697,6 +707,7 @@ inline const char *getQualifierString(TQualifier q)
case EvqFragDepth: return "FragDepth";
case EvqSecondaryFragColorEXT: return "SecondaryFragColorEXT";
case EvqSecondaryFragDataEXT: return "SecondaryFragDataEXT";
case EvqViewIDOVR: return "ViewIDOVR";
case EvqLastFragColor: return "LastFragColor";
case EvqLastFragData: return "LastFragData";
case EvqSmoothOut: return "smooth out";
......
......@@ -30,6 +30,7 @@
#include "compiler/translator/UseInterfaceBlockFields.h"
#include "compiler/translator/ValidateLimitations.h"
#include "compiler/translator/ValidateMaxParameters.h"
#include "compiler/translator/ValidateMultiviewWebGL.h"
#include "compiler/translator/ValidateOutputs.h"
#include "compiler/translator/VariablePacker.h"
#include "third_party/compiler/ArrayBoundsClamper.h"
......@@ -320,11 +321,22 @@ TIntermBlock *TCompiler::compileTreeImpl(const char *const shaderStrings[],
mComputeShaderLocalSizeDeclared = parseContext.isComputeShaderLocalSizeDeclared();
mComputeShaderLocalSize = parseContext.getComputeShaderLocalSize();
mNumViews = parseContext.getNumViews();
root = parseContext.getTreeRoot();
// Highp might have been auto-enabled based on shader version
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.
if (success && (compileOptions & SH_LIMIT_EXPRESSION_COMPLEXITY))
success = limitExpressionComplexity(root);
......@@ -358,6 +370,11 @@ TIntermBlock *TCompiler::compileTreeImpl(const char *const shaderStrings[],
if (success && shouldRunLoopAndIndexingValidation(compileOptions))
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.
if (success && getResources().WEBGL_debug_shader_precision &&
getPragma().debugShaderPrecision)
......@@ -650,6 +667,8 @@ void TCompiler::clearResults()
interfaceBlocks.clear();
variablesCollected = false;
mNumViews = -1;
builtInFunctionEmulator.Cleanup();
nameMap.clear();
......
......@@ -101,7 +101,8 @@ class TCompiler : public TShHandleBase
TInfoSink &getInfoSink() { return infoSink; }
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.
void clearResults();
......@@ -247,6 +248,9 @@ class TCompiler : public TShHandleBase
bool mComputeShaderLocalSizeDeclared;
sh::WorkGroupSize mComputeShaderLocalSize;
// GL_OVR_multiview num_views.
int mNumViews;
// name hashing.
ShHashFunction64 hashFunction;
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,
// Insert some special built-in variables that are not in
// 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)
{
case GL_FRAGMENT_SHADER:
......@@ -858,6 +866,11 @@ void InitExtensionBehavior(const ShBuiltInResources &resources, TExtensionBehavi
extBehavior["GL_NV_shader_framebuffer_fetch"] = EBhUndefined;
if (resources.ARM_shader_framebuffer_fetch)
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)
......
......@@ -838,6 +838,11 @@ bool TIntermSwizzle::hasDuplicateOffsets() const
return false;
}
bool TIntermSwizzle::offsetsMatch(int offset) const
{
return mSwizzleOffsets.size() == 1 && mSwizzleOffsets[0] == offset;
}
void TIntermSwizzle::writeOffsetsAsXYZW(TInfoSinkBase *out) const
{
for (const int offset : mSwizzleOffsets)
......
......@@ -430,6 +430,7 @@ class TIntermSwizzle : public TIntermTyped
void writeOffsetsAsXYZW(TInfoSinkBase *out) const;
bool hasDuplicateOffsets() const;
bool offsetsMatch(int offset) const;
TIntermTyped *fold();
......
......@@ -1279,7 +1279,16 @@ TString TOutputGLSLBase::hashName(const TName &name)
TString TOutputGLSLBase::hashVariableName(const TName &name)
{
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 hashName(name);
}
......
......@@ -30,6 +30,11 @@ class TOutputGLSLBase : public TIntermTraverser
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:
TInfoSinkBase &objSink() { return mObjSink; }
void writeFloat(TInfoSinkBase &out, float f);
......@@ -62,9 +67,6 @@ class TOutputGLSLBase : public TIntermTraverser
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.
TString hashVariableName(const TName &name);
// Same as hashName(), but without hashing built-in functions and with unmangling.
......
......@@ -106,7 +106,10 @@ TParseContext::TParseContext(TSymbolTable &symt,
mUsesSecondaryOutputs(false),
mMinProgramTexelOffset(resources.MinProgramTexelOffset),
mMaxProgramTexelOffset(resources.MaxProgramTexelOffset),
mMultiviewAvailable(resources.OVR_multiview == 1),
mComputeShaderLocalSizeDeclared(false),
mNumViews(-1),
mMaxNumViews(resources.MaxViewsOVR),
mDeclaringFunction(false)
{
mComputeShaderLocalSize.fill(-1);
......@@ -1085,6 +1088,12 @@ bool TParseContext::checkCanUseExtension(const TSourceLoc &line, const TString &
// In GLSL ES, an extension's default behavior is "disable".
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());
return false;
}
......@@ -1481,6 +1490,14 @@ TIntermTyped *TParseContext::parseVariableIdentifier(const TSourceLoc &location,
{
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())
{
const TConstantUnion *constArray = variable->getConstPointer();
......@@ -2315,10 +2332,37 @@ void TParseContext::parseGlobalLayoutQualifier(const TTypeQualifierBuilder &type
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;
}
......@@ -2337,7 +2381,7 @@ void TParseContext::parseGlobalLayoutQualifier(const TTypeQualifierBuilder &type
return;
}
checkLocationIsNotSpecified(typeQualifier.line, typeQualifier.layoutQualifier);
checkLocationIsNotSpecified(typeQualifier.line, layoutQualifier);
if (layoutQualifier.matrixPacking != EmpUnspecified)
{
......@@ -3348,6 +3392,20 @@ void TParseContext::parseLocalSize(const TString &qualifierType,
(*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,
const TSourceLoc &qualifierTypeLine,
int intValue,
......@@ -3386,6 +3444,12 @@ TLayoutQualifier TParseContext::parseLayoutQualifier(const TString &qualifierTyp
parseLocalSize(qualifierType, qualifierTypeLine, intValue, intValueLine, intValueString, 2u,
&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
{
error(qualifierTypeLine, "invalid layout qualifier", qualifierType.c_str());
......
......@@ -81,6 +81,8 @@ class TParseContext : angle::NonCopyable
bool isComputeShaderLocalSizeDeclared() const { return mComputeShaderLocalSizeDeclared; }
sh::WorkGroupSize getComputeShaderLocalSize() const;
int getNumViews() const { return mNumViews; }
void enterFunctionDeclaration() { mDeclaringFunction = true; }
void exitFunctionDeclaration() { mDeclaringFunction = false; }
......@@ -294,6 +296,10 @@ class TParseContext : angle::NonCopyable
const std::string &intValueString,
size_t index,
sh::WorkGroupSize *localSize);
void parseNumViews(int intValue,
const TSourceLoc &intValueLine,
const std::string &intValueString,
int *numViews);
TLayoutQualifier parseLayoutQualifier(const TString &qualifierType,
const TSourceLoc &qualifierTypeLine);
TLayoutQualifier parseLayoutQualifier(const TString &qualifierType,
......@@ -445,9 +451,14 @@ class TParseContext : angle::NonCopyable
int mMinProgramTexelOffset;
int mMaxProgramTexelOffset;
bool mMultiviewAvailable;
// keep track of local group size declared in layout. It should be declared only once.
bool mComputeShaderLocalSizeDeclared;
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
bool mDeclaringFunction;
};
......
......@@ -584,6 +584,11 @@ TLayoutQualifier JoinLayoutQualifiers(TLayoutQualifier leftQualifier,
}
}
if (rightQualifier.numViews != -1)
{
joinedQualifier.numViews = rightQualifier.numViews;
}
if (rightQualifier.imageInternalFormat != EiifUnspecified)
{
joinedQualifier.imageInternalFormat = rightQualifier.imageInternalFormat;
......
......@@ -161,6 +161,7 @@ void ShInitBuiltInResources(ShBuiltInResources *resources)
resources->EXT_shader_framebuffer_fetch = 0;
resources->NV_shader_framebuffer_fetch = 0;
resources->ARM_shader_framebuffer_fetch = 0;
resources->OVR_multiview = 0;
resources->NV_draw_buffers = 0;
......@@ -176,6 +177,8 @@ void ShInitBuiltInResources(ShBuiltInResources *resources)
// Extensions constants.
resources->MaxDualSourceDrawBuffers = 0;
resources->MaxViewsOVR = 2;
// Disable name hashing by default.
resources->HashFunction = NULL;
......@@ -371,6 +374,16 @@ WorkGroupSize ShGetComputeShaderLocalGroupSize(const ShHandle handle)
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,
const std::vector<ShaderVariable> &variables)
{
......@@ -512,6 +525,11 @@ sh::WorkGroupSize GetComputeShaderLocalGroupSize(const ShHandle handle)
return ShGetComputeShaderLocalGroupSize(handle);
}
int GetVertexShaderNumViews(const ShHandle handle)
{
return ShGetVertexShaderNumViews(handle);
}
bool CheckVariablesWithinPackingLimits(int maxVectors,
const std::vector<sh::ShaderVariable> &variables)
{
......
......@@ -40,7 +40,7 @@ void TranslatorESSL::translate(TIntermNode *root, ShCompileOptions compileOption
}
// Write built-in extension behaviors.
writeExtensionBehavior();
writeExtensionBehavior(compileOptions);
// Write pragmas after extensions because some drivers consider pragmas
// like non-preprocessor tokens.
......@@ -94,6 +94,14 @@ void TranslatorESSL::translate(TIntermNode *root, ShCompileOptions compileOption
TOutputESSL outputESSL(sink, getArrayIndexClampingStrategy(), getHashFunction(), getNameMap(),
getSymbolTable(), getShaderType(), shaderVer, precisionEmulation,
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);
}
......@@ -103,7 +111,7 @@ bool TranslatorESSL::shouldFlattenPragmaStdglInvariantAll()
return false;
}
void TranslatorESSL::writeExtensionBehavior()
void TranslatorESSL::writeExtensionBehavior(ShCompileOptions compileOptions)
{
TInfoSinkBase &sink = getInfoSink().obj;
const TExtensionBehavior &extBehavior = getExtensionBehavior();
......@@ -123,6 +131,12 @@ void TranslatorESSL::writeExtensionBehavior()
sink << "#extension GL_NV_draw_buffers : " << getBehaviorString(iter->second)
<< "\n";
}
else if (compileOptions & SH_TRANSLATE_VIEWID_OVR_TO_UNIFORM &&
(iter->first == "GL_OVR_multiview" || iter->first == "GL_OVR_multiview2"))
{
// No output
continue;
}
else
{
sink << "#extension " << iter->first << " : " << getBehaviorString(iter->second)
......
......@@ -25,7 +25,7 @@ class TranslatorESSL : public TCompiler
bool shouldFlattenPragmaStdglInvariantAll() override;
private:
void writeExtensionBehavior();
void writeExtensionBehavior(ShCompileOptions compileOptions);
};
} // namespace sh
......
......@@ -204,6 +204,14 @@ void TranslatorGLSL::translate(TIntermNode *root, ShCompileOptions compileOption
TOutputGLSL outputGLSL(sink, getArrayIndexClampingStrategy(), getHashFunction(), getNameMap(),
getSymbolTable(), getShaderType(), getShaderVersion(), getOutputType(),
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);
}
......
//
// 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 @@
'<(angle_path)/src/tests/compiler_tests/ShCompile_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/WEBGL_multiview_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/comment_test.cpp',
......
......@@ -3268,4 +3268,20 @@ TEST_F(FragmentShaderValidationTest, BuiltinESSL31FunctionDeclaredInESSL30Shader
{
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
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
{
public:
......@@ -237,15 +209,6 @@ bool MatchOutputCodeTest::notFoundInCode(const char *stringToFind) const
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)
{
FunctionCallFinder finder(functionName);
......
......@@ -16,6 +16,7 @@
#include "angle_gl.h"
#include "compiler/translator/TranslatorESSL.h"
#include "GLSLANG/ShaderLang.h"
#include "compiler/translator/FindSymbolNode.h"
namespace sh
{
......@@ -92,10 +93,6 @@ class MatchOutputCodeTest : public testing::Test
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.
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