draw: draw_range_elements trial

This commit is contained in:
Keith Whitwell 2008-05-29 11:46:43 +01:00
parent cb87d7e44a
commit 82605d7bcd
13 changed files with 404 additions and 17 deletions

View File

@ -348,14 +348,30 @@ void draw_set_edgeflags( struct draw_context *draw,
* \param elements the element buffer ptr
*/
void
draw_set_mapped_element_buffer( struct draw_context *draw,
unsigned eltSize, void *elements )
draw_set_mapped_element_buffer_range( struct draw_context *draw,
unsigned eltSize,
unsigned min_index,
unsigned max_index,
void *elements )
{
draw->pt.user.elts = elements;
draw->pt.user.eltSize = eltSize;
draw->pt.user.min_index = min_index;
draw->pt.user.max_index = max_index;
}
void
draw_set_mapped_element_buffer( struct draw_context *draw,
unsigned eltSize,
void *elements )
{
draw->pt.user.elts = elements;
draw->pt.user.eltSize = eltSize;
draw->pt.user.min_index = 0;
draw->pt.user.max_index = 0xffffffff;
}
/* Revamp me please:
*/

View File

@ -118,8 +118,16 @@ void draw_set_vertex_elements(struct draw_context *draw,
unsigned count,
const struct pipe_vertex_element *elements);
void
draw_set_mapped_element_buffer_range( struct draw_context *draw,
unsigned eltSize,
unsigned min_index,
unsigned max_index,
void *elements );
void draw_set_mapped_element_buffer( struct draw_context *draw,
unsigned eltSize, void *elements );
unsigned eltSize,
void *elements );
void draw_set_mapped_vertex_buffer(struct draw_context *draw,
unsigned attr, const void *buffer);

View File

@ -147,6 +147,8 @@ struct draw_context
const void *elts;
/** bytes per index (0, 1, 2 or 4) */
unsigned eltSize;
unsigned min_index;
unsigned max_index;
/** vertex arrays */
const void *vbuffer[PIPE_MAX_ATTRIBS];

View File

@ -96,6 +96,15 @@ struct draw_pt_middle_end {
unsigned start,
unsigned count);
/* Transform all vertices in a linear range and then draw them with
* the supplied element list.
*/
void (*run_linear_elts)( struct draw_pt_middle_end *,
unsigned fetch_start,
unsigned fetch_count,
const ushort *draw_elts,
unsigned draw_count );
void (*finish)( struct draw_pt_middle_end * );
void (*destroy)( struct draw_pt_middle_end * );
};

View File

@ -311,6 +311,53 @@ static void fetch_emit_run_linear( struct draw_pt_middle_end *middle,
}
static void fetch_emit_run_linear_elts( struct draw_pt_middle_end *middle,
unsigned start,
unsigned count,
const ushort *draw_elts,
unsigned draw_count )
{
struct fetch_emit_middle_end *feme = (struct fetch_emit_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->translate->key.output_stride,
(ushort)count );
if (!hw_verts) {
assert(0);
return;
}
/* Single routine to fetch vertices and emit HW verts.
*/
feme->translate->run( feme->translate,
start,
count,
hw_verts );
/* XXX: Draw arrays path to avoid re-emitting index list again and
* again.
*/
draw->render->draw( draw->render,
draw_elts,
draw_count );
/* Done -- that was easy, wasn't it:
*/
draw->render->release_vertices( draw->render,
hw_verts,
feme->translate->key.output_stride,
count );
}
static void fetch_emit_finish( struct draw_pt_middle_end *middle )
{
@ -343,6 +390,7 @@ struct draw_pt_middle_end *draw_pt_fetch_emit( struct draw_context *draw )
fetch_emit->base.prepare = fetch_emit_prepare;
fetch_emit->base.run = fetch_emit_run;
fetch_emit->base.run_linear = fetch_emit_run_linear;
fetch_emit->base.run_linear_elts = fetch_emit_run_linear_elts;
fetch_emit->base.finish = fetch_emit_finish;
fetch_emit->base.destroy = fetch_emit_destroy;

View File

@ -310,6 +310,54 @@ fse_run(struct draw_pt_middle_end *middle,
}
static void fse_run_linear_elts( struct draw_pt_middle_end *middle,
unsigned start,
unsigned count,
const ushort *draw_elts,
unsigned draw_count )
{
struct fetch_shade_emit *fse = (struct fetch_shade_emit *)middle;
struct draw_context *draw = fse->draw;
unsigned alloc_count = align(count, 4);
char *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)fse->key.output_stride,
(ushort)alloc_count );
if (!hw_verts) {
assert(0);
return;
}
/* Single routine to fetch vertices, run shader and emit HW verts.
* Clipping is done elsewhere -- either by the API or on hardware,
* or for some other reason not required...
*/
fse->active->run_linear( fse->active,
start, count,
hw_verts );
draw->render->draw( draw->render,
draw_elts,
draw_count );
draw->render->release_vertices( draw->render,
hw_verts,
fse->key.output_stride,
count );
}
static void fse_finish( struct draw_pt_middle_end *middle )
{
}
@ -330,6 +378,7 @@ struct draw_pt_middle_end *draw_pt_middle_fse( struct draw_context *draw )
fse->base.prepare = fse_prepare;
fse->base.run = fse_run;
fse->base.run_linear = fse_run_linear;
fse->base.run_linear_elts = fse_run_linear_elts;
fse->base.finish = fse_finish;
fse->base.destroy = fse_destroy;
fse->draw = draw;

