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: Jamie Madill <jmadill@chromium.org>
diff --git a/src/libANGLE/Context.cpp b/src/libANGLE/Context.cpp
index 53b6d32..a1f3214 100644
--- a/src/libANGLE/Context.cpp
+++ b/src/libANGLE/Context.cpp
@@ -2097,6 +2097,15 @@
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)
{
if (error.isError())
diff --git a/src/libANGLE/Context.h b/src/libANGLE/Context.h
index b6b5ba4..35c6e33 100644
--- a/src/libANGLE/Context.h
+++ b/src/libANGLE/Context.h
@@ -213,6 +213,11 @@
GLsizei *length,
GLint *params);
+ void getProgramInterfaceiv(GLuint program,
+ GLenum programInterface,
+ GLenum pname,
+ GLint *params);
+
Buffer *getBuffer(GLuint handle) const;
FenceNV *getFenceNV(GLuint handle);
Sync *getSync(GLsync handle) const;
diff --git a/src/libANGLE/queryutils.cpp b/src/libANGLE/queryutils.cpp
index 46bc656..9d8b2c8 100644
--- a/src/libANGLE/queryutils.cpp
+++ b/src/libANGLE/queryutils.cpp
@@ -445,19 +445,19 @@
switch (prop)
{
case GL_TYPE:
- return var.type;
+ return ConvertToGLint(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 ConvertToGLint(var.elementCount());
}
return 1;
case GL_NAME_LENGTH:
{
- GLint length = static_cast<GLint>(var.name.size());
+ size_t length = var.name.size();
if (var.isArray())
{
// Counts "[0]".
@@ -465,7 +465,7 @@
}
// ES31 spec p84: This counts the terminating null char.
++length;
- return length;
+ return ConvertToGLint(length);
}
case GL_LOCATION:
@@ -527,6 +527,105 @@
}
}
+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
void QueryFramebufferAttachmentParameteriv(const Framebuffer *framebuffer,
@@ -1261,6 +1360,30 @@
}
}
+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 egl
diff --git a/src/libANGLE/queryutils.h b/src/libANGLE/queryutils.h
index e47776c..1ae7343 100644
--- a/src/libANGLE/queryutils.h
+++ b/src/libANGLE/queryutils.h
@@ -136,6 +136,11 @@
GLsizei *length,
GLint *params);
+void QueryProgramInterfaceiv(const Program *program,
+ GLenum programInterface,
+ GLenum pname,
+ GLint *params);
+
} // namespace gl
namespace egl
diff --git a/src/libANGLE/validationES31.cpp b/src/libANGLE/validationES31.cpp
index 09719ce..cbf44e7 100644
--- a/src/libANGLE/validationES31.cpp
+++ b/src/libANGLE/validationES31.cpp
@@ -1153,7 +1153,7 @@
{
if (context->getClientVersion() < ES_3_1)
{
- context->handleError(InvalidOperation() << "Context does not support GLES3.1.");
+ ANGLE_VALIDATION_ERR(context, InvalidOperation(), ES31Required);
return false;
}
@@ -1198,4 +1198,67 @@
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
diff --git a/src/libANGLE/validationES31.h b/src/libANGLE/validationES31.h
index a48eac1..d3deb8b 100644
--- a/src/libANGLE/validationES31.h
+++ b/src/libANGLE/validationES31.h
@@ -80,6 +80,12 @@
GLsizei *length,
GLint *params);
+bool ValidateGetProgramInterfaceiv(Context *context,
+ GLuint program,
+ GLenum programInterface,
+ GLenum pname,
+ GLint *params);
+
bool ValidateBindVertexBuffer(ValidationContext *context,
GLuint bindingIndex,
GLuint buffer,