一区二区三区日韩精品-日韩经典一区二区三区-五月激情综合丁香婷婷-欧美精品中文字幕专区

分享

Android6.0 顯示系統(tǒng)(四) 圖像顯示相關

 Elaine個人小館 2017-03-01

Linux通常使用Framebuffer來用作顯示輸出,F(xiàn)ramebuffer就是一塊內(nèi)存區(qū)域,它通常是顯示驅(qū)動的內(nèi)部緩沖區(qū)在內(nèi)存中的映射。一旦用戶進程把圖像數(shù)據(jù)復制到Framebuffer中,顯示驅(qū)動會一個像素一個像素地掃描整個Framebuffer,并根據(jù)其中的值更新屏幕上像素點的顏色。驅(qū)動中這種更新屏幕的動作是固定的,它的周期就是我們常說的刷新率。

但是在屏幕更新一半時,用戶進程更新了Framebuffer中的數(shù)據(jù),將導致屏幕上畫面的上半部分是前一幀的畫面,下半部分變成了新的畫面。當然錯誤會在下次刷新時糾正過來,但是這樣也會有閃爍的感覺。這個可以使用雙緩沖機制,雙緩沖就是提供兩塊Framebuffer,一塊用于顯示,一塊用于數(shù)據(jù)更新。數(shù)據(jù)準備好后,通過ioctl操作告訴顯示設備切換用于顯示的FrameBuffer,這樣圖像就能快速的顯示出來。

但是雙緩沖并沒有完全解決問題,雖然雙緩沖切換的速度很快,但是如果切換的時間點不對,在畫面更新一半的時候切換,還是會出現(xiàn)閃爍的問題。當然,我們可以在底層進行控制,收到切換請求的時候,內(nèi)部并不馬上執(zhí)行,等到刷新完成后再切換,這樣完全避免了畫面重疊問題。但是這樣也有問題,如果用ioctl操作告訴底層可以進行切換了,但是緩沖區(qū)沒有切換,這樣應用層就不能確定何時可以再使用緩沖區(qū),因此只能不斷的通過ioctl來查詢緩沖區(qū)的狀態(tài),一直到切換完成了。這種方式效率太低,拖慢了整個系統(tǒng)。解決這個問題就是底層固定發(fā)送信號給用戶進程,通知進程切換的時機。這個信號就是VSync信號。

VSync信號是一個硬件信號,一般是顯示設備刷新的周期到了會發(fā)送。

一、VSync信號的產(chǎn)生

Android通過VSync機制來提高顯示效果,那么VSync是如何產(chǎn)生的?通常這個信號是由顯示驅(qū)動產(chǎn)生,這樣才能達到最佳效果。但是Android為了能運行在不支持VSync機制的設備上,也提供了軟件模擬產(chǎn)生VSync信號的手段。

SurfaceFlinger中用HWComposer類來表示硬件顯示設備,

