llvmpipe: add compute sampler + sampler view support.
authorDave Airlie <airlied@redhat.com>
Tue, 27 Aug 2019 05:17:29 +0000 (15:17 +1000)
committerDave Airlie <airlied@redhat.com>
Wed, 4 Sep 2019 05:22:20 +0000 (15:22 +1000)
This is ported from the fragment shader code.

Reviewed-by: Roland Scheidegger <sroland@vmware.com>
src/gallium/drivers/llvmpipe/lp_state.h
src/gallium/drivers/llvmpipe/lp_state_cs.c
src/gallium/drivers/llvmpipe/lp_state_cs.h
src/gallium/drivers/llvmpipe/lp_state_sampler.c

index ca6e412..7138e6d 100644 (file)
@@ -61,6 +61,8 @@
 
 #define LP_CSNEW_CS 0x1
 #define LP_CSNEW_CONSTANTS 0x2
+#define LP_CSNEW_SAMPLER 0x4
+#define LP_CSNEW_SAMPLER_VIEW 0x8
 
 struct vertex_info;
 struct pipe_context;
index 41d845a..32bbdd2 100644 (file)
@@ -25,6 +25,8 @@
 #include "util/u_memory.h"
 #include "util/simple_list.h"
 #include "util/os_time.h"
+#include "util/u_dump.h"
+#include "util/u_string.h"
 #include "tgsi/tgsi_dump.h"
 #include "tgsi/tgsi_parse.h"
 #include "gallivm/lp_bld_const.h"
@@ -39,7 +41,9 @@
 #include "lp_state.h"
 #include "lp_perf.h"
 #include "lp_screen.h"
+#include "lp_memory.h"
 #include "lp_cs_tpool.h"