View File

@ -98,7 +98,6 @@ static void fetch_pipeline_prepare( struct draw_pt_middle_end *middle,
static void fetch_pipeline_run( struct draw_pt_middle_end *middle,
const unsigned *fetch_elts,
unsigned fetch_count,
@ -251,6 +250,84 @@ static void fetch_pipeline_linear_run( struct draw_pt_middle_end *middle,
static void fetch_pipeline_linear_run_elts( struct draw_pt_middle_end *middle,
unsigned start,
unsigned 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->vs.vertex_shader;
unsigned opt = fpme->opt;
unsigned alloc_count = align_int( count, 4 );
struct vertex_header *pipeline_verts =
(struct vertex_header *)MALLOC(fpme->vertex_size * alloc_count);
if (!pipeline_verts) {
/* Not much we can do here - just skip the rendering.
*/
assert(0);
return;
}
/* Fetch into our vertex buffer
*/
draw_pt_fetch_run_linear( fpme->fetch,
start,
count,
(char *)pipeline_verts );
/* Run the shader, note that this overwrites the data[] parts of
* the pipeline verts. If there is no shader, ie a bypass shader,
* then the inputs == outputs, and are already in the correct
* place.
*/
if (opt & PT_SHADE)
{
shader->run_linear(shader,
(const float (*)[4])pipeline_verts->data,
( float (*)[4])pipeline_verts->data,
(const float (*)[4])draw->pt.user.constants,
count,
fpme->vertex_size,
fpme->vertex_size);
}
if (draw_pt_post_vs_run( fpme->post_vs,
pipeline_verts,
count,
fpme->vertex_size ))
{
opt |= PT_PIPELINE;
}
/* Do we need to run the pipeline?
*/
if (opt & PT_PIPELINE) {
draw_pipeline_run( fpme->draw,
fpme->prim,
pipeline_verts,
count,
fpme->vertex_size,
draw_elts,
draw_count );
}
else {
draw_pt_emit( fpme->emit,
(const float (*)[4])pipeline_verts->data,
count,
fpme->vertex_size,
draw_elts,
draw_count );
}
FREE(pipeline_verts);
}
static void fetch_pipeline_finish( struct draw_pt_middle_end *middle )
{
/* nothing to do */
@ -282,6 +359,7 @@ struct draw_pt_middle_end *draw_pt_fetch_pipeline_or_emit( struct draw_context *
fpme->base.prepare = fetch_pipeline_prepare;
fpme->base.run = fetch_pipeline_run;
fpme->base.run_linear = fetch_pipeline_linear_run;
fpme->base.run_linear_elts = fetch_pipeline_linear_run_elts;
fpme->base.finish = fetch_pipeline_finish;
fpme->base.destroy = fetch_pipeline_destroy;

View File

@ -36,8 +36,8 @@
#include "draw/draw_pt.h"
#define CACHE_MAX 32
#define FETCH_MAX 128
#define CACHE_MAX 1024
#define FETCH_MAX 4096
#define DRAW_MAX (16*1024)
struct vcache_frontend {
@ -201,7 +201,124 @@ static void vcache_ef_quad( struct vcache_frontend *vcache,
#define FUNC vcache_run
#include "draw_pt_vcache_tmp.h"
static void translate_uint_elts( const unsigned *src,
unsigned count,
int delta,
ushort *dest )
{
unsigned i;
for (i = 0; i < count; i++)
dest[i] = (ushort)(src[i] + delta);
}
static void translate_ushort_elts( const ushort *src,
unsigned count,
int delta,
ushort *dest )
{
unsigned i;
for (i = 0; i < count; i++)
dest[i] = (ushort)(src[i] + delta);
}
static void translate_ubyte_elts( const ubyte *src,
unsigned count,
int delta,
ushort *dest )
{
unsigned i;
for (i = 0; i < count; i++)
dest[i] = (ushort)(src[i] + delta);
}
#if 0
static enum pipe_format format_from_get_elt( pt_elt_func get_elt )
{
switch (draw->pt.user.eltSize) {
case 1: return PIPE_FORMAT_R8_UNORM;
case 2: return PIPE_FORMAT_R16_UNORM;
case 4: return PIPE_FORMAT_R32_UNORM;
default: return PIPE_FORMAT_NONE;
}
}
#endif
static void vcache_check_run( struct draw_pt_front_end *frontend,
pt_elt_func get_elt,
const void *elts,
unsigned draw_count )
{
struct vcache_frontend *vcache = (struct vcache_frontend *)frontend;
struct draw_context *draw = vcache->draw;
unsigned min_index = draw->pt.user.min_index;
unsigned max_index = draw->pt.user.max_index;
unsigned index_size = draw->pt.user.eltSize;
unsigned fetch_count = MAX2(max_index, max_index + 1 - min_index);
const ushort *transformed_elts;
ushort *storage = NULL;
printf("fetch_count %x\n", fetch_count);
if (fetch_count >= FETCH_MAX ||
fetch_count > draw_count)
goto fail;
if (min_index == 0 &&
index_size == 2)
{
transformed_elts = (const ushort *)elts;
}
else
{
storage = MALLOC( draw_count * sizeof(ushort) );
if (!storage)
goto fail;
switch(index_size) {
case 1:
translate_ubyte_elts( (const ubyte *)elts,
draw_count,
0 - (int)min_index,
storage );
break;
case 2:
translate_ushort_elts( (const ushort *)elts,
draw_count,
0 - (int)min_index,
storage );
break;
case 4:
translate_uint_elts( (const uint *)elts,
draw_count,
0 - (int)min_index,
storage );
break;
default:
assert(0);
return;
}
transformed_elts = storage;
}
vcache->middle->run_linear_elts( vcache->middle,
min_index, /* start */
fetch_count,
transformed_elts,
draw_count );
FREE(storage);
return;
fail:
vcache_run( frontend, get_elt, elts, draw_count );
}
@ -219,7 +336,7 @@ static void vcache_prepare( struct draw_pt_front_end *frontend,
}
else
{
vcache->base.run = vcache_run;
vcache->base.run = vcache_check_run;
}
vcache->input_prim = prim;

View File

@ -179,6 +179,7 @@ softpipe_create( struct pipe_screen *screen,
softpipe->pipe.draw_arrays = softpipe_draw_arrays;
softpipe->pipe.draw_elements = softpipe_draw_elements;
softpipe->pipe.draw_range_elements = softpipe_draw_range_elements;
softpipe->pipe.set_edgeflags = softpipe_set_edgeflags;

View File

@ -108,11 +108,14 @@ softpipe_draw_arrays(struct pipe_context *pipe, unsigned mode,
*
* XXX should the element buffer be specified/bound with a separate function?
*/
boolean
softpipe_draw_elements(struct pipe_context *pipe,
struct pipe_buffer *indexBuffer,
unsigned indexSize,
unsigned mode, unsigned start, unsigned count)
softpipe_draw_range_elements(struct pipe_context *pipe,
struct pipe_buffer *indexBuffer,
unsigned indexSize,
unsigned min_index,
unsigned max_index,
unsigned mode, unsigned start, unsigned count)
{
struct softpipe_context *sp = softpipe_context(pipe);
struct draw_context *draw = sp->draw;
@ -141,11 +144,14 @@ softpipe_draw_elements(struct pipe_context *pipe,
void *mapped_indexes
= pipe->winsys->buffer_map(pipe->winsys, indexBuffer,
PIPE_BUFFER_USAGE_CPU_READ);
draw_set_mapped_element_buffer(draw, indexSize, mapped_indexes);
draw_set_mapped_element_buffer_range(draw, indexSize,
min_index,
max_index,
mapped_indexes);
}
else {
/* no index/element buffer */
draw_set_mapped_element_buffer(draw, 0, NULL);
draw_set_mapped_element_buffer_range(draw, 0, start, start + count - 1, NULL);
}
@ -171,6 +177,19 @@ softpipe_draw_elements(struct pipe_context *pipe,
return TRUE;
}
boolean
softpipe_draw_elements(struct pipe_context *pipe,
struct pipe_buffer *indexBuffer,
unsigned indexSize,
unsigned mode, unsigned start, unsigned count)
{
return softpipe_draw_range_elements( pipe, indexBuffer,
indexSize,
0, 0xffffffff,
mode, start, count );
}
void
softpipe_set_edgeflags(struct pipe_context *pipe, const unsigned *edgeflags)

View File

@ -171,6 +171,13 @@ boolean softpipe_draw_elements(struct pipe_context *pipe,
struct pipe_buffer *indexBuffer,
unsigned indexSize,
unsigned mode, unsigned start, unsigned count);
boolean
softpipe_draw_range_elements(struct pipe_context *pipe,
struct pipe_buffer *indexBuffer,
unsigned indexSize,
unsigned min_index,
unsigned max_index,
unsigned mode, unsigned start, unsigned count);
void
softpipe_set_edgeflags(struct pipe_context *pipe, const unsigned *edgeflags);

View File

@ -76,6 +76,20 @@ struct pipe_context {
struct pipe_buffer *indexBuffer,
unsigned indexSize,
unsigned mode, unsigned start, unsigned count);
/* XXX: this is (probably) a temporary entrypoint, as the range
* information should be available from the vertex_buffer state.
* Using this to quickly evaluate a specialized path in the draw
* module.
*/
boolean (*draw_range_elements)( struct pipe_context *pipe,
struct pipe_buffer *indexBuffer,
unsigned indexSize,
unsigned minIndex,
unsigned maxIndex,
unsigned mode,
unsigned start,
unsigned count);
/*@}*/

View File

@ -365,14 +365,33 @@ st_draw_vbo(GLcontext *ctx,
}
/* draw */
for (i = 0; i < nr_prims; i++) {
if (nr_prims == 1 && pipe->draw_range_elements != NULL) {
i = 0;
/* XXX: exercise temporary path to pass min/max directly
* through to driver & draw module. These interfaces still
* need a bit of work...
*/
setup_edgeflags(ctx, prims[i].mode,
prims[i].start + indexOffset, prims[i].count,
arrays[VERT_ATTRIB_EDGEFLAG]);
pipe->draw_elements(pipe, indexBuf, indexSize,
prims[i].mode,
prims[i].start + indexOffset, prims[i].count);
pipe->draw_range_elements(pipe, indexBuf, indexSize,
min_index,
max_index,
prims[i].mode,
prims[i].start + indexOffset, prims[i].count);
}
else {
for (i = 0; i < nr_prims; i++) {
setup_edgeflags(ctx, prims[i].mode,
prims[i].start + indexOffset, prims[i].count,
arrays[VERT_ATTRIB_EDGEFLAG]);
pipe->draw_elements(pipe, indexBuf, indexSize,
prims[i].mode,
prims[i].start + indexOffset, prims[i].count);
}
}
pipe_reference_buffer(pipe, &indexBuf, NULL);