HWComposer::HWComposer( const sp& flinger, EventHandler& handler) : mFlinger(flinger), mFbDev(0), mHwc(0), mNumDisplays(1), mCBContext(new cb_context), mEventHandler(handler), mDebugForceFakeVSync(false){ ...... bool needVSyncThread = true; // Note: some devices may insist that the FB HAL be opened before HWC. int fberr = loadFbHalModule();//裝載FrameBuffer的硬件模塊 loadHwcModule();//裝載HWComposer的硬件模塊,這個函數(shù)中會將mHwc置為true ...... if (mHwc) {//這個為true代表硬件設備打開了 ALOGI('Using %s version %u.%u', HWC_HARDWARE_COMPOSER, (hwcApiVersion(mHwc) >> 24) & 0xff, (hwcApiVersion(mHwc) >> 16) & 0xff); if (mHwc->registerProcs) { mCBContext->hwc = this; mCBContext->procs.invalidate = &hook_invalidate; mCBContext->procs.vsync = &hook_vsync;//vsync回調(diào)函數(shù) if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) mCBContext->procs.hotplug = &hook_hotplug; else mCBContext->procs.hotplug = NULL; memset(mCBContext->procs.zero, 0, sizeof(mCBContext->procs.zero)); mHwc->registerProcs(mHwc, &mCBContext->procs); } // don't need a vsync thread if we have a hardware composer needVSyncThread = false;//打開硬件設備成功了,將needVSncThread為false ...... } ...... if (needVSyncThread) { // we don't have VSYNC support, we need to fake it mVSyncThread = new VSyncThread(*this); }}

通過loadHwcModule來裝載硬件模塊,如果成功,mHwc為true,needVSyncThread為false。如果不成功,needVsyncThread為true,然后就要創(chuàng)建VSyncThread對象了,它就是產(chǎn)生VSync信號的軟件手段了。

VSyncThread是一個thread,在onFirstRef中會調(diào)用run函數(shù),就是執(zhí)行threadLoop,這個函數(shù)只要返回true就會一直執(zhí)行。

bool HWComposer::VSyncThread::threadLoop() { { // scope for lock Mutex::Autolock _l(mLock); while (!mEnabled) { mCondition.wait(mLock); } } const nsecs_t period = mRefreshPeriod; const nsecs_t now = systemTime(CLOCK_MONOTONIC); nsecs_t next_vsync = mNextFakeVSync; nsecs_t sleep = next_vsync - now; if (sleep < 0) { // we missed, find where the next vsync should be sleep = (period - ((now - next_vsync) % period)); next_vsync = now + sleep; } mNextFakeVSync = next_vsync + period; struct timespec spec; spec.tv_sec = next_vsync / 1000000000; spec.tv_nsec = next_vsync % 1000000000; int err; do { err = clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &spec, NULL); } while (err<0 && errno == EINTR); if (err == 0) { mHwc.mEventHandler.onVSyncReceived(0, next_vsync); } return true;}

這個函數(shù)會間隔模擬產(chǎn)生VSync的信號的原理是在固定時間發(fā)送消息給HWCompoer的消息對象mEventHandler,這個其實就到SurfaceFlinger的onVSyncReceived函數(shù)了。用軟件模擬VSync信號在系統(tǒng)比較忙的時候可能會丟失一些信號。

Android源碼再hardware/lib/libhardware/modules下有一個hwcomposer目錄,里面是一個Android提供的缺省的硬件HWComposer模塊的例子,這個例子只實現(xiàn)了一個open接口,并不能真正工作。在前面HWComposer的構(gòu)造函數(shù)中,有如下代碼

mCBContext->procs.vsync = &hook_vsync;

這里指定了vsync的回調(diào)函數(shù)是hook_vsync,如果硬件中產(chǎn)生了VSync信號,將通過這個函數(shù)來通知上層,看看它的代碼:

void HWComposer::hook_vsync(const struct hwc_procs* procs, int disp, int64_t timestamp) { cb_context* ctx = reinterpret_cast( const_cast(procs)); ctx->hwc->vsync(disp, timestamp);}

然后又調(diào)用了vsync函數(shù),這個函數(shù)最后也是調(diào)用了mEventHandler.onVSyncReceived函數(shù),這個函數(shù)最后回到SurfaceFlinger中的onVsyncReceived函數(shù)中。

void HWComposer::vsync(int disp, int64_t timestamp) { if (uint32_t(disp) < HWC_NUM_PHYSICAL_DISPLAY_TYPES) { { Mutex::Autolock _l(mLock); // There have been reports of HWCs that signal several vsync events // with the same timestamp when turning the display off and on. This // is a bug in the HWC implementation, but filter the extra events // out here so they don't cause havoc downstream. if (timestamp == mLastHwVSync[disp]) { ALOGW('Ignoring duplicate VSYNC event from HWC (t=%' PRId64 ')', timestamp); return; } mLastHwVSync[disp] = timestamp; } char tag[16]; snprintf(tag, sizeof(tag), 'HW_VSYNC_%1u', disp); ATRACE_INT(tag, ++mVSyncCounts[disp] & 1); mEventHandler.onVSyncReceived(disp, timestamp); }}

二、FrameBuffer工作原理

我們先來看下loadFbHalModule函數(shù),hw_get_module是HAl框架中裝載HAL模塊的函數(shù)

int HWComposer::loadFbHalModule(){ hw_module_t const* module; int err = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module); if (err != 0) { ALOGE('%s module not found', GRALLOC_HARDWARE_MODULE_ID); return err; } return framebuffer_open(module, &mFbDev);}

我們再來看看framebuffer_open函數(shù),

static inline int framebuffer_open(const struct hw_module_t* module, struct framebuffer_device_t** device) { return module->methods->open(module, GRALLOC_HARDWARE_FB0, (struct hw_device_t**)device);}

GRALLOC_HARDWARE_FB0 就是fb0

#define GRALLOC_HARDWARE_FB0 'fb0'

Gralloc模塊在實際設備中有硬件廠商提供。我們來看下這個open函數(shù)

static int gralloc_device_open(const hw_module_t* module, const char* name, hw_device_t** device){ int status = -EINVAL; if (!strncmp(name, GRALLOC_HARDWARE_GPU0, MALI_GRALLOC_HARDWARE_MAX_STR_LEN)) { status = alloc_device_open(module, name, device);//處理gpu的 } else if (!strncmp(name, GRALLOC_HARDWARE_FB0, MALI_GRALLOC_HARDWARE_MAX_STR_LEN)) { status = framebuffer_device_open(module, name, device); } return status;}

我們來看framebuffer_device_open函數(shù),如果不支持framebuffer直接退出了(現(xiàn)在很多設備都開始不支持了)。如果支持framebuffer的話先是調(diào)用了init_frame_buffer函數(shù)來獲取設備信息,通過mmap分配一塊共享內(nèi)存,然后設置FrameBuffer的操作函數(shù)等。

int framebuffer_device_open(hw_module_t const* module, const char* name, hw_device_t** device){ int status = -EINVAL; log_fbpost = false; char property[PROPERTY_VALUE_MAX]; if(property_get('debug.gralloc.fbpost', property, '0') > 0) { if(atoi(property) == 1) { log_fbpost = true; ALOGI('enable fbpost log!'); } } alloc_device_t* gralloc_device;#if DISABLE_FRAMEBUFFER_HAL == 1 //不支持FrameBuffer AERR('Framebuffer HAL not support/disabled %s',#ifdef MALI_DISPLAY_VERSION 'with MALI display enable');#else '');#endif return -ENODEV;#endif status = gralloc_open(module, &gralloc_device); if (status < 0) { return status; } private_module_t* m = (private_module_t*)module; status = init_frame_buffer(m); framebuffer_device_t *dev = reinterpret_cast (malloc(sizeof(framebuffer_device_t))); /* if either or both of init_frame_buffer() and malloc failed */ if ((status < 0) || (!dev)) { gralloc_close(gralloc_device); (!dev) ? (void)(status = -ENOMEM) : free(dev); return status; } memset(dev, 0, sizeof(*dev)); //設置framebuffer的操作函數(shù) dev->common.tag = HARDWARE_DEVICE_TAG; dev->common.version = 0; dev->common.module = const_cast(module); dev->common.close = fb_close; dev->setSwapInterval = fb_set_swap_interval; dev->post = fb_post; dev->enableScreen = fb_enable_screen; dev->setUpdateRect = 0; dev->compositionComplete = &compositionComplete; int stride = m->finfo.line_length / (m->info.bits_per_pixel >> 3); const_cast(dev->flags) = 0; const_cast(dev->width) = m->info.xres; const_cast(dev->height) = m->info.yres; const_cast(dev->stride) = stride; const_cast(dev->format) = m->fbFormat; const_cast(dev->xdpi) = m->xdpi; const_cast(dev->ydpi) = m->ydpi; const_cast(dev->fps) = m->fps; const_cast(dev->minSwapInterval) = 0; const_cast(dev->maxSwapInterval) = 1; const_cast(dev->numFramebuffers) = m->numBuffers; *device = &dev->common; AINF('%s line %d format %d numBuffers %d',__FUNCTION__,__LINE__, dev->format, m->numBuffers); //init dynamic lcd fps adjustment dyn_fps_init(m);#if GRALLOC_VSYNC_NEEDED == 1 gralloc_vsync_enable(dev);//支持vsync#endif gralloc_close(gralloc_device); return status;}

init_frame_buffer函數(shù)主要調(diào)用了init_frame_buffer_locked函數(shù)

static int init_frame_buffer(struct private_module_t* module){ pthread_mutex_lock(&module->lock); int err = init_frame_buffer_locked(module); pthread_mutex_unlock(&module->lock); return err;}

我們來看看init_frame_buffer_locked函數(shù),先打開設備列表中的一個設備即可,然后通過ioctl獲取設備信息,把設備信息放到module中,后面通過mmap分配一塊共享內(nèi)存。

int init_frame_buffer_locked(struct private_module_t* module){ if (module->framebuffer) { return 0; // Nothing to do, already initialized } char const * const device_template[] =//設備列表 { '/dev/graphics/fb%u', '/dev/fb%u', NULL }; 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; if(info.bits_per_pixel == 32) { /* * Explicitly request 8/8/8 */ info.bits_per_pixel = 32; info.red.offset = 16; info.red.length = 8; info.green.offset = 8; info.green.length = 8; info.blue.offset = 0; info.blue.length = 8; info.transp.offset = 24; info.transp.length = 8; } else { /* * Explicitly request 5/6/5 */ info.bits_per_pixel = 16; info.red.offset = 11; info.red.length = 5; info.green.offset = 5; info.green.length = 6; info.blue.offset = 0; info.blue.length = 5; info.transp.offset = 0; info.transp.length = 0; } /* * Request NUM_BUFFERS screens (at lest 2 for page flipping) */ info.yres_virtual = info.yres * NUM_BUFFERS; uint32_t flags = PAGE_FLIP; if (ioctl(fd, FBIOPUT_VSCREENINFO, &info) == -1) { info.yres_virtual = info.yres; flags &= ~PAGE_FLIP; AWAR( 'FBIOPUT_VSCREENINFO failed, page flipping not supported fd: %d', fd ); } if (info.yres_virtual < info.yres * 2) { // we need at least 2 for page-flipping info.yres_virtual = info.yres; flags &= ~PAGE_FLIP; AWAR( 'page flipping not supported (yres_virtual=%d, requested=%d)', info.yres_virtual, info.yres*2 ); } if (ioctl(fd, FBIOGET_VSCREENINFO, &info) == -1) { return -errno; } int refreshRate = 0; if ( info.pixclock > 0 ) { refreshRate = 1000000000000000LLU / ( uint64_t( info.upper_margin + info.lower_margin + info.yres + info.hsync_len ) * ( info.left_margin + info.right_margin + info.xres + info.vsync_len ) * info.pixclock ); } else { AWAR( 'fbdev pixclock is zero for fd: %d', fd ); } if (refreshRate == 0) { refreshRate = 60*1000; // 60 Hz } if (int(info.width) <= 0 || int(info.height) <= 0) { // the driver doesn't return that information // default to 320 dpi // debugging stuff... char value[PROPERTY_VALUE_MAX]; int lcd_density; property_get('ro.sf.lcd_density', value, '320'); lcd_density = atoi(value); info.width = ((info.xres * 25.4f) / (float)lcd_density + 0.5f); info.height = ((info.yres * 25.4f) / (float)lcd_density + 0.5f); } float xdpi = (info.xres * 25.4f) / info.width; float ydpi = (info.yres * 25.4f) / info.height; float fps = refreshRate / 1000.0f; AINF('leadcore fb 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); AINF('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 (0 == strncmp(finfo.id, 'CLCD FB', 7)) { module->dpy_type = MALI_DPY_TYPE_CLCD; } else if (0 == strncmp(finfo.id, 'ARM Mali HDLCD', 14)) { module->dpy_type = MALI_DPY_TYPE_HDLCD; } else { module->dpy_type = MALI_DPY_TYPE_UNKNOWN; } if (ioctl(fd, FBIOGET_FSCREENINFO, &finfo) == -1) { return -errno; } if (finfo.smem_len <= 0) { return -errno; } if( info.bits_per_pixel == 32 && info.red.offset == 16 && info.red.length == 8 && info.green.offset == 8 && info.green.length == 8 && info.blue.offset == 0 && info.blue.length == 8) { module->fbFormat = HAL_PIXEL_FORMAT_BGRA_8888; } if( 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) { module->fbFormat = HAL_PIXEL_FORMAT_RGBA_8888; } if( info.bits_per_pixel == 16 && info.red.offset == 0 && info.red.length == 5 && info.green.offset == 5 && info.green.length == 6 && info.blue.offset == 11 && info.blue.length == 5) { module->fbFormat = HAL_PIXEL_FORMAT_RGB_565; } module->flags = flags;//設置信息 module->info = info; module->finfo = finfo; module->xdpi = xdpi; module->ydpi = ydpi; module->fps = fps; module->swapInterval = 1; /* * map the framebuffer */ size_t fbSize = round_up_to_page_size(finfo.line_length * info.yres_virtual); void* vaddr = mmap(0, fbSize, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);//mmap分配一塊共享內(nèi)存 if (vaddr == MAP_FAILED) { AERR( 'Error mapping the framebuffer (%s)', strerror(errno) ); return -errno; } //fix black screen between uboot logo and bootanimation //memset(vaddr, 0, fbSize); // Create a 'fake' buffer object for the entire frame buffer memory, and store it in the module module->framebuffer = new private_handle_t(private_handle_t::PRIV_FLAGS_FRAMEBUFFER, GRALLOC_USAGE_HW_FB, fbSize, vaddr, 0, dup(fd), 0, 0); module->numBuffers = info.yres_virtual / info.yres; module->bufferMask = 0; return 0;}

最后我們再來看看framebuffer的操作函數(shù)fb_post,這個函數(shù)根據(jù)PRIV_FLAGS_FRAMEBUFFER來判斷Framebuffer是否支持多緩沖,如果不支持方法很簡單,直接把buffer中的數(shù)據(jù)復制到Framebuffer中就可以了。

Filp是指使用ioctl的FBIOPUT_VSCREENINFO參數(shù)設置當前顯示的buffer。通過將顯示區(qū)域指向Framebuffer中的新的數(shù)據(jù)幀,能非常迅速地完成buffer的切換。單緩沖模式下數(shù)據(jù)復制到緩沖區(qū)還需要一定時間,會加重閃爍感,通過Filp的方式切換緩沖區(qū)就不存在這個問題了。

static int fb_post(struct framebuffer_device_t* dev, buffer_handle_t buffer){ if (private_handle_t::validate(buffer) < 0) { return -EINVAL; } private_handle_t const* hnd = reinterpret_cast(buffer); private_module_t* m = reinterpret_cast(dev->common.module); if (m->currentBuffer) { m->base.unlock(&m->base, m->currentBuffer); m->currentBuffer = 0; } struct timeval tv1, tv2; if (hnd->flags & private_handle_t::PRIV_FLAGS_FRAMEBUFFER) //framebuffer是否支持多緩沖區(qū)(flip) { m->base.lock(&m->base, buffer, private_module_t::PRIV_USAGE_LOCKED_FOR_POST, 0, 0, m->info.xres, m->info.yres, NULL); const size_t offset = (uintptr_t)hnd->base - (uintptr_t)m->framebuffer->base; int interrupt; m->info.activate = FB_ACTIVATE_VBL; m->info.yoffset = offset / m->finfo.line_length; up_fps(m); gettimeofday(&tv1, NULL); if (ioctl(m->framebuffer->fd, FBIOPUT_VSCREENINFO, &m->info) == -1) { AERR( 'FBIOPUT_VSCREENINFO failed for fd: %d', m->framebuffer->fd ); m->base.unlock(&m->base, buffer); return -errno; }#if GRALLOC_VSYNC_NEEDED if ( 0 != gralloc_wait_for_vsync(dev) ) { AERR( 'Gralloc wait for vsync failed for fd: %d', m->framebuffer->fd ); m->base.unlock(&m->base, buffer); return -errno; }#endif gettimeofday(&tv2, NULL); if((int64_t)tv2.tv_sec * 1000 + tv2.tv_usec/1000 - (int64_t)tv1.tv_sec * 1000 - tv1.tv_usec/1000 > 50) { ALOGI('%s line %d FBIOPUT_VSCREENINFO buffer %p blocktime=%lldms now=%lldms lasttime=%lld tid=%d',__FUNCTION__,__LINE__, buffer, (int64_t)tv2.tv_sec * 1000 + tv2.tv_usec/1000 - (int64_t)tv1.tv_sec * 1000 - tv1.tv_usec/1000, systemTime(CLOCK_MONOTONIC)/1000000, (int64_t)tv2.tv_sec * 1000 + tv2.tv_usec/1000 - lasttime, gettid()); } else { ALOGD_IF(log_fbpost, '%s line %d FBIOPUT_VSCREENINFO buffer %p blocktime=%lldms now=%lldms lasttime=%lld tid=%d',__FUNCTION__,__LINE__, buffer, (int64_t)tv2.tv_sec * 1000 + tv2.tv_usec/1000 - (int64_t)tv1.tv_sec * 1000 - tv1.tv_usec/1000, systemTime(CLOCK_MONOTONIC)/1000000, (int64_t)tv2.tv_sec * 1000 + tv2.tv_usec/1000 - lasttime, gettid()); } lasttime = (int64_t)tv2.tv_sec * 1000 + tv2.tv_usec/1000; postcount++; if(postcount == 1000) { ALOGI('%s line %d avgframerate = %2f',__FUNCTION__,__LINE__, (float)postcount*1000.0/(lasttime - timecount)); postcount = 0; timecount = lasttime; } m->currentBuffer = buffer; } else {//不支持多緩沖(flip) void* fb_vaddr; void* buffer_vaddr; m->base.lock(&m->base, m->framebuffer, GRALLOC_USAGE_SW_WRITE_RARELY, 0, 0, m->info.xres, m->info.yres, &fb_vaddr); m->base.lock(&m->base, buffer, GRALLOC_USAGE_SW_READ_RARELY, 0, 0, m->info.xres, m->info.yres, &buffer_vaddr); // If buffer's alignment match framebuffer alignment we can do a direct copy. // If not we must fallback to do an aligned copy of each line. if ( hnd->byte_stride == (int)m->finfo.line_length ) { memcpy(fb_vaddr, buffer_vaddr, m->finfo.line_length * m->info.yres); } else { uintptr_t fb_offset = 0; uintptr_t buffer_offset = 0; unsigned int i; for (i = 0; i < m->info.yres; i++) { memcpy((void *)((uintptr_t)fb_vaddr + fb_offset), (void *)((uintptr_t)buffer_vaddr + buffer_offset), m->finfo.line_length); fb_offset += m->finfo.line_length; buffer_offset += hnd->byte_stride; } } m->base.unlock(&m->base, buffer); m->base.unlock(&m->base, m->framebuffer); } return 0;}

三、分配圖像緩沖區(qū)的內(nèi)存

之前的博客在GraphicBufferAllocator的alloc方法是調(diào)用了mAllocDev的alloc,而這個mAllocDev也是Gralloc模塊,最后會調(diào)用如下方法。

int gralloc_alloc(struct alloc_device_t* dev, int w, int h, int format, int usage, buffer_handle_t* pHandle, int* pStride){ int rel; /* TODO: Redirect to specific allocator according to usage. */ if (usage & GRALLOC_USAGE_HW_FB) { /* Dispatch to framebuffer allocator. */ rel = gralloc_alloc_framebuffer(dev, w, h, format, usage, pHandle, pStride); } else { rel = gc_gralloc_alloc(dev, w, h, format, usage, pHandle, pStride); } return rel;}

gralloc_alloc函數(shù)會根據(jù)usage中的標志是否有GRALLOC_USAGE_HW_FB來決定是從硬件緩沖中分配緩沖區(qū)還是從普通內(nèi)存分配緩沖區(qū)。我們先看看從內(nèi)存中分配緩沖區(qū)的。

如果不支持framebuffer,只能從普通內(nèi)存中分配緩沖區(qū)。gc_gralloc_alloc函數(shù)是從普通內(nèi)存中分配緩沖區(qū),主要使用了匿名共享內(nèi)存的方法。最后pHandle裝了共享內(nèi)存的fd。

另外從硬件緩沖區(qū)分配內(nèi)存是調(diào)用了gralloc_alloc_framebuffer方法,這個函數(shù)主要調(diào)用了gralloc_alloc_framebuffer_locked方法

static int gralloc_alloc_framebuffer_locked(alloc_device_t* dev, size_t size, int usage, buffer_handle_t* pHandle, int* stride, int* byte_stride){ private_module_t* m = reinterpret_cast(dev->common.module); // allocate the framebuffer if (m->framebuffer == NULL)//如果為空 { // initialize the framebuffer, the framebuffer is mapped once and forever. int err = init_frame_buffer_locked(m);//分配一大塊內(nèi)存 if (err < 0) { return err; } } const uint32_t bufferMask = m->bufferMask; const uint32_t numBuffers = m->numBuffers; /* framebufferSize is used for allocating the handle to the framebuffer and refers * to the size of the actual framebuffer. * alignedFramebufferSize is used for allocating a possible internal buffer and * thus need to consider internal alignment requirements. */ const size_t framebufferSize = m->finfo.line_length * m->info.yres; const size_t alignedFramebufferSize = GRALLOC_ALIGN(m->finfo.line_length, 64) * m->info.yres; *stride = m->info.xres; if (numBuffers == 1)//如果是單緩沖,使用普通內(nèi)存分配 { // If we have only one buffer, we never use page-flipping. Instead, // we return a regular buffer which will be memcpy'ed to the main // screen when post is called. int newUsage = (usage & ~GRALLOC_USAGE_HW_FB) | GRALLOC_USAGE_HW_2D; AWAR( 'fallback to single buffering. Virtual Y-res too small %d', m->info.yres ); *byte_stride = GRALLOC_ALIGN(m->finfo.line_length, 64); return alloc_backend_alloc(dev, alignedFramebufferSize, newUsage, pHandle); } if (bufferMask >= ((1LU<framebuffer->base; // find a free slot for (uint32_t i=0 ; ibufferMask |= (1LU<framebuffer->fd), (framebufferVaddr - (uintptr_t)m->framebuffer->base), 0); /* * Perform allocator specific actions. If these fail we fall back to a regular buffer * which will be memcpy'ed to the main screen when fb_post is called. */ if (alloc_backend_alloc_framebuffer(m, hnd) == -1) { delete hnd; int newUsage = (usage & ~GRALLOC_USAGE_HW_FB) | GRALLOC_USAGE_HW_2D; AERR( 'Fallback to single buffering. Unable to map framebuffer memory to handle:%p', hnd ); *byte_stride = GRALLOC_ALIGN(m->finfo.line_length, 64); return alloc_backend_alloc(dev, alignedFramebufferSize, newUsage, pHandle); } *pHandle = hnd; *byte_stride = m->finfo.line_length; return 0;}
這個函數(shù)如果第一次調(diào)用會調(diào)用init_frame_buffer_locked來從Framebuffer設備上分配一大塊共享內(nèi)存,內(nèi)存的大小是屏幕尺寸的整數(shù)倍。numBuffers是內(nèi)存的塊數(shù),如果只有一塊代表是單緩沖,單緩沖調(diào)用分配普通內(nèi)存的函數(shù)(單內(nèi)存只能分配普通內(nèi)存也很好理解,因為framebuffer的內(nèi)存要用于顯示。重新分配的話只能就分配普通內(nèi)存了)。多緩沖的話使用Framebuffer的內(nèi)存。但是Framebuffer的緩沖區(qū)塊數(shù)也是有限的,因此函數(shù)要找一塊空閑的緩沖區(qū)。如果緩沖區(qū)分配完了,返回錯誤值-ENOMEM。

    本站是提供個人知識管理的網(wǎng)絡存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多

    欧美久久一区二区精品| 美国黑人一级黄色大片| 婷婷九月在线中文字幕| 亚洲一区二区三区av高清| 蜜桃av人妻精品一区二区三区| 激情五月天免费在线观看| 男生和女生哪个更好色| 国产传媒一区二区三区| 大香蕉再在线大香蕉再在线| 日韩精品福利在线观看| 精品al亚洲麻豆一区| 婷婷开心五月亚洲综合| 色哟哟精品一区二区三区| 99久久国产精品免费| 大尺度激情福利视频在线观看| 91国内视频一区二区三区| 欧美极品欧美精品欧美| 日韩一区二区三区18| 中文久久乱码一区二区| 亚洲一区二区亚洲日本 | 情一色一区二区三区四| 国产情侣激情在线对白| 国产精品免费无遮挡不卡视频| 日本少妇中文字幕不卡视频| 日韩欧美高清国内精品| 一区二区三区四区亚洲专区| 麻豆精品在线一区二区三区| 可以在线看的欧美黄片| 99久久精品久久免费| 日本av在线不卡一区| 少妇人妻精品一区二区三区 | 欧美国产精品区一区二区三区 | 国产成人精品综合久久久看| 国产精品蜜桃久久一区二区| 九九热这里只有免费精品| 国产一区二区三区丝袜不卡 | 黑人粗大一区二区三区| 亚洲中文字幕在线乱码av| 91久久国产福利自产拍| 国产精品亚洲综合色区韩国| 久久夜色精品国产高清不卡|