Android 图形系统详解

news2024/11/28 4:39:00

概述

一个页面(Activity)显示到屏幕上主要经过一下几个流程:
启动 Activity → 创建 Window → WMS 注册 Window → SurfaceFlinger 创建 Surface → 合成 layer → 显示
主要涉及三个进程:App进程、System_server进程、SurfaceFlinger进程

  1. App 进程:负责发起 Surface 创建的请求。同时触发对控件的测量、布局、绘制以及输入事件的派发处理,主要在 ViewRootImpl中 触发( AMS 作用是统一调度所有 App 的 Activity )
  2. System_server 进程:主要是 WindowManagerService,负责接收 App 请求,同时和 SurfaceFlinger 建立连接,向 SF 发起具体请求创建 Surface,并且创建 Surace 的辅助管理类 SurfaceControl(与 window 一一对应)
  3. SurfaceFlinger:为 App 创建具体的 Surface,在 SurfaceFlinger 对应 Layer,然后负责管理、合成所有图层,最终显示在屏幕上
    在这里插入图片描述

应用层可通过两种方式将图像绘制到屏幕上:使用 Canvas 或 OpenGL

  • android.graphics.Canvas 是一个 2D 图形 API,从 4.0 开始通过 OpenGLRenderer 的绘制库实现硬件加速,将Canvas 运算转换为 OpenGL 运算,以便它们可以在 GPU 上执行,提升效率
  • OpenGL ES 直接渲染到 Surface ,Android 在 Android.opengl 软件包中提供了 OpenGL ES 接口
    下图是 view 绘制到 display 展示的整体流程,我们主要看左上角虚线框部分,整体分为 App 进程和系统进程两个部分
    在这里插入图片描述

App 进程

概念解释

  • Activity: 一个 Activity 对应创建一个 Surface,每个 Surface 对应 SurfaceFlinger 中的一个 Layer
  • Window:每个 Activity 包含一个 Window 对象(抽象类,提供绘制窗口的通用API),由 PhoneWindow 实现。是 Activity 和整个 View 系统交互的接口。
  • PhoneWindow: 继承于 Window,是 Window 类的具体实现。该类内部包含了一个 DecorView 对象,该对象是所有应用窗口(Activity 界面)的根 View。把一个 FrameLayout 类,即 DecorView 对象进行一定的包装,将他作为应用窗口的根 View,并提供一组通用的窗口操作接口。
  • DecorView:PhoneWindow setContentView 函数中创建,继承 FrameLayout,是所有应用窗口的根 View。
  • WindowManager :继承 ViewManager ,操作 UI 的接口,具备添加、删除和更新View,具体却委托给了WindowsManagerGlobal来进行实现
  • WindowManagerImpl: 实现了 WindowManager,并持有 WindowManagerGlobal 的对象
  • WindowManagerGlobal:单例模式,每个进程只有一个。持有 ViewRootImpl 的对象
  • ViewRootImpl:所有 View 的根,作为 View 与后台各种服务的桥梁。用户输入系统(接收用户按键,触摸屏输入)、窗口系统(复杂窗口的布局,刷新,动画)、显示合成系统(包括定时器Choreograph, SurfaceFlinger)等
  • Surface:app 层用于绘制的对象在这里插入图片描述

流程分析

在这里插入图片描述

源码分析


ActivityThread.java {
    private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
        ......
        activity = mInstrumentation.newActivity(cl, component.getClassName(), r.intent);
        ......
        activity.attach(appContext, this, getInstrumentation(), r.token,
                            r.ident, app, r.intent, r.activityInfo, title, r.parent,
                            r.embeddedID, r.lastNonConfigurationInstances, config,
                            r.referrer, r.voiceInteractor, window, r.activityConfigCallback,
                            r.assistToken, r.shareableActivityToken);
        ......
        mInstrumentation.callActivityOnCreate(activity, r.state);
    }
    
    public void handleResumeActivity(ActivityClientRecord r, boolean finalStateRequest,
                boolean isForward, String reason) {
        ......
        wm.addView(decor, l);
        ......
    }
}

