Commit 9696316d by Olli Etuaho Committed by Commit Bot

Support ESSL structs containing samplers on D3D

Since HLSL can't natively handle samplers in structs, samplers need to be extracted out of structs into separate variables in the translated shader code. In HLSL 4.1, samplers that were in structs go into the normal sampler arrays and are identified by index constants. In other HLSL versions, samplers that were in structs are translated as uniform variables. These transformations are done inside the HLSL output classes, not as tree transformations. This helps to keep the uniform API provided by the shader translator intact. Wherever a struct containing samplers is passed into a user-defined function, the translated HLSL code passes the separate sampler variables alongside a struct where the samplers have been removed. The D3D backend in libANGLE queries the uniform registers of any samplers that were in uniform structs, and adds them to the register maps, so that correct sampler state gets assigned to them. The extracted sampler variables are prefixed with "angle_" instead of the usual "_" to prevent any name conflicts between them and regular variables. BUG=angleproject:504 TEST=angle_end2end_tests, dEQP-GLES*.functional.shaders.struct.uniform.* (all pass), dEQP-GLES*.functional.uniform_api.* (most now pass) Change-Id: Ib79cba2fa0ff8257a973d70dfd917a64f0ca1efb Reviewed-on: https://chromium-review.googlesource.com/333743Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarCorentin Wallez <cwallez@chromium.org> Commit-Queue: Olli Etuaho <oetuaho@nvidia.com>
parent f0fee07a
...@@ -48,7 +48,7 @@ typedef unsigned int GLenum; ...@@ -48,7 +48,7 @@ typedef unsigned int GLenum;
// 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 144 #define ANGLE_SH_VERSION 145
typedef enum { typedef enum {
SH_GLES2_SPEC = 0x8B40, SH_GLES2_SPEC = 0x8B40,
...@@ -454,16 +454,10 @@ COMPILER_EXPORT bool ShGetInterfaceBlockRegister(const ShHandle handle, ...@@ -454,16 +454,10 @@ COMPILER_EXPORT bool ShGetInterfaceBlockRegister(const ShHandle handle,
const std::string &interfaceBlockName, const std::string &interfaceBlockName,
unsigned int *indexOut); unsigned int *indexOut);
// Gives the compiler-assigned register for uniforms in the default // Gives a map from uniform names to compiler-assigned registers in the default
// interface block. // interface block. Note that the map contains also registers of samplers that
// The method writes the value to the output variable "indexOut". // have been extracted from structs.
// Returns true if it found a valid default uniform, false otherwise. COMPILER_EXPORT const std::map<std::string, unsigned int> *ShGetUniformRegisterMap(
// Parameters: const ShHandle handle);
// handle: Specifies the compiler
// interfaceBlockName: Specifies the uniform
// indexOut: output variable that stores the assigned register
COMPILER_EXPORT bool ShGetUniformRegister(const ShHandle handle,
const std::string &uniformName,
unsigned int *indexOut);
#endif // GLSLANG_SHADERLANG_H_ #endif // GLSLANG_SHADERLANG_H_
...@@ -738,6 +738,16 @@ class TIntermTraverser : angle::NonCopyable ...@@ -738,6 +738,16 @@ class TIntermTraverser : angle::NonCopyable
return mPath.size() == 0 ? NULL : mPath.back(); return mPath.size() == 0 ? NULL : mPath.back();
} }
// Return the nth ancestor of the node being traversed. getAncestorNode(0) == getParentNode()
TIntermNode *getAncestorNode(unsigned int n)
{
if (mPath.size() > n)
{
return mPath[mPath.size() - n - 1u];
}
return nullptr;
}
void pushParentBlock(TIntermAggregate *node); void pushParentBlock(TIntermAggregate *node);
void incrementParentBlockPos(); void incrementParentBlockPos();
void popParentBlock(); void popParentBlock();
......
...@@ -1464,7 +1464,8 @@ void OutputHLSL::visitSymbol(TIntermSymbol *node) ...@@ -1464,7 +1464,8 @@ void OutputHLSL::visitSymbol(TIntermSymbol *node)
ensureStructDefined(nodeType); ensureStructDefined(nodeType);
out << DecorateUniform(name, nodeType); const TName &nameWithMetadata = node->getName();
out << DecorateUniform(nameWithMetadata, nodeType);
} }
else if (qualifier == EvqAttribute || qualifier == EvqVertexIn) else if (qualifier == EvqAttribute || qualifier == EvqVertexIn)
{ {
...@@ -1577,6 +1578,42 @@ void OutputHLSL::outputEqual(Visit visit, const TType &type, TOperator op, TInfo ...@@ -1577,6 +1578,42 @@ void OutputHLSL::outputEqual(Visit visit, const TType &type, TOperator op, TInfo
} }
} }
bool OutputHLSL::ancestorEvaluatesToSamplerInStruct(Visit visit)
{
// Inside InVisit the current node is already in the path.
const unsigned int initialN = visit == InVisit ? 1u : 0u;
for (unsigned int n = initialN; getAncestorNode(n) != nullptr; ++n)
{
TIntermNode *ancestor = getAncestorNode(n);
const TIntermBinary *ancestorBinary = ancestor->getAsBinaryNode();
if (ancestorBinary == nullptr)
{
return false;
}
switch (ancestorBinary->getOp())
{
case EOpIndexDirectStruct:
{
const TStructure *structure = ancestorBinary->getLeft()->getType().getStruct();
const TIntermConstantUnion *index =
ancestorBinary->getRight()->getAsConstantUnion();
const TField *field = structure->fields()[index->getIConst(0)];
if (IsSampler(field->type()->getBasicType()))
{
return true;
}
break;
}
case EOpIndexDirect:
break;
default:
// Returning a sampler from indirect indexing is not supported.
return false;
}
}
return false;
}
bool OutputHLSL::visitBinary(Visit visit, TIntermBinary *node) bool OutputHLSL::visitBinary(Visit visit, TIntermBinary *node)
{ {
TInfoSinkBase &out = getInfoSink(); TInfoSinkBase &out = getInfoSink();
...@@ -1741,6 +1778,12 @@ bool OutputHLSL::visitBinary(Visit visit, TIntermBinary *node) ...@@ -1741,6 +1778,12 @@ bool OutputHLSL::visitBinary(Visit visit, TIntermBinary *node)
return false; return false;
} }
} }
else if (ancestorEvaluatesToSamplerInStruct(visit))
{
// All parts of an expression that access a sampler in a struct need to use _ as
// separator to access the sampler variable that has been moved out of the struct.
outputTriplet(out, visit, "", "_", "");
}
else else
{ {
outputTriplet(out, visit, "", "[", "]"); outputTriplet(out, visit, "", "[", "]");
...@@ -1753,15 +1796,41 @@ bool OutputHLSL::visitBinary(Visit visit, TIntermBinary *node) ...@@ -1753,15 +1796,41 @@ bool OutputHLSL::visitBinary(Visit visit, TIntermBinary *node)
outputTriplet(out, visit, "", "[", "]"); outputTriplet(out, visit, "", "[", "]");
break; break;
case EOpIndexDirectStruct: case EOpIndexDirectStruct:
if (visit == InVisit)
{ {
const TStructure* structure = node->getLeft()->getType().getStruct(); const TStructure* structure = node->getLeft()->getType().getStruct();
const TIntermConstantUnion* index = node->getRight()->getAsConstantUnion(); const TIntermConstantUnion* index = node->getRight()->getAsConstantUnion();
const TField* field = structure->fields()[index->getIConst(0)]; const TField* field = structure->fields()[index->getIConst(0)];
// In cases where indexing returns a sampler, we need to access the sampler variable
// that has been moved out of the struct.
bool indexingReturnsSampler = IsSampler(field->type()->getBasicType());
if (visit == PreVisit && indexingReturnsSampler)
{
// Samplers extracted from structs have "angle" prefix to avoid name conflicts.
// This prefix is only output at the beginning of the indexing expression, which
// may have multiple parts.
out << "angle";
}
if (!indexingReturnsSampler)
{
// All parts of an expression that access a sampler in a struct need to use _ as
// separator to access the sampler variable that has been moved out of the struct.
indexingReturnsSampler = ancestorEvaluatesToSamplerInStruct(visit);
}
if (visit == InVisit)
{
if (indexingReturnsSampler)
{
out << "_" + field->name();
}
else
{
out << "." + DecorateField(field->name(), *structure); out << "." + DecorateField(field->name(), *structure);
}
return false; return false;
} }
}
break; break;
case EOpIndexDirectInterfaceBlock: case EOpIndexDirectInterfaceBlock:
if (visit == InVisit) if (visit == InVisit)
...@@ -2114,6 +2183,40 @@ bool OutputHLSL::visitUnary(Visit visit, TIntermUnary *node) ...@@ -2114,6 +2183,40 @@ bool OutputHLSL::visitUnary(Visit visit, TIntermUnary *node)
return true; return true;
} }
TString OutputHLSL::samplerNamePrefixFromStruct(TIntermTyped *node)
{
if (node->getAsSymbolNode())
{
return node->getAsSymbolNode()->getSymbol();
}
TIntermBinary *nodeBinary = node->getAsBinaryNode();
switch (nodeBinary->getOp())
{
case EOpIndexDirect:
{
int index = nodeBinary->getRight()->getAsConstantUnion()->getIConst(0);
TInfoSinkBase prefixSink;
prefixSink << samplerNamePrefixFromStruct(nodeBinary->getLeft()) << "_" << index;
return TString(prefixSink.c_str());
}
case EOpIndexDirectStruct:
{
TStructure *s = nodeBinary->getLeft()->getAsTyped()->getType().getStruct();
int index = nodeBinary->getRight()->getAsConstantUnion()->getIConst(0);
const TField *field = s->fields()[index];
TInfoSinkBase prefixSink;
prefixSink << samplerNamePrefixFromStruct(nodeBinary->getLeft()) << "_"
<< field->name();
return TString(prefixSink.c_str());
}
default:
UNREACHABLE();
return TString("");
}
}
bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node) bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node)
{ {
TInfoSinkBase &out = getInfoSink(); TInfoSinkBase &out = getInfoSink();
...@@ -2485,8 +2588,8 @@ bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node) ...@@ -2485,8 +2588,8 @@ bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node)
for (TIntermSequence::iterator arg = arguments->begin(); arg != arguments->end(); arg++) for (TIntermSequence::iterator arg = arguments->begin(); arg != arguments->end(); arg++)
{ {
if (mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT && TIntermTyped *typedArg = (*arg)->getAsTyped();
IsSampler((*arg)->getAsTyped()->getBasicType())) if (mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT && IsSampler(typedArg->getBasicType()))
{ {
out << "texture_"; out << "texture_";
(*arg)->traverse(this); (*arg)->traverse(this);
...@@ -2495,6 +2598,30 @@ bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node) ...@@ -2495,6 +2598,30 @@ bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node)
(*arg)->traverse(this); (*arg)->traverse(this);
if (typedArg->getType().isStructureContainingSamplers())
{
const TType &argType = typedArg->getType();
TVector<TIntermSymbol *> samplerSymbols;
TString structName = samplerNamePrefixFromStruct(typedArg);
argType.createSamplerSymbols("angle_" + structName, "",
argType.isArray() ? argType.getArraySize() : 0,
&samplerSymbols, nullptr);
for (const TIntermSymbol *sampler : samplerSymbols)
{
if (mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
{
out << ", texture_" << sampler->getSymbol();
out << ", sampler_" << sampler->getSymbol();
}
else
{
// In case of HLSL 4.1+, this symbol is the sampler index, and in case
// of D3D9, it's the sampler variable.
out << ", " + sampler->getSymbol();
}
}
}
if (arg < arguments->end() - 1) if (arg < arguments->end() - 1)
{ {
out << ", "; out << ", ";
...@@ -3264,7 +3391,49 @@ TString OutputHLSL::argumentString(const TIntermSymbol *symbol) ...@@ -3264,7 +3391,49 @@ TString OutputHLSL::argumentString(const TIntermSymbol *symbol)
} }
} }
return QualifierString(qualifier) + " " + TypeString(type) + " " + nameStr + ArrayString(type); TStringStream argString;
argString << QualifierString(qualifier) << " " << TypeString(type) << " " << nameStr
<< ArrayString(type);
// If the structure parameter contains samplers, they need to be passed into the function as
// separate parameters. HLSL doesn't natively support samplers in structs.
if (type.isStructureContainingSamplers())
{
ASSERT(qualifier != EvqOut && qualifier != EvqInOut);
TVector<TIntermSymbol *> samplerSymbols;
type.createSamplerSymbols("angle" + nameStr, "", 0, &samplerSymbols, nullptr);
for (const TIntermSymbol *sampler : samplerSymbols)
{
if (mOutputType == SH_HLSL_4_1_OUTPUT)
{
argString << ", const uint " << sampler->getSymbol() << ArrayString(type);
}
else if (mOutputType == SH_HLSL_4_0_FL9_3_OUTPUT)
{
const TType &samplerType = sampler->getType();
ASSERT((!type.isArray() && !samplerType.isArray()) ||
type.getArraySize() == samplerType.getArraySize());
ASSERT(IsSampler(samplerType.getBasicType()));
argString << ", " << QualifierString(qualifier) << " "
<< TextureString(samplerType.getBasicType()) << " texture_"
<< sampler->getSymbol() << ArrayString(type) << ", "
<< QualifierString(qualifier) << " "
<< SamplerString(samplerType.getBasicType()) << " sampler_"
<< sampler->getSymbol() << ArrayString(type);
}
else
{
const TType &samplerType = sampler->getType();
ASSERT((!type.isArray() && !samplerType.isArray()) ||
type.getArraySize() == samplerType.getArraySize());
ASSERT(IsSampler(samplerType.getBasicType()));
argString << ", " << QualifierString(qualifier) << " " << TypeString(samplerType)
<< " " << sampler->getSymbol() << ArrayString(type);
}
}
}
return argString.str();
} }
TString OutputHLSL::initializer(const TType &type) TString OutputHLSL::initializer(const TType &type)
......
...@@ -240,6 +240,10 @@ class OutputHLSL : public TIntermTraverser ...@@ -240,6 +240,10 @@ class OutputHLSL : public TIntermTraverser
// with the other N parameters of the function. This is used to work around that arrays can't be // with the other N parameters of the function. This is used to work around that arrays can't be
// return values in HLSL. // return values in HLSL.
std::vector<ArrayHelperFunction> mArrayConstructIntoFunctions; std::vector<ArrayHelperFunction> mArrayConstructIntoFunctions;
private:
TString samplerNamePrefixFromStruct(TIntermTyped *node);
bool ancestorEvaluatesToSamplerInStruct(Visit visit);
}; };
} }
......
...@@ -363,23 +363,15 @@ bool ShGetInterfaceBlockRegister(const ShHandle handle, ...@@ -363,23 +363,15 @@ bool ShGetInterfaceBlockRegister(const ShHandle handle,
#endif // ANGLE_ENABLE_HLSL #endif // ANGLE_ENABLE_HLSL
} }
bool ShGetUniformRegister(const ShHandle handle, const std::map<std::string, unsigned int> *ShGetUniformRegisterMap(const ShHandle handle)
const std::string &uniformName,
unsigned int *indexOut)
{ {
#ifdef ANGLE_ENABLE_HLSL #ifdef ANGLE_ENABLE_HLSL
ASSERT(indexOut);
TranslatorHLSL *translator = GetTranslatorHLSLFromHandle(handle); TranslatorHLSL *translator = GetTranslatorHLSLFromHandle(handle);
ASSERT(translator); ASSERT(translator);
if (!translator->hasUniform(uniformName)) return translator->getUniformRegisterMap();
{
return false;
}
*indexOut = translator->getUniformRegister(uniformName);
return true;
#else #else
return false; static std::map<std::string, unsigned int> map;
return &map;
#endif // ANGLE_ENABLE_HLSL #endif // ANGLE_ENABLE_HLSL
} }
\ No newline at end of file
...@@ -182,28 +182,31 @@ TString StructureHLSL::define(const TStructure &structure, bool useHLSLRowMajorP ...@@ -182,28 +182,31 @@ TString StructureHLSL::define(const TStructure &structure, bool useHLSLRowMajorP
string += declareString + "\n" string += declareString + "\n"
"{\n"; "{\n";
for (unsigned int i = 0; i < fields.size(); i++) for (const TField *field : fields)
{
const TType &fieldType = *field->type();
if (!IsSampler(fieldType.getBasicType()))
{ {
const TField &field = *fields[i];
const TType &fieldType = *field.type();
const TStructure *fieldStruct = fieldType.getStruct(); const TStructure *fieldStruct = fieldType.getStruct();
const TString &fieldTypeString = fieldStruct ? const TString &fieldTypeString =
QualifiedStructNameString(*fieldStruct, useHLSLRowMajorPacking, fieldStruct ? QualifiedStructNameString(*fieldStruct, useHLSLRowMajorPacking,
useStd140Packing) : useStd140Packing)
TypeString(fieldType); : TypeString(fieldType);
if (padHelper) if (padHelper)
{ {
string += padHelper->prePaddingString(fieldType); string += padHelper->prePaddingString(fieldType);
} }
string += " " + fieldTypeString + " " + DecorateField(field.name(), structure) + ArrayString(fieldType) + ";\n"; string += " " + fieldTypeString + " " + DecorateField(field->name(), structure) +
ArrayString(fieldType) + ";\n";
if (padHelper) if (padHelper)
{ {
string += padHelper->postPaddingString(fieldType, useHLSLRowMajorPacking); string += padHelper->postPaddingString(fieldType, useHLSLRowMajorPacking);
} }
} }
}
// Nameless structs do not finish with a semicolon and newline, to leave room for an instance variable // Nameless structs do not finish with a semicolon and newline, to leave room for an instance variable
string += (isNameless ? "} " : "};\n"); string += (isNameless ? "} " : "};\n");
...@@ -265,9 +268,13 @@ TString StructureHLSL::addConstructor(const TType &type, ...@@ -265,9 +268,13 @@ TString StructureHLSL::addConstructor(const TType &type,
} }
const TFieldList &fields = structure->fields(); const TFieldList &fields = structure->fields();
for (unsigned int i = 0; i < fields.size(); i++) for (const TField *field : fields)
{
const TType *fieldType = field->type();
if (!IsSampler(fieldType->getBasicType()))
{ {
ctorParameters.push_back(*fields[i]->type()); ctorParameters.push_back(*fieldType);
}
} }
constructorFunctionName = TString(name); constructorFunctionName = TString(name);
} }
...@@ -310,7 +317,15 @@ TString StructureHLSL::addConstructor(const TType &type, ...@@ -310,7 +317,15 @@ TString StructureHLSL::addConstructor(const TType &type,
if (ctorType.getStruct()) if (ctorType.getStruct())
{ {
constructor += " " + name + " structure = {"; constructor += " " + name + " structure";
if (ctorParameters.empty())
{
constructor += ";\n";
}
else
{
constructor += " = { ";
}
} }
else else
{ {
...@@ -369,7 +384,15 @@ TString StructureHLSL::addConstructor(const TType &type, ...@@ -369,7 +384,15 @@ TString StructureHLSL::addConstructor(const TType &type,
} }
else else
{ {
size_t remainingComponents = ctorType.getObjectSize(); size_t remainingComponents = 0;
if (ctorType.getStruct())
{
remainingComponents = ctorParameters.size();
}
else
{
remainingComponents = ctorType.getObjectSize();
}
size_t parameterIndex = 0; size_t parameterIndex = 0;
while (remainingComponents > 0) while (remainingComponents > 0)
...@@ -382,10 +405,9 @@ TString StructureHLSL::addConstructor(const TType &type, ...@@ -382,10 +405,9 @@ TString StructureHLSL::addConstructor(const TType &type,
if (ctorType.getStruct()) if (ctorType.getStruct())
{ {
ASSERT(remainingComponents == parameterSize || moreParameters); ASSERT(remainingComponents == 1 || moreParameters);
ASSERT(parameterSize <= remainingComponents);
remainingComponents -= parameterSize; --remainingComponents;
} }
else if (parameter.isScalar()) else if (parameter.isScalar())
{ {
...@@ -461,7 +483,11 @@ TString StructureHLSL::addConstructor(const TType &type, ...@@ -461,7 +483,11 @@ TString StructureHLSL::addConstructor(const TType &type,
if (ctorType.getStruct()) if (ctorType.getStruct())
{ {
constructor += "};\n" if (!ctorParameters.empty())
{
constructor += "};\n";
}
constructor +=
" return structure;\n" " return structure;\n"
"}\n"; "}\n";
} }
......
...@@ -72,13 +72,7 @@ unsigned int TranslatorHLSL::getInterfaceBlockRegister(const std::string &interf ...@@ -72,13 +72,7 @@ unsigned int TranslatorHLSL::getInterfaceBlockRegister(const std::string &interf
return mInterfaceBlockRegisterMap.find(interfaceBlockName)->second; return mInterfaceBlockRegisterMap.find(interfaceBlockName)->second;
} }
bool TranslatorHLSL::hasUniform(const std::string &uniformName) const const std::map<std::string, unsigned int> *TranslatorHLSL::getUniformRegisterMap() const
{ {
return (mUniformRegisterMap.count(uniformName) > 0); return &mUniformRegisterMap;
}
unsigned int TranslatorHLSL::getUniformRegister(const std::string &uniformName) const
{
ASSERT(hasUniform(uniformName));
return mUniformRegisterMap.find(uniformName)->second;
} }
\ No newline at end of file
...@@ -18,8 +18,7 @@ class TranslatorHLSL : public TCompiler ...@@ -18,8 +18,7 @@ class TranslatorHLSL : public TCompiler
bool hasInterfaceBlock(const std::string &interfaceBlockName) const; bool hasInterfaceBlock(const std::string &interfaceBlockName) const;
unsigned int getInterfaceBlockRegister(const std::string &interfaceBlockName) const; unsigned int getInterfaceBlockRegister(const std::string &interfaceBlockName) const;
bool hasUniform(const std::string &uniformName) const; const std::map<std::string, unsigned int> *getUniformRegisterMap() const;
unsigned int getUniformRegister(const std::string &uniformName) const;
protected: protected:
void translate(TIntermNode *root, int compileOptions) override; void translate(TIntermNode *root, int compileOptions) override;
......
...@@ -9,6 +9,8 @@ ...@@ -9,6 +9,8 @@
#endif #endif
#include "compiler/translator/Types.h" #include "compiler/translator/Types.h"
#include "compiler/translator/InfoSink.h"
#include "compiler/translator/IntermNode.h"
#include <algorithm> #include <algorithm>
#include <climits> #include <climits>
...@@ -244,6 +246,76 @@ bool TStructure::containsSamplers() const ...@@ -244,6 +246,76 @@ bool TStructure::containsSamplers() const
return false; return false;
} }
void TStructure::createSamplerSymbols(const TString &structName,
const TString &structAPIName,
const int arrayOfStructsSize,
TVector<TIntermSymbol *> *outputSymbols,
TMap<TIntermSymbol *, TString> *outputSymbolsToAPINames) const
{
for (auto &field : *mFields)
{
const TType *fieldType = field->type();
if (IsSampler(fieldType->getBasicType()))
{
if (arrayOfStructsSize > 0)
{
for (int arrayIndex = 0; arrayIndex < arrayOfStructsSize; ++arrayIndex)
{
TStringStream name;
name << structName << "_" << arrayIndex << "_" << field->name();
TIntermSymbol *symbol = new TIntermSymbol(0, name.str(), *fieldType);
outputSymbols->push_back(symbol);
if (outputSymbolsToAPINames)
{
TStringStream apiName;
apiName << structAPIName << "[" << arrayIndex << "]." << field->name();
(*outputSymbolsToAPINames)[symbol] = apiName.str();
}
}
}
else
{
TString symbolName = structName + "_" + field->name();
TIntermSymbol *symbol = new TIntermSymbol(0, symbolName, *fieldType);
outputSymbols->push_back(symbol);
if (outputSymbolsToAPINames)
{
TString apiName = structAPIName + "." + field->name();
(*outputSymbolsToAPINames)[symbol] = apiName;
}
}
}
else if (fieldType->isStructureContainingSamplers())
{
int nestedArrayOfStructsSize = fieldType->isArray() ? fieldType->getArraySize() : 0;
if (arrayOfStructsSize > 0)
{
for (int arrayIndex = 0; arrayIndex < arrayOfStructsSize; ++arrayIndex)
{
TStringStream fieldName;
fieldName << structName << "_" << arrayIndex << "_" << field->name();
TStringStream fieldAPIName;
if (outputSymbolsToAPINames)
{
fieldAPIName << structAPIName << "[" << arrayIndex << "]." << field->name();
}
fieldType->createSamplerSymbols(fieldName.str(), fieldAPIName.str(),
nestedArrayOfStructsSize, outputSymbols,
outputSymbolsToAPINames);
}
}
else
{
fieldType->createSamplerSymbols(
structName + "_" + field->name(), structAPIName + "." + field->name(),
nestedArrayOfStructsSize, outputSymbols, outputSymbolsToAPINames);
}
}
}
}
TString TFieldListCollection::buildMangledName(const TString &mangledNamePrefix) const TString TFieldListCollection::buildMangledName(const TString &mangledNamePrefix) const
{ {
TString mangledName(mangledNamePrefix); TString mangledName(mangledNamePrefix);
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
struct TPublicType; struct TPublicType;
class TType; class TType;
class TSymbol; class TSymbol;
class TIntermSymbol;
class TField : angle::NonCopyable class TField : angle::NonCopyable
{ {
...@@ -120,6 +121,12 @@ class TStructure : public TFieldListCollection ...@@ -120,6 +121,12 @@ class TStructure : public TFieldListCollection
bool containsType(TBasicType t) const; bool containsType(TBasicType t) const;
bool containsSamplers() const; bool containsSamplers() const;
void createSamplerSymbols(const TString &structName,
const TString &structAPIName,
const int arrayOfStructsSize,
TVector<TIntermSymbol *> *outputSymbols,
TMap<TIntermSymbol *, TString> *outputSymbolsToAPINames) const;
bool equals(const TStructure &other) const; bool equals(const TStructure &other) const;
void setUniqueId(int uniqueId) void setUniqueId(int uniqueId)
...@@ -529,6 +536,17 @@ class TType ...@@ -529,6 +536,17 @@ class TType
return structure ? structure->containsSamplers() : false; return structure ? structure->containsSamplers() : false;
} }
void createSamplerSymbols(const TString &structName,
const TString &structAPIName,
const int arrayOfStructsSize,
TVector<TIntermSymbol *> *outputSymbols,
TMap<TIntermSymbol *, TString> *outputSymbolsToAPINames) const
{
ASSERT(structure != nullptr && structure->containsSamplers());
structure->createSamplerSymbols(structName, structAPIName, arrayOfStructsSize,
outputSymbols, outputSymbolsToAPINames);
}
// Initializes all lazily-initialized members. // Initializes all lazily-initialized members.
void realize() void realize()
{ {
......
...@@ -89,13 +89,12 @@ const Uniform *UniformHLSL::findUniformByName(const TString &name) const ...@@ -89,13 +89,12 @@ const Uniform *UniformHLSL::findUniformByName(const TString &name) const
} }
} }
UNREACHABLE(); return nullptr;
return NULL;
} }
unsigned int UniformHLSL::declareUniformAndAssignRegister(const TType &type, unsigned int UniformHLSL::assignUniformRegister(const TType &type,
const TString &name, const TString &name,
unsigned int *registerCount) unsigned int *outRegisterCount)
{ {
unsigned int registerIndex = (IsSampler(type.getBasicType()) ? mSamplerRegister : mUniformRegister); unsigned int registerIndex = (IsSampler(type.getBasicType()) ? mSamplerRegister : mUniformRegister);
...@@ -104,30 +103,45 @@ unsigned int UniformHLSL::declareUniformAndAssignRegister(const TType &type, ...@@ -104,30 +103,45 @@ unsigned int UniformHLSL::declareUniformAndAssignRegister(const TType &type,
mUniformRegisterMap[uniform->name] = registerIndex; mUniformRegisterMap[uniform->name] = registerIndex;
ASSERT(registerCount); unsigned int registerCount = HLSLVariableRegisterCount(*uniform, mOutputType);
*registerCount = HLSLVariableRegisterCount(*uniform, mOutputType);
if (gl::IsSamplerType(uniform->type)) if (gl::IsSamplerType(uniform->type))
{ {
mSamplerRegister += *registerCount; mSamplerRegister += registerCount;
} }
else else
{ {
mUniformRegister += *registerCount; mUniformRegister += registerCount;
}
if (outRegisterCount)
{
*outRegisterCount = registerCount;
} }
return registerIndex; return registerIndex;
} }
unsigned int UniformHLSL::declareUniformAndAssignRegister(const TType &type, const TString &name) unsigned int UniformHLSL::assignSamplerInStructUniformRegister(const TType &type,
const TString &name,
unsigned int *outRegisterCount)
{ {
unsigned int registerCount; // Sampler that is a field of a uniform structure.
return declareUniformAndAssignRegister(type, name, &registerCount); ASSERT(IsSampler(type.getBasicType()));
unsigned int registerIndex = mSamplerRegister;
mUniformRegisterMap[std::string(name.c_str())] = registerIndex;
unsigned int registerCount = type.isArray() ? type.getArraySize() : 1;
mSamplerRegister += registerCount;
if (outRegisterCount)
{
*outRegisterCount = registerCount;
}
return registerIndex;
} }
void UniformHLSL::outputHLSLSamplerUniformGroup(TInfoSinkBase &out, void UniformHLSL::outputHLSLSamplerUniformGroup(
TInfoSinkBase &out,
const HLSLTextureSamplerGroup textureGroup, const HLSLTextureSamplerGroup textureGroup,
const TVector<const TIntermSymbol *> &group, const TVector<const TIntermSymbol *> &group,
const TMap<const TIntermSymbol *, TString> &samplerInStructSymbolsToAPINames,
unsigned int *groupTextureRegisterIndex) unsigned int *groupTextureRegisterIndex)
{ {
if (group.empty()) if (group.empty())
...@@ -140,9 +154,23 @@ void UniformHLSL::outputHLSLSamplerUniformGroup(TInfoSinkBase &out, ...@@ -140,9 +154,23 @@ void UniformHLSL::outputHLSLSamplerUniformGroup(TInfoSinkBase &out,
const TType &type = uniform->getType(); const TType &type = uniform->getType();
const TString &name = uniform->getSymbol(); const TString &name = uniform->getSymbol();
unsigned int registerCount; unsigned int registerCount;
unsigned int samplerArrayIndex =
declareUniformAndAssignRegister(type, name, &registerCount); // The uniform might be just a regular sampler or one extracted from a struct.
unsigned int samplerArrayIndex = 0u;
const Uniform *uniformByName = findUniformByName(name);
if (uniformByName)
{
samplerArrayIndex = assignUniformRegister(type, name, &registerCount);
}
else
{
ASSERT(samplerInStructSymbolsToAPINames.find(uniform) !=
samplerInStructSymbolsToAPINames.end());
samplerArrayIndex = assignSamplerInStructUniformRegister(
type, samplerInStructSymbolsToAPINames.at(uniform), &registerCount);
}
groupRegisterCount += registerCount; groupRegisterCount += registerCount;
if (type.isArray()) if (type.isArray())
{ {
out << "static const uint " << DecorateIfNeeded(uniform->getName()) << ArrayString(type) out << "static const uint " << DecorateIfNeeded(uniform->getName()) << ArrayString(type)
...@@ -179,6 +207,44 @@ void UniformHLSL::outputHLSLSamplerUniformGroup(TInfoSinkBase &out, ...@@ -179,6 +207,44 @@ void UniformHLSL::outputHLSLSamplerUniformGroup(TInfoSinkBase &out,
*groupTextureRegisterIndex += groupRegisterCount; *groupTextureRegisterIndex += groupRegisterCount;
} }
void UniformHLSL::outputHLSL4_0_FL9_3Sampler(TInfoSinkBase &out,
const TType &type,
const TName &name,
const unsigned int registerIndex)
{
out << "uniform " << SamplerString(type.getBasicType()) << " sampler_"
<< DecorateUniform(name, type) << ArrayString(type) << " : register(s" << str(registerIndex)
<< ");\n";
out << "uniform " << TextureString(type.getBasicType()) << " texture_"
<< DecorateUniform(name, type) << ArrayString(type) << " : register(t" << str(registerIndex)
<< ");\n";
}
void UniformHLSL::outputUniform(TInfoSinkBase &out,
const TType &type,
const TName &name,
const unsigned int registerIndex)
{
const TStructure *structure = type.getStruct();
// If this is a nameless struct, we need to use its full definition, rather than its (empty)
// name.
// TypeString() will invoke defineNameless in this case; qualifier prefixes are unnecessary for
// nameless structs in ES, as nameless structs cannot be used anywhere that layout qualifiers
// are permitted.
const TString &typeName = ((structure && !structure->name().empty())
? QualifiedStructNameString(*structure, false, false)
: TypeString(type));
const TString &registerString =
TString("register(") + UniformRegisterPrefix(type) + str(registerIndex) + ")";
out << "uniform " << typeName << " ";
out << DecorateUniform(name, type);
out << ArrayString(type) << " : " << registerString << ";\n";
}
void UniformHLSL::uniformsHeader(TInfoSinkBase &out, void UniformHLSL::uniformsHeader(TInfoSinkBase &out,
ShShaderOutput outputType, ShShaderOutput outputType,
const ReferencedSymbols &referencedUniforms) const ReferencedSymbols &referencedUniforms)
...@@ -190,14 +256,14 @@ void UniformHLSL::uniformsHeader(TInfoSinkBase &out, ...@@ -190,14 +256,14 @@ void UniformHLSL::uniformsHeader(TInfoSinkBase &out,
// In the case of HLSL 4, sampler uniforms need to be grouped by type before the code is // In the case of HLSL 4, sampler uniforms need to be grouped by type before the code is
// written. They are grouped based on the combination of the HLSL texture type and // written. They are grouped based on the combination of the HLSL texture type and
// HLSL sampler type, enumerated in HLSLTextureSamplerGroup. // HLSL sampler type, enumerated in HLSLTextureSamplerGroup.
TVector<TVector<const TIntermSymbol *>> groupedSamplerUniforms; TVector<TVector<const TIntermSymbol *>> groupedSamplerUniforms(HLSL_TEXTURE_MAX + 1);
groupedSamplerUniforms.resize(HLSL_TEXTURE_MAX + 1); TMap<const TIntermSymbol *, TString> samplerInStructSymbolsToAPINames;
for (auto &uniformIt : referencedUniforms) for (auto &uniformIt : referencedUniforms)
{ {
// Output regular uniforms. Group sampler uniforms by type. // Output regular uniforms. Group sampler uniforms by type.
const TIntermSymbol &uniform = *uniformIt.second; const TIntermSymbol &uniform = *uniformIt.second;
const TType &type = uniform.getType(); const TType &type = uniform.getType();
const TString &name = uniform.getSymbol(); const TName &name = uniform.getName();
if (outputType == SH_HLSL_4_1_OUTPUT && IsSampler(type.getBasicType())) if (outputType == SH_HLSL_4_1_OUTPUT && IsSampler(type.getBasicType()))
{ {
...@@ -206,29 +272,49 @@ void UniformHLSL::uniformsHeader(TInfoSinkBase &out, ...@@ -206,29 +272,49 @@ void UniformHLSL::uniformsHeader(TInfoSinkBase &out,
} }
else if (outputType == SH_HLSL_4_0_FL9_3_OUTPUT && IsSampler(type.getBasicType())) else if (outputType == SH_HLSL_4_0_FL9_3_OUTPUT && IsSampler(type.getBasicType()))
{ {
unsigned int registerIndex = declareUniformAndAssignRegister(type, name); unsigned int registerIndex = assignUniformRegister(type, name.getString(), nullptr);
out << "uniform " << SamplerString(type.getBasicType()) << " sampler_" outputHLSL4_0_FL9_3Sampler(out, type, name, registerIndex);
<< DecorateUniform(name, type) << ArrayString(type) << " : register(s"
<< str(registerIndex) << ");\n";
out << "uniform " << TextureString(type.getBasicType()) << " texture_"
<< DecorateUniform(name, type) << ArrayString(type) << " : register(t"
<< str(registerIndex) << ");\n";
} }
else else
{ {
unsigned int registerIndex = declareUniformAndAssignRegister(type, name); if (type.isStructureContainingSamplers())
const TStructure *structure = type.getStruct(); {
// If this is a nameless struct, we need to use its full definition, rather than its (empty) name. TVector<TIntermSymbol *> samplerSymbols;
// TypeString() will invoke defineNameless in this case; qualifier prefixes are unnecessary for TMap<TIntermSymbol *, TString> symbolsToAPINames;
// nameless structs in ES, as nameless structs cannot be used anywhere that layout qualifiers are int arrayOfStructsSize = type.isArray() ? type.getArraySize() : 0;
// permitted. type.createSamplerSymbols("angle_" + name.getString(), name.getString(),
const TString &typeName = ((structure && !structure->name().empty()) ? arrayOfStructsSize, &samplerSymbols, &symbolsToAPINames);
QualifiedStructNameString(*structure, false, false) : TypeString(type)); for (TIntermSymbol *sampler : samplerSymbols)
{
const TType &samplerType = sampler->getType();
const TString &registerString = TString("register(") + UniformRegisterPrefix(type) + str(registerIndex) + ")"; // Will use angle_ prefix instead of regular prefix.
sampler->setInternal(true);
const TName &samplerName = sampler->getName();
out << "uniform " << typeName << " " << DecorateUniform(name, type) << ArrayString(type) if (outputType == SH_HLSL_4_1_OUTPUT)
<< " : " << registerString << ";\n"; {
HLSLTextureSamplerGroup group = TextureGroup(samplerType.getBasicType());
groupedSamplerUniforms[group].push_back(sampler);
samplerInStructSymbolsToAPINames[sampler] = symbolsToAPINames[sampler];
}
else if (outputType == SH_HLSL_4_0_FL9_3_OUTPUT)
{
unsigned int registerIndex = assignSamplerInStructUniformRegister(
samplerType, symbolsToAPINames[sampler], nullptr);
outputHLSL4_0_FL9_3Sampler(out, samplerType, samplerName, registerIndex);
}
else
{
ASSERT(outputType == SH_HLSL_3_0_OUTPUT);
unsigned int registerIndex = assignSamplerInStructUniformRegister(
samplerType, symbolsToAPINames[sampler], nullptr);
outputUniform(out, samplerType, samplerName, registerIndex);
}
}
}
unsigned int registerIndex = assignUniformRegister(type, name.getString(), nullptr);
outputUniform(out, type, name, registerIndex);
} }
} }
...@@ -239,9 +325,9 @@ void UniformHLSL::uniformsHeader(TInfoSinkBase &out, ...@@ -239,9 +325,9 @@ void UniformHLSL::uniformsHeader(TInfoSinkBase &out,
ASSERT(HLSL_TEXTURE_MIN == HLSL_TEXTURE_2D); ASSERT(HLSL_TEXTURE_MIN == HLSL_TEXTURE_2D);
for (int groupId = HLSL_TEXTURE_MIN; groupId < HLSL_TEXTURE_MAX; ++groupId) for (int groupId = HLSL_TEXTURE_MIN; groupId < HLSL_TEXTURE_MAX; ++groupId)
{ {
outputHLSLSamplerUniformGroup(out, HLSLTextureSamplerGroup(groupId), outputHLSLSamplerUniformGroup(
groupedSamplerUniforms[groupId], out, HLSLTextureSamplerGroup(groupId), groupedSamplerUniforms[groupId],
&groupTextureRegisterIndex); samplerInStructSymbolsToAPINames, &groupTextureRegisterIndex);
} }
} }
} }
......
...@@ -24,10 +24,6 @@ class UniformHLSL : angle::NonCopyable ...@@ -24,10 +24,6 @@ class UniformHLSL : angle::NonCopyable
void reserveUniformRegisters(unsigned int registerCount); void reserveUniformRegisters(unsigned int registerCount);
void reserveInterfaceBlockRegisters(unsigned int registerCount); void reserveInterfaceBlockRegisters(unsigned int registerCount);
void outputHLSLSamplerUniformGroup(TInfoSinkBase &out,
const HLSLTextureSamplerGroup textureGroup,
const TVector<const TIntermSymbol *> &group,
unsigned int *groupTextureRegisterIndex);
void uniformsHeader(TInfoSinkBase &out, void uniformsHeader(TInfoSinkBase &out,
ShShaderOutput outputType, ShShaderOutput outputType,
const ReferencedSymbols &referencedUniforms); const ReferencedSymbols &referencedUniforms);
...@@ -55,11 +51,30 @@ class UniformHLSL : angle::NonCopyable ...@@ -55,11 +51,30 @@ class UniformHLSL : angle::NonCopyable
TString interfaceBlockStructString(const TInterfaceBlock &interfaceBlock); TString interfaceBlockStructString(const TInterfaceBlock &interfaceBlock);
const Uniform *findUniformByName(const TString &name) const; const Uniform *findUniformByName(const TString &name) const;
void outputHLSL4_0_FL9_3Sampler(TInfoSinkBase &out,
const TType &type,
const TName &name,
const unsigned int registerIndex);
void outputUniform(TInfoSinkBase &out,
const TType &type,
const TName &name,
const unsigned int registerIndex);
// Returns the uniform's register index // Returns the uniform's register index
unsigned int declareUniformAndAssignRegister(const TType &type, unsigned int assignUniformRegister(const TType &type,
const TString &name, const TString &name,
unsigned int *registerCount); unsigned int *outRegisterCount);
unsigned int declareUniformAndAssignRegister(const TType &type, const TString &name); unsigned int assignSamplerInStructUniformRegister(const TType &type,
const TString &name,
unsigned int *outRegisterCount);
void outputHLSLSamplerUniformGroup(
TInfoSinkBase &out,
const HLSLTextureSamplerGroup textureGroup,
const TVector<const TIntermSymbol *> &group,
const TMap<const TIntermSymbol *, TString> &samplerInStructSymbolsToAPINames,
unsigned int *groupTextureRegisterIndex);
unsigned int mUniformRegister; unsigned int mUniformRegister;
unsigned int mInterfaceBlockRegister; unsigned int mInterfaceBlockRegister;
......
...@@ -179,14 +179,14 @@ TString TextureTypeSuffix(const TBasicType type) ...@@ -179,14 +179,14 @@ TString TextureTypeSuffix(const TBasicType type)
} }
} }
TString DecorateUniform(const TString &string, const TType &type) TString DecorateUniform(const TName &name, const TType &type)
{ {
if (type.getBasicType() == EbtSamplerExternalOES) if (type.getBasicType() == EbtSamplerExternalOES)
{ {
return "ex_" + string; return "ex_" + name.getString();
} }
return Decorate(string); return DecorateIfNeeded(name);
} }
TString DecorateField(const TString &string, const TStructure &structure) TString DecorateField(const TString &string, const TStructure &structure)
......
...@@ -64,7 +64,7 @@ TString Decorate(const TString &string); ...@@ -64,7 +64,7 @@ TString Decorate(const TString &string);
TString DecorateIfNeeded(const TName &name); TString DecorateIfNeeded(const TName &name);
// Decorates and also unmangles the function name // Decorates and also unmangles the function name
TString DecorateFunctionIfNeeded(const TName &name); TString DecorateFunctionIfNeeded(const TName &name);
TString DecorateUniform(const TString &string, const TType &type); TString DecorateUniform(const TName &name, const TType &type);
TString DecorateField(const TString &string, const TStructure &structure); TString DecorateField(const TString &string, const TStructure &structure);
TString DecoratePrivate(const TString &privateText); TString DecoratePrivate(const TString &privateText);
TString TypeString(const TType &type); TString TypeString(const TType &type);
......
...@@ -1347,16 +1347,6 @@ LinkResult ProgramD3D::link(const gl::Data &data, gl::InfoLog &infoLog) ...@@ -1347,16 +1347,6 @@ LinkResult ProgramD3D::link(const gl::Data &data, gl::InfoLog &infoLog)
{ {
reset(); reset();
// TODO(jmadill): structures containing samplers
for (const gl::LinkedUniform &linkedUniform : mData.getUniforms())
{
if (linkedUniform.isSampler() && linkedUniform.isField())
{
infoLog << "Structures containing samplers not currently supported in D3D.";
return LinkResult(false, gl::Error(GL_NO_ERROR));
}
}
const gl::Shader *vertexShader = mData.getAttachedVertexShader(); const gl::Shader *vertexShader = mData.getAttachedVertexShader();
const gl::Shader *fragmentShader = mData.getAttachedFragmentShader(); const gl::Shader *fragmentShader = mData.getAttachedFragmentShader();
...@@ -1820,7 +1810,8 @@ void ProgramD3D::defineUniformBase(const gl::Shader *shader, ...@@ -1820,7 +1810,8 @@ void ProgramD3D::defineUniformBase(const gl::Shader *shader,
const sh::Uniform &uniform, const sh::Uniform &uniform,
D3DUniformMap *uniformMap) D3DUniformMap *uniformMap)
{ {
if (uniform.isBuiltIn()) // Samplers get their registers assigned in assignAllSamplerRegisters.
if (uniform.isBuiltIn() || gl::IsSamplerType(uniform.type))
{ {
defineUniform(shader->getType(), uniform, uniform.name, nullptr, uniformMap); defineUniform(shader->getType(), uniform, uniform.name, nullptr, uniformMap);
return; return;
...@@ -1869,8 +1860,18 @@ void ProgramD3D::defineUniform(GLenum shaderType, ...@@ -1869,8 +1860,18 @@ void ProgramD3D::defineUniform(GLenum shaderType,
const sh::ShaderVariable &field = uniform.fields[fieldIndex]; const sh::ShaderVariable &field = uniform.fields[fieldIndex];
const std::string &fieldFullName = (fullName + elementString + "." + field.name); const std::string &fieldFullName = (fullName + elementString + "." + field.name);
// Samplers get their registers assigned in assignAllSamplerRegisters.
// Also they couldn't use the same encoder as the rest of the struct, since they are
// extracted out of the struct by the shader translator.
if (gl::IsSamplerType(field.type))
{
defineUniform(shaderType, field, fieldFullName, nullptr, uniformMap);
}
else
{
defineUniform(shaderType, field, fieldFullName, encoder, uniformMap); defineUniform(shaderType, field, fieldFullName, encoder, uniformMap);
} }
}
if (encoder) if (encoder)
encoder->exitAggregateType(); encoder->exitAggregateType();
...@@ -2066,7 +2067,7 @@ size_t ProgramD3D::getUniformBlockInfo(const sh::InterfaceBlock &interfaceBlock) ...@@ -2066,7 +2067,7 @@ size_t ProgramD3D::getUniformBlockInfo(const sh::InterfaceBlock &interfaceBlock)
void ProgramD3D::assignAllSamplerRegisters() void ProgramD3D::assignAllSamplerRegisters()
{ {
for (const D3DUniform *d3dUniform : mD3DUniforms) for (D3DUniform *d3dUniform : mD3DUniforms)
{ {
if (d3dUniform->isSampler()) if (d3dUniform->isSampler())
{ {
...@@ -2075,20 +2076,23 @@ void ProgramD3D::assignAllSamplerRegisters() ...@@ -2075,20 +2076,23 @@ void ProgramD3D::assignAllSamplerRegisters()
} }
} }
void ProgramD3D::assignSamplerRegisters(const D3DUniform *d3dUniform) void ProgramD3D::assignSamplerRegisters(D3DUniform *d3dUniform)
{ {
ASSERT(d3dUniform->isSampler()); ASSERT(d3dUniform->isSampler());
ASSERT(d3dUniform->vsRegisterIndex != GL_INVALID_INDEX || const ShaderD3D *vertexShaderD3D = GetImplAs<ShaderD3D>(mData.getAttachedVertexShader());
d3dUniform->psRegisterIndex != GL_INVALID_INDEX); const ShaderD3D *fragmentShaderD3D = GetImplAs<ShaderD3D>(mData.getAttachedFragmentShader());
ASSERT(vertexShaderD3D->hasUniform(d3dUniform) || fragmentShaderD3D->hasUniform(d3dUniform));
if (d3dUniform->vsRegisterIndex != GL_INVALID_INDEX) if (vertexShaderD3D->hasUniform(d3dUniform))
{ {
d3dUniform->vsRegisterIndex = vertexShaderD3D->getUniformRegister(d3dUniform->name);
ASSERT(d3dUniform->vsRegisterIndex != GL_INVALID_INDEX);
AssignSamplers(d3dUniform->vsRegisterIndex, d3dUniform->type, d3dUniform->arraySize, AssignSamplers(d3dUniform->vsRegisterIndex, d3dUniform->type, d3dUniform->arraySize,
mSamplersVS, &mUsedVertexSamplerRange); mSamplersVS, &mUsedVertexSamplerRange);
} }
if (fragmentShaderD3D->hasUniform(d3dUniform))
if (d3dUniform->psRegisterIndex != GL_INVALID_INDEX)
{ {
d3dUniform->psRegisterIndex = fragmentShaderD3D->getUniformRegister(d3dUniform->name);
ASSERT(d3dUniform->psRegisterIndex != GL_INVALID_INDEX);
AssignSamplers(d3dUniform->psRegisterIndex, d3dUniform->type, d3dUniform->arraySize, AssignSamplers(d3dUniform->psRegisterIndex, d3dUniform->type, d3dUniform->arraySize,
mSamplersPS, &mUsedPixelSamplerRange); mSamplersPS, &mUsedPixelSamplerRange);
} }
......
...@@ -322,7 +322,7 @@ class ProgramD3D : public ProgramImpl ...@@ -322,7 +322,7 @@ class ProgramD3D : public ProgramImpl
sh::HLSLBlockEncoder *encoder, sh::HLSLBlockEncoder *encoder,
D3DUniformMap *uniformMap); D3DUniformMap *uniformMap);
void assignAllSamplerRegisters(); void assignAllSamplerRegisters();
void assignSamplerRegisters(const D3DUniform *d3dUniform); void assignSamplerRegisters(D3DUniform *d3dUniform);
static void AssignSamplers(unsigned int startSamplerIndex, static void AssignSamplers(unsigned int startSamplerIndex,
GLenum samplerType, GLenum samplerType,
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include "libANGLE/Shader.h" #include "libANGLE/Shader.h"
#include "libANGLE/features.h" #include "libANGLE/features.h"
#include "libANGLE/renderer/d3d/RendererD3D.h" #include "libANGLE/renderer/d3d/RendererD3D.h"
#include "libANGLE/renderer/d3d/ProgramD3D.h"
// Definitions local to the translation unit // Definitions local to the translation unit
namespace namespace
...@@ -139,6 +140,18 @@ int ShaderD3D::prepareSourceAndReturnOptions(std::stringstream *shaderSourceStre ...@@ -139,6 +140,18 @@ int ShaderD3D::prepareSourceAndReturnOptions(std::stringstream *shaderSourceStre
return additionalOptions; return additionalOptions;
} }
bool ShaderD3D::hasUniform(const D3DUniform *d3dUniform) const
{
return mUniformRegisterMap.find(d3dUniform->name) != mUniformRegisterMap.end();
}
const std::map<std::string, unsigned int> &GetUniformRegisterMap(
const std::map<std::string, unsigned int> *uniformRegisterMap)
{
ASSERT(uniformRegisterMap);
return *uniformRegisterMap;
}
bool ShaderD3D::postTranslateCompile(gl::Compiler *compiler, std::string *infoLog) bool ShaderD3D::postTranslateCompile(gl::Compiler *compiler, std::string *infoLog)
{ {
// TODO(jmadill): We shouldn't need to cache this. // TODO(jmadill): We shouldn't need to cache this.
...@@ -164,19 +177,7 @@ bool ShaderD3D::postTranslateCompile(gl::Compiler *compiler, std::string *infoLo ...@@ -164,19 +177,7 @@ bool ShaderD3D::postTranslateCompile(gl::Compiler *compiler, std::string *infoLo
ShHandle compilerHandle = compiler->getCompilerHandle(mData.getShaderType()); ShHandle compilerHandle = compiler->getCompilerHandle(mData.getShaderType());
for (const sh::Uniform &uniform : mData.getUniforms()) mUniformRegisterMap = GetUniformRegisterMap(ShGetUniformRegisterMap(compilerHandle));
{
if (uniform.staticUse && !uniform.isBuiltIn())
{
unsigned int index = static_cast<unsigned int>(-1);
bool getUniformRegisterResult =
ShGetUniformRegister(compilerHandle, uniform.name, &index);
UNUSED_ASSERTION_VARIABLE(getUniformRegisterResult);
ASSERT(getUniformRegisterResult);
mUniformRegisterMap[uniform.name] = index;
}
}
for (const sh::InterfaceBlock &interfaceBlock : mData.getInterfaceBlocks()) for (const sh::InterfaceBlock &interfaceBlock : mData.getInterfaceBlocks())
{ {
......
...@@ -18,6 +18,7 @@ namespace rx ...@@ -18,6 +18,7 @@ namespace rx
class DynamicHLSL; class DynamicHLSL;
class RendererD3D; class RendererD3D;
struct D3DCompilerWorkarounds; struct D3DCompilerWorkarounds;
struct D3DUniform;
class ShaderD3D : public ShaderImpl class ShaderD3D : public ShaderImpl
{ {
...@@ -33,7 +34,13 @@ class ShaderD3D : public ShaderImpl ...@@ -33,7 +34,13 @@ class ShaderD3D : public ShaderImpl
// D3D-specific methods // D3D-specific methods
void uncompile(); void uncompile();
bool hasUniform(const D3DUniform *d3dUniform) const;
// Query regular uniforms with their name. Query sampler fields of structs with field selection
// using dot (.) operator.
unsigned int getUniformRegister(const std::string &uniformName) const; unsigned int getUniformRegister(const std::string &uniformName) const;
unsigned int getInterfaceBlockRegister(const std::string &blockName) const; unsigned int getInterfaceBlockRegister(const std::string &blockName) const;
void appendDebugInfo(const std::string &info) const { mDebugInfo += info; } void appendDebugInfo(const std::string &info) const { mDebugInfo += info; }
......
...@@ -101,12 +101,6 @@ ...@@ -101,12 +101,6 @@
1017 WIN : dEQP-GLES2.functional.shaders.loops.while_constant_iterations.nested_tricky_dataflow_* = FAIL 1017 WIN : dEQP-GLES2.functional.shaders.loops.while_constant_iterations.nested_tricky_dataflow_* = FAIL
1017 WIN : dEQP-GLES2.functional.shaders.loops.do_while_constant_iterations.nested_tricky_dataflow_* = FAIL 1017 WIN : dEQP-GLES2.functional.shaders.loops.do_while_constant_iterations.nested_tricky_dataflow_* = FAIL
989 WIN : dEQP-GLES2.functional.shaders.preprocessor.pragmas.invalid_pragma_invalid_* = FAIL 989 WIN : dEQP-GLES2.functional.shaders.preprocessor.pragmas.invalid_pragma_invalid_* = FAIL
504 WIN : dEQP-GLES2.functional.shaders.struct.uniform.sampler_vertex = FAIL
504 WIN : dEQP-GLES2.functional.shaders.struct.uniform.sampler_fragment = FAIL
504 WIN : dEQP-GLES2.functional.shaders.struct.uniform.sampler_nested_vertex = FAIL
504 WIN : dEQP-GLES2.functional.shaders.struct.uniform.sampler_nested_fragment = FAIL
504 WIN : dEQP-GLES2.functional.shaders.struct.uniform.sampler_array_vertex = FAIL
504 WIN : dEQP-GLES2.functional.shaders.struct.uniform.sampler_array_fragment = FAIL
1018 WIN : dEQP-GLES2.functional.shaders.texture_functions.vertex.texturecubelod = FAIL 1018 WIN : dEQP-GLES2.functional.shaders.texture_functions.vertex.texturecubelod = FAIL
1020 WIN : dEQP-GLES2.functional.texture.mipmap.cube.basic.linear_nearest = FAIL 1020 WIN : dEQP-GLES2.functional.texture.mipmap.cube.basic.linear_nearest = FAIL
1020 WIN : dEQP-GLES2.functional.texture.mipmap.cube.basic.linear_linear = FAIL 1020 WIN : dEQP-GLES2.functional.texture.mipmap.cube.basic.linear_linear = FAIL
...@@ -144,51 +138,6 @@ ...@@ -144,51 +138,6 @@
1025 WIN : dEQP-GLES2.functional.fragment_ops.blend.equation_src_func_dst_func.reverse_subtract_constant_alpha_one_minus_constant_color = FAIL 1025 WIN : dEQP-GLES2.functional.fragment_ops.blend.equation_src_func_dst_func.reverse_subtract_constant_alpha_one_minus_constant_color = FAIL
1025 WIN : dEQP-GLES2.functional.fragment_ops.blend.equation_src_func_dst_func.reverse_subtract_one_minus_constant_alpha_constant_color = FAIL 1025 WIN : dEQP-GLES2.functional.fragment_ops.blend.equation_src_func_dst_func.reverse_subtract_one_minus_constant_alpha_constant_color = FAIL
1025 WIN : dEQP-GLES2.functional.fragment_ops.blend.equation_src_func_dst_func.reverse_subtract_one_minus_constant_alpha_one_minus_constant_color = FAIL 1025 WIN : dEQP-GLES2.functional.fragment_ops.blend.equation_src_func_dst_func.reverse_subtract_one_minus_constant_alpha_one_minus_constant_color = FAIL
504 WIN : dEQP-GLES2.functional.uniform_api.info_query.basic_struct.sampler2D_samplerCube_* = FAIL
504 WIN : dEQP-GLES2.functional.uniform_api.info_query.struct_in_array.sampler2D_samplerCube_* = FAIL
504 WIN : dEQP-GLES2.functional.uniform_api.info_query.array_in_struct.sampler2D_samplerCube_* = FAIL
504 WIN : dEQP-GLES2.functional.uniform_api.info_query.nested_structs_arrays.sampler2D_samplerCube_* = FAIL
504 WIN : dEQP-GLES2.functional.uniform_api.info_query.unused_uniforms.sampler2D_samplerCube_* = FAIL
1031 WIN : dEQP-GLES2.functional.uniform_api.random.3 = FAIL
1031 WIN : dEQP-GLES2.functional.uniform_api.random.13 = FAIL
1031 WIN : dEQP-GLES2.functional.uniform_api.random.21 = FAIL
1031 WIN : dEQP-GLES2.functional.uniform_api.random.23 = FAIL
1031 WIN : dEQP-GLES2.functional.uniform_api.random.24 = FAIL
1031 WIN : dEQP-GLES2.functional.uniform_api.random.25 = FAIL
1031 WIN : dEQP-GLES2.functional.uniform_api.random.27 = FAIL
1031 WIN : dEQP-GLES2.functional.uniform_api.random.29 = FAIL
1031 WIN : dEQP-GLES2.functional.uniform_api.random.37 = FAIL
1031 WIN : dEQP-GLES2.functional.uniform_api.random.41 = FAIL
1031 WIN : dEQP-GLES2.functional.uniform_api.random.51 = FAIL
1031 WIN : dEQP-GLES2.functional.uniform_api.random.54 = FAIL
1031 WIN : dEQP-GLES2.functional.uniform_api.random.61 = FAIL
1031 WIN : dEQP-GLES2.functional.uniform_api.random.72 = FAIL
1031 WIN : dEQP-GLES2.functional.uniform_api.random.79 = FAIL
1031 WIN : dEQP-GLES2.functional.uniform_api.random.82 = FAIL
1031 WIN : dEQP-GLES2.functional.uniform_api.random.87 = FAIL
1031 WIN : dEQP-GLES2.functional.uniform_api.random.93 = FAIL
504 WIN : dEQP-GLES2.functional.uniform_api.value.initial.get_uniform.basic_struct.sampler2D_samplerCube_* = FAIL
504 WIN : dEQP-GLES2.functional.uniform_api.value.initial.get_uniform.struct_in_array.sampler2D_samplerCube_* = FAIL
504 WIN : dEQP-GLES2.functional.uniform_api.value.initial.get_uniform.array_in_struct.sampler2D_samplerCube_* = FAIL
504 WIN : dEQP-GLES2.functional.uniform_api.value.initial.get_uniform.nested_structs_arrays.sampler2D_samplerCube_* = FAIL
504 WIN : dEQP-GLES2.functional.uniform_api.value.assigned.by_pointer.get_uniform.struct_in_array.sampler2D_samplerCube_* = FAIL
504 WIN : dEQP-GLES2.functional.uniform_api.value.assigned.by_pointer.get_uniform.basic_struct.sampler2D_samplerCube_* = FAIL
504 WIN : dEQP-GLES2.functional.uniform_api.value.assigned.by_pointer.get_uniform.array_in_struct.sampler2D_samplerCube_* = FAIL
504 WIN : dEQP-GLES2.functional.uniform_api.value.assigned.by_pointer.get_uniform.nested_structs_arrays.sampler2D_samplerCube_* = FAIL
504 WIN : dEQP-GLES2.functional.uniform_api.value.assigned.by_pointer.render.basic_struct.sampler2D_samplerCube_* = FAIL
504 WIN : dEQP-GLES2.functional.uniform_api.value.assigned.by_pointer.render.struct_in_array.sampler2D_samplerCube_* = FAIL
504 WIN : dEQP-GLES2.functional.uniform_api.value.assigned.by_pointer.render.array_in_struct.sampler2D_samplerCube_* = FAIL
504 WIN : dEQP-GLES2.functional.uniform_api.value.assigned.by_pointer.render.nested_structs_arrays.sampler2D_samplerCube_* = FAIL
504 WIN : dEQP-GLES2.functional.uniform_api.value.assigned.by_value.get_uniform.basic_struct.sampler2D_samplerCube_* = FAIL
504 WIN : dEQP-GLES2.functional.uniform_api.value.assigned.by_value.get_uniform.struct_in_array.sampler2D_samplerCube_* = FAIL
504 WIN : dEQP-GLES2.functional.uniform_api.value.assigned.by_value.get_uniform.array_in_struct.sampler2D_samplerCube_* = FAIL
504 WIN : dEQP-GLES2.functional.uniform_api.value.assigned.by_value.get_uniform.nested_structs_arrays.sampler2D_samplerCube_* = FAIL
504 WIN : dEQP-GLES2.functional.uniform_api.value.assigned.by_value.render.basic_struct.sampler2D_samplerCube_* = FAIL
504 WIN : dEQP-GLES2.functional.uniform_api.value.assigned.by_value.render.struct_in_array.sampler2D_samplerCube_* = FAIL
504 WIN : dEQP-GLES2.functional.uniform_api.value.assigned.by_value.render.array_in_struct.sampler2D_samplerCube_* = FAIL
504 WIN : dEQP-GLES2.functional.uniform_api.value.assigned.basic_array_assign_full.array_in_struct.sampler2D_samplerCube_* = FAIL
504 WIN : dEQP-GLES2.functional.uniform_api.value.assigned.basic_array_assign_partial.array_in_struct.sampler2D_samplerCube_* = FAIL
504 WIN : dEQP-GLES2.functional.uniform_api.value.assigned.unused_uniforms.sampler2D_samplerCube_* = FAIL
// Failures on the dEQP Windows bots that do not reproduce locally // Failures on the dEQP Windows bots that do not reproduce locally
1108 WIN : dEQP-GLES2.functional.shaders.struct.local.dynamic_loop_struct_array_fragment = FAIL 1108 WIN : dEQP-GLES2.functional.shaders.struct.local.dynamic_loop_struct_array_fragment = FAIL
......
...@@ -82,7 +82,6 @@ ...@@ -82,7 +82,6 @@
1095 WIN LINUX : dEQP-GLES3.functional.texture.specification.basic_copytexsubimage2d.cube_luminance = FAIL 1095 WIN LINUX : dEQP-GLES3.functional.texture.specification.basic_copytexsubimage2d.cube_luminance = FAIL
1095 WIN LINUX : dEQP-GLES3.functional.texture.specification.basic_copytexsubimage2d.cube_luminance_alpha = FAIL 1095 WIN LINUX : dEQP-GLES3.functional.texture.specification.basic_copytexsubimage2d.cube_luminance_alpha = FAIL
1095 WIN LINUX : dEQP-GLES3.functional.texture.specification.basic_copytexsubimage2d.cube_rgb = FAIL 1095 WIN LINUX : dEQP-GLES3.functional.texture.specification.basic_copytexsubimage2d.cube_rgb = FAIL
1098 WIN LINUX : dEQP-GLES3.functional.uniform_api.random.6 = FAIL
// Windows only failure // Windows only failure
...@@ -100,11 +99,6 @@ ...@@ -100,11 +99,6 @@
1091 WIN : dEQP-GLES3.functional.shaders.loops.do_while_constant_iterations.nested_tricky_dataflow_1_fragment = FAIL 1091 WIN : dEQP-GLES3.functional.shaders.loops.do_while_constant_iterations.nested_tricky_dataflow_1_fragment = FAIL
1091 WIN : dEQP-GLES3.functional.shaders.loops.do_while_constant_iterations.nested_tricky_dataflow_2_vertex = FAIL 1091 WIN : dEQP-GLES3.functional.shaders.loops.do_while_constant_iterations.nested_tricky_dataflow_2_vertex = FAIL
1091 WIN : dEQP-GLES3.functional.shaders.loops.do_while_constant_iterations.nested_tricky_dataflow_2_fragment = FAIL 1091 WIN : dEQP-GLES3.functional.shaders.loops.do_while_constant_iterations.nested_tricky_dataflow_2_fragment = FAIL
504 WIN : dEQP-GLES3.functional.shaders.struct.uniform.sampler_vertex = FAIL
504 WIN : dEQP-GLES3.functional.shaders.struct.uniform.sampler_fragment = FAIL
504 WIN : dEQP-GLES3.functional.shaders.struct.uniform.sampler_nested_fragment = FAIL
504 WIN : dEQP-GLES3.functional.shaders.struct.uniform.sampler_array_vertex = FAIL
504 WIN : dEQP-GLES3.functional.shaders.struct.uniform.sampler_array_fragment = FAIL
1092 WIN : dEQP-GLES3.functional.shaders.texture_functions.textureoffset.isampler* = FAIL 1092 WIN : dEQP-GLES3.functional.shaders.texture_functions.textureoffset.isampler* = FAIL
1092 WIN : dEQP-GLES3.functional.shaders.texture_functions.textureoffset.usampler* = FAIL 1092 WIN : dEQP-GLES3.functional.shaders.texture_functions.textureoffset.usampler* = FAIL
1092 WIN : dEQP-GLES3.functional.shaders.texture_functions.textureoffset.sampler3d_fixed_fragment = FAIL 1092 WIN : dEQP-GLES3.functional.shaders.texture_functions.textureoffset.sampler3d_fixed_fragment = FAIL
...@@ -436,130 +430,8 @@ ...@@ -436,130 +430,8 @@
1097 WIN : dEQP-GLES3.functional.fbo.msaa.8_samples.depth32f_stencil8 = FAIL 1097 WIN : dEQP-GLES3.functional.fbo.msaa.8_samples.depth32f_stencil8 = FAIL
1097 WIN : dEQP-GLES3.functional.fbo.msaa.8_samples.depth24_stencil8 = FAIL 1097 WIN : dEQP-GLES3.functional.fbo.msaa.8_samples.depth24_stencil8 = FAIL
1097 WIN : dEQP-GLES3.functional.fbo.msaa.8_samples.stencil_index8 = FAIL 1097 WIN : dEQP-GLES3.functional.fbo.msaa.8_samples.stencil_index8 = FAIL
1098 WIN : dEQP-GLES3.functional.uniform_api.info_query.active_uniform.basic_struct.sampler2D_samplerCube_vertex = FAIL
1098 WIN : dEQP-GLES3.functional.uniform_api.info_query.active_uniform.basic_struct.sampler2D_samplerCube_fragment = FAIL
1098 WIN : dEQP-GLES3.functional.uniform_api.info_query.active_uniform.basic_struct.sampler2D_samplerCube_both = FAIL
1098 WIN : dEQP-GLES3.functional.uniform_api.info_query.active_uniform.struct_in_array.sampler2D_samplerCube_vertex = FAIL
1098 WIN : dEQP-GLES3.functional.uniform_api.info_query.active_uniform.struct_in_array.sampler2D_samplerCube_fragment = FAIL
1098 WIN : dEQP-GLES3.functional.uniform_api.info_query.active_uniform.struct_in_array.sampler2D_samplerCube_both = FAIL
1098 WIN : dEQP-GLES3.functional.uniform_api.info_query.active_uniform.array_in_struct.sampler2D_samplerCube_vertex = FAIL
1098 WIN : dEQP-GLES3.functional.uniform_api.info_query.active_uniform.array_in_struct.sampler2D_samplerCube_fragment = FAIL
1098 WIN : dEQP-GLES3.functional.uniform_api.info_query.active_uniform.array_in_struct.sampler2D_samplerCube_both = FAIL
1098 WIN : dEQP-GLES3.functional.uniform_api.info_query.active_uniform.nested_structs_arrays.sampler2D_samplerCube_vertex = FAIL
1098 WIN : dEQP-GLES3.functional.uniform_api.info_query.active_uniform.nested_structs_arrays.sampler2D_samplerCube_fragment = FAIL
1098 WIN : dEQP-GLES3.functional.uniform_api.info_query.active_uniform.nested_structs_arrays.sampler2D_samplerCube_both = FAIL
1098 WIN : dEQP-GLES3.functional.uniform_api.info_query.active_uniform.unused_uniforms.sampler2D_samplerCube_vertex = FAIL
1098 WIN : dEQP-GLES3.functional.uniform_api.info_query.active_uniform.unused_uniforms.sampler2D_samplerCube_fragment = FAIL
1098 WIN : dEQP-GLES3.functional.uniform_api.info_query.active_uniform.unused_uniforms.sampler2D_samplerCube_both = FAIL
1098 WIN : dEQP-GLES3.functional.uniform_api.info_query.indices_active_uniformsiv.basic_struct.sampler2D_samplerCube_vertex = FAIL
1098 WIN : dEQP-GLES3.functional.uniform_api.info_query.indices_active_uniformsiv.basic_struct.sampler2D_samplerCube_fragment = FAIL
1098 WIN : dEQP-GLES3.functional.uniform_api.info_query.indices_active_uniformsiv.basic_struct.sampler2D_samplerCube_both = FAIL
1098 WIN : dEQP-GLES3.functional.uniform_api.info_query.indices_active_uniformsiv.struct_in_array.sampler2D_samplerCube_vertex = FAIL
1098 WIN : dEQP-GLES3.functional.uniform_api.info_query.indices_active_uniformsiv.struct_in_array.sampler2D_samplerCube_fragment = FAIL
1098 WIN : dEQP-GLES3.functional.uniform_api.info_query.indices_active_uniformsiv.struct_in_array.sampler2D_samplerCube_both = FAIL
1098 WIN : dEQP-GLES3.functional.uniform_api.info_query.indices_active_uniformsiv.array_in_struct.sampler2D_samplerCube_vertex = FAIL
1098 WIN : dEQP-GLES3.functional.uniform_api.info_query.indices_active_uniformsiv.array_in_struct.sampler2D_samplerCube_fragment = FAIL
1098 WIN : dEQP-GLES3.functional.uniform_api.info_query.indices_active_uniformsiv.array_in_struct.sampler2D_samplerCube_both = FAIL
1098 WIN : dEQP-GLES3.functional.uniform_api.info_query.indices_active_uniformsiv.nested_structs_arrays.sampler2D_samplerCube_vertex = FAIL
1098 WIN : dEQP-GLES3.functional.uniform_api.info_query.indices_active_uniformsiv.nested_structs_arrays.sampler2D_samplerCube_fragment = FAIL
1098 WIN : dEQP-GLES3.functional.uniform_api.info_query.indices_active_uniformsiv.nested_structs_arrays.sampler2D_samplerCube_both = FAIL
1098 WIN : dEQP-GLES3.functional.uniform_api.info_query.indices_active_uniformsiv.unused_uniforms.sampler2D_samplerCube_vertex = FAIL
1098 WIN : dEQP-GLES3.functional.uniform_api.info_query.indices_active_uniformsiv.unused_uniforms.sampler2D_samplerCube_fragment = FAIL
1098 WIN : dEQP-GLES3.functional.uniform_api.info_query.indices_active_uniformsiv.unused_uniforms.sampler2D_samplerCube_both = FAIL
1098 WIN : dEQP-GLES3.functional.uniform_api.info_query.consistency.basic_struct.sampler2D_samplerCube_vertex = FAIL
1098 WIN : dEQP-GLES3.functional.uniform_api.info_query.consistency.basic_struct.sampler2D_samplerCube_fragment = FAIL
1098 WIN : dEQP-GLES3.functional.uniform_api.info_query.consistency.basic_struct.sampler2D_samplerCube_both = FAIL
1098 WIN : dEQP-GLES3.functional.uniform_api.info_query.consistency.struct_in_array.sampler2D_samplerCube_vertex = FAIL
1098 WIN : dEQP-GLES3.functional.uniform_api.info_query.consistency.struct_in_array.sampler2D_samplerCube_fragment = FAIL
1098 WIN : dEQP-GLES3.functional.uniform_api.info_query.consistency.struct_in_array.sampler2D_samplerCube_both = FAIL
1098 WIN : dEQP-GLES3.functional.uniform_api.info_query.consistency.array_in_struct.sampler2D_samplerCube_vertex = FAIL
1098 WIN : dEQP-GLES3.functional.uniform_api.info_query.consistency.array_in_struct.sampler2D_samplerCube_fragment = FAIL
1098 WIN : dEQP-GLES3.functional.uniform_api.info_query.consistency.array_in_struct.sampler2D_samplerCube_both = FAIL
1098 WIN : dEQP-GLES3.functional.uniform_api.info_query.consistency.nested_structs_arrays.sampler2D_samplerCube_vertex = FAIL
1098 WIN : dEQP-GLES3.functional.uniform_api.info_query.consistency.nested_structs_arrays.sampler2D_samplerCube_fragment = FAIL
1098 WIN : dEQP-GLES3.functional.uniform_api.info_query.consistency.nested_structs_arrays.sampler2D_samplerCube_both = FAIL
1098 WIN : dEQP-GLES3.functional.uniform_api.info_query.consistency.unused_uniforms.sampler2D_samplerCube_vertex = FAIL
1098 WIN : dEQP-GLES3.functional.uniform_api.info_query.consistency.unused_uniforms.sampler2D_samplerCube_fragment = FAIL
1098 WIN : dEQP-GLES3.functional.uniform_api.info_query.consistency.unused_uniforms.sampler2D_samplerCube_both = FAIL
1098 WIN : dEQP-GLES3.functional.uniform_api.value.initial.get_uniform.basic_struct.sampler2D_samplerCube_vertex = FAIL
1098 WIN : dEQP-GLES3.functional.uniform_api.value.initial.get_uniform.basic_struct.sampler2D_samplerCube_fragment = FAIL
1098 WIN : dEQP-GLES3.functional.uniform_api.value.initial.get_uniform.basic_struct.sampler2D_samplerCube_both = FAIL
1098 WIN : dEQP-GLES3.functional.uniform_api.value.initial.get_uniform.struct_in_array.sampler2D_samplerCube_vertex = FAIL
1098 WIN : dEQP-GLES3.functional.uniform_api.value.initial.get_uniform.struct_in_array.sampler2D_samplerCube_fragment = FAIL
1098 WIN : dEQP-GLES3.functional.uniform_api.value.initial.get_uniform.struct_in_array.sampler2D_samplerCube_both = FAIL
1098 WIN : dEQP-GLES3.functional.uniform_api.value.initial.get_uniform.array_in_struct.sampler2D_samplerCube_vertex = FAIL
1098 WIN : dEQP-GLES3.functional.uniform_api.value.initial.get_uniform.array_in_struct.sampler2D_samplerCube_fragment = FAIL
1098 WIN : dEQP-GLES3.functional.uniform_api.value.initial.get_uniform.array_in_struct.sampler2D_samplerCube_both = FAIL
1098 WIN : dEQP-GLES3.functional.uniform_api.value.initial.get_uniform.nested_structs_arrays.sampler2D_samplerCube_vertex = FAIL
1098 WIN : dEQP-GLES3.functional.uniform_api.value.initial.get_uniform.nested_structs_arrays.sampler2D_samplerCube_fragment = FAIL
1098 WIN : dEQP-GLES3.functional.uniform_api.value.initial.get_uniform.nested_structs_arrays.sampler2D_samplerCube_both = FAIL
1098 WIN : dEQP-GLES3.functional.uniform_api.value.assigned.by_pointer.get_uniform.basic_struct.sampler2D_samplerCube_vertex = FAIL
1098 WIN : dEQP-GLES3.functional.uniform_api.value.assigned.by_pointer.get_uniform.basic_struct.sampler2D_samplerCube_fragment = FAIL
1098 WIN : dEQP-GLES3.functional.uniform_api.value.assigned.by_pointer.get_uniform.basic_struct.sampler2D_samplerCube_both = FAIL
1098 WIN : dEQP-GLES3.functional.uniform_api.value.assigned.by_pointer.get_uniform.struct_in_array.sampler2D_samplerCube_vertex = FAIL
1098 WIN : dEQP-GLES3.functional.uniform_api.value.assigned.by_pointer.get_uniform.struct_in_array.sampler2D_samplerCube_fragment = FAIL
1098 WIN : dEQP-GLES3.functional.uniform_api.value.assigned.by_pointer.get_uniform.struct_in_array.sampler2D_samplerCube_both = FAIL
1098 WIN : dEQP-GLES3.functional.uniform_api.value.assigned.by_pointer.get_uniform.array_in_struct.sampler2D_samplerCube_vertex = FAIL
1098 WIN : dEQP-GLES3.functional.uniform_api.value.assigned.by_pointer.get_uniform.array_in_struct.sampler2D_samplerCube_fragment = FAIL
1098 WIN : dEQP-GLES3.functional.uniform_api.value.assigned.by_pointer.get_uniform.array_in_struct.sampler2D_samplerCube_both = FAIL
1098 WIN : dEQP-GLES3.functional.uniform_api.value.assigned.by_pointer.get_uniform.nested_structs_arrays.sampler2D_samplerCube_vertex = FAIL
1098 WIN : dEQP-GLES3.functional.uniform_api.value.assigned.by_pointer.get_uniform.nested_structs_arrays.sampler2D_samplerCube_fragment = FAIL
1098 WIN : dEQP-GLES3.functional.uniform_api.value.assigned.by_pointer.get_uniform.nested_structs_arrays.sampler2D_samplerCube_both = FAIL
1098 WIN : dEQP-GLES3.functional.uniform_api.value.assigned.by_pointer.render.basic_struct.sampler2D_samplerCube_vertex = FAIL
1098 WIN : dEQP-GLES3.functional.uniform_api.value.assigned.by_pointer.render.basic_struct.sampler2D_samplerCube_fragment = FAIL
1098 WIN : dEQP-GLES3.functional.uniform_api.value.assigned.by_pointer.render.basic_struct.sampler2D_samplerCube_both = FAIL
1098 WIN : dEQP-GLES3.functional.uniform_api.value.assigned.by_pointer.render.struct_in_array.sampler2D_samplerCube_vertex = FAIL
1098 WIN : dEQP-GLES3.functional.uniform_api.value.assigned.by_pointer.render.struct_in_array.sampler2D_samplerCube_fragment = FAIL
1098 WIN : dEQP-GLES3.functional.uniform_api.value.assigned.by_pointer.render.struct_in_array.sampler2D_samplerCube_both = FAIL
1098 WIN : dEQP-GLES3.functional.uniform_api.value.assigned.by_pointer.render.array_in_struct.sampler2D_samplerCube_vertex = FAIL
1098 WIN : dEQP-GLES3.functional.uniform_api.value.assigned.by_pointer.render.array_in_struct.sampler2D_samplerCube_fragment = FAIL
1098 WIN : dEQP-GLES3.functional.uniform_api.value.assigned.by_pointer.render.array_in_struct.sampler2D_samplerCube_both = FAIL
1098 WIN : dEQP-GLES3.functional.uniform_api.value.assigned.by_pointer.render.nested_structs_arrays.sampler2D_samplerCube_vertex = FAIL
1098 WIN : dEQP-GLES3.functional.uniform_api.value.assigned.by_pointer.render.nested_structs_arrays.sampler2D_samplerCube_fragment = FAIL
1098 WIN : dEQP-GLES3.functional.uniform_api.value.assigned.by_pointer.render.nested_structs_arrays.sampler2D_samplerCube_both = FAIL
1098 WIN : dEQP-GLES3.functional.uniform_api.value.assigned.by_value.get_uniform.basic_struct.sampler2D_samplerCube_vertex = FAIL
1098 WIN : dEQP-GLES3.functional.uniform_api.value.assigned.by_value.get_uniform.basic_struct.sampler2D_samplerCube_fragment = FAIL
1098 WIN : dEQP-GLES3.functional.uniform_api.value.assigned.by_value.get_uniform.basic_struct.sampler2D_samplerCube_both = FAIL
1098 WIN : dEQP-GLES3.functional.uniform_api.value.assigned.by_value.get_uniform.struct_in_array.sampler2D_samplerCube_vertex = FAIL
1098 WIN : dEQP-GLES3.functional.uniform_api.value.assigned.by_value.get_uniform.struct_in_array.sampler2D_samplerCube_fragment = FAIL
1098 WIN : dEQP-GLES3.functional.uniform_api.value.assigned.by_value.get_uniform.struct_in_array.sampler2D_samplerCube_both = FAIL
1098 WIN : dEQP-GLES3.functional.uniform_api.value.assigned.by_value.get_uniform.array_in_struct.sampler2D_samplerCube_vertex = FAIL
1098 WIN : dEQP-GLES3.functional.uniform_api.value.assigned.by_value.get_uniform.array_in_struct.sampler2D_samplerCube_fragment = FAIL
1098 WIN : dEQP-GLES3.functional.uniform_api.value.assigned.by_value.get_uniform.array_in_struct.sampler2D_samplerCube_both = FAIL
1098 WIN : dEQP-GLES3.functional.uniform_api.value.assigned.by_value.get_uniform.nested_structs_arrays.sampler2D_samplerCube_vertex = FAIL
1098 WIN : dEQP-GLES3.functional.uniform_api.value.assigned.by_value.get_uniform.nested_structs_arrays.sampler2D_samplerCube_fragment = FAIL
1098 WIN : dEQP-GLES3.functional.uniform_api.value.assigned.by_value.get_uniform.nested_structs_arrays.sampler2D_samplerCube_both = FAIL
1098 WIN : dEQP-GLES3.functional.uniform_api.value.assigned.by_value.render.basic_struct.sampler2D_samplerCube_vertex = FAIL
1098 WIN : dEQP-GLES3.functional.uniform_api.value.assigned.by_value.render.basic_struct.sampler2D_samplerCube_fragment = FAIL
1098 WIN : dEQP-GLES3.functional.uniform_api.value.assigned.by_value.render.basic_struct.sampler2D_samplerCube_both = FAIL
1098 WIN : dEQP-GLES3.functional.uniform_api.value.assigned.by_value.render.struct_in_array.sampler2D_samplerCube_vertex = FAIL
1098 WIN : dEQP-GLES3.functional.uniform_api.value.assigned.by_value.render.struct_in_array.sampler2D_samplerCube_fragment = FAIL
1098 WIN : dEQP-GLES3.functional.uniform_api.value.assigned.by_value.render.struct_in_array.sampler2D_samplerCube_both = FAIL
1098 WIN : dEQP-GLES3.functional.uniform_api.value.assigned.by_value.render.array_in_struct.sampler2D_samplerCube_vertex = FAIL
1098 WIN : dEQP-GLES3.functional.uniform_api.value.assigned.by_value.render.array_in_struct.sampler2D_samplerCube_fragment = FAIL
1098 WIN : dEQP-GLES3.functional.uniform_api.value.assigned.by_value.render.array_in_struct.sampler2D_samplerCube_both = FAIL
1098 WIN : dEQP-GLES3.functional.uniform_api.value.assigned.by_value.render.nested_structs_arrays.sampler2D_samplerCube_vertex = FAIL
1098 WIN : dEQP-GLES3.functional.uniform_api.value.assigned.by_value.render.nested_structs_arrays.sampler2D_samplerCube_fragment = FAIL
1098 WIN : dEQP-GLES3.functional.uniform_api.value.assigned.by_value.render.nested_structs_arrays.sampler2D_samplerCube_both = FAIL
1098 WIN : dEQP-GLES3.functional.uniform_api.value.assigned.basic_array_assign_full.array_in_struct.sampler2D_samplerCube_vertex = FAIL
1098 WIN : dEQP-GLES3.functional.uniform_api.value.assigned.basic_array_assign_full.array_in_struct.sampler2D_samplerCube_fragment = FAIL
1098 WIN : dEQP-GLES3.functional.uniform_api.value.assigned.basic_array_assign_full.array_in_struct.sampler2D_samplerCube_both = FAIL
1098 WIN : dEQP-GLES3.functional.uniform_api.value.assigned.basic_array_assign_partial.array_in_struct.sampler2D_samplerCube_vertex = FAIL
1098 WIN : dEQP-GLES3.functional.uniform_api.value.assigned.basic_array_assign_partial.array_in_struct.sampler2D_samplerCube_fragment = FAIL
1098 WIN : dEQP-GLES3.functional.uniform_api.value.assigned.basic_array_assign_partial.array_in_struct.sampler2D_samplerCube_both = FAIL
1098 WIN : dEQP-GLES3.functional.uniform_api.value.assigned.unused_uniforms.sampler2D_samplerCube_vertex = FAIL
1098 WIN : dEQP-GLES3.functional.uniform_api.value.assigned.unused_uniforms.sampler2D_samplerCube_fragment = FAIL
1098 WIN : dEQP-GLES3.functional.uniform_api.value.assigned.unused_uniforms.sampler2D_samplerCube_both = FAIL
1098 WIN : dEQP-GLES3.functional.uniform_api.random.3 = FAIL
1098 WIN : dEQP-GLES3.functional.uniform_api.random.8 = FAIL 1098 WIN : dEQP-GLES3.functional.uniform_api.random.8 = FAIL
1098 WIN : dEQP-GLES3.functional.uniform_api.random.17 = FAIL
1098 WIN : dEQP-GLES3.functional.uniform_api.random.20 = FAIL
1098 WIN : dEQP-GLES3.functional.uniform_api.random.21 = FAIL
1098 WIN : dEQP-GLES3.functional.uniform_api.random.29 = FAIL
1098 WIN : dEQP-GLES3.functional.uniform_api.random.54 = FAIL
1098 WIN : dEQP-GLES3.functional.uniform_api.random.81 = FAIL 1098 WIN : dEQP-GLES3.functional.uniform_api.random.81 = FAIL
1098 WIN : dEQP-GLES3.functional.uniform_api.random.83 = FAIL
1098 WIN : dEQP-GLES3.functional.uniform_api.random.87 = FAIL
1101 WIN : dEQP-GLES3.functional.polygon_offset.fixed16_render_with_units = FAIL 1101 WIN : dEQP-GLES3.functional.polygon_offset.fixed16_render_with_units = FAIL
1101 WIN : dEQP-GLES3.functional.polygon_offset.fixed24_render_with_units = FAIL 1101 WIN : dEQP-GLES3.functional.polygon_offset.fixed24_render_with_units = FAIL
1101 WIN : dEQP-GLES3.functional.lifetime.attach.deleted_input.buffer_vertex_array = FAIL 1101 WIN : dEQP-GLES3.functional.lifetime.attach.deleted_input.buffer_vertex_array = FAIL
...@@ -695,6 +567,7 @@ ...@@ -695,6 +567,7 @@
1323 LINUX : dEQP-GLES3.functional.transform_feedback.basic_types.separate.triangles.lowp_mat2 = FAIL 1323 LINUX : dEQP-GLES3.functional.transform_feedback.basic_types.separate.triangles.lowp_mat2 = FAIL
1323 LINUX : dEQP-GLES3.functional.transform_feedback.basic_types.separate.triangles.mediump_mat2 = FAIL 1323 LINUX : dEQP-GLES3.functional.transform_feedback.basic_types.separate.triangles.mediump_mat2 = FAIL
1323 LINUX : dEQP-GLES3.functional.transform_feedback.random.separate.lines.8 = FAIL 1323 LINUX : dEQP-GLES3.functional.transform_feedback.random.separate.lines.8 = FAIL
1098 LINUX : dEQP-GLES3.functional.uniform_api.random.6 = FAIL
// While loops with 'continue' seem flaky on Linux. (Possibly all GL renderers) // While loops with 'continue' seem flaky on Linux. (Possibly all GL renderers)
1324 LINUX : dEQP-GLES3.functional.shaders.loops.while_constant_iterations.conditional_continue_vertex = FAIL 1324 LINUX : dEQP-GLES3.functional.shaders.loops.while_constant_iterations.conditional_continue_vertex = FAIL
......
...@@ -139,6 +139,8 @@ class Texture2DTest : public TexCoordDrawTest ...@@ -139,6 +139,8 @@ class Texture2DTest : public TexCoordDrawTest
); );
} }
virtual const char *getTextureUniformName() { return "tex"; }
void SetUp() override void SetUp() override
{ {
TexCoordDrawTest::SetUp(); TexCoordDrawTest::SetUp();
...@@ -146,7 +148,7 @@ class Texture2DTest : public TexCoordDrawTest ...@@ -146,7 +148,7 @@ class Texture2DTest : public TexCoordDrawTest
ASSERT_GL_NO_ERROR(); ASSERT_GL_NO_ERROR();
mTexture2DUniformLocation = glGetUniformLocation(mProgram, "tex"); mTexture2DUniformLocation = glGetUniformLocation(mProgram, getTextureUniformName());
ASSERT_NE(-1, mTexture2DUniformLocation); ASSERT_NE(-1, mTexture2DUniformLocation);
} }
...@@ -921,6 +923,152 @@ class SamplerTypeMixTestES3 : public TexCoordDrawTest ...@@ -921,6 +923,152 @@ class SamplerTypeMixTestES3 : public TexCoordDrawTest
GLint mDepthRefUniformLocation; GLint mDepthRefUniformLocation;
}; };
class SamplerInStructTest : public Texture2DTest
{
protected:
SamplerInStructTest() : Texture2DTest() {}
const char *getTextureUniformName() override { return "us.tex"; }
std::string getFragmentShaderSource() override
{
return std::string(
"precision highp float;\n"
"struct S\n"
"{\n"
" vec4 a;\n"
" highp sampler2D tex;\n"
"};\n"
"uniform S us;\n"
"varying vec2 texcoord;\n"
"void main()\n"
"{\n"
" gl_FragColor = texture2D(us.tex, texcoord + us.a.x);\n"
"}\n");
}
void runSamplerInStructTest()
{
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, mTexture2D);
GLubyte texDataGreen[1u * 1u * 4u];
FillWithRGBA<GLubyte>(1u * 1u, 0u, 255u, 0u, 255u, texDataGreen);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, texDataGreen);
drawQuad(mProgram, "position", 0.5f);
EXPECT_PIXEL_EQ(0, 0, 0, 255, 0, 255);
}
};
class SamplerInStructAsFunctionParameterTest : public SamplerInStructTest
{
protected:
SamplerInStructAsFunctionParameterTest() : SamplerInStructTest() {}
std::string getFragmentShaderSource() override
{
return std::string(
"precision highp float;\n"
"struct S\n"
"{\n"
" vec4 a;\n"
" highp sampler2D tex;\n"
"};\n"
"uniform S us;\n"
"varying vec2 texcoord;\n"
"vec4 sampleFrom(S s) {\n"
" return texture2D(s.tex, texcoord + s.a.x);\n"
"}\n"
"void main()\n"
"{\n"
" gl_FragColor = sampleFrom(us);\n"
"}\n");
}
};
class SamplerInStructArrayAsFunctionParameterTest : public SamplerInStructTest
{
protected:
SamplerInStructArrayAsFunctionParameterTest() : SamplerInStructTest() {}
const char *getTextureUniformName() override { return "us[0].tex"; }
std::string getFragmentShaderSource() override
{
return std::string(
"precision highp float;\n"
"struct S\n"
"{\n"
" vec4 a;\n"
" highp sampler2D tex;\n"
"};\n"
"uniform S us[1];\n"
"varying vec2 texcoord;\n"
"vec4 sampleFrom(S s) {\n"
" return texture2D(s.tex, texcoord + s.a.x);\n"
"}\n"
"void main()\n"
"{\n"
" gl_FragColor = sampleFrom(us[0]);\n"
"}\n");
}
};
class SamplerInNestedStructAsFunctionParameterTest : public SamplerInStructTest
{
protected:
SamplerInNestedStructAsFunctionParameterTest() : SamplerInStructTest() {}
const char *getTextureUniformName() override { return "us[0].sub.tex"; }
std::string getFragmentShaderSource() override
{
return std::string(
"precision highp float;\n"
"struct SUB\n"
"{\n"
" vec4 a;\n"
" highp sampler2D tex;\n"
"};\n"
"struct S\n"
"{\n"
" SUB sub;\n"
"};\n"
"uniform S us[1];\n"
"varying vec2 texcoord;\n"
"vec4 sampleFrom(SUB s) {\n"
" return texture2D(s.tex, texcoord + s.a.x);\n"
"}\n"
"void main()\n"
"{\n"
" gl_FragColor = sampleFrom(us[0].sub);\n"
"}\n");
}
};
class SamplerInStructAndOtherVariableTest : public SamplerInStructTest
{
protected:
SamplerInStructAndOtherVariableTest() : SamplerInStructTest() {}
std::string getFragmentShaderSource() override
{
return std::string(
"precision highp float;\n"
"struct S\n"
"{\n"
" vec4 a;\n"
" highp sampler2D tex;\n"
"};\n"
"uniform S us;\n"
"uniform float us_tex;\n"
"varying vec2 texcoord;\n"
"void main()\n"
"{\n"
" gl_FragColor = texture2D(us.tex, texcoord + us.a.x + us_tex);\n"
"}\n");
}
};
TEST_P(Texture2DTest, NegativeAPISubImage) TEST_P(Texture2DTest, NegativeAPISubImage)
{ {
glBindTexture(GL_TEXTURE_2D, mTexture2D); glBindTexture(GL_TEXTURE_2D, mTexture2D);
...@@ -1864,6 +2012,39 @@ TEST_P(Texture2DTestES3, TextureCOMPRESSEDSRGB8ETC2ImplicitAlpha1) ...@@ -1864,6 +2012,39 @@ TEST_P(Texture2DTestES3, TextureCOMPRESSEDSRGB8ETC2ImplicitAlpha1)
EXPECT_PIXEL_ALPHA_EQ(0, 0, 255); EXPECT_PIXEL_ALPHA_EQ(0, 0, 255);
} }
// Use a sampler in a uniform struct.
TEST_P(SamplerInStructTest, SamplerInStruct)
{
runSamplerInStructTest();
}
// Use a sampler in a uniform struct that's passed as a function parameter.
TEST_P(SamplerInStructAsFunctionParameterTest, SamplerInStructAsFunctionParameter)
{
runSamplerInStructTest();
}
// Use a sampler in a uniform struct array with a struct from the array passed as a function
// parameter.
TEST_P(SamplerInStructArrayAsFunctionParameterTest, SamplerInStructArrayAsFunctionParameter)
{
runSamplerInStructTest();
}
// Use a sampler in a struct inside a uniform struct with the nested struct passed as a function
// parameter.
TEST_P(SamplerInNestedStructAsFunctionParameterTest, SamplerInNestedStructAsFunctionParameter)
{
runSamplerInStructTest();
}
// Make sure that there isn't a name conflict between sampler extracted from a struct and a
// similarly named uniform.
TEST_P(SamplerInStructAndOtherVariableTest, SamplerInStructAndOtherVariable)
{
runSamplerInStructTest();
}
class TextureLimitsTest : public ANGLETest class TextureLimitsTest : public ANGLETest
{ {
protected: protected:
...@@ -2310,6 +2491,36 @@ ANGLE_INSTANTIATE_TEST(ShadowSamplerPlusSampler3DTestES3, ...@@ -2310,6 +2491,36 @@ ANGLE_INSTANTIATE_TEST(ShadowSamplerPlusSampler3DTestES3,
ANGLE_INSTANTIATE_TEST(SamplerTypeMixTestES3, ES3_D3D11(), ES3_OPENGL(), ES3_OPENGLES()); ANGLE_INSTANTIATE_TEST(SamplerTypeMixTestES3, ES3_D3D11(), ES3_OPENGL(), ES3_OPENGLES());
ANGLE_INSTANTIATE_TEST(Texture2DArrayTestES3, ES3_D3D11(), ES3_OPENGL(), ES3_OPENGLES()); ANGLE_INSTANTIATE_TEST(Texture2DArrayTestES3, ES3_D3D11(), ES3_OPENGL(), ES3_OPENGLES());
ANGLE_INSTANTIATE_TEST(TextureSizeTextureArrayTest, ES3_D3D11(), ES3_OPENGL()); ANGLE_INSTANTIATE_TEST(TextureSizeTextureArrayTest, ES3_D3D11(), ES3_OPENGL());
ANGLE_INSTANTIATE_TEST(SamplerInStructTest,
ES2_D3D11(),
ES2_D3D11_FL9_3(),
ES2_D3D9(),
ES2_OPENGL(),
ES2_OPENGLES());
ANGLE_INSTANTIATE_TEST(SamplerInStructAsFunctionParameterTest,
ES2_D3D11(),
ES2_D3D11_FL9_3(),
ES2_D3D9(),
ES2_OPENGL(),
ES2_OPENGLES());
ANGLE_INSTANTIATE_TEST(SamplerInStructArrayAsFunctionParameterTest,
ES2_D3D11(),
ES2_D3D11_FL9_3(),
ES2_D3D9(),
ES2_OPENGL(),
ES2_OPENGLES());
ANGLE_INSTANTIATE_TEST(SamplerInNestedStructAsFunctionParameterTest,
ES2_D3D11(),
ES2_D3D11_FL9_3(),
ES2_D3D9(),
ES2_OPENGL(),
ES2_OPENGLES());
ANGLE_INSTANTIATE_TEST(SamplerInStructAndOtherVariableTest,
ES2_D3D11(),
ES2_D3D11_FL9_3(),
ES2_D3D9(),
ES2_OPENGL(),
ES2_OPENGLES());
ANGLE_INSTANTIATE_TEST(TextureLimitsTest, ES2_D3D11(), ES2_OPENGL(), ES2_OPENGLES()); ANGLE_INSTANTIATE_TEST(TextureLimitsTest, ES2_D3D11(), ES2_OPENGL(), ES2_OPENGLES());
} // namespace } // namespace
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