llvmpipe: Code generate the texture sampling inside the shader.

Finally a substantial performance improvement: framerates of apps using
texturing tripled, and furthermore, enabling/disabling texturing only
affects around 15% of the framerate, which means the bottleneck is now
somewhere else.

Generated texture sampling code is not complete though -- we always
sample from the base level -- so final figures will be different.
This commit is contained in:
José Fonseca
2009-09-07 14:52:39 +01:00
parent de8376e2f2
commit e4c76c02f7
11 changed files with 306 additions and 6 deletions

View File

@@ -46,7 +46,8 @@ C_SOURCES = \
lp_state_vs.c \
lp_surface.c \
lp_tex_cache.c \
lp_tex_sample.c \
lp_tex_sample_c.c \
lp_tex_sample_llvm.c \
lp_texture.c \
lp_tile_cache.c \
lp_tile_soa.c

View File

@@ -54,7 +54,8 @@ llvmpipe = env.ConvenienceLibrary(
'lp_state_vs.c',
'lp_surface.c',
'lp_tex_cache.c',
'lp_tex_sample.c',
'lp_tex_sample_c.c',
'lp_tex_sample_llvm.c',
'lp_texture.c',
'lp_tile_cache.c',
'lp_tile_soa.c',

View File

@@ -44,15 +44,47 @@
static void
lp_jit_init_globals(struct llvmpipe_screen *screen)
{
/* struct lp_jit_context */
LLVMTypeRef texture_type;
/* struct lp_jit_texture */
{
LLVMTypeRef elem_types[4];
elem_types[LP_JIT_TEXTURE_WIDTH] = LLVMInt32Type();
elem_types[LP_JIT_TEXTURE_HEIGHT] = LLVMInt32Type();
elem_types[LP_JIT_TEXTURE_STRIDE] = LLVMInt32Type();
elem_types[LP_JIT_TEXTURE_DATA] = LLVMPointerType(LLVMInt8Type(), 0);
texture_type = LLVMStructType(elem_types, Elements(elem_types), 0);
LP_CHECK_MEMBER_OFFSET(struct lp_jit_texture, width,
screen->target, texture_type,
LP_JIT_TEXTURE_WIDTH);
LP_CHECK_MEMBER_OFFSET(struct lp_jit_texture, height,
screen->target, texture_type,
LP_JIT_TEXTURE_HEIGHT);
LP_CHECK_MEMBER_OFFSET(struct lp_jit_texture, stride,
screen->target, texture_type,
LP_JIT_TEXTURE_STRIDE);
LP_CHECK_MEMBER_OFFSET(struct lp_jit_texture, data,
screen->target, texture_type,
LP_JIT_TEXTURE_DATA);
LP_CHECK_STRUCT_SIZE(struct lp_jit_texture,
screen->target, texture_type);
LLVMAddTypeName(screen->module, "texture", texture_type);
}
/* struct lp_jit_context */
{
LLVMTypeRef elem_types[5];
LLVMTypeRef context_type;
elem_types[0] = LLVMPointerType(LLVMFloatType(), 0); /* constants */
elem_types[1] = LLVMPointerType(LLVMInt8Type(), 0); /* samplers */
elem_types[2] = LLVMFloatType(); /* alpha_ref_value */
elem_types[3] = LLVMPointerType(LLVMInt8Type(), 0); /* blend_color */
elem_types[4] = LLVMArrayType(texture_type, PIPE_MAX_SAMPLERS); /* textures */
context_type = LLVMStructType(elem_types, Elements(elem_types), 0);
@@ -64,6 +96,9 @@ lp_jit_init_globals(struct llvmpipe_screen *screen)
screen->target, context_type, 2);
LP_CHECK_MEMBER_OFFSET(struct lp_jit_context, blend_color,
screen->target, context_type, 3);
LP_CHECK_MEMBER_OFFSET(struct lp_jit_context, textures,
screen->target, context_type,
LP_JIT_CONTEXT_TEXTURES_INDEX);
LP_CHECK_STRUCT_SIZE(struct lp_jit_context,
screen->target, context_type);

View File

@@ -38,11 +38,31 @@
#include "lp_bld_struct.h"
#include "pipe/p_state.h"
struct tgsi_sampler;
struct llvmpipe_screen;
struct lp_jit_texture
{
uint32_t width;
uint32_t height;
uint32_t stride;
const void *data;
};
enum {
LP_JIT_TEXTURE_WIDTH = 0,
LP_JIT_TEXTURE_HEIGHT,
LP_JIT_TEXTURE_STRIDE,
LP_JIT_TEXTURE_DATA
};
/**
* This structure is passed directly to the generated fragment shader.
*
@@ -65,6 +85,8 @@ struct lp_jit_context
/* TODO: blend constant color */
uint8_t *blend_color;
struct lp_jit_texture textures[PIPE_MAX_SAMPLERS];
};
@@ -80,6 +102,11 @@ struct lp_jit_context
#define lp_jit_context_blend_color(_builder, _ptr) \
lp_build_struct_get(_builder, _ptr, 3, "blend_color")
#define LP_JIT_CONTEXT_TEXTURES_INDEX 4
#define lp_jit_context_textures(_builder, _ptr) \
lp_build_struct_get_ptr(_builder, _ptr, LP_JIT_CONTEXT_TEXTURES_INDEX, "textures")
typedef void
(*lp_jit_frag_func)(struct lp_jit_context *context,

View File

@@ -36,6 +36,7 @@
#include "pipe/p_state.h"
#include "tgsi/tgsi_scan.h"
#include "lp_jit.h"
#include "lp_bld_sample.h" /* for struct lp_sampler_static_state */
#define LP_NEW_VIEWPORT 0x1
@@ -57,7 +58,8 @@
struct tgsi_sampler;
struct vertex_info;
struct pipe_context;
struct llvmpipe_context;
struct lp_fragment_shader;
@@ -67,6 +69,8 @@ struct lp_fragment_shader_variant_key
struct pipe_depth_state depth;
struct pipe_alpha_state alpha;
struct pipe_blend_state blend;
struct lp_sampler_static_state sampler[PIPE_MAX_SAMPLERS];
};

View File

@@ -250,7 +250,9 @@ void llvmpipe_update_derived( struct llvmpipe_context *llvmpipe )
if (llvmpipe->dirty & (LP_NEW_FS |
LP_NEW_BLEND |
LP_NEW_DEPTH_STENCIL_ALPHA))
LP_NEW_DEPTH_STENCIL_ALPHA |
LP_NEW_SAMPLER |
LP_NEW_TEXTURE))
llvmpipe_update_fs( llvmpipe );

View File

@@ -486,7 +486,13 @@ generate_fragment(struct llvmpipe_context *lp,
a0_ptr, dadx_ptr, dady_ptr,
x0, y0, 2, 0);
#if 0
/* C texture sampling */
sampler = lp_c_sampler_soa_create(context_ptr);
#else
/* code generated texture sampling */
sampler = lp_llvm_sampler_soa_create(key->sampler, context_ptr);
#endif
for(i = 0; i < num_fs; ++i) {
LLVMValueRef index = LLVMConstInt(LLVMInt32Type(), i, 0);
@@ -666,8 +672,11 @@ llvmpipe_set_constant_buffer(struct pipe_context *pipe,
*/
static void
make_variant_key(struct llvmpipe_context *lp,
struct lp_fragment_shader *shader,
struct lp_fragment_shader_variant_key *key)
{
unsigned i;
memset(key, 0, sizeof *key);
memcpy(&key->depth, &lp->depth_stencil->depth, sizeof key->depth);
@@ -678,6 +687,10 @@ make_variant_key(struct llvmpipe_context *lp,
/* alpha.ref_value is passed in jit_context */
memcpy(&key->blend, lp->blend, sizeof key->blend);
for(i = 0; i < PIPE_MAX_SAMPLERS; ++i)
if(shader->info.file_mask[TGSI_FILE_SAMPLER] & (1 << i))
lp_sampler_static_state(&key->sampler[i], lp->texture[i], lp->sampler[i]);
}
@@ -688,7 +701,7 @@ llvmpipe_update_fs(struct llvmpipe_context *lp)
struct lp_fragment_shader_variant_key key;
struct lp_fragment_shader_variant *variant;
make_variant_key(lp, &key);
make_variant_key(lp, shader, &key);
variant = shader->variants;
while(variant) {

View File

@@ -98,6 +98,16 @@ llvmpipe_set_sampler_textures(struct pipe_context *pipe,
pipe_texture_reference(&llvmpipe->texture[i], tex);
lp_tex_tile_cache_set_texture(llvmpipe->tex_cache[i], tex);
if(tex) {
struct llvmpipe_texture *lp_tex = llvmpipe_texture(tex);
struct lp_jit_texture *jit_tex = &llvmpipe->jit_context.textures[i];
jit_tex->width = tex->width[0];
jit_tex->height = tex->height[0];
jit_tex->stride = lp_tex->stride[0];
if(!lp_tex->dt)
jit_tex->data = lp_tex->data;
}
}
llvmpipe->num_textures = num;

View File

@@ -35,6 +35,7 @@
struct llvmpipe_tex_tile_cache;
struct lp_sampler_static_state;
/**
@@ -87,4 +88,14 @@ struct lp_build_sampler_soa *
lp_c_sampler_soa_create(LLVMValueRef context_ptr);
/**
* Pure-LLVM texture sampling code generator.
*
* @param context_ptr LLVM value with the pointer to the struct lp_jit_context.
*/
struct lp_build_sampler_soa *
lp_llvm_sampler_soa_create(const struct lp_sampler_static_state *key,
LLVMValueRef context_ptr);
#endif /* LP_TEX_SAMPLE_H */

View File

@@ -0,0 +1,196 @@
/**************************************************************************
*
* 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.
*
**************************************************************************/
/**
* Texture sampling code generation
*
* This file is nothing more than ugly glue between three largely independent
* entities:
* - TGSI -> LLVM translation (i.e., lp_build_tgsi_soa)
* - texture sampling code generation (i.e., lp_build_sample_soa)
* - LLVM pipe driver
*
* All interesting code is in the functions mentioned above. There is really
* nothing to see here.
*
* @author Jose Fonseca <jfonseca@vmware.com>
*/
#include "pipe/p_defines.h"
#include "pipe/p_shader_tokens.h"
#include "lp_bld_debug.h"
#include "lp_bld_type.h"
#include "lp_bld_intr.h"
#include "lp_bld_sample.h"
#include "lp_bld_tgsi.h"
#include "lp_state.h"
#include "lp_tex_sample.h"
/**
* This provides the bridge between the sampler state store in lp_jit_context
* and lp_jit_texture and the sampler code generator. It provides the
* texture layout information required by the texture sampler code generator
* in terms of the state stored in lp_jit_context and lp_jit_texture in runtime.
*/
struct llvmpipe_sampler_dynamic_state
{
struct lp_sampler_dynamic_state base;
const struct lp_sampler_static_state *static_state;
LLVMValueRef context_ptr;
};
/**
* This is the bridge between our sampler and the TGSI translator.
*/
struct lp_llvm_sampler_soa
{
struct lp_build_sampler_soa base;
struct llvmpipe_sampler_dynamic_state dynamic_state;
};
/**
* Fetch the specified member of the lp_jit_texture structure.
*
* @sa http://llvm.org/docs/GetElementPtr.html
*/
static LLVMValueRef
lp_llvm_texture_member(struct lp_sampler_dynamic_state *base,
LLVMBuilderRef builder,
unsigned unit,
unsigned member_index,
const char *member_name)
{
struct llvmpipe_sampler_dynamic_state *state = (struct llvmpipe_sampler_dynamic_state *)base;
LLVMValueRef indices[4];
LLVMValueRef ptr;
LLVMValueRef res;
assert(unit < PIPE_MAX_SAMPLERS);
/* context[0] */
indices[0] = LLVMConstInt(LLVMInt32Type(), 0, 0);
/* context[0].textures */
indices[1] = LLVMConstInt(LLVMInt32Type(), LP_JIT_CONTEXT_TEXTURES_INDEX, 0);
/* context[0].textures[unit] */
indices[2] = LLVMConstInt(LLVMInt32Type(), unit, 0);
/* context[0].textures[unit].member */
indices[3] = LLVMConstInt(LLVMInt32Type(), member_index, 0);
ptr = LLVMBuildGEP(builder, state->context_ptr, indices, Elements(indices), "");
res = LLVMBuildLoad(builder, ptr, "");
lp_build_name(res, "context.texture%u.%s", unit, member_name);
return res;
}
/**
* Helper macro to instantiate the functions that generate the code to fetch
* the members of lp_jit_texture to fulfill the sampler code generator requests.
*
* This complexity is the price we have to pay to keep the texture sampler code
* generator a reusable module without dependencies to llvmpipe internals.
*/
#define LP_LLVM_TEXTURE_MEMBER(_name, _index) \
static LLVMValueRef \
lp_llvm_texture_##_name( struct lp_sampler_dynamic_state *base, \
LLVMBuilderRef builder, \
unsigned unit) \
{ \
return lp_llvm_texture_member(base, builder, unit, _index, #_name ); \
}
LP_LLVM_TEXTURE_MEMBER(width, LP_JIT_TEXTURE_WIDTH)
LP_LLVM_TEXTURE_MEMBER(height, LP_JIT_TEXTURE_HEIGHT)
LP_LLVM_TEXTURE_MEMBER(stride, LP_JIT_TEXTURE_STRIDE)
LP_LLVM_TEXTURE_MEMBER(data_ptr, LP_JIT_TEXTURE_DATA)
static void
lp_llvm_sampler_soa_destroy(struct lp_build_sampler_soa *sampler)
{
FREE(sampler);
}
static void
lp_llvm_sampler_soa_emit_fetch_texel(struct lp_build_sampler_soa *base,
LLVMBuilderRef builder,
union lp_type type,
unsigned unit,
unsigned num_coords,
const LLVMValueRef *coords,
LLVMValueRef lodbias,
LLVMValueRef *texel)
{
struct lp_llvm_sampler_soa *sampler = (struct lp_llvm_sampler_soa *)base;
assert(unit < PIPE_MAX_SAMPLERS);
lp_build_sample_soa(builder,
&sampler->dynamic_state.static_state[unit],
&sampler->dynamic_state.base,
type,
unit,
num_coords,
coords,
lodbias,
texel);
}
struct lp_build_sampler_soa *
lp_llvm_sampler_soa_create(const struct lp_sampler_static_state *static_state,
LLVMValueRef context_ptr)
{
struct lp_llvm_sampler_soa *sampler;
sampler = CALLOC_STRUCT(lp_llvm_sampler_soa);
if(!sampler)
return NULL;
sampler->base.destroy = lp_llvm_sampler_soa_destroy;
sampler->base.emit_fetch_texel = lp_llvm_sampler_soa_emit_fetch_texel;
sampler->dynamic_state.base.width = lp_llvm_texture_width;
sampler->dynamic_state.base.height = lp_llvm_texture_height;
sampler->dynamic_state.base.stride = lp_llvm_texture_stride;
sampler->dynamic_state.base.data_ptr = lp_llvm_texture_data_ptr;
sampler->dynamic_state.static_state = static_state;
sampler->dynamic_state.context_ptr = context_ptr;
return &sampler->base;
}