日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 >

Android帧缓冲区(Frame Buffer)硬件抽象层(HAL)模块Gralloc的实现原理分析(10)...

發布時間:2025/7/14 46 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Android帧缓冲区(Frame Buffer)硬件抽象层(HAL)模块Gralloc的实现原理分析(10)... 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

??? ? ? 7. 圖形緩沖區的注銷過程

?? ? ? 圖形緩沖區使用完成之后,就需要從當前進程中注銷。前面提到,注銷圖形緩沖區是由Gralloc模塊中的函數gralloc_unregister_buffer來實現的,這個函數實現在文件hardware/libhardware/modules/gralloc/mapper.cpp中,如下所示:
  • int?gralloc_unregister_buffer(gralloc_module_t?const*?module,??
  • ????????buffer_handle_t?handle)??
  • {??
  • ????if?(private_handle_t::validate(handle)?<?0)??
  • ????????return?-EINVAL;??
  • ??
  • ????//?never?unmap?buffers?that?were?created?in?this?process??
  • ????private_handle_t*?hnd?=?(private_handle_t*)handle;??
  • ????if?(hnd->pid?!=?getpid())?{??
  • ????????if?(hnd->base)?{??
  • ????????????gralloc_unmap(module,?handle);??
  • ????????}??
  • ????}??
  • ????return?0;??
  • }??
  • ?? ? ? ?這個函數同樣是首先調用private_handle_t類的靜態成員函數validate來驗證參數handle指向的一塊圖形緩沖區的確是由Gralloc模塊分配的,接著再將將參數handle指向的一塊圖形緩沖區轉換為一個private_handle_t結構體hnd來訪問。 ?? ? ? ?一塊圖形緩沖區只有被注冊過,即被Gralloc模塊中的函數gralloc_register_buffer注冊過,才需要注銷,而由函數gralloc_register_buffer注冊的圖形緩沖區都不是由當前進程分配的,因此,當前進程在注銷一個圖形緩沖區的時候,會檢查要注銷的圖形緩沖區是否是由自己分配的。如果是由自己分配的話,那么它什么也不做就返回了。 ?? ? ? ?假設要注銷的圖形緩沖區hnd不是由當前進程分配的,那么接下來就會調用另外一個函數galloc_unmap來注銷圖形緩沖區hnd。 ?? ? ? ?函數galloc_unmap也是實現在文件hardware/libhardware/modules/gralloc/mapper.cpp中,如下所示:
  • static?int?gralloc_unmap(gralloc_module_t?const*?module,??
  • ????????buffer_handle_t?handle)??
  • {??
  • ????private_handle_t*?hnd?=?(private_handle_t*)handle;??
  • ????if?(!(hnd->flags?&?private_handle_t::PRIV_FLAGS_FRAMEBUFFER))?{??
  • ????????void*?base?=?(void*)hnd->base;??
  • ????????size_t?size?=?hnd->size;??
  • ????????//LOGD("unmapping?from?%p,?size=%d",?base,?size);??
  • ????????if?(munmap(base,?size)?<?0)?{??
  • ????????????LOGE("Could?not?unmap?%s",?strerror(errno));??
  • ????????}??
  • ????}??
  • ????hnd->base?=?0;??
  • ????return?0;??
  • }??
  • ?? ? ? ?這個函數的實現與前面所分析的函數gralloc_map的實現是類似的,只不過它執行的是相反的操作,即將解除一個指定的圖形緩沖區在當前進程的地址空間中的映射,從而完成對這個圖形緩沖區的注銷工作。 ?? ? ? ?這樣,圖形緩沖區的注銷過程就分析完成了,接下來我們再繼續分析一個圖形緩沖區是如何被渲染到系統幀緩沖區去的,即它的內容是如何繪制在設備顯示屏中的。 ?? ? ? ?8. 圖形緩沖區的渲染過程 ?? ? ? ?用戶空間的應用程序將畫面內容寫入到圖形緩沖區中去之后,還需要將圖形緩沖區渲染到系統幀緩沖區中去,這樣才可以把畫面繪制到設備顯示屏中去。前面提到,渲染圖形緩沖區是由Gralloc模塊中的函數fb_post來實現的,這個函數實現在文件hardware/libhardware/modules/gralloc/framebuffer.cpp中,如下所示:
  • static?int?fb_post(struct?framebuffer_device_t*?dev,?buffer_handle_t?buffer)??
  • {??
  • ????if?(private_handle_t::validate(buffer)?<?0)??
  • ????????return?-EINVAL;??
  • ??
  • ????fb_context_t*?ctx?=?(fb_context_t*)dev;??
  • ??
  • ????private_handle_t?const*?hnd?=?reinterpret_cast<private_handle_t?const*>(buffer);??
  • ????private_module_t*?m?=?reinterpret_cast<private_module_t*>(??
  • ????????????dev->common.module);??
  • ??
  • ????if?(hnd->flags?&?private_handle_t::PRIV_FLAGS_FRAMEBUFFER)?{??
  • ????????const?size_t?offset?=?hnd->base?-?m->framebuffer->base;??
  • ????????m->info.activate?=?FB_ACTIVATE_VBL;??
  • ????????m->info.yoffset?=?offset?/?m->finfo.line_length;??
  • ????????if?(ioctl(m->framebuffer->fd,?FBIOPUT_VSCREENINFO,?&m->info)?==?-1)?{??
  • ????????????LOGE("FBIOPUT_VSCREENINFO?failed");??
  • ????????????m->base.unlock(&m->base,?buffer);??
  • ????????????return?-errno;??
  • ????????}??
  • ????????m->currentBuffer?=?buffer;??
  • ??
  • ????}?else?{??
  • ????????//?If?we?can't?do?the?page_flip,?just?copy?the?buffer?to?the?front???
  • ????????//?FIXME:?use?copybit?HAL?instead?of?memcpy??
  • ??
  • ????????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);??
  • ??
  • ????????memcpy(fb_vaddr,?buffer_vaddr,?m->finfo.line_length?*?m->info.yres);??
  • ??
  • ????????m->base.unlock(&m->base,?buffer);??
  • ????????m->base.unlock(&m->base,?m->framebuffer);??
  • ????}??
  • ??
  • ????return?0;??
  • }??
  • ?? ? ? ?參數buffer用來描述要渲染的圖形緩沖區,它指向的必須要是一個private_handle_t結構體,這是通過調用private_handle_t類的靜態成員函數validate來驗證的。驗證通過之后,就可以將參數buffer所描述的一個buffer_handle_t結構體轉換成一個private_handle_t結構體hnd。 ?? ? ? ?參數dev用來描述在Gralloc模塊中的一個fb設備。從前面第3部分的內容可以知道,在打開fb設備的時候,Gralloc模塊返回給調用者的實際上是一個fb_context_t結構體,因此,這里就可以將參數dev所描述的一個framebuffer_device_t結構體轉換成一個fb_context_t結構體ctx。 ?? ? ? ?參數dev的成員變量common指向了一個hw_device_t結構體,這個結構體的成員變量module指向了一個Gralloc模塊。從前面第1部分的內容可以知道,一個Gralloc模塊是使用一個private_module_t結構體來描述的,因此,我們可以將dev->common.moudle轉換成一個private_module_t結構體m。 ?? ? ? ?由于private_handle_t結構體hnd所描述的圖形緩沖區可能是在系統幀緩沖區分配的,也有可能是內存中分配的,因此,我們分兩種情況來討論圖形緩沖區渲染過程。 ?? ? ? ?當private_handle_t結構體hnd所描述的圖形緩沖區是在系統幀緩沖區中分配的時候,即這個圖形緩沖區的標志值flags的PRIV_FLAGS_FRAMEBUFFER位等于1的時候,我們是不需要將圖形緩沖區的內容拷貝到系統幀緩沖區去的,因為我們將內容寫入到圖形緩沖區的時候,已經相當于是將內容寫入到了系統幀緩沖區中去了。雖然在這種情況下,我們不需要將圖形緩沖區的內容拷貝到系統幀緩沖區去,但是我們需要告訴系統幀緩沖區設備將要渲染的圖形緩沖區作為系統當前的輸出圖形緩沖區,這樣才可以將要渲染的圖形緩沖區的內容繪制到設備顯示屏來。例如,假設系統幀緩沖區有2個圖形緩沖區,當前是以第1個圖形緩沖區作為輸出圖形緩沖區的,這時候如果我們需要渲染第2個圖形緩沖區,那么就必須告訴系統幀繪沖區設備,將第2個圖形緩沖區作為輸出圖形緩沖區。 ?? ? ? 設置系統幀緩沖區的當前輸出圖形緩沖區是通過IO控制命令FBIOPUT_VSCREENINFO來進行的。IO控制命令FBIOPUT_VSCREENINFO需要一個fb_var_screeninfo結構體作為參數。從前面第3部分的內容可以知道,private_module_t結構體m的成員變量info正好保存在我們所需要的這個fb_var_screeninfo結構體。有了個m->info這個fb_var_screeninfo結構體之后,我們只需要設置好它的成員變量yoffset的值(不用設置成員變量xoffset的值是因為所有的圖形緩沖區的寬度是相等的),就可以將要渲染的圖形緩沖區設置為系統幀緩沖區的當前輸出圖形緩沖區。fb_var_screeninfo結構體的成員變量yoffset保存的是當前輸出圖形緩沖區在整個系統幀緩沖區的縱向偏移量,即Y偏移量。我們只需要將要渲染的圖形緩沖區的開始地址hnd->base的值減去系統幀緩沖區的基地址m->framebuffer->base的值,再除以圖形緩沖區一行所占據的字節數m->finfo.line_length,就可以得到所需要的Y偏移量。 ?? ? ? ?在執行IO控制命令FBIOPUT_VSCREENINFO之前,還會將作為參數的fb_var_screeninfo結構體的成員變量activate的值設置FB_ACTIVATE_VBL,表示要等到下一個垂直同步事件出現時,再將當前要渲染的圖形緩沖區的內容繪制出來。這樣做的目的是避免出現屏幕閃爍,即避免前后兩個圖形緩沖區的內容各有一部分同時出現屏幕中。 ?? ? ? ?成功地執行完成IO控制命令FBIOPUT_VSCREENINFO之后,函數還會將當前被渲染的圖形緩沖區保存在private_module_t結構體m的成員變量currentBuffer中,以便可以記錄當前被渲染的圖形緩沖區是哪一個。 ?? ? ? ?當private_handle_t結構體hnd所描述的圖形緩沖區是在內存中分配的時候,即這個圖形緩沖區的標志值flags的PRIV_FLAGS_FRAMEBUFFER位等于0的時候,我們就需要將它的內容拷貝到系統幀緩沖區中去了。這個拷貝的工作是通過調用函數memcpy來完成的。在拷貝之前,我們需要三個參數。第一個參數是要渲染的圖形緩沖區的起址地址,這個地址保存在參數buffer所指向的一個private_handle_t結構體中。第二個參數是要系統幀緩沖區的基地址,這個地址保存在private_module_t結構體m的成員變量framebuffer所指向的一個private_handle_t結構體中。第三個參數是要拷貝的內容的大小,這個大小就剛好是一個屏幕像素所占據的內存的大小。屏幕高度由m->info.yres來描述,而一行屏幕像素所占用的字節數由m->finfo.line_length來描述,將這兩者相乘,就可以得到一個屏幕像素所占據的內存的大小。 ?? ? ? ?在將一塊內存緩沖區的內容拷貝到系統幀緩沖區中去之前,需要對這兩塊緩沖區進行鎖定,以保證在拷貝的過程中,這兩塊緩沖區的內容不會被修改。這個鎖定的工作是由Gralloc模塊中的函數gralloc_lock來實現的。從前面第1部分的內容可以知道,Gralloc模塊中的函數gralloc_lock的地址正好就保存在private_module_t結構體m的成員變量base所描述的一個gralloc_module_t結構體的成員函數lock中。 ?? ? ? ?在調用函數gralloc_lock來鎖定一塊緩沖區之后,還可以通過最后一個輸出參數來獲得被鎖定的緩沖區的開始地址,因此,通過調用函數gralloc_lock來鎖定要渲染的圖形緩沖區以及系統幀緩沖區,就可以得到前面所需要的第一個和第二個參數。 ?? ? ? ?將要渲染的圖形緩沖區的內容拷貝到系統幀緩沖區之后,就可以解除前面對它們的鎖定了,這個解鎖的工作是由Gralloc模塊中的函數gralloc_unlock來實現的。從前面第1部分的內容可以知道,Gralloc模塊中的函數gralloc_unlock的地址正好就保存在private_module_t結構體m的成員變量base所描述的一個gralloc_module_t結構體的成員函數unlock中。 ?? ? ? ?這樣,一個圖形緩沖區的渲染過程就分析完成了。

    總結

    以上是生活随笔為你收集整理的Android帧缓冲区(Frame Buffer)硬件抽象层(HAL)模块Gralloc的实现原理分析(10)...的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。