llvmpipe: add fragment shader image support
authorDave Airlie <airlied@redhat.com>
Sat, 20 Jul 2019 04:28:23 +0000 (14:28 +1000)
committerDave Airlie <airlied@redhat.com>
Tue, 27 Aug 2019 02:30:04 +0000 (12:30 +1000)
Reviewed-by: Roland Scheidegger <sroland@vmware.com>
src/gallium/drivers/llvmpipe/lp_context.h
src/gallium/drivers/llvmpipe/lp_setup.c
src/gallium/drivers/llvmpipe/lp_setup.h
src/gallium/drivers/llvmpipe/lp_setup_context.h
src/gallium/drivers/llvmpipe/lp_state.h
src/gallium/drivers/llvmpipe/lp_state_derived.c
src/gallium/drivers/llvmpipe/lp_state_fs.c
src/gallium/drivers/llvmpipe/lp_state_fs.h
src/gallium/drivers/llvmpipe/lp_tex_sample.c
src/gallium/drivers/llvmpipe/lp_tex_sample.h
src/gallium/drivers/llvmpipe/lp_texture.c

index 8127b16261bc99bb78e98d429edd2f66d873b126..889228861d7caa0f9473b94128434b6c6c0b28ee 100644 (file)
@@ -83,9 +83,11 @@ struct llvmpipe_context {
    struct pipe_vertex_buffer vertex_buffer[PIPE_MAX_ATTRIBS];
 
    struct pipe_shader_buffer ssbos[PIPE_SHADER_TYPES][LP_MAX_TGSI_SHADER_BUFFERS];
+   struct pipe_image_view images[PIPE_SHADER_TYPES][LP_MAX_TGSI_SHADER_IMAGES];
 
    unsigned num_samplers[PIPE_SHADER_TYPES];
    unsigned num_sampler_views[PIPE_SHADER_TYPES];
+   unsigned num_images[PIPE_SHADER_TYPES];
 
    unsigned num_vertex_buffers;
 
index a3c9960bcafdb08f934cad266a528d2b7b9aa272..e6fa082f4f005007acf67fa70503d67fa78e3658 100644 (file)
@@ -684,6 +684,77 @@ lp_setup_set_fs_ssbos(struct lp_setup_context *setup,
    setup->dirty |= LP_SETUP_NEW_SSBOS;
 }
 
+void
+lp_setup_set_fs_images(struct lp_setup_context *setup,
+                       unsigned num,
+                       struct pipe_image_view *images)
+{
+   unsigned i;
+
+   LP_DBG(DEBUG_SETUP, "%s %p\n", __FUNCTION__, (void *) images);
+
+   assert(num <= ARRAY_SIZE(setup->images));
+
+   for (i = 0; i < num; ++i) {
+      struct pipe_image_view *image = &images[i];
+      util_copy_image_view(&setup->images[i].current, &images[i]);
+
+      struct pipe_resource *res = image->resource;
+      struct llvmpipe_resource *lp_res = llvmpipe_resource(res);
+      struct lp_jit_image *jit_image;
+
+      jit_image = &setup->fs.current.jit_context.images[i];
+      if (!lp_res)
+         continue;
+      if (!lp_res->dt) {
+         /* regular texture - setup array of mipmap level offsets */
+         if (llvmpipe_resource_is_texture(res)) {
+            jit_image->base = lp_res->tex_data;
+         } else
+            jit_image->base = lp_res->data;
+
+         jit_image->width = res->width0;
+         jit_image->height = res->height0;
+         jit_image->depth = res->depth0;
+
+         if (llvmpipe_resource_is_texture(res)) {
+            uint32_t mip_offset = lp_res->mip_offsets[image->u.tex.level];
+
+            jit_image->width = u_minify(jit_image->width, image->u.tex.level);
+            jit_image->height = u_minify(jit_image->height, image->u.tex.level);
+
+            if (res->target == PIPE_TEXTURE_1D_ARRAY ||
+                res->target == PIPE_TEXTURE_2D_ARRAY ||
+                res->target == PIPE_TEXTURE_3D ||
+                res->target == PIPE_TEXTURE_CUBE ||
+                res->target == PIPE_TEXTURE_CUBE_ARRAY) {
+               /*
+                * For array textures, we don't have first_layer, instead
+                * adjust last_layer (stored as depth) plus the mip level offsets
+                * (as we have mip-first layout can't just adjust base ptr).
+                * XXX For mip levels, could do something similar.
+                */
+               jit_image->depth = image->u.tex.last_layer - image->u.tex.first_layer + 1;
+               mip_offset += image->u.tex.first_layer * lp_res->img_stride[image->u.tex.level];
+            } else
+               jit_image->depth = u_minify(jit_image->depth, image->u.tex.level);
+
+            jit_image->row_stride = lp_res->row_stride[image->u.tex.level];
+            jit_image->img_stride = lp_res->img_stride[image->u.tex.level];
+            jit_image->base = (uint8_t *)jit_image->base + mip_offset;
+         }
+         else {
+            unsigned view_blocksize = util_format_get_blocksize(image->format);
+            jit_image->width = image->u.buf.size / view_blocksize;
+            jit_image->base = (uint8_t *)jit_image->base + image->u.buf.offset;
+         }
+      }
+   }
+   for (; i < ARRAY_SIZE(setup->images); i++) {
+      util_copy_image_view(&setup->images[i].current, NULL);
+   }
+   setup->dirty |= LP_SETUP_NEW_IMAGES;
+}
 
 void
 lp_setup_set_alpha_ref_value( struct lp_setup_context *setup,
@@ -1017,6 +1088,11 @@ lp_setup_is_resource_referenced( const struct lp_setup_context *setup,
          return LP_REFERENCED_FOR_READ | LP_REFERENCED_FOR_WRITE;
    }
 
+   for (i = 0; i < ARRAY_SIZE(setup->images); i++) {
+      if (setup->images[i].current.resource == texture)
+         return LP_REFERENCED_FOR_READ | LP_REFERENCED_FOR_WRITE;
+   }
+
    return LP_UNREFERENCED;
 }
 
index 7ee50718b66e18f1f644c6a43f29021a99a1af23..ccf67fe2b272e9aab42d12b92d49044314b2e105 100644 (file)
@@ -109,6 +109,11 @@ lp_setup_set_fs_ssbos(struct lp_setup_context *setup,
                       unsigned num,
                       struct pipe_shader_buffer *buffers);
 
+void
+lp_setup_set_fs_images(struct lp_setup_context *setup,
+                       unsigned num,
+                       struct pipe_image_view *images);
+
 void
 lp_setup_set_alpha_ref_value( struct lp_setup_context *setup,
                               float alpha_ref_value );
index 9c8dde5b6ae52cb802d195abce5cb1c76b4734a8..701dcadfdf995c14963c5ecd2fb8325766a611f9 100644 (file)
@@ -50,6 +50,7 @@
 #define LP_SETUP_NEW_SCISSOR     0x08
 #define LP_SETUP_NEW_VIEWPORTS   0x10
 #define LP_SETUP_NEW_SSBOS       0x20
+#define LP_SETUP_NEW_IMAGES      0x40
 
 struct lp_setup_variant;
 
@@ -148,6 +149,10 @@ struct lp_setup_context
       struct pipe_shader_buffer current;
    } ssbos[LP_MAX_TGSI_SHADER_BUFFERS];
 
