7dbb5e5ddab97640bfb61374c09a4fd53dd7d8ca
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 #include "drirenderbuffer.h"
49 #define R128_TIMEOUT 2048
50 #define R128_IDLE_RETRY 32
53 /* =============================================================
54 * Hardware vertex buffer handling
57 /* Get a new VB from the pool of vertex buffers in AGP space.
59 drmBufPtr
r128GetBufferLocked( r128ContextPtr rmesa
)
61 int fd
= rmesa
->r128Screen
->driScreen
->fd
;
69 dma
.context
= rmesa
->hHWContext
;
72 dma
.send_sizes
= NULL
;
74 dma
.request_count
= 1;
75 dma
.request_size
= R128_BUFFER_SIZE
;
76 dma
.request_list
= &index
;
77 dma
.request_sizes
= &size
;
78 dma
.granted_count
= 0;
80 while ( !buf
&& ( to
++ < R128_TIMEOUT
) ) {
81 ret
= drmDMA( fd
, &dma
);
84 buf
= &rmesa
->r128Screen
->buffers
->list
[index
];
87 /* Bump the performance counter */
88 rmesa
->c_vertexBuffers
++;
95 drmCommandNone( fd
, DRM_R128_CCE_RESET
);
96 UNLOCK_HARDWARE( rmesa
);
97 fprintf( stderr
, "Error: Could not get new VB... exiting\n" );
104 void r128FlushVerticesLocked( r128ContextPtr rmesa
)
106 drm_clip_rect_t
*pbox
= rmesa
->pClipRects
;
107 int nbox
= rmesa
->numClipRects
;
108 drmBufPtr buffer
= rmesa
->vert_buf
;
109 int count
= rmesa
->num_verts
;
110 int prim
= rmesa
->hw_primitive
;
111 int fd
= rmesa
->driScreen
->fd
;
112 drm_r128_vertex_t vertex
;
115 rmesa
->num_verts
= 0;
116 rmesa
->vert_buf
= NULL
;
121 if ( rmesa
->dirty
& ~R128_UPLOAD_CLIPRECTS
)
122 r128EmitHwStateLocked( rmesa
);
127 if ( nbox
>= R128_NR_SAREA_CLIPRECTS
)
128 rmesa
->dirty
|= R128_UPLOAD_CLIPRECTS
;
130 if ( !count
|| !(rmesa
->dirty
& R128_UPLOAD_CLIPRECTS
) )
133 rmesa
->sarea
->nbox
= 0;
135 rmesa
->sarea
->nbox
= nbox
;
139 vertex
.idx
= buffer
->idx
;
140 vertex
.count
= count
;
142 drmCommandWrite( fd
, DRM_R128_VERTEX
, &vertex
, sizeof(vertex
) );
146 for ( i
= 0 ; i
< nbox
; ) {
147 int nr
= MIN2( i
+ R128_NR_SAREA_CLIPRECTS
, nbox
);
148 drm_clip_rect_t
*b
= rmesa
->sarea
->boxes
;
151 rmesa
->sarea
->nbox
= nr
- i
;
152 for ( ; i
< nr
; i
++ ) {
156 /* Finished with the buffer?
162 rmesa
->sarea
->dirty
|= R128_UPLOAD_CLIPRECTS
;
165 vertex
.idx
= buffer
->idx
;
166 vertex
.count
= count
;
167 vertex
.discard
= discard
;
168 drmCommandWrite( fd
, DRM_R128_VERTEX
, &vertex
, sizeof(vertex
) );
172 rmesa
->dirty
&= ~R128_UPLOAD_CLIPRECTS
;
179 /* ================================================================
183 void r128FireBlitLocked( r128ContextPtr rmesa
, drmBufPtr buffer
,
184 GLint offset
, GLint pitch
, GLint format
,
185 GLint x
, GLint y
, GLint width
, GLint height
)
187 drm_r128_blit_t blit
;
190 blit
.idx
= buffer
->idx
;
191 blit
.offset
= offset
;
193 blit
.format
= format
;
197 blit
.height
= height
;
199 ret
= drmCommandWrite( rmesa
->driFd
, DRM_R128_BLIT
,
200 &blit
, sizeof(blit
) );
203 UNLOCK_HARDWARE( rmesa
);
204 fprintf( stderr
, "DRM_R128_BLIT: return = %d\n", ret
);
210 /* ================================================================
211 * SwapBuffers with client-side throttling
214 static void delay( void ) {
215 /* Prevent an optimizing compiler from removing a spin loop */
218 #define R128_MAX_OUTSTANDING 2
221 /* Throttle the frame rate -- only allow one pending swap buffers
223 * GH: We probably don't want a timeout here, as we can wait as
224 * long as we want for a frame to complete. If it never does, then
225 * the card has locked.
227 static int r128WaitForFrameCompletion( r128ContextPtr rmesa
)
229 unsigned char *R128MMIO
= rmesa
->r128Screen
->mmio
.map
;
234 u_int32_t frame
= read_MMIO_LE32( R128MMIO
, R128_LAST_FRAME_REG
);
236 if ( rmesa
->sarea
->last_frame
- frame
<= R128_MAX_OUTSTANDING
) {
240 /* Spin in place a bit so we aren't hammering the register */
242 for ( i
= 0 ; i
< 1024 ; i
++ ) {
250 /* Copy the back color buffer to the front color buffer.
252 void r128CopyBuffer( const __DRIdrawablePrivate
*dPriv
)
254 r128ContextPtr rmesa
;
256 GLboolean missed_target
;
259 assert(dPriv
->driContextPriv
);
260 assert(dPriv
->driContextPriv
->driverPrivate
);
262 rmesa
= (r128ContextPtr
) dPriv
->driContextPriv
->driverPrivate
;
264 if ( R128_DEBUG
& DEBUG_VERBOSE_API
) {
265 fprintf( stderr
, "\n********************************\n" );
266 fprintf( stderr
, "\n%s( %p )\n\n",
267 __FUNCTION__
, (void *)rmesa
->glCtx
);
271 FLUSH_BATCH( rmesa
);
273 LOCK_HARDWARE( rmesa
);
275 /* Throttle the frame rate -- only allow one pending swap buffers
278 if ( !r128WaitForFrameCompletion( rmesa
) ) {
279 rmesa
->hardwareWentIdle
= 1;
281 rmesa
->hardwareWentIdle
= 0;
284 UNLOCK_HARDWARE( rmesa
);
285 driWaitForVBlank( dPriv
, &rmesa
->vbl_seq
, rmesa
->vblank_flags
, &missed_target
);
286 LOCK_HARDWARE( rmesa
);
288 nbox
= dPriv
->numClipRects
; /* must be in locked region */
290 for ( i
= 0 ; i
< nbox
; ) {
291 GLint nr
= MIN2( i
+ R128_NR_SAREA_CLIPRECTS
, nbox
);
292 drm_clip_rect_t
*box
= dPriv
->pClipRects
;
293 drm_clip_rect_t
*b
= rmesa
->sarea
->boxes
;
296 for ( ; i
< nr
; i
++ ) {
300 rmesa
->sarea
->nbox
= n
;
302 ret
= drmCommandNone( rmesa
->driFd
, DRM_R128_SWAP
);
305 UNLOCK_HARDWARE( rmesa
);
306 fprintf( stderr
, "DRM_R128_SWAP: return = %d\n", ret
);
311 if ( R128_DEBUG
& DEBUG_ALWAYS_SYNC
) {
314 ret
= drmCommandNone(rmesa
->driFd
, DRM_R128_CCE_IDLE
);
315 } while ( ret
&& errno
== EBUSY
&& i
++ < R128_IDLE_RETRY
);
318 UNLOCK_HARDWARE( rmesa
);
320 rmesa
->new_state
|= R128_NEW_CONTEXT
;
321 rmesa
->dirty
|= (R128_UPLOAD_CONTEXT
|
323 R128_UPLOAD_CLIPRECTS
);
325 #if ENABLE_PERF_BOXES
326 /* Log the performance counters if necessary */
327 r128PerformanceCounters( rmesa
);
331 void r128PageFlip( const __DRIdrawablePrivate
*dPriv
)
333 r128ContextPtr rmesa
;
335 GLboolean missed_target
;
338 assert(dPriv
->driContextPriv
);
339 assert(dPriv
->driContextPriv
->driverPrivate
);
341 rmesa
= (r128ContextPtr
) dPriv
->driContextPriv
->driverPrivate
;
343 if ( R128_DEBUG
& DEBUG_VERBOSE_API
) {
344 fprintf( stderr
, "\n%s( %p ): page=%d\n\n",
345 __FUNCTION__
, (void *)rmesa
->glCtx
, rmesa
->sarea
->pfCurrentPage
);
348 FLUSH_BATCH( rmesa
);
350 LOCK_HARDWARE( rmesa
);
352 /* Throttle the frame rate -- only allow one pending swap buffers
355 if ( !r128WaitForFrameCompletion( rmesa
) ) {
356 rmesa
->hardwareWentIdle
= 1;
358 rmesa
->hardwareWentIdle
= 0;
361 UNLOCK_HARDWARE( rmesa
);
362 driWaitForVBlank( dPriv
, &rmesa
->vbl_seq
, rmesa
->vblank_flags
, &missed_target
);
363 LOCK_HARDWARE( rmesa
);
365 /* The kernel will have been initialized to perform page flipping
366 * on a swapbuffers ioctl.
368 ret
= drmCommandNone( rmesa
->driFd
, DRM_R128_FLIP
);
370 UNLOCK_HARDWARE( rmesa
);
373 fprintf( stderr
, "DRM_R128_FLIP: return = %d\n", ret
);
377 /* Get ready for drawing next frame. Update the renderbuffers'
378 * flippedOffset/Pitch fields so we draw into the right place.
380 driFlipRenderbuffers(rmesa
->glCtx
->WinSysDrawBuffer
,
381 rmesa
->sarea
->pfCurrentPage
);
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 r128Clear( GLcontext
*ctx
, GLbitfield mask
, GLboolean allFoo
,
403 GLint cxFoo
, GLint cyFoo
, GLint cwFoo
, GLint chFoo
)
405 r128ContextPtr rmesa
= R128_CONTEXT(ctx
);
406 __DRIdrawablePrivate
*dPriv
= rmesa
->driDrawable
;
407 drm_r128_clear_t clear
;
411 GLuint depthmask
= 0;
412 GLint cx
, cy
, cw
, ch
;
414 if ( R128_DEBUG
& DEBUG_VERBOSE_API
) {
415 fprintf( stderr
, "%s:\n", __FUNCTION__
);
418 FLUSH_BATCH( rmesa
);
420 /* The only state change we care about here is the RGBA colormask
421 * We'll just update that state, if needed. If we do more then
422 * there's some strange side-effects that the conformance tests find.
424 if ( rmesa
->new_state
& R128_NEW_MASKS
) {
425 const GLuint save_state
= rmesa
->new_state
;
426 rmesa
->new_state
= R128_NEW_MASKS
;
427 r128DDUpdateHWState( ctx
);
428 rmesa
->new_state
= save_state
& ~R128_NEW_MASKS
;
431 if ( mask
& BUFFER_BIT_FRONT_LEFT
) {
433 mask
&= ~BUFFER_BIT_FRONT_LEFT
;
436 if ( mask
& BUFFER_BIT_BACK_LEFT
) {
438 mask
&= ~BUFFER_BIT_BACK_LEFT
;
441 if ( ( mask
& BUFFER_BIT_DEPTH
) && ctx
->Depth
.Mask
) {
443 /* if we're at 16 bits, extra plane mask won't hurt */
444 depthmask
|= 0x00ffffff;
445 mask
&= ~BUFFER_BIT_DEPTH
;
448 if ( mask
& BUFFER_BIT_STENCIL
&&
449 (ctx
->Visual
.stencilBits
> 0 && ctx
->Visual
.depthBits
== 24) ) {
451 depthmask
|= ctx
->Stencil
.WriteMask
[0] << 24;
452 mask
&= ~BUFFER_BIT_STENCIL
;
457 LOCK_HARDWARE( rmesa
);
459 /* compute region after locking: */
460 cx
= ctx
->DrawBuffer
->_Xmin
;
461 cy
= ctx
->DrawBuffer
->_Ymin
;
462 cw
= ctx
->DrawBuffer
->_Xmax
- cx
;
463 ch
= ctx
->DrawBuffer
->_Ymax
- cy
;
465 /* Flip top to bottom */
467 cy
= dPriv
->y
+ dPriv
->h
- cy
- ch
;
469 /* FIXME: Do we actually need this?
471 if ( rmesa
->dirty
& ~R128_UPLOAD_CLIPRECTS
) {
472 r128EmitHwStateLocked( rmesa
);
475 for ( i
= 0 ; i
< rmesa
->numClipRects
; ) {
476 GLint nr
= MIN2( i
+ R128_NR_SAREA_CLIPRECTS
, rmesa
->numClipRects
);
477 drm_clip_rect_t
*box
= rmesa
->pClipRects
;
478 drm_clip_rect_t
*b
= rmesa
->sarea
->boxes
;
481 if (cw
!= dPriv
->w
|| ch
!= dPriv
->h
) {
482 /* clear subregion */
483 for ( ; i
< nr
; i
++ ) {
486 GLint w
= box
[i
].x2
- x
;
487 GLint h
= box
[i
].y2
- y
;
489 if ( x
< cx
) w
-= cx
- x
, x
= cx
;
490 if ( y
< cy
) h
-= cy
- y
, y
= cy
;
491 if ( x
+ w
> cx
+ cw
) w
= cx
+ cw
- x
;
492 if ( y
+ h
> cy
+ ch
) h
= cy
+ ch
- y
;
493 if ( w
<= 0 ) continue;
494 if ( h
<= 0 ) continue;
504 /* clear whole window */
505 for ( ; i
< nr
; i
++ ) {
511 rmesa
->sarea
->nbox
= n
;
513 if ( R128_DEBUG
& DEBUG_VERBOSE_IOCTL
) {
515 "DRM_R128_CLEAR: flag 0x%x color %x depth %x nbox %d\n",
517 (GLuint
)rmesa
->ClearColor
,
518 (GLuint
)rmesa
->ClearDepth
,
519 rmesa
->sarea
->nbox
);
523 clear
.clear_color
= rmesa
->ClearColor
;
524 clear
.clear_depth
= rmesa
->ClearDepth
;
525 clear
.color_mask
= rmesa
->setup
.plane_3d_mask_c
;
526 clear
.depth_mask
= depthmask
;
528 ret
= drmCommandWrite( rmesa
->driFd
, DRM_R128_CLEAR
,
529 &clear
, sizeof(clear
) );
532 UNLOCK_HARDWARE( rmesa
);
533 fprintf( stderr
, "DRM_R128_CLEAR: return = %d\n", ret
);
538 UNLOCK_HARDWARE( rmesa
);
540 rmesa
->dirty
|= R128_UPLOAD_CLIPRECTS
;
544 _swrast_Clear( ctx
, mask
, 0, 0, 0, 0, 0 );
548 /* ================================================================
549 * Depth spans, pixels
552 void r128WriteDepthSpanLocked( r128ContextPtr rmesa
,
553 GLuint n
, GLint x
, GLint y
,
554 const GLuint depth
[],
555 const GLubyte mask
[] )
557 drm_clip_rect_t
*pbox
= rmesa
->pClipRects
;
559 int nbox
= rmesa
->numClipRects
;
560 int fd
= rmesa
->driScreen
->fd
;
566 if ( nbox
>= R128_NR_SAREA_CLIPRECTS
) {
567 rmesa
->dirty
|= R128_UPLOAD_CLIPRECTS
;
570 if ( !(rmesa
->dirty
& R128_UPLOAD_CLIPRECTS
) )
573 rmesa
->sarea
->nbox
= 0;
575 rmesa
->sarea
->nbox
= nbox
;
578 d
.func
= R128_WRITE_SPAN
;
582 d
.buffer
= (unsigned int *)depth
;
583 d
.mask
= (unsigned char *)mask
;
585 drmCommandWrite( fd
, DRM_R128_DEPTH
, &d
, sizeof(d
));
590 for (i
= 0 ; i
< nbox
; ) {
591 int nr
= MIN2( i
+ R128_NR_SAREA_CLIPRECTS
, nbox
);
592 drm_clip_rect_t
*b
= rmesa
->sarea
->boxes
;
594 rmesa
->sarea
->nbox
= nr
- i
;
595 for ( ; i
< nr
; i
++) {
599 rmesa
->sarea
->dirty
|= R128_UPLOAD_CLIPRECTS
;
601 d
.func
= R128_WRITE_SPAN
;
605 d
.buffer
= (unsigned int *)depth
;
606 d
.mask
= (unsigned char *)mask
;
608 drmCommandWrite( fd
, DRM_R128_DEPTH
, &d
, sizeof(d
));
612 rmesa
->dirty
&= ~R128_UPLOAD_CLIPRECTS
;
615 void r128WriteDepthPixelsLocked( r128ContextPtr rmesa
, GLuint n
,
616 const GLint x
[], const GLint y
[],
617 const GLuint depth
[],
618 const GLubyte mask
[] )
620 drm_clip_rect_t
*pbox
= rmesa
->pClipRects
;
622 int nbox
= rmesa
->numClipRects
;
623 int fd
= rmesa
->driScreen
->fd
;
629 if ( nbox
>= R128_NR_SAREA_CLIPRECTS
) {
630 rmesa
->dirty
|= R128_UPLOAD_CLIPRECTS
;
633 if ( !(rmesa
->dirty
& R128_UPLOAD_CLIPRECTS
) )
636 rmesa
->sarea
->nbox
= 0;
638 rmesa
->sarea
->nbox
= nbox
;
641 d
.func
= R128_WRITE_PIXELS
;
645 d
.buffer
= (unsigned int *)depth
;
646 d
.mask
= (unsigned char *)mask
;
648 drmCommandWrite( fd
, DRM_R128_DEPTH
, &d
, sizeof(d
));
652 for (i
= 0 ; i
< nbox
; ) {
653 int nr
= MIN2( i
+ R128_NR_SAREA_CLIPRECTS
, nbox
);
654 drm_clip_rect_t
*b
= rmesa
->sarea
->boxes
;
656 rmesa
->sarea
->nbox
= nr
- i
;
657 for ( ; i
< nr
; i
++) {
661 rmesa
->sarea
->dirty
|= R128_UPLOAD_CLIPRECTS
;
663 d
.func
= R128_WRITE_PIXELS
;
667 d
.buffer
= (unsigned int *)depth
;
668 d
.mask
= (unsigned char *)mask
;
670 drmCommandWrite( fd
, DRM_R128_DEPTH
, &d
, sizeof(d
));
674 rmesa
->dirty
&= ~R128_UPLOAD_CLIPRECTS
;
677 void r128ReadDepthSpanLocked( r128ContextPtr rmesa
,
678 GLuint n
, GLint x
, GLint y
)
680 drm_clip_rect_t
*pbox
= rmesa
->pClipRects
;
682 int nbox
= rmesa
->numClipRects
;
683 int fd
= rmesa
->driScreen
->fd
;
689 if ( nbox
>= R128_NR_SAREA_CLIPRECTS
) {
690 rmesa
->dirty
|= R128_UPLOAD_CLIPRECTS
;
693 if ( !(rmesa
->dirty
& R128_UPLOAD_CLIPRECTS
) )
696 rmesa
->sarea
->nbox
= 0;
698 rmesa
->sarea
->nbox
= nbox
;
701 d
.func
= R128_READ_SPAN
;
708 drmCommandWrite( fd
, DRM_R128_DEPTH
, &d
, sizeof(d
));
712 for (i
= 0 ; i
< nbox
; ) {
713 int nr
= MIN2( i
+ R128_NR_SAREA_CLIPRECTS
, nbox
);
714 drm_clip_rect_t
*b
= rmesa
->sarea
->boxes
;
716 rmesa
->sarea
->nbox
= nr
- i
;
717 for ( ; i
< nr
; i
++) {
721 rmesa
->sarea
->dirty
|= R128_UPLOAD_CLIPRECTS
;
723 d
.func
= R128_READ_SPAN
;
730 drmCommandWrite( fd
, DRM_R128_DEPTH
, &d
, sizeof(d
));
734 rmesa
->dirty
&= ~R128_UPLOAD_CLIPRECTS
;
737 void r128ReadDepthPixelsLocked( r128ContextPtr rmesa
, GLuint n
,
738 const GLint x
[], const GLint y
[] )
740 drm_clip_rect_t
*pbox
= rmesa
->pClipRects
;
742 int nbox
= rmesa
->numClipRects
;
743 int fd
= rmesa
->driScreen
->fd
;
749 if ( nbox
>= R128_NR_SAREA_CLIPRECTS
) {
750 rmesa
->dirty
|= R128_UPLOAD_CLIPRECTS
;
753 if ( !(rmesa
->dirty
& R128_UPLOAD_CLIPRECTS
) )
756 rmesa
->sarea
->nbox
= 0;
758 rmesa
->sarea
->nbox
= nbox
;
761 d
.func
= R128_READ_PIXELS
;
768 drmCommandWrite( fd
, DRM_R128_DEPTH
, &d
, sizeof(d
));
772 for (i
= 0 ; i
< nbox
; ) {
773 int nr
= MIN2( i
+ R128_NR_SAREA_CLIPRECTS
, nbox
);
774 drm_clip_rect_t
*b
= rmesa
->sarea
->boxes
;
776 rmesa
->sarea
->nbox
= nr
- i
;
777 for ( ; i
< nr
; i
++) {
781 rmesa
->sarea
->dirty
|= R128_UPLOAD_CLIPRECTS
;
783 d
.func
= R128_READ_PIXELS
;
790 drmCommandWrite( fd
, DRM_R128_DEPTH
, &d
, sizeof(d
));
794 rmesa
->dirty
&= ~R128_UPLOAD_CLIPRECTS
;
798 void r128WaitForIdleLocked( r128ContextPtr rmesa
)
800 int fd
= rmesa
->r128Screen
->driScreen
->fd
;
807 ret
= drmCommandNone( fd
, DRM_R128_CCE_IDLE
);
808 } while ( ret
&& errno
== EBUSY
&& i
++ < R128_IDLE_RETRY
);
809 } while ( ( ret
== -EBUSY
) && ( to
++ < R128_TIMEOUT
) );
812 drmCommandNone( fd
, DRM_R128_CCE_RESET
);
813 UNLOCK_HARDWARE( rmesa
);
814 fprintf( stderr
, "Error: Rage 128 timed out... exiting\n" );
819 void r128InitIoctlFuncs( struct dd_function_table
*functions
)
821 functions
->Clear
= r128Clear
;