日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 运维知识 > Android >内容正文

Android

【译】Why Wayland on Android is a hard problem

發(fā)布時(shí)間:2025/3/15 Android 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【译】Why Wayland on Android is a hard problem 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

這是幾個(gè)人問我的問題,而且我已經(jīng)成為一名專家。?有一些嘗試(moste notablly,一個(gè)內(nèi)置于libhybris?)解決這個(gè)問題。?然而,由于Wayland和Android處理EGL和圖形上下文的方式存在差異,因此幾乎不可能真正實(shí)現(xiàn)它的正確性。?在我真正解釋之前,我們需要一些背景知識(shí)。

Wayland EGL

首先,讓我們從客戶在Wayland合成器上獲取GL上下文時(shí)的工作方式開始吧。?從客戶的角度來看,這很簡(jiǎn)單。?它使用EGL中的eglGetDisplay()函數(shù),并為EGL提供了將其轉(zhuǎn)換為NativeDisplayType指針的wl_display指針。?然后,當(dāng)它想要?jiǎng)?chuàng)建一個(gè)窗口時(shí),它調(diào)用wl_egl_window_create()和它想要使用的表面以及獲得wl_egl_window指針的大小。?然后wl_egl_window指針強(qiáng)制轉(zhuǎn)換為NativeWindowType指針并將其傳遞給eglCreateWindowSurface()?。?通過wayland-egl.h的函數(shù)來破壞wl_egl_window以及改變它的大小。?除此之外,客戶端可以使用常規(guī)EGL函數(shù)來處理渲染上下文,就像任何其他EGLSurface并且可以使用Wayland協(xié)議調(diào)用來管理輸入和任何其他Wayland事物。

服務(wù)器對(duì)Wayland EGL表面的看法有點(diǎn)復(fù)雜,但它仍然不錯(cuò)。?服務(wù)器的EGL表面末端通過EGL_WL_bind_wayland_display擴(kuò)展來處理。?在啟動(dòng)時(shí),服務(wù)器調(diào)用eglBindWaylandDisplayWL()和EGL為其提供wl_display指針。?EGL實(shí)現(xiàn)設(shè)置和aditional全局或兩個(gè),并在此時(shí)添加它需要的任何鉤子。?當(dāng)服務(wù)器從客戶端wl_buffer對(duì)象時(shí),它可以使用eglQueryWaylandBufferWL()來獲取緩沖區(qū)的寬度,高度和顏色格式。?為了將緩沖區(qū)綁定為紋理,它使用eglCreateImageKHR()函數(shù),目標(biāo)為EGL_WAYLAND_BUFFER_WL并且從客戶端接收的wl_buffer資源被wl_buffer到EGLClientBuffer?。?然后,合成器可以使用glEGLImageTargetTexture2DOES()將EGLImageKHR綁定為紋理。?它看起來有點(diǎn)復(fù)雜,但它非常簡(jiǎn)單:獲取一個(gè)wl_buffer?,創(chuàng)建一個(gè)EGLImageKHR?,綁定為紋理。

但是從駕駛員的角度來看,這一切看起來如何呢??這就是它開始變得復(fù)雜的地方......

