Mesa (master): draw: implement vertex texture sampling using llvm

Zack Rusin zack at kemper.freedesktop.org
Tue Jul 6 17:25:35 UTC 2010


Module: Mesa
Branch: master
Commit: 01eebfe1b6de2e36dd3af0952fc8329b7073a100
URL:    http://cgit.freedesktop.org/mesa/mesa/commit/?id=01eebfe1b6de2e36dd3af0952fc8329b7073a100

Author: Zack Rusin <zackr at vmware.com>
Date:   Mon Jun 14 10:18:09 2010 -0400

draw: implement vertex texture sampling using llvm

---

 src/gallium/auxiliary/Makefile                     |    3 +-
 src/gallium/auxiliary/SConscript                   |    3 +-
 src/gallium/auxiliary/draw/draw_context.c          |   56 +++++
 src/gallium/auxiliary/draw/draw_context.h          |   18 ++
 src/gallium/auxiliary/draw/draw_llvm.c             |   98 ++++++++--
 src/gallium/auxiliary/draw/draw_llvm.h             |   42 +++-
 src/gallium/auxiliary/draw/draw_llvm_sample.c      |  216 ++++++++++++++++++++
 src/gallium/auxiliary/draw/draw_private.h          |    7 +
 .../draw/draw_pt_fetch_shade_pipeline_llvm.c       |    5 +-
 src/gallium/drivers/llvmpipe/lp_screen.c           |    2 +-
 src/gallium/drivers/llvmpipe/lp_setup.c            |   73 +++++++-
 src/gallium/drivers/llvmpipe/lp_setup.h            |    5 +
 src/gallium/drivers/llvmpipe/lp_setup_context.h    |    4 +
 src/gallium/drivers/llvmpipe/lp_state_derived.c    |    8 +-
 src/gallium/drivers/llvmpipe/lp_state_sampler.c    |    8 +
 15 files changed, 516 insertions(+), 32 deletions(-)

diff --git a/src/gallium/auxiliary/Makefile b/src/gallium/auxiliary/Makefile
index 91f8b10..731f60d 100644
--- a/src/gallium/auxiliary/Makefile
+++ b/src/gallium/auxiliary/Makefile
@@ -171,7 +171,8 @@ GALLIVM_SOURCES = \
         draw/draw_llvm.c \
         draw/draw_vs_llvm.c \
         draw/draw_pt_fetch_shade_pipeline_llvm.c \
-        draw/draw_llvm_translate.c
+        draw/draw_llvm_translate.c \
+        draw/draw_llvm_sample.c
 
 GALLIVM_CPP_SOURCES = \
     gallivm/lp_bld_misc.cpp
diff --git a/src/gallium/auxiliary/SConscript b/src/gallium/auxiliary/SConscript
index af3f47b..7e06cc0 100644
--- a/src/gallium/auxiliary/SConscript
+++ b/src/gallium/auxiliary/SConscript
@@ -221,7 +221,8 @@ if env['llvm']:
     'draw/draw_llvm.c',
     'draw/draw_pt_fetch_shade_pipeline_llvm.c',
     'draw/draw_llvm_translate.c',
-    'draw/draw_vs_llvm.c'
+    'draw/draw_vs_llvm.c',
+    'draw/draw_llvm_sample.c'
     ]
 
 gallium = env.ConvenienceLibrary(
diff --git a/src/gallium/auxiliary/draw/draw_context.c b/src/gallium/auxiliary/draw/draw_context.c
index dab95e5..aac1ed6 100644
--- a/src/gallium/auxiliary/draw/draw_context.c
+++ b/src/gallium/auxiliary/draw/draw_context.c
@@ -40,6 +40,7 @@
 
 #if HAVE_LLVM
 #include "gallivm/lp_bld_init.h"
+#include "draw_llvm.h"
 #endif
 
 struct draw_context *draw_create( struct pipe_context *pipe )
@@ -52,6 +53,7 @@ struct draw_context *draw_create( struct pipe_context *pipe )
    lp_build_init();
    assert(lp_build_engine);
    draw->engine = lp_build_engine;
+   draw->llvm = draw_llvm_create(draw);
 #endif
 
    if (!draw_init(draw))
@@ -132,6 +134,9 @@ void draw_destroy( struct draw_context *draw )
    draw_pt_destroy( draw );
    draw_vs_destroy( draw );
    draw_gs_destroy( draw );
+#ifdef HAVE_LLVM
+   draw_llvm_destroy( draw->llvm );
+#endif
 
    FREE( draw );
 }
@@ -601,3 +606,54 @@ draw_set_so_state(struct draw_context *draw,
           state,
           sizeof(struct pipe_stream_output_state));
 }
