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"
51 mgaSetFence( mgaContextPtr mmesa
, uint32_t * fence
)
55 if ( mmesa
->driScreen
->drm_version
.minor
>= 2 ) {
56 ret
= drmCommandWriteRead( mmesa
->driScreen
->fd
, DRM_MGA_SET_FENCE
,
57 fence
, sizeof( uint32_t ));
59 fprintf(stderr
, "drmMgaSetFence: %d\n", ret
);
69 mgaWaitFence( mgaContextPtr mmesa
, uint32_t fence
, uint32_t * curr_fence
)
73 if ( mmesa
->driScreen
->drm_version
.minor
>= 2 ) {
74 uint32_t temp
= fence
;
76 ret
= drmCommandWriteRead( mmesa
->driScreen
->fd
,
78 & temp
, sizeof( uint32_t ));
80 fprintf(stderr
, "drmMgaSetFence: %d\n", ret
);
93 static void mga_iload_dma_ioctl(mgaContextPtr mmesa
,
97 drmBufPtr buf
= mmesa
->iload_buffer
;
98 drm_mga_iload_t iload
;
101 if (MGA_DEBUG
&DEBUG_VERBOSE_IOCTL
)
102 fprintf(stderr
, "DRM_IOCTL_MGA_ILOAD idx %d dst %x length %d\n",
103 buf
->idx
, (int) dest
, length
);
105 if ( (length
& MGA_ILOAD_MASK
) != 0 ) {
106 UNLOCK_HARDWARE( mmesa
);
107 fprintf( stderr
, "%s: Invalid ILOAD datasize (%d), must be "
108 "multiple of %u.\n", __FUNCTION__
, length
, MGA_ILOAD_ALIGN
);
112 iload
.idx
= buf
->idx
;
114 iload
.length
= length
;
118 ret
= drmCommandWrite( mmesa
->driFd
, DRM_MGA_ILOAD
,
119 &iload
, sizeof(iload
) );
120 } while ( ret
== -EBUSY
&& i
++ < DRM_MGA_IDLE_RETRY
);
123 printf("send iload retcode = %d\n", ret
);
127 mmesa
->iload_buffer
= 0;
129 if (MGA_DEBUG
&DEBUG_VERBOSE_IOCTL
)
130 fprintf(stderr
, "finished iload dma put\n");
134 drmBufPtr
mga_get_buffer_ioctl( mgaContextPtr mmesa
)
142 if (MGA_DEBUG
&DEBUG_VERBOSE_IOCTL
)
143 fprintf(stderr
, "Getting dma buffer\n");
145 dma
.context
= mmesa
->hHWContext
;
147 dma
.send_list
= NULL
;
148 dma
.send_sizes
= NULL
;
150 dma
.request_count
= 1;
151 dma
.request_size
= MGA_BUFFER_SIZE
;
152 dma
.request_list
= &idx
;
153 dma
.request_sizes
= &size
;
154 dma
.granted_count
= 0;
157 if (MGA_DEBUG
&DEBUG_VERBOSE_IOCTL
)
158 fprintf(stderr
, "drmDMA (get) ctx %d count %d size 0x%x\n",
159 dma
.context
, dma
.request_count
,
163 retcode
= drmDMA(mmesa
->driFd
, &dma
);
165 if (MGA_DEBUG
&DEBUG_VERBOSE_IOCTL
)
166 fprintf(stderr
, "retcode %d sz %d idx %d count %d\n",
168 dma
.request_sizes
[0],
173 dma
.request_sizes
[0] &&
177 if (MGA_DEBUG
&DEBUG_VERBOSE_IOCTL
)
178 fprintf(stderr
, "\n\nflush");
180 UPDATE_LOCK( mmesa
, DRM_LOCK_FLUSH
| DRM_LOCK_QUIESCENT
);
183 buf
= &(mmesa
->mgaScreen
->bufs
->list
[idx
]);
186 if (MGA_DEBUG
&DEBUG_VERBOSE_IOCTL
)
188 "drmDMA (get) returns size[0] 0x%x idx[0] %d\n"
189 "dma_buffer now: buf idx: %d size: %d used: %d addr %p\n",
190 dma
.request_sizes
[0], dma
.request_list
[0],
191 buf
->idx
, buf
->total
,
192 buf
->used
, buf
->address
);
194 if (MGA_DEBUG
&DEBUG_VERBOSE_IOCTL
)
195 fprintf(stderr
, "finished getbuffer\n");
204 mgaClear( GLcontext
*ctx
, GLbitfield mask
)
206 mgaContextPtr mmesa
= MGA_CONTEXT(ctx
);
207 __DRIdrawable
*dPriv
= mmesa
->driDrawable
;
209 GLuint clear_color
= mmesa
->ClearColor
;
210 GLuint clear_depth
= 0;
211 GLuint color_mask
= 0;
212 GLuint depth_mask
= 0;
216 drm_mga_clear_t clear
;
217 GLint cx
, cy
, cw
, ch
;
219 FLUSH_BATCH( mmesa
);
221 if ( mask
& BUFFER_BIT_FRONT_LEFT
) {
223 color_mask
= mmesa
->setup
.plnwt
;
224 mask
&= ~BUFFER_BIT_FRONT_LEFT
;
227 if ( mask
& BUFFER_BIT_BACK_LEFT
) {
229 color_mask
= mmesa
->setup
.plnwt
;
230 mask
&= ~BUFFER_BIT_BACK_LEFT
;
233 if ( (mask
& BUFFER_BIT_DEPTH
) && ctx
->Depth
.Mask
) {
235 clear_depth
= (mmesa
->ClearDepth
& mmesa
->depth_clear_mask
);
236 depth_mask
|= mmesa
->depth_clear_mask
;
237 mask
&= ~BUFFER_BIT_DEPTH
;
240 if ( (mask
& BUFFER_BIT_STENCIL
) && mmesa
->hw_stencil
) {
242 clear_depth
|= (ctx
->Stencil
.Clear
& mmesa
->stencil_clear_mask
);
243 depth_mask
|= mmesa
->stencil_clear_mask
;
244 mask
&= ~BUFFER_BIT_STENCIL
;
248 LOCK_HARDWARE( mmesa
);
250 /* compute region after locking: */
251 cx
= ctx
->DrawBuffer
->_Xmin
;
252 cy
= ctx
->DrawBuffer
->_Ymin
;
253 cw
= ctx
->DrawBuffer
->_Xmax
- cx
;
254 ch
= ctx
->DrawBuffer
->_Ymax
- cy
;
256 if ( mmesa
->dirty_cliprects
)
257 mgaUpdateRects( mmesa
, (MGA_FRONT
| MGA_BACK
) );
259 /* flip top to bottom */
264 if ( MGA_DEBUG
& DEBUG_VERBOSE_IOCTL
)
265 fprintf( stderr
, "Clear, bufs %x nbox %d\n",
266 (int)flags
, (int)mmesa
->numClipRects
);
268 for (i
= 0 ; i
< mmesa
->numClipRects
; )
270 int nr
= MIN2(i
+ MGA_NR_SAREA_CLIPRECTS
, mmesa
->numClipRects
);
271 drm_clip_rect_t
*box
= mmesa
->pClipRects
;
272 drm_clip_rect_t
*b
= mmesa
->sarea
->boxes
;
275 if (cw
!= dPriv
->w
|| ch
!= dPriv
->h
) {
276 /* clear subregion */
277 for ( ; i
< nr
; i
++) {
280 GLint w
= box
[i
].x2
- x
;
281 GLint h
= box
[i
].y2
- y
;
283 if (x
< cx
) w
-= cx
- x
, x
= cx
;
284 if (y
< cy
) h
-= cy
- y
, y
= cy
;
285 if (x
+ w
> cx
+ cw
) w
= cx
+ cw
- x
;
286 if (y
+ h
> cy
+ ch
) h
= cy
+ ch
- y
;
287 if (w
<= 0) continue;
288 if (h
<= 0) continue;
298 /* clear whole window */
299 for ( ; i
< nr
; i
++) {
306 if ( MGA_DEBUG
& DEBUG_VERBOSE_IOCTL
)
308 "DRM_IOCTL_MGA_CLEAR flag 0x%x color %x depth %x nbox %d\n",
309 flags
, clear_color
, clear_depth
, mmesa
->sarea
->nbox
);
311 mmesa
->sarea
->nbox
= n
;
314 clear
.clear_color
= clear_color
;
315 clear
.clear_depth
= clear_depth
;
316 clear
.color_mask
= color_mask
;
317 clear
.depth_mask
= depth_mask
;
318 ret
= drmCommandWrite( mmesa
->driFd
, DRM_MGA_CLEAR
,
319 &clear
, sizeof(clear
));
321 fprintf( stderr
, "send clear retcode = %d\n", ret
);
324 if ( MGA_DEBUG
& DEBUG_VERBOSE_IOCTL
)
325 fprintf( stderr
, "finished clear %d\n", ++nrclears
);
328 UNLOCK_HARDWARE( mmesa
);
329 mmesa
->dirty
|= MGA_UPLOAD_CLIPRECTS
|MGA_UPLOAD_CONTEXT
;
333 _swrast_Clear( ctx
, mask
);
338 * Wait for the previous frame of rendering has completed.
340 * \param mmesa Hardware context pointer.
343 * The loop in this function should have some sort of a timeout mechanism.
346 * This routine used to assume that the hardware lock was held on entry. It
347 * now assumes that the lock is \b not held on entry.
350 static void mgaWaitForFrameCompletion( mgaContextPtr mmesa
)
352 if ( mgaWaitFence( mmesa
, mmesa
->last_frame_fence
, NULL
) == ENOSYS
) {
358 LOCK_HARDWARE( mmesa
);
359 last_frame
= mmesa
->sarea
->last_frame
.head
;
360 last_wrap
= mmesa
->sarea
->last_frame
.wrap
;
362 /* The DMA routines in the kernel track a couple values in the SAREA
363 * that we use here. The number of times that the primary DMA buffer
364 * has "wrapped" around is tracked in last_wrap. In addition, the
365 * wrap count and the buffer position at the end of the last frame are
366 * stored in last_frame.wrap and last_frame.head.
368 * By comparing the wrap counts and the current DMA pointer value
369 * (read directly from the hardware) to last_frame.head, we can
370 * determine when the graphics processor has processed all of the
371 * commands for the last frame.
373 * In this case "last frame" means the frame of the *previous* swap-
374 * buffers call. This is done to prevent queuing a second buffer swap
375 * before the previous swap is executed.
378 if ( last_wrap
< mmesa
->sarea
->last_wrap
||
379 ( last_wrap
== mmesa
->sarea
->last_wrap
&&
380 last_frame
<= (MGA_READ( MGAREG_PRIMADDRESS
) -
381 mmesa
->primary_offset
) ) ) {
386 fprintf( stderr
, " last: head=0x%06x wrap=%d\n",
387 last_frame
, last_wrap
);
388 fprintf( stderr
, " head: head=0x%06lx wrap=%d\n",
389 (long)(MGA_READ( MGAREG_PRIMADDRESS
) - mmesa
->primary_offset
),
390 mmesa
->sarea
->last_wrap
);
392 UPDATE_LOCK( mmesa
, DRM_LOCK_FLUSH
);
394 UNLOCK_HARDWARE( mmesa
);
396 LOCK_HARDWARE( mmesa
);
399 fprintf( stderr
, "\n" );
401 UNLOCK_HARDWARE( mmesa
);
407 * Copy the back buffer to the front buffer.
409 void mgaCopyBuffer( __DRIdrawable
*dPriv
)
412 drm_clip_rect_t
*pbox
;
416 GLboolean missed_target
;
417 __DRIscreen
*psp
= dPriv
->driScreenPriv
;
420 assert(dPriv
->driContextPriv
);
421 assert(dPriv
->driContextPriv
->driverPrivate
);
423 mmesa
= (mgaContextPtr
) dPriv
->driContextPriv
->driverPrivate
;
425 FLUSH_BATCH( mmesa
);
427 mgaWaitForFrameCompletion( mmesa
);
428 driWaitForVBlank( dPriv
, & missed_target
);
429 if ( missed_target
) {
430 mmesa
->swap_missed_count
++;
431 (void) (*psp
->systemTime
->getUST
)( & mmesa
->swap_missed_ust
);
433 LOCK_HARDWARE( mmesa
);
435 /* Use the frontbuffer cliprects
437 if (mmesa
->dirty_cliprects
& MGA_FRONT
)
438 mgaUpdateRects( mmesa
, MGA_FRONT
);
441 pbox
= dPriv
->pClipRects
;
442 nbox
= dPriv
->numClipRects
;
444 for (i
= 0 ; i
< nbox
; )
446 int nr
= MIN2(i
+ MGA_NR_SAREA_CLIPRECTS
, dPriv
->numClipRects
);
447 drm_clip_rect_t
*b
= mmesa
->sarea
->boxes
;
449 mmesa
->sarea
->nbox
= nr
- i
;
451 for ( ; i
< nr
; i
++)
455 fprintf(stderr
, "DRM_IOCTL_MGA_SWAP\n");
457 ret
= drmCommandNone( mmesa
->driFd
, DRM_MGA_SWAP
);
459 printf("send swap retcode = %d\n", ret
);
464 (void) mgaSetFence( mmesa
, & mmesa
->last_frame_fence
);
465 UNLOCK_HARDWARE( mmesa
);
467 mmesa
->dirty
|= MGA_UPLOAD_CLIPRECTS
;
469 (void) (*psp
->systemTime
->getUST
)( & mmesa
->swap_ust
);
474 * Implement the hardware-specific portion of \c glFinish.
476 * Flushes all pending commands to the hardware and wait for them to finish.
478 * \param ctx Context where the \c glFinish command was issued.
480 * \sa glFinish, mgaFlush, mgaFlushDMA
482 static void mgaFinish( GLcontext
*ctx
)
484 mgaContextPtr mmesa
= MGA_CONTEXT(ctx
);
488 LOCK_HARDWARE( mmesa
);
489 if ( mmesa
->vertex_dma_buffer
!= NULL
) {
490 mgaFlushVerticesLocked( mmesa
);
493 if ( mgaSetFence( mmesa
, & fence
) == 0 ) {
494 UNLOCK_HARDWARE( mmesa
);
495 (void) mgaWaitFence( mmesa
, fence
, NULL
);
498 if (MGA_DEBUG
&DEBUG_VERBOSE_IOCTL
) {
499 fprintf(stderr
, "mgaRegetLockQuiescent\n");
502 UPDATE_LOCK( mmesa
, DRM_LOCK_QUIESCENT
| DRM_LOCK_FLUSH
);
503 UNLOCK_HARDWARE( mmesa
);
509 * Flush all commands upto at least a certain point to the hardware.
512 * The term "wait" in the name of this function is misleading. It doesn't
513 * actually wait for anything. It just makes sure that the commands have
514 * been flushed to the hardware.
517 * As the name implies, this function assumes that the hardware lock is
520 void mgaWaitAgeLocked( mgaContextPtr mmesa
, int age
)
522 if (GET_DISPATCH_AGE(mmesa
) < age
) {
523 UPDATE_LOCK( mmesa
, DRM_LOCK_FLUSH
);
528 static GLboolean
intersect_rect( drm_clip_rect_t
*out
,
529 const drm_clip_rect_t
*a
,
530 const drm_clip_rect_t
*b
)
533 if (b
->x1
> out
->x1
) out
->x1
= b
->x1
;
534 if (b
->y1
> out
->y1
) out
->y1
= b
->y1
;
535 if (b
->x2
< out
->x2
) out
->x2
= b
->x2
;
536 if (b
->y2
< out
->y2
) out
->y2
= b
->y2
;
538 return ((out
->x1
< out
->x2
) && (out
->y1
< out
->y2
));
544 static void age_mmesa( mgaContextPtr mmesa
, int age
)
546 if (mmesa
->CurrentTexObj
[0]) mmesa
->CurrentTexObj
[0]->age
= age
;
547 if (mmesa
->CurrentTexObj
[1]) mmesa
->CurrentTexObj
[1]->age
= age
;
551 void mgaFlushVerticesLocked( mgaContextPtr mmesa
)
553 drm_clip_rect_t
*pbox
= mmesa
->pClipRects
;
554 int nbox
= mmesa
->numClipRects
;
555 drmBufPtr buffer
= mmesa
->vertex_dma_buffer
;
556 drm_mga_vertex_t vertex
;
559 mmesa
->vertex_dma_buffer
= 0;
564 if (mmesa
->dirty_cliprects
& mmesa
->draw_buffer
)
565 mgaUpdateRects( mmesa
, mmesa
->draw_buffer
);
567 if (mmesa
->dirty
& ~MGA_UPLOAD_CLIPRECTS
)
568 mgaEmitHwStateLocked( mmesa
);
570 /* FIXME: Workaround bug in kernel module.
572 mmesa
->sarea
->dirty
|= MGA_UPLOAD_CONTEXT
;
577 if (nbox
>= MGA_NR_SAREA_CLIPRECTS
)
578 mmesa
->dirty
|= MGA_UPLOAD_CLIPRECTS
;
581 if (!buffer
->used
|| !(mmesa
->dirty
& MGA_UPLOAD_CLIPRECTS
))
584 mmesa
->sarea
->nbox
= 0;
586 mmesa
->sarea
->nbox
= nbox
;
588 if (MGA_DEBUG
&DEBUG_VERBOSE_IOCTL
)
589 fprintf(stderr
, "Firing vertex -- case a nbox %d\n", nbox
);
591 vertex
.idx
= buffer
->idx
;
592 vertex
.used
= buffer
->used
;
594 drmCommandWrite( mmesa
->driFd
, DRM_MGA_VERTEX
,
595 &vertex
, sizeof(drmMGAVertex
) );
597 age_mmesa(mmesa
, mmesa
->sarea
->last_enqueue
);
602 for (i
= 0 ; i
< nbox
; )
604 int nr
= MIN2(i
+ MGA_NR_SAREA_CLIPRECTS
, nbox
);
605 drm_clip_rect_t
*b
= mmesa
->sarea
->boxes
;
608 if (mmesa
->scissor
) {
609 mmesa
->sarea
->nbox
= 0;
611 for ( ; i
< nr
; i
++) {
613 if (intersect_rect(b
, b
, &mmesa
->scissor_rect
)) {
614 mmesa
->sarea
->nbox
++;
621 if (!mmesa
->sarea
->nbox
) {
622 if (nr
< nbox
) continue;
626 mmesa
->sarea
->nbox
= nr
- i
;
627 for ( ; i
< nr
; i
++)
631 /* Finished with the buffer?
636 mmesa
->sarea
->dirty
|= MGA_UPLOAD_CLIPRECTS
;
638 vertex
.idx
= buffer
->idx
;
639 vertex
.used
= buffer
->used
;
640 vertex
.discard
= discard
;
641 drmCommandWrite( mmesa
->driFd
, DRM_MGA_VERTEX
,
642 &vertex
, sizeof(vertex
) );
644 age_mmesa(mmesa
, mmesa
->sarea
->last_enqueue
);
648 mmesa
->dirty
&= ~MGA_UPLOAD_CLIPRECTS
;
651 void mgaFlushVertices( mgaContextPtr mmesa
)
653 LOCK_HARDWARE( mmesa
);
654 mgaFlushVerticesLocked( mmesa
);
655 UNLOCK_HARDWARE( mmesa
);
659 void mgaFireILoadLocked( mgaContextPtr mmesa
,
660 GLuint offset
, GLuint length
)
662 if (!mmesa
->iload_buffer
) {
663 fprintf(stderr
, "mgaFireILoad: no buffer\n");
667 if (MGA_DEBUG
&DEBUG_VERBOSE_IOCTL
)
668 fprintf(stderr
, "mgaFireILoad idx %d ofs 0x%x length %d\n",
669 mmesa
->iload_buffer
->idx
, (int)offset
, (int)length
);
671 mga_iload_dma_ioctl( mmesa
, offset
, length
);
674 void mgaGetILoadBufferLocked( mgaContextPtr mmesa
)
676 if (MGA_DEBUG
&DEBUG_VERBOSE_IOCTL
)
677 fprintf(stderr
, "mgaGetIloadBuffer (buffer now %p)\n",
678 (void *) mmesa
->iload_buffer
);
680 mmesa
->iload_buffer
= mga_get_buffer_ioctl( mmesa
);
685 * Implement the hardware-specific portion of \c glFlush.
687 * \param ctx Context to be flushed.
689 * \sa glFlush, mgaFinish, mgaFlushDMA
691 static void mgaFlush( GLcontext
*ctx
)
693 mgaContextPtr mmesa
= MGA_CONTEXT( ctx
);
696 LOCK_HARDWARE( mmesa
);
697 if ( mmesa
->vertex_dma_buffer
!= NULL
) {
698 mgaFlushVerticesLocked( mmesa
);
701 UPDATE_LOCK( mmesa
, DRM_LOCK_FLUSH
);
702 UNLOCK_HARDWARE( mmesa
);
706 int mgaFlushDMA( int fd
, drmLockFlags flags
)
711 memset( &lock
, 0, sizeof(lock
) );
713 lock
.flags
= flags
& (DRM_LOCK_QUIESCENT
| DRM_LOCK_FLUSH
714 | DRM_LOCK_FLUSH_ALL
);
717 ret
= drmCommandWrite( fd
, DRM_MGA_FLUSH
, &lock
, sizeof(lock
) );
718 } while ( ret
&& errno
== EBUSY
&& i
++ < DRM_MGA_IDLE_RETRY
);
722 if ( errno
!= EBUSY
)
725 if ( lock
.flags
& DRM_LOCK_QUIESCENT
) {
726 /* Only keep trying if we need quiescence.
728 lock
.flags
&= ~(DRM_LOCK_FLUSH
| DRM_LOCK_FLUSH_ALL
);
731 ret
= drmCommandWrite( fd
, DRM_MGA_FLUSH
, &lock
, sizeof(lock
) );
732 } while ( ret
&& errno
== EBUSY
&& i
++ < DRM_MGA_IDLE_RETRY
);
742 void mgaInitIoctlFuncs( struct dd_function_table
*functions
)
744 functions
->Clear
= mgaClear
;
745 functions
->Flush
= mgaFlush
;
746 functions
->Finish
= mgaFinish
;