Added a fast path for emitting unclipped primitives directly to a
[mesa.git] / src / mesa / drivers / dri / savage / savagerender.c
1 /*
2 * Copyright 2005 Felix Kuehling
3 * All rights reserved.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sub license,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice (including the
13 * next paragraph) shall be included in all copies or substantial portions
14 * of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 * NON-INFRINGEMENT. IN NO EVENT SHALL FELIX KUEHLING BE LIABLE FOR
20 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
21 * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 */
24
25 /*
26 * Render unclipped vertex buffers by emitting vertices directly to
27 * dma buffers. Use strip/fan hardware primitives where possible.
28 * Simulate missing primitives with indexed vertices.
29 */
30 #include "glheader.h"
31 #include "context.h"
32 #include "macros.h"
33 #include "imports.h"
34 #include "mtypes.h"
35
36 #include "tnl/t_context.h"
37
38 #include "savagecontext.h"
39 #include "savagetris.h"
40 #include "savagestate.h"
41 #include "savageioctl.h"
42
43 /*
44 * Standard render tab for Savage4 and smooth shading on Savage3D
45 */
46 #define HAVE_POINTS 0
47 #define HAVE_LINES 0
48 #define HAVE_LINE_STRIPS 0
49 #define HAVE_TRIANGLES 1
50 #define HAVE_TRI_STRIPS 1
51 #define HAVE_TRI_STRIP_1 0
52 #define HAVE_TRI_FANS 1
53 #define HAVE_POLYGONS 0
54 #define HAVE_QUADS 0
55 #define HAVE_QUAD_STRIPS 0
56
57 #define HAVE_ELTS 0 /* for now */
58
59 #define LOCAL_VARS savageContextPtr imesa = SAVAGE_CONTEXT(ctx)
60 #define INIT( prim ) do { \
61 if (0) fprintf(stderr, "%s\n", __FUNCTION__); \
62 savageFlushVertices(imesa); \
63 switch (prim) { \
64 case GL_TRIANGLES: imesa->HwPrim = SAVAGE_PRIM_TRILIST; break; \
65 case GL_TRIANGLE_STRIP: imesa->HwPrim = SAVAGE_PRIM_TRISTRIP; break; \
66 case GL_TRIANGLE_FAN: imesa->HwPrim = SAVAGE_PRIM_TRIFAN; break; \
67 } \
68 } while (0)
69 #define FLUSH() savageFlushVertices(imesa)
70 #define GET_CURRENT_VB_MAX_VERTS() \
71 ((imesa->bufferSize/4 - imesa->vtxBuf->used) / imesa->HwVertexSize)
72 #define GET_SUBSEQUENT_VB_MAX_VERTS() \
73 (imesa->bufferSize/4 / imesa->HwVertexSize)
74
75 #define ALLOC_VERTS( nr ) \
76 savageAllocVtxBuf( imesa, (nr) * imesa->HwVertexSize )
77 #define EMIT_VERTS( ctx, j, nr, buf ) \
78 _tnl_emit_vertices_to_buffer(ctx, j, (j)+(nr), buf )
79
80 #define TAG(x) savage_##x
81 #include "tnl_dd/t_dd_dmatmp.h"
82
83 /*
84 * On Savage3D triangle fans and strips are broken with flat
85 * shading. With triangles it wants the color for flat shading in the
86 * first vertex! So we make another template instance which uses
87 * triangles only (with reordered vertices: SAVAGE_PRIM_TRILIST_201).
88 * The reordering is done by the DRM.
89 */
90 #undef HAVE_TRI_STRIPS
91 #undef HAVE_TRI_FANS
92 #define HAVE_TRI_STRIPS 0
93 #define HAVE_TRI_FANS 0
94
95 #undef INIT
96 #define INIT( prim ) do { \
97 if (0) fprintf(stderr, "%s\n", __FUNCTION__); \
98 savageFlushVertices(imesa); \
99 imesa->HwPrim = SAVAGE_PRIM_TRILIST_201; \
100 } while(0)
101
102 #undef TAG
103 #define TAG(x) savage_flat_##x##_s3d
104 #include "tnl_dd/t_dd_dmatmp.h"
105
106
107 /**********************************************************************/
108 /* Render pipeline stage */
109 /**********************************************************************/
110
111 static GLboolean savage_run_render( GLcontext *ctx,
112 struct tnl_pipeline_stage *stage )
113 {
114 savageContextPtr imesa = SAVAGE_CONTEXT(ctx);
115 TNLcontext *tnl = TNL_CONTEXT(ctx);
116 struct vertex_buffer *VB = &tnl->vb;
117 tnl_render_func *tab;
118 GLboolean valid;
119 GLuint i;
120
121 if (imesa->savageScreen->chipset < S3_SAVAGE4 &&
122 (ctx->_TriangleCaps & DD_FLATSHADE)) {
123 tab = savage_flat_render_tab_verts_s3d;
124 valid = savage_flat_validate_render_s3d( ctx, VB );
125 } else {
126 tab = savage_render_tab_verts;
127 valid = savage_validate_render( ctx, VB );
128 }
129
130 /* Don't handle clipping or indexed vertices or vertex manipulations.
131 */
132 if (imesa->RenderIndex != 0 || !valid) {
133 return GL_TRUE;
134 }
135
136 tnl->Driver.Render.Start( ctx );
137 /* Check RenderIndex again. The ptexHack is detected late in RenderStart.
138 * Also check for fallbacks detected late.
139 */
140 if (imesa->RenderIndex != 0 || imesa->Fallback != 0) {
141 return GL_TRUE;
142 }
143
144 /* setup for hardware culling */
145 imesa->raster_primitive = GL_TRIANGLES;
146 imesa->new_state |= SAVAGE_NEW_CULL;
147 savageDDUpdateHwState(ctx);
148
149 for (i = 0 ; i < VB->PrimitiveCount ; i++)
150 {
151 GLuint prim = VB->Primitive[i].mode;
152 GLuint start = VB->Primitive[i].start;
153 GLuint length = VB->Primitive[i].count;
154
155 if (length)
156 tab[prim & PRIM_MODE_MASK]( ctx, start, start+length, prim);
157 }
158
159 tnl->Driver.Render.Finish( ctx );
160
161 return GL_FALSE; /* finished the pipe */
162 }
163
164 static void savage_check_render( GLcontext *ctx,
165 struct tnl_pipeline_stage *stage )
166 {
167 __DRIscreenPrivate *driScrnPriv =
168 SAVAGE_CONTEXT(ctx)->savageScreen->driScrnPriv;
169 stage->inputs = TNL_CONTEXT(ctx)->render_inputs;
170 /* This hack will go away when we depend on 2.2.x for ELTS. */
171 if (driScrnPriv->drmMinor <= 1 && driScrnPriv->drmPatch < 3) {
172 static GLboolean firstTime = GL_TRUE;
173 stage->active = GL_FALSE;
174 if (firstTime) {
175 fprintf (stderr,
176 "*** Disabling fast path because your DRM version is buggy.\n"
177 "*** You need at least Savage DRM version 2.1.3.\n");
178 firstTime = GL_FALSE;
179 }
180 }
181 }
182
183 static void dtr( struct tnl_pipeline_stage *stage )
184 {
185 (void)stage;
186 }
187
188 const struct tnl_pipeline_stage _savage_render_stage =
189 {
190 "savage render",
191 (_DD_NEW_SEPARATE_SPECULAR |
192 _NEW_TEXTURE|
193 _NEW_FOG|
194 _NEW_RENDERMODE), /* re-check (new inputs) */
195 0, /* re-run (always runs) */
196 GL_TRUE, /* active */
197 0, 0, /* inputs (set in check_render), outputs */
198 0, 0, /* changed_inputs, private */
199 dtr, /* destructor */
200 savage_check_render, /* check - initially set to alloc data */
201 savage_run_render /* run */
202 };
203
204
205 /**********************************************************************/
206 /* Pipeline stage for texture coordinate normalization */
207 /**********************************************************************/
208 struct texnorm_stage_data {
209 GLvector4f texcoord[MAX_TEXTURE_UNITS];
210 };
211
212 #define TEXNORM_STAGE_DATA(stage) ((struct texnorm_stage_data *)stage->privatePtr)
213
214
215 static GLboolean run_texnorm_stage( GLcontext *ctx,
216 struct tnl_pipeline_stage *stage )
217 {
218 struct texnorm_stage_data *store = TEXNORM_STAGE_DATA(stage);
219 savageContextPtr imesa = SAVAGE_CONTEXT(ctx);
220 TNLcontext *tnl = TNL_CONTEXT(ctx);
221 struct vertex_buffer *VB = &tnl->vb;
222 GLuint i;
223
224 if (imesa->Fallback)
225 return GL_TRUE;
226
227 for (i = 0 ; i < ctx->Const.MaxTextureUnits ; i++) {
228 if (!(stage->inputs & stage->changed_inputs & VERT_BIT_TEX(i)) ||
229 VB->TexCoordPtr[i]->size == 4)
230 /* Never try to normalize homogenous tex coords! */
231 continue;
232
233 GLuint reallyEnabled = ctx->Texture.Unit[i]._ReallyEnabled;
234 struct gl_texture_object *texObj = ctx->Texture.Unit[i]._Current;
235 GLboolean normalizeS = (texObj->WrapS == GL_REPEAT);
236 GLboolean normalizeT = (reallyEnabled & TEXTURE_2D_BIT) &&
237 (texObj->WrapT == GL_REPEAT);
238 GLfloat *in = (GLfloat *)VB->TexCoordPtr[i]->data;
239 GLint instride = VB->TexCoordPtr[i]->stride;
240 GLfloat (*out)[4] = store->texcoord[i].data;
241 GLint j;
242
243 if (normalizeS && normalizeT) {
244 /* take first texcoords as rough estimate of mean value */
245 GLfloat correctionS = -floor(in[0]+0.5);
246 GLfloat correctionT = -floor(in[1]+0.5);
247 for (j = 0; j < VB->Count; ++j) {
248 out[j][0] = in[0] + correctionS;
249 out[j][1] = in[1] + correctionT;
250 in = (GLfloat *)((GLubyte *)in + instride);
251 }
252 } else if (normalizeS) {
253 /* take first texcoords as rough estimate of mean value */
254 GLfloat correctionS = -floor(in[0]+0.5);
255 if (reallyEnabled & TEXTURE_2D_BIT) {
256 for (j = 0; j < VB->Count; ++j) {
257 out[j][0] = in[0] + correctionS;
258 out[j][1] = in[1];
259 in = (GLfloat *)((GLubyte *)in + instride);
260 }
261 } else {
262 for (j = 0; j < VB->Count; ++j) {
263 out[j][0] = in[0] + correctionS;
264 in = (GLfloat *)((GLubyte *)in + instride);
265 }
266 }
267 } else if (normalizeT) {
268 /* take first texcoords as rough estimate of mean value */
269 GLfloat correctionT = -floor(in[1]+0.5);
270 for (j = 0; j < VB->Count; ++j) {
271 out[j][0] = in[0];
272 out[j][1] = in[1] + correctionT;
273 in = (GLfloat *)((GLubyte *)in + instride);
274 }
275 }
276
277 if (normalizeS || normalizeT)
278 VB->AttribPtr[VERT_ATTRIB_TEX0+i] = VB->TexCoordPtr[i] = &store->texcoord[i];
279 }
280
281 return GL_TRUE;
282 }
283
284 /* Called the first time stage->run() is invoked.
285 */
286 static GLboolean alloc_texnorm_data( GLcontext *ctx,
287 struct tnl_pipeline_stage *stage )
288 {
289 struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb;
290 struct texnorm_stage_data *store;
291 GLuint i;
292
293 stage->privatePtr = CALLOC(sizeof(*store));
294 store = TEXNORM_STAGE_DATA(stage);
295 if (!store)
296 return GL_FALSE;
297
298 for (i = 0 ; i < ctx->Const.MaxTextureUnits ; i++)
299 _mesa_vector4f_alloc( &store->texcoord[i], 0, VB->Size, 32 );
300
301 /* Now run the stage.
302 */
303 stage->run = run_texnorm_stage;
304 return stage->run( ctx, stage );
305 }
306
307 static void check_texnorm( GLcontext *ctx,
308 struct tnl_pipeline_stage *stage )
309 {
310 GLuint flags = 0;
311
312 if (((ctx->Texture.Unit[0]._ReallyEnabled & (TEXTURE_1D_BIT|TEXTURE_2D_BIT)) &&
313 (ctx->Texture.Unit[0]._Current->WrapS == GL_REPEAT)) ||
314 ((ctx->Texture.Unit[0]._ReallyEnabled & TEXTURE_2D_BIT) &&
315 (ctx->Texture.Unit[0]._Current->WrapT == GL_REPEAT)))
316 flags |= VERT_BIT_TEX0;
317
318 if (((ctx->Texture.Unit[1]._ReallyEnabled & (TEXTURE_1D_BIT|TEXTURE_2D_BIT)) &&
319 (ctx->Texture.Unit[1]._Current->WrapS == GL_REPEAT)) ||
320 ((ctx->Texture.Unit[1]._ReallyEnabled & TEXTURE_2D_BIT) &&
321 (ctx->Texture.Unit[1]._Current->WrapT == GL_REPEAT)))
322 flags |= VERT_BIT_TEX1;
323
324 stage->inputs = flags;
325 stage->outputs = flags;
326 stage->active = (flags != 0);
327 }
328
329 static void free_texnorm_data( struct tnl_pipeline_stage *stage )
330 {
331 struct texnorm_stage_data *store = TEXNORM_STAGE_DATA(stage);
332 GLuint i;
333
334 if (store) {
335 for (i = 0 ; i < MAX_TEXTURE_UNITS ; i++)
336 if (store->texcoord[i].data)
337 _mesa_vector4f_free( &store->texcoord[i] );
338 FREE( store );
339 stage->privatePtr = 0;
340 }
341 }
342
343 const struct tnl_pipeline_stage _savage_texnorm_stage =
344 {
345 "savage texture coordinate normalization stage", /* name */
346 _NEW_TEXTURE, /* check_state */
347 _NEW_TEXTURE, /* run_state */
348 GL_TRUE, /* active? */
349 0, /* inputs */
350 0, /* outputs */
351 0, /* changed_inputs */
352 NULL, /* private data */
353 free_texnorm_data, /* destructor */
354 check_texnorm, /* check */
355 alloc_texnorm_data, /* run -- initially set to init */
356 };