#include "glheader.h"
#include "api_validate.h"
#include "context.h"
#include "imports.h"
#include "macros.h"
#include "mmath.h"
#include "mtypes.h"
#include "state.h"
#include "array_cache/acache.h"
#include "t_array_api.h"
#include "t_array_import.h"
#include "t_imm_api.h"
#include "t_imm_exec.h"
#include "t_context.h"
#include "t_pipeline.h"
static void fallback_drawarrays( GLcontext *ctx, GLenum mode, GLint start,
GLsizei count )
{
if (_tnl_hard_begin( ctx, mode )) {
GLint i;
for (i = start; i < count; i++)
glArrayElement( i );
glEnd();
}
}
static void fallback_drawelements( GLcontext *ctx, GLenum mode, GLsizei count,
const GLuint *indices)
{
if (_tnl_hard_begin(ctx, mode)) {
GLint i;
for (i = 0 ; i < count ; i++)
glArrayElement( indices[i] );
glEnd();
}
}
static void _tnl_draw_range_elements( GLcontext *ctx, GLenum mode,
GLuint start, GLuint end,
GLsizei count, GLuint *indices )
{
TNLcontext *tnl = TNL_CONTEXT(ctx);
int i;
FLUSH_CURRENT( ctx, 0 );
if (tnl->pipeline.build_state_changes)
_tnl_validate_pipeline( ctx );
_tnl_vb_bind_arrays( ctx, start, end );
tnl->vb.FirstPrimitive = 0;
tnl->vb.Primitive[0] = mode | PRIM_BEGIN | PRIM_END | PRIM_LAST;
tnl->vb.PrimitiveLength[0] = count;
tnl->vb.Elts = (GLuint *)indices;
for (i = 0 ; i < count ; i++)
indices[i] -= start;
if (ctx->Array.LockCount)
tnl->Driver.RunPipeline( ctx );
else {
tnl->pipeline.run_input_changes |= ctx->Array._Enabled;
tnl->Driver.RunPipeline( ctx );
tnl->pipeline.run_input_changes |= ctx->Array._Enabled;
}
for (i = 0 ; i < count ; i++)
indices[i] += start;
}
void
_tnl_DrawArrays(GLenum mode, GLint start, GLsizei count)
{
GET_CURRENT_CONTEXT(ctx);
TNLcontext *tnl = TNL_CONTEXT(ctx);
struct vertex_buffer *VB = &tnl->vb;
GLuint thresh = (ctx->Driver.NeedFlush & FLUSH_STORED_VERTICES) ? 30 : 10;
if (MESA_VERBOSE & VERBOSE_API)
_mesa_debug(NULL, "_tnl_DrawArrays %d %d\n", start, count);
if (!_mesa_validate_DrawArrays( ctx, mode, start, count ))
return;
if (tnl->pipeline.build_state_changes)
_tnl_validate_pipeline( ctx );
if (ctx->CompileFlag) {
fallback_drawarrays( ctx, mode, start, start + count );
}
else if (!ctx->Array.LockCount && (GLuint) count < thresh) {
fallback_drawarrays( ctx, mode, start, start + count );
}
else if (ctx->Array.LockCount &&
count < (GLint) ctx->Const.MaxArrayLockSize) {
FLUSH_CURRENT( ctx, 0 );
if (start < (GLint) ctx->Array.LockFirst)
start = ctx->Array.LockFirst;
if (start + count > (GLint) ctx->Array.LockCount)
count = ctx->Array.LockCount - start;
_tnl_vb_bind_arrays( ctx, ctx->Array.LockFirst, ctx->Array.LockCount );
VB->FirstPrimitive = start;
VB->Primitive[start] = mode | PRIM_BEGIN | PRIM_END | PRIM_LAST;
VB->PrimitiveLength[start] = count;
tnl->Driver.RunPipeline( ctx );
}
else {
int bufsz = 256;
int j, nr;
int minimum, modulo, skip;
switch (mode) {
case GL_POINTS:
minimum = 0;
modulo = 1;
skip = 0;
break;
case GL_LINES:
minimum = 1;
modulo = 2;
skip = 1;
break;
case GL_LINE_STRIP:
minimum = 1;
modulo = 1;
skip = 0;
break;
case GL_TRIANGLES:
minimum = 2;
modulo = 3;
skip = 2;
break;
case GL_TRIANGLE_STRIP:
minimum = 2;
modulo = 1;
skip = 0;
break;
case GL_QUADS:
minimum = 3;
modulo = 4;
skip = 3;
break;
case GL_QUAD_STRIP:
minimum = 3;
modulo = 2;
skip = 0;
break;
case GL_LINE_LOOP:
case GL_TRIANGLE_FAN:
case GL_POLYGON:
default:
if (count < (GLint) ctx->Const.MaxArrayLockSize) {
bufsz = ctx->Const.MaxArrayLockSize;
minimum = 0;
modulo = 1;
skip = 0;
}
else {
fallback_drawarrays( ctx, mode, start, start + count );
return;
}
}
FLUSH_CURRENT( ctx, 0 );
bufsz -= bufsz % modulo;
bufsz -= minimum;
count += start;
for (j = start + minimum ; j < count ; j += nr + skip ) {
nr = MIN2( bufsz, count - j );
_tnl_vb_bind_arrays( ctx, j - minimum, j + nr );
VB->FirstPrimitive = 0;
VB->Primitive[0] = mode | PRIM_BEGIN | PRIM_END | PRIM_LAST;
VB->PrimitiveLength[0] = nr + minimum;
tnl->pipeline.run_input_changes |= ctx->Array._Enabled;
tnl->Driver.RunPipeline( ctx );
tnl->pipeline.run_input_changes |= ctx->Array._Enabled;
}
}
}
void
_tnl_DrawRangeElements(GLenum mode,
GLuint start, GLuint end,
GLsizei count, GLenum type, const GLvoid *indices)
{
GET_CURRENT_CONTEXT(ctx);
GLuint *ui_indices;
if (MESA_VERBOSE & VERBOSE_API)
_mesa_debug(NULL, "_tnl_DrawRangeElements %d %d %d\n", start, end, count);
if (!_mesa_validate_DrawRangeElements( ctx, mode, start, end, count,
type, indices ))
return;
ui_indices = (GLuint *)_ac_import_elements( ctx, GL_UNSIGNED_INT,
count, type, indices );
if (ctx->CompileFlag) {
fallback_drawelements( ctx, mode, count, ui_indices );
}
else if (ctx->Array.LockCount) {
if (start >= ctx->Array.LockFirst && end <= ctx->Array.LockCount)
_tnl_draw_range_elements( ctx, mode,
ctx->Array.LockFirst,
ctx->Array.LockCount,
count, ui_indices );
else {
_mesa_problem( ctx,
"DrawRangeElements references "
"elements outside locked range.");
}
}
else if (end + 1 - start < ctx->Const.MaxArrayLockSize) {
_tnl_draw_range_elements( ctx, mode, start, end + 1, count, ui_indices );
} else {
fallback_drawelements( ctx, mode, count, ui_indices );
}
}
void
_tnl_DrawElements(GLenum mode, GLsizei count, GLenum type,
const GLvoid *indices)
{
GET_CURRENT_CONTEXT(ctx);
GLuint *ui_indices;
if (MESA_VERBOSE & VERBOSE_API)
_mesa_debug(NULL, "_tnl_DrawElements %d\n", count);
if (!_mesa_validate_DrawElements( ctx, mode, count, type, indices ))
return;
ui_indices = (GLuint *)_ac_import_elements( ctx, GL_UNSIGNED_INT,
count, type, indices );
if (ctx->CompileFlag) {
fallback_drawelements( ctx, mode, count, ui_indices );
}
else if (ctx->Array.LockCount) {
_tnl_draw_range_elements( ctx, mode,
ctx->Array.LockFirst,
ctx->Array.LockCount,
count, ui_indices );
}
else {
GLuint max_elt = 0;
GLint i;
for (i = 0 ; i < count ; i++)
if (ui_indices[i] > max_elt)
max_elt = ui_indices[i];
if (max_elt < ctx->Const.MaxArrayLockSize &&
max_elt < (GLuint) count)
_tnl_draw_range_elements( ctx, mode, 0, max_elt+1, count, ui_indices );
else
fallback_drawelements( ctx, mode, count, ui_indices );
}
}
void _tnl_array_init( GLcontext *ctx )
{
TNLcontext *tnl = TNL_CONTEXT(ctx);
struct vertex_arrays *tmp = &tnl->array_inputs;
GLvertexformat *vfmt = &(TNL_CONTEXT(ctx)->vtxfmt);
GLuint i;
vfmt->DrawArrays = _tnl_DrawArrays;
vfmt->DrawElements = _tnl_DrawElements;
vfmt->DrawRangeElements = _tnl_DrawRangeElements;
_mesa_vector4f_init( &tmp->Obj, 0, 0 );
_mesa_vector4f_init( &tmp->Normal, 0, 0 );
_mesa_vector4f_init( &tmp->FogCoord, 0, 0 );
_mesa_vector1ui_init( &tmp->Index, 0, 0 );
_mesa_vector1ub_init( &tmp->EdgeFlag, 0, 0 );
for (i = 0; i < ctx->Const.MaxTextureUnits; i++)
_mesa_vector4f_init( &tmp->TexCoord[i], 0, 0);
tnl->tmp_primitive = (GLuint *)MALLOC(sizeof(GLuint)*tnl->vb.Size);
tnl->tmp_primitive_length = (GLuint *)MALLOC(sizeof(GLuint)*tnl->vb.Size);
}
void _tnl_array_destroy( GLcontext *ctx )
{
TNLcontext *tnl = TNL_CONTEXT(ctx);
if (tnl->tmp_primitive_length) FREE(tnl->tmp_primitive_length);
if (tnl->tmp_primitive) FREE(tnl->tmp_primitive);
}