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.
27 * MGA IOCTL related wrapper functions.
29 * \author Keith Whitwell <keith@tungstengraphics.com>
30 * \author Gareth Hughes <gareth@valinux.com>
37 #include "swrast/swrast.h"
42 #include "mgacontext.h"
54 mgaSetFence( mgaContextPtr mmesa
, uint32_t * fence
)
58 if ( mmesa
->driScreen
->drmMinor
>= 2 ) {
59 ret
= drmCommandWriteRead( mmesa
->driScreen
->fd
, DRM_MGA_SET_FENCE
,
60 fence
, sizeof( uint32_t ));
62 fprintf(stderr
, "drmMgaSetFence: %d\n", ret
);
72 mgaWaitFence( mgaContextPtr mmesa
, uint32_t fence
, uint32_t * curr_fence
)
76 if ( mmesa
->driScreen
->drmMinor
>= 2 ) {
77 uint32_t temp
= fence
;
79 ret
= drmCommandWriteRead( mmesa
->driScreen
->fd
,
81 & temp
, sizeof( uint32_t ));
83 fprintf(stderr
, "drmMgaSetFence: %d\n", ret
);
96 static void mga_iload_dma_ioctl(mgaContextPtr mmesa
,
100 drmBufPtr buf
= mmesa
->iload_buffer
;
101 drm_mga_iload_t iload
;
104 if (MGA_DEBUG
&DEBUG_VERBOSE_IOCTL
)
105 fprintf(stderr
, "DRM_IOCTL_MGA_ILOAD idx %d dst %x length %d\n",
106 buf
->idx
, (int) dest
, length
);
108 if ( (length
& MGA_ILOAD_MASK
) != 0 ) {
109 UNLOCK_HARDWARE( mmesa
);
110 fprintf( stderr
, "%s: Invalid ILOAD datasize (%d), must be "
111 "multiple of %u.\n", __FUNCTION__
, length
, MGA_ILOAD_ALIGN
);
115 iload
.idx
= buf
->idx
;
117 iload
.length
= length
;
121 ret
= drmCommandWrite( mmesa
->driFd
, DRM_MGA_ILOAD
,
122 &iload
, sizeof(iload
) );
123 } while ( ret
== -EBUSY
&& i
++ < DRM_MGA_IDLE_RETRY
);
126 printf("send iload retcode = %d\n", ret
);
130 mmesa
->iload_buffer
= 0;
132 if (MGA_DEBUG
&DEBUG_VERBOSE_IOCTL
)
133 fprintf(stderr
, "finished iload dma put\n");
137 drmBufPtr
mga_get_buffer_ioctl( mgaContextPtr mmesa
)
145 if (MGA_DEBUG
&DEBUG_VERBOSE_IOCTL
)
146 fprintf(stderr
, "Getting dma buffer\n");
148 dma
.context
= mmesa
->hHWContext
;
150 dma
.send_list
= NULL
;
151 dma
.send_sizes
= NULL
;
153 dma
.request_count
= 1;
154 dma
.request_size
= MGA_BUFFER_SIZE
;
155 dma
.request_list
= &idx
;
156 dma
.request_sizes
= &size
;
157 dma
.granted_count
= 0;
160 if (MGA_DEBUG
&DEBUG_VERBOSE_IOCTL
)
161 fprintf(stderr
, "drmDMA (get) ctx %d count %d size 0x%x\n",
162 dma
.context
, dma
.request_count
,
166 retcode
= drmDMA(mmesa
->driFd
, &dma
);
168 if (MGA_DEBUG
&DEBUG_VERBOSE_IOCTL
)
169 fprintf(stderr
, "retcode %d sz %d idx %d count %d\n",
171 dma
.request_sizes
[0],
176 dma
.request_sizes
[0] &&
180 if (MGA_DEBUG
&DEBUG_VERBOSE_IOCTL
)
181 fprintf(stderr
, "\n\nflush");
183 UPDATE_LOCK( mmesa
, DRM_LOCK_FLUSH
| DRM_LOCK_QUIESCENT
);
186 buf
= &(mmesa
->mgaScreen
->bufs
->list
[idx
]);
189 if (MGA_DEBUG
&DEBUG_VERBOSE_IOCTL
)
191 "drmDMA (get) returns size[0] 0x%x idx[0] %d\n"
192 "dma_buffer now: buf idx: %d size: %d used: %d addr %p\n",
193 dma
.request_sizes
[0], dma
.request_list
[0],
194 buf
->idx
, buf
->total
,
195 buf
->used
, buf
->address
);
197 if (MGA_DEBUG
&DEBUG_VERBOSE_IOCTL
)
198 fprintf(stderr
, "finished getbuffer\n");
207 mgaClear( GLcontext
*ctx
, GLbitfield mask
, GLboolean all
,
208 GLint cx
, GLint cy
, GLint cw
, GLint ch
)
210 mgaContextPtr mmesa
= MGA_CONTEXT(ctx
);
211 __DRIdrawablePrivate
*dPriv
= mmesa
->driDrawable
;
213 GLuint clear_color
= mmesa
->ClearColor
;
214 GLuint clear_depth
= 0;
215 GLuint color_mask
= 0;
216 GLuint depth_mask
= 0;
220 drm_mga_clear_t clear
;
222 FLUSH_BATCH( mmesa
);
224 if ( mask
& BUFFER_BIT_FRONT_LEFT
) {
226 color_mask
= mmesa
->setup
.plnwt
;
227 mask
&= ~BUFFER_BIT_FRONT_LEFT
;
230 if ( mask
& BUFFER_BIT_BACK_LEFT
) {
232 color_mask
= mmesa
->setup
.plnwt
;
233 mask
&= ~BUFFER_BIT_BACK_LEFT
;
236 if ( (mask
& BUFFER_BIT_DEPTH
) && ctx
->Depth
.Mask
) {
238 clear_depth
= (mmesa
->ClearDepth
& mmesa
->depth_clear_mask
);
239 depth_mask
|= mmesa
->depth_clear_mask
;
240 mask
&= ~BUFFER_BIT_DEPTH
;
243 if ( (mask
& BUFFER_BIT_STENCIL
) && mmesa
->hw_stencil
) {
245 clear_depth
|= (ctx
->Stencil
.Clear
& mmesa
->stencil_clear_mask
);
246 depth_mask
|= mmesa
->stencil_clear_mask
;
247 mask
&= ~BUFFER_BIT_STENCIL
;
251 LOCK_HARDWARE( mmesa
);
253 if ( mmesa
->dirty_cliprects
)
254 mgaUpdateRects( mmesa
, (MGA_FRONT
| MGA_BACK
) );
256 /* flip top to bottom */
261 if ( MGA_DEBUG
& DEBUG_VERBOSE_IOCTL
)
262 fprintf( stderr
, "Clear, bufs %x nbox %d\n",
263 (int)flags
, (int)mmesa
->numClipRects
);
265 for (i
= 0 ; i
< mmesa
->numClipRects
; )
267 int nr
= MIN2(i
+ MGA_NR_SAREA_CLIPRECTS
, mmesa
->numClipRects
);
268 drm_clip_rect_t
*box
= mmesa
->pClipRects
;
269 drm_clip_rect_t
*b
= mmesa
->sarea
->boxes
;
273 for ( ; i
< nr
; i
++) {
276 GLint w
= box
[i
].x2
- x
;
277 GLint h
= box
[i
].y2
- y
;
279 if (x
< cx
) w
-= cx
- x
, x
= cx
;
280 if (y
< cy
) h
-= cy
- y
, y
= cy
;
281 if (x
+ w
> cx
+ cw
) w
= cx
+ cw
- x
;
282 if (y
+ h
> cy
+ ch
) h
= cy
+ ch
- y
;
283 if (w
<= 0) continue;
284 if (h
<= 0) continue;
294 for ( ; i
< nr
; i
++) {
301 if ( MGA_DEBUG
& DEBUG_VERBOSE_IOCTL
)
303 "DRM_IOCTL_MGA_CLEAR flag 0x%x color %x depth %x nbox %d\n",
304 flags
, clear_color
, clear_depth
, mmesa
->sarea
->nbox
);
306 mmesa
->sarea
->nbox
= n
;
309 clear
.clear_color
= clear_color
;
310 clear
.clear_depth
= clear_depth
;
311 clear
.color_mask
= color_mask
;
312 clear
.depth_mask
= depth_mask
;
313 ret
= drmCommandWrite( mmesa
->driFd
, DRM_MGA_CLEAR
,
314 &clear
, sizeof(clear
));
316 fprintf( stderr
, "send clear retcode = %d\n", ret
);
319 if ( MGA_DEBUG
& DEBUG_VERBOSE_IOCTL
)
320 fprintf( stderr
, "finished clear %d\n", ++nrclears
);
323 UNLOCK_HARDWARE( mmesa
);
324 mmesa
->dirty
|= MGA_UPLOAD_CLIPRECTS
|MGA_UPLOAD_CONTEXT
;
328 _swrast_Clear( ctx
, mask
, all
, cx
, cy
, cw
, ch
);
333 * Wait for the previous frame of rendering has completed.
335 * \param mmesa Hardware context pointer.
338 * The loop in this function should have some sort of a timeout mechanism.
341 * This routine used to assume that the hardware lock was held on entry. It
342 * now assumes that the lock is \b not held on entry.
345 static void mgaWaitForFrameCompletion( mgaContextPtr mmesa
)
347 if ( mgaWaitFence( mmesa
, mmesa
->last_frame_fence
, NULL
) == ENOSYS
) {
353 LOCK_HARDWARE( mmesa
);
354 last_frame
= mmesa
->sarea
->last_frame
.head
;
355 last_wrap
= mmesa
->sarea
->last_frame
.wrap
;
357 /* The DMA routines in the kernel track a couple values in the SAREA
358 * that we use here. The number of times that the primary DMA buffer
359 * has "wrapped" around is tracked in last_wrap. In addition, the
360 * wrap count and the buffer position at the end of the last frame are
361 * stored in last_frame.wrap and last_frame.head.
363 * By comparing the wrap counts and the current DMA pointer value
364 * (read directly from the hardware) to last_frame.head, we can
365 * determine when the graphics processor has processed all of the
366 * commands for the last frame.
368 * In this case "last frame" means the frame of the *previous* swap-
369 * buffers call. This is done to prevent queuing a second buffer swap
370 * before the previous swap is executed.
373 if ( last_wrap
< mmesa
->sarea
->last_wrap
||
374 ( last_wrap
== mmesa
->sarea
->last_wrap
&&
375 last_frame
<= (MGA_READ( MGAREG_PRIMADDRESS
) -
376 mmesa
->primary_offset
) ) ) {
381 fprintf( stderr
, " last: head=0x%06x wrap=%d\n",
382 last_frame
, last_wrap
);
383 fprintf( stderr
, " head: head=0x%06lx wrap=%d\n",
384 (long)(MGA_READ( MGAREG_PRIMADDRESS
) - mmesa
->primary_offset
),
385 mmesa
->sarea
->last_wrap
);
387 UPDATE_LOCK( mmesa
, DRM_LOCK_FLUSH
);
389 UNLOCK_HARDWARE( mmesa
);
391 LOCK_HARDWARE( mmesa
);
394 fprintf( stderr
, "\n" );
396 UNLOCK_HARDWARE( mmesa
);
402 * Copy the back buffer to the front buffer.
404 void mgaCopyBuffer( const __DRIdrawablePrivate
*dPriv
)
407 drm_clip_rect_t
*pbox
;
411 GLboolean missed_target
;
415 assert(dPriv
->driContextPriv
);
416 assert(dPriv
->driContextPriv
->driverPrivate
);
418 mmesa
= (mgaContextPtr
) dPriv
->driContextPriv
->driverPrivate
;
420 FLUSH_BATCH( mmesa
);
422 mgaWaitForFrameCompletion( mmesa
);
423 driWaitForVBlank( dPriv
, & mmesa
->vbl_seq
, mmesa
->vblank_flags
,
425 if ( missed_target
) {
426 mmesa
->swap_missed_count
++;
427 (void) (*mmesa
->get_ust
)( & mmesa
->swap_missed_ust
);
429 LOCK_HARDWARE( mmesa
);
431 /* Use the frontbuffer cliprects
433 if (mmesa
->dirty_cliprects
& MGA_FRONT
)
434 mgaUpdateRects( mmesa
, MGA_FRONT
);
437 pbox
= dPriv
->pClipRects
;
438 nbox
= dPriv
->numClipRects
;
440 for (i
= 0 ; i
< nbox
; )
442 int nr
= MIN2(i
+ MGA_NR_SAREA_CLIPRECTS
, dPriv
->numClipRects
);
443 drm_clip_rect_t
*b
= mmesa
->sarea
->boxes
;
445 mmesa
->sarea
->nbox
= nr
- i
;
447 for ( ; i
< nr
; i
++)
451 fprintf(stderr
, "DRM_IOCTL_MGA_SWAP\n");
453 ret
= drmCommandNone( mmesa
->driFd
, DRM_MGA_SWAP
);
455 printf("send swap retcode = %d\n", ret
);
460 (void) mgaSetFence( mmesa
, & mmesa
->last_frame_fence
);
461 UNLOCK_HARDWARE( mmesa
);
463 mmesa
->dirty
|= MGA_UPLOAD_CLIPRECTS
;
465 (void) (*mmesa
->get_ust
)( & mmesa
->swap_ust
);
470 * Implement the hardware-specific portion of \c glFinish.
472 * Flushes all pending commands to the hardware and wait for them to finish.
474 * \param ctx Context where the \c glFinish command was issued.
476 * \sa glFinish, mgaFlush, mgaFlushDMA
478 static void mgaFinish( GLcontext
*ctx
)
480 mgaContextPtr mmesa
= MGA_CONTEXT(ctx
);
484 LOCK_HARDWARE( mmesa
);
485 if ( mmesa
->vertex_dma_buffer
!= NULL
) {
486 mgaFlushVerticesLocked( mmesa
);
489 if ( mgaSetFence( mmesa
, & fence
) == 0 ) {
490 UNLOCK_HARDWARE( mmesa
);
491 (void) mgaWaitFence( mmesa
, fence
, NULL
);
494 if (MGA_DEBUG
&DEBUG_VERBOSE_IOCTL
) {
495 fprintf(stderr
, "mgaRegetLockQuiescent\n");
498 UPDATE_LOCK( mmesa
, DRM_LOCK_QUIESCENT
| DRM_LOCK_FLUSH
);
499 UNLOCK_HARDWARE( mmesa
);
505 * Flush all commands upto at least a certain point to the hardware.
508 * The term "wait" in the name of this function is misleading. It doesn't
509 * actually wait for anything. It just makes sure that the commands have
510 * been flushed to the hardware.
513 * As the name implies, this function assumes that the hardware lock is
516 void mgaWaitAgeLocked( mgaContextPtr mmesa
, int age
)
518 if (GET_DISPATCH_AGE(mmesa
) < age
) {
519 UPDATE_LOCK( mmesa
, DRM_LOCK_FLUSH
);
524 static GLboolean
intersect_rect( drm_clip_rect_t
*out
,
525 const drm_clip_rect_t
*a
,
526 const drm_clip_rect_t
*b
)
529 if (b
->x1
> out
->x1
) out
->x1
= b
->x1
;
530 if (b
->y1
> out
->y1
) out
->y1
= b
->y1
;
531 if (b
->x2
< out
->x2
) out
->x2
= b
->x2
;
532 if (b
->y2
< out
->y2
) out
->y2
= b
->y2
;
534 return ((out
->x1
< out
->x2
) && (out
->y1
< out
->y2
));
540 static void age_mmesa( mgaContextPtr mmesa
, int age
)
542 if (mmesa
->CurrentTexObj
[0]) mmesa
->CurrentTexObj
[0]->age
= age
;
543 if (mmesa
->CurrentTexObj
[1]) mmesa
->CurrentTexObj
[1]->age
= age
;
547 void mgaFlushVerticesLocked( mgaContextPtr mmesa
)
549 drm_clip_rect_t
*pbox
= mmesa
->pClipRects
;
550 int nbox
= mmesa
->numClipRects
;
551 drmBufPtr buffer
= mmesa
->vertex_dma_buffer
;
552 drm_mga_vertex_t vertex
;
555 mmesa
->vertex_dma_buffer
= 0;
560 if (mmesa
->dirty_cliprects
& mmesa
->draw_buffer
)
561 mgaUpdateRects( mmesa
, mmesa
->draw_buffer
);
563 if (mmesa
->dirty
& ~MGA_UPLOAD_CLIPRECTS
)
564 mgaEmitHwStateLocked( mmesa
);
566 /* FIXME: Workaround bug in kernel module.
568 mmesa
->sarea
->dirty
|= MGA_UPLOAD_CONTEXT
;
573 if (nbox
>= MGA_NR_SAREA_CLIPRECTS
)
574 mmesa
->dirty
|= MGA_UPLOAD_CLIPRECTS
;
577 if (!buffer
->used
|| !(mmesa
->dirty
& MGA_UPLOAD_CLIPRECTS
))
580 mmesa
->sarea
->nbox
= 0;
582 mmesa
->sarea
->nbox
= nbox
;
584 if (MGA_DEBUG
&DEBUG_VERBOSE_IOCTL
)
585 fprintf(stderr
, "Firing vertex -- case a nbox %d\n", nbox
);
587 vertex
.idx
= buffer
->idx
;
588 vertex
.used
= buffer
->used
;
590 drmCommandWrite( mmesa
->driFd
, DRM_MGA_VERTEX
,
591 &vertex
, sizeof(drmMGAVertex
) );
593 age_mmesa(mmesa
, mmesa
->sarea
->last_enqueue
);
598 for (i
= 0 ; i
< nbox
; )
600 int nr
= MIN2(i
+ MGA_NR_SAREA_CLIPRECTS
, nbox
);
601 drm_clip_rect_t
*b
= mmesa
->sarea
->boxes
;
604 if (mmesa
->scissor
) {
605 mmesa
->sarea
->nbox
= 0;
607 for ( ; i
< nr
; i
++) {
609 if (intersect_rect(b
, b
, &mmesa
->scissor_rect
)) {
610 mmesa
->sarea
->nbox
++;
617 if (!mmesa
->sarea
->nbox
) {
618 if (nr
< nbox
) continue;
622 mmesa
->sarea
->nbox
= nr
- i
;
623 for ( ; i
< nr
; i
++)
627 /* Finished with the buffer?
632 mmesa
->sarea
->dirty
|= MGA_UPLOAD_CLIPRECTS
;
634 vertex
.idx
= buffer
->idx
;
635 vertex
.used
= buffer
->used
;
636 vertex
.discard
= discard
;
637 drmCommandWrite( mmesa
->driFd
, DRM_MGA_VERTEX
,
638 &vertex
, sizeof(vertex
) );
640 age_mmesa(mmesa
, mmesa
->sarea
->last_enqueue
);
644 mmesa
->dirty
&= ~MGA_UPLOAD_CLIPRECTS
;
647 void mgaFlushVertices( mgaContextPtr mmesa
)
649 LOCK_HARDWARE( mmesa
);
650 mgaFlushVerticesLocked( mmesa
);
651 UNLOCK_HARDWARE( mmesa
);
655 void mgaFireILoadLocked( mgaContextPtr mmesa
,
656 GLuint offset
, GLuint length
)
658 if (!mmesa
->iload_buffer
) {
659 fprintf(stderr
, "mgaFireILoad: no buffer\n");
663 if (MGA_DEBUG
&DEBUG_VERBOSE_IOCTL
)
664 fprintf(stderr
, "mgaFireILoad idx %d ofs 0x%x length %d\n",
665 mmesa
->iload_buffer
->idx
, (int)offset
, (int)length
);
667 mga_iload_dma_ioctl( mmesa
, offset
, length
);
670 void mgaGetILoadBufferLocked( mgaContextPtr mmesa
)
672 if (MGA_DEBUG
&DEBUG_VERBOSE_IOCTL
)
673 fprintf(stderr
, "mgaGetIloadBuffer (buffer now %p)\n",
674 (void *) mmesa
->iload_buffer
);
676 mmesa
->iload_buffer
= mga_get_buffer_ioctl( mmesa
);
681 * Implement the hardware-specific portion of \c glFlush.
683 * \param ctx Context to be flushed.
685 * \sa glFlush, mgaFinish, mgaFlushDMA
687 static void mgaFlush( GLcontext
*ctx
)
689 mgaContextPtr mmesa
= MGA_CONTEXT( ctx
);
692 LOCK_HARDWARE( mmesa
);
693 if ( mmesa
->vertex_dma_buffer
!= NULL
) {
694 mgaFlushVerticesLocked( mmesa
);
697 UPDATE_LOCK( mmesa
, DRM_LOCK_FLUSH
);
698 UNLOCK_HARDWARE( mmesa
);
702 int mgaFlushDMA( int fd
, drmLockFlags flags
)
707 memset( &lock
, 0, sizeof(lock
) );
709 lock
.flags
= flags
& (DRM_LOCK_QUIESCENT
| DRM_LOCK_FLUSH
710 | DRM_LOCK_FLUSH_ALL
);
713 ret
= drmCommandWrite( fd
, DRM_MGA_FLUSH
, &lock
, sizeof(lock
) );
714 } while ( ret
&& errno
== EBUSY
&& i
++ < DRM_MGA_IDLE_RETRY
);
718 if ( errno
!= EBUSY
)
721 if ( lock
.flags
& DRM_LOCK_QUIESCENT
) {
722 /* Only keep trying if we need quiescence.
724 lock
.flags
&= ~(DRM_LOCK_FLUSH
| DRM_LOCK_FLUSH_ALL
);
727 ret
= drmCommandWrite( fd
, DRM_MGA_FLUSH
, &lock
, sizeof(lock
) );
728 } while ( ret
&& errno
== EBUSY
&& i
++ < DRM_MGA_IDLE_RETRY
);
738 void mgaInitIoctlFuncs( struct dd_function_table
*functions
)
740 functions
->Clear
= mgaClear
;
741 functions
->Flush
= mgaFlush
;
742 functions
->Finish
= mgaFinish
;