#include "glheader.h"
#include "context.h"
#include "dlist.h"
#include "debug.h"
#include "mmath.h"
#include "imports.h"
#include "state.h"
#include "t_context.h"
#include "t_imm_api.h"
#include "t_imm_elt.h"
#include "t_imm_alloc.h"
#include "t_imm_dlist.h"
#include "t_imm_debug.h"
#include "t_imm_exec.h"
#include "t_imm_fixup.h"
#include "t_pipeline.h"
typedef struct {
struct immediate *IM;
GLuint Start;
GLuint Count;
GLuint BeginState;
GLuint SavedBeginState;
GLuint OrFlag;
GLuint AndFlag;
GLuint TexSize;
GLuint LastData;
GLuint LastPrimitive;
GLuint LastMaterial;
GLuint MaterialOrMask;
GLuint MaterialAndMask;
} TNLvertexcassette;
static void execute_compiled_cassette( GLcontext *ctx, void *data );
static void loopback_compiled_cassette( GLcontext *ctx, struct immediate *IM );
static void build_normal_lengths( struct immediate *IM )
{
GLuint i;
GLfloat len;
GLfloat (*data)[4] = IM->Attrib[VERT_ATTRIB_NORMAL] + IM->Start;
GLfloat *dest = IM->NormalLengthPtr;
GLuint *flags = IM->Flag + IM->Start;
GLuint count = IM->Count - IM->Start;
if (!dest) {
dest = IM->NormalLengthPtr = (GLfloat *) ALIGN_MALLOC( IMM_SIZE*sizeof(GLfloat), 32 );
if (!dest) return;
}
dest += IM->Start;
len = (GLfloat) LEN_3FV( data[0] );
if (len > 0.0F) len = 1.0F / len;
for (i = 0 ; i < count ; ) {
dest[i] = len;
if (flags[++i] & VERT_BIT_NORMAL) {
len = (GLfloat) LEN_3FV( data[i] );
if (len > 0.0F) len = 1.0F / len;
}
}
}
static void fixup_normal_lengths( struct immediate *IM )
{
GLuint i;
GLfloat len = 1.0F;
GLfloat (*data)[4] = IM->Attrib[VERT_ATTRIB_NORMAL];
GLfloat *dest = IM->NormalLengthPtr;
GLuint *flags = IM->Flag;
for (i = IM->CopyStart ; i <= IM->Start ; i++) {
len = (GLfloat) LEN_3FV( data[i] );
if (len > 0.0F) len = 1.0F / len;
dest[i] = len;
}
if (i < IM->Count) {
while (!(flags[i] & (VERT_BIT_NORMAL|VERT_BIT_END_VB))) {
dest[i] = len;
i++;
}
}
}
void
_tnl_compile_cassette( GLcontext *ctx, struct immediate *IM )
{
struct immediate *im = TNL_CURRENT_IM(ctx);
TNLcontext *tnl = TNL_CONTEXT(ctx);
TNLvertexcassette *node;
GLuint new_beginstate;
if (MESA_VERBOSE & VERBOSE_DISPLAY_LIST)
_mesa_debug(ctx, "_tnl_compiled_cassette IM: %d\n", IM->id);
if (IM->FlushElt) {
ASSERT (IM->FlushElt == FLUSH_ELT_LAZY);
_tnl_translate_array_elts( ctx, IM, IM->Start, IM->Count );
}
_tnl_compute_orflag( IM, IM->Start );
IM->OrFlag &= ~VERT_BIT_ELT;
IM->AndFlag &= ~VERT_BIT_ELT;
_tnl_fixup_input( ctx, IM );
node = (TNLvertexcassette *)
_mesa_alloc_instruction(ctx,
tnl->opcode_vertex_cassette,
sizeof(TNLvertexcassette));
if (!node)
return;
node->IM = im; im->ref_count++;
node->Start = im->Start;
node->Count = im->Count;
node->BeginState = im->BeginState;
node->SavedBeginState = im->SavedBeginState;
node->OrFlag = im->OrFlag;
node->TexSize = im->TexSize;
node->AndFlag = im->AndFlag;
node->LastData = im->LastData;
node->LastPrimitive = im->LastPrimitive;
node->LastMaterial = im->LastMaterial;
node->MaterialOrMask = im->MaterialOrMask;
node->MaterialAndMask = im->MaterialAndMask;
if (tnl->CalcDListNormalLengths) {
build_normal_lengths( im );
}
if (ctx->ExecuteFlag) {
execute_compiled_cassette( ctx, (void *)node );
}
new_beginstate = node->BeginState & (VERT_BEGIN_0|VERT_BEGIN_1);
if (im->Count > IMM_MAXDATA - 16) {
struct immediate *new_im = _tnl_alloc_immediate(ctx);
new_im->ref_count++;
im->ref_count--;
ASSERT(im->ref_count > 0);
SET_IMMEDIATE( ctx, new_im );
_tnl_reset_compile_input( ctx, IMM_MAX_COPIED_VERTS,
new_beginstate, node->SavedBeginState );
} else {
_tnl_reset_compile_input( ctx, im->Count+1+IMM_MAX_COPIED_VERTS,
new_beginstate, node->SavedBeginState);
}
}
static void fixup_compiled_primitives( GLcontext *ctx, struct immediate *IM )
{
TNLcontext *tnl = TNL_CONTEXT(ctx);
tnl->DlistPrimitive = IM->Primitive[IM->Start];
tnl->DlistPrimitiveLength = IM->PrimitiveLength[IM->Start];
tnl->DlistLastPrimitive = IM->LastPrimitive;
if (ctx->Driver.CurrentExecPrimitive == GL_POLYGON+1) {
GLuint i;
if (IM->BeginState & VERT_ERROR_1)
_mesa_error( ctx, GL_INVALID_OPERATION, "glBegin/glEnd");
for (i = IM->Start ; i <= IM->Count ; i += IM->PrimitiveLength[i])
if (IM->Flag[i] & (VERT_BIT_BEGIN|VERT_BIT_END_VB))
break;
ASSERT(IM->Start == IM->CopyStart);
if (i > IM->CopyStart || !(IM->Flag[IM->Start] & VERT_BIT_BEGIN)) {
IM->Primitive[IM->CopyStart] = GL_POLYGON+1;
IM->PrimitiveLength[IM->CopyStart] = i - IM->CopyStart;
if (IM->Flag[i] & VERT_BIT_END_VB) {
IM->Primitive[IM->CopyStart] |= PRIM_LAST;
IM->LastPrimitive = IM->CopyStart;
}
}
} else {
GLuint i;
if (IM->BeginState & VERT_ERROR_0)
_mesa_error( ctx, GL_INVALID_OPERATION, "glBegin/glEnd");
if (IM->CopyStart == IM->Start &&
IM->Flag[IM->Start] & (VERT_BIT_END | VERT_BIT_END_VB))
{
}
else
{
IM->Primitive[IM->CopyStart] = ctx->Driver.CurrentExecPrimitive;
if (tnl->ExecParity)
IM->Primitive[IM->CopyStart] |= PRIM_PARITY;
ASSERT(IM->PrimitiveLength[IM->Start] > 0 ||
IM->Flag[IM->Start] & (VERT_BIT_END | VERT_BIT_END_VB));
for (i = IM->Start ; i <= IM->Count ; i += IM->PrimitiveLength[i])
if (IM->Flag[i] & (VERT_BIT_END | VERT_BIT_END_VB)) {
IM->PrimitiveLength[IM->CopyStart] = i - IM->CopyStart;
if (IM->Flag[i] & VERT_BIT_END_VB) {
IM->Primitive[IM->CopyStart] |= PRIM_LAST;
IM->LastPrimitive = IM->CopyStart;
}
if (IM->Flag[i] & VERT_BIT_END) {
IM->Primitive[IM->CopyStart] |= PRIM_END;
}
break;
}
}
}
}
static void restore_compiled_primitives( GLcontext *ctx, struct immediate *IM )
{
TNLcontext *tnl = TNL_CONTEXT(ctx);
IM->Primitive[IM->Start] = tnl->DlistPrimitive;
IM->PrimitiveLength[IM->Start] = tnl->DlistPrimitiveLength;
}
static void
execute_compiled_cassette( GLcontext *ctx, void *data )
{
TNLcontext *tnl = TNL_CONTEXT(ctx);
TNLvertexcassette *node = (TNLvertexcassette *)data;
struct immediate *IM = node->IM;
IM->Start = node->Start;
IM->CopyStart = node->Start;
IM->Count = node->Count;
IM->BeginState = node->BeginState;
IM->SavedBeginState = node->SavedBeginState;
IM->OrFlag = node->OrFlag;
IM->TexSize = node->TexSize;
IM->AndFlag = node->AndFlag;
IM->LastData = node->LastData;
IM->LastPrimitive = node->LastPrimitive;
IM->LastMaterial = node->LastMaterial;
IM->MaterialOrMask = node->MaterialOrMask;
IM->MaterialAndMask = node->MaterialAndMask;
if ((MESA_VERBOSE & VERBOSE_DISPLAY_LIST) &&
(MESA_VERBOSE & VERBOSE_IMMEDIATE))
_tnl_print_cassette( IM );
if (MESA_VERBOSE & VERBOSE_DISPLAY_LIST) {
_mesa_debug(ctx, "Run cassette %d, rows %d..%d, beginstate %x ",
IM->id, IM->Start, IM->Count, IM->BeginState);
_tnl_print_vert_flags("orflag", IM->OrFlag);
}
if (IM->SavedBeginState) {
if (ctx->Driver.CurrentExecPrimitive == GL_POLYGON+1)
tnl->ReplayHardBeginEnd = 1;
if (!tnl->ReplayHardBeginEnd) {
_mesa_error(ctx, GL_INVALID_OPERATION, "hard replay");
return;
}
}
if (tnl->LoopbackDListCassettes) {
fixup_compiled_primitives( ctx, IM );
loopback_compiled_cassette( ctx, IM );
restore_compiled_primitives( ctx, IM );
}
else {
if (ctx->NewState)
_mesa_update_state(ctx);
if (tnl->pipeline.build_state_changes)
_tnl_validate_pipeline( ctx );
_tnl_fixup_compiled_cassette( ctx, IM );
fixup_compiled_primitives( ctx, IM );
if (IM->Primitive[IM->LastPrimitive] & PRIM_END)
ctx->Driver.CurrentExecPrimitive = GL_POLYGON+1;
else if ((IM->Primitive[IM->LastPrimitive] & PRIM_BEGIN) ||
(IM->Primitive[IM->LastPrimitive] & PRIM_MODE_MASK) ==
PRIM_OUTSIDE_BEGIN_END) {
ctx->Driver.CurrentExecPrimitive =
IM->Primitive[IM->LastPrimitive] & PRIM_MODE_MASK;
}
_tnl_get_exec_copy_verts( ctx, IM );
if (IM->NormalLengthPtr)
fixup_normal_lengths( IM );
if (IM->Count == IM->Start)
_tnl_copy_to_current( ctx, IM, IM->OrFlag, IM->LastData );
else {
_tnl_run_cassette( ctx, IM );
}
restore_compiled_primitives( ctx, IM );
}
if (ctx->Driver.CurrentExecPrimitive == GL_POLYGON+1)
tnl->ReplayHardBeginEnd = 0;
}
static void
destroy_compiled_cassette( GLcontext *ctx, void *data )
{
TNLvertexcassette *node = (TNLvertexcassette *)data;
if ( --node->IM->ref_count == 0 )
_tnl_free_immediate( ctx, node->IM );
}
static void
print_compiled_cassette( GLcontext *ctx, void *data )
{
TNLvertexcassette *node = (TNLvertexcassette *)data;
struct immediate *IM = node->IM;
_mesa_debug(ctx, "TNL-VERTEX-CASSETTE, id %u, rows %u..%u\n",
node->IM->id, node->Start, node->Count);
IM->Start = node->Start;
IM->CopyStart = node->Start;
IM->Count = node->Count;
IM->BeginState = node->BeginState;
IM->OrFlag = node->OrFlag;
IM->TexSize = node->TexSize;
IM->AndFlag = node->AndFlag;
IM->LastData = node->LastData;
IM->LastPrimitive = node->LastPrimitive;
IM->LastMaterial = node->LastMaterial;
IM->MaterialOrMask = node->MaterialOrMask;
IM->MaterialAndMask = node->MaterialAndMask;
_tnl_print_cassette( node->IM );
}
void
_tnl_BeginCallList( GLcontext *ctx, GLuint list )
{
(void) ctx;
(void) list;
FLUSH_CURRENT(ctx, 0);
}
void
_tnl_EndCallList( GLcontext *ctx )
{
GLuint beginstate = 0;
if (ctx->Driver.CurrentExecPrimitive != PRIM_OUTSIDE_BEGIN_END)
beginstate = VERT_BEGIN_0|VERT_BEGIN_1;
_tnl_reset_exec_input( ctx, TNL_CURRENT_IM(ctx)->Start, beginstate, 0 );
}
void
_tnl_EndList( GLcontext *ctx )
{
struct immediate *IM = TNL_CURRENT_IM(ctx);
ctx->swtnl_im = 0;
IM->ref_count--;
ASSERT(TNL_CONTEXT(ctx)->ExecCopyCount == 0);
if (IM->ref_count != 0)
IM = _tnl_alloc_immediate( ctx );
ASSERT(IM->ref_count == 0);
SET_IMMEDIATE( ctx, IM );
IM->ref_count++;
_tnl_reset_exec_input( ctx, IMM_MAX_COPIED_VERTS, 0, 0 );
}
void
_tnl_NewList( GLcontext *ctx, GLuint list, GLenum mode )
{
struct immediate *IM = TNL_CURRENT_IM(ctx);
ASSERT(TNL_CURRENT_IM(ctx));
ASSERT(TNL_CURRENT_IM(ctx)->Start == IMM_MAX_COPIED_VERTS);
ASSERT(TNL_CURRENT_IM(ctx)->Start == TNL_CURRENT_IM(ctx)->Count);
ASSERT(TNL_CONTEXT(ctx)->ExecCopyCount == 0);
IM->BeginState = VERT_BEGIN_0;
ctx->Driver.CurrentSavePrimitive = PRIM_UNKNOWN;
}
void
_tnl_dlist_init( GLcontext *ctx )
{
TNLcontext *tnl = TNL_CONTEXT(ctx);
tnl->opcode_vertex_cassette =
_mesa_alloc_opcode( ctx,
sizeof(TNLvertexcassette),
execute_compiled_cassette,
destroy_compiled_cassette,
print_compiled_cassette );
}
static void emit_material( struct gl_material *src, GLuint bitmask )
{
if (bitmask & FRONT_EMISSION_BIT)
glMaterialfv( GL_FRONT, GL_EMISSION, src[0].Emission );
if (bitmask & BACK_EMISSION_BIT)
glMaterialfv( GL_BACK, GL_EMISSION, src[1].Emission );
if (bitmask & FRONT_AMBIENT_BIT)
glMaterialfv( GL_FRONT, GL_AMBIENT, src[0].Ambient );
if (bitmask & BACK_AMBIENT_BIT)
glMaterialfv( GL_BACK, GL_AMBIENT, src[1].Ambient );
if (bitmask & FRONT_DIFFUSE_BIT)
glMaterialfv( GL_FRONT, GL_DIFFUSE, src[0].Diffuse );
if (bitmask & BACK_DIFFUSE_BIT)
glMaterialfv( GL_BACK, GL_DIFFUSE, src[1].Diffuse );
if (bitmask & FRONT_SPECULAR_BIT)
glMaterialfv( GL_FRONT, GL_SPECULAR, src[0].Specular );
if (bitmask & BACK_SPECULAR_BIT)
glMaterialfv( GL_BACK, GL_SPECULAR, src[1].Specular );
if (bitmask & FRONT_SHININESS_BIT)
glMaterialfv( GL_FRONT, GL_SHININESS, &src[0].Shininess );
if (bitmask & BACK_SHININESS_BIT)
glMaterialfv( GL_BACK, GL_SHININESS, &src[1].Shininess );
if (bitmask & FRONT_INDEXES_BIT) {
GLfloat ind[3];
ind[0] = src[0].AmbientIndex;
ind[1] = src[0].DiffuseIndex;
ind[2] = src[0].SpecularIndex;
glMaterialfv( GL_FRONT, GL_COLOR_INDEXES, ind );
}
if (bitmask & BACK_INDEXES_BIT) {
GLfloat ind[3];
ind[0] = src[1].AmbientIndex;
ind[1] = src[1].DiffuseIndex;
ind[2] = src[1].SpecularIndex;
glMaterialfv( GL_BACK, GL_COLOR_INDEXES, ind );
}
}
static void loopback_compiled_cassette( GLcontext *ctx, struct immediate *IM )
{
GLuint i;
GLuint *flags = IM->Flag;
GLuint orflag = IM->OrFlag;
GLuint j;
void (GLAPIENTRY *vertex)( const GLfloat * );
void (GLAPIENTRY *texcoordfv[MAX_TEXTURE_UNITS])( GLenum, const GLfloat * );
GLuint maxtex = 0;
GLuint p, length, prim = 0;
if (orflag & VERT_BITS_OBJ_234)
vertex = (void (GLAPIENTRY *)(const GLfloat *)) glVertex4fv;
else
vertex = (void (GLAPIENTRY *)(const GLfloat *)) glVertex3fv;
if (orflag & VERT_BITS_TEX_ANY) {
for (j = 0 ; j < ctx->Const.MaxTextureUnits ; j++) {
if (orflag & VERT_BIT_TEX(j)) {
maxtex = j+1;
if ((IM->TexSize & TEX_SIZE_4(j)) == TEX_SIZE_4(j))
texcoordfv[j] = glMultiTexCoord4fvARB;
else if (IM->TexSize & TEX_SIZE_3(j))
texcoordfv[j] = glMultiTexCoord3fvARB;
else
texcoordfv[j] = glMultiTexCoord2fvARB;
}
}
}
for (p = IM->Start ; !(prim & PRIM_LAST) ; p += length)
{
prim = IM->Primitive[p];
length= IM->PrimitiveLength[p];
ASSERT(length || (prim & PRIM_LAST));
ASSERT((prim & PRIM_MODE_MASK) <= GL_POLYGON+1);
if (prim & PRIM_BEGIN) {
glBegin(prim & PRIM_MODE_MASK);
}
for ( i = p ; i <= p+length ; i++) {
if (flags[i] & VERT_BITS_TEX_ANY) {
GLuint k;
for (k = 0 ; k < maxtex ; k++) {
if (flags[i] & VERT_BIT_TEX(k)) {
texcoordfv[k]( GL_TEXTURE0_ARB + k,
IM->Attrib[VERT_ATTRIB_TEX0 + k][i] );
}
}
}
if (flags[i] & VERT_BIT_NORMAL)
glNormal3fv(IM->Attrib[VERT_ATTRIB_NORMAL][i]);
if (flags[i] & VERT_BIT_COLOR0)
glColor4fv( IM->Attrib[VERT_ATTRIB_COLOR0][i] );
if (flags[i] & VERT_BIT_COLOR1)
_glapi_Dispatch->SecondaryColor3fvEXT( IM->Attrib[VERT_ATTRIB_COLOR1][i] );
if (flags[i] & VERT_BIT_FOG)
_glapi_Dispatch->FogCoordfEXT( IM->Attrib[VERT_ATTRIB_FOG][i][0] );
if (flags[i] & VERT_BIT_INDEX)
glIndexi( IM->Index[i] );
if (flags[i] & VERT_BIT_EDGEFLAG)
glEdgeFlag( IM->EdgeFlag[i] );
if (flags[i] & VERT_BIT_MATERIAL)
emit_material( IM->Material[i], IM->MaterialMask[i] );
if (flags[i]&VERT_BITS_OBJ_234)
vertex( IM->Attrib[VERT_ATTRIB_POS][i] );
else if (flags[i] & VERT_BIT_EVAL_C1)
glEvalCoord1f( IM->Attrib[VERT_ATTRIB_POS][i][0] );
else if (flags[i] & VERT_BIT_EVAL_P1)
glEvalPoint1( (GLint) IM->Attrib[VERT_ATTRIB_POS][i][0] );
else if (flags[i] & VERT_BIT_EVAL_C2)
glEvalCoord2f( IM->Attrib[VERT_ATTRIB_POS][i][0],
IM->Attrib[VERT_ATTRIB_POS][i][1] );
else if (flags[i] & VERT_BIT_EVAL_P2)
glEvalPoint2( (GLint) IM->Attrib[VERT_ATTRIB_POS][i][0],
(GLint) IM->Attrib[VERT_ATTRIB_POS][i][1] );
}
if (prim & PRIM_END) {
glEnd();
}
}
}