nir: improvements to native_integers removal
[mesa.git] / src / mesa / program / program.c
index c35a89b5983ad5fe9e7824c1be4385a09d377c99..6ab1bf50177b9919035740d622ac347cdc9fb381 100644 (file)
 
 #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/bitscan.h"
 #include "util/ralloc.h"
+#include "util/u_atomic.h"
 
 
 /**
@@ -86,16 +90,17 @@ _mesa_init_program(struct gl_context *ctx)
    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();
+   ctx->VertexProgram._VPMode = VP_MODE_FF;
 
    /* XXX probably move this stuff */
    ctx->ATIFragmentShader.Enabled = GL_FALSE;
@@ -111,9 +116,9 @@ _mesa_init_program(struct gl_context *ctx)
 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 */
@@ -136,11 +141,11 @@ _mesa_free_program_data(struct gl_context *ctx)
 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);
 
@@ -176,24 +181,36 @@ _mesa_set_program_error(struct gl_context *ctx, GLint pos, const char *string)
  * Initialize a new gl_program object.
  */
 struct gl_program *
-_mesa_init_gl_program(void *_prog, GLenum target, GLuint id)
+_mesa_init_gl_program(struct gl_program *prog, GLenum target, GLuint id,
+                      bool is_arb_asm)
 {
-   struct gl_program *prog = (struct gl_program*)_prog;
-   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;
 }
@@ -212,40 +229,23 @@ _mesa_init_gl_program(void *_prog, GLenum target, GLuint id)
  * \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_gl_program(CALLOC_STRUCT(gl_vertex_program),
-                                   target, id);
-      break;
-   case GL_FRAGMENT_PROGRAM_NV:
-   case GL_FRAGMENT_PROGRAM_ARB:
-      prog =_mesa_init_gl_program(CALLOC_STRUCT(gl_fragment_program),
-                                  target, id);
-      break;
    case GL_GEOMETRY_PROGRAM_NV:
-      prog = _mesa_init_gl_program(CALLOC_STRUCT(gl_geometry_program),
-                                   target, id);
-      break;
    case GL_TESS_CONTROL_PROGRAM_NV:
-      prog = _mesa_init_gl_program(CALLOC_STRUCT(gl_tess_ctrl_program),
-                                   target, id);
-      break;
    case GL_TESS_EVALUATION_PROGRAM_NV:
-      prog = _mesa_init_gl_program(CALLOC_STRUCT(gl_tess_eval_program),
-                                   target, id);
-      break;
-   case GL_COMPUTE_PROGRAM_NV:
-      prog = _mesa_init_gl_program(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;
 }
 
 
@@ -265,12 +265,6 @@ _mesa_delete_program(struct gl_context *ctx, struct gl_program *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);
    }
@@ -279,8 +273,19 @@ _mesa_delete_program(struct gl_context *ctx, struct gl_program *prog)
       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);
+   }
+
+   if (prog->driver_cache_blob) {
+      ralloc_free(prog->driver_cache_blob);
+   }
+
+   ralloc_free(prog);
 }
 
 
@@ -324,18 +329,13 @@ _mesa_reference_program_(struct gl_context *ctx,
 #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);
       }
 
@@ -344,9 +344,7 @@ _mesa_reference_program_(struct gl_context *ctx,
 
    assert(!*ptr);
    if (prog) {
-      mtx_lock(&prog->Mutex);
-      prog->RefCount++;
-      mtx_unlock(&prog->Mutex);
+      p_atomic_inc(&prog->RefCount);
    }
 
    *ptr = prog;
@@ -360,14 +358,14 @@ _mesa_reference_program_(struct gl_context *ctx,
 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;
@@ -376,28 +374,28 @@ _mesa_insert_instructions(struct gl_program *prog, GLuint start, GLuint 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;
 }
@@ -407,16 +405,17 @@ _mesa_insert_instructions(struct gl_program *prog, GLuint start, GLuint count)
  * 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;
@@ -425,81 +424,30 @@ _mesa_delete_instructions(struct gl_program *prog, GLuint start, GLuint 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.
@@ -516,8 +464,8 @@ _mesa_find_used_registers(const struct gl_program *prog,
 
    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) {
@@ -568,8 +516,7 @@ _mesa_find_free_register(const GLboolean used[],
  */
 GLint
 _mesa_get_min_invocations_per_fragment(struct gl_context *ctx,
-                                       const struct gl_fragment_program *prog,
-                                       bool ignore_sample_qualifier)
+                                       const struct gl_program *prog)
 {
    /* From ARB_sample_shading specification:
     * "Using gl_SampleID in a fragment shader causes the entire shader
@@ -587,17 +534,31 @@ _mesa_get_min_invocations_per_fragment(struct gl_context *ctx,
        * "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->Base.SystemValuesRead & (SYSTEM_BIT_SAMPLE_ID |
-                                         SYSTEM_BIT_SAMPLE_POS))
-         return MAX2(ctx->DrawBuffer->Visual.samples, 1);
+      if (prog->info.fs.uses_sample_qualifier ||
+          (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;
    }
    return 1;
 }
+
+
+GLbitfield
+gl_external_samplers(const struct gl_program *prog)
+{
+   GLbitfield external_samplers = 0;
+   GLbitfield mask = prog->SamplersUsed;
+
+   while (mask) {
+      int idx = u_bit_scan(&mask);
+      if (prog->sh.SamplerTargets[idx] == TEXTURE_EXTERNAL_INDEX)
+         external_samplers |= (1 << idx);
+   }
+
+   return external_samplers;
+}