+
+void
+draw_set_sampler_views(struct draw_context *draw,
+                       struct pipe_sampler_view **views,
+                       unsigned num)
+{
+   unsigned i;
+
+   debug_assert(num <= PIPE_MAX_VERTEX_SAMPLERS);
+
+   for (i = 0; i < num; ++i)
+      draw->sampler_views[i] = views[i];
+   for (i = num; i < PIPE_MAX_VERTEX_SAMPLERS; ++i)
+      draw->sampler_views[i] = NULL;
+
+   draw->num_sampler_views = num;
+}
+
+void
+draw_set_samplers(struct draw_context *draw,
+                  struct pipe_sampler_state **samplers,
+                  unsigned num)
+{
+   unsigned i;
+
+   debug_assert(num <= PIPE_MAX_VERTEX_SAMPLERS);
+
+   for (i = 0; i < num; ++i)
+      draw->samplers[i] = samplers[i];
+   for (i = num; i < PIPE_MAX_VERTEX_SAMPLERS; ++i)
+      draw->samplers[i] = NULL;
+
+   draw->num_samplers = num;
+}
+
+void
+draw_set_mapped_texture(struct draw_context *draw,
+                        unsigned sampler_idx,
+                        uint32_t width, uint32_t height, uint32_t depth,
+                        uint32_t last_level,
+                        uint32_t row_stride[DRAW_MAX_TEXTURE_LEVELS],
+                        uint32_t img_stride[DRAW_MAX_TEXTURE_LEVELS],
+                        const void *data[DRAW_MAX_TEXTURE_LEVELS])
+{
+#ifdef HAVE_LLVM
+   draw_llvm_set_mapped_texture(draw,
+                                sampler_idx,
+                                width, height, depth, last_level,
+                                row_stride, img_stride, data);
+#endif
+}
diff --git a/src/gallium/auxiliary/draw/draw_context.h b/src/gallium/auxiliary/draw/draw_context.h
index c0122f2..724f992 100644
--- a/src/gallium/auxiliary/draw/draw_context.h
+++ b/src/gallium/auxiliary/draw/draw_context.h
@@ -47,6 +47,7 @@ struct draw_vertex_shader;
 struct draw_geometry_shader;
 struct tgsi_sampler;
 
+#define DRAW_MAX_TEXTURE_LEVELS 13  /* 4K x 4K for now */
 
 struct draw_context *draw_create( struct pipe_context *pipe );
 
@@ -101,6 +102,23 @@ draw_texture_samplers(struct draw_context *draw,
                       uint num_samplers,
                       struct tgsi_sampler **samplers);
 
+void
+draw_set_sampler_views(struct draw_context *draw,
+                       struct pipe_sampler_view **views,
+                       unsigned num);
+void
+draw_set_samplers(struct draw_context *draw,
+                  struct pipe_sampler_state **samplers,
+                  unsigned num);
+
+void
+draw_set_mapped_texture(struct draw_context *draw,
+                        unsigned sampler_idx,
+                        uint32_t width, uint32_t height, uint32_t depth,
+                        uint32_t last_level,
+                        uint32_t row_stride[DRAW_MAX_TEXTURE_LEVELS],
+                        uint32_t img_stride[DRAW_MAX_TEXTURE_LEVELS],
+                        const void *data[DRAW_MAX_TEXTURE_LEVELS]);
 
 
 /*
diff --git a/src/gallium/auxiliary/draw/draw_llvm.c b/src/gallium/auxiliary/draw/draw_llvm.c
index f521669..42653d3 100644
--- a/src/gallium/auxiliary/draw/draw_llvm.c
+++ b/src/gallium/auxiliary/draw/draw_llvm.c
@@ -42,14 +42,13 @@
 #include "tgsi/tgsi_dump.h"
 
 #include "util/u_cpu_detect.h"
-#include "util/u_string.h"
 #include "util/u_pointer.h"
+#include "util/u_string.h"
 
 #include <llvm-c/Transforms/Scalar.h>
 
 #define DEBUG_STORE 0
 
-
 /* generates the draw jit function */
 static void
 draw_llvm_generate(struct draw_llvm *llvm, struct draw_llvm_variant *var);
@@ -63,12 +62,19 @@ init_globals(struct draw_llvm *llvm)
 
    /* struct draw_jit_texture */
    {
-      LLVMTypeRef elem_types[4];
+      LLVMTypeRef elem_types[DRAW_JIT_TEXTURE_NUM_FIELDS];
 
       elem_types[DRAW_JIT_TEXTURE_WIDTH]  = LLVMInt32Type();
       elem_types[DRAW_JIT_TEXTURE_HEIGHT] = LLVMInt32Type();
-      elem_types[DRAW_JIT_TEXTURE_STRIDE] = LLVMInt32Type();
-      elem_types[DRAW_JIT_TEXTURE_DATA]   = LLVMPointerType(LLVMInt8Type(), 0);
+      elem_types[DRAW_JIT_TEXTURE_DEPTH] = LLVMInt32Type();
+      elem_types[DRAW_JIT_TEXTURE_LAST_LEVEL] = LLVMInt32Type();
+      elem_types[DRAW_JIT_TEXTURE_ROW_STRIDE] =
+         LLVMArrayType(LLVMInt32Type(), DRAW_MAX_TEXTURE_LEVELS);
+      elem_types[DRAW_JIT_TEXTURE_IMG_STRIDE] =
+         LLVMArrayType(LLVMInt32Type(), DRAW_MAX_TEXTURE_LEVELS);
+      elem_types[DRAW_JIT_TEXTURE_DATA] =
+         LLVMArrayType(LLVMPointerType(LLVMInt8Type(), 0),
+                       DRAW_MAX_TEXTURE_LEVELS);
 
       texture_type = LLVMStructType(elem_types, Elements(elem_types), 0);
 
@@ -78,9 +84,18 @@ init_globals(struct draw_llvm *llvm)
       LP_CHECK_MEMBER_OFFSET(struct draw_jit_texture, height,
                              llvm->target, texture_type,
                              DRAW_JIT_TEXTURE_HEIGHT);
-      LP_CHECK_MEMBER_OFFSET(struct draw_jit_texture, stride,
+      LP_CHECK_MEMBER_OFFSET(struct draw_jit_texture, depth,
+                             llvm->target, texture_type,
+                             DRAW_JIT_TEXTURE_DEPTH);
+      LP_CHECK_MEMBER_OFFSET(struct draw_jit_texture, last_level,
+                             llvm->target, texture_type,
+                             DRAW_JIT_TEXTURE_LAST_LEVEL);
+      LP_CHECK_MEMBER_OFFSET(struct draw_jit_texture, row_stride,
                              llvm->target, texture_type,
-                             DRAW_JIT_TEXTURE_STRIDE);
+                             DRAW_JIT_TEXTURE_ROW_STRIDE);
+      LP_CHECK_MEMBER_OFFSET(struct draw_jit_texture, img_stride,
+                             llvm->target, texture_type,
+                             DRAW_JIT_TEXTURE_IMG_STRIDE);
       LP_CHECK_MEMBER_OFFSET(struct draw_jit_texture, data,
                              llvm->target, texture_type,
                              DRAW_JIT_TEXTURE_DATA);
@@ -98,7 +113,8 @@ init_globals(struct draw_llvm *llvm)
 
       elem_types[0] = LLVMPointerType(LLVMFloatType(), 0); /* vs_constants */
       elem_types[1] = LLVMPointerType(LLVMFloatType(), 0); /* vs_constants */
-      elem_types[2] = LLVMArrayType(texture_type, PIPE_MAX_SAMPLERS); /* textures */
+      elem_types[2] = LLVMArrayType(texture_type,
+                                    PIPE_MAX_VERTEX_SAMPLERS); /* textures */
 
       context_type = LLVMStructType(elem_types, Elements(elem_types), 0);
 
@@ -108,7 +124,7 @@ init_globals(struct draw_llvm *llvm)
                              llvm->target, context_type, 1);
       LP_CHECK_MEMBER_OFFSET(struct draw_jit_context, textures,
                              llvm->target, context_type,
-                             DRAW_JIT_CONTEXT_TEXTURES_INDEX);
+                             DRAW_JIT_CTX_TEXTURES);
       LP_CHECK_STRUCT_SIZE(struct draw_jit_context,
                            llvm->target, context_type);
 
