8f1d9fe59cda5a73f3c81561708a05fa929f9755
[mesa.git] / src / mesa / drivers / dri / r200 / r200_ioctl.c
1 /* $XFree86: xc/lib/GL/mesa/src/drv/r200/r200_ioctl.c,v 1.4 2002/12/17 00:32:56 dawes Exp $ */
2 /*
3 Copyright (C) The Weather Channel, Inc. 2002. All Rights Reserved.
4
5 The Weather Channel (TM) funded Tungsten Graphics to develop the
6 initial release of the Radeon 8500 driver under the XFree86 license.
7 This notice must be preserved.
8
9 Permission is hereby granted, free of charge, to any person obtaining
10 a copy of this software and associated documentation files (the
11 "Software"), to deal in the Software without restriction, including
12 without limitation the rights to use, copy, modify, merge, publish,
13 distribute, sublicense, and/or sell copies of the Software, and to
14 permit persons to whom the Software is furnished to do so, subject to
15 the following conditions:
16
17 The above copyright notice and this permission notice (including the
18 next paragraph) shall be included in all copies or substantial
19 portions of the Software.
20
21 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
24 IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
25 LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
26 OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
27 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28
29 **************************************************************************/
30
31 /*
32 * Authors:
33 * Keith Whitwell <keith@tungstengraphics.com>
34 */
35
36 #include <sched.h>
37 #include <errno.h>
38
39 #include "glheader.h"
40 #include "imports.h"
41 #include "macros.h"
42 #include "context.h"
43 #include "swrast/swrast.h"
44
45 #include "r200_context.h"
46 #include "r200_state.h"
47 #include "r200_ioctl.h"
48 #include "r200_tcl.h"
49 #include "r200_sanity.h"
50 #include "radeon_reg.h"
51
52 #include "vblank.h"
53
54
55 #define R200_TIMEOUT 512
56 #define R200_IDLE_RETRY 16
57
58
59 static void r200WaitForIdle( r200ContextPtr rmesa );
60
61
62 int r200FlushCmdBufLocked( r200ContextPtr rmesa, const char * caller )
63 {
64 int ret, i;
65 drm_radeon_cmd_buffer_t cmd;
66
67 if (R200_DEBUG & DEBUG_IOCTL) {
68 fprintf(stderr, "%s from %s\n", __FUNCTION__, caller);
69
70 if (0 & R200_DEBUG & DEBUG_VERBOSE)
71 for (i = 0 ; i < rmesa->store.cmd_used ; i += 4 )
72 fprintf(stderr, "%d: %x\n", i/4,
73 *(int *)(&rmesa->store.cmd_buf[i]));
74 }
75
76 if (R200_DEBUG & DEBUG_DMA)
77 fprintf(stderr, "%s: Releasing %d buffers\n", __FUNCTION__,
78 rmesa->dma.nr_released_bufs);
79
80
81 if (R200_DEBUG & DEBUG_SANITY) {
82 if (rmesa->state.scissor.enabled)
83 ret = r200SanityCmdBuffer( rmesa,
84 rmesa->state.scissor.numClipRects,
85 rmesa->state.scissor.pClipRects);
86 else
87 ret = r200SanityCmdBuffer( rmesa,
88 rmesa->numClipRects,
89 rmesa->pClipRects);
90 if (ret) {
91 fprintf(stderr, "drmSanityCommandWrite: %d\n", ret);
92 goto out;
93 }
94 }
95
96
97 if (R200_DEBUG & DEBUG_MEMORY) {
98 if (! driValidateTextureHeaps( rmesa->texture_heaps, rmesa->nr_heaps,
99 & rmesa->swapped ) ) {
100 fprintf( stderr, "%s: texture memory is inconsistent - expect "
101 "mangled textures\n", __FUNCTION__ );
102 }
103 }
104
105
106 cmd.bufsz = rmesa->store.cmd_used;
107 cmd.buf = rmesa->store.cmd_buf;
108
109 if (rmesa->state.scissor.enabled) {
110 cmd.nbox = rmesa->state.scissor.numClipRects;
111 cmd.boxes = (drm_clip_rect_t *)rmesa->state.scissor.pClipRects;
112 } else {
113 cmd.nbox = rmesa->numClipRects;
114 cmd.boxes = (drm_clip_rect_t *)rmesa->pClipRects;
115 }
116
117 ret = drmCommandWrite( rmesa->dri.fd,
118 DRM_RADEON_CMDBUF,
119 &cmd, sizeof(cmd) );
120
121 if (ret)
122 fprintf(stderr, "drmCommandWrite: %d\n", ret);
123
124 if (R200_DEBUG & DEBUG_SYNC) {
125 fprintf(stderr, "\nSyncing in %s\n\n", __FUNCTION__);
126 r200WaitForIdleLocked( rmesa );
127 }
128
129
130 out:
131 rmesa->store.primnr = 0;
132 rmesa->store.statenr = 0;
133 rmesa->store.cmd_used = 0;
134 rmesa->dma.nr_released_bufs = 0;
135 rmesa->lost_context = 1;
136 return ret;
137 }
138
139
140 /* Note: does not emit any commands to avoid recursion on
141 * r200AllocCmdBuf.
142 */
143 void r200FlushCmdBuf( r200ContextPtr rmesa, const char *caller )
144 {
145 int ret;
146
147 LOCK_HARDWARE( rmesa );
148
149 ret = r200FlushCmdBufLocked( rmesa, caller );
150
151 UNLOCK_HARDWARE( rmesa );
152
153 if (ret) {
154 fprintf(stderr, "drmRadeonCmdBuffer: %d (exiting)\n", ret);
155 exit(ret);
156 }
157 }
158
159
160 /* =============================================================
161 * Hardware vertex buffer handling
162 */
163
164
165 void r200RefillCurrentDmaRegion( r200ContextPtr rmesa )
166 {
167 struct r200_dma_buffer *dmabuf;
168 int fd = rmesa->dri.fd;
169 int index = 0;
170 int size = 0;
171 drmDMAReq dma;
172 int ret;
173
174 if (R200_DEBUG & (DEBUG_IOCTL|DEBUG_DMA))
175 fprintf(stderr, "%s\n", __FUNCTION__);
176
177 if (rmesa->dma.flush) {
178 rmesa->dma.flush( rmesa );
179 }
180
181 if (rmesa->dma.current.buf)
182 r200ReleaseDmaRegion( rmesa, &rmesa->dma.current, __FUNCTION__ );
183
184 if (rmesa->dma.nr_released_bufs > 4)
185 r200FlushCmdBuf( rmesa, __FUNCTION__ );
186
187 dma.context = rmesa->dri.hwContext;
188 dma.send_count = 0;
189 dma.send_list = NULL;
190 dma.send_sizes = NULL;
191 dma.flags = 0;
192 dma.request_count = 1;
193 dma.request_size = RADEON_BUFFER_SIZE;
194 dma.request_list = &index;
195 dma.request_sizes = &size;
196 dma.granted_count = 0;
197
198 LOCK_HARDWARE(rmesa); /* no need to validate */
199
200 while (1) {
201 ret = drmDMA( fd, &dma );
202 if (ret == 0)
203 break;
204
205 if (rmesa->dma.nr_released_bufs) {
206 r200FlushCmdBufLocked( rmesa, __FUNCTION__ );
207 }
208
209 if (rmesa->do_usleeps) {
210 UNLOCK_HARDWARE( rmesa );
211 DO_USLEEP( 1 );
212 LOCK_HARDWARE( rmesa );
213 }
214 }
215
216 UNLOCK_HARDWARE(rmesa);
217
218 if (R200_DEBUG & DEBUG_DMA)
219 fprintf(stderr, "Allocated buffer %d\n", index);
220
221 dmabuf = CALLOC_STRUCT( r200_dma_buffer );
222 dmabuf->buf = &rmesa->r200Screen->buffers->list[index];
223 dmabuf->refcount = 1;
224
225 rmesa->dma.current.buf = dmabuf;
226 rmesa->dma.current.address = dmabuf->buf->address;
227 rmesa->dma.current.end = dmabuf->buf->total;
228 rmesa->dma.current.start = 0;
229 rmesa->dma.current.ptr = 0;
230 }
231
232 void r200ReleaseDmaRegion( r200ContextPtr rmesa,
233 struct r200_dma_region *region,
234 const char *caller )
235 {
236 if (R200_DEBUG & DEBUG_IOCTL)
237 fprintf(stderr, "%s from %s\n", __FUNCTION__, caller);
238
239 if (!region->buf)
240 return;
241
242 if (rmesa->dma.flush)
243 rmesa->dma.flush( rmesa );
244
245 if (--region->buf->refcount == 0) {
246 drm_radeon_cmd_header_t *cmd;
247
248 if (R200_DEBUG & (DEBUG_IOCTL|DEBUG_DMA))
249 fprintf(stderr, "%s -- DISCARD BUF %d\n", __FUNCTION__,
250 region->buf->buf->idx);
251
252 cmd = (drm_radeon_cmd_header_t *)r200AllocCmdBuf( rmesa, sizeof(*cmd),
253 __FUNCTION__ );
254 cmd->dma.cmd_type = RADEON_CMD_DMA_DISCARD;
255 cmd->dma.buf_idx = region->buf->buf->idx;
256 FREE(region->buf);
257 rmesa->dma.nr_released_bufs++;
258 }
259
260 region->buf = 0;
261 region->start = 0;
262 }
263
264 /* Allocates a region from rmesa->dma.current. If there isn't enough
265 * space in current, grab a new buffer (and discard what was left of current)
266 */
267 void r200AllocDmaRegion( r200ContextPtr rmesa,
268 struct r200_dma_region *region,
269 int bytes,
270 int alignment )
271 {
272 if (R200_DEBUG & DEBUG_IOCTL)
273 fprintf(stderr, "%s %d\n", __FUNCTION__, bytes);
274
275 if (rmesa->dma.flush)
276 rmesa->dma.flush( rmesa );
277
278 if (region->buf)
279 r200ReleaseDmaRegion( rmesa, region, __FUNCTION__ );
280
281 alignment--;
282 rmesa->dma.current.start = rmesa->dma.current.ptr =
283 (rmesa->dma.current.ptr + alignment) & ~alignment;
284
285 if ( rmesa->dma.current.ptr + bytes > rmesa->dma.current.end )
286 r200RefillCurrentDmaRegion( rmesa );
287
288 region->start = rmesa->dma.current.start;
289 region->ptr = rmesa->dma.current.start;
290 region->end = rmesa->dma.current.start + bytes;
291 region->address = rmesa->dma.current.address;
292 region->buf = rmesa->dma.current.buf;
293 region->buf->refcount++;
294
295 rmesa->dma.current.ptr += bytes; /* bug - if alignment > 7 */
296 rmesa->dma.current.start =
297 rmesa->dma.current.ptr = (rmesa->dma.current.ptr + 0x7) & ~0x7;
298
299 assert( rmesa->dma.current.ptr <= rmesa->dma.current.end );
300 }
301
302 void r200AllocDmaRegionVerts( r200ContextPtr rmesa,
303 struct r200_dma_region *region,
304 int numverts,
305 int vertsize,
306 int alignment )
307 {
308 r200AllocDmaRegion( rmesa, region, vertsize * numverts, alignment );
309 }
310
311 /* ================================================================
312 * SwapBuffers with client-side throttling
313 */
314
315 static CARD32 r200GetLastFrame(r200ContextPtr rmesa)
316 {
317 drm_radeon_getparam_t gp;
318 int ret;
319 CARD32 frame;
320
321 gp.param = RADEON_PARAM_LAST_FRAME;
322 gp.value = (int *)&frame;
323 ret = drmCommandWriteRead( rmesa->dri.fd, DRM_RADEON_GETPARAM,
324 &gp, sizeof(gp) );
325 if ( ret ) {
326 fprintf( stderr, "%s: drmRadeonGetParam: %d\n", __FUNCTION__, ret );
327 exit(1);
328 }
329
330 return frame;
331 }
332
333 static void r200EmitIrqLocked( r200ContextPtr rmesa )
334 {
335 drm_radeon_irq_emit_t ie;
336 int ret;
337
338 ie.irq_seq = &rmesa->iw.irq_seq;
339 ret = drmCommandWriteRead( rmesa->dri.fd, DRM_RADEON_IRQ_EMIT,
340 &ie, sizeof(ie) );
341 if ( ret ) {
342 fprintf( stderr, "%s: drmRadeonIrqEmit: %d\n", __FUNCTION__, ret );
343 exit(1);
344 }
345 }
346
347
348 static void r200WaitIrq( r200ContextPtr rmesa )
349 {
350 int ret;
351
352 do {
353 ret = drmCommandWrite( rmesa->dri.fd, DRM_RADEON_IRQ_WAIT,
354 &rmesa->iw, sizeof(rmesa->iw) );
355 } while (ret && (errno == EINTR || errno == EAGAIN));
356
357 if ( ret ) {
358 fprintf( stderr, "%s: drmRadeonIrqWait: %d\n", __FUNCTION__, ret );
359 exit(1);
360 }
361 }
362
363
364 static void r200WaitForFrameCompletion( r200ContextPtr rmesa )
365 {
366 drm_radeon_sarea_t *sarea = rmesa->sarea;
367
368 if (rmesa->do_irqs) {
369 if (r200GetLastFrame(rmesa) < sarea->last_frame) {
370 if (!rmesa->irqsEmitted) {
371 while (r200GetLastFrame (rmesa) < sarea->last_frame)
372 ;
373 }
374 else {
375 UNLOCK_HARDWARE( rmesa );
376 r200WaitIrq( rmesa );
377 LOCK_HARDWARE( rmesa );
378 }
379 rmesa->irqsEmitted = 10;
380 }
381
382 if (rmesa->irqsEmitted) {
383 r200EmitIrqLocked( rmesa );
384 rmesa->irqsEmitted--;
385 }
386 }
387 else {
388 while (r200GetLastFrame (rmesa) < sarea->last_frame) {
389 UNLOCK_HARDWARE( rmesa );
390 if (rmesa->do_usleeps)
391 DO_USLEEP( 1 );
392 LOCK_HARDWARE( rmesa );
393 }
394 }
395 }
396
397
398
399 /* Copy the back color buffer to the front color buffer.
400 */
401 void r200CopyBuffer( const __DRIdrawablePrivate *dPriv )
402 {
403 r200ContextPtr rmesa;
404 GLint nbox, i, ret;
405 GLboolean missed_target;
406 int64_t ust;
407
408 assert(dPriv);
409 assert(dPriv->driContextPriv);
410 assert(dPriv->driContextPriv->driverPrivate);
411
412 rmesa = (r200ContextPtr) dPriv->driContextPriv->driverPrivate;
413
414 if ( R200_DEBUG & DEBUG_IOCTL ) {
415 fprintf( stderr, "\n%s( %p )\n\n", __FUNCTION__, (void *)rmesa->glCtx );
416 }
417
418 R200_FIREVERTICES( rmesa );
419
420 LOCK_HARDWARE( rmesa );
421
422
423 /* Throttle the frame rate -- only allow one pending swap buffers
424 * request at a time.
425 */
426 r200WaitForFrameCompletion( rmesa );
427 UNLOCK_HARDWARE( rmesa );
428 driWaitForVBlank( dPriv, & rmesa->vbl_seq, rmesa->vblank_flags, & missed_target );
429 LOCK_HARDWARE( rmesa );
430
431 nbox = dPriv->numClipRects; /* must be in locked region */
432
433 for ( i = 0 ; i < nbox ; ) {
434 GLint nr = MIN2( i + RADEON_NR_SAREA_CLIPRECTS , nbox );
435 drm_clip_rect_t *box = dPriv->pClipRects;
436 drm_clip_rect_t *b = rmesa->sarea->boxes;
437 GLint n = 0;
438
439 for ( ; i < nr ; i++ ) {
440 *b++ = box[i];
441 n++;
442 }
443 rmesa->sarea->nbox = n;
444
445 ret = drmCommandNone( rmesa->dri.fd, DRM_RADEON_SWAP );
446
447 if ( ret ) {
448 fprintf( stderr, "DRM_R200_SWAP_BUFFERS: return = %d\n", ret );
449 UNLOCK_HARDWARE( rmesa );
450 exit( 1 );
451 }
452 }
453
454 UNLOCK_HARDWARE( rmesa );
455 rmesa->lost_context = 1;
456
457 rmesa->swap_count++;
458 (*rmesa->get_ust)( & ust );
459 if ( missed_target ) {
460 rmesa->swap_missed_count++;
461 rmesa->swap_missed_ust = ust - rmesa->swap_ust;
462 }
463
464 rmesa->swap_ust = ust;
465
466 sched_yield();
467 }
468
469 void r200PageFlip( const __DRIdrawablePrivate *dPriv )
470 {
471 r200ContextPtr rmesa;
472 GLint ret;
473 GLboolean missed_target;
474
475 assert(dPriv);
476 assert(dPriv->driContextPriv);
477 assert(dPriv->driContextPriv->driverPrivate);
478
479 rmesa = (r200ContextPtr) dPriv->driContextPriv->driverPrivate;
480
481 if ( R200_DEBUG & DEBUG_IOCTL ) {
482 fprintf(stderr, "%s: pfCurrentPage: %d\n", __FUNCTION__,
483 rmesa->sarea->pfCurrentPage);
484 }
485
486 R200_FIREVERTICES( rmesa );
487 LOCK_HARDWARE( rmesa );
488
489 if (!dPriv->numClipRects) {
490 UNLOCK_HARDWARE( rmesa );
491 usleep( 10000 ); /* throttle invisible client 10ms */
492 return;
493 }
494
495 /* Need to do this for the perf box placement:
496 */
497 {
498 drm_clip_rect_t *box = dPriv->pClipRects;
499 drm_clip_rect_t *b = rmesa->sarea->boxes;
500 b[0] = box[0];
501 rmesa->sarea->nbox = 1;
502 }
503
504 /* Throttle the frame rate -- only allow a few pending swap buffers
505 * request at a time.
506 */
507 r200WaitForFrameCompletion( rmesa );
508 UNLOCK_HARDWARE( rmesa );
509 driWaitForVBlank( dPriv, & rmesa->vbl_seq, rmesa->vblank_flags, & missed_target );
510 if ( missed_target ) {
511 rmesa->swap_missed_count++;
512 (void) (*rmesa->get_ust)( & rmesa->swap_missed_ust );
513 }
514 LOCK_HARDWARE( rmesa );
515
516 ret = drmCommandNone( rmesa->dri.fd, DRM_RADEON_FLIP );
517
518 UNLOCK_HARDWARE( rmesa );
519
520 if ( ret ) {
521 fprintf( stderr, "DRM_RADEON_FLIP: return = %d\n", ret );
522 exit( 1 );
523 }
524
525 rmesa->swap_count++;
526 (void) (*rmesa->get_ust)( & rmesa->swap_ust );
527
528 if ( rmesa->sarea->pfCurrentPage == 1 ) {
529 rmesa->state.color.drawOffset = rmesa->r200Screen->frontOffset;
530 rmesa->state.color.drawPitch = rmesa->r200Screen->frontPitch;
531 } else {
532 rmesa->state.color.drawOffset = rmesa->r200Screen->backOffset;
533 rmesa->state.color.drawPitch = rmesa->r200Screen->backPitch;
534 }
535
536 R200_STATECHANGE( rmesa, ctx );
537 rmesa->hw.ctx.cmd[CTX_RB3D_COLOROFFSET] = rmesa->state.color.drawOffset
538 + rmesa->r200Screen->fbLocation;
539 rmesa->hw.ctx.cmd[CTX_RB3D_COLORPITCH] = rmesa->state.color.drawPitch;
540 }
541
542
543 /* ================================================================
544 * Buffer clear
545 */
546 static void r200Clear( GLcontext *ctx, GLbitfield mask, GLboolean all,
547 GLint cx, GLint cy, GLint cw, GLint ch )
548 {
549 r200ContextPtr rmesa = R200_CONTEXT(ctx);
550 __DRIdrawablePrivate *dPriv = rmesa->dri.drawable;
551 GLuint flags = 0;
552 GLuint color_mask = 0;
553 GLint ret, i;
554
555 if ( R200_DEBUG & DEBUG_IOCTL ) {
556 fprintf( stderr, "%s: all=%d cx=%d cy=%d cw=%d ch=%d\n",
557 __FUNCTION__, all, cx, cy, cw, ch );
558 }
559
560 {
561 LOCK_HARDWARE( rmesa );
562 UNLOCK_HARDWARE( rmesa );
563 if ( dPriv->numClipRects == 0 )
564 return;
565 }
566
567 r200EmitState( rmesa );
568
569 /* Need to cope with lostcontext here as kernel relies on
570 * some residual state:
571 */
572 R200_FIREVERTICES( rmesa );
573
574 if ( mask & DD_FRONT_LEFT_BIT ) {
575 flags |= RADEON_FRONT;
576 color_mask = rmesa->hw.msk.cmd[MSK_RB3D_PLANEMASK];
577 mask &= ~DD_FRONT_LEFT_BIT;
578 }
579
580 if ( mask & DD_BACK_LEFT_BIT ) {
581 flags |= RADEON_BACK;
582 color_mask = rmesa->hw.msk.cmd[MSK_RB3D_PLANEMASK];
583 mask &= ~DD_BACK_LEFT_BIT;
584 }
585
586 if ( mask & DD_DEPTH_BIT ) {
587 if ( ctx->Depth.Mask ) flags |= RADEON_DEPTH; /* FIXME: ??? */
588 mask &= ~DD_DEPTH_BIT;
589 }
590
591 if ( (mask & DD_STENCIL_BIT) && rmesa->state.stencil.hwBuffer ) {
592 flags |= RADEON_STENCIL;
593 mask &= ~DD_STENCIL_BIT;
594 }
595
596 if ( mask ) {
597 if (R200_DEBUG & DEBUG_FALLBACKS)
598 fprintf(stderr, "%s: swrast clear, mask: %x\n", __FUNCTION__, mask);
599 _swrast_Clear( ctx, mask, all, cx, cy, cw, ch );
600 }
601
602 if ( !flags )
603 return;
604
605 /* Flip top to bottom */
606 cx += dPriv->x;
607 cy = dPriv->y + dPriv->h - cy - ch;
608
609 LOCK_HARDWARE( rmesa );
610
611 /* Throttle the number of clear ioctls we do.
612 */
613 while ( 1 ) {
614 drm_radeon_getparam_t gp;
615 int ret;
616 int clear;
617
618 gp.param = RADEON_PARAM_LAST_CLEAR;
619 gp.value = (int *)&clear;
620 ret = drmCommandWriteRead( rmesa->dri.fd,
621 DRM_RADEON_GETPARAM, &gp, sizeof(gp) );
622
623 if ( ret ) {
624 fprintf( stderr, "%s: drmRadeonGetParam: %d\n", __FUNCTION__, ret );
625 exit(1);
626 }
627
628 /* Clear throttling needs more thought.
629 */
630 if ( rmesa->sarea->last_clear - clear <= 25 ) {
631 break;
632 }
633
634 if (rmesa->do_usleeps) {
635 UNLOCK_HARDWARE( rmesa );
636 DO_USLEEP( 1 );
637 LOCK_HARDWARE( rmesa );
638 }
639 }
640
641
642 for ( i = 0 ; i < dPriv->numClipRects ; ) {
643 GLint nr = MIN2( i + RADEON_NR_SAREA_CLIPRECTS, dPriv->numClipRects );
644 drm_clip_rect_t *box = dPriv->pClipRects;
645 drm_clip_rect_t *b = rmesa->sarea->boxes;
646 drm_radeon_clear_t clear;
647 drm_radeon_clear_rect_t depth_boxes[RADEON_NR_SAREA_CLIPRECTS];
648 GLint n = 0;
649
650 if ( !all ) {
651 for ( ; i < nr ; i++ ) {
652 GLint x = box[i].x1;
653 GLint y = box[i].y1;
654 GLint w = box[i].x2 - x;
655 GLint h = box[i].y2 - y;
656
657 if ( x < cx ) w -= cx - x, x = cx;
658 if ( y < cy ) h -= cy - y, y = cy;
659 if ( x + w > cx + cw ) w = cx + cw - x;
660 if ( y + h > cy + ch ) h = cy + ch - y;
661 if ( w <= 0 ) continue;
662 if ( h <= 0 ) continue;
663
664 b->x1 = x;
665 b->y1 = y;
666 b->x2 = x + w;
667 b->y2 = y + h;
668 b++;
669 n++;
670 }
671 } else {
672 for ( ; i < nr ; i++ ) {
673 *b++ = box[i];
674 n++;
675 }
676 }
677
678 rmesa->sarea->nbox = n;
679
680 clear.flags = flags;
681 clear.clear_color = rmesa->state.color.clear;
682 clear.clear_depth = 0; /* not used */
683 clear.color_mask = rmesa->hw.msk.cmd[MSK_RB3D_PLANEMASK];
684 clear.depth_mask = rmesa->state.stencil.clear;
685 clear.depth_boxes = depth_boxes;
686
687 n--;
688 b = rmesa->sarea->boxes;
689 for ( ; n >= 0 ; n-- ) {
690 depth_boxes[n].f[CLEAR_X1] = (float)b[n].x1;
691 depth_boxes[n].f[CLEAR_Y1] = (float)b[n].y1;
692 depth_boxes[n].f[CLEAR_X2] = (float)b[n].x2;
693 depth_boxes[n].f[CLEAR_Y2] = (float)b[n].y2;
694 depth_boxes[n].f[CLEAR_DEPTH] = ctx->Depth.Clear;
695 }
696
697 ret = drmCommandWrite( rmesa->dri.fd, DRM_RADEON_CLEAR,
698 &clear, sizeof(clear));
699
700
701 if ( ret ) {
702 UNLOCK_HARDWARE( rmesa );
703 fprintf( stderr, "DRM_RADEON_CLEAR: return = %d\n", ret );
704 exit( 1 );
705 }
706 }
707
708 UNLOCK_HARDWARE( rmesa );
709 rmesa->lost_context = 1;
710 }
711
712
713 void r200WaitForIdleLocked( r200ContextPtr rmesa )
714 {
715 int ret;
716 int i = 0;
717
718 do {
719 ret = drmCommandNone( rmesa->dri.fd, DRM_RADEON_CP_IDLE);
720 if (ret)
721 DO_USLEEP( 1 );
722 } while (ret && ++i < 100);
723
724 if ( ret < 0 ) {
725 UNLOCK_HARDWARE( rmesa );
726 fprintf( stderr, "Error: R200 timed out... exiting\n" );
727 exit( -1 );
728 }
729 }
730
731
732 static void r200WaitForIdle( r200ContextPtr rmesa )
733 {
734 LOCK_HARDWARE(rmesa);
735 r200WaitForIdleLocked( rmesa );
736 UNLOCK_HARDWARE(rmesa);
737 }
738
739
740 void r200Flush( GLcontext *ctx )
741 {
742 r200ContextPtr rmesa = R200_CONTEXT( ctx );
743
744 if (R200_DEBUG & DEBUG_IOCTL)
745 fprintf(stderr, "%s\n", __FUNCTION__);
746
747 if (rmesa->dma.flush)
748 rmesa->dma.flush( rmesa );
749
750 if (!is_empty_list(&rmesa->hw.dirty))
751 r200EmitState( rmesa );
752
753 if (rmesa->store.cmd_used)
754 r200FlushCmdBuf( rmesa, __FUNCTION__ );
755 }
756
757 /* Make sure all commands have been sent to the hardware and have
758 * completed processing.
759 */
760 void r200Finish( GLcontext *ctx )
761 {
762 r200ContextPtr rmesa = R200_CONTEXT(ctx);
763 r200Flush( ctx );
764
765 if (rmesa->do_irqs) {
766 LOCK_HARDWARE( rmesa );
767 r200EmitIrqLocked( rmesa );
768 UNLOCK_HARDWARE( rmesa );
769 r200WaitIrq( rmesa );
770 }
771 else
772 r200WaitForIdle( rmesa );
773 }
774
775
776 /* This version of AllocateMemoryMESA allocates only GART memory, and
777 * only does so after the point at which the driver has been
778 * initialized.
779 *
780 * Theoretically a valid context isn't required. However, in this
781 * implementation, it is, as I'm using the hardware lock to protect
782 * the kernel data structures, and the current context to get the
783 * device fd.
784 */
785 void *r200AllocateMemoryMESA(GLsizei size,
786 GLfloat readfreq, GLfloat writefreq,
787 GLfloat priority)
788 {
789 GET_CURRENT_CONTEXT(ctx);
790 r200ContextPtr rmesa;
791 int region_offset;
792 drm_radeon_mem_alloc_t alloc;
793 int ret;
794
795 if (R200_DEBUG & DEBUG_IOCTL)
796 fprintf(stderr, "%s sz %d %f/%f/%f\n", __FUNCTION__, size, readfreq,
797 writefreq, priority);
798
799 if (!ctx || !(rmesa = R200_CONTEXT(ctx)) || !rmesa->r200Screen->gartTextures.map)
800 return NULL;
801
802 if (getenv("R200_NO_ALLOC"))
803 return NULL;
804
805 if (rmesa->dri.drmMinor < 6)
806 return NULL;
807
808 alloc.region = RADEON_MEM_REGION_GART;
809 alloc.alignment = 0;
810 alloc.size = size;
811 alloc.region_offset = &region_offset;
812
813 ret = drmCommandWriteRead( rmesa->r200Screen->driScreen->fd,
814 DRM_RADEON_ALLOC,
815 &alloc, sizeof(alloc));
816
817 if (ret) {
818 fprintf(stderr, "%s: DRM_RADEON_ALLOC ret %d\n", __FUNCTION__, ret);
819 return NULL;
820 }
821
822 {
823 char *region_start = (char *)rmesa->r200Screen->gartTextures.map;
824 return (void *)(region_start + region_offset);
825 }
826 }
827
828
829 /* Called via glXFreeMemoryMESA() */
830 void r200FreeMemoryMESA(GLvoid *pointer)
831 {
832 GET_CURRENT_CONTEXT(ctx);
833 r200ContextPtr rmesa;
834 int region_offset;
835 drm_radeon_mem_free_t memfree;
836 int ret;
837
838 if (R200_DEBUG & DEBUG_IOCTL)
839 fprintf(stderr, "%s %p\n", __FUNCTION__, pointer);
840
841 if (!ctx || !(rmesa = R200_CONTEXT(ctx)) || !rmesa->r200Screen->gartTextures.map) {
842 fprintf(stderr, "%s: no context\n", __FUNCTION__);
843 return;
844 }
845
846 if (rmesa->dri.drmMinor < 6)
847 return;
848
849 region_offset = (char *)pointer - (char *)rmesa->r200Screen->gartTextures.map;
850
851 if (region_offset < 0 ||
852 region_offset > rmesa->r200Screen->gartTextures.size) {
853 fprintf(stderr, "offset %d outside range 0..%d\n", region_offset,
854 rmesa->r200Screen->gartTextures.size);
855 return;
856 }
857
858 memfree.region = RADEON_MEM_REGION_GART;
859 memfree.region_offset = region_offset;
860
861 ret = drmCommandWrite( rmesa->r200Screen->driScreen->fd,
862 DRM_RADEON_FREE,
863 &memfree, sizeof(memfree));
864
865 if (ret)
866 fprintf(stderr, "%s: DRM_RADEON_FREE ret %d\n", __FUNCTION__, ret);
867 }
868
869 /* Called via glXGetMemoryOffsetMESA() */
870 GLuint r200GetMemoryOffsetMESA(const GLvoid *pointer)
871 {
872 GET_CURRENT_CONTEXT(ctx);
873 r200ContextPtr rmesa;
874 GLuint card_offset;
875
876 if (!ctx || !(rmesa = R200_CONTEXT(ctx)) ) {
877 fprintf(stderr, "%s: no context\n", __FUNCTION__);
878 return ~0;
879 }
880
881 if (!r200IsGartMemory( rmesa, pointer, 0 ))
882 return ~0;
883
884 if (rmesa->dri.drmMinor < 6)
885 return ~0;
886
887 card_offset = r200GartOffsetFromVirtual( rmesa, pointer );
888
889 return card_offset - rmesa->r200Screen->gart_base;
890 }
891
892
893 GLboolean r200IsGartMemory( r200ContextPtr rmesa, const GLvoid *pointer,
894 GLint size )
895 {
896 int offset = (char *)pointer - (char *)rmesa->r200Screen->gartTextures.map;
897 int valid = (size >= 0 &&
898 offset >= 0 &&
899 offset + size < rmesa->r200Screen->gartTextures.size);
900
901 if (R200_DEBUG & DEBUG_IOCTL)
902 fprintf(stderr, "r200IsGartMemory( %p ) : %d\n", pointer, valid );
903
904 return valid;
905 }
906
907
908 GLuint r200GartOffsetFromVirtual( r200ContextPtr rmesa, const GLvoid *pointer )
909 {
910 int offset = (char *)pointer - (char *)rmesa->r200Screen->gartTextures.map;
911
912 if (offset < 0 || offset > rmesa->r200Screen->gartTextures.size)
913 return ~0;
914 else
915 return rmesa->r200Screen->gart_texture_offset + offset;
916 }
917
918
919
920 void r200InitIoctlFuncs( struct dd_function_table *functions )
921 {
922 functions->Clear = r200Clear;
923 functions->Finish = r200Finish;
924 functions->Flush = r200Flush;
925 }
926