#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.
*/
struct gl_program *
-_mesa_init_gl_program(struct gl_program *prog, GLenum target, GLuint id)
+_mesa_init_gl_program(struct gl_program *prog, GLenum target, GLuint id,
+ bool is_arb_asm)
{
- GLuint i;
-
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;
+ /* 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 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)
{
switch (target) {
- case GL_VERTEX_PROGRAM_ARB: { /* == GL_VERTEX_PROGRAM_NV */
- struct gl_vertex_program *prog = CALLOC_STRUCT(gl_vertex_program);
- return _mesa_init_gl_program(&prog->Base, target, id);
- }
- case GL_FRAGMENT_PROGRAM_ARB: {
- struct gl_fragment_program *prog = CALLOC_STRUCT(gl_fragment_program);
- return _mesa_init_gl_program(&prog->Base, target, id);
- }
+ case GL_VERTEX_PROGRAM_ARB: /* == GL_VERTEX_PROGRAM_NV */
case GL_GEOMETRY_PROGRAM_NV:
case GL_TESS_CONTROL_PROGRAM_NV:
- case GL_TESS_EVALUATION_PROGRAM_NV: {
- struct gl_program *prog = CALLOC_STRUCT(gl_program);
- return _mesa_init_gl_program(prog, target, id);
- }
+ case GL_TESS_EVALUATION_PROGRAM_NV:
+ case GL_FRAGMENT_PROGRAM_ARB:
case GL_COMPUTE_PROGRAM_NV: {
- struct gl_compute_program *prog = CALLOC_STRUCT(gl_compute_program);
- return _mesa_init_gl_program(&prog->Base, target, id);
+ 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");
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);
+ 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;
}
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) {
*/
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)
+ 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))
+ 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 *