android Surface(1, 2)

android Surface(1, 2)

android的Surface相关内容从底层依次往上分别是:

1.frameBuffer,简称fb,对于同一个android系统,可以同时存在多个frameBuffer,本机是fb0,依次外接时,fb1, fb2, ……fbn等。fb文件的目录在类Linux操作系统的dev/目录下,因为一般而言,只有一个显示器。

2.hal层对设备的定义gralloc。

3.FrameBufferNativeWindow。

4.HWCompose。

5.SurfaceFlinger。

6.java层的frameWork。

7.应用。

他们的大致关系图如下所示:
在这里插入图片描述
这个图是参考的,在最新的版本中会有一些变动的,比如FrameBufferNativeWindow在新的andori版本已经没有了,被ANativeWindow替换掉了。

1.FrameBuffer

android底层在绘制图形时分为两种方式:

1.CPU为主,GPU为辅。?

2.GPU绘制,CPU为辅。?

​ 其中CPU作为主要角色绘制时,在底层是通过gralloc,framebuffer绘制的,这个过程中CPU为主,GPU为辅。FrameBuffer绘制是使用CPU进行图形绘制和渲染,然后将最终结果存储在内存中的一个FrameBuffer对象中。这种方式虽然简单,但是在绘制复杂图形时会占用大量的CPU资源,导致性能下降。如果是GPU为主进行绘制时,这个过程中,GPU绘制使用GPU进行图形绘制和渲染,最终的结果直接输出到屏幕上。这种方式可以充分利用GPU的性能,提高图形渲染的速度和质量。但是相对于FrameBuffer绘制,GPU绘制需要更加复杂的渲染管线和硬件支持。

​ 但是他们两个不是互相独立的,framebuffer绘制时,也需要GPU参与,GPU绘制时也需要framebuffer参与。

​ Android系统在硬件抽象层中提供了一个Gralloc模块,封装了对帧缓冲区的所有访问操作。用户空间的应用程序在使用帧缓冲区之间,首先要加载Gralloc模块,并且获得一个gralloc设备和一个fb设备。有了gralloc设备之后,用户空间中的应用程序就可以申请分配一块图形缓冲区,并且将这块图形缓冲区映射到应用程序的地址空间来,以便可以向里面写入要绘制的画面的内容。最后,用户空间中的应用程序就通过fb设备来将已经准备好了的图形缓冲区渲染到帧缓冲区中去,即将图形缓冲区的内容绘制到显示屏中去。相应地,当用户空间中的应用程序不再需要使用一块图形缓冲区的时候,就可以通过gralloc设备来释放它,并且将它从地址空间中解除映射。

这个过程中相关的头文件路径如下:

hardware/libhardware/include/hardware/

其中涉及到的头文件如下:

fb.h 指的就是framebuffer

gralloc.h

hardware.h

对应定义的文件路径如下:

hardware/libhardware/modules/gralloc/

其中涉及到的文件如下:

framebuffer.cpp

gr.h

gralloc.cpp

gralloc_priv.h

mapper.cpp

1.1Hardware

 Every hardware module must have a data structure named HAL_MODULE_INFO_SYM and the fields of this data structure must begin with hw_module_t followed by module specific information.

hardware.h文件中主要定义了三个结构体,分别是:

1.hw_module_t

2.hw_module_methods_t

3.hw_device_t

​ 其中hw_module_t定义了一些基本的内容,包括tag,版本,作者,还有hw_module_methods_t。hw_module_methods_t结构体中定义了一个打开设备的方法。hw_device_t中包含hw_module_t,还多了一些其他的变量,还有一个指向关闭设备的指针。

1.2FrameBuffer

​ framebuffer的头文件中定义了一些内容:

