llvmpipe: Eliminate non-LLVM fs execution paths.

This commit is contained in:
José Fonseca 2009-08-14 10:27:32 +01:00
parent 95f38dd67c
commit 73af91e938
11 changed files with 285 additions and 802 deletions

View file

@ -4,9 +4,6 @@ include $(TOP)/configs/current
LIBNAME = llvmpipe
C_SOURCES = \
lp_fs_exec.c \
lp_fs_sse.c \
lp_fs_llvm.c \
lp_bld_arit.c \
lp_bld_pack.c \
lp_bld_unpack.c \

View file

@ -7,9 +7,6 @@ env.ParseConfig('llvm-config --cppflags')
llvmpipe = env.ConvenienceLibrary(
target = 'llvmpipe',
source = [
'lp_fs_exec.c',
'lp_fs_sse.c',
'lp_fs_llvm.c',
'lp_bld_arit.c',
'lp_bld_blend_aos.c',
'lp_bld_blend_soa.c',

View file

@ -148,14 +148,6 @@ llvmpipe_create( struct pipe_screen *screen )
util_init_math();
#ifdef PIPE_ARCH_X86
llvmpipe->use_sse = !debug_get_bool_option( "GALLIUM_NOSSE", FALSE );
#else
llvmpipe->use_sse = FALSE;
#endif
llvmpipe->dump_fs = debug_get_bool_option( "GALLIUM_DUMP_FS", FALSE );
llvmpipe->pipe.winsys = screen->winsys;
llvmpipe->pipe.screen = screen;
llvmpipe->pipe.destroy = llvmpipe_destroy;

View file

@ -57,7 +57,7 @@ struct llvmpipe_context {
const struct pipe_sampler_state *sampler[PIPE_MAX_SAMPLERS];
const struct pipe_depth_stencil_alpha_state *depth_stencil;
const struct pipe_rasterizer_state *rasterizer;
const struct lp_fragment_shader *fs;
struct lp_fragment_shader *fs;
const struct lp_vertex_shader *vs;
/** Other rendering state */
@ -145,8 +145,6 @@ struct llvmpipe_context {
unsigned tex_timestamp;
struct llvmpipe_tex_tile_cache *tex_cache[PIPE_MAX_SAMPLERS];
unsigned use_sse : 1;
unsigned dump_fs : 1;
unsigned no_rast : 1;
};

View file

@ -1,54 +0,0 @@
/**************************************************************************
*
* Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas.
* 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 TUNGSTEN GRAPHICS 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.
*
**************************************************************************/
/* Authors: Keith Whitwell <keith@tungstengraphics.com>
*/
#ifndef LP_FS_H
#define LP_FS_H
struct lp_fragment_shader *
llvmpipe_create_fs_exec(struct llvmpipe_context *llvmpipe,
const struct pipe_shader_state *templ);
struct lp_fragment_shader *
llvmpipe_create_fs_sse(struct llvmpipe_context *llvmpipe,
const struct pipe_shader_state *templ);
struct lp_fragment_shader *
llvmpipe_create_fs_llvm(struct llvmpipe_context *llvmpipe,
const struct pipe_shader_state *templ);
struct tgsi_interp_coef;
struct tgsi_exec_vector;
void lp_setup_pos_vector(const struct tgsi_interp_coef *coef,
float x, float y,
struct tgsi_exec_vector *quadpos);
#endif

View file

@ -1,162 +0,0 @@
/**************************************************************************
*
* Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas.
* 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 TUNGSTEN GRAPHICS 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.
*
**************************************************************************/
/**
* Execute fragment shader using the TGSI interpreter.
*/
#include "lp_context.h"
#include "lp_state.h"
#include "lp_fs.h"
#include "lp_quad.h"
#include "pipe/p_state.h"
#include "pipe/p_defines.h"
#include "util/u_memory.h"
#include "tgsi/tgsi_exec.h"
#include "tgsi/tgsi_parse.h"
/**
* Subclass of lp_fragment_shader
*/
struct lp_exec_fragment_shader
{
struct lp_fragment_shader base;
/* No other members for now */
};
/** cast wrapper */
static INLINE struct lp_exec_fragment_shader *
lp_exec_fragment_shader(const struct lp_fragment_shader *base)
{
return (struct lp_exec_fragment_shader *) base;
}
/**
* Compute quad X,Y,Z,W for the four fragments in a quad.
*
* This should really be part of the compiled shader.
*/
void
lp_setup_pos_vector(const struct tgsi_interp_coef *coef,
float x, float y,
struct tgsi_exec_vector *quadpos)
{
uint chan;
/* do X */
quadpos->xyzw[0].f[0] = x;
quadpos->xyzw[0].f[1] = x + 1;
quadpos->xyzw[0].f[2] = x;
quadpos->xyzw[0].f[3] = x + 1;
/* do Y */
quadpos->xyzw[1].f[0] = y;
quadpos->xyzw[1].f[1] = y;
quadpos->xyzw[1].f[2] = y + 1;
quadpos->xyzw[1].f[3] = y + 1;
/* do Z and W for all fragments in the quad */
for (chan = 2; chan < 4; chan++) {
const float dadx = coef->dadx[chan];
const float dady = coef->dady[chan];
const float a0 = coef->a0[chan] + dadx * x + dady * y;
quadpos->xyzw[chan].f[0] = a0;
quadpos->xyzw[chan].f[1] = a0 + dadx;
quadpos->xyzw[chan].f[2] = a0 + dady;
quadpos->xyzw[chan].f[3] = a0 + dadx + dady;
}
}
static void
exec_prepare( const struct lp_fragment_shader *base,
struct tgsi_exec_machine *machine,
struct tgsi_sampler **samplers )
{
/*
* Bind tokens/shader to the interpreter's machine state.
* Avoid redundant binding.
*/
if (machine->Tokens != base->shader.tokens) {
tgsi_exec_machine_bind_shader( machine,
base->shader.tokens,
PIPE_MAX_SAMPLERS,
samplers );
}
}
/* TODO: hide the machine struct in here somewhere, remove from this
* interface:
*/
static unsigned
exec_run( const struct lp_fragment_shader *base,
struct tgsi_exec_machine *machine,
struct quad_header *quad )
{
/* Compute X, Y, Z, W vals for this quad */
lp_setup_pos_vector(quad->posCoef,
(float)quad->input.x0, (float)quad->input.y0,
&machine->QuadPos);
return tgsi_exec_machine_run( machine );
}
static void
exec_delete( struct lp_fragment_shader *base )
{
FREE((void *) base->shader.tokens);
FREE(base);
}
struct lp_fragment_shader *
llvmpipe_create_fs_exec(struct llvmpipe_context *llvmpipe,
const struct pipe_shader_state *templ)
{
struct lp_exec_fragment_shader *shader;
/* Decide whether we'll be codegenerating this shader and if so do
* that now.
*/
shader = CALLOC_STRUCT(lp_exec_fragment_shader);
if (!shader)
return NULL;
/* we need to keep a local copy of the tokens */
shader->base.shader.tokens = tgsi_dup_tokens(templ->tokens);
shader->base.prepare = exec_prepare;
shader->base.run = exec_run;
shader->base.delete = exec_delete;
return &shader->base;
}

View file

@ -1,360 +0,0 @@
/**************************************************************************
*
* Copyright 2009 VMware, Inc.
* Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas.
* 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 TUNGSTEN GRAPHICS 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.
*
**************************************************************************/
/**
* Execute fragment shader using LLVM code generation.
*/
#include "pipe/p_state.h"
#include "pipe/p_defines.h"
#include "util/u_memory.h"
#include "tgsi/tgsi_parse.h"
#include "tgsi/tgsi_exec.h"
#include "tgsi/tgsi_dump.h"
#include "lp_bld_type.h"
#include "lp_bld_tgsi.h"
#include "lp_screen.h"
#include "lp_context.h"
#include "lp_state.h"
#include "lp_fs.h"
#include "lp_quad.h"
typedef void
(*lp_shader_fs_func)(void *pos,
void *a0,
void *dadx,
void *dady,
void *consts,
void *outputs,
struct tgsi_sampler **samplers);
/**
* Subclass of lp_fragment_shader
*/
struct lp_llvm_fragment_shader
{
struct lp_fragment_shader base;
struct llvmpipe_screen *screen;
LLVMValueRef function;
lp_shader_fs_func jit_function;
union tgsi_exec_channel ALIGN16_ATTRIB pos[NUM_CHANNELS];
union tgsi_exec_channel ALIGN16_ATTRIB a0[PIPE_MAX_SHADER_INPUTS][NUM_CHANNELS];
union tgsi_exec_channel ALIGN16_ATTRIB dadx[PIPE_MAX_SHADER_INPUTS][NUM_CHANNELS];
union tgsi_exec_channel ALIGN16_ATTRIB dady[PIPE_MAX_SHADER_INPUTS][NUM_CHANNELS];
uint32_t magic;
};
/** cast wrapper */
static INLINE struct lp_llvm_fragment_shader *
lp_llvm_fragment_shader(const struct lp_fragment_shader *base)
{
return (struct lp_llvm_fragment_shader *) base;
}
static void
shader_generate(struct llvmpipe_screen *screen,
struct lp_llvm_fragment_shader *shader)
{
const struct tgsi_token *tokens = shader->base.shader.tokens;
union lp_type type;
LLVMTypeRef elem_type;
LLVMTypeRef vec_type;
LLVMTypeRef arg_types[7];
LLVMTypeRef func_type;
LLVMValueRef pos_ptr;
LLVMValueRef a0_ptr;
LLVMValueRef dadx_ptr;
LLVMValueRef dady_ptr;
LLVMValueRef consts_ptr;
LLVMValueRef outputs_ptr;
LLVMValueRef samplers_ptr;
LLVMBasicBlockRef block;
LLVMBuilderRef builder;
LLVMValueRef pos[NUM_CHANNELS];
LLVMValueRef outputs[PIPE_MAX_SHADER_OUTPUTS][NUM_CHANNELS];
char name[32];
unsigned i, j;
type.value = 0;
type.floating = TRUE;
type.sign = TRUE;
type.norm = FALSE;
type.width = 32;
type.length = 4;
elem_type = lp_build_elem_type(type);
vec_type = lp_build_vec_type(type);
arg_types[0] = LLVMPointerType(vec_type, 0); /* pos */
arg_types[1] = LLVMPointerType(vec_type, 0); /* a0 */
arg_types[2] = LLVMPointerType(vec_type, 0); /* dadx */
arg_types[3] = LLVMPointerType(vec_type, 0); /* dady */
arg_types[4] = LLVMPointerType(elem_type, 0); /* consts */
arg_types[5] = LLVMPointerType(vec_type, 0); /* outputs */
arg_types[6] = LLVMPointerType(LLVMInt8Type(), 0); /* samplers */
func_type = LLVMFunctionType(LLVMVoidType(), arg_types, Elements(arg_types), 0);
shader->function = LLVMAddFunction(screen->module, "shader", func_type);
LLVMSetFunctionCallConv(shader->function, LLVMCCallConv);
pos_ptr = LLVMGetParam(shader->function, 0);
a0_ptr = LLVMGetParam(shader->function, 1);
dadx_ptr = LLVMGetParam(shader->function, 2);
dady_ptr = LLVMGetParam(shader->function, 3);
consts_ptr = LLVMGetParam(shader->function, 4);
outputs_ptr = LLVMGetParam(shader->function, 5);
samplers_ptr = LLVMGetParam(shader->function, 6);
LLVMSetValueName(pos_ptr, "pos");
LLVMSetValueName(a0_ptr, "a0");
LLVMSetValueName(dadx_ptr, "dadx");
LLVMSetValueName(dady_ptr, "dady");
LLVMSetValueName(consts_ptr, "consts");
LLVMSetValueName(outputs_ptr, "outputs");
LLVMSetValueName(samplers_ptr, "samplers");
block = LLVMAppendBasicBlock(shader->function, "entry");
builder = LLVMCreateBuilder();
LLVMPositionBuilderAtEnd(builder, block);
for(j = 0; j < NUM_CHANNELS; ++j) {
LLVMValueRef index = LLVMConstInt(LLVMInt32Type(), j, 0);
util_snprintf(name, sizeof name, "pos.%c", "xyzw"[j]);
pos[j] = LLVMBuildLoad(builder, LLVMBuildGEP(builder, pos_ptr, &index, 1, ""), name);
}
memset(outputs, 0, sizeof outputs);
lp_build_tgsi_soa(builder, tokens, type,
pos, a0_ptr, dadx_ptr, dady_ptr,
consts_ptr, outputs, samplers_ptr);
for(i = 0; i < PIPE_MAX_SHADER_OUTPUTS; ++i) {
for(j = 0; j < NUM_CHANNELS; ++j) {
if(outputs[i][j]) {
LLVMValueRef index = LLVMConstInt(LLVMInt32Type(), i*NUM_CHANNELS + j, 0);
util_snprintf(name, sizeof name, "output%u.%c", i, "xyzw"[j]);
LLVMBuildStore(builder, outputs[i][j], LLVMBuildGEP(builder, outputs_ptr, &index, 1, name));
}
}
}
LLVMBuildRetVoid(builder);;
LLVMDisposeBuilder(builder);
}
static void
fs_llvm_prepare( const struct lp_fragment_shader *base,
struct tgsi_exec_machine *machine,
struct tgsi_sampler **samplers )
{
/*
* Bind tokens/shader to the interpreter's machine state.
* Avoid redundant binding.
*/
if (machine->Tokens != base->shader.tokens) {
tgsi_exec_machine_bind_shader( machine,
base->shader.tokens,
PIPE_MAX_SAMPLERS,
samplers );
}
}
static void
setup_pos_vector(struct lp_llvm_fragment_shader *shader,
const struct tgsi_interp_coef *coef,
float x, float y)
{
uint chan;
/* do X */
shader->pos[0].f[0] = x;
shader->pos[0].f[1] = x + 1;
shader->pos[0].f[2] = x;
shader->pos[0].f[3] = x + 1;
/* do Y */
shader->pos[1].f[0] = y;
shader->pos[1].f[1] = y;
shader->pos[1].f[2] = y + 1;
shader->pos[1].f[3] = y + 1;
/* do Z and W for all fragments in the quad */
for (chan = 2; chan < 4; chan++) {
const float dadx = coef->dadx[chan];
const float dady = coef->dady[chan];
const float a0 = coef->a0[chan] + dadx * x + dady * y;
shader->pos[chan].f[0] = a0;
shader->pos[chan].f[1] = a0 + dadx;
shader->pos[chan].f[2] = a0 + dady;
shader->pos[chan].f[3] = a0 + dadx + dady;
}
}
static void
setup_coef_vector(struct lp_llvm_fragment_shader *shader,
const struct tgsi_interp_coef *coef)
{
unsigned attrib, chan, i;
for (attrib = 0; attrib < PIPE_MAX_SHADER_INPUTS; ++attrib) {
for (chan = 0; chan < NUM_CHANNELS; ++chan) {
for( i = 0; i < QUAD_SIZE; ++i ) {
shader->a0[attrib][chan].f[i] = coef[attrib].a0[chan];
shader->dadx[attrib][chan].f[i] = coef[attrib].dadx[chan];
shader->dady[attrib][chan].f[i] = coef[attrib].dady[chan];
}
}
}
}
/* TODO: codegenerate the whole run function, skip this wrapper.
* TODO: break dependency on tgsi_exec_machine struct
* TODO: push Position calculation into the generated shader
* TODO: process >1 quad at a time
*/
static unsigned
fs_llvm_run( const struct lp_fragment_shader *base,
struct tgsi_exec_machine *machine,
struct quad_header *quad )
{
struct lp_llvm_fragment_shader *shader = lp_llvm_fragment_shader(base);
unsigned mask;
/* Compute X, Y, Z, W vals for this quad */
setup_pos_vector(shader,
quad->posCoef,
(float)quad->input.x0, (float)quad->input.y0);
setup_coef_vector(shader,
quad->coef);
/* init kill mask */
tgsi_set_kill_mask(machine, 0x0);
tgsi_set_exec_mask(machine, 1, 1, 1, 1);
memset(machine->Outputs, 0, sizeof machine->Outputs);
shader->jit_function( shader->pos,
shader->a0, shader->dadx, shader->dady,
machine->Consts,
machine->Outputs,
machine->Samplers);
/* FIXME */
mask = ~0;
return mask;
}
static void
fs_llvm_delete( struct lp_fragment_shader *base )
{
struct lp_llvm_fragment_shader *shader = lp_llvm_fragment_shader(base);
struct llvmpipe_screen *screen = shader->screen;
if(shader->function) {
if(shader->jit_function)
LLVMFreeMachineCodeForFunction(screen->engine, shader->function);
LLVMDeleteFunction(shader->function);
}
FREE((void *) shader->base.shader.tokens);
FREE(shader);
}
struct lp_fragment_shader *
llvmpipe_create_fs_llvm(struct llvmpipe_context *llvmpipe,
const struct pipe_shader_state *templ)
{
struct llvmpipe_screen *screen = llvmpipe_screen(llvmpipe->pipe.screen);
struct lp_llvm_fragment_shader *shader;
LLVMValueRef fetch_texel;
shader = CALLOC_STRUCT(lp_llvm_fragment_shader);
if (!shader)
return NULL;
/* we need to keep a local copy of the tokens */
shader->base.shader.tokens = tgsi_dup_tokens(templ->tokens);
shader->base.prepare = fs_llvm_prepare;
shader->base.run = fs_llvm_run;
shader->base.delete = fs_llvm_delete;
shader->screen = screen;
tgsi_dump(templ->tokens, 0);
shader_generate(screen, shader);
LLVMRunFunctionPassManager(screen->pass, shader->function);
#if 1
LLVMDumpValue(shader->function);
debug_printf("\n");
#endif
if(LLVMVerifyFunction(shader->function, LLVMPrintMessageAction)) {
LLVMDumpValue(shader->function);
abort();
}
fetch_texel = LLVMGetNamedFunction(screen->module, "fetch_texel");
if(fetch_texel) {
static boolean first_time = TRUE;
if(first_time) {
LLVMAddGlobalMapping(screen->engine, fetch_texel, lp_build_tgsi_fetch_texel_soa);
first_time = FALSE;
}
}
shader->jit_function = (lp_shader_fs_func)LLVMGetPointerToGlobal(screen->engine, shader->function);
return &shader->base;
}

View file

@ -1,169 +0,0 @@
/**************************************************************************
*
* Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas.
* 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 TUNGSTEN GRAPHICS 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.
*
**************************************************************************/
/**
* Execute fragment shader using runtime SSE code generation.
*/
#include "lp_context.h"
#include "lp_state.h"
#include "lp_fs.h"
#include "lp_quad.h"
#include "pipe/p_state.h"
#include "pipe/p_defines.h"
#include "util/u_memory.h"
#include "tgsi/tgsi_exec.h"
#include "tgsi/tgsi_sse2.h"
#if defined(PIPE_ARCH_X86)
#include "rtasm/rtasm_x86sse.h"
/**
* Subclass of lp_fragment_shader
*/
struct lp_sse_fragment_shader
{
struct lp_fragment_shader base;
struct x86_function sse2_program;
tgsi_sse2_fs_function func;
float immediates[TGSI_EXEC_NUM_IMMEDIATES][4];
};
/** cast wrapper */
static INLINE struct lp_sse_fragment_shader *
lp_sse_fragment_shader(const struct lp_fragment_shader *base)
{
return (struct lp_sse_fragment_shader *) base;
}
static void
fs_sse_prepare( const struct lp_fragment_shader *base,
struct tgsi_exec_machine *machine,
struct tgsi_sampler **samplers )
{
machine->Samplers = samplers;
}
/* TODO: codegenerate the whole run function, skip this wrapper.
* TODO: break dependency on tgsi_exec_machine struct
* TODO: push Position calculation into the generated shader
* TODO: process >1 quad at a time
*/
static unsigned
fs_sse_run( const struct lp_fragment_shader *base,
struct tgsi_exec_machine *machine,
struct quad_header *quad )
{
struct lp_sse_fragment_shader *shader = lp_sse_fragment_shader(base);
/* Compute X, Y, Z, W vals for this quad -- place in temp[0] for now */
lp_setup_pos_vector(quad->posCoef,
(float)quad->input.x0, (float)quad->input.y0,
machine->Temps);
/* init kill mask */
tgsi_set_kill_mask(machine, 0x0);
tgsi_set_exec_mask(machine, 1, 1, 1, 1);
shader->func( machine,
machine->Consts,
(const float (*)[4])shader->immediates,
machine->InterpCoefs
// , &machine->QuadPos
);
return ~(machine->Temps[TGSI_EXEC_TEMP_KILMASK_I].xyzw[TGSI_EXEC_TEMP_KILMASK_C].u[0]);
}
static void
fs_sse_delete( struct lp_fragment_shader *base )
{
struct lp_sse_fragment_shader *shader = lp_sse_fragment_shader(base);
x86_release_func( &shader->sse2_program );
FREE(shader);
}
struct lp_fragment_shader *
llvmpipe_create_fs_sse(struct llvmpipe_context *llvmpipe,
const struct pipe_shader_state *templ)
{
struct lp_sse_fragment_shader *shader;
if (!llvmpipe->use_sse)
return NULL;
shader = CALLOC_STRUCT(lp_sse_fragment_shader);
if (!shader)
return NULL;
x86_init_func( &shader->sse2_program );
if (!tgsi_emit_sse2( templ->tokens, &shader->sse2_program,
shader->immediates, FALSE )) {
FREE(shader);
return NULL;
}
shader->func = (tgsi_sse2_fs_function) x86_get_func( &shader->sse2_program );
if (!shader->func) {
x86_release_func( &shader->sse2_program );
FREE(shader);
return NULL;
}
shader->base.shader.tokens = NULL; /* don't hold reference to templ->tokens */
shader->base.prepare = fs_sse_prepare;
shader->base.run = fs_sse_run;
shader->base.delete = fs_sse_delete;
return &shader->base;
}
#else
/* Maybe put this variant in the header file.
*/
struct lp_fragment_shader *
llvmpipe_create_fs_sse(struct llvmpipe_context *llvmpipe,
const struct pipe_shader_state *templ)
{
return NULL;
}
#endif

View file

@ -1,8 +1,8 @@
/**************************************************************************
*
* Copyright 2008-2009 VMware, Inc.
* Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas.
* All Rights Reserved.
* Copyright 2008 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
@ -65,6 +65,114 @@ quad_shade_stage(struct quad_stage *qs)
}
static void
shader_prepare( const struct lp_fragment_shader *shader,
struct tgsi_exec_machine *machine,
struct tgsi_sampler **samplers )
{
/*
* Bind tokens/shader to the interpreter's machine state.
* Avoid redundant binding.
*/
if (machine->Tokens != shader->base.tokens) {
tgsi_exec_machine_bind_shader( machine,
shader->base.tokens,
PIPE_MAX_SAMPLERS,
samplers );
}
}
static void
setup_pos_vector(struct lp_fragment_shader *shader,
const struct tgsi_interp_coef *coef,
float x, float y)
{
uint chan;
/* do X */
shader->pos[0].f[0] = x;
shader->pos[0].f[1] = x + 1;
shader->pos[0].f[2] = x;
shader->pos[0].f[3] = x + 1;
/* do Y */
shader->pos[1].f[0] = y;
shader->pos[1].f[1] = y;
shader->pos[1].f[2] = y + 1;
shader->pos[1].f[3] = y + 1;
/* do Z and W for all fragments in the quad */
for (chan = 2; chan < 4; chan++) {
const float dadx = coef->dadx[chan];
const float dady = coef->dady[chan];
const float a0 = coef->a0[chan] + dadx * x + dady * y;
shader->pos[chan].f[0] = a0;
shader->pos[chan].f[1] = a0 + dadx;
shader->pos[chan].f[2] = a0 + dady;
shader->pos[chan].f[3] = a0 + dadx + dady;
}
}
static void
setup_coef_vector(struct lp_fragment_shader *shader,
const struct tgsi_interp_coef *coef)
{
unsigned attrib, chan, i;
for (attrib = 0; attrib < PIPE_MAX_SHADER_INPUTS; ++attrib) {
for (chan = 0; chan < NUM_CHANNELS; ++chan) {
for( i = 0; i < QUAD_SIZE; ++i ) {
shader->a0[attrib][chan].f[i] = coef[attrib].a0[chan];
shader->dadx[attrib][chan].f[i] = coef[attrib].dadx[chan];
shader->dady[attrib][chan].f[i] = coef[attrib].dady[chan];
}
}
}
}
/* TODO: codegenerate the whole run function, skip this wrapper.
* TODO: break dependency on tgsi_exec_machine struct
* TODO: push Position calculation into the generated shader
* TODO: process >1 quad at a time
*/
static unsigned
shader_run( struct lp_fragment_shader *shader,
struct tgsi_exec_machine *machine,
struct quad_header *quad )
{
unsigned mask;
/* Compute X, Y, Z, W vals for this quad */
setup_pos_vector(shader,
quad->posCoef,
(float)quad->input.x0, (float)quad->input.y0);
setup_coef_vector(shader,
quad->coef);
/* init kill mask */
tgsi_set_kill_mask(machine, 0x0);
tgsi_set_exec_mask(machine, 1, 1, 1, 1);
memset(machine->Outputs, 0, sizeof machine->Outputs);
shader->jit_function( shader->pos,
shader->a0, shader->dadx, shader->dady,
machine->Consts,
machine->Outputs,
machine->Samplers);
/* FIXME */
mask = ~0;
return mask;
}
/**
* Execute fragment shader for the four fragments in the quad.
*/
@ -77,7 +185,7 @@ shade_quad(struct quad_stage *qs, struct quad_header *quad)
boolean z_written;
/* run shader */
quad->inout.mask &= llvmpipe->fs->run( llvmpipe->fs, machine, quad );
quad->inout.mask &= shader_run( llvmpipe->fs, machine, quad );
if (quad->inout.mask == 0)
return FALSE;
@ -177,10 +285,9 @@ shade_begin(struct quad_stage *qs)
struct quad_shade_stage *qss = quad_shade_stage(qs);
struct llvmpipe_context *llvmpipe = qs->llvmpipe;
llvmpipe->fs->prepare( llvmpipe->fs,
qss->machine,
(struct tgsi_sampler **)
llvmpipe->tgsi.frag_samplers_list );
shader_prepare( llvmpipe->fs,
qss->machine,
(struct tgsi_sampler **)llvmpipe->tgsi.frag_samplers_list );
qs->next->begin(qs->next);
}

View file

@ -59,29 +59,36 @@ struct tgsi_exec_machine;
struct vertex_info;
typedef void
(*lp_shader_fs_func)(void *pos,
void *a0,
void *dadx,
void *dady,
void *consts,
void *outputs,
struct tgsi_sampler **samplers);
/**
* 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 {
struct pipe_shader_state shader;
struct lp_fragment_shader
{
struct pipe_shader_state base;
struct tgsi_shader_info info;
void (*prepare)( const struct lp_fragment_shader *shader,
struct tgsi_exec_machine *machine,
struct tgsi_sampler **samplers);
struct llvmpipe_screen *screen;
/* Run the shader - this interface will get cleaned up in the
* future:
*/
unsigned (*run)( const struct lp_fragment_shader *shader,
struct tgsi_exec_machine *machine,
struct quad_header *quad );
LLVMValueRef function;
lp_shader_fs_func jit_function;
void (*delete)( struct lp_fragment_shader * );
union tgsi_exec_channel ALIGN16_ATTRIB pos[NUM_CHANNELS];
union tgsi_exec_channel ALIGN16_ATTRIB a0[PIPE_MAX_SHADER_INPUTS][NUM_CHANNELS];
union tgsi_exec_channel ALIGN16_ATTRIB dadx[PIPE_MAX_SHADER_INPUTS][NUM_CHANNELS];
union tgsi_exec_channel ALIGN16_ATTRIB dady[PIPE_MAX_SHADER_INPUTS][NUM_CHANNELS];
};

View file

@ -1,5 +1,6 @@
/**************************************************************************
*
* Copyright 2009 VMware, Inc.
* Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas.
* All Rights Reserved.
*
@ -25,10 +26,6 @@
*
**************************************************************************/
#include "lp_context.h"
#include "lp_state.h"
#include "lp_fs.h"
#include "pipe/p_defines.h"
#include "util/u_memory.h"
#include "pipe/internal/p_winsys_screen.h"
@ -37,34 +34,159 @@
#include "tgsi/tgsi_dump.h"
#include "tgsi/tgsi_scan.h"
#include "tgsi/tgsi_parse.h"
#include "lp_bld_type.h"
#include "lp_bld_tgsi.h"
#include "lp_screen.h"
#include "lp_context.h"
#include "lp_state.h"
#include "lp_quad.h"
static void
shader_generate(struct llvmpipe_screen *screen,
struct lp_fragment_shader *shader)
{
const struct tgsi_token *tokens = shader->base.tokens;
union lp_type type;
LLVMTypeRef elem_type;
LLVMTypeRef vec_type;
LLVMTypeRef arg_types[7];
LLVMTypeRef func_type;
LLVMValueRef pos_ptr;
LLVMValueRef a0_ptr;
LLVMValueRef dadx_ptr;
LLVMValueRef dady_ptr;
LLVMValueRef consts_ptr;
LLVMValueRef outputs_ptr;
LLVMValueRef samplers_ptr;
LLVMBasicBlockRef block;
LLVMBuilderRef builder;
LLVMValueRef pos[NUM_CHANNELS];
LLVMValueRef outputs[PIPE_MAX_SHADER_OUTPUTS][NUM_CHANNELS];
char name[32];
unsigned i, j;
type.value = 0;
type.floating = TRUE;
type.sign = TRUE;
type.norm = FALSE;
type.width = 32;
type.length = 4;
elem_type = lp_build_elem_type(type);
vec_type = lp_build_vec_type(type);
arg_types[0] = LLVMPointerType(vec_type, 0); /* pos */
arg_types[1] = LLVMPointerType(vec_type, 0); /* a0 */
arg_types[2] = LLVMPointerType(vec_type, 0); /* dadx */
arg_types[3] = LLVMPointerType(vec_type, 0); /* dady */
arg_types[4] = LLVMPointerType(elem_type, 0); /* consts */
arg_types[5] = LLVMPointerType(vec_type, 0); /* outputs */
arg_types[6] = LLVMPointerType(LLVMInt8Type(), 0); /* samplers */
func_type = LLVMFunctionType(LLVMVoidType(), arg_types, Elements(arg_types), 0);
shader->function = LLVMAddFunction(screen->module, "shader", func_type);
LLVMSetFunctionCallConv(shader->function, LLVMCCallConv);
pos_ptr = LLVMGetParam(shader->function, 0);
a0_ptr = LLVMGetParam(shader->function, 1);
dadx_ptr = LLVMGetParam(shader->function, 2);
dady_ptr = LLVMGetParam(shader->function, 3);
consts_ptr = LLVMGetParam(shader->function, 4);
outputs_ptr = LLVMGetParam(shader->function, 5);
samplers_ptr = LLVMGetParam(shader->function, 6);
LLVMSetValueName(pos_ptr, "pos");
LLVMSetValueName(a0_ptr, "a0");
LLVMSetValueName(dadx_ptr, "dadx");
LLVMSetValueName(dady_ptr, "dady");
LLVMSetValueName(consts_ptr, "consts");
LLVMSetValueName(outputs_ptr, "outputs");
LLVMSetValueName(samplers_ptr, "samplers");
block = LLVMAppendBasicBlock(shader->function, "entry");
builder = LLVMCreateBuilder();
LLVMPositionBuilderAtEnd(builder, block);
for(j = 0; j < NUM_CHANNELS; ++j) {
LLVMValueRef index = LLVMConstInt(LLVMInt32Type(), j, 0);
util_snprintf(name, sizeof name, "pos.%c", "xyzw"[j]);
pos[j] = LLVMBuildLoad(builder, LLVMBuildGEP(builder, pos_ptr, &index, 1, ""), name);
}
memset(outputs, 0, sizeof outputs);
lp_build_tgsi_soa(builder, tokens, type,
pos, a0_ptr, dadx_ptr, dady_ptr,
consts_ptr, outputs, samplers_ptr);
for(i = 0; i < PIPE_MAX_SHADER_OUTPUTS; ++i) {
for(j = 0; j < NUM_CHANNELS; ++j) {
if(outputs[i][j]) {
LLVMValueRef index = LLVMConstInt(LLVMInt32Type(), i*NUM_CHANNELS + j, 0);
util_snprintf(name, sizeof name, "output%u.%c", i, "xyzw"[j]);
LLVMBuildStore(builder, outputs[i][j], LLVMBuildGEP(builder, outputs_ptr, &index, 1, name));
}
}
}
LLVMBuildRetVoid(builder);;
LLVMDisposeBuilder(builder);
}
void *
llvmpipe_create_fs_state(struct pipe_context *pipe,
const struct pipe_shader_state *templ)
{
struct llvmpipe_context *llvmpipe = llvmpipe_context(pipe);
struct lp_fragment_shader *state;
struct llvmpipe_screen *screen = llvmpipe_screen(pipe->screen);
struct lp_fragment_shader *shader;
LLVMValueRef fetch_texel;
/* debug */
if (llvmpipe->dump_fs)
tgsi_dump(templ->tokens, 0);
shader = CALLOC_STRUCT(lp_fragment_shader);
if (!shader)
return NULL;
/* codegen */
state = llvmpipe_create_fs_llvm( llvmpipe, templ );
if (!state) {
state = llvmpipe_create_fs_sse( llvmpipe, templ );
if (!state) {
state = llvmpipe_create_fs_exec( llvmpipe, templ );
/* 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;
#ifdef DEBUG
tgsi_dump(templ->tokens, 0);
#endif
shader_generate(screen, shader);
LLVMRunFunctionPassManager(screen->pass, shader->function);
#ifdef DEBUG
LLVMDumpValue(shader->function);
debug_printf("\n");
#endif
if(LLVMVerifyFunction(shader->function, LLVMPrintMessageAction)) {
LLVMDumpValue(shader->function);
abort();
}
fetch_texel = LLVMGetNamedFunction(screen->module, "fetch_texel");
if(fetch_texel) {
static boolean first_time = TRUE;
if(first_time) {
LLVMAddGlobalMapping(screen->engine, fetch_texel, lp_build_tgsi_fetch_texel_soa);
first_time = FALSE;
}
}
assert(state);
shader->jit_function = (lp_shader_fs_func)LLVMGetPointerToGlobal(screen->engine, shader->function);
/* get/save the summary info for this shader */
tgsi_scan_shader(templ->tokens, &state->info);
return state;
return shader;
}
@ -82,11 +204,19 @@ llvmpipe_bind_fs_state(struct pipe_context *pipe, void *fs)
void
llvmpipe_delete_fs_state(struct pipe_context *pipe, void *fs)
{
struct lp_fragment_shader *state = fs;
struct lp_fragment_shader *shader = fs;
struct llvmpipe_screen *screen = shader->screen;
assert(fs != llvmpipe_context(pipe)->fs);
state->delete( state );
if(shader->function) {
if(shader->jit_function)
LLVMFreeMachineCodeForFunction(screen->engine, shader->function);
LLVMDeleteFunction(shader->function);
}
FREE((void *) shader->base.tokens);
FREE(shader);
}