Activity.java {
    private Window mWindow;
    
    final void attach(......){
        ......
        mWindow = new PhoneWindow(this, window, activityConfigCallback);
        ......
        mWindow.setWindowManager(
                (WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
                mToken, mComponent.flattenToString(),
                (info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
        ......
    }
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity);
    }
    public void setContentView(@LayoutRes int layoutResID) {
        getWindow().setContentView(layoutResID);
        initWindowDecorActionBar();
    }
}

Window.java {
    private WindowManager mWindowManager;
    public void setWindowManager(WindowManager wm, IBinder appToken, String appName,
            boolean hardwareAccelerated) {
        ......
        mWindowManager = ((WindowManagerImpl)wm).createLocalWindowManager(this);
        ......
    }
}

PhoneWindow.java {
    private DecorView mDecor;
    public void setContentView(View view, ViewGroup.LayoutParams params) {
        ......
        installDecor();
        ......
    }
    private void installDecor() {
        ......
        mDecor = generateDecor(-1);
        ......
    }
    protected DecorView generateDecor(int featureId) {
        ......
        return new DecorView(context, featureId, this, getAttributes());
    }
}
WindowManagerImpl.java {

    private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();
    
    public WindowManagerImpl createLocalWindowManager(Window parentWindow) {
        return new WindowManagerImpl(mContext, parentWindow, mWindowContextToken);
    }
    public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
        ......
        mGlobal.addView(view, params, mContext.getDisplayNoVerify(), mParentWindow,
                mContext.getUserId());
    }
}
WindowManagerGlobal.java {

    private final ArrayList<ViewRootImpl> mRoots = new ArrayList<ViewRootImpl>();
    
    public void addView(View view, ViewGroup.LayoutParams params,
            Display display, Window parentWindow, int userId) {
        ......
        ViewRootImpl root = new ViewRootImpl(view.getContext(), display);
        ......
        root = new ViewRootImpl(view.getContext(), display);
        ......
        mRoots.add(root);
        ......
        root.setView(view, wparams, panelParentView, userId);
        ......
    }
}

ViewRootImpl.java {

    View mView;//DecorView
    
    public final Surface mSurface = new Surface();
    private final SurfaceControl mSurfaceControl = new SurfaceControl();
    
    // 接收显示系统的时间脉冲(垂直同步信号- VSync 信号)
    // 同 Vsync 机制配合,控制同步处理输入(Input)、动画(Animation)、绘制(Draw)三个UI操作
    final Choreographer mChoreographer;
    
    public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView,
            int userId) {
        ......
        mView = view;
        ......
        mWindowSession.addToDisplayAsUser()
        ......
        requestLayout();
        ......
    }
    public void requestLayout() {
        ......
        scheduleTraversals();
        ......
    }
    
    final class TraversalRunnable implements Runnable {
        @Override
        public void run() {
            doTraversal();
        }
    }
    final TraversalRunnable mTraversalRunnable = new TraversalRunnable();
    
    void scheduleTraversals() {
        ......
        mChoreographer.postCallback(
                    Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
        ......
    }
    void doTraversal() {
        ......
        performTraversals();
        ......
    }
    private void performTraversals() {
        ......
        performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
        ......
        performLayout(lp, mWidth, mHeight);
        ......
        performDraw()
        ......
    }
    private boolean performDraw() {
        ......
        draw(fullRedrawNeeded, usingAsyncReport && mSyncBuffer);
        ......
    }
    private boolean draw(boolean fullRedrawNeeded, boolean forceDraw) {
        ......
        drawSoftware(surface, mAttachInfo, xOffset, yOffset,
                        scalingRequired, dirty, surfaceInsets);
        ......
    }
    private boolean drawSoftware(Surface surface, AttachInfo attachInfo, int xoff, int yoff,
            boolean scalingRequired, Rect dirty, Rect surfaceInsets) {
        ......
        canvas = mSurface.lockCanvas(dirty);
        ......
        //DecorView
        mView.draw(canvas);
        ......
        surface.unlockCanvasAndPost(canvas);
    }
}

System 进程

