summaryrefslogtreecommitdiffstats
path: root/src/gallium/auxiliary/draw/draw_llvm.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/gallium/auxiliary/draw/draw_llvm.c')
-rw-r--r--src/gallium/auxiliary/draw/draw_llvm.c229
1 files changed, 205 insertions, 24 deletions
diff --git a/src/gallium/auxiliary/draw/draw_llvm.c b/src/gallium/auxiliary/draw/draw_llvm.c
index 9117c1303dc..19f96c37ab4 100644
--- a/src/gallium/auxiliary/draw/draw_llvm.c
+++ b/src/gallium/auxiliary/draw/draw_llvm.c
@@ -1,3 +1,30 @@
+/**************************************************************************
+ *
+ * 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.
+ *
+ **************************************************************************/
+
#include "draw_llvm.h"
#include "draw_context.h"
@@ -15,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);
@@ -36,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);
@@ -51,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);
@@ -71,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);
@@ -81,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);
@@ -195,9 +238,22 @@ draw_llvm_create(struct draw_context *draw)
/* These are the passes currently listed in llvm-c/Transforms/Scalar.h,
* but there are more on SVN. */
/* TODO: Add more passes */
+
LLVMAddCFGSimplificationPass(llvm->pass);
- LLVMAddPromoteMemoryToRegisterPass(llvm->pass);
- LLVMAddConstantPropagationPass(llvm->pass);
+
+ if (HAVE_LLVM >= 0x207 && sizeof(void*) == 4) {
+ /* For LLVM >= 2.7 and 32-bit build, use this order of passes to
+ * avoid generating bad code.
+ * Test with piglit glsl-vs-sqrt-zero test.
+ */
+ LLVMAddConstantPropagationPass(llvm->pass);
+ LLVMAddPromoteMemoryToRegisterPass(llvm->pass);
+ }
+ else {
+ LLVMAddPromoteMemoryToRegisterPass(llvm->pass);
+ LLVMAddConstantPropagationPass(llvm->pass);
+ }
+
if(util_cpu_caps.has_sse4_1) {
/* FIXME: There is a bug in this pass, whereby the combination of fptosi
* and sitofp (necessary for trunc/floor/ceil/round implementation)
@@ -219,6 +275,9 @@ draw_llvm_create(struct draw_context *draw)
LLVMDumpModule(llvm->module);
}
+ llvm->nr_variants = 0;
+ make_empty_list(&llvm->vs_variants_list);
+
return llvm;
}
@@ -231,9 +290,13 @@ draw_llvm_destroy(struct draw_llvm *llvm)
}
struct draw_llvm_variant *
-draw_llvm_prepare(struct draw_llvm *llvm, int num_inputs)
+draw_llvm_create_variant(struct draw_llvm *llvm, int num_inputs)
{
struct draw_llvm_variant *variant = MALLOC(sizeof(struct draw_llvm_variant));
+ struct llvm_vertex_shader *shader =
+ llvm_vertex_shader(llvm->draw->vs.vertex_shader);
+
+ variant->llvm = llvm;
draw_llvm_make_variant_key(llvm, &variant->key);
@@ -242,6 +305,12 @@ draw_llvm_prepare(struct draw_llvm *llvm, int num_inputs)
draw_llvm_generate(llvm, variant);
draw_llvm_generate_elts(llvm, variant);
+ variant->shader = shader;
+ variant->list_item_global.base = variant;
+ variant->list_item_local.base = variant;
+ /*variant->no = */shader->variants_created++;
+ variant->list_item_global.base = variant;
+
return variant;
}
@@ -250,11 +319,13 @@ 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 *draw_sampler)
{
const struct tgsi_token *tokens = llvm->draw->vs.vertex_shader->state.tokens;
struct lp_type vs_type;
LLVMValueRef consts_ptr = draw_jit_context_vs_constants(builder, context_ptr);
+ struct lp_build_sampler_soa *sampler = 0;
memset(&vs_type, 0, sizeof vs_type);
vs_type.floating = TRUE; /* floating point values */
@@ -270,6 +341,10 @@ generate_vs(struct draw_llvm *llvm,
tgsi_dump(tokens, 0);
}
+ if (llvm->draw->num_sampler_views &&
+ llvm->draw->num_samplers)
+ sampler = draw_sampler;
+
lp_build_tgsi_soa(builder,
tokens,
vs_type,
@@ -278,7 +353,7 @@ generate_vs(struct draw_llvm *llvm,
NULL /*pos*/,
inputs,
outputs,
- NULL/*sampler*/,
+ sampler,
&llvm->draw->vs.vertex_shader->info);
}
@@ -306,7 +381,8 @@ generate_fetch(LLVMBuilderRef builder,
LLVMValueRef *res,
struct pipe_vertex_element *velem,
LLVMValueRef vbuf,
- LLVMValueRef index)
+ LLVMValueRef index,
+ LLVMValueRef instance_id)
{
LLVMValueRef indices = LLVMConstInt(LLVMInt64Type(), velem->vertex_buffer_index, 0);
LLVMValueRef vbuffer_ptr = LLVMBuildGEP(builder, vbuffers_ptr,
@@ -317,8 +393,15 @@ generate_fetch(LLVMBuilderRef builder,
LLVMValueRef cond;
LLVMValueRef stride;
- cond = LLVMBuildICmp(builder, LLVMIntULE, index, vb_max_index, "");
+ if (velem->instance_divisor) {
+ /* array index = instance_id / instance_divisor */
+ index = LLVMBuildUDiv(builder, instance_id,
+ LLVMConstInt(LLVMInt32Type(), velem->instance_divisor, 0),
+ "instance_divisor");
+ }
+ /* limit index to min(inex, vb_max_index) */
+ cond = LLVMBuildICmp(builder, LLVMIntULE, index, vb_max_index, "");
index = LLVMBuildSelect(builder, cond, index, vb_max_index, "");
stride = LLVMBuildMul(builder, vb_stride, index, "");
@@ -586,13 +669,14 @@ convert_to_aos(LLVMBuilderRef builder,
static void
draw_llvm_generate(struct draw_llvm *llvm, struct draw_llvm_variant *variant)
{
- LLVMTypeRef arg_types[7];
+ LLVMTypeRef arg_types[8];
LLVMTypeRef func_type;
LLVMValueRef context_ptr;
LLVMBasicBlockRef block;
LLVMBuilderRef builder;
LLVMValueRef start, end, count, stride, step, io_itr;
LLVMValueRef io_ptr, vbuffers_ptr, vb_ptr;
+ LLVMValueRef instance_id;
struct draw_context *draw = llvm->draw;
unsigned i, j;
struct lp_build_context bld;
@@ -601,6 +685,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 */
@@ -609,6 +694,7 @@ draw_llvm_generate(struct draw_llvm *llvm, struct draw_llvm_variant *variant)
arg_types[4] = LLVMInt32Type(); /* count */
arg_types[5] = LLVMInt32Type(); /* stride */
arg_types[6] = llvm->vb_ptr_type; /* pipe_vertex_buffer's */
+ arg_types[7] = LLVMInt32Type(); /* instance_id */
func_type = LLVMFunctionType(LLVMVoidType(), arg_types, Elements(arg_types), 0);
@@ -625,6 +711,7 @@ draw_llvm_generate(struct draw_llvm *llvm, struct draw_llvm_variant *variant)
count = LLVMGetParam(variant->function, 4);
stride = LLVMGetParam(variant->function, 5);
vb_ptr = LLVMGetParam(variant->function, 6);
+ instance_id = LLVMGetParam(variant->function, 7);
lp_build_name(context_ptr, "context");
lp_build_name(io_ptr, "io");
@@ -633,6 +720,7 @@ draw_llvm_generate(struct draw_llvm *llvm, struct draw_llvm_variant *variant)
lp_build_name(count, "count");
lp_build_name(stride, "stride");
lp_build_name(vb_ptr, "vb");
+ lp_build_name(instance_id, "instance_id");
/*
* Function body
@@ -648,6 +736,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);
@@ -678,7 +770,8 @@ draw_llvm_generate(struct draw_llvm *llvm, struct draw_llvm_variant *variant)
LLVMValueRef vb = LLVMBuildGEP(builder, vb_ptr,
&vb_index, 1, "");
generate_fetch(builder, vbuffers_ptr,
- &aos_attribs[j][i], velem, vb, true_index);
+ &aos_attribs[j][i], velem, vb, true_index,
+ instance_id);
}
}
convert_to_soa(builder, aos_attribs, inputs,
@@ -689,7 +782,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,
@@ -697,6 +791,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);
@@ -730,13 +826,14 @@ draw_llvm_generate(struct draw_llvm *llvm, struct draw_llvm_variant *variant)
static void
draw_llvm_generate_elts(struct draw_llvm *llvm, struct draw_llvm_variant *variant)
{
- LLVMTypeRef arg_types[7];
+ LLVMTypeRef arg_types[8];
LLVMTypeRef func_type;
LLVMValueRef context_ptr;
LLVMBasicBlockRef block;
LLVMBuilderRef builder;
LLVMValueRef fetch_elts, fetch_count, stride, step, io_itr;
LLVMValueRef io_ptr, vbuffers_ptr, vb_ptr;
+ LLVMValueRef instance_id;
struct draw_context *draw = llvm->draw;
unsigned i, j;
struct lp_build_context bld;
@@ -747,6 +844,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 */
@@ -755,14 +853,17 @@ draw_llvm_generate_elts(struct draw_llvm *llvm, struct draw_llvm_variant *varian
arg_types[4] = LLVMInt32Type(); /* fetch_count */
arg_types[5] = LLVMInt32Type(); /* stride */
arg_types[6] = llvm->vb_ptr_type; /* pipe_vertex_buffer's */
+ arg_types[7] = LLVMInt32Type(); /* instance_id */
func_type = LLVMFunctionType(LLVMVoidType(), arg_types, Elements(arg_types), 0);
- variant->function_elts = LLVMAddFunction(llvm->module, "draw_llvm_shader_elts", func_type);
+ variant->function_elts = LLVMAddFunction(llvm->module, "draw_llvm_shader_elts",
+ func_type);
LLVMSetFunctionCallConv(variant->function_elts, LLVMCCallConv);
for(i = 0; i < Elements(arg_types); ++i)
if(LLVMGetTypeKind(arg_types[i]) == LLVMPointerTypeKind)
- LLVMAddAttribute(LLVMGetParam(variant->function_elts, i), LLVMNoAliasAttribute);
+ LLVMAddAttribute(LLVMGetParam(variant->function_elts, i),
+ LLVMNoAliasAttribute);
context_ptr = LLVMGetParam(variant->function_elts, 0);
io_ptr = LLVMGetParam(variant->function_elts, 1);
@@ -771,6 +872,7 @@ draw_llvm_generate_elts(struct draw_llvm *llvm, struct draw_llvm_variant *varian
fetch_count = LLVMGetParam(variant->function_elts, 4);
stride = LLVMGetParam(variant->function_elts, 5);
vb_ptr = LLVMGetParam(variant->function_elts, 6);
+ instance_id = LLVMGetParam(variant->function_elts, 7);
lp_build_name(context_ptr, "context");
lp_build_name(io_ptr, "io");
@@ -779,6 +881,7 @@ draw_llvm_generate_elts(struct draw_llvm *llvm, struct draw_llvm_variant *varian
lp_build_name(fetch_count, "fetch_count");
lp_build_name(stride, "stride");
lp_build_name(vb_ptr, "vb");
+ lp_build_name(instance_id, "instance_id");
/*
* Function body
@@ -793,6 +896,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");
@@ -833,7 +940,8 @@ draw_llvm_generate_elts(struct draw_llvm *llvm, struct draw_llvm_variant *varian
LLVMValueRef vb = LLVMBuildGEP(builder, vb_ptr,
&vb_index, 1, "");
generate_fetch(builder, vbuffers_ptr,
- &aos_attribs[j][i], velem, vb, true_index);
+ &aos_attribs[j][i], velem, vb, true_index,
+ instance_id);
}
}
convert_to_soa(builder, aos_attribs, inputs,
@@ -844,7 +952,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,
@@ -852,6 +961,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);
@@ -885,6 +996,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;
@@ -896,4 +1009,72 @@ draw_llvm_make_variant_key(struct draw_llvm *llvm,
memcpy(&key->vs,
&llvm->draw->vs.vertex_shader->state,
sizeof(struct pipe_shader_state));
+
+ /* if the driver implemented the sampling hooks then
+ * setup our sampling state */
+ if (llvm->draw->num_sampler_views && llvm->draw->num_samplers) {
+ 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
+draw_llvm_destroy_variant(struct draw_llvm_variant *variant)
+{
+ struct draw_llvm *llvm = variant->llvm;
+ struct draw_context *draw = llvm->draw;
+
+ if (variant->function_elts) {
+ if (variant->function_elts)
+ LLVMFreeMachineCodeForFunction(draw->engine,
+ variant->function_elts);
+ LLVMDeleteFunction(variant->function_elts);
+ }
+
+ if (variant->function) {
+ if (variant->function)
+ LLVMFreeMachineCodeForFunction(draw->engine,
+ variant->function);
+ LLVMDeleteFunction(variant->function);
+ }
+
+ remove_from_list(&variant->list_item_local);
+ variant->shader->variants_cached--;
+ remove_from_list(&variant->list_item_global);
+ llvm->nr_variants--;
+ FREE(variant);
}