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>
35 #include "r128_context.h"
36 #include "r128_state.h"
37 #include "r128_ioctl.h"
42 #include "swrast/swrast.h"
46 #define R128_TIMEOUT 2048
47 #define R128_IDLE_RETRY 32
50 /* =============================================================
51 * Hardware vertex buffer handling
54 /* Get a new VB from the pool of vertex buffers in AGP space.
56 drmBufPtr
r128GetBufferLocked( r128ContextPtr rmesa
)
58 int fd
= rmesa
->r128Screen
->driScreen
->fd
;
66 dma
.context
= rmesa
->hHWContext
;
69 dma
.send_sizes
= NULL
;
71 dma
.request_count
= 1;
72 dma
.request_size
= R128_BUFFER_SIZE
;
73 dma
.request_list
= &index
;
74 dma
.request_sizes
= &size
;
75 dma
.granted_count
= 0;
77 while ( !buf
&& ( to
++ < R128_TIMEOUT
) ) {
78 ret
= drmDMA( fd
, &dma
);
81 buf
= &rmesa
->r128Screen
->buffers
->list
[index
];
84 /* Bump the performance counter */
85 rmesa
->c_vertexBuffers
++;
92 drmCommandNone( fd
, DRM_R128_CCE_RESET
);
93 UNLOCK_HARDWARE( rmesa
);
94 fprintf( stderr
, "Error: Could not get new VB... exiting\n" );
101 void r128FlushVerticesLocked( r128ContextPtr rmesa
)
103 XF86DRIClipRectPtr pbox
= rmesa
->pClipRects
;
104 int nbox
= rmesa
->numClipRects
;
105 drmBufPtr buffer
= rmesa
->vert_buf
;
106 int count
= rmesa
->num_verts
;
107 int prim
= rmesa
->hw_primitive
;
108 int fd
= rmesa
->driScreen
->fd
;
109 drmR128Vertex vertex
;
112 rmesa
->num_verts
= 0;
113 rmesa
->vert_buf
= NULL
;
118 if ( rmesa
->dirty
& ~R128_UPLOAD_CLIPRECTS
)
119 r128EmitHwStateLocked( rmesa
);
124 if ( nbox
>= R128_NR_SAREA_CLIPRECTS
)
125 rmesa
->dirty
|= R128_UPLOAD_CLIPRECTS
;
127 if ( !count
|| !(rmesa
->dirty
& R128_UPLOAD_CLIPRECTS
) )
130 rmesa
->sarea
->nbox
= 0;
132 rmesa
->sarea
->nbox
= nbox
;
136 vertex
.idx
= buffer
->idx
;
137 vertex
.count
= count
;
139 drmCommandWrite( fd
, DRM_R128_VERTEX
, &vertex
, sizeof(drmR128Vertex
) );
143 for ( i
= 0 ; i
< nbox
; ) {
144 int nr
= MIN2( i
+ R128_NR_SAREA_CLIPRECTS
, nbox
);
145 XF86DRIClipRectPtr b
= rmesa
->sarea
->boxes
;
148 rmesa
->sarea
->nbox
= nr
- i
;
149 for ( ; i
< nr
; i
++ ) {
153 /* Finished with the buffer?
159 rmesa
->sarea
->dirty
|= R128_UPLOAD_CLIPRECTS
;
162 vertex
.idx
= buffer
->idx
;
163 vertex
.count
= count
;
164 vertex
.discard
= discard
;
165 drmCommandWrite( fd
, DRM_R128_VERTEX
, &vertex
, sizeof(drmR128Vertex
) );
169 rmesa
->dirty
&= ~R128_UPLOAD_CLIPRECTS
;
176 /* ================================================================
180 void r128FireBlitLocked( r128ContextPtr rmesa
, drmBufPtr buffer
,
181 GLint offset
, GLint pitch
, GLint format
,
182 GLint x
, GLint y
, GLint width
, GLint height
)
187 blit
.idx
= buffer
->idx
;
188 blit
.offset
= offset
;
190 blit
.format
= format
;
194 blit
.height
= height
;
196 ret
= drmCommandWrite( rmesa
->driFd
, DRM_R128_BLIT
,
197 &blit
, sizeof(drmR128Blit
) );
200 UNLOCK_HARDWARE( rmesa
);
201 fprintf( stderr
, "DRM_R128_BLIT: return = %d\n", ret
);
207 /* ================================================================
208 * SwapBuffers with client-side throttling
211 static void delay( void ) {
212 /* Prevent an optimizing compiler from removing a spin loop */
215 #define R128_MAX_OUTSTANDING 2
217 /* Throttle the frame rate -- only allow one pending swap buffers
219 * GH: We probably don't want a timeout here, as we can wait as
220 * long as we want for a frame to complete. If it never does, then
221 * the card has locked.
223 static int r128WaitForFrameCompletion( r128ContextPtr rmesa
)
225 unsigned char *R128MMIO
= rmesa
->r128Screen
->mmio
.map
;
231 frame
= INREG( R128_LAST_FRAME_REG
);
232 if ( rmesa
->sarea
->last_frame
- frame
<= R128_MAX_OUTSTANDING
) {
236 /* Spin in place a bit so we aren't hammering the register */
238 for ( i
= 0 ; i
< 1024 ; i
++ ) {
246 /* Copy the back color buffer to the front color buffer.
248 void r128CopyBuffer( const __DRIdrawablePrivate
*dPriv
)
250 r128ContextPtr rmesa
;
252 GLboolean missed_target
;
255 assert(dPriv
->driContextPriv
);
256 assert(dPriv
->driContextPriv
->driverPrivate
);
258 rmesa
= (r128ContextPtr
) dPriv
->driContextPriv
->driverPrivate
;
260 if ( R128_DEBUG
& DEBUG_VERBOSE_API
) {
261 fprintf( stderr
, "\n********************************\n" );
262 fprintf( stderr
, "\n%s( %p )\n\n",
263 __FUNCTION__
, rmesa
->glCtx
);
267 FLUSH_BATCH( rmesa
);
269 LOCK_HARDWARE( rmesa
);
271 /* Throttle the frame rate -- only allow one pending swap buffers
274 if ( !r128WaitForFrameCompletion( rmesa
) ) {
275 rmesa
->hardwareWentIdle
= 1;
277 rmesa
->hardwareWentIdle
= 0;
280 UNLOCK_HARDWARE( rmesa
);
281 driWaitForVBlank( dPriv
, &rmesa
->vbl_seq
, rmesa
->vblank_flags
, &missed_target
);
282 LOCK_HARDWARE( rmesa
);
284 nbox
= dPriv
->numClipRects
; /* must be in locked region */
286 for ( i
= 0 ; i
< nbox
; ) {
287 GLint nr
= MIN2( i
+ R128_NR_SAREA_CLIPRECTS
, nbox
);
288 XF86DRIClipRectPtr box
= dPriv
->pClipRects
;
289 XF86DRIClipRectPtr b
= rmesa
->sarea
->boxes
;
292 for ( ; i
< nr
; i
++ ) {
293 *b
++ = *(XF86DRIClipRectRec
*)&box
[i
];
296 rmesa
->sarea
->nbox
= n
;
298 ret
= drmCommandNone( rmesa
->driFd
, DRM_R128_SWAP
);
301 UNLOCK_HARDWARE( rmesa
);
302 fprintf( stderr
, "DRM_R128_SWAP: return = %d\n", ret
);
307 if ( R128_DEBUG
& DEBUG_ALWAYS_SYNC
) {
310 ret
= drmCommandNone(rmesa
->driFd
, DRM_R128_CCE_IDLE
);
311 } while ( ret
&& errno
== EBUSY
&& i
++ < R128_IDLE_RETRY
);
314 UNLOCK_HARDWARE( rmesa
);
316 rmesa
->new_state
|= R128_NEW_CONTEXT
;
317 rmesa
->dirty
|= (R128_UPLOAD_CONTEXT
|
319 R128_UPLOAD_CLIPRECTS
);
321 #if ENABLE_PERF_BOXES
322 /* Log the performance counters if necessary */
323 r128PerformanceCounters( rmesa
);
327 void r128PageFlip( const __DRIdrawablePrivate
*dPriv
)
329 r128ContextPtr rmesa
;
331 GLboolean missed_target
;
334 assert(dPriv
->driContextPriv
);
335 assert(dPriv
->driContextPriv
->driverPrivate
);
337 rmesa
= (r128ContextPtr
) dPriv
->driContextPriv
->driverPrivate
;
339 if ( R128_DEBUG
& DEBUG_VERBOSE_API
) {
340 fprintf( stderr
, "\n%s( %p ): page=%d\n\n",
341 __FUNCTION__
, rmesa
->glCtx
, rmesa
->sarea
->pfCurrentPage
);
344 FLUSH_BATCH( rmesa
);
346 LOCK_HARDWARE( rmesa
);
348 /* Throttle the frame rate -- only allow one pending swap buffers
351 if ( !r128WaitForFrameCompletion( rmesa
) ) {
352 rmesa
->hardwareWentIdle
= 1;
354 rmesa
->hardwareWentIdle
= 0;
357 UNLOCK_HARDWARE( rmesa
);
358 driWaitForVBlank( dPriv
, &rmesa
->vbl_seq
, rmesa
->vblank_flags
, &missed_target
);
359 LOCK_HARDWARE( rmesa
);
361 /* The kernel will have been initialized to perform page flipping
362 * on a swapbuffers ioctl.
364 ret
= drmCommandNone( rmesa
->driFd
, DRM_R128_FLIP
);
366 UNLOCK_HARDWARE( rmesa
);
369 fprintf( stderr
, "DRM_R128_FLIP: return = %d\n", ret
);
373 if ( rmesa
->sarea
->pfCurrentPage
== 1 ) {
374 rmesa
->drawOffset
= rmesa
->r128Screen
->frontOffset
;
375 rmesa
->drawPitch
= rmesa
->r128Screen
->frontPitch
;
377 rmesa
->drawOffset
= rmesa
->r128Screen
->backOffset
;
378 rmesa
->drawPitch
= rmesa
->r128Screen
->backPitch
;
381 rmesa
->setup
.dst_pitch_offset_c
= (((rmesa
->drawPitch
/8) << 21) |
382 (rmesa
->drawOffset
>> 5));
383 rmesa
->new_state
|= R128_NEW_WINDOW
;
385 /* FIXME: Do we need this anymore? */
386 rmesa
->new_state
|= R128_NEW_CONTEXT
;
387 rmesa
->dirty
|= (R128_UPLOAD_CONTEXT
|
389 R128_UPLOAD_CLIPRECTS
);
391 #if ENABLE_PERF_BOXES
392 /* Log the performance counters if necessary */
393 r128PerformanceCounters( rmesa
);
398 /* ================================================================
402 static void r128DDClear( GLcontext
*ctx
, GLbitfield mask
, GLboolean all
,
403 GLint cx
, GLint cy
, GLint cw
, GLint ch
)
405 r128ContextPtr rmesa
= R128_CONTEXT(ctx
);
406 __DRIdrawablePrivate
*dPriv
= rmesa
->driDrawable
;
412 if ( R128_DEBUG
& DEBUG_VERBOSE_API
) {
413 fprintf( stderr
, "%s:\n", __FUNCTION__
);
416 FLUSH_BATCH( rmesa
);
418 /* The only state change we care about here is the RGBA colormask
419 * We'll just update that state, if needed. If we do more then
420 * there's some strange side-effects that the conformance tests find.
422 if ( rmesa
->new_state
& R128_NEW_MASKS
) {
423 const GLuint save_state
= rmesa
->new_state
;
424 rmesa
->new_state
= R128_NEW_MASKS
;
425 r128DDUpdateHWState( ctx
);
426 rmesa
->new_state
= save_state
& ~R128_NEW_MASKS
;
429 if ( mask
& DD_FRONT_LEFT_BIT
) {
430 flags
|= DRM_R128_FRONT_BUFFER
;
431 mask
&= ~DD_FRONT_LEFT_BIT
;
434 if ( mask
& DD_BACK_LEFT_BIT
) {
435 flags
|= DRM_R128_BACK_BUFFER
;
436 mask
&= ~DD_BACK_LEFT_BIT
;
439 if ( ( mask
& DD_DEPTH_BIT
) && ctx
->Depth
.Mask
) {
440 flags
|= DRM_R128_DEPTH_BUFFER
;
441 mask
&= ~DD_DEPTH_BIT
;
444 /* FIXME: Add stencil support */
445 if ( mask
& DD_STENCIL_BIT
) {
446 flags
|= DRM_R128_DEPTH_BUFFER
;
447 mask
&= ~DD_STENCIL_BIT
;
453 /* Flip top to bottom */
455 cy
= dPriv
->y
+ dPriv
->h
- cy
- ch
;
457 LOCK_HARDWARE( rmesa
);
459 /* FIXME: Do we actually need this?
461 if ( rmesa
->dirty
& ~R128_UPLOAD_CLIPRECTS
) {
462 r128EmitHwStateLocked( rmesa
);
465 for ( i
= 0 ; i
< rmesa
->numClipRects
; ) {
466 GLint nr
= MIN2( i
+ R128_NR_SAREA_CLIPRECTS
, rmesa
->numClipRects
);
467 XF86DRIClipRectPtr box
= rmesa
->pClipRects
;
468 XF86DRIClipRectPtr b
= rmesa
->sarea
->boxes
;
472 for ( ; i
< nr
; i
++ ) {
475 GLint w
= box
[i
].x2
- x
;
476 GLint h
= box
[i
].y2
- y
;
478 if ( x
< cx
) w
-= cx
- x
, x
= cx
;
479 if ( y
< cy
) h
-= cy
- y
, y
= cy
;
480 if ( x
+ w
> cx
+ cw
) w
= cx
+ cw
- x
;
481 if ( y
+ h
> cy
+ ch
) h
= cy
+ ch
- y
;
482 if ( w
<= 0 ) continue;
483 if ( h
<= 0 ) continue;
493 for ( ; i
< nr
; i
++ ) {
494 *b
++ = *(XF86DRIClipRectPtr
)&box
[i
];
499 rmesa
->sarea
->nbox
= n
;
501 if ( R128_DEBUG
& DEBUG_VERBOSE_IOCTL
) {
503 "DRM_R128_CLEAR: flag 0x%x color %x depth %x nbox %d\n",
505 (GLuint
)rmesa
->ClearColor
,
506 (GLuint
)rmesa
->ClearDepth
,
507 rmesa
->sarea
->nbox
);
511 clear
.clear_color
= rmesa
->ClearColor
;
512 clear
.clear_depth
= rmesa
->ClearDepth
;
513 clear
.color_mask
= rmesa
->setup
.plane_3d_mask_c
;
514 clear
.depth_mask
= ~0;
516 ret
= drmCommandWrite( rmesa
->driFd
, DRM_R128_CLEAR
,
517 &clear
, sizeof(drmR128Clear
) );
520 UNLOCK_HARDWARE( rmesa
);
521 fprintf( stderr
, "DRM_R128_CLEAR: return = %d\n", ret
);
526 UNLOCK_HARDWARE( rmesa
);
528 rmesa
->dirty
|= R128_UPLOAD_CLIPRECTS
;
532 _swrast_Clear( ctx
, mask
, all
, cx
, cy
, cw
, ch
);
536 /* ================================================================
537 * Depth spans, pixels
540 void r128WriteDepthSpanLocked( r128ContextPtr rmesa
,
541 GLuint n
, GLint x
, GLint y
,
542 const GLdepth depth
[],
543 const GLubyte mask
[] )
545 XF86DRIClipRectPtr pbox
= rmesa
->pClipRects
;
547 int nbox
= rmesa
->numClipRects
;
548 int fd
= rmesa
->driScreen
->fd
;
554 if ( nbox
>= R128_NR_SAREA_CLIPRECTS
) {
555 rmesa
->dirty
|= R128_UPLOAD_CLIPRECTS
;
558 if ( !(rmesa
->dirty
& R128_UPLOAD_CLIPRECTS
) )
561 rmesa
->sarea
->nbox
= 0;
563 rmesa
->sarea
->nbox
= nbox
;
566 d
.func
= DRM_R128_WRITE_SPAN
;
570 d
.buffer
= (unsigned int *)depth
;
571 d
.mask
= (unsigned char *)mask
;
573 drmCommandWrite( fd
, DRM_R128_DEPTH
, &d
, sizeof(drmR128Depth
));
578 for (i
= 0 ; i
< nbox
; ) {
579 int nr
= MIN2( i
+ R128_NR_SAREA_CLIPRECTS
, nbox
);
580 XF86DRIClipRectPtr b
= rmesa
->sarea
->boxes
;
582 rmesa
->sarea
->nbox
= nr
- i
;
583 for ( ; i
< nr
; i
++) {
587 rmesa
->sarea
->dirty
|= R128_UPLOAD_CLIPRECTS
;
589 d
.func
= DRM_R128_WRITE_SPAN
;
593 d
.buffer
= (unsigned int *)depth
;
594 d
.mask
= (unsigned char *)mask
;
596 drmCommandWrite( fd
, DRM_R128_DEPTH
, &d
, sizeof(drmR128Depth
));
600 rmesa
->dirty
&= ~R128_UPLOAD_CLIPRECTS
;
603 void r128WriteDepthPixelsLocked( r128ContextPtr rmesa
, GLuint n
,
604 const GLint x
[], const GLint y
[],
605 const GLdepth depth
[],
606 const GLubyte mask
[] )
608 XF86DRIClipRectPtr pbox
= rmesa
->pClipRects
;
610 int nbox
= rmesa
->numClipRects
;
611 int fd
= rmesa
->driScreen
->fd
;
617 if ( nbox
>= R128_NR_SAREA_CLIPRECTS
) {
618 rmesa
->dirty
|= R128_UPLOAD_CLIPRECTS
;
621 if ( !(rmesa
->dirty
& R128_UPLOAD_CLIPRECTS
) )
624 rmesa
->sarea
->nbox
= 0;
626 rmesa
->sarea
->nbox
= nbox
;
629 d
.func
= DRM_R128_WRITE_PIXELS
;
633 d
.buffer
= (unsigned int *)depth
;
634 d
.mask
= (unsigned char *)mask
;
636 drmCommandWrite( fd
, DRM_R128_DEPTH
, &d
, sizeof(drmR128Depth
));
640 for (i
= 0 ; i
< nbox
; ) {
641 int nr
= MIN2( i
+ R128_NR_SAREA_CLIPRECTS
, nbox
);
642 XF86DRIClipRectPtr b
= rmesa
->sarea
->boxes
;
644 rmesa
->sarea
->nbox
= nr
- i
;
645 for ( ; i
< nr
; i
++) {
649 rmesa
->sarea
->dirty
|= R128_UPLOAD_CLIPRECTS
;
651 d
.func
= DRM_R128_WRITE_PIXELS
;
655 d
.buffer
= (unsigned int *)depth
;
656 d
.mask
= (unsigned char *)mask
;
658 drmCommandWrite( fd
, DRM_R128_DEPTH
, &d
, sizeof(drmR128Depth
));
662 rmesa
->dirty
&= ~R128_UPLOAD_CLIPRECTS
;
665 void r128ReadDepthSpanLocked( r128ContextPtr rmesa
,
666 GLuint n
, GLint x
, GLint y
)
668 XF86DRIClipRectPtr pbox
= rmesa
->pClipRects
;
670 int nbox
= rmesa
->numClipRects
;
671 int fd
= rmesa
->driScreen
->fd
;
677 if ( nbox
>= R128_NR_SAREA_CLIPRECTS
) {
678 rmesa
->dirty
|= R128_UPLOAD_CLIPRECTS
;
681 if ( !(rmesa
->dirty
& R128_UPLOAD_CLIPRECTS
) )
684 rmesa
->sarea
->nbox
= 0;
686 rmesa
->sarea
->nbox
= nbox
;
689 d
.func
= DRM_R128_READ_SPAN
;
696 drmCommandWrite( fd
, DRM_R128_DEPTH
, &d
, sizeof(drmR128Depth
));
700 for (i
= 0 ; i
< nbox
; ) {
701 int nr
= MIN2( i
+ R128_NR_SAREA_CLIPRECTS
, nbox
);
702 XF86DRIClipRectPtr b
= rmesa
->sarea
->boxes
;
704 rmesa
->sarea
->nbox
= nr
- i
;
705 for ( ; i
< nr
; i
++) {
709 rmesa
->sarea
->dirty
|= R128_UPLOAD_CLIPRECTS
;
711 d
.func
= DRM_R128_READ_SPAN
;
718 drmCommandWrite( fd
, DRM_R128_DEPTH
, &d
, sizeof(drmR128Depth
));
722 rmesa
->dirty
&= ~R128_UPLOAD_CLIPRECTS
;
725 void r128ReadDepthPixelsLocked( r128ContextPtr rmesa
, GLuint n
,
726 const GLint x
[], const GLint y
[] )
728 XF86DRIClipRectPtr pbox
= rmesa
->pClipRects
;
730 int nbox
= rmesa
->numClipRects
;
731 int fd
= rmesa
->driScreen
->fd
;
737 if ( nbox
>= R128_NR_SAREA_CLIPRECTS
) {
738 rmesa
->dirty
|= R128_UPLOAD_CLIPRECTS
;
741 if ( !(rmesa
->dirty
& R128_UPLOAD_CLIPRECTS
) )
744 rmesa
->sarea
->nbox
= 0;
746 rmesa
->sarea
->nbox
= nbox
;
749 d
.func
= DRM_R128_READ_PIXELS
;
756 drmCommandWrite( fd
, DRM_R128_DEPTH
, &d
, sizeof(drmR128Depth
));
760 for (i
= 0 ; i
< nbox
; ) {
761 int nr
= MIN2( i
+ R128_NR_SAREA_CLIPRECTS
, nbox
);
762 XF86DRIClipRectPtr b
= rmesa
->sarea
->boxes
;
764 rmesa
->sarea
->nbox
= nr
- i
;
765 for ( ; i
< nr
; i
++) {
769 rmesa
->sarea
->dirty
|= R128_UPLOAD_CLIPRECTS
;
771 d
.func
= DRM_R128_READ_PIXELS
;
778 drmCommandWrite( fd
, DRM_R128_DEPTH
, &d
, sizeof(drmR128Depth
));
782 rmesa
->dirty
&= ~R128_UPLOAD_CLIPRECTS
;
786 void r128WaitForIdleLocked( r128ContextPtr rmesa
)
788 int fd
= rmesa
->r128Screen
->driScreen
->fd
;
795 ret
= drmCommandNone( fd
, DRM_R128_CCE_IDLE
);
796 } while ( ret
&& errno
== EBUSY
&& i
++ < R128_IDLE_RETRY
);
797 } while ( ( ret
== -EBUSY
) && ( to
++ < R128_TIMEOUT
) );
800 drmCommandNone( fd
, DRM_R128_CCE_RESET
);
801 UNLOCK_HARDWARE( rmesa
);
802 fprintf( stderr
, "Error: Rage 128 timed out... exiting\n" );
807 void r128DDInitIoctlFuncs( GLcontext
*ctx
)
809 ctx
->Driver
.Clear
= r128DDClear
;