Merge branch 'dri2'
[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 "glheader.h"
39 #include "imports.h"
40 #include "macros.h"
41 #include "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 u_int32_t r200GetLastFrame(r200ContextPtr rmesa)
337 {
338 drm_radeon_getparam_t gp;
339 int ret;
340 u_int32_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( const __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
430 assert(dPriv);
431 assert(dPriv->driContextPriv);
432 assert(dPriv->driContextPriv->driverPrivate);
433
434 rmesa = (r200ContextPtr) dPriv->driContextPriv->driverPrivate;
435
436 if ( R200_DEBUG & DEBUG_IOCTL ) {
437 fprintf( stderr, "\n%s( %p )\n\n", __FUNCTION__, (void *)rmesa->glCtx );
438 }
439
440 R200_FIREVERTICES( rmesa );
441
442 LOCK_HARDWARE( rmesa );
443
444
445 /* Throttle the frame rate -- only allow one pending swap buffers
446 * request at a time.
447 */
448 r200WaitForFrameCompletion( rmesa );
449 if (!rect)
450 {
451 UNLOCK_HARDWARE( rmesa );
452 driWaitForVBlank( dPriv, & rmesa->vbl_seq, rmesa->vblank_flags, & missed_target );
453 LOCK_HARDWARE( rmesa );
454 }
455
456 nbox = dPriv->numClipRects; /* must be in locked region */
457
458 for ( i = 0 ; i < nbox ; ) {
459 GLint nr = MIN2( i + RADEON_NR_SAREA_CLIPRECTS , nbox );
460 drm_clip_rect_t *box = dPriv->pClipRects;
461 drm_clip_rect_t *b = rmesa->sarea->boxes;
462 GLint n = 0;
463
464 for ( ; i < nr ; i++ ) {
465
466 *b = box[i];
467
468 if (rect)
469 {
470 if (rect->x1 > b->x1)
471 b->x1 = rect->x1;
472 if (rect->y1 > b->y1)
473 b->y1 = rect->y1;
474 if (rect->x2 < b->x2)
475 b->x2 = rect->x2;
476 if (rect->y2 < b->y2)
477 b->y2 = rect->y2;
478
479 if (b->x1 < b->x2 && b->y1 < b->y2)
480 b++;
481 }
482 else
483 b++;
484
485 n++;
486 }
487 rmesa->sarea->nbox = n;
488
489 ret = drmCommandNone( rmesa->dri.fd, DRM_RADEON_SWAP );
490
491 if ( ret ) {
492 fprintf( stderr, "DRM_R200_SWAP_BUFFERS: return = %d\n", ret );
493 UNLOCK_HARDWARE( rmesa );
494 exit( 1 );
495 }
496 }
497
498 UNLOCK_HARDWARE( rmesa );
499 if (!rect)
500 {
501 rmesa->hw.all_dirty = GL_TRUE;
502
503 rmesa->swap_count++;
504 (*dri_interface->getUST)( & ust );
505 if ( missed_target ) {
506 rmesa->swap_missed_count++;
507 rmesa->swap_missed_ust = ust - rmesa->swap_ust;
508 }
509
510 rmesa->swap_ust = ust;
511
512 sched_yield();
513 }
514 }
515
516 void r200PageFlip( const __DRIdrawablePrivate *dPriv )
517 {
518 r200ContextPtr rmesa;
519 GLint ret;
520 GLboolean missed_target;
521
522 assert(dPriv);
523 assert(dPriv->driContextPriv);
524 assert(dPriv->driContextPriv->driverPrivate);
525
526 rmesa = (r200ContextPtr) dPriv->driContextPriv->driverPrivate;
527
528 if ( R200_DEBUG & DEBUG_IOCTL ) {
529 fprintf(stderr, "%s: pfCurrentPage: %d\n", __FUNCTION__,
530 rmesa->sarea->pfCurrentPage);
531 }
532
533 R200_FIREVERTICES( rmesa );
534 LOCK_HARDWARE( rmesa );
535
536 if (!dPriv->numClipRects) {
537 UNLOCK_HARDWARE( rmesa );
538 usleep( 10000 ); /* throttle invisible client 10ms */
539 return;
540 }
541
542 /* Need to do this for the perf box placement:
543 */
544 {
545 drm_clip_rect_t *box = dPriv->pClipRects;
546 drm_clip_rect_t *b = rmesa->sarea->boxes;
547 b[0] = box[0];
548 rmesa->sarea->nbox = 1;
549 }
550
551 /* Throttle the frame rate -- only allow a few pending swap buffers
552 * request at a time.
553 */
554 r200WaitForFrameCompletion( rmesa );
555 UNLOCK_HARDWARE( rmesa );
556 driWaitForVBlank( dPriv, & rmesa->vbl_seq, rmesa->vblank_flags, & missed_target );
557 if ( missed_target ) {
558 rmesa->swap_missed_count++;
559 (void) (*dri_interface->getUST)( & rmesa->swap_missed_ust );
560 }
561 LOCK_HARDWARE( rmesa );
562
563 ret = drmCommandNone( rmesa->dri.fd, DRM_RADEON_FLIP );
564
565 UNLOCK_HARDWARE( rmesa );
566
567 if ( ret ) {
568 fprintf( stderr, "DRM_RADEON_FLIP: return = %d\n", ret );
569 exit( 1 );
570 }
571
572 rmesa->swap_count++;
573 (void) (*dri_interface->getUST)( & rmesa->swap_ust );
574
575 #if 000
576 if ( rmesa->sarea->pfCurrentPage == 1 ) {
577 rmesa->state.color.drawOffset = rmesa->r200Screen->frontOffset;
578 rmesa->state.color.drawPitch = rmesa->r200Screen->frontPitch;
579 } else {
580 rmesa->state.color.drawOffset = rmesa->r200Screen->backOffset;
581 rmesa->state.color.drawPitch = rmesa->r200Screen->backPitch;
582 }
583
584 R200_STATECHANGE( rmesa, ctx );
585 rmesa->hw.ctx.cmd[CTX_RB3D_COLOROFFSET] = rmesa->state.color.drawOffset
586 + rmesa->r200Screen->fbLocation;
587 rmesa->hw.ctx.cmd[CTX_RB3D_COLORPITCH] = rmesa->state.color.drawPitch;
588 if (rmesa->sarea->tiling_enabled) {
589 rmesa->hw.ctx.cmd[CTX_RB3D_COLORPITCH] |= R200_COLOR_TILE_ENABLE;
590 }
591 #else
592 /* Get ready for drawing next frame. Update the renderbuffers'
593 * flippedOffset/Pitch fields so we draw into the right place.
594 */
595 driFlipRenderbuffers(rmesa->glCtx->WinSysDrawBuffer,
596 rmesa->sarea->pfCurrentPage);
597
598
599 r200UpdateDrawBuffer(rmesa->glCtx);
600 #endif
601 }
602
603
604 /* ================================================================
605 * Buffer clear
606 */
607 static void r200Clear( GLcontext *ctx, GLbitfield mask )
608 {
609 r200ContextPtr rmesa = R200_CONTEXT(ctx);
610 __DRIdrawablePrivate *dPriv = rmesa->dri.drawable;
611 GLuint flags = 0;
612 GLuint color_mask = 0;
613 GLint ret, i;
614 GLint cx, cy, cw, ch;
615
616 if ( R200_DEBUG & DEBUG_IOCTL ) {
617 fprintf( stderr, "r200Clear\n");
618 }
619
620 {
621 LOCK_HARDWARE( rmesa );
622 UNLOCK_HARDWARE( rmesa );
623 if ( dPriv->numClipRects == 0 )
624 return;
625 }
626
627 r200Flush( ctx );
628
629 if ( mask & BUFFER_BIT_FRONT_LEFT ) {
630 flags |= RADEON_FRONT;
631 color_mask = rmesa->hw.msk.cmd[MSK_RB3D_PLANEMASK];
632 mask &= ~BUFFER_BIT_FRONT_LEFT;
633 }
634
635 if ( mask & BUFFER_BIT_BACK_LEFT ) {
636 flags |= RADEON_BACK;
637 color_mask = rmesa->hw.msk.cmd[MSK_RB3D_PLANEMASK];
638 mask &= ~BUFFER_BIT_BACK_LEFT;
639 }
640
641 if ( mask & BUFFER_BIT_DEPTH ) {
642 flags |= RADEON_DEPTH;
643 mask &= ~BUFFER_BIT_DEPTH;
644 }
645
646 if ( (mask & BUFFER_BIT_STENCIL) && rmesa->state.stencil.hwBuffer ) {
647 flags |= RADEON_STENCIL;
648 mask &= ~BUFFER_BIT_STENCIL;
649 }
650
651 if ( mask ) {
652 if (R200_DEBUG & DEBUG_FALLBACKS)
653 fprintf(stderr, "%s: swrast clear, mask: %x\n", __FUNCTION__, mask);
654 _swrast_Clear( ctx, mask );
655 }
656
657 if ( !flags )
658 return;
659
660 if (rmesa->using_hyperz) {
661 flags |= RADEON_USE_COMP_ZBUF;
662 /* if (rmesa->r200Screen->chip_family == CHIP_FAMILY_R200)
663 flags |= RADEON_USE_HIERZ; */
664 if (!(rmesa->state.stencil.hwBuffer) ||
665 ((flags & RADEON_DEPTH) && (flags & RADEON_STENCIL) &&
666 ((rmesa->state.stencil.clear & R200_STENCIL_WRITE_MASK) == R200_STENCIL_WRITE_MASK))) {
667 flags |= RADEON_CLEAR_FASTZ;
668 }
669 }
670
671 LOCK_HARDWARE( rmesa );
672
673 /* compute region after locking: */
674 cx = ctx->DrawBuffer->_Xmin;
675 cy = ctx->DrawBuffer->_Ymin;
676 cw = ctx->DrawBuffer->_Xmax - cx;
677 ch = ctx->DrawBuffer->_Ymax - cy;
678
679 /* Flip top to bottom */
680 cx += dPriv->x;
681 cy = dPriv->y + dPriv->h - cy - ch;
682
683 /* Throttle the number of clear ioctls we do.
684 */
685 while ( 1 ) {
686 drm_radeon_getparam_t gp;
687 int ret;
688 int clear;
689
690 gp.param = RADEON_PARAM_LAST_CLEAR;
691 gp.value = (int *)&clear;
692 ret = drmCommandWriteRead( rmesa->dri.fd,
693 DRM_RADEON_GETPARAM, &gp, sizeof(gp) );
694
695 if ( ret ) {
696 fprintf( stderr, "%s: drmRadeonGetParam: %d\n", __FUNCTION__, ret );
697 exit(1);
698 }
699
700 /* Clear throttling needs more thought.
701 */
702 if ( rmesa->sarea->last_clear - clear <= 25 ) {
703 break;
704 }
705
706 if (rmesa->do_usleeps) {
707 UNLOCK_HARDWARE( rmesa );
708 DO_USLEEP( 1 );
709 LOCK_HARDWARE( rmesa );
710 }
711 }
712
713 /* Send current state to the hardware */
714 r200FlushCmdBufLocked( rmesa, __FUNCTION__ );
715
716 for ( i = 0 ; i < dPriv->numClipRects ; ) {
717 GLint nr = MIN2( i + RADEON_NR_SAREA_CLIPRECTS, dPriv->numClipRects );
718 drm_clip_rect_t *box = dPriv->pClipRects;
719 drm_clip_rect_t *b = rmesa->sarea->boxes;
720 drm_radeon_clear_t clear;
721 drm_radeon_clear_rect_t depth_boxes[RADEON_NR_SAREA_CLIPRECTS];
722 GLint n = 0;
723
724 if (cw != dPriv->w || ch != dPriv->h) {
725 /* clear subregion */
726 for ( ; i < nr ; i++ ) {
727 GLint x = box[i].x1;
728 GLint y = box[i].y1;
729 GLint w = box[i].x2 - x;
730 GLint h = box[i].y2 - y;
731
732 if ( x < cx ) w -= cx - x, x = cx;
733 if ( y < cy ) h -= cy - y, y = cy;
734 if ( x + w > cx + cw ) w = cx + cw - x;
735 if ( y + h > cy + ch ) h = cy + ch - y;
736 if ( w <= 0 ) continue;
737 if ( h <= 0 ) continue;
738
739 b->x1 = x;
740 b->y1 = y;
741 b->x2 = x + w;
742 b->y2 = y + h;
743 b++;
744 n++;
745 }
746 } else {
747 /* clear whole window */
748 for ( ; i < nr ; i++ ) {
749 *b++ = box[i];
750 n++;
751 }
752 }
753
754 rmesa->sarea->nbox = n;
755
756 clear.flags = flags;
757 clear.clear_color = rmesa->state.color.clear;
758 clear.clear_depth = rmesa->state.depth.clear; /* needed for hyperz */
759 clear.color_mask = rmesa->hw.msk.cmd[MSK_RB3D_PLANEMASK];
760 clear.depth_mask = rmesa->state.stencil.clear;
761 clear.depth_boxes = depth_boxes;
762
763 n--;
764 b = rmesa->sarea->boxes;
765 for ( ; n >= 0 ; n-- ) {
766 depth_boxes[n].f[CLEAR_X1] = (float)b[n].x1;
767 depth_boxes[n].f[CLEAR_Y1] = (float)b[n].y1;
768 depth_boxes[n].f[CLEAR_X2] = (float)b[n].x2;
769 depth_boxes[n].f[CLEAR_Y2] = (float)b[n].y2;
770 depth_boxes[n].f[CLEAR_DEPTH] = ctx->Depth.Clear;
771 }
772
773 ret = drmCommandWrite( rmesa->dri.fd, DRM_RADEON_CLEAR,
774 &clear, sizeof(clear));
775
776
777 if ( ret ) {
778 UNLOCK_HARDWARE( rmesa );
779 fprintf( stderr, "DRM_RADEON_CLEAR: return = %d\n", ret );
780 exit( 1 );
781 }
782 }
783
784 UNLOCK_HARDWARE( rmesa );
785 rmesa->hw.all_dirty = GL_TRUE;
786 }
787
788
789 void r200WaitForIdleLocked( r200ContextPtr rmesa )
790 {
791 int ret;
792 int i = 0;
793
794 do {
795 ret = drmCommandNone( rmesa->dri.fd, DRM_RADEON_CP_IDLE);
796 if (ret)
797 DO_USLEEP( 1 );
798 } while (ret && ++i < 100);
799
800 if ( ret < 0 ) {
801 UNLOCK_HARDWARE( rmesa );
802 fprintf( stderr, "Error: R200 timed out... exiting\n" );
803 exit( -1 );
804 }
805 }
806
807
808 static void r200WaitForIdle( r200ContextPtr rmesa )
809 {
810 LOCK_HARDWARE(rmesa);
811 r200WaitForIdleLocked( rmesa );
812 UNLOCK_HARDWARE(rmesa);
813 }
814
815
816 void r200Flush( GLcontext *ctx )
817 {
818 r200ContextPtr rmesa = R200_CONTEXT( ctx );
819
820 if (R200_DEBUG & DEBUG_IOCTL)
821 fprintf(stderr, "%s\n", __FUNCTION__);
822
823 if (rmesa->dma.flush)
824 rmesa->dma.flush( rmesa );
825
826 r200EmitState( rmesa );
827
828 if (rmesa->store.cmd_used)
829 r200FlushCmdBuf( rmesa, __FUNCTION__ );
830 }
831
832 /* Make sure all commands have been sent to the hardware and have
833 * completed processing.
834 */
835 void r200Finish( GLcontext *ctx )
836 {
837 r200ContextPtr rmesa = R200_CONTEXT(ctx);
838 r200Flush( ctx );
839
840 if (rmesa->do_irqs) {
841 LOCK_HARDWARE( rmesa );
842 r200EmitIrqLocked( rmesa );
843 UNLOCK_HARDWARE( rmesa );
844 r200WaitIrq( rmesa );
845 }
846 else
847 r200WaitForIdle( rmesa );
848 }
849
850
851 /* This version of AllocateMemoryMESA allocates only GART memory, and
852 * only does so after the point at which the driver has been
853 * initialized.
854 *
855 * Theoretically a valid context isn't required. However, in this
856 * implementation, it is, as I'm using the hardware lock to protect
857 * the kernel data structures, and the current context to get the
858 * device fd.
859 */
860 void *r200AllocateMemoryMESA(__DRIscreen *screen, GLsizei size,
861 GLfloat readfreq, GLfloat writefreq,
862 GLfloat priority)
863 {
864 GET_CURRENT_CONTEXT(ctx);
865 r200ContextPtr rmesa;
866 int region_offset;
867 drm_radeon_mem_alloc_t alloc;
868 int ret;
869
870 if (R200_DEBUG & DEBUG_IOCTL)
871 fprintf(stderr, "%s sz %d %f/%f/%f\n", __FUNCTION__, size, readfreq,
872 writefreq, priority);
873
874 if (!ctx || !(rmesa = R200_CONTEXT(ctx)) || !rmesa->r200Screen->gartTextures.map)
875 return NULL;
876
877 if (getenv("R200_NO_ALLOC"))
878 return NULL;
879
880 alloc.region = RADEON_MEM_REGION_GART;
881 alloc.alignment = 0;
882 alloc.size = size;
883 alloc.region_offset = &region_offset;
884
885 ret = drmCommandWriteRead( rmesa->r200Screen->driScreen->fd,
886 DRM_RADEON_ALLOC,
887 &alloc, sizeof(alloc));
888
889 if (ret) {
890 fprintf(stderr, "%s: DRM_RADEON_ALLOC ret %d\n", __FUNCTION__, ret);
891 return NULL;
892 }
893
894 {
895 char *region_start = (char *)rmesa->r200Screen->gartTextures.map;
896 return (void *)(region_start + region_offset);
897 }
898 }
899
900
901 /* Called via glXFreeMemoryMESA() */
902 void r200FreeMemoryMESA(__DRIscreen *screen, GLvoid *pointer)
903 {
904 GET_CURRENT_CONTEXT(ctx);
905 r200ContextPtr rmesa;
906 ptrdiff_t region_offset;
907 drm_radeon_mem_free_t memfree;
908 int ret;
909
910 if (R200_DEBUG & DEBUG_IOCTL)
911 fprintf(stderr, "%s %p\n", __FUNCTION__, pointer);
912
913 if (!ctx || !(rmesa = R200_CONTEXT(ctx)) || !rmesa->r200Screen->gartTextures.map) {
914 fprintf(stderr, "%s: no context\n", __FUNCTION__);
915 return;
916 }
917
918 region_offset = (char *)pointer - (char *)rmesa->r200Screen->gartTextures.map;
919
920 if (region_offset < 0 ||
921 region_offset > rmesa->r200Screen->gartTextures.size) {
922 fprintf(stderr, "offset %d outside range 0..%d\n", region_offset,
923 rmesa->r200Screen->gartTextures.size);
924 return;
925 }
926
927 memfree.region = RADEON_MEM_REGION_GART;
928 memfree.region_offset = region_offset;
929
930 ret = drmCommandWrite( rmesa->r200Screen->driScreen->fd,
931 DRM_RADEON_FREE,
932 &memfree, sizeof(memfree));
933
934 if (ret)
935 fprintf(stderr, "%s: DRM_RADEON_FREE ret %d\n", __FUNCTION__, ret);
936 }
937
938 /* Called via glXGetMemoryOffsetMESA() */
939 GLuint r200GetMemoryOffsetMESA(__DRIscreen *screen, const GLvoid *pointer)
940 {
941 GET_CURRENT_CONTEXT(ctx);
942 r200ContextPtr rmesa;
943 GLuint card_offset;
944
945 if (!ctx || !(rmesa = R200_CONTEXT(ctx)) ) {
946 fprintf(stderr, "%s: no context\n", __FUNCTION__);
947 return ~0;
948 }
949
950 if (!r200IsGartMemory( rmesa, pointer, 0 ))
951 return ~0;
952
953 card_offset = r200GartOffsetFromVirtual( rmesa, pointer );
954
955 return card_offset - rmesa->r200Screen->gart_base;
956 }
957
958 GLboolean r200IsGartMemory( r200ContextPtr rmesa, const GLvoid *pointer,
959 GLint size )
960 {
961 ptrdiff_t offset = (char *)pointer - (char *)rmesa->r200Screen->gartTextures.map;
962 int valid = (size >= 0 &&
963 offset >= 0 &&
964 offset + size < rmesa->r200Screen->gartTextures.size);
965
966 if (R200_DEBUG & DEBUG_IOCTL)
967 fprintf(stderr, "r200IsGartMemory( %p ) : %d\n", pointer, valid );
968
969 return valid;
970 }
971
972
973 GLuint r200GartOffsetFromVirtual( r200ContextPtr rmesa, const GLvoid *pointer )
974 {
975 ptrdiff_t offset = (char *)pointer - (char *)rmesa->r200Screen->gartTextures.map;
976
977 if (offset < 0 || offset > rmesa->r200Screen->gartTextures.size)
978 return ~0;
979 else
980 return rmesa->r200Screen->gart_texture_offset + offset;
981 }
982
983
984
985 void r200InitIoctlFuncs( struct dd_function_table *functions )
986 {
987 functions->Clear = r200Clear;
988 functions->Finish = r200Finish;
989 functions->Flush = r200Flush;
990 }
991