Initial work for post-transform vertex feedback buffers.

This will be used for:
  GL_NV_transform_feedback, or GL3 equivalent.
  RasterPos
  GL select/feedback modes
This commit is contained in:
Brian 2007-09-06 17:03:54 -06:00
parent 4c01d498fa
commit 41ddd76b98

View file

@ -0,0 +1,247 @@
/**************************************************************************
*
* 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.
*
**************************************************************************/
/**
* Primitive/vertex feedback (and/or discard) stage.
* Used to implement transformation feedback/streaming and other things
* which require a post-transformed vertex position (such as rasterpos,
* selection and feedback modes).
*
* Authors:
* Brian Paul
*/
#include "pipe/p_util.h"
#include "draw_private.h"
struct feedback_stage {
struct draw_stage stage; /**< base class */
uint num_prim_generated; /**< number of primitives received */
uint num_prim_emitted; /**< number of primitives fed back */
uint num_vert_emitted; /**< number of vertices fed back */
uint max_vert_emit; /**< max number of verts we can emit */
float *dest[PIPE_MAX_FEEDBACK_ATTRIBS]; /**< dests for vertex attribs */
};
/**
* Check if there's space to store 'numVerts' in the feedback buffer(s).
*/
static boolean
check_space(const struct draw_stage *stage, uint numVerts)
{
const struct feedback_stage *fs = (struct feedback_stage *) stage;
return fs->num_vert_emitted + numVerts <= fs->max_vert_emit;
}
/**
* Record the given vertex's attributes into the feedback buffer(s).
*/
static void
feedback_vertex(struct draw_stage *stage, const struct vertex_header *vertex)
{
struct feedback_stage *fs = (struct feedback_stage *) stage;
const struct pipe_feedback_state *feedback = &stage->draw->feedback;
const uint select = feedback->interleaved ? 0 : 1;
uint i;
/*
* Note: 'select' is either 0 or 1. By multiplying 'i' by 'select'
* we can either address output buffer 0 (for interleaving) or
* output buffer i (for non-interleaved).
*/
for (i = 0; i < feedback->num_attribs; i++) {
const uint attr = feedback->attrib[i];
const float *src = attr ? vertex->data[attr] : vertex->clip;
const uint size = feedback->size[i];
float *dest = fs->dest[i * select];
switch (size) {
case 4:
dest[3] = src[3];
/* fall-through */
case 3:
dest[2] = src[2];
/* fall-through */
case 2:
dest[1] = src[1];
/* fall-through */
case 1:
dest[0] = src[0];
/* fall-through */
default:
;
}
fs->dest[i * select] += size;
}
fs->num_vert_emitted++;
}
static void feedback_begin( struct draw_stage *stage )
{
struct feedback_stage *fs = (struct feedback_stage *) stage;
const struct pipe_feedback_state *feedback = &stage->draw->feedback;
fs->num_prim_generated = 0;
fs->num_prim_emitted = 0;
fs->num_vert_emitted = 0;
assert(feedback->enabled);
/* Compute max_vert_emit, the max number of vertices we can emit.
* And, setup dest[] pointers.
*/
if (stage->draw->feedback.interleaved) {
uint i, vertex_size = 0;
/* compute size of each interleaved vertex, in floats */
for (i = 0; i < feedback->num_attribs; i++) {
vertex_size += feedback->size[i];
}
/* compute max number of vertices we can feedback */
fs->max_vert_emit = stage->draw->mapped_feedback_buffer_size[0]
/ sizeof(float) / vertex_size;
fs->dest[0] = (float *) stage->draw->mapped_feedback_buffer[0];
}
else {
uint i;
uint max = ~0;
for (i = 0; i < feedback->num_attribs; i++) {
uint n = stage->draw->mapped_feedback_buffer_size[i]
/ sizeof(float) / feedback->size[i];
if (n < max)
max = n;
fs->dest[i] = (float *) stage->draw->mapped_feedback_buffer[i];
}
fs->max_vert_emit = max;
}
if (!feedback->discard)
stage->next->begin( stage->next );
}
static void feedback_tri( struct draw_stage *stage,
struct prim_header *header )
{
struct feedback_stage *fs = (struct feedback_stage *) stage;
fs->num_prim_generated++;
if (stage->draw->feedback.enabled && check_space(stage, 3)) {
feedback_vertex(stage, header->v[0]);
feedback_vertex(stage, header->v[1]);
feedback_vertex(stage, header->v[2]);
fs->num_prim_emitted++;
}
if (!stage->draw->feedback.discard)
stage->next->tri( stage->next, header );
}
static void feedback_line( struct draw_stage *stage,
struct prim_header *header )
{
struct feedback_stage *fs = (struct feedback_stage *) stage;
fs->num_prim_generated++;
if (stage->draw->feedback.enabled && check_space(stage, 2)) {
feedback_vertex(stage, header->v[0]);
feedback_vertex(stage, header->v[1]);
fs->num_prim_emitted++;
}
if (!stage->draw->feedback.discard)
stage->next->line( stage->next, header );
}
static void feedback_point( struct draw_stage *stage,
struct prim_header *header )
{
struct feedback_stage *fs = (struct feedback_stage *) stage;
fs->num_prim_generated++;
if (stage->draw->feedback.enabled && check_space(stage, 1)) {
feedback_vertex(stage, header->v[0]);
fs->num_prim_emitted++;
}
if (!stage->draw->feedback.discard)
stage->next->point( stage->next, header );
}
static void feedback_end( struct draw_stage *stage )
{
/* XXX Unmap the vertex feedback buffers so we can write to them */
if (!stage->draw->feedback.discard)
stage->next->end( stage->next );
}
static void feedback_reset_stipple_counter( struct draw_stage *stage )
{
if (!stage->draw->feedback.discard)
stage->next->reset_stipple_counter( stage->next );
}
/**
* Create feedback drawing stage.
*/
struct draw_stage *draw_feedback_stage( struct draw_context *draw )
{
struct feedback_stage *feedback = CALLOC_STRUCT(feedback_stage);
feedback->stage.draw = draw;
feedback->stage.next = NULL;
feedback->stage.begin = feedback_begin;
feedback->stage.point = feedback_point;
feedback->stage.line = feedback_line;
feedback->stage.tri = feedback_tri;
feedback->stage.end = feedback_end;
feedback->stage.reset_stipple_counter = feedback_reset_stipple_counter;
return &feedback->stage;
}