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
29 * Gareth Hughes <gareth@valinux.com>, 29 Sep - 1 Oct 2000
32 * Gareth Hughes <gareth@valinux.com>
33 * Brian Paul <brianp@valinux.com>
34 * Nathan Hand <nhand@valinux.com>
38 #include "tdfx_context.h"
40 #include "tdfx_lock.h"
41 #include "tdfx_pixels.h"
42 #include "tdfx_render.h"
44 #include "swrast/swrast.h"
46 #include "main/image.h"
49 #define FX_grLfbWriteRegion(fxMesa,dst_buffer,dst_x,dst_y,src_format,src_width,src_height,src_stride,src_data) \
51 LOCK_HARDWARE(fxMesa); \
52 fxMesa->Glide.grLfbWriteRegion(dst_buffer,dst_x,dst_y,src_format,src_width,src_height,FXFALSE,src_stride,src_data); \
53 UNLOCK_HARDWARE(fxMesa); \
57 #define FX_grLfbReadRegion(fxMesa,src_buffer,src_x,src_y,src_width,src_height,dst_stride,dst_data) \
59 LOCK_HARDWARE(fxMesa); \
60 fxMesa->Glide.grLfbReadRegion(src_buffer,src_x,src_y,src_width,src_height,dst_stride,dst_data); \
61 UNLOCK_HARDWARE(fxMesa); \
67 FX_grLfbLock(tdfxContextPtr fxMesa
, GrLock_t type
, GrBuffer_t buffer
,
68 GrLfbWriteMode_t writeMode
, GrOriginLocation_t origin
,
69 FxBool pixelPipeline
, GrLfbInfo_t
* info
)
73 LOCK_HARDWARE(fxMesa
);
74 result
= fxMesa
->Glide
.grLfbLock(type
, buffer
, writeMode
, origin
, pixelPipeline
, info
);
75 UNLOCK_HARDWARE(fxMesa
);
81 #define FX_grLfbUnlock(fxMesa, t, b) \
83 LOCK_HARDWARE(fxMesa); \
84 fxMesa->Glide.grLfbUnlock(t, b); \
85 UNLOCK_HARDWARE(fxMesa); \
91 /* test if window coord (px,py) is visible */
93 inClipRects(tdfxContextPtr fxMesa
, int px
, int py
)
96 for (i
= 0; i
< fxMesa
->numClipRects
; i
++) {
97 if ((px
>= fxMesa
->pClipRects
[i
].x1
) &&
98 (px
< fxMesa
->pClipRects
[i
].x2
) &&
99 (py
>= fxMesa
->pClipRects
[i
].y1
) &&
100 (py
< fxMesa
->pClipRects
[i
].y2
)) return GL_TRUE
;
106 /* test if rectangle of pixels (px,py) (px+width,py+height) is visible */
108 inClipRects_Region(tdfxContextPtr fxMesa
, int x
, int y
, int width
, int height
)
112 int xmin
, xmax
, ymin
, ymax
, pixelsleft
;
114 y1
= y
- height
+ 1; y2
= y
;
115 x1
= x
; x2
= x
+ width
- 1;
116 pixelsleft
= width
* height
;
118 for (i
= 0; i
< fxMesa
->numClipRects
; i
++)
120 /* algorithm requires x1 < x2 and y1 < y2 */
121 if ((fxMesa
->pClipRects
[i
].x1
< fxMesa
->pClipRects
[i
].x2
)) {
122 xmin
= fxMesa
->pClipRects
[i
].x1
;
123 xmax
= fxMesa
->pClipRects
[i
].x2
-1;
125 xmin
= fxMesa
->pClipRects
[i
].x2
;
126 xmax
= fxMesa
->pClipRects
[i
].x1
-1;
128 if ((fxMesa
->pClipRects
[i
].y1
< fxMesa
->pClipRects
[i
].y2
)) {
129 ymin
= fxMesa
->pClipRects
[i
].y1
;
130 ymax
= fxMesa
->pClipRects
[i
].y2
-1;
132 ymin
= fxMesa
->pClipRects
[i
].y2
;
133 ymax
= fxMesa
->pClipRects
[i
].y1
-1;
136 /* reject trivial cases */
137 if (xmax
< x1
) continue;
138 if (ymax
< y1
) continue;
139 if (xmin
> x2
) continue;
140 if (ymin
> y2
) continue;
142 /* find the intersection */
143 if (xmin
< x1
) xmin
= x1
;
144 if (ymin
< y1
) ymin
= y1
;
145 if (xmax
> x2
) xmax
= x2
;
146 if (ymax
> y2
) ymax
= y2
;
148 pixelsleft
-= (xmax
-xmin
+1) * (ymax
-ymin
+1);
151 return pixelsleft
== 0;
156 tdfx_bitmap_R5G6B5(GLcontext
* ctx
, GLint px
, GLint py
,
157 GLsizei width
, GLsizei height
,
158 const struct gl_pixelstore_attrib
*unpack
,
159 const GLubyte
* bitmap
)
161 tdfxContextPtr fxMesa
= TDFX_CONTEXT(ctx
);
164 const struct gl_pixelstore_attrib
*finalUnpack
;
165 struct gl_pixelstore_attrib scissoredUnpack
;
167 /* check if there's any raster operations enabled which we can't handle */
168 if (ctx
->RasterMask
& (ALPHATEST_BIT
|
176 MULTI_DRAW_BIT
)) return GL_FALSE
;
178 if (ctx
->Scissor
.Enabled
) {
179 /* This is a bit tricky, but by carefully adjusting the px, py,
180 * width, height, skipPixels and skipRows values we can do
181 * scissoring without special code in the rendering loop.
184 /* we'll construct a new pixelstore struct */
185 finalUnpack
= &scissoredUnpack
;
186 scissoredUnpack
= *unpack
;
187 if (scissoredUnpack
.RowLength
== 0)
188 scissoredUnpack
.RowLength
= width
;
191 if (px
< ctx
->Scissor
.X
) {
192 scissoredUnpack
.SkipPixels
+= (ctx
->Scissor
.X
- px
);
193 width
-= (ctx
->Scissor
.X
- px
);
197 if (px
+ width
>= ctx
->Scissor
.X
+ ctx
->Scissor
.Width
) {
198 width
-= (px
+ width
- (ctx
->Scissor
.X
+ ctx
->Scissor
.Width
));
201 if (py
< ctx
->Scissor
.Y
) {
202 scissoredUnpack
.SkipRows
+= (ctx
->Scissor
.Y
- py
);
203 height
-= (ctx
->Scissor
.Y
- py
);
207 if (py
+ height
>= ctx
->Scissor
.Y
+ ctx
->Scissor
.Height
) {
208 height
-= (py
+ height
- (ctx
->Scissor
.Y
+ ctx
->Scissor
.Height
));
211 if (width
<= 0 || height
<= 0)
212 return GL_TRUE
; /* totally scissored away */
215 finalUnpack
= unpack
;
218 /* compute pixel value */
220 GLint r
= (GLint
) (ctx
->Current
.RasterColor
[0] * 255.0f
);
221 GLint g
= (GLint
) (ctx
->Current
.RasterColor
[1] * 255.0f
);
222 GLint b
= (GLint
) (ctx
->Current
.RasterColor
[2] * 255.0f
);
223 /*GLint a = (GLint)(ctx->Current.RasterColor[3]*255.0f); */
224 if (fxMesa
->bgrOrder
) {
226 (((TdfxU16
) 0xf8 & b
) << (11 - 3)) |
227 (((TdfxU16
) 0xfc & g
) << (5 - 3 + 1)) |
228 (((TdfxU16
) 0xf8 & r
) >> 3);
232 (((TdfxU16
) 0xf8 & r
) << (11 - 3)) |
233 (((TdfxU16
) 0xfc & g
) << (5 - 3 + 1)) |
234 (((TdfxU16
) 0xf8 & b
) >> 3);
237 info
.size
= sizeof(info
);
238 if (!TDFX_grLfbLock(fxMesa
,
242 GR_ORIGIN_UPPER_LEFT
, FXFALSE
, &info
)) {
244 fprintf(stderr
, "tdfx Driver: error locking the linear frame buffer\n");
250 const GLint winX
= fxMesa
->x_offset
;
251 const GLint winY
= fxMesa
->y_offset
+ fxMesa
->height
- 1;
252 /* The dest stride depends on the hardware and whether we're drawing
253 * to the front or back buffer. This compile-time test seems to do
256 const GLint dstStride
= (fxMesa
->glCtx
->Color
.DrawBuffer
[0] == GL_FRONT
)
257 ? (fxMesa
->screen_width
) : (info
.strideInBytes
/ 2);
259 /* compute dest address of bottom-left pixel in bitmap */
260 GLushort
*dst
= (GLushort
*) info
.lfbPtr
261 + (winY
- py
) * dstStride
+ (winX
+ px
);
263 for (row
= 0; row
< height
; row
++) {
265 (const GLubyte
*) _mesa_image_address2d(finalUnpack
,
266 bitmap
, width
, height
,
269 if (finalUnpack
->LsbFirst
) {
270 /* least significan bit first */
271 GLubyte mask
= 1U << (finalUnpack
->SkipPixels
& 0x7);
273 for (col
= 0; col
< width
; col
++) {
275 if (inClipRects(fxMesa
, winX
+ px
+ col
, winY
- py
- row
))
290 /* most significan bit first */
291 GLubyte mask
= 128U >> (finalUnpack
->SkipPixels
& 0x7);
293 for (col
= 0; col
< width
; col
++) {
295 if (inClipRects(fxMesa
, winX
+ px
+ col
, winY
- py
- row
))
313 TDFX_grLfbUnlock(fxMesa
, GR_LFB_WRITE_ONLY
, fxMesa
->currentFB
);
320 tdfx_bitmap_R8G8B8A8(GLcontext
* ctx
, GLint px
, GLint py
,
321 GLsizei width
, GLsizei height
,
322 const struct gl_pixelstore_attrib
*unpack
,
323 const GLubyte
* bitmap
)
325 tdfxContextPtr fxMesa
= TDFX_CONTEXT(ctx
);
328 const struct gl_pixelstore_attrib
*finalUnpack
;
329 struct gl_pixelstore_attrib scissoredUnpack
;
331 /* check if there's any raster operations enabled which we can't handle */
332 if (ctx
->RasterMask
& (ALPHATEST_BIT
|
340 MULTI_DRAW_BIT
)) return GL_FALSE
;
342 if (ctx
->Scissor
.Enabled
) {
343 /* This is a bit tricky, but by carefully adjusting the px, py,
344 * width, height, skipPixels and skipRows values we can do
345 * scissoring without special code in the rendering loop.
348 /* we'll construct a new pixelstore struct */
349 finalUnpack
= &scissoredUnpack
;
350 scissoredUnpack
= *unpack
;
351 if (scissoredUnpack
.RowLength
== 0)
352 scissoredUnpack
.RowLength
= width
;
355 if (px
< ctx
->Scissor
.X
) {
356 scissoredUnpack
.SkipPixels
+= (ctx
->Scissor
.X
- px
);
357 width
-= (ctx
->Scissor
.X
- px
);
361 if (px
+ width
>= ctx
->Scissor
.X
+ ctx
->Scissor
.Width
) {
362 width
-= (px
+ width
- (ctx
->Scissor
.X
+ ctx
->Scissor
.Width
));
365 if (py
< ctx
->Scissor
.Y
) {
366 scissoredUnpack
.SkipRows
+= (ctx
->Scissor
.Y
- py
);
367 height
-= (ctx
->Scissor
.Y
- py
);
371 if (py
+ height
>= ctx
->Scissor
.Y
+ ctx
->Scissor
.Height
) {
372 height
-= (py
+ height
- (ctx
->Scissor
.Y
+ ctx
->Scissor
.Height
));
375 if (width
<= 0 || height
<= 0)
376 return GL_TRUE
; /* totally scissored away */
379 finalUnpack
= unpack
;
382 /* compute pixel value */
384 GLint r
= (GLint
) (ctx
->Current
.RasterColor
[0] * 255.0f
);
385 GLint g
= (GLint
) (ctx
->Current
.RasterColor
[1] * 255.0f
);
386 GLint b
= (GLint
) (ctx
->Current
.RasterColor
[2] * 255.0f
);
387 GLint a
= (GLint
) (ctx
->Current
.RasterColor
[3] * 255.0f
);
388 color
= PACK_BGRA32(r
, g
, b
, a
);
391 info
.size
= sizeof(info
);
392 if (!TDFX_grLfbLock(fxMesa
, GR_LFB_WRITE_ONLY
,
393 fxMesa
->currentFB
, GR_LFBWRITEMODE_8888
,
394 GR_ORIGIN_UPPER_LEFT
, FXFALSE
, &info
)) {
396 fprintf(stderr
, "tdfx Driver: error locking the linear frame buffer\n");
402 const GLint winX
= fxMesa
->x_offset
;
403 const GLint winY
= fxMesa
->y_offset
+ fxMesa
->height
- 1;
408 if (fxMesa
->glCtx
->Color
.DrawBuffer
[0] == GL_FRONT
) {
409 dstStride
= fxMesa
->screen_width
;
411 (GLuint
*) info
.lfbPtr
+ (winY
- py
) * dstStride
+ (winX
+
415 dstStride
= info
.strideInBytes
/ 4;
417 (GLuint
*) info
.lfbPtr
+ (winY
- py
) * dstStride
+ (winX
+
421 /* compute dest address of bottom-left pixel in bitmap */
422 for (row
= 0; row
< height
; row
++) {
424 (const GLubyte
*) _mesa_image_address2d(finalUnpack
,
425 bitmap
, width
, height
,
428 if (finalUnpack
->LsbFirst
) {
429 /* least significan bit first */
430 GLubyte mask
= 1U << (finalUnpack
->SkipPixels
& 0x7);
432 for (col
= 0; col
< width
; col
++) {
434 if (inClipRects(fxMesa
, winX
+ px
+ col
, winY
- py
- row
))
449 /* most significan bit first */
450 GLubyte mask
= 128U >> (finalUnpack
->SkipPixels
& 0x7);
452 for (col
= 0; col
< width
; col
++) {
454 if (inClipRects(fxMesa
, winX
+ px
+ col
, winY
- py
- row
))
472 TDFX_grLfbUnlock(fxMesa
, GR_LFB_WRITE_ONLY
, fxMesa
->currentFB
);
478 tdfx_readpixels_R5G6B5(GLcontext
* ctx
, GLint x
, GLint y
,
479 GLsizei width
, GLsizei height
,
480 GLenum format
, GLenum type
,
481 const struct gl_pixelstore_attrib
*packing
,
484 if (format
!= GL_RGB
||
485 type
!= GL_UNSIGNED_SHORT_5_6_5
||
486 (ctx
->_ImageTransferState
& (IMAGE_SCALE_BIAS_BIT
|
487 IMAGE_MAP_COLOR_BIT
)))
489 _swrast_ReadPixels( ctx
, x
, y
, width
, height
, format
, type
, packing
,
495 tdfxContextPtr fxMesa
= TDFX_CONTEXT(ctx
);
497 __DRIdrawable
*const readable
= fxMesa
->driReadable
;
498 const GLint winX
= readable
->x
;
499 const GLint winY
= readable
->y
+ readable
->h
- 1;
500 const GLint scrX
= winX
+ x
;
501 const GLint scrY
= winY
- y
;
503 LOCK_HARDWARE( fxMesa
);
504 info
.size
= sizeof(info
);
505 if (fxMesa
->Glide
.grLfbLock(GR_LFB_READ_ONLY
,
508 GR_ORIGIN_UPPER_LEFT
, FXFALSE
, &info
)) {
509 const GLint srcStride
= (fxMesa
->glCtx
->Color
.DrawBuffer
[0] ==
510 GL_FRONT
) ? (fxMesa
->screen_width
) : (info
.strideInBytes
/ 2);
511 const GLushort
*src
= (const GLushort
*) info
.lfbPtr
512 + scrY
* srcStride
+ scrX
;
513 GLubyte
*dst
= (GLubyte
*) _mesa_image_address2d(packing
,
514 dstImage
, width
, height
, format
, type
, 0, 0);
515 const GLint dstStride
= _mesa_image_row_stride(packing
,
516 width
, format
, type
);
518 /* directly memcpy 5R6G5B pixels into client's buffer */
519 const GLint widthInBytes
= width
* 2;
521 for (row
= 0; row
< height
; row
++) {
522 memcpy(dst
, src
, widthInBytes
);
527 fxMesa
->Glide
.grLfbUnlock(GR_LFB_READ_ONLY
, fxMesa
->ReadBuffer
);
529 UNLOCK_HARDWARE( fxMesa
);
535 tdfx_readpixels_R8G8B8A8(GLcontext
* ctx
, GLint x
, GLint y
,
536 GLsizei width
, GLsizei height
,
537 GLenum format
, GLenum type
,
538 const struct gl_pixelstore_attrib
*packing
,
541 if ((!(format
== GL_BGRA
&& type
== GL_UNSIGNED_INT_8_8_8_8
) &&
542 !(format
== GL_BGRA
&& type
== GL_UNSIGNED_BYTE
)) ||
543 (ctx
->_ImageTransferState
& (IMAGE_SCALE_BIAS_BIT
|
544 IMAGE_MAP_COLOR_BIT
)))
546 _swrast_ReadPixels( ctx
, x
, y
, width
, height
, format
, type
, packing
,
553 tdfxContextPtr fxMesa
= TDFX_CONTEXT(ctx
);
555 __DRIdrawable
*const readable
= fxMesa
->driReadable
;
556 const GLint winX
= readable
->x
;
557 const GLint winY
= readable
->y
+ readable
->h
- 1;
558 const GLint scrX
= winX
+ x
;
559 const GLint scrY
= winY
- y
;
561 LOCK_HARDWARE(fxMesa
);
562 info
.size
= sizeof(info
);
563 if (fxMesa
->Glide
.grLfbLock(GR_LFB_READ_ONLY
,
566 GR_ORIGIN_UPPER_LEFT
, FXFALSE
, &info
))
568 const GLint srcStride
= (fxMesa
->glCtx
->Color
.DrawBuffer
[0] == GL_FRONT
)
569 ? (fxMesa
->screen_width
) : (info
.strideInBytes
/ 4);
570 const GLuint
*src
= (const GLuint
*) info
.lfbPtr
571 + scrY
* srcStride
+ scrX
;
572 const GLint dstStride
=
573 _mesa_image_row_stride(packing
, width
, format
, type
);
574 GLubyte
*dst
= (GLubyte
*) _mesa_image_address2d(packing
,
575 dstImage
, width
, height
, format
, type
, 0, 0);
576 const GLint widthInBytes
= width
* 4;
580 for (row
= 0; row
< height
; row
++) {
581 memcpy(dst
, src
, widthInBytes
);
587 fxMesa
->Glide
.grLfbUnlock(GR_LFB_READ_ONLY
, fxMesa
->ReadBuffer
);
589 UNLOCK_HARDWARE(fxMesa
);
594 tdfx_drawpixels_R8G8B8A8(GLcontext
* ctx
, GLint x
, GLint y
,
595 GLsizei width
, GLsizei height
,
596 GLenum format
, GLenum type
,
597 const struct gl_pixelstore_attrib
*unpack
,
598 const GLvoid
* pixels
)
600 tdfxContextPtr fxMesa
= TDFX_CONTEXT(ctx
);
602 if ((!(format
== GL_BGRA
&& type
== GL_UNSIGNED_INT_8_8_8_8
) &&
603 !(format
== GL_BGRA
&& type
== GL_UNSIGNED_BYTE
)) ||
604 ctx
->Pixel
.ZoomX
!= 1.0F
||
605 ctx
->Pixel
.ZoomY
!= 1.0F
||
606 (ctx
->_ImageTransferState
& (IMAGE_SCALE_BIAS_BIT
|
607 IMAGE_MAP_COLOR_BIT
)) ||
608 ctx
->Color
.AlphaEnabled
||
611 ctx
->Scissor
.Enabled
||
612 ctx
->Stencil
._Enabled
||
613 !ctx
->Color
.ColorMask
[0][0] ||
614 !ctx
->Color
.ColorMask
[0][1] ||
615 !ctx
->Color
.ColorMask
[0][2] ||
616 !ctx
->Color
.ColorMask
[0][3] ||
617 ctx
->Color
.ColorLogicOpEnabled
||
618 ctx
->Texture
._EnabledUnits
||
621 _swrast_DrawPixels( ctx
, x
, y
, width
, height
, format
, type
,
627 tdfxContextPtr fxMesa
= TDFX_CONTEXT(ctx
);
629 GLboolean result
= GL_FALSE
;
631 const GLint winX
= fxMesa
->x_offset
;
632 const GLint winY
= fxMesa
->y_offset
+ fxMesa
->height
- 1;
633 const GLint scrX
= winX
+ x
;
634 const GLint scrY
= winY
- y
;
636 /* lock early to make sure cliprects are right */
637 LOCK_HARDWARE(fxMesa
);
639 /* make sure hardware has latest blend funcs */
640 if (ctx
->Color
.BlendEnabled
) {
641 fxMesa
->dirty
|= TDFX_UPLOAD_BLEND_FUNC
;
642 tdfxEmitHwStateLocked( fxMesa
);
645 /* look for clipmasks, giveup if region obscured */
646 if (fxMesa
->glCtx
->Color
.DrawBuffer
[0] == GL_FRONT
) {
647 if (!inClipRects_Region(fxMesa
, scrX
, scrY
, width
, height
)) {
648 UNLOCK_HARDWARE(fxMesa
);
649 _swrast_DrawPixels( ctx
, x
, y
, width
, height
, format
, type
,
655 info
.size
= sizeof(info
);
656 if (fxMesa
->Glide
.grLfbLock(GR_LFB_WRITE_ONLY
,
658 GR_LFBWRITEMODE_8888
,
659 GR_ORIGIN_UPPER_LEFT
, FXTRUE
, &info
))
661 const GLint dstStride
= (fxMesa
->glCtx
->Color
.DrawBuffer
[0] == GL_FRONT
)
662 ? (fxMesa
->screen_width
* 4) : (info
.strideInBytes
);
663 GLubyte
*dst
= (GLubyte
*) info
.lfbPtr
664 + scrY
* dstStride
+ scrX
* 4;
665 const GLint srcStride
=
666 _mesa_image_row_stride(unpack
, width
, format
, type
);
667 const GLubyte
*src
= (GLubyte
*) _mesa_image_address2d(unpack
,
668 pixels
, width
, height
, format
, type
, 0, 0);
669 const GLint widthInBytes
= width
* 4;
671 if ((format
== GL_BGRA
&& type
== GL_UNSIGNED_INT_8_8_8_8
) ||
672 (format
== GL_BGRA
&& type
== GL_UNSIGNED_BYTE
)) {
674 for (row
= 0; row
< height
; row
++) {
675 memcpy(dst
, src
, widthInBytes
);
682 fxMesa
->Glide
.grLfbUnlock(GR_LFB_WRITE_ONLY
, fxMesa
->DrawBuffer
);
684 UNLOCK_HARDWARE(fxMesa
);