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