概念解释

  • WindowToken:将同一应用组件(Activity、InputMethod、Wallpaper或者Dream)的窗口组织到一起

  • WindowState:表示一个窗口的所有属性,是 WMS 事实上的窗口
    在这里插入图片描述

  • WindowManagerService:为所有窗口分配 Surface、负责 Surface 的显示顺序(Z序)以及大小尺寸、控制窗口动画,并且还是输入系统的中转站

  • Surface:native 层用于处理窗口的大小位置裁剪等操作

  • SurfaceComposerClient:与 SurfaceFlinger 进行通信,代理对象 mClient,对应 SurfaceFlinger 的 Binder 本地 Client 对象

  • SurfaceControl: app 层 surface 向 native 层提交的 buffer 的控制逻辑

  • BufferQueue:数据的生产者(Surface、BufferQueueProducer)与消费者 (SurfaceFlinger、BufferQueueConsumer)

  • Layer:SurfaceFlinger 进行合成的基本操作单元,当应用创建 Surface 的时候在 SurfaceFlinger 内部创建Layer,因此一个 Surface 对应一个 Layer。

  • SurfaceFlinger:运行在独立进程的 Service, 接收所有 Window 的 Surface 作为输入,根据 Z-Order, 透明度,大小,位置等参数,计算出每个 Surface 在最终合成图像中的位置,然后交由 HWComposer 或 OpenGL 生成最终的显示 Buffer, 然后显示到设备上

对应关系:
Activity -> Window -> DecorView -> ViewRootImpl -> WindowState -> Surface -> Layer 是一一对应的。
在这里插入图片描述

流程分析

在这里插入图片描述

源码分析

SurfaceFlinger 启动

main_surfaceflinger.cpp {
    int main(int, char**) {
        ......
        sp<SurfaceFlinger> flinger = surfaceflinger::createSurfaceFlinger();
        ......
        flinger->init();
        ......
        // publish surface flinger
        sp<IServiceManager> sm(defaultServiceManager());
        sm->addService(String16(SurfaceFlinger::getServiceName()), flinger, false,
                   IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL | IServiceManager::DUMP_FLAG_PROTO);
        ......
        // run surface flinger in this thread
        flinger->run();
    }
}
SurfaceFlinger.cpp {
    void SurfaceFlinger::onFirstRef() {
        ......
        mEventQueue.init(this);
        ......
    }
    void SurfaceFlinger::init(){
        ......
        // 初始化OpenGL 图形库相关配置
        mEGLDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
        ......
        // 创建显示设备的抽象代表,负责和显示设备打交道
        mHwc = new HWComposer(this, *static_cast<HWComposer::EventHandler *>(this));
        ......
        // app的VSync信号,也就是Systrace中的VSync-app,它最终是发往到choreographer,
        // 主要处理三件事情INPUT、ANIMATION、TRAVERSAL
        // start the EventThread
        sp<VSyncSource> vsyncSrc = new DispSyncSource(&mPrimaryDispSync, vsyncPhaseOffsetNs, true, "app");
        mEventThread = new EventThread(vsyncSrc);
        ......
    }
    void SurfaceFlinger::run() {
        do {
            //运行线程,等待数据
            waitForEvent();
        } while (true);
    }
    void SurfaceFlinger::waitForEvent() {
        mEventQueue.waitMessage();
    }
    // 发送数据
    status_t SurfaceFlinger::postMessageSync(const sp<MessageBase>& msg,
        nsecs_t reltime, uint32_t /* flags */) {
        status_t res = mEventQueue.postMessage(msg, reltime);
        if (res == NO_ERROR) {
            msg->wait();
        }
        return res;
    }
}
MessageQueue.cpp {
    void MessageQueue::init(const sp<SurfaceFlinger>& flinger) {
        mFlinger = flinger;
        mLooper = new Looper(true);
        mHandler = new Handler(*this);
    }
    
    status_t MessageQueue::postMessage(const sp<MessageBase>& messageHandler, nsecs_t relTime) {
        const Message dummyMessage;
        if (relTime > 0) {
            mLooper->sendMessageDelayed(relTime, messageHandler, dummyMessage);
        } else {
            mLooper->sendMessage(messageHandler, dummyMessage);
        }
        return NO_ERROR;
    }
}

创建 Native 层 Surface 以及 SurfaceFlinger 的 Layer

