2 * Copyright 2000-2001 VA Linux Systems, Inc.
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * on the rights to use, copy, modify, merge, publish, distribute, sub
9 * license, and/or sell copies of the Software, and to permit persons to whom
10 * the Software is furnished to do so, subject to the following conditions:
12 * The above copyright notice and this permission notice (including the next
13 * paragraph) shall be included in all copies or substantial portions of the
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
19 * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22 * OTHER DEALINGS IN THE SOFTWARE.
25 * Keith Whitwell <keith@tungstengraphics.com>
26 * Gareth Hughes <gareth@valinux.com>
28 /* $XFree86: xc/lib/GL/mesa/src/drv/mga/mgaioctl.c,v 1.16 2002/12/16 16:18:52 dawes Exp $ */
34 #include "swrast/swrast.h"
37 #include "mgacontext.h"
44 #include "mga_common.h"
49 static void mga_iload_dma_ioctl(mgaContextPtr mmesa
,
53 drmBufPtr buf
= mmesa
->iload_buffer
;
57 if (MGA_DEBUG
&DEBUG_VERBOSE_IOCTL
)
58 fprintf(stderr
, "DRM_IOCTL_MGA_ILOAD idx %d dst %x length %d\n",
59 buf
->idx
, (int) dest
, length
);
61 if ( (length
& MGA_ILOAD_MASK
) != 0 ) {
62 UNLOCK_HARDWARE( mmesa
);
63 fprintf( stderr
, "%s: Invalid ILOAD datasize (%d), must be "
64 "multiple of %u.\n", __FUNCTION__
, length
, MGA_ILOAD_ALIGN
);
70 iload
.length
= length
;
74 ret
= drmCommandWrite( mmesa
->driFd
, DRM_MGA_ILOAD
,
75 &iload
, sizeof(drmMGAIload
) );
76 } while ( ret
== -EBUSY
&& i
++ < DRM_MGA_IDLE_RETRY
);
79 printf("send iload retcode = %d\n", ret
);
83 mmesa
->iload_buffer
= 0;
85 if (MGA_DEBUG
&DEBUG_VERBOSE_IOCTL
)
86 fprintf(stderr
, "finished iload dma put\n");
90 drmBufPtr
mga_get_buffer_ioctl( mgaContextPtr mmesa
)
98 if (MGA_DEBUG
&DEBUG_VERBOSE_IOCTL
)
99 fprintf(stderr
, "Getting dma buffer\n");
101 dma
.context
= mmesa
->hHWContext
;
103 dma
.send_list
= NULL
;
104 dma
.send_sizes
= NULL
;
106 dma
.request_count
= 1;
107 dma
.request_size
= MGA_BUFFER_SIZE
;
108 dma
.request_list
= &idx
;
109 dma
.request_sizes
= &size
;
110 dma
.granted_count
= 0;
113 if (MGA_DEBUG
&DEBUG_VERBOSE_IOCTL
)
114 fprintf(stderr
, "drmDMA (get) ctx %d count %d size 0x%x\n",
115 dma
.context
, dma
.request_count
,
119 retcode
= drmDMA(mmesa
->driFd
, &dma
);
121 if (MGA_DEBUG
&DEBUG_VERBOSE_IOCTL
)
122 fprintf(stderr
, "retcode %d sz %d idx %d count %d\n",
124 dma
.request_sizes
[0],
129 dma
.request_sizes
[0] &&
133 if (MGA_DEBUG
&DEBUG_VERBOSE_IOCTL
)
134 fprintf(stderr
, "\n\nflush");
136 UPDATE_LOCK( mmesa
, DRM_LOCK_FLUSH
| DRM_LOCK_QUIESCENT
);
139 buf
= &(mmesa
->mgaScreen
->bufs
->list
[idx
]);
142 if (MGA_DEBUG
&DEBUG_VERBOSE_IOCTL
)
144 "drmDMA (get) returns size[0] 0x%x idx[0] %d\n"
145 "dma_buffer now: buf idx: %d size: %d used: %d addr %p\n",
146 dma
.request_sizes
[0], dma
.request_list
[0],
147 buf
->idx
, buf
->total
,
148 buf
->used
, buf
->address
);
150 if (MGA_DEBUG
&DEBUG_VERBOSE_IOCTL
)
151 fprintf(stderr
, "finished getbuffer\n");
160 mgaClear( GLcontext
*ctx
, GLbitfield mask
, GLboolean all
,
161 GLint cx
, GLint cy
, GLint cw
, GLint ch
)
163 mgaContextPtr mmesa
= MGA_CONTEXT(ctx
);
164 __DRIdrawablePrivate
*dPriv
= mmesa
->driDrawable
;
166 GLuint clear_color
= mmesa
->ClearColor
;
167 GLuint clear_depth
= 0;
168 GLuint color_mask
= 0;
169 GLuint depth_mask
= 0;
173 drmMGAClearRec clear
;
175 FLUSH_BATCH( mmesa
);
177 if ( mask
& DD_FRONT_LEFT_BIT
) {
179 color_mask
= mmesa
->setup
.plnwt
;
180 mask
&= ~DD_FRONT_LEFT_BIT
;
183 if ( mask
& DD_BACK_LEFT_BIT
) {
185 color_mask
= mmesa
->setup
.plnwt
;
186 mask
&= ~DD_BACK_LEFT_BIT
;
189 if ( (mask
& DD_DEPTH_BIT
) && ctx
->Depth
.Mask
) {
191 clear_depth
= (mmesa
->ClearDepth
& mmesa
->depth_clear_mask
);
192 depth_mask
|= mmesa
->depth_clear_mask
;
193 mask
&= ~DD_DEPTH_BIT
;
196 if ( (mask
& DD_STENCIL_BIT
) && mmesa
->hw_stencil
) {
198 clear_depth
|= (ctx
->Stencil
.Clear
& mmesa
->stencil_clear_mask
);
199 depth_mask
|= mmesa
->stencil_clear_mask
;
200 mask
&= ~DD_STENCIL_BIT
;
204 LOCK_HARDWARE( mmesa
);
206 if ( mmesa
->dirty_cliprects
)
207 mgaUpdateRects( mmesa
, (MGA_FRONT
| MGA_BACK
) );
209 /* flip top to bottom */
214 if ( MGA_DEBUG
& DEBUG_VERBOSE_IOCTL
)
215 fprintf( stderr
, "Clear, bufs %x nbox %d\n",
216 (int)flags
, (int)mmesa
->numClipRects
);
218 for (i
= 0 ; i
< mmesa
->numClipRects
; )
220 int nr
= MIN2(i
+ MGA_NR_SAREA_CLIPRECTS
, mmesa
->numClipRects
);
221 XF86DRIClipRectPtr box
= mmesa
->pClipRects
;
222 XF86DRIClipRectPtr b
= mmesa
->sarea
->boxes
;
226 for ( ; i
< nr
; i
++) {
229 GLint w
= box
[i
].x2
- x
;
230 GLint h
= box
[i
].y2
- y
;
232 if (x
< cx
) w
-= cx
- x
, x
= cx
;
233 if (y
< cy
) h
-= cy
- y
, y
= cy
;
234 if (x
+ w
> cx
+ cw
) w
= cx
+ cw
- x
;
235 if (y
+ h
> cy
+ ch
) h
= cy
+ ch
- y
;
236 if (w
<= 0) continue;
237 if (h
<= 0) continue;
247 for ( ; i
< nr
; i
++) {
248 *b
++ = *(XF86DRIClipRectPtr
)&box
[i
];
254 if ( MGA_DEBUG
& DEBUG_VERBOSE_IOCTL
)
256 "DRM_IOCTL_MGA_CLEAR flag 0x%x color %x depth %x nbox %d\n",
257 flags
, clear_color
, clear_depth
, mmesa
->sarea
->nbox
);
259 mmesa
->sarea
->nbox
= n
;
262 clear
.clear_color
= clear_color
;
263 clear
.clear_depth
= clear_depth
;
264 clear
.color_mask
= color_mask
;
265 clear
.depth_mask
= depth_mask
;
266 ret
= drmCommandWrite( mmesa
->driFd
, DRM_MGA_CLEAR
,
267 &clear
, sizeof(drmMGAClearRec
));
269 fprintf( stderr
, "send clear retcode = %d\n", ret
);
272 if ( MGA_DEBUG
& DEBUG_VERBOSE_IOCTL
)
273 fprintf( stderr
, "finished clear %d\n", ++nrclears
);
276 UNLOCK_HARDWARE( mmesa
);
277 mmesa
->dirty
|= MGA_UPLOAD_CLIPRECTS
|MGA_UPLOAD_CONTEXT
;
281 _swrast_Clear( ctx
, mask
, all
, cx
, cy
, cw
, ch
);
285 static void mgaWaitForFrameCompletion( mgaContextPtr mmesa
)
288 GLuint last_frame
, last_wrap
;
291 last_frame
= mmesa
->sarea
->last_frame
.head
;
292 last_wrap
= mmesa
->sarea
->last_frame
.wrap
;
294 /* FIXME: Add a timeout to this loop...
297 if ( last_wrap
< mmesa
->sarea
->last_wrap
||
298 ( last_wrap
== mmesa
->sarea
->last_wrap
&&
299 last_frame
<= (MGA_READ( MGAREG_PRIMADDRESS
) -
300 mmesa
->primary_offset
) ) ) {
305 fprintf( stderr
, " last: head=0x%06x wrap=%d\n",
306 last_frame
, last_wrap
);
307 fprintf( stderr
, " head: head=0x%06lx wrap=%d\n",
308 (long)(MGA_READ( MGAREG_PRIMADDRESS
) - mmesa
->primary_offset
),
309 mmesa
->sarea
->last_wrap
);
311 UPDATE_LOCK( mmesa
, DRM_LOCK_FLUSH
);
313 UNLOCK_HARDWARE( mmesa
);
315 LOCK_HARDWARE( mmesa
);
318 fprintf( stderr
, "\n" );
323 * Copy the back buffer to the front buffer.
325 void mgaCopyBuffer( const __DRIdrawablePrivate
*dPriv
)
328 XF86DRIClipRectPtr pbox
;
332 GLboolean missed_target
;
336 assert(dPriv
->driContextPriv
);
337 assert(dPriv
->driContextPriv
->driverPrivate
);
339 mmesa
= (mgaContextPtr
) dPriv
->driContextPriv
->driverPrivate
;
341 FLUSH_BATCH( mmesa
);
343 LOCK_HARDWARE( mmesa
);
344 mgaWaitForFrameCompletion( mmesa
);
345 UNLOCK_HARDWARE( mmesa
);
346 driWaitForVBlank( dPriv
, & mmesa
->vbl_seq
, mmesa
->vblank_flags
,
348 if ( missed_target
) {
349 mmesa
->swap_missed_count
++;
350 (void) (*mmesa
->get_ust
)( & mmesa
->swap_missed_ust
);
352 LOCK_HARDWARE( mmesa
);
354 /* Use the frontbuffer cliprects
356 if (mmesa
->dirty_cliprects
& MGA_FRONT
)
357 mgaUpdateRects( mmesa
, MGA_FRONT
);
360 pbox
= dPriv
->pClipRects
;
361 nbox
= dPriv
->numClipRects
;
363 for (i
= 0 ; i
< nbox
; )
365 int nr
= MIN2(i
+ MGA_NR_SAREA_CLIPRECTS
, dPriv
->numClipRects
);
366 XF86DRIClipRectPtr b
= mmesa
->sarea
->boxes
;
368 mmesa
->sarea
->nbox
= nr
- i
;
370 for ( ; i
< nr
; i
++)
374 fprintf(stderr
, "DRM_IOCTL_MGA_SWAP\n");
376 ret
= drmCommandNone( mmesa
->driFd
, DRM_MGA_SWAP
);
378 printf("send swap retcode = %d\n", ret
);
383 UNLOCK_HARDWARE( mmesa
);
385 mmesa
->dirty
|= MGA_UPLOAD_CLIPRECTS
;
387 (void) (*mmesa
->get_ust
)( & mmesa
->swap_ust
);
393 void mgaFinish( GLcontext
*ctx
)
395 mgaContextPtr mmesa
= MGA_CONTEXT(ctx
);
397 FLUSH_BATCH( mmesa
);
399 if (1/*mmesa->sarea->last_quiescent != mmesa->sarea->last_enqueue*/) {
400 if (MGA_DEBUG
&DEBUG_VERBOSE_IOCTL
)
401 fprintf(stderr
, "mgaRegetLockQuiescent\n");
403 LOCK_HARDWARE( mmesa
);
404 UPDATE_LOCK( mmesa
, DRM_LOCK_QUIESCENT
| DRM_LOCK_FLUSH
);
405 UNLOCK_HARDWARE( mmesa
);
407 mmesa
->sarea
->last_quiescent
= mmesa
->sarea
->last_enqueue
;
411 void mgaWaitAgeLocked( mgaContextPtr mmesa
, int age
)
413 if (GET_DISPATCH_AGE(mmesa
) < age
) {
414 UPDATE_LOCK( mmesa
, DRM_LOCK_FLUSH
);
419 void mgaWaitAge( mgaContextPtr mmesa
, int age
)
421 if (GET_DISPATCH_AGE(mmesa
) < age
) {
422 LOCK_HARDWARE(mmesa
);
423 if (GET_DISPATCH_AGE(mmesa
) < age
) {
424 UPDATE_LOCK( mmesa
, DRM_LOCK_FLUSH
);
426 UNLOCK_HARDWARE(mmesa
);
431 static GLboolean
intersect_rect( XF86DRIClipRectPtr out
,
432 const XF86DRIClipRectPtr a
,
433 const XF86DRIClipRectPtr b
)
436 if (b
->x1
> out
->x1
) out
->x1
= b
->x1
;
437 if (b
->y1
> out
->y1
) out
->y1
= b
->y1
;
438 if (b
->x2
< out
->x2
) out
->x2
= b
->x2
;
439 if (b
->y2
< out
->y2
) out
->y2
= b
->y2
;
441 return ((out
->x1
< out
->x2
) && (out
->y1
< out
->y2
));
447 static void age_mmesa( mgaContextPtr mmesa
, int age
)
449 if (mmesa
->CurrentTexObj
[0]) mmesa
->CurrentTexObj
[0]->age
= age
;
450 if (mmesa
->CurrentTexObj
[1]) mmesa
->CurrentTexObj
[1]->age
= age
;
454 static int __break_vertex
= 0;
457 void mgaFlushVerticesLocked( mgaContextPtr mmesa
)
459 XF86DRIClipRectPtr pbox
= mmesa
->pClipRects
;
460 int nbox
= mmesa
->numClipRects
;
461 drmBufPtr buffer
= mmesa
->vertex_dma_buffer
;
465 mmesa
->vertex_dma_buffer
= 0;
470 if (mmesa
->dirty_cliprects
& mmesa
->draw_buffer
)
471 mgaUpdateRects( mmesa
, mmesa
->draw_buffer
);
473 if (mmesa
->dirty
& ~MGA_UPLOAD_CLIPRECTS
)
474 mgaEmitHwStateLocked( mmesa
);
476 /* FIXME: Workaround bug in kernel module.
478 mmesa
->sarea
->dirty
|= MGA_UPLOAD_CONTEXT
;
483 if (nbox
>= MGA_NR_SAREA_CLIPRECTS
)
484 mmesa
->dirty
|= MGA_UPLOAD_CLIPRECTS
;
487 if (!buffer
->used
|| !(mmesa
->dirty
& MGA_UPLOAD_CLIPRECTS
))
490 mmesa
->sarea
->nbox
= 0;
492 mmesa
->sarea
->nbox
= nbox
;
494 if (MGA_DEBUG
&DEBUG_VERBOSE_IOCTL
)
495 fprintf(stderr
, "Firing vertex -- case a nbox %d\n", nbox
);
497 vertex
.idx
= buffer
->idx
;
498 vertex
.used
= buffer
->used
;
500 drmCommandWrite( mmesa
->driFd
, DRM_MGA_VERTEX
,
501 &vertex
, sizeof(drmMGAVertex
) );
503 age_mmesa(mmesa
, mmesa
->sarea
->last_enqueue
);
508 for (i
= 0 ; i
< nbox
; )
510 int nr
= MIN2(i
+ MGA_NR_SAREA_CLIPRECTS
, nbox
);
511 XF86DRIClipRectPtr b
= mmesa
->sarea
->boxes
;
514 if (mmesa
->scissor
) {
515 mmesa
->sarea
->nbox
= 0;
517 for ( ; i
< nr
; i
++) {
519 if (intersect_rect(b
, b
, &mmesa
->scissor_rect
)) {
520 mmesa
->sarea
->nbox
++;
527 if (!mmesa
->sarea
->nbox
) {
528 if (nr
< nbox
) continue;
532 mmesa
->sarea
->nbox
= nr
- i
;
533 for ( ; i
< nr
; i
++)
537 /* Finished with the buffer?
542 mmesa
->sarea
->dirty
|= MGA_UPLOAD_CLIPRECTS
;
544 vertex
.idx
= buffer
->idx
;
545 vertex
.used
= buffer
->used
;
546 vertex
.discard
= discard
;
547 drmCommandWrite( mmesa
->driFd
, DRM_MGA_VERTEX
,
548 &vertex
, sizeof(drmMGAVertex
) );
550 age_mmesa(mmesa
, mmesa
->sarea
->last_enqueue
);
554 /* Do we really need to do this ? */
556 if ( __break_vertex
) {
557 __asm__
__volatile__ ( "int $3" );
561 mmesa
->dirty
&= ~MGA_UPLOAD_CLIPRECTS
;
564 void mgaFlushVertices( mgaContextPtr mmesa
)
566 LOCK_HARDWARE( mmesa
);
567 mgaFlushVerticesLocked( mmesa
);
568 UNLOCK_HARDWARE( mmesa
);
572 void mgaFireILoadLocked( mgaContextPtr mmesa
,
573 GLuint offset
, GLuint length
)
575 if (!mmesa
->iload_buffer
) {
576 fprintf(stderr
, "mgaFireILoad: no buffer\n");
580 if (MGA_DEBUG
&DEBUG_VERBOSE_IOCTL
)
581 fprintf(stderr
, "mgaFireILoad idx %d ofs 0x%x length %d\n",
582 mmesa
->iload_buffer
->idx
, (int)offset
, (int)length
);
584 mga_iload_dma_ioctl( mmesa
, offset
, length
);
587 void mgaGetILoadBufferLocked( mgaContextPtr mmesa
)
589 if (MGA_DEBUG
&DEBUG_VERBOSE_IOCTL
)
590 fprintf(stderr
, "mgaGetIloadBuffer (buffer now %p)\n",
591 mmesa
->iload_buffer
);
593 mmesa
->iload_buffer
= mga_get_buffer_ioctl( mmesa
);
596 drmBufPtr
mgaGetBufferLocked( mgaContextPtr mmesa
)
598 return mga_get_buffer_ioctl( mmesa
);
603 void mgaFlush( GLcontext
*ctx
)
605 mgaContextPtr mmesa
= MGA_CONTEXT( ctx
);
608 FLUSH_BATCH( mmesa
);
610 /* This may be called redundantly - dispatch_age may trail what
611 * has actually been sent and processed by the hardware.
613 if (1 || GET_DISPATCH_AGE( mmesa
) < mmesa
->sarea
->last_enqueue
) {
614 LOCK_HARDWARE( mmesa
);
615 UPDATE_LOCK( mmesa
, DRM_LOCK_FLUSH
);
616 UNLOCK_HARDWARE( mmesa
);
623 void mgaReleaseBufLocked( mgaContextPtr mmesa
, drmBufPtr buffer
)
629 vertex
.idx
= buffer
->idx
;
632 drmCommandWrite( mmesa
->driFd
, DRM_MGA_VERTEX
,
633 &vertex
, sizeof(drmMGAVertex
) );
636 int mgaFlushDMA( int fd
, drmLockFlags flags
)
641 memset( &lock
, 0, sizeof(drmMGALock
) );
643 if ( flags
& DRM_LOCK_QUIESCENT
) lock
.flags
|= DRM_LOCK_QUIESCENT
;
644 if ( flags
& DRM_LOCK_FLUSH
) lock
.flags
|= DRM_LOCK_FLUSH
;
645 if ( flags
& DRM_LOCK_FLUSH_ALL
) lock
.flags
|= DRM_LOCK_FLUSH_ALL
;
648 ret
= drmCommandWrite( fd
, DRM_MGA_FLUSH
, &lock
, sizeof(drmMGALock
) );
649 } while ( ret
&& errno
== EBUSY
&& i
++ < DRM_MGA_IDLE_RETRY
);
653 if ( errno
!= EBUSY
)
656 if ( lock
.flags
& DRM_LOCK_QUIESCENT
) {
657 /* Only keep trying if we need quiescence.
659 lock
.flags
&= ~(DRM_LOCK_FLUSH
| DRM_LOCK_FLUSH_ALL
);
662 ret
= drmCommandWrite( fd
, DRM_MGA_FLUSH
, &lock
, sizeof(drmMGALock
) );
663 } while ( ret
&& errno
== EBUSY
&& i
++ < DRM_MGA_IDLE_RETRY
);
673 void mgaInitIoctlFuncs( struct dd_function_table
*functions
)
675 functions
->Clear
= mgaClear
;
676 functions
->Flush
= mgaFlush
;
677 functions
->Finish
= mgaFinish
;