diff options
Diffstat (limited to 'src/gallium/auxiliary')
39 files changed, 2034 insertions, 590 deletions
diff --git a/src/gallium/auxiliary/draw/Makefile b/src/gallium/auxiliary/draw/Makefile index 28262a92c6..5ab3cfe5ce 100644 --- a/src/gallium/auxiliary/draw/Makefile +++ b/src/gallium/auxiliary/draw/Makefile @@ -19,6 +19,7 @@ C_SOURCES = \ draw_pt_vcache.c \ draw_pt_fetch_emit.c \ draw_pt_fetch_pipeline.c \ + draw_pt_fetch_shade_pipeline.c \ draw_pt_pipeline.c \ draw_pt_elts.c \ draw_prim.c \ diff --git a/src/gallium/auxiliary/draw/SConscript b/src/gallium/auxiliary/draw/SConscript index 52107912f5..a7fb5dbd61 100644 --- a/src/gallium/auxiliary/draw/SConscript +++ b/src/gallium/auxiliary/draw/SConscript @@ -18,6 +18,7 @@ draw = env.ConvenienceLibrary( 'draw_pt_vcache.c', 'draw_pt_fetch_emit.c', 'draw_pt_fetch_pipeline.c', + 'draw_pt_fetch_shade_pipeline.c', 'draw_pt_pipeline.c', 'draw_pt_elts.c', 'draw_prim.c', diff --git a/src/gallium/auxiliary/draw/draw_context.c b/src/gallium/auxiliary/draw/draw_context.c index b3c65c90d6..0c314f6e1d 100644 --- a/src/gallium/auxiliary/draw/draw_context.c +++ b/src/gallium/auxiliary/draw/draw_context.c @@ -49,6 +49,8 @@ struct draw_context *draw_create( void ) draw->use_sse = FALSE; #endif + draw->use_pt_shaders = GETENV( "GALLIUM_PT_SHADERS" ) != NULL; + /* create pipeline stages */ draw->pipeline.wide_line = draw_wide_line_stage( draw ); draw->pipeline.wide_point = draw_wide_point_stage( draw ); @@ -86,14 +88,11 @@ struct draw_context *draw_create( void ) /* Statically allocate maximum sized vertices for the cache - could be cleverer... */ { - uint i; - const unsigned size = (MAX_VERTEX_SIZE + 0x0f) & ~0x0f; - char *tmp = align_malloc(Elements(draw->vs.queue) * size, 16); + char *tmp = align_malloc(VS_QUEUE_LENGTH * MAX_VERTEX_ALLOCATION, 16); if (!tmp) goto fail; - for (i = 0; i < Elements(draw->vs.queue); i++) - draw->vs.queue[i].vertex = (struct vertex_header *)(tmp + i * size); + draw->vs.vertex_cache = tmp; } draw->shader_queue_flush = draw_vertex_shader_queue_flush; @@ -156,8 +155,8 @@ void draw_destroy( struct draw_context *draw ) tgsi_exec_machine_free_data(&draw->machine); - if (draw->vs.queue[0].vertex) - align_free( draw->vs.queue[0].vertex ); /* Frees all the vertices. */ + if (draw->vs.vertex_cache) + align_free( draw->vs.vertex_cache ); /* Frees all the vertices. */ /* Not so fast -- we're just borrowing this at the moment. * diff --git a/src/gallium/auxiliary/draw/draw_private.h b/src/gallium/auxiliary/draw/draw_private.h index 4d056f6dba..c8cb96c8ba 100644 --- a/src/gallium/auxiliary/draw/draw_private.h +++ b/src/gallium/auxiliary/draw/draw_private.h @@ -56,6 +56,8 @@ struct gallivm_cpu_engine; struct draw_pt_middle_end; struct draw_pt_front_end; +#define MAX_SHADER_VERTICES 128 + /** * Basic vertex info. * Carry some useful information around with the vertices in the prim pipe. @@ -76,6 +78,7 @@ struct vertex_header { /* XXX This is too large */ #define MAX_VERTEX_SIZE ((2 + PIPE_MAX_SHADER_OUTPUTS) * 4 * sizeof(float)) +#define MAX_VERTEX_ALLOCATION ((MAX_VERTEX_SIZE + 0x0f) & ~0x0f) @@ -146,12 +149,13 @@ struct draw_vertex_shader { /* Run the shader - this interface will get cleaned up in the * future: */ - void (*run)( struct draw_vertex_shader *shader, - struct draw_context *draw, - const unsigned *elts, - unsigned count, - struct vertex_header *vOut[] ); - + boolean (*run)( struct draw_vertex_shader *shader, + struct draw_context *draw, + const unsigned *elts, + unsigned count, + void *out, + unsigned vertex_size); + void (*delete)( struct draw_vertex_shader * ); }; @@ -274,6 +278,7 @@ struct draw_context boolean line_stipple; /**< do line stipple? */ boolean point_sprite; /**< convert points to quads for sprites? */ boolean use_sse; + boolean use_pt_shaders; /* temporary flag to switch on pt shader paths */ /* If a prim stage introduces new vertex attributes, they'll be stored here */ @@ -319,10 +324,8 @@ struct draw_context /* Vertex shader queue: */ struct { - struct { - unsigned elt; /**< index into the user's vertex arrays */ - struct vertex_header *vertex; - } queue[VS_QUEUE_LENGTH]; + unsigned elts[VS_QUEUE_LENGTH]; /**< index into the user's vertex arrays */ + char *vertex_cache; unsigned queue_nr; unsigned post_nr; } vs; @@ -448,4 +451,10 @@ dot4(const float *a, const float *b) return result; } +static INLINE struct vertex_header * +draw_header_from_block(char *block, int size, int num) +{ + return (struct vertex_header*)(block + num * size); +} + #endif /* DRAW_PRIVATE_H */ diff --git a/src/gallium/auxiliary/draw/draw_pt.c b/src/gallium/auxiliary/draw/draw_pt.c index f59fb86f78..3d2e7bf7b8 100644 --- a/src/gallium/auxiliary/draw/draw_pt.c +++ b/src/gallium/auxiliary/draw/draw_pt.c @@ -36,21 +36,25 @@ #include "draw/draw_pt.h" -/* XXX: Shouldn't those two functions below use the '>' operator??? - */ - -static boolean too_many_verts( struct draw_context *draw, - unsigned verts ) +#if 0 +static boolean too_many_elts( struct draw_context *draw, + unsigned elts ) { - return verts < 1024; + return elts > (8 * 1024); } +#endif -static boolean too_many_elts( struct draw_context *draw, - unsigned elts ) +static INLINE unsigned reduced_prim(unsigned prim) { - return elts < (16 * 1024); + /*FIXME*/ + return prim; } +static INLINE boolean good_prim(unsigned prim) +{ + /*FIXME*/ + return FALSE; +} boolean draw_pt_arrays(struct draw_context *draw, @@ -64,6 +68,9 @@ draw_pt_arrays(struct draw_context *draw, struct draw_pt_front_end *frontend = NULL; struct draw_pt_middle_end *middle = NULL; + if (!draw->render) + return FALSE; + /*debug_printf("XXXXXXXXXX needs_pipeline = %d\n", pipeline);*/ /* Overall we do: * - frontend -- prepare fetch_elts, draw_elts - eg vcache @@ -72,6 +79,9 @@ draw_pt_arrays(struct draw_context *draw, * - backend -- the vbuf_render provided by the driver. */ + if (shading && !draw->use_pt_shaders) + return FALSE; + if (!cliptest && !pipeline && !shading) { /* This is the 'passthrough' path: @@ -87,7 +97,6 @@ draw_pt_arrays(struct draw_context *draw, */ middle = draw->pt.middle.fetch_pipeline; } -#if 0 else if (!cliptest && !pipeline) { /* Fetch user verts, run vertex shader, emit hw verts: */ @@ -111,23 +120,15 @@ draw_pt_arrays(struct draw_context *draw, */ middle = draw->pt.middle.fetch_shade_cliptest_pipeline_or_emit; } - else if (!cliptest) { - /* Fetch user verts, run vertex shader, run pipeline: - */ - middle = draw->pt.middle.fetch_shade_pipeline; - } else { /* This is what we're currently always doing: */ - /* Fetch user verts, run vertex shader, cliptest, run pipeline: + /* Fetch user verts, run vertex shader, cliptest, run pipeline + * or + * Fetch user verts, run vertex shader, run pipeline */ - middle = draw->pt.middle.fetch_shade_cliptest_pipeline; - } -#else - else { - return FALSE; + middle = draw->pt.middle.fetch_shade_cliptest_pipeline_or_emit; } -#endif /* If !pipeline, need to make sure we respect the driver's limited @@ -143,7 +144,7 @@ draw_pt_arrays(struct draw_context *draw, frontend = draw->pt.front.vcache; hw_prim = reduced_prim(prim); } - +#if 0 if (too_many_verts(nr_verts)) { /* if (is_verts(draw) && can_split(prim)) { draw = draw_arrays_split; @@ -153,6 +154,7 @@ draw_pt_arrays(struct draw_context *draw, hw_prim = reduced_prim(prim); } } +#endif if (too_many_elts(count)) { @@ -166,17 +168,13 @@ draw_pt_arrays(struct draw_context *draw, } if (!good_prim(hw_prim)) { - draw = draw->pt.front.vcache; + frontend = draw->pt.front.vcache; } } #else frontend = draw->pt.front.vcache; #endif - /* XXX: need to flush to get prim_vbuf.c to release its allocation?? - */ - draw_do_flush( draw, DRAW_FLUSH_BACKEND ); - frontend->prepare( frontend, prim, middle ); frontend->run( frontend, @@ -200,6 +198,11 @@ boolean draw_pt_init( struct draw_context *draw ) if (!draw->pt.middle.fetch_pipeline) return FALSE; + draw->pt.middle.fetch_shade_cliptest_pipeline_or_emit = + draw_pt_fetch_pipeline_or_emit( draw ); + if (!draw->pt.middle.fetch_shade_cliptest_pipeline_or_emit) + return FALSE; + draw->pt.front.vcache = draw_pt_vcache( draw ); if (!draw->pt.front.vcache) return FALSE; @@ -220,6 +223,12 @@ void draw_pt_destroy( struct draw_context *draw ) draw->pt.middle.fetch_pipeline = NULL; } + if (draw->pt.middle.fetch_shade_cliptest_pipeline_or_emit) { + draw->pt.middle.fetch_shade_cliptest_pipeline_or_emit->destroy( + draw->pt.middle.fetch_shade_cliptest_pipeline_or_emit ); + draw->pt.middle.fetch_shade_cliptest_pipeline_or_emit = NULL; + } + if (draw->pt.front.vcache) { draw->pt.front.vcache->destroy( draw->pt.front.vcache ); draw->pt.front.vcache = NULL; diff --git a/src/gallium/auxiliary/draw/draw_pt.h b/src/gallium/auxiliary/draw/draw_pt.h index 590823fd33..48413b648a 100644 --- a/src/gallium/auxiliary/draw/draw_pt.h +++ b/src/gallium/auxiliary/draw/draw_pt.h @@ -123,7 +123,7 @@ const void *draw_pt_elt_ptr( struct draw_context *draw, struct draw_pt_front_end *draw_pt_vcache( struct draw_context *draw ); struct draw_pt_middle_end *draw_pt_fetch_emit( struct draw_context *draw ); struct draw_pt_middle_end *draw_pt_fetch_pipeline( struct draw_context *draw ); - +struct draw_pt_middle_end *draw_pt_fetch_pipeline_or_emit(struct draw_context *draw); #endif diff --git a/src/gallium/auxiliary/draw/draw_pt_fetch_emit.c b/src/gallium/auxiliary/draw/draw_pt_fetch_emit.c index 0806076956..3a26a5d712 100644 --- a/src/gallium/auxiliary/draw/draw_pt_fetch_emit.c +++ b/src/gallium/auxiliary/draw/draw_pt_fetch_emit.c @@ -145,7 +145,6 @@ fetch_store_general( struct fetch_emit_middle_end *feme, unsigned count ) { float *out = (float *)out_ptr; - struct vbuf_render *render = feme->draw->render; uint i, j; for (i = 0; i < count; i++) { @@ -167,7 +166,6 @@ fetch_store_general( struct fetch_emit_middle_end *feme, static void fetch_emit_prepare( struct draw_pt_middle_end *middle, unsigned prim ) { - static const float zero = 0; struct fetch_emit_middle_end *feme = (struct fetch_emit_middle_end *)middle; struct draw_context *draw = feme->draw; const struct vertex_info *vinfo; @@ -212,12 +210,6 @@ static void fetch_emit_prepare( struct draw_pt_middle_end *middle, case EMIT_1F: feme->fetch[i].emit = emit_R32_FLOAT; break; - case EMIT_HEADER: - feme->fetch[i].ptr = (const ubyte *)&zero; - feme->fetch[i].pitch = 0; - feme->fetch[i].fetch = fetch_R32_FLOAT; - feme->fetch[i].emit = emit_R32_FLOAT; - break; case EMIT_1F_PSIZE: feme->fetch[i].ptr = (const ubyte *)&feme->draw->rasterizer->point_size; feme->fetch[i].pitch = 0; @@ -249,6 +241,10 @@ static void fetch_emit_run( struct draw_pt_middle_end *middle, struct draw_context *draw = feme->draw; void *hw_verts; + /* XXX: need to flush to get prim_vbuf.c to release its allocation?? + */ + draw_do_flush( draw, DRAW_FLUSH_BACKEND ); + hw_verts = draw->render->allocate_vertices( draw->render, (ushort)feme->hw_vertex_size, (ushort)fetch_count ); diff --git a/src/gallium/auxiliary/draw/draw_pt_fetch_pipeline.c b/src/gallium/auxiliary/draw/draw_pt_fetch_pipeline.c index 4c2a281b29..a70d129c93 100644 --- a/src/gallium/auxiliary/draw/draw_pt_fetch_pipeline.c +++ b/src/gallium/auxiliary/draw/draw_pt_fetch_pipeline.c @@ -87,7 +87,7 @@ struct fetch_pipeline_middle_end { }; - +#if 0 static void emit_R32_FLOAT( const float *attrib, float **out ) { @@ -111,7 +111,7 @@ static void emit_R32G32B32_FLOAT( const float *attrib, (*out)[2] = attrib[2]; (*out) += 3; } - +#endif static void emit_R32G32B32A32_FLOAT( const float *attrib, float **out ) { @@ -211,7 +211,6 @@ fetch_store_general( struct fetch_pipeline_middle_end *fpme, static void fetch_pipeline_prepare( struct draw_pt_middle_end *middle, unsigned prim ) { - static const float zero = 0; struct fetch_pipeline_middle_end *fpme = (struct fetch_pipeline_middle_end *)middle; struct draw_context *draw = fpme->draw; unsigned i, nr = 0; @@ -264,7 +263,6 @@ static void fetch_pipeline_run( struct draw_pt_middle_end *middle, unsigned draw_count ) { struct fetch_pipeline_middle_end *fpme = (struct fetch_pipeline_middle_end *)middle; - struct draw_context *draw = fpme->draw; char *pipeline_verts; pipeline_verts = MALLOC( fpme->pipeline_vertex_size * diff --git a/src/gallium/auxiliary/draw/draw_pt_fetch_shade_pipeline.c b/src/gallium/auxiliary/draw/draw_pt_fetch_shade_pipeline.c new file mode 100644 index 0000000000..04b3d2c4cf --- /dev/null +++ b/src/gallium/auxiliary/draw/draw_pt_fetch_shade_pipeline.c @@ -0,0 +1,243 @@ +/************************************************************************** + * + * 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. + * + **************************************************************************/ + +#include "pipe/p_util.h" +#include "draw/draw_context.h" +#include "draw/draw_private.h" +#include "draw/draw_vbuf.h" +#include "draw/draw_vertex.h" +#include "draw/draw_pt.h" + +struct fetch_pipeline_middle_end { + struct draw_pt_middle_end base; + struct draw_context *draw; + + struct { + const ubyte *ptr; + unsigned pitch; + void (*fetch)( const void *from, float *attrib); + void (*emit)( const float *attrib, float **out ); + } fetch[PIPE_MAX_ATTRIBS]; + + unsigned nr_fetch; + unsigned pipeline_vertex_size; + unsigned hw_vertex_size; + unsigned prim; +}; + +#if 0 +static void emit_R32_FLOAT( const float *attrib, + float **out ) +{ + (*out)[0] = attrib[0]; + (*out) += 1; +} + +static void emit_R32G32_FLOAT( const float *attrib, + float **out ) +{ + (*out)[0] = attrib[0]; + (*out)[1] = attrib[1]; + (*out) += 2; +} + +static void emit_R32G32B32_FLOAT( const float *attrib, + float **out ) +{ + (*out)[0] = attrib[0]; + (*out)[1] = attrib[1]; + (*out)[2] = attrib[2]; + (*out) += 3; +} +#endif +static void emit_R32G32B32A32_FLOAT( const float *attrib, + float **out ) +{ + (*out)[0] = attrib[0]; + (*out)[1] = attrib[1]; + (*out)[2] = attrib[2]; + (*out)[3] = attrib[3]; + (*out) += 4; +} + +static void fetch_pipeline_prepare( struct draw_pt_middle_end *middle, + unsigned prim ) +{ + struct fetch_pipeline_middle_end *fpme = (struct fetch_pipeline_middle_end *)middle; + struct draw_context *draw = fpme->draw; + unsigned i, nr = 0; + boolean ok; + const struct vertex_info *vinfo; + + fpme->prim = prim; + + ok = draw->render->set_primitive(draw->render, prim); + if (!ok) { + assert(0); + return; + } + /* Must do this after set_primitive() above: + */ + vinfo = draw->render->get_vertex_info(draw->render); + + /* Need to look at vertex shader inputs (we know it is a + * passthrough shader, so these define the outputs too). If we + * were running a shader, we'd still be looking at the inputs at + * this point. + */ + for (i = 0; i < draw->vertex_shader->info.num_inputs; i++) { + unsigned buf = draw->vertex_element[i].vertex_buffer_index; + enum pipe_format format = draw->vertex_element[i].src_format; + + fpme->fetch[nr].ptr = ((const ubyte *) draw->user.vbuffer[buf] + + draw->vertex_buffer[buf].buffer_offset + + draw->vertex_element[i].src_offset); + + fpme->fetch[nr].pitch = draw->vertex_buffer[buf].pitch; + fpme->fetch[nr].fetch = draw_get_fetch_func( format ); + + /* Always do this -- somewhat redundant... + */ + fpme->fetch[nr].emit = emit_R32G32B32A32_FLOAT; + nr++; + } + + fpme->nr_fetch = nr; + //fpme->pipeline_vertex_size = sizeof(struct vertex_header) + nr * 4 * sizeof(float); + fpme->pipeline_vertex_size = MAX_VERTEX_ALLOCATION; + fpme->hw_vertex_size = vinfo->size * 4; +} + + + + +static void fetch_pipeline_run( struct draw_pt_middle_end *middle, + const unsigned *fetch_elts, + unsigned fetch_count, + const ushort *draw_elts, + unsigned draw_count ) +{ + struct fetch_pipeline_middle_end *fpme = (struct fetch_pipeline_middle_end *)middle; + struct draw_context *draw = fpme->draw; + struct draw_vertex_shader *shader = draw->vertex_shader; + char *pipeline_verts; + + pipeline_verts = MALLOC(fpme->pipeline_vertex_size * + fetch_count); + + if (!pipeline_verts) { + assert(0); + return; + } + + + /* Shade + */ + shader->prepare(shader, draw); + if (shader->run(shader, draw, fetch_elts, fetch_count, pipeline_verts, + fpme->pipeline_vertex_size)) { + /* Run the pipeline */ + draw_pt_run_pipeline( fpme->draw, + fpme->prim, + pipeline_verts, + fpme->pipeline_vertex_size, + fetch_count, + draw_elts, + draw_count ); + } else { + unsigned i, j; + void *hw_verts; + float *out; + + /* XXX: need to flush to get prim_vbuf.c to release its allocation?? + */ + draw_do_flush( draw, DRAW_FLUSH_BACKEND ); + + hw_verts = draw->render->allocate_vertices(draw->render, + (ushort)fpme->hw_vertex_size, + (ushort)fetch_count); + if (!hw_verts) { + assert(0); + return; + } + + out = (float *)hw_verts; + for (i = 0; i < fetch_count; i++) { + struct vertex_header *header = + (struct vertex_header*)(pipeline_verts + (fpme->pipeline_vertex_size * i)); + + for (j = 0; j < fpme->nr_fetch; j++) { + float *attrib = header->data[j]; + /*debug_printf("emiting [%f, %f, %f, %f]\n", + attrib[0], attrib[1], + attrib[2], attrib[3]);*/ + fpme->fetch[j].emit(attrib, &out); + } + } + /* XXX: Draw arrays path to avoid re-emitting index list again and + * again. + */ + draw->render->draw(draw->render, + draw_elts, + draw_count); + + draw->render->release_vertices(draw->render, + hw_verts, + fpme->hw_vertex_size, + fetch_count); + } + + + FREE(pipeline_verts); +} + + + +static void fetch_pipeline_finish( struct draw_pt_middle_end *middle ) +{ + /* nothing to do */ +} + +static void fetch_pipeline_destroy( struct draw_pt_middle_end *middle ) +{ + FREE(middle); +} + + +struct draw_pt_middle_end *draw_pt_fetch_pipeline_or_emit( struct draw_context *draw ) +{ + struct fetch_pipeline_middle_end *fetch_pipeline = CALLOC_STRUCT( fetch_pipeline_middle_end ); + + fetch_pipeline->base.prepare = fetch_pipeline_prepare; + fetch_pipeline->base.run = fetch_pipeline_run; + fetch_pipeline->base.finish = fetch_pipeline_finish; + fetch_pipeline->base.destroy = fetch_pipeline_destroy; + + fetch_pipeline->draw = draw; + + return &fetch_pipeline->base; +} diff --git a/src/gallium/auxiliary/draw/draw_vbuf.c b/src/gallium/auxiliary/draw/draw_vbuf.c index f83b441e93..e3216ff711 100644 --- a/src/gallium/auxiliary/draw/draw_vbuf.c +++ b/src/gallium/auxiliary/draw/draw_vbuf.c @@ -126,13 +126,6 @@ dump_emitted_vertex(const struct vertex_info *vinfo, const uint8_t *data) case EMIT_OMIT: debug_printf("EMIT_OMIT:"); break; - case EMIT_ALL: - assert(i == 0); - assert(j == 0); - debug_printf("EMIT_ALL:\t"); - for(k = 0; k < vinfo->size*4; ++k) - debug_printf("%02x ", *data++); - break; case EMIT_1F: debug_printf("EMIT_1F:\t"); debug_printf("%f ", *(float *)data); data += sizeof(float); @@ -217,19 +210,6 @@ emit_vertex( struct vbuf_stage *vbuf, case EMIT_OMIT: /* no-op */ break; - case EMIT_ALL: - /* just copy the whole vertex as-is to the vbuf */ - assert(i == 0); - assert(j == 0); - memcpy(vbuf->vertex_ptr, vertex, vinfo->size * 4); - vbuf->vertex_ptr += vinfo->size; - count += vinfo->size; - break; - case EMIT_HEADER: - memcpy(vbuf->vertex_ptr, vertex, sizeof(*vertex)); - *vbuf->vertex_ptr += sizeof(*vertex) / 4; - count += sizeof(*vertex) / 4; - break; case EMIT_1F: *vbuf->vertex_ptr++ = fui(vertex->data[j][0]); count++; diff --git a/src/gallium/auxiliary/draw/draw_vertex.c b/src/gallium/auxiliary/draw/draw_vertex.c index 970adc95e7..168036eee8 100644 --- a/src/gallium/auxiliary/draw/draw_vertex.c +++ b/src/gallium/auxiliary/draw/draw_vertex.c @@ -52,9 +52,6 @@ draw_compute_vertex_size(struct vertex_info *vinfo) switch (vinfo->emit[i]) { case EMIT_OMIT: break; - case EMIT_HEADER: - vinfo->size += sizeof(struct vertex_header) / 4; - break; case EMIT_4UB: /* fall-through */ case EMIT_1F_PSIZE: @@ -71,8 +68,6 @@ draw_compute_vertex_size(struct vertex_info *vinfo) case EMIT_4F: vinfo->size += 4; break; - case EMIT_ALL: - /* fall-through */ default: assert(0); } diff --git a/src/gallium/auxiliary/draw/draw_vertex.h b/src/gallium/auxiliary/draw/draw_vertex.h index abd2017ed3..65818463ca 100644 --- a/src/gallium/auxiliary/draw/draw_vertex.h +++ b/src/gallium/auxiliary/draw/draw_vertex.h @@ -47,8 +47,6 @@ */ enum attrib_emit { EMIT_OMIT, /**< don't emit the attribute */ - EMIT_ALL, /**< emit whole post-xform vertex, w/ header */ - EMIT_HEADER, /**< emit vertex_header struct (XXX temp?) */ EMIT_1F, EMIT_1F_PSIZE, /**< insert constant point size */ EMIT_2F, diff --git a/src/gallium/auxiliary/draw/draw_vertex_cache.c b/src/gallium/auxiliary/draw/draw_vertex_cache.c index c0248979e2..730c18bcb3 100644 --- a/src/gallium/auxiliary/draw/draw_vertex_cache.c +++ b/src/gallium/auxiliary/draw/draw_vertex_cache.c @@ -71,25 +71,28 @@ static struct vertex_header *get_vertex( struct draw_context *draw, /* Cache hit? */ if (draw->vcache.idx[slot].in == i) { -// _mesa_printf("HIT %d %d\n", slot, i); + /*debug_printf("HIT %d %d\n", slot, i);*/ assert(draw->vcache.idx[slot].out < draw->vs.queue_nr); - return draw->vs.queue[draw->vcache.idx[slot].out].vertex; + return draw_header_from_block(draw->vs.vertex_cache, + MAX_VERTEX_ALLOCATION, + draw->vcache.idx[slot].out); } /* Otherwise a collision */ slot = VCACHE_SIZE + draw->vcache.overflow++; -// _mesa_printf("XXX %d --> %d\n", i, slot); + /*debug_printf("XXX %d --> %d\n", i, slot);*/ } /* Deal with the cache miss: */ { unsigned out; - + struct vertex_header *header; + assert(slot < Elements(draw->vcache.idx)); -// _mesa_printf("NEW %d %d\n", slot, i); + /*debug_printf("NEW %d %d\n", slot, i);*/ draw->vcache.idx[slot].in = i; draw->vcache.idx[slot].out = out = draw->vs.queue_nr++; draw->vcache.referenced |= (1 << slot); @@ -99,17 +102,21 @@ static struct vertex_header *get_vertex( struct draw_context *draw, */ assert(draw->vs.queue_nr < VS_QUEUE_LENGTH); - draw->vs.queue[out].elt = i; - draw->vs.queue[out].vertex->clipmask = 0; - draw->vs.queue[out].vertex->edgeflag = draw_get_edgeflag(draw, i); - draw->vs.queue[out].vertex->pad = 0; - draw->vs.queue[out].vertex->vertex_id = UNDEFINED_VERTEX_ID; + header = draw_header_from_block(draw->vs.vertex_cache, MAX_VERTEX_ALLOCATION, + out); + draw->vs.elts[out] = i; + header->clipmask = 0; + header->edgeflag = draw_get_edgeflag(draw, i); + header->pad = 0; + header->vertex_id = UNDEFINED_VERTEX_ID; /* Need to set the vertex's edge flag here. If we're being called * by do_ef_triangle(), that function needs edge flag info! */ - return draw->vs.queue[draw->vcache.idx[slot].out].vertex; + return draw_header_from_block(draw->vs.vertex_cache, + MAX_VERTEX_ALLOCATION, + draw->vcache.idx[slot].out); } } @@ -142,8 +149,12 @@ void draw_vertex_cache_reset_vertex_ids( struct draw_context *draw ) { unsigned i; - for (i = 0; i < draw->vs.post_nr; i++) - draw->vs.queue[i].vertex->vertex_id = UNDEFINED_VERTEX_ID; + for (i = 0; i < draw->vs.post_nr; i++) { + struct vertex_header * header = + draw_header_from_block(draw->vs.vertex_cache, + MAX_VERTEX_ALLOCATION, i); + header->vertex_id = UNDEFINED_VERTEX_ID; + } } diff --git a/src/gallium/auxiliary/draw/draw_vertex_shader.c b/src/gallium/auxiliary/draw/draw_vertex_shader.c index 133418baca..8572a6d40c 100644 --- a/src/gallium/auxiliary/draw/draw_vertex_shader.c +++ b/src/gallium/auxiliary/draw/draw_vertex_shader.c @@ -37,8 +37,6 @@ #include "draw_context.h" #include "draw_vs.h" - - /** * Run the vertex shader on all vertices in the vertex queue. * Called by the draw module when the vertx cache needs to be flushed. @@ -58,25 +56,25 @@ draw_vertex_shader_queue_flush(struct draw_context *draw) // fprintf(stderr, "%s %d\n", __FUNCTION__, draw->vs.queue_nr ); /* run vertex shader on vertex cache entries, four per invokation */ - for (i = 0; i < draw->vs.queue_nr; i += 4) { - struct vertex_header *dests[4]; - unsigned elts[4]; - int j, n = MIN2(4, draw->vs.queue_nr - i); + for (i = 0; i < draw->vs.queue_nr; i += MAX_SHADER_VERTICES) { + unsigned elts[MAX_SHADER_VERTICES]; + int j, n = MIN2(MAX_SHADER_VERTICES, draw->vs.queue_nr - i); + struct vertex_header *dests = + draw_header_from_block(draw->vs.vertex_cache, + MAX_VERTEX_ALLOCATION, i); for (j = 0; j < n; j++) { - elts[j] = draw->vs.queue[i + j].elt; - dests[j] = draw->vs.queue[i + j].vertex; + elts[j] = draw->vs.elts[i + j]; } - for ( ; j < 4; j++) { + for ( ; j < MAX_SHADER_VERTICES; j++) { elts[j] = elts[0]; - dests[j] = draw->vs.queue[i + j].vertex; } assert(n > 0); - assert(n <= 4); + assert(n <= MAX_SHADER_VERTICES); - shader->run(shader, draw, elts, n, dests); + shader->run(shader, draw, elts, n, dests, MAX_VERTEX_ALLOCATION); } draw->vs.post_nr = draw->vs.queue_nr; diff --git a/src/gallium/auxiliary/draw/draw_vf.c b/src/gallium/auxiliary/draw/draw_vf.c index 7bb34ace7a..9d0154c50d 100644 --- a/src/gallium/auxiliary/draw/draw_vf.c +++ b/src/gallium/auxiliary/draw/draw_vf.c @@ -205,7 +205,7 @@ void draw_vf_set_vertex_info( struct draw_vertex_fetch *vf, const struct vertex_info *vinfo, float point_size ) { - unsigned i, j, k; + unsigned i, j; struct draw_vf_attr *a = vf->attr; struct draw_vf_attr_map attrs[PIPE_MAX_SHADER_INPUTS]; unsigned count = 0; /* for debug/sanity */ @@ -217,60 +217,6 @@ void draw_vf_set_vertex_info( struct draw_vertex_fetch *vf, case EMIT_OMIT: /* no-op */ break; - case EMIT_ALL: { - /* just copy the whole vertex as-is to the vbuf */ - unsigned s = vinfo->size; - assert(i == 0); - assert(j == 0); - /* copy the vertex header */ - /* XXX: we actually don't copy the header, just pad it */ - attrs[nr_attrs].attrib = 0; - attrs[nr_attrs].format = DRAW_EMIT_PAD; - attrs[nr_attrs].offset = offsetof(struct vertex_header, data); - s -= offsetof(struct vertex_header, data)/4; - count += offsetof(struct vertex_header, data)/4; - nr_attrs++; - /* copy the vertex data */ - for(k = 0; k < (s & ~0x3); k += 4) { - attrs[nr_attrs].attrib = k/4; - attrs[nr_attrs].format = DRAW_EMIT_4F; - attrs[nr_attrs].offset = 0; - nr_attrs++; - count += 4; - } - /* tail */ - /* XXX: actually, this shouldn't be needed */ - attrs[nr_attrs].attrib = k/4; - attrs[nr_attrs].offset = 0; - switch(s & 0x3) { - case 0: - break; - case 1: - attrs[nr_attrs].format = DRAW_EMIT_1F; - nr_attrs++; - count += 1; - break; - case 2: - attrs[nr_attrs].format = DRAW_EMIT_2F; - nr_attrs++; - count += 2; - break; - case 3: - attrs[nr_attrs].format = DRAW_EMIT_3F; - nr_attrs++; - count += 3; - break; - } - break; - } - case EMIT_HEADER: - /* XXX emit new DRAW_EMIT_HEADER attribute??? */ - attrs[nr_attrs].attrib = 0; - attrs[nr_attrs].format = DRAW_EMIT_PAD; - attrs[nr_attrs].offset = offsetof(struct vertex_header, data); - count += offsetof(struct vertex_header, data)/4; - nr_attrs++; - break; case EMIT_1F: attrs[nr_attrs].attrib = j; attrs[nr_attrs].format = DRAW_EMIT_1F; diff --git a/src/gallium/auxiliary/draw/draw_vf.h b/src/gallium/auxiliary/draw/draw_vf.h index 7555d1bd58..0ef98d6257 100644 --- a/src/gallium/auxiliary/draw/draw_vf.h +++ b/src/gallium/auxiliary/draw/draw_vf.h @@ -128,9 +128,6 @@ draw_vf_destroy( struct draw_vertex_fetch *vf ); struct draw_vf_attr; -typedef void (*draw_vf_extract_func)( const struct draw_vf_attr *a, - float *out, - const uint8_t *v ); typedef void (*draw_vf_insert_func)( const struct draw_vf_attr *a, uint8_t *v, @@ -164,7 +161,6 @@ struct draw_vf_attr uint8_t *inputptr; const draw_vf_insert_func *insert; draw_vf_insert_func do_insert; - draw_vf_extract_func extract; }; struct draw_vertex_fetch diff --git a/src/gallium/auxiliary/draw/draw_vs.h b/src/gallium/auxiliary/draw/draw_vs.h index 4ee7e705e9..33ce1e335e 100644 --- a/src/gallium/auxiliary/draw/draw_vs.h +++ b/src/gallium/auxiliary/draw/draw_vs.h @@ -31,6 +31,10 @@ #ifndef DRAW_VS_H #define DRAW_VS_H +#include "draw_context.h" +#include "draw_private.h" + + struct draw_vertex_shader; struct draw_context; struct pipe_shader_state; @@ -47,4 +51,33 @@ struct draw_vertex_shader * draw_create_vs_llvm(struct draw_context *draw, const struct pipe_shader_state *templ); + +/* Should be part of the generated shader: + */ +static INLINE unsigned +compute_clipmask(const float *clip, /*const*/ float plane[][4], unsigned nr) +{ + unsigned mask = 0x0; + unsigned i; + + /* Do the hardwired planes first: + */ + if (-clip[0] + clip[3] < 0) mask |= CLIP_RIGHT_BIT; + if ( clip[0] + clip[3] < 0) mask |= CLIP_LEFT_BIT; + if (-clip[1] + clip[3] < 0) mask |= CLIP_TOP_BIT; + if ( clip[1] + clip[3] < 0) mask |= CLIP_BOTTOM_BIT; + if (-clip[2] + clip[3] < 0) mask |= CLIP_FAR_BIT; + if ( clip[2] + clip[3] < 0) mask |= CLIP_NEAR_BIT; + + /* Followed by any remaining ones: + */ + for (i = 6; i < nr; i++) { + if (dot4(clip, plane[i]) < 0) + mask |= (1<<i); + } + + return mask; +} + + #endif diff --git a/src/gallium/auxiliary/draw/draw_vs_exec.c b/src/gallium/auxiliary/draw/draw_vs_exec.c index c6e503686a..5c88c2e24e 100644 --- a/src/gallium/auxiliary/draw/draw_vs_exec.c +++ b/src/gallium/auxiliary/draw/draw_vs_exec.c @@ -40,32 +40,7 @@ #include "tgsi/util/tgsi_parse.h" - -static INLINE unsigned -compute_clipmask(const float *clip, /*const*/ float plane[][4], unsigned nr) -{ - unsigned mask = 0; - unsigned i; - - /* Do the hardwired planes first: - */ - if (-clip[0] + clip[3] < 0) mask |= CLIP_RIGHT_BIT; - if ( clip[0] + clip[3] < 0) mask |= CLIP_LEFT_BIT; - if (-clip[1] + clip[3] < 0) mask |= CLIP_TOP_BIT; - if ( clip[1] + clip[3] < 0) mask |= CLIP_BOTTOM_BIT; - if (-clip[2] + clip[3] < 0) mask |= CLIP_FAR_BIT; - if ( clip[2] + clip[3] < 0) mask |= CLIP_NEAR_BIT; - - /* Followed by any remaining ones: - */ - for (i = 6; i < nr; i++) { - if (dot4(clip, plane[i]) < 0) - mask |= (1<<i); - } - - return mask; -} - +#define MAX_TGSI_VERTICES 4 static void vs_exec_prepare( struct draw_vertex_shader *shader, @@ -89,22 +64,23 @@ vs_exec_prepare( struct draw_vertex_shader *shader, * \param count number of vertices to shade [1..4] * \param vOut array of pointers to four output vertices */ -static void +static boolean vs_exec_run( struct draw_vertex_shader *shader, struct draw_context *draw, const unsigned *elts, unsigned count, - struct vertex_header *vOut[] ) + void *vOut, + unsigned vertex_size) { struct tgsi_exec_machine *machine = &draw->machine; - unsigned int j; + unsigned int i, j; + unsigned int clipped = 0; ALIGN16_DECL(struct tgsi_exec_vector, inputs, PIPE_MAX_ATTRIBS); ALIGN16_DECL(struct tgsi_exec_vector, outputs, PIPE_MAX_ATTRIBS); const float *scale = draw->viewport.scale; const float *trans = draw->viewport.translate; - assert(count <= 4); assert(draw->vertex_shader->info.output_semantic_name[0] == TGSI_SEMANTIC_POSITION); @@ -118,80 +94,87 @@ vs_exec_run( struct draw_vertex_shader *shader, machine->Outputs = ALIGN16_ASSIGN(outputs); } - draw->vertex_fetch.fetch_func( draw, machine, elts, count ); - - if (!draw->rasterizer->bypass_vs) { - /* run interpreter */ - tgsi_exec_machine_run( machine ); - } + for (i = 0; i < count; i += MAX_TGSI_VERTICES) { + unsigned int max_vertices = MIN2(MAX_TGSI_VERTICES, count - i); + draw->vertex_fetch.fetch_func( draw, machine, &elts[i], max_vertices ); - /* store machine results */ - for (j = 0; j < count; j++) { - unsigned slot; - float x, y, z, w; - - /* Handle attr[0] (position) specially: - * - * XXX: Computing the clipmask should be done in the vertex - * program as a set of DP4 instructions appended to the - * user-provided code. - */ - x = vOut[j]->clip[0] = machine->Outputs[0].xyzw[0].f[j]; - y = vOut[j]->clip[1] = machine->Outputs[0].xyzw[1].f[j]; - z = vOut[j]->clip[2] = machine->Outputs[0].xyzw[2].f[j]; - w = vOut[j]->clip[3] = machine->Outputs[0].xyzw[3].f[j]; - - if (!draw->rasterizer->bypass_clipping) { - vOut[j]->clipmask = compute_clipmask(vOut[j]->clip, draw->plane, draw->nr_planes); - - /* divide by w */ - w = 1.0f / w; - x *= w; - y *= w; - z *= w; - } - else { - vOut[j]->clipmask = 0; - } - vOut[j]->edgeflag = 1; - - if (!draw->identity_viewport) { - /* Viewport mapping */ - vOut[j]->data[0][0] = x * scale[0] + trans[0]; - vOut[j]->data[0][1] = y * scale[1] + trans[1]; - vOut[j]->data[0][2] = z * scale[2] + trans[2]; - vOut[j]->data[0][3] = w; - } - else { - vOut[j]->data[0][0] = x; - vOut[j]->data[0][1] = y; - vOut[j]->data[0][2] = z; - vOut[j]->data[0][3] = w; + if (!draw->rasterizer->bypass_vs) { + /* run interpreter */ + tgsi_exec_machine_run( machine ); } - /* Remaining attributes are packed into sequential post-transform - * vertex attrib slots. - */ - for (slot = 1; slot < draw->num_vs_outputs; slot++) { - vOut[j]->data[slot][0] = machine->Outputs[slot].xyzw[0].f[j]; - vOut[j]->data[slot][1] = machine->Outputs[slot].xyzw[1].f[j]; - vOut[j]->data[slot][2] = machine->Outputs[slot].xyzw[2].f[j]; - vOut[j]->data[slot][3] = machine->Outputs[slot].xyzw[3].f[j]; - } + /* store machine results */ + for (j = 0; j < max_vertices; j++) { + unsigned slot; + float x, y, z, w; + struct vertex_header *out = + draw_header_from_block(vOut, vertex_size, i + j); + + /* Handle attr[0] (position) specially: + * + * XXX: Computing the clipmask should be done in the vertex + * program as a set of DP4 instructions appended to the + * user-provided code. + */ + x = out->clip[0] = machine->Outputs[0].xyzw[0].f[j]; + y = out->clip[1] = machine->Outputs[0].xyzw[1].f[j]; + z = out->clip[2] = machine->Outputs[0].xyzw[2].f[j]; + w = out->clip[3] = machine->Outputs[0].xyzw[3].f[j]; + + if (!draw->rasterizer->bypass_clipping) { + out->clipmask = compute_clipmask(out->clip, draw->plane, + draw->nr_planes); + clipped += out->clipmask; + + /* divide by w */ + w = 1.0f / w; + x *= w; + y *= w; + z *= w; + } + else { + out->clipmask = 0; + } + out->edgeflag = 1; + out->vertex_id = UNDEFINED_VERTEX_ID; + + if (!draw->identity_viewport) { + /* Viewport mapping */ + out->data[0][0] = x * scale[0] + trans[0]; + out->data[0][1] = y * scale[1] + trans[1]; + out->data[0][2] = z * scale[2] + trans[2]; + out->data[0][3] = w; + } + else { + out->data[0][0] = x; + out->data[0][1] = y; + out->data[0][2] = z; + out->data[0][3] = w; + } + + /* Remaining attributes are packed into sequential post-transform + * vertex attrib slots. + */ + for (slot = 1; slot < draw->num_vs_outputs; slot++) { + out->data[slot][0] = machine->Outputs[slot].xyzw[0].f[j]; + out->data[slot][1] = machine->Outputs[slot].xyzw[1].f[j]; + out->data[slot][2] = machine->Outputs[slot].xyzw[2].f[j]; + out->data[slot][3] = machine->Outputs[slot].xyzw[3].f[j]; + } #if 0 /*DEBUG*/ - printf("Post xform vert:\n"); - for (slot = 0; slot < draw->num_vs_outputs; slot++) { - printf("%d: %f %f %f %f\n", slot, - vOut[j]->data[slot][0], - vOut[j]->data[slot][1], - vOut[j]->data[slot][2], - vOut[j]->data[slot][3]); - } -#endif - - - } /* loop over vertices */ + printf("%d) Post xform vert:\n", i + j); + for (slot = 0; slot < draw->num_vs_outputs; slot++) { + printf("\t%d: %f %f %f %f\n", slot, + out->data[slot][0], + out->data[slot][1], + out->data[slot][2], + out->data[slot][3]); + } +#endif + } /* loop over vertices */ + } + return clipped != 0; } diff --git a/src/gallium/auxiliary/draw/draw_vs_llvm.c b/src/gallium/auxiliary/draw/draw_vs_llvm.c index c8268317ef..73076d2467 100644 --- a/src/gallium/auxiliary/draw/draw_vs_llvm.c +++ b/src/gallium/auxiliary/draw/draw_vs_llvm.c @@ -50,33 +50,6 @@ struct draw_llvm_vertex_shader { }; -static INLINE unsigned -compute_clipmask(const float *clip, /*const*/ float plane[][4], unsigned nr) -{ - unsigned mask = 0; - unsigned i; - - /* Do the hardwired planes first: - */ - if (-clip[0] + clip[3] < 0) mask |= CLIP_RIGHT_BIT; - if ( clip[0] + clip[3] < 0) mask |= CLIP_LEFT_BIT; - if (-clip[1] + clip[3] < 0) mask |= CLIP_TOP_BIT; - if ( clip[1] + clip[3] < 0) mask |= CLIP_BOTTOM_BIT; - if (-clip[2] + clip[3] < 0) mask |= CLIP_FAR_BIT; - if ( clip[2] + clip[3] < 0) mask |= CLIP_NEAR_BIT; - - /* Followed by any remaining ones: - */ - for (i = 6; i < nr; i++) { - if (dot4(clip, plane[i]) < 0) - mask |= (1<<i); - } - - return mask; -} - - - static void vs_llvm_prepare( struct draw_vertex_shader *base, struct draw_context *draw ) @@ -94,18 +67,19 @@ vs_llvm_prepare( struct draw_vertex_shader *base, * \param count number of vertices to shade [1..4] * \param vOut array of pointers to four output vertices */ -static void +static boolean vs_llvm_run( struct draw_vertex_shader *base, - struct draw_context *draw, - const unsigned *elts, + struct draw_context *draw, + const unsigned *elts, unsigned count, - struct vertex_header *vOut[] ) + void *vOut ) { - struct draw_llvm_vertex_shader *shader = + struct draw_llvm_vertex_shader *shader = (struct draw_llvm_vertex_shader *)base; struct tgsi_exec_machine *machine = &draw->machine; unsigned int j; + unsigned int clipped = 0; ALIGN16_DECL(struct tgsi_exec_vector, inputs, PIPE_MAX_ATTRIBS); ALIGN16_DECL(struct tgsi_exec_vector, outputs, PIPE_MAX_ATTRIBS); @@ -152,19 +126,22 @@ vs_llvm_run( struct draw_vertex_shader *base, w = vOut[j]->clip[3] = machine->Outputs[0].xyzw[3].f[j]; if (!draw->rasterizer->bypass_clipping) { - vOut[j]->clipmask = compute_clipmask(vOut[j]->clip, draw->plane, draw->nr_planes); + vOut[j]->clipmask = compute_clipmask(vOut[j]->clip, draw->plane, + draw->nr_planes); + clipped += vOut[j]->clipmask; /* divide by w */ w = 1.0f / w; x *= w; y *= w; - z *= w; + z *= w; } else { vOut[j]->clipmask = 0; } vOut[j]->edgeflag = 1; - + vOut[j]->vertex_id = UNDEFINED_VERTEX_ID; + if (!draw->identity_viewport) { /* Viewport mapping */ vOut[j]->data[0][0] = x * scale[0] + trans[0]; @@ -189,6 +166,7 @@ vs_llvm_run( struct draw_vertex_shader *base, vOut[j]->data[slot][3] = machine->Outputs[slot].xyzw[3].f[j]; } } /* loop over vertices */ + return clipped != 0; } static void diff --git a/src/gallium/auxiliary/draw/draw_vs_sse.c b/src/gallium/auxiliary/draw/draw_vs_sse.c index f40d65df08..ee0a3105b9 100644 --- a/src/gallium/auxiliary/draw/draw_vs_sse.c +++ b/src/gallium/auxiliary/draw/draw_vs_sse.c @@ -45,49 +45,24 @@ #include "tgsi/exec/tgsi_sse2.h" #include "tgsi/util/tgsi_parse.h" +#define SSE_MAX_VERTICES 4 typedef void (XSTDCALL *codegen_function) ( const struct tgsi_exec_vector *input, struct tgsi_exec_vector *output, float (*constant)[4], - struct tgsi_exec_vector *temporary ); + struct tgsi_exec_vector *temporary, + float (*immediates)[4] ); struct draw_sse_vertex_shader { struct draw_vertex_shader base; struct x86_function sse2_program; codegen_function func; + float immediates[TGSI_EXEC_NUM_IMMEDIATES][4]; }; -/* Should be part of the generated shader: - */ -static INLINE unsigned -compute_clipmask(const float *clip, /*const*/ float plane[][4], unsigned nr) -{ - unsigned mask = 0; - unsigned i; - - /* Do the hardwired planes first: - */ - if (-clip[0] + clip[3] < 0) mask |= CLIP_RIGHT_BIT; - if ( clip[0] + clip[3] < 0) mask |= CLIP_LEFT_BIT; - if (-clip[1] + clip[3] < 0) mask |= CLIP_TOP_BIT; - if ( clip[1] + clip[3] < 0) mask |= CLIP_BOTTOM_BIT; - if (-clip[2] + clip[3] < 0) mask |= CLIP_FAR_BIT; - if ( clip[2] + clip[3] < 0) mask |= CLIP_NEAR_BIT; - - /* Followed by any remaining ones: - */ - for (i = 6; i < nr; i++) { - if (dot4(clip, plane[i]) < 0) - mask |= (1<<i); - } - - return mask; -} - - static void vs_sse_prepare( struct draw_vertex_shader *base, struct draw_context *draw ) @@ -103,23 +78,24 @@ vs_sse_prepare( struct draw_vertex_shader *base, * \param count number of vertices to shade [1..4] * \param vOut array of pointers to four output vertices */ -static void +static boolean vs_sse_run( struct draw_vertex_shader *base, struct draw_context *draw, const unsigned *elts, unsigned count, - struct vertex_header *vOut[] ) + void *vOut, + unsigned vertex_size ) { struct draw_sse_vertex_shader *shader = (struct draw_sse_vertex_shader *)base; struct tgsi_exec_machine *machine = &draw->machine; - unsigned int j; + unsigned int i, j; + unsigned int clipped = 0; ALIGN16_DECL(struct tgsi_exec_vector, inputs, PIPE_MAX_ATTRIBS); ALIGN16_DECL(struct tgsi_exec_vector, outputs, PIPE_MAX_ATTRIBS); const float *scale = draw->viewport.scale; const float *trans = draw->viewport.translate; - assert(count <= 4); assert(draw->vertex_shader->info.output_semantic_name[0] == TGSI_SEMANTIC_POSITION); @@ -134,76 +110,93 @@ vs_sse_run( struct draw_vertex_shader *base, machine->Outputs = ALIGN16_ASSIGN(outputs); } - - /* Fetch vertices. This may at some point be integrated into the - * compiled shader -- that would require a reorganization where - * multiple versions of the compiled shader might exist, - * specialized for each fetch state. - */ - draw->vertex_fetch.fetch_func( draw, machine, elts, count ); - - - if (!draw->rasterizer->bypass_vs) { - /* run compiled shader - */ - shader->func(machine->Inputs, - machine->Outputs, - machine->Consts, - machine->Temps ); - } - - - /* XXX: Computing the clipmask and emitting results should be done - * in the vertex program as a set of instructions appended to - * the user-provided code. - */ - for (j = 0; j < count; j++) { - unsigned slot; - float x, y, z, w; - - x = vOut[j]->clip[0] = machine->Outputs[0].xyzw[0].f[j]; - y = vOut[j]->clip[1] = machine->Outputs[0].xyzw[1].f[j]; - z = vOut[j]->clip[2] = machine->Outputs[0].xyzw[2].f[j]; - w = vOut[j]->clip[3] = machine->Outputs[0].xyzw[3].f[j]; - - if (!draw->rasterizer->bypass_clipping) { - vOut[j]->clipmask = compute_clipmask(vOut[j]->clip, draw->plane, draw->nr_planes); - - /* divide by w */ - w = 1.0f / w; - x *= w; - y *= w; - z *= w; - } - else { - vOut[j]->clipmask = 0; - } - vOut[j]->edgeflag = 1; - - if (!draw->identity_viewport) { - /* Viewport mapping */ - vOut[j]->data[0][0] = x * scale[0] + trans[0]; - vOut[j]->data[0][1] = y * scale[1] + trans[1]; - vOut[j]->data[0][2] = z * scale[2] + trans[2]; - vOut[j]->data[0][3] = w; - } - else { - vOut[j]->data[0][0] = x; - vOut[j]->data[0][1] = y; - vOut[j]->data[0][2] = z; - vOut[j]->data[0][3] = w; + for (i = 0; i < count; i += SSE_MAX_VERTICES) { + unsigned int max_vertices = MIN2(SSE_MAX_VERTICES, count - i); + /* Fetch vertices. This may at some point be integrated into the + * compiled shader -- that would require a reorganization where + * multiple versions of the compiled shader might exist, + * specialized for each fetch state. + */ + draw->vertex_fetch.fetch_func(draw, machine, &elts[i], max_vertices); + + if (!draw->rasterizer->bypass_vs) { + /* run compiled shader + */ + shader->func(machine->Inputs, + machine->Outputs, + machine->Consts, + machine->Temps, + shader->immediates); } - /* Remaining attributes are packed into sequential post-transform - * vertex attrib slots. + /* XXX: Computing the clipmask and emitting results should be done + * in the vertex program as a set of instructions appended to + * the user-provided code. */ - for (slot = 1; slot < draw->num_vs_outputs; slot++) { - vOut[j]->data[slot][0] = machine->Outputs[slot].xyzw[0].f[j]; - vOut[j]->data[slot][1] = machine->Outputs[slot].xyzw[1].f[j]; - vOut[j]->data[slot][2] = machine->Outputs[slot].xyzw[2].f[j]; - vOut[j]->data[slot][3] = machine->Outputs[slot].xyzw[3].f[j]; + for (j = 0; j < max_vertices; j++) { + unsigned slot; + float x, y, z, w; + struct vertex_header *out = + draw_header_from_block(vOut, vertex_size, i + j); + + x = out->clip[0] = machine->Outputs[0].xyzw[0].f[j]; + y = out->clip[1] = machine->Outputs[0].xyzw[1].f[j]; + z = out->clip[2] = machine->Outputs[0].xyzw[2].f[j]; + w = out->clip[3] = machine->Outputs[0].xyzw[3].f[j]; + + if (!draw->rasterizer->bypass_clipping) { + out->clipmask = compute_clipmask(out->clip, draw->plane, + draw->nr_planes); + clipped += out->clipmask; + + /* divide by w */ + w = 1.0f / w; + x *= w; + y *= w; + z *= w; + } + else { + out->clipmask = 0; + } + out->edgeflag = 1; + out->vertex_id = UNDEFINED_VERTEX_ID; + + if (!draw->identity_viewport) { + /* Viewport mapping */ + out->data[0][0] = x * scale[0] + trans[0]; + out->data[0][1] = y * scale[1] + trans[1]; + out->data[0][2] = z * scale[2] + trans[2]; + out->data[0][3] = w; + } + else { + out->data[0][0] = x; + out->data[0][1] = y; + out->data[0][2] = z; + out->data[0][3] = w; + } + + /* Remaining attributes are packed into sequential post-transform + * vertex attrib slots. + */ + for (slot = 1; slot < draw->num_vs_outputs; slot++) { + out->data[slot][0] = machine->Outputs[slot].xyzw[0].f[j]; + out->data[slot][1] = machine->Outputs[slot].xyzw[1].f[j]; + out->data[slot][2] = machine->Outputs[slot].xyzw[2].f[j]; + out->data[slot][3] = machine->Outputs[slot].xyzw[3].f[j]; + } +#if 0 /*DEBUG*/ + printf("%d) Post xform vert:\n", i + j); + for (slot = 0; slot < draw->num_vs_outputs; slot++) { + printf("\t%d: %f %f %f %f\n", slot, + out->data[slot][0], + out->data[slot][1], + out->data[slot][2], + out->data[slot][3]); + } +#endif } - } + } + return clipped != 0; } @@ -243,7 +236,7 @@ draw_create_vs_sse(struct draw_context *draw, x86_init_func( &vs->sse2_program ); if (!tgsi_emit_sse2( (struct tgsi_token *) vs->base.state.tokens, - &vs->sse2_program )) + &vs->sse2_program, vs->immediates )) goto fail; vs->func = (codegen_function) x86_get_func( &vs->sse2_program ); diff --git a/src/gallium/auxiliary/pipebuffer/Makefile b/src/gallium/auxiliary/pipebuffer/Makefile index a9fa518c67..d654dbcc91 100644 --- a/src/gallium/auxiliary/pipebuffer/Makefile +++ b/src/gallium/auxiliary/pipebuffer/Makefile @@ -6,9 +6,11 @@ LIBNAME = pipebuffer C_SOURCES = \ pb_buffer_fenced.c \ pb_buffer_malloc.c \ + pb_bufmgr_cache.c \ pb_bufmgr_fenced.c \ pb_bufmgr_mm.c \ pb_bufmgr_pool.c \ + pb_bufmgr_slab.c \ pb_winsys.c include ../../Makefile.template diff --git a/src/gallium/auxiliary/pipebuffer/SConscript b/src/gallium/auxiliary/pipebuffer/SConscript index 3d41fd84a6..604a217982 100644 --- a/src/gallium/auxiliary/pipebuffer/SConscript +++ b/src/gallium/auxiliary/pipebuffer/SConscript @@ -5,9 +5,11 @@ pipebuffer = env.ConvenienceLibrary( source = [ 'pb_buffer_fenced.c', 'pb_buffer_malloc.c', + 'pb_bufmgr_cache.c', 'pb_bufmgr_fenced.c', 'pb_bufmgr_mm.c', 'pb_bufmgr_pool.c', + 'pb_bufmgr_slab.c', 'pb_winsys.c', ]) diff --git a/src/gallium/auxiliary/pipebuffer/pb_buffer_fenced.c b/src/gallium/auxiliary/pipebuffer/pb_buffer_fenced.c index b1f7d93057..65b6584003 100644 --- a/src/gallium/auxiliary/pipebuffer/pb_buffer_fenced.c +++ b/src/gallium/auxiliary/pipebuffer/pb_buffer_fenced.c @@ -35,6 +35,7 @@ #include "pipe/p_compiler.h" +#include "pipe/p_error.h" #include "pipe/p_debug.h" #include "pipe/p_winsys.h" #include "pipe/p_thread.h" @@ -54,6 +55,13 @@ */ #define SUPER(__derived) (&(__derived)->base) +#define PIPE_BUFFER_USAGE_CPU_READ_WRITE \ + ( PIPE_BUFFER_USAGE_CPU_READ | PIPE_BUFFER_USAGE_CPU_WRITE ) +#define PIPE_BUFFER_USAGE_GPU_READ_WRITE \ + ( PIPE_BUFFER_USAGE_GPU_READ | PIPE_BUFFER_USAGE_GPU_WRITE ) +#define PIPE_BUFFER_USAGE_WRITE \ + ( PIPE_BUFFER_USAGE_CPU_WRITE | PIPE_BUFFER_USAGE_GPU_WRITE ) + struct fenced_buffer_list { @@ -76,6 +84,15 @@ struct fenced_buffer struct pb_buffer *buffer; + /* FIXME: protect access with mutex */ + + /** + * A bitmask of PIPE_BUFFER_USAGE_CPU/GPU_READ/WRITE describing the current + * buffer usage. + */ + unsigned flags; + + unsigned mapcount; struct pipe_fence_handle *fence; struct list_head head; @@ -98,7 +115,9 @@ _fenced_buffer_add(struct fenced_buffer *fenced_buf) struct fenced_buffer_list *fenced_list = fenced_buf->list; assert(fenced_buf->base.base.refcount); + assert(fenced_buf->flags & PIPE_BUFFER_USAGE_GPU_READ_WRITE); assert(fenced_buf->fence); + assert(!fenced_buf->head.prev); assert(!fenced_buf->head.next); LIST_ADDTAIL(&fenced_buf->head, &fenced_list->delayed); @@ -130,6 +149,7 @@ _fenced_buffer_remove(struct fenced_buffer *fenced_buf) assert(fenced_buf->fence); winsys->fence_reference(winsys, &fenced_buf->fence, NULL); + fenced_buf->flags &= ~PIPE_BUFFER_USAGE_GPU_READ_WRITE; assert(fenced_buf->head.prev); assert(fenced_buf->head.next); @@ -186,6 +206,34 @@ _fenced_buffer_list_check_free(struct fenced_buffer_list *fenced_list, } +/** + * Serialize writes, but allow concurrent reads. + */ +static INLINE enum pipe_error +fenced_buffer_serialize(struct fenced_buffer *fenced_buf, unsigned flags) +{ + struct fenced_buffer_list *fenced_list = fenced_buf->list; + struct pipe_winsys *winsys = fenced_list->winsys; + + if(((fenced_buf->flags | flags) & PIPE_BUFFER_USAGE_WRITE) == 0) + return PIPE_OK; + + if(fenced_buf->mapcount) { + /* FIXME */ + debug_warning("attemp to write concurrently to buffer"); + return PIPE_ERROR_RETRY; + } + + if(fenced_buf->fence) { + if(winsys->fence_finish(winsys, fenced_buf->fence, 0) != 0) + return PIPE_ERROR_RETRY; + _fenced_buffer_remove(fenced_buf); + } + + return PIPE_OK; +} + + static void fenced_buffer_destroy(struct pb_buffer *buf) { @@ -223,16 +271,30 @@ static void * fenced_buffer_map(struct pb_buffer *buf, unsigned flags) { - struct fenced_buffer *fenced_buf = fenced_buffer(buf); - return pb_map(fenced_buf->buffer, flags); + struct fenced_buffer *fenced_buf = fenced_buffer(buf); + void *map; + assert((flags & ~PIPE_BUFFER_USAGE_CPU_READ_WRITE) == 0); + + if(fenced_buffer_serialize(fenced_buf, flags) != PIPE_OK) + return NULL; + + map = pb_map(fenced_buf->buffer, flags); + if(map) + ++fenced_buf->mapcount; + fenced_buf->flags |= flags & PIPE_BUFFER_USAGE_CPU_READ_WRITE; + return map; } static void fenced_buffer_unmap(struct pb_buffer *buf) { - struct fenced_buffer *fenced_buf = fenced_buffer(buf); + struct fenced_buffer *fenced_buf = fenced_buffer(buf); + assert(fenced_buf->mapcount); pb_unmap(fenced_buf->buffer); + --fenced_buf->mapcount; + if(!fenced_buf->mapcount) + fenced_buf->flags &= ~PIPE_BUFFER_USAGE_CPU_READ_WRITE; } @@ -288,13 +350,22 @@ buffer_fence(struct pb_buffer *buf, struct fenced_buffer *fenced_buf = fenced_buffer(buf); struct fenced_buffer_list *fenced_list = fenced_buf->list; struct pipe_winsys *winsys = fenced_list->winsys; + /* FIXME: receive this as a parameter */ + unsigned flags = fence ? PIPE_BUFFER_USAGE_GPU_READ_WRITE : 0; + + if(fenced_buffer_serialize(fenced_buf, flags) != PIPE_OK) { + /* FIXME: propagate error */ + (void)0; + } _glthread_LOCK_MUTEX(fenced_list->mutex); if (fenced_buf->fence) _fenced_buffer_remove(fenced_buf); - winsys->fence_reference(winsys, &fenced_buf->fence, fence); - if (fenced_buf->fence) + if (fence) { + winsys->fence_reference(winsys, &fenced_buf->fence, fence); + fenced_buf->flags |= flags & PIPE_BUFFER_USAGE_GPU_READ_WRITE; _fenced_buffer_add(fenced_buf); + } _glthread_UNLOCK_MUTEX(fenced_list->mutex); } diff --git a/src/gallium/auxiliary/pipebuffer/pb_bufmgr.h b/src/gallium/auxiliary/pipebuffer/pb_bufmgr.h index 0cf8e92e37..b2d2520b67 100644 --- a/src/gallium/auxiliary/pipebuffer/pb_bufmgr.h +++ b/src/gallium/auxiliary/pipebuffer/pb_bufmgr.h @@ -80,7 +80,7 @@ struct pb_manager /** - * Static buffer pool manager. + * Static buffer pool sub-allocator. * * Manages the allocation of equally sized buffers. It does so by allocating * a single big buffer and divide it equally sized buffers. @@ -94,7 +94,7 @@ pool_bufmgr_create(struct pb_manager *provider, /** - * Wraper around the old memory manager. + * Static sub-allocator based the old memory manager. * * It managers buffers of different sizes. It does so by allocating a buffer * with the size of the heap, and then using the old mm memory manager to manage @@ -114,6 +114,29 @@ mm_bufmgr_create_from_buffer(struct pb_buffer *buffer, size_t size, size_t align2); +/** + * Slab sub-allocator. + */ +struct pb_manager * +pb_slab_manager_create(struct pb_manager *provider, + const struct pb_desc *desc, + size_t smallestSize, + size_t numSizes, + size_t desiredNumBuffers, + size_t maxSlabSize, + size_t pageAlignment); + + +/** + * Time-based buffer cache. + * + * This manager keeps a cache of destroyed buffers during a time interval. + */ +struct pb_manager * +pb_cache_manager_create(struct pb_manager *provider, + unsigned usecs); + + /** * Fenced buffer manager. * diff --git a/src/gallium/auxiliary/pipebuffer/pb_bufmgr_cache.c b/src/gallium/auxiliary/pipebuffer/pb_bufmgr_cache.c new file mode 100644 index 0000000000..06de0bb6c3 --- /dev/null +++ b/src/gallium/auxiliary/pipebuffer/pb_bufmgr_cache.c @@ -0,0 +1,299 @@ +/************************************************************************** + * + * Copyright 2007-2008 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. + * + **************************************************************************/ + +/** + * \file + * Buffer cache. + * + * \author José Fonseca <jrfonseca-at-tungstengraphics-dot-com> + * \author Thomas Hellström <thomas-at-tungstengraphics-dot-com> + */ + + +#include "pipe/p_compiler.h" +#include "pipe/p_debug.h" +#include "pipe/p_winsys.h" +#include "pipe/p_thread.h" +#include "pipe/p_util.h" +#include "util/u_double_list.h" +#include "util/u_time.h" + +#include "pb_buffer.h" +#include "pb_bufmgr.h" + + +/** + * Convenience macro (type safe). + */ +#define SUPER(__derived) (&(__derived)->base) + + +struct pb_cache_manager; + + +/** + * Wrapper around a pipe buffer which adds delayed destruction. + */ +struct pb_cache_buffer +{ + struct pb_buffer base; + + struct pb_buffer *buffer; + struct pb_cache_manager *mgr; + + /** Caching time interval */ + struct util_time start, end; + + struct list_head head; +}; + + +struct pb_cache_manager +{ + struct pb_manager base; + + struct pb_manager *provider; + unsigned usecs; + + _glthread_Mutex mutex; + + struct list_head delayed; + size_t numDelayed; +}; + + +static INLINE struct pb_cache_buffer * +pb_cache_buffer(struct pb_buffer *buf) +{ + assert(buf); + return (struct pb_cache_buffer *)buf; +} + + +static INLINE struct pb_cache_manager * +pb_cache_manager(struct pb_manager *mgr) +{ + assert(mgr); + return (struct pb_cache_manager *)mgr; +} + + +/** + * Actually destroy the buffer. + */ +static INLINE void +_pb_cache_buffer_destroy(struct pb_cache_buffer *buf) +{ + struct pb_cache_manager *mgr = buf->mgr; + + LIST_DEL(&buf->head); + assert(mgr->numDelayed); + --mgr->numDelayed; + assert(!buf->base.base.refcount); + pb_reference(&buf->buffer, NULL); + FREE(buf); +} + + +/** + * Free as many cache buffers from the list head as possible. + */ +static void +_pb_cache_buffer_list_check_free(struct pb_cache_manager *mgr) +{ + struct list_head *curr, *next; + struct pb_cache_buffer *buf; + struct util_time now; + + util_time_get(&now); + + curr = mgr->delayed.next; + next = curr->next; + while(curr != &mgr->delayed) { + buf = LIST_ENTRY(struct pb_cache_buffer, curr, head); + + if(util_time_timeout(&buf->start, &buf->end, &now) != 0) + break; + + _pb_cache_buffer_destroy(buf); + + curr = next; + next = curr->next; + } +} + + +static void +pb_cache_buffer_destroy(struct pb_buffer *_buf) +{ + struct pb_cache_buffer *buf = pb_cache_buffer(_buf); + struct pb_cache_manager *mgr = buf->mgr; + + _glthread_LOCK_MUTEX(mgr->mutex); + assert(buf->base.base.refcount == 0); + + _pb_cache_buffer_list_check_free(mgr); + + util_time_get(&buf->start); + util_time_add(&buf->start, mgr->usecs, &buf->end); + LIST_ADDTAIL(&buf->head, &mgr->delayed); + ++mgr->numDelayed; + _glthread_UNLOCK_MUTEX(mgr->mutex); +} + + +static void * +pb_cache_buffer_map(struct pb_buffer *_buf, + unsigned flags) +{ + struct pb_cache_buffer *buf = pb_cache_buffer(_buf); + return pb_map(buf->buffer, flags); +} + + +static void +pb_cache_buffer_unmap(struct pb_buffer *_buf) +{ + struct pb_cache_buffer *buf = pb_cache_buffer(_buf); + pb_unmap(buf->buffer); +} + + +static void +pb_cache_buffer_get_base_buffer(struct pb_buffer *_buf, + struct pb_buffer **base_buf, + unsigned *offset) +{ + struct pb_cache_buffer *buf = pb_cache_buffer(_buf); + pb_get_base_buffer(buf->buffer, base_buf, offset); +} + + +const struct pb_vtbl +pb_cache_buffer_vtbl = { + pb_cache_buffer_destroy, + pb_cache_buffer_map, + pb_cache_buffer_unmap, + pb_cache_buffer_get_base_buffer +}; + + +static struct pb_buffer * +pb_cache_manager_create_buffer(struct pb_manager *_mgr, + size_t size, + const struct pb_desc *desc) +{ + struct pb_cache_manager *mgr = pb_cache_manager(_mgr); + struct pb_cache_buffer *buf; + struct list_head *curr, *next; + struct util_time now; + + util_time_get(&now); + curr = mgr->delayed.next; + next = curr->next; + while(curr != &mgr->delayed) { + buf = LIST_ENTRY(struct pb_cache_buffer, curr, head); + + if(buf->base.base.size == size && + buf->base.base.alignment >= desc->alignment && + (buf->base.base.alignment % desc->alignment) == 0 && + /* buf->base.base.usage == usage */ 1) { + ++buf->base.base.refcount; + return &buf->base; + } + + if(util_time_timeout(&buf->start, &buf->end, &now) != 0) + _pb_cache_buffer_destroy(buf); + + curr = next; + next = curr->next; + } + + buf = CALLOC_STRUCT(pb_cache_buffer); + if(!buf) + return NULL; + + buf->buffer = mgr->provider->create_buffer(mgr->provider, size, desc); + if(!buf->buffer) { + FREE(buf); + return NULL; + } + + buf->base.base.refcount = 1; + buf->base.base.alignment = buf->buffer->base.alignment; + buf->base.base.usage = buf->buffer->base.usage; + buf->base.base.size = buf->buffer->base.size; + + buf->base.vtbl = &pb_cache_buffer_vtbl; + buf->mgr = mgr; + + return &buf->base; +} + + +static void +pb_cache_manager_destroy(struct pb_manager *_mgr) +{ + struct pb_cache_manager *mgr = pb_cache_manager(_mgr); + struct list_head *curr, *next; + struct pb_cache_buffer *buf; + + _glthread_LOCK_MUTEX(mgr->mutex); + curr = mgr->delayed.next; + next = curr->next; + while(curr != &mgr->delayed) { + buf = LIST_ENTRY(struct pb_cache_buffer, curr, head); + _pb_cache_buffer_destroy(buf); + curr = next; + next = curr->next; + } + _glthread_UNLOCK_MUTEX(mgr->mutex); + + FREE(mgr); +} + + +struct pb_manager * +pb_cache_manager_create(struct pb_manager *provider, + unsigned usecs) +{ + struct pb_cache_manager *mgr; + + mgr = (struct pb_cache_manager *)CALLOC(1, sizeof(*mgr)); + if (!mgr) + return NULL; + + mgr->base.destroy = pb_cache_manager_destroy; + mgr->base.create_buffer = pb_cache_manager_create_buffer; + mgr->provider = provider; + mgr->usecs = usecs; + LIST_INITHEAD(&mgr->delayed); + mgr->numDelayed = 0; + _glthread_INIT_MUTEX(mgr->mutex); + + return &mgr->base; +} diff --git a/src/gallium/auxiliary/pipebuffer/pb_bufmgr_slab.c b/src/gallium/auxiliary/pipebuffer/pb_bufmgr_slab.c new file mode 100644 index 0000000000..676e8e29b9 --- /dev/null +++ b/src/gallium/auxiliary/pipebuffer/pb_bufmgr_slab.c @@ -0,0 +1,429 @@ +/************************************************************************** + * + * Copyright 2006-2008 Tungsten Graphics, Inc., Cedar Park, TX., USA + * 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 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 + * THE COPYRIGHT HOLDERS, AUTHORS 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. + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * + **************************************************************************/ + +/** + * @file + * S-lab pool implementation. + * + * @author Thomas Hellstrom <thomas-at-tungstengraphics-dot-com> + * @author Jose Fonseca <jrfonseca@tungstengraphics.com> + */ + +#include "pipe/p_compiler.h" +#include "pipe/p_error.h" +#include "pipe/p_debug.h" +#include "pipe/p_thread.h" +#include "pipe/p_defines.h" +#include "pipe/p_util.h" +#include "util/u_double_list.h" +#include "util/u_time.h" + +#include "pb_buffer.h" +#include "pb_bufmgr.h" + + +#define DRI_SLABPOOL_ALLOC_RETRIES 100 + + +struct pb_slab; + +struct pb_slab_buffer +{ + struct pb_buffer base; + + struct pb_slab *slab; + struct list_head head; + unsigned mapCount; + size_t start; + _glthread_Cond event; +}; + +struct pb_slab +{ + struct list_head head; + struct list_head freeBuffers; + size_t numBuffers; + size_t numFree; + struct pb_slab_buffer *buffers; + struct pb_slab_size_header *header; + + struct pb_buffer *bo; + size_t pageAlignment; + void *virtual; +}; + +struct pb_slab_size_header +{ + struct list_head slabs; + struct list_head freeSlabs; + struct pb_slab_manager *pool; + size_t bufSize; + _glthread_Mutex mutex; +}; + +/** + * The data of this structure remains constant after + * initialization and thus needs no mutex protection. + */ +struct pb_slab_manager +{ + struct pb_manager base; + + struct pb_desc desc; + size_t *bucketSizes; + size_t numBuckets; + size_t pageSize; + struct pb_manager *provider; + unsigned pageAlignment; + unsigned maxSlabSize; + unsigned desiredNumBuffers; + struct pb_slab_size_header *headers; +}; + + +static INLINE struct pb_slab_buffer * +pb_slab_buffer(struct pb_buffer *buf) +{ + assert(buf); + return (struct pb_slab_buffer *)buf; +} + + +static INLINE struct pb_slab_manager * +pb_slab_manager(struct pb_manager *mgr) +{ + assert(mgr); + return (struct pb_slab_manager *)mgr; +} + + +/** + * Delete a buffer from the slab header delayed list and put + * it on the slab FREE list. + */ +static void +pb_slab_buffer_destroy(struct pb_buffer *_buf) +{ + struct pb_slab_buffer *buf = pb_slab_buffer(_buf); + struct pb_slab *slab = buf->slab; + struct pb_slab_size_header *header = slab->header; + struct list_head *list = &buf->head; + + _glthread_LOCK_MUTEX(header->mutex); + + assert(buf->base.base.refcount == 0); + + buf->mapCount = 0; + + LIST_DEL(list); + LIST_ADDTAIL(list, &slab->freeBuffers); + slab->numFree++; + + if (slab->head.next == &slab->head) + LIST_ADDTAIL(&slab->head, &header->slabs); + + if (slab->numFree == slab->numBuffers) { + list = &slab->head; + LIST_DEL(list); + LIST_ADDTAIL(list, &header->freeSlabs); + } + + if (header->slabs.next == &header->slabs || slab->numFree + != slab->numBuffers) { + + struct list_head *next; + + for (list = header->freeSlabs.next, next = list->next; list + != &header->freeSlabs; list = next, next = list->next) { + + slab = LIST_ENTRY(struct pb_slab, list, head); + + LIST_DELINIT(list); + pb_reference(&slab->bo, NULL); + FREE(slab->buffers); + FREE(slab); + } + } + + _glthread_UNLOCK_MUTEX(header->mutex); +} + + +static void * +pb_slab_buffer_map(struct pb_buffer *_buf, + unsigned flags) +{ + struct pb_slab_buffer *buf = pb_slab_buffer(_buf); + + ++buf->mapCount; + return (void *) ((uint8_t *) buf->slab->virtual + buf->start); +} + + +static void +pb_slab_buffer_unmap(struct pb_buffer *_buf) +{ + struct pb_slab_buffer *buf = pb_slab_buffer(_buf); + + --buf->mapCount; + if (buf->mapCount == 0) + _glthread_COND_BROADCAST(buf->event); +} + + +static void +pb_slab_buffer_get_base_buffer(struct pb_buffer *_buf, + struct pb_buffer **base_buf, + unsigned *offset) +{ + struct pb_slab_buffer *buf = pb_slab_buffer(_buf); + pb_get_base_buffer(buf->slab->bo, base_buf, offset); + *offset += buf->start; +} + + +static const struct pb_vtbl +pb_slab_buffer_vtbl = { + pb_slab_buffer_destroy, + pb_slab_buffer_map, + pb_slab_buffer_unmap, + pb_slab_buffer_get_base_buffer +}; + + +static enum pipe_error +pb_slab_create(struct pb_slab_size_header *header) +{ + struct pb_slab_manager *pool = header->pool; + size_t size = header->bufSize * pool->desiredNumBuffers; + struct pb_slab *slab; + struct pb_slab_buffer *buf; + size_t numBuffers; + int ret; + unsigned i; + + slab = CALLOC_STRUCT(pb_slab); + if (!slab) + return PIPE_ERROR_OUT_OF_MEMORY; + + /* + * FIXME: We should perhaps allow some variation in slabsize in order + * to efficiently reuse slabs. + */ + + size = (size <= pool->maxSlabSize) ? size : pool->maxSlabSize; + size = (size + pool->pageSize - 1) & ~(pool->pageSize - 1); + + slab->bo = pool->provider->create_buffer(pool->provider, size, &pool->desc); + if(!slab->bo) + goto out_err0; + + slab->virtual = pb_map(slab->bo, + PIPE_BUFFER_USAGE_CPU_READ | + PIPE_BUFFER_USAGE_CPU_WRITE); + if(!slab->virtual) + goto out_err1; + + pb_unmap(slab->bo); + + numBuffers = slab->bo->base.size / header->bufSize; + + slab->buffers = CALLOC(numBuffers, sizeof(*slab->buffers)); + if (!slab->buffers) { + ret = PIPE_ERROR_OUT_OF_MEMORY; + goto out_err1; + } + + LIST_INITHEAD(&slab->head); + LIST_INITHEAD(&slab->freeBuffers); + slab->numBuffers = numBuffers; + slab->numFree = 0; + slab->header = header; + + buf = slab->buffers; + for (i=0; i < numBuffers; ++i) { + buf->base.base.refcount = 0; + buf->base.base.size = header->bufSize; + buf->base.base.alignment = 0; + buf->base.base.usage = 0; + buf->base.vtbl = &pb_slab_buffer_vtbl; + buf->slab = slab; + buf->start = i* header->bufSize; + buf->mapCount = 0; + _glthread_INIT_COND(buf->event); + LIST_ADDTAIL(&buf->head, &slab->freeBuffers); + slab->numFree++; + buf++; + } + + LIST_ADDTAIL(&slab->head, &header->slabs); + + return PIPE_OK; + +out_err1: + pb_reference(&slab->bo, NULL); +out_err0: + FREE(slab); + return ret; +} + + +static struct pb_buffer * +pb_slab_manager_create_buffer(struct pb_manager *_pool, + size_t size, + const struct pb_desc *desc) +{ + struct pb_slab_manager *pool = pb_slab_manager(_pool); + struct pb_slab_size_header *header; + unsigned i; + static struct pb_slab_buffer *buf; + struct pb_slab *slab; + struct list_head *list; + int count = DRI_SLABPOOL_ALLOC_RETRIES; + + /* + * FIXME: Check for compatibility. + */ + + header = pool->headers; + for (i=0; i<pool->numBuckets; ++i) { + if (header->bufSize >= size) + break; + header++; + } + + if (i >= pool->numBuckets) + /* Fall back to allocate a buffer object directly from the provider. */ + return pool->provider->create_buffer(pool->provider, size, desc); + + + _glthread_LOCK_MUTEX(header->mutex); + while (header->slabs.next == &header->slabs && count > 0) { + if (header->slabs.next != &header->slabs) + break; + + _glthread_UNLOCK_MUTEX(header->mutex); + if (count != DRI_SLABPOOL_ALLOC_RETRIES) + util_time_sleep(1); + _glthread_LOCK_MUTEX(header->mutex); + (void) pb_slab_create(header); + count--; + } + + list = header->slabs.next; + if (list == &header->slabs) { + _glthread_UNLOCK_MUTEX(header->mutex); + return NULL; + } + slab = LIST_ENTRY(struct pb_slab, list, head); + if (--slab->numFree == 0) + LIST_DELINIT(list); + + list = slab->freeBuffers.next; + LIST_DELINIT(list); + + _glthread_UNLOCK_MUTEX(header->mutex); + buf = LIST_ENTRY(struct pb_slab_buffer, list, head); + ++buf->base.base.refcount; + return &buf->base; +} + + +static void +pb_slab_manager_destroy(struct pb_manager *_pool) +{ + struct pb_slab_manager *pool = pb_slab_manager(_pool); + + FREE(pool->headers); + FREE(pool->bucketSizes); + FREE(pool); +} + + +struct pb_manager * +pb_slab_manager_create(struct pb_manager *provider, + const struct pb_desc *desc, + size_t smallestSize, + size_t numSizes, + size_t desiredNumBuffers, + size_t maxSlabSize, + size_t pageAlignment) +{ + struct pb_slab_manager *pool; + size_t i; + + pool = CALLOC_STRUCT(pb_slab_manager); + if (!pool) + goto out_err0; + + pool->bucketSizes = CALLOC(numSizes, sizeof(*pool->bucketSizes)); + if (!pool->bucketSizes) + goto out_err1; + + pool->headers = CALLOC(numSizes, sizeof(*pool->headers)); + if (!pool->headers) + goto out_err2; + + pool->desc = *desc; + pool->numBuckets = numSizes; +#ifdef WIN32 + pool->pageSize = 4096; +#else + pool->pageSize = getpagesize(); +#endif + pool->provider = provider; + pool->pageAlignment = pageAlignment; + pool->maxSlabSize = maxSlabSize; + pool->desiredNumBuffers = desiredNumBuffers; + + for (i=0; i<pool->numBuckets; ++i) { + struct pb_slab_size_header *header = &pool->headers[i]; + + pool->bucketSizes[i] = (smallestSize << i); + + _glthread_INIT_MUTEX(header->mutex); + + LIST_INITHEAD(&header->slabs); + LIST_INITHEAD(&header->freeSlabs); + + header->pool = pool; + header->bufSize = (smallestSize << i); + } + + pool->base.destroy = pb_slab_manager_destroy; + pool->base.create_buffer = pb_slab_manager_create_buffer; + + return &pool->base; + +out_err2: + FREE(pool->bucketSizes); +out_err1: + FREE(pool); +out_err0: + return NULL; +} diff --git a/src/gallium/auxiliary/rtasm/rtasm_x86sse.c b/src/gallium/auxiliary/rtasm/rtasm_x86sse.c index 4d33950e99..aea8b28e58 100644 --- a/src/gallium/auxiliary/rtasm/rtasm_x86sse.c +++ b/src/gallium/auxiliary/rtasm/rtasm_x86sse.c @@ -317,7 +317,7 @@ void x86_call( struct x86_function *p, void (*label)()) void x86_call( struct x86_function *p, struct x86_reg reg) { emit_1ub(p, 0xff); - emit_modrm(p, reg, reg); + emit_modrm_noreg(p, 2, reg); } #endif diff --git a/src/gallium/auxiliary/tgsi/exec/tgsi_sse2.c b/src/gallium/auxiliary/tgsi/exec/tgsi_sse2.c index 4e80597b3f..c37e201b2b 100755 --- a/src/gallium/auxiliary/tgsi/exec/tgsi_sse2.c +++ b/src/gallium/auxiliary/tgsi/exec/tgsi_sse2.c @@ -225,6 +225,15 @@ get_coef_base( void ) return get_output_base(); } +static struct x86_reg +get_immediate_base( void ) +{ + return x86_make_reg( + file_REG32, + reg_DI ); +} + + /** * Data access helpers. */ @@ -239,6 +248,16 @@ get_argument( } static struct x86_reg +get_immediate( + unsigned vec, + unsigned chan ) +{ + return x86_make_disp( + get_immediate_base(), + (vec * 4 + chan) * 4 ); +} + +static struct x86_reg get_const( unsigned vec, unsigned chan ) @@ -548,6 +567,12 @@ emit_xorps( * Data fetch helpers. */ +/** + * Copy a shader constant to xmm register + * \param xmm the destination xmm register + * \param vec the src const buffer index + * \param chan src channel to fetch (X, Y, Z or W) + */ static void emit_const( struct x86_function *func, @@ -567,6 +592,31 @@ emit_const( } static void +emit_immediate( + struct x86_function *func, + unsigned xmm, + unsigned vec, + unsigned chan ) +{ + emit_movss( + func, + make_xmm( xmm ), + get_immediate( vec, chan ) ); + emit_shufps( + func, + make_xmm( xmm ), + make_xmm( xmm ), + SHUF( 0, 0, 0, 0 ) ); +} + + +/** + * Copy a shader input to xmm register + * \param xmm the destination xmm register + * \param vec the src input attrib + * \param chan src channel to fetch (X, Y, Z or W) + */ +static void emit_inputf( struct x86_function *func, unsigned xmm, @@ -579,6 +629,12 @@ emit_inputf( get_input( vec, chan ) ); } +/** + * Store an xmm register to a shader output + * \param xmm the source xmm register + * \param vec the dest output attrib + * \param chan src dest channel to store (X, Y, Z or W) + */ static void emit_output( struct x86_function *func, @@ -592,6 +648,12 @@ emit_output( make_xmm( xmm ) ); } +/** + * Copy a shader temporary to xmm register + * \param xmm the destination xmm register + * \param vec the src temp register + * \param chan src channel to fetch (X, Y, Z or W) + */ static void emit_tempf( struct x86_function *func, @@ -605,6 +667,13 @@ emit_tempf( get_temp( vec, chan ) ); } +/** + * Load an xmm register with an input attrib coefficient (a0, dadx or dady) + * \param xmm the destination xmm register + * \param vec the src input/attribute coefficient index + * \param chan src channel to fetch (X, Y, Z or W) + * \param member 0=a0, 1=dadx, 2=dady + */ static void emit_coef( struct x86_function *func, @@ -1160,6 +1229,14 @@ emit_fetch( swizzle ); break; + case TGSI_FILE_IMMEDIATE: + emit_immediate( + func, + xmm, + reg->SrcRegister.Index, + swizzle ); + break; + case TGSI_FILE_INPUT: emit_inputf( func, @@ -2020,7 +2097,7 @@ emit_instruction( STORE( func, *inst, 0, 0, CHAN_X ); } IF_IS_DST0_CHANNEL_ENABLED( *inst, CHAN_Y ) { - FETCH( func, *inst, 0, 0, CHAN_Y ); + FETCH( func, *inst, 0, 0, CHAN_X ); emit_sin( func, 0 ); STORE( func, *inst, 0, 0, CHAN_Y ); } @@ -2236,135 +2313,116 @@ emit_declaration( } } -unsigned -tgsi_emit_sse2( - struct tgsi_token *tokens, - struct x86_function *func ) -{ - struct tgsi_parse_context parse; - unsigned ok = 1; - - DUMP_START(); - - func->csr = func->store; - - emit_mov( - func, - get_input_base(), - get_argument( 0 ) ); - emit_mov( - func, - get_output_base(), - get_argument( 1 ) ); - emit_mov( - func, - get_const_base(), - get_argument( 2 ) ); - emit_mov( - func, - get_temp_base(), - get_argument( 3 ) ); - - tgsi_parse_init( &parse, tokens ); - - while( !tgsi_parse_end_of_tokens( &parse ) && ok ) { - tgsi_parse_token( &parse ); - - switch( parse.FullToken.Token.Type ) { - case TGSI_TOKEN_TYPE_DECLARATION: - break; - - case TGSI_TOKEN_TYPE_INSTRUCTION: - ok = emit_instruction( - func, - &parse.FullToken.FullInstruction ); - - if (!ok) { - debug_printf("failed to translate tgsi opcode %d to SSE\n", - parse.FullToken.FullInstruction.Instruction.Opcode ); - } - break; - - case TGSI_TOKEN_TYPE_IMMEDIATE: - /* XXX implement this */ - ok = 0; - debug_printf("failed to emit immediate value to SSE\n"); - break; - - default: - assert( 0 ); - ok = 0; - break; - } - } - - tgsi_parse_free( &parse ); - - DUMP_END(); - - return ok; -} /** - * Fragment shaders are responsible for interpolating shader inputs. Because on - * x86 we have only 4 GP registers, and here we have 5 shader arguments (input, - * output, const, temp and coef), the code is split into two phases -- - * DECLARATION and INSTRUCTION phase. - * GP register holding the output argument is aliased with the coeff argument, - * as outputs are not needed in the DECLARATION phase. + * Translate a TGSI vertex/fragment shader to SSE2 code. + * Slightly different things are done for vertex vs. fragment shaders. + * + * Note that fragment shaders are responsible for interpolating shader + * inputs. Because on x86 we have only 4 GP registers, and here we + * have 5 shader arguments (input, output, const, temp and coef), the + * code is split into two phases -- DECLARATION and INSTRUCTION phase. + * GP register holding the output argument is aliased with the coeff + * argument, as outputs are not needed in the DECLARATION phase. + * + * \param tokens the TGSI input shader + * \param func the output SSE code/function + * \param immediates buffer to place immediates, later passed to SSE func + * \param return 1 for success, 0 if translation failed */ unsigned -tgsi_emit_sse2_fs( +tgsi_emit_sse2( struct tgsi_token *tokens, - struct x86_function *func ) + struct x86_function *func, + float (*immediates)[4]) { struct tgsi_parse_context parse; boolean instruction_phase = FALSE; unsigned ok = 1; + uint num_immediates = 0; DUMP_START(); func->csr = func->store; - /* DECLARATION phase, do not load output argument. */ - emit_mov( - func, - get_input_base(), - get_argument( 0 ) ); - emit_mov( - func, - get_const_base(), - get_argument( 2 ) ); - emit_mov( - func, - get_temp_base(), - get_argument( 3 ) ); - emit_mov( - func, - get_coef_base(), - get_argument( 4 ) ); - tgsi_parse_init( &parse, tokens ); + /* + * Different function args for vertex/fragment shaders: + */ + if (parse.FullHeader.Processor.Processor == TGSI_PROCESSOR_FRAGMENT) { + /* DECLARATION phase, do not load output argument. */ + emit_mov( + func, + get_input_base(), + get_argument( 0 ) ); + /* skipping outputs argument here */ + emit_mov( + func, + get_const_base(), + get_argument( 2 ) ); + emit_mov( + func, + get_temp_base(), + get_argument( 3 ) ); + emit_mov( + func, + get_coef_base(), + get_argument( 4 ) ); + emit_mov( + func, + get_immediate_base(), + get_argument( 5 ) ); + } + else { + assert(parse.FullHeader.Processor.Processor == TGSI_PROCESSOR_VERTEX); + + emit_mov( + func, + get_input_base(), + get_argument( 0 ) ); + emit_mov( + func, + get_output_base(), + get_argument( 1 ) ); + emit_mov( + func, + get_const_base(), + get_argument( 2 ) ); + emit_mov( + func, + get_temp_base(), + get_argument( 3 ) ); + emit_mov( + func, + get_immediate_base(), + get_argument( 4 ) ); + } + while( !tgsi_parse_end_of_tokens( &parse ) && ok ) { tgsi_parse_token( &parse ); switch( parse.FullToken.Token.Type ) { case TGSI_TOKEN_TYPE_DECLARATION: - emit_declaration( - func, - &parse.FullToken.FullDeclaration ); + if (parse.FullHeader.Processor.Processor == TGSI_PROCESSOR_FRAGMENT) { + emit_declaration( + func, + &parse.FullToken.FullDeclaration ); + } break; case TGSI_TOKEN_TYPE_INSTRUCTION: - if( !instruction_phase ) { - /* INSTRUCTION phase, overwrite coeff with output. */ - instruction_phase = TRUE; - emit_mov( - func, - get_output_base(), - get_argument( 1 ) ); + if (parse.FullHeader.Processor.Processor == TGSI_PROCESSOR_FRAGMENT) { + if( !instruction_phase ) { + /* INSTRUCTION phase, overwrite coeff with output. */ + instruction_phase = TRUE; + emit_mov( + func, + get_output_base(), + get_argument( 1 ) ); + } } + ok = emit_instruction( func, &parse.FullToken.FullInstruction ); @@ -2376,9 +2434,26 @@ tgsi_emit_sse2_fs( break; case TGSI_TOKEN_TYPE_IMMEDIATE: - /* XXX implement this */ - ok = 0; - debug_printf("failed to emit immediate value to SSE\n"); + /* simply copy the immediate values into the next immediates[] slot */ + { + const uint size = parse.FullToken.FullImmediate.Immediate.Size - 1; + uint i; + assert(size <= 4); + assert(num_immediates < TGSI_EXEC_NUM_IMMEDIATES); + for( i = 0; i < size; i++ ) { + immediates[num_immediates][i] = + parse.FullToken.FullImmediate.u.ImmediateFloat32[i].Float; + } +#if 0 + debug_printf("SSE FS immediate[%d] = %f %f %f %f\n", + num_immediates, + immediates[num_immediates][0], + immediates[num_immediates][1], + immediates[num_immediates][2], + immediates[num_immediates][3]); +#endif + num_immediates++; + } break; default: diff --git a/src/gallium/auxiliary/tgsi/exec/tgsi_sse2.h b/src/gallium/auxiliary/tgsi/exec/tgsi_sse2.h index 63b8ef3911..d56bf7f98a 100755 --- a/src/gallium/auxiliary/tgsi/exec/tgsi_sse2.h +++ b/src/gallium/auxiliary/tgsi/exec/tgsi_sse2.h @@ -11,12 +11,9 @@ struct x86_function; unsigned tgsi_emit_sse2( struct tgsi_token *tokens, - struct x86_function *function ); - -unsigned -tgsi_emit_sse2_fs( - struct tgsi_token *tokens, - struct x86_function *function ); + struct x86_function *function, + float (*immediates)[4] + ); #if defined __cplusplus } diff --git a/src/gallium/auxiliary/tgsi/util/tgsi_dump.c b/src/gallium/auxiliary/tgsi/util/tgsi_dump.c index 7d292778ad..ff6a2c4194 100644 --- a/src/gallium/auxiliary/tgsi/util/tgsi_dump.c +++ b/src/gallium/auxiliary/tgsi/util/tgsi_dump.c @@ -30,6 +30,7 @@ #include "pipe/p_debug.h" #include "pipe/p_util.h" #include "pipe/p_shader_tokens.h" +#include "util/u_string.h" #include "tgsi_dump.h" #include "tgsi_parse.h" #include "tgsi_build.h" @@ -147,7 +148,7 @@ gen_dump_uix( { char str[36]; - sprintf( str, "0x%x", ui ); + util_snprintf( str, sizeof(str), "0x%x", ui ); gen_dump_str( dump, str ); } @@ -158,7 +159,7 @@ gen_dump_uid( { char str[16]; - sprintf( str, "%u", ui ); + util_snprintf( str, sizeof(str), "%u", ui ); gen_dump_str( dump, str ); } @@ -169,7 +170,7 @@ gen_dump_sid( { char str[16]; - sprintf( str, "%d", si ); + util_snprintf( str, sizeof(str), "%d", si ); gen_dump_str( dump, str ); } @@ -180,7 +181,7 @@ gen_dump_flt( { char str[48]; - sprintf( str, "%10.4f", flt ); + util_snprintf( str, sizeof(str), "%10.4f", flt ); gen_dump_str( dump, str ); } @@ -746,17 +747,19 @@ dump_declaration_short( } } - if( decl->Declaration.Interpolate ) { + if (decl->Declaration.Semantic) { TXT( ", " ); - ENM( decl->Interpolation.Interpolate, TGSI_INTERPOLATES_SHORT ); + ENM( decl->Semantic.SemanticName, TGSI_SEMANTICS_SHORT ); + if (decl->Semantic.SemanticIndex != 0) { + CHR( '[' ); + UID( decl->Semantic.SemanticIndex ); + CHR( ']' ); + } } - if( decl->Declaration.Semantic ) { + if (decl->Declaration.Interpolate) { TXT( ", " ); - ENM( decl->Semantic.SemanticName, TGSI_SEMANTICS_SHORT ); - CHR( '[' ); - UID( decl->Semantic.SemanticIndex ); - CHR( ']' ); + ENM( decl->Interpolation.Interpolate, TGSI_INTERPOLATES_SHORT ); } } @@ -966,18 +969,18 @@ dump_instruction_short( } CHR( ' ' ); - if( src->SrcRegisterExtMod.Complement ) { - TXT( "(1 - " ); - } - if( src->SrcRegisterExtMod.Negate ) { - CHR( '-' ); - } - if( src->SrcRegisterExtMod.Absolute ) { + if (src->SrcRegisterExtMod.Negate) + TXT( "-(" ); + if (src->SrcRegisterExtMod.Absolute) CHR( '|' ); - } - if( src->SrcRegister.Negate ) { + if (src->SrcRegisterExtMod.Scale2X) + TXT( "2*(" ); + if (src->SrcRegisterExtMod.Bias) + CHR( '(' ); + if (src->SrcRegisterExtMod.Complement) + TXT( "1-(" ); + if (src->SrcRegister.Negate) CHR( '-' ); - } ENM( src->SrcRegister.File, TGSI_FILES_SHORT ); @@ -985,35 +988,37 @@ dump_instruction_short( SID( src->SrcRegister.Index ); CHR( ']' ); - if (src->SrcRegister.Extended) { - if (src->SrcRegisterExtSwz.ExtSwizzleX != TGSI_EXTSWIZZLE_X || - src->SrcRegisterExtSwz.ExtSwizzleY != TGSI_EXTSWIZZLE_Y || - src->SrcRegisterExtSwz.ExtSwizzleZ != TGSI_EXTSWIZZLE_Z || - src->SrcRegisterExtSwz.ExtSwizzleW != TGSI_EXTSWIZZLE_W) { - CHR( '.' ); - ENM( src->SrcRegisterExtSwz.ExtSwizzleX, TGSI_EXTSWIZZLES_SHORT ); - ENM( src->SrcRegisterExtSwz.ExtSwizzleY, TGSI_EXTSWIZZLES_SHORT ); - ENM( src->SrcRegisterExtSwz.ExtSwizzleZ, TGSI_EXTSWIZZLES_SHORT ); - ENM( src->SrcRegisterExtSwz.ExtSwizzleW, TGSI_EXTSWIZZLES_SHORT ); - } - } - else if( src->SrcRegister.SwizzleX != TGSI_SWIZZLE_X || - src->SrcRegister.SwizzleY != TGSI_SWIZZLE_Y || - src->SrcRegister.SwizzleZ != TGSI_SWIZZLE_Z || - src->SrcRegister.SwizzleW != TGSI_SWIZZLE_W ) { + if (src->SrcRegister.SwizzleX != TGSI_SWIZZLE_X || + src->SrcRegister.SwizzleY != TGSI_SWIZZLE_Y || + src->SrcRegister.SwizzleZ != TGSI_SWIZZLE_Z || + src->SrcRegister.SwizzleW != TGSI_SWIZZLE_W) { CHR( '.' ); ENM( src->SrcRegister.SwizzleX, TGSI_SWIZZLES_SHORT ); ENM( src->SrcRegister.SwizzleY, TGSI_SWIZZLES_SHORT ); ENM( src->SrcRegister.SwizzleZ, TGSI_SWIZZLES_SHORT ); ENM( src->SrcRegister.SwizzleW, TGSI_SWIZZLES_SHORT ); } + if (src->SrcRegisterExtSwz.ExtSwizzleX != TGSI_EXTSWIZZLE_X || + src->SrcRegisterExtSwz.ExtSwizzleY != TGSI_EXTSWIZZLE_Y || + src->SrcRegisterExtSwz.ExtSwizzleZ != TGSI_EXTSWIZZLE_Z || + src->SrcRegisterExtSwz.ExtSwizzleW != TGSI_EXTSWIZZLE_W) { + CHR( '.' ); + ENM( src->SrcRegisterExtSwz.ExtSwizzleX, TGSI_EXTSWIZZLES_SHORT ); + ENM( src->SrcRegisterExtSwz.ExtSwizzleY, TGSI_EXTSWIZZLES_SHORT ); + ENM( src->SrcRegisterExtSwz.ExtSwizzleZ, TGSI_EXTSWIZZLES_SHORT ); + ENM( src->SrcRegisterExtSwz.ExtSwizzleW, TGSI_EXTSWIZZLES_SHORT ); + } - if( src->SrcRegisterExtMod.Absolute ) { + if (src->SrcRegisterExtMod.Complement) + CHR( ')' ); + if (src->SrcRegisterExtMod.Bias) + TXT( ")-.5" ); + if (src->SrcRegisterExtMod.Scale2X) + CHR( ')' ); + if (src->SrcRegisterExtMod.Absolute) CHR( '|' ); - } - if( src->SrcRegisterExtMod.Complement ) { + if (src->SrcRegisterExtMod.Negate) CHR( ')' ); - } first_reg = FALSE; } @@ -1400,7 +1405,6 @@ dump_gen( CHR( '\n' ); ENM( parse.FullHeader.Processor.Processor, TGSI_PROCESSOR_TYPES_SHORT ); - CHR( ' ' ); UID( parse.FullVersion.Version.MajorVersion ); CHR( '.' ); UID( parse.FullVersion.Version.MinorVersion ); diff --git a/src/gallium/auxiliary/util/Makefile b/src/gallium/auxiliary/util/Makefile index 9b6c2708b6..05bc43131a 100644 --- a/src/gallium/auxiliary/util/Makefile +++ b/src/gallium/auxiliary/util/Makefile @@ -14,7 +14,9 @@ C_SOURCES = \ u_hash_table.c \ u_mm.c \ u_simple_shaders.c \ - u_snprintf.c + u_snprintf.c \ + u_time.c \ + u_mm.c include ../../Makefile.template diff --git a/src/gallium/auxiliary/util/SConscript b/src/gallium/auxiliary/util/SConscript index 9b3929eb2d..d55d2c7081 100644 --- a/src/gallium/auxiliary/util/SConscript +++ b/src/gallium/auxiliary/util/SConscript @@ -15,6 +15,7 @@ util = env.ConvenienceLibrary( 'u_mm.c', 'u_simple_shaders.c', 'u_snprintf.c', + 'u_time.c', ]) auxiliaries.insert(0, util) diff --git a/src/gallium/auxiliary/util/p_debug.c b/src/gallium/auxiliary/util/p_debug.c index 090e3b7794..f9366467cd 100644 --- a/src/gallium/auxiliary/util/p_debug.c +++ b/src/gallium/auxiliary/util/p_debug.c @@ -39,6 +39,7 @@ #include "pipe/p_compiler.h" #include "pipe/p_util.h" #include "pipe/p_debug.h" +#include "util/u_string.h" #ifdef WIN32 @@ -60,7 +61,7 @@ void _debug_vprintf(const char *format, va_list ap) /* EngDebugPrint does not handle float point arguments, so we need to use * our own vsnprintf implementation */ char buf[512 + 1]; - vsnprintf(buf, sizeof(buf), format, ap); + util_vsnprintf(buf, sizeof(buf), format, ap); _EngDebugPrint("%s", buf); #else /* TODO: Implement debug print for WINCE */ @@ -311,7 +312,7 @@ debug_dump_enum(const struct debug_named_value *names, ++names; } - snprintf(rest, sizeof(rest), "0x%08lx", value); + util_snprintf(rest, sizeof(rest), "0x%08lx", value); return rest; } @@ -344,7 +345,7 @@ debug_dump_flags(const struct debug_named_value *names, else first = 0; - snprintf(rest, sizeof(rest), "0x%08lx", value); + util_snprintf(rest, sizeof(rest), "0x%08lx", value); strncat(output, rest, sizeof(output)); } diff --git a/src/gallium/auxiliary/util/p_debug_mem.c b/src/gallium/auxiliary/util/p_debug_mem.c index 97ec9c5b39..aba69c0294 100644 --- a/src/gallium/auxiliary/util/p_debug_mem.c +++ b/src/gallium/auxiliary/util/p_debug_mem.c @@ -73,6 +73,25 @@ static struct list_head list = { &list, &list }; static unsigned long last_no = 0; +static INLINE struct debug_memory_header * +header_from_data(void *data) +{ + if(data) + return (struct debug_memory_header *)((char *)data - sizeof(struct debug_memory_header)); + else + return NULL; +} + +static INLINE void * +data_from_header(struct debug_memory_header *hdr) +{ + if(hdr) + return (void *)((char *)hdr + sizeof(struct debug_memory_header)); + else + return NULL; +} + + void * debug_malloc(const char *file, unsigned line, const char *function, size_t size) @@ -92,7 +111,7 @@ debug_malloc(const char *file, unsigned line, const char *function, LIST_ADDTAIL(&hdr->head, &list); - return (void *)((char *)hdr + sizeof(*hdr)); + return data_from_header(hdr); } void @@ -104,7 +123,7 @@ debug_free(const char *file, unsigned line, const char *function, if(!ptr) return; - hdr = (struct debug_memory_header *)((char *)ptr - sizeof(*hdr)); + hdr = header_from_data(ptr); if(hdr->magic != DEBUG_MEMORY_MAGIC) { debug_printf("%s:%u:%s: freeing bad or corrupted memory %p\n", file, line, function, @@ -133,16 +152,46 @@ void * debug_realloc(const char *file, unsigned line, const char *function, void *old_ptr, size_t old_size, size_t new_size ) { - void *new_ptr = NULL; - - if (new_size != 0) { - new_ptr = debug_malloc( file, line, function, new_size ); - - if( new_ptr && old_ptr ) - memcpy( new_ptr, old_ptr, old_size ); + struct debug_memory_header *old_hdr, *new_hdr; + void *new_ptr; + + if(!old_ptr) + return debug_malloc( file, line, function, new_size ); + + if(!new_size) { + debug_free( file, line, function, old_ptr ); + return NULL; } + + old_hdr = header_from_data(old_ptr); + if(old_hdr->magic != DEBUG_MEMORY_MAGIC) { + debug_printf("%s:%u:%s: reallocating bad or corrupted memory %p\n", + file, line, function, + old_ptr); + debug_assert(0); + return NULL; + } + + /* alloc new */ + new_hdr = real_malloc(sizeof(*new_hdr) + new_size); + if(!new_hdr) + return NULL; + new_hdr->no = old_hdr->no; + new_hdr->file = old_hdr->file; + new_hdr->line = old_hdr->line; + new_hdr->function = old_hdr->function; + new_hdr->size = new_size; + new_hdr->magic = DEBUG_MEMORY_MAGIC; + LIST_REPLACE(&old_hdr->head, &new_hdr->head); + + /* copy data */ + new_ptr = data_from_header(new_hdr); + memcpy( new_ptr, old_ptr, old_size < new_size ? old_size : new_size ); + + /* free old */ + old_hdr->magic = 0; + real_free(old_hdr); - debug_free( file, line, function, old_ptr ); return new_ptr; } @@ -162,7 +211,7 @@ debug_memory_end(unsigned long start_no) struct debug_memory_header *hdr; void *ptr; hdr = LIST_ENTRY(struct debug_memory_header, entry, head); - ptr = (void *)((char *)hdr + sizeof(*hdr)); + ptr = data_from_header(hdr); if(start_no <= hdr->no && hdr->no < last_no || last_no < start_no && (hdr->no < last_no || start_no <= hdr->no)) debug_printf("%s:%u:%s: %u bytes at %p not freed\n", diff --git a/src/gallium/auxiliary/util/u_double_list.h b/src/gallium/auxiliary/util/u_double_list.h index 8cb10c9820..d108d92e52 100644 --- a/src/gallium/auxiliary/util/u_double_list.h +++ b/src/gallium/auxiliary/util/u_double_list.h @@ -70,6 +70,14 @@ struct list_head (__list)->prev = (__item); \ } while(0) +#define LIST_REPLACE(__from, __to) \ + do { \ + (__to)->prev = (__from)->prev; \ + (__to)->next = (__from)->next; \ + (__from)->next->prev = (__to); \ + (__from)->prev->next = (__to); \ + } while (0) + #define LIST_DEL(__item) \ do { \ (__item)->prev->next = (__item)->next; \ diff --git a/src/gallium/auxiliary/util/u_snprintf.c b/src/gallium/auxiliary/util/u_snprintf.c index 48426abcb7..c4f4bbd30c 100644 --- a/src/gallium/auxiliary/util/u_snprintf.c +++ b/src/gallium/auxiliary/util/u_snprintf.c @@ -166,8 +166,8 @@ #include <config.h> #else #ifdef WIN32 -#define vsnprintf rpl_vsnprintf -#define snprintf rpl_snprintf +#define vsnprintf util_vsnprintf +#define snprintf util_snprintf #define HAVE_VSNPRINTF 0 #define HAVE_SNPRINTF 0 #define HAVE_VASPRINTF 1 /* not needed */ @@ -445,7 +445,7 @@ static UINTMAX_T myround(LDOUBLE); static LDOUBLE mypow10(int); int -rpl_vsnprintf(char *str, size_t size, const char *format, va_list args) +util_vsnprintf(char *str, size_t size, const char *format, va_list args) { LDOUBLE fvalue; INTMAX_T value; @@ -1404,7 +1404,7 @@ mymemcpy(void *dst, void *src, size_t len) #endif /* NEED_MYMEMCPY */ int -rpl_vasprintf(char **ret, const char *format, va_list ap) +util_vasprintf(char **ret, const char *format, va_list ap) { size_t size; int len; @@ -1422,10 +1422,10 @@ rpl_vasprintf(char **ret, const char *format, va_list ap) #if !HAVE_SNPRINTF #if HAVE_STDARG_H int -rpl_snprintf(char *str, size_t size, const char *format, ...) +util_snprintf(char *str, size_t size, const char *format, ...) #else int -rpl_snprintf(va_alist) va_dcl +util_snprintf(va_alist) va_dcl #endif /* HAVE_STDARG_H */ { #if !HAVE_STDARG_H @@ -1449,10 +1449,10 @@ rpl_snprintf(va_alist) va_dcl #if !HAVE_ASPRINTF #if HAVE_STDARG_H int -rpl_asprintf(char **ret, const char *format, ...) +util_asprintf(char **ret, const char *format, ...) #else int -rpl_asprintf(va_alist) va_dcl +util_asprintf(va_alist) va_dcl #endif /* HAVE_STDARG_H */ { #if !HAVE_STDARG_H diff --git a/src/gallium/auxiliary/util/u_string.h b/src/gallium/auxiliary/util/u_string.h new file mode 100644 index 0000000000..b99d4e8021 --- /dev/null +++ b/src/gallium/auxiliary/util/u_string.h @@ -0,0 +1,63 @@ +/************************************************************************** + * + * Copyright 2008 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. + * + **************************************************************************/ + +/** + * @file + * Platform independent functions for string manipulation. + * + * @author Jose Fonseca <jrfonseca@tungstengraphics.com> + */ + +#ifndef U_STRING_H_ +#define U_STRING_H_ + +#ifndef WIN32 +#include <stdio.h> +#endif +#include <stddef.h> +#include <stdarg.h> + + +#ifdef __cplusplus +extern "C" { +#endif + + +#ifdef WIN32 +int util_vsnprintf(char *, size_t, const char *, va_list); +int util_snprintf(char *str, size_t size, const char *format, ...); +#else +#define util_vsnprintf vsnprintf +#define util_snprintf snprintf +#endif + + +#ifdef __cplusplus +} +#endif + +#endif /* U_STRING_H_ */ diff --git a/src/gallium/auxiliary/util/u_time.c b/src/gallium/auxiliary/util/u_time.c new file mode 100644 index 0000000000..e6c0b19ff6 --- /dev/null +++ b/src/gallium/auxiliary/util/u_time.c @@ -0,0 +1,152 @@ +/************************************************************************** + * + * Copyright 2008 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. + * + **************************************************************************/ + +/** + * @file + * OS independent time-manipulation functions. + * + * @author Jose Fonseca <jrfonseca@tungstengraphics.com> + */ + + +#ifndef WIN32 +#include <sys/time.h> +#else +#include <windows.h> +#include <winddi.h> +#endif + +#include "util/u_time.h" + + +#ifdef WIN32 +static LONGLONG frequency = 0; +#endif + + +void +util_time_get(struct util_time *t) +{ +#ifndef WIN32 + gettimeofday(&t->tv, NULL); +#else + EngQueryPerformanceCounter(&t->counter); +#endif +} + + +void +util_time_add(const struct util_time *t1, + int64_t usecs, + struct util_time *t2) +{ +#ifndef WIN32 + t2->tv.tv_sec = t1->tv.tv_sec + usecs / 1000000; + t2->tv.tv_usec = t1->tv.tv_usec + usecs % 1000000; +#else + if(!frequency) + EngQueryPerformanceFrequency(&frequency); + t2->counter = t1->counter + (usecs * frequency + 999999LL)/1000000LL; +#endif +} + + +int64_t +util_time_diff(const struct util_time *t1, + const struct util_time *t2) +{ +#ifndef WIN32 + return (t2->tv.tv_usec - t1->tv.tv_usec) + + (t2->tv.tv_sec - t1->tv.tv_sec)*1000000; +#else + return (t2->counter - t1->counter)*1000000LL/frequency; +#endif +} + + +/** + * Compare two time values. + * + * Not publicly available because it does not take in account wrap-arounds. + * Use util_time_timeout instead. + */ +static INLINE int +util_time_compare(const struct util_time *t1, + const struct util_time *t2) +{ +#ifndef WIN32 + if (t1->tv.tv_sec < t2->tv.tv_sec) + return -1; + else if(t1->tv.tv_sec > t2->tv.tv_sec) + return 1; + else if (t1->tv.tv_usec < t2->tv.tv_usec) + return -1; + else if(t1->tv.tv_usec > t2->tv.tv_usec) + return 1; + else + return 0; +#else + if (t1->counter < t2->counter) + return -1; + else if(t1->counter > t2->counter) + return 1; + else + return 0; +#endif +} + + +int +util_time_timeout(const struct util_time *start, + const struct util_time *end, + const struct util_time *curr) +{ + if(util_time_compare(start, end) <= 0) + return util_time_compare(start, curr) <= 0 && util_time_compare(curr, end) < 0; + else + return util_time_compare(start, curr) <= 0 || util_time_compare(curr, end) < 0; +} + + +#ifdef WIN32 +void util_time_usleep(unsigned usecs) +{ + LONGLONG start, curr, end; + + EngQueryPerformanceCounter(&start); + + if(!frequency) + EngQueryPerformanceFrequency(&frequency); + + end = start + (usecs * frequency + 999999LL)/1000000LL; + + do { + EngQueryPerformanceCounter(&curr); + } while(start <= curr && curr < end || + end < start && (curr < end || start <= curr)); +} +#endif diff --git a/src/gallium/auxiliary/util/u_time.h b/src/gallium/auxiliary/util/u_time.h new file mode 100644 index 0000000000..32035cceb5 --- /dev/null +++ b/src/gallium/auxiliary/util/u_time.h @@ -0,0 +1,99 @@ +/************************************************************************** + * + * Copyright 2008 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. + * + **************************************************************************/ + +/** + * @file + * OS independent time-manipulation functions. + * + * @author Jose Fonseca <jrfonseca@tungstengraphics.com> + */ + +#ifndef U_TIME_H_ +#define U_TIME_H_ + + +#ifndef WIN32 +#include <time.h> /* timeval */ +#include <unistd.h> /* usleep */ +#endif + +#include "pipe/p_compiler.h" + + +#ifdef __cplusplus +extern "C" { +#endif + + +/** + * Time abstraction. + * + * Do not access this structure directly. Use the provided function instead. + */ +struct util_time +{ +#ifndef WIN32 + struct timeval tv; +#else + long long counter; +#endif +}; + + +void +util_time_get(struct util_time *t); + +void +util_time_add(const struct util_time *t1, + int64_t usecs, + struct util_time *t2); + +int64_t +util_time_diff(const struct util_time *t1, + const struct util_time *t2); + +/** + * Returns zero when the timeout expires, non zero otherwise. + */ +int +util_time_timeout(const struct util_time *start, + const struct util_time *end, + const struct util_time *curr); + +#ifndef WIN32 +#define util_time_sleep usleep +#else +int +util_time_sleep(unsigned usecs); +#endif + + +#ifdef __cplusplus +} +#endif + +#endif /* U_TIME_H_ */ |