Commit d9cd7b7f by jchen10 Committed by Commit Bot

ES31: Add glGetProgramInterfaceiv API

Add API entry and validation checks(GLES 3.1 section 7.3). Add the first 4 interfaces(PROGRAM_INPUT, PROGRAM_OUTPUT, UNIFORM and UNIFORM_BLOCK) implementation. BUG=angleproject:1920 TEST=angle_end2end_tests:ProgramInterfaceTestES31.* Change-Id: Iab80ba332e2a5e2b3e677039359e60a420e3d6b0 Reviewed-on: https://chromium-review.googlesource.com/642729 Commit-Queue: Jamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org>
parent 2a1e8f95
...@@ -773,6 +773,20 @@ GLuint ConvertToGLuint(GLfloat param) ...@@ -773,6 +773,20 @@ GLuint ConvertToGLuint(GLfloat param)
} }
template <> template <>
GLint ConvertToGLint(uint32_t param)
{
uint32_t max = static_cast<uint32_t>(std::numeric_limits<GLint>::max());
return static_cast<GLint>(param >= max ? max : param);
}
template <>
GLint ConvertToGLint(uint64_t param)
{
uint64_t max = static_cast<uint64_t>(std::numeric_limits<GLint>::max());
return static_cast<GLint>(param >= max ? max : param);
}
template <>
GLint ConvertToGLint(GLfloat param) GLint ConvertToGLint(GLfloat param)
{ {
return iround<GLint>(param); return iround<GLint>(param);
......
...@@ -74,6 +74,11 @@ template <typename outT> outT iround(GLfloat value) { return static_cast<outT>(v ...@@ -74,6 +74,11 @@ template <typename outT> outT iround(GLfloat value) { return static_cast<outT>(v
template <typename outT> outT uiround(GLfloat value) { return static_cast<outT>(value + 0.5f); } template <typename outT> outT uiround(GLfloat value) { return static_cast<outT>(value + 0.5f); }
// Helper for converting arbitrary GL types to other GL types used in queries and state setting // Helper for converting arbitrary GL types to other GL types used in queries and state setting
// TODO(jie.a.chen@intel.com): Add the conversion rule for all helpers as the spec requires:
// "If a value is so large in magnitude that it cannot be represented with the requested type,"
// "then the nearest value representable using the requested type is returned."
template <typename ParamType> template <typename ParamType>
GLuint ConvertToGLuint(ParamType param) GLuint ConvertToGLuint(ParamType param)
{ {
...@@ -87,6 +92,13 @@ GLint ConvertToGLint(ParamType param) ...@@ -87,6 +92,13 @@ GLint ConvertToGLint(ParamType param)
{ {
return static_cast<GLint>(param); return static_cast<GLint>(param);
} }
template <>
GLint ConvertToGLint(uint32_t param);
template <>
GLint ConvertToGLint(uint64_t param);
template <> template <>
GLint ConvertToGLint(GLfloat param); GLint ConvertToGLint(GLfloat param);
......
...@@ -2097,6 +2097,15 @@ void Context::getProgramResourceiv(GLuint program, ...@@ -2097,6 +2097,15 @@ void Context::getProgramResourceiv(GLuint program,
length, params); length, params);
} }
void Context::getProgramInterfaceiv(GLuint program,
GLenum programInterface,
GLenum pname,
GLint *params)
{
const auto *programObject = getProgram(program);
QueryProgramInterfaceiv(programObject, programInterface, pname, params);
}
Error Context::handleError(const Error &error) Error Context::handleError(const Error &error)
{ {
if (error.isError()) if (error.isError())
......
...@@ -213,6 +213,11 @@ class Context final : public ValidationContext ...@@ -213,6 +213,11 @@ class Context final : public ValidationContext
GLsizei *length, GLsizei *length,
GLint *params); GLint *params);
void getProgramInterfaceiv(GLuint program,
GLenum programInterface,
GLenum pname,
GLint *params);
Buffer *getBuffer(GLuint handle) const; Buffer *getBuffer(GLuint handle) const;
FenceNV *getFenceNV(GLuint handle); FenceNV *getFenceNV(GLuint handle);
Sync *getSync(GLsync handle) const; Sync *getSync(GLsync handle) const;
......
...@@ -445,19 +445,19 @@ GLint GetLocationVariableProperty(const sh::VariableWithLocation &var, GLenum pr ...@@ -445,19 +445,19 @@ GLint GetLocationVariableProperty(const sh::VariableWithLocation &var, GLenum pr
switch (prop) switch (prop)
{ {
case GL_TYPE: case GL_TYPE:
return var.type; return ConvertToGLint(var.type);
case GL_ARRAY_SIZE: case GL_ARRAY_SIZE:
// TODO(jie.a.chen@intel.com): check array of array. // TODO(jie.a.chen@intel.com): check array of array.
if (var.isArray() && !var.isStruct()) if (var.isArray() && !var.isStruct())
{ {
return static_cast<GLint>(var.elementCount()); return ConvertToGLint(var.elementCount());
} }
return 1; return 1;
case GL_NAME_LENGTH: case GL_NAME_LENGTH:
{ {
GLint length = static_cast<GLint>(var.name.size()); size_t length = var.name.size();
if (var.isArray()) if (var.isArray())
{ {
// Counts "[0]". // Counts "[0]".
...@@ -465,7 +465,7 @@ GLint GetLocationVariableProperty(const sh::VariableWithLocation &var, GLenum pr ...@@ -465,7 +465,7 @@ GLint GetLocationVariableProperty(const sh::VariableWithLocation &var, GLenum pr
} }
// ES31 spec p84: This counts the terminating null char. // ES31 spec p84: This counts the terminating null char.
++length; ++length;
return length; return ConvertToGLint(length);
} }
case GL_LOCATION: case GL_LOCATION:
...@@ -527,6 +527,105 @@ GLint GetOutputResourceProperty(const Program *program, GLuint index, const GLen ...@@ -527,6 +527,105 @@ GLint GetOutputResourceProperty(const Program *program, GLuint index, const GLen
} }
} }
GLint QueryProgramInterfaceActiveResources(const Program *program, GLenum programInterface)
{
switch (programInterface)
{
case GL_PROGRAM_INPUT:
return ConvertToGLint(program->getAttributes().size());
case GL_PROGRAM_OUTPUT:
return ConvertToGLint(program->getState().getOutputVariables().size());
case GL_UNIFORM:
return ConvertToGLint(program->getState().getUniforms().size());
case GL_UNIFORM_BLOCK:
return ConvertToGLint(program->getState().getUniformBlocks().size());
// TODO(jie.a.chen@intel.com): more interfaces.
case GL_TRANSFORM_FEEDBACK_VARYING:
case GL_BUFFER_VARIABLE:
case GL_SHADER_STORAGE_BLOCK:
case GL_ATOMIC_COUNTER_BUFFER:
UNIMPLEMENTED();
return 0;
default:
UNREACHABLE();
return 0;
}
}
template <typename T, typename M>
GLint FindMaxSize(const std::vector<T> &resources, M member)
{
GLint max = 0;
for (const T &resource : resources)
{
max = std::max(max, ConvertToGLint((resource.*member).size()));
}
return max;
}
GLint QueryProgramInterfaceMaxNameLength(const Program *program, GLenum programInterface)
{
GLint maxNameLength = 0;
switch (programInterface)
{
case GL_PROGRAM_INPUT:
maxNameLength = FindMaxSize(program->getAttributes(), &sh::Attribute::name);
break;
case GL_PROGRAM_OUTPUT:
maxNameLength =
FindMaxSize(program->getState().getOutputVariables(), &sh::OutputVariable::name);
break;
case GL_UNIFORM:
maxNameLength = FindMaxSize(program->getState().getUniforms(), &LinkedUniform::name);
break;
case GL_UNIFORM_BLOCK:
maxNameLength =
FindMaxSize(program->getState().getUniformBlocks(), &UniformBlock::name);
break;
// TODO(jie.a.chen@intel.com): more interfaces.
case GL_TRANSFORM_FEEDBACK_VARYING:
case GL_BUFFER_VARIABLE:
case GL_SHADER_STORAGE_BLOCK:
UNIMPLEMENTED();
return 0;
default:
UNREACHABLE();
return 0;
}
// This length includes an extra character for the null terminator.
return (maxNameLength == 0 ? 0 : maxNameLength + 1);
}
GLint QueryProgramInterfaceMaxNumActiveVariables(const Program *program, GLenum programInterface)
{
switch (programInterface)
{
case GL_UNIFORM_BLOCK:
return FindMaxSize(program->getState().getUniformBlocks(),
&UniformBlock::memberIndexes);
// TODO(jie.a.chen@intel.com): more interfaces.
case GL_SHADER_STORAGE_BLOCK:
case GL_ATOMIC_COUNTER_BUFFER:
UNIMPLEMENTED();
return 0;
default:
UNREACHABLE();
return 0;
}
}
} // anonymous namespace } // anonymous namespace
void QueryFramebufferAttachmentParameteriv(const Framebuffer *framebuffer, void QueryFramebufferAttachmentParameteriv(const Framebuffer *framebuffer,
...@@ -1261,6 +1360,30 @@ void QueryProgramResourceiv(const Program *program, ...@@ -1261,6 +1360,30 @@ void QueryProgramResourceiv(const Program *program,
} }
} }
void QueryProgramInterfaceiv(const Program *program,
GLenum programInterface,
GLenum pname,
GLint *params)
{
switch (pname)
{
case GL_ACTIVE_RESOURCES:
*params = QueryProgramInterfaceActiveResources(program, programInterface);
break;
case GL_MAX_NAME_LENGTH:
*params = QueryProgramInterfaceMaxNameLength(program, programInterface);
break;
case GL_MAX_NUM_ACTIVE_VARIABLES:
*params = QueryProgramInterfaceMaxNumActiveVariables(program, programInterface);
break;
default:
UNREACHABLE();
}
}
} // namespace gl } // namespace gl
namespace egl namespace egl
......
...@@ -136,6 +136,11 @@ void QueryProgramResourceiv(const Program *program, ...@@ -136,6 +136,11 @@ void QueryProgramResourceiv(const Program *program,
GLsizei *length, GLsizei *length,
GLint *params); GLint *params);
void QueryProgramInterfaceiv(const Program *program,
GLenum programInterface,
GLenum pname,
GLint *params);
} // namespace gl } // namespace gl
namespace egl namespace egl
......
...@@ -1153,7 +1153,7 @@ bool ValidateGetProgramResourceiv(Context *context, ...@@ -1153,7 +1153,7 @@ bool ValidateGetProgramResourceiv(Context *context,
{ {
if (context->getClientVersion() < ES_3_1) if (context->getClientVersion() < ES_3_1)
{ {
context->handleError(InvalidOperation() << "Context does not support GLES3.1."); ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES31Required);
return false; return false;
} }
...@@ -1198,4 +1198,67 @@ bool ValidateGetProgramResourceiv(Context *context, ...@@ -1198,4 +1198,67 @@ bool ValidateGetProgramResourceiv(Context *context,
return true; return true;
} }
bool ValidateGetProgramInterfaceiv(Context *context,
GLuint program,
GLenum programInterface,
GLenum pname,
GLint *params)
{
if (context->getClientVersion() < ES_3_1)
{
ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES31Required);
return false;
}
Program *programObject = GetValidProgram(context, program);
if (programObject == nullptr)
{
return false;
}
if (!ValidateProgramInterface(programInterface))
{
context->handleError(InvalidEnum() << "Invalid program interface.");
return false;
}
switch (pname)
{
case GL_ACTIVE_RESOURCES:
case GL_MAX_NAME_LENGTH:
case GL_MAX_NUM_ACTIVE_VARIABLES:
break;
default:
context->handleError(InvalidEnum() << "Unknown property of program interface.");
return false;
}
if (pname == GL_MAX_NAME_LENGTH && programInterface == GL_ATOMIC_COUNTER_BUFFER)
{
context->handleError(InvalidOperation()
<< "Active atomic counter resources are not assigned name strings.");
return false;
}
if (pname == GL_MAX_NUM_ACTIVE_VARIABLES)
{
switch (programInterface)
{
case GL_ATOMIC_COUNTER_BUFFER:
case GL_SHADER_STORAGE_BLOCK:
case GL_UNIFORM_BLOCK:
break;
default:
context->handleError(
InvalidOperation()
<< "MAX_NUM_ACTIVE_VARIABLES requires a buffer or block interface.");
return false;
}
}
return true;
}
} // namespace gl } // namespace gl
...@@ -80,6 +80,12 @@ bool ValidateGetProgramResourceiv(Context *context, ...@@ -80,6 +80,12 @@ bool ValidateGetProgramResourceiv(Context *context,
GLsizei *length, GLsizei *length,
GLint *params); GLint *params);
bool ValidateGetProgramInterfaceiv(Context *context,
GLuint program,
GLenum programInterface,
GLenum pname,
GLint *params);
bool ValidateBindVertexBuffer(ValidationContext *context, bool ValidateBindVertexBuffer(ValidationContext *context,
GLuint bindingIndex, GLuint bindingIndex,
GLuint buffer, GLuint buffer,
......
...@@ -130,11 +130,12 @@ void GL_APIENTRY GetProgramInterfaceiv(GLuint program, ...@@ -130,11 +130,12 @@ void GL_APIENTRY GetProgramInterfaceiv(GLuint program,
Context *context = GetValidGlobalContext(); Context *context = GetValidGlobalContext();
if (context) if (context)
{ {
if (!context->skipValidation()) if (!context->skipValidation() &&
!ValidateGetProgramInterfaceiv(context, program, programInterface, pname, params))
{ {
context->handleError(InvalidOperation() << "Entry point not implemented"); return;
} }
UNIMPLEMENTED(); context->getProgramInterfaceiv(program, programInterface, pname, params);
} }
} }
......
...@@ -259,5 +259,80 @@ TEST_P(ProgramInterfaceTestES31, GetResource) ...@@ -259,5 +259,80 @@ TEST_P(ProgramInterfaceTestES31, GetResource)
EXPECT_GL_ERROR(GL_INVALID_OPERATION); EXPECT_GL_ERROR(GL_INVALID_OPERATION);
} }
// Tests glGetProgramInterfaceiv.
TEST_P(ProgramInterfaceTestES31, GetProgramInterface)
{
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"
"uniform ub {\n"
" vec4 mem0;\n"
" vec4 mem1;\n"
"} instance;\n"
"void main()\n"
"{\n"
" oColor = color;\n"
"}";
ANGLE_GL_PROGRAM(program, vertexShaderSource, fragmentShaderSource);
GLint num;
glGetProgramInterfaceiv(program, GL_PROGRAM_INPUT, GL_ACTIVE_RESOURCES, &num);
EXPECT_GL_NO_ERROR();
EXPECT_EQ(1, num);
glGetProgramInterfaceiv(program, GL_PROGRAM_INPUT, GL_MAX_NAME_LENGTH, &num);
EXPECT_GL_NO_ERROR();
EXPECT_EQ(9, num);
glGetProgramInterfaceiv(program, GL_PROGRAM_INPUT, GL_MAX_NUM_ACTIVE_VARIABLES, &num);
EXPECT_GL_ERROR(GL_INVALID_OPERATION);
glGetProgramInterfaceiv(program, GL_PROGRAM_OUTPUT, GL_ACTIVE_RESOURCES, &num);
EXPECT_GL_NO_ERROR();
EXPECT_EQ(1, num);
glGetProgramInterfaceiv(program, GL_PROGRAM_OUTPUT, GL_MAX_NAME_LENGTH, &num);
EXPECT_GL_NO_ERROR();
EXPECT_EQ(7, num);
glGetProgramInterfaceiv(program, GL_PROGRAM_OUTPUT, GL_MAX_NUM_ACTIVE_VARIABLES, &num);
EXPECT_GL_ERROR(GL_INVALID_OPERATION);
glGetProgramInterfaceiv(program, GL_UNIFORM_BLOCK, GL_ACTIVE_RESOURCES, &num);
EXPECT_GL_NO_ERROR();
EXPECT_EQ(1, num);
glGetProgramInterfaceiv(program, GL_UNIFORM_BLOCK, GL_MAX_NAME_LENGTH, &num);
EXPECT_GL_NO_ERROR();
EXPECT_EQ(3, num);
glGetProgramInterfaceiv(program, GL_UNIFORM_BLOCK, GL_MAX_NUM_ACTIVE_VARIABLES, &num);
EXPECT_GL_NO_ERROR();
EXPECT_EQ(2, num); // mem0, mem1
glGetProgramInterfaceiv(program, GL_UNIFORM, GL_ACTIVE_RESOURCES, &num);
EXPECT_GL_NO_ERROR();
EXPECT_EQ(3, num);
glGetProgramInterfaceiv(program, GL_UNIFORM, GL_MAX_NAME_LENGTH, &num);
EXPECT_GL_NO_ERROR();
EXPECT_EQ(8, num); // "ub.mem0"
glGetProgramInterfaceiv(program, GL_UNIFORM, GL_MAX_NUM_ACTIVE_VARIABLES, &num);
EXPECT_GL_ERROR(GL_INVALID_OPERATION);
}
ANGLE_INSTANTIATE_TEST(ProgramInterfaceTestES31, ES31_OPENGL(), ES31_D3D11(), ES31_OPENGLES()); ANGLE_INSTANTIATE_TEST(ProgramInterfaceTestES31, ES31_OPENGL(), ES31_D3D11(), ES31_OPENGLES());
} // 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