#define GRALLOC_HARDWARE_FB0 "fb0" //这个指的是本机的设备
typedef struct framebuffer_device_t {/*** Common methods of the framebuffer device.  This *must* be the first member of* framebuffer_device_t as users of this structure will cast a hw_device_t to* framebuffer_device_t pointer in contexts where it's known the hw_device_t references a* framebuffer_device_t.*/struct hw_device_t common;//这个在hardware.h里面有定义/* flags describing some attributes of the framebuffer */const uint32_t  flags;/* dimensions of the framebuffer in pixels */const uint32_t  width;const uint32_t  height;/* frambuffer stride in pixels */const int       stride;/* framebuffer pixel format */const int       format;/* resolution of the framebuffer's display panel in pixel per inch*/const float     xdpi;const float     ydpi;/* framebuffer's display panel refresh rate in frames per second */const float     fps;/* min swap interval supported by this framebuffer */const int       minSwapInterval;/* max swap interval supported by this framebuffer */const int       maxSwapInterval;/* Number of framebuffers supported*/const int       numFramebuffers;int reserved[7];/** requests a specific swap-interval (same definition than EGL)** Returns 0 on success or -errno on error.*/int (*setSwapInterval)(struct framebuffer_device_t* window,int interval);//设置更新区域,一般通过framebuffer更新/** This hook is OPTIONAL.** It is non NULL If the framebuffer driver supports "update-on-demand"* and the given rectangle is the area of the screen that gets* updated during (*post)().** This is useful on devices that are able to DMA only a portion of* the screen to the display panel, upon demand -- as opposed to* constantly refreshing the panel 60 times per second, for instance.** Only the area defined by this rectangle is guaranteed to be valid, that* is, the driver is not allowed to post anything outside of this* rectangle.** The rectangle evaluated during (*post)() and specifies which area* of the buffer passed in (*post)() shall to be posted.** return -EINVAL if width or height <=0, or if left or top < 0*/int (*setUpdateRect)(struct framebuffer_device_t* window,int left, int top, int width, int height);//post数据,刷新/** Post <buffer> to the display (display it on the screen)* The buffer must have been allocated with the*   GRALLOC_USAGE_HW_FB usage flag.* buffer must be the same width and height as the display and must NOT* be locked.** The buffer is shown during the next VSYNC.** If the same buffer is posted again (possibly after some other buffer),* post() will block until the the first post is completed.** Internally, post() is expected to lock the buffer so that a* subsequent call to gralloc_module_t::(*lock)() with USAGE_RENDER or* USAGE_*_WRITE will block until it is safe; that is typically once this* buffer is shown and another buffer has been posted.** Returns 0 on success or -errno on error.*/int (*post)(struct framebuffer_device_t* dev, buffer_handle_t buffer);/** The (*compositionComplete)() method must be called after the* compositor has finished issuing GL commands for client buffers.*/int (*compositionComplete)(struct framebuffer_device_t* dev);/** This hook is OPTIONAL.** If non NULL it will be caused by SurfaceFlinger on dumpsys*/void (*dump)(struct framebuffer_device_t* dev, char *buff, int buff_len);/** (*enableScreen)() is used to either blank (enable=0) or* unblank (enable=1) the screen this framebuffer is attached to.** Returns 0 on success or -errno on error.*/int (*enableScreen)(struct framebuffer_device_t* dev, int enable);void* reserved_proc[6];} framebuffer_device_t;/** convenience API for opening and closing a supported device */static inline int framebuffer_open(const struct hw_module_t* module,struct framebuffer_device_t** device) {return module->methods->open(module,GRALLOC_HARDWARE_FB0, TO_HW_DEVICE_T_OPEN(device));
}static inline int framebuffer_close(struct framebuffer_device_t* device) {return device->common.close(&device->common);
}

总结:

​ fb.h的头文件中主要定义了framebuffer_device_t这个结构体,framebuffer_device_t结构体中大致如下:hw_device_t,宽高,像素步幅,x方向的像素,y方向的像素,帧率,framebuffer交换间隔,刷新区域。

他的实现文件framebuffer.cpp里面主要解释如下:定义了android设备的buffer数量是2(默认是2),里面有6个函数,分别是:

