| /************************************************************************** |
| * |
| * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. |
| * All Rights Reserved. |
| * |
| * Permission is hereby granted, free of charge, to any person obtaining a |
| * copy of this software and associated documentation files (the |
| * "Software"), to deal in the Software without restriction, including |
| * without limitation the rights to use, copy, modify, merge, publish, |
| * distribute, sub license, and/or sell copies of the Software, and to |
| * permit persons to whom the Software is furnished to do so, subject to |
| * the following conditions: |
| * |
| * The above copyright notice and this permission notice (including the |
| * next paragraph) shall be included in all copies or substantial portions |
| * of the Software. |
| * |
| * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS |
| * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
| * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. |
| * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR |
| * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, |
| * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE |
| * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
| * |
| **************************************************************************/ |
| |
| #include "intel_blit.h" |
| #include "intel_buffers.h" |
| #include "intel_swapbuffers.h" |
| #include "intel_fbo.h" |
| #include "intel_batchbuffer.h" |
| #include "drirenderbuffer.h" |
| #include "vblank.h" |
| #include "i915_drm.h" |
| |
| |
| |
| /* |
| * Correct a drawablePrivate's set of vblank flags WRT the current context. |
| * When considering multiple crtcs. |
| */ |
| GLuint |
| intelFixupVblank(struct intel_context *intel, __DRIdrawablePrivate *dPriv) |
| { |
| if (!intel->intelScreen->driScrnPriv->dri2.enabled && |
| intel->intelScreen->driScrnPriv->ddx_version.minor >= 7) { |
| volatile drm_i915_sarea_t *sarea = intel->sarea; |
| drm_clip_rect_t drw_rect = { .x1 = dPriv->x, .x2 = dPriv->x + dPriv->w, |
| .y1 = dPriv->y, .y2 = dPriv->y + dPriv->h }; |
| drm_clip_rect_t planeA_rect = { .x1 = sarea->planeA_x, .y1 = sarea->planeA_y, |
| .x2 = sarea->planeA_x + sarea->planeA_w, |
| .y2 = sarea->planeA_y + sarea->planeA_h }; |
| drm_clip_rect_t planeB_rect = { .x1 = sarea->planeB_x, .y1 = sarea->planeB_y, |
| .x2 = sarea->planeB_x + sarea->planeB_w, |
| .y2 = sarea->planeB_y + sarea->planeB_h }; |
| GLint areaA = driIntersectArea( drw_rect, planeA_rect ); |
| GLint areaB = driIntersectArea( drw_rect, planeB_rect ); |
| GLuint flags = dPriv->vblFlags; |
| |
| /* Update vblank info |
| */ |
| if (areaB > areaA || (areaA == areaB && areaB > 0)) { |
| flags = dPriv->vblFlags | VBLANK_FLAG_SECONDARY; |
| } else { |
| flags = dPriv->vblFlags & ~VBLANK_FLAG_SECONDARY; |
| } |
| |
| /* Do the stupid test: Is one of them actually disabled? |
| */ |
| if (sarea->planeA_w == 0 || sarea->planeA_h == 0) { |
| flags = dPriv->vblFlags | VBLANK_FLAG_SECONDARY; |
| } else if (sarea->planeB_w == 0 || sarea->planeB_h == 0) { |
| flags = dPriv->vblFlags & ~VBLANK_FLAG_SECONDARY; |
| } |
| |
| return flags; |
| } else { |
| return dPriv->vblFlags & ~VBLANK_FLAG_SECONDARY; |
| } |
| } |
| |
| |
| /** |
| * Called from driSwapBuffers() |
| */ |
| void |
| intelSwapBuffers(__DRIdrawablePrivate * dPriv) |
| { |
| __DRIscreenPrivate *psp = dPriv->driScreenPriv; |
| |
| if (dPriv->driContextPriv && dPriv->driContextPriv->driverPrivate) { |
| GET_CURRENT_CONTEXT(ctx); |
| struct intel_context *intel; |
| |
| if (ctx == NULL) |
| return; |
| |
| intel = intel_context(ctx); |
| |
| if (ctx->Visual.doubleBufferMode) { |
| GLboolean missed_target; |
| struct intel_framebuffer *intel_fb = dPriv->driverPrivate; |
| int64_t ust; |
| |
| _mesa_notifySwapBuffers(ctx); /* flush pending rendering comands */ |
| |
| /* |
| * The old swapping ioctl was incredibly racy, just wait for vblank |
| * and do the swap ourselves. |
| */ |
| driWaitForVBlank(dPriv, &missed_target); |
| |
| /* |
| * Update each buffer's vbl_pending so we don't get too out of |
| * sync |
| */ |
| intel_get_renderbuffer(&intel_fb->Base, |
| BUFFER_BACK_LEFT)->vbl_pending = dPriv->vblSeq; |
| intel_get_renderbuffer(&intel_fb->Base, |
| BUFFER_FRONT_LEFT)->vbl_pending = dPriv->vblSeq; |
| |
| intelCopyBuffer(dPriv, NULL); |
| |
| intel_fb->swap_count++; |
| (*psp->systemTime->getUST) (&ust); |
| if (missed_target) { |
| intel_fb->swap_missed_count++; |
| intel_fb->swap_missed_ust = ust - intel_fb->swap_ust; |
| } |
| |
| intel_fb->swap_ust = ust; |
| } |
| drmCommandNone(intel->driFd, DRM_I915_GEM_THROTTLE); |
| } |
| else { |
| /* XXX this shouldn't be an error but we can't handle it for now */ |
| fprintf(stderr, "%s: drawable has no context!\n", __FUNCTION__); |
| } |
| } |
| |
| |
| /** |
| * Called from driCopySubBuffer() |
| */ |
| void |
| intelCopySubBuffer(__DRIdrawablePrivate * dPriv, int x, int y, int w, int h) |
| { |
| if (dPriv->driContextPriv && dPriv->driContextPriv->driverPrivate) { |
| struct intel_context *intel = |
| (struct intel_context *) dPriv->driContextPriv->driverPrivate; |
| GLcontext *ctx = &intel->ctx; |
| |
| if (ctx->Visual.doubleBufferMode) { |
| drm_clip_rect_t rect; |
| rect.x1 = x + dPriv->x; |
| rect.y1 = (dPriv->h - y - h) + dPriv->y; |
| rect.x2 = rect.x1 + w; |
| rect.y2 = rect.y1 + h; |
| _mesa_notifySwapBuffers(ctx); /* flush pending rendering comands */ |
| intelCopyBuffer(dPriv, &rect); |
| } |
| } |
| else { |
| /* XXX this shouldn't be an error but we can't handle it for now */ |
| fprintf(stderr, "%s: drawable has no context!\n", __FUNCTION__); |
| } |
| } |
| |
| |
| /** |
| * This will be called whenever the currently bound window is moved/resized. |
| * XXX: actually, it seems to NOT be called when the window is only moved (BP). |
| */ |
| void |
| intelWindowMoved(struct intel_context *intel) |
| { |
| GLcontext *ctx = &intel->ctx; |
| __DRIdrawablePrivate *dPriv = intel->driDrawable; |
| struct intel_framebuffer *intel_fb = dPriv->driverPrivate; |
| |
| if (!intel->intelScreen->driScrnPriv->dri2.enabled && |
| intel->intelScreen->driScrnPriv->ddx_version.minor >= 7) { |
| GLuint flags = intelFixupVblank(intel, dPriv); |
| |
| /* Check to see if we changed pipes */ |
| if (flags != dPriv->vblFlags && dPriv->vblFlags && |
| !(dPriv->vblFlags & VBLANK_FLAG_NO_IRQ)) { |
| int64_t count; |
| drmVBlank vbl; |
| int i; |
| |
| /* |
| * Deal with page flipping |
| */ |
| vbl.request.type = DRM_VBLANK_ABSOLUTE; |
| |
| if ( dPriv->vblFlags & VBLANK_FLAG_SECONDARY ) { |
| vbl.request.type |= DRM_VBLANK_SECONDARY; |
| } |
| |
| for (i = 0; i < 2; i++) { |
| if (!intel_fb->color_rb[i] || |
| (intel_fb->vbl_waited - intel_fb->color_rb[i]->vbl_pending) <= |
| (1<<23)) |
| continue; |
| |
| vbl.request.sequence = intel_fb->color_rb[i]->vbl_pending; |
| drmWaitVBlank(intel->driFd, &vbl); |
| } |
| |
| /* |
| * Update msc_base from old pipe |
| */ |
| driDrawableGetMSC32(dPriv->driScreenPriv, dPriv, &count); |
| dPriv->msc_base = count; |
| /* |
| * Then get new vblank_base and vblSeq values |
| */ |
| dPriv->vblFlags = flags; |
| driGetCurrentVBlank(dPriv); |
| dPriv->vblank_base = dPriv->vblSeq; |
| |
| intel_fb->vbl_waited = dPriv->vblSeq; |
| |
| for (i = 0; i < 2; i++) { |
| if (intel_fb->color_rb[i]) |
| intel_fb->color_rb[i]->vbl_pending = intel_fb->vbl_waited; |
| } |
| } |
| } else { |
| dPriv->vblFlags &= ~VBLANK_FLAG_SECONDARY; |
| } |
| |
| /* Update Mesa's notion of window size */ |
| driUpdateFramebufferSize(ctx, dPriv); |
| intel_fb->Base.Initialized = GL_TRUE; /* XXX remove someday */ |
| |
| /* Update hardware scissor */ |
| if (ctx->Driver.Scissor != NULL) { |
| ctx->Driver.Scissor(ctx, ctx->Scissor.X, ctx->Scissor.Y, |
| ctx->Scissor.Width, ctx->Scissor.Height); |
| } |
| |
| /* Re-calculate viewport related state */ |
| if (ctx->Driver.DepthRange != NULL) |
| ctx->Driver.DepthRange( ctx, ctx->Viewport.Near, ctx->Viewport.Far ); |
| } |