2 Copyright (C) The Weather Channel, Inc. 2002. All Rights Reserved.
4 The Weather Channel (TM) funded Tungsten Graphics to develop the
5 initial release of the Radeon 8500 driver under the XFree86 license.
6 This notice must be preserved.
8 Permission is hereby granted, free of charge, to any person obtaining
9 a copy of this software and associated documentation files (the
10 "Software"), to deal in the Software without restriction, including
11 without limitation the rights to use, copy, modify, merge, publish,
12 distribute, sublicense, and/or sell copies of the Software, and to
13 permit persons to whom the Software is furnished to do so, subject to
14 the following conditions:
16 The above copyright notice and this permission notice (including the
17 next paragraph) shall be included in all copies or substantial
18 portions of the Software.
20 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
23 IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
24 LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28 **************************************************************************/
32 * Keith Whitwell <keith@tungstengraphics.com>
38 #include "main/glheader.h"
39 #include "main/imports.h"
40 #include "main/macros.h"
41 #include "main/context.h"
42 #include "swrast/swrast.h"
44 #include "radeon_common.h"
45 #include "radeon_lock.h"
46 #include "r200_context.h"
47 #include "r200_state.h"
48 #include "r200_ioctl.h"
50 #include "r200_sanity.h"
51 #include "radeon_reg.h"
53 #include "drirenderbuffer.h"
56 #define R200_TIMEOUT 512
57 #define R200_IDLE_RETRY 16
59 static void r200UserClear(GLcontext
*ctx
, GLuint flags
)
61 if (flags
& (RADEON_FRONT
| RADEON_BACK
)) {
66 if ((flags
& (RADEON_DEPTH
| RADEON_STENCIL
))
67 && (flags
& RADEON_CLEAR_FASTZ
)) {
73 static void r200KernelClear(GLcontext
*ctx
, GLuint flags
)
75 r200ContextPtr rmesa
= R200_CONTEXT(ctx
);
76 __DRIdrawablePrivate
*dPriv
= rmesa
->radeon
.dri
.drawable
;
77 GLint cx
, cy
, cw
, ch
, ret
;
80 LOCK_HARDWARE( &rmesa
->radeon
);
82 /* Throttle the number of clear ioctls we do.
85 drm_radeon_getparam_t gp
;
89 gp
.param
= RADEON_PARAM_LAST_CLEAR
;
90 gp
.value
= (int *)&clear
;
91 ret
= drmCommandWriteRead( rmesa
->radeon
.dri
.fd
,
92 DRM_RADEON_GETPARAM
, &gp
, sizeof(gp
) );
95 fprintf( stderr
, "%s: drmRadeonGetParam: %d\n", __FUNCTION__
, ret
);
99 /* Clear throttling needs more thought.
101 if ( rmesa
->radeon
.sarea
->last_clear
- clear
<= 25 ) {
105 if (rmesa
->radeon
.do_usleeps
) {
106 UNLOCK_HARDWARE( &rmesa
->radeon
);
108 LOCK_HARDWARE( &rmesa
->radeon
);
112 /* Send current state to the hardware */
113 rcommonFlushCmdBufLocked( &rmesa
->radeon
, __FUNCTION__
);
116 /* compute region after locking: */
117 cx
= ctx
->DrawBuffer
->_Xmin
;
118 cy
= ctx
->DrawBuffer
->_Ymin
;
119 cw
= ctx
->DrawBuffer
->_Xmax
- cx
;
120 ch
= ctx
->DrawBuffer
->_Ymax
- cy
;
122 /* Flip top to bottom */
124 cy
= dPriv
->y
+ dPriv
->h
- cy
- ch
;
125 for ( i
= 0 ; i
< dPriv
->numClipRects
; ) {
126 GLint nr
= MIN2( i
+ RADEON_NR_SAREA_CLIPRECTS
, dPriv
->numClipRects
);
127 drm_clip_rect_t
*box
= dPriv
->pClipRects
;
128 drm_clip_rect_t
*b
= rmesa
->radeon
.sarea
->boxes
;
129 drm_radeon_clear_t clear
;
130 drm_radeon_clear_rect_t depth_boxes
[RADEON_NR_SAREA_CLIPRECTS
];
133 if (cw
!= dPriv
->w
|| ch
!= dPriv
->h
) {
134 /* clear subregion */
135 for ( ; i
< nr
; i
++ ) {
138 GLint w
= box
[i
].x2
- x
;
139 GLint h
= box
[i
].y2
- y
;
141 if ( x
< cx
) w
-= cx
- x
, x
= cx
;
142 if ( y
< cy
) h
-= cy
- y
, y
= cy
;
143 if ( x
+ w
> cx
+ cw
) w
= cx
+ cw
- x
;
144 if ( y
+ h
> cy
+ ch
) h
= cy
+ ch
- y
;
145 if ( w
<= 0 ) continue;
146 if ( h
<= 0 ) continue;
156 /* clear whole window */
157 for ( ; i
< nr
; i
++ ) {
163 rmesa
->radeon
.sarea
->nbox
= n
;
166 clear
.clear_color
= rmesa
->radeon
.state
.color
.clear
;
167 clear
.clear_depth
= rmesa
->radeon
.state
.depth
.clear
; /* needed for hyperz */
168 clear
.color_mask
= rmesa
->hw
.msk
.cmd
[MSK_RB3D_PLANEMASK
];
169 clear
.depth_mask
= rmesa
->radeon
.state
.stencil
.clear
;
170 clear
.depth_boxes
= depth_boxes
;
173 b
= rmesa
->radeon
.sarea
->boxes
;
174 for ( ; n
>= 0 ; n
-- ) {
175 depth_boxes
[n
].f
[CLEAR_X1
] = (float)b
[n
].x1
;
176 depth_boxes
[n
].f
[CLEAR_Y1
] = (float)b
[n
].y1
;
177 depth_boxes
[n
].f
[CLEAR_X2
] = (float)b
[n
].x2
;
178 depth_boxes
[n
].f
[CLEAR_Y2
] = (float)b
[n
].y2
;
179 depth_boxes
[n
].f
[CLEAR_DEPTH
] = ctx
->Depth
.Clear
;
182 ret
= drmCommandWrite( rmesa
->radeon
.dri
.fd
, DRM_RADEON_CLEAR
,
183 &clear
, sizeof(clear
));
187 UNLOCK_HARDWARE( &rmesa
->radeon
);
188 fprintf( stderr
, "DRM_RADEON_CLEAR: return = %d\n", ret
);
192 UNLOCK_HARDWARE( &rmesa
->radeon
);
194 /* ================================================================
197 static void r200Clear( GLcontext
*ctx
, GLbitfield mask
)
199 r200ContextPtr rmesa
= R200_CONTEXT(ctx
);
200 __DRIdrawablePrivate
*dPriv
= rmesa
->radeon
.dri
.drawable
;
202 GLuint color_mask
= 0;
205 if ( R200_DEBUG
& DEBUG_IOCTL
) {
206 fprintf( stderr
, "r200Clear %x %d\n", mask
, rmesa
->radeon
.sarea
->pfCurrentPage
);
210 LOCK_HARDWARE( &rmesa
->radeon
);
211 UNLOCK_HARDWARE( &rmesa
->radeon
);
212 if ( dPriv
->numClipRects
== 0 )
218 if ( mask
& BUFFER_BIT_FRONT_LEFT
) {
219 flags
|= RADEON_FRONT
;
220 color_mask
= rmesa
->hw
.msk
.cmd
[MSK_RB3D_PLANEMASK
];
221 mask
&= ~BUFFER_BIT_FRONT_LEFT
;
224 if ( mask
& BUFFER_BIT_BACK_LEFT
) {
225 flags
|= RADEON_BACK
;
226 color_mask
= rmesa
->hw
.msk
.cmd
[MSK_RB3D_PLANEMASK
];
227 mask
&= ~BUFFER_BIT_BACK_LEFT
;
230 if ( mask
& BUFFER_BIT_DEPTH
) {
231 flags
|= RADEON_DEPTH
;
232 mask
&= ~BUFFER_BIT_DEPTH
;
235 if ( (mask
& BUFFER_BIT_STENCIL
) && rmesa
->radeon
.state
.stencil
.hwBuffer
) {
236 flags
|= RADEON_STENCIL
;
237 mask
&= ~BUFFER_BIT_STENCIL
;
241 if (R200_DEBUG
& DEBUG_FALLBACKS
)
242 fprintf(stderr
, "%s: swrast clear, mask: %x\n", __FUNCTION__
, mask
);
243 _swrast_Clear( ctx
, mask
);
249 if (rmesa
->using_hyperz
) {
250 flags
|= RADEON_USE_COMP_ZBUF
;
251 /* if (rmesa->radeon.radeonScreen->chip_family == CHIP_FAMILY_R200)
252 flags |= RADEON_USE_HIERZ; */
253 if (!(rmesa
->radeon
.state
.stencil
.hwBuffer
) ||
254 ((flags
& RADEON_DEPTH
) && (flags
& RADEON_STENCIL
) &&
255 ((rmesa
->radeon
.state
.stencil
.clear
& R200_STENCIL_WRITE_MASK
) == R200_STENCIL_WRITE_MASK
))) {
256 flags
|= RADEON_CLEAR_FASTZ
;
260 if (rmesa
->radeon
.radeonScreen
->kernel_mm
)
261 r200UserClear(ctx
, flags
);
263 r200KernelClear(ctx
, flags
);
265 rmesa
->radeon
.hw
.all_dirty
= GL_TRUE
;
268 /* This version of AllocateMemoryMESA allocates only GART memory, and
269 * only does so after the point at which the driver has been
272 * Theoretically a valid context isn't required. However, in this
273 * implementation, it is, as I'm using the hardware lock to protect
274 * the kernel data structures, and the current context to get the
277 void *r200AllocateMemoryMESA(__DRIscreen
*screen
, GLsizei size
,
278 GLfloat readfreq
, GLfloat writefreq
,
281 GET_CURRENT_CONTEXT(ctx
);
282 r200ContextPtr rmesa
;
284 drm_radeon_mem_alloc_t alloc
;
287 if (R200_DEBUG
& DEBUG_IOCTL
)
288 fprintf(stderr
, "%s sz %d %f/%f/%f\n", __FUNCTION__
, size
, readfreq
,
289 writefreq
, priority
);
291 if (!ctx
|| !(rmesa
= R200_CONTEXT(ctx
)) || !rmesa
->radeon
.radeonScreen
->gartTextures
.map
)
294 if (getenv("R200_NO_ALLOC"))
297 alloc
.region
= RADEON_MEM_REGION_GART
;
300 alloc
.region_offset
= ®ion_offset
;
302 ret
= drmCommandWriteRead( rmesa
->radeon
.radeonScreen
->driScreen
->fd
,
304 &alloc
, sizeof(alloc
));
307 fprintf(stderr
, "%s: DRM_RADEON_ALLOC ret %d\n", __FUNCTION__
, ret
);
312 char *region_start
= (char *)rmesa
->radeon
.radeonScreen
->gartTextures
.map
;
313 return (void *)(region_start
+ region_offset
);
318 /* Called via glXFreeMemoryMESA() */
319 void r200FreeMemoryMESA(__DRIscreen
*screen
, GLvoid
*pointer
)
321 GET_CURRENT_CONTEXT(ctx
);
322 r200ContextPtr rmesa
;
323 ptrdiff_t region_offset
;
324 drm_radeon_mem_free_t memfree
;
327 if (R200_DEBUG
& DEBUG_IOCTL
)
328 fprintf(stderr
, "%s %p\n", __FUNCTION__
, pointer
);
330 if (!ctx
|| !(rmesa
= R200_CONTEXT(ctx
)) || !rmesa
->radeon
.radeonScreen
->gartTextures
.map
) {
331 fprintf(stderr
, "%s: no context\n", __FUNCTION__
);
335 region_offset
= (char *)pointer
- (char *)rmesa
->radeon
.radeonScreen
->gartTextures
.map
;
337 if (region_offset
< 0 ||
338 region_offset
> rmesa
->radeon
.radeonScreen
->gartTextures
.size
) {
339 fprintf(stderr
, "offset %d outside range 0..%d\n", region_offset
,
340 rmesa
->radeon
.radeonScreen
->gartTextures
.size
);
344 memfree
.region
= RADEON_MEM_REGION_GART
;
345 memfree
.region_offset
= region_offset
;
347 ret
= drmCommandWrite( rmesa
->radeon
.radeonScreen
->driScreen
->fd
,
349 &memfree
, sizeof(memfree
));
352 fprintf(stderr
, "%s: DRM_RADEON_FREE ret %d\n", __FUNCTION__
, ret
);
355 /* Called via glXGetMemoryOffsetMESA() */
356 GLuint
r200GetMemoryOffsetMESA(__DRIscreen
*screen
, const GLvoid
*pointer
)
358 GET_CURRENT_CONTEXT(ctx
);
359 r200ContextPtr rmesa
;
362 if (!ctx
|| !(rmesa
= R200_CONTEXT(ctx
)) ) {
363 fprintf(stderr
, "%s: no context\n", __FUNCTION__
);
367 if (!r200IsGartMemory( rmesa
, pointer
, 0 ))
370 card_offset
= r200GartOffsetFromVirtual( rmesa
, pointer
);
372 return card_offset
- rmesa
->radeon
.radeonScreen
->gart_base
;
375 GLboolean
r200IsGartMemory( r200ContextPtr rmesa
, const GLvoid
*pointer
,
378 ptrdiff_t offset
= (char *)pointer
- (char *)rmesa
->radeon
.radeonScreen
->gartTextures
.map
;
379 int valid
= (size
>= 0 &&
381 offset
+ size
< rmesa
->radeon
.radeonScreen
->gartTextures
.size
);
383 if (R200_DEBUG
& DEBUG_IOCTL
)
384 fprintf(stderr
, "r200IsGartMemory( %p ) : %d\n", pointer
, valid
);
390 GLuint
r200GartOffsetFromVirtual( r200ContextPtr rmesa
, const GLvoid
*pointer
)
392 ptrdiff_t offset
= (char *)pointer
- (char *)rmesa
->radeon
.radeonScreen
->gartTextures
.map
;
394 if (offset
< 0 || offset
> rmesa
->radeon
.radeonScreen
->gartTextures
.size
)
397 return rmesa
->radeon
.radeonScreen
->gart_texture_offset
+ offset
;
402 void r200InitIoctlFuncs( struct dd_function_table
*functions
)
404 functions
->Clear
= r200Clear
;
405 functions
->Finish
= radeonFinish
;
406 functions
->Flush
= radeonFlush
;