关于Android下gralloc,hwcompoer以及surface模块的重新认识

关于Android下gralloc,hwcompoer以及surface模块的重新认识



引言

欠债还钱天经地义,知识的债也是如此!这不必须得将我前面欠下来的债给补上!对于任何复杂的知识点,我们都可以采用庖丁解牛的学习方式,一步步的分解。将知识由大到小吃透。虽说Android的graphics图形栈是一个非常负责的模块,但是完事开头难,我们先从基本面入手!



一. allocator service的实现

这里我只能无力的吐糟下Android为了所谓的system,vendor隔离,搞了一个HIDL,这可苦了我们这些搞Android的。这里我以最简单的alloctaor 2.0来作为参考,简单介绍其实现!


1.1 . allocator 2.0 service代码结构

这个比较简单,我们直接上代码!

//hardware/interfaces/graphics/allocator/2.0
├── Android.bp
├── default
│   ├── Android.bp
│   ├── android.hardware.graphics.allocator@2.0-service.rc
│   ├── OWNERS
│   ├── passthrough.cpp
│   └── service.cpp
├── IAllocator.hal
└── utils├── gralloc1-adapter│   ├── Android.bp│   ├── gralloc1-adapter.cpp│   ├── gralloc1-adapter.h│   ├── Gralloc1On0Adapter.cpp│   └── Gralloc1On0Adapter.h├── hal│   ├── Android.bp│   └── include│       └── allocator-hal│           └── 2.0│               ├── Allocator.h│               └── AllocatorHal.h├── OWNERS└── passthrough├── Android.bp└── include└── allocator-passthrough└── 2.0├── Gralloc0Hal.h├── Gralloc1Hal.h└── GrallocLoader.h11 directories, 20 files

1.2 allocator 2.0 service passthrough方式的实现

这里我们不对细节,做过多的纠缠,我们只梳理其大体框架!


/*** The id of this module*/
#define GRALLOC_HARDWARE_MODULE_ID "gralloc"
/*** Name of the graphics device to open*/#define GRALLOC_HARDWARE_GPU0 "gpu0"//[passthrough.cpp]
HIDL_FETCH_IAllocator(...)GrallocLoader::load()   //GrallocLoader.hloadModule()//核心是这个,加载HAL MODLEhw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module)createHal(module)//这里无论是Gralloc1Hal还是Gralloc0Hal最终都会调用 gralloc_open(module, &mDevice)gralloc_open(module, &mDevice)module->methods->open(module, GRALLOC_HARDWARE_GPU0, TO_HW_DEVICE_T_OPEN(device)) //注意这里传递的id为GRALLOC_HARDWARE_GPU0createAllocator(std::move(hal))

这里我们重点需要关心的是,这里hw_get_modul传递的id是GRALLOC_HARDWARE_MODULE_ID!


1.3 allocator HAL的实现

通过前面分析可知,hw_get_module会加载HAL模块,这里我们以Android默认的gralloc实现来说明:

