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(struct gl_context * 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(struct gl_context * 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(struct gl_context * 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(struct gl_context * 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(struct gl_context * 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);