softpipe: rework texture sampling code

Split into component pieces, stitch together at runtime using function
pointers.  Make it possible to utilize the existing fastpaths as image-level
filters for generic mip-filtering routines.

Remove special case for rectangle filtering, as it can now be handled by
the 2d path.

As most of the mesa demo texturing was already covered by fast paths, its
harder to find examples of speedups, but tunnel gets a boost as mip-nearest
filtering is now able to access the img_2d_linear_wrap_POT functions
for sampling within a mipmap level.
This commit is contained in:
Keith Whitwell 2009-08-21 17:13:11 +01:00
parent b1cc196e6d
commit 4fc7d0345a
11 changed files with 1487 additions and 1237 deletions

View file

@ -228,21 +228,6 @@ softpipe_create( struct pipe_screen *screen )
softpipe->quad.depth_test = sp_quad_depth_test_stage(softpipe);
softpipe->quad.blend = sp_quad_blend_stage(softpipe);
/* vertex shader samplers */
for (i = 0; i < PIPE_MAX_SAMPLERS; i++) {
softpipe->tgsi.vert_samplers[i].base.get_samples = sp_get_samples;
softpipe->tgsi.vert_samplers[i].processor = TGSI_PROCESSOR_VERTEX;
softpipe->tgsi.vert_samplers[i].cache = softpipe->tex_cache[i];
softpipe->tgsi.vert_samplers_list[i] = &softpipe->tgsi.vert_samplers[i];
}
/* fragment shader samplers */
for (i = 0; i < PIPE_MAX_SAMPLERS; i++) {
softpipe->tgsi.frag_samplers[i].base.get_samples = sp_get_samples;
softpipe->tgsi.frag_samplers[i].processor = TGSI_PROCESSOR_FRAGMENT;
softpipe->tgsi.frag_samplers[i].cache = softpipe->tex_cache[i];
softpipe->tgsi.frag_samplers_list[i] = &softpipe->tgsi.frag_samplers[i];
}
/*
* Create drawing context and plug our rendering stage into it.

View file

@ -36,7 +36,6 @@
#include "draw/draw_vertex.h"
#include "sp_quad_pipe.h"
#include "sp_tex_sample.h"
struct softpipe_vbuf_render;
@ -51,12 +50,12 @@ struct softpipe_context {
struct pipe_context pipe; /**< base class */
/** Constant state objects */
const struct pipe_blend_state *blend;
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 sp_fragment_shader *fs;
const struct sp_vertex_shader *vs;
struct pipe_blend_state *blend;
struct pipe_sampler_state *sampler[PIPE_MAX_SAMPLERS];
struct pipe_depth_stencil_alpha_state *depth_stencil;
struct pipe_rasterizer_state *rasterizer;
struct sp_fragment_shader *fs;
struct sp_vertex_shader *vs;
/** Other rendering state */
struct pipe_blend_color blend_color;
@ -123,10 +122,8 @@ struct softpipe_context {
/** TGSI exec things */
struct {
struct sp_shader_sampler vert_samplers[PIPE_MAX_SAMPLERS];
struct sp_shader_sampler *vert_samplers_list[PIPE_MAX_SAMPLERS];
struct sp_shader_sampler frag_samplers[PIPE_MAX_SAMPLERS];
struct sp_shader_sampler *frag_samplers_list[PIPE_MAX_SAMPLERS];
struct sp_sampler_varient *vert_samplers_list[PIPE_MAX_SAMPLERS];
struct sp_sampler_varient *frag_samplers_list[PIPE_MAX_SAMPLERS];
} tgsi;
/** The primitive drawing context */
@ -155,5 +152,9 @@ softpipe_context( struct pipe_context *pipe )
return (struct softpipe_context *)pipe;
}
void
softpipe_reset_sampler_varients(struct softpipe_context *softpipe);
#endif /* SP_CONTEXT_H */

View file

