// requestBuffer requests a new buffer for the given index. The server (i.e. // the IGraphicBufferProducer implementation) assigns the newly created // buffer to the given slot index, and the client is expected to mirror the // slot->buffer mapping so that it's not necessary to transfer a // GraphicBuffer for every dequeue operation. // // The slot must be in the range of [0, NUM_BUFFER_SLOTS). virtualstatus_trequestBuffer(int slot, sp<GraphicBuffer>* buf)= 0;
// dequeueBuffer requests a new buffer slot for the client to use. Ownership // of the slot is transfered to the client, meaning that the server will not // use the contents of the buffer associated with that slot. // virtualstatus_tdequeueBuffer(int* slot, sp<Fence>* fence, uint32_t w, uint32_t h, PixelFormat format, uint32_t usage)= 0;
// detachBuffer attempts to remove all ownership of the buffer in the given // slot from the buffer queue. If this call succeeds, the slot will be // freed, and there will be no way to obtain the buffer from this interface. // The freed slot will remain unallocated until either it is selected to // hold a freshly allocated buffer in dequeueBuffer or a buffer is attached // to the slot. The buffer must have already been dequeued, and the caller // must already possesses the sp<GraphicBuffer> (i.e., must have called // requestBuffer). // virtualstatus_tdetachBuffer(int slot)= 0;
// attachBuffer attempts to transfer ownership of a buffer to the buffer // queue. If this call succeeds, it will be as if this buffer was dequeued // from the returned slot number. As such, this call will fail if attaching // this buffer would cause too many buffers to be simultaneously dequeued. // virtualstatus_tattachBuffer(int* outSlot, const sp<GraphicBuffer>& buffer)= 0;
// acquireBuffer attempts to acquire ownership of the next pending buffer in // the BufferQueue. If no buffer is pending then it returns // NO_BUFFER_AVAILABLE. If a buffer is successfully acquired, the // information about the buffer is returned in BufferItem. // virtualstatus_tacquireBuffer(BufferItem* buffer, nsecs_t presentWhen, uint64_t maxFrameNumber = 0)= 0;
// releaseBuffer releases a buffer slot from the consumer back to the // BufferQueue. This may be done while the buffer's contents are still // being accessed. The fence will signal when the buffer is no longer // in use. frameNumber is used to indentify the exact buffer returned. // virtualstatus_treleaseBuffer(int buf, uint64_t frameNumber, EGLDisplay display, EGLSyncKHR fence, const sp<Fence>& releaseFence)= 0;
// detachBuffer attempts to remove all ownership of the buffer in the given // slot from the buffer queue. If this call succeeds, the slot will be // freed, and there will be no way to obtain the buffer from this interface. // The freed slot will remain unallocated until either it is selected to // hold a freshly allocated buffer in dequeueBuffer or a buffer is attached // to the slot. The buffer must have already been acquired. // virtualstatus_tdetachBuffer(int slot)= 0;
// attachBuffer attempts to transfer ownership of a buffer to the buffer // queue. If this call succeeds, it will be as if this buffer was acquired // from the returned slot number. As such, this call will fail if attaching // this buffer would cause too many buffers to be simultaneously acquired. // virtualstatus_tattachBuffer(int *outSlot, const sp<GraphicBuffer>& buffer)= 0;
publicintrelayout(IWindow window, int seq, WindowManager.LayoutParams attrs, int requestedWidth, int requestedHeight, int viewFlags, int flags, Rect outFrame, Rect outOverscanInsets, Rect outContentInsets, Rect outVisibleInsets, Rect outStableInsets, Rect outsets, Rect outBackdropFrame, Configuration outConfig, Surface outSurface){ int res = mService.relayoutWindow(this, window, seq, attrs, requestedWidth, requestedHeight, viewFlags, flags, outFrame, outOverscanInsets, outContentInsets, outVisibleInsets, outStableInsets, outsets, outBackdropFrame, outConfig, outSurface); return res; }
publicintrelayoutWindow(Session session, IWindow client, int seq, WindowManager.LayoutParams attrs, int requestedWidth, int requestedHeight, int viewVisibility, int flags, Rect outFrame, Rect outOverscanInsets, Rect outContentInsets, Rect outVisibleInsets, Rect outStableInsets, Rect outOutsets, Rect outBackdropFrame, Configuration outConfig, Surface outSurface){ int result = 0; ...... if (viewVisibility == View.VISIBLE && (win.mAppToken == null || !win.mAppToken.clientHidden)) { result = relayoutVisibleWindow(outConfig, result, win, winAnimator, attrChanges, oldVisibility); try { result = createSurfaceControl(outSurface, result, win, winAnimator); } catch (Exception e) { ...... return0; } ...... } else { ...... }
...... return result; }
[->WindowManagerService.java]
1 2 3 4 5 6 7 8 9 10 11 12 13
privateintcreateSurfaceControl(Surface outSurface, int result, WindowState win, WindowStateAnimator winAnimator){ if (!win.mHasSurface) { result |= RELAYOUT_RES_SURFACE_CHANGED; } WindowSurfaceController surfaceController = winAnimator.createSurfaceLocked(); if (surfaceController != null) { surfaceController.getSurface(outSurface); } else { outSurface.release(); } return result; }
publicWindowSurfaceController(SurfaceSession s, String name, int w, int h, int format, int flags, WindowStateAnimator animator){ mAnimator = animator; mSurfaceW = w; mSurfaceH = h; ...... if (animator.mWin.isChildWindow() && animator.mWin.mSubLayer < 0 && animator.mWin.mAppToken != null) { ...... } else { mSurfaceControl = new SurfaceControl( s, name, w, h, format, flags); } }
4.2.4.1、APP申请创建Surface过程(c层)
SurfaceControl创建过程 [->SurfaceControl.java]
1 2 3 4 5 6 7
publicSurfaceControl(SurfaceSession session, String name, int w, int h, int format, int flags) throws OutOfResourcesException { ...... mNativeObject = nativeCreate(session, name, w, h, format, flags); ...... }
status_tClient::createSurface( const String8& name, uint32_t w, uint32_t h, PixelFormat format, uint32_t flags, sp<IBinder>* handle, sp<IGraphicBufferProducer>* gbp){ /* * createSurface must be called from the GL thread so that it can * have access to the GL context. */
int numStartingBuffers = getMaxBufferCountLocked(); for (int s = 0; s < numStartingBuffers; s++) { mFreeSlots.insert(s); } for (int s = numStartingBuffers; s < BufferQueueDefs::NUM_BUFFER_SLOTS; s++) { mUnusedSlots.push_front(s); } }
static jlong nativeCreateFromSurfaceControl(JNIEnv* env, jclass clazz, jlong surfaceControlNativeObj){ /* * This is used by the WindowManagerService just after constructing * a Surface and is necessary for returning the Surface reference to * the caller. At this point, we should only have a SurfaceControl. */
@Override publicvoidwriteToParcel(Parcel dest, int flags){ if (dest == null) { thrownew IllegalArgumentException("dest must not be null"); } synchronized (mLock) { // NOTE: This must be kept synchronized with the native parceling code // in frameworks/native/libs/Surface.cpp dest.writeString(mName); dest.writeInt(mIsSingleBuffered ? 1 : 0); nativeWriteToParcel(mNativeObject, dest); } if ((flags & Parcelable.PARCELABLE_WRITE_RETURN_VALUE) != 0) { release(); } }
[android_view_Surface.cpp]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
staticvoidnativeWriteToParcel(JNIEnv* env, jclass clazz, jlong nativeObject, jobject parcelObj){ Parcel* parcel = parcelForJavaObject(env, parcelObj); if (parcel == NULL) { doThrowNPE(env); return; } sp<Surface> self(reinterpret_cast<Surface *>(nativeObject)); android::view::Surface surfaceShim; if (self != nullptr) { surfaceShim.graphicBufferProducer = self->getIGraphicBufferProducer(); } // Calling code in Surface.java has already written the name of the Surface // to the Parcel surfaceShim.writeToParcel(parcel, /*nameAlreadyWritten*/true); }
publicvoidreadFromParcel(Parcel source){ if (source == null) { thrownew IllegalArgumentException("source must not be null"); }
synchronized (mLock) { // nativeReadFromParcel() will either return mNativeObject, or // create a new native Surface and return it after reducing // the reference count on mNativeObject. Either way, it is // not necessary to call nativeRelease() here. // NOTE: This must be kept synchronized with the native parceling code // in frameworks/native/libs/Surface.cpp mName = source.readString(); mIsSingleBuffered = source.readInt() != 0; setNativeObjectLocked(nativeReadFromParcel(mNativeObject, source)); } }
static jlong nativeCreateFromSurfaceControl(JNIEnv* env, jclass clazz, jlong surfaceControlNativeObj){ /* * This is used by the WindowManagerService just after constructing * a Surface and is necessary for returning the Surface reference to * the caller. At this point, we should only have a SurfaceControl. */
sp<Surface> SurfaceControl::getSurface()const { Mutex::Autolock _l(mLock); if (mSurfaceData == 0) { // This surface is always consumed by SurfaceFlinger, so the // producerControlledByApp value doesn't matter; using false. mSurfaceData = new Surface(mGraphicBufferProducer, false); } return mSurfaceData; }
{ // scope for the lock Mutex::Autolock lock(mCallbackMutex); while (callbackTicket != mCurrentCallbackTicket) { mCallbackCondition.wait(mCallbackMutex); }
bool refreshNeeded = handleMessageTransaction(); refreshNeeded |= handleMessageInvalidate(); refreshNeeded |= mRepaintEverything; if (refreshNeeded) { // Signal a refresh if a transaction modified the window state, // a new buffer was latched, or if HWC has requested a full // repaint signalRefresh(); } break; } case MessageQueue::REFRESH: { handleMessageRefresh(); break; } } }
// Release any buffers which were replaced this frame for (auto& layer : mLayersWithQueuedFrames) { layer->releasePendingBuffer(); } mLayersWithQueuedFrames.clear(); }
if (sizeChanged) { // the size changed, we need to ask our client to request a new buffer //如果Layer的尺寸发生变化,就要改变Surface的缓冲区的尺寸 // record the new size, form this point on, when the client request // a buffer, it'll get the new size. mSurfaceFlingerConsumer->setDefaultBufferSize( c.requested.w, c.requested.h); }
const bool resizePending = (c.requested.w != c.active.w) || (c.requested.h != c.active.h); if (!isFixedSize()) { if (resizePending && mSidebandStream == NULL) { //如果Layer不是固定尺寸的类型,比较它的实际大小和要求的改变大小 flags |= eDontUpdateGeometryState; } } //如果没有eDontUpdateGeometryState标志,更新active的值为request if (flags & eDontUpdateGeometryState) { } else { Layer::State& editCurrentState(getCurrentState()); if (mFreezePositionUpdates) { float tx = c.active.transform.tx(); float ty = c.active.transform.ty(); c.active = c.requested; c.active.transform.set(tx, ty); editCurrentState.active = c.active; } else { editCurrentState.active = editCurrentState.requested; c.active = c.requested; } } // 如果当前state的active和以前的State的active不等,设置更新标志 if (s.active != c.active) { // invalidate and recompute the visible regions if needed flags |= Layer::eVisibleRegion; } //如果当前state的sequence和以前state的sequence不等,设置更新标志 if (c.sequence != s.sequence) { // invalidate and recompute the visible regions if needed flags |= eVisibleRegion; this->contentDirty = true;
// we may use linear filtering, if the matrix scales us const uint8_t type = c.active.transform.getType(); mNeedsFiltering = (!c.active.transform.preserveRects() || (type >= Transform::SCALE)); }
// If the layer is hidden, signal and clear out all local sync points so // that transactions for layers depending on this layer's frames becoming // visible are not blocked if (c.flags & layer_state_t::eLayerHidden) { Mutex::Autolock lock(mLocalSyncPointMutex); for (auto& point : mLocalSyncPoints) { point->setFrameAvailable(); } mLocalSyncPoints.clear(); }
// Commit the transaction commitTransaction(c); return flags; }
if (transactionFlags & eDisplayTransactionNeeded) { // here we take advantage of Vector's copy-on-write semantics to // improve performance by skipping the transaction entirely when // know that the lists are identical const KeyedVector< wp<IBinder>, DisplayDeviceState>& curr(mCurrentState.displays); const KeyedVector< wp<IBinder>, DisplayDeviceState>& draw(mDrawingState.displays); if (!curr.isIdenticalTo(draw)) { mVisibleRegionsDirty = true; constsize_t cc = curr.size(); size_t dc = draw.size();
// find the displays that were removed // (ie: in drawing state but not in current state) // also handle displays that changed // (ie: displays that are in both lists) for (size_t i=0 ; i<dc ; i++) { constssize_t j = curr.indexOfKey(draw.keyAt(i)); if (j < 0) { // in drawing state but not in current state if (!draw[i].isMainDisplay()) { // Call makeCurrent() on the primary display so we can // be sure that nothing associated with this display // is current. const sp<const DisplayDevice> defaultDisplay(getDefaultDisplayDevice()); defaultDisplay->makeCurrent(mEGLDisplay, mEGLContext); sp<DisplayDevice> hw(getDisplayDevice(draw.keyAt(i))); if (hw != NULL) hw->disconnect(getHwComposer()); if (draw[i].type < DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES) mEventThread->onHotplugReceived(draw[i].type, false); mDisplays.removeItem(draw.keyAt(i)); } else { ALOGW("trying to remove the main display"); } } else { // this display is in both lists. see if something changed. const DisplayDeviceState& state(curr[j]); const wp<IBinder>& display(curr.keyAt(j)); const sp<IBinder> state_binder = IInterface::asBinder(state.surface); const sp<IBinder> draw_binder = IInterface::asBinder(draw[i].surface); if (state_binder != draw_binder) { // changing the surface is like destroying and // recreating the DisplayDevice, so we just remove it // from the drawing state, so that it get re-added // below. sp<DisplayDevice> hw(getDisplayDevice(display)); if (hw != NULL) hw->disconnect(getHwComposer()); mDisplays.removeItem(display); mDrawingState.displays.removeItemsAt(i); dc--; i--; // at this point we must loop to the next item continue; }
// find displays that were added // (ie: in current state but not in drawing state) for (size_t i=0 ; i<cc ; i++) { if (draw.indexOfKey(curr.keyAt(i)) < 0) { const DisplayDeviceState& state(curr[i]);
int32_t hwcDisplayId = -1; if (state.isVirtualDisplay()) { // Virtual displays without a surface are dormant: // they have external state (layer stack, projection, // etc.) but no internal state (i.e. a DisplayDevice). if (state.surface != NULL) {
int width = 0; DisplayUtils* displayUtils = DisplayUtils::getInstance(); int status = state.surface->query( NATIVE_WINDOW_WIDTH, &width); ALOGE_IF(status != NO_ERROR, "Unable to query width (%d)", status); int height = 0; status = state.surface->query( NATIVE_WINDOW_HEIGHT, &height); ALOGE_IF(status != NO_ERROR, "Unable to query height (%d)", status); if (MAX_VIRTUAL_DISPLAY_DIMENSION == 0 || (width <= MAX_VIRTUAL_DISPLAY_DIMENSION && height <= MAX_VIRTUAL_DISPLAY_DIMENSION)) { int usage = 0; status = state.surface->query( NATIVE_WINDOW_CONSUMER_USAGE_BITS, &usage); ALOGW_IF(status != NO_ERROR, "Unable to query usage (%d)", status); if ( (status == NO_ERROR) && displayUtils->canAllocateHwcDisplayIdForVDS(usage)) { hwcDisplayId = allocateHwcDisplayId(state.type); } }
displayUtils->initVDSInstance(mHwc, hwcDisplayId, state.surface, dispSurface, producer, bqProducer, bqConsumer, state.displayName, state.isSecure, state.type); } } else { ALOGE_IF(state.surface!=NULL, "adding a supported display, but rendering " "surface is provided (%p), ignoring it", state.surface.get()); hwcDisplayId = allocateHwcDisplayId(state.type); // for supported (by hwc) displays we provide our // own rendering surface dispSurface = new FramebufferSurface(*mHwc, state.type, bqConsumer); producer = bqProducer; }
const wp<IBinder>& display(curr.keyAt(i)); if (dispSurface != NULL && producer != NULL) { sp<DisplayDevice> hw = new DisplayDevice(this, state.type, hwcDisplayId, mHwc->getFormat(hwcDisplayId), state.isSecure, display, dispSurface, producer, mRenderEngine->getEGLConfig()); hw->setLayerStack(state.layerStack); hw->setProjection(state.orientation, state.viewport, state.frame); hw->setDisplayName(state.displayName); // When a new display device is added update the active // config by querying HWC otherwise the default config // (config 0) will be used. if (hwcDisplayId >= DisplayDevice::DISPLAY_PRIMARY && hwcDisplayId < DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES) { int activeConfig = mHwc->getActiveConfig(hwcDisplayId); if (activeConfig >= 0) { hw->setActiveConfig(activeConfig); } } mDisplays.add(display, hw); if (state.isVirtualDisplay()) { if (hwcDisplayId >= 0) { mHwc->setVirtualDisplayProperties(hwcDisplayId, hw->getWidth(), hw->getHeight(), hw->getFormat()); } } else { mEventThread->onHotplugReceived(state.type, true); } } } } } }
if (transactionFlags & (eTraversalNeeded|eDisplayTransactionNeeded)) { ...... sp<const DisplayDevice> disp; uint32_t currentlayerStack = 0; for (size_t i=0; i<count; i++) { // NOTE: we rely on the fact that layers are sorted by // layerStack first (so we don't have to traverse the list // of displays for every layer). const sp<Layer>& layer(currentLayers[i]); uint32_t layerStack = layer->getDrawingState().layerStack; if (i==0 || currentlayerStack != layerStack) { currentlayerStack = layerStack; // figure out if this layerstack is mirrored // (more than one display) if so, pick the default display, // if not, pick the only display it's on. disp.clear(); for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) { sp<const DisplayDevice> hw(mDisplays[dpy]); if (hw->getLayerStack() == currentlayerStack) { if (disp == NULL) { disp = hw; } else { disp = NULL; break; } } } } if (disp == NULL) { // NOTE: TEMPORARY FIX ONLY. Real fix should cause layers to // redraw after transform hint changes. See bug 8508397.
// could be null when this layer is using a layerStack // that is not visible on any display. Also can occur at // screen off/on times. disp = getDefaultDisplayDevice(); } layer->updateTransformHint(disp); } }
const LayerVector& layers(mDrawingState.layersSortedByZ); if (currentLayers.size() > layers.size()) { // layers have been added mVisibleRegionsDirty = true; }
// some layers might have been removed, so // we need to update the regions they're exposing. if (mLayersRemoved) { mLayersRemoved = false; mVisibleRegionsDirty = true; constsize_t count = layers.size(); for (size_t i=0 ; i<count ; i++) { const sp<Layer>& layer(layers[i]); if (currentLayers.indexOf(layer) < 0) { // this layer is not visible anymore // TODO: we could traverse the tree from front to back and // compute the actual visible region // TODO: we could cache the transformed region const Layer::State& s(layer->getDrawingState()); Region visibleReg = s.active.transform.transform( Region(Rect(s.active.w, s.active.h))); invalidateLayerStack(s.layerStack, visibleReg); } } }
// Store the set of layers that need updates. This set must not change as // buffers are being latched, as this could result in a deadlock. // Example: Two producers share the same command stream and: // 1.) Layer 0 is latched // 2.) Layer 0 gets a new frame // 2.) Layer 1 gets a new frame // 3.) Layer 1 is latched. // Display is now waiting on Layer 1's frame, which is behind layer 0's // second frame. But layer 0's second frame could be waiting on display. Vector<Layer*> layersWithQueuedFrames; for (size_t i = 0, count = layers.size(); i<count ; i++) { const sp<Layer>& layer(layers[i]); if (layer->hasQueuedFrame()) { frameQueued = true; if (layer->shouldPresentNow(mPrimaryDispSync)) { layersWithQueuedFrames.push_back(layer.get()); } else { layer->useEmptyDamage(); } } else { layer->useEmptyDamage(); } } for (size_t i = 0, count = layersWithQueuedFrames.size() ; i<count ; i++) { Layer* layer = layersWithQueuedFrames[i]; const Region dirty(layer->latchBuffer(visibleRegions)); layer->useSurfaceDamage(); const Layer::State& s(layer->getDrawingState()); invalidateLayerStack(s.layerStack, dirty); }
mVisibleRegionsDirty |= visibleRegions;
// If we will need to wake up at some time in the future to deal with a // queued frame that shouldn't be displayed during this vsync period, wake // up during the next vsync period to check again. if (frameQueued && layersWithQueuedFrames.empty()) { signalLayerUpdate(); }
// Only continue with the refresh if there is actually new work to do return !layersWithQueuedFrames.empty(); }
if (mustRecompose) { mDisplays[dpy]->lastCompositionHadVisibleLayers = !empty; } } //得到系统HWComposer对象 HWComposer& hwc(getHwComposer()); if (hwc.initCheck() == NO_ERROR) { // build the h/w work list if (CC_UNLIKELY(mHwWorkListDirty)) { mHwWorkListDirty = false; for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) { sp<const DisplayDevice> hw(mDisplays[dpy]); constint32_t id = hw->getHwcDisplayId(); if (id >= 0) { const Vector< sp<Layer> >& currentLayers( hw->getVisibleLayersSortedByZ()); constsize_t count = currentLayers.size(); //根据Layer数量在HWComposer中创建hwc_layer_list_t列表 if (hwc.createWorkList(id, count) == NO_ERROR) { HWComposer::LayerListIterator cur = hwc.begin(id); const HWComposer::LayerListIterator end = hwc.end(id); for (size_t i=0 ; cur!=end && i<count ; ++i, ++cur) { const sp<Layer>& layer(currentLayers[i]); layer->setGeometry(hw, *cur); if (mDebugDisableHWC || mDebugRegion || mDaltonize || mHasColorMatrix) { cur->setSkip(true); } } } } } }
// set the per-frame data for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) { sp<const DisplayDevice> hw(mDisplays[dpy]); constint32_t id = hw->getHwcDisplayId(); if (id >= 0) { bool freezeSurfacePresent = false; isfreezeSurfacePresent(freezeSurfacePresent, hw, id); const Vector< sp<Layer> >& currentLayers( hw->getVisibleLayersSortedByZ()); constsize_t count = currentLayers.size(); HWComposer::LayerListIterator cur = hwc.begin(id); const HWComposer::LayerListIterator end = hwc.end(id); for (size_t i=0 ; cur!=end && i<count ; ++i, ++cur) { /* * update the per-frame h/w composer data for each layer * and build the transparent region of the FB */ const sp<Layer>& layer(currentLayers[i]); //将Layer的mActiveBuffer设置到HWComposer中 layer->setPerFrameData(hw, *cur); setOrientationEventControl(freezeSurfacePresent,id); } } }
// If possible, attempt to use the cursor overlay on each display. for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) { sp<const DisplayDevice> hw(mDisplays[dpy]); constint32_t id = hw->getHwcDisplayId(); if (id >= 0) { const Vector< sp<Layer> >& currentLayers( hw->getVisibleLayersSortedByZ()); constsize_t count = currentLayers.size(); HWComposer::LayerListIterator cur = hwc.begin(id); const HWComposer::LayerListIterator end = hwc.end(id); for (size_t i=0 ; cur!=end && i<count ; ++i, ++cur) { const sp<Layer>& layer(currentLayers[i]); if (layer->isPotentialCursor()) { cur->setIsCursorLayerHint(); break; } } } }
voidSurfaceFlinger::doComposition(){ ATRACE_CALL(); constbool repaintEverything = android_atomic_and(0, &mRepaintEverything); for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) { const sp<DisplayDevice>& hw(mDisplays[dpy]); if (hw->isDisplayOn()) { // transform the dirty region into this screen's coordinate space const Region dirtyRegion(hw->getDirtyRegion(repaintEverything));
// repaint the framebuffer (if needed) doDisplayComposition(hw, dirtyRegion);
hw->dirtyRegion.clear(); hw->flip(hw->swapRegion); hw->swapRegion.clear(); } // inform the h/w that we're done compositing hw->compositionComplete(); } postFramebuffer(); }
voidSurfaceFlinger::doDisplayComposition(const sp<const DisplayDevice>& hw, const Region& inDirtyRegion) { // We only need to actually compose the display if: // 1) It is being handled by hardware composer, which may need this to // keep its virtual display state machine in sync, or // 2) There is work to be done (the dirty region isn't empty) bool isHwcDisplay = hw->getHwcDisplayId() >= 0; if (!isHwcDisplay && inDirtyRegion.isEmpty()) { ALOGV("Skipping display composition"); return; }
ALOGV("doDisplayComposition");
Region dirtyRegion(inDirtyRegion);
// compute the invalid region //swapRegion设置为需要更新的区域 hw->swapRegion.orSelf(dirtyRegion);
uint32_t flags = hw->getFlags();//获得显示设备支持的更新方式标志 if (flags & DisplayDevice::SWAP_RECTANGLE) { // we can redraw only what's dirty, but since SWAP_RECTANGLE only // takes a rectangle, we must make sure to update that whole // rectangle in that case dirtyRegion.set(hw->swapRegion.bounds()); } else { if (flags & DisplayDevice::PARTIAL_UPDATES) {//支持部分更新 // We need to redraw the rectangle that will be updated // (pushed to the framebuffer). // This is needed because PARTIAL_UPDATES only takes one // rectangle instead of a region (see DisplayDevice::flip()) //将更新区域调整为整个窗口大小 dirtyRegion.set(hw->swapRegion.bounds()); } else { // we need to redraw everything (the whole screen) dirtyRegion.set(hw->bounds()); hw->swapRegion = dirtyRegion; } } //合成 if (!doComposeSurfaces(hw, dirtyRegion)) return;
// update the swap region and clear the dirty region hw->swapRegion.orSelf(dirtyRegion); //没有硬件composer的情况,输出图像 // swap buffers (presentation) hw->swapBuffers(getHwComposer()); }
constnsecs_t now = systemTime(); mDebugInSwapBuffers = now;
HWComposer& hwc(getHwComposer()); if (hwc.initCheck() == NO_ERROR) { if (!hwc.supportsFramebufferTarget()) { // EGL spec says: // "surface must be bound to the calling thread's current context, // for the current rendering API." getDefaultDisplayDevice()->makeCurrent(mEGLDisplay, mEGLContext); } hwc.commit(); }
// make the default display current because the VirtualDisplayDevice code cannot // deal with dequeueBuffer() being called outside of the composition loop; however // the code below can call glFlush() which is allowed (and does in some case) call // dequeueBuffer(). getDefaultDisplayDevice()->makeCurrent(mEGLDisplay, mEGLContext);
for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) { sp<const DisplayDevice> hw(mDisplays[dpy]); const Vector< sp<Layer> >& currentLayers(hw->getVisibleLayersSortedByZ()); hw->onSwapBuffersCompleted(hwc); constsize_t count = currentLayers.size(); int32_t id = hw->getHwcDisplayId(); if (id >=0 && hwc.initCheck() == NO_ERROR) { HWComposer::LayerListIterator cur = hwc.begin(id); const HWComposer::LayerListIterator end = hwc.end(id); for (size_t i = 0; cur != end && i < count; ++i, ++cur) { currentLayers[i]->onLayerDisplayed(hw, &*cur); } } else { for (size_t i = 0; i < count; i++) { currentLayers[i]->onLayerDisplayed(hw, NULL); } } }
status_tHWComposer::commit(){ int err = NO_ERROR; if (mHwc) { if (!hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) { // On version 1.0, the OpenGL ES target surface is communicated // by the (dpy, sur) fields and we are guaranteed to have only // a single display. mLists[0]->dpy = eglGetCurrentDisplay(); mLists[0]->sur = eglGetCurrentSurface(EGL_DRAW); }
for (size_t i=VIRTUAL_DISPLAY_ID_BASE; i<mNumDisplays; i++) { DisplayData& disp(mDisplayData[i]); if (disp.outbufHandle) { mLists[i]->outbuf = disp.outbufHandle; mLists[i]->outbufAcquireFenceFd = disp.outbufAcquireFence->dup(); } }
HWComposer::HWComposer( const sp<SurfaceFlinger>& flinger, EventHandler& handler) : mFlinger(flinger), mFbDev(0), mHwc(0), mNumDisplays(1), mCBContext(new cb_context), mEventHandler(handler), mDebugForceFakeVSync(false) { ... //首先是一些和VSYNC有关的信息的初始化 //因为在硬件支持的情况下,VSYNC的功能就是由HWC提供的 for (size_t i=0 ; i<HWC_NUM_PHYSICAL_DISPLAY_TYPES ; i++) { mLastHwVSync[i] = 0; mVSyncCounts[i] = 0; } //根据配置来看是否需要模拟VSYNC消息 char value[PROPERTY_VALUE_MAX]; property_get("debug.sf.no_hw_vsync", value, "0"); mDebugForceFakeVSync = atoi(value); ... // don't need a vsync thread if we have a hardware composer needVSyncThread = false; // always turn vsync off when we start,只是暂时关闭信号,后面会再开启 eventControl(HWC_DISPLAY_PRIMARY, HWC_EVENT_VSYNC, 0);
//显然,如果需要模拟VSync信号的话,我们需要线程来做这个工作 if (needVSyncThread) { // we don't have VSYNC support, we need to fake it //VSyncThread类的实现很简单,无非就是一个计时器而已,定时发送消息而已 //TODO VSYNC专题 mVSyncThread = new VSyncThread(*this); } ... }
HWComposer::HWComposer( const sp<SurfaceFlinger>& flinger, EventHandler& handler) : mFlinger(flinger), mFbDev(0), mHwc(0), mNumDisplays(1), mCBContext(new cb_context), mEventHandler(handler), mDebugForceFakeVSync(false) { ... //首先是一些和VSYNC有关的信息的初始化 //因为在硬件支持的情况下,VSYNC的功能就是由HWC提供的 for (size_t i=0 ; i<HWC_NUM_PHYSICAL_DISPLAY_TYPES ; i++) { mLastHwVSync[i] = 0; mVSyncCounts[i] = 0; } //根据配置来看是否需要模拟VSYNC消息 char value[PROPERTY_VALUE_MAX]; property_get("debug.sf.no_hw_vsync", value, "0"); mDebugForceFakeVSync = atoi(value); ... // don't need a vsync thread if we have a hardware composer needVSyncThread = false; // always turn vsync off when we start,只是暂时关闭信号,后面会再开启 eventControl(HWC_DISPLAY_PRIMARY, HWC_EVENT_VSYNC, 0);
//显然,如果需要模拟VSync信号的话,我们需要线程来做这个工作 if (needVSyncThread) { // we don't have VSYNC support, we need to fake it //VSyncThread类的实现很简单,无非就是一个计时器而已,定时发送消息而已 //TODO VSYNC专题 mVSyncThread = new VSyncThread(*this); } ... }
// dispatch events to listeners... constsize_t count = signalConnections.size(); for (size_t i=0 ; i<count ; i++) { const sp<Connection>& conn(signalConnections[i]); // now see if we still need to report this event status_t err = conn->postEvent(event); ...... } returntrue; }
// dispatch events to listeners... constsize_t count = signalConnections.size(); for (size_t i=0 ; i<count ; i++) { const sp<Connection>& conn(signalConnections[i]); // now see if we still need to report this event status_t err = conn->postEvent(event); ...... } returntrue; }
structepoll_eventeventItem; memset(& eventItem, 0, sizeof(epoll_event)); // zero out unused members of data field union eventItem.events = epollEvents; eventItem.data.fd = fd;
publicvoidscheduleVsync(){ if (mReceiverPtr == 0) { Log.w(TAG, "Attempted to schedule a vertical sync pulse but the display event " + "receiver has already been disposed."); } else { nativeScheduleVsync(mReceiverPtr); } }
[->android_view_DisplayEventReceiver.cpp ]
1 2 3 4 5 6 7 8 9 10
staticvoidnativeScheduleVsync(JNIEnv* env, jclass clazz, jlong receiverPtr){ sp<NativeDisplayEventReceiver> receiver = reinterpret_cast<NativeDisplayEventReceiver*>(receiverPtr); status_t status = receiver->scheduleVsync(); if (status) { String8 message; message.appendFormat("Failed to schedule next vertical sync pulse. status=%d", status); jniThrowRuntimeException(env, message.string()); } }
// Invoke all response callbacks. for (size_t i = 0; i < mResponses.size(); i++) { Response& response = mResponses.editItemAt(i); if (response.request.ident == POLL_CALLBACK) { int fd = response.request.fd; int events = response.events; void* data = response.request.data; int callbackResult = response.request.callback->handleEvent(fd, events, data); if (callbackResult == 0) { removeFd(fd); } // Clear the callback reference in the response structure promptly because we // will not clear the response vector itself until the next poll. response.request.callback.clear(); result = POLL_CALLBACK; } }
boolNativeDisplayEventReceiver::processPendingEvents(nsecs_t* outTimestamp, int32_t* outId, uint32_t* outCount){ bool gotVsync = false; DisplayEventReceiver::Event buf[EVENT_BUFFER_SIZE]; ssize_t n; while ((n = mReceiver.getEvents(buf, EVENT_BUFFER_SIZE)) > 0) { for (ssize_t i = 0; i < n; i++) { const DisplayEventReceiver::Event& ev = buf[i]; switch (ev.header.type) { case DisplayEventReceiver::DISPLAY_EVENT_VSYNC: // Later vsync events will just overwrite the info from earlier // ones. That's fine, we only care about the most recent. gotVsync = true; *outTimestamp = ev.header.timestamp; *outId = ev.header.id; *outCount = ev.vsync.count; break; case DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG: dispatchHotplug(ev.header.timestamp, ev.header.id, ev.hotplug.connected); break; default: ALOGW("receiver %p ~ ignoring unknown event type %#x", this, ev.header.type); break; } } } if (n < 0) { ALOGW("Failed to get events from display event receiver, status=%d", status_t(n)); } return gotVsync; }
// Called from native code. @SuppressWarnings("unused") privatevoiddispatchVsync(long timestampNanos, int builtInDisplayId, int frame){ onVsync(timestampNanos, builtInDisplayId, frame); } 注释表明这个方法是从native代码调用的,该函数然后会调用FrameDisplayEventReceiver.onVsync方法: @Override publicvoidonVsync(long timestampNanos, int builtInDisplayId, int frame){ // Ignore vsync from secondary display. // This can be problematic because the call to scheduleVsync() is a one-shot. // We need to ensure that we will still receive the vsync from the primary // display which is the one we really care about. Ideally we should schedule // vsync for a particular display. // At this time Surface Flinger won't send us vsyncs for secondary displays // but that could change in the future so let's log a message to help us remember // that we need to fix this. //注释:忽略来自非主显示器的Vsync信号,但是我们前面调用的scheduleVsync函数只能请求到一次Vsync信号,因此需要重新调用scheduleVsync函数 //请求来自主显示设备的Vsync信号 if (builtInDisplayId != SurfaceControl.BUILT_IN_DISPLAY_ID_MAIN) { Log.d(TAG, "Received vsync from secondary display, but we don't support " + "this case yet. Choreographer needs a way to explicitly request " + "vsync for a specific display to ensure it doesn't lose track " + "of its scheduled vsync."); scheduleVsync(); return; }
// Post the vsync event to the Handler. // The idea is to prevent incoming vsync events from completely starving // the message queue. If there are no messages in the queue with timestamps // earlier than the frame time, then the vsync event will be processed immediately. // Otherwise, messages that predate the vsync event will be handled first. long now = System.nanoTime(); if (timestampNanos > now) { Log.w(TAG, "Frame time is " + ((timestampNanos - now) * 0.000001f) + " ms in the future! Check that graphics HAL is generating vsync " + "timestamps using the correct timebase."); timestampNanos = now; }
if (mHavePendingVsync) { Log.w(TAG, "Already have a pending vsync event. There should only be " + "one at a time."); } else { mHavePendingVsync = true; }