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
= rmesa
->radeon
.dri
.drawable
;
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
= rmesa
->radeon
.dri
.drawable
;
195 GLuint color_mask
= 0;
196 GLuint orig_mask
= mask
;
198 if ( R200_DEBUG
& DEBUG_IOCTL
) {
199 fprintf( stderr
, "r200Clear %x %d\n", mask
, rmesa
->radeon
.sarea
->pfCurrentPage
);
203 LOCK_HARDWARE( &rmesa
->radeon
);
204 UNLOCK_HARDWARE( &rmesa
->radeon
);
205 if ( dPriv
->numClipRects
== 0 )
211 if ( mask
& BUFFER_BIT_FRONT_LEFT
) {
212 flags
|= RADEON_FRONT
;
213 color_mask
= rmesa
->hw
.msk
.cmd
[MSK_RB3D_PLANEMASK
];
214 mask
&= ~BUFFER_BIT_FRONT_LEFT
;
217 if ( mask
& BUFFER_BIT_BACK_LEFT
) {
218 flags
|= RADEON_BACK
;
219 color_mask
= rmesa
->hw
.msk
.cmd
[MSK_RB3D_PLANEMASK
];
220 mask
&= ~BUFFER_BIT_BACK_LEFT
;
223 if ( mask
& BUFFER_BIT_DEPTH
) {
224 flags
|= RADEON_DEPTH
;
225 mask
&= ~BUFFER_BIT_DEPTH
;
228 if ( (mask
& BUFFER_BIT_STENCIL
) ) {
229 flags
|= RADEON_STENCIL
;
230 mask
&= ~BUFFER_BIT_STENCIL
;
234 if (R200_DEBUG
& DEBUG_FALLBACKS
)
235 fprintf(stderr
, "%s: swrast clear, mask: %x\n", __FUNCTION__
, mask
);
236 _swrast_Clear( ctx
, mask
);
242 if (rmesa
->using_hyperz
) {
243 flags
|= RADEON_USE_COMP_ZBUF
;
244 /* if (rmesa->radeon.radeonScreen->chip_family == CHIP_FAMILY_R200)
245 flags |= RADEON_USE_HIERZ; */
246 if (!((flags
& RADEON_DEPTH
) && (flags
& RADEON_STENCIL
) &&
247 ((rmesa
->radeon
.state
.stencil
.clear
& R200_STENCIL_WRITE_MASK
) == R200_STENCIL_WRITE_MASK
))) {
248 flags
|= RADEON_CLEAR_FASTZ
;
252 if (rmesa
->radeon
.radeonScreen
->kernel_mm
)
253 r200UserClear(ctx
, orig_mask
);
255 r200KernelClear(ctx
, flags
);
256 rmesa
->radeon
.hw
.all_dirty
= GL_TRUE
;
260 /* This version of AllocateMemoryMESA allocates only GART memory, and
261 * only does so after the point at which the driver has been
264 * Theoretically a valid context isn't required. However, in this
265 * implementation, it is, as I'm using the hardware lock to protect
266 * the kernel data structures, and the current context to get the
269 void *r200AllocateMemoryMESA(__DRIscreen
*screen
, GLsizei size
,
270 GLfloat readfreq
, GLfloat writefreq
,
273 GET_CURRENT_CONTEXT(ctx
);
274 r200ContextPtr rmesa
;
276 drm_radeon_mem_alloc_t alloc
;
279 if (R200_DEBUG
& DEBUG_IOCTL
)
280 fprintf(stderr
, "%s sz %d %f/%f/%f\n", __FUNCTION__
, size
, readfreq
,
281 writefreq
, priority
);
283 if (!ctx
|| !(rmesa
= R200_CONTEXT(ctx
)) || !rmesa
->radeon
.radeonScreen
->gartTextures
.map
)
286 if (getenv("R200_NO_ALLOC"))
289 alloc
.region
= RADEON_MEM_REGION_GART
;
292 alloc
.region_offset
= ®ion_offset
;
294 ret
= drmCommandWriteRead( rmesa
->radeon
.radeonScreen
->driScreen
->fd
,
296 &alloc
, sizeof(alloc
));
299 fprintf(stderr
, "%s: DRM_RADEON_ALLOC ret %d\n", __FUNCTION__
, ret
);
304 char *region_start
= (char *)rmesa
->radeon
.radeonScreen
->gartTextures
.map
;
305 return (void *)(region_start
+ region_offset
);
310 /* Called via glXFreeMemoryMESA() */
311 void r200FreeMemoryMESA(__DRIscreen
*screen
, GLvoid
*pointer
)
313 GET_CURRENT_CONTEXT(ctx
);
314 r200ContextPtr rmesa
;
315 ptrdiff_t region_offset
;
316 drm_radeon_mem_free_t memfree
;
319 if (R200_DEBUG
& DEBUG_IOCTL
)
320 fprintf(stderr
, "%s %p\n", __FUNCTION__
, pointer
);
322 if (!ctx
|| !(rmesa
= R200_CONTEXT(ctx
)) || !rmesa
->radeon
.radeonScreen
->gartTextures
.map
) {
323 fprintf(stderr
, "%s: no context\n", __FUNCTION__
);
327 region_offset
= (char *)pointer
- (char *)rmesa
->radeon
.radeonScreen
->gartTextures
.map
;
329 if (region_offset
< 0 ||
330 region_offset
> rmesa
->radeon
.radeonScreen
->gartTextures
.size
) {
331 fprintf(stderr
, "offset %d outside range 0..%d\n", region_offset
,
332 rmesa
->radeon
.radeonScreen
->gartTextures
.size
);
336 memfree
.region
= RADEON_MEM_REGION_GART
;
337 memfree
.region_offset
= region_offset
;
339 ret
= drmCommandWrite( rmesa
->radeon
.radeonScreen
->driScreen
->fd
,
341 &memfree
, sizeof(memfree
));
344 fprintf(stderr
, "%s: DRM_RADEON_FREE ret %d\n", __FUNCTION__
, ret
);
347 /* Called via glXGetMemoryOffsetMESA() */
348 GLuint
r200GetMemoryOffsetMESA(__DRIscreen
*screen
, const GLvoid
*pointer
)
350 GET_CURRENT_CONTEXT(ctx
);
351 r200ContextPtr rmesa
;
354 if (!ctx
|| !(rmesa
= R200_CONTEXT(ctx
)) ) {
355 fprintf(stderr
, "%s: no context\n", __FUNCTION__
);
359 if (!r200IsGartMemory( rmesa
, pointer
, 0 ))
362 card_offset
= r200GartOffsetFromVirtual( rmesa
, pointer
);
364 return card_offset
- rmesa
->radeon
.radeonScreen
->gart_base
;
367 GLboolean
r200IsGartMemory( r200ContextPtr rmesa
, const GLvoid
*pointer
,
370 ptrdiff_t offset
= (char *)pointer
- (char *)rmesa
->radeon
.radeonScreen
->gartTextures
.map
;
371 int valid
= (size
>= 0 &&
373 offset
+ size
< rmesa
->radeon
.radeonScreen
->gartTextures
.size
);
375 if (R200_DEBUG
& DEBUG_IOCTL
)
376 fprintf(stderr
, "r200IsGartMemory( %p ) : %d\n", pointer
, valid
);
382 GLuint
r200GartOffsetFromVirtual( r200ContextPtr rmesa
, const GLvoid
*pointer
)
384 ptrdiff_t offset
= (char *)pointer
- (char *)rmesa
->radeon
.radeonScreen
->gartTextures
.map
;
386 if (offset
< 0 || offset
> rmesa
->radeon
.radeonScreen
->gartTextures
.size
)
389 return rmesa
->radeon
.radeonScreen
->gart_texture_offset
+ offset
;
394 void r200InitIoctlFuncs( struct dd_function_table
*functions
)
396 functions
->Clear
= r200Clear
;
397 functions
->Finish
= radeonFinish
;
398 functions
->Flush
= radeonFlush
;