@@ -290,7 +306,8 @@ generate_vs(struct draw_llvm *llvm,
             LLVMBuilderRef builder,
             LLVMValueRef (*outputs)[NUM_CHANNELS],
             const LLVMValueRef (*inputs)[NUM_CHANNELS],
-            LLVMValueRef context_ptr)
+            LLVMValueRef context_ptr,
+            struct lp_build_sampler_soa *sampler)
 {
    const struct tgsi_token *tokens = llvm->draw->vs.vertex_shader->state.tokens;
    struct lp_type vs_type;
@@ -318,7 +335,7 @@ generate_vs(struct draw_llvm *llvm,
                      NULL /*pos*/,
                      inputs,
                      outputs,
-                     NULL/*sampler*/,
+                     sampler,
                      &llvm->draw->vs.vertex_shader->info);
 }
 
@@ -641,6 +658,7 @@ draw_llvm_generate(struct draw_llvm *llvm, struct draw_llvm_variant *variant)
    const int max_vertices = 4;
    LLVMValueRef outputs[PIPE_MAX_SHADER_OUTPUTS][NUM_CHANNELS];
    void *code;
+   struct lp_build_sampler_soa *sampler = 0;
 
    arg_types[0] = llvm->context_ptr_type;           /* context */
    arg_types[1] = llvm->vertex_header_ptr_type;     /* vertex_header */
@@ -688,6 +706,10 @@ draw_llvm_generate(struct draw_llvm *llvm, struct draw_llvm_variant *variant)
 
    step = LLVMConstInt(LLVMInt32Type(), max_vertices, 0);
 
+   /* code generated texture sampling */
+   sampler = draw_llvm_sampler_soa_create(variant->key.sampler,
+                                          context_ptr);
+
 #if DEBUG_STORE
    lp_build_printf(builder, "start = %d, end = %d, step = %d\n",
                    start, end, step);
@@ -729,7 +751,8 @@ draw_llvm_generate(struct draw_llvm *llvm, struct draw_llvm_variant *variant)
                   builder,
                   outputs,
                   ptr_aos,
-                  context_ptr);
+                  context_ptr,
+                  sampler);
 
       convert_to_aos(builder, io, outputs,
                      draw->vs.vertex_shader->info.num_outputs,
@@ -737,6 +760,8 @@ draw_llvm_generate(struct draw_llvm *llvm, struct draw_llvm_variant *variant)
    }
    lp_build_loop_end_cond(builder, end, step, LLVMIntUGE, &lp_loop);
 
+   sampler->destroy(sampler);
+
    LLVMBuildRetVoid(builder);
 
    LLVMDisposeBuilder(builder);
