1 /* -*- mode: c; c-basic-offset: 3 -*-
3 * Copyright 2000 VA Linux Systems Inc., Fremont, California.
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation
10 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 * and/or sell copies of the Software, and to permit persons to whom the
12 * Software is furnished to do so, subject to the following conditions:
14 * The above copyright notice and this permission notice (including the next
15 * paragraph) shall be included in all copies or substantial portions of the
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
21 * VA LINUX SYSTEMS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
22 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
23 * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26 /* $XFree86: xc/lib/GL/mesa/src/drv/tdfx/tdfx_pixels.c,v 1.4 2002/02/22 21:45:03 dawes Exp $ */
30 * Gareth Hughes <gareth@valinux.com>, 29 Sep - 1 Oct 2000
33 * Gareth Hughes <gareth@valinux.com>
34 * Brian Paul <brianp@valinux.com>
35 * Nathan Hand <nhand@valinux.com>
39 #include "tdfx_context.h"
41 #include "tdfx_lock.h"
43 #include "tdfx_pixels.h"
44 #include "tdfx_render.h"
46 #include "swrast/swrast.h"
48 #include "main/image.h"
51 #define FX_grLfbWriteRegion(fxMesa,dst_buffer,dst_x,dst_y,src_format,src_width,src_height,src_stride,src_data) \
53 LOCK_HARDWARE(fxMesa); \
54 fxMesa->Glide.grLfbWriteRegion(dst_buffer,dst_x,dst_y,src_format,src_width,src_height,FXFALSE,src_stride,src_data); \
55 UNLOCK_HARDWARE(fxMesa); \
59 #define FX_grLfbReadRegion(fxMesa,src_buffer,src_x,src_y,src_width,src_height,dst_stride,dst_data) \
61 LOCK_HARDWARE(fxMesa); \
62 fxMesa->Glide.grLfbReadRegion(src_buffer,src_x,src_y,src_width,src_height,dst_stride,dst_data); \
63 UNLOCK_HARDWARE(fxMesa); \
69 FX_grLfbLock(tdfxContextPtr fxMesa
, GrLock_t type
, GrBuffer_t buffer
,
70 GrLfbWriteMode_t writeMode
, GrOriginLocation_t origin
,
71 FxBool pixelPipeline
, GrLfbInfo_t
* info
)
75 LOCK_HARDWARE(fxMesa
);
76 result
= fxMesa
->Glide
.grLfbLock(type
, buffer
, writeMode
, origin
, pixelPipeline
, info
);
77 UNLOCK_HARDWARE(fxMesa
);
83 #define FX_grLfbUnlock(fxMesa, t, b) \
85 LOCK_HARDWARE(fxMesa); \
86 fxMesa->Glide.grLfbUnlock(t, b); \
87 UNLOCK_HARDWARE(fxMesa); \
93 /* test if window coord (px,py) is visible */
95 inClipRects(tdfxContextPtr fxMesa
, int px
, int py
)
98 for (i
= 0; i
< fxMesa
->numClipRects
; i
++) {
99 if ((px
>= fxMesa
->pClipRects
[i
].x1
) &&
100 (px
< fxMesa
->pClipRects
[i
].x2
) &&
101 (py
>= fxMesa
->pClipRects
[i
].y1
) &&
102 (py
< fxMesa
->pClipRects
[i
].y2
)) return GL_TRUE
;
108 /* test if rectangle of pixels (px,py) (px+width,py+height) is visible */
110 inClipRects_Region(tdfxContextPtr fxMesa
, int x
, int y
, int width
, int height
)
114 int xmin
, xmax
, ymin
, ymax
, pixelsleft
;
116 y1
= y
- height
+ 1; y2
= y
;
117 x1
= x
; x2
= x
+ width
- 1;
118 pixelsleft
= width
* height
;
120 for (i
= 0; i
< fxMesa
->numClipRects
; i
++)
122 /* algorithm requires x1 < x2 and y1 < y2 */
123 if ((fxMesa
->pClipRects
[i
].x1
< fxMesa
->pClipRects
[i
].x2
)) {
124 xmin
= fxMesa
->pClipRects
[i
].x1
;
125 xmax
= fxMesa
->pClipRects
[i
].x2
-1;
127 xmin
= fxMesa
->pClipRects
[i
].x2
;
128 xmax
= fxMesa
->pClipRects
[i
].x1
-1;
130 if ((fxMesa
->pClipRects
[i
].y1
< fxMesa
->pClipRects
[i
].y2
)) {
131 ymin
= fxMesa
->pClipRects
[i
].y1
;
132 ymax
= fxMesa
->pClipRects
[i
].y2
-1;
134 ymin
= fxMesa
->pClipRects
[i
].y2
;
135 ymax
= fxMesa
->pClipRects
[i
].y1
-1;
138 /* reject trivial cases */
139 if (xmax
< x1
) continue;
140 if (ymax
< y1
) continue;
141 if (xmin
> x2
) continue;
142 if (ymin
> y2
) continue;
144 /* find the intersection */
145 if (xmin
< x1
) xmin
= x1
;
146 if (ymin
< y1
) ymin
= y1
;
147 if (xmax
> x2
) xmax
= x2
;
148 if (ymax
> y2
) ymax
= y2
;
150 pixelsleft
-= (xmax
-xmin
+1) * (ymax
-ymin
+1);
153 return pixelsleft
== 0;
158 tdfx_bitmap_R5G6B5(GLcontext
* ctx
, GLint px
, GLint py
,
159 GLsizei width
, GLsizei height
,
160 const struct gl_pixelstore_attrib
*unpack
,
161 const GLubyte
* bitmap
)
163 tdfxContextPtr fxMesa
= TDFX_CONTEXT(ctx
);
166 const struct gl_pixelstore_attrib
*finalUnpack
;
167 struct gl_pixelstore_attrib scissoredUnpack
;
169 /* check if there's any raster operations enabled which we can't handle */
170 if (ctx
->RasterMask
& (ALPHATEST_BIT
|
178 MULTI_DRAW_BIT
)) return GL_FALSE
;
180 if (ctx
->Scissor
.Enabled
) {
181 /* This is a bit tricky, but by carefully adjusting the px, py,
182 * width, height, skipPixels and skipRows values we can do
183 * scissoring without special code in the rendering loop.
186 /* we'll construct a new pixelstore struct */
187 finalUnpack
= &scissoredUnpack
;
188 scissoredUnpack
= *unpack
;
189 if (scissoredUnpack
.RowLength
== 0)
190 scissoredUnpack
.RowLength
= width
;
193 if (px
< ctx
->Scissor
.X
) {
194 scissoredUnpack
.SkipPixels
+= (ctx
->Scissor
.X
- px
);
195 width
-= (ctx
->Scissor
.X
- px
);
199 if (px
+ width
>= ctx
->Scissor
.X
+ ctx
->Scissor
.Width
) {
200 width
-= (px
+ width
- (ctx
->Scissor
.X
+ ctx
->Scissor
.Width
));
203 if (py
< ctx
->Scissor
.Y
) {
204 scissoredUnpack
.SkipRows
+= (ctx
->Scissor
.Y
- py
);
205 height
-= (ctx
->Scissor
.Y
- py
);
209 if (py
+ height
>= ctx
->Scissor
.Y
+ ctx
->Scissor
.Height
) {
210 height
-= (py
+ height
- (ctx
->Scissor
.Y
+ ctx
->Scissor
.Height
));
213 if (width
<= 0 || height
<= 0)
214 return GL_TRUE
; /* totally scissored away */
217 finalUnpack
= unpack
;
220 /* compute pixel value */
222 GLint r
= (GLint
) (ctx
->Current
.RasterColor
[0] * 255.0f
);
223 GLint g
= (GLint
) (ctx
->Current
.RasterColor
[1] * 255.0f
);
224 GLint b
= (GLint
) (ctx
->Current
.RasterColor
[2] * 255.0f
);
225 /*GLint a = (GLint)(ctx->Current.RasterColor[3]*255.0f); */
226 if (fxMesa
->bgrOrder
) {
228 (((TdfxU16
) 0xf8 & b
) << (11 - 3)) |
229 (((TdfxU16
) 0xfc & g
) << (5 - 3 + 1)) |
230 (((TdfxU16
) 0xf8 & r
) >> 3);
234 (((TdfxU16
) 0xf8 & r
) << (11 - 3)) |
235 (((TdfxU16
) 0xfc & g
) << (5 - 3 + 1)) |
236 (((TdfxU16
) 0xf8 & b
) >> 3);
239 info
.size
= sizeof(info
);
240 if (!TDFX_grLfbLock(fxMesa
,
244 GR_ORIGIN_UPPER_LEFT
, FXFALSE
, &info
)) {
246 fprintf(stderr
, "tdfx Driver: error locking the linear frame buffer\n");
252 const GLint winX
= fxMesa
->x_offset
;
253 const GLint winY
= fxMesa
->y_offset
+ fxMesa
->height
- 1;
254 /* The dest stride depends on the hardware and whether we're drawing
255 * to the front or back buffer. This compile-time test seems to do
258 const GLint dstStride
= (fxMesa
->glCtx
->Color
.DrawBuffer
[0] == GL_FRONT
)
259 ? (fxMesa
->screen_width
) : (info
.strideInBytes
/ 2);
261 /* compute dest address of bottom-left pixel in bitmap */
262 GLushort
*dst
= (GLushort
*) info
.lfbPtr
263 + (winY
- py
) * dstStride
+ (winX
+ px
);
265 for (row
= 0; row
< height
; row
++) {
267 (const GLubyte
*) _mesa_image_address2d(finalUnpack
,
268 bitmap
, width
, height
,
271 if (finalUnpack
->LsbFirst
) {
272 /* least significan bit first */
273 GLubyte mask
= 1U << (finalUnpack
->SkipPixels
& 0x7);
275 for (col
= 0; col
< width
; col
++) {
277 if (inClipRects(fxMesa
, winX
+ px
+ col
, winY
- py
- row
))
292 /* most significan bit first */
293 GLubyte mask
= 128U >> (finalUnpack
->SkipPixels
& 0x7);
295 for (col
= 0; col
< width
; col
++) {
297 if (inClipRects(fxMesa
, winX
+ px
+ col
, winY
- py
- row
))
315 TDFX_grLfbUnlock(fxMesa
, GR_LFB_WRITE_ONLY
, fxMesa
->currentFB
);
322 tdfx_bitmap_R8G8B8A8(GLcontext
* ctx
, GLint px
, GLint py
,
323 GLsizei width
, GLsizei height
,
324 const struct gl_pixelstore_attrib
*unpack
,
325 const GLubyte
* bitmap
)
327 tdfxContextPtr fxMesa
= TDFX_CONTEXT(ctx
);
330 const struct gl_pixelstore_attrib
*finalUnpack
;
331 struct gl_pixelstore_attrib scissoredUnpack
;
333 /* check if there's any raster operations enabled which we can't handle */
334 if (ctx
->RasterMask
& (ALPHATEST_BIT
|
342 MULTI_DRAW_BIT
)) return GL_FALSE
;
344 if (ctx
->Scissor
.Enabled
) {
345 /* This is a bit tricky, but by carefully adjusting the px, py,
346 * width, height, skipPixels and skipRows values we can do
347 * scissoring without special code in the rendering loop.
350 /* we'll construct a new pixelstore struct */
351 finalUnpack
= &scissoredUnpack
;
352 scissoredUnpack
= *unpack
;
353 if (scissoredUnpack
.RowLength
== 0)
354 scissoredUnpack
.RowLength
= width
;
357 if (px
< ctx
->Scissor
.X
) {
358 scissoredUnpack
.SkipPixels
+= (ctx
->Scissor
.X
- px
);
359 width
-= (ctx
->Scissor
.X
- px
);
363 if (px
+ width
>= ctx
->Scissor
.X
+ ctx
->Scissor
.Width
) {
364 width
-= (px
+ width
- (ctx
->Scissor
.X
+ ctx
->Scissor
.Width
));
367 if (py
< ctx
->Scissor
.Y
) {
368 scissoredUnpack
.SkipRows
+= (ctx
->Scissor
.Y
- py
);
369 height
-= (ctx
->Scissor
.Y
- py
);
373 if (py
+ height
>= ctx
->Scissor
.Y
+ ctx
->Scissor
.Height
) {
374 height
-= (py
+ height
- (ctx
->Scissor
.Y
+ ctx
->Scissor
.Height
));
377 if (width
<= 0 || height
<= 0)
378 return GL_TRUE
; /* totally scissored away */
381 finalUnpack
= unpack
;
384 /* compute pixel value */
386 GLint r
= (GLint
) (ctx
->Current
.RasterColor
[0] * 255.0f
);
387 GLint g
= (GLint
) (ctx
->Current
.RasterColor
[1] * 255.0f
);
388 GLint b
= (GLint
) (ctx
->Current
.RasterColor
[2] * 255.0f
);
389 GLint a
= (GLint
) (ctx
->Current
.RasterColor
[3] * 255.0f
);
390 color
= PACK_BGRA32(r
, g
, b
, a
);
393 info
.size
= sizeof(info
);
394 if (!TDFX_grLfbLock(fxMesa
, GR_LFB_WRITE_ONLY
,
395 fxMesa
->currentFB
, GR_LFBWRITEMODE_8888
,
396 GR_ORIGIN_UPPER_LEFT
, FXFALSE
, &info
)) {
398 fprintf(stderr
, "tdfx Driver: error locking the linear frame buffer\n");
404 const GLint winX
= fxMesa
->x_offset
;
405 const GLint winY
= fxMesa
->y_offset
+ fxMesa
->height
- 1;
410 if (fxMesa
->glCtx
->Color
.DrawBuffer
[0] == GL_FRONT
) {
411 dstStride
= fxMesa
->screen_width
;
413 (GLuint
*) info
.lfbPtr
+ (winY
- py
) * dstStride
+ (winX
+
417 dstStride
= info
.strideInBytes
/ 4;
419 (GLuint
*) info
.lfbPtr
+ (winY
- py
) * dstStride
+ (winX
+
423 /* compute dest address of bottom-left pixel in bitmap */
424 for (row
= 0; row
< height
; row
++) {
426 (const GLubyte
*) _mesa_image_address2d(finalUnpack
,
427 bitmap
, width
, height
,
430 if (finalUnpack
->LsbFirst
) {
431 /* least significan bit first */
432 GLubyte mask
= 1U << (finalUnpack
->SkipPixels
& 0x7);
434 for (col
= 0; col
< width
; col
++) {
436 if (inClipRects(fxMesa
, winX
+ px
+ col
, winY
- py
- row
))
451 /* most significan bit first */
452 GLubyte mask
= 128U >> (finalUnpack
->SkipPixels
& 0x7);
454 for (col
= 0; col
< width
; col
++) {
456 if (inClipRects(fxMesa
, winX
+ px
+ col
, winY
- py
- row
))
474 TDFX_grLfbUnlock(fxMesa
, GR_LFB_WRITE_ONLY
, fxMesa
->currentFB
);
480 tdfx_readpixels_R5G6B5(GLcontext
* ctx
, GLint x
, GLint y
,
481 GLsizei width
, GLsizei height
,
482 GLenum format
, GLenum type
,
483 const struct gl_pixelstore_attrib
*packing
,
486 if (format
!= GL_RGB
||
487 type
!= GL_UNSIGNED_SHORT_5_6_5
||
488 (ctx
->_ImageTransferState
& (IMAGE_SCALE_BIAS_BIT
|
489 IMAGE_MAP_COLOR_BIT
)))
491 _swrast_ReadPixels( ctx
, x
, y
, width
, height
, format
, type
, packing
,
497 tdfxContextPtr fxMesa
= TDFX_CONTEXT(ctx
);
499 __DRIdrawablePrivate
*const readable
= fxMesa
->driReadable
;
500 const GLint winX
= readable
->x
;
501 const GLint winY
= readable
->y
+ readable
->h
- 1;
502 const GLint scrX
= winX
+ x
;
503 const GLint scrY
= winY
- y
;
505 LOCK_HARDWARE( fxMesa
);
506 info
.size
= sizeof(info
);
507 if (fxMesa
->Glide
.grLfbLock(GR_LFB_READ_ONLY
,
510 GR_ORIGIN_UPPER_LEFT
, FXFALSE
, &info
)) {
511 const GLint srcStride
= (fxMesa
->glCtx
->Color
.DrawBuffer
[0] ==
512 GL_FRONT
) ? (fxMesa
->screen_width
) : (info
.strideInBytes
/ 2);
513 const GLushort
*src
= (const GLushort
*) info
.lfbPtr
514 + scrY
* srcStride
+ scrX
;
515 GLubyte
*dst
= (GLubyte
*) _mesa_image_address2d(packing
,
516 dstImage
, width
, height
, format
, type
, 0, 0);
517 const GLint dstStride
= _mesa_image_row_stride(packing
,
518 width
, format
, type
);
520 /* directly memcpy 5R6G5B pixels into client's buffer */
521 const GLint widthInBytes
= width
* 2;
523 for (row
= 0; row
< height
; row
++) {
524 MEMCPY(dst
, src
, widthInBytes
);
529 fxMesa
->Glide
.grLfbUnlock(GR_LFB_READ_ONLY
, fxMesa
->ReadBuffer
);
531 UNLOCK_HARDWARE( fxMesa
);
537 tdfx_readpixels_R8G8B8A8(GLcontext
* ctx
, GLint x
, GLint y
,
538 GLsizei width
, GLsizei height
,
539 GLenum format
, GLenum type
,
540 const struct gl_pixelstore_attrib
*packing
,
543 if ((!(format
== GL_BGRA
&& type
== GL_UNSIGNED_INT_8_8_8_8
) &&
544 !(format
== GL_BGRA
&& type
== GL_UNSIGNED_BYTE
)) ||
545 (ctx
->_ImageTransferState
& (IMAGE_SCALE_BIAS_BIT
|
546 IMAGE_MAP_COLOR_BIT
)))
548 _swrast_ReadPixels( ctx
, x
, y
, width
, height
, format
, type
, packing
,
555 tdfxContextPtr fxMesa
= TDFX_CONTEXT(ctx
);
557 __DRIdrawablePrivate
*const readable
= fxMesa
->driReadable
;
558 const GLint winX
= readable
->x
;
559 const GLint winY
= readable
->y
+ readable
->h
- 1;
560 const GLint scrX
= winX
+ x
;
561 const GLint scrY
= winY
- y
;
563 LOCK_HARDWARE(fxMesa
);
564 info
.size
= sizeof(info
);
565 if (fxMesa
->Glide
.grLfbLock(GR_LFB_READ_ONLY
,
568 GR_ORIGIN_UPPER_LEFT
, FXFALSE
, &info
))
570 const GLint srcStride
= (fxMesa
->glCtx
->Color
.DrawBuffer
[0] == GL_FRONT
)
571 ? (fxMesa
->screen_width
) : (info
.strideInBytes
/ 4);
572 const GLuint
*src
= (const GLuint
*) info
.lfbPtr
573 + scrY
* srcStride
+ scrX
;
574 const GLint dstStride
=
575 _mesa_image_row_stride(packing
, width
, format
, type
);
576 GLubyte
*dst
= (GLubyte
*) _mesa_image_address2d(packing
,
577 dstImage
, width
, height
, format
, type
, 0, 0);
578 const GLint widthInBytes
= width
* 4;
582 for (row
= 0; row
< height
; row
++) {
583 MEMCPY(dst
, src
, widthInBytes
);
589 fxMesa
->Glide
.grLfbUnlock(GR_LFB_READ_ONLY
, fxMesa
->ReadBuffer
);
591 UNLOCK_HARDWARE(fxMesa
);
596 tdfx_drawpixels_R8G8B8A8(GLcontext
* ctx
, GLint x
, GLint y
,
597 GLsizei width
, GLsizei height
,
598 GLenum format
, GLenum type
,
599 const struct gl_pixelstore_attrib
*unpack
,
600 const GLvoid
* pixels
)
602 tdfxContextPtr fxMesa
= TDFX_CONTEXT(ctx
);
604 if ((!(format
== GL_BGRA
&& type
== GL_UNSIGNED_INT_8_8_8_8
) &&
605 !(format
== GL_BGRA
&& type
== GL_UNSIGNED_BYTE
)) ||
606 ctx
->Pixel
.ZoomX
!= 1.0F
||
607 ctx
->Pixel
.ZoomY
!= 1.0F
||
608 (ctx
->_ImageTransferState
& (IMAGE_SCALE_BIAS_BIT
|
609 IMAGE_MAP_COLOR_BIT
)) ||
610 ctx
->Color
.AlphaEnabled
||
613 ctx
->Scissor
.Enabled
||
614 ctx
->Stencil
.Enabled
||
615 !ctx
->Color
.ColorMask
[0] ||
616 !ctx
->Color
.ColorMask
[1] ||
617 !ctx
->Color
.ColorMask
[2] ||
618 !ctx
->Color
.ColorMask
[3] ||
619 ctx
->Color
.ColorLogicOpEnabled
||
620 ctx
->Texture
._EnabledUnits
||
623 _swrast_DrawPixels( ctx
, x
, y
, width
, height
, format
, type
,
629 tdfxContextPtr fxMesa
= TDFX_CONTEXT(ctx
);
631 GLboolean result
= GL_FALSE
;
633 const GLint winX
= fxMesa
->x_offset
;
634 const GLint winY
= fxMesa
->y_offset
+ fxMesa
->height
- 1;
635 const GLint scrX
= winX
+ x
;
636 const GLint scrY
= winY
- y
;
638 /* lock early to make sure cliprects are right */
639 LOCK_HARDWARE(fxMesa
);
641 /* make sure hardware has latest blend funcs */
642 if (ctx
->Color
.BlendEnabled
) {
643 fxMesa
->dirty
|= TDFX_UPLOAD_BLEND_FUNC
;
644 tdfxEmitHwStateLocked( fxMesa
);
647 /* look for clipmasks, giveup if region obscured */
648 if (fxMesa
->glCtx
->Color
.DrawBuffer
[0] == GL_FRONT
) {
649 if (!inClipRects_Region(fxMesa
, scrX
, scrY
, width
, height
)) {
650 UNLOCK_HARDWARE(fxMesa
);
651 _swrast_DrawPixels( ctx
, x
, y
, width
, height
, format
, type
,
657 info
.size
= sizeof(info
);
658 if (fxMesa
->Glide
.grLfbLock(GR_LFB_WRITE_ONLY
,
660 GR_LFBWRITEMODE_8888
,
661 GR_ORIGIN_UPPER_LEFT
, FXTRUE
, &info
))
663 const GLint dstStride
= (fxMesa
->glCtx
->Color
.DrawBuffer
[0] == GL_FRONT
)
664 ? (fxMesa
->screen_width
* 4) : (info
.strideInBytes
);
665 GLubyte
*dst
= (GLubyte
*) info
.lfbPtr
666 + scrY
* dstStride
+ scrX
* 4;
667 const GLint srcStride
=
668 _mesa_image_row_stride(unpack
, width
, format
, type
);
669 const GLubyte
*src
= (GLubyte
*) _mesa_image_address2d(unpack
,
670 pixels
, width
, height
, format
, type
, 0, 0);
671 const GLint widthInBytes
= width
* 4;
673 if ((format
== GL_BGRA
&& type
== GL_UNSIGNED_INT_8_8_8_8
) ||
674 (format
== GL_BGRA
&& type
== GL_UNSIGNED_BYTE
)) {
676 for (row
= 0; row
< height
; row
++) {
677 MEMCPY(dst
, src
, widthInBytes
);
684 fxMesa
->Glide
.grLfbUnlock(GR_LFB_WRITE_ONLY
, fxMesa
->DrawBuffer
);
686 UNLOCK_HARDWARE(fxMesa
);