1 /* $XFree86: xc/lib/GL/mesa/src/drv/r128/r128_ioctl.c,v 1.10 2002/12/16 16:18:53 dawes Exp $ */
2 /**************************************************************************
4 Copyright 1999, 2000 ATI Technologies Inc. and Precision Insight, Inc.,
8 Permission is hereby granted, free of charge, to any person obtaining a
9 copy of this software and associated documentation files (the "Software"),
10 to deal in the Software without restriction, including without limitation
11 on the rights to use, copy, modify, merge, publish, distribute, sub
12 license, and/or sell copies of the Software, and to permit persons to whom
13 the Software is furnished to do so, subject to the following conditions:
15 The above copyright notice and this permission notice (including the next
16 paragraph) shall be included in all copies or substantial portions of the
19 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
22 ATI, PRECISION INSIGHT AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
23 DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
24 OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
25 USE OR OTHER DEALINGS IN THE SOFTWARE.
27 **************************************************************************/
31 * Gareth Hughes <gareth@valinux.com>
36 #define STANDALONE_MMIO
37 #include "r128_context.h"
38 #include "r128_state.h"
39 #include "r128_ioctl.h"
43 #include "swrast/swrast.h"
47 #define R128_TIMEOUT 2048
48 #define R128_IDLE_RETRY 32
51 /* =============================================================
52 * Hardware vertex buffer handling
55 /* Get a new VB from the pool of vertex buffers in AGP space.
57 drmBufPtr
r128GetBufferLocked( r128ContextPtr rmesa
)
59 int fd
= rmesa
->r128Screen
->driScreen
->fd
;
67 dma
.context
= rmesa
->hHWContext
;
70 dma
.send_sizes
= NULL
;
72 dma
.request_count
= 1;
73 dma
.request_size
= R128_BUFFER_SIZE
;
74 dma
.request_list
= &index
;
75 dma
.request_sizes
= &size
;
76 dma
.granted_count
= 0;
78 while ( !buf
&& ( to
++ < R128_TIMEOUT
) ) {
79 ret
= drmDMA( fd
, &dma
);
82 buf
= &rmesa
->r128Screen
->buffers
->list
[index
];
85 /* Bump the performance counter */
86 rmesa
->c_vertexBuffers
++;
93 drmCommandNone( fd
, DRM_R128_CCE_RESET
);
94 UNLOCK_HARDWARE( rmesa
);
95 fprintf( stderr
, "Error: Could not get new VB... exiting\n" );
102 void r128FlushVerticesLocked( r128ContextPtr rmesa
)
104 drm_clip_rect_t
*pbox
= rmesa
->pClipRects
;
105 int nbox
= rmesa
->numClipRects
;
106 drmBufPtr buffer
= rmesa
->vert_buf
;
107 int count
= rmesa
->num_verts
;
108 int prim
= rmesa
->hw_primitive
;
109 int fd
= rmesa
->driScreen
->fd
;
110 drm_r128_vertex_t vertex
;
113 rmesa
->num_verts
= 0;
114 rmesa
->vert_buf
= NULL
;
119 if ( rmesa
->dirty
& ~R128_UPLOAD_CLIPRECTS
)
120 r128EmitHwStateLocked( rmesa
);
125 if ( nbox
>= R128_NR_SAREA_CLIPRECTS
)
126 rmesa
->dirty
|= R128_UPLOAD_CLIPRECTS
;
128 if ( !count
|| !(rmesa
->dirty
& R128_UPLOAD_CLIPRECTS
) )
131 rmesa
->sarea
->nbox
= 0;
133 rmesa
->sarea
->nbox
= nbox
;
137 vertex
.idx
= buffer
->idx
;
138 vertex
.count
= count
;
140 drmCommandWrite( fd
, DRM_R128_VERTEX
, &vertex
, sizeof(vertex
) );
144 for ( i
= 0 ; i
< nbox
; ) {
145 int nr
= MIN2( i
+ R128_NR_SAREA_CLIPRECTS
, nbox
);
146 drm_clip_rect_t
*b
= rmesa
->sarea
->boxes
;
149 rmesa
->sarea
->nbox
= nr
- i
;
150 for ( ; i
< nr
; i
++ ) {
154 /* Finished with the buffer?
160 rmesa
->sarea
->dirty
|= R128_UPLOAD_CLIPRECTS
;
163 vertex
.idx
= buffer
->idx
;
164 vertex
.count
= count
;
165 vertex
.discard
= discard
;
166 drmCommandWrite( fd
, DRM_R128_VERTEX
, &vertex
, sizeof(vertex
) );
170 rmesa
->dirty
&= ~R128_UPLOAD_CLIPRECTS
;
177 /* ================================================================
181 void r128FireBlitLocked( r128ContextPtr rmesa
, drmBufPtr buffer
,
182 GLint offset
, GLint pitch
, GLint format
,
183 GLint x
, GLint y
, GLint width
, GLint height
)
185 drm_r128_blit_t blit
;
188 blit
.idx
= buffer
->idx
;
189 blit
.offset
= offset
;
191 blit
.format
= format
;
195 blit
.height
= height
;
197 ret
= drmCommandWrite( rmesa
->driFd
, DRM_R128_BLIT
,
198 &blit
, sizeof(blit
) );
201 UNLOCK_HARDWARE( rmesa
);
202 fprintf( stderr
, "DRM_R128_BLIT: return = %d\n", ret
);
208 /* ================================================================
209 * SwapBuffers with client-side throttling
212 static void delay( void ) {
213 /* Prevent an optimizing compiler from removing a spin loop */
216 #define R128_MAX_OUTSTANDING 2
219 /* Throttle the frame rate -- only allow one pending swap buffers
221 * GH: We probably don't want a timeout here, as we can wait as
222 * long as we want for a frame to complete. If it never does, then
223 * the card has locked.
225 static int r128WaitForFrameCompletion( r128ContextPtr rmesa
)
227 unsigned char *R128MMIO
= rmesa
->r128Screen
->mmio
.map
;
233 frame
= *(volatile unsigned int *)(R128MMIO
+ R128_LAST_FRAME_REG
);
235 if ( rmesa
->sarea
->last_frame
- frame
<= R128_MAX_OUTSTANDING
) {
239 /* Spin in place a bit so we aren't hammering the register */
241 for ( i
= 0 ; i
< 1024 ; i
++ ) {
249 /* Copy the back color buffer to the front color buffer.
251 void r128CopyBuffer( const __DRIdrawablePrivate
*dPriv
)
253 r128ContextPtr rmesa
;
255 GLboolean missed_target
;
258 assert(dPriv
->driContextPriv
);
259 assert(dPriv
->driContextPriv
->driverPrivate
);
261 rmesa
= (r128ContextPtr
) dPriv
->driContextPriv
->driverPrivate
;
263 if ( R128_DEBUG
& DEBUG_VERBOSE_API
) {
264 fprintf( stderr
, "\n********************************\n" );
265 fprintf( stderr
, "\n%s( %p )\n\n",
266 __FUNCTION__
, (void *)rmesa
->glCtx
);
270 FLUSH_BATCH( rmesa
);
272 LOCK_HARDWARE( rmesa
);
274 /* Throttle the frame rate -- only allow one pending swap buffers
277 if ( !r128WaitForFrameCompletion( rmesa
) ) {
278 rmesa
->hardwareWentIdle
= 1;
280 rmesa
->hardwareWentIdle
= 0;
283 UNLOCK_HARDWARE( rmesa
);
284 driWaitForVBlank( dPriv
, &rmesa
->vbl_seq
, rmesa
->vblank_flags
, &missed_target
);
285 LOCK_HARDWARE( rmesa
);
287 nbox
= dPriv
->numClipRects
; /* must be in locked region */
289 for ( i
= 0 ; i
< nbox
; ) {
290 GLint nr
= MIN2( i
+ R128_NR_SAREA_CLIPRECTS
, nbox
);
291 drm_clip_rect_t
*box
= dPriv
->pClipRects
;
292 drm_clip_rect_t
*b
= rmesa
->sarea
->boxes
;
295 for ( ; i
< nr
; i
++ ) {
299 rmesa
->sarea
->nbox
= n
;
301 ret
= drmCommandNone( rmesa
->driFd
, DRM_R128_SWAP
);
304 UNLOCK_HARDWARE( rmesa
);
305 fprintf( stderr
, "DRM_R128_SWAP: return = %d\n", ret
);
310 if ( R128_DEBUG
& DEBUG_ALWAYS_SYNC
) {
313 ret
= drmCommandNone(rmesa
->driFd
, DRM_R128_CCE_IDLE
);
314 } while ( ret
&& errno
== EBUSY
&& i
++ < R128_IDLE_RETRY
);
317 UNLOCK_HARDWARE( rmesa
);
319 rmesa
->new_state
|= R128_NEW_CONTEXT
;
320 rmesa
->dirty
|= (R128_UPLOAD_CONTEXT
|
322 R128_UPLOAD_CLIPRECTS
);
324 #if ENABLE_PERF_BOXES
325 /* Log the performance counters if necessary */
326 r128PerformanceCounters( rmesa
);
330 void r128PageFlip( const __DRIdrawablePrivate
*dPriv
)
332 r128ContextPtr rmesa
;
334 GLboolean missed_target
;
337 assert(dPriv
->driContextPriv
);
338 assert(dPriv
->driContextPriv
->driverPrivate
);
340 rmesa
= (r128ContextPtr
) dPriv
->driContextPriv
->driverPrivate
;
342 if ( R128_DEBUG
& DEBUG_VERBOSE_API
) {
343 fprintf( stderr
, "\n%s( %p ): page=%d\n\n",
344 __FUNCTION__
, (void *)rmesa
->glCtx
, rmesa
->sarea
->pfCurrentPage
);
347 FLUSH_BATCH( rmesa
);
349 LOCK_HARDWARE( rmesa
);
351 /* Throttle the frame rate -- only allow one pending swap buffers
354 if ( !r128WaitForFrameCompletion( rmesa
) ) {
355 rmesa
->hardwareWentIdle
= 1;
357 rmesa
->hardwareWentIdle
= 0;
360 UNLOCK_HARDWARE( rmesa
);
361 driWaitForVBlank( dPriv
, &rmesa
->vbl_seq
, rmesa
->vblank_flags
, &missed_target
);
362 LOCK_HARDWARE( rmesa
);
364 /* The kernel will have been initialized to perform page flipping
365 * on a swapbuffers ioctl.
367 ret
= drmCommandNone( rmesa
->driFd
, DRM_R128_FLIP
);
369 UNLOCK_HARDWARE( rmesa
);
372 fprintf( stderr
, "DRM_R128_FLIP: return = %d\n", ret
);
376 if ( rmesa
->sarea
->pfCurrentPage
== 1 ) {
377 rmesa
->drawOffset
= rmesa
->r128Screen
->frontOffset
;
378 rmesa
->drawPitch
= rmesa
->r128Screen
->frontPitch
;
380 rmesa
->drawOffset
= rmesa
->r128Screen
->backOffset
;
381 rmesa
->drawPitch
= rmesa
->r128Screen
->backPitch
;
384 rmesa
->setup
.dst_pitch_offset_c
= (((rmesa
->drawPitch
/8) << 21) |
385 (rmesa
->drawOffset
>> 5));
386 rmesa
->new_state
|= R128_NEW_WINDOW
;
388 /* FIXME: Do we need this anymore? */
389 rmesa
->new_state
|= R128_NEW_CONTEXT
;
390 rmesa
->dirty
|= (R128_UPLOAD_CONTEXT
|
392 R128_UPLOAD_CLIPRECTS
);
394 #if ENABLE_PERF_BOXES
395 /* Log the performance counters if necessary */
396 r128PerformanceCounters( rmesa
);
401 /* ================================================================
405 static void r128Clear( GLcontext
*ctx
, GLbitfield mask
, GLboolean all
,
406 GLint cx
, GLint cy
, GLint cw
, GLint ch
)
408 r128ContextPtr rmesa
= R128_CONTEXT(ctx
);
409 __DRIdrawablePrivate
*dPriv
= rmesa
->driDrawable
;
410 drm_r128_clear_t clear
;
415 if ( R128_DEBUG
& DEBUG_VERBOSE_API
) {
416 fprintf( stderr
, "%s:\n", __FUNCTION__
);
419 FLUSH_BATCH( rmesa
);
421 /* The only state change we care about here is the RGBA colormask
422 * We'll just update that state, if needed. If we do more then
423 * there's some strange side-effects that the conformance tests find.
425 if ( rmesa
->new_state
& R128_NEW_MASKS
) {
426 const GLuint save_state
= rmesa
->new_state
;
427 rmesa
->new_state
= R128_NEW_MASKS
;
428 r128DDUpdateHWState( ctx
);
429 rmesa
->new_state
= save_state
& ~R128_NEW_MASKS
;
432 if ( mask
& DD_FRONT_LEFT_BIT
) {
434 mask
&= ~DD_FRONT_LEFT_BIT
;
437 if ( mask
& DD_BACK_LEFT_BIT
) {
439 mask
&= ~DD_BACK_LEFT_BIT
;
442 if ( ( mask
& DD_DEPTH_BIT
) && ctx
->Depth
.Mask
) {
444 mask
&= ~DD_DEPTH_BIT
;
447 /* FIXME: Add stencil support */
448 if ( mask
& DD_STENCIL_BIT
) {
449 flags
|= DRM_R128_DEPTH_BUFFER
;
450 mask
&= ~DD_STENCIL_BIT
;
456 /* Flip top to bottom */
458 cy
= dPriv
->y
+ dPriv
->h
- cy
- ch
;
460 LOCK_HARDWARE( rmesa
);
462 /* FIXME: Do we actually need this?
464 if ( rmesa
->dirty
& ~R128_UPLOAD_CLIPRECTS
) {
465 r128EmitHwStateLocked( rmesa
);
468 for ( i
= 0 ; i
< rmesa
->numClipRects
; ) {
469 GLint nr
= MIN2( i
+ R128_NR_SAREA_CLIPRECTS
, rmesa
->numClipRects
);
470 drm_clip_rect_t
*box
= rmesa
->pClipRects
;
471 drm_clip_rect_t
*b
= rmesa
->sarea
->boxes
;
475 for ( ; i
< nr
; i
++ ) {
478 GLint w
= box
[i
].x2
- x
;
479 GLint h
= box
[i
].y2
- y
;
481 if ( x
< cx
) w
-= cx
- x
, x
= cx
;
482 if ( y
< cy
) h
-= cy
- y
, y
= cy
;
483 if ( x
+ w
> cx
+ cw
) w
= cx
+ cw
- x
;
484 if ( y
+ h
> cy
+ ch
) h
= cy
+ ch
- y
;
485 if ( w
<= 0 ) continue;
486 if ( h
<= 0 ) continue;
496 for ( ; i
< nr
; i
++ ) {
502 rmesa
->sarea
->nbox
= n
;
504 if ( R128_DEBUG
& DEBUG_VERBOSE_IOCTL
) {
506 "DRM_R128_CLEAR: flag 0x%x color %x depth %x nbox %d\n",
508 (GLuint
)rmesa
->ClearColor
,
509 (GLuint
)rmesa
->ClearDepth
,
510 rmesa
->sarea
->nbox
);
514 clear
.clear_color
= rmesa
->ClearColor
;
515 clear
.clear_depth
= rmesa
->ClearDepth
;
516 clear
.color_mask
= rmesa
->setup
.plane_3d_mask_c
;
517 clear
.depth_mask
= ~0;
519 ret
= drmCommandWrite( rmesa
->driFd
, DRM_R128_CLEAR
,
520 &clear
, sizeof(clear
) );
523 UNLOCK_HARDWARE( rmesa
);
524 fprintf( stderr
, "DRM_R128_CLEAR: return = %d\n", ret
);
529 UNLOCK_HARDWARE( rmesa
);
531 rmesa
->dirty
|= R128_UPLOAD_CLIPRECTS
;
535 _swrast_Clear( ctx
, mask
, all
, cx
, cy
, cw
, ch
);
539 /* ================================================================
540 * Depth spans, pixels
543 void r128WriteDepthSpanLocked( r128ContextPtr rmesa
,
544 GLuint n
, GLint x
, GLint y
,
545 const GLdepth depth
[],
546 const GLubyte mask
[] )
548 drm_clip_rect_t
*pbox
= rmesa
->pClipRects
;
550 int nbox
= rmesa
->numClipRects
;
551 int fd
= rmesa
->driScreen
->fd
;
557 if ( nbox
>= R128_NR_SAREA_CLIPRECTS
) {
558 rmesa
->dirty
|= R128_UPLOAD_CLIPRECTS
;
561 if ( !(rmesa
->dirty
& R128_UPLOAD_CLIPRECTS
) )
564 rmesa
->sarea
->nbox
= 0;
566 rmesa
->sarea
->nbox
= nbox
;
569 d
.func
= R128_WRITE_SPAN
;
573 d
.buffer
= (unsigned int *)depth
;
574 d
.mask
= (unsigned char *)mask
;
576 drmCommandWrite( fd
, DRM_R128_DEPTH
, &d
, sizeof(d
));
581 for (i
= 0 ; i
< nbox
; ) {
582 int nr
= MIN2( i
+ R128_NR_SAREA_CLIPRECTS
, nbox
);
583 drm_clip_rect_t
*b
= rmesa
->sarea
->boxes
;
585 rmesa
->sarea
->nbox
= nr
- i
;
586 for ( ; i
< nr
; i
++) {
590 rmesa
->sarea
->dirty
|= R128_UPLOAD_CLIPRECTS
;
592 d
.func
= R128_WRITE_SPAN
;
596 d
.buffer
= (unsigned int *)depth
;
597 d
.mask
= (unsigned char *)mask
;
599 drmCommandWrite( fd
, DRM_R128_DEPTH
, &d
, sizeof(d
));
603 rmesa
->dirty
&= ~R128_UPLOAD_CLIPRECTS
;
606 void r128WriteDepthPixelsLocked( r128ContextPtr rmesa
, GLuint n
,
607 const GLint x
[], const GLint y
[],
608 const GLdepth depth
[],
609 const GLubyte mask
[] )
611 drm_clip_rect_t
*pbox
= rmesa
->pClipRects
;
613 int nbox
= rmesa
->numClipRects
;
614 int fd
= rmesa
->driScreen
->fd
;
620 if ( nbox
>= R128_NR_SAREA_CLIPRECTS
) {
621 rmesa
->dirty
|= R128_UPLOAD_CLIPRECTS
;
624 if ( !(rmesa
->dirty
& R128_UPLOAD_CLIPRECTS
) )
627 rmesa
->sarea
->nbox
= 0;
629 rmesa
->sarea
->nbox
= nbox
;
632 d
.func
= R128_WRITE_PIXELS
;
636 d
.buffer
= (unsigned int *)depth
;
637 d
.mask
= (unsigned char *)mask
;
639 drmCommandWrite( fd
, DRM_R128_DEPTH
, &d
, sizeof(d
));
643 for (i
= 0 ; i
< nbox
; ) {
644 int nr
= MIN2( i
+ R128_NR_SAREA_CLIPRECTS
, nbox
);
645 drm_clip_rect_t
*b
= rmesa
->sarea
->boxes
;
647 rmesa
->sarea
->nbox
= nr
- i
;
648 for ( ; i
< nr
; i
++) {
652 rmesa
->sarea
->dirty
|= R128_UPLOAD_CLIPRECTS
;
654 d
.func
= R128_WRITE_PIXELS
;
658 d
.buffer
= (unsigned int *)depth
;
659 d
.mask
= (unsigned char *)mask
;
661 drmCommandWrite( fd
, DRM_R128_DEPTH
, &d
, sizeof(d
));
665 rmesa
->dirty
&= ~R128_UPLOAD_CLIPRECTS
;
668 void r128ReadDepthSpanLocked( r128ContextPtr rmesa
,
669 GLuint n
, GLint x
, GLint y
)
671 drm_clip_rect_t
*pbox
= rmesa
->pClipRects
;
673 int nbox
= rmesa
->numClipRects
;
674 int fd
= rmesa
->driScreen
->fd
;
680 if ( nbox
>= R128_NR_SAREA_CLIPRECTS
) {
681 rmesa
->dirty
|= R128_UPLOAD_CLIPRECTS
;
684 if ( !(rmesa
->dirty
& R128_UPLOAD_CLIPRECTS
) )
687 rmesa
->sarea
->nbox
= 0;
689 rmesa
->sarea
->nbox
= nbox
;
692 d
.func
= R128_READ_SPAN
;
699 drmCommandWrite( fd
, DRM_R128_DEPTH
, &d
, sizeof(d
));
703 for (i
= 0 ; i
< nbox
; ) {
704 int nr
= MIN2( i
+ R128_NR_SAREA_CLIPRECTS
, nbox
);
705 drm_clip_rect_t
*b
= rmesa
->sarea
->boxes
;
707 rmesa
->sarea
->nbox
= nr
- i
;
708 for ( ; i
< nr
; i
++) {
712 rmesa
->sarea
->dirty
|= R128_UPLOAD_CLIPRECTS
;
714 d
.func
= R128_READ_SPAN
;
721 drmCommandWrite( fd
, DRM_R128_DEPTH
, &d
, sizeof(d
));
725 rmesa
->dirty
&= ~R128_UPLOAD_CLIPRECTS
;
728 void r128ReadDepthPixelsLocked( r128ContextPtr rmesa
, GLuint n
,
729 const GLint x
[], const GLint y
[] )
731 drm_clip_rect_t
*pbox
= rmesa
->pClipRects
;
733 int nbox
= rmesa
->numClipRects
;
734 int fd
= rmesa
->driScreen
->fd
;
740 if ( nbox
>= R128_NR_SAREA_CLIPRECTS
) {
741 rmesa
->dirty
|= R128_UPLOAD_CLIPRECTS
;
744 if ( !(rmesa
->dirty
& R128_UPLOAD_CLIPRECTS
) )
747 rmesa
->sarea
->nbox
= 0;
749 rmesa
->sarea
->nbox
= nbox
;
752 d
.func
= R128_READ_PIXELS
;
759 drmCommandWrite( fd
, DRM_R128_DEPTH
, &d
, sizeof(d
));
763 for (i
= 0 ; i
< nbox
; ) {
764 int nr
= MIN2( i
+ R128_NR_SAREA_CLIPRECTS
, nbox
);
765 drm_clip_rect_t
*b
= rmesa
->sarea
->boxes
;
767 rmesa
->sarea
->nbox
= nr
- i
;
768 for ( ; i
< nr
; i
++) {
772 rmesa
->sarea
->dirty
|= R128_UPLOAD_CLIPRECTS
;
774 d
.func
= R128_READ_PIXELS
;
781 drmCommandWrite( fd
, DRM_R128_DEPTH
, &d
, sizeof(d
));
785 rmesa
->dirty
&= ~R128_UPLOAD_CLIPRECTS
;
789 void r128WaitForIdleLocked( r128ContextPtr rmesa
)
791 int fd
= rmesa
->r128Screen
->driScreen
->fd
;
798 ret
= drmCommandNone( fd
, DRM_R128_CCE_IDLE
);
799 } while ( ret
&& errno
== EBUSY
&& i
++ < R128_IDLE_RETRY
);
800 } while ( ( ret
== -EBUSY
) && ( to
++ < R128_TIMEOUT
) );
803 drmCommandNone( fd
, DRM_R128_CCE_RESET
);
804 UNLOCK_HARDWARE( rmesa
);
805 fprintf( stderr
, "Error: Rage 128 timed out... exiting\n" );
810 void r128InitIoctlFuncs( struct dd_function_table
*functions
)
812 functions
->Clear
= r128Clear
;