1 /**************************************************************************
3 Copyright 1999, 2000 ATI Technologies Inc. and Precision Insight, Inc.,
7 Permission is hereby granted, free of charge, to any person obtaining a
8 copy of this software and associated documentation files (the "Software"),
9 to deal in the Software without restriction, including without limitation
10 on the rights to use, copy, modify, merge, publish, distribute, sub
11 license, and/or sell copies of the Software, and to permit persons to whom
12 the Software is furnished to do so, subject to the following conditions:
14 The above copyright notice and this permission notice (including the next
15 paragraph) shall be included in all copies or substantial portions of the
18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
21 ATI, PRECISION INSIGHT AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
22 DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
23 OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
24 USE OR OTHER DEALINGS IN THE SOFTWARE.
26 **************************************************************************/
30 * Gareth Hughes <gareth@valinux.com>
35 #define STANDALONE_MMIO
36 #include "r128_context.h"
37 #include "r128_state.h"
38 #include "r128_ioctl.h"
39 #include "main/imports.h"
40 #include "main/macros.h"
42 #include "swrast/swrast.h"
46 #include "drirenderbuffer.h"
48 #define R128_TIMEOUT 2048
49 #define R128_IDLE_RETRY 32
52 /* =============================================================
53 * Hardware vertex buffer handling
56 /* Get a new VB from the pool of vertex buffers in AGP space.
58 drmBufPtr
r128GetBufferLocked( r128ContextPtr rmesa
)
60 int fd
= rmesa
->r128Screen
->driScreen
->fd
;
68 dma
.context
= rmesa
->hHWContext
;
71 dma
.send_sizes
= NULL
;
73 dma
.request_count
= 1;
74 dma
.request_size
= R128_BUFFER_SIZE
;
75 dma
.request_list
= &index
;
76 dma
.request_sizes
= &size
;
77 dma
.granted_count
= 0;
79 while ( !buf
&& ( to
++ < R128_TIMEOUT
) ) {
80 ret
= drmDMA( fd
, &dma
);
83 buf
= &rmesa
->r128Screen
->buffers
->list
[index
];
86 /* Bump the performance counter */
87 rmesa
->c_vertexBuffers
++;
94 drmCommandNone( fd
, DRM_R128_CCE_RESET
);
95 UNLOCK_HARDWARE( rmesa
);
96 fprintf( stderr
, "Error: Could not get new VB... exiting\n" );
103 void r128FlushVerticesLocked( r128ContextPtr rmesa
)
105 drm_clip_rect_t
*pbox
= rmesa
->pClipRects
;
106 int nbox
= rmesa
->numClipRects
;
107 drmBufPtr buffer
= rmesa
->vert_buf
;
108 int count
= rmesa
->num_verts
;
109 int prim
= rmesa
->hw_primitive
;
110 int fd
= rmesa
->driScreen
->fd
;
111 drm_r128_vertex_t vertex
;
114 rmesa
->num_verts
= 0;
115 rmesa
->vert_buf
= NULL
;
120 if ( rmesa
->dirty
& ~R128_UPLOAD_CLIPRECTS
)
121 r128EmitHwStateLocked( rmesa
);
126 if ( nbox
>= R128_NR_SAREA_CLIPRECTS
)
127 rmesa
->dirty
|= R128_UPLOAD_CLIPRECTS
;
129 if ( !count
|| !(rmesa
->dirty
& R128_UPLOAD_CLIPRECTS
) )
132 rmesa
->sarea
->nbox
= 0;
134 rmesa
->sarea
->nbox
= nbox
;
138 vertex
.idx
= buffer
->idx
;
139 vertex
.count
= count
;
141 drmCommandWrite( fd
, DRM_R128_VERTEX
, &vertex
, sizeof(vertex
) );
145 for ( i
= 0 ; i
< nbox
; ) {
146 int nr
= MIN2( i
+ R128_NR_SAREA_CLIPRECTS
, nbox
);
147 drm_clip_rect_t
*b
= rmesa
->sarea
->boxes
;
150 rmesa
->sarea
->nbox
= nr
- i
;
151 for ( ; i
< nr
; i
++ ) {
155 /* Finished with the buffer?
161 rmesa
->sarea
->dirty
|= R128_UPLOAD_CLIPRECTS
;
164 vertex
.idx
= buffer
->idx
;
165 vertex
.count
= count
;
166 vertex
.discard
= discard
;
167 drmCommandWrite( fd
, DRM_R128_VERTEX
, &vertex
, sizeof(vertex
) );
171 rmesa
->dirty
&= ~R128_UPLOAD_CLIPRECTS
;
178 /* ================================================================
182 void r128FireBlitLocked( r128ContextPtr rmesa
, drmBufPtr buffer
,
183 GLint offset
, GLint pitch
, GLint format
,
184 GLint x
, GLint y
, GLint width
, GLint height
)
186 drm_r128_blit_t blit
;
189 blit
.idx
= buffer
->idx
;
190 blit
.offset
= offset
;
192 blit
.format
= format
;
196 blit
.height
= height
;
198 ret
= drmCommandWrite( rmesa
->driFd
, DRM_R128_BLIT
,
199 &blit
, sizeof(blit
) );
202 UNLOCK_HARDWARE( rmesa
);
203 fprintf( stderr
, "DRM_R128_BLIT: return = %d\n", ret
);
209 /* ================================================================
210 * SwapBuffers with client-side throttling
213 static void delay( void ) {
214 /* Prevent an optimizing compiler from removing a spin loop */
217 #define R128_MAX_OUTSTANDING 2
220 /* Throttle the frame rate -- only allow one pending swap buffers
222 * GH: We probably don't want a timeout here, as we can wait as
223 * long as we want for a frame to complete. If it never does, then
224 * the card has locked.
226 static int r128WaitForFrameCompletion( r128ContextPtr rmesa
)
228 unsigned char *R128MMIO
= rmesa
->r128Screen
->mmio
.map
;
233 uint32_t frame
= read_MMIO_LE32( R128MMIO
, R128_LAST_FRAME_REG
);
235 if ( rmesa
->sarea
->last_frame
- frame
<= R128_MAX_OUTSTANDING
) {
239 /* Spin in place a bit so we aren't hammering the register */
241 for ( i
= 0 ; i
< 1024 ; i
++ ) {
249 /* Copy the back color buffer to the front color buffer.
251 void r128CopyBuffer( __DRIdrawablePrivate
*dPriv
)
253 r128ContextPtr rmesa
;
255 GLboolean missed_target
;
258 assert(dPriv
->driContextPriv
);
259 assert(dPriv
->driContextPriv
->driverPrivate
);
261 rmesa
= (r128ContextPtr
) dPriv
->driContextPriv
->driverPrivate
;
263 if ( R128_DEBUG
& DEBUG_VERBOSE_API
) {
264 fprintf( stderr
, "\n********************************\n" );
265 fprintf( stderr
, "\n%s( %p )\n\n",
266 __FUNCTION__
, (void *)rmesa
->glCtx
);
270 FLUSH_BATCH( rmesa
);
272 LOCK_HARDWARE( rmesa
);
274 /* Throttle the frame rate -- only allow one pending swap buffers
277 if ( !r128WaitForFrameCompletion( rmesa
) ) {
278 rmesa
->hardwareWentIdle
= 1;
280 rmesa
->hardwareWentIdle
= 0;
283 UNLOCK_HARDWARE( rmesa
);
284 driWaitForVBlank( dPriv
, &missed_target
);
285 LOCK_HARDWARE( rmesa
);
287 nbox
= dPriv
->numClipRects
; /* must be in locked region */
289 for ( i
= 0 ; i
< nbox
; ) {
290 GLint nr
= MIN2( i
+ R128_NR_SAREA_CLIPRECTS
, nbox
);
291 drm_clip_rect_t
*box
= dPriv
->pClipRects
;
292 drm_clip_rect_t
*b
= rmesa
->sarea
->boxes
;
295 for ( ; i
< nr
; i
++ ) {
299 rmesa
->sarea
->nbox
= n
;
301 ret
= drmCommandNone( rmesa
->driFd
, DRM_R128_SWAP
);
304 UNLOCK_HARDWARE( rmesa
);
305 fprintf( stderr
, "DRM_R128_SWAP: return = %d\n", ret
);
310 if ( R128_DEBUG
& DEBUG_ALWAYS_SYNC
) {
313 ret
= drmCommandNone(rmesa
->driFd
, DRM_R128_CCE_IDLE
);
314 } while ( ret
&& errno
== EBUSY
&& i
++ < R128_IDLE_RETRY
);
317 UNLOCK_HARDWARE( rmesa
);
319 rmesa
->new_state
|= R128_NEW_CONTEXT
;
320 rmesa
->dirty
|= (R128_UPLOAD_CONTEXT
|
322 R128_UPLOAD_CLIPRECTS
);
324 #if ENABLE_PERF_BOXES
325 /* Log the performance counters if necessary */
326 r128PerformanceCounters( rmesa
);
330 void r128PageFlip( __DRIdrawablePrivate
*dPriv
)
332 r128ContextPtr rmesa
;
334 GLboolean missed_target
;
337 assert(dPriv
->driContextPriv
);
338 assert(dPriv
->driContextPriv
->driverPrivate
);
340 rmesa
= (r128ContextPtr
) dPriv
->driContextPriv
->driverPrivate
;
342 if ( R128_DEBUG
& DEBUG_VERBOSE_API
) {
343 fprintf( stderr
, "\n%s( %p ): page=%d\n\n",
344 __FUNCTION__
, (void *)rmesa
->glCtx
, rmesa
->sarea
->pfCurrentPage
);
347 FLUSH_BATCH( rmesa
);
349 LOCK_HARDWARE( rmesa
);
351 /* Throttle the frame rate -- only allow one pending swap buffers
354 if ( !r128WaitForFrameCompletion( rmesa
) ) {
355 rmesa
->hardwareWentIdle
= 1;
357 rmesa
->hardwareWentIdle
= 0;
360 UNLOCK_HARDWARE( rmesa
);
361 driWaitForVBlank( dPriv
, &missed_target
);
362 LOCK_HARDWARE( rmesa
);
364 /* The kernel will have been initialized to perform page flipping
365 * on a swapbuffers ioctl.
367 ret
= drmCommandNone( rmesa
->driFd
, DRM_R128_FLIP
);
369 UNLOCK_HARDWARE( rmesa
);
372 fprintf( stderr
, "DRM_R128_FLIP: return = %d\n", ret
);
376 /* Get ready for drawing next frame. Update the renderbuffers'
377 * flippedOffset/Pitch fields so we draw into the right place.
379 driFlipRenderbuffers(rmesa
->glCtx
->WinSysDrawBuffer
,
380 rmesa
->sarea
->pfCurrentPage
);
382 rmesa
->new_state
|= R128_NEW_WINDOW
;
384 /* FIXME: Do we need this anymore? */
385 rmesa
->new_state
|= R128_NEW_CONTEXT
;
386 rmesa
->dirty
|= (R128_UPLOAD_CONTEXT
|
388 R128_UPLOAD_CLIPRECTS
);
390 #if ENABLE_PERF_BOXES
391 /* Log the performance counters if necessary */
392 r128PerformanceCounters( rmesa
);
397 /* ================================================================
401 static void r128Clear( GLcontext
*ctx
, GLbitfield mask
)
403 r128ContextPtr rmesa
= R128_CONTEXT(ctx
);
404 __DRIdrawablePrivate
*dPriv
= rmesa
->driDrawable
;
405 drm_r128_clear_t clear
;
409 GLuint depthmask
= 0;
410 GLint cx
, cy
, cw
, ch
;
412 if ( R128_DEBUG
& DEBUG_VERBOSE_API
) {
413 fprintf( stderr
, "%s:\n", __FUNCTION__
);
416 FLUSH_BATCH( rmesa
);
418 /* The only state change we care about here is the RGBA colormask
419 * We'll just update that state, if needed. If we do more then
420 * there's some strange side-effects that the conformance tests find.
422 if ( rmesa
->new_state
& R128_NEW_MASKS
) {
423 const GLuint save_state
= rmesa
->new_state
;
424 rmesa
->new_state
= R128_NEW_MASKS
;
425 r128DDUpdateHWState( ctx
);
426 rmesa
->new_state
= save_state
& ~R128_NEW_MASKS
;
429 if ( mask
& BUFFER_BIT_FRONT_LEFT
) {
431 mask
&= ~BUFFER_BIT_FRONT_LEFT
;
434 if ( mask
& BUFFER_BIT_BACK_LEFT
) {
436 mask
&= ~BUFFER_BIT_BACK_LEFT
;
439 if ( ( mask
& BUFFER_BIT_DEPTH
) && ctx
->Depth
.Mask
) {
441 /* if we're at 16 bits, extra plane mask won't hurt */
442 depthmask
|= 0x00ffffff;
443 mask
&= ~BUFFER_BIT_DEPTH
;
446 if ( mask
& BUFFER_BIT_STENCIL
&&
447 (ctx
->Visual
.stencilBits
> 0 && ctx
->Visual
.depthBits
== 24) ) {
449 depthmask
|= ctx
->Stencil
.WriteMask
[0] << 24;
450 mask
&= ~BUFFER_BIT_STENCIL
;
455 LOCK_HARDWARE( rmesa
);
457 /* compute region after locking: */
458 cx
= ctx
->DrawBuffer
->_Xmin
;
459 cy
= ctx
->DrawBuffer
->_Ymin
;
460 cw
= ctx
->DrawBuffer
->_Xmax
- cx
;
461 ch
= ctx
->DrawBuffer
->_Ymax
- cy
;
463 /* Flip top to bottom */
465 cy
= dPriv
->y
+ dPriv
->h
- cy
- ch
;
467 /* FIXME: Do we actually need this?
469 if ( rmesa
->dirty
& ~R128_UPLOAD_CLIPRECTS
) {
470 r128EmitHwStateLocked( rmesa
);
473 for ( i
= 0 ; i
< rmesa
->numClipRects
; ) {
474 GLint nr
= MIN2( i
+ R128_NR_SAREA_CLIPRECTS
, rmesa
->numClipRects
);
475 drm_clip_rect_t
*box
= rmesa
->pClipRects
;
476 drm_clip_rect_t
*b
= rmesa
->sarea
->boxes
;
479 if (cw
!= dPriv
->w
|| ch
!= dPriv
->h
) {
480 /* clear subregion */
481 for ( ; i
< nr
; i
++ ) {
484 GLint w
= box
[i
].x2
- x
;
485 GLint h
= box
[i
].y2
- y
;
487 if ( x
< cx
) w
-= cx
- x
, x
= cx
;
488 if ( y
< cy
) h
-= cy
- y
, y
= cy
;
489 if ( x
+ w
> cx
+ cw
) w
= cx
+ cw
- x
;
490 if ( y
+ h
> cy
+ ch
) h
= cy
+ ch
- y
;
491 if ( w
<= 0 ) continue;
492 if ( h
<= 0 ) continue;
502 /* clear whole window */
503 for ( ; i
< nr
; i
++ ) {
509 rmesa
->sarea
->nbox
= n
;
511 if ( R128_DEBUG
& DEBUG_VERBOSE_IOCTL
) {
513 "DRM_R128_CLEAR: flag 0x%x color %x depth %x nbox %d\n",
515 (GLuint
)rmesa
->ClearColor
,
516 (GLuint
)rmesa
->ClearDepth
,
517 rmesa
->sarea
->nbox
);
521 clear
.clear_color
= rmesa
->ClearColor
;
522 clear
.clear_depth
= rmesa
->ClearDepth
;
523 clear
.color_mask
= rmesa
->setup
.plane_3d_mask_c
;
524 clear
.depth_mask
= depthmask
;
526 ret
= drmCommandWrite( rmesa
->driFd
, DRM_R128_CLEAR
,
527 &clear
, sizeof(clear
) );
530 UNLOCK_HARDWARE( rmesa
);
531 fprintf( stderr
, "DRM_R128_CLEAR: return = %d\n", ret
);
536 UNLOCK_HARDWARE( rmesa
);
538 rmesa
->dirty
|= R128_UPLOAD_CLIPRECTS
;
542 _swrast_Clear( ctx
, mask
);
546 /* ================================================================
547 * Depth spans, pixels
550 void r128WriteDepthSpanLocked( r128ContextPtr rmesa
,
551 GLuint n
, GLint x
, GLint y
,
552 const GLuint depth
[],
553 const GLubyte mask
[] )
555 drm_clip_rect_t
*pbox
= rmesa
->pClipRects
;
557 int nbox
= rmesa
->numClipRects
;
558 int fd
= rmesa
->driScreen
->fd
;
564 if ( nbox
>= R128_NR_SAREA_CLIPRECTS
) {
565 rmesa
->dirty
|= R128_UPLOAD_CLIPRECTS
;
568 if ( !(rmesa
->dirty
& R128_UPLOAD_CLIPRECTS
) )
571 rmesa
->sarea
->nbox
= 0;
573 rmesa
->sarea
->nbox
= nbox
;
576 d
.func
= R128_WRITE_SPAN
;
580 d
.buffer
= (unsigned int *)depth
;
581 d
.mask
= (unsigned char *)mask
;
583 drmCommandWrite( fd
, DRM_R128_DEPTH
, &d
, sizeof(d
));
588 for (i
= 0 ; i
< nbox
; ) {
589 int nr
= MIN2( i
+ R128_NR_SAREA_CLIPRECTS
, nbox
);
590 drm_clip_rect_t
*b
= rmesa
->sarea
->boxes
;
592 rmesa
->sarea
->nbox
= nr
- i
;
593 for ( ; i
< nr
; i
++) {
597 rmesa
->sarea
->dirty
|= R128_UPLOAD_CLIPRECTS
;
599 d
.func
= R128_WRITE_SPAN
;
603 d
.buffer
= (unsigned int *)depth
;
604 d
.mask
= (unsigned char *)mask
;
606 drmCommandWrite( fd
, DRM_R128_DEPTH
, &d
, sizeof(d
));
610 rmesa
->dirty
&= ~R128_UPLOAD_CLIPRECTS
;
613 void r128WriteDepthPixelsLocked( r128ContextPtr rmesa
, GLuint n
,
614 const GLint x
[], const GLint y
[],
615 const GLuint depth
[],
616 const GLubyte mask
[] )
618 drm_clip_rect_t
*pbox
= rmesa
->pClipRects
;
620 int nbox
= rmesa
->numClipRects
;
621 int fd
= rmesa
->driScreen
->fd
;
627 if ( nbox
>= R128_NR_SAREA_CLIPRECTS
) {
628 rmesa
->dirty
|= R128_UPLOAD_CLIPRECTS
;
631 if ( !(rmesa
->dirty
& R128_UPLOAD_CLIPRECTS
) )
634 rmesa
->sarea
->nbox
= 0;
636 rmesa
->sarea
->nbox
= nbox
;
639 d
.func
= R128_WRITE_PIXELS
;
643 d
.buffer
= (unsigned int *)depth
;
644 d
.mask
= (unsigned char *)mask
;
646 drmCommandWrite( fd
, DRM_R128_DEPTH
, &d
, sizeof(d
));
650 for (i
= 0 ; i
< nbox
; ) {
651 int nr
= MIN2( i
+ R128_NR_SAREA_CLIPRECTS
, nbox
);
652 drm_clip_rect_t
*b
= rmesa
->sarea
->boxes
;
654 rmesa
->sarea
->nbox
= nr
- i
;
655 for ( ; i
< nr
; i
++) {
659 rmesa
->sarea
->dirty
|= R128_UPLOAD_CLIPRECTS
;
661 d
.func
= R128_WRITE_PIXELS
;
665 d
.buffer
= (unsigned int *)depth
;
666 d
.mask
= (unsigned char *)mask
;
668 drmCommandWrite( fd
, DRM_R128_DEPTH
, &d
, sizeof(d
));
672 rmesa
->dirty
&= ~R128_UPLOAD_CLIPRECTS
;
675 void r128ReadDepthSpanLocked( r128ContextPtr rmesa
,
676 GLuint n
, GLint x
, GLint y
)
678 drm_clip_rect_t
*pbox
= rmesa
->pClipRects
;
680 int nbox
= rmesa
->numClipRects
;
681 int fd
= rmesa
->driScreen
->fd
;
687 if ( nbox
>= R128_NR_SAREA_CLIPRECTS
) {
688 rmesa
->dirty
|= R128_UPLOAD_CLIPRECTS
;
691 if ( !(rmesa
->dirty
& R128_UPLOAD_CLIPRECTS
) )
694 rmesa
->sarea
->nbox
= 0;
696 rmesa
->sarea
->nbox
= nbox
;
699 d
.func
= R128_READ_SPAN
;
706 drmCommandWrite( fd
, DRM_R128_DEPTH
, &d
, sizeof(d
));
710 for (i
= 0 ; i
< nbox
; ) {
711 int nr
= MIN2( i
+ R128_NR_SAREA_CLIPRECTS
, nbox
);
712 drm_clip_rect_t
*b
= rmesa
->sarea
->boxes
;
714 rmesa
->sarea
->nbox
= nr
- i
;
715 for ( ; i
< nr
; i
++) {
719 rmesa
->sarea
->dirty
|= R128_UPLOAD_CLIPRECTS
;
721 d
.func
= R128_READ_SPAN
;
728 drmCommandWrite( fd
, DRM_R128_DEPTH
, &d
, sizeof(d
));
732 rmesa
->dirty
&= ~R128_UPLOAD_CLIPRECTS
;
735 void r128ReadDepthPixelsLocked( r128ContextPtr rmesa
, GLuint n
,
736 const GLint x
[], const GLint y
[] )
738 drm_clip_rect_t
*pbox
= rmesa
->pClipRects
;
740 int nbox
= rmesa
->numClipRects
;
741 int fd
= rmesa
->driScreen
->fd
;
747 if ( nbox
>= R128_NR_SAREA_CLIPRECTS
) {
748 rmesa
->dirty
|= R128_UPLOAD_CLIPRECTS
;
751 if ( !(rmesa
->dirty
& R128_UPLOAD_CLIPRECTS
) )
754 rmesa
->sarea
->nbox
= 0;
756 rmesa
->sarea
->nbox
= nbox
;
759 d
.func
= R128_READ_PIXELS
;
766 drmCommandWrite( fd
, DRM_R128_DEPTH
, &d
, sizeof(d
));
770 for (i
= 0 ; i
< nbox
; ) {
771 int nr
= MIN2( i
+ R128_NR_SAREA_CLIPRECTS
, nbox
);
772 drm_clip_rect_t
*b
= rmesa
->sarea
->boxes
;
774 rmesa
->sarea
->nbox
= nr
- i
;
775 for ( ; i
< nr
; i
++) {
779 rmesa
->sarea
->dirty
|= R128_UPLOAD_CLIPRECTS
;
781 d
.func
= R128_READ_PIXELS
;
788 drmCommandWrite( fd
, DRM_R128_DEPTH
, &d
, sizeof(d
));
792 rmesa
->dirty
&= ~R128_UPLOAD_CLIPRECTS
;
796 void r128WaitForIdleLocked( r128ContextPtr rmesa
)
798 int fd
= rmesa
->r128Screen
->driScreen
->fd
;
805 ret
= drmCommandNone( fd
, DRM_R128_CCE_IDLE
);
806 } while ( ret
&& errno
== EBUSY
&& i
++ < R128_IDLE_RETRY
);
807 } while ( ( ret
== -EBUSY
) && ( to
++ < R128_TIMEOUT
) );
810 drmCommandNone( fd
, DRM_R128_CCE_RESET
);
811 UNLOCK_HARDWARE( rmesa
);
812 fprintf( stderr
, "Error: Rage 128 timed out... exiting\n" );
817 void r128InitIoctlFuncs( struct dd_function_table
*functions
)
819 functions
->Clear
= r128Clear
;