1 /**************************************************************************
3 Copyright (C) The Weather Channel, Inc. 2002. All Rights Reserved.
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.
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:
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.
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.
29 **************************************************************************/
33 * Keith Whitwell <keith@tungstengraphics.com>
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"
45 #include "swrast/swrast.h"
48 #include "tnl/t_pipeline.h"
49 #include "swrast_setup/swrast_setup.h"
51 #include "drirenderbuffer.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"
63 /* =============================================================
67 static GLboolean
intersect_rect(drm_clip_rect_t
* out
,
68 drm_clip_rect_t
* a
, drm_clip_rect_t
* b
)
79 if (out
->x1
>= out
->x2
)
81 if (out
->y1
>= out
->y2
)
86 void radeonRecalcScissorRects(radeonContextPtr radeon
)
91 /* Grow cliprect store?
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;
100 if (radeon
->state
.scissor
.pClipRects
)
101 FREE(radeon
->state
.scissor
.pClipRects
);
103 radeon
->state
.scissor
.pClipRects
=
104 MALLOC(radeon
->state
.scissor
.numAllocedClipRects
*
105 sizeof(drm_clip_rect_t
));
107 if (radeon
->state
.scissor
.pClipRects
== NULL
) {
108 radeon
->state
.scissor
.numAllocedClipRects
= 0;
113 out
= radeon
->state
.scissor
.pClipRects
;
114 radeon
->state
.scissor
.numClipRects
= 0;
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
++;
127 * Update cliprects and scissors.
129 void radeonSetCliprects(radeonContextPtr radeon
)
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
;
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
;
144 radeon
->numClipRects
= drawable
->numBackClipRects
;
145 radeon
->pClipRects
= drawable
->pBackClipRects
;
148 /* front buffer (or none, or multiple buffers */
149 radeon
->numClipRects
= drawable
->numClipRects
;
150 radeon
->pClipRects
= drawable
->pClipRects
;
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
;
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
;
170 if (radeon
->state
.scissor
.enabled
)
171 radeonRecalcScissorRects(radeon
);
173 radeon
->lastStamp
= drawable
->lastStamp
;
176 void radeonUpdateScissor( GLcontext
*ctx
)
178 radeonContextPtr rmesa
= RADEON_CONTEXT(ctx
);
180 if ( rmesa
->dri
.drawable
) {
181 __DRIdrawablePrivate
*dPriv
= rmesa
->dri
.drawable
;
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;
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;
193 radeonRecalcScissorRects( rmesa
);
197 /* ================================================================
198 * SwapBuffers with client-side throttling
201 static uint32_t radeonGetLastFrame(radeonContextPtr radeon
)
203 drm_radeon_getparam_t gp
;
207 gp
.param
= RADEON_PARAM_LAST_FRAME
;
208 gp
.value
= (int *)&frame
;
209 ret
= drmCommandWriteRead(radeon
->dri
.fd
, DRM_RADEON_GETPARAM
,
212 fprintf(stderr
, "%s: drmRadeonGetParam: %d\n", __FUNCTION__
,
220 uint32_t radeonGetAge(radeonContextPtr radeon
)
222 drm_radeon_getparam_t gp
;
226 gp
.param
= RADEON_PARAM_LAST_CLEAR
;
227 gp
.value
= (int *)&age
;
228 ret
= drmCommandWriteRead(radeon
->dri
.fd
, DRM_RADEON_GETPARAM
,
231 fprintf(stderr
, "%s: drmRadeonGetParam: %d\n", __FUNCTION__
,
239 static void radeonEmitIrqLocked(radeonContextPtr radeon
)
241 drm_radeon_irq_emit_t ie
;
244 ie
.irq_seq
= &radeon
->iw
.irq_seq
;
245 ret
= drmCommandWriteRead(radeon
->dri
.fd
, DRM_RADEON_IRQ_EMIT
,
248 fprintf(stderr
, "%s: drmRadeonIrqEmit: %d\n", __FUNCTION__
,
254 static void radeonWaitIrq(radeonContextPtr radeon
)
259 ret
= drmCommandWrite(radeon
->dri
.fd
, DRM_RADEON_IRQ_WAIT
,
260 &radeon
->iw
, sizeof(radeon
->iw
));
261 } while (ret
&& (errno
== EINTR
|| errno
== EBUSY
));
264 fprintf(stderr
, "%s: drmRadeonIrqWait: %d\n", __FUNCTION__
,
270 static void radeonWaitForFrameCompletion(radeonContextPtr radeon
)
272 drm_radeon_sarea_t
*sarea
= radeon
->sarea
;
274 if (radeon
->do_irqs
) {
275 if (radeonGetLastFrame(radeon
) < sarea
->last_frame
) {
276 if (!radeon
->irqsEmitted
) {
277 while (radeonGetLastFrame(radeon
) <
280 UNLOCK_HARDWARE(radeon
);
281 radeonWaitIrq(radeon
);
282 LOCK_HARDWARE(radeon
);
284 radeon
->irqsEmitted
= 10;
287 if (radeon
->irqsEmitted
) {
288 radeonEmitIrqLocked(radeon
);
289 radeon
->irqsEmitted
--;
292 while (radeonGetLastFrame(radeon
) < sarea
->last_frame
) {
293 UNLOCK_HARDWARE(radeon
);
294 if (radeon
->do_usleeps
)
296 LOCK_HARDWARE(radeon
);
302 void radeonWaitForIdleLocked(radeonContextPtr radeon
)
308 ret
= drmCommandNone(radeon
->dri
.fd
, DRM_RADEON_CP_IDLE
);
311 } while (ret
&& ++i
< 100);
314 UNLOCK_HARDWARE(radeon
);
315 fprintf(stderr
, "Error: R300 timed out... exiting\n");
320 static void radeonWaitForIdle(radeonContextPtr radeon
)
322 LOCK_HARDWARE(radeon
);
323 radeonWaitForIdleLocked(radeon
);
324 UNLOCK_HARDWARE(radeon
);
328 /* Copy the back color buffer to the front color buffer.
330 void radeonCopyBuffer( __DRIdrawablePrivate
*dPriv
,
331 const drm_clip_rect_t
*rect
)
334 radeonContextPtr rmesa
;
336 GLboolean missed_target
;
338 __DRIscreenPrivate
*psp
;
341 assert(dPriv
->driContextPriv
);
342 assert(dPriv
->driContextPriv
->driverPrivate
);
344 ctx
= (GLcontext
*) dPriv
->driContextPriv
->driverPrivate
;
345 rmesa
= (radeonContextPtr
) dPriv
->driContextPriv
->driverPrivate
;
347 /// if ( RADEON_DEBUG & DEBUG_IOCTL ) {
348 // fprintf( stderr, "\n%s( %p )\n\n", __FUNCTION__, (void *) rmesa->glCtx );
351 rmesa
->vtbl
.flush(ctx
);
352 LOCK_HARDWARE( rmesa
);
354 /* Throttle the frame rate -- only allow one pending swap buffers
357 radeonWaitForFrameCompletion( rmesa
);
360 UNLOCK_HARDWARE( rmesa
);
361 driWaitForVBlank( dPriv
, & missed_target
);
362 LOCK_HARDWARE( rmesa
);
365 nbox
= dPriv
->numClipRects
; /* must be in locked region */
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
;
373 for ( ; i
< nr
; i
++ ) {
379 if (rect
->x1
> b
->x1
)
381 if (rect
->y1
> b
->y1
)
383 if (rect
->x2
< b
->x2
)
385 if (rect
->y2
< b
->y2
)
388 if (b
->x1
>= b
->x2
|| b
->y1
>= b
->y2
)
395 rmesa
->sarea
->nbox
= n
;
400 ret
= drmCommandNone( rmesa
->dri
.fd
, DRM_RADEON_SWAP
);
403 fprintf( stderr
, "DRM_RADEON_SWAP_BUFFERS: return = %d\n", ret
);
404 UNLOCK_HARDWARE( rmesa
);
409 UNLOCK_HARDWARE( rmesa
);
412 psp
= dPriv
->driScreenPriv
;
414 (*psp
->systemTime
->getUST
)( & ust
);
415 if ( missed_target
) {
416 rmesa
->swap_missed_count
++;
417 rmesa
->swap_missed_ust
= ust
- rmesa
->swap_ust
;
420 rmesa
->swap_ust
= ust
;
421 rmesa
->vtbl
.set_all_dirty(ctx
);
426 void radeonPageFlip( __DRIdrawablePrivate
*dPriv
)
428 radeonContextPtr rmesa
;
430 GLboolean missed_target
;
431 __DRIscreenPrivate
*psp
;
432 struct radeon_renderbuffer
*rrb
;
433 GLframebuffer
*fb
= dPriv
->driverPrivate
;
436 assert(dPriv
->driContextPriv
);
437 assert(dPriv
->driContextPriv
->driverPrivate
);
439 rmesa
= (radeonContextPtr
) dPriv
->driContextPriv
->driverPrivate
;
440 rrb
= (void *)fb
->Attachment
[BUFFER_FRONT_LEFT
].Renderbuffer
;
442 psp
= dPriv
->driScreenPriv
;
445 if ( RADEON_DEBUG
& DEBUG_IOCTL
) {
446 fprintf(stderr
, "%s: pfCurrentPage: %d\n", __FUNCTION__
,
447 rmesa
->sarea
->pfCurrentPage
);
451 rmesa
->vtbl
.flush(rmesa
->glCtx
);
453 LOCK_HARDWARE( rmesa
);
455 if (!dPriv
->numClipRects
) {
456 UNLOCK_HARDWARE(rmesa
);
457 usleep(10000); /* throttle invisible client 10ms */
461 drm_clip_rect_t
*box
= dPriv
->pClipRects
;
462 drm_clip_rect_t
*b
= rmesa
->sarea
->boxes
;
464 rmesa
->sarea
->nbox
= 1;
466 /* Throttle the frame rate -- only allow a few pending swap buffers
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
);
476 LOCK_HARDWARE( rmesa
);
478 ret
= drmCommandNone( rmesa
->dri
.fd
, DRM_RADEON_FLIP
);
480 UNLOCK_HARDWARE( rmesa
);
483 fprintf( stderr
, "DRM_RADEON_FLIP: return = %d\n", ret
);
488 (void) (*psp
->systemTime
->getUST
)( & rmesa
->swap_ust
);
490 /* Get ready for drawing next frame. Update the renderbuffers'
491 * flippedOffset/Pitch fields so we draw into the right place.
493 driFlipRenderbuffers(rmesa
->glCtx
->WinSysDrawBuffer
,
494 rmesa
->sarea
->pfCurrentPage
);
496 rmesa
->state
.color
.rrb
= rrb
;
498 if (rmesa
->vtbl
.update_draw_buffer
)
499 rmesa
->vtbl
.update_draw_buffer(rmesa
->glCtx
);
503 /* Make sure all commands have been sent to the hardware and have
504 * completed processing.
506 void radeon_common_finish(GLcontext
* ctx
)
508 radeonContextPtr radeon
= RADEON_CONTEXT(ctx
);
509 struct gl_framebuffer
*fb
= ctx
->DrawBuffer
;
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
];
517 radeon_bo_wait(rrb
->bo
);
519 } else if (radeon
->do_irqs
) {
520 LOCK_HARDWARE(radeon
);
521 radeonEmitIrqLocked(radeon
);
522 UNLOCK_HARDWARE(radeon
);
523 radeonWaitIrq(radeon
);
525 radeonWaitForIdle(radeon
);