android_view_Surface.cpp {
    static jlong nativeGetFromSurfaceControl(JNIEnv* env, jclass clazz, jlong nativeObject, jlong surfaceControlNativeObj) {
        Surface* self(reinterpret_cast<Surface *>(nativeObject));
        sp<SurfaceControl> ctrl(reinterpret_cast<SurfaceControl *>(surfaceControlNativeObj));
        // If the underlying IGBP's are the same, we don't need to do anything.
        if (self != nullptr &&
                IInterface::asBinder(self->getIGraphicBufferProducer()) ==
                IInterface::asBinder(ctrl->getIGraphicBufferProducer())) {
            return nativeObject;
        }
        sp<Surface> surface(ctrl->getSurface());
        if (surface != NULL) {
            surface->incStrong(&sRefBaseOwner);
        }
        return reinterpret_cast<jlong>(surface.get());
    }
}
SurfaceControl.cpp {

    sp<SurfaceComposerClient>   mClient;
    
    sp<Surface> SurfaceControl::getSurface() {
        Mutex::Autolock _l(mLock);
        if (mSurfaceData == nullptr) {
            return generateSurfaceLocked();
        }
        return mSurfaceData;
    }
    
    sp<Surface> SurfaceControl::generateSurfaceLocked() {
        ......
        mBbqChild = mClient->createSurface(String8("bbq-wrapper"), 0, 0, mFormat,
                                           flags, mHandle, {}, &ignore);
        // 当 buffer 入队后会回调 BLASTBufferQueue 的 onFrameAvailable
        mBbq = sp<BLASTBufferQueue>::make("bbq-adapter", mBbqChild, mWidth, mHeight, mFormat);
        // This surface is always consumed by SurfaceFlinger, so the
        // producerControlledByApp value doesn't matter; using false.
        mSurfaceData = mBbq->getSurface(true);
        return mSurfaceData;
    }
}

SurfaceComposerClient.cpp {
    
    sp<ISurfaceComposerClient>  mClient;
    
    sp<SurfaceControl> SurfaceComposerClient::createSurface(const String8& name, DisplayID display,uint32_t w, uint32_t h, PixelFormat format, uint32_t flags) {
        sp<SurfaceControl> result;
        if (mStatus == NO_ERROR) {
            ISurfaceComposerClient::surface_data_t data;
            sp<ISurface> surface = mClient->createSurface(&data, name, display, w, h, format, flags);
            if (surface != 0) {
                result = new SurfaceControl(this, surface, data);
            }
        }
        return result;
    }
}
Client.cpp {
    status_t Client::createSurface( const String8& name, uint32_t w, uint32_t h, PixelFormat format, uint32_t flags,
        sp<IBinder>* handle, sp<IGraphicBufferProducer>* gbp) {
        ......
        class MessageCreateLayer : public MessageBase {
            virtual bool handler() {
                //最后会执行这里 createLayer
                result = flinger->createLayer(name, client, w, h, format, flags,
                        handle, gbp);
                return true;
            }
        }
        sp<MessageBase> msg = new MessageCreateLayer(mFlinger.get(),
                name, this, w, h, format, flags, handle, gbp);
        //这个mFlinger 就是SurfaceFlinger对象
        mFlinger->postMessageSync(msg);
        return static_cast<MessageCreateLayer*>( msg.get() )->getResult();
    }
}
SurfaceFlinger.cpp {
    status_t SurfaceFlinger::createLayer( const String8& name, const sp<Client>& client, uint32_t w, uint32_t h, PixelFormat format, uint32_t flags,sp<IBinder>* handle, sp<IGraphicBufferProducer>* gbp) {
        ......
        sp<Layer> layer;
        ......
        result = createNormalLayer(client, name, w, h, flags, format, handle, gbp, &layer);
        ......
        addClientLayer(client, *handle, *gbp, layer);
        ......
        return result;
    }
    status_t SurfaceFlinger::createNormalLayer(const sp<Client>& client,
        const String8& name, uint32_t w, uint32_t h, uint32_t flags, PixelFormat& format,
        sp<IBinder>* handle, sp<IGraphicBufferProducer>* gbp, sp<Layer>* outLayer){
        ......
        *outLayer = new Layer(this, client, name, w, h, flags);
        ......
        status_t err = (*outLayer)->setBuffers(w, h, format, flags);
        if (err == NO_ERROR) {
            *handle = (*outLayer)->getHandle();
            *gbp = (*outLayer)->getProducer();
        }
        ......
        return err;
    }
}
Layer.cpp {
    void Layer::onFirstRef() {
        // Creates a custom BufferQueue for SurfaceFlingerConsumer to use
        //创建了生产者和消费者缓冲区,这两个缓冲区将来会存放UI的内容数据
        sp<IGraphicBufferProducer> producer;
        sp<IGraphicBufferConsumer> consumer;
        ......
        BufferQueue::createBufferQueue(&producer, &consumer);
        mProducer = new MonitoredProducer(producer, mFlinger);
        mSurfaceFlingerConsumer = new SurfaceFlingerConsumer(consumer, mTextureName);
        ......
        // 这里设置使用 双缓存 还是 三重缓存
        #ifdef TARGET_DISABLE_TRIPLE_BUFFERING
        #warning "disabling triple buffering"
            mSurfaceFlingerConsumer->setDefaultMaxBufferCount(2);
        #else
            mSurfaceFlingerConsumer->setDefaultMaxBufferCount(3);
        #endif
        ......
    }
}

