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 /* ================================================================
91 static void r200Clear( GLcontext
*ctx
, GLbitfield mask
)
93 r200ContextPtr rmesa
= R200_CONTEXT(ctx
);
94 __DRIdrawablePrivate
*dPriv
= rmesa
->radeon
.dri
.drawable
;
96 GLuint color_mask
= 0;
100 if ( R200_DEBUG
& DEBUG_IOCTL
) {
101 fprintf( stderr
, "r200Clear\n");
105 LOCK_HARDWARE( &rmesa
->radeon
);
106 UNLOCK_HARDWARE( &rmesa
->radeon
);
107 if ( dPriv
->numClipRects
== 0 )
113 if ( mask
& BUFFER_BIT_FRONT_LEFT
) {
114 flags
|= RADEON_FRONT
;
115 color_mask
= rmesa
->hw
.msk
.cmd
[MSK_RB3D_PLANEMASK
];
116 mask
&= ~BUFFER_BIT_FRONT_LEFT
;
119 if ( mask
& BUFFER_BIT_BACK_LEFT
) {
120 flags
|= RADEON_BACK
;
121 color_mask
= rmesa
->hw
.msk
.cmd
[MSK_RB3D_PLANEMASK
];
122 mask
&= ~BUFFER_BIT_BACK_LEFT
;
125 if ( mask
& BUFFER_BIT_DEPTH
) {
126 flags
|= RADEON_DEPTH
;
127 mask
&= ~BUFFER_BIT_DEPTH
;
130 if ( (mask
& BUFFER_BIT_STENCIL
) && rmesa
->radeon
.state
.stencil
.hwBuffer
) {
131 flags
|= RADEON_STENCIL
;
132 mask
&= ~BUFFER_BIT_STENCIL
;
136 if (R200_DEBUG
& DEBUG_FALLBACKS
)
137 fprintf(stderr
, "%s: swrast clear, mask: %x\n", __FUNCTION__
, mask
);
138 _swrast_Clear( ctx
, mask
);
144 if (rmesa
->using_hyperz
) {
145 flags
|= RADEON_USE_COMP_ZBUF
;
146 /* if (rmesa->radeon.radeonScreen->chip_family == CHIP_FAMILY_R200)
147 flags |= RADEON_USE_HIERZ; */
148 if (!(rmesa
->radeon
.state
.stencil
.hwBuffer
) ||
149 ((flags
& RADEON_DEPTH
) && (flags
& RADEON_STENCIL
) &&
150 ((rmesa
->radeon
.state
.stencil
.clear
& R200_STENCIL_WRITE_MASK
) == R200_STENCIL_WRITE_MASK
))) {
151 flags
|= RADEON_CLEAR_FASTZ
;
155 LOCK_HARDWARE( &rmesa
->radeon
);
157 /* compute region after locking: */
158 cx
= ctx
->DrawBuffer
->_Xmin
;
159 cy
= ctx
->DrawBuffer
->_Ymin
;
160 cw
= ctx
->DrawBuffer
->_Xmax
- cx
;
161 ch
= ctx
->DrawBuffer
->_Ymax
- cy
;
163 /* Flip top to bottom */
165 cy
= dPriv
->y
+ dPriv
->h
- cy
- ch
;
167 /* Throttle the number of clear ioctls we do.
170 drm_radeon_getparam_t gp
;
174 gp
.param
= RADEON_PARAM_LAST_CLEAR
;
175 gp
.value
= (int *)&clear
;
176 ret
= drmCommandWriteRead( rmesa
->radeon
.dri
.fd
,
177 DRM_RADEON_GETPARAM
, &gp
, sizeof(gp
) );
180 fprintf( stderr
, "%s: drmRadeonGetParam: %d\n", __FUNCTION__
, ret
);
184 /* Clear throttling needs more thought.
186 if ( rmesa
->radeon
.sarea
->last_clear
- clear
<= 25 ) {
190 if (rmesa
->radeon
.do_usleeps
) {
191 UNLOCK_HARDWARE( &rmesa
->radeon
);
193 LOCK_HARDWARE( &rmesa
->radeon
);
197 /* Send current state to the hardware */
198 rcommonFlushCmdBufLocked( &rmesa
->radeon
, __FUNCTION__
);
200 for ( i
= 0 ; i
< dPriv
->numClipRects
; ) {
201 GLint nr
= MIN2( i
+ RADEON_NR_SAREA_CLIPRECTS
, dPriv
->numClipRects
);
202 drm_clip_rect_t
*box
= dPriv
->pClipRects
;
203 drm_clip_rect_t
*b
= rmesa
->radeon
.sarea
->boxes
;
204 drm_radeon_clear_t clear
;
205 drm_radeon_clear_rect_t depth_boxes
[RADEON_NR_SAREA_CLIPRECTS
];
208 if (cw
!= dPriv
->w
|| ch
!= dPriv
->h
) {
209 /* clear subregion */
210 for ( ; i
< nr
; i
++ ) {
213 GLint w
= box
[i
].x2
- x
;
214 GLint h
= box
[i
].y2
- y
;
216 if ( x
< cx
) w
-= cx
- x
, x
= cx
;
217 if ( y
< cy
) h
-= cy
- y
, y
= cy
;
218 if ( x
+ w
> cx
+ cw
) w
= cx
+ cw
- x
;
219 if ( y
+ h
> cy
+ ch
) h
= cy
+ ch
- y
;
220 if ( w
<= 0 ) continue;
221 if ( h
<= 0 ) continue;
231 /* clear whole window */
232 for ( ; i
< nr
; i
++ ) {
238 rmesa
->radeon
.sarea
->nbox
= n
;
241 clear
.clear_color
= rmesa
->radeon
.state
.color
.clear
;
242 clear
.clear_depth
= rmesa
->radeon
.state
.depth
.clear
; /* needed for hyperz */
243 clear
.color_mask
= rmesa
->hw
.msk
.cmd
[MSK_RB3D_PLANEMASK
];
244 clear
.depth_mask
= rmesa
->radeon
.state
.stencil
.clear
;
245 clear
.depth_boxes
= depth_boxes
;
248 b
= rmesa
->radeon
.sarea
->boxes
;
249 for ( ; n
>= 0 ; n
-- ) {
250 depth_boxes
[n
].f
[CLEAR_X1
] = (float)b
[n
].x1
;
251 depth_boxes
[n
].f
[CLEAR_Y1
] = (float)b
[n
].y1
;
252 depth_boxes
[n
].f
[CLEAR_X2
] = (float)b
[n
].x2
;
253 depth_boxes
[n
].f
[CLEAR_Y2
] = (float)b
[n
].y2
;
254 depth_boxes
[n
].f
[CLEAR_DEPTH
] = ctx
->Depth
.Clear
;
257 ret
= drmCommandWrite( rmesa
->radeon
.dri
.fd
, DRM_RADEON_CLEAR
,
258 &clear
, sizeof(clear
));
262 UNLOCK_HARDWARE( &rmesa
->radeon
);
263 fprintf( stderr
, "DRM_RADEON_CLEAR: return = %d\n", ret
);
268 UNLOCK_HARDWARE( &rmesa
->radeon
);
269 rmesa
->hw
.all_dirty
= GL_TRUE
;
273 void r200Flush( GLcontext
*ctx
)
275 r200ContextPtr rmesa
= R200_CONTEXT( ctx
);
277 if (R200_DEBUG
& DEBUG_IOCTL
)
278 fprintf(stderr
, "%s\n", __FUNCTION__
);
280 if (rmesa
->dma
.flush
)
281 rmesa
->dma
.flush( ctx
);
283 if (rmesa
->tcl
.flush
)
284 rmesa
->tcl
.flush( rmesa
);
286 r200EmitState( rmesa
);
288 if (rmesa
->radeon
.cmdbuf
.cs
->cdw
)
289 rcommonFlushCmdBuf( &rmesa
->radeon
, __FUNCTION__
);
292 /* Make sure all commands have been sent to the hardware and have
293 * completed processing.
295 void r200Finish( GLcontext
*ctx
)
298 radeon_common_finish(ctx
);
302 /* This version of AllocateMemoryMESA allocates only GART memory, and
303 * only does so after the point at which the driver has been
306 * Theoretically a valid context isn't required. However, in this
307 * implementation, it is, as I'm using the hardware lock to protect
308 * the kernel data structures, and the current context to get the
311 void *r200AllocateMemoryMESA(__DRIscreen
*screen
, GLsizei size
,
312 GLfloat readfreq
, GLfloat writefreq
,
315 GET_CURRENT_CONTEXT(ctx
);
316 r200ContextPtr rmesa
;
318 drm_radeon_mem_alloc_t alloc
;
321 if (R200_DEBUG
& DEBUG_IOCTL
)
322 fprintf(stderr
, "%s sz %d %f/%f/%f\n", __FUNCTION__
, size
, readfreq
,
323 writefreq
, priority
);
325 if (!ctx
|| !(rmesa
= R200_CONTEXT(ctx
)) || !rmesa
->radeon
.radeonScreen
->gartTextures
.map
)
328 if (getenv("R200_NO_ALLOC"))
331 alloc
.region
= RADEON_MEM_REGION_GART
;
334 alloc
.region_offset
= ®ion_offset
;
336 ret
= drmCommandWriteRead( rmesa
->radeon
.radeonScreen
->driScreen
->fd
,
338 &alloc
, sizeof(alloc
));
341 fprintf(stderr
, "%s: DRM_RADEON_ALLOC ret %d\n", __FUNCTION__
, ret
);
346 char *region_start
= (char *)rmesa
->radeon
.radeonScreen
->gartTextures
.map
;
347 return (void *)(region_start
+ region_offset
);
352 /* Called via glXFreeMemoryMESA() */
353 void r200FreeMemoryMESA(__DRIscreen
*screen
, GLvoid
*pointer
)
355 GET_CURRENT_CONTEXT(ctx
);
356 r200ContextPtr rmesa
;
357 ptrdiff_t region_offset
;
358 drm_radeon_mem_free_t memfree
;
361 if (R200_DEBUG
& DEBUG_IOCTL
)
362 fprintf(stderr
, "%s %p\n", __FUNCTION__
, pointer
);
364 if (!ctx
|| !(rmesa
= R200_CONTEXT(ctx
)) || !rmesa
->radeon
.radeonScreen
->gartTextures
.map
) {
365 fprintf(stderr
, "%s: no context\n", __FUNCTION__
);
369 region_offset
= (char *)pointer
- (char *)rmesa
->radeon
.radeonScreen
->gartTextures
.map
;
371 if (region_offset
< 0 ||
372 region_offset
> rmesa
->radeon
.radeonScreen
->gartTextures
.size
) {
373 fprintf(stderr
, "offset %d outside range 0..%d\n", region_offset
,
374 rmesa
->radeon
.radeonScreen
->gartTextures
.size
);
378 memfree
.region
= RADEON_MEM_REGION_GART
;
379 memfree
.region_offset
= region_offset
;
381 ret
= drmCommandWrite( rmesa
->radeon
.radeonScreen
->driScreen
->fd
,
383 &memfree
, sizeof(memfree
));
386 fprintf(stderr
, "%s: DRM_RADEON_FREE ret %d\n", __FUNCTION__
, ret
);
389 /* Called via glXGetMemoryOffsetMESA() */
390 GLuint
r200GetMemoryOffsetMESA(__DRIscreen
*screen
, const GLvoid
*pointer
)
392 GET_CURRENT_CONTEXT(ctx
);
393 r200ContextPtr rmesa
;
396 if (!ctx
|| !(rmesa
= R200_CONTEXT(ctx
)) ) {
397 fprintf(stderr
, "%s: no context\n", __FUNCTION__
);
401 if (!r200IsGartMemory( rmesa
, pointer
, 0 ))
404 card_offset
= r200GartOffsetFromVirtual( rmesa
, pointer
);
406 return card_offset
- rmesa
->radeon
.radeonScreen
->gart_base
;
409 GLboolean
r200IsGartMemory( r200ContextPtr rmesa
, const GLvoid
*pointer
,
412 ptrdiff_t offset
= (char *)pointer
- (char *)rmesa
->radeon
.radeonScreen
->gartTextures
.map
;
413 int valid
= (size
>= 0 &&
415 offset
+ size
< rmesa
->radeon
.radeonScreen
->gartTextures
.size
);
417 if (R200_DEBUG
& DEBUG_IOCTL
)
418 fprintf(stderr
, "r200IsGartMemory( %p ) : %d\n", pointer
, valid
);
424 GLuint
r200GartOffsetFromVirtual( r200ContextPtr rmesa
, const GLvoid
*pointer
)
426 ptrdiff_t offset
= (char *)pointer
- (char *)rmesa
->radeon
.radeonScreen
->gartTextures
.map
;
428 if (offset
< 0 || offset
> rmesa
->radeon
.radeonScreen
->gartTextures
.size
)
431 return rmesa
->radeon
.radeonScreen
->gart_texture_offset
+ offset
;
436 void r200InitIoctlFuncs( struct dd_function_table
*functions
)
438 functions
->Clear
= r200Clear
;
439 functions
->Finish
= r200Finish
;
440 functions
->Flush
= r200Flush
;