Merge commit 'origin/gallium-0.1'
[mesa.git] / src / mesa / drivers / dri / mga / mgaioctl.c
1 /*
2 * Copyright 2000-2001 VA Linux Systems, Inc.
3 * All Rights Reserved.
4 *
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:
11 *
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
14 * Software.
15 *
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.
23 */
24
25 /**
26 * \file mgaioctl.c
27 * MGA IOCTL related wrapper functions.
28 *
29 * \author Keith Whitwell <keith@tungstengraphics.com>
30 * \author Gareth Hughes <gareth@valinux.com>
31 */
32
33 #include <errno.h>
34 #include "main/mtypes.h"
35 #include "main/macros.h"
36 #include "main/dd.h"
37 #include "swrast/swrast.h"
38
39 #include "main/mm.h"
40 #include "drm.h"
41 #include "mga_drm.h"
42 #include "mgacontext.h"
43 #include "mgadd.h"
44 #include "mgastate.h"
45 #include "mgatex.h"
46 #include "mgavb.h"
47 #include "mgaioctl.h"
48 #include "mgatris.h"
49
50 #include "vblank.h"
51
52
53 static int
54 mgaSetFence( mgaContextPtr mmesa, uint32_t * fence )
55 {
56 int ret = ENOSYS;
57
58 if ( mmesa->driScreen->drm_version.minor >= 2 ) {
59 ret = drmCommandWriteRead( mmesa->driScreen->fd, DRM_MGA_SET_FENCE,
60 fence, sizeof( uint32_t ));
61 if (ret) {
62 fprintf(stderr, "drmMgaSetFence: %d\n", ret);
63 exit(1);
64 }
65 }
66
67 return ret;
68 }
69
70
71 static int
72 mgaWaitFence( mgaContextPtr mmesa, uint32_t fence, uint32_t * curr_fence )
73 {
74 int ret = ENOSYS;
75
76 if ( mmesa->driScreen->drm_version.minor >= 2 ) {
77 uint32_t temp = fence;
78
79 ret = drmCommandWriteRead( mmesa->driScreen->fd,
80 DRM_MGA_WAIT_FENCE,
81 & temp, sizeof( uint32_t ));
82 if (ret) {
83 fprintf(stderr, "drmMgaSetFence: %d\n", ret);
84 exit(1);
85 }
86
87 if ( curr_fence ) {
88 *curr_fence = temp;
89 }
90 }
91
92 return ret;
93 }
94
95
96 static void mga_iload_dma_ioctl(mgaContextPtr mmesa,
97 unsigned long dest,
98 int length)
99 {
100 drmBufPtr buf = mmesa->iload_buffer;
101 drm_mga_iload_t iload;
102 int ret, i;
103
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);
107
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 );
112 exit( 1 );
113 }
114
115 iload.idx = buf->idx;
116 iload.dstorg = dest;
117 iload.length = length;
118
119 i = 0;
120 do {
121 ret = drmCommandWrite( mmesa->driFd, DRM_MGA_ILOAD,
122 &iload, sizeof(iload) );
123 } while ( ret == -EBUSY && i++ < DRM_MGA_IDLE_RETRY );
124
125 if ( ret < 0 ) {
126 printf("send iload retcode = %d\n", ret);
127 exit(1);
128 }
129
130 mmesa->iload_buffer = 0;
131
132 if (MGA_DEBUG&DEBUG_VERBOSE_IOCTL)
133 fprintf(stderr, "finished iload dma put\n");
134
135 }
136
137 drmBufPtr mga_get_buffer_ioctl( mgaContextPtr mmesa )
138 {
139 int idx = 0;
140 int size = 0;
141 drmDMAReq dma;
142 int retcode;
143 drmBufPtr buf;
144
145 if (MGA_DEBUG&DEBUG_VERBOSE_IOCTL)
146 fprintf(stderr, "Getting dma buffer\n");
147
148 dma.context = mmesa->hHWContext;
149 dma.send_count = 0;
150 dma.send_list = NULL;
151 dma.send_sizes = NULL;
152 dma.flags = 0;
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;
158
159
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,
163 dma.request_size);
164
165 while (1) {
166 retcode = drmDMA(mmesa->driFd, &dma);
167
168 if (MGA_DEBUG&DEBUG_VERBOSE_IOCTL)
169 fprintf(stderr, "retcode %d sz %d idx %d count %d\n",
170 retcode,
171 dma.request_sizes[0],
172 dma.request_list[0],
173 dma.granted_count);
174
175 if (retcode == 0 &&
176 dma.request_sizes[0] &&
177 dma.granted_count)
178 break;
179
180 if (MGA_DEBUG&DEBUG_VERBOSE_IOCTL)
181 fprintf(stderr, "\n\nflush");
182
183 UPDATE_LOCK( mmesa, DRM_LOCK_FLUSH | DRM_LOCK_QUIESCENT );
184 }
185
186 buf = &(mmesa->mgaScreen->bufs->list[idx]);
187 buf->used = 0;
188
189 if (MGA_DEBUG&DEBUG_VERBOSE_IOCTL)
190 fprintf(stderr,
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);
196
197 if (MGA_DEBUG&DEBUG_VERBOSE_IOCTL)
198 fprintf(stderr, "finished getbuffer\n");
199
200 return buf;
201 }
202
203
204
205
206 static void
207 mgaClear( GLcontext *ctx, GLbitfield mask )
208 {
209 mgaContextPtr mmesa = MGA_CONTEXT(ctx);
210 __DRIdrawablePrivate *dPriv = mmesa->driDrawable;
211 GLuint flags = 0;
212 GLuint clear_color = mmesa->ClearColor;
213 GLuint clear_depth = 0;
214 GLuint color_mask = 0;
215 GLuint depth_mask = 0;
216 int ret;
217 int i;
218 static int nrclears;
219 drm_mga_clear_t clear;
220 GLint cx, cy, cw, ch;
221
222 FLUSH_BATCH( mmesa );
223
224 if ( mask & BUFFER_BIT_FRONT_LEFT ) {
225 flags |= MGA_FRONT;
226 color_mask = mmesa->setup.plnwt;
227 mask &= ~BUFFER_BIT_FRONT_LEFT;
228 }
229
230 if ( mask & BUFFER_BIT_BACK_LEFT ) {
231 flags |= MGA_BACK;
232 color_mask = mmesa->setup.plnwt;
233 mask &= ~BUFFER_BIT_BACK_LEFT;
234 }
235
236 if ( (mask & BUFFER_BIT_DEPTH) && ctx->Depth.Mask ) {
237 flags |= MGA_DEPTH;
238 clear_depth = (mmesa->ClearDepth & mmesa->depth_clear_mask);
239 depth_mask |= mmesa->depth_clear_mask;
240 mask &= ~BUFFER_BIT_DEPTH;
241 }
242
243 if ( (mask & BUFFER_BIT_STENCIL) && mmesa->hw_stencil ) {
244 flags |= MGA_DEPTH;
245 clear_depth |= (ctx->Stencil.Clear & mmesa->stencil_clear_mask);
246 depth_mask |= mmesa->stencil_clear_mask;
247 mask &= ~BUFFER_BIT_STENCIL;
248 }
249
250 if ( flags ) {
251 LOCK_HARDWARE( mmesa );
252
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;
258
259 if ( mmesa->dirty_cliprects )
260 mgaUpdateRects( mmesa, (MGA_FRONT | MGA_BACK) );
261
262 /* flip top to bottom */
263 cy = dPriv->h-cy-ch;
264 cx += mmesa->drawX;
265 cy += mmesa->drawY;
266
267 if ( MGA_DEBUG & DEBUG_VERBOSE_IOCTL )
268 fprintf( stderr, "Clear, bufs %x nbox %d\n",
269 (int)flags, (int)mmesa->numClipRects );
270
271 for (i = 0 ; i < mmesa->numClipRects ; )
272 {
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;
276 int n = 0;
277
278 if (cw != dPriv->w || ch != dPriv->h) {
279 /* clear subregion */
280 for ( ; i < nr ; i++) {
281 GLint x = box[i].x1;
282 GLint y = box[i].y1;
283 GLint w = box[i].x2 - x;
284 GLint h = box[i].y2 - y;
285
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;
292
293 b->x1 = x;
294 b->y1 = y;
295 b->x2 = x + w;
296 b->y2 = y + h;
297 b++;
298 n++;
299 }
300 } else {
301 /* clear whole window */
302 for ( ; i < nr ; i++) {
303 *b++ = box[i];
304 n++;
305 }
306 }
307
308
309 if ( MGA_DEBUG & DEBUG_VERBOSE_IOCTL )
310 fprintf( stderr,
311 "DRM_IOCTL_MGA_CLEAR flag 0x%x color %x depth %x nbox %d\n",
312 flags, clear_color, clear_depth, mmesa->sarea->nbox );
313
314 mmesa->sarea->nbox = n;
315
316 clear.flags = flags;
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));
323 if ( ret ) {
324 fprintf( stderr, "send clear retcode = %d\n", ret );
325 exit( 1 );
326 }
327 if ( MGA_DEBUG & DEBUG_VERBOSE_IOCTL )
328 fprintf( stderr, "finished clear %d\n", ++nrclears );
329 }
330
331 UNLOCK_HARDWARE( mmesa );
332 mmesa->dirty |= MGA_UPLOAD_CLIPRECTS|MGA_UPLOAD_CONTEXT;
333 }
334
335 if (mask)
336 _swrast_Clear( ctx, mask );
337 }
338
339
340 /**
341 * Wait for the previous frame of rendering has completed.
342 *
343 * \param mmesa Hardware context pointer.
344 *
345 * \bug
346 * The loop in this function should have some sort of a timeout mechanism.
347 *
348 * \warning
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.
351 */
352
353 static void mgaWaitForFrameCompletion( mgaContextPtr mmesa )
354 {
355 if ( mgaWaitFence( mmesa, mmesa->last_frame_fence, NULL ) == ENOSYS ) {
356 unsigned wait = 0;
357 GLuint last_frame;
358 GLuint last_wrap;
359
360
361 LOCK_HARDWARE( mmesa );
362 last_frame = mmesa->sarea->last_frame.head;
363 last_wrap = mmesa->sarea->last_frame.wrap;
364
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.
370 *
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.
375 *
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.
379 */
380 while ( 1 ) {
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) ) ) {
385 break;
386 }
387 if ( 0 ) {
388 wait++;
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 );
394 }
395 UPDATE_LOCK( mmesa, DRM_LOCK_FLUSH );
396
397 UNLOCK_HARDWARE( mmesa );
398 DO_USLEEP( 1 );
399 LOCK_HARDWARE( mmesa );
400 }
401 if ( wait )
402 fprintf( stderr, "\n" );
403
404 UNLOCK_HARDWARE( mmesa );
405 }
406 }
407
408
409 /*
410 * Copy the back buffer to the front buffer.
411 */
412 void mgaCopyBuffer( __DRIdrawablePrivate *dPriv )
413 {
414 mgaContextPtr mmesa;
415 drm_clip_rect_t *pbox;
416 GLint nbox;
417 GLint ret;
418 GLint i;
419 GLboolean missed_target;
420 __DRIscreenPrivate *psp = dPriv->driScreenPriv;
421
422 assert(dPriv);
423 assert(dPriv->driContextPriv);
424 assert(dPriv->driContextPriv->driverPrivate);
425
426 mmesa = (mgaContextPtr) dPriv->driContextPriv->driverPrivate;
427
428 FLUSH_BATCH( mmesa );
429
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 );
435 }
436 LOCK_HARDWARE( mmesa );
437
438 /* Use the frontbuffer cliprects
439 */
440 if (mmesa->dirty_cliprects & MGA_FRONT)
441 mgaUpdateRects( mmesa, MGA_FRONT );
442
443
444 pbox = dPriv->pClipRects;
445 nbox = dPriv->numClipRects;
446
447 for (i = 0 ; i < nbox ; )
448 {
449 int nr = MIN2(i + MGA_NR_SAREA_CLIPRECTS, dPriv->numClipRects);
450 drm_clip_rect_t *b = mmesa->sarea->boxes;
451
452 mmesa->sarea->nbox = nr - i;
453
454 for ( ; i < nr ; i++)
455 *b++ = pbox[i];
456
457 if (0)
458 fprintf(stderr, "DRM_IOCTL_MGA_SWAP\n");
459
460 ret = drmCommandNone( mmesa->driFd, DRM_MGA_SWAP );
461 if ( ret ) {
462 printf("send swap retcode = %d\n", ret);
463 exit(1);
464 }
465 }
466
467 (void) mgaSetFence( mmesa, & mmesa->last_frame_fence );
468 UNLOCK_HARDWARE( mmesa );
469
470 mmesa->dirty |= MGA_UPLOAD_CLIPRECTS;
471 mmesa->swap_count++;
472 (void) (*psp->systemTime->getUST)( & mmesa->swap_ust );
473 }
474
475
476 /**
477 * Implement the hardware-specific portion of \c glFinish.
478 *
479 * Flushes all pending commands to the hardware and wait for them to finish.
480 *
481 * \param ctx Context where the \c glFinish command was issued.
482 *
483 * \sa glFinish, mgaFlush, mgaFlushDMA
484 */
485 static void mgaFinish( GLcontext *ctx )
486 {
487 mgaContextPtr mmesa = MGA_CONTEXT(ctx);
488 uint32_t fence;
489
490
491 LOCK_HARDWARE( mmesa );
492 if ( mmesa->vertex_dma_buffer != NULL ) {
493 mgaFlushVerticesLocked( mmesa );
494 }
495
496 if ( mgaSetFence( mmesa, & fence ) == 0 ) {
497 UNLOCK_HARDWARE( mmesa );
498 (void) mgaWaitFence( mmesa, fence, NULL );
499 }
500 else {
501 if (MGA_DEBUG&DEBUG_VERBOSE_IOCTL) {
502 fprintf(stderr, "mgaRegetLockQuiescent\n");
503 }
504
505 UPDATE_LOCK( mmesa, DRM_LOCK_QUIESCENT | DRM_LOCK_FLUSH );
506 UNLOCK_HARDWARE( mmesa );
507 }
508 }
509
510
511 /**
512 * Flush all commands upto at least a certain point to the hardware.
513 *
514 * \note
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.
518 *
519 * \warning
520 * As the name implies, this function assumes that the hardware lock is
521 * held on entry.
522 */
523 void mgaWaitAgeLocked( mgaContextPtr mmesa, int age )
524 {
525 if (GET_DISPATCH_AGE(mmesa) < age) {
526 UPDATE_LOCK( mmesa, DRM_LOCK_FLUSH );
527 }
528 }
529
530
531 static GLboolean intersect_rect( drm_clip_rect_t *out,
532 const drm_clip_rect_t *a,
533 const drm_clip_rect_t *b )
534 {
535 *out = *a;
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;
540
541 return ((out->x1 < out->x2) && (out->y1 < out->y2));
542 }
543
544
545
546
547 static void age_mmesa( mgaContextPtr mmesa, int age )
548 {
549 if (mmesa->CurrentTexObj[0]) mmesa->CurrentTexObj[0]->age = age;
550 if (mmesa->CurrentTexObj[1]) mmesa->CurrentTexObj[1]->age = age;
551 }
552
553
554 void mgaFlushVerticesLocked( mgaContextPtr mmesa )
555 {
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;
560 int i;
561
562 mmesa->vertex_dma_buffer = 0;
563
564 if (!buffer)
565 return;
566
567 if (mmesa->dirty_cliprects & mmesa->draw_buffer)
568 mgaUpdateRects( mmesa, mmesa->draw_buffer );
569
570 if (mmesa->dirty & ~MGA_UPLOAD_CLIPRECTS)
571 mgaEmitHwStateLocked( mmesa );
572
573 /* FIXME: Workaround bug in kernel module.
574 */
575 mmesa->sarea->dirty |= MGA_UPLOAD_CONTEXT;
576
577 if (!nbox)
578 buffer->used = 0;
579
580 if (nbox >= MGA_NR_SAREA_CLIPRECTS)
581 mmesa->dirty |= MGA_UPLOAD_CLIPRECTS;
582
583 #if 0
584 if (!buffer->used || !(mmesa->dirty & MGA_UPLOAD_CLIPRECTS))
585 {
586 if (nbox == 1)
587 mmesa->sarea->nbox = 0;
588 else
589 mmesa->sarea->nbox = nbox;
590
591 if (MGA_DEBUG&DEBUG_VERBOSE_IOCTL)
592 fprintf(stderr, "Firing vertex -- case a nbox %d\n", nbox);
593
594 vertex.idx = buffer->idx;
595 vertex.used = buffer->used;
596 vertex.discard = 1;
597 drmCommandWrite( mmesa->driFd, DRM_MGA_VERTEX,
598 &vertex, sizeof(drmMGAVertex) );
599
600 age_mmesa(mmesa, mmesa->sarea->last_enqueue);
601 }
602 else
603 #endif
604 {
605 for (i = 0 ; i < nbox ; )
606 {
607 int nr = MIN2(i + MGA_NR_SAREA_CLIPRECTS, nbox);
608 drm_clip_rect_t *b = mmesa->sarea->boxes;
609 int discard = 0;
610
611 if (mmesa->scissor) {
612 mmesa->sarea->nbox = 0;
613
614 for ( ; i < nr ; i++) {
615 *b = pbox[i];
616 if (intersect_rect(b, b, &mmesa->scissor_rect)) {
617 mmesa->sarea->nbox++;
618 b++;
619 }
620 }
621
622 /* Culled?
623 */
624 if (!mmesa->sarea->nbox) {
625 if (nr < nbox) continue;
626 buffer->used = 0;
627 }
628 } else {
629 mmesa->sarea->nbox = nr - i;
630 for ( ; i < nr ; i++)
631 *b++ = pbox[i];
632 }
633
634 /* Finished with the buffer?
635 */
636 if (nr == nbox)
637 discard = 1;
638
639 mmesa->sarea->dirty |= MGA_UPLOAD_CLIPRECTS;
640
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) );
646
647 age_mmesa(mmesa, mmesa->sarea->last_enqueue);
648 }
649 }
650
651 mmesa->dirty &= ~MGA_UPLOAD_CLIPRECTS;
652 }
653
654 void mgaFlushVertices( mgaContextPtr mmesa )
655 {
656 LOCK_HARDWARE( mmesa );
657 mgaFlushVerticesLocked( mmesa );
658 UNLOCK_HARDWARE( mmesa );
659 }
660
661
662 void mgaFireILoadLocked( mgaContextPtr mmesa,
663 GLuint offset, GLuint length )
664 {
665 if (!mmesa->iload_buffer) {
666 fprintf(stderr, "mgaFireILoad: no buffer\n");
667 return;
668 }
669
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 );
673
674 mga_iload_dma_ioctl( mmesa, offset, length );
675 }
676
677 void mgaGetILoadBufferLocked( mgaContextPtr mmesa )
678 {
679 if (MGA_DEBUG&DEBUG_VERBOSE_IOCTL)
680 fprintf(stderr, "mgaGetIloadBuffer (buffer now %p)\n",
681 (void *) mmesa->iload_buffer);
682
683 mmesa->iload_buffer = mga_get_buffer_ioctl( mmesa );
684 }
685
686
687 /**
688 * Implement the hardware-specific portion of \c glFlush.
689 *
690 * \param ctx Context to be flushed.
691 *
692 * \sa glFlush, mgaFinish, mgaFlushDMA
693 */
694 static void mgaFlush( GLcontext *ctx )
695 {
696 mgaContextPtr mmesa = MGA_CONTEXT( ctx );
697
698
699 LOCK_HARDWARE( mmesa );
700 if ( mmesa->vertex_dma_buffer != NULL ) {
701 mgaFlushVerticesLocked( mmesa );
702 }
703
704 UPDATE_LOCK( mmesa, DRM_LOCK_FLUSH );
705 UNLOCK_HARDWARE( mmesa );
706 }
707
708
709 int mgaFlushDMA( int fd, drmLockFlags flags )
710 {
711 drm_lock_t lock;
712 int ret, i = 0;
713
714 memset( &lock, 0, sizeof(lock) );
715
716 lock.flags = flags & (DRM_LOCK_QUIESCENT | DRM_LOCK_FLUSH
717 | DRM_LOCK_FLUSH_ALL);
718
719 do {
720 ret = drmCommandWrite( fd, DRM_MGA_FLUSH, &lock, sizeof(lock) );
721 } while ( ret && errno == EBUSY && i++ < DRM_MGA_IDLE_RETRY );
722
723 if ( ret == 0 )
724 return 0;
725 if ( errno != EBUSY )
726 return -errno;
727
728 if ( lock.flags & DRM_LOCK_QUIESCENT ) {
729 /* Only keep trying if we need quiescence.
730 */
731 lock.flags &= ~(DRM_LOCK_FLUSH | DRM_LOCK_FLUSH_ALL);
732
733 do {
734 ret = drmCommandWrite( fd, DRM_MGA_FLUSH, &lock, sizeof(lock) );
735 } while ( ret && errno == EBUSY && i++ < DRM_MGA_IDLE_RETRY );
736 }
737
738 if ( ret == 0 ) {
739 return 0;
740 } else {
741 return -errno;
742 }
743 }
744
745 void mgaInitIoctlFuncs( struct dd_function_table *functions )
746 {
747 functions->Clear = mgaClear;
748 functions->Flush = mgaFlush;
749 functions->Finish = mgaFinish;
750 }