#include "sp_context.h"
#include "sp_screen.h"
#include "sp_state.h"
- #include "sp_tile_cache.h"
+#include "sp_texture.h"
++#include "sp_tex_tile_cache.h"
/**
{
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];
- }
-
- /* 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_fragment;
- }
+ softpipe_reset_sampler_varients( softpipe );
for (i = 0; i < PIPE_MAX_SAMPLERS; i++) {
- struct softpipe_tile_cache *tc = softpipe->tex_cache[i];
- sp_tex_tile_cache_validate_texture( softpipe->tex_cache[i] );
++ struct softpipe_tex_tile_cache *tc = softpipe->tex_cache[i];
+ if (tc->texture) {
+ struct softpipe_texture *spt = softpipe_texture(tc->texture);
+ if (spt->timestamp != tc->timestamp) {
- sp_tile_cache_validate_texture( tc );
++ sp_tex_tile_cache_validate_texture( tc );
+ _debug_printf("INV %d %d\n", tc->timestamp, spt->timestamp);
+ tc->timestamp = spt->timestamp;
+ }
+ }
}
}
#include "sp_context.h"
#include "sp_state.h"
#include "sp_texture.h"
- #include "sp_tile_cache.h"
+#include "sp_tex_sample.h"
+ #include "sp_tex_tile_cache.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,
*
* Authors:
* Brian Paul
+ * Keith Whitwell
*/
-#include "sp_context.h"
-#include "sp_quad.h"
-#include "sp_surface.h"
-#include "sp_texture.h"
-#include "sp_tex_sample.h"
-#include "sp_tex_tile_cache.h"
#include "pipe/p_context.h"
#include "pipe/p_defines.h"
+#include "pipe/p_shader_tokens.h"
#include "util/u_math.h"
#include "util/u_memory.h"
- #include "sp_tile_cache.h"
+#include "sp_quad.h" /* only for #define QUAD_* tokens */
+#include "sp_tex_sample.h"
++#include "sp_tex_tile_cache.h"
* \param rgba the quad to put the texel/color into
* \param j which element of the rgba quad to write to
*
- * XXX maybe move this into sp_tile_cache.c and merge with the
+ * XXX maybe move this into sp_tex_tile_cache.c and merge with the
* sp_get_cached_tile_tex() function. Also, get 4 texels instead of 1...
*/
-static void
+static INLINE void
get_texel_quad_2d(const struct tgsi_sampler *tgsi_sampler,
unsigned face, unsigned level, int x, int y,
const float *out[4])
{
- const struct sp_shader_sampler *samp = sp_shader_sampler(tgsi_sampler);
+ const struct sp_sampler_varient *samp = sp_sampler_varient(tgsi_sampler);
- const struct softpipe_cached_tile *tile
+ const struct softpipe_tex_cached_tile *tile
= sp_get_cached_tile_tex(samp->cache,
- tile_address(x, y, 0, face, level));
+ tex_tile_address(x, y, 0, face, level));
y %= TILE_SIZE;
x %= TILE_SIZE;
get_texel_2d_ptr(const struct tgsi_sampler *tgsi_sampler,
unsigned face, unsigned level, int x, int y)
{
- const struct sp_shader_sampler *samp = sp_shader_sampler(tgsi_sampler);
+ const struct sp_sampler_varient *samp = sp_sampler_varient(tgsi_sampler);
- const struct softpipe_cached_tile *tile
+ const struct softpipe_tex_cached_tile *tile
= sp_get_cached_tile_tex(samp->cache,
- tile_address(x, y, 0, face, level));
+ tex_tile_address(x, y, 0, face, level));
y %= TILE_SIZE;
x %= TILE_SIZE;
/**
- * Called via tgsi_sampler::get_samples() when running a vertex shader.
- * Get four filtered RGBA values from the sampler's texture.
+ * Bind the given texture object and texture cache to the sampler varient.
*/
void
-sp_get_samples_vertex(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])
+sp_sampler_varient_bind_texture( struct sp_sampler_varient *samp,
- struct softpipe_tile_cache *tex_cache,
++ struct softpipe_tex_tile_cache *tex_cache,
+ const struct pipe_texture *texture )
+{
+ const struct pipe_sampler_state *sampler = samp->sampler;
+
+ samp->texture = texture;
+ samp->cache = tex_cache;
+ samp->xpot = util_unsigned_logbase2( texture->width[0] );
+ samp->ypot = util_unsigned_logbase2( texture->height[0] );
+ samp->level = CLAMP((int) sampler->min_lod, 0, (int) texture->last_level);
+}
+
+
+void
+sp_sampler_varient_destroy( struct sp_sampler_varient *samp )
{
- sp_get_samples(tgsi_sampler, s, t, p, FALSE, lodbias, rgba);
+ FREE(samp);
+}
+
+
+/* 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 )
+{
+ struct sp_sampler_varient *samp = CALLOC_STRUCT(sp_sampler_varient);
+ if (!samp)
+ return NULL;
+
+ samp->sampler = sampler;
+ samp->key = key;
+
+ /* Note that (for instance) linear_texcoord_s and
+ * nearest_texcoord_s may be active at the same time, if the
+ * sampler min_img_filter differs from its mag_img_filter.
+ */
+ if (sampler->normalized_coords) {
+ samp->linear_texcoord_s = get_linear_wrap( sampler->wrap_s );
+ samp->linear_texcoord_t = get_linear_wrap( sampler->wrap_t );
+ samp->linear_texcoord_p = get_linear_wrap( sampler->wrap_r );
+
+ samp->nearest_texcoord_s = get_nearest_wrap( sampler->wrap_s );
+ samp->nearest_texcoord_t = get_nearest_wrap( sampler->wrap_t );
+ samp->nearest_texcoord_p = get_nearest_wrap( sampler->wrap_r );
+ }
+ else {
+ samp->linear_texcoord_s = get_linear_unorm_wrap( sampler->wrap_s );
+ samp->linear_texcoord_t = get_linear_unorm_wrap( sampler->wrap_t );
+ samp->linear_texcoord_p = get_linear_unorm_wrap( sampler->wrap_r );
+
+ samp->nearest_texcoord_s = get_nearest_unorm_wrap( sampler->wrap_s );
+ samp->nearest_texcoord_t = get_nearest_unorm_wrap( sampler->wrap_t );
+ samp->nearest_texcoord_p = get_nearest_unorm_wrap( sampler->wrap_r );
+ }
+
+ samp->compute_lambda = get_lambda_func( key );
+
+ samp->min_img_filter = get_img_filter(key, sampler->min_img_filter, sampler);
+ samp->mag_img_filter = get_img_filter(key, sampler->mag_img_filter, sampler);
+
+ switch (sampler->min_mip_filter) {
+ case PIPE_TEX_MIPFILTER_NONE:
+ if (sampler->min_img_filter == sampler->mag_img_filter)
+ samp->mip_filter = samp->min_img_filter;
+ else
+ samp->mip_filter = mip_filter_none;
+ break;
+
+ case PIPE_TEX_MIPFILTER_NEAREST:
+ samp->mip_filter = mip_filter_nearest;
+ break;
+
+ case PIPE_TEX_MIPFILTER_LINEAR:
+ if (key.bits.is_pot &&
+ sampler->min_img_filter == sampler->mag_img_filter &&
+ sampler->normalized_coords &&
+ sampler->wrap_s == PIPE_TEX_WRAP_REPEAT &&
+ sampler->wrap_t == PIPE_TEX_WRAP_REPEAT &&
+ sampler->min_img_filter == PIPE_TEX_FILTER_LINEAR)
+ {
+ samp->mip_filter = mip_filter_linear_2d_linear_repeat_POT;
+ }
+ else
+ {
+ samp->mip_filter = mip_filter_linear;
+ }
+ break;
+ }
+
+ if (sampler->compare_mode != FALSE) {
+ samp->compare = sample_compare;
+ }
+ else {
+ /* Skip compare operation by promoting the mip_filter function
+ * pointer:
+ */
+ samp->compare = samp->mip_filter;
+ }
+
+ if (key.bits.target == PIPE_TEXTURE_CUBE) {
+ samp->base.get_samples = sample_cube;
+ }
+ else {
+ samp->faces[0] = 0;
+ samp->faces[1] = 0;
+ samp->faces[2] = 0;
+ samp->faces[3] = 0;
+
+ /* Skip cube face determination by promoting the compare
+ * function pointer:
+ */
+ samp->base.get_samples = samp->compare;
+ }
+
+ return samp;
}
+
+
+
+
+
+
{
struct tgsi_sampler base; /**< base class */
- struct softpipe_tile_cache *cache;
+ 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_tex_tile_cache *cache;
+
+ unsigned processor;
+
/* For sp_get_samples_2d_linear_POT:
*/
unsigned xpot;
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_tex_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 );
-static INLINE struct sp_shader_sampler *
-sp_shader_sampler(const struct tgsi_sampler *sampler)
-{
- return (struct sp_shader_sampler *) sampler;
-}
+void sp_sampler_varient_bind_texture( struct sp_sampler_varient *varient,
- struct softpipe_tile_cache *tex_cache,
++ struct softpipe_tex_tile_cache *tex_cache,
+ const struct pipe_texture *tex );
+void sp_sampler_varient_destroy( struct sp_sampler_varient * );
-extern void
-sp_get_samples_fragment(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]);
+
+
+static INLINE struct sp_sampler_varient *
+sp_sampler_varient(const struct tgsi_sampler *sampler)
+{
+ return (struct sp_sampler_varient *) sampler;
+}
extern void
-sp_get_samples_vertex(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]);
+sp_get_samples(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]);
#endif /* SP_TEX_SAMPLE_H */
--- /dev/null
- if (tc->texture) {
- struct softpipe_texture *spt = softpipe_texture(tc->texture);
- if (spt->timestamp != tc->timestamp) {
- /* texture was modified, invalidate all cached tiles */
- uint i;
- _debug_printf("INV %d %d\n", tc->timestamp, spt->timestamp);
- for (i = 0; i < NUM_ENTRIES; i++) {
- tc->entries[i].addr.bits.invalid = 1;
- }
-
- tc->timestamp = spt->timestamp;
- }
+ /**************************************************************************
+ *
+ * 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.
+ *
+ **************************************************************************/
+
+ /**
+ * Texture tile caching.
+ *
+ * Author:
+ * Brian Paul
+ */
+
+ #include "pipe/p_inlines.h"
+ #include "util/u_memory.h"
+ #include "util/u_tile.h"
+ #include "sp_context.h"
+ #include "sp_surface.h"
+ #include "sp_texture.h"
+ #include "sp_tex_tile_cache.h"
+
+
+
+ struct softpipe_tex_tile_cache *
+ sp_create_tex_tile_cache( struct pipe_screen *screen )
+ {
+ struct softpipe_tex_tile_cache *tc;
+ uint pos;
+
+ tc = CALLOC_STRUCT( softpipe_tex_tile_cache );
+ if (tc) {
+ tc->screen = screen;
+ for (pos = 0; pos < NUM_ENTRIES; pos++) {
+ tc->entries[pos].addr.bits.invalid = 1;
+ }
+ tc->last_tile = &tc->entries[0]; /* any tile */
+ }
+ return tc;
+ }
+
+
+ void
+ sp_destroy_tex_tile_cache(struct softpipe_tex_tile_cache *tc)
+ {
+ struct pipe_screen *screen;
+ uint pos;
+
+ for (pos = 0; pos < NUM_ENTRIES; pos++) {
+ /*assert(tc->entries[pos].x < 0);*/
+ }
+ if (tc->transfer) {
+ screen = tc->transfer->texture->screen;
+ screen->tex_transfer_destroy(tc->transfer);
+ }
+ if (tc->tex_trans) {
+ screen = tc->tex_trans->texture->screen;
+ screen->tex_transfer_destroy(tc->tex_trans);
+ }
+
+ FREE( tc );
+ }
+
+
+
+
+ void
+ sp_tex_tile_cache_map_transfers(struct softpipe_tex_tile_cache *tc)
+ {
+ if (tc->tex_trans && !tc->tex_trans_map)
+ tc->tex_trans_map = tc->screen->transfer_map(tc->screen, tc->tex_trans);
+ }
+
+
+ void
+ sp_tex_tile_cache_unmap_transfers(struct softpipe_tex_tile_cache *tc)
+ {
+ if (tc->tex_trans_map) {
+ tc->screen->transfer_unmap(tc->screen, tc->tex_trans);
+ tc->tex_trans_map = NULL;
+ }
+ }
+
++/**
++ * Invalidate all cached tiles for the cached texture.
++ * Should be called when the texture is modified.
++ */
+ void
+ sp_tex_tile_cache_validate_texture(struct softpipe_tex_tile_cache *tc)
+ {
++ unsigned i;
++
++ assert(tc);
++ assert(tc->texture);
++
++ for (i = 0; i < NUM_ENTRIES; i++) {
++ tc->entries[i].addr.bits.invalid = 1;
+ }
+ }
+
+ /**
+ * Specify the texture to cache.
+ */
+ void
+ sp_tex_tile_cache_set_texture(struct softpipe_tex_tile_cache *tc,
+ struct pipe_texture *texture)
+ {
+ uint i;
+
+ assert(!tc->transfer);
+
+ if (tc->texture != texture) {
+ pipe_texture_reference(&tc->texture, texture);
+
+ if (tc->tex_trans) {
+ struct pipe_screen *screen = tc->tex_trans->texture->screen;
+
+ if (tc->tex_trans_map) {
+ screen->transfer_unmap(screen, tc->tex_trans);
+ tc->tex_trans_map = NULL;
+ }
+
+ screen->tex_transfer_destroy(tc->tex_trans);
+ tc->tex_trans = NULL;
+ }
+
+ /* mark as entries as invalid/empty */
+ /* XXX we should try to avoid this when the teximage hasn't changed */
+ for (i = 0; i < NUM_ENTRIES; i++) {
+ tc->entries[i].addr.bits.invalid = 1;
+ }
+
+ tc->tex_face = -1; /* any invalid value here */
+ }
+ }
+
+
+
+
+ /**
+ * Flush the tile cache: write all dirty tiles back to the transfer.
+ * any tiles "flagged" as cleared will be "really" cleared.
+ */
+ void
+ sp_flush_tex_tile_cache(struct softpipe_tex_tile_cache *tc)
+ {
+ int pos;
+
+ if (tc->texture) {
+ /* caching a texture, mark all entries as empty */
+ for (pos = 0; pos < NUM_ENTRIES; pos++) {
+ tc->entries[pos].addr.bits.invalid = 1;
+ }
+ tc->tex_face = -1;
+ }
+
+ }
+
+
+ /**
+ * Given the texture face, level, zslice, x and y values, compute
+ * the cache entry position/index where we'd hope to find the
+ * cached texture tile.
+ * This is basically a direct-map cache.
+ * XXX There's probably lots of ways in which we can improve this.
+ */
+ static INLINE uint
+ tex_cache_pos( union tex_tile_address addr )
+ {
+ uint entry = (addr.bits.x +
+ addr.bits.y * 9 +
+ addr.bits.z * 3 +
+ addr.bits.face +
+ addr.bits.level * 7);
+
+ return entry % NUM_ENTRIES;
+ }
+
+ /**
+ * Similar to sp_get_cached_tile() but for textures.
+ * Tiles are read-only and indexed with more params.
+ */
+ const struct softpipe_tex_cached_tile *
+ sp_find_cached_tile_tex(struct softpipe_tex_tile_cache *tc,
+ union tex_tile_address addr )
+ {
+ struct pipe_screen *screen = tc->screen;
+ struct softpipe_tex_cached_tile *tile;
+
+ tile = tc->entries + tex_cache_pos( addr );
+
+ if (addr.value != tile->addr.value) {
+
+ /* cache miss. Most misses are because we've invaldiated the
+ * texture cache previously -- most commonly on binding a new
+ * texture. Currently we effectively flush the cache on texture
+ * bind.
+ */
+ #if 0
+ _debug_printf("miss at %u: x=%d y=%d z=%d face=%d level=%d\n"
+ " tile %u: x=%d y=%d z=%d face=%d level=%d\n",
+ pos, x/TILE_SIZE, y/TILE_SIZE, z, face, level,
+ pos, tile->addr.bits.x, tile->addr.bits.y, tile->z, tile->face, tile->level);
+ #endif
+
+ /* check if we need to get a new transfer */
+ if (!tc->tex_trans ||
+ tc->tex_face != addr.bits.face ||
+ tc->tex_level != addr.bits.level ||
+ tc->tex_z != addr.bits.z) {
+ /* get new transfer (view into texture) */
+
+ if (tc->tex_trans) {
+ if (tc->tex_trans_map) {
+ tc->screen->transfer_unmap(tc->screen, tc->tex_trans);
+ tc->tex_trans_map = NULL;
+ }
+
+ screen->tex_transfer_destroy(tc->tex_trans);
+ tc->tex_trans = NULL;
+ }
+
+ tc->tex_trans =
+ screen->get_tex_transfer(screen, tc->texture,
+ addr.bits.face,
+ addr.bits.level,
+ addr.bits.z,
+ PIPE_TRANSFER_READ, 0, 0,
+ tc->texture->width[addr.bits.level],
+ tc->texture->height[addr.bits.level]);
+
+ tc->tex_trans_map = screen->transfer_map(screen, tc->tex_trans);
+
+ tc->tex_face = addr.bits.face;
+ tc->tex_level = addr.bits.level;
+ tc->tex_z = addr.bits.z;
+ }
+
+ /* get tile from the transfer (view into texture) */
+ pipe_get_tile_rgba(tc->tex_trans,
+ addr.bits.x * TILE_SIZE,
+ addr.bits.y * TILE_SIZE,
+ TILE_SIZE, TILE_SIZE,
+ (float *) tile->data.color);
+ tile->addr = addr;
+ }
+
+ tc->last_tile = tile;
+ return tile;
+ }
+
+
+
tc->screen->transfer_unmap(tc->screen, tc->transfer);
tc->transfer_map = NULL;
}
-
- if (tc->tex_trans_map) {
- tc->screen->transfer_unmap(tc->screen, tc->tex_trans);
- tc->tex_trans_map = NULL;
- }
- }
-
-
- /**
- * Invalidate all cached tiles for the cached texture.
- * Should be called when the texture is modified.
- */
- void
- sp_tile_cache_validate_texture(struct softpipe_tile_cache *tc)
- {
- uint i;
-
- assert(tc);
- assert(tc->texture);
-
- for (i = 0; i < NUM_ENTRIES; i++) {
- tc->entries[i].addr.bits.invalid = 1;
- }
- }
-
-
- /**
- * Specify the texture to cache.
- */
- void
- sp_tile_cache_set_texture(struct softpipe_tile_cache *tc,
- struct pipe_texture *texture)
- {
- uint i;
-
- assert(!tc->transfer);
-
- if (tc->texture != texture) {
- pipe_texture_reference(&tc->texture, texture);
-
- if (tc->tex_trans) {
- struct pipe_screen *screen = tc->tex_trans->texture->screen;
-
- if (tc->tex_trans_map) {
- screen->transfer_unmap(screen, tc->tex_trans);
- tc->tex_trans_map = NULL;
- }
-
- screen->tex_transfer_destroy(tc->tex_trans);
- tc->tex_trans = NULL;
- }
-
- /* mark as entries as invalid/empty */
- /* XXX we should try to avoid this when the teximage hasn't changed */
- for (i = 0; i < NUM_ENTRIES; i++) {
- tc->entries[i].addr.bits.invalid = 1;
- }
-
- tc->tex_face = -1; /* any invalid value here */
- }
}
+
/**
* Set pixels in a tile to the given clear color/value, float.
*/