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 r200UserClear(GLcontext
*ctx
, GLuint mask
)
63 radeon_clear_tris(ctx
, mask
);
66 static void r200KernelClear(GLcontext
*ctx
, GLuint flags
)
68 r200ContextPtr rmesa
= R200_CONTEXT(ctx
);
69 __DRIdrawablePrivate
*dPriv
= radeon_get_drawable(&rmesa
->radeon
);
70 GLint cx
, cy
, cw
, ch
, ret
;
73 LOCK_HARDWARE( &rmesa
->radeon
);
75 /* Throttle the number of clear ioctls we do.
78 drm_radeon_getparam_t gp
;
82 gp
.param
= RADEON_PARAM_LAST_CLEAR
;
83 gp
.value
= (int *)&clear
;
84 ret
= drmCommandWriteRead( rmesa
->radeon
.dri
.fd
,
85 DRM_RADEON_GETPARAM
, &gp
, sizeof(gp
) );
88 fprintf( stderr
, "%s: drmRadeonGetParam: %d\n", __FUNCTION__
, ret
);
92 /* Clear throttling needs more thought.
94 if ( rmesa
->radeon
.sarea
->last_clear
- clear
<= 25 ) {
98 if (rmesa
->radeon
.do_usleeps
) {
99 UNLOCK_HARDWARE( &rmesa
->radeon
);
101 LOCK_HARDWARE( &rmesa
->radeon
);
105 /* Send current state to the hardware */
106 rcommonFlushCmdBufLocked( &rmesa
->radeon
, __FUNCTION__
);
109 /* compute region after locking: */
110 cx
= ctx
->DrawBuffer
->_Xmin
;
111 cy
= ctx
->DrawBuffer
->_Ymin
;
112 cw
= ctx
->DrawBuffer
->_Xmax
- cx
;
113 ch
= ctx
->DrawBuffer
->_Ymax
- cy
;
115 /* Flip top to bottom */
117 cy
= dPriv
->y
+ dPriv
->h
- cy
- ch
;
118 for ( i
= 0 ; i
< dPriv
->numClipRects
; ) {
119 GLint nr
= MIN2( i
+ RADEON_NR_SAREA_CLIPRECTS
, dPriv
->numClipRects
);
120 drm_clip_rect_t
*box
= dPriv
->pClipRects
;
121 drm_clip_rect_t
*b
= rmesa
->radeon
.sarea
->boxes
;
122 drm_radeon_clear_t clear
;
123 drm_radeon_clear_rect_t depth_boxes
[RADEON_NR_SAREA_CLIPRECTS
];
126 if (cw
!= dPriv
->w
|| ch
!= dPriv
->h
) {
127 /* clear subregion */
128 for ( ; i
< nr
; i
++ ) {
131 GLint w
= box
[i
].x2
- x
;
132 GLint h
= box
[i
].y2
- y
;
134 if ( x
< cx
) w
-= cx
- x
, x
= cx
;
135 if ( y
< cy
) h
-= cy
- y
, y
= cy
;
136 if ( x
+ w
> cx
+ cw
) w
= cx
+ cw
- x
;
137 if ( y
+ h
> cy
+ ch
) h
= cy
+ ch
- y
;
138 if ( w
<= 0 ) continue;
139 if ( h
<= 0 ) continue;
149 /* clear whole window */
150 for ( ; i
< nr
; i
++ ) {
156 rmesa
->radeon
.sarea
->nbox
= n
;
159 clear
.clear_color
= rmesa
->radeon
.state
.color
.clear
;
160 clear
.clear_depth
= rmesa
->radeon
.state
.depth
.clear
; /* needed for hyperz */
161 clear
.color_mask
= rmesa
->hw
.msk
.cmd
[MSK_RB3D_PLANEMASK
];
162 clear
.depth_mask
= rmesa
->radeon
.state
.stencil
.clear
;
163 clear
.depth_boxes
= depth_boxes
;
166 b
= rmesa
->radeon
.sarea
->boxes
;
167 for ( ; n
>= 0 ; n
-- ) {
168 depth_boxes
[n
].f
[CLEAR_X1
] = (float)b
[n
].x1
;
169 depth_boxes
[n
].f
[CLEAR_Y1
] = (float)b
[n
].y1
;
170 depth_boxes
[n
].f
[CLEAR_X2
] = (float)b
[n
].x2
;
171 depth_boxes
[n
].f
[CLEAR_Y2
] = (float)b
[n
].y2
;
172 depth_boxes
[n
].f
[CLEAR_DEPTH
] = ctx
->Depth
.Clear
;
175 ret
= drmCommandWrite( rmesa
->radeon
.dri
.fd
, DRM_RADEON_CLEAR
,
176 &clear
, sizeof(clear
));
180 UNLOCK_HARDWARE( &rmesa
->radeon
);
181 fprintf( stderr
, "DRM_RADEON_CLEAR: return = %d\n", ret
);
185 UNLOCK_HARDWARE( &rmesa
->radeon
);
187 /* ================================================================
190 static void r200Clear( GLcontext
*ctx
, GLbitfield mask
)
192 r200ContextPtr rmesa
= R200_CONTEXT(ctx
);
193 __DRIdrawablePrivate
*dPriv
= radeon_get_drawable(&rmesa
->radeon
);
195 GLuint color_mask
= 0;
196 GLuint orig_mask
= mask
;
198 if ( R200_DEBUG
& DEBUG_IOCTL
) {
199 if (rmesa
->radeon
.sarea
)
200 fprintf( stderr
, "r200Clear %x %d\n", mask
, rmesa
->radeon
.sarea
->pfCurrentPage
);
202 fprintf( stderr
, "r200Clear %x radeon->sarea is NULL\n", mask
);
206 LOCK_HARDWARE( &rmesa
->radeon
);
207 UNLOCK_HARDWARE( &rmesa
->radeon
);
208 if ( dPriv
->numClipRects
== 0 )
214 if ( mask
& BUFFER_BIT_FRONT_LEFT
) {
215 flags
|= RADEON_FRONT
;
216 color_mask
= rmesa
->hw
.msk
.cmd
[MSK_RB3D_PLANEMASK
];
217 mask
&= ~BUFFER_BIT_FRONT_LEFT
;
220 if ( mask
& BUFFER_BIT_BACK_LEFT
) {
221 flags
|= RADEON_BACK
;
222 color_mask
= rmesa
->hw
.msk
.cmd
[MSK_RB3D_PLANEMASK
];
223 mask
&= ~BUFFER_BIT_BACK_LEFT
;
226 if ( mask
& BUFFER_BIT_DEPTH
) {
227 flags
|= RADEON_DEPTH
;
228 mask
&= ~BUFFER_BIT_DEPTH
;
231 if ( (mask
& BUFFER_BIT_STENCIL
) ) {
232 flags
|= RADEON_STENCIL
;
233 mask
&= ~BUFFER_BIT_STENCIL
;
237 if (R200_DEBUG
& DEBUG_FALLBACKS
)
238 fprintf(stderr
, "%s: swrast clear, mask: %x\n", __FUNCTION__
, mask
);
239 _swrast_Clear( ctx
, mask
);
245 if (rmesa
->using_hyperz
) {
246 flags
|= RADEON_USE_COMP_ZBUF
;
247 /* if (rmesa->radeon.radeonScreen->chip_family == CHIP_FAMILY_R200)
248 flags |= RADEON_USE_HIERZ; */
249 if (!((flags
& RADEON_DEPTH
) && (flags
& RADEON_STENCIL
) &&
250 ((rmesa
->radeon
.state
.stencil
.clear
& R200_STENCIL_WRITE_MASK
) == R200_STENCIL_WRITE_MASK
))) {
251 flags
|= RADEON_CLEAR_FASTZ
;
255 if (rmesa
->radeon
.radeonScreen
->kernel_mm
)
256 r200UserClear(ctx
, orig_mask
);
258 r200KernelClear(ctx
, flags
);
259 rmesa
->radeon
.hw
.all_dirty
= GL_TRUE
;
263 /* This version of AllocateMemoryMESA allocates only GART memory, and
264 * only does so after the point at which the driver has been
267 * Theoretically a valid context isn't required. However, in this
268 * implementation, it is, as I'm using the hardware lock to protect
269 * the kernel data structures, and the current context to get the
272 void *r200AllocateMemoryMESA(__DRIscreen
*screen
, GLsizei size
,
273 GLfloat readfreq
, GLfloat writefreq
,
276 GET_CURRENT_CONTEXT(ctx
);
277 r200ContextPtr rmesa
;
279 drm_radeon_mem_alloc_t alloc
;
282 if (R200_DEBUG
& DEBUG_IOCTL
)
283 fprintf(stderr
, "%s sz %d %f/%f/%f\n", __FUNCTION__
, size
, readfreq
,
284 writefreq
, priority
);
286 if (!ctx
|| !(rmesa
= R200_CONTEXT(ctx
)) || !rmesa
->radeon
.radeonScreen
->gartTextures
.map
)
289 if (getenv("R200_NO_ALLOC"))
292 alloc
.region
= RADEON_MEM_REGION_GART
;
295 alloc
.region_offset
= ®ion_offset
;
297 ret
= drmCommandWriteRead( rmesa
->radeon
.radeonScreen
->driScreen
->fd
,
299 &alloc
, sizeof(alloc
));
302 fprintf(stderr
, "%s: DRM_RADEON_ALLOC ret %d\n", __FUNCTION__
, ret
);
307 char *region_start
= (char *)rmesa
->radeon
.radeonScreen
->gartTextures
.map
;
308 return (void *)(region_start
+ region_offset
);
313 /* Called via glXFreeMemoryMESA() */
314 void r200FreeMemoryMESA(__DRIscreen
*screen
, GLvoid
*pointer
)
316 GET_CURRENT_CONTEXT(ctx
);
317 r200ContextPtr rmesa
;
318 ptrdiff_t region_offset
;
319 drm_radeon_mem_free_t memfree
;
322 if (R200_DEBUG
& DEBUG_IOCTL
)
323 fprintf(stderr
, "%s %p\n", __FUNCTION__
, pointer
);
325 if (!ctx
|| !(rmesa
= R200_CONTEXT(ctx
)) || !rmesa
->radeon
.radeonScreen
->gartTextures
.map
) {
326 fprintf(stderr
, "%s: no context\n", __FUNCTION__
);
330 region_offset
= (char *)pointer
- (char *)rmesa
->radeon
.radeonScreen
->gartTextures
.map
;
332 if (region_offset
< 0 ||
333 region_offset
> rmesa
->radeon
.radeonScreen
->gartTextures
.size
) {
334 fprintf(stderr
, "offset %d outside range 0..%d\n", region_offset
,
335 rmesa
->radeon
.radeonScreen
->gartTextures
.size
);
339 memfree
.region
= RADEON_MEM_REGION_GART
;
340 memfree
.region_offset
= region_offset
;
342 ret
= drmCommandWrite( rmesa
->radeon
.radeonScreen
->driScreen
->fd
,
344 &memfree
, sizeof(memfree
));
347 fprintf(stderr
, "%s: DRM_RADEON_FREE ret %d\n", __FUNCTION__
, ret
);
350 /* Called via glXGetMemoryOffsetMESA() */
351 GLuint
r200GetMemoryOffsetMESA(__DRIscreen
*screen
, const GLvoid
*pointer
)
353 GET_CURRENT_CONTEXT(ctx
);
354 r200ContextPtr rmesa
;
357 if (!ctx
|| !(rmesa
= R200_CONTEXT(ctx
)) ) {
358 fprintf(stderr
, "%s: no context\n", __FUNCTION__
);
362 if (!r200IsGartMemory( rmesa
, pointer
, 0 ))
365 card_offset
= r200GartOffsetFromVirtual( rmesa
, pointer
);
367 return card_offset
- rmesa
->radeon
.radeonScreen
->gart_base
;
370 GLboolean
r200IsGartMemory( r200ContextPtr rmesa
, const GLvoid
*pointer
,
373 ptrdiff_t offset
= (char *)pointer
- (char *)rmesa
->radeon
.radeonScreen
->gartTextures
.map
;
374 int valid
= (size
>= 0 &&
376 offset
+ size
< rmesa
->radeon
.radeonScreen
->gartTextures
.size
);
378 if (R200_DEBUG
& DEBUG_IOCTL
)
379 fprintf(stderr
, "r200IsGartMemory( %p ) : %d\n", pointer
, valid
);
385 GLuint
r200GartOffsetFromVirtual( r200ContextPtr rmesa
, const GLvoid
*pointer
)
387 ptrdiff_t offset
= (char *)pointer
- (char *)rmesa
->radeon
.radeonScreen
->gartTextures
.map
;
389 if (offset
< 0 || offset
> rmesa
->radeon
.radeonScreen
->gartTextures
.size
)
392 return rmesa
->radeon
.radeonScreen
->gart_texture_offset
+ offset
;
397 void r200InitIoctlFuncs( struct dd_function_table
*functions
)
399 functions
->Clear
= r200Clear
;
400 functions
->Finish
= radeonFinish
;
401 functions
->Flush
= radeonFlush
;