绘制

ViewRootImpl.java {
    private boolean drawSoftware(Surface surface, AttachInfo attachInfo, int xoff, int yoff,
            boolean scalingRequired, Rect dirty, Rect surfaceInsets) {
        ......
        canvas = mSurface.lockCanvas(dirty);
        ......
        mView.draw(canvas);
        ......
        surface.unlockCanvasAndPost(canvas);
        ......
    }
}

android_view_Surface.cpp {
    static jlong nativeLockCanvas(JNIEnv* env, jclass clazz, jlong nativeObject, jobject canvasObj, jobject dirtyRectObj) {
        sp<Surface> surface(reinterpret_cast<Surface *>(nativeObject));
        ......
        ANativeWindow_Buffer buffer;
        //申请图形 buffer
        status_t err = surface->lock(&buffer, dirtyRectPtr);
        ......
        graphics::Canvas canvas(env, canvasObj);
        canvas.setBuffer(&buffer, static_cast<int32_t>(surface->getBuffersDataSpace()));
        ......
        sp<Surface> lockedSurface(surface);
        lockedSurface->incStrong(&sRefBaseOwner);
        return (jlong) lockedSurface.get();
    }
    static void nativeUnlockCanvasAndPost(JNIEnv* env, jclass clazz, jlong nativeObject, jobject canvasObj) {
        sp<Surface> surface(reinterpret_cast<Surface *>(nativeObject));
        ......
        status_t err = surface->unlockAndPost();
        ......
    }
}
Surface.cpp {

    sp<IGraphicBufferProducer> mGraphicBufferProducer;
    
    status_t Surface::lock(ANativeWindow_Buffer* outBuffer, ARect* inOutDirtyBounds) {
        ......
        status_t err = dequeueBuffer(&out, &fenceFd);
        ......
        if (err == NO_ERROR) {
            ......
            sp<GraphicBuffer> backBuffer(GraphicBuffer::getSelf(out));
            const Rect bounds(backBuffer->width, backBuffer->height);
            ......
        }
    }
    int Surface::dequeueBuffer(android_native_buffer_t** buffer, int* fenceFd) {
        ......
        status_t result = mGraphicBufferProducer->dequeueBuffer(&buf, &fence, dqInput.width,
                                dqInput.height, dqInput.format,dqInput.usage, &mBufferAge,
                                dqInput.getTimestamps ? &frameTimestamps : nullptr);
        ......
    }
    
    status_t Surface::unlockAndPost() {
        ......
        status_t err = mLockedBuffer->unlockAsync(&fd);
        ......
        err = queueBuffer(mLockedBuffer.get(), fd);
        ......
        return err;
    }
    int Surface::queueBuffer(android_native_buffer_t* buffer, int fenceFd) {
        ......
        int i = getSlotFromBufferLocked(buffer);
        ......
        status_t err = mGraphicBufferProducer->queueBuffer(i, input, &output);
        ......
        onBufferQueuedLocked(i, fence, output);
        return err;
    }
}
BufferQueueProducer.cpp {
    status_t BufferQueueProducer::dequeueBuffer(int* outSlot, sp<android::Fence>* outFence,
                                            uint32_t width, uint32_t height, PixelFormat format,
                                            uint64_t usage, uint64_t* outBufferAge,
                                            FrameEventHistoryDelta* outTimestamps) {
        ......
        std::unique_lock<std::mutex> lock(mCore->mMutex);
        ......
        int found = BufferItem::INVALID_BUFFER_SLOT;
        while (found == BufferItem::INVALID_BUFFER_SLOT) {
            //从队列中取出一块已经 releas 的 buffer
            status_t status = waitForFreeSlotThenRelock(FreeSlotCaller::Dequeue, lock, &found);
            if (status != NO_ERROR) {
                return status;
            }
            ......
        }
    }
    status_t BufferQueueProducer::waitForFreeSlotThenRelock(FreeSlotCaller caller,
        std::unique_lock<std::mutex>& lock, int* found) const {
        ......
        *found = getFreeBufferLocked();
        ......
    }
    int BufferQueueProducer::getFreeBufferLocked() const {
        if (mCore->mFreeBuffers.empty()) {
            return BufferQueueCore::INVALID_BUFFER_SLOT;
        }
        int slot = mCore->mFreeBuffers.front();
        mCore->mFreeBuffers.pop_front();
        return slot;
    }
    
    status_t BufferQueueProducer::queueBuffer(int slot,
        const QueueBufferInput &input, QueueBufferOutput *output) {
        ......
        const sp<GraphicBuffer>& graphicBuffer(mSlots[slot].mGraphicBuffer);
        Rect bufferRect(graphicBuffer->getWidth(), graphicBuffer->getHeight());
        Rect croppedRect(Rect::EMPTY_RECT);
        crop.intersect(bufferRect, &croppedRect);
        ......
        mSlots[slot].mFence = acquireFence;
        mSlots[slot].mBufferState.queue();
        ......
        BufferItem item;
        // 相关数据封装成 BufferItem 并入队
        item.mGraphicBuffer = mSlots[slot].mGraphicBuffer;
        ......
        mCore->mQueue.push_back(item);
        ......
        //取出 BufferQueueCore 的回调接口,下面调用这个接口的onFrameAvailable 函数,来通知SurfaceFlinger 进行渲染
        frameAvailableListener = mCore->mConsumerListener;
        ......
        // 回调 BLASTBufferQueue 的 onFrameAvailable
        frameAvailableListener->onFrameAvailable(item);

    }
}
BLASTBufferQueue.cpp {
    void BLASTBufferQueue::onFrameAvailable(const BufferItem& item) {
        ......
        SurfaceComposerClient::Transaction* prevTransaction = nullptr;
        ......
        if (syncTransactionSet) {
            acquireNextBufferLocked(mSyncTransaction);
            // Only need a commit callback when syncing to ensure the buffer that's synced has been
            // sent to SF
            mSyncTransaction->addTransactionCommittedCallback(transactionCommittedCallbackThunk,
                                                              static_cast<void*>(this));
            ......
            if (mAcquireSingleBuffer) {
                prevCallback = mTransactionReadyCallback;
                prevTransaction = mSyncTransaction;
                ......
            }
        }
        if (prevCallback) {
            prevCallback(prevTransaction);
        }
    }
    void BLASTBufferQueue::acquireNextBufferLocked(const std::optional<SurfaceComposerClient::Transaction*> transaction){
        ......
        status_t status = mBufferItemConsumer->acquireBuffer(&bufferItem, 0 , false);
        ......
        t = *transaction;
        ......
        //将提交的 buffer 设置给 SurfaceComposerClient 去进行合成显示
        t->setBuffer(mSurfaceControl, buffer, fence, bufferItem.mFrameNumber, releaseBufferCallback);
        ......
        mergePendingTransactions(t, bufferItem.mFrameNumber);
        ......
    }
}
BufferQueueConsumer.cpp {
    status_t BufferQueueConsumer::acquireBuffer(BufferItem* outBuffer,
        nsecs_t expectedPresent, uint64_t maxFrameNumber) {
        while (mCore->mQueue.size() > 1 && !mCore->mQueue[0].mIsAutoTimestamp) {
            ......
            const BufferItem& bufferItem(mCore->mQueue[1]);
            ......
        }
        ......
        //填充相关数据
        outBuffer->mGraphicBuffer = mSlots[slot].mGraphicBuffer;
        ......
        //通知消费者该buffer可以重新使用了
        listener->onBufferReleased();
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/331588.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

常用的硬件端口中各个引脚代表的含义(持续更新)

常见接口 参考&#xff1a;https://blog.csdn.net/qlexcel/article/details/117429653 type-c 示意图 参考&#xff1a;https://blog.csdn.net/qlexcel/article/details/117431413&#xff0c;https://blog.csdn.net/HandsomeHong/article/details/119823915&#xff…

Hystrix容错组件

Hystrix简介Hystrix,英文意思是豪猪&#xff0c;全身是刺&#xff0c;看起来就不好惹&#xff0c;是一种保护机制。它是容错组件&#xff0c;Hystrix也是Netflix公司的一款组件。那么Hystix的作用是什么呢&#xff1f;具体要保护什么呢&#xff1f;Hystix是Netflix开源的一个延…

基于WebGl的智慧校园Web3D管理系统

学校是社会进步与学生成才的重要载体。随着信息化趋势的不断加强&#xff0c;构建"智慧型"校园&#xff0c;继续加强把学校作为主体的教育信息化进程&#xff0c;是教育信息化的主要构成部分。今天给大家分享一个基于 数维图 的 Sovit3D编辑器 构建的学校3D可视化场景…

BIM技巧 | Revit绘制围栏12步骤

首先简单介绍一下revit中的栏杆其实是有三部分的族组成&#xff0c;分别是&#xff1a;支柱&#xff0c;扶栏结构&#xff0c;栏杆。 所以要灵活的运用栏杆命令绘制需要的构造&#xff0c;最少要新建三个族。 第一步&#xff1a;绘制支柱族 用“公制栏杆-支柱”族样板绘制围墙…

【GD32F427开发板试用】二、USB库移植与双USB CDC-ACM功能开发

本篇文章来自极术社区与兆易创新组织的GD32F427开发板评测活动&#xff0c;更多开发板试用活动请关注极术社区网站。作者&#xff1a;chenjie 【GD32F427开发板试用】一、环境搭建与freertos移植 【GD32F427开发板试用】二、USB库移植与双USB CDC-ACM功能开发 【GD32F427开发板…

SSM之前回顾

1、技术栈总览 学习要搞清楚你的目标&#xff1b;先学C/JAVA&#xff1b;搞程序不要太浮躁&#xff1b; java基础&#xff1a;计算机基础、写博客、java基础语法、流程控制和方法、数组、面向对象、异常、常用类、集合框架、IO、多线程、GUI、网络编程、注解与反射、JUC编程、…

操作符详解(上篇)

前言小伙伴们大家好&#xff0c;随着对c的不断学习今天我们将来学习操作符。在初始c语言中也介绍过操作符但也只是点到即可&#xff0c;今天我们将详细了解操作符。操作符分类&#xff1a;算术操作符移位操作符位操作符赋值操作符单目操作符关系操作符逻辑操作符条件操作符逗号…

不用自己排版设计的海报设计工具!在线海量模板!

人才招聘旺季&#xff0c;如何再众多的招聘海报中脱颖而出&#xff0c;招聘到心意人才呢&#xff1f;HR要如何排版设计招聘海报呢&#xff1f;只需跟着小编下面的乔拓云工具使用教程&#xff0c;不仅能帮你解决海报设计文案灵感和排版灵感&#xff0c;还不需要任何设计基础就能…

15.面向对象程序设计

文章目录面向对象程序设计15.1OOP&#xff1a;概述继承动态绑定15.2定义基类和派生类15.2.1定义基类成员函数与继承访问控制与继承15.2.2定义派生类派生类对象及派生类向基类的类型转换派生类构造函数派生类使用基类的成员继承与静态成员派生类的声明被用作基类的类防止继承的发…

【虹科公告】好消息!云展厅开放时间长达1年,2023年不限次云观展

云展厅开放通知 2023年&#xff0c;【虹科赋能汽车智能化云展厅】将持续开放&#xff0c;开放时间长达一年&#xff0c;开放期内&#xff0c;均可进入观展&#xff0c;没有次数及观看时长限制&#xff0c;欢迎大家随时进入云展厅观展。 虹科赋能汽车智能化云展厅 聚焦前沿技…

【手撕面试题】HTML+CSS(高频知识点五)

目录 面试官&#xff1a;css 如何实现左侧固定 300px&#xff0c;右侧自适应的布局&#xff1f; 面试官&#xff1a;flex 布局中 align-content 与 align-items 有何区别&#xff1f; 面试官&#xff1a;Grid 布局的优势在哪里&#xff1f; 面试官&#xff1a;Flex 布局中的…

【1797. 设计一个验证系统】

来源&#xff1a;力扣&#xff08;LeetCode&#xff09; 描述&#xff1a; 你需要设计一个包含验证码的验证系统。每一次验证中&#xff0c;用户会收到一个新的验证码&#xff0c;这个验证码在 currentTime 时刻之后 timeToLive 秒过期。如果验证码被更新了&#xff0c;那么它…

游戏多开的分析与实现

大部分游戏为了防止工作室通过多开游戏牟利&#xff0c;都会采取各种手段来防止游戏被多次打开。检测窗口标题&#xff0c;创建互斥体&#xff0c;创建内存映射这些都是防止游戏多开的常用手段。 主要内容 游戏运行后&#xff0c;无非执行两步操作 若已经存在&#xff0c;退出…

【问题代码】顺序点的深入理解(汇编剖析+手画图解)

这好像是一个哲学问题。 目录 前言 一、顺序点是什么&#xff1f; 二、发生有关顺序点的问题代码 vs中&#xff1a; gcc中&#xff1a; 三、细读汇编 1.vs汇编如下&#xff08;示例&#xff09;&#xff1a; 2.gcc汇编如下&#xff08;示例&#xff09;&#xff1a; 四…

R语言raster包遍历多个文件夹并批量计算每一个文件夹下全部遥感影像的平均值

本文介绍基于R语言中的raster包&#xff0c;遍历读取多个文件夹下的多张栅格遥感影像&#xff0c;分别批量对每一个文件夹中的多个栅格图像计算平均值&#xff0c;并将所得各个结果栅格分别加以保存的方法。 其中&#xff0c;本文是用R语言来进行操作的&#xff1b;如果希望基于…

每天10个前端小知识 【Day 9】

前端面试基础知识题 1. bind、call、apply 有什么区别&#xff1f;如何实现一个bind? apply、call、bind三者的区别在于&#xff1a; 三者都可以改变函数的this对象指向三者第一个参数都是this要指向的对象&#xff0c;如果如果没有这个参数或参数为undefined或null&#x…

智能硬件的工作原理与发展定位

一、硬件概述 智能硬件是以平台性底层软硬件为基础&#xff0c;以智能传感互联、人机交互、新型显示及大数据处理等新一代信息技术为特征&#xff0c;以新设计、新材料、新工艺硬件为载体的新型智能终端产品及服务。 与传统硬件相比&#xff0c;智能硬件相比传统硬件&#xf…

【LeetCode每日一题】【2023/2/9】1797. 设计一个验证系统

文章目录1797. 设计一个验证系统方法1&#xff1a;哈希表代码总体1797. 设计一个验证系统 LeetCode: 1797. 设计一个验证系统 中等\color{#FFB800}{中等}中等 你需要设计一个包含验证码的验证系统。每一次验证中&#xff0c;用户会收到一个新的验证码&#xff0c;这个验证码在…

java 线程池

线程池概念 线程池可以看做是一个池子&#xff0c;在这个池子中存储了很多线程&#xff0c;线程池也可以说是一个复用线程的技术。 线程池存在的意义 系统创建一个线程的成本是比较高的&#xff0c;因为它涉及到与操作系统交互&#xff0c;当程序中需要创建大量生存期很短暂的线…

ChatGPT edge/chrome浏览器离线安装

最近chatgpt又热了起来&#xff0c;数据显示很多朋友过来下载浏览器插件&#xff0c;由于大家无法直接访问谷歌应用市场&#xff0c;因此提供一个离线安装的方式。 火热程度 对于大多资本与巨头来说&#xff0c;入局ChatGPT赛道&#xff0c;看中的无疑是ChatGPT概念背后的…