Hi Brian, That one will not work as is.
Display lists are shared objects across contexts. Means past that change the const struct gl_vertex_array *inputs[VBO_ATTRIB_MAX]; may be concurrently written to from different threads filling in current value pointers from the context where the list is executed from. That leaves current values form a differnet context and concurrency issues at least. Beside that I am also not sure if the array update logic in bind_vertex_list works correctly when VBO_ATTRIB* arrays ending in an aliasing VERT_ATTRIB* slot are both enabled. You probably need to currectly mask out the VBO_ATTRIB arrays before you distribute them across the inputs[] array. But the the logic just to store subsequent node->arrays entries to save memory fails when skipping the masked out arrays. best Mathias On Thursday, 25 January 2018 00:20:35 CET Brian Paul wrote: > Do more of the vertex array setup at display list compilation time > via the compile_vertex_list() function. > > Then, at draw time, just do final vertex array setup dependent on > whether we're using fixed function or a vertex shader. > > This can help apps which use a lot of short display list drawing. > --- > src/mesa/vbo/vbo_save.h | 11 ++- > src/mesa/vbo/vbo_save_api.c | 93 ++++++++++++++++++++++--- > src/mesa/vbo/vbo_save_draw.c | 157 +++++++++++++ +----------------------------- > 3 files changed, 147 insertions(+), 114 deletions(-) > > diff --git a/src/mesa/vbo/vbo_save.h b/src/mesa/vbo/vbo_save.h > index 51ea9cc..62a9d54 100644 > --- a/src/mesa/vbo/vbo_save.h > +++ b/src/mesa/vbo/vbo_save.h > @@ -85,6 +85,16 @@ struct vbo_save_vertex_list { > > struct vbo_save_vertex_store *vertex_store; > struct vbo_save_primitive_store *prim_store; > + > + /* Array [bitcount(enabled)] of gl_vertex_array objects describing > + * the vertex data contained in this vbo_save_vertex_list. > + */ > + struct gl_vertex_array *arrays; > + > + /* The arrays to actually use at draw time. Some will point at the > + * 'arrays' field above. The rest will point at the vbo->currval arrays > + */ > + const struct gl_vertex_array *inputs[VBO_ATTRIB_MAX]; > }; > > > @@ -140,7 +150,6 @@ struct vbo_save_context { > GLvertexformat vtxfmt; > GLvertexformat vtxfmt_noop; /**< Used if out_of_memory is true */ > struct gl_vertex_array arrays[VBO_ATTRIB_MAX]; > - const struct gl_vertex_array *inputs[VBO_ATTRIB_MAX]; > > GLbitfield64 enabled; /**< mask of enabled vbo arrays. */ > GLubyte attrsz[VBO_ATTRIB_MAX]; /**< 1, 2, 3 or 4 */ > diff --git a/src/mesa/vbo/vbo_save_api.c b/src/mesa/vbo/vbo_save_api.c > index 11c40a2..e394d88 100644 > --- a/src/mesa/vbo/vbo_save_api.c > +++ b/src/mesa/vbo/vbo_save_api.c > @@ -412,8 +412,80 @@ convert_line_loop_to_strip(struct vbo_save_context *save, > > > /** > - * Insert the active immediate struct onto the display list currently > - * being built. > + * Prepare the vertex arrays which will be used for drawing the primitives > + * in the given vertex list. By doing it here, we can avoid doing this > + * work at display list execution/draw time. > + */ > +static void > +setup_vertex_arrays(struct gl_context *ctx, > + struct vbo_save_vertex_list *node) > +{ > + struct vbo_context *vbo = vbo_context(ctx); > + unsigned buffer_offset = node->buffer_offset; > + unsigned attr; > + const unsigned num_arrays = _mesa_bitcount_64(node->enabled); > + unsigned array_count; > + > + 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; > + } > + > + assert(!node->arrays); > + node->arrays = calloc(num_arrays, sizeof(struct gl_vertex_array)); > + if (!node->arrays) { > + _mesa_error(ctx, GL_OUT_OF_MEMORY, > + "compiling vertex data into display list"); > + /* just turn off all arrays */ > + node->enabled = 0; > + return; > + } > + > + array_count = 0; > + for (attr = 0; attr < VBO_ATTRIB_MAX; attr++) { > + if (node->attrsz[attr]) { > + /* this vertex array points at actual per-vertex data in a VB */ > + struct gl_vertex_array *array = &node->arrays[array_count]; > + > + array->Ptr = (const GLubyte *) NULL + buffer_offset; > + array->Size = node->attrsz[attr]; > + array->StrideB = node->vertex_size * sizeof(GLfloat); > + array->Type = node->attrtype[attr]; > + array->Integer = vbo_attrtype_to_integer_flag(node- >attrtype[attr]); > + array->Format = GL_RGBA; > + array->_ElementSize = array->Size * sizeof(GLfloat); > + _mesa_reference_buffer_object(ctx, > + &array->BufferObj, > + node->vertex_store->bufferobj); > + > + node->inputs[attr] = array; > + > + buffer_offset += node->attrsz[attr] * sizeof(GLfloat); > + > + array_count++; > + } > + else { > + /* this vertex array points at currval/default values */ > + node->inputs[attr] = &vbo->currval[attr]; > + } > + } > + > + assert(array_count == num_arrays); > +} > + > + > +/** > + * Create a new vbo_save_vertex_list object and fill it with the vertices > + * and primitives accumulated in the vbo_save_context. > + * The new vbo_save_vertex_list is allocated from display list memory > + * and will automatically be inserted into the current display list. > */ > static void > compile_vertex_list(struct gl_context *ctx) > @@ -430,6 +502,8 @@ compile_vertex_list(struct gl_context *ctx) > if (!node) > return; > > + memset(node, 0, sizeof(*node)); > + > /* Make sure the pointer is aligned to the size of a pointer */ > assert((GLintptr) node % sizeof(void *) == 0); > > @@ -568,6 +642,8 @@ compile_vertex_list(struct gl_context *ctx) > node->start_vertex = 0; > } > > + setup_vertex_arrays(ctx, node); > + > /* Reset our structures for the next run of vertices: > */ > reset_counters(ctx); > @@ -1679,7 +1755,6 @@ static void > vbo_destroy_vertex_list(struct gl_context *ctx, void *data) > { > struct vbo_save_vertex_list *node = (struct vbo_save_vertex_list *) data; > - (void) ctx; > > if (--node->vertex_store->refcount == 0) > free_vertex_store(ctx, node->vertex_store); > @@ -1688,6 +1763,13 @@ vbo_destroy_vertex_list(struct gl_context *ctx, void *data) > free(node->prim_store); > > free(node->current_data); > + > + const unsigned num_arrays = _mesa_bitcount_64(node->enabled); > + for (unsigned i = 0; i < num_arrays; i++) { > + _mesa_reference_buffer_object(ctx, &(node->arrays[i].BufferObj), NULL); > + } > + free(node->arrays); > + > node->current_data = NULL; > } > > @@ -1752,7 +1834,6 @@ void > vbo_save_api_init(struct vbo_save_context *save) > { > struct gl_context *ctx = save->ctx; > - GLuint i; > > save->opcode_vertex_list = > _mesa_dlist_alloc_opcode(ctx, > @@ -1764,8 +1845,4 @@ vbo_save_api_init(struct vbo_save_context *save) > vtxfmt_init(ctx); > current_init(ctx); > _mesa_noop_vtxfmt_init(&save->vtxfmt_noop); > - > - /* These will actually get set again when binding/drawing */ > - for (i = 0; i < VBO_ATTRIB_MAX; i++) > - save->inputs[i] = &save->arrays[i]; > } > diff --git a/src/mesa/vbo/vbo_save_draw.c b/src/mesa/vbo/vbo_save_draw.c > index 5f5dcbe..1ef74d7 100644 > --- a/src/mesa/vbo/vbo_save_draw.c > +++ b/src/mesa/vbo/vbo_save_draw.c > @@ -125,69 +125,63 @@ playback_copy_to_current(struct gl_context *ctx, > } > > > - > /** > - * Treat the vertex storage as a VBO, define vertex arrays pointing > - * into it: > + * Setup the vertex arrays for drawing the primitives described by 'node'. > + * This populates the node->inputs[] vertex arrays and calls > + * _mesa_set_drawing_arrays(). Most of the work was previously done in > + * the setup_vertex_arrays() function when the display list was compiled. > */ > static void > bind_vertex_list(struct gl_context *ctx, > - const struct vbo_save_vertex_list *node) > + struct vbo_save_vertex_list *node) > { > struct vbo_context *vbo = vbo_context(ctx); > - struct vbo_save_context *save = &vbo->save; > - struct gl_vertex_array *arrays = save->arrays; > - GLuint buffer_offset = node->buffer_offset; > - const GLubyte *map; /** map from VERT_ATTRIB_x to VBO_ATTRIB_x */ > - GLuint attr; > - GLubyte node_attrsz[VBO_ATTRIB_MAX]; /* copy of node->attrsz[] */ > - GLenum node_attrtype[VBO_ATTRIB_MAX]; /* copy of node->attrtype[] */ > + const enum vp_mode vp_mode = get_vp_mode(ctx); > + unsigned array_count = 0; > GLbitfield64 enabled = node->enabled; > > - 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; > + if (vp_mode == VP_SHADER) { > + /* per-vertex materials are to be ignored when using a VS */ > + enabled &= ~VBO_ATTRIBS_MATERIALS; > } > > - /* 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]; > - } > + /* Loop over the attributes which are present in the vertex buffer > + * and set the node->input vertex arrays to point to those attributes. > + */ > + GLbitfield64 enabled_scan = enabled; > + while (enabled_scan) { > + const int attr = u_bit_scan64(&enabled_scan); > + unsigned dst; > > - /* Overlay other active attributes */ > - switch (get_vp_mode(ctx)) { > - case VP_FF: > - /* Point the generic attributes at the legacy material values */ > - for (attr = 0; attr < MAT_ATTRIB_MAX; attr++) { > - save->inputs[VERT_ATTRIB_GENERIC(attr)] = > - &vbo->currval[VBO_ATTRIB_MAT_FRONT_AMBIENT+attr]; > + /* Here is where we resolve whether array[16...] points to legacy > + * material coefficients or generic vertex attributes. > + */ > + if (vp_mode == VP_FF) { > + if (attr >= VBO_ATTRIB_FIRST_MATERIAL) { > + dst = VBO_ATTRIB_GENERIC0 + attr - VBO_ATTRIB_FIRST_MATERIAL; > + } else { > + dst = attr; > + } > + } else { > + assert(vp_mode == VP_SHADER); > + dst = attr; > } > - map = vbo->map_vp_none; > > - /* shift material attrib flags into generic attribute positions */ > + assert(dst < VERT_ATTRIB_MAX); > + assert(node->arrays); > + node->inputs[dst] = &node->arrays[array_count++]; > + } > + > + /* Final vertex array setup depending on whether we're using fixed > + * function or a vertex shader. > + */ > + if (vp_mode == VP_FF) { > + /* Update the enabled attribute bitfield so the material attrib bits > + * replace the generic attrib bits. > + */ > enabled = (enabled & VBO_ATTRIBS_LEGACY) > | ((enabled & VBO_ATTRIBS_MATERIALS) >> VBO_MATERIAL_SHIFT); > - break; > - case VP_SHADER: > - 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; > - > - /* per-vertex materials are to be ignored when using a VS */ > - enabled &= ~VBO_ATTRIBS_MATERIALS; > - > + } else { > /* check if VERT_ATTRIB_POS is not read but VERT_BIT_GENERIC0 is read. > * In that case we effectively need to route the data from > * glVertexAttrib(0, val) calls to feed into the GENERIC0 input. > @@ -196,64 +190,19 @@ bind_vertex_list(struct gl_context *ctx, > 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; > - enabled = (enabled & ~VERT_BIT_POS) | VERT_BIT_GENERIC0; > - } > - break; > - default: > - unreachable("Bad vertex program mode"); > - } > - > -#ifdef DEBUG > - /* verify the enabled bitmask is consistent with attribute size info */ > - { > - GLbitfield64 used = 0x0; > - for (attr = 0; attr < VERT_ATTRIB_MAX; attr++) { > - const GLuint src = map[attr]; > - if (node_attrsz[src]) { > - assert(enabled & VERT_BIT(attr)); > - used |= VERT_BIT(attr); > - } else { > - assert((enabled & VERT_BIT(attr)) == 0); > - } > + node->inputs[VERT_ATTRIB_GENERIC0] = &node- >arrays[VBO_ATTRIB_POS]; > + node->inputs[VERT_ATTRIB_POS] = &vbo->currval[VBO_ATTRIB_POS]; > + enabled &= ~BITFIELD64_BIT(VBO_ATTRIB_POS); > + enabled |= BITFIELD64_BIT(VBO_ATTRIB_GENERIC0); > } > - assert(used == enabled); > } > -#endif > > - GLbitfield64 enabled_scan = enabled; > - while (enabled_scan) { > - const int attr = u_bit_scan64(&enabled_scan); > - 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] = 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, > - &array->BufferObj, > - node->vertex_store->bufferobj); > - > - assert(array->BufferObj->Name); > - > - buffer_offset += node_attrsz[src] * sizeof(GLfloat); > - } > - } > + /* make sure none of the extra VBO_ATTRIB bits are set */ > + assert((enabled & (GLbitfield64) VERT_BIT_ALL) == enabled); > > _mesa_set_varying_vp_inputs(ctx, enabled); > - ctx->NewDriverState |= ctx->DriverFlags.NewArray; > + > + _mesa_set_drawing_arrays(ctx, node->inputs); > } > > > @@ -292,8 +241,8 @@ loopback_vertex_list(struct gl_context *ctx, > void > 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_vertex_list *node = > + (struct vbo_save_vertex_list *) data; > struct vbo_context *vbo = vbo_context(ctx); > struct vbo_save_context *save = &vbo->save; > GLboolean remap_vertex_store = GL_FALSE; > @@ -346,8 +295,6 @@ vbo_save_playback_vertex_list(struct gl_context *ctx, void *data) > > bind_vertex_list(ctx, node); > > - _mesa_set_drawing_arrays(ctx, vbo->save.inputs); > - > /* Again... > */ > if (ctx->NewState) > _______________________________________________ mesa-dev mailing list mesa-dev@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/mesa-dev