2 * Copyright 2000 Compaq Computer Inc. and VA Linux Systems, Inc.
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:
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
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.
25 * Keith Whitwell <keith@tungstengraphics.com>
26 * Gareth Hughes <gareth@valinux.com>
28 /* $XFree86: xc/lib/GL/mesa/src/drv/mga/mgapixel.c,v 1.9 2002/11/05 17:46:08 tsi Exp $ */
35 #include "mgacontext.h"
40 #include "mga_common.h"
42 #include "swrast/swrast.h"
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)
53 #if defined(MESA_packed_depth_stencil)
55 check_depth_stencil_24_8( const GLcontext
*ctx
, GLenum type
,
56 const struct gl_pixelstore_attrib
*packing
,
57 const void *pixels
, GLint sz
,
60 mgaContextPtr mmesa
= MGA_CONTEXT(ctx
);
62 return ( type
== GL_UNSIGNED_INT_24_8_MESA
&&
63 ctx
->Visual
->DepthBits
== 24 &&
64 ctx
->Visual
->StencilBits
== 8 &&
65 mmesa
->mgaScreen
->cpp
== 4 &&
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
&&
80 check_depth( const GLcontext
*ctx
, GLenum type
,
81 const struct gl_pixelstore_attrib
*packing
,
82 const void *pixels
, GLint sz
, GLint pitch
)
84 mgaContextPtr mmesa
= MGA_CONTEXT(ctx
);
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 ) ) )
91 return ( ctx
->Pixel
.DepthBias
== 0.0 &&
92 ctx
->Pixel
.DepthScale
== 1.0 &&
93 !packing
->SwapBytes
&&
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
)
104 mgaContextPtr mmesa
= MGA_CONTEXT(ctx
);
105 GLuint cpp
= mmesa
->mgaScreen
->cpp
;
107 /* Can't do conversions on agp reads/draws.
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
) ) ) )
119 return (!ctx
->_ImageTransferState
&&
120 !packing
->SwapBytes
&&
125 check_color_per_fragment_ops( const GLcontext
*ctx
)
127 return (!( ctx
->Color
.AlphaEnabled
||
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
140 ctx
->Current
.RasterPosValid
&&
141 ctx
->Pixel
.ZoomX
== 1.0F
&&
142 (ctx
->Pixel
.ZoomY
== 1.0F
|| ctx
->Pixel
.ZoomY
== -1.0F
));
146 check_depth_per_fragment_ops( const GLcontext
*ctx
)
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
) );
157 /* In addition to the requirements for depth:
159 #if defined(MESA_packed_depth_stencil)
161 check_stencil_per_fragment_ops( const GLcontext
*ctx
)
163 return ( !ctx
->Pixel
.IndexShift
&&
164 !ctx
->Pixel
.IndexOffset
);
170 clip_pixelrect( const GLcontext
*ctx
,
171 const GLframebuffer
*buffer
,
173 GLsizei
*width
, GLsizei
*height
,
174 GLint
*skipPixels
, GLint
*skipRows
,
177 mgaContextPtr mmesa
= MGA_CONTEXT(ctx
);
179 *width
= MIN2(*width
, MAX_WIDTH
); /* redundant? */
182 if (*x
< buffer
->_Xmin
) {
183 *skipPixels
+= (buffer
->_Xmin
- *x
);
184 *width
-= (buffer
->_Xmin
- *x
);
189 if (*x
+ *width
> buffer
->_Xmax
)
190 *width
-= (*x
+ *width
- buffer
->_Xmax
- 1);
195 /* bottom clipping */
196 if (*y
< buffer
->_Ymin
) {
197 *skipRows
+= (buffer
->_Ymin
- *y
);
198 *height
-= (buffer
->_Ymin
- *y
);
203 if (*y
+ *height
> buffer
->_Ymax
)
204 *height
-= (*y
+ *height
- buffer
->_Ymax
- 1);
209 *size
= ((*y
+ *height
- 1) * mmesa
->mgaScreen
->frontPitch
+
210 (*x
+ *width
- 1) * mmesa
->mgaScreen
->cpp
);
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
,
222 mgaContextPtr mmesa
= MGA_CONTEXT(ctx
);
223 GLint size
, skipPixels
, skipRows
;
224 GLint pitch
= pack
->RowLength
? pack
->RowLength
: width
;
232 GLint source_pitch
, dest_pitch
;
233 GLint delta_sx
, delta_sy
;
234 GLint delta_dx
, delta_dy
;
235 GLint blit_height
, ydir
;
238 if (!clip_pixelrect(ctx
, ctx
->ReadBuffer
,
239 &x
, &y
, &width
, &height
,
240 &skipPixels
, &skipRows
, &size
)) {
244 /* Only accelerate reading to agp buffers.
246 if ( !IS_AGP_MEM(mmesa
, (char *)pixels
) ||
247 !IS_AGP_MEM(mmesa
, (char *)pixels
+ size
) )
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
);
255 source
= mmesa
->mgaScreen
->depthOffset
;
259 case GL_DEPTH_COMPONENT
:
260 ok
= check_depth(ctx
, type
, pack
, pixels
, size
, pitch
);
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.
266 * Could get the acclerator to solid fill the destination with
267 * zeros first... Or get the cpu to do it...
269 if (ctx
->Visual
.depthBits
== 24)
273 source
= mmesa
->mgaScreen
->depthOffset
;
278 ok
= check_color(ctx
, type
, format
, pack
, pixels
, size
, pitch
);
280 source
= (mmesa
->draw_buffer
== MGA_FRONT
?
281 mmesa
->mgaScreen
->frontOffset
:
282 mmesa
->mgaScreen
->backOffset
);
294 LOCK_HARDWARE( mmesa
);
298 __DRIdrawablePrivate
*dPriv
= mmesa
->driDrawable
;
299 int nbox
, retcode
, i
;
301 UPDATE_LOCK( mmesa
, DRM_LOCK_FLUSH
| DRM_LOCK_QUIESCENT
);
303 if (mmesa
->dirty_cliprects
& MGA_FRONT
)
304 mgaUpdateRects( mmesa
, MGA_FRONT
);
306 nbox
= dPriv
->numClipRects
;
308 y
= dPriv
->h
- y
- height
;
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
;
320 blit_height
= 2*y
+ height
;
323 if (0) fprintf(stderr
, "XX doing readpixel blit src_pitch %d dst_pitch %d\n",
324 source_pitch
, dest_pitch
);
328 for (i
= 0 ; i
< nbox
; )
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
;
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
;
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;
356 mmesa
->sarea
->nbox
= n
;
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
);
366 UPDATE_LOCK( mmesa
, DRM_LOCK_FLUSH
| DRM_LOCK_QUIESCENT
);
370 UNLOCK_HARDWARE( mmesa
);
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
,
382 if (!mgaTryReadPixels( ctx
, x
, y
, width
, height
, format
, type
, pack
, pixels
))
383 _swrast_ReadPixels( ctx
, x
, y
, width
, height
, format
, type
, pack
, pixels
);
389 static void do_draw_pix( GLcontext
*ctx
,
390 GLint x
, GLint y
, GLsizei width
, GLsizei height
,
393 GLuint dest
, GLuint planemask
)
396 mgaContextPtr mmesa
= MGA_CONTEXT(ctx
);
398 __DRIdrawablePrivate
*dPriv
= mmesa
->driDrawable
;
399 XF86DRIClipRectPtr pbox
= dPriv
->pClipRects
;
400 int nbox
= dPriv
->numClipRects
;
403 y
= dPriv
->h
- y
- height
;
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
;
417 if (ctx
->Pixel
.ZoomY
== -1) {
418 blit
.height
= height
;
421 blit
.height
= height
;
425 if (0) fprintf(stderr
,
426 "doing drawpixel blit src_pitch %d dst_pitch %d\n",
427 blit
.source_pitch
, blit
.dest_pitch
);
429 for (i
= 0 ; i
< nbox
; )
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
;
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
;
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;
457 mmesa
->sarea
->nbox
= n
;
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
);
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
)
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
;
485 if (!clip_pixelrect(ctx
, ctx
->DrawBuffer
,
486 &x
, &y
, &width
, &height
,
487 &skipPixels
, &skipRows
, &size
)) {
493 #if defined(MESA_packed_depth_stencil)
494 case GL_DEPTH_STENCIL_MESA
:
495 dest
= mmesa
->mgaScreen
->depthOffset
;
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
))
504 case GL_DEPTH_COMPONENT
:
505 dest
= mmesa
->mgaScreen
->depthOffset
;
507 if (ctx
->Visual
.depthBits
== 24)
512 if (!check_depth(ctx
, type
, unpack
, pixels
, size
, pitch
) ||
513 !check_depth_per_fragment_ops(ctx
))
519 dest
= (mmesa
->draw_buffer
== MGA_FRONT
?
520 mmesa
->mgaScreen
->frontOffset
:
521 mmesa
->mgaScreen
->backOffset
);
523 planemask
= mgaPackColor(cpp
,
524 ctx
->Color
.ColorMask
[RCOMP
],
525 ctx
->Color
.ColorMask
[GCOMP
],
526 ctx
->Color
.ColorMask
[BCOMP
],
527 ctx
->Color
.ColorMask
[ACOMP
]);
530 planemask
|= planemask
<< 16;
532 if (!check_color(ctx
, type
, format
, unpack
, pixels
, size
, pitch
)) {
535 if (!check_color_per_fragment_ops(ctx
)) {
544 LOCK_HARDWARE_QUIESCENT( mmesa
);
546 if (mmesa
->dirty_cliprects
& MGA_FRONT
)
547 mgaUpdateRects( mmesa
, MGA_FRONT
);
549 if ( IS_AGP_MEM(mmesa
, (char *)pixels
) &&
550 IS_AGP_MEM(mmesa
, (char *)pixels
+ size
) )
552 do_draw_pix( ctx
, x
, y
, width
, height
, pitch
, pixels
,
554 UPDATE_LOCK( mmesa
, DRM_LOCK_FLUSH
| DRM_LOCK_QUIESCENT
);
558 /* Pixels is in regular memory -- get dma buffers and perform
559 * upload through them.
561 /* drmBufPtr buf = mgaGetBufferLocked(mmesa); */
562 GLuint bufferpitch
= (width
*cpp
+31)&~31;
564 char *address
= 0; /* mmesa->mgaScreen->agp.map; */
567 /* GLuint rows = MIN2( height, MGA_DMA_BUF_SZ / bufferpitch ); */
568 GLuint rows
= height
;
571 if (0) fprintf(stderr
, "trying to upload %d rows (pitch %d)\n",
574 /* The texture conversion code is so slow that there is only
575 * negligble speedup when the buffers/images don't exactly
580 if (!_mesa_convert_texsubimage2d( MESA_FORMAT_RGB565
,
582 bufferpitch
, format
, type
,
583 unpack
, pixels
, address
)) {
584 /* mgaReleaseBufLocked( mmesa, buf ); */
585 UNLOCK_HARDWARE(mmesa
);
589 if (!_mesa_convert_texsubimage2d( MESA_FORMAT_ARGB8888
,
591 bufferpitch
, format
, type
,
592 unpack
, pixels
, address
)) {
593 /* mgaReleaseBufLocked( mmesa, buf ); */
594 UNLOCK_HARDWARE(mmesa
);
599 MEMCPY( address
, pixels
, rows
*bufferpitch
);
602 do_draw_pix( ctx
, x
, y
, width
, rows
,
603 bufferpitch
/cpp
, address
, dest
, planemask
);
605 /* Fix me -- use multiple buffers to avoid flush.
607 UPDATE_LOCK( mmesa
, DRM_LOCK_FLUSH
| DRM_LOCK_QUIESCENT
);
609 pixels
= (void *)((char *) pixels
+ rows
* pitch
);
614 /* mgaReleaseBufLocked( mmesa, buf ); */
617 UNLOCK_HARDWARE( mmesa
);
618 mmesa
->dirty
|= MGA_UPLOAD_CLIPRECTS
;
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
)
630 if (!mgaTryDrawPixels( ctx
, x
, y
, width
, height
, format
, type
,
632 _swrast_DrawPixels( ctx
, x
, y
, width
, height
, format
, type
,
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
642 void mgaDDInitPixelFuncs( GLcontext
*ctx
)
644 /* Pixel path fallbacks.
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
;
652 if (getenv("MGA_BLIT_PIXELS")) {
653 ctx
->Driver
.ReadPixels
= mgaDDReadPixels
; /* requires agp dest */
654 ctx
->Driver
.DrawPixels
= mgaDDDrawPixels
; /* works with agp/normal mem */