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"
48 /* temporary - should really split r128_reg.h into r128_reg.h & r128_macros.h
50 #include "r128_macros.h"
53 #define R128_TIMEOUT 2048
54 #define R128_IDLE_RETRY 32
57 /* =============================================================
58 * Hardware vertex buffer handling
61 /* Get a new VB from the pool of vertex buffers in AGP space.
63 drmBufPtr
r128GetBufferLocked( r128ContextPtr rmesa
)
65 int fd
= rmesa
->r128Screen
->driScreen
->fd
;
73 dma
.context
= rmesa
->hHWContext
;
76 dma
.send_sizes
= NULL
;
78 dma
.request_count
= 1;
79 dma
.request_size
= R128_BUFFER_SIZE
;
80 dma
.request_list
= &index
;
81 dma
.request_sizes
= &size
;
82 dma
.granted_count
= 0;
84 while ( !buf
&& ( to
++ < R128_TIMEOUT
) ) {
85 ret
= drmDMA( fd
, &dma
);
88 buf
= &rmesa
->r128Screen
->buffers
->list
[index
];
91 /* Bump the performance counter */
92 rmesa
->c_vertexBuffers
++;
99 drmCommandNone( fd
, DRM_R128_CCE_RESET
);
100 UNLOCK_HARDWARE( rmesa
);
101 fprintf( stderr
, "Error: Could not get new VB... exiting\n" );
108 void r128FlushVerticesLocked( r128ContextPtr rmesa
)
110 drm_clip_rect_t
*pbox
= rmesa
->pClipRects
;
111 int nbox
= rmesa
->numClipRects
;
112 drmBufPtr buffer
= rmesa
->vert_buf
;
113 int count
= rmesa
->num_verts
;
114 int prim
= rmesa
->hw_primitive
;
115 int fd
= rmesa
->driScreen
->fd
;
116 drm_r128_vertex_t vertex
;
119 rmesa
->num_verts
= 0;
120 rmesa
->vert_buf
= NULL
;
125 if ( rmesa
->dirty
& ~R128_UPLOAD_CLIPRECTS
)
126 r128EmitHwStateLocked( rmesa
);
131 if ( nbox
>= R128_NR_SAREA_CLIPRECTS
)
132 rmesa
->dirty
|= R128_UPLOAD_CLIPRECTS
;
134 if ( !count
|| !(rmesa
->dirty
& R128_UPLOAD_CLIPRECTS
) )
137 rmesa
->sarea
->nbox
= 0;
139 rmesa
->sarea
->nbox
= nbox
;
143 vertex
.idx
= buffer
->idx
;
144 vertex
.count
= count
;
146 drmCommandWrite( fd
, DRM_R128_VERTEX
, &vertex
, sizeof(vertex
) );
150 for ( i
= 0 ; i
< nbox
; ) {
151 int nr
= MIN2( i
+ R128_NR_SAREA_CLIPRECTS
, nbox
);
152 drm_clip_rect_t
*b
= rmesa
->sarea
->boxes
;
155 rmesa
->sarea
->nbox
= nr
- i
;
156 for ( ; i
< nr
; i
++ ) {
160 /* Finished with the buffer?
166 rmesa
->sarea
->dirty
|= R128_UPLOAD_CLIPRECTS
;
169 vertex
.idx
= buffer
->idx
;
170 vertex
.count
= count
;
171 vertex
.discard
= discard
;
172 drmCommandWrite( fd
, DRM_R128_VERTEX
, &vertex
, sizeof(vertex
) );
176 rmesa
->dirty
&= ~R128_UPLOAD_CLIPRECTS
;
183 /* ================================================================
187 void r128FireBlitLocked( r128ContextPtr rmesa
, drmBufPtr buffer
,
188 GLint offset
, GLint pitch
, GLint format
,
189 GLint x
, GLint y
, GLint width
, GLint height
)
191 drm_r128_blit_t blit
;
194 blit
.idx
= buffer
->idx
;
195 blit
.offset
= offset
;
197 blit
.format
= format
;
201 blit
.height
= height
;
203 ret
= drmCommandWrite( rmesa
->driFd
, DRM_R128_BLIT
,
204 &blit
, sizeof(blit
) );
207 UNLOCK_HARDWARE( rmesa
);
208 fprintf( stderr
, "DRM_R128_BLIT: return = %d\n", ret
);
214 /* ================================================================
215 * SwapBuffers with client-side throttling
218 static void delay( void ) {
219 /* Prevent an optimizing compiler from removing a spin loop */
222 #define R128_MAX_OUTSTANDING 2
224 /* Throttle the frame rate -- only allow one pending swap buffers
226 * GH: We probably don't want a timeout here, as we can wait as
227 * long as we want for a frame to complete. If it never does, then
228 * the card has locked.
230 static int r128WaitForFrameCompletion( r128ContextPtr rmesa
)
232 unsigned char *R128MMIO
= rmesa
->r128Screen
->mmio
.map
;
238 frame
= INREG( R128_LAST_FRAME_REG
);
239 if ( rmesa
->sarea
->last_frame
- frame
<= R128_MAX_OUTSTANDING
) {
243 /* Spin in place a bit so we aren't hammering the register */
245 for ( i
= 0 ; i
< 1024 ; i
++ ) {
253 /* Copy the back color buffer to the front color buffer.
255 void r128CopyBuffer( const __DRIdrawablePrivate
*dPriv
)
257 r128ContextPtr rmesa
;
259 GLboolean missed_target
;
262 assert(dPriv
->driContextPriv
);
263 assert(dPriv
->driContextPriv
->driverPrivate
);
265 rmesa
= (r128ContextPtr
) dPriv
->driContextPriv
->driverPrivate
;
267 if ( R128_DEBUG
& DEBUG_VERBOSE_API
) {
268 fprintf( stderr
, "\n********************************\n" );
269 fprintf( stderr
, "\n%s( %p )\n\n",
270 __FUNCTION__
, (void *)rmesa
->glCtx
);
274 FLUSH_BATCH( rmesa
);
276 LOCK_HARDWARE( rmesa
);
278 /* Throttle the frame rate -- only allow one pending swap buffers
281 if ( !r128WaitForFrameCompletion( rmesa
) ) {
282 rmesa
->hardwareWentIdle
= 1;
284 rmesa
->hardwareWentIdle
= 0;
287 UNLOCK_HARDWARE( rmesa
);
288 driWaitForVBlank( dPriv
, &rmesa
->vbl_seq
, rmesa
->vblank_flags
, &missed_target
);
289 LOCK_HARDWARE( rmesa
);
291 nbox
= dPriv
->numClipRects
; /* must be in locked region */
293 for ( i
= 0 ; i
< nbox
; ) {
294 GLint nr
= MIN2( i
+ R128_NR_SAREA_CLIPRECTS
, nbox
);
295 drm_clip_rect_t
*box
= dPriv
->pClipRects
;
296 drm_clip_rect_t
*b
= rmesa
->sarea
->boxes
;
299 for ( ; i
< nr
; i
++ ) {
303 rmesa
->sarea
->nbox
= n
;
305 ret
= drmCommandNone( rmesa
->driFd
, DRM_R128_SWAP
);
308 UNLOCK_HARDWARE( rmesa
);
309 fprintf( stderr
, "DRM_R128_SWAP: return = %d\n", ret
);
314 if ( R128_DEBUG
& DEBUG_ALWAYS_SYNC
) {
317 ret
= drmCommandNone(rmesa
->driFd
, DRM_R128_CCE_IDLE
);
318 } while ( ret
&& errno
== EBUSY
&& i
++ < R128_IDLE_RETRY
);
321 UNLOCK_HARDWARE( rmesa
);
323 rmesa
->new_state
|= R128_NEW_CONTEXT
;
324 rmesa
->dirty
|= (R128_UPLOAD_CONTEXT
|
326 R128_UPLOAD_CLIPRECTS
);
328 #if ENABLE_PERF_BOXES
329 /* Log the performance counters if necessary */
330 r128PerformanceCounters( rmesa
);
334 void r128PageFlip( const __DRIdrawablePrivate
*dPriv
)
336 r128ContextPtr rmesa
;
338 GLboolean missed_target
;
341 assert(dPriv
->driContextPriv
);
342 assert(dPriv
->driContextPriv
->driverPrivate
);
344 rmesa
= (r128ContextPtr
) dPriv
->driContextPriv
->driverPrivate
;
346 if ( R128_DEBUG
& DEBUG_VERBOSE_API
) {
347 fprintf( stderr
, "\n%s( %p ): page=%d\n\n",
348 __FUNCTION__
, (void *)rmesa
->glCtx
, rmesa
->sarea
->pfCurrentPage
);
351 FLUSH_BATCH( rmesa
);
353 LOCK_HARDWARE( rmesa
);
355 /* Throttle the frame rate -- only allow one pending swap buffers
358 if ( !r128WaitForFrameCompletion( rmesa
) ) {
359 rmesa
->hardwareWentIdle
= 1;
361 rmesa
->hardwareWentIdle
= 0;
364 UNLOCK_HARDWARE( rmesa
);
365 driWaitForVBlank( dPriv
, &rmesa
->vbl_seq
, rmesa
->vblank_flags
, &missed_target
);
366 LOCK_HARDWARE( rmesa
);
368 /* The kernel will have been initialized to perform page flipping
369 * on a swapbuffers ioctl.
371 ret
= drmCommandNone( rmesa
->driFd
, DRM_R128_FLIP
);
373 UNLOCK_HARDWARE( rmesa
);
376 fprintf( stderr
, "DRM_R128_FLIP: return = %d\n", ret
);
380 if ( rmesa
->sarea
->pfCurrentPage
== 1 ) {
381 rmesa
->drawOffset
= rmesa
->r128Screen
->frontOffset
;
382 rmesa
->drawPitch
= rmesa
->r128Screen
->frontPitch
;
384 rmesa
->drawOffset
= rmesa
->r128Screen
->backOffset
;
385 rmesa
->drawPitch
= rmesa
->r128Screen
->backPitch
;
388 rmesa
->setup
.dst_pitch_offset_c
= (((rmesa
->drawPitch
/8) << 21) |
389 (rmesa
->drawOffset
>> 5));
390 rmesa
->new_state
|= R128_NEW_WINDOW
;
392 /* FIXME: Do we need this anymore? */
393 rmesa
->new_state
|= R128_NEW_CONTEXT
;
394 rmesa
->dirty
|= (R128_UPLOAD_CONTEXT
|
396 R128_UPLOAD_CLIPRECTS
);
398 #if ENABLE_PERF_BOXES
399 /* Log the performance counters if necessary */
400 r128PerformanceCounters( rmesa
);
405 /* ================================================================
409 static void r128Clear( GLcontext
*ctx
, GLbitfield mask
, GLboolean all
,
410 GLint cx
, GLint cy
, GLint cw
, GLint ch
)
412 r128ContextPtr rmesa
= R128_CONTEXT(ctx
);
413 __DRIdrawablePrivate
*dPriv
= rmesa
->driDrawable
;
414 drm_r128_clear_t clear
;
419 if ( R128_DEBUG
& DEBUG_VERBOSE_API
) {
420 fprintf( stderr
, "%s:\n", __FUNCTION__
);
423 FLUSH_BATCH( rmesa
);
425 /* The only state change we care about here is the RGBA colormask
426 * We'll just update that state, if needed. If we do more then
427 * there's some strange side-effects that the conformance tests find.
429 if ( rmesa
->new_state
& R128_NEW_MASKS
) {
430 const GLuint save_state
= rmesa
->new_state
;
431 rmesa
->new_state
= R128_NEW_MASKS
;
432 r128DDUpdateHWState( ctx
);
433 rmesa
->new_state
= save_state
& ~R128_NEW_MASKS
;
436 if ( mask
& DD_FRONT_LEFT_BIT
) {
438 mask
&= ~DD_FRONT_LEFT_BIT
;
441 if ( mask
& DD_BACK_LEFT_BIT
) {
443 mask
&= ~DD_BACK_LEFT_BIT
;
446 if ( ( mask
& DD_DEPTH_BIT
) && ctx
->Depth
.Mask
) {
448 mask
&= ~DD_DEPTH_BIT
;
451 /* FIXME: Add stencil support */
452 if ( mask
& DD_STENCIL_BIT
) {
453 flags
|= DRM_R128_DEPTH_BUFFER
;
454 mask
&= ~DD_STENCIL_BIT
;
460 /* Flip top to bottom */
462 cy
= dPriv
->y
+ dPriv
->h
- cy
- ch
;
464 LOCK_HARDWARE( rmesa
);
466 /* FIXME: Do we actually need this?
468 if ( rmesa
->dirty
& ~R128_UPLOAD_CLIPRECTS
) {
469 r128EmitHwStateLocked( rmesa
);
472 for ( i
= 0 ; i
< rmesa
->numClipRects
; ) {
473 GLint nr
= MIN2( i
+ R128_NR_SAREA_CLIPRECTS
, rmesa
->numClipRects
);
474 drm_clip_rect_t
*box
= rmesa
->pClipRects
;
475 drm_clip_rect_t
*b
= rmesa
->sarea
->boxes
;
479 for ( ; i
< nr
; i
++ ) {
482 GLint w
= box
[i
].x2
- x
;
483 GLint h
= box
[i
].y2
- y
;
485 if ( x
< cx
) w
-= cx
- x
, x
= cx
;
486 if ( y
< cy
) h
-= cy
- y
, y
= cy
;
487 if ( x
+ w
> cx
+ cw
) w
= cx
+ cw
- x
;
488 if ( y
+ h
> cy
+ ch
) h
= cy
+ ch
- y
;
489 if ( w
<= 0 ) continue;
490 if ( h
<= 0 ) continue;
500 for ( ; i
< nr
; i
++ ) {
506 rmesa
->sarea
->nbox
= n
;
508 if ( R128_DEBUG
& DEBUG_VERBOSE_IOCTL
) {
510 "DRM_R128_CLEAR: flag 0x%x color %x depth %x nbox %d\n",
512 (GLuint
)rmesa
->ClearColor
,
513 (GLuint
)rmesa
->ClearDepth
,
514 rmesa
->sarea
->nbox
);
518 clear
.clear_color
= rmesa
->ClearColor
;
519 clear
.clear_depth
= rmesa
->ClearDepth
;
520 clear
.color_mask
= rmesa
->setup
.plane_3d_mask_c
;
521 clear
.depth_mask
= ~0;
523 ret
= drmCommandWrite( rmesa
->driFd
, DRM_R128_CLEAR
,
524 &clear
, sizeof(clear
) );
527 UNLOCK_HARDWARE( rmesa
);
528 fprintf( stderr
, "DRM_R128_CLEAR: return = %d\n", ret
);
533 UNLOCK_HARDWARE( rmesa
);
535 rmesa
->dirty
|= R128_UPLOAD_CLIPRECTS
;
539 _swrast_Clear( ctx
, mask
, all
, cx
, cy
, cw
, ch
);
543 /* ================================================================
544 * Depth spans, pixels
547 void r128WriteDepthSpanLocked( r128ContextPtr rmesa
,
548 GLuint n
, GLint x
, GLint y
,
549 const GLdepth depth
[],
550 const GLubyte mask
[] )
552 drm_clip_rect_t
*pbox
= rmesa
->pClipRects
;
554 int nbox
= rmesa
->numClipRects
;
555 int fd
= rmesa
->driScreen
->fd
;
561 if ( nbox
>= R128_NR_SAREA_CLIPRECTS
) {
562 rmesa
->dirty
|= R128_UPLOAD_CLIPRECTS
;
565 if ( !(rmesa
->dirty
& R128_UPLOAD_CLIPRECTS
) )
568 rmesa
->sarea
->nbox
= 0;
570 rmesa
->sarea
->nbox
= nbox
;
573 d
.func
= R128_WRITE_SPAN
;
577 d
.buffer
= (unsigned int *)depth
;
578 d
.mask
= (unsigned char *)mask
;
580 drmCommandWrite( fd
, DRM_R128_DEPTH
, &d
, sizeof(d
));
585 for (i
= 0 ; i
< nbox
; ) {
586 int nr
= MIN2( i
+ R128_NR_SAREA_CLIPRECTS
, nbox
);
587 drm_clip_rect_t
*b
= rmesa
->sarea
->boxes
;
589 rmesa
->sarea
->nbox
= nr
- i
;
590 for ( ; i
< nr
; i
++) {
594 rmesa
->sarea
->dirty
|= R128_UPLOAD_CLIPRECTS
;
596 d
.func
= R128_WRITE_SPAN
;
600 d
.buffer
= (unsigned int *)depth
;
601 d
.mask
= (unsigned char *)mask
;
603 drmCommandWrite( fd
, DRM_R128_DEPTH
, &d
, sizeof(d
));
607 rmesa
->dirty
&= ~R128_UPLOAD_CLIPRECTS
;
610 void r128WriteDepthPixelsLocked( r128ContextPtr rmesa
, GLuint n
,
611 const GLint x
[], const GLint y
[],
612 const GLdepth depth
[],
613 const GLubyte mask
[] )
615 drm_clip_rect_t
*pbox
= rmesa
->pClipRects
;
617 int nbox
= rmesa
->numClipRects
;
618 int fd
= rmesa
->driScreen
->fd
;
624 if ( nbox
>= R128_NR_SAREA_CLIPRECTS
) {
625 rmesa
->dirty
|= R128_UPLOAD_CLIPRECTS
;
628 if ( !(rmesa
->dirty
& R128_UPLOAD_CLIPRECTS
) )
631 rmesa
->sarea
->nbox
= 0;
633 rmesa
->sarea
->nbox
= nbox
;
636 d
.func
= R128_WRITE_PIXELS
;
640 d
.buffer
= (unsigned int *)depth
;
641 d
.mask
= (unsigned char *)mask
;
643 drmCommandWrite( fd
, DRM_R128_DEPTH
, &d
, sizeof(d
));
647 for (i
= 0 ; i
< nbox
; ) {
648 int nr
= MIN2( i
+ R128_NR_SAREA_CLIPRECTS
, nbox
);
649 drm_clip_rect_t
*b
= rmesa
->sarea
->boxes
;
651 rmesa
->sarea
->nbox
= nr
- i
;
652 for ( ; i
< nr
; i
++) {
656 rmesa
->sarea
->dirty
|= R128_UPLOAD_CLIPRECTS
;
658 d
.func
= R128_WRITE_PIXELS
;
662 d
.buffer
= (unsigned int *)depth
;
663 d
.mask
= (unsigned char *)mask
;
665 drmCommandWrite( fd
, DRM_R128_DEPTH
, &d
, sizeof(d
));
669 rmesa
->dirty
&= ~R128_UPLOAD_CLIPRECTS
;
672 void r128ReadDepthSpanLocked( r128ContextPtr rmesa
,
673 GLuint n
, GLint x
, GLint y
)
675 drm_clip_rect_t
*pbox
= rmesa
->pClipRects
;
677 int nbox
= rmesa
->numClipRects
;
678 int fd
= rmesa
->driScreen
->fd
;
684 if ( nbox
>= R128_NR_SAREA_CLIPRECTS
) {
685 rmesa
->dirty
|= R128_UPLOAD_CLIPRECTS
;
688 if ( !(rmesa
->dirty
& R128_UPLOAD_CLIPRECTS
) )
691 rmesa
->sarea
->nbox
= 0;
693 rmesa
->sarea
->nbox
= nbox
;
696 d
.func
= R128_READ_SPAN
;
703 drmCommandWrite( fd
, DRM_R128_DEPTH
, &d
, sizeof(d
));
707 for (i
= 0 ; i
< nbox
; ) {
708 int nr
= MIN2( i
+ R128_NR_SAREA_CLIPRECTS
, nbox
);
709 drm_clip_rect_t
*b
= rmesa
->sarea
->boxes
;
711 rmesa
->sarea
->nbox
= nr
- i
;
712 for ( ; i
< nr
; i
++) {
716 rmesa
->sarea
->dirty
|= R128_UPLOAD_CLIPRECTS
;
718 d
.func
= R128_READ_SPAN
;
725 drmCommandWrite( fd
, DRM_R128_DEPTH
, &d
, sizeof(d
));
729 rmesa
->dirty
&= ~R128_UPLOAD_CLIPRECTS
;
732 void r128ReadDepthPixelsLocked( r128ContextPtr rmesa
, GLuint n
,
733 const GLint x
[], const GLint y
[] )
735 drm_clip_rect_t
*pbox
= rmesa
->pClipRects
;
737 int nbox
= rmesa
->numClipRects
;
738 int fd
= rmesa
->driScreen
->fd
;
744 if ( nbox
>= R128_NR_SAREA_CLIPRECTS
) {
745 rmesa
->dirty
|= R128_UPLOAD_CLIPRECTS
;
748 if ( !(rmesa
->dirty
& R128_UPLOAD_CLIPRECTS
) )
751 rmesa
->sarea
->nbox
= 0;
753 rmesa
->sarea
->nbox
= nbox
;
756 d
.func
= R128_READ_PIXELS
;
763 drmCommandWrite( fd
, DRM_R128_DEPTH
, &d
, sizeof(d
));
767 for (i
= 0 ; i
< nbox
; ) {
768 int nr
= MIN2( i
+ R128_NR_SAREA_CLIPRECTS
, nbox
);
769 drm_clip_rect_t
*b
= rmesa
->sarea
->boxes
;
771 rmesa
->sarea
->nbox
= nr
- i
;
772 for ( ; i
< nr
; i
++) {
776 rmesa
->sarea
->dirty
|= R128_UPLOAD_CLIPRECTS
;
778 d
.func
= R128_READ_PIXELS
;
785 drmCommandWrite( fd
, DRM_R128_DEPTH
, &d
, sizeof(d
));
789 rmesa
->dirty
&= ~R128_UPLOAD_CLIPRECTS
;
793 void r128WaitForIdleLocked( r128ContextPtr rmesa
)
795 int fd
= rmesa
->r128Screen
->driScreen
->fd
;
802 ret
= drmCommandNone( fd
, DRM_R128_CCE_IDLE
);
803 } while ( ret
&& errno
== EBUSY
&& i
++ < R128_IDLE_RETRY
);
804 } while ( ( ret
== -EBUSY
) && ( to
++ < R128_TIMEOUT
) );
807 drmCommandNone( fd
, DRM_R128_CCE_RESET
);
808 UNLOCK_HARDWARE( rmesa
);
809 fprintf( stderr
, "Error: Rage 128 timed out... exiting\n" );
814 void r128InitIoctlFuncs( struct dd_function_table
*functions
)
816 functions
->Clear
= r128Clear
;