* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
- * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
*/
/**
#include "main/dispatch.h"
#include "main/enums.h"
#include "main/hash.h"
-#include "main/mfeatures.h"
+#include "main/hash_table.h"
#include "main/mtypes.h"
#include "main/shaderapi.h"
#include "main/shaderobj.h"
#include "main/transformfeedback.h"
#include "main/uniforms.h"
#include "program/program.h"
+#include "program/prog_print.h"
#include "program/prog_parameter.h"
#include "ralloc.h"
#include <stdbool.h>
#include "../glsl/glsl_parser_extras.h"
+#include "../glsl/ir.h"
#include "../glsl/ir_uniform.h"
+#include "../glsl/program.h"
/** Define this to enable shader substitution (see below) */
#define SHADER_SUBST 0
const char *env = _mesa_getenv("MESA_GLSL");
if (env) {
- if (strstr(env, "dump"))
+ if (strstr(env, "dump_on_error"))
+ flags |= GLSL_DUMP_ON_ERROR;
+ else if (strstr(env, "dump"))
flags |= GLSL_DUMP;
if (strstr(env, "log"))
flags |= GLSL_LOG;
* are generated by the GLSL compiler.
*/
struct gl_shader_compiler_options options;
- gl_shader_type sh;
+ gl_shader_stage sh;
memset(&options, 0, sizeof(options));
options.MaxUnrollIterations = 32;
/* Default pragma settings */
options.DefaultPragmas.Optimize = GL_TRUE;
- for (sh = 0; sh < MESA_SHADER_TYPES; ++sh)
+ for (sh = 0; sh < MESA_SHADER_STAGES; ++sh)
memcpy(&ctx->ShaderCompilerOptions[sh], &options, sizeof(options));
ctx->Shader.Flags = get_shader_flags();
void
_mesa_free_shader_state(struct gl_context *ctx)
{
- _mesa_reference_shader_program(ctx, &ctx->Shader.CurrentVertexProgram, NULL);
- _mesa_reference_shader_program(ctx, &ctx->Shader.CurrentGeometryProgram,
- NULL);
- _mesa_reference_shader_program(ctx, &ctx->Shader.CurrentFragmentProgram,
- NULL);
+ int i;
+ for (i = 0; i < MESA_SHADER_STAGES; i++) {
+ _mesa_reference_shader_program(ctx, &ctx->Shader.CurrentProgram[i],
+ NULL);
+ }
_mesa_reference_shader_program(ctx, &ctx->Shader._CurrentFragmentProgram,
NULL);
_mesa_reference_shader_program(ctx, &ctx->Shader.ActiveProgram, NULL);
* \param type Shader target
*
*/
-static bool
-validate_shader_target(const struct gl_context *ctx, GLenum type)
-{
+bool
+_mesa_validate_shader_target(const struct gl_context *ctx, GLenum type)
+{
+ /* Note: when building built-in GLSL functions, this function may be
+ * invoked with ctx == NULL. In that case, we can only validate that it's
+ * a shader target we recognize, not that it's supported in the current
+ * context. But that's fine--we don't need any further validation than
+ * that when building built-in GLSL functions.
+ */
+
switch (type) {
case GL_FRAGMENT_SHADER:
- return ctx->Extensions.ARB_fragment_shader;
+ return ctx == NULL || ctx->Extensions.ARB_fragment_shader;
case GL_VERTEX_SHADER:
- return ctx->Extensions.ARB_vertex_shader;
+ return ctx == NULL || ctx->Extensions.ARB_vertex_shader;
case GL_GEOMETRY_SHADER_ARB:
- return _mesa_is_desktop_gl(ctx) && ctx->Extensions.ARB_geometry_shader4;
+ return ctx == NULL || _mesa_has_geometry_shaders(ctx);
+ case GL_COMPUTE_SHADER:
+ return ctx == NULL || ctx->Extensions.ARB_compute_shader;
default:
return false;
}
struct gl_shader *sh;
GLuint name;
- if (!validate_shader_target(ctx, type)) {
+ if (!_mesa_validate_shader_target(ctx, type)) {
_mesa_error(ctx, GL_INVALID_ENUM, "CreateShader(type)");
return 0;
}
_mesa_reference_shader(ctx, &shProg->Shaders[i], NULL);
/* alloc new, smaller array */
- newList =
- malloc((n - 1) * sizeof(struct gl_shader *));
+ newList = malloc((n - 1) * sizeof(struct gl_shader *));
if (!newList) {
_mesa_error(ctx, GL_OUT_OF_MEMORY, "glDetachShader");
return;
}
+ /* Copy old list entries to new list, skipping removed entry at [i] */
for (j = 0; j < i; j++) {
newList[j] = shProg->Shaders[j];
}
- while (++i < n)
+ while (++i < n) {
newList[j++] = shProg->Shaders[i];
- free(shProg->Shaders);
+ }
+ /* Free old list and install new one */
+ free(shProg->Shaders);
shProg->Shaders = newList;
shProg->NumShaders = n - 1;
#ifdef DEBUG
- /* sanity check */
- {
- for (j = 0; j < shProg->NumShaders; j++) {
- assert(shProg->Shaders[j]->Type == GL_VERTEX_SHADER ||
- shProg->Shaders[j]->Type == GL_FRAGMENT_SHADER);
- assert(shProg->Shaders[j]->RefCount > 0);
- }
+ /* sanity check - make sure the new list's entries are sensible */
+ for (j = 0; j < shProg->NumShaders; j++) {
+ assert(shProg->Shaders[j]->Type == GL_VERTEX_SHADER ||
+ shProg->Shaders[j]->Type == GL_GEOMETRY_SHADER ||
+ shProg->Shaders[j]->Type == GL_FRAGMENT_SHADER);
+ assert(shProg->Shaders[j]->RefCount > 0);
}
#endif
err = GL_INVALID_OPERATION;
else
err = GL_INVALID_VALUE;
- _mesa_error(ctx, err, "glDetachProgram(shader)");
+ _mesa_error(ctx, err, "glDetachShader(shader)");
return;
}
}
}
+/**
+ * Check if a geometry shader query is valid at this time. If not, report an
+ * error and return false.
+ *
+ * From GL 3.2 section 6.1.16 (Shader and Program Queries):
+ *
+ * "If GEOMETRY_VERTICES_OUT, GEOMETRY_INPUT_TYPE, or GEOMETRY_OUTPUT_TYPE
+ * are queried for a program which has not been linked successfully, or
+ * which does not contain objects to form a geometry shader, then an
+ * INVALID_OPERATION error is generated."
+ */
+static bool
+check_gs_query(struct gl_context *ctx, const struct gl_shader_program *shProg)
+{
+ if (shProg->LinkStatus &&
+ shProg->_LinkedShaders[MESA_SHADER_GEOMETRY] != NULL) {
+ return true;
+ }
+
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glGetProgramv(linked geometry shader required)");
+ return false;
+}
+
+
/**
* glGetProgramiv() - get shader program state.
* Note that this is for GLSL shader programs, not ARB vertex/fragment
|| ctx->API == API_OPENGL_CORE
|| _mesa_is_gles3(ctx);
- /* Are geometry shaders available in this context?
+ /* True if geometry shaders (of the form that was adopted into GLSL 1.50
+ * and GL 3.2) are available in this context
*/
- const bool has_gs =
- _mesa_is_desktop_gl(ctx) && ctx->Extensions.ARB_geometry_shader4;
+ const bool has_core_gs = _mesa_is_desktop_gl(ctx) && ctx->Version >= 32;
/* Are uniform buffer objects available in this context?
*/
break;
*params = shProg->TransformFeedback.BufferMode;
return;
- case GL_GEOMETRY_VERTICES_OUT_ARB:
- if (!has_gs)
+ case GL_GEOMETRY_VERTICES_OUT:
+ if (!has_core_gs)
break;
- *params = shProg->Geom.VerticesOut;
+ if (check_gs_query(ctx, shProg))
+ *params = shProg->Geom.VerticesOut;
return;
- case GL_GEOMETRY_INPUT_TYPE_ARB:
- if (!has_gs)
+ case GL_GEOMETRY_SHADER_INVOCATIONS:
+ if (!has_core_gs || !ctx->Extensions.ARB_gpu_shader5)
break;
- *params = shProg->Geom.InputType;
+ if (check_gs_query(ctx, shProg))
+ *params = shProg->Geom.Invocations;
return;
- case GL_GEOMETRY_OUTPUT_TYPE_ARB:
- if (!has_gs)
+ case GL_GEOMETRY_INPUT_TYPE:
+ if (!has_core_gs)
break;
- *params = shProg->Geom.OutputType;
+ if (check_gs_query(ctx, shProg))
+ *params = shProg->Geom.InputType;
+ return;
+ case GL_GEOMETRY_OUTPUT_TYPE:
+ if (!has_core_gs)
+ break;
+ if (check_gs_query(ctx, shProg))
+ *params = shProg->Geom.OutputType;
return;
case GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH: {
unsigned i;
case GL_PROGRAM_BINARY_LENGTH:
*params = 0;
return;
+ case GL_ACTIVE_ATOMIC_COUNTER_BUFFERS:
+ if (!ctx->Extensions.ARB_shader_atomic_counters)
+ break;
+
+ *params = shProg->NumAtomicBuffers;
+ return;
+ case GL_COMPUTE_WORK_GROUP_SIZE: {
+ int i;
+ if (!_mesa_is_desktop_gl(ctx) || !ctx->Extensions.ARB_compute_shader)
+ break;
+ if (!shProg->LinkStatus) {
+ _mesa_error(ctx, GL_INVALID_OPERATION, "glGetProgramiv(program not "
+ "linked)");
+ return;
+ }
+ if (shProg->_LinkedShaders[MESA_SHADER_COMPUTE] == NULL) {
+ _mesa_error(ctx, GL_INVALID_OPERATION, "glGetProgramiv(no compute "
+ "shaders)");
+ return;
+ }
+ for (i = 0; i < 3; i++)
+ params[i] = shProg->Comp.LocalSize[i];
+ return;
+ }
default:
break;
}
if (!sh)
return;
- options = &ctx->ShaderCompilerOptions[_mesa_shader_type_to_index(sh->Type)];
+ options = &ctx->ShaderCompilerOptions[sh->Stage];
/* set default pragma state for shader */
sh->Pragmas = options->DefaultPragmas;
- /* this call will set the sh->CompileStatus field to indicate if
- * compilation was successful.
- */
- _mesa_glsl_compile_shader(ctx, sh);
+ if (!sh->Source) {
+ /* If the user called glCompileShader without first calling
+ * glShaderSource, we should fail to compile, but not raise a GL_ERROR.
+ */
+ sh->CompileStatus = GL_FALSE;
+ } else {
+ if (ctx->Shader.Flags & GLSL_DUMP) {
+ printf("GLSL source for %s shader %d:\n",
+ _mesa_shader_stage_to_string(sh->Stage), sh->Name);
+ printf("%s\n", sh->Source);
+ }
- if (sh->CompileStatus == GL_FALSE &&
- (ctx->Shader.Flags & GLSL_REPORT_ERRORS)) {
- _mesa_debug(ctx, "Error compiling shader %u:\n%s\n",
- sh->Name, sh->InfoLog);
+ /* this call will set the shader->CompileStatus field to indicate if
+ * compilation was successful.
+ */
+ _mesa_glsl_compile_shader(ctx, sh, false, false);
+
+ if (ctx->Shader.Flags & GLSL_LOG) {
+ _mesa_write_shader_to_file(sh);
+ }
+
+ if (ctx->Shader.Flags & GLSL_DUMP) {
+ if (sh->CompileStatus) {
+ printf("GLSL IR for shader %d:\n", sh->Name);
+ _mesa_print_ir(sh->ir, NULL);
+ printf("\n\n");
+ } else {
+ printf("GLSL shader %d failed to compile.\n", sh->Name);
+ }
+ if (sh->InfoLog && sh->InfoLog[0] != 0) {
+ printf("GLSL shader %d info log:\n", sh->Name);
+ printf("%s\n", sh->InfoLog);
+ }
+ }
+
+ }
+
+ if (!sh->CompileStatus) {
+ if (ctx->Shader.Flags & GLSL_DUMP_ON_ERROR) {
+ fprintf(stderr, "GLSL source for %s shader %d:\n",
+ _mesa_shader_stage_to_string(sh->Stage), sh->Name);
+ fprintf(stderr, "%s\n", sh->Source);
+ fprintf(stderr, "Info Log:\n%s\n", sh->InfoLog);
+ fflush(stderr);
+ }
+
+ if (ctx->Shader.Flags & GLSL_REPORT_ERRORS) {
+ _mesa_debug(ctx, "Error compiling shader %u:\n%s\n",
+ sh->Name, sh->InfoLog);
+ }
}
}
link_program(struct gl_context *ctx, GLuint program)
{
struct gl_shader_program *shProg;
- struct gl_transform_feedback_object *obj =
- ctx->TransformFeedback.CurrentObject;
shProg = _mesa_lookup_shader_program_err(ctx, program, "glLinkProgram");
if (!shProg)
return;
- if (obj->Active
- && (shProg == ctx->Shader.CurrentVertexProgram
- || shProg == ctx->Shader.CurrentGeometryProgram
- || shProg == ctx->Shader.CurrentFragmentProgram)) {
+ /* From the ARB_transform_feedback2 specification:
+ * "The error INVALID_OPERATION is generated by LinkProgram if <program> is
+ * the name of a program being used by one or more transform feedback
+ * objects, even if the objects are not currently bound or are paused."
+ */
+ if (_mesa_transform_feedback_is_using_program(ctx, shProg)) {
_mesa_error(ctx, GL_INVALID_OPERATION,
- "glLinkProgram(transform feedback active)");
+ "glLinkProgram(transform feedback is using the program)");
return;
}
printf("Mesa: glUseProgram(%u)\n", shProg->Name);
for (i = 0; i < shProg->NumShaders; i++) {
- const char *s;
- switch (shProg->Shaders[i]->Type) {
- case GL_VERTEX_SHADER:
- s = "vertex";
- break;
- case GL_FRAGMENT_SHADER:
- s = "fragment";
- break;
- case GL_GEOMETRY_SHADER:
- s = "geometry";
- break;
- default:
- s = "";
- }
- printf(" %s shader %u, checksum %u\n", s,
+ printf(" %s shader %u, checksum %u\n",
+ _mesa_shader_stage_to_string(shProg->Shaders[i]->Stage),
shProg->Shaders[i]->Name,
shProg->Shaders[i]->SourceChecksum);
}
/**
*/
-static bool
+static void
use_shader_program(struct gl_context *ctx, GLenum type,
struct gl_shader_program *shProg)
{
struct gl_shader_program **target;
+ gl_shader_stage stage = _mesa_shader_enum_to_shader_stage(type);
- switch (type) {
- case GL_VERTEX_SHADER:
- target = &ctx->Shader.CurrentVertexProgram;
- if ((shProg == NULL)
- || (shProg->_LinkedShaders[MESA_SHADER_VERTEX] == NULL)) {
- shProg = NULL;
- }
- break;
- case GL_GEOMETRY_SHADER_ARB:
- target = &ctx->Shader.CurrentGeometryProgram;
- if ((shProg == NULL)
- || (shProg->_LinkedShaders[MESA_SHADER_GEOMETRY] == NULL)) {
- shProg = NULL;
- }
- break;
- case GL_FRAGMENT_SHADER:
- target = &ctx->Shader.CurrentFragmentProgram;
- if ((shProg == NULL)
- || (shProg->_LinkedShaders[MESA_SHADER_FRAGMENT] == NULL)) {
- shProg = NULL;
- }
- break;
- default:
- return false;
- }
+ target = &ctx->Shader.CurrentProgram[stage];
+ if ((shProg == NULL) || (shProg->_LinkedShaders[stage] == NULL))
+ shProg = NULL;
if (*target != shProg) {
FLUSH_VERTICES(ctx, _NEW_PROGRAM | _NEW_PROGRAM_CONSTANTS);
case GL_GEOMETRY_SHADER_ARB:
/* Empty for now. */
break;
+ case GL_COMPUTE_SHADER:
+ /* Empty for now. */
+ break;
case GL_FRAGMENT_SHADER:
if (*target == ctx->Shader._CurrentFragmentProgram) {
_mesa_reference_shader_program(ctx,
}
_mesa_reference_shader_program(ctx, target, shProg);
- return true;
+ return;
}
-
- return false;
}
/**
use_shader_program(ctx, GL_VERTEX_SHADER, shProg);
use_shader_program(ctx, GL_GEOMETRY_SHADER_ARB, shProg);
use_shader_program(ctx, GL_FRAGMENT_SHADER, shProg);
+ use_shader_program(ctx, GL_COMPUTE_SHADER, shProg);
_mesa_active_program(ctx, shProg, "glUseProgram");
if (ctx->Driver.UseProgram)
switch (shadertype) {
case GL_VERTEX_SHADER:
- limits = &ctx->Const.VertexProgram;
+ limits = &ctx->Const.Program[MESA_SHADER_VERTEX];
break;
case GL_FRAGMENT_SHADER:
- limits = &ctx->Const.FragmentProgram;
+ limits = &ctx->Const.Program[MESA_SHADER_FRAGMENT];
break;
default:
_mesa_error(ctx, GL_INVALID_ENUM,
return;
switch (pname) {
- case GL_GEOMETRY_VERTICES_OUT_ARB:
- if (!_mesa_is_desktop_gl(ctx) || !ctx->Extensions.ARB_geometry_shader4)
- break;
-
- if (value < 1 ||
- (unsigned) value > ctx->Const.MaxGeometryOutputVertices) {
- _mesa_error(ctx, GL_INVALID_VALUE,
- "glProgramParameteri(GL_GEOMETRY_VERTICES_OUT_ARB=%d",
- value);
- return;
- }
- shProg->Geom.VerticesOut = value;
- return;
- case GL_GEOMETRY_INPUT_TYPE_ARB:
- if (!_mesa_is_desktop_gl(ctx) || !ctx->Extensions.ARB_geometry_shader4)
- break;
-
- switch (value) {
- case GL_POINTS:
- case GL_LINES:
- case GL_LINES_ADJACENCY_ARB:
- case GL_TRIANGLES:
- case GL_TRIANGLES_ADJACENCY_ARB:
- shProg->Geom.InputType = value;
- break;
- default:
- _mesa_error(ctx, GL_INVALID_VALUE,
- "glProgramParameteri(geometry input type = %s",
- _mesa_lookup_enum_by_nr(value));
- return;
- }
- return;
- case GL_GEOMETRY_OUTPUT_TYPE_ARB:
- if (!_mesa_is_desktop_gl(ctx) || !ctx->Extensions.ARB_geometry_shader4)
- break;
-
- switch (value) {
- case GL_POINTS:
- case GL_LINE_STRIP:
- case GL_TRIANGLE_STRIP:
- shProg->Geom.OutputType = value;
- break;
- default:
- _mesa_error(ctx, GL_INVALID_VALUE,
- "glProgramParameteri(geometry output type = %s",
- _mesa_lookup_enum_by_nr(value));
- return;
- }
- return;
case GL_PROGRAM_BINARY_RETRIEVABLE_HINT:
/* This enum isn't part of the OES extension for OpenGL ES 2.0, but it
* is part of OpenGL ES 3.0. For the ES2 case, this function shouldn't
GET_CURRENT_CONTEXT(ctx);
struct gl_shader_program *shProg = NULL;
- if (!validate_shader_target(ctx, type)) {
+ if (!_mesa_validate_shader_target(ctx, type)) {
_mesa_error(ctx, GL_INVALID_ENUM, "glUseShaderProgramEXT(type)");
return;
}
return program;
}
+
+
+/**
+ * Copy program-specific data generated by linking from the gl_shader_program
+ * object to a specific gl_program object.
+ */
+void
+_mesa_copy_linked_program_data(gl_shader_stage type,
+ const struct gl_shader_program *src,
+ struct gl_program *dst)
+{
+ switch (type) {
+ case MESA_SHADER_VERTEX:
+ dst->UsesClipDistanceOut = src->Vert.UsesClipDistance;
+ 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->UsesClipDistanceOut = src->Geom.UsesClipDistance;
+ dst_gp->UsesEndPrimitive = src->Geom.UsesEndPrimitive;
+ }
+ 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];
+ }
+ break;
+ default:
+ break;
+ }
+}