@@ -62,6 +62,7 @@ | |||
#define need_GL_SGI_color_table | |||
/* sw extensions not associated with some GL version */ | |||
#define need_GL_ARB_draw_elements_base_vertex | |||
#define need_GL_ARB_shader_objects | |||
#define need_GL_ARB_vertex_array_object | |||
#define need_GL_ARB_vertex_program | |||
@@ -96,6 +97,7 @@ const struct dri_extension card_extensions[] = | |||
{ "GL_SGI_color_table", GL_SGI_color_table_functions }, | |||
{ "GL_ARB_depth_clamp", NULL }, | |||
{ "GL_ARB_draw_elements_base_vertex", GL_ARB_draw_elements_base_vertex_functions }, | |||
{ "GL_ARB_shader_objects", GL_ARB_shader_objects_functions }, | |||
{ "GL_ARB_vertex_array_object", GL_ARB_vertex_array_object_functions }, | |||
{ "GL_ARB_vertex_program", GL_ARB_vertex_program_functions }, |
@@ -1317,6 +1317,7 @@ xmesa_convert_from_x_visual_type( int visualType ) | |||
#define need_GL_SGI_color_table | |||
/* sw extensions not associated with some GL version */ | |||
#define need_GL_ARB_draw_elements_base_vertex | |||
#define need_GL_ARB_shader_objects | |||
#define need_GL_ARB_sync | |||
#define need_GL_ARB_vertex_program | |||
@@ -1348,6 +1349,7 @@ const struct dri_extension card_extensions[] = | |||
{ "GL_SGI_color_table", GL_SGI_color_table_functions }, | |||
{ "GL_ARB_depth_clamp", NULL }, | |||
{ "GL_ARB_draw_elements_base_vertex", GL_ARB_draw_elements_base_vertex_functions }, | |||
{ "GL_ARB_shader_objects", GL_ARB_shader_objects_functions }, | |||
{ "GL_ARB_sync", GL_ARB_sync_functions }, | |||
{ "GL_ARB_vertex_program", GL_ARB_vertex_program_functions }, |
@@ -731,7 +731,7 @@ _mesa_noop_DrawElements(GLenum mode, GLsizei count, GLenum type, | |||
GET_CURRENT_CONTEXT(ctx); | |||
GLint i; | |||
if (!_mesa_validate_DrawElements( ctx, mode, count, type, indices )) | |||
if (!_mesa_validate_DrawElements( ctx, mode, count, type, indices, 0 )) | |||
return; | |||
CALL_Begin(GET_DISPATCH(), (mode)); | |||
@@ -757,6 +757,43 @@ _mesa_noop_DrawElements(GLenum mode, GLsizei count, GLenum type, | |||
CALL_End(GET_DISPATCH(), ()); | |||
} | |||
static void GLAPIENTRY | |||
_mesa_noop_DrawElementsBaseVertex(GLenum mode, GLsizei count, GLenum type, | |||
const GLvoid *indices, GLint basevertex) | |||
{ | |||
GET_CURRENT_CONTEXT(ctx); | |||
GLint i; | |||
if (!_mesa_validate_DrawElements( ctx, mode, count, type, indices, | |||
basevertex )) | |||
return; | |||
CALL_Begin(GET_DISPATCH(), (mode)); | |||
switch (type) { | |||
case GL_UNSIGNED_BYTE: | |||
for (i = 0 ; i < count ; i++) | |||
CALL_ArrayElement(GET_DISPATCH(), ( ((GLubyte *)indices)[i] + | |||
basevertex)); | |||
break; | |||
case GL_UNSIGNED_SHORT: | |||
for (i = 0 ; i < count ; i++) | |||
CALL_ArrayElement(GET_DISPATCH(), ( ((GLushort *)indices)[i] + | |||
basevertex )); | |||
break; | |||
case GL_UNSIGNED_INT: | |||
for (i = 0 ; i < count ; i++) | |||
CALL_ArrayElement(GET_DISPATCH(), ( ((GLuint *)indices)[i] + | |||
basevertex )); | |||
break; | |||
default: | |||
_mesa_error( ctx, GL_INVALID_ENUM, "glDrawElementsBaseVertex(type)" ); | |||
break; | |||
} | |||
CALL_End(GET_DISPATCH(), ()); | |||
} | |||
static void GLAPIENTRY | |||
_mesa_noop_DrawRangeElements(GLenum mode, | |||
@@ -768,7 +805,7 @@ _mesa_noop_DrawRangeElements(GLenum mode, | |||
if (_mesa_validate_DrawRangeElements( ctx, mode, | |||
start, end, | |||
count, type, indices )) | |||
count, type, indices, 0 )) | |||
CALL_DrawElements(GET_DISPATCH(), (mode, count, type, indices)); | |||
} | |||
@@ -786,6 +823,40 @@ _mesa_noop_MultiDrawElements(GLenum mode, const GLsizei *count, GLenum type, | |||
} | |||
} | |||
static void GLAPIENTRY | |||
_mesa_noop_DrawRangeElementsBaseVertex(GLenum mode, | |||
GLuint start, GLuint end, | |||
GLsizei count, GLenum type, | |||
const GLvoid *indices, GLint basevertex) | |||
{ | |||
GET_CURRENT_CONTEXT(ctx); | |||
if (_mesa_validate_DrawRangeElements( ctx, mode, | |||
start, end, | |||
count, type, indices, basevertex )) | |||
CALL_DrawElementsBaseVertex(GET_DISPATCH(), (mode, count, type, indices, | |||
basevertex)); | |||
} | |||
/* GL_EXT_multi_draw_arrays */ | |||
void GLAPIENTRY | |||
_mesa_noop_MultiDrawElementsBaseVertex(GLenum mode, const GLsizei *count, | |||
GLenum type, | |||
const GLvoid **indices, | |||
GLsizei primcount, | |||
const GLint *basevertex) | |||
{ | |||
GLsizei i; | |||
for (i = 0; i < primcount; i++) { | |||
if (count[i] > 0) { | |||
CALL_DrawElementsBaseVertex(GET_DISPATCH(), (mode, count[i], type, | |||
indices[i], | |||
basevertex[i])); | |||
} | |||
} | |||
} | |||
/* | |||
* Eval Mesh | |||
*/ | |||
@@ -995,6 +1066,9 @@ _mesa_noop_vtxfmt_init( GLvertexformat *vfmt ) | |||
vfmt->DrawElements = _mesa_noop_DrawElements; | |||
vfmt->DrawRangeElements = _mesa_noop_DrawRangeElements; | |||
vfmt->MultiDrawElementsEXT = _mesa_noop_MultiDrawElements; | |||
vfmt->DrawElementsBaseVertex = _mesa_noop_DrawElementsBaseVertex; | |||
vfmt->DrawRangeElementsBaseVertex = _mesa_noop_DrawRangeElementsBaseVertex; | |||
vfmt->MultiDrawElementsBaseVertex = _mesa_noop_MultiDrawElementsBaseVertex; | |||
vfmt->EvalMesh1 = _mesa_noop_EvalMesh1; | |||
vfmt->EvalMesh2 = _mesa_noop_EvalMesh2; | |||
} |
@@ -44,6 +44,13 @@ extern void GLAPIENTRY | |||
_mesa_noop_MultiDrawElements(GLenum mode, const GLsizei *count, GLenum type, | |||
const GLvoid **indices, GLsizei primcount); | |||
extern void GLAPIENTRY | |||
_mesa_noop_MultiDrawElementsBaseVertex(GLenum mode, const GLsizei *count, | |||
GLenum type, | |||
const GLvoid **indices, | |||
GLsizei primcount, | |||
const GLint *basevertex); | |||
extern void | |||
_mesa_noop_vtxfmt_init(GLvertexformat *vfmt); | |||
@@ -29,7 +29,7 @@ | |||
#include "imports.h" | |||
#include "mtypes.h" | |||
#include "state.h" | |||
#include "vbo/vbo.h" | |||
/** | |||
@@ -51,51 +51,6 @@ index_bytes(GLenum type, GLsizei count) | |||
} | |||
/** | |||
* Find the max index in the given element/index buffer | |||
*/ | |||
static GLuint | |||
max_buffer_index(GLcontext *ctx, GLuint count, GLenum type, | |||
const void *indices, | |||
struct gl_buffer_object *elementBuf) | |||
{ | |||
const GLubyte *map = NULL; | |||
GLuint max = 0; | |||
GLuint i; | |||
if (_mesa_is_bufferobj(elementBuf)) { | |||
/* elements are in a user-defined buffer object. need to map it */ | |||
map = ctx->Driver.MapBuffer(ctx, GL_ELEMENT_ARRAY_BUFFER, | |||
GL_READ_ONLY, elementBuf); | |||
/* Actual address is the sum of pointers */ | |||
indices = (const GLvoid *) ADD_POINTERS(map, (const GLubyte *) indices); | |||
} | |||
if (type == GL_UNSIGNED_INT) { | |||
for (i = 0; i < count; i++) | |||
if (((GLuint *) indices)[i] > max) | |||
max = ((GLuint *) indices)[i]; | |||
} | |||
else if (type == GL_UNSIGNED_SHORT) { | |||
for (i = 0; i < count; i++) | |||
if (((GLushort *) indices)[i] > max) | |||
max = ((GLushort *) indices)[i]; | |||
} | |||
else { | |||
ASSERT(type == GL_UNSIGNED_BYTE); | |||
for (i = 0; i < count; i++) | |||
if (((GLubyte *) indices)[i] > max) | |||
max = ((GLubyte *) indices)[i]; | |||
} | |||
if (map) { | |||
ctx->Driver.UnmapBuffer(ctx, GL_ELEMENT_ARRAY_BUFFER_ARB, elementBuf); | |||
} | |||
return max; | |||
} | |||
/** | |||
* Check if OK to draw arrays/elements. | |||
*/ | |||
@@ -124,6 +79,40 @@ check_valid_to_render(GLcontext *ctx, const char *function) | |||
return GL_TRUE; | |||
} | |||
static GLboolean | |||
check_index_bounds(GLcontext *ctx, GLsizei count, GLenum type, | |||
const GLvoid *indices, GLint basevertex) | |||
{ | |||
struct _mesa_prim prim; | |||
struct _mesa_index_buffer ib; | |||
GLuint min, max; | |||
/* Only the X Server needs to do this -- otherwise, accessing outside | |||
* array/BO bounds allows application termination. | |||
*/ | |||
if (!ctx->Const.CheckArrayBounds) | |||
return GL_TRUE; | |||
memset(&prim, 0, sizeof(prim)); | |||
prim.count = count; | |||
memset(&ib, 0, sizeof(ib)); | |||
ib.type = type; | |||
ib.ptr = indices; | |||
ib.obj = ctx->Array.ElementArrayBufferObj; | |||
vbo_get_minmax_index(ctx, &prim, &ib, &min, &max); | |||
if (min + basevertex < 0 || | |||
max + basevertex > ctx->Array.ArrayObj->_MaxElement) { | |||
/* the max element is out of bounds of one or more enabled arrays */ | |||
_mesa_warning(ctx, "glDrawElements() index=%u is " | |||
"out of bounds (max=%u)", max, ctx->Array.ArrayObj->_MaxElement); | |||
return GL_FALSE; | |||
} | |||
return GL_TRUE; | |||
} | |||
/** | |||
* Error checking for glDrawElements(). Includes parameter checking | |||
@@ -133,7 +122,7 @@ check_valid_to_render(GLcontext *ctx, const char *function) | |||
GLboolean | |||
_mesa_validate_DrawElements(GLcontext *ctx, | |||
GLenum mode, GLsizei count, GLenum type, | |||
const GLvoid *indices) | |||
const GLvoid *indices, GLint basevertex) | |||
{ | |||
ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE); | |||
@@ -177,17 +166,8 @@ _mesa_validate_DrawElements(GLcontext *ctx, | |||
return GL_FALSE; | |||
} | |||
if (ctx->Const.CheckArrayBounds) { | |||
/* find max array index */ | |||
GLuint max = max_buffer_index(ctx, count, type, indices, | |||
ctx->Array.ElementArrayBufferObj); | |||
if (max >= ctx->Array.ArrayObj->_MaxElement) { | |||
/* the max element is out of bounds of one or more enabled arrays */ | |||
_mesa_warning(ctx, "glDrawElements() index=%u is " | |||
"out of bounds (max=%u)", max, ctx->Array.ArrayObj->_MaxElement); | |||
return GL_FALSE; | |||
} | |||
} | |||
if (!check_index_bounds(ctx, count, type, indices, basevertex)) | |||
return GL_FALSE; | |||
return GL_TRUE; | |||
} | |||
@@ -202,7 +182,7 @@ GLboolean | |||
_mesa_validate_DrawRangeElements(GLcontext *ctx, GLenum mode, | |||
GLuint start, GLuint end, | |||
GLsizei count, GLenum type, | |||
const GLvoid *indices) | |||
const GLvoid *indices, GLint basevertex) | |||
{ | |||
ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE); | |||
@@ -250,14 +230,8 @@ _mesa_validate_DrawRangeElements(GLcontext *ctx, GLenum mode, | |||
return GL_FALSE; | |||
} | |||
if (ctx->Const.CheckArrayBounds) { | |||
GLuint max = max_buffer_index(ctx, count, type, indices, | |||
ctx->Array.ElementArrayBufferObj); | |||
if (max >= ctx->Array.ArrayObj->_MaxElement) { | |||
/* the max element is out of bounds of one or more enabled arrays */ | |||
return GL_FALSE; | |||
} | |||
} | |||
if (!check_index_bounds(ctx, count, type, indices, basevertex)) | |||
return GL_FALSE; | |||
return GL_TRUE; | |||
} |
@@ -37,13 +37,13 @@ _mesa_validate_DrawArrays(GLcontext *ctx, | |||
extern GLboolean | |||
_mesa_validate_DrawElements(GLcontext *ctx, | |||
GLenum mode, GLsizei count, GLenum type, | |||
const GLvoid *indices); | |||
const GLvoid *indices, GLint basevertex); | |||
extern GLboolean | |||
_mesa_validate_DrawRangeElements(GLcontext *ctx, GLenum mode, | |||
GLuint start, GLuint end, | |||
GLsizei count, GLenum type, | |||
const GLvoid *indices); | |||
const GLvoid *indices, GLint basevertex); | |||
#endif |
@@ -1172,7 +1172,22 @@ typedef struct { | |||
GLenum type, | |||
const GLvoid **indices, | |||
GLsizei primcount); | |||
/*@}*/ | |||
void (GLAPIENTRYP DrawElementsBaseVertex)( GLenum mode, GLsizei count, | |||
GLenum type, | |||
const GLvoid *indices, | |||
GLint basevertex ); | |||
void (GLAPIENTRYP DrawRangeElementsBaseVertex)( GLenum mode, GLuint start, | |||
GLuint end, GLsizei count, | |||
GLenum type, | |||
const GLvoid *indices, | |||
GLint basevertex); | |||
void (GLAPIENTRYP MultiDrawElementsBaseVertex)( GLenum mode, | |||
const GLsizei *count, | |||
GLenum type, | |||
const GLvoid **indices, | |||
GLsizei primcount, | |||
const GLint *basevertex); | |||
/*@}*/ | |||
/** | |||
* \name Eval |
@@ -8711,6 +8711,9 @@ _mesa_save_vtxfmt_init(GLvertexformat * vfmt) | |||
vfmt->DrawElements = 0; | |||
vfmt->DrawRangeElements = 0; | |||
vfmt->MultiDrawElemementsEXT = 0; | |||
vfmt->DrawElementsBaseVertex = 0; | |||
vfmt->DrawRangeElementsBaseVertex = 0; | |||
vfmt->MultiDrawElemementsBaseVertex = 0; | |||
#endif | |||
} | |||
@@ -49,6 +49,7 @@ static const struct { | |||
{ OFF, "GL_ARB_depth_texture", F(ARB_depth_texture) }, | |||
{ OFF, "GL_ARB_depth_clamp", F(ARB_depth_clamp) }, | |||
{ ON, "GL_ARB_draw_buffers", F(ARB_draw_buffers) }, | |||
{ OFF, "GL_ARB_draw_elements_base_vertex", F(ARB_draw_elements_base_vertex) }, | |||
{ OFF, "GL_ARB_fragment_program", F(ARB_fragment_program) }, | |||
{ OFF, "GL_ARB_fragment_program_shadow", F(ARB_fragment_program_shadow) }, | |||
{ OFF, "GL_ARB_fragment_shader", F(ARB_fragment_shader) }, | |||
@@ -197,6 +198,7 @@ _mesa_enable_sw_extensions(GLcontext *ctx) | |||
ctx->Extensions.ARB_depth_clamp = GL_TRUE; | |||
ctx->Extensions.ARB_depth_texture = GL_TRUE; | |||
/*ctx->Extensions.ARB_draw_buffers = GL_TRUE;*/ | |||
ctx->Extensions.ARB_draw_elements_base_vertex = GL_TRUE; | |||
#if FEATURE_ARB_fragment_program | |||
ctx->Extensions.ARB_fragment_program = GL_TRUE; | |||
ctx->Extensions.ARB_fragment_program_shadow = GL_TRUE; |
@@ -2478,6 +2478,7 @@ struct gl_extensions | |||
GLboolean ARB_depth_texture; | |||
GLboolean ARB_depth_clamp; | |||
GLboolean ARB_draw_buffers; | |||
GLboolean ARB_draw_elements_base_vertex; | |||
GLboolean ARB_fragment_program; | |||
GLboolean ARB_fragment_program_shadow; | |||
GLboolean ARB_fragment_shader; |
@@ -129,6 +129,11 @@ extern void GLAPIENTRY | |||
_mesa_MultiDrawElementsEXT( GLenum mode, const GLsizei *count, GLenum type, | |||
const GLvoid **indices, GLsizei primcount ); | |||
extern void GLAPIENTRY | |||
_mesa_MultiDrawElementsBaseVertex( GLenum mode, | |||
const GLsizei *count, GLenum type, | |||
const GLvoid **indices, GLsizei primcount, | |||
const GLint *basevertex); | |||
extern void GLAPIENTRY | |||
_mesa_MultiModeDrawArraysIBM( const GLenum * mode, const GLint * first, | |||
@@ -159,6 +164,16 @@ extern void GLAPIENTRY | |||
_mesa_DrawRangeElements(GLenum mode, GLuint start, GLuint end, GLsizei count, | |||
GLenum type, const GLvoid *indices); | |||
extern void GLAPIENTRY | |||
_mesa_DrawElementsBaseVertex(GLenum mode, GLsizei count, GLenum type, | |||
const GLvoid *indices, GLint basevertex); | |||
extern void GLAPIENTRY | |||
_mesa_DrawRangeElementsBaseVertex(GLenum mode, GLuint start, GLuint end, | |||
GLsizei count, GLenum type, | |||
const GLvoid *indices, | |||
GLint basevertex); | |||
extern void | |||
_mesa_copy_client_array(GLcontext *ctx, |
@@ -134,6 +134,9 @@ install_vtxfmt( struct _glapi_table *tab, const GLvertexformat *vfmt ) | |||
SET_DrawElements(tab, vfmt->DrawElements); | |||
SET_DrawRangeElements(tab, vfmt->DrawRangeElements); | |||
SET_MultiDrawElementsEXT(tab, vfmt->MultiDrawElementsEXT); | |||
SET_DrawElementsBaseVertex(tab, vfmt->DrawElementsBaseVertex); | |||
SET_DrawRangeElementsBaseVertex(tab, vfmt->DrawRangeElementsBaseVertex); | |||
SET_MultiDrawElementsBaseVertex(tab, vfmt->MultiDrawElementsBaseVertex); | |||
SET_EvalMesh1(tab, vfmt->EvalMesh1); | |||
SET_EvalMesh2(tab, vfmt->EvalMesh2); | |||
ASSERT(tab->EvalMesh2); |
@@ -354,6 +354,44 @@ static void GLAPIENTRY TAG(DrawRangeElements)( GLenum mode, GLuint start, | |||
CALL_DrawRangeElements(GET_DISPATCH(), ( mode, start, end, count, type, indices )); | |||
} | |||
static void GLAPIENTRY TAG(DrawElementsBaseVertex)( GLenum mode, | |||
GLsizei count, | |||
GLenum type, | |||
const GLvoid *indices, | |||
GLint basevertex) | |||
{ | |||
PRE_LOOPBACK( DrawElementsBaseVertex ); | |||
CALL_DrawElementsBaseVertex(GET_DISPATCH(), ( mode, count, type, | |||
indices, basevertex )); | |||
} | |||
static void GLAPIENTRY TAG(DrawRangeElementsBaseVertex)( GLenum mode, | |||
GLuint start, | |||
GLuint end, | |||
GLsizei count, | |||
GLenum type, | |||
const GLvoid *indices, | |||
GLint basevertex) | |||
{ | |||
PRE_LOOPBACK( DrawRangeElementsBaseVertex ); | |||
CALL_DrawRangeElementsBaseVertex(GET_DISPATCH(), ( mode, start, end, | |||
count, type, indices, | |||
basevertex )); | |||
} | |||
static void GLAPIENTRY TAG(MultiDrawElementsBaseVertex)( GLenum mode, | |||
const GLsizei *count, | |||
GLenum type, | |||
const GLvoid **indices, | |||
GLsizei primcount, | |||
const GLint *basevertex) | |||
{ | |||
PRE_LOOPBACK( MultiDrawElementsBaseVertex ); | |||
CALL_MultiDrawElementsBaseVertex(GET_DISPATCH(), ( mode, count, type, | |||
indices, | |||
primcount, basevertex )); | |||
} | |||
static void GLAPIENTRY TAG(EvalMesh1)( GLenum mode, GLint i1, GLint i2 ) | |||
{ | |||
PRE_LOOPBACK( EvalMesh1 ); | |||
@@ -534,6 +572,9 @@ static GLvertexformat TAG(vtxfmt) = { | |||
TAG(DrawElements), | |||
TAG(DrawRangeElements), | |||
TAG(MultiDrawElementsEXT), | |||
TAG(DrawElementsBaseVertex), | |||
TAG(DrawRangeElementsBaseVertex), | |||
TAG(MultiDrawElementsBaseVertex), | |||
TAG(EvalMesh1), | |||
TAG(EvalMesh2) | |||
}; |
@@ -316,22 +316,27 @@ static void bind_indices( GLcontext *ctx, | |||
ptr = ADD_POINTERS(ib->obj->Pointer, ib->ptr); | |||
if (ib->type == GL_UNSIGNED_INT) { | |||
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_SHORT) { | |||
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++); | |||
*elts++ = (GLuint)(*in++) + VB->Primitive[0].basevertex; | |||
} | |||
else { | |||
const GLubyte *in = (GLubyte *)ptr; | |||
for (i = 0; i < ib->count; i++) | |||
*elts++ = (GLuint)(*in++); | |||
*elts++ = (GLuint)(*in++) + VB->Primitive[0].basevertex; | |||
} | |||
} | |||
} | |||
@@ -390,10 +395,14 @@ void _tnl_draw_prims( GLcontext *ctx, | |||
TNLcontext *tnl = TNL_CONTEXT(ctx); | |||
const GLuint TEST_SPLIT = 0; | |||
const GLint max = TEST_SPLIT ? 8 : tnl->vb.Size - MAX_CLIPPED_VERTICES; | |||
GLuint max_basevertex = prim->basevertex; | |||
GLuint i; | |||
for (i = 1; i < nr_prims; i++) | |||
max_basevertex = MAX2(max_basevertex, prim[i].basevertex); | |||
if (0) | |||
{ | |||
GLuint i; | |||
_mesa_printf("%s %d..%d\n", __FUNCTION__, min_index, max_index); | |||
for (i = 0; i < nr_prims; i++) | |||
_mesa_printf("prim %d: %s start %d count %d\n", i, | |||
@@ -410,7 +419,7 @@ void _tnl_draw_prims( GLcontext *ctx, | |||
_tnl_vbo_draw_prims ); | |||
return; | |||
} | |||
else if (max_index > max) { | |||
else if (max_index + max_basevertex > max) { | |||
/* The software TNL pipeline has a fixed amount of storage for | |||
* vertices and it is necessary to split incoming drawing commands | |||
* if they exceed that limit. | |||
@@ -424,7 +433,7 @@ void _tnl_draw_prims( GLcontext *ctx, | |||
* recursively call back into this function. | |||
*/ | |||
vbo_split_prims( ctx, arrays, prim, nr_prims, ib, | |||
0, max_index, | |||
0, max_index + prim->basevertex, | |||
_tnl_vbo_draw_prims, | |||
&limits ); | |||
} | |||
@@ -435,17 +444,34 @@ void _tnl_draw_prims( GLcontext *ctx, | |||
struct gl_buffer_object *bo[VERT_ATTRIB_MAX + 1]; | |||
GLuint nr_bo = 0; | |||
/* Binding inputs may imply mapping some vertex buffer objects. | |||
* They will need to be unmapped below. | |||
*/ | |||
bind_inputs(ctx, arrays, max_index+1, bo, &nr_bo); | |||
bind_indices(ctx, ib, bo, &nr_bo); | |||
bind_prims(ctx, prim, nr_prims ); | |||
for (i = 0; i < nr_prims;) { | |||
GLuint this_nr_prims; | |||
/* Our SW TNL pipeline doesn't handle basevertex yet, so bind_indices | |||
* will rebase the elements to the basevertex, and we'll only | |||
* emit strings of prims with the same basevertex in one draw call. | |||
*/ | |||
for (this_nr_prims = 1; i + this_nr_prims < nr_prims; | |||
this_nr_prims++) { | |||
if (prim[i].basevertex != prim[i + this_nr_prims].basevertex) | |||
break; | |||
} | |||
/* Binding inputs may imply mapping some vertex buffer objects. | |||
* They will need to be unmapped below. | |||
*/ | |||
bind_prims(ctx, &prim[i], this_nr_prims); | |||
bind_inputs(ctx, arrays, max_index + prim[i].basevertex + 1, | |||
bo, &nr_bo); | |||
bind_indices(ctx, ib, bo, &nr_bo); | |||
TNL_CONTEXT(ctx)->Driver.RunPipeline(ctx); | |||
TNL_CONTEXT(ctx)->Driver.RunPipeline(ctx); | |||
unmap_vbos(ctx, bo, nr_bo); | |||
free_space(ctx); | |||
unmap_vbos(ctx, bo, nr_bo); | |||
free_space(ctx); | |||
i += this_nr_prims; | |||
} | |||
} | |||
} | |||
@@ -44,6 +44,7 @@ struct _mesa_prim { | |||
GLuint start; | |||
GLuint count; | |||
GLint basevertex; | |||
}; | |||
/* Would like to call this a "vbo_index_buffer", but this would be |
@@ -181,7 +181,7 @@ unmap_array_buffer(GLcontext *ctx, struct gl_client_array *array) | |||
*/ | |||
static void | |||
check_draw_elements_data(GLcontext *ctx, GLsizei count, GLenum elemType, | |||
const void *elements) | |||
const void *elements, GLint basevertex) | |||
{ | |||
struct gl_array_object *arrayObj = ctx->Array.ArrayObj; | |||
const void *elemMap; | |||
@@ -518,6 +518,7 @@ vbo_exec_DrawArrays(GLenum mode, GLint start, GLsizei count) | |||
prim[0].start = start; | |||
prim[0].count = count; | |||
prim[0].indexed = 0; | |||
prim[0].basevertex = 0; | |||
vbo->draw_prims( ctx, exec->array.inputs, prim, 1, NULL, | |||
GL_TRUE, start, start + count - 1 ); | |||
@@ -592,7 +593,8 @@ vbo_validated_drawrangeelements(GLcontext *ctx, GLenum mode, | |||
GLboolean index_bounds_valid, | |||
GLuint start, GLuint end, | |||
GLsizei count, GLenum type, | |||
const GLvoid *indices) | |||
const GLvoid *indices, | |||
GLint basevertex) | |||
{ | |||
struct vbo_context *vbo = vbo_context(ctx); | |||
struct vbo_exec_context *exec = &vbo->exec; | |||
@@ -626,6 +628,7 @@ vbo_validated_drawrangeelements(GLcontext *ctx, GLenum mode, | |||
prim[0].start = 0; | |||
prim[0].count = count; | |||
prim[0].indexed = 1; | |||
prim[0].basevertex = basevertex; | |||
/* Need to give special consideration to rendering a range of | |||
* indices starting somewhere above zero. Typically the | |||
@@ -663,23 +666,25 @@ vbo_validated_drawrangeelements(GLcontext *ctx, GLenum mode, | |||
} | |||
static void GLAPIENTRY | |||
vbo_exec_DrawRangeElements(GLenum mode, | |||
GLuint start, GLuint end, | |||
GLsizei count, GLenum type, const GLvoid *indices) | |||
vbo_exec_DrawRangeElementsBaseVertex(GLenum mode, | |||
GLuint start, GLuint end, | |||
GLsizei count, GLenum type, | |||
const GLvoid *indices, | |||
GLint basevertex) | |||
{ | |||
GET_CURRENT_CONTEXT(ctx); | |||
if (!_mesa_validate_DrawRangeElements( ctx, mode, start, end, count, | |||
type, indices )) | |||
type, indices, basevertex )) | |||
return; | |||
if (end >= ctx->Array.ArrayObj->_MaxElement) { | |||
/* the max element is out of bounds of one or more enabled arrays */ | |||
_mesa_warning(ctx, "glDraw[Range]Elements(start %u, end %u, count %d, " | |||
"type 0x%x, indices=%p)\n" | |||
_mesa_warning(ctx, "glDraw[Range]Elements{,BaseVertex}(start %u, end %u, " | |||
"count %d, type 0x%x, indices=%p, base=%d)\n" | |||
"\tindex=%u is out of bounds (max=%u) " | |||
"Element Buffer %u (size %d)", | |||
start, end, count, type, indices, end, | |||
start, end, count, type, indices, end, basevertex, | |||
ctx->Array.ArrayObj->_MaxElement - 1, | |||
ctx->Array.ElementArrayBufferObj->Name, | |||
ctx->Array.ElementArrayBufferObj->Size); | |||
@@ -692,10 +697,12 @@ vbo_exec_DrawRangeElements(GLenum mode, | |||
return; | |||
} | |||
else if (0) { | |||
_mesa_printf("glDraw[Range]Elements" | |||
"(start %u, end %u, type 0x%x, count %d) ElemBuf %u\n", | |||
_mesa_printf("glDraw[Range]Elements{,BaseVertex}" | |||
"(start %u, end %u, type 0x%x, count %d) ElemBuf %u, " | |||
"base %d\n", | |||
start, end, type, count, | |||
ctx->Array.ElementArrayBufferObj->Name); | |||
ctx->Array.ElementArrayBufferObj->Name, | |||
basevertex); | |||
} | |||
#if 0 | |||
@@ -705,7 +712,17 @@ vbo_exec_DrawRangeElements(GLenum mode, | |||
#endif | |||
vbo_validated_drawrangeelements(ctx, mode, GL_TRUE, start, end, | |||
count, type, indices); | |||
count, type, indices, basevertex); | |||
} | |||
static void GLAPIENTRY | |||
vbo_exec_DrawRangeElements(GLenum mode, | |||
GLuint start, GLuint end, | |||
GLsizei count, GLenum type, | |||
const GLvoid *indices) | |||
{ | |||
vbo_exec_DrawRangeElementsBaseVertex(mode, start, end, count, type, | |||
indices, 0); | |||
} | |||
@@ -715,18 +732,33 @@ vbo_exec_DrawElements(GLenum mode, GLsizei count, GLenum type, | |||
{ | |||
GET_CURRENT_CONTEXT(ctx); | |||
if (!_mesa_validate_DrawElements( ctx, mode, count, type, indices )) | |||
if (!_mesa_validate_DrawElements( ctx, mode, count, type, indices, 0 )) | |||
return; | |||
vbo_validated_drawrangeelements(ctx, mode, GL_FALSE, ~0, ~0, | |||
count, type, indices, 0); | |||
} | |||
static void GLAPIENTRY | |||
vbo_exec_DrawElementsBaseVertex(GLenum mode, GLsizei count, GLenum type, | |||
const GLvoid *indices, GLint basevertex) | |||
{ | |||
GET_CURRENT_CONTEXT(ctx); | |||
if (!_mesa_validate_DrawElements( ctx, mode, count, type, indices, | |||
basevertex )) | |||
return; | |||
vbo_validated_drawrangeelements(ctx, mode, GL_FALSE, ~0, ~0, | |||
count, type, indices); | |||
count, type, indices, basevertex); | |||
} | |||
/* Inner support for both _mesa_DrawElements and _mesa_DrawRangeElements */ | |||
static void | |||
vbo_validated_multidrawelements(GLcontext *ctx, GLenum mode, | |||
const GLsizei *count, GLenum type, | |||
const GLvoid **indices, GLsizei primcount) | |||
const GLvoid **indices, GLsizei primcount, | |||
const GLint *basevertex) | |||
{ | |||
struct vbo_context *vbo = vbo_context(ctx); | |||
struct vbo_exec_context *exec = &vbo->exec; | |||
@@ -820,6 +852,10 @@ vbo_validated_multidrawelements(GLcontext *ctx, GLenum mode, | |||
prim[i].start = ((uintptr_t)indices[i] - min_index_ptr) / index_type_size; | |||
prim[i].count = count[i]; | |||
prim[i].indexed = 1; | |||
if (basevertex != NULL) | |||
prim[i].basevertex = basevertex[i]; | |||
else | |||
prim[i].basevertex = 0; | |||
} | |||
vbo->draw_prims(ctx, exec->array.inputs, prim, primcount, &ib, | |||
@@ -840,6 +876,10 @@ vbo_validated_multidrawelements(GLcontext *ctx, GLenum mode, | |||
prim[0].start = 0; | |||
prim[0].count = count[i]; | |||
prim[0].indexed = 1; | |||
if (basevertex != NULL) | |||
prim[0].basevertex = basevertex[i]; | |||
else | |||
prim[0].basevertex = 0; | |||
} | |||
vbo->draw_prims(ctx, exec->array.inputs, prim, 1, &ib, | |||
@@ -860,13 +900,36 @@ vbo_exec_MultiDrawElements(GLenum mode, | |||
ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); | |||
for (i = 0; i < primcount; i++) { | |||
if (!_mesa_validate_DrawElements( ctx, mode, count[i], type, indices[i] )) | |||
if (!_mesa_validate_DrawElements(ctx, mode, count[i], type, indices[i], | |||
0)) | |||
return; | |||
} | |||
vbo_validated_multidrawelements(ctx, mode, count, type, indices, primcount); | |||
vbo_validated_multidrawelements(ctx, mode, count, type, indices, primcount, | |||
NULL); | |||
} | |||
static void GLAPIENTRY | |||
vbo_exec_MultiDrawElementsBaseVertex(GLenum mode, | |||
const GLsizei *count, GLenum type, | |||
const GLvoid **indices, | |||
GLsizei primcount, | |||
const GLsizei *basevertex) | |||
{ | |||
GET_CURRENT_CONTEXT(ctx); | |||
GLint i; | |||
ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); | |||
for (i = 0; i < primcount; i++) { | |||
if (!_mesa_validate_DrawElements(ctx, mode, count[i], type, indices[i], | |||
basevertex[i])) | |||
return; | |||
} | |||
vbo_validated_multidrawelements(ctx, mode, count, type, indices, primcount, | |||
basevertex); | |||
} | |||
/*********************************************************************** | |||
@@ -881,11 +944,17 @@ vbo_exec_array_init( struct vbo_exec_context *exec ) | |||
exec->vtxfmt.DrawElements = vbo_exec_DrawElements; | |||
exec->vtxfmt.DrawRangeElements = vbo_exec_DrawRangeElements; | |||
exec->vtxfmt.MultiDrawElementsEXT = vbo_exec_MultiDrawElements; | |||
exec->vtxfmt.DrawElementsBaseVertex = vbo_exec_DrawElementsBaseVertex; | |||
exec->vtxfmt.DrawRangeElementsBaseVertex = vbo_exec_DrawRangeElementsBaseVertex; | |||
exec->vtxfmt.MultiDrawElementsBaseVertex = vbo_exec_MultiDrawElementsBaseVertex; | |||
#else | |||
exec->vtxfmt.DrawArrays = _mesa_noop_DrawArrays; | |||
exec->vtxfmt.DrawElements = _mesa_noop_DrawElements; | |||
exec->vtxfmt.DrawRangeElements = _mesa_noop_DrawRangeElements; | |||
exec->vtxfmt.MultiDrawElementsEXT = _mesa_noop_MultiDrawElements; | |||
exec->vtxfmt.DrawElementsBaseVertex = _mesa_noop_DrawElementsBaseVertex; | |||
exec->vtxfmt.DrawRangeElementsBaseVertex = _mesa_noop_DrawRangeElementsBaseVertex; | |||
exec->vtxfmt.MultiDrawElementsBaseVertex = _mesa_noop_MultiDrawElementsBaseVertex; | |||
#endif | |||
} | |||
@@ -913,6 +982,13 @@ _mesa_DrawElements(GLenum mode, GLsizei count, GLenum type, | |||
vbo_exec_DrawElements(mode, count, type, indices); | |||
} | |||
void GLAPIENTRY | |||
_mesa_DrawElementsBaseVertex(GLenum mode, GLsizei count, GLenum type, | |||
const GLvoid *indices, GLint basevertex) | |||
{ | |||
vbo_exec_DrawElementsBaseVertex(mode, count, type, indices, basevertex); | |||
} | |||
/* This API entrypoint is not ordinarily used */ | |||
void GLAPIENTRY | |||
@@ -922,6 +998,15 @@ _mesa_DrawRangeElements(GLenum mode, GLuint start, GLuint end, GLsizei count, | |||
vbo_exec_DrawRangeElements(mode, start, end, count, type, indices); | |||
} | |||
void GLAPIENTRY | |||
_mesa_DrawRangeElementsBaseVertex(GLenum mode, GLuint start, GLuint end, | |||
GLsizei count, GLenum type, | |||
const GLvoid *indices, GLint basevertex) | |||
{ | |||
vbo_exec_DrawRangeElementsBaseVertex(mode, start, end, count, type, | |||
indices, basevertex); | |||
} | |||
/* GL_EXT_multi_draw_arrays */ | |||
void GLAPIENTRY | |||
_mesa_MultiDrawElementsEXT(GLenum mode, const GLsizei *count, GLenum type, | |||
@@ -929,3 +1014,13 @@ _mesa_MultiDrawElementsEXT(GLenum mode, const GLsizei *count, GLenum type, | |||
{ | |||
vbo_exec_MultiDrawElements(mode, count, type, indices, primcount); | |||
} | |||
void GLAPIENTRY | |||
_mesa_MultiDrawElementsBaseVertex(GLenum mode, | |||
const GLsizei *count, GLenum type, | |||
const GLvoid **indices, GLsizei primcount, | |||
const GLint *basevertex) | |||
{ | |||
vbo_exec_MultiDrawElementsBaseVertex(mode, count, type, indices, | |||
primcount, basevertex); | |||
} |
@@ -126,7 +126,20 @@ void vbo_rebase_prims( GLcontext *ctx, | |||
if (0) | |||
_mesa_printf("%s %d..%d\n", __FUNCTION__, min_index, max_index); | |||
if (ib) { | |||
if (ib && ctx->Extensions.ARB_draw_elements_base_vertex) { | |||
/* If we can just tell the hardware or the TNL to interpret our | |||
* indices with a different base, do so. | |||
*/ | |||
tmp_prims = (struct _mesa_prim *)_mesa_malloc(sizeof(*prim) * nr_prims); | |||
for (i = 0; i < nr_prims; i++) { | |||
tmp_prims[i] = prim[i]; | |||
tmp_prims[i].basevertex -= min_index; | |||
} | |||
prim = tmp_prims; | |||
} else if (ib) { | |||
/* Unfortunately need to adjust each index individually. | |||
*/ | |||
GLboolean map_ib = ib->obj->Name && !ib->obj->Pointer; |
@@ -826,6 +826,33 @@ static void GLAPIENTRY _save_DrawRangeElements(GLenum mode, | |||
_mesa_compile_error( ctx, GL_INVALID_OPERATION, "glDrawRangeElements" ); | |||
} | |||
static void GLAPIENTRY _save_DrawElementsBaseVertex(GLenum mode, | |||
GLsizei count, | |||
GLenum type, | |||
const GLvoid *indices, | |||
GLint basevertex) | |||
{ | |||
GET_CURRENT_CONTEXT(ctx); | |||
(void) mode; (void) count; (void) type; (void) indices; (void)basevertex; | |||
_mesa_compile_error( ctx, GL_INVALID_OPERATION, "glDrawElements" ); | |||
} | |||
static void GLAPIENTRY _save_DrawRangeElementsBaseVertex(GLenum mode, | |||
GLuint start, | |||
GLuint end, | |||
GLsizei count, | |||
GLenum type, | |||
const GLvoid *indices, | |||
GLint basevertex) | |||
{ | |||
GET_CURRENT_CONTEXT(ctx); | |||
(void) mode; (void) start; (void) end; (void) count; (void) type; | |||
(void) indices; (void)basevertex; | |||
_mesa_compile_error( ctx, GL_INVALID_OPERATION, "glDrawRangeElements" ); | |||
} | |||
static void GLAPIENTRY _save_DrawArrays(GLenum mode, GLint start, GLsizei count) | |||
{ | |||
GET_CURRENT_CONTEXT(ctx); | |||
@@ -907,7 +934,7 @@ static void GLAPIENTRY _save_OBE_DrawElements(GLenum mode, GLsizei count, GLenum | |||
GET_CURRENT_CONTEXT(ctx); | |||
GLint i; | |||
if (!_mesa_validate_DrawElements( ctx, mode, count, type, indices )) | |||
if (!_mesa_validate_DrawElements( ctx, mode, count, type, indices, 0 )) | |||
return; | |||
_ae_map_vbos( ctx ); | |||
@@ -948,7 +975,7 @@ static void GLAPIENTRY _save_OBE_DrawRangeElements(GLenum mode, | |||
GET_CURRENT_CONTEXT(ctx); | |||
if (_mesa_validate_DrawRangeElements( ctx, mode, | |||
start, end, | |||
count, type, indices )) | |||
count, type, indices, 0 )) | |||
_save_OBE_DrawElements( mode, count, type, indices ); | |||
} | |||
@@ -1039,9 +1066,11 @@ static void _save_vtxfmt_init( GLcontext *ctx ) | |||
vfmt->DrawArrays = _save_DrawArrays; | |||
vfmt->DrawElements = _save_DrawElements; | |||
vfmt->DrawRangeElements = _save_DrawRangeElements; | |||
vfmt->DrawElementsBaseVertex = _save_DrawElementsBaseVertex; | |||
vfmt->DrawRangeElementsBaseVertex = _save_DrawRangeElementsBaseVertex; | |||
/* Loops back into vfmt->DrawElements */ | |||
vfmt->MultiDrawElementsEXT = _mesa_noop_MultiDrawElements; | |||
vfmt->MultiDrawElementsBaseVertex = _mesa_noop_MultiDrawElementsBaseVertex; | |||
} | |||
@@ -1233,6 +1262,7 @@ void vbo_save_api_init( struct vbo_save_context *save ) | |||
ctx->ListState.ListVtxfmt.DrawRangeElements = _save_OBE_DrawRangeElements; | |||
/* loops back into _save_OBE_DrawElements */ | |||
ctx->ListState.ListVtxfmt.MultiDrawElementsEXT = _mesa_noop_MultiDrawElements; | |||
ctx->ListState.ListVtxfmt.MultiDrawElementsBaseVertex = _mesa_noop_MultiDrawElementsBaseVertex; | |||
_mesa_install_save_vtxfmt( ctx, &ctx->ListState.ListVtxfmt ); | |||
} | |||
@@ -50,6 +50,7 @@ | |||
#include "main/glheader.h" | |||
#include "main/imports.h" | |||
#include "main/mtypes.h" | |||
#include "main/macros.h" | |||
#include "vbo_split.h" | |||
#include "vbo.h" | |||
@@ -107,7 +108,12 @@ void vbo_split_prims( GLcontext *ctx, | |||
vbo_draw_func draw, | |||
const struct split_limits *limits ) | |||
{ | |||
GLuint max_basevertex = prim->basevertex; | |||
GLuint i; | |||
for (i = 1; i < nr_prims; i++) | |||
max_basevertex = MAX2(max_basevertex, prim[i].basevertex); | |||
if (ib) { | |||
if (limits->max_indices == 0) { | |||
/* Could traverse the indices, re-emitting vertices in turn. |
@@ -589,28 +589,40 @@ void vbo_split_copy( GLcontext *ctx, | |||
const struct split_limits *limits ) | |||
{ | |||
struct copy_context copy; | |||
GLuint i; | |||
GLuint i, this_nr_prims; | |||
for (i = 0; i < nr_prims;) { | |||
/* Our SW TNL pipeline doesn't handle basevertex yet, so bind_indices | |||
* will rebase the elements to the basevertex, and we'll only | |||
* emit strings of prims with the same basevertex in one draw call. | |||
*/ | |||
for (this_nr_prims = 1; i + this_nr_prims < nr_prims; | |||
this_nr_prims++) { | |||
if (prim[i].basevertex != prim[i + this_nr_prims].basevertex) | |||
break; | |||
} | |||
memset(©, 0, sizeof(copy)); | |||
memset(©, 0, sizeof(copy)); | |||
/* Require indexed primitives: | |||
*/ | |||
assert(ib); | |||
copy.ctx = ctx; | |||
copy.array = arrays; | |||
copy.prim = prim; | |||
copy.nr_prims = nr_prims; | |||
copy.ib = ib; | |||
copy.draw = draw; | |||
copy.limits = limits; | |||
/* Require indexed primitives: | |||
*/ | |||
assert(ib); | |||
/* Clear the vertex cache: | |||
*/ | |||
for (i = 0; i < ELT_TABLE_SIZE; i++) | |||
copy.vert_cache[i].in = ~0; | |||
copy.ctx = ctx; | |||
copy.array = arrays; | |||
copy.prim = &prim[i]; | |||
copy.nr_prims = this_nr_prims; | |||
copy.ib = ib; | |||
copy.draw = draw; | |||
copy.limits = limits; | |||
replay_init(©); | |||
replay_elts(©); | |||
replay_finish(©); | |||
/* Clear the vertex cache: | |||
*/ | |||
for (i = 0; i < ELT_TABLE_SIZE; i++) | |||
copy.vert_cache[i].in = ~0; | |||
replay_init(©); | |||
replay_elts(©); | |||
replay_finish(©); | |||
} | |||
} |