@@ -787,6 +812,7 @@ draw_llvm_generate_elts(struct draw_llvm *llvm, struct draw_llvm_variant *varian
    LLVMValueRef outputs[PIPE_MAX_SHADER_OUTPUTS][NUM_CHANNELS];
    LLVMValueRef fetch_max;
    void *code;
+   struct lp_build_sampler_soa *sampler = 0;
 
    arg_types[0] = llvm->context_ptr_type;               /* context */
    arg_types[1] = llvm->vertex_header_ptr_type;         /* vertex_header */
@@ -833,6 +859,10 @@ draw_llvm_generate_elts(struct draw_llvm *llvm, struct draw_llvm_variant *varian
 
    step = LLVMConstInt(LLVMInt32Type(), max_vertices, 0);
 
+   /* code generated texture sampling */
+   sampler = draw_llvm_sampler_soa_create(variant->key.sampler,
+                                          context_ptr);
+
    fetch_max = LLVMBuildSub(builder, fetch_count,
                             LLVMConstInt(LLVMInt32Type(), 1, 0),
                             "fetch_max");
@@ -884,7 +914,8 @@ draw_llvm_generate_elts(struct draw_llvm *llvm, struct draw_llvm_variant *varian
                   builder,
                   outputs,
                   ptr_aos,
-                  context_ptr);
+                  context_ptr,
+                  sampler);
 
       convert_to_aos(builder, io, outputs,
                      draw->vs.vertex_shader->info.num_outputs,
@@ -892,6 +923,8 @@ draw_llvm_generate_elts(struct draw_llvm *llvm, struct draw_llvm_variant *varian
    }
    lp_build_loop_end_cond(builder, fetch_count, step, LLVMIntUGE, &lp_loop);
 
+   sampler->destroy(sampler);
+
    LLVMBuildRetVoid(builder);
 
    LLVMDisposeBuilder(builder);
@@ -925,6 +958,8 @@ void
 draw_llvm_make_variant_key(struct draw_llvm *llvm,
                            struct draw_llvm_variant_key *key)
 {
+   unsigned i;
+
    memset(key, 0, sizeof(struct draw_llvm_variant_key));
 
    key->nr_vertex_elements = llvm->draw->pt.nr_vertex_elements;
@@ -936,6 +971,43 @@ draw_llvm_make_variant_key(struct draw_llvm *llvm,
    memcpy(&key->vs,
           &llvm->draw->vs.vertex_shader->state,
           sizeof(struct pipe_shader_state));
+
+   for(i = 0; i < PIPE_MAX_VERTEX_SAMPLERS; ++i) {
+      struct draw_vertex_shader *shader = llvm->draw->vs.vertex_shader;
+      if(shader->info.file_mask[TGSI_FILE_SAMPLER] & (1 << i))
+         lp_sampler_static_state(&key->sampler[i],
+                                 llvm->draw->sampler_views[i],
+                                 llvm->draw->samplers[i]);
+   }
+}
+
+void
+draw_llvm_set_mapped_texture(struct draw_context *draw,
+                             unsigned sampler_idx,
+                             uint32_t width, uint32_t height, uint32_t depth,
+                             uint32_t last_level,
+                             uint32_t row_stride[DRAW_MAX_TEXTURE_LEVELS],
+                             uint32_t img_stride[DRAW_MAX_TEXTURE_LEVELS],
+                             const void *data[DRAW_MAX_TEXTURE_LEVELS])
+{
+   unsigned j;
+   struct draw_jit_texture *jit_tex;
+
+   assert(sampler_idx <= PIPE_MAX_VERTEX_SAMPLERS);
+
+
+   jit_tex = &draw->llvm->jit_context.textures[sampler_idx];
+
+   jit_tex->width = width;
+   jit_tex->height = height;
+   jit_tex->depth = depth;
+   jit_tex->last_level = last_level;
+
+   for (j = 0; j <= last_level; j++) {
+      jit_tex->data[j] = data[j];
+      jit_tex->row_stride[j] = row_stride[j];
+      jit_tex->img_stride[j] = img_stride[j];
+   }
 }
 
 void
diff --git a/src/gallium/auxiliary/draw/draw_llvm.h b/src/gallium/auxiliary/draw/draw_llvm.h
index 1ef009b..0544651 100644
--- a/src/gallium/auxiliary/draw/draw_llvm.h
+++ b/src/gallium/auxiliary/draw/draw_llvm.h
@@ -25,12 +25,13 @@
  *
  **************************************************************************/
 
-#ifndef HAVE_LLVM_H
-#define HAVE_LLVM_H
+#ifndef DRAW_LLVM_H
+#define DRAW_LLVM_H
 
 #include "draw/draw_private.h"
 
 #include "draw/draw_vs.h"
+#include "gallivm/lp_bld_sample.h"
 
 #include "pipe/p_context.h"
 #include "util/u_simple_list.h"
@@ -40,6 +41,8 @@
 #include <llvm-c/Target.h>
 #include <llvm-c/ExecutionEngine.h>
 
+#define DRAW_MAX_TEXTURE_LEVELS 13  /* 4K x 4K for now */
+
 struct draw_llvm;
 struct llvm_vertex_shader;
 
@@ -47,15 +50,22 @@ struct draw_jit_texture
 {
    uint32_t width;
    uint32_t height;
-   uint32_t stride;
-   const void *data;
+   uint32_t depth;
+   uint32_t last_level;
+   uint32_t row_stride[DRAW_MAX_TEXTURE_LEVELS];
+   uint32_t img_stride[DRAW_MAX_TEXTURE_LEVELS];
+   const void *data[DRAW_MAX_TEXTURE_LEVELS];
 };
 
 enum {
    DRAW_JIT_TEXTURE_WIDTH = 0,
    DRAW_JIT_TEXTURE_HEIGHT,
-   DRAW_JIT_TEXTURE_STRIDE,
-   DRAW_JIT_TEXTURE_DATA
+   DRAW_JIT_TEXTURE_DEPTH,
+   DRAW_JIT_TEXTURE_LAST_LEVEL,
+   DRAW_JIT_TEXTURE_ROW_STRIDE,
+   DRAW_JIT_TEXTURE_IMG_STRIDE,
+   DRAW_JIT_TEXTURE_DATA,
+   DRAW_JIT_TEXTURE_NUM_FIELDS  /* number of fields above */
 };
 
 enum {
@@ -81,7 +91,7 @@ struct draw_jit_context
    const float *gs_constants;
 
 
-   struct draw_jit_texture textures[PIPE_MAX_SAMPLERS];
+   struct draw_jit_texture textures[PIPE_MAX_VERTEX_SAMPLERS];
 };
 
 
@@ -91,10 +101,10 @@ struct draw_jit_context
 #define draw_jit_context_gs_constants(_builder, _ptr) \
    lp_build_struct_get(_builder, _ptr, 1, "gs_constants")
 
-#define DRAW_JIT_CONTEXT_TEXTURES_INDEX 2
+#define DRAW_JIT_CTX_TEXTURES 2
 
 #define draw_jit_context_textures(_builder, _ptr) \
-   lp_build_struct_get_ptr(_builder, _ptr, DRAW_JIT_CONTEXT_TEXTURES_INDEX, "textures")
+   lp_build_struct_get_ptr(_builder, _ptr, DRAW_JIT_CTX_TEXTURES, "textures")
 
 
 
@@ -142,6 +152,7 @@ struct draw_llvm_variant_key
    struct pipe_vertex_element vertex_element[PIPE_MAX_ATTRIBS];
    unsigned                   nr_vertex_elements;
    struct pipe_shader_state   vs;
+   struct lp_sampler_static_state sampler[PIPE_MAX_VERTEX_SAMPLERS];
 };
 
 struct draw_llvm_variant_list_item
@@ -221,4 +232,17 @@ draw_llvm_translate_from(LLVMBuilderRef builder,
                          LLVMValueRef vbuffer,
                          enum pipe_format from_format);
 
+struct lp_build_sampler_soa *
+draw_llvm_sampler_soa_create(const struct lp_sampler_static_state *static_state,
+                             LLVMValueRef context_ptr);
+
+void
+draw_llvm_set_mapped_texture(struct draw_context *draw,
+                             unsigned sampler_idx,
+                             uint32_t width, uint32_t height, uint32_t depth,
+                             uint32_t last_level,
+                             uint32_t row_stride[DRAW_MAX_TEXTURE_LEVELS],
+                             uint32_t img_stride[DRAW_MAX_TEXTURE_LEVELS],
+                             const void *data[DRAW_MAX_TEXTURE_LEVELS]);
+
 #endif
diff --git a/src/gallium/auxiliary/draw/draw_llvm_sample.c b/src/gallium/auxiliary/draw/draw_llvm_sample.c
new file mode 100644
index 0000000..2613224
--- /dev/null
+++ b/src/gallium/auxiliary/draw/draw_llvm_sample.c
@@ -0,0 +1,216 @@
+/**************************************************************************
+ *
+ * Copyright 2010 VMware, Inc.
+ * All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ **************************************************************************/
+
+/**
+ * Texture sampling code generation
+ * @author Jose Fonseca <jfonseca at vmware.com>
+ */
+
+#include "pipe/p_defines.h"
+#include "pipe/p_shader_tokens.h"
+#include "gallivm/lp_bld_debug.h"
+#include "gallivm/lp_bld_type.h"
+#include "gallivm/lp_bld_sample.h"
+#include "gallivm/lp_bld_tgsi.h"
+
+
+#include "util/u_cpu_detect.h"
+#include "util/u_debug.h"
+#include "util/u_memory.h"
+#include "util/u_pointer.h"
+#include "util/u_string.h"
+
+#include "draw_llvm.h"
+
+
+/**
+ * This provides the bridge between the sampler state store in
+ * lp_jit_context and lp_jit_texture and the sampler code
+ * generator. It provides the texture layout information required by
+ * the texture sampler code generator in terms of the state stored in
+ * lp_jit_context and lp_jit_texture in runtime.
+ */
+struct draw_llvm_sampler_dynamic_state
+{
+   struct lp_sampler_dynamic_state base;
+
+   const struct lp_sampler_static_state *static_state;
+
+   LLVMValueRef context_ptr;
+};
+
+
+/**
+ * This is the bridge between our sampler and the TGSI translator.
+ */
+struct draw_llvm_sampler_soa
+{
+   struct lp_build_sampler_soa base;
+
+   struct draw_llvm_sampler_dynamic_state dynamic_state;
+};
+
+
+/**
+ * Fetch the specified member of the lp_jit_texture 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
+draw_llvm_texture_member(const struct lp_sampler_dynamic_state *base,
+                         LLVMBuilderRef builder,
+                         unsigned unit,
+                         unsigned member_index,
+                         const char *member_name,
+                         boolean emit_load)
+{
+   struct draw_llvm_sampler_dynamic_state *state =
+      (struct draw_llvm_sampler_dynamic_state *)base;
+   LLVMValueRef indices[4];
+   LLVMValueRef ptr;
+   LLVMValueRef res;
+
+   debug_assert(unit < PIPE_MAX_VERTEX_SAMPLERS);
+
+   /* context[0] */
+   indices[0] = LLVMConstInt(LLVMInt32Type(), 0, 0);
+   /* context[0].textures */
+   indices[1] = LLVMConstInt(LLVMInt32Type(), DRAW_JIT_CTX_TEXTURES, 0);
+   /* context[0].textures[unit] */
+   indices[2] = LLVMConstInt(LLVMInt32Type(), unit, 0);
+   /* context[0].textures[unit].member */
+   indices[3] = LLVMConstInt(LLVMInt32Type(), member_index, 0);
+
+   ptr = LLVMBuildGEP(builder, state->context_ptr, indices, Elements(indices), "");
+
+   if (emit_load)
+      res = LLVMBuildLoad(builder, ptr, "");
+   else
+      res = ptr;
+
+   lp_build_name(res, "context.texture%u.%s", unit, member_name);
+
+   return res;
+}
+
+
+/**
+ * Helper macro to instantiate the functions that generate the code to
+ * fetch the members of lp_jit_texture to fulfill the sampler code
+ * generator requests.
+ *
+ * This complexity is the price we have to pay to keep the texture
+ * sampler code generator a reusable module without dependencies to
+ * llvmpipe internals.
+ */
+#define DRAW_LLVM_TEXTURE_MEMBER(_name, _index, _emit_load)  \
+   static LLVMValueRef \
+   draw_llvm_texture_##_name( const struct lp_sampler_dynamic_state *base, \
+                              LLVMBuilderRef builder,                   \
+                              unsigned unit)                            \
+   { \
+      return draw_llvm_texture_member(base, builder, unit, _index, #_name, _emit_load ); \
+   }
+
+
+DRAW_LLVM_TEXTURE_MEMBER(width,      DRAW_JIT_TEXTURE_WIDTH, TRUE)
+DRAW_LLVM_TEXTURE_MEMBER(height,     DRAW_JIT_TEXTURE_HEIGHT, TRUE)
+DRAW_LLVM_TEXTURE_MEMBER(depth,      DRAW_JIT_TEXTURE_DEPTH, TRUE)
+DRAW_LLVM_TEXTURE_MEMBER(last_level, DRAW_JIT_TEXTURE_LAST_LEVEL, TRUE)
+DRAW_LLVM_TEXTURE_MEMBER(row_stride, DRAW_JIT_TEXTURE_ROW_STRIDE, FALSE)
+DRAW_LLVM_TEXTURE_MEMBER(img_stride, DRAW_JIT_TEXTURE_IMG_STRIDE, FALSE)
+DRAW_LLVM_TEXTURE_MEMBER(data_ptr,   DRAW_JIT_TEXTURE_DATA, FALSE)
+
+
+static void
+draw_llvm_sampler_soa_destroy(struct lp_build_sampler_soa *sampler)
+{
+   FREE(sampler);
+}
+
+
+/**
+ * Fetch filtered values from texture.
+ * The 'texel' parameter returns four vectors corresponding to R, G, B, A.
+ */
+static void
+draw_llvm_sampler_soa_emit_fetch_texel(const struct lp_build_sampler_soa *base,
+                                       LLVMBuilderRef builder,
+                                       struct lp_type type,
+                                       unsigned unit,
+                                       unsigned num_coords,
+                                       const LLVMValueRef *coords,
+                                       const LLVMValueRef *ddx,
+                                       const LLVMValueRef *ddy,
+                                       LLVMValueRef lod_bias, /* optional */
+                                       LLVMValueRef explicit_lod, /* optional */
+                                       LLVMValueRef *texel)
+{
+   struct draw_llvm_sampler_soa *sampler = (struct draw_llvm_sampler_soa *)base;
+
+   assert(unit < PIPE_MAX_VERTEX_SAMPLERS);
+
+   lp_build_sample_soa(builder,
+                       &sampler->dynamic_state.static_state[unit],
+                       &sampler->dynamic_state.base,
+                       type,
+                       unit,
+                       num_coords, coords,
+                       ddx, ddy,
+                       lod_bias, explicit_lod,
+                       texel);
+}
+
+
+struct lp_build_sampler_soa *
+draw_llvm_sampler_soa_create(const struct lp_sampler_static_state *static_state,
+                             LLVMValueRef context_ptr)
+{
+   struct draw_llvm_sampler_soa *sampler;
+
+   sampler = CALLOC_STRUCT(draw_llvm_sampler_soa);
+   if(!sampler)
+      return NULL;
+
+   sampler->base.destroy = draw_llvm_sampler_soa_destroy;
+   sampler->base.emit_fetch_texel = draw_llvm_sampler_soa_emit_fetch_texel;
+   sampler->dynamic_state.base.width = draw_llvm_texture_width;
+   sampler->dynamic_state.base.height = draw_llvm_texture_height;
+   sampler->dynamic_state.base.depth = draw_llvm_texture_depth;
+   sampler->dynamic_state.base.last_level = draw_llvm_texture_last_level;
+   sampler->dynamic_state.base.row_stride = draw_llvm_texture_row_stride;
+   sampler->dynamic_state.base.img_stride = draw_llvm_texture_img_stride;
+   sampler->dynamic_state.base.data_ptr = draw_llvm_texture_data_ptr;
+   sampler->dynamic_state.static_state = static_state;
+   sampler->dynamic_state.context_ptr = context_ptr;
+
+   return &sampler->base;
+}
+
diff --git a/src/gallium/auxiliary/draw/draw_private.h b/src/gallium/auxiliary/draw/draw_private.h
index 54944a7..8af8859 100644
--- a/src/gallium/auxiliary/draw/draw_private.h
+++ b/src/gallium/auxiliary/draw/draw_private.h
@@ -48,6 +48,7 @@
 
 #ifdef HAVE_LLVM
 #include <llvm-c/ExecutionEngine.h>
+struct draw_llvm;
 #endif
 
 
@@ -262,9 +263,15 @@ struct draw_context
    unsigned instance_id;
 
 #ifdef HAVE_LLVM
+   struct draw_llvm *llvm;
    LLVMExecutionEngineRef engine;
 #endif
 
+   struct pipe_sampler_view *sampler_views[PIPE_MAX_VERTEX_SAMPLERS];
+   unsigned num_sampler_views;
+   const struct pipe_sampler_state *samplers[PIPE_MAX_VERTEX_SAMPLERS];
+   unsigned num_samplers;
+
    void *driver_private;
 };
 
