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:
@@ -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
|
||||
|
@@ -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',
|
||||
|
@@ -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);
|
||||
|
||||
|
@@ -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,
|
||||
|
@@ -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];
|
||||
};
|
||||
|
||||
|
||||
|
@@ -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 );
|
||||
|
||||
|
||||
|
@@ -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) {
|
||||
|
@@ -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;
|
||||
|
@@ -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 */
|
||||
|
196
src/gallium/drivers/llvmpipe/lp_tex_sample_llvm.c
Normal file
196
src/gallium/drivers/llvmpipe/lp_tex_sample_llvm.c
Normal 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;
|
||||
}
|
||||
|
Reference in New Issue
Block a user