summaryrefslogtreecommitdiffstats
path: root/src/gallium/auxiliary
diff options
context:
space:
mode:
Diffstat (limited to 'src/gallium/auxiliary')
-rw-r--r--src/gallium/auxiliary/Makefile1
-rw-r--r--src/gallium/auxiliary/SConscript1
-rw-r--r--src/gallium/auxiliary/draw/draw_context.c73
-rw-r--r--src/gallium/auxiliary/draw/draw_context.h12
-rw-r--r--src/gallium/auxiliary/draw/draw_llvm.c23
-rw-r--r--src/gallium/auxiliary/draw/draw_pipe_aaline.c50
-rw-r--r--src/gallium/auxiliary/draw/draw_pipe_aapoint.c39
-rw-r--r--src/gallium/auxiliary/draw/draw_pipe_wide_line.c34
-rw-r--r--src/gallium/auxiliary/draw/draw_pipe_wide_point.c36
-rw-r--r--src/gallium/auxiliary/draw/draw_private.h16
-rw-r--r--src/gallium/auxiliary/draw/draw_pt.c4
-rw-r--r--src/gallium/auxiliary/gallivm/lp_bld_pack.c2
-rw-r--r--src/gallium/auxiliary/gallivm/lp_bld_sample.h5
-rw-r--r--src/gallium/auxiliary/gallivm/lp_bld_sample_soa.c22
-rw-r--r--src/gallium/auxiliary/tgsi/tgsi_exec.c6
-rw-r--r--src/gallium/auxiliary/tgsi/tgsi_ureg.c4
-rw-r--r--src/gallium/auxiliary/util/u_blit.c1
-rw-r--r--src/gallium/auxiliary/util/u_blitter.c8
-rw-r--r--src/gallium/auxiliary/util/u_blitter.h16
-rw-r--r--src/gallium/auxiliary/util/u_dirty_surfaces.h88
-rw-r--r--src/gallium/auxiliary/util/u_inlines.h23
-rw-r--r--src/gallium/auxiliary/util/u_surfaces.c112
-rw-r--r--src/gallium/auxiliary/util/u_surfaces.h54
23 files changed, 539 insertions, 91 deletions
diff --git a/src/gallium/auxiliary/Makefile b/src/gallium/auxiliary/Makefile
index c672f32b7b2..38ce14df6b6 100644
--- a/src/gallium/auxiliary/Makefile
+++ b/src/gallium/auxiliary/Makefile
@@ -129,6 +129,7 @@ C_SOURCES = \
util/u_simple_shaders.c \
util/u_snprintf.c \
util/u_surface.c \
+ util/u_surfaces.c \
util/u_texture.c \
util/u_tile.c \
util/u_transfer.c \
diff --git a/src/gallium/auxiliary/SConscript b/src/gallium/auxiliary/SConscript
index 42f2cffc812..a9ec5d4e2cc 100644
--- a/src/gallium/auxiliary/SConscript
+++ b/src/gallium/auxiliary/SConscript
@@ -178,6 +178,7 @@ source = [
'util/u_simple_shaders.c',
'util/u_snprintf.c',
'util/u_surface.c',
+ 'util/u_surfaces.c',
'util/u_texture.c',
'util/u_tile.c',
'util/u_transfer.c',
diff --git a/src/gallium/auxiliary/draw/draw_context.c b/src/gallium/auxiliary/draw/draw_context.c
index b6c558ba9b1..4196f01e0b2 100644
--- a/src/gallium/auxiliary/draw/draw_context.c
+++ b/src/gallium/auxiliary/draw/draw_context.c
@@ -31,22 +31,33 @@
*/
+#include "pipe/p_context.h"
#include "util/u_memory.h"
#include "util/u_math.h"
#include "draw_context.h"
#include "draw_vs.h"
#include "draw_gs.h"
+#if HAVE_LLVM
+#include "gallivm/lp_bld_init.h"
+#endif
-struct draw_context *draw_create( void )
+struct draw_context *draw_create( struct pipe_context *pipe )
{
struct draw_context *draw = CALLOC_STRUCT( draw_context );
if (draw == NULL)
goto fail;
+#if HAVE_LLVM
+ assert(lp_build_engine);
+ draw->engine = lp_build_engine;
+#endif
+
if (!draw_init(draw))
goto fail;
+ draw->pipe = pipe;
+
return draw;
fail:
@@ -92,10 +103,23 @@ boolean draw_init(struct draw_context *draw)
void draw_destroy( struct draw_context *draw )
{
+ struct pipe_context *pipe;
+ int i, j;
+
if (!draw)
return;
+ pipe = draw->pipe;
+ /* free any rasterizer CSOs that we may have created.
+ */
+ for (i = 0; i < 2; i++) {
+ for (j = 0; j < 2; j++) {
+ if (draw->rasterizer_no_cull[i][j]) {
+ pipe->delete_rasterizer_state(pipe, draw->rasterizer_no_cull[i][j]);
+ }
+ }
+ }
/* Not so fast -- we're just borrowing this at the moment.
*
@@ -137,12 +161,17 @@ void draw_set_mrd(struct draw_context *draw, double mrd)
* This causes the drawing pipeline to be rebuilt.
*/
void draw_set_rasterizer_state( struct draw_context *draw,
- const struct pipe_rasterizer_state *raster )
+ const struct pipe_rasterizer_state *raster,
+ void *rast_handle )
{
- draw_do_flush( draw, DRAW_FLUSH_STATE_CHANGE );
+ if (!draw->suspend_flushing) {
+ draw_do_flush( draw, DRAW_FLUSH_STATE_CHANGE );
- draw->rasterizer = raster;
- draw->bypass_clipping = draw->driver.bypass_clipping;
+ draw->rasterizer = raster;
+ draw->rast_handle = rast_handle;
+
+ draw->bypass_clipping = draw->driver.bypass_clipping;
+ }
}
@@ -499,3 +528,37 @@ draw_current_shader_position_output(const struct draw_context *draw)
return draw->gs.position_output;
return draw->vs.position_output;
}
+
+
+/**
+ * Return a pointer/handle for a driver/CSO rasterizer object which
+ * disabled culling, stippling, unfilled tris, etc.
+ * This is used by some pipeline stages (such as wide_point, aa_line
+ * and aa_point) which convert points/lines into triangles. In those
+ * cases we don't want to accidentally cull the triangles.
+ *
+ * \param scissor should the rasterizer state enable scissoring?
+ * \param flatshade should the rasterizer state use flat shading?
+ * \return rasterizer CSO handle
+ */
+void *
+draw_get_rasterizer_no_cull( struct draw_context *draw,
+ boolean scissor,
+ boolean flatshade )
+{
+ if (!draw->rasterizer_no_cull[scissor][flatshade]) {
+ /* create now */
+ struct pipe_context *pipe = draw->pipe;
+ struct pipe_rasterizer_state rast;
+
+ memset(&rast, 0, sizeof(rast));
+ rast.scissor = scissor;
+ rast.flatshade = flatshade;
+ rast.front_winding = PIPE_WINDING_CCW;
+ rast.gl_rasterization_rules = draw->rasterizer->gl_rasterization_rules;
+
+ draw->rasterizer_no_cull[scissor][flatshade] =
+ pipe->create_rasterizer_state(pipe, &rast);
+ }
+ return draw->rasterizer_no_cull[scissor][flatshade];
+}
diff --git a/src/gallium/auxiliary/draw/draw_context.h b/src/gallium/auxiliary/draw/draw_context.h
index cfa0ad88d0a..7b41bb48dd3 100644
--- a/src/gallium/auxiliary/draw/draw_context.h
+++ b/src/gallium/auxiliary/draw/draw_context.h
@@ -48,7 +48,7 @@ struct draw_geometry_shader;
struct tgsi_sampler;
-struct draw_context *draw_create( void );
+struct draw_context *draw_create( struct pipe_context *pipe );
void draw_destroy( struct draw_context *draw );
@@ -59,7 +59,8 @@ void draw_set_clip_state( struct draw_context *pipe,
const struct pipe_clip_state *clip );
void draw_set_rasterizer_state( struct draw_context *draw,
- const struct pipe_rasterizer_state *raster );
+ const struct pipe_rasterizer_state *raster,
+ void *rast_handle );
void draw_set_rasterize_stage( struct draw_context *draw,
struct draw_stage *stage );
@@ -198,11 +199,4 @@ boolean draw_need_pipeline(const struct draw_context *draw,
const struct pipe_rasterizer_state *rasterizer,
unsigned prim );
-#ifdef HAVE_LLVM
-/*******************************************************************************
- * LLVM integration
- */
-struct draw_context *draw_create_with_llvm(void);
-#endif
-
#endif /* DRAW_CONTEXT_H */
diff --git a/src/gallium/auxiliary/draw/draw_llvm.c b/src/gallium/auxiliary/draw/draw_llvm.c
index a5403a49c35..9d110317698 100644
--- a/src/gallium/auxiliary/draw/draw_llvm.c
+++ b/src/gallium/auxiliary/draw/draw_llvm.c
@@ -10,7 +10,6 @@
#include "gallivm/lp_bld_debug.h"
#include "gallivm/lp_bld_tgsi.h"
#include "gallivm/lp_bld_printf.h"
-#include "gallivm/lp_bld_init.h"
#include "tgsi/tgsi_exec.h"
@@ -196,7 +195,7 @@ draw_llvm_create(struct draw_context *draw)
init_globals(llvm);
-#if 1
+#if 0
LLVMDumpModule(llvm->module);
#endif
@@ -223,26 +222,6 @@ draw_llvm_prepare(struct draw_llvm *llvm, int num_inputs)
return variant;
}
-
-struct draw_context *draw_create_with_llvm(void)
-{
- struct draw_context *draw = CALLOC_STRUCT( draw_context );
- if (draw == NULL)
- goto fail;
-
- assert(lp_build_engine);
- draw->engine = lp_build_engine;
-
- if (!draw_init(draw))
- goto fail;
-
- return draw;
-
-fail:
- draw_destroy( draw );
- return NULL;
-}
-
static void
generate_vs(struct draw_llvm *llvm,
LLVMBuilderRef builder,
diff --git a/src/gallium/auxiliary/draw/draw_pipe_aaline.c b/src/gallium/auxiliary/draw/draw_pipe_aaline.c
index e96dbecd262..4faf0a779ca 100644
--- a/src/gallium/auxiliary/draw/draw_pipe_aaline.c
+++ b/src/gallium/auxiliary/draw/draw_pipe_aaline.c
@@ -113,11 +113,10 @@ struct aaline_stage
void (*driver_bind_sampler_states)(struct pipe_context *, unsigned,
void **);
+
void (*driver_set_sampler_views)(struct pipe_context *,
unsigned,
struct pipe_sampler_view **);
-
- struct pipe_context *pipe;
};
@@ -342,6 +341,7 @@ aa_transform_inst(struct tgsi_transform_context *ctx,
static boolean
generate_aaline_fs(struct aaline_stage *aaline)
{
+ struct pipe_context *pipe = aaline->stage.draw->pipe;
const struct pipe_shader_state *orig_fs = &aaline->fs->state;
struct pipe_shader_state aaline_fs;
struct aa_transform_context transform;
@@ -374,7 +374,7 @@ generate_aaline_fs(struct aaline_stage *aaline)
aaline->fs->sampler_unit = transform.freeSampler;
aaline->fs->aaline_fs
- = aaline->driver_create_fs_state(aaline->pipe, &aaline_fs);
+ = aaline->driver_create_fs_state(pipe, &aaline_fs);
if (aaline->fs->aaline_fs == NULL)
goto fail;
@@ -394,7 +394,7 @@ fail:
static boolean
aaline_create_texture(struct aaline_stage *aaline)
{
- struct pipe_context *pipe = aaline->pipe;
+ struct pipe_context *pipe = aaline->stage.draw->pipe;
struct pipe_screen *screen = pipe->screen;
struct pipe_resource texTemp;
struct pipe_sampler_view viewTempl;
@@ -486,7 +486,7 @@ static boolean
aaline_create_sampler(struct aaline_stage *aaline)
{
struct pipe_sampler_state sampler;
- struct pipe_context *pipe = aaline->pipe;
+ struct pipe_context *pipe = aaline->stage.draw->pipe;
memset(&sampler, 0, sizeof(sampler));
sampler.wrap_s = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
@@ -515,13 +515,14 @@ static boolean
bind_aaline_fragment_shader(struct aaline_stage *aaline)
{
struct draw_context *draw = aaline->stage.draw;
+ struct pipe_context *pipe = draw->pipe;
if (!aaline->fs->aaline_fs &&
!generate_aaline_fs(aaline))
return FALSE;
draw->suspend_flushing = TRUE;
- aaline->driver_bind_fs_state(aaline->pipe, aaline->fs->aaline_fs);
+ aaline->driver_bind_fs_state(pipe, aaline->fs->aaline_fs);
draw->suspend_flushing = FALSE;
return TRUE;
@@ -661,8 +662,10 @@ aaline_first_line(struct draw_stage *stage, struct prim_header *header)
{
auto struct aaline_stage *aaline = aaline_stage(stage);
struct draw_context *draw = stage->draw;
- struct pipe_context *pipe = aaline->pipe;
+ struct pipe_context *pipe = draw->pipe;
+ const struct pipe_rasterizer_state *rast = draw->rasterizer;
uint num_samplers;
+ void *r;
assert(draw->rasterizer->line_smooth);
@@ -701,6 +704,11 @@ aaline_first_line(struct draw_stage *stage, struct prim_header *header)
draw->suspend_flushing = TRUE;
aaline->driver_bind_sampler_states(pipe, num_samplers, aaline->state.sampler);
aaline->driver_set_sampler_views(pipe, num_samplers, aaline->state.sampler_views);
+
+ /* Disable triangle culling, stippling, unfilled mode etc. */
+ r = draw_get_rasterizer_no_cull(draw, rast->scissor, rast->flatshade);
+ pipe->bind_rasterizer_state(pipe, r);
+
draw->suspend_flushing = FALSE;
/* now really draw first line */
@@ -714,7 +722,7 @@ aaline_flush(struct draw_stage *stage, unsigned flags)
{
struct draw_context *draw = stage->draw;
struct aaline_stage *aaline = aaline_stage(stage);
- struct pipe_context *pipe = aaline->pipe;
+ struct pipe_context *pipe = draw->pipe;
stage->line = aaline_first_line;
stage->next->flush( stage->next, flags );
@@ -727,6 +735,12 @@ aaline_flush(struct draw_stage *stage, unsigned flags)
aaline->driver_set_sampler_views(pipe,
aaline->num_sampler_views,
aaline->state.sampler_views);
+
+ /* restore original rasterizer state */
+ if (draw->rast_handle) {
+ pipe->bind_rasterizer_state(pipe, draw->rast_handle);
+ }
+
draw->suspend_flushing = FALSE;
draw->extra_shader_outputs.slot = 0;
@@ -744,6 +758,7 @@ static void
aaline_destroy(struct draw_stage *stage)
{
struct aaline_stage *aaline = aaline_stage(stage);
+ struct pipe_context *pipe = stage->draw->pipe;
uint i;
for (i = 0; i < PIPE_MAX_SAMPLERS; i++) {
@@ -751,7 +766,7 @@ aaline_destroy(struct draw_stage *stage)
}
if (aaline->sampler_cso)
- aaline->pipe->delete_sampler_state(aaline->pipe, aaline->sampler_cso);
+ pipe->delete_sampler_state(pipe, aaline->sampler_cso);
if (aaline->texture)
pipe_resource_reference(&aaline->texture, NULL);
@@ -814,13 +829,14 @@ aaline_create_fs_state(struct pipe_context *pipe,
{
struct aaline_stage *aaline = aaline_stage_from_pipe(pipe);
struct aaline_fragment_shader *aafs = CALLOC_STRUCT(aaline_fragment_shader);
+
if (aafs == NULL)
return NULL;
aafs->state = *fs;
/* pass-through */
- aafs->driver_fs = aaline->driver_create_fs_state(aaline->pipe, fs);
+ aafs->driver_fs = aaline->driver_create_fs_state(pipe, fs);
return aafs;
}
@@ -835,8 +851,7 @@ aaline_bind_fs_state(struct pipe_context *pipe, void *fs)
/* save current */
aaline->fs = aafs;
/* pass-through */
- aaline->driver_bind_fs_state(aaline->pipe,
- (aafs ? aafs->driver_fs : NULL));
+ aaline->driver_bind_fs_state(pipe, (aafs ? aafs->driver_fs : NULL));
}
@@ -845,11 +860,12 @@ aaline_delete_fs_state(struct pipe_context *pipe, void *fs)
{
struct aaline_stage *aaline = aaline_stage_from_pipe(pipe);
struct aaline_fragment_shader *aafs = (struct aaline_fragment_shader *) fs;
+
/* pass-through */
- aaline->driver_delete_fs_state(aaline->pipe, aafs->driver_fs);
+ aaline->driver_delete_fs_state(pipe, aafs->driver_fs);
if (aafs->aaline_fs)
- aaline->driver_delete_fs_state(aaline->pipe, aafs->aaline_fs);
+ aaline->driver_delete_fs_state(pipe, aafs->aaline_fs);
FREE(aafs);
}
@@ -866,7 +882,7 @@ aaline_bind_sampler_states(struct pipe_context *pipe,
aaline->num_samplers = num;
/* pass-through */
- aaline->driver_bind_sampler_states(aaline->pipe, num, sampler);
+ aaline->driver_bind_sampler_states(pipe, num, sampler);
}
@@ -888,7 +904,7 @@ aaline_set_sampler_views(struct pipe_context *pipe,
aaline->num_sampler_views = num;
/* pass-through */
- aaline->driver_set_sampler_views(aaline->pipe, num, views);
+ aaline->driver_set_sampler_views(pipe, num, views);
}
@@ -911,8 +927,6 @@ draw_install_aaline_stage(struct draw_context *draw, struct pipe_context *pipe)
if (!aaline)
goto fail;
- aaline->pipe = pipe;
-
/* create special texture, sampler state */
if (!aaline_create_texture(aaline))
goto fail;
diff --git a/src/gallium/auxiliary/draw/draw_pipe_aapoint.c b/src/gallium/auxiliary/draw/draw_pipe_aapoint.c
index 9f9fb4312c1..bba6f50c020 100644
--- a/src/gallium/auxiliary/draw/draw_pipe_aapoint.c
+++ b/src/gallium/auxiliary/draw/draw_pipe_aapoint.c
@@ -107,8 +107,6 @@ struct aapoint_stage
const struct pipe_shader_state *);
void (*driver_bind_fs_state)(struct pipe_context *, void *);
void (*driver_delete_fs_state)(struct pipe_context *, void *);
-
- struct pipe_context *pipe;
};
@@ -499,6 +497,7 @@ generate_aapoint_fs(struct aapoint_stage *aapoint)
struct pipe_shader_state aapoint_fs;
struct aa_transform_context transform;
const uint newLen = tgsi_num_tokens(orig_fs->tokens) + NUM_NEW_TOKENS;
+ struct pipe_context *pipe = aapoint->stage.draw->pipe;
aapoint_fs = *orig_fs; /* copy to init */
aapoint_fs.tokens = tgsi_alloc_tokens(newLen);
@@ -527,7 +526,7 @@ generate_aapoint_fs(struct aapoint_stage *aapoint)
#endif
aapoint->fs->aapoint_fs
- = aapoint->driver_create_fs_state(aapoint->pipe, &aapoint_fs);
+ = aapoint->driver_create_fs_state(pipe, &aapoint_fs);
if (aapoint->fs->aapoint_fs == NULL)
goto fail;
@@ -549,13 +548,14 @@ static boolean
bind_aapoint_fragment_shader(struct aapoint_stage *aapoint)
{
struct draw_context *draw = aapoint->stage.draw;
+ struct pipe_context *pipe = draw->pipe;
if (!aapoint->fs->aapoint_fs &&
!generate_aapoint_fs(aapoint))
return FALSE;
draw->suspend_flushing = TRUE;
- aapoint->driver_bind_fs_state(aapoint->pipe, aapoint->fs->aapoint_fs);
+ aapoint->driver_bind_fs_state(pipe, aapoint->fs->aapoint_fs);
draw->suspend_flushing = FALSE;
return TRUE;
@@ -679,6 +679,9 @@ aapoint_first_point(struct draw_stage *stage, struct prim_header *header)
{
auto struct aapoint_stage *aapoint = aapoint_stage(stage);
struct draw_context *draw = stage->draw;
+ struct pipe_context *pipe = draw->pipe;
+ const struct pipe_rasterizer_state *rast = draw->rasterizer;
+ void *r;
assert(draw->rasterizer->point_smooth);
@@ -716,6 +719,14 @@ aapoint_first_point(struct draw_stage *stage, struct prim_header *header)
}
}
+ draw->suspend_flushing = TRUE;
+
+ /* Disable triangle culling, stippling, unfilled mode etc. */
+ r = draw_get_rasterizer_no_cull(draw, rast->scissor, rast->flatshade);
+ pipe->bind_rasterizer_state(pipe, r);
+
+ draw->suspend_flushing = FALSE;
+
/* now really draw first point */
stage->point = aapoint_point;
stage->point(stage, header);
@@ -727,7 +738,7 @@ aapoint_flush(struct draw_stage *stage, unsigned flags)
{
struct draw_context *draw = stage->draw;
struct aapoint_stage *aapoint = aapoint_stage(stage);
- struct pipe_context *pipe = aapoint->pipe;
+ struct pipe_context *pipe = draw->pipe;
stage->point = aapoint_first_point;
stage->next->flush( stage->next, flags );
@@ -735,6 +746,12 @@ aapoint_flush(struct draw_stage *stage, unsigned flags)
/* restore original frag shader */
draw->suspend_flushing = TRUE;
aapoint->driver_bind_fs_state(pipe, aapoint->fs->driver_fs);
+
+ /* restore original rasterizer state */
+ if (draw->rast_handle) {
+ pipe->bind_rasterizer_state(pipe, draw->rast_handle);
+ }
+
draw->suspend_flushing = FALSE;
draw->extra_shader_outputs.slot = 0;
@@ -811,7 +828,7 @@ aapoint_create_fs_state(struct pipe_context *pipe,
aafs->state = *fs;
/* pass-through */
- aafs->driver_fs = aapoint->driver_create_fs_state(aapoint->pipe, fs);
+ aafs->driver_fs = aapoint->driver_create_fs_state(pipe, fs);
return aafs;
}
@@ -825,7 +842,7 @@ aapoint_bind_fs_state(struct pipe_context *pipe, void *fs)
/* save current */
aapoint->fs = aafs;
/* pass-through */
- aapoint->driver_bind_fs_state(aapoint->pipe,
+ aapoint->driver_bind_fs_state(pipe,
(aafs ? aafs->driver_fs : NULL));
}
@@ -837,10 +854,10 @@ aapoint_delete_fs_state(struct pipe_context *pipe, void *fs)
struct aapoint_fragment_shader *aafs = (struct aapoint_fragment_shader *) fs;
/* pass-through */
- aapoint->driver_delete_fs_state(aapoint->pipe, aafs->driver_fs);
+ aapoint->driver_delete_fs_state(pipe, aafs->driver_fs);
if (aafs->aapoint_fs)
- aapoint->driver_delete_fs_state(aapoint->pipe, aafs->aapoint_fs);
+ aapoint->driver_delete_fs_state(pipe, aafs->aapoint_fs);
FREE(aafs);
}
@@ -857,8 +874,6 @@ draw_install_aapoint_stage(struct draw_context *draw,
{
struct aapoint_stage *aapoint;
- pipe->draw = (void *) draw;
-
/*
* Create / install AA point drawing / prim stage
*/
@@ -866,8 +881,6 @@ draw_install_aapoint_stage(struct draw_context *draw,
if (aapoint == NULL)
return FALSE;
- aapoint->pipe = pipe;
-
/* save original driver functions */
aapoint->driver_create_fs_state = pipe->create_fs_state;
aapoint->driver_bind_fs_state = pipe->bind_fs_state;
diff --git a/src/gallium/auxiliary/draw/draw_pipe_wide_line.c b/src/gallium/auxiliary/draw/draw_pipe_wide_line.c
index 3073c870825..265a420d01e 100644
--- a/src/gallium/auxiliary/draw/draw_pipe_wide_line.c
+++ b/src/gallium/auxiliary/draw/draw_pipe_wide_line.c
@@ -28,6 +28,7 @@
/* Authors: Keith Whitwell <[email protected]>
*/
+#include "pipe/p_context.h"
#include "pipe/p_defines.h"
#include "pipe/p_shader_tokens.h"
#include "util/u_math.h"
@@ -142,9 +143,40 @@ static void wideline_line( struct draw_stage *stage,
}
+static void wideline_first_line( struct draw_stage *stage,
+ struct prim_header *header )
+{
+ struct draw_context *draw = stage->draw;
+ struct pipe_context *pipe = draw->pipe;
+ const struct pipe_rasterizer_state *rast = draw->rasterizer;
+ void *r;
+
+ /* Disable triangle culling, stippling, unfilled mode etc. */
+ r = draw_get_rasterizer_no_cull(draw, rast->scissor, rast->flatshade);
+ draw->suspend_flushing = TRUE;
+ pipe->bind_rasterizer_state(pipe, r);
+ draw->suspend_flushing = FALSE;
+
+ stage->line = wideline_line;
+
+ wideline_line(stage, header);
+}
+
+
static void wideline_flush( struct draw_stage *stage, unsigned flags )
{
+ struct draw_context *draw = stage->draw;
+ struct pipe_context *pipe = draw->pipe;
+
+ stage->line = wideline_first_line;
stage->next->flush( stage->next, flags );
+
+ /* restore original rasterizer state */
+ if (draw->rast_handle) {
+ draw->suspend_flushing = TRUE;
+ pipe->bind_rasterizer_state(pipe, draw->rast_handle);
+ draw->suspend_flushing = FALSE;
+ }
}
@@ -171,7 +203,7 @@ struct draw_stage *draw_wide_line_stage( struct draw_context *draw )
wide->stage.name = "wide-line";
wide->stage.next = NULL;
wide->stage.point = draw_pipe_passthrough_point;
- wide->stage.line = wideline_line;
+ wide->stage.line = wideline_first_line;
wide->stage.tri = draw_pipe_passthrough_tri;
wide->stage.flush = wideline_flush;
wide->stage.reset_stipple_counter = wideline_reset_stipple_counter;
diff --git a/src/gallium/auxiliary/draw/draw_pipe_wide_point.c b/src/gallium/auxiliary/draw/draw_pipe_wide_point.c
index 6864b4015b3..30116f4925f 100644
--- a/src/gallium/auxiliary/draw/draw_pipe_wide_point.c
+++ b/src/gallium/auxiliary/draw/draw_pipe_wide_point.c
@@ -52,6 +52,7 @@
*/
+#include "pipe/p_context.h"
#include "util/u_math.h"
#include "util/u_memory.h"
#include "pipe/p_defines.h"
@@ -216,33 +217,42 @@ static void widepoint_first_point( struct draw_stage *stage,
{
struct widepoint_stage *wide = widepoint_stage(stage);
struct draw_context *draw = stage->draw;
+ struct pipe_context *pipe = draw->pipe;
+ const struct pipe_rasterizer_state *rast = draw->rasterizer;
+ void *r;
- wide->half_point_size = 0.5f * draw->rasterizer->point_size;
+ wide->half_point_size = 0.5f * rast->point_size;
wide->xbias = 0.0;
wide->ybias = 0.0;
- if (draw->rasterizer->gl_rasterization_rules) {
+ if (rast->gl_rasterization_rules) {
wide->xbias = 0.125;
}
+ /* Disable triangle culling, stippling, unfilled mode etc. */
+ r = draw_get_rasterizer_no_cull(draw, rast->scissor, rast->flatshade);
+ draw->suspend_flushing = TRUE;
+ pipe->bind_rasterizer_state(pipe, r);
+ draw->suspend_flushing = FALSE;
+
/* XXX we won't know the real size if it's computed by the vertex shader! */
- if ((draw->rasterizer->point_size > draw->pipeline.wide_point_threshold) ||
- (draw->rasterizer->sprite_coord_enable && draw->pipeline.point_sprite)) {
+ if ((rast->point_size > draw->pipeline.wide_point_threshold) ||
+ (rast->sprite_coord_enable && draw->pipeline.point_sprite)) {
stage->point = widepoint_point;
}
else {
stage->point = draw_pipe_passthrough_point;
}
- if (draw->rasterizer->sprite_coord_enable) {
+ if (rast->sprite_coord_enable) {
/* find vertex shader texcoord outputs */
const struct draw_vertex_shader *vs = draw->vs.vertex_shader;
uint i, j = 0;
- wide->texcoord_mode = draw->rasterizer->sprite_coord_mode;
+ wide->texcoord_mode = rast->sprite_coord_mode;
for (i = 0; i < vs->info.num_outputs; i++) {
if (vs->info.output_semantic_name[i] == TGSI_SEMANTIC_GENERIC) {
wide->texcoord_slot[j] = i;
- wide->texcoord_enable[j] = (draw->rasterizer->sprite_coord_enable >> j) & 1;
+ wide->texcoord_enable[j] = (rast->sprite_coord_enable >> j) & 1;
j++;
}
}
@@ -262,7 +272,7 @@ static void widepoint_first_point( struct draw_stage *stage,
}
wide->psize_slot = -1;
- if (draw->rasterizer->point_size_per_vertex) {
+ if (rast->point_size_per_vertex) {
/* find PSIZ vertex output */
const struct draw_vertex_shader *vs = draw->vs.vertex_shader;
uint i;
@@ -280,9 +290,19 @@ static void widepoint_first_point( struct draw_stage *stage,
static void widepoint_flush( struct draw_stage *stage, unsigned flags )
{
+ struct draw_context *draw = stage->draw;
+ struct pipe_context *pipe = draw->pipe;
+
stage->point = widepoint_first_point;
stage->next->flush( stage->next, flags );
stage->draw->extra_shader_outputs.slot = 0;
+
+ /* restore original rasterizer state */
+ if (draw->rast_handle) {
+ draw->suspend_flushing = TRUE;
+ pipe->bind_rasterizer_state(pipe, draw->rast_handle);
+ draw->suspend_flushing = FALSE;
+ }
}
diff --git a/src/gallium/auxiliary/draw/draw_private.h b/src/gallium/auxiliary/draw/draw_private.h
index 33b0c196d4e..0b3c9e69bd5 100644
--- a/src/gallium/auxiliary/draw/draw_private.h
+++ b/src/gallium/auxiliary/draw/draw_private.h
@@ -86,6 +86,8 @@ struct vertex_header {
*/
struct draw_context
{
+ struct pipe_context *pipe;
+
/** Drawing/primitive pipeline stages */
struct {
struct draw_stage *first; /**< one of the following */
@@ -179,8 +181,14 @@ struct draw_context
double mrd; /**< minimum resolvable depth value, for polygon offset */
- /* pipe state that we need: */
+ /** Current rasterizer state given to us by the driver */
const struct pipe_rasterizer_state *rasterizer;
+ /** Driver CSO handle for the current rasterizer state */
+ void *rast_handle;
+
+ /** Rasterizer CSOs without culling/stipple/etc */
+ void *rasterizer_no_cull[2][2];
+
struct pipe_viewport_state viewport;
boolean identity_viewport;
@@ -244,6 +252,7 @@ struct draw_context
#ifdef HAVE_LLVM
LLVMExecutionEngineRef engine;
+ boolean use_llvm;
#endif
void *driver_private;
};
@@ -357,5 +366,10 @@ void draw_do_flush( struct draw_context *draw, unsigned flags );
+void *
+draw_get_rasterizer_no_cull( struct draw_context *draw,
+ boolean scissor,
+ boolean flatshade );
+
#endif /* DRAW_PRIVATE_H */
diff --git a/src/gallium/auxiliary/draw/draw_pt.c b/src/gallium/auxiliary/draw/draw_pt.c
index aa1f7064a3a..b5876bb1bdb 100644
--- a/src/gallium/auxiliary/draw/draw_pt.c
+++ b/src/gallium/auxiliary/draw/draw_pt.c
@@ -142,7 +142,9 @@ boolean draw_pt_init( struct draw_context *draw )
return FALSE;
#if HAVE_LLVM
- draw->pt.middle.general = draw_pt_fetch_pipeline_or_emit_llvm( draw );
+ draw->use_llvm = debug_get_bool_option("DRAW_USE_LLVM", TRUE);
+ if (draw->use_llvm)
+ draw->pt.middle.general = draw_pt_fetch_pipeline_or_emit_llvm( draw );
#else
draw->pt.middle.general = NULL;
#endif
diff --git a/src/gallium/auxiliary/gallivm/lp_bld_pack.c b/src/gallium/auxiliary/gallivm/lp_bld_pack.c
index 2daa8a3b582..186f8849b8d 100644
--- a/src/gallium/auxiliary/gallivm/lp_bld_pack.c
+++ b/src/gallium/auxiliary/gallivm/lp_bld_pack.c
@@ -263,8 +263,6 @@ lp_build_pack2(LLVMBuilderRef builder,
LLVMValueRef shuffle;
LLVMValueRef res;
- dst_vec_type = lp_build_vec_type(dst_type);
-
assert(!src_type.floating);
assert(!dst_type.floating);
assert(src_type.width == dst_type.width * 2);
diff --git a/src/gallium/auxiliary/gallivm/lp_bld_sample.h b/src/gallium/auxiliary/gallivm/lp_bld_sample.h
index 8c1af95c506..e2873763857 100644
--- a/src/gallium/auxiliary/gallivm/lp_bld_sample.h
+++ b/src/gallium/auxiliary/gallivm/lp_bld_sample.h
@@ -119,6 +119,11 @@ struct lp_sampler_dynamic_state
unsigned unit);
LLVMValueRef
+ (*img_stride)( struct lp_sampler_dynamic_state *state,
+ LLVMBuilderRef builder,
+ unsigned unit);
+
+ LLVMValueRef
(*data_ptr)( struct lp_sampler_dynamic_state *state,
LLVMBuilderRef builder,
unsigned unit);
diff --git a/src/gallium/auxiliary/gallivm/lp_bld_sample_soa.c b/src/gallium/auxiliary/gallivm/lp_bld_sample_soa.c
index 767429ba060..c9b613e21c8 100644
--- a/src/gallium/auxiliary/gallivm/lp_bld_sample_soa.c
+++ b/src/gallium/auxiliary/gallivm/lp_bld_sample_soa.c
@@ -1534,7 +1534,7 @@ lp_build_sample_general(struct lp_build_sample_context *bld,
LLVMValueRef height_vec,
LLVMValueRef depth_vec,
LLVMValueRef row_stride_array,
- LLVMValueRef img_stride_vec,
+ LLVMValueRef img_stride_array,
LLVMValueRef data_array,
LLVMValueRef *colors_out)
{
@@ -1602,8 +1602,9 @@ lp_build_sample_general(struct lp_build_sample_context *bld,
row_stride0_vec = lp_build_get_level_stride_vec(bld, row_stride_array,
ilevel0);
if (dims == 3 || bld->static_state->target == PIPE_TEXTURE_CUBE) {
- img_stride0_vec = lp_build_mul(&bld->int_coord_bld,
- row_stride0_vec, height0_vec);
+ img_stride0_vec = lp_build_get_level_stride_vec(bld,
+ img_stride_array,
+ ilevel0);
if (dims == 3) {
depth0_vec = lp_build_minify(bld, depth_vec, ilevel0_vec);
}
@@ -1617,8 +1618,9 @@ lp_build_sample_general(struct lp_build_sample_context *bld,
row_stride1_vec = lp_build_get_level_stride_vec(bld, row_stride_array,
ilevel1);
if (dims == 3 || bld->static_state->target == PIPE_TEXTURE_CUBE) {
- img_stride1_vec = lp_build_mul(&bld->int_coord_bld,
- row_stride1_vec, height1_vec);
+ img_stride1_vec = lp_build_get_level_stride_vec(bld,
+ img_stride_array,
+ ilevel1);
if (dims ==3) {
depth1_vec = lp_build_minify(bld, depth_vec, ilevel1_vec);
}
@@ -2002,7 +2004,7 @@ lp_build_sample_soa(LLVMBuilderRef builder,
LLVMValueRef width, width_vec;
LLVMValueRef height, height_vec;
LLVMValueRef depth, depth_vec;
- LLVMValueRef stride_array;
+ LLVMValueRef row_stride_array, img_stride_array;
LLVMValueRef data_array;
LLVMValueRef s;
LLVMValueRef t;
@@ -2033,7 +2035,8 @@ lp_build_sample_soa(LLVMBuilderRef builder,
width = dynamic_state->width(dynamic_state, builder, unit);
height = dynamic_state->height(dynamic_state, builder, unit);
depth = dynamic_state->depth(dynamic_state, builder, unit);
- stride_array = dynamic_state->row_stride(dynamic_state, builder, unit);
+ row_stride_array = dynamic_state->row_stride(dynamic_state, builder, unit);
+ img_stride_array = dynamic_state->img_stride(dynamic_state, builder, unit);
data_array = dynamic_state->data_ptr(dynamic_state, builder, unit);
/* Note that data_array is an array[level] of pointers to texture images */
@@ -2054,13 +2057,14 @@ lp_build_sample_soa(LLVMBuilderRef builder,
is_simple_wrap_mode(static_state->wrap_t)) {
/* special case */
lp_build_sample_2d_linear_aos(&bld, s, t, width_vec, height_vec,
- stride_array, data_array, texel);
+ row_stride_array, data_array, texel);
}
else {
lp_build_sample_general(&bld, unit, s, t, r,
width, height, depth,
width_vec, height_vec, depth_vec,
- stride_array, NULL, data_array,
+ row_stride_array, img_stride_array,
+ data_array,
texel);
}
diff --git a/src/gallium/auxiliary/tgsi/tgsi_exec.c b/src/gallium/auxiliary/tgsi/tgsi_exec.c
index f853ea2820e..11045e4ba2f 100644
--- a/src/gallium/auxiliary/tgsi/tgsi_exec.c
+++ b/src/gallium/auxiliary/tgsi/tgsi_exec.c
@@ -1796,6 +1796,12 @@ exec_declaration(struct tgsi_exec_machine *mach,
last = decl->Range.Last;
mask = decl->Declaration.UsageMask;
+ /* XXX we could remove this special-case code since
+ * mach->InterpCoefs[first].a0 should already have the
+ * front/back-face value. But we should first update the
+ * ureg code to emit the right UsageMask value (WRITEMASK_X).
+ * Then, we could remove the tgsi_exec_machine::Face field.
+ */
if (decl->Semantic.Name == TGSI_SEMANTIC_FACE) {
uint i;
diff --git a/src/gallium/auxiliary/tgsi/tgsi_ureg.c b/src/gallium/auxiliary/tgsi/tgsi_ureg.c
index 3d0455de7ce..f725405ade1 100644
--- a/src/gallium/auxiliary/tgsi/tgsi_ureg.c
+++ b/src/gallium/auxiliary/tgsi/tgsi_ureg.c
@@ -1158,7 +1158,7 @@ static void emit_decl_range( struct ureg_program *ureg,
out[0].decl.Type = TGSI_TOKEN_TYPE_DECLARATION;
out[0].decl.NrTokens = 2;
out[0].decl.File = file;
- out[0].decl.UsageMask = 0xf;
+ out[0].decl.UsageMask = TGSI_WRITEMASK_XYZW;
out[0].decl.Interpolate = TGSI_INTERPOLATE_CONSTANT;
out[0].decl.Semantic = 0;
@@ -1180,7 +1180,7 @@ emit_decl_range2D(struct ureg_program *ureg,
out[0].decl.Type = TGSI_TOKEN_TYPE_DECLARATION;
out[0].decl.NrTokens = 3;
out[0].decl.File = file;
- out[0].decl.UsageMask = 0xf;
+ out[0].decl.UsageMask = TGSI_WRITEMASK_XYZW;
out[0].decl.Interpolate = TGSI_INTERPOLATE_CONSTANT;
out[0].decl.Dimension = 1;
diff --git a/src/gallium/auxiliary/util/u_blit.c b/src/gallium/auxiliary/util/u_blit.c
index 7850f81e585..e45310b9bb7 100644
--- a/src/gallium/auxiliary/util/u_blit.c
+++ b/src/gallium/auxiliary/util/u_blit.c
@@ -374,6 +374,7 @@ util_blit_pixels_writemask(struct blit_state *ctx,
texTemp.width0 = srcW;
texTemp.height0 = srcH;
texTemp.depth0 = 1;
+ texTemp.bind = PIPE_BIND_SAMPLER_VIEW;
tex = screen->resource_create(screen, &texTemp);
if (!tex)
diff --git a/src/gallium/auxiliary/util/u_blitter.c b/src/gallium/auxiliary/util/u_blitter.c
index f3b42f7bf9c..956aedc8a15 100644
--- a/src/gallium/auxiliary/util/u_blitter.c
+++ b/src/gallium/auxiliary/util/u_blitter.c
@@ -132,6 +132,7 @@ struct blitter_context *util_blitter_create(struct pipe_context *pipe)
ctx->blitter.saved_fb_state.nr_cbufs = ~0;
ctx->blitter.saved_num_sampler_views = ~0;
ctx->blitter.saved_num_sampler_states = ~0;
+ ctx->blitter.saved_num_vertex_buffers = ~0;
/* blend state objects */
memset(&blend, 0, sizeof(blend));
@@ -318,6 +319,13 @@ static void blitter_restore_CSOs(struct blitter_context_priv *ctx)
ctx->blitter.saved_sampler_views);
ctx->blitter.saved_num_sampler_views = ~0;
}
+
+ if (ctx->blitter.saved_num_vertex_buffers != ~0) {
+ pipe->set_vertex_buffers(pipe,
+ ctx->blitter.saved_num_vertex_buffers,
+ ctx->blitter.saved_vertex_buffers);
+ ctx->blitter.saved_num_vertex_buffers = ~0;
+ }
}
static void blitter_set_rectangle(struct blitter_context_priv *ctx,
diff --git a/src/gallium/auxiliary/util/u_blitter.h b/src/gallium/auxiliary/util/u_blitter.h
index 2ad7201a29d..f6e3ce4874e 100644
--- a/src/gallium/auxiliary/util/u_blitter.h
+++ b/src/gallium/auxiliary/util/u_blitter.h
@@ -57,6 +57,9 @@ struct blitter_context
int saved_num_sampler_views;
struct pipe_sampler_view *saved_sampler_views[PIPE_MAX_SAMPLERS];
+
+ int saved_num_vertex_buffers;
+ struct pipe_vertex_buffer saved_vertex_buffers[PIPE_MAX_ATTRIBS];
};
/**
@@ -255,6 +258,19 @@ util_blitter_save_fragment_sampler_views(struct blitter_context *blitter,
num_views * sizeof(struct pipe_sampler_view *));
}
+static INLINE void
+util_blitter_save_vertex_buffers(struct blitter_context *blitter,
+ int num_vertex_buffers,
+ struct pipe_vertex_buffer *vertex_buffers)
+{
+ assert(num_vertex_buffers <= Elements(blitter->saved_vertex_buffers));
+
+ blitter->saved_num_vertex_buffers = num_vertex_buffers;
+ memcpy(blitter->saved_vertex_buffers,
+ vertex_buffers,
+ num_vertex_buffers * sizeof(struct pipe_vertex_buffer));
+}
+
#ifdef __cplusplus
}
#endif
diff --git a/src/gallium/auxiliary/util/u_dirty_surfaces.h b/src/gallium/auxiliary/util/u_dirty_surfaces.h
new file mode 100644
index 00000000000..99f260bf967
--- /dev/null
+++ b/src/gallium/auxiliary/util/u_dirty_surfaces.h
@@ -0,0 +1,88 @@
+#ifndef U_DIRTY_SURFACES_H_
+#define U_DIRTY_SURFACES_H_
+
+#include "util/u_double_list.h"
+#include "util/u_math.h"
+
+typedef void (*util_dirty_surface_flush_t) (struct pipe_context *, struct pipe_surface *);
+
+struct util_dirty_surfaces
+{
+ struct list_head dirty_list;
+};
+
+struct util_dirty_surface
+{
+ struct pipe_surface base;
+ struct list_head dirty_list;
+};
+
+static INLINE void
+util_dirty_surfaces_init(struct util_dirty_surfaces *ds)
+{
+ LIST_INITHEAD(&ds->dirty_list);
+}
+
+static INLINE void
+util_dirty_surfaces_use_for_sampling(struct pipe_context *pipe, struct util_dirty_surfaces *dss, util_dirty_surface_flush_t flush)
+{
+ struct list_head *p, *next;
+ for(p = dss->dirty_list.next; p != &dss->dirty_list; p = next)
+ {
+ struct util_dirty_surface *ds = LIST_ENTRY(struct util_dirty_surface, p, dirty_list);
+ next = p->next;
+
+ flush(pipe, &ds->base);
+ }
+}
+
+static INLINE void
+util_dirty_surfaces_use_levels_for_sampling(struct pipe_context *pipe, struct util_dirty_surfaces *dss, unsigned first, unsigned last, util_dirty_surface_flush_t flush)
+{
+ struct list_head *p, *next;
+ if(first > last)
+ return;
+ for(p = dss->dirty_list.next; p != &dss->dirty_list; p = next)
+ {
+ struct util_dirty_surface *ds = LIST_ENTRY(struct util_dirty_surface, p, dirty_list);
+ next = p->next;
+
+ if(ds->base.level >= first && ds->base.level <= last)
+ flush(pipe, &ds->base);
+ }
+}
+
+static INLINE void
+util_dirty_surfaces_use_for_sampling_with(struct pipe_context *pipe, struct util_dirty_surfaces *dss, struct pipe_sampler_view *psv, struct pipe_sampler_state *pss, util_dirty_surface_flush_t flush)
+{
+ if(!LIST_IS_EMPTY(&dss->dirty_list))
+ util_dirty_surfaces_use_levels_for_sampling(pipe, dss, (unsigned)pss->min_lod + psv->first_level, MIN2((unsigned)ceilf(pss->max_lod) + psv->first_level, psv->last_level), flush);
+}
+
+static INLINE void
+util_dirty_surface_init(struct util_dirty_surface *ds)
+{
+ LIST_INITHEAD(&ds->dirty_list);
+}
+
+static INLINE boolean
+util_dirty_surface_is_dirty(struct util_dirty_surface *ds)
+{
+ return !LIST_IS_EMPTY(&ds->dirty_list);
+}
+
+static INLINE void
+util_dirty_surface_set_dirty(struct util_dirty_surfaces *dss, struct util_dirty_surface *ds)
+{
+ if(LIST_IS_EMPTY(&ds->dirty_list))
+ LIST_ADDTAIL(&ds->dirty_list, &dss->dirty_list);
+}
+
+static INLINE void
+util_dirty_surface_set_clean(struct util_dirty_surfaces *dss, struct util_dirty_surface *ds)
+{
+ if(!LIST_IS_EMPTY(&ds->dirty_list))
+ LIST_DELINIT(&ds->dirty_list);
+}
+
+#endif
diff --git a/src/gallium/auxiliary/util/u_inlines.h b/src/gallium/auxiliary/util/u_inlines.h
index c2f4f05990b..089adcf3827 100644
--- a/src/gallium/auxiliary/util/u_inlines.h
+++ b/src/gallium/auxiliary/util/u_inlines.h
@@ -35,6 +35,7 @@
#include "util/u_debug.h"
#include "util/u_atomic.h"
#include "util/u_box.h"
+#include "util/u_math.h"
#ifdef __cplusplus
@@ -121,6 +122,28 @@ pipe_sampler_view_reference(struct pipe_sampler_view **ptr, struct pipe_sampler_
*ptr = view;
}
+static INLINE void
+pipe_surface_reset(struct pipe_surface* ps, struct pipe_resource *pt,
+ unsigned face, unsigned level, unsigned zslice, unsigned flags)
+{
+ pipe_resource_reference(&ps->texture, pt);
+ ps->format = pt->format;
+ ps->width = u_minify(pt->width0, level);
+ ps->height = u_minify(pt->height0, level);
+ ps->usage = flags;
+ ps->face = face;
+ ps->level = level;
+ ps->zslice = zslice;
+}
+
+static INLINE void
+pipe_surface_init(struct pipe_surface* ps, struct pipe_resource *pt,
+ unsigned face, unsigned level, unsigned zslice, unsigned flags)
+{
+ ps->texture = 0;
+ pipe_reference_init(&ps->reference, 1);
+ pipe_surface_reset(ps, pt, face, level, zslice, flags);
+}
/*
* Convenience wrappers for screen buffer functions.
diff --git a/src/gallium/auxiliary/util/u_surfaces.c b/src/gallium/auxiliary/util/u_surfaces.c
new file mode 100644
index 00000000000..0be4609a207
--- /dev/null
+++ b/src/gallium/auxiliary/util/u_surfaces.c
@@ -0,0 +1,112 @@
+#include "u_surfaces.h"
+#include "util/u_hash_table.h"
+#include "util/u_inlines.h"
+#include "util/u_memory.h"
+
+/* TODO: ouch, util_hash_table should do these by default when passed a null function pointer
+ * this indirect function call is quite bad
+ */
+static unsigned
+hash(void *key)
+{
+ return (unsigned)key;
+}
+
+static int
+compare(void *key1, void *key2)
+{
+ return (unsigned)key1 - (unsigned)key2;
+}
+
+struct pipe_surface *
+util_surfaces_do_get(struct util_surfaces *us, unsigned surface_struct_size, struct pipe_screen *pscreen, struct pipe_resource *pt, unsigned face, unsigned level, unsigned zslice, unsigned flags)
+{
+ struct pipe_surface *ps;
+ void *key = NULL;
+
+ if(pt->target == PIPE_TEXTURE_3D || pt->target == PIPE_TEXTURE_CUBE)
+ { /* or 2D array */
+ if(!us->u.table)
+ us->u.table = util_hash_table_create(hash, compare);
+ key = (void *)(((zslice + face) << 8) | level);
+ /* TODO: ouch, should have a get-reference function...
+ * also, shouldn't allocate a two-pointer structure for each item... */
+ ps = util_hash_table_get(us->u.table, key);
+ }
+ else
+ {
+ if(!us->u.array)
+ us->u.array = CALLOC(pt->last_level + 1, sizeof(struct pipe_surface *));
+ ps = us->u.array[level];
+ }
+
+ if(ps)
+ {
+ p_atomic_inc(&ps->reference.count);
+ return ps;
+ }
+
+ ps = (struct pipe_surface *)CALLOC(1, surface_struct_size);
+ if(!ps)
+ return NULL;
+
+ pipe_surface_init(ps, pt, face, level, zslice, flags);
+ ps->offset = ~0;
+
+ if(pt->target == PIPE_TEXTURE_3D || pt->target == PIPE_TEXTURE_CUBE)
+ util_hash_table_set(us->u.table, key, ps);
+ else
+ us->u.array[level] = ps;
+
+ return ps;
+}
+
+void
+util_surfaces_do_detach(struct util_surfaces *us, struct pipe_surface *ps)
+{
+ struct pipe_resource *pt = ps->texture;
+ if(pt->target == PIPE_TEXTURE_3D || pt->target == PIPE_TEXTURE_CUBE)
+ { /* or 2D array */
+ void* key = (void*)(((ps->zslice + ps->face) << 8) | ps->level);
+ util_hash_table_remove(us->u.table, key);
+ }
+ else
+ us->u.array[ps->level] = 0;
+}
+
+static enum pipe_error
+util_surfaces_destroy_callback(void *key, void *value, void *data)
+{
+ void (*destroy_surface) (struct pipe_surface * ps) = data;
+ destroy_surface((struct pipe_surface *)value);
+ return PIPE_OK;
+}
+
+void
+util_surfaces_destroy(struct util_surfaces *us, struct pipe_resource *pt, void (*destroy_surface) (struct pipe_surface *))
+{
+ if(pt->target == PIPE_TEXTURE_3D || pt->target == PIPE_TEXTURE_CUBE)
+ { /* or 2D array */
+ if(us->u.table)
+ {
+ util_hash_table_foreach(us->u.table, util_surfaces_destroy_callback, destroy_surface);
+ util_hash_table_destroy(us->u.table);
+ us->u.table = NULL;
+ }
+ }
+ else
+ {
+ if(us->u.array)
+ {
+ unsigned i;
+ for(i = 0; i < pt->last_level; ++i)
+ {
+ struct pipe_surface *ps = us->u.array[i];
+ if(ps)
+ destroy_surface(ps);
+ }
+ free(us->u.array);
+ us->u.array = NULL;
+ }
+ }
+}
diff --git a/src/gallium/auxiliary/util/u_surfaces.h b/src/gallium/auxiliary/util/u_surfaces.h
new file mode 100644
index 00000000000..6de5e7cc17e
--- /dev/null
+++ b/src/gallium/auxiliary/util/u_surfaces.h
@@ -0,0 +1,54 @@
+#ifndef U_SURFACES_H_
+#define U_SURFACES_H_
+
+#include "pipe/p_compiler.h"
+#include "pipe/p_state.h"
+#include "util/u_atomic.h"
+
+struct util_hash_table;
+
+struct util_surfaces
+{
+ union
+ {
+ struct util_hash_table *table;
+ struct pipe_surface **array;
+ } u;
+};
+
+struct pipe_surface *util_surfaces_do_get(struct util_surfaces *us, unsigned surface_struct_size, struct pipe_screen *pscreen, struct pipe_resource *pt, unsigned face, unsigned level, unsigned zslice, unsigned flags);
+
+/* fast inline path for the very common case */
+static INLINE struct pipe_surface *
+util_surfaces_get(struct util_surfaces *us, unsigned surface_struct_size, struct pipe_screen *pscreen, struct pipe_resource *pt, unsigned face, unsigned level, unsigned zslice, unsigned flags)
+{
+ if(likely(pt->target == PIPE_TEXTURE_2D && us->u.array))
+ {
+ struct pipe_surface *ps = us->u.array[level];
+ if(ps)
+ {
+ p_atomic_inc(&ps->reference.count);
+ return ps;
+ }
+ }
+
+ return util_surfaces_do_get(us, surface_struct_size, pscreen, pt, face, level, zslice, flags);
+}
+
+void util_surfaces_do_detach(struct util_surfaces *us, struct pipe_surface *ps);
+
+static INLINE void
+util_surfaces_detach(struct util_surfaces *us, struct pipe_surface *ps)
+{
+ if(likely(ps->texture->target == PIPE_TEXTURE_2D))
+ {
+ us->u.array[ps->level] = 0;
+ return;
+ }
+
+ return util_surfaces_do_detach(us, ps);
+}
+
+void util_surfaces_destroy(struct util_surfaces *us, struct pipe_resource *pt, void (*destroy_surface) (struct pipe_surface *));
+
+#endif