#include "main/mtypes.h"
#include "main/shaderapi.h"
#include "main/shaderobj.h"
+#include "main/context.h"
#include "program_resource.h"
-
+#include "compiler/glsl/ir_uniform.h"
static bool
-supported_interface_enum(GLenum iface)
+supported_interface_enum(struct gl_context *ctx, GLenum iface)
{
switch (iface) {
case GL_UNIFORM:
case GL_UNIFORM_BLOCK:
case GL_PROGRAM_INPUT:
case GL_PROGRAM_OUTPUT:
+ case GL_TRANSFORM_FEEDBACK_BUFFER:
case GL_TRANSFORM_FEEDBACK_VARYING:
case GL_ATOMIC_COUNTER_BUFFER:
+ case GL_BUFFER_VARIABLE:
+ case GL_SHADER_STORAGE_BLOCK:
return true;
case GL_VERTEX_SUBROUTINE:
- case GL_TESS_CONTROL_SUBROUTINE:
- case GL_TESS_EVALUATION_SUBROUTINE:
- case GL_GEOMETRY_SUBROUTINE:
case GL_FRAGMENT_SUBROUTINE:
- case GL_COMPUTE_SUBROUTINE:
case GL_VERTEX_SUBROUTINE_UNIFORM:
- case GL_TESS_CONTROL_SUBROUTINE_UNIFORM:
- case GL_TESS_EVALUATION_SUBROUTINE_UNIFORM:
- case GL_GEOMETRY_SUBROUTINE_UNIFORM:
case GL_FRAGMENT_SUBROUTINE_UNIFORM:
+ return _mesa_has_shader_subroutine(ctx);
+ case GL_GEOMETRY_SUBROUTINE:
+ case GL_GEOMETRY_SUBROUTINE_UNIFORM:
+ return _mesa_has_geometry_shaders(ctx) && _mesa_has_shader_subroutine(ctx);
+ case GL_COMPUTE_SUBROUTINE:
case GL_COMPUTE_SUBROUTINE_UNIFORM:
- case GL_BUFFER_VARIABLE:
- case GL_SHADER_STORAGE_BLOCK:
+ return _mesa_has_compute_shaders(ctx) && _mesa_has_shader_subroutine(ctx);
+ case GL_TESS_CONTROL_SUBROUTINE:
+ case GL_TESS_EVALUATION_SUBROUTINE:
+ case GL_TESS_CONTROL_SUBROUTINE_UNIFORM:
+ case GL_TESS_EVALUATION_SUBROUTINE_UNIFORM:
+ return _mesa_has_tessellation(ctx) && _mesa_has_shader_subroutine(ctx);
default:
return false;
}
GLenum pname, GLint *params)
{
GET_CURRENT_CONTEXT(ctx);
+
+ if (MESA_VERBOSE & VERBOSE_API) {
+ _mesa_debug(ctx, "glGetProgramInterfaceiv(%u, %s, %s, %p)\n",
+ program, _mesa_enum_to_string(programInterface),
+ _mesa_enum_to_string(pname), params);
+ }
+
unsigned i;
struct gl_shader_program *shProg =
_mesa_lookup_shader_program_err(ctx, program,
}
/* Validate interface. */
- if (!supported_interface_enum(programInterface)) {
+ if (!supported_interface_enum(ctx, programInterface)) {
_mesa_error(ctx, GL_INVALID_OPERATION, "glGetProgramInterfaceiv(%s)",
- _mesa_lookup_enum_by_nr(programInterface));
+ _mesa_enum_to_string(programInterface));
return;
}
(*params)++;
break;
case GL_MAX_NAME_LENGTH:
- if (programInterface == GL_ATOMIC_COUNTER_BUFFER) {
+ if (programInterface == GL_ATOMIC_COUNTER_BUFFER ||
+ programInterface == GL_TRANSFORM_FEEDBACK_BUFFER) {
_mesa_error(ctx, GL_INVALID_OPERATION,
"glGetProgramInterfaceiv(%s pname %s)",
- _mesa_lookup_enum_by_nr(programInterface),
- _mesa_lookup_enum_by_nr(pname));
+ _mesa_enum_to_string(programInterface),
+ _mesa_enum_to_string(pname));
return;
}
/* Name length consists of base name, 3 additional chars '[0]' if
for (i = 0, *params = 0; i < shProg->NumProgramResourceList; i++) {
if (shProg->ProgramResourceList[i].Type != programInterface)
continue;
- const char *name =
- _mesa_program_resource_name(&shProg->ProgramResourceList[i]);
- unsigned array_size =
- _mesa_program_resource_array_size(&shProg->ProgramResourceList[i]);
- *params = MAX2(*params, strlen(name) + (array_size ? 3 : 0) + 1);
+ unsigned len =
+ _mesa_program_resource_name_len(&shProg->ProgramResourceList[i]);
+ *params = MAX2(*params, len + 1);
}
break;
case GL_MAX_NUM_ACTIVE_VARIABLES:
}
}
break;
+ case GL_SHADER_STORAGE_BLOCK:
+ for (i = 0, *params = 0; i < shProg->NumProgramResourceList; i++) {
+ if (shProg->ProgramResourceList[i].Type == programInterface) {
+ struct gl_uniform_block *block =
+ (struct gl_uniform_block *)
+ shProg->ProgramResourceList[i].Data;
+ GLint block_params = 0;
+ for (unsigned j = 0; j < block->NumUniforms; j++) {
+ const char *iname = block->Uniforms[j].IndexName;
+ struct gl_program_resource *uni =
+ _mesa_program_resource_find_name(shProg, GL_BUFFER_VARIABLE,
+ iname, NULL);
+ if (!uni)
+ continue;
+ block_params++;
+ }
+ *params = MAX2(*params, block_params);
+ }
+ }
+ break;
case GL_ATOMIC_COUNTER_BUFFER:
for (i = 0, *params = 0; i < shProg->NumProgramResourceList; i++) {
if (shProg->ProgramResourceList[i].Type == programInterface) {
}
}
break;
+ case GL_TRANSFORM_FEEDBACK_BUFFER:
+ for (i = 0, *params = 0; i < shProg->NumProgramResourceList; i++) {
+ if (shProg->ProgramResourceList[i].Type == programInterface) {
+ struct gl_transform_feedback_buffer *buffer =
+ (struct gl_transform_feedback_buffer *)
+ shProg->ProgramResourceList[i].Data;
+ *params = MAX2(*params, buffer->NumVaryings);
+ }
+ }
+ break;
default:
_mesa_error(ctx, GL_INVALID_OPERATION,
"glGetProgramInterfaceiv(%s pname %s)",
- _mesa_lookup_enum_by_nr(programInterface),
- _mesa_lookup_enum_by_nr(pname));
+ _mesa_enum_to_string(programInterface),
+ _mesa_enum_to_string(pname));
};
break;
case GL_MAX_NUM_COMPATIBLE_SUBROUTINES:
+ switch (programInterface) {
+ case GL_VERTEX_SUBROUTINE_UNIFORM:
+ case GL_FRAGMENT_SUBROUTINE_UNIFORM:
+ case GL_GEOMETRY_SUBROUTINE_UNIFORM:
+ case GL_COMPUTE_SUBROUTINE_UNIFORM:
+ case GL_TESS_CONTROL_SUBROUTINE_UNIFORM:
+ case GL_TESS_EVALUATION_SUBROUTINE_UNIFORM: {
+ for (i = 0, *params = 0; i < shProg->NumProgramResourceList; i++) {
+ if (shProg->ProgramResourceList[i].Type == programInterface) {
+ struct gl_uniform_storage *uni =
+ (struct gl_uniform_storage *)
+ shProg->ProgramResourceList[i].Data;
+ *params = MAX2(*params, uni->num_compatible_subroutines);
+ }
+ }
+ break;
+ }
+
+ default:
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glGetProgramInterfaceiv(%s pname %s)",
+ _mesa_enum_to_string(programInterface),
+ _mesa_enum_to_string(pname));
+ }
+ break;
default:
_mesa_error(ctx, GL_INVALID_OPERATION,
"glGetProgramInterfaceiv(pname %s)",
- _mesa_lookup_enum_by_nr(pname));
+ _mesa_enum_to_string(pname));
}
}
return false;
}
-/**
- * Checks if given name index is legal for GetProgramResourceIndex,
- * check is written to be compatible with GL_ARB_array_of_arrays.
- */
-static bool
-valid_program_resource_index_name(const GLchar *name)
-{
- const char *array = strstr(name, "[");
- const char *close = strrchr(name, ']');
-
- /* Not array, no need for the check. */
- if (!array)
- return true;
-
- /* Last array index has to be zero. */
- if (!close || *--close != '0')
- return false;
-
- return true;
-}
-
GLuint GLAPIENTRY
_mesa_GetProgramResourceIndex(GLuint program, GLenum programInterface,
const GLchar *name)
{
GET_CURRENT_CONTEXT(ctx);
+
+ if (MESA_VERBOSE & VERBOSE_API) {
+ _mesa_debug(ctx, "glGetProgramResourceIndex(%u, %s, %s)\n",
+ program, _mesa_enum_to_string(programInterface), name);
+ }
+
+ unsigned array_index = 0;
struct gl_program_resource *res;
struct gl_shader_program *shProg =
_mesa_lookup_shader_program_err(ctx, program,
if (!shProg || !name)
return GL_INVALID_INDEX;
+ if (!supported_interface_enum(ctx, programInterface)) {
+ _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramResourceIndex(%s)",
+ _mesa_enum_to_string(programInterface));
+ return GL_INVALID_INDEX;
+ }
/*
* For the interface TRANSFORM_FEEDBACK_VARYING, the value INVALID_INDEX
* should be returned when querying the index assigned to the special names
return GL_INVALID_INDEX;
switch (programInterface) {
+ case GL_TESS_CONTROL_SUBROUTINE:
+ case GL_TESS_CONTROL_SUBROUTINE_UNIFORM:
+ case GL_TESS_EVALUATION_SUBROUTINE:
+ case GL_TESS_EVALUATION_SUBROUTINE_UNIFORM:
+ case GL_COMPUTE_SUBROUTINE:
+ case GL_COMPUTE_SUBROUTINE_UNIFORM:
+ case GL_GEOMETRY_SUBROUTINE:
+ case GL_GEOMETRY_SUBROUTINE_UNIFORM:
+ case GL_VERTEX_SUBROUTINE:
+ case GL_FRAGMENT_SUBROUTINE:
+ case GL_VERTEX_SUBROUTINE_UNIFORM:
+ case GL_FRAGMENT_SUBROUTINE_UNIFORM:
case GL_PROGRAM_INPUT:
case GL_PROGRAM_OUTPUT:
case GL_UNIFORM:
- case GL_UNIFORM_BLOCK:
+ case GL_BUFFER_VARIABLE:
case GL_TRANSFORM_FEEDBACK_VARYING:
- /* Validate name syntax for arrays. */
- if (!valid_program_resource_index_name(name))
- return GL_INVALID_INDEX;
-
- res = _mesa_program_resource_find_name(shProg, programInterface, name);
- if (!res)
+ case GL_UNIFORM_BLOCK:
+ case GL_SHADER_STORAGE_BLOCK:
+ res = _mesa_program_resource_find_name(shProg, programInterface, name,
+ &array_index);
+ if (!res || array_index > 0)
return GL_INVALID_INDEX;
return _mesa_program_resource_index(shProg, res);
case GL_ATOMIC_COUNTER_BUFFER:
+ case GL_TRANSFORM_FEEDBACK_BUFFER:
default:
_mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramResourceIndex(%s)",
- _mesa_lookup_enum_by_nr(programInterface));
+ _mesa_enum_to_string(programInterface));
}
return GL_INVALID_INDEX;
GLchar *name)
{
GET_CURRENT_CONTEXT(ctx);
+
+ if (MESA_VERBOSE & VERBOSE_API) {
+ _mesa_debug(ctx, "glGetProgramResourceName(%u, %s, %u, %d, %p, %p)\n",
+ program, _mesa_enum_to_string(programInterface), index,
+ bufSize, length, name);
+ }
+
struct gl_shader_program *shProg =
_mesa_lookup_shader_program_err(ctx, program,
"glGetProgramResourceName");
- /* Set user friendly return values in case of errors. */
- if (name)
- *name = '\0';
- if (length)
- *length = 0;
-
if (!shProg || !name)
return;
if (programInterface == GL_ATOMIC_COUNTER_BUFFER ||
- !supported_interface_enum(programInterface)) {
+ programInterface == GL_TRANSFORM_FEEDBACK_BUFFER ||
+ !supported_interface_enum(ctx, programInterface)) {
_mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramResourceName(%s)",
- _mesa_lookup_enum_by_nr(programInterface));
+ _mesa_enum_to_string(programInterface));
return;
}
const GLenum *props, GLsizei bufSize,
GLsizei *length, GLint *params)
{
+ GET_CURRENT_CONTEXT(ctx);
+
+ if (MESA_VERBOSE & VERBOSE_API) {
+ _mesa_debug(ctx, "glGetProgramResourceiv(%u, %s, %u, %d, %p, %d, %p, %p)\n",
+ program, _mesa_enum_to_string(programInterface), index,
+ propCount, props, bufSize, length, params);
+ }
+
+ struct gl_shader_program *shProg =
+ _mesa_lookup_shader_program_err(ctx, program, "glGetProgramResourceiv");
+
+ if (!shProg || !params)
+ return;
+
+ /* The error INVALID_VALUE is generated if <propCount> is zero.
+ * Note that we check < 0 here because it makes sense to bail early.
+ */
+ if (propCount <= 0) {
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "glGetProgramResourceiv(propCount <= 0)");
+ return;
+ }
+
+ _mesa_get_program_resourceiv(shProg, programInterface, index,
+ propCount, props, bufSize, length, params);
+}
+
+static struct gl_shader_program *
+lookup_linked_program(GLuint program, const char *caller)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ struct gl_shader_program *prog =
+ _mesa_lookup_shader_program_err(ctx, program, caller);
+
+ if (!prog)
+ return NULL;
+
+ if (prog->LinkStatus == GL_FALSE) {
+ _mesa_error(ctx, GL_INVALID_OPERATION, "%s(program not linked)",
+ caller);
+ return NULL;
+ }
+ return prog;
}
GLint GLAPIENTRY
_mesa_GetProgramResourceLocation(GLuint program, GLenum programInterface,
const GLchar *name)
{
+ GET_CURRENT_CONTEXT(ctx);
+
+ if (MESA_VERBOSE & VERBOSE_API) {
+ _mesa_debug(ctx, "glGetProgramResourceLocation(%u, %s, %s)\n",
+ program, _mesa_enum_to_string(programInterface), name);
+ }
+
+ struct gl_shader_program *shProg =
+ lookup_linked_program(program, "glGetProgramResourceLocation");
+
+ if (!shProg || !name)
+ return -1;
+
+ /* Validate programInterface. */
+ switch (programInterface) {
+ case GL_UNIFORM:
+ case GL_PROGRAM_INPUT:
+ case GL_PROGRAM_OUTPUT:
+ break;
+
+ case GL_VERTEX_SUBROUTINE_UNIFORM:
+ case GL_FRAGMENT_SUBROUTINE_UNIFORM:
+ if (!_mesa_has_shader_subroutine(ctx))
+ goto fail;
+ break;
+ case GL_GEOMETRY_SUBROUTINE_UNIFORM:
+ if (!_mesa_has_geometry_shaders(ctx) || !_mesa_has_shader_subroutine(ctx))
+ goto fail;
+ break;
+ case GL_COMPUTE_SUBROUTINE_UNIFORM:
+ if (!_mesa_has_compute_shaders(ctx) || !_mesa_has_shader_subroutine(ctx))
+ goto fail;
+ break;
+ case GL_TESS_CONTROL_SUBROUTINE_UNIFORM:
+ case GL_TESS_EVALUATION_SUBROUTINE_UNIFORM:
+ if (!_mesa_has_tessellation(ctx) || !_mesa_has_shader_subroutine(ctx))
+ goto fail;
+ break;
+ default:
+ goto fail;
+ }
+
+ return _mesa_program_resource_location(shProg, programInterface, name);
+fail:
+ _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramResourceLocation(%s %s)",
+ _mesa_enum_to_string(programInterface), name);
return -1;
}
+/**
+ * Returns output index for dual source blending.
+ */
GLint GLAPIENTRY
_mesa_GetProgramResourceLocationIndex(GLuint program, GLenum programInterface,
const GLchar *name)
{
- return -1;
+ GET_CURRENT_CONTEXT(ctx);
+
+ if (MESA_VERBOSE & VERBOSE_API) {
+ _mesa_debug(ctx, "glGetProgramResourceLocationIndex(%u, %s, %s)\n",
+ program, _mesa_enum_to_string(programInterface), name);
+ }
+
+ struct gl_shader_program *shProg =
+ lookup_linked_program(program, "glGetProgramResourceLocationIndex");
+
+ if (!shProg || !name)
+ return -1;
+
+ /* From the GL_ARB_program_interface_query spec:
+ *
+ * "For GetProgramResourceLocationIndex, <programInterface> must be
+ * PROGRAM_OUTPUT."
+ */
+ if (programInterface != GL_PROGRAM_OUTPUT) {
+ _mesa_error(ctx, GL_INVALID_ENUM,
+ "glGetProgramResourceLocationIndex(%s)",
+ _mesa_enum_to_string(programInterface));
+ return -1;
+ }
+
+ return _mesa_program_resource_location_index(shProg, GL_PROGRAM_OUTPUT,
+ name);
}