//设置两个buffer的交换间隔
static int fb_setSwapInterval(struct framebuffer_device_t* dev,int interval)
//往framebuffer里面写数据
static int fb_post(struct framebuffer_device_t* dev, buffer_handle_t buffer)
//映射buffer的数据,并初始化buffer的内容
int mapFrameBufferLocked(struct private_module_t* module, int format)
//带了个锁,里面执行的是mapFrameBufferLocked函数
static int mapFrameBuffer(struct private_module_t* module)
//关闭设备
static int fb_close(struct hw_device_t *dev)
//打开设备
int fb_device_open(hw_module_t const* module, const char* name,hw_device_t** device)

Q1:CPU和GPU是怎么协作的?

2.Gralloc

2.1基本定义

gralloc和Framebuffer是密不可分的。他的头文件主要内容如下:

路径:hardware/libhardware/include/hardware/gralloc.h

主要定义了两个结构体和几个静态方法:

typedef struct gralloc_module_t {struct hw_module_t common;//在hardware.h里面定义的/** 在buffer_handle_t没有被初始化之前调用* (*registerBuffer)() must be called before a buffer_handle_t that has not* been created with (*alloc_device_t::alloc)() can be used.* * This is intended to be used with buffer_handle_t's that have been* received in this process through IPC.* * This function checks that the handle is indeed a valid one and prepares* it for use with (*lock)() and (*unlock)().* * It is not necessary to call (*registerBuffer)() on a handle created * with (*alloc_device_t::alloc)().* * returns an error if this buffer_handle_t is not valid.*/int (*registerBuffer)(struct gralloc_module_t const* module,buffer_handle_t handle);/** (*unregisterBuffer)() is called once this handle is no longer needed in* this process. After this call, it is an error to call (*lock)(),* (*unlock)(), or (*registerBuffer)().* * This function doesn't close or free the handle itself; this is done* by other means, usually through libcutils's native_handle_close() and* native_handle_free(). * * It is an error to call (*unregisterBuffer)() on a buffer that wasn't* explicitly registered first.*/int (*unregisterBuffer)(struct gralloc_module_t const* module,buffer_handle_t handle);//当一个buffer被使用之前调用,会阻塞,比如硬件需要完成渲染或者CPU缓存需要被同步时/** The (*lock)() method is called before a buffer is accessed for the * specified usage. This call may block, for instance if the h/w needs* to finish rendering or if CPU caches need to be synchronized.* * The caller promises to modify only pixels in the area specified * by (l,t,w,h).* * The content of the buffer outside of the specified area is NOT modified* by this call.** If usage specifies GRALLOC_USAGE_SW_*, vaddr is filled with the address* of the buffer in virtual memory.** Note calling (*lock)() on HAL_PIXEL_FORMAT_YCbCr_*_888 buffers will fail* and return -EINVAL.  These buffers must be locked with (*lock_ycbcr)()* instead.** THREADING CONSIDERATIONS:** It is legal for several different threads to lock a buffer from * read access, none of the threads are blocked.* * However, locking a buffer simultaneously for write or read/write is* undefined, but:* - shall not result in termination of the process* - shall not block the caller* It is acceptable to return an error or to leave the buffer's content* into an indeterminate state.** If the buffer was created with a usage mask incompatible with the* requested usage flags here, -EINVAL is returned. * */int (*lock)(struct gralloc_module_t const* module,buffer_handle_t handle, int usage,int l, int t, int w, int h,void** vaddr);/** The (*unlock)() method must be called after all changes to the buffer* are completed.*/int (*unlock)(struct gralloc_module_t const* module,buffer_handle_t handle);//留作扩展用/* reserved for future use */int (*perform)(struct gralloc_module_t const* module,int operation, ... );/** 和lock差不多,只不过使用的ycbcr的格式存储的像素之类的数据* The (*lock_ycbcr)() method is like the (*lock)() method, with the* difference that it fills a struct ycbcr with a description of the buffer* layout, and zeroes out the reserved fields.** If the buffer format is not compatible with a flexible YUV format (e.g.* the buffer layout cannot be represented with the ycbcr struct), it* will return -EINVAL.** This method must work on buffers with HAL_PIXEL_FORMAT_YCbCr_*_888* if supported by the device, as well as with any other format that is* requested by the multimedia codecs when they are configured with a* flexible-YUV-compatible color-format with android native buffers.** Note that this method may also be called on buffers of other formats,* including non-YUV formats.** Added in GRALLOC_MODULE_API_VERSION_0_2.*/int (*lock_ycbcr)(struct gralloc_module_t const* module,buffer_handle_t handle, int usage,int l, int t, int w, int h,struct android_ycbcr *ycbcr);/** 把锁传进去不用让调用者等待结束* The (*lockAsync)() method is like the (*lock)() method except* that the buffer's sync fence object is passed into the lock* call instead of requiring the caller to wait for completion.** The gralloc implementation takes ownership of the fenceFd and* is responsible for closing it when no longer needed.** Added in GRALLOC_MODULE_API_VERSION_0_3.*/int (*lockAsync)(struct gralloc_module_t const* module,buffer_handle_t handle, int usage,int l, int t, int w, int h,void** vaddr, int fenceFd);/** The (*unlockAsync)() method is like the (*unlock)() method* except that a buffer sync fence object is returned from the* lock call, representing the completion of any pending work* performed by the gralloc implementation.** The caller takes ownership of the fenceFd and is responsible* for closing it when no longer needed.** Added in GRALLOC_MODULE_API_VERSION_0_3.*/int (*unlockAsync)(struct gralloc_module_t const* module,buffer_handle_t handle, int* fenceFd);/** The (*lockAsync_ycbcr)() method is like the (*lock_ycbcr)()* method except that the buffer's sync fence object is passed* into the lock call instead of requiring the caller to wait for* completion.** The gralloc implementation takes ownership of the fenceFd and* is responsible for closing it when no longer needed.** Added in GRALLOC_MODULE_API_VERSION_0_3.*/int (*lockAsync_ycbcr)(struct gralloc_module_t const* module,buffer_handle_t handle, int usage,int l, int t, int w, int h,struct android_ycbcr *ycbcr, int fenceFd);/* 获取缓冲区的大小* getTransportSize(..., outNumFds, outNumInts)* This function is mandatory on devices running IMapper2.1 or higher.** Get the transport size of a buffer. An imported buffer handle is a raw* buffer handle with the process-local runtime data appended. This* function, for example, allows a caller to omit the process-local* runtime data at the tail when serializing the imported buffer handle.** Note that a client might or might not omit the process-local runtime* data when sending an imported buffer handle. The mapper must support* both cases on the receiving end.*/int32_t (*getTransportSize)(struct gralloc_module_t const* module, buffer_handle_t handle, uint32_t *outNumFds,uint32_t *outNumInts);/* validateBufferSize(..., w, h, format, usage, stride)* This function is mandatory on devices running IMapper2.1 or higher.** Validate that the buffer can be safely accessed by a caller who assumes* the specified width, height, format, usage, and stride. This must at least validate* that the buffer size is large enough. Validating the buffer against* individual buffer attributes is optional.*/int32_t (*validateBufferSize)(struct gralloc_module_t const* device, buffer_handle_t handle,uint32_t w, uint32_t h, int32_t format, int usage,uint32_t stride);//留作扩展用/* reserved for future use */void* reserved_proc[1];} gralloc_module_t;

下面又定义了另外一个结构体:

/*** Every device data structure must begin with hw_device_t* followed by module specific public methods and attributes.*/typedef struct alloc_device_t {struct hw_device_t common; //在hardware.h里面有定义//分配buffer,返回buffer_handle_t/* * (*alloc)() Allocates a buffer in graphic memory with the requested* parameters and returns a buffer_handle_t and the stride in pixels to* allow the implementation to satisfy hardware constraints on the width* of a pixmap (eg: it may have to be multiple of 8 pixels). * The CALLER TAKES OWNERSHIP of the buffer_handle_t.** If format is HAL_PIXEL_FORMAT_YCbCr_420_888, the returned stride must be* 0, since the actual strides are available from the android_ycbcr* structure.* * Returns 0 on success or -errno on error.*/int (*alloc)(struct alloc_device_t* dev,int w, int h, int format, int usage,buffer_handle_t* handle, int* stride);/** (*free)() Frees a previously allocated buffer. * Behavior is undefined if the buffer is still mapped in any process,* but shall not result in termination of the program or security breaches* (allowing a process to get access to another process' buffers).* THIS FUNCTION TAKES OWNERSHIP of the buffer_handle_t which becomes* invalid after the call. * * Returns 0 on success or -errno on error.*/int (*free)(struct alloc_device_t* dev,buffer_handle_t handle);/* This hook is OPTIONAL.** If non NULL it will be caused by SurfaceFlinger on dumpsys*/void (*dump)(struct alloc_device_t *dev, char *buff, int buff_len);void* reserved_proc[7];
} alloc_device_t;

总结:

​ 1.gralloc_module_t结构体里面定义了hw_module_t common(hw_module_t 在hardware.h中定义)一个变量,还有注册,取消注册缓冲器,加锁,去锁,常规,yuv分量存储,获取缓冲区大小,校验缓冲区大小的几个方法。

​ 2.alloc_device_t结构体中定义了hw_device_t common(hw_device_t 在hardware.h中定义)一个变量,还有分配,释放buffer的两个指向函数的变量。

后面还有几个静态方法:

/** convenience API for opening and closing a supported device */static inline int gralloc_open(const struct hw_module_t* module, struct alloc_device_t** device) {return module->methods->open(module, GRALLOC_HARDWARE_GPU0, TO_HW_DEVICE_T_OPEN(device));
}static inline int gralloc_close(struct alloc_device_t* device) {return device->common.close(&device->common);
}		

​ 上面的是gralloc.h中文件的大概内容,gralloc.cpp的文件路径是hardware/libhardware/modules/gralloc/gralloc.cpp,在gralloc.cpp里面的内容大致如下:

​ 1.定义了一个gralloc_context_t结构体变量,gralloc_context_t结构体里面有一个alloc_device_t。

​ 2.初始化了HAL_MODULE_INFO_SYM这个private_module_t结构体类型的变量,其中private_module_t结构体在同级目录下的gralloc_priv.h中。

​ 为了方便直接查找上下文的代码,这里把他的代码大概罗列一下:

struct gralloc_context_t {alloc_device_t  device;/* our private data here */
};struct private_module_t HAL_MODULE_INFO_SYM = {.base = {.common = {.tag = HARDWARE_MODULE_TAG,.version_major = 1,.version_minor = 0,.id = GRALLOC_HARDWARE_MODULE_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,
};

​ 上述是在gralloc中主要做的两个大的操作。

​ 下面是gralloc_priv.h中定义的两个结构体:

struct private_module_t {gralloc_module_t base;private_handle_t* framebuffer;uint32_t flags;uint32_t numBuffers;uint32_t bufferMask;pthread_mutex_t lock;buffer_handle_t currentBuffer;int pmem_master;void* pmem_master_base;struct fb_var_screeninfo info;struct fb_fix_screeninfo finfo;float xdpi;float ydpi;float fps;
};#ifdef __cplusplus
struct private_handle_t : public native_handle {
#else
struct private_handle_t {struct native_handle nativeHandle;
#endifenum {PRIV_FLAGS_FRAMEBUFFER = 0x00000001};// file-descriptorsint     fd;// intsint     magic;int     flags;int     size;int     offset;// FIXME: the attributes below should be out-of-lineuint64_t base __attribute__((aligned(8)));int     pid;#ifdef __cplusplusstatic inline int sNumInts() {return (((sizeof(private_handle_t) - sizeof(native_handle_t))/sizeof(int)) - sNumFds);}static const int sNumFds = 1;static const int sMagic = 0x3141592;//这里是赋值操作private_handle_t(int fd, int size, int flags) :fd(fd), magic(sMagic), flags(flags), size(size), offset(0),base(0), pid(getpid()){version = sizeof(native_handle);numInts = sNumInts();numFds = sNumFds;}~private_handle_t() {magic = 0;}static int validate(const native_handle* h) {const private_handle_t* hnd = (const private_handle_t*)h;if (!h || h->version != sizeof(native_handle) ||h->numInts != sNumInts() || h->numFds != sNumFds ||hnd->magic != sMagic){ALOGE("invalid gralloc handle (at %p)", h);return -EINVAL;}return 0;}
#endif
};

​ 设备gpu用于分配图形缓冲区,而设备fb用于渲染图形缓冲区;hw_module_t用于描述硬件抽象层Gralloc模块,而hw_device_t则用于描述硬件抽象层Gralloc设备,通过硬件抽象层设备可以找到对应的硬件抽象层模块。

2.2Gralloc打开流程

2.2.1FB打开流程

​ fb的打开流程如下:

​ framebuffer_open的最终定义是在gralloc.cpp文件中:

int gralloc_device_open(const hw_module_t* module, const char* name,hw_device_t** device)
{int status = -EINVAL;//if里面是打开GPU的函数,传GPU0,进到函数里面,传frameBuffer,走到else里面if (!strcmp(name, GRALLOC_HARDWARE_GPU0)) {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 {//这里是打开framebufferstatus = fb_device_open(module, name, device);}return status;
}

​ fb_device_open函数定义:

int fb_device_open(hw_module_t const* module, const char* name,hw_device_t** device)
{int status = -EINVAL;//判断打开的是fb设备时,再做操作if (!strcmp(name, 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;//这里是在处理映射地址,将fb映射到当前进程地址空间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;
}

​ mapFrameBuffer通过锁结构最终申请了一块区域后初始化:

int mapFrameBufferLocked(struct private_module_t* module, int format)
{// already initialized...if (module->framebuffer) {return 0;}char const * const device_template[] = {"/dev/graphics/fb%u","/dev/fb%u",0 };int fd = -1;int i=0;char name[64];while ((fd==-1) && device_template[i]) {snprintf(name, 64, device_template[i], 0);fd = open(name, O_RDWR, 0);i++;}if (fd < 0)return -errno;struct fb_fix_screeninfo finfo;if (ioctl(fd, FBIOGET_FSCREENINFO, &finfo) == -1)return -errno;struct fb_var_screeninfo info;if (ioctl(fd, FBIOGET_VSCREENINFO, &info) == -1)return -errno;info.reserved[0] = 0;info.reserved[1] = 0;info.reserved[2] = 0;info.xoffset = 0;info.yoffset = 0;info.activate = FB_ACTIVATE_NOW;/** Request NUM_BUFFERS screens* To enable page flipping, NUM_BUFFERS should be at least 2.*/info.yres_virtual = info.yres * NUM_BUFFERS;switch (format) {case HAL_PIXEL_FORMAT_RGBA_8888:info.bits_per_pixel = 32;info.red.offset = 0;info.red.length = 8;info.green.offset = 8;info.green.length = 8;info.blue.offset = 16;info.blue.length = 8;break;default:ALOGW("unknown format: %d", format);break;}uint32_t flags = PAGE_FLIP;
#if USE_PAN_DISPLAYif (ioctl(fd, FBIOPAN_DISPLAY, &info) == -1) {ALOGW("FBIOPAN_DISPLAY failed, page flipping not supported");
#elseif (ioctl(fd, FBIOPUT_VSCREENINFO, &info) == -1) {ALOGW("FBIOPUT_VSCREENINFO failed, page flipping not supported");
#endifinfo.yres_virtual = info.yres;flags &= ~PAGE_FLIP;}if (info.yres_virtual < info.yres * 2) {// we need at least 2 for page-flippinginfo.yres_virtual = info.yres;flags &= ~PAGE_FLIP;ALOGW("page flipping not supported (yres_virtual=%d, requested=%d)",info.yres_virtual, info.yres*2);}if (ioctl(fd, FBIOGET_VSCREENINFO, &info) == -1)return -errno;uint64_t  refreshQuotient =(uint64_t( info.upper_margin + info.lower_margin + info.yres )* ( info.left_margin  + info.right_margin + info.xres )* info.pixclock);/* Beware, info.pixclock might be 0 under emulation, so avoid a* division-by-0 here (SIGFPE on ARM) */int refreshRate = refreshQuotient > 0 ? (int)(1000000000000000LLU / refreshQuotient) : 0;//刷新频率if (refreshRate == 0) {// bleagh, bad info from the driverrefreshRate = 60*1000;  // 60 Hz}if (int(info.width) <= 0 || int(info.height) <= 0) {// the driver doesn't return that information// default to 160 dpiinfo.width  = ((info.xres * 25.4f)/160.0f + 0.5f);info.height = ((info.yres * 25.4f)/160.0f + 0.5f);}float xdpi = (info.xres * 25.4f) / info.width;float ydpi = (info.yres * 25.4f) / info.height;float fps  = refreshRate / 1000.0f;ALOGI(   "using (fd=%d)\n""id           = %s\n""xres         = %d px\n""yres         = %d px\n""xres_virtual = %d px\n""yres_virtual = %d px\n""bpp          = %d\n""r            = %2u:%u\n""g            = %2u:%u\n""b            = %2u:%u\n",fd,finfo.id,info.xres,info.yres,info.xres_virtual,info.yres_virtual,info.bits_per_pixel,info.red.offset, info.red.length,info.green.offset, info.green.length,info.blue.offset, info.blue.length);ALOGI(   "width        = %d mm (%f dpi)\n""height       = %d mm (%f dpi)\n""refresh rate = %.2f Hz\n",info.width,  xdpi,info.height, ydpi,fps);if (ioctl(fd, FBIOGET_FSCREENINFO, &finfo) == -1)return -errno;if (finfo.smem_len <= 0)return -errno;module->flags = flags;module->info = info;module->finfo = finfo;module->xdpi = xdpi;module->ydpi = ydpi;module->fps = fps;//帧率/** map the framebuffer*/size_t fbSize = roundUpToPageSize(finfo.line_length * info.yres_virtual);module->framebuffer = new private_handle_t(dup(fd), fbSize, 0);//设置pagerFlip的缓存数量module->numBuffers = info.yres_virtual / info.yres;module->bufferMask = 0;//通过mmap映射得到一个地址void* vaddr = mmap(0, fbSize, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);if (vaddr == MAP_FAILED) {ALOGE("Error mapping the framebuffer (%s)", strerror(errno));return -errno;}//把地址赋值过去module->framebuffer->base = intptr_t(vaddr);//最终把这里空间全部置为0memset(vaddr, 0, fbSize);return 0;
}
2.2.2GPU打开流程

​ GPU的打开流程在上面已经大概描述过,也是通过gralloc_device_open打开的。函数主要是用来创建一个gralloc_context_t结构体,并且对它的成员变量device进行初始化。结构体gralloc_context_t的成员变量device的类型为gralloc_device_t,它用来描述一个gralloc设备。前面提到,gralloc设备是用来分配和释放图形缓冲区的,这是通过调用它的成员函数alloc和free来实现的。函数gralloc_device_open所打开的gralloc设备的成员函数alloc和free分别被设置为Gralloc模块中的函数gralloc_alloc和gralloc_free。

参考:(133条消息) Android图形显示之硬件抽象层Gralloc_android gralloc_快乐安卓的博客-CSDN博客

Q1: YUV存储图像格式的方式?

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

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

相关文章

安全漏洞的检测利用

安全漏洞的检测&利用 一、安全漏洞的基本概念1.1、什么是漏洞1.2、漏洞的简单理解1.3、微软的RPC漏洞与蠕虫病毒1.4、微软经典的蓝屏漏洞1.5、Heartbleed&#xff08;心脏滴血&#xff09;漏洞1.6、破壳漏洞CVE-2014-62711.7、漏洞的危害1.8、漏洞的成因1.9、漏洞的信息的组…

electron+vue3全家桶+vite项目搭建【21】自定义窗口拖拽移动

引入 如果你尝试过透明窗口&#xff0c;并控制透明部分事件击穿&#xff0c;就会发现使用 drag属性样式去控制窗口拖拽会导致点击事件失效&#xff0c;并且带drag属性的窗口移动到另一个窗口的透明部分会有窗口乱动的各种BUG&#xff0c;于是&#xff0c;这便需要我们自己去实…

mac上 如何批量在文件名后加相同的文字?

mac上如何批量在文件名后加相同的文字&#xff1f;不管你是使用windows电脑还是使用mac电脑&#xff0c;很多小伙伴都会在电脑上进行文件批量重命名的操作&#xff0c;不过这项操作对于使用windows系统电脑的小伙伴来说会简单一些&#xff0c;因为在网上可以搜索到很多这样的教…

软考:中级软件设计师:计算机体系结构,CISC和RISC,Flynn分类,指令流水线,吞吐率,效率

软考&#xff1a;中级软件设计师:计算机体系结构 提示&#xff1a;系列被面试官问的问题&#xff0c;我自己当时不会&#xff0c;所以下来自己复盘一下&#xff0c;认真学习和总结&#xff0c;以应对未来更多的可能性 关于互联网大厂的笔试面试&#xff0c;都是需要细心准备的…

LabVIEW开发X射线图像增强

LabVIEW开发X射线图像增强 X射线图像在临床诊断中起着重要作用。但是&#xff0c;由于各种原因&#xff0c;例如不均匀&#xff0c;低照度条件和一些噪点&#xff0c;图像质量通常不是很好。因此有必要增强这些图像&#xff0c;以方便后续处理或诊断。模糊集论是开发图像处理中…

SpringBoot第19讲:SpringBoot 如何保证接口幂等

SpringBoot第19讲&#xff1a;SpringBoot 如何保证接口幂等 在以SpringBoot开发Restful接口时&#xff0c;如何防止接口的重复提交呢&#xff1f; 本文是SpringBoot第19讲&#xff0c;主要介绍接口幂等相关的知识点&#xff0c;并实践常见基于Token实现接口幂等。 文章目录 Spr…

LLaMA: Open and Efficient Foundation Language Models

背景 用最少的计算资源&#xff0c;解决了LLM大模型预测问题&#xff0c;训练了一些列的LLaMa模型&#xff0c;在参数量比较少的情况下&#xff0c;达到业界大模型效果。 主要贡献就是提升了LLM模型的训练速度和效率&#xff0c;在小容量的基础上&#xff0c;大大提升了模型的…

基于模型预测算法的混合储能微电网双层能量管理系统研究(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

最长公共子序列LCA

最长连续公共子序列 题目链接:3692. 最长连续公共子序列 - AcWing题库 /*解法:定义dp[i1][j1]为以a[i]结尾的字符串和b[j]结尾的字符串的最长连续公共子序列那么对于a[i] b[j]的时候 dp[i1][j1] dp[i][j]1否则为0 其他就是细枝末节 */ #include<iostream> #include<…

【底部消息红点提示】uniapp开发小程序时,使用uni.setTabBarBadge设置底部菜单的红点

一、实现的效果 功能描述&#xff1a;无论点击底部的哪个菜单栏&#xff0c;都可以看到第二个菜单栏下显示的红点通知。 如果只在人脉当前页面设置的话&#xff0c;当你在第二个菜单栏的页面中调用uni.setTabBarBadge方法设置红点后&#xff0c;切换到第一个菜单栏的页面时&am…

基础算法-前缀和

1 算法笔记 2.代码示例 3.代码解析 #include<iostream> using namespace std; const int maxn 1010000; int a[maxn],s[maxn];//a数组是用来存放数组的&#xff0c;s是用来存放前n项数组的和 int m,n;int main(){scanf("%d%d",&n,&m);for(int i1;i&l…

怎么用转转大师工具旋转PDF文件页面

有时候我们会在网上下载一下PDF格式文件&#xff0c;下载的PDF文件中可能会出现页面倒过来的情况&#xff0c;遇到这种情况我们需要先将PDF文件旋转到正确的角度才能继续阅读使用&#xff0c;那么有哪些方法可以快速旋转PDF页面呢&#xff1f; 可以使用转转大师工具快速旋转PD…