Port viewport setting code from R200.
[profile/ivi/mesa.git] / src / mesa / drivers / dri / r300 / r300_state.c
1 /*
2 Copyright (C) The Weather Channel, Inc.  2002.
3 Copyright (C) 2004 Nicolai Haehnle.
4 All Rights Reserved.
5
6 The Weather Channel (TM) funded Tungsten Graphics to develop the
7 initial release of the Radeon 8500 driver under the XFree86 license.
8 This notice must be preserved.
9
10 Permission is hereby granted, free of charge, to any person obtaining
11 a copy of this software and associated documentation files (the
12 "Software"), to deal in the Software without restriction, including
13 without limitation the rights to use, copy, modify, merge, publish,
14 distribute, sublicense, and/or sell copies of the Software, and to
15 permit persons to whom the Software is furnished to do so, subject to
16 the following conditions:
17
18 The above copyright notice and this permission notice (including the
19 next paragraph) shall be included in all copies or substantial
20 portions of the Software.
21
22 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
25 IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
26 LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27 OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29
30 **************************************************************************/
31
32 /*
33  * Authors:
34  *   Nicolai Haehnle <prefect_@gmx.net>
35  */
36
37 #include "glheader.h"
38 #include "state.h"
39 #include "imports.h"
40 #include "enums.h"
41 #include "macros.h"
42 #include "context.h"
43 #include "dd.h"
44 #include "simple_list.h"
45
46 #include "api_arrayelt.h"
47 #include "swrast/swrast.h"
48 #include "swrast_setup/swrast_setup.h"
49 #include "array_cache/acache.h"
50 #include "tnl/tnl.h"
51
52 #include "radeon_ioctl.h"
53 #include "radeon_state.h"
54 #include "r300_context.h"
55 #include "r300_ioctl.h"
56 #include "r300_state.h"
57 #include "r300_reg.h"
58 #include "r300_program.h"
59
60
61 /**
62  * Update our tracked culling state based on Mesa's state.
63  */
64 static void r300UpdateCulling(GLcontext* ctx)
65 {
66         r300ContextPtr r300 = R300_CONTEXT(ctx);
67         uint32_t val = 0;
68
69         R300_STATECHANGE(r300, cul);
70         if (ctx->Polygon.CullFlag) {
71                 if (ctx->Polygon.CullFaceMode == GL_FRONT_AND_BACK)
72                         val = R300_CULL_FRONT|R300_CULL_BACK;
73                 else if (ctx->Polygon.CullFaceMode == GL_FRONT)
74                         val = R300_CULL_FRONT;
75                 else
76                         val = R300_CULL_BACK;
77
78                 if (ctx->Polygon.FrontFace == GL_CW)
79                         val |= R300_FRONT_FACE_CW;
80                 else
81                         val |= R300_FRONT_FACE_CCW;
82         }
83
84         r300->hw.cul.cmd[R300_CUL_CULL] = val;
85 }
86
87
88 /**
89  * Handle glEnable()/glDisable().
90  *
91  * \note Mesa already filters redundant calls to glEnable/glDisable.
92  */
93 static void r300Enable(GLcontext* ctx, GLenum cap, GLboolean state)
94 {
95         r300ContextPtr r300 = R300_CONTEXT(ctx);
96         uint32_t newval;
97
98         if (RADEON_DEBUG & DEBUG_STATE)
99                 fprintf(stderr, "%s( %s = %s )\n", __FUNCTION__,
100                         _mesa_lookup_enum_by_nr(cap),
101                         state ? "GL_TRUE" : "GL_FALSE");
102
103         switch (cap) {
104         case GL_DEPTH_TEST:
105                 R300_STATECHANGE(r300, zc);
106
107                 if (state) {
108                         if (ctx->Depth.Mask)
109                                 newval = R300_RB3D_Z_TEST_AND_WRITE;
110                         else
111                                 newval = R300_RB3D_Z_TEST;
112                 } else
113                         newval = 0;
114
115                 r300->hw.zc.cmd[R300_ZC_CNTL_0] = newval;
116                 break;
117
118         case GL_CULL_FACE:
119                 r300UpdateCulling(ctx);
120                 break;
121
122         default:
123                 radeonEnable(ctx, cap, state);
124                 return;
125         }
126 }
127
128
129 /**
130  * Change the culling mode.
131  *
132  * \note Mesa already filters redundant calls to this function.
133  */
134 static void r300CullFace(GLcontext* ctx, GLenum mode)
135 {
136         (void)mode;
137
138         r300UpdateCulling(ctx);
139 }
140
141
142 /**
143  * Change the polygon orientation.
144  *
145  * \note Mesa already filters redundant calls to this function.
146  */
147 static void r300FrontFace(GLcontext* ctx, GLenum mode)
148 {
149         (void)mode;
150
151         r300UpdateCulling(ctx);
152 }
153
154
155 /**
156  * Change the depth testing function.
157  *
158  * \note Mesa already filters redundant calls to this function.
159  */
160 static void r300DepthFunc(GLcontext* ctx, GLenum func)
161 {
162         r300ContextPtr r300 = R300_CONTEXT(ctx);
163
164         R300_STATECHANGE(r300, zc);
165
166         switch(func) {
167         case GL_NEVER:
168                 r300->hw.zc.cmd[R300_ZC_CNTL_1] = R300_Z_TEST_NEVER;
169                 break;
170         case GL_LESS:
171                 r300->hw.zc.cmd[R300_ZC_CNTL_1] = R300_Z_TEST_LESS;
172                 break;
173         case GL_EQUAL:
174                 r300->hw.zc.cmd[R300_ZC_CNTL_1] = R300_Z_TEST_EQUAL;
175                 break;
176         case GL_LEQUAL:
177                 r300->hw.zc.cmd[R300_ZC_CNTL_1] = R300_Z_TEST_LEQUAL;
178                 break;
179         case GL_GREATER:
180                 r300->hw.zc.cmd[R300_ZC_CNTL_1] = R300_Z_TEST_GREATER;
181                 break;
182         case GL_NOTEQUAL:
183                 r300->hw.zc.cmd[R300_ZC_CNTL_1] = R300_Z_TEST_NEQUAL;
184                 break;
185         case GL_GEQUAL:
186                 r300->hw.zc.cmd[R300_ZC_CNTL_1] = R300_Z_TEST_GEQUAL;
187                 break;
188         case GL_ALWAYS:
189                 r300->hw.zc.cmd[R300_ZC_CNTL_1] = R300_Z_TEST_ALWAYS;
190                 break;
191         }
192 }
193
194
195 /**
196  * Enable/Disable depth writing.
197  *
198  * \note Mesa already filters redundant calls to this function.
199  */
200 static void r300DepthMask(GLcontext* ctx, GLboolean mask)
201 {
202         r300ContextPtr r300 = R300_CONTEXT(ctx);
203
204         if (!ctx->Depth.Test)
205                 return;
206
207         R300_STATECHANGE(r300, zc);
208         r300->hw.zc.cmd[R300_ZC_CNTL_0] = mask
209                 ? R300_RB3D_Z_TEST_AND_WRITE : R300_RB3D_Z_TEST;
210 }
211
212
213 /**
214  * Handle glColorMask()
215  */
216 static void r300ColorMask(GLcontext* ctx,
217                           GLboolean r, GLboolean g, GLboolean b, GLboolean a)
218 {
219         r300ContextPtr r300 = R300_CONTEXT(ctx);
220         int mask = (b << 0) | (g << 1) | (r << 2) | (a << 3);
221
222         if (mask != r300->hw.cmk.cmd[R300_CMK_COLORMASK]) {
223                 R300_STATECHANGE(r300, cmk);
224                 r300->hw.cmk.cmd[R300_CMK_COLORMASK] = mask;
225         }
226 }
227
228 /* =============================================================
229  * Window position and viewport transformation
230  */
231
232 /*
233  * To correctly position primitives:
234  */
235 #define SUBPIXEL_X 0.125
236 #define SUBPIXEL_Y 0.125
237
238 void r300UpdateWindow(GLcontext * ctx)
239 {
240         r300ContextPtr rmesa = R300_CONTEXT(ctx);
241         __DRIdrawablePrivate *dPriv = rmesa->radeon.dri.drawable;
242         GLfloat xoffset = dPriv ? (GLfloat) dPriv->x : 0;
243         GLfloat yoffset = dPriv ? (GLfloat) dPriv->y + dPriv->h : 0;
244         const GLfloat *v = ctx->Viewport._WindowMap.m;
245
246         GLfloat sx = v[MAT_SX];
247         GLfloat tx = v[MAT_TX] + xoffset + SUBPIXEL_X;
248         GLfloat sy = -v[MAT_SY];
249         GLfloat ty = (-v[MAT_TY]) + yoffset + SUBPIXEL_Y;
250         GLfloat sz = v[MAT_SZ] * rmesa->state.depth.scale;
251         GLfloat tz = v[MAT_TZ] * rmesa->state.depth.scale;
252
253         R300_FIREVERTICES(rmesa);
254         R300_STATECHANGE(rmesa, vpt);
255
256         rmesa->hw.vpt.cmd[R300_VPT_XSCALE]  = r300PackFloat32(sx);
257         rmesa->hw.vpt.cmd[R300_VPT_XOFFSET] = r300PackFloat32(tx);
258         rmesa->hw.vpt.cmd[R300_VPT_YSCALE]  = r300PackFloat32(sy);
259         rmesa->hw.vpt.cmd[R300_VPT_YOFFSET] = r300PackFloat32(ty);
260         rmesa->hw.vpt.cmd[R300_VPT_ZSCALE]  = r300PackFloat32(sz);
261         rmesa->hw.vpt.cmd[R300_VPT_ZOFFSET] = r300PackFloat32(tz);
262 }
263
264 static void r300Viewport(GLcontext * ctx, GLint x, GLint y,
265                          GLsizei width, GLsizei height)
266 {
267         /* Don't pipeline viewport changes, conflict with window offset
268          * setting below.  Could apply deltas to rescue pipelined viewport
269          * values, or keep the originals hanging around.
270          */
271         R200_FIREVERTICES(R200_CONTEXT(ctx));
272         r300UpdateWindow(ctx);
273 }
274
275 static void r300DepthRange(GLcontext * ctx, GLclampd nearval, GLclampd farval)
276 {
277         r300UpdateWindow(ctx);
278 }
279
280
281 /**
282  * Called by Mesa after an internal state update.
283  */
284 static void r300InvalidateState(GLcontext * ctx, GLuint new_state)
285 {
286         r300ContextPtr r300 = R300_CONTEXT(ctx);
287
288         _swrast_InvalidateState(ctx, new_state);
289         _swsetup_InvalidateState(ctx, new_state);
290         _ac_InvalidateState(ctx, new_state);
291         _tnl_InvalidateState(ctx, new_state);
292         _ae_invalidate_state(ctx, new_state);
293
294         /* Go inefficiency! */
295         r300ResetHwState(r300);
296 }
297
298
299 /**
300  * Completely recalculates hardware state based on the Mesa state.
301  */
302 void r300ResetHwState(r300ContextPtr r300)
303 {
304         GLcontext* ctx = r300->radeon.glCtx;
305         int i;
306
307         if (RADEON_DEBUG & DEBUG_STATE)
308                 fprintf(stderr, "%s\n", __FUNCTION__);
309
310         r300UpdateWindow(ctx);
311         
312         r300ColorMask(ctx,
313                 ctx->Color.ColorMask[RCOMP],
314                 ctx->Color.ColorMask[GCOMP],
315                 ctx->Color.ColorMask[BCOMP],
316                 ctx->Color.ColorMask[ACOMP]);
317
318         r300Enable(ctx, GL_DEPTH_TEST, ctx->Depth.Test);
319         r300DepthMask(ctx, ctx->Depth.Mask);
320         r300DepthFunc(ctx, ctx->Depth.Func);
321
322         r300UpdateCulling(ctx);
323
324 //BEGIN: TODO
325         r300->hw.unk2080.cmd[1] = 0x0030045A;
326
327         r300->hw.ovf.cmd[R300_OVF_FMT_0] = 0x00000003;
328         r300->hw.ovf.cmd[R300_OVF_FMT_1] = 0x00000000;
329
330         r300->hw.unk20B0.cmd[1] = 0x0000040A;
331         r300->hw.unk20B0.cmd[2] = 0x00000008;
332
333         r300->hw.unk2134.cmd[1] = 0x00FFFFFF;
334         r300->hw.unk2134.cmd[2] = 0x00000000;
335
336         r300->hw.unk2140.cmd[1] = 0x00000000;
337
338         ((drm_r300_cmd_header_t*)r300->hw.vir[0].cmd)->unchecked_state.count = 1;
339         r300->hw.vir[0].cmd[1] = 0x21030003;
340
341         ((drm_r300_cmd_header_t*)r300->hw.vir[1].cmd)->unchecked_state.count = 1;
342         r300->hw.vir[1].cmd[1] = 0xF688F688;
343
344         r300->hw.vic.cmd[R300_VIR_CNTL_0] = 0x00000001;
345         r300->hw.vic.cmd[R300_VIR_CNTL_1] = 0x00000405;
346
347         r300->hw.unk21DC.cmd[1] = 0xAAAAAAAA;
348
349         r300->hw.unk221C.cmd[1] = R300_221C_NORMAL;
350
351         r300->hw.unk2220.cmd[1] = r300PackFloat32(1.0);
352         r300->hw.unk2220.cmd[2] = r300PackFloat32(1.0);
353         r300->hw.unk2220.cmd[3] = r300PackFloat32(1.0);
354         r300->hw.unk2220.cmd[4] = r300PackFloat32(1.0);
355
356         if (GET_CHIP(r300->radeon.radeonScreen) == RADEON_CHIP_R300)
357                 r300->hw.unk2288.cmd[1] = R300_2288_R300;
358         else
359                 r300->hw.unk2288.cmd[1] = R300_2288_RV350;
360
361         r300->hw.pvs.cmd[R300_PVS_CNTL_1] = 0;
362         r300->hw.pvs.cmd[R300_PVS_CNTL_2] = 0;
363         r300->hw.pvs.cmd[R300_PVS_CNTL_3] = 0;
364
365         r300->hw.unk4008.cmd[1] = 0x00000007;
366
367         r300->hw.unk4010.cmd[1] = 0x66666666;
368         r300->hw.unk4010.cmd[2] = 0x06666666;
369         if (GET_CHIP(r300->radeon.radeonScreen) == RADEON_CHIP_R300)
370                 r300->hw.unk4010.cmd[3] = 0x00000017;
371         else
372                 r300->hw.unk4010.cmd[3] = 0x00000011;
373         r300->hw.unk4010.cmd[4] = 0x00000000;
374         r300->hw.unk4010.cmd[5] = 0x00000000;
375
376         r300->hw.txe.cmd[R300_TXE_ENABLE] = 0;
377
378         r300->hw.unk4200.cmd[1] = r300PackFloat32(0.0);
379         r300->hw.unk4200.cmd[2] = r300PackFloat32(0.0);
380         r300->hw.unk4200.cmd[3] = r300PackFloat32(1.0);
381         r300->hw.unk4200.cmd[4] = r300PackFloat32(1.0);
382
383         r300->hw.unk4214.cmd[1] = 0x00050005;
384
385         r300->hw.ps.cmd[R300_PS_POINTSIZE] = (6 << R300_POINTSIZE_X_SHIFT) |
386                                              (6 << R300_POINTSIZE_Y_SHIFT);
387
388         r300->hw.unk4230.cmd[1] = 0x01800000;
389         r300->hw.unk4230.cmd[2] = 0x00020006;
390         r300->hw.unk4230.cmd[3] = r300PackFloat32(1.0 / 192.0);
391
392         r300->hw.unk4260.cmd[1] = 0;
393         r300->hw.unk4260.cmd[2] = r300PackFloat32(0.0);
394         r300->hw.unk4260.cmd[3] = r300PackFloat32(1.0);
395
396         r300->hw.unk4274.cmd[1] = 0x00000002;
397         r300->hw.unk4274.cmd[2] = 0x0003AAAA;
398         r300->hw.unk4274.cmd[3] = 0x00000000;
399         r300->hw.unk4274.cmd[4] = 0x00000000;
400
401         r300->hw.unk4288.cmd[1] = 0x00000000;
402         r300->hw.unk4288.cmd[2] = 0x00000001;
403         r300->hw.unk4288.cmd[3] = 0x00000000;
404         r300->hw.unk4288.cmd[4] = 0x00000000;
405         r300->hw.unk4288.cmd[5] = 0x00000000;
406
407         r300->hw.unk42A0.cmd[1] = 0x00000000;
408
409         r300->hw.unk42B4.cmd[1] = 0x00000000;
410
411         r300->hw.unk42C0.cmd[1] = 0x4B7FFFFF;
412         r300->hw.unk42C0.cmd[2] = 0x00000000;
413
414         r300->hw.rc.cmd[1] = R300_RS_CNTL_0_UNKNOWN_7;
415         r300->hw.rc.cmd[2] = 0;
416
417         for(i = 1; i <= 8; ++i)
418                 r300->hw.ri.cmd[i] = 0;
419
420         ((drm_r300_cmd_header_t*)r300->hw.rr.cmd)->unchecked_state.count = 1;
421         for(i = 1; i <= 8; ++i)
422                 r300->hw.rr.cmd[1] = 0;
423
424         r300->hw.unk43A4.cmd[1] = 0x0000001C;
425         r300->hw.unk43A4.cmd[2] = 0x2DA49525;
426
427         r300->hw.unk43E8.cmd[1] = 0x00FFFFFF;
428
429         r300->hw.fp.cmd[R300_FP_CNTL0] = 0;
430         r300->hw.fp.cmd[R300_FP_CNTL1] = 0;
431         r300->hw.fp.cmd[R300_FP_CNTL2] = 0;
432         r300->hw.fp.cmd[R300_FP_NODE0] = 0;
433         r300->hw.fp.cmd[R300_FP_NODE1] = 0;
434         r300->hw.fp.cmd[R300_FP_NODE2] = 0;
435         r300->hw.fp.cmd[R300_FP_NODE3] = 0;
436
437         r300->hw.unk46A4.cmd[1] = 0x00001B01;
438         r300->hw.unk46A4.cmd[2] = 0x00001B0F;
439         r300->hw.unk46A4.cmd[3] = 0x00001B0F;
440         r300->hw.unk46A4.cmd[4] = 0x00001B0F;
441         r300->hw.unk46A4.cmd[5] = 0x00000001;
442
443         for(i = 1; i <= 64; ++i) {
444                 /* create NOP instructions */
445                 r300->hw.fpi[0].cmd[i] = FP_INSTRC(MAD, FP_ARGC(SRC0C_XYZ), FP_ARGC(ONE), FP_ARGC(ZERO));
446                 r300->hw.fpi[1].cmd[i] = FP_SELC(0,XYZ,NO,FP_TMP(0),0,0);
447                 r300->hw.fpi[2].cmd[i] = FP_INSTRA(MAD, FP_ARGA(SRC0A), FP_ARGA(ONE), FP_ARGA(ZERO));
448                 r300->hw.fpi[3].cmd[i] = FP_SELA(0,W,NO,FP_TMP(0),0,0);
449         }
450
451         r300->hw.unk4BC0.cmd[1] = 0;
452
453         r300->hw.unk4BC8.cmd[1] = 0;
454         r300->hw.unk4BC8.cmd[2] = 0;
455         r300->hw.unk4BC8.cmd[3] = 0;
456
457         r300->hw.at.cmd[R300_AT_ALPHA_TEST] = 0;
458
459         r300->hw.unk4BD8.cmd[1] = 0;
460
461         r300->hw.unk4E00.cmd[1] = 0;
462
463         r300->hw.bld.cmd[R300_BLD_CBLEND] = 0;
464         r300->hw.bld.cmd[R300_BLD_ABLEND] = 0;
465
466         r300->hw.unk4E10.cmd[1] = 0;
467         r300->hw.unk4E10.cmd[2] = 0;
468         r300->hw.unk4E10.cmd[3] = 0;
469
470         r300->hw.cb.cmd[R300_CB_OFFSET] =
471                 r300->radeon.radeonScreen->backOffset +
472                 r300->radeon.radeonScreen->fbLocation;
473         r300->hw.cb.cmd[R300_CB_PITCH] = r300->radeon.radeonScreen->backPitch
474                 | R300_COLOR_UNKNOWN_22_23;
475
476         r300->hw.unk4E50.cmd[1] = 0;
477         r300->hw.unk4E50.cmd[2] = 0;
478         r300->hw.unk4E50.cmd[3] = 0;
479         r300->hw.unk4E50.cmd[4] = 0;
480         r300->hw.unk4E50.cmd[5] = 0;
481         r300->hw.unk4E50.cmd[6] = 0;
482         r300->hw.unk4E50.cmd[7] = 0;
483         r300->hw.unk4E50.cmd[8] = 0;
484         r300->hw.unk4E50.cmd[9] = 0;
485
486         r300->hw.unk4E88.cmd[1] = 0;
487
488         r300->hw.unk4F08.cmd[1] = 0x00FFFF00;
489
490         r300->hw.unk4F10.cmd[1] = 0x00000002; // depthbuffer format?
491         r300->hw.unk4F10.cmd[2] = 0x00000000;
492         r300->hw.unk4F10.cmd[3] = 0x00000003;
493         r300->hw.unk4F10.cmd[4] = 0x00000000;
494
495         r300->hw.zb.cmd[R300_ZB_OFFSET] =
496                 r300->radeon.radeonScreen->depthOffset +
497                 r300->radeon.radeonScreen->fbLocation;
498         r300->hw.zb.cmd[R300_ZB_PITCH] = r300->radeon.radeonScreen->depthPitch;
499
500         r300->hw.unk4F28.cmd[1] = 0;
501
502         r300->hw.unk4F30.cmd[1] = 0;
503         r300->hw.unk4F30.cmd[2] = 0;
504
505         r300->hw.unk4F44.cmd[1] = 0;
506
507         r300->hw.unk4F54.cmd[1] = 0;
508
509         ((drm_r300_cmd_header_t*)r300->hw.vpi.cmd)->vpu.count = 0;
510         for(i = 1; i < R300_VPI_CMDSIZE; i += 4) {
511                 /* MOV t0, t0 */
512                 r300->hw.vpi.cmd[i+0] = VP_OUT(ADD,TMP,0,XYZW);
513                 r300->hw.vpi.cmd[i+1] = VP_IN(TMP,0);
514                 r300->hw.vpi.cmd[i+2] = VP_ZERO();
515                 r300->hw.vpi.cmd[i+3] = VP_ZERO();
516         }
517
518         ((drm_r300_cmd_header_t*)r300->hw.vpp.cmd)->vpu.count = 0;
519         for(i = 1; i < R300_VPP_CMDSIZE; ++i)
520                 r300->hw.vpp.cmd[i] = 0;
521
522         r300->hw.vps.cmd[R300_VPS_ZERO_0] = 0;
523         r300->hw.vps.cmd[R300_VPS_ZERO_1] = 0;
524         r300->hw.vps.cmd[R300_VPS_POINTSIZE] = r300PackFloat32(1.0);
525         r300->hw.vps.cmd[R300_VPS_ZERO_3] = 0;
526 //END: TODO
527
528         r300->hw.all_dirty = GL_TRUE;
529 }
530
531
532
533 /**
534  * Calculate initial hardware state and register state functions.
535  * Assumes that the command buffer and state atoms have been
536  * initialized already.
537  */
538 void r300InitState(r300ContextPtr r300)
539 {
540         radeonInitState(&r300->radeon);
541         
542         r300->state.depth.scale = 1.0 / (GLfloat) 0xffff;
543
544         r300ResetHwState(r300);
545 }
546
547
548
549 /**
550  * Initialize driver's state callback functions
551  */
552 void r300InitStateFuncs(struct dd_function_table* functions)
553 {
554         radeonInitStateFuncs(functions);
555
556         functions->UpdateState = r300InvalidateState;
557         functions->Enable = r300Enable;
558         functions->ColorMask = r300ColorMask;
559         functions->DepthFunc = r300DepthFunc;
560         functions->DepthMask = r300DepthMask;
561         functions->CullFace = r300CullFace;
562         functions->FrontFace = r300FrontFace;
563
564         /* Viewport related */
565         functions->Viewport = r300Viewport;
566         functions->DepthRange = r300DepthRange;
567 }
568