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>
34 #include "main/mtypes.h"
35 #include "main/macros.h"
37 #include "swrast/swrast.h"
42 #include "mgacontext.h"
54 mgaSetFence( mgaContextPtr mmesa
, uint32_t * fence
)
58 if ( mmesa
->driScreen
->drm_version
.minor
>= 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
->drm_version
.minor
>= 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
)
209 mgaContextPtr mmesa
= MGA_CONTEXT(ctx
);
210 __DRIdrawablePrivate
*dPriv
= mmesa
->driDrawable
;
212 GLuint clear_color
= mmesa
->ClearColor
;
213 GLuint clear_depth
= 0;
214 GLuint color_mask
= 0;
215 GLuint depth_mask
= 0;
219 drm_mga_clear_t clear
;
220 GLint cx
, cy
, cw
, ch
;
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 /* compute region after locking: */
254 cx
= ctx
->DrawBuffer
->_Xmin
;
255 cy
= ctx
->DrawBuffer
->_Ymin
;
256 cw
= ctx
->DrawBuffer
->_Xmax
- cx
;
257 ch
= ctx
->DrawBuffer
->_Ymax
- cy
;
259 if ( mmesa
->dirty_cliprects
)
260 mgaUpdateRects( mmesa
, (MGA_FRONT
| MGA_BACK
) );
262 /* flip top to bottom */
267 if ( MGA_DEBUG
& DEBUG_VERBOSE_IOCTL
)
268 fprintf( stderr
, "Clear, bufs %x nbox %d\n",
269 (int)flags
, (int)mmesa
->numClipRects
);
271 for (i
= 0 ; i
< mmesa
->numClipRects
; )
273 int nr
= MIN2(i
+ MGA_NR_SAREA_CLIPRECTS
, mmesa
->numClipRects
);
274 drm_clip_rect_t
*box
= mmesa
->pClipRects
;
275 drm_clip_rect_t
*b
= mmesa
->sarea
->boxes
;
278 if (cw
!= dPriv
->w
|| ch
!= dPriv
->h
) {
279 /* clear subregion */
280 for ( ; i
< nr
; i
++) {
283 GLint w
= box
[i
].x2
- x
;
284 GLint h
= box
[i
].y2
- y
;
286 if (x
< cx
) w
-= cx
- x
, x
= cx
;
287 if (y
< cy
) h
-= cy
- y
, y
= cy
;
288 if (x
+ w
> cx
+ cw
) w
= cx
+ cw
- x
;
289 if (y
+ h
> cy
+ ch
) h
= cy
+ ch
- y
;
290 if (w
<= 0) continue;
291 if (h
<= 0) continue;
301 /* clear whole window */
302 for ( ; i
< nr
; i
++) {
309 if ( MGA_DEBUG
& DEBUG_VERBOSE_IOCTL
)
311 "DRM_IOCTL_MGA_CLEAR flag 0x%x color %x depth %x nbox %d\n",
312 flags
, clear_color
, clear_depth
, mmesa
->sarea
->nbox
);
314 mmesa
->sarea
->nbox
= n
;
317 clear
.clear_color
= clear_color
;
318 clear
.clear_depth
= clear_depth
;
319 clear
.color_mask
= color_mask
;
320 clear
.depth_mask
= depth_mask
;
321 ret
= drmCommandWrite( mmesa
->driFd
, DRM_MGA_CLEAR
,
322 &clear
, sizeof(clear
));
324 fprintf( stderr
, "send clear retcode = %d\n", ret
);
327 if ( MGA_DEBUG
& DEBUG_VERBOSE_IOCTL
)
328 fprintf( stderr
, "finished clear %d\n", ++nrclears
);
331 UNLOCK_HARDWARE( mmesa
);
332 mmesa
->dirty
|= MGA_UPLOAD_CLIPRECTS
|MGA_UPLOAD_CONTEXT
;
336 _swrast_Clear( ctx
, mask
);
341 * Wait for the previous frame of rendering has completed.
343 * \param mmesa Hardware context pointer.
346 * The loop in this function should have some sort of a timeout mechanism.
349 * This routine used to assume that the hardware lock was held on entry. It
350 * now assumes that the lock is \b not held on entry.
353 static void mgaWaitForFrameCompletion( mgaContextPtr mmesa
)
355 if ( mgaWaitFence( mmesa
, mmesa
->last_frame_fence
, NULL
) == ENOSYS
) {
361 LOCK_HARDWARE( mmesa
);
362 last_frame
= mmesa
->sarea
->last_frame
.head
;
363 last_wrap
= mmesa
->sarea
->last_frame
.wrap
;
365 /* The DMA routines in the kernel track a couple values in the SAREA
366 * that we use here. The number of times that the primary DMA buffer
367 * has "wrapped" around is tracked in last_wrap. In addition, the
368 * wrap count and the buffer position at the end of the last frame are
369 * stored in last_frame.wrap and last_frame.head.
371 * By comparing the wrap counts and the current DMA pointer value
372 * (read directly from the hardware) to last_frame.head, we can
373 * determine when the graphics processor has processed all of the
374 * commands for the last frame.
376 * In this case "last frame" means the frame of the *previous* swap-
377 * buffers call. This is done to prevent queuing a second buffer swap
378 * before the previous swap is executed.
381 if ( last_wrap
< mmesa
->sarea
->last_wrap
||
382 ( last_wrap
== mmesa
->sarea
->last_wrap
&&
383 last_frame
<= (MGA_READ( MGAREG_PRIMADDRESS
) -
384 mmesa
->primary_offset
) ) ) {
389 fprintf( stderr
, " last: head=0x%06x wrap=%d\n",
390 last_frame
, last_wrap
);
391 fprintf( stderr
, " head: head=0x%06lx wrap=%d\n",
392 (long)(MGA_READ( MGAREG_PRIMADDRESS
) - mmesa
->primary_offset
),
393 mmesa
->sarea
->last_wrap
);
395 UPDATE_LOCK( mmesa
, DRM_LOCK_FLUSH
);
397 UNLOCK_HARDWARE( mmesa
);
399 LOCK_HARDWARE( mmesa
);
402 fprintf( stderr
, "\n" );
404 UNLOCK_HARDWARE( mmesa
);
410 * Copy the back buffer to the front buffer.
412 void mgaCopyBuffer( __DRIdrawablePrivate
*dPriv
)
415 drm_clip_rect_t
*pbox
;
419 GLboolean missed_target
;
420 __DRIscreenPrivate
*psp
= dPriv
->driScreenPriv
;
423 assert(dPriv
->driContextPriv
);
424 assert(dPriv
->driContextPriv
->driverPrivate
);
426 mmesa
= (mgaContextPtr
) dPriv
->driContextPriv
->driverPrivate
;
428 FLUSH_BATCH( mmesa
);
430 mgaWaitForFrameCompletion( mmesa
);
431 driWaitForVBlank( dPriv
, & missed_target
);
432 if ( missed_target
) {
433 mmesa
->swap_missed_count
++;
434 (void) (*psp
->systemTime
->getUST
)( & mmesa
->swap_missed_ust
);
436 LOCK_HARDWARE( mmesa
);
438 /* Use the frontbuffer cliprects
440 if (mmesa
->dirty_cliprects
& MGA_FRONT
)
441 mgaUpdateRects( mmesa
, MGA_FRONT
);
444 pbox
= dPriv
->pClipRects
;
445 nbox
= dPriv
->numClipRects
;
447 for (i
= 0 ; i
< nbox
; )
449 int nr
= MIN2(i
+ MGA_NR_SAREA_CLIPRECTS
, dPriv
->numClipRects
);
450 drm_clip_rect_t
*b
= mmesa
->sarea
->boxes
;
452 mmesa
->sarea
->nbox
= nr
- i
;
454 for ( ; i
< nr
; i
++)
458 fprintf(stderr
, "DRM_IOCTL_MGA_SWAP\n");
460 ret
= drmCommandNone( mmesa
->driFd
, DRM_MGA_SWAP
);
462 printf("send swap retcode = %d\n", ret
);
467 (void) mgaSetFence( mmesa
, & mmesa
->last_frame_fence
);
468 UNLOCK_HARDWARE( mmesa
);
470 mmesa
->dirty
|= MGA_UPLOAD_CLIPRECTS
;
472 (void) (*psp
->systemTime
->getUST
)( & mmesa
->swap_ust
);
477 * Implement the hardware-specific portion of \c glFinish.
479 * Flushes all pending commands to the hardware and wait for them to finish.
481 * \param ctx Context where the \c glFinish command was issued.
483 * \sa glFinish, mgaFlush, mgaFlushDMA
485 static void mgaFinish( GLcontext
*ctx
)
487 mgaContextPtr mmesa
= MGA_CONTEXT(ctx
);
491 LOCK_HARDWARE( mmesa
);
492 if ( mmesa
->vertex_dma_buffer
!= NULL
) {
493 mgaFlushVerticesLocked( mmesa
);
496 if ( mgaSetFence( mmesa
, & fence
) == 0 ) {
497 UNLOCK_HARDWARE( mmesa
);
498 (void) mgaWaitFence( mmesa
, fence
, NULL
);
501 if (MGA_DEBUG
&DEBUG_VERBOSE_IOCTL
) {
502 fprintf(stderr
, "mgaRegetLockQuiescent\n");
505 UPDATE_LOCK( mmesa
, DRM_LOCK_QUIESCENT
| DRM_LOCK_FLUSH
);
506 UNLOCK_HARDWARE( mmesa
);
512 * Flush all commands upto at least a certain point to the hardware.
515 * The term "wait" in the name of this function is misleading. It doesn't
516 * actually wait for anything. It just makes sure that the commands have
517 * been flushed to the hardware.
520 * As the name implies, this function assumes that the hardware lock is
523 void mgaWaitAgeLocked( mgaContextPtr mmesa
, int age
)
525 if (GET_DISPATCH_AGE(mmesa
) < age
) {
526 UPDATE_LOCK( mmesa
, DRM_LOCK_FLUSH
);
531 static GLboolean
intersect_rect( drm_clip_rect_t
*out
,
532 const drm_clip_rect_t
*a
,
533 const drm_clip_rect_t
*b
)
536 if (b
->x1
> out
->x1
) out
->x1
= b
->x1
;
537 if (b
->y1
> out
->y1
) out
->y1
= b
->y1
;
538 if (b
->x2
< out
->x2
) out
->x2
= b
->x2
;
539 if (b
->y2
< out
->y2
) out
->y2
= b
->y2
;
541 return ((out
->x1
< out
->x2
) && (out
->y1
< out
->y2
));
547 static void age_mmesa( mgaContextPtr mmesa
, int age
)
549 if (mmesa
->CurrentTexObj
[0]) mmesa
->CurrentTexObj
[0]->age
= age
;
550 if (mmesa
->CurrentTexObj
[1]) mmesa
->CurrentTexObj
[1]->age
= age
;
554 void mgaFlushVerticesLocked( mgaContextPtr mmesa
)
556 drm_clip_rect_t
*pbox
= mmesa
->pClipRects
;
557 int nbox
= mmesa
->numClipRects
;
558 drmBufPtr buffer
= mmesa
->vertex_dma_buffer
;
559 drm_mga_vertex_t vertex
;
562 mmesa
->vertex_dma_buffer
= 0;
567 if (mmesa
->dirty_cliprects
& mmesa
->draw_buffer
)
568 mgaUpdateRects( mmesa
, mmesa
->draw_buffer
);
570 if (mmesa
->dirty
& ~MGA_UPLOAD_CLIPRECTS
)
571 mgaEmitHwStateLocked( mmesa
);
573 /* FIXME: Workaround bug in kernel module.
575 mmesa
->sarea
->dirty
|= MGA_UPLOAD_CONTEXT
;
580 if (nbox
>= MGA_NR_SAREA_CLIPRECTS
)
581 mmesa
->dirty
|= MGA_UPLOAD_CLIPRECTS
;
584 if (!buffer
->used
|| !(mmesa
->dirty
& MGA_UPLOAD_CLIPRECTS
))
587 mmesa
->sarea
->nbox
= 0;
589 mmesa
->sarea
->nbox
= nbox
;
591 if (MGA_DEBUG
&DEBUG_VERBOSE_IOCTL
)
592 fprintf(stderr
, "Firing vertex -- case a nbox %d\n", nbox
);
594 vertex
.idx
= buffer
->idx
;
595 vertex
.used
= buffer
->used
;
597 drmCommandWrite( mmesa
->driFd
, DRM_MGA_VERTEX
,
598 &vertex
, sizeof(drmMGAVertex
) );
600 age_mmesa(mmesa
, mmesa
->sarea
->last_enqueue
);
605 for (i
= 0 ; i
< nbox
; )
607 int nr
= MIN2(i
+ MGA_NR_SAREA_CLIPRECTS
, nbox
);
608 drm_clip_rect_t
*b
= mmesa
->sarea
->boxes
;
611 if (mmesa
->scissor
) {
612 mmesa
->sarea
->nbox
= 0;
614 for ( ; i
< nr
; i
++) {
616 if (intersect_rect(b
, b
, &mmesa
->scissor_rect
)) {
617 mmesa
->sarea
->nbox
++;
624 if (!mmesa
->sarea
->nbox
) {
625 if (nr
< nbox
) continue;
629 mmesa
->sarea
->nbox
= nr
- i
;
630 for ( ; i
< nr
; i
++)
634 /* Finished with the buffer?
639 mmesa
->sarea
->dirty
|= MGA_UPLOAD_CLIPRECTS
;
641 vertex
.idx
= buffer
->idx
;
642 vertex
.used
= buffer
->used
;
643 vertex
.discard
= discard
;
644 drmCommandWrite( mmesa
->driFd
, DRM_MGA_VERTEX
,
645 &vertex
, sizeof(vertex
) );
647 age_mmesa(mmesa
, mmesa
->sarea
->last_enqueue
);
651 mmesa
->dirty
&= ~MGA_UPLOAD_CLIPRECTS
;
654 void mgaFlushVertices( mgaContextPtr mmesa
)
656 LOCK_HARDWARE( mmesa
);
657 mgaFlushVerticesLocked( mmesa
);
658 UNLOCK_HARDWARE( mmesa
);
662 void mgaFireILoadLocked( mgaContextPtr mmesa
,
663 GLuint offset
, GLuint length
)
665 if (!mmesa
->iload_buffer
) {
666 fprintf(stderr
, "mgaFireILoad: no buffer\n");
670 if (MGA_DEBUG
&DEBUG_VERBOSE_IOCTL
)
671 fprintf(stderr
, "mgaFireILoad idx %d ofs 0x%x length %d\n",
672 mmesa
->iload_buffer
->idx
, (int)offset
, (int)length
);
674 mga_iload_dma_ioctl( mmesa
, offset
, length
);
677 void mgaGetILoadBufferLocked( mgaContextPtr mmesa
)
679 if (MGA_DEBUG
&DEBUG_VERBOSE_IOCTL
)
680 fprintf(stderr
, "mgaGetIloadBuffer (buffer now %p)\n",
681 (void *) mmesa
->iload_buffer
);
683 mmesa
->iload_buffer
= mga_get_buffer_ioctl( mmesa
);
688 * Implement the hardware-specific portion of \c glFlush.
690 * \param ctx Context to be flushed.
692 * \sa glFlush, mgaFinish, mgaFlushDMA
694 static void mgaFlush( GLcontext
*ctx
)
696 mgaContextPtr mmesa
= MGA_CONTEXT( ctx
);
699 LOCK_HARDWARE( mmesa
);
700 if ( mmesa
->vertex_dma_buffer
!= NULL
) {
701 mgaFlushVerticesLocked( mmesa
);
704 UPDATE_LOCK( mmesa
, DRM_LOCK_FLUSH
);
705 UNLOCK_HARDWARE( mmesa
);
709 int mgaFlushDMA( int fd
, drmLockFlags flags
)
714 memset( &lock
, 0, sizeof(lock
) );
716 lock
.flags
= flags
& (DRM_LOCK_QUIESCENT
| DRM_LOCK_FLUSH
717 | DRM_LOCK_FLUSH_ALL
);
720 ret
= drmCommandWrite( fd
, DRM_MGA_FLUSH
, &lock
, sizeof(lock
) );
721 } while ( ret
&& errno
== EBUSY
&& i
++ < DRM_MGA_IDLE_RETRY
);
725 if ( errno
!= EBUSY
)
728 if ( lock
.flags
& DRM_LOCK_QUIESCENT
) {
729 /* Only keep trying if we need quiescence.
731 lock
.flags
&= ~(DRM_LOCK_FLUSH
| DRM_LOCK_FLUSH_ALL
);
734 ret
= drmCommandWrite( fd
, DRM_MGA_FLUSH
, &lock
, sizeof(lock
) );
735 } while ( ret
&& errno
== EBUSY
&& i
++ < DRM_MGA_IDLE_RETRY
);
745 void mgaInitIoctlFuncs( struct dd_function_table
*functions
)
747 functions
->Clear
= mgaClear
;
748 functions
->Flush
= mgaFlush
;
749 functions
->Finish
= mgaFinish
;