#include "util/ralloc.h"
#include "util/hash_table.h"
#include "util/mesa-sha1.h"
-
-#ifdef _MSC_VER
-#include <stdlib.h>
-#define PATH_MAX _MAX_PATH
-#endif
+#include "util/crc32.h"
/**
* Return mask of GLSL_x flags by examining the MESA_GLSL env var.
if (!read_env_var) {
path = getenv("MESA_SHADER_CAPTURE_PATH");
read_env_var = true;
- if (path &&
- strlen(path) > PATH_MAX - strlen("/fp-4294967295.shader_test")) {
- GET_CURRENT_CONTEXT(ctx);
- _mesa_warning(ctx, "MESA_SHADER_CAPTURE_PATH too long; ignoring "
- "request to capture shaders");
- path = NULL;
- }
}
return path;
_mesa_reference_shader_program(ctx, &ctx->Shader.CurrentProgram[i],
NULL);
}
- _mesa_reference_shader_program(ctx, &ctx->Shader._CurrentFragmentProgram,
- NULL);
+ _mesa_reference_program(ctx, &ctx->Shader._CurrentFragmentProgram, NULL);
_mesa_reference_shader_program(ctx, &ctx->Shader.ActiveProgram, NULL);
/* Extended for ARB_separate_shader_objects */
_mesa_HashLockMutex(ctx->Shared->ShaderObjects);
name = _mesa_HashFindFreeKeyBlock(ctx->Shared->ShaderObjects, 1);
- sh = ctx->Driver.NewShader(ctx, name,
- _mesa_shader_enum_to_shader_stage(type));
+ sh = _mesa_new_shader(name, _mesa_shader_enum_to_shader_stage(type));
sh->Type = type;
_mesa_HashInsertLocked(ctx->Shared->ShaderObjects, name, sh);
_mesa_HashUnlockMutex(ctx->Shared->ShaderObjects);
static bool
check_gs_query(struct gl_context *ctx, const struct gl_shader_program *shProg)
{
- if (shProg->LinkStatus &&
+ if (shProg->data->LinkStatus &&
shProg->_LinkedShaders[MESA_SHADER_GEOMETRY] != NULL) {
return true;
}
static bool
check_tcs_query(struct gl_context *ctx, const struct gl_shader_program *shProg)
{
- if (shProg->LinkStatus &&
+ if (shProg->data->LinkStatus &&
shProg->_LinkedShaders[MESA_SHADER_TESS_CTRL] != NULL) {
return true;
}
static bool
check_tes_query(struct gl_context *ctx, const struct gl_shader_program *shProg)
{
- if (shProg->LinkStatus &&
+ if (shProg->data->LinkStatus &&
shProg->_LinkedShaders[MESA_SHADER_TESS_EVAL] != NULL) {
return true;
}
*params = shProg->DeletePending;
return;
case GL_LINK_STATUS:
- *params = shProg->LinkStatus;
+ *params = shProg->data->LinkStatus;
return;
case GL_VALIDATE_STATUS:
- *params = shProg->Validated;
+ *params = shProg->data->Validated;
return;
case GL_INFO_LOG_LENGTH:
- *params = shProg->InfoLog ? strlen(shProg->InfoLog) + 1 : 0;
+ *params = (shProg->data->InfoLog && shProg->data->InfoLog[0] != '\0') ?
+ strlen(shProg->data->InfoLog) + 1 : 0;
return;
case GL_ATTACHED_SHADERS:
*params = shProg->NumShaders;
case GL_ACTIVE_UNIFORMS: {
unsigned i;
const unsigned num_uniforms =
- shProg->NumUniformStorage - shProg->NumHiddenUniforms;
+ shProg->data->NumUniformStorage - shProg->data->NumHiddenUniforms;
for (*params = 0, i = 0; i < num_uniforms; i++) {
- if (!shProg->UniformStorage[i].is_shader_storage)
+ if (!shProg->data->UniformStorage[i].is_shader_storage)
(*params)++;
}
return;
unsigned i;
GLint max_len = 0;
const unsigned num_uniforms =
- shProg->NumUniformStorage - shProg->NumHiddenUniforms;
+ shProg->data->NumUniformStorage - shProg->data->NumHiddenUniforms;
for (i = 0; i < num_uniforms; i++) {
- if (shProg->UniformStorage[i].is_shader_storage)
+ if (shProg->data->UniformStorage[i].is_shader_storage)
continue;
/* Add one for the terminating NUL character for a non-array, and
* 4 for the "[0]" and the NUL for an array.
*/
- const GLint len = strlen(shProg->UniformStorage[i].name) + 1 +
- ((shProg->UniformStorage[i].array_elements != 0) ? 3 : 0);
+ const GLint len = strlen(shProg->data->UniformStorage[i].name) + 1 +
+ ((shProg->data->UniformStorage[i].array_elements != 0) ? 3 : 0);
if (len > max_len)
max_len = len;
case GL_GEOMETRY_VERTICES_OUT:
if (!has_core_gs)
break;
- if (check_gs_query(ctx, shProg))
- *params = shProg->Geom.VerticesOut;
+ if (check_gs_query(ctx, shProg)) {
+ *params = shProg->_LinkedShaders[MESA_SHADER_GEOMETRY]->
+ info.Geom.VerticesOut;
+ }
return;
case GL_GEOMETRY_SHADER_INVOCATIONS:
if (!has_core_gs || !ctx->Extensions.ARB_gpu_shader5)
break;
- if (check_gs_query(ctx, shProg))
- *params = shProg->Geom.Invocations;
+ if (check_gs_query(ctx, shProg)) {
+ *params = shProg->_LinkedShaders[MESA_SHADER_GEOMETRY]->
+ info.Geom.Invocations;
+ }
return;
case GL_GEOMETRY_INPUT_TYPE:
if (!has_core_gs)
break;
- if (check_gs_query(ctx, shProg))
- *params = shProg->Geom.InputType;
+ if (check_gs_query(ctx, shProg)) {
+ *params = shProg->_LinkedShaders[MESA_SHADER_GEOMETRY]->
+ info.Geom.InputType;
+ }
return;
case GL_GEOMETRY_OUTPUT_TYPE:
if (!has_core_gs)
break;
- if (check_gs_query(ctx, shProg))
- *params = shProg->Geom.OutputType;
+ if (check_gs_query(ctx, shProg)) {
+ *params = shProg->_LinkedShaders[MESA_SHADER_GEOMETRY]->
+ info.Geom.OutputType;
+ }
return;
case GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH: {
unsigned i;
if (!has_ubo)
break;
- for (i = 0; i < shProg->NumUniformBlocks; i++) {
+ for (i = 0; i < shProg->data->NumUniformBlocks; i++) {
/* Add one for the terminating NUL character.
*/
- const GLint len = strlen(shProg->UniformBlocks[i].Name) + 1;
+ const GLint len = strlen(shProg->data->UniformBlocks[i].Name) + 1;
if (len > max_len)
max_len = len;
if (!has_ubo)
break;
- *params = shProg->NumUniformBlocks;
+ *params = shProg->data->NumUniformBlocks;
return;
case GL_PROGRAM_BINARY_RETRIEVABLE_HINT:
/* This enum isn't part of the OES extension for OpenGL ES 2.0. It is
if (!ctx->Extensions.ARB_shader_atomic_counters)
break;
- *params = shProg->NumAtomicBuffers;
+ *params = shProg->data->NumAtomicBuffers;
return;
case GL_COMPUTE_WORK_GROUP_SIZE: {
int i;
if (!_mesa_has_compute_shaders(ctx))
break;
- if (!shProg->LinkStatus) {
+ if (!shProg->data->LinkStatus) {
_mesa_error(ctx, GL_INVALID_OPERATION, "glGetProgramiv(program not "
"linked)");
return;
}
case GL_PROGRAM_SEPARABLE:
/* If the program has not been linked, return initial value 0. */
- *params = (shProg->LinkStatus == GL_FALSE) ? 0 : shProg->SeparateShader;
+ *params = (shProg->data->LinkStatus == GL_FALSE) ? 0 : shProg->SeparateShader;
return;
/* ARB_tessellation_shader */
case GL_TESS_CONTROL_OUTPUT_VERTICES:
if (!has_tess)
break;
- if (check_tcs_query(ctx, shProg))
- *params = shProg->TessCtrl.VerticesOut;
+ if (check_tcs_query(ctx, shProg)) {
+ *params = shProg->_LinkedShaders[MESA_SHADER_TESS_CTRL]->
+ info.TessCtrl.VerticesOut;
+ }
return;
case GL_TESS_GEN_MODE:
if (!has_tess)
break;
if (check_tes_query(ctx, shProg)) {
*params = shProg->_LinkedShaders[MESA_SHADER_TESS_EVAL]->
- TessEval.PrimitiveMode;
+ info.TessEval.PrimitiveMode;
}
return;
case GL_TESS_GEN_SPACING:
break;
if (check_tes_query(ctx, shProg)) {
*params = shProg->_LinkedShaders[MESA_SHADER_TESS_EVAL]->
- TessEval.Spacing;
+ info.TessEval.Spacing;
}
return;
case GL_TESS_GEN_VERTEX_ORDER:
break;
if (check_tes_query(ctx, shProg)) {
*params = shProg->_LinkedShaders[MESA_SHADER_TESS_EVAL]->
- TessEval.VertexOrder;
+ info.TessEval.VertexOrder;
}
return;
case GL_TESS_GEN_POINT_MODE:
break;
if (check_tes_query(ctx, shProg)) {
*params = shProg->_LinkedShaders[MESA_SHADER_TESS_EVAL]->
- TessEval.PointMode;
+ info.TessEval.PointMode;
}
return;
default:
*params = shader->CompileStatus;
break;
case GL_INFO_LOG_LENGTH:
- *params = shader->InfoLog ? strlen(shader->InfoLog) + 1 : 0;
+ *params = (shader->InfoLog && shader->InfoLog[0] != '\0') ?
+ strlen(shader->InfoLog) + 1 : 0;
break;
case GL_SHADER_SOURCE_LENGTH:
*params = shader->Source ? strlen((char *) shader->Source) + 1 : 0;
return;
}
- _mesa_copy_string(infoLog, bufSize, length, shProg->InfoLog);
+ _mesa_copy_string(infoLog, bufSize, length, shProg->data->InfoLog);
}
free((void *)sh->Source);
sh->Source = source;
#ifdef DEBUG
- sh->SourceChecksum = _mesa_str_checksum(sh->Source);
+ sh->SourceChecksum = util_hash_crc32(sh->Source, strlen(sh->Source));
#endif
}
if (ctx->_Shader->Flags & GLSL_DUMP) {
if (sh->CompileStatus) {
- _mesa_log("GLSL IR for shader %d:\n", sh->Name);
- _mesa_print_ir(_mesa_get_log_file(), sh->ir, NULL);
+ if (sh->ir) {
+ _mesa_log("GLSL IR for shader %d:\n", sh->Name);
+ _mesa_print_ir(_mesa_get_log_file(), sh->ir, NULL);
+ } else {
+ _mesa_log("No GLSL IR for shader %d (shader may be from "
+ "cache)\n", sh->Name);
+ }
_mesa_log("\n\n");
} else {
_mesa_log("GLSL shader %d failed to compile.\n", sh->Name);
/* Capture .shader_test files. */
const char *capture_path = _mesa_get_shader_capture_path();
- if (shProg->Name != 0 && capture_path != NULL) {
+ if (shProg->Name != 0 && shProg->Name != ~0 && capture_path != NULL) {
FILE *file;
- char filename[PATH_MAX];
-
- _mesa_snprintf(filename, sizeof(filename), "%s/%u.shader_test",
- capture_path, shProg->Name);
-
+ char *filename = ralloc_asprintf(NULL, "%s/%u.shader_test",
+ capture_path, shProg->Name);
file = fopen(filename, "w");
if (file) {
fprintf(file, "[require]\nGLSL%s >= %u.%02u\n",
shProg->IsES ? " ES" : "",
- shProg->Version / 100, shProg->Version % 100);
+ shProg->data->Version / 100, shProg->data->Version % 100);
if (shProg->SeparateShader)
fprintf(file, "GL_ARB_separate_shader_objects\nSSO ENABLED\n");
fprintf(file, "\n");
} else {
_mesa_warning(ctx, "Failed to open %s", filename);
}
+
+ ralloc_free(filename);
}
- if (shProg->LinkStatus == GL_FALSE &&
+ if (shProg->data->LinkStatus == GL_FALSE &&
(ctx->_Shader->Flags & GLSL_REPORT_ERRORS)) {
_mesa_debug(ctx, "Error linking program %u:\n%s\n",
- shProg->Name, shProg->InfoLog);
+ shProg->Name, shProg->data->InfoLog);
}
/* debug code */
printf("Link %u shaders in program %u: %s\n",
shProg->NumShaders, shProg->Name,
- shProg->LinkStatus ? "Success" : "Failed");
+ shProg->data->LinkStatus ? "Success" : "Failed");
for (i = 0; i < shProg->NumShaders; i++) {
printf(" shader %u, stage %u\n",
printf("Mesa: glUseProgram(%u)\n", shProg->Name);
for (i = 0; i < shProg->NumShaders; i++) {
+#ifdef DEBUG
printf(" %s shader %u, checksum %u\n",
_mesa_shader_stage_to_string(shProg->Shaders[i]->Stage),
shProg->Shaders[i]->Name,
shProg->Shaders[i]->SourceChecksum);
+#else
+ printf(" %s shader %u\n",
+ _mesa_shader_stage_to_string(shProg->Shaders[i]->Stage),
+ shProg->Shaders[i]->Name);
+#endif
}
if (shProg->_LinkedShaders[MESA_SHADER_VERTEX])
printf(" vert prog %u\n",
_mesa_active_program(struct gl_context *ctx, struct gl_shader_program *shProg,
const char *caller)
{
- if ((shProg != NULL) && !shProg->LinkStatus) {
+ if ((shProg != NULL) && !shProg->data->LinkStatus) {
_mesa_error(ctx, GL_INVALID_OPERATION,
"%s(program %u not linked)", caller, shProg->Name);
return;
shProg = NULL;
if (shProg)
- _mesa_shader_program_init_subroutine_defaults(shProg);
+ _mesa_shader_program_init_subroutine_defaults(ctx, shProg);
if (*target != shProg) {
/* Program is current, flush it */
/* Empty for now. */
break;
case MESA_SHADER_FRAGMENT:
- if (*target == ctx->_Shader->_CurrentFragmentProgram) {
- _mesa_reference_shader_program(ctx,
- &ctx->_Shader->_CurrentFragmentProgram,
- NULL);
+ if (*target != NULL &&
+ ((*target)->_LinkedShaders[MESA_SHADER_FRAGMENT] &&
+ (*target)->_LinkedShaders[MESA_SHADER_FRAGMENT]->Program ==
+ ctx->_Shader->_CurrentFragmentProgram)) {
+ _mesa_reference_program(ctx,
+ &ctx->_Shader->_CurrentFragmentProgram,
+ NULL);
}
break;
}
for (i = 0; i < MESA_SHADER_STAGES; i++)
use_shader_program(ctx, i, shProg, &ctx->Shader);
_mesa_active_program(ctx, shProg, "glUseProgram");
-
- if (ctx->Driver.UseProgram)
- ctx->Driver.UseProgram(ctx, shProg);
}
validate_shader_program(const struct gl_shader_program *shProg,
char *errMsg)
{
- if (!shProg->LinkStatus) {
+ if (!shProg->data->LinkStatus) {
return GL_FALSE;
}
return;
}
- shProg->Validated = validate_shader_program(shProg, errMsg);
- if (!shProg->Validated) {
+ shProg->data->Validated = validate_shader_program(shProg, errMsg);
+ if (!shProg->data->Validated) {
/* update info log */
- if (shProg->InfoLog) {
- ralloc_free(shProg->InfoLog);
+ if (shProg->data->InfoLog) {
+ ralloc_free(shProg->data->InfoLog);
}
- shProg->InfoLog = ralloc_strdup(shProg, errMsg);
+ shProg->data->InfoLog = ralloc_strdup(shProg->data, errMsg);
}
}
*
* <path>/<stage prefix>_<CHECKSUM>.glsl
*/
-static void
+static char *
construct_name(const gl_shader_stage stage, const char *source,
- const char *path, char *name, unsigned length)
+ const char *path)
{
char sha[64];
static const char *types[] = {
};
generate_sha1(source, sha);
- _mesa_snprintf(name, length, "%s/%s_%s.glsl", path, types[stage],
- sha);
+ return ralloc_asprintf(NULL, "%s/%s_%s.glsl", path, types[stage], sha);
}
/**
static void
dump_shader(const gl_shader_stage stage, const char *source)
{
- char name[PATH_MAX];
static bool path_exists = true;
char *dump_path;
FILE *f;
return;
}
- construct_name(stage, source, dump_path, name, PATH_MAX);
+ char *name = construct_name(stage, source, dump_path);
f = fopen(name, "w");
if (f) {
_mesa_warning(ctx, "could not open %s for dumping shader (%s)", name,
strerror(errno));
}
+ ralloc_free(name);
}
/**
static GLcharARB *
read_shader(const gl_shader_stage stage, const char *source)
{
- char name[PATH_MAX];
char *read_path;
static bool path_exists = true;
int len, shader_size = 0;
return NULL;
}
- construct_name(stage, source, read_path, name, PATH_MAX);
-
+ char *name = construct_name(stage, source, read_path);
f = fopen(name, "r");
+ ralloc_free(name);
if (!f)
return NULL;
if (!shProg) {
return;
}
- if (!shProg->LinkStatus) {
+ if (!shProg->data->LinkStatus) {
_mesa_error(ctx, GL_INVALID_OPERATION,
"glUseProgram(program %u not linked)", program);
return;
* length is zero, and a call to GetProgramBinary will generate an
* INVALID_OPERATION error.
*/
- if (!shProg->LinkStatus) {
+ if (!shProg->data->LinkStatus) {
_mesa_error(ctx, GL_INVALID_OPERATION,
"glGetProgramBinary(program %u not linked)",
shProg->Name);
* Since any value of binaryFormat passed "is not one of those specified as
* allowable for [this] command, an INVALID_ENUM error is generated."
*/
- shProg->LinkStatus = GL_FALSE;
+ shProg->data->LinkStatus = GL_FALSE;
_mesa_error(ctx, GL_INVALID_ENUM, "glProgramBinary");
}
{
gl_shader_stage stage = _mesa_shader_enum_to_shader_stage(type);
use_shader_program(ctx, stage, shProg, shTarget);
-
- if (ctx->Driver.UseProgram)
- ctx->Driver.UseProgram(ctx, shProg);
}
/**
* Copy program-specific data generated by linking from the gl_shader_program
- * object to a specific gl_program object.
+ * object to the gl_program object referred to by the gl_linked_shader.
+ *
+ * This function expects _mesa_reference_program() to have been previously
+ * called setting the gl_linked_shaders program reference.
*/
void
-_mesa_copy_linked_program_data(gl_shader_stage type,
- const struct gl_shader_program *src,
- struct gl_program *dst)
+_mesa_copy_linked_program_data(const struct gl_shader_program *src,
+ struct gl_linked_shader *dst_sh)
{
- switch (type) {
+ assert(dst_sh->Program);
+
+ struct gl_program *dst = dst_sh->Program;
+
+ dst->info.num_images = dst_sh->NumImages;
+ dst->info.separate_shader = src->SeparateShader;
+
+ switch (dst_sh->Stage) {
case MESA_SHADER_VERTEX:
dst->ClipDistanceArraySize = src->Vert.ClipDistanceArraySize;
dst->CullDistanceArraySize = src->Vert.CullDistanceArraySize;
break;
case MESA_SHADER_TESS_CTRL: {
- struct gl_tess_ctrl_program *dst_tcp =
- (struct gl_tess_ctrl_program *) dst;
- dst_tcp->VerticesOut = src->TessCtrl.VerticesOut;
+ dst->info.tcs.vertices_out = dst_sh->info.TessCtrl.VerticesOut;
break;
}
case MESA_SHADER_TESS_EVAL: {
- struct gl_tess_eval_program *dst_tep =
- (struct gl_tess_eval_program *) dst;
- struct gl_shader *tes_sh = src->_LinkedShaders[MESA_SHADER_TESS_EVAL];
-
- dst_tep->PrimitiveMode = tes_sh->TessEval.PrimitiveMode;
- dst_tep->Spacing = tes_sh->TessEval.Spacing;
- dst_tep->VertexOrder = tes_sh->TessEval.VertexOrder;
- dst_tep->PointMode = tes_sh->TessEval.PointMode;
+ dst->info.tes.primitive_mode = dst_sh->info.TessEval.PrimitiveMode;
+ dst->info.tes.spacing = dst_sh->info.TessEval.Spacing;
+ dst->info.tes.vertex_order = dst_sh->info.TessEval.VertexOrder;
+ dst->info.tes.point_mode = dst_sh->info.TessEval.PointMode;
dst->ClipDistanceArraySize = src->TessEval.ClipDistanceArraySize;
dst->CullDistanceArraySize = src->TessEval.CullDistanceArraySize;
break;
}
case MESA_SHADER_GEOMETRY: {
- struct gl_geometry_program *dst_gp = (struct gl_geometry_program *) dst;
- dst_gp->VerticesIn = src->Geom.VerticesIn;
- dst_gp->VerticesOut = src->Geom.VerticesOut;
- dst_gp->Invocations = src->Geom.Invocations;
- dst_gp->InputType = src->Geom.InputType;
- dst_gp->OutputType = src->Geom.OutputType;
+ dst->info.gs.vertices_in = src->Geom.VerticesIn;
+ dst->info.gs.vertices_out = dst_sh->info.Geom.VerticesOut;
+ dst->info.gs.invocations = dst_sh->info.Geom.Invocations;
+ dst->info.gs.input_primitive = dst_sh->info.Geom.InputType;
+ dst->info.gs.output_primitive = dst_sh->info.Geom.OutputType;
dst->ClipDistanceArraySize = src->Geom.ClipDistanceArraySize;
dst->CullDistanceArraySize = src->Geom.CullDistanceArraySize;
- dst_gp->UsesEndPrimitive = src->Geom.UsesEndPrimitive;
- dst_gp->UsesStreams = src->Geom.UsesStreams;
+ dst->info.gs.uses_end_primitive = src->Geom.UsesEndPrimitive;
+ dst->info.gs.uses_streams = src->Geom.UsesStreams;
break;
}
case MESA_SHADER_FRAGMENT: {
- struct gl_fragment_program *dst_fp = (struct gl_fragment_program *) dst;
- dst_fp->FragDepthLayout = src->FragDepthLayout;
+ dst->info.fs.depth_layout = src->FragDepthLayout;
+ dst->info.fs.early_fragment_tests = dst_sh->info.EarlyFragmentTests;
+ dst->info.fs.inner_coverage = dst_sh->info.InnerCoverage;
+ dst->info.fs.post_depth_coverage = dst_sh->info.PostDepthCoverage;
break;
}
case MESA_SHADER_COMPUTE: {
- struct gl_compute_program *dst_cp = (struct gl_compute_program *) dst;
- int i;
- for (i = 0; i < 3; i++)
- dst_cp->LocalSize[i] = src->Comp.LocalSize[i];
- dst_cp->SharedSize = src->Comp.SharedSize;
+ for (int i = 0; i < 3; i++)
+ dst->info.cs.local_size[i] = src->Comp.LocalSize[i];
+ dst->info.cs.shared_size = src->Comp.SharedSize;
+ dst->info.cs.local_size_variable = src->Comp.LocalSizeVariable;
break;
}
default:
/* Possibly... */
if (active-user-defined-varyings-in-linked-program) {
append-error-to-info-log;
- shProg->LinkStatus = GL_FALSE;
+ shProg->data->LinkStatus = GL_FALSE;
}
#endif
}
if (sh->InfoLog)
- ralloc_strcat(&shProg->InfoLog, sh->InfoLog);
+ ralloc_strcat(&shProg->data->InfoLog, sh->InfoLog);
}
delete_shader(ctx, shader);
GLenum resource_type;
gl_shader_stage stage;
- if (!_mesa_has_shader_subroutine(ctx)) {
+ if (!_mesa_has_ARB_shader_subroutine(ctx)) {
_mesa_error(ctx, GL_INVALID_OPERATION, "%s", api_name);
return -1;
}
GLenum resource_type;
gl_shader_stage stage;
- if (!_mesa_has_shader_subroutine(ctx)) {
+ if (!_mesa_has_ARB_shader_subroutine(ctx)) {
_mesa_error(ctx, GL_INVALID_OPERATION, "%s", api_name);
return -1;
}
GET_CURRENT_CONTEXT(ctx);
const char *api_name = "glGetActiveSubroutineUniformiv";
struct gl_shader_program *shProg;
- struct gl_shader *sh;
+ struct gl_linked_shader *sh;
gl_shader_stage stage;
struct gl_program_resource *res;
const struct gl_uniform_storage *uni;
GLenum resource_type;
int count, i, j;
- if (!_mesa_has_shader_subroutine(ctx)) {
+ if (!_mesa_has_ARB_shader_subroutine(ctx)) {
_mesa_error(ctx, GL_INVALID_OPERATION, "%s", api_name);
return;
}
return;
}
- if (index >= sh->NumSubroutineUniforms) {
+ struct gl_program *p = shProg->_LinkedShaders[stage]->Program;
+ if (index >= p->sh.NumSubroutineUniforms) {
_mesa_error(ctx, GL_INVALID_VALUE, "%s: invalid index greater than GL_ACTIVE_SUBROUTINE_UNIFORMS", api_name);
return;
}
if (res) {
uni = res->Data;
count = 0;
- for (i = 0; i < sh->NumSubroutineFunctions; i++) {
- struct gl_subroutine_function *fn = &sh->SubroutineFunctions[i];
+ for (i = 0; i < p->sh.NumSubroutineFunctions; i++) {
+ struct gl_subroutine_function *fn = &p->sh.SubroutineFunctions[i];
for (j = 0; j < fn->num_compat_types; j++) {
if (fn->types[j] == uni->type) {
values[count++] = i;
GLenum resource_type;
gl_shader_stage stage;
- if (!_mesa_has_shader_subroutine(ctx)) {
+ if (!_mesa_has_ARB_shader_subroutine(ctx)) {
_mesa_error(ctx, GL_INVALID_OPERATION, "%s", api_name);
return;
}
GLenum resource_type;
gl_shader_stage stage;
- if (!_mesa_has_shader_subroutine(ctx)) {
+ if (!_mesa_has_ARB_shader_subroutine(ctx)) {
_mesa_error(ctx, GL_INVALID_OPERATION, "%s", api_name);
return;
}
length, name, api_name);
}
-
GLvoid GLAPIENTRY
_mesa_UniformSubroutinesuiv(GLenum shadertype, GLsizei count,
const GLuint *indices)
GET_CURRENT_CONTEXT(ctx);
const char *api_name = "glUniformSubroutinesuiv";
struct gl_shader_program *shProg;
- struct gl_shader *sh;
+ struct gl_linked_shader *sh;
gl_shader_stage stage;
int i;
- if (!_mesa_has_shader_subroutine(ctx)) {
+ if (!_mesa_has_ARB_shader_subroutine(ctx)) {
_mesa_error(ctx, GL_INVALID_OPERATION, "%s", api_name);
return;
}
return;
}
- if (count != sh->NumSubroutineUniformRemapTable) {
+ struct gl_program *p = shProg->_LinkedShaders[stage]->Program;
+ if (count != p->sh.NumSubroutineUniformRemapTable) {
_mesa_error(ctx, GL_INVALID_VALUE, "%s", api_name);
return;
}
i = 0;
do {
- struct gl_uniform_storage *uni = sh->SubroutineUniformRemapTable[i];
+ struct gl_uniform_storage *uni = p->sh.SubroutineUniformRemapTable[i];
if (uni == NULL) {
i++;
continue;
for (j = i; j < i + uni_count; j++) {
struct gl_subroutine_function *subfn = NULL;
- if (indices[j] > sh->MaxSubroutineFunctionIndex) {
+ if (indices[j] > p->sh.MaxSubroutineFunctionIndex) {
_mesa_error(ctx, GL_INVALID_VALUE, "%s", api_name);
return;
}
- for (f = 0; f < sh->NumSubroutineFunctions; f++) {
- if (sh->SubroutineFunctions[f].index == indices[j])
- subfn = &sh->SubroutineFunctions[f];
+ for (f = 0; f < p->sh.NumSubroutineFunctions; f++) {
+ if (p->sh.SubroutineFunctions[f].index == indices[j])
+ subfn = &p->sh.SubroutineFunctions[f];
}
if (!subfn) {
_mesa_error(ctx, GL_INVALID_OPERATION, "%s", api_name);
return;
}
+
+ ctx->SubroutineIndex[p->info.stage].IndexPtr[j] = indices[j];
}
i += uni_count;
} while(i < count);
FLUSH_VERTICES(ctx, _NEW_PROGRAM_CONSTANTS);
- i = 0;
- do {
- struct gl_uniform_storage *uni = sh->SubroutineUniformRemapTable[i];
- if (uni == NULL) {
- i++;
- continue;
- }
-
- int uni_count = uni->array_elements ? uni->array_elements : 1;
-
- memcpy(&uni->storage[0], &indices[i],
- sizeof(GLuint) * uni_count);
-
- _mesa_propagate_uniforms_to_driver_storage(uni, 0, uni_count);
- i += uni_count;
- } while(i < count);
}
GET_CURRENT_CONTEXT(ctx);
const char *api_name = "glGetUniformSubroutineuiv";
struct gl_shader_program *shProg;
- struct gl_shader *sh;
+ struct gl_linked_shader *sh;
gl_shader_stage stage;
- if (!_mesa_has_shader_subroutine(ctx)) {
+ if (!_mesa_has_ARB_shader_subroutine(ctx)) {
_mesa_error(ctx, GL_INVALID_OPERATION, "%s", api_name);
return;
}
return;
}
- if (location >= sh->NumSubroutineUniformRemapTable) {
+ struct gl_program *p = sh->Program;
+ if (location >= p->sh.NumSubroutineUniformRemapTable) {
_mesa_error(ctx, GL_INVALID_VALUE, "%s", api_name);
return;
}
- {
- struct gl_uniform_storage *uni = sh->SubroutineUniformRemapTable[location];
- int offset = location - uni->opaque[stage].index;
- memcpy(params, &uni->storage[offset],
- sizeof(GLuint));
- }
+ *params = ctx->SubroutineIndex[p->info.stage].IndexPtr[location];
}
GET_CURRENT_CONTEXT(ctx);
const char *api_name = "glGetProgramStageiv";
struct gl_shader_program *shProg;
- struct gl_shader *sh;
+ struct gl_linked_shader *sh;
gl_shader_stage stage;
- if (!_mesa_has_shader_subroutine(ctx)) {
+ if (!_mesa_has_ARB_shader_subroutine(ctx)) {
_mesa_error(ctx, GL_INVALID_OPERATION, "%s", api_name);
return;
}
stage = _mesa_shader_enum_to_shader_stage(shadertype);
sh = shProg->_LinkedShaders[stage];
+
+ /* ARB_shader_subroutine doesn't ask the program to be linked, or list any
+ * INVALID_OPERATION in the case of not be linked.
+ *
+ * And for some pnames, like GL_ACTIVE_SUBROUTINE_UNIFORMS, you can ask the
+ * same info using other specs (ARB_program_interface_query), without the
+ * need of the program to be linked, being the value for that case 0.
+ *
+ * But at the same time, some other methods require the program to be
+ * linked for pname related to locations, so it would be inconsistent to
+ * not do the same here. So we are:
+ * * Return GL_INVALID_OPERATION if not linked only for locations.
+ * * Setting a default value of 0, to be returned if not linked.
+ */
if (!sh) {
- _mesa_error(ctx, GL_INVALID_OPERATION, "%s", api_name);
+ values[0] = 0;
+ if (pname == GL_ACTIVE_SUBROUTINE_UNIFORM_LOCATIONS) {
+ _mesa_error(ctx, GL_INVALID_OPERATION, "%s", api_name);
+ }
return;
}
+ struct gl_program *p = sh->Program;
switch (pname) {
case GL_ACTIVE_SUBROUTINES:
- values[0] = sh->NumSubroutineFunctions;
+ values[0] = p->sh.NumSubroutineFunctions;
break;
case GL_ACTIVE_SUBROUTINE_UNIFORM_LOCATIONS:
- values[0] = sh->NumSubroutineUniformRemapTable;
+ values[0] = p->sh.NumSubroutineUniformRemapTable;
break;
case GL_ACTIVE_SUBROUTINE_UNIFORMS:
- values[0] = sh->NumSubroutineUniforms;
+ values[0] = p->sh.NumSubroutineUniforms;
break;
case GL_ACTIVE_SUBROUTINE_MAX_LENGTH:
{
struct gl_program_resource *res;
resource_type = _mesa_shader_stage_to_subroutine(stage);
- for (i = 0; i < sh->NumSubroutineFunctions; i++) {
+ for (i = 0; i < p->sh.NumSubroutineFunctions; i++) {
res = _mesa_program_resource_find_index(shProg, resource_type, i);
if (res) {
const GLint len = strlen(_mesa_program_resource_name(res)) + 1;
struct gl_program_resource *res;
resource_type = _mesa_shader_stage_to_subroutine_uniform(stage);
- for (i = 0; i < sh->NumSubroutineUniformRemapTable; i++) {
+ for (i = 0; i < p->sh.NumSubroutineUniformRemapTable; i++) {
res = _mesa_program_resource_find_index(shProg, resource_type, i);
if (res) {
const GLint len = strlen(_mesa_program_resource_name(res)) + 1
}
static int
-find_compat_subroutine(struct gl_shader *sh, const struct glsl_type *type)
+find_compat_subroutine(struct gl_program *p, const struct glsl_type *type)
{
int i, j;
- for (i = 0; i < sh->NumSubroutineFunctions; i++) {
- struct gl_subroutine_function *fn = &sh->SubroutineFunctions[i];
+ for (i = 0; i < p->sh.NumSubroutineFunctions; i++) {
+ struct gl_subroutine_function *fn = &p->sh.SubroutineFunctions[i];
for (j = 0; j < fn->num_compat_types; j++) {
if (fn->types[j] == type)
return i;
}
static void
-_mesa_shader_init_subroutine_defaults(struct gl_shader *sh)
+_mesa_shader_write_subroutine_index(struct gl_context *ctx,
+ struct gl_program *p)
{
int i, j;
- for (i = 0; i < sh->NumSubroutineUniformRemapTable; i++) {
- struct gl_uniform_storage *uni = sh->SubroutineUniformRemapTable[i];
+ if (p->sh.NumSubroutineUniformRemapTable == 0)
+ return;
+
+ i = 0;
+ do {
+ struct gl_uniform_storage *uni = p->sh.SubroutineUniformRemapTable[i];
int uni_count;
int val;
- if (!uni)
+ if (!uni) {
+ i++;
continue;
- uni_count = uni->array_elements ? uni->array_elements : 1;
- val = find_compat_subroutine(sh, uni->type);
+ }
- for (j = 0; j < uni_count; j++)
+ uni_count = uni->array_elements ? uni->array_elements : 1;
+ for (j = 0; j < uni_count; j++) {
+ val = ctx->SubroutineIndex[p->info.stage].IndexPtr[i + j];
memcpy(&uni->storage[j], &val, sizeof(int));
+ }
_mesa_propagate_uniforms_to_driver_storage(uni, 0, uni_count);
+ i += uni_count;
+ } while(i < p->sh.NumSubroutineUniformRemapTable);
+}
+
+void
+_mesa_shader_write_subroutine_indices(struct gl_context *ctx,
+ gl_shader_stage stage)
+{
+ if (ctx->_Shader->CurrentProgram[stage] &&
+ ctx->_Shader->CurrentProgram[stage]->_LinkedShaders[stage])
+ _mesa_shader_write_subroutine_index(ctx,
+ ctx->_Shader->CurrentProgram[stage]->_LinkedShaders[stage]->Program);
+}
+
+static void
+_mesa_program_init_subroutine_defaults(struct gl_context *ctx,
+ struct gl_program *p)
+{
+ assert(p);
+
+ struct gl_subroutine_index_binding *binding = &ctx->SubroutineIndex[p->info.stage];
+ if (binding->NumIndex != p->sh.NumSubroutineUniformRemapTable) {
+ binding->IndexPtr = realloc(binding->IndexPtr,
+ p->sh.NumSubroutineUniformRemapTable * (sizeof(GLuint)));
+ binding->NumIndex = p->sh.NumSubroutineUniformRemapTable;
+ }
+
+ for (int i = 0; i < p->sh.NumSubroutineUniformRemapTable; i++) {
+ struct gl_uniform_storage *uni = p->sh.SubroutineUniformRemapTable[i];
+
+ if (!uni)
+ continue;
+
+ binding->IndexPtr[i] = find_compat_subroutine(p, uni->type);
}
}
void
-_mesa_shader_program_init_subroutine_defaults(struct gl_shader_program *shProg)
+_mesa_shader_program_init_subroutine_defaults(struct gl_context *ctx,
+ struct gl_shader_program *shProg)
{
int i;
if (!shProg->_LinkedShaders[i])
continue;
- _mesa_shader_init_subroutine_defaults(shProg->_LinkedShaders[i]);
+ _mesa_program_init_subroutine_defaults(ctx, shProg->_LinkedShaders[i]->Program);
}
}