summaryrefslogtreecommitdiffstats
path: root/src/mesa/main/shaderapi.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/mesa/main/shaderapi.c')
-rw-r--r--src/mesa/main/shaderapi.c315
1 files changed, 260 insertions, 55 deletions
diff --git a/src/mesa/main/shaderapi.c b/src/mesa/main/shaderapi.c
index c25d2a19747..e6c7f7aa3f8 100644
--- a/src/mesa/main/shaderapi.c
+++ b/src/mesa/main/shaderapi.c
@@ -47,7 +47,7 @@
#include "program/prog_parameter.h"
#include "program/prog_uniform.h"
#include "talloc.h"
-
+#include <stdbool.h>
/** Define this to enable shader substitution (see below) */
#define SHADER_SUBST 0
@@ -89,7 +89,7 @@ get_shader_flags(void)
* 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.
@@ -114,9 +114,14 @@ _mesa_init_shader_state(GLcontext *ctx)
* Free the per-context shader-related state.
*/
void
-_mesa_free_shader_state(GLcontext *ctx)
+_mesa_free_shader_state(struct gl_context *ctx)
{
- _mesa_reference_shader_program(ctx, &ctx->Shader.CurrentProgram, NULL);
+ _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.ActiveProgram, NULL);
}
@@ -202,6 +207,35 @@ _mesa_copy_string(GLchar *dst, GLsizei maxLength,
/**
+ * 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().
*/
@@ -221,7 +255,7 @@ longest_feedback_varying_name(const struct gl_shader_program *shProg)
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;
@@ -229,7 +263,7 @@ is_program(GLcontext *ctx, GLuint name)
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;
@@ -240,7 +274,7 @@ is_shader(GLcontext *ctx, GLuint name)
* 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;
@@ -287,7 +321,7 @@ attach_shader(GLcontext *ctx, GLuint program, GLuint shader)
static GLint
-get_attrib_location(GLcontext *ctx, GLuint program, const GLchar *name)
+get_attrib_location(struct gl_context *ctx, GLuint program, const GLchar *name)
{
struct gl_shader_program *shProg
= _mesa_lookup_shader_program_err(ctx, program, "glGetAttribLocation");
@@ -320,7 +354,7 @@ get_attrib_location(GLcontext *ctx, GLuint program, const GLchar *name)
static void
-bind_attrib_location(GLcontext *ctx, GLuint program, GLuint index,
+bind_attrib_location(struct gl_context *ctx, GLuint program, GLuint index,
const GLchar *name)
{
struct gl_shader_program *shProg;
@@ -371,24 +405,18 @@ bind_attrib_location(GLcontext *ctx, GLuint program, GLuint index,
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;
@@ -396,7 +424,7 @@ create_shader(GLcontext *ctx, GLenum type)
static GLuint
-create_shader_program(GLcontext *ctx)
+create_shader_program(struct gl_context *ctx)
{
GLuint name;
struct gl_shader_program *shProg;
@@ -418,7 +446,7 @@ create_shader_program(GLcontext *ctx)
* 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
@@ -442,7 +470,7 @@ delete_shader_program(GLcontext *ctx, GLuint name)
static void
-delete_shader(GLcontext *ctx, GLuint shader)
+delete_shader(struct gl_context *ctx, GLuint shader)
{
struct gl_shader *sh;
@@ -458,7 +486,7 @@ delete_shader(GLcontext *ctx, GLuint shader)
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;
@@ -526,7 +554,7 @@ detach_shader(GLcontext *ctx, GLuint program, GLuint shader)
static void
-get_active_attrib(GLcontext *ctx, GLuint program, GLuint index,
+get_active_attrib(struct gl_context *ctx, GLuint program, GLuint index,
GLsizei maxLength, GLsizei *length, GLint *size,
GLenum *type, GLchar *nameOut)
{
@@ -561,7 +589,7 @@ get_active_attrib(GLcontext *ctx, GLuint program, GLuint index,
* 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 =
@@ -581,11 +609,11 @@ get_attached_shaders(GLcontext *ctx, GLuint program, GLsizei maxCount,
* 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;
}
@@ -602,7 +630,7 @@ get_handle(GLcontext *ctx, GLenum pname)
* 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
@@ -684,7 +712,7 @@ get_programiv(GLcontext *ctx, GLuint program, GLenum pname, GLint *params)
* 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");
@@ -717,7 +745,7 @@ get_shaderiv(GLcontext *ctx, GLuint name, GLenum pname, GLint *params)
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
@@ -731,7 +759,7 @@ get_program_info_log(GLcontext *ctx, GLuint program, GLsizei bufSize,
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);
@@ -747,7 +775,7 @@ get_shader_info_log(GLcontext *ctx, GLuint shader, GLsizei bufSize,
* 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;
@@ -763,7 +791,7 @@ get_shader_source(GLcontext *ctx, GLuint shader, GLsizei maxLength,
* 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;
@@ -787,7 +815,7 @@ shader_source(GLcontext *ctx, GLuint shader, const GLchar *source)
* 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;
@@ -812,7 +840,7 @@ compile_shader(GLcontext *ctx, GLuint shaderObj)
* 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 =
@@ -822,7 +850,10 @@ link_program(GLcontext *ctx, GLuint program)
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");
return;
@@ -885,14 +916,81 @@ print_shader_info(const struct gl_shader_program *shProg)
/**
+ * Use the named shader program for subsequent glUniform calls
+ */
+static void
+active_program(struct gl_context *ctx, struct gl_shader_program *shProg,
+ const char *caller)
+{
+ if ((shProg != NULL) && !shProg->LinkStatus) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "%s(program %u not linked)", caller, shProg->Name);
+ return;
+ }
+
+ if (ctx->Shader.ActiveProgram != shProg) {
+ _mesa_reference_shader_program(ctx, &ctx->Shader.ActiveProgram, shProg);
+ }
+}
+
+/**
+ */
+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;
+ }
+ 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;
+ }
+ 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;
+ }
+ break;
+#endif
+ default:
+ return false;
+ }
+
+ if (*target != shProg) {
+ _mesa_reference_shader_program(ctx, target, shProg);
+ return true;
+ }
+
+ return false;
+}
+
+/**
* Use the named shader program for subsequent rendering.
*/
void
-_mesa_use_program(GLcontext *ctx, GLuint program)
+_mesa_use_program(struct gl_context *ctx, GLuint program)
{
struct gl_shader_program *shProg;
struct gl_transform_feedback_object *obj =
ctx->TransformFeedback.CurrentObject;
+ bool changed = false;
if (obj->Active) {
_mesa_error(ctx, GL_INVALID_OPERATION,
@@ -900,12 +998,6 @@ _mesa_use_program(GLcontext *ctx, GLuint program)
return;
}
- if (ctx->Shader.CurrentProgram &&
- ctx->Shader.CurrentProgram->Name == program) {
- /* no-op */
- return;
- }
-
if (program) {
shProg = _mesa_lookup_shader_program_err(ctx, program, "glUseProgram");
if (!shProg) {
@@ -926,9 +1018,15 @@ _mesa_use_program(GLcontext *ctx, GLuint program)
shProg = NULL;
}
- if (ctx->Shader.CurrentProgram != shProg) {
+ changed = use_shader_program(ctx, GL_VERTEX_SHADER, shProg);
+ changed = use_shader_program(ctx, GL_GEOMETRY_SHADER_ARB, shProg)
+ || changed;
+ changed = use_shader_program(ctx, GL_FRAGMENT_SHADER, shProg)
+ || changed;
+ active_program(ctx, shProg, "glUseProgram");
+
+ if (changed) {
FLUSH_VERTICES(ctx, _NEW_PROGRAM | _NEW_PROGRAM_CONSTANTS);
- _mesa_reference_shader_program(ctx, &ctx->Shader.CurrentProgram, shProg);
}
if (ctx->Driver.UseProgram)
@@ -943,7 +1041,7 @@ _mesa_use_program(GLcontext *ctx, GLuint program)
* \return GL_TRUE if valid, GL_FALSE if invalid
*/
static GLboolean
-validate_samplers(GLcontext *ctx, const struct gl_program *prog, char *errMsg)
+validate_samplers(const struct gl_program *prog, char *errMsg)
{
static const char *targetName[] = {
"TEXTURE_2D_ARRAY",
@@ -975,7 +1073,7 @@ validate_samplers(GLcontext *ctx, const struct gl_program *prog, char *errMsg)
assert(sampler < MAX_TEXTURE_IMAGE_UNITS);
unit = prog->SamplerUnits[sampler];
target = prog->SamplerTargets[sampler];
- if (targetUsed[unit] != -1 && targetUsed[unit] != target) {
+ if (targetUsed[unit] != -1 && targetUsed[unit] != (int) target) {
_mesa_snprintf(errMsg, 100,
"Texture unit %d is accessed both as %s and %s",
unit, targetName[targetUsed[unit]], targetName[target]);
@@ -995,8 +1093,7 @@ validate_samplers(GLcontext *ctx, const struct gl_program *prog, char *errMsg)
* \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;
@@ -1026,10 +1123,10 @@ validate_shader_program(GLcontext *ctx,
* 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)) {
+ if (vp && !validate_samplers(&vp->Base, errMsg)) {
return GL_FALSE;
}
- if (fp && !validate_samplers(ctx, &fp->Base, errMsg)) {
+ if (fp && !validate_samplers(&fp->Base, errMsg)) {
return GL_FALSE;
}
@@ -1041,7 +1138,7 @@ validate_shader_program(GLcontext *ctx,
* 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];
@@ -1051,7 +1148,7 @@ validate_program(GLcontext *ctx, GLuint program)
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) {
@@ -1498,6 +1595,10 @@ _mesa_GetShaderPrecisionFormat(GLenum shadertype, GLenum precisiontype,
GLint* range, GLint* precision)
{
GET_CURRENT_CONTEXT(ctx);
+ (void) shadertype;
+ (void) precisiontype;
+ (void) range;
+ (void) precision;
_mesa_error(ctx, GL_INVALID_OPERATION, __FUNCTION__);
}
@@ -1515,6 +1616,11 @@ _mesa_ShaderBinary(GLint n, const GLuint* shaders, GLenum binaryformat,
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__);
}
@@ -1540,7 +1646,7 @@ _mesa_ProgramParameteriARB(GLuint program, GLenum pname,
switch (pname) {
case GL_GEOMETRY_VERTICES_OUT_ARB:
if (value < 1 ||
- value > ctx->Const.GeometryProgram.MaxGeometryOutputVertices) {
+ (unsigned) value > ctx->Const.GeometryProgram.MaxGeometryOutputVertices) {
_mesa_error(ctx, GL_INVALID_VALUE,
"glProgramParameteri(GL_GEOMETRY_VERTICES_OUT_ARB=%d",
value);
@@ -1587,6 +1693,101 @@ _mesa_ProgramParameteriARB(GLuint program, GLenum pname,
#endif
+void GLAPIENTRY
+_mesa_UseShaderProgramEXT(GLenum type, GLuint program)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ struct gl_shader_program *shProg = NULL;
+ bool changed = false;
+
+ if (!validate_shader_target(ctx, type)) {
+ _mesa_error(ctx, GL_INVALID_ENUM, "glUseShaderProgramEXT(type)");
+ return;
+ }
+
+ if (ctx->TransformFeedback.CurrentObject->Active) {
+ _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;
+ }
+ }
+
+ changed = use_shader_program(ctx, type, shProg);
+ if (changed)
+ FLUSH_VERTICES(ctx, _NEW_PROGRAM | _NEW_PROGRAM_CONSTANTS);
+
+ if (ctx->Driver.UseProgram)
+ ctx->Driver.UseProgram(ctx, shProg);
+ return;
+}
+
+void GLAPIENTRY
+_mesa_ActiveProgramEXT(GLuint program)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ struct gl_shader_program *shProg = (program != 0)
+ ? _mesa_lookup_shader_program_err(ctx, program, "glActiveProgramEXT")
+ : NULL;
+
+ 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
+ }
+
+ shProg->InfoLog = talloc_strdup_append(shProg->InfoLog, sh->InfoLog);
+ }
+
+ delete_shader(ctx, shader);
+ }
+
+ return program;
+}
/**
* Plug in shader-related functions into API dispatch table.
@@ -1637,6 +1838,10 @@ _mesa_init_shader_dispatch(struct _glapi_table *exec)
#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);
#endif /* FEATURE_GL */
}