summaryrefslogtreecommitdiffstats
path: root/src/gallium/drivers/llvmpipe
diff options
context:
space:
mode:
authorJosé Fonseca <[email protected]>2009-08-19 20:42:50 +0100
committerJosé Fonseca <[email protected]>2009-08-29 09:21:37 +0100
commit9ae47069b4a2b67e381b02d805f1ca74f31ea7b8 (patch)
tree69928d0be32cc2efe339791ed815920365ccfd9d /src/gallium/drivers/llvmpipe
parentb5e397c3693fbae6b2c91c602454d9a70651c9c4 (diff)
llvmpipe: Code generate alpha testing and append to generated fragment shader.
Diffstat (limited to 'src/gallium/drivers/llvmpipe')
-rw-r--r--src/gallium/drivers/llvmpipe/Makefile1
-rw-r--r--src/gallium/drivers/llvmpipe/SConscript1
-rw-r--r--src/gallium/drivers/llvmpipe/lp_bld_alpha.c68
-rw-r--r--src/gallium/drivers/llvmpipe/lp_bld_alpha.h52
-rw-r--r--src/gallium/drivers/llvmpipe/lp_quad_depth_test.c81
-rw-r--r--src/gallium/drivers/llvmpipe/lp_quad_fs.c25
-rw-r--r--src/gallium/drivers/llvmpipe/lp_state.h27
-rw-r--r--src/gallium/drivers/llvmpipe/lp_state_derived.c5
-rw-r--r--src/gallium/drivers/llvmpipe/lp_state_fs.c166
9 files changed, 279 insertions, 147 deletions
diff --git a/src/gallium/drivers/llvmpipe/Makefile b/src/gallium/drivers/llvmpipe/Makefile
index 170eefd51a4..96e03804979 100644
--- a/src/gallium/drivers/llvmpipe/Makefile
+++ b/src/gallium/drivers/llvmpipe/Makefile
@@ -4,6 +4,7 @@ include $(TOP)/configs/current
LIBNAME = llvmpipe
C_SOURCES = \
+ lp_bld_alpha.c \
lp_bld_arit.c \
lp_bld_blend_aos.c \
lp_bld_blend_soa.c \
diff --git a/src/gallium/drivers/llvmpipe/SConscript b/src/gallium/drivers/llvmpipe/SConscript
index 97af1b95c34..68989792aaa 100644
--- a/src/gallium/drivers/llvmpipe/SConscript
+++ b/src/gallium/drivers/llvmpipe/SConscript
@@ -8,6 +8,7 @@ env.ParseConfig('llvm-config --cppflags')
llvmpipe = env.ConvenienceLibrary(
target = 'llvmpipe',
source = [
+ 'lp_bld_alpha.c',
'lp_bld_arit.c',
'lp_bld_blend_aos.c',
'lp_bld_blend_soa.c',
diff --git a/src/gallium/drivers/llvmpipe/lp_bld_alpha.c b/src/gallium/drivers/llvmpipe/lp_bld_alpha.c
new file mode 100644
index 00000000000..a3faa22b997
--- /dev/null
+++ b/src/gallium/drivers/llvmpipe/lp_bld_alpha.c
@@ -0,0 +1,68 @@
+/**************************************************************************
+ *
+ * Copyright 2009 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.
+ *
+ **************************************************************************/
+
+/**
+ * Alpha testing to LLVM IR translation.
+ *
+ * @author Jose Fonseca <[email protected]>
+ */
+
+#include "pipe/p_state.h"
+
+#include "lp_bld_type.h"
+#include "lp_bld_const.h"
+#include "lp_bld_arit.h"
+#include "lp_bld_logic.h"
+#include "lp_bld_debug.h"
+#include "lp_bld_alpha.h"
+
+
+LLVMValueRef
+lp_build_alpha_test(LLVMBuilderRef builder,
+ const struct pipe_alpha_state *state,
+ union lp_type type,
+ LLVMValueRef alpha,
+ LLVMValueRef mask)
+{
+ struct lp_build_context bld;
+
+ lp_build_context_init(&bld, builder, type);
+
+ if(state->enabled) {
+ LLVMValueRef ref = lp_build_const_uni(type, state->ref_value);
+ LLVMValueRef test = lp_build_cmp(&bld, state->func, alpha, ref);
+
+ lp_build_name(test, "alpha_mask");
+
+ if(mask)
+ mask = LLVMBuildAnd(builder, mask, test, "");
+ else
+ mask = test;
+ }
+
+ return mask;
+}
diff --git a/src/gallium/drivers/llvmpipe/lp_bld_alpha.h b/src/gallium/drivers/llvmpipe/lp_bld_alpha.h
new file mode 100644
index 00000000000..f3fa8b60534
--- /dev/null
+++ b/src/gallium/drivers/llvmpipe/lp_bld_alpha.h
@@ -0,0 +1,52 @@
+/**************************************************************************
+ *
+ * Copyright 2009 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.
+ *
+ **************************************************************************/
+
+/**
+ * Alpha testing to LLVM IR translation.
+ *
+ * @author Jose Fonseca <[email protected]>
+ */
+
+#ifndef LP_BLD_ALPHA_H
+#define LP_BLD_ALPHA_H
+
+
+#include <llvm-c/Core.h>
+
+struct pipe_alpha_state;
+union lp_type;
+
+
+LLVMValueRef
+lp_build_alpha_test(LLVMBuilderRef builder,
+ const struct pipe_alpha_state *state,
+ union lp_type type,
+ LLVMValueRef alpha,
+ LLVMValueRef mask);
+
+
+#endif /* !LP_BLD_ALPHA_H */
diff --git a/src/gallium/drivers/llvmpipe/lp_quad_depth_test.c b/src/gallium/drivers/llvmpipe/lp_quad_depth_test.c
index fefb99c1ffa..124301688f7 100644
--- a/src/gallium/drivers/llvmpipe/lp_quad_depth_test.c
+++ b/src/gallium/drivers/llvmpipe/lp_quad_depth_test.c
@@ -564,75 +564,6 @@ depth_stencil_test_quad(struct quad_stage *qs,
}
-#define ALPHATEST( FUNC, COMP ) \
- static int \
- alpha_test_quads_##FUNC( struct quad_stage *qs, \
- struct quad_header *quads[], \
- unsigned nr ) \
- { \
- const float ref = qs->llvmpipe->depth_stencil->alpha.ref_value; \
- const uint cbuf = 0; /* only output[0].alpha is tested */ \
- unsigned pass_nr = 0; \
- unsigned i; \
- \
- for (i = 0; i < nr; i++) { \
- const float *aaaa = quads[i]->output.color[cbuf][3]; \
- unsigned passMask = 0; \
- \
- if (!quads[i]->inout.mask) \
- continue; \
- \
- if (aaaa[0] COMP ref) passMask |= (1 << 0); \
- if (aaaa[1] COMP ref) passMask |= (1 << 1); \
- if (aaaa[2] COMP ref) passMask |= (1 << 2); \
- if (aaaa[3] COMP ref) passMask |= (1 << 3); \
- \
- quads[i]->inout.mask &= passMask; \
- \
- if (quads[i]->inout.mask) \
- ++pass_nr; \
- } \
- \
- return pass_nr; \
- }
-
-
-ALPHATEST( LESS, < )
-ALPHATEST( EQUAL, == )
-ALPHATEST( LEQUAL, <= )
-ALPHATEST( GREATER, > )
-ALPHATEST( NOTEQUAL, != )
-ALPHATEST( GEQUAL, >= )
-
-
-/* XXX: Incorporate into shader using KILP.
- */
-static int
-alpha_test_quads(struct quad_stage *qs,
- struct quad_header *quads[],
- unsigned nr)
-{
- switch (qs->llvmpipe->depth_stencil->alpha.func) {
- case PIPE_FUNC_LESS:
- return alpha_test_quads_LESS( qs, quads, nr );
- case PIPE_FUNC_EQUAL:
- return alpha_test_quads_EQUAL( qs, quads, nr );
- break;
- case PIPE_FUNC_LEQUAL:
- return alpha_test_quads_LEQUAL( qs, quads, nr );
- case PIPE_FUNC_GREATER:
- return alpha_test_quads_GREATER( qs, quads, nr );
- case PIPE_FUNC_NOTEQUAL:
- return alpha_test_quads_NOTEQUAL( qs, quads, nr );
- case PIPE_FUNC_GEQUAL:
- return alpha_test_quads_GEQUAL( qs, quads, nr );
- case PIPE_FUNC_ALWAYS:
- return nr;
- case PIPE_FUNC_NEVER:
- default:
- return 0;
- }
-}
static unsigned mask_count[0x8] =
{
@@ -659,10 +590,6 @@ depth_test_quads_fallback(struct quad_stage *qs,
struct depth_data data;
- if (qs->llvmpipe->depth_stencil->alpha.enabled) {
- alpha_test_quads(qs, quads, nr);
- }
-
if (qs->llvmpipe->framebuffer.zsbuf &&
(qs->llvmpipe->depth_stencil->depth.enabled ||
qs->llvmpipe->depth_stencil->stencil[0].enabled)) {
@@ -801,8 +728,6 @@ choose_depth_test(struct quad_stage *qs,
{
boolean interp_depth = !qs->llvmpipe->fs->info.writes_z;
- boolean alpha = qs->llvmpipe->depth_stencil->alpha.enabled;
-
boolean depth = (qs->llvmpipe->framebuffer.zsbuf &&
qs->llvmpipe->depth_stencil->depth.enabled);
@@ -815,13 +740,11 @@ choose_depth_test(struct quad_stage *qs,
qs->run = depth_test_quads_fallback;
- if (!alpha &&
- !depth &&
+ if (!depth &&
!stencil) {
qs->run = depth_noop;
}
- else if (!alpha &&
- interp_depth &&
+ else if (interp_depth &&
depth &&
depthfunc == PIPE_FUNC_LESS &&
depthwrite &&
diff --git a/src/gallium/drivers/llvmpipe/lp_quad_fs.c b/src/gallium/drivers/llvmpipe/lp_quad_fs.c
index 78b4e1bab6d..2736efc956a 100644
--- a/src/gallium/drivers/llvmpipe/lp_quad_fs.c
+++ b/src/gallium/drivers/llvmpipe/lp_quad_fs.c
@@ -76,10 +76,15 @@ shade_quad(struct quad_stage *qs, struct quad_header *quad)
{
struct quad_shade_stage *qss = quad_shade_stage( qs );
struct llvmpipe_context *llvmpipe = qs->llvmpipe;
+ struct lp_fragment_shader *fs = llvmpipe->fs;
void *constants;
struct tgsi_sampler **samplers;
unsigned chan_index;
+ assert(fs->current);
+ if(!fs->current)
+ return FALSE;
+
constants = llvmpipe->mapped_constants[PIPE_SHADER_FRAGMENT];
samplers = (struct tgsi_sampler **)llvmpipe->tgsi.frag_samplers_list;
@@ -87,16 +92,16 @@ shade_quad(struct quad_stage *qs, struct quad_header *quad)
qss->mask[chan_index] = ~0;
/* run shader */
- llvmpipe->fs->jit_function( quad->input.x0,
- quad->input.y0,
- quad->coef->a0,
- quad->coef->dadx,
- quad->coef->dady,
- constants,
- qss->mask,
- quad->output.color,
- quad->output.depth,
- samplers);
+ fs->current->jit_function( quad->input.x0,
+ quad->input.y0,
+ quad->coef->a0,
+ quad->coef->dadx,
+ quad->coef->dady,
+ constants,
+ qss->mask,
+ quad->output.color,
+ quad->output.depth,
+ samplers);
for (chan_index = 0; chan_index < NUM_CHANNELS; ++chan_index)
if(!qss->mask[chan_index])
diff --git a/src/gallium/drivers/llvmpipe/lp_state.h b/src/gallium/drivers/llvmpipe/lp_state.h
index f8b3793a595..db21096f215 100644
--- a/src/gallium/drivers/llvmpipe/lp_state.h
+++ b/src/gallium/drivers/llvmpipe/lp_state.h
@@ -70,6 +70,28 @@ typedef void
void *depth,
struct tgsi_sampler **samplers);
+
+struct lp_fragment_shader;
+
+
+/**
+ * Subclass of pipe_shader_state (though it doesn't really need to be).
+ *
+ * This is starting to look an awful lot like a quad pipeline stage...
+ */
+struct lp_fragment_shader_variant
+{
+ struct lp_fragment_shader *shader;
+ struct pipe_alpha_state alpha;
+
+ LLVMValueRef function;
+
+ lp_shader_fs_func jit_function;
+
+ struct lp_fragment_shader_variant *next;
+};
+
+
/**
* Subclass of pipe_shader_state (though it doesn't really need to be).
*
@@ -83,9 +105,9 @@ struct lp_fragment_shader
struct llvmpipe_screen *screen;
- LLVMValueRef function;
+ struct lp_fragment_shader_variant *variants;
- lp_shader_fs_func jit_function;
+ struct lp_fragment_shader_variant *current;
};
@@ -183,6 +205,7 @@ void llvmpipe_set_vertex_buffers(struct pipe_context *,
unsigned count,
const struct pipe_vertex_buffer *);
+void llvmpipe_update_fs(struct llvmpipe_context *lp);
void llvmpipe_update_derived( struct llvmpipe_context *llvmpipe );
diff --git a/src/gallium/drivers/llvmpipe/lp_state_derived.c b/src/gallium/drivers/llvmpipe/lp_state_derived.c
index 79861b2d133..b42e6b15021 100644
--- a/src/gallium/drivers/llvmpipe/lp_state_derived.c
+++ b/src/gallium/drivers/llvmpipe/lp_state_derived.c
@@ -244,6 +244,11 @@ void llvmpipe_update_derived( struct llvmpipe_context *llvmpipe )
LP_NEW_FRAMEBUFFER))
compute_cliprect(llvmpipe);
+ if (llvmpipe->dirty & (LP_NEW_FS |
+ LP_NEW_DEPTH_STENCIL_ALPHA))
+ llvmpipe_update_fs( llvmpipe );
+
+
if (llvmpipe->dirty & (LP_NEW_BLEND |
LP_NEW_DEPTH_STENCIL_ALPHA |
LP_NEW_FRAMEBUFFER |
diff --git a/src/gallium/drivers/llvmpipe/lp_state_fs.c b/src/gallium/drivers/llvmpipe/lp_state_fs.c
index ffcc8336b12..702be429164 100644
--- a/src/gallium/drivers/llvmpipe/lp_state_fs.c
+++ b/src/gallium/drivers/llvmpipe/lp_state_fs.c
@@ -28,6 +28,7 @@
#include "pipe/p_defines.h"
#include "util/u_memory.h"
+#include "util/u_debug_dump.h"
#include "pipe/internal/p_winsys_screen.h"
#include "pipe/p_shader_tokens.h"
#include "draw/draw_context.h"
@@ -36,6 +37,7 @@
#include "tgsi/tgsi_parse.h"
#include "lp_bld_type.h"
#include "lp_bld_tgsi.h"
+#include "lp_bld_alpha.h"
#include "lp_bld_swizzle.h"
#include "lp_bld_debug.h"
#include "lp_screen.h"
@@ -103,10 +105,12 @@ setup_pos_vector(LLVMBuilderRef builder,
}
-static void
+static struct lp_fragment_shader_variant *
shader_generate(struct llvmpipe_screen *screen,
- struct lp_fragment_shader *shader)
+ struct lp_fragment_shader *shader,
+ const struct pipe_alpha_state *alpha)
{
+ struct lp_fragment_shader_variant *variant;
const struct tgsi_token *tokens = shader->base.tokens;
union lp_type type;
LLVMTypeRef elem_type;
@@ -129,10 +133,25 @@ shader_generate(struct llvmpipe_screen *screen,
LLVMValueRef pos[NUM_CHANNELS];
LLVMValueRef outputs[PIPE_MAX_SHADER_OUTPUTS][NUM_CHANNELS];
LLVMValueRef mask;
+ LLVMValueRef fetch_texel;
unsigned i;
unsigned attrib;
unsigned chan;
+#ifdef DEBUG
+ tgsi_dump(shader->base.tokens, 0);
+ debug_printf("alpha.enabled = %u\n", alpha->enabled);
+ debug_printf("alpha.func = %s\n", debug_dump_func(alpha->func, TRUE));
+ debug_printf("alpha.ref_value = %f\n", alpha->ref_value);
+#endif
+
+ variant = CALLOC_STRUCT(lp_fragment_shader_variant);
+ if(!variant)
+ return NULL;
+
+ variant->shader = shader;
+ memcpy(&variant->alpha, alpha, sizeof *alpha);
+
type.value = 0;
type.floating = TRUE; /* floating point values */
type.sign = TRUE; /* values are signed */
@@ -157,22 +176,22 @@ shader_generate(struct llvmpipe_screen *screen,
func_type = LLVMFunctionType(LLVMVoidType(), arg_types, Elements(arg_types), 0);
- shader->function = LLVMAddFunction(screen->module, "shader", func_type);
- LLVMSetFunctionCallConv(shader->function, LLVMCCallConv);
+ variant->function = LLVMAddFunction(screen->module, "shader", func_type);
+ LLVMSetFunctionCallConv(variant->function, LLVMCCallConv);
for(i = 0; i < Elements(arg_types); ++i)
if(LLVMGetTypeKind(arg_types[i]) == LLVMPointerTypeKind)
- LLVMAddAttribute(LLVMGetParam(shader->function, i), LLVMNoAliasAttribute);
-
- x = LLVMGetParam(shader->function, 0);
- y = LLVMGetParam(shader->function, 1);
- a0_ptr = LLVMGetParam(shader->function, 2);
- dadx_ptr = LLVMGetParam(shader->function, 3);
- dady_ptr = LLVMGetParam(shader->function, 4);
- consts_ptr = LLVMGetParam(shader->function, 5);
- mask_ptr = LLVMGetParam(shader->function, 6);
- color_ptr = LLVMGetParam(shader->function, 7);
- depth_ptr = LLVMGetParam(shader->function, 8);
- samplers_ptr = LLVMGetParam(shader->function, 9);
+ LLVMAddAttribute(LLVMGetParam(variant->function, i), LLVMNoAliasAttribute);
+
+ x = LLVMGetParam(variant->function, 0);
+ y = LLVMGetParam(variant->function, 1);
+ a0_ptr = LLVMGetParam(variant->function, 2);
+ dadx_ptr = LLVMGetParam(variant->function, 3);
+ dady_ptr = LLVMGetParam(variant->function, 4);
+ consts_ptr = LLVMGetParam(variant->function, 5);
+ mask_ptr = LLVMGetParam(variant->function, 6);
+ color_ptr = LLVMGetParam(variant->function, 7);
+ depth_ptr = LLVMGetParam(variant->function, 8);
+ samplers_ptr = LLVMGetParam(variant->function, 9);
lp_build_name(x, "x");
lp_build_name(y, "y");
@@ -185,7 +204,7 @@ shader_generate(struct llvmpipe_screen *screen,
lp_build_name(depth_ptr, "depth");
lp_build_name(samplers_ptr, "samplers");
- block = LLVMAppendBasicBlock(shader->function, "entry");
+ block = LLVMAppendBasicBlock(variant->function, "entry");
builder = LLVMCreateBuilder();
LLVMPositionBuilderAtEnd(builder, block);
@@ -210,6 +229,12 @@ shader_generate(struct llvmpipe_screen *screen,
LLVMValueRef output_ptr = LLVMBuildGEP(builder, color_ptr, &index, 1, "");
lp_build_name(outputs[attrib][chan], "color%u.%c", attrib, "rgba"[chan]);
LLVMBuildStore(builder, outputs[attrib][chan], output_ptr);
+
+ /* Alpha test */
+ /* XXX: should the alpha reference value be passed separately? */
+ if(cbuf == 0 && chan == 3)
+ mask = lp_build_alpha_test(builder, alpha, type, outputs[attrib][chan], mask);
+
break;
}
@@ -228,44 +253,16 @@ shader_generate(struct llvmpipe_screen *screen,
LLVMBuildRetVoid(builder);;
LLVMDisposeBuilder(builder);
-}
-
-void *
-llvmpipe_create_fs_state(struct pipe_context *pipe,
- const struct pipe_shader_state *templ)
-{
- struct llvmpipe_screen *screen = llvmpipe_screen(pipe->screen);
- struct lp_fragment_shader *shader;
- LLVMValueRef fetch_texel;
-
- shader = CALLOC_STRUCT(lp_fragment_shader);
- if (!shader)
- return NULL;
-
- /* get/save the summary info for this shader */
- tgsi_scan_shader(templ->tokens, &shader->info);
-
- /* we need to keep a local copy of the tokens */
- shader->base.tokens = tgsi_dup_tokens(templ->tokens);
-
- shader->screen = screen;
+ LLVMRunFunctionPassManager(screen->pass, variant->function);
#ifdef DEBUG
- tgsi_dump(templ->tokens, 0);
-#endif
-
- shader_generate(screen, shader);
-
- LLVMRunFunctionPassManager(screen->pass, shader->function);
-
-#ifdef DEBUG
- LLVMDumpValue(shader->function);
+ LLVMDumpValue(variant->function);
debug_printf("\n");
#endif
- if(LLVMVerifyFunction(shader->function, LLVMPrintMessageAction)) {
- LLVMDumpValue(shader->function);
+ if(LLVMVerifyFunction(variant->function, LLVMPrintMessageAction)) {
+ LLVMDumpValue(variant->function);
abort();
}
@@ -278,12 +275,38 @@ llvmpipe_create_fs_state(struct pipe_context *pipe,
}
}
- shader->jit_function = (lp_shader_fs_func)LLVMGetPointerToGlobal(screen->engine, shader->function);
+ variant->jit_function = (lp_shader_fs_func)LLVMGetPointerToGlobal(screen->engine, variant->function);
#ifdef DEBUG
- lp_disassemble(shader->jit_function);
+ lp_disassemble(variant->jit_function);
#endif
+ variant->next = shader->variants;
+ shader->variants = variant;
+
+ return variant;
+}
+
+
+void *
+llvmpipe_create_fs_state(struct pipe_context *pipe,
+ const struct pipe_shader_state *templ)
+{
+ struct llvmpipe_screen *screen = llvmpipe_screen(pipe->screen);
+ struct lp_fragment_shader *shader;
+
+ shader = CALLOC_STRUCT(lp_fragment_shader);
+ if (!shader)
+ return NULL;
+
+ /* get/save the summary info for this shader */
+ tgsi_scan_shader(templ->tokens, &shader->info);
+
+ /* we need to keep a local copy of the tokens */
+ shader->base.tokens = tgsi_dup_tokens(templ->tokens);
+
+ shader->screen = screen;
+
return shader;
}
@@ -303,14 +326,24 @@ void
llvmpipe_delete_fs_state(struct pipe_context *pipe, void *fs)
{
struct lp_fragment_shader *shader = fs;
+ struct lp_fragment_shader_variant *variant;
struct llvmpipe_screen *screen = shader->screen;
assert(fs != llvmpipe_context(pipe)->fs);
-
- if(shader->function) {
- if(shader->jit_function)
- LLVMFreeMachineCodeForFunction(screen->engine, shader->function);
- LLVMDeleteFunction(shader->function);
+
+ variant = shader->variants;
+ while(variant) {
+ struct lp_fragment_shader_variant *next = variant->next;
+
+ if(variant->function) {
+ if(variant->jit_function)
+ LLVMFreeMachineCodeForFunction(screen->engine, variant->function);
+ LLVMDeleteFunction(variant->function);
+ }
+
+ FREE(variant);
+
+ variant = next;
}
FREE((void *) shader->base.tokens);
@@ -395,3 +428,24 @@ llvmpipe_set_constant_buffer(struct pipe_context *pipe,
llvmpipe->dirty |= LP_NEW_CONSTANTS;
}
+
+
+void llvmpipe_update_fs(struct llvmpipe_context *lp)
+{
+ struct lp_fragment_shader *shader = lp->fs;
+ const struct pipe_alpha_state *alpha = &lp->depth_stencil->alpha;
+ struct lp_fragment_shader_variant *variant;
+
+ variant = shader->variants;
+ while(variant) {
+ if(memcmp(&variant->alpha, alpha, sizeof *alpha) == 0)
+ break;
+
+ variant = variant->next;
+ }
+
+ if(!variant)
+ variant = shader_generate(shader->screen, shader, alpha);
+
+ shader->current = variant;
+}