vbo: Implement vbo_loopback_vertex_list in terms of the VAO.
Use the information already present in the VAO to replay a display list node using immediate mode draw commands. Use a hand full of helper methods that will be useful for the next patches also. v2: Insert asserts, constify local variables. Reviewed-by: Brian Paul <brianp@vmware.com> Signed-off-by: Mathias Fröhlich <Mathias.Froehlich@web.de>
This commit is contained in:
+48
-7
@@ -100,6 +100,52 @@ aligned_vertex_buffer_offset(const struct vbo_save_vertex_list *node)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the stride in bytes of the display list node.
|
||||
*/
|
||||
static inline GLsizei
|
||||
_vbo_save_get_stride(const struct vbo_save_vertex_list *node)
|
||||
{
|
||||
return node->VAO[0]->BufferBinding[0].Stride;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the first referenced vertex index in the display list node.
|
||||
*/
|
||||
static inline GLuint
|
||||
_vbo_save_get_min_index(const struct vbo_save_vertex_list *node)
|
||||
{
|
||||
assert(node->prim_count > 0);
|
||||
return node->prims[0].start;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the last referenced vertex index in the display list node.
|
||||
*/
|
||||
static inline GLuint
|
||||
_vbo_save_get_max_index(const struct vbo_save_vertex_list *node)
|
||||
{
|
||||
assert(node->prim_count > 0);
|
||||
const struct _mesa_prim *last_prim = &node->prims[node->prim_count - 1];
|
||||
return last_prim->start + last_prim->count - 1;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the vertex count in the display list node.
|
||||
*/
|
||||
static inline GLuint
|
||||
_vbo_save_get_vertex_count(const struct vbo_save_vertex_list *node)
|
||||
{
|
||||
assert(node->prim_count > 0);
|
||||
const struct _mesa_prim *first_prim = &node->prims[0];
|
||||
const struct _mesa_prim *last_prim = &node->prims[node->prim_count - 1];
|
||||
return last_prim->start - first_prim->start + last_prim->count;
|
||||
}
|
||||
|
||||
|
||||
/* These buffers should be a reasonable size to support upload to
|
||||
* hardware. Current vbo implementation will re-upload on any
|
||||
* changes, so don't make too big or apps which dynamically create
|
||||
@@ -178,13 +224,8 @@ void vbo_save_fallback(struct gl_context *ctx, GLboolean fallback);
|
||||
|
||||
/* save_loopback.c:
|
||||
*/
|
||||
void vbo_loopback_vertex_list(struct gl_context *ctx,
|
||||
const GLfloat *buffer,
|
||||
const GLubyte *attrsz,
|
||||
const struct _mesa_prim *prim,
|
||||
GLuint prim_count,
|
||||
GLuint wrap_count,
|
||||
GLuint vertex_size);
|
||||
void _vbo_loopback_vertex_list(struct gl_context *ctx,
|
||||
const struct vbo_save_vertex_list* node);
|
||||
|
||||
/* Callbacks:
|
||||
*/
|
||||
|
||||
+18
-24
@@ -641,6 +641,22 @@ compile_vertex_list(struct gl_context *ctx)
|
||||
|
||||
merge_prims(node->prims, &node->prim_count);
|
||||
|
||||
/* Correct the primitive starts, we can only do this here as copy_vertices
|
||||
* and convert_line_loop_to_strip above consume the uncorrected starts.
|
||||
* On the other hand the _vbo_loopback_vertex_list call below needs the
|
||||
* primitves to be corrected already.
|
||||
*/
|
||||
if (aligned_vertex_buffer_offset(node)) {
|
||||
const unsigned start_offset =
|
||||
node->buffer_offset / (node->vertex_size * sizeof(GLfloat));
|
||||
for (unsigned i = 0; i < node->prim_count; i++) {
|
||||
node->prims[i].start += start_offset;
|
||||
}
|
||||
node->start_vertex = start_offset;
|
||||
} else {
|
||||
node->start_vertex = 0;
|
||||
}
|
||||
|
||||
/* Deal with GL_COMPILE_AND_EXECUTE:
|
||||
*/
|
||||
if (ctx->ExecuteFlag) {
|
||||
@@ -648,13 +664,8 @@ compile_vertex_list(struct gl_context *ctx)
|
||||
|
||||
_glapi_set_dispatch(ctx->Exec);
|
||||
|
||||
const GLfloat *buffer = (const GLfloat *)
|
||||
((const char *) save->vertex_store->buffer_map +
|
||||
node->buffer_offset);
|
||||
|
||||
vbo_loopback_vertex_list(ctx, buffer,
|
||||
node->attrsz, node->prims, node->prim_count,
|
||||
node->wrap_count, node->vertex_size);
|
||||
/* Note that the range of referenced vertices must be mapped already */
|
||||
_vbo_loopback_vertex_list(ctx, node);
|
||||
|
||||
_glapi_set_dispatch(dispatch);
|
||||
}
|
||||
@@ -693,23 +704,6 @@ compile_vertex_list(struct gl_context *ctx)
|
||||
save->prim_store = alloc_prim_store();
|
||||
}
|
||||
|
||||
/*
|
||||
* If the vertex buffer offset is a multiple of the vertex size,
|
||||
* we can use the _mesa_prim::start value to indicate where the
|
||||
* vertices starts, instead of the buffer offset. Also see the
|
||||
* bind_vertex_list() function.
|
||||
*/
|
||||
if (aligned_vertex_buffer_offset(node)) {
|
||||
const unsigned start_offset =
|
||||
node->buffer_offset / (node->vertex_size * sizeof(GLfloat));
|
||||
for (unsigned i = 0; i < save->prim_count; i++) {
|
||||
save->prims[i].start += start_offset;
|
||||
}
|
||||
node->start_vertex = start_offset;
|
||||
} else {
|
||||
node->start_vertex = 0;
|
||||
}
|
||||
|
||||
/* Reset our structures for the next run of vertices:
|
||||
*/
|
||||
reset_counters(ctx);
|
||||
|
||||
@@ -144,26 +144,14 @@ static void
|
||||
loopback_vertex_list(struct gl_context *ctx,
|
||||
const struct vbo_save_vertex_list *list)
|
||||
{
|
||||
const char *buffer =
|
||||
ctx->Driver.MapBufferRange(ctx, 0,
|
||||
list->vertex_store->bufferobj->Size,
|
||||
GL_MAP_READ_BIT, /* ? */
|
||||
list->vertex_store->bufferobj,
|
||||
MAP_INTERNAL);
|
||||
struct gl_buffer_object *bo = list->VAO[0]->BufferBinding[0].BufferObj;
|
||||
ctx->Driver.MapBufferRange(ctx, 0, bo->Size, GL_MAP_READ_BIT, /* ? */
|
||||
bo, MAP_INTERNAL);
|
||||
|
||||
unsigned buffer_offset =
|
||||
aligned_vertex_buffer_offset(list) ? 0 : list->buffer_offset;
|
||||
/* Note that the range of referenced vertices must be mapped already */
|
||||
_vbo_loopback_vertex_list(ctx, list);
|
||||
|
||||
vbo_loopback_vertex_list(ctx,
|
||||
(const GLfloat *) (buffer + buffer_offset),
|
||||
list->attrsz,
|
||||
list->prims,
|
||||
list->prim_count,
|
||||
list->wrap_count,
|
||||
list->vertex_size);
|
||||
|
||||
ctx->Driver.UnmapBuffer(ctx, list->vertex_store->bufferobj,
|
||||
MAP_INTERNAL);
|
||||
ctx->Driver.UnmapBuffer(ctx, bo, MAP_INTERNAL);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -81,8 +81,8 @@ static attr_func vert_attrfunc[4] = {
|
||||
|
||||
|
||||
struct loopback_attr {
|
||||
GLint index;
|
||||
GLint sz;
|
||||
enum vbo_attrib index;
|
||||
GLuint offset;
|
||||
attr_func func;
|
||||
};
|
||||
|
||||
@@ -94,17 +94,15 @@ struct loopback_attr {
|
||||
*/
|
||||
static void
|
||||
loopback_prim(struct gl_context *ctx,
|
||||
const GLfloat *buffer,
|
||||
const GLubyte *buffer,
|
||||
const struct _mesa_prim *prim,
|
||||
GLuint wrap_count,
|
||||
GLuint vertex_size,
|
||||
GLuint stride,
|
||||
const struct loopback_attr *la, GLuint nr)
|
||||
{
|
||||
GLint start = prim->start;
|
||||
GLint end = start + prim->count;
|
||||
const GLfloat *data;
|
||||
GLint j;
|
||||
GLuint k;
|
||||
GLuint start = prim->start;
|
||||
const GLuint end = start + prim->count;
|
||||
const GLubyte *data;
|
||||
|
||||
if (0)
|
||||
printf("loopback prim %s(%s,%s) verts %d..%d vsize %d\n",
|
||||
@@ -112,7 +110,7 @@ loopback_prim(struct gl_context *ctx,
|
||||
prim->begin ? "begin" : "..",
|
||||
prim->end ? "end" : "..",
|
||||
start, end,
|
||||
vertex_size);
|
||||
stride);
|
||||
|
||||
if (prim->begin) {
|
||||
CALL_Begin(GET_DISPATCH(), (prim->mode));
|
||||
@@ -121,20 +119,13 @@ loopback_prim(struct gl_context *ctx,
|
||||
start += wrap_count;
|
||||
}
|
||||
|
||||
data = buffer + start * vertex_size;
|
||||
data = buffer + start * stride;
|
||||
|
||||
for (j = start; j < end; j++) {
|
||||
const GLfloat *tmp = data + la[0].sz;
|
||||
for (GLuint j = start; j < end; j++) {
|
||||
for (GLuint k = 0; k < nr; k++)
|
||||
la[k].func(ctx, la[k].index, (const GLfloat *)(data + la[k].offset));
|
||||
|
||||
for (k = 1; k < nr; k++) {
|
||||
la[k].func(ctx, la[k].index, tmp);
|
||||
tmp += la[k].sz;
|
||||
}
|
||||
|
||||
/* Fire the vertex
|
||||
*/
|
||||
la[0].func(ctx, VBO_ATTRIB_POS, data);
|
||||
data = tmp;
|
||||
data += stride;
|
||||
}
|
||||
|
||||
if (prim->end) {
|
||||
@@ -167,36 +158,80 @@ loopback_weak_prim(struct gl_context *ctx,
|
||||
}
|
||||
|
||||
|
||||
static inline void
|
||||
append_attr(GLuint *nr, struct loopback_attr la[], int i, int shift,
|
||||
const struct gl_vertex_array_object *vao)
|
||||
{
|
||||
la[*nr].index = shift + i;
|
||||
la[*nr].offset = vao->VertexAttrib[i].RelativeOffset;
|
||||
la[*nr].func = vert_attrfunc[vao->VertexAttrib[i].Size - 1];
|
||||
(*nr)++;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
vbo_loopback_vertex_list(struct gl_context *ctx,
|
||||
const GLfloat *buffer,
|
||||
const GLubyte *attrsz,
|
||||
const struct _mesa_prim *prim,
|
||||
GLuint prim_count,
|
||||
GLuint wrap_count,
|
||||
GLuint vertex_size)
|
||||
_vbo_loopback_vertex_list(struct gl_context *ctx,
|
||||
const struct vbo_save_vertex_list* node)
|
||||
{
|
||||
struct loopback_attr la[VBO_ATTRIB_MAX];
|
||||
GLuint i, nr = 0;
|
||||
GLuint nr = 0;
|
||||
|
||||
/* All Legacy, NV, ARB and Material attributes are routed through
|
||||
* the NV attributes entrypoints:
|
||||
*/
|
||||
for (i = 0; i < VBO_ATTRIB_MAX; i++) {
|
||||
if (attrsz[i]) {
|
||||
la[nr].index = i;
|
||||
la[nr].sz = attrsz[i];
|
||||
la[nr].func = vert_attrfunc[attrsz[i]-1];
|
||||
nr++;
|
||||
}
|
||||
const struct gl_vertex_array_object *vao = node->VAO[VP_MODE_FF];
|
||||
GLbitfield mask = vao->_Enabled & VERT_BIT_MAT_ALL;
|
||||
while (mask) {
|
||||
const int i = u_bit_scan(&mask);
|
||||
append_attr(&nr, la, i, VBO_MATERIAL_SHIFT, vao);
|
||||
}
|
||||
|
||||
for (i = 0; i < prim_count; i++) {
|
||||
if ((prim[i].mode & VBO_SAVE_PRIM_WEAK) &&
|
||||
_mesa_inside_begin_end(ctx)) {
|
||||
loopback_weak_prim(ctx, &prim[i]);
|
||||
vao = node->VAO[VP_MODE_SHADER];
|
||||
mask = vao->_Enabled & ~(VERT_BIT_POS | VERT_BIT_GENERIC0);
|
||||
while (mask) {
|
||||
const int i = u_bit_scan(&mask);
|
||||
append_attr(&nr, la, i, 0, vao);
|
||||
}
|
||||
|
||||
/* The last in the list should be the vertex provoking attribute */
|
||||
if (vao->_Enabled & VERT_BIT_GENERIC0) {
|
||||
append_attr(&nr, la, VERT_ATTRIB_GENERIC0, 0, vao);
|
||||
} else if (vao->_Enabled & VERT_BIT_POS) {
|
||||
append_attr(&nr, la, VERT_ATTRIB_POS, 0, vao);
|
||||
}
|
||||
|
||||
const GLuint wrap_count = node->wrap_count;
|
||||
const GLuint stride = _vbo_save_get_stride(node);
|
||||
const GLubyte *buffer = NULL;
|
||||
if (0 < nr) {
|
||||
/* Compute the minimal offset into the vertex buffer object */
|
||||
GLuint offset = ~0u;
|
||||
for (GLuint i = 0; i < nr; ++i)
|
||||
offset = MIN2(offset, la[i].offset);
|
||||
for (GLuint i = 0; i < nr; ++i)
|
||||
la[i].offset -= offset;
|
||||
|
||||
/* Get the mapped base pointer, assert sufficient mapping */
|
||||
struct gl_buffer_object *bufferobj = vao->BufferBinding[0].BufferObj;
|
||||
assert(bufferobj && bufferobj->Mappings[MAP_INTERNAL].Pointer);
|
||||
buffer = bufferobj->Mappings[MAP_INTERNAL].Pointer;
|
||||
assert(bufferobj->Mappings[MAP_INTERNAL].Offset
|
||||
<= vao->BufferBinding[0].Offset + offset
|
||||
+ stride*(_vbo_save_get_min_index(node) + wrap_count));
|
||||
buffer += vao->BufferBinding[0].Offset + offset
|
||||
- bufferobj->Mappings[MAP_INTERNAL].Offset;
|
||||
assert(stride*(_vbo_save_get_vertex_count(node) - wrap_count)
|
||||
<= bufferobj->Mappings[MAP_INTERNAL].Length);
|
||||
}
|
||||
|
||||
/* Replay the primitives */
|
||||
const struct _mesa_prim *prims = node->prims;
|
||||
const GLuint prim_count = node->prim_count;
|
||||
for (GLuint i = 0; i < prim_count; i++) {
|
||||
if ((prims[i].mode & VBO_SAVE_PRIM_WEAK) && _mesa_inside_begin_end(ctx)) {
|
||||
loopback_weak_prim(ctx, &prims[i]);
|
||||
} else {
|
||||
loopback_prim(ctx, buffer, &prim[i], wrap_count, vertex_size, la, nr);
|
||||
loopback_prim(ctx, buffer, &prims[i], wrap_count, stride, la, nr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user