| /* |
| * 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 "glheader.h" |
| #include "context.h" |
| #include "macros.h" |
| #include "imports.h" |
| #include "mtypes.h" |
| |
| #include "tnl/t_context.h" |
| |
| #include "savagecontext.h" |
| #include "savagetris.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( GLcontext *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( GLcontext *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->TexCoordPtr[i]->data; |
| const GLint instride = VB->TexCoordPtr[i]->stride; |
| GLfloat (*out)[4] = store->texcoord[i].data; |
| GLint j; |
| |
| if (!ctx->Texture.Unit[i]._ReallyEnabled || |
| VB->TexCoordPtr[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[VERT_ATTRIB_TEX0+i] = VB->TexCoordPtr[i] = &store->texcoord[i]; |
| } |
| } |
| |
| return GL_TRUE; |
| } |
| |
| /* Called the first time stage->run() is invoked. |
| */ |
| static GLboolean alloc_texnorm_data( GLcontext *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( GLcontext *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 |
| }; |