diff --git a/src/gallium/auxiliary/draw/draw_pt_fetch_shade_pipeline_llvm.c b/src/gallium/auxiliary/draw/draw_pt_fetch_shade_pipeline_llvm.c
index d33969a..6aefbed 100644
--- a/src/gallium/auxiliary/draw/draw_pt_fetch_shade_pipeline_llvm.c
+++ b/src/gallium/auxiliary/draw/draw_pt_fetch_shade_pipeline_llvm.c
@@ -392,9 +392,6 @@ static void llvm_middle_end_destroy( struct draw_pt_middle_end *middle )
    if (fpme->post_vs)
       draw_pt_post_vs_destroy( fpme->post_vs );
 
-   if (fpme->llvm)
-      draw_llvm_destroy( fpme->llvm );
-
    FREE(middle);
 }
 
@@ -436,7 +433,7 @@ draw_pt_fetch_pipeline_or_emit_llvm(struct draw_context *draw)
    if (!fpme->so_emit)
       goto fail;
 
-   fpme->llvm = draw_llvm_create(draw);
+   fpme->llvm = draw->llvm;
    if (!fpme->llvm)
       goto fail;
 
diff --git a/src/gallium/drivers/llvmpipe/lp_screen.c b/src/gallium/drivers/llvmpipe/lp_screen.c
index 49b13f4..edcab0f 100644
--- a/src/gallium/drivers/llvmpipe/lp_screen.c
+++ b/src/gallium/drivers/llvmpipe/lp_screen.c
@@ -86,7 +86,7 @@ llvmpipe_get_param(struct pipe_screen *screen, enum pipe_cap param)
    case PIPE_CAP_MAX_TEXTURE_IMAGE_UNITS:
       return PIPE_MAX_SAMPLERS;
    case PIPE_CAP_MAX_VERTEX_TEXTURE_UNITS:
