b14ca8b51b26530643bb8b1ef42dee4b0d336489
[mesa.git] / src / mesa / drivers / dri / radeon / common_misc.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 #include <errno.h>
37 #include "main/glheader.h"
38 #include "main/imports.h"
39 #include "main/api_arrayelt.h"
40 #include "main/enums.h"
41 #include "main/colormac.h"
42 #include "main/light.h"
43 #include "main/framebuffer.h"
44
45 #include "swrast/swrast.h"
46 #include "vbo/vbo.h"
47 #include "tnl/tnl.h"
48 #include "tnl/t_pipeline.h"
49 #include "swrast_setup/swrast_setup.h"
50
51 #include "drirenderbuffer.h"
52 #include "vblank.h"
53
54
55 #include "dri_util.h"
56 #include "radeon_drm.h"
57 #include "radeon_screen.h"
58 #include "radeon_buffer.h"
59 #include "common_context.h"
60 #include "common_misc.h"
61 #include "common_lock.h"
62
63 /* =============================================================
64 * Scissoring
65 */
66
67 static GLboolean intersect_rect(drm_clip_rect_t * out,
68 drm_clip_rect_t * a, drm_clip_rect_t * b)
69 {
70 *out = *a;
71 if (b->x1 > out->x1)
72 out->x1 = b->x1;
73 if (b->y1 > out->y1)
74 out->y1 = b->y1;
75 if (b->x2 < out->x2)
76 out->x2 = b->x2;
77 if (b->y2 < out->y2)
78 out->y2 = b->y2;
79 if (out->x1 >= out->x2)
80 return GL_FALSE;
81 if (out->y1 >= out->y2)
82 return GL_FALSE;
83 return GL_TRUE;
84 }
85
86 void radeonRecalcScissorRects(radeonContextPtr radeon)
87 {
88 drm_clip_rect_t *out;
89 int i;
90
91 /* Grow cliprect store?
92 */
93 if (radeon->state.scissor.numAllocedClipRects < radeon->numClipRects) {
94 while (radeon->state.scissor.numAllocedClipRects <
95 radeon->numClipRects) {
96 radeon->state.scissor.numAllocedClipRects += 1; /* zero case */
97 radeon->state.scissor.numAllocedClipRects *= 2;
98 }
99
100 if (radeon->state.scissor.pClipRects)
101 FREE(radeon->state.scissor.pClipRects);
102
103 radeon->state.scissor.pClipRects =
104 MALLOC(radeon->state.scissor.numAllocedClipRects *
105 sizeof(drm_clip_rect_t));
106
107 if (radeon->state.scissor.pClipRects == NULL) {
108 radeon->state.scissor.numAllocedClipRects = 0;
109 return;
110 }
111 }
112
113 out = radeon->state.scissor.pClipRects;
114 radeon->state.scissor.numClipRects = 0;
115
116 for (i = 0; i < radeon->numClipRects; i++) {
117 if (intersect_rect(out,
118 &radeon->pClipRects[i],
119 &radeon->state.scissor.rect)) {
120 radeon->state.scissor.numClipRects++;
121 out++;
122 }
123 }
124 }
125
126 /**
127 * Update cliprects and scissors.
128 */
129 void radeonSetCliprects(radeonContextPtr radeon)
130 {
131 __DRIdrawablePrivate *const drawable = radeon->dri.drawable;
132 __DRIdrawablePrivate *const readable = radeon->dri.readable;
133 GLframebuffer *const draw_fb = (GLframebuffer*)drawable->driverPrivate;
134 GLframebuffer *const read_fb = (GLframebuffer*)readable->driverPrivate;
135
136 if (!radeon->radeonScreen->driScreen->dri2.enabled) {
137 if (draw_fb->_ColorDrawBufferIndexes[0] == BUFFER_BACK_LEFT) {
138 /* Can't ignore 2d windows if we are page flipping. */
139 if (drawable->numBackClipRects == 0 || radeon->doPageFlip ||
140 radeon->sarea->pfCurrentPage == 1) {
141 radeon->numClipRects = drawable->numClipRects;
142 radeon->pClipRects = drawable->pClipRects;
143 } else {
144 radeon->numClipRects = drawable->numBackClipRects;
145 radeon->pClipRects = drawable->pBackClipRects;
146 }
147 } else {
148 /* front buffer (or none, or multiple buffers */
149 radeon->numClipRects = drawable->numClipRects;
150 radeon->pClipRects = drawable->pClipRects;
151 }
152 }
153
154 if ((draw_fb->Width != drawable->w) ||
155 (draw_fb->Height != drawable->h)) {
156 _mesa_resize_framebuffer(radeon->glCtx, draw_fb,
157 drawable->w, drawable->h);
158 draw_fb->Initialized = GL_TRUE;
159 }
160
161 if (drawable != readable) {
162 if ((read_fb->Width != readable->w) ||
163 (read_fb->Height != readable->h)) {
164 _mesa_resize_framebuffer(radeon->glCtx, read_fb,
165 readable->w, readable->h);
166 read_fb->Initialized = GL_TRUE;
167 }
168 }
169
170 if (radeon->state.scissor.enabled)
171 radeonRecalcScissorRects(radeon);
172
173 radeon->lastStamp = drawable->lastStamp;
174 }
175
176 void radeonUpdateScissor( GLcontext *ctx )
177 {
178 radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
179
180 if ( rmesa->dri.drawable ) {
181 __DRIdrawablePrivate *dPriv = rmesa->dri.drawable;
182
183 int x = ctx->Scissor.X;
184 int y = dPriv->h - ctx->Scissor.Y - ctx->Scissor.Height;
185 int w = ctx->Scissor.X + ctx->Scissor.Width - 1;
186 int h = dPriv->h - ctx->Scissor.Y - 1;
187
188 rmesa->state.scissor.rect.x1 = x + dPriv->x;
189 rmesa->state.scissor.rect.y1 = y + dPriv->y;
190 rmesa->state.scissor.rect.x2 = w + dPriv->x + 1;
191 rmesa->state.scissor.rect.y2 = h + dPriv->y + 1;
192
193 radeonRecalcScissorRects( rmesa );
194 }
195 }
196
197 /* ================================================================
198 * SwapBuffers with client-side throttling
199 */
200
201 static uint32_t radeonGetLastFrame(radeonContextPtr radeon)
202 {
203 drm_radeon_getparam_t gp;
204 int ret;
205 uint32_t frame;
206
207 gp.param = RADEON_PARAM_LAST_FRAME;
208 gp.value = (int *)&frame;
209 ret = drmCommandWriteRead(radeon->dri.fd, DRM_RADEON_GETPARAM,
210 &gp, sizeof(gp));
211 if (ret) {
212 fprintf(stderr, "%s: drmRadeonGetParam: %d\n", __FUNCTION__,
213 ret);
214 exit(1);
215 }
216
217 return frame;
218 }
219
220 uint32_t radeonGetAge(radeonContextPtr radeon)
221 {
222 drm_radeon_getparam_t gp;
223 int ret;
224 uint32_t age;
225
226 gp.param = RADEON_PARAM_LAST_CLEAR;
227 gp.value = (int *)&age;
228 ret = drmCommandWriteRead(radeon->dri.fd, DRM_RADEON_GETPARAM,
229 &gp, sizeof(gp));
230 if (ret) {
231 fprintf(stderr, "%s: drmRadeonGetParam: %d\n", __FUNCTION__,
232 ret);
233 exit(1);
234 }
235
236 return age;
237 }
238
239 static void radeonEmitIrqLocked(radeonContextPtr radeon)
240 {
241 drm_radeon_irq_emit_t ie;
242 int ret;
243
244 ie.irq_seq = &radeon->iw.irq_seq;
245 ret = drmCommandWriteRead(radeon->dri.fd, DRM_RADEON_IRQ_EMIT,
246 &ie, sizeof(ie));
247 if (ret) {
248 fprintf(stderr, "%s: drmRadeonIrqEmit: %d\n", __FUNCTION__,
249 ret);
250 exit(1);
251 }
252 }
253
254 static void radeonWaitIrq(radeonContextPtr radeon)
255 {
256 int ret;
257
258 do {
259 ret = drmCommandWrite(radeon->dri.fd, DRM_RADEON_IRQ_WAIT,
260 &radeon->iw, sizeof(radeon->iw));
261 } while (ret && (errno == EINTR || errno == EBUSY));
262
263 if (ret) {
264 fprintf(stderr, "%s: drmRadeonIrqWait: %d\n", __FUNCTION__,
265 ret);
266 exit(1);
267 }
268 }
269
270 static void radeonWaitForFrameCompletion(radeonContextPtr radeon)
271 {
272 drm_radeon_sarea_t *sarea = radeon->sarea;
273
274 if (radeon->do_irqs) {
275 if (radeonGetLastFrame(radeon) < sarea->last_frame) {
276 if (!radeon->irqsEmitted) {
277 while (radeonGetLastFrame(radeon) <
278 sarea->last_frame) ;
279 } else {
280 UNLOCK_HARDWARE(radeon);
281 radeonWaitIrq(radeon);
282 LOCK_HARDWARE(radeon);
283 }
284 radeon->irqsEmitted = 10;
285 }
286
287 if (radeon->irqsEmitted) {
288 radeonEmitIrqLocked(radeon);
289 radeon->irqsEmitted--;
290 }
291 } else {
292 while (radeonGetLastFrame(radeon) < sarea->last_frame) {
293 UNLOCK_HARDWARE(radeon);
294 if (radeon->do_usleeps)
295 DO_USLEEP(1);
296 LOCK_HARDWARE(radeon);
297 }
298 }
299 }
300
301 /* wait for idle */
302 void radeonWaitForIdleLocked(radeonContextPtr radeon)
303 {
304 int ret;
305 int i = 0;
306
307 do {
308 ret = drmCommandNone(radeon->dri.fd, DRM_RADEON_CP_IDLE);
309 if (ret)
310 DO_USLEEP(1);
311 } while (ret && ++i < 100);
312
313 if (ret < 0) {
314 UNLOCK_HARDWARE(radeon);
315 fprintf(stderr, "Error: R300 timed out... exiting\n");
316 exit(-1);
317 }
318 }
319
320 static void radeonWaitForIdle(radeonContextPtr radeon)
321 {
322 LOCK_HARDWARE(radeon);
323 radeonWaitForIdleLocked(radeon);
324 UNLOCK_HARDWARE(radeon);
325 }
326
327
328 /* Copy the back color buffer to the front color buffer.
329 */
330 void radeonCopyBuffer( __DRIdrawablePrivate *dPriv,
331 const drm_clip_rect_t *rect)
332 {
333 GLcontext *ctx;
334 radeonContextPtr rmesa;
335 GLint nbox, i, ret;
336 GLboolean missed_target;
337 int64_t ust;
338 __DRIscreenPrivate *psp;
339
340 assert(dPriv);
341 assert(dPriv->driContextPriv);
342 assert(dPriv->driContextPriv->driverPrivate);
343
344 ctx = (GLcontext *) dPriv->driContextPriv->driverPrivate;
345 rmesa = (radeonContextPtr) dPriv->driContextPriv->driverPrivate;
346
347 /// if ( RADEON_DEBUG & DEBUG_IOCTL ) {
348 // fprintf( stderr, "\n%s( %p )\n\n", __FUNCTION__, (void *) rmesa->glCtx );
349 // }
350
351 rmesa->vtbl.flush(ctx);
352 LOCK_HARDWARE( rmesa );
353
354 /* Throttle the frame rate -- only allow one pending swap buffers
355 * request at a time.
356 */
357 radeonWaitForFrameCompletion( rmesa );
358 if (!rect)
359 {
360 UNLOCK_HARDWARE( rmesa );
361 driWaitForVBlank( dPriv, & missed_target );
362 LOCK_HARDWARE( rmesa );
363 }
364
365 nbox = dPriv->numClipRects; /* must be in locked region */
366
367 for ( i = 0 ; i < nbox ; ) {
368 GLint nr = MIN2( i + RADEON_NR_SAREA_CLIPRECTS , nbox );
369 drm_clip_rect_t *box = dPriv->pClipRects;
370 drm_clip_rect_t *b = rmesa->sarea->boxes;
371 GLint n = 0;
372
373 for ( ; i < nr ; i++ ) {
374
375 *b = box[i];
376
377 if (rect)
378 {
379 if (rect->x1 > b->x1)
380 b->x1 = rect->x1;
381 if (rect->y1 > b->y1)
382 b->y1 = rect->y1;
383 if (rect->x2 < b->x2)
384 b->x2 = rect->x2;
385 if (rect->y2 < b->y2)
386 b->y2 = rect->y2;
387
388 if (b->x1 >= b->x2 || b->y1 >= b->y2)
389 continue;
390 }
391
392 b++;
393 n++;
394 }
395 rmesa->sarea->nbox = n;
396
397 if (!n)
398 continue;
399
400 ret = drmCommandNone( rmesa->dri.fd, DRM_RADEON_SWAP );
401
402 if ( ret ) {
403 fprintf( stderr, "DRM_RADEON_SWAP_BUFFERS: return = %d\n", ret );
404 UNLOCK_HARDWARE( rmesa );
405 exit( 1 );
406 }
407 }
408
409 UNLOCK_HARDWARE( rmesa );
410 if (!rect)
411 {
412 psp = dPriv->driScreenPriv;
413 rmesa->swap_count++;
414 (*psp->systemTime->getUST)( & ust );
415 if ( missed_target ) {
416 rmesa->swap_missed_count++;
417 rmesa->swap_missed_ust = ust - rmesa->swap_ust;
418 }
419
420 rmesa->swap_ust = ust;
421 rmesa->vtbl.set_all_dirty(ctx);
422
423 }
424 }
425
426 void radeonPageFlip( __DRIdrawablePrivate *dPriv )
427 {
428 radeonContextPtr rmesa;
429 GLint ret;
430 GLboolean missed_target;
431 __DRIscreenPrivate *psp;
432 struct radeon_renderbuffer *rrb;
433 GLframebuffer *fb = dPriv->driverPrivate;
434
435 assert(dPriv);
436 assert(dPriv->driContextPriv);
437 assert(dPriv->driContextPriv->driverPrivate);
438
439 rmesa = (radeonContextPtr) dPriv->driContextPriv->driverPrivate;
440 rrb = (void *)fb->Attachment[BUFFER_FRONT_LEFT].Renderbuffer;
441
442 psp = dPriv->driScreenPriv;
443
444 #if 0
445 if ( RADEON_DEBUG & DEBUG_IOCTL ) {
446 fprintf(stderr, "%s: pfCurrentPage: %d\n", __FUNCTION__,
447 rmesa->sarea->pfCurrentPage);
448 }
449 #endif
450
451 rmesa->vtbl.flush(rmesa->glCtx);
452
453 LOCK_HARDWARE( rmesa );
454
455 if (!dPriv->numClipRects) {
456 UNLOCK_HARDWARE(rmesa);
457 usleep(10000); /* throttle invisible client 10ms */
458 return;
459 }
460
461 drm_clip_rect_t *box = dPriv->pClipRects;
462 drm_clip_rect_t *b = rmesa->sarea->boxes;
463 b[0] = box[0];
464 rmesa->sarea->nbox = 1;
465
466 /* Throttle the frame rate -- only allow a few pending swap buffers
467 * request at a time.
468 */
469 radeonWaitForFrameCompletion( rmesa );
470 UNLOCK_HARDWARE( rmesa );
471 driWaitForVBlank( dPriv, & missed_target );
472 if ( missed_target ) {
473 rmesa->swap_missed_count++;
474 (void) (*psp->systemTime->getUST)( & rmesa->swap_missed_ust );
475 }
476 LOCK_HARDWARE( rmesa );
477
478 ret = drmCommandNone( rmesa->dri.fd, DRM_RADEON_FLIP );
479
480 UNLOCK_HARDWARE( rmesa );
481
482 if ( ret ) {
483 fprintf( stderr, "DRM_RADEON_FLIP: return = %d\n", ret );
484 exit( 1 );
485 }
486
487 rmesa->swap_count++;
488 (void) (*psp->systemTime->getUST)( & rmesa->swap_ust );
489
490 /* Get ready for drawing next frame. Update the renderbuffers'
491 * flippedOffset/Pitch fields so we draw into the right place.
492 */
493 driFlipRenderbuffers(rmesa->glCtx->WinSysDrawBuffer,
494 rmesa->sarea->pfCurrentPage);
495
496 rmesa->state.color.rrb = rrb;
497
498 if (rmesa->vtbl.update_draw_buffer)
499 rmesa->vtbl.update_draw_buffer(rmesa->glCtx);
500 }
501
502
503 /* Make sure all commands have been sent to the hardware and have
504 * completed processing.
505 */
506 void radeon_common_finish(GLcontext * ctx)
507 {
508 radeonContextPtr radeon = RADEON_CONTEXT(ctx);
509 struct gl_framebuffer *fb = ctx->DrawBuffer;
510 int i;
511
512 if (radeon->radeonScreen->kernel_mm) {
513 for (i = 0; i < fb->_NumColorDrawBuffers; i++) {
514 struct radeon_renderbuffer *rrb;
515 rrb = (struct radeon_renderbuffer *)fb->_ColorDrawBuffers[i];
516 if (rrb->bo)
517 radeon_bo_wait(rrb->bo);
518 }
519 } else if (radeon->do_irqs) {
520 LOCK_HARDWARE(radeon);
521 radeonEmitIrqLocked(radeon);
522 UNLOCK_HARDWARE(radeon);
523 radeonWaitIrq(radeon);
524 } else {
525 radeonWaitForIdle(radeon);
526 }
527 }