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;
// Version number for shader translation API.
// It is incremented every time the API changes.
#define ANGLE_SH_VERSION 144
#define ANGLE_SH_VERSION 145
typedef enum {
SH_GLES2_SPEC = 0x8B40,
......@@ -454,16 +454,10 @@ COMPILER_EXPORT bool ShGetInterfaceBlockRegister(const ShHandle handle,
const std::string &interfaceBlockName,
unsigned int *indexOut);
// Gives the compiler-assigned register for uniforms in the default
// interface block.
// The method writes the value to the output variable "indexOut".
// Returns true if it found a valid default uniform, false otherwise.
// Parameters:
// 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);
// Gives a map from uniform names to compiler-assigned registers in the default
// interface block. Note that the map contains also registers of samplers that
// have been extracted from structs.
COMPILER_EXPORT const std::map<std::string, unsigned int> *ShGetUniformRegisterMap(
const ShHandle handle);
#endif // GLSLANG_SHADERLANG_H_
......@@ -738,6 +738,16 @@ class TIntermTraverser : angle::NonCopyable
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 incrementParentBlockPos();
void popParentBlock();
......
......@@ -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
// return values in HLSL.
std::vector<ArrayHelperFunction> mArrayConstructIntoFunctions;
private:
TString samplerNamePrefixFromStruct(TIntermTyped *node);
bool ancestorEvaluatesToSamplerInStruct(Visit visit);
};
}
......
......@@ -363,23 +363,15 @@ bool ShGetInterfaceBlockRegister(const ShHandle handle,
#endif // ANGLE_ENABLE_HLSL
}
bool ShGetUniformRegister(const ShHandle handle,
const std::string &uniformName,
unsigned int *indexOut)
const std::map<std::string, unsigned int> *ShGetUniformRegisterMap(const ShHandle handle)
{
#ifdef ANGLE_ENABLE_HLSL
ASSERT(indexOut);
TranslatorHLSL *translator = GetTranslatorHLSLFromHandle(handle);
ASSERT(translator);
if (!translator->hasUniform(uniformName))
{
return false;
}
*indexOut = translator->getUniformRegister(uniformName);
return true;
return translator->getUniformRegisterMap();
#else
return false;
#endif // ANGLE_ENABLE_HLSL
}
static std::map<std::string, unsigned int> map;
return &map;
#endif // ANGLE_ENABLE_HLSL
}
\ No newline at end of file
......@@ -182,26 +182,29 @@ TString StructureHLSL::define(const TStructure &structure, bool useHLSLRowMajorP
string += declareString + "\n"
"{\n";
for (unsigned int i = 0; i < fields.size(); i++)
for (const TField *field : fields)
{
const TField &field = *fields[i];
const TType &fieldType = *field.type();
const TStructure *fieldStruct = fieldType.getStruct();
const TString &fieldTypeString = fieldStruct ?
QualifiedStructNameString(*fieldStruct, useHLSLRowMajorPacking,
useStd140Packing) :
TypeString(fieldType);
if (padHelper)
const TType &fieldType = *field->type();
if (!IsSampler(fieldType.getBasicType()))
{
string += padHelper->prePaddingString(fieldType);
}
const TStructure *fieldStruct = fieldType.getStruct();
const TString &fieldTypeString =
fieldStruct ? QualifiedStructNameString(*fieldStruct, useHLSLRowMajorPacking,
useStd140Packing)
: TypeString(fieldType);
if (padHelper)
{
string += padHelper->prePaddingString(fieldType);
}
string += " " + fieldTypeString + " " + DecorateField(field.name(), structure) + ArrayString(fieldType) + ";\n";
string += " " + fieldTypeString + " " + DecorateField(field->name(), structure) +
ArrayString(fieldType) + ";\n";
if (padHelper)
{
string += padHelper->postPaddingString(fieldType, useHLSLRowMajorPacking);
if (padHelper)
{
string += padHelper->postPaddingString(fieldType, useHLSLRowMajorPacking);
}
}
}
......@@ -265,9 +268,13 @@ TString StructureHLSL::addConstructor(const TType &type,
}
const TFieldList &fields = structure->fields();
for (unsigned int i = 0; i < fields.size(); i++)
for (const TField *field : fields)
{
ctorParameters.push_back(*fields[i]->type());
const TType *fieldType = field->type();
if (!IsSampler(fieldType->getBasicType()))
{
ctorParameters.push_back(*fieldType);
}
}
constructorFunctionName = TString(name);
}
......@@ -310,7 +317,15 @@ TString StructureHLSL::addConstructor(const TType &type,
if (ctorType.getStruct())
{
constructor += " " + name + " structure = {";
constructor += " " + name + " structure";
if (ctorParameters.empty())
{
constructor += ";\n";
}
else
{
constructor += " = { ";
}
}
else
{
......@@ -369,7 +384,15 @@ TString StructureHLSL::addConstructor(const TType &type,
}
else
{
size_t remainingComponents = ctorType.getObjectSize();
size_t remainingComponents = 0;
if (ctorType.getStruct())
{
remainingComponents = ctorParameters.size();
}
else
{
remainingComponents = ctorType.getObjectSize();
}
size_t parameterIndex = 0;
while (remainingComponents > 0)
......@@ -382,10 +405,9 @@ TString StructureHLSL::addConstructor(const TType &type,
if (ctorType.getStruct())
{
ASSERT(remainingComponents == parameterSize || moreParameters);
ASSERT(parameterSize <= remainingComponents);
ASSERT(remainingComponents == 1 || moreParameters);
remainingComponents -= parameterSize;
--remainingComponents;
}
else if (parameter.isScalar())
{
......@@ -461,9 +483,13 @@ TString StructureHLSL::addConstructor(const TType &type,
if (ctorType.getStruct())
{
constructor += "};\n"
" return structure;\n"
"}\n";
if (!ctorParameters.empty())
{
constructor += "};\n";
}
constructor +=
" return structure;\n"
"}\n";
}
else
{
......
......@@ -72,13 +72,7 @@ unsigned int TranslatorHLSL::getInterfaceBlockRegister(const std::string &interf
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);
}
unsigned int TranslatorHLSL::getUniformRegister(const std::string &uniformName) const
{
ASSERT(hasUniform(uniformName));
return mUniformRegisterMap.find(uniformName)->second;
}
return &mUniformRegisterMap;
}
\ No newline at end of file
......@@ -18,8 +18,7 @@ class TranslatorHLSL : public TCompiler
bool hasInterfaceBlock(const std::string &interfaceBlockName) const;
unsigned int getInterfaceBlockRegister(const std::string &interfaceBlockName) const;
bool hasUniform(const std::string &uniformName) const;
unsigned int getUniformRegister(const std::string &uniformName) const;
const std::map<std::string, unsigned int> *getUniformRegisterMap() const;
protected:
void translate(TIntermNode *root, int compileOptions) override;
......
......@@ -9,6 +9,8 @@
#endif
#include "compiler/translator/Types.h"
#include "compiler/translator/InfoSink.h"
#include "compiler/translator/IntermNode.h"
#include <algorithm>
#include <climits>
......@@ -244,6 +246,76 @@ bool TStructure::containsSamplers() const
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 mangledName(mangledNamePrefix);
......
......@@ -16,6 +16,7 @@
struct TPublicType;
class TType;
class TSymbol;
class TIntermSymbol;
class TField : angle::NonCopyable
{
......@@ -120,6 +121,12 @@ class TStructure : public TFieldListCollection
bool containsType(TBasicType t) 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;
void setUniqueId(int uniqueId)
......@@ -529,6 +536,17 @@ class TType
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.
void realize()
{
......
......@@ -24,10 +24,6 @@ class UniformHLSL : angle::NonCopyable
void reserveUniformRegisters(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,
ShShaderOutput outputType,
const ReferencedSymbols &referencedUniforms);
......@@ -55,11 +51,30 @@ class UniformHLSL : angle::NonCopyable
TString interfaceBlockStructString(const TInterfaceBlock &interfaceBlock);
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
unsigned int declareUniformAndAssignRegister(const TType &type,
const TString &name,
unsigned int *registerCount);
unsigned int declareUniformAndAssignRegister(const TType &type, const TString &name);
unsigned int assignUniformRegister(const TType &type,
const TString &name,
unsigned int *outRegisterCount);
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 mInterfaceBlockRegister;
......
......@@ -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)
{
return "ex_" + string;
return "ex_" + name.getString();
}
return Decorate(string);
return DecorateIfNeeded(name);
}
TString DecorateField(const TString &string, const TStructure &structure)
......
......@@ -64,7 +64,7 @@ TString Decorate(const TString &string);
TString DecorateIfNeeded(const TName &name);
// Decorates and also unmangles the function 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 DecoratePrivate(const TString &privateText);
TString TypeString(const TType &type);
......
......@@ -1347,16 +1347,6 @@ LinkResult ProgramD3D::link(const gl::Data &data, gl::InfoLog &infoLog)
{
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 *fragmentShader = mData.getAttachedFragmentShader();
......@@ -1820,7 +1810,8 @@ void ProgramD3D::defineUniformBase(const gl::Shader *shader,
const sh::Uniform &uniform,
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);
return;
......@@ -1869,7 +1860,17 @@ void ProgramD3D::defineUniform(GLenum shaderType,
const sh::ShaderVariable &field = uniform.fields[fieldIndex];
const std::string &fieldFullName = (fullName + elementString + "." + field.name);
defineUniform(shaderType, field, fieldFullName, encoder, uniformMap);
// 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);
}
}
if (encoder)
......@@ -2066,7 +2067,7 @@ size_t ProgramD3D::getUniformBlockInfo(const sh::InterfaceBlock &interfaceBlock)
void ProgramD3D::assignAllSamplerRegisters()
{
for (const D3DUniform *d3dUniform : mD3DUniforms)
for (D3DUniform *d3dUniform : mD3DUniforms)
{
if (d3dUniform->isSampler())
{
......@@ -2075,20 +2076,23 @@ void ProgramD3D::assignAllSamplerRegisters()
}
}
void ProgramD3D::assignSamplerRegisters(const D3DUniform *d3dUniform)
void ProgramD3D::assignSamplerRegisters(D3DUniform *d3dUniform)
{
ASSERT(d3dUniform->isSampler());
ASSERT(d3dUniform->vsRegisterIndex != GL_INVALID_INDEX ||
d3dUniform->psRegisterIndex != GL_INVALID_INDEX);
if (d3dUniform->vsRegisterIndex != GL_INVALID_INDEX)
const ShaderD3D *vertexShaderD3D = GetImplAs<ShaderD3D>(mData.getAttachedVertexShader());
const ShaderD3D *fragmentShaderD3D = GetImplAs<ShaderD3D>(mData.getAttachedFragmentShader());
ASSERT(vertexShaderD3D->hasUniform(d3dUniform) || fragmentShaderD3D->hasUniform(d3dUniform));
if (vertexShaderD3D->hasUniform(d3dUniform))
{
d3dUniform->vsRegisterIndex = vertexShaderD3D->getUniformRegister(d3dUniform->name);
ASSERT(d3dUniform->vsRegisterIndex != GL_INVALID_INDEX);
AssignSamplers(d3dUniform->vsRegisterIndex, d3dUniform->type, d3dUniform->arraySize,
mSamplersVS, &mUsedVertexSamplerRange);
}
if (d3dUniform->psRegisterIndex != GL_INVALID_INDEX)
if (fragmentShaderD3D->hasUniform(d3dUniform))
{
d3dUniform->psRegisterIndex = fragmentShaderD3D->getUniformRegister(d3dUniform->name);
ASSERT(d3dUniform->psRegisterIndex != GL_INVALID_INDEX);
AssignSamplers(d3dUniform->psRegisterIndex, d3dUniform->type, d3dUniform->arraySize,
mSamplersPS, &mUsedPixelSamplerRange);
}
......
......@@ -322,7 +322,7 @@ class ProgramD3D : public ProgramImpl
sh::HLSLBlockEncoder *encoder,
D3DUniformMap *uniformMap);
void assignAllSamplerRegisters();
void assignSamplerRegisters(const D3DUniform *d3dUniform);
void assignSamplerRegisters(D3DUniform *d3dUniform);
static void AssignSamplers(unsigned int startSamplerIndex,
GLenum samplerType,
......
......@@ -13,6 +13,7 @@
#include "libANGLE/Shader.h"
#include "libANGLE/features.h"
#include "libANGLE/renderer/d3d/RendererD3D.h"
#include "libANGLE/renderer/d3d/ProgramD3D.h"
// Definitions local to the translation unit
namespace
......@@ -139,6 +140,18 @@ int ShaderD3D::prepareSourceAndReturnOptions(std::stringstream *shaderSourceStre
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)
{
// TODO(jmadill): We shouldn't need to cache this.
......@@ -164,19 +177,7 @@ bool ShaderD3D::postTranslateCompile(gl::Compiler *compiler, std::string *infoLo
ShHandle compilerHandle = compiler->getCompilerHandle(mData.getShaderType());
for (const sh::Uniform &uniform : mData.getUniforms())
{
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;
}
}
mUniformRegisterMap = GetUniformRegisterMap(ShGetUniformRegisterMap(compilerHandle));
for (const sh::InterfaceBlock &interfaceBlock : mData.getInterfaceBlocks())
{
......
......@@ -18,6 +18,7 @@ namespace rx
class DynamicHLSL;
class RendererD3D;
struct D3DCompilerWorkarounds;
struct D3DUniform;
class ShaderD3D : public ShaderImpl
{
......@@ -33,7 +34,13 @@ class ShaderD3D : public ShaderImpl
// D3D-specific methods
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 getInterfaceBlockRegister(const std::string &blockName) const;
void appendDebugInfo(const std::string &info) const { mDebugInfo += info; }
......
......@@ -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.do_while_constant_iterations.nested_tricky_dataflow_* = 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
1020 WIN : dEQP-GLES2.functional.texture.mipmap.cube.basic.linear_nearest = FAIL
1020 WIN : dEQP-GLES2.functional.texture.mipmap.cube.basic.linear_linear = FAIL
......@@ -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_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
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
1108 WIN : dEQP-GLES2.functional.shaders.struct.local.dynamic_loop_struct_array_fragment = FAIL
......
......@@ -139,6 +139,8 @@ class Texture2DTest : public TexCoordDrawTest
);
}
virtual const char *getTextureUniformName() { return "tex"; }
void SetUp() override
{
TexCoordDrawTest::SetUp();
......@@ -146,7 +148,7 @@ class Texture2DTest : public TexCoordDrawTest
ASSERT_GL_NO_ERROR();
mTexture2DUniformLocation = glGetUniformLocation(mProgram, "tex");
mTexture2DUniformLocation = glGetUniformLocation(mProgram, getTextureUniformName());
ASSERT_NE(-1, mTexture2DUniformLocation);
}
......@@ -921,6 +923,152 @@ class SamplerTypeMixTestES3 : public TexCoordDrawTest
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)
{
glBindTexture(GL_TEXTURE_2D, mTexture2D);
......@@ -1864,6 +2012,39 @@ TEST_P(Texture2DTestES3, TextureCOMPRESSEDSRGB8ETC2ImplicitAlpha1)
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
{
protected:
......@@ -2310,6 +2491,36 @@ ANGLE_INSTANTIATE_TEST(ShadowSamplerPlusSampler3DTestES3,
ANGLE_INSTANTIATE_TEST(SamplerTypeMixTestES3, 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(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());
} // 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