#include "main/dispatch.h"
#include "main/enums.h"
#include "main/hash.h"
+#include "main/mfeatures.h"
+#include "main/mtypes.h"
#include "main/shaderapi.h"
#include "main/shaderobj.h"
+#include "main/uniforms.h"
#include "program/program.h"
#include "program/prog_parameter.h"
-#include "program/prog_uniform.h"
-#include "slang/slang_compile.h"
-#include "slang/slang_link.h"
-
+#include "ralloc.h"
+#include <stdbool.h>
+#include "../glsl/glsl_parser_extras.h"
+#include "../glsl/ir_uniform.h"
/** Define this to enable shader substitution (see below) */
#define SHADER_SUBST 0
* Initialize context's shader state.
*/
void
-_mesa_init_shader_state(GLcontext *ctx)
+_mesa_init_shader_state(struct gl_context *ctx)
{
/* Device drivers may override these to control what kind of instructions
* are generated by the GLSL compiler.
*/
- ctx->Shader.EmitHighLevelInstructions = GL_TRUE;
- ctx->Shader.EmitContReturn = GL_TRUE;
- ctx->Shader.EmitCondCodes = GL_FALSE;
- ctx->Shader.EmitComments = GL_FALSE;
- ctx->Shader.Flags = get_shader_flags();
+ struct gl_shader_compiler_options options;
+ gl_shader_type sh;
+
+ memset(&options, 0, sizeof(options));
+ options.MaxUnrollIterations = 32;
/* Default pragma settings */
- ctx->Shader.DefaultPragmas.IgnoreOptimize = GL_FALSE;
- ctx->Shader.DefaultPragmas.IgnoreDebug = GL_FALSE;
- ctx->Shader.DefaultPragmas.Optimize = GL_TRUE;
- ctx->Shader.DefaultPragmas.Debug = GL_FALSE;
-}
+ options.DefaultPragmas.Optimize = GL_TRUE;
+ for (sh = 0; sh < MESA_SHADER_TYPES; ++sh)
+ memcpy(&ctx->ShaderCompilerOptions[sh], &options, sizeof(options));
-/**
- * Free the per-context shader-related state.
- */
-void
-_mesa_free_shader_state(GLcontext *ctx)
-{
- _mesa_reference_shader_program(ctx, &ctx->Shader.CurrentProgram, NULL);
+ ctx->Shader.Flags = get_shader_flags();
}
/**
- * Return the size of the given GLSL datatype, in floats (components).
+ * Free the per-context shader-related state.
*/
-GLint
-_mesa_sizeof_glsl_type(GLenum type)
+void
+_mesa_free_shader_state(struct gl_context *ctx)
{
- switch (type) {
- case GL_FLOAT:
- case GL_INT:
- case GL_BOOL:
- case GL_SAMPLER_1D:
- case GL_SAMPLER_2D:
- case GL_SAMPLER_3D:
- case GL_SAMPLER_CUBE:
- case GL_SAMPLER_1D_SHADOW:
- case GL_SAMPLER_2D_SHADOW:
- case GL_SAMPLER_2D_RECT_ARB:
- case GL_SAMPLER_2D_RECT_SHADOW_ARB:
- case GL_SAMPLER_1D_ARRAY_EXT:
- case GL_SAMPLER_2D_ARRAY_EXT:
- case GL_SAMPLER_1D_ARRAY_SHADOW_EXT:
- case GL_SAMPLER_2D_ARRAY_SHADOW_EXT:
- case GL_SAMPLER_CUBE_SHADOW_EXT:
- return 1;
- case GL_FLOAT_VEC2:
- case GL_INT_VEC2:
- case GL_UNSIGNED_INT_VEC2:
- case GL_BOOL_VEC2:
- return 2;
- case GL_FLOAT_VEC3:
- case GL_INT_VEC3:
- case GL_UNSIGNED_INT_VEC3:
- case GL_BOOL_VEC3:
- return 3;
- case GL_FLOAT_VEC4:
- case GL_INT_VEC4:
- case GL_UNSIGNED_INT_VEC4:
- case GL_BOOL_VEC4:
- return 4;
- case GL_FLOAT_MAT2:
- case GL_FLOAT_MAT2x3:
- case GL_FLOAT_MAT2x4:
- return 8; /* two float[4] vectors */
- case GL_FLOAT_MAT3:
- case GL_FLOAT_MAT3x2:
- case GL_FLOAT_MAT3x4:
- return 12; /* three float[4] vectors */
- case GL_FLOAT_MAT4:
- case GL_FLOAT_MAT4x2:
- case GL_FLOAT_MAT4x3:
- return 16; /* four float[4] vectors */
- default:
- _mesa_problem(NULL, "Invalid type in _mesa_sizeof_glsl_type()");
- return 1;
- }
+ _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);
+ _mesa_reference_shader_program(ctx, &ctx->Shader._CurrentFragmentProgram,
+ NULL);
+ _mesa_reference_shader_program(ctx, &ctx->Shader.ActiveProgram, NULL);
}
+/**
+ * Confirm that the a shader type is valid and supported by the implementation
+ *
+ * \param ctx Current GL context
+ * \param type Shader target
+ *
+ */
+static bool
+validate_shader_target(const struct gl_context *ctx, GLenum type)
+{
+ switch (type) {
+#if FEATURE_ARB_fragment_shader
+ case GL_FRAGMENT_SHADER:
+ return ctx->Extensions.ARB_fragment_shader;
+#endif
+#if FEATURE_ARB_vertex_shader
+ case GL_VERTEX_SHADER:
+ return ctx->Extensions.ARB_vertex_shader;
+#endif
+#if FEATURE_ARB_geometry_shader4
+ case GL_GEOMETRY_SHADER_ARB:
+ return ctx->Extensions.ARB_geometry_shader4;
+#endif
+ default:
+ return false;
+ }
+}
+
+
/**
* Find the length of the longest transform feedback varying name
* which was specified with glTransformFeedbackVaryings().
static GLboolean
-is_program(GLcontext *ctx, GLuint name)
+is_program(struct gl_context *ctx, GLuint name)
{
struct gl_shader_program *shProg = _mesa_lookup_shader_program(ctx, name);
return shProg ? GL_TRUE : GL_FALSE;
static GLboolean
-is_shader(GLcontext *ctx, GLuint name)
+is_shader(struct gl_context *ctx, GLuint name)
{
struct gl_shader *shader = _mesa_lookup_shader(ctx, name);
return shader ? GL_TRUE : GL_FALSE;
* Attach shader to a shader program.
*/
static void
-attach_shader(GLcontext *ctx, GLuint program, GLuint shader)
+attach_shader(struct gl_context *ctx, GLuint program, GLuint shader)
{
struct gl_shader_program *shProg;
struct gl_shader *sh;
}
-static GLint
-get_attrib_location(GLcontext *ctx, GLuint program, const GLchar *name)
-{
- struct gl_shader_program *shProg
- = _mesa_lookup_shader_program_err(ctx, program, "glGetAttribLocation");
-
- if (!shProg) {
- return -1;
- }
-
- if (!shProg->LinkStatus) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glGetAttribLocation(program not linked)");
- return -1;
- }
-
- if (!name)
- return -1;
-
- if (shProg->VertexProgram) {
- const struct gl_program_parameter_list *attribs =
- shProg->VertexProgram->Base.Attributes;
- if (attribs) {
- GLint i = _mesa_lookup_parameter_index(attribs, -1, name);
- if (i >= 0) {
- return attribs->Parameters[i].StateIndexes[0];
- }
- }
- }
- return -1;
-}
-
-
-static void
-bind_attrib_location(GLcontext *ctx, GLuint program, GLuint index,
- const GLchar *name)
-{
- struct gl_shader_program *shProg;
- const GLint size = -1; /* unknown size */
- GLint i, oldIndex;
- GLenum datatype = GL_FLOAT_VEC4;
-
- shProg = _mesa_lookup_shader_program_err(ctx, program,
- "glBindAttribLocation");
- if (!shProg) {
- return;
- }
-
- if (!name)
- return;
-
- if (strncmp(name, "gl_", 3) == 0) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glBindAttribLocation(illegal name)");
- return;
- }
-
- if (index >= ctx->Const.VertexProgram.MaxAttribs) {
- _mesa_error(ctx, GL_INVALID_VALUE, "glBindAttribLocation(index)");
- return;
- }
-
- if (shProg->LinkStatus) {
- /* get current index/location for the attribute */
- oldIndex = get_attrib_location(ctx, program, name);
- }
- else {
- oldIndex = -1;
- }
-
- /* this will replace the current value if it's already in the list */
- i = _mesa_add_attribute(shProg->Attributes, name, size, datatype, index);
- if (i < 0) {
- _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindAttribLocation");
- return;
- }
-
- /*
- * Note that this attribute binding won't go into effect until
- * glLinkProgram is called again.
- */
-}
-
-
static GLuint
-create_shader(GLcontext *ctx, GLenum type)
+create_shader(struct gl_context *ctx, GLenum type)
{
struct gl_shader *sh;
GLuint name;
- name = _mesa_HashFindFreeKeyBlock(ctx->Shared->ShaderObjects, 1);
-
- switch (type) {
- case GL_FRAGMENT_SHADER:
- case GL_VERTEX_SHADER:
- case GL_GEOMETRY_SHADER_ARB:
- sh = ctx->Driver.NewShader(ctx, name, type);
- break;
- default:
+ if (!validate_shader_target(ctx, type)) {
_mesa_error(ctx, GL_INVALID_ENUM, "CreateShader(type)");
return 0;
}
+ name = _mesa_HashFindFreeKeyBlock(ctx->Shared->ShaderObjects, 1);
+ sh = ctx->Driver.NewShader(ctx, name, type);
_mesa_HashInsert(ctx->Shared->ShaderObjects, name, sh);
return name;
static GLuint
-create_shader_program(GLcontext *ctx)
+create_shader_program(struct gl_context *ctx)
{
GLuint name;
struct gl_shader_program *shProg;
* DeleteProgramARB.
*/
static void
-delete_shader_program(GLcontext *ctx, GLuint name)
+delete_shader_program(struct gl_context *ctx, GLuint name)
{
/*
* NOTE: deleting shaders/programs works a bit differently than
if (!shProg)
return;
- shProg->DeletePending = GL_TRUE;
+ if (!shProg->DeletePending) {
+ shProg->DeletePending = GL_TRUE;
- /* effectively, decr shProg's refcount */
- _mesa_reference_shader_program(ctx, &shProg, NULL);
+ /* effectively, decr shProg's refcount */
+ _mesa_reference_shader_program(ctx, &shProg, NULL);
+ }
}
static void
-delete_shader(GLcontext *ctx, GLuint shader)
+delete_shader(struct gl_context *ctx, GLuint shader)
{
struct gl_shader *sh;
static void
-detach_shader(GLcontext *ctx, GLuint program, GLuint shader)
+detach_shader(struct gl_context *ctx, GLuint program, GLuint shader)
{
struct gl_shader_program *shProg;
GLuint n;
}
-static void
-get_active_attrib(GLcontext *ctx, GLuint program, GLuint index,
- GLsizei maxLength, GLsizei *length, GLint *size,
- GLenum *type, GLchar *nameOut)
-{
- const struct gl_program_parameter_list *attribs = NULL;
- struct gl_shader_program *shProg;
-
- shProg = _mesa_lookup_shader_program_err(ctx, program, "glGetActiveAttrib");
- if (!shProg)
- return;
-
- if (shProg->VertexProgram)
- attribs = shProg->VertexProgram->Base.Attributes;
-
- if (!attribs || index >= attribs->NumParameters) {
- _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveAttrib(index)");
- return;
- }
-
- _mesa_copy_string(nameOut, maxLength, length,
- attribs->Parameters[index].Name);
-
- if (size)
- *size = attribs->Parameters[index].Size
- / _mesa_sizeof_glsl_type(attribs->Parameters[index].DataType);
-
- if (type)
- *type = attribs->Parameters[index].DataType;
-}
-
-
/**
* Return list of shaders attached to shader program.
*/
static void
-get_attached_shaders(GLcontext *ctx, GLuint program, GLsizei maxCount,
+get_attached_shaders(struct gl_context *ctx, GLuint program, GLsizei maxCount,
GLsizei *count, GLuint *obj)
{
struct gl_shader_program *shProg =
* glGetHandleARB() - return ID/name of currently bound shader program.
*/
static GLuint
-get_handle(GLcontext *ctx, GLenum pname)
+get_handle(struct gl_context *ctx, GLenum pname)
{
if (pname == GL_PROGRAM_OBJECT_ARB) {
- if (ctx->Shader.CurrentProgram)
- return ctx->Shader.CurrentProgram->Name;
+ if (ctx->Shader.ActiveProgram)
+ return ctx->Shader.ActiveProgram->Name;
else
return 0;
}
* programs (see glGetProgramivARB).
*/
static void
-get_programiv(GLcontext *ctx, GLuint program, GLenum pname, GLint *params)
+get_programiv(struct gl_context *ctx, GLuint program, GLenum pname, GLint *params)
{
- const struct gl_program_parameter_list *attribs;
struct gl_shader_program *shProg
= _mesa_lookup_shader_program(ctx, program);
return;
}
- if (shProg->VertexProgram)
- attribs = shProg->VertexProgram->Base.Attributes;
- else
- attribs = NULL;
-
switch (pname) {
case GL_DELETE_STATUS:
*params = shProg->DeletePending;
*params = shProg->NumShaders;
break;
case GL_ACTIVE_ATTRIBUTES:
- *params = attribs ? attribs->NumParameters : 0;
+ *params = _mesa_count_active_attribs(shProg);
break;
case GL_ACTIVE_ATTRIBUTE_MAX_LENGTH:
- *params = _mesa_longest_parameter_name(attribs, PROGRAM_INPUT) + 1;
+ *params = _mesa_longest_attribute_name_length(shProg);
break;
case GL_ACTIVE_UNIFORMS:
- *params = shProg->Uniforms ? shProg->Uniforms->NumUniforms : 0;
+ *params = shProg->NumUserUniformStorage;
break;
- case GL_ACTIVE_UNIFORM_MAX_LENGTH:
- *params = _mesa_longest_uniform_name(shProg->Uniforms);
- if (*params > 0)
- (*params)++; /* add one for terminating zero */
+ case GL_ACTIVE_UNIFORM_MAX_LENGTH: {
+ unsigned i;
+ GLint max_len = 0;
+
+ for (i = 0; i < shProg->NumUserUniformStorage; i++) {
+ /* Add one for the terminating NUL character.
+ */
+ const GLint len = strlen(shProg->UniformStorage[i].name) + 1;
+
+ if (len > max_len)
+ max_len = len;
+ }
+
+ *params = max_len;
break;
+ }
case GL_PROGRAM_BINARY_LENGTH_OES:
*params = 0;
break;
case GL_TRANSFORM_FEEDBACK_BUFFER_MODE:
*params = shProg->TransformFeedback.BufferMode;
break;
+#endif
+#if FEATURE_ARB_geometry_shader4
+ case GL_GEOMETRY_VERTICES_OUT_ARB:
+ *params = shProg->Geom.VerticesOut;
+ break;
+ case GL_GEOMETRY_INPUT_TYPE_ARB:
+ *params = shProg->Geom.InputType;
+ break;
+ case GL_GEOMETRY_OUTPUT_TYPE_ARB:
+ *params = shProg->Geom.OutputType;
+ break;
#endif
default:
_mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramiv(pname)");
* glGetShaderiv() - get GLSL shader state
*/
static void
-get_shaderiv(GLcontext *ctx, GLuint name, GLenum pname, GLint *params)
+get_shaderiv(struct gl_context *ctx, GLuint name, GLenum pname, GLint *params)
{
struct gl_shader *shader =
_mesa_lookup_shader_err(ctx, name, "glGetShaderiv");
static void
-get_program_info_log(GLcontext *ctx, GLuint program, GLsizei bufSize,
+get_program_info_log(struct gl_context *ctx, GLuint program, GLsizei bufSize,
GLsizei *length, GLchar *infoLog)
{
struct gl_shader_program *shProg
static void
-get_shader_info_log(GLcontext *ctx, GLuint shader, GLsizei bufSize,
+get_shader_info_log(struct gl_context *ctx, GLuint shader, GLsizei bufSize,
GLsizei *length, GLchar *infoLog)
{
struct gl_shader *sh = _mesa_lookup_shader(ctx, shader);
* Return shader source code.
*/
static void
-get_shader_source(GLcontext *ctx, GLuint shader, GLsizei maxLength,
+get_shader_source(struct gl_context *ctx, GLuint shader, GLsizei maxLength,
GLsizei *length, GLchar *sourceOut)
{
struct gl_shader *sh;
* Set/replace shader source code.
*/
static void
-shader_source(GLcontext *ctx, GLuint shader, const GLchar *source)
+shader_source(struct gl_context *ctx, GLuint shader, const GLchar *source)
{
struct gl_shader *sh;
* Compile a shader.
*/
static void
-compile_shader(GLcontext *ctx, GLuint shaderObj)
+compile_shader(struct gl_context *ctx, GLuint shaderObj)
{
struct gl_shader *sh;
+ struct gl_shader_compiler_options *options;
sh = _mesa_lookup_shader_err(ctx, shaderObj, "glCompileShader");
if (!sh)
return;
+ options = &ctx->ShaderCompilerOptions[_mesa_shader_type_to_index(sh->Type)];
+
/* set default pragma state for shader */
- sh->Pragmas = ctx->Shader.DefaultPragmas;
+ sh->Pragmas = options->DefaultPragmas;
/* this call will set the sh->CompileStatus field to indicate if
* compilation was successful.
*/
- (void) _slang_compile(ctx, sh);
+ _mesa_glsl_compile_shader(ctx, sh);
}
* Link a program's shaders.
*/
static void
-link_program(GLcontext *ctx, GLuint program)
+link_program(struct gl_context *ctx, GLuint program)
{
struct gl_shader_program *shProg;
struct gl_transform_feedback_object *obj =
if (!shProg)
return;
- if (obj->Active && shProg == ctx->Shader.CurrentProgram) {
+ if (obj->Active
+ && (shProg == ctx->Shader.CurrentVertexProgram
+ || shProg == ctx->Shader.CurrentGeometryProgram
+ || shProg == ctx->Shader.CurrentFragmentProgram)) {
_mesa_error(ctx, GL_INVALID_OPERATION,
- "glLinkProgram(transform feedback active");
+ "glLinkProgram(transform feedback active)");
return;
}
FLUSH_VERTICES(ctx, _NEW_PROGRAM);
- _slang_link(ctx, program, shProg);
+ _mesa_glsl_link_shader(ctx, shProg);
/* debug code */
if (0) {
shProg->Shaders[i]->Name,
shProg->Shaders[i]->SourceChecksum);
}
- if (shProg->VertexProgram)
- printf(" vert prog %u\n", shProg->VertexProgram->Base.Id);
- if (shProg->FragmentProgram)
- printf(" frag prog %u\n", shProg->FragmentProgram->Base.Id);
+ if (shProg->_LinkedShaders[MESA_SHADER_VERTEX])
+ printf(" vert prog %u\n",
+ shProg->_LinkedShaders[MESA_SHADER_VERTEX]->Program->Id);
+ if (shProg->_LinkedShaders[MESA_SHADER_FRAGMENT])
+ printf(" frag prog %u\n",
+ shProg->_LinkedShaders[MESA_SHADER_FRAGMENT]->Program->Id);
+ if (shProg->_LinkedShaders[MESA_SHADER_GEOMETRY])
+ printf(" geom prog %u\n",
+ shProg->_LinkedShaders[MESA_SHADER_GEOMETRY]->Program->Id);
}
/**
- * Use the named shader program for subsequent rendering.
+ * Use the named shader program for subsequent glUniform calls
*/
void
-_mesa_use_program(GLcontext *ctx, GLuint program)
+_mesa_active_program(struct gl_context *ctx, struct gl_shader_program *shProg,
+ const char *caller)
{
- struct gl_shader_program *shProg;
- struct gl_transform_feedback_object *obj =
- ctx->TransformFeedback.CurrentObject;
-
- if (obj->Active) {
+ if ((shProg != NULL) && !shProg->LinkStatus) {
_mesa_error(ctx, GL_INVALID_OPERATION,
- "glUseProgram(transform feedback active)");
+ "%s(program %u not linked)", caller, shProg->Name);
return;
}
- if (ctx->Shader.CurrentProgram &&
- ctx->Shader.CurrentProgram->Name == program) {
- /* no-op */
- return;
+ if (ctx->Shader.ActiveProgram != shProg) {
+ _mesa_reference_shader_program(ctx, &ctx->Shader.ActiveProgram, shProg);
}
+}
- if (program) {
- shProg = _mesa_lookup_shader_program_err(ctx, program, "glUseProgram");
- if (!shProg) {
- return;
+/**
+ */
+static bool
+use_shader_program(struct gl_context *ctx, GLenum type,
+ struct gl_shader_program *shProg)
+{
+ struct gl_shader_program **target;
+
+ switch (type) {
+#if FEATURE_ARB_vertex_shader
+ case GL_VERTEX_SHADER:
+ target = &ctx->Shader.CurrentVertexProgram;
+ if ((shProg == NULL)
+ || (shProg->_LinkedShaders[MESA_SHADER_VERTEX] == NULL)) {
+ shProg = NULL;
}
- if (!shProg->LinkStatus) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glUseProgram(program %u not linked)", program);
- return;
+ break;
+#endif
+#if FEATURE_ARB_geometry_shader4
+ case GL_GEOMETRY_SHADER_ARB:
+ target = &ctx->Shader.CurrentGeometryProgram;
+ if ((shProg == NULL)
+ || (shProg->_LinkedShaders[MESA_SHADER_GEOMETRY] == NULL)) {
+ shProg = NULL;
}
-
- /* debug code */
- if (ctx->Shader.Flags & GLSL_USE_PROG) {
- print_shader_info(shProg);
+ break;
+#endif
+#if FEATURE_ARB_fragment_shader
+ case GL_FRAGMENT_SHADER:
+ target = &ctx->Shader.CurrentFragmentProgram;
+ if ((shProg == NULL)
+ || (shProg->_LinkedShaders[MESA_SHADER_FRAGMENT] == NULL)) {
+ shProg = NULL;
}
- }
- else {
- shProg = NULL;
+ break;
+#endif
+ default:
+ return false;
}
- if (ctx->Shader.CurrentProgram != shProg) {
+ if (*target != shProg) {
FLUSH_VERTICES(ctx, _NEW_PROGRAM | _NEW_PROGRAM_CONSTANTS);
- _mesa_reference_shader_program(ctx, &ctx->Shader.CurrentProgram, shProg);
+
+ /* If the shader is also bound as the current rendering shader, unbind
+ * it from that binding point as well. This ensures that the correct
+ * semantics of glDeleteProgram are maintained.
+ */
+ switch (type) {
+#if FEATURE_ARB_vertex_shader
+ case GL_VERTEX_SHADER:
+ /* Empty for now. */
+ break;
+#endif
+#if FEATURE_ARB_geometry_shader4
+ case GL_GEOMETRY_SHADER_ARB:
+ /* Empty for now. */
+ break;
+#endif
+#if FEATURE_ARB_fragment_shader
+ case GL_FRAGMENT_SHADER:
+ if (*target == ctx->Shader._CurrentFragmentProgram) {
+ _mesa_reference_shader_program(ctx,
+ &ctx->Shader._CurrentFragmentProgram,
+ NULL);
+ }
+ break;
+#endif
+ }
+
+ _mesa_reference_shader_program(ctx, target, shProg);
+ return true;
}
- if (ctx->Driver.UseProgram)
- ctx->Driver.UseProgram(ctx, shProg);
+ return false;
}
-
/**
- * Validate a program's samplers.
- * Specifically, check that there aren't two samplers of different types
- * pointing to the same texture unit.
- * \return GL_TRUE if valid, GL_FALSE if invalid
+ * Use the named shader program for subsequent rendering.
*/
-static GLboolean
-validate_samplers(GLcontext *ctx, const struct gl_program *prog, char *errMsg)
-{
- static const char *targetName[] = {
- "TEXTURE_2D_ARRAY",
- "TEXTURE_1D_ARRAY",
- "TEXTURE_CUBE",
- "TEXTURE_3D",
- "TEXTURE_RECT",
- "TEXTURE_2D",
- "TEXTURE_1D",
- };
- GLint targetUsed[MAX_TEXTURE_IMAGE_UNITS];
- GLbitfield samplersUsed = prog->SamplersUsed;
- GLuint i;
-
- assert(Elements(targetName) == NUM_TEXTURE_TARGETS);
-
- if (samplersUsed == 0x0)
- return GL_TRUE;
-
- for (i = 0; i < Elements(targetUsed); i++)
- targetUsed[i] = -1;
-
- /* walk over bits which are set in 'samplers' */
- while (samplersUsed) {
- GLuint unit;
- gl_texture_index target;
- GLint sampler = _mesa_ffs(samplersUsed) - 1;
- assert(sampler >= 0);
- assert(sampler < MAX_TEXTURE_IMAGE_UNITS);
- unit = prog->SamplerUnits[sampler];
- target = prog->SamplerTargets[sampler];
- if (targetUsed[unit] != -1 && targetUsed[unit] != target) {
- _mesa_snprintf(errMsg, 100,
- "Texture unit %d is accessed both as %s and %s",
- unit, targetName[targetUsed[unit]], targetName[target]);
- return GL_FALSE;
- }
- targetUsed[unit] = target;
- samplersUsed ^= (1 << sampler);
- }
+void
+_mesa_use_program(struct gl_context *ctx, struct gl_shader_program *shProg)
+{
+ 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);
+ _mesa_active_program(ctx, shProg, "glUseProgram");
- return GL_TRUE;
+ if (ctx->Driver.UseProgram)
+ ctx->Driver.UseProgram(ctx, shProg);
}
* \return GL_TRUE if valid, GL_FALSE if invalid (and set errMsg)
*/
static GLboolean
-validate_shader_program(GLcontext *ctx,
- const struct gl_shader_program *shProg,
+validate_shader_program(const struct gl_shader_program *shProg,
char *errMsg)
{
- const struct gl_vertex_program *vp = shProg->VertexProgram;
- const struct gl_fragment_program *fp = shProg->FragmentProgram;
-
if (!shProg->LinkStatus) {
return GL_FALSE;
}
* Check: any two active samplers in the current program object are of
* different types, but refer to the same texture image unit,
*/
- if (vp && !validate_samplers(ctx, &vp->Base, errMsg)) {
- return GL_FALSE;
- }
- if (fp && !validate_samplers(ctx, &fp->Base, errMsg)) {
+ if (!_mesa_sampler_uniforms_are_valid(shProg, errMsg, 100))
return GL_FALSE;
- }
return GL_TRUE;
}
* Called via glValidateProgram()
*/
static void
-validate_program(GLcontext *ctx, GLuint program)
+validate_program(struct gl_context *ctx, GLuint program)
{
struct gl_shader_program *shProg;
- char errMsg[100];
+ char errMsg[100] = "";
shProg = _mesa_lookup_shader_program_err(ctx, program, "glValidateProgram");
if (!shProg) {
return;
}
- shProg->Validated = validate_shader_program(ctx, shProg, errMsg);
+ shProg->Validated = validate_shader_program(shProg, errMsg);
if (!shProg->Validated) {
/* update info log */
if (shProg->InfoLog) {
- free(shProg->InfoLog);
+ ralloc_free(shProg->InfoLog);
}
- shProg->InfoLog = _mesa_strdup(errMsg);
+ shProg->InfoLog = ralloc_strdup(shProg, errMsg);
}
}
}
-void GLAPIENTRY
-_mesa_BindAttribLocationARB(GLhandleARB program, GLuint index,
- const GLcharARB *name)
-{
- GET_CURRENT_CONTEXT(ctx);
- bind_attrib_location(ctx, program, index, name);
-}
-
-
void GLAPIENTRY
_mesa_CompileShaderARB(GLhandleARB shaderObj)
{
GET_CURRENT_CONTEXT(ctx);
+ if (MESA_VERBOSE & VERBOSE_API)
+ _mesa_debug(ctx, "glCompileShader %u\n", shaderObj);
compile_shader(ctx, shaderObj);
}
_mesa_CreateShader(GLenum type)
{
GET_CURRENT_CONTEXT(ctx);
+ if (MESA_VERBOSE & VERBOSE_API)
+ _mesa_debug(ctx, "glCreateShader %s\n", _mesa_lookup_enum_by_nr(type));
return create_shader(ctx, type);
}
_mesa_CreateProgram(void)
{
GET_CURRENT_CONTEXT(ctx);
+ if (MESA_VERBOSE & VERBOSE_API)
+ _mesa_debug(ctx, "glCreateProgram\n");
return create_shader_program(ctx);
}
void GLAPIENTRY
_mesa_DeleteObjectARB(GLhandleARB obj)
{
+ if (MESA_VERBOSE & VERBOSE_API) {
+ GET_CURRENT_CONTEXT(ctx);
+ _mesa_debug(ctx, "glDeleteObjectARB(%u)\n", obj);
+ }
+
if (obj) {
GET_CURRENT_CONTEXT(ctx);
+ FLUSH_VERTICES(ctx, 0);
if (is_program(ctx, obj)) {
delete_shader_program(ctx, obj);
}
{
if (name) {
GET_CURRENT_CONTEXT(ctx);
+ FLUSH_VERTICES(ctx, 0);
delete_shader_program(ctx, name);
}
}
{
if (name) {
GET_CURRENT_CONTEXT(ctx);
+ FLUSH_VERTICES(ctx, 0);
delete_shader(ctx, name);
}
}
}
-void GLAPIENTRY
-_mesa_GetActiveAttribARB(GLhandleARB program, GLuint index,
- GLsizei maxLength, GLsizei * length, GLint * size,
- GLenum * type, GLcharARB * name)
-{
- GET_CURRENT_CONTEXT(ctx);
- get_active_attrib(ctx, program, index, maxLength, length, size, type, name);
-}
-
-
void GLAPIENTRY
_mesa_GetAttachedObjectsARB(GLhandleARB container, GLsizei maxCount,
GLsizei * count, GLhandleARB * obj)
}
-GLint GLAPIENTRY
-_mesa_GetAttribLocationARB(GLhandleARB program, const GLcharARB * name)
-{
- GET_CURRENT_CONTEXT(ctx);
- return get_attrib_location(ctx, program, name);
-}
-
-
void GLAPIENTRY
_mesa_GetInfoLogARB(GLhandleARB object, GLsizei maxLength, GLsizei * length,
GLcharARB * infoLog)
for (i = 0; i < count; i++) {
if (string[i] == NULL) {
free((GLvoid *) offsets);
- _mesa_error(ctx, GL_INVALID_OPERATION, "glShaderSourceARB(null string)");
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glShaderSourceARB(null string)");
return;
}
if (length == NULL || length[i] < 0)
free(source);
source = newSource;
}
- }
+ }
shader_source(ctx, shaderObj, source);
_mesa_UseProgramObjectARB(GLhandleARB program)
{
GET_CURRENT_CONTEXT(ctx);
- FLUSH_VERTICES(ctx, _NEW_PROGRAM);
- _mesa_use_program(ctx, program);
+ struct gl_shader_program *shProg;
+ struct gl_transform_feedback_object *obj =
+ ctx->TransformFeedback.CurrentObject;
+
+ ASSERT_OUTSIDE_BEGIN_END(ctx);
+
+ if (obj->Active && !obj->Paused) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glUseProgram(transform feedback active)");
+ return;
+ }
+
+ if (program) {
+ shProg = _mesa_lookup_shader_program_err(ctx, program, "glUseProgram");
+ if (!shProg) {
+ return;
+ }
+ if (!shProg->LinkStatus) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glUseProgram(program %u not linked)", program);
+ return;
+ }
+
+ /* debug code */
+ if (ctx->Shader.Flags & GLSL_USE_PROG) {
+ print_shader_info(shProg);
+ }
+ }
+ else {
+ shProg = NULL;
+ }
+
+ _mesa_use_program(ctx, shProg);
}
_mesa_GetShaderPrecisionFormat(GLenum shadertype, GLenum precisiontype,
GLint* range, GLint* precision)
{
+ const struct gl_program_constants *limits;
+ const struct gl_precision *p;
GET_CURRENT_CONTEXT(ctx);
- _mesa_error(ctx, GL_INVALID_OPERATION, __FUNCTION__);
+
+ switch (shadertype) {
+ case GL_VERTEX_SHADER:
+ limits = &ctx->Const.VertexProgram;
+ break;
+ case GL_FRAGMENT_SHADER:
+ limits = &ctx->Const.FragmentProgram;
+ break;
+ default:
+ _mesa_error(ctx, GL_INVALID_ENUM,
+ "glGetShaderPrecisionFormat(shadertype)");
+ return;
+ }
+
+ switch (precisiontype) {
+ case GL_LOW_FLOAT:
+ p = &limits->LowFloat;
+ break;
+ case GL_MEDIUM_FLOAT:
+ p = &limits->MediumFloat;
+ break;
+ case GL_HIGH_FLOAT:
+ p = &limits->HighFloat;
+ break;
+ case GL_LOW_INT:
+ p = &limits->LowInt;
+ break;
+ case GL_MEDIUM_INT:
+ p = &limits->MediumInt;
+ break;
+ case GL_HIGH_INT:
+ p = &limits->HighInt;
+ break;
+ default:
+ _mesa_error(ctx, GL_INVALID_ENUM,
+ "glGetShaderPrecisionFormat(precisiontype)");
+ return;
+ }
+
+ range[0] = p->RangeMin;
+ range[1] = p->RangeMax;
+ precision[0] = p->Precision;
}
void GLAPIENTRY
_mesa_ReleaseShaderCompiler(void)
{
- GET_CURRENT_CONTEXT(ctx);
- _mesa_error(ctx, GL_INVALID_OPERATION, __FUNCTION__);
+ _mesa_destroy_shader_compiler_caches();
}
const void* binary, GLint length)
{
GET_CURRENT_CONTEXT(ctx);
+ (void) n;
+ (void) shaders;
+ (void) binaryformat;
+ (void) binary;
+ (void) length;
_mesa_error(ctx, GL_INVALID_OPERATION, __FUNCTION__);
}
#endif /* FEATURE_ES2 */
+
#if FEATURE_ARB_geometry_shader4
-/**
- * Look up a geometry program given a shader ID.
- * An error will be recorded if the ID is invalid, etc.
- */
-static struct gl_geometry_program *
-_mesa_geometry_from_shader(GLuint program)
+void GLAPIENTRY
+_mesa_ProgramParameteriARB(GLuint program, GLenum pname, GLint value)
{
+ struct gl_shader_program *shProg;
GET_CURRENT_CONTEXT(ctx);
- struct gl_shader_program *shProg = NULL;
- struct gl_shader *sh = NULL;
- GLuint i;
- shProg = _mesa_lookup_shader_program(ctx, program);
-
- if (!ctx->Extensions.ARB_geometry_shader4) {
- _mesa_error(ctx, GL_INVALID_OPERATION, "glProgramParameteriARB");
- return NULL;
- }
-
- if (!shProg) {
- _mesa_error(ctx, GL_INVALID_ENUM, "glProgramParameteriARB");
- return NULL;
- }
- for (i = 0; i < shProg->NumShaders; ++i) {
- if (shProg->Shaders[i]->Type == GL_GEOMETRY_SHADER_ARB) {
- sh = shProg->Shaders[i];
- }
- }
- if (!sh || !sh->Program) {
- _mesa_error(ctx, GL_INVALID_ENUM, "glProgramParameteriARB");
- return NULL;
- }
- return (struct gl_geometry_program *) sh->Program;
-}
-
-static void
-_mesa_program_parameteri(GLcontext *ctx, GLuint program,
- GLenum pname, GLint value)
-{
- struct gl_geometry_program *gprog;
ASSERT_OUTSIDE_BEGIN_END(ctx);
- gprog = _mesa_geometry_from_shader(program);
- if (!gprog) {
- /* error will have been recorded */
+ shProg = _mesa_lookup_shader_program_err(ctx, program,
+ "glProgramParameteri");
+ if (!shProg)
return;
- }
switch (pname) {
case GL_GEOMETRY_VERTICES_OUT_ARB:
if (value < 1 ||
- value > ctx->Const.GeometryProgram.MaxGeometryOutputVertices) {
+ (unsigned) value > ctx->Const.MaxGeometryOutputVertices) {
_mesa_error(ctx, GL_INVALID_VALUE,
"glProgramParameteri(GL_GEOMETRY_VERTICES_OUT_ARB=%d",
value);
return;
}
- gprog->VerticesOut = value;
+ shProg->Geom.VerticesOut = value;
break;
case GL_GEOMETRY_INPUT_TYPE_ARB:
switch (value) {
case GL_LINES_ADJACENCY_ARB:
case GL_TRIANGLES:
case GL_TRIANGLES_ADJACENCY_ARB:
- gprog->InputType = value;
+ shProg->Geom.InputType = value;
break;
default:
_mesa_error(ctx, GL_INVALID_VALUE,
case GL_POINTS:
case GL_LINE_STRIP:
case GL_TRIANGLE_STRIP:
- gprog->OutputType = value;
+ shProg->Geom.OutputType = value;
break;
default:
_mesa_error(ctx, GL_INVALID_VALUE,
}
}
+#endif
+
+void
+_mesa_use_shader_program(struct gl_context *ctx, GLenum type,
+ struct gl_shader_program *shProg)
+{
+ use_shader_program(ctx, type, shProg);
+
+ if (ctx->Driver.UseProgram)
+ ctx->Driver.UseProgram(ctx, shProg);
+}
+
+void GLAPIENTRY
+_mesa_UseShaderProgramEXT(GLenum type, GLuint program)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ struct gl_shader_program *shProg = NULL;
+
+ ASSERT_OUTSIDE_BEGIN_END(ctx);
+
+ if (!validate_shader_target(ctx, type)) {
+ _mesa_error(ctx, GL_INVALID_ENUM, "glUseShaderProgramEXT(type)");
+ return;
+ }
+
+ if (ctx->TransformFeedback.CurrentObject->Active &&
+ !ctx->TransformFeedback.CurrentObject->Paused) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glUseShaderProgramEXT(transform feedback is active)");
+ return;
+ }
+
+ if (program) {
+ shProg = _mesa_lookup_shader_program_err(ctx, program,
+ "glUseShaderProgramEXT");
+ if (shProg == NULL)
+ return;
+
+ if (!shProg->LinkStatus) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glUseShaderProgramEXT(program not linked)");
+ return;
+ }
+ }
+
+ _mesa_use_shader_program(ctx, type, shProg);
+}
+
void GLAPIENTRY
-_mesa_ProgramParameteriARB(GLuint program, GLenum pname,
- GLint value)
+_mesa_ActiveProgramEXT(GLuint program)
{
GET_CURRENT_CONTEXT(ctx);
- _mesa_program_parameteri(ctx, program, pname, value);
+ struct gl_shader_program *shProg = (program != 0)
+ ? _mesa_lookup_shader_program_err(ctx, program, "glActiveProgramEXT")
+ : NULL;
+
+ _mesa_active_program(ctx, shProg, "glActiveProgramEXT");
+ return;
}
+GLuint GLAPIENTRY
+_mesa_CreateShaderProgramEXT(GLenum type, const GLchar *string)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ const GLuint shader = create_shader(ctx, type);
+ GLuint program = 0;
+
+ if (shader) {
+ shader_source(ctx, shader, _mesa_strdup(string));
+ compile_shader(ctx, shader);
+
+ program = create_shader_program(ctx);
+ if (program) {
+ struct gl_shader_program *shProg;
+ struct gl_shader *sh;
+ GLint compiled = GL_FALSE;
+
+ shProg = _mesa_lookup_shader_program(ctx, program);
+ sh = _mesa_lookup_shader(ctx, shader);
+
+ get_shaderiv(ctx, shader, GL_COMPILE_STATUS, &compiled);
+ if (compiled) {
+ attach_shader(ctx, program, shader);
+ link_program(ctx, program);
+ detach_shader(ctx, program, shader);
+
+#if 0
+ /* Possibly... */
+ if (active-user-defined-varyings-in-linked-program) {
+ append-error-to-info-log;
+ shProg->LinkStatus = GL_FALSE;
+ }
#endif
+ }
+
+ ralloc_strcat(&shProg->InfoLog, sh->InfoLog);
+ }
+
+ delete_shader(ctx, shader);
+ }
+
+ return program;
+}
/**
* Plug in shader-related functions into API dispatch table.
void
_mesa_init_shader_dispatch(struct _glapi_table *exec)
{
+#if FEATURE_GL
/* GL_ARB_vertex/fragment_shader */
SET_DeleteObjectARB(exec, _mesa_DeleteObjectARB);
SET_GetHandleARB(exec, _mesa_GetHandleARB);
#if FEATURE_ARB_geometry_shader4
SET_ProgramParameteriARB(exec, _mesa_ProgramParameteriARB);
#endif
+
+ SET_UseShaderProgramEXT(exec, _mesa_UseShaderProgramEXT);
+ SET_ActiveProgramEXT(exec, _mesa_ActiveProgramEXT);
+ SET_CreateShaderProgramEXT(exec, _mesa_CreateShaderProgramEXT);
+
+ /* GL_EXT_gpu_shader4 / GL 3.0 */
+ SET_BindFragDataLocationEXT(exec, _mesa_BindFragDataLocation);
+ SET_GetFragDataLocationEXT(exec, _mesa_GetFragDataLocation);
+
+ /* GL_ARB_ES2_compatibility */
+ SET_ReleaseShaderCompiler(exec, _mesa_ReleaseShaderCompiler);
+ SET_GetShaderPrecisionFormat(exec, _mesa_GetShaderPrecisionFormat);
+
+ /* GL_ARB_blend_func_extended */
+ SET_BindFragDataLocationIndexed(exec, _mesa_BindFragDataLocationIndexed);
+ SET_GetFragDataIndex(exec, _mesa_GetFragDataIndex);
+#endif /* FEATURE_GL */
}