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