#include "main/glheader.h"
#include "main/context.h"
+#include "main/framebuffer.h"
#include "main/hash.h"
#include "main/macros.h"
+#include "main/shaderobj.h"
#include "program.h"
#include "prog_cache.h"
#include "prog_parameter.h"
#include "prog_instruction.h"
#include "util/ralloc.h"
+#include "util/u_atomic.h"
/**
ctx->VertexProgram.PointSizeEnabled =
(ctx->API == API_OPENGLES2) ? GL_TRUE : GL_FALSE;
ctx->VertexProgram.TwoSideEnabled = GL_FALSE;
- _mesa_reference_vertprog(ctx, &ctx->VertexProgram.Current,
- ctx->Shared->DefaultVertexProgram);
+ _mesa_reference_program(ctx, &ctx->VertexProgram.Current,
+ ctx->Shared->DefaultVertexProgram);
assert(ctx->VertexProgram.Current);
ctx->VertexProgram.Cache = _mesa_new_program_cache();
ctx->FragmentProgram.Enabled = GL_FALSE;
- _mesa_reference_fragprog(ctx, &ctx->FragmentProgram.Current,
- ctx->Shared->DefaultFragmentProgram);
+ _mesa_reference_program(ctx, &ctx->FragmentProgram.Current,
+ ctx->Shared->DefaultFragmentProgram);
assert(ctx->FragmentProgram.Current);
ctx->FragmentProgram.Cache = _mesa_new_program_cache();
void
_mesa_free_program_data(struct gl_context *ctx)
{
- _mesa_reference_vertprog(ctx, &ctx->VertexProgram.Current, NULL);
+ _mesa_reference_program(ctx, &ctx->VertexProgram.Current, NULL);
_mesa_delete_program_cache(ctx, ctx->VertexProgram.Cache);
- _mesa_reference_fragprog(ctx, &ctx->FragmentProgram.Current, NULL);
+ _mesa_reference_program(ctx, &ctx->FragmentProgram.Current, NULL);
_mesa_delete_shader_cache(ctx, ctx->FragmentProgram.Cache);
/* XXX probably move this stuff */
void
_mesa_update_default_objects_program(struct gl_context *ctx)
{
- _mesa_reference_vertprog(ctx, &ctx->VertexProgram.Current,
- ctx->Shared->DefaultVertexProgram);
+ _mesa_reference_program(ctx, &ctx->VertexProgram.Current,
+ ctx->Shared->DefaultVertexProgram);
assert(ctx->VertexProgram.Current);
- _mesa_reference_fragprog(ctx, &ctx->FragmentProgram.Current,
+ _mesa_reference_program(ctx, &ctx->FragmentProgram.Current,
ctx->Shared->DefaultFragmentProgram);
assert(ctx->FragmentProgram.Current);
/**
* Initialize a new gl_program object.
*/
-static void
-init_program_struct(struct gl_program *prog, GLenum target, GLuint id)
+struct gl_program *
+_mesa_init_gl_program(struct gl_program *prog, GLenum target, GLuint id,
+ bool is_arb_asm)
{
- GLuint i;
-
- assert(prog);
+ if (!prog)
+ return NULL;
memset(prog, 0, sizeof(*prog));
- mtx_init(&prog->Mutex, mtx_plain);
prog->Id = id;
prog->Target = target;
prog->RefCount = 1;
prog->Format = GL_PROGRAM_FORMAT_ASCII_ARB;
+ prog->info.stage = _mesa_program_enum_to_shader_stage(target);
+ prog->is_arb_asm = is_arb_asm;
- /* default mapping from samplers to texture units */
- for (i = 0; i < MAX_SAMPLERS; i++)
- prog->SamplerUnits[i] = i;
-}
-
-
-/**
- * Initialize a new fragment program object.
- */
-struct gl_program *
-_mesa_init_fragment_program(struct gl_context *ctx,
- struct gl_fragment_program *prog,
- GLenum target, GLuint id)
-{
- if (prog) {
- init_program_struct(&prog->Base, target, id);
- return &prog->Base;
- }
- return NULL;
-}
-
-
-/**
- * Initialize a new vertex program object.
- */
-struct gl_program *
-_mesa_init_vertex_program(struct gl_context *ctx,
- struct gl_vertex_program *prog,
- GLenum target, GLuint id)
-{
- if (prog) {
- init_program_struct(&prog->Base, target, id);
- return &prog->Base;
- }
- return NULL;
-}
-
-
-/**
- * Initialize a new compute program object.
- */
-struct gl_program *
-_mesa_init_compute_program(struct gl_context *ctx,
- struct gl_compute_program *prog,
- GLenum target, GLuint id)
-{
- if (prog) {
- init_program_struct(&prog->Base, target, id);
- return &prog->Base;
- }
- return NULL;
-}
-
-
-/**
- * Initialize a new tessellation control program object.
- */
-struct gl_program *
-_mesa_init_tess_ctrl_program(struct gl_context *ctx,
- struct gl_tess_ctrl_program *prog,
- GLenum target, GLuint id)
-{
- if (prog) {
- init_program_struct(&prog->Base, target, id);
- return &prog->Base;
- }
- return NULL;
-}
-
-
-/**
- * Initialize a new tessellation evaluation program object.
- */
-struct gl_program *
-_mesa_init_tess_eval_program(struct gl_context *ctx,
- struct gl_tess_eval_program *prog,
- GLenum target, GLuint id)
-{
- if (prog) {
- init_program_struct(&prog->Base, target, id);
- return &prog->Base;
+ /* Uniforms that lack an initializer in the shader code have an initial
+ * value of zero. This includes sampler uniforms.
+ *
+ * Page 24 (page 30 of the PDF) of the GLSL 1.20 spec says:
+ *
+ * "The link time initial value is either the value of the variable's
+ * initializer, if present, or 0 if no initializer is present. Sampler
+ * types cannot have initializers."
+ *
+ * So we only initialise ARB assembly style programs.
+ */
+ if (is_arb_asm) {
+ /* default mapping from samplers to texture units */
+ for (unsigned i = 0; i < MAX_SAMPLERS; i++)
+ prog->SamplerUnits[i] = i;
}
- return NULL;
-}
-
-/**
- * Initialize a new geometry program object.
- */
-struct gl_program *
-_mesa_init_geometry_program(struct gl_context *ctx,
- struct gl_geometry_program *prog,
- GLenum target, GLuint id)
-{
- if (prog) {
- init_program_struct(&prog->Base, target, id);
- return &prog->Base;
- }
- return NULL;
+ return prog;
}
* \return pointer to new program object
*/
struct gl_program *
-_mesa_new_program(struct gl_context *ctx, GLenum target, GLuint id)
+_mesa_new_program(struct gl_context *ctx, GLenum target, GLuint id,
+ bool is_arb_asm)
{
- struct gl_program *prog;
switch (target) {
case GL_VERTEX_PROGRAM_ARB: /* == GL_VERTEX_PROGRAM_NV */
- prog = _mesa_init_vertex_program(ctx, CALLOC_STRUCT(gl_vertex_program),
- target, id );
- break;
- case GL_FRAGMENT_PROGRAM_NV:
- case GL_FRAGMENT_PROGRAM_ARB:
- prog =_mesa_init_fragment_program(ctx,
- CALLOC_STRUCT(gl_fragment_program),
- target, id );
- break;
case GL_GEOMETRY_PROGRAM_NV:
- prog = _mesa_init_geometry_program(ctx,
- CALLOC_STRUCT(gl_geometry_program),
- target, id);
- break;
case GL_TESS_CONTROL_PROGRAM_NV:
- prog = _mesa_init_tess_ctrl_program(ctx,
- CALLOC_STRUCT(gl_tess_ctrl_program),
- target, id);
- break;
case GL_TESS_EVALUATION_PROGRAM_NV:
- prog = _mesa_init_tess_eval_program(ctx,
- CALLOC_STRUCT(gl_tess_eval_program),
- target, id);
- break;
- case GL_COMPUTE_PROGRAM_NV:
- prog = _mesa_init_compute_program(ctx,
- CALLOC_STRUCT(gl_compute_program),
- target, id);
- break;
+ case GL_FRAGMENT_PROGRAM_ARB:
+ case GL_COMPUTE_PROGRAM_NV: {
+ struct gl_program *prog = rzalloc(NULL, struct gl_program);
+ return _mesa_init_gl_program(prog, target, id, is_arb_asm);
+ }
default:
_mesa_problem(ctx, "bad target in _mesa_new_program");
- prog = NULL;
+ return NULL;
}
- return prog;
}
if (prog == &_mesa_DummyProgram)
return;
- free(prog->String);
- free(prog->LocalParams);
-
- if (prog->Instructions) {
- _mesa_free_instructions(prog->Instructions, prog->NumInstructions);
- }
if (prog->Parameters) {
_mesa_free_parameter_list(prog->Parameters);
}
ralloc_free(prog->nir);
}
- mtx_destroy(&prog->Mutex);
- free(prog);
+ if (prog->sh.BindlessSamplers) {
+ ralloc_free(prog->sh.BindlessSamplers);
+ }
+
+ if (prog->sh.BindlessImages) {
+ ralloc_free(prog->sh.BindlessImages);
+ }
+
+ ralloc_free(prog);
}
#endif
if (*ptr) {
- GLboolean deleteFlag;
struct gl_program *oldProg = *ptr;
- mtx_lock(&oldProg->Mutex);
assert(oldProg->RefCount > 0);
- oldProg->RefCount--;
-
- deleteFlag = (oldProg->RefCount == 0);
- mtx_unlock(&oldProg->Mutex);
- if (deleteFlag) {
+ if (p_atomic_dec_zero(&oldProg->RefCount)) {
assert(ctx);
+ _mesa_reference_shader_program_data(ctx, &oldProg->sh.data, NULL);
ctx->Driver.DeleteProgram(ctx, oldProg);
}
assert(!*ptr);
if (prog) {
- mtx_lock(&prog->Mutex);
- prog->RefCount++;
- mtx_unlock(&prog->Mutex);
+ p_atomic_inc(&prog->RefCount);
}
*ptr = prog;
GLboolean
_mesa_insert_instructions(struct gl_program *prog, GLuint start, GLuint count)
{
- const GLuint origLen = prog->NumInstructions;
+ const GLuint origLen = prog->arb.NumInstructions;
const GLuint newLen = origLen + count;
struct prog_instruction *newInst;
GLuint i;
/* adjust branches */
- for (i = 0; i < prog->NumInstructions; i++) {
- struct prog_instruction *inst = prog->Instructions + i;
+ for (i = 0; i < prog->arb.NumInstructions; i++) {
+ struct prog_instruction *inst = prog->arb.Instructions + i;
if (inst->BranchTarget > 0) {
if ((GLuint)inst->BranchTarget >= start) {
inst->BranchTarget += count;
}
/* Alloc storage for new instructions */
- newInst = _mesa_alloc_instructions(newLen);
+ newInst = rzalloc_array(prog, struct prog_instruction, newLen);
if (!newInst) {
return GL_FALSE;
}
/* Copy 'start' instructions into new instruction buffer */
- _mesa_copy_instructions(newInst, prog->Instructions, start);
+ _mesa_copy_instructions(newInst, prog->arb.Instructions, start);
/* init the new instructions */
_mesa_init_instructions(newInst + start, count);
/* Copy the remaining/tail instructions to new inst buffer */
_mesa_copy_instructions(newInst + start + count,
- prog->Instructions + start,
+ prog->arb.Instructions + start,
origLen - start);
/* free old instructions */
- _mesa_free_instructions(prog->Instructions, origLen);
+ ralloc_free(prog->arb.Instructions);
/* install new instructions */
- prog->Instructions = newInst;
- prog->NumInstructions = newLen;
+ prog->arb.Instructions = newInst;
+ prog->arb.NumInstructions = newLen;
return GL_TRUE;
}
* Adjust branch targets accordingly.
*/
GLboolean
-_mesa_delete_instructions(struct gl_program *prog, GLuint start, GLuint count)
+_mesa_delete_instructions(struct gl_program *prog, GLuint start, GLuint count,
+ void *mem_ctx)
{
- const GLuint origLen = prog->NumInstructions;
+ const GLuint origLen = prog->arb.NumInstructions;
const GLuint newLen = origLen - count;
struct prog_instruction *newInst;
GLuint i;
/* adjust branches */
- for (i = 0; i < prog->NumInstructions; i++) {
- struct prog_instruction *inst = prog->Instructions + i;
+ for (i = 0; i < prog->arb.NumInstructions; i++) {
+ struct prog_instruction *inst = prog->arb.Instructions + i;
if (inst->BranchTarget > 0) {
if (inst->BranchTarget > (GLint) start) {
inst->BranchTarget -= count;
}
/* Alloc storage for new instructions */
- newInst = _mesa_alloc_instructions(newLen);
+ newInst = rzalloc_array(mem_ctx, struct prog_instruction, newLen);
if (!newInst) {
return GL_FALSE;
}
/* Copy 'start' instructions into new instruction buffer */
- _mesa_copy_instructions(newInst, prog->Instructions, start);
+ _mesa_copy_instructions(newInst, prog->arb.Instructions, start);
/* Copy the remaining/tail instructions to new inst buffer */
_mesa_copy_instructions(newInst + start,
- prog->Instructions + start + count,
+ prog->arb.Instructions + start + count,
newLen - start);
/* free old instructions */
- _mesa_free_instructions(prog->Instructions, origLen);
+ ralloc_free(prog->arb.Instructions);
/* install new instructions */
- prog->Instructions = newInst;
- prog->NumInstructions = newLen;
+ prog->arb.Instructions = newInst;
+ prog->arb.NumInstructions = newLen;
return GL_TRUE;
}
-/**
- * Search instructions for registers that match (oldFile, oldIndex),
- * replacing them with (newFile, newIndex).
- */
-static void
-replace_registers(struct prog_instruction *inst, GLuint numInst,
- GLuint oldFile, GLuint oldIndex,
- GLuint newFile, GLuint newIndex)
-{
- GLuint i, j;
- for (i = 0; i < numInst; i++) {
- /* src regs */
- for (j = 0; j < _mesa_num_inst_src_regs(inst[i].Opcode); j++) {
- if (inst[i].SrcReg[j].File == oldFile &&
- inst[i].SrcReg[j].Index == oldIndex) {
- inst[i].SrcReg[j].File = newFile;
- inst[i].SrcReg[j].Index = newIndex;
- }
- }
- /* dst reg */
- if (inst[i].DstReg.File == oldFile && inst[i].DstReg.Index == oldIndex) {
- inst[i].DstReg.File = newFile;
- inst[i].DstReg.Index = newIndex;
- }
- }
-}
-
-
-/**
- * Search instructions for references to program parameters. When found,
- * increment the parameter index by 'offset'.
- * Used when combining programs.
- */
-static void
-adjust_param_indexes(struct prog_instruction *inst, GLuint numInst,
- GLuint offset)
-{
- GLuint i, j;
- for (i = 0; i < numInst; i++) {
- for (j = 0; j < _mesa_num_inst_src_regs(inst[i].Opcode); j++) {
- GLuint f = inst[i].SrcReg[j].File;
- if (f == PROGRAM_CONSTANT ||
- f == PROGRAM_UNIFORM ||
- f == PROGRAM_STATE_VAR) {
- inst[i].SrcReg[j].Index += offset;
- }
- }
- }
-}
-
-
/**
* Populate the 'used' array with flags indicating which registers (TEMPs,
* INPUTs, OUTPUTs, etc, are used by the given program.
memset(used, 0, usedSize);
- for (i = 0; i < prog->NumInstructions; i++) {
- const struct prog_instruction *inst = prog->Instructions + i;
+ for (i = 0; i < prog->arb.NumInstructions; i++) {
+ const struct prog_instruction *inst = prog->arb.Instructions + i;
const GLuint n = _mesa_num_inst_src_regs(inst->Opcode);
if (inst->DstReg.File == file) {
}
-
-/**
- * Check if the given register index is valid (doesn't exceed implementation-
- * dependent limits).
- * \return GL_TRUE if OK, GL_FALSE if bad index
- */
-GLboolean
-_mesa_valid_register_index(const struct gl_context *ctx,
- gl_shader_stage shaderType,
- gl_register_file file, GLint index)
-{
- const struct gl_program_constants *c;
-
- assert(0 <= shaderType && shaderType < MESA_SHADER_STAGES);
- c = &ctx->Const.Program[shaderType];
-
- switch (file) {
- case PROGRAM_UNDEFINED:
- return GL_TRUE; /* XXX or maybe false? */
-
- case PROGRAM_TEMPORARY:
- return index >= 0 && index < (GLint) c->MaxTemps;
-
- case PROGRAM_UNIFORM:
- case PROGRAM_STATE_VAR:
- /* aka constant buffer */
- return index >= 0 && index < (GLint) c->MaxUniformComponents / 4;
-
- case PROGRAM_CONSTANT:
- /* constant buffer w/ possible relative negative addressing */
- return (index > (int) c->MaxUniformComponents / -4 &&
- index < (int) c->MaxUniformComponents / 4);
-
- case PROGRAM_INPUT:
- if (index < 0)
- return GL_FALSE;
-
- switch (shaderType) {
- case MESA_SHADER_VERTEX:
- return index < VERT_ATTRIB_GENERIC0 + (GLint) c->MaxAttribs;
- case MESA_SHADER_FRAGMENT:
- return index < VARYING_SLOT_VAR0 + (GLint) ctx->Const.MaxVarying;
- case MESA_SHADER_GEOMETRY:
- return index < VARYING_SLOT_VAR0 + (GLint) ctx->Const.MaxVarying;
- default:
- return GL_FALSE;
- }
-
- case PROGRAM_OUTPUT:
- if (index < 0)
- return GL_FALSE;
-
- switch (shaderType) {
- case MESA_SHADER_VERTEX:
- return index < VARYING_SLOT_VAR0 + (GLint) ctx->Const.MaxVarying;
- case MESA_SHADER_FRAGMENT:
- return index < FRAG_RESULT_DATA0 + (GLint) ctx->Const.MaxDrawBuffers;
- case MESA_SHADER_GEOMETRY:
- return index < VARYING_SLOT_VAR0 + (GLint) ctx->Const.MaxVarying;
- default:
- return GL_FALSE;
- }
-
- case PROGRAM_ADDRESS:
- return index >= 0 && index < (GLint) c->MaxAddressRegs;
-
- default:
- _mesa_problem(ctx,
- "unexpected register file in _mesa_valid_register_index()");
- return GL_FALSE;
- }
-}
-
-
-
-/**
- * "Post-process" a GPU program. This is intended to be used for debugging.
- * Example actions include no-op'ing instructions or changing instruction
- * behaviour.
- */
-void
-_mesa_postprocess_program(struct gl_context *ctx, struct gl_program *prog)
-{
- static const GLfloat white[4] = { 0.5, 0.5, 0.5, 0.5 };
- GLuint i;
- GLuint whiteSwizzle;
- GLint whiteIndex = _mesa_add_unnamed_constant(prog->Parameters,
- (gl_constant_value *) white,
- 4, &whiteSwizzle);
-
- (void) whiteIndex;
-
- for (i = 0; i < prog->NumInstructions; i++) {
- struct prog_instruction *inst = prog->Instructions + i;
- const GLuint n = _mesa_num_inst_src_regs(inst->Opcode);
-
- (void) n;
-
- if (_mesa_is_tex_instruction(inst->Opcode)) {
-#if 0
- /* replace TEX/TXP/TXB with MOV */
- inst->Opcode = OPCODE_MOV;
- inst->DstReg.WriteMask = WRITEMASK_XYZW;
- inst->SrcReg[0].Swizzle = SWIZZLE_XYZW;
- inst->SrcReg[0].Negate = NEGATE_NONE;
-#endif
-
-#if 0
- /* disable shadow texture mode */
- inst->TexShadow = 0;
-#endif
- }
-
- if (inst->Opcode == OPCODE_TXP) {
-#if 0
- inst->Opcode = OPCODE_MOV;
- inst->DstReg.WriteMask = WRITEMASK_XYZW;
- inst->SrcReg[0].File = PROGRAM_CONSTANT;
- inst->SrcReg[0].Index = whiteIndex;
- inst->SrcReg[0].Swizzle = SWIZZLE_XYZW;
- inst->SrcReg[0].Negate = NEGATE_NONE;
-#endif
-#if 0
- inst->TexShadow = 0;
-#endif
-#if 0
- inst->Opcode = OPCODE_TEX;
- inst->TexShadow = 0;
-#endif
- }
-
- }
-}
-
/* Gets the minimum number of shader invocations per fragment.
* This function is useful to determine if we need to do per
* sample shading or per fragment shading.
*/
GLint
_mesa_get_min_invocations_per_fragment(struct gl_context *ctx,
- const struct gl_fragment_program *prog,
+ const struct gl_program *prog,
bool ignore_sample_qualifier)
{
/* From ARB_sample_shading specification:
* "Use of the "sample" qualifier on a fragment shader input
* forces per-sample shading"
*/
- if (prog->IsSample && !ignore_sample_qualifier)
- return MAX2(ctx->DrawBuffer->Visual.samples, 1);
+ if (prog->info.fs.uses_sample_qualifier && !ignore_sample_qualifier)
+ return MAX2(_mesa_geometric_samples(ctx->DrawBuffer), 1);
- if (prog->Base.SystemValuesRead & (SYSTEM_BIT_SAMPLE_ID |
- SYSTEM_BIT_SAMPLE_POS))
- return MAX2(ctx->DrawBuffer->Visual.samples, 1);
+ if (prog->info.system_values_read & (SYSTEM_BIT_SAMPLE_ID |
+ SYSTEM_BIT_SAMPLE_POS))
+ return MAX2(_mesa_geometric_samples(ctx->DrawBuffer), 1);
else if (ctx->Multisample.SampleShading)
return MAX2(ceil(ctx->Multisample.MinSampleShadingValue *
- ctx->DrawBuffer->Visual.samples), 1);
+ _mesa_geometric_samples(ctx->DrawBuffer)), 1);
else
return 1;
}