📄 tdfx_span.c
字号:
/* -*- 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 voidgenerate_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 GLbooleanvisible_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.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -