static void brw_draw_rectlist(struct brw_context *brw, struct rect *rect, int num_instances) { struct gl_context *ctx = &brw->ctx; struct brw_fast_clear_state *clear = brw->fast_clear_state; int start = 0, count = 3; struct _mesa_prim prim; float verts[6]; verts[0] = rect->x1; verts[1] = rect->y1; verts[2] = rect->x0; verts[3] = rect->y1; verts[4] = rect->x0; verts[5] = rect->y0; /* upload new vertex data */ _mesa_buffer_data(ctx, clear->buf_obj, GL_NONE, sizeof(verts), verts, GL_DYNAMIC_DRAW, __func__); if (ctx->NewState) _mesa_update_state(ctx); vbo_bind_arrays(ctx); memset(&prim, 0, sizeof prim); prim.begin = 1; prim.end = 1; prim.mode = BRW_PRIM_OFFSET + _3DPRIM_RECTLIST; prim.num_instances = num_instances; prim.start = start; prim.count = count; /* Make sure our internal prim value doesn't clash with a valid GL value. */ assert(!_mesa_is_valid_prim_mode(ctx, prim.mode)); brw_draw_prims(ctx, &prim, 1, NULL, GL_TRUE, start, start + count - 1, NULL, 0, NULL); }
static void vbo_draw_transform_feedback(struct gl_context *ctx, GLenum mode, struct gl_transform_feedback_object *obj, GLuint stream, GLuint numInstances) { struct vbo_context *vbo = vbo_context(ctx); struct vbo_exec_context *exec = &vbo->exec; struct _mesa_prim prim[2]; if (!_mesa_validate_DrawTransformFeedback(ctx, mode, obj, stream, numInstances)) { return; } vbo_bind_arrays(ctx); /* init most fields to zero */ memset(prim, 0, sizeof(prim)); prim[0].begin = 1; prim[0].end = 1; prim[0].mode = mode; prim[0].num_instances = numInstances; prim[0].base_instance = 0; /* Maybe we should do some primitive splitting for primitive restart * (like in DrawArrays), but we have no way to know how many vertices * will be rendered. */ check_buffers_are_unmapped(exec->array.inputs); vbo->draw_prims(ctx, prim, 1, NULL, GL_TRUE, 0, 0, obj); if (MESA_DEBUG_FLAGS & DEBUG_ALWAYS_FLUSH) { _mesa_flush(ctx); } }
/** * Inner support for both _mesa_DrawElements and _mesa_DrawRangeElements. * Do the rendering for a glDrawElements or glDrawRangeElements call after * we've validated buffer bounds, etc. */ static void vbo_validated_drawrangeelements(struct gl_context *ctx, GLenum mode, GLboolean index_bounds_valid, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid *indices, GLint basevertex, GLuint numInstances, GLuint baseInstance) { struct vbo_context *vbo = vbo_context(ctx); struct vbo_exec_context *exec = &vbo->exec; struct _mesa_index_buffer ib; struct _mesa_prim prim[1]; vbo_bind_arrays(ctx); ib.count = count; ib.type = type; ib.obj = ctx->Array.ArrayObj->ElementArrayBufferObj; ib.ptr = indices; 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; prim[0].indexed = 1; prim[0].basevertex = basevertex; prim[0].num_instances = numInstances; prim[0].base_instance = baseInstance; /* Need to give special consideration to rendering a range of * indices starting somewhere above zero. Typically the * application is issuing multiple DrawRangeElements() to draw * successive primitives layed out linearly in the vertex arrays. * Unless the vertex arrays are all in a VBO (or locked as with * CVA), the OpenGL semantics imply that we need to re-read or * re-upload the vertex data on each draw call. * * In the case of hardware tnl, we want to avoid starting the * upload at zero, as it will mean every draw call uploads an * increasing amount of not-used vertex data. Worse - in the * software tnl module, all those vertices might be transformed and * lit but never rendered. * * If we just upload or transform the vertices in start..end, * however, the indices will be incorrect. * * At this level, we don't know exactly what the requirements of * the backend are going to be, though it will likely boil down to * either: * * 1) Do nothing, everything is in a VBO and is processed once * only. * * 2) Adjust the indices and vertex arrays so that start becomes * zero. * * Rather than doing anything here, I'll provide a helper function * for the latter case elsewhere. */ check_buffers_are_unmapped(exec->array.inputs); vbo_handle_primitive_restart(ctx, prim, 1, &ib, index_bounds_valid, start, end); if (MESA_DEBUG_FLAGS & DEBUG_ALWAYS_FLUSH) { _mesa_flush(ctx); } }
/** * Helper function called by the other DrawArrays() functions below. * This is where we handle primitive restart for drawing non-indexed * arrays. If primitive restart is enabled, it typically means * splitting one DrawArrays() into two. */ static void vbo_draw_arrays(struct gl_context *ctx, GLenum mode, GLint start, GLsizei count, GLuint numInstances, GLuint baseInstance) { struct vbo_context *vbo = vbo_context(ctx); struct vbo_exec_context *exec = &vbo->exec; struct _mesa_prim prim[2]; vbo_bind_arrays(ctx); /* init most fields to zero */ memset(prim, 0, sizeof(prim)); prim[0].begin = 1; prim[0].end = 1; prim[0].mode = mode; prim[0].num_instances = numInstances; prim[0].base_instance = baseInstance; /* Implement the primitive restart index */ if (ctx->Array.PrimitiveRestart && ctx->Array.RestartIndex < count) { GLuint primCount = 0; if (ctx->Array.RestartIndex == start) { /* special case: RestartIndex at beginning */ if (count > 1) { prim[0].start = start + 1; prim[0].count = count - 1; primCount = 1; } } else if (ctx->Array.RestartIndex == start + count - 1) { /* special case: RestartIndex at end */ if (count > 1) { prim[0].start = start; prim[0].count = count - 1; primCount = 1; } } else { /* general case: RestartIndex in middle, split into two prims */ prim[0].start = start; prim[0].count = ctx->Array.RestartIndex - start; prim[1] = prim[0]; prim[1].start = ctx->Array.RestartIndex + 1; prim[1].count = count - prim[1].start; primCount = 2; } if (primCount > 0) { /* draw one or two prims */ check_buffers_are_unmapped(exec->array.inputs); vbo->draw_prims(ctx, prim, primCount, NULL, GL_TRUE, start, start + count - 1, NULL); } } else { /* no prim restart */ prim[0].start = start; prim[0].count = count; check_buffers_are_unmapped(exec->array.inputs); vbo->draw_prims(ctx, prim, 1, NULL, GL_TRUE, start, start + count - 1, NULL); } if (MESA_DEBUG_FLAGS & DEBUG_ALWAYS_FLUSH) { _mesa_flush(ctx); } }
/** * 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); } }