| /* -*- mode: c; c-basic-offset: 3 -*- |
| * |
| * Copyright 2000 VA Linux Systems Inc., Fremont, California. |
| * |
| * All Rights Reserved. |
| * |
| * Permission is hereby granted, free of charge, to any person obtaining a |
| * copy of this software and associated documentation files (the "Software"), |
| * to deal in the Software without restriction, including without limitation |
| * the rights to use, copy, modify, merge, publish, distribute, sublicense, |
| * and/or sell copies of the Software, and to permit persons to whom the |
| * Software is furnished to do so, subject to the following conditions: |
| * |
| * The above copyright notice and this permission notice (including the next |
| * paragraph) shall be included in all copies or substantial portions of the |
| * Software. |
| * |
| * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
| * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
| * VA LINUX SYSTEMS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, |
| * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF |
| * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
| * SOFTWARE. |
| */ |
| /* $XFree86: xc/lib/GL/mesa/src/drv/tdfx/tdfx_span.c,v 1.7 2002/10/30 12:52:00 alanh Exp $ */ |
| |
| /* |
| * Original rewrite: |
| * Gareth Hughes <gareth@valinux.com>, 29 Sep - 1 Oct 2000 |
| * |
| * Authors: |
| * Gareth Hughes <gareth@valinux.com> |
| * Brian Paul <brianp@valinux.com> |
| * Keith Whitwell <keith@tungstengraphics.com> |
| * |
| */ |
| |
| #include "tdfx_context.h" |
| #include "tdfx_lock.h" |
| #include "tdfx_span.h" |
| #include "tdfx_render.h" |
| #include "swrast/swrast.h" |
| |
| |
| #define DBG 0 |
| |
| |
| #define LOCAL_VARS \ |
| driRenderbuffer *drb = (driRenderbuffer *) rb; \ |
| __DRIdrawablePrivate *const dPriv = drb->dPriv; \ |
| GLuint pitch = drb->backBuffer ? info.strideInBytes \ |
| : (drb->pitch * drb->cpp); \ |
| const GLuint bottom = dPriv->h - 1; \ |
| char *buf = (char *)((char *)info.lfbPtr + \ |
| (dPriv->x * drb->cpp) + \ |
| (dPriv->y * pitch)); \ |
| GLuint p; \ |
| (void) buf; (void) p; |
| |
| |
| #define Y_FLIP(_y) (bottom - _y) |
| |
| |
| #define HW_WRITE_LOCK() \ |
| tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx); \ |
| GrLfbInfo_t info; \ |
| FLUSH_BATCH( fxMesa ); \ |
| UNLOCK_HARDWARE( fxMesa ); \ |
| LOCK_HARDWARE( fxMesa ); \ |
| info.size = sizeof(GrLfbInfo_t); \ |
| if (fxMesa->Glide.grLfbLock(GR_LFB_WRITE_ONLY, fxMesa->DrawBuffer, \ |
| LFB_MODE, GR_ORIGIN_UPPER_LEFT, FXFALSE, \ |
| &info)) { |
| |
| #define HW_WRITE_UNLOCK() \ |
| fxMesa->Glide.grLfbUnlock( GR_LFB_WRITE_ONLY, fxMesa->DrawBuffer );\ |
| } |
| |
| |
| #define HW_READ_LOCK() \ |
| tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx); \ |
| GrLfbInfo_t info; \ |
| FLUSH_BATCH( fxMesa ); \ |
| UNLOCK_HARDWARE( fxMesa ); \ |
| LOCK_HARDWARE( fxMesa ); \ |
| info.size = sizeof(GrLfbInfo_t); \ |
| if ( fxMesa->Glide.grLfbLock( GR_LFB_READ_ONLY, fxMesa->ReadBuffer, \ |
| LFB_MODE, GR_ORIGIN_UPPER_LEFT, FXFALSE, &info ) ) \ |
| { |
| |
| #define HW_READ_UNLOCK() \ |
| fxMesa->Glide.grLfbUnlock( GR_LFB_READ_ONLY, fxMesa->ReadBuffer );\ |
| } |
| |
| |
| #define HW_WRITE_CLIPLOOP() \ |
| do { \ |
| int _nc = fxMesa->numClipRects; \ |
| while (_nc--) { \ |
| int minx = fxMesa->pClipRects[_nc].x1 - fxMesa->x_offset; \ |
| int miny = fxMesa->pClipRects[_nc].y1 - fxMesa->y_offset; \ |
| int maxx = fxMesa->pClipRects[_nc].x2 - fxMesa->x_offset; \ |
| int maxy = fxMesa->pClipRects[_nc].y2 - fxMesa->y_offset; |
| |
| #define HW_READ_CLIPLOOP() \ |
| do { \ |
| const __DRIdrawablePrivate *dPriv = fxMesa->driDrawable; \ |
| drm_clip_rect_t *rect = dPriv->pClipRects; \ |
| int _nc = dPriv->numClipRects; \ |
| while (_nc--) { \ |
| const int minx = rect->x1 - fxMesa->x_offset; \ |
| const int miny = rect->y1 - fxMesa->y_offset; \ |
| const int maxx = rect->x2 - fxMesa->x_offset; \ |
| const int maxy = rect->y2 - fxMesa->y_offset; \ |
| rect++; |
| |
| #define HW_ENDCLIPLOOP() \ |
| } \ |
| } while (0) |
| |
| |
| |
| #define LFB_MODE GR_LFBWRITEMODE_565 |
| |
| |
| /* 16 bit, RGB565 color spanline and pixel functions */ \ |
| |
| #undef INIT_MONO_PIXEL |
| #define INIT_MONO_PIXEL(p, color) \ |
| p = TDFXPACKCOLOR565( color[0], color[1], color[2] ) |
| |
| |
| #define WRITE_RGBA( _x, _y, r, g, b, a ) \ |
| *(GLushort *)(buf + _x*2 + _y*pitch) = ((((int)r & 0xf8) << 8) | \ |
| (((int)g & 0xfc) << 3) | \ |
| (((int)b & 0xf8) >> 3)) |
| |
| #define WRITE_PIXEL( _x, _y, p ) \ |
| *(GLushort *)(buf + _x*2 + _y*pitch) = p |
| |
| #define READ_RGBA( rgba, _x, _y ) \ |
| do { \ |
| GLushort p = *(GLushort *)(buf + _x*2 + _y*pitch); \ |
| rgba[0] = (((p >> 11) & 0x1f) * 255) / 31; \ |
| rgba[1] = (((p >> 5) & 0x3f) * 255) / 63; \ |
| rgba[2] = (((p >> 0) & 0x1f) * 255) / 31; \ |
| rgba[3] = 0xff; \ |
| } while (0) |
| |
| #define TAG(x) tdfx##x##_RGB565 |
| #define BYTESPERPIXEL 2 |
| #include "spantmp.h" |
| #undef BYTESPERPIXEL |
| |
| |
| /* 16 bit, BGR565 color spanline and pixel functions */ \ |
| #if 0 |
| |
| #define WRITE_RGBA( _x, _y, r, g, b, a ) \ |
| *(GLushort *)(buf + _x*2 + _y*pitch) = ((((int)b & 0xf8) << 8) | \ |
| (((int)g & 0xfc) << 3) | \ |
| (((int)r & 0xf8) >> 3)) |
| |
| #define WRITE_PIXEL( _x, _y, p ) \ |
| *(GLushort *)(buf + _x*2 + _y*pitch) = p |
| |
| #define READ_RGBA( rgba, _x, _y ) \ |
| do { \ |
| GLushort p = *(GLushort *)(buf + _x*2 + _y*pitch); \ |
| rgba[0] = (p << 3) & 0xf8; \ |
| rgba[1] = (p >> 3) & 0xfc; \ |
| rgba[2] = (p >> 8) & 0xf8; \ |
| rgba[3] = 0xff; \ |
| } while (0) |
| |
| #define TAG(x) tdfx##x##_BGR565 |
| #define BYTESPERPIXEL 2 |
| #include "spantmp.h" |
| #undef BYTESPERPIXEL |
| #endif |
| |
| |
| #undef LFB_MODE |
| #define LFB_MODE GR_LFBWRITEMODE_888 |
| |
| |
| /* 24 bit, RGB888 color spanline and pixel functions */ |
| #undef INIT_MONO_PIXEL |
| #define INIT_MONO_PIXEL(p, color) \ |
| p = TDFXPACKCOLOR888( color[0], color[1], color[2] ) |
| |
| #define WRITE_RGBA( _x, _y, r, g, b, a ) \ |
| *(GLuint *)(buf + _x*3 + _y*pitch) = ((b << 0) | \ |
| (g << 8) | \ |
| (r << 16)) |
| |
| #define WRITE_PIXEL( _x, _y, p ) \ |
| *(GLuint *)(buf + _x*3 + _y*pitch) = p |
| |
| #define READ_RGBA( rgba, _x, _y ) \ |
| do { \ |
| GLuint p = *(GLuint *)(buf + _x*3 + _y*pitch); \ |
| rgba[0] = (p >> 16) & 0xff; \ |
| rgba[1] = (p >> 8) & 0xff; \ |
| rgba[2] = (p >> 0) & 0xff; \ |
| rgba[3] = 0xff; \ |
| } while (0) |
| |
| #define TAG(x) tdfx##x##_RGB888 |
| #define BYTESPERPIXEL 4 |
| #include "spantmp.h" |
| #undef BYTESPERPIXEL |
| |
| |
| #undef LFB_MODE |
| #define LFB_MODE GR_LFBWRITEMODE_8888 |
| |
| |
| /* 32 bit, ARGB8888 color spanline and pixel functions */ |
| #undef INIT_MONO_PIXEL |
| #define INIT_MONO_PIXEL(p, color) \ |
| p = TDFXPACKCOLOR8888( color[0], color[1], color[2], color[3] ) |
| |
| #define WRITE_RGBA( _x, _y, r, g, b, a ) \ |
| *(GLuint *)(buf + _x*4 + _y*pitch) = ((b << 0) | \ |
| (g << 8) | \ |
| (r << 16) | \ |
| (a << 24) ) |
| |
| #define WRITE_PIXEL( _x, _y, p ) \ |
| *(GLuint *)(buf + _x*4 + _y*pitch) = p |
| |
| #define READ_RGBA( rgba, _x, _y ) \ |
| do { \ |
| GLuint p = *(GLuint *)(buf + _x*4 + _y*pitch); \ |
| rgba[0] = (p >> 16) & 0xff; \ |
| rgba[1] = (p >> 8) & 0xff; \ |
| rgba[2] = (p >> 0) & 0xff; \ |
| rgba[3] = (p >> 24) & 0xff; \ |
| } while (0) |
| |
| #define TAG(x) tdfx##x##_ARGB8888 |
| #define BYTESPERPIXEL 4 |
| #include "spantmp.h" |
| #undef BYTESPERPIXEL |
| |
| |
| |
| /* ================================================================ |
| * Old span functions below... |
| */ |
| |
| |
| /* |
| * Examine the cliprects to generate an array of flags to indicate |
| * which pixels in a span are visible. Note: (x,y) is a screen |
| * coordinate. |
| */ |
| static void |
| generate_vismask(const tdfxContextPtr fxMesa, GLint x, GLint y, GLint n, |
| GLubyte vismask[]) |
| { |
| GLboolean initialized = GL_FALSE; |
| GLint i, j; |
| |
| /* Ensure we clear the visual mask */ |
| MEMSET(vismask, 0, n); |
| |
| /* turn on flags for all visible pixels */ |
| for (i = 0; i < fxMesa->numClipRects; i++) { |
| const drm_clip_rect_t *rect = &fxMesa->pClipRects[i]; |
| |
| if (y >= rect->y1 && y < rect->y2) { |
| if (x >= rect->x1 && x + n <= rect->x2) { |
| /* common case, whole span inside cliprect */ |
| MEMSET(vismask, 1, n); |
| return; |
| } |
| if (x < rect->x2 && x + n >= rect->x1) { |
| /* some of the span is inside the rect */ |
| GLint start, end; |
| if (!initialized) { |
| MEMSET(vismask, 0, n); |
| initialized = GL_TRUE; |
| } |
| if (x < rect->x1) |
| start = rect->x1 - x; |
| else |
| start = 0; |
| if (x + n > rect->x2) |
| end = rect->x2 - x; |
| else |
| end = n; |
| assert(start >= 0); |
| assert(end <= n); |
| for (j = start; j < end; j++) |
| vismask[j] = 1; |
| } |
| } |
| } |
| } |
| |
| /* |
| * Examine cliprects and determine if the given screen pixel is visible. |
| */ |
| static GLboolean |
| visible_pixel(const tdfxContextPtr fxMesa, int scrX, int scrY) |
| { |
| int i; |
| for (i = 0; i < fxMesa->numClipRects; i++) { |
| const drm_clip_rect_t *rect = &fxMesa->pClipRects[i]; |
| if (scrX >= rect->x1 && |
| scrX < rect->x2 && |
| scrY >= rect->y1 && scrY < rect->y2) return GL_TRUE; |
| } |
| return GL_FALSE; |
| } |
| |
| |
| |
| /* |
| * Depth buffer read/write functions. |
| */ |
| /* |
| * To read the frame buffer, we need to lock and unlock it. The |
| * four macros {READ,WRITE}_FB_SPAN_{LOCK,UNLOCK} |
| * do this for us. |
| * |
| * Note that the lock must be matched with an unlock. These |
| * macros include a spare curly brace, so they must |
| * be syntactically matched. |
| * |
| * Note, also, that you can't lock a buffer twice with different |
| * modes. That is to say, you can't lock a buffer in both read |
| * and write modes. The strideInBytes and LFB pointer will be |
| * the same with read and write locks, so you can use either. |
| * o The HW has different state for reads and writes, so |
| * locking it twice may give screwy results. |
| * o The DRM won't let you lock twice. It hangs. This is probably |
| * because of the LOCK_HARDWARE IN THE *_FB_SPAN_LOCK macros, |
| * and could be eliminated with nonlocking lock routines. But |
| * what's the point after all. |
| */ |
| #define READ_FB_SPAN_LOCK(fxMesa, info, target_buffer) \ |
| UNLOCK_HARDWARE(fxMesa); \ |
| LOCK_HARDWARE(fxMesa); \ |
| (info).size=sizeof(info); \ |
| if (fxMesa->Glide.grLfbLock(GR_LFB_READ_ONLY, \ |
| target_buffer, \ |
| GR_LFBWRITEMODE_ANY, \ |
| GR_ORIGIN_UPPER_LEFT, \ |
| FXFALSE, \ |
| &(info))) { |
| |
| #define READ_FB_SPAN_UNLOCK(fxMesa, target_buffer) \ |
| fxMesa->Glide.grLfbUnlock(GR_LFB_READ_ONLY, target_buffer); \ |
| } else { \ |
| fprintf(stderr, "tdfxDriver: Can't get %s (%d) read lock\n", \ |
| (target_buffer == GR_BUFFER_BACKBUFFER) \ |
| ? "back buffer" \ |
| : ((target_buffer == GR_BUFFER_AUXBUFFER) \ |
| ? "depth buffer" \ |
| : "unknown buffer"), \ |
| target_buffer); \ |
| } |
| |
| #define WRITE_FB_SPAN_LOCK(fxMesa, info, target_buffer, write_mode) \ |
| UNLOCK_HARDWARE(fxMesa); \ |
| LOCK_HARDWARE(fxMesa); \ |
| info.size=sizeof(info); \ |
| if (fxMesa->Glide.grLfbLock(GR_LFB_WRITE_ONLY, \ |
| target_buffer, \ |
| write_mode, \ |
| GR_ORIGIN_UPPER_LEFT, \ |
| FXFALSE, \ |
| &info)) { |
| |
| #define WRITE_FB_SPAN_UNLOCK(fxMesa, target_buffer) \ |
| fxMesa->Glide.grLfbUnlock(GR_LFB_WRITE_ONLY, target_buffer); \ |
| } else { \ |
| fprintf(stderr, "tdfxDriver: Can't get %s (%d) write lock\n", \ |
| (target_buffer == GR_BUFFER_BACKBUFFER) \ |
| ? "back buffer" \ |
| : ((target_buffer == GR_BUFFER_AUXBUFFER) \ |
| ? "depth buffer" \ |
| : "unknown buffer"), \ |
| target_buffer); \ |
| } |
| |
| /* |
| * Because the Linear Frame Buffer is not necessarily aligned |
| * with the depth buffer, we have to do some fiddling |
| * around to get the right addresses. |
| * |
| * Perhaps a picture is in order. The Linear Frame Buffer |
| * looks like this: |
| * |
| * |<----------------------info.strideInBytes------------->| |
| * |<-----physicalStrideInBytes------->| |
| * +-----------------------------------+xxxxxxxxxxxxxxxxxxx+ |
| * | | | |
| * | Legal Memory | Forbidden Zone | |
| * | | | |
| * +-----------------------------------+xxxxxxxxxxxxxxxxxxx+ |
| * |
| * You can only reliably read and write legal locations. Reads |
| * and writes from the Forbidden Zone will return undefined values, |
| * and may cause segmentation faults. |
| * |
| * Now, the depth buffer may not end up in a location such each |
| * scan line is an LFB line. For example, the depth buffer may |
| * look like this: |
| * |
| * wrapped ordinary. |
| * +-----------------------------------+xxxxxxxxxxxxxxxxxxx+ |
| * |0000000000000000000000 | | back |
| * |1111111111111111111111 | | buffer |
| * |2222222222222222222222 | | |
| * |4096b align. padxx00000000000000000| Forbidden Zone | depth |
| * |0000 11111111111111111| | buffer |
| * |1111 22222222222222222| | |
| * |2222 | | |
| * +-----------------------------------+xxxxxxxxxxxxxxxxxxx+ |
| * where each number is the scan line number. We know it will |
| * be aligned on 128 byte boundaries, at least. Aligning this |
| * on a scanline boundary causes the back and depth buffers to |
| * thrash in the SST1 cache. (Note that the back buffer is always |
| * allocated at the beginning of LFB memory, and so it is always |
| * properly aligned with the LFB stride.) |
| * |
| * We call the beginning of the line (which is the rightmost |
| * part of the depth line in the picture above) the *ordinary* part |
| * of the scanline, and the end of the line (which is the |
| * leftmost part, one line below) the *wrapped* part of the scanline. |
| * a.) We need to know what x value to subtract from the screen |
| * x coordinate to index into the wrapped part. |
| * b.) We also need to figure out if we need to read from the ordinary |
| * part scan line, or from the wrapped part of the scan line. |
| * |
| * [ad a] |
| * The first wrapped x coordinate is that coordinate such that |
| * depthBufferOffset&(info.strideInBytes) + x*elmentSize {*} |
| * > physicalStrideInBytes |
| * where depthBufferOffset is the LFB distance in bytes |
| * from the back buffer to the depth buffer. The expression |
| * depthBufferOffset&(info.strideInBytes) |
| * is then the offset (in bytes) from the beginining of (any) |
| * depth buffer line to first element in the line. |
| * Simplifying inequation {*} above we see that x is the smallest |
| * value such that |
| * x*elementSize > physicalStrideInBytes {**} |
| * - depthBufferOffset&(info.strideInBytes) |
| * Now, we know that both the summands on the right are multiples of |
| * 128, and elementSize <= 4, so if equality holds in {**}, x would |
| * be a multiple of 32. Thus we can set x to |
| * xwrapped = (physicalStrideInBytes |
| * - depthBufferOffset&(info.strideInBytes))/elementSize |
| * + 1 |
| * |
| * [ad b] |
| * Question b is now simple. We read from the wrapped scan line if |
| * x is greater than xwrapped. |
| */ |
| #define TILE_WIDTH_IN_BYTES 128 |
| #define TILE_WIDTH_IN_ZOXELS(bpz) (TILE_WIDTH_IN_BYTES/(bpz)) |
| #define TILE_HEIGHT_IN_LINES 32 |
| typedef struct |
| { |
| void *lfbPtr; |
| void *lfbWrapPtr; |
| FxU32 LFBStrideInElts; |
| GLint firstWrappedX; |
| } |
| LFBParameters; |
| |
| /* |
| * We need information about the back buffer. Note that |
| * this function *cannot be called* while the aux buffer |
| * is locked, or the caller will hang. |
| * |
| * Only Glide knows the LFB address of the back and depth |
| * offsets. The upper levels of Mesa know the depth offset, |
| * but that is not in LFB space, it is tiled memory space, |
| * and is not useable for us. |
| */ |
| static void |
| GetBackBufferInfo(tdfxContextPtr fxMesa, GrLfbInfo_t * backBufferInfo) |
| { |
| READ_FB_SPAN_LOCK(fxMesa, *backBufferInfo, GR_BUFFER_BACKBUFFER); |
| READ_FB_SPAN_UNLOCK(fxMesa, GR_BUFFER_BACKBUFFER); |
| } |
| |
| static void |
| GetFbParams(tdfxContextPtr fxMesa, |
| GrLfbInfo_t * info, |
| GrLfbInfo_t * backBufferInfo, |
| LFBParameters * ReadParamsp, FxU32 elementSize) |
| { |
| FxU32 physicalStrideInBytes, bufferOffset; |
| FxU32 strideInBytes = info->strideInBytes; |
| char *lfbPtr = (char *) (info->lfbPtr); /* For arithmetic, use char * */ |
| |
| /* |
| * These two come directly from the info structure. |
| */ |
| ReadParamsp->lfbPtr = (void *) lfbPtr; |
| ReadParamsp->LFBStrideInElts = strideInBytes / elementSize; |
| /* |
| * Now, calculate the value of firstWrappedX. |
| * |
| * The physical stride is the screen width in bytes rounded up to |
| * the next highest multiple of 128 bytes. Note that this fails |
| * when TILE_WIDTH_IN_BYTES is not a power of two. |
| * |
| * The buffer Offset is the distance between the beginning of |
| * the LFB space, which is the beginning of the back buffer, |
| * and the buffer we are gathering information about. |
| * We want to make this routine usable for operations on the |
| * back buffer, though we don't actually use it on the back |
| * buffer. Note, then, that if bufferOffset == 0, the firstWrappedX |
| * is in the forbidden zone, and is therefore never reached. |
| * |
| * Note that if |
| * physicalStrideInBytes |
| * < bufferOffset&(info->strideInBytes-1) |
| * the buffer begins in the forbidden zone. We assert for this. |
| */ |
| bufferOffset = (FxU32)(lfbPtr - (char *) backBufferInfo->lfbPtr); |
| physicalStrideInBytes |
| = (fxMesa->screen_width * elementSize + TILE_WIDTH_IN_BYTES - 1) |
| & ~(TILE_WIDTH_IN_BYTES - 1); |
| assert(physicalStrideInBytes > (bufferOffset & (strideInBytes - 1))); |
| ReadParamsp->firstWrappedX |
| = (physicalStrideInBytes |
| - (bufferOffset & (strideInBytes - 1))) / elementSize; |
| /* |
| * This is the address of the next physical line. |
| */ |
| ReadParamsp->lfbWrapPtr |
| = (void *) ((char *) backBufferInfo->lfbPtr |
| + (bufferOffset & ~(strideInBytes - 1)) |
| + (TILE_HEIGHT_IN_LINES) * strideInBytes); |
| } |
| |
| /* |
| * These macros fetch data from the frame buffer. The type is |
| * the type of data we want to fetch. It should match the type |
| * whose size was used with GetFbParams to fill in the structure |
| * in *ReadParamsp. We have a macro to read the ordinary |
| * part, a second macro to read the wrapped part, and one which |
| * will do either. When we are reading a span, we will know |
| * when the ordinary part ends, so there's no need to test for |
| * it. However, when reading and writing pixels, we don't |
| * necessarily know. I suppose it's a matter of taste whether |
| * it's better in the macro or in the call. |
| * |
| * Recall that x and y are screen coordinates. |
| */ |
| #define GET_ORDINARY_FB_DATA(ReadParamsp, type, x, y) \ |
| (((type *)((ReadParamsp)->lfbPtr)) \ |
| [(y) * ((ReadParamsp)->LFBStrideInElts) \ |
| + (x)]) |
| #define GET_WRAPPED_FB_DATA(ReadParamsp, type, x, y) \ |
| (((type *)((ReadParamsp)->lfbWrapPtr)) \ |
| [((y)) * ((ReadParamsp)->LFBStrideInElts) \ |
| + ((x) - (ReadParamsp)->firstWrappedX)]) |
| #define GET_FB_DATA(ReadParamsp, type, x, y) \ |
| (((x) < (ReadParamsp)->firstWrappedX) \ |
| ? GET_ORDINARY_FB_DATA(ReadParamsp, type, x, y) \ |
| : GET_WRAPPED_FB_DATA(ReadParamsp, type, x, y)) |
| #define PUT_ORDINARY_FB_DATA(ReadParamsp, type, x, y, value) \ |
| (GET_ORDINARY_FB_DATA(ReadParamsp, type, x, y) = (type)(value)) |
| #define PUT_WRAPPED_FB_DATA(ReadParamsp, type, x, y, value) \ |
| (GET_WRAPPED_FB_DATA(ReadParamsp, type, x, y) = (type)(value)) |
| #define PUT_FB_DATA(ReadParamsp, type, x, y, value) \ |
| do { \ |
| if ((x) < (ReadParamsp)->firstWrappedX) \ |
| PUT_ORDINARY_FB_DATA(ReadParamsp, type, x, y, value); \ |
| else \ |
| PUT_WRAPPED_FB_DATA(ReadParamsp, type, x, y, value); \ |
| } while (0) |
| |
| |
| static void |
| tdfxDDWriteDepthSpan(GLcontext * ctx, struct gl_renderbuffer *rb, |
| GLuint n, GLint x, GLint y, const void *values, |
| const GLubyte mask[]) |
| { |
| const GLuint *depth = (const GLuint *) values; |
| tdfxContextPtr fxMesa = (tdfxContextPtr) ctx->DriverCtx; |
| GLint bottom = fxMesa->y_offset + fxMesa->height - 1; |
| GLuint depth_size = fxMesa->glCtx->Visual.depthBits; |
| GLuint stencil_size = fxMesa->glCtx->Visual.stencilBits; |
| GrLfbInfo_t info; |
| GLubyte visMask[MAX_WIDTH]; |
| |
| if (MESA_VERBOSE & VERBOSE_DRIVER) { |
| fprintf(stderr, "tdfxmesa: tdfxDDWriteDepthSpan(...)\n"); |
| } |
| |
| assert((depth_size == 16) || (depth_size == 24) || (depth_size == 32)); |
| /* |
| * Convert x and y to screen coordinates. |
| */ |
| x += fxMesa->x_offset; |
| y = bottom - y; |
| if (mask) { |
| GLint i; |
| GLushort d16; |
| GrLfbInfo_t backBufferInfo; |
| |
| switch (depth_size) { |
| case 16: |
| GetBackBufferInfo(fxMesa, &backBufferInfo); |
| /* |
| * Note that the _LOCK macro adds a curly brace, |
| * and the UNLOCK macro removes it. |
| */ |
| WRITE_FB_SPAN_LOCK(fxMesa, info, GR_BUFFER_AUXBUFFER, |
| GR_LFBWRITEMODE_ANY); |
| generate_vismask(fxMesa, x, y, n, visMask); |
| { |
| LFBParameters ReadParams; |
| int wrappedPartStart; |
| GetFbParams(fxMesa, &info, &backBufferInfo, |
| &ReadParams, sizeof(GLushort)); |
| if (ReadParams.firstWrappedX <= x) { |
| wrappedPartStart = 0; |
| } |
| else if (n <= (ReadParams.firstWrappedX - x)) { |
| wrappedPartStart = n; |
| } |
| else { |
| wrappedPartStart = (ReadParams.firstWrappedX - x); |
| } |
| for (i = 0; i < wrappedPartStart; i++) { |
| if (mask[i] && visMask[i]) { |
| d16 = depth[i]; |
| PUT_ORDINARY_FB_DATA(&ReadParams, GLushort, x + i, y, d16); |
| } |
| } |
| for (; i < n; i++) { |
| if (mask[i] && visMask[i]) { |
| d16 = depth[i]; |
| PUT_WRAPPED_FB_DATA(&ReadParams, GLushort, x + i, y, d16); |
| } |
| } |
| } |
| WRITE_FB_SPAN_UNLOCK(fxMesa, GR_BUFFER_AUXBUFFER); |
| break; |
| case 24: |
| case 32: |
| GetBackBufferInfo(fxMesa, &backBufferInfo); |
| /* |
| * Note that the _LOCK macro adds a curly brace, |
| * and the UNLOCK macro removes it. |
| */ |
| WRITE_FB_SPAN_LOCK(fxMesa, info, GR_BUFFER_AUXBUFFER, |
| GR_LFBWRITEMODE_ANY); |
| generate_vismask(fxMesa, x, y, n, visMask); |
| { |
| LFBParameters ReadParams; |
| int wrappedPartStart; |
| GetFbParams(fxMesa, &info, &backBufferInfo, |
| &ReadParams, sizeof(GLuint)); |
| if (ReadParams.firstWrappedX <= x) { |
| wrappedPartStart = 0; |
| } |
| else if (n <= (ReadParams.firstWrappedX - x)) { |
| wrappedPartStart = n; |
| } |
| else { |
| wrappedPartStart = (ReadParams.firstWrappedX - x); |
| } |
| for (i = 0; i < wrappedPartStart; i++) { |
| GLuint d32; |
| if (mask[i] && visMask[i]) { |
| if (stencil_size > 0) { |
| d32 = |
| GET_ORDINARY_FB_DATA(&ReadParams, GLuint, |
| x + i, y); |
| d32 = |
| (d32 & 0xFF000000) | (depth[i] & 0x00FFFFFF); |
| } |
| else { |
| d32 = depth[i]; |
| } |
| PUT_ORDINARY_FB_DATA(&ReadParams, GLuint, x + i, y, d32); |
| } |
| } |
| for (; i < n; i++) { |
| GLuint d32; |
| if (mask[i] && visMask[i]) { |
| if (stencil_size > 0) { |
| d32 = |
| GET_WRAPPED_FB_DATA(&ReadParams, GLuint, |
| x + i, y); |
| d32 = |
| (d32 & 0xFF000000) | (depth[i] & 0x00FFFFFF); |
| } |
| else { |
| d32 = depth[i]; |
| } |
| PUT_WRAPPED_FB_DATA(&ReadParams, GLuint, x + i, y, d32); |
| } |
| } |
| } |
| WRITE_FB_SPAN_UNLOCK(fxMesa, GR_BUFFER_AUXBUFFER); |
| break; |
| } |
| } |
| else { |
| GLint i; |
| GLuint d32; |
| GLushort d16; |
| GrLfbInfo_t backBufferInfo; |
| |
| switch (depth_size) { |
| case 16: |
| GetBackBufferInfo(fxMesa, &backBufferInfo); |
| /* |
| * Note that the _LOCK macro adds a curly brace, |
| * and the UNLOCK macro removes it. |
| */ |
| WRITE_FB_SPAN_LOCK(fxMesa, info, |
| GR_BUFFER_AUXBUFFER, GR_LFBWRITEMODE_ANY); |
| generate_vismask(fxMesa, x, y, n, visMask); |
| { |
| LFBParameters ReadParams; |
| GLuint wrappedPartStart; |
| GetFbParams(fxMesa, &info, &backBufferInfo, |
| &ReadParams, sizeof(GLushort)); |
| if (ReadParams.firstWrappedX <= x) { |
| wrappedPartStart = 0; |
| } |
| else if (n <= (ReadParams.firstWrappedX - x)) { |
| wrappedPartStart = n; |
| } |
| else { |
| wrappedPartStart = (ReadParams.firstWrappedX - x); |
| } |
| for (i = 0; i < wrappedPartStart; i++) { |
| if (visMask[i]) { |
| d16 = depth[i]; |
| PUT_ORDINARY_FB_DATA(&ReadParams, |
| GLushort, |
| x + i, y, |
| d16); |
| } |
| } |
| for (; i < n; i++) { |
| if (visMask[i]) { |
| d16 = depth[i]; |
| PUT_WRAPPED_FB_DATA(&ReadParams, |
| GLushort, |
| x + i, y, |
| d16); |
| } |
| } |
| } |
| WRITE_FB_SPAN_UNLOCK(fxMesa, GR_BUFFER_AUXBUFFER); |
| break; |
| case 24: |
| case 32: |
| GetBackBufferInfo(fxMesa, &backBufferInfo); |
| /* |
| * Note that the _LOCK macro adds a curly brace, |
| * and the UNLOCK macro removes it. |
| */ |
| WRITE_FB_SPAN_LOCK(fxMesa, info, |
| GR_BUFFER_AUXBUFFER, GR_LFBWRITEMODE_ANY); |
| generate_vismask(fxMesa, x, y, n, visMask); |
| { |
| LFBParameters ReadParams; |
| GLuint wrappedPartStart; |
| |
| GetFbParams(fxMesa, &info, &backBufferInfo, |
| &ReadParams, sizeof(GLuint)); |
| if (ReadParams.firstWrappedX <= x) { |
| wrappedPartStart = 0; |
| } |
| else if (n <= (ReadParams.firstWrappedX - x)) { |
| wrappedPartStart = n; |
| } |
| else { |
| wrappedPartStart = (ReadParams.firstWrappedX - x); |
| } |
| for (i = 0; i < wrappedPartStart; i++) { |
| if (visMask[i]) { |
| if (stencil_size > 0) { |
| d32 = GET_ORDINARY_FB_DATA(&ReadParams, GLuint, x + i, y); |
| d32 = |
| (d32 & 0xFF000000) | (depth[i] & 0x00FFFFFF); |
| } |
| else { |
| d32 = depth[i]; |
| } |
| PUT_ORDINARY_FB_DATA(&ReadParams, GLuint, x + i, y, d32); |
| } |
| } |
| for (; i < n; i++) { |
| if (visMask[i]) { |
| if (stencil_size > 0) { |
| d32 = GET_WRAPPED_FB_DATA(&ReadParams, GLuint, x + i, y); |
| d32 = |
| (d32 & 0xFF000000) | (depth[i] & 0x00FFFFFF); |
| } |
| else { |
| d32 = depth[i]; |
| } |
| PUT_WRAPPED_FB_DATA(&ReadParams, GLuint, x + i, y, d32); |
| } |
| } |
| } |
| WRITE_FB_SPAN_UNLOCK(fxMesa, GR_BUFFER_AUXBUFFER); |
| break; |
| } |
| } |
| } |
| |
| static void |
| tdfxDDWriteMonoDepthSpan(GLcontext * ctx, struct gl_renderbuffer *rb, |
| GLuint n, GLint x, GLint y, const void *value, |
| const GLubyte mask[]) |
| { |
| GLuint depthVal = *((GLuint *) value); |
| GLuint depths[MAX_WIDTH]; |
| GLuint i; |
| for (i = 0; i < n; i++) |
| depths[i] = depthVal; |
| tdfxDDWriteDepthSpan(ctx, rb, n, x, y, depths, mask); |
| } |
| |
| |
| static void |
| tdfxDDReadDepthSpan(GLcontext * ctx, struct gl_renderbuffer *rb, |
| GLuint n, GLint x, GLint y, void *values) |
| { |
| GLuint *depth = (GLuint *) values; |
| tdfxContextPtr fxMesa = (tdfxContextPtr) ctx->DriverCtx; |
| GLint bottom = fxMesa->height + fxMesa->y_offset - 1; |
| GLuint i; |
| GLuint depth_size = fxMesa->glCtx->Visual.depthBits; |
| GrLfbInfo_t info; |
| |
| if (MESA_VERBOSE & VERBOSE_DRIVER) { |
| fprintf(stderr, "tdfxmesa: tdfxDDReadDepthSpan(...)\n"); |
| } |
| |
| /* |
| * Convert to screen coordinates. |
| */ |
| x += fxMesa->x_offset; |
| y = bottom - y; |
| switch (depth_size) { |
| case 16: |
| { |
| LFBParameters ReadParams; |
| GrLfbInfo_t backBufferInfo; |
| int wrappedPartStart; |
| GetBackBufferInfo(fxMesa, &backBufferInfo); |
| /* |
| * Note that the _LOCK macro adds a curly brace, |
| * and the UNLOCK macro removes it. |
| */ |
| READ_FB_SPAN_LOCK(fxMesa, info, GR_BUFFER_AUXBUFFER); |
| GetFbParams(fxMesa, &info, &backBufferInfo, |
| &ReadParams, sizeof(GLushort)); |
| if (ReadParams.firstWrappedX <= x) { |
| wrappedPartStart = 0; |
| } |
| else if (n <= (ReadParams.firstWrappedX - x)) { |
| wrappedPartStart = n; |
| } |
| else { |
| wrappedPartStart = (ReadParams.firstWrappedX - x); |
| } |
| /* |
| * Read the line. |
| */ |
| for (i = 0; i < wrappedPartStart; i++) { |
| depth[i] = |
| GET_ORDINARY_FB_DATA(&ReadParams, GLushort, x + i, y); |
| } |
| for (; i < n; i++) { |
| depth[i] = GET_WRAPPED_FB_DATA(&ReadParams, GLushort, |
| x + i, y); |
| } |
| READ_FB_SPAN_UNLOCK(fxMesa, GR_BUFFER_AUXBUFFER); |
| break; |
| } |
| case 24: |
| case 32: |
| { |
| LFBParameters ReadParams; |
| GrLfbInfo_t backBufferInfo; |
| int wrappedPartStart; |
| GLuint stencil_size = fxMesa->glCtx->Visual.stencilBits; |
| GetBackBufferInfo(fxMesa, &backBufferInfo); |
| /* |
| * Note that the _LOCK macro adds a curly brace, |
| * and the UNLOCK macro removes it. |
| */ |
| READ_FB_SPAN_LOCK(fxMesa, info, GR_BUFFER_AUXBUFFER); |
| GetFbParams(fxMesa, &info, &backBufferInfo, |
| &ReadParams, sizeof(GLuint)); |
| if (ReadParams.firstWrappedX <= x) { |
| wrappedPartStart = 0; |
| } |
| else if (n <= (ReadParams.firstWrappedX - x)) { |
| wrappedPartStart = n; |
| } |
| else { |
| wrappedPartStart = (ReadParams.firstWrappedX - x); |
| } |
| /* |
| * Read the line. |
| */ |
| for (i = 0; i < wrappedPartStart; i++) { |
| const GLuint mask = |
| (stencil_size > 0) ? 0x00FFFFFF : 0xFFFFFFFF; |
| depth[i] = |
| GET_ORDINARY_FB_DATA(&ReadParams, GLuint, x + i, y); |
| depth[i] &= mask; |
| } |
| for (; i < n; i++) { |
| const GLuint mask = |
| (stencil_size > 0) ? 0x00FFFFFF : 0xFFFFFFFF; |
| depth[i] = GET_WRAPPED_FB_DATA(&ReadParams, GLuint, x + i, y); |
| depth[i] &= mask; |
| } |
| READ_FB_SPAN_UNLOCK(fxMesa, GR_BUFFER_AUXBUFFER); |
| break; |
| } |
| } |
| } |
| |
| |
| static void |
| tdfxDDWriteDepthPixels(GLcontext * ctx, struct gl_renderbuffer *rb, |
| GLuint n, const GLint x[], const GLint y[], |
| const void *values, const GLubyte mask[]) |
| { |
| const GLuint *depth = (const GLuint *) values; |
| tdfxContextPtr fxMesa = (tdfxContextPtr) ctx->DriverCtx; |
| GLint bottom = fxMesa->height + fxMesa->y_offset - 1; |
| GLuint i; |
| GLushort d16; |
| GLuint d32; |
| GLuint depth_size = fxMesa->glCtx->Visual.depthBits; |
| GLuint stencil_size = fxMesa->glCtx->Visual.stencilBits; |
| GrLfbInfo_t info; |
| int xpos; |
| int ypos; |
| GrLfbInfo_t backBufferInfo; |
| |
| if (MESA_VERBOSE & VERBOSE_DRIVER) { |
| fprintf(stderr, "tdfxmesa: tdfxDDWriteDepthPixels(...)\n"); |
| } |
| |
| switch (depth_size) { |
| case 16: |
| GetBackBufferInfo(fxMesa, &backBufferInfo); |
| /* |
| * Note that the _LOCK macro adds a curly brace, |
| * and the UNLOCK macro removes it. |
| */ |
| WRITE_FB_SPAN_LOCK(fxMesa, info, |
| GR_BUFFER_AUXBUFFER, GR_LFBWRITEMODE_ANY); |
| { |
| LFBParameters ReadParams; |
| GetFbParams(fxMesa, &info, &backBufferInfo, |
| &ReadParams, sizeof(GLushort)); |
| for (i = 0; i < n; i++) { |
| if ((!mask || mask[i]) && visible_pixel(fxMesa, x[i], y[i])) { |
| xpos = x[i] + fxMesa->x_offset; |
| ypos = bottom - y[i]; |
| d16 = depth[i]; |
| PUT_FB_DATA(&ReadParams, GLushort, xpos, ypos, d16); |
| } |
| } |
| } |
| WRITE_FB_SPAN_UNLOCK(fxMesa, GR_BUFFER_AUXBUFFER); |
| break; |
| case 24: |
| case 32: |
| GetBackBufferInfo(fxMesa, &backBufferInfo); |
| /* |
| * Note that the _LOCK macro adds a curly brace, |
| * and the UNLOCK macro removes it. |
| */ |
| WRITE_FB_SPAN_LOCK(fxMesa, info, |
| GR_BUFFER_AUXBUFFER, GR_LFBWRITEMODE_ANY); |
| { |
| LFBParameters ReadParams; |
| GetFbParams(fxMesa, &info, &backBufferInfo, |
| &ReadParams, sizeof(GLuint)); |
| for (i = 0; i < n; i++) { |
| if (!mask || mask[i]) { |
| if (visible_pixel(fxMesa, x[i], y[i])) { |
| xpos = x[i] + fxMesa->x_offset; |
| ypos = bottom - y[i]; |
| if (stencil_size > 0) { |
| d32 = |
| GET_FB_DATA(&ReadParams, GLuint, xpos, ypos); |
| d32 = (d32 & 0xFF000000) | (depth[i] & 0xFFFFFF); |
| } |
| else { |
| d32 = depth[i]; |
| } |
| PUT_FB_DATA(&ReadParams, GLuint, xpos, ypos, d32); |
| } |
| } |
| } |
| } |
| WRITE_FB_SPAN_UNLOCK(fxMesa, GR_BUFFER_AUXBUFFER); |
| break; |
| } |
| } |
| |
| |
| static void |
| tdfxDDReadDepthPixels(GLcontext * ctx, struct gl_renderbuffer *rb, GLuint n, |
| const GLint x[], const GLint y[], void *values) |
| { |
| GLuint *depth = (GLuint *) values; |
| tdfxContextPtr fxMesa = (tdfxContextPtr) ctx->DriverCtx; |
| GLint bottom = fxMesa->height + fxMesa->y_offset - 1; |
| GLuint i; |
| GLuint depth_size = fxMesa->glCtx->Visual.depthBits; |
| GLushort d16; |
| int xpos; |
| int ypos; |
| GrLfbInfo_t info; |
| GLuint stencil_size; |
| GrLfbInfo_t backBufferInfo; |
| |
| if (MESA_VERBOSE & VERBOSE_DRIVER) { |
| fprintf(stderr, "tdfxmesa: tdfxDDReadDepthPixels(...)\n"); |
| } |
| |
| assert((depth_size == 16) || (depth_size == 24) || (depth_size == 32)); |
| switch (depth_size) { |
| case 16: |
| GetBackBufferInfo(fxMesa, &backBufferInfo); |
| /* |
| * Note that the _LOCK macro adds a curly brace, |
| * and the UNLOCK macro removes it. |
| */ |
| READ_FB_SPAN_LOCK(fxMesa, info, GR_BUFFER_AUXBUFFER); |
| { |
| LFBParameters ReadParams; |
| GetFbParams(fxMesa, &info, &backBufferInfo, |
| &ReadParams, sizeof(GLushort)); |
| for (i = 0; i < n; i++) { |
| /* |
| * Convert to screen coordinates. |
| */ |
| xpos = x[i] + fxMesa->x_offset; |
| ypos = bottom - y[i]; |
| d16 = GET_FB_DATA(&ReadParams, GLushort, xpos, ypos); |
| depth[i] = d16; |
| } |
| } |
| READ_FB_SPAN_UNLOCK(fxMesa, GR_BUFFER_AUXBUFFER); |
| break; |
| case 24: |
| case 32: |
| GetBackBufferInfo(fxMesa, &backBufferInfo); |
| /* |
| * Note that the _LOCK macro adds a curly brace, |
| * and the UNLOCK macro removes it. |
| */ |
| READ_FB_SPAN_LOCK(fxMesa, info, GR_BUFFER_AUXBUFFER); |
| stencil_size = fxMesa->glCtx->Visual.stencilBits; |
| { |
| LFBParameters ReadParams; |
| GetFbParams(fxMesa, &info, &backBufferInfo, |
| &ReadParams, sizeof(GLuint)); |
| for (i = 0; i < n; i++) { |
| GLuint d32; |
| |
| /* |
| * Convert to screen coordinates. |
| */ |
| xpos = x[i] + fxMesa->x_offset; |
| ypos = bottom - y[i]; |
| d32 = GET_FB_DATA(&ReadParams, GLuint, xpos, ypos); |
| if (stencil_size > 0) { |
| d32 &= 0x00FFFFFF; |
| } |
| depth[i] = d32; |
| } |
| } |
| READ_FB_SPAN_UNLOCK(fxMesa, GR_BUFFER_AUXBUFFER); |
| break; |
| default: |
| assert(0); |
| } |
| } |
| |
| /* |
| * Stencil buffer read/write functions. |
| */ |
| #define EXTRACT_S_FROM_ZS(zs) (((zs) >> 24) & 0xFF) |
| #define EXTRACT_Z_FROM_ZS(zs) ((zs) & 0xffffff) |
| #define BUILD_ZS(z, s) (((s) << 24) | (z)) |
| |
| static void |
| write_stencil_span(GLcontext * ctx, struct gl_renderbuffer *rb, |
| GLuint n, GLint x, GLint y, |
| const void *values, const GLubyte mask[]) |
| { |
| const GLubyte *stencil = (const GLubyte *) values; |
| tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx); |
| GrLfbInfo_t info; |
| GrLfbInfo_t backBufferInfo; |
| |
| GetBackBufferInfo(fxMesa, &backBufferInfo); |
| /* |
| * Note that the _LOCK macro adds a curly brace, |
| * and the UNLOCK macro removes it. |
| */ |
| WRITE_FB_SPAN_LOCK(fxMesa, info, GR_BUFFER_AUXBUFFER, GR_LFBWRITEMODE_ANY); |
| { |
| const GLint winY = fxMesa->y_offset + fxMesa->height - 1; |
| const GLint winX = fxMesa->x_offset; |
| const GLint scrX = winX + x; |
| const GLint scrY = winY - y; |
| LFBParameters ReadParams; |
| GLubyte visMask[MAX_WIDTH]; |
| GLuint i; |
| int wrappedPartStart; |
| |
| GetFbParams(fxMesa, &info, &backBufferInfo, &ReadParams, |
| sizeof(GLuint)); |
| if (ReadParams.firstWrappedX <= x) { |
| wrappedPartStart = 0; |
| } |
| else if (n <= (ReadParams.firstWrappedX - x)) { |
| wrappedPartStart = n; |
| } |
| else { |
| wrappedPartStart = (ReadParams.firstWrappedX - x); |
| } |
| generate_vismask(fxMesa, scrX, scrY, n, visMask); |
| for (i = 0; i < wrappedPartStart; i++) { |
| if (visMask[i] && (!mask || mask[i])) { |
| GLuint z = GET_ORDINARY_FB_DATA(&ReadParams, GLuint, |
| scrX + i, scrY) & 0x00FFFFFF; |
| z |= (stencil[i] & 0xFF) << 24; |
| PUT_ORDINARY_FB_DATA(&ReadParams, GLuint, scrX + i, scrY, z); |
| } |
| } |
| for (; i < n; i++) { |
| if (visMask[i] && (!mask || mask[i])) { |
| GLuint z = GET_WRAPPED_FB_DATA(&ReadParams, GLuint, |
| scrX + i, scrY) & 0x00FFFFFF; |
| z |= (stencil[i] & 0xFF) << 24; |
| PUT_WRAPPED_FB_DATA(&ReadParams, GLuint, scrX + i, scrY, z); |
| } |
| } |
| } |
| WRITE_FB_SPAN_UNLOCK(fxMesa, GR_BUFFER_AUXBUFFER); |
| } |
| |
| |
| static void |
| write_mono_stencil_span(GLcontext * ctx, struct gl_renderbuffer *rb, |
| GLuint n, GLint x, GLint y, |
| const void *value, const GLubyte mask[]) |
| { |
| GLbyte stencilVal = *((GLbyte *) value); |
| GLbyte stencils[MAX_WIDTH]; |
| GLuint i; |
| for (i = 0; i < n; i++) |
| stencils[i] = stencilVal; |
| write_stencil_span(ctx, rb, n, x, y, stencils, mask); |
| } |
| |
| |
| static void |
| read_stencil_span(GLcontext * ctx, struct gl_renderbuffer *rb, |
| GLuint n, GLint x, GLint y, |
| void *values) |
| { |
| GLubyte *stencil = (GLubyte *) values; |
| tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx); |
| GrLfbInfo_t info; |
| GrLfbInfo_t backBufferInfo; |
| |
| GetBackBufferInfo(fxMesa, &backBufferInfo); |
| /* |
| * Note that the _LOCK macro adds a curly brace, |
| * and the UNLOCK macro removes it. |
| */ |
| READ_FB_SPAN_LOCK(fxMesa, info, GR_BUFFER_AUXBUFFER); |
| { |
| const GLint winY = fxMesa->y_offset + fxMesa->height - 1; |
| const GLint winX = fxMesa->x_offset; |
| GLuint i; |
| LFBParameters ReadParams; |
| int wrappedPartStart; |
| |
| /* |
| * Convert to screen coordinates. |
| */ |
| x += winX; |
| y = winY - y; |
| GetFbParams(fxMesa, &info, &backBufferInfo, &ReadParams, |
| sizeof(GLuint)); |
| if (ReadParams.firstWrappedX <= x) { |
| wrappedPartStart = 0; |
| } |
| else if (n <= (ReadParams.firstWrappedX - x)) { |
| wrappedPartStart = n; |
| } |
| else { |
| wrappedPartStart = (ReadParams.firstWrappedX - x); |
| } |
| for (i = 0; i < wrappedPartStart; i++) { |
| stencil[i] = (GET_ORDINARY_FB_DATA(&ReadParams, GLuint, |
| x + i, y) >> 24) & 0xFF; |
| } |
| for (; i < n; i++) { |
| stencil[i] = (GET_WRAPPED_FB_DATA(&ReadParams, GLuint, |
| x + i, y) >> 24) & 0xFF; |
| } |
| } |
| READ_FB_SPAN_UNLOCK(fxMesa, GR_BUFFER_AUXBUFFER); |
| } |
| |
| |
| static void |
| write_stencil_pixels(GLcontext * ctx, struct gl_renderbuffer *rb, |
| GLuint n, const GLint x[], const GLint y[], |
| const void *values, const GLubyte mask[]) |
| { |
| const GLubyte *stencil = (const GLubyte *) values; |
| tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx); |
| GrLfbInfo_t info; |
| GrLfbInfo_t backBufferInfo; |
| |
| GetBackBufferInfo(fxMesa, &backBufferInfo); |
| /* |
| * Note that the _LOCK macro adds a curly brace, |
| * and the UNLOCK macro removes it. |
| */ |
| WRITE_FB_SPAN_LOCK(fxMesa, info, GR_BUFFER_AUXBUFFER, GR_LFBWRITEMODE_ANY); |
| { |
| const GLint winY = fxMesa->y_offset + fxMesa->height - 1; |
| const GLint winX = fxMesa->x_offset; |
| LFBParameters ReadParams; |
| GLuint i; |
| |
| GetFbParams(fxMesa, &info, &backBufferInfo, &ReadParams, |
| sizeof(GLuint)); |
| for (i = 0; i < n; i++) { |
| const GLint scrX = winX + x[i]; |
| const GLint scrY = winY - y[i]; |
| if ((!mask || mask[i]) && visible_pixel(fxMesa, scrX, scrY)) { |
| GLuint z = |
| GET_FB_DATA(&ReadParams, GLuint, scrX, scrY) & 0x00FFFFFF; |
| z |= (stencil[i] & 0xFF) << 24; |
| PUT_FB_DATA(&ReadParams, GLuint, scrX, scrY, z); |
| } |
| } |
| } |
| WRITE_FB_SPAN_UNLOCK(fxMesa, GR_BUFFER_AUXBUFFER); |
| } |
| |
| |
| static void |
| read_stencil_pixels(GLcontext * ctx, struct gl_renderbuffer *rb, |
| GLuint n, const GLint x[], const GLint y[], |
| void *values) |
| { |
| GLubyte *stencil = (GLubyte *) values; |
| tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx); |
| GrLfbInfo_t info; |
| GrLfbInfo_t backBufferInfo; |
| |
| GetBackBufferInfo(fxMesa, &backBufferInfo); |
| /* |
| * Note that the _LOCK macro adds a curly brace, |
| * and the UNLOCK macro removes it. |
| */ |
| READ_FB_SPAN_LOCK(fxMesa, info, GR_BUFFER_AUXBUFFER); |
| { |
| const GLint winY = fxMesa->y_offset + fxMesa->height - 1; |
| const GLint winX = fxMesa->x_offset; |
| GLuint i; |
| LFBParameters ReadParams; |
| |
| GetFbParams(fxMesa, &info, &backBufferInfo, &ReadParams, |
| sizeof(GLuint)); |
| for (i = 0; i < n; i++) { |
| const GLint scrX = winX + x[i]; |
| const GLint scrY = winY - y[i]; |
| stencil[i] = |
| (GET_FB_DATA(&ReadParams, GLuint, scrX, scrY) >> 24) & 0xFF; |
| } |
| } |
| READ_FB_SPAN_UNLOCK(fxMesa, GR_BUFFER_AUXBUFFER); |
| } |
| |
| #define VISUAL_EQUALS_RGBA(vis, r, g, b, a) \ |
| ((vis.redBits == r) && \ |
| (vis.greenBits == g) && \ |
| (vis.blueBits == b) && \ |
| (vis.alphaBits == a)) |
| |
| |
| |
| |
| /**********************************************************************/ |
| /* Locking for swrast */ |
| /**********************************************************************/ |
| |
| |
| static void tdfxSpanRenderStart( GLcontext *ctx ) |
| { |
| tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx); |
| LOCK_HARDWARE(fxMesa); |
| } |
| |
| static void tdfxSpanRenderFinish( GLcontext *ctx ) |
| { |
| tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx); |
| _swrast_flush( ctx ); |
| UNLOCK_HARDWARE(fxMesa); |
| } |
| |
| /**********************************************************************/ |
| /* Initialize swrast device driver */ |
| /**********************************************************************/ |
| |
| void tdfxDDInitSpanFuncs( GLcontext *ctx ) |
| { |
| struct swrast_device_driver *swdd = _swrast_GetDeviceDriverReference( ctx ); |
| swdd->SpanRenderStart = tdfxSpanRenderStart; |
| swdd->SpanRenderFinish = tdfxSpanRenderFinish; |
| } |
| |
| |
| |
| /** |
| * Plug in the Get/Put routines for the given driRenderbuffer. |
| */ |
| void |
| tdfxSetSpanFunctions(driRenderbuffer *drb, const GLvisual *vis) |
| { |
| if (drb->Base.InternalFormat == GL_RGBA) { |
| if (vis->redBits == 5 && vis->greenBits == 6 && vis->blueBits == 5) { |
| tdfxInitPointers_RGB565(&drb->Base); |
| } |
| else if (vis->redBits == 8 && vis->greenBits == 8 |
| && vis->blueBits == 8 && vis->alphaBits == 0) { |
| tdfxInitPointers_RGB888(&drb->Base); |
| } |
| else if (vis->redBits == 8 && vis->greenBits == 8 |
| && vis->blueBits == 8 && vis->alphaBits == 8) { |
| tdfxInitPointers_ARGB8888(&drb->Base); |
| } |
| else { |
| _mesa_problem(NULL, "problem in tdfxSetSpanFunctions"); |
| } |
| } |
| else if (drb->Base.InternalFormat == GL_DEPTH_COMPONENT16 || |
| drb->Base.InternalFormat == GL_DEPTH_COMPONENT24) { |
| drb->Base.GetRow = tdfxDDReadDepthSpan; |
| drb->Base.GetValues = tdfxDDReadDepthPixels; |
| drb->Base.PutRow = tdfxDDWriteDepthSpan; |
| drb->Base.PutMonoRow = tdfxDDWriteMonoDepthSpan; |
| drb->Base.PutValues = tdfxDDWriteDepthPixels; |
| drb->Base.PutMonoValues = NULL; |
| } |
| else if (drb->Base.InternalFormat == GL_STENCIL_INDEX8_EXT) { |
| drb->Base.GetRow = read_stencil_span; |
| drb->Base.GetValues = read_stencil_pixels; |
| drb->Base.PutRow = write_stencil_span; |
| drb->Base.PutMonoRow = write_mono_stencil_span; |
| drb->Base.PutValues = write_stencil_pixels; |
| drb->Base.PutMonoValues = NULL; |
| } |
| } |