OSDN Git Service

0146e0d05151776f5cb4b41b83814bc4cca035db
[android-x86/external-mesa.git] / src / mesa / drivers / dri / mach64 / mach64_ioctl.c
1 /* -*- mode: c; c-basic-offset: 3 -*- */
2 /*
3  * Copyright 2000 Gareth Hughes
4  * All Rights Reserved.
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a
7  * copy of this software and associated documentation files (the "Software"),
8  * to deal in the Software without restriction, including without limitation
9  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10  * and/or sell copies of the Software, and to permit persons to whom the
11  * Software is furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice (including the next
14  * paragraph) shall be included in all copies or substantial portions of the
15  * Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20  * GARETH HUGHES BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
21  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23  */
24
25 /*
26  * Authors:
27  *      Gareth Hughes <gareth@valinux.com>
28  *      Leif Delgass <ldelgass@retinalburn.net>
29  *      Jos�Fonseca <j_r_fonseca@yahoo.co.uk>
30  */
31 #include <errno.h>
32
33 #include "mach64_context.h"
34 #include "mach64_state.h"
35 #include "mach64_ioctl.h"
36 #include "mach64_tex.h"
37
38 #include "main/imports.h"
39 #include "main/macros.h"
40
41 #include "swrast/swrast.h"
42
43 #include "vblank.h"
44
45 #define MACH64_TIMEOUT        10 /* the DRM already has a timeout, so keep this small */
46
47
48 /* =============================================================
49  * Hardware vertex buffer handling
50  */
51
52 /* Get a new VB from the pool of vertex buffers in AGP space.
53  */
54 drmBufPtr mach64GetBufferLocked( mach64ContextPtr mmesa )
55 {
56    int fd = mmesa->mach64Screen->driScreen->fd;
57    int index = 0;
58    int size = 0;
59    drmDMAReq dma;
60    drmBufPtr buf = NULL;
61    int to = 0;
62    int ret;
63
64    dma.context = mmesa->hHWContext;
65    dma.send_count = 0;
66    dma.send_list = NULL;
67    dma.send_sizes = NULL;
68    dma.flags = 0;
69    dma.request_count = 1;
70    dma.request_size = MACH64_BUFFER_SIZE;
71    dma.request_list = &index;
72    dma.request_sizes = &size;
73    dma.granted_count = 0;
74
75    while ( !buf && ( to++ < MACH64_TIMEOUT ) ) {
76       ret = drmDMA( fd, &dma );
77
78       if ( ret == 0 ) {
79          buf = &mmesa->mach64Screen->buffers->list[index];
80          buf->used = 0;
81 #if ENABLE_PERF_BOXES
82          /* Bump the performance counter */
83          mmesa->c_vertexBuffers++;
84 #endif
85          return buf;
86       }
87    }
88
89    if ( !buf ) {
90       drmCommandNone( fd, DRM_MACH64_RESET );
91       UNLOCK_HARDWARE( mmesa );
92       fprintf( stderr, "Error: Could not get new VB... exiting\n" );
93       exit( -1 );
94    }
95
96    return buf;
97 }
98
99 void mach64FlushVerticesLocked( mach64ContextPtr mmesa )
100 {
101    drm_clip_rect_t *pbox = mmesa->pClipRects;
102    int nbox = mmesa->numClipRects;
103    void *buffer = mmesa->vert_buf;
104    int count = mmesa->vert_used;
105    int prim = mmesa->hw_primitive;
106    int fd = mmesa->driScreen->fd;
107    drm_mach64_vertex_t vertex;
108    int i;
109
110    mmesa->num_verts = 0;
111    mmesa->vert_used = 0;
112
113    if ( !count )
114       return;
115
116    if ( mmesa->dirty & ~MACH64_UPLOAD_CLIPRECTS )
117       mach64EmitHwStateLocked( mmesa );
118
119    if ( !nbox )
120       count = 0;
121
122    if ( nbox > MACH64_NR_SAREA_CLIPRECTS )
123       mmesa->dirty |= MACH64_UPLOAD_CLIPRECTS;
124
125    if ( !count || !(mmesa->dirty & MACH64_UPLOAD_CLIPRECTS) ) {
126       int to = 0;
127       int ret;
128
129       /* FIXME: Is this really necessary */
130       if ( nbox == 1 )
131          mmesa->sarea->nbox = 0;
132       else
133          mmesa->sarea->nbox = nbox;
134
135       vertex.prim = prim;
136       vertex.buf = buffer;
137       vertex.used = count;
138       vertex.discard = 1;
139       do {
140          ret = drmCommandWrite( fd, DRM_MACH64_VERTEX,
141                                 &vertex, sizeof(drm_mach64_vertex_t) );
142       } while ( ( ret == -EAGAIN ) && ( to++ < MACH64_TIMEOUT ) );
143       if ( ret ) {
144          UNLOCK_HARDWARE( mmesa );
145          fprintf( stderr, "Error flushing vertex buffer: return = %d\n", ret );
146          exit( -1 );
147       }
148
149    } else {
150
151       for ( i = 0 ; i < nbox ; ) {
152          int nr = MIN2( i + MACH64_NR_SAREA_CLIPRECTS, nbox );
153          drm_clip_rect_t *b = mmesa->sarea->boxes;
154          int discard = 0;
155          int to = 0;
156          int ret;
157
158          mmesa->sarea->nbox = nr - i;
159          for ( ; i < nr ; i++ ) {
160             *b++ = pbox[i];
161          }
162
163          /* Finished with the buffer?
164           */
165          if ( nr == nbox ) {
166             discard = 1;
167          }
168
169          mmesa->sarea->dirty |= MACH64_UPLOAD_CLIPRECTS;
170          
171          vertex.prim = prim;
172          vertex.buf = buffer;
173          vertex.used = count;
174          vertex.discard = discard;
175          do {
176             ret = drmCommandWrite( fd, DRM_MACH64_VERTEX,
177                                    &vertex, sizeof(drm_mach64_vertex_t) );
178          } while ( ( ret == -EAGAIN ) && ( to++ < MACH64_TIMEOUT ) );
179          if ( ret ) {
180             UNLOCK_HARDWARE( mmesa );
181             fprintf( stderr, "Error flushing vertex buffer: return = %d\n", ret );
182             exit( -1 );
183          }
184       }
185    }
186
187    mmesa->dirty &= ~MACH64_UPLOAD_CLIPRECTS;
188 }
189
190 /* ================================================================
191  * Texture uploads
192  */
193
194 void mach64FireBlitLocked( mach64ContextPtr mmesa, void *buffer,
195                            GLint offset, GLint pitch, GLint format,
196                            GLint x, GLint y, GLint width, GLint height )
197 {
198    drm_mach64_blit_t blit;
199    int to = 0;
200    int ret;
201
202    blit.buf = buffer;
203    blit.offset = offset;
204    blit.pitch = pitch;
205    blit.format = format;
206    blit.x = x;
207    blit.y = y;
208    blit.width = width;
209    blit.height = height;
210
211    do {
212       ret = drmCommandWrite( mmesa->driFd, DRM_MACH64_BLIT, 
213                              &blit, sizeof(drm_mach64_blit_t) );
214    } while ( ( ret == -EAGAIN ) && ( to++ < MACH64_TIMEOUT ) );
215
216    if ( ret ) {
217       UNLOCK_HARDWARE( mmesa );
218       fprintf( stderr, "DRM_MACH64_BLIT: return = %d\n", ret );
219       exit( -1 );
220    }
221 }
222
223
224 /* ================================================================
225  * SwapBuffers with client-side throttling
226  */
227 static void delay( void ) {
228 /* Prevent an optimizing compiler from removing a spin loop */
229 }
230
231 /* Throttle the frame rate -- only allow MACH64_MAX_QUEUED_FRAMES
232  * pending swap buffers requests at a time.
233  *
234  * GH: We probably don't want a timeout here, as we can wait as
235  * long as we want for a frame to complete.  If it never does, then
236  * the card has locked.
237  */
238 static int mach64WaitForFrameCompletion( mach64ContextPtr mmesa )
239 {
240    int fd = mmesa->driFd;
241    int i;
242    int wait = 0;
243    int frames;
244
245    while ( 1 ) {
246       drm_mach64_getparam_t gp;
247       int ret;
248
249       if ( mmesa->sarea->frames_queued < MACH64_MAX_QUEUED_FRAMES ) {
250          break;
251       }
252
253       if (MACH64_DEBUG & DEBUG_NOWAIT) {
254          return 1;
255       }
256
257       gp.param = MACH64_PARAM_FRAMES_QUEUED;
258       gp.value = &frames; /* also copied into sarea->frames_queued by DRM */
259
260       ret = drmCommandWriteRead( fd, DRM_MACH64_GETPARAM, &gp, sizeof(gp) );
261
262       if ( ret ) {
263          UNLOCK_HARDWARE( mmesa );
264          fprintf( stderr, "DRM_MACH64_GETPARAM: return = %d\n", ret );
265          exit( -1 );
266       }
267
268       /* Spin in place a bit so we aren't hammering the register */
269       wait++;
270
271       for ( i = 0 ; i < 1024 ; i++ ) {
272          delay();
273       }
274
275    }
276
277    return wait;
278 }
279
280 /* Copy the back color buffer to the front color buffer.
281  */
282 void mach64CopyBuffer( __DRIdrawable *dPriv )
283 {
284    mach64ContextPtr mmesa;
285    GLint nbox, i, ret;
286    drm_clip_rect_t *pbox;
287    GLboolean missed_target;
288
289    assert(dPriv);
290    assert(dPriv->driContextPriv);
291    assert(dPriv->driContextPriv->driverPrivate);
292
293    mmesa = (mach64ContextPtr) dPriv->driContextPriv->driverPrivate;
294
295    if ( MACH64_DEBUG & DEBUG_VERBOSE_API ) {
296       fprintf( stderr, "\n********************************\n" );
297       fprintf( stderr, "\n%s( %p )\n\n",
298                __FUNCTION__, mmesa->glCtx );
299       fflush( stderr );
300    }
301
302    /* Flush any outstanding vertex buffers */
303    FLUSH_BATCH( mmesa );
304
305    LOCK_HARDWARE( mmesa );
306
307    /* Throttle the frame rate -- only allow one pending swap buffers
308     * request at a time.
309     */
310    if ( !mach64WaitForFrameCompletion( mmesa ) ) {
311       mmesa->hardwareWentIdle = 1;
312    } else {
313       mmesa->hardwareWentIdle = 0;
314    }
315
316 #if ENABLE_PERF_BOXES
317    if ( mmesa->boxes ) {
318       mach64PerformanceBoxesLocked( mmesa );
319    }
320 #endif
321
322    UNLOCK_HARDWARE( mmesa );
323    driWaitForVBlank( dPriv, &missed_target );
324    LOCK_HARDWARE( mmesa );
325
326    /* use front buffer cliprects */
327    nbox = dPriv->numClipRects;
328    pbox = dPriv->pClipRects;
329
330    for ( i = 0 ; i < nbox ; ) {
331       GLint nr = MIN2( i + MACH64_NR_SAREA_CLIPRECTS , nbox );
332       drm_clip_rect_t *b = mmesa->sarea->boxes;
333       GLint n = 0;
334
335       for ( ; i < nr ; i++ ) {
336          *b++ = pbox[i];
337          n++;
338       }
339       mmesa->sarea->nbox = n;
340
341       ret = drmCommandNone( mmesa->driFd, DRM_MACH64_SWAP );
342
343       if ( ret ) {
344          UNLOCK_HARDWARE( mmesa );
345          fprintf( stderr, "DRM_MACH64_SWAP: return = %d\n", ret );
346          exit( -1 );
347       }
348    }
349
350    if ( MACH64_DEBUG & DEBUG_ALWAYS_SYNC ) {
351       mach64WaitForIdleLocked( mmesa );
352    }
353
354    UNLOCK_HARDWARE( mmesa );
355
356    mmesa->dirty |= (MACH64_UPLOAD_CONTEXT |
357                     MACH64_UPLOAD_MISC |
358                     MACH64_UPLOAD_CLIPRECTS);
359
360 #if ENABLE_PERF_BOXES
361    /* Log the performance counters if necessary */
362    mach64PerformanceCounters( mmesa );
363 #endif
364 }
365
366 #if ENABLE_PERF_BOXES
367 /* ================================================================
368  * Performance monitoring
369  */
370
371 void mach64PerformanceCounters( mach64ContextPtr mmesa )
372 {
373
374    if (MACH64_DEBUG & DEBUG_VERBOSE_COUNT) {
375       /* report performance counters */
376       fprintf( stderr, "mach64CopyBuffer: vertexBuffers:%i drawWaits:%i clears:%i\n",
377                mmesa->c_vertexBuffers, mmesa->c_drawWaits, mmesa->c_clears );
378    }
379
380    mmesa->c_vertexBuffers = 0;
381    mmesa->c_drawWaits = 0;
382    mmesa->c_clears = 0;
383
384    if ( mmesa->c_textureSwaps || mmesa->c_textureBytes || mmesa->c_agpTextureBytes ) {
385       if (MACH64_DEBUG & DEBUG_VERBOSE_COUNT) {
386          fprintf( stderr, "    textureSwaps:%i  textureBytes:%i agpTextureBytes:%i\n",
387                   mmesa->c_textureSwaps, mmesa->c_textureBytes, mmesa->c_agpTextureBytes );
388       }
389       mmesa->c_textureSwaps = 0;
390       mmesa->c_textureBytes = 0;
391       mmesa->c_agpTextureBytes = 0;
392    }
393
394    mmesa->c_texsrc_agp = 0;
395    mmesa->c_texsrc_card = 0;
396
397    if (MACH64_DEBUG & DEBUG_VERBOSE_COUNT)
398       fprintf( stderr, "---------------------------------------------------------\n" );
399 }
400
401
402 void mach64PerformanceBoxesLocked( mach64ContextPtr mmesa )
403 {
404    GLint ret;
405    drm_mach64_clear_t clear;
406    GLint x, y, w, h;
407    GLuint color;
408    GLint nbox;
409    GLint x1, y1, x2, y2;
410    drm_clip_rect_t *b = mmesa->sarea->boxes;
411
412    /* save cliprects */
413    nbox = mmesa->sarea->nbox;
414    x1 = b[0].x1;
415    y1 = b[0].y1;
416    x2 = b[0].x2;
417    y2 = b[0].y2;
418  
419    /* setup a single cliprect and call the clear ioctl for each box */
420    mmesa->sarea->nbox = 1;
421
422    w = h = 8;
423    x = mmesa->drawX;
424    y = mmesa->drawY;
425    b[0].x1 = x;
426    b[0].x2 = x + w;
427    b[0].y1 = y;
428    b[0].y2 = y + h;
429
430    clear.flags = MACH64_BACK;
431    clear.clear_depth = 0;
432
433    /* Red box if DDFinish was called to wait for rendering to complete */
434    if ( mmesa->c_drawWaits ) {
435       color = mach64PackColor( mmesa->mach64Screen->cpp, 255, 0, 0, 0 );
436       
437       clear.x = x;
438       clear.y = y;
439       clear.w = w;
440       clear.h = h;
441       clear.clear_color = color;
442
443       ret = drmCommandWrite( mmesa->driFd, DRM_MACH64_CLEAR,
444                              &clear, sizeof(drm_mach64_clear_t) );
445
446       if (ret < 0) {
447          UNLOCK_HARDWARE( mmesa );
448          fprintf( stderr, "DRM_MACH64_CLEAR: return = %d\n", ret );
449          exit( -1 );
450       }
451
452    }
453
454    x += w;
455    b[0].x1 = x;
456    b[0].x2 = x + w;
457
458    /* draw a green box if we had to wait for previous frame(s) to complete */
459    if ( !mmesa->hardwareWentIdle ) {
460       color = mach64PackColor( mmesa->mach64Screen->cpp, 0, 255, 0, 0 );
461       
462       clear.x = x;
463       clear.y = y;
464       clear.w = w;
465       clear.h = h;
466       clear.clear_color = color;
467
468       ret = drmCommandWrite( mmesa->driFd, DRM_MACH64_CLEAR,
469                              &clear, sizeof(drm_mach64_clear_t) );
470
471       if (ret < 0) {
472          UNLOCK_HARDWARE( mmesa );
473          fprintf( stderr, "DRM_MACH64_CLEAR: return = %d\n", ret );
474          exit( -1 );
475       }
476
477    }
478
479    x += w;
480    w = 20;
481    b[0].x1 = x;
482
483    /* show approx. ratio of AGP/card textures used - Blue = AGP, Purple = Card */
484    if ( mmesa->c_texsrc_agp || mmesa->c_texsrc_card ) {
485       color = mach64PackColor( mmesa->mach64Screen->cpp, 0, 0, 255, 0 );
486       w = ((GLfloat)mmesa->c_texsrc_agp / (GLfloat)(mmesa->c_texsrc_agp + mmesa->c_texsrc_card))*20;
487       if (w > 1) {
488
489          b[0].x2 = x + w;
490
491          clear.x = x;
492          clear.y = y;
493          clear.w = w;
494          clear.h = h;
495          clear.clear_color = color;
496
497          ret = drmCommandWrite( mmesa->driFd, DRM_MACH64_CLEAR,
498                                 &clear, sizeof(drm_mach64_clear_t) );
499
500          if (ret < 0) {
501             UNLOCK_HARDWARE( mmesa );
502             fprintf( stderr, "DRM_MACH64_CLEAR: return = %d\n", ret );
503             exit( -1 );
504          }
505       }
506
507       x += w;
508       w = 20 - w;
509
510       if (w > 1) {
511          b[0].x1 = x;
512          b[0].x2 = x + w;
513
514          color = mach64PackColor( mmesa->mach64Screen->cpp, 255, 0, 255, 0 );
515
516          clear.x = x;
517          clear.y = y;
518          clear.w = w;
519          clear.h = h;
520          clear.clear_color = color;
521
522          ret = drmCommandWrite( mmesa->driFd, DRM_MACH64_CLEAR,
523                                 &clear, sizeof(drm_mach64_clear_t) );
524
525          if (ret < 0) {
526             UNLOCK_HARDWARE( mmesa );
527             fprintf( stderr, "DRM_MACH64_CLEAR: return = %d\n", ret );
528             exit( -1 );
529          }
530       }
531    }  
532
533    x += w;
534    w = 8;
535    b[0].x1 = x;
536    b[0].x2 = x + w;
537
538    /* Yellow box if we swapped textures */
539    if ( mmesa->c_textureSwaps ) {
540       color = mach64PackColor( mmesa->mach64Screen->cpp, 255, 255, 0, 0 );
541
542       clear.x = x;
543       clear.y = y;
544       clear.w = w;
545       clear.h = h;
546       clear.clear_color = color;
547
548       ret = drmCommandWrite( mmesa->driFd, DRM_MACH64_CLEAR,
549                                 &clear, sizeof(drm_mach64_clear_t) );
550
551       if (ret < 0) {
552          UNLOCK_HARDWARE( mmesa );
553          fprintf( stderr, "DRM_MACH64_CLEAR: return = %d\n", ret );
554          exit( -1 );
555       }
556       
557    }
558
559    h = 4;
560    x += 8;
561    b[0].x1 = x;
562    b[0].y2 = y + h;
563
564    /* Purple bar for card memory texture blits/uploads */
565    if ( mmesa->c_textureBytes ) {
566       color = mach64PackColor( mmesa->mach64Screen->cpp, 255, 0, 255, 0 );
567       w = mmesa->c_textureBytes / 16384;
568       if ( w <= 0 ) 
569          w = 1; 
570       if (w > (mmesa->driDrawable->w - 44))
571          w = mmesa->driDrawable->w - 44;
572
573       b[0].x2 = x + w;
574
575       clear.x = x;
576       clear.y = y;
577       clear.w = w;
578       clear.h = h;
579       clear.clear_color = color;
580
581       ret = drmCommandWrite( mmesa->driFd, DRM_MACH64_CLEAR,
582                                 &clear, sizeof(drm_mach64_clear_t) );
583
584       if (ret < 0) {
585          UNLOCK_HARDWARE( mmesa );
586          fprintf( stderr, "DRM_MACH64_CLEAR: return = %d\n", ret );
587          exit( -1 );
588       }
589    }
590
591    /* Blue bar for AGP memory texture blits/uploads */
592    if ( mmesa->c_agpTextureBytes ) {
593       color = mach64PackColor( mmesa->mach64Screen->cpp, 0, 0, 255, 0 );
594       w = mmesa->c_agpTextureBytes / 16384;
595       if ( w <= 0 ) 
596          w = 1; 
597       if (w > (mmesa->driDrawable->w - 44))
598          w = mmesa->driDrawable->w - 44;
599
600       y += 4;
601       b[0].x2 = x + w;
602       b[0].y1 = y;
603       b[0].y2 = y + h;
604
605       clear.x = x;
606       clear.y = y;
607       clear.w = w;
608       clear.h = h;
609       clear.clear_color = color;
610
611       ret = drmCommandWrite( mmesa->driFd, DRM_MACH64_CLEAR,
612                                 &clear, sizeof(drm_mach64_clear_t) );
613
614       if (ret < 0) {
615          UNLOCK_HARDWARE( mmesa );
616          fprintf( stderr, "DRM_MACH64_CLEAR: return = %d\n", ret );
617          exit( -1 );
618       }
619    }
620
621    /* Pink bar for number of vertex buffers used */
622    if ( mmesa->c_vertexBuffers ) {
623       color = mach64PackColor( mmesa->mach64Screen->cpp, 196, 128, 128, 0 );
624
625       w = mmesa->c_vertexBuffers;
626       if (w > (mmesa->driDrawable->w))
627          w = mmesa->driDrawable->w;
628
629       h = 8;
630       x = mmesa->drawX;
631       y = mmesa->drawY + 8;
632       b[0].x1 = x;
633       b[0].x2 = x + w;
634       b[0].y1 = y;
635       b[0].y2 = y + h;
636
637       clear.x = x;
638       clear.y = y;
639       clear.w = w;
640       clear.h = h;
641       clear.clear_color = color;
642
643       ret = drmCommandWrite( mmesa->driFd, DRM_MACH64_CLEAR,
644                                 &clear, sizeof(drm_mach64_clear_t) );
645
646       if (ret < 0) {
647          UNLOCK_HARDWARE( mmesa );
648          fprintf( stderr, "DRM_MACH64_CLEAR: return = %d\n", ret );
649          exit( -1 );
650       }
651    }
652
653    /* restore cliprects */
654    mmesa->sarea->nbox = nbox;
655    b[0].x1 = x1;
656    b[0].y1 = y1;
657    b[0].x2 = x2;
658    b[0].y2 = y2;
659
660 }
661
662 #endif
663
664 /* ================================================================
665  * Buffer clear
666  */
667
668 static void mach64DDClear( struct gl_context *ctx, GLbitfield mask )
669 {
670    mach64ContextPtr mmesa = MACH64_CONTEXT( ctx );
671    __DRIdrawable *dPriv = mmesa->driDrawable;
672    drm_mach64_clear_t clear;
673    GLuint flags = 0;
674    GLint i;
675    GLint ret;
676    GLint cx, cy, cw, ch;
677
678    if ( MACH64_DEBUG & DEBUG_VERBOSE_API ) {
679       fprintf( stderr, "mach64DDClear\n");
680    }
681
682 #if ENABLE_PERF_BOXES
683    /* Bump the performance counter */
684    mmesa->c_clears++;
685 #endif
686
687    FLUSH_BATCH( mmesa );
688
689    /* The only state changes we care about here are the RGBA colormask
690     * and scissor/clipping.  We'll just update that state, if needed.
691     */
692    if ( mmesa->new_state & (MACH64_NEW_MASKS | MACH64_NEW_CLIP) ) {
693       const GLuint save_state = mmesa->new_state;
694       mmesa->new_state &= (MACH64_NEW_MASKS | MACH64_NEW_CLIP);
695       mach64DDUpdateHWState( ctx );
696       mmesa->new_state = save_state & ~(MACH64_NEW_MASKS | MACH64_NEW_CLIP);
697    }
698
699    if ( mask & BUFFER_BIT_FRONT_LEFT ) {
700       flags |= MACH64_FRONT;
701       mask &= ~BUFFER_BIT_FRONT_LEFT;
702    }
703
704    if ( mask & BUFFER_BIT_BACK_LEFT ) {
705       flags |= MACH64_BACK;
706       mask &= ~BUFFER_BIT_BACK_LEFT;
707    }
708
709    if ( ( mask & BUFFER_BIT_DEPTH ) && ctx->Depth.Mask ) {
710       flags |= MACH64_DEPTH;
711       mask &= ~BUFFER_BIT_DEPTH;
712    }
713
714    if ( mask )
715       _swrast_Clear( ctx, mask );
716
717    if ( !flags )
718       return;
719
720    LOCK_HARDWARE( mmesa );
721
722    /* compute region after locking: */
723    cx = ctx->DrawBuffer->_Xmin;
724    cy = ctx->DrawBuffer->_Ymin;
725    cw = ctx->DrawBuffer->_Xmax - cx;
726    ch = ctx->DrawBuffer->_Ymax - cy;
727
728    /* Flip top to bottom */
729    cx += mmesa->drawX;
730    cy  = mmesa->drawY + dPriv->h - cy - ch;
731
732    /* HACK?
733     */
734    if ( mmesa->dirty & ~MACH64_UPLOAD_CLIPRECTS ) {
735       mach64EmitHwStateLocked( mmesa );
736    }
737
738    for ( i = 0 ; i < mmesa->numClipRects ; ) {
739       int nr = MIN2( i + MACH64_NR_SAREA_CLIPRECTS, mmesa->numClipRects );
740       drm_clip_rect_t *box = mmesa->pClipRects;
741       drm_clip_rect_t *b = mmesa->sarea->boxes;
742       GLint n = 0;
743
744       if (cw != dPriv->w || ch != dPriv->h) {
745          /* clear subregion */
746          for ( ; i < nr ; i++ ) {
747             GLint x = box[i].x1;
748             GLint y = box[i].y1;
749             GLint w = box[i].x2 - x;
750             GLint h = box[i].y2 - y;
751
752             if ( x < cx ) w -= cx - x, x = cx;
753             if ( y < cy ) h -= cy - y, y = cy;
754             if ( x + w > cx + cw ) w = cx + cw - x;
755             if ( y + h > cy + ch ) h = cy + ch - y;
756             if ( w <= 0 ) continue;
757             if ( h <= 0 ) continue;
758
759             b->x1 = x;
760             b->y1 = y;
761             b->x2 = x + w;
762             b->y2 = y + h;
763             b++;
764             n++;
765          }
766       } else {
767          /* clear whole window */
768          for ( ; i < nr ; i++ ) {
769             *b++ = box[i];
770             n++;
771          }
772       }
773
774       mmesa->sarea->nbox = n;
775
776       if ( MACH64_DEBUG & DEBUG_VERBOSE_IOCTL ) {
777          fprintf( stderr,
778                   "DRM_MACH64_CLEAR: flag 0x%x color %x depth %x nbox %d\n",
779                   flags,
780                   (GLuint)mmesa->ClearColor,
781                   (GLuint)mmesa->ClearDepth,
782                   mmesa->sarea->nbox );
783       }
784
785       clear.flags = flags;
786       clear.x = cx;
787       clear.y = cy;
788       clear.w = cw;
789       clear.h = ch;
790       clear.clear_color = mmesa->ClearColor;
791       clear.clear_depth = mmesa->ClearDepth;
792
793       ret = drmCommandWrite( mmesa->driFd, DRM_MACH64_CLEAR,
794                              &clear, sizeof(drm_mach64_clear_t) );
795
796       if ( ret ) {
797          UNLOCK_HARDWARE( mmesa );
798          fprintf( stderr, "DRM_MACH64_CLEAR: return = %d\n", ret );
799          exit( -1 );
800       }
801    }
802
803    UNLOCK_HARDWARE( mmesa );
804
805    mmesa->dirty |= (MACH64_UPLOAD_CONTEXT |
806                     MACH64_UPLOAD_MISC |
807                     MACH64_UPLOAD_CLIPRECTS);
808
809 }
810
811
812 void mach64WaitForIdleLocked( mach64ContextPtr mmesa )
813 {
814    int fd = mmesa->driFd;
815    int to = 0;
816    int ret;
817
818    do {
819       ret = drmCommandNone( fd, DRM_MACH64_IDLE );
820    } while ( ( ret == -EBUSY ) && ( to++ < MACH64_TIMEOUT ) );
821
822    if ( ret < 0 ) {
823       drmCommandNone( fd, DRM_MACH64_RESET );
824       UNLOCK_HARDWARE( mmesa );
825       fprintf( stderr, "Error: Mach64 timed out... exiting\n" );
826       exit( -1 );
827    }
828 }
829
830 /* Flush the DMA queue to the hardware */
831 void mach64FlushDMALocked( mach64ContextPtr mmesa )
832 {
833    int fd = mmesa->driFd;
834    int ret;
835
836    ret = drmCommandNone( fd, DRM_MACH64_FLUSH );
837
838    if ( ret < 0 ) {
839       drmCommandNone( fd, DRM_MACH64_RESET );
840       UNLOCK_HARDWARE( mmesa );
841       fprintf( stderr, "Error flushing DMA... exiting\n" );
842       exit( -1 );
843    }
844
845    mmesa->dirty |= (MACH64_UPLOAD_CONTEXT |
846                     MACH64_UPLOAD_MISC |
847                     MACH64_UPLOAD_CLIPRECTS);
848
849 }
850
851 /* For client-side state emits - currently unused */
852 void mach64UploadHwStateLocked( mach64ContextPtr mmesa )
853 {
854    drm_mach64_sarea_t *sarea = mmesa->sarea;
855    
856    drm_mach64_context_regs_t *regs = &sarea->context_state;
857    unsigned int dirty = sarea->dirty;
858    CARD32 offset = ((regs->tex_size_pitch & 0xf0) >> 2);
859
860    DMALOCALS;
861
862    DMAGETPTR( 19*2 );
863
864    if ( dirty & MACH64_UPLOAD_MISC ) {
865       DMAOUTREG( MACH64_DP_MIX, regs->dp_mix );
866       DMAOUTREG( MACH64_DP_SRC, regs->dp_src );
867       DMAOUTREG( MACH64_CLR_CMP_CNTL, regs->clr_cmp_cntl );
868       DMAOUTREG( MACH64_GUI_TRAJ_CNTL, regs->gui_traj_cntl );
869       DMAOUTREG( MACH64_SC_LEFT_RIGHT, regs->sc_left_right );
870       DMAOUTREG( MACH64_SC_TOP_BOTTOM, regs->sc_top_bottom );
871       sarea->dirty &= ~MACH64_UPLOAD_MISC;
872    }
873
874    if ( dirty & MACH64_UPLOAD_DST_OFF_PITCH ) {
875       DMAOUTREG( MACH64_DST_OFF_PITCH, regs->dst_off_pitch );
876       sarea->dirty &= ~MACH64_UPLOAD_DST_OFF_PITCH;
877    }
878    if ( dirty & MACH64_UPLOAD_Z_OFF_PITCH ) {
879       DMAOUTREG( MACH64_Z_OFF_PITCH, regs->z_off_pitch );
880       sarea->dirty &= ~MACH64_UPLOAD_Z_OFF_PITCH;
881    }
882    if ( dirty & MACH64_UPLOAD_Z_ALPHA_CNTL ) {
883       DMAOUTREG( MACH64_Z_CNTL, regs->z_cntl );
884       DMAOUTREG( MACH64_ALPHA_TST_CNTL, regs->alpha_tst_cntl );
885       sarea->dirty &= ~MACH64_UPLOAD_Z_ALPHA_CNTL;
886    }
887    if ( dirty & MACH64_UPLOAD_SCALE_3D_CNTL ) {
888       DMAOUTREG( MACH64_SCALE_3D_CNTL, regs->scale_3d_cntl );
889       sarea->dirty &= ~MACH64_UPLOAD_SCALE_3D_CNTL;
890    }
891    if ( dirty & MACH64_UPLOAD_DP_FOG_CLR ) {
892       DMAOUTREG( MACH64_DP_FOG_CLR, regs->dp_fog_clr );
893       sarea->dirty &= ~MACH64_UPLOAD_DP_FOG_CLR;
894    }
895    if ( dirty & MACH64_UPLOAD_DP_WRITE_MASK ) {
896       DMAOUTREG( MACH64_DP_WRITE_MASK, regs->dp_write_mask );
897       sarea->dirty &= ~MACH64_UPLOAD_DP_WRITE_MASK;
898    }
899    if ( dirty & MACH64_UPLOAD_DP_PIX_WIDTH ) {
900       DMAOUTREG( MACH64_DP_PIX_WIDTH, regs->dp_pix_width );
901       sarea->dirty &= ~MACH64_UPLOAD_DP_PIX_WIDTH;
902    }
903    if ( dirty & MACH64_UPLOAD_SETUP_CNTL ) {
904       DMAOUTREG( MACH64_SETUP_CNTL, regs->setup_cntl );
905       sarea->dirty &= ~MACH64_UPLOAD_SETUP_CNTL;
906    }
907
908    if ( dirty & MACH64_UPLOAD_TEXTURE ) {
909       DMAOUTREG( MACH64_TEX_SIZE_PITCH, regs->tex_size_pitch );
910       DMAOUTREG( MACH64_TEX_CNTL, regs->tex_cntl );
911       DMAOUTREG( MACH64_SECONDARY_TEX_OFF, regs->secondary_tex_off );
912       DMAOUTREG( MACH64_TEX_0_OFF + offset, regs->tex_offset );
913       sarea->dirty &= ~MACH64_UPLOAD_TEXTURE;
914    }
915
916 #if 0
917    if ( dirty & MACH64_UPLOAD_CLIPRECTS ) {
918       DMAOUTREG( MACH64_SC_LEFT_RIGHT, regs->sc_left_right );
919       DMAOUTREG( MACH64_SC_TOP_BOTTOM, regs->sc_top_bottom );
920       sarea->dirty &= ~MACH64_UPLOAD_CLIPRECTS;
921    }
922 #endif
923
924    sarea->dirty = 0;
925
926    DMAADVANCE();
927 }
928
929 void mach64InitIoctlFuncs( struct dd_function_table *functions )
930 {
931     functions->Clear = mach64DDClear;
932 }