Commit 15015f7f by jchen10 Committed by Commit Bot

ES31: Add glGetProgramResourceIndex API

Add API entry and validation checks(GLES 3.1 section 7.3). Add the first 2 interfaces(PROGRAM_INPUT and PROGRAM_OUTPUT) implementation. BUG=angleproject:1920 Change-Id: Ib2dedded9fd79b315e9f38de7c27a5e4ec4c6066 Reviewed-on: https://chromium-review.googlesource.com/453085 Commit-Queue: Jamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarCorentin Wallez <cwallez@chromium.org>
parent f651c773
...@@ -697,7 +697,7 @@ int VariableSortOrder(GLenum type) ...@@ -697,7 +697,7 @@ int VariableSortOrder(GLenum type)
} }
} }
std::string ParseUniformName(const std::string &name, size_t *outSubscript) std::string ParseResourceName(const std::string &name, size_t *outSubscript)
{ {
// Strip any trailing array operator and retrieve the subscript // Strip any trailing array operator and retrieve the subscript
size_t open = name.find_last_of('['); size_t open = name.find_last_of('[');
......
...@@ -48,9 +48,10 @@ bool IsCubeMapTextureTarget(GLenum target); ...@@ -48,9 +48,10 @@ bool IsCubeMapTextureTarget(GLenum target);
size_t CubeMapTextureTargetToLayerIndex(GLenum target); size_t CubeMapTextureTargetToLayerIndex(GLenum target);
GLenum LayerIndexToCubeMapTextureTarget(size_t index); GLenum LayerIndexToCubeMapTextureTarget(size_t index);
// Parse the base uniform name and array index. Returns the base name of the uniform. outSubscript is // Parse the base resource name and array index. Returns the base name of the resource.
// set to GL_INVALID_INDEX if the provided name is not an array or the array index is invalid. // outSubscript is set to GL_INVALID_INDEX if the provided name is not an array or the array index
std::string ParseUniformName(const std::string &name, size_t *outSubscript); // is invalid.
std::string ParseResourceName(const std::string &name, size_t *outSubscript);
// Find the range of index values in the provided indices pointer. Primitive restart indices are // Find the range of index values in the provided indices pointer. Primitive restart indices are
// only counted in the range if primitive restart is disabled. // only counted in the range if primitive restart is disabled.
......
...@@ -13,42 +13,42 @@ ...@@ -13,42 +13,42 @@
namespace namespace
{ {
TEST(ParseUniformName, ArrayIndex) TEST(ParseResourceName, ArrayIndex)
{ {
size_t index; size_t index;
EXPECT_EQ("foo", gl::ParseUniformName("foo[123]", &index)); EXPECT_EQ("foo", gl::ParseResourceName("foo[123]", &index));
EXPECT_EQ(123u, index); EXPECT_EQ(123u, index);
EXPECT_EQ("bar", gl::ParseUniformName("bar[0]", &index)); EXPECT_EQ("bar", gl::ParseResourceName("bar[0]", &index));
EXPECT_EQ(0u, index); EXPECT_EQ(0u, index);
} }
TEST(ParseUniformName, NegativeArrayIndex) TEST(ParseResourceName, NegativeArrayIndex)
{ {
size_t index; size_t index;
EXPECT_EQ("foo", gl::ParseUniformName("foo[-1]", &index)); EXPECT_EQ("foo", gl::ParseResourceName("foo[-1]", &index));
EXPECT_EQ(GL_INVALID_INDEX, index); EXPECT_EQ(GL_INVALID_INDEX, index);
} }
TEST(ParseUniformName, NoArrayIndex) TEST(ParseResourceName, NoArrayIndex)
{ {
size_t index; size_t index;
EXPECT_EQ("foo", gl::ParseUniformName("foo", &index)); EXPECT_EQ("foo", gl::ParseResourceName("foo", &index));
EXPECT_EQ(GL_INVALID_INDEX, index); EXPECT_EQ(GL_INVALID_INDEX, index);
} }
TEST(ParseUniformName, NULLArrayIndex) TEST(ParseResourceName, NULLArrayIndex)
{ {
EXPECT_EQ("foo", gl::ParseUniformName("foo[10]", nullptr)); EXPECT_EQ("foo", gl::ParseResourceName("foo[10]", nullptr));
} }
TEST(ParseUniformName, TrailingWhitespace) TEST(ParseResourceName, TrailingWhitespace)
{ {
size_t index; size_t index;
EXPECT_EQ("foo ", gl::ParseUniformName("foo ", &index)); EXPECT_EQ("foo ", gl::ParseResourceName("foo ", &index));
EXPECT_EQ(GL_INVALID_INDEX, index); EXPECT_EQ(GL_INVALID_INDEX, index);
EXPECT_EQ("foo[10] ", gl::ParseUniformName("foo[10] ", &index)); EXPECT_EQ("foo[10] ", gl::ParseResourceName("foo[10] ", &index));
EXPECT_EQ(GL_INVALID_INDEX, index); EXPECT_EQ(GL_INVALID_INDEX, index);
} }
......
...@@ -2038,6 +2038,12 @@ void Context::programPathFragmentInputGen(GLuint program, ...@@ -2038,6 +2038,12 @@ void Context::programPathFragmentInputGen(GLuint program,
programObject->pathFragmentInputGen(location, genMode, components, coeffs); programObject->pathFragmentInputGen(location, genMode, components, coeffs);
} }
GLuint Context::getProgramResourceIndex(GLuint program, GLenum programInterface, const GLchar *name)
{
gl::Program *programObject = getProgram(program);
return QueryProgramResourceIndex(programObject, programInterface, name);
}
void Context::handleError(const Error &error) void Context::handleError(const Error &error)
{ {
if (error.isError()) if (error.isError())
......
...@@ -188,6 +188,8 @@ class Context final : public ValidationContext ...@@ -188,6 +188,8 @@ class Context final : public ValidationContext
void programParameteri(GLuint program, GLenum pname, GLint value); void programParameteri(GLuint program, GLenum pname, GLint value);
GLuint getProgramResourceIndex(GLuint program, GLenum programInterface, const GLchar *name);
Buffer *getBuffer(GLuint handle) const; Buffer *getBuffer(GLuint handle) const;
FenceNV *getFenceNV(GLuint handle); FenceNV *getFenceNV(GLuint handle);
FenceSync *getFenceSync(GLsync handle) const; FenceSync *getFenceSync(GLsync handle) const;
......
...@@ -132,6 +132,33 @@ bool ComparePackedVarying(const PackedVarying &x, const PackedVarying &y) ...@@ -132,6 +132,33 @@ bool ComparePackedVarying(const PackedVarying &x, const PackedVarying &y)
return gl::CompareShaderVar(*x.varying, *y.varying); return gl::CompareShaderVar(*x.varying, *y.varying);
} }
template <typename VarT>
GLuint GetResourceIndexFromName(const std::vector<VarT> &list, const std::string &name)
{
size_t subscript = GL_INVALID_INDEX;
std::string baseName = ParseResourceName(name, &subscript);
// The app is not allowed to specify array indices other than 0 for arrays of basic types
if (subscript != 0 && subscript != GL_INVALID_INDEX)
{
return GL_INVALID_INDEX;
}
for (size_t index = 0; index < list.size(); index++)
{
const VarT &resource = list[index];
if (resource.name == baseName)
{
if (resource.isArray() || subscript == GL_INVALID_INDEX)
{
return static_cast<GLuint>(index);
}
}
}
return GL_INVALID_INDEX;
}
} // anonymous namespace } // anonymous namespace
const char *const g_fakepath = "C:\\fakepath"; const char *const g_fakepath = "C:\\fakepath";
...@@ -255,7 +282,7 @@ const std::string &ProgramState::getLabel() ...@@ -255,7 +282,7 @@ const std::string &ProgramState::getLabel()
GLint ProgramState::getUniformLocation(const std::string &name) const GLint ProgramState::getUniformLocation(const std::string &name) const
{ {
size_t subscript = GL_INVALID_INDEX; size_t subscript = GL_INVALID_INDEX;
std::string baseName = ParseUniformName(name, &subscript); std::string baseName = ParseResourceName(name, &subscript);
for (size_t location = 0; location < mUniformLocations.size(); ++location) for (size_t location = 0; location < mUniformLocations.size(); ++location)
{ {
...@@ -292,28 +319,7 @@ GLint ProgramState::getUniformLocation(const std::string &name) const ...@@ -292,28 +319,7 @@ GLint ProgramState::getUniformLocation(const std::string &name) const
GLuint ProgramState::getUniformIndexFromName(const std::string &name) const GLuint ProgramState::getUniformIndexFromName(const std::string &name) const
{ {
size_t subscript = GL_INVALID_INDEX; return GetResourceIndexFromName(mUniforms, name);
std::string baseName = ParseUniformName(name, &subscript);
// The app is not allowed to specify array indices other than 0 for arrays of basic types
if (subscript != 0 && subscript != GL_INVALID_INDEX)
{
return GL_INVALID_INDEX;
}
for (size_t index = 0; index < mUniforms.size(); index++)
{
const LinkedUniform &uniform = mUniforms[index];
if (uniform.name == baseName)
{
if (uniform.isArray() || subscript == GL_INVALID_INDEX)
{
return static_cast<GLuint>(index);
}
}
}
return GL_INVALID_INDEX;
} }
GLuint ProgramState::getUniformIndexFromLocation(GLint location) const GLuint ProgramState::getUniformIndexFromLocation(GLint location) const
...@@ -487,7 +493,7 @@ void Program::bindAttributeLocation(GLuint index, const char *name) ...@@ -487,7 +493,7 @@ void Program::bindAttributeLocation(GLuint index, const char *name)
void Program::bindUniformLocation(GLuint index, const char *name) void Program::bindUniformLocation(GLuint index, const char *name)
{ {
// Bind the base uniform name only since array indices other than 0 cannot be bound // Bind the base uniform name only since array indices other than 0 cannot be bound
mUniformLocationBindings.bindLocation(index, ParseUniformName(name, nullptr)); mUniformLocationBindings.bindLocation(index, ParseResourceName(name, nullptr));
} }
void Program::bindFragmentInputLocation(GLint index, const char *name) void Program::bindFragmentInputLocation(GLint index, const char *name)
...@@ -720,6 +726,7 @@ void Program::unlink() ...@@ -720,6 +726,7 @@ void Program::unlink()
mState.mUniformLocations.clear(); mState.mUniformLocations.clear();
mState.mUniformBlocks.clear(); mState.mUniformBlocks.clear();
mState.mOutputVariables.clear(); mState.mOutputVariables.clear();
mState.mOutputLocations.clear();
mState.mComputeShaderLocalSize.fill(1); mState.mComputeShaderLocalSize.fill(1);
mState.mSamplerBindings.clear(); mState.mSamplerBindings.clear();
...@@ -865,6 +872,16 @@ Error Program::loadBinary(const Context *context, ...@@ -865,6 +872,16 @@ Error Program::loadBinary(const Context *context,
stream.readInt(&mState.mTransformFeedbackBufferMode); stream.readInt(&mState.mTransformFeedbackBufferMode);
unsigned int outputCount = stream.readInt<unsigned int>();
ASSERT(mState.mOutputVariables.empty());
for (unsigned int outputIndex = 0; outputIndex < outputCount; ++outputIndex)
{
sh::OutputVariable output;
LoadShaderVar(&stream, &output);
output.location = stream.readInt<int>();
mState.mOutputVariables.push_back(output);
}
unsigned int outputVarCount = stream.readInt<unsigned int>(); unsigned int outputVarCount = stream.readInt<unsigned int>();
for (unsigned int outputIndex = 0; outputIndex < outputVarCount; ++outputIndex) for (unsigned int outputIndex = 0; outputIndex < outputVarCount; ++outputIndex)
{ {
...@@ -873,7 +890,7 @@ Error Program::loadBinary(const Context *context, ...@@ -873,7 +890,7 @@ Error Program::loadBinary(const Context *context,
stream.readInt(&locationData.element); stream.readInt(&locationData.element);
stream.readInt(&locationData.index); stream.readInt(&locationData.index);
stream.readString(&locationData.name); stream.readString(&locationData.name);
mState.mOutputVariables[locationIndex] = locationData; mState.mOutputLocations[locationIndex] = locationData;
} }
stream.readInt(&mState.mSamplerUniformRange.start); stream.readInt(&mState.mSamplerUniformRange.start);
...@@ -991,7 +1008,14 @@ Error Program::saveBinary(const Context *context, ...@@ -991,7 +1008,14 @@ Error Program::saveBinary(const Context *context,
stream.writeInt(mState.mTransformFeedbackBufferMode); stream.writeInt(mState.mTransformFeedbackBufferMode);
stream.writeInt(mState.mOutputVariables.size()); stream.writeInt(mState.mOutputVariables.size());
for (const auto &outputPair : mState.mOutputVariables) for (const sh::OutputVariable &output : mState.mOutputVariables)
{
WriteShaderVar(&stream, output);
stream.writeInt(output.location);
}
stream.writeInt(mState.mOutputLocations.size());
for (const auto &outputPair : mState.mOutputLocations)
{ {
stream.writeInt(outputPair.first); stream.writeInt(outputPair.first);
stream.writeIntOrNegOne(outputPair.second.element); stream.writeIntOrNegOne(outputPair.second.element);
...@@ -1222,11 +1246,29 @@ GLint Program::getActiveAttributeMaxLength() const ...@@ -1222,11 +1246,29 @@ GLint Program::getActiveAttributeMaxLength() const
return static_cast<GLint>(maxLength); return static_cast<GLint>(maxLength);
} }
GLuint Program::getInputResourceIndex(const GLchar *name) const
{
for (GLuint attributeIndex = 0; attributeIndex < mState.mAttributes.size(); ++attributeIndex)
{
const sh::Attribute &attribute = mState.mAttributes[attributeIndex];
if (attribute.name == name)
{
return attributeIndex;
}
}
return GL_INVALID_INDEX;
}
GLuint Program::getOutputResourceIndex(const GLchar *name) const
{
return GetResourceIndexFromName(mState.mOutputVariables, std::string(name));
}
GLint Program::getFragDataLocation(const std::string &name) const GLint Program::getFragDataLocation(const std::string &name) const
{ {
std::string baseName(name); std::string baseName(name);
unsigned int arrayIndex = ParseAndStripArrayIndex(&baseName); unsigned int arrayIndex = ParseAndStripArrayIndex(&baseName);
for (auto outputPair : mState.mOutputVariables) for (auto outputPair : mState.mOutputLocations)
{ {
const VariableLocation &outputVariable = outputPair.second; const VariableLocation &outputVariable = outputPair.second;
if (outputVariable.name == baseName && (arrayIndex == GL_INVALID_INDEX || arrayIndex == outputVariable.element)) if (outputVariable.name == baseName && (arrayIndex == GL_INVALID_INDEX || arrayIndex == outputVariable.element))
...@@ -1679,7 +1721,7 @@ GLint Program::getActiveUniformBlockMaxLength() const ...@@ -1679,7 +1721,7 @@ GLint Program::getActiveUniformBlockMaxLength() const
GLuint Program::getUniformBlockIndex(const std::string &name) const GLuint Program::getUniformBlockIndex(const std::string &name) const
{ {
size_t subscript = GL_INVALID_INDEX; size_t subscript = GL_INVALID_INDEX;
std::string baseName = ParseUniformName(name, &subscript); std::string baseName = ParseResourceName(name, &subscript);
unsigned int numUniformBlocks = static_cast<unsigned int>(mState.mUniformBlocks.size()); unsigned int numUniformBlocks = static_cast<unsigned int>(mState.mUniformBlocks.size());
for (unsigned int blockIndex = 0; blockIndex < numUniformBlocks; blockIndex++) for (unsigned int blockIndex = 0; blockIndex < numUniformBlocks; blockIndex++)
...@@ -2505,14 +2547,13 @@ void Program::linkOutputVariables() ...@@ -2505,14 +2547,13 @@ void Program::linkOutputVariables()
if (fragmentShader->getShaderVersion() == 100) if (fragmentShader->getShaderVersion() == 100)
return; return;
const auto &shaderOutputVars = fragmentShader->getActiveOutputVariables(); mState.mOutputVariables = fragmentShader->getActiveOutputVariables();
// TODO(jmadill): any caps validation here? // TODO(jmadill): any caps validation here?
for (unsigned int outputVariableIndex = 0; outputVariableIndex < shaderOutputVars.size(); for (unsigned int outputVariableIndex = 0; outputVariableIndex < mState.mOutputVariables.size();
outputVariableIndex++) outputVariableIndex++)
{ {
const sh::OutputVariable &outputVariable = shaderOutputVars[outputVariableIndex]; const sh::OutputVariable &outputVariable = mState.mOutputVariables[outputVariableIndex];
// Don't store outputs for gl_FragDepth, gl_FragColor, etc. // Don't store outputs for gl_FragDepth, gl_FragColor, etc.
if (outputVariable.isBuiltIn()) if (outputVariable.isBuiltIn())
...@@ -2525,9 +2566,9 @@ void Program::linkOutputVariables() ...@@ -2525,9 +2566,9 @@ void Program::linkOutputVariables()
elementIndex++) elementIndex++)
{ {
const int location = baseLocation + elementIndex; const int location = baseLocation + elementIndex;
ASSERT(mState.mOutputVariables.count(location) == 0); ASSERT(mState.mOutputLocations.count(location) == 0);
unsigned int element = outputVariable.isArray() ? elementIndex : GL_INVALID_INDEX; unsigned int element = outputVariable.isArray() ? elementIndex : GL_INVALID_INDEX;
mState.mOutputVariables[location] = mState.mOutputLocations[location] =
VariableLocation(outputVariable.name, element, outputVariableIndex); VariableLocation(outputVariable.name, element, outputVariableIndex);
} }
} }
......
...@@ -205,7 +205,7 @@ class ProgramState final : angle::NonCopyable ...@@ -205,7 +205,7 @@ class ProgramState final : angle::NonCopyable
{ {
return mActiveAttribLocationsMask; return mActiveAttribLocationsMask;
} }
const std::map<int, VariableLocation> &getOutputVariables() const { return mOutputVariables; } const std::map<int, VariableLocation> &getOutputLocations() const { return mOutputLocations; }
const std::vector<LinkedUniform> &getUniforms() const { return mUniforms; } const std::vector<LinkedUniform> &getUniforms() const { return mUniforms; }
const std::vector<VariableLocation> &getUniformLocations() const { return mUniformLocations; } const std::vector<VariableLocation> &getUniformLocations() const { return mUniformLocations; }
const std::vector<UniformBlock> &getUniformBlocks() const { return mUniformBlocks; } const std::vector<UniformBlock> &getUniformBlocks() const { return mUniformBlocks; }
...@@ -252,8 +252,9 @@ class ProgramState final : angle::NonCopyable ...@@ -252,8 +252,9 @@ class ProgramState final : angle::NonCopyable
// An array of the samplers that are used by the program // An array of the samplers that are used by the program
std::vector<gl::SamplerBinding> mSamplerBindings; std::vector<gl::SamplerBinding> mSamplerBindings;
std::vector<sh::OutputVariable> mOutputVariables;
// TODO(jmadill): use unordered/hash map when available // TODO(jmadill): use unordered/hash map when available
std::map<int, VariableLocation> mOutputVariables; std::map<int, VariableLocation> mOutputLocations;
bool mBinaryRetrieveableHint; bool mBinaryRetrieveableHint;
}; };
...@@ -411,6 +412,9 @@ class Program final : angle::NonCopyable, public LabeledObject ...@@ -411,6 +412,9 @@ class Program final : angle::NonCopyable, public LabeledObject
const sh::ShaderVariable &fragmentVariable, const sh::ShaderVariable &fragmentVariable,
bool validatePrecision); bool validatePrecision);
GLuint getInputResourceIndex(const GLchar *name) const;
GLuint getOutputResourceIndex(const GLchar *name) const;
class Bindings final : angle::NonCopyable class Bindings final : angle::NonCopyable
{ {
public: public:
......
...@@ -939,6 +939,33 @@ void SetFramebufferParameteri(Framebuffer *framebuffer, GLenum pname, GLint para ...@@ -939,6 +939,33 @@ void SetFramebufferParameteri(Framebuffer *framebuffer, GLenum pname, GLint para
} }
} }
GLuint QueryProgramResourceIndex(const Program *program,
GLenum programInterface,
const GLchar *name)
{
switch (programInterface)
{
case GL_PROGRAM_INPUT:
return program->getInputResourceIndex(name);
case GL_PROGRAM_OUTPUT:
return program->getOutputResourceIndex(name);
// TODO(Jie): more interfaces.
case GL_UNIFORM:
case GL_UNIFORM_BLOCK:
case GL_TRANSFORM_FEEDBACK_VARYING:
case GL_BUFFER_VARIABLE:
case GL_SHADER_STORAGE_BLOCK:
UNIMPLEMENTED();
return GL_INVALID_INDEX;
default:
UNREACHABLE();
return GL_INVALID_INDEX;
}
}
} // namespace gl } // namespace gl
namespace egl namespace egl
......
...@@ -107,6 +107,10 @@ void SetSamplerParameteriv(Sampler *sampler, GLenum pname, const GLint *params); ...@@ -107,6 +107,10 @@ void SetSamplerParameteriv(Sampler *sampler, GLenum pname, const GLint *params);
void SetFramebufferParameteri(Framebuffer *framebuffer, GLenum pname, GLint param); void SetFramebufferParameteri(Framebuffer *framebuffer, GLenum pname, GLint param);
GLuint QueryProgramResourceIndex(const Program *program,
GLenum programInterface,
const GLchar *name);
} // namespace gl } // namespace gl
namespace egl namespace egl
......
...@@ -1130,7 +1130,7 @@ void DynamicHLSL::getPixelShaderOutputKey(const gl::ContextState &data, ...@@ -1130,7 +1130,7 @@ void DynamicHLSL::getPixelShaderOutputKey(const gl::ContextState &data,
const auto &shaderOutputVars = const auto &shaderOutputVars =
metadata.getFragmentShader()->getData().getActiveOutputVariables(); metadata.getFragmentShader()->getData().getActiveOutputVariables();
for (auto outputPair : programData.getOutputVariables()) for (auto outputPair : programData.getOutputLocations())
{ {
const VariableLocation &outputLocation = outputPair.second; const VariableLocation &outputLocation = outputPair.second;
const sh::ShaderVariable &outputVariable = shaderOutputVars[outputLocation.index]; const sh::ShaderVariable &outputVariable = shaderOutputVars[outputLocation.index];
......
...@@ -21,6 +21,28 @@ using namespace angle; ...@@ -21,6 +21,28 @@ using namespace angle;
namespace gl namespace gl
{ {
namespace
{
bool ValidateNamedProgramInterface(GLenum programInterface)
{
switch (programInterface)
{
case GL_UNIFORM:
case GL_UNIFORM_BLOCK:
case GL_PROGRAM_INPUT:
case GL_PROGRAM_OUTPUT:
case GL_TRANSFORM_FEEDBACK_VARYING:
case GL_BUFFER_VARIABLE:
case GL_SHADER_STORAGE_BLOCK:
return true;
default:
return false;
}
}
} // anonymous namespace
bool ValidateGetBooleani_v(Context *context, GLenum target, GLuint index, GLboolean *data) bool ValidateGetBooleani_v(Context *context, GLenum target, GLuint index, GLboolean *data)
{ {
if (context->getClientVersion() < ES_3_1) if (context->getClientVersion() < ES_3_1)
...@@ -505,4 +527,30 @@ bool ValidationGetFramebufferParameteri(Context *context, ...@@ -505,4 +527,30 @@ bool ValidationGetFramebufferParameteri(Context *context,
return true; return true;
} }
bool ValidateGetProgramResourceIndex(Context *context,
GLuint program,
GLenum programInterface,
const GLchar *name)
{
if (context->getClientVersion() < ES_3_1)
{
context->handleError(Error(GL_INVALID_OPERATION, "Context does not support GLES 3.1."));
return false;
}
Program *programObject = GetValidProgram(context, program);
if (programObject == nullptr)
{
return false;
}
if (!ValidateNamedProgramInterface(programInterface))
{
context->handleError(
Error(GL_INVALID_ENUM, "Invalid program interface: 0x%X", programInterface));
return false;
}
return true;
}
} // namespace gl } // namespace gl
...@@ -55,6 +55,12 @@ bool ValidationGetFramebufferParameteri(Context *context, ...@@ -55,6 +55,12 @@ bool ValidationGetFramebufferParameteri(Context *context,
GLenum target, GLenum target,
GLenum pname, GLenum pname,
GLint *params); GLint *params);
bool ValidateGetProgramResourceIndex(Context *context,
GLuint program,
GLenum programInterface,
const GLchar *name);
} // namespace gl } // namespace gl
#endif // LIBANGLE_VALIDATION_ES31_H_ #endif // LIBANGLE_VALIDATION_ES31_H_
...@@ -145,11 +145,12 @@ GLuint GL_APIENTRY GetProgramResourceIndex(GLuint program, ...@@ -145,11 +145,12 @@ GLuint GL_APIENTRY GetProgramResourceIndex(GLuint program,
Context *context = GetValidGlobalContext(); Context *context = GetValidGlobalContext();
if (context) if (context)
{ {
if (!context->skipValidation()) if (!context->skipValidation() &&
!ValidateGetProgramResourceIndex(context, program, programInterface, name))
{ {
context->handleError(Error(GL_INVALID_OPERATION, "Entry point not implemented")); return GL_INVALID_INDEX;
} }
UNIMPLEMENTED(); return context->getProgramResourceIndex(program, programInterface, name);
} }
return 0u; return 0u;
} }
......
...@@ -64,6 +64,7 @@ ...@@ -64,6 +64,7 @@
'<(angle_path)/src/tests/gl_tests/ObjectAllocationTest.cpp', '<(angle_path)/src/tests/gl_tests/ObjectAllocationTest.cpp',
'<(angle_path)/src/tests/gl_tests/OcclusionQueriesTest.cpp', '<(angle_path)/src/tests/gl_tests/OcclusionQueriesTest.cpp',
'<(angle_path)/src/tests/gl_tests/ProgramBinaryTest.cpp', '<(angle_path)/src/tests/gl_tests/ProgramBinaryTest.cpp',
'<(angle_path)/src/tests/gl_tests/ProgramInterfaceTest.cpp',
'<(angle_path)/src/tests/gl_tests/ReadPixelsTest.cpp', '<(angle_path)/src/tests/gl_tests/ReadPixelsTest.cpp',
'<(angle_path)/src/tests/gl_tests/RendererTest.cpp', '<(angle_path)/src/tests/gl_tests/RendererTest.cpp',
'<(angle_path)/src/tests/gl_tests/RobustClientMemoryTest.cpp', '<(angle_path)/src/tests/gl_tests/RobustClientMemoryTest.cpp',
......
//
// Copyright 2017 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// ProgramInterfaceTest: Tests of program interfaces.
#include "test_utils/ANGLETest.h"
#include "test_utils/gl_raii.h"
using namespace angle;
namespace
{
class ProgramInterfaceTestES31 : public ANGLETest
{
protected:
ProgramInterfaceTestES31()
{
setWindowWidth(64);
setWindowHeight(64);
setConfigRedBits(8);
setConfigGreenBits(8);
setConfigBlueBits(8);
setConfigAlphaBits(8);
}
};
// Tests glGetProgramResourceIndex.
TEST_P(ProgramInterfaceTestES31, GetResourceIndex)
{
const std::string &vertexShaderSource =
"#version 310 es\n"
"precision highp float;\n"
"in highp vec4 position;\n"
"void main()\n"
"{\n"
" gl_Position = position;\n"
"}";
const std::string fragmentShaderSource =
"#version 310 es\n"
"precision highp float;\n"
"uniform vec4 color;\n"
"out vec4 oColor;\n"
"void main()\n"
"{\n"
" oColor = color;\n"
"}";
ANGLE_GL_PROGRAM(program, vertexShaderSource, fragmentShaderSource);
GLuint index = glGetProgramResourceIndex(program, GL_PROGRAM_INPUT, "position");
EXPECT_GL_NO_ERROR();
EXPECT_NE(GL_INVALID_INDEX, index);
index = glGetProgramResourceIndex(program, GL_PROGRAM_INPUT, "missing");
EXPECT_GL_NO_ERROR();
EXPECT_EQ(GL_INVALID_INDEX, index);
index = glGetProgramResourceIndex(program, GL_PROGRAM_OUTPUT, "oColor");
EXPECT_GL_NO_ERROR();
EXPECT_NE(GL_INVALID_INDEX, index);
index = glGetProgramResourceIndex(program, GL_PROGRAM_OUTPUT, "missing");
EXPECT_GL_NO_ERROR();
EXPECT_EQ(GL_INVALID_INDEX, index);
index = glGetProgramResourceIndex(program, GL_ATOMIC_COUNTER_BUFFER, "missing");
EXPECT_GL_ERROR(GL_INVALID_ENUM);
}
ANGLE_INSTANTIATE_TEST(ProgramInterfaceTestES31, ES31_OPENGL(), ES31_D3D11(), ES31_OPENGLES());
} // 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