/* * Copyright 2005 Felix Kuehling * 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, sub license, * 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 (including the * next paragraph) 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 * NON-INFRINGEMENT. IN NO EVENT SHALL FELIX KUEHLING 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 unclipped vertex buffers by emitting vertices directly to * dma buffers. Use strip/fan hardware primitives where possible. * Simulate missing primitives with indexed vertices. */ #include "main/glheader.h" #include "main/context.h" #include "main/macros.h" #include "main/imports.h" #include "main/mtypes.h" #include "math/m_xform.h" #include "tnl/t_context.h" #include "savagecontext.h" #include "savagestate.h" #include "savageioctl.h" /* * Standard render tab for Savage4 and smooth shading on Savage3D */ #define HAVE_POINTS 0 #define HAVE_LINES 0 #define HAVE_LINE_STRIPS 0 #define HAVE_TRIANGLES 1 #define HAVE_TRI_STRIPS 1 #define HAVE_TRI_STRIP_1 0 #define HAVE_TRI_FANS 1 #define HAVE_POLYGONS 0 #define HAVE_QUADS 0 #define HAVE_QUAD_STRIPS 0 #define HAVE_ELTS 1 #define LOCAL_VARS savageContextPtr imesa = SAVAGE_CONTEXT(ctx) #define INIT( prim ) do { \ if (0) fprintf(stderr, "%s\n", __FUNCTION__); \ savageFlushVertices(imesa); \ switch (prim) { \ case GL_TRIANGLES: imesa->HwPrim = SAVAGE_PRIM_TRILIST; break; \ case GL_TRIANGLE_STRIP: imesa->HwPrim = SAVAGE_PRIM_TRISTRIP; break; \ case GL_TRIANGLE_FAN: imesa->HwPrim = SAVAGE_PRIM_TRIFAN; break; \ } \ } while (0) #define FLUSH() savageFlushElts(imesa), savageFlushVertices(imesa) #define GET_CURRENT_VB_MAX_VERTS() \ ((imesa->bufferSize/4 - imesa->vtxBuf->used) / imesa->HwVertexSize) #define GET_SUBSEQUENT_VB_MAX_VERTS() \ (imesa->bufferSize/4 / imesa->HwVertexSize) #define ALLOC_VERTS( nr ) \ savageAllocVtxBuf( imesa, (nr) * imesa->HwVertexSize ) #define EMIT_VERTS( ctx, j, nr, buf ) \ _tnl_emit_vertices_to_buffer(ctx, j, (j)+(nr), buf ) #define ELTS_VARS( buf ) GLushort *dest = buf, firstElt = imesa->firstElt #define ELT_INIT( prim ) INIT(prim) /* (size - used - 1 qword for drawing command) * 4 elts per qword */ #define GET_CURRENT_VB_MAX_ELTS() \ ((imesa->cmdBuf.size - (imesa->cmdBuf.write - imesa->cmdBuf.base) - 1)*4) /* (size - space for initial state - 1 qword for drawing command) * 4 elts * imesa is not defined in validate_render :( */ #define GET_SUBSEQUENT_VB_MAX_ELTS() \ ((SAVAGE_CONTEXT(ctx)->cmdBuf.size - \ (SAVAGE_CONTEXT(ctx)->cmdBuf.start - \ SAVAGE_CONTEXT(ctx)->cmdBuf.base) - 1)*4) #define ALLOC_ELTS(nr) savageAllocElts(imesa, nr) #define EMIT_ELT(offset, x) do { \ (dest)[offset] = (GLushort) ((x)+firstElt); \ } while (0) #define EMIT_TWO_ELTS(offset, x, y) do { \ *(GLuint *)(dest + offset) = (((y)+firstElt) << 16) | \ ((x)+firstElt); \ } while (0) #define INCR_ELTS( nr ) dest += nr #define ELTPTR dest #define RELEASE_ELT_VERTS() \ savageReleaseIndexedVerts(imesa) #define EMIT_INDEXED_VERTS( ctx, start, count ) do { \ GLuint *buf = savageAllocIndexedVerts(imesa, count-start); \ EMIT_VERTS(ctx, start, count-start, buf); \ } while (0) #define TAG(x) savage_##x #include "tnl_dd/t_dd_dmatmp.h" /* * On Savage3D triangle fans and strips are broken with flat * shading. With triangles it wants the color for flat shading in the * first vertex! So we make another template instance which uses * triangles only (with reordered vertices: SAVAGE_PRIM_TRILIST_201). * The reordering is done by the DRM. */ #undef HAVE_TRI_STRIPS #undef HAVE_TRI_FANS #define HAVE_TRI_STRIPS 0 #define HAVE_TRI_FANS 0 #undef INIT #define INIT( prim ) do { \ if (0) fprintf(stderr, "%s\n", __FUNCTION__); \ savageFlushVertices(imesa); \ imesa->HwPrim = SAVAGE_PRIM_TRILIST_201; \ } while(0) #undef TAG #define TAG(x) savage_flat_##x##_s3d #include "tnl_dd/t_dd_dmatmp.h" /**********************************************************************/ /* Render pipeline stage */ /**********************************************************************/ static GLboolean savage_run_render( struct gl_context *ctx, struct tnl_pipeline_stage *stage ) { savageContextPtr imesa = SAVAGE_CONTEXT(ctx); TNLcontext *tnl = TNL_CONTEXT(ctx); struct vertex_buffer *VB = &tnl->vb; tnl_render_func *tab, *tab_elts; GLboolean valid; GLuint i; if (savageHaveIndexedVerts(imesa)) savageReleaseIndexedVerts(imesa); if (imesa->savageScreen->chipset < S3_SAVAGE4 && (ctx->_TriangleCaps & DD_FLATSHADE)) { tab = savage_flat_render_tab_verts_s3d; tab_elts = savage_flat_render_tab_elts_s3d; valid = savage_flat_validate_render_s3d( ctx, VB ); } else { tab = savage_render_tab_verts; tab_elts = savage_render_tab_elts; valid = savage_validate_render( ctx, VB ); } /* Don't handle clipping or vertex manipulations. */ if (imesa->RenderIndex != 0 || !valid) { return GL_TRUE; } tnl->Driver.Render.Start( ctx ); /* Check RenderIndex again. The ptexHack is detected late in RenderStart. * Also check for ptex fallbacks detected late. */ if (imesa->RenderIndex != 0 || imesa->Fallback != 0) { return GL_TRUE; } /* setup for hardware culling */ imesa->raster_primitive = GL_TRIANGLES; imesa->new_state |= SAVAGE_NEW_CULL; /* update and emit state */ savageDDUpdateHwState(ctx); savageEmitChangedState(imesa); if (VB->Elts) { tab = tab_elts; if (!savageHaveIndexedVerts(imesa)) { if (VB->Count > GET_SUBSEQUENT_VB_MAX_VERTS()) return GL_TRUE; EMIT_INDEXED_VERTS(ctx, 0, VB->Count); } } for (i = 0 ; i < VB->PrimitiveCount ; i++) { GLuint prim = _tnl_translate_prim(&VB->Primitive[i]); GLuint start = VB->Primitive[i].start; GLuint length = VB->Primitive[i].count; if (length) tab[prim & PRIM_MODE_MASK]( ctx, start, start+length, prim); } tnl->Driver.Render.Finish( ctx ); return GL_FALSE; /* finished the pipe */ } struct tnl_pipeline_stage _savage_render_stage = { "savage render", NULL, NULL, NULL, NULL, savage_run_render /* run */ }; /**********************************************************************/ /* Pipeline stage for texture coordinate normalization */ /**********************************************************************/ struct texnorm_stage_data { GLboolean active; GLvector4f texcoord[MAX_TEXTURE_UNITS]; }; #define TEXNORM_STAGE_DATA(stage) ((struct texnorm_stage_data *)stage->privatePtr) static GLboolean run_texnorm_stage( struct gl_context *ctx, struct tnl_pipeline_stage *stage ) { struct texnorm_stage_data *store = TEXNORM_STAGE_DATA(stage); savageContextPtr imesa = SAVAGE_CONTEXT(ctx); TNLcontext *tnl = TNL_CONTEXT(ctx); struct vertex_buffer *VB = &tnl->vb; GLuint i; if (imesa->Fallback || !store->active) return GL_TRUE; for (i = 0 ; i < ctx->Const.MaxTextureUnits ; i++) { const GLbitfield reallyEnabled = ctx->Texture.Unit[i]._ReallyEnabled; if (reallyEnabled) { const struct gl_texture_object *texObj = ctx->Texture.Unit[i]._Current; const GLboolean normalizeS = (texObj->WrapS == GL_REPEAT); const GLboolean normalizeT = (reallyEnabled & TEXTURE_2D_BIT) && (texObj->WrapT == GL_REPEAT); const GLfloat *in = (GLfloat *)VB->AttribPtr[_TNL_ATTRIB_TEX0 + i]->data; const GLint instride = VB->AttribPtr[_TNL_ATTRIB_TEX0 + i]->stride; GLfloat (*out)[4] = store->texcoord[i].data; GLint j; if (!ctx->Texture.Unit[i]._ReallyEnabled || VB->AttribPtr[_TNL_ATTRIB_TEX0 + i]->size == 4) /* Never try to normalize homogenous tex coords! */ continue; if (normalizeS && normalizeT) { /* take first texcoords as rough estimate of mean value */ GLfloat correctionS = -floor(in[0]+0.5); GLfloat correctionT = -floor(in[1]+0.5); for (j = 0; j < VB->Count; ++j) { out[j][0] = in[0] + correctionS; out[j][1] = in[1] + correctionT; in = (GLfloat *)((GLubyte *)in + instride); } } else if (normalizeS) { /* take first texcoords as rough estimate of mean value */ GLfloat correctionS = -floor(in[0]+0.5); if (reallyEnabled & TEXTURE_2D_BIT) { for (j = 0; j < VB->Count; ++j) { out[j][0] = in[0] + correctionS; out[j][1] = in[1]; in = (GLfloat *)((GLubyte *)in + instride); } } else { for (j = 0; j < VB->Count; ++j) { out[j][0] = in[0] + correctionS; in = (GLfloat *)((GLubyte *)in + instride); } } } else if (normalizeT) { /* take first texcoords as rough estimate of mean value */ GLfloat correctionT = -floor(in[1]+0.5); for (j = 0; j < VB->Count; ++j) { out[j][0] = in[0]; out[j][1] = in[1] + correctionT; in = (GLfloat *)((GLubyte *)in + instride); } } if (normalizeS || normalizeT) VB->AttribPtr[_TNL_ATTRIB_TEX0 + i] = &store->texcoord[i]; } } return GL_TRUE; } /* Called the first time stage->run() is invoked. */ static GLboolean alloc_texnorm_data( struct gl_context *ctx, struct tnl_pipeline_stage *stage ) { struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb; struct texnorm_stage_data *store; GLuint i; stage->privatePtr = CALLOC(sizeof(*store)); store = TEXNORM_STAGE_DATA(stage); if (!store) return GL_FALSE; for (i = 0 ; i < ctx->Const.MaxTextureUnits ; i++) _mesa_vector4f_alloc( &store->texcoord[i], 0, VB->Size, 32 ); return GL_TRUE; } static void validate_texnorm( struct gl_context *ctx, struct tnl_pipeline_stage *stage ) { struct texnorm_stage_data *store = TEXNORM_STAGE_DATA(stage); GLuint flags = 0; if (((ctx->Texture.Unit[0]._ReallyEnabled & (TEXTURE_1D_BIT|TEXTURE_2D_BIT)) && (ctx->Texture.Unit[0]._Current->WrapS == GL_REPEAT)) || ((ctx->Texture.Unit[0]._ReallyEnabled & TEXTURE_2D_BIT) && (ctx->Texture.Unit[0]._Current->WrapT == GL_REPEAT))) flags |= VERT_BIT_TEX0; if (((ctx->Texture.Unit[1]._ReallyEnabled & (TEXTURE_1D_BIT|TEXTURE_2D_BIT)) && (ctx->Texture.Unit[1]._Current->WrapS == GL_REPEAT)) || ((ctx->Texture.Unit[1]._ReallyEnabled & TEXTURE_2D_BIT) && (ctx->Texture.Unit[1]._Current->WrapT == GL_REPEAT))) flags |= VERT_BIT_TEX1; store->active = (flags != 0); } static void free_texnorm_data( struct tnl_pipeline_stage *stage ) { struct texnorm_stage_data *store = TEXNORM_STAGE_DATA(stage); GLuint i; if (store) { for (i = 0 ; i < MAX_TEXTURE_UNITS ; i++) if (store->texcoord[i].data) _mesa_vector4f_free( &store->texcoord[i] ); FREE( store ); stage->privatePtr = 0; } } struct tnl_pipeline_stage _savage_texnorm_stage = { "savage texture coordinate normalization stage", /* name */ NULL, /* private data */ alloc_texnorm_data, /* run -- initially set to init */ free_texnorm_data, /* destructor */ validate_texnorm, run_texnorm_stage };