+   struct {
+      struct pipe_image_view current;
+   } images[LP_MAX_TGSI_SHADER_IMAGES];
+
    struct {
       struct pipe_blend_color current;
       uint8_t *stored;
index 1c3191b983fe21667ee6f5e0a0cf01779bfa4848..753f596a858242846600ee222f6e47d1f4534595 100644 (file)
@@ -57,7 +57,7 @@
 #define LP_NEW_SO            0x20000
 #define LP_NEW_SO_BUFFERS    0x40000
 #define LP_NEW_FS_SSBOS      0x80000
-
+#define LP_NEW_FS_IMAGES    0x100000
 
 
 struct vertex_info;
index f93bc434c644e342097666402597d459ec556266..6f8e855e8aed15c6f1f04f035f844211dcfbcfc2 100644 (file)
@@ -260,6 +260,11 @@ void llvmpipe_update_derived( struct llvmpipe_context *llvmpipe )
                             ARRAY_SIZE(llvmpipe->ssbos[PIPE_SHADER_FRAGMENT]),
                             llvmpipe->ssbos[PIPE_SHADER_FRAGMENT]);
 
+   if (llvmpipe->dirty & LP_NEW_FS_IMAGES)
+      lp_setup_set_fs_images(llvmpipe->setup,
+                             ARRAY_SIZE(llvmpipe->images[PIPE_SHADER_FRAGMENT]),
+                             llvmpipe->images[PIPE_SHADER_FRAGMENT]);
+
    if (llvmpipe->dirty & (LP_NEW_SAMPLER_VIEW))
       lp_setup_set_fragment_sampler_views(llvmpipe->setup,
                                           llvmpipe->num_sampler_views[PIPE_SHADER_FRAGMENT],
index dc5a0ae69af045bb8e42c0929064709b7b4c9033..86adfbd934a96332cbe23b6c533e4374cc5706a8 100644 (file)
@@ -300,6 +300,7 @@ generate_fs_loop(struct gallivm_state *gallivm,
                  LLVMValueRef num_loop,
                  struct lp_build_interp_soa_context *interp,
                  const struct lp_build_sampler_soa *sampler,
+                 const struct lp_build_image_soa *image,
                  LLVMValueRef mask_store,
                  LLVMValueRef (*out_color)[4],
                  LLVMValueRef depth_ptr,
@@ -497,6 +498,7 @@ generate_fs_loop(struct gallivm_state *gallivm,
    params.info = &shader->info.base;
    params.ssbo_ptr = ssbo_ptr;
    params.ssbo_sizes_ptr = num_ssbo_ptr;
+   params.image = image;
 
    /* Build the actual shader */
    lp_build_tgsi_soa(gallivm, tokens, &params,
@@ -2450,6 +2452,7 @@ generate_fragment(struct llvmpipe_context *lp,
    LLVMBasicBlockRef block;
    LLVMBuilderRef builder;
    struct lp_build_sampler_soa *sampler;
+   struct lp_build_image_soa *image;
    struct lp_build_interp_soa_context interp;
    LLVMValueRef fs_mask[16 / 4];
    LLVMValueRef fs_out_color[PIPE_MAX_COLOR_BUFS][TGSI_NUM_CHANNELS][16 / 4];
@@ -2596,6 +2599,7 @@ generate_fragment(struct llvmpipe_context *lp,
 
    /* code generated texture sampling */
    sampler = lp_llvm_sampler_soa_create(key->samplers);
+   image = lp_llvm_image_soa_create(lp_fs_variant_key_images(key));
 
    num_fs = 16 / fs_type.length; /* number of loops per 4x4 stamp */
    /* for 1d resources only run "upper half" of stamp */
@@ -2650,6 +2654,7 @@ generate_fragment(struct llvmpipe_context *lp,
                        num_loop,
                        &interp,
                        sampler,
+                       image,
                        mask_store, /* output */
                        color_store,
                        depth_ptr,
@@ -2684,7 +2689,7 @@ generate_fragment(struct llvmpipe_context *lp,
    }
 
    sampler->destroy(sampler);
-
+   image->destroy(image);
    /* Loop over color outputs / color buffers to do blending.
     */
    for(cbuf = 0; cbuf < key->nr_cbufs; cbuf++) {
@@ -2813,6 +2818,21 @@ dump_fs_variant_key(struct lp_fragment_shader_variant_key *key)
                    texture->pot_height,
                    texture->pot_depth);
    }
+   struct lp_image_static_state *images = lp_fs_variant_key_images(key);
+   for (i = 0; i < key->nr_images; ++i) {
+      const struct lp_static_texture_state *image = &images[i].image_state;
+      debug_printf("image[%u] = \n", i);
+      debug_printf("  .format = %s\n",
+                   util_format_name(image->format));
+      debug_printf("  .target = %s\n",
+                   util_str_tex_target(image->target, TRUE));
+      debug_printf("  .level_zero_only = %u\n",
+                   image->level_zero_only);
+      debug_printf("  .pot = %u %u %u\n",
+                   image->pot_width,
+                   image->pot_height,
+                   image->pot_depth);
+   }
 }
 
 
@@ -2936,6 +2956,7 @@ llvmpipe_create_fs_state(struct pipe_context *pipe,
    struct lp_fragment_shader *shader;
    int nr_samplers;
    int nr_sampler_views;
+   int nr_images;
    int i;
 
    shader = CALLOC_STRUCT(lp_fragment_shader);
@@ -2960,8 +2981,8 @@ llvmpipe_create_fs_state(struct pipe_context *pipe,
 
    nr_samplers = shader->info.base.file_max[TGSI_FILE_SAMPLER] + 1;
    nr_sampler_views = shader->info.base.file_max[TGSI_FILE_SAMPLER_VIEW] + 1;
-
-   shader->variant_key_size = lp_fs_variant_key_size(MAX2(nr_samplers, nr_sampler_views));
+   nr_images = shader->info.base.file_max[TGSI_FILE_IMAGE] + 1;
+   shader->variant_key_size = lp_fs_variant_key_size(MAX2(nr_samplers, nr_sampler_views), nr_images);
 
    for (i = 0; i < shader->info.base.num_inputs; i++) {
       shader->inputs[i].usage_mask = shader->info.base.input_usage_mask[i];
@@ -3187,6 +3208,32 @@ llvmpipe_set_shader_buffers(struct pipe_context *pipe,
    }
 }
 
+static void
+llvmpipe_set_shader_images(struct pipe_context *pipe,
+                            enum pipe_shader_type shader, unsigned start_slot,
+                           unsigned count, const struct pipe_image_view *images)
+{
+   struct llvmpipe_context *llvmpipe = llvmpipe_context(pipe);
+   unsigned i, idx;
+
+   draw_flush(llvmpipe->draw);
+   for (i = start_slot, idx = 0; i < start_slot + count; i++, idx++) {
+      const struct pipe_image_view *image = images ? &images[idx] : NULL;
+
+      util_copy_image_view(&llvmpipe->images[shader][i], image);
+   }
+
+   llvmpipe->num_images[shader] = start_slot + count;
+   if (shader == PIPE_SHADER_VERTEX ||
+       shader == PIPE_SHADER_GEOMETRY) {
+      draw_set_images(llvmpipe->draw,
+                      shader,
+                      llvmpipe->images[shader],
+                      start_slot + count);
+   } else
+      llvmpipe->dirty |= LP_NEW_FS_IMAGES;
+}
+
 /**
  * Return the blend factor equivalent to a destination alpha of one.
  */
@@ -3413,6 +3460,16 @@ make_variant_key(struct llvmpipe_context *lp,
          }
       }
    }
+
+   struct lp_image_static_state *lp_image;
+   lp_image = lp_fs_variant_key_images(key);
+   key->nr_images = shader->info.base.file_max[TGSI_FILE_IMAGE] + 1;
+   for (i = 0; i < key->nr_images; ++i) {
+      if (shader->info.base.file_mask[TGSI_FILE_IMAGE] & (1 << i)) {
+         lp_sampler_static_texture_state_image(&lp_image[i].image_state,
+                                               &lp->images[PIPE_SHADER_FRAGMENT][i]);
+      }
+   }
    return key;
 }
 
@@ -3542,6 +3599,7 @@ llvmpipe_init_fs_funcs(struct llvmpipe_context *llvmpipe)
    llvmpipe->pipe.set_constant_buffer = llvmpipe_set_constant_buffer;
 
    llvmpipe->pipe.set_shader_buffers = llvmpipe_set_shader_buffers;
+   llvmpipe->pipe.set_shader_images = llvmpipe_set_shader_images;
 }
 
 
index 02e9de86946bb2bbf3d24367ee2f06912aded6a3..4800498f2b65a1abbeb7a2020900ba5fc5d10fc9 100644 (file)
@@ -59,6 +59,11 @@ struct lp_sampler_static_state
 };
 
 
+struct lp_image_static_state
+{
+   struct lp_static_texture_state image_state;
+};
+
 struct lp_fragment_shader_variant_key
 {
    struct pipe_depth_state depth;
@@ -73,6 +78,7 @@ struct lp_fragment_shader_variant_key
    unsigned nr_cbufs:8;
    unsigned nr_samplers:8;      /* actually derivable from just the shader */
    unsigned nr_sampler_views:8; /* actually derivable from just the shader */
+   unsigned nr_images:8;        /* actually derivable from just the shader */
    unsigned flatshade:1;
    unsigned occlusion_count:1;
    unsigned resource_1d:1;
@@ -82,18 +88,28 @@ struct lp_fragment_shader_variant_key
    enum pipe_format cbuf_format[PIPE_MAX_COLOR_BUFS];
 
    struct lp_sampler_static_state samplers[1];
+   /* followed by variable number of images */
 };
 
 #define LP_FS_MAX_VARIANT_KEY_SIZE                                      \
    (sizeof(struct lp_fragment_shader_variant_key) +                     \
-    PIPE_MAX_SHADER_SAMPLER_VIEWS * sizeof(struct lp_sampler_static_state))
+    PIPE_MAX_SHADER_SAMPLER_VIEWS * sizeof(struct lp_sampler_static_state) +\
+    PIPE_MAX_SHADER_IMAGES * sizeof(struct lp_image_static_state))
 
 static inline size_t
-lp_fs_variant_key_size(unsigned nr_samplers)
+lp_fs_variant_key_size(unsigned nr_samplers, unsigned nr_images)
 {
    unsigned samplers = nr_samplers > 1 ? (nr_samplers - 1) : 0;
    return (sizeof(struct lp_fragment_shader_variant_key) +
-           samplers * sizeof(struct lp_sampler_static_state));
+           samplers * sizeof(struct lp_sampler_static_state) +
+           nr_images * sizeof(struct lp_image_static_state));
+}
+
+static inline struct lp_image_static_state *
+lp_fs_variant_key_images(struct lp_fragment_shader_variant_key *key)
+{
+   return (struct lp_image_static_state *)
+      &key->samplers[key->nr_samplers];
 }
 
 /** doubly-linked list item */
