Discuz! Board

 找回密码
 立即注册
搜索
热搜: 活动 交友 discuz
查看: 44|回复: 44
打印 上一主题 下一主题

Android graphic path

[复制链接]

1198

主题

2060

帖子

7058

积分

超级版主

Rank: 8Rank: 8

积分
7058
跳转到指定楼层
楼主
发表于 2016-4-17 12:02:35 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
UI的画图流程中,先不管怎么填充要画的数据的,只是来看一下需要画到屏幕上的数据是通过怎样的流程最终传递到屏幕上的。这个流程都是UI获取并创建Surface并利用Cavans,Bitmap等画好之后,传递给SurfaceFlinger去Composite并传递给HWComposer去画到屏幕上的。根据Chris Simmonds关于graphic path的说明来具体看一。下http://elinux.org/images/2/2b/Android_graphics_path–chis_simmonds.pdf)。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
回复

使用道具 举报

1198

主题

2060

帖子

7058

积分

超级版主

Rank: 8Rank: 8

积分
7058
沙发
 楼主| 发表于 2016-4-17 12:04:47 | 只看该作者
Inception of a pixel
  • Everything begins when an activity draws to a surface
  • 2D applications can use
    1) drawing functions in Canvas to write to a Bitmap:android.graphics.Canvas.drawRect(), drawText(), etc
    2) descendants of the View class to draw objects such as buttons and lists
    3) a custom View class to implement your own appearance and behaviour
  • In all cases the drawing is rendered to a Surface which contains a GraphicBuffer
SurfaceFlinger binder interfaces

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
回复 支持 反对

使用道具 举报

1198

主题

2060

帖子

7058

积分

超级版主

Rank: 8Rank: 8

积分
7058
板凳
 楼主| 发表于 2016-4-17 12:05:54 | 只看该作者
ISurfaceComposer

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
回复 支持 反对

使用道具 举报

1198

主题

2060

帖子

7058

积分

超级版主

Rank: 8Rank: 8

积分
7058
地板
 楼主| 发表于 2016-4-17 12:07:56 | 只看该作者
ISurfaceComposerClient
IDisplayEventConnection


本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
回复 支持 反对

使用道具 举报

1198

主题

2060

帖子

7058

积分

超级版主

Rank: 8Rank: 8

积分
7058
5#
 楼主| 发表于 2016-4-17 12:09:04 | 只看该作者
一个activity等Client画一个UI的流程如下:
ISurfaceComposer is the interface to talk to SurfaceFlinger, there’re two ways to get ISurfaceComposer interface in Client:
sp<ISurfaceComposer> composer;
composer = ComposerService::getComposerService();
or
getService("SurfaceFlinger", &composer);
回复 支持 反对

使用道具 举报

1198

主题

2060

帖子

7058

积分

超级版主

Rank: 8Rank: 8

积分
7058
6#
 楼主| 发表于 2016-4-17 12:10:24 | 只看该作者
ISurfaceComposerClient is the interface to create Surface. To get ISurfaceComposerClient interface, use the ISurfaceComposer instance returned above:

sp<ISurfaceComposerClient> composerClient = composer->createConnection();
The above two methods can be combined in single step:
sp<SurfaceComposerClient> composerClient = new SurfaceComposerClient;
To operate on Surface, you have to get SurfaceControl first, simply call createSurface on the SurfaceComposerClient instance:
sp<SurfaceControl> surfaceControl = composerClient->createSurface();
And call getSurface on SurfaceControl instance, you can finally get Surface:
sp<Surface> surface = surfaceControl->getSurface();
回复 支持 反对

使用道具 举报

1198

主题

2060

帖子

7058

积分

超级版主

Rank: 8Rank: 8

积分
7058
7#
 楼主| 发表于 2016-4-17 12:12:29 | 只看该作者
