summaryrefslogtreecommitdiff
path: root/src/mesa/tnl/t_imm_dlist.c
diff options
context:
space:
mode:
authorKeith Whitwell <keith@tungstengraphics.com>2000-12-26 05:09:27 +0000
committerKeith Whitwell <keith@tungstengraphics.com>2000-12-26 05:09:27 +0000
commitcab974cf6c2dbfbf5dd5d291e1aae0f8eeb34290 (patch)
tree45385bd755d8e3876c54b2b0113636f5ceb7976a /src/mesa/tnl/t_imm_dlist.c
parentd1ff1f6798b003a820f5de9fad835ff352f31afe (diff)
Major rework of tnl module
New array_cache module Support 8 texture units in core mesa (now support 8 everywhere) Rework core mesa statechange operations to avoid flushing on many noop statechanges.
Diffstat (limited to 'src/mesa/tnl/t_imm_dlist.c')
-rw-r--r--src/mesa/tnl/t_imm_dlist.c415
1 files changed, 415 insertions, 0 deletions
diff --git a/src/mesa/tnl/t_imm_dlist.c b/src/mesa/tnl/t_imm_dlist.c
new file mode 100644
index 0000000000..f5f3bca5cd
--- /dev/null
+++ b/src/mesa/tnl/t_imm_dlist.c
@@ -0,0 +1,415 @@
+/* $Id: t_imm_dlist.c,v 1.1 2000/12/26 05:09:32 keithw Exp $ */
+
+/*
+ * Mesa 3-D graphics library
+ * Version: 3.5
+ *
+ * Copyright (C) 1999 Brian Paul All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Author:
+ * Keith Whitwell <keithw@valinux.com>
+ */
+
+
+#include "glheader.h"
+#include "context.h"
+#include "dlist.h"
+#include "debug.h"
+#include "mmath.h"
+#include "mem.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;
+ GLboolean have_normal_lengths;
+} TNLvertexcassette;
+
+static void execute_compiled_cassette( GLcontext *ctx, void *data );
+
+
+/* Insert the active immediate struct onto the display list currently
+ * being built.
+ */
+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;
+
+
+ _tnl_compute_orflag( IM );
+
+ IM->CopyStart = IM->Start;
+
+ if (IM->OrFlag & VERT_ELT) {
+ GLuint andflag = ~0;
+ GLuint i;
+ GLuint start = IM->FlushElt ? IM->LastPrimitive : IM->CopyStart;
+ _tnl_translate_array_elts( ctx, IM, start, IM->Count );
+
+ /* Need to recompute andflag.
+ */
+ if (IM->AndFlag & VERT_ELT)
+ IM->CopyAndFlag = IM->AndFlag |= ctx->Array._Enabled;
+ else {
+ for (i = IM->CopyStart ; i < IM->Count ; i++)
+ andflag &= IM->Flag[i];
+ IM->CopyAndFlag = IM->AndFlag = andflag;
+ }
+ }
+
+ _tnl_fixup_input( ctx, IM );
+
+ /* Mark the last primitive:
+ */
+ IM->PrimitiveLength[IM->LastPrimitive] = IM->Count - IM->LastPrimitive;
+ ASSERT(IM->Primitive[IM->LastPrimitive] & PRIM_LAST);
+
+
+ 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->have_normal_lengths = GL_FALSE;
+
+ if (ctx->ExecuteFlag) {
+ execute_compiled_cassette( ctx, (void *)node );
+ }
+
+
+ /* Discard any errors raised in the last cassette.
+ */
+ new_beginstate = node->BeginState & (VERT_BEGIN_0|VERT_BEGIN_1);
+
+ /* Decide whether this immediate struct is full, or can be used for
+ * the next batch of vertices as well.
+ */
+ if (im->Count > IMM_MAXDATA - 16) {
+ /* Call it full...
+ */
+ struct immediate *new_im = _tnl_alloc_immediate(ctx);
+ if (!new_im) return;
+ new_im->ref_count++;
+ im->ref_count--; /* remove CURRENT_IM reference */
+ ASSERT(im->ref_count > 0);
+ SET_IMMEDIATE( ctx, new_im );
+ _tnl_reset_input( ctx, IMM_MAX_COPIED_VERTS,
+ new_beginstate, node->SavedBeginState );
+ } else {
+ /* Still some room in the current immediate.
+ */
+ _tnl_reset_input( ctx, im->Count+1+IMM_MAX_COPIED_VERTS,
+ new_beginstate, node->SavedBeginState);
+ }
+}
+
+
+
+static void calc_normal_lengths( GLfloat *dest,
+ CONST GLfloat (*data)[3],
+ GLuint *flags,
+ GLuint count )
+{
+ GLuint i;
+ GLint tmpflag = flags[0];
+
+ flags[0] |= VERT_NORM;
+
+ for (i = 0 ; i < count ; i++ )
+ if (flags[i] & VERT_NORM) {
+ GLfloat tmp = (GLfloat) LEN_3FV( data[i] );
+ dest[i] = 0;
+ if (tmp > 0)
+ dest[i] = 1.0F / tmp;
+ } else
+ dest[i] = dest[i-1];
+
+ flags[0] = tmpflag;
+}
+
+
+
+static void
+execute_compiled_cassette( GLcontext *ctx, void *data )
+{
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ TNLvertexcassette *node = (TNLvertexcassette *)data;
+ struct immediate *IM = node->IM;
+
+ FLUSH_VERTICES( ctx, 0 );
+
+ if (ctx->NewState)
+ gl_update_state(ctx);
+
+ if (tnl->pipeline.build_state_changes)
+ _tnl_validate_pipeline( ctx );
+
+ 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;
+
+ if ((MESA_VERBOSE & VERBOSE_DISPLAY_LIST) &&
+ (MESA_VERBOSE & VERBOSE_IMMEDIATE))
+ _tnl_print_cassette( IM );
+
+ if (MESA_VERBOSE & VERBOSE_DISPLAY_LIST) {
+ fprintf(stderr, "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) {
+ gl_error(ctx, GL_INVALID_OPERATION, "hard replay");
+ return;
+ }
+ }
+
+
+
+ /* Lazy optimization of the cassette.
+ */
+/* if (ctx->Transform.Normalize && !node->have_normal_lengths) { */
+
+/* if (!IM->NormalLengths) */
+/* IM->NormalLengths = (GLfloat *)MALLOC(sizeof(GLfloat) * IMM_SIZE); */
+
+/* calc_normal_lengths( IM->NormalLengths + IM->Start, */
+/* (const GLfloat (*)[3])(IM->Normal + IM->Start), */
+/* IM->Flag + IM->Start, */
+/* IM->Count - IM->Start); */
+
+/* node->have_normal_lengths = GL_TRUE; */
+/* } */
+
+
+#if 0
+ if (0 && im->v.Obj.size < 4 && im->Count > 15) {
+ im->Bounds = (GLfloat (*)[3]) MALLOC(6 * sizeof(GLfloat));
+ (_tnl_calc_bound_tab[im->v.Obj.size])( im->Bounds, &im->v.Obj );
+ }
+#endif
+
+
+ _tnl_fixup_compiled_cassette( ctx, IM );
+ _tnl_get_exec_copy_verts( ctx, IM );
+ _tnl_run_cassette( ctx, IM );
+ _tnl_restore_compiled_cassette( 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( node->IM );
+}
+
+
+static void
+print_compiled_cassette( GLcontext *ctx, void *data )
+{
+ TNLvertexcassette *node = (TNLvertexcassette *)data;
+ struct immediate *IM = node->IM;
+
+ fprintf(stderr, "TNL-VERTEX-CASSETTE, id %u, rows %u..%u\n",
+ node->IM->id, node->Start, node->Count);
+
+ IM->Start = 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;
+
+ _tnl_print_cassette( node->IM );
+}
+
+void
+_tnl_BeginCallList( GLcontext *ctx, GLuint list )
+{
+ (void) ctx;
+ (void) list;
+ FLUSH_CURRENT(ctx, 0);
+}
+
+
+/* Called at the tail of a CallList. Copy vertices out of the display
+ * list if necessary.
+ */
+void
+_tnl_EndCallList( GLcontext *ctx )
+{
+ /* May have to copy vertices from a dangling begin/end inside the
+ * list to the current immediate.
+ */
+ if (ctx->CallDepth == 0) {
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ struct immediate *IM = TNL_CURRENT_IM(ctx);
+
+ if (tnl->ExecCopySource != IM)
+ _tnl_copy_immediate_vertices( ctx, IM );
+ }
+}
+
+
+void
+_tnl_EndList( GLcontext *ctx )
+{
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ struct immediate *IM = TNL_CURRENT_IM(ctx);
+
+ IM->ref_count--;
+ if (IM == tnl->ExecCopySource)
+ IM->ref_count--;
+
+ /* If this one isn't free, get a clean one. (Otherwise we'll be
+ * using one that's already half full).
+ */
+ if (IM->ref_count != 0)
+ IM = _tnl_alloc_immediate( ctx );
+
+ ASSERT(IM->ref_count == 0);
+
+ tnl->ExecCopySource = IM;
+ IM->ref_count++;
+
+ SET_IMMEDIATE( ctx, IM );
+ IM->ref_count++;
+
+ _tnl_reset_input( ctx, IMM_MAX_COPIED_VERTS, 0, 0 );
+
+ /* outside begin/end, even in COMPILE_AND_EXEC,
+ * so no vertices to copy, right?
+ */
+ ASSERT(TNL_CONTEXT(ctx)->ExecCopyCount == 0);
+}
+
+
+void
+_tnl_NewList( GLcontext *ctx, GLuint list, GLenum mode )
+{
+ struct immediate *IM = TNL_CURRENT_IM(ctx);
+
+ /* Use the installed immediate struct. No vertices in the current
+ * immediate, no copied vertices in the system.
+ */
+ 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);
+
+ /* Set current Begin/End state to unknown:
+ */
+ IM->BeginState = VERT_BEGIN_0;
+}
+
+
+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 );
+}
+
+/* Need to do this to get the correct begin/end error behaviour from
+ * functions like ColorPointerEXT which are still active in
+ * SAVE_AND_EXEC modes.
+ */
+void
+_tnl_save_Begin( GLenum mode )
+{
+ GET_CURRENT_CONTEXT(ctx);
+
+ if (mode > GL_POLYGON) {
+ _mesa_compile_error( ctx, GL_INVALID_ENUM, "glBegin" );
+ return;
+ }
+
+ if (ctx->ExecuteFlag) {
+ /* Preserve vtxfmt invarient:
+ */
+ if (ctx->NewState)
+ gl_update_state( ctx );
+
+ /* Slot in geomexec: No need to call setdispatch as we know
+ * CurrentDispatch is Save.
+ */
+ ASSERT(ctx->CurrentDispatch == ctx->Save);
+ }
+
+ _tnl_begin( ctx, mode );
+}