1 /**************************************************************************
3 * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas.
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sub license, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial portions
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21 * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
22 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26 **************************************************************************/
28 #include "intel_screen.h"
29 #include "intel_context.h"
30 #include "intel_blit.h"
31 #include "intel_buffers.h"
32 #include "intel_batchbuffer.h"
33 #include "intel_reg.h"
36 #include "drirenderbuffer.h"
39 #include "pipe/p_context.h"
42 /* This block can be removed when libdrm >= 2.3.1 is required */
44 #ifndef DRM_VBLANK_FLIP
46 #define DRM_VBLANK_FLIP 0x8000000
48 typedef struct drm_i915_flip
{
52 #undef DRM_IOCTL_I915_FLIP
53 #define DRM_IOCTL_I915_FLIP DRM_IOW(DRM_COMMAND_BASE + DRM_I915_FLIP, \
60 * XXX move this into a new dri/common/cliprects.c file.
63 intel_intersect_cliprects(drm_clip_rect_t
* dst
,
64 const drm_clip_rect_t
* a
,
65 const drm_clip_rect_t
* b
)
69 GLint bw
= b
->x2
- bx
;
70 GLint bh
= b
->y2
- by
;
73 bw
-= a
->x1
- bx
, bx
= a
->x1
;
75 bh
-= a
->y1
- by
, by
= a
->y1
;
95 * This will be called whenever the currently bound window is moved/resized.
96 * XXX: actually, it seems to NOT be called when the window is only moved (BP).
99 intelWindowMoved(struct intel_context
*intel
)
101 GLcontext
*ctx
= &intel
->ctx
;
102 __DRIdrawablePrivate
*dPriv
= intel
->driDrawable
;
103 struct intel_framebuffer
*intel_fb
= dPriv
->driverPrivate
;
105 if (!intel
->ctx
.DrawBuffer
) {
106 /* when would this happen? -BP */
108 intel
->numClipRects
= 0;
111 /* Update Mesa's notion of window size */
112 driUpdateFramebufferSize(ctx
, dPriv
);
113 intel_fb
->Base
.Initialized
= GL_TRUE
; /* XXX remove someday */
116 drmI830Sarea
*sarea
= intel
->sarea
;
117 drm_clip_rect_t drw_rect
= { .x1
= dPriv
->x
, .x2
= dPriv
->x
+ dPriv
->w
,
118 .y1
= dPriv
->y
, .y2
= dPriv
->y
+ dPriv
->h
};
119 drm_clip_rect_t pipeA_rect
= { .x1
= sarea
->pipeA_x
, .y1
= sarea
->pipeA_y
,
120 .x2
= sarea
->pipeA_x
+ sarea
->pipeA_w
,
121 .y2
= sarea
->pipeA_y
+ sarea
->pipeA_h
};
122 drm_clip_rect_t pipeB_rect
= { .x1
= sarea
->pipeB_x
, .y1
= sarea
->pipeB_y
,
123 .x2
= sarea
->pipeB_x
+ sarea
->pipeB_w
,
124 .y2
= sarea
->pipeB_y
+ sarea
->pipeB_h
};
125 GLint areaA
= driIntersectArea( drw_rect
, pipeA_rect
);
126 GLint areaB
= driIntersectArea( drw_rect
, pipeB_rect
);
127 GLuint flags
= intel_fb
->vblank_flags
;
131 /* Update page flipping info
141 intel_fb
->pf_current_page
= (intel
->sarea
->pf_current_page
>>
142 (intel_fb
->pf_pipes
& 0x2)) & 0x3;
144 intel_fb
->pf_num_pages
= 2 /*intel->intelScreen->third.handle ? 3 : 2*/;
146 pf_active
= pf_pipes
&& (pf_pipes
& intel
->sarea
->pf_active
) == pf_pipes
;
148 if (INTEL_DEBUG
& DEBUG_LOCK
)
149 if (pf_active
!= intel_fb
->pf_active
)
150 _mesa_printf("%s - Page flipping %sactive\n", __progname
,
151 pf_active
? "" : "in");
154 /* Sync pages between pipes if we're flipping on both at the same time */
155 if (pf_pipes
== 0x3 && pf_pipes
!= intel_fb
->pf_pipes
&&
156 (intel
->sarea
->pf_current_page
& 0x3) !=
157 (((intel
->sarea
->pf_current_page
) >> 2) & 0x3)) {
158 drm_i915_flip_t flip
;
160 if (intel_fb
->pf_current_page
==
161 (intel
->sarea
->pf_current_page
& 0x3)) {
162 /* XXX: This is ugly, but emitting two flips 'in a row' can cause
163 * lockups for unknown reasons.
165 intel
->sarea
->pf_current_page
=
166 intel
->sarea
->pf_current_page
& 0x3;
167 intel
->sarea
->pf_current_page
|=
168 ((intel_fb
->pf_current_page
+ intel_fb
->pf_num_pages
- 1) %
169 intel_fb
->pf_num_pages
) << 2;
173 intel
->sarea
->pf_current_page
=
174 intel
->sarea
->pf_current_page
& (0x3 << 2);
175 intel
->sarea
->pf_current_page
|=
176 (intel_fb
->pf_current_page
+ intel_fb
->pf_num_pages
- 1) %
177 intel_fb
->pf_num_pages
;
182 drmCommandWrite(intel
->driFd
, DRM_I915_FLIP
, &flip
, sizeof(flip
));
185 intel_fb
->pf_pipes
= pf_pipes
;
188 intel_fb
->pf_active
= pf_active
;
190 intel_flip_renderbuffers(intel_fb
);
191 intel_draw_buffer(&intel
->ctx
, intel
->ctx
.DrawBuffer
);
194 /* Update vblank info
196 if (areaB
> areaA
|| (areaA
== areaB
&& areaB
> 0)) {
197 flags
= intel_fb
->vblank_flags
| VBLANK_FLAG_SECONDARY
;
199 flags
= intel_fb
->vblank_flags
& ~VBLANK_FLAG_SECONDARY
;
202 if (flags
!= intel_fb
->vblank_flags
&& intel_fb
->vblank_flags
&&
203 !(intel_fb
->vblank_flags
& VBLANK_FLAG_NO_IRQ
)) {
207 vbl
.request
.type
= DRM_VBLANK_ABSOLUTE
;
209 if ( intel_fb
->vblank_flags
& VBLANK_FLAG_SECONDARY
) {
210 vbl
.request
.type
|= DRM_VBLANK_SECONDARY
;
213 for (i
= 0; i
< intel_fb
->pf_num_pages
; i
++) {
214 if ((intel_fb
->vbl_waited
- intel_fb
->vbl_pending
[i
]) <= (1<<23))
217 vbl
.request
.sequence
= intel_fb
->vbl_pending
[i
];
218 drmWaitVBlank(intel
->driFd
, &vbl
);
221 intel_fb
->vblank_flags
= flags
;
222 driGetCurrentVBlank(dPriv
, intel_fb
->vblank_flags
, &intel_fb
->vbl_seq
);
223 intel_fb
->vbl_waited
= intel_fb
->vbl_seq
;
225 for (i
= 0; i
< intel_fb
->pf_num_pages
; i
++) {
226 intel_fb
->vbl_pending
[i
] = intel_fb
->vbl_waited
;
231 /* This will be picked up by looking at the dirty state flags:
234 /* Update hardware scissor */
235 // ctx->Driver.Scissor(ctx, ctx->Scissor.X, ctx->Scissor.Y,
236 // ctx->Scissor.Width, ctx->Scissor.Height);
238 /* Re-calculate viewport related state */
239 // ctx->Driver.DepthRange( ctx, ctx->Viewport.Near, ctx->Viewport.Far );
246 /* Emit wait for pending flips */
249 intel_wait_flips(struct intel_context
*intel
, GLuint batch_flags
)
251 struct intel_framebuffer
*intel_fb
=
252 (struct intel_framebuffer
*) intel
->ctx
.DrawBuffer
;
253 struct intel_renderbuffer
*intel_rb
=
254 intel_get_renderbuffer(&intel_fb
->Base
,
255 intel_fb
->Base
._ColorDrawBufferMask
[0] ==
256 BUFFER_BIT_FRONT_LEFT
? BUFFER_FRONT_LEFT
:
259 if (intel_fb
->Base
.Name
== 0 && intel_rb
->pf_pending
== intel_fb
->pf_seq
) {
260 GLint pf_pipes
= intel_fb
->pf_pipes
;
263 /* Wait for pending flips to take effect */
264 BEGIN_BATCH(2, batch_flags
);
265 OUT_BATCH(pf_pipes
& 0x1 ? (MI_WAIT_FOR_EVENT
| MI_WAIT_FOR_PLANE_A_FLIP
)
267 OUT_BATCH(pf_pipes
& 0x2 ? (MI_WAIT_FOR_EVENT
| MI_WAIT_FOR_PLANE_B_FLIP
)
271 intel_rb
->pf_pending
--;
277 /* Flip the front & back buffers
280 intelPageFlip(const __DRIdrawablePrivate
* dPriv
)
282 struct intel_context
*intel
;
284 struct intel_framebuffer
*intel_fb
= dPriv
->driverPrivate
;
286 if (INTEL_DEBUG
& DEBUG_IOCTL
)
287 fprintf(stderr
, "%s\n", __FUNCTION__
);
290 assert(dPriv
->driContextPriv
);
291 assert(dPriv
->driContextPriv
->driverPrivate
);
293 intel
= (struct intel_context
*) dPriv
->driContextPriv
->driverPrivate
;
295 if (intel
->intelScreen
->drmMinor
< 9)
298 intelFlush(&intel
->ctx
);
302 LOCK_HARDWARE(intel
);
304 if (dPriv
->numClipRects
&& intel_fb
->pf_active
) {
305 drm_i915_flip_t flip
;
307 flip
.pipes
= intel_fb
->pf_pipes
;
309 ret
= drmCommandWrite(intel
->driFd
, DRM_I915_FLIP
, &flip
, sizeof(flip
));
312 UNLOCK_HARDWARE(intel
);
314 if (ret
|| !intel_fb
->pf_active
)
317 if (!dPriv
->numClipRects
) {
318 usleep(10000); /* throttle invisible client 10ms */
321 intel_fb
->pf_current_page
= (intel
->sarea
->pf_current_page
>>
322 (intel_fb
->pf_pipes
& 0x2)) & 0x3;
324 if (dPriv
->numClipRects
!= 0) {
325 intel_get_renderbuffer(&intel_fb
->Base
, BUFFER_FRONT_LEFT
)->pf_pending
=
326 intel_get_renderbuffer(&intel_fb
->Base
, BUFFER_BACK_LEFT
)->pf_pending
=
331 intel_flip_renderbuffers(intel_fb
);
332 intel_draw_buffer(&intel
->ctx
, &intel_fb
->Base
);
335 if (INTEL_DEBUG
& DEBUG_IOCTL
)
336 fprintf(stderr
, "%s: success\n", __FUNCTION__
);
344 intelScheduleSwap(const __DRIdrawablePrivate
* dPriv
, GLboolean
*missed_target
)
346 struct intel_framebuffer
*intel_fb
= dPriv
->driverPrivate
;
347 unsigned int interval
= driGetVBlankInterval(dPriv
, intel_fb
->vblank_flags
);
348 struct intel_context
*intel
=
349 intelScreenContext(dPriv
->driScreenPriv
->private);
350 const intelScreenPrivate
*intelScreen
= intel
->intelScreen
;
352 drm_i915_vblank_swap_t swap
;
355 if (!intel_fb
->vblank_flags
||
356 (intel_fb
->vblank_flags
& VBLANK_FLAG_NO_IRQ
) ||
357 intelScreen
->drmMinor
< (intel_fb
->pf_active
? 9 : 6))
360 swap
.seqtype
= DRM_VBLANK_ABSOLUTE
;
362 if (intel_fb
->vblank_flags
& VBLANK_FLAG_SYNC
) {
363 swap
.seqtype
|= DRM_VBLANK_NEXTONMISS
;
364 } else if (interval
== 0) {
368 swap
.drawable
= dPriv
->hHWDrawable
;
369 target
= swap
.sequence
= intel_fb
->vbl_seq
+ interval
;
371 if ( intel_fb
->vblank_flags
& VBLANK_FLAG_SECONDARY
) {
372 swap
.seqtype
|= DRM_VBLANK_SECONDARY
;
375 LOCK_HARDWARE(intel
);
377 intel_batchbuffer_flush(intel
->batch
);
379 if ( intel_fb
->pf_active
) {
380 swap
.seqtype
|= DRM_VBLANK_FLIP
;
382 intel_fb
->pf_current_page
= (((intel
->sarea
->pf_current_page
>>
383 (intel_fb
->pf_pipes
& 0x2)) & 0x3) + 1) %
384 intel_fb
->pf_num_pages
;
387 if (!drmCommandWriteRead(intel
->driFd
, DRM_I915_VBLANK_SWAP
, &swap
,
389 intel_fb
->vbl_seq
= swap
.sequence
;
390 swap
.sequence
-= target
;
391 *missed_target
= swap
.sequence
> 0 && swap
.sequence
<= (1 << 23);
394 intel_fb
->vbl_pending
[1] = intel_fb
->vbl_pending
[0] = intel_fb
->vbl_seq
;
396 intel_get_renderbuffer(&intel_fb
->Base
, BUFFER_BACK_LEFT
)->vbl_pending
=
397 intel_get_renderbuffer(&intel_fb
->Base
,
398 BUFFER_FRONT_LEFT
)->vbl_pending
=
402 if (swap
.seqtype
& DRM_VBLANK_FLIP
) {
404 intel_flip_renderbuffers(intel_fb
);
405 intel_draw_buffer(&intel
->ctx
, intel
->ctx
.DrawBuffer
);
411 if (swap
.seqtype
& DRM_VBLANK_FLIP
) {
412 intel_fb
->pf_current_page
= ((intel
->sarea
->pf_current_page
>>
413 (intel_fb
->pf_pipes
& 0x2)) & 0x3) %
414 intel_fb
->pf_num_pages
;
420 UNLOCK_HARDWARE(intel
);
426 intelSwapBuffers(__DRIdrawablePrivate
* dPriv
)
428 if (dPriv
->driContextPriv
&& dPriv
->driContextPriv
->driverPrivate
) {
429 GET_CURRENT_CONTEXT(ctx
);
430 struct intel_context
*intel
;
435 intel
= intel_context(ctx
);
437 if (ctx
->Visual
.doubleBufferMode
) {
438 GLboolean missed_target
;
439 struct intel_framebuffer
*intel_fb
= dPriv
->driverPrivate
;
442 _mesa_notifySwapBuffers(ctx
); /* flush pending rendering comands */
444 if (!intelScheduleSwap(dPriv
, &missed_target
)) {
445 driWaitForVBlank(dPriv
, &intel_fb
->vbl_seq
, intel_fb
->vblank_flags
,
448 intelCopyBuffer(dPriv
, NULL
);
451 intel_fb
->swap_count
++;
452 (*dri_interface
->getUST
) (&ust
);
454 intel_fb
->swap_missed_count
++;
455 intel_fb
->swap_missed_ust
= ust
- intel_fb
->swap_ust
;
458 intel_fb
->swap_ust
= ust
;
462 /* XXX this shouldn't be an error but we can't handle it for now */
463 fprintf(stderr
, "%s: drawable has no context!\n", __FUNCTION__
);
468 intelCopySubBuffer(__DRIdrawablePrivate
* dPriv
, int x
, int y
, int w
, int h
)
470 if (dPriv
->driContextPriv
&& dPriv
->driContextPriv
->driverPrivate
) {
471 struct intel_context
*intel
=
472 (struct intel_context
*) dPriv
->driContextPriv
->driverPrivate
;
473 GLcontext
*ctx
= &intel
->ctx
;
475 if (ctx
->Visual
.doubleBufferMode
) {
476 drm_clip_rect_t rect
;
477 /* fixup cliprect (driDrawable may have changed?) later */
482 _mesa_notifySwapBuffers(ctx
); /* flush pending rendering comands */
483 intelCopyBuffer(dPriv
, &rect
);
487 /* XXX this shouldn't be an error but we can't handle it for now */
488 fprintf(stderr
, "%s: drawable has no context!\n", __FUNCTION__
);