status_t Surface::lock(
        ANativeWindow_Buffer* outBuffer, ARect* inOutDirtyBounds)
{
    if (mLockedBuffer != 0) {
        ALOGE("Surface::lock failed, already locked");
        return INVALID_OPERATION;
    }

    if (!mConnectedToCpu) {
        int err = Surface::connect(NATIVE_WINDOW_API_CPU);
        if (err) {
            return err;
        }
        // we're intending to do software rendering from this point
        setUsage(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN);
    }

    ANativeWindowBuffer* out;
    int fenceFd = -1;
    status_t err = dequeueBuffer(&out, &fenceFd);
    ALOGE_IF(err, "dequeueBuffer failed (%s)", strerror(-err));
    if (err == NO_ERROR) {
        sp<GraphicBuffer> backBuffer(GraphicBuffer::getSelf(out));
        const Rect bounds(backBuffer->width, backBuffer->height);

        Region newDirtyRegion;
        if (inOutDirtyBounds) {
            newDirtyRegion.set(static_cast<Rect const&>(*inOutDirtyBounds));
            newDirtyRegion.andSelf(bounds);
        } else {
            newDirtyRegion.set(bounds);
        }

        // figure out if we can copy the frontbuffer back
        const sp<GraphicBuffer>& frontBuffer(mPostedBuffer);
        const bool canCopyBack = (frontBuffer != 0 &&
                backBuffer->width  == frontBuffer->width &&
                backBuffer->height == frontBuffer->height &&
                backBuffer->format == frontBuffer->format);

        if (canCopyBack) {
            // copy the area that is invalid and not repainted this round
            const Region copyback(mDirtyRegion.subtract(newDirtyRegion));
            if (!copyback.isEmpty())
                copyBlt(backBuffer, frontBuffer, copyback);
        } else {
            // if we can't copy-back anything, modify the user's dirty
            // region to make sure they redraw the whole buffer
            newDirtyRegion.set(bounds);
            mDirtyRegion.clear();
            Mutex::Autolock lock(mMutex);
            for (size_t i=0 ; i<NUM_BUFFER_SLOTS ; i++) {
                mSlots[i].dirtyRegion.clear();
            }
        }

        { // scope for the lock
            Mutex::Autolock lock(mMutex);
            int backBufferSlot(getSlotFromBufferLocked(backBuffer.get()));
            if (backBufferSlot >= 0) {
                Region& dirtyRegion(mSlots[backBufferSlot].dirtyRegion);
                mDirtyRegion.subtract(dirtyRegion);
                dirtyRegion = newDirtyRegion;
            }
        }

        mDirtyRegion.orSelf(newDirtyRegion);
        if (inOutDirtyBounds) {
            *inOutDirtyBounds = newDirtyRegion.getBounds();
        }

        void* vaddr;
        status_t res = backBuffer->lockAsync(
                GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN,
                newDirtyRegion.bounds(), &vaddr, fenceFd);

        ALOGW_IF(res, "failed locking buffer (handle = %p)",
                backBuffer->handle);

        if (res != 0) {
            err = INVALID_OPERATION;
        } else {
            mLockedBuffer = backBuffer;
            outBuffer->width  = backBuffer->width;
            outBuffer->height = backBuffer->height;
            outBuffer->stride = backBuffer->stride;
            outBuffer->format = backBuffer->format;
            outBuffer->bits   = vaddr;
        }
    }
    return err;
}
回复 支持 反对

使用道具 举报

1198

主题

2060

帖子

7058

积分

超级版主

Rank: 8Rank: 8

积分
7058
8#
 楼主| 发表于 2016-4-17 12:13:54 | 只看该作者
本帖最后由 zangcf 于 2016-4-17 12:18 编辑

