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 \
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',
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;
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 */
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;
};
+++ /dev/null
-/**************************************************************************
- *
- * 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
+++ /dev/null
-/**************************************************************************
- *
- * 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;
-}
+++ /dev/null
-/**************************************************************************
- *
- * 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;
-}
-
+++ /dev/null
-/**************************************************************************
- *
- * 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
/**************************************************************************
*
+ * 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
}
+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.
*/
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;
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);
}
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];
};
/**************************************************************************
*
+ * Copyright 2009 VMware, Inc.
* Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas.
* All Rights Reserved.
*
*
**************************************************************************/
-#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"
#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;
-
- /* debug */
- if (llvmpipe->dump_fs)
- tgsi_dump(templ->tokens, 0);
-
- /* 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 );
- }
- }
+ struct llvmpipe_screen *screen = llvmpipe_screen(pipe->screen);
+ struct lp_fragment_shader *shader;
+ LLVMValueRef fetch_texel;
- assert(state);
+ shader = CALLOC_STRUCT(lp_fragment_shader);
+ if (!shader)
+ return NULL;
/* get/save the summary info for this shader */
- tgsi_scan_shader(templ->tokens, &state->info);
+ tgsi_scan_shader(templ->tokens, &shader->info);
- return state;
+ /* 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;
+ }
+ }
+
+ shader->jit_function = (lp_shader_fs_func)LLVMGetPointerToGlobal(screen->engine, shader->function);
+
+ return shader;
}
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);
}