7f9f7a923ea4adca80526684f31bd78736853705
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 #include "r128_context.h"
37 #include "r128_state.h"
38 #include "r128_ioctl.h"
42 #include "swrast/swrast.h"
47 /* temporary - should really split r128_reg.h into r128_reg.h & r128_macros.h
49 #include "r128_macros.h"
52 #define R128_TIMEOUT 2048
53 #define R128_IDLE_RETRY 32
56 /* =============================================================
57 * Hardware vertex buffer handling
60 /* Get a new VB from the pool of vertex buffers in AGP space.
62 drmBufPtr
r128GetBufferLocked( r128ContextPtr rmesa
)
64 int fd
= rmesa
->r128Screen
->driScreen
->fd
;
72 dma
.context
= rmesa
->hHWContext
;
75 dma
.send_sizes
= NULL
;
77 dma
.request_count
= 1;
78 dma
.request_size
= R128_BUFFER_SIZE
;
79 dma
.request_list
= &index
;
80 dma
.request_sizes
= &size
;
81 dma
.granted_count
= 0;
83 while ( !buf
&& ( to
++ < R128_TIMEOUT
) ) {
84 ret
= drmDMA( fd
, &dma
);
87 buf
= &rmesa
->r128Screen
->buffers
->list
[index
];
90 /* Bump the performance counter */
91 rmesa
->c_vertexBuffers
++;
98 drmCommandNone( fd
, DRM_R128_CCE_RESET
);
99 UNLOCK_HARDWARE( rmesa
);
100 fprintf( stderr
, "Error: Could not get new VB... exiting\n" );
107 void r128FlushVerticesLocked( r128ContextPtr rmesa
)
109 XF86DRIClipRectPtr pbox
= rmesa
->pClipRects
;
110 int nbox
= rmesa
->numClipRects
;
111 drmBufPtr buffer
= rmesa
->vert_buf
;
112 int count
= rmesa
->num_verts
;
113 int prim
= rmesa
->hw_primitive
;
114 int fd
= rmesa
->driScreen
->fd
;
115 drmR128Vertex vertex
;
118 rmesa
->num_verts
= 0;
119 rmesa
->vert_buf
= NULL
;
124 if ( rmesa
->dirty
& ~R128_UPLOAD_CLIPRECTS
)
125 r128EmitHwStateLocked( rmesa
);
130 if ( nbox
>= R128_NR_SAREA_CLIPRECTS
)
131 rmesa
->dirty
|= R128_UPLOAD_CLIPRECTS
;
133 if ( !count
|| !(rmesa
->dirty
& R128_UPLOAD_CLIPRECTS
) )
136 rmesa
->sarea
->nbox
= 0;
138 rmesa
->sarea
->nbox
= nbox
;
142 vertex
.idx
= buffer
->idx
;
143 vertex
.count
= count
;
145 drmCommandWrite( fd
, DRM_R128_VERTEX
, &vertex
, sizeof(drmR128Vertex
) );
149 for ( i
= 0 ; i
< nbox
; ) {
150 int nr
= MIN2( i
+ R128_NR_SAREA_CLIPRECTS
, nbox
);
151 XF86DRIClipRectPtr b
= rmesa
->sarea
->boxes
;
154 rmesa
->sarea
->nbox
= nr
- i
;
155 for ( ; i
< nr
; i
++ ) {
159 /* Finished with the buffer?
165 rmesa
->sarea
->dirty
|= R128_UPLOAD_CLIPRECTS
;
168 vertex
.idx
= buffer
->idx
;
169 vertex
.count
= count
;
170 vertex
.discard
= discard
;
171 drmCommandWrite( fd
, DRM_R128_VERTEX
, &vertex
, sizeof(drmR128Vertex
) );
175 rmesa
->dirty
&= ~R128_UPLOAD_CLIPRECTS
;
182 /* ================================================================
186 void r128FireBlitLocked( r128ContextPtr rmesa
, drmBufPtr buffer
,
187 GLint offset
, GLint pitch
, GLint format
,
188 GLint x
, GLint y
, GLint width
, GLint height
)
193 blit
.idx
= buffer
->idx
;
194 blit
.offset
= offset
;
196 blit
.format
= format
;
200 blit
.height
= height
;
202 ret
= drmCommandWrite( rmesa
->driFd
, DRM_R128_BLIT
,
203 &blit
, sizeof(drmR128Blit
) );
206 UNLOCK_HARDWARE( rmesa
);
207 fprintf( stderr
, "DRM_R128_BLIT: return = %d\n", ret
);
213 /* ================================================================
214 * SwapBuffers with client-side throttling
217 static void delay( void ) {
218 /* Prevent an optimizing compiler from removing a spin loop */
221 #define R128_MAX_OUTSTANDING 2
223 /* Throttle the frame rate -- only allow one pending swap buffers
225 * GH: We probably don't want a timeout here, as we can wait as
226 * long as we want for a frame to complete. If it never does, then
227 * the card has locked.
229 static int r128WaitForFrameCompletion( r128ContextPtr rmesa
)
231 unsigned char *R128MMIO
= rmesa
->r128Screen
->mmio
.map
;
237 frame
= INREG( R128_LAST_FRAME_REG
);
238 if ( rmesa
->sarea
->last_frame
- frame
<= R128_MAX_OUTSTANDING
) {
242 /* Spin in place a bit so we aren't hammering the register */
244 for ( i
= 0 ; i
< 1024 ; i
++ ) {
252 /* Copy the back color buffer to the front color buffer.
254 void r128CopyBuffer( const __DRIdrawablePrivate
*dPriv
)
256 r128ContextPtr rmesa
;
258 GLboolean missed_target
;
261 assert(dPriv
->driContextPriv
);
262 assert(dPriv
->driContextPriv
->driverPrivate
);
264 rmesa
= (r128ContextPtr
) dPriv
->driContextPriv
->driverPrivate
;
266 if ( R128_DEBUG
& DEBUG_VERBOSE_API
) {
267 fprintf( stderr
, "\n********************************\n" );
268 fprintf( stderr
, "\n%s( %p )\n\n",
269 __FUNCTION__
, rmesa
->glCtx
);
273 FLUSH_BATCH( rmesa
);
275 LOCK_HARDWARE( rmesa
);
277 /* Throttle the frame rate -- only allow one pending swap buffers
280 if ( !r128WaitForFrameCompletion( rmesa
) ) {
281 rmesa
->hardwareWentIdle
= 1;
283 rmesa
->hardwareWentIdle
= 0;
286 UNLOCK_HARDWARE( rmesa
);
287 driWaitForVBlank( dPriv
, &rmesa
->vbl_seq
, rmesa
->vblank_flags
, &missed_target
);
288 LOCK_HARDWARE( rmesa
);
290 nbox
= dPriv
->numClipRects
; /* must be in locked region */
292 for ( i
= 0 ; i
< nbox
; ) {
293 GLint nr
= MIN2( i
+ R128_NR_SAREA_CLIPRECTS
, nbox
);
294 XF86DRIClipRectPtr box
= dPriv
->pClipRects
;
295 XF86DRIClipRectPtr b
= rmesa
->sarea
->boxes
;
298 for ( ; i
< nr
; i
++ ) {
299 *b
++ = *(XF86DRIClipRectRec
*)&box
[i
];
302 rmesa
->sarea
->nbox
= n
;
304 ret
= drmCommandNone( rmesa
->driFd
, DRM_R128_SWAP
);
307 UNLOCK_HARDWARE( rmesa
);
308 fprintf( stderr
, "DRM_R128_SWAP: return = %d\n", ret
);
313 if ( R128_DEBUG
& DEBUG_ALWAYS_SYNC
) {
316 ret
= drmCommandNone(rmesa
->driFd
, DRM_R128_CCE_IDLE
);
317 } while ( ret
&& errno
== EBUSY
&& i
++ < R128_IDLE_RETRY
);
320 UNLOCK_HARDWARE( rmesa
);
322 rmesa
->new_state
|= R128_NEW_CONTEXT
;
323 rmesa
->dirty
|= (R128_UPLOAD_CONTEXT
|
325 R128_UPLOAD_CLIPRECTS
);
327 #if ENABLE_PERF_BOXES
328 /* Log the performance counters if necessary */
329 r128PerformanceCounters( rmesa
);
333 void r128PageFlip( const __DRIdrawablePrivate
*dPriv
)
335 r128ContextPtr rmesa
;
337 GLboolean missed_target
;
340 assert(dPriv
->driContextPriv
);
341 assert(dPriv
->driContextPriv
->driverPrivate
);
343 rmesa
= (r128ContextPtr
) dPriv
->driContextPriv
->driverPrivate
;
345 if ( R128_DEBUG
& DEBUG_VERBOSE_API
) {
346 fprintf( stderr
, "\n%s( %p ): page=%d\n\n",
347 __FUNCTION__
, rmesa
->glCtx
, rmesa
->sarea
->pfCurrentPage
);
350 FLUSH_BATCH( rmesa
);
352 LOCK_HARDWARE( rmesa
);
354 /* Throttle the frame rate -- only allow one pending swap buffers
357 if ( !r128WaitForFrameCompletion( rmesa
) ) {
358 rmesa
->hardwareWentIdle
= 1;
360 rmesa
->hardwareWentIdle
= 0;
363 UNLOCK_HARDWARE( rmesa
);
364 driWaitForVBlank( dPriv
, &rmesa
->vbl_seq
, rmesa
->vblank_flags
, &missed_target
);
365 LOCK_HARDWARE( rmesa
);
367 /* The kernel will have been initialized to perform page flipping
368 * on a swapbuffers ioctl.
370 ret
= drmCommandNone( rmesa
->driFd
, DRM_R128_FLIP
);
372 UNLOCK_HARDWARE( rmesa
);
375 fprintf( stderr
, "DRM_R128_FLIP: return = %d\n", ret
);
379 if ( rmesa
->sarea
->pfCurrentPage
== 1 ) {
380 rmesa
->drawOffset
= rmesa
->r128Screen
->frontOffset
;
381 rmesa
->drawPitch
= rmesa
->r128Screen
->frontPitch
;
383 rmesa
->drawOffset
= rmesa
->r128Screen
->backOffset
;
384 rmesa
->drawPitch
= rmesa
->r128Screen
->backPitch
;
387 rmesa
->setup
.dst_pitch_offset_c
= (((rmesa
->drawPitch
/8) << 21) |
388 (rmesa
->drawOffset
>> 5));
389 rmesa
->new_state
|= R128_NEW_WINDOW
;
391 /* FIXME: Do we need this anymore? */
392 rmesa
->new_state
|= R128_NEW_CONTEXT
;
393 rmesa
->dirty
|= (R128_UPLOAD_CONTEXT
|
395 R128_UPLOAD_CLIPRECTS
);
397 #if ENABLE_PERF_BOXES
398 /* Log the performance counters if necessary */
399 r128PerformanceCounters( rmesa
);
404 /* ================================================================
408 static void r128DDClear( GLcontext
*ctx
, GLbitfield mask
, GLboolean all
,
409 GLint cx
, GLint cy
, GLint cw
, GLint ch
)
411 r128ContextPtr rmesa
= R128_CONTEXT(ctx
);
412 __DRIdrawablePrivate
*dPriv
= rmesa
->driDrawable
;
418 if ( R128_DEBUG
& DEBUG_VERBOSE_API
) {
419 fprintf( stderr
, "%s:\n", __FUNCTION__
);
422 FLUSH_BATCH( rmesa
);
424 /* The only state change we care about here is the RGBA colormask
425 * We'll just update that state, if needed. If we do more then
426 * there's some strange side-effects that the conformance tests find.
428 if ( rmesa
->new_state
& R128_NEW_MASKS
) {
429 const GLuint save_state
= rmesa
->new_state
;
430 rmesa
->new_state
= R128_NEW_MASKS
;
431 r128DDUpdateHWState( ctx
);
432 rmesa
->new_state
= save_state
& ~R128_NEW_MASKS
;
435 if ( mask
& DD_FRONT_LEFT_BIT
) {
436 flags
|= DRM_R128_FRONT_BUFFER
;
437 mask
&= ~DD_FRONT_LEFT_BIT
;
440 if ( mask
& DD_BACK_LEFT_BIT
) {
441 flags
|= DRM_R128_BACK_BUFFER
;
442 mask
&= ~DD_BACK_LEFT_BIT
;
445 if ( ( mask
& DD_DEPTH_BIT
) && ctx
->Depth
.Mask
) {
446 flags
|= DRM_R128_DEPTH_BUFFER
;
447 mask
&= ~DD_DEPTH_BIT
;
450 /* FIXME: Add stencil support */
451 if ( mask
& DD_STENCIL_BIT
) {
452 flags
|= DRM_R128_DEPTH_BUFFER
;
453 mask
&= ~DD_STENCIL_BIT
;
459 /* Flip top to bottom */
461 cy
= dPriv
->y
+ dPriv
->h
- cy
- ch
;
463 LOCK_HARDWARE( rmesa
);
465 /* FIXME: Do we actually need this?
467 if ( rmesa
->dirty
& ~R128_UPLOAD_CLIPRECTS
) {
468 r128EmitHwStateLocked( rmesa
);
471 for ( i
= 0 ; i
< rmesa
->numClipRects
; ) {
472 GLint nr
= MIN2( i
+ R128_NR_SAREA_CLIPRECTS
, rmesa
->numClipRects
);
473 XF86DRIClipRectPtr box
= rmesa
->pClipRects
;
474 XF86DRIClipRectPtr b
= rmesa
->sarea
->boxes
;
478 for ( ; i
< nr
; i
++ ) {
481 GLint w
= box
[i
].x2
- x
;
482 GLint h
= box
[i
].y2
- y
;
484 if ( x
< cx
) w
-= cx
- x
, x
= cx
;
485 if ( y
< cy
) h
-= cy
- y
, y
= cy
;
486 if ( x
+ w
> cx
+ cw
) w
= cx
+ cw
- x
;
487 if ( y
+ h
> cy
+ ch
) h
= cy
+ ch
- y
;
488 if ( w
<= 0 ) continue;
489 if ( h
<= 0 ) continue;
499 for ( ; i
< nr
; i
++ ) {
500 *b
++ = *(XF86DRIClipRectPtr
)&box
[i
];
505 rmesa
->sarea
->nbox
= n
;
507 if ( R128_DEBUG
& DEBUG_VERBOSE_IOCTL
) {
509 "DRM_R128_CLEAR: flag 0x%x color %x depth %x nbox %d\n",
511 (GLuint
)rmesa
->ClearColor
,
512 (GLuint
)rmesa
->ClearDepth
,
513 rmesa
->sarea
->nbox
);
517 clear
.clear_color
= rmesa
->ClearColor
;
518 clear
.clear_depth
= rmesa
->ClearDepth
;
519 clear
.color_mask
= rmesa
->setup
.plane_3d_mask_c
;
520 clear
.depth_mask
= ~0;
522 ret
= drmCommandWrite( rmesa
->driFd
, DRM_R128_CLEAR
,
523 &clear
, sizeof(drmR128Clear
) );
526 UNLOCK_HARDWARE( rmesa
);
527 fprintf( stderr
, "DRM_R128_CLEAR: return = %d\n", ret
);
532 UNLOCK_HARDWARE( rmesa
);
534 rmesa
->dirty
|= R128_UPLOAD_CLIPRECTS
;
538 _swrast_Clear( ctx
, mask
, all
, cx
, cy
, cw
, ch
);
542 /* ================================================================
543 * Depth spans, pixels
546 void r128WriteDepthSpanLocked( r128ContextPtr rmesa
,
547 GLuint n
, GLint x
, GLint y
,
548 const GLdepth depth
[],
549 const GLubyte mask
[] )
551 XF86DRIClipRectPtr pbox
= rmesa
->pClipRects
;
553 int nbox
= rmesa
->numClipRects
;
554 int fd
= rmesa
->driScreen
->fd
;
560 if ( nbox
>= R128_NR_SAREA_CLIPRECTS
) {
561 rmesa
->dirty
|= R128_UPLOAD_CLIPRECTS
;
564 if ( !(rmesa
->dirty
& R128_UPLOAD_CLIPRECTS
) )
567 rmesa
->sarea
->nbox
= 0;
569 rmesa
->sarea
->nbox
= nbox
;
572 d
.func
= DRM_R128_WRITE_SPAN
;
576 d
.buffer
= (unsigned int *)depth
;
577 d
.mask
= (unsigned char *)mask
;
579 drmCommandWrite( fd
, DRM_R128_DEPTH
, &d
, sizeof(drmR128Depth
));
584 for (i
= 0 ; i
< nbox
; ) {
585 int nr
= MIN2( i
+ R128_NR_SAREA_CLIPRECTS
, nbox
);
586 XF86DRIClipRectPtr b
= rmesa
->sarea
->boxes
;
588 rmesa
->sarea
->nbox
= nr
- i
;
589 for ( ; i
< nr
; i
++) {
593 rmesa
->sarea
->dirty
|= R128_UPLOAD_CLIPRECTS
;
595 d
.func
= DRM_R128_WRITE_SPAN
;
599 d
.buffer
= (unsigned int *)depth
;
600 d
.mask
= (unsigned char *)mask
;
602 drmCommandWrite( fd
, DRM_R128_DEPTH
, &d
, sizeof(drmR128Depth
));
606 rmesa
->dirty
&= ~R128_UPLOAD_CLIPRECTS
;
609 void r128WriteDepthPixelsLocked( r128ContextPtr rmesa
, GLuint n
,
610 const GLint x
[], const GLint y
[],
611 const GLdepth depth
[],
612 const GLubyte mask
[] )
614 XF86DRIClipRectPtr pbox
= rmesa
->pClipRects
;
616 int nbox
= rmesa
->numClipRects
;
617 int fd
= rmesa
->driScreen
->fd
;
623 if ( nbox
>= R128_NR_SAREA_CLIPRECTS
) {
624 rmesa
->dirty
|= R128_UPLOAD_CLIPRECTS
;
627 if ( !(rmesa
->dirty
& R128_UPLOAD_CLIPRECTS
) )
630 rmesa
->sarea
->nbox
= 0;
632 rmesa
->sarea
->nbox
= nbox
;
635 d
.func
= DRM_R128_WRITE_PIXELS
;
639 d
.buffer
= (unsigned int *)depth
;
640 d
.mask
= (unsigned char *)mask
;
642 drmCommandWrite( fd
, DRM_R128_DEPTH
, &d
, sizeof(drmR128Depth
));
646 for (i
= 0 ; i
< nbox
; ) {
647 int nr
= MIN2( i
+ R128_NR_SAREA_CLIPRECTS
, nbox
);
648 XF86DRIClipRectPtr b
= rmesa
->sarea
->boxes
;
650 rmesa
->sarea
->nbox
= nr
- i
;
651 for ( ; i
< nr
; i
++) {
655 rmesa
->sarea
->dirty
|= R128_UPLOAD_CLIPRECTS
;
657 d
.func
= DRM_R128_WRITE_PIXELS
;
661 d
.buffer
= (unsigned int *)depth
;
662 d
.mask
= (unsigned char *)mask
;
664 drmCommandWrite( fd
, DRM_R128_DEPTH
, &d
, sizeof(drmR128Depth
));
668 rmesa
->dirty
&= ~R128_UPLOAD_CLIPRECTS
;
671 void r128ReadDepthSpanLocked( r128ContextPtr rmesa
,
672 GLuint n
, GLint x
, GLint y
)
674 XF86DRIClipRectPtr pbox
= rmesa
->pClipRects
;
676 int nbox
= rmesa
->numClipRects
;
677 int fd
= rmesa
->driScreen
->fd
;
683 if ( nbox
>= R128_NR_SAREA_CLIPRECTS
) {
684 rmesa
->dirty
|= R128_UPLOAD_CLIPRECTS
;
687 if ( !(rmesa
->dirty
& R128_UPLOAD_CLIPRECTS
) )
690 rmesa
->sarea
->nbox
= 0;
692 rmesa
->sarea
->nbox
= nbox
;
695 d
.func
= DRM_R128_READ_SPAN
;
702 drmCommandWrite( fd
, DRM_R128_DEPTH
, &d
, sizeof(drmR128Depth
));
706 for (i
= 0 ; i
< nbox
; ) {
707 int nr
= MIN2( i
+ R128_NR_SAREA_CLIPRECTS
, nbox
);
708 XF86DRIClipRectPtr b
= rmesa
->sarea
->boxes
;
710 rmesa
->sarea
->nbox
= nr
- i
;
711 for ( ; i
< nr
; i
++) {
715 rmesa
->sarea
->dirty
|= R128_UPLOAD_CLIPRECTS
;
717 d
.func
= DRM_R128_READ_SPAN
;
724 drmCommandWrite( fd
, DRM_R128_DEPTH
, &d
, sizeof(drmR128Depth
));
728 rmesa
->dirty
&= ~R128_UPLOAD_CLIPRECTS
;
731 void r128ReadDepthPixelsLocked( r128ContextPtr rmesa
, GLuint n
,
732 const GLint x
[], const GLint y
[] )
734 XF86DRIClipRectPtr pbox
= rmesa
->pClipRects
;
736 int nbox
= rmesa
->numClipRects
;
737 int fd
= rmesa
->driScreen
->fd
;
743 if ( nbox
>= R128_NR_SAREA_CLIPRECTS
) {
744 rmesa
->dirty
|= R128_UPLOAD_CLIPRECTS
;
747 if ( !(rmesa
->dirty
& R128_UPLOAD_CLIPRECTS
) )
750 rmesa
->sarea
->nbox
= 0;
752 rmesa
->sarea
->nbox
= nbox
;
755 d
.func
= DRM_R128_READ_PIXELS
;
762 drmCommandWrite( fd
, DRM_R128_DEPTH
, &d
, sizeof(drmR128Depth
));
766 for (i
= 0 ; i
< nbox
; ) {
767 int nr
= MIN2( i
+ R128_NR_SAREA_CLIPRECTS
, nbox
);
768 XF86DRIClipRectPtr b
= rmesa
->sarea
->boxes
;
770 rmesa
->sarea
->nbox
= nr
- i
;
771 for ( ; i
< nr
; i
++) {
775 rmesa
->sarea
->dirty
|= R128_UPLOAD_CLIPRECTS
;
777 d
.func
= DRM_R128_READ_PIXELS
;
784 drmCommandWrite( fd
, DRM_R128_DEPTH
, &d
, sizeof(drmR128Depth
));
788 rmesa
->dirty
&= ~R128_UPLOAD_CLIPRECTS
;
792 void r128WaitForIdleLocked( r128ContextPtr rmesa
)
794 int fd
= rmesa
->r128Screen
->driScreen
->fd
;
801 ret
= drmCommandNone( fd
, DRM_R128_CCE_IDLE
);
802 } while ( ret
&& errno
== EBUSY
&& i
++ < R128_IDLE_RETRY
);
803 } while ( ( ret
== -EBUSY
) && ( to
++ < R128_TIMEOUT
) );
806 drmCommandNone( fd
, DRM_R128_CCE_RESET
);
807 UNLOCK_HARDWARE( rmesa
);
808 fprintf( stderr
, "Error: Rage 128 timed out... exiting\n" );
813 void r128DDInitIoctlFuncs( GLcontext
*ctx
)
815 ctx
->Driver
.Clear
= r128DDClear
;