//[hardware/libhardware/modules/gralloc]├── Android.mk
├── framebuffer.cpp
├── gralloc.cpp
├── gralloc_priv.h
├── gr.h
└── mapper.cppstruct private_module_t HAL_MODULE_INFO_SYM = {.base = {.common = {.tag = HARDWARE_MODULE_TAG,.version_major = 1,.version_minor = 0,.id = GRALLOC_HARDWARE_MODULE_ID,//注意这里的ID.name = "Graphics Memory Allocator Module",.author = "The Android Open Source Project",.methods = &gralloc_module_methods},.registerBuffer = gralloc_register_buffer,.unregisterBuffer = gralloc_unregister_buffer,.lock = gralloc_lock,.unlock = gralloc_unlock,},.framebuffer = 0,.flags = 0,.numBuffers = 0,.bufferMask = 0,.lock = PTHREAD_MUTEX_INITIALIZER,.currentBuffer = 0,
};int gralloc_device_open(const hw_module_t* module, const char* name,hw_device_t** device)
{int status = -EINVAL;if (!strcmp(name, GRALLOC_HARDWARE_GPU0)) {//allocator的gralloc加载会走次分支gralloc_context_t *dev;dev = (gralloc_context_t*)malloc(sizeof(*dev));/* initialize our state here */memset(dev, 0, sizeof(*dev));/* initialize the procs */dev->device.common.tag = HARDWARE_DEVICE_TAG;dev->device.common.version = 0;dev->device.common.module = const_cast<hw_module_t*>(module);dev->device.common.close = gralloc_close;dev->device.alloc   = gralloc_alloc;dev->device.free    = gralloc_free;*device = &dev->device.common;status = 0;} else {status = fb_device_open(module, name, device);}return status;
}

这里需要注意的是,此时allocator service调用open时候传递下来的id为GRALLOC_HARDWARE_GPU0,这个地方要和后面的composer的open对比来看


1.4 allocator HAL alloc的实现

上面的都是常规操作,下面我们接下来看下 allocator HAL alloc的实现!

//[gralloc.cpp]
static int gralloc_alloc(alloc_device_t* dev,int width, int height, int format, int usage,buffer_handle_t* pHandle, int* pStride)
{...if (usage & GRALLOC_USAGE_HW_FB) {err = gralloc_alloc_framebuffer(dev, size, format, usage, pHandle);} else {err = gralloc_alloc_buffer(dev, size, usage, pHandle);}if (err < 0) {return err;}*pStride = stride;return 0;
}

此时的你是不是蒙圈了!尼玛gralloc_alloc里面又有两个分支:

  • gralloc_alloc_framebuffer

    这个分支比较特殊,主要用于GPU合成时候FramebufferSurface使用!然后该buffer在后面就可以用于hwcompower合成使用了。

    并且这里注意这里的FramebufferSurface是消费者,当消费者设置了GRALLOC_USAGE_HW_FB后,这个值在其对应的生产者申请buffer类型的时候,会获取到这个usage,然后这个usage就会随着生产者allocat()的调用逻辑,传递到gralloc来了!

    //[frameworks/native/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp]FramebufferSurface::FramebufferSurface(HWComposer& hwc, DisplayId displayId,const sp<IGraphicBufferConsumer>& consumer,uint32_t maxWidth, uint32_t maxHeight): ConsumerBase(consumer),mDisplayId(displayId),mMaxWidth(maxWidth),mMaxHeight(maxHeight),mCurrentBufferSlot(-1),mCurrentBuffer(),mCurrentFence(Fence::NO_FENCE),mHwc(hwc),mHasPendingRelease(false),mPreviousBufferSlot(BufferQueue::INVALID_BUFFER_SLOT),mPreviousBuffer() {ALOGV("Creating for display %s", to_string(displayId).c_str());mName = "FramebufferSurface";mConsumer->setConsumerName(mName);mConsumer->setConsumerUsageBits(GRALLOC_USAGE_HW_FB |//注意这个地方GRALLOC_USAGE_HW_RENDER |GRALLOC_USAGE_HW_COMPOSER);...}

    关于这块可以参考博客:
    图像显示系统 - SurfaceFlinger GPU合成/CLIENT合成方式

  • gralloc_alloc_buffer

    它是基本的,像App的渲染buffer啊,其它的通用buffer,都是通过它alloc的!




二. hwcomposer service的实现

这里我只能无力的吐糟下Android为了所谓的system,vendor隔离,搞了一个HIDL,这可苦了我们这些搞Android的。composer 2.1来作为参考,简单介绍其实现!


2.1 . composer 2.1 service代码结构

这个比较简单,我们直接上代码!

//[hardware/interfaces/graphics/composer/2.1]├── Android.bp
├── default
│   ├── Android.bp
│   ├── android.hardware.graphics.composer@2.1-service.rc
│   ├── OWNERS
│   └── service.cpp
├── IComposerCallback.hal
├── IComposerClient.hal
├── IComposer.hal
├── types.hal
└── utils├── command-buffer│   ├── Android.bp│   └── include│       └── composer-command-buffer│           └── 2.1│               └── ComposerCommandBuffer.h├── hal│   ├── Android.bp│   └── include│       └── composer-hal│           └── 2.1│               ├── ComposerClient.h│               ├── ComposerCommandEngine.h│               ├── Composer.h│               └── ComposerHal.h├── hwc2on1adapter│   ├── Android.bp│   ├── CleanSpec.mk│   ├── HWC2On1Adapter.cpp│   ├── include│   │   └── hwc2on1adapter│   │       ├── HWC2On1Adapter.h│   │       └── MiniFence.h│   └── MiniFence.cpp├── hwc2onfbadapter│   ├── Android.bp│   ├── HWC2OnFbAdapter.cpp│   └── include│       └── hwc2onfbadapter│           └── HWC2OnFbAdapter.h├── OWNERS├── passthrough│   ├── Android.bp│   └── include│       └── composer-passthrough│           └── 2.1│               ├── HwcHal.h│               └── HwcLoader.h└── resources├── Android.bp├── ComposerResources.cpp└── include└── composer-resources└── 2.1└── ComposerResources.h24 directories, 32 files

2.2 composer 2.1 service passthrough方式的实现

这里我们不对细节,做过多的纠缠,我们只梳理其大体框架!

这里有一点需要注意,composer使用Android默认的实现,即不设置ro属性指定!

//[service.cpp]
android::sp<IComposer> composer = HwcLoader::load()//HwcLoader.hloadModule()hw_get_module(HWC_HARDWARE_MODULE_ID, &module)//默认使用,这个分支加载失败hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module)//加载这个分支,和gralloc使用的HAL是同一个模块createHalWithAdapter()openDeviceWithAdapter()adaptGrallocModule(...module->methods->open(module,GRALLOC_HARDWARE_FB0, TO_HW_DEVICE_T_OPEN(device));createComposer())

这里我需要重点注意的几点:

  • composer的默认实现,加载的HAL库的实现是gralloc.default
  • 调用HAL下open方法的时候,传递的ID的名称是GRALLOC_HARDWARE_FB0这个是需要和allocator实现区分开来的

2.3 composer 2.1 service HAL的实现

这里的实现,就很简单了。因为这里使用gralloc.default作为composer HAL的实现,只实现了其H2C 1.0。

//[hardware/libhardware/modules/gralloc]├── Android.mk
├── framebuffer.cpp
├── gralloc.cpp
├── gralloc_priv.h
├── gr.h
└── mapper.cppstruct private_module_t HAL_MODULE_INFO_SYM = {.base = {.common = {.tag = HARDWARE_MODULE_TAG,.version_major = 1,.version_minor = 0,.id = GRALLOC_HARDWARE_MODULE_ID,//注意这里的ID.name = "Graphics Memory Allocator Module",.author = "The Android Open Source Project",.methods = &gralloc_module_methods},.registerBuffer = gralloc_register_buffer,.unregisterBuffer = gralloc_unregister_buffer,.lock = gralloc_lock,.unlock = gralloc_unlock,},.framebuffer = 0,.flags = 0,.numBuffers = 0,.bufferMask = 0,.lock = PTHREAD_MUTEX_INITIALIZER,.currentBuffer = 0,
};int gralloc_device_open(const hw_module_t* module, const char* name,hw_device_t** device)
{int status = -EINVAL;if (!strcmp(name, GRALLOC_HARDWARE_GPU0)) {....} else {status = fb_device_open(module, name, device);//composer的HAL加载会走次分支}return status;
}int fb_device_open(hw_module_t const* module, const char* name,hw_device_t** device)
{int status = -EINVAL;if (!strcmp(name, GRALLOC_HARDWARE_FB0)) {//前面传递进来的id 那么就是GRALLOC_HARDWARE_FB0/* initialize our state here */fb_context_t *dev = (fb_context_t*)malloc(sizeof(*dev));memset(dev, 0, sizeof(*dev));/* initialize the procs */dev->device.common.tag = HARDWARE_DEVICE_TAG;dev->device.common.version = 0;dev->device.common.module = const_cast<hw_module_t*>(module);dev->device.common.close = fb_close;dev->device.setSwapInterval = fb_setSwapInterval;dev->device.post            = fb_post;dev->device.setUpdateRect = 0;private_module_t* m = (private_module_t*)module;status = mapFrameBuffer(m);if (status >= 0) {int stride = m->finfo.line_length / (m->info.bits_per_pixel >> 3);int format = (m->info.bits_per_pixel == 32)? (m->info.red.offset ? HAL_PIXEL_FORMAT_BGRA_8888 : HAL_PIXEL_FORMAT_RGBX_8888): HAL_PIXEL_FORMAT_RGB_565;const_cast<uint32_t&>(dev->device.flags) = 0;const_cast<uint32_t&>(dev->device.width) = m->info.xres;const_cast<uint32_t&>(dev->device.height) = m->info.yres;const_cast<int&>(dev->device.stride) = stride;const_cast<int&>(dev->device.format) = format;const_cast<float&>(dev->device.xdpi) = m->xdpi;const_cast<float&>(dev->device.ydpi) = m->ydpi;const_cast<float&>(dev->device.fps) = m->fps;const_cast<int&>(dev->device.minSwapInterval) = 1;const_cast<int&>(dev->device.maxSwapInterval) = 1;*device = &dev->device.common;} else {free(dev);}}return status;
}



三. gralloc和hwcompoer中各种让人眼花缭乱的数据关系

这块之前的花式关系,真的是让人眼花缭乱,不知道是李鬼还是李逵。尼玛,让人不得不一吐为快啊!


3.1 native_handle_t*和buffer_handle_t

其它它们是一个东西,具体的定义如下:

//[system/core/libcutils/include/cutils/native_handle.h]
typedef struct native_handle
{int version;        /* sizeof(native_handle_t) */int numFds;         /* number of file-descriptors at &data[0] */int numInts;        /* number of ints at &data[numFds] */
#if defined(__clang__)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wzero-length-array"
#endifint data[0];        /* numFds + numInts ints */
#if defined(__clang__)
#pragma clang diagnostic pop
#endif
} native_handle_t;typedef const native_handle_t* buffer_handle_t;

它的源码目录比较奇特,在libcutils里面。这点大家需要注意。

native_handle/native_handle_t只是定义了一个描述buffer的结构体原型,这个原型是和平台无关的,方便buffer在各个进程之间传递,注意成员data是一个大小为0的数组,这意味着data指向紧挨着numInts后面的一个地址.我们可以把native_handle_t看成是一个纯虚的基类.

image

一般来说,我们描述一块buffer,需要知道它在kernel中对应的fd,虚拟地址/物理地址,offset,size等等信息,后面我们在private_handle_t中就可以看到这些字段.
android的gralloc模块负责从fb设备或者gpu中分配meomory,所以我们在gralloc中就可以找到native_handle的具体实现,gralloc中对buffer的描述就和具体的平台相关了,我们以aosp中最基本的gralloc为例,来看下gralloc中对native_handle是如何使用的.


3.2 private_handle_t

我们来看下,Android aosp为我们打样实现的一个private_handle_t,如下:

//[hardware/libhardware/modules/gralloc/gralloc_priv.h]
#ifdef __cplusplus  
//在c++编译环境下private_handle_t继承于native_handle  
struct private_handle_t : public native_handle {  
#else  
//在c编译环境下,private_handle_t的第一个成员是native_handle类型,其实和c++的继承是一个意思,  
//总之就是一个指向private_handle_t的指针同样也可以表示一个指向native_handle的指针.  
struct private_handle_t {  struct native_handle nativeHandle;  
#endif  // file-descriptors  int     fd;   // ints  int     magic;  int     flags;  int     size;  int     offset;  // 因为native_handle的data成员是一个大小为0的数组,所以data[0]其实就是指向了fd,data[1]指向magic,以此类推.  // 上面提到我们可以把native_handle看成是一个纯虚的基类,那么在private_handle_t这个派生类中,numFds=1 numInts=4.  ...  
}  

gralloc分配的buffer都可以用一个private_handle_T来描述(不一定是上面的实现,可以是私有的)同时也可以用一个native_handle来描述.在不同的平台的实现上,private_handle_t可能会有不同的定义,所以private_handle_t在各个模块之间传递的时候很不方便,而如果用native_handle的身份来传递,就可以消除平台的差异性.在HardwareComposer中,由SurfaceFlinger传给hwc的handle即是native_handle类型,而hwc作为平台相关的模块,他需要知道native_handle中各个字段的具体含义,所以hwc往往会将native_handle指针转化为private_handle_t指针来使用。

image


3.3 小结

对于native_handle和native_handle_t,以及private_handle_t这三个类型可以看作是同一个东西,而buffer_handle_t则是指向他们的指针.
那么android是如何使用这些struct的,gralloc分配的buffer如何和android联系起来呢?我们继续来看window.h


3.4 ANativeWindowBuffer和ANativeWindow

在具体分析ANativeWindowBuffer和ANativeWindow之前,我们先来看下和这两个类型都相关的另外一个结构体android_native_base_t。

[frameworks/native/libs/nativebase/include/nativebase/nativebase.h]typedef struct android_native_base_t
{/* a magic value defined by the actual EGL native type */int magic;/* the sizeof() of the actual EGL native type */int version;void* reserved[4];/* reference-counting interface */void (*incRef)(struct android_native_base_t* base);void (*decRef)(struct android_native_base_t* base);
} android_native_base_t;

这里的incRef和decRef是为了把派生类和android所有class的老祖宗RefBase联系起来所预留的函数指针,在后面我们在会看到指针具体会指向哪些函数.

好了,前面该说的也已经说了。是时候亮出看家本领了,我们直接来看ANativeWindowBuffer。

ANativeWindowBuffer:

    [frameworks/native/libs/nativebase/include/nativebase/nativebase.h]typedef struct ANativeWindowBuffer{#ifdef __cplusplusANativeWindowBuffer() {// ANDROID_NATIVE_BUFFER_MAGIC的值是"_bfr"  common.magic = ANDROID_NATIVE_BUFFER_MAGIC;common.version = sizeof(ANativeWindowBuffer);memset(common.reserved, 0, sizeof(common.reserved));}// Implement the methods that sp<ANativeWindowBuffer> expects so that it// can be used to automatically refcount ANativeWindowBuffer's.// 调用common,也就是android_native_base_t的incRef和decRef函数void incStrong(const void* /*id*/) const {common.incRef(const_cast<android_native_base_t*>(&common));}void decStrong(const void* /*id*/) const {common.decRef(const_cast<android_native_base_t*>(&common));}#endif// common的incRef和decRef  struct android_native_base_t common;int width;int height;int stride;int format;int usage_deprecated;uintptr_t layerCount;void* reserved[1];const native_handle_t* handle;uint64_t usage;// we needed extra space for storing the 64-bits usage flags// the number of slots to use from reserved_proc depends on the// architecture.void* reserved_proc[8 - (sizeof(uint64_t) / sizeof(void*))];} ANativeWindowBuffer_t;typedef struct ANativeWindowBuffer ANativeWindowBuffer;// Old typedef for backwards compatibility.typedef ANativeWindowBuffer_t android_native_buffer_t;**==ANativeWindow==** 的定义如下:[frameworks/native/libs/nativewindow/include/system/window.h]
struct ANativeWindow
{
#ifdef __cplusplusANativeWindow(): flags(0), minSwapInterval(0), maxSwapInterval(0), xdpi(0), ydpi(0){common.magic = ANDROID_NATIVE_WINDOW_MAGIC;common.version = sizeof(ANativeWindow);memset(common.reserved, 0, sizeof(common.reserved));}/* Implement the methods that sp<ANativeWindow> expects so that itcan be used to automatically refcount ANativeWindow's. */void incStrong(const void* /*id*/) const {common.incRef(const_cast<android_native_base_t*>(&common));}void decStrong(const void* /*id*/) const {common.decRef(const_cast<android_native_base_t*>(&common));}
#endifstruct android_native_base_t common;const uint32_t flags;const int   minSwapInterval;const int   maxSwapInterval;const float xdpi;const float ydpi;intptr_t    oem[4];int     (*setSwapInterval)(struct ANativeWindow* window,int interval);int     (*dequeueBuffer_DEPRECATED)(struct ANativeWindow* window,struct ANativeWindowBuffer** buffer);int     (*lockBuffer_DEPRECATED)(struct ANativeWindow* window,struct ANativeWindowBuffer* buffer);int     (*queueBuffer_DEPRECATED)(struct ANativeWindow* window,struct ANativeWindowBuffer* buffer);int     (*query)(const struct ANativeWindow* window,int what, int* value);int     (*perform)(struct ANativeWindow* window,int operation, ... );int     (*cancelBuffer_DEPRECATED)(struct ANativeWindow* window,struct ANativeWindowBuffer* buffer);int     (*dequeueBuffer)(struct ANativeWindow* window,struct ANativeWindowBuffer** buffer, int* fenceFd);int     (*queueBuffer)(struct ANativeWindow* window,struct ANativeWindowBuffer* buffer, int fenceFd);int     (*cancelBuffer)(struct ANativeWindow* window,struct ANativeWindowBuffer* buffer, int fenceFd);
};//没有定义在这里,这里只是为了学习方便
[frameworks/native/libs/nativewindow/include/android/native_window.h]
typedef struct ANativeWindow ANativeWindow;

我们目前需要注意的是ANativeWindow的函数指针成员所指向的函数都需要一个struct ANativeWindowBuffer* buffer的参数.

ANativeWindowBuffer和ANativeWindow还是没有给android_native_base_t的incRef和decRef指针赋值,ANativeWindowBuffer和ANativeWindow两个还是可以理解为抽象类!

image



3.5 GraphicBuffer和Surface

前面我们认知了ANativeWindow和ANativeWindowBuffer,接下来也让我们揭开GraphicBuffer和Surface的庐山真面目。

frameworks/native/libs/ui/include/ui/GraphicBuffer.h]
class GraphicBuffer: public ANativeObjectBase<ANativeWindowBuffer, GraphicBuffer, RefBase>,public Flattenable<GraphicBuffer>
{...
}

GraphicBuffer继承于模板类模版类ANativeObjectBase,这个模版类有三个模版.它的定义如下:

[frameworks/native/libs/ui/include/ui/ANativeObjectBase.h]
// NATIVE_TYPE=ANativeWindowBuffer TYPE=GraphicBuffer REF=RefBase  
template <typename NATIVE_TYPE, typename TYPE, typename REF>  
// ANativeObjectBase多重继承于ANativeWindowBuffer和RefBase  
class ANativeObjectBase : public NATIVE_TYPE, public REF   
{  
public:  // Disambiguate between the incStrong in REF and NATIVE_TYPE  // incStrong和decStrong直接调用其中一个基类RefBase的对应函数  void incStrong(const void* id) const {  REF::incStrong(id);  }     void decStrong(const void* id) const {  REF::decStrong(id);  }     protected:  // 给ANativeObjectBase取了个别名BASE  typedef ANativeObjectBase<NATIVE_TYPE, TYPE, REF> BASE;  ANativeObjectBase() : NATIVE_TYPE(), REF() {  // 构造函数中给ANativeWindowBuffer.common的两个函数指针赋值了!这两个指针就是我们之前在分析ANativeWindowBuffer的时候悬而未决的地方.  // incRef和decRef指针分别指向内部函数incRef和decRef  NATIVE_TYPE::common.incRef = incRef;  NATIVE_TYPE::common.decRef = decRef;  }     static inline TYPE* getSelf(NATIVE_TYPE* self) {  return static_cast<TYPE*>(self);  }     static inline TYPE const* getSelf(NATIVE_TYPE const* self) {  return static_cast<TYPE const *>(self);  }     static inline TYPE* getSelf(android_native_base_t* base) {  return getSelf(reinterpret_cast<NATIVE_TYPE*>(base));  }     static inline TYPE const * getSelf(android_native_base_t const* base) {  return getSelf(reinterpret_cast<NATIVE_TYPE const*>(base));  }  // 内部函数incRef和decRef调用上面的incStong和decStrong,也就是说ANativeWindowBuffer.common的两个函数指针最终会调用到RefBase的incStrong和decStrong.  static void incRef(android_native_base_t* base) {  ANativeObjectBase* self = getSelf(base);  self->incStrong(self);  }     static void decRef(android_native_base_t* base) {  ANativeObjectBase* self = getSelf(base);  self->decStrong(self);  }   
};  

搞了半天,原来GraphicBuffer就是ANativeWindowBuffer一种具体实现,把ANativeWindowBuffer的common成员的两个函数指针incRef decRef指向了GraphicBuffer的另一个基类RefBase的incStrong和decStrong,而ANativeWindowBuffer无非就是把buffer_handle_t包了一层.

我们看下另外一个从ANativeObjectBase派生的类,他就是大名鼎鼎的,Surface!它的定义如下:

class Surface  : public ANativeObjectBase<ANativeWindow, Surface, RefBase>  
{  enum { NUM_BUFFER_SLOTS = BufferQueue::NUM_BUFFER_SLOTS };  ...  struct BufferSlot {  sp<GraphicBuffer> buffer;  Region dirtyRegion;  };  // mSlots stores the buffers that have been allocated for each buffer slot.  // It is initialized to null pointers, and gets filled in with the result of  // IGraphicBufferProducer::requestBuffer when the client dequeues a buffer from a  // slot that has not yet been used. The buffer allocated to a slot will also  // be replaced if the requested buffer usage or geometry differs from that  // of the buffer allocated to a slot.  BufferSlot mSlots[NUM_BUFFER_SLOTS];  ...  
}  

Surface和GraphicBuffer都继承自模版类ANativeObjectBase,他使用的三个模版是ANativeWindow, Surface, RefBase,关于incRef和decRef两个函数指针的指向问题和上面GraphicBuffer是完全相同的, 这里就不赘述了.我们需要注意的是Surface有一个BufferSlot类型的成员数组mSlots,BufferSlot是GraphicBuffer的包装,所以我们可以理解为每个Surface中都有一个大小为NUM_BUFFER_SLOTS的GraphicBuffer数组.

image

因为Surface继承自ANativeWindow,所以Surface需要实现ANativeWindow中定义的一些接口,这些实现在Surface的构造函数中,我们来看下它的实现:

[frameworks/native/libs/gui/Surface.cpp]
Surface::Surface(  const sp<IGraphicBufferProducer>& bufferProducer,  bool controlledByApp)  : mGraphicBufferProducer(bufferProducer)  
{  // Initialize the ANativeWindow function pointers.  ANativeWindow::setSwapInterval  = hook_setSwapInterval;  ANativeWindow::dequeueBuffer    = hook_dequeueBuffer;  ANativeWindow::cancelBuffer     = hook_cancelBuffer;  ANativeWindow::queueBuffer      = hook_queueBuffer;  ANativeWindow::query            = hook_query;  ANativeWindow::perform          = hook_perform;  ANativeWindow::dequeueBuffer_DEPRECATED = hook_dequeueBuffer_DEPRECATED;  ANativeWindow::cancelBuffer_DEPRECATED  = hook_cancelBuffer_DEPRECATED;  ANativeWindow::lockBuffer_DEPRECATED    = hook_lockBuffer_DEPRECATED;  ANativeWindow::queueBuffer_DEPRECATED   = hook_queueBuffer_DEPRECATED;  const_cast<int&>(ANativeWindow::minSwapInterval) = 0;  const_cast<int&>(ANativeWindow::maxSwapInterval) = 1;  
}  

ANativeWindow定义的这些接口有什么用呢?谁会来call这些函数呢?举个例子来看.我们在EGL的api中可以找到eglCreateWindowSurface这个函数的定义:

[frameworks/native/opengl/libs/EGL/eglApi.cpp]EGLSurface eglCreateWindowSurface(  EGLDisplay dpy, EGLConfig config,  NativeWindowType window,  const EGLint *attrib_list)  
{  ...  
}

注意其中一个参数NativeWindowType window,这个NativeWindowType又是什么呢?

[frameworks/native/opengl/include/EGL/eglplatform.h]
typedef struct ANativeWindow*           EGLNativeWindowType;  
typedef EGLNativeWindowType  NativeWindowType;

原来NativeWindowType在Android环境下,就是ANativeWindow*,也就是Surface*!
总结一下:

  • native_handle/native_handle_t是private_handle_t的抽象表示方法,消除平台相关性,方便private_handle_t所表示的memory信息在android各个层次之间传递.而buffer_handle_t是指向他们的指针.

  • ANativeWindowBuffer将buffer_handle_t进行了包装,ANativeWindow和ANativeWindowBuffer都继承于android_native_base_t,定义了common.incRef和common.decRef两个函数指针,但是并没有为函数指针赋值,所以ANativeWindow和ANativeWindowBuffer仍然是抽象类.
    GraphicBuffer和Surface通过继承模版类ANativeObjectBase并指定其中一个模版是RefBase,为incRef和decRef两个指针分别赋值为RefBase的incStrong和decStrong,这样

  • GraphicBuffer继承了ANativeWindowBuffer,Surface继承了ANativeWindow,并且两者都具有的和RefBase同样的incStong decStrong成员函数.

  • Surface的成员BufferSlot mSlots[NUM_BUFFER_SLOTS];可以看作是sp类型的数组,也就是说每个Surface中都包含有NUM_BUFFER_SLOTS个sp.

关于ANativeWindow的使用方法,我们可以在SurfaceFlinger中找到一个很好的列子,就是SF的captureScreen接口。


3.6 关于GraphicBuffer和Surface牵涉的各种数据结构小结

通过上述的一通咔咔学习,我们在以后的SurfaceFlinger HardWare Composer以及gralloc相关代码的学习过程中,native_handle private_handle_t ANativeWindowBuffer ANativeWindow GraphicBuffer Surface等等一系列和memory相关的struct和class,他们相互之间到底是什么区别,又有什么联系呢,我们应该已经很清楚了。

概括来说native_handle,private_handle_t,ANativeWindowBuffer,GraphicBuffer这四个struct/class所描述的是一块memory。而ANativeWindow和Surface所描述的是一系列上述memeofy的组合和对buffer的操作方法,有的struct/class在比较低的level使用,和平台有关,而另外一些在比较高的level使用和平台无关,还有一些介于低/高level之间,用以消除平台相关性,让android可以方便运行在不同的平台上。

在这里插入图片描述




写在最后

好了今天的博客关于Android下gralloc,hwcompoer以及surface模块的重新认识就到这里了。总之,青山不改绿水长流先到这里了。如果本博客对你有所帮助,麻烦关注或者点个赞,如果觉得很烂也可以踩一脚!谢谢各位了!!

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

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

相关文章

文献速递:GAN医学影像合成--双向映射生成对抗网络用于脑部 MR 到 PET 合成

文献速递&#xff1a;GAN医学影像合成–双向映射生成对抗网络用于脑部 MR 到 PET 合成 01 文献速递介绍 作为精准医学的基石&#xff0c;多模态医学图像已成为必备要素。稿件收到日期&#xff1a;2021年6月26日&#xff1b;修改日期&#xff1a;2021年8月6日&#xff1b;接受…

常用的消息中间件RabbitMQ

目录 一、消息中间件 1、简介 2、作用 3、两种模式 1、P2P模式 2、Pub/Sub模式 4、常用中间件介绍与对比 1、Kafka 2、RabbitMQ 3、RocketMQ RabbitMQ和Kafka的区别 二、RabbiMQ集群 RabbiMQ特点 RabbitMQ模式⼤概分为以下三种: 集群中的基本概念&#xff1a; 集…

Linux系统安全:安全技术和防火墙

目录 一、安全技术和防火墙 1.安全技术 2.防火墙的分类 二、防火墙 1.iptables四表五链 2.黑白名单 3.iptables基本语法 4.iptables选项 5.控制类型 6.隐藏扩展模块 7.显示扩展模块 8.iptables规则保存 9.自定义链使用 一、安全技术和防火墙 1.安全技术 入侵检测系…

2000-2022各省产业结构高级化合理化指数(含原始数据、计算过程+计算结果)

2000-2022各省产业结构高级化合理化指数&#xff08;含原始数据、计算过程计算结果&#xff09; 1、时间&#xff1a;2000-2022年 2、指标&#xff1a;国内生产总值、第一产业增加值、第二产业增加值、第三产业增加值、总就业人数、第一产业就业人数、第二产业就业人数、第三…

C++中自定义类型使用标准输入cin输出cout

自定义类型的输出 引言示例一运行结果示例二运行结果注意点 引言 当自己定义的数据为一些复杂数据&#xff0c;不再为基本数据类型&#xff0c;这时候要使用cout输出这些数据&#xff0c;就需要重载输出运算符<<,这样就可以使用cout来输出自定义的数据&#xff0c;相同如…

【高阶数据结构】B+树

文章目录 1. B树的概念2. B树的查找3. B-树 VS B树4. B 树的插入分析 1. B树的概念 B树是B树的变形&#xff0c;是在B树基础上优化的多路平衡搜索树&#xff0c;B树的规则跟B树基本类似&#xff0c;但是又在B树的基础上做了一些改进优化。 一棵m阶的B树需满足下列条件&#x…

算法刷题:找到字符串中所有的字母异位词

找到字符串中所有的字母异位词 .题目链接题目详情题目解析算法原理滑动窗口流程图定义指针及变量进窗口判断出窗口更新结果 我的答案 . 题目链接 找到字符串中所有的字母异位词 题目详情 题目解析 所谓的异位词,就是一个单词中的字母,打乱顺序,重新排列得到的单词 如:abc-&g…

图片怎么变成透明背景?分享这些变透明的方法

很多从事编辑和图片设计的同行在日常工作中经常需要处理图片的背景色。为了更好地进行设计和编辑&#xff0c;将图片的背景色替换成透明是非常必要的。然而&#xff0c;对于一些新手来说&#xff0c;使用专业的图像处理软件可能有些困难。不过&#xff0c;现在有很多在线的图像…

N5182A MXG 矢量信号发生器,100 kHz 至 6 GHz

N5182A MXG 矢量信号发生器 简述&#xff1a; Agilent N5182A 具有快速频率、幅度和波形切换、带有电子衰减器的高功率和高可靠性——所有这些都在两个机架单元 (2RU) 中。安捷伦 MXG 矢量针对制造蜂窝通信和无线连接组件进行了优化。安捷伦 MXG 矢量通过增加吞吐量、提高测试良…

Elasticsearch:什么是 kNN?

kNN - K-nearest neighbor 定义 kNN&#xff08;即 k 最近邻算法&#xff09;是一种机器学习算法&#xff0c;它使用邻近度将一个数据点与其训练并记忆的一组数据进行比较以进行预测。 这种基于实例的学习为 kNN 提供了 “惰性学习&#xff08;lazy learning&#xff09;” 名…

IO进程:多进程实现文件的拷贝

1.使用多进程完成两个文件的拷贝&#xff0c;父进程拷贝前一半&#xff0c;子进程拷贝后一半&#xff0c;父进程回收子进程的资源 程序代码&#xff1a; 1 #include<myhead.h>2 int main(int argc, const char *argv[])3 {4 //判断传入的文件个数5 if(argc!3)6 …

Arcmap excel转shp

使用excel表格转shp的时候&#xff0c;如果你的excel里面有很多字段&#xff0c;直接转很大概率会出现转换结果错误的情况&#xff0c;那么就需要精简一下字段的个数。将原来的表格文件另存一份&#xff0c;在另存为的文件中只保留关键的经度、纬度、和用于匹配的字段即可&…

LeetCode JS专栏刷题笔记(一)

一、前言 LeetCode 在前不久出了一个 JavaScript 专栏&#xff0c;这个专栏一个目的是为了非前端工程师学习 JS&#xff0c;另一个是为了前端工程师提升 JS 能力。 因此在这个专栏中&#xff0c;基本不涉及什么具体算法问题&#xff0c;都是一些 JS 的入门语法与常见的 JS 面…

redis分布式锁redisson

文章目录 1. 分布式锁1.1 基本原理和实现方式对比synchronized锁在集群模式下的问题多jvm使用同一个锁监视器分布式锁概念分布式锁须满足的条件分布式锁的实现 1.2 基于Redis的分布式锁获取锁&释放锁操作示例 基于Redis实现分布式锁初级版本ILock接口SimpleRedisLock使用示…

前端秘法基础式终章----欢迎来到JS的世界

目录 一.JavaScript的背景 二.JavaScript的书写形式 1.行内式 2.嵌入式 3.外部式 三.JS中的变量 1.变量的定义 2.JS动态类型变量 2.1强类型和弱类型 3.JS中的变量类型 四.运算符 五.if语句和三元表达式和Switch语句和循环语句 六.数组 1.创建获取数组元素 2.新增…

unity学习(28)——登录功能

有之前注册的知识&#xff0c;登录就很容易处理了。 登陆成功返回id&#xff1a; 登录失败返回null&#xff1a; 测试同一账号不能重复登陆&#xff01;登录成功后最好可以跳到新的场景中 结果是好的&#xff0c;去服务器看一下对应部分的代码&#xff0c;可见&#xff0c;登…

MySQL错误-this is incompatible with sql_mode=only_full_group_by完美解决方案

项目场景 有时候&#xff0c;遇到数据库重复数据&#xff0c;需要将数据进行分组&#xff0c;并取出其中一条来展示&#xff0c;这时就需要用到group by语句。 但是&#xff0c;如果mysql是高版本&#xff0c;当执行group by时&#xff0c;select的字段不属于group by的字段的…

【FastAPI】P3 请求与响应

目录 请求路径参数查询参数 响应JSON 响应文本响应返回 Pydantic 模型 在网络通讯中&#xff0c;请求&#xff08;Request&#xff09; 与 响应&#xff08;Response&#xff09; 扮演着至关重要的角色&#xff0c;它们构成了客户端与服务器间互动的根本理念。 请求&#xff0…

Linux编辑器——Vim详解

目录 ⭐前言 ⭐vim的基本概念 ⭐vim的基本操作 ⭐vim命令模式命令集 ⭐vim末行模式命令集 ⭐简单vim配置 ⭐配置文件的位置 ⭐常用配置选项 ⭐前言 vi/vim的区别简单点来说&#xff0c;它们都是多模式编辑器&#xff0c;不同的是vim是vi的升级版本&#xff0c;它不仅兼容…

CMake的简单使用

一、一个最简单的CMake项目 在Ubuntu上使用CMake构建一个最简单的项目。 1. 安装CMake 首先安装CMake&#xff0c;这里使用的是Ubuntu系统。 sudo apt-get install cmake2. 编写源程序 编写代码&#xff0c;新建文件main.c。 // main.c #include "stdio.h"int …