码迷,mamicode.com
首页 > 移动开发 > 详细

Android SurfaceFlinger服务(八) ----- 图像的输出

时间:2018-07-24 11:53:01      阅读:289      评论:0      收藏:0      [点我收藏+]

标签:没有   format   efault   phi   connected   RoCE   bre   com   comm   

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服务(八) ----- 图像的输出

标签:没有   format   efault   phi   connected   RoCE   bre   com   comm   

原文地址:https://www.cnblogs.com/qzhang1535/p/9359056.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!