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