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 #define R128_TIMEOUT 2048
48 #define R128_IDLE_RETRY 32
51 /* =============================================================
52 * Hardware vertex buffer handling
55 /* Get a new VB from the pool of vertex buffers in AGP space.
57 drmBufPtr
r128GetBufferLocked( r128ContextPtr rmesa
)
59 int fd
= rmesa
->r128Screen
->driScreen
->fd
;
67 dma
.context
= rmesa
->hHWContext
;
70 dma
.send_sizes
= NULL
;
72 dma
.request_count
= 1;
73 dma
.request_size
= R128_BUFFER_SIZE
;
74 dma
.request_list
= &index
;
75 dma
.request_sizes
= &size
;
76 dma
.granted_count
= 0;
78 while ( !buf
&& ( to
++ < R128_TIMEOUT
) ) {
79 ret
= drmDMA( fd
, &dma
);
82 buf
= &rmesa
->r128Screen
->buffers
->list
[index
];
85 /* Bump the performance counter */
86 rmesa
->c_vertexBuffers
++;
93 drmCommandNone( fd
, DRM_R128_CCE_RESET
);
94 UNLOCK_HARDWARE( rmesa
);
95 fprintf( stderr
, "Error: Could not get new VB... exiting\n" );
102 void r128FlushVerticesLocked( r128ContextPtr rmesa
)
104 drm_clip_rect_t
*pbox
= rmesa
->pClipRects
;
105 int nbox
= rmesa
->numClipRects
;
106 drmBufPtr buffer
= rmesa
->vert_buf
;
107 int count
= rmesa
->num_verts
;
108 int prim
= rmesa
->hw_primitive
;
109 int fd
= rmesa
->driScreen
->fd
;
110 drm_r128_vertex_t vertex
;
113 rmesa
->num_verts
= 0;
114 rmesa
->vert_buf
= NULL
;
119 if ( rmesa
->dirty
& ~R128_UPLOAD_CLIPRECTS
)
120 r128EmitHwStateLocked( rmesa
);
125 if ( nbox
>= R128_NR_SAREA_CLIPRECTS
)
126 rmesa
->dirty
|= R128_UPLOAD_CLIPRECTS
;
128 if ( !count
|| !(rmesa
->dirty
& R128_UPLOAD_CLIPRECTS
) )
131 rmesa
->sarea
->nbox
= 0;
133 rmesa
->sarea
->nbox
= nbox
;
137 vertex
.idx
= buffer
->idx
;
138 vertex
.count
= count
;
140 drmCommandWrite( fd
, DRM_R128_VERTEX
, &vertex
, sizeof(vertex
) );
144 for ( i
= 0 ; i
< nbox
; ) {
145 int nr
= MIN2( i
+ R128_NR_SAREA_CLIPRECTS
, nbox
);
146 drm_clip_rect_t
*b
= rmesa
->sarea
->boxes
;
149 rmesa
->sarea
->nbox
= nr
- i
;
150 for ( ; i
< nr
; i
++ ) {
154 /* Finished with the buffer?
160 rmesa
->sarea
->dirty
|= R128_UPLOAD_CLIPRECTS
;
163 vertex
.idx
= buffer
->idx
;
164 vertex
.count
= count
;
165 vertex
.discard
= discard
;
166 drmCommandWrite( fd
, DRM_R128_VERTEX
, &vertex
, sizeof(vertex
) );
170 rmesa
->dirty
&= ~R128_UPLOAD_CLIPRECTS
;
177 /* ================================================================
181 void r128FireBlitLocked( r128ContextPtr rmesa
, drmBufPtr buffer
,
182 GLint offset
, GLint pitch
, GLint format
,
183 GLint x
, GLint y
, GLint width
, GLint height
)
185 drm_r128_blit_t blit
;
188 blit
.idx
= buffer
->idx
;
189 blit
.offset
= offset
;
191 blit
.format
= format
;
195 blit
.height
= height
;
197 ret
= drmCommandWrite( rmesa
->driFd
, DRM_R128_BLIT
,
198 &blit
, sizeof(blit
) );
201 UNLOCK_HARDWARE( rmesa
);
202 fprintf( stderr
, "DRM_R128_BLIT: return = %d\n", ret
);
208 /* ================================================================
209 * SwapBuffers with client-side throttling
212 static void delay( void ) {
213 /* Prevent an optimizing compiler from removing a spin loop */
216 #define R128_MAX_OUTSTANDING 2
219 /* Throttle the frame rate -- only allow one pending swap buffers
221 * GH: We probably don't want a timeout here, as we can wait as
222 * long as we want for a frame to complete. If it never does, then
223 * the card has locked.
225 static int r128WaitForFrameCompletion( r128ContextPtr rmesa
)
227 unsigned char *R128MMIO
= rmesa
->r128Screen
->mmio
.map
;
232 uint32_t frame
= LE32_TO_CPU(*(volatile uint32_t *)(R128MMIO
+ R128_LAST_FRAME_REG
));
234 if ( rmesa
->sarea
->last_frame
- frame
<= R128_MAX_OUTSTANDING
) {
238 /* Spin in place a bit so we aren't hammering the register */
240 for ( i
= 0 ; i
< 1024 ; i
++ ) {
248 /* Copy the back color buffer to the front color buffer.
250 void r128CopyBuffer( const __DRIdrawablePrivate
*dPriv
)
252 r128ContextPtr rmesa
;
254 GLboolean missed_target
;
257 assert(dPriv
->driContextPriv
);
258 assert(dPriv
->driContextPriv
->driverPrivate
);
260 rmesa
= (r128ContextPtr
) dPriv
->driContextPriv
->driverPrivate
;
262 if ( R128_DEBUG
& DEBUG_VERBOSE_API
) {
263 fprintf( stderr
, "\n********************************\n" );
264 fprintf( stderr
, "\n%s( %p )\n\n",
265 __FUNCTION__
, (void *)rmesa
->glCtx
);
269 FLUSH_BATCH( rmesa
);
271 LOCK_HARDWARE( rmesa
);
273 /* Throttle the frame rate -- only allow one pending swap buffers
276 if ( !r128WaitForFrameCompletion( rmesa
) ) {
277 rmesa
->hardwareWentIdle
= 1;
279 rmesa
->hardwareWentIdle
= 0;
282 UNLOCK_HARDWARE( rmesa
);
283 driWaitForVBlank( dPriv
, &rmesa
->vbl_seq
, rmesa
->vblank_flags
, &missed_target
);
284 LOCK_HARDWARE( rmesa
);
286 nbox
= dPriv
->numClipRects
; /* must be in locked region */
288 for ( i
= 0 ; i
< nbox
; ) {
289 GLint nr
= MIN2( i
+ R128_NR_SAREA_CLIPRECTS
, nbox
);
290 drm_clip_rect_t
*box
= dPriv
->pClipRects
;
291 drm_clip_rect_t
*b
= rmesa
->sarea
->boxes
;
294 for ( ; i
< nr
; i
++ ) {
298 rmesa
->sarea
->nbox
= n
;
300 ret
= drmCommandNone( rmesa
->driFd
, DRM_R128_SWAP
);
303 UNLOCK_HARDWARE( rmesa
);
304 fprintf( stderr
, "DRM_R128_SWAP: return = %d\n", ret
);
309 if ( R128_DEBUG
& DEBUG_ALWAYS_SYNC
) {
312 ret
= drmCommandNone(rmesa
->driFd
, DRM_R128_CCE_IDLE
);
313 } while ( ret
&& errno
== EBUSY
&& i
++ < R128_IDLE_RETRY
);
316 UNLOCK_HARDWARE( rmesa
);
318 rmesa
->new_state
|= R128_NEW_CONTEXT
;
319 rmesa
->dirty
|= (R128_UPLOAD_CONTEXT
|
321 R128_UPLOAD_CLIPRECTS
);
323 #if ENABLE_PERF_BOXES
324 /* Log the performance counters if necessary */
325 r128PerformanceCounters( rmesa
);
329 void r128PageFlip( const __DRIdrawablePrivate
*dPriv
)
331 r128ContextPtr rmesa
;
333 GLboolean missed_target
;
336 assert(dPriv
->driContextPriv
);
337 assert(dPriv
->driContextPriv
->driverPrivate
);
339 rmesa
= (r128ContextPtr
) dPriv
->driContextPriv
->driverPrivate
;
341 if ( R128_DEBUG
& DEBUG_VERBOSE_API
) {
342 fprintf( stderr
, "\n%s( %p ): page=%d\n\n",
343 __FUNCTION__
, (void *)rmesa
->glCtx
, rmesa
->sarea
->pfCurrentPage
);
346 FLUSH_BATCH( rmesa
);
348 LOCK_HARDWARE( rmesa
);
350 /* Throttle the frame rate -- only allow one pending swap buffers
353 if ( !r128WaitForFrameCompletion( rmesa
) ) {
354 rmesa
->hardwareWentIdle
= 1;
356 rmesa
->hardwareWentIdle
= 0;
359 UNLOCK_HARDWARE( rmesa
);
360 driWaitForVBlank( dPriv
, &rmesa
->vbl_seq
, rmesa
->vblank_flags
, &missed_target
);
361 LOCK_HARDWARE( rmesa
);
363 /* The kernel will have been initialized to perform page flipping
364 * on a swapbuffers ioctl.
366 ret
= drmCommandNone( rmesa
->driFd
, DRM_R128_FLIP
);
368 UNLOCK_HARDWARE( rmesa
);
371 fprintf( stderr
, "DRM_R128_FLIP: return = %d\n", ret
);
375 if ( rmesa
->sarea
->pfCurrentPage
== 1 ) {
376 rmesa
->drawOffset
= rmesa
->r128Screen
->frontOffset
;
377 rmesa
->drawPitch
= rmesa
->r128Screen
->frontPitch
;
379 rmesa
->drawOffset
= rmesa
->r128Screen
->backOffset
;
380 rmesa
->drawPitch
= rmesa
->r128Screen
->backPitch
;
383 rmesa
->setup
.dst_pitch_offset_c
= (((rmesa
->drawPitch
/8) << 21) |
384 (rmesa
->drawOffset
>> 5));
385 rmesa
->new_state
|= R128_NEW_WINDOW
;
387 /* FIXME: Do we need this anymore? */
388 rmesa
->new_state
|= R128_NEW_CONTEXT
;
389 rmesa
->dirty
|= (R128_UPLOAD_CONTEXT
|
391 R128_UPLOAD_CLIPRECTS
);
393 #if ENABLE_PERF_BOXES
394 /* Log the performance counters if necessary */
395 r128PerformanceCounters( rmesa
);
400 /* ================================================================
404 static void r128Clear( GLcontext
*ctx
, GLbitfield mask
, GLboolean all
,
405 GLint cx
, GLint cy
, GLint cw
, GLint ch
)
407 r128ContextPtr rmesa
= R128_CONTEXT(ctx
);
408 __DRIdrawablePrivate
*dPriv
= rmesa
->driDrawable
;
409 drm_r128_clear_t clear
;
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
& DD_FRONT_LEFT_BIT
) {
433 mask
&= ~DD_FRONT_LEFT_BIT
;
436 if ( mask
& DD_BACK_LEFT_BIT
) {
438 mask
&= ~DD_BACK_LEFT_BIT
;
441 if ( ( mask
& DD_DEPTH_BIT
) && ctx
->Depth
.Mask
) {
443 mask
&= ~DD_DEPTH_BIT
;
446 /* FIXME: Add stencil support */
447 if ( mask
& DD_STENCIL_BIT
) {
448 flags
|= DRM_R128_DEPTH_BUFFER
;
449 mask
&= ~DD_STENCIL_BIT
;
455 /* Flip top to bottom */
457 cy
= dPriv
->y
+ dPriv
->h
- cy
- ch
;
459 LOCK_HARDWARE( rmesa
);
461 /* FIXME: Do we actually need this?
463 if ( rmesa
->dirty
& ~R128_UPLOAD_CLIPRECTS
) {
464 r128EmitHwStateLocked( rmesa
);
467 for ( i
= 0 ; i
< rmesa
->numClipRects
; ) {
468 GLint nr
= MIN2( i
+ R128_NR_SAREA_CLIPRECTS
, rmesa
->numClipRects
);
469 drm_clip_rect_t
*box
= rmesa
->pClipRects
;
470 drm_clip_rect_t
*b
= rmesa
->sarea
->boxes
;
474 for ( ; i
< nr
; i
++ ) {
477 GLint w
= box
[i
].x2
- x
;
478 GLint h
= box
[i
].y2
- y
;
480 if ( x
< cx
) w
-= cx
- x
, x
= cx
;
481 if ( y
< cy
) h
-= cy
- y
, y
= cy
;
482 if ( x
+ w
> cx
+ cw
) w
= cx
+ cw
- x
;
483 if ( y
+ h
> cy
+ ch
) h
= cy
+ ch
- y
;
484 if ( w
<= 0 ) continue;
485 if ( h
<= 0 ) continue;
495 for ( ; i
< nr
; i
++ ) {
501 rmesa
->sarea
->nbox
= n
;
503 if ( R128_DEBUG
& DEBUG_VERBOSE_IOCTL
) {
505 "DRM_R128_CLEAR: flag 0x%x color %x depth %x nbox %d\n",
507 (GLuint
)rmesa
->ClearColor
,
508 (GLuint
)rmesa
->ClearDepth
,
509 rmesa
->sarea
->nbox
);
513 clear
.clear_color
= rmesa
->ClearColor
;
514 clear
.clear_depth
= rmesa
->ClearDepth
;
515 clear
.color_mask
= rmesa
->setup
.plane_3d_mask_c
;
516 clear
.depth_mask
= ~0;
518 ret
= drmCommandWrite( rmesa
->driFd
, DRM_R128_CLEAR
,
519 &clear
, sizeof(clear
) );
522 UNLOCK_HARDWARE( rmesa
);
523 fprintf( stderr
, "DRM_R128_CLEAR: return = %d\n", ret
);
528 UNLOCK_HARDWARE( rmesa
);
530 rmesa
->dirty
|= R128_UPLOAD_CLIPRECTS
;
534 _swrast_Clear( ctx
, mask
, all
, cx
, cy
, cw
, ch
);
538 /* ================================================================
539 * Depth spans, pixels
542 void r128WriteDepthSpanLocked( r128ContextPtr rmesa
,
543 GLuint n
, GLint x
, GLint y
,
544 const GLdepth depth
[],
545 const GLubyte mask
[] )
547 drm_clip_rect_t
*pbox
= rmesa
->pClipRects
;
549 int nbox
= rmesa
->numClipRects
;
550 int fd
= rmesa
->driScreen
->fd
;
556 if ( nbox
>= R128_NR_SAREA_CLIPRECTS
) {
557 rmesa
->dirty
|= R128_UPLOAD_CLIPRECTS
;
560 if ( !(rmesa
->dirty
& R128_UPLOAD_CLIPRECTS
) )
563 rmesa
->sarea
->nbox
= 0;
565 rmesa
->sarea
->nbox
= nbox
;
568 d
.func
= R128_WRITE_SPAN
;
572 d
.buffer
= (unsigned int *)depth
;
573 d
.mask
= (unsigned char *)mask
;
575 drmCommandWrite( fd
, DRM_R128_DEPTH
, &d
, sizeof(d
));
580 for (i
= 0 ; i
< nbox
; ) {
581 int nr
= MIN2( i
+ R128_NR_SAREA_CLIPRECTS
, nbox
);
582 drm_clip_rect_t
*b
= rmesa
->sarea
->boxes
;
584 rmesa
->sarea
->nbox
= nr
- i
;
585 for ( ; i
< nr
; i
++) {
589 rmesa
->sarea
->dirty
|= R128_UPLOAD_CLIPRECTS
;
591 d
.func
= R128_WRITE_SPAN
;
595 d
.buffer
= (unsigned int *)depth
;
596 d
.mask
= (unsigned char *)mask
;
598 drmCommandWrite( fd
, DRM_R128_DEPTH
, &d
, sizeof(d
));
602 rmesa
->dirty
&= ~R128_UPLOAD_CLIPRECTS
;
605 void r128WriteDepthPixelsLocked( r128ContextPtr rmesa
, GLuint n
,
606 const GLint x
[], const GLint y
[],
607 const GLdepth depth
[],
608 const GLubyte mask
[] )
610 drm_clip_rect_t
*pbox
= rmesa
->pClipRects
;
612 int nbox
= rmesa
->numClipRects
;
613 int fd
= rmesa
->driScreen
->fd
;
619 if ( nbox
>= R128_NR_SAREA_CLIPRECTS
) {
620 rmesa
->dirty
|= R128_UPLOAD_CLIPRECTS
;
623 if ( !(rmesa
->dirty
& R128_UPLOAD_CLIPRECTS
) )
626 rmesa
->sarea
->nbox
= 0;
628 rmesa
->sarea
->nbox
= nbox
;
631 d
.func
= R128_WRITE_PIXELS
;
635 d
.buffer
= (unsigned int *)depth
;
636 d
.mask
= (unsigned char *)mask
;
638 drmCommandWrite( fd
, DRM_R128_DEPTH
, &d
, sizeof(d
));
642 for (i
= 0 ; i
< nbox
; ) {
643 int nr
= MIN2( i
+ R128_NR_SAREA_CLIPRECTS
, nbox
);
644 drm_clip_rect_t
*b
= rmesa
->sarea
->boxes
;
646 rmesa
->sarea
->nbox
= nr
- i
;
647 for ( ; i
< nr
; i
++) {
651 rmesa
->sarea
->dirty
|= R128_UPLOAD_CLIPRECTS
;
653 d
.func
= R128_WRITE_PIXELS
;
657 d
.buffer
= (unsigned int *)depth
;
658 d
.mask
= (unsigned char *)mask
;
660 drmCommandWrite( fd
, DRM_R128_DEPTH
, &d
, sizeof(d
));
664 rmesa
->dirty
&= ~R128_UPLOAD_CLIPRECTS
;
667 void r128ReadDepthSpanLocked( r128ContextPtr rmesa
,
668 GLuint n
, GLint x
, GLint y
)
670 drm_clip_rect_t
*pbox
= rmesa
->pClipRects
;
672 int nbox
= rmesa
->numClipRects
;
673 int fd
= rmesa
->driScreen
->fd
;
679 if ( nbox
>= R128_NR_SAREA_CLIPRECTS
) {
680 rmesa
->dirty
|= R128_UPLOAD_CLIPRECTS
;
683 if ( !(rmesa
->dirty
& R128_UPLOAD_CLIPRECTS
) )
686 rmesa
->sarea
->nbox
= 0;
688 rmesa
->sarea
->nbox
= nbox
;
691 d
.func
= R128_READ_SPAN
;
698 drmCommandWrite( fd
, DRM_R128_DEPTH
, &d
, sizeof(d
));
702 for (i
= 0 ; i
< nbox
; ) {
703 int nr
= MIN2( i
+ R128_NR_SAREA_CLIPRECTS
, nbox
);
704 drm_clip_rect_t
*b
= rmesa
->sarea
->boxes
;
706 rmesa
->sarea
->nbox
= nr
- i
;
707 for ( ; i
< nr
; i
++) {
711 rmesa
->sarea
->dirty
|= R128_UPLOAD_CLIPRECTS
;
713 d
.func
= R128_READ_SPAN
;
720 drmCommandWrite( fd
, DRM_R128_DEPTH
, &d
, sizeof(d
));
724 rmesa
->dirty
&= ~R128_UPLOAD_CLIPRECTS
;
727 void r128ReadDepthPixelsLocked( r128ContextPtr rmesa
, GLuint n
,
728 const GLint x
[], const GLint y
[] )
730 drm_clip_rect_t
*pbox
= rmesa
->pClipRects
;
732 int nbox
= rmesa
->numClipRects
;
733 int fd
= rmesa
->driScreen
->fd
;
739 if ( nbox
>= R128_NR_SAREA_CLIPRECTS
) {
740 rmesa
->dirty
|= R128_UPLOAD_CLIPRECTS
;
743 if ( !(rmesa
->dirty
& R128_UPLOAD_CLIPRECTS
) )
746 rmesa
->sarea
->nbox
= 0;
748 rmesa
->sarea
->nbox
= nbox
;
751 d
.func
= R128_READ_PIXELS
;
758 drmCommandWrite( fd
, DRM_R128_DEPTH
, &d
, sizeof(d
));
762 for (i
= 0 ; i
< nbox
; ) {
763 int nr
= MIN2( i
+ R128_NR_SAREA_CLIPRECTS
, nbox
);
764 drm_clip_rect_t
*b
= rmesa
->sarea
->boxes
;
766 rmesa
->sarea
->nbox
= nr
- i
;
767 for ( ; i
< nr
; i
++) {
771 rmesa
->sarea
->dirty
|= R128_UPLOAD_CLIPRECTS
;
773 d
.func
= R128_READ_PIXELS
;
780 drmCommandWrite( fd
, DRM_R128_DEPTH
, &d
, sizeof(d
));
784 rmesa
->dirty
&= ~R128_UPLOAD_CLIPRECTS
;
788 void r128WaitForIdleLocked( r128ContextPtr rmesa
)
790 int fd
= rmesa
->r128Screen
->driScreen
->fd
;
797 ret
= drmCommandNone( fd
, DRM_R128_CCE_IDLE
);
798 } while ( ret
&& errno
== EBUSY
&& i
++ < R128_IDLE_RETRY
);
799 } while ( ( ret
== -EBUSY
) && ( to
++ < R128_TIMEOUT
) );
802 drmCommandNone( fd
, DRM_R128_CCE_RESET
);
803 UNLOCK_HARDWARE( rmesa
);
804 fprintf( stderr
, "Error: Rage 128 timed out... exiting\n" );
809 void r128InitIoctlFuncs( struct dd_function_table
*functions
)
811 functions
->Clear
= r128Clear
;