+#include "state_tracker/sw_winsys.h"
 
 struct lp_cs_job_info {
    unsigned grid_size[3];
@@ -53,6 +57,7 @@ generate_compute(struct llvmpipe_context *lp,
                  struct lp_compute_shader_variant *variant)
 {
    struct gallivm_state *gallivm = variant->gallivm;
+   const struct lp_compute_shader_variant_key *key = &variant->key;
    char func_name[64], func_name_coro[64];
    LLVMTypeRef arg_types[13];
    LLVMTypeRef func_type, coro_func_type;
@@ -64,6 +69,7 @@ generate_compute(struct llvmpipe_context *lp,
    LLVMValueRef thread_data_ptr;
    LLVMBasicBlockRef block;
    LLVMBuilderRef builder;
+   struct lp_build_sampler_soa *sampler;
    LLVMValueRef function, coro;
    struct lp_type cs_type;
    unsigned i;
@@ -149,6 +155,7 @@ generate_compute(struct llvmpipe_context *lp,
    builder = gallivm->builder;
    assert(builder);
    LLVMPositionBuilderAtEnd(builder, block);
+   sampler = lp_llvm_sampler_soa_create(key->state);
 
    struct lp_build_loop_state loop_state[4];
    LLVMValueRef num_x_loop;
@@ -342,6 +349,7 @@ generate_compute(struct llvmpipe_context *lp,
       params.const_sizes_ptr = num_consts_ptr;
       params.system_values = &system_values;
       params.context_ptr = context_ptr;
+      params.sampler = sampler;
       params.info = &shader->info.base;
       params.ssbo_ptr = ssbo_ptr;
       params.ssbo_sizes_ptr = num_ssbo_ptr;
@@ -364,6 +372,8 @@ generate_compute(struct llvmpipe_context *lp,
       LLVMBuildRet(builder, coro_hdl);
    }
 
+   sampler->destroy(sampler);
+
    gallivm_verify_function(gallivm, coro);
    gallivm_verify_function(gallivm, function);
 }
@@ -373,7 +383,7 @@ llvmpipe_create_compute_state(struct pipe_context *pipe,
                                      const struct pipe_compute_state *templ)
 {
    struct lp_compute_shader *shader;
-
+   int nr_samplers, nr_sampler_views;
    shader = CALLOC_STRUCT(lp_compute_shader);
    if (!shader)
       return NULL;
@@ -384,6 +394,10 @@ llvmpipe_create_compute_state(struct pipe_context *pipe,
    lp_build_tgsi_info(shader->base.tokens, &shader->info);
    make_empty_list(&shader->variants);
 
+   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 = Offset(struct lp_compute_shader_variant_key,
+                                     state[MAX2(nr_samplers, nr_sampler_views)]);
    return shader;
 }
 
@@ -455,13 +469,93 @@ make_variant_key(struct llvmpipe_context *lp,
                  struct lp_compute_shader *shader,
                  struct lp_compute_shader_variant_key *key)
 {
+   int i;
+
    memset(key, 0, shader->variant_key_size);
+
+   /* This value will be the same for all the variants of a given shader:
+    */
+   key->nr_samplers = shader->info.base.file_max[TGSI_FILE_SAMPLER] + 1;
+
+   for(i = 0; i < key->nr_samplers; ++i) {
+      if(shader->info.base.file_mask[TGSI_FILE_SAMPLER] & (1 << i)) {
+         lp_sampler_static_sampler_state(&key->state[i].sampler_state,
+                                         lp->samplers[PIPE_SHADER_COMPUTE][i]);
+      }
+   }
+
+   /*
+    * XXX If TGSI_FILE_SAMPLER_VIEW exists assume all texture opcodes
+    * are dx10-style? Can't really have mixed opcodes, at least not
+    * if we want to skip the holes here (without rescanning tgsi).
+    */
+   if (shader->info.base.file_max[TGSI_FILE_SAMPLER_VIEW] != -1) {
+      key->nr_sampler_views = shader->info.base.file_max[TGSI_FILE_SAMPLER_VIEW] + 1;
+      for(i = 0; i < key->nr_sampler_views; ++i) {
+         /*
+          * Note sview may exceed what's representable by file_mask.
+          * This will still work, the only downside is that not actually
+          * used views may be included in the shader key.
+          */
+         if(shader->info.base.file_mask[TGSI_FILE_SAMPLER_VIEW] & (1u << (i & 31))) {
+            lp_sampler_static_texture_state(&key->state[i].texture_state,
+                                            lp->sampler_views[PIPE_SHADER_COMPUTE][i]);
+         }
+      }
+   }
+   else {
+      key->nr_sampler_views = key->nr_samplers;
+      for(i = 0; i < key->nr_sampler_views; ++i) {
+         if(shader->info.base.file_mask[TGSI_FILE_SAMPLER] & (1 << i)) {
+            lp_sampler_static_texture_state(&key->state[i].texture_state,
+                                            lp->sampler_views[PIPE_SHADER_COMPUTE][i]);
+         }
+      }
+   }
+
 }
 
 static void
 dump_cs_variant_key(const struct lp_compute_shader_variant_key *key)
 {
+   int i;
    debug_printf("cs variant %p:\n", (void *) key);
+
+   for (i = 0; i < key->nr_samplers; ++i) {
+      const struct lp_static_sampler_state *sampler = &key->state[i].sampler_state;
+      debug_printf("sampler[%u] = \n", i);
+      debug_printf("  .wrap = %s %s %s\n",
+                   util_str_tex_wrap(sampler->wrap_s, TRUE),
+                   util_str_tex_wrap(sampler->wrap_t, TRUE),
+                   util_str_tex_wrap(sampler->wrap_r, TRUE));
+      debug_printf("  .min_img_filter = %s\n",
+                   util_str_tex_filter(sampler->min_img_filter, TRUE));
+      debug_printf("  .min_mip_filter = %s\n",
+                   util_str_tex_mipfilter(sampler->min_mip_filter, TRUE));
+      debug_printf("  .mag_img_filter = %s\n",
+                   util_str_tex_filter(sampler->mag_img_filter, TRUE));
+      if (sampler->compare_mode != PIPE_TEX_COMPARE_NONE)
+         debug_printf("  .compare_func = %s\n", util_str_func(sampler->compare_func, TRUE));
+      debug_printf("  .normalized_coords = %u\n", sampler->normalized_coords);
+      debug_printf("  .min_max_lod_equal = %u\n", sampler->min_max_lod_equal);
+      debug_printf("  .lod_bias_non_zero = %u\n", sampler->lod_bias_non_zero);
+      debug_printf("  .apply_min_lod = %u\n", sampler->apply_min_lod);
+      debug_printf("  .apply_max_lod = %u\n", sampler->apply_max_lod);
+   }
+   for (i = 0; i < key->nr_sampler_views; ++i) {
+      const struct lp_static_texture_state *texture = &key->state[i].texture_state;
+      debug_printf("texture[%u] = \n", i);
+      debug_printf("  .format = %s\n",
+                   util_format_name(texture->format));
+      debug_printf("  .target = %s\n",
+                   util_str_tex_target(texture->target, TRUE));
+      debug_printf("  .level_zero_only = %u\n",
+                   texture->level_zero_only);
+      debug_printf("  .pot = %u %u %u\n",
+                   texture->pot_width,
+                   texture->pot_height,
+                   texture->pot_depth);
+   }
 }
 
 static void
@@ -622,6 +716,176 @@ llvmpipe_update_cs(struct llvmpipe_context *lp)
    lp_cs_ctx_set_cs_variant(lp->csctx, variant);
 }
 
+/**
+ * Called during state validation when LP_CSNEW_SAMPLER_VIEW is set.
+ */
+static void
+lp_csctx_set_sampler_views(struct lp_cs_context *csctx,
+                           unsigned num,
+                           struct pipe_sampler_view **views)
+{
+   unsigned i, max_tex_num;
+
+   LP_DBG(DEBUG_SETUP, "%s\n", __FUNCTION__);
+
+   assert(num <= PIPE_MAX_SHADER_SAMPLER_VIEWS);
+
+   max_tex_num = MAX2(num, csctx->cs.current_tex_num);
+
+   for (i = 0; i < max_tex_num; i++) {
+      struct pipe_sampler_view *view = i < num ? views[i] : NULL;
+
+      if (view) {
+         struct pipe_resource *res = view->texture;
+         struct llvmpipe_resource *lp_tex = llvmpipe_resource(res);
+         struct lp_jit_texture *jit_tex;
+         jit_tex = &csctx->cs.current.jit_context.textures[i];
+
+         /* We're referencing the texture's internal data, so save a
+          * reference to it.
+          */
+         pipe_resource_reference(&csctx->cs.current_tex[i], res);
+
+         if (!lp_tex->dt) {
+            /* regular texture - csctx array of mipmap level offsets */
+            int j;
+            unsigned first_level = 0;
+            unsigned last_level = 0;
+
+            if (llvmpipe_resource_is_texture(res)) {
+               first_level = view->u.tex.first_level;
+               last_level = view->u.tex.last_level;
+               assert(first_level <= last_level);
+               assert(last_level <= res->last_level);
+               jit_tex->base = lp_tex->tex_data;
+            }
+            else {
+              jit_tex->base = lp_tex->data;
+            }
+            if (LP_PERF & PERF_TEX_MEM) {
+               /* use dummy tile memory */
+               jit_tex->base = lp_dummy_tile;
+               jit_tex->width = TILE_SIZE/8;
+               jit_tex->height = TILE_SIZE/8;
+               jit_tex->depth = 1;
+               jit_tex->first_level = 0;
+               jit_tex->last_level = 0;
+               jit_tex->mip_offsets[0] = 0;
+               jit_tex->row_stride[0] = 0;
+               jit_tex->img_stride[0] = 0;
+            }
+            else {
+               jit_tex->width = res->width0;
+               jit_tex->height = res->height0;
+               jit_tex->depth = res->depth0;
+               jit_tex->first_level = first_level;
+               jit_tex->last_level = last_level;
+
+               if (llvmpipe_resource_is_texture(res)) {
+                  for (j = first_level; j <= last_level; j++) {
+                     jit_tex->mip_offsets[j] = lp_tex->mip_offsets[j];
+                     jit_tex->row_stride[j] = lp_tex->row_stride[j];
+                     jit_tex->img_stride[j] = lp_tex->img_stride[j];
+                  }
+
+                  if (res->target == PIPE_TEXTURE_1D_ARRAY ||
+                      res->target == PIPE_TEXTURE_2D_ARRAY ||
+                      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_tex->depth = view->u.tex.last_layer - view->u.tex.first_layer + 1;
+                     for (j = first_level; j <= last_level; j++) {
+                        jit_tex->mip_offsets[j] += view->u.tex.first_layer *
+                                                   lp_tex->img_stride[j];
+                     }
+                     if (view->target == PIPE_TEXTURE_CUBE ||
+                         view->target == PIPE_TEXTURE_CUBE_ARRAY) {
+                        assert(jit_tex->depth % 6 == 0);
+                     }
+                     assert(view->u.tex.first_layer <= view->u.tex.last_layer);
+                     assert(view->u.tex.last_layer < res->array_size);
+                  }
+               }
+               else {
+                  /*
+                   * For buffers, we don't have "offset", instead adjust
+                   * the size (stored as width) plus the base pointer.
+                   */
+                  unsigned view_blocksize = util_format_get_blocksize(view->format);
+                  /* probably don't really need to fill that out */
+                  jit_tex->mip_offsets[0] = 0;
+                  jit_tex->row_stride[0] = 0;
+                  jit_tex->img_stride[0] = 0;
+
+                  /* everything specified in number of elements here. */
+                  jit_tex->width = view->u.buf.size / view_blocksize;
+                  jit_tex->base = (uint8_t *)jit_tex->base + view->u.buf.offset;
+                  /* XXX Unsure if we need to sanitize parameters? */
+                  assert(view->u.buf.offset + view->u.buf.size <= res->width0);
+               }
+            }
+         }
+         else {
+            /* display target texture/surface */
+            /*
+             * XXX: Where should this be unmapped?
+             */
+            struct llvmpipe_screen *screen = llvmpipe_screen(res->screen);
+            struct sw_winsys *winsys = screen->winsys;
+            jit_tex->base = winsys->displaytarget_map(winsys, lp_tex->dt,
+                                                         PIPE_TRANSFER_READ);
+            jit_tex->row_stride[0] = lp_tex->row_stride[0];
+            jit_tex->img_stride[0] = lp_tex->img_stride[0];
+            jit_tex->mip_offsets[0] = 0;
+            jit_tex->width = res->width0;
+            jit_tex->height = res->height0;
+            jit_tex->depth = res->depth0;
+            jit_tex->first_level = jit_tex->last_level = 0;
+            assert(jit_tex->base);
+         }
+      }
+      else {
+         pipe_resource_reference(&csctx->cs.current_tex[i], NULL);
+      }
+   }
+   csctx->cs.current_tex_num = num;
+}
+
+
+/**
+ * Called during state validation when LP_NEW_SAMPLER is set.
+ */
+static void
+lp_csctx_set_sampler_state(struct lp_cs_context *csctx,
+                           unsigned num,
+                           struct pipe_sampler_state **samplers)
+{
+   unsigned i;
+
+   LP_DBG(DEBUG_SETUP, "%s\n", __FUNCTION__);
+
+   assert(num <= PIPE_MAX_SAMPLERS);
+
+   for (i = 0; i < PIPE_MAX_SAMPLERS; i++) {
+      const struct pipe_sampler_state *sampler = i < num ? samplers[i] : NULL;
+
+      if (sampler) {
+         struct lp_jit_sampler *jit_sam;
+         jit_sam = &csctx->cs.current.jit_context.samplers[i];
+
+         jit_sam->min_lod = sampler->min_lod;
+         jit_sam->max_lod = sampler->max_lod;
+         jit_sam->lod_bias = sampler->lod_bias;
+         COPY_4V(jit_sam->border_color, sampler->border_color.f);
+      }
+   }
+}
+
 static void
 lp_csctx_set_cs_constants(struct lp_cs_context *csctx,
                           unsigned num,
@@ -685,6 +949,15 @@ llvmpipe_cs_update_derived(struct llvmpipe_context *llvmpipe)
       update_csctx_consts(llvmpipe);
    }
 
+   if (llvmpipe->cs_dirty & LP_CSNEW_SAMPLER_VIEW)
+      lp_csctx_set_sampler_views(llvmpipe->csctx,
+                                 llvmpipe->num_sampler_views[PIPE_SHADER_COMPUTE],
+                                 llvmpipe->sampler_views[PIPE_SHADER_COMPUTE]);
+
+   if (llvmpipe->cs_dirty & LP_CSNEW_SAMPLER)
+      lp_csctx_set_sampler_state(llvmpipe->csctx,
+                                 llvmpipe->num_samplers[PIPE_SHADER_COMPUTE],
+                                 llvmpipe->samplers[PIPE_SHADER_COMPUTE]);
    llvmpipe->cs_dirty = 0;
 }
 
@@ -778,6 +1051,9 @@ void
 lp_csctx_destroy(struct lp_cs_context *csctx)
 {
    unsigned i;
+   for (i = 0; i < ARRAY_SIZE(csctx->cs.current_tex); i++) {
+      pipe_resource_reference(&csctx->cs.current_tex[i], NULL);
+   }
    for (i = 0; i < ARRAY_SIZE(csctx->constants); i++) {
       pipe_resource_reference(&csctx->constants[i].current.buffer, NULL);
    }
index 35c8f75..031c1d3 100644 (file)
 #include "pipe/p_state.h"
 
 #include "gallivm/lp_bld.h"
-#include "gallivm/lp_bld_tgsi.h" /* for lp_tgsi_info */
+#include "gallivm/lp_bld_sample.h" /* for struct lp_sampler_static_state */
 #include "lp_jit.h"
+#include "lp_state_fs.h"
 
 struct lp_compute_shader_variant;
 
 struct lp_compute_shader_variant_key
 {
+   unsigned nr_samplers:8;
+   unsigned nr_sampler_views:8;
+   struct lp_sampler_static_state state[PIPE_MAX_SHADER_SAMPLER_VIEWS];
 };
 
 struct lp_cs_variant_list_item
@@ -92,6 +96,8 @@ struct lp_cs_context {
 
    struct {
       struct lp_cs_exec current;
+      struct pipe_resource *current_tex[PIPE_MAX_SHADER_SAMPLER_VIEWS];
+      unsigned current_tex_num;
    } cs;
 
    /** compute shader constants */
index fface0c..36159a3 100644 (file)
@@ -98,7 +98,9 @@ llvmpipe_bind_sampler_states(struct pipe_context *pipe,
                         llvmpipe->samplers[shader],
                         llvmpipe->num_samplers[shader]);
    }
-   else {
+   else if (shader == PIPE_SHADER_COMPUTE) {
+      llvmpipe->cs_dirty |= LP_CSNEW_SAMPLER;
+   } else {
       llvmpipe->dirty |= LP_NEW_SAMPLER;
    }
 }
@@ -150,7 +152,9 @@ llvmpipe_set_sampler_views(struct pipe_context *pipe,
                              llvmpipe->sampler_views[shader],
                              llvmpipe->num_sampler_views[shader]);
    }
-   else {
+   else if (shader == PIPE_SHADER_COMPUTE) {
+      llvmpipe->cs_dirty |= LP_CSNEW_SAMPLER_VIEW;
+   } else {
       llvmpipe->dirty |= LP_NEW_SAMPLER_VIEW;
    }
 }