Commit 616a4dc0 by Tim Van Patten Committed by Commit Bot

Vulkan: Full support for program interface queries

Program interface queries are a generic way to query attributes of the program like uniforms, samplers, attributes, etc. This change supports those queries for program outputs. Bug: angleproject:3596 Test: dEQP-GLES31.functional.program_interface_query.* Test: ProgramInterfaceTest.cpp Change-Id: I0f13692949073b45988b6f930eee9eaa6411bbe2 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/1801998 Commit-Queue: Tim Van Patten <timvp@google.com> Reviewed-by: 's avatarGeoff Lang <geofflang@chromium.org>
parent f10bf6bf
...@@ -787,8 +787,11 @@ std::string ParseResourceName(const std::string &name, std::vector<unsigned int> ...@@ -787,8 +787,11 @@ std::string ParseResourceName(const std::string &name, std::vector<unsigned int>
std::string StripLastArrayIndex(const std::string &name) std::string StripLastArrayIndex(const std::string &name)
{ {
size_t strippedNameLength = name.find_last_of('['); size_t strippedNameLength = name.find_last_of('[');
ASSERT(strippedNameLength != std::string::npos && name.back() == ']'); if (strippedNameLength != std::string::npos && name.back() == ']')
return name.substr(0, strippedNameLength); {
return name.substr(0, strippedNameLength);
}
return name;
} }
const sh::ShaderVariable *FindShaderVarField(const sh::ShaderVariable &var, const sh::ShaderVariable *FindShaderVarField(const sh::ShaderVariable &var,
......
...@@ -59,6 +59,15 @@ HashStream &operator<<(HashStream &stream, const ProgramBindings &bindings) ...@@ -59,6 +59,15 @@ HashStream &operator<<(HashStream &stream, const ProgramBindings &bindings)
{ {
for (const auto &binding : bindings) for (const auto &binding : bindings)
{ {
stream << binding.first << binding.second;
}
return stream;
}
HashStream &operator<<(HashStream &stream, const ProgramAliasedBindings &bindings)
{
for (const auto &binding : bindings)
{
stream << binding.first << binding.second.location; stream << binding.first << binding.second.location;
} }
return stream; return stream;
......
...@@ -401,6 +401,7 @@ class ProgramState final : angle::NonCopyable ...@@ -401,6 +401,7 @@ class ProgramState final : angle::NonCopyable
return mActiveSamplerFormats[textureUnitIndex]; return mActiveSamplerFormats[textureUnitIndex];
} }
ShaderType getFirstAttachedShaderStageType() const; ShaderType getFirstAttachedShaderStageType() const;
ShaderType getLastAttachedShaderStageType() const;
private: private:
friend class MemoryProgramCache; friend class MemoryProgramCache;
...@@ -410,6 +411,7 @@ class ProgramState final : angle::NonCopyable ...@@ -410,6 +411,7 @@ class ProgramState final : angle::NonCopyable
void updateActiveSamplers(); void updateActiveSamplers();
void updateActiveImages(); void updateActiveImages();
void updateProgramInterfaceInputs(); void updateProgramInterfaceInputs();
void updateProgramInterfaceOutputs();
// Scans the sampler bindings for type conflicts with sampler 'textureUnitIndex'. // Scans the sampler bindings for type conflicts with sampler 'textureUnitIndex'.
void setSamplerUniformTextureTypeAndFormat(size_t textureUnitIndex); void setSamplerUniformTextureTypeAndFormat(size_t textureUnitIndex);
...@@ -534,6 +536,25 @@ class ProgramBindings final : angle::NonCopyable ...@@ -534,6 +536,25 @@ class ProgramBindings final : angle::NonCopyable
int getBindingByName(const std::string &name) const; int getBindingByName(const std::string &name) const;
int getBinding(const sh::ShaderVariable &variable) const; int getBinding(const sh::ShaderVariable &variable) const;
using const_iterator = std::unordered_map<std::string, GLuint>::const_iterator;
const_iterator begin() const;
const_iterator end() const;
private:
std::unordered_map<std::string, GLuint> mBindings;
};
// Uniforms and Fragment Outputs require special treatment due to array notation (e.g., "[0]")
class ProgramAliasedBindings final : angle::NonCopyable
{
public:
ProgramAliasedBindings();
~ProgramAliasedBindings();
void bindLocation(GLuint index, const std::string &name);
int getBindingByName(const std::string &name) const;
int getBinding(const sh::ShaderVariable &variable) const;
using const_iterator = std::unordered_map<std::string, ProgramBinding>::const_iterator; using const_iterator = std::unordered_map<std::string, ProgramBinding>::const_iterator;
const_iterator begin() const; const_iterator begin() const;
const_iterator end() const; const_iterator end() const;
...@@ -883,14 +904,20 @@ class Program final : angle::NonCopyable, public LabeledObject ...@@ -883,14 +904,20 @@ class Program final : angle::NonCopyable, public LabeledObject
GLsizei *length, GLsizei *length,
GLchar *name) const; GLchar *name) const;
const sh::ShaderVariable &getInputResource(size_t index) const; const sh::ShaderVariable &getInputResource(size_t index) const;
GLuint getResourceMaxNameSize(const sh::ShaderVariable &resource, GLint max) const;
GLuint getInputResourceMaxNameSize() const; GLuint getInputResourceMaxNameSize() const;
GLuint getOutputResourceMaxNameSize() const;
GLuint getResourceLocation(const GLchar *name, const sh::ShaderVariable &variable) const;
GLuint getInputResourceLocation(const GLchar *name) const; GLuint getInputResourceLocation(const GLchar *name) const;
GLuint getOutputResourceLocation(const GLchar *name) const;
const std::string getResourceName(const sh::ShaderVariable &resource) const;
const std::string getInputResourceName(GLuint index) const; const std::string getInputResourceName(GLuint index) const;
const sh::ShaderVariable &getOutputResource(GLuint index) const; const std::string getOutputResourceName(GLuint index) const;
const sh::ShaderVariable &getOutputResource(size_t index) const;
const ProgramBindings &getAttributeBindings() const; const ProgramBindings &getAttributeBindings() const;
const ProgramBindings &getUniformLocationBindings() const;
const ProgramBindings &getFragmentInputBindings() const; const ProgramBindings &getFragmentInputBindings() const;
const ProgramAliasedBindings &getUniformLocationBindings() const;
int getNumViews() const int getNumViews() const
{ {
...@@ -942,8 +969,6 @@ class Program final : angle::NonCopyable, public LabeledObject ...@@ -942,8 +969,6 @@ class Program final : angle::NonCopyable, public LabeledObject
// Writes a program's binary to the output memory buffer. // Writes a program's binary to the output memory buffer.
void serialize(const Context *context, angle::MemoryBuffer *binaryOut) const; void serialize(const Context *context, angle::MemoryBuffer *binaryOut) const;
int getArrayIndexFromName(const GLchar *name) const;
private: private:
struct LinkingState; struct LinkingState;
...@@ -966,7 +991,7 @@ class Program final : angle::NonCopyable, public LabeledObject ...@@ -966,7 +991,7 @@ class Program final : angle::NonCopyable, public LabeledObject
bool linkUniforms(const Caps &caps, bool linkUniforms(const Caps &caps,
InfoLog &infoLog, InfoLog &infoLog,
const ProgramBindings &uniformLocationBindings, const ProgramAliasedBindings &uniformLocationBindings,
GLuint *combinedImageUniformsCount, GLuint *combinedImageUniformsCount,
std::vector<UnusedUniform> *unusedUniforms); std::vector<UnusedUniform> *unusedUniforms);
void linkSamplerAndImageBindings(GLuint *combinedImageUniformsCount); void linkSamplerAndImageBindings(GLuint *combinedImageUniformsCount);
...@@ -1050,8 +1075,6 @@ class Program final : angle::NonCopyable, public LabeledObject ...@@ -1050,8 +1075,6 @@ class Program final : angle::NonCopyable, public LabeledObject
void postResolveLink(const gl::Context *context); void postResolveLink(const gl::Context *context);
std::string stripArraySubscriptFromName(const GLchar *name) const;
ProgramState mState; ProgramState mState;
rx::ProgramImpl *mProgram; rx::ProgramImpl *mProgram;
...@@ -1061,14 +1084,14 @@ class Program final : angle::NonCopyable, public LabeledObject ...@@ -1061,14 +1084,14 @@ class Program final : angle::NonCopyable, public LabeledObject
// Note that this has nothing to do with binding layout qualifiers that can be set for some // Note that this has nothing to do with binding layout qualifiers that can be set for some
// uniforms in GLES3.1+. It is used to pre-set the location of uniforms. // uniforms in GLES3.1+. It is used to pre-set the location of uniforms.
ProgramBindings mUniformLocationBindings; ProgramAliasedBindings mUniformLocationBindings;
// CHROMIUM_path_rendering // CHROMIUM_path_rendering
ProgramBindings mFragmentInputBindings; ProgramBindings mFragmentInputBindings;
// EXT_blend_func_extended // EXT_blend_func_extended
ProgramBindings mFragmentOutputLocations; ProgramAliasedBindings mFragmentOutputLocations;
ProgramBindings mFragmentOutputIndexes; ProgramAliasedBindings mFragmentOutputIndexes;
bool mLinked; bool mLinked;
bool mLinkResolved; bool mLinkResolved;
......
...@@ -670,7 +670,7 @@ void UniformLinker::getResults(std::vector<LinkedUniform> *uniforms, ...@@ -670,7 +670,7 @@ void UniformLinker::getResults(std::vector<LinkedUniform> *uniforms,
bool UniformLinker::link(const Caps &caps, bool UniformLinker::link(const Caps &caps,
InfoLog &infoLog, InfoLog &infoLog,
const ProgramBindings &uniformLocationBindings) const ProgramAliasedBindings &uniformLocationBindings)
{ {
if (mState.getAttachedShader(ShaderType::Vertex) && if (mState.getAttachedShader(ShaderType::Vertex) &&
mState.getAttachedShader(ShaderType::Fragment)) mState.getAttachedShader(ShaderType::Fragment))
...@@ -735,7 +735,8 @@ bool UniformLinker::validateGraphicsUniforms(InfoLog &infoLog) const ...@@ -735,7 +735,8 @@ bool UniformLinker::validateGraphicsUniforms(InfoLog &infoLog) const
return true; return true;
} }
bool UniformLinker::indexUniforms(InfoLog &infoLog, const ProgramBindings &uniformLocationBindings) bool UniformLinker::indexUniforms(InfoLog &infoLog,
const ProgramAliasedBindings &uniformLocationBindings)
{ {
// Locations which have been allocated for an unused uniform. // Locations which have been allocated for an unused uniform.
std::set<GLuint> ignoredLocations; std::set<GLuint> ignoredLocations;
...@@ -830,7 +831,7 @@ bool UniformLinker::indexUniforms(InfoLog &infoLog, const ProgramBindings &unifo ...@@ -830,7 +831,7 @@ bool UniformLinker::indexUniforms(InfoLog &infoLog, const ProgramBindings &unifo
bool UniformLinker::gatherUniformLocationsAndCheckConflicts( bool UniformLinker::gatherUniformLocationsAndCheckConflicts(
InfoLog &infoLog, InfoLog &infoLog,
const ProgramBindings &uniformLocationBindings, const ProgramAliasedBindings &uniformLocationBindings,
std::set<GLuint> *ignoredLocations, std::set<GLuint> *ignoredLocations,
int *maxUniformLocation) int *maxUniformLocation)
{ {
......
...@@ -40,6 +40,7 @@ enum class LinkMismatchError; ...@@ -40,6 +40,7 @@ enum class LinkMismatchError;
struct LinkedUniform; struct LinkedUniform;
class ProgramState; class ProgramState;
class ProgramBindings; class ProgramBindings;
class ProgramAliasedBindings;
class Shader; class Shader;
struct ShaderVariableBuffer; struct ShaderVariableBuffer;
struct UnusedUniform; struct UnusedUniform;
...@@ -53,7 +54,9 @@ class UniformLinker final : angle::NonCopyable ...@@ -53,7 +54,9 @@ class UniformLinker final : angle::NonCopyable
UniformLinker(const ProgramState &state); UniformLinker(const ProgramState &state);
~UniformLinker(); ~UniformLinker();
bool link(const Caps &caps, InfoLog &infoLog, const ProgramBindings &uniformLocationBindings); bool link(const Caps &caps,
InfoLog &infoLog,
const ProgramAliasedBindings &uniformLocationBindings);
void getResults(std::vector<LinkedUniform> *uniforms, void getResults(std::vector<LinkedUniform> *uniforms,
std::vector<UnusedUniform> *unusedUniforms, std::vector<UnusedUniform> *unusedUniforms,
...@@ -73,11 +76,12 @@ class UniformLinker final : angle::NonCopyable ...@@ -73,11 +76,12 @@ class UniformLinker final : angle::NonCopyable
bool flattenUniformsAndCheckCaps(const Caps &caps, InfoLog &infoLog); bool flattenUniformsAndCheckCaps(const Caps &caps, InfoLog &infoLog);
bool checkMaxCombinedAtomicCounters(const Caps &caps, InfoLog &infoLog); bool checkMaxCombinedAtomicCounters(const Caps &caps, InfoLog &infoLog);
bool indexUniforms(InfoLog &infoLog, const ProgramBindings &uniformLocationBindings); bool indexUniforms(InfoLog &infoLog, const ProgramAliasedBindings &uniformLocationBindings);
bool gatherUniformLocationsAndCheckConflicts(InfoLog &infoLog, bool gatherUniformLocationsAndCheckConflicts(
const ProgramBindings &uniformLocationBindings, InfoLog &infoLog,
std::set<GLuint> *ignoredLocations, const ProgramAliasedBindings &uniformLocationBindings,
int *maxUniformLocation); std::set<GLuint> *ignoredLocations,
int *maxUniformLocation);
void pruneUnusedUniforms(); void pruneUnusedUniforms();
const ProgramState &mState; const ProgramState &mState;
......
...@@ -650,28 +650,40 @@ GLint GetInputResourceProperty(const Program *program, GLuint index, GLenum prop ...@@ -650,28 +650,40 @@ GLint GetInputResourceProperty(const Program *program, GLuint index, GLenum prop
GLint GetOutputResourceProperty(const Program *program, GLuint index, const GLenum prop) GLint GetOutputResourceProperty(const Program *program, GLuint index, const GLenum prop)
{ {
const auto &outputVariable = program->getOutputResource(index); const sh::ShaderVariable &outputVariable = program->getOutputResource(index);
switch (prop) switch (prop)
{ {
case GL_TYPE: case GL_TYPE:
case GL_ARRAY_SIZE: case GL_ARRAY_SIZE:
case GL_NAME_LENGTH:
return GetCommonVariableProperty(outputVariable, prop); return GetCommonVariableProperty(outputVariable, prop);
case GL_NAME_LENGTH:
return clampCast<GLint>(program->getOutputResourceName(index).size() + 1u);
case GL_LOCATION: case GL_LOCATION:
return program->getFragDataLocation(outputVariable.name); return outputVariable.location;
case GL_LOCATION_INDEX_EXT: case GL_LOCATION_INDEX_EXT:
// EXT_blend_func_extended // EXT_blend_func_extended
return program->getFragDataIndex(outputVariable.name); if (program->getState().getLastAttachedShaderStageType() == gl::ShaderType::Fragment)
{
case GL_REFERENCED_BY_FRAGMENT_SHADER: return program->getFragDataIndex(outputVariable.name);
return 1; }
return GL_INVALID_INDEX;
// The set of active user-defined outputs from the final shader stage in this program. If
// the final stage is a Fragment Shader, then this represents the fragment outputs that get
// written to individual color buffers. If the program only contains a Compute Shader, then
// there are no user-defined outputs.
case GL_REFERENCED_BY_VERTEX_SHADER: case GL_REFERENCED_BY_VERTEX_SHADER:
return program->getState().getLastAttachedShaderStageType() == ShaderType::Vertex;
case GL_REFERENCED_BY_FRAGMENT_SHADER:
return program->getState().getLastAttachedShaderStageType() == ShaderType::Fragment;
case GL_REFERENCED_BY_COMPUTE_SHADER: case GL_REFERENCED_BY_COMPUTE_SHADER:
return program->getState().getLastAttachedShaderStageType() == ShaderType::Compute;
case GL_REFERENCED_BY_GEOMETRY_SHADER_EXT: case GL_REFERENCED_BY_GEOMETRY_SHADER_EXT:
return 0; return program->getState().getLastAttachedShaderStageType() == ShaderType::Geometry;
default: default:
UNREACHABLE(); UNREACHABLE();
...@@ -756,8 +768,7 @@ GLint QueryProgramInterfaceMaxNameLength(const Program *program, GLenum programI ...@@ -756,8 +768,7 @@ GLint QueryProgramInterfaceMaxNameLength(const Program *program, GLenum programI
break; break;
case GL_PROGRAM_OUTPUT: case GL_PROGRAM_OUTPUT:
maxNameLength = maxNameLength = program->getOutputResourceMaxNameSize();
FindMaxSize(program->getState().getOutputVariables(), &sh::ShaderVariable::name);
break; break;
case GL_UNIFORM: case GL_UNIFORM:
...@@ -1847,7 +1858,7 @@ GLint QueryProgramResourceLocation(const Program *program, ...@@ -1847,7 +1858,7 @@ GLint QueryProgramResourceLocation(const Program *program,
return program->getInputResourceLocation(name); return program->getInputResourceLocation(name);
case GL_PROGRAM_OUTPUT: case GL_PROGRAM_OUTPUT:
return program->getFragDataLocation(name); return program->getOutputResourceLocation(name);
case GL_UNIFORM: case GL_UNIFORM:
return program->getUniformLocation(name); return program->getUniformLocation(name);
......
...@@ -522,13 +522,6 @@ void AssignAttributeLocations(const gl::ProgramState &programState, ...@@ -522,13 +522,6 @@ void AssignAttributeLocations(const gl::ProgramState &programState,
} }
} }
std::string RemoveArrayZeroSubscript(const std::string &expression)
{
ASSERT(expression.size() > 3);
ASSERT(expression.substr(expression.size() - 3) == "[0]");
return expression.substr(0, expression.size() - 3);
}
void AssignOutputLocations(const gl::ProgramState &programState, void AssignOutputLocations(const gl::ProgramState &programState,
IntermediateShaderSource *fragmentSource) IntermediateShaderSource *fragmentSource)
{ {
...@@ -545,21 +538,7 @@ void AssignOutputLocations(const gl::ProgramState &programState, ...@@ -545,21 +538,7 @@ void AssignOutputLocations(const gl::ProgramState &programState,
{ {
const sh::ShaderVariable &outputVar = outputVariables[outputLocation.index]; const sh::ShaderVariable &outputVar = outputVariables[outputLocation.index];
// In the following:
//
// out vec4 fragOutput[N];
//
// The varying name is |fragOutput[0]|. We need to remove the extra |[0]|.
std::string name = outputVar.name; std::string name = outputVar.name;
if (outputVar.isArray())
{
name = RemoveArrayZeroSubscript(name);
if (outputVar.isArrayOfArrays())
{
name = RemoveArrayZeroSubscript(name);
}
}
std::string locationString; std::string locationString;
if (outputVar.location != -1) if (outputVar.location != -1)
{ {
......
...@@ -798,6 +798,7 @@ void ProgramVk::initDefaultUniformLayoutMapping(gl::ShaderMap<sh::BlockLayoutMap ...@@ -798,6 +798,7 @@ void ProgramVk::initDefaultUniformLayoutMapping(gl::ShaderMap<sh::BlockLayoutMap
{ {
// Gets the uniform name without the [0] at the end. // Gets the uniform name without the [0] at the end.
uniformName = gl::StripLastArrayIndex(uniformName); uniformName = gl::StripLastArrayIndex(uniformName);
ASSERT(uniformName.size() != uniform.name.size());
} }
bool found = false; bool found = false;
......
...@@ -620,16 +620,6 @@ ...@@ -620,16 +620,6 @@
// SSBO and Image qualifiers: // SSBO and Image qualifiers:
3602 VULKAN : dEQP-GLES31.functional.synchronization.in_invocation.ssbo_alias_overwrite = FAIL 3602 VULKAN : dEQP-GLES31.functional.synchronization.in_invocation.ssbo_alias_overwrite = FAIL
// Separate shader objects:
3570 VULKAN : dEQP-GLES31.functional.program_interface_query.program_output.resource_list.separable_vertex.* = FAIL
3570 VULKAN : dEQP-GLES31.functional.program_interface_query.program_output.array_size.separable_vertex.var* = FAIL
3570 VULKAN : dEQP-GLES31.functional.program_interface_query.program_output.location.separable_vertex.var* = FAIL
3570 VULKAN : dEQP-GLES31.functional.program_interface_query.program_output.name_length.separable_vertex.var* = FAIL
3570 VULKAN : dEQP-GLES31.functional.program_interface_query.program_output.referenced_by.referenced_by_separable_vertex = FAIL
3570 VULKAN : dEQP-GLES31.functional.program_interface_query.program_output.type.separable_vertex.basic_type.* = FAIL
3570 VULKAN : dEQP-GLES31.functional.program_interface_query.program_output.type.separable_vertex.array.* = FAIL
3570 VULKAN : dEQP-GLES31.functional.program_interface_query.program_output.type.separable_vertex.struct.* = FAIL
// Block name matching failure: // Block name matching failure:
3459 VULKAN : dEQP-GLES31.functional.shaders.linkage.es31.shader_storage_block.mismatch_with_and_without_instance_name = FAIL 3459 VULKAN : dEQP-GLES31.functional.shaders.linkage.es31.shader_storage_block.mismatch_with_and_without_instance_name = FAIL
......
...@@ -231,6 +231,16 @@ class EXTBlendFuncExtendedDrawTestES3 : public EXTBlendFuncExtendedDrawTest ...@@ -231,6 +231,16 @@ class EXTBlendFuncExtendedDrawTestES3 : public EXTBlendFuncExtendedDrawTest
} }
} }
void LinkProgram()
{
glLinkProgram(mProgram);
GLint linked = 0;
glGetProgramiv(mProgram, GL_LINK_STATUS, &linked);
EXPECT_NE(0, linked);
glUseProgram(mProgram);
return;
}
private: private:
bool mIsES31OrNewer; bool mIsES31OrNewer;
}; };
...@@ -421,6 +431,121 @@ void main() { ...@@ -421,6 +431,121 @@ void main() {
drawTest(); drawTest();
} }
// Ported from TranslatorVariants/EXTBlendFuncExtendedES3DrawTest
// Test that tests glBindFragDataLocationEXT, glBindFragDataLocationIndexedEXT,
// glGetFragDataLocation, glGetFragDataIndexEXT work correctly with
// GLSL array output variables. The output variable can be bound by
// referring to the variable name with or without the first element array
// accessor. The getters can query location of the individual elements in
// the array. The test does not actually use the base test drawing,
// since the drivers at the time of writing do not support multiple
// buffers and dual source blending.
TEST_P(EXTBlendFuncExtendedDrawTestES3, ES3GettersArray)
{
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_blend_func_extended"));
// TODO(zmo): Figure out why this fails on AMD. crbug.com/585132.
// Also fails on the Intel Mesa driver, see
// https://bugs.freedesktop.org/show_bug.cgi?id=96765
ANGLE_SKIP_TEST_IF(IsLinux() && IsAMD());
ANGLE_SKIP_TEST_IF(IsLinux() && IsIntel());
const GLint kTestArraySize = 2;
const GLint kFragData0Location = 2;
const GLint kFragData1Location = 1;
const GLint kUnusedLocation = 5;
// The test binds kTestArraySize -sized array to location 1 for test purposes.
// The GL_MAX_DRAW_BUFFERS must be > kTestArraySize, since an
// array will be bound to continuous locations, starting from the first
// location.
GLint maxDrawBuffers = 0;
glGetIntegerv(GL_MAX_DRAW_BUFFERS_EXT, &maxDrawBuffers);
EXPECT_LT(kTestArraySize, maxDrawBuffers);
constexpr char kFragColorShader[] = R"(#version 300 es
#extension GL_EXT_blend_func_extended : require
precision mediump float;
uniform vec4 src;
uniform vec4 src1;
out vec4 FragData[2];
void main() {
FragData[0] = src;
FragData[1] = src1;
})";
struct testCase
{
std::string unusedLocationName;
std::string fragData0LocationName;
std::string fragData1LocationName;
};
testCase testCases[4]{{"FragData[0]", "FragData", "FragData[1]"},
{"FragData", "FragData[0]", "FragData[1]"},
{"FragData[0]", "FragData", "FragData[1]"},
{"FragData", "FragData[0]", "FragData[1]"}};
for (const testCase &test : testCases)
{
mProgram =
CompileProgram(essl3_shaders::vs::Simple(), kFragColorShader, [&](GLuint program) {
glBindFragDataLocationEXT(program, kUnusedLocation,
test.unusedLocationName.c_str());
glBindFragDataLocationEXT(program, kFragData0Location,
test.fragData0LocationName.c_str());
glBindFragDataLocationEXT(program, kFragData1Location,
test.fragData1LocationName.c_str());
});
EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError());
LinkProgram();
EXPECT_EQ(kFragData0Location, glGetFragDataLocation(mProgram, "FragData"));
EXPECT_EQ(0, glGetFragDataIndexEXT(mProgram, "FragData"));
EXPECT_EQ(kFragData0Location, glGetFragDataLocation(mProgram, "FragData[0]"));
EXPECT_EQ(0, glGetFragDataIndexEXT(mProgram, "FragData[0]"));
EXPECT_EQ(kFragData1Location, glGetFragDataLocation(mProgram, "FragData[1]"));
EXPECT_EQ(0, glGetFragDataIndexEXT(mProgram, "FragData[1]"));
// Index bigger than the GLSL variable array length does not find anything.
EXPECT_EQ(-1, glGetFragDataLocation(mProgram, "FragData[3]"));
}
}
// Ported from TranslatorVariants/EXTBlendFuncExtendedES3DrawTest
TEST_P(EXTBlendFuncExtendedDrawTestES3, ESSL3BindSimpleVarAsArrayNoBind)
{
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_blend_func_extended"));
constexpr char kFragDataShader[] = R"(#version 300 es
#extension GL_EXT_blend_func_extended : require
precision mediump float;
uniform vec4 src;
uniform vec4 src1;
out vec4 FragData;
out vec4 SecondaryFragData;
void main() {
FragData = src;
SecondaryFragData = src1;
})";
mProgram = CompileProgram(essl3_shaders::vs::Simple(), kFragDataShader, [](GLuint program) {
glBindFragDataLocationEXT(program, 0, "FragData[0]");
glBindFragDataLocationIndexedEXT(program, 0, 1, "SecondaryFragData[0]");
});
LinkProgram();
EXPECT_EQ(-1, glGetFragDataLocation(mProgram, "FragData[0]"));
EXPECT_EQ(0, glGetFragDataLocation(mProgram, "FragData"));
EXPECT_EQ(1, glGetFragDataLocation(mProgram, "SecondaryFragData"));
// Did not bind index.
EXPECT_EQ(0, glGetFragDataIndexEXT(mProgram, "SecondaryFragData"));
glBindFragDataLocationEXT(mProgram, 0, "FragData");
glBindFragDataLocationIndexedEXT(mProgram, 0, 1, "SecondaryFragData");
LinkProgram();
}
// Test an ESSL 3.00 program with a link-time fragment output location conflict. // Test an ESSL 3.00 program with a link-time fragment output location conflict.
TEST_P(EXTBlendFuncExtendedTestES3, FragmentOutputLocationConflict) TEST_P(EXTBlendFuncExtendedTestES3, FragmentOutputLocationConflict)
{ {
...@@ -592,7 +717,9 @@ ANGLE_INSTANTIATE_TEST(EXTBlendFuncExtendedTestES3, ...@@ -592,7 +717,9 @@ ANGLE_INSTANTIATE_TEST(EXTBlendFuncExtendedTestES3,
ES3_OPENGL(), ES3_OPENGL(),
ES3_OPENGLES(), ES3_OPENGLES(),
ES31_OPENGL(), ES31_OPENGL(),
ES31_OPENGLES()); ES31_OPENGLES(),
ES3_VULKAN(),
ES31_VULKAN());
ANGLE_INSTANTIATE_TEST(EXTBlendFuncExtendedDrawTest, ANGLE_INSTANTIATE_TEST(EXTBlendFuncExtendedDrawTest,
ES2_OPENGL(), ES2_OPENGL(),
ES2_OPENGLES(), ES2_OPENGLES(),
...@@ -603,4 +730,6 @@ ANGLE_INSTANTIATE_TEST(EXTBlendFuncExtendedDrawTestES3, ...@@ -603,4 +730,6 @@ ANGLE_INSTANTIATE_TEST(EXTBlendFuncExtendedDrawTestES3,
ES3_OPENGL(), ES3_OPENGL(),
ES3_OPENGLES(), ES3_OPENGLES(),
ES31_OPENGL(), ES31_OPENGL(),
ES31_OPENGLES()); ES31_OPENGLES(),
ES3_VULKAN(),
ES31_VULKAN());
...@@ -1195,6 +1195,10 @@ void main() { ...@@ -1195,6 +1195,10 @@ void main() {
glDeleteProgram(program); glDeleteProgram(program);
} }
ANGLE_INSTANTIATE_TEST(ProgramInterfaceTestES31, ES31_OPENGL(), ES31_OPENGLES(), ES31_D3D11()); ANGLE_INSTANTIATE_TEST(ProgramInterfaceTestES31,
ES31_OPENGL(),
ES31_OPENGLES(),
ES31_D3D11(),
ES31_VULKAN());
} // anonymous namespace } // anonymous 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