软件绘制源码流程分析

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了软件绘制源码流程分析相关的知识,希望对你有一定的参考价值。

Surface.lockCanvas

大致流程:

// 得到c层的 surface 对象    
sp<Surface> surface(reinterpret_cast<Surface *>(nativeObject));
//声明 buffer
ANativeWindow_Buffer buffer;
// 获取GraphicBuffer 
status_t err = surface->lock(&buffer, dirtyRectPtr);

// 创建 c层的SkiaCanvas对象,并且与java层的绑定
graphics::Canvas canvas(env, canvasObj);
// 设置buffer绑定到ANativeWindow_Buffer的bits结构中
canvas.setBuffer(&buffer, static_cast<int32_t>(surface->getBuffersDataSpace()));

Surface.lock

lock方法中 首先声明NativeWindowBuffer对象,然后调用dequeBuffe获取到ANativeWindwoBuffer对象接着请求SF真正创建GraphBuffer对象并返回NativeWindowBuffer

 // 声明 ANativeWindowBuffer 对象
    ANativeWindowBuffer* out;
    
    //1  调用dequeueBuffer获取 ANativeWindowBuffer 对象
    status_t err = dequeueBuffer(&out, &fenceFd);
    // 2 创建GraphicBuffer 对象
    sp<GraphicBuffer> backBuffer(GraphicBuffer::getSelf(out));
    //3.返回dequeueBuffer获取的ANativeWindowBuffer 对象
    return err;

请求SF进程获取GraphBuffer

c层的surface对象调用lock方法传入ANatieWindow_Buffer,这块Buffer记录着lock方法返回的GraphBuffer绘制内存地址,绘制区域大小坐标等信息, ANatieWindow_Buffer内部变量bits用于之后和SkiaCanvas绑定用于直接渲染。

dequeneBuffer

// 从共享的位置mSharedBufferSlot,拿出GraphicBuffer
sp<GraphicBuffer>& gbuf(mSlots[mSharedBufferSlot].buffer);
int buf = -1; //mSlots中对应的下标,需下一步 dequeneSF进程分配

// 跨进程 从SF进程的mSlots数组(BufferQueue)中分配一块 GraphicBuffer
    status_t result = mGraphicBufferProducer->dequeueBuffer(
    &buf, &fence, dqInput.width,
    dqInput.height, dqInput.format,
    dqInput.usage, &mBufferAge,
    dqInput.getTimestamps ?
     &frameTimestamps : nullptr);
// 得到GraphicBuffer
sp<GraphicBuffer>& gbuf(mSlots[buf].buffer);
//请求 buffer
result = mGraphicBufferProducer->requestBuffer(buf, &gbuf);

请求SF进程返回一个下标对应Slots中的位置,Slots才是SF中真正的GraphBuffer。然后把这个slot位置发送给SF返回真正可以用的Buffer空间,但是此时还并没有分配内存;当调用GraphBufferProducer对象的requestBuffer方法时将SF返回的那块SF中slots内存空间和对应的下标slot传入参数调用时 就可以真正的请求分配对应mSlot位置的GraphBuffer内存空间。

获取canvas

创建canvas对象,canvas的构造方法中表示native层没有bitamp不占内存,空画布,然后调用createCanvas方法返回来一个SkiaCanvas对象,内部通过SKiaBitmap承载绘制内容

  //获取SkiaBitmap绑定到上面ANativeWindowBuffer中的bits属性中
  if (surface.get() != nullptr) 
        if (outBitmap) 
            outBitmap->setInfo(imageInfo, rowBytes);
            
            // 关键: 将bits指针设置给SKBitmap
            outBitmap->setPixels(buffer->bits);
        
        return true;

绑定SkiaBitmap到Buffer中的bits属性

Skiavas对象的mCanvas获取到SKBitmap对象然后和ANativeWindowBuffer的bits指针绑定,也就是SKBitmap指向了分配好的内存空间

unLockAndPost

 // 设置一个空的bitmap,释放canvas的画布SKBitmap。也就是说此时SKBitmap不在引用到buffer了。
 nativeCanvas->setBitmap(SkBitmap());
status_t err = mLockedBuffer->unlockAsync(&fd); //解除buffer的绑定
 // 加入队列 
err = queueBuffer(mLockedBuffer.get(), fd);
  • 清空Canvas的 SKBitmap画布,解除与buffer的引用。
  • 解除surface的buffer与 SF进程的GraphicBuffer的绑定。
  • 将SF的GraphicBuffer入队BufferQueue,请求下一个vsync信号,通知SF来进行合成消费。

以上是关于软件绘制源码流程分析的主要内容,如果未能解决你的问题,请参考以下文章

Android视图View绘制流程与源码分析(全)

Android应用层View绘制流程与源码分析

源码分析Android中View的绘制流程

源码分析Android中View的绘制流程

Flutter 绘制动机 VSYNC 流程源码全方位分析

Android绘制源码分析(下)