1 /**************************************************************************
3 Copyright (C) The Weather Channel, Inc. 2002. All Rights Reserved.
4 Copyright 2000, 2001 ATI Technologies Inc., Ontario, Canada, and
5 VA Linux Systems Inc., Fremont, California.
7 The Weather Channel (TM) funded Tungsten Graphics to develop the
8 initial release of the Radeon 8500 driver under the XFree86 license.
9 This notice must be preserved.
13 Permission is hereby granted, free of charge, to any person obtaining
14 a copy of this software and associated documentation files (the
15 "Software"), to deal in the Software without restriction, including
16 without limitation the rights to use, copy, modify, merge, publish,
17 distribute, sublicense, and/or sell copies of the Software, and to
18 permit persons to whom the Software is furnished to do so, subject to
19 the following conditions:
21 The above copyright notice and this permission notice (including the
22 next paragraph) shall be included in all copies or substantial
23 portions of the Software.
25 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
26 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
27 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
28 IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
29 LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
30 OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
31 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
33 **************************************************************************/
37 * Kevin E. Martin <martin@valinux.com>
38 * Gareth Hughes <gareth@valinux.com>
39 * Keith Whitwell <keith@tungstengraphics.com>
43 #include "main/glheader.h"
44 #include "swrast/swrast.h"
46 #include "radeon_common.h"
47 #include "radeon_lock.h"
48 #include "radeon_span.h"
52 static void radeonSetSpanFunctions(struct radeon_renderbuffer
*rrb
);
54 static GLubyte
*radeon_ptr32(const struct radeon_renderbuffer
* rrb
,
57 GLubyte
*ptr
= rrb
->bo
->ptr
;
58 uint32_t mask
= RADEON_BO_FLAGS_MACRO_TILE
| RADEON_BO_FLAGS_MICRO_TILE
;
63 if (rrb
->has_surface
|| !(rrb
->bo
->flags
& mask
)) {
64 offset
= x
* rrb
->cpp
+ y
* rrb
->pitch
;
67 if (rrb
->bo
->flags
& RADEON_BO_FLAGS_MACRO_TILE
) {
68 if (rrb
->bo
->flags
& RADEON_BO_FLAGS_MICRO_TILE
) {
69 nmacroblkpl
= rrb
->pitch
>> 5;
70 offset
+= ((y
>> 4) * nmacroblkpl
) << 11;
71 offset
+= ((y
& 15) >> 1) << 8;
72 offset
+= (y
& 1) << 4;
73 offset
+= (x
>> 5) << 11;
74 offset
+= ((x
& 31) >> 2) << 5;
75 offset
+= (x
& 3) << 2;
77 nmacroblkpl
= rrb
->pitch
>> 6;
78 offset
+= ((y
>> 3) * nmacroblkpl
) << 11;
79 offset
+= (y
& 7) << 8;
80 offset
+= (x
>> 6) << 11;
81 offset
+= ((x
& 63) >> 3) << 5;
82 offset
+= (x
& 7) << 2;
85 nmicroblkpl
= ((rrb
->pitch
+ 31) & ~31) >> 5;
86 offset
+= (y
* nmicroblkpl
) << 5;
87 offset
+= (x
>> 3) << 5;
88 offset
+= (x
& 7) << 2;
94 static GLubyte
*radeon_ptr16(const struct radeon_renderbuffer
* rrb
,
97 GLubyte
*ptr
= rrb
->bo
->ptr
;
98 uint32_t mask
= RADEON_BO_FLAGS_MACRO_TILE
| RADEON_BO_FLAGS_MICRO_TILE
;
103 if (rrb
->has_surface
|| !(rrb
->bo
->flags
& mask
)) {
104 offset
= x
* rrb
->cpp
+ y
* rrb
->pitch
;
107 if (rrb
->bo
->flags
& RADEON_BO_FLAGS_MACRO_TILE
) {
108 if (rrb
->bo
->flags
& RADEON_BO_FLAGS_MICRO_TILE
) {
109 nmacroblkpl
= rrb
->pitch
>> 6;
110 offset
+= ((y
>> 4) * nmacroblkpl
) << 11;
111 offset
+= ((y
& 15) >> 1) << 8;
112 offset
+= (y
& 1) << 4;
113 offset
+= (x
>> 6) << 11;
114 offset
+= ((x
& 63) >> 3) << 5;
115 offset
+= (x
& 7) << 1;
117 nmacroblkpl
= rrb
->pitch
>> 7;
118 offset
+= ((y
>> 3) * nmacroblkpl
) << 11;
119 offset
+= (y
& 7) << 8;
120 offset
+= (x
>> 7) << 11;
121 offset
+= ((x
& 127) >> 4) << 5;
122 offset
+= (x
& 15) << 2;
125 nmicroblkpl
= ((rrb
->pitch
+ 31) & ~31) >> 5;
126 offset
+= (y
* nmicroblkpl
) << 5;
127 offset
+= (x
>> 4) << 5;
128 offset
+= (x
& 15) << 2;
134 static GLubyte
*radeon_ptr(const struct radeon_renderbuffer
* rrb
,
137 GLubyte
*ptr
= rrb
->bo
->ptr
;
138 uint32_t mask
= RADEON_BO_FLAGS_MACRO_TILE
| RADEON_BO_FLAGS_MICRO_TILE
;
145 if (rrb
->has_surface
|| !(rrb
->bo
->flags
& mask
)) {
146 offset
= x
* rrb
->cpp
+ y
* rrb
->pitch
;
149 if (rrb
->bo
->flags
& RADEON_BO_FLAGS_MACRO_TILE
) {
150 if (rrb
->bo
->flags
& RADEON_BO_FLAGS_MICRO_TILE
) {
151 microblkxs
= 16 / rrb
->cpp
;
152 macroblkxs
= 128 / rrb
->cpp
;
153 nmacroblkpl
= rrb
->pitch
/ macroblkxs
;
154 offset
+= ((y
>> 4) * nmacroblkpl
) << 11;
155 offset
+= ((y
& 15) >> 1) << 8;
156 offset
+= (y
& 1) << 4;
157 offset
+= (x
/ macroblkxs
) << 11;
158 offset
+= ((x
& (macroblkxs
- 1)) / microblkxs
) << 5;
159 offset
+= (x
& (microblkxs
- 1)) * rrb
->cpp
;
161 microblkxs
= 32 / rrb
->cpp
;
162 macroblkxs
= 256 / rrb
->cpp
;
163 nmacroblkpl
= rrb
->pitch
/ macroblkxs
;
164 offset
+= ((y
>> 3) * nmacroblkpl
) << 11;
165 offset
+= (y
& 7) << 8;
166 offset
+= (x
/ macroblkxs
) << 11;
167 offset
+= ((x
& (macroblkxs
- 1)) / microblkxs
) << 5;
168 offset
+= (x
& (microblkxs
- 1)) * rrb
->cpp
;
171 microblkxs
= 32 / rrb
->cpp
;
172 nmicroblkpl
= ((rrb
->pitch
+ 31) & ~31) >> 5;
173 offset
+= (y
* nmicroblkpl
) << 5;
174 offset
+= (x
/ microblkxs
) << 5;
175 offset
+= (x
& (microblkxs
- 1)) * rrb
->cpp
;
183 z24s8_to_s8z24(uint32_t val
)
185 return (val
<< 24) | (val
>> 8);
189 s8z24_to_z24s8(uint32_t val
)
191 return (val
>> 24) | (val
<< 8);
196 * Note that all information needed to access pixels in a renderbuffer
197 * should be obtained through the gl_renderbuffer parameter, not per-context
201 struct radeon_context *radeon = RADEON_CONTEXT(ctx); \
202 struct radeon_renderbuffer *rrb = (void *) rb; \
203 const GLint yScale = ctx->DrawBuffer->Name ? 1 : -1; \
204 const GLint yBias = ctx->DrawBuffer->Name ? 0 : rrb->base.Height - 1;\
205 unsigned int num_cliprects; \
206 struct drm_clip_rect *cliprects; \
210 radeon_get_cliprects(radeon, &cliprects, &num_cliprects, &x_off, &y_off);
212 #define LOCAL_DEPTH_VARS \
213 struct radeon_context *radeon = RADEON_CONTEXT(ctx); \
214 struct radeon_renderbuffer *rrb = (void *) rb; \
215 const GLint yScale = ctx->DrawBuffer->Name ? 1 : -1; \
216 const GLint yBias = ctx->DrawBuffer->Name ? 0 : rrb->base.Height - 1;\
217 unsigned int num_cliprects; \
218 struct drm_clip_rect *cliprects; \
220 radeon_get_cliprects(radeon, &cliprects, &num_cliprects, &x_off, &y_off);
222 #define LOCAL_STENCIL_VARS LOCAL_DEPTH_VARS
224 #define Y_FLIP(_y) ((_y) * yScale + yBias)
230 /* XXX FBO: this is identical to the macro in spantmp2.h except we get
231 * the cliprect info from the context, not the driDrawable.
232 * Move this into spantmp2.h someday.
234 #define HW_CLIPLOOP() \
236 int _nc = num_cliprects; \
238 int minx = cliprects[_nc].x1 - x_off; \
239 int miny = cliprects[_nc].y1 - y_off; \
240 int maxx = cliprects[_nc].x2 - x_off; \
241 int maxy = cliprects[_nc].y2 - y_off;
243 /* ================================================================
247 /* 16 bit, RGB565 color spanline and pixel functions
249 #define SPANTMP_PIXEL_FMT GL_RGB
250 #define SPANTMP_PIXEL_TYPE GL_UNSIGNED_SHORT_5_6_5
252 #define TAG(x) radeon##x##_RGB565
253 #define TAG2(x,y) radeon##x##_RGB565##y
254 #define GET_PTR(X,Y) radeon_ptr16(rrb, (X) + x_off, (Y) + y_off)
255 #include "spantmp2.h"
257 /* 32 bit, xRGB8888 color spanline and pixel functions
259 #define SPANTMP_PIXEL_FMT GL_BGRA
260 #define SPANTMP_PIXEL_TYPE GL_UNSIGNED_INT_8_8_8_8_REV
262 #define TAG(x) radeon##x##_xRGB8888
263 #define TAG2(x,y) radeon##x##_xRGB8888##y
264 #define GET_VALUE(_x, _y) ((*(GLuint*)(radeon_ptr32(rrb, _x + x_off, _y + y_off)) | 0xff000000))
265 #define PUT_VALUE(_x, _y, d) { \
266 GLuint *_ptr = (GLuint*)radeon_ptr32( rrb, _x + x_off, _y + y_off ); \
269 #include "spantmp2.h"
271 /* 32 bit, ARGB8888 color spanline and pixel functions
273 #define SPANTMP_PIXEL_FMT GL_BGRA
274 #define SPANTMP_PIXEL_TYPE GL_UNSIGNED_INT_8_8_8_8_REV
276 #define TAG(x) radeon##x##_ARGB8888
277 #define TAG2(x,y) radeon##x##_ARGB8888##y
278 #define GET_PTR(X,Y) radeon_ptr32(rrb, (X) + x_off, (Y) + y_off)
279 #include "spantmp2.h"
281 /* ================================================================
285 /* The Radeon family has depth tiling on all the time, so we have to convert
286 * the x,y coordinates into the memory bus address (mba) in the same
287 * manner as the engine. In each case, the linear block address (ba)
288 * is calculated, and then wired with x and y to produce the final
290 * The chip will do address translation on its own if the surface registers
291 * are set up correctly. It is not quite enough to get it working with hyperz
295 /* 16-bit depth buffer functions
297 #define VALUE_TYPE GLushort
299 #define WRITE_DEPTH( _x, _y, d ) \
300 *(GLushort *)radeon_ptr(rrb, _x + x_off, _y + y_off) = d
302 #define READ_DEPTH( d, _x, _y ) \
303 d = *(GLushort *)radeon_ptr(rrb, _x + x_off, _y + y_off)
305 #define TAG(x) radeon##x##_z16
306 #include "depthtmp.h"
310 * Careful: It looks like the R300 uses ZZZS byte order while the R200
311 * uses SZZZ for 24 bit depth, 8 bit stencil mode.
313 #define VALUE_TYPE GLuint
316 #define WRITE_DEPTH( _x, _y, d ) \
318 GLuint *_ptr = (GLuint*)radeon_ptr32( rrb, _x + x_off, _y + y_off ); \
319 GLuint tmp = *_ptr; \
321 tmp |= ((d << 8) & 0xffffff00); \
325 #define WRITE_DEPTH( _x, _y, d ) \
327 GLuint *_ptr = (GLuint*)radeon_ptr32( rrb, _x + x_off, _y + y_off ); \
328 GLuint tmp = *_ptr; \
330 tmp |= ((d) & 0x00ffffff); \
336 #define READ_DEPTH( d, _x, _y ) \
338 d = (*(GLuint*)(radeon_ptr32(rrb, _x + x_off, _y + y_off)) & 0xffffff00) >> 8; \
341 #define READ_DEPTH( d, _x, _y ) \
342 d = *(GLuint*)(radeon_ptr32(rrb, _x + x_off, _y + y_off)) & 0x00ffffff;
345 fprintf(stderr, "dval(%d, %d, %d, %d)=0x%08X\n", _x, xo, _y, yo, d);\
346 d = *(GLuint*)(radeon_ptr(rrb, _x, _y )) & 0x00ffffff;
348 #define TAG(x) radeon##x##_z24
349 #include "depthtmp.h"
351 /* 24 bit depth, 8 bit stencil depthbuffer functions
354 * Careful: It looks like the R300 uses ZZZS byte order while the R200
355 * uses SZZZ for 24 bit depth, 8 bit stencil mode.
357 #define VALUE_TYPE GLuint
360 #define WRITE_DEPTH( _x, _y, d ) \
362 GLuint *_ptr = (GLuint*)radeon_ptr32( rrb, _x + x_off, _y + y_off ); \
366 #define WRITE_DEPTH( _x, _y, d ) \
368 GLuint *_ptr = (GLuint*)radeon_ptr32( rrb, _x + x_off, _y + y_off ); \
369 GLuint tmp = z24s8_to_s8z24(d); \
375 #define READ_DEPTH( d, _x, _y ) \
377 d = (*(GLuint*)(radeon_ptr32(rrb, _x + x_off, _y + y_off))); \
380 #define READ_DEPTH( d, _x, _y ) do { \
381 d = s8z24_to_z24s8(*(GLuint*)(radeon_ptr32(rrb, _x + x_off, _y + y_off ))); \
385 fprintf(stderr, "dval(%d, %d, %d, %d)=0x%08X\n", _x, xo, _y, yo, d);\
386 d = *(GLuint*)(radeon_ptr(rrb, _x, _y )) & 0x00ffffff;
388 #define TAG(x) radeon##x##_z24_s8
389 #include "depthtmp.h"
391 /* ================================================================
395 /* 24 bit depth, 8 bit stencil depthbuffer functions
398 #define WRITE_STENCIL( _x, _y, d ) \
400 GLuint *_ptr = (GLuint*)radeon_ptr32(rrb, _x + x_off, _y + y_off); \
401 GLuint tmp = *_ptr; \
407 #define WRITE_STENCIL( _x, _y, d ) \
409 GLuint *_ptr = (GLuint*)radeon_ptr32(rrb, _x + x_off, _y + y_off); \
410 GLuint tmp = *_ptr; \
412 tmp |= (((d) & 0xff) << 24); \
418 #define READ_STENCIL( d, _x, _y ) \
420 GLuint *_ptr = (GLuint*)radeon_ptr32( rrb, _x + x_off, _y + y_off ); \
421 GLuint tmp = *_ptr; \
422 d = tmp & 0x000000ff; \
425 #define READ_STENCIL( d, _x, _y ) \
427 GLuint *_ptr = (GLuint*)radeon_ptr32( rrb, _x + x_off, _y + y_off ); \
428 GLuint tmp = *_ptr; \
429 d = (tmp & 0xff000000) >> 24; \
433 #define TAG(x) radeon##x##_z24_s8
434 #include "stenciltmp.h"
437 static void map_unmap_rb(struct gl_renderbuffer
*rb
, int flag
)
439 struct radeon_renderbuffer
*rrb
= radeon_renderbuffer(rb
);
442 if (rrb
== NULL
|| !rrb
->bo
)
446 r
= radeon_bo_map(rrb
->bo
, 1);
448 fprintf(stderr
, "(%s) error(%d) mapping buffer.\n",
452 radeonSetSpanFunctions(rrb
);
454 radeon_bo_unmap(rrb
->bo
);
461 radeon_map_unmap_buffers(GLcontext
*ctx
, GLboolean map
)
465 /* color draw buffers */
466 for (j
= 0; j
< ctx
->DrawBuffer
->_NumColorDrawBuffers
; j
++)
467 map_unmap_rb(ctx
->DrawBuffer
->_ColorDrawBuffers
[j
], map
);
469 /* check for render to textures */
470 for (i
= 0; i
< BUFFER_COUNT
; i
++) {
471 struct gl_renderbuffer_attachment
*att
=
472 ctx
->DrawBuffer
->Attachment
+ i
;
473 struct gl_texture_object
*tex
= att
->Texture
;
475 /* render to texture */
476 ASSERT(att
->Renderbuffer
);
478 ctx
->Driver
.MapTexture(ctx
, tex
);
480 ctx
->Driver
.UnmapTexture(ctx
, tex
);
484 map_unmap_rb(ctx
->ReadBuffer
->_ColorReadBuffer
, map
);
486 /* depth buffer (Note wrapper!) */
487 if (ctx
->DrawBuffer
->_DepthBuffer
)
488 map_unmap_rb(ctx
->DrawBuffer
->_DepthBuffer
->Wrapped
, map
);
490 if (ctx
->DrawBuffer
->_StencilBuffer
)
491 map_unmap_rb(ctx
->DrawBuffer
->_StencilBuffer
->Wrapped
, map
);
494 static void radeonSpanRenderStart(GLcontext
* ctx
)
496 radeonContextPtr rmesa
= RADEON_CONTEXT(ctx
);
499 radeon_firevertices(rmesa
);
501 /* The locking and wait for idle should really only be needed in classic mode.
502 * In a future memory manager based implementation, this should become
503 * unnecessary due to the fact that mapping our buffers, textures, etc.
504 * should implicitly wait for any previous rendering commands that must
506 if (!rmesa
->radeonScreen
->driScreen
->dri2
.enabled
) {
507 LOCK_HARDWARE(rmesa
);
508 radeonWaitForIdleLocked(rmesa
);
510 for (i
= 0; i
< ctx
->Const
.MaxTextureImageUnits
; i
++) {
511 if (ctx
->Texture
.Unit
[i
]._ReallyEnabled
)
512 ctx
->Driver
.MapTexture(ctx
, ctx
->Texture
.Unit
[i
]._Current
);
515 radeon_map_unmap_buffers(ctx
, 1);
521 static void radeonSpanRenderFinish(GLcontext
* ctx
)
523 radeonContextPtr rmesa
= RADEON_CONTEXT(ctx
);
526 if (!rmesa
->radeonScreen
->driScreen
->dri2
.enabled
) {
527 UNLOCK_HARDWARE(rmesa
);
529 for (i
= 0; i
< ctx
->Const
.MaxTextureImageUnits
; i
++) {
530 if (ctx
->Texture
.Unit
[i
]._ReallyEnabled
)
531 ctx
->Driver
.UnmapTexture(ctx
, ctx
->Texture
.Unit
[i
]._Current
);
534 radeon_map_unmap_buffers(ctx
, 0);
537 void radeonInitSpanFuncs(GLcontext
* ctx
)
539 struct swrast_device_driver
*swdd
=
540 _swrast_GetDeviceDriverReference(ctx
);
541 swdd
->SpanRenderStart
= radeonSpanRenderStart
;
542 swdd
->SpanRenderFinish
= radeonSpanRenderFinish
;
546 * Plug in the Get/Put routines for the given driRenderbuffer.
548 static void radeonSetSpanFunctions(struct radeon_renderbuffer
*rrb
)
550 if (rrb
->base
._ActualFormat
== GL_RGB5
) {
551 radeonInitPointers_RGB565(&rrb
->base
);
552 } else if (rrb
->base
._ActualFormat
== GL_RGB8
) {
553 radeonInitPointers_xRGB8888(&rrb
->base
);
554 } else if (rrb
->base
._ActualFormat
== GL_RGBA8
) {
555 radeonInitPointers_ARGB8888(&rrb
->base
);
556 } else if (rrb
->base
._ActualFormat
== GL_DEPTH_COMPONENT16
) {
557 radeonInitDepthPointers_z16(&rrb
->base
);
558 } else if (rrb
->base
._ActualFormat
== GL_DEPTH_COMPONENT24
) {
559 radeonInitDepthPointers_z24(&rrb
->base
);
560 } else if (rrb
->base
._ActualFormat
== GL_DEPTH24_STENCIL8_EXT
) {
561 radeonInitDepthPointers_z24_s8(&rrb
->base
);
562 } else if (rrb
->base
._ActualFormat
== GL_STENCIL_INDEX8_EXT
) {
563 radeonInitStencilPointers_z24_s8(&rrb
->base
);