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_cs.h"
45 #include "r200_context.h"
47 #include "common_cmdbuf.h"
48 #include "r200_state.h"
49 #include "r200_ioctl.h"
51 #include "r200_sanity.h"
52 #include "radeon_reg.h"
54 #include "drirenderbuffer.h"
57 #define R200_TIMEOUT 512
58 #define R200_IDLE_RETRY 16
61 /* At this point we were in FlushCmdBufLocked but we had lost our context, so
62 * we need to unwire our current cmdbuf, hook the one with the saved state in
63 * it, flush it, and then put the current one back. This is so commands at the
64 * start of a cmdbuf can rely on the state being kept from the previous one.
66 static void r200BackUpAndEmitLostStateLocked( r200ContextPtr rmesa
)
68 GLuint nr_released_bufs
;
69 struct radeon_store saved_store
;
71 if (rmesa
->backup_store
.cmd_used
== 0)
74 if (R200_DEBUG
& DEBUG_STATE
)
75 fprintf(stderr
, "Emitting backup state on lost context\n");
77 rmesa
->radeon
.lost_context
= GL_FALSE
;
79 nr_released_bufs
= rmesa
->dma
.nr_released_bufs
;
80 saved_store
= rmesa
->store
;
81 rmesa
->dma
.nr_released_bufs
= 0;
82 rmesa
->store
= rmesa
->backup_store
;
83 rcommonFlushCmdBufLocked( &rmesa
->radeon
, __FUNCTION__
);
84 rmesa
->dma
.nr_released_bufs
= nr_released_bufs
;
85 rmesa
->store
= saved_store
;
88 static void r200UserClear(GLcontext
*ctx
, GLuint flags
)
90 if (flags
& (RADEON_FRONT
| RADEON_BACK
)) {
95 if ((flags
& (RADEON_DEPTH
| RADEON_STENCIL
))
96 && (flags
& RADEON_CLEAR_FASTZ
)) {
102 static void r200KernelClear(GLcontext
*ctx
, GLuint flags
)
104 r200ContextPtr rmesa
= R200_CONTEXT(ctx
);
105 __DRIdrawablePrivate
*dPriv
= rmesa
->radeon
.dri
.drawable
;
106 GLint cx
, cy
, cw
, ch
, ret
;
109 LOCK_HARDWARE( &rmesa
->radeon
);
111 /* Throttle the number of clear ioctls we do.
114 drm_radeon_getparam_t gp
;
118 gp
.param
= RADEON_PARAM_LAST_CLEAR
;
119 gp
.value
= (int *)&clear
;
120 ret
= drmCommandWriteRead( rmesa
->radeon
.dri
.fd
,
121 DRM_RADEON_GETPARAM
, &gp
, sizeof(gp
) );
124 fprintf( stderr
, "%s: drmRadeonGetParam: %d\n", __FUNCTION__
, ret
);
128 /* Clear throttling needs more thought.
130 if ( rmesa
->radeon
.sarea
->last_clear
- clear
<= 25 ) {
134 if (rmesa
->radeon
.do_usleeps
) {
135 UNLOCK_HARDWARE( &rmesa
->radeon
);
137 LOCK_HARDWARE( &rmesa
->radeon
);
141 /* Send current state to the hardware */
142 rcommonFlushCmdBufLocked( &rmesa
->radeon
, __FUNCTION__
);
145 /* compute region after locking: */
146 cx
= ctx
->DrawBuffer
->_Xmin
;
147 cy
= ctx
->DrawBuffer
->_Ymin
;
148 cw
= ctx
->DrawBuffer
->_Xmax
- cx
;
149 ch
= ctx
->DrawBuffer
->_Ymax
- cy
;
151 /* Flip top to bottom */
153 cy
= dPriv
->y
+ dPriv
->h
- cy
- ch
;
154 for ( i
= 0 ; i
< dPriv
->numClipRects
; ) {
155 GLint nr
= MIN2( i
+ RADEON_NR_SAREA_CLIPRECTS
, dPriv
->numClipRects
);
156 drm_clip_rect_t
*box
= dPriv
->pClipRects
;
157 drm_clip_rect_t
*b
= rmesa
->radeon
.sarea
->boxes
;
158 drm_radeon_clear_t clear
;
159 drm_radeon_clear_rect_t depth_boxes
[RADEON_NR_SAREA_CLIPRECTS
];
162 if (cw
!= dPriv
->w
|| ch
!= dPriv
->h
) {
163 /* clear subregion */
164 for ( ; i
< nr
; i
++ ) {
167 GLint w
= box
[i
].x2
- x
;
168 GLint h
= box
[i
].y2
- y
;
170 if ( x
< cx
) w
-= cx
- x
, x
= cx
;
171 if ( y
< cy
) h
-= cy
- y
, y
= cy
;
172 if ( x
+ w
> cx
+ cw
) w
= cx
+ cw
- x
;
173 if ( y
+ h
> cy
+ ch
) h
= cy
+ ch
- y
;
174 if ( w
<= 0 ) continue;
175 if ( h
<= 0 ) continue;
185 /* clear whole window */
186 for ( ; i
< nr
; i
++ ) {
192 rmesa
->radeon
.sarea
->nbox
= n
;
195 clear
.clear_color
= rmesa
->radeon
.state
.color
.clear
;
196 clear
.clear_depth
= rmesa
->radeon
.state
.depth
.clear
; /* needed for hyperz */
197 clear
.color_mask
= rmesa
->hw
.msk
.cmd
[MSK_RB3D_PLANEMASK
];
198 clear
.depth_mask
= rmesa
->radeon
.state
.stencil
.clear
;
199 clear
.depth_boxes
= depth_boxes
;
202 b
= rmesa
->radeon
.sarea
->boxes
;
203 for ( ; n
>= 0 ; n
-- ) {
204 depth_boxes
[n
].f
[CLEAR_X1
] = (float)b
[n
].x1
;
205 depth_boxes
[n
].f
[CLEAR_Y1
] = (float)b
[n
].y1
;
206 depth_boxes
[n
].f
[CLEAR_X2
] = (float)b
[n
].x2
;
207 depth_boxes
[n
].f
[CLEAR_Y2
] = (float)b
[n
].y2
;
208 depth_boxes
[n
].f
[CLEAR_DEPTH
] = ctx
->Depth
.Clear
;
211 ret
= drmCommandWrite( rmesa
->radeon
.dri
.fd
, DRM_RADEON_CLEAR
,
212 &clear
, sizeof(clear
));
216 UNLOCK_HARDWARE( &rmesa
->radeon
);
217 fprintf( stderr
, "DRM_RADEON_CLEAR: return = %d\n", ret
);
221 UNLOCK_HARDWARE( &rmesa
->radeon
);
223 /* ================================================================
226 static void r200Clear( GLcontext
*ctx
, GLbitfield mask
)
228 r200ContextPtr rmesa
= R200_CONTEXT(ctx
);
229 __DRIdrawablePrivate
*dPriv
= rmesa
->radeon
.dri
.drawable
;
231 GLuint color_mask
= 0;
234 if ( R200_DEBUG
& DEBUG_IOCTL
) {
235 fprintf( stderr
, "r200Clear\n");
239 LOCK_HARDWARE( &rmesa
->radeon
);
240 UNLOCK_HARDWARE( &rmesa
->radeon
);
241 if ( dPriv
->numClipRects
== 0 )
247 if ( mask
& BUFFER_BIT_FRONT_LEFT
) {
248 flags
|= RADEON_FRONT
;
249 color_mask
= rmesa
->hw
.msk
.cmd
[MSK_RB3D_PLANEMASK
];
250 mask
&= ~BUFFER_BIT_FRONT_LEFT
;
253 if ( mask
& BUFFER_BIT_BACK_LEFT
) {
254 flags
|= RADEON_BACK
;
255 color_mask
= rmesa
->hw
.msk
.cmd
[MSK_RB3D_PLANEMASK
];
256 mask
&= ~BUFFER_BIT_BACK_LEFT
;
259 if ( mask
& BUFFER_BIT_DEPTH
) {
260 flags
|= RADEON_DEPTH
;
261 mask
&= ~BUFFER_BIT_DEPTH
;
264 if ( (mask
& BUFFER_BIT_STENCIL
) && rmesa
->radeon
.state
.stencil
.hwBuffer
) {
265 flags
|= RADEON_STENCIL
;
266 mask
&= ~BUFFER_BIT_STENCIL
;
270 if (R200_DEBUG
& DEBUG_FALLBACKS
)
271 fprintf(stderr
, "%s: swrast clear, mask: %x\n", __FUNCTION__
, mask
);
272 _swrast_Clear( ctx
, mask
);
278 if (rmesa
->using_hyperz
) {
279 flags
|= RADEON_USE_COMP_ZBUF
;
280 /* if (rmesa->radeon.radeonScreen->chip_family == CHIP_FAMILY_R200)
281 flags |= RADEON_USE_HIERZ; */
282 if (!(rmesa
->radeon
.state
.stencil
.hwBuffer
) ||
283 ((flags
& RADEON_DEPTH
) && (flags
& RADEON_STENCIL
) &&
284 ((rmesa
->radeon
.state
.stencil
.clear
& R200_STENCIL_WRITE_MASK
) == R200_STENCIL_WRITE_MASK
))) {
285 flags
|= RADEON_CLEAR_FASTZ
;
289 if (rmesa
->radeon
.radeonScreen
->kernel_mm
)
290 r200UserClear(ctx
, flags
);
292 r200KernelClear(ctx
, flags
);
294 rmesa
->hw
.all_dirty
= GL_TRUE
;
298 void r200Flush( GLcontext
*ctx
)
300 r200ContextPtr rmesa
= R200_CONTEXT( ctx
);
302 if (R200_DEBUG
& DEBUG_IOCTL
)
303 fprintf(stderr
, "%s\n", __FUNCTION__
);
305 if (rmesa
->swtcl
.flush
)
306 rmesa
->swtcl
.flush( ctx
);
308 if (rmesa
->tcl
.flush
)
309 rmesa
->tcl
.flush( ctx
);
311 r200EmitState( rmesa
);
313 if (rmesa
->radeon
.cmdbuf
.cs
->cdw
)
314 rcommonFlushCmdBuf( &rmesa
->radeon
, __FUNCTION__
);
317 /* Make sure all commands have been sent to the hardware and have
318 * completed processing.
320 void r200Finish( GLcontext
*ctx
)
323 radeon_common_finish(ctx
);
327 /* This version of AllocateMemoryMESA allocates only GART memory, and
328 * only does so after the point at which the driver has been
331 * Theoretically a valid context isn't required. However, in this
332 * implementation, it is, as I'm using the hardware lock to protect
333 * the kernel data structures, and the current context to get the
336 void *r200AllocateMemoryMESA(__DRIscreen
*screen
, GLsizei size
,
337 GLfloat readfreq
, GLfloat writefreq
,
340 GET_CURRENT_CONTEXT(ctx
);
341 r200ContextPtr rmesa
;
343 drm_radeon_mem_alloc_t alloc
;
346 if (R200_DEBUG
& DEBUG_IOCTL
)
347 fprintf(stderr
, "%s sz %d %f/%f/%f\n", __FUNCTION__
, size
, readfreq
,
348 writefreq
, priority
);
350 if (!ctx
|| !(rmesa
= R200_CONTEXT(ctx
)) || !rmesa
->radeon
.radeonScreen
->gartTextures
.map
)
353 if (getenv("R200_NO_ALLOC"))
356 alloc
.region
= RADEON_MEM_REGION_GART
;
359 alloc
.region_offset
= ®ion_offset
;
361 ret
= drmCommandWriteRead( rmesa
->radeon
.radeonScreen
->driScreen
->fd
,
363 &alloc
, sizeof(alloc
));
366 fprintf(stderr
, "%s: DRM_RADEON_ALLOC ret %d\n", __FUNCTION__
, ret
);
371 char *region_start
= (char *)rmesa
->radeon
.radeonScreen
->gartTextures
.map
;
372 return (void *)(region_start
+ region_offset
);
377 /* Called via glXFreeMemoryMESA() */
378 void r200FreeMemoryMESA(__DRIscreen
*screen
, GLvoid
*pointer
)
380 GET_CURRENT_CONTEXT(ctx
);
381 r200ContextPtr rmesa
;
382 ptrdiff_t region_offset
;
383 drm_radeon_mem_free_t memfree
;
386 if (R200_DEBUG
& DEBUG_IOCTL
)
387 fprintf(stderr
, "%s %p\n", __FUNCTION__
, pointer
);
389 if (!ctx
|| !(rmesa
= R200_CONTEXT(ctx
)) || !rmesa
->radeon
.radeonScreen
->gartTextures
.map
) {
390 fprintf(stderr
, "%s: no context\n", __FUNCTION__
);
394 region_offset
= (char *)pointer
- (char *)rmesa
->radeon
.radeonScreen
->gartTextures
.map
;
396 if (region_offset
< 0 ||
397 region_offset
> rmesa
->radeon
.radeonScreen
->gartTextures
.size
) {
398 fprintf(stderr
, "offset %d outside range 0..%d\n", region_offset
,
399 rmesa
->radeon
.radeonScreen
->gartTextures
.size
);
403 memfree
.region
= RADEON_MEM_REGION_GART
;
404 memfree
.region_offset
= region_offset
;
406 ret
= drmCommandWrite( rmesa
->radeon
.radeonScreen
->driScreen
->fd
,
408 &memfree
, sizeof(memfree
));
411 fprintf(stderr
, "%s: DRM_RADEON_FREE ret %d\n", __FUNCTION__
, ret
);
414 /* Called via glXGetMemoryOffsetMESA() */
415 GLuint
r200GetMemoryOffsetMESA(__DRIscreen
*screen
, const GLvoid
*pointer
)
417 GET_CURRENT_CONTEXT(ctx
);
418 r200ContextPtr rmesa
;
421 if (!ctx
|| !(rmesa
= R200_CONTEXT(ctx
)) ) {
422 fprintf(stderr
, "%s: no context\n", __FUNCTION__
);
426 if (!r200IsGartMemory( rmesa
, pointer
, 0 ))
429 card_offset
= r200GartOffsetFromVirtual( rmesa
, pointer
);
431 return card_offset
- rmesa
->radeon
.radeonScreen
->gart_base
;
434 GLboolean
r200IsGartMemory( r200ContextPtr rmesa
, const GLvoid
*pointer
,
437 ptrdiff_t offset
= (char *)pointer
- (char *)rmesa
->radeon
.radeonScreen
->gartTextures
.map
;
438 int valid
= (size
>= 0 &&
440 offset
+ size
< rmesa
->radeon
.radeonScreen
->gartTextures
.size
);
442 if (R200_DEBUG
& DEBUG_IOCTL
)
443 fprintf(stderr
, "r200IsGartMemory( %p ) : %d\n", pointer
, valid
);
449 GLuint
r200GartOffsetFromVirtual( r200ContextPtr rmesa
, const GLvoid
*pointer
)
451 ptrdiff_t offset
= (char *)pointer
- (char *)rmesa
->radeon
.radeonScreen
->gartTextures
.map
;
453 if (offset
< 0 || offset
> rmesa
->radeon
.radeonScreen
->gartTextures
.size
)
456 return rmesa
->radeon
.radeonScreen
->gart_texture_offset
+ offset
;
461 void r200InitIoctlFuncs( struct dd_function_table
*functions
)
463 functions
->Clear
= r200Clear
;
464 functions
->Finish
= r200Finish
;
465 functions
->Flush
= r200Flush
;