Commit 880683b1 by jchen10 Committed by Geoff Lang

ES31: Add glGetProgramResourceiv 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 TEST=angle_end2end_tests:ProgramInterfaceTestES31.* Change-Id: I50057f7b99f4dc7c23ca87fa9b797ca424f66e3d Reviewed-on: https://chromium-review.googlesource.com/475075Reviewed-by: 's avatarGeoff Lang <geofflang@chromium.org> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org>
parent ccb9fad3
......@@ -2180,6 +2180,20 @@ GLint Context::getProgramResourceLocation(GLuint program,
return QueryProgramResourceLocation(programObject, programInterface, name);
}
void Context::getProgramResourceiv(GLuint program,
GLenum programInterface,
GLuint index,
GLsizei propCount,
const GLenum *props,
GLsizei bufSize,
GLsizei *length,
GLint *params)
{
const auto *programObject = getProgram(program);
QueryProgramResourceiv(programObject, programInterface, index, propCount, props, bufSize,
length, params);
}
Error Context::handleError(const Error &error)
{
if (error.isError())
......
......@@ -218,6 +218,14 @@ class Context final : public ValidationContext
GLsizei *length,
GLchar *name);
GLint getProgramResourceLocation(GLuint program, GLenum programInterface, const GLchar *name);
void getProgramResourceiv(GLuint program,
GLenum programInterface,
GLuint index,
GLsizei propCount,
const GLenum *props,
GLsizei bufSize,
GLsizei *length,
GLint *params);
Buffer *getBuffer(GLuint handle) const;
FenceNV *getFenceNV(GLuint handle);
......
......@@ -1151,6 +1151,18 @@ void Program::getOutputResourceName(GLuint index,
}
}
const sh::Attribute &Program::getInputResource(GLuint index) const
{
ASSERT(index < mState.mAttributes.size());
return mState.mAttributes[index];
}
const sh::OutputVariable &Program::getOutputResource(GLuint index) const
{
ASSERT(index < mState.mOutputVariables.size());
return mState.mOutputVariables[index];
}
GLint Program::getFragDataLocation(const std::string &name) const
{
std::string baseName(name);
......
......@@ -516,6 +516,8 @@ class Program final : angle::NonCopyable, public LabeledObject
GLuint getOutputResourceIndex(const GLchar *name) const;
void getInputResourceName(GLuint index, GLsizei bufSize, GLsizei *length, GLchar *name) const;
void getOutputResourceName(GLuint index, GLsizei bufSize, GLsizei *length, GLchar *name) const;
const sh::Attribute &getInputResource(GLuint index) const;
const sh::OutputVariable &getOutputResource(GLuint index) const;
class Bindings final : angle::NonCopyable
{
......
......@@ -440,6 +440,93 @@ void QueryBufferParameterBase(const Buffer *buffer, GLenum pname, ParamType *par
}
}
GLint GetLocationVariableProperty(const sh::VariableWithLocation &var, GLenum prop)
{
switch (prop)
{
case GL_TYPE:
return var.type;
case GL_ARRAY_SIZE:
// TODO(jie.a.chen@intel.com): check array of array.
if (var.isArray() && !var.isStruct())
{
return static_cast<GLint>(var.elementCount());
}
return 1;
case GL_NAME_LENGTH:
{
GLint length = static_cast<GLint>(var.name.size());
if (var.isArray())
{
// Counts "[0]".
length += 3;
}
// ES31 spec p84: This counts the terminating null char.
++length;
return length;
}
case GL_LOCATION:
return var.location;
default:
UNREACHABLE();
return GL_INVALID_VALUE;
}
}
GLint GetInputResourceProperty(const Program *program, GLuint index, GLenum prop)
{
const auto &attribute = program->getInputResource(index);
switch (prop)
{
case GL_TYPE:
case GL_ARRAY_SIZE:
case GL_LOCATION:
case GL_NAME_LENGTH:
return GetLocationVariableProperty(attribute, prop);
case GL_REFERENCED_BY_VERTEX_SHADER:
return 1;
case GL_REFERENCED_BY_FRAGMENT_SHADER:
case GL_REFERENCED_BY_COMPUTE_SHADER:
return 0;
default:
UNREACHABLE();
return GL_INVALID_VALUE;
}
}
GLint GetOutputResourceProperty(const Program *program, GLuint index, const GLenum prop)
{
const auto &outputVariable = program->getOutputResource(index);
switch (prop)
{
case GL_TYPE:
case GL_ARRAY_SIZE:
case GL_LOCATION:
case GL_NAME_LENGTH:
return GetLocationVariableProperty(outputVariable, prop);
case GL_REFERENCED_BY_VERTEX_SHADER:
return 0;
case GL_REFERENCED_BY_FRAGMENT_SHADER:
return 1;
case GL_REFERENCED_BY_COMPUTE_SHADER:
return 0;
default:
UNREACHABLE();
return GL_INVALID_VALUE;
}
}
} // anonymous namespace
void QueryFramebufferAttachmentParameteriv(const Framebuffer *framebuffer,
......@@ -1124,6 +1211,60 @@ GLint QueryProgramResourceLocation(const Program *program,
}
}
void QueryProgramResourceiv(const Program *program,
GLenum programInterface,
GLuint index,
GLsizei propCount,
const GLenum *props,
GLsizei bufSize,
GLsizei *length,
GLint *params)
{
if (!program->isLinked())
{
if (length != nullptr)
{
*length = 0;
}
return;
}
GLsizei count = std::min(propCount, bufSize);
if (length != nullptr)
{
*length = count;
}
for (GLsizei i = 0; i < count; i++)
{
switch (programInterface)
{
case GL_PROGRAM_INPUT:
params[i] = GetInputResourceProperty(program, index, props[i]);
break;
case GL_PROGRAM_OUTPUT:
params[i] = GetOutputResourceProperty(program, index, props[i]);
break;
// TODO(jie.a.chen@intel.com): more interfaces.
case GL_UNIFORM:
case GL_UNIFORM_BLOCK:
case GL_TRANSFORM_FEEDBACK_VARYING:
case GL_BUFFER_VARIABLE:
case GL_SHADER_STORAGE_BLOCK:
case GL_ATOMIC_COUNTER_BUFFER:
UNIMPLEMENTED();
params[i] = GL_INVALID_VALUE;
break;
default:
UNREACHABLE();
params[i] = GL_INVALID_VALUE;
}
}
}
} // namespace gl
namespace egl
......
......@@ -131,6 +131,14 @@ void QueryProgramResourceName(const Program *program,
GLint QueryProgramResourceLocation(const Program *program,
GLenum programInterface,
const GLchar *name);
void QueryProgramResourceiv(const Program *program,
GLenum programInterface,
GLuint index,
GLsizei propCount,
const GLenum *props,
GLsizei bufSize,
GLsizei *length,
GLint *params);
} // namespace gl
......
......@@ -54,6 +54,195 @@ bool ValidateLocationProgramInterface(GLenum programInterface)
}
}
bool ValidateProgramInterface(GLenum programInterface)
{
return (programInterface == GL_ATOMIC_COUNTER_BUFFER ||
ValidateNamedProgramInterface(programInterface));
}
bool ValidateProgramResourceProperty(GLenum prop)
{
switch (prop)
{
case GL_ACTIVE_VARIABLES:
case GL_BUFFER_BINDING:
case GL_NUM_ACTIVE_VARIABLES:
case GL_ARRAY_SIZE:
case GL_ARRAY_STRIDE:
case GL_BLOCK_INDEX:
case GL_IS_ROW_MAJOR:
case GL_MATRIX_STRIDE:
case GL_ATOMIC_COUNTER_BUFFER_INDEX:
case GL_BUFFER_DATA_SIZE:
case GL_LOCATION:
case GL_NAME_LENGTH:
case GL_OFFSET:
case GL_REFERENCED_BY_VERTEX_SHADER:
case GL_REFERENCED_BY_FRAGMENT_SHADER:
case GL_REFERENCED_BY_COMPUTE_SHADER:
case GL_TOP_LEVEL_ARRAY_SIZE:
case GL_TOP_LEVEL_ARRAY_STRIDE:
case GL_TYPE:
return true;
default:
return false;
}
}
// GLES 3.10 spec: Page 82 -- Table 7.2
bool ValidateProgramResourcePropertyByInterface(GLenum prop, GLenum programInterface)
{
switch (prop)
{
case GL_ACTIVE_VARIABLES:
case GL_BUFFER_BINDING:
case GL_NUM_ACTIVE_VARIABLES:
{
switch (programInterface)
{
case GL_ATOMIC_COUNTER_BUFFER:
case GL_SHADER_STORAGE_BLOCK:
case GL_UNIFORM_BLOCK:
return true;
default:
return false;
}
}
case GL_ARRAY_SIZE:
{
switch (programInterface)
{
case GL_BUFFER_VARIABLE:
case GL_PROGRAM_INPUT:
case GL_PROGRAM_OUTPUT:
case GL_TRANSFORM_FEEDBACK_VARYING:
case GL_UNIFORM:
return true;
default:
return false;
}
}
case GL_ARRAY_STRIDE:
case GL_BLOCK_INDEX:
case GL_IS_ROW_MAJOR:
case GL_MATRIX_STRIDE:
{
switch (programInterface)
{
case GL_BUFFER_VARIABLE:
case GL_UNIFORM:
return true;
default:
return false;
}
}
case GL_ATOMIC_COUNTER_BUFFER_INDEX:
{
if (programInterface == GL_UNIFORM)
{
return true;
}
return false;
}
case GL_BUFFER_DATA_SIZE:
{
switch (programInterface)
{
case GL_ATOMIC_COUNTER_BUFFER:
case GL_SHADER_STORAGE_BLOCK:
case GL_UNIFORM_BLOCK:
return true;
default:
return false;
}
}
case GL_LOCATION:
{
return ValidateLocationProgramInterface(programInterface);
}
case GL_NAME_LENGTH:
{
return ValidateNamedProgramInterface(programInterface);
}
case GL_OFFSET:
{
switch (programInterface)
{
case GL_BUFFER_VARIABLE:
case GL_UNIFORM:
return true;
default:
return false;
}
}
case GL_REFERENCED_BY_VERTEX_SHADER:
case GL_REFERENCED_BY_FRAGMENT_SHADER:
case GL_REFERENCED_BY_COMPUTE_SHADER:
{
switch (programInterface)
{
case GL_ATOMIC_COUNTER_BUFFER:
case GL_BUFFER_VARIABLE:
case GL_PROGRAM_INPUT:
case GL_PROGRAM_OUTPUT:
case GL_SHADER_STORAGE_BLOCK:
case GL_UNIFORM:
case GL_UNIFORM_BLOCK:
return true;
default:
return false;
}
}
case GL_TOP_LEVEL_ARRAY_SIZE:
case GL_TOP_LEVEL_ARRAY_STRIDE:
{
if (programInterface == GL_BUFFER_VARIABLE)
{
return true;
}
return false;
}
case GL_TYPE:
{
switch (programInterface)
{
case GL_BUFFER_VARIABLE:
case GL_PROGRAM_INPUT:
case GL_PROGRAM_OUTPUT:
case GL_TRANSFORM_FEEDBACK_VARYING:
case GL_UNIFORM:
return true;
default:
return false;
}
}
default:
return false;
}
}
bool ValidateProgramResourceIndex(const Program *programObject,
GLenum programInterface,
GLuint index)
......@@ -66,12 +255,13 @@ bool ValidateProgramResourceIndex(const Program *programObject,
case GL_PROGRAM_OUTPUT:
return (index < static_cast<GLuint>(programObject->getOutputResourceCount()));
// TODO(Jie): more interfaces.
// TODO(jie.a.chen@intel.com): more interfaces.
case GL_UNIFORM:
case GL_UNIFORM_BLOCK:
case GL_TRANSFORM_FEEDBACK_VARYING:
case GL_BUFFER_VARIABLE:
case GL_SHADER_STORAGE_BLOCK:
case GL_ATOMIC_COUNTER_BUFFER:
UNIMPLEMENTED();
return false;
......@@ -953,4 +1143,61 @@ bool ValidateGetProgramResourceLocation(Context *context,
return true;
}
bool ValidateGetProgramResourceiv(Context *context,
GLuint program,
GLenum programInterface,
GLuint index,
GLsizei propCount,
const GLenum *props,
GLsizei bufSize,
GLsizei *length,
GLint *params)
{
if (context->getClientVersion() < ES_3_1)
{
context->handleError(InvalidOperation() << "Context does not support GLES3.1.");
return false;
}
Program *programObject = GetValidProgram(context, program);
if (programObject == nullptr)
{
return false;
}
if (!ValidateProgramInterface(programInterface))
{
context->handleError(InvalidEnum() << "Invalid program interface.");
return false;
}
if (propCount <= 0)
{
context->handleError(InvalidValue() << "Invalid propCount.");
return false;
}
if (bufSize < 0)
{
context->handleError(InvalidValue() << "Invalid bufSize.");
return false;
}
if (!ValidateProgramResourceIndex(programObject, programInterface, index))
{
context->handleError(InvalidValue() << "Invalid index: " << index);
return false;
}
for (GLsizei i = 0; i < propCount; i++)
{
if (!ValidateProgramResourceProperty(props[i]))
{
context->handleError(InvalidEnum() << "Invalid prop.");
return false;
}
if (!ValidateProgramResourcePropertyByInterface(props[i], programInterface))
{
context->handleError(InvalidOperation() << "Not an allowed prop for interface");
return false;
}
}
return true;
}
} // namespace gl
......@@ -70,6 +70,16 @@ bool ValidateGetProgramResourceLocation(Context *context,
GLenum programInterface,
const GLchar *name);
bool ValidateGetProgramResourceiv(Context *context,
GLuint program,
GLenum programInterface,
GLuint index,
GLsizei propCount,
const GLenum *props,
GLsizei bufSize,
GLsizei *length,
GLint *params);
bool ValidateBindVertexBuffer(ValidationContext *context,
GLuint bindingIndex,
GLuint buffer,
......
......@@ -198,11 +198,14 @@ void GL_APIENTRY GetProgramResourceiv(GLuint program,
Context *context = GetValidGlobalContext();
if (context)
{
if (!context->skipValidation())
if (!context->skipValidation() &&
!ValidateGetProgramResourceiv(context, program, programInterface, index, propCount,
props, bufSize, length, params))
{
context->handleError(InvalidOperation() << "Entry point not implemented");
return;
}
UNIMPLEMENTED();
context->getProgramResourceiv(program, programInterface, index, propCount, props, bufSize,
length, params);
}
}
......
......@@ -193,5 +193,71 @@ TEST_P(ProgramInterfaceTestES31, GetResourceLocation)
EXPECT_EQ(5, location);
}
// Tests glGetProgramResource.
TEST_P(ProgramInterfaceTestES31, GetResource)
{
const std::string &vertexShaderSource =
"#version 310 es\n"
"precision highp float;\n"
"layout(location = 3) 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"
"layout(location = 2) out vec4 oColor[4];\n"
"void main()\n"
"{\n"
" oColor[0] = 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);
constexpr int kPropCount = 7;
std::array<GLint, kPropCount> params;
GLsizei length;
std::array<GLenum, kPropCount> props = {
{GL_TYPE, GL_ARRAY_SIZE, GL_LOCATION, GL_NAME_LENGTH, GL_REFERENCED_BY_VERTEX_SHADER,
GL_REFERENCED_BY_FRAGMENT_SHADER, GL_REFERENCED_BY_COMPUTE_SHADER}};
glGetProgramResourceiv(program, GL_PROGRAM_INPUT, index, kPropCount, props.data(), kPropCount,
&length, params.data());
EXPECT_GL_NO_ERROR();
EXPECT_EQ(kPropCount, length);
EXPECT_EQ(GL_FLOAT_VEC4, params[0]);
EXPECT_EQ(1, params[1]);
EXPECT_EQ(3, params[2]);
EXPECT_EQ(9, params[3]);
EXPECT_EQ(1, params[4]);
EXPECT_EQ(0, params[5]);
EXPECT_EQ(0, params[6]);
index = glGetProgramResourceIndex(program, GL_PROGRAM_OUTPUT, "oColor[0]");
EXPECT_GL_NO_ERROR();
EXPECT_NE(index, GL_INVALID_INDEX);
glGetProgramResourceiv(program, GL_PROGRAM_OUTPUT, index, kPropCount, props.data(),
kPropCount - 1, &length, params.data());
EXPECT_GL_NO_ERROR();
EXPECT_EQ(kPropCount - 1, length);
EXPECT_EQ(GL_FLOAT_VEC4, params[0]);
EXPECT_EQ(4, params[1]);
EXPECT_EQ(2, params[2]);
EXPECT_EQ(10, params[3]);
EXPECT_EQ(0, params[4]);
EXPECT_EQ(1, params[5]);
GLenum invalidOutputProp = GL_OFFSET;
glGetProgramResourceiv(program, GL_PROGRAM_OUTPUT, index, 1, &invalidOutputProp, 1, &length,
params.data());
EXPECT_GL_ERROR(GL_INVALID_OPERATION);
}
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