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"
42 #include "tdfx_pixels.h"
43 #include "tdfx_render.h"
45 #include "swrast/swrast.h"
47 #include "main/image.h"
50 #define FX_grLfbWriteRegion(fxMesa,dst_buffer,dst_x,dst_y,src_format,src_width,src_height,src_stride,src_data) \
52 LOCK_HARDWARE(fxMesa); \
53 fxMesa->Glide.grLfbWriteRegion(dst_buffer,dst_x,dst_y,src_format,src_width,src_height,FXFALSE,src_stride,src_data); \
54 UNLOCK_HARDWARE(fxMesa); \
58 #define FX_grLfbReadRegion(fxMesa,src_buffer,src_x,src_y,src_width,src_height,dst_stride,dst_data) \
60 LOCK_HARDWARE(fxMesa); \
61 fxMesa->Glide.grLfbReadRegion(src_buffer,src_x,src_y,src_width,src_height,dst_stride,dst_data); \
62 UNLOCK_HARDWARE(fxMesa); \
68 FX_grLfbLock(tdfxContextPtr fxMesa
, GrLock_t type
, GrBuffer_t buffer
,
69 GrLfbWriteMode_t writeMode
, GrOriginLocation_t origin
,
70 FxBool pixelPipeline
, GrLfbInfo_t
* info
)
74 LOCK_HARDWARE(fxMesa
);
75 result
= fxMesa
->Glide
.grLfbLock(type
, buffer
, writeMode
, origin
, pixelPipeline
, info
);
76 UNLOCK_HARDWARE(fxMesa
);
82 #define FX_grLfbUnlock(fxMesa, t, b) \
84 LOCK_HARDWARE(fxMesa); \
85 fxMesa->Glide.grLfbUnlock(t, b); \
86 UNLOCK_HARDWARE(fxMesa); \
92 /* test if window coord (px,py) is visible */
94 inClipRects(tdfxContextPtr fxMesa
, int px
, int py
)
97 for (i
= 0; i
< fxMesa
->numClipRects
; i
++) {
98 if ((px
>= fxMesa
->pClipRects
[i
].x1
) &&
99 (px
< fxMesa
->pClipRects
[i
].x2
) &&
100 (py
>= fxMesa
->pClipRects
[i
].y1
) &&
101 (py
< fxMesa
->pClipRects
[i
].y2
)) return GL_TRUE
;
107 /* test if rectangle of pixels (px,py) (px+width,py+height) is visible */
109 inClipRects_Region(tdfxContextPtr fxMesa
, int x
, int y
, int width
, int height
)
113 int xmin
, xmax
, ymin
, ymax
, pixelsleft
;
115 y1
= y
- height
+ 1; y2
= y
;
116 x1
= x
; x2
= x
+ width
- 1;
117 pixelsleft
= width
* height
;
119 for (i
= 0; i
< fxMesa
->numClipRects
; i
++)
121 /* algorithm requires x1 < x2 and y1 < y2 */
122 if ((fxMesa
->pClipRects
[i
].x1
< fxMesa
->pClipRects
[i
].x2
)) {
123 xmin
= fxMesa
->pClipRects
[i
].x1
;
124 xmax
= fxMesa
->pClipRects
[i
].x2
-1;
126 xmin
= fxMesa
->pClipRects
[i
].x2
;
127 xmax
= fxMesa
->pClipRects
[i
].x1
-1;
129 if ((fxMesa
->pClipRects
[i
].y1
< fxMesa
->pClipRects
[i
].y2
)) {
130 ymin
= fxMesa
->pClipRects
[i
].y1
;
131 ymax
= fxMesa
->pClipRects
[i
].y2
-1;
133 ymin
= fxMesa
->pClipRects
[i
].y2
;
134 ymax
= fxMesa
->pClipRects
[i
].y1
-1;
137 /* reject trivial cases */
138 if (xmax
< x1
) continue;
139 if (ymax
< y1
) continue;
140 if (xmin
> x2
) continue;
141 if (ymin
> y2
) continue;
143 /* find the intersection */
144 if (xmin
< x1
) xmin
= x1
;
145 if (ymin
< y1
) ymin
= y1
;
146 if (xmax
> x2
) xmax
= x2
;
147 if (ymax
> y2
) ymax
= y2
;
149 pixelsleft
-= (xmax
-xmin
+1) * (ymax
-ymin
+1);
152 return pixelsleft
== 0;
157 tdfx_bitmap_R5G6B5(GLcontext
* ctx
, GLint px
, GLint py
,
158 GLsizei width
, GLsizei height
,
159 const struct gl_pixelstore_attrib
*unpack
,
160 const GLubyte
* bitmap
)
162 tdfxContextPtr fxMesa
= TDFX_CONTEXT(ctx
);
165 const struct gl_pixelstore_attrib
*finalUnpack
;
166 struct gl_pixelstore_attrib scissoredUnpack
;
168 /* check if there's any raster operations enabled which we can't handle */
169 if (ctx
->RasterMask
& (ALPHATEST_BIT
|
177 MULTI_DRAW_BIT
)) return GL_FALSE
;
179 if (ctx
->Scissor
.Enabled
) {
180 /* This is a bit tricky, but by carefully adjusting the px, py,
181 * width, height, skipPixels and skipRows values we can do
182 * scissoring without special code in the rendering loop.
185 /* we'll construct a new pixelstore struct */
186 finalUnpack
= &scissoredUnpack
;
187 scissoredUnpack
= *unpack
;
188 if (scissoredUnpack
.RowLength
== 0)
189 scissoredUnpack
.RowLength
= width
;
192 if (px
< ctx
->Scissor
.X
) {
193 scissoredUnpack
.SkipPixels
+= (ctx
->Scissor
.X
- px
);
194 width
-= (ctx
->Scissor
.X
- px
);
198 if (px
+ width
>= ctx
->Scissor
.X
+ ctx
->Scissor
.Width
) {
199 width
-= (px
+ width
- (ctx
->Scissor
.X
+ ctx
->Scissor
.Width
));
202 if (py
< ctx
->Scissor
.Y
) {
203 scissoredUnpack
.SkipRows
+= (ctx
->Scissor
.Y
- py
);
204 height
-= (ctx
->Scissor
.Y
- py
);
208 if (py
+ height
>= ctx
->Scissor
.Y
+ ctx
->Scissor
.Height
) {
209 height
-= (py
+ height
- (ctx
->Scissor
.Y
+ ctx
->Scissor
.Height
));
212 if (width
<= 0 || height
<= 0)
213 return GL_TRUE
; /* totally scissored away */
216 finalUnpack
= unpack
;
219 /* compute pixel value */
221 GLint r
= (GLint
) (ctx
->Current
.RasterColor
[0] * 255.0f
);
222 GLint g
= (GLint
) (ctx
->Current
.RasterColor
[1] * 255.0f
);
223 GLint b
= (GLint
) (ctx
->Current
.RasterColor
[2] * 255.0f
);
224 /*GLint a = (GLint)(ctx->Current.RasterColor[3]*255.0f); */
225 if (fxMesa
->bgrOrder
) {
227 (((TdfxU16
) 0xf8 & b
) << (11 - 3)) |
228 (((TdfxU16
) 0xfc & g
) << (5 - 3 + 1)) |
229 (((TdfxU16
) 0xf8 & r
) >> 3);
233 (((TdfxU16
) 0xf8 & r
) << (11 - 3)) |
234 (((TdfxU16
) 0xfc & g
) << (5 - 3 + 1)) |
235 (((TdfxU16
) 0xf8 & b
) >> 3);
238 info
.size
= sizeof(info
);
239 if (!TDFX_grLfbLock(fxMesa
,
243 GR_ORIGIN_UPPER_LEFT
, FXFALSE
, &info
)) {
245 fprintf(stderr
, "tdfx Driver: error locking the linear frame buffer\n");
251 const GLint winX
= fxMesa
->x_offset
;
252 const GLint winY
= fxMesa
->y_offset
+ fxMesa
->height
- 1;
253 /* The dest stride depends on the hardware and whether we're drawing
254 * to the front or back buffer. This compile-time test seems to do
257 const GLint dstStride
= (fxMesa
->glCtx
->Color
.DrawBuffer
[0] == GL_FRONT
)
258 ? (fxMesa
->screen_width
) : (info
.strideInBytes
/ 2);
260 /* compute dest address of bottom-left pixel in bitmap */
261 GLushort
*dst
= (GLushort
*) info
.lfbPtr
262 + (winY
- py
) * dstStride
+ (winX
+ px
);
264 for (row
= 0; row
< height
; row
++) {
266 (const GLubyte
*) _mesa_image_address2d(finalUnpack
,
267 bitmap
, width
, height
,
270 if (finalUnpack
->LsbFirst
) {
271 /* least significan bit first */
272 GLubyte mask
= 1U << (finalUnpack
->SkipPixels
& 0x7);
274 for (col
= 0; col
< width
; col
++) {
276 if (inClipRects(fxMesa
, winX
+ px
+ col
, winY
- py
- row
))
291 /* most significan bit first */
292 GLubyte mask
= 128U >> (finalUnpack
->SkipPixels
& 0x7);
294 for (col
= 0; col
< width
; col
++) {
296 if (inClipRects(fxMesa
, winX
+ px
+ col
, winY
- py
- row
))
314 TDFX_grLfbUnlock(fxMesa
, GR_LFB_WRITE_ONLY
, fxMesa
->currentFB
);
321 tdfx_bitmap_R8G8B8A8(GLcontext
* ctx
, GLint px
, GLint py
,
322 GLsizei width
, GLsizei height
,
323 const struct gl_pixelstore_attrib
*unpack
,
324 const GLubyte
* bitmap
)
326 tdfxContextPtr fxMesa
= TDFX_CONTEXT(ctx
);
329 const struct gl_pixelstore_attrib
*finalUnpack
;
330 struct gl_pixelstore_attrib scissoredUnpack
;
332 /* check if there's any raster operations enabled which we can't handle */
333 if (ctx
->RasterMask
& (ALPHATEST_BIT
|
341 MULTI_DRAW_BIT
)) return GL_FALSE
;
343 if (ctx
->Scissor
.Enabled
) {
344 /* This is a bit tricky, but by carefully adjusting the px, py,
345 * width, height, skipPixels and skipRows values we can do
346 * scissoring without special code in the rendering loop.
349 /* we'll construct a new pixelstore struct */
350 finalUnpack
= &scissoredUnpack
;
351 scissoredUnpack
= *unpack
;
352 if (scissoredUnpack
.RowLength
== 0)
353 scissoredUnpack
.RowLength
= width
;
356 if (px
< ctx
->Scissor
.X
) {
357 scissoredUnpack
.SkipPixels
+= (ctx
->Scissor
.X
- px
);
358 width
-= (ctx
->Scissor
.X
- px
);
362 if (px
+ width
>= ctx
->Scissor
.X
+ ctx
->Scissor
.Width
) {
363 width
-= (px
+ width
- (ctx
->Scissor
.X
+ ctx
->Scissor
.Width
));
366 if (py
< ctx
->Scissor
.Y
) {
367 scissoredUnpack
.SkipRows
+= (ctx
->Scissor
.Y
- py
);
368 height
-= (ctx
->Scissor
.Y
- py
);
372 if (py
+ height
>= ctx
->Scissor
.Y
+ ctx
->Scissor
.Height
) {
373 height
-= (py
+ height
- (ctx
->Scissor
.Y
+ ctx
->Scissor
.Height
));
376 if (width
<= 0 || height
<= 0)
377 return GL_TRUE
; /* totally scissored away */
380 finalUnpack
= unpack
;
383 /* compute pixel value */
385 GLint r
= (GLint
) (ctx
->Current
.RasterColor
[0] * 255.0f
);
386 GLint g
= (GLint
) (ctx
->Current
.RasterColor
[1] * 255.0f
);
387 GLint b
= (GLint
) (ctx
->Current
.RasterColor
[2] * 255.0f
);
388 GLint a
= (GLint
) (ctx
->Current
.RasterColor
[3] * 255.0f
);
389 color
= PACK_BGRA32(r
, g
, b
, a
);
392 info
.size
= sizeof(info
);
393 if (!TDFX_grLfbLock(fxMesa
, GR_LFB_WRITE_ONLY
,
394 fxMesa
->currentFB
, GR_LFBWRITEMODE_8888
,
395 GR_ORIGIN_UPPER_LEFT
, FXFALSE
, &info
)) {
397 fprintf(stderr
, "tdfx Driver: error locking the linear frame buffer\n");
403 const GLint winX
= fxMesa
->x_offset
;
404 const GLint winY
= fxMesa
->y_offset
+ fxMesa
->height
- 1;
409 if (fxMesa
->glCtx
->Color
.DrawBuffer
[0] == GL_FRONT
) {
410 dstStride
= fxMesa
->screen_width
;
412 (GLuint
*) info
.lfbPtr
+ (winY
- py
) * dstStride
+ (winX
+
416 dstStride
= info
.strideInBytes
/ 4;
418 (GLuint
*) info
.lfbPtr
+ (winY
- py
) * dstStride
+ (winX
+
422 /* compute dest address of bottom-left pixel in bitmap */
423 for (row
= 0; row
< height
; row
++) {
425 (const GLubyte
*) _mesa_image_address2d(finalUnpack
,
426 bitmap
, width
, height
,
429 if (finalUnpack
->LsbFirst
) {
430 /* least significan bit first */
431 GLubyte mask
= 1U << (finalUnpack
->SkipPixels
& 0x7);
433 for (col
= 0; col
< width
; col
++) {
435 if (inClipRects(fxMesa
, winX
+ px
+ col
, winY
- py
- row
))
450 /* most significan bit first */
451 GLubyte mask
= 128U >> (finalUnpack
->SkipPixels
& 0x7);
453 for (col
= 0; col
< width
; col
++) {
455 if (inClipRects(fxMesa
, winX
+ px
+ col
, winY
- py
- row
))
473 TDFX_grLfbUnlock(fxMesa
, GR_LFB_WRITE_ONLY
, fxMesa
->currentFB
);
479 tdfx_readpixels_R5G6B5(GLcontext
* ctx
, GLint x
, GLint y
,
480 GLsizei width
, GLsizei height
,
481 GLenum format
, GLenum type
,
482 const struct gl_pixelstore_attrib
*packing
,
485 if (format
!= GL_RGB
||
486 type
!= GL_UNSIGNED_SHORT_5_6_5
||
487 (ctx
->_ImageTransferState
& (IMAGE_SCALE_BIAS_BIT
|
488 IMAGE_MAP_COLOR_BIT
)))
490 _swrast_ReadPixels( ctx
, x
, y
, width
, height
, format
, type
, packing
,
496 tdfxContextPtr fxMesa
= TDFX_CONTEXT(ctx
);
498 __DRIdrawablePrivate
*const readable
= fxMesa
->driReadable
;
499 const GLint winX
= readable
->x
;
500 const GLint winY
= readable
->y
+ readable
->h
- 1;
501 const GLint scrX
= winX
+ x
;
502 const GLint scrY
= winY
- y
;
504 LOCK_HARDWARE( fxMesa
);
505 info
.size
= sizeof(info
);
506 if (fxMesa
->Glide
.grLfbLock(GR_LFB_READ_ONLY
,
509 GR_ORIGIN_UPPER_LEFT
, FXFALSE
, &info
)) {
510 const GLint srcStride
= (fxMesa
->glCtx
->Color
.DrawBuffer
[0] ==
511 GL_FRONT
) ? (fxMesa
->screen_width
) : (info
.strideInBytes
/ 2);
512 const GLushort
*src
= (const GLushort
*) info
.lfbPtr
513 + scrY
* srcStride
+ scrX
;
514 GLubyte
*dst
= (GLubyte
*) _mesa_image_address2d(packing
,
515 dstImage
, width
, height
, format
, type
, 0, 0);
516 const GLint dstStride
= _mesa_image_row_stride(packing
,
517 width
, format
, type
);
519 /* directly memcpy 5R6G5B pixels into client's buffer */
520 const GLint widthInBytes
= width
* 2;
522 for (row
= 0; row
< height
; row
++) {
523 MEMCPY(dst
, src
, widthInBytes
);
528 fxMesa
->Glide
.grLfbUnlock(GR_LFB_READ_ONLY
, fxMesa
->ReadBuffer
);
530 UNLOCK_HARDWARE( fxMesa
);
536 tdfx_readpixels_R8G8B8A8(GLcontext
* ctx
, GLint x
, GLint y
,
537 GLsizei width
, GLsizei height
,
538 GLenum format
, GLenum type
,
539 const struct gl_pixelstore_attrib
*packing
,
542 if ((!(format
== GL_BGRA
&& type
== GL_UNSIGNED_INT_8_8_8_8
) &&
543 !(format
== GL_BGRA
&& type
== GL_UNSIGNED_BYTE
)) ||
544 (ctx
->_ImageTransferState
& (IMAGE_SCALE_BIAS_BIT
|
545 IMAGE_MAP_COLOR_BIT
)))
547 _swrast_ReadPixels( ctx
, x
, y
, width
, height
, format
, type
, packing
,
554 tdfxContextPtr fxMesa
= TDFX_CONTEXT(ctx
);
556 __DRIdrawablePrivate
*const readable
= fxMesa
->driReadable
;
557 const GLint winX
= readable
->x
;
558 const GLint winY
= readable
->y
+ readable
->h
- 1;
559 const GLint scrX
= winX
+ x
;
560 const GLint scrY
= winY
- y
;
562 LOCK_HARDWARE(fxMesa
);
563 info
.size
= sizeof(info
);
564 if (fxMesa
->Glide
.grLfbLock(GR_LFB_READ_ONLY
,
567 GR_ORIGIN_UPPER_LEFT
, FXFALSE
, &info
))
569 const GLint srcStride
= (fxMesa
->glCtx
->Color
.DrawBuffer
[0] == GL_FRONT
)
570 ? (fxMesa
->screen_width
) : (info
.strideInBytes
/ 4);
571 const GLuint
*src
= (const GLuint
*) info
.lfbPtr
572 + scrY
* srcStride
+ scrX
;
573 const GLint dstStride
=
574 _mesa_image_row_stride(packing
, width
, format
, type
);
575 GLubyte
*dst
= (GLubyte
*) _mesa_image_address2d(packing
,
576 dstImage
, width
, height
, format
, type
, 0, 0);
577 const GLint widthInBytes
= width
* 4;
581 for (row
= 0; row
< height
; row
++) {
582 MEMCPY(dst
, src
, widthInBytes
);
588 fxMesa
->Glide
.grLfbUnlock(GR_LFB_READ_ONLY
, fxMesa
->ReadBuffer
);
590 UNLOCK_HARDWARE(fxMesa
);
595 tdfx_drawpixels_R8G8B8A8(GLcontext
* ctx
, GLint x
, GLint y
,
596 GLsizei width
, GLsizei height
,
597 GLenum format
, GLenum type
,
598 const struct gl_pixelstore_attrib
*unpack
,
599 const GLvoid
* pixels
)
601 tdfxContextPtr fxMesa
= TDFX_CONTEXT(ctx
);
603 if ((!(format
== GL_BGRA
&& type
== GL_UNSIGNED_INT_8_8_8_8
) &&
604 !(format
== GL_BGRA
&& type
== GL_UNSIGNED_BYTE
)) ||
605 ctx
->Pixel
.ZoomX
!= 1.0F
||
606 ctx
->Pixel
.ZoomY
!= 1.0F
||
607 (ctx
->_ImageTransferState
& (IMAGE_SCALE_BIAS_BIT
|
608 IMAGE_MAP_COLOR_BIT
)) ||
609 ctx
->Color
.AlphaEnabled
||
612 ctx
->Scissor
.Enabled
||
613 ctx
->Stencil
.Enabled
||
614 !ctx
->Color
.ColorMask
[0] ||
615 !ctx
->Color
.ColorMask
[1] ||
616 !ctx
->Color
.ColorMask
[2] ||
617 !ctx
->Color
.ColorMask
[3] ||
618 ctx
->Color
.ColorLogicOpEnabled
||
619 ctx
->Texture
._EnabledUnits
||
622 _swrast_DrawPixels( ctx
, x
, y
, width
, height
, format
, type
,
628 tdfxContextPtr fxMesa
= TDFX_CONTEXT(ctx
);
630 GLboolean result
= GL_FALSE
;
632 const GLint winX
= fxMesa
->x_offset
;
633 const GLint winY
= fxMesa
->y_offset
+ fxMesa
->height
- 1;
634 const GLint scrX
= winX
+ x
;
635 const GLint scrY
= winY
- y
;
637 /* lock early to make sure cliprects are right */
638 LOCK_HARDWARE(fxMesa
);
640 /* make sure hardware has latest blend funcs */
641 if (ctx
->Color
.BlendEnabled
) {
642 fxMesa
->dirty
|= TDFX_UPLOAD_BLEND_FUNC
;
643 tdfxEmitHwStateLocked( fxMesa
);
646 /* look for clipmasks, giveup if region obscured */
647 if (fxMesa
->glCtx
->Color
.DrawBuffer
[0] == GL_FRONT
) {
648 if (!inClipRects_Region(fxMesa
, scrX
, scrY
, width
, height
)) {
649 UNLOCK_HARDWARE(fxMesa
);
650 _swrast_DrawPixels( ctx
, x
, y
, width
, height
, format
, type
,
656 info
.size
= sizeof(info
);
657 if (fxMesa
->Glide
.grLfbLock(GR_LFB_WRITE_ONLY
,
659 GR_LFBWRITEMODE_8888
,
660 GR_ORIGIN_UPPER_LEFT
, FXTRUE
, &info
))
662 const GLint dstStride
= (fxMesa
->glCtx
->Color
.DrawBuffer
[0] == GL_FRONT
)
663 ? (fxMesa
->screen_width
* 4) : (info
.strideInBytes
);
664 GLubyte
*dst
= (GLubyte
*) info
.lfbPtr
665 + scrY
* dstStride
+ scrX
* 4;
666 const GLint srcStride
=
667 _mesa_image_row_stride(unpack
, width
, format
, type
);
668 const GLubyte
*src
= (GLubyte
*) _mesa_image_address2d(unpack
,
669 pixels
, width
, height
, format
, type
, 0, 0);
670 const GLint widthInBytes
= width
* 4;
672 if ((format
== GL_BGRA
&& type
== GL_UNSIGNED_INT_8_8_8_8
) ||
673 (format
== GL_BGRA
&& type
== GL_UNSIGNED_BYTE
)) {
675 for (row
= 0; row
< height
; row
++) {
676 MEMCPY(dst
, src
, widthInBytes
);
683 fxMesa
->Glide
.grLfbUnlock(GR_LFB_WRITE_ONLY
, fxMesa
->DrawBuffer
);
685 UNLOCK_HARDWARE(fxMesa
);