87b6dac40bc640928d7f7a1f1e508248a306a0d0
[mesa.git] / src / mesa / drivers / dri / radeon / radeon_common.c
1 /**************************************************************************
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 /*
37 - Scissor implementation
38 - buffer swap/copy ioctls
39 - finish/flush
40 - state emission
41 - cmdbuffer management
42 */
43
44 #include <errno.h>
45 #include "main/glheader.h"
46 #include "main/imports.h"
47 #include "main/context.h"
48 #include "main/api_arrayelt.h"
49 #include "main/enums.h"
50 #include "main/colormac.h"
51 #include "main/light.h"
52 #include "main/framebuffer.h"
53 #include "main/simple_list.h"
54
55 #include "swrast/swrast.h"
56 #include "vbo/vbo.h"
57 #include "tnl/tnl.h"
58 #include "tnl/t_pipeline.h"
59 #include "swrast_setup/swrast_setup.h"
60
61 #include "dri_util.h"
62 #include "drirenderbuffer.h"
63 #include "vblank.h"
64
65 #include "radeon_common.h"
66 #include "radeon_common.h"
67 #include "radeon_bo.h"
68 #include "radeon_cs.h"
69 #include "radeon_bo_legacy.h"
70 #include "radeon_cs_legacy.h"
71 #include "radeon_bo_gem.h"
72 #include "radeon_cs_gem.h"
73 #include "radeon_drm.h"
74 #include "radeon_mipmap_tree.h"
75
76 #define DEBUG_CMDBUF 0
77
78 /* =============================================================
79 * Scissoring
80 */
81
82 static GLboolean intersect_rect(drm_clip_rect_t * out,
83 drm_clip_rect_t * a, drm_clip_rect_t * b)
84 {
85 *out = *a;
86 if (b->x1 > out->x1)
87 out->x1 = b->x1;
88 if (b->y1 > out->y1)
89 out->y1 = b->y1;
90 if (b->x2 < out->x2)
91 out->x2 = b->x2;
92 if (b->y2 < out->y2)
93 out->y2 = b->y2;
94 if (out->x1 >= out->x2)
95 return GL_FALSE;
96 if (out->y1 >= out->y2)
97 return GL_FALSE;
98 return GL_TRUE;
99 }
100
101 void radeonRecalcScissorRects(radeonContextPtr radeon)
102 {
103 drm_clip_rect_t *out;
104 int i;
105
106 /* Grow cliprect store?
107 */
108 if (radeon->state.scissor.numAllocedClipRects < radeon->numClipRects) {
109 while (radeon->state.scissor.numAllocedClipRects <
110 radeon->numClipRects) {
111 radeon->state.scissor.numAllocedClipRects += 1; /* zero case */
112 radeon->state.scissor.numAllocedClipRects *= 2;
113 }
114
115 if (radeon->state.scissor.pClipRects)
116 FREE(radeon->state.scissor.pClipRects);
117
118 radeon->state.scissor.pClipRects =
119 MALLOC(radeon->state.scissor.numAllocedClipRects *
120 sizeof(drm_clip_rect_t));
121
122 if (radeon->state.scissor.pClipRects == NULL) {
123 radeon->state.scissor.numAllocedClipRects = 0;
124 return;
125 }
126 }
127
128 out = radeon->state.scissor.pClipRects;
129 radeon->state.scissor.numClipRects = 0;
130
131 for (i = 0; i < radeon->numClipRects; i++) {
132 if (intersect_rect(out,
133 &radeon->pClipRects[i],
134 &radeon->state.scissor.rect)) {
135 radeon->state.scissor.numClipRects++;
136 out++;
137 }
138 }
139 }
140
141 /**
142 * Update cliprects and scissors.
143 */
144 void radeonSetCliprects(radeonContextPtr radeon)
145 {
146 __DRIdrawablePrivate *const drawable = radeon->dri.drawable;
147 __DRIdrawablePrivate *const readable = radeon->dri.readable;
148 GLframebuffer *const draw_fb = (GLframebuffer*)drawable->driverPrivate;
149 GLframebuffer *const read_fb = (GLframebuffer*)readable->driverPrivate;
150
151 if (!radeon->radeonScreen->driScreen->dri2.enabled) {
152 if (draw_fb->_ColorDrawBufferIndexes[0] == BUFFER_BACK_LEFT) {
153 /* Can't ignore 2d windows if we are page flipping. */
154 if (drawable->numBackClipRects == 0 || radeon->doPageFlip ||
155 radeon->sarea->pfCurrentPage == 1) {
156 radeon->numClipRects = drawable->numClipRects;
157 radeon->pClipRects = drawable->pClipRects;
158 } else {
159 radeon->numClipRects = drawable->numBackClipRects;
160 radeon->pClipRects = drawable->pBackClipRects;
161 }
162 } else {
163 /* front buffer (or none, or multiple buffers */
164 radeon->numClipRects = drawable->numClipRects;
165 radeon->pClipRects = drawable->pClipRects;
166 }
167 }
168
169 if ((draw_fb->Width != drawable->w) ||
170 (draw_fb->Height != drawable->h)) {
171 _mesa_resize_framebuffer(radeon->glCtx, draw_fb,
172 drawable->w, drawable->h);
173 draw_fb->Initialized = GL_TRUE;
174 }
175
176 if (drawable != readable) {
177 if ((read_fb->Width != readable->w) ||
178 (read_fb->Height != readable->h)) {
179 _mesa_resize_framebuffer(radeon->glCtx, read_fb,
180 readable->w, readable->h);
181 read_fb->Initialized = GL_TRUE;
182 }
183 }
184
185 if (radeon->state.scissor.enabled)
186 radeonRecalcScissorRects(radeon);
187
188 radeon->lastStamp = drawable->lastStamp;
189 }
190
191 void radeonUpdateScissor( GLcontext *ctx )
192 {
193 radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
194
195 if ( rmesa->dri.drawable ) {
196 __DRIdrawablePrivate *dPriv = rmesa->dri.drawable;
197
198 int x = ctx->Scissor.X;
199 int y = dPriv->h - ctx->Scissor.Y - ctx->Scissor.Height;
200 int w = ctx->Scissor.X + ctx->Scissor.Width - 1;
201 int h = dPriv->h - ctx->Scissor.Y - 1;
202
203 rmesa->state.scissor.rect.x1 = x + dPriv->x;
204 rmesa->state.scissor.rect.y1 = y + dPriv->y;
205 rmesa->state.scissor.rect.x2 = w + dPriv->x + 1;
206 rmesa->state.scissor.rect.y2 = h + dPriv->y + 1;
207
208 radeonRecalcScissorRects( rmesa );
209 }
210 }
211
212 /* =============================================================
213 * Scissoring
214 */
215
216 void radeonScissor(GLcontext* ctx, GLint x, GLint y, GLsizei w, GLsizei h)
217 {
218 radeonContextPtr radeon = RADEON_CONTEXT(ctx);
219 if (ctx->Scissor.Enabled) {
220 /* We don't pipeline cliprect changes */
221 radeon_firevertices(radeon);
222 radeonUpdateScissor(ctx);
223 }
224 }
225
226
227 /* ================================================================
228 * SwapBuffers with client-side throttling
229 */
230
231 static uint32_t radeonGetLastFrame(radeonContextPtr radeon)
232 {
233 drm_radeon_getparam_t gp;
234 int ret;
235 uint32_t frame;
236
237 gp.param = RADEON_PARAM_LAST_FRAME;
238 gp.value = (int *)&frame;
239 ret = drmCommandWriteRead(radeon->dri.fd, DRM_RADEON_GETPARAM,
240 &gp, sizeof(gp));
241 if (ret) {
242 fprintf(stderr, "%s: drmRadeonGetParam: %d\n", __FUNCTION__,
243 ret);
244 exit(1);
245 }
246
247 return frame;
248 }
249
250 uint32_t radeonGetAge(radeonContextPtr radeon)
251 {
252 drm_radeon_getparam_t gp;
253 int ret;
254 uint32_t age;
255
256 gp.param = RADEON_PARAM_LAST_CLEAR;
257 gp.value = (int *)&age;
258 ret = drmCommandWriteRead(radeon->dri.fd, DRM_RADEON_GETPARAM,
259 &gp, sizeof(gp));
260 if (ret) {
261 fprintf(stderr, "%s: drmRadeonGetParam: %d\n", __FUNCTION__,
262 ret);
263 exit(1);
264 }
265
266 return age;
267 }
268
269 static void radeonEmitIrqLocked(radeonContextPtr radeon)
270 {
271 drm_radeon_irq_emit_t ie;
272 int ret;
273
274 ie.irq_seq = &radeon->iw.irq_seq;
275 ret = drmCommandWriteRead(radeon->dri.fd, DRM_RADEON_IRQ_EMIT,
276 &ie, sizeof(ie));
277 if (ret) {
278 fprintf(stderr, "%s: drmRadeonIrqEmit: %d\n", __FUNCTION__,
279 ret);
280 exit(1);
281 }
282 }
283
284 static void radeonWaitIrq(radeonContextPtr radeon)
285 {
286 int ret;
287
288 do {
289 ret = drmCommandWrite(radeon->dri.fd, DRM_RADEON_IRQ_WAIT,
290 &radeon->iw, sizeof(radeon->iw));
291 } while (ret && (errno == EINTR || errno == EBUSY));
292
293 if (ret) {
294 fprintf(stderr, "%s: drmRadeonIrqWait: %d\n", __FUNCTION__,
295 ret);
296 exit(1);
297 }
298 }
299
300 static void radeonWaitForFrameCompletion(radeonContextPtr radeon)
301 {
302 drm_radeon_sarea_t *sarea = radeon->sarea;
303
304 if (radeon->do_irqs) {
305 if (radeonGetLastFrame(radeon) < sarea->last_frame) {
306 if (!radeon->irqsEmitted) {
307 while (radeonGetLastFrame(radeon) <
308 sarea->last_frame) ;
309 } else {
310 UNLOCK_HARDWARE(radeon);
311 radeonWaitIrq(radeon);
312 LOCK_HARDWARE(radeon);
313 }
314 radeon->irqsEmitted = 10;
315 }
316
317 if (radeon->irqsEmitted) {
318 radeonEmitIrqLocked(radeon);
319 radeon->irqsEmitted--;
320 }
321 } else {
322 while (radeonGetLastFrame(radeon) < sarea->last_frame) {
323 UNLOCK_HARDWARE(radeon);
324 if (radeon->do_usleeps)
325 DO_USLEEP(1);
326 LOCK_HARDWARE(radeon);
327 }
328 }
329 }
330
331 /* wait for idle */
332 void radeonWaitForIdleLocked(radeonContextPtr radeon)
333 {
334 int ret;
335 int i = 0;
336
337 do {
338 ret = drmCommandNone(radeon->dri.fd, DRM_RADEON_CP_IDLE);
339 if (ret)
340 DO_USLEEP(1);
341 } while (ret && ++i < 100);
342
343 if (ret < 0) {
344 UNLOCK_HARDWARE(radeon);
345 fprintf(stderr, "Error: R300 timed out... exiting\n");
346 exit(-1);
347 }
348 }
349
350 static void radeonWaitForIdle(radeonContextPtr radeon)
351 {
352 LOCK_HARDWARE(radeon);
353 radeonWaitForIdleLocked(radeon);
354 UNLOCK_HARDWARE(radeon);
355 }
356
357
358 /* Copy the back color buffer to the front color buffer.
359 */
360 void radeonCopyBuffer( __DRIdrawablePrivate *dPriv,
361 const drm_clip_rect_t *rect)
362 {
363 radeonContextPtr rmesa;
364 GLint nbox, i, ret;
365 GLboolean missed_target;
366 int64_t ust;
367 __DRIscreenPrivate *psp;
368
369 assert(dPriv);
370 assert(dPriv->driContextPriv);
371 assert(dPriv->driContextPriv->driverPrivate);
372
373 rmesa = (radeonContextPtr) dPriv->driContextPriv->driverPrivate;
374
375 if ( RADEON_DEBUG & DEBUG_IOCTL ) {
376 fprintf( stderr, "\n%s( %p )\n\n", __FUNCTION__, (void *) rmesa->glCtx );
377 }
378
379 radeon_firevertices(rmesa);
380 LOCK_HARDWARE( rmesa );
381
382 /* Throttle the frame rate -- only allow one pending swap buffers
383 * request at a time.
384 */
385 radeonWaitForFrameCompletion( rmesa );
386 if (!rect)
387 {
388 UNLOCK_HARDWARE( rmesa );
389 driWaitForVBlank( dPriv, & missed_target );
390 LOCK_HARDWARE( rmesa );
391 }
392
393 nbox = dPriv->numClipRects; /* must be in locked region */
394
395 for ( i = 0 ; i < nbox ; ) {
396 GLint nr = MIN2( i + RADEON_NR_SAREA_CLIPRECTS , nbox );
397 drm_clip_rect_t *box = dPriv->pClipRects;
398 drm_clip_rect_t *b = rmesa->sarea->boxes;
399 GLint n = 0;
400
401 for ( ; i < nr ; i++ ) {
402
403 *b = box[i];
404
405 if (rect)
406 {
407 if (rect->x1 > b->x1)
408 b->x1 = rect->x1;
409 if (rect->y1 > b->y1)
410 b->y1 = rect->y1;
411 if (rect->x2 < b->x2)
412 b->x2 = rect->x2;
413 if (rect->y2 < b->y2)
414 b->y2 = rect->y2;
415
416 if (b->x1 >= b->x2 || b->y1 >= b->y2)
417 continue;
418 }
419
420 b++;
421 n++;
422 }
423 rmesa->sarea->nbox = n;
424
425 if (!n)
426 continue;
427
428 ret = drmCommandNone( rmesa->dri.fd, DRM_RADEON_SWAP );
429
430 if ( ret ) {
431 fprintf( stderr, "DRM_RADEON_SWAP_BUFFERS: return = %d\n", ret );
432 UNLOCK_HARDWARE( rmesa );
433 exit( 1 );
434 }
435 }
436
437 UNLOCK_HARDWARE( rmesa );
438 if (!rect)
439 {
440 psp = dPriv->driScreenPriv;
441 rmesa->swap_count++;
442 (*psp->systemTime->getUST)( & ust );
443 if ( missed_target ) {
444 rmesa->swap_missed_count++;
445 rmesa->swap_missed_ust = ust - rmesa->swap_ust;
446 }
447
448 rmesa->swap_ust = ust;
449 rmesa->hw.all_dirty = GL_TRUE;
450
451 }
452 }
453
454 void radeonPageFlip( __DRIdrawablePrivate *dPriv )
455 {
456 radeonContextPtr rmesa;
457 GLint ret;
458 GLboolean missed_target;
459 __DRIscreenPrivate *psp;
460 struct radeon_renderbuffer *rrb;
461 GLframebuffer *fb = dPriv->driverPrivate;
462
463 assert(dPriv);
464 assert(dPriv->driContextPriv);
465 assert(dPriv->driContextPriv->driverPrivate);
466
467 rmesa = (radeonContextPtr) dPriv->driContextPriv->driverPrivate;
468 rrb = (void *)fb->Attachment[BUFFER_FRONT_LEFT].Renderbuffer;
469
470 psp = dPriv->driScreenPriv;
471
472 if ( RADEON_DEBUG & DEBUG_IOCTL ) {
473 fprintf(stderr, "%s: pfCurrentPage: %d\n", __FUNCTION__,
474 rmesa->sarea->pfCurrentPage);
475 }
476
477 radeon_firevertices(rmesa);
478
479 LOCK_HARDWARE( rmesa );
480
481 if (!dPriv->numClipRects) {
482 UNLOCK_HARDWARE(rmesa);
483 usleep(10000); /* throttle invisible client 10ms */
484 return;
485 }
486
487 drm_clip_rect_t *box = dPriv->pClipRects;
488 drm_clip_rect_t *b = rmesa->sarea->boxes;
489 b[0] = box[0];
490 rmesa->sarea->nbox = 1;
491
492 /* Throttle the frame rate -- only allow a few pending swap buffers
493 * request at a time.
494 */
495 radeonWaitForFrameCompletion( rmesa );
496 UNLOCK_HARDWARE( rmesa );
497 driWaitForVBlank( dPriv, & missed_target );
498 if ( missed_target ) {
499 rmesa->swap_missed_count++;
500 (void) (*psp->systemTime->getUST)( & rmesa->swap_missed_ust );
501 }
502 LOCK_HARDWARE( rmesa );
503
504 ret = drmCommandNone( rmesa->dri.fd, DRM_RADEON_FLIP );
505
506 UNLOCK_HARDWARE( rmesa );
507
508 if ( ret ) {
509 fprintf( stderr, "DRM_RADEON_FLIP: return = %d\n", ret );
510 exit( 1 );
511 }
512
513 rmesa->swap_count++;
514 (void) (*psp->systemTime->getUST)( & rmesa->swap_ust );
515
516 /* Get ready for drawing next frame. Update the renderbuffers'
517 * flippedOffset/Pitch fields so we draw into the right place.
518 */
519 driFlipRenderbuffers(rmesa->glCtx->WinSysDrawBuffer,
520 rmesa->sarea->pfCurrentPage);
521
522 rmesa->state.color.rrb = rrb;
523
524 if (rmesa->vtbl.update_draw_buffer)
525 rmesa->vtbl.update_draw_buffer(rmesa->glCtx);
526 }
527
528
529 /**
530 * Swap front and back buffer.
531 */
532 void radeonSwapBuffers(__DRIdrawablePrivate * dPriv)
533 {
534 if (dPriv->driContextPriv && dPriv->driContextPriv->driverPrivate) {
535 radeonContextPtr radeon;
536 GLcontext *ctx;
537
538 radeon = (radeonContextPtr) dPriv->driContextPriv->driverPrivate;
539 ctx = radeon->glCtx;
540
541 if (ctx->Visual.doubleBufferMode) {
542 _mesa_notifySwapBuffers(ctx);/* flush pending rendering comands */
543 if (radeon->doPageFlip) {
544 radeonPageFlip(dPriv);
545 } else {
546 radeonCopyBuffer(dPriv, NULL);
547 }
548 }
549 } else {
550 /* XXX this shouldn't be an error but we can't handle it for now */
551 _mesa_problem(NULL, "%s: drawable has no context!",
552 __FUNCTION__);
553 }
554 }
555
556 void radeonCopySubBuffer(__DRIdrawablePrivate * dPriv,
557 int x, int y, int w, int h )
558 {
559 if (dPriv->driContextPriv && dPriv->driContextPriv->driverPrivate) {
560 radeonContextPtr radeon;
561 GLcontext *ctx;
562
563 radeon = (radeonContextPtr) dPriv->driContextPriv->driverPrivate;
564 ctx = radeon->glCtx;
565
566 if (ctx->Visual.doubleBufferMode) {
567 drm_clip_rect_t rect;
568 rect.x1 = x + dPriv->x;
569 rect.y1 = (dPriv->h - y - h) + dPriv->y;
570 rect.x2 = rect.x1 + w;
571 rect.y2 = rect.y1 + h;
572 _mesa_notifySwapBuffers(ctx); /* flush pending rendering comands */
573 radeonCopyBuffer(dPriv, &rect);
574 }
575 } else {
576 /* XXX this shouldn't be an error but we can't handle it for now */
577 _mesa_problem(NULL, "%s: drawable has no context!",
578 __FUNCTION__);
579 }
580 }
581
582
583 static void radeon_print_state_atom( struct radeon_state_atom *state )
584 {
585 int i;
586
587 fprintf(stderr, "emit %s/%d\n", state->name, state->cmd_size);
588
589 if (RADEON_DEBUG & DEBUG_VERBOSE)
590 for (i = 0 ; i < state->cmd_size ; i++)
591 fprintf(stderr, "\t%s[%d]: %x\n", state->name, i, state->cmd[i]);
592
593 }
594
595 static INLINE void radeonEmitAtoms(radeonContextPtr radeon, GLboolean dirty)
596 {
597 BATCH_LOCALS(radeon);
598 struct radeon_state_atom *atom;
599 int dwords;
600
601 if (radeon->vtbl.pre_emit_atoms)
602 radeon->vtbl.pre_emit_atoms(radeon);
603
604 /* Emit actual atoms */
605 foreach(atom, &radeon->hw.atomlist) {
606 if ((atom->dirty || radeon->hw.all_dirty) == dirty) {
607 dwords = (*atom->check) (radeon->glCtx, atom);
608 if (dwords) {
609 if (DEBUG_CMDBUF && RADEON_DEBUG & DEBUG_STATE) {
610 radeon_print_state_atom(atom);
611 }
612 if (atom->emit) {
613 (*atom->emit)(radeon->glCtx, atom);
614 } else {
615 BEGIN_BATCH_NO_AUTOSTATE(dwords);
616 OUT_BATCH_TABLE(atom->cmd, dwords);
617 END_BATCH();
618 }
619 atom->dirty = GL_FALSE;
620 } else {
621 if (DEBUG_CMDBUF && RADEON_DEBUG & DEBUG_STATE) {
622 fprintf(stderr, " skip state %s\n",
623 atom->name);
624 }
625 }
626 }
627 }
628
629 COMMIT_BATCH();
630 }
631
632 void radeonEmitState(radeonContextPtr radeon)
633 {
634 if (RADEON_DEBUG & (DEBUG_STATE|DEBUG_PRIMS))
635 fprintf(stderr, "%s\n", __FUNCTION__);
636
637 if (radeon->vtbl.pre_emit_state)
638 radeon->vtbl.pre_emit_state(radeon);
639
640 /* this code used to return here but now it emits zbs */
641 if (radeon->cmdbuf.cs->cdw && !radeon->hw.is_dirty && !radeon->hw.all_dirty)
642 return;
643
644 /* To avoid going across the entire set of states multiple times, just check
645 * for enough space for the case of emitting all state, and inline the
646 * radeonAllocCmdBuf code here without all the checks.
647 */
648 rcommonEnsureCmdBufSpace(radeon, radeon->hw.max_state_size, __FUNCTION__);
649
650 if (!radeon->cmdbuf.cs->cdw) {
651 if (RADEON_DEBUG & DEBUG_STATE)
652 fprintf(stderr, "Begin reemit state\n");
653
654 radeonEmitAtoms(radeon, GL_FALSE);
655 }
656
657 if (RADEON_DEBUG & DEBUG_STATE)
658 fprintf(stderr, "Begin dirty state\n");
659
660 radeonEmitAtoms(radeon, GL_TRUE);
661 radeon->hw.is_dirty = GL_FALSE;
662 radeon->hw.all_dirty = GL_FALSE;
663
664 }
665
666
667 void radeonFlush(GLcontext *ctx)
668 {
669 radeonContextPtr radeon = RADEON_CONTEXT(ctx);
670 if (RADEON_DEBUG & DEBUG_IOCTL)
671 fprintf(stderr, "%s\n", __FUNCTION__);
672
673 if (radeon->dma.flush)
674 radeon->dma.flush( ctx );
675
676 radeonEmitState(radeon);
677
678 if (radeon->cmdbuf.cs->cdw)
679 rcommonFlushCmdBuf(radeon, __FUNCTION__);
680 }
681
682 /* Make sure all commands have been sent to the hardware and have
683 * completed processing.
684 */
685 void radeonFinish(GLcontext * ctx)
686 {
687 radeonContextPtr radeon = RADEON_CONTEXT(ctx);
688 struct gl_framebuffer *fb = ctx->DrawBuffer;
689 int i;
690
691 radeonFlush(ctx);
692
693 if (radeon->radeonScreen->kernel_mm) {
694 for (i = 0; i < fb->_NumColorDrawBuffers; i++) {
695 struct radeon_renderbuffer *rrb;
696 rrb = (struct radeon_renderbuffer *)fb->_ColorDrawBuffers[i];
697 if (rrb->bo)
698 radeon_bo_wait(rrb->bo);
699 }
700 } else if (radeon->do_irqs) {
701 LOCK_HARDWARE(radeon);
702 radeonEmitIrqLocked(radeon);
703 UNLOCK_HARDWARE(radeon);
704 radeonWaitIrq(radeon);
705 } else {
706 radeonWaitForIdle(radeon);
707 }
708 }
709
710 /* cmdbuffer */
711 /**
712 * Send the current command buffer via ioctl to the hardware.
713 */
714 int rcommonFlushCmdBufLocked(radeonContextPtr rmesa, const char *caller)
715 {
716 int ret = 0;
717
718 if (rmesa->cmdbuf.flushing) {
719 fprintf(stderr, "Recursive call into r300FlushCmdBufLocked!\n");
720 exit(-1);
721 }
722 rmesa->cmdbuf.flushing = 1;
723 if (rmesa->cmdbuf.cs->cdw) {
724 ret = radeon_cs_emit(rmesa->cmdbuf.cs);
725 rmesa->hw.all_dirty = GL_TRUE;
726 }
727 radeon_cs_erase(rmesa->cmdbuf.cs);
728 rmesa->cmdbuf.flushing = 0;
729 return ret;
730 }
731
732 int rcommonFlushCmdBuf(radeonContextPtr rmesa, const char *caller)
733 {
734 int ret;
735
736 radeonReleaseDmaRegion(rmesa);
737
738 LOCK_HARDWARE(rmesa);
739 ret = rcommonFlushCmdBufLocked(rmesa, caller);
740 UNLOCK_HARDWARE(rmesa);
741
742 if (ret) {
743 fprintf(stderr, "drmRadeonCmdBuffer: %d\n", ret);
744 _mesa_exit(ret);
745 }
746
747 return ret;
748 }
749
750 /**
751 * Make sure that enough space is available in the command buffer
752 * by flushing if necessary.
753 *
754 * \param dwords The number of dwords we need to be free on the command buffer
755 */
756 void rcommonEnsureCmdBufSpace(radeonContextPtr rmesa, int dwords, const char *caller)
757 {
758 if ((rmesa->cmdbuf.cs->cdw + dwords + 128) > rmesa->cmdbuf.size ||
759 radeon_cs_need_flush(rmesa->cmdbuf.cs)) {
760 rcommonFlushCmdBuf(rmesa, caller);
761 }
762 }
763
764 void rcommonInitCmdBuf(radeonContextPtr rmesa)
765 {
766 GLuint size;
767 /* Initialize command buffer */
768 size = 256 * driQueryOptioni(&rmesa->optionCache,
769 "command_buffer_size");
770 if (size < 2 * rmesa->hw.max_state_size) {
771 size = 2 * rmesa->hw.max_state_size + 65535;
772 }
773 if (size > 64 * 256)
774 size = 64 * 256;
775
776 if (RADEON_DEBUG & (DEBUG_IOCTL | DEBUG_DMA)) {
777 fprintf(stderr, "sizeof(drm_r300_cmd_header_t)=%zd\n",
778 sizeof(drm_r300_cmd_header_t));
779 fprintf(stderr, "sizeof(drm_radeon_cmd_buffer_t)=%zd\n",
780 sizeof(drm_radeon_cmd_buffer_t));
781 fprintf(stderr,
782 "Allocating %d bytes command buffer (max state is %d bytes)\n",
783 size * 4, rmesa->hw.max_state_size * 4);
784 }
785
786 if (rmesa->radeonScreen->kernel_mm) {
787 int fd = rmesa->radeonScreen->driScreen->fd;
788 rmesa->cmdbuf.csm = radeon_cs_manager_gem_ctor(fd);
789 } else {
790 rmesa->cmdbuf.csm = radeon_cs_manager_legacy_ctor(rmesa);
791 }
792 if (rmesa->cmdbuf.csm == NULL) {
793 /* FIXME: fatal error */
794 return;
795 }
796 rmesa->cmdbuf.cs = radeon_cs_create(rmesa->cmdbuf.csm, size);
797 assert(rmesa->cmdbuf.cs != NULL);
798 rmesa->cmdbuf.size = size;
799
800 if (!rmesa->radeonScreen->kernel_mm) {
801 radeon_cs_set_limit(rmesa->cmdbuf.cs, RADEON_GEM_DOMAIN_VRAM, rmesa->radeonScreen->texSize[0]);
802 radeon_cs_set_limit(rmesa->cmdbuf.cs, RADEON_GEM_DOMAIN_GTT, rmesa->radeonScreen->gartTextures.size);
803 } else {
804 struct drm_radeon_gem_info mminfo;
805
806 if (!drmCommandWriteRead(rmesa->dri.fd, DRM_RADEON_GEM_INFO, &mminfo, sizeof(mminfo)))
807 {
808 radeon_cs_set_limit(rmesa->cmdbuf.cs, RADEON_GEM_DOMAIN_VRAM, mminfo.vram_size);
809 radeon_cs_set_limit(rmesa->cmdbuf.cs, RADEON_GEM_DOMAIN_GTT, mminfo.gart_size);
810 }
811 }
812
813 }
814 /**
815 * Destroy the command buffer
816 */
817 void rcommonDestroyCmdBuf(radeonContextPtr rmesa)
818 {
819 radeon_cs_destroy(rmesa->cmdbuf.cs);
820 if (rmesa->radeonScreen->driScreen->dri2.enabled || rmesa->radeonScreen->kernel_mm) {
821 radeon_cs_manager_gem_dtor(rmesa->cmdbuf.csm);
822 } else {
823 radeon_cs_manager_legacy_dtor(rmesa->cmdbuf.csm);
824 }
825 }
826
827 void rcommonBeginBatch(radeonContextPtr rmesa, int n,
828 int dostate,
829 const char *file,
830 const char *function,
831 int line)
832 {
833 rcommonEnsureCmdBufSpace(rmesa, n, function);
834 if (!rmesa->cmdbuf.cs->cdw && dostate) {
835 if (RADEON_DEBUG & DEBUG_IOCTL)
836 fprintf(stderr, "Reemit state after flush (from %s)\n", function);
837 radeonEmitState(rmesa);
838 }
839 radeon_cs_begin(rmesa->cmdbuf.cs, n, file, function, line);
840 }
841
842
843