Refactor "class" texture environments to be implemented in terms of
[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 * Authors:
25 * Keith Whitwell <keith@tungstengraphics.com>
26 * Gareth Hughes <gareth@valinux.com>
27 */
28 /* $XFree86: xc/lib/GL/mesa/src/drv/mga/mgaioctl.c,v 1.16 2002/12/16 16:18:52 dawes Exp $ */
29
30 #include <errno.h>
31 #include "mtypes.h"
32 #include "macros.h"
33 #include "dd.h"
34 #include "swrast/swrast.h"
35
36 #include "mm.h"
37 #include "mgacontext.h"
38 #include "mgadd.h"
39 #include "mgastate.h"
40 #include "mgatex.h"
41 #include "mgavb.h"
42 #include "mgaioctl.h"
43 #include "mgatris.h"
44 #include "mga_common.h"
45
46 #include "vblank.h"
47
48
49 static void mga_iload_dma_ioctl(mgaContextPtr mmesa,
50 unsigned long dest,
51 int length)
52 {
53 drmBufPtr buf = mmesa->iload_buffer;
54 drmMGAIload iload;
55 int ret, i;
56
57 if (MGA_DEBUG&DEBUG_VERBOSE_IOCTL)
58 fprintf(stderr, "DRM_IOCTL_MGA_ILOAD idx %d dst %x length %d\n",
59 buf->idx, (int) dest, length);
60
61 if ( (length & MGA_ILOAD_MASK) != 0 ) {
62 UNLOCK_HARDWARE( mmesa );
63 fprintf( stderr, "%s: Invalid ILOAD datasize (%d), must be "
64 "multiple of %u.\n", __FUNCTION__, length, MGA_ILOAD_ALIGN );
65 exit( 1 );
66 }
67
68 iload.idx = buf->idx;
69 iload.dstorg = dest;
70 iload.length = length;
71
72 i = 0;
73 do {
74 ret = drmCommandWrite( mmesa->driFd, DRM_MGA_ILOAD,
75 &iload, sizeof(drmMGAIload) );
76 } while ( ret == -EBUSY && i++ < DRM_MGA_IDLE_RETRY );
77
78 if ( ret < 0 ) {
79 printf("send iload retcode = %d\n", ret);
80 exit(1);
81 }
82
83 mmesa->iload_buffer = 0;
84
85 if (MGA_DEBUG&DEBUG_VERBOSE_IOCTL)
86 fprintf(stderr, "finished iload dma put\n");
87
88 }
89
90 drmBufPtr mga_get_buffer_ioctl( mgaContextPtr mmesa )
91 {
92 int idx = 0;
93 int size = 0;
94 drmDMAReq dma;
95 int retcode;
96 drmBufPtr buf;
97
98 if (MGA_DEBUG&DEBUG_VERBOSE_IOCTL)
99 fprintf(stderr, "Getting dma buffer\n");
100
101 dma.context = mmesa->hHWContext;
102 dma.send_count = 0;
103 dma.send_list = NULL;
104 dma.send_sizes = NULL;
105 dma.flags = 0;
106 dma.request_count = 1;
107 dma.request_size = MGA_BUFFER_SIZE;
108 dma.request_list = &idx;
109 dma.request_sizes = &size;
110 dma.granted_count = 0;
111
112
113 if (MGA_DEBUG&DEBUG_VERBOSE_IOCTL)
114 fprintf(stderr, "drmDMA (get) ctx %d count %d size 0x%x\n",
115 dma.context, dma.request_count,
116 dma.request_size);
117
118 while (1) {
119 retcode = drmDMA(mmesa->driFd, &dma);
120
121 if (MGA_DEBUG&DEBUG_VERBOSE_IOCTL)
122 fprintf(stderr, "retcode %d sz %d idx %d count %d\n",
123 retcode,
124 dma.request_sizes[0],
125 dma.request_list[0],
126 dma.granted_count);
127
128 if (retcode == 0 &&
129 dma.request_sizes[0] &&
130 dma.granted_count)
131 break;
132
133 if (MGA_DEBUG&DEBUG_VERBOSE_IOCTL)
134 fprintf(stderr, "\n\nflush");
135
136 UPDATE_LOCK( mmesa, DRM_LOCK_FLUSH | DRM_LOCK_QUIESCENT );
137 }
138
139 buf = &(mmesa->mgaScreen->bufs->list[idx]);
140 buf->used = 0;
141
142 if (MGA_DEBUG&DEBUG_VERBOSE_IOCTL)
143 fprintf(stderr,
144 "drmDMA (get) returns size[0] 0x%x idx[0] %d\n"
145 "dma_buffer now: buf idx: %d size: %d used: %d addr %p\n",
146 dma.request_sizes[0], dma.request_list[0],
147 buf->idx, buf->total,
148 buf->used, buf->address);
149
150 if (MGA_DEBUG&DEBUG_VERBOSE_IOCTL)
151 fprintf(stderr, "finished getbuffer\n");
152
153 return buf;
154 }
155
156
157
158
159 static void
160 mgaClear( GLcontext *ctx, GLbitfield mask, GLboolean all,
161 GLint cx, GLint cy, GLint cw, GLint ch )
162 {
163 mgaContextPtr mmesa = MGA_CONTEXT(ctx);
164 __DRIdrawablePrivate *dPriv = mmesa->driDrawable;
165 GLuint flags = 0;
166 GLuint clear_color = mmesa->ClearColor;
167 GLuint clear_depth = 0;
168 GLuint color_mask = 0;
169 GLuint depth_mask = 0;
170 int ret;
171 int i;
172 static int nrclears;
173 drmMGAClearRec clear;
174
175 FLUSH_BATCH( mmesa );
176
177 if ( mask & DD_FRONT_LEFT_BIT ) {
178 flags |= MGA_FRONT;
179 color_mask = mmesa->setup.plnwt;
180 mask &= ~DD_FRONT_LEFT_BIT;
181 }
182
183 if ( mask & DD_BACK_LEFT_BIT ) {
184 flags |= MGA_BACK;
185 color_mask = mmesa->setup.plnwt;
186 mask &= ~DD_BACK_LEFT_BIT;
187 }
188
189 if ( (mask & DD_DEPTH_BIT) && ctx->Depth.Mask ) {
190 flags |= MGA_DEPTH;
191 clear_depth = (mmesa->ClearDepth & mmesa->depth_clear_mask);
192 depth_mask |= mmesa->depth_clear_mask;
193 mask &= ~DD_DEPTH_BIT;
194 }
195
196 if ( (mask & DD_STENCIL_BIT) && mmesa->hw_stencil ) {
197 flags |= MGA_DEPTH;
198 clear_depth |= (ctx->Stencil.Clear & mmesa->stencil_clear_mask);
199 depth_mask |= mmesa->stencil_clear_mask;
200 mask &= ~DD_STENCIL_BIT;
201 }
202
203 if ( flags ) {
204 LOCK_HARDWARE( mmesa );
205
206 if ( mmesa->dirty_cliprects )
207 mgaUpdateRects( mmesa, (MGA_FRONT | MGA_BACK) );
208
209 /* flip top to bottom */
210 cy = dPriv->h-cy-ch;
211 cx += mmesa->drawX;
212 cy += mmesa->drawY;
213
214 if ( MGA_DEBUG & DEBUG_VERBOSE_IOCTL )
215 fprintf( stderr, "Clear, bufs %x nbox %d\n",
216 (int)flags, (int)mmesa->numClipRects );
217
218 for (i = 0 ; i < mmesa->numClipRects ; )
219 {
220 int nr = MIN2(i + MGA_NR_SAREA_CLIPRECTS, mmesa->numClipRects);
221 XF86DRIClipRectPtr box = mmesa->pClipRects;
222 XF86DRIClipRectPtr b = mmesa->sarea->boxes;
223 int n = 0;
224
225 if (!all) {
226 for ( ; i < nr ; i++) {
227 GLint x = box[i].x1;
228 GLint y = box[i].y1;
229 GLint w = box[i].x2 - x;
230 GLint h = box[i].y2 - y;
231
232 if (x < cx) w -= cx - x, x = cx;
233 if (y < cy) h -= cy - y, y = cy;
234 if (x + w > cx + cw) w = cx + cw - x;
235 if (y + h > cy + ch) h = cy + ch - y;
236 if (w <= 0) continue;
237 if (h <= 0) continue;
238
239 b->x1 = x;
240 b->y1 = y;
241 b->x2 = x + w;
242 b->y2 = y + h;
243 b++;
244 n++;
245 }
246 } else {
247 for ( ; i < nr ; i++) {
248 *b++ = *(XF86DRIClipRectPtr)&box[i];
249 n++;
250 }
251 }
252
253
254 if ( MGA_DEBUG & DEBUG_VERBOSE_IOCTL )
255 fprintf( stderr,
256 "DRM_IOCTL_MGA_CLEAR flag 0x%x color %x depth %x nbox %d\n",
257 flags, clear_color, clear_depth, mmesa->sarea->nbox );
258
259 mmesa->sarea->nbox = n;
260
261 clear.flags = flags;
262 clear.clear_color = clear_color;
263 clear.clear_depth = clear_depth;
264 clear.color_mask = color_mask;
265 clear.depth_mask = depth_mask;
266 ret = drmCommandWrite( mmesa->driFd, DRM_MGA_CLEAR,
267 &clear, sizeof(drmMGAClearRec));
268 if ( ret ) {
269 fprintf( stderr, "send clear retcode = %d\n", ret );
270 exit( 1 );
271 }
272 if ( MGA_DEBUG & DEBUG_VERBOSE_IOCTL )
273 fprintf( stderr, "finished clear %d\n", ++nrclears );
274 }
275
276 UNLOCK_HARDWARE( mmesa );
277 mmesa->dirty |= MGA_UPLOAD_CLIPRECTS|MGA_UPLOAD_CONTEXT;
278 }
279
280 if (mask)
281 _swrast_Clear( ctx, mask, all, cx, cy, cw, ch );
282 }
283
284
285 static void mgaWaitForFrameCompletion( mgaContextPtr mmesa )
286 {
287 unsigned wait = 0;
288 GLuint last_frame, last_wrap;
289
290
291 last_frame = mmesa->sarea->last_frame.head;
292 last_wrap = mmesa->sarea->last_frame.wrap;
293
294 /* FIXME: Add a timeout to this loop...
295 */
296 while ( 1 ) {
297 if ( last_wrap < mmesa->sarea->last_wrap ||
298 ( last_wrap == mmesa->sarea->last_wrap &&
299 last_frame <= (MGA_READ( MGAREG_PRIMADDRESS ) -
300 mmesa->primary_offset) ) ) {
301 break;
302 }
303 if ( 0 ) {
304 wait++;
305 fprintf( stderr, " last: head=0x%06x wrap=%d\n",
306 last_frame, last_wrap );
307 fprintf( stderr, " head: head=0x%06lx wrap=%d\n",
308 (long)(MGA_READ( MGAREG_PRIMADDRESS ) - mmesa->primary_offset),
309 mmesa->sarea->last_wrap );
310 }
311 UPDATE_LOCK( mmesa, DRM_LOCK_FLUSH );
312
313 UNLOCK_HARDWARE( mmesa );
314 DO_USLEEP( 1 );
315 LOCK_HARDWARE( mmesa );
316 }
317 if ( wait )
318 fprintf( stderr, "\n" );
319 }
320
321
322 /*
323 * Copy the back buffer to the front buffer.
324 */
325 void mgaCopyBuffer( const __DRIdrawablePrivate *dPriv )
326 {
327 mgaContextPtr mmesa;
328 XF86DRIClipRectPtr pbox;
329 GLint nbox;
330 GLint ret;
331 GLint i;
332 GLboolean missed_target;
333
334
335 assert(dPriv);
336 assert(dPriv->driContextPriv);
337 assert(dPriv->driContextPriv->driverPrivate);
338
339 mmesa = (mgaContextPtr) dPriv->driContextPriv->driverPrivate;
340
341 FLUSH_BATCH( mmesa );
342
343 LOCK_HARDWARE( mmesa );
344 mgaWaitForFrameCompletion( mmesa );
345 UNLOCK_HARDWARE( mmesa );
346 driWaitForVBlank( dPriv, & mmesa->vbl_seq, mmesa->vblank_flags,
347 & missed_target );
348 if ( missed_target ) {
349 mmesa->swap_missed_count++;
350 (void) (*mmesa->get_ust)( & mmesa->swap_missed_ust );
351 }
352 LOCK_HARDWARE( mmesa );
353
354 /* Use the frontbuffer cliprects
355 */
356 if (mmesa->dirty_cliprects & MGA_FRONT)
357 mgaUpdateRects( mmesa, MGA_FRONT );
358
359
360 pbox = dPriv->pClipRects;
361 nbox = dPriv->numClipRects;
362
363 for (i = 0 ; i < nbox ; )
364 {
365 int nr = MIN2(i + MGA_NR_SAREA_CLIPRECTS, dPriv->numClipRects);
366 XF86DRIClipRectPtr b = mmesa->sarea->boxes;
367
368 mmesa->sarea->nbox = nr - i;
369
370 for ( ; i < nr ; i++)
371 *b++ = pbox[i];
372
373 if (0)
374 fprintf(stderr, "DRM_IOCTL_MGA_SWAP\n");
375
376 ret = drmCommandNone( mmesa->driFd, DRM_MGA_SWAP );
377 if ( ret ) {
378 printf("send swap retcode = %d\n", ret);
379 exit(1);
380 }
381 }
382
383 UNLOCK_HARDWARE( mmesa );
384
385 mmesa->dirty |= MGA_UPLOAD_CLIPRECTS;
386 mmesa->swap_count++;
387 (void) (*mmesa->get_ust)( & mmesa->swap_ust );
388 }
389
390
391 /* This is overkill
392 */
393 void mgaFinish( GLcontext *ctx )
394 {
395 mgaContextPtr mmesa = MGA_CONTEXT(ctx);
396
397 FLUSH_BATCH( mmesa );
398
399 if (1/*mmesa->sarea->last_quiescent != mmesa->sarea->last_enqueue*/) {
400 if (MGA_DEBUG&DEBUG_VERBOSE_IOCTL)
401 fprintf(stderr, "mgaRegetLockQuiescent\n");
402
403 LOCK_HARDWARE( mmesa );
404 UPDATE_LOCK( mmesa, DRM_LOCK_QUIESCENT | DRM_LOCK_FLUSH );
405 UNLOCK_HARDWARE( mmesa );
406
407 mmesa->sarea->last_quiescent = mmesa->sarea->last_enqueue;
408 }
409 }
410
411 void mgaWaitAgeLocked( mgaContextPtr mmesa, int age )
412 {
413 if (GET_DISPATCH_AGE(mmesa) < age) {
414 UPDATE_LOCK( mmesa, DRM_LOCK_FLUSH );
415 }
416 }
417
418
419 void mgaWaitAge( mgaContextPtr mmesa, int age )
420 {
421 if (GET_DISPATCH_AGE(mmesa) < age) {
422 LOCK_HARDWARE(mmesa);
423 if (GET_DISPATCH_AGE(mmesa) < age) {
424 UPDATE_LOCK( mmesa, DRM_LOCK_FLUSH );
425 }
426 UNLOCK_HARDWARE(mmesa);
427 }
428 }
429
430
431 static GLboolean intersect_rect( XF86DRIClipRectPtr out,
432 const XF86DRIClipRectPtr a,
433 const XF86DRIClipRectPtr b )
434 {
435 *out = *a;
436 if (b->x1 > out->x1) out->x1 = b->x1;
437 if (b->y1 > out->y1) out->y1 = b->y1;
438 if (b->x2 < out->x2) out->x2 = b->x2;
439 if (b->y2 < out->y2) out->y2 = b->y2;
440
441 return ((out->x1 < out->x2) && (out->y1 < out->y2));
442 }
443
444
445
446
447 static void age_mmesa( mgaContextPtr mmesa, int age )
448 {
449 if (mmesa->CurrentTexObj[0]) mmesa->CurrentTexObj[0]->age = age;
450 if (mmesa->CurrentTexObj[1]) mmesa->CurrentTexObj[1]->age = age;
451 }
452
453 #ifdef __i386__
454 static int __break_vertex = 0;
455 #endif
456
457 void mgaFlushVerticesLocked( mgaContextPtr mmesa )
458 {
459 XF86DRIClipRectPtr pbox = mmesa->pClipRects;
460 int nbox = mmesa->numClipRects;
461 drmBufPtr buffer = mmesa->vertex_dma_buffer;
462 drmMGAVertex vertex;
463 int i;
464
465 mmesa->vertex_dma_buffer = 0;
466
467 if (!buffer)
468 return;
469
470 if (mmesa->dirty_cliprects & mmesa->draw_buffer)
471 mgaUpdateRects( mmesa, mmesa->draw_buffer );
472
473 if (mmesa->dirty & ~MGA_UPLOAD_CLIPRECTS)
474 mgaEmitHwStateLocked( mmesa );
475
476 /* FIXME: Workaround bug in kernel module.
477 */
478 mmesa->sarea->dirty |= MGA_UPLOAD_CONTEXT;
479
480 if (!nbox)
481 buffer->used = 0;
482
483 if (nbox >= MGA_NR_SAREA_CLIPRECTS)
484 mmesa->dirty |= MGA_UPLOAD_CLIPRECTS;
485
486 #if 0
487 if (!buffer->used || !(mmesa->dirty & MGA_UPLOAD_CLIPRECTS))
488 {
489 if (nbox == 1)
490 mmesa->sarea->nbox = 0;
491 else
492 mmesa->sarea->nbox = nbox;
493
494 if (MGA_DEBUG&DEBUG_VERBOSE_IOCTL)
495 fprintf(stderr, "Firing vertex -- case a nbox %d\n", nbox);
496
497 vertex.idx = buffer->idx;
498 vertex.used = buffer->used;
499 vertex.discard = 1;
500 drmCommandWrite( mmesa->driFd, DRM_MGA_VERTEX,
501 &vertex, sizeof(drmMGAVertex) );
502
503 age_mmesa(mmesa, mmesa->sarea->last_enqueue);
504 }
505 else
506 #endif
507 {
508 for (i = 0 ; i < nbox ; )
509 {
510 int nr = MIN2(i + MGA_NR_SAREA_CLIPRECTS, nbox);
511 XF86DRIClipRectPtr b = mmesa->sarea->boxes;
512 int discard = 0;
513
514 if (mmesa->scissor) {
515 mmesa->sarea->nbox = 0;
516
517 for ( ; i < nr ; i++) {
518 *b = pbox[i];
519 if (intersect_rect(b, b, &mmesa->scissor_rect)) {
520 mmesa->sarea->nbox++;
521 b++;
522 }
523 }
524
525 /* Culled?
526 */
527 if (!mmesa->sarea->nbox) {
528 if (nr < nbox) continue;
529 buffer->used = 0;
530 }
531 } else {
532 mmesa->sarea->nbox = nr - i;
533 for ( ; i < nr ; i++)
534 *b++ = pbox[i];
535 }
536
537 /* Finished with the buffer?
538 */
539 if (nr == nbox)
540 discard = 1;
541
542 mmesa->sarea->dirty |= MGA_UPLOAD_CLIPRECTS;
543
544 vertex.idx = buffer->idx;
545 vertex.used = buffer->used;
546 vertex.discard = discard;
547 drmCommandWrite( mmesa->driFd, DRM_MGA_VERTEX,
548 &vertex, sizeof(drmMGAVertex) );
549
550 age_mmesa(mmesa, mmesa->sarea->last_enqueue);
551 }
552 }
553
554 /* Do we really need to do this ? */
555 #ifdef __i386__
556 if ( __break_vertex ) {
557 __asm__ __volatile__ ( "int $3" );
558 }
559 #endif
560
561 mmesa->dirty &= ~MGA_UPLOAD_CLIPRECTS;
562 }
563
564 void mgaFlushVertices( mgaContextPtr mmesa )
565 {
566 LOCK_HARDWARE( mmesa );
567 mgaFlushVerticesLocked( mmesa );
568 UNLOCK_HARDWARE( mmesa );
569 }
570
571
572 void mgaFireILoadLocked( mgaContextPtr mmesa,
573 GLuint offset, GLuint length )
574 {
575 if (!mmesa->iload_buffer) {
576 fprintf(stderr, "mgaFireILoad: no buffer\n");
577 return;
578 }
579
580 if (MGA_DEBUG&DEBUG_VERBOSE_IOCTL)
581 fprintf(stderr, "mgaFireILoad idx %d ofs 0x%x length %d\n",
582 mmesa->iload_buffer->idx, (int)offset, (int)length );
583
584 mga_iload_dma_ioctl( mmesa, offset, length );
585 }
586
587 void mgaGetILoadBufferLocked( mgaContextPtr mmesa )
588 {
589 if (MGA_DEBUG&DEBUG_VERBOSE_IOCTL)
590 fprintf(stderr, "mgaGetIloadBuffer (buffer now %p)\n",
591 mmesa->iload_buffer);
592
593 mmesa->iload_buffer = mga_get_buffer_ioctl( mmesa );
594 }
595
596 drmBufPtr mgaGetBufferLocked( mgaContextPtr mmesa )
597 {
598 return mga_get_buffer_ioctl( mmesa );
599 }
600
601
602
603 void mgaFlush( GLcontext *ctx )
604 {
605 mgaContextPtr mmesa = MGA_CONTEXT( ctx );
606
607
608 FLUSH_BATCH( mmesa );
609
610 /* This may be called redundantly - dispatch_age may trail what
611 * has actually been sent and processed by the hardware.
612 */
613 if (1 || GET_DISPATCH_AGE( mmesa ) < mmesa->sarea->last_enqueue) {
614 LOCK_HARDWARE( mmesa );
615 UPDATE_LOCK( mmesa, DRM_LOCK_FLUSH );
616 UNLOCK_HARDWARE( mmesa );
617 }
618 }
619
620
621
622
623 void mgaReleaseBufLocked( mgaContextPtr mmesa, drmBufPtr buffer )
624 {
625 drmMGAVertex vertex;
626
627 if (!buffer) return;
628
629 vertex.idx = buffer->idx;
630 vertex.used = 0;
631 vertex.discard = 1;
632 drmCommandWrite( mmesa->driFd, DRM_MGA_VERTEX,
633 &vertex, sizeof(drmMGAVertex) );
634 }
635
636 int mgaFlushDMA( int fd, drmLockFlags flags )
637 {
638 drmMGALock lock;
639 int ret, i = 0;
640
641 memset( &lock, 0, sizeof(drmMGALock) );
642
643 if ( flags & DRM_LOCK_QUIESCENT ) lock.flags |= DRM_LOCK_QUIESCENT;
644 if ( flags & DRM_LOCK_FLUSH ) lock.flags |= DRM_LOCK_FLUSH;
645 if ( flags & DRM_LOCK_FLUSH_ALL ) lock.flags |= DRM_LOCK_FLUSH_ALL;
646
647 do {
648 ret = drmCommandWrite( fd, DRM_MGA_FLUSH, &lock, sizeof(drmMGALock) );
649 } while ( ret && errno == EBUSY && i++ < DRM_MGA_IDLE_RETRY );
650
651 if ( ret == 0 )
652 return 0;
653 if ( errno != EBUSY )
654 return -errno;
655
656 if ( lock.flags & DRM_LOCK_QUIESCENT ) {
657 /* Only keep trying if we need quiescence.
658 */
659 lock.flags &= ~(DRM_LOCK_FLUSH | DRM_LOCK_FLUSH_ALL);
660
661 do {
662 ret = drmCommandWrite( fd, DRM_MGA_FLUSH, &lock, sizeof(drmMGALock) );
663 } while ( ret && errno == EBUSY && i++ < DRM_MGA_IDLE_RETRY );
664 }
665
666 if ( ret == 0 ) {
667 return 0;
668 } else {
669 return -errno;
670 }
671 }
672
673 void mgaInitIoctlFuncs( struct dd_function_table *functions )
674 {
675 functions->Clear = mgaClear;
676 functions->Flush = mgaFlush;
677 functions->Finish = mgaFinish;
678 }