void Layer::unlockPageFlip( const Transform& planeTransform, Region& outDirtyRegion) { ATRACE_CALL(); Region postedRegion(mPostedDirtyRegion); if (!postedRegion.isEmpty()) { mPostedDirtyRegion.clear(); if (!visibleRegionScreen.isEmpty()) { // The dirty region is given in the layer's coordinate space // transform the dirty region by the surface's transformation // and the global transformation. const Layer::State& s(drawingState()); const Transform tr(planeTransform * s.transform); postedRegion = tr.transform(postedRegion); // At this point, the dirty region is in screen space. // Make sure it's constrained by the visible region (which // is in screen space as well). postedRegion.andSelf(visibleRegionScreen); outDirtyRegion.orSelf(postedRegion); } } }
void Layer::lockPageFlip(bool& recomputeVisibleRegions) { ATRACE_CALL(); if (mQueuedFrames > 0) { // if we've already called updateTexImage() without going through // a composition step, we have to skip this layer at this point // because we cannot call updateTeximage() without a corresponding // compositionComplete() call. // we'll trigger an update in onPreComposition(). if (mRefreshPending) { mPostedDirtyRegion.clear(); return; } // Capture the old state of the layer for comparisons later const bool oldOpacity = isOpaque(); sp<GraphicBuffer> oldActiveBuffer = mActiveBuffer; // signal another event if we have more frames pending if (android_atomic_dec(&mQueuedFrames) > 1) { mFlinger->signalLayerUpdate(); } struct Reject : public SurfaceTexture::BufferRejecter { Layer::State& front; Layer::State& current; bool& recomputeVisibleRegions; Reject(Layer::State& front, Layer::State& current, bool& recomputeVisibleRegions) : front(front), current(current), recomputeVisibleRegions(recomputeVisibleRegions) { } virtual bool reject(const sp<GraphicBuffer>& buf, const BufferQueue::BufferItem& item) { if (buf == NULL) { return false; } uint32_t bufWidth = buf->getWidth(); uint32_t bufHeight = buf->getHeight(); // check that we received a buffer of the right size // (Take the buffer's orientation into account) if (item.mTransform & Transform::ROT_90) { swap(bufWidth, bufHeight); } bool isFixedSize = item.mScalingMode != NATIVE_WINDOW_SCALING_MODE_FREEZE; if (front.active != front.requested) { if (isFixedSize || (bufWidth == front.requested.w && bufHeight == front.requested.h)) { // Here we pretend the transaction happened by updating the // current and drawing states. Drawing state is only accessed // in this thread, no need to have it locked front.active = front.requested; // We also need to update the current state so that // we don't end-up overwriting the drawing state with // this stale current state during the next transaction // // NOTE: We don't need to hold the transaction lock here // because State::active is only accessed from this thread. current.active = front.active; // recompute visible region recomputeVisibleRegions = true; } ALOGD_IF(DEBUG_RESIZE, "lockPageFlip: (layer=%p), buffer (%ux%u, tr=%02x), scalingMode=%d\n" " drawing={ active ={ wh={%4u,%4u} crop={%4d,%4d,%4d,%4d} (%4d,%4d) }\n" " requested={ wh={%4u,%4u} crop={%4d,%4d,%4d,%4d} (%4d,%4d) }}\n", this, bufWidth, bufHeight, item.mTransform, item.mScalingMode, front.active.w, front.active.h, front.active.crop.left, front.active.crop.top, front.active.crop.right, front.active.crop.bottom, front.active.crop.getWidth(), front.active.crop.getHeight(), front.requested.w, front.requested.h, front.requested.crop.left, front.requested.crop.top, front.requested.crop.right, front.requested.crop.bottom, front.requested.crop.getWidth(), front.requested.crop.getHeight()); } if (!isFixedSize) { if (front.active.w != bufWidth || front.active.h != bufHeight) { // reject this buffer return true; } } return false; } }; Reject r(mDrawingState, currentState(), recomputeVisibleRegions); #ifdef DECIDE_TEXTURE_TARGET // While calling updateTexImage() from SurfaceFlinger, let it know // by passing an extra parameter // This will be true always. bool isComposition = true; if (mSurfaceTexture->updateTexImage(&r, isComposition) < NO_ERROR) { #else if (mSurfaceTexture->updateTexImage(&r) < NO_ERROR) { #endif // something happened! recomputeVisibleRegions = true; return; } // update the active buffer mActiveBuffer = mSurfaceTexture->getCurrentBuffer(); if (mActiveBuffer == NULL) { // this can only happen if the very first buffer was rejected. return; } mRefreshPending = true; mFrameLatencyNeeded = true; if (oldActiveBuffer == NULL) { // the first time we receive a buffer, we need to trigger a // geometry invalidation. mFlinger->invalidateHwcGeometry(); } Rect crop(mSurfaceTexture->getCurrentCrop()); const uint32_t transform(mSurfaceTexture->getCurrentTransform()); const uint32_t scalingMode(mSurfaceTexture->getCurrentScalingMode()); if ((crop != mCurrentCrop) || (transform != mCurrentTransform) || (scalingMode != mCurrentScalingMode)) { mCurrentCrop = crop; mCurrentTransform = transform; mCurrentScalingMode = scalingMode; mFlinger->invalidateHwcGeometry(); } if (oldActiveBuffer != NULL) { uint32_t bufWidth = mActiveBuffer->getWidth(); uint32_t bufHeight = mActiveBuffer->getHeight(); if (bufWidth != uint32_t(oldActiveBuffer->width) || bufHeight != uint32_t(oldActiveBuffer->height)) { mFlinger->invalidateHwcGeometry(); } } mCurrentOpacity = getOpacityForFormat(mActiveBuffer->format); if (oldOpacity != isOpaque()) { recomputeVisibleRegions = true; } // FIXME: mPostedDirtyRegion = dirty & bounds const Layer::State& front(drawingState()); mPostedDirtyRegion.set(front.active.w, front.active.h); glTexParameterx(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameterx(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); } } void Layer::unlockPageFlip( const Transform& planeTransform, Region& outDirtyRegion) { ATRACE_CALL(); Region postedRegion(mPostedDirtyRegion); if (!postedRegion.isEmpty()) { mPostedDirtyRegion.clear(); if (!visibleRegionScreen.isEmpty()) { // The dirty region is given in the layer's coordinate space // transform the dirty region by the surface's transformation // and the global transformation. const Layer::State& s(drawingState()); const Transform tr(planeTransform * s.transform); postedRegion = tr.transform(postedRegion); // At this point, the dirty region is in screen space. // Make sure it's constrained by the visible region (which // is in screen space as well). postedRegion.andSelf(visibleRegionScreen); outDirtyRegion.orSelf(postedRegion); } } }