Tizen 2.0 Release
[profile/ivi/osmesa.git] / src / mesa / drivers / dri / r128 / r128_ioctl.c
1 /**************************************************************************
2
3 Copyright 1999, 2000 ATI Technologies Inc. and Precision Insight, Inc.,
4                                                Cedar Park, Texas.
5 All Rights Reserved.
6
7 Permission is hereby granted, free of charge, to any person obtaining a
8 copy of this software and associated documentation files (the "Software"),
9 to deal in the Software without restriction, including without limitation
10 on the rights to use, copy, modify, merge, publish, distribute, sub
11 license, and/or sell copies of the Software, and to permit persons to whom
12 the Software is furnished to do so, subject to the following conditions:
13
14 The above copyright notice and this permission notice (including the next
15 paragraph) shall be included in all copies or substantial portions of the
16 Software.
17
18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
21 ATI, PRECISION INSIGHT AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
22 DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
23 OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
24 USE OR OTHER DEALINGS IN THE SOFTWARE.
25
26 **************************************************************************/
27
28 /*
29  * Authors:
30  *   Gareth Hughes <gareth@valinux.com>
31  *
32  */
33 #include <errno.h>
34
35 #define STANDALONE_MMIO
36 #include "r128_context.h"
37 #include "r128_state.h"
38 #include "r128_ioctl.h"
39 #include "main/imports.h"
40 #include "main/macros.h"
41
42 #include "swrast/swrast.h"
43
44 #include "vblank.h"
45 #include "mmio.h"
46 #include "drirenderbuffer.h"
47
48 #define R128_TIMEOUT        2048
49 #define R128_IDLE_RETRY       32
50
51
52 /* =============================================================
53  * Hardware vertex buffer handling
54  */
55
56 /* Get a new VB from the pool of vertex buffers in AGP space.
57  */
58 drmBufPtr r128GetBufferLocked( r128ContextPtr rmesa )
59 {
60    int fd = rmesa->r128Screen->driScreen->fd;
61    int index = 0;
62    int size = 0;
63    drmDMAReq dma;
64    drmBufPtr buf = NULL;
65    int to = 0;
66    int ret;
67
68    dma.context = rmesa->hHWContext;
69    dma.send_count = 0;
70    dma.send_list = NULL;
71    dma.send_sizes = NULL;
72    dma.flags = 0;
73    dma.request_count = 1;
74    dma.request_size = R128_BUFFER_SIZE;
75    dma.request_list = &index;
76    dma.request_sizes = &size;
77    dma.granted_count = 0;
78
79    while ( !buf && ( to++ < R128_TIMEOUT ) ) {
80       ret = drmDMA( fd, &dma );
81
82       if ( ret == 0 ) {
83          buf = &rmesa->r128Screen->buffers->list[index];
84          buf->used = 0;
85 #if ENABLE_PERF_BOXES
86          /* Bump the performance counter */
87          rmesa->c_vertexBuffers++;
88 #endif
89          return buf;
90       }
91    }
92
93    if ( !buf ) {
94       drmCommandNone( fd, DRM_R128_CCE_RESET);
95       UNLOCK_HARDWARE( rmesa );
96       fprintf( stderr, "Error: Could not get new VB... exiting\n" );
97       exit( -1 );
98    }
99
100    return buf;
101 }
102
103 void r128FlushVerticesLocked( r128ContextPtr rmesa )
104 {
105    drm_clip_rect_t *pbox = rmesa->pClipRects;
106    int nbox = rmesa->numClipRects;
107    drmBufPtr buffer = rmesa->vert_buf;
108    int count = rmesa->num_verts;
109    int prim = rmesa->hw_primitive;
110    int fd = rmesa->driScreen->fd;
111    drm_r128_vertex_t vertex;
112    int i;
113
114    rmesa->num_verts = 0;
115    rmesa->vert_buf = NULL;
116
117    if ( !buffer )
118       return;
119
120    if ( rmesa->dirty & ~R128_UPLOAD_CLIPRECTS )
121       r128EmitHwStateLocked( rmesa );
122
123    if ( !nbox )
124       count = 0;
125
126    if ( nbox >= R128_NR_SAREA_CLIPRECTS )
127       rmesa->dirty |= R128_UPLOAD_CLIPRECTS;
128
129    if ( !count || !(rmesa->dirty & R128_UPLOAD_CLIPRECTS) )
130    {
131       if ( nbox < 3 ) {
132          rmesa->sarea->nbox = 0;
133       } else {
134          rmesa->sarea->nbox = nbox;
135       }
136
137       vertex.prim = prim;
138       vertex.idx = buffer->idx;
139       vertex.count = count;
140       vertex.discard = 1;
141       drmCommandWrite( fd, DRM_R128_VERTEX, &vertex, sizeof(vertex) );
142    }
143    else
144    {
145       for ( i = 0 ; i < nbox ; ) {
146          int nr = MIN2( i + R128_NR_SAREA_CLIPRECTS, nbox );
147          drm_clip_rect_t *b = rmesa->sarea->boxes;
148          int discard = 0;
149
150          rmesa->sarea->nbox = nr - i;
151          for ( ; i < nr ; i++ ) {
152             *b++ = pbox[i];
153          }
154
155          /* Finished with the buffer?
156           */
157          if ( nr == nbox ) {
158             discard = 1;
159          }
160
161          rmesa->sarea->dirty |= R128_UPLOAD_CLIPRECTS;
162
163          vertex.prim = prim;
164          vertex.idx = buffer->idx;
165          vertex.count = count;
166          vertex.discard = discard;
167          drmCommandWrite( fd, DRM_R128_VERTEX, &vertex, sizeof(vertex) );
168       }
169    }
170
171    rmesa->dirty &= ~R128_UPLOAD_CLIPRECTS;
172 }
173
174
175
176
177
178 /* ================================================================
179  * Texture uploads
180  */
181
182 void r128FireBlitLocked( r128ContextPtr rmesa, drmBufPtr buffer,
183                          GLint offset, GLint pitch, GLint format,
184                          GLint x, GLint y, GLint width, GLint height )
185 {
186    drm_r128_blit_t blit;
187    GLint ret;
188
189    blit.idx = buffer->idx;
190    blit.offset = offset;
191    blit.pitch = pitch;
192    blit.format = format;
193    blit.x = x;
194    blit.y = y;
195    blit.width = width;
196    blit.height = height;
197
198    ret = drmCommandWrite( rmesa->driFd, DRM_R128_BLIT, 
199                           &blit, sizeof(blit) );
200
201    if ( ret ) {
202       UNLOCK_HARDWARE( rmesa );
203       fprintf( stderr, "DRM_R128_BLIT: return = %d\n", ret );
204       exit( 1 );
205    }
206 }
207
208
209 /* ================================================================
210  * SwapBuffers with client-side throttling
211  */
212
213 static void delay( void ) {
214 /* Prevent an optimizing compiler from removing a spin loop */
215 }
216
217 #define R128_MAX_OUTSTANDING    2
218
219
220 /* Throttle the frame rate -- only allow one pending swap buffers
221  * request at a time.
222  * GH: We probably don't want a timeout here, as we can wait as
223  * long as we want for a frame to complete.  If it never does, then
224  * the card has locked.
225  */
226 static int r128WaitForFrameCompletion( r128ContextPtr rmesa )
227 {
228    unsigned char *R128MMIO = rmesa->r128Screen->mmio.map;
229    int i;
230    int wait = 0;
231
232    while ( 1 ) {
233       uint32_t frame = read_MMIO_LE32( R128MMIO, R128_LAST_FRAME_REG );
234
235       if ( rmesa->sarea->last_frame - frame <= R128_MAX_OUTSTANDING ) {
236          break;
237       }
238
239       /* Spin in place a bit so we aren't hammering the register */
240       wait++;
241       for ( i = 0 ; i < 1024 ; i++ ) {
242          delay();
243       }
244    }
245
246    return wait;
247 }
248
249 /* Copy the back color buffer to the front color buffer.
250  */
251 void r128CopyBuffer( __DRIdrawable *dPriv )
252 {
253    r128ContextPtr rmesa;
254    GLint nbox, i, ret;
255    GLboolean missed_target;
256
257    assert(dPriv);
258    assert(dPriv->driContextPriv);
259    assert(dPriv->driContextPriv->driverPrivate);
260
261    rmesa = (r128ContextPtr) dPriv->driContextPriv->driverPrivate;
262
263    if ( R128_DEBUG & DEBUG_VERBOSE_API ) {
264       fprintf( stderr, "\n********************************\n" );
265       fprintf( stderr, "\n%s( %p )\n\n",
266                __FUNCTION__, (void *)rmesa->glCtx );
267       fflush( stderr );
268    }
269
270    FLUSH_BATCH( rmesa );
271
272    LOCK_HARDWARE( rmesa );
273
274    /* Throttle the frame rate -- only allow one pending swap buffers
275     * request at a time.
276     */
277    if ( !r128WaitForFrameCompletion( rmesa ) ) {
278       rmesa->hardwareWentIdle = 1;
279    } else {
280       rmesa->hardwareWentIdle = 0;
281    }
282
283    UNLOCK_HARDWARE( rmesa );
284    driWaitForVBlank( dPriv, &missed_target );
285    LOCK_HARDWARE( rmesa );
286
287    nbox = dPriv->numClipRects;  /* must be in locked region */
288
289    for ( i = 0 ; i < nbox ; ) {
290       GLint nr = MIN2( i + R128_NR_SAREA_CLIPRECTS , nbox );
291       drm_clip_rect_t *box = dPriv->pClipRects;
292       drm_clip_rect_t *b = rmesa->sarea->boxes;
293       GLint n = 0;
294
295       for ( ; i < nr ; i++ ) {
296          *b++ = box[i];
297          n++;
298       }
299       rmesa->sarea->nbox = n;
300
301       ret = drmCommandNone( rmesa->driFd, DRM_R128_SWAP );
302
303       if ( ret ) {
304          UNLOCK_HARDWARE( rmesa );
305          fprintf( stderr, "DRM_R128_SWAP: return = %d\n", ret );
306          exit( 1 );
307       }
308    }
309
310    if ( R128_DEBUG & DEBUG_ALWAYS_SYNC ) {
311       i = 0;
312       do {
313          ret = drmCommandNone(rmesa->driFd, DRM_R128_CCE_IDLE);
314       } while ( ret && errno == EBUSY && i++ < R128_IDLE_RETRY );
315    }
316
317    UNLOCK_HARDWARE( rmesa );
318
319    rmesa->new_state |= R128_NEW_CONTEXT;
320    rmesa->dirty |= (R128_UPLOAD_CONTEXT |
321                     R128_UPLOAD_MASKS |
322                     R128_UPLOAD_CLIPRECTS);
323
324 #if ENABLE_PERF_BOXES
325    /* Log the performance counters if necessary */
326    r128PerformanceCounters( rmesa );
327 #endif
328 }
329
330 void r128PageFlip( __DRIdrawable *dPriv )
331 {
332    r128ContextPtr rmesa;
333    GLint ret;
334    GLboolean missed_target;
335
336    assert(dPriv);
337    assert(dPriv->driContextPriv);
338    assert(dPriv->driContextPriv->driverPrivate);
339
340    rmesa = (r128ContextPtr) dPriv->driContextPriv->driverPrivate;
341
342    if ( R128_DEBUG & DEBUG_VERBOSE_API ) {
343       fprintf( stderr, "\n%s( %p ): page=%d\n\n",
344                __FUNCTION__, (void *)rmesa->glCtx, rmesa->sarea->pfCurrentPage );
345    }
346
347    FLUSH_BATCH( rmesa );
348
349    LOCK_HARDWARE( rmesa );
350
351    /* Throttle the frame rate -- only allow one pending swap buffers
352     * request at a time.
353     */
354    if ( !r128WaitForFrameCompletion( rmesa ) ) {
355       rmesa->hardwareWentIdle = 1;
356    } else {
357       rmesa->hardwareWentIdle = 0;
358    }
359
360    UNLOCK_HARDWARE( rmesa );
361    driWaitForVBlank( dPriv, &missed_target );
362    LOCK_HARDWARE( rmesa );
363
364    /* The kernel will have been initialized to perform page flipping
365     * on a swapbuffers ioctl.
366     */
367    ret = drmCommandNone( rmesa->driFd, DRM_R128_FLIP );
368
369    UNLOCK_HARDWARE( rmesa );
370
371    if ( ret ) {
372       fprintf( stderr, "DRM_R128_FLIP: return = %d\n", ret );
373       exit( 1 );
374    }
375
376    /* Get ready for drawing next frame.  Update the renderbuffers'
377     * flippedOffset/Pitch fields so we draw into the right place.
378     */
379    driFlipRenderbuffers(rmesa->glCtx->WinSysDrawBuffer,
380                         rmesa->sarea->pfCurrentPage);
381
382    rmesa->new_state |= R128_NEW_WINDOW;
383
384    /* FIXME: Do we need this anymore? */
385    rmesa->new_state |= R128_NEW_CONTEXT;
386    rmesa->dirty |= (R128_UPLOAD_CONTEXT |
387                     R128_UPLOAD_MASKS |
388                     R128_UPLOAD_CLIPRECTS);
389
390 #if ENABLE_PERF_BOXES
391    /* Log the performance counters if necessary */
392    r128PerformanceCounters( rmesa );
393 #endif
394 }
395
396
397 /* ================================================================
398  * Buffer clear
399  */
400
401 static void r128Clear( struct gl_context *ctx, GLbitfield mask )
402 {
403    r128ContextPtr rmesa = R128_CONTEXT(ctx);
404    __DRIdrawable *dPriv = rmesa->driDrawable;
405    drm_r128_clear_t clear;
406    GLuint flags = 0;
407    GLint i;
408    GLint ret;
409    GLuint depthmask = 0;
410    GLint cx, cy, cw, ch;
411
412    if ( R128_DEBUG & DEBUG_VERBOSE_API ) {
413       fprintf( stderr, "%s:\n", __FUNCTION__ );
414    }
415
416    FLUSH_BATCH( rmesa );
417
418    /* The only state change we care about here is the RGBA colormask
419     * We'll just update that state, if needed.  If we do more then
420     * there's some strange side-effects that the conformance tests find.
421     */
422    if ( rmesa->new_state & R128_NEW_MASKS) {
423       const GLuint save_state = rmesa->new_state;
424       rmesa->new_state = R128_NEW_MASKS;
425       r128DDUpdateHWState( ctx );
426       rmesa->new_state = save_state & ~R128_NEW_MASKS;
427    }
428
429    if ( mask & BUFFER_BIT_FRONT_LEFT ) {
430       flags |= R128_FRONT;
431       mask &= ~BUFFER_BIT_FRONT_LEFT;
432    }
433
434    if ( mask & BUFFER_BIT_BACK_LEFT ) {
435       flags |= R128_BACK;
436       mask &= ~BUFFER_BIT_BACK_LEFT;
437    }
438
439    if ( ( mask & BUFFER_BIT_DEPTH ) && ctx->Depth.Mask ) {
440       flags |= R128_DEPTH;
441       /* if we're at 16 bits, extra plane mask won't hurt */
442       depthmask |= 0x00ffffff;
443       mask &= ~BUFFER_BIT_DEPTH;
444    }
445
446    if ( mask & BUFFER_BIT_STENCIL &&
447         (ctx->Visual.stencilBits > 0 && ctx->Visual.depthBits == 24) ) {
448       flags |= R128_DEPTH;
449       depthmask |= ctx->Stencil.WriteMask[0] << 24;
450       mask &= ~BUFFER_BIT_STENCIL;
451    }
452
453    if ( flags ) {
454
455       LOCK_HARDWARE( rmesa );
456
457       /* compute region after locking: */
458       cx = ctx->DrawBuffer->_Xmin;
459       cy = ctx->DrawBuffer->_Ymin;
460       cw = ctx->DrawBuffer->_Xmax - cx;
461       ch = ctx->DrawBuffer->_Ymax - cy;
462
463       /* Flip top to bottom */
464       cx += dPriv->x;
465       cy  = dPriv->y + dPriv->h - cy - ch;
466
467       /* FIXME: Do we actually need this?
468        */
469       if ( rmesa->dirty & ~R128_UPLOAD_CLIPRECTS ) {
470          r128EmitHwStateLocked( rmesa );
471       }
472
473       for ( i = 0 ; i < rmesa->numClipRects ; ) {
474          GLint nr = MIN2( i + R128_NR_SAREA_CLIPRECTS , rmesa->numClipRects );
475          drm_clip_rect_t *box = rmesa->pClipRects;
476          drm_clip_rect_t *b = rmesa->sarea->boxes;
477          GLint n = 0;
478
479          if (cw != dPriv->w || ch != dPriv->h) {
480             /* clear subregion */
481             for ( ; i < nr ; i++ ) {
482                GLint x = box[i].x1;
483                GLint y = box[i].y1;
484                GLint w = box[i].x2 - x;
485                GLint h = box[i].y2 - y;
486
487                if ( x < cx ) w -= cx - x, x = cx;
488                if ( y < cy ) h -= cy - y, y = cy;
489                if ( x + w > cx + cw ) w = cx + cw - x;
490                if ( y + h > cy + ch ) h = cy + ch - y;
491                if ( w <= 0 ) continue;
492                if ( h <= 0 ) continue;
493
494                b->x1 = x;
495                b->y1 = y;
496                b->x2 = x + w;
497                b->y2 = y + h;
498                b++;
499                n++;
500             }
501          } else {
502             /* clear whole window */
503             for ( ; i < nr ; i++ ) {
504                *b++ = box[i];
505                n++;
506             }
507          }
508
509          rmesa->sarea->nbox = n;
510
511          if ( R128_DEBUG & DEBUG_VERBOSE_IOCTL ) {
512             fprintf( stderr,
513                      "DRM_R128_CLEAR: flag 0x%x color %x depth %x nbox %d\n",
514                      flags,
515                      (GLuint)rmesa->ClearColor,
516                      (GLuint)rmesa->ClearDepth,
517                      rmesa->sarea->nbox );
518          }
519
520          clear.flags = flags;
521          clear.clear_color = rmesa->ClearColor;
522          clear.clear_depth = rmesa->ClearDepth;
523          clear.color_mask = rmesa->setup.plane_3d_mask_c;
524          clear.depth_mask = depthmask;
525
526          ret = drmCommandWrite( rmesa->driFd, DRM_R128_CLEAR,
527                                 &clear, sizeof(clear) );
528
529          if ( ret ) {
530             UNLOCK_HARDWARE( rmesa );
531             fprintf( stderr, "DRM_R128_CLEAR: return = %d\n", ret );
532             exit( 1 );
533          }
534       }
535
536       UNLOCK_HARDWARE( rmesa );
537
538       rmesa->dirty |= R128_UPLOAD_CLIPRECTS;
539    }
540
541    if ( mask )
542       _swrast_Clear( ctx, mask );
543 }
544
545
546 /* ================================================================
547  * Depth spans, pixels
548  */
549
550 void r128WriteDepthSpanLocked( r128ContextPtr rmesa,
551                                GLuint n, GLint x, GLint y,
552                                const GLuint depth[],
553                                const GLubyte mask[] )
554 {
555    drm_clip_rect_t *pbox = rmesa->pClipRects;
556    drm_r128_depth_t d;
557    int nbox = rmesa->numClipRects;
558    int fd = rmesa->driScreen->fd;
559    int i;
560
561    if ( !nbox || !n ) {
562       return;
563    }
564    if ( nbox >= R128_NR_SAREA_CLIPRECTS ) {
565       rmesa->dirty |= R128_UPLOAD_CLIPRECTS;
566    }
567
568    if ( !(rmesa->dirty & R128_UPLOAD_CLIPRECTS) )
569    {
570       if ( nbox < 3 ) {
571          rmesa->sarea->nbox = 0;
572       } else {
573          rmesa->sarea->nbox = nbox;
574       }
575
576       d.func = R128_WRITE_SPAN;
577       d.n = n;
578       d.x = (int*)&x;
579       d.y = (int*)&y;
580       d.buffer = (unsigned int *)depth;
581       d.mask = (unsigned char *)mask;
582
583       drmCommandWrite( fd, DRM_R128_DEPTH, &d, sizeof(d));
584
585    }
586    else
587    {
588       for (i = 0 ; i < nbox ; ) {
589          int nr = MIN2( i + R128_NR_SAREA_CLIPRECTS, nbox );
590          drm_clip_rect_t *b = rmesa->sarea->boxes;
591
592          rmesa->sarea->nbox = nr - i;
593          for ( ; i < nr ; i++) {
594             *b++ = pbox[i];
595          }
596
597          rmesa->sarea->dirty |= R128_UPLOAD_CLIPRECTS;
598
599          d.func = R128_WRITE_SPAN;
600          d.n = n;
601          d.x = (int*)&x;
602          d.y = (int*)&y;
603          d.buffer = (unsigned int *)depth;
604          d.mask = (unsigned char *)mask;
605
606          drmCommandWrite( fd, DRM_R128_DEPTH, &d, sizeof(d));
607       }
608    }
609
610    rmesa->dirty &= ~R128_UPLOAD_CLIPRECTS;
611 }
612
613 void r128WriteDepthPixelsLocked( r128ContextPtr rmesa, GLuint n,
614                                  const GLint x[], const GLint y[],
615                                  const GLuint depth[],
616                                  const GLubyte mask[] )
617 {
618    drm_clip_rect_t *pbox = rmesa->pClipRects;
619    drm_r128_depth_t d;
620    int nbox = rmesa->numClipRects;
621    int fd = rmesa->driScreen->fd;
622    int i;
623
624    if ( !nbox || !n ) {
625       return;
626    }
627    if ( nbox >= R128_NR_SAREA_CLIPRECTS ) {
628       rmesa->dirty |= R128_UPLOAD_CLIPRECTS;
629    }
630
631    if ( !(rmesa->dirty & R128_UPLOAD_CLIPRECTS) )
632    {
633       if ( nbox < 3 ) {
634          rmesa->sarea->nbox = 0;
635       } else {
636          rmesa->sarea->nbox = nbox;
637       }
638
639       d.func = R128_WRITE_PIXELS;
640       d.n = n;
641       d.x = (int*)&x;
642       d.y = (int*)&y;
643       d.buffer = (unsigned int *)depth;
644       d.mask = (unsigned char *)mask;
645
646       drmCommandWrite( fd, DRM_R128_DEPTH, &d, sizeof(d));
647    }
648    else
649    {
650       for (i = 0 ; i < nbox ; ) {
651          int nr = MIN2( i + R128_NR_SAREA_CLIPRECTS, nbox );
652          drm_clip_rect_t *b = rmesa->sarea->boxes;
653
654          rmesa->sarea->nbox = nr - i;
655          for ( ; i < nr ; i++) {
656             *b++ = pbox[i];
657          }
658
659          rmesa->sarea->dirty |= R128_UPLOAD_CLIPRECTS;
660
661          d.func = R128_WRITE_PIXELS;
662          d.n = n;
663          d.x = (int*)&x;
664          d.y = (int*)&y;
665          d.buffer = (unsigned int *)depth;
666          d.mask = (unsigned char *)mask;
667
668          drmCommandWrite( fd, DRM_R128_DEPTH, &d, sizeof(d));
669       }
670    }
671
672    rmesa->dirty &= ~R128_UPLOAD_CLIPRECTS;
673 }
674
675 void r128ReadDepthSpanLocked( r128ContextPtr rmesa,
676                               GLuint n, GLint x, GLint y )
677 {
678    drm_clip_rect_t *pbox = rmesa->pClipRects;
679    drm_r128_depth_t d;
680    int nbox = rmesa->numClipRects;
681    int fd = rmesa->driScreen->fd;
682    int i;
683
684    if ( !nbox || !n ) {
685       return;
686    }
687    if ( nbox >= R128_NR_SAREA_CLIPRECTS ) {
688       rmesa->dirty |= R128_UPLOAD_CLIPRECTS;
689    }
690
691    if ( !(rmesa->dirty & R128_UPLOAD_CLIPRECTS) )
692    {
693       if ( nbox < 3 ) {
694          rmesa->sarea->nbox = 0;
695       } else {
696          rmesa->sarea->nbox = nbox;
697       }
698
699       d.func = R128_READ_SPAN;
700       d.n = n;
701       d.x = (int*)&x;
702       d.y = (int*)&y;
703       d.buffer = NULL;
704       d.mask = NULL;
705
706       drmCommandWrite( fd, DRM_R128_DEPTH, &d, sizeof(d));
707    }
708    else
709    {
710       for (i = 0 ; i < nbox ; ) {
711          int nr = MIN2( i + R128_NR_SAREA_CLIPRECTS, nbox );
712          drm_clip_rect_t *b = rmesa->sarea->boxes;
713
714          rmesa->sarea->nbox = nr - i;
715          for ( ; i < nr ; i++) {
716             *b++ = pbox[i];
717          }
718
719          rmesa->sarea->dirty |= R128_UPLOAD_CLIPRECTS;
720
721          d.func = R128_READ_SPAN;
722          d.n = n;
723          d.x = (int*)&x;
724          d.y = (int*)&y;
725          d.buffer = NULL;
726          d.mask = NULL;
727
728          drmCommandWrite( fd, DRM_R128_DEPTH, &d, sizeof(d));
729       }
730    }
731
732    rmesa->dirty &= ~R128_UPLOAD_CLIPRECTS;
733 }
734
735 void r128ReadDepthPixelsLocked( r128ContextPtr rmesa, GLuint n,
736                                 const GLint x[], const GLint y[] )
737 {
738    drm_clip_rect_t *pbox = rmesa->pClipRects;
739    drm_r128_depth_t d;
740    int nbox = rmesa->numClipRects;
741    int fd = rmesa->driScreen->fd;
742    int i;
743
744    if ( !nbox || !n ) {
745       return;
746    }
747    if ( nbox >= R128_NR_SAREA_CLIPRECTS ) {
748       rmesa->dirty |= R128_UPLOAD_CLIPRECTS;
749    }
750
751    if ( !(rmesa->dirty & R128_UPLOAD_CLIPRECTS) )
752    {
753       if ( nbox < 3 ) {
754          rmesa->sarea->nbox = 0;
755       } else {
756          rmesa->sarea->nbox = nbox;
757       }
758
759       d.func = R128_READ_PIXELS;
760       d.n = n;
761       d.x = (int*)&x;
762       d.y = (int*)&y;
763       d.buffer = NULL;
764       d.mask = NULL;
765
766       drmCommandWrite( fd, DRM_R128_DEPTH, &d, sizeof(d));
767    }
768    else
769    {
770       for (i = 0 ; i < nbox ; ) {
771          int nr = MIN2( i + R128_NR_SAREA_CLIPRECTS, nbox );
772          drm_clip_rect_t *b = rmesa->sarea->boxes;
773
774          rmesa->sarea->nbox = nr - i;
775          for ( ; i < nr ; i++) {
776             *b++ = pbox[i];
777          }
778
779          rmesa->sarea->dirty |= R128_UPLOAD_CLIPRECTS;
780
781          d.func = R128_READ_PIXELS;
782          d.n = n;
783          d.x = (int*)&x;
784          d.y = (int*)&y;
785          d.buffer = NULL;
786          d.mask = NULL;
787
788          drmCommandWrite( fd, DRM_R128_DEPTH, &d, sizeof(d));
789       }
790    }
791
792    rmesa->dirty &= ~R128_UPLOAD_CLIPRECTS;
793 }
794
795
796 void r128WaitForIdleLocked( r128ContextPtr rmesa )
797 {
798     int fd = rmesa->r128Screen->driScreen->fd;
799     int to = 0;
800     int ret, i;
801
802     do {
803         i = 0;
804         do {
805             ret = drmCommandNone( fd, DRM_R128_CCE_IDLE);
806         } while ( ret && errno == EBUSY && i++ < R128_IDLE_RETRY );
807     } while ( ( ret == -EBUSY ) && ( to++ < R128_TIMEOUT ) );
808
809     if ( ret < 0 ) {
810         drmCommandNone( fd, DRM_R128_CCE_RESET);
811         UNLOCK_HARDWARE( rmesa );
812         fprintf( stderr, "Error: Rage 128 timed out... exiting\n" );
813         exit( -1 );
814     }
815 }
816
817 void r128InitIoctlFuncs( struct dd_function_table *functions )
818 {
819     functions->Clear = r128Clear;
820 }