diff options
author | Keith Whitwell <[email protected]> | 2000-12-26 05:09:27 +0000 |
---|---|---|
committer | Keith Whitwell <[email protected]> | 2000-12-26 05:09:27 +0000 |
commit | cab974cf6c2dbfbf5dd5d291e1aae0f8eeb34290 (patch) | |
tree | 45385bd755d8e3876c54b2b0113636f5ceb7976a /src/mesa/tnl | |
parent | d1ff1f6798b003a820f5de9fad835ff352f31afe (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')
38 files changed, 11388 insertions, 1012 deletions
diff --git a/src/mesa/tnl/t_array_api.c b/src/mesa/tnl/t_array_api.c new file mode 100644 index 00000000000..83d10337be3 --- /dev/null +++ b/src/mesa/tnl/t_array_api.c @@ -0,0 +1,355 @@ +/* $Id: t_array_api.c,v 1.1 2000/12/26 05:09:32 keithw Exp $ */ + +/* + * Mesa 3-D graphics library + * Version: 3.5 + * + * Copyright (C) 1999-2000 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. + * + * Authors: + * Keith Whitwell <[email protected]> + */ + +#include "glheader.h" +#include "api_validate.h" +#include "context.h" +#include "macros.h" +#include "mmath.h" +#include "mem.h" +#include "state.h" +#include "mtypes.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" + + + + + +void +_tnl_DrawArrays(GLenum mode, GLint start, GLsizei count) +{ + GET_CURRENT_CONTEXT(ctx); + TNLcontext *tnl = TNL_CONTEXT(ctx); + struct vertex_buffer *VB = &tnl->vb; + + /* Check arguments, etc. + */ + if (!_mesa_validate_DrawArrays( ctx, mode, start, count )) + return; + + if (tnl->pipeline.build_state_changes) + _tnl_validate_pipeline( ctx ); + + if (!ctx->CompileFlag && count - start < ctx->Const.MaxArrayLockSize) { + FLUSH_CURRENT( ctx, 0 ); + + if (ctx->Array.LockCount) + { + if (start < ctx->Array.LockFirst) start = ctx->Array.LockFirst; + if (count > ctx->Array.LockCount) count = ctx->Array.LockCount; + if (start >= count) return; + + /* Locked drawarrays. Reuse any previously transformed data. + */ + _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 - start; + _tnl_run_pipeline( ctx ); + } else { + /* The arrays are small enough to fit in a single VB; just bind + * them and go. Any untransformed data will be copied on + * clipping. + * + * Invalidate any locked data dependent on these arrays. + */ + _tnl_vb_bind_arrays( ctx, start, count ); + VB->FirstPrimitive = 0; + VB->Primitive[0] = mode | PRIM_BEGIN | PRIM_END | PRIM_LAST; + VB->PrimitiveLength[0] = count - start; + tnl->pipeline.run_input_changes |= ctx->Array._Enabled; + _tnl_run_pipeline( ctx ); + tnl->pipeline.run_input_changes |= ctx->Array._Enabled; + } + } + else { + /* Need to produce immediate structs, either for compiling or + * because the array range is too large to process in a single + * VB. In GL_EXECUTE mode, this introduces two redundant + * operations: producing the flag array and computing the orflag + * of the flag array. + */ +#if 0 + if (_tnl_hard_begin( ctx, mode )) { + GLuint j; + for (j = 0 ; j < count ; ) { + struct immediate *IM = TNL_CURRENT_IM(ctx); + GLuint nr = MIN2( IMM_MAXDATA - IM->Start, count - j ); + GLuint sf = IM->Flag[IM->Start]; + + _tnl_fill_immediate_drawarrays( ctx, IM, j, j+nr ); + + if (j == 0) IM->Flag[IM->Start] |= sf; + + IM->Count = IM->Start + nr; + j += nr; + + if (j == count) + _tnl_end( ctx ); + + _tnl_flush_immediate( IM ); + } + } +#else + /* Simple alternative to above code. + */ +/* if (_tnl_hard_begin( ctx, mode )) */ + _tnl_begin(ctx,mode); + { + GLuint i; + for (i=start;i<count;i++) { + _tnl_array_element( ctx, i ); + } + _tnl_end( ctx ); + } +#endif + } +} + + + +static void _tnl_draw_range_elements( GLcontext *ctx, GLenum mode, + GLuint start, GLuint end, + GLsizei count, const GLuint *indices ) + +{ + TNLcontext *tnl = TNL_CONTEXT(ctx); + FLUSH_CURRENT( ctx, 0 ); + + _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; + + if (ctx->Array.LockCount) + _tnl_run_pipeline( ctx ); + else { + /* Note that arrays may have changed before/after execution. + */ + tnl->pipeline.run_input_changes |= ctx->Array._Enabled; + _tnl_run_pipeline( ctx ); + tnl->pipeline.run_input_changes |= ctx->Array._Enabled; + } +} + + + + +static void _tnl_draw_elements( GLcontext *ctx, GLenum mode, GLsizei count, + const GLuint *indices) +{ +#if 1 + /* Optimized code that fakes the effect of calling + * _tnl_array_element for each index in the list. + */ + if (_tnl_hard_begin( ctx, mode )) { + GLuint i,j; + for (j = 0 ; j < count ; ) { + struct immediate *IM = TNL_CURRENT_IM(ctx); + GLuint start = IM->Start; + GLuint nr = MIN2( IMM_MAXDATA - start, count - j ) + start; + GLuint sf = IM->Flag[start]; + IM->FlushElt |= 1; + + for (i = start ; i < nr ; i++) { + IM->Elt[i] = (GLuint) *indices++; + IM->Flag[i] = VERT_ELT; + } + + if (j == 0) IM->Flag[start] |= sf; + + IM->Count = nr; + j += nr - start; + + if (j == count) + _tnl_end( ctx ); + + _tnl_flush_immediate( IM ); + } + } +#else + /* Simple version of the above code. + */ + if (_tnl_hard_begin(ctx, mode)) { + GLuint i; + for (i = 0 ; i < count ; i++) + _tnl_array_element( ctx, indices[i] ); + _tnl_end( ctx ); + } +#endif +} + + +void +_tnl_DrawRangeElements(GLenum mode, + GLuint start, GLuint end, + GLsizei count, GLenum type, const GLvoid *indices) +{ + GET_CURRENT_CONTEXT(ctx); + TNLcontext *tnl = TNL_CONTEXT(ctx); + GLuint *ui_indices; + + /* Check arguments, etc. + */ + if (!_mesa_validate_DrawRangeElements( ctx, mode, start, end, count, + type, indices )) + return; + + if (tnl->pipeline.build_state_changes) + _tnl_validate_pipeline( ctx ); + + ui_indices = (GLuint *)_ac_import_elements( ctx, GL_UNSIGNED_INT, + count, type, indices ); + + + if (ctx->Array.LockCount) { + /* Are the arrays already locked? If so we currently have to look + * at the whole locked range. + */ + 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 { + /* The spec says referencing elements outside the locked + * range is undefined. I'm going to make it a noop this time + * round, maybe come up with something beter before 3.6. + * + * May be able to get away with just setting LockCount==0, + * though this raises the problems of dependent state. May + * have to call glUnlockArrays() directly? + */ + gl_problem( ctx, + "DrawRangeElements references " + "elements outside locked range."); + } + } + else if (end - start < ctx->Const.MaxArrayLockSize) { + /* The arrays aren't locked but we can still fit them inside a single + * vertexbuffer. + */ + _tnl_draw_range_elements( ctx, mode, start, end, count, ui_indices ); + } else { + /* Range is too big to optimize: + */ + _tnl_draw_elements( ctx, mode, count, ui_indices ); + } +} + + + +void +_tnl_DrawElements(GLenum mode, GLsizei count, GLenum type, + const GLvoid *indices) +{ + GET_CURRENT_CONTEXT(ctx); + TNLcontext *tnl = TNL_CONTEXT(ctx); + GLuint *ui_indices; + + /* Check arguments, etc. + */ + if (!_mesa_validate_DrawElements( ctx, mode, count, type, indices )) + return; + + if (tnl->pipeline.build_state_changes) + _tnl_validate_pipeline( ctx ); + + ui_indices = (GLuint *)_ac_import_elements( ctx, GL_UNSIGNED_INT, + count, type, indices ); + + if (ctx->Array.LockCount) { + _tnl_draw_range_elements( ctx, mode, + ctx->Array.LockFirst, + ctx->Array.LockCount, + count, ui_indices ); + } + else { + /* Scan the index list and see if we can use the locked path anyway. + */ + GLuint max_elt = 0; + GLuint i; + + for (i = 0 ; i < count ; i++) + if (ui_indices[i] > max_elt) max_elt = ui_indices[i]; + + if (max_elt < ctx->Const.MaxArrayLockSize && /* can we use it? */ + max_elt < count) /* do we want to use it? */ + _tnl_draw_range_elements( ctx, mode, 0, max_elt, count, ui_indices ); + else + _tnl_draw_elements( 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; + + /* Setup vector pointers that will be used to bind arrays to VB's. + */ + gl_vector4f_init( &tmp->Obj, 0, 0 ); + gl_vector3f_init( &tmp->Normal, 0, 0 ); + gl_vector4ub_init( &tmp->Color, 0, 0 ); + gl_vector4ub_init( &tmp->SecondaryColor, 0, 0 ); + gl_vector1f_init( &tmp->FogCoord, 0, 0 ); + gl_vector1ui_init( &tmp->Index, 0, 0 ); + gl_vector1ub_init( &tmp->EdgeFlag, 0, 0 ); + + for (i = 0; i < ctx->Const.MaxTextureUnits; i++) + gl_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); +} diff --git a/src/mesa/tnl/t_array_api.h b/src/mesa/tnl/t_array_api.h new file mode 100644 index 00000000000..ebb99e78d6b --- /dev/null +++ b/src/mesa/tnl/t_array_api.h @@ -0,0 +1,47 @@ +/* $Id: t_array_api.h,v 1.1 2000/12/26 05:09:32 keithw Exp $ */ + +/* + * Mesa 3-D graphics library + * Version: 3.5 + * + * Copyright (C) 1999-2000 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. + */ + +#ifndef _T_VARRAY_H +#define _T_VARRAY_H + +#include "mtypes.h" +#include "t_context.h" + + +extern void _tnl_DrawArrays(GLenum mode, GLint first, GLsizei count); + +extern void _tnl_DrawElements(GLenum mode, GLsizei count, GLenum type, + const GLvoid *indices); + +extern void _tnl_DrawRangeElements(GLenum mode, GLuint start, + GLuint end, GLsizei count, GLenum type, + const GLvoid *indices); + + +extern void _tnl_array_init( GLcontext *ctx ); +extern void _tnl_array_destroy( GLcontext *ctx ); + +#endif diff --git a/src/mesa/tnl/t_array_import.c b/src/mesa/tnl/t_array_import.c new file mode 100644 index 00000000000..16a669dc287 --- /dev/null +++ b/src/mesa/tnl/t_array_import.c @@ -0,0 +1,521 @@ +/* $Id: t_array_import.c,v 1.1 2000/12/26 05:09:32 keithw Exp $ */ + +/* + * Mesa 3-D graphics library + * Version: 3.5 + * + * Copyright (C) 1999-2000 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. + * + * Authors: + * Keith Whitwell <[email protected]> + */ + +#include "glheader.h" +#include "context.h" +#include "macros.h" +#include "mem.h" +#include "mmath.h" +#include "state.h" +#include "mtypes.h" + +#include "array_cache/acache.h" +#include "math/m_translate.h" + +#include "t_array_import.h" +#include "t_context.h" + + +static void _tnl_import_vertex( GLcontext *ctx, + GLboolean writeable, + GLboolean stride ) +{ + struct gl_client_array *tmp; + GLboolean is_writeable = 0; + struct vertex_arrays *inputs = &TNL_CONTEXT(ctx)->array_inputs; + + tmp = _ac_import_vertex(ctx, + GL_FLOAT, + stride ? 4*sizeof(GLfloat) : 0, + 0, + writeable, + &is_writeable); + + inputs->Obj.data = tmp->Ptr; + inputs->Obj.start = (GLfloat *)tmp->Ptr; + inputs->Obj.stride = tmp->StrideB; + inputs->Obj.size = tmp->Size; + inputs->Obj.flags &= ~(VEC_BAD_STRIDE|VEC_NOT_WRITEABLE); + if (stride != 4*sizeof(GLfloat)) + inputs->Obj.flags |= VEC_BAD_STRIDE; + if (!is_writeable) + inputs->Obj.flags |= VEC_NOT_WRITEABLE; +} + +static void _tnl_import_normal( GLcontext *ctx, + GLboolean writeable, + GLboolean stride ) +{ + struct gl_client_array *tmp; + GLboolean is_writeable = 0; + struct vertex_arrays *inputs = &TNL_CONTEXT(ctx)->array_inputs; + + tmp = _ac_import_normal(ctx, GL_FLOAT, + stride ? 3*sizeof(GLfloat) : 0, writeable, + &is_writeable); + + inputs->Normal.data = tmp->Ptr; + inputs->Normal.start = (GLfloat *)tmp->Ptr; + inputs->Normal.stride = tmp->StrideB; + inputs->Normal.flags &= ~(VEC_BAD_STRIDE|VEC_NOT_WRITEABLE); + if (stride != 3*sizeof(GLfloat)) + inputs->Normal.flags |= VEC_BAD_STRIDE; + if (!is_writeable) + inputs->Normal.flags |= VEC_NOT_WRITEABLE; +} + + +static void _tnl_import_color( GLcontext *ctx, + GLboolean writeable, + GLboolean stride ) +{ + struct gl_client_array *tmp; + GLboolean is_writeable = 0; + struct vertex_arrays *inputs = &TNL_CONTEXT(ctx)->array_inputs; + + tmp = _ac_import_color(ctx, + GL_UNSIGNED_BYTE, + stride ? 4*sizeof(GLubyte) : 0, + 4, + writeable, + &is_writeable); + + inputs->Color.data = tmp->Ptr; + inputs->Color.start = (GLubyte *)tmp->Ptr; + inputs->Color.stride = tmp->StrideB; + inputs->Color.flags &= ~(VEC_BAD_STRIDE|VEC_NOT_WRITEABLE); + if (stride != 4*sizeof(GLubyte)) + inputs->Color.flags |= VEC_BAD_STRIDE; + if (!is_writeable) + inputs->Color.flags |= VEC_NOT_WRITEABLE; +} + + +static void _tnl_import_secondarycolor( GLcontext *ctx, + GLboolean writeable, + GLboolean stride ) +{ + struct gl_client_array *tmp; + GLboolean is_writeable = 0; + struct vertex_arrays *inputs = &TNL_CONTEXT(ctx)->array_inputs; + + tmp = _ac_import_secondarycolor(ctx, GL_UNSIGNED_BYTE, + stride ? 4*sizeof(GLubyte) : 0, + 4, + writeable, + &is_writeable); + + inputs->SecondaryColor.data = tmp->Ptr; + inputs->SecondaryColor.start = (GLubyte *)tmp->Ptr; + inputs->SecondaryColor.stride = tmp->StrideB; + inputs->SecondaryColor.flags &= ~(VEC_BAD_STRIDE|VEC_NOT_WRITEABLE); + if (stride != 4*sizeof(GLubyte)) + inputs->SecondaryColor.flags |= VEC_BAD_STRIDE; + if (!is_writeable) + inputs->SecondaryColor.flags |= VEC_NOT_WRITEABLE; +} + +static void _tnl_import_fogcoord( GLcontext *ctx, + GLboolean writeable, + GLboolean stride ) +{ + struct vertex_arrays *inputs = &TNL_CONTEXT(ctx)->array_inputs; + struct gl_client_array *tmp; + GLboolean is_writeable = 0; + + tmp = _ac_import_fogcoord(ctx, GL_FLOAT, + stride ? sizeof(GLfloat) : 0, writeable, + &is_writeable); + + inputs->FogCoord.data = tmp->Ptr; + inputs->FogCoord.start = (GLfloat *)tmp->Ptr; + inputs->FogCoord.stride = tmp->StrideB; + inputs->FogCoord.flags &= ~(VEC_BAD_STRIDE|VEC_NOT_WRITEABLE); + if (stride != sizeof(GLfloat)) + inputs->FogCoord.flags |= VEC_BAD_STRIDE; + if (!is_writeable) + inputs->FogCoord.flags |= VEC_NOT_WRITEABLE; +} + +static void _tnl_import_index( GLcontext *ctx, + GLboolean writeable, + GLboolean stride ) +{ + struct vertex_arrays *inputs = &TNL_CONTEXT(ctx)->array_inputs; + struct gl_client_array *tmp; + GLboolean is_writeable = 0; + + tmp = _ac_import_index(ctx, GL_UNSIGNED_INT, + stride ? sizeof(GLuint) : 0, writeable, + &is_writeable); + + inputs->Index.data = tmp->Ptr; + inputs->Index.start = (GLuint *)tmp->Ptr; + inputs->Index.stride = tmp->StrideB; + inputs->Index.flags &= ~(VEC_BAD_STRIDE|VEC_NOT_WRITEABLE); + if (stride != sizeof(GLuint)) + inputs->Index.flags |= VEC_BAD_STRIDE; + if (!is_writeable) + inputs->Index.flags |= VEC_NOT_WRITEABLE; +} + + +static void _tnl_import_texcoord( GLcontext *ctx, + GLuint i, + GLboolean writeable, + GLboolean stride ) +{ + struct vertex_arrays *inputs = &TNL_CONTEXT(ctx)->array_inputs; + struct gl_client_array *tmp; + GLboolean is_writeable = 0; + + tmp = _ac_import_texcoord(ctx, i, GL_FLOAT, + stride ? 4*sizeof(GLfloat) : 0, + 0, + writeable, + &is_writeable); + + inputs->TexCoord[i].data = tmp->Ptr; + inputs->TexCoord[i].start = (GLfloat *)tmp->Ptr; + inputs->TexCoord[i].stride = tmp->StrideB; + inputs->TexCoord[i].size = tmp->Size; + inputs->TexCoord[i].flags &= ~(VEC_BAD_STRIDE|VEC_NOT_WRITEABLE); + if (stride != 4*sizeof(GLfloat)) + inputs->TexCoord[i].flags |= VEC_BAD_STRIDE; + if (!is_writeable) + inputs->TexCoord[i].flags |= VEC_NOT_WRITEABLE; +} + + +static void _tnl_import_edgeflag( GLcontext *ctx, + GLboolean writeable, + GLboolean stride ) +{ + struct vertex_arrays *inputs = &TNL_CONTEXT(ctx)->array_inputs; + struct gl_client_array *tmp; + GLboolean is_writeable = 0; + + tmp = _ac_import_edgeflag(ctx, GL_UNSIGNED_BYTE, + stride ? sizeof(GLubyte) : 0, + 0, + &is_writeable); + + inputs->EdgeFlag.data = tmp->Ptr; + inputs->EdgeFlag.start = (GLubyte *)tmp->Ptr; + inputs->EdgeFlag.stride = tmp->StrideB; + inputs->EdgeFlag.flags &= ~(VEC_BAD_STRIDE|VEC_NOT_WRITEABLE); + if (stride != sizeof(GLubyte)) + inputs->EdgeFlag.flags |= VEC_BAD_STRIDE; + if (!is_writeable) + inputs->EdgeFlag.flags |= VEC_NOT_WRITEABLE; +} + + + +/* Callback for VB stages that need to improve the quality of arrays + * bound to the VB. This is only necessary for client arrays which + * have not been transformed at any point in the pipeline. + */ +static void _tnl_upgrade_client_data( GLcontext *ctx, + GLuint required, + GLuint flags ) +{ + GLuint i; + struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb; + struct vertex_arrays *inputs = &TNL_CONTEXT(ctx)->array_inputs; + GLboolean writeable = (flags & VEC_NOT_WRITEABLE) != 0; + GLboolean stride = (flags & VEC_BAD_STRIDE) != 0; + + if ((required & VERT_CLIP) && VB->ClipPtr == VB->ObjPtr) + required |= VERT_OBJ; + + if ((required & VERT_OBJ) && (VB->ObjPtr->flags & flags)) { + ASSERT(VB->ObjPtr == &inputs->Obj); + _tnl_import_vertex( ctx, writeable, stride ); + } + + if ((required & VERT_NORM) && (VB->NormalPtr->flags & flags)) { + ASSERT(VB->NormalPtr == &inputs->Normal); + _tnl_import_normal( ctx, writeable, stride ); + } + + if ((required & VERT_RGBA) && (VB->ColorPtr[0]->flags & flags)) { + ASSERT(VB->ColorPtr[0] == &inputs->Color); + _tnl_import_color( ctx, writeable, stride ); + } + + if ((required & VERT_SPEC_RGB) && (VB->SecondaryColorPtr[0]->flags&flags)) { + ASSERT(VB->SecondaryColorPtr[0] == &inputs->SecondaryColor); + _tnl_import_secondarycolor( ctx, writeable, stride ); + } + + if ((required & VERT_FOG_COORD) && (VB->FogCoordPtr->flags & flags)) { + ASSERT(VB->FogCoordPtr == &inputs->FogCoord); + _tnl_import_fogcoord( ctx, writeable, stride ); + } + + if ((required & VERT_INDEX) && (VB->IndexPtr[0]->flags & flags)) { + ASSERT(VB->IndexPtr[0] == &inputs->Index); + _tnl_import_index( ctx, writeable, stride ); + } + + if (required & VERT_TEX_ANY) + for (i = 0 ; i < ctx->Const.MaxTextureUnits ; i++) + if ((required & VERT_TEX(i)) && (VB->TexCoordPtr[i]->flags & flags)) { + ASSERT(VB->TexCoordPtr[i] == &inputs->TexCoord[i]); + _tnl_import_texcoord( ctx, i, writeable, stride ); + } + + if ((required & VERT_EDGE) && (VB->EdgeFlagPtr->flags & flags)) { + ASSERT(VB->EdgeFlagPtr == &inputs->EdgeFlag); + _tnl_import_edgeflag( ctx, writeable, stride ); + } + + VB->importable_data &= ~required; +} + + + + + +void _tnl_vb_bind_arrays( GLcontext *ctx, GLint start, GLsizei count ) +{ + TNLcontext *tnl = TNL_CONTEXT(ctx); + struct vertex_buffer *VB = &tnl->vb; + GLuint inputs = tnl->pipeline.inputs; + GLuint imports; + struct vertex_arrays *tmp = &tnl->array_inputs; + + if (ctx->Array.LockCount) { + ASSERT(start == ctx->Array.LockFirst); + ASSERT(count == ctx->Array.LockCount); + } + + imports = tnl->pipeline.inputs; + + _ac_import_range( ctx, start, count ); + + VB->Count = count - start; + VB->FirstClipped = VB->Count; + + VB->Elts = 0; + VB->MaterialMask = 0; + VB->Material = 0; + VB->Flag = 0; + +/* _tnl_print_vert_flags("_tnl_print_vert_flags: inputs", inputs); */ +/* _tnl_print_vert_flags("_tnl_print_vert_flags: imports", imports); */ +/* _tnl_print_vert_flags("_tnl_print_vert_flags: _Enabled", ctx->Array._Enabled); */ + + if (inputs & VERT_OBJ) { + if (imports & VERT_OBJ) { + _tnl_import_vertex( ctx, 0, 0 ); + tmp->Obj.count = VB->Count; + } + VB->ObjPtr = &tmp->Obj; + } + + if (inputs & VERT_NORM) { + if (imports & VERT_NORM) { + _tnl_import_normal( ctx, 0, 0 ); + tmp->Normal.count = VB->Count; + } + VB->NormalPtr = &tmp->Normal; + } + + if (inputs & VERT_RGBA) { + if (imports & VERT_RGBA) { + _tnl_import_color( ctx, 0, 0 ); + tmp->Color.count = VB->Count; + } + VB->ColorPtr[0] = &tmp->Color; + VB->ColorPtr[1] = 0; + } + + if (inputs & VERT_INDEX) { + if (imports & VERT_INDEX) { + _tnl_import_index( ctx, 0, 0 ); + tmp->Index.count = VB->Count; + } + VB->IndexPtr[0] = &tmp->Index; + VB->IndexPtr[1] = 0; + } + + + if (inputs & VERT_FOG_COORD) { + if (imports & VERT_FOG_COORD) { + _tnl_import_fogcoord( ctx, 0, 0 ); + tmp->FogCoord.count = VB->Count; + } + VB->FogCoordPtr = &tmp->FogCoord; + } + + if (inputs & VERT_EDGE) { + if (imports & VERT_EDGE) { + _tnl_import_edgeflag( ctx, 0, 0 ); + tmp->EdgeFlag.count = VB->Count; + } + VB->EdgeFlagPtr = &tmp->EdgeFlag; + } + + if (inputs & VERT_SPEC_RGB) { + if (imports & VERT_SPEC_RGB) { + _tnl_import_secondarycolor( ctx, 0, 0 ); + tmp->SecondaryColor.count = VB->Count; + } + VB->SecondaryColorPtr[0] = &tmp->SecondaryColor; + VB->SecondaryColorPtr[1] = 0; + } + + if (inputs & VERT_TEX_ANY) { + GLuint i; + for (i = 0; i < ctx->Const.MaxTextureUnits ; i++) + if (inputs & VERT_TEX(i)) { + if (imports & VERT_TEX(i)) { + _tnl_import_texcoord( ctx, i, 0, 0 ); + tmp->TexCoord[i].count = VB->Count; + } + VB->TexCoordPtr[i] = &tmp->TexCoord[i]; + } + } + + VB->Primitive = tnl->tmp_primitive; + VB->PrimitiveLength = tnl->tmp_primitive_length; + VB->import_data = _tnl_upgrade_client_data; + VB->importable_data = imports; +} + + + + +/* Function to fill an immediate struct with the effects of + * consecutive calls to ArrayElement with consecutive indices. + */ +void _tnl_fill_immediate_drawarrays( GLcontext *ctx, struct immediate *IM, + GLuint start, GLuint count ) +{ + TNLcontext *tnl = TNL_CONTEXT(ctx); + GLuint required = ctx->Array._Enabled; + GLuint n = count - start; + GLuint i; + + if (!ctx->CompileFlag) + required &= tnl->pipeline.inputs; + + if (MESA_VERBOSE&VERBOSE_IMMEDIATE) + fprintf(stderr, "exec_full_array_elements %d .. %d\n", start, count); + + _math_trans_4f( IM->Obj + IM->Start, + ctx->Array.Vertex.Ptr, + ctx->Array.Vertex.StrideB, + ctx->Array.Vertex.Type, + ctx->Array.Vertex.Size, + start, n ); + + if (ctx->Array.Vertex.Size == 4) + required |= VERT_OBJ_234; + else if (ctx->Array.Vertex.Size == 3) + required |= VERT_OBJ_23; + + + if (required & VERT_NORM) { + _math_trans_3f( IM->Normal + IM->Start, + ctx->Array.Normal.Ptr, + ctx->Array.Normal.StrideB, + ctx->Array.Normal.Type, + start, n ); + } + + if (required & VERT_EDGE) { + _math_trans_1ub( IM->EdgeFlag + IM->Start, + ctx->Array.EdgeFlag.Ptr, + ctx->Array.EdgeFlag.StrideB, + ctx->Array.EdgeFlag.Type, + start, n ); + } + + if (required & VERT_RGBA) { + _math_trans_4ub( IM->Color + IM->Start, + ctx->Array.Color.Ptr, + ctx->Array.Color.StrideB, + ctx->Array.Color.Type, + ctx->Array.Color.Size, + start, n ); + } + + if (required & VERT_SPEC_RGB) { + _math_trans_4ub( IM->SecondaryColor + IM->Start, + ctx->Array.SecondaryColor.Ptr, + ctx->Array.SecondaryColor.StrideB, + ctx->Array.SecondaryColor.Type, + ctx->Array.SecondaryColor.Size, + start, n ); + } + + if (required & VERT_FOG_COORD) { + _math_trans_1f( IM->FogCoord + IM->Start, + ctx->Array.FogCoord.Ptr, + ctx->Array.FogCoord.StrideB, + ctx->Array.FogCoord.Type, + start, n ); + } + + if (required & VERT_INDEX) { + _math_trans_1ui( IM->Index + IM->Start, + ctx->Array.Index.Ptr, + ctx->Array.Index.StrideB, + ctx->Array.Index.Type, + start, n ); + } + + if (required & VERT_TEX_ANY) { + for (i = 0 ; i < ctx->Const.MaxTextureUnits ; i++) { + if (required & VERT_TEX(i)) { + _math_trans_4f( IM->TexCoord[i] + IM->Start, + ctx->Array.TexCoord[i].Ptr, + ctx->Array.TexCoord[i].StrideB, + ctx->Array.TexCoord[i].Size, + ctx->Array.TexCoord[i].Type, + start, n ); + + if (ctx->Array.TexCoord[i].Size == 4) + IM->TexSize |= TEX_SIZE_4(i); + else if (ctx->Array.TexCoord[i].Size == 3) + IM->TexSize |= TEX_SIZE_3(i); + } + } + } + + IM->Count = IM->Start + n; + IM->Flag[IM->Start] |= required; + for (i = IM->Start+1 ; i < IM->Count ; i++) + IM->Flag[i] = required; +} + + diff --git a/src/mesa/tnl/t_array_import.h b/src/mesa/tnl/t_array_import.h new file mode 100644 index 00000000000..c1b903e24a5 --- /dev/null +++ b/src/mesa/tnl/t_array_import.h @@ -0,0 +1,42 @@ +/* $Id: t_array_import.h,v 1.1 2000/12/26 05:09:32 keithw Exp $ */ + +/* + * Mesa 3-D graphics library + * Version: 3.5 + * + * Copyright (C) 1999-2000 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. + */ + +#ifndef _T_ARRAY_IMPORT_H +#define _T_ARRAY_IMPORT_H + +#include "mtypes.h" +#include "t_context.h" + +extern void _tnl_vb_bind_arrays( GLcontext *ctx, GLint start, GLsizei count ); + +extern void _tnl_fill_immediate_drawarrays( GLcontext *ctx, + struct immediate *IM, + GLuint start, GLuint count ) ; + +extern void _tnl_array_import_init( GLcontext *ctx ); + + +#endif diff --git a/src/mesa/tnl/t_context.c b/src/mesa/tnl/t_context.c index d27a48b2960..5b879d8a831 100644 --- a/src/mesa/tnl/t_context.c +++ b/src/mesa/tnl/t_context.c @@ -1,101 +1,74 @@ +/* $Id: t_context.c,v 1.7 2000/12/26 05:09:32 keithw Exp $ */ + +/* + * Mesa 3-D graphics library + * Version: 3.5 + * + * Copyright (C) 1999-2000 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. + * + * Authors: + * Keith Whitwell <[email protected]> + */ + + +#include "glheader.h" +#include "macros.h" #include "mtypes.h" #include "mem.h" #include "dlist.h" #include "vtxfmt.h" #include "t_context.h" -#include "t_clip.h" -#include "t_cva.h" -#include "t_dlist.h" -#include "t_eval.h" +#include "t_array_api.h" +#include "t_eval_api.h" +#include "t_imm_alloc.h" +#include "t_imm_exec.h" +#include "t_imm_dlist.h" #include "t_pipeline.h" -#include "t_shade.h" -#include "t_light.h" -#include "t_texture.h" -#include "t_stages.h" -#include "t_varray.h" -#include "t_vb.h" -#include "t_vbrender.h" -#include "t_vbxform.h" -#include "t_vtxfmt.h" #include "tnl.h" -#if !defined(THREADS) +#ifndef THREADS struct immediate *_tnl_CurrentInput = NULL; #endif -GLboolean -_tnl_flush_vertices( GLcontext *ctx, GLuint flush_flags ) -{ - TNLcontext *tnl = TNL_CONTEXT(ctx); - struct immediate *IM = TNL_CURRENT_IM(ctx); - - if ((IM->Flag[IM->Count] & (VERT_BEGIN|VERT_END)) != VERT_END || - (flush_flags & (FLUSH_STORED_VERTICES|FLUSH_UPDATE_CURRENT))) - { - if (IM->Flag[IM->Start]) - _tnl_maybe_transform_vb( IM ); - - /* Although this code updates the ctx->Current values, that bit - * is left set as there is no easy mechanism to set it - * elsewhere. This means that each time core wants to examine - * ctx->Current, this function will be called. After the first - * time, however, it will be a no-op. - */ - ctx->Driver.NeedFlush &= ~(FLUSH_STORED_VERTICES | - FLUSH_INSIDE_BEGIN_END); - - return (tnl->_CurrentPrimitive == GL_POLYGON+1); - } - else - return GL_TRUE; -} - - - - void +void _tnl_MakeCurrent( GLcontext *ctx, GLframebuffer *drawBuffer, GLframebuffer *readBuffer ) { #ifndef THREADS - SET_IMMEDIATE( ctx, TNL_VB(ctx)->IM ); + SET_IMMEDIATE( ctx, TNL_CURRENT_IM(ctx) ); #endif } -/* Update all state that references _NeedEyeCoords - */ - void -_tnl_LightingSpaceChange( GLcontext *ctx ) -{ - _tnl_update_normal_transform( ctx ); -} - - static void install_driver_callbacks( GLcontext *ctx ) { - ctx->Driver.RenderVBCulledTab = _tnl_render_tab_cull; - ctx->Driver.RenderVBClippedTab = _tnl_render_tab_clipped; - ctx->Driver.RenderVBRawTab = _tnl_render_tab_raw; ctx->Driver.NewList = _tnl_NewList; ctx->Driver.EndList = _tnl_EndList; ctx->Driver.FlushVertices = _tnl_flush_vertices; - ctx->Driver.NeedFlush = FLUSH_UPDATE_CURRENT; - ctx->Driver.LightingSpaceChange = _tnl_LightingSpaceChange; ctx->Driver.MakeCurrent = _tnl_MakeCurrent; - ctx->Driver.VertexPointer = _tnl_VertexPointer; - ctx->Driver.NormalPointer = _tnl_NormalPointer; - ctx->Driver.ColorPointer = _tnl_ColorPointer; - ctx->Driver.FogCoordPointer = _tnl_FogCoordPointer; - ctx->Driver.IndexPointer = _tnl_IndexPointer; - ctx->Driver.SecondaryColorPointer = _tnl_SecondaryColorPointer; - ctx->Driver.TexCoordPointer = _tnl_TexCoordPointer; - ctx->Driver.EdgeFlagPointer = _tnl_EdgeFlagPointer; - ctx->Driver.LockArraysEXT = _tnl_LockArraysEXT; - ctx->Driver.UnlockArraysEXT = _tnl_UnlockArraysEXT; + ctx->Driver.BeginCallList = _tnl_BeginCallList; + ctx->Driver.EndCallList = _tnl_EndCallList; } @@ -104,21 +77,6 @@ GLboolean _tnl_CreateContext( GLcontext *ctx ) { TNLcontext *tnl; - static int firsttime = 1; - - /* Onetime initializations. Doesn't really matter if this gets - * done twice: no need for mutexes. - */ - if (firsttime) { - firsttime = 0; - _tnl_clip_init(); - _tnl_eval_init(); - _tnl_shade_init(); - _tnl_texture_init(); - _tnl_trans_elt_init(); - _tnl_vbrender_init(); - _tnl_stages_init(); - } /* Create the TNLcontext structure */ @@ -127,43 +85,35 @@ _tnl_CreateContext( GLcontext *ctx ) return GL_FALSE; } - /* Create and hook in the data structures available from ctx. + /* Initialize the VB. */ - ctx->swtnl_vb = (void *)_tnl_vb_create_for_immediate( ctx ); - if (!ctx->swtnl_vb) { - FREE(tnl); - ctx->swtnl_context = 0; - return GL_FALSE; - } + tnl->vb.Size = MAX2( IMM_SIZE, + ctx->Const.MaxArrayLockSize + MAX_CLIPPED_VERTICES); - ctx->swtnl_im = (void *)TNL_VB(ctx)->IM; - - /* Initialize tnl state. + /* Initialize tnl state and tnl->vtxfmt. */ _tnl_dlist_init( ctx ); - _tnl_pipeline_init( ctx ); - _tnl_vtxfmt_init( ctx ); - _tnl_cva_init( ctx ); - - _tnl_reset_vb( TNL_VB(ctx) ); - _tnl_reset_input( ctx, 0, 0 ); /* initially outside begin/end */ - - - tnl->_CurrentTex3Flag = 0; - tnl->_CurrentTex4Flag = 0; - tnl->_CurrentPrimitive = GL_POLYGON+1; + _tnl_array_init( ctx ); + _tnl_imm_init( ctx ); + _tnl_eval_init( ctx ); + _tnl_install_pipeline( ctx, _tnl_default_pipeline ); + /* Hook our functions into exec and compile dispatch tables. */ _mesa_install_exec_vtxfmt( ctx, &tnl->vtxfmt ); _mesa_install_save_vtxfmt( ctx, &tnl->vtxfmt ); ctx->Save->EvalMesh1 = _mesa_save_EvalMesh1; /* fixme */ ctx->Save->EvalMesh2 = _mesa_save_EvalMesh2; + ctx->Save->Begin = _tnl_save_Begin; /* Set a few default values in the driver struct. */ install_driver_callbacks(ctx); + ctx->Driver.NeedFlush = FLUSH_UPDATE_CURRENT|FLUSH_STORED_VERTICES; + ctx->Driver.CurrentExecPrimitive = PRIM_OUTSIDE_BEGIN_END; + ctx->Driver.CurrentSavePrimitive = PRIM_UNKNOWN; return GL_TRUE; } @@ -174,56 +124,45 @@ _tnl_DestroyContext( GLcontext *ctx ) { TNLcontext *tnl = TNL_CONTEXT(ctx); - if (TNL_CURRENT_IM(ctx) != TNL_VB(ctx)->IM) - _tnl_immediate_free( TNL_CURRENT_IM(ctx) ); - - _tnl_vb_free( TNL_VB(ctx) ); +/* _tnl_dlist_destroy( ctx ); */ + _tnl_array_destroy( ctx ); + _tnl_imm_destroy( ctx ); +/* _tnl_eval_destroy( ctx ); */ + _tnl_destroy_pipeline( ctx ); - /* Free cache of immediate buffers. */ - while (tnl->nr_im_queued-- > 0) { - struct immediate * next = tnl->freed_im_queue->next; - ALIGN_FREE( tnl->freed_im_queue ); - tnl->freed_im_queue = next; - } + FREE(tnl); + ctx->swtnl_context = 0; } - void _tnl_InvalidateState( GLcontext *ctx, GLuint new_state ) { - if (new_state & _NEW_LIGHT) - _tnl_update_lighting_function(ctx); - - if (new_state & _NEW_ARRAY) - _tnl_update_client_state( ctx ); - - if (new_state & _NEW_TEXTURE) - if (ctx->_Enabled & ENABLE_TEXGEN_ANY) - _tnl_update_texgen( ctx ); + TNLcontext *tnl = TNL_CONTEXT(ctx); - if (new_state & (_NEW_LIGHT|_NEW_TEXTURE|_NEW_FOG| - _DD_NEW_TRI_LIGHT_TWOSIDE | - _DD_NEW_SEPERATE_SPECULAR | - _DD_NEW_TRI_UNFILLED )) - _tnl_update_clipmask(ctx); + if (new_state & _NEW_ARRAY) { + struct immediate *IM = TNL_CURRENT_IM(ctx); + IM->ArrayEltFlags = ~ctx->Array._Enabled; + IM->ArrayEltFlush = !ctx->Array.LockCount; + IM->ArrayEltIncr = ctx->Array.Vertex.Enabled ? 1 : 0; + tnl->pipeline.run_input_changes |= ctx->Array.NewState; /* overkill */ + } - if (new_state & _TNL_NEW_NORMAL_TRANSFORM) - _tnl_update_normal_transform( ctx ); + tnl->pipeline.run_state_changes |= new_state; + tnl->pipeline.build_state_changes |= (new_state & + tnl->pipeline.build_state_trigger); - _tnl_update_pipelines(ctx); + tnl->eval.EvalNewState |= new_state; } + void _tnl_wakeup_exec( GLcontext *ctx ) { TNLcontext *tnl = TNL_CONTEXT(ctx); -#ifndef VMS - fprintf(stderr, "%s\n", __FUNCTION__); -#endif - install_driver_callbacks(ctx); + ctx->Driver.NeedFlush |= FLUSH_UPDATE_CURRENT; /* Hook our functions into exec and compile dispatch tables. */ @@ -232,35 +171,23 @@ _tnl_wakeup_exec( GLcontext *ctx ) /* Call all appropriate driver callbacks to revive state. */ _tnl_MakeCurrent( ctx, ctx->DrawBuffer, ctx->ReadBuffer ); - _tnl_UnlockArraysEXT( ctx ); - _tnl_LockArraysEXT( ctx, ctx->Array.LockFirst, ctx->Array.LockCount ); - - /* Equivalent to calling all _tnl_*Pointer functions: - */ - tnl->_ArrayNewState = ~0; /* Assume we haven't been getting state updates either: */ - _tnl_InvalidateState( ctx, ~0 ); - - /* Special state not restored by other methods: - */ - _tnl_validate_current_tex_flags( ctx, ~0 ); - + _tnl_InvalidateState( ctx, ~0 ); + tnl->pipeline.run_input_changes = ~0; } + void _tnl_wakeup_save_exec( GLcontext *ctx ) { TNLcontext *tnl = TNL_CONTEXT(ctx); -#ifndef VMS - fprintf(stderr, "%s\n", __FUNCTION__); -#endif - _tnl_wakeup_exec( ctx ); _mesa_install_save_vtxfmt( ctx, &tnl->vtxfmt ); ctx->Save->EvalMesh1 = _mesa_save_EvalMesh1; /* fixme */ ctx->Save->EvalMesh2 = _mesa_save_EvalMesh2; + ctx->Save->Begin = _tnl_save_Begin; } diff --git a/src/mesa/tnl/t_context.h b/src/mesa/tnl/t_context.h index fb036b9f3d9..1a4ebb2170f 100644 --- a/src/mesa/tnl/t_context.h +++ b/src/mesa/tnl/t_context.h @@ -1,5 +1,4 @@ - -/* $Id: t_context.h,v 1.6 2000/12/08 00:18:39 brianp Exp $ */ +/* $Id: t_context.h,v 1.7 2000/12/26 05:09:32 keithw Exp $ */ /* * Mesa 3-D graphics library @@ -23,6 +22,9 @@ * 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 <[email protected]> */ #ifndef _T_CONTEXT_H @@ -35,99 +37,91 @@ #include "math/m_vector.h" #include "math/m_xform.h" -#include "t_trans_elt.h" +#define MAX_PIPELINE_STAGES 30 -/* - * Bits to indicate which faces a vertex participates in, - * what facing the primitive provoked by that vertex has, - * and some misc. flags. +/* Numbers for sizing immediate structs. */ -#define VERT_FACE_FRONT 0x1 /* is in a front-color primitive */ -#define VERT_FACE_REAR 0x2 /* is in a rear-color primitive */ -#define PRIM_FACE_FRONT 0x4 /* use front color */ -#define PRIM_FACE_REAR 0x8 /* use rear color */ -#define PRIM_CLIPPED 0x10 /* needs clipping */ -#define PRIM_USER_CLIPPED CLIP_USER_BIT /* 0x40 */ +#define IMM_MAX_COPIED_VERTS 3 +#define IMM_MAXDATA (216 + IMM_MAX_COPIED_VERTS) +#define IMM_SIZE (IMM_MAXDATA + MAX_CLIPPED_VERTICES) -#define PRIM_FLAG_SHIFT 2 -#define PRIM_FACE_FLAGS (PRIM_FACE_FRONT|PRIM_FACE_REAR) -#define VERT_FACE_FLAGS (VERT_FACE_FRONT|VERT_FACE_REAR) - -#define PRIM_ANY_CLIP (PRIM_CLIPPED|PRIM_USER_CLIPPED) -#define PRIM_NOT_CULLED (PRIM_ANY_CLIP|PRIM_FACE_FLAGS) - -/* Flags for VB->CullMode. +/* Values for IM->BeginState */ -#define CULL_MASK_ACTIVE 0x1 -#define COMPACTED_NORMALS 0x2 -#define CLIP_MASK_ACTIVE 0x4 +#define VERT_BEGIN_0 0x1 /* glBegin (if initially inside beg/end) */ +#define VERT_BEGIN_1 0x2 /* glBegin (if initially outside beg/end) */ +#define VERT_ERROR_0 0x4 /* invalid_operation in initial state 0 */ +#define VERT_ERROR_1 0x8 /* invalid_operation in initial state 1 */ -/* Flags for selecting a shading function. The first two bits are - * shared with the cull mode (ie. cull_mask_active and - * compacted_normals.) + +/* Flags to be added to the primitive enum in VB->Primitive. */ -#define SHADE_TWOSIDE 0x4 +#define PRIM_MODE_MASK 0xff /* Extract the actual primitive */ +#define PRIM_BEGIN 0x100 /* The prim starts here (not wrapped) */ +#define PRIM_END 0x200 /* The prim ends in this VB (does not wrap) */ +#define PRIM_PARITY 0x400 /* The prim wrapped on an odd number of verts */ +#define PRIM_LAST 0x800 /* No more prims in the VB */ -/* KW: Flags that describe the current vertex state, and the contents - * of a vertex in a vertex-cassette. +/* Flags that describe the inputs and outputs of pipeline stages, and + * the contents of a vertex-cassette. * - * For really major expansion, consider a 'VERT_ADDITIONAL_FLAGS' flag, - * which means there is data in another flags array (eg, extra_flags[]). + * 5 spare flags, rearrangement of eval flags can secure at least 3 + * more. + */ +#define VERT_OBJ _NEW_ARRAY_VERTEX +#define VERT_RGBA _NEW_ARRAY_COLOR +#define VERT_NORM _NEW_ARRAY_NORMAL +#define VERT_INDEX _NEW_ARRAY_INDEX +#define VERT_EDGE _NEW_ARRAY_EDGEFLAG +#define VERT_SPEC_RGB _NEW_ARRAY_SECONDARYCOLOR +#define VERT_FOG_COORD _NEW_ARRAY_FOGCOORD +#define VERT_TEX0 _NEW_ARRAY_TEXCOORD_0 +#define VERT_TEX1 _NEW_ARRAY_TEXCOORD_1 +#define VERT_TEX2 _NEW_ARRAY_TEXCOORD_2 +#define VERT_TEX3 _NEW_ARRAY_TEXCOORD_3 +#define VERT_TEX4 _NEW_ARRAY_TEXCOORD_4 +#define VERT_TEX5 _NEW_ARRAY_TEXCOORD_5 +#define VERT_TEX6 _NEW_ARRAY_TEXCOORD_6 +#define VERT_TEX7 _NEW_ARRAY_TEXCOORD_7 +#define VERT_EVAL_C1 0x8000 /* imm only */ +#define VERT_EVAL_C2 0x10000 /* imm only */ +#define VERT_EVAL_P1 0x20000 /* imm only */ +#define VERT_EVAL_P2 0x40000 /* imm only */ +#define VERT_OBJ_3 0x80000 /* imm only */ +#define VERT_OBJ_4 0x100000 /* imm only */ +#define VERT_MATERIAL 0x200000 /* imm only, but tested in vb code */ +#define VERT_ELT 0x400000 /* imm only */ +#define VERT_BEGIN 0x800000 /* imm only, but tested in vb code */ +#define VERT_END 0x1000000 /* imm only, but tested in vb code */ +#define VERT_END_VB 0x2000000 /* imm only, but tested in vb code */ +#define VERT_POINT_SIZE 0x4000000 /* vb only, could reuse a bit */ +#define VERT_EYE VERT_BEGIN /* vb only, reuse imm bit */ +#define VERT_CLIP VERT_END /* vb only, reuse imm bit*/ + + +/* Flags for IM->TexCoordSize. Enough flags for 16 units. */ +#define TEX_0_SIZE_3 0x1 +#define TEX_0_SIZE_4 0x1000 +#define TEX_SIZE_3(unit) (TEX_0_SIZE_3<<unit) +#define TEX_SIZE_4(unit) (TEX_0_SIZE_4<<unit) -#define VERT_OBJ_2 0x1 /* glVertex2 */ -#define VERT_OBJ_3 0x2 /* glVertex3 */ -#define VERT_OBJ_4 0x4 /* glVertex4 */ -#define VERT_BEGIN 0x8 /* glBegin */ -#define VERT_END 0x10 /* glEnd */ -#define VERT_ELT 0x20 /* glArrayElement */ -#define VERT_RGBA 0x40 /* glColor */ -#define VERT_NORM 0x80 /* glNormal */ -#define VERT_INDEX 0x100 /* glIndex */ -#define VERT_EDGE 0x200 /* glEdgeFlag */ -#define VERT_MATERIAL 0x400 /* glMaterial */ -#define VERT_END_VB 0x800 /* end vb marker */ -#define VERT_TEX0 0x1000 -#define VERT_TEX1 0x2000 -#define VERT_TEX2 0x3000 -#define VERT_TEX3 0x4000 -#define VERT_TEX4 0x10000 -#define VERT_TEX5 0x20000 -#define VERT_TEX6 0x30000 -#define VERT_TEX7 0x40000 -#define VERT_TEX8 0x100000 -#define VERT_TEX9 0x200000 -#define VERT_TEX10 0x300000 -#define VERT_TEX11 0x400000 -#define VERT_EVAL_C1 0x1000000 /* could reuse OBJ bits for this? */ -#define VERT_EVAL_C2 0x2000000 /* - or just use 3 bits */ -#define VERT_EVAL_P1 0x4000000 /* */ -#define VERT_EVAL_P2 0x8000000 /* */ -#define VERT_SPEC_RGB 0x10000000 -#define VERT_FOG_COORD 0x20000000 -#define VERT_POINT_SIZE 0x40000000 - -#define VERT_EYE VERT_BEGIN /* reuse */ -#define VERT_WIN VERT_END /* reuse */ -#define VERT_SETUP_FULL VERT_EVAL_P1 /* Rastersetup has been done */ -#define VERT_PRECALC_DATA VERT_END_VB /* reuse */ /* Shorthands. */ - #define VERT_EVAL_ANY (VERT_EVAL_C1|VERT_EVAL_P1| \ VERT_EVAL_C2|VERT_EVAL_P2) -#define VERT_OBJ_23 (VERT_OBJ_3|VERT_OBJ_2) +#define VERT_OBJ_23 (VERT_OBJ_3|VERT_OBJ) #define VERT_OBJ_234 (VERT_OBJ_4|VERT_OBJ_23) -#define VERT_OBJ_ANY VERT_OBJ_2 #define VERT_TEX0_SHIFT 11 + #define VERT_TEX(i) (VERT_TEX0 << i) + #define VERT_TEX_ANY (VERT_TEX0 | \ VERT_TEX1 | \ VERT_TEX2 | \ @@ -135,461 +129,287 @@ VERT_TEX4 | \ VERT_TEX5 | \ VERT_TEX6 | \ - VERT_TEX7 | \ - VERT_TEX8 | \ - VERT_TEX9 | \ - VERT_TEX10 | \ - VERT_TEX11) + VERT_TEX7) + +#define VERT_FIXUP (VERT_TEX_ANY | \ + VERT_RGBA | \ + VERT_SPEC_RGB | \ + VERT_FOG_COORD | \ + VERT_INDEX | \ + VERT_EDGE | \ + VERT_NORM) -#define VERT_FIXUP (VERT_TEX_ANY | \ +#define VERT_CURRENT_DATA (VERT_FIXUP | \ + VERT_MATERIAL) + +#define VERT_DATA (VERT_TEX_ANY | \ VERT_RGBA | \ VERT_SPEC_RGB | \ VERT_FOG_COORD | \ VERT_INDEX | \ VERT_EDGE | \ - VERT_NORM) - -#define VERT_DATA (VERT_TEX_ANY | \ - VERT_RGBA | \ - VERT_SPEC_RGB | \ - VERT_FOG_COORD | \ - VERT_INDEX | \ - VERT_EDGE | \ - VERT_NORM | \ - VERT_OBJ_ANY | \ - VERT_MATERIAL | \ - VERT_ELT | \ - VERT_EVAL_ANY | \ - VERT_FOG_COORD) - - - - -struct gl_pipeline; -struct tnl_context; - -/** - ** Vertex buffer/array structures - **/ - -struct vertex_data -{ - GLfloat (*Obj)[4]; - GLfloat (*Normal)[3]; - GLchan (*Color)[4]; - GLuint *Index; - GLubyte *EdgeFlag; - GLfloat (*TexCoord[MAX_TEXTURE_UNITS])[4]; - GLuint *Elt; - GLfloat *FogCoord; - GLubyte (*SecondaryColor)[4]; -}; - -struct vertex_arrays -{ - GLvector4f Obj; - GLvector3f Normal; - GLvector4ub Color; - GLvector1ui Index; - GLvector1ub EdgeFlag; - GLvector4f TexCoord[MAX_TEXTURE_UNITS]; - GLvector1ui Elt; - GLvector4ub SecondaryColor; - GLvector1f FogCoord; -}; + VERT_NORM | \ + VERT_OBJ | \ + VERT_MATERIAL | \ + VERT_ELT | \ + VERT_EVAL_ANY) -struct vertex_array_pointers -{ - GLvector4f *Obj; - GLvector3f *Normal; - GLvector4ub *Color; - GLvector1ui *Index; - GLvector1ub *EdgeFlag; - GLvector4f *TexCoord[MAX_TEXTURE_UNITS]; - GLvector1ui *Elt; - GLvector4ub *SecondaryColor; - GLvector1f *FogCoord; -}; - -/* Values for VB->Type */ -enum { - VB_IMMEDIATE, - VB_CVA_PRECALC -}; - - -/* Values for immediate->BeginState */ -#define VERT_BEGIN_0 0x1 /* glBegin (if initially inside beg/end) */ -#define VERT_BEGIN_1 0x2 /* glBegin (if initially outside beg/end) */ -#define VERT_ERROR_0 0x4 /* invalid_operation in initial state 0 */ -#define VERT_ERROR_1 0x8 /* invalid_operation in initial state 1 */ /* KW: Represents everything that can take place between a begin and - * end, and can represent multiple begin/end pairs. This plus *any* - * state variable (GLcontext) should be all you need to replay the - * represented begin/end pairs as if they took place in that state. - * - * Thus this is sufficient for both immediate and compiled modes, but - * we could/should throw some elements away for compiled mode if we - * know they were empty. + * end, and can represent multiple begin/end pairs. Can be used to + * losslessly encode this information in display lists. */ struct immediate { - struct immediate *next; /* for cache of free IM's */ + struct __GLcontextRec *backref; GLuint id, ref_count; /* This must be saved when immediates are shared in display lists. */ - GLuint Start, Count; + GLuint CopyStart, Start, Count; GLuint LastData; /* count or count+1 */ GLuint AndFlag, OrFlag; - GLuint Tex3Flag, Tex4Flag; /* keep track of texcoord sizes */ + GLuint TexSize; /* keep track of texcoord sizes */ GLuint BeginState, SavedBeginState; GLuint LastPrimitive; - GLuint ArrayAndFlags; /* precalc'ed for glArrayElt */ - GLuint ArrayIncr; + GLuint ArrayEltFlags; /* precalc'ed for glArrayElt */ + GLuint ArrayEltIncr; GLuint ArrayEltFlush; GLuint FlushElt; - GLuint Primitive[VB_SIZE]; /* GLubyte would do... */ - GLuint NextPrimitive[VB_SIZE]; + GLuint MaxTextureUnits; /* precalc'ed for glMultiTexCoordARB */ - /* allocate storage for these on demand: + /* Temporary values created when vertices are copied into the + * first 3 slots of the struct: */ - struct gl_material (*Material)[2]; - GLuint *MaterialMask; + GLuint CopyOrFlag; + GLuint CopyAndFlag; + GLuint CopyTexSize; + - GLfloat (*TexCoordPtr[MAX_TEXTURE_UNITS])[4]; + /* allocate storage for these on demand: + */ + struct gl_material (*Material)[2]; + GLuint *MaterialMask; + GLfloat *NormalLengths; + GLfloat (*TexCoord[MAX_TEXTURE_UNITS])[4]; - struct vertex_arrays v; + GLuint Primitive[IMM_SIZE]; /* BEGIN/END */ + GLuint PrimitiveLength[IMM_SIZE]; /* BEGIN/END */ + GLuint Flag[IMM_SIZE]; /* VERT_* flags */ + GLchan Color[IMM_SIZE][4]; + GLfloat Obj[IMM_SIZE][4]; + GLfloat Normal[IMM_SIZE][3]; + GLfloat TexCoord0[IMM_SIZE][4]; /* just VERT_TEX0 */ + GLuint Elt[IMM_SIZE]; + GLubyte EdgeFlag[IMM_SIZE]; + GLuint Index[IMM_SIZE]; + GLubyte SecondaryColor[IMM_SIZE][4]; + GLfloat FogCoord[IMM_SIZE]; +}; - struct __GLcontextRec *backref; - /* Normal lengths, zero if not available. - */ - GLfloat *NormalLengths; - GLuint LastCalcedLength; - - GLuint Flag[VB_SIZE]; /* bitwise-OR of VERT_ flags */ - GLchan Color[VB_SIZE][4]; - GLfloat Obj[VB_SIZE][4]; - GLfloat Normal[VB_SIZE][3]; - GLfloat TexCoord[MAX_TEXTURE_UNITS][VB_SIZE][4]; - GLuint Elt[VB_SIZE]; - GLubyte EdgeFlag[VB_SIZE]; - GLuint Index[VB_SIZE]; - GLubyte SecondaryColor[VB_SIZE][4]; - GLfloat FogCoord[VB_SIZE]; +struct vertex_arrays +{ + GLvector4f Obj; + GLvector3f Normal; + GLvector4ub Color; + GLvector1ui Index; + GLvector1ub EdgeFlag; + GLvector4f TexCoord[MAX_TEXTURE_UNITS]; + GLvector1ui Elt; + GLvector4ub SecondaryColor; + GLvector1f FogCoord; }; -/* Not so big on storage these days, although still has pointers to - * arrays used for temporary results. +typedef struct gl_material GLmaterial; + +/* Contains the current state of a running pipeline. */ typedef struct vertex_buffer { - /* Backpointers. + /* Constant over life of the vertex_buffer. */ - struct __GLcontextRec *ctx; - struct tnl_context *tnlctx; + GLuint Size; - /* Driver_data is allocated in Driver.RegisterVB(), if required. + /* Constant over the pipeline. */ - void *driver_data; + GLuint Count; /* for everything except Elts */ + GLuint FirstClipped; /* temp verts for clipping */ + GLuint FirstPrimitive; /* usually zero */ - /* List of operations to process vertices in current state. + /* Pointers to current data. */ - struct gl_pipeline *pipeline; - - /* Temporary storage used by immediate mode functions and various - * operations in the pipeline. + GLuint *Elts; /* VERT_ELT */ + GLvector4f *ObjPtr; /* VERT_OBJ */ + GLvector4f *EyePtr; /* VERT_EYE */ + GLvector4f *ClipPtr; /* VERT_CLIP */ + GLvector4f *ProjectedClipPtr; /* VERT_CLIP (2) */ + GLubyte ClipOrMask; /* VERT_CLIP (3) */ + GLubyte *ClipMask; /* VERT_CLIP (4) */ + GLvector3f *NormalPtr; /* VERT_NORM */ + GLfloat *NormalLengthPtr; /* VERT_NORM (optional) */ + GLvector1ub *EdgeFlagPtr; /* VERT_EDGE */ + GLvector4f *TexCoordPtr[MAX_TEXTURE_UNITS]; /* VERT_TEX_0..n */ + GLvector1ui *IndexPtr[2]; /* VERT_INDEX */ + GLvector4ub *ColorPtr[2]; /* VERT_RGBA */ + GLvector4ub *SecondaryColorPtr[2]; /* VERT_SPEC_RGB */ + GLvector1f *FogCoordPtr; /* VERT_FOG_COORD */ + GLvector1f *PointSizePtr; /* VERT_POINT_SIZE */ + GLmaterial (*Material)[2]; /* VERT_MATERIAL, optional */ + GLuint *MaterialMask; /* VERT_MATERIAL, optional */ + GLuint *Flag; /* VERT_* flags, optional */ + GLuint *Primitive; /* GL_(mode)|PRIM_* flags */ + GLuint *PrimitiveLength; /* integers */ + + + GLuint importable_data; + void (*import_data)( GLcontext *ctx, GLuint flags, GLuint vecflags ); + /* Callback to the provider of the untransformed input for the + * render stage (or other stages) to call if they need to write into + * write-protected arrays, or fixup the stride on input arrays. + * + * This is currently only necessary for client arrays that make it + * as far down the pipeline as the render stage. */ - struct immediate *IM; - struct vertex_array_pointers store; - /* Where to find outstanding untransformed vertices. - */ - struct immediate *prev_buffer; - - GLuint Type; /* Either VB_IMMEDIATE or VB_CVA_PRECALC */ - - GLuint Size, Start, Count; - GLuint Free, FirstFree; - GLuint CopyStart; - GLuint Parity, Ovf; - GLuint PurgeFlags; - GLuint IndirectCount; /* defaults to count */ - GLuint OrFlag, SavedOrFlag; - GLuint Tex3Flag, Tex4Flag; - GLuint SavedTex3Flag, SavedTex4Flag; - GLuint EarlyCull; - GLuint Culled, CullDone; - - /* Pointers to input data - default to buffers in 'im' above. - */ - GLvector4f *ObjPtr; - GLvector3f *NormalPtr; - GLvector4ub *ColorPtr; - GLvector1ui *IndexPtr; - GLvector1ub *EdgeFlagPtr; - GLvector4f *TexCoordPtr[MAX_TEXTURE_UNITS]; - GLvector1ui *EltPtr; - GLvector4ub *SecondaryColorPtr; - GLvector1f *FogCoordPtr; - GLuint *Flag, FlagMax; - struct gl_material (*Material)[2]; - GLuint *MaterialMask; - - GLuint *NextPrimitive; - GLuint *Primitive; - GLuint LastPrimitive; - - GLfloat (*BoundsPtr)[3]; /* Bounds for cull check */ - GLfloat *NormalLengthPtr; /* Array of precomputed inv. normal lengths */ - - /* Holds malloced storage for pipeline data not supplied by - * the immediate struct. - */ - GLvector4f Eye; - GLvector4f Clip; - GLvector4f Win; - GLvector1f PointSize; - GLvector4ub BColor; /* not used in cva vb's */ - GLvector1ui BIndex; /* not used in cva vb's */ - GLvector4ub BSecondary; /* not used in cva vb's */ - - /* Temporary storage - may point into IM, or be dynamically - * allocated (for cva). + GLuint LastClipped; + void *interpfunc; + /* Two pieces of private data from _tnl_render_stage that have no + * business being in this struct. */ - GLubyte *ClipMask; - GLubyte *UserClipMask; - /* Internal values. Where these point depends on whether - * there were any identity matrices defined as transformations - * in the pipeline. - */ - GLvector4f *EyePtr; - GLvector4f *ClipPtr; - GLvector4f *Unprojected; - GLvector4f *Projected; - GLvector4f *CurrentTexCoord; - GLuint *Indirect; /* For eval rescue and cva render */ - - /* Currently active colors - */ - GLvector4ub *Color[2]; - GLvector1ui *Index[2]; - GLvector4ub *SecondaryColor[2]; +} TNLvertexbuffer; - /* Storage for colors which have been lit but not yet fogged. - * Required for CVA, just point into store for normal VB's. - */ - GLvector4ub *LitColor[2]; - GLvector1ui *LitIndex[2]; - GLvector4ub *LitSecondary[2]; - /* Temporary values used in texgen. - */ - GLfloat (*tmp_f)[3]; - GLfloat *tmp_m; - /* Temporary values used in eval. - */ - GLuint *EvaluatedFlags; +/* Describes an individual operation on the pipeline. + */ +struct gl_pipeline_stage { + const char *name; + GLuint check_state; /* All state referenced in check() -- + * When is the pipeline_stage struct + * itself invalidated? Must be + * constant. + */ - /* Not used for cva: + /* Usually constant or set by the 'check' callback: */ - GLubyte *NormCullStart; - GLubyte *CullMask; /* Results of vertex culling */ - GLubyte *NormCullMask; /* Compressed onto shared normals */ - - GLubyte ClipOrMask; /* bitwise-OR of all ClipMask[] values */ - GLubyte ClipAndMask; /* bitwise-AND of all ClipMask[] values */ - GLubyte CullFlag[2]; - GLubyte CullMode; /* see flags below */ - - GLuint CopyCount; /* max 3 vertices to copy after transform */ - GLuint Copy[3]; - GLfloat CopyProj[3][4]; /* temporary store for projected clip coords */ - - /* Hooks for module private data + GLuint run_state; /* All state referenced in run() -- + * When is the cached output of the + * stage invalidated? + */ + + GLboolean active; /* True if runnable in current state */ + GLuint inputs; /* VERT_* inputs to the stage */ + GLuint outputs; /* VERT_* outputs of the stage */ + + /* Set in _tnl_run_pipeline(): */ - void *swsetup_vb; - -} TNLvertexbuffer; - - -typedef void (*shade_func)( struct vertex_buffer *VB ); - -typedef void (*clip_interp_func)( struct vertex_buffer *VB, GLuint dst, - GLfloat t, GLuint in, GLuint out ); - -typedef GLuint (*clip_line_func)( struct vertex_buffer *VB, - GLuint *i, GLuint *j, - GLubyte mask); - -typedef GLuint (*clip_poly_func)( struct vertex_buffer *VB, - GLuint n, GLuint vlist[], - GLubyte mask ); - + GLuint changed_inputs; /* Generated value -- inputs to the + * stage that have changed since last + * call to 'run'. + */ -#define MAX_PIPELINE_STAGES 30 - -#define PIPE_IMMEDIATE 0x1 -#define PIPE_PRECALC 0x2 - -#define PIPE_OP_VERT_XFORM 0x1 -#define PIPE_OP_NORM_XFORM 0x2 -#define PIPE_OP_LIGHT 0x4 -#define PIPE_OP_FOG 0x8 -#define PIPE_OP_TEX 0x10 -#define PIPE_OP_RAST_SETUP_0 0x100 -#define PIPE_OP_RAST_SETUP_1 0x200 -#define PIPE_OP_RENDER 0x400 -#define PIPE_OP_CVA_PREPARE 0x800 -#define PIPE_OP_POINT_SIZE 0x1000 + /* Private data for the pipeline stage: + */ + void *private; + /* Free private data. May not be null. + */ + void (*destroy)( struct gl_pipeline_stage * ); -struct gl_pipeline_stage { - const char *name; - GLuint ops; /* PIPE_OP flags */ - GLuint type; /* VERT flags */ - GLuint special; /* VERT flags - force update_inputs() */ - GLuint state_change; /* state flags - trigger update_inputs() */ - GLuint cva_state_change; /* state flags - recalc cva buffer */ - GLuint elt_forbidden_inputs; /* VERT flags - force a pipeline recalc */ - GLuint pre_forbidden_inputs; /* VERT flags - force a pipeline recalc */ - GLuint active; /* VERT flags */ - GLuint inputs; /* VERT flags */ - GLuint outputs; /* VERT flags */ + /* Called from _tnl_validate_pipeline(). Must update all fields in + * the pipeline_stage struct for the current state. + */ void (*check)( GLcontext *ctx, struct gl_pipeline_stage * ); - void (*run)( struct vertex_buffer *VB ); + + /* Called from _tnl_run_pipeline(). The stage.changed_inputs value + * encodes all inputs to thee struct which have changed. If + * non-zero, recompute all affected outputs of the stage, otherwise + * execute any 'sideeffects' of the stage. + * + * Return value: GL_TRUE - keep going + * GL_FALSE - finished pipeline + */ + GLboolean (*run)( GLcontext *ctx, struct gl_pipeline_stage * ); }; struct gl_pipeline { - GLuint state_change; /* state changes which require recalc */ - GLuint cva_state_change; /* ... which require re-run */ - GLuint forbidden_inputs; /* inputs which require recalc */ - GLuint ops; /* what gets done in this pipe */ - GLuint changed_ops; - GLuint inputs; - GLuint outputs; - GLuint new_inputs; - GLuint new_outputs; - GLuint fallback; - GLuint type; - GLuint pipeline_valid:1; - GLuint data_valid:1; - GLuint copy_transformed_data:1; - GLuint replay_copied_vertices:1; - GLuint new_state; /* state changes since last recalc */ - struct gl_pipeline_stage *stages[MAX_PIPELINE_STAGES]; + GLuint build_state_trigger; /* state changes which require build */ + GLuint build_state_changes; /* state changes since last build */ + GLuint run_state_changes; /* state changes since last run */ + GLuint run_input_changes; /* VERT_* changes since last run */ + GLuint inputs; /* VERT_* inputs to pipeline */ + struct gl_pipeline_stage stages[MAX_PIPELINE_STAGES]; + GLuint nr_stages; }; +struct tnl_eval_store { + GLuint EvalMap1Flags; + GLuint EvalMap2Flags; + GLuint EvalNewState; -/* All fields are derived. - */ -struct gl_cva { - struct gl_pipeline pre; - struct gl_pipeline elt; - - struct gl_client_array Elt; - trans_1ui_func EltFunc; - - struct vertex_buffer *VB; - struct vertex_arrays v; - struct vertex_data store; - - GLuint elt_count; - GLenum elt_mode; - GLuint elt_size; - - GLuint forbidden_inputs; - GLuint orflag; - GLuint merge; - - GLuint locked; - GLuint lock_changed; - GLuint last_orflag; - GLuint last_array_flags; - GLuint last_array_new_state; -}; - -/* These are used to make the ctx->Current values look like - * arrays (with zero StrideB). - */ -struct gl_fallback_arrays { - struct gl_client_array Normal; - struct gl_client_array Color; - struct gl_client_array SecondaryColor; - struct gl_client_array FogCoord; - struct gl_client_array Index; - struct gl_client_array TexCoord[MAX_TEXTURE_UNITS]; - struct gl_client_array EdgeFlag; + GLfloat Obj[IMM_SIZE][4]; + GLfloat TexCoord[IMM_SIZE][4]; + GLfloat Normal[IMM_SIZE][3]; + GLchan Color[IMM_SIZE][4]; + GLuint Index[IMM_SIZE]; + GLuint Flag[IMM_SIZE]; + GLuint Elts[IMM_SIZE]; }; +typedef struct { - -typedef void (*texgen_func)( struct vertex_buffer *VB, - GLuint textureSet); - - - -typedef struct tnl_context { - - GLuint _ArrayFlag[VB_SIZE]; /* crock */ - GLuint _ArrayFlags; - GLuint _ArraySummary; /* Like flags, but no size information */ - GLuint _ArrayNewState; /* Tracks which arrays have been changed. */ - GLuint _ArrayTex3Flag; - GLuint _ArrayTex4Flag; - - - /* Pipeline stages - shared between the two pipelines, - * which live in CVA. - */ - struct gl_pipeline_stage PipelineStage[MAX_PIPELINE_STAGES]; - GLuint NrPipelineStages; - - /* Per-texunit derived state. + /* Track whether the module is active. */ - GLuint _TexgenSize[MAX_TEXTURE_UNITS]; - GLuint _TexgenHoles[MAX_TEXTURE_UNITS]; - texgen_func *_TexgenFunc[MAX_TEXTURE_UNITS]; - + GLboolean bound_exec; /* Display list extensions */ GLuint opcode_vertex_cassette; - /* Cva + /* Pipeline */ - struct gl_cva CVA; - GLboolean CompileCVAFlag; + struct gl_pipeline pipeline; + struct vertex_buffer vb; - clip_poly_func *_poly_clip_tab; - clip_line_func *_line_clip_tab; - clip_interp_func _ClipInterpFunc; /* Clip interpolation function */ - normal_func *_NormalTransform; - shade_func *_shade_func_tab; /* Current shading function table */ - - GLenum _CurrentPrimitive; /* Prim or GL_POLYGON+1 */ - GLuint _CurrentTex3Flag; - GLuint _CurrentTex4Flag; + /* GLvectors for binding to vb: + */ + struct vertex_arrays imm_inputs; + struct vertex_arrays array_inputs; + GLuint *tmp_primitive; + GLuint *tmp_primitive_length; - GLboolean _ReplayHardBeginEnd; /* Display list execution of rect, etc */ + /* Set when executing an internally generated immediate. + */ + GLboolean ReplayHardBeginEnd; + GLenum CurrentPrimitive; - GLuint _RenderFlags; /* Active inputs to render stage */ + /* Note which vertices need copying over succesive immediates. + * Will add save versions to precompute vertex copying where + * possible. + */ + struct immediate *ExecCopySource; + GLuint ExecCopyCount; + GLuint ExecCopyElts[IMM_MAX_COPIED_VERTS]; + GLuint ExecCopyTexSize; + GLuint ExecParity; - /* Cache of unused immediate structs */ - struct immediate *freed_im_queue; - GLuint nr_im_queued; + GLuint DlistPrimitive; + GLuint DlistPrimitiveLength; + GLuint DlistLastPrimitive; - struct gl_fallback_arrays Fallback; + /* Derived state and storage for _tnl_eval_vb: + */ + struct tnl_eval_store eval; + /* Functions to be plugged into dispatch when tnl is active. + */ GLvertexformat vtxfmt; } TNLcontext; @@ -598,20 +418,16 @@ typedef struct tnl_context { #define TNL_CONTEXT(ctx) ((TNLcontext *)(ctx->swtnl_context)) #define TNL_CURRENT_IM(ctx) ((struct immediate *)(ctx->swtnl_im)) -#define TNL_VB(ctx) ((struct vertex_buffer *)(ctx->swtnl_vb)) -extern GLboolean _tnl_flush_vertices( GLcontext *ctx, GLuint flush_flags ); +#define TYPE_IDX(t) ((t) & 0xf) +#define MAX_TYPES TYPE_IDX(GL_DOUBLE)+1 /* 0xa + 1 */ -extern void -_tnl_MakeCurrent( GLcontext *ctx, - GLframebuffer *drawBuffer, - GLframebuffer *readBuffer ); +extern void _tnl_MakeCurrent( GLcontext *ctx, + GLframebuffer *drawBuffer, + GLframebuffer *readBuffer ); -extern void -_tnl_LightingSpaceChange( GLcontext *ctx ); - /* * Macros for fetching current input buffer. */ @@ -628,4 +444,5 @@ do { \ } while (0) #endif + #endif diff --git a/src/mesa/tnl/t_eval_api.c b/src/mesa/tnl/t_eval_api.c new file mode 100644 index 00000000000..efe78763337 --- /dev/null +++ b/src/mesa/tnl/t_eval_api.c @@ -0,0 +1,209 @@ +/* $Id: t_eval_api.c,v 1.1 2000/12/26 05:09:32 keithw Exp $ */ + +/* + * Mesa 3-D graphics library + * Version: 3.5 + * + * Copyright (C) 1999-2000 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. + */ + + +#include "glheader.h" +#include "colormac.h" +#include "context.h" +#include "macros.h" +#include "mem.h" +#include "mmath.h" +#include "mtypes.h" +#include "math/m_eval.h" + +#include "t_eval_api.h" +#include "t_imm_api.h" +#include "t_imm_alloc.h" +#include "t_imm_exec.h" + + + + + +/* KW: If are compiling, we don't know whether eval will produce a + * vertex when it is run in the future. If this is pure immediate + * mode, eval is a noop if neither vertex map is enabled. + * + * Thus we need to have a check in the display list code or + * elsewhere for eval(1,2) vertices in the case where + * map(1,2)_vertex is disabled, and to purge those vertices from + * the vb. + */ +void +_tnl_exec_EvalMesh1( GLenum mode, GLint i1, GLint i2 ) +{ + GET_CURRENT_CONTEXT(ctx); + GLint i; + GLfloat u, du; + GLenum prim; + ASSERT_OUTSIDE_BEGIN_END(ctx); + + switch (mode) { + case GL_POINT: + prim = GL_POINTS; + break; + case GL_LINE: + prim = GL_LINE_STRIP; + break; + default: + gl_error( ctx, GL_INVALID_ENUM, "glEvalMesh1(mode)" ); + return; + } + + /* No effect if vertex maps disabled. + */ + if (!ctx->Eval.Map1Vertex4 && !ctx->Eval.Map1Vertex3) + return; + + du = ctx->Eval.MapGrid1du; + u = ctx->Eval.MapGrid1u1 + i1 * du; + + /* Need to turn off compilation -- this is already saved, and the + * coordinates generated and the test above depend on state that + * may change before the list is executed. + * + * TODO: Anaylse display lists to determine if this state is + * constant. + */ + { + GLboolean compiling = ctx->CompileFlag; + struct immediate *im = TNL_CURRENT_IM(ctx); + + if (compiling) { + FLUSH_VERTICES( ctx, 0 ); + SET_IMMEDIATE( ctx, _tnl_alloc_immediate( ctx ) ); + ctx->CompileFlag = GL_FALSE; + } + + _tnl_begin( ctx, prim ); + for (i=i1;i<=i2;i++,u+=du) { + _tnl_eval_coord1f( ctx, u ); + } + _tnl_end(ctx); + + if (compiling) { + FLUSH_VERTICES( ctx, 0 ); + ASSERT( TNL_CURRENT_IM(ctx)->ref_count == 0 ); + _tnl_free_immediate( TNL_CURRENT_IM(ctx) ); + SET_IMMEDIATE( ctx, im ); + ctx->CompileFlag = GL_TRUE; + } + } +} + + + +void +_tnl_exec_EvalMesh2( GLenum mode, GLint i1, GLint i2, GLint j1, GLint j2 ) +{ + GET_CURRENT_CONTEXT(ctx); + GLint i, j; + GLfloat u, du, v, dv, v1, u1; + ASSERT_OUTSIDE_BEGIN_END(ctx); + + /* No effect if vertex maps disabled. + */ + if (!ctx->Eval.Map2Vertex4 && !ctx->Eval.Map2Vertex3) + return; + + + du = ctx->Eval.MapGrid2du; + dv = ctx->Eval.MapGrid2dv; + v1 = ctx->Eval.MapGrid2v1 + j1 * dv; + u1 = ctx->Eval.MapGrid2u1 + i1 * du; + + /* Need to turn off compilation -- this is already saved, and the + * coordinates generated and the test above depend on state that + * may change before the list is executed. + */ + { + GLboolean compiling = ctx->CompileFlag; + struct immediate *im = TNL_CURRENT_IM(ctx); + + if (compiling) { + FLUSH_VERTICES( ctx, 0 ); + SET_IMMEDIATE( ctx, _tnl_alloc_immediate( ctx ) ); + ctx->CompileFlag = GL_FALSE; + } + + switch (mode) { + case GL_POINT: + _tnl_begin( ctx, GL_POINTS ); + for (v=v1,j=j1;j<=j2;j++,v+=dv) { + for (u=u1,i=i1;i<=i2;i++,u+=du) { + _tnl_eval_coord2f( ctx, u, v ); + } + } + _tnl_end(ctx); + break; + case GL_LINE: + for (v=v1,j=j1;j<=j2;j++,v+=dv) { + _tnl_begin( ctx, GL_LINE_STRIP ); + for (u=u1,i=i1;i<=i2;i++,u+=du) { + _tnl_eval_coord2f( ctx, u, v ); + } + _tnl_end(ctx); + } + for (u=u1,i=i1;i<=i2;i++,u+=du) { + _tnl_begin( ctx, GL_LINE_STRIP ); + for (v=v1,j=j1;j<=j2;j++,v+=dv) { + _tnl_eval_coord2f( ctx, u, v ); + } + _tnl_end(ctx); + } + break; + case GL_FILL: + for (v=v1,j=j1;j<j2;j++,v+=dv) { + _tnl_begin( ctx, GL_TRIANGLE_STRIP ); + for (u=u1,i=i1;i<=i2;i++,u+=du) { + _tnl_eval_coord2f( ctx, u, v ); + _tnl_eval_coord2f( ctx, u, v+dv ); + } + _tnl_end(ctx); + } + break; + default: + gl_error( ctx, GL_INVALID_ENUM, "glEvalMesh2(mode)" ); + return; + } + + if (compiling) { + FLUSH_VERTICES( ctx, 0 ); + _tnl_free_immediate( TNL_CURRENT_IM( ctx ) ); + SET_IMMEDIATE( ctx, im ); + ctx->CompileFlag = GL_TRUE; + } + } +} + + + +void _tnl_eval_init( GLcontext *ctx ) +{ + GLvertexformat *vfmt = &(TNL_CONTEXT(ctx)->vtxfmt); + vfmt->EvalMesh1 = _tnl_exec_EvalMesh1; + vfmt->EvalMesh2 = _tnl_exec_EvalMesh2; +} diff --git a/src/mesa/tnl/t_eval_api.h b/src/mesa/tnl/t_eval_api.h new file mode 100644 index 00000000000..fab6108c8da --- /dev/null +++ b/src/mesa/tnl/t_eval_api.h @@ -0,0 +1,44 @@ +/* $Id: t_eval_api.h,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. + */ + + +#ifndef _T_EVAL_H +#define _T_EVAL_H + + +#include "mtypes.h" +#include "t_context.h" + +/* Use _mesa_save_EvalMesh{1,2} to save these to display lists. + */ +extern void _tnl_exec_EvalMesh1( GLenum mode, GLint i1, GLint i2 ); + +extern void _tnl_exec_EvalMesh2( GLenum mode, GLint i1, GLint i2, + GLint j1, GLint j2 ); + +void _tnl_eval_init( GLcontext *ctx ); + +#endif diff --git a/src/mesa/tnl/t_imm_alloc.c b/src/mesa/tnl/t_imm_alloc.c new file mode 100644 index 00000000000..44e3a598ecb --- /dev/null +++ b/src/mesa/tnl/t_imm_alloc.c @@ -0,0 +1,104 @@ +/* $Id: t_imm_alloc.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. + * + * Authors: + * Keith Whitwell <[email protected]> + */ + +#include "glheader.h" +#include "mem.h" +#include "mtypes.h" + +#include "t_imm_alloc.h" + + + +struct immediate *_tnl_alloc_immediate( GLcontext *ctx ) +{ + static int id = 0; + struct immediate *IM = ALIGN_MALLOC_STRUCT( immediate, 32 ); + GLuint j; + + if (!IM) + return 0; + + IM->id = id++; + IM->ref_count = 0; + IM->backref = ctx; + IM->NormalLengths = 0; + IM->FlushElt = 0; + IM->LastPrimitive = IMM_MAX_COPIED_VERTS; + IM->Count = IMM_MAX_COPIED_VERTS; + IM->Start = IMM_MAX_COPIED_VERTS; + IM->Material = 0; + IM->MaterialMask = 0; + IM->MaxTextureUnits = ctx->Const.MaxTextureUnits; + IM->TexSize = 0; + + IM->CopyTexSize = 0; + IM->CopyStart = IM->Start; + + + /* TexCoord0 is special. + */ + IM->TexCoord[0] = IM->TexCoord0; + + for (j = 1; j < ctx->Const.MaxTextureUnits; j++) + IM->TexCoord[j] = ALIGN_MALLOC( IMM_SIZE * sizeof(GLfloat) * 4, 32 ); + + /* KW: Removed initialization of normals as these are now treated + * identically to all other data types. + */ + + MEMSET(IM->Flag, 0, sizeof(IM->Flag)); + + return IM; +} + + +void _tnl_free_immediate( struct immediate *IM ) +{ + GLuint j; + + if (IM->NormalLengths) { + FREE( IM->NormalLengths ); + IM->NormalLengths = 0; + } + + if (IM->Material) { + FREE( IM->Material ); + FREE( IM->MaterialMask ); + IM->Material = 0; + IM->MaterialMask = 0; + + for (j = 1; j < IM->MaxTextureUnits; j++) + ALIGN_FREE( IM->TexCoord[j] ); + } + + ALIGN_FREE( IM ); +} + + + diff --git a/src/mesa/tnl/t_imm_alloc.h b/src/mesa/tnl/t_imm_alloc.h new file mode 100644 index 00000000000..5640f80ceaa --- /dev/null +++ b/src/mesa/tnl/t_imm_alloc.h @@ -0,0 +1,40 @@ +/* $Id: t_imm_alloc.h,v 1.1 2000/12/26 05:09:32 keithw Exp $ */ + +/* + * Mesa 3-D graphics library + * Version: 3.5 + * + * Copyright (C) 1999-2000 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. + */ + + +#ifndef _T_IMM_ALLOC_H +#define _T_IMM_ALLOC_H + +#include "mtypes.h" +#include "t_context.h" + + +extern struct immediate *_tnl_alloc_immediate( GLcontext *ctx ); + +extern void _tnl_free_immediate( struct immediate *im ); + + +#endif diff --git a/src/mesa/tnl/t_imm_api.c b/src/mesa/tnl/t_imm_api.c new file mode 100644 index 00000000000..6224bff3cba --- /dev/null +++ b/src/mesa/tnl/t_imm_api.c @@ -0,0 +1,1398 @@ + +/* + * Mesa 3-D graphics library + * Version: 3.3 + * + * Copyright (C) 1999-2000 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 <[email protected]> + */ + + + +#include "glheader.h" +#include "context.h" +#include "dlist.h" +#include "enums.h" +#include "light.h" +#include "mem.h" +#include "state.h" +#include "colormac.h" +#include "macros.h" + +#include "t_context.h" +#include "t_imm_api.h" +#include "t_imm_elt.h" +#include "t_imm_exec.h" +#include "t_imm_dlist.h" + + +/* A cassette is full or flushed on a statechange. + */ +void _tnl_flush_immediate( struct immediate *IM ) +{ + GLcontext *ctx = IM->backref; + + if (ctx->CompileFlag) + _tnl_compile_cassette( ctx, IM ); + else + _tnl_execute_cassette( ctx, IM ); +} + + +void _tnl_flush_vertices( GLcontext *ctx, GLuint flags ) +{ + struct immediate *IM = TNL_CURRENT_IM(ctx); + + if (IM->Flag[IM->Start]) + if ((flags & FLUSH_UPDATE_CURRENT) || IM->Count > IM->Start) + _tnl_flush_immediate( IM ); +} + + +void +_tnl_begin( GLcontext *ctx, GLenum p ) +{ + struct immediate *IM = TNL_CURRENT_IM(ctx); + GLuint inflags, state; + + if (MESA_VERBOSE&VERBOSE_API) + fprintf(stderr, "glBegin(IM %d) %s\n", IM->id, gl_lookup_enum_by_nr(p)); + + if (ctx->NewState) + gl_update_state(ctx); + + /* if only a very few slots left, might as well flush now + */ + if (IM->Count > IMM_MAXDATA-8) { + _tnl_flush_immediate( IM ); + IM = TNL_CURRENT_IM(ctx); + } + + /* Check for and flush buffered vertices from internal operations. + */ + if (IM->SavedBeginState) { + _tnl_flush_immediate( IM ); + IM = TNL_CURRENT_IM(ctx); + IM->BeginState = IM->SavedBeginState; + IM->SavedBeginState = 0; + } + + state = IM->BeginState; + inflags = state & (VERT_BEGIN_0|VERT_BEGIN_1); + state |= inflags << 2; /* set error conditions */ + + if (inflags != (VERT_BEGIN_0|VERT_BEGIN_1)) + { + GLuint count = IM->Count; + GLuint last = IM->LastPrimitive; + + ASSERT(IM->Primitive[IM->LastPrimitive] & PRIM_LAST); + + state |= (VERT_BEGIN_0|VERT_BEGIN_1); + IM->Flag[count] |= VERT_BEGIN; + IM->Primitive[IM->LastPrimitive] &= ~PRIM_LAST; + IM->Primitive[count] = p | PRIM_BEGIN | PRIM_LAST; + IM->PrimitiveLength[IM->LastPrimitive] = count - IM->LastPrimitive; + IM->LastPrimitive = count; + + /* Not quite right. Need to use the fallback '_aa_ArrayElement' + * when not known to be inside begin/end and arrays are unlocked. + */ + if (IM->FlushElt) { + _tnl_translate_array_elts( ctx, IM, last, count ); + IM->FlushElt = 0; + } + } + + ctx->Driver.NeedFlush |= FLUSH_STORED_VERTICES; + IM->BeginState = state; +} + + + +static void +_tnl_Begin( GLenum mode ) +{ + GET_CURRENT_CONTEXT(ctx); + + if (mode > GL_POLYGON) { + _mesa_compile_error( ctx, GL_INVALID_ENUM, "glBegin" ); + return; + } + + _tnl_begin(ctx, mode); + + /* If compiling update SavePrimitive now. + * + * In compile_and_exec mode, exec_primitive will be updated when + * the cassette is finished. + * + * If not compiling, update exec_primitive now. + */ + if (ctx->CompileFlag) { + if (ctx->Driver.CurrentSavePrimitive == PRIM_UNKNOWN) + ctx->Driver.CurrentSavePrimitive = PRIM_INSIDE_UNKNOWN_PRIM; + else if (ctx->Driver.CurrentSavePrimitive == PRIM_OUTSIDE_BEGIN_END) + ctx->Driver.CurrentSavePrimitive = mode; + } + else if (ctx->Driver.CurrentExecPrimitive == PRIM_OUTSIDE_BEGIN_END) + ctx->Driver.CurrentExecPrimitive = mode; +} + + +GLboolean +_tnl_hard_begin( GLcontext *ctx, GLenum p ) +{ + struct immediate *IM = TNL_CURRENT_IM(ctx); + GLuint count, last; + + if (ctx->NewState) + gl_update_state(ctx); + + /* If not compiling, treat as a normal begin(). + */ + if (!ctx->CompileFlag) { + _tnl_begin( ctx, p ); + return GL_TRUE; + } + + if (IM->Count > IMM_MAXDATA-8) { + _tnl_flush_immediate( IM ); + IM = TNL_CURRENT_IM(ctx); + } + + switch (IM->BeginState & (VERT_BEGIN_0|VERT_BEGIN_1)) { + case VERT_BEGIN_0|VERT_BEGIN_1: + /* In this case we know for sure that the list is going to be + * inside a begin/end object at this point when run. Rather + * than saving the redundant data, compile in an error and + * return. + */ + IM->BeginState |= (VERT_ERROR_1|VERT_ERROR_0); + return GL_FALSE; + + case VERT_BEGIN_0: + case VERT_BEGIN_1: + /* This is a normal (non-hard) immediate, in an unknown + * begin/end state. Assert it is empty and conviert it to a + * 'hard' one. + */ + ASSERT (IM->SavedBeginState == 0); + +/* ASSERT (ctx->Driver.CurrentSavePrimitive >= GL_POLYGON+1); */ + + /* Push current beginstate, to be restored later. Don't worry + * about raising errors. + */ + IM->SavedBeginState = IM->BeginState; + + /* FALLTHROUGH */ + case 0: + + IM->BeginState |= VERT_BEGIN_0|VERT_BEGIN_1; + + + count = IM->Count; + last = IM->LastPrimitive; + + ASSERT(IM->Primitive[IM->LastPrimitive] & PRIM_LAST); + + IM->Flag[count] |= VERT_BEGIN; + IM->Primitive[last] &= ~PRIM_LAST; + IM->Primitive[count] = p | PRIM_BEGIN | PRIM_LAST; + IM->PrimitiveLength[last] = count - last; + IM->LastPrimitive = count; + + ASSERT (!IM->FlushElt); + + /* This is necessary as this immediate will not be flushed in + * _tnl_end() -- we leave it active, hoping to pick up more + * vertices before the next state change. + */ + ctx->Driver.NeedFlush |= FLUSH_STORED_VERTICES; + return GL_TRUE; + + default: + ASSERT (0); + return GL_TRUE; + } +} + +/* Note the continuation of a partially completed primitive. For + * driver t&l fallbacks between begin/end primitives. Has basically + * the same effects as a primitive wrapping onto a second immediate + * struct. + * + * ==> Can actually call this from _tnl_wakeup_exec, taking mode from + * ctx->Driver.CurrentExecPrimitive. + */ +#if 0 +void _tnl_fallback_begin( GLcontext *ctx, GLenum mode ) +{ + struct immediate *IM = TNL_CURRENT_IM(ctx); + ASSERT( IM->Count == IM->Start ); + ASSERT( IM->Flag[IM->Start] == 0 ); + ASSERT( mode < GL_POLYGON+1 ); + _tnl_begin( ctx, mode ); + IM->Primitive[IM->Start] &= ~PRIM_BEGIN; +} +#endif + + +/* Both streams now outside begin/end. + * + * Leave SavedBeginState untouched -- attempt to gather several + * rects/arrays together in a single immediate struct. + */ +void +_tnl_end( GLcontext *ctx ) +{ + struct immediate *IM = TNL_CURRENT_IM(ctx); + GLuint state = IM->BeginState; + GLuint inflags = (~state) & (VERT_BEGIN_0|VERT_BEGIN_1); + + state |= inflags << 2; /* errors */ + + if (inflags != (VERT_BEGIN_0|VERT_BEGIN_1)) + { + GLuint count = IM->Count; + GLuint last = IM->LastPrimitive; + + ASSERT(IM->Primitive[IM->LastPrimitive] & PRIM_LAST); + + state &= ~(VERT_BEGIN_0|VERT_BEGIN_1); /* update state */ + IM->Flag[count] |= VERT_END; + IM->Primitive[last] |= PRIM_END; + IM->Primitive[last] &= ~PRIM_LAST; + IM->PrimitiveLength[last] = count - last; + IM->Primitive[count] = (GL_POLYGON+1) | PRIM_LAST; + IM->LastPrimitive = count; + + if (IM->FlushElt) { + _tnl_translate_array_elts( ctx, IM, last, count ); + IM->FlushElt = 0; + } + + ctx->Driver.NeedFlush |= FLUSH_STORED_VERTICES; + } + + IM->BeginState = state; + + /* You can set this flag to get the old 'flush_vb on glEnd()' + * behaviour. + */ + if ((MESA_DEBUG_FLAGS&DEBUG_ALWAYS_FLUSH)) + _tnl_flush_immediate( IM ); +} + +static void +_tnl_End(void) +{ + GET_CURRENT_CONTEXT(ctx); + _tnl_end( ctx ); + + /* Need to keep save primitive uptodate in COMPILE and + * COMPILE_AND_EXEC modes, need to keep exec primitive uptodate + * otherwise. + */ + if (ctx->CompileFlag) + ctx->Driver.CurrentSavePrimitive = PRIM_OUTSIDE_BEGIN_END; + else + ctx->Driver.CurrentExecPrimitive = PRIM_OUTSIDE_BEGIN_END; + + +} + + +#define COLOR( IM, r, g, b, a ) \ +{ \ + GLuint count = IM->Count; \ + IM->Flag[count] |= VERT_RGBA; \ + IM->Color[count][0] = r; \ + IM->Color[count][1] = g; \ + IM->Color[count][2] = b; \ + IM->Color[count][3] = a; \ +} + +#define COLORV( IM, v ) \ +{ \ + GLuint count = IM->Count; \ + IM->Flag[count] |= VERT_RGBA; \ + COPY_CHAN4(IM->Color[count], v); \ +} + + +static void +_tnl_Color3f( GLfloat red, GLfloat green, GLfloat blue ) +{ +#if CHAN_BITS == 8 + GLubyte col[4]; + GET_IMMEDIATE; + FLOAT_COLOR_TO_UBYTE_COLOR(col[0], red); + FLOAT_COLOR_TO_UBYTE_COLOR(col[1], green); + FLOAT_COLOR_TO_UBYTE_COLOR(col[2], blue); + col[3] = CHAN_MAX; + COLORV( IM, col ); +#else + GET_IMMEDIATE; + COLOR(IM, + UNCLAMPED_FLOAT_TO_CHAN(red), + UNCLAMPED_FLOAT_TO_CHAN(green), + UNCLAMPED_FLOAT_TO_CHAN(blue), + CHAN_MAX); +#endif +} + + +static void +_tnl_Color3ub( GLubyte red, GLubyte green, GLubyte blue ) +{ +#if CHAN_BITS == 8 + GET_IMMEDIATE; + COLOR( IM, red, green, blue, CHAN_MAX ); +#else + GET_IMMEDIATE; + COLOR(IM, + UBYTE_TO_CHAN(red), + UBYTE_TO_CHAN(green), + UBYTE_TO_CHAN(blue), + CHAN_MAX); +#endif +} + + + + +static void +_tnl_Color4f( GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha ) +{ +#if CHAN_BITS == 8 + GLubyte col[4]; + GET_IMMEDIATE; + FLOAT_COLOR_TO_UBYTE_COLOR(col[0], red); + FLOAT_COLOR_TO_UBYTE_COLOR(col[1], green); + FLOAT_COLOR_TO_UBYTE_COLOR(col[2], blue); + FLOAT_COLOR_TO_UBYTE_COLOR(col[3], alpha); + COLORV( IM, col ); +#else + GET_IMMEDIATE; + COLOR(IM, + UNCLAMPED_FLOAT_TO_CHAN(red), + UNCLAMPED_FLOAT_TO_CHAN(green), + UNCLAMPED_FLOAT_TO_CHAN(blue), + UNCLAMPED_FLOAT_TO_CHAN(alpha)); +#endif +} + +static void +_tnl_Color4ub( GLubyte red, GLubyte green, GLubyte blue, GLubyte alpha ) +{ +#if CHAN_BITS == 8 + GET_IMMEDIATE; + COLOR( IM, red, green, blue, alpha ); +#else + GET_IMMEDIATE; + COLOR(IM, + UBYTE_TO_CHAN(red), + UBYTE_TO_CHAN(green), + UBYTE_TO_CHAN(blue), + UBYTE_TO_CHAN(alpha)); +#endif +} + + +static void +_tnl_Color3fv( const GLfloat *v ) +{ +#if CHAN_BITS == 8 + GLubyte col[4]; + GET_IMMEDIATE; + FLOAT_COLOR_TO_UBYTE_COLOR(col[0], v[0]); + FLOAT_COLOR_TO_UBYTE_COLOR(col[1], v[1]); + FLOAT_COLOR_TO_UBYTE_COLOR(col[2], v[2]); + col[3] = CHAN_MAX; + COLORV( IM, col ); +#else + GET_IMMEDIATE; + COLOR(IM, + UNCLAMPED_FLOAT_TO_CHAN(v[0]), + UNCLAMPED_FLOAT_TO_CHAN(v[1]), + UNCLAMPED_FLOAT_TO_CHAN(v[2]), + CHAN_MAX); + +#endif +} + + + +static void +_tnl_Color3ubv( const GLubyte *v ) +{ +#if CHAN_BITS == 8 + GET_IMMEDIATE; + COLOR( IM, v[0], v[1], v[2], CHAN_MAX ); +#else + GET_IMMEDIATE; + COLOR(IM, + UBYTE_TO_CHAN(v[0]), + UBYTE_TO_CHAN(v[1]), + UBYTE_TO_CHAN(v[2]), + CHAN_MAX); +#endif +} + +static void +_tnl_Color4fv( const GLfloat *v ) +{ +#if CHAN_BITS == 8 + GLubyte col[4]; + GET_IMMEDIATE; + FLOAT_COLOR_TO_UBYTE_COLOR(col[0], v[0]); + FLOAT_COLOR_TO_UBYTE_COLOR(col[1], v[1]); + FLOAT_COLOR_TO_UBYTE_COLOR(col[2], v[2]); + FLOAT_COLOR_TO_UBYTE_COLOR(col[3], v[3]); + COLORV( IM, col ); +#else + GET_IMMEDIATE; + COLOR(IM, + UNCLAMPED_FLOAT_TO_CHAN(v[0]), + UNCLAMPED_FLOAT_TO_CHAN(v[1]), + UNCLAMPED_FLOAT_TO_CHAN(v[2]), + UNCLAMPED_FLOAT_TO_CHAN(v[3])); +#endif +} + + + +static void +_tnl_Color4ubv( const GLubyte *v) +{ +#if CHAN_BITS == 8 + GET_IMMEDIATE; + COLORV( IM, v ); +#else + GET_IMMEDIATE; + COLOR(IM, + UBYTE_TO_CHAN(v[0]), + UBYTE_TO_CHAN(v[1]), + UBYTE_TO_CHAN(v[2]), + UBYTE_TO_CHAN(v[3])); +#endif +} + + + + +#define SECONDARY_COLOR( IM, r, g, b ) \ +{ \ + GLuint count = IM->Count; \ + IM->Flag[count] |= VERT_SPEC_RGB; \ + IM->SecondaryColor[count][0] = r; \ + IM->SecondaryColor[count][1] = g; \ + IM->SecondaryColor[count][2] = b; \ +} + +#define SECONDARY_COLORV( IM, v ) \ +{ \ + GLuint count = IM->Count; \ + IM->Flag[count] |= VERT_SPEC_RGB; \ + IM->SecondaryColor[count][0] = v[0]; \ + IM->SecondaryColor[count][1] = v[1]; \ + IM->SecondaryColor[count][2] = v[2]; \ +} + + + + +static void +_tnl_SecondaryColor3fEXT( GLfloat red, GLfloat green, GLfloat blue ) +{ +#if CHAN_BITS == 8 + GLubyte col[3]; + GET_IMMEDIATE; + FLOAT_COLOR_TO_UBYTE_COLOR(col[0], red); + FLOAT_COLOR_TO_UBYTE_COLOR(col[1], green); + FLOAT_COLOR_TO_UBYTE_COLOR(col[2], blue); + SECONDARY_COLORV( IM, col ); +#else + GET_IMMEDIATE; + SECONDARY_COLOR(IM, + UNCLAMPED_FLOAT_TO_CHAN(red), + UNCLAMPED_FLOAT_TO_CHAN(green), + UNCLAMPED_FLOAT_TO_CHAN(blue)); +#endif +} + + + +static void +_tnl_SecondaryColor3ubEXT( GLubyte red, GLubyte green, GLubyte blue ) +{ +#if CHAN_BITS == 8 + GET_IMMEDIATE; + SECONDARY_COLOR( IM, red, green, blue ); +#else + GET_IMMEDIATE; + SECONDARY_COLOR(IM, + UBYTE_TO_CHAN(red), + UBYTE_TO_CHAN(green), + UBYTE_TO_CHAN(blue)); +#endif +} + + + + +static void +_tnl_SecondaryColor3fvEXT( const GLfloat *v ) +{ +#if CHAN_BITS == 8 + GLubyte col[3]; + GET_IMMEDIATE; + FLOAT_COLOR_TO_UBYTE_COLOR(col[0], v[0]); + FLOAT_COLOR_TO_UBYTE_COLOR(col[1], v[1]); + FLOAT_COLOR_TO_UBYTE_COLOR(col[2], v[2]); + SECONDARY_COLORV( IM, col ); +#else + GET_IMMEDIATE; + SECONDARY_COLOR(IM, + UNCLAMPED_FLOAT_TO_CHAN(v[0]), + UNCLAMPED_FLOAT_TO_CHAN(v[1]), + UNCLAMPED_FLOAT_TO_CHAN(v[2])); +#endif +} + + + +static void +_tnl_SecondaryColor3ubvEXT( const GLubyte *v ) +{ +#if CHAN_BITS == 8 + GET_IMMEDIATE; + SECONDARY_COLOR( IM, v[0], v[1], v[2] ); +#else + GET_IMMEDIATE; + SECONDARY_COLOR(IM, + UBYTE_TO_CHAN(v[0]), + UBYTE_TO_CHAN(v[1]), + UBYTE_TO_CHAN(v[2])); +#endif +} + + + + +static void +_tnl_EdgeFlag( GLboolean flag ) +{ + GLuint count; + GET_IMMEDIATE; + count = IM->Count; + IM->EdgeFlag[count] = flag; + IM->Flag[count] |= VERT_EDGE; +} + + +static void +_tnl_EdgeFlagv( const GLboolean *flag ) +{ + GLuint count; + GET_IMMEDIATE; + count = IM->Count; + IM->EdgeFlag[count] = *flag; + IM->Flag[count] |= VERT_EDGE; +} + + +static void +_tnl_FogCoordfEXT( GLfloat f ) +{ + GLuint count; + GET_IMMEDIATE; + count = IM->Count; + IM->FogCoord[count] = f; + IM->Flag[count] |= VERT_FOG_COORD; +} + +static void +_tnl_FogCoordfvEXT( const GLfloat *v ) +{ + GLuint count; + GET_IMMEDIATE; + count = IM->Count; + IM->FogCoord[count] = v[0]; + IM->Flag[count] |= VERT_FOG_COORD; +} + + +static void +_tnl_Indexi( GLint c ) +{ + GLuint count; + GET_IMMEDIATE; + count = IM->Count; + IM->Index[count] = c; + IM->Flag[count] |= VERT_INDEX; +} + + +static void +_tnl_Indexiv( const GLint *c ) +{ + GLuint count; + GET_IMMEDIATE; + count = IM->Count; + IM->Index[count] = *c; + IM->Flag[count] |= VERT_INDEX; +} + + +#define NORMAL( x, y, z ) \ +{ \ + GLuint count; \ + GLfloat *normal; \ + GET_IMMEDIATE; \ + count = IM->Count; \ + IM->Flag[count] |= VERT_NORM; \ + normal = IM->Normal[count]; \ + ASSIGN_3V(normal, x,y,z); \ +} + +#if defined(USE_IEEE) +#define NORMALF( x, y, z ) \ +{ \ + GLuint count; \ + GLint *normal; \ + GET_IMMEDIATE; \ + count = IM->Count; \ + IM->Flag[count] |= VERT_NORM; \ + normal = (GLint *)IM->Normal[count]; \ + ASSIGN_3V(normal, *(int*)&(x), *(int*)&(y), *(int*)&(z)); \ +} +#else +#define NORMALF NORMAL +#endif + +static void +_tnl_Normal3f( GLfloat nx, GLfloat ny, GLfloat nz ) +{ + NORMALF(nx, ny, nz); +} + + +static void +_tnl_Normal3fv( const GLfloat *v ) +{ + NORMALF( v[0], v[1], v[2] ); +} + + + +#define TEXCOORD1(s) \ +{ \ + GLuint count; \ + GLfloat *tc; \ + GET_IMMEDIATE; \ + count = IM->Count; \ + IM->Flag[count] |= VERT_TEX0; \ + tc = IM->TexCoord0[count]; \ + ASSIGN_4V(tc,s,0,0,1); \ +} + +#define TEXCOORD2(s,t) \ +{ \ + GLuint count; \ + GLfloat *tc; \ + GET_IMMEDIATE; \ + count = IM->Count; \ + IM->Flag[count] |= VERT_TEX0; \ + tc = IM->TexCoord0[count]; \ + ASSIGN_4V(tc, s,t,0,1); \ +} + +#define TEXCOORD3(s,t,u) \ +{ \ + GLuint count; \ + GLfloat *tc; \ + GET_IMMEDIATE; \ + count = IM->Count; \ + IM->Flag[count] |= VERT_TEX0; \ + IM->TexSize |= TEX_0_SIZE_3; \ + tc = IM->TexCoord0[count]; \ + ASSIGN_4V(tc, s,t,u,1); \ +} + +#define TEXCOORD4(s,t,u,v) \ +{ \ + GLuint count; \ + GLfloat *tc; \ + GET_IMMEDIATE; \ + count = IM->Count; \ + IM->Flag[count] |= VERT_TEX0; \ + IM->TexSize |= TEX_0_SIZE_4; \ + tc = IM->TexCoord0[count]; \ + ASSIGN_4V(tc, s,t,u,v); \ +} + +#if defined(USE_IEEE) +#define TEXCOORD2F(s,t) \ +{ \ + GLuint count; \ + GLint *tc; \ + GET_IMMEDIATE; \ + count = IM->Count; \ + IM->Flag[count] |= VERT_TEX0; \ + tc = (GLint *)IM->TexCoord0[count]; \ + tc[0] = *(GLint *)&(s); \ + tc[1] = *(GLint *)&(t); \ + tc[2] = 0; \ + tc[3] = IEEE_ONE; \ +} +#else +#define TEXCOORD2F TEXCOORD2 +#endif + +static void +_tnl_TexCoord1f( GLfloat s ) +{ + TEXCOORD1(s); +} + + +static void +_tnl_TexCoord2f( GLfloat s, GLfloat t ) +{ + TEXCOORD2F(s,t); +} + + +static void +_tnl_TexCoord3f( GLfloat s, GLfloat t, GLfloat r ) +{ + TEXCOORD3(s,t,r); +} + +static void +_tnl_TexCoord4f( GLfloat s, GLfloat t, GLfloat r, GLfloat q ) +{ + TEXCOORD4(s,t,r,q) +} + +static void +_tnl_TexCoord1fv( const GLfloat *v ) +{ + TEXCOORD1(v[0]); +} + +static void +_tnl_TexCoord2fv( const GLfloat *v ) +{ + TEXCOORD2F(v[0],v[1]); +} + +static void +_tnl_TexCoord3fv( const GLfloat *v ) +{ + TEXCOORD3(v[0],v[1],v[2]); +} + +static void +_tnl_TexCoord4fv( const GLfloat *v ) +{ + TEXCOORD4(v[0],v[1],v[2],v[3]); +} + + + +/* KW: Run into bad problems in vertex copying if we don't fully pad + * the incoming vertices. + */ +#define VERTEX2(IM, x,y) \ +{ \ + GLuint count = IM->Count++; \ + GLfloat *dest = IM->Obj[count]; \ + IM->Flag[count] |= VERT_OBJ; \ + ASSIGN_4V(dest, x, y, 0, 1); \ +/* ASSERT(IM->Flag[IM->Count]==0); */\ + if (count == IMM_MAXDATA - 1) \ + _tnl_flush_immediate( IM ); \ +} + +#define VERTEX3(IM,x,y,z) \ +{ \ + GLuint count = IM->Count++; \ + GLfloat *dest = IM->Obj[count]; \ + IM->Flag[count] |= VERT_OBJ_23; \ + ASSIGN_4V(dest, x, y, z, 1); \ +/* ASSERT(IM->Flag[IM->Count]==0); */ \ + if (count == IMM_MAXDATA - 1) \ + _tnl_flush_immediate( IM ); \ +} + +#define VERTEX4(IM, x,y,z,w) \ +{ \ + GLuint count = IM->Count++; \ + GLfloat *dest = IM->Obj[count]; \ + IM->Flag[count] |= VERT_OBJ_234; \ + ASSIGN_4V(dest, x, y, z, w); \ + if (count == IMM_MAXDATA - 1) \ + _tnl_flush_immediate( IM ); \ +} + +#if defined(USE_IEEE) +#define VERTEX2F(IM, x, y) \ +{ \ + GLuint count = IM->Count++; \ + GLint *dest = (GLint *)IM->Obj[count]; \ + IM->Flag[count] |= VERT_OBJ; \ + dest[0] = *(GLint *)&(x); \ + dest[1] = *(GLint *)&(y); \ + dest[2] = 0; \ + dest[3] = IEEE_ONE; \ +/* ASSERT(IM->Flag[IM->Count]==0); */ \ + if (count == IMM_MAXDATA - 1) \ + _tnl_flush_immediate( IM ); \ +} +#else +#define VERTEX2F VERTEX2 +#endif + +#if defined(USE_IEEE) +#define VERTEX3F(IM, x, y, z) \ +{ \ + GLuint count = IM->Count++; \ + GLint *dest = (GLint *)IM->Obj[count]; \ + IM->Flag[count] |= VERT_OBJ_23; \ + dest[0] = *(GLint *)&(x); \ + dest[1] = *(GLint *)&(y); \ + dest[2] = *(GLint *)&(z); \ + dest[3] = IEEE_ONE; \ +/* ASSERT(IM->Flag[IM->Count]==0); */ \ + if (count == IMM_MAXDATA - 1) \ + _tnl_flush_immediate( IM ); \ +} +#else +#define VERTEX3F VERTEX3 +#endif + +#if defined(USE_IEEE) +#define VERTEX4F(IM, x, y, z, w) \ +{ \ + GLuint count = IM->Count++; \ + GLint *dest = (GLint *)IM->Obj[count]; \ + IM->Flag[count] |= VERT_OBJ_234; \ + dest[0] = *(GLint *)&(x); \ + dest[1] = *(GLint *)&(y); \ + dest[2] = *(GLint *)&(z); \ + dest[3] = *(GLint *)&(w); \ + if (count == IMM_MAXDATA - 1) \ + _tnl_flush_immediate( IM ); \ +} +#else +#define VERTEX4F VERTEX4 +#endif + + + +static void +_tnl_Vertex2f( GLfloat x, GLfloat y ) +{ + GET_IMMEDIATE; + VERTEX2F( IM, x, y ); +} + +static void +_tnl_Vertex3f( GLfloat x, GLfloat y, GLfloat z ) +{ + GET_IMMEDIATE; + VERTEX3F( IM, x, y, z ); +} +static void +_tnl_Vertex4f( GLfloat x, GLfloat y, GLfloat z, GLfloat w ) +{ + GET_IMMEDIATE; + VERTEX4F( IM, x, y, z, w ); +} + +static void +_tnl_Vertex2fv( const GLfloat *v ) +{ + GET_IMMEDIATE; + VERTEX2F( IM, v[0], v[1] ); +} + +static void +_tnl_Vertex3fv( const GLfloat *v ) +{ + GET_IMMEDIATE; + VERTEX3F( IM, v[0], v[1], v[2] ); +} + +static void +_tnl_Vertex4fv( const GLfloat *v ) +{ + GET_IMMEDIATE; + VERTEX4F( IM, v[0], v[1], v[2], v[3] ); +} + + + + +/* + * GL_ARB_multitexture + * + * Note: the multitexture spec says that specifying an invalid target + * has undefined results and does not have to generate an error. Just + * don't crash. We no-op on invalid targets. + */ + +#define MAX_TARGET (GL_TEXTURE0_ARB + MAX_TEXTURE_UNITS) + +#define MULTI_TEXCOORD1(target, s) \ +{ \ + GET_IMMEDIATE; \ + GLuint texunit = target - GL_TEXTURE0_ARB; \ + if (texunit < IM->MaxTextureUnits) { \ + GLuint count = IM->Count; \ + GLfloat *tc = IM->TexCoord[texunit][count]; \ + ASSIGN_4V(tc, s, 0.0F, 0.0F, 1.0F); \ + IM->Flag[count] |= VERT_TEX(texunit); \ + } \ +} + +#define MULTI_TEXCOORD2(target, s, t) \ +{ \ + GET_IMMEDIATE; \ + GLuint texunit = target - GL_TEXTURE0_ARB; \ + if (texunit < IM->MaxTextureUnits) { \ + GLuint count = IM->Count; \ + GLfloat *tc = IM->TexCoord[texunit][count]; \ + ASSIGN_4V(tc, s, t, 0.0F, 1.0F); \ + IM->Flag[count] |= VERT_TEX(texunit); \ + } \ +} + +#define MULTI_TEXCOORD3(target, s, t, u) \ +{ \ + GET_IMMEDIATE; \ + GLuint texunit = target - GL_TEXTURE0_ARB; \ + if (texunit < IM->MaxTextureUnits) { \ + GLuint count = IM->Count; \ + GLfloat *tc = IM->TexCoord[texunit][count]; \ + ASSIGN_4V(tc, s, t, u, 1.0F); \ + IM->Flag[count] |= VERT_TEX(texunit); \ + IM->TexSize |= TEX_SIZE_3(texunit); \ + } \ +} + +#define MULTI_TEXCOORD4(target, s, t, u, v) \ +{ \ + GET_IMMEDIATE; \ + GLuint texunit = target - GL_TEXTURE0_ARB; \ + if (texunit < IM->MaxTextureUnits) { \ + GLuint count = IM->Count; \ + GLfloat *tc = IM->TexCoord[texunit][count]; \ + ASSIGN_4V(tc, s, t, u, v); \ + IM->Flag[count] |= VERT_TEX(texunit); \ + IM->TexSize |= TEX_SIZE_4(texunit); \ + } \ +} + +#if defined(USE_IEEE) +#define MULTI_TEXCOORD2F(target, s, t) \ +{ \ + GET_IMMEDIATE; \ + GLuint texunit = target - GL_TEXTURE0_ARB; \ + if (texunit < IM->MaxTextureUnits) { \ + GLuint count = IM->Count; \ + GLint *tc = (GLint *)IM->TexCoord[texunit][count]; \ + IM->Flag[count] |= VERT_TEX(texunit); \ + tc[0] = *(int *)&(s); \ + tc[1] = *(int *)&(t); \ + tc[2] = 0; \ + tc[3] = IEEE_ONE; \ + } \ +} +#else +#define MULTI_TEXCOORD2F MULTI_TEXCOORD2 +#endif + +static void +_tnl_MultiTexCoord1fARB(GLenum target, GLfloat s) +{ + MULTI_TEXCOORD1( target, s ); +} + +static void +_tnl_MultiTexCoord1fvARB(GLenum target, const GLfloat *v) +{ + MULTI_TEXCOORD1( target, v[0] ); +} + +static void +_tnl_MultiTexCoord2fARB(GLenum target, GLfloat s, GLfloat t) +{ + MULTI_TEXCOORD2F( target, s, t ); +} + +static void +_tnl_MultiTexCoord2fvARB(GLenum target, const GLfloat *v) +{ + MULTI_TEXCOORD2F( target, v[0], v[1] ); +} + +static void +_tnl_MultiTexCoord3fARB(GLenum target, GLfloat s, GLfloat t, GLfloat r) +{ + MULTI_TEXCOORD3( target, s, t, r ); +} + +static void +_tnl_MultiTexCoord3fvARB(GLenum target, const GLfloat *v) +{ + MULTI_TEXCOORD3( target, v[0], v[1], v[2] ); +} + +static void +_tnl_MultiTexCoord4fARB(GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q) +{ + MULTI_TEXCOORD4( target, s, t, r, q ); +} + +static void +_tnl_MultiTexCoord4fvARB(GLenum target, const GLfloat *v) +{ + MULTI_TEXCOORD4( target, v[0], v[1], v[2], v[3] ); +} + + + +/* KW: Because the eval values don't become 'current', fixup will flow + * through these vertices, and then evaluation will write on top + * of the fixup results. + * + * Note: using Obj to hold eval coord data. + */ +#define EVALCOORD1(IM, x) \ +{ \ + GLuint count = IM->Count++; \ + IM->Flag[count] |= VERT_EVAL_C1; \ + ASSIGN_4V(IM->Obj[count], x, 0, 0, 1); \ + if (count == IMM_MAXDATA-1) \ + _tnl_flush_immediate( IM ); \ +} + +#define EVALCOORD2(IM, x, y) \ +{ \ + GLuint count = IM->Count++; \ + IM->Flag[count] |= VERT_EVAL_C2; \ + ASSIGN_4V(IM->Obj[count], x, y, 0, 1); \ + if (count == IMM_MAXDATA-1) \ + _tnl_flush_immediate( IM ); \ +} + +#define EVALPOINT1(IM, x) \ +{ \ + GLuint count = IM->Count++; \ + IM->Flag[count] |= VERT_EVAL_P1; \ + ASSIGN_4V(IM->Obj[count], x, 0, 0, 1); \ + if (count == IMM_MAXDATA-1) \ + _tnl_flush_immediate( IM ); \ +} + +#define EVALPOINT2(IM, x, y) \ +{ \ + GLuint count = IM->Count++; \ + IM->Flag[count] |= VERT_EVAL_P2; \ + ASSIGN_4V(IM->Obj[count], x, y, 0, 1); \ + if (count == IMM_MAXDATA-1) \ + _tnl_flush_immediate( IM ); \ +} + +static void +_tnl_EvalCoord1f( GLfloat u ) +{ + GET_IMMEDIATE; + EVALCOORD1( IM, u ); +} + +static void +_tnl_EvalCoord1fv( const GLfloat *u ) +{ + GET_IMMEDIATE; + EVALCOORD1( IM, (GLfloat) *u ); +} + +static void +_tnl_EvalCoord2f( GLfloat u, GLfloat v ) +{ + GET_IMMEDIATE; + EVALCOORD2( IM, u, v ); +} + +static void +_tnl_EvalCoord2fv( const GLfloat *u ) +{ + GET_IMMEDIATE; + EVALCOORD2( IM, u[0], u[1] ); +} + + +static void +_tnl_EvalPoint1( GLint i ) +{ + GET_IMMEDIATE; + EVALPOINT1( IM, i ); +} + + +static void +_tnl_EvalPoint2( GLint i, GLint j ) +{ + GET_IMMEDIATE; + EVALPOINT2( IM, i, j ); +} + + +/* Need to use the default array-elt outside begin/end for strict + * conformance. + */ +#define ARRAY_ELT( IM, i ) \ +{ \ + GLuint count = IM->Count; \ + IM->Elt[count] = i; \ + IM->Flag[count] &= IM->ArrayEltFlags; \ + IM->Flag[count] |= VERT_ELT; \ + IM->FlushElt |= IM->ArrayEltFlush; \ + IM->Count += IM->ArrayEltIncr; \ + if (IM->Count == IMM_MAXDATA) \ + _tnl_flush_immediate( IM ); \ +} + + +static void +_tnl_ArrayElement( GLint i ) +{ + GET_IMMEDIATE; + ARRAY_ELT( IM, i ); +} + + +/* Internal functions. These are safe to use providing either: + * + * - It is determined that a display list is not being compiled, or + * if so that these commands won't be compiled into the list (see + * t_eval.c for an example). + * + * - _tnl_hard_begin() is used instead of _tnl_[bB]egin, and tested + * for a GL_TRUE return value. See _tnl_Rectf, below. + */ +void +_tnl_eval_coord1f( GLcontext *CC, GLfloat u ) +{ + struct immediate *i = TNL_CURRENT_IM(CC); + EVALCOORD1( i, u ); +} + +void +_tnl_eval_coord2f( GLcontext *CC, GLfloat u, GLfloat v ) +{ + struct immediate *i = TNL_CURRENT_IM(CC); + EVALCOORD2( i, u, v ); +} + +void +_tnl_array_element( GLcontext *CC, GLint i ) +{ + struct immediate *im = TNL_CURRENT_IM(CC); + ARRAY_ELT( im, i ); +} + +void +_tnl_vertex2f( GLcontext *ctx, GLfloat x, GLfloat y ) +{ + struct immediate *im = TNL_CURRENT_IM(ctx); + VERTEX2( im, x, y ); +} + + + + + +/* Execute a glRectf() function. _tnl_hard_begin() ensures the check + * on outside_begin_end is executed even in compiled lists. These + * vertices can now participate in the same VB as regular ones, even + * in most display lists. + */ +static void +_tnl_Rectf( GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2 ) +{ + GET_CURRENT_CONTEXT(ctx); + + if (_tnl_hard_begin( ctx, GL_QUADS )) { + _tnl_vertex2f( ctx, x1, y1 ); + _tnl_vertex2f( ctx, x2, y1 ); + _tnl_vertex2f( ctx, x2, y2 ); + _tnl_vertex2f( ctx, x1, y2 ); + _tnl_end( ctx ); + } +} + +static void +_tnl_Materialfv( GLenum face, GLenum pname, const GLfloat *params ) +{ + GET_CURRENT_CONTEXT(ctx); + struct immediate *IM = TNL_CURRENT_IM(ctx); + GLuint count = IM->Count; + struct gl_material *mat; + GLuint bitmask = gl_material_bitmask( ctx, face, pname, ~0, "Materialfv" ); + + if (bitmask == 0) + return; + + if (!IM->Material) { + IM->Material = (GLmaterial (*)[2]) MALLOC( sizeof(GLmaterial) * + IMM_SIZE * 2 ); + IM->MaterialMask = (GLuint *) MALLOC( sizeof(GLuint) * IMM_SIZE ); + } + + if (!(IM->Flag[count] & VERT_MATERIAL)) { + IM->Flag[count] |= VERT_MATERIAL; + IM->MaterialMask[count] = 0; + } + + IM->MaterialMask[count] |= bitmask; + mat = IM->Material[count]; + + if (bitmask & FRONT_AMBIENT_BIT) { + COPY_4FV( mat[0].Ambient, params ); + } + if (bitmask & BACK_AMBIENT_BIT) { + COPY_4FV( mat[1].Ambient, params ); + } + if (bitmask & FRONT_DIFFUSE_BIT) { + COPY_4FV( mat[0].Diffuse, params ); + } + if (bitmask & BACK_DIFFUSE_BIT) { + COPY_4FV( mat[1].Diffuse, params ); + } + if (bitmask & FRONT_SPECULAR_BIT) { + COPY_4FV( mat[0].Specular, params ); + } + if (bitmask & BACK_SPECULAR_BIT) { + COPY_4FV( mat[1].Specular, params ); + } + if (bitmask & FRONT_EMISSION_BIT) { + COPY_4FV( mat[0].Emission, params ); + } + if (bitmask & BACK_EMISSION_BIT) { + COPY_4FV( mat[1].Emission, params ); + } + if (bitmask & FRONT_SHININESS_BIT) { + GLfloat shininess = CLAMP( params[0], 0.0F, 128.0F ); + mat[0].Shininess = shininess; + } + if (bitmask & BACK_SHININESS_BIT) { + GLfloat shininess = CLAMP( params[0], 0.0F, 128.0F ); + mat[1].Shininess = shininess; + } + if (bitmask & FRONT_INDEXES_BIT) { + mat[0].AmbientIndex = params[0]; + mat[0].DiffuseIndex = params[1]; + mat[0].SpecularIndex = params[2]; + } + if (bitmask & BACK_INDEXES_BIT) { + mat[1].AmbientIndex = params[0]; + mat[1].DiffuseIndex = params[1]; + mat[1].SpecularIndex = params[2]; + } +} + +void _tnl_imm_vtxfmt_init( GLcontext *ctx ) +{ + GLvertexformat *vfmt = &(TNL_CONTEXT(ctx)->vtxfmt); + + /* All begin/end operations are handled by this vertex format: + */ + vfmt->ArrayElement = _tnl_ArrayElement; + vfmt->Begin = _tnl_Begin; + vfmt->Color3f = _tnl_Color3f; + vfmt->Color3fv = _tnl_Color3fv; + vfmt->Color3ub = _tnl_Color3ub; + vfmt->Color3ubv = _tnl_Color3ubv; + vfmt->Color4f = _tnl_Color4f; + vfmt->Color4fv = _tnl_Color4fv; + vfmt->Color4ub = _tnl_Color4ub; + vfmt->Color4ubv = _tnl_Color4ubv; + vfmt->EdgeFlag = _tnl_EdgeFlag; + vfmt->EdgeFlagv = _tnl_EdgeFlagv; + vfmt->End = _tnl_End; + vfmt->EvalCoord1f = _tnl_EvalCoord1f; + vfmt->EvalCoord1fv = _tnl_EvalCoord1fv; + vfmt->EvalCoord2f = _tnl_EvalCoord2f; + vfmt->EvalCoord2fv = _tnl_EvalCoord2fv; + vfmt->EvalPoint1 = _tnl_EvalPoint1; + vfmt->EvalPoint2 = _tnl_EvalPoint2; + vfmt->FogCoordfEXT = _tnl_FogCoordfEXT; + vfmt->FogCoordfvEXT = _tnl_FogCoordfvEXT; + vfmt->Indexi = _tnl_Indexi; + vfmt->Indexiv = _tnl_Indexiv; + vfmt->Materialfv = _tnl_Materialfv; + vfmt->MultiTexCoord1fARB = _tnl_MultiTexCoord1fARB; + vfmt->MultiTexCoord1fvARB = _tnl_MultiTexCoord1fvARB; + vfmt->MultiTexCoord2fARB = _tnl_MultiTexCoord2fARB; + vfmt->MultiTexCoord2fvARB = _tnl_MultiTexCoord2fvARB; + vfmt->MultiTexCoord3fARB = _tnl_MultiTexCoord3fARB; + vfmt->MultiTexCoord3fvARB = _tnl_MultiTexCoord3fvARB; + vfmt->MultiTexCoord4fARB = _tnl_MultiTexCoord4fARB; + vfmt->MultiTexCoord4fvARB = _tnl_MultiTexCoord4fvARB; + vfmt->Normal3f = _tnl_Normal3f; + vfmt->Normal3fv = _tnl_Normal3fv; + vfmt->SecondaryColor3fEXT = _tnl_SecondaryColor3fEXT; + vfmt->SecondaryColor3fvEXT = _tnl_SecondaryColor3fvEXT; + vfmt->SecondaryColor3ubEXT = _tnl_SecondaryColor3ubEXT; + vfmt->SecondaryColor3ubvEXT = _tnl_SecondaryColor3ubvEXT; + vfmt->TexCoord1f = _tnl_TexCoord1f; + vfmt->TexCoord1fv = _tnl_TexCoord1fv; + vfmt->TexCoord2f = _tnl_TexCoord2f; + vfmt->TexCoord2fv = _tnl_TexCoord2fv; + vfmt->TexCoord3f = _tnl_TexCoord3f; + vfmt->TexCoord3fv = _tnl_TexCoord3fv; + vfmt->TexCoord4f = _tnl_TexCoord4f; + vfmt->TexCoord4fv = _tnl_TexCoord4fv; + vfmt->Vertex2f = _tnl_Vertex2f; + vfmt->Vertex2fv = _tnl_Vertex2fv; + vfmt->Vertex3f = _tnl_Vertex3f; + vfmt->Vertex3fv = _tnl_Vertex3fv; + vfmt->Vertex4f = _tnl_Vertex4f; + vfmt->Vertex4fv = _tnl_Vertex4fv; + + /* Outside begin/end functions (from t_varray.c, t_eval.c, ...): + */ + vfmt->Rectf = _tnl_Rectf; + + /* Just use the core function: + */ + vfmt->CallList = _mesa_CallList; + + vfmt->prefer_float_colors = GL_FALSE; +} diff --git a/src/mesa/tnl/t_imm_api.h b/src/mesa/tnl/t_imm_api.h new file mode 100644 index 00000000000..8e4c9943d21 --- /dev/null +++ b/src/mesa/tnl/t_imm_api.h @@ -0,0 +1,50 @@ +/* $Id: t_imm_api.h,v 1.1 2000/12/26 05:09:32 keithw Exp $ */ + +/* + * Mesa 3-D graphics library + * Version: 3.5 + * + * Copyright (C) 1999-2000 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. + */ + + +#ifndef _T_VTXFMT_H +#define _T_VTXFMT_H + +#include "mtypes.h" +#include "t_context.h" + + +/* TNL-private internal functions for building higher-level operations: + */ +extern void _tnl_begin( GLcontext *ctx, GLenum p ); +extern GLboolean _tnl_hard_begin( GLcontext *ctx, GLenum p ); +extern void _tnl_end( GLcontext *ctx ); +extern void _tnl_vertex2f( GLcontext *ctx, GLfloat x, GLfloat y ); +extern void _tnl_eval_coord1f( GLcontext *CC, GLfloat u ); +extern void _tnl_eval_coord2f( GLcontext *CC, GLfloat u, GLfloat v ); +extern void _tnl_array_element( GLcontext *CC, GLint i ); + +/* Initialize our part of the vtxfmt struct: + */ +extern void _tnl_imm_vtxfmt_init( GLcontext *ctx ); + + +#endif diff --git a/src/mesa/tnl/t_imm_debug.c b/src/mesa/tnl/t_imm_debug.c new file mode 100644 index 00000000000..192259afcda --- /dev/null +++ b/src/mesa/tnl/t_imm_debug.c @@ -0,0 +1,169 @@ +/* $Id: t_imm_debug.c,v 1.1 2000/12/26 05:09:32 keithw Exp $ */ + +/* + * Mesa 3-D graphics library + * Version: 3.5 + * + * Copyright (C) 1999-2000 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. + */ + +#include "mtypes.h" +#include "t_context.h" +#include "t_imm_debug.h" + +void _tnl_print_vert_flags( const char *name, GLuint flags ) +{ + fprintf(stderr, + "%s: (0x%x) %s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n", + name, + flags, + (flags & VERT_CLIP) ? "clip/proj-clip/glend, " : "", + (flags & VERT_EDGE) ? "edgeflag, " : "", + (flags & VERT_ELT) ? "array-elt, " : "", + (flags & VERT_END_VB) ? "end-vb, " : "", + (flags & VERT_EVAL_ANY) ? "eval-coord, " : "", + (flags & VERT_EYE) ? "eye/glbegin, " : "", + (flags & VERT_FOG_COORD) ? "fog-coord, " : "", + (flags & VERT_INDEX) ? "index, " : "", + (flags & VERT_MATERIAL) ? "material, " : "", + (flags & VERT_NORM) ? "normals, " : "", + (flags & VERT_OBJ) ? "obj, " : "", + (flags & VERT_OBJ_3) ? "obj-3, " : "", + (flags & VERT_OBJ_4) ? "obj-4, " : "", + (flags & VERT_POINT_SIZE) ? "point-size, " : "", + (flags & VERT_RGBA) ? "colors, " : "", + (flags & VERT_SPEC_RGB) ? "specular, " : "", + (flags & VERT_TEX0) ? "texcoord0, " : "", + (flags & VERT_TEX1) ? "texcoord1, " : "", + (flags & VERT_TEX2) ? "texcoord2, " : "", + (flags & VERT_TEX3) ? "texcoord3, " : "", + (flags & VERT_TEX4) ? "texcoord4, " : "", + (flags & VERT_TEX5) ? "texcoord5, " : "", + (flags & VERT_TEX6) ? "texcoord6, " : "", + (flags & VERT_TEX7) ? "texcoord7, " : "" + ); +} + +void _tnl_print_cassette( struct immediate *IM ) +{ + GLuint i; + GLuint *flags = IM->Flag; + GLuint andflag = IM->CopyAndFlag; + GLuint orflag = IM->CopyOrFlag; + GLuint state = IM->BeginState; + GLuint req = ~0; + + fprintf(stderr, "Cassette id %d, %u rows.\n", IM->id, + IM->Count - IM->CopyStart); + + _tnl_print_vert_flags("Contains at least one", orflag); + + if (IM->Count != IM->CopyStart) + { + _tnl_print_vert_flags("Contains a full complement of", andflag); + + fprintf(stderr, "Final begin/end state %s/%s, errors %s/%s\n", + (state & VERT_BEGIN_0) ? "in" : "out", + (state & VERT_BEGIN_1) ? "in" : "out", + (state & VERT_ERROR_0) ? "y" : "n", + (state & VERT_ERROR_1) ? "y" : "n"); + + } + + for (i = IM->CopyStart ; i <= IM->Count ; i++) { + fprintf(stderr, "%u: ", i); + if (req & VERT_OBJ_234) { + if (flags[i] & VERT_EVAL_C1) + fprintf(stderr, "EvalCoord %f ", IM->Obj[i][0]); + else if (flags[i] & VERT_EVAL_P1) + fprintf(stderr, "EvalPoint %.0f ", IM->Obj[i][0]); + else if (flags[i] & VERT_EVAL_C2) + fprintf(stderr, "EvalCoord %f %f ", IM->Obj[i][0], IM->Obj[i][1]); + else if (flags[i] & VERT_EVAL_P2) + fprintf(stderr, "EvalPoint %.0f %.0f ", IM->Obj[i][0], IM->Obj[i][1]); + else if (i < IM->Count && (flags[i]&VERT_OBJ_234)) { + fprintf(stderr, "Obj %f %f %f %f", + IM->Obj[i][0], IM->Obj[i][1], IM->Obj[i][2], IM->Obj[i][3]); + } + } + + if (req & flags[i] & VERT_ELT) + fprintf(stderr, " Elt %u\t", IM->Elt[i]); + + if (req & flags[i] & VERT_NORM) + fprintf(stderr, " Norm %f %f %f ", + IM->Normal[i][0], IM->Normal[i][1], IM->Normal[i][2]); + + if (req & flags[i] & VERT_TEX_ANY) { + GLuint j; + for (j = 0 ; j < MAX_TEXTURE_UNITS ; j++) { + if (req & flags[i] & VERT_TEX(j)) { + fprintf(stderr, + "TC%d %f %f %f %f", + j, + IM->TexCoord[j][i][0], IM->TexCoord[j][i][1], + IM->TexCoord[j][i][2], IM->TexCoord[j][i][2]); + } + } + } + + if (req & flags[i] & VERT_RGBA) + fprintf(stderr, " Rgba %d %d %d %d ", + IM->Color[i][0], IM->Color[i][1], + IM->Color[i][2], IM->Color[i][3]); + + if (req & flags[i] & VERT_SPEC_RGB) + fprintf(stderr, " Spec %d %d %d ", + IM->SecondaryColor[i][0], IM->SecondaryColor[i][1], + IM->SecondaryColor[i][2]); + + if (req & flags[i] & VERT_FOG_COORD) + fprintf(stderr, " Fog %f ", IM->FogCoord[i]); + + if (req & flags[i] & VERT_INDEX) + fprintf(stderr, " Index %u ", IM->Index[i]); + + if (req & flags[i] & VERT_EDGE) + fprintf(stderr, " Edgeflag %d ", IM->EdgeFlag[i]); + + if (req & flags[i] & VERT_MATERIAL) + fprintf(stderr, " Material "); + + + /* The order of these two is not easily knowable, but this is + * the usually correct way to look at them. + */ + if (req & flags[i] & VERT_END) + fprintf(stderr, " END "); + + if (req & flags[i] & VERT_BEGIN) + fprintf(stderr, " BEGIN(%s) (%s%s%s%s)", + _mesa_prim_name[IM->Primitive[i] & PRIM_MODE_MASK], + (IM->Primitive[i] & PRIM_LAST) ? "LAST," : "", + (IM->Primitive[i] & PRIM_BEGIN) ? "BEGIN," : "", + (IM->Primitive[i] & PRIM_END) ? "END," : "", + (IM->Primitive[i] & PRIM_PARITY) ? "PARITY," : ""); + + fprintf(stderr, "\n"); + } +} + + + diff --git a/src/mesa/tnl/t_imm_debug.h b/src/mesa/tnl/t_imm_debug.h new file mode 100644 index 00000000000..aaae5c11da3 --- /dev/null +++ b/src/mesa/tnl/t_imm_debug.h @@ -0,0 +1,11 @@ + +#ifndef _T_DEBUG_H +#define _T_DEBUG_H + +#include "mtypes.h" +#include "t_context.h" + +void _tnl_print_cassette( struct immediate *IM ); +void _tnl_print_vert_flags( const char *name, GLuint flags ); + +#endif diff --git a/src/mesa/tnl/t_imm_dlist.c b/src/mesa/tnl/t_imm_dlist.c new file mode 100644 index 00000000000..f5f3bca5cd9 --- /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 <[email protected]> + */ + + +#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 ); +} diff --git a/src/mesa/tnl/t_imm_dlist.h b/src/mesa/tnl/t_imm_dlist.h new file mode 100644 index 00000000000..1b6c4a778ac --- /dev/null +++ b/src/mesa/tnl/t_imm_dlist.h @@ -0,0 +1,46 @@ +/* $Id: t_imm_dlist.h,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 <[email protected]> + */ + +#ifndef _T_DLIST_H +#define _T_DLIST_H + +#include "mtypes.h" +#include "t_context.h" + +extern void _tnl_dlist_init( GLcontext *ctx ); + +extern void _tnl_compile_cassette( GLcontext *ctx, struct immediate *IM ); +extern void _tnl_EndList( GLcontext *ctx ); +extern void _tnl_NewList( GLcontext *ctx, GLuint list, GLenum mode ); +extern void _tnl_save_Begin( GLenum mode ); + +extern void _tnl_EndCallList( GLcontext *ctx ); +extern void _tnl_BeginCallList( GLcontext *ctx, GLuint list ); + +#endif diff --git a/src/mesa/tnl/t_imm_elt.c b/src/mesa/tnl/t_imm_elt.c new file mode 100644 index 00000000000..67fbdbe907c --- /dev/null +++ b/src/mesa/tnl/t_imm_elt.c @@ -0,0 +1,759 @@ +/* $Id: t_imm_elt.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 <[email protected]> + */ + +#include "glheader.h" +#include "colormac.h" +#include "mem.h" +#include "mmath.h" +#include "mtypes.h" + +#include "math/m_translate.h" + +#include "t_context.h" +#include "t_imm_elt.h" + + + +typedef void (*trans_elt_1f_func)(GLfloat *to, + CONST void *ptr, + GLuint stride, + GLuint *flags, + GLuint *elts, + GLuint match, + GLuint start, + GLuint n ); + +typedef void (*trans_elt_1ui_func)(GLuint *to, + CONST void *ptr, + GLuint stride, + GLuint *flags, + GLuint *elts, + GLuint match, + GLuint start, + GLuint n ); + +typedef void (*trans_elt_1ub_func)(GLubyte *to, + CONST void *ptr, + GLuint stride, + GLuint *flags, + GLuint *elts, + GLuint match, + GLuint start, + GLuint n ); + +typedef void (*trans_elt_4ub_func)(GLubyte (*to)[4], + CONST void *ptr, + GLuint stride, + GLuint *flags, + GLuint *elts, + GLuint match, + GLuint start, + GLuint n ); + +typedef void (*trans_elt_4f_func)(GLfloat (*to)[4], + CONST void *ptr, + GLuint stride, + GLuint *flags, + GLuint *elts, + GLuint match, + GLuint start, + GLuint n ); + +typedef void (*trans_elt_3f_func)(GLfloat (*to)[3], + CONST void *ptr, + GLuint stride, + GLuint *flags, + GLuint *elts, + GLuint match, + GLuint start, + GLuint n ); + + + + +static trans_elt_1f_func _tnl_trans_elt_1f_tab[MAX_TYPES]; +static trans_elt_1ui_func _tnl_trans_elt_1ui_tab[MAX_TYPES]; +static trans_elt_1ub_func _tnl_trans_elt_1ub_tab[MAX_TYPES]; +static trans_elt_3f_func _tnl_trans_elt_3f_tab[MAX_TYPES]; +static trans_elt_4ub_func _tnl_trans_elt_4ub_tab[5][MAX_TYPES]; +static trans_elt_4f_func _tnl_trans_elt_4f_tab[5][MAX_TYPES]; + + +#define PTR_ELT(ptr, elt) (((SRC *)ptr)[elt]) + + + + + +/* Code specific to array element implementation. There is a small + * subtlety in the bits CHECK() tests, and the way bits are set in + * glArrayElement which ensures that if, eg, in the case that the + * vertex array is disabled and normal array is enabled, and we get + * either sequence: + * + * ArrayElement() OR Normal() + * Normal() ArrayElement() + * Vertex() Vertex() + * + * That the correct value for normal is used. + */ +#define TAB(x) _tnl_trans_elt##x##_tab +#define ARGS GLuint *flags, GLuint *elts, GLuint match, \ + GLuint start, GLuint n +#define SRC_START 0 +#define DST_START start +#undef CHECK +#define CHECK if ((flags[i]&match) == VERT_ELT) +#define NEXT_F (void)1 +#define NEXT_F2 f = first + elts[i] * stride; + + +/* GL_BYTE + */ +#define SRC GLbyte +#define SRC_IDX TYPE_IDX(GL_BYTE) +#define TRX_3F(f,n) BYTE_TO_FLOAT( PTR_ELT(f,n) ) +#define TRX_4F(f,n) (GLfloat)( PTR_ELT(f,n) ) +#define TRX_UB(ub, f,n) ub = BYTE_TO_UBYTE( PTR_ELT(f,n) ) +#define TRX_UI(f,n) (PTR_ELT(f,n) < 0 ? 0 : (GLuint) PTR_ELT(f,n)) + + +#define SZ 4 +#define INIT init_trans_4_GLbyte_elt +#define DEST_4F trans_4_GLbyte_4f_elt +#define DEST_4UB trans_4_GLbyte_4ub_elt +#include "math/m_trans_tmp.h" + +#define SZ 3 +#define INIT init_trans_3_GLbyte_elt +#define DEST_4F trans_3_GLbyte_4f_elt +#define DEST_4UB trans_3_GLbyte_4ub_elt +#define DEST_3F trans_3_GLbyte_3f_elt +#include "math/m_trans_tmp.h" + +#define SZ 2 +#define INIT init_trans_2_GLbyte_elt +#define DEST_4F trans_2_GLbyte_4f_elt +#include "math/m_trans_tmp.h" + +#define SZ 1 +#define INIT init_trans_1_GLbyte_elt +#define DEST_4F trans_1_GLbyte_4f_elt +#define DEST_1UB trans_1_GLbyte_1ub_elt +#define DEST_1UI trans_1_GLbyte_1ui_elt +#include "math/m_trans_tmp.h" + +#undef SRC +#undef TRX_3F +#undef TRX_4F +#undef TRX_UB +#undef TRX_UI +#undef SRC_IDX + +/* GL_UNSIGNED_BYTE + */ +#define SRC GLubyte +#define SRC_IDX TYPE_IDX(GL_UNSIGNED_BYTE) +#define TRX_3F(f,n) /* unused */ +#define TRX_4F(f,n) /* unused */ +#define TRX_UB(ub, f,n) ub = PTR_ELT(f,n) +#define TRX_UI(f,n) (GLuint)PTR_ELT(f,n) + +/* 4ub->4ub handled in special case below. + */ + +#define SZ 3 +#define INIT init_trans_3_GLubyte_elt +#define DEST_4UB trans_3_GLubyte_4ub_elt +#include "math/m_trans_tmp.h" + + +#define SZ 1 +#define INIT init_trans_1_GLubyte_elt +#define DEST_1UI trans_1_GLubyte_1ui_elt +#define DEST_1UB trans_1_GLubyte_1ub_elt +#include "math/m_trans_tmp.h" + +#undef SRC +#undef SRC_IDX +#undef TRX_3F +#undef TRX_4F +#undef TRX_UB +#undef TRX_UI + + +/* GL_SHORT + */ +#define SRC GLshort +#define SRC_IDX TYPE_IDX(GL_SHORT) +#define TRX_3F(f,n) SHORT_TO_FLOAT( PTR_ELT(f,n) ) +#define TRX_4F(f,n) (GLfloat)( PTR_ELT(f,n) ) +#define TRX_UB(ub, f,n) ub = SHORT_TO_UBYTE(PTR_ELT(f,n)) +#define TRX_UI(f,n) (PTR_ELT(f,n) < 0 ? 0 : (GLuint) PTR_ELT(f,n)) + + +#define SZ 4 +#define INIT init_trans_4_GLshort_elt +#define DEST_4F trans_4_GLshort_4f_elt +#define DEST_4UB trans_4_GLshort_4ub_elt +#include "math/m_trans_tmp.h" + +#define SZ 3 +#define INIT init_trans_3_GLshort_elt +#define DEST_4F trans_3_GLshort_4f_elt +#define DEST_4UB trans_3_GLshort_4ub_elt +#define DEST_3F trans_3_GLshort_3f_elt +#include "math/m_trans_tmp.h" + +#define SZ 2 +#define INIT init_trans_2_GLshort_elt +#define DEST_4F trans_2_GLshort_4f_elt +#include "math/m_trans_tmp.h" + +#define SZ 1 +#define INIT init_trans_1_GLshort_elt +#define DEST_4F trans_1_GLshort_4f_elt +#define DEST_1UB trans_1_GLshort_1ub_elt +#define DEST_1UI trans_1_GLshort_1ui_elt +#include "math/m_trans_tmp.h" + + +#undef SRC +#undef SRC_IDX +#undef TRX_3F +#undef TRX_4F +#undef TRX_UB +#undef TRX_UI + + +/* GL_UNSIGNED_SHORT + */ +#define SRC GLushort +#define SRC_IDX TYPE_IDX(GL_UNSIGNED_SHORT) +#define TRX_3F(f,n) USHORT_TO_FLOAT( PTR_ELT(f,n) ) +#define TRX_4F(f,n) (GLfloat)( PTR_ELT(f,n) ) +#define TRX_UB(ub,f,n) ub = (GLubyte) (PTR_ELT(f,n) >> 8) +#define TRX_UI(f,n) (GLuint) PTR_ELT(f,n) + + +#define SZ 4 +#define INIT init_trans_4_GLushort_elt +#define DEST_4F trans_4_GLushort_4f_elt +#define DEST_4UB trans_4_GLushort_4ub_elt +#include "math/m_trans_tmp.h" + +#define SZ 3 +#define INIT init_trans_3_GLushort_elt +#define DEST_4F trans_3_GLushort_4f_elt +#define DEST_4UB trans_3_GLushort_4ub_elt +#define DEST_3F trans_3_GLushort_3f_elt +#include "math/m_trans_tmp.h" + +#define SZ 2 +#define INIT init_trans_2_GLushort_elt +#define DEST_4F trans_2_GLushort_4f_elt +#include "math/m_trans_tmp.h" + +#define SZ 1 +#define INIT init_trans_1_GLushort_elt +#define DEST_4F trans_1_GLushort_4f_elt +#define DEST_1UB trans_1_GLushort_1ub_elt +#define DEST_1UI trans_1_GLushort_1ui_elt +#include "math/m_trans_tmp.h" + +#undef SRC +#undef SRC_IDX +#undef TRX_3F +#undef TRX_4F +#undef TRX_UB +#undef TRX_UI + + +/* GL_INT + */ +#define SRC GLint +#define SRC_IDX TYPE_IDX(GL_INT) +#define TRX_3F(f,n) INT_TO_FLOAT( PTR_ELT(f,n) ) +#define TRX_4F(f,n) (GLfloat)( PTR_ELT(f,n) ) +#define TRX_UB(ub, f,n) ub = INT_TO_UBYTE(PTR_ELT(f,n)) +#define TRX_UI(f,n) (PTR_ELT(f,n) < 0 ? 0 : (GLuint) PTR_ELT(f,n)) + + +#define SZ 4 +#define INIT init_trans_4_GLint_elt +#define DEST_4F trans_4_GLint_4f_elt +#define DEST_4UB trans_4_GLint_4ub_elt +#include "math/m_trans_tmp.h" + +#define SZ 3 +#define INIT init_trans_3_GLint_elt +#define DEST_4F trans_3_GLint_4f_elt +#define DEST_4UB trans_3_GLint_4ub_elt +#define DEST_3F trans_3_GLint_3f_elt +#include "math/m_trans_tmp.h" + +#define SZ 2 +#define INIT init_trans_2_GLint_elt +#define DEST_4F trans_2_GLint_4f_elt +#include "math/m_trans_tmp.h" + +#define SZ 1 +#define INIT init_trans_1_GLint_elt +#define DEST_4F trans_1_GLint_4f_elt +#define DEST_1UB trans_1_GLint_1ub_elt +#define DEST_1UI trans_1_GLint_1ui_elt +#include "math/m_trans_tmp.h" + + +#undef SRC +#undef SRC_IDX +#undef TRX_3F +#undef TRX_4F +#undef TRX_UB +#undef TRX_UI + + +/* GL_UNSIGNED_INT + */ +#define SRC GLuint +#define SRC_IDX TYPE_IDX(GL_UNSIGNED_INT) +#define TRX_3F(f,n) UINT_TO_FLOAT( PTR_ELT(f,n) ) +#define TRX_4F(f,n) (GLfloat)( PTR_ELT(f,n) ) +#define TRX_UB(ub, f,n) ub = (GLubyte) (PTR_ELT(f,n) >> 24) +#define TRX_UI(f,n) PTR_ELT(f,n) + + +#define SZ 4 +#define INIT init_trans_4_GLuint_elt +#define DEST_4F trans_4_GLuint_4f_elt +#define DEST_4UB trans_4_GLuint_4ub_elt +#include "math/m_trans_tmp.h" + +#define SZ 3 +#define INIT init_trans_3_GLuint_elt +#define DEST_4F trans_3_GLuint_4f_elt +#define DEST_4UB trans_3_GLuint_4ub_elt +#define DEST_3F trans_3_GLuint_3f_elt +#include "math/m_trans_tmp.h" + +#define SZ 2 +#define INIT init_trans_2_GLuint_elt +#define DEST_4F trans_2_GLuint_4f_elt +#include "math/m_trans_tmp.h" + +#define SZ 1 +#define INIT init_trans_1_GLuint_elt +#define DEST_4F trans_1_GLuint_4f_elt +#define DEST_1UB trans_1_GLuint_1ub_elt +#define DEST_1UI trans_1_GLuint_1ui_elt +#include "math/m_trans_tmp.h" + +#undef SRC +#undef SRC_IDX +#undef TRX_3F +#undef TRX_4F +#undef TRX_UB +#undef TRX_UI + + +/* GL_DOUBLE + */ +#define SRC GLdouble +#define SRC_IDX TYPE_IDX(GL_DOUBLE) +#define TRX_3F(f,n) PTR_ELT(f,n) +#define TRX_4F(f,n) PTR_ELT(f,n) +#define TRX_UB(ub,f,n) FLOAT_COLOR_TO_CHAN(ub, PTR_ELT(f,n)) +#define TRX_UI(f,n) (GLuint) (GLint) PTR_ELT(f,n) +#define TRX_1F(f,n) PTR_ELT(f,n) + + +#define SZ 4 +#define INIT init_trans_4_GLdouble_elt +#define DEST_4F trans_4_GLdouble_4f_elt +#define DEST_4UB trans_4_GLdouble_4ub_elt +#include "math/m_trans_tmp.h" + +#define SZ 3 +#define INIT init_trans_3_GLdouble_elt +#define DEST_4F trans_3_GLdouble_4f_elt +#define DEST_4UB trans_3_GLdouble_4ub_elt +#define DEST_3F trans_3_GLdouble_3f_elt +#include "math/m_trans_tmp.h" + +#define SZ 2 +#define INIT init_trans_2_GLdouble_elt +#define DEST_4F trans_2_GLdouble_4f_elt +#include "math/m_trans_tmp.h" + +#define SZ 1 +#define INIT init_trans_1_GLdouble_elt +#define DEST_4F trans_1_GLdouble_4f_elt +#define DEST_1UB trans_1_GLdouble_1ub_elt +#define DEST_1UI trans_1_GLdouble_1ui_elt +#define DEST_1F trans_1_GLdouble_1f_elt +#include "math/m_trans_tmp.h" + +#undef SRC +#undef SRC_IDX + +/* GL_FLOAT + */ +#define SRC GLfloat +#define SRC_IDX TYPE_IDX(GL_FLOAT) +#define SZ 4 +#define INIT init_trans_4_GLfloat_elt +#define DEST_4UB trans_4_GLfloat_4ub_elt +#define DEST_4F trans_4_GLfloat_4f_elt +#include "math/m_trans_tmp.h" + +#define SZ 3 +#define INIT init_trans_3_GLfloat_elt +#define DEST_4F trans_3_GLfloat_4f_elt +#define DEST_4UB trans_3_GLfloat_4ub_elt +#define DEST_3F trans_3_GLfloat_3f_elt +#include "math/m_trans_tmp.h" + +#define SZ 2 +#define INIT init_trans_2_GLfloat_elt +#define DEST_4F trans_2_GLfloat_4f_elt +#include "math/m_trans_tmp.h" + +#define SZ 1 +#define INIT init_trans_1_GLfloat_elt +#define DEST_4F trans_1_GLfloat_3f_elt +#define DEST_1UB trans_1_GLfloat_1ub_elt +#define DEST_1UI trans_1_GLfloat_1ui_elt +#define DEST_1F trans_1_GLfloat_1f_elt +#include "math/m_trans_tmp.h" + +#undef SRC +#undef SRC_IDX +#undef TRX_3F +#undef TRX_4F +#undef TRX_UB +#undef TRX_UI + + +static void trans_4_GLubyte_4ub(GLubyte (*t)[4], + CONST void *Ptr, + GLuint stride, + ARGS ) +{ + const GLubyte *f = (GLubyte *) Ptr + SRC_START * stride; + const GLubyte *first = f; + GLuint i; + (void) start; + if (((((long) f | (long) stride)) & 3L) == 0L) { + /* Aligned. + */ + for (i = DST_START ; i < n ; i++, NEXT_F) { + CHECK { + NEXT_F2; + COPY_4UBV( t[i], f ); + } + } + } else { + for (i = DST_START ; i < n ; i++, NEXT_F) { + CHECK { + NEXT_F2; + t[i][0] = f[0]; + t[i][1] = f[1]; + t[i][2] = f[2]; + t[i][3] = f[3]; + } + } + } +} + + +static void init_translate_elt(void) +{ + MEMSET( TAB(_1ui), 0, sizeof(TAB(_1ui)) ); + MEMSET( TAB(_1ub), 0, sizeof(TAB(_1ub)) ); + MEMSET( TAB(_3f), 0, sizeof(TAB(_3f)) ); + MEMSET( TAB(_4ub), 0, sizeof(TAB(_4ub)) ); + MEMSET( TAB(_4f), 0, sizeof(TAB(_4f)) ); + + TAB(_4ub)[4][TYPE_IDX(GL_UNSIGNED_BYTE)] = trans_4_GLubyte_4ub; + + init_trans_4_GLbyte_elt(); + init_trans_3_GLbyte_elt(); + init_trans_2_GLbyte_elt(); + init_trans_1_GLbyte_elt(); + init_trans_1_GLubyte_elt(); + init_trans_3_GLubyte_elt(); + init_trans_4_GLshort_elt(); + init_trans_3_GLshort_elt(); + init_trans_2_GLshort_elt(); + init_trans_1_GLshort_elt(); + init_trans_4_GLushort_elt(); + init_trans_3_GLushort_elt(); + init_trans_2_GLushort_elt(); + init_trans_1_GLushort_elt(); + init_trans_4_GLint_elt(); + init_trans_3_GLint_elt(); + init_trans_2_GLint_elt(); + init_trans_1_GLint_elt(); + init_trans_4_GLuint_elt(); + init_trans_3_GLuint_elt(); + init_trans_2_GLuint_elt(); + init_trans_1_GLuint_elt(); + init_trans_4_GLdouble_elt(); + init_trans_3_GLdouble_elt(); + init_trans_2_GLdouble_elt(); + init_trans_1_GLdouble_elt(); + init_trans_4_GLfloat_elt(); + init_trans_3_GLfloat_elt(); + init_trans_2_GLfloat_elt(); + init_trans_1_GLfloat_elt(); +} + + +#undef TAB +#undef CLASS +#undef ARGS +#undef CHECK +#undef START + + + + +void _tnl_imm_elt_init( void ) +{ + init_translate_elt(); +} + + +static void _tnl_trans_elt_1f(GLfloat *to, + const struct gl_client_array *from, + GLuint *flags, + GLuint *elts, + GLuint match, + GLuint start, + GLuint n ) +{ + _tnl_trans_elt_1f_tab[TYPE_IDX(from->Type)]( to, + from->Ptr, + from->StrideB, + flags, + elts, + match, + start, + n ); + +} + +static void _tnl_trans_elt_1ui(GLuint *to, + const struct gl_client_array *from, + GLuint *flags, + GLuint *elts, + GLuint match, + GLuint start, + GLuint n ) +{ + _tnl_trans_elt_1ui_tab[TYPE_IDX(from->Type)]( to, + from->Ptr, + from->StrideB, + flags, + elts, + match, + start, + n ); + +} + + +static void _tnl_trans_elt_1ub(GLubyte *to, + const struct gl_client_array *from, + GLuint *flags, + GLuint *elts, + GLuint match, + GLuint start, + GLuint n ) +{ + _tnl_trans_elt_1ub_tab[TYPE_IDX(from->Type)]( to, + from->Ptr, + from->StrideB, + flags, + elts, + match, + start, + n ); + +} + + +static void _tnl_trans_elt_4ub(GLubyte (*to)[4], + const struct gl_client_array *from, + GLuint *flags, + GLuint *elts, + GLuint match, + GLuint start, + GLuint n ) +{ + _tnl_trans_elt_4ub_tab[from->Size][TYPE_IDX(from->Type)]( to, + from->Ptr, + from->StrideB, + flags, + elts, + match, + start, + n ); + +} + +static void _tnl_trans_elt_4f(GLfloat (*to)[4], + const struct gl_client_array *from, + GLuint *flags, + GLuint *elts, + GLuint match, + GLuint start, + GLuint n ) +{ + _tnl_trans_elt_4f_tab[from->Size][TYPE_IDX(from->Type)]( to, + from->Ptr, + from->StrideB, + flags, + elts, + match, + start, + n ); + +} + +static void _tnl_trans_elt_3f(GLfloat (*to)[3], + const struct gl_client_array *from, + GLuint *flags, + GLuint *elts, + GLuint match, + GLuint start, + GLuint n ) +{ + _tnl_trans_elt_3f_tab[TYPE_IDX(from->Type)]( to, + from->Ptr, + from->StrideB, + flags, + elts, + match, + start, + n ); +} + + + + +/* Batch function to translate away all the array elements in the + * input buffer prior to transform. Done only the first time a vertex + * buffer is executed or compiled. + * + * KW: Have to do this after each glEnd if arrays aren't locked. + */ +void _tnl_translate_array_elts( GLcontext *ctx, struct immediate *IM, + GLuint start, GLuint count ) +{ + GLuint *flags = IM->Flag; + GLuint *elts = IM->Elt; + GLuint translate = ctx->Array._Enabled; + GLuint i; + + if (MESA_VERBOSE&VERBOSE_IMMEDIATE) + fprintf(stderr, "exec_array_elements %d .. %d\n", start, count); + + if (translate & VERT_OBJ) { + _tnl_trans_elt_4f( IM->Obj, + &ctx->Array.Vertex, + flags, elts, (VERT_ELT|VERT_OBJ), + start, count); + + if (ctx->Array.Vertex.Size == 4) + translate |= VERT_OBJ_234; + else if (ctx->Array.Vertex.Size == 3) + translate |= VERT_OBJ_23; + } + + + if (translate & VERT_NORM) + _tnl_trans_elt_3f( IM->Normal, + &ctx->Array.Normal, + flags, elts, (VERT_ELT|VERT_NORM), + start, count); + + if (translate & VERT_EDGE) + _tnl_trans_elt_1ub( IM->EdgeFlag, + &ctx->Array.EdgeFlag, + flags, elts, (VERT_ELT|VERT_EDGE), + start, count); + + if (translate & VERT_RGBA) + _tnl_trans_elt_4ub( IM->Color, + &ctx->Array.Color, + flags, elts, (VERT_ELT|VERT_RGBA), + start, count); + + + if (translate & VERT_SPEC_RGB) + _tnl_trans_elt_4ub( IM->SecondaryColor, + &ctx->Array.SecondaryColor, + flags, elts, (VERT_ELT|VERT_SPEC_RGB), + start, count); + + if (translate & VERT_FOG_COORD) + _tnl_trans_elt_1f( IM->FogCoord, + &ctx->Array.FogCoord, + flags, elts, (VERT_ELT|VERT_FOG_COORD), + start, count); + + if (translate & VERT_INDEX) + _tnl_trans_elt_1ui( IM->Index, + &ctx->Array.Index, + flags, elts, (VERT_ELT|VERT_INDEX), + start, count); + + if (translate & VERT_TEX_ANY) { + for (i = 0 ; i < ctx->Const.MaxTextureUnits ; i++) + if (translate & VERT_TEX(i)) { + _tnl_trans_elt_4f( IM->TexCoord[i], + &ctx->Array.TexCoord[i], + flags, elts, (VERT_ELT|VERT_TEX(i)), + start, count); + + if (ctx->Array.TexCoord[i].Size == 4) + IM->TexSize |= TEX_SIZE_4(i); + else if (ctx->Array.TexCoord[i].Size == 3) + IM->TexSize |= TEX_SIZE_3(i); + } + } + + for (i = start ; i < count ; i++) + if (flags[i] & VERT_ELT) flags[i] |= translate; + + IM->CopyOrFlag |= translate; +} + + diff --git a/src/mesa/tnl/t_imm_elt.h b/src/mesa/tnl/t_imm_elt.h new file mode 100644 index 00000000000..180b75fbee8 --- /dev/null +++ b/src/mesa/tnl/t_imm_elt.h @@ -0,0 +1,46 @@ +/* $Id: t_imm_elt.h,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 <[email protected]> + */ + + +#ifndef _T_IMM_ELT_H_ +#define _T_IMM_ELT_H_ + +#include "mtypes.h" +#include "t_context.h" + + +extern void _tnl_imm_elt_init( void ); + +extern void _tnl_translate_array_elts( GLcontext *ctx, + struct immediate *IM, + GLuint start, + GLuint end ); + + +#endif diff --git a/src/mesa/tnl/t_imm_eval.c b/src/mesa/tnl/t_imm_eval.c new file mode 100644 index 00000000000..ed8af649aad --- /dev/null +++ b/src/mesa/tnl/t_imm_eval.c @@ -0,0 +1,623 @@ +/* $Id: t_imm_eval.c,v 1.1 2000/12/26 05:09:32 keithw Exp $ */ + +/* + * Mesa 3-D graphics library + * Version: 3.5 + * + * Copyright (C) 1999-2000 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. + */ + + +#include "glheader.h" +#include "colormac.h" +#include "context.h" +#include "macros.h" +#include "mem.h" +#include "mmath.h" +#include "mtypes.h" +#include "math/m_eval.h" + +#include "t_context.h" +#include "t_imm_eval.h" +#include "t_imm_exec.h" +#include "t_imm_fixup.h" + + +static void eval_points1( GLfloat outcoord[][4], + GLfloat coord[][4], + const GLuint *flags, + GLfloat du, GLfloat u1 ) +{ + GLuint i; + for (i = 0 ; !(flags[i] & VERT_END_VB) ; i++) + if (flags[i] & VERT_EVAL_ANY) { + outcoord[i][0] = coord[i][0]; + outcoord[i][1] = coord[i][1]; + if (flags[i] & VERT_EVAL_P1) + outcoord[i][0] = coord[i][0] * du + u1; + } +} + +static void eval_points2( GLfloat outcoord[][4], + GLfloat coord[][4], + const GLuint *flags, + GLfloat du, GLfloat u1, + GLfloat dv, GLfloat v1 ) +{ + GLuint i; + for (i = 0 ; !(flags[i] & VERT_END_VB) ; i++) { + if (flags[i] & VERT_EVAL_ANY) { + outcoord[i][0] = coord[i][0]; + outcoord[i][1] = coord[i][1]; + if (flags[i] & VERT_EVAL_P2) { + outcoord[i][0] = coord[i][0] * du + u1; + outcoord[i][1] = coord[i][1] * dv + v1; + } + } + } +} + +static const GLubyte dirty_flags[5] = { + 0, /* not possible */ + VEC_DIRTY_0, + VEC_DIRTY_1, + VEC_DIRTY_2, + VEC_DIRTY_3 +}; + + +static void eval1_4f( GLvector4f *dest, + GLfloat coord[][4], + const GLuint *flags, + GLuint dimension, + struct gl_1d_map *map ) +{ + const GLfloat u1 = map->u1; + const GLfloat du = map->du; + GLfloat (*to)[4] = dest->data; + GLuint i; + + for (i = 0 ; !(flags[i] & VERT_END_VB) ; i++) + if (flags[i] & (VERT_EVAL_C1|VERT_EVAL_P1)) { + GLfloat u = (coord[i][0] - u1) * du; + ASSIGN_4V(to[i], 0,0,0,1); + _math_horner_bezier_curve(map->Points, to[i], u, + dimension, map->Order); + } + + dest->size = MAX2(dest->size, dimension); + dest->flags |= dirty_flags[dimension]; +} + + +static void eval1_1ui( GLvector1ui *dest, + GLfloat coord[][4], + const GLuint *flags, + struct gl_1d_map *map ) +{ + const GLfloat u1 = map->u1; + const GLfloat du = map->du; + GLuint *to = dest->data; + GLuint i; + + for (i = 0 ; !(flags[i] & VERT_END_VB) ; i++) + if (flags[i] & (VERT_EVAL_C1|VERT_EVAL_P1)) { + GLfloat u = (coord[i][0] - u1) * du; + GLfloat tmp; + _math_horner_bezier_curve(map->Points, &tmp, u, 1, map->Order); + to[i] = (GLuint) (GLint) tmp; + } + +} + +static void eval1_norm( GLvector3f *dest, + GLfloat coord[][4], + const GLuint *flags, + struct gl_1d_map *map ) +{ + const GLfloat u1 = map->u1; + const GLfloat du = map->du; + GLfloat (*to)[3] = dest->data; + GLuint i; + + for (i = 0 ; !(flags[i] & VERT_END_VB) ; i++) + if (flags[i] & (VERT_EVAL_C1|VERT_EVAL_P1)) { + GLfloat u = (coord[i][0] - u1) * du; + _math_horner_bezier_curve(map->Points, to[i], u, 3, map->Order); + } +} + +static void eval1_color( GLvector4ub *dest, + GLfloat coord[][4], + const GLuint *flags, + struct gl_1d_map *map ) +{ + const GLfloat u1 = map->u1; + const GLfloat du = map->du; + GLubyte (*to)[4] = dest->data; + GLuint i; + + for (i = 0 ; !(flags[i] & VERT_END_VB) ; i++) + if (flags[i] & (VERT_EVAL_C1|VERT_EVAL_P1)) { + GLfloat u = (coord[i][0] - u1) * du; + GLfloat fcolor[4]; + _math_horner_bezier_curve(map->Points, fcolor, u, 4, map->Order); + FLOAT_RGBA_TO_CHAN_RGBA(to[i], fcolor); + } +} + + + + +static void eval2_obj_norm( GLvector4f *obj_ptr, + GLvector3f *norm_ptr, + GLfloat coord[][4], + GLuint *flags, + GLuint dimension, + struct gl_2d_map *map ) +{ + const GLfloat u1 = map->u1; + const GLfloat du = map->du; + const GLfloat v1 = map->v1; + const GLfloat dv = map->dv; + GLfloat (*obj)[4] = obj_ptr->data; + GLfloat (*normal)[3] = norm_ptr->data; + GLuint i; + + for (i = 0 ; !(flags[i] & VERT_END_VB) ; i++) + if (flags[i] & (VERT_EVAL_C2|VERT_EVAL_P2)) { + GLfloat u = (coord[i][0] - u1) * du; + GLfloat v = (coord[i][1] - v1) * dv; + GLfloat du[4], dv[4]; + + ASSIGN_4V(obj[i], 0,0,0,1); + _math_de_casteljau_surf(map->Points, obj[i], du, dv, u, v, dimension, + map->Uorder, map->Vorder); + + CROSS3(normal[i], du, dv); + NORMALIZE_3FV(normal[i]); + } + + obj_ptr->size = MAX2(obj_ptr->size, dimension); + obj_ptr->flags |= dirty_flags[dimension]; +} + + +static void eval2_4f( GLvector4f *dest, + GLfloat coord[][4], + const GLuint *flags, + GLuint dimension, + struct gl_2d_map *map ) +{ + const GLfloat u1 = map->u1; + const GLfloat du = map->du; + const GLfloat v1 = map->v1; + const GLfloat dv = map->dv; + GLfloat (*to)[4] = dest->data; + GLuint i; + + for (i = 0 ; !(flags[i] & VERT_END_VB) ; i++) + if (flags[i] & (VERT_EVAL_C2|VERT_EVAL_P2)) { + GLfloat u = (coord[i][0] - u1) * du; + GLfloat v = (coord[i][1] - v1) * dv; + _math_horner_bezier_surf(map->Points, to[i], u, v, dimension, + map->Uorder, map->Vorder); + } + + dest->size = MAX2(dest->size, dimension); + dest->flags |= dirty_flags[dimension]; +} + + +static void eval2_norm( GLvector3f *dest, + GLfloat coord[][4], + GLuint *flags, + struct gl_2d_map *map ) +{ + const GLfloat u1 = map->u1; + const GLfloat du = map->du; + const GLfloat v1 = map->v1; + const GLfloat dv = map->dv; + GLfloat (*to)[3] = dest->data; + GLuint i; + + for (i = 0 ; !(flags[i] & VERT_END_VB) ; i++) + if (flags[i] & (VERT_EVAL_C2|VERT_EVAL_P2)) { + GLfloat u = (coord[i][0] - u1) * du; + GLfloat v = (coord[i][1] - v1) * dv; + _math_horner_bezier_surf(map->Points, to[i], u, v, 3, + map->Uorder, map->Vorder); + } + +} + + +static void eval2_1ui( GLvector1ui *dest, + GLfloat coord[][4], + const GLuint *flags, + struct gl_2d_map *map ) +{ + const GLfloat u1 = map->u1; + const GLfloat du = map->du; + const GLfloat v1 = map->v1; + const GLfloat dv = map->dv; + GLuint *to = dest->data; + GLuint i; + + for (i = 0 ; !(flags[i] & VERT_END_VB) ; i++) + if (flags[i] & (VERT_EVAL_C2|VERT_EVAL_P2)) { + GLfloat u = (coord[i][0] - u1) * du; + GLfloat v = (coord[i][1] - v1) * dv; + GLfloat tmp; + _math_horner_bezier_surf(map->Points, &tmp, u, v, 1, + map->Uorder, map->Vorder); + + to[i] = (GLuint) (GLint) tmp; + } +} + + + +static void eval2_color( GLvector4ub *dest, + GLfloat coord[][4], + GLuint *flags, + struct gl_2d_map *map ) +{ + const GLfloat u1 = map->u1; + const GLfloat du = map->du; + const GLfloat v1 = map->v1; + const GLfloat dv = map->dv; + GLubyte (*to)[4] = dest->data; + GLuint i; + + for (i = 0 ; !(flags[i] & VERT_END_VB) ; i++) + if (flags[i] & (VERT_EVAL_C2|VERT_EVAL_P2)) { + GLfloat u = (coord[i][0] - u1) * du; + GLfloat v = (coord[i][1] - v1) * dv; + GLfloat fcolor[4]; + _math_horner_bezier_surf(map->Points, fcolor, u, v, 4, + map->Uorder, map->Vorder); + FLOAT_RGBA_TO_CHAN_RGBA(to[i], fcolor); + } + +} + + + +static void copy_4f( GLfloat to[][4], GLfloat from[][4], GLuint count ) +{ + MEMCPY( to, from, count * sizeof(to[0])); +} + +static void copy_3f( GLfloat to[][3], GLfloat from[][3], GLuint count ) +{ + MEMCPY( to, from, (count) * sizeof(to[0])); +} + +static void copy_4ub( GLubyte to[][4], GLubyte from[][4], GLuint count ) +{ + MEMCPY( to, from, (count) * sizeof(to[0])); +} + +static void copy_1ui( GLuint to[], GLuint from[], GLuint count ) +{ + MEMCPY( to, from, (count) * sizeof(to[0])); +} + + + +/* Translate eval enabled flags to VERT_* flags. + */ +static void update_eval( GLcontext *ctx ) +{ + TNLcontext *tnl = TNL_CONTEXT(ctx); + GLuint eval1 = 0, eval2 = 0; + + if (ctx->Eval.Map1Index) + eval1 |= VERT_INDEX; + + if (ctx->Eval.Map2Index) + eval2 |= VERT_INDEX; + + if (ctx->Eval.Map1Color4) + eval1 |= VERT_RGBA; + + if (ctx->Eval.Map2Color4) + eval2 |= VERT_RGBA; + + if (ctx->Eval.Map1Normal) + eval1 |= VERT_NORM; + + if (ctx->Eval.Map2Normal) + eval2 |= VERT_NORM; + + if (ctx->Eval.Map1TextureCoord4 || + ctx->Eval.Map1TextureCoord3 || + ctx->Eval.Map1TextureCoord2 || + ctx->Eval.Map1TextureCoord1) + eval1 |= VERT_TEX0; + + if (ctx->Eval.Map2TextureCoord4 || + ctx->Eval.Map2TextureCoord3 || + ctx->Eval.Map2TextureCoord2 || + ctx->Eval.Map2TextureCoord1) + eval2 |= VERT_TEX0; + + if (ctx->Eval.Map1Vertex4) + eval1 |= VERT_OBJ_234; + + if (ctx->Eval.Map1Vertex3) + eval1 |= VERT_OBJ_23; + + if (ctx->Eval.Map2Vertex4) { + if (ctx->Eval.AutoNormal) + eval2 |= VERT_OBJ_234 | VERT_NORM; + else + eval2 |= VERT_OBJ_234; + } + else if (ctx->Eval.Map2Vertex3) { + if (ctx->Eval.AutoNormal) + eval2 |= VERT_OBJ_23 | VERT_NORM; + else + eval2 |= VERT_OBJ_23; + } + + tnl->eval.EvalMap1Flags = eval1; + tnl->eval.EvalMap2Flags = eval2; + tnl->eval.EvalNewState = 0; +} + + +/* This looks a lot like a pipeline stage, but for various reasons is + * better handled outside the pipeline, and considered the final stage + * of fixing up an immediate struct for execution. + * + * Really want to cache the results of this function in display lists, + * at least for EvalMesh commands. + */ +void _tnl_eval_vb( GLcontext *ctx, + GLfloat (*coord)[4], + GLuint orflag, + GLuint andflag ) +{ + TNLcontext *tnl = TNL_CONTEXT(ctx); + struct vertex_arrays *tmp = &tnl->imm_inputs; + struct tnl_eval_store *store = &tnl->eval; + GLuint *flags = tnl->vb.Flag; + GLuint count = tnl->vb.Count; + GLuint any_eval1 = orflag & (VERT_EVAL_C1|VERT_EVAL_P1); + GLuint any_eval2 = orflag & (VERT_EVAL_C2|VERT_EVAL_P2); + GLuint all_eval = andflag & VERT_EVAL_ANY; /* may have false negatives */ + GLuint req = 0; + GLuint purge_flags = 0; + + if (tnl->eval.EvalNewState & _NEW_EVAL) + update_eval( ctx ); + + /* Handle the degenerate cases. + */ + if (any_eval1 && !ctx->Eval.Map1Vertex4 && !ctx->Eval.Map1Vertex3) + purge_flags = (VERT_EVAL_P1|VERT_EVAL_C1); + + if (any_eval2 && !ctx->Eval.Map2Vertex4 && !ctx->Eval.Map2Vertex3) + purge_flags |= (VERT_EVAL_P1|VERT_EVAL_C1); + + if (any_eval1) + req |= tnl->pipeline.inputs & tnl->eval.EvalMap1Flags; + + if (any_eval2) + req |= tnl->pipeline.inputs & tnl->eval.EvalMap2Flags; + + + /* Translate points into coords. Use store->Obj to hold the + * new data. + */ + if (any_eval1 && (orflag & VERT_EVAL_P1)) + { + eval_points1( store->Obj, coord, flags, + ctx->Eval.MapGrid1du, + ctx->Eval.MapGrid1u1); + + coord = store->Obj; + } + + if (any_eval2 && (orflag & VERT_EVAL_P2)) + { + eval_points2( store->Obj, coord, flags, + ctx->Eval.MapGrid2du, + ctx->Eval.MapGrid2u1, + ctx->Eval.MapGrid2dv, + ctx->Eval.MapGrid2v1 ); + + coord = store->Obj; + } + + + /* Perform the evaluations on active data elements. + */ + if (req & VERT_INDEX) + { + if (!all_eval) + copy_1ui( store->Index, tmp->Index.data, count ); + + tmp->Index.data = store->Index; + tmp->Index.start = store->Index; + + if (ctx->Eval.Map1Index && any_eval1) + eval1_1ui( &tmp->Index, coord, flags, &ctx->EvalMap.Map1Index ); + + if (ctx->Eval.Map2Index && any_eval2) + eval2_1ui( &tmp->Index, coord, flags, &ctx->EvalMap.Map2Index ); + + } + + if (req & VERT_RGBA) + { + if (!all_eval) + copy_4ub( store->Color, tmp->Color.data, count ); + + tmp->Color.data = store->Color; + tmp->Color.start = (GLubyte *)store->Color; + + if (ctx->Eval.Map1Color4 && any_eval1) + eval1_color( &tmp->Color, coord, flags, &ctx->EvalMap.Map1Color4 ); + + if (ctx->Eval.Map2Color4 && any_eval2) + eval2_color( &tmp->Color, coord, flags, &ctx->EvalMap.Map2Color4 ); + } + + + if (req & VERT_TEX(0)) + { + if (!all_eval) + copy_4f( store->TexCoord, tmp->TexCoord[0].data, count ); + else + tmp->TexCoord[0].size = 0; + + tmp->TexCoord[0].data = store->TexCoord; + tmp->TexCoord[0].start = (GLfloat *)store->TexCoord; + + if (any_eval1) { + if (ctx->Eval.Map1TextureCoord4) { + eval1_4f( &tmp->TexCoord[0], coord, flags, 4, + &ctx->EvalMap.Map1Texture4 ); + } + else if (ctx->Eval.Map1TextureCoord3) { + eval1_4f( &tmp->TexCoord[0], coord, flags, 3, + &ctx->EvalMap.Map1Texture3 ); + } + else if (ctx->Eval.Map1TextureCoord2) { + eval1_4f( &tmp->TexCoord[0], coord, flags, 2, + &ctx->EvalMap.Map1Texture2 ); + } + else if (ctx->Eval.Map1TextureCoord1) { + eval1_4f( &tmp->TexCoord[0], coord, flags, 1, + &ctx->EvalMap.Map1Texture1 ); + } + } + + if (any_eval2) { + if (ctx->Eval.Map2TextureCoord4) { + eval2_4f( &tmp->TexCoord[0], coord, flags, 4, + &ctx->EvalMap.Map2Texture4 ); + } + else if (ctx->Eval.Map2TextureCoord3) { + eval2_4f( &tmp->TexCoord[0], coord, flags, 3, + &ctx->EvalMap.Map2Texture3 ); + } + else if (ctx->Eval.Map2TextureCoord2) { + eval2_4f( &tmp->TexCoord[0], coord, flags, 2, + &ctx->EvalMap.Map2Texture2 ); + } + else if (ctx->Eval.Map2TextureCoord1) { + eval2_4f( &tmp->TexCoord[0], coord, flags, 1, + &ctx->EvalMap.Map2Texture1 ); + } + } + } + + + if (req & VERT_NORM) + { + if (!all_eval) + copy_3f( store->Normal, tmp->Normal.data, count ); + + tmp->Normal.data = store->Normal; + tmp->Normal.start = (GLfloat *)store->Normal; + + if (ctx->Eval.Map1Normal && any_eval1) + eval1_norm( &tmp->Normal, coord, flags, + &ctx->EvalMap.Map1Normal ); + + if (ctx->Eval.Map2Normal && any_eval2) + eval2_norm( &tmp->Normal, coord, flags, + &ctx->EvalMap.Map2Normal ); + } + + + + /* In the AutoNormal case, the copy and assignment of tmp->NormalPtr + * are done above. + */ + if (req & VERT_OBJ) + { + if (!all_eval) { + copy_4f( store->Obj, tmp->Obj.data, count ); + } else + tmp->Obj.size = 0; + + tmp->Obj.data = store->Obj; + tmp->Obj.start = (GLfloat *)store->Obj; + + if (any_eval1) { + if (ctx->Eval.Map1Vertex4) { + eval1_4f( &tmp->Obj, coord, flags, 4, + &ctx->EvalMap.Map1Vertex4 ); + } + else if (ctx->Eval.Map1Vertex3) { + eval1_4f( &tmp->Obj, coord, flags, 3, + &ctx->EvalMap.Map1Vertex3 ); + } + } + + if (any_eval2) { + if (ctx->Eval.Map2Vertex4) + { + if (ctx->Eval.AutoNormal && (req & VERT_NORM)) + eval2_obj_norm( &tmp->Obj, &tmp->Normal, coord, flags, 4, + &ctx->EvalMap.Map2Vertex4 ); + else + eval2_4f( &tmp->Obj, coord, flags, 4, + &ctx->EvalMap.Map2Vertex4 ); + } + else if (ctx->Eval.Map2Vertex3) + { + if (ctx->Eval.AutoNormal && (req & VERT_NORM)) + eval2_obj_norm( &tmp->Obj, &tmp->Normal, coord, flags, 3, + &ctx->EvalMap.Map2Vertex3 ); + else + eval2_4f( &tmp->Obj, coord, flags, 3, + &ctx->EvalMap.Map2Vertex3 ); + } + } + } + + + { + GLuint i; + copy_1ui( store->Flag, flags, count ); + tnl->vb.Flag = store->Flag; + + /* This is overkill, but correct as fixup will have copied the + * values to all vertices in the VB - we may be falsely stating + * that some repeated values are new, but doing so is fairly + * harmless. + */ + for (i = 0 ; i < count ; i++) + store->Flag[i] |= req; + } +} + + + + + + + diff --git a/src/mesa/tnl/t_imm_eval.h b/src/mesa/tnl/t_imm_eval.h new file mode 100644 index 00000000000..06a91e0cd5b --- /dev/null +++ b/src/mesa/tnl/t_imm_eval.h @@ -0,0 +1,40 @@ +/* $Id: t_imm_eval.h,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. + */ + + +#ifndef _T_IMM_EVAL_H +#define _T_IMM_EVAL_H + + +#include "mtypes.h" +#include "t_context.h" + +extern void _tnl_eval_init( void ); + +extern void _tnl_eval_vb( GLcontext *ctx, GLfloat (*coord)[4], + GLuint orflag, GLuint andflag ); + +#endif diff --git a/src/mesa/tnl/t_imm_exec.c b/src/mesa/tnl/t_imm_exec.c new file mode 100644 index 00000000000..97f23d86e64 --- /dev/null +++ b/src/mesa/tnl/t_imm_exec.c @@ -0,0 +1,507 @@ +/* $Id: t_imm_exec.c,v 1.1 2000/12/26 05:09:32 keithw Exp $ */ + +/* + * Mesa 3-D graphics library + * Version: 3.5 + * + * Copyright (C) 1999-2000 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. + * + * Authors: + * Keith Whitwell <[email protected]> + */ + + +#include "glheader.h" +#include "context.h" +#include "enums.h" +#include "dlist.h" +#include "macros.h" +#include "mem.h" +#include "mmath.h" +#include "light.h" +#include "state.h" +#include "texture.h" +#include "mtypes.h" + +#include "math/m_matrix.h" +#include "math/m_xform.h" + +#include "t_context.h" +#include "t_array_import.h" +#include "t_imm_alloc.h" +#include "t_imm_api.h" +#include "t_imm_debug.h" +#include "t_imm_dlist.h" +#include "t_imm_eval.h" +#include "t_imm_elt.h" +#include "t_imm_exec.h" +#include "t_imm_fixup.h" +#include "t_pipeline.h" + + + +/* Called to initialize new buffers, and to recycle old ones. + */ +void _tnl_reset_input( GLcontext *ctx, + GLuint start, + GLuint beginstate, + GLuint savedbeginstate ) +{ + struct immediate *IM = TNL_CURRENT_IM(ctx); + + /* Clear the dirty part of the flag array. + */ + if (start < IM->Count+2) + MEMSET(IM->Flag + start, 0, sizeof(GLuint) * (IM->Count+2-start)); + + IM->CopyStart = IM->Start = IM->Count = start; + IM->Primitive[IM->Start] = (ctx->Driver.CurrentExecPrimitive | PRIM_LAST); + IM->LastPrimitive = IM->Start; + IM->BeginState = beginstate; + IM->SavedBeginState = savedbeginstate; + IM->TexSize = 0; + + IM->ArrayEltFlags = ~ctx->Array._Enabled; + IM->ArrayEltIncr = ctx->Array.Vertex.Enabled ? 1 : 0; + IM->ArrayEltFlush = !ctx->Array.LockCount; +} + + + +static void copy_to_current( GLcontext *ctx, struct immediate *IM, + GLuint flag ) +{ + GLuint count = IM->LastData; + + if (MESA_VERBOSE&VERBOSE_IMMEDIATE) + _tnl_print_vert_flags("copy to current", flag); + + if (flag & VERT_NORM) + COPY_3FV( ctx->Current.Normal, IM->Normal[count]); + + if (flag & VERT_INDEX) + ctx->Current.Index = IM->Index[count]; + + if (flag & VERT_EDGE) + ctx->Current.EdgeFlag = IM->EdgeFlag[count]; + + if (flag & VERT_RGBA) + COPY_4UBV(ctx->Current.Color, IM->Color[count]); + + if (flag & VERT_SPEC_RGB) + COPY_4UBV(ctx->Current.SecondaryColor, IM->SecondaryColor[count]); + + if (flag & VERT_FOG_COORD) + ctx->Current.FogCoord = IM->FogCoord[count]; + + if (flag & VERT_TEX_ANY) { + GLuint i; + for (i = 0 ; i < ctx->Const.MaxTextureUnits ; i++) { + if (flag & VERT_TEX(i)) { + COPY_4FV( ctx->Current.Texcoord[0], IM->TexCoord[0][count]); + } + } + } +} + + + +void _tnl_compute_orflag( struct immediate *IM ) +{ + GLuint count = IM->Count; + GLuint orflag = 0; + GLuint andflag = ~0U; + GLuint i; + + IM->LastData = count-1; + + + /* Compute the flags for the whole buffer. + */ + for (i = IM->CopyStart ; i < count ; i++) { + andflag &= IM->Flag[i]; + orflag |= IM->Flag[i]; + } + + /* It is possible there will be data in the buffer arising from + * calls like 'glNormal', 'glMaterial' that occur after the final + * glVertex, glEval, etc. Additionally, a buffer can consist of + * only a single glMaterial call, in which case IM->Start == + * IM->Count, but the buffer is definitely not empty. + */ + if (IM->Flag[i] & VERT_DATA) { + IM->LastData++; + orflag |= IM->Flag[i]; + } + + IM->Flag[IM->LastData+1] |= VERT_END_VB; + IM->CopyAndFlag = IM->AndFlag = andflag; + IM->CopyOrFlag = IM->OrFlag = orflag; +} + + + + + +/* Note: The 'start' member of the GLvector structs is now redundant + * because we always re-transform copied vertices, and the vectors + * below are set up so that the first copied vertex (if any) appears + * at position zero. + */ +static void _tnl_vb_bind_immediate( GLcontext *ctx, struct immediate *IM ) +{ + TNLcontext *tnl = TNL_CONTEXT(ctx); + struct vertex_buffer *VB = &tnl->vb; + struct vertex_arrays *tmp = &tnl->imm_inputs; + GLuint inputs = tnl->pipeline.inputs; /* for copy-to-current */ + GLuint start = IM->CopyStart; + GLuint count = IM->Count - start; + + /* TODO: optimize the case where nothing has changed. (Just bind + * tmp to vb). + */ + + /* Setup constant data in the VB. + */ + VB->Count = count; + VB->FirstClipped = IMM_MAXDATA - IM->CopyStart; + VB->import_data = 0; + VB->importable_data = 0; + + /* Need an IM->FirstPrimitive? + */ + VB->Primitive = IM->Primitive + IM->CopyStart; + VB->PrimitiveLength = IM->PrimitiveLength + IM->CopyStart; + VB->FirstPrimitive = 0; + + VB->Flag = IM->Flag + start; + + /* TexCoordPtr's are zeroed in loop below. + */ + VB->NormalPtr = 0; + VB->NormalLengthPtr = 0; + VB->FogCoordPtr = 0; + VB->EdgeFlagPtr = 0; + VB->IndexPtr[0] = 0; + VB->IndexPtr[1] = 0; + VB->ColorPtr[0] = 0; + VB->ColorPtr[1] = 0; + VB->SecondaryColorPtr[0] = 0; + VB->SecondaryColorPtr[1] = 0; + VB->Elts = 0; + VB->MaterialMask = 0; + VB->Material = 0; + +/* _tnl_print_vert_flags("copy-orflag", IM->CopyOrFlag); */ +/* _tnl_print_vert_flags("orflag", IM->OrFlag); */ +/* _tnl_print_vert_flags("inputs", inputs); */ + + /* Setup the initial values of array pointers in the vb. + */ + if (inputs & VERT_OBJ) { + tmp->Obj.data = IM->Obj + start; + tmp->Obj.start = (GLfloat *)(IM->Obj + start); + tmp->Obj.count = count; + VB->ObjPtr = &tmp->Obj; + if ((IM->CopyOrFlag & VERT_OBJ_234) == VERT_OBJ_234) + tmp->Obj.size = 4; + else if ((IM->CopyOrFlag & VERT_OBJ_234) == VERT_OBJ_23) + tmp->Obj.size = 3; + else + tmp->Obj.size = 2; + } + + if (inputs & VERT_NORM) { + tmp->Normal.data = IM->Normal + start; + tmp->Normal.start = (GLfloat *)(IM->Normal + start); + tmp->Normal.count = count; + VB->NormalPtr = &tmp->Normal; + if (IM->NormalLengths) + VB->NormalLengthPtr = IM->NormalLengths + start; + } + + if (inputs & VERT_INDEX) { + tmp->Index.count = count; + tmp->Index.data = IM->Index + start; + tmp->Index.start = IM->Index + start; + VB->IndexPtr[0] = &tmp->Index; + } + + if (inputs & VERT_FOG_COORD) { + tmp->FogCoord.data = IM->FogCoord + start; + tmp->FogCoord.start = IM->FogCoord + start; + tmp->FogCoord.count = count; + VB->FogCoordPtr = &tmp->FogCoord; + } + + if (inputs & VERT_SPEC_RGB) { + tmp->SecondaryColor.data = IM->SecondaryColor + start; + tmp->SecondaryColor.start = (GLubyte *)(IM->SecondaryColor + start); + tmp->SecondaryColor.count = count; + VB->SecondaryColorPtr[0] = &tmp->SecondaryColor; + } + + if (inputs & VERT_EDGE) { + tmp->EdgeFlag.data = IM->EdgeFlag + start; + tmp->EdgeFlag.start = IM->EdgeFlag + start; + tmp->EdgeFlag.count = count; + VB->EdgeFlagPtr = &tmp->EdgeFlag; + } + + if (inputs & VERT_RGBA) { + tmp->Color.data = IM->Color + start; + tmp->Color.start = (GLubyte *)(IM->Color + start); + tmp->Color.count = count; + VB->ColorPtr[0] = &tmp->Color; + } + + if (inputs & VERT_TEX_ANY) { + GLuint i; + for (i = 0; i < ctx->Const.MaxTextureUnits; i++) { + VB->TexCoordPtr[i] = 0; + if (inputs & VERT_TEX(i)) { + tmp->TexCoord[i].count = count; + tmp->TexCoord[i].data = IM->TexCoord[i] + start; + tmp->TexCoord[i].start = (GLfloat *)(IM->TexCoord[i] + start); + tmp->TexCoord[i].size = 2; + if (IM->TexSize & i) { + tmp->TexCoord[i].size = 3; + if (IM->TexSize & (i<<16)) + tmp->TexCoord[i].size = 4; + } + VB->TexCoordPtr[i] = &tmp->TexCoord[i]; + } + } + } + + if ((inputs & VERT_MATERIAL) && IM->Material) { + VB->MaterialMask = IM->MaterialMask + start; + VB->Material = IM->Material + start; + } +} + + + + +/* Called by exec_cassette and execute_compiled_cassette. + */ +void _tnl_run_cassette( GLcontext *ctx, struct immediate *IM ) +{ + TNLcontext *tnl = TNL_CONTEXT(ctx); + + _tnl_vb_bind_immediate( ctx, IM ); + + if (IM->CopyOrFlag & VERT_EVAL_ANY) + _tnl_eval_vb( ctx, + IM->Obj + IM->CopyStart, + IM->CopyOrFlag, + IM->CopyAndFlag ); + + + /* Invalidate all stored data before and after run: + */ + tnl->pipeline.run_input_changes |= tnl->pipeline.inputs; + _tnl_run_pipeline( ctx ); + tnl->pipeline.run_input_changes |= tnl->pipeline.inputs; + + copy_to_current( ctx, IM, IM->OrFlag ); +} + + + + +/* Called for pure, locked VERT_ELT cassettes instead of + * _tnl_run_cassette. + */ +static void exec_elt_cassette( GLcontext *ctx, struct immediate *IM ) +{ + TNLcontext *tnl = TNL_CONTEXT(ctx); + struct vertex_buffer *VB = &tnl->vb; + + _tnl_vb_bind_arrays( ctx, ctx->Array.LockFirst, ctx->Array.LockCount ); + + VB->Elts = IM->Elt + IM->CopyStart; + VB->Primitive = IM->Primitive + IM->CopyStart; + VB->PrimitiveLength = IM->PrimitiveLength + IM->CopyStart; + VB->FirstPrimitive = 0; + + /* Run the pipeline. No input changes as a result of this action. + */ + _tnl_run_pipeline( ctx ); + + /* Still need to update current values: (TODO - copy from VB) + * TODO: delay this until FlushVertices + */ + if (ctx->Driver.CurrentExecPrimitive == GL_POLYGON+1) { + _tnl_translate_array_elts( ctx, IM, IM->LastData, IM->LastData ); + copy_to_current( ctx, IM, ctx->Array._Enabled ); + } +} + +/* Called for cassettes where CopyStart == Count -- no need to run the + * pipeline. + */ +static void exec_empty_cassette( GLcontext *ctx, struct immediate *IM ) +{ + GLuint start = IM->CopyStart; + + if (IM->OrFlag & VERT_ELT) + _tnl_translate_array_elts( ctx, IM, start, start ); + + _tnl_fixup_input( ctx, IM ); /* shouldn't be needed? (demos/fire) */ + copy_to_current( ctx, IM, IM->OrFlag ); + + if (IM->OrFlag & VERT_MATERIAL) + gl_update_material( ctx, IM->Material[start], IM->MaterialMask[start] ); + + if (IM->OrFlag & VERT_RGBA) + if (ctx->Light.ColorMaterialEnabled) + gl_update_color_material( ctx, ctx->Current.Color ); +} + + +/* Called for regular vertex cassettes. + */ +static void exec_vert_cassette( GLcontext *ctx, struct immediate *IM ) +{ + 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->CopyAndFlag & VERT_ELT) + IM->CopyAndFlag |= ctx->Array._Enabled; + else { + for (i = IM->CopyStart ; i < IM->Count ; i++) + andflag &= IM->Flag[i]; + IM->CopyAndFlag = andflag; + } + } + + _tnl_fixup_input( ctx, IM ); +/* _tnl_print_cassette( IM ); */ + _tnl_run_cassette( ctx, IM ); +} + + + +/* Called for all cassettes when not compiling or playing a display + * list. + */ +void _tnl_execute_cassette( GLcontext *ctx, struct immediate *IM ) +{ + TNLcontext *tnl = TNL_CONTEXT(ctx); + + ASSERT(tnl->ExecCopySource == IM); + + _tnl_compute_orflag( IM ); + + /* Mark the last primitive: + */ + IM->PrimitiveLength[IM->LastPrimitive] = IM->Count - IM->LastPrimitive; + ASSERT(IM->Primitive[IM->LastPrimitive] & PRIM_LAST); + + + if (tnl->pipeline.build_state_changes) + _tnl_validate_pipeline( ctx ); + + _tnl_get_exec_copy_verts( ctx, IM ); + + if (IM->CopyStart == IM->Count) { + exec_empty_cassette( ctx, IM ); + } + else if ((IM->OrFlag & VERT_DATA) == VERT_ELT && + ctx->Array.LockCount && + ctx->Array.Vertex.Enabled) { + exec_elt_cassette( ctx, IM ); + } + else { + exec_vert_cassette( ctx, IM ); + } + + _tnl_reset_input( ctx, + IMM_MAX_COPIED_VERTS, + IM->BeginState & (VERT_BEGIN_0|VERT_BEGIN_1), + IM->SavedBeginState ); + + /* Copy vertices and primitive information to immediate before it + * can be overwritten. + */ + _tnl_copy_immediate_vertices( ctx, IM ); + +/* if (ctx->Driver.CurrentExecPrimitive == GL_POLYGON+1) */ +/* ctx->Driver.NeedFlush &= ~FLUSH_STORED_VERTICES; */ +} + + + + +/* Setup vector pointers that will be used to bind immediates to VB's. + */ +void _tnl_imm_init( GLcontext *ctx ) +{ + TNLcontext *tnl = TNL_CONTEXT(ctx); + struct vertex_arrays *tmp = &tnl->imm_inputs; + GLuint i; + static int firsttime = 1; + + if (firsttime) { + firsttime = 0; + _tnl_imm_elt_init(); + } + + ctx->swtnl_im = _tnl_alloc_immediate( ctx ); + TNL_CURRENT_IM(ctx)->ref_count++; + + tnl->ExecCopyTexSize = 0; + tnl->ExecCopyCount = 0; + tnl->ExecCopySource = TNL_CURRENT_IM(ctx); + TNL_CURRENT_IM(ctx)->ref_count++; + TNL_CURRENT_IM(ctx)->CopyStart = IMM_MAX_COPIED_VERTS; + + gl_vector4f_init( &tmp->Obj, 0, 0 ); + gl_vector3f_init( &tmp->Normal, 0, 0 ); + gl_vector4ub_init( &tmp->Color, 0, 0 ); + gl_vector4ub_init( &tmp->SecondaryColor, 0, 0 ); + gl_vector1f_init( &tmp->FogCoord, 0, 0 ); + gl_vector1ui_init( &tmp->Index, 0, 0 ); + gl_vector1ub_init( &tmp->EdgeFlag, 0, 0 ); + + for (i = 0; i < ctx->Const.MaxTextureUnits; i++) + gl_vector4f_init( &tmp->TexCoord[i], 0, 0); + + /* Install the first immediate. Intially outside begin/end. + */ + _tnl_reset_input( ctx, IMM_MAX_COPIED_VERTS, 0, 0 ); + tnl->ReplayHardBeginEnd = 0; + + _tnl_imm_vtxfmt_init( ctx ); +} + + +void _tnl_imm_destroy( GLcontext *ctx ) +{ + if (TNL_CURRENT_IM(ctx)) + _tnl_free_immediate( TNL_CURRENT_IM(ctx) ); + +} diff --git a/src/mesa/tnl/t_imm_exec.h b/src/mesa/tnl/t_imm_exec.h new file mode 100644 index 00000000000..3a7284ccfd8 --- /dev/null +++ b/src/mesa/tnl/t_imm_exec.h @@ -0,0 +1,62 @@ +/* $Id: t_imm_exec.h,v 1.1 2000/12/26 05:09:32 keithw Exp $ */ + +/* + * Mesa 3-D graphics library + * Version: 3.5 + * + * Copyright (C) 1999-2000 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. + */ + + +#ifndef _T_VBXFORM_H +#define _T_VBXFORM_H + +#include "mtypes.h" +#include "t_context.h" + + +/* Hook for ctx->Driver.FlushVertices: + */ +extern void _tnl_flush_vertices( GLcontext *ctx, GLuint flush_flags ); + +/* Called from imm_api.c and _tnl_flush_vertices: + */ +extern void _tnl_flush_immediate( struct immediate *IM ); + +/* Called from imm_dlist.c and _tnl_flush_immediate: + */ +extern void _tnl_run_cassette( GLcontext *ctx, struct immediate *IM ); + +/* Initialize some stuff: + */ +extern void _tnl_imm_init( GLcontext *ctx ); + +extern void _tnl_imm_destroy( GLcontext *ctx ); + +extern void _tnl_reset_input( GLcontext *ctx, + GLuint start, + GLuint beginstate, + GLuint savedbeginstate ); + +extern void _tnl_compute_orflag( struct immediate *IM ); +extern void _tnl_execute_cassette( GLcontext *ctx, struct immediate *IM ); + + +#endif diff --git a/src/mesa/tnl/t_imm_fixup.c b/src/mesa/tnl/t_imm_fixup.c new file mode 100644 index 00000000000..d55ab48c56d --- /dev/null +++ b/src/mesa/tnl/t_imm_fixup.c @@ -0,0 +1,811 @@ +/* $Id: t_imm_fixup.c,v 1.1 2000/12/26 05:09:32 keithw Exp $ */ + +/* + * Mesa 3-D graphics library + * Version: 3.5 + * + * Copyright (C) 1999-2000 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. + */ + +/* + * Authors: + * Keith Whitwell <[email protected]> + */ + + +#include "glheader.h" +#include "context.h" +#include "enums.h" +#include "dlist.h" +#include "macros.h" +#include "mem.h" +#include "mmath.h" +#include "state.h" +#include "texture.h" +#include "mtypes.h" + +#include "math/m_matrix.h" +#include "math/m_xform.h" + +#include "t_context.h" +#include "t_imm_alloc.h" +#include "t_imm_debug.h" +#include "t_imm_fixup.h" +#include "t_pipeline.h" + + + +static void +fixup_4f( GLfloat data[][4], GLuint flag[], GLuint start, GLuint match ) +{ + GLuint i = start; + + for (;;) { + if ((flag[++i] & match) == 0) { + COPY_4FV(data[i], data[i-1]); + if (flag[i] & VERT_END_VB) break; + } + } +} + +static void +fixup_3f( float data[][3], GLuint flag[], GLuint start, GLuint match ) +{ + GLuint i = start; + + for (;;) { + if ((flag[++i] & match) == 0) { + COPY_3V(data[i], data[i-1]); + if (flag[i] & VERT_END_VB) break; + } + } +} + + +static void +fixup_1ui( GLuint *data, GLuint flag[], GLuint start, GLuint match ) +{ + GLuint i = start; + + for (;;) { + if ((flag[++i] & match) == 0) { + data[i] = data[i-1]; + if (flag[i] & VERT_END_VB) break; + } + } + flag[i] |= match; +} + + +static void +fixup_1f( GLfloat *data, GLuint flag[], GLuint start, GLuint match ) +{ + GLuint i = start; + + for (;;) { + if ((flag[++i] & match) == 0) { + data[i] = data[i-1]; + if (flag[i] & VERT_END_VB) break; + } + } + flag[i] |= match; +} + +static void +fixup_1ub( GLubyte *data, GLuint flag[], GLuint start, GLuint match ) +{ + GLuint i = start; + + for (;;) { + if ((flag[++i] & match) == 0) { + data[i] = data[i-1]; + if (flag[i] & VERT_END_VB) break; + } + } + flag[i] |= match; +} + + +static void +fixup_4ub( GLubyte data[][4], GLuint flag[], GLuint start, GLuint match ) +{ + GLuint i = start; + + for (;;) { + if ((flag[++i] & match) == 0) { + COPY_4UBV(data[i], data[i-1]); + if (flag[i] & VERT_END_VB) break; + } + } + flag[i] |= match; +} + + +static void +fixup_first_4f( GLfloat data[][4], GLuint flag[], GLuint match, + GLuint start, GLfloat *dflt ) +{ + GLuint i = start-1; + match |= VERT_END_VB; + + while ((flag[++i]&match) == 0) + COPY_4FV(data[i], dflt); +} + +static void +fixup_first_3f( GLfloat data[][3], GLuint flag[], GLuint match, + GLuint start, GLfloat *dflt ) +{ + GLuint i = start-1; + match |= VERT_END_VB; + + while ((flag[++i]&match) == 0) + COPY_3FV(data[i], dflt); +} + + +static void +fixup_first_1ui( GLuint data[], GLuint flag[], GLuint match, + GLuint start, GLuint dflt ) +{ + GLuint i = start-1; + match |= VERT_END_VB; + + while ((flag[++i]&match) == 0) + data[i] = dflt; +} + +static void +fixup_first_1f( GLfloat data[], GLuint flag[], GLuint match, + GLuint start, GLfloat dflt ) +{ + GLuint i = start-1; + match |= VERT_END_VB; + + while ((flag[++i]&match) == 0) + data[i] = dflt; +} + + +static void +fixup_first_1ub( GLubyte data[], GLuint flag[], GLuint match, + GLuint start, GLubyte dflt ) +{ + GLuint i = start-1; + match |= VERT_END_VB; + + while ((flag[++i]&match) == 0) + data[i] = dflt; +} + + +static void +fixup_first_4ub( GLubyte data[][4], GLuint flag[], GLuint match, + GLuint start, GLubyte dflt[4] ) +{ + GLuint i = start-1; + match |= VERT_END_VB; + + while ((flag[++i]&match) == 0) + COPY_4UBV(data[i], dflt); +} + + +void _tnl_fixup_input( GLcontext *ctx, struct immediate *IM ) +{ + TNLcontext *tnl = TNL_CONTEXT(ctx); + GLuint start = IM->CopyStart; + GLuint andflag = IM->CopyAndFlag; + GLuint orflag = IM->CopyOrFlag; + GLuint fixup; + + IM->CopyTexSize = IM->TexSize; + +/* fprintf(stderr, "Fixup input, Start: %u Count: %u LastData: %u\n", */ +/* IM->Start, IM->Count, IM->LastData); */ +/* _tnl_print_vert_flags("Orflag", orflag); */ +/* _tnl_print_vert_flags("Andflag", andflag); */ + + + fixup = ~andflag & VERT_FIXUP; + + if (!ctx->CompileFlag) + fixup &= tnl->pipeline.inputs; + + if (!ctx->ExecuteFlag) + fixup &= orflag; + + if ((orflag & (VERT_OBJ|VERT_EVAL_ANY)) == 0) + fixup = 0; + + if (fixup) { + GLuint copy = fixup & ~IM->Flag[start]; + + + /* Equivalent to a lazy copy-from-current when setting up the + * immediate. + */ + if (ctx->ExecuteFlag && copy) { +/* _tnl_print_vert_flags("copy from current", copy); */ + + if (copy & VERT_NORM) { + COPY_3V( IM->Normal[start], ctx->Current.Normal ); + } + + if (copy & VERT_RGBA) { + COPY_4UBV( IM->Color[start], ctx->Current.Color); + } + + if (copy & VERT_SPEC_RGB) + COPY_4UBV( IM->SecondaryColor[start], ctx->Current.SecondaryColor); + + if (copy & VERT_FOG_COORD) + IM->FogCoord[start] = ctx->Current.FogCoord; + + if (copy & VERT_INDEX) + IM->Index[start] = ctx->Current.Index; + + if (copy & VERT_EDGE) + IM->EdgeFlag[start] = ctx->Current.EdgeFlag; + + if (copy & VERT_TEX_ANY) { + GLuint i; + for (i = 0 ; i < ctx->Const.MaxTextureUnits ; i++) { + if (copy & VERT_TEX(i)) + COPY_4FV( IM->TexCoord[i][start], ctx->Current.Texcoord[i] ); + } + } + } + + if (MESA_VERBOSE&VERBOSE_IMMEDIATE) +/* _tnl_print_vert_flags("fixup", fixup); */ + + if (fixup & VERT_TEX_ANY) { + GLuint i; + for (i = 0 ; i < ctx->Const.MaxTextureUnits ; i++) { + if (fixup & VERT_TEX(i)) { + if (orflag & VERT_TEX(i)) + fixup_4f( IM->TexCoord[i], IM->Flag, start, VERT_TEX(i) ); + else + fixup_first_4f( IM->TexCoord[i], IM->Flag, VERT_END_VB, start, + IM->TexCoord[i][start]); + } + } + } + } + + if (fixup & VERT_EDGE) { + if (orflag & VERT_EDGE) + fixup_1ub( IM->EdgeFlag, IM->Flag, start, VERT_EDGE ); + else + fixup_first_1ub( IM->EdgeFlag, IM->Flag, VERT_END_VB, start, + IM->EdgeFlag[start] ); + } + + if (fixup & VERT_INDEX) { + if (orflag & VERT_INDEX) + fixup_1ui( IM->Index, IM->Flag, start, VERT_INDEX ); + else + fixup_first_1ui( IM->Index, IM->Flag, VERT_END_VB, start, IM->Index[start] ); + } + + if (fixup & VERT_RGBA) { + if (orflag & VERT_RGBA) + fixup_4ub( IM->Color, IM->Flag, start, VERT_RGBA ); + else + fixup_first_4ub( IM->Color, IM->Flag, VERT_END_VB, start, IM->Color[start] ); + } + + if (fixup & VERT_SPEC_RGB) { + if (orflag & VERT_SPEC_RGB) + fixup_4ub( IM->SecondaryColor, IM->Flag, start, VERT_SPEC_RGB ); + else + fixup_first_4ub( IM->SecondaryColor, IM->Flag, VERT_END_VB, start, + IM->SecondaryColor[start] ); + } + + if (fixup & VERT_FOG_COORD) { + if (orflag & VERT_FOG_COORD) + fixup_1f( IM->FogCoord, IM->Flag, start, VERT_FOG_COORD ); + else + fixup_first_1f( IM->FogCoord, IM->Flag, VERT_END_VB, start, + IM->FogCoord[start] ); + } + + if (fixup & VERT_NORM) { + if (orflag & VERT_NORM) + fixup_3f( IM->Normal, IM->Flag, start, VERT_NORM ); + else + fixup_first_3f( IM->Normal, IM->Flag, VERT_END_VB, start, + IM->Normal[start] ); + } + + /* Prune possible half-filled slot. + */ + IM->Flag[IM->LastData+1] &= ~VERT_END_VB; + IM->Flag[IM->Count] |= VERT_END_VB; + +} + + + + +static void copy_material( struct immediate *next, + struct immediate *prev, + GLuint dst, GLuint src ) +{ + if (next->Material == 0) { + next->Material = (GLmaterial (*)[2]) MALLOC( sizeof(GLmaterial) * + IMM_SIZE * 2 ); + next->MaterialMask = (GLuint *) MALLOC( sizeof(GLuint) * IMM_SIZE ); + } + + next->MaterialMask[dst] = prev->MaterialMask[src]; + MEMCPY(next->Material[dst], prev->Material[src], 2*sizeof(GLmaterial)); +} + + + +/* Copy the untransformed data from the shared vertices of a primitive + * that wraps over two immediate structs. This is done prior to + * set_immediate so that prev and next may point to the same + * structure. In general it's difficult to avoid this copy on long + * primitives. + * + * Have to be careful with the transitions between display list + * replay, compile and normal execute modes. + */ +static void copy_vertices( GLcontext *ctx, + struct immediate *next, + struct immediate *prev, + GLuint count, + GLuint *elts ) +{ + TNLcontext *tnl = TNL_CONTEXT(ctx); + GLuint offset = IMM_MAX_COPIED_VERTS - count; + GLuint i; + + next->CopyStart = next->Start - count; + + /* Copy the vertices + */ + for (i = 0 ; i < count ; i++) + { + GLuint src = elts[i+offset]; + GLuint dst = next->CopyStart+i; + + COPY_4FV( next->Obj[dst], prev->Obj[src] ); + COPY_3FV( next->Normal[dst], prev->Normal[src] ); + COPY_4UBV( next->Color[dst], prev->Color[src] ); + + if (prev->OrFlag & VERT_TEX_ANY) { + GLuint i; + for (i = 0 ; i < prev->MaxTextureUnits ; i++) { + if (prev->OrFlag & VERT_TEX(i)) + COPY_4FV( next->TexCoord[i][dst], prev->TexCoord[i][src] ); + } + } + + if (prev->Flag[src] & VERT_MATERIAL) + copy_material(next, prev, dst, src); + + next->Elt[dst] = prev->Elt[src]; + next->EdgeFlag[dst] = prev->EdgeFlag[src]; + next->Index[dst] = prev->Index[src]; + COPY_4UBV( next->SecondaryColor[dst], prev->SecondaryColor[src] ); + next->FogCoord[dst] = prev->FogCoord[src]; + next->Flag[dst] = (prev->CopyOrFlag & VERT_FIXUP); + next->CopyOrFlag |= prev->Flag[src]; /* redundant for current_im */ + next->CopyAndFlag &= prev->Flag[src]; /* redundant for current_im */ + } + + /* Only needed when copying to a compiled cassette + */ + if (next->NormalLengths) { + for (i = 0 ; i < count ; i++) + { + GLuint src = elts[i+offset]; + GLuint dst = next->CopyStart+i; + + if (prev->NormalLengths) + next->NormalLengths[dst] = prev->NormalLengths[src]; + else + next->NormalLengths[dst] = 1.0/LEN_3FV(prev->Normal[src]); + } + } + + ASSERT(prev == tnl->ExecCopySource); + if (--tnl->ExecCopySource->ref_count == 0) + _tnl_free_immediate( tnl->ExecCopySource ); + + next->ref_count++; + tnl->ExecCopySource = next; + tnl->ExecCopyElts[0] = next->Start-3; + tnl->ExecCopyElts[1] = next->Start-2; + tnl->ExecCopyElts[2] = next->Start-1; +} + +/* Copy vertices to an empty immediate struct. + */ +void _tnl_copy_immediate_vertices( GLcontext *ctx, struct immediate *IM ) +{ + TNLcontext *tnl = TNL_CONTEXT(ctx); + + ASSERT(IM == TNL_CURRENT_IM(ctx)); + ASSERT(IM->Count == IM->Start); + + /* Need to push this in now as it won't be computed anywhere else/ + */ + IM->TexSize = tnl->ExecCopyTexSize; + + /* A wrapped primitive. We may be copying into a revived + * display list immediate, or onto the front of a new execute-mode + * immediate. + */ + copy_vertices( ctx, IM, + tnl->ExecCopySource, + tnl->ExecCopyCount, + tnl->ExecCopyElts ); + + if (ctx->Driver.CurrentExecPrimitive == GL_POLYGON+1) { + /* Immediates are built by default to be correct in this state, + * and copying to the first slots of an immediate doesn't remove + * this property. + */ + ASSERT(tnl->ExecCopyTexSize == 0); + ASSERT(tnl->ExecCopyCount == 0); + ASSERT(IM->CopyStart == IM->Start); + } + + /* Copy the primitive information: + */ + IM->Primitive[IM->CopyStart] = (ctx->Driver.CurrentExecPrimitive | PRIM_LAST); + IM->LastPrimitive = IM->CopyStart; + if (tnl->ExecParity) + IM->Primitive[IM->CopyStart] |= PRIM_PARITY; +} + + +/* Revive a compiled immediate struct - propogate new 'Current' + * values. Often this is redundant because the current values were + * known and fixed up at compile time. + */ +void _tnl_fixup_compiled_cassette( GLcontext *ctx, struct immediate *IM ) +{ + TNLcontext *tnl = TNL_CONTEXT(ctx); + GLuint fixup; + GLuint count = IM->Count; + GLuint start = IM->Start; + + if (count == start) + return; + + IM->CopyOrFlag = IM->OrFlag; /* redundant for current_im */ + IM->CopyAndFlag = IM->AndFlag; /* redundant for current_im */ + IM->CopyTexSize = IM->TexSize | tnl->ExecCopyTexSize; + + copy_vertices( ctx, IM, + tnl->ExecCopySource, + tnl->ExecCopyCount, + tnl->ExecCopyElts ); + + if (ctx->Driver.CurrentExecPrimitive == GL_POLYGON+1) { + ASSERT(tnl->ExecCopyTexSize == 0); + ASSERT(tnl->ExecCopyCount == 0); + ASSERT(IM->CopyStart == IM->Start); + } + + fixup = tnl->pipeline.inputs & ~IM->Flag[start] & VERT_FIXUP; + + if (fixup) { + if (fixup & VERT_TEX_ANY) { + GLuint i; + for (i = 0 ; i < ctx->Const.MaxTextureUnits ; i++) { + if (fixup & VERT_TEX(i)) + fixup_first_4f( IM->TexCoord[i], IM->Flag, VERT_TEX(i), start, + ctx->Current.Texcoord[i] ); + } + } + + if (fixup & VERT_EDGE) + fixup_first_1ub(IM->EdgeFlag, IM->Flag, VERT_EDGE, start, + ctx->Current.EdgeFlag ); + + if (fixup & VERT_INDEX) + fixup_first_1ui(IM->Index, IM->Flag, VERT_INDEX, start, + ctx->Current.Index ); + + if (fixup & VERT_RGBA) + fixup_first_4ub(IM->Color, IM->Flag, VERT_RGBA, start, + ctx->Current.Color ); + + if (fixup & VERT_SPEC_RGB) + fixup_first_4ub(IM->SecondaryColor, IM->Flag, VERT_SPEC_RGB, start, + ctx->Current.SecondaryColor ); + + if (fixup & VERT_FOG_COORD) + fixup_first_1f(IM->FogCoord, IM->Flag, VERT_FOG_COORD, start, + ctx->Current.FogCoord ); + + if (fixup & VERT_NORM) { + fixup_first_3f(IM->Normal, IM->Flag, VERT_NORM, start, + ctx->Current.Normal ); + if (IM->NormalLengths) + fixup_first_1f(IM->NormalLengths, IM->Flag, VERT_NORM, start, + 1.0F / (GLfloat) LEN_3FV(ctx->Current.Normal) ); + } + } + + + /* Can potentially overwrite primitive details - need to save the + * first slot: + */ + tnl->DlistPrimitive = IM->Primitive[IM->Start]; + tnl->DlistPrimitiveLength = IM->PrimitiveLength[IM->Start]; + tnl->DlistLastPrimitive = IM->LastPrimitive; + + /* The first primitive may be different from what was recorded in + * the immediate struct. Consider an immediate that starts with a + * glBegin, compiled in a display list, which is called from within + * an existing Begin/End object. + */ + if (ctx->Driver.CurrentExecPrimitive == GL_POLYGON+1) { + GLuint i; + + if (IM->BeginState & VERT_ERROR_1) + gl_error( ctx, GL_INVALID_OPERATION, "begin/end"); + + for (i = IM->Start ; i <= IM->Count ; i += IM->PrimitiveLength[i]) + if (IM->Flag[i] & (VERT_BEGIN|VERT_END_VB)) + break; + + /* Would like to just ignore vertices upto this point. Can't + * set copystart because it might skip materials? + */ + ASSERT(IM->Start == IM->CopyStart); + if (i > IM->CopyStart) { + IM->Primitive[IM->CopyStart] = GL_POLYGON+1; + IM->PrimitiveLength[IM->CopyStart] = i - IM->CopyStart; + if (IM->Flag[i] & VERT_END_VB) { + IM->Primitive[IM->CopyStart] |= PRIM_LAST; + IM->LastPrimitive = IM->CopyStart; + } + } + /* Shouldn't immediates be set up to have this structure *by default*? + */ + } else { + GLuint i; + + if (IM->BeginState & VERT_ERROR_0) + gl_error( ctx, GL_INVALID_OPERATION, "begin/end"); + + if (IM->CopyStart == IM->Start && + IM->Flag[IM->Start] & (VERT_END|VERT_END_VB)) + { + } + else + { + IM->Primitive[IM->CopyStart] = ctx->Driver.CurrentExecPrimitive; + if (tnl->ExecParity) + IM->Primitive[IM->CopyStart] |= PRIM_PARITY; + + + for (i = IM->Start ; i <= IM->Count ; i += IM->PrimitiveLength[i]) + if (IM->Flag[i] & (VERT_END|VERT_END_VB)) { + IM->PrimitiveLength[IM->CopyStart] = i - IM->CopyStart; + if (IM->Flag[i] & VERT_END_VB) { + IM->Primitive[IM->CopyStart] |= PRIM_LAST; + IM->LastPrimitive = IM->CopyStart; + } + if (IM->Flag[i] & VERT_END) { + IM->Primitive[IM->CopyStart] |= PRIM_END; + } + break; + } + } + } + + if (IM->Primitive[IM->LastPrimitive] & PRIM_END) + ctx->Driver.CurrentExecPrimitive = GL_POLYGON+1; + else + ctx->Driver.CurrentExecPrimitive = + IM->Primitive[IM->LastPrimitive] & PRIM_MODE_MASK; +} + + +/* Undo any changes potentially made to the immediate in the range + * IM->Start..IM->Count above. + */ +void _tnl_restore_compiled_cassette( GLcontext *ctx, struct immediate *IM ) +{ + TNLcontext *tnl = TNL_CONTEXT(ctx); + IM->Primitive[IM->Start] = tnl->DlistPrimitive; + IM->PrimitiveLength[IM->Start] = tnl->DlistPrimitiveLength; +} + + + + + + +static void copy_none( TNLcontext *tnl, GLuint start, GLuint count, GLuint ovf) +{ + (void) (start && ovf && tnl && count); +} + +static void copy_last( TNLcontext *tnl, GLuint start, GLuint count, GLuint ovf) +{ + (void) start; (void) ovf; + tnl->ExecCopyCount = 1; + tnl->ExecCopyElts[2] = count-1; +} + +static void copy_first_and_last( TNLcontext *tnl, GLuint start, GLuint count, + GLuint ovf) +{ + (void) ovf; + tnl->ExecCopyCount = 2; + tnl->ExecCopyElts[1] = start; + tnl->ExecCopyElts[2] = count-1; +} + +static void copy_last_two( TNLcontext *tnl, GLuint start, GLuint count, + GLuint ovf ) +{ + (void) start; + tnl->ExecCopyCount = 2+ovf; + tnl->ExecCopyElts[0] = count-3; + tnl->ExecCopyElts[1] = count-2; + tnl->ExecCopyElts[2] = count-1; +} + +static void copy_overflow( TNLcontext *tnl, GLuint start, GLuint count, + GLuint ovf ) +{ + (void) start; + tnl->ExecCopyCount = ovf; + tnl->ExecCopyElts[0] = count-3; + tnl->ExecCopyElts[1] = count-2; + tnl->ExecCopyElts[2] = count-1; +} + + +typedef void (*copy_func)( TNLcontext *tnl, GLuint start, GLuint count, + GLuint ovf ); + +static copy_func copy_tab[GL_POLYGON+2] = +{ + copy_none, + copy_overflow, + copy_first_and_last, + copy_last, + copy_overflow, + copy_last_two, + copy_first_and_last, + copy_overflow, + copy_last_two, + copy_first_and_last, + copy_none +}; + + + + + +/* Figure out what vertices need to be copied next time. + */ +void +_tnl_get_exec_copy_verts( GLcontext *ctx, struct immediate *IM ) +{ + static const GLuint increment[GL_POLYGON+2] = { 1,2,1,1,3,1,1,4,2,1,1 }; + static const GLuint intro[GL_POLYGON+2] = { 0,0,2,2,0,2,2,0,2,2,0 }; + + TNLcontext *tnl = TNL_CONTEXT(ctx); + GLuint last = IM->LastPrimitive; + GLuint prim = ctx->Driver.CurrentExecPrimitive; + GLuint pincr = increment[prim]; + GLuint pintro = intro[prim]; + GLuint ovf = 0; + + + if (tnl->ExecCopySource != IM) { + if (--tnl->ExecCopySource->ref_count == 0) + _tnl_free_immediate( tnl->ExecCopySource ); + IM->ref_count++; + tnl->ExecCopySource = IM; + } + + if (prim == GL_POLYGON+1) { + tnl->ExecCopyCount = 0; + tnl->ExecCopyTexSize = 0; + tnl->ExecParity = 0; + } else { + tnl->ExecCopyCount = 0; + tnl->ExecCopyTexSize = IM->CopyTexSize; + tnl->ExecParity = IM->PrimitiveLength[IM->LastPrimitive] & 1; + + if (pincr != 1 && (IM->Count - last - pintro)) + ovf = (IM->Count - last - pintro) % pincr; + + if (last < IM->Count) + copy_tab[prim]( tnl, last, IM->Count, ovf ); + } +} + + +/* If we receive evalcoords in an immediate struct for maps which + * don't have a vertex enabled, need to do an additional fixup, as + * those rows containing evalcoords must now be ignored. The + * evalcoords may still generate colors, normals, etc, so have to + * respect the relative order between calls to EvalCoord and Normal + * etc. + * + * Generate the index list that will be used to render this immediate + * struct. + * + * Finally, generate a new primitives list for rendering the indices. + */ +#if 0 +void _tnl_fixup_purged_eval( GLcontext *ctx, + GLuint fixup, GLuint purge ) +{ + TNLcontext *tnl = TNL_CONTEXT(ctx); + struct tnl_eval_store *store = &tnl->eval; + GLuint *flags = tnl->vb.Flag; + GLuint i, j, nextprim; + GLuint fixup_fence = purge|VERT_OBJ; + GLuint good_index = (VERT_EVAL_ANY & ~purge)|VERT_OBJ; + GLuint prim_length = 0, lastprim = 0, nextprim = 0; + + if (fixup & VERT_TEX0) + fixup_4f( store->TexCoord, flags, 0, VERT_TEX0|fixup_fence ); + + if (fixup & VERT_INDEX) + fixup_1ui( store->Index, flags, 0, VERT_INDEX|fixup_fence ); + + if (fixup & VERT_RGBA) + fixup_4ub( store->Color, flags, 0, VERT_RGBA|fixup_fence ); + + if (fixup & VERT_NORM) + fixup_3f( store->Normal, flags, 0, VERT_NORM|fixup_fence ); + + for (i = 0, j = 0 ; i < tnl->vb.Count ; i++) { + if (flags[i] & good_index) { + store->Elts[j++] = i; + prim_length++; + } + if (i == nextprim) { + VB->PrimitiveLength[lastprim] = prim_length; + VB->Primitive[j] = VB->Primitive[i]; + nextprim += lastprimlen; + lastprim = i; + lastprimlen = VB->PrimitiveLength[i]; + } + } + + VB->Elts = store->Elts; + + /* What about copying??? No immediate exists with the right + * vertices in place... + */ + if (tnl->CurrentPrimitive != GL_POLYGON+1) { + } +} +#endif diff --git a/src/mesa/tnl/t_imm_fixup.h b/src/mesa/tnl/t_imm_fixup.h new file mode 100644 index 00000000000..a6740a2a55b --- /dev/null +++ b/src/mesa/tnl/t_imm_fixup.h @@ -0,0 +1,52 @@ +/* $Id: t_imm_fixup.h,v 1.1 2000/12/26 05:09:33 keithw Exp $ */ + +/* + * Mesa 3-D graphics library + * Version: 3.5 + * + * Copyright (C) 1999-2000 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. + */ + + +#ifndef _T_IMM_FIXUP_H +#define _T_IMM_FIXUP_H + +#include "mtypes.h" +#include "t_context.h" + + + +extern void _tnl_fixup_input( GLcontext *ctx, struct immediate *IM ); + +extern void _tnl_fixup_compiled_cassette( GLcontext *ctx, + struct immediate *IM ); + +extern void _tnl_restore_compiled_cassette( GLcontext *ctx, + struct immediate *IM ); + + +extern void _tnl_fixup_purged_eval( GLcontext *ctx, + GLuint fixup, GLuint purge ); + + +extern void _tnl_copy_immediate_vertices( GLcontext *ctx, struct immediate *IM ); +extern void _tnl_get_exec_copy_verts( GLcontext *ctx, struct immediate *IM ); + +#endif diff --git a/src/mesa/tnl/t_pipeline.c b/src/mesa/tnl/t_pipeline.c index 60e375d7530..457b160eb95 100644 --- a/src/mesa/tnl/t_pipeline.c +++ b/src/mesa/tnl/t_pipeline.c @@ -1,4 +1,4 @@ -/* $Id: t_pipeline.c,v 1.6 2000/11/27 09:05:52 joukj Exp $ */ +/* $Id: t_pipeline.c,v 1.7 2000/12/26 05:09:33 keithw Exp $ */ /* * Mesa 3-D graphics library @@ -22,10 +22,9 @@ * 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. - */ - -/* Dynamic pipelines, support for CVA. - * Copyright (C) 1999 Keith Whitwell. + * + * Author: + * Keith Whitwell <[email protected]> */ #include "glheader.h" @@ -38,435 +37,165 @@ #include "math/m_translate.h" #include "math/m_xform.h" -#include "t_bbox.h" -#include "t_clip.h" -#include "t_cva.h" -#include "t_debug.h" -#include "t_fog.h" -#include "t_light.h" +#include "t_context.h" #include "t_pipeline.h" -#include "t_shade.h" -#include "t_stages.h" -#include "t_vbcull.h" -#include "t_vbindirect.h" -#include "t_vbrender.h" -#include "t_vbxform.h" - - - - - -void _tnl_print_pipe_ops( const char *msg, GLuint flags ) -{ - fprintf(stderr, - "%s: (0x%x) %s%s%s%s%s%s%s%s%s\n", - msg, - flags, - (flags & PIPE_OP_CVA_PREPARE) ? "cva-prepare, " : "", - (flags & PIPE_OP_VERT_XFORM) ? "vert-xform, " : "", - (flags & PIPE_OP_NORM_XFORM) ? "norm-xform, " : "", - (flags & PIPE_OP_LIGHT) ? "light, " : "", - (flags & PIPE_OP_FOG) ? "fog, " : "", - (flags & PIPE_OP_TEX) ? "tex-gen/tex-mat, " : "", - (flags & PIPE_OP_RAST_SETUP_0) ? "rast-0, " : "", - (flags & PIPE_OP_RAST_SETUP_1) ? "rast-1, " : "", - (flags & PIPE_OP_RENDER) ? "render, " : ""); - -} - -/* Have to reset only those parts of the vb which are being recalculated. - */ -void _tnl_reset_cva_vb( struct vertex_buffer *VB, GLuint stages ) +void _tnl_install_pipeline( GLcontext *ctx, + const struct gl_pipeline_stage **stages ) { - GLcontext *ctx = VB->ctx; TNLcontext *tnl = TNL_CONTEXT(ctx); - - if (MESA_VERBOSE&VERBOSE_PIPELINE) - _tnl_print_pipe_ops( "reset cva vb", stages ); - - if (stages & PIPE_OP_VERT_XFORM) - { - if (VB->ClipOrMask & CLIP_USER_BIT) - MEMSET(VB->UserClipMask, 0, VB->Count); - - VB->ClipOrMask = 0; - VB->ClipAndMask = CLIP_ALL_BITS; - VB->CullMode = 0; - VB->CullFlag[0] = VB->CullFlag[1] = 0; - VB->Culled = 0; - } - - if (stages & PIPE_OP_NORM_XFORM) { - VB->NormalPtr = &tnl->CVA.v.Normal; - } - - if (stages & PIPE_OP_LIGHT) - { - VB->ColorPtr = VB->Color[0] = VB->Color[1] = &tnl->CVA.v.Color; - VB->IndexPtr = VB->Index[0] = VB->Index[1] = &tnl->CVA.v.Index; - } - else if (stages & PIPE_OP_FOG) - { - if (ctx->Light.Enabled) { - VB->Color[0] = VB->LitColor[0]; - VB->Color[1] = VB->LitColor[1]; - VB->Index[0] = VB->LitIndex[0]; - VB->Index[1] = VB->LitIndex[1]; - } else { - VB->Color[0] = VB->Color[1] = &tnl->CVA.v.Color; - VB->Index[0] = VB->Index[1] = &tnl->CVA.v.Index; - } - VB->ColorPtr = VB->Color[0]; - VB->IndexPtr = VB->Index[0]; - } -} - - - - - - -static void pipeline_ctr( struct gl_pipeline *p, GLcontext *ctx, GLuint type ) -{ + struct gl_pipeline *pipe = &tnl->pipeline; GLuint i; - (void) ctx; - - p->state_change = 0; - p->cva_state_change = 0; - p->inputs = 0; - p->outputs = 0; - p->type = type; - p->ops = 0; - - for (i = 0 ; i < _tnl_default_nr_stages ; i++) - p->state_change |= _tnl_default_pipeline[i].state_change; -} - - -void _tnl_pipeline_init( GLcontext *ctx ) -{ - TNLcontext *tnl = TNL_CONTEXT(ctx); - - MEMCPY( tnl->PipelineStage, - _tnl_default_pipeline, - sizeof(*_tnl_default_pipeline) * _tnl_default_nr_stages ); - - tnl->NrPipelineStages = _tnl_default_nr_stages; - - pipeline_ctr( &tnl->CVA.elt, ctx, PIPE_IMMEDIATE); - pipeline_ctr( &tnl->CVA.pre, ctx, PIPE_PRECALC ); -} - + ASSERT(pipe->nr_stages == 0); -#define MINIMAL_VERT_DATA (VERT_DATA & ~VERT_EVAL_ANY) + pipe->run_state_changes = ~0; + pipe->run_input_changes = ~0; + pipe->build_state_changes = ~0; + pipe->build_state_trigger = 0; + pipe->inputs = 0; -#define VERT_CURRENT_DATA (VERT_TEX_ANY | \ - VERT_RGBA | \ - VERT_SPEC_RGB | \ - VERT_FOG_COORD | \ - VERT_INDEX | \ - VERT_EDGE | \ - VERT_NORM | \ - VERT_MATERIAL) - -/* Called prior to every recomputation of the CVA precalc data, except where - * the driver is able to calculate the pipeline unassisted. - */ -static void build_full_precalc_pipeline( GLcontext *ctx ) -{ - TNLcontext *tnl = TNL_CONTEXT(ctx); - struct gl_pipeline_stage *pipeline = tnl->PipelineStage; - struct gl_cva *cva = &tnl->CVA; - struct gl_pipeline *pre = &cva->pre; - struct gl_pipeline_stage **stages = pre->stages; - GLuint i; - GLuint newstate = pre->new_state; - GLuint changed_ops = 0; - GLuint oldoutputs = pre->outputs; - GLuint oldinputs = pre->inputs; - GLuint fallback = (VERT_CURRENT_DATA & - ~tnl->_ArraySummary); - GLuint changed_outputs = (tnl->_ArrayNewState | - (fallback & cva->orflag)); - GLuint available = fallback | tnl->_ArrayFlags; - - pre->cva_state_change = 0; - pre->ops = 0; - pre->outputs = 0; - pre->inputs = 0; - pre->forbidden_inputs = 0; - pre->fallback = 0; - - /* KW: Disable data reuse during Mesa reorg. Make this more readable... + /* Create a writeable copy of each stage. */ - newstate = ~0; - - if (tnl->_ArraySummary & VERT_ELT) - cva->orflag &= VERT_MATERIAL; - - cva->orflag &= ~(tnl->_ArraySummary & ~VERT_OBJ_ANY); - available &= ~cva->orflag; - - pre->outputs = available; - pre->inputs = available; - - if (MESA_VERBOSE & VERBOSE_PIPELINE) { - fprintf(stderr, ": Rebuild pipeline\n"); - _tnl_print_vert_flags("orflag", cva->orflag); + for (i = 0 ; i < MAX_PIPELINE_STAGES && stages[i] ; i++) { + MEMCPY( &pipe->stages[i], stages[i], sizeof( **stages )); + pipe->build_state_trigger |= pipe->stages[i].check_state; } - - - /* If something changes in the pipeline, tag all subsequent stages - * using this value for recalcuation. Also used to build the full - * pipeline by setting newstate and newinputs to ~0. - * - * Because all intermediate values are buffered, the new inputs - * are enough to fully specify what needs to be calculated, and a - * single pass identifies all stages requiring recalculation. - */ - for (i = 0 ; i < tnl->NrPipelineStages ; i++) - { - pipeline[i].check(ctx, &pipeline[i]); - - if (pipeline[i].type & PIPE_PRECALC) - { - if ((newstate & pipeline[i].cva_state_change) || - (changed_outputs & pipeline[i].inputs) || - !pipeline[i].inputs) - { - changed_ops |= pipeline[i].ops; - changed_outputs |= pipeline[i].outputs; - pipeline[i].active &= ~PIPE_PRECALC; - - if ((pipeline[i].inputs & ~available) == 0 && - (pipeline[i].ops & pre->ops) == 0) - { - pipeline[i].active |= PIPE_PRECALC; - *stages++ = &pipeline[i]; - } - } - - /* Incompatible with multiple stages structs implementing - * the same stage. - */ - available &= ~pipeline[i].outputs; - pre->outputs &= ~pipeline[i].outputs; - - if (pipeline[i].active & PIPE_PRECALC) { - pre->ops |= pipeline[i].ops; - pre->outputs |= pipeline[i].outputs; - available |= pipeline[i].outputs; - pre->forbidden_inputs |= pipeline[i].pre_forbidden_inputs; - } - } - else if (pipeline[i].active & PIPE_PRECALC) - { - pipeline[i].active &= ~PIPE_PRECALC; - changed_outputs |= pipeline[i].outputs; - changed_ops |= pipeline[i].ops; - } - } - - *stages = 0; - - pre->new_outputs = pre->outputs & (changed_outputs | ~oldoutputs); - pre->new_inputs = pre->inputs & ~oldinputs; - pre->fallback = pre->inputs & fallback; - pre->forbidden_inputs |= pre->inputs & fallback; - - pre->changed_ops = changed_ops; + pipe->nr_stages = i; } -void _tnl_build_precalc_pipeline( GLcontext *ctx ) +void _tnl_destroy_pipeline( GLcontext *ctx ) { TNLcontext *tnl = TNL_CONTEXT(ctx); - struct gl_pipeline *pre = &tnl->CVA.pre; - struct gl_pipeline *elt = &tnl->CVA.elt; - - if (!ctx->Driver.BuildPrecalcPipeline || - !ctx->Driver.BuildPrecalcPipeline( ctx )) - build_full_precalc_pipeline( ctx ); - - pre->data_valid = 0; - pre->pipeline_valid = 1; - elt->pipeline_valid = 0; + GLuint i; - tnl->CVA.orflag = 0; + for (i = 0 ; i < tnl->pipeline.nr_stages ; i++) + tnl->pipeline.stages[i].destroy( &tnl->pipeline.stages[i] ); - if (MESA_VERBOSE&VERBOSE_PIPELINE) - _tnl_print_pipeline( ctx, pre ); + tnl->pipeline.nr_stages = 0; } -static void build_full_immediate_pipeline( GLcontext *ctx ) + +void _tnl_validate_pipeline( GLcontext *ctx ) { TNLcontext *tnl = TNL_CONTEXT(ctx); - struct gl_pipeline_stage *pipeline = tnl->PipelineStage; - struct gl_cva *cva = &tnl->CVA; - struct gl_pipeline *pre = &cva->pre; - struct gl_pipeline *elt = &cva->elt; - struct gl_pipeline_stage **stages = elt->stages; - GLuint i; - GLuint newstate = elt->new_state; - GLuint active_ops = 0; - GLuint available = cva->orflag | MINIMAL_VERT_DATA; + struct gl_pipeline *pipe = &tnl->pipeline; + struct gl_pipeline_stage *stage = pipe->stages; + GLuint newstate = pipe->build_state_changes; GLuint generated = 0; - GLuint is_elt = 0; - - if (pre->data_valid && tnl->CompileCVAFlag) { - is_elt = 1; - active_ops = cva->pre.ops; - available |= pre->outputs | VERT_PRECALC_DATA; - } - - - elt->outputs = 0; /* not used */ - elt->inputs = 0; + GLuint i; - for (i = 0 ; i < tnl->NrPipelineStages ; i++) { - pipeline[i].active &= ~PIPE_IMMEDIATE; + pipe->inputs = 0; + pipe->build_state_changes = 0; - if ((pipeline[i].state_change & newstate) || - (pipeline[i].elt_forbidden_inputs & available)) - { - pipeline[i].check(ctx, &pipeline[i]); + for (i = 0 ; i < pipe->nr_stages ; i++) { + if (stage[i].check_state & newstate) { + stage[i].check(ctx, &stage[i]); } - if ((pipeline[i].type & PIPE_IMMEDIATE) && - (pipeline[i].ops & active_ops) == 0 && - (pipeline[i].elt_forbidden_inputs & available) == 0 - ) - { - if (pipeline[i].inputs & ~available) - elt->forbidden_inputs |= pipeline[i].inputs & ~available; - else - { - elt->inputs |= pipeline[i].inputs & ~generated; - elt->forbidden_inputs |= pipeline[i].elt_forbidden_inputs; - pipeline[i].active |= PIPE_IMMEDIATE; - *stages++ = &pipeline[i]; - generated |= pipeline[i].outputs; - available |= pipeline[i].outputs; - active_ops |= pipeline[i].ops; - } - } - } - - *stages = 0; - - elt->copy_transformed_data = 1; - elt->replay_copied_vertices = 0; - - if (is_elt) { - cva->merge = elt->inputs & pre->outputs; - elt->ops = active_ops & ~pre->ops; + if (stage[i].active) { + pipe->inputs |= stage[i].inputs & ~generated; + generated |= stage[i].outputs; + } } } -void _tnl_build_immediate_pipeline( GLcontext *ctx ) + +void _tnl_run_pipeline( GLcontext *ctx ) { TNLcontext *tnl = TNL_CONTEXT(ctx); - struct gl_pipeline *elt = &tnl->CVA.elt; + struct gl_pipeline *pipe = &tnl->pipeline; + struct gl_pipeline_stage *stage = pipe->stages; + GLuint changed_state = pipe->run_state_changes; + GLuint changed_inputs = pipe->run_input_changes; + GLboolean running = GL_TRUE; + GLuint i; - if (!ctx->Driver.BuildEltPipeline || - !ctx->Driver.BuildEltPipeline( ctx )) { - build_full_immediate_pipeline( ctx ); - } + unsigned short __tmp; - elt->pipeline_valid = 1; - tnl->CVA.orflag = 0; + /* Done elsewhere. + */ + ASSERT(pipe->build_state_changes == 0); - if (MESA_VERBOSE&VERBOSE_PIPELINE) - _tnl_print_pipeline( ctx, elt ); -} + START_FAST_MATH(__tmp); -#define INTERESTED ~0 + /* If something changes in the pipeline, tag all subsequent stages + * using this value for recalculation. + * + * Even inactive stages have their state and inputs examined to try + * to keep cached data alive over state-changes. + */ + for (i = 0 ; i < pipe->nr_stages ; i++) { + + stage[i].changed_inputs |= stage[i].inputs & changed_inputs; -void _tnl_update_pipelines( GLcontext *ctx ) -{ - TNLcontext *tnl = TNL_CONTEXT(ctx); - GLuint newstate = ctx->NewState; - struct gl_cva *cva = &tnl->CVA; - - newstate &= INTERESTED; - - if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_STATE)) - gl_print_enable_flags("enabled", ctx->_Enabled); - - if (newstate || - cva->lock_changed || - cva->orflag != cva->last_orflag || - tnl->_ArrayFlags != cva->last_array_flags) - { - GLuint j; - GLuint flags = VERT_WIN; - - if (ctx->Visual.RGBAflag) { - flags |= VERT_RGBA; - if (ctx->_TriangleCaps && DD_SEPERATE_SPECULAR) - flags |= VERT_SPEC_RGB; - } else - flags |= VERT_INDEX; - - for (j = 0 ; j < ctx->Const.MaxTextureUnits ; j++) { - if (ctx->Texture.Unit[j]._ReallyEnabled) - flags |= VERT_TEX(j); + if (stage[i].run_state & changed_state) { + stage[i].changed_inputs = stage[i].inputs; } - if (ctx->Polygon._Unfilled) - flags |= VERT_EDGE; - - if (ctx->Fog.FogCoordinateSource == GL_FOG_COORDINATE_EXT) - flags |= VERT_FOG_COORD; + if (stage[i].active) { + if (stage[i].changed_inputs) + changed_inputs |= stage[i].outputs; - if (ctx->RenderMode==GL_FEEDBACK) { - flags = (VERT_WIN | VERT_RGBA | VERT_INDEX | VERT_NORM | - VERT_EDGE | VERT_TEX_ANY); + if (running) { + running = stage[i].run( ctx, &stage[i] ); + } } - - tnl->_RenderFlags = flags; - - cva->elt.new_state |= newstate; - cva->elt.pipeline_valid = 0; - - cva->pre.new_state |= newstate; - cva->pre.forbidden_inputs = 0; - cva->pre.pipeline_valid = 0; - cva->lock_changed = 0; } + END_FAST_MATH(__tmp); - if (tnl->_ArrayNewState != cva->last_array_new_state) - cva->pre.pipeline_valid = 0; - - cva->pre.data_valid = 0; - cva->last_array_new_state = tnl->_ArrayNewState; - cva->last_orflag = cva->orflag; - cva->last_array_flags = tnl->_ArrayFlags; + pipe->run_state_changes = 0; + pipe->run_input_changes = 0; } -void _tnl_run_pipeline( struct vertex_buffer *VB ) -{ - struct gl_pipeline *pipe = VB->pipeline; - struct gl_pipeline_stage **stages = pipe->stages; - unsigned short x; - - pipe->data_valid = 1; /* optimized stages might want to reset this. */ - if (0) _tnl_print_pipeline( VB->ctx, pipe ); - - START_FAST_MATH(x); - for ( VB->Culled = 0; *stages && !VB->Culled ; stages++ ) - (*stages)->run( VB ); - - END_FAST_MATH(x); - - pipe->new_state = 0; -} +/* The default pipeline. This is useful for software rasterizers, and + * simple hardware rasterizers. For customization, I don't recommend + * tampering with the internals of these stages in the way that + * drivers did in Mesa 3.4. These stages are basically black boxes, + * and should be left intact. + * + * To customize the pipeline, consider: + * + * - removing redundant stages (making sure that the software rasterizer + * can cope with this on fallback paths). An example is fog + * coordinate generation, which is not required in the FX driver. + * + * - replacing general-purpose machine-independent stages with + * general-purpose machine-specific stages. There is no example of + * this to date, though it must be borne in mind that all subsequent + * stages that reference the output of the new stage must cope with + * any machine-specific data introduced. This may not be easy + * unless there are no such stages (ie the new stage is the last in + * the pipe). + * + * - inserting optimized (but specialized) stages ahead of the + * general-purpose fallback implementation. For example, the old + * fastpath mechanism, which only works when the VERT_ELT input is + * available, can be duplicated by placing the fastpath stage at the + * head of this pipeline. Such specialized stages are currently + * constrained to have no outputs (ie. they must either finish the * + * pipeline by returning GL_FALSE from run(), or do nothing). + * + * Some work can be done to lift some of the restrictions in the final + * case, if it becomes necessary to do so. + */ +const struct gl_pipeline_stage *_tnl_default_pipeline[] = { + &_tnl_update_material_stage, + &_tnl_vertex_transform_stage, + &_tnl_normal_transform_stage, + &_tnl_lighting_stage, + &_tnl_fog_coordinate_stage, + &_tnl_texgen_stage, + &_tnl_texture_transform_stage, + &_tnl_point_attenuation_stage, + &_tnl_render_stage, + 0 +}; diff --git a/src/mesa/tnl/t_pipeline.h b/src/mesa/tnl/t_pipeline.h index b9ae641894f..9d433bde0a7 100644 --- a/src/mesa/tnl/t_pipeline.h +++ b/src/mesa/tnl/t_pipeline.h @@ -1,4 +1,4 @@ -/* $Id: t_pipeline.h,v 1.3 2000/11/24 10:25:12 keithw Exp $ */ +/* $Id: t_pipeline.h,v 1.4 2000/12/26 05:09:33 keithw Exp $ */ /* * Mesa 3-D graphics library @@ -36,25 +36,30 @@ #include "mtypes.h" #include "t_context.h" -extern void _tnl_pipeline_init( GLcontext *ctx ); +extern void _tnl_run_pipeline( GLcontext *ctx ); -extern void _tnl_update_materials( struct vertex_buffer *VB); +extern void _tnl_validate_pipeline( GLcontext *ctx ); -extern void _tnl_update_pipelines( GLcontext *ctx ); +extern void _tnl_destroy_pipeline( GLcontext *ctx ); -extern void _tnl_build_precalc_pipeline( GLcontext *ctx ); -extern void _tnl_build_immediate_pipeline( GLcontext *ctx ); +extern void _tnl_install_pipeline( GLcontext *ctx, + const struct gl_pipeline_stage **stages ); -extern void _tnl_print_vert_flags( const char *name, GLuint flags ); -extern void _tnl_print_pipeline( GLcontext *ctx, struct gl_pipeline *p ); -extern void _tnl_print_active_pipeline( GLcontext *ctx, struct gl_pipeline *p ); -extern void _tnl_run_pipeline( struct vertex_buffer *VB ); - -extern void _tnl_clean_color( struct vertex_buffer *VB ); - -extern void _tnl_reset_cva_vb( struct vertex_buffer *VB, GLuint stages ); +/* These are implemented in the t_vb_*.c files: + */ +extern const struct gl_pipeline_stage _tnl_update_material_stage; +extern const struct gl_pipeline_stage _tnl_vertex_transform_stage; +extern const struct gl_pipeline_stage _tnl_normal_transform_stage; +extern const struct gl_pipeline_stage _tnl_lighting_stage; +extern const struct gl_pipeline_stage _tnl_fog_coordinate_stage; +extern const struct gl_pipeline_stage _tnl_texgen_stage; +extern const struct gl_pipeline_stage _tnl_texture_transform_stage; +extern const struct gl_pipeline_stage _tnl_point_attenuation_stage; +extern const struct gl_pipeline_stage _tnl_render_stage; -extern void _tnl_print_pipe_ops( const char *msg, GLuint flags ); +/* Shorthand to plug in the default pipeline: + */ +extern const struct gl_pipeline_stage *_tnl_default_pipeline[]; #endif diff --git a/src/mesa/tnl/t_vb_cliptmp.h b/src/mesa/tnl/t_vb_cliptmp.h new file mode 100644 index 00000000000..8a73e87de30 --- /dev/null +++ b/src/mesa/tnl/t_vb_cliptmp.h @@ -0,0 +1,477 @@ +/* $Id: t_vb_cliptmp.h,v 1.1 2000/12/26 05:09:33 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 <[email protected]> + */ + + +#define INSIDE( J ) !NEGATIVE(J) +#define OUTSIDE( J ) NEGATIVE(J) + + + + +static GLuint TAG(userclip_line)( GLcontext *ctx, + GLuint *i, GLuint *j, + interp_func interp ) +{ + struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb; + GLfloat (*coord)[4] = VB->ClipPtr->data; + GLuint ii = *i; + GLuint jj = *j; + GLuint p; + + for (p=0;p<MAX_CLIP_PLANES;p++) { + if (ctx->Transform.ClipEnabled[p]) { + GLfloat a = ctx->Transform._ClipUserPlane[p][0]; + GLfloat b = ctx->Transform._ClipUserPlane[p][1]; + GLfloat c = ctx->Transform._ClipUserPlane[p][2]; + GLfloat d = ctx->Transform._ClipUserPlane[p][3]; + + GLfloat dpI = d*W(ii) + c*Z(ii) + b*Y(ii) + a*X(ii); + GLfloat dpJ = d*W(jj) + c*Z(jj) + b*Y(jj) + a*X(jj); + + GLuint flagI = OUTSIDE( dpI ); + GLuint flagJ = OUTSIDE( dpJ ); + + if (flagI ^ flagJ) { + if (flagJ) { + GLfloat t = dpI / (dpI - dpJ); + jj = interp( ctx, t, ii, jj, GL_FALSE ); + } else { + GLfloat t = dpJ / (dpJ - dpI); + ii = interp( ctx, t, jj, ii, GL_FALSE ); + } + } + else if (flagI) + return 0; + } + } + + *i = ii; + *j = jj; + return 1; +} + + +static GLuint TAG(userclip_polygon)( GLcontext *ctx, + GLuint n, + GLuint vlist[], + interp_func interp ) +{ + struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb; + GLfloat (*coord)[4] = VB->ClipPtr->data; + GLuint vlist2[MAX_CLIPPED_VERTICES]; + GLuint *inlist = vlist, *outlist = vlist2; + GLuint p; + + for (p=0;p<MAX_CLIP_PLANES;p++) { + if (ctx->Transform.ClipEnabled[p]) { + register float a = ctx->Transform._ClipUserPlane[p][0]; + register float b = ctx->Transform._ClipUserPlane[p][1]; + register float c = ctx->Transform._ClipUserPlane[p][2]; + register float d = ctx->Transform._ClipUserPlane[p][3]; + + /* initialize prev to be last in the input list */ + GLuint prevj = inlist[0]; + GLfloat dpJ = d*W(prevj) + c*Z(prevj) + b*Y(prevj) + a*X(prevj); + GLuint outcount = 0; + GLuint curri; + + inlist[n] = inlist[0]; + + for (curri=1;curri<n+1;curri++) { GLuint currj = inlist[curri]; + GLfloat dpI = d*W(currj) + c*Z(currj) + b*Y(currj) + a*X(currj); + + if (!NEGATIVE(dpJ)) { + outlist[outcount++] = prevj; + VB->ClipMask[prevj] &= ~CLIP_USER_BIT; + } else { + VB->ClipMask[prevj] |= CLIP_USER_BIT; + } + + if (DIFFERENT_SIGNS(dpI, dpJ)) { + if (NEGATIVE(dpI)) { + GLfloat t = dpI/(dpI-dpJ); + outlist[outcount++] = interp( ctx, t, currj, prevj, GL_TRUE); + } else { + GLfloat t = dpJ/(dpJ-dpI); + outlist[outcount++] = interp( ctx, t, prevj, currj, GL_FALSE); + } + } + + prevj = currj; + dpJ = dpI; + } + + if (outcount < 3) + return 0; + else { + GLuint *tmp; + tmp = inlist; + inlist = outlist; + outlist = tmp; + n = outcount; + } + + } /* if */ + } /* for p */ + + if (inlist!=vlist) { + GLuint i; + for (i = 0 ; i < n ; i++) + vlist[i] = inlist[i]; + } + + return n; +} + + +/* This now calls the user clip functions if required. + */ +static void TAG(viewclip_line)( GLcontext *ctx, + GLuint i, GLuint j, + GLubyte mask ) +{ + struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb; + interp_func interp = (interp_func) VB->interpfunc; + GLfloat (*coord)[4] = VB->ClipPtr->data; + GLuint ii = i, jj = j; + GLuint vlist[2]; + GLuint n; + + VB->LastClipped = VB->FirstClipped; + +/* + * We use 6 instances of this code to clip against the 6 planes. + */ +#define GENERAL_CLIP \ + if (mask & PLANE) { \ + GLfloat dpI = CLIP_DOTPROD( ii ); \ + GLfloat dpJ = CLIP_DOTPROD( jj ); \ + \ + if (DIFFERENT_SIGNS(dpI, dpJ)) { \ + if (NEGATIVE(dpJ)) { \ + GLfloat t = dpI / (dpI - dpJ); \ + jj = interp( ctx, t, ii, jj, GL_FALSE ); \ + } else { \ + GLfloat t = dpJ / (dpJ - dpI); \ + ii = interp( ctx, t, jj, ii, GL_FALSE ); \ + } \ + } \ + else if (NEGATIVE(dpI)) \ + return; \ + } + + +#define PLANE CLIP_RIGHT_BIT +#define CLIP_DOTPROD(K) (- X(K) + W(K)) + + GENERAL_CLIP + +#undef CLIP_DOTPROD +#undef PLANE +#define PLANE CLIP_LEFT_BIT +#define CLIP_DOTPROD(K) (X(K) + W(K)) + + GENERAL_CLIP + +#undef CLIP_DOTPROD +#undef PLANE +#define PLANE CLIP_TOP_BIT +#define CLIP_DOTPROD(K) (- Y(K) + W(K)) + + GENERAL_CLIP + +#undef CLIP_DOTPROD +#undef PLANE +#define PLANE CLIP_BOTTOM_BIT +#define CLIP_DOTPROD(K) (Y(K) + W(K)) + + GENERAL_CLIP + +#undef CLIP_DOTPROD +#undef PLANE +#define PLANE CLIP_FAR_BIT +#define CLIP_DOTPROD(K) (- Z(K) + W(K)) + + if (SIZE >= 3) { + GENERAL_CLIP + } + +#undef CLIP_DOTPROD +#undef PLANE +#define PLANE CLIP_NEAR_BIT +#define CLIP_DOTPROD(K) (Z(K) + W(K)) + + if (SIZE >=3 ) { + GENERAL_CLIP + } + +#undef CLIP_DOTPROD +#undef PLANE +#undef GENERAL_CLIP + + + if (mask & CLIP_USER_BIT) { + if ( TAG(userclip_line)( ctx, &ii, &jj, interp ) == 0 ) + return; + } + + vlist[0] = ii; + vlist[1] = jj; + n = 2; + + /* If necessary, project new vertices. + */ + { + GLuint i, j; + GLfloat (*proj)[4] = VB->ProjectedClipPtr->data; + GLuint start = VB->FirstClipped; + + for (i = 0; i < n; i++) { + j = vlist[i]; + if (j >= start) { + if (SIZE == 4 && W(j) != 0.0F) { + GLfloat wInv = 1.0F / W(j); + proj[j][0] = X(j) * wInv; + proj[j][1] = Y(j) * wInv; + proj[j][2] = Z(j) * wInv; + proj[j][3] = wInv; + } else { + proj[j][0] = X(j); + proj[j][1] = Y(j); + proj[j][2] = Z(j); + proj[j][3] = W(j); + } + } + } + } + + if (ctx->Driver.BuildProjectedVertices) + ctx->Driver.BuildProjectedVertices(ctx, + VB->FirstClipped, + VB->LastClipped, + ~0); + + /* Render the new line. + */ + ctx->Driver.LineFunc( ctx, ii, jj, j ); +} + +/* We now clip polygon triangles individually. This is necessary to + * avoid artifacts dependent on where the boundary of the VB falls + * within the polygon. As a result, there is an upper bound on the + * number of vertices which may be created, and the test against VB_SIZE + * is redundant. + */ +static void TAG(viewclip_polygon)( GLcontext *ctx, + GLuint n, GLuint vlist[], GLuint pv, + GLubyte mask ) +{ + struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb; + interp_func interp = (interp_func) VB->interpfunc; + GLfloat (*coord)[4] = VB->ClipPtr->data; + GLuint vlist2[MAX_CLIPPED_VERTICES]; + GLuint *inlist = vlist, *outlist = vlist2; + GLuint i; + GLubyte *clipmask = VB->ClipMask; + + VB->LastClipped = VB->FirstClipped; + + if (mask & CLIP_ALL_BITS) { + +#define GENERAL_CLIP \ + if (mask & PLANE) { \ + GLuint idxPrev = inlist[n-1]; \ + GLfloat dpPrev = CLIP_DOTPROD(idxPrev); \ + GLuint outcount = 0; \ + GLuint i; \ + \ + mask &= ~PLANE; \ + \ + for (i = 0; i < n; i++) { \ + GLuint idx = inlist[i]; \ + GLfloat dp = CLIP_DOTPROD(idx); \ + \ + if (!NEGATIVE(dpPrev)) { \ + outlist[outcount++] = idxPrev; \ + clipmask[idxPrev] &= ~PLANE; \ + } \ + \ + if (DIFFERENT_SIGNS(dp, dpPrev)) { \ + GLuint newvert; \ + if (NEGATIVE(dp)) { \ + /* Going out of bounds. Avoid division by zero as we \ + * know dp != dpPrev from DIFFERENT_SIGNS, above. \ + */ \ + GLfloat t = dp / (dp - dpPrev); \ + newvert = interp( ctx, t, idx, idxPrev, GL_TRUE ); \ + } else { \ + /* Coming back in. \ + */ \ + GLfloat t = dpPrev / (dpPrev - dp); \ + newvert = interp( ctx, t, idxPrev, idx, GL_FALSE ); \ + } \ + clipmask[newvert] = mask; \ + outlist[outcount++] = newvert; \ + } \ + \ + idxPrev = idx; \ + dpPrev = dp; \ + } \ + \ + if (outcount < 3) \ + return; \ + \ + { \ + GLuint *tmp = inlist; \ + inlist = outlist; \ + outlist = tmp; \ + n = outcount; \ + } \ + } + + +#define PLANE CLIP_RIGHT_BIT +#define CLIP_DOTPROD(K) (- X(K) + W(K)) + + GENERAL_CLIP + +#undef CLIP_DOTPROD +#undef PLANE + + +#define PLANE CLIP_LEFT_BIT +#define CLIP_DOTPROD(K) (X(K) + W(K)) + + GENERAL_CLIP + +#undef CLIP_DOTPROD +#undef PLANE + +#define PLANE CLIP_TOP_BIT +#define CLIP_DOTPROD(K) (- Y(K) + W(K)) + + GENERAL_CLIP + +#undef CLIP_DOTPROD +#undef PLANE + +#define PLANE CLIP_BOTTOM_BIT +#define CLIP_DOTPROD(K) (Y(K) + W(K)) + + GENERAL_CLIP + +#undef CLIP_DOTPROD +#undef PLANE + +#define PLANE CLIP_FAR_BIT +#define CLIP_DOTPROD(K) (- Z(K) + W(K)) + + if (SIZE >= 3) { + GENERAL_CLIP + } + +#undef CLIP_DOTPROD +#undef PLANE + +#define PLANE CLIP_NEAR_BIT +#define CLIP_DOTPROD(K) (Z(K) + W(K)) + + if (SIZE >=3 ) { + GENERAL_CLIP + } + +#undef CLIP_DOTPROD +#undef PLANE +#undef GENERAL_CLIP + + if (inlist != vlist) + for (i = 0 ; i < n ; i++) + vlist[i] = inlist[i]; + } + + /* Clip against user clipping planes in clip space. + */ + if (mask & CLIP_USER_BIT) { + n = TAG(userclip_polygon)( ctx, n, vlist, interp ); + if (n < 3) return; + } + + /* Project if necessary. + */ + { + GLuint i; + GLfloat (*proj)[4] = VB->ProjectedClipPtr->data; + GLuint first = VB->FirstClipped; + + for (i = 0; i < n; i++) { + GLuint j = vlist[i]; + if (j >= first) { + if (SIZE == 4 && W(j) != 0.0F) { + GLfloat wInv = 1.0F / W(j); + proj[j][0] = X(j) * wInv; + proj[j][1] = Y(j) * wInv; + proj[j][2] = Z(j) * wInv; + proj[j][3] = wInv; + } else { + proj[j][0] = X(j); + proj[j][1] = Y(j); + proj[j][2] = Z(j); + proj[j][3] = W(j); + } + } + } + } + + if (ctx->Driver.BuildProjectedVertices) + ctx->Driver.BuildProjectedVertices(ctx, + VB->FirstClipped, + VB->LastClipped, + ~0); + + /* Render the new vertices as an unclipped polygon. + * Argh - need to pass in pv... + */ + { + GLuint *tmp = VB->Elts; + VB->Elts = vlist; + render_poly_pv_raw_elts( ctx, 0, n, PRIM_BEGIN|PRIM_END, pv ); + VB->Elts = tmp; + } +} + + + +#undef W +#undef Z +#undef Y +#undef X +#undef SIZE +#undef TAG +#undef INSIDE +#undef OUTSIDE diff --git a/src/mesa/tnl/t_vb_fog.c b/src/mesa/tnl/t_vb_fog.c new file mode 100644 index 00000000000..38a80702ab2 --- /dev/null +++ b/src/mesa/tnl/t_vb_fog.c @@ -0,0 +1,201 @@ +/* $Id: t_vb_fog.c,v 1.1 2000/12/26 05:09:33 keithw Exp $ */ + +/* + * Mesa 3-D graphics library + * Version: 3.5 + * + * Copyright (C) 1999-2000 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 <[email protected]> + */ + + +#include "glheader.h" +#include "colormac.h" +#include "context.h" +#include "macros.h" +#include "mem.h" +#include "mmath.h" +#include "mtypes.h" + +#include "math/m_xform.h" + +#include "t_context.h" +#include "t_pipeline.h" + + +struct fog_stage_data { + GLvector1f fogcoord; /* has actual storage allocated */ + GLvector1f input; /* points into VB->EyePtr Z values */ +}; + +#define FOG_STAGE_DATA(stage) ((struct fog_stage_data *)stage->private) + + + +/* Use lookup table & interpolation? + */ +static void make_win_fog_coords( GLcontext *ctx, GLvector1f *out, + const GLvector1f *in ) +{ + GLfloat end = ctx->Fog.End; + GLfloat *v = in->start; + GLuint stride = in->stride; + GLuint n = in->count; + GLfloat *data = out->data; + GLfloat d; + GLuint i; + + out->count = in->count; + + switch (ctx->Fog.Mode) { + case GL_LINEAR: + d = 1.0F / (ctx->Fog.End - ctx->Fog.Start); + for ( i = 0 ; i < n ; i++, STRIDE_F(v, stride)) + data[i] = (end - ABSF(*v)) * d; + break; + case GL_EXP: + d = -ctx->Fog.Density; + for ( i = 0 ; i < n ; i++, STRIDE_F(v,stride)) + data[i] = exp( d*ABSF(*v) ); + break; + case GL_EXP2: + d = -(ctx->Fog.Density*ctx->Fog.Density); + for ( i = 0 ; i < n ; i++, STRIDE_F(v, stride)) { + GLfloat z = *v; + data[i] = exp( d*z*z ); + } + break; + default: + gl_problem(ctx, "Bad fog mode in make_fog_coord"); + return; + } +} + + +static GLboolean run_fog_stage( GLcontext *ctx, + struct gl_pipeline_stage *stage ) +{ + struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb; + struct fog_stage_data *store = FOG_STAGE_DATA(stage); + GLvector1f *input; + + VB->FogCoordPtr = &store->fogcoord; + + if (stage->changed_inputs == 0) + return GL_TRUE; + + if (ctx->Fog.FogCoordinateSource == GL_FRAGMENT_DEPTH_EXT) { + if (!ctx->_NeedEyeCoords) { + GLfloat *m = ctx->ModelView.m; + GLfloat plane[4]; + + /* Use this to store calculated eye z values: + */ + input = &store->fogcoord; + + plane[0] = m[2]; + plane[1] = m[6]; + plane[2] = m[10]; + plane[3] = m[14]; + + /* Full eye coords weren't required, just calculate the + * eye Z values. + */ + gl_dotprod_tab[0][VB->ObjPtr->size](input->data, sizeof(GLfloat), + VB->ObjPtr, plane, 0 ); + + input->count = VB->ObjPtr->count; + } + else + { + input = &store->input; + + if (VB->EyePtr->size < 2) + gl_vector4f_clean_elem( VB->EyePtr, VB->Count, 2 ); + + input->data = &(VB->EyePtr->data[0][2]); + input->start = VB->EyePtr->start+2; + input->stride = VB->EyePtr->stride; + input->count = VB->EyePtr->count; + } + } else + input = VB->FogCoordPtr; + + make_win_fog_coords( ctx, VB->FogCoordPtr, input ); + return GL_TRUE; +} + +static void check_fog_stage( GLcontext *ctx, struct gl_pipeline_stage *stage ) +{ + stage->active = ctx->Fog.Enabled; + + if (ctx->Fog.FogCoordinateSource == GL_FRAGMENT_DEPTH_EXT) + stage->inputs = VERT_EYE; + else + stage->inputs = VERT_FOG_COORD; +} + + +/* Called the first time stage->run() is invoked. + */ +static GLboolean alloc_fog_data( GLcontext *ctx, + struct gl_pipeline_stage *stage ) +{ + TNLcontext *tnl = TNL_CONTEXT(ctx); + struct fog_stage_data *store; + stage->private = MALLOC(sizeof(*store)); + store = FOG_STAGE_DATA(stage); + if (!store) + return GL_FALSE; + + gl_vector1f_alloc( &store->fogcoord, 0, tnl->vb.Size, 32 ); + gl_vector1f_init( &store->input, 0, 0 ); + + /* Now run the stage. + */ + stage->run = run_fog_stage; + return stage->run( ctx, stage ); +} + + +static void free_fog_data( struct gl_pipeline_stage *stage ) +{ + struct fog_stage_data *store = FOG_STAGE_DATA(stage); + if (store) { + gl_vector1f_free( &store->fogcoord ); + FREE( store ); + stage->private = 0; + } +} + + +const struct gl_pipeline_stage _tnl_fog_coordinate_stage = +{ + "build fog coordinates", + _NEW_FOG, + _NEW_FOG, + 0, 0, VERT_FOG_COORD, /* active, inputs, outputs */ + 0, 0, /* changed_inputs, private_data */ + free_fog_data, /* dtr */ + check_fog_stage, /* check */ + alloc_fog_data /* run -- initially set to init. */ +}; diff --git a/src/mesa/tnl/t_vb_light.c b/src/mesa/tnl/t_vb_light.c new file mode 100644 index 00000000000..b55cda38588 --- /dev/null +++ b/src/mesa/tnl/t_vb_light.c @@ -0,0 +1,280 @@ +/* $Id: t_vb_light.c,v 1.1 2000/12/26 05:09:33 keithw Exp $ */ + +/* + * Mesa 3-D graphics library + * Version: 3.5 + * + * Copyright (C) 1999-2000 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. + */ + + + +#include "glheader.h" +#include "colormac.h" +#include "light.h" +#include "macros.h" +#include "mem.h" +#include "mmath.h" +#include "simple_list.h" +#include "mtypes.h" + +#include "t_context.h" +#include "t_pipeline.h" + +#define LIGHT_FLAGS 0x1 /* must be first */ +#define LIGHT_TWOSIDE 0x2 +#define LIGHT_COLORMATERIAL 0x4 +#define MAX_LIGHT_FUNC 0x8 + +typedef void (*light_func)( GLcontext *ctx, + struct vertex_buffer *VB, + struct gl_pipeline_stage *stage, + GLvector4f *input ); + +struct light_stage_data { + GLvector4ub LitColor[2]; + GLvector1ui LitIndex[2]; + GLvector4ub LitSecondary[2]; + + light_func *light_func_tab; +}; + +#define LIGHT_STAGE_DATA(stage) ((struct light_stage_data *)(stage->private)) + +/* Tables for all the shading functions. + */ +static light_func _tnl_light_tab[MAX_LIGHT_FUNC]; +static light_func _tnl_light_fast_tab[MAX_LIGHT_FUNC]; +static light_func _tnl_light_fast_single_tab[MAX_LIGHT_FUNC]; +static light_func _tnl_light_spec_tab[MAX_LIGHT_FUNC]; +static light_func _tnl_light_ci_tab[MAX_LIGHT_FUNC]; + +#define TAG(x) x +#define IDX (0) +#include "t_vb_lighttmp.h" + +#define TAG(x) x##_tw +#define IDX (LIGHT_TWOSIDE) +#include "t_vb_lighttmp.h" + +#define TAG(x) x##_fl +#define IDX (LIGHT_FLAGS) +#include "t_vb_lighttmp.h" + +#define TAG(x) x##_tw_fl +#define IDX (LIGHT_FLAGS|LIGHT_TWOSIDE) +#include "t_vb_lighttmp.h" + +#define TAG(x) x##_cm +#define IDX (LIGHT_COLORMATERIAL) +#include "t_vb_lighttmp.h" + +#define TAG(x) x##_tw_cm +#define IDX (LIGHT_TWOSIDE|LIGHT_COLORMATERIAL) +#include "t_vb_lighttmp.h" + +#define TAG(x) x##_fl_cm +#define IDX (LIGHT_FLAGS|LIGHT_COLORMATERIAL) +#include "t_vb_lighttmp.h" + +#define TAG(x) x##_tw_fl_cm +#define IDX (LIGHT_FLAGS|LIGHT_TWOSIDE|LIGHT_COLORMATERIAL) +#include "t_vb_lighttmp.h" + + +static void init_lighting( void ) +{ + static int done; + + if (!done) { + init_light_tab(); + init_light_tab_tw(); + init_light_tab_fl(); + init_light_tab_tw_fl(); + init_light_tab_cm(); + init_light_tab_tw_cm(); + init_light_tab_fl_cm(); + init_light_tab_tw_fl_cm(); + done = 1; + } +} + + +static GLboolean run_lighting( GLcontext *ctx, struct gl_pipeline_stage *stage ) +{ + struct light_stage_data *store = LIGHT_STAGE_DATA(stage); + TNLcontext *tnl = TNL_CONTEXT(ctx); + struct vertex_buffer *VB = &tnl->vb; + GLvector4f *input = ctx->_NeedEyeCoords ? VB->EyePtr : VB->ObjPtr; + GLuint ind; + + /* Make sure we can talk about elements 0..2 in the vector we are + * lighting. TODO: Don't repeat this in CVA! + */ + if (input->size <= 2) { + if (input->flags & VEC_NOT_WRITEABLE) { + ASSERT(VB->importable_data & VERT_OBJ); + VB->import_data( ctx, VERT_OBJ, VEC_NOT_WRITEABLE ); + input = ctx->_NeedEyeCoords ? VB->EyePtr : VB->ObjPtr; + ASSERT((input->flags & VEC_NOT_WRITEABLE) == 0); + } + + gl_vector4f_clean_elem(input, VB->Count, 2); + } + + if (VB->Flag) + ind = LIGHT_FLAGS; + else + ind = 0; + + /* The individual tabs know about replaying side-effects vs. full + * re-execution. + */ + store->light_func_tab[ind]( ctx, VB, stage, input ); + + return GL_TRUE; +} + + +/* Called in place of do_lighting when the light table may have changed. + */ +static GLboolean run_validate_lighting( GLcontext *ctx, + struct gl_pipeline_stage *stage ) +{ + GLuint ind = 0; + light_func *tab; + + if (ctx->Visual.RGBAflag) { + if (ctx->Light._NeedVertices) { + if (ctx->Light.Model.ColorControl==GL_SEPARATE_SPECULAR_COLOR) + tab = _tnl_light_spec_tab; + else + tab = _tnl_light_tab; + } + else { + if (ctx->Light.EnabledList.next == ctx->Light.EnabledList.prev) + tab = _tnl_light_fast_single_tab; + else + tab = _tnl_light_fast_tab; + } +/* tab = _tnl_light_tab; */ + } + + if (ctx->Light.ColorMaterialEnabled) + ind |= LIGHT_COLORMATERIAL; + + if (ctx->Light.Model.TwoSide) + ind |= LIGHT_TWOSIDE; + + LIGHT_STAGE_DATA(stage)->light_func_tab = &tab[ind]; + + /* This and the above should only be done on _NEW_LIGHT: + */ + gl_validate_all_lighting_tables( ctx ); + + /* Now run the stage... + */ + stage->run = run_lighting; + return stage->run( ctx, stage ); +} + +/* Called the first time stage->run is called. In effect, don't + * allocate data until the first time the stage is run. + */ +static GLboolean run_init_lighting( GLcontext *ctx, + struct gl_pipeline_stage *stage ) +{ + TNLcontext *tnl = TNL_CONTEXT(ctx); + struct light_stage_data *store; + GLuint size = tnl->vb.Size; + + stage->private = MALLOC(sizeof(*store)); + store = LIGHT_STAGE_DATA(stage); + if (!store) + return GL_FALSE; + + /* Do onetime init. + */ + init_lighting(); + + gl_vector4ub_alloc( &store->LitColor[0], 0, size, 32 ); + gl_vector4ub_alloc( &store->LitColor[1], 0, size, 32 ); + gl_vector4ub_alloc( &store->LitSecondary[0], 0, size, 32 ); + gl_vector4ub_alloc( &store->LitSecondary[1], 0, size, 32 ); + gl_vector1ui_alloc( &store->LitIndex[0], 0, size, 32 ); + gl_vector1ui_alloc( &store->LitIndex[1], 0, size, 32 ); + + /* Now validate the stage derived data... + */ + stage->run = run_validate_lighting; + return stage->run( ctx, stage ); +} + + + +/* + * Check if lighting is enabled. If so, configure the pipeline stage's + * type, inputs, and outputs. + */ +static void check_lighting( GLcontext *ctx, struct gl_pipeline_stage *stage ) +{ + stage->active = ctx->Light.Enabled; + if (stage->active) { + if (stage->private) + stage->run = run_validate_lighting; + stage->inputs = VERT_NORM|VERT_MATERIAL; + if (ctx->Light._NeedVertices) + stage->inputs |= VERT_EYE; /* effectively, even when lighting in obj */ + if (ctx->Light.ColorMaterialEnabled) + stage->inputs |= VERT_RGBA; + } +} + + +static void dtr( struct gl_pipeline_stage *stage ) +{ + struct light_stage_data *store = LIGHT_STAGE_DATA(stage); + + if (store) { + gl_vector4ub_free( &store->LitColor[0] ); + gl_vector4ub_free( &store->LitColor[1] ); + gl_vector1ui_free( &store->LitIndex[0] ); + gl_vector1ui_free( &store->LitIndex[1] ); + gl_vector4ub_free( &store->LitSecondary[0] ); + gl_vector4ub_free( &store->LitSecondary[1] ); + FREE( store ); + stage->private = 0; + } +} + +const struct gl_pipeline_stage _tnl_lighting_stage = +{ + "lighting", + _NEW_LIGHT, /* recheck */ + _NEW_LIGHT|_NEW_MODELVIEW, /* recalc -- modelview dependency + * otherwise not captured by inputs + * (which may be VERT_OBJ) */ + 0,0,VERT_RGBA, /* active, inputs, outputs */ + 0,0, /* changed_inputs, private_data */ + dtr, /* destroy */ + check_lighting, /* check */ + run_init_lighting /* run -- initially set to ctr */ +}; + diff --git a/src/mesa/tnl/t_vb_lighttmp.h b/src/mesa/tnl/t_vb_lighttmp.h new file mode 100644 index 00000000000..f2bcde67148 --- /dev/null +++ b/src/mesa/tnl/t_vb_lighttmp.h @@ -0,0 +1,965 @@ +/* $Id: t_vb_lighttmp.h,v 1.1 2000/12/26 05:09:33 keithw Exp $ */ + +/* + * Mesa 3-D graphics library + * Version: 3.5 + * + * Copyright (C) 1999-2000 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. + * + * + * Authors: + * Brian Paul <[email protected]> + * Keith Whitwell <[email protected]> + */ + + +#if (IDX & LIGHT_FLAGS) +# define VSTRIDE (4 * sizeof(GLfloat)) +# define NSTRIDE (3 * sizeof(GLfloat)) +# define CHECK_MATERIAL(x) (flags[x] & VERT_MATERIAL) +# define CHECK_END_VB(x) (flags[x] & VERT_END_VB) +# if (IDX & LIGHT_COLORMATERIAL) +# define CMSTRIDE STRIDE_4UB(CMcolor, (4 * sizeof(GLubyte))) +# define CHECK_COLOR_MATERIAL(x) (flags[x] & VERT_RGBA) +# define CHECK_VALIDATE(x) (flags[x] & (VERT_RGBA|VERT_MATERIAL)) +# define DO_ANOTHER_NORMAL(x) \ + ((flags[x] & (VERT_RGBA|VERT_NORM|VERT_END_VB|VERT_MATERIAL)) == VERT_NORM) +# define REUSE_LIGHT_RESULTS(x) \ + ((flags[x] & (VERT_RGBA|VERT_NORM|VERT_END_VB|VERT_MATERIAL)) == 0) +# else +# define CMSTRIDE 0 +# define CHECK_COLOR_MATERIAL(x) 0 +# define CHECK_VALIDATE(x) (flags[x] & (VERT_MATERIAL)) +# define DO_ANOTHER_NORMAL(x) \ + ((flags[x] & (VERT_NORM|VERT_END_VB|VERT_MATERIAL)) == VERT_NORM) +# define REUSE_LIGHT_RESULTS(x) \ + ((flags[x] & (VERT_NORM|VERT_END_VB|VERT_MATERIAL)) == 0) +# endif +#else +# define VSTRIDE vstride +# define NSTRIDE nstride +# define CHECK_MATERIAL(x) 0 /* no materials on array paths */ +# define CHECK_END_VB(XX) (XX >= nr) +# if (IDX & LIGHT_COLORMATERIAL) +# define CMSTRIDE STRIDE_4UB(CMcolor, CMstride) +# define CHECK_COLOR_MATERIAL(x) (x < nr) /* always have colormaterial */ +# define CHECK_VALIDATE(x) (x < nr) +# define DO_ANOTHER_NORMAL(x) 0 /* always stop to recalc colormat */ +# else +# define CMSTRIDE 0 +# define CHECK_COLOR_MATERIAL(x) 0 /* no colormaterial */ +# define CHECK_VALIDATE(x) (0) +# define DO_ANOTHER_NORMAL(XX) (XX < nr) /* keep going to end of vb */ +# endif +# define REUSE_LIGHT_RESULTS(x) 0 /* always have a new normal */ +#endif + + + +#if (IDX & LIGHT_TWOSIDE) +# define NR_SIDES 2 +#else +# define NR_SIDES 1 +#endif + + + +static void TAG(light_rgba_spec)( GLcontext *ctx, + struct vertex_buffer *VB, + struct gl_pipeline_stage *stage, + GLvector4f *input ) +{ + struct light_stage_data *store = LIGHT_STAGE_DATA(stage); + GLfloat (*base)[3] = ctx->Light._BaseColor; + const GLchan *sumA = ctx->Light._BaseAlpha; + + GLuint j; + + GLuint vstride = input->stride; + const GLfloat *vertex = (GLfloat *)input->data; + GLuint nstride = VB->NormalPtr->stride; + const GLfloat *normal = (GLfloat *)VB->NormalPtr->data; + + GLchan (*CMcolor)[4]; + GLuint CMstride; + + GLchan (*Fcolor)[4] = (GLchan (*)[4]) store->LitColor[0].data; + GLchan (*Bcolor)[4] = (GLchan (*)[4]) store->LitColor[1].data; + GLchan (*Fspec)[4] = (GLchan (*)[4]) store->LitSecondary[0].data; + GLchan (*Bspec)[4] = (GLchan (*)[4]) store->LitSecondary[1].data; + GLuint nr = VB->Count; + + GLuint *flags = VB->Flag; + struct gl_material (*new_material)[2] = VB->Material; + GLuint *new_material_mask = VB->MaterialMask; + + (void) flags; + (void) nstride; + (void) vstride; + + if (IDX & LIGHT_COLORMATERIAL) { + CMcolor = (GLchan (*)[4]) VB->ColorPtr[0]->data; + CMstride = VB->ColorPtr[0]->stride; + } + + VB->ColorPtr[0] = &store->LitColor[0]; + VB->SecondaryColorPtr[0] = &store->LitSecondary[0]; + + if (IDX & LIGHT_TWOSIDE) { + VB->ColorPtr[1] = &store->LitColor[1]; + VB->SecondaryColorPtr[1] = &store->LitSecondary[1]; + } + + /* Side-effects done, can we finish now? + */ + if (stage->changed_inputs == 0) + return; + + for ( j=0 ; + j<nr ; + j++,STRIDE_F(vertex,VSTRIDE),STRIDE_F(normal,NSTRIDE),CMSTRIDE) + { + GLfloat sum[2][3], spec[2][3]; + struct gl_light *light; + + if ( CHECK_COLOR_MATERIAL(j) ) + gl_update_color_material( ctx, CMcolor[j] ); + + if ( CHECK_MATERIAL(j) ) + gl_update_material( ctx, new_material[j], new_material_mask[j] ); + + if ( CHECK_VALIDATE(j) ) + gl_validate_all_lighting_tables( ctx ); + + COPY_3V(sum[0], base[0]); + ZERO_3V(spec[0]); + + if (IDX & LIGHT_TWOSIDE) { + COPY_3V(sum[1], base[1]); + ZERO_3V(spec[1]); + } + + /* Add contribution from each enabled light source */ + foreach (light, &ctx->Light.EnabledList) { + GLfloat n_dot_h; + GLfloat correction; + GLint side; + GLfloat contrib[3]; + GLfloat attenuation; + GLfloat VP[3]; /* unit vector from vertex to light */ + GLfloat n_dot_VP; /* n dot VP */ + GLfloat *h; + + /* compute VP and attenuation */ + if (!(light->_Flags & LIGHT_POSITIONAL)) { + /* directional light */ + COPY_3V(VP, light->_VP_inf_norm); + attenuation = light->_VP_inf_spot_attenuation; + } + else { + GLfloat d; /* distance from vertex to light */ + + SUB_3V(VP, light->_Position, vertex); + + d = (GLfloat) LEN_3FV( VP ); + + if (d > 1e-6) { + GLfloat invd = 1.0F / d; + SELF_SCALE_SCALAR_3V(VP, invd); + } + + attenuation = 1.0F / (light->ConstantAttenuation + d * + (light->LinearAttenuation + d * + light->QuadraticAttenuation)); + + /* spotlight attenuation */ + if (light->_Flags & LIGHT_SPOT) { + GLfloat PV_dot_dir = - DOT3(VP, light->_NormDirection); + + if (PV_dot_dir<light->_CosCutoff) { + continue; /* this light makes no contribution */ + } + else { + double x = PV_dot_dir * (EXP_TABLE_SIZE-1); + int k = (int) x; + GLfloat spot = (GLfloat) (light->_SpotExpTable[k][0] + + (x-k)*light->_SpotExpTable[k][1]); + attenuation *= spot; + } + } + } + + + if (attenuation < 1e-3) + continue; /* this light makes no contribution */ + + /* Compute dot product or normal and vector from V to light pos */ + n_dot_VP = DOT3( normal, VP ); + + /* Which side gets the diffuse & specular terms? */ + if (n_dot_VP < 0.0F) { + ACC_SCALE_SCALAR_3V(sum[0], attenuation, light->_MatAmbient[0]); + if (!(IDX & LIGHT_TWOSIDE)) { + continue; + } + side = 1; + correction = -1; + n_dot_VP = -n_dot_VP; + } + else { + if (IDX & LIGHT_TWOSIDE) { + ACC_SCALE_SCALAR_3V( sum[1], attenuation, light->_MatAmbient[1]); + } + side = 0; + correction = 1; + } + + /* diffuse term */ + COPY_3V(contrib, light->_MatAmbient[side]); + ACC_SCALE_SCALAR_3V(contrib, n_dot_VP, light->_MatDiffuse[side]); + ACC_SCALE_SCALAR_3V(sum[side], attenuation, contrib ); + + /* specular term - cannibalize VP... */ + if (ctx->Light.Model.LocalViewer) { + GLfloat v[3]; + COPY_3V(v, vertex); + NORMALIZE_3FV(v); + SUB_3V(VP, VP, v); /* h = VP + VPe */ + h = VP; + NORMALIZE_3FV(h); + } + else if (light->_Flags & LIGHT_POSITIONAL) { + h = VP; + ACC_3V(h, ctx->_EyeZDir); + NORMALIZE_3FV(h); + } + else { + h = light->_h_inf_norm; + } + + n_dot_h = correction * DOT3(normal, h); + + if (n_dot_h > 0.0F) { + GLfloat spec_coef; + struct gl_shine_tab *tab = ctx->_ShineTable[side]; + GET_SHINE_TAB_ENTRY( tab, n_dot_h, spec_coef ); + + if (spec_coef > 1.0e-10) { + spec_coef *= attenuation; + ACC_SCALE_SCALAR_3V( spec[side], spec_coef, + light->_MatSpecular[side]); + } + } + } /*loop over lights*/ + + FLOAT_RGB_TO_CHAN_RGB( Fcolor[j], sum[0] ); + FLOAT_RGB_TO_CHAN_RGB( Fspec[j], spec[0] ); + Fcolor[j][3] = sumA[0]; + + if (IDX & LIGHT_TWOSIDE) { + FLOAT_RGB_TO_CHAN_RGB( Bcolor[j], sum[1] ); + FLOAT_RGB_TO_CHAN_RGB( Bspec[j], spec[1] ); + Bcolor[j][3] = sumA[1]; + } + } + + if ( CHECK_COLOR_MATERIAL(j) ) + gl_update_color_material( ctx, CMcolor[j] ); + + if ( CHECK_MATERIAL(j) ) + gl_update_material( ctx, new_material[j], new_material_mask[j] ); + + if ( CHECK_VALIDATE(j) ) + gl_validate_all_lighting_tables( ctx ); +} + + +static void TAG(light_rgba)( GLcontext *ctx, + struct vertex_buffer *VB, + struct gl_pipeline_stage *stage, + GLvector4f *input ) +{ + struct light_stage_data *store = LIGHT_STAGE_DATA(stage); + GLuint j; + + GLfloat (*base)[3] = ctx->Light._BaseColor; + const GLchan *sumA = ctx->Light._BaseAlpha; + + GLuint vstride = input->stride; + const GLfloat *vertex = (GLfloat *) input->data; + GLuint nstride = VB->NormalPtr->stride; + const GLfloat *normal = (GLfloat *)VB->NormalPtr->data; + + GLubyte (*CMcolor)[4]; + GLuint CMstride; + + GLchan (*Fcolor)[4] = (GLchan (*)[4]) store->LitColor[0].data; + GLchan (*Bcolor)[4] = (GLchan (*)[4]) store->LitColor[1].data; + GLuint *flags = VB->Flag; + + struct gl_material (*new_material)[2] = VB->Material; + GLuint *new_material_mask = VB->MaterialMask; + GLuint nr = VB->Count; + + (void) flags; + (void) nstride; + (void) vstride; + + if (IDX & LIGHT_COLORMATERIAL) { + CMcolor = VB->ColorPtr[0]->data; + CMstride = VB->ColorPtr[0]->stride; + } + + VB->ColorPtr[0] = &store->LitColor[0]; + if (IDX & LIGHT_TWOSIDE) + VB->ColorPtr[1] = &store->LitColor[1]; + + if (stage->changed_inputs == 0) + return; + + for ( j=0 ; + j<nr ; + j++,STRIDE_F(vertex,VSTRIDE), STRIDE_F(normal,NSTRIDE),CMSTRIDE) + { + GLfloat sum[2][3]; + struct gl_light *light; + + if ( CHECK_COLOR_MATERIAL(j) ) + gl_update_color_material( ctx, (GLchan *)CMcolor[j] ); + + if ( CHECK_MATERIAL(j) ) + gl_update_material( ctx, new_material[j], new_material_mask[j] ); + + if ( CHECK_VALIDATE(j) ) + gl_validate_all_lighting_tables( ctx ); + + COPY_3V(sum[0], base[0]); + + if ( IDX & LIGHT_TWOSIDE ) + COPY_3V(sum[1], base[1]); + + /* Add contribution from each enabled light source */ + foreach (light, &ctx->Light.EnabledList) { + + GLfloat n_dot_h; + GLfloat correction; + GLint side; + GLfloat contrib[3]; + GLfloat attenuation = 1.0; + GLfloat VP[3]; /* unit vector from vertex to light */ + GLfloat n_dot_VP; /* n dot VP */ + GLfloat *h; + + /* compute VP and attenuation */ + if (!(light->_Flags & LIGHT_POSITIONAL)) { + /* directional light */ + COPY_3V(VP, light->_VP_inf_norm); + attenuation = light->_VP_inf_spot_attenuation; + } + else { + GLfloat d; /* distance from vertex to light */ + + + SUB_3V(VP, light->_Position, vertex); + + d = LEN_3FV( VP ); + + if ( d > 1e-6) { + GLfloat invd = 1.0F / d; + SELF_SCALE_SCALAR_3V(VP, invd); + } + + attenuation = 1.0F / (light->ConstantAttenuation + d * + (light->LinearAttenuation + d * + light->QuadraticAttenuation)); + + /* spotlight attenuation */ + if (light->_Flags & LIGHT_SPOT) { + GLfloat PV_dot_dir = - DOT3(VP, light->_NormDirection); + + if (PV_dot_dir<light->_CosCutoff) { + continue; /* this light makes no contribution */ + } + else { + double x = PV_dot_dir * (EXP_TABLE_SIZE-1); + int k = (int) x; + GLfloat spot = (light->_SpotExpTable[k][0] + + (x-k)*light->_SpotExpTable[k][1]); + attenuation *= spot; + } + } + } + + + if (attenuation < 1e-3) + continue; /* this light makes no contribution */ + + + /* Compute dot product or normal and vector from V to light pos */ + n_dot_VP = DOT3( normal, VP ); + + /* which side are we lighting? */ + if (n_dot_VP < 0.0F) { + ACC_SCALE_SCALAR_3V(sum[0], attenuation, light->_MatAmbient[0]); + + if (!(IDX & LIGHT_TWOSIDE)) + continue; + + side = 1; + correction = -1; + n_dot_VP = -n_dot_VP; + } + else { + if (IDX & LIGHT_TWOSIDE) { + ACC_SCALE_SCALAR_3V( sum[1], attenuation, light->_MatAmbient[1]); + } + side = 0; + correction = 1; + } + + COPY_3V(contrib, light->_MatAmbient[side]); + + /* diffuse term */ + ACC_SCALE_SCALAR_3V(contrib, n_dot_VP, light->_MatDiffuse[side]); + + /* specular term - cannibalize VP... */ + { + if (ctx->Light.Model.LocalViewer) { + GLfloat v[3]; + COPY_3V(v, vertex); + NORMALIZE_3FV(v); + SUB_3V(VP, VP, v); /* h = VP + VPe */ + h = VP; + NORMALIZE_3FV(h); + } + else if (light->_Flags & LIGHT_POSITIONAL) { + h = VP; + ACC_3V(h, ctx->_EyeZDir); + NORMALIZE_3FV(h); + } + else { + h = light->_h_inf_norm; + } + + n_dot_h = correction * DOT3(normal, h); + + if (n_dot_h > 0.0F) + { + GLfloat spec_coef; + struct gl_shine_tab *tab = ctx->_ShineTable[side]; + + GET_SHINE_TAB_ENTRY( tab, n_dot_h, spec_coef ); + + ACC_SCALE_SCALAR_3V( contrib, spec_coef, + light->_MatSpecular[side]); + } + } + + ACC_SCALE_SCALAR_3V( sum[side], attenuation, contrib ); + } + + FLOAT_RGB_TO_CHAN_RGB( Fcolor[j], sum[0] ); + Fcolor[j][3] = sumA[0]; + + if (IDX & LIGHT_TWOSIDE) { + FLOAT_RGB_TO_CHAN_RGB( Bcolor[j], sum[1] ); + Bcolor[j][3] = sumA[1]; + } + } + + if ( CHECK_COLOR_MATERIAL(j) ) + gl_update_color_material( ctx, (GLchan *)CMcolor[j] ); + + if ( CHECK_MATERIAL(j) ) + gl_update_material( ctx, new_material[j], new_material_mask[j] ); + + if ( CHECK_VALIDATE(j) ) + gl_validate_all_lighting_tables( ctx ); +} + + + + +/* As below, but with just a single light. + */ +static void TAG(light_fast_rgba_single)( GLcontext *ctx, + struct vertex_buffer *VB, + struct gl_pipeline_stage *stage, + GLvector4f *input ) + +{ + struct light_stage_data *store = LIGHT_STAGE_DATA(stage); + GLuint nstride = VB->NormalPtr->stride; + const GLfloat *normal = (GLfloat *)VB->NormalPtr->data; + GLubyte (*CMcolor)[4]; + GLuint CMstride; + GLchan (*Fcolor)[4] = (GLchan (*)[4]) store->LitColor[0].data; + GLchan (*Bcolor)[4] = (GLchan (*)[4]) store->LitColor[1].data; + struct gl_light *light = ctx->Light.EnabledList.next; + GLuint *flags = VB->Flag; + GLchan baseubyte[2][4]; + GLuint j = 0; + struct gl_material (*new_material)[2] = VB->Material; + GLuint *new_material_mask = VB->MaterialMask; + GLfloat base[2][3]; + GLuint nr = VB->Count; + + (void) input; /* doesn't refer to Eye or Obj */ + (void) flags; + (void) nr; + (void) nstride; + + if (IDX & LIGHT_COLORMATERIAL) { + CMcolor = VB->ColorPtr[0]->data; + CMstride = VB->ColorPtr[0]->stride; + } + + VB->ColorPtr[0] = &store->LitColor[0]; + if (IDX & LIGHT_TWOSIDE) + VB->ColorPtr[1] = &store->LitColor[1]; + + if (stage->changed_inputs == 0) + return; + + if ( CHECK_COLOR_MATERIAL(j) ) + gl_update_color_material( ctx, (GLchan *)CMcolor[j] ); + + if ( CHECK_MATERIAL(j) ) + gl_update_material( ctx, new_material[j], new_material_mask[j] ); + + if ( CHECK_VALIDATE(j) ) + gl_validate_all_lighting_tables( ctx ); + + baseubyte[0][3] = ctx->Light._BaseAlpha[0]; + baseubyte[1][3] = ctx->Light._BaseAlpha[1]; + + do { + /* No attenuation, so incoporate _MatAmbient into base color. + */ + { + COPY_3V(base[0], light->_MatAmbient[0]); + ACC_3V(base[0], ctx->Light._BaseColor[0] ); + FLOAT_RGB_TO_CHAN_RGB( baseubyte[0], base[0] ); + + if (IDX & LIGHT_TWOSIDE) { + COPY_3V(base[1], light->_MatAmbient[1]); + ACC_3V(base[1], ctx->Light._BaseColor[1]); + FLOAT_RGB_TO_CHAN_RGB( baseubyte[1], base[1]); + } + } + + do { + GLfloat n_dot_VP = DOT3(normal, light->_VP_inf_norm); + + COPY_CHAN4(Fcolor[j], baseubyte[0]); + if (IDX & LIGHT_TWOSIDE) COPY_CHAN4(Bcolor[j], baseubyte[1]); + + if (n_dot_VP < 0.0F) { + if (IDX & LIGHT_TWOSIDE) { + GLfloat n_dot_h = -DOT3(normal, light->_h_inf_norm); + GLfloat sum[3]; + COPY_3V(sum, base[1]); + ACC_SCALE_SCALAR_3V(sum, -n_dot_VP, light->_MatDiffuse[1]); + if (n_dot_h > 0.0F) { + GLfloat spec; + GET_SHINE_TAB_ENTRY( ctx->_ShineTable[1], n_dot_h, spec ); + ACC_SCALE_SCALAR_3V(sum, spec, light->_MatSpecular[1]); + } + FLOAT_RGB_TO_CHAN_RGB(Bcolor[j], sum ); + } + } else { + GLfloat n_dot_h = DOT3(normal, light->_h_inf_norm); + GLfloat sum[3]; + COPY_3V(sum, base[0]); + ACC_SCALE_SCALAR_3V(sum, n_dot_VP, light->_MatDiffuse[0]); + if (n_dot_h > 0.0F) { + GLfloat spec; + GET_SHINE_TAB_ENTRY( ctx->_ShineTable[0], n_dot_h, spec ); + ACC_SCALE_SCALAR_3V(sum, spec, light->_MatSpecular[0]); + + } + FLOAT_RGB_TO_CHAN_RGB(Fcolor[j], sum ); + } + + j++; + STRIDE_F(normal, NSTRIDE); + } while (DO_ANOTHER_NORMAL(j)); + + + for ( ; REUSE_LIGHT_RESULTS(j) ; j++ ) { + COPY_CHAN4(Fcolor[j], Fcolor[j-1]); + if (IDX & LIGHT_TWOSIDE) + COPY_CHAN4(Bcolor[j], Bcolor[j-1]); + STRIDE_F(normal, NSTRIDE); + } + + /* Have to recompute our base colors on material change. + */ + if ( CHECK_MATERIAL(j) ) + gl_update_material( ctx, new_material[j], new_material_mask[j] ); + + if ( CHECK_COLOR_MATERIAL(j) ) + gl_update_color_material( ctx, (GLchan *)CMcolor[j] ); + + if ( CHECK_VALIDATE(j) ) + gl_validate_all_lighting_tables( ctx ); + + } while (!CHECK_END_VB(j)); +} + + +/* Light infinite lights + */ +static void TAG(light_fast_rgba)( GLcontext *ctx, + struct vertex_buffer *VB, + struct gl_pipeline_stage *stage, + GLvector4f *input ) +{ + struct light_stage_data *store = LIGHT_STAGE_DATA(stage); + const GLchan *sumA = ctx->Light._BaseAlpha; + GLuint nstride = VB->NormalPtr->stride; + const GLfloat *normal = (GLfloat *)VB->NormalPtr->data; + GLubyte (*CMcolor)[4]; + GLuint CMstride; + GLchan (*Fcolor)[4] = (GLchan (*)[4]) store->LitColor[0].data; + GLchan (*Bcolor)[4] = (GLchan (*)[4]) store->LitColor[1].data; + GLuint *flags = VB->Flag; + GLuint j = 0; + struct gl_material (*new_material)[2] = VB->Material; + GLuint *new_material_mask = VB->MaterialMask; + GLuint nr = VB->Count; + struct gl_light *light; + + (void) flags; + (void) input; + (void) nr; + (void) nstride; + + if (IDX & LIGHT_COLORMATERIAL) { + CMcolor = VB->ColorPtr[0]->data; + CMstride = VB->ColorPtr[0]->stride; + } + + VB->ColorPtr[0] = &store->LitColor[0]; + if (IDX & LIGHT_TWOSIDE) + VB->ColorPtr[1] = &store->LitColor[1]; + + if ( CHECK_COLOR_MATERIAL(j) ) + gl_update_color_material( ctx, *CMcolor ); + + if ( CHECK_MATERIAL(j) ) + gl_update_material( ctx, new_material[j], new_material_mask[j] ); + + if ( CHECK_VALIDATE(j) ) + gl_validate_all_lighting_tables( ctx ); + + do { + do { + GLfloat sum[2][3]; + + COPY_3V(sum[0], ctx->Light._BaseColor[0]); + if (IDX & LIGHT_TWOSIDE) + COPY_3V(sum[1], ctx->Light._BaseColor[1]); + + foreach (light, &ctx->Light.EnabledList) { + GLfloat n_dot_h, n_dot_VP, spec; + + ACC_3V(sum[0], light->_MatAmbient[0]); + if (IDX & LIGHT_TWOSIDE) + ACC_3V(sum[1], light->_MatAmbient[1]); + + n_dot_VP = DOT3(normal, light->_VP_inf_norm); + + if (n_dot_VP > 0.0F) { + ACC_SCALE_SCALAR_3V(sum[0], n_dot_VP, light->_MatDiffuse[0]); + n_dot_h = DOT3(normal, light->_h_inf_norm); + if (n_dot_h > 0.0F) { + struct gl_shine_tab *tab = ctx->_ShineTable[0]; + GET_SHINE_TAB_ENTRY( tab, n_dot_h, spec ); + ACC_SCALE_SCALAR_3V( sum[0], spec, + light->_MatSpecular[0]); + } + } + else if (IDX & LIGHT_TWOSIDE) { + ACC_SCALE_SCALAR_3V(sum[1], -n_dot_VP, light->_MatDiffuse[1]); + n_dot_h = -DOT3(normal, light->_h_inf_norm); + if (n_dot_h > 0.0F) { + struct gl_shine_tab *tab = ctx->_ShineTable[1]; + GET_SHINE_TAB_ENTRY( tab, n_dot_h, spec ); + ACC_SCALE_SCALAR_3V( sum[1], spec, + light->_MatSpecular[1]); + } + } + } + + FLOAT_RGB_TO_CHAN_RGB( Fcolor[j], sum[0] ); + Fcolor[j][3] = sumA[0]; + + if (IDX & LIGHT_TWOSIDE) { + FLOAT_RGB_TO_CHAN_RGB( Bcolor[j], sum[1] ); + Bcolor[j][3] = sumA[1]; + } + + j++; + STRIDE_F(normal, NSTRIDE); + } while (DO_ANOTHER_NORMAL(j)); + + /* Reuse the shading results while there is no change to + * normal or material values. + */ + for ( ; REUSE_LIGHT_RESULTS(j) ; j++ ) { + COPY_CHAN4(Fcolor[j], Fcolor[j-1]); + if (IDX & LIGHT_TWOSIDE) + COPY_CHAN4(Bcolor[j], Bcolor[j-1]); + STRIDE_F(normal, NSTRIDE); + } + + if ( CHECK_COLOR_MATERIAL(j) ) + gl_update_color_material( ctx, CMcolor[j] ); + + if ( CHECK_MATERIAL(j) ) + gl_update_material( ctx, new_material[j], new_material_mask[j] ); + + if ( CHECK_VALIDATE(j) ) + gl_validate_all_lighting_tables( ctx ); + + } while (!CHECK_END_VB(j)); +} + + + + + +/* + * Use current lighting/material settings to compute the color indexes + * for an array of vertices. + * Input: n - number of vertices to light + * side - 0=use front material, 1=use back material + * vertex - array of [n] vertex position in eye coordinates + * normal - array of [n] surface normal vector + * Output: indexResult - resulting array of [n] color indexes + */ +static void TAG(light_ci)( GLcontext *ctx, + struct vertex_buffer *VB, + struct gl_pipeline_stage *stage, + GLvector4f *input ) +{ + struct light_stage_data *store = LIGHT_STAGE_DATA(stage); + GLuint j; + GLuint vstride = input->stride; + const GLfloat *vertex = (GLfloat *) input->data; + GLuint nstride = VB->NormalPtr->stride; + const GLfloat *normal = (GLfloat *)VB->NormalPtr->data; + GLubyte (*CMcolor)[4]; + GLuint CMstride; + GLuint *flags = VB->Flag; + GLuint *indexResult[2]; + struct gl_material (*new_material)[2] = VB->Material; + GLuint *new_material_mask = VB->MaterialMask; + GLuint nr = VB->Count; + + (void) flags; + (void) nstride; + (void) vstride; + + VB->IndexPtr[0] = &store->LitIndex[0]; + if (IDX & LIGHT_TWOSIDE) + VB->IndexPtr[1] = &store->LitIndex[1]; + + indexResult[0] = VB->IndexPtr[0]->data; + indexResult[1] = VB->IndexPtr[1]->data; + + if (IDX & LIGHT_COLORMATERIAL) { + CMcolor = VB->ColorPtr[0]->data; + CMstride = VB->ColorPtr[0]->stride; + } + + /* loop over vertices */ + for ( j=0 ; + j<nr ; + j++,STRIDE_F(vertex,VSTRIDE),STRIDE_F(normal, NSTRIDE), CMSTRIDE) + { + GLfloat diffuse[2], specular[2]; + GLuint side = 0; + struct gl_light *light; + + if ( CHECK_COLOR_MATERIAL(j) ) + gl_update_color_material( ctx, (GLchan *)CMcolor[j] ); + + if ( CHECK_MATERIAL(j) ) + gl_update_material( ctx, new_material[j], new_material_mask[j] ); + + if ( CHECK_VALIDATE(j) ) + gl_validate_all_lighting_tables( ctx ); + + diffuse[0] = specular[0] = 0.0F; + + if ( IDX & LIGHT_TWOSIDE ) { + diffuse[1] = specular[1] = 0.0F; + } + + /* Accumulate diffuse and specular from each light source */ + foreach (light, &ctx->Light.EnabledList) { + + GLfloat attenuation = 1.0F; + GLfloat VP[3]; /* unit vector from vertex to light */ + GLfloat n_dot_VP; /* dot product of l and n */ + GLfloat *h, n_dot_h, correction = 1.0; + + /* compute l and attenuation */ + if (!(light->_Flags & LIGHT_POSITIONAL)) { + /* directional light */ + COPY_3V(VP, light->_VP_inf_norm); + } + else { + GLfloat d; /* distance from vertex to light */ + + SUB_3V(VP, light->_Position, vertex); + + d = LEN_3FV( VP ); + if ( d > 1e-6) { + GLfloat invd = 1.0F / d; + SELF_SCALE_SCALAR_3V(VP, invd); + } + + attenuation = 1.0F / (light->ConstantAttenuation + d * + (light->LinearAttenuation + d * + light->QuadraticAttenuation)); + + /* spotlight attenuation */ + if (light->_Flags & LIGHT_SPOT) { + GLfloat PV_dot_dir = - DOT3(VP, light->_NormDirection); + if (PV_dot_dir<light->_CosCutoff) { + continue; /* this light makes no contribution */ + } + else { + double x = PV_dot_dir * (EXP_TABLE_SIZE-1); + int k = (int) x; + GLfloat spot = (light->_SpotExpTable[k][0] + + (x-k)*light->_SpotExpTable[k][1]); + attenuation *= spot; + } + } + } + + if (attenuation < 1e-3) + continue; /* this light makes no contribution */ + + n_dot_VP = DOT3( normal, VP ); + + /* which side are we lighting? */ + if (n_dot_VP < 0.0F) { + if (!(IDX & LIGHT_TWOSIDE)) + continue; + side = 1; + correction = -1; + n_dot_VP = -n_dot_VP; + } + + /* accumulate diffuse term */ + diffuse[side] += n_dot_VP * light->_dli * attenuation; + + /* specular term */ + if (ctx->Light.Model.LocalViewer) { + GLfloat v[3]; + COPY_3V(v, vertex); + NORMALIZE_3FV(v); + SUB_3V(VP, VP, v); /* h = VP + VPe */ + h = VP; + NORMALIZE_3FV(h); + } + else if (light->_Flags & LIGHT_POSITIONAL) { + h = VP; + ACC_3V(h, ctx->_EyeZDir); + NORMALIZE_3FV(h); + } + else { + h = light->_h_inf_norm; + } + + n_dot_h = correction * DOT3(normal, h); + + if (n_dot_h > 0.0F) + { + GLfloat spec_coef; + struct gl_shine_tab *tab = ctx->_ShineTable[side]; + GET_SHINE_TAB_ENTRY( tab, n_dot_h, spec_coef); + specular[side] += spec_coef * light->_sli * attenuation; + } + } /*loop over lights*/ + + /* Now compute final color index */ + for (side = 0 ; side < NR_SIDES ; side++) { + struct gl_material *mat = &ctx->Light.Material[side]; + GLfloat index; + + if (specular[side] > 1.0F) { + index = mat->SpecularIndex; + } + else { + GLfloat d_a = mat->DiffuseIndex - mat->AmbientIndex; + GLfloat s_a = mat->SpecularIndex - mat->AmbientIndex; + + index = mat->AmbientIndex + + diffuse[side] * (1.0F-specular[side]) * d_a + + specular[side] * s_a; + + if (index > mat->SpecularIndex) { + index = mat->SpecularIndex; + } + } + indexResult[side][j] = (GLuint) (GLint) index; + } + } /*for vertex*/ + + if ( CHECK_COLOR_MATERIAL(j) ) + gl_update_color_material( ctx, CMcolor[j] ); + + if ( CHECK_MATERIAL(j) ) + gl_update_material( ctx, new_material[j], new_material_mask[j] ); + + if ( CHECK_VALIDATE(j) ) + gl_validate_all_lighting_tables( ctx ); +} + + + +static void TAG(init_light_tab)( void ) +{ + _tnl_light_tab[IDX] = TAG(light_rgba); + _tnl_light_fast_tab[IDX] = TAG(light_fast_rgba); + _tnl_light_fast_single_tab[IDX] = TAG(light_fast_rgba_single); + _tnl_light_spec_tab[IDX] = TAG(light_rgba_spec); + _tnl_light_ci_tab[IDX] = TAG(light_ci); +} + + +#undef TAG +#undef IDX +#undef NR_SIDES +#undef NSTRIDE +#undef VSTRIDE +#undef CHECK_MATERIAL +#undef CHECK_END_VB +#undef DO_ANOTHER_NORMAL +#undef REUSE_LIGHT_RESULTS +#undef CMSTRIDE +#undef CHECK_COLOR_MATERIAL +#undef CHECK_VALIDATE diff --git a/src/mesa/tnl/t_vb_normals.c b/src/mesa/tnl/t_vb_normals.c new file mode 100644 index 00000000000..97e7b9bb356 --- /dev/null +++ b/src/mesa/tnl/t_vb_normals.c @@ -0,0 +1,193 @@ +/* $Id: t_vb_normals.c,v 1.1 2000/12/26 05:09:33 keithw Exp $ */ + +/* + * Mesa 3-D graphics library + * Version: 3.5 + * + * Copyright (C) 1999-2000 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 <[email protected]> + */ + + +#include "glheader.h" +#include "colormac.h" +#include "context.h" +#include "macros.h" +#include "mem.h" +#include "mmath.h" +#include "mtypes.h" + +#include "math/m_xform.h" + +#include "t_context.h" +#include "t_pipeline.h" + + + +struct normal_stage_data { + normal_func *NormalTransform; + GLvector3f normal; +}; + +#define NORMAL_STAGE_DATA(stage) ((struct normal_stage_data *)stage->private) + + + + +static GLboolean run_normal_stage( GLcontext *ctx, + struct gl_pipeline_stage *stage ) +{ + struct normal_stage_data *store = NORMAL_STAGE_DATA(stage); + struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb; + + ASSERT(store->NormalTransform); + + if (VB->NormalLengthPtr) { + GLfloat diff = VB->NormalLengthPtr[0] - + 1.0/LEN_3FV(VB->NormalPtr->data[0]); + ASSERT((diff*diff) < .01); + } + + if (stage->changed_inputs) + (store->NormalTransform[0])(&ctx->ModelView, + ctx->_ModelViewInvScale, + VB->NormalPtr, + VB->NormalLengthPtr, + 0, + &store->normal); + + VB->NormalPtr = &store->normal; + return GL_TRUE; +} + + +static GLboolean run_validate_normal_stage( GLcontext *ctx, + struct gl_pipeline_stage *stage) +{ + struct normal_stage_data *store = NORMAL_STAGE_DATA(stage); + + ASSERT(ctx->_NeedNormals); + + if (ctx->_NeedEyeCoords) { + GLuint transform = NORM_TRANSFORM_NO_ROT; + + if (ctx->ModelView.flags & (MAT_FLAG_GENERAL | + MAT_FLAG_ROTATION | + MAT_FLAG_GENERAL_3D | + MAT_FLAG_PERSPECTIVE)) + transform = NORM_TRANSFORM; + + + if (ctx->Transform.Normalize) { + store->NormalTransform = gl_normal_tab[transform | NORM_NORMALIZE]; + } + else if (ctx->Transform.RescaleNormals && + ctx->_ModelViewInvScale != 1.0) { + store->NormalTransform = gl_normal_tab[transform | NORM_RESCALE]; + } + else { + store->NormalTransform = gl_normal_tab[transform]; + } + } + else { + if (ctx->Transform.Normalize) { + store->NormalTransform = gl_normal_tab[NORM_NORMALIZE]; + } + else if (!ctx->Transform.RescaleNormals && + ctx->_ModelViewInvScale != 1.0) { + store->NormalTransform = gl_normal_tab[NORM_RESCALE]; + } + else { + store->NormalTransform = 0; + } + } + + if (store->NormalTransform) { + stage->run = run_normal_stage; + return stage->run( ctx, stage ); + } else { + stage->active = GL_FALSE; /* !!! */ + return GL_TRUE; + } +} + + +static void check_normal_transform( GLcontext *ctx, + struct gl_pipeline_stage *stage ) +{ + stage->active = ctx->_NeedNormals; + /* Don't clobber the initialize function: + */ + if (stage->private) + stage->run = run_validate_normal_stage; +} + + +static GLboolean alloc_normal_data( GLcontext *ctx, + struct gl_pipeline_stage *stage ) +{ + TNLcontext *tnl = TNL_CONTEXT(ctx); + struct normal_stage_data *store; + stage->private = MALLOC(sizeof(*store)); + store = NORMAL_STAGE_DATA(stage); + if (!store) + return GL_FALSE; + + gl_vector3f_alloc( &store->normal, 0, tnl->vb.Size, 32 ); + + /* Now run the stage. + */ + stage->run = run_validate_normal_stage; + return stage->run( ctx, stage ); +} + + + +static void free_normal_data( struct gl_pipeline_stage *stage ) +{ + struct normal_stage_data *store = NORMAL_STAGE_DATA(stage); + if (store) { + gl_vector3f_free( &store->normal ); + FREE( store ); + stage->private = 0; + } +} + +#define _TNL_NEW_NORMAL_TRANSFORM (_NEW_MODELVIEW| \ + _NEW_TRANSFORM| \ + _MESA_NEW_NEED_NORMALS| \ + _MESA_NEW_NEED_EYE_COORDS) + + + +const struct gl_pipeline_stage _tnl_normal_transform_stage = +{ + "normal transform", + _TNL_NEW_NORMAL_TRANSFORM, /* re-check */ + _TNL_NEW_NORMAL_TRANSFORM, /* re-run */ + 0,VERT_NORM,VERT_NORM, /* active, inputs, outputs */ + 0, 0, /* changed_inputs, private */ + free_normal_data, /* destructor */ + check_normal_transform, /* check */ + alloc_normal_data /* run -- initially set to alloc */ +}; + diff --git a/src/mesa/tnl/t_vb_points.c b/src/mesa/tnl/t_vb_points.c new file mode 100644 index 00000000000..16f9ca9722f --- /dev/null +++ b/src/mesa/tnl/t_vb_points.c @@ -0,0 +1,124 @@ +/* $Id: t_vb_points.c,v 1.1 2000/12/26 05:09:33 keithw Exp $ */ + +/* + * Mesa 3-D graphics library + * Version: 3.5 + * + * Copyright (C) 1999-2000 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: + * Brian Paul <[email protected]> + */ + +#include "mtypes.h" +#include "mem.h" +#include "t_context.h" +#include "t_pipeline.h" + + +struct point_stage_data { + GLvector1f PointSize; +}; + +#define POINT_STAGE_DATA(stage) ((struct point_stage_data *)stage->private) + + +/* + * Compute attenuated point sizes + */ +static GLboolean run_point_stage( GLcontext *ctx, + struct gl_pipeline_stage *stage ) +{ + struct point_stage_data *store = POINT_STAGE_DATA(stage); + struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb; + const GLfloat (*eye)[4] = (const GLfloat (*)[4]) VB->EyePtr->data; + const GLfloat p0 = ctx->Point.Params[0]; + const GLfloat p1 = ctx->Point.Params[1]; + const GLfloat p2 = ctx->Point.Params[2]; + const GLfloat pointSize = ctx->Point._Size; + GLfloat *size = store->PointSize.data; + GLuint i; + + if (stage->changed_inputs) { + /* XXX do threshold and min/max clamping here? */ + for (i = 0; i < VB->Count; i++) { + const GLfloat dist = -eye[i][2]; + /* GLfloat dist = GL_SQRT(pos[0]*pos[0]+pos[1]*pos[1]+pos[2]*pos[2]);*/ + size[i] = pointSize / (p0 + dist * (p1 + dist * p2)); + } + } + + VB->PointSizePtr = &store->PointSize; + + return GL_TRUE; +} + + +/* If point size attenuation is on we'll compute the point size for + * each vertex in a special pipeline stage. + */ +static void check_point_size( GLcontext *ctx, struct gl_pipeline_stage *d ) +{ + d->active = ctx->Point._Attenuated; +} + +static GLboolean alloc_point_data( GLcontext *ctx, + struct gl_pipeline_stage *stage ) +{ + struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb; + struct point_stage_data *store; + stage->private = MALLOC(sizeof(*store)); + store = POINT_STAGE_DATA(stage); + if (!store) + return GL_FALSE; + + gl_vector1f_alloc( &store->PointSize, 0, VB->Size, 32 ); + + /* Now run the stage. + */ + stage->run = run_point_stage; + return stage->run( ctx, stage ); +} + + +static void free_point_data( struct gl_pipeline_stage *stage ) +{ + struct point_stage_data *store = POINT_STAGE_DATA(stage); + if (store) { + gl_vector1f_free( &store->PointSize ); + FREE( store ); + stage->private = 0; + } +} + +const struct gl_pipeline_stage _tnl_point_attenuation_stage = +{ + "point size attenuation", /* name */ + _NEW_POINT, /* build_state_change */ + _NEW_POINT, /* run_state_change */ + 0, /* active */ + VERT_EYE, /* inputs */ + VERT_POINT_SIZE, /* outputs */ + 0, /* changed_inputs (temporary value) */ + 0, /* stage private data */ + free_point_data, /* destructor */ + check_point_size, /* check */ + alloc_point_data /* run -- initially set to alloc data */ +}; diff --git a/src/mesa/tnl/t_vb_render.c b/src/mesa/tnl/t_vb_render.c new file mode 100644 index 00000000000..5707f21c901 --- /dev/null +++ b/src/mesa/tnl/t_vb_render.c @@ -0,0 +1,698 @@ +/* $Id: t_vb_render.c,v 1.1 2000/12/26 05:09:33 keithw Exp $ */ + +/* + * Mesa 3-D graphics library + * Version: 3.5 + * + * Copyright (C) 1999-2000 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. + */ + + +/* + * Render whole vertex buffers, including projection of vertices from + * clip space and clipping of primitives. + * + * This file makes calls to project vertices and to the point, line + * and triangle rasterizers via the function pointers: + * + * context->Driver.BuildProjectedVertices() + * context->Driver.PointsFunc() + * context->Driver.LineFunc() + * context->Driver.TriangleFunc() + * context->Driver.QuadFunc() + * + */ + + +#include "glheader.h" +#include "context.h" +#include "colormac.h" +#include "macros.h" +#include "mem.h" +#include "mtypes.h" +#include "mmath.h" + +#include "math/m_matrix.h" +#include "math/m_xform.h" + +#include "t_pipeline.h" + + +typedef GLuint (*interp_func)( GLcontext *ctx, + GLfloat t, GLuint in, GLuint out, + GLboolean force_boundary ); + +typedef void (*clip_line_func)( GLcontext *ctx, + GLuint i, GLuint j, + GLubyte mask); + +typedef void (*clip_poly_func)( GLcontext *ctx, + GLuint n, GLuint vlist[], + GLuint pv, GLubyte mask ); + + +typedef void (*render_func)( GLcontext *ctx, + GLuint start, + GLuint count, + GLuint flags ); + + + +struct render_stage_data { + + /* Clipping functions for current state. + */ + interp_func interp; /* Clip interpolation function */ + GLuint _ClipInputs; /* Inputs referenced by interpfunc */ + +}; + +#define RENDER_STAGE_DATA(stage) ((struct render_stage_data *)stage->private) + +static void render_poly_pv_raw_elts( GLcontext *ctx, + GLuint start, + GLuint count, + GLuint flags, + GLuint pv ); + +/**********************************************************************/ +/* Interpolate between pairs of vertices */ +/**********************************************************************/ + + +#define INTERP_RGBA 0x1 +#define INTERP_TEX 0x2 +#define INTERP_INDEX 0x4 +#define INTERP_SPEC 0x8 +#define INTERP_FOG 0x10 +#define INTERP_EDGE 0x20 +#define MAX_INTERP 0x40 + + +#define LINTERP_SZ( t, vec, to, a, b, sz ) \ +do { \ + switch (sz) { \ + case 4: vec[to][3] = LINTERP( t, vec[a][3], vec[b][3] ); \ + case 3: vec[to][2] = LINTERP( t, vec[a][2], vec[b][2] ); \ + case 2: vec[to][1] = LINTERP( t, vec[a][1], vec[b][1] ); \ + case 1: vec[to][0] = LINTERP( t, vec[a][0], vec[b][0] ); \ + } \ +} while(0) + + +#if 1 + +#define LINTERP_RGBA(nr, t, out, a, b) { \ + int i; \ + for (i = 0; i < nr; i++) { \ + GLfloat fa = CHAN_TO_FLOAT(a[i]); \ + GLfloat fb = CHAN_TO_FLOAT(b[i]); \ + GLfloat fo = LINTERP(t, fa, fb); \ + FLOAT_COLOR_TO_CHAN(out[i], fo); \ + } \ +} + +#else + +#define LINTERP_RGBA(nr, t, out, a, b) { \ + int n; \ + const GLuint ti = FloatToInt(t*256.0F); \ + const GLubyte *Ib = (const GLubyte *)&a[0]; \ + const GLubyte *Jb = (const GLubyte *)&b[0]; \ + GLubyte *Ob = (GLubyte *)&out[0]; \ + \ + for (n = 0 ; n < nr ; n++) \ + Ob[n] = (GLubyte) (Ib[n] + ((ti * (Jb[n] - Ib[n]))/256)); \ +} + +#endif + + + +static interp_func interp_tab[0x80]; + + +#define IND (INTERP_RGBA) +#define NAME interp_RGBA +#include "t_vb_interptmp.h" + +#define IND (INTERP_RGBA|INTERP_SPEC) +#define NAME interp_RGBA_SPEC +#include "t_vb_interptmp.h" + +#define IND (INTERP_RGBA|INTERP_FOG) +#define NAME interp_RGBA_FOG +#include "t_vb_interptmp.h" + +#define IND (INTERP_RGBA|INTERP_SPEC|INTERP_FOG) +#define NAME interp_RGBA_SPEC_FOG +#include "t_vb_interptmp.h" + +#define IND (INTERP_RGBA|INTERP_TEX) +#define NAME interp_RGBA_TEX +#include "t_vb_interptmp.h" + +#define IND (INTERP_RGBA|INTERP_SPEC|INTERP_TEX) +#define NAME interp_RGBA_SPEC_TEX +#include "t_vb_interptmp.h" + +#define IND (INTERP_RGBA|INTERP_FOG|INTERP_TEX) +#define NAME interp_RGBA_FOG_TEX +#include "t_vb_interptmp.h" + +#define IND (INTERP_RGBA|INTERP_SPEC|INTERP_FOG|INTERP_TEX) +#define NAME interp_RGBA_SPEC_FOG_TEX +#include "t_vb_interptmp.h" + +#define IND (INTERP_INDEX) +#define NAME interp_INDEX +#include "t_vb_interptmp.h" + +#define IND (INTERP_FOG|INTERP_INDEX) +#define NAME interp_FOG_INDEX +#include "t_vb_interptmp.h" + +#define IND (INTERP_TEX|INTERP_INDEX) +#define NAME interp_TEX_INDEX +#include "t_vb_interptmp.h" + +#define IND (INTERP_FOG|INTERP_TEX|INTERP_INDEX) +#define NAME interp_FOG_TEX_INDEX +#include "t_vb_interptmp.h" + +#define IND (INTERP_RGBA|INTERP_EDGE) +#define NAME interp_RGBA_EDGE +#include "t_vb_interptmp.h" + +#define IND (INTERP_RGBA|INTERP_SPEC|INTERP_EDGE) +#define NAME interp_RGBA_SPEC_EDGE +#include "t_vb_interptmp.h" + +#define IND (INTERP_RGBA|INTERP_FOG|INTERP_EDGE) +#define NAME interp_RGBA_FOG_EDGE +#include "t_vb_interptmp.h" + +#define IND (INTERP_RGBA|INTERP_SPEC|INTERP_FOG|INTERP_EDGE) +#define NAME interp_RGBA_SPEC_FOG_EDGE +#include "t_vb_interptmp.h" + +#define IND (INTERP_RGBA|INTERP_TEX|INTERP_EDGE) +#define NAME interp_RGBA_TEX_EDGE +#include "t_vb_interptmp.h" + +#define IND (INTERP_RGBA|INTERP_SPEC|INTERP_TEX|INTERP_EDGE) +#define NAME interp_RGBA_SPEC_TEX_EDGE +#include "t_vb_interptmp.h" + +#define IND (INTERP_RGBA|INTERP_FOG|INTERP_TEX|INTERP_EDGE) +#define NAME interp_RGBA_FOG_TEX_EDGE +#include "t_vb_interptmp.h" + +#define IND (INTERP_RGBA|INTERP_SPEC|INTERP_FOG|INTERP_TEX|INTERP_EDGE) +#define NAME interp_RGBA_SPEC_FOG_TEX_EDGE +#include "t_vb_interptmp.h" + +#define IND (INTERP_INDEX|INTERP_EDGE) +#define NAME interp_INDEX_EDGE +#include "t_vb_interptmp.h" + +#define IND (INTERP_FOG|INTERP_INDEX|INTERP_EDGE) +#define NAME interp_FOG_INDEX_EDGE +#include "t_vb_interptmp.h" + +#define IND (INTERP_TEX|INTERP_INDEX|INTERP_EDGE) +#define NAME interp_TEX_INDEX_EDGE +#include "t_vb_interptmp.h" + +#define IND (INTERP_FOG|INTERP_TEX|INTERP_INDEX|INTERP_EDGE) +#define NAME interp_FOG_TEX_INDEX_EDGE +#include "t_vb_interptmp.h" + + + +static GLuint interp_invalid( GLcontext *ctx, + GLfloat t, + GLuint in, GLuint out, + GLboolean boundary ) +{ + (void)(ctx && t && in && out && boundary); + fprintf(stderr, "Invalid interpolation function in t_vbrender.c\n"); + return in; +} + + +static void interp_init( void ) +{ + GLuint i; + + /* Use the maximal function as the default. I don't believe any of + * the non-implemented combinations are reachable, but this gives + * some safety from crashes. + */ + for (i = 0 ; i < Elements(interp_tab) ; i++) + interp_tab[i] = interp_invalid; + + interp_tab[INTERP_RGBA] = interp_RGBA; + interp_tab[INTERP_RGBA|INTERP_SPEC] = interp_RGBA_SPEC; + interp_tab[INTERP_RGBA|INTERP_FOG] = interp_RGBA_FOG; + interp_tab[INTERP_RGBA|INTERP_SPEC|INTERP_FOG] = interp_RGBA_SPEC_FOG; + interp_tab[INTERP_RGBA|INTERP_TEX] = interp_RGBA_TEX; + interp_tab[INTERP_RGBA|INTERP_SPEC|INTERP_TEX] = interp_RGBA_SPEC_TEX; + interp_tab[INTERP_RGBA|INTERP_FOG|INTERP_TEX] = interp_RGBA_FOG_TEX; + interp_tab[INTERP_RGBA|INTERP_SPEC|INTERP_FOG|INTERP_TEX] = interp_RGBA_SPEC_FOG_TEX; + interp_tab[INTERP_INDEX] = interp_INDEX; + interp_tab[INTERP_FOG|INTERP_INDEX] = interp_FOG_INDEX; + interp_tab[INTERP_TEX|INTERP_INDEX] = interp_TEX_INDEX; + interp_tab[INTERP_FOG|INTERP_TEX|INTERP_INDEX] = interp_FOG_TEX_INDEX; + interp_tab[INTERP_RGBA|INTERP_EDGE] = interp_RGBA_EDGE; + interp_tab[INTERP_RGBA|INTERP_SPEC|INTERP_EDGE] = interp_RGBA_SPEC_EDGE; + interp_tab[INTERP_RGBA|INTERP_FOG|INTERP_EDGE] = interp_RGBA_FOG_EDGE; + interp_tab[INTERP_RGBA|INTERP_SPEC|INTERP_FOG|INTERP_EDGE] = interp_RGBA_SPEC_FOG_EDGE; + interp_tab[INTERP_RGBA|INTERP_TEX|INTERP_EDGE] = interp_RGBA_TEX_EDGE; + interp_tab[INTERP_RGBA|INTERP_SPEC|INTERP_TEX|INTERP_EDGE] = interp_RGBA_SPEC_TEX_EDGE; + interp_tab[INTERP_RGBA|INTERP_FOG|INTERP_TEX|INTERP_EDGE] = interp_RGBA_FOG_TEX_EDGE; + interp_tab[INTERP_RGBA|INTERP_SPEC|INTERP_FOG|INTERP_TEX|INTERP_EDGE] = interp_RGBA_SPEC_FOG_TEX_EDGE; + interp_tab[INTERP_INDEX|INTERP_EDGE] = interp_INDEX_EDGE; + interp_tab[INTERP_FOG|INTERP_INDEX|INTERP_EDGE] = interp_FOG_INDEX_EDGE; + interp_tab[INTERP_TEX|INTERP_INDEX|INTERP_EDGE] = interp_TEX_INDEX_EDGE; + interp_tab[INTERP_FOG|INTERP_TEX|INTERP_INDEX|INTERP_EDGE] = interp_FOG_TEX_INDEX_EDGE; +} + + +/**********************************************************************/ +/* Clip single primitives */ +/**********************************************************************/ + + +#if 0 +#define NEGATIVE(x) ((*(int *)&x)<0) +#define DIFFERENT_SIGNS(a,b) ((a*b) < 0) +#else +#define NEGATIVE(x) (x < 0) +#define DIFFERENT_SIGNS(a,b) ((a*b) < 0) +#endif + +#define W(i) coord[i][3] +#define Z(i) coord[i][2] +#define Y(i) coord[i][1] +#define X(i) coord[i][0] +#define SIZE 4 +#define TAG(x) x##_4 +#include "t_vb_cliptmp.h" + +#define W(i) 1.0 +#define Z(i) coord[i][2] +#define Y(i) coord[i][1] +#define X(i) coord[i][0] +#define SIZE 3 +#define TAG(x) x##_3 +#include "t_vb_cliptmp.h" + +#define W(i) 1.0 +#define Z(i) 0.0 +#define Y(i) coord[i][1] +#define X(i) coord[i][0] +#define SIZE 2 +#define TAG(x) x##_2 +#include "t_vb_cliptmp.h" + +static clip_poly_func clip_poly_tab[5] = { + 0, + 0, + viewclip_polygon_2, + viewclip_polygon_3, + viewclip_polygon_4 +}; + +static clip_line_func clip_line_tab[5] = { + 0, + 0, + viewclip_line_2, + viewclip_line_3, + viewclip_line_4 +}; + + + +/**********************************************************************/ +/* Clip and render single primitives */ +/**********************************************************************/ + + + +static INLINE void draw_line(GLcontext *ctx, GLuint v1, GLuint v2 ) +{ + struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb; + GLubyte c1 = VB->ClipMask[v1], c2 = VB->ClipMask[v2]; + GLubyte ormask = c1|c2; + if (!ormask) + ctx->Driver.LineFunc( ctx, v1, v2, v2 ); + else if (!(c1 & c2 & 0x3f)) + clip_line_tab[VB->ClipPtr->size]( ctx, v1, v2, ormask ); +} + +static INLINE void draw_triangle(GLcontext *ctx, + GLuint v1, GLuint v2, GLuint v3, + GLuint pv ) +{ + struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb; + GLubyte c1 = VB->ClipMask[v1], c2 = VB->ClipMask[v2], c3 = VB->ClipMask[v3]; + GLubyte ormask = c1|c2|c3; + if (!ormask) + ctx->Driver.TriangleFunc( ctx, v1, v2, v3, pv ); + else if (!(c1 & c2 & c3 & 0x3f)) { + GLuint vlist[MAX_CLIPPED_VERTICES]; + ASSIGN_3V(vlist, v1, v2, v3 ); + clip_poly_tab[VB->ClipPtr->size]( ctx, 3, vlist, pv, ormask ); + } +} + + +static INLINE void draw_quad( GLcontext *ctx, + GLuint v1, GLuint v2, GLuint v3, + GLuint v4, GLuint pv ) +{ + struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb; + GLubyte c1 = VB->ClipMask[v1], c2 = VB->ClipMask[v2]; + GLubyte c3 = VB->ClipMask[v3], c4 = VB->ClipMask[v4]; + GLubyte ormask = c1|c2|c3|c4; + if (!ormask) + ctx->Driver.QuadFunc( ctx, v1, v2, v3, v4, pv ); + else if (!(c1 & c2 & c3 & c4 & 0x3f)) { + GLuint vlist[MAX_CLIPPED_VERTICES]; + ASSIGN_4V(vlist, v1, v2, v3, v4 ); + clip_poly_tab[VB->ClipPtr->size]( ctx, 4, vlist, pv, ormask ); + } +} + + +/**********************************************************************/ +/* Clip and render whole begin/end objects */ +/**********************************************************************/ + +#define NEED_EDGEFLAG_SETUP (ctx->_TriangleCaps & DD_TRI_UNFILLED) +#define EDGEFLAG_GET(idx) VB->EdgeFlagPtr->data[idx] +#define EDGEFLAG_SET(idx, val) VB->EdgeFlagPtr->data[idx] = val + + +/* Vertices, no clipping. + */ +#define RENDER_POINTS( start, count ) \ + ctx->Driver.PointsFunc( ctx, start, count-1 ) + +#define RENDER_LINE( i1, i ) \ + ctx->Driver.LineFunc( ctx, i1, i, i ) + +#define RENDER_TRI( i2, i1, i, pv, parity ) \ +do { \ + if (parity) \ + ctx->Driver.TriangleFunc( ctx, i1, i2, i, pv ); \ + else \ + ctx->Driver.TriangleFunc( ctx, i2, i1, i, pv ); \ +} while (0) + +#define RENDER_QUAD( i3, i2, i1, i, pv ) \ + ctx->Driver.QuadFunc( ctx, i3, i2, i1, i, pv ); + +#define TAG(x) x##_raw + +#define LOCAL_VARS \ + struct vertex_buffer *VB = &(TNL_CONTEXT(ctx)->vb); \ + (void) VB; + +#define RESET_STIPPLE ctx->Driver.ResetLineStipple( ctx ) +#define RESET_OCCLUSION ctx->OcclusionResult = GL_TRUE; +#define PRESERVE_VB_DEFS +#include "t_vb_rendertmp.h" + + +/* Elts, no clipping. + */ +#undef ELT +#undef TAG +#undef LOCAL_VARS +#define TAG(x) x##_raw_elts +#define ELT(x) elt[x] +#define LOCAL_VARS \ + struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb; \ + const GLuint * const elt = VB->Elts; \ + (void) elt; +#include "t_vb_rendertmp.h" + + + + +/* Vertices, with the possibility of clipping. + */ +#define RENDER_POINTS( start, count ) \ + ctx->Driver.PointsFunc( ctx, start, count-1 ) + +#define RENDER_LINE( i1, i ) \ + draw_line( ctx, i1, i ) + +#define RENDER_TRI( i2, i1, i, pv, parity) \ +do { \ + GLuint e2=i2, e1=i1; \ + if (parity) { GLuint t=e2; e2=e1; e1=t; } \ + draw_triangle(ctx,e2,e1,i,pv); \ +} while (0) + +#define RENDER_QUAD( i3, i2, i1, i, pv) \ + draw_quad(ctx,i3,i2,i1,i,pv) + + +#define LOCAL_VARS \ + struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb; \ + (void)VB; + +#define TAG(x) x##_clipped +#define RESET_STIPPLE ctx->Driver.ResetLineStipple( ctx ) +#define RESET_OCCLUSION ctx->OcclusionResult = GL_TRUE; +#define PRESERVE_VB_DEFS +#include "t_vb_rendertmp.h" + + + +/* Elts, with the possibility of clipping. + */ +#undef ELT +#undef TAG +#undef LOCAL_VARS +#define ELT(x) elt[x] +#define LOCAL_VARS \ + struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb; \ + const GLuint * const elt = VB->Elts; \ + (void) elt; +#define TAG(x) x##_clipped_elts + +#include "t_vb_rendertmp.h" + + + +/**********************************************************************/ +/* Clip and render whole vertex buffers */ +/**********************************************************************/ + + +static GLboolean run_render( GLcontext *ctx, + struct gl_pipeline_stage *stage ) +{ + TNLcontext *tnl = TNL_CONTEXT(ctx); + struct vertex_buffer *VB = &tnl->vb; + GLuint new_inputs = stage->changed_inputs; + render_func *tab; + GLint pass = 0; + + VB->interpfunc = (void *)RENDER_STAGE_DATA(stage)->interp; + + if (new_inputs) { + GLuint importable = new_inputs & VB->importable_data; + GLuint interested = 0; + + if (VB->ClipOrMask) + interested = ~0; + + if (ctx->_TriangleCaps & DD_TRI_UNFILLED) + interested |= VERT_EDGE; + + importable &= interested; + + if (importable) + VB->import_data( ctx, importable, VEC_NOT_WRITEABLE|VEC_BAD_STRIDE); + + if (ctx->Driver.BuildProjectedVertices) + ctx->Driver.BuildProjectedVertices( ctx, 0, VB->Count, new_inputs); + } + + /* Rendering is considered a side-effect, and must be repeated each + * time the stage is run, even if no inputs have changed. + */ + if (VB->Elts) { + tab = VB->ClipOrMask ? render_tab_clipped_elts : render_tab_raw_elts; + } else { + tab = VB->ClipOrMask ? render_tab_clipped : render_tab_raw; + } + + if (ctx->Driver.RenderStart) + ctx->Driver.RenderStart( ctx ); + + do + { + GLuint i, length, flags = 0; + for (i = 0 ; !(flags & PRIM_LAST) ; i += length) + { + flags = VB->Primitive[i]; + length= VB->PrimitiveLength[i]; + ASSERT(length || (flags & PRIM_LAST)); + ASSERT((flags & PRIM_MODE_MASK) <= GL_POLYGON+1); + if (length) + tab[flags & PRIM_MODE_MASK]( ctx, i, i + length, flags ); + } + } while (ctx->Driver.MultipassFunc && + ctx->Driver.MultipassFunc( ctx, ++pass )); + + if (ctx->Driver.RenderFinish) + ctx->Driver.RenderFinish( ctx ); + + return GL_FALSE; /* finished the pipe */ +} + + +/**********************************************************************/ +/* Render pipeline stage */ +/**********************************************************************/ + + + +/* Quite a bit of work involved in finding out the inputs for the + * render stage. This function also identifies which vertex + * interpolation function to use, as these are essentially the same + * question. + */ +static void check_render( GLcontext *ctx, struct gl_pipeline_stage *stage ) +{ + struct render_stage_data *store = RENDER_STAGE_DATA(stage); + GLuint interp = 0; + GLuint inputs = VERT_CLIP; + GLuint i; + + if (ctx->Visual.RGBAflag) + { + interp |= INTERP_RGBA; + inputs |= VERT_RGBA; + + if (ctx->_TriangleCaps & DD_SEPERATE_SPECULAR) { + interp |= INTERP_SPEC; + inputs |= VERT_SPEC_RGB; + } + + if (ctx->Texture._ReallyEnabled) { + interp |= INTERP_TEX; + + for (i = 0 ; i < ctx->Const.MaxTextureUnits ; i++) { + if (ctx->Texture.Unit[i]._ReallyEnabled) + inputs |= VERT_TEX(i); + } + } + } + else if (ctx->Light.ShadeModel==GL_SMOOTH) + { + interp |= INTERP_INDEX; + inputs |= VERT_INDEX; + } + + if (ctx->Point._Attenuated) + inputs |= VERT_POINT_SIZE; + + /* How do drivers turn this off? + */ + if (ctx->Fog.Enabled) { + interp |= INTERP_FOG; + inputs |= VERT_FOG_COORD; + } + + if (ctx->_TriangleCaps & DD_TRI_UNFILLED) { + inputs |= VERT_EDGE; + } + + if (ctx->RenderMode==GL_FEEDBACK) { + interp |= INTERP_TEX; + inputs |= VERT_TEX_ANY; + } + + store->interp = interp_tab[interp]; + stage->inputs = inputs; +} + + +/* Called the first time stage->check() is invoked. + */ +static void alloc_render_data( GLcontext *ctx, + struct gl_pipeline_stage *stage ) +{ + struct render_stage_data *store; + static GLboolean first_time = 1; + + if (first_time) { + interp_init(); + first_time = 0; + } + + stage->private = MALLOC(sizeof(*store)); + if (!stage->private) + return; + + /* Now do the check. + */ + stage->check = check_render; + stage->check( ctx, stage ); +} + + + +static void dtr( struct gl_pipeline_stage *stage ) +{ + struct render_stage_data *store = RENDER_STAGE_DATA(stage); + if (store) { + FREE( store ); + stage->private = 0; + } +} + + +const struct gl_pipeline_stage _tnl_render_stage = +{ + "render", + (_NEW_BUFFERS | + _DD_NEW_SEPERATE_SPECULAR | + _NEW_TEXTURE| + _NEW_LIGHT| + _NEW_POINT| + _NEW_FOG| + _DD_NEW_TRI_UNFILLED | + _NEW_RENDERMODE), /* re-check (new inputs, interp function) */ + 0, /* re-run (always runs) */ + GL_TRUE, /* active */ + 0, 0, /* inputs (set in check_render), outputs */ + 0, 0, /* changed_inputs, private */ + dtr, /* destructor */ + alloc_render_data, /* check - initially set to alloc data */ + run_render /* run */ +}; diff --git a/src/mesa/tnl/t_vb_rendertmp.h b/src/mesa/tnl/t_vb_rendertmp.h new file mode 100644 index 00000000000..de8adb23ec5 --- /dev/null +++ b/src/mesa/tnl/t_vb_rendertmp.h @@ -0,0 +1,452 @@ +/* $Id: t_vb_rendertmp.h,v 1.1 2000/12/26 05:09:33 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 <[email protected]> + */ + + +#ifndef POSTFIX +#define POSTFIX +#endif + +#ifndef INIT +#define INIT(x) +#endif + +#ifndef NEED_EDGEFLAG_SETUP +#define NEED_EDGEFLAG_SETUP 0 +#define EDGEFLAG_GET(a) 0 +#define EDGEFLAG_SET(a,b) +#endif + +#ifndef RESET_STIPPLE +#define RESET_STIPPLE +#endif + +#ifndef RESET_OCCLUSION +#define RESET_OCCLUSION +#endif + +#ifndef TEST_PRIM_END +#define TEST_PRIM_END(flags) (flags & PRIM_END) +#define TEST_PRIM_BEGIN(flags) (flags & PRIM_BEGIN) +#define TEST_PRIM_PARITY(flags) (flags & PRIM_PARITY) +#endif + +#ifndef ELT +#define ELT(x) x +#endif + +static void TAG(render_points)( GLcontext *ctx, + GLuint start, + GLuint count, + GLuint flags ) +{ + LOCAL_VARS; + (void) flags; + + RESET_OCCLUSION; + INIT(GL_POINTS); + RENDER_POINTS( start, count ); + POSTFIX; +} + +static void TAG(render_lines)( GLcontext *ctx, + GLuint start, + GLuint count, + GLuint flags ) +{ + GLuint j; + LOCAL_VARS; + (void) flags; + + RESET_OCCLUSION; + INIT(GL_LINES); + for (j=start+1; j<count; j+=2 ) { + RENDER_LINE( ELT(j-1), ELT(j) ); + RESET_STIPPLE; + } + POSTFIX; +} + + +static void TAG(render_line_strip)( GLcontext *ctx, + GLuint start, + GLuint count, + GLuint flags ) +{ + GLuint j; + LOCAL_VARS; + (void) flags; + + RESET_OCCLUSION; + INIT(GL_LINES); + + for (j=start+1; j<count; j++ ) { + RENDER_LINE( ELT(j-1), ELT(j) ); + } + + if (TEST_PRIM_END(flags)) + RESET_STIPPLE; + + POSTFIX; +} + + +static void TAG(render_line_loop)( GLcontext *ctx, + GLuint start, + GLuint count, + GLuint flags ) +{ + GLuint i; + LOCAL_VARS; + + (void) flags; + + RESET_OCCLUSION; + INIT(GL_LINES); + + if (start+1 < count) { + if (TEST_PRIM_BEGIN(flags)) { + RENDER_LINE( ELT(start), ELT(start+1) ); + } + + for ( i = start+2 ; i < count ; i++) { + RENDER_LINE( ELT(i-1), ELT(i) ); + } + + if ( TEST_PRIM_END(flags)) { + RENDER_LINE( ELT(count-1), ELT(start) ); + RESET_STIPPLE; + } + } + + POSTFIX; +} + + +static void TAG(render_triangles)( GLcontext *ctx, + GLuint start, + GLuint count, + GLuint flags ) +{ + GLuint j; + LOCAL_VARS; + (void) flags; + + INIT(GL_POLYGON); + if (NEED_EDGEFLAG_SETUP) { + for (j=start+2; j<count; j+=3) { + /* Leave the edgeflags as supplied by the user. + */ + RENDER_TRI( ELT(j-2), ELT(j-1), ELT(j), ELT(j), 0 ); + RESET_STIPPLE; + } + } else { + for (j=start+2; j<count; j+=3) { + RENDER_TRI( ELT(j-2), ELT(j-1), ELT(j), ELT(j), 0 ); + } + } + POSTFIX; +} + + + +static void TAG(render_tri_strip)( GLcontext *ctx, + GLuint start, + GLuint count, + GLuint flags ) +{ + GLuint j; + GLuint parity = 0; + LOCAL_VARS; + + if (TEST_PRIM_PARITY(flags)) + parity = 1; + + INIT(GL_POLYGON); + if (NEED_EDGEFLAG_SETUP) { + for (j=start+2;j<count;j++,parity^=1) { + /* All edges are boundary. Set edgeflags to 1, draw the + * triangle, and restore them to the original values. + */ + GLuint ej2 = ELT(j-2); + GLuint ej1 = ELT(j-1); + GLuint ej = ELT(j); + GLboolean ef2 = EDGEFLAG_GET( ej2 ); + GLboolean ef1 = EDGEFLAG_GET( ej1 ); + GLboolean ef = EDGEFLAG_GET( ej ); + EDGEFLAG_SET( ej2, GL_TRUE ); + EDGEFLAG_SET( ej1, GL_TRUE ); + EDGEFLAG_SET( ej, GL_TRUE ); + RENDER_TRI( ej2, ej1, ej, ej, parity ); + EDGEFLAG_SET( ej2, ef2 ); + EDGEFLAG_SET( ej1, ef1 ); + EDGEFLAG_SET( ej, ef ); + RESET_STIPPLE; + } + } else { + for (j=start+2;j<count;j++,parity^=1) { + RENDER_TRI( ELT(j-2), ELT(j-1), ELT(j), ELT(j), parity ); + } + } + POSTFIX; +} + + +static void TAG(render_tri_fan)( GLcontext *ctx, + GLuint start, + GLuint count, + GLuint flags ) +{ + GLuint j; + LOCAL_VARS; + (void) flags; + + INIT(GL_POLYGON); + if (NEED_EDGEFLAG_SETUP) { + for (j=start+2;j<count;j++) { + /* For trifans, all edges are boundary. + */ + GLuint ejs = ELT(start); + GLuint ej1 = ELT(j-1); + GLuint ej = ELT(j); + GLboolean efs = EDGEFLAG_GET( ejs ); + GLboolean ef1 = EDGEFLAG_GET( ej1 ); + GLboolean ef = EDGEFLAG_GET( ej ); + EDGEFLAG_SET( ejs, GL_TRUE ); + EDGEFLAG_SET( ej1, GL_TRUE ); + EDGEFLAG_SET( ej, GL_TRUE ); + RENDER_TRI( ejs, ej1, ej, ej, 0); + EDGEFLAG_SET( ejs, efs ); + EDGEFLAG_SET( ej1, ef1 ); + EDGEFLAG_SET( ej, ef ); + RESET_STIPPLE; + } + } else { + for (j=start+2;j<count;j++) { + RENDER_TRI( ELT(start), ELT(j-1), ELT(j), ELT(j), 0 ); + } + } + + POSTFIX; +} + + +/* This is a bit of a hack. Clipping produces polygons and really + * wants to use this function to render them (in particular to get the + * edgeflags right). However, the rule that pv==start for polys + * doens't hold there, hence the extra arg and the wrapper below. + */ +static void TAG(render_poly_pv)( GLcontext *ctx, + GLuint start, + GLuint count, + GLuint flags, + GLuint pv ) +{ + GLuint j = start+2; + LOCAL_VARS; + (void) flags; + + INIT(GL_POLYGON); + if (NEED_EDGEFLAG_SETUP) { + if (start+3 < count) { + GLboolean efstart = EDGEFLAG_GET( ELT(start) ); + GLboolean efcount = EDGEFLAG_GET( ELT(count-1) ); + + + /* If the primitive does not begin here, the first edge + * is non-boundary. + */ + if (!TEST_PRIM_BEGIN(flags)) + EDGEFLAG_SET( ELT(start), GL_FALSE ); + + /* If the primitive does not end here, the final edge is + * non-boundary. + */ + if (!TEST_PRIM_END(flags)) + EDGEFLAG_SET( ELT(count-1), GL_FALSE ); + + /* Draw the first triangle (possibly also the last). + */ + if (j<count) { + GLboolean ef = EDGEFLAG_GET( ELT(j) ); + EDGEFLAG_SET( ELT(j), GL_FALSE ); + RENDER_TRI( ELT(start), ELT(j-1), ELT(j), ELT(pv), 0 ); + EDGEFLAG_SET( ELT(j), ef ); + j++; + } + + /* For internal tris, the first and last edges are non-boundary. + */ + EDGEFLAG_SET( ELT(start), GL_FALSE ); + for (;j<count-1;j++) { + GLboolean ef = EDGEFLAG_GET( ELT(j) ); + EDGEFLAG_SET( ELT(j), GL_FALSE ); + RENDER_TRI( ELT(start), ELT(j-1), ELT(j), ELT(pv), 0 ); + EDGEFLAG_SET( ELT(j), ef ); + } + + /* Draw the last triangle + */ + if (j < count) { + RENDER_TRI( ELT(start), ELT(j-1), ELT(j), ELT(pv), 0 ); + j++; + } + + /* Restore the first, last edgeflags: + */ + EDGEFLAG_SET( ELT(count-1), efcount ); + EDGEFLAG_SET( ELT(start), efstart ); + } + + if (TEST_PRIM_END(flags)) { + RESET_STIPPLE; + } + } + else { + for (j=start+2;j<count;j++) { + RENDER_TRI( ELT(start), ELT(j-1), ELT(j), ELT(start), 0 ); + } + } + POSTFIX; +} + +static void TAG(render_poly)( GLcontext *ctx, + GLuint start, + GLuint count, + GLuint flags ) +{ + TAG(render_poly_pv)( ctx, start, count, flags, start ); +} + +static void TAG(render_quads)( GLcontext *ctx, + GLuint start, + GLuint count, + GLuint flags ) +{ + GLuint j; + LOCAL_VARS; + (void) flags; + + INIT(GL_POLYGON); + if (NEED_EDGEFLAG_SETUP) { + for (j=start+3; j<count; j+=4) { + /* Use user-specified edgeflags for quads. + */ + RENDER_QUAD( ELT(j-3), ELT(j-2), ELT(j-1), ELT(j), ELT(j) ); + RESET_STIPPLE; + } + } else { + for (j=start+3; j<count; j+=4) { + RENDER_QUAD( ELT(j-3), ELT(j-2), ELT(j-1), ELT(j), ELT(j) ); + } + } + POSTFIX; +} + +static void TAG(render_quad_strip)( GLcontext *ctx, + GLuint start, + GLuint count, + GLuint flags ) +{ + GLuint j; + LOCAL_VARS; + (void) flags; + + INIT(GL_POLYGON); + if (NEED_EDGEFLAG_SETUP) { + for (j=start+3;j<count;j+=2) { + /* All edges are boundary. Set edgeflags to 1, draw the + * quad, and restore them to the original values. + */ + GLboolean ef3 = EDGEFLAG_GET( ELT(j-3) ); + GLboolean ef2 = EDGEFLAG_GET( ELT(j-2) ); + GLboolean ef1 = EDGEFLAG_GET( ELT(j-1) ); + GLboolean ef = EDGEFLAG_GET( ELT(j) ); + EDGEFLAG_SET( ELT(j-3), GL_TRUE ); + EDGEFLAG_SET( ELT(j-2), GL_TRUE ); + EDGEFLAG_SET( ELT(j-1), GL_TRUE ); + EDGEFLAG_SET( ELT(j), GL_TRUE ); + RENDER_QUAD( ELT(j-3), ELT(j-2), ELT(j), ELT(j-1), ELT(j) ); + EDGEFLAG_SET( ELT(j-3), ef3 ); + EDGEFLAG_SET( ELT(j-2), ef2 ); + EDGEFLAG_SET( ELT(j-1), ef1 ); + EDGEFLAG_SET( ELT(j), ef ); + RESET_STIPPLE; + } + } else { + for (j=start+3;j<count;j+=2) { + RENDER_QUAD( ELT(j-3), ELT(j-2), ELT(j), ELT(j-1), ELT(j) ); + } + } + POSTFIX; +} + +static void TAG(render_noop)( GLcontext *ctx, + GLuint start, + GLuint count, + GLuint flags ) +{ + (void)(ctx && start && count && flags); +} + +static render_func TAG(render_tab)[GL_POLYGON+2] = { + TAG(render_points), + TAG(render_lines), + TAG(render_line_loop), + TAG(render_line_strip), + TAG(render_triangles), + TAG(render_tri_strip), + TAG(render_tri_fan), + TAG(render_quads), + TAG(render_quad_strip), + TAG(render_poly), + TAG(render_noop), +}; + + + +#ifndef PRESERVE_VB_DEFS +#undef RENDER_TRI +#undef RENDER_QUAD +#undef RENDER_LINE +#undef RENDER_POINTS +#undef LOCAL_VARS +#undef INIT +#undef POSTFIX +#undef RESET_STIPPLE +#undef DBG +#undef ELT +#endif + +#ifndef PRESERVE_TAG +#undef TAG +#endif + +#undef PRESERVE_VB_DEFS +#undef PRESERVE_TAG + diff --git a/src/mesa/tnl/t_vb_texgen.c b/src/mesa/tnl/t_vb_texgen.c new file mode 100644 index 00000000000..e975665e8a4 --- /dev/null +++ b/src/mesa/tnl/t_vb_texgen.c @@ -0,0 +1,685 @@ +/* $Id: t_vb_texgen.c,v 1.1 2000/12/26 05:09:33 keithw Exp $ */ + +/* + * Mesa 3-D graphics library + * Version: 3.5 + * + * Copyright (C) 1999-2000 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. + * + * Authors: + * Brian Paul <[email protected]> + * Keith Whitwell <[email protected]> + */ + + +#include "glheader.h" +#include "colormac.h" +#include "context.h" +#include "macros.h" +#include "mmath.h" +#include "mem.h" +#include "mtypes.h" + +#include "math/m_xform.h" + +#include "t_context.h" +#include "t_pipeline.h" + + +/*********************************************************************** + * Automatic texture coordinate generation (texgen) code. + */ + + +struct texgen_stage_data; + +typedef void (*texgen_func)( GLcontext *ctx, + struct texgen_stage_data *store, + GLuint unit); + + +struct texgen_stage_data { + + /* Per-texunit derived state. + */ + GLuint TexgenSize[MAX_TEXTURE_UNITS]; + GLuint TexgenHoles[MAX_TEXTURE_UNITS]; + texgen_func TexgenFunc[MAX_TEXTURE_UNITS]; + + /* Temporary values used in texgen. + */ + GLfloat (*tmp_f)[3]; + GLfloat *tmp_m; + + /* Buffered outputs of the stage. + */ + GLvector4f texcoord[MAX_TEXTURE_UNITS]; +}; + + +#define TEXGEN_STAGE_DATA(stage) ((struct texgen_stage_data *)stage->private) + + + + +static GLuint all_bits[5] = { + 0, + VEC_SIZE_1, + VEC_SIZE_2, + VEC_SIZE_3, + VEC_SIZE_4, +}; + +#define VEC_SIZE_FLAGS (VEC_SIZE_1|VEC_SIZE_2|VEC_SIZE_3|VEC_SIZE_4) + +/* + */ +static void build_m3(GLfloat f[][3], GLfloat m[], + const GLvector3f *normal, + const GLvector4f *eye ) +{ + GLuint stride = eye->stride; + GLfloat *coord = (GLfloat *)eye->start; + GLuint count = eye->count; + const GLfloat *norm = normal->start; + GLuint i; + + + /* KW: Had to rearrange this loop to avoid a compiler bug with gcc + * 2.7.3.1 at -O3 optimization. Using -fno-strength-reduce + * also fixed the bug - is this generally necessary? + */ + for (i=0;i<count;i++,STRIDE_F(coord,stride)) { + GLfloat u[3], two_nu, fx, fy, fz; + COPY_3V( u, coord ); + NORMALIZE_3FV( u ); + two_nu = 2.0F * DOT3(norm,u); + fx = f[i][0] = u[0] - norm[0] * two_nu; + fy = f[i][1] = u[1] - norm[1] * two_nu; + fz = f[i][2] = u[2] - norm[2] * two_nu; + m[i] = fx * fx + fy * fy + (fz + 1.0F) * (fz + 1.0F); + if (m[i] != 0.0F) { + m[i] = 0.5F / (GLfloat) GL_SQRT(m[i]); + } + + STRIDE_F(norm, normal->stride); + } +} + + + +static void build_m2(GLfloat f[][3], GLfloat m[], + const GLvector3f *normal, + const GLvector4f *eye ) +{ + GLuint stride = eye->stride; + GLfloat *coord = eye->start; + GLuint count = eye->count; + + GLfloat *norm = normal->start; + GLuint i; + + for (i=0;i<count;i++,STRIDE_F(coord,stride)) { + + GLfloat u[3], two_nu, fx, fy, fz; + COPY_2V( u, coord ); + u[2] = 0; + NORMALIZE_3FV( u ); + two_nu = 2.0F * DOT3(norm,u); + fx = f[i][0] = u[0] - norm[0] * two_nu; + fy = f[i][1] = u[1] - norm[1] * two_nu; + fz = f[i][2] = u[2] - norm[2] * two_nu; + m[i] = fx * fx + fy * fy + (fz + 1.0F) * (fz + 1.0F); + if (m[i] != 0.0F) { + m[i] = 0.5F / (GLfloat) GL_SQRT(m[i]); + } + + STRIDE_F(norm, normal->stride); + } +} + + + +typedef void (*build_m_func)(GLfloat f[][3], + GLfloat m[], + const GLvector3f *normal, + const GLvector4f *eye ); + + + +static build_m_func build_m_tab[5] = { + 0, + 0, + build_m2, + build_m3, + build_m3 +}; + + +/* This is unusual in that we respect the stride of the output vector + * (f). This allows us to pass in either a texcoord vector4f, or a + * temporary vector3f. + */ +static void build_f3( GLfloat *f, + GLuint fstride, + const GLvector3f *normal, + const GLvector4f *eye ) +{ + GLuint stride = eye->stride; + GLfloat *coord = eye->start; + GLuint count = eye->count; + + GLfloat *norm = normal->start; + GLuint i; + + for (i=0;i<count;i++) { + GLfloat u[3], two_nu; + COPY_3V( u, coord ); + NORMALIZE_3FV( u ); + two_nu = 2.0F * DOT3(norm,u); + f[0] = u[0] - norm[0] * two_nu; + f[1] = u[1] - norm[1] * two_nu; + f[2] = u[2] - norm[2] * two_nu; + STRIDE_F(coord,stride); + STRIDE_F(f,fstride); + STRIDE_F(norm, normal->stride); + } +} + + +static void build_f2( GLfloat *f, + GLuint fstride, + const GLvector3f *normal, + const GLvector4f *eye ) +{ + GLuint stride = eye->stride; + GLfloat *coord = eye->start; + GLuint count = eye->count; + GLfloat *norm = normal->start; + GLuint i; + + for (i=0;i<count;i++) { + + GLfloat u[3], two_nu; + COPY_2V( u, coord ); + u[2] = 0; + NORMALIZE_3FV( u ); + two_nu = 2.0F * DOT3(norm,u); + f[0] = u[0] - norm[0] * two_nu; + f[1] = u[1] - norm[1] * two_nu; + f[2] = u[2] - norm[2] * two_nu; + + STRIDE_F(coord,stride); + STRIDE_F(f,fstride); + STRIDE_F(norm, normal->stride); + } +} + +typedef void (*build_f_func)( GLfloat *f, + GLuint fstride, + const GLvector3f *normal_vec, + const GLvector4f *eye ); + + + +/* Just treat 4-vectors as 3-vectors. + */ +static build_f_func build_f_tab[5] = { + 0, + 0, + build_f2, + build_f3, + build_f3 +}; + + +/* Special case texgen functions. + */ +static void texgen_reflection_map_nv( GLcontext *ctx, + struct texgen_stage_data *store, + GLuint unit ) +{ + struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb; + GLvector4f *in = VB->TexCoordPtr[unit]; + GLvector4f *out = &store->texcoord[unit]; + + build_f_tab[VB->EyePtr->size]( out->start, + out->stride, + VB->NormalPtr, + VB->EyePtr ); + + if (in) { + out->flags |= (in->flags & VEC_SIZE_FLAGS) | VEC_SIZE_3; + out->count = in->count; + out->size = MAX2(in->size, 3); + if (in->size == 4) + gl_copy_tab[0][0x8](out, in, 0); + } + else { + out->flags |= VEC_SIZE_3; + out->size = 3; + out->count = in->count; + } + +} + + + +static void texgen_normal_map_nv( GLcontext *ctx, + struct texgen_stage_data *store, + GLuint unit ) +{ + struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb; + GLvector4f *in = VB->TexCoordPtr[unit]; + GLvector4f *out = &store->texcoord[unit]; + GLvector3f *normal = VB->NormalPtr; + GLfloat (*texcoord)[4] = (GLfloat (*)[4])out->start; + GLuint count = VB->Count; + GLuint i; + const GLfloat *norm = normal->start; + + for (i=0;i<count;i++, STRIDE_F(norm, normal->stride)) { + texcoord[i][0] = norm[0]; + texcoord[i][1] = norm[1]; + texcoord[i][2] = norm[2]; + } + + + if (in) { + out->flags |= (in->flags & VEC_SIZE_FLAGS) | VEC_SIZE_3; + out->count = in->count; + out->size = MAX2(in->size, 3); + if (in->size == 4) + gl_copy_tab[0][0x8](out, in, 0); + } + else { + out->flags |= VEC_SIZE_3; + out->size = 3; + out->count = in->count; + } +} + + +static void texgen_sphere_map( GLcontext *ctx, + struct texgen_stage_data *store, + GLuint unit ) +{ + struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb; + GLvector4f *in = VB->TexCoordPtr[unit]; + GLvector4f *out = &store->texcoord[unit]; + GLfloat (*texcoord)[4] = (GLfloat (*)[4]) out->start; + GLuint count = VB->Count; + GLuint i; + GLfloat (*f)[3] = store->tmp_f; + GLfloat *m = store->tmp_m; + + (build_m_tab[VB->EyePtr->size])( store->tmp_f, + store->tmp_m, + VB->NormalPtr, + VB->EyePtr ); + + for (i=0;i<count;i++) { + texcoord[i][0] = f[i][0] * m[i] + 0.5F; + texcoord[i][1] = f[i][1] * m[i] + 0.5F; + } + + if (in) { + out->size = MAX2(in->size,2); + out->count = in->count; + out->flags |= (in->flags & VEC_SIZE_FLAGS) | VEC_SIZE_2; + if (in->size > 2) + gl_copy_tab[0][all_bits[in->size] & ~0x3](out, in, 0); + } else { + out->size = 2; + out->flags |= VEC_SIZE_2; + out->count = in->count; + } +} + + + +static void texgen( GLcontext *ctx, + struct texgen_stage_data *store, + GLuint unit ) +{ + TNLcontext *tnl = TNL_CONTEXT(ctx); + struct vertex_buffer *VB = &tnl->vb; + GLvector4f *in = VB->TexCoordPtr[unit]; + GLvector4f *out = &store->texcoord[unit]; + struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit]; + const GLvector4f *obj = VB->ObjPtr; + const GLvector4f *eye = VB->EyePtr; + const GLvector3f *normal = VB->NormalPtr; + GLfloat (*texcoord)[4] = (GLfloat (*)[4])out->data; + GLfloat *indata; + GLuint count = VB->Count; + GLfloat (*f)[3] = store->tmp_f; + GLfloat *m = store->tmp_m; + + + if (texUnit->_GenFlags & TEXGEN_NEED_M) { + build_m_tab[in->size]( store->tmp_f, store->tmp_m, normal, eye ); + } else if (texUnit->_GenFlags & TEXGEN_NEED_F) { + build_f_tab[in->size]( (GLfloat *)store->tmp_f, 3, normal, eye ); + } + + if (in != out) { + GLuint copy = (all_bits[in->size] & ~texUnit->TexGenEnabled); + if (copy) + gl_copy_tab[0][copy](out, in, 0); + } + + if (store->TexgenHoles[unit]) + { + GLuint holes = (~all_bits[in->size] & store->TexgenHoles[unit]); + if (holes) { + if (holes & VEC_DIRTY_2) gl_vector4f_clean_elem(out, count, 2); + if (holes & VEC_DIRTY_1) gl_vector4f_clean_elem(out, count, 1); + if (holes & VEC_DIRTY_0) gl_vector4f_clean_elem(out, count, 0); + } + } + + out->size = MAX2(in->size, store->TexgenSize[unit]); + out->flags |= (in->flags & VEC_SIZE_FLAGS) | texUnit->TexGenEnabled; + out->count = in->count; + + if (texUnit->TexGenEnabled & S_BIT) { + GLuint i; + switch (texUnit->GenModeS) { + case GL_OBJECT_LINEAR: + (gl_dotprod_tab[0][obj->size])((GLfloat *)out->data, + sizeof(out->data[0]), obj, + texUnit->ObjectPlaneS, 0); + break; + case GL_EYE_LINEAR: + (gl_dotprod_tab[0][eye->size])((GLfloat *)out->data, + sizeof(out->data[0]), eye, + texUnit->EyePlaneS, 0); + break; + case GL_SPHERE_MAP: + for (indata=in->start,i=0 ; i<count ; i++, STRIDE_F(indata,in->stride)) + texcoord[i][0] = indata[0] * m[i] + 0.5F; + break; + case GL_REFLECTION_MAP_NV: + for (i=0;i<count;i++) + texcoord[i][0] = f[i][0]; + break; + case GL_NORMAL_MAP_NV: { + const GLfloat *norm = normal->start; + for (i=0;i<count;i++, STRIDE_F(norm, normal->stride)) { + texcoord[i][0] = norm[0]; + } + break; + } + default: + gl_problem(ctx, "Bad S texgen"); + } + } + + if (texUnit->TexGenEnabled & T_BIT) { + GLuint i; + switch (texUnit->GenModeT) { + case GL_OBJECT_LINEAR: + (gl_dotprod_tab[0][obj->size])(&(out->data[0][1]), + sizeof(out->data[0]), obj, + texUnit->ObjectPlaneT, 0); + break; + case GL_EYE_LINEAR: + (gl_dotprod_tab[0][eye->size])(&(out->data[0][1]), + sizeof(out->data[0]), eye, + texUnit->EyePlaneT, 0); + break; + case GL_SPHERE_MAP: + for (indata=in->start,i=0; i<count ;i++,STRIDE_F(indata,in->stride)) + texcoord[i][1] = indata[1] * m[i] + 0.5F; + break; + case GL_REFLECTION_MAP_NV: + for (i=0;i<count;i++) + texcoord[i][0] = f[i][0]; + break; + case GL_NORMAL_MAP_NV: { + const GLfloat *norm = normal->start; + for (i=0;i<count;i++, STRIDE_F(norm, normal->stride)) { + texcoord[i][1] = norm[1]; + } + break; + } + default: + gl_problem(ctx, "Bad T texgen"); + } + } + + if (texUnit->TexGenEnabled & R_BIT) { + GLuint i; + switch (texUnit->GenModeR) { + case GL_OBJECT_LINEAR: + (gl_dotprod_tab[0][obj->size])(&(out->data[0][2]), + sizeof(out->data[0]), obj, + texUnit->ObjectPlaneR, 0); + break; + case GL_EYE_LINEAR: + (gl_dotprod_tab[0][eye->size])(&(out->data[0][2]), + sizeof(out->data[0]), eye, + texUnit->EyePlaneR, 0); + break; + case GL_REFLECTION_MAP_NV: + for (i=0;i<count;i++) + texcoord[i][2] = f[i][2]; + break; + case GL_NORMAL_MAP_NV: { + const GLfloat *norm = normal->start; + for (i=0;i<count;i++,STRIDE_F(norm, normal->stride)) { + texcoord[i][2] = norm[2]; + } + break; + } + default: + gl_problem(ctx, "Bad R texgen"); + } + } + + if (texUnit->TexGenEnabled & Q_BIT) { + switch (texUnit->GenModeQ) { + case GL_OBJECT_LINEAR: + (gl_dotprod_tab[0][obj->size])(&(out->data[0][3]), + sizeof(out->data[0]), obj, + texUnit->ObjectPlaneQ, 0); + break; + case GL_EYE_LINEAR: + (gl_dotprod_tab[0][eye->size])(&(out->data[0][3]), + sizeof(out->data[0]), eye, + texUnit->EyePlaneQ, 0); + break; + default: + gl_problem(ctx, "Bad Q texgen"); + } + } +} + + + +static GLboolean run_texgen_stage( GLcontext *ctx, + struct gl_pipeline_stage *stage ) +{ + struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb; + struct texgen_stage_data *store = TEXGEN_STAGE_DATA( stage ); + GLuint i; + + for (i = 0 ; i < ctx->Const.MaxTextureUnits ; i++) + if (ctx->_Enabled & ENABLE_TEXGEN(i)) { + if (stage->changed_inputs & (VERT_EYE | VERT_NORM | VERT_TEX(i))) + store->TexgenFunc[i]( ctx, store, i ); + + VB->TexCoordPtr[i] = &store->texcoord[i]; + } + + return GL_TRUE; +} + + + + +static GLboolean run_validate_texgen_stage( GLcontext *ctx, + struct gl_pipeline_stage *stage ) +{ + struct texgen_stage_data *store = TEXGEN_STAGE_DATA(stage); + GLuint i; + + for (i = 0 ; i < ctx->Const.MaxTextureUnits ; i++) { + struct gl_texture_unit *texUnit = &ctx->Texture.Unit[i]; + + if (texUnit->TexGenEnabled) { + GLuint sz; + + if (texUnit->TexGenEnabled & R_BIT) + sz = 4; + else if (texUnit->TexGenEnabled & Q_BIT) + sz = 3; + else if (texUnit->TexGenEnabled & T_BIT) + sz = 2; + else + sz = 1; + + store->TexgenSize[i] = sz; + store->TexgenHoles[i] = (all_bits[sz] & ~texUnit->TexGenEnabled); + store->TexgenFunc[i] = texgen; + + if (texUnit->TexGenEnabled == (S_BIT|T_BIT|R_BIT)) { + if (texUnit->_GenFlags == TEXGEN_REFLECTION_MAP_NV) { + store->TexgenFunc[i] = texgen_reflection_map_nv; + } + else if (texUnit->_GenFlags == TEXGEN_NORMAL_MAP_NV) { + store->TexgenFunc[i] = texgen_normal_map_nv; + } + } + else if (texUnit->TexGenEnabled == (S_BIT|T_BIT) && + texUnit->_GenFlags == TEXGEN_SPHERE_MAP) { + store->TexgenFunc[i] = texgen_sphere_map; + } + } + } + + stage->run = run_texgen_stage; + return stage->run( ctx, stage ); +} + + +static void check_texgen( GLcontext *ctx, struct gl_pipeline_stage *stage ) +{ + GLuint i; + stage->active = 0; + + if (ctx->_Enabled & ENABLE_TEXGEN_ANY) { + GLuint inputs = 0; + GLuint outputs = 0; + + if (ctx->Texture._GenFlags & TEXGEN_NEED_VERTICES) + inputs |= VERT_EYE; + + if (ctx->Texture._GenFlags & TEXGEN_NEED_NORMALS) + inputs |= VERT_NORM; + + for (i = 0 ; i < ctx->Const.MaxTextureUnits ; i++) + if (ctx->_Enabled & ENABLE_TEXGEN(i)) + { + outputs |= VERT_TEX(i); + + /* Need the original input in case it contains a Q coord: + * (sigh) + */ + if ((ctx->Texture.Unit[i]._ReallyEnabled|Q_BIT) & + ~ctx->Texture.Unit[i].TexGenEnabled) + inputs |= VERT_TEX(i); + + /* Something for Feedback? */ + } + + if (stage->private) + stage->run = run_validate_texgen_stage; + stage->active = 1; + stage->inputs = inputs; + stage->outputs = outputs; + } +} + + + + +/* Called the first time stage->run() is invoked. + */ +static GLboolean alloc_texgen_data( GLcontext *ctx, + struct gl_pipeline_stage *stage ) +{ + struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb; + struct texgen_stage_data *store; + GLuint i; + + stage->private = CALLOC(sizeof(*store)); + store = TEXGEN_STAGE_DATA(stage); + if (!store) + return GL_FALSE; + + for (i = 0 ; i < ctx->Const.MaxTextureUnits ; i++) + gl_vector4f_alloc( &store->texcoord[i], 0, VB->Size, 32 ); + + store->tmp_f = (GLfloat (*)[3]) MALLOC(VB->Size * sizeof(GLfloat) * 3); + store->tmp_m = (GLfloat *) MALLOC(VB->Size * sizeof(GLfloat)); + + /* Now validate and run the stage. + */ + stage->run = run_validate_texgen_stage; + return stage->run( ctx, stage ); +} + + +static void free_texgen_data( struct gl_pipeline_stage *stage ) + +{ + struct texgen_stage_data *store = TEXGEN_STAGE_DATA(stage); + GLuint i; + + if (store) { + for (i = 0 ; i < MAX_TEXTURE_UNITS ; i++) + if (store->texcoord[i].data) + gl_vector4f_free( &store->texcoord[i] ); + + + if (store->tmp_f) FREE( store->tmp_f ); + if (store->tmp_m) FREE( store->tmp_m ); + FREE( store ); + stage->private = 0; + } +} + + + +const struct gl_pipeline_stage _tnl_texgen_stage = +{ + "texgen", + _NEW_TEXTURE, /* when to call check() */ + _NEW_TEXTURE, /* when to invalidate stored data */ + 0,0,0, /* active, inputs, outputs */ + 0,0, /* changed_inputs, private */ + free_texgen_data, /* destructor */ + check_texgen, /* check */ + alloc_texgen_data /* run -- initially set to alloc data */ +}; + + diff --git a/src/mesa/tnl/t_vb_texmat.c b/src/mesa/tnl/t_vb_texmat.c new file mode 100644 index 00000000000..ea415a550e3 --- /dev/null +++ b/src/mesa/tnl/t_vb_texmat.c @@ -0,0 +1,148 @@ +/* $Id: t_vb_texmat.c,v 1.1 2000/12/26 05:09:33 keithw Exp $ */ + +/* + * Mesa 3-D graphics library + * Version: 3.5 + * + * Copyright (C) 1999-2000 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 <[email protected]> + */ + + +#include "glheader.h" +#include "colormac.h" +#include "context.h" +#include "macros.h" +#include "mem.h" +#include "mmath.h" +#include "mtypes.h" + +#include "math/m_xform.h" + +#include "t_context.h" +#include "t_pipeline.h" + +/* Is there any real benefit seperating texmat from texgen? It means + * we need two lots of intermediate storage. Any changes to + * _NEW_TEXTURE will invalidate both sets -- it's only on changes to + * *only* _NEW_TEXTURE_MATRIX that texgen survives but texmat doesn't. + * + * However, the seperation of this code from the complex texgen stuff + * is very appealing. + */ +struct texmat_stage_data { + GLvector4f texcoord[MAX_TEXTURE_UNITS]; +}; + +#define TEXMAT_STAGE_DATA(stage) ((struct texmat_stage_data *)stage->private) + +static void check_texmat( GLcontext *ctx, struct gl_pipeline_stage *stage ) +{ + GLuint i; + stage->active = 0; + + if (ctx->_Enabled & ENABLE_TEXMAT_ANY) { + GLuint flags = 0; + + for (i = 0 ; i < ctx->Const.MaxTextureUnits ; i++) + if (ctx->_Enabled & ENABLE_TEXMAT(i)) + flags |= VERT_TEX(i); + + stage->active = 1; + stage->inputs = flags; + stage->outputs = flags; + } +} + +static GLboolean run_texmat_stage( GLcontext *ctx, + struct gl_pipeline_stage *stage ) +{ + struct texmat_stage_data *store = TEXMAT_STAGE_DATA(stage); + struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb; + GLuint i; + + /* ENABLE_TEXMAT implies that the texture matrix is not the + * identity, so we don't have to check that here. + */ + for (i = 0 ; i < ctx->Const.MaxTextureUnits ; i++) + if (ctx->_Enabled & ENABLE_TEXMAT(i)) { + if (stage->changed_inputs & VERT_TEX(i)) + (void) TransformRaw( &store->texcoord[i], &ctx->TextureMatrix[i], + VB->TexCoordPtr[i]); + + VB->TexCoordPtr[i] = &store->texcoord[i]; + } + return GL_TRUE; +} + + +/* Called the first time stage->run() is invoked. + */ +static GLboolean alloc_texmat_data( GLcontext *ctx, + struct gl_pipeline_stage *stage ) +{ + struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb; + struct texmat_stage_data *store; + GLuint i; + + stage->private = CALLOC(sizeof(*store)); + store = TEXMAT_STAGE_DATA(stage); + if (!store) + return GL_FALSE; + + for (i = 0 ; i < ctx->Const.MaxTextureUnits ; i++) + gl_vector4f_alloc( &store->texcoord[i], 0, VB->Size, 32 ); + + /* Now run the stage. + */ + stage->run = run_texmat_stage; + return stage->run( ctx, stage ); +} + + +static void free_texmat_data( struct gl_pipeline_stage *stage ) +{ + struct texmat_stage_data *store = TEXMAT_STAGE_DATA(stage); + GLuint i; + + if (store) { + for (i = 0 ; i < MAX_TEXTURE_UNITS ; i++) + if (store->texcoord[i].data) + gl_vector4f_free( &store->texcoord[i] ); + FREE( store ); + stage->private = 0; + } +} + + + +const struct gl_pipeline_stage _tnl_texture_transform_stage = +{ + "texture transform", + _NEW_TEXTURE|_NEW_TEXTURE_MATRIX, + _NEW_TEXTURE|_NEW_TEXTURE_MATRIX, + 0,0,0, /* active, inputs, outputs */ + 0,0, /* changed_inputs, private */ + free_texmat_data, /* destructor */ + check_texmat, /* check */ + alloc_texmat_data, /* run -- initially set to init */ +}; diff --git a/src/mesa/tnl/t_vb_vertex.c b/src/mesa/tnl/t_vb_vertex.c new file mode 100644 index 00000000000..7667d423a8b --- /dev/null +++ b/src/mesa/tnl/t_vb_vertex.c @@ -0,0 +1,311 @@ +/* $Id: t_vb_vertex.c,v 1.1 2000/12/26 05:09:33 keithw Exp $ */ + +/* + * Mesa 3-D graphics library + * Version: 3.5 + * + * Copyright (C) 1999-2000 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 <[email protected]> + */ + + +#include "glheader.h" +#include "colormac.h" +#include "context.h" +#include "macros.h" +#include "mem.h" +#include "mmath.h" +#include "mtypes.h" + +#include "math/m_xform.h" + +#include "t_context.h" +#include "t_pipeline.h" + + + +struct vertex_stage_data { + GLvector4f eye; + GLvector4f clip; + GLvector4f proj; + GLubyte *clipmask; + GLubyte ormask; + GLubyte andmask; + + + /* Need these because it's difficult to replay the sideeffects + * analytically. + */ + GLvector4f *save_eyeptr; + GLvector4f *save_clipptr; + GLvector4f *save_projptr; +}; + +#define VERTEX_STAGE_DATA(stage) ((struct vertex_stage_data *)stage->private) + + + + +/* This function implements cliptesting for user-defined clip planes. + * The clipping of primitives to these planes is implemented in + * t_render_clip.h. + */ +#define USER_CLIPTEST(NAME, SZ) \ +static void NAME( GLcontext *ctx, \ + GLvector4f *clip, \ + GLubyte *clipmask, \ + GLubyte *clipormask, \ + GLubyte *clipandmask ) \ +{ \ + GLuint p; \ + \ + for (p = 0; p < ctx->Const.MaxClipPlanes; p++) \ + if (ctx->Transform.ClipEnabled[p]) { \ + GLuint nr, i; \ + const GLfloat a = ctx->Transform._ClipUserPlane[p][0]; \ + const GLfloat b = ctx->Transform._ClipUserPlane[p][1]; \ + const GLfloat c = ctx->Transform._ClipUserPlane[p][2]; \ + const GLfloat d = ctx->Transform._ClipUserPlane[p][3]; \ + GLfloat *coord = (GLfloat *)clip->data; \ + GLuint stride = clip->stride; \ + GLuint count = clip->count; \ + \ + for (nr = 0, i = 0 ; i < count ; i++) { \ + GLfloat dp = coord[0] * a + coord[1] * b; \ + if (SZ > 2) dp += coord[2] * c; \ + if (SZ > 3) dp += coord[3] * d; else dp += d; \ + \ + if (dp < 0) { \ + nr++; \ + clipmask[i] |= CLIP_USER_BIT; \ + } \ + \ + STRIDE_F(coord, stride); \ + } \ + \ + if (nr > 0) { \ + *clipormask |= CLIP_USER_BIT; \ + if (nr == count) { \ + *clipandmask |= CLIP_USER_BIT; \ + return; \ + } \ + } \ + } \ +} + + +USER_CLIPTEST(userclip2, 2) +USER_CLIPTEST(userclip3, 3) +USER_CLIPTEST(userclip4, 4) + +static void (*(usercliptab[5]))( GLcontext *, + GLvector4f *, GLubyte *, + GLubyte *, GLubyte * ) = +{ + 0, + 0, + userclip2, + userclip3, + userclip4 +}; + + + +static GLboolean run_vertex_stage( GLcontext *ctx, + struct gl_pipeline_stage *stage ) +{ + struct vertex_stage_data *store = (struct vertex_stage_data *)stage->private; + struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb; + + if (stage->changed_inputs) + { +/* VB->ObjPtr->size = 4; */ + + if (ctx->_NeedEyeCoords) { + /* Seperate modelview and project transformations: + */ + if (ctx->ModelView.type == MATRIX_IDENTITY) + VB->EyePtr = VB->ObjPtr; + else + VB->EyePtr = TransformRaw( &store->eye, &ctx->ModelView, + VB->ObjPtr); + + if (ctx->ProjectionMatrix.type == MATRIX_IDENTITY) + VB->ClipPtr = VB->EyePtr; + else + VB->ClipPtr = TransformRaw( &store->clip, &ctx->ProjectionMatrix, + VB->EyePtr ); + } + else + { + /* Combined modelviewproject transform: + */ + if (ctx->_ModelProjectMatrix.type == MATRIX_IDENTITY) + VB->ClipPtr = VB->ObjPtr; + else + VB->ClipPtr = TransformRaw( &store->clip, &ctx->_ModelProjectMatrix, + VB->ObjPtr ); + } + + /* Cliptest and perspective divide. Clip functions must clear + * the clipmask. + */ + store->ormask = 0; + store->andmask = CLIP_ALL_BITS; + + VB->ProjectedClipPtr = + gl_clip_tab[VB->ClipPtr->size]( VB->ClipPtr, + &store->proj, + store->clipmask, + &store->ormask, + &store->andmask ); + + if (store->andmask) + return GL_FALSE; + + + /* Test userclip planes. This contributes to VB->ClipMask, so + * is essentially required to be in this stage. + */ + if (ctx->Transform._AnyClip) { + usercliptab[VB->ClipPtr->size]( ctx, + VB->ClipPtr, + store->clipmask, + &store->ormask, + &store->andmask ); + + if (store->andmask) + return GL_FALSE; + } + + VB->ClipOrMask = store->ormask; + VB->ClipMask = store->clipmask; + + if (VB->ClipPtr == VB->ObjPtr && (VB->importable_data & VERT_OBJ)) + VB->importable_data |= VERT_CLIP; + + /* Drivers expect this to be size 4... + */ + if (VB->ProjectedClipPtr->size < 4) { + ASSERT(VB->ProjectedClipPtr == VB->ClipPtr); + if (VB->ProjectedClipPtr->flags & VEC_NOT_WRITEABLE) { + ASSERT(VB->ProjectedClipPtr == VB->ObjPtr); + VB->import_data( ctx, VERT_OBJ, VEC_NOT_WRITEABLE ); + VB->ProjectedClipPtr = VB->ClipPtr = VB->ObjPtr; + } + if (VB->ClipPtr->size == 2) + gl_vector4f_clean_elem( VB->ClipPtr, VB->Count, 2 ); + gl_vector4f_clean_elem( VB->ClipPtr, VB->Count, 3 ); + VB->ClipPtr->size = 4; + } + + store->save_eyeptr = VB->EyePtr; + store->save_clipptr = VB->ClipPtr; + store->save_projptr = VB->ProjectedClipPtr; + } + else { + /* Replay the sideeffects. + */ + VB->EyePtr = store->save_eyeptr; + VB->ClipPtr = store->save_clipptr; + VB->ProjectedClipPtr = store->save_projptr; + VB->ClipMask = store->clipmask; + VB->ClipOrMask = store->ormask; + if (VB->ClipPtr == VB->ObjPtr && (VB->importable_data & VERT_OBJ)) + VB->importable_data |= VERT_CLIP; + if (store->andmask) + return GL_FALSE; + } + + return GL_TRUE; +} + + +static void check_vertex( GLcontext *ctx, struct gl_pipeline_stage *stage ) +{ + (void) ctx; + (void) stage; +} + +static GLboolean init_vertex_stage( GLcontext *ctx, + struct gl_pipeline_stage *stage ) +{ + struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb; + struct vertex_stage_data *store; + GLuint size = VB->Size; + + stage->private = CALLOC(sizeof(*store)); + store = VERTEX_STAGE_DATA(stage); + if (!store) + return GL_FALSE; + + gl_vector4f_alloc( &store->eye, 0, size, 32 ); + gl_vector4f_alloc( &store->clip, 0, size, 32 ); + gl_vector4f_alloc( &store->proj, 0, size, 32 ); + + store->clipmask = (GLubyte *) ALIGN_MALLOC(sizeof(GLubyte)*size, 32 ); + + if (!store->clipmask || + !store->eye.data || + !store->clip.data || + !store->proj.data) + return GL_FALSE; + + /* Now run the stage. + */ + stage->run = run_vertex_stage; + return stage->run( ctx, stage ); +} + +static void dtr( struct gl_pipeline_stage *stage ) +{ + struct vertex_stage_data *store = VERTEX_STAGE_DATA(stage); + + if (store) { + gl_vector4f_free( &store->eye ); + gl_vector4f_free( &store->clip ); + gl_vector4f_free( &store->proj ); + ALIGN_FREE( store->clipmask ); + FREE(store); + stage->private = 0; + stage->run = init_vertex_stage; + } +} + + +const struct gl_pipeline_stage _tnl_vertex_transform_stage = +{ + "modelview/project/cliptest/divide", + 0, /* re-check -- always on */ + _NEW_MODELVIEW| + _NEW_PROJECTION| + _NEW_TRANSFORM, /* re-run */ + GL_TRUE, /* active */ + VERT_OBJ, /* inputs */ + VERT_EYE|VERT_CLIP, /* outputs */ + 0, 0, /* changed_inputs, private */ + dtr, /* destructor */ + check_vertex, /* check */ + init_vertex_stage /* run -- initially set to init */ +}; + + diff --git a/src/mesa/tnl/tnl.h b/src/mesa/tnl/tnl.h index c14ed296ad5..f95ce0e5037 100644 --- a/src/mesa/tnl/tnl.h +++ b/src/mesa/tnl/tnl.h @@ -32,8 +32,9 @@ -/* These are the public-access functions exported from tnl. (Many - * more are currently hooked into dispatch directly by core code.) +/* These are the public-access functions exported from tnl. (A few + * more are currently hooked into dispatch directly by the module + * itself.) */ extern GLboolean _tnl_CreateContext( GLcontext *ctx ); @@ -59,4 +60,16 @@ extern void _tnl_wakeup_save_exec( GLcontext *ctx ); +/* Functions to assist driver t&l modules which have to fallback to + * this module in the middle of a begin/end pair. Use this instead of + * glBegin() to identify the primitive as wrapped: + * + * Even with this it's difficult to see how the drivers are going to + * replay any glMaterial commands received in the few vertices before + * the fallback. + */ +extern void +_tnl_fallback_begin( GLcontext *ctx, GLenum mode ); + + #endif |