Reduce noiseness of the driver.
[mesa.git] / src / mesa / drivers / dri / mga / mgapixel.c
1 /*
2 * Copyright 2000 Compaq Computer Inc. and VA Linux Systems, Inc.
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 * on the rights to use, copy, modify, merge, publish, distribute, sub
9 * license, and/or sell copies of the Software, and to permit persons to whom
10 * the Software is furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice (including the next
13 * paragraph) shall be included in all copies or substantial portions of the
14 * Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
19 * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22 * OTHER DEALINGS IN THE SOFTWARE.
23 *
24 * Authors:
25 * Keith Whitwell <keith@tungstengraphics.com>
26 * Gareth Hughes <gareth@valinux.com>
27 */
28 /* $XFree86: xc/lib/GL/mesa/src/drv/mga/mgapixel.c,v 1.9 2002/11/05 17:46:08 tsi Exp $ */
29
30 #include "mtypes.h"
31 #include "macros.h"
32 #include "mgadd.h"
33 #include "mgacontext.h"
34 #include "mgaioctl.h"
35 #include "mgapixel.h"
36 #include "mgastate.h"
37
38 #include "swrast/swrast.h"
39 #include "imports.h"
40
41 #define IS_AGP_MEM( mmesa, p ) \
42 ((unsigned long)mmesa->mgaScreen->buffers.map <= ((unsigned long)p) && \
43 (unsigned long)mmesa->mgaScreen->buffers.map + \
44 (unsigned long)mmesa->mgaScreen->buffers.size > ((unsigned long)p))
45 #define AGP_OFFSET( mmesa, p ) \
46 (((unsigned long)p) - (unsigned long)mmesa->mgaScreen->buffers.map)
47
48
49 #if defined(MESA_packed_depth_stencil)
50 static GLboolean
51 check_depth_stencil_24_8( const GLcontext *ctx, GLenum type,
52 const struct gl_pixelstore_attrib *packing,
53 const void *pixels, GLint sz,
54 GLint pitch )
55 {
56 mgaContextPtr mmesa = MGA_CONTEXT(ctx);
57
58 return ( type == GL_UNSIGNED_INT_24_8_MESA &&
59 ctx->Visual->DepthBits == 24 &&
60 ctx->Visual->StencilBits == 8 &&
61 mmesa->mgaScreen->cpp == 4 &&
62 mmesa->hw_stencil &&
63 !ctx->Pixel.IndexShift &&
64 !ctx->Pixel.IndexOffset &&
65 !ctx->Pixel.MapStencilFlag &&
66 ctx->Pixel.DepthBias == 0.0 &&
67 ctx->Pixel.DepthScale == 1.0 &&
68 !packing->SwapBytes &&
69 pitch % 32 == 0 &&
70 pitch < 4096 );
71 }
72 #endif
73
74
75 static GLboolean
76 check_depth( const GLcontext *ctx, GLenum type,
77 const struct gl_pixelstore_attrib *packing,
78 const void *pixels, GLint sz, GLint pitch )
79 {
80 mgaContextPtr mmesa = MGA_CONTEXT(ctx);
81
82 if ( IS_AGP_MEM( mmesa, pixels ) &&
83 !( ( type == GL_UNSIGNED_INT && mmesa->mgaScreen->cpp == 4 ) ||
84 ( type == GL_UNSIGNED_SHORT && mmesa->mgaScreen->cpp == 2 ) ) )
85 return GL_FALSE;
86
87 return ( ctx->Pixel.DepthBias == 0.0 &&
88 ctx->Pixel.DepthScale == 1.0 &&
89 !packing->SwapBytes &&
90 pitch % 32 == 0 &&
91 pitch < 4096 );
92 }
93
94
95 static GLboolean
96 check_color( const GLcontext *ctx, GLenum type, GLenum format,
97 const struct gl_pixelstore_attrib *packing,
98 const void *pixels, GLint sz, GLint pitch )
99 {
100 mgaContextPtr mmesa = MGA_CONTEXT(ctx);
101 GLuint cpp = mmesa->mgaScreen->cpp;
102
103 /* Can't do conversions on agp reads/draws.
104 */
105 if ( IS_AGP_MEM( mmesa, pixels ) &&
106 !( pitch % 32 == 0 && pitch < 4096 &&
107 ( ( type == GL_UNSIGNED_BYTE &&
108 cpp == 4 && format == GL_BGRA ) ||
109 ( type == GL_UNSIGNED_INT_8_8_8_8 &&
110 cpp == 4 && format == GL_BGRA ) ||
111 ( type == GL_UNSIGNED_SHORT_5_6_5_REV &&
112 cpp == 2 && format == GL_RGB ) ) ) )
113 return GL_FALSE;
114
115 return (!ctx->_ImageTransferState &&
116 !packing->SwapBytes &&
117 !packing->LsbFirst);
118 }
119
120 static GLboolean
121 check_color_per_fragment_ops( const GLcontext *ctx )
122 {
123 return (!( ctx->Color.AlphaEnabled ||
124 ctx->Depth.Test ||
125 ctx->Fog.Enabled ||
126 ctx->Scissor.Enabled ||
127 ctx->Stencil.Enabled ||
128 !ctx->Color.ColorMask[0] ||
129 !ctx->Color.ColorMask[1] ||
130 !ctx->Color.ColorMask[2] ||
131 !ctx->Color.ColorMask[3] ||
132 ctx->Color.ColorLogicOpEnabled ||
133 ctx->Texture._EnabledUnits ||
134 ctx->Depth.OcclusionTest
135 ) &&
136 ctx->Current.RasterPosValid &&
137 ctx->Pixel.ZoomX == 1.0F &&
138 (ctx->Pixel.ZoomY == 1.0F || ctx->Pixel.ZoomY == -1.0F));
139 }
140
141 static GLboolean
142 check_depth_per_fragment_ops( const GLcontext *ctx )
143 {
144 return ( ctx->Current.RasterPosValid &&
145 ctx->Color.ColorMask[RCOMP] == 0 &&
146 ctx->Color.ColorMask[BCOMP] == 0 &&
147 ctx->Color.ColorMask[GCOMP] == 0 &&
148 ctx->Color.ColorMask[ACOMP] == 0 &&
149 ctx->Pixel.ZoomX == 1.0F &&
150 ( ctx->Pixel.ZoomY == 1.0F || ctx->Pixel.ZoomY == -1.0F ) );
151 }
152
153 /* In addition to the requirements for depth:
154 */
155 #if defined(MESA_packed_depth_stencil)
156 static GLboolean
157 check_stencil_per_fragment_ops( const GLcontext *ctx )
158 {
159 return ( !ctx->Pixel.IndexShift &&
160 !ctx->Pixel.IndexOffset );
161 }
162 #endif
163
164
165 static GLboolean
166 clip_pixelrect( const GLcontext *ctx,
167 const GLframebuffer *buffer,
168 GLint *x, GLint *y,
169 GLsizei *width, GLsizei *height,
170 GLint *skipPixels, GLint *skipRows,
171 GLint *size )
172 {
173 mgaContextPtr mmesa = MGA_CONTEXT(ctx);
174
175 *width = MIN2(*width, MAX_WIDTH); /* redundant? */
176
177 /* left clipping */
178 if (*x < buffer->_Xmin) {
179 *skipPixels += (buffer->_Xmin - *x);
180 *width -= (buffer->_Xmin - *x);
181 *x = buffer->_Xmin;
182 }
183
184 /* right clipping */
185 if (*x + *width > buffer->_Xmax)
186 *width -= (*x + *width - buffer->_Xmax - 1);
187
188 if (*width <= 0)
189 return GL_FALSE;
190
191 /* bottom clipping */
192 if (*y < buffer->_Ymin) {
193 *skipRows += (buffer->_Ymin - *y);
194 *height -= (buffer->_Ymin - *y);
195 *y = buffer->_Ymin;
196 }
197
198 /* top clipping */
199 if (*y + *height > buffer->_Ymax)
200 *height -= (*y + *height - buffer->_Ymax - 1);
201
202 if (*height <= 0)
203 return GL_FALSE;
204
205 *size = ((*y + *height - 1) * mmesa->mgaScreen->frontPitch +
206 (*x + *width - 1) * mmesa->mgaScreen->cpp);
207
208 return GL_TRUE;
209 }
210
211 static GLboolean
212 mgaTryReadPixels( GLcontext *ctx,
213 GLint x, GLint y, GLsizei width, GLsizei height,
214 GLenum format, GLenum type,
215 const struct gl_pixelstore_attrib *pack,
216 GLvoid *pixels )
217 {
218 mgaContextPtr mmesa = MGA_CONTEXT(ctx);
219 GLint size, skipPixels, skipRows;
220 GLint pitch = pack->RowLength ? pack->RowLength : width;
221 GLboolean ok;
222
223 GLuint planemask;
224 GLuint source;
225 #if 0
226 drmMGABlit blit;
227 GLuint dest;
228 GLint source_pitch, dest_pitch;
229 GLint delta_sx, delta_sy;
230 GLint delta_dx, delta_dy;
231 GLint blit_height, ydir;
232 #endif
233
234 if (!clip_pixelrect(ctx, ctx->ReadBuffer,
235 &x, &y, &width, &height,
236 &skipPixels, &skipRows, &size)) {
237 return GL_TRUE;
238 }
239
240 /* Only accelerate reading to agp buffers.
241 */
242 if ( !IS_AGP_MEM(mmesa, (char *)pixels) ||
243 !IS_AGP_MEM(mmesa, (char *)pixels + size) )
244 return GL_FALSE;
245
246 switch (format) {
247 #if defined(MESA_packed_depth_stencil)
248 case GL_DEPTH_STENCIL_MESA:
249 ok = check_depth_stencil_24_8(ctx, type, pack, pixels, size, pitch);
250 planemask = ~0;
251 source = mmesa->mgaScreen->depthOffset;
252 break;
253 #endif
254
255 case GL_DEPTH_COMPONENT:
256 ok = check_depth(ctx, type, pack, pixels, size, pitch);
257
258 /* Can't accelerate at this depth -- planemask does the wrong
259 * thing; it doesn't clear the low order bits in the
260 * destination, instead it leaves them untouched.
261 *
262 * Could get the acclerator to solid fill the destination with
263 * zeros first... Or get the cpu to do it...
264 */
265 if (ctx->Visual.depthBits == 24)
266 return GL_FALSE;
267
268 planemask = ~0;
269 source = mmesa->mgaScreen->depthOffset;
270 break;
271
272 case GL_RGB:
273 case GL_BGRA:
274 ok = check_color(ctx, type, format, pack, pixels, size, pitch);
275 planemask = ~0;
276 source = (mmesa->draw_buffer == MGA_FRONT ?
277 mmesa->mgaScreen->frontOffset :
278 mmesa->mgaScreen->backOffset);
279 break;
280
281 default:
282 return GL_FALSE;
283 }
284
285 if (!ok) {
286 return GL_FALSE;
287 }
288
289
290 LOCK_HARDWARE( mmesa );
291
292 #if 0
293 {
294 __DRIdrawablePrivate *dPriv = mmesa->driDrawable;
295 int nbox, retcode, i;
296
297 UPDATE_LOCK( mmesa, DRM_LOCK_FLUSH | DRM_LOCK_QUIESCENT );
298
299 if (mmesa->dirty_cliprects & MGA_FRONT)
300 mgaUpdateRects( mmesa, MGA_FRONT );
301
302 nbox = dPriv->numClipRects;
303
304 y = dPriv->h - y - height;
305 x += mmesa->drawX;
306 y += mmesa->drawY;
307
308 dest = ((mmesa->mgaScreen->agp.handle + AGP_OFFSET(mmesa, pixels)) |
309 DO_dstmap_sys | DO_dstacc_agp);
310 source_pitch = mmesa->mgaScreen->frontPitch / mmesa->mgaScreen->cpp;
311 dest_pitch = pitch;
312 delta_sx = 0;
313 delta_sy = 0;
314 delta_dx = -x;
315 delta_dy = -y;
316 blit_height = 2*y + height;
317 ydir = -1;
318
319 if (0) fprintf(stderr, "XX doing readpixel blit src_pitch %d dst_pitch %d\n",
320 source_pitch, dest_pitch);
321
322
323
324 for (i = 0 ; i < nbox ; )
325 {
326 int nr = MIN2(i + MGA_NR_SAREA_CLIPRECTS, dPriv->numClipRects);
327 drm_clip_rect_t *box = dPriv->pClipRects;
328 drm_clip_rect_t *b = mmesa->sarea->boxes;
329 int n = 0;
330
331 for ( ; i < nr ; i++) {
332 GLint bx = box[i].x1;
333 GLint by = box[i].y1;
334 GLint bw = box[i].x2 - bx;
335 GLint bh = box[i].y2 - by;
336
337 if (bx < x) bw -= x - bx, bx = x;
338 if (by < y) bh -= y - by, by = y;
339 if (bx + bw > x + width) bw = x + width - bx;
340 if (by + bh > y + height) bh = y + height - by;
341 if (bw <= 0) continue;
342 if (bh <= 0) continue;
343
344 b->x1 = bx;
345 b->y1 = by;
346 b->x2 = bx + bw;
347 b->y2 = by + bh;
348 b++;
349 n++;
350 }
351
352 mmesa->sarea->nbox = n;
353
354 if (n && (retcode = drmCommandWrite( mmesa->driFd, DRM_MGA_BLIT,
355 &blit, sizeof(drmMGABlit)))) {
356 fprintf(stderr, "blit ioctl failed, retcode = %d\n", retcode);
357 UNLOCK_HARDWARE( mmesa );
358 exit(1);
359 }
360 }
361
362 UPDATE_LOCK( mmesa, DRM_LOCK_FLUSH | DRM_LOCK_QUIESCENT );
363 }
364 #endif
365
366 UNLOCK_HARDWARE( mmesa );
367
368 return GL_TRUE;
369 }
370
371 static void
372 mgaDDReadPixels( GLcontext *ctx,
373 GLint x, GLint y, GLsizei width, GLsizei height,
374 GLenum format, GLenum type,
375 const struct gl_pixelstore_attrib *pack,
376 GLvoid *pixels )
377 {
378 if (!mgaTryReadPixels( ctx, x, y, width, height, format, type, pack, pixels))
379 _swrast_ReadPixels( ctx, x, y, width, height, format, type, pack, pixels);
380 }
381
382
383
384
385 static void do_draw_pix( GLcontext *ctx,
386 GLint x, GLint y, GLsizei width, GLsizei height,
387 GLint pitch,
388 const void *pixels,
389 GLuint dest, GLuint planemask)
390 {
391 #if 0
392 mgaContextPtr mmesa = MGA_CONTEXT(ctx);
393 drmMGABlit blit;
394 __DRIdrawablePrivate *dPriv = mmesa->driDrawable;
395 drm_clip_rect_t pbox = dPriv->pClipRects;
396 int nbox = dPriv->numClipRects;
397 int retcode, i;
398
399 y = dPriv->h - y - height;
400 x += mmesa->drawX;
401 y += mmesa->drawY;
402
403 blit.dest = dest;
404 blit.planemask = planemask;
405 blit.source = ((mmesa->mgaScreen->agp.handle + AGP_OFFSET(mmesa, pixels))
406 | SO_srcmap_sys | SO_srcacc_agp);
407 blit.dest_pitch = mmesa->mgaScreen->frontPitch / mmesa->mgaScreen->cpp;
408 blit.source_pitch = pitch;
409 blit.delta_sx = -x;
410 blit.delta_sy = -y;
411 blit.delta_dx = 0;
412 blit.delta_dy = 0;
413 if (ctx->Pixel.ZoomY == -1) {
414 blit.height = height;
415 blit.ydir = 1;
416 } else {
417 blit.height = height;
418 blit.ydir = -1;
419 }
420
421 if (0) fprintf(stderr,
422 "doing drawpixel blit src_pitch %d dst_pitch %d\n",
423 blit.source_pitch, blit.dest_pitch);
424
425 for (i = 0 ; i < nbox ; )
426 {
427 int nr = MIN2(i + MGA_NR_SAREA_CLIPRECTS, dPriv->numClipRects);
428 drm_clip_rect_t *box = mmesa->pClipRects;
429 drm_clip_rect_t *b = mmesa->sarea->boxes;
430 int n = 0;
431
432 for ( ; i < nr ; i++) {
433 GLint bx = box[i].x1;
434 GLint by = box[i].y1;
435 GLint bw = box[i].x2 - bx;
436 GLint bh = box[i].y2 - by;
437
438 if (bx < x) bw -= x - bx, bx = x;
439 if (by < y) bh -= y - by, by = y;
440 if (bx + bw > x + width) bw = x + width - bx;
441 if (by + bh > y + height) bh = y + height - by;
442 if (bw <= 0) continue;
443 if (bh <= 0) continue;
444
445 b->x1 = bx;
446 b->y1 = by;
447 b->x2 = bx + bw;
448 b->y2 = by + bh;
449 b++;
450 n++;
451 }
452
453 mmesa->sarea->nbox = n;
454
455 if (n && (retcode = drmCommandWrite( mmesa->driFd, DRM_MGA_BLIT,
456 &blit, sizeof(drmMGABlit)))) {
457 fprintf(stderr, "blit ioctl failed, retcode = %d\n", retcode);
458 UNLOCK_HARDWARE( mmesa );
459 exit(1);
460 }
461 }
462 #endif
463 }
464
465
466
467
468 static GLboolean
469 mgaTryDrawPixels( GLcontext *ctx,
470 GLint x, GLint y, GLsizei width, GLsizei height,
471 GLenum format, GLenum type,
472 const struct gl_pixelstore_attrib *unpack,
473 const GLvoid *pixels )
474 {
475 mgaContextPtr mmesa = MGA_CONTEXT(ctx);
476 GLint size, skipPixels, skipRows;
477 GLint pitch = unpack->RowLength ? unpack->RowLength : width;
478 GLuint dest, planemask;
479 GLuint cpp = mmesa->mgaScreen->cpp;
480
481 if (!clip_pixelrect(ctx, ctx->DrawBuffer,
482 &x, &y, &width, &height,
483 &skipPixels, &skipRows, &size)) {
484 return GL_TRUE;
485 }
486
487
488 switch (format) {
489 #if defined(MESA_packed_depth_stencil)
490 case GL_DEPTH_STENCIL_MESA:
491 dest = mmesa->mgaScreen->depthOffset;
492 planemask = ~0;
493 if (!check_depth_stencil_24_8(ctx, type, unpack, pixels, size, pitch) ||
494 !check_depth_per_fragment_ops(ctx) ||
495 !check_stencil_per_fragment_ops(ctx))
496 return GL_FALSE;
497 break;
498 #endif
499
500 case GL_DEPTH_COMPONENT:
501 dest = mmesa->mgaScreen->depthOffset;
502
503 if (ctx->Visual.depthBits == 24)
504 planemask = ~0xff;
505 else
506 planemask = ~0;
507
508 if (!check_depth(ctx, type, unpack, pixels, size, pitch) ||
509 !check_depth_per_fragment_ops(ctx))
510 return GL_FALSE;
511 break;
512
513 case GL_RGB:
514 case GL_BGRA:
515 dest = (mmesa->draw_buffer == MGA_FRONT ?
516 mmesa->mgaScreen->frontOffset :
517 mmesa->mgaScreen->backOffset);
518
519 planemask = mgaPackColor(cpp,
520 ctx->Color.ColorMask[RCOMP],
521 ctx->Color.ColorMask[GCOMP],
522 ctx->Color.ColorMask[BCOMP],
523 ctx->Color.ColorMask[ACOMP]);
524
525 if (cpp == 2)
526 planemask |= planemask << 16;
527
528 if (!check_color(ctx, type, format, unpack, pixels, size, pitch)) {
529 return GL_FALSE;
530 }
531 if (!check_color_per_fragment_ops(ctx)) {
532 return GL_FALSE;
533 }
534 break;
535
536 default:
537 return GL_FALSE;
538 }
539
540 LOCK_HARDWARE_QUIESCENT( mmesa );
541
542 if (mmesa->dirty_cliprects & MGA_FRONT)
543 mgaUpdateRects( mmesa, MGA_FRONT );
544
545 if ( IS_AGP_MEM(mmesa, (char *)pixels) &&
546 IS_AGP_MEM(mmesa, (char *)pixels + size) )
547 {
548 do_draw_pix( ctx, x, y, width, height, pitch, pixels,
549 dest, planemask );
550 UPDATE_LOCK( mmesa, DRM_LOCK_FLUSH | DRM_LOCK_QUIESCENT );
551 }
552 else
553 {
554 /* Pixels is in regular memory -- get dma buffers and perform
555 * upload through them.
556 */
557 /* drmBufPtr buf = mgaGetBufferLocked(mmesa); */
558 GLuint bufferpitch = (width*cpp+31)&~31;
559
560 char *address = 0; /* mmesa->mgaScreen->agp.map; */
561
562 do {
563 /* GLuint rows = MIN2( height, MGA_DMA_BUF_SZ / bufferpitch ); */
564 GLuint rows = height;
565
566
567 if (0) fprintf(stderr, "trying to upload %d rows (pitch %d)\n",
568 rows, bufferpitch);
569
570 /* The texture conversion code is so slow that there is only
571 * negligble speedup when the buffers/images don't exactly
572 * match:
573 */
574 #if 0
575 if (cpp == 2) {
576 if (!_mesa_convert_texsubimage2d( MESA_FORMAT_RGB565,
577 0, 0, width, rows,
578 bufferpitch, format, type,
579 unpack, pixels, address )) {
580 /* mgaReleaseBufLocked( mmesa, buf ); */
581 UNLOCK_HARDWARE(mmesa);
582 return GL_FALSE;
583 }
584 } else {
585 if (!_mesa_convert_texsubimage2d( MESA_FORMAT_ARGB8888,
586 0, 0, width, rows,
587 bufferpitch, format, type,
588 unpack, pixels, address )) {
589 /* mgaReleaseBufLocked( mmesa, buf ); */
590 UNLOCK_HARDWARE(mmesa);
591 return GL_FALSE;
592 }
593 }
594 #else
595 MEMCPY( address, pixels, rows*bufferpitch );
596 #endif
597
598 do_draw_pix( ctx, x, y, width, rows,
599 bufferpitch/cpp, address, dest, planemask );
600
601 /* Fix me -- use multiple buffers to avoid flush.
602 */
603 UPDATE_LOCK( mmesa, DRM_LOCK_FLUSH | DRM_LOCK_QUIESCENT );
604
605 pixels = (void *)((char *) pixels + rows * pitch);
606 height -= rows;
607 y += rows;
608 } while (height);
609
610 /* mgaReleaseBufLocked( mmesa, buf ); */
611 }
612
613 UNLOCK_HARDWARE( mmesa );
614 mmesa->dirty |= MGA_UPLOAD_CLIPRECTS;
615
616 return GL_TRUE;
617 }
618
619 static void
620 mgaDDDrawPixels( GLcontext *ctx,
621 GLint x, GLint y, GLsizei width, GLsizei height,
622 GLenum format, GLenum type,
623 const struct gl_pixelstore_attrib *unpack,
624 const GLvoid *pixels )
625 {
626 if (!mgaTryDrawPixels( ctx, x, y, width, height, format, type,
627 unpack, pixels ))
628 _swrast_DrawPixels( ctx, x, y, width, height, format, type,
629 unpack, pixels );
630 }
631
632
633
634 /* Stub functions - not a real allocator, always returns pointer to
635 * the same block of agp space which isn't used for anything else at
636 * present.
637 */
638 void mgaDDInitPixelFuncs( GLcontext *ctx )
639 {
640 /* Pixel path fallbacks.
641 */
642 ctx->Driver.Accum = _swrast_Accum;
643 ctx->Driver.Bitmap = _swrast_Bitmap;
644 ctx->Driver.CopyPixels = _swrast_CopyPixels;
645 ctx->Driver.DrawPixels = _swrast_DrawPixels;
646 ctx->Driver.ReadPixels = _swrast_ReadPixels;
647
648 if (getenv("MGA_BLIT_PIXELS")) {
649 ctx->Driver.ReadPixels = mgaDDReadPixels; /* requires agp dest */
650 ctx->Driver.DrawPixels = mgaDDDrawPixels; /* works with agp/normal mem */
651 }
652 }