#include "main/hash.h"
#include "main/hash_table.h"
#include "main/mtypes.h"
+#include "main/pipelineobj.h"
#include "main/shaderapi.h"
#include "main/shaderobj.h"
#include "main/transformfeedback.h"
/**
* Return mask of GLSL_x flags by examining the MESA_GLSL env var.
*/
-static GLbitfield
-get_shader_flags(void)
+GLbitfield
+_mesa_get_shader_flags(void)
{
GLbitfield flags = 0x0;
const char *env = _mesa_getenv("MESA_GLSL");
for (sh = 0; sh < MESA_SHADER_STAGES; ++sh)
memcpy(&ctx->ShaderCompilerOptions[sh], &options, sizeof(options));
- ctx->Shader.Flags = get_shader_flags();
+ ctx->Shader.Flags = _mesa_get_shader_flags();
+
+ /* Extended for ARB_separate_shader_objects */
+ ctx->Shader.RefCount = 1;
+ mtx_init(&ctx->Shader.Mutex, mtx_plain);
}
_mesa_reference_shader_program(ctx, &ctx->Shader._CurrentFragmentProgram,
NULL);
_mesa_reference_shader_program(ctx, &ctx->Shader.ActiveProgram, NULL);
+
+ /* Extended for ARB_separate_shader_objects */
+ _mesa_reference_pipeline_object(ctx, &ctx->_Shader, NULL);
+
+ assert(ctx->Shader.RefCount == 1);
+ mtx_destroy(&ctx->Shader.Mutex);
}
get_handle(struct gl_context *ctx, GLenum pname)
{
if (pname == GL_PROGRAM_OBJECT_ARB) {
- if (ctx->Shader.ActiveProgram)
- return ctx->Shader.ActiveProgram->Name;
+ if (ctx->_Shader->ActiveProgram)
+ return ctx->_Shader->ActiveProgram->Name;
else
return 0;
}
params[i] = shProg->Comp.LocalSize[i];
return;
}
+ case GL_PROGRAM_SEPARABLE:
+ *params = shProg->SeparateShader;
+ return;
default:
break;
}
/**
* Set/replace shader source code. A helper function used by
- * glShaderSource[ARB] and glCreateShaderProgramEXT.
+ * glShaderSource[ARB].
*/
static void
shader_source(struct gl_context *ctx, GLuint shader, const GLchar *source)
*/
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 (ctx->_Shader->Flags & GLSL_DUMP) {
+ fprintf(stderr, "GLSL source for %s shader %d:\n",
+ _mesa_shader_stage_to_string(sh->Stage), sh->Name);
+ fprintf(stderr, "%s\n", sh->Source);
+ fflush(stderr);
}
/* this call will set the shader->CompileStatus field to indicate if
*/
_mesa_glsl_compile_shader(ctx, sh, false, false);
- if (ctx->Shader.Flags & GLSL_LOG) {
+ if (ctx->_Shader->Flags & GLSL_LOG) {
_mesa_write_shader_to_file(sh);
}
- if (ctx->Shader.Flags & GLSL_DUMP) {
+ 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");
+ fprintf(stderr, "GLSL IR for shader %d:\n", sh->Name);
+ _mesa_print_ir(stderr, sh->ir, NULL);
+ fprintf(stderr, "\n\n");
} else {
- printf("GLSL shader %d failed to compile.\n", sh->Name);
+ fprintf(stderr, "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);
+ fprintf(stderr, "GLSL shader %d info log:\n", sh->Name);
+ fprintf(stderr, "%s\n", sh->InfoLog);
}
+ fflush(stderr);
}
}
if (!sh->CompileStatus) {
- if (ctx->Shader.Flags & GLSL_DUMP_ON_ERROR) {
+ 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);
fflush(stderr);
}
- if (ctx->Shader.Flags & GLSL_REPORT_ERRORS) {
+ if (ctx->_Shader->Flags & GLSL_REPORT_ERRORS) {
_mesa_debug(ctx, "Error compiling shader %u:\n%s\n",
sh->Name, sh->InfoLog);
}
_mesa_glsl_link_shader(ctx, shProg);
if (shProg->LinkStatus == GL_FALSE &&
- (ctx->Shader.Flags & GLSL_REPORT_ERRORS)) {
+ (ctx->_Shader->Flags & GLSL_REPORT_ERRORS)) {
_mesa_debug(ctx, "Error linking program %u:\n%s\n",
shProg->Name, shProg->InfoLog);
}
*/
static void
use_shader_program(struct gl_context *ctx, GLenum type,
- struct gl_shader_program *shProg)
+ struct gl_shader_program *shProg,
+ struct gl_pipeline_object *shTarget)
{
struct gl_shader_program **target;
gl_shader_stage stage = _mesa_shader_enum_to_shader_stage(type);
- target = &ctx->Shader.CurrentProgram[stage];
+ target = &shTarget->CurrentProgram[stage];
if ((shProg == NULL) || (shProg->_LinkedShaders[stage] == NULL))
shProg = NULL;
if (*target != shProg) {
- FLUSH_VERTICES(ctx, _NEW_PROGRAM | _NEW_PROGRAM_CONSTANTS);
+ /* Program is current, flush it */
+ if (shTarget == ctx->_Shader) {
+ FLUSH_VERTICES(ctx, _NEW_PROGRAM | _NEW_PROGRAM_CONSTANTS);
+ }
/* If the shader is also bound as the current rendering shader, unbind
* it from that binding point as well. This ensures that the correct
/* Empty for now. */
break;
case GL_FRAGMENT_SHADER:
- if (*target == ctx->Shader._CurrentFragmentProgram) {
+ if (*target == ctx->_Shader->_CurrentFragmentProgram) {
_mesa_reference_shader_program(ctx,
- &ctx->Shader._CurrentFragmentProgram,
+ &ctx->_Shader->_CurrentFragmentProgram,
NULL);
}
break;
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);
- use_shader_program(ctx, GL_COMPUTE_SHADER, shProg);
+ use_shader_program(ctx, GL_VERTEX_SHADER, shProg, &ctx->Shader);
+ use_shader_program(ctx, GL_GEOMETRY_SHADER_ARB, shProg, &ctx->Shader);
+ use_shader_program(ctx, GL_FRAGMENT_SHADER, shProg, &ctx->Shader);
+ use_shader_program(ctx, GL_COMPUTE_SHADER, shProg, &ctx->Shader);
_mesa_active_program(ctx, shProg, "glUseProgram");
if (ctx->Driver.UseProgram)
static GLcharARB *
read_shader(const char *fname)
{
- const int max = 50*1000;
+ int shader_size = 0;
FILE *f = fopen(fname, "r");
GLcharARB *buffer, *shader;
int len;
return NULL;
}
- buffer = malloc(max);
- len = fread(buffer, 1, max, f);
+ /* allocate enough room for the entire shader */
+ fseek(f, 0, SEEK_END);
+ shader_size = ftell(f);
+ rewind(f);
+ assert(shader_size);
+
+ /* add one for terminating zero */
+ shader_size++;
+
+ buffer = malloc(shader_size);
+ assert(buffer);
+
+ len = fread(buffer, 1, shader_size, f);
buffer[len] = 0;
fclose(f);
}
/* debug code */
- if (ctx->Shader.Flags & GLSL_USE_PROG) {
+ if (ctx->_Shader->Flags & GLSL_USE_PROG) {
print_shader_info(shProg);
}
}
shProg = NULL;
}
- _mesa_use_program(ctx, shProg);
+ /* The ARB_separate_shader_object spec says:
+ *
+ * "The executable code for an individual shader stage is taken from
+ * the current program for that stage. If there is a current program
+ * object established by UseProgram, that program is considered current
+ * for all stages. Otherwise, if there is a bound program pipeline
+ * object (section 2.14.PPO), the program bound to the appropriate
+ * stage of the pipeline object is considered current."
+ */
+ if (program) {
+ /* Attach shader state to the binding point */
+ _mesa_reference_pipeline_object(ctx, &ctx->_Shader, &ctx->Shader);
+ /* Update the program */
+ _mesa_use_program(ctx, shProg);
+ } else {
+ /* Must be done first: detach the progam */
+ _mesa_use_program(ctx, shProg);
+ /* Unattach shader_state binding point */
+ _mesa_reference_pipeline_object(ctx, &ctx->_Shader, ctx->Pipeline.Default);
+ /* If a pipeline was bound, rebind it */
+ if (ctx->Pipeline.Current) {
+ _mesa_BindProgramPipeline(ctx->Pipeline.Current->Name);
+ }
+ }
}
*/
shProg->BinaryRetreivableHint = value;
return;
+
+ case GL_PROGRAM_SEPARABLE:
+ /* Spec imply that the behavior is the same as ARB_get_program_binary
+ * Chapter 7.3 Program Objects
+ */
+ if (value != GL_TRUE && value != GL_FALSE) {
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "glProgramParameteri(pname=%s, value=%d): "
+ "value must be 0 or 1.",
+ _mesa_lookup_enum_by_nr(pname),
+ value);
+ return;
+ }
+ shProg->SeparateShader = value;
+ return;
+
default:
break;
}
void
_mesa_use_shader_program(struct gl_context *ctx, GLenum type,
- struct gl_shader_program *shProg)
+ struct gl_shader_program *shProg,
+ struct gl_pipeline_object *shTarget)
{
- use_shader_program(ctx, type, shProg);
+ use_shader_program(ctx, type, shProg, shTarget);
if (ctx->Driver.UseProgram)
ctx->Driver.UseProgram(ctx, shProg);
}
-/**
- * For GL_EXT_separate_shader_objects
- */
-void GLAPIENTRY
-_mesa_UseShaderProgramEXT(GLenum type, GLuint program)
-{
- GET_CURRENT_CONTEXT(ctx);
- struct gl_shader_program *shProg = NULL;
-
- if (!_mesa_validate_shader_target(ctx, type)) {
- _mesa_error(ctx, GL_INVALID_ENUM, "glUseShaderProgramEXT(type)");
- return;
- }
-
- if (_mesa_is_xfb_active_and_unpaused(ctx)) {
- _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);
-}
-
-
-/**
- * For GL_EXT_separate_shader_objects
- */
-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;
-
- _mesa_active_program(ctx, shProg, "glActiveProgramEXT");
- return;
-}
-
-
-/**
- * For GL_EXT_separate_shader_objects
- */
-GLuint GLAPIENTRY
-_mesa_CreateShaderProgramEXT(GLenum type, const GLchar *string)
+static GLuint
+_mesa_create_shader_program(struct gl_context* ctx, GLboolean separate,
+ GLenum type, GLsizei count, const GLchar* const *strings)
{
- GET_CURRENT_CONTEXT(ctx);
const GLuint shader = create_shader(ctx, type);
GLuint program = 0;
if (shader) {
- shader_source(ctx, shader, _mesa_strdup(string));
+ _mesa_ShaderSource(shader, count, strings, NULL);
+
compile_shader(ctx, shader);
program = create_shader_program(ctx);
shProg = _mesa_lookup_shader_program(ctx, program);
sh = _mesa_lookup_shader(ctx, shader);
+ shProg->SeparateShader = separate;
+
get_shaderiv(ctx, shader, GL_COMPILE_STATUS, &compiled);
if (compiled) {
attach_shader(ctx, program, shader);
dst_gp->UsesEndPrimitive = src->Geom.UsesEndPrimitive;
}
break;
+ case MESA_SHADER_FRAGMENT: {
+ struct gl_fragment_program *dst_fp = (struct gl_fragment_program *) dst;
+ dst_fp->FragDepthLayout = src->FragDepthLayout;
+ }
+ break;
case MESA_SHADER_COMPUTE: {
struct gl_compute_program *dst_cp = (struct gl_compute_program *) dst;
int i;
}
}
-
/**
* ARB_separate_shader_objects: Compile & Link Program
*/
_mesa_CreateShaderProgramv(GLenum type, GLsizei count,
const GLchar* const *strings)
{
- return 0;
+ GET_CURRENT_CONTEXT(ctx);
+
+ return _mesa_create_shader_program(ctx, GL_TRUE, type, count, strings);
}