在eglBindWaylandDisplayWL()內(nèi)部,驅(qū)動(dòng)程序向wl_display添加至少一個(gè)全局,它提供了一些創(chuàng)建wl_buffer對(duì)象并將其與物理GPU緩沖區(qū)相關(guān)聯(lián)的方法。?在客戶端實(shí)現(xiàn)中,它獲取GPU緩沖區(qū),允許客戶端呈現(xiàn)給它們,然后使用wl_surface.commit()將緩沖區(qū)交給服務(wù)器。eglSwapBuffers()調(diào)用的一般過程如下:

  • 獲取與客戶端剛剛完成呈現(xiàn)的緩沖區(qū)對(duì)應(yīng)的wl_buffer對(duì)象。
  • 使用給定的緩沖區(qū)調(diào)用wl_surface.attach()。
  • 調(diào)用wl_surface.damage()來破壞整個(gè)緩沖區(qū)。?(最好使用wl_surface.damage(INT32_MIN, INT32_MIN, UINT32_MAX, UINT32_MAX)?。)
  • 調(diào)用wl_surface.commit()來應(yīng)用客戶端的更改
  • EGL實(shí)現(xiàn)調(diào)用wl_surface.commit()而不是將其留給客戶端的原因是它允許客戶端在簡(jiǎn)單的渲染循環(huán)中運(yùn)行而不涉及實(shí)際的Wayland調(diào)用。?渲染所需的一切都隱藏在eglSwapBuffers()?。

    到目前為止,還沒那么糟糕。?事物變得多毛的是同步的。?需要eglSwapBuffers()?(根據(jù)規(guī)范)執(zhí)行隱式glFlus()操作,以保證客戶端在調(diào)用eglSwapBuffers()之前呈現(xiàn)的所有內(nèi)容都在屏幕上結(jié)束。?從服務(wù)器的角度來看,它從客戶端獲取一個(gè)wl_buffer?,并假設(shè)它可以自由地將其綁定為紋理并立即使用它進(jìn)行渲染。?Wayland協(xié)議沒有說緩沖和渲染同步?。?這聽起來很糟糕,但它在現(xiàn)實(shí)中非常有效,因?yàn)樗试S驅(qū)動(dòng)程序使用它想要的任何同步原語(yǔ),而不限制它現(xiàn)在必須實(shí)現(xiàn)的Wayland特定的同步對(duì)象。?為了正確處理同步,EGL實(shí)現(xiàn)為Wayland客戶端/服務(wù)器提供以下兩個(gè)保證:

  • eglSwapBuffers(或eglSwapBuffersWithDamageEXT)必須在返回之前調(diào)用wl_display.attach,wl_display.damage和wl_display.commit。?這樣客戶端就可以將各種表面狀態(tài)位與wl_display.commit請(qǐng)求同步。?它是否發(fā)生在另一個(gè)線程中并不重要,只是它發(fā)生在eglSwapBuffers reutnrs時(shí)。

  • 只要合成器獲得wl_surface.attach,就可以將該緩沖區(qū)資源自由地傳遞到類型為EGL_WAYLAND_BUFFER_WL的eglCreateImageKHR中,將其轉(zhuǎn)換為紋理,并立即開始繪制。

  • 究竟如何滿足這兩個(gè)約束取決于EGL的實(shí)現(xiàn)。?在某些特定的圖形堆棧中,?glFinish()在eglSwapBuffers()內(nèi)部調(diào)用,以確保圖形卡在將緩沖區(qū)傳遞給合成器之前已完成緩沖區(qū)。?但是,這會(huì)導(dǎo)致GPU停滯并降低性能。?大多數(shù)驅(qū)動(dòng)程序通過使用與每個(gè)緩沖區(qū)關(guān)聯(lián)的柵欄來解決此問題。在調(diào)用wl_surface.attach/damage/commit之前,等待緩沖區(qū)完成而不是eglSwapBuffers()?,它們?cè)O(shè)置了一個(gè)同步圍欄,調(diào)用wl_surface.attach/damage/commit,并立即返回。?然后,他們使用圍欄在流的下游某處序列化渲染命令。?這可能意味著eglCreateImageKHR()阻塞等待緩沖區(qū)完成,或者您將柵欄進(jìn)一步向下傳遞并阻止在glBindTexture()或者甚至只是使用它來將命令序列化到GPU。?如何創(chuàng)建,傳遞和等待圍欄是EGL實(shí)現(xiàn)的內(nèi)部細(xì)節(jié),并且超出了Wayland核心協(xié)議的范圍。

    關(guān)于wl_surface.frame事件的最后一個(gè)注釋。?此事件與緩沖區(qū)或GPU上發(fā)生的事情無關(guān)。?它的存在唯一的目的是告訴客戶端合成器已經(jīng)開始使用當(dāng)前連接的緩沖區(qū)進(jìn)行渲染,并且它可以繼續(xù)并開始渲染它的下一幀。?在很多情況下,驅(qū)動(dòng)程序并不關(guān)心此事件,但它對(duì)于實(shí)現(xiàn)eglSwapInterval(1)或類似事件非常有用。

    Android EGL

    好了,既然我們已經(jīng)給Wayland EGL做了一個(gè)簡(jiǎn)短的介紹,讓我們來談?wù)凙ndroid。?Android通過使用有時(shí)稱為meta-EGL的實(shí)現(xiàn)其圖形堆棧:包含另一個(gè)EGL實(shí)現(xiàn)的EGL實(shí)現(xiàn)。?這允許Android OS跟蹤一些內(nèi)容,并在核心驅(qū)動(dòng)程序EGL實(shí)現(xiàn)提供的基礎(chǔ)上提供額外的擴(kuò)展。?然而,我們關(guān)心的大部分內(nèi)容實(shí)際上都在驅(qū)動(dòng)程序EGL實(shí)現(xiàn)中。

    對(duì)于客戶端,Android提供了一個(gè)名為ANativeWindow的數(shù)據(jù)結(jié)構(gòu),由顯示服務(wù)器實(shí)現(xiàn)。?(對(duì)于純android,這是SurfaceFlinger。)顯示服務(wù)器使用一些魔法將此結(jié)構(gòu)傳遞給客戶端,客戶端將其傳遞給eglCreateWindowSurface()?。?然后,EGL實(shí)現(xiàn)使用ANativeWindow結(jié)構(gòu)內(nèi)部的函數(shù)指針從隊(duì)列中獲取緩沖區(qū),渲染它們,然后將它們傳遞回顯示服務(wù)器進(jìn)行顯示。?ANativeWindow結(jié)構(gòu)還包含使用基于文件描述符的柵欄同步渲染的機(jī)制。?我們關(guān)心的函數(shù)指針如下:

    • dequeueBuffer()?:驅(qū)動(dòng)程序使用它從窗口系統(tǒng)的緩沖區(qū)隊(duì)列中獲取該窗口的緩沖區(qū)。ANativeWindow接口的實(shí)現(xiàn)者負(fù)責(zé)通過gralloc分配一些緩沖區(qū),并在驅(qū)動(dòng)程序調(diào)用dequeueBuffer()時(shí)將它們分發(fā)出去。

    • queueBuffer()?:驅(qū)動(dòng)程序調(diào)用dequeueBuffer()緩沖區(qū)(先前從dequeueBuffer()檢索)傳回窗口系統(tǒng)進(jìn)行合成。?對(duì)此函數(shù)唯一真正的要求是緩沖區(qū)必須來自此ANativeWindow上的dequeueBuffer()?,并且緩沖區(qū)必須按照它們被dequed的相同順序排隊(duì)。

    • cancelBuffer()?:驅(qū)動(dòng)程序調(diào)用它來告訴它它不打算使用它先前出列的緩沖區(qū)。

    • perform()?:此函數(shù)用于執(zhí)行各種操作,例如設(shè)置曲面的大小或更改顏色格式。?調(diào)用執(zhí)行來自客戶端(而不是驅(qū)動(dòng)程序)通過一組內(nèi)聯(lián)包裝函數(shù),如native_window_set_buffers_diemnsions()?。

    從服務(wù)器的角度來看,它必須找到一些方法通過IPC將這些ANativeWindow結(jié)構(gòu)傳遞給客戶端,并在客戶端實(shí)現(xiàn)函數(shù)指針。?這怎么發(fā)生并不重要。?結(jié)構(gòu)中的所有內(nèi)容都是基本的二進(jìn)制數(shù)據(jù)和一些文件描述符。?顯示服務(wù)器還負(fù)責(zé)分配緩沖區(qū)并在需要時(shí)將它們交給EGL實(shí)現(xiàn)。?緩沖區(qū)由ANativeBuffer表示,它只是整數(shù)和文件描述符的集合。?使用Android的“gralloc”模塊分配緩沖區(qū),這不在本文的討論范圍之內(nèi)。?顯示服務(wù)器是否在服務(wù)器進(jìn)程中分配緩沖區(qū)并將它們傳遞給客戶端或在客戶端進(jìn)程中分配它們并將它們傳遞給服務(wù)器無關(guān)緊要。?關(guān)鍵是EGL實(shí)現(xiàn)可以通過ANativeWindow訪問緩沖區(qū)隊(duì)列,并使用gralloc分配它們。

    值得注意的是,Android對(duì)如何調(diào)用這些函數(shù)的限制很少。?已經(jīng)提到過,緩沖區(qū)必須按照它們出列的順序排隊(duì)或取消。?但是,Android沒有與輸入或窗口幾何體更改同步的要求。?實(shí)際上,在大多數(shù)Android應(yīng)用程序中,每次幾何體因?yàn)樵O(shè)備旋轉(zhuǎn)或應(yīng)用程序全屏而發(fā)生變化時(shí),整個(gè)UI都會(huì)被破壞并重新創(chuàng)建。?這與Wayland的“每一幀都是完美的”口頭禪是截然不同的。

    Wayland + Android

    好吧,當(dāng)我們采用這兩個(gè)并嘗試讓W(xué)ayland在Android世界中工作時(shí)會(huì)發(fā)生什么。?事實(shí)證明,這非常有效。?libhybris項(xiàng)目有一個(gè)實(shí)現(xiàn),至少在某些硬件上運(yùn)行得很好,?Jolla?(以及其他)正在運(yùn)行在其上運(yùn)行的設(shè)備。?雖然它在某些硬件上運(yùn)行良好,但在一般情況下還遠(yuǎn)非完美。?真的,這不是libhybris開發(fā)人員的錯(cuò),而是Wayland和Android思維方式的核心沖突。

    libhybris的工作方式(以及任何其他尋求做同樣事情的實(shí)現(xiàn))是通過編寫另一個(gè)meta-EGL層。meta-EGL提供了一個(gè)支持EGL_WL_bind_wayland_display擴(kuò)展的EGL實(shí)現(xiàn),并使用ANativeWindow下的ANativeWindow實(shí)現(xiàn)它。?ANativeWindow結(jié)構(gòu)通常或多或少地實(shí)現(xiàn)如下:

    • dequeueBuffer()?:如果已存在足夠的曲面,請(qǐng)從隊(duì)列中抓取一個(gè)并將其交還給驅(qū)動(dòng)程序。?如果它需要一個(gè)新的表面,它通過Wayland協(xié)議發(fā)送與驅(qū)動(dòng)程序的服務(wù)器端的通信,以分配一個(gè)新的緩沖區(qū)并獲得一個(gè)wl_buffer對(duì)象。?客戶端是否從gralloc獲取緩沖區(qū)并將其交給服務(wù)器或服務(wù)器分配緩沖區(qū)并將其交給客戶端并不重要。?libhybris庫(kù)目前是前者,但后者也可以完成,我已經(jīng)考慮過這樣做了。

    • queueBuffer()?:通常,這會(huì)調(diào)用attach(使用驅(qū)動(dòng)程序給它的緩沖區(qū)),損壞和提交。?這是(sort-of)由驅(qū)動(dòng)程序的SwapBuffers()函數(shù)調(diào)用的。

    • cancelBuffer()?:是的,這應(yīng)該是顯而易見的。

    • perform()?:未使用。?這些操作可以通過Wayland協(xié)議直接完成,也可以通過作用于wl_egl_window結(jié)構(gòu)的函數(shù)完成。

    現(xiàn)在滾動(dòng)回Wayland部分,看看每個(gè)支持Wayland的EGL實(shí)現(xiàn)應(yīng)該提供的兩個(gè)要求。?第二個(gè)是相當(dāng)容易的,因?yàn)锳ndroid已經(jīng)提供了一個(gè)fence機(jī)制。?事實(shí)證明,第一個(gè)幾乎不可能實(shí)際滿足。

    真正的問題來自于Android沒有提供關(guān)于驅(qū)動(dòng)程序在eglSwapBuffers中必須做什么的真正保證。?在某些時(shí)候,驅(qū)動(dòng)程序會(huì)將客戶端呈現(xiàn)的緩沖區(qū)放回到使用ANativeWindow.queueBuffer()的隊(duì)列中,但它可能會(huì)在將來的某個(gè)時(shí)刻或從另一個(gè)線程執(zhí)行此操作。?更糟糕的是,在某些情況下可能根本不提交緩沖區(qū)。?通過將EGL_SWAP_BEHAVIOR屬性設(shè)置為EGL_BUFFER_PRESERVED?,或者通過使用EGL_EXT_swap_buffers_with_damage擴(kuò)展,客戶端根本不進(jìn)行渲染,然后調(diào)用eglSwapBuffers()是完全可以接受的。?在這種情況下,預(yù)計(jì)相同的圖像將顯示在屏幕上與前一個(gè)圖像相同。?但是,Wayland保證在每個(gè)eglSwapBuffers()調(diào)用上調(diào)用wl_surface.attach?,?wl_surface.damage和wl_surface.commit變得非常難以滿足。

    我已經(jīng)在libhybris中做了幾次嘗試來解決這個(gè)問題。?一種是使用EGL_KHR_fence_sync擴(kuò)展來等待驅(qū)動(dòng)程序EGL實(shí)現(xiàn)在執(zhí)行提交之前實(shí)際將緩沖區(qū)提交給ANativeWindow?。?如果驅(qū)動(dòng)程序EGL實(shí)現(xiàn)在同步返回時(shí)沒有為我們提供緩沖區(qū),那么無論如何我們都會(huì)繼續(xù)提交。?不幸的是,這依賴于驅(qū)動(dòng)程序EGL實(shí)現(xiàn)以我們期望的方式實(shí)現(xiàn)EGL_KHR_fence_sync,即不從eglClientWaitSyncKHR()返回,直到緩沖區(qū)實(shí)際被推送。?并非所有與Android兼容的驅(qū)動(dòng)程序EGL實(shí)現(xiàn)都會(huì)這樣做。?Giulio Camuffo試圖使libhybris的實(shí)現(xiàn)更加智能,跟蹤驅(qū)動(dòng)程序EGL實(shí)現(xiàn)從隊(duì)列中提取的緩沖區(qū),并試圖猜測(cè)它將在下一個(gè)緩沖區(qū)中放入哪個(gè)緩沖區(qū)。?不幸的是,這些解決方案都不適用于所有驅(qū)動(dòng)程序。

    這是關(guān)于它的長(zhǎng)期和短期。?這是一種不幸的情況。?如果您對(duì)如何使其變得更好有任何想法,我很樂意聽到它們。?或者甚至更好,只是開始攻擊libhybris,看看你是否可以改進(jìn)它。?但是,請(qǐng)注意,對(duì)一個(gè)驅(qū)動(dòng)程序起作用的東西可能完全打破另一個(gè)驅(qū)動(dòng)程序。?歡迎來到硬件世界。?我希望你讀得好!

    http://www.jlekstrand.net/jason/projects/wayland/wayland-android/

    總結(jié)

    以上是生活随笔為你收集整理的【译】Why Wayland on Android is a hard problem的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。