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"
46 #include "radeon_common.h"
47 #include "radeon_lock.h"
48 #include "r200_context.h"
49 #include "r200_state.h"
50 #include "r200_ioctl.h"
52 #include "r200_sanity.h"
53 #include "radeon_reg.h"
55 #include "drirenderbuffer.h"
58 #define R200_TIMEOUT 512
59 #define R200_IDLE_RETRY 16
61 static void r200KernelClear(GLcontext
*ctx
, GLuint flags
)
63 r200ContextPtr rmesa
= R200_CONTEXT(ctx
);
64 __DRIdrawablePrivate
*dPriv
= radeon_get_drawable(&rmesa
->radeon
);
65 GLint cx
, cy
, cw
, ch
, ret
;
68 LOCK_HARDWARE( &rmesa
->radeon
);
70 /* Throttle the number of clear ioctls we do.
73 drm_radeon_getparam_t gp
;
77 gp
.param
= RADEON_PARAM_LAST_CLEAR
;
78 gp
.value
= (int *)&clear
;
79 ret
= drmCommandWriteRead( rmesa
->radeon
.dri
.fd
,
80 DRM_RADEON_GETPARAM
, &gp
, sizeof(gp
) );
83 fprintf( stderr
, "%s: drmRadeonGetParam: %d\n", __FUNCTION__
, ret
);
87 /* Clear throttling needs more thought.
89 if ( rmesa
->radeon
.sarea
->last_clear
- clear
<= 25 ) {
93 if (rmesa
->radeon
.do_usleeps
) {
94 UNLOCK_HARDWARE( &rmesa
->radeon
);
96 LOCK_HARDWARE( &rmesa
->radeon
);
100 /* Send current state to the hardware */
101 rcommonFlushCmdBufLocked( &rmesa
->radeon
, __FUNCTION__
);
104 /* compute region after locking: */
105 cx
= ctx
->DrawBuffer
->_Xmin
;
106 cy
= ctx
->DrawBuffer
->_Ymin
;
107 cw
= ctx
->DrawBuffer
->_Xmax
- cx
;
108 ch
= ctx
->DrawBuffer
->_Ymax
- cy
;
110 /* Flip top to bottom */
112 cy
= dPriv
->y
+ dPriv
->h
- cy
- ch
;
113 for ( i
= 0 ; i
< dPriv
->numClipRects
; ) {
114 GLint nr
= MIN2( i
+ RADEON_NR_SAREA_CLIPRECTS
, dPriv
->numClipRects
);
115 drm_clip_rect_t
*box
= dPriv
->pClipRects
;
116 drm_clip_rect_t
*b
= rmesa
->radeon
.sarea
->boxes
;
117 drm_radeon_clear_t clear
;
118 drm_radeon_clear_rect_t depth_boxes
[RADEON_NR_SAREA_CLIPRECTS
];
121 if (cw
!= dPriv
->w
|| ch
!= dPriv
->h
) {
122 /* clear subregion */
123 for ( ; i
< nr
; i
++ ) {
126 GLint w
= box
[i
].x2
- x
;
127 GLint h
= box
[i
].y2
- y
;
129 if ( x
< cx
) w
-= cx
- x
, x
= cx
;
130 if ( y
< cy
) h
-= cy
- y
, y
= cy
;
131 if ( x
+ w
> cx
+ cw
) w
= cx
+ cw
- x
;
132 if ( y
+ h
> cy
+ ch
) h
= cy
+ ch
- y
;
133 if ( w
<= 0 ) continue;
134 if ( h
<= 0 ) continue;
144 /* clear whole window */
145 for ( ; i
< nr
; i
++ ) {
151 rmesa
->radeon
.sarea
->nbox
= n
;
154 clear
.clear_color
= rmesa
->radeon
.state
.color
.clear
;
155 clear
.clear_depth
= rmesa
->radeon
.state
.depth
.clear
; /* needed for hyperz */
156 clear
.color_mask
= rmesa
->hw
.msk
.cmd
[MSK_RB3D_PLANEMASK
];
157 clear
.depth_mask
= rmesa
->radeon
.state
.stencil
.clear
;
158 clear
.depth_boxes
= depth_boxes
;
161 b
= rmesa
->radeon
.sarea
->boxes
;
162 for ( ; n
>= 0 ; n
-- ) {
163 depth_boxes
[n
].f
[CLEAR_X1
] = (float)b
[n
].x1
;
164 depth_boxes
[n
].f
[CLEAR_Y1
] = (float)b
[n
].y1
;
165 depth_boxes
[n
].f
[CLEAR_X2
] = (float)b
[n
].x2
;
166 depth_boxes
[n
].f
[CLEAR_Y2
] = (float)b
[n
].y2
;
167 depth_boxes
[n
].f
[CLEAR_DEPTH
] = ctx
->Depth
.Clear
;
170 ret
= drmCommandWrite( rmesa
->radeon
.dri
.fd
, DRM_RADEON_CLEAR
,
171 &clear
, sizeof(clear
));
175 UNLOCK_HARDWARE( &rmesa
->radeon
);
176 fprintf( stderr
, "DRM_RADEON_CLEAR: return = %d\n", ret
);
180 UNLOCK_HARDWARE( &rmesa
->radeon
);
182 /* ================================================================
185 static void r200Clear( GLcontext
*ctx
, GLbitfield mask
)
187 r200ContextPtr rmesa
= R200_CONTEXT(ctx
);
188 __DRIdrawablePrivate
*dPriv
= radeon_get_drawable(&rmesa
->radeon
);
190 GLuint color_mask
= 0;
191 GLuint orig_mask
= mask
;
193 if ( R200_DEBUG
& DEBUG_IOCTL
) {
194 if (rmesa
->radeon
.sarea
)
195 fprintf( stderr
, "r200Clear %x %d\n", mask
, rmesa
->radeon
.sarea
->pfCurrentPage
);
197 fprintf( stderr
, "r200Clear %x radeon->sarea is NULL\n", mask
);
201 LOCK_HARDWARE( &rmesa
->radeon
);
202 UNLOCK_HARDWARE( &rmesa
->radeon
);
203 if ( dPriv
->numClipRects
== 0 )
209 if ( mask
& BUFFER_BIT_FRONT_LEFT
) {
210 flags
|= RADEON_FRONT
;
211 color_mask
= rmesa
->hw
.msk
.cmd
[MSK_RB3D_PLANEMASK
];
212 mask
&= ~BUFFER_BIT_FRONT_LEFT
;
215 if ( mask
& BUFFER_BIT_BACK_LEFT
) {
216 flags
|= RADEON_BACK
;
217 color_mask
= rmesa
->hw
.msk
.cmd
[MSK_RB3D_PLANEMASK
];
218 mask
&= ~BUFFER_BIT_BACK_LEFT
;
221 if ( mask
& BUFFER_BIT_DEPTH
) {
222 flags
|= RADEON_DEPTH
;
223 mask
&= ~BUFFER_BIT_DEPTH
;
226 if ( (mask
& BUFFER_BIT_STENCIL
) ) {
227 flags
|= RADEON_STENCIL
;
228 mask
&= ~BUFFER_BIT_STENCIL
;
232 if (R200_DEBUG
& DEBUG_FALLBACKS
)
233 fprintf(stderr
, "%s: swrast clear, mask: %x\n", __FUNCTION__
, mask
);
234 _swrast_Clear( ctx
, mask
);
240 if (rmesa
->using_hyperz
) {
241 flags
|= RADEON_USE_COMP_ZBUF
;
242 /* if (rmesa->radeon.radeonScreen->chip_family == CHIP_FAMILY_R200)
243 flags |= RADEON_USE_HIERZ; */
244 if (!((flags
& RADEON_DEPTH
) && (flags
& RADEON_STENCIL
) &&
245 ((rmesa
->radeon
.state
.stencil
.clear
& R200_STENCIL_WRITE_MASK
) == R200_STENCIL_WRITE_MASK
))) {
246 flags
|= RADEON_CLEAR_FASTZ
;
250 if (rmesa
->radeon
.radeonScreen
->kernel_mm
)
251 radeonUserClear(ctx
, orig_mask
);
253 r200KernelClear(ctx
, flags
);
254 rmesa
->radeon
.hw
.all_dirty
= GL_TRUE
;
258 /* This version of AllocateMemoryMESA allocates only GART memory, and
259 * only does so after the point at which the driver has been
262 * Theoretically a valid context isn't required. However, in this
263 * implementation, it is, as I'm using the hardware lock to protect
264 * the kernel data structures, and the current context to get the
267 void *r200AllocateMemoryMESA(__DRIscreen
*screen
, GLsizei size
,
268 GLfloat readfreq
, GLfloat writefreq
,
271 GET_CURRENT_CONTEXT(ctx
);
272 r200ContextPtr rmesa
;
274 drm_radeon_mem_alloc_t alloc
;
277 if (R200_DEBUG
& DEBUG_IOCTL
)
278 fprintf(stderr
, "%s sz %d %f/%f/%f\n", __FUNCTION__
, size
, readfreq
,
279 writefreq
, priority
);
281 if (!ctx
|| !(rmesa
= R200_CONTEXT(ctx
)) || !rmesa
->radeon
.radeonScreen
->gartTextures
.map
)
284 if (getenv("R200_NO_ALLOC"))
287 alloc
.region
= RADEON_MEM_REGION_GART
;
290 alloc
.region_offset
= ®ion_offset
;
292 ret
= drmCommandWriteRead( rmesa
->radeon
.radeonScreen
->driScreen
->fd
,
294 &alloc
, sizeof(alloc
));
297 fprintf(stderr
, "%s: DRM_RADEON_ALLOC ret %d\n", __FUNCTION__
, ret
);
302 char *region_start
= (char *)rmesa
->radeon
.radeonScreen
->gartTextures
.map
;
303 return (void *)(region_start
+ region_offset
);
308 /* Called via glXFreeMemoryMESA() */
309 void r200FreeMemoryMESA(__DRIscreen
*screen
, GLvoid
*pointer
)
311 GET_CURRENT_CONTEXT(ctx
);
312 r200ContextPtr rmesa
;
313 ptrdiff_t region_offset
;
314 drm_radeon_mem_free_t memfree
;
317 if (R200_DEBUG
& DEBUG_IOCTL
)
318 fprintf(stderr
, "%s %p\n", __FUNCTION__
, pointer
);
320 if (!ctx
|| !(rmesa
= R200_CONTEXT(ctx
)) || !rmesa
->radeon
.radeonScreen
->gartTextures
.map
) {
321 fprintf(stderr
, "%s: no context\n", __FUNCTION__
);
325 region_offset
= (char *)pointer
- (char *)rmesa
->radeon
.radeonScreen
->gartTextures
.map
;
327 if (region_offset
< 0 ||
328 region_offset
> rmesa
->radeon
.radeonScreen
->gartTextures
.size
) {
329 fprintf(stderr
, "offset %d outside range 0..%d\n", region_offset
,
330 rmesa
->radeon
.radeonScreen
->gartTextures
.size
);
334 memfree
.region
= RADEON_MEM_REGION_GART
;
335 memfree
.region_offset
= region_offset
;
337 ret
= drmCommandWrite( rmesa
->radeon
.radeonScreen
->driScreen
->fd
,
339 &memfree
, sizeof(memfree
));
342 fprintf(stderr
, "%s: DRM_RADEON_FREE ret %d\n", __FUNCTION__
, ret
);
345 /* Called via glXGetMemoryOffsetMESA() */
346 GLuint
r200GetMemoryOffsetMESA(__DRIscreen
*screen
, const GLvoid
*pointer
)
348 GET_CURRENT_CONTEXT(ctx
);
349 r200ContextPtr rmesa
;
352 if (!ctx
|| !(rmesa
= R200_CONTEXT(ctx
)) ) {
353 fprintf(stderr
, "%s: no context\n", __FUNCTION__
);
357 if (!r200IsGartMemory( rmesa
, pointer
, 0 ))
360 card_offset
= r200GartOffsetFromVirtual( rmesa
, pointer
);
362 return card_offset
- rmesa
->radeon
.radeonScreen
->gart_base
;
365 GLboolean
r200IsGartMemory( r200ContextPtr rmesa
, const GLvoid
*pointer
,
368 ptrdiff_t offset
= (char *)pointer
- (char *)rmesa
->radeon
.radeonScreen
->gartTextures
.map
;
369 int valid
= (size
>= 0 &&
371 offset
+ size
< rmesa
->radeon
.radeonScreen
->gartTextures
.size
);
373 if (R200_DEBUG
& DEBUG_IOCTL
)
374 fprintf(stderr
, "r200IsGartMemory( %p ) : %d\n", pointer
, valid
);
380 GLuint
r200GartOffsetFromVirtual( r200ContextPtr rmesa
, const GLvoid
*pointer
)
382 ptrdiff_t offset
= (char *)pointer
- (char *)rmesa
->radeon
.radeonScreen
->gartTextures
.map
;
384 if (offset
< 0 || offset
> rmesa
->radeon
.radeonScreen
->gartTextures
.size
)
387 return rmesa
->radeon
.radeonScreen
->gart_texture_offset
+ offset
;
392 void r200InitIoctlFuncs( struct dd_function_table
*functions
)
394 functions
->Clear
= r200Clear
;
395 functions
->Finish
= radeonFinish
;
396 functions
->Flush
= radeonFlush
;