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_blit.h"
29 #include "intel_buffers.h"
30 #include "intel_swapbuffers.h"
31 #include "intel_fbo.h"
32 #include "intel_batchbuffer.h"
33 #include "drirenderbuffer.h"
40 * Correct a drawablePrivate's set of vblank flags WRT the current context.
41 * When considering multiple crtcs.
44 intelFixupVblank(struct intel_context
*intel
, __DRIdrawablePrivate
*dPriv
)
46 if (!intel
->intelScreen
->driScrnPriv
->dri2
.enabled
&&
47 intel
->intelScreen
->driScrnPriv
->ddx_version
.minor
>= 7) {
48 volatile drm_i915_sarea_t
*sarea
= intel
->sarea
;
49 drm_clip_rect_t drw_rect
= { .x1
= dPriv
->x
, .x2
= dPriv
->x
+ dPriv
->w
,
50 .y1
= dPriv
->y
, .y2
= dPriv
->y
+ dPriv
->h
};
51 drm_clip_rect_t planeA_rect
= { .x1
= sarea
->planeA_x
, .y1
= sarea
->planeA_y
,
52 .x2
= sarea
->planeA_x
+ sarea
->planeA_w
,
53 .y2
= sarea
->planeA_y
+ sarea
->planeA_h
};
54 drm_clip_rect_t planeB_rect
= { .x1
= sarea
->planeB_x
, .y1
= sarea
->planeB_y
,
55 .x2
= sarea
->planeB_x
+ sarea
->planeB_w
,
56 .y2
= sarea
->planeB_y
+ sarea
->planeB_h
};
57 GLint areaA
= driIntersectArea( drw_rect
, planeA_rect
);
58 GLint areaB
= driIntersectArea( drw_rect
, planeB_rect
);
59 GLuint flags
= dPriv
->vblFlags
;
63 if (areaB
> areaA
|| (areaA
== areaB
&& areaB
> 0)) {
64 flags
= dPriv
->vblFlags
| VBLANK_FLAG_SECONDARY
;
66 flags
= dPriv
->vblFlags
& ~VBLANK_FLAG_SECONDARY
;
69 /* Do the stupid test: Is one of them actually disabled?
71 if (sarea
->planeA_w
== 0 || sarea
->planeA_h
== 0) {
72 flags
= dPriv
->vblFlags
| VBLANK_FLAG_SECONDARY
;
73 } else if (sarea
->planeB_w
== 0 || sarea
->planeB_h
== 0) {
74 flags
= dPriv
->vblFlags
& ~VBLANK_FLAG_SECONDARY
;
79 return dPriv
->vblFlags
& ~VBLANK_FLAG_SECONDARY
;
85 * Called from driSwapBuffers()
88 intelSwapBuffers(__DRIdrawablePrivate
* dPriv
)
90 __DRIscreenPrivate
*psp
= dPriv
->driScreenPriv
;
92 if (dPriv
->driContextPriv
&& dPriv
->driContextPriv
->driverPrivate
) {
93 GET_CURRENT_CONTEXT(ctx
);
94 struct intel_context
*intel
;
99 intel
= intel_context(ctx
);
101 if (ctx
->Visual
.doubleBufferMode
) {
102 GLboolean missed_target
;
103 struct intel_framebuffer
*intel_fb
= dPriv
->driverPrivate
;
106 _mesa_notifySwapBuffers(ctx
); /* flush pending rendering comands */
109 * The old swapping ioctl was incredibly racy, just wait for vblank
110 * and do the swap ourselves.
112 driWaitForVBlank(dPriv
, &missed_target
);
115 * Update each buffer's vbl_pending so we don't get too out of
118 intel_get_renderbuffer(&intel_fb
->Base
,
119 BUFFER_BACK_LEFT
)->vbl_pending
= dPriv
->vblSeq
;
120 intel_get_renderbuffer(&intel_fb
->Base
,
121 BUFFER_FRONT_LEFT
)->vbl_pending
= dPriv
->vblSeq
;
123 intelCopyBuffer(dPriv
, NULL
);
125 intel_fb
->swap_count
++;
126 (*psp
->systemTime
->getUST
) (&ust
);
128 intel_fb
->swap_missed_count
++;
129 intel_fb
->swap_missed_ust
= ust
- intel_fb
->swap_ust
;
132 intel_fb
->swap_ust
= ust
;
134 drmCommandNone(intel
->driFd
, DRM_I915_GEM_THROTTLE
);
137 /* XXX this shouldn't be an error but we can't handle it for now */
138 fprintf(stderr
, "%s: drawable has no context!\n", __FUNCTION__
);
144 * Called from driCopySubBuffer()
147 intelCopySubBuffer(__DRIdrawablePrivate
* dPriv
, int x
, int y
, int w
, int h
)
149 if (dPriv
->driContextPriv
&& dPriv
->driContextPriv
->driverPrivate
) {
150 struct intel_context
*intel
=
151 (struct intel_context
*) dPriv
->driContextPriv
->driverPrivate
;
152 GLcontext
*ctx
= &intel
->ctx
;
154 if (ctx
->Visual
.doubleBufferMode
) {
155 drm_clip_rect_t rect
;
156 rect
.x1
= x
+ dPriv
->x
;
157 rect
.y1
= (dPriv
->h
- y
- h
) + dPriv
->y
;
158 rect
.x2
= rect
.x1
+ w
;
159 rect
.y2
= rect
.y1
+ h
;
160 _mesa_notifySwapBuffers(ctx
); /* flush pending rendering comands */
161 intelCopyBuffer(dPriv
, &rect
);
165 /* XXX this shouldn't be an error but we can't handle it for now */
166 fprintf(stderr
, "%s: drawable has no context!\n", __FUNCTION__
);
172 * This will be called whenever the currently bound window is moved/resized.
173 * XXX: actually, it seems to NOT be called when the window is only moved (BP).
176 intelWindowMoved(struct intel_context
*intel
)
178 GLcontext
*ctx
= &intel
->ctx
;
179 __DRIdrawablePrivate
*dPriv
= intel
->driDrawable
;
180 struct intel_framebuffer
*intel_fb
= dPriv
->driverPrivate
;
182 if (!intel
->intelScreen
->driScrnPriv
->dri2
.enabled
&&
183 intel
->intelScreen
->driScrnPriv
->ddx_version
.minor
>= 7) {
184 GLuint flags
= intelFixupVblank(intel
, dPriv
);
186 /* Check to see if we changed pipes */
187 if (flags
!= dPriv
->vblFlags
&& dPriv
->vblFlags
&&
188 !(dPriv
->vblFlags
& VBLANK_FLAG_NO_IRQ
)) {
194 * Deal with page flipping
196 vbl
.request
.type
= DRM_VBLANK_ABSOLUTE
;
198 if ( dPriv
->vblFlags
& VBLANK_FLAG_SECONDARY
) {
199 vbl
.request
.type
|= DRM_VBLANK_SECONDARY
;
202 for (i
= 0; i
< 2; i
++) {
203 if (!intel_fb
->color_rb
[i
] ||
204 (intel_fb
->vbl_waited
- intel_fb
->color_rb
[i
]->vbl_pending
) <=
208 vbl
.request
.sequence
= intel_fb
->color_rb
[i
]->vbl_pending
;
209 drmWaitVBlank(intel
->driFd
, &vbl
);
213 * Update msc_base from old pipe
215 driDrawableGetMSC32(dPriv
->driScreenPriv
, dPriv
, &count
);
216 dPriv
->msc_base
= count
;
218 * Then get new vblank_base and vblSeq values
220 dPriv
->vblFlags
= flags
;
221 driGetCurrentVBlank(dPriv
);
222 dPriv
->vblank_base
= dPriv
->vblSeq
;
224 intel_fb
->vbl_waited
= dPriv
->vblSeq
;
226 for (i
= 0; i
< 2; i
++) {
227 if (intel_fb
->color_rb
[i
])
228 intel_fb
->color_rb
[i
]->vbl_pending
= intel_fb
->vbl_waited
;
232 dPriv
->vblFlags
&= ~VBLANK_FLAG_SECONDARY
;
235 /* Update Mesa's notion of window size */
236 driUpdateFramebufferSize(ctx
, dPriv
);
237 intel_fb
->Base
.Initialized
= GL_TRUE
; /* XXX remove someday */
239 /* Update hardware scissor */
240 if (ctx
->Driver
.Scissor
!= NULL
) {
241 ctx
->Driver
.Scissor(ctx
, ctx
->Scissor
.X
, ctx
->Scissor
.Y
,
242 ctx
->Scissor
.Width
, ctx
->Scissor
.Height
);
245 /* Re-calculate viewport related state */
246 if (ctx
->Driver
.DepthRange
!= NULL
)
247 ctx
->Driver
.DepthRange( ctx
, ctx
->Viewport
.Near
, ctx
->Viewport
.Far
);