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