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