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( __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
, &dPriv
->vblSeq
, dPriv
->vblFlags
, &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( __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
, &dPriv
->vblSeq
, dPriv
->vblFlags
, &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
)
404 r128ContextPtr rmesa
= R128_CONTEXT(ctx
);
405 __DRIdrawablePrivate
*dPriv
= rmesa
->driDrawable
;
406 drm_r128_clear_t clear
;
410 GLuint depthmask
= 0;
411 GLint cx
, cy
, cw
, ch
;
413 if ( R128_DEBUG
& DEBUG_VERBOSE_API
) {
414 fprintf( stderr
, "%s:\n", __FUNCTION__
);
417 FLUSH_BATCH( rmesa
);
419 /* The only state change we care about here is the RGBA colormask
420 * We'll just update that state, if needed. If we do more then
421 * there's some strange side-effects that the conformance tests find.
423 if ( rmesa
->new_state
& R128_NEW_MASKS
) {
424 const GLuint save_state
= rmesa
->new_state
;
425 rmesa
->new_state
= R128_NEW_MASKS
;
426 r128DDUpdateHWState( ctx
);
427 rmesa
->new_state
= save_state
& ~R128_NEW_MASKS
;
430 if ( mask
& BUFFER_BIT_FRONT_LEFT
) {
432 mask
&= ~BUFFER_BIT_FRONT_LEFT
;
435 if ( mask
& BUFFER_BIT_BACK_LEFT
) {
437 mask
&= ~BUFFER_BIT_BACK_LEFT
;
440 if ( ( mask
& BUFFER_BIT_DEPTH
) && ctx
->Depth
.Mask
) {
442 /* if we're at 16 bits, extra plane mask won't hurt */
443 depthmask
|= 0x00ffffff;
444 mask
&= ~BUFFER_BIT_DEPTH
;
447 if ( mask
& BUFFER_BIT_STENCIL
&&
448 (ctx
->Visual
.stencilBits
> 0 && ctx
->Visual
.depthBits
== 24) ) {
450 depthmask
|= ctx
->Stencil
.WriteMask
[0] << 24;
451 mask
&= ~BUFFER_BIT_STENCIL
;
456 LOCK_HARDWARE( rmesa
);
458 /* compute region after locking: */
459 cx
= ctx
->DrawBuffer
->_Xmin
;
460 cy
= ctx
->DrawBuffer
->_Ymin
;
461 cw
= ctx
->DrawBuffer
->_Xmax
- cx
;
462 ch
= ctx
->DrawBuffer
->_Ymax
- cy
;
464 /* Flip top to bottom */
466 cy
= dPriv
->y
+ dPriv
->h
- cy
- ch
;
468 /* FIXME: Do we actually need this?
470 if ( rmesa
->dirty
& ~R128_UPLOAD_CLIPRECTS
) {
471 r128EmitHwStateLocked( rmesa
);
474 for ( i
= 0 ; i
< rmesa
->numClipRects
; ) {
475 GLint nr
= MIN2( i
+ R128_NR_SAREA_CLIPRECTS
, rmesa
->numClipRects
);
476 drm_clip_rect_t
*box
= rmesa
->pClipRects
;
477 drm_clip_rect_t
*b
= rmesa
->sarea
->boxes
;
480 if (cw
!= dPriv
->w
|| ch
!= dPriv
->h
) {
481 /* clear subregion */
482 for ( ; i
< nr
; i
++ ) {
485 GLint w
= box
[i
].x2
- x
;
486 GLint h
= box
[i
].y2
- y
;
488 if ( x
< cx
) w
-= cx
- x
, x
= cx
;
489 if ( y
< cy
) h
-= cy
- y
, y
= cy
;
490 if ( x
+ w
> cx
+ cw
) w
= cx
+ cw
- x
;
491 if ( y
+ h
> cy
+ ch
) h
= cy
+ ch
- y
;
492 if ( w
<= 0 ) continue;
493 if ( h
<= 0 ) continue;
503 /* clear whole window */
504 for ( ; i
< nr
; i
++ ) {
510 rmesa
->sarea
->nbox
= n
;
512 if ( R128_DEBUG
& DEBUG_VERBOSE_IOCTL
) {
514 "DRM_R128_CLEAR: flag 0x%x color %x depth %x nbox %d\n",
516 (GLuint
)rmesa
->ClearColor
,
517 (GLuint
)rmesa
->ClearDepth
,
518 rmesa
->sarea
->nbox
);
522 clear
.clear_color
= rmesa
->ClearColor
;
523 clear
.clear_depth
= rmesa
->ClearDepth
;
524 clear
.color_mask
= rmesa
->setup
.plane_3d_mask_c
;
525 clear
.depth_mask
= depthmask
;
527 ret
= drmCommandWrite( rmesa
->driFd
, DRM_R128_CLEAR
,
528 &clear
, sizeof(clear
) );
531 UNLOCK_HARDWARE( rmesa
);
532 fprintf( stderr
, "DRM_R128_CLEAR: return = %d\n", ret
);
537 UNLOCK_HARDWARE( rmesa
);
539 rmesa
->dirty
|= R128_UPLOAD_CLIPRECTS
;
543 _swrast_Clear( ctx
, mask
);
547 /* ================================================================
548 * Depth spans, pixels
551 void r128WriteDepthSpanLocked( r128ContextPtr rmesa
,
552 GLuint n
, GLint x
, GLint y
,
553 const GLuint depth
[],
554 const GLubyte mask
[] )
556 drm_clip_rect_t
*pbox
= rmesa
->pClipRects
;
558 int nbox
= rmesa
->numClipRects
;
559 int fd
= rmesa
->driScreen
->fd
;
565 if ( nbox
>= R128_NR_SAREA_CLIPRECTS
) {
566 rmesa
->dirty
|= R128_UPLOAD_CLIPRECTS
;
569 if ( !(rmesa
->dirty
& R128_UPLOAD_CLIPRECTS
) )
572 rmesa
->sarea
->nbox
= 0;
574 rmesa
->sarea
->nbox
= nbox
;
577 d
.func
= R128_WRITE_SPAN
;
581 d
.buffer
= (unsigned int *)depth
;
582 d
.mask
= (unsigned char *)mask
;
584 drmCommandWrite( fd
, DRM_R128_DEPTH
, &d
, sizeof(d
));
589 for (i
= 0 ; i
< nbox
; ) {
590 int nr
= MIN2( i
+ R128_NR_SAREA_CLIPRECTS
, nbox
);
591 drm_clip_rect_t
*b
= rmesa
->sarea
->boxes
;
593 rmesa
->sarea
->nbox
= nr
- i
;
594 for ( ; i
< nr
; i
++) {
598 rmesa
->sarea
->dirty
|= R128_UPLOAD_CLIPRECTS
;
600 d
.func
= R128_WRITE_SPAN
;
604 d
.buffer
= (unsigned int *)depth
;
605 d
.mask
= (unsigned char *)mask
;
607 drmCommandWrite( fd
, DRM_R128_DEPTH
, &d
, sizeof(d
));
611 rmesa
->dirty
&= ~R128_UPLOAD_CLIPRECTS
;
614 void r128WriteDepthPixelsLocked( r128ContextPtr rmesa
, GLuint n
,
615 const GLint x
[], const GLint y
[],
616 const GLuint depth
[],
617 const GLubyte mask
[] )
619 drm_clip_rect_t
*pbox
= rmesa
->pClipRects
;
621 int nbox
= rmesa
->numClipRects
;
622 int fd
= rmesa
->driScreen
->fd
;
628 if ( nbox
>= R128_NR_SAREA_CLIPRECTS
) {
629 rmesa
->dirty
|= R128_UPLOAD_CLIPRECTS
;
632 if ( !(rmesa
->dirty
& R128_UPLOAD_CLIPRECTS
) )
635 rmesa
->sarea
->nbox
= 0;
637 rmesa
->sarea
->nbox
= nbox
;
640 d
.func
= R128_WRITE_PIXELS
;
644 d
.buffer
= (unsigned int *)depth
;
645 d
.mask
= (unsigned char *)mask
;
647 drmCommandWrite( fd
, DRM_R128_DEPTH
, &d
, sizeof(d
));
651 for (i
= 0 ; i
< nbox
; ) {
652 int nr
= MIN2( i
+ R128_NR_SAREA_CLIPRECTS
, nbox
);
653 drm_clip_rect_t
*b
= rmesa
->sarea
->boxes
;
655 rmesa
->sarea
->nbox
= nr
- i
;
656 for ( ; i
< nr
; i
++) {
660 rmesa
->sarea
->dirty
|= R128_UPLOAD_CLIPRECTS
;
662 d
.func
= R128_WRITE_PIXELS
;
666 d
.buffer
= (unsigned int *)depth
;
667 d
.mask
= (unsigned char *)mask
;
669 drmCommandWrite( fd
, DRM_R128_DEPTH
, &d
, sizeof(d
));
673 rmesa
->dirty
&= ~R128_UPLOAD_CLIPRECTS
;
676 void r128ReadDepthSpanLocked( r128ContextPtr rmesa
,
677 GLuint n
, GLint x
, GLint y
)
679 drm_clip_rect_t
*pbox
= rmesa
->pClipRects
;
681 int nbox
= rmesa
->numClipRects
;
682 int fd
= rmesa
->driScreen
->fd
;
688 if ( nbox
>= R128_NR_SAREA_CLIPRECTS
) {
689 rmesa
->dirty
|= R128_UPLOAD_CLIPRECTS
;
692 if ( !(rmesa
->dirty
& R128_UPLOAD_CLIPRECTS
) )
695 rmesa
->sarea
->nbox
= 0;
697 rmesa
->sarea
->nbox
= nbox
;
700 d
.func
= R128_READ_SPAN
;
707 drmCommandWrite( fd
, DRM_R128_DEPTH
, &d
, sizeof(d
));
711 for (i
= 0 ; i
< nbox
; ) {
712 int nr
= MIN2( i
+ R128_NR_SAREA_CLIPRECTS
, nbox
);
713 drm_clip_rect_t
*b
= rmesa
->sarea
->boxes
;
715 rmesa
->sarea
->nbox
= nr
- i
;
716 for ( ; i
< nr
; i
++) {
720 rmesa
->sarea
->dirty
|= R128_UPLOAD_CLIPRECTS
;
722 d
.func
= R128_READ_SPAN
;
729 drmCommandWrite( fd
, DRM_R128_DEPTH
, &d
, sizeof(d
));
733 rmesa
->dirty
&= ~R128_UPLOAD_CLIPRECTS
;
736 void r128ReadDepthPixelsLocked( r128ContextPtr rmesa
, GLuint n
,
737 const GLint x
[], const GLint y
[] )
739 drm_clip_rect_t
*pbox
= rmesa
->pClipRects
;
741 int nbox
= rmesa
->numClipRects
;
742 int fd
= rmesa
->driScreen
->fd
;
748 if ( nbox
>= R128_NR_SAREA_CLIPRECTS
) {
749 rmesa
->dirty
|= R128_UPLOAD_CLIPRECTS
;
752 if ( !(rmesa
->dirty
& R128_UPLOAD_CLIPRECTS
) )
755 rmesa
->sarea
->nbox
= 0;
757 rmesa
->sarea
->nbox
= nbox
;
760 d
.func
= R128_READ_PIXELS
;
767 drmCommandWrite( fd
, DRM_R128_DEPTH
, &d
, sizeof(d
));
771 for (i
= 0 ; i
< nbox
; ) {
772 int nr
= MIN2( i
+ R128_NR_SAREA_CLIPRECTS
, nbox
);
773 drm_clip_rect_t
*b
= rmesa
->sarea
->boxes
;
775 rmesa
->sarea
->nbox
= nr
- i
;
776 for ( ; i
< nr
; i
++) {
780 rmesa
->sarea
->dirty
|= R128_UPLOAD_CLIPRECTS
;
782 d
.func
= R128_READ_PIXELS
;
789 drmCommandWrite( fd
, DRM_R128_DEPTH
, &d
, sizeof(d
));
793 rmesa
->dirty
&= ~R128_UPLOAD_CLIPRECTS
;
797 void r128WaitForIdleLocked( r128ContextPtr rmesa
)
799 int fd
= rmesa
->r128Screen
->driScreen
->fd
;
806 ret
= drmCommandNone( fd
, DRM_R128_CCE_IDLE
);
807 } while ( ret
&& errno
== EBUSY
&& i
++ < R128_IDLE_RETRY
);
808 } while ( ( ret
== -EBUSY
) && ( to
++ < R128_TIMEOUT
) );
811 drmCommandNone( fd
, DRM_R128_CCE_RESET
);
812 UNLOCK_HARDWARE( rmesa
);
813 fprintf( stderr
, "Error: Rage 128 timed out... exiting\n" );
818 void r128InitIoctlFuncs( struct dd_function_table
*functions
)
820 functions
->Clear
= r128Clear
;