/** * Basically, translate Mesa's index buffer information into * a pipe_index_buffer object. * \return TRUE or FALSE for success/failure */ static boolean setup_index_buffer(struct st_context *st, const struct _mesa_index_buffer *ib, struct pipe_index_buffer *ibuffer) { struct gl_buffer_object *bufobj = ib->obj; ibuffer->index_size = vbo_sizeof_ib_type(ib->type); /* get/create the index buffer object */ if (_mesa_is_bufferobj(bufobj)) { /* indices are in a real VBO */ ibuffer->buffer = st_buffer_object(bufobj)->buffer; ibuffer->offset = pointer_to_offset(ib->ptr); } else if (st->indexbuf_uploader) { /* upload indexes from user memory into a real buffer */ if (u_upload_data(st->indexbuf_uploader, 0, ib->count * ibuffer->index_size, ib->ptr, &ibuffer->offset, &ibuffer->buffer) != PIPE_OK) { /* out of memory */ return FALSE; } u_upload_unmap(st->indexbuf_uploader); } else { /* indices are in user space memory */ ibuffer->user_buffer = ib->ptr; } cso_set_index_buffer(st->cso_context, ibuffer); return TRUE; }
static void setup_index_buffer(struct st_context *st, const struct _mesa_index_buffer *ib, struct pipe_index_buffer *ibuffer) { struct gl_buffer_object *bufobj = ib->obj; ibuffer->index_size = vbo_sizeof_ib_type(ib->type); /* get/create the index buffer object */ if (_mesa_is_bufferobj(bufobj)) { /* indices are in a real VBO */ ibuffer->buffer = st_buffer_object(bufobj)->buffer; ibuffer->offset = pointer_to_offset(ib->ptr); } else if (st->indexbuf_uploader) { u_upload_data(st->indexbuf_uploader, 0, ib->count * ibuffer->index_size, ib->ptr, &ibuffer->offset, &ibuffer->buffer); u_upload_unmap(st->indexbuf_uploader); } else { /* indices are in user space memory */ ibuffer->user_buffer = ib->ptr; } cso_set_index_buffer(st->cso_context, ibuffer); }
/* Translate indices to GLuints and store in VB->Elts. */ static void bind_indices( struct gl_context *ctx, const struct _mesa_index_buffer *ib, struct gl_buffer_object **bo, GLuint *nr_bo) { TNLcontext *tnl = TNL_CONTEXT(ctx); struct vertex_buffer *VB = &tnl->vb; GLuint i; const void *ptr; if (!ib) { VB->Elts = NULL; return; } if (_mesa_is_bufferobj(ib->obj) && !_mesa_bufferobj_mapped(ib->obj, MAP_INTERNAL)) { /* if the buffer object isn't mapped yet, map it now */ bo[*nr_bo] = ib->obj; (*nr_bo)++; ptr = ctx->Driver.MapBufferRange(ctx, (GLsizeiptr) ib->ptr, ib->count * vbo_sizeof_ib_type(ib->type), GL_MAP_READ_BIT, ib->obj, MAP_INTERNAL); assert(ib->obj->Mappings[MAP_INTERNAL].Pointer); } else { /* user-space elements, or buffer already mapped */ ptr = ADD_POINTERS(ib->obj->Mappings[MAP_INTERNAL].Pointer, ib->ptr); } if (ib->type == GL_UNSIGNED_INT && VB->Primitive[0].basevertex == 0) { VB->Elts = (GLuint *) ptr; } else { GLuint *elts = (GLuint *)get_space(ctx, ib->count * sizeof(GLuint)); VB->Elts = elts; if (ib->type == GL_UNSIGNED_INT) { const GLuint *in = (GLuint *)ptr; for (i = 0; i < ib->count; i++) *elts++ = (GLuint)(*in++) + VB->Primitive[0].basevertex; } else if (ib->type == GL_UNSIGNED_SHORT) { const GLushort *in = (GLushort *)ptr; for (i = 0; i < ib->count; i++) *elts++ = (GLuint)(*in++) + VB->Primitive[0].basevertex; } else { const GLubyte *in = (GLubyte *)ptr; for (i = 0; i < ib->count; i++) *elts++ = (GLuint)(*in++) + VB->Primitive[0].basevertex; } } }
/** * Compute min and max elements by scanning the index buffer for * glDraw[Range]Elements() calls. * If primitive restart is enabled, we need to ignore restart * indexes when computing min/max. */ static void vbo_get_minmax_index(struct gl_context *ctx, const struct _mesa_prim *prim, const struct _mesa_index_buffer *ib, GLuint *min_index, GLuint *max_index, const GLuint count) { const GLboolean restart = ctx->Array._PrimitiveRestart; const GLuint restartIndex = _mesa_primitive_restart_index(ctx, ib->type); const int index_size = vbo_sizeof_ib_type(ib->type); const char *indices; GLuint i; indices = (char *) ib->ptr + prim->start * index_size; if (_mesa_is_bufferobj(ib->obj)) { GLsizeiptr size = MIN2(count * index_size, ib->obj->Size); indices = ctx->Driver.MapBufferRange(ctx, (GLintptr) indices, size, GL_MAP_READ_BIT, ib->obj); } switch (ib->type) { case GL_UNSIGNED_INT: { const GLuint *ui_indices = (const GLuint *)indices; GLuint max_ui = 0; GLuint min_ui = ~0U; if (restart) { for (i = 0; i < count; i++) { if (ui_indices[i] != restartIndex) { if (ui_indices[i] > max_ui) max_ui = ui_indices[i]; if (ui_indices[i] < min_ui) min_ui = ui_indices[i]; } } } else { for (i = 0; i < count; i++) { if (ui_indices[i] > max_ui) max_ui = ui_indices[i]; if (ui_indices[i] < min_ui) min_ui = ui_indices[i]; } } *min_index = min_ui; *max_index = max_ui; break; } case GL_UNSIGNED_SHORT: { const GLushort *us_indices = (const GLushort *)indices; GLuint max_us = 0; GLuint min_us = ~0U; if (restart) { for (i = 0; i < count; i++) { if (us_indices[i] != restartIndex) { if (us_indices[i] > max_us) max_us = us_indices[i]; if (us_indices[i] < min_us) min_us = us_indices[i]; } } } else { for (i = 0; i < count; i++) { if (us_indices[i] > max_us) max_us = us_indices[i]; if (us_indices[i] < min_us) min_us = us_indices[i]; } } *min_index = min_us; *max_index = max_us; break; } case GL_UNSIGNED_BYTE: { const GLubyte *ub_indices = (const GLubyte *)indices; GLuint max_ub = 0; GLuint min_ub = ~0U; if (restart) { for (i = 0; i < count; i++) { if (ub_indices[i] != restartIndex) { if (ub_indices[i] > max_ub) max_ub = ub_indices[i]; if (ub_indices[i] < min_ub) min_ub = ub_indices[i]; } } } else { for (i = 0; i < count; i++) { if (ub_indices[i] > max_ub) max_ub = ub_indices[i]; if (ub_indices[i] < min_ub) min_ub = ub_indices[i]; } } *min_index = min_ub; *max_index = max_ub; break; } default: assert(0); break; } if (_mesa_is_bufferobj(ib->obj)) { ctx->Driver.UnmapBuffer(ctx, ib->obj); } }
/** * Inner support for both _mesa_MultiDrawElements() and * _mesa_MultiDrawRangeElements(). * This does the actual rendering after we've checked array indexes, etc. */ static void vbo_validated_multidrawelements(struct gl_context *ctx, GLenum mode, const GLsizei *count, GLenum type, const GLvoid * const *indices, GLsizei primcount, const GLint *basevertex) { struct vbo_context *vbo = vbo_context(ctx); struct vbo_exec_context *exec = &vbo->exec; struct _mesa_index_buffer ib; struct _mesa_prim *prim; unsigned int index_type_size = vbo_sizeof_ib_type(type); uintptr_t min_index_ptr, max_index_ptr; GLboolean fallback = GL_FALSE; int i; if (primcount == 0) return; prim = calloc(1, primcount * sizeof(*prim)); if (prim == NULL) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glMultiDrawElements"); return; } vbo_bind_arrays(ctx); min_index_ptr = (uintptr_t)indices[0]; max_index_ptr = 0; for (i = 0; i < primcount; i++) { min_index_ptr = MIN2(min_index_ptr, (uintptr_t)indices[i]); max_index_ptr = MAX2(max_index_ptr, (uintptr_t)indices[i] + index_type_size * count[i]); } /* Check if we can handle this thing as a bunch of index offsets from the * same index pointer. If we can't, then we have to fall back to doing * a draw_prims per primitive. * Check that the difference between each prim's indexes is a multiple of * the index/element size. */ if (index_type_size != 1) { for (i = 0; i < primcount; i++) { if ((((uintptr_t)indices[i] - min_index_ptr) % index_type_size) != 0) { fallback = GL_TRUE; break; } } } /* If the index buffer isn't in a VBO, then treating the application's * subranges of the index buffer as one large index buffer may lead to * us reading unmapped memory. */ if (!_mesa_is_bufferobj(ctx->Array.ArrayObj->ElementArrayBufferObj)) fallback = GL_TRUE; if (!fallback) { ib.count = (max_index_ptr - min_index_ptr) / index_type_size; ib.type = type; ib.obj = ctx->Array.ArrayObj->ElementArrayBufferObj; ib.ptr = (void *)min_index_ptr; for (i = 0; i < primcount; i++) { prim[i].begin = (i == 0); prim[i].end = (i == primcount - 1); prim[i].weak = 0; prim[i].pad = 0; prim[i].mode = mode; prim[i].start = ((uintptr_t)indices[i] - min_index_ptr) / index_type_size; prim[i].count = count[i]; prim[i].indexed = 1; prim[i].num_instances = 1; prim[i].base_instance = 0; if (basevertex != NULL) prim[i].basevertex = basevertex[i]; else prim[i].basevertex = 0; } check_buffers_are_unmapped(exec->array.inputs); vbo_handle_primitive_restart(ctx, prim, primcount, &ib, GL_FALSE, ~0, ~0); } else { /* render one prim at a time */ for (i = 0; i < primcount; i++) { ib.count = count[i]; ib.type = type; ib.obj = ctx->Array.ArrayObj->ElementArrayBufferObj; ib.ptr = indices[i]; prim[0].begin = 1; prim[0].end = 1; prim[0].weak = 0; prim[0].pad = 0; prim[0].mode = mode; prim[0].start = 0; prim[0].count = count[i]; prim[0].indexed = 1; prim[0].num_instances = 1; prim[0].base_instance = 0; if (basevertex != NULL) prim[0].basevertex = basevertex[i]; else prim[0].basevertex = 0; check_buffers_are_unmapped(exec->array.inputs); vbo_handle_primitive_restart(ctx, prim, 1, &ib, GL_FALSE, ~0, ~0); } } free(prim); if (MESA_DEBUG_FLAGS & DEBUG_ALWAYS_FLUSH) { _mesa_flush(ctx); } }
/** * Called by VBO to draw arrays when in selection or feedback mode and * to implement glRasterPos. * This is very much like the normal draw_vbo() function above. * Look at code refactoring some day. */ void st_feedback_draw_vbo(struct gl_context *ctx, const struct gl_client_array **arrays, const struct _mesa_prim *prims, GLuint nr_prims, const struct _mesa_index_buffer *ib, GLboolean index_bounds_valid, GLuint min_index, GLuint max_index, struct gl_transform_feedback_object *tfb_vertcount) { struct st_context *st = st_context(ctx); struct pipe_context *pipe = st->pipe; struct draw_context *draw = st->draw; const struct st_vertex_program *vp; const struct pipe_shader_state *vs; struct pipe_vertex_buffer vbuffers[PIPE_MAX_SHADER_INPUTS]; struct pipe_vertex_element velements[PIPE_MAX_ATTRIBS]; struct pipe_index_buffer ibuffer; struct pipe_transfer *vb_transfer[PIPE_MAX_ATTRIBS]; struct pipe_transfer *ib_transfer = NULL; GLuint attr, i; const GLubyte *low_addr = NULL; const void *mapped_indices = NULL; assert(draw); st_validate_state(st); if (!index_bounds_valid) vbo_get_minmax_indices(ctx, prims, ib, &min_index, &max_index, nr_prims); /* must get these after state validation! */ vp = st->vp; vs = &st->vp_variant->tgsi; if (!st->vp_variant->draw_shader) { st->vp_variant->draw_shader = draw_create_vertex_shader(draw, vs); } /* * Set up the draw module's state. * * We'd like to do this less frequently, but the normal state-update * code sends state updates to the pipe, not to our private draw module. */ assert(draw); draw_set_viewport_state(draw, &st->state.viewport); draw_set_clip_state(draw, &st->state.clip); draw_set_rasterizer_state(draw, &st->state.rasterizer, NULL); draw_bind_vertex_shader(draw, st->vp_variant->draw_shader); set_feedback_vertex_format(ctx); /* Find the lowest address of the arrays we're drawing */ if (vp->num_inputs) { low_addr = arrays[vp->index_to_input[0]]->Ptr; for (attr = 1; attr < vp->num_inputs; attr++) { const GLubyte *start = arrays[vp->index_to_input[attr]]->Ptr; low_addr = MIN2(low_addr, start); } } /* loop over TGSI shader inputs to determine vertex buffer * and attribute info */ for (attr = 0; attr < vp->num_inputs; attr++) { const GLuint mesaAttr = vp->index_to_input[attr]; struct gl_buffer_object *bufobj = arrays[mesaAttr]->BufferObj; void *map; if (bufobj && bufobj->Name) { /* Attribute data is in a VBO. * Recall that for VBOs, the gl_client_array->Ptr field is * really an offset from the start of the VBO, not a pointer. */ struct st_buffer_object *stobj = st_buffer_object(bufobj); assert(stobj->buffer); vbuffers[attr].buffer = NULL; pipe_resource_reference(&vbuffers[attr].buffer, stobj->buffer); vbuffers[attr].buffer_offset = pointer_to_offset(low_addr); velements[attr].src_offset = arrays[mesaAttr]->Ptr - low_addr; } else { /* attribute data is in user-space memory, not a VBO */ uint bytes = (arrays[mesaAttr]->Size * _mesa_sizeof_type(arrays[mesaAttr]->Type) * (max_index + 1)); /* wrap user data */ vbuffers[attr].buffer = pipe_user_buffer_create(pipe->screen, (void *) arrays[mesaAttr]->Ptr, bytes, PIPE_BIND_VERTEX_BUFFER); vbuffers[attr].buffer_offset = 0; velements[attr].src_offset = 0; } /* common-case setup */ vbuffers[attr].stride = arrays[mesaAttr]->StrideB; /* in bytes */ velements[attr].instance_divisor = 0; velements[attr].vertex_buffer_index = attr; velements[attr].src_format = st_pipe_vertex_format(arrays[mesaAttr]->Type, arrays[mesaAttr]->Size, arrays[mesaAttr]->Format, arrays[mesaAttr]->Normalized, arrays[mesaAttr]->Integer); assert(velements[attr].src_format); /* tell draw about this attribute */ #if 0 draw_set_vertex_buffer(draw, attr, &vbuffer[attr]); #endif /* map the attrib buffer */ map = pipe_buffer_map(pipe, vbuffers[attr].buffer, PIPE_TRANSFER_READ, &vb_transfer[attr]); draw_set_mapped_vertex_buffer(draw, attr, map); } draw_set_vertex_buffers(draw, vp->num_inputs, vbuffers); draw_set_vertex_elements(draw, vp->num_inputs, velements); memset(&ibuffer, 0, sizeof(ibuffer)); if (ib) { struct gl_buffer_object *bufobj = ib->obj; ibuffer.index_size = vbo_sizeof_ib_type(ib->type); if (ibuffer.index_size == 0) goto out_unref_vertex; if (bufobj && bufobj->Name) { struct st_buffer_object *stobj = st_buffer_object(bufobj); pipe_resource_reference(&ibuffer.buffer, stobj->buffer); ibuffer.offset = pointer_to_offset(ib->ptr); mapped_indices = pipe_buffer_map(pipe, stobj->buffer, PIPE_TRANSFER_READ, &ib_transfer); } else { /* skip setting ibuffer.buffer as the draw module does not use it */ mapped_indices = ib->ptr; } draw_set_index_buffer(draw, &ibuffer); draw_set_mapped_index_buffer(draw, mapped_indices); } /* set the constant buffer */ draw_set_mapped_constant_buffer(st->draw, PIPE_SHADER_VERTEX, 0, st->state.constants[PIPE_SHADER_VERTEX].ptr, st->state.constants[PIPE_SHADER_VERTEX].size); /* draw here */ for (i = 0; i < nr_prims; i++) { draw_arrays(draw, prims[i].mode, prims[i].start, prims[i].count); } /* * unmap vertex/index buffers */ if (ib) { draw_set_mapped_index_buffer(draw, NULL); draw_set_index_buffer(draw, NULL); if (ib_transfer) pipe_buffer_unmap(pipe, ib_transfer); pipe_resource_reference(&ibuffer.buffer, NULL); } out_unref_vertex: for (attr = 0; attr < vp->num_inputs; attr++) { pipe_buffer_unmap(pipe, vb_transfer[attr]); draw_set_mapped_vertex_buffer(draw, attr, NULL); pipe_resource_reference(&vbuffers[attr].buffer, NULL); } draw_set_vertex_buffers(draw, 0, NULL); }
/** * Handle primitive restart in software. * * This function breaks up calls into the driver so primitive restart * support is not required in the driver. */ void vbo_sw_primitive_restart(struct gl_context *ctx, const struct _mesa_prim *prims, GLuint nr_prims, const struct _mesa_index_buffer *ib, struct gl_buffer_object *indirect) { GLuint prim_num; struct sub_primitive *sub_prims; struct sub_primitive *sub_prim; GLuint num_sub_prims; GLuint sub_prim_num; GLuint end_index; GLuint sub_end_index; GLuint restart_index = _mesa_primitive_restart_index(ctx, ib->type); struct _mesa_prim temp_prim; struct vbo_context *vbo = vbo_context(ctx); vbo_draw_func draw_prims_func = vbo->draw_prims; GLboolean map_ib = ib->obj->Name && !ib->obj->Pointer; void *ptr; /* If there is an indirect buffer, map it and extract the draw params */ if (indirect && prims[0].is_indirect) { struct _mesa_prim new_prim = *prims; struct _mesa_index_buffer new_ib = *ib; const uint32_t *indirect_params; if (!ctx->Driver.MapBufferRange(ctx, 0, indirect->Size, GL_MAP_READ_BIT, indirect)) { /* something went wrong with mapping, give up */ _mesa_error(ctx, GL_OUT_OF_MEMORY, "failed to map indirect buffer for sw primitive restart"); return; } assert(nr_prims == 1); indirect_params = (const uint32_t *) ADD_POINTERS(indirect->Pointer, new_prim.indirect_offset); new_prim.is_indirect = 0; new_prim.count = indirect_params[0]; new_prim.num_instances = indirect_params[1]; new_prim.start = indirect_params[2]; new_prim.basevertex = indirect_params[3]; new_prim.base_instance = indirect_params[4]; new_ib.count = new_prim.count; prims = &new_prim; ib = &new_ib; ctx->Driver.UnmapBuffer(ctx, indirect); } /* Find the sub-primitives. These are regions in the index buffer which * are split based on the primitive restart index value. */ if (map_ib) { ctx->Driver.MapBufferRange(ctx, 0, ib->obj->Size, GL_MAP_READ_BIT, ib->obj); } ptr = ADD_POINTERS(ib->obj->Pointer, ib->ptr); sub_prims = find_sub_primitives(ptr, vbo_sizeof_ib_type(ib->type), 0, ib->count, restart_index, &num_sub_prims); if (map_ib) { ctx->Driver.UnmapBuffer(ctx, ib->obj); } /* Loop over the primitives, and use the located sub-primitives to draw * each primitive with a break to implement each primitive restart. */ for (prim_num = 0; prim_num < nr_prims; prim_num++) { end_index = prims[prim_num].start + prims[prim_num].count; memcpy(&temp_prim, &prims[prim_num], sizeof (temp_prim)); /* Loop over the sub-primitives drawing sub-ranges of the primitive. */ for (sub_prim_num = 0; sub_prim_num < num_sub_prims; sub_prim_num++) { sub_prim = &sub_prims[sub_prim_num]; sub_end_index = sub_prim->start + sub_prim->count; if (prims[prim_num].start <= sub_prim->start) { temp_prim.start = MAX2(prims[prim_num].start, sub_prim->start); temp_prim.count = MIN2(sub_end_index, end_index) - temp_prim.start; if ((temp_prim.start == sub_prim->start) && (temp_prim.count == sub_prim->count)) { draw_prims_func(ctx, &temp_prim, 1, ib, GL_TRUE, sub_prim->min_index, sub_prim->max_index, NULL, NULL); } else { draw_prims_func(ctx, &temp_prim, 1, ib, GL_FALSE, -1, -1, NULL, NULL); } } if (sub_end_index >= end_index) { break; } } } free(sub_prims); }
/** * Compute min and max elements by scanning the index buffer for * glDraw[Range]Elements() calls. * If primitive restart is enabled, we need to ignore restart * indexes when computing min/max. */ static void vbo_get_minmax_index(struct gl_context *ctx, const struct _mesa_prim *prim, const struct _mesa_index_buffer *ib, GLuint *min_index, GLuint *max_index, const GLuint count) { const GLboolean restart = ctx->Array._PrimitiveRestart; const GLuint restartIndex = _mesa_primitive_restart_index(ctx, ib->type); const int index_size = vbo_sizeof_ib_type(ib->type); const char *indices; GLuint i; indices = (char *) ib->ptr + prim->start * index_size; if (_mesa_is_bufferobj(ib->obj)) { GLsizeiptr size = MIN2(count * index_size, ib->obj->Size); if (vbo_get_minmax_cached(ib->obj, ib->type, (GLintptr) indices, count, min_index, max_index)) return; indices = ctx->Driver.MapBufferRange(ctx, (GLintptr) indices, size, GL_MAP_READ_BIT, ib->obj, MAP_INTERNAL); } switch (ib->type) { case GL_UNSIGNED_INT: { const GLuint *ui_indices = (const GLuint *)indices; GLuint max_ui = 0; GLuint min_ui = ~0U; if (restart) { for (i = 0; i < count; i++) { if (ui_indices[i] != restartIndex) { if (ui_indices[i] > max_ui) max_ui = ui_indices[i]; if (ui_indices[i] < min_ui) min_ui = ui_indices[i]; } } } else { #if defined(USE_SSE41) if (cpu_has_sse4_1) { _mesa_uint_array_min_max(ui_indices, &min_ui, &max_ui, count); } else #endif for (i = 0; i < count; i++) { if (ui_indices[i] > max_ui) max_ui = ui_indices[i]; if (ui_indices[i] < min_ui) min_ui = ui_indices[i]; } } *min_index = min_ui; *max_index = max_ui; break; } case GL_UNSIGNED_SHORT: { const GLushort *us_indices = (const GLushort *)indices; GLuint max_us = 0; GLuint min_us = ~0U; if (restart) { for (i = 0; i < count; i++) { if (us_indices[i] != restartIndex) { if (us_indices[i] > max_us) max_us = us_indices[i]; if (us_indices[i] < min_us) min_us = us_indices[i]; } } } else { for (i = 0; i < count; i++) { if (us_indices[i] > max_us) max_us = us_indices[i]; if (us_indices[i] < min_us) min_us = us_indices[i]; } } *min_index = min_us; *max_index = max_us; break; } case GL_UNSIGNED_BYTE: { const GLubyte *ub_indices = (const GLubyte *)indices; GLuint max_ub = 0; GLuint min_ub = ~0U; if (restart) { for (i = 0; i < count; i++) { if (ub_indices[i] != restartIndex) { if (ub_indices[i] > max_ub) max_ub = ub_indices[i]; if (ub_indices[i] < min_ub) min_ub = ub_indices[i]; } } } else { for (i = 0; i < count; i++) { if (ub_indices[i] > max_ub) max_ub = ub_indices[i]; if (ub_indices[i] < min_ub) min_ub = ub_indices[i]; } } *min_index = min_ub; *max_index = max_ub; break; } default: unreachable("not reached"); } if (_mesa_is_bufferobj(ib->obj)) { vbo_minmax_cache_store(ctx, ib->obj, ib->type, prim->start, count, *min_index, *max_index); ctx->Driver.UnmapBuffer(ctx, ib->obj, MAP_INTERNAL); } }
/** * Handle primitive restart in software. * * This function breaks up calls into the driver so primitive restart * support is not required in the driver. */ void vbo_sw_primitive_restart(struct gl_context *ctx, const struct _mesa_prim *prims, GLuint nr_prims, const struct _mesa_index_buffer *ib) { GLuint prim_num; struct sub_primitive *sub_prims; struct sub_primitive *sub_prim; GLuint num_sub_prims; GLuint sub_prim_num; GLuint end_index; GLuint sub_end_index; GLuint restart_index = ctx->Array.RestartIndex; struct _mesa_prim temp_prim; struct vbo_context *vbo = vbo_context(ctx); vbo_draw_func draw_prims_func = vbo->draw_prims; GLboolean map_ib = ib->obj->Name && !ib->obj->Pointer; void *ptr; /* Find the sub-primitives. These are regions in the index buffer which * are split based on the primitive restart index value. */ if (map_ib) { ctx->Driver.MapBufferRange(ctx, 0, ib->obj->Size, GL_MAP_READ_BIT, ib->obj); } ptr = ADD_POINTERS(ib->obj->Pointer, ib->ptr); sub_prims = find_sub_primitives(ptr, vbo_sizeof_ib_type(ib->type), 0, ib->count, restart_index, &num_sub_prims); if (map_ib) { ctx->Driver.UnmapBuffer(ctx, ib->obj); } /* Loop over the primitives, and use the located sub-primitives to draw * each primitive with a break to implement each primitive restart. */ for (prim_num = 0; prim_num < nr_prims; prim_num++) { end_index = prims[prim_num].start + prims[prim_num].count; memcpy(&temp_prim, &prims[prim_num], sizeof (temp_prim)); /* Loop over the sub-primitives drawing sub-ranges of the primitive. */ for (sub_prim_num = 0; sub_prim_num < num_sub_prims; sub_prim_num++) { sub_prim = &sub_prims[sub_prim_num]; sub_end_index = sub_prim->start + sub_prim->count; if (prims[prim_num].start <= sub_prim->start) { temp_prim.start = MAX2(prims[prim_num].start, sub_prim->start); temp_prim.count = MIN2(sub_end_index, end_index) - temp_prim.start; if ((temp_prim.start == sub_prim->start) && (temp_prim.count == sub_prim->count)) { draw_prims_func(ctx, &temp_prim, 1, ib, GL_TRUE, sub_prim->min_index, sub_prim->max_index, NULL); } else { draw_prims_func(ctx, &temp_prim, 1, ib, GL_FALSE, -1, -1, NULL); } } if (sub_end_index >= end_index) { break; } } } free(sub_prims); }