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"
39 #include "mgacontext.h"
50 static void mga_iload_dma_ioctl(mgaContextPtr mmesa
,
54 drmBufPtr buf
= mmesa
->iload_buffer
;
55 drm_mga_iload_t iload
;
58 if (MGA_DEBUG
&DEBUG_VERBOSE_IOCTL
)
59 fprintf(stderr
, "DRM_IOCTL_MGA_ILOAD idx %d dst %x length %d\n",
60 buf
->idx
, (int) dest
, length
);
62 if ( (length
& MGA_ILOAD_MASK
) != 0 ) {
63 UNLOCK_HARDWARE( mmesa
);
64 fprintf( stderr
, "%s: Invalid ILOAD datasize (%d), must be "
65 "multiple of %u.\n", __FUNCTION__
, length
, MGA_ILOAD_ALIGN
);
71 iload
.length
= length
;
75 ret
= drmCommandWrite( mmesa
->driFd
, DRM_MGA_ILOAD
,
76 &iload
, sizeof(iload
) );
77 } while ( ret
== -EBUSY
&& i
++ < DRM_MGA_IDLE_RETRY
);
80 printf("send iload retcode = %d\n", ret
);
84 mmesa
->iload_buffer
= 0;
86 if (MGA_DEBUG
&DEBUG_VERBOSE_IOCTL
)
87 fprintf(stderr
, "finished iload dma put\n");
91 drmBufPtr
mga_get_buffer_ioctl( mgaContextPtr mmesa
)
99 if (MGA_DEBUG
&DEBUG_VERBOSE_IOCTL
)
100 fprintf(stderr
, "Getting dma buffer\n");
102 dma
.context
= mmesa
->hHWContext
;
104 dma
.send_list
= NULL
;
105 dma
.send_sizes
= NULL
;
107 dma
.request_count
= 1;
108 dma
.request_size
= MGA_BUFFER_SIZE
;
109 dma
.request_list
= &idx
;
110 dma
.request_sizes
= &size
;
111 dma
.granted_count
= 0;
114 if (MGA_DEBUG
&DEBUG_VERBOSE_IOCTL
)
115 fprintf(stderr
, "drmDMA (get) ctx %d count %d size 0x%x\n",
116 dma
.context
, dma
.request_count
,
120 retcode
= drmDMA(mmesa
->driFd
, &dma
);
122 if (MGA_DEBUG
&DEBUG_VERBOSE_IOCTL
)
123 fprintf(stderr
, "retcode %d sz %d idx %d count %d\n",
125 dma
.request_sizes
[0],
130 dma
.request_sizes
[0] &&
134 if (MGA_DEBUG
&DEBUG_VERBOSE_IOCTL
)
135 fprintf(stderr
, "\n\nflush");
137 UPDATE_LOCK( mmesa
, DRM_LOCK_FLUSH
| DRM_LOCK_QUIESCENT
);
140 buf
= &(mmesa
->mgaScreen
->bufs
->list
[idx
]);
143 if (MGA_DEBUG
&DEBUG_VERBOSE_IOCTL
)
145 "drmDMA (get) returns size[0] 0x%x idx[0] %d\n"
146 "dma_buffer now: buf idx: %d size: %d used: %d addr %p\n",
147 dma
.request_sizes
[0], dma
.request_list
[0],
148 buf
->idx
, buf
->total
,
149 buf
->used
, buf
->address
);
151 if (MGA_DEBUG
&DEBUG_VERBOSE_IOCTL
)
152 fprintf(stderr
, "finished getbuffer\n");
161 mgaClear( GLcontext
*ctx
, GLbitfield mask
, GLboolean all
,
162 GLint cx
, GLint cy
, GLint cw
, GLint ch
)
164 mgaContextPtr mmesa
= MGA_CONTEXT(ctx
);
165 __DRIdrawablePrivate
*dPriv
= mmesa
->driDrawable
;
167 GLuint clear_color
= mmesa
->ClearColor
;
168 GLuint clear_depth
= 0;
169 GLuint color_mask
= 0;
170 GLuint depth_mask
= 0;
174 drm_mga_clear_t clear
;
176 FLUSH_BATCH( mmesa
);
178 if ( mask
& DD_FRONT_LEFT_BIT
) {
180 color_mask
= mmesa
->setup
.plnwt
;
181 mask
&= ~DD_FRONT_LEFT_BIT
;
184 if ( mask
& DD_BACK_LEFT_BIT
) {
186 color_mask
= mmesa
->setup
.plnwt
;
187 mask
&= ~DD_BACK_LEFT_BIT
;
190 if ( (mask
& DD_DEPTH_BIT
) && ctx
->Depth
.Mask
) {
192 clear_depth
= (mmesa
->ClearDepth
& mmesa
->depth_clear_mask
);
193 depth_mask
|= mmesa
->depth_clear_mask
;
194 mask
&= ~DD_DEPTH_BIT
;
197 if ( (mask
& DD_STENCIL_BIT
) && mmesa
->hw_stencil
) {
199 clear_depth
|= (ctx
->Stencil
.Clear
& mmesa
->stencil_clear_mask
);
200 depth_mask
|= mmesa
->stencil_clear_mask
;
201 mask
&= ~DD_STENCIL_BIT
;
205 LOCK_HARDWARE( mmesa
);
207 if ( mmesa
->dirty_cliprects
)
208 mgaUpdateRects( mmesa
, (MGA_FRONT
| MGA_BACK
) );
210 /* flip top to bottom */
215 if ( MGA_DEBUG
& DEBUG_VERBOSE_IOCTL
)
216 fprintf( stderr
, "Clear, bufs %x nbox %d\n",
217 (int)flags
, (int)mmesa
->numClipRects
);
219 for (i
= 0 ; i
< mmesa
->numClipRects
; )
221 int nr
= MIN2(i
+ MGA_NR_SAREA_CLIPRECTS
, mmesa
->numClipRects
);
222 drm_clip_rect_t
*box
= mmesa
->pClipRects
;
223 drm_clip_rect_t
*b
= mmesa
->sarea
->boxes
;
227 for ( ; i
< nr
; i
++) {
230 GLint w
= box
[i
].x2
- x
;
231 GLint h
= box
[i
].y2
- y
;
233 if (x
< cx
) w
-= cx
- x
, x
= cx
;
234 if (y
< cy
) h
-= cy
- y
, y
= cy
;
235 if (x
+ w
> cx
+ cw
) w
= cx
+ cw
- x
;
236 if (y
+ h
> cy
+ ch
) h
= cy
+ ch
- y
;
237 if (w
<= 0) continue;
238 if (h
<= 0) continue;
248 for ( ; i
< nr
; i
++) {
255 if ( MGA_DEBUG
& DEBUG_VERBOSE_IOCTL
)
257 "DRM_IOCTL_MGA_CLEAR flag 0x%x color %x depth %x nbox %d\n",
258 flags
, clear_color
, clear_depth
, mmesa
->sarea
->nbox
);
260 mmesa
->sarea
->nbox
= n
;
263 clear
.clear_color
= clear_color
;
264 clear
.clear_depth
= clear_depth
;
265 clear
.color_mask
= color_mask
;
266 clear
.depth_mask
= depth_mask
;
267 ret
= drmCommandWrite( mmesa
->driFd
, DRM_MGA_CLEAR
,
268 &clear
, sizeof(clear
));
270 fprintf( stderr
, "send clear retcode = %d\n", ret
);
273 if ( MGA_DEBUG
& DEBUG_VERBOSE_IOCTL
)
274 fprintf( stderr
, "finished clear %d\n", ++nrclears
);
277 UNLOCK_HARDWARE( mmesa
);
278 mmesa
->dirty
|= MGA_UPLOAD_CLIPRECTS
|MGA_UPLOAD_CONTEXT
;
282 _swrast_Clear( ctx
, mask
, all
, cx
, cy
, cw
, ch
);
286 static void mgaWaitForFrameCompletion( mgaContextPtr mmesa
)
289 GLuint last_frame
, last_wrap
;
292 last_frame
= mmesa
->sarea
->last_frame
.head
;
293 last_wrap
= mmesa
->sarea
->last_frame
.wrap
;
295 /* FIXME: Add a timeout to this loop...
298 if ( last_wrap
< mmesa
->sarea
->last_wrap
||
299 ( last_wrap
== mmesa
->sarea
->last_wrap
&&
300 last_frame
<= (MGA_READ( MGAREG_PRIMADDRESS
) -
301 mmesa
->primary_offset
) ) ) {
306 fprintf( stderr
, " last: head=0x%06x wrap=%d\n",
307 last_frame
, last_wrap
);
308 fprintf( stderr
, " head: head=0x%06lx wrap=%d\n",
309 (long)(MGA_READ( MGAREG_PRIMADDRESS
) - mmesa
->primary_offset
),
310 mmesa
->sarea
->last_wrap
);
312 UPDATE_LOCK( mmesa
, DRM_LOCK_FLUSH
);
314 UNLOCK_HARDWARE( mmesa
);
316 LOCK_HARDWARE( mmesa
);
319 fprintf( stderr
, "\n" );
324 * Copy the back buffer to the front buffer.
326 void mgaCopyBuffer( const __DRIdrawablePrivate
*dPriv
)
329 drm_clip_rect_t
*pbox
;
333 GLboolean missed_target
;
337 assert(dPriv
->driContextPriv
);
338 assert(dPriv
->driContextPriv
->driverPrivate
);
340 mmesa
= (mgaContextPtr
) dPriv
->driContextPriv
->driverPrivate
;
342 FLUSH_BATCH( mmesa
);
344 LOCK_HARDWARE( mmesa
);
345 mgaWaitForFrameCompletion( mmesa
);
346 UNLOCK_HARDWARE( mmesa
);
347 driWaitForVBlank( dPriv
, & mmesa
->vbl_seq
, mmesa
->vblank_flags
,
349 if ( missed_target
) {
350 mmesa
->swap_missed_count
++;
351 (void) (*mmesa
->get_ust
)( & mmesa
->swap_missed_ust
);
353 LOCK_HARDWARE( mmesa
);
355 /* Use the frontbuffer cliprects
357 if (mmesa
->dirty_cliprects
& MGA_FRONT
)
358 mgaUpdateRects( mmesa
, MGA_FRONT
);
361 pbox
= dPriv
->pClipRects
;
362 nbox
= dPriv
->numClipRects
;
364 for (i
= 0 ; i
< nbox
; )
366 int nr
= MIN2(i
+ MGA_NR_SAREA_CLIPRECTS
, dPriv
->numClipRects
);
367 drm_clip_rect_t
*b
= mmesa
->sarea
->boxes
;
369 mmesa
->sarea
->nbox
= nr
- i
;
371 for ( ; i
< nr
; i
++)
375 fprintf(stderr
, "DRM_IOCTL_MGA_SWAP\n");
377 ret
= drmCommandNone( mmesa
->driFd
, DRM_MGA_SWAP
);
379 printf("send swap retcode = %d\n", ret
);
384 UNLOCK_HARDWARE( mmesa
);
386 mmesa
->dirty
|= MGA_UPLOAD_CLIPRECTS
;
388 (void) (*mmesa
->get_ust
)( & mmesa
->swap_ust
);
394 static void mgaFinish( GLcontext
*ctx
)
396 mgaContextPtr mmesa
= MGA_CONTEXT(ctx
);
398 FLUSH_BATCH( mmesa
);
400 if (1/*mmesa->sarea->last_quiescent != mmesa->sarea->last_enqueue*/) {
401 if (MGA_DEBUG
&DEBUG_VERBOSE_IOCTL
)
402 fprintf(stderr
, "mgaRegetLockQuiescent\n");
404 LOCK_HARDWARE( mmesa
);
405 UPDATE_LOCK( mmesa
, DRM_LOCK_QUIESCENT
| DRM_LOCK_FLUSH
);
406 UNLOCK_HARDWARE( mmesa
);
408 mmesa
->sarea
->last_quiescent
= mmesa
->sarea
->last_enqueue
;
412 void mgaWaitAgeLocked( mgaContextPtr mmesa
, int age
)
414 if (GET_DISPATCH_AGE(mmesa
) < age
) {
415 UPDATE_LOCK( mmesa
, DRM_LOCK_FLUSH
);
420 void mgaWaitAge( mgaContextPtr mmesa
, int age
)
422 if (GET_DISPATCH_AGE(mmesa
) < age
) {
423 LOCK_HARDWARE(mmesa
);
424 if (GET_DISPATCH_AGE(mmesa
) < age
) {
425 UPDATE_LOCK( mmesa
, DRM_LOCK_FLUSH
);
427 UNLOCK_HARDWARE(mmesa
);
432 static GLboolean
intersect_rect( drm_clip_rect_t
*out
,
433 const drm_clip_rect_t
*a
,
434 const drm_clip_rect_t
*b
)
437 if (b
->x1
> out
->x1
) out
->x1
= b
->x1
;
438 if (b
->y1
> out
->y1
) out
->y1
= b
->y1
;
439 if (b
->x2
< out
->x2
) out
->x2
= b
->x2
;
440 if (b
->y2
< out
->y2
) out
->y2
= b
->y2
;
442 return ((out
->x1
< out
->x2
) && (out
->y1
< out
->y2
));
448 static void age_mmesa( mgaContextPtr mmesa
, int age
)
450 if (mmesa
->CurrentTexObj
[0]) mmesa
->CurrentTexObj
[0]->age
= age
;
451 if (mmesa
->CurrentTexObj
[1]) mmesa
->CurrentTexObj
[1]->age
= age
;
455 static int __break_vertex
= 0;
458 void mgaFlushVerticesLocked( mgaContextPtr mmesa
)
460 drm_clip_rect_t
*pbox
= mmesa
->pClipRects
;
461 int nbox
= mmesa
->numClipRects
;
462 drmBufPtr buffer
= mmesa
->vertex_dma_buffer
;
463 drm_mga_vertex_t vertex
;
466 mmesa
->vertex_dma_buffer
= 0;
471 if (mmesa
->dirty_cliprects
& mmesa
->draw_buffer
)
472 mgaUpdateRects( mmesa
, mmesa
->draw_buffer
);
474 if (mmesa
->dirty
& ~MGA_UPLOAD_CLIPRECTS
)
475 mgaEmitHwStateLocked( mmesa
);
477 /* FIXME: Workaround bug in kernel module.
479 mmesa
->sarea
->dirty
|= MGA_UPLOAD_CONTEXT
;
484 if (nbox
>= MGA_NR_SAREA_CLIPRECTS
)
485 mmesa
->dirty
|= MGA_UPLOAD_CLIPRECTS
;
488 if (!buffer
->used
|| !(mmesa
->dirty
& MGA_UPLOAD_CLIPRECTS
))
491 mmesa
->sarea
->nbox
= 0;
493 mmesa
->sarea
->nbox
= nbox
;
495 if (MGA_DEBUG
&DEBUG_VERBOSE_IOCTL
)
496 fprintf(stderr
, "Firing vertex -- case a nbox %d\n", nbox
);
498 vertex
.idx
= buffer
->idx
;
499 vertex
.used
= buffer
->used
;
501 drmCommandWrite( mmesa
->driFd
, DRM_MGA_VERTEX
,
502 &vertex
, sizeof(drmMGAVertex
) );
504 age_mmesa(mmesa
, mmesa
->sarea
->last_enqueue
);
509 for (i
= 0 ; i
< nbox
; )
511 int nr
= MIN2(i
+ MGA_NR_SAREA_CLIPRECTS
, nbox
);
512 drm_clip_rect_t
*b
= mmesa
->sarea
->boxes
;
515 if (mmesa
->scissor
) {
516 mmesa
->sarea
->nbox
= 0;
518 for ( ; i
< nr
; i
++) {
520 if (intersect_rect(b
, b
, &mmesa
->scissor_rect
)) {
521 mmesa
->sarea
->nbox
++;
528 if (!mmesa
->sarea
->nbox
) {
529 if (nr
< nbox
) continue;
533 mmesa
->sarea
->nbox
= nr
- i
;
534 for ( ; i
< nr
; i
++)
538 /* Finished with the buffer?
543 mmesa
->sarea
->dirty
|= MGA_UPLOAD_CLIPRECTS
;
545 vertex
.idx
= buffer
->idx
;
546 vertex
.used
= buffer
->used
;
547 vertex
.discard
= discard
;
548 drmCommandWrite( mmesa
->driFd
, DRM_MGA_VERTEX
,
549 &vertex
, sizeof(vertex
) );
551 age_mmesa(mmesa
, mmesa
->sarea
->last_enqueue
);
555 /* Do we really need to do this ? */
557 if ( __break_vertex
) {
558 __asm__
__volatile__ ( "int $3" );
562 mmesa
->dirty
&= ~MGA_UPLOAD_CLIPRECTS
;
565 void mgaFlushVertices( mgaContextPtr mmesa
)
567 LOCK_HARDWARE( mmesa
);
568 mgaFlushVerticesLocked( mmesa
);
569 UNLOCK_HARDWARE( mmesa
);
573 void mgaFireILoadLocked( mgaContextPtr mmesa
,
574 GLuint offset
, GLuint length
)
576 if (!mmesa
->iload_buffer
) {
577 fprintf(stderr
, "mgaFireILoad: no buffer\n");
581 if (MGA_DEBUG
&DEBUG_VERBOSE_IOCTL
)
582 fprintf(stderr
, "mgaFireILoad idx %d ofs 0x%x length %d\n",
583 mmesa
->iload_buffer
->idx
, (int)offset
, (int)length
);
585 mga_iload_dma_ioctl( mmesa
, offset
, length
);
588 void mgaGetILoadBufferLocked( mgaContextPtr mmesa
)
590 if (MGA_DEBUG
&DEBUG_VERBOSE_IOCTL
)
591 fprintf(stderr
, "mgaGetIloadBuffer (buffer now %p)\n",
592 (void *) mmesa
->iload_buffer
);
594 mmesa
->iload_buffer
= mga_get_buffer_ioctl( mmesa
);
597 drmBufPtr
mgaGetBufferLocked( mgaContextPtr mmesa
)
599 return mga_get_buffer_ioctl( mmesa
);
604 static void mgaFlush( GLcontext
*ctx
)
606 mgaContextPtr mmesa
= MGA_CONTEXT( ctx
);
609 FLUSH_BATCH( mmesa
);
611 /* This may be called redundantly - dispatch_age may trail what
612 * has actually been sent and processed by the hardware.
614 if (1 || GET_DISPATCH_AGE( mmesa
) < mmesa
->sarea
->last_enqueue
) {
615 LOCK_HARDWARE( mmesa
);
616 UPDATE_LOCK( mmesa
, DRM_LOCK_FLUSH
);
617 UNLOCK_HARDWARE( mmesa
);
624 void mgaReleaseBufLocked( mgaContextPtr mmesa
, drmBufPtr buffer
)
626 drm_mga_vertex_t vertex
;
630 vertex
.idx
= buffer
->idx
;
633 drmCommandWrite( mmesa
->driFd
, DRM_MGA_VERTEX
,
634 &vertex
, sizeof(vertex
) );
637 int mgaFlushDMA( int fd
, drmLockFlags flags
)
642 memset( &lock
, 0, sizeof(lock
) );
644 if ( flags
& DRM_LOCK_QUIESCENT
) lock
.flags
|= DRM_LOCK_QUIESCENT
;
645 if ( flags
& DRM_LOCK_FLUSH
) lock
.flags
|= DRM_LOCK_FLUSH
;
646 if ( flags
& DRM_LOCK_FLUSH_ALL
) lock
.flags
|= DRM_LOCK_FLUSH_ALL
;
649 ret
= drmCommandWrite( fd
, DRM_MGA_FLUSH
, &lock
, sizeof(lock
) );
650 } while ( ret
&& errno
== EBUSY
&& i
++ < DRM_MGA_IDLE_RETRY
);
654 if ( errno
!= EBUSY
)
657 if ( lock
.flags
& DRM_LOCK_QUIESCENT
) {
658 /* Only keep trying if we need quiescence.
660 lock
.flags
&= ~(DRM_LOCK_FLUSH
| DRM_LOCK_FLUSH_ALL
);
663 ret
= drmCommandWrite( fd
, DRM_MGA_FLUSH
, &lock
, sizeof(lock
) );
664 } while ( ret
&& errno
== EBUSY
&& i
++ < DRM_MGA_IDLE_RETRY
);
674 void mgaInitIoctlFuncs( struct dd_function_table
*functions
)
676 functions
->Clear
= mgaClear
;
677 functions
->Flush
= mgaFlush
;
678 functions
->Finish
= mgaFinish
;