Surface::lock()函数中outBuffer就是backBuffer,是通过GraphicBufferProducer从BufferQueue中获取的空闲buffer。
获取了这个空闲的backBuffer之后就可以往backBuffer中填充数据,并通过queueBuffer发给SurfaceFlinger了(backBuffer是画画用的,frontBuffer是composite用的)。
所以Surface和SurfaceFlinger之间也是一个C/S架构,其桥梁就是BufferQueue。Surface从BufferQueue中获取空闲Buffer填充数据并发给BufferQueue。SurfaceFlinger也是从BufferQueue中获取buffer并画上去。buffer是共享缓冲区,所以会涉及互斥锁,buffer状态也有很多种,一般buffer会大致经过FREE->DEQUEUED->QUEUED->ACQUIRED->FREE这几种流程(状态机参考下面的BufferQueue state diagram)。如下图:





本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
回复 支持 反对

使用道具 举报

1198

主题

2060

帖子

7058

积分

超级版主

Rank: 8Rank: 8

积分
7058
9#
 楼主| 发表于 2016-4-17 12:18:10 | 只看该作者
本帖最后由 zangcf 于 2016-4-17 12:19 编辑

BufferQueue
可以認爲BufferQueue是一個服務中心,其它兩個owner必須要通過它來管理buffer。比如說當producer想要獲取一個buffer時,它不能越過BufferQueue直接與consumer進行聯系,反之亦然。

Producer
生産者就是“填充”buffer空間的人,通常情況下當然就是應用程序。因爲應用程序不斷地刷新UI,從而將産生的顯示數據源源不斷地寫到buffer中。當Producer需要使用一塊buffer時,它首先會向中介BufferQueue發起dequeue申請,然後才能對指定的緩沖區進行操作。這種情況下buffer就屬于producer一個人的了,它可以對buffer進行任何必要的操作,而其它owner此刻絕不能擅自插手。
當生産者認爲一塊buffer已經寫入完成後,它進一步調用BufferQueue的queue。從字面上看這個函數是“入列”的意思,形象地表達了buffer此時的操作——把buffer歸還到BufferQueue的隊列中。一旦queue成功後,owner也就隨之改變爲BufferQueue了

Consumer
消費者是與生産者相對應的,它的操作同樣受到BufferQueue的管控。當一塊buffer已經就緒後,Consumer就可以開始工作了。這裏需要特別留意的是,從各個對象所扮演的角色來看,BufferQueue是中介機構,屬于服務提供方roducer屬于buffer內容的産出方,它對緩沖區的操作是一個“主動”的過程;反之,Consumer對buffer的處理則是“被動”的、“等待式”的——它必須要等到一塊buffer填充完成後才能做工作。在這樣的模型下,我們怎麽保證Consumer可以及時的處理buffer呢?換句話說,當一塊buffer數據ready後,應該怎麽告知Consumer來操作呢?
仔細觀察的話,可以看到BufferQueue裏還同時提供了一個特別的類,名稱爲ProxyConsumerListener,其中的函數接口包括:class ProxyConsumerListener : public BnConsumerListener {   
public:        //省略構造函數        
virtual void onFrameAvailable();        /*當一塊buffer可以被消費時,這個函數會被調用,特別注意此時沒有共享鎖的保護*/        
virtual voidonBuffersReleased();        /*BufferQueue通知consumer它已經釋放其slot中的一個或多個 GraphicBuffer引用*/   
private:            wp<ConsumerListener>mConsumerListener;}

回复 支持 反对

使用道具 举报

1198

主题

2060

帖子

7058

积分

超级版主

Rank: 8Rank: 8

积分
7058
10#
 楼主| 发表于 2016-4-17 12:20:12 | 只看该作者

這樣子就很清楚了,當有一幀數據准備就緒後,BufferQueue就會調用onFrameAvailable()來通知Consumer進行消費。

BufferQueue和SurfaceFlinger之間的通信模式如下:


本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Archiver|手机版|小黑屋|Comsenz Inc.

GMT+8, 2025-12-15 02:03 , Processed in 0.015770 second(s), 8 queries , Apc On.

Powered by Discuz! X3.2

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表