Android SurfaceFlinger服務(八) ----- 圖像的輸出
阿新 • • 發佈:2018-07-24
getc position %d replace ger gin surface geo android
SurfaceFlinger合成後就進行圖像的輸出的工作。在圖像輸出時,存在硬件合成器與不存在的情況有些差別。軟件合成時用到圖像緩沖區生產者與消費者模型。首先來看看圖像緩沖區的初始化。
void SurfaceFlinger::init() { ALOGI( "SurfaceFlinger‘s main thread ready to run. " "Initializing graphics H/W..."); ...... // initialize our non-virtual displays for (size_t i=0 ; i<DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES ; i++) { DisplayDevice::DisplayType type((DisplayDevice::DisplayType)i); // set-up the displays that are already connected if (mHwc->isConnected(i) || type==DisplayDevice::DISPLAY_PRIMARY) { // All non-virtual displays are currently considered secure. bool isSecure = true; createBuiltinDisplayLocked(type); wp<IBinder> token = mBuiltinDisplays[i]; sp<IGraphicBufferProducer> producer; sp<IGraphicBufferConsumer> consumer; BufferQueue::createBufferQueue(&producer, &consumer, new GraphicBufferAlloc()); sp<FramebufferSurface> fbs = new FramebufferSurface(*mHwc, i, consumer); int32_t hwcId = allocateHwcDisplayId(type); sp<DisplayDevice> hw = new DisplayDevice(this, type, hwcId, mHwc->getFormat(hwcId), isSecure, token, fbs, producer, mRenderEngine->getEGLConfig()); if (i > DisplayDevice::DISPLAY_PRIMARY) { // FIXME: currently we don‘t get blank/unblank requests // for displays other than the main display, so we always // assume a connected display is unblanked. ALOGD("marking display %zu as acquired/unblanked", i); hw->setPowerMode(HWC_POWER_MODE_NORMAL); } mDisplays.add(token, hw); } } ...... }
- 調用BufferQueue::createBufferQueue創建圖像緩沖區,並得到其生產者和消費者接口
- 利用上面得到的consumer消費者接口創建FramebufferSurface
- 利用上面得到的producer生產者接口創建DisplayDevice
- DisplayDevice軟件合成的圖像在FramebufferSurface中得以消費處理
DisplayDevice::DisplayDevice( const sp<SurfaceFlinger>& flinger, DisplayType type, int32_t hwcId, int format, bool isSecure, const wp<IBinder>& displayToken, const sp<DisplaySurface>& displaySurface, const sp<IGraphicBufferProducer>& producer, EGLConfig config) : lastCompositionHadVisibleLayers(false), mFlinger(flinger), mType(type), mHwcDisplayId(hwcId), mDisplayToken(displayToken), mDisplaySurface(displaySurface), mDisplay(EGL_NO_DISPLAY), mSurface(EGL_NO_SURFACE), mDisplayWidth(), mDisplayHeight(), mFormat(), mFlags(), mPageFlipCount(), mIsSecure(isSecure), mSecureLayerVisible(false), mLayerStack(NO_LAYER_STACK), mOrientation(), mPowerMode(HWC_POWER_MODE_OFF), mActiveConfig(0) { mNativeWindow = new Surface(producer, false); ANativeWindow* const window = mNativeWindow.get(); /* * Create our display‘s surface */ EGLSurface surface; EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY); if (config == EGL_NO_CONFIG) { config = RenderEngine::chooseEglConfig(display, format); } surface = eglCreateWindowSurface(display, config, window, NULL); eglQuerySurface(display, surface, EGL_WIDTH, &mDisplayWidth); eglQuerySurface(display, surface, EGL_HEIGHT, &mDisplayHeight); // Make sure that composition can never be stalled by a virtual display // consumer that isn‘t processing buffers fast enough. We have to do this // in two places: // * Here, in case the display is composed entirely by HWC. // * In makeCurrent(), using eglSwapInterval. Some EGL drivers set the // window‘s swap interval in eglMakeCurrent, so they‘ll override the // interval we set here. if (mType >= DisplayDevice::DISPLAY_VIRTUAL) window->setSwapInterval(window, 0); mConfig = config; mDisplay = display; mSurface = surface; mFormat = format; mPageFlipCount = 0; mViewport.makeInvalid(); mFrame.makeInvalid(); // virtual displays are always considered enabled mPowerMode = (mType >= DisplayDevice::DISPLAY_VIRTUAL) ? HWC_POWER_MODE_NORMAL : HWC_POWER_MODE_OFF; // Name the display. The name will be replaced shortly if the display // was created with createDisplay(). switch (mType) { case DISPLAY_PRIMARY: mDisplayName = "Built-in Screen"; break; case DISPLAY_EXTERNAL: mDisplayName = "HDMI Screen"; break; default: mDisplayName = "Virtual Screen"; // e.g. Overlay #n break; } // initialize the display orientation transform. setProjection(DisplayState::eOrientationDefault, mViewport, mFrame); }
- 使用生產者接口初始化egl圖形庫
- 軟件繪制圖層時就會調用EGL圖形庫,間接調用生產者接口
在SurfaceFlinger::doDisplayComposition函數中調用doComposeSurfaces函數合成圖層,然後調用hw->swapBuffers。對於沒有HWComper存在時,直接提交顯示。若存在HWComper時,將軟件合成的圖層交由HWComper處理。
void DisplayDevice::swapBuffers(HWComposer& hwc) const { // We need to call eglSwapBuffers() if: // (1) we don‘t have a hardware composer, or // (2) we did GLES composition this frame, and either // (a) we have framebuffer target support (not present on legacy // devices, where HWComposer::commit() handles things); or // (b) this is a virtual display if (hwc.initCheck() != NO_ERROR || (hwc.hasGlesComposition(mHwcDisplayId) && (hwc.supportsFramebufferTarget() || mType >= DISPLAY_VIRTUAL))) { EGLBoolean success = eglSwapBuffers(mDisplay, mSurface); if (!success) { EGLint error = eglGetError(); if (error == EGL_CONTEXT_LOST || mType == DisplayDevice::DISPLAY_PRIMARY) { LOG_ALWAYS_FATAL("eglSwapBuffers(%p, %p) failed with 0x%08x", mDisplay, mSurface, error); } else { ALOGE("eglSwapBuffers(%p, %p) failed with 0x%08x", mDisplay, mSurface, error); } } } status_t result = mDisplaySurface->advanceFrame(); if (result != NO_ERROR) { ALOGE("[%s] failed pushing new frame to HWC: %d", mDisplayName.string(), result); } }
- 在不存在HWComposer或存在HWComposer但使用gles合成時調用eglSwapBuffers提交gles合成的緩沖區
- 其它情況對圖層合層不作處理
eglSwapBuffers提交gles合成的緩沖區後交由圖層消費者去處理,前文中提到消費者是FramebufferSurface。看看其處理函數:
void FramebufferSurface::onFrameAvailable(const BufferItem& /* item */) {
sp<GraphicBuffer> buf;
sp<Fence> acquireFence;
status_t err = nextBuffer(buf, acquireFence);
if (err != NO_ERROR) {
ALOGE("error latching nnext FramebufferSurface buffer: %s (%d)",
strerror(-err), err);
return;
}
err = mHwc.fbPost(mDisplayType, acquireFence, buf);
if (err != NO_ERROR) {
ALOGE("error posting framebuffer: %d", err);
}
}
- 調用mHwc.fbPost提交buffer到HWComposer函數
int HWComposer::fbPost(int32_t id,
const sp<Fence>& acquireFence, const sp<GraphicBuffer>& buffer) {
if (mHwc && hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) {
return setFramebufferTarget(id, acquireFence, buffer);
} else {
acquireFence->waitForever("HWComposer::fbPost");
return mFbDev->post(mFbDev, buffer->handle);
}
}
- 存在硬件合成器時,調用setFramebufferTarget函數將軟件合成的結果提交給硬件合成器去混合圖層輸出
- 不存在硬件合成器時,直接調用mFbDev->post將軟件合成的結果提交到framebuffer進去輸出
在SurfaceFlinger中執行完doDisplayComposition進行圖層處理後會調用postFramebuffer提交圖層到HWComposer中。
void SurfaceFlinger::postFramebuffer()
{
ATRACE_CALL();
......
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();
}
......
}
- 存在HWComposer時調用hwc.commit()提交圖層。
status_t HWComposer::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();
}
}
err = mHwc->set(mHwc, mNumDisplays, mLists);
for (size_t i=0 ; i<mNumDisplays ; i++) {
DisplayData& disp(mDisplayData[i]);
disp.lastDisplayFence = disp.lastRetireFence;
disp.lastRetireFence = Fence::NO_FENCE;
if (disp.list) {
if (disp.list->retireFenceFd != -1) {
disp.lastRetireFence = new Fence(disp.list->retireFenceFd);
disp.list->retireFenceFd = -1;
}
disp.list->flags &= ~HWC_GEOMETRY_CHANGED;
}
}
}
return (status_t)err;
}
- 調用mHwc->set使用硬件對層圖進行合成並輸出到顯示設備
Android SurfaceFlinger服務(八) ----- 圖像的輸出