i965: Improve same-buffer restriction for imports
[mesa.git] / src / mesa / program / ir_to_mesa.cpp
index 7ea375f03621414bb9e65ef5b002b866fe283edc..4c30bea2f2347b1478f6edfa018b480929304a21 100644 (file)
@@ -46,6 +46,7 @@
 #include "compiler/glsl_types.h"
 #include "compiler/glsl/linker.h"
 #include "compiler/glsl/program.h"
+#include "compiler/glsl/shader_cache.h"
 #include "program/prog_instruction.h"
 #include "program/prog_optimize.h"
 #include "program/prog_print.h"
@@ -532,6 +533,12 @@ type_size(const struct glsl_type *type)
             return 1;
       }
       break;
+   case GLSL_TYPE_UINT64:
+   case GLSL_TYPE_INT64:
+      if (type->vector_elements > 2)
+         return 2;
+      else
+         return 1;
    case GLSL_TYPE_ARRAY:
       assert(type->length > 0);
       return type_size(type->fields.array) * type->length;
@@ -1062,8 +1069,10 @@ ir_to_mesa_visitor::visit(ir_expression *ir)
       emit_scalar(ir, OPCODE_EX2, result_dst, op[0]);
       break;
    case ir_unop_exp:
+      assert(!"not reached: should be handled by exp_to_exp2");
+      break;
    case ir_unop_log:
-      assert(!"not reached: should be handled by ir_explog_to_explog2");
+      assert(!"not reached: should be handled by log_to_log2");
       break;
    case ir_unop_log2:
       emit_scalar(ir, OPCODE_LG2, result_dst, op[0]);
@@ -1354,13 +1363,20 @@ ir_to_mesa_visitor::visit(ir_expression *ir)
       emit(ir, OPCODE_LRP, result_dst, op[2], op[1], op[0]);
       break;
 
+   case ir_triop_csel:
+      /* We assume that boolean true and false are 1.0 and 0.0.  OPCODE_CMP
+       * selects src1 if src0 is < 0, src2 otherwise.
+       */
+      op[0].negate = ~op[0].negate;
+      emit(ir, OPCODE_CMP, result_dst, op[0], op[1], op[2]);
+      break;
+
    case ir_binop_vector_extract:
    case ir_triop_fma:
    case ir_triop_bitfield_extract:
    case ir_triop_vector_insert:
    case ir_quadop_bitfield_insert:
    case ir_binop_ldexp:
-   case ir_triop_csel:
    case ir_binop_carry:
    case ir_binop_borrow:
    case ir_binop_imul_high:
@@ -1373,9 +1389,38 @@ ir_to_mesa_visitor::visit(ir_expression *ir)
    case ir_unop_dFdy_fine:
    case ir_unop_subroutine_to_int:
    case ir_unop_get_buffer_size:
-   case ir_unop_vote_any:
-   case ir_unop_vote_all:
-   case ir_unop_vote_eq:
+   case ir_unop_bitcast_u642d:
+   case ir_unop_bitcast_i642d:
+   case ir_unop_bitcast_d2u64:
+   case ir_unop_bitcast_d2i64:
+   case ir_unop_i642i:
+   case ir_unop_u642i:
+   case ir_unop_i642u:
+   case ir_unop_u642u:
+   case ir_unop_i642b:
+   case ir_unop_i642f:
+   case ir_unop_u642f:
+   case ir_unop_i642d:
+   case ir_unop_u642d:
+   case ir_unop_i2i64:
+   case ir_unop_u2i64:
+   case ir_unop_b2i64:
+   case ir_unop_f2i64:
+   case ir_unop_d2i64:
+   case ir_unop_i2u64:
+   case ir_unop_u2u64:
+   case ir_unop_f2u64:
+   case ir_unop_d2u64:
+   case ir_unop_u642i64:
+   case ir_unop_i642u64:
+   case ir_unop_pack_int_2x32:
+   case ir_unop_unpack_int_2x32:
+   case ir_unop_pack_uint_2x32:
+   case ir_unop_unpack_uint_2x32:
+   case ir_unop_pack_sampler_2x32:
+   case ir_unop_unpack_sampler_2x32:
+   case ir_unop_pack_image_2x32:
+   case ir_unop_unpack_image_2x32:
       assert(!"not supported");
       break;
 
@@ -1622,7 +1667,7 @@ calc_sampler_offsets(struct gl_shader_program *prog, ir_dereference *deref,
          * all that would work would be an unrolled loop counter that ends
          * up being constant above.
          */
-        ralloc_strcat(&prog->InfoLog,
+         ralloc_strcat(&prog->data->InfoLog,
                       "warning: Variable sampler array index unsupported.\n"
                       "This feature of the language was removed in GLSL 1.20 "
                       "and is unlikely to be supported for 1.10 in Mesa.\n");
@@ -1668,8 +1713,8 @@ get_sampler_uniform_value(class ir_dereference *sampler,
    calc_sampler_offsets(shader_program, sampler, &offset, &array_elements,
                         &location);
 
-   assert(shader_program->UniformStorage[location].opaque[shader].active);
-   return shader_program->UniformStorage[location].opaque[shader].index +
+   assert(shader_program->data->UniformStorage[location].opaque[shader].active);
+   return shader_program->data->UniformStorage[location].opaque[shader].index +
           offset;
 }
 
@@ -1856,7 +1901,7 @@ ir_to_mesa_visitor::visit(ir_constant *ir)
     * get lucky, copy propagation will eliminate the extra moves.
     */
 
-   if (ir->type->base_type == GLSL_TYPE_STRUCT) {
+   if (ir->type->is_record()) {
       src_reg temp_base = get_temp(ir->type);
       dst_reg temp = dst_reg(temp_base);
 
@@ -1905,7 +1950,7 @@ ir_to_mesa_visitor::visit(ir_constant *ir)
       dst_reg mat_column = dst_reg(mat);
 
       for (i = 0; i < ir->type->matrix_columns; i++) {
-        assert(ir->type->base_type == GLSL_TYPE_FLOAT);
+        assert(ir->type->is_float());
         values = &ir->value.f[i * ir->type->vector_elements];
 
         src = src_reg(PROGRAM_CONSTANT, -1, NULL);
@@ -2055,14 +2100,14 @@ ir_to_mesa_visitor::visit(ir_texture *ir)
         emit(ir, OPCODE_RCP, coord_dst, projector);
 
         /* In the case where we have to project the coordinates "by hand,"
-         * the shadow comparitor value must also be projected.
+         * the shadow comparator value must also be projected.
          */
         src_reg tmp_src = coord;
-        if (ir->shadow_comparitor) {
+        if (ir->shadow_comparator) {
            /* Slot the shadow value in as the second to last component of the
             * coord.
             */
-           ir->shadow_comparitor->accept(this);
+           ir->shadow_comparator->accept(this);
 
            tmp_src = get_temp(glsl_type::vec4_type);
            dst_reg tmp_dst = dst_reg(tmp_src);
@@ -2086,14 +2131,14 @@ ir_to_mesa_visitor::visit(ir_texture *ir)
    }
 
    /* If projection is done and the opcode is not OPCODE_TXP, then the shadow
-    * comparitor was put in the correct place (and projected) by the code,
+    * comparator was put in the correct place (and projected) by the code,
     * above, that handles by-hand projection.
     */
-   if (ir->shadow_comparitor && (!ir->projector || opcode == OPCODE_TXP)) {
+   if (ir->shadow_comparator && (!ir->projector || opcode == OPCODE_TXP)) {
       /* Slot the shadow value in as the second to last component of the
        * coord.
        */
-      ir->shadow_comparitor->accept(this);
+      ir->shadow_comparator->accept(this);
 
       /* XXX This will need to be updated for cubemap array samplers. */
       if (sampler_type->sampler_dimensionality == GLSL_SAMPLER_DIM_2D &&
@@ -2119,7 +2164,7 @@ ir_to_mesa_visitor::visit(ir_texture *ir)
    else
       inst = emit(ir, opcode, result_dst, coord);
 
-   if (ir->shadow_comparitor)
+   if (ir->shadow_comparator)
       inst->tex_shadow = GL_TRUE;
 
    inst->sampler = get_sampler_uniform_value(ir->sampler, shader_program,
@@ -2400,20 +2445,10 @@ add_uniform_to_shader::visit_field(const glsl_type *type, const char *name,
                                    const enum glsl_interface_packing,
                                    bool /* last_field */)
 {
-   unsigned int size;
-
    /* atomics don't get real storage */
    if (type->contains_atomic())
       return;
 
-   if (type->is_vector() || type->is_scalar()) {
-      size = type->vector_elements;
-      if (type->is_64bit())
-         size *= 2;
-   } else {
-      size = type_size(type) * 4;
-   }
-
    gl_register_file file;
    if (type->without_array()->is_sampler()) {
       file = PROGRAM_SAMPLER;
@@ -2423,6 +2458,8 @@ add_uniform_to_shader::visit_field(const glsl_type *type, const char *name,
 
    int index = _mesa_lookup_parameter_index(params, name);
    if (index < 0) {
+      unsigned size = type_size(type) * 4;
+
       index = _mesa_add_parameter(params, file, name, size, type->gl_type,
                                  NULL, NULL);
 
@@ -2441,7 +2478,7 @@ add_uniform_to_shader::visit_field(const glsl_type *type, const char *name,
            return;
 
         struct gl_uniform_storage *storage =
-           &this->shader_program->UniformStorage[location];
+            &this->shader_program->data->UniformStorage[location];
 
          assert(storage->type->is_sampler() &&
                 storage->opaque[shader_type].active);
@@ -2489,8 +2526,9 @@ _mesa_generate_parameters_list_for_uniforms(struct gl_shader_program
 
 void
 _mesa_associate_uniform_storage(struct gl_context *ctx,
-                               struct gl_shader_program *shader_program,
-                               struct gl_program_parameter_list *params)
+                                struct gl_shader_program *shader_program,
+                                struct gl_program_parameter_list *params,
+                                bool propagate_to_storage)
 {
    /* After adding each uniform to the parameter list, connect the storage for
     * the parameter with the tracking structure used by the API for the
@@ -2499,58 +2537,65 @@ _mesa_associate_uniform_storage(struct gl_context *ctx,
    unsigned last_location = unsigned(~0);
    for (unsigned i = 0; i < params->NumParameters; i++) {
       if (params->Parameters[i].Type != PROGRAM_UNIFORM)
-        continue;
+         continue;
 
       unsigned location;
       const bool found =
-        shader_program->UniformHash->get(location, params->Parameters[i].Name);
+         shader_program->UniformHash->get(location, params->Parameters[i].Name);
       assert(found);
 
       if (!found)
-        continue;
+         continue;
 
       struct gl_uniform_storage *storage =
-         &shader_program->UniformStorage[location];
+         &shader_program->data->UniformStorage[location];
 
       /* Do not associate any uniform storage to built-in uniforms */
       if (storage->builtin)
          continue;
 
       if (location != last_location) {
-        enum gl_uniform_driver_format format = uniform_native;
-
-        unsigned columns = 0;
-        int dmul = 4 * sizeof(float);
-        switch (storage->type->base_type) {
-        case GLSL_TYPE_UINT:
-           assert(ctx->Const.NativeIntegers);
-           format = uniform_native;
-           columns = 1;
-           break;
-        case GLSL_TYPE_INT:
-           format =
-              (ctx->Const.NativeIntegers) ? uniform_native : uniform_int_float;
-           columns = 1;
-           break;
+         enum gl_uniform_driver_format format = uniform_native;
+         unsigned columns = 0;
+         int dmul = 4 * sizeof(float);
 
-        case GLSL_TYPE_DOUBLE:
-           if (storage->type->vector_elements > 2)
+         switch (storage->type->base_type) {
+         case GLSL_TYPE_UINT64:
+            if (storage->type->vector_elements > 2)
                dmul *= 2;
-           /* fallthrough */
-        case GLSL_TYPE_FLOAT:
-           format = uniform_native;
-           columns = storage->type->matrix_columns;
-           break;
-        case GLSL_TYPE_BOOL:
-           format = uniform_native;
-           columns = 1;
-           break;
-        case GLSL_TYPE_SAMPLER:
-        case GLSL_TYPE_IMAGE:
+            /* fallthrough */
+         case GLSL_TYPE_UINT:
+            assert(ctx->Const.NativeIntegers);
+            format = uniform_native;
+            columns = 1;
+            break;
+         case GLSL_TYPE_INT64:
+            if (storage->type->vector_elements > 2)
+               dmul *= 2;
+            /* fallthrough */
+         case GLSL_TYPE_INT:
+            format =
+               (ctx->Const.NativeIntegers) ? uniform_native : uniform_int_float;
+            columns = 1;
+            break;
+         case GLSL_TYPE_DOUBLE:
+            if (storage->type->vector_elements > 2)
+               dmul *= 2;
+            /* fallthrough */
+         case GLSL_TYPE_FLOAT:
+            format = uniform_native;
+            columns = storage->type->matrix_columns;
+            break;
+         case GLSL_TYPE_BOOL:
+            format = uniform_native;
+            columns = 1;
+            break;
+         case GLSL_TYPE_SAMPLER:
+         case GLSL_TYPE_IMAGE:
          case GLSL_TYPE_SUBROUTINE:
-           format = uniform_native;
-           columns = 1;
-           break;
+            format = uniform_native;
+            columns = 1;
+            break;
          case GLSL_TYPE_ATOMIC_UINT:
          case GLSL_TYPE_ARRAY:
          case GLSL_TYPE_VOID:
@@ -2558,25 +2603,25 @@ _mesa_associate_uniform_storage(struct gl_context *ctx,
          case GLSL_TYPE_ERROR:
          case GLSL_TYPE_INTERFACE:
          case GLSL_TYPE_FUNCTION:
-           assert(!"Should not get here.");
-           break;
-        }
+            assert(!"Should not get here.");
+            break;
+         }
 
-        _mesa_uniform_attach_driver_storage(storage,
-                                            dmul * columns,
-                                            dmul,
-                                            format,
-                                            &params->ParameterValues[i]);
+         _mesa_uniform_attach_driver_storage(storage, dmul * columns, dmul,
+                                             format,
+                                             &params->ParameterValues[i]);
 
-        /* After attaching the driver's storage to the uniform, propagate any
-         * data from the linker's backing store.  This will cause values from
-         * initializers in the source code to be copied over.
-         */
-        _mesa_propagate_uniforms_to_driver_storage(storage,
-                                                   0,
-                                                   MAX2(1, storage->array_elements));
+         /* After attaching the driver's storage to the uniform, propagate any
+          * data from the linker's backing store.  This will cause values from
+          * initializers in the source code to be copied over.
+          */
+         if (propagate_to_storage) {
+            unsigned array_elements = MAX2(1, storage->array_elements);
+            _mesa_propagate_uniforms_to_driver_storage(storage, 0,
+                                                       array_elements);
+         }
 
-        last_location = location;
+             last_location = location;
       }
    }
 }
@@ -2794,9 +2839,7 @@ get_mesa_program(struct gl_context *ctx,
 
    validate_ir_tree(shader->ir);
 
-   prog = ctx->Driver.NewProgram(ctx, target, shader_program->Name);
-   if (!prog)
-      return NULL;
+   prog = shader->Program;
    prog->Parameters = _mesa_new_parameter_list();
    v.ctx = ctx;
    v.prog = prog;
@@ -2810,13 +2853,12 @@ get_mesa_program(struct gl_context *ctx,
    visit_exec_list(shader->ir, &v);
    v.emit(NULL, OPCODE_END);
 
-   prog->NumTemporaries = v.next_temp;
+   prog->arb.NumTemporaries = v.next_temp;
 
    unsigned num_instructions = v.instructions.length();
 
-   mesa_instructions =
-      (struct prog_instruction *)calloc(num_instructions,
-                                       sizeof(*mesa_instructions));
+   mesa_instructions = rzalloc_array(prog, struct prog_instruction,
+                                     num_instructions);
    mesa_instruction_annotation = ralloc_array(v.mem_ctx, ir_instruction *,
                                              num_instructions);
 
@@ -2844,12 +2886,12 @@ get_mesa_program(struct gl_context *ctx,
 
       /* Set IndirectRegisterFiles. */
       if (mesa_inst->DstReg.RelAddr)
-         prog->IndirectRegisterFiles |= 1 << mesa_inst->DstReg.File;
+         prog->arb.IndirectRegisterFiles |= 1 << mesa_inst->DstReg.File;
 
       /* Update program's bitmask of indirectly accessed register files */
       for (unsigned src = 0; src < 3; src++)
          if (mesa_inst->SrcReg[src].RelAddr)
-            prog->IndirectRegisterFiles |= 1 << mesa_inst->SrcReg[src].File;
+            prog->arb.IndirectRegisterFiles |= 1 << mesa_inst->SrcReg[src].File;
 
       switch (mesa_inst->Opcode) {
       case OPCODE_IF:
@@ -2877,7 +2919,7 @@ get_mesa_program(struct gl_context *ctx,
         }
         break;
       case OPCODE_ARL:
-        prog->NumAddressRegs = 1;
+         prog->arb.NumAddressRegs = 1;
         break;
       default:
         break;
@@ -2886,11 +2928,11 @@ get_mesa_program(struct gl_context *ctx,
       mesa_inst++;
       i++;
 
-      if (!shader_program->LinkStatus)
+      if (!shader_program->data->LinkStatus)
          break;
    }
 
-   if (!shader_program->LinkStatus) {
+   if (!shader_program->data->LinkStatus) {
       goto fail_exit;
    }
 
@@ -2910,8 +2952,8 @@ get_mesa_program(struct gl_context *ctx,
       fflush(stderr);
    }
 
-   prog->Instructions = mesa_instructions;
-   prog->NumInstructions = num_instructions;
+   prog->arb.Instructions = mesa_instructions;
+   prog->arb.NumInstructions = num_instructions;
 
    /* Setting this to NULL prevents a possible double free in the fail_exit
     * path (far below).
@@ -2920,9 +2962,8 @@ get_mesa_program(struct gl_context *ctx,
 
    do_set_program_inouts(shader->ir, prog, shader->Stage);
 
-   prog->SamplersUsed = shader->active_samplers;
    prog->ShadowSamplers = shader->shadow_samplers;
-   prog->ExternalSamplersUsed = gl_external_samplers(shader);
+   prog->ExternalSamplersUsed = gl_external_samplers(prog);
    _mesa_update_shader_textures_used(shader_program, prog);
 
    /* Set the gl_FragDepth layout. */
@@ -2930,25 +2971,22 @@ get_mesa_program(struct gl_context *ctx,
       prog->info.fs.depth_layout = shader_program->FragDepthLayout;
    }
 
-   _mesa_reference_program(ctx, &shader->Program, prog);
-
-   if ((ctx->_Shader->Flags & GLSL_NO_OPT) == 0) {
-      _mesa_optimize_program(ctx, prog, prog);
-   }
+   _mesa_optimize_program(ctx, prog, prog);
 
    /* This has to be done last.  Any operation that can cause
     * prog->ParameterValues to get reallocated (e.g., anything that adds a
     * program constant) has to happen before creating this linkage.
     */
-   _mesa_associate_uniform_storage(ctx, shader_program, prog->Parameters);
-   if (!shader_program->LinkStatus) {
+   _mesa_associate_uniform_storage(ctx, shader_program, prog->Parameters,
+                                   true);
+   if (!shader_program->data->LinkStatus) {
       goto fail_exit;
    }
 
    return prog;
 
 fail_exit:
-   free(mesa_instructions);
+   ralloc_free(mesa_instructions);
    _mesa_reference_program(ctx, &shader->Program, NULL);
    return NULL;
 }
@@ -2964,7 +3002,7 @@ extern "C" {
 GLboolean
 _mesa_ir_link_shader(struct gl_context *ctx, struct gl_shader_program *prog)
 {
-   assert(prog->LinkStatus);
+   assert(prog->data->LinkStatus);
 
    for (unsigned i = 0; i < MESA_SHADER_STAGES; i++) {
       if (prog->_LinkedShaders[i] == NULL)
@@ -2984,8 +3022,6 @@ _mesa_ir_link_shader(struct gl_context *ctx, struct gl_shader_program *prog)
                                 | LOG_TO_LOG2 | INT_DIV_TO_MUL_RCP
                                 | ((options->EmitNoPow) ? POW_TO_EXP2 : 0)));
 
-        progress = do_lower_jumps(ir, true, true, options->EmitNoMainReturn, options->EmitNoCont, options->EmitNoLoops) || progress;
-
         progress = do_common_optimization(ir, true, true,
                                            options, ctx->Const.NativeIntegers)
           || progress;
@@ -3034,15 +3070,15 @@ _mesa_ir_link_shader(struct gl_context *ctx, struct gl_shader_program *prog)
          if (!ctx->Driver.ProgramStringNotify(ctx,
                                               _mesa_shader_stage_to_program(i),
                                               linked_prog)) {
+            _mesa_reference_program(ctx, &prog->_LinkedShaders[i]->Program,
+                                    NULL);
             return GL_FALSE;
          }
       }
-
-      _mesa_reference_program(ctx, &linked_prog, NULL);
    }
 
    build_program_resource_list(ctx, prog);
-   return prog->LinkStatus;
+   return prog->data->LinkStatus;
 }
 
 /**
@@ -3055,7 +3091,7 @@ _mesa_glsl_link_shader(struct gl_context *ctx, struct gl_shader_program *prog)
 
    _mesa_clear_shader_program_data(ctx, prog);
 
-   prog->LinkStatus = GL_TRUE;
+   prog->data->LinkStatus = linking_success;
 
    for (i = 0; i < prog->NumShaders; i++) {
       if (!prog->Shaders[i]->CompileStatus) {
@@ -3063,26 +3099,40 @@ _mesa_glsl_link_shader(struct gl_context *ctx, struct gl_shader_program *prog)
       }
    }
 
-   if (prog->LinkStatus) {
+   if (prog->data->LinkStatus) {
       link_shaders(ctx, prog);
    }
 
-   if (prog->LinkStatus) {
+   if (prog->data->LinkStatus) {
+      /* Reset sampler validated to true, validation happens via the
+       * LinkShader call below.
+       */
+      prog->SamplersValidated = GL_TRUE;
+
       if (!ctx->Driver.LinkShader(ctx, prog)) {
-        prog->LinkStatus = GL_FALSE;
+         prog->data->LinkStatus = linking_failure;
       }
    }
 
+   /* Return early if we are loading the shader from on-disk cache */
+   if (prog->data->LinkStatus == linking_skipped)
+      return;
+
    if (ctx->_Shader->Flags & GLSL_DUMP) {
-      if (!prog->LinkStatus) {
+      if (!prog->data->LinkStatus) {
         fprintf(stderr, "GLSL shader program %d failed to link\n", prog->Name);
       }
 
-      if (prog->InfoLog && prog->InfoLog[0] != 0) {
+      if (prog->data->InfoLog && prog->data->InfoLog[0] != 0) {
         fprintf(stderr, "GLSL shader program %d info log:\n", prog->Name);
-        fprintf(stderr, "%s\n", prog->InfoLog);
+         fprintf(stderr, "%s\n", prog->data->InfoLog);
       }
    }
+
+#ifdef ENABLE_SHADER_CACHE
+   if (prog->data->LinkStatus)
+      shader_cache_write_program_metadata(ctx, prog);
+#endif
 }
 
 } /* extern "C" */