mesa/st: implement memory objects as a backend for buffer objects
[mesa.git] / src / mesa / program / ir_to_mesa.cpp
index 0089e80faa37d5c6e611e2646a9157d4b50b6e27..ac12b59d0751399c1889d381b5b6d50b711a717c 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;
 
@@ -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);
@@ -2364,10 +2409,8 @@ namespace {
 class add_uniform_to_shader : public program_resource_visitor {
 public:
    add_uniform_to_shader(struct gl_shader_program *shader_program,
-                        struct gl_program_parameter_list *params,
-                         gl_shader_stage shader_type)
-      : shader_program(shader_program), params(params), idx(-1),
-        shader_type(shader_type)
+                        struct gl_program_parameter_list *params)
+      : shader_program(shader_program), params(params), idx(-1)
    {
       /* empty */
    }
@@ -2375,6 +2418,7 @@ public:
    void process(ir_variable *var)
    {
       this->idx = -1;
+      this->var = var;
       this->program_resource_visitor::process(var);
       var->data.param_index = this->idx;
    }
@@ -2388,7 +2432,7 @@ private:
    struct gl_shader_program *shader_program;
    struct gl_program_parameter_list *params;
    int idx;
-   gl_shader_stage shader_type;
+   ir_variable *var;
 };
 
 } /* anonymous namespace */
@@ -2400,57 +2444,18 @@ 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())
+   /* opaque types don't use storage in the param list unless they are
+    * bindless samplers or images.
+    */
+   if (type->contains_opaque() && !var->data.bindless)
       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;
-   } else {
-      file = PROGRAM_UNIFORM;
-   }
-
-   int index = _mesa_lookup_parameter_index(params, name);
-   if (index < 0) {
-      index = _mesa_add_parameter(params, file, name, size, type->gl_type,
-                                 NULL, NULL);
-
-      /* Sampler uniform values are stored in prog->SamplerUnits,
-       * and the entry in that array is selected by this index we
-       * store in ParameterValues[].
-       */
-      if (file == PROGRAM_SAMPLER) {
-        unsigned location;
-        const bool found =
-           this->shader_program->UniformHash->get(location,
-                                                  params->Parameters[index].Name);
-        assert(found);
-
-        if (!found)
-           return;
+   assert(_mesa_lookup_parameter_index(params, name) < 0);
 
-        struct gl_uniform_storage *storage =
-            &this->shader_program->data->UniformStorage[location];
+   unsigned size = type_size(type) * 4;
 
-         assert(storage->type->is_sampler() &&
-                storage->opaque[shader_type].active);
-
-        for (unsigned int j = 0; j < size / 4; j++)
-            params->ParameterValues[index + j][0].f =
-               storage->opaque[shader_type].index + j;
-      }
-   }
+   int index = _mesa_add_parameter(params, PROGRAM_UNIFORM, name, size,
+                                   type->gl_type, NULL, NULL);
 
    /* The first part of the uniform that's processed determines the base
     * location of the whole uniform (for structures).
@@ -2474,7 +2479,7 @@ _mesa_generate_parameters_list_for_uniforms(struct gl_shader_program
                                            struct gl_program_parameter_list
                                            *params)
 {
-   add_uniform_to_shader add(shader_program, params, sh->Stage);
+   add_uniform_to_shader add(shader_program, params);
 
    foreach_in_list(ir_instruction, node, sh->ir) {
       ir_variable *var = node->as_variable();
@@ -2489,9 +2494,13 @@ _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 *prog,
+                                bool propagate_to_storage)
 {
+   struct gl_program_parameter_list *params = prog->Parameters;
+   gl_shader_stage shader_type = prog->info.stage;
+
    /* After adding each uniform to the parameter list, connect the storage for
     * the parameter with the tracking structure used by the API for the
     * uniform.
@@ -2499,15 +2508,15 @@ _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->data->UniformStorage[location];
@@ -2517,40 +2526,47 @@ _mesa_associate_uniform_storage(struct gl_context *ctx,
          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 +2574,49 @@ _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));
+         /* When a bindless sampler/image is bound to a texture/image unit, we
+          * have to overwrite the constant value by the resident handle
+          * directly in the constant buffer before the next draw. One solution
+          * is to keep track a pointer to the base of the data.
+          */
+         if (storage->is_bindless && (prog->sh.NumBindlessSamplers ||
+                                      prog->sh.NumBindlessImages)) {
+            unsigned array_elements = MAX2(1, storage->array_elements);
+
+            for (unsigned j = 0; j < array_elements; ++j) {
+               unsigned unit = storage->opaque[shader_type].index + j;
+
+               if (storage->type->without_array()->is_sampler()) {
+                  assert(unit >= 0 && unit < prog->sh.NumBindlessSamplers);
+                  prog->sh.BindlessSamplers[unit].data =
+                     &params->ParameterValues[i] + j;
+               } else if (storage->type->without_array()->is_image()) {
+                  assert(unit >= 0 && unit < prog->sh.NumBindlessImages);
+                  prog->sh.BindlessImages[unit].data =
+                     &params->ParameterValues[i] + j;
+               }
+            }
+         }
+
+         /* 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;
       }
    }
 }
@@ -2917,9 +2957,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. */
@@ -2927,15 +2966,13 @@ get_mesa_program(struct gl_context *ctx,
       prog->info.fs.depth_layout = shader_program->FragDepthLayout;
    }
 
-   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);
+   _mesa_associate_uniform_storage(ctx, shader_program, prog, true);
    if (!shader_program->data->LinkStatus) {
       goto fail_exit;
    }
@@ -3048,7 +3085,7 @@ _mesa_glsl_link_shader(struct gl_context *ctx, struct gl_shader_program *prog)
 
    _mesa_clear_shader_program_data(ctx, prog);
 
-   prog->data->LinkStatus = GL_TRUE;
+   prog->data->LinkStatus = linking_success;
 
    for (i = 0; i < prog->NumShaders; i++) {
       if (!prog->Shaders[i]->CompileStatus) {
@@ -3061,11 +3098,20 @@ _mesa_glsl_link_shader(struct gl_context *ctx, struct gl_shader_program *prog)
    }
 
    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->data->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->data->LinkStatus) {
         fprintf(stderr, "GLSL shader program %d failed to link\n", prog->Name);
@@ -3076,6 +3122,11 @@ _mesa_glsl_link_shader(struct gl_context *ctx, struct gl_shader_program *prog)
          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" */