llvmpipe: Code generate alpha testing and append to generated fragment shader.

This commit is contained in:
José Fonseca 2009-08-19 20:42:50 +01:00
parent b5e397c369
commit 9ae47069b4
9 changed files with 278 additions and 146 deletions

View file

@ -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 \

View file

@ -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',

View file

@ -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 <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;
}

View file

@ -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 <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 */

View file

@ -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 &&

View file

@ -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])

View file

@ -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 );

View file

@ -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 |

View file

@ -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);
LLVMAddAttribute(LLVMGetParam(variant->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);
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;
}