1 /* $XFree86: xc/lib/GL/mesa/src/drv/radeon/radeon_span.c,v 1.6 2002/10/30 12:51:56 alanh Exp $ */
2 /**************************************************************************
4 Copyright 2000, 2001 ATI Technologies Inc., Ontario, Canada, and
5 VA Linux Systems Inc., Fremont, California.
9 Permission is hereby granted, free of charge, to any person obtaining
10 a copy of this software and associated documentation files (the
11 "Software"), to deal in the Software without restriction, including
12 without limitation the rights to use, copy, modify, merge, publish,
13 distribute, sublicense, and/or sell copies of the Software, and to
14 permit persons to whom the Software is furnished to do so, subject to
15 the following conditions:
17 The above copyright notice and this permission notice (including the
18 next paragraph) shall be included in all copies or substantial
19 portions of the Software.
21 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
24 IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
25 LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
26 OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
27 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29 **************************************************************************/
33 * Kevin E. Martin <martin@valinux.com>
34 * Gareth Hughes <gareth@valinux.com>
35 * Keith Whitwell <keith@tungstengraphics.com>
40 #include "swrast/swrast.h"
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"
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)); \
66 (void) read_buf; (void) buf; (void) p
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); \
79 #define LOCAL_STENCIL_VARS LOCAL_DEPTH_VARS
81 #define Y_FLIP( _y ) (height - _y - 1)
89 /* ================================================================
93 /* 16 bit, RGB565 color spanline and pixel functions
95 #define SPANTMP_PIXEL_FMT GL_RGB
96 #define SPANTMP_PIXEL_TYPE GL_UNSIGNED_SHORT_5_6_5
98 #define TAG(x) radeon##x##_RGB565
99 #define TAG2(x,y) radeon##x##_RGB565##y
100 #include "spantmp2.h"
102 /* 32 bit, ARGB8888 color spanline and pixel functions
104 #define SPANTMP_PIXEL_FMT GL_BGRA
105 #define SPANTMP_PIXEL_TYPE GL_UNSIGNED_INT_8_8_8_8_REV
107 #define TAG(x) radeon##x##_ARGB8888
108 #define TAG2(x,y) radeon##x##_ARGB8888##y
109 #include "spantmp2.h"
112 /* ================================================================
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
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...
125 static GLuint
radeon_mba_z32( radeonContextPtr rmesa
,
128 GLuint pitch
= rmesa
->radeonScreen
->frontPitch
;
129 if (rmesa
->radeonScreen
->depthHasSurface
) {
130 return 4*(x
+ y
*pitch
);
133 GLuint ba
, address
= 0; /* a[0..1] = 0 */
135 ba
= (y
/ 16) * (pitch
/ 16) + (x
/ 16);
137 address
|= (x
& 0x7) << 2; /* a[2..4] = x[0..2] */
138 address
|= (y
& 0x3) << 5; /* a[5..6] = y[0..1] */
140 (((x
& 0x10) >> 2) ^ (y
& 0x4)) << 5; /* a[7] = x[4] ^ y[2] */
141 address
|= (ba
& 0x3) << 8; /* a[8..9] = ba[0..1] */
143 address
|= (y
& 0x8) << 7; /* a[10] = y[3] */
145 (((x
& 0x8) << 1) ^ (y
& 0x10)) << 7; /* a[11] = x[3] ^ y[4] */
146 address
|= (ba
& ~0x3) << 10; /* a[12..] = ba[2..] */
152 static __inline GLuint
radeon_mba_z16( radeonContextPtr rmesa
, GLint x
, GLint y
)
154 GLuint pitch
= rmesa
->radeonScreen
->frontPitch
;
155 if (rmesa
->radeonScreen
->depthHasSurface
) {
156 return 2*(x
+ y
*pitch
);
159 GLuint ba
, address
= 0; /* a[0] = 0 */
161 ba
= (y
/ 16) * (pitch
/ 32) + (x
/ 32);
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..] */
176 /* 16-bit depth buffer functions
178 #define WRITE_DEPTH( _x, _y, d ) \
179 *(GLushort *)(buf + radeon_mba_z16( rmesa, _x + xo, _y + yo )) = d;
181 #define READ_DEPTH( d, _x, _y ) \
182 d = *(GLushort *)(buf + radeon_mba_z16( rmesa, _x + xo, _y + yo ));
184 #define TAG(x) radeon##x##_16
185 #include "depthtmp.h"
187 /* 24 bit depth, 8 bit stencil depthbuffer functions
189 #define WRITE_DEPTH( _x, _y, d ) \
191 GLuint offset = radeon_mba_z32( rmesa, _x + xo, _y + yo ); \
192 GLuint tmp = *(GLuint *)(buf + offset); \
194 tmp |= ((d) & 0x00ffffff); \
195 *(GLuint *)(buf + offset) = tmp; \
198 #define READ_DEPTH( d, _x, _y ) \
199 d = *(GLuint *)(buf + radeon_mba_z32( rmesa, _x + xo, \
200 _y + yo )) & 0x00ffffff;
202 #define TAG(x) radeon##x##_24_8
203 #include "depthtmp.h"
206 /* ================================================================
210 /* 24 bit depth, 8 bit stencil depthbuffer functions
212 #define WRITE_STENCIL( _x, _y, d ) \
214 GLuint offset = radeon_mba_z32( rmesa, _x + xo, _y + yo ); \
215 GLuint tmp = *(GLuint *)(buf + offset); \
217 tmp |= (((d) & 0xff) << 24); \
218 *(GLuint *)(buf + offset) = tmp; \
221 #define READ_STENCIL( d, _x, _y ) \
223 GLuint offset = radeon_mba_z32( rmesa, _x + xo, _y + yo ); \
224 GLuint tmp = *(GLuint *)(buf + offset); \
229 #define TAG(x) radeon##x##_24_8
230 #include "stenciltmp.h"
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.
238 static void radeonSetBuffer( GLcontext
*ctx
,
239 GLframebuffer
*colorBuffer
,
242 radeonContextPtr rmesa
= RADEON_CONTEXT(ctx
);
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
;
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
;
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
;
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
;
277 /* Move locking out to get reasonable span performance (10x better
278 * than doing this in HW_LOCK above). WaitForIdle() is the main
282 static void radeonSpanRenderStart( GLcontext
*ctx
)
284 radeonContextPtr rmesa
= RADEON_CONTEXT( ctx
);
286 RADEON_FIREVERTICES( rmesa
);
287 LOCK_HARDWARE( rmesa
);
288 radeonWaitForIdleLocked( rmesa
);
291 static void radeonSpanRenderFinish( GLcontext
*ctx
)
293 radeonContextPtr rmesa
= RADEON_CONTEXT( ctx
);
294 _swrast_flush( ctx
);
295 UNLOCK_HARDWARE( rmesa
);
298 void radeonInitSpanFuncs( GLcontext
*ctx
)
300 struct swrast_device_driver
*swdd
= _swrast_GetDeviceDriverReference(ctx
);
302 swdd
->SetBuffer
= radeonSetBuffer
;
303 swdd
->SpanRenderStart
= radeonSpanRenderStart
;
304 swdd
->SpanRenderFinish
= radeonSpanRenderFinish
;
309 * Plug in the Get/Put routines for the given driRenderbuffer.
312 radeonSetSpanFunctions(driRenderbuffer
*drb
, const GLvisual
*vis
)
314 if (drb
->Base
.InternalFormat
== GL_RGBA
) {
315 if (vis
->redBits
== 5 && vis
->greenBits
== 6 && vis
->blueBits
== 5) {
316 radeonInitPointers_RGB565(&drb
->Base
);
319 radeonInitPointers_ARGB8888(&drb
->Base
);
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
;
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
;
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
;