-      return 0;
+      return PIPE_MAX_VERTEX_SAMPLERS;
    case PIPE_CAP_MAX_COMBINED_SAMPLERS:
       return PIPE_MAX_SAMPLERS + PIPE_MAX_VERTEX_SAMPLERS;
    case PIPE_CAP_NPOT_TEXTURES:
diff --git a/src/gallium/drivers/llvmpipe/lp_setup.c b/src/gallium/drivers/llvmpipe/lp_setup.c
index 2597fa8..fcb6e06 100644
--- a/src/gallium/drivers/llvmpipe/lp_setup.c
+++ b/src/gallium/drivers/llvmpipe/lp_setup.c
@@ -641,7 +641,6 @@ lp_setup_set_fragment_sampler_views(struct lp_setup_context *setup,
             /*
              * XXX: Where should this be unmapped?
              */
-
             struct llvmpipe_screen *screen = llvmpipe_screen(tex->screen);
             struct sw_winsys *winsys = screen->winsys;
             jit_tex->data[0] = winsys->displaytarget_map(winsys, lp_tex->dt,
@@ -658,6 +657,75 @@ lp_setup_set_fragment_sampler_views(struct lp_setup_context *setup,
 
 
 /**
+ * Called during state validation when LP_NEW_SAMPLER_VIEW is set.
+ */
+void
+lp_setup_set_vertex_sampler_views(struct lp_setup_context *setup,
+                                  unsigned num,
+                                  struct pipe_sampler_view **views)
+{
+   unsigned i;
+   uint32_t row_stride[DRAW_MAX_TEXTURE_LEVELS];
+   uint32_t img_stride[DRAW_MAX_TEXTURE_LEVELS];
+   const void *data[DRAW_MAX_TEXTURE_LEVELS];
+   struct lp_scene *scene;
+   struct llvmpipe_context *lp;
+
+   LP_DBG(DEBUG_SETUP, "%s\n", __FUNCTION__);
+
+   assert(num <= PIPE_MAX_VERTEX_SAMPLERS);
+
+   scene = lp_setup_get_current_scene(setup);
+   lp = llvmpipe_context(scene->pipe);
+
+   for (i = 0; i < PIPE_MAX_VERTEX_SAMPLERS; i++) {
+      struct pipe_sampler_view *view = i < num ? views[i] : NULL;
+
+      if (view) {
+         struct pipe_resource *tex = view->texture;
+         struct llvmpipe_resource *lp_tex = llvmpipe_resource(tex);
+
+         /* We're referencing the texture's internal data, so save a
+          * reference to it.
+          */
+         pipe_resource_reference(&setup->vs.current_tex[i], tex);
+
+         if (!lp_tex->dt) {
+            /* regular texture - setup array of mipmap level pointers */
+            int j;
+            for (j = 0; j <= tex->last_level; j++) {
+               data[j] =
+                  llvmpipe_get_texture_image_all(lp_tex, j, LP_TEX_USAGE_READ,
+                                                 LP_TEX_LAYOUT_LINEAR);
+               row_stride[j] = lp_tex->row_stride[j];
+               img_stride[j] = lp_tex->img_stride[j];
+            }
+         }
+         else {
+            /* display target texture/surface */
+            /*
+             * XXX: Where should this be unmapped?
+             */
+            struct llvmpipe_screen *screen = llvmpipe_screen(tex->screen);
+            struct sw_winsys *winsys = screen->winsys;
+            data[0] = winsys->displaytarget_map(winsys, lp_tex->dt,
+                                                PIPE_TRANSFER_READ);
+            row_stride[0] = lp_tex->row_stride[0];
+            img_stride[0] = lp_tex->img_stride[0];
+            assert(data[0]);
+         }
+         draw_set_mapped_texture(lp->draw,
+                                 i,
+                                 tex->width0, tex->height0, tex->depth0,
+                                 tex->last_level,
+                                 row_stride, img_stride, data);
+      }
+   }
+}
+
+
+
+/**
  * Is the given texture referenced by any scene?
  * Note: we have to check all scenes including any scenes currently
  * being rendered and the current scene being built.
@@ -850,6 +918,9 @@ lp_setup_destroy( struct lp_setup_context *setup )
 
    util_unreference_framebuffer_state(&setup->fb);
 
+   for (i = 0; i < Elements(setup->vs.current_tex); i++) {
+      pipe_resource_reference(&setup->vs.current_tex[i], NULL);
+   }
    for (i = 0; i < Elements(setup->fs.current_tex); i++) {
       pipe_resource_reference(&setup->fs.current_tex[i], NULL);
    }
diff --git a/src/gallium/drivers/llvmpipe/lp_setup.h b/src/gallium/drivers/llvmpipe/lp_setup.h
index 6a0dc55..fd2c927 100644
--- a/src/gallium/drivers/llvmpipe/lp_setup.h
+++ b/src/gallium/drivers/llvmpipe/lp_setup.h
@@ -133,6 +133,11 @@ lp_setup_set_fragment_sampler_views(struct lp_setup_context *setup,
                                     unsigned num,
                                     struct pipe_sampler_view **views);
 
+void
+lp_setup_set_vertex_sampler_views(struct lp_setup_context *setup,
+                                  unsigned num,
+                                  struct pipe_sampler_view **views);
+
 unsigned
 lp_setup_is_resource_referenced( const struct lp_setup_context *setup,
                                 const struct pipe_resource *texture );
diff --git a/src/gallium/drivers/llvmpipe/lp_setup_context.h b/src/gallium/drivers/llvmpipe/lp_setup_context.h
index 8f4e00f..947d5ef 100644
--- a/src/gallium/drivers/llvmpipe/lp_setup_context.h
+++ b/src/gallium/drivers/llvmpipe/lp_setup_context.h
@@ -116,6 +116,10 @@ struct lp_setup_context
       struct pipe_resource *current_tex[PIPE_MAX_SAMPLERS];
    } fs;
 
+   struct {
+      struct pipe_resource *current_tex[PIPE_MAX_VERTEX_SAMPLERS];
+   } vs;
+
    /** fragment shader constants */
    struct {
       struct pipe_resource *current;
diff --git a/src/gallium/drivers/llvmpipe/lp_state_derived.c b/src/gallium/drivers/llvmpipe/lp_state_derived.c
index d20a521..263b117 100644
--- a/src/gallium/drivers/llvmpipe/lp_state_derived.c
+++ b/src/gallium/drivers/llvmpipe/lp_state_derived.c
@@ -188,10 +188,14 @@ void llvmpipe_update_derived( struct llvmpipe_context *llvmpipe )
       lp_setup_set_fs_constants(llvmpipe->setup, 
                                 llvmpipe->constants[PIPE_SHADER_FRAGMENT][0]);
 
-   if (llvmpipe->dirty & LP_NEW_SAMPLER_VIEW)
-      lp_setup_set_fragment_sampler_views(llvmpipe->setup, 
+   if (llvmpipe->dirty & LP_NEW_SAMPLER_VIEW) {
+      lp_setup_set_fragment_sampler_views(llvmpipe->setup,
                                           llvmpipe->num_fragment_sampler_views,
                                           llvmpipe->fragment_sampler_views);
+      lp_setup_set_vertex_sampler_views(llvmpipe->setup,
+                                        llvmpipe->num_vertex_sampler_views,
+                                        llvmpipe->vertex_sampler_views);
+   }
 
    llvmpipe->dirty = 0;
 }
diff --git a/src/gallium/drivers/llvmpipe/lp_state_sampler.c b/src/gallium/drivers/llvmpipe/lp_state_sampler.c
index e94065f..0fea7f2 100644
--- a/src/gallium/drivers/llvmpipe/lp_state_sampler.c
+++ b/src/gallium/drivers/llvmpipe/lp_state_sampler.c
@@ -100,6 +100,10 @@ llvmpipe_bind_vertex_sampler_states(struct pipe_context *pipe,
 
    llvmpipe->num_vertex_samplers = num_samplers;
 
+   draw_set_samplers(llvmpipe->draw,
+                     llvmpipe->vertex_samplers,
+                     llvmpipe->num_vertex_samplers);
+
    llvmpipe->dirty |= LP_NEW_SAMPLER;
 }
 
@@ -166,6 +170,10 @@ llvmpipe_set_vertex_sampler_views(struct pipe_context *pipe,
 
    llvmpipe->num_vertex_sampler_views = num;
 
+   draw_set_sampler_views(llvmpipe->draw,
+                          llvmpipe->vertex_sampler_views,
+                          llvmpipe->num_vertex_sampler_views);
+
    llvmpipe->dirty |= LP_NEW_SAMPLER_VIEW;
 }
 




More information about the mesa-commit mailing list