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