radeon_span.c revision 758f334717eaf6700defcde126cb9194155a2264
1/* $XFree86: xc/lib/GL/mesa/src/drv/radeon/radeon_span.c,v 1.6 2002/10/30 12:51:56 alanh Exp $ */ 2/************************************************************************** 3 4Copyright 2000, 2001 ATI Technologies Inc., Ontario, Canada, and 5 VA Linux Systems Inc., Fremont, California. 6 7All Rights Reserved. 8 9Permission is hereby granted, free of charge, to any person obtaining 10a copy of this software and associated documentation files (the 11"Software"), to deal in the Software without restriction, including 12without limitation the rights to use, copy, modify, merge, publish, 13distribute, sublicense, and/or sell copies of the Software, and to 14permit persons to whom the Software is furnished to do so, subject to 15the following conditions: 16 17The above copyright notice and this permission notice (including the 18next paragraph) shall be included in all copies or substantial 19portions of the Software. 20 21THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 22EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 23MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 24IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE 25LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 26OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 27WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 28 29**************************************************************************/ 30 31/* 32 * Authors: 33 * Kevin E. Martin <martin@valinux.com> 34 * Gareth Hughes <gareth@valinux.com> 35 * Keith Whitwell <keith@tungstengraphics.com> 36 * 37 */ 38 39#include "glheader.h" 40#include "swrast/swrast.h" 41 42#include "radeon_context.h" 43#include "radeon_ioctl.h" 44#include "radeon_state.h" 45#include "radeon_span.h" 46#include "radeon_tex.h" 47 48#define DBG 0 49 50#define LOCAL_VARS \ 51 radeonContextPtr rmesa = RADEON_CONTEXT(ctx); \ 52 radeonScreenPtr radeonScreen = rmesa->radeonScreen; \ 53 __DRIscreenPrivate *sPriv = rmesa->dri.screen; \ 54 __DRIdrawablePrivate *dPriv = rmesa->dri.drawable; \ 55 GLuint pitch = radeonScreen->frontPitch * radeonScreen->cpp; \ 56 GLuint height = dPriv->h; \ 57 char *buf = (char *)(sPriv->pFB + \ 58 rmesa->state.color.drawOffset + \ 59 (dPriv->x * radeonScreen->cpp) + \ 60 (dPriv->y * pitch)); \ 61 char *read_buf = (char *)(sPriv->pFB + \ 62 rmesa->state.pixel.readOffset + \ 63 (dPriv->x * radeonScreen->cpp) + \ 64 (dPriv->y * pitch)); \ 65 GLuint p; \ 66 (void) read_buf; (void) buf; (void) p 67 68#define LOCAL_DEPTH_VARS \ 69 radeonContextPtr rmesa = RADEON_CONTEXT(ctx); \ 70 radeonScreenPtr radeonScreen = rmesa->radeonScreen; \ 71 __DRIscreenPrivate *sPriv = rmesa->dri.screen; \ 72 __DRIdrawablePrivate *dPriv = rmesa->dri.drawable; \ 73 GLuint height = dPriv->h; \ 74 GLuint xo = dPriv->x; \ 75 GLuint yo = dPriv->y; \ 76 char *buf = (char *)(sPriv->pFB + radeonScreen->depthOffset); \ 77 (void) buf 78 79#define LOCAL_STENCIL_VARS LOCAL_DEPTH_VARS 80 81#define Y_FLIP( _y ) (height - _y - 1) 82 83#define HW_LOCK() 84 85#define HW_UNLOCK() 86 87 88 89/* ================================================================ 90 * Color buffer 91 */ 92 93/* 16 bit, RGB565 color spanline and pixel functions 94 */ 95#define SPANTMP_PIXEL_FMT GL_RGB 96#define SPANTMP_PIXEL_TYPE GL_UNSIGNED_SHORT_5_6_5 97 98#define TAG(x) radeon##x##_RGB565 99#define TAG2(x,y) radeon##x##_RGB565##y 100#include "spantmp2.h" 101 102/* 32 bit, ARGB8888 color spanline and pixel functions 103 */ 104#define SPANTMP_PIXEL_FMT GL_BGRA 105#define SPANTMP_PIXEL_TYPE GL_UNSIGNED_INT_8_8_8_8_REV 106 107#define TAG(x) radeon##x##_ARGB8888 108#define TAG2(x,y) radeon##x##_ARGB8888##y 109#include "spantmp2.h" 110 111 112/* ================================================================ 113 * Depth buffer 114 */ 115 116/* The Radeon family has depth tiling on all the time, so we have to convert 117 * the x,y coordinates into the memory bus address (mba) in the same 118 * manner as the engine. In each case, the linear block address (ba) 119 * is calculated, and then wired with x and y to produce the final 120 * memory address. 121 * The chip will do address translation on its own if the surface registers 122 * are set up correctly. It is not quite enough to get it working with hyperz too... 123 */ 124 125static GLuint radeon_mba_z32( radeonContextPtr rmesa, 126 GLint x, GLint y ) 127{ 128 GLuint pitch = rmesa->radeonScreen->frontPitch; 129 if (rmesa->radeonScreen->depthHasSurface) { 130 return 4*(x + y*pitch); 131 } 132 else { 133 GLuint ba, address = 0; /* a[0..1] = 0 */ 134 135 ba = (y / 16) * (pitch / 16) + (x / 16); 136 137 address |= (x & 0x7) << 2; /* a[2..4] = x[0..2] */ 138 address |= (y & 0x3) << 5; /* a[5..6] = y[0..1] */ 139 address |= 140 (((x & 0x10) >> 2) ^ (y & 0x4)) << 5; /* a[7] = x[4] ^ y[2] */ 141 address |= (ba & 0x3) << 8; /* a[8..9] = ba[0..1] */ 142 143 address |= (y & 0x8) << 7; /* a[10] = y[3] */ 144 address |= 145 (((x & 0x8) << 1) ^ (y & 0x10)) << 7; /* a[11] = x[3] ^ y[4] */ 146 address |= (ba & ~0x3) << 10; /* a[12..] = ba[2..] */ 147 148 return address; 149 } 150} 151 152static __inline GLuint radeon_mba_z16( radeonContextPtr rmesa, GLint x, GLint y ) 153{ 154 GLuint pitch = rmesa->radeonScreen->frontPitch; 155 if (rmesa->radeonScreen->depthHasSurface) { 156 return 2*(x + y*pitch); 157 } 158 else { 159 GLuint ba, address = 0; /* a[0] = 0 */ 160 161 ba = (y / 16) * (pitch / 32) + (x / 32); 162 163 address |= (x & 0x7) << 1; /* a[1..3] = x[0..2] */ 164 address |= (y & 0x7) << 4; /* a[4..6] = y[0..2] */ 165 address |= (x & 0x8) << 4; /* a[7] = x[3] */ 166 address |= (ba & 0x3) << 8; /* a[8..9] = ba[0..1] */ 167 address |= (y & 0x8) << 7; /* a[10] = y[3] */ 168 address |= ((x & 0x10) ^ (y & 0x10)) << 7; /* a[11] = x[4] ^ y[4] */ 169 address |= (ba & ~0x3) << 10; /* a[12..] = ba[2..] */ 170 171 return address; 172 } 173} 174 175 176/* 16-bit depth buffer functions 177 */ 178#define WRITE_DEPTH( _x, _y, d ) \ 179 *(GLushort *)(buf + radeon_mba_z16( rmesa, _x + xo, _y + yo )) = d; 180 181#define READ_DEPTH( d, _x, _y ) \ 182 d = *(GLushort *)(buf + radeon_mba_z16( rmesa, _x + xo, _y + yo )); 183 184#define TAG(x) radeon##x##_16 185#include "depthtmp.h" 186 187/* 24 bit depth, 8 bit stencil depthbuffer functions 188 */ 189#define WRITE_DEPTH( _x, _y, d ) \ 190do { \ 191 GLuint offset = radeon_mba_z32( rmesa, _x + xo, _y + yo ); \ 192 GLuint tmp = *(GLuint *)(buf + offset); \ 193 tmp &= 0xff000000; \ 194 tmp |= ((d) & 0x00ffffff); \ 195 *(GLuint *)(buf + offset) = tmp; \ 196} while (0) 197 198#define READ_DEPTH( d, _x, _y ) \ 199 d = *(GLuint *)(buf + radeon_mba_z32( rmesa, _x + xo, \ 200 _y + yo )) & 0x00ffffff; 201 202#define TAG(x) radeon##x##_24_8 203#include "depthtmp.h" 204 205 206/* ================================================================ 207 * Stencil buffer 208 */ 209 210/* 24 bit depth, 8 bit stencil depthbuffer functions 211 */ 212#define WRITE_STENCIL( _x, _y, d ) \ 213do { \ 214 GLuint offset = radeon_mba_z32( rmesa, _x + xo, _y + yo ); \ 215 GLuint tmp = *(GLuint *)(buf + offset); \ 216 tmp &= 0x00ffffff; \ 217 tmp |= (((d) & 0xff) << 24); \ 218 *(GLuint *)(buf + offset) = tmp; \ 219} while (0) 220 221#define READ_STENCIL( d, _x, _y ) \ 222do { \ 223 GLuint offset = radeon_mba_z32( rmesa, _x + xo, _y + yo ); \ 224 GLuint tmp = *(GLuint *)(buf + offset); \ 225 tmp &= 0xff000000; \ 226 d = tmp >> 24; \ 227} while (0) 228 229#define TAG(x) radeon##x##_24_8 230#include "stenciltmp.h" 231 232 233/* 234 * This function is called to specify which buffer to read and write 235 * for software rasterization (swrast) fallbacks. This doesn't necessarily 236 * correspond to glDrawBuffer() or glReadBuffer() calls. 237 */ 238static void radeonSetBuffer( GLcontext *ctx, 239 GLframebuffer *colorBuffer, 240 GLuint bufferBit ) 241{ 242 radeonContextPtr rmesa = RADEON_CONTEXT(ctx); 243 244 switch ( bufferBit ) { 245 case BUFFER_BIT_FRONT_LEFT: 246 if ( rmesa->sarea->pfCurrentPage == 1 ) { 247 rmesa->state.pixel.readOffset = rmesa->radeonScreen->backOffset; 248 rmesa->state.pixel.readPitch = rmesa->radeonScreen->backPitch; 249 rmesa->state.color.drawOffset = rmesa->radeonScreen->backOffset; 250 rmesa->state.color.drawPitch = rmesa->radeonScreen->backPitch; 251 } else { 252 rmesa->state.pixel.readOffset = rmesa->radeonScreen->frontOffset; 253 rmesa->state.pixel.readPitch = rmesa->radeonScreen->frontPitch; 254 rmesa->state.color.drawOffset = rmesa->radeonScreen->frontOffset; 255 rmesa->state.color.drawPitch = rmesa->radeonScreen->frontPitch; 256 } 257 break; 258 case BUFFER_BIT_BACK_LEFT: 259 if ( rmesa->sarea->pfCurrentPage == 1 ) { 260 rmesa->state.pixel.readOffset = rmesa->radeonScreen->frontOffset; 261 rmesa->state.pixel.readPitch = rmesa->radeonScreen->frontPitch; 262 rmesa->state.color.drawOffset = rmesa->radeonScreen->frontOffset; 263 rmesa->state.color.drawPitch = rmesa->radeonScreen->frontPitch; 264 } else { 265 rmesa->state.pixel.readOffset = rmesa->radeonScreen->backOffset; 266 rmesa->state.pixel.readPitch = rmesa->radeonScreen->backPitch; 267 rmesa->state.color.drawOffset = rmesa->radeonScreen->backOffset; 268 rmesa->state.color.drawPitch = rmesa->radeonScreen->backPitch; 269 } 270 break; 271 default: 272 assert(0); 273 break; 274 } 275} 276 277/* Move locking out to get reasonable span performance (10x better 278 * than doing this in HW_LOCK above). WaitForIdle() is the main 279 * culprit. 280 */ 281 282static void radeonSpanRenderStart( GLcontext *ctx ) 283{ 284 radeonContextPtr rmesa = RADEON_CONTEXT( ctx ); 285 286 RADEON_FIREVERTICES( rmesa ); 287 LOCK_HARDWARE( rmesa ); 288 radeonWaitForIdleLocked( rmesa ); 289} 290 291static void radeonSpanRenderFinish( GLcontext *ctx ) 292{ 293 radeonContextPtr rmesa = RADEON_CONTEXT( ctx ); 294 _swrast_flush( ctx ); 295 UNLOCK_HARDWARE( rmesa ); 296} 297 298void radeonInitSpanFuncs( GLcontext *ctx ) 299{ 300 struct swrast_device_driver *swdd = _swrast_GetDeviceDriverReference(ctx); 301 302 swdd->SetBuffer = radeonSetBuffer; 303 swdd->SpanRenderStart = radeonSpanRenderStart; 304 swdd->SpanRenderFinish = radeonSpanRenderFinish; 305} 306 307 308/** 309 * Plug in the Get/Put routines for the given driRenderbuffer. 310 */ 311void 312radeonSetSpanFunctions(driRenderbuffer *drb, const GLvisual *vis) 313{ 314 if (drb->Base.InternalFormat == GL_RGBA) { 315 if (vis->redBits == 5 && vis->greenBits == 6 && vis->blueBits == 5) { 316 radeonInitPointers_RGB565(&drb->Base); 317 } 318 else { 319 radeonInitPointers_ARGB8888(&drb->Base); 320 } 321 } 322 else if (drb->Base.InternalFormat == GL_DEPTH_COMPONENT16) { 323 drb->Base.GetRow = radeonReadDepthSpan_16; 324 drb->Base.GetValues = radeonReadDepthPixels_16; 325 drb->Base.PutRow = radeonWriteDepthSpan_16; 326 drb->Base.PutMonoRow = radeonWriteMonoDepthSpan_16; 327 drb->Base.PutValues = radeonWriteDepthPixels_16; 328 drb->Base.PutMonoValues = NULL; 329 } 330 else if (drb->Base.InternalFormat == GL_DEPTH_COMPONENT24) { 331 drb->Base.GetRow = radeonReadDepthSpan_24_8; 332 drb->Base.GetValues = radeonReadDepthPixels_24_8; 333 drb->Base.PutRow = radeonWriteDepthSpan_24_8; 334 drb->Base.PutMonoRow = radeonWriteMonoDepthSpan_24_8; 335 drb->Base.PutValues = radeonWriteDepthPixels_24_8; 336 drb->Base.PutMonoValues = NULL; 337 } 338 else if (drb->Base.InternalFormat == GL_STENCIL_INDEX8_EXT) { 339 drb->Base.GetRow = radeonReadStencilSpan_24_8; 340 drb->Base.GetValues = radeonReadStencilPixels_24_8; 341 drb->Base.PutRow = radeonWriteStencilSpan_24_8; 342 drb->Base.PutMonoRow = radeonWriteMonoStencilSpan_24_8; 343 drb->Base.PutValues = radeonWriteStencilPixels_24_8; 344 drb->Base.PutMonoValues = NULL; 345 } 346} 347