llvmpipe: do constant buffer bounds checking in shaders
authorZack Rusin <zackr@vmware.com>
Thu, 19 Dec 2013 00:16:07 +0000 (19:16 -0500)
committerZack Rusin <zackr@vmware.com>
Thu, 16 Jan 2014 21:33:57 +0000 (16:33 -0500)
It's possible to bind a smaller buffer as a constant buffer, than
what the shader actually uses/requires. This could cause nasty
crashes. This patch adds the architecture to pass the maximum
allowable constant buffer index to the jit to let it make
sure that the constant buffer indices are always within bounds.
The behavior follows the d3d10 spec, which says the overflow
should always return all zeros, and overflow is only defined
as access beyond the size of the currently bound buffer. Accesses
beyond the declared shader constant register size are not
considered an overflow and expected to return garbage but consistent
garbage (we follow the behavior which some wlk tests expect which
is to return the actual values from the bound buffer).

Signed-off-by: Zack Rusin <zackr@vmware.com>
Reviewed-by: Jose Fonseca <jfonseca@vmware.com>
Reviewed-by: Brian Paul <brianp@vmware.com>
Reviewed-by: Roland Scheidegger <sroland@vmware.com>
src/gallium/auxiliary/draw/draw_llvm.c
src/gallium/auxiliary/draw/draw_llvm.h
src/gallium/auxiliary/draw/draw_pt_fetch_shade_pipeline_llvm.c
src/gallium/auxiliary/gallivm/lp_bld_tgsi.h
src/gallium/auxiliary/gallivm/lp_bld_tgsi_soa.c
src/gallium/drivers/llvmpipe/lp_jit.c
src/gallium/drivers/llvmpipe/lp_jit.h
src/gallium/drivers/llvmpipe/lp_setup.c
src/gallium/drivers/llvmpipe/lp_state_fs.c

