--- /dev/null
+/**************************************************************************
+ *
+ * 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 <jfonseca@vmware.com>
+ */
+
+#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;
+}
--- /dev/null
+/**************************************************************************
+ *
+ * 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 <jfonseca@vmware.com>
+ */
+
+#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 */
}
-#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] =
{
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)) {
{
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);
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 &&
#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"
#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"
}
-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;
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 */
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");
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);
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;
}
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();
}
}
}
- 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;
}
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);
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;
+}