index 5d0d35091958f7c20eb468a014c7ddf08061a1ed..3051774e8c445dc66d32cd8c4431ff9b5ed226cf 100644 (file)
@@ -78,6 +78,23 @@ struct lp_llvm_sampler_soa
    struct llvmpipe_sampler_dynamic_state dynamic_state;
 };
 
+struct llvmpipe_image_dynamic_state
+{
+   struct lp_sampler_dynamic_state base;
+
+   const struct lp_image_static_state *static_state;
+};
+
+/**
+ * This is the bridge between our sampler and the TGSI translator.
+ */
+struct lp_llvm_image_soa
+{
+   struct lp_build_image_soa base;
+
+   struct llvmpipe_image_dynamic_state dynamic_state;
+};
+
 
 /**
  * Fetch the specified member of the lp_jit_texture structure.
@@ -221,6 +238,80 @@ LP_LLVM_SAMPLER_MEMBER(lod_bias,   LP_JIT_SAMPLER_LOD_BIAS, TRUE)
 LP_LLVM_SAMPLER_MEMBER(border_color, LP_JIT_SAMPLER_BORDER_COLOR, FALSE)
 
 
+/**
+ * Fetch the specified member of the lp_jit_image structure.
+ * \param emit_load  if TRUE, emit the LLVM load instruction to actually
+ *                   fetch the field's value.  Otherwise, just emit the
+ *                   GEP code to address the field.
+ *
+ * @sa http://llvm.org/docs/GetElementPtr.html
+ */
+static LLVMValueRef
+lp_llvm_image_member(const struct lp_sampler_dynamic_state *base,
+                     struct gallivm_state *gallivm,
+                     LLVMValueRef context_ptr,
+                     unsigned image_unit,
+                     unsigned member_index,
+                     const char *member_name,
+                     boolean emit_load)
+{
+   LLVMBuilderRef builder = gallivm->builder;
+   LLVMValueRef indices[4];
+   LLVMValueRef ptr;
+   LLVMValueRef res;
+
+   assert(image_unit < PIPE_MAX_SHADER_IMAGES);
+
+   /* context[0] */
+   indices[0] = lp_build_const_int32(gallivm, 0);
+   /* context[0].images */
+   indices[1] = lp_build_const_int32(gallivm, LP_JIT_CTX_IMAGES);
+   /* context[0].images[unit] */
+   indices[2] = lp_build_const_int32(gallivm, image_unit);
+   /* context[0].images[unit].member */
+   indices[3] = lp_build_const_int32(gallivm, member_index);
+
+   ptr = LLVMBuildGEP(builder, context_ptr, indices, ARRAY_SIZE(indices), "");
+
+   if (emit_load)
+      res = LLVMBuildLoad(builder, ptr, "");
+   else
+      res = ptr;
+
+   lp_build_name(res, "context.image%u.%s", image_unit, member_name);
+
+   return res;
+}
+
+
+/**
+ * Helper macro to instantiate the functions that generate the code to
+ * fetch the members of lp_jit_image to fulfill the sampler code
+ * generator requests.
+ *
+ * This complexity is the price we have to pay to keep the image
+ * sampler code generator a reusable module without dependencies to
+ * llvmpipe internals.
+ */
+#define LP_LLVM_IMAGE_MEMBER(_name, _index, _emit_load)  \
+   static LLVMValueRef \
+   lp_llvm_image_##_name( const struct lp_sampler_dynamic_state *base, \
+                            struct gallivm_state *gallivm, \
+                            LLVMValueRef context_ptr, \
+                            unsigned image_unit) \
+   { \
+      return lp_llvm_image_member(base, gallivm, context_ptr, \
+                                    image_unit, _index, #_name, _emit_load ); \
+   }
+
+
+LP_LLVM_IMAGE_MEMBER(width,      LP_JIT_IMAGE_WIDTH, TRUE)
+LP_LLVM_IMAGE_MEMBER(height,     LP_JIT_IMAGE_HEIGHT, TRUE)
+LP_LLVM_IMAGE_MEMBER(depth,      LP_JIT_IMAGE_DEPTH, TRUE)
+LP_LLVM_IMAGE_MEMBER(base_ptr,   LP_JIT_IMAGE_BASE, TRUE)
+LP_LLVM_IMAGE_MEMBER(row_stride, LP_JIT_IMAGE_ROW_STRIDE, TRUE)
+LP_LLVM_IMAGE_MEMBER(img_stride, LP_JIT_IMAGE_IMG_STRIDE, TRUE)
+
 #if LP_USE_TEXTURE_CACHE
 static LLVMValueRef
 lp_llvm_texture_cache_ptr(const struct lp_sampler_dynamic_state *base,
@@ -324,3 +415,66 @@ lp_llvm_sampler_soa_create(const struct lp_sampler_static_state *static_state)
    return &sampler->base;
 }
 
+static void
+lp_llvm_image_soa_destroy(struct lp_build_image_soa *image)
+{
+   FREE(image);
+}
+
+static void
+lp_llvm_image_soa_emit_op(const struct lp_build_image_soa *base,
+                             struct gallivm_state *gallivm,
+                             const struct lp_img_params *params)
+{
+   struct lp_llvm_image_soa *image = (struct lp_llvm_image_soa *)base;
+   unsigned image_index = params->image_index;
+   assert(image_index < PIPE_MAX_SHADER_IMAGES);
+
+   lp_build_img_op_soa(&image->dynamic_state.static_state[image_index].image_state,
+                       &image->dynamic_state.base,
+                       gallivm, params);
+}
+
+/**
+ * Fetch the texture size.
+ */
+static void
+lp_llvm_image_soa_emit_size_query(const struct lp_build_image_soa *base,
+                                    struct gallivm_state *gallivm,
+                                    const struct lp_sampler_size_query_params *params)
+{
+   struct lp_llvm_image_soa *image = (struct lp_llvm_image_soa *)base;
+
+   assert(params->texture_unit < PIPE_MAX_SHADER_IMAGES);
+
+   lp_build_size_query_soa(gallivm,
+                           &image->dynamic_state.static_state[params->texture_unit].image_state,
+                           &image->dynamic_state.base,
+                           params);
+}
+
+struct lp_build_image_soa *
+lp_llvm_image_soa_create(const struct lp_image_static_state *static_state)
+{
+   struct lp_llvm_image_soa *image;
+
+   image = CALLOC_STRUCT(lp_llvm_image_soa);
+   if (!image)
+      return NULL;
+
+   image->base.destroy = lp_llvm_image_soa_destroy;
+   image->base.emit_op = lp_llvm_image_soa_emit_op;
+   image->base.emit_size_query = lp_llvm_image_soa_emit_size_query;
+
+   image->dynamic_state.base.width = lp_llvm_image_width;
+   image->dynamic_state.base.height = lp_llvm_image_height;
+
+   image->dynamic_state.base.depth = lp_llvm_image_depth;
+   image->dynamic_state.base.base_ptr = lp_llvm_image_base_ptr;
+   image->dynamic_state.base.row_stride = lp_llvm_image_row_stride;
+   image->dynamic_state.base.img_stride = lp_llvm_image_img_stride;
+
+   image->dynamic_state.static_state = static_state;
+
+   return &image->base;
+}
index e26d608c9eb6b64f60314cfe6e158d8d43170cde..ce60f21792ef895eab9277f010c68ae463288d55 100644 (file)
@@ -33,6 +33,7 @@
 
 
 struct lp_sampler_static_state;
+struct lp_image_static_state;
 
 /**
  * Whether texture cache is used for s3tc textures.
@@ -46,4 +47,7 @@ struct lp_sampler_static_state;
 struct lp_build_sampler_soa *
 lp_llvm_sampler_soa_create(const struct lp_sampler_static_state *key);
 
+struct lp_build_image_soa *
+lp_llvm_image_soa_create(const struct lp_image_static_state *key);
+
 #endif /* LP_TEX_SAMPLE_H */
index ea993c9e52412f3d3cf1be0338c50fad6428fe94..ca15d785055ad5b26edd464fa944808edc47a111 100644 (file)
@@ -647,7 +647,8 @@ llvmpipe_is_resource_referenced( struct pipe_context *pipe,
    if (!(presource->bind & (PIPE_BIND_DEPTH_STENCIL |
                             PIPE_BIND_RENDER_TARGET |
                             PIPE_BIND_SAMPLER_VIEW |
-                            PIPE_BIND_SHADER_BUFFER)))
+                            PIPE_BIND_SHADER_BUFFER |
+                            PIPE_BIND_SHADER_IMAGE)))
       return LP_UNREFERENCED;
 
    return lp_setup_is_resource_referenced(llvmpipe->setup, presource);