X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;ds=sidebyside;f=src%2Fmesa%2Fvbo%2Fvbo_save_draw.c;h=a63e0674d898047510b7b85750651ef66564efc0;hb=67dc551ba9e1c05fdd9b67ebec16debbb5ae1a32;hp=d0454bf6212da8bf8d03b0c47266cbe36235fd78;hpb=a96fe679e2f57e8e4e26c38660d8b6e5b67d5b4b;p=mesa.git diff --git a/src/mesa/vbo/vbo_save_draw.c b/src/mesa/vbo/vbo_save_draw.c index d0454bf6212..a63e0674d89 100644 --- a/src/mesa/vbo/vbo_save_draw.c +++ b/src/mesa/vbo/vbo_save_draw.c @@ -1,6 +1,5 @@ /* * Mesa 3-D graphics library - * Version: 7.2 * * Copyright (C) 1999-2008 Brian Paul All Rights Reserved. * @@ -17,43 +16,41 @@ * 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 NONINFRINGEMENT. IN NO EVENT SHALL - * BRIAN PAUL 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 AUTHORS OR COPYRIGHT HOLDERS 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. */ /* Author: - * Keith Whitwell + * Keith Whitwell */ #include "main/glheader.h" #include "main/bufferobj.h" #include "main/context.h" #include "main/imports.h" -#include "main/mfeatures.h" #include "main/mtypes.h" #include "main/macros.h" #include "main/light.h" #include "main/state.h" +#include "util/bitscan.h" #include "vbo_context.h" -#if FEATURE_dlist - - /** * After playback, copy everything but the position from the * last vertex to the saved state */ static void -_playback_copy_to_current(struct gl_context *ctx, - const struct vbo_save_vertex_list *node) +playback_copy_to_current(struct gl_context *ctx, + const struct vbo_save_vertex_list *node) { struct vbo_context *vbo = vbo_context(ctx); - GLfloat vertex[VBO_ATTRIB_MAX * 4]; - GLfloat *data; - GLuint i, offset; + fi_type vertex[VBO_ATTRIB_MAX * 4]; + fi_type *data; + GLbitfield64 mask; if (node->current_size == 0) return; @@ -62,44 +59,51 @@ _playback_copy_to_current(struct gl_context *ctx, data = node->current_data; } else { - data = vertex; + /* Position of last vertex */ + const GLuint pos = node->vertex_count > 0 ? node->vertex_count - 1 : 0; + /* Offset to last vertex in the vertex buffer */ + const GLuint offset = node->buffer_offset + + pos * node->vertex_size * sizeof(GLfloat); - if (node->count) - offset = (node->buffer_offset + - (node->count-1) * node->vertex_size * sizeof(GLfloat)); - else - offset = node->buffer_offset; + data = vertex; - ctx->Driver.GetBufferSubData( ctx, 0, offset, - node->vertex_size * sizeof(GLfloat), - data, node->vertex_store->bufferobj ); + ctx->Driver.GetBufferSubData(ctx, offset, + node->vertex_size * sizeof(GLfloat), + data, node->vertex_store->bufferobj); data += node->attrsz[0]; /* skip vertex position */ } - for (i = VBO_ATTRIB_POS+1 ; i < VBO_ATTRIB_MAX ; i++) { - if (node->attrsz[i]) { - GLfloat *current = (GLfloat *)vbo->currval[i].Ptr; - GLfloat tmp[4]; - - COPY_CLEAN_4V(tmp, - node->attrsz[i], - data); - - if (memcmp(current, tmp, 4 * sizeof(GLfloat)) != 0) { - memcpy(current, tmp, 4 * sizeof(GLfloat)); - - vbo->currval[i].Size = node->attrsz[i]; - - if (i >= VBO_ATTRIB_FIRST_MATERIAL && - i <= VBO_ATTRIB_LAST_MATERIAL) - ctx->NewState |= _NEW_LIGHT; - - ctx->NewState |= _NEW_CURRENT_ATTRIB; - } - - data += node->attrsz[i]; + mask = node->enabled & (~BITFIELD64_BIT(VBO_ATTRIB_POS)); + while (mask) { + const int i = u_bit_scan64(&mask); + fi_type *current = (fi_type *)vbo->currval[i].Ptr; + fi_type tmp[4]; + assert(node->attrsz[i]); + + COPY_CLEAN_4V_TYPE_AS_UNION(tmp, + node->attrsz[i], + data, + node->attrtype[i]); + + if (node->attrtype[i] != vbo->currval[i].Type || + memcmp(current, tmp, 4 * sizeof(GLfloat)) != 0) { + memcpy(current, tmp, 4 * sizeof(GLfloat)); + + vbo->currval[i].Size = node->attrsz[i]; + vbo->currval[i]._ElementSize = vbo->currval[i].Size * sizeof(GLfloat); + vbo->currval[i].Type = node->attrtype[i]; + vbo->currval[i].Integer = + vbo_attrtype_to_integer_flag(node->attrtype[i]); + + if (i >= VBO_ATTRIB_FIRST_MATERIAL && + i <= VBO_ATTRIB_LAST_MATERIAL) + ctx->NewState |= _NEW_LIGHT; + + ctx->NewState |= _NEW_CURRENT_ATTRIB; } + + data += node->attrsz[i]; } /* Colormaterial -- this kindof sucks. @@ -111,11 +115,11 @@ _playback_copy_to_current(struct gl_context *ctx, /* CurrentExecPrimitive */ if (node->prim_count) { - const struct _mesa_prim *prim = &node->prim[node->prim_count - 1]; + const struct _mesa_prim *prim = &node->prims[node->prim_count - 1]; if (prim->end) - ctx->Driver.CurrentExecPrimitive = PRIM_OUTSIDE_BEGIN_END; + ctx->Driver.CurrentExecPrimitive = PRIM_OUTSIDE_BEGIN_END; else - ctx->Driver.CurrentExecPrimitive = prim->mode; + ctx->Driver.CurrentExecPrimitive = prim->mode; } } @@ -125,42 +129,53 @@ _playback_copy_to_current(struct gl_context *ctx, * Treat the vertex storage as a VBO, define vertex arrays pointing * into it: */ -static void vbo_bind_vertex_list(struct gl_context *ctx, - const struct vbo_save_vertex_list *node) +static void +bind_vertex_list(struct gl_context *ctx, + const struct vbo_save_vertex_list *node) { struct vbo_context *vbo = vbo_context(ctx); struct vbo_save_context *save = &vbo->save; - struct gl_client_array *arrays = save->arrays; + struct gl_vertex_array *arrays = save->arrays; GLuint buffer_offset = node->buffer_offset; - const GLuint *map; + const GLubyte *map; GLuint attr; GLubyte node_attrsz[VBO_ATTRIB_MAX]; /* copy of node->attrsz[] */ + GLenum node_attrtype[VBO_ATTRIB_MAX]; /* copy of node->attrtype[] */ GLbitfield varying_inputs = 0x0; memcpy(node_attrsz, node->attrsz, sizeof(node->attrsz)); + memcpy(node_attrtype, node->attrtype, sizeof(node->attrtype)); + + if (aligned_vertex_buffer_offset(node)) { + /* The vertex size is an exact multiple of the buffer offset. + * This means that we can use zero-based vertex attribute pointers + * and specify the start of the primitive with the _mesa_prim::start + * field. This results in issuing several draw calls with identical + * vertex attribute information. This can result in fewer state + * changes in drivers. In particular, the Gallium CSO module will + * filter out redundant vertex buffer changes. + */ + buffer_offset = 0; + } - /* Install the default (ie Current) attributes first, then overlay - * all active ones. - */ + /* Install the default (ie Current) attributes first */ + for (attr = 0; attr < VERT_ATTRIB_FF_MAX; attr++) { + save->inputs[attr] = &vbo->currval[VBO_ATTRIB_POS + attr]; + } + + /* Overlay other active attributes */ switch (get_program_mode(ctx)) { case VP_NONE: - for (attr = 0; attr < 16; attr++) { - save->inputs[attr] = &vbo->legacy_currval[attr]; - } for (attr = 0; attr < MAT_ATTRIB_MAX; attr++) { - save->inputs[attr + 16] = &vbo->mat_currval[attr]; + save->inputs[VERT_ATTRIB_GENERIC(attr)] = + &vbo->currval[VBO_ATTRIB_MAT_FRONT_AMBIENT+attr]; } map = vbo->map_vp_none; break; - case VP_NV: case VP_ARB: - /* The aliasing of attributes for NV vertex programs has already - * occurred. NV vertex programs cannot access material values, - * nor attributes greater than VERT_ATTRIB_TEX7. - */ - for (attr = 0; attr < 16; attr++) { - save->inputs[attr] = &vbo->legacy_currval[attr]; - save->inputs[attr + 16] = &vbo->generic_currval[attr]; + for (attr = 0; attr < VERT_ATTRIB_GENERIC_MAX; attr++) { + save->inputs[VERT_ATTRIB_GENERIC(attr)] = + &vbo->currval[VBO_ATTRIB_GENERIC0+attr]; } map = vbo->map_vp_arb; @@ -168,66 +183,76 @@ static void vbo_bind_vertex_list(struct gl_context *ctx, * In that case we effectively need to route the data from * glVertexAttrib(0, val) calls to feed into the GENERIC0 input. */ - if ((ctx->VertexProgram._Current->Base.InputsRead & VERT_BIT_POS) == 0 && - (ctx->VertexProgram._Current->Base.InputsRead & VERT_BIT_GENERIC0)) { - save->inputs[16] = save->inputs[0]; - node_attrsz[16] = node_attrsz[0]; + const GLbitfield64 inputs_read = + ctx->VertexProgram._Current->info.inputs_read; + if ((inputs_read & VERT_BIT_POS) == 0 && + (inputs_read & VERT_BIT_GENERIC0)) { + save->inputs[VERT_ATTRIB_GENERIC0] = save->inputs[0]; + node_attrsz[VERT_ATTRIB_GENERIC0] = node_attrsz[0]; + node_attrtype[VERT_ATTRIB_GENERIC0] = node_attrtype[0]; node_attrsz[0] = 0; } break; default: - assert(0); + unreachable("Bad vertex program mode"); } for (attr = 0; attr < VERT_ATTRIB_MAX; attr++) { const GLuint src = map[attr]; if (node_attrsz[src]) { + struct gl_vertex_array *array = &arrays[attr]; + /* override the default array set above */ - save->inputs[attr] = &arrays[attr]; - - arrays[attr].Ptr = (const GLubyte *) NULL + buffer_offset; - arrays[attr].Size = node->attrsz[src]; - arrays[attr].StrideB = node->vertex_size * sizeof(GLfloat); - arrays[attr].Stride = node->vertex_size * sizeof(GLfloat); - arrays[attr].Type = GL_FLOAT; - arrays[attr].Format = GL_RGBA; - arrays[attr].Enabled = 1; + save->inputs[attr] = array; + + array->Ptr = (const GLubyte *) NULL + buffer_offset; + array->Size = node_attrsz[src]; + array->StrideB = node->vertex_size * sizeof(GLfloat); + array->Type = node_attrtype[src]; + array->Integer = vbo_attrtype_to_integer_flag(node_attrtype[src]); + array->Format = GL_RGBA; + array->_ElementSize = array->Size * sizeof(GLfloat); _mesa_reference_buffer_object(ctx, - &arrays[attr].BufferObj, + &array->BufferObj, node->vertex_store->bufferobj); - arrays[attr]._MaxElement = node->count; /* ??? */ - - assert(arrays[attr].BufferObj->Name); - buffer_offset += node->attrsz[src] * sizeof(GLfloat); - varying_inputs |= 1<BufferObj->Name); + + buffer_offset += node_attrsz[src] * sizeof(GLfloat); + varying_inputs |= VERT_BIT(attr); } } - _mesa_set_varying_vp_inputs( ctx, varying_inputs ); + _mesa_set_varying_vp_inputs(ctx, varying_inputs); + ctx->NewDriverState |= ctx->DriverFlags.NewArray; } static void -vbo_save_loopback_vertex_list(struct gl_context *ctx, - const struct vbo_save_vertex_list *list) +loopback_vertex_list(struct gl_context *ctx, + const struct vbo_save_vertex_list *list) { - const char *buffer = ctx->Driver.MapBuffer(ctx, - GL_ARRAY_BUFFER_ARB, - GL_READ_ONLY, /* ? */ - list->vertex_store->bufferobj); + const char *buffer = + ctx->Driver.MapBufferRange(ctx, 0, + list->vertex_store->bufferobj->Size, + GL_MAP_READ_BIT, /* ? */ + list->vertex_store->bufferobj, + MAP_INTERNAL); + + unsigned buffer_offset = + aligned_vertex_buffer_offset(list) ? 0 : list->buffer_offset; vbo_loopback_vertex_list(ctx, - (const GLfloat *)(buffer + list->buffer_offset), + (const GLfloat *) (buffer + buffer_offset), list->attrsz, - list->prim, + list->prims, list->prim_count, list->wrap_count, list->vertex_size); - ctx->Driver.UnmapBuffer(ctx, GL_ARRAY_BUFFER_ARB, - list->vertex_store->bufferobj); + ctx->Driver.UnmapBuffer(ctx, list->vertex_store->bufferobj, + MAP_INTERNAL); } @@ -242,63 +267,81 @@ vbo_save_playback_vertex_list(struct gl_context *ctx, void *data) const struct vbo_save_vertex_list *node = (const struct vbo_save_vertex_list *) data; struct vbo_save_context *save = &vbo_context(ctx)->save; + GLboolean remap_vertex_store = GL_FALSE; + + if (save->vertex_store && save->vertex_store->buffer_map) { + /* The vertex store is currently mapped but we're about to replay + * a display list. This can happen when a nested display list is + * being build with GL_COMPILE_AND_EXECUTE. + * We never want to have mapped vertex buffers when we're drawing. + * Unmap the vertex store, execute the list, then remap the vertex + * store. + */ + vbo_save_unmap_vertex_store(ctx, save->vertex_store); + remap_vertex_store = GL_TRUE; + } FLUSH_CURRENT(ctx, 0); - if (node->prim_count > 0 && node->count > 0) { - - if (ctx->Driver.CurrentExecPrimitive != PRIM_OUTSIDE_BEGIN_END && - node->prim[0].begin) { + if (node->prim_count > 0) { - /* Degenerate case: list is called inside begin/end pair and - * includes operations such as glBegin or glDrawArrays. - */ - if (0) - printf("displaylist recursive begin"); - - vbo_save_loopback_vertex_list( ctx, node ); - return; + if (_mesa_inside_begin_end(ctx) && node->prims[0].begin) { + /* Error: we're about to begin a new primitive but we're already + * inside a glBegin/End pair. + */ + _mesa_error(ctx, GL_INVALID_OPERATION, + "draw operation inside glBegin/End"); + goto end; } else if (save->replay_flags) { - /* Various degnerate cases: translate into immediate mode - * calls rather than trying to execute in place. - */ - vbo_save_loopback_vertex_list( ctx, node ); - return; + /* Various degenerate cases: translate into immediate mode + * calls rather than trying to execute in place. + */ + loopback_vertex_list(ctx, node); + + goto end; } - + if (ctx->NewState) - _mesa_update_state( ctx ); + _mesa_update_state(ctx); /* XXX also need to check if shader enabled, but invalid */ - if ((ctx->VertexProgram.Enabled && !ctx->VertexProgram._Enabled) || - (ctx->FragmentProgram.Enabled && !ctx->FragmentProgram._Enabled)) { + if ((ctx->VertexProgram.Enabled && + !_mesa_arb_vertex_program_enabled(ctx)) || + (ctx->FragmentProgram.Enabled && + !_mesa_arb_fragment_program_enabled(ctx))) { _mesa_error(ctx, GL_INVALID_OPERATION, "glBegin (invalid vertex/fragment program)"); return; } - vbo_bind_vertex_list( ctx, node ); + bind_vertex_list(ctx, node); + + vbo_draw_method(vbo_context(ctx), DRAW_DISPLAY_LIST); /* Again... */ if (ctx->NewState) - _mesa_update_state( ctx ); - - vbo_context(ctx)->draw_prims(ctx, - save->inputs, - node->prim, - node->prim_count, - NULL, - GL_TRUE, - 0, /* Node is a VBO, so this is ok */ - node->count - 1); + _mesa_update_state(ctx); + + if (node->vertex_count > 0) { + vbo_context(ctx)->draw_prims(ctx, + node->prims, + node->prim_count, + NULL, + GL_TRUE, + 0, /* Node is a VBO, so this is ok */ + node->vertex_count - 1, + NULL, 0, NULL); + } } /* Copy to current? */ - _playback_copy_to_current( ctx, node ); -} - + playback_copy_to_current(ctx, node); -#endif /* FEATURE_dlist */ +end: + if (remap_vertex_store) { + save->buffer_ptr = vbo_save_map_vertex_store(ctx, save->vertex_store); + } +}