index 331039aad6e4cbc1bf48e08578d725faee35ac78..0bbb6804984e86519ccd4a97be59f4541582b115 100644 (file)
@@ -242,17 +242,20 @@ create_jit_context_type(struct gallivm_state *gallivm,
 {
    LLVMTargetDataRef target = gallivm->target;
    LLVMTypeRef float_type = LLVMFloatTypeInContext(gallivm->context);
+   LLVMTypeRef int_type = LLVMInt32TypeInContext(gallivm->context);
    LLVMTypeRef elem_types[DRAW_JIT_CTX_NUM_FIELDS];
    LLVMTypeRef context_type;
 
    elem_types[0] = LLVMArrayType(LLVMPointerType(float_type, 0), /* vs_constants */
                                  LP_MAX_TGSI_CONST_BUFFERS);
-   elem_types[1] = LLVMPointerType(LLVMArrayType(LLVMArrayType(float_type, 4),
+   elem_types[1] = LLVMArrayType(int_type, /* num_vs_constants */
+                                 LP_MAX_TGSI_CONST_BUFFERS);
+   elem_types[2] = LLVMPointerType(LLVMArrayType(LLVMArrayType(float_type, 4),
                                                  DRAW_TOTAL_CLIP_PLANES), 0);
-   elem_types[2] = LLVMPointerType(float_type, 0); /* viewport */
-   elem_types[3] = LLVMArrayType(texture_type,
+   elem_types[3] = LLVMPointerType(float_type, 0); /* viewport */
+   elem_types[4] = LLVMArrayType(texture_type,
                                  PIPE_MAX_SHADER_SAMPLER_VIEWS); /* textures */
-   elem_types[4] = LLVMArrayType(sampler_type,
+   elem_types[5] = LLVMArrayType(sampler_type,
                                  PIPE_MAX_SAMPLERS); /* samplers */
    context_type = LLVMStructTypeInContext(gallivm->context, elem_types,
                                           Elements(elem_types), 0);
@@ -264,6 +267,8 @@ create_jit_context_type(struct gallivm_state *gallivm,
 
    LP_CHECK_MEMBER_OFFSET(struct draw_jit_context, vs_constants,
                           target, context_type, DRAW_JIT_CTX_CONSTANTS);
+   LP_CHECK_MEMBER_OFFSET(struct draw_jit_context, num_vs_constants,
+                          target, context_type, DRAW_JIT_CTX_NUM_CONSTANTS);
    LP_CHECK_MEMBER_OFFSET(struct draw_jit_context, planes,
                           target, context_type, DRAW_JIT_CTX_PLANES);
    LP_CHECK_MEMBER_OFFSET(struct draw_jit_context, viewport,
@@ -298,20 +303,22 @@ create_gs_jit_context_type(struct gallivm_state *gallivm,
 
    elem_types[0] = LLVMArrayType(LLVMPointerType(float_type, 0), /* constants */
                                  LP_MAX_TGSI_CONST_BUFFERS);
-   elem_types[1] = LLVMPointerType(LLVMArrayType(LLVMArrayType(float_type, 4),
+   elem_types[1] = LLVMArrayType(int_type, /* num_constants */
+                                 LP_MAX_TGSI_CONST_BUFFERS);
+   elem_types[2] = LLVMPointerType(LLVMArrayType(LLVMArrayType(float_type, 4),
                                                  DRAW_TOTAL_CLIP_PLANES), 0);
-   elem_types[2] = LLVMPointerType(float_type, 0); /* viewport */
+   elem_types[3] = LLVMPointerType(float_type, 0); /* viewport */
 
-   elem_types[3] = LLVMArrayType(texture_type,
+   elem_types[4] = LLVMArrayType(texture_type,
                                  PIPE_MAX_SHADER_SAMPLER_VIEWS); /* textures */
-   elem_types[4] = LLVMArrayType(sampler_type,
+   elem_types[5] = LLVMArrayType(sampler_type,
                                  PIPE_MAX_SAMPLERS); /* samplers */
    
-   elem_types[5] = LLVMPointerType(LLVMPointerType(int_type, 0), 0);
-   elem_types[6] = LLVMPointerType(LLVMVectorType(int_type,
-                                                  vector_length), 0);
+   elem_types[6] = LLVMPointerType(LLVMPointerType(int_type, 0), 0);
    elem_types[7] = LLVMPointerType(LLVMVectorType(int_type,
                                                   vector_length), 0);
+   elem_types[8] = LLVMPointerType(LLVMVectorType(int_type,
+                                                  vector_length), 0);
 
    context_type = LLVMStructTypeInContext(gallivm->context, elem_types,
                                           Elements(elem_types), 0);
@@ -323,6 +330,8 @@ create_gs_jit_context_type(struct gallivm_state *gallivm,
 
    LP_CHECK_MEMBER_OFFSET(struct draw_gs_jit_context, constants,
                           target, context_type, DRAW_GS_JIT_CTX_CONSTANTS);
+   LP_CHECK_MEMBER_OFFSET(struct draw_gs_jit_context, num_constants,
+                          target, context_type, DRAW_GS_JIT_CTX_NUM_CONSTANTS);
    LP_CHECK_MEMBER_OFFSET(struct draw_gs_jit_context, planes,
                           target, context_type, DRAW_GS_JIT_CTX_PLANES);
    LP_CHECK_MEMBER_OFFSET(struct draw_gs_jit_context, viewport,
@@ -617,7 +626,10 @@ generate_vs(struct draw_llvm_variant *variant,
 {
    struct draw_llvm *llvm = variant->llvm;
    const struct tgsi_token *tokens = llvm->draw->vs.vertex_shader->state.tokens;
-   LLVMValueRef consts_ptr = draw_jit_context_vs_constants(variant->gallivm, context_ptr);
+   LLVMValueRef consts_ptr =
+      draw_jit_context_vs_constants(variant->gallivm, context_ptr);
+   LLVMValueRef num_consts_ptr =
+      draw_jit_context_num_vs_constants(variant->gallivm, context_ptr);
    struct lp_build_sampler_soa *sampler = 0;
 
    if (gallivm_debug & (GALLIVM_DEBUG_TGSI | GALLIVM_DEBUG_IR)) {
@@ -633,6 +645,7 @@ generate_vs(struct draw_llvm_variant *variant,
                      vs_type,
                      NULL /*struct lp_build_mask_context *mask*/,
                      consts_ptr,
+                     num_consts_ptr,
                      system_values,
                      inputs,
                      outputs,
@@ -2089,7 +2102,7 @@ draw_gs_llvm_generate(struct draw_llvm *llvm,
    unsigned i;
    struct draw_gs_llvm_iface gs_iface;
    const struct tgsi_token *tokens = variant->shader->base.state.tokens;
-   LLVMValueRef consts_ptr;
+   LLVMValueRef consts_ptr, num_consts_ptr;
    LLVMValueRef outputs[PIPE_MAX_SHADER_OUTPUTS][TGSI_NUM_CHANNELS];
    struct lp_build_mask_context mask;
    const struct tgsi_shader_info *gs_info = &variant->shader->base.info;
@@ -2163,6 +2176,8 @@ draw_gs_llvm_generate(struct draw_llvm *llvm,
    gs_type.length = vector_length;
 
    consts_ptr = draw_gs_jit_context_constants(variant->gallivm, context_ptr);
+   num_consts_ptr =
+      draw_gs_jit_context_num_constants(variant->gallivm, context_ptr);
 
    /* code generated texture sampling */
    sampler = draw_llvm_sampler_soa_create(variant->key.samplers,
@@ -2185,6 +2200,7 @@ draw_gs_llvm_generate(struct draw_llvm *llvm,
                      gs_type,
                      &mask,
                      consts_ptr,
+                     num_consts_ptr,
                      &system_values,
                      NULL,
                      outputs,
index 1d238a2a9c2a75c90dcba803d4503c1d4b84f78d..2e465b2239c67e739172ddea1c90e7eddd5544f2 100644 (file)
@@ -123,6 +123,7 @@ enum {
 struct draw_jit_context
 {
    const float *vs_constants[LP_MAX_TGSI_CONST_BUFFERS];
+   int num_vs_constants[LP_MAX_TGSI_CONST_BUFFERS];
    float (*planes) [DRAW_TOTAL_CLIP_PLANES][4];
    float *viewport;
 
@@ -131,17 +132,21 @@ struct draw_jit_context
 };
 
 enum {
-   DRAW_JIT_CTX_CONSTANTS   = 0,
-   DRAW_JIT_CTX_PLANES      = 1,
-   DRAW_JIT_CTX_VIEWPORT    = 2,
-   DRAW_JIT_CTX_TEXTURES    = 3,
-   DRAW_JIT_CTX_SAMPLERS    = 4,
+   DRAW_JIT_CTX_CONSTANTS            = 0,
+   DRAW_JIT_CTX_NUM_CONSTANTS        = 1,
+   DRAW_JIT_CTX_PLANES               = 2,
+   DRAW_JIT_CTX_VIEWPORT             = 3,
+   DRAW_JIT_CTX_TEXTURES             = 4,
+   DRAW_JIT_CTX_SAMPLERS             = 5,
    DRAW_JIT_CTX_NUM_FIELDS
 };
 
 #define draw_jit_context_vs_constants(_gallivm, _ptr) \
    lp_build_struct_get_ptr(_gallivm, _ptr, DRAW_JIT_CTX_CONSTANTS, "vs_constants")
 
+#define draw_jit_context_num_vs_constants(_gallivm, _ptr) \
+   lp_build_struct_get_ptr(_gallivm, _ptr, DRAW_JIT_CTX_NUM_CONSTANTS, "num_vs_constants")
+
 #define draw_jit_context_planes(_gallivm, _ptr) \
    lp_build_struct_get(_gallivm, _ptr, DRAW_JIT_CTX_PLANES, "planes")
 
@@ -200,6 +205,7 @@ enum {
 struct draw_gs_jit_context
 {
    const float *constants[LP_MAX_TGSI_CONST_BUFFERS];
+   int num_constants[LP_MAX_TGSI_CONST_BUFFERS];
    float (*planes) [DRAW_TOTAL_CLIP_PLANES][4];
    float *viewport;
 
@@ -215,23 +221,27 @@ struct draw_gs_jit_context
 
 enum {
    DRAW_GS_JIT_CTX_CONSTANTS = 0,
-   DRAW_GS_JIT_CTX_PLANES = 1,
-   DRAW_GS_JIT_CTX_VIEWPORT = 2,
+   DRAW_GS_JIT_CTX_NUM_CONSTANTS = 1,
+   DRAW_GS_JIT_CTX_PLANES = 2,
+   DRAW_GS_JIT_CTX_VIEWPORT = 3,
    /* Textures and samples are reserved for DRAW_JIT_CTX_TEXTURES
     * and DRAW_JIT_CTX_SAMPLERS, because they both need
     * to be at exactly the same locations as they are in the
     * VS ctx structure for sampling to work. */
    DRAW_GS_JIT_CTX_TEXTURES = DRAW_JIT_CTX_TEXTURES,
    DRAW_GS_JIT_CTX_SAMPLERS = DRAW_JIT_CTX_SAMPLERS,
-   DRAW_GS_JIT_CTX_PRIM_LENGTHS = 5,
-   DRAW_GS_JIT_CTX_EMITTED_VERTICES = 6,
-   DRAW_GS_JIT_CTX_EMITTED_PRIMS = 7,
-   DRAW_GS_JIT_CTX_NUM_FIELDS = 8
+   DRAW_GS_JIT_CTX_PRIM_LENGTHS = 6,
+   DRAW_GS_JIT_CTX_EMITTED_VERTICES = 7,
+   DRAW_GS_JIT_CTX_EMITTED_PRIMS = 8,
+   DRAW_GS_JIT_CTX_NUM_FIELDS = 9
 };
 
 #define draw_gs_jit_context_constants(_gallivm, _ptr) \
    lp_build_struct_get_ptr(_gallivm, _ptr, DRAW_GS_JIT_CTX_CONSTANTS, "constants")
 
+#define draw_gs_jit_context_num_constants(_gallivm, _ptr) \
+   lp_build_struct_get_ptr(_gallivm, _ptr, DRAW_GS_JIT_CTX_NUM_CONSTANTS, "num_constants")
+
 #define draw_gs_jit_context_planes(_gallivm, _ptr) \
    lp_build_struct_get(_gallivm, _ptr, DRAW_GS_JIT_CTX_PLANES, "planes")
 
index 9f172418544c6f1911ae4d1a0ea48e21c15d898f..846e1d58052e2d9529533e8dc39cc2352e8e662b 100644 (file)
@@ -262,10 +262,16 @@ llvm_middle_end_bind_parameters(struct draw_pt_middle_end *middle)
    unsigned i;
 
    for (i = 0; i < Elements(fpme->llvm->jit_context.vs_constants); ++i) {
+      int num_consts =
+         draw->pt.user.vs_constants_size[i] / (sizeof(float) * 4);
       fpme->llvm->jit_context.vs_constants[i] = draw->pt.user.vs_constants[i];
+      fpme->llvm->jit_context.num_vs_constants[i] = num_consts;
    }
    for (i = 0; i < Elements(fpme->llvm->gs_jit_context.constants); ++i) {
+      int num_consts =
+         draw->pt.user.gs_constants_size[i] / (sizeof(float) * 4);
       fpme->llvm->gs_jit_context.constants[i] = draw->pt.user.gs_constants[i];
+      fpme->llvm->gs_jit_context.num_constants[i] = num_consts;
    }
 
    fpme->llvm->jit_context.planes =
index 881cd5ba829ddd0e80d2919b5c06ec1cd8c7ffbd..4f988b8fa4d4d9c6f0fd999617002f20f96c6e79 100644 (file)
@@ -225,6 +225,7 @@ lp_build_tgsi_soa(struct gallivm_state *gallivm,
                   struct lp_type type,
                   struct lp_build_mask_context *mask,
                   LLVMValueRef consts_ptr,
+                  LLVMValueRef const_sizes_ptr,
                   const struct lp_bld_tgsi_system_values *system_values,
                   const LLVMValueRef (*inputs)[4],
                   LLVMValueRef (*outputs)[4],
@@ -433,6 +434,7 @@ struct lp_build_tgsi_soa_context
    LLVMValueRef max_output_vertices_vec;
 
    LLVMValueRef consts_ptr;
+   LLVMValueRef const_sizes_ptr;
    const LLVMValueRef (*inputs)[TGSI_NUM_CHANNELS];
    LLVMValueRef (*outputs)[TGSI_NUM_CHANNELS];
 
index 6d8dc8c6f1977731ef19a01895216efe96130251..d9b21f831ca7ff2179b0c060d28db97575d3f00c 100644 (file)
@@ -789,11 +789,19 @@ gather_outputs(struct lp_build_tgsi_soa_context * bld)
 static LLVMValueRef
 build_gather(struct lp_build_context *bld,
              LLVMValueRef base_ptr,
-             LLVMValueRef indexes)
+             LLVMValueRef indexes,
+             LLVMValueRef *overflow_mask)
 {
    LLVMBuilderRef builder = bld->gallivm->builder;
    LLVMValueRef res = bld->undef;
    unsigned i;
+   LLVMValueRef temp_ptr;
+
+   if (overflow_mask) {
+      temp_ptr = lp_build_alloca(
+         bld->gallivm,
+         lp_build_vec_type(bld->gallivm, bld->type), "");
+   }
 
    /*
     * Loop over elements of index_vec, load scalar value, insert it into 'res'.
@@ -802,11 +810,54 @@ build_gather(struct lp_build_context *bld,
       LLVMValueRef ii = lp_build_const_int32(bld->gallivm, i);
       LLVMValueRef index = LLVMBuildExtractElement(builder,
                                                    indexes, ii, "");
-      LLVMValueRef scalar_ptr = LLVMBuildGEP(builder, base_ptr,
-                                             &index, 1, "gather_ptr");
-      LLVMValueRef scalar = LLVMBuildLoad(builder, scalar_ptr, "");
+      LLVMValueRef scalar_ptr, scalar;
+      LLVMValueRef overflow;
+      struct lp_build_if_state if_ctx;
+
+      /*
+       * overflow_mask is a boolean vector telling us which channels
+       * in the vector overflowed. We use the overflow behavior for
+       * constant buffers which is defined as:
+       * Out of bounds access to constant buffer returns 0 in all
+       * componenets. Out of bounds behavior is always with respect
+       * to the size of the buffer bound at that slot.
+       */
+      if (overflow_mask) {
+         overflow = LLVMBuildExtractElement(builder, *overflow_mask,
+                                            ii, "");
+         lp_build_if(&if_ctx, bld->gallivm, overflow);
+         {
+            LLVMValueRef val = LLVMBuildLoad(builder, temp_ptr, "");
+            val = LLVMBuildInsertElement(
+               builder, val,
+               LLVMConstNull(LLVMFloatTypeInContext(bld->gallivm->context)),
+               ii, "");
+            LLVMBuildStore(builder, val, temp_ptr);
+         }
+         lp_build_else(&if_ctx);
+         {
+            LLVMValueRef val = LLVMBuildLoad(builder, temp_ptr, "");
+
+            scalar_ptr = LLVMBuildGEP(builder, base_ptr,
+                                      &index, 1, "gather_ptr");
+            scalar = LLVMBuildLoad(builder, scalar_ptr, "");
+
+            val = LLVMBuildInsertElement(builder, val, scalar, ii, "");
 
-      res = LLVMBuildInsertElement(builder, res, scalar, ii, "");
+            LLVMBuildStore(builder, val, temp_ptr);
+         }
+         lp_build_endif(&if_ctx);
+      } else {
+         scalar_ptr = LLVMBuildGEP(builder, base_ptr,
+                                   &index, 1, "gather_ptr");
+         scalar = LLVMBuildLoad(builder, scalar_ptr, "");
+
+         res = LLVMBuildInsertElement(builder, res, scalar, ii, "");
+      }
+   }
+
+   if (overflow_mask) {
+      res = LLVMBuildLoad(builder, temp_ptr, "gather_val");
    }
 
    return res;
@@ -912,12 +963,23 @@ get_indirect_index(struct lp_build_tgsi_soa_context *bld,
 
    index = lp_build_add(uint_bld, base, rel);
 
-   max_index = lp_build_const_int_vec(bld->bld_base.base.gallivm,
-                                      uint_bld->type,
-                                      bld->bld_base.info->file_max[reg_file]);
+   /*
+    * emit_fetch_constant handles constant buffer overflow so this code
+    * is pointless for them.
+    * Furthermore the D3D10 spec in section 6.5 says:
+    * If the constant buffer bound to a slot is larger than the size
+    * declared in the shader for that slot, implementations are allowed
+    * to return incorrect data (not necessarily 0) for indices that are
+    * larger than the declared size but smaller than the buffer size.
+    */
+   if (reg_file != TGSI_FILE_CONSTANT) {
+      max_index = lp_build_const_int_vec(bld->bld_base.base.gallivm,
+                                         uint_bld->type,
+                                         bld->bld_base.info->file_max[reg_file]);
 
-   assert(!uint_bld->type.sign);
-   index = lp_build_min(uint_bld, index, max_index);
+      assert(!uint_bld->type.sign);
+      index = lp_build_min(uint_bld, index, max_index);
+   }
 
    return index;
 }
@@ -996,6 +1058,7 @@ emit_fetch_constant(
    unsigned dimension = 0;
    LLVMValueRef dimension_index;
    LLVMValueRef consts_ptr;
+   LLVMValueRef num_consts;
    LLVMValueRef res;
 
    /* XXX: Handle fetching xyzw components as a vector */
@@ -1008,25 +1071,40 @@ emit_fetch_constant(
    }
 
    dimension_index = lp_build_const_int32(gallivm, dimension);
-   consts_ptr = lp_build_array_get(gallivm, bld->consts_ptr, dimension_index);
+   consts_ptr =
+      lp_build_array_get(gallivm, bld->consts_ptr, dimension_index);
+   num_consts =
+      lp_build_array_get(gallivm, bld->const_sizes_ptr, dimension_index);
 
    if (reg->Register.Indirect) {
       LLVMValueRef indirect_index;
       LLVMValueRef swizzle_vec =
          lp_build_const_int_vec(gallivm, uint_bld->type, swizzle);
       LLVMValueRef index_vec;  /* index into the const buffer */
+      LLVMValueRef overflow_mask;
 
       indirect_index = get_indirect_index(bld,
                                           reg->Register.File,
                                           reg->Register.Index,
                                           &reg->Indirect);
 
+      /* All fetches are from the same constant buffer, so
+       * we need to propagate the size to a vector to do a
+       * vector comparison */
+      num_consts = lp_build_broadcast_scalar(uint_bld, num_consts);
+      /* Construct a boolean vector telling us which channels
+       * overflow the bound constant buffer */
+      overflow_mask = LLVMBuildICmp(builder, LLVMIntUGE,
+                                    indirect_index,
+                                    num_consts, "");
+
       /* index_vec = indirect_index * 4 + swizzle */
       index_vec = lp_build_shl_imm(uint_bld, indirect_index, 2);
       index_vec = lp_build_add(uint_bld, index_vec, swizzle_vec);
 
       /* Gather values from the constant buffer */
-      res = build_gather(&bld_base->base, consts_ptr, index_vec);
+      res = build_gather(&bld_base->base, consts_ptr, index_vec,
+                         &overflow_mask);
    }
    else {
       LLVMValueRef index;  /* index into the const buffer */
@@ -1044,6 +1122,7 @@ emit_fetch_constant(
       struct lp_build_context *bld_fetch = stype_to_fetch(bld_base, stype);
       res = LLVMBuildBitCast(builder, res, bld_fetch->vec_type, "");
    }
+
    return res;
 }
 
@@ -1085,7 +1164,7 @@ emit_fetch_immediate(
       imms_array = LLVMBuildBitCast(builder, bld->imms_array, fptr_type, "");
 
       /* Gather values from the immediate register array */
-      res = build_gather(&bld_base->base, imms_array, index_vec);
+      res = build_gather(&bld_base->base, imms_array, index_vec, NULL);
    }
    else {
       res = bld->immediates[reg->Register.Index][swizzle];
@@ -1132,7 +1211,7 @@ emit_fetch_input(
       inputs_array = LLVMBuildBitCast(builder, bld->inputs_array, fptr_type, "");
 
       /* Gather values from the input register array */
-      res = build_gather(&bld_base->base, inputs_array, index_vec);
+      res = build_gather(&bld_base->base, inputs_array, index_vec, NULL);
    } else {
       if (bld->indirect_files & (1 << TGSI_FILE_INPUT)) {
          LLVMValueRef lindex = lp_build_const_int32(gallivm,
@@ -1242,7 +1321,7 @@ emit_fetch_temporary(
       temps_array = LLVMBuildBitCast(builder, bld->temps_array, fptr_type, "");
 
       /* Gather values from the temporary register array */
-      res = build_gather(&bld_base->base, temps_array, index_vec);
+      res = build_gather(&bld_base->base, temps_array, index_vec, NULL);
    }
    else {
       LLVMValueRef temp_ptr;
@@ -3352,6 +3431,7 @@ lp_build_tgsi_soa(struct gallivm_state *gallivm,
                   struct lp_type type,
                   struct lp_build_mask_context *mask,
                   LLVMValueRef consts_ptr,
+                  LLVMValueRef const_sizes_ptr,
                   const struct lp_bld_tgsi_system_values *system_values,
                   const LLVMValueRef (*inputs)[TGSI_NUM_CHANNELS],
                   LLVMValueRef (*outputs)[TGSI_NUM_CHANNELS],
@@ -3379,6 +3459,7 @@ lp_build_tgsi_soa(struct gallivm_state *gallivm,
    bld.inputs = inputs;
    bld.outputs = outputs;
    bld.consts_ptr = consts_ptr;
+   bld.const_sizes_ptr = const_sizes_ptr;
    bld.sampler = sampler;
    bld.bld_base.info = info;
    bld.indirect_files = info->indirect_files;
index fa36fd3512e220acaaab5f0aeb3e8b6485d45f30..075bd148e884839f5575b5aa45e7fd29bf0dde3c 100644 (file)
@@ -166,7 +166,9 @@ lp_jit_create_types(struct lp_fragment_shader_variant *lp)
       LLVMTypeRef context_type;
 
       elem_types[LP_JIT_CTX_CONSTANTS] =
-            LLVMArrayType(LLVMPointerType(LLVMFloatTypeInContext(lc), 0), LP_MAX_TGSI_CONST_BUFFERS);
+         LLVMArrayType(LLVMPointerType(LLVMFloatTypeInContext(lc), 0), LP_MAX_TGSI_CONST_BUFFERS);
+      elem_types[LP_JIT_CTX_NUM_CONSTANTS] =
+            LLVMArrayType(LLVMInt32TypeInContext(lc), LP_MAX_TGSI_CONST_BUFFERS);
       elem_types[LP_JIT_CTX_ALPHA_REF] = LLVMFloatTypeInContext(lc);
       elem_types[LP_JIT_CTX_STENCIL_REF_FRONT] =
       elem_types[LP_JIT_CTX_STENCIL_REF_BACK] = LLVMInt32TypeInContext(lc);
@@ -190,6 +192,9 @@ lp_jit_create_types(struct lp_fragment_shader_variant *lp)
       LP_CHECK_MEMBER_OFFSET(struct lp_jit_context, constants,
                              gallivm->target, context_type,
                              LP_JIT_CTX_CONSTANTS);
+      LP_CHECK_MEMBER_OFFSET(struct lp_jit_context, num_constants,
+                             gallivm->target, context_type,
+                             LP_JIT_CTX_NUM_CONSTANTS);
       LP_CHECK_MEMBER_OFFSET(struct lp_jit_context, alpha_ref_value,
                              gallivm->target, context_type,
                              LP_JIT_CTX_ALPHA_REF);
index 8eefa7c8479a3eb2562cfc6a222e27f64d094ed1..1325a8cc4829146dd93aee60180646588e7a87e8 100644 (file)
@@ -121,6 +121,7 @@ enum {
 struct lp_jit_context
 {
    const float *constants[LP_MAX_TGSI_CONST_BUFFERS];
+   int num_constants[LP_MAX_TGSI_CONST_BUFFERS];
 
    float alpha_ref_value;
 
@@ -142,6 +143,7 @@ struct lp_jit_context
  */
 enum {
    LP_JIT_CTX_CONSTANTS = 0,
+   LP_JIT_CTX_NUM_CONSTANTS,
    LP_JIT_CTX_ALPHA_REF,
    LP_JIT_CTX_STENCIL_REF_FRONT,
    LP_JIT_CTX_STENCIL_REF_BACK,
@@ -157,6 +159,9 @@ enum {
 #define lp_jit_context_constants(_gallivm, _ptr) \
    lp_build_struct_get_ptr(_gallivm, _ptr, LP_JIT_CTX_CONSTANTS, "constants")
 
+#define lp_jit_context_num_constants(_gallivm, _ptr) \
+   lp_build_struct_get_ptr(_gallivm, _ptr, LP_JIT_CTX_NUM_CONSTANTS, "num_constants")
+
 #define lp_jit_context_alpha_ref_value(_gallivm, _ptr) \
    lp_build_struct_get(_gallivm, _ptr, LP_JIT_CTX_ALPHA_REF, "alpha_ref_value")
 
index 7f2223129aa0121481900b3c581c6985a82b9357..58811b0edd38e8bf5b8cc6f481b03fd6fb40137a 100644 (file)
@@ -984,6 +984,7 @@ try_update_scene_state( struct lp_setup_context *setup )
          struct pipe_resource *buffer = setup->constants[i].current.buffer;
          const unsigned current_size = setup->constants[i].current.buffer_size;
          const ubyte *current_data = NULL;
+         int num_constants;
 
          if (buffer) {
             /* resource buffer */
@@ -1024,7 +1025,11 @@ try_update_scene_state( struct lp_setup_context *setup )
             setup->constants[i].stored_data = NULL;
          }
 
-         setup->fs.current.jit_context.constants[i] = setup->constants[i].stored_data;
+         setup->fs.current.jit_context.constants[i] =
+            setup->constants[i].stored_data;
+         num_constants =
+            setup->constants[i].stored_size / (sizeof(float) * 4);
+         setup->fs.current.jit_context.num_constants[i] = num_constants;
          setup->dirty |= LP_SETUP_NEW_FS;
       }
    }
index eedafa368384bf2081a6abba8eda39a4435bde4d..31ed8478e9be93d1a316540bb5a38d04686d6225 100644 (file)
@@ -262,7 +262,7 @@ generate_fs_loop(struct gallivm_state *gallivm,
    const struct tgsi_token *tokens = shader->base.tokens;
    LLVMTypeRef vec_type;
    LLVMValueRef mask_ptr, mask_val;
-   LLVMValueRef consts_ptr;
+   LLVMValueRef consts_ptr, num_consts_ptr;
    LLVMValueRef z;
    LLVMValueRef z_value, s_value;
    LLVMValueRef z_fb, s_fb;
@@ -336,6 +336,7 @@ generate_fs_loop(struct gallivm_state *gallivm,
    vec_type = lp_build_vec_type(gallivm, type);
 
    consts_ptr = lp_jit_context_constants(gallivm, context_ptr);
+   num_consts_ptr = lp_jit_context_num_constants(gallivm, context_ptr);
 
    lp_build_for_loop_begin(&loop_state, gallivm,
                            lp_build_const_int32(gallivm, 0),
@@ -414,7 +415,7 @@ generate_fs_loop(struct gallivm_state *gallivm,
 
    /* Build the actual shader */
    lp_build_tgsi_soa(gallivm, tokens, type, &mask,
-                     consts_ptr, &system_values,
+                     consts_ptr, num_consts_ptr, &system_values,
                      interp->inputs,
                      outputs, sampler, &shader->info.base, NULL);