Merge branch 'mesa_7_6_branch' into mesa_7_7_branch
[mesa.git] / src / mesa / drivers / dri / intel / intel_swapbuffers.c
1 /**************************************************************************
2 *
3 * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas.
4 * All Rights Reserved.
5 *
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:
13 *
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial portions
16 * of the Software.
17 *
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.
25 *
26 **************************************************************************/
27
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"
34 #include "vblank.h"
35 #include "i915_drm.h"
36
37
38
39 /*
40 * Correct a drawablePrivate's set of vblank flags WRT the current context.
41 * When considering multiple crtcs.
42 */
43 GLuint
44 intelFixupVblank(struct intel_context *intel, __DRIdrawablePrivate *dPriv)
45 {
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;
60
61 /* Update vblank info
62 */
63 if (areaB > areaA || (areaA == areaB && areaB > 0)) {
64 flags = dPriv->vblFlags | VBLANK_FLAG_SECONDARY;
65 } else {
66 flags = dPriv->vblFlags & ~VBLANK_FLAG_SECONDARY;
67 }
68
69 /* Do the stupid test: Is one of them actually disabled?
70 */
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;
75 }
76
77 return flags;
78 } else {
79 return dPriv->vblFlags & ~VBLANK_FLAG_SECONDARY;
80 }
81 }
82
83
84 /**
85 * Called from driSwapBuffers()
86 */
87 void
88 intelSwapBuffers(__DRIdrawablePrivate * dPriv)
89 {
90 __DRIscreenPrivate *psp = dPriv->driScreenPriv;
91
92 if (dPriv->driContextPriv && dPriv->driContextPriv->driverPrivate) {
93 GET_CURRENT_CONTEXT(ctx);
94 struct intel_context *intel;
95
96 if (ctx == NULL)
97 return;
98
99 intel = intel_context(ctx);
100
101 if (ctx->Visual.doubleBufferMode) {
102 GLboolean missed_target;
103 struct intel_framebuffer *intel_fb = dPriv->driverPrivate;
104 int64_t ust;
105
106 _mesa_notifySwapBuffers(ctx); /* flush pending rendering comands */
107
108 /*
109 * The old swapping ioctl was incredibly racy, just wait for vblank
110 * and do the swap ourselves.
111 */
112 driWaitForVBlank(dPriv, &missed_target);
113
114 /*
115 * Update each buffer's vbl_pending so we don't get too out of
116 * sync
117 */
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;
122
123 intelCopyBuffer(dPriv, NULL);
124
125 intel_fb->swap_count++;
126 (*psp->systemTime->getUST) (&ust);
127 if (missed_target) {
128 intel_fb->swap_missed_count++;
129 intel_fb->swap_missed_ust = ust - intel_fb->swap_ust;
130 }
131
132 intel_fb->swap_ust = ust;
133 }
134 drmCommandNone(intel->driFd, DRM_I915_GEM_THROTTLE);
135 }
136 else {
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__);
139 }
140 }
141
142
143 /**
144 * Called from driCopySubBuffer()
145 */
146 void
147 intelCopySubBuffer(__DRIdrawablePrivate * dPriv, int x, int y, int w, int h)
148 {
149 if (dPriv->driContextPriv && dPriv->driContextPriv->driverPrivate) {
150 struct intel_context *intel =
151 (struct intel_context *) dPriv->driContextPriv->driverPrivate;
152 GLcontext *ctx = &intel->ctx;
153
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);
162 }
163 }
164 else {
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__);
167 }
168 }
169
170
171 /**
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).
174 */
175 void
176 intelWindowMoved(struct intel_context *intel)
177 {
178 GLcontext *ctx = &intel->ctx;
179 __DRIdrawablePrivate *dPriv = intel->driDrawable;
180 struct intel_framebuffer *intel_fb = dPriv->driverPrivate;
181
182 if (!intel->intelScreen->driScrnPriv->dri2.enabled &&
183 intel->intelScreen->driScrnPriv->ddx_version.minor >= 7) {
184 GLuint flags = intelFixupVblank(intel, dPriv);
185
186 /* Check to see if we changed pipes */
187 if (flags != dPriv->vblFlags && dPriv->vblFlags &&
188 !(dPriv->vblFlags & VBLANK_FLAG_NO_IRQ)) {
189 int64_t count;
190 drmVBlank vbl;
191 int i;
192
193 /*
194 * Deal with page flipping
195 */
196 vbl.request.type = DRM_VBLANK_ABSOLUTE;
197
198 if ( dPriv->vblFlags & VBLANK_FLAG_SECONDARY ) {
199 vbl.request.type |= DRM_VBLANK_SECONDARY;
200 }
201
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) <=
205 (1<<23))
206 continue;
207
208 vbl.request.sequence = intel_fb->color_rb[i]->vbl_pending;
209 drmWaitVBlank(intel->driFd, &vbl);
210 }
211
212 /*
213 * Update msc_base from old pipe
214 */
215 driDrawableGetMSC32(dPriv->driScreenPriv, dPriv, &count);
216 dPriv->msc_base = count;
217 /*
218 * Then get new vblank_base and vblSeq values
219 */
220 dPriv->vblFlags = flags;
221 driGetCurrentVBlank(dPriv);
222 dPriv->vblank_base = dPriv->vblSeq;
223
224 intel_fb->vbl_waited = dPriv->vblSeq;
225
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;
229 }
230 }
231 } else {
232 dPriv->vblFlags &= ~VBLANK_FLAG_SECONDARY;
233 }
234
235 /* Update Mesa's notion of window size */
236 driUpdateFramebufferSize(ctx, dPriv);
237 intel_fb->Base.Initialized = GL_TRUE; /* XXX remove someday */
238
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);
243 }
244
245 /* Re-calculate viewport related state */
246 if (ctx->Driver.DepthRange != NULL)
247 ctx->Driver.DepthRange( ctx, ctx->Viewport.Near, ctx->Viewport.Far );
248 }