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.
27 * Implement framebuffer pixel operations for MGA.
30 * Someday the accelerated \c glReadPixels and \c glDrawPixels paths need to
31 * be resurrected. They are currently ifdef'ed out because they don't seem
32 * to work and they only get activated some very rare circumstances.
34 * \author Keith Whitwell <keith@tungstengraphics.com>
35 * \author Gareth Hughes <gareth@valinux.com>
38 #include "main/mtypes.h"
39 #include "main/macros.h"
41 #include "mgacontext.h"
46 #include "swrast/swrast.h"
47 #include "main/imports.h"
50 #define IS_AGP_MEM( mmesa, p ) \
51 ((unsigned long)mmesa->mgaScreen->buffers.map <= ((unsigned long)p) && \
52 (unsigned long)mmesa->mgaScreen->buffers.map + \
53 (unsigned long)mmesa->mgaScreen->buffers.size > ((unsigned long)p))
54 #define AGP_OFFSET( mmesa, p ) \
55 (((unsigned long)p) - (unsigned long)mmesa->mgaScreen->buffers.map)
59 check_depth_stencil_24_8( const struct gl_context *ctx, GLenum type,
60 const struct gl_pixelstore_attrib *packing,
61 const void *pixels, GLint sz,
64 mgaContextPtr mmesa = MGA_CONTEXT(ctx);
66 return ( type == GL_UNSIGNED_INT_24_8 &&
67 ctx->Visual->DepthBits == 24 &&
68 ctx->Visual->StencilBits == 8 &&
69 mmesa->mgaScreen->cpp == 4 &&
71 !ctx->Pixel.IndexShift &&
72 !ctx->Pixel.IndexOffset &&
73 !ctx->Pixel.MapStencilFlag &&
74 ctx->Pixel.DepthBias == 0.0 &&
75 ctx->Pixel.DepthScale == 1.0 &&
76 !packing->SwapBytes &&
83 check_depth( const struct gl_context *ctx, GLenum type,
84 const struct gl_pixelstore_attrib *packing,
85 const void *pixels, GLint sz, GLint pitch )
87 mgaContextPtr mmesa = MGA_CONTEXT(ctx);
89 if ( IS_AGP_MEM( mmesa, pixels ) &&
90 !( ( type == GL_UNSIGNED_INT && mmesa->mgaScreen->cpp == 4 ) ||
91 ( type == GL_UNSIGNED_SHORT && mmesa->mgaScreen->cpp == 2 ) ) )
94 return ( ctx->Pixel.DepthBias == 0.0 &&
95 ctx->Pixel.DepthScale == 1.0 &&
96 !packing->SwapBytes &&
103 check_color( const struct gl_context *ctx, GLenum type, GLenum format,
104 const struct gl_pixelstore_attrib *packing,
105 const void *pixels, GLint sz, GLint pitch )
107 mgaContextPtr mmesa = MGA_CONTEXT(ctx);
108 GLuint cpp = mmesa->mgaScreen->cpp;
110 /* Can't do conversions on agp reads/draws.
112 if ( IS_AGP_MEM( mmesa, pixels ) &&
113 !( pitch % 32 == 0 && pitch < 4096 &&
114 ( ( type == GL_UNSIGNED_BYTE &&
115 cpp == 4 && format == GL_BGRA ) ||
116 ( type == GL_UNSIGNED_INT_8_8_8_8 &&
117 cpp == 4 && format == GL_BGRA ) ||
118 ( type == GL_UNSIGNED_SHORT_5_6_5_REV &&
119 cpp == 2 && format == GL_RGB ) ) ) )
122 return (!ctx->_ImageTransferState &&
123 !packing->SwapBytes &&
128 check_color_per_fragment_ops( const struct gl_context *ctx )
130 return (!( ctx->Color.AlphaEnabled ||
133 ctx->Scissor.Enabled ||
134 ctx->Stencil._Enabled ||
135 !ctx->Color.ColorMask[0][0] ||
136 !ctx->Color.ColorMask[0][1] ||
137 !ctx->Color.ColorMask[0][2] ||
138 !ctx->Color.ColorMask[0][3] ||
139 ctx->Color.ColorLogicOpEnabled ||
140 ctx->Texture._EnabledUnits
142 ctx->Current.RasterPosValid &&
143 ctx->Pixel.ZoomX == 1.0F &&
144 (ctx->Pixel.ZoomY == 1.0F || ctx->Pixel.ZoomY == -1.0F));
148 check_depth_per_fragment_ops( const struct gl_context *ctx )
150 return ( ctx->Current.RasterPosValid &&
151 ctx->Color.ColorMask[0][RCOMP] == 0 &&
152 ctx->Color.ColorMask[0][BCOMP] == 0 &&
153 ctx->Color.ColorMask[0][GCOMP] == 0 &&
154 ctx->Color.ColorMask[0][ACOMP] == 0 &&
155 ctx->Pixel.ZoomX == 1.0F &&
156 ( ctx->Pixel.ZoomY == 1.0F || ctx->Pixel.ZoomY == -1.0F ) );
159 /* In addition to the requirements for depth:
161 #if defined(MESA_packed_depth_stencil)
163 check_stencil_per_fragment_ops( const struct gl_context *ctx )
165 return ( !ctx->Pixel.IndexShift &&
166 !ctx->Pixel.IndexOffset );
172 clip_pixelrect( const struct gl_context *ctx,
173 const struct gl_framebuffer *buffer,
175 GLsizei *width, GLsizei *height,
176 GLint *skipPixels, GLint *skipRows,
179 mgaContextPtr mmesa = MGA_CONTEXT(ctx);
181 *width = MIN2(*width, MAX_WIDTH); /* redundant? */
184 if (*x < buffer->_Xmin) {
185 *skipPixels += (buffer->_Xmin - *x);
186 *width -= (buffer->_Xmin - *x);
191 if (*x + *width > buffer->_Xmax)
192 *width -= (*x + *width - buffer->_Xmax - 1);
197 /* bottom clipping */
198 if (*y < buffer->_Ymin) {
199 *skipRows += (buffer->_Ymin - *y);
200 *height -= (buffer->_Ymin - *y);
205 if (*y + *height > buffer->_Ymax)
206 *height -= (*y + *height - buffer->_Ymax - 1);
211 *size = ((*y + *height - 1) * mmesa->mgaScreen->frontPitch +
212 (*x + *width - 1) * mmesa->mgaScreen->cpp);
218 mgaTryReadPixels( struct gl_context *ctx,
219 GLint x, GLint y, GLsizei width, GLsizei height,
220 GLenum format, GLenum type,
221 const struct gl_pixelstore_attrib *pack,
224 mgaContextPtr mmesa = MGA_CONTEXT(ctx);
225 GLint size, skipPixels, skipRows;
226 GLint pitch = pack->RowLength ? pack->RowLength : width;
234 GLint source_pitch, dest_pitch;
235 GLint delta_sx, delta_sy;
236 GLint delta_dx, delta_dy;
237 GLint blit_height, ydir;
240 if (!clip_pixelrect(ctx, ctx->ReadBuffer,
241 &x, &y, &width, &height,
242 &skipPixels, &skipRows, &size)) {
246 /* Only accelerate reading to agp buffers.
248 if ( !IS_AGP_MEM(mmesa, (char *)pixels) ||
249 !IS_AGP_MEM(mmesa, (char *)pixels + size) )
253 case GL_DEPTH_STENCIL:
254 ok = check_depth_stencil_24_8(ctx, type, pack, pixels, size, pitch);
256 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 __DRIdrawable *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 drm_clip_rect_t *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( struct gl_context *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( struct gl_context *ctx,
390 GLint x, GLint y, GLsizei width, GLsizei height,
393 GLuint dest, GLuint planemask)
396 mgaContextPtr mmesa = MGA_CONTEXT(ctx);
398 __DRIdrawable *dPriv = mmesa->driDrawable;
399 drm_clip_rect_t 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 drm_clip_rect_t *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( struct gl_context *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 case GL_DEPTH_STENCIL:
494 dest = mmesa->mgaScreen->depthOffset;
496 if (!check_depth_stencil_24_8(ctx, type, unpack, pixels, size, pitch) ||
497 !check_depth_per_fragment_ops(ctx) ||
498 !check_stencil_per_fragment_ops(ctx))
502 case GL_DEPTH_COMPONENT:
503 dest = mmesa->mgaScreen->depthOffset;
505 if (ctx->Visual.depthBits == 24)
510 if (!check_depth(ctx, type, unpack, pixels, size, pitch) ||
511 !check_depth_per_fragment_ops(ctx))
517 dest = (mmesa->draw_buffer == MGA_FRONT ?
518 mmesa->mgaScreen->frontOffset :
519 mmesa->mgaScreen->backOffset);
521 planemask = mgaPackColor(cpp,
522 ctx->Color.ColorMask[0][RCOMP],
523 ctx->Color.ColorMask[0][GCOMP],
524 ctx->Color.ColorMask[0][BCOMP],
525 ctx->Color.ColorMask[0][ACOMP]);
528 planemask |= planemask << 16;
530 if (!check_color(ctx, type, format, unpack, pixels, size, pitch)) {
533 if (!check_color_per_fragment_ops(ctx)) {
542 LOCK_HARDWARE_QUIESCENT( mmesa );
544 if (mmesa->dirty_cliprects & MGA_FRONT)
545 mgaUpdateRects( mmesa, MGA_FRONT );
547 if ( IS_AGP_MEM(mmesa, (char *)pixels) &&
548 IS_AGP_MEM(mmesa, (char *)pixels + size) )
550 do_draw_pix( ctx, x, y, width, height, pitch, pixels,
552 UPDATE_LOCK( mmesa, DRM_LOCK_FLUSH | DRM_LOCK_QUIESCENT );
556 /* Pixels is in regular memory -- get dma buffers and perform
557 * upload through them.
559 /* drmBufPtr buf = mgaGetBufferLocked(mmesa); */
560 GLuint bufferpitch = (width*cpp+31)&~31;
562 char *address = 0; /* mmesa->mgaScreen->agp.map; */
565 /* GLuint rows = MIN2( height, MGA_DMA_BUF_SZ / bufferpitch ); */
566 GLuint rows = height;
569 if (0) fprintf(stderr, "trying to upload %d rows (pitch %d)\n",
572 /* The texture conversion code is so slow that there is only
573 * negligble speedup when the buffers/images don't exactly
578 if (!_mesa_convert_texsubimage2d( MESA_FORMAT_RGB565,
580 bufferpitch, format, type,
581 unpack, pixels, address )) {
582 /* mgaReleaseBufLocked( mmesa, buf ); */
583 UNLOCK_HARDWARE(mmesa);
587 if (!_mesa_convert_texsubimage2d( MESA_FORMAT_ARGB8888,
589 bufferpitch, format, type,
590 unpack, pixels, address )) {
591 /* mgaReleaseBufLocked( mmesa, buf ); */
592 UNLOCK_HARDWARE(mmesa);
597 memcpy( address, pixels, rows*bufferpitch );
600 do_draw_pix( ctx, x, y, width, rows,
601 bufferpitch/cpp, address, dest, planemask );
603 /* Fix me -- use multiple buffers to avoid flush.
605 UPDATE_LOCK( mmesa, DRM_LOCK_FLUSH | DRM_LOCK_QUIESCENT );
607 pixels = (void *)((char *) pixels + rows * pitch);
612 /* mgaReleaseBufLocked( mmesa, buf ); */
615 UNLOCK_HARDWARE( mmesa );
616 mmesa->dirty |= MGA_UPLOAD_CLIPRECTS;
622 mgaDDDrawPixels( struct gl_context *ctx,
623 GLint x, GLint y, GLsizei width, GLsizei height,
624 GLenum format, GLenum type,
625 const struct gl_pixelstore_attrib *unpack,
626 const GLvoid *pixels )
628 if (!mgaTryDrawPixels( ctx, x, y, width, height, format, type,
630 _swrast_DrawPixels( ctx, x, y, width, height, format, type,
636 /* Stub functions - not a real allocator, always returns pointer to
637 * the same block of agp space which isn't used for anything else at
640 void mgaDDInitPixelFuncs( struct gl_context *ctx )
643 /* evidently, these functions don't always work */
644 if (getenv("MGA_BLIT_PIXELS")) {
645 ctx->Driver.ReadPixels = mgaDDReadPixels; /* requires agp dest */
646 ctx->Driver.DrawPixels = mgaDDDrawPixels; /* works with agp/normal mem */