@ -87,6 +87,7 @@ struct sp_fragment_shader {
struct sp_vertex_shader {
struct pipe_shader_state shader;
struct draw_vertex_shader *draw_data;
int max_sampler; /* -1 if no samplers */
};

View file

@ -45,7 +45,7 @@ void softpipe_bind_blend_state( struct pipe_context *pipe,
{
struct softpipe_context *softpipe = softpipe_context(pipe);
softpipe->blend = (const struct pipe_blend_state *)blend;
softpipe->blend = (struct pipe_blend_state *)blend;
softpipe->dirty |= SP_NEW_BLEND;
}
@ -86,7 +86,7 @@ softpipe_bind_depth_stencil_state(struct pipe_context *pipe,
{
struct softpipe_context *softpipe = softpipe_context(pipe);
softpipe->depth_stencil = (const struct pipe_depth_stencil_alpha_state *)depth_stencil;
softpipe->depth_stencil = (struct pipe_depth_stencil_alpha_state *)depth_stencil;
softpipe->dirty |= SP_NEW_DEPTH_STENCIL_ALPHA;
}

View file

@ -198,19 +198,7 @@ update_tgsi_samplers( struct softpipe_context *softpipe )
{
unsigned i;
/* vertex shader samplers */
for (i = 0; i < PIPE_MAX_SAMPLERS; i++) {
softpipe->tgsi.vert_samplers[i].sampler = softpipe->sampler[i];
softpipe->tgsi.vert_samplers[i].texture = softpipe->texture[i];
softpipe->tgsi.frag_samplers[i].base.get_samples = sp_get_samples;
}
/* fragment shader samplers */
for (i = 0; i < PIPE_MAX_SAMPLERS; i++) {
softpipe->tgsi.frag_samplers[i].sampler = softpipe->sampler[i];
softpipe->tgsi.frag_samplers[i].texture = softpipe->texture[i];
softpipe->tgsi.frag_samplers[i].base.get_samples = sp_get_samples;
}
softpipe_reset_sampler_varients( softpipe );
for (i = 0; i < PIPE_MAX_SAMPLERS; i++) {
sp_tile_cache_validate_texture( softpipe->tex_cache[i] );
@ -232,7 +220,9 @@ void softpipe_update_derived( struct softpipe_context *softpipe )
}
if (softpipe->dirty & (SP_NEW_SAMPLER |
SP_NEW_TEXTURE))
SP_NEW_TEXTURE |
SP_NEW_FS |
SP_NEW_VS))
update_tgsi_samplers( softpipe );
if (softpipe->dirty & (SP_NEW_RASTERIZER |

View file

@ -34,6 +34,7 @@
#include "pipe/internal/p_winsys_screen.h"
#include "pipe/p_shader_tokens.h"
#include "draw/draw_context.h"
#include "draw/draw_vs.h"
#include "tgsi/tgsi_dump.h"
#include "tgsi/tgsi_scan.h"
#include "tgsi/tgsi_parse.h"
@ -108,6 +109,8 @@ softpipe_create_vs_state(struct pipe_context *pipe,
if (state->draw_data == NULL)
goto fail;
state->max_sampler = state->draw_data->info.file_max[TGSI_FILE_SAMPLER];
return state;
fail:

View file

@ -38,15 +38,32 @@
#include "sp_state.h"
#include "sp_texture.h"
#include "sp_tile_cache.h"
#include "sp_tex_sample.h"
#include "draw/draw_context.h"
struct sp_sampler {
struct pipe_sampler_state base;
struct sp_sampler_varient *varients;
struct sp_sampler_varient *current;
};
static struct sp_sampler *sp_sampler( struct pipe_sampler_state *sampler )
{
return (struct sp_sampler *)sampler;
}
void *
softpipe_create_sampler_state(struct pipe_context *pipe,
const struct pipe_sampler_state *sampler)
{
return mem_dup(sampler, sizeof(*sampler));
struct sp_sampler *sp_sampler = CALLOC_STRUCT(sp_sampler);
sp_sampler->base = *sampler;
sp_sampler->varients = NULL;
return (void *)sp_sampler;
}
@ -106,10 +123,95 @@ softpipe_set_sampler_textures(struct pipe_context *pipe,
}
static struct sp_sampler_varient *
get_sampler_varient( struct sp_sampler *sampler,
struct pipe_texture *texture,
unsigned processor )
{
struct softpipe_texture *sp_texture = softpipe_texture(texture);
struct sp_sampler_varient *v = NULL;
union sp_sampler_key key;
key.bits.target = sp_texture->base.target;
key.bits.is_pot = sp_texture->pot;
key.bits.processor = processor;
key.bits.pad = 0;
if (sampler->current &&
key.value == sampler->current->key.value) {
v = sampler->current;
}
if (v == NULL) {
for (v = sampler->varients; v; v = v->next)
if (v->key.value == key.value)
break;
if (v == NULL) {
v = sp_create_sampler_varient( &sampler->base, key );
v->next = sampler->varients;
sampler->varients = v;
}
}
sampler->current = v;
return v;
}
void
softpipe_reset_sampler_varients(struct softpipe_context *softpipe)
{
int i;
/* It's a bit hard to build these samplers ahead of time -- don't
* really know which samplers are going to be used for vertex and
* fragment programs.
*/
for (i = 0; i <= softpipe->vs->max_sampler; i++) {
if (softpipe->sampler[i]) {
softpipe->tgsi.vert_samplers_list[i] =
get_sampler_varient( sp_sampler(softpipe->sampler[i]),
softpipe->texture[i],
TGSI_PROCESSOR_VERTEX );
sp_sampler_varient_bind_texture( softpipe->tgsi.vert_samplers_list[i],
softpipe->tex_cache[i],
softpipe->texture[i] );
}
}
for (i = 0; i <= softpipe->fs->info.file_max[TGSI_FILE_SAMPLER]; i++) {
if (softpipe->sampler[i]) {
softpipe->tgsi.frag_samplers_list[i] =
get_sampler_varient( sp_sampler(softpipe->sampler[i]),
softpipe->texture[i],
TGSI_PROCESSOR_FRAGMENT );
sp_sampler_varient_bind_texture( softpipe->tgsi.frag_samplers_list[i],
softpipe->tex_cache[i],
softpipe->texture[i] );
}
}
}
void
softpipe_delete_sampler_state(struct pipe_context *pipe,
void *sampler)
{
struct sp_sampler *sp_sampler = (struct sp_sampler *)sampler;
struct sp_sampler_varient *v, *tmp;
for (v = sp_sampler->varients; v; v = tmp) {
tmp = v->next;
sp_sampler_varient_destroy(v);
}
FREE( sampler );
}

File diff suppressed because it is too large Load diff

View file

@ -31,14 +31,61 @@
#include "tgsi/tgsi_exec.h"
struct sp_sampler_varient;
typedef void (*wrap_nearest_func)(const float s[4],
unsigned size,
int icoord[4]);
typedef void (*wrap_linear_func)(const float s[4],
unsigned size,
int icoord0[4],
int icoord1[4],
float w[4]);
typedef float (*compute_lambda_func)(const struct sp_sampler_varient *sampler,
const float s[QUAD_SIZE],
const float t[QUAD_SIZE],
const float p[QUAD_SIZE],
float lodbias);
typedef void (*filter_func)(struct tgsi_sampler *tgsi_sampler,
const float s[QUAD_SIZE],
const float t[QUAD_SIZE],
const float p[QUAD_SIZE],
float lodbias,
float rgba[NUM_CHANNELS][QUAD_SIZE]);
union sp_sampler_key {
struct {
unsigned target:3;
unsigned is_pot:1;
unsigned processor:2;
unsigned pad:26;
} bits;
unsigned value;
};
/**
* Subclass of tgsi_sampler
*/
struct sp_shader_sampler
struct sp_sampler_varient
{
struct tgsi_sampler base; /**< base class */
union sp_sampler_key key;
/* The owner of this struct:
*/
const struct pipe_sampler_state *sampler;
/* Currently bound texture:
*/
const struct pipe_texture *texture;
struct softpipe_tile_cache *cache;
unsigned processor;
/* For sp_get_samples_2d_linear_POT:
@ -47,22 +94,51 @@ struct sp_shader_sampler
unsigned ypot;
unsigned level;
const struct pipe_texture *texture;
const struct pipe_sampler_state *sampler;
unsigned faces[4];
wrap_nearest_func nearest_texcoord_s;
wrap_nearest_func nearest_texcoord_t;
wrap_nearest_func nearest_texcoord_p;
struct softpipe_tile_cache *cache;
wrap_linear_func linear_texcoord_s;
wrap_linear_func linear_texcoord_t;
wrap_linear_func linear_texcoord_p;
filter_func min_img_filter;
filter_func mag_img_filter;
compute_lambda_func compute_lambda;
filter_func mip_filter;
filter_func compare;
/* Linked list:
*/
struct sp_sampler_varient *next;
};
struct sp_sampler;
/* Create a sampler varient for a given set of non-orthogonal state. Currently the
*/
struct sp_sampler_varient *
sp_create_sampler_varient( const struct pipe_sampler_state *sampler,
const union sp_sampler_key key );
void sp_sampler_varient_bind_texture( struct sp_sampler_varient *varient,
struct softpipe_tile_cache *tex_cache,
const struct pipe_texture *tex );
void sp_sampler_varient_destroy( struct sp_sampler_varient * );
static INLINE struct sp_shader_sampler *
sp_shader_sampler(const struct tgsi_sampler *sampler)
static INLINE struct sp_sampler_varient *
sp_sampler_varient(const struct tgsi_sampler *sampler)
{
return (struct sp_shader_sampler *) sampler;
return (struct sp_sampler_varient *) sampler;
}
extern void
sp_get_samples(struct tgsi_sampler *tgsi_sampler,
const float s[QUAD_SIZE],

View file

@ -120,16 +120,20 @@ softpipe_displaytarget_layout(struct pipe_screen *screen,
static struct pipe_texture *
softpipe_texture_create(struct pipe_screen *screen,
const struct pipe_texture *templat)
const struct pipe_texture *template)
{
struct softpipe_texture *spt = CALLOC_STRUCT(softpipe_texture);
if (!spt)
return NULL;
spt->base = *templat;
spt->base = *template;
pipe_reference_init(&spt->base.reference, 1);
spt->base.screen = screen;
spt->pot = (util_is_power_of_two(template->width[0]) &&
util_is_power_of_two(template->height[0]) &&
util_is_power_of_two(template->depth[0]));
if (spt->base.tex_usage & PIPE_TEXTURE_USAGE_DISPLAY_TARGET) {
if (!softpipe_displaytarget_layout(screen, spt))
goto fail;

View file

@ -48,6 +48,10 @@ struct softpipe_texture
*/
struct pipe_buffer *buffer;
/* True if texture images are power-of-two in all dimensions:
*/
boolean pot;
unsigned timestamp;
};