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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 综合教程 >内容正文

综合教程

wayland学习笔记(四) 全局服务对象初探

發布時間:2023/12/13 综合教程 19 生活家
生活随笔 收集整理的這篇文章主要介紹了 wayland学习笔记(四) 全局服务对象初探 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

wl_display是wayland協議的核心類, 一個wl_display 對象代表一個客戶端, 這個對象里面包含了client和server之間通信的socket, 所有和服務器之間的交互都是通過這個socket. wl_display也是客戶端必須第一個創建的wayland對象。

wl_display中比較特殊的地方在于,它的事件處理函數是在wayland源碼中實現的,可以認為這個是個基礎設施,不宜為用戶所改動。

客戶端調用的第一個wayland函數就是wl_display_connect(), 然后獲得一個wl_display對象

get_registry 請求基本上是客戶端調用的第二個wayland函數

static inline struct wl_registry * wl_display_get_registry(struct wl_display *wl_display)
{
    struct wl_proxy *registry;
    registry = wl_proxy_marshal_constructor((struct wl_proxy *) wl_display,
             WL_DISPLAY_GET_REGISTRY, &wl_registry_interface, NULL);
    return (struct wl_registry *) registry;
}

客戶端通過registry可以得知哪些服務可用,然后通過bind請求得到對應的服務對象,然后就可以使用對應的服務提供的接口了。

兩個事件函數(回調函數)是通過wl_registry_add_listener中的傳入參數struct wl_registry_listner 注冊進去的. 這兩個事件函數分別是

global 和 global_remove. global是啥意思捏,服務端有多少個服務,這個global就會被調用多少次。 global_remove則與之相反,當服務端某個服務停止了,就會調一次這個回調。

在調完wl_registry_add_listener之后,一般通過wl_display_dispatch 和 wl_display_roundtrip來確保異步操作已經完成。這里我們看一下client是如何bind到具體的服務對象的

struct wl_compositor* compositor = NULL;

static void global_registry_handler(void*data, struct wl_registry* registry, uint32_t id, 
 const char* interface, uint32_t version)
{
     printf("Availalbe interface: %s, id: %d, version: %d
", interface, id , version);
     if( strcmp("wl_compositor", interface)  == 0) {
        compositor = wl_registry_bind(registry, id, &wl_compositor_interface, 1);
    } else if (strcmp(interface, "wl_shell")) {
         shell = wl_registry_bind(registry, id, &wl_shell_interface, 1);
    }
}    

wl_compositor 是wayland中創建窗口的靈魂

static inline struct wl_surface * wl_compositor_create_surface(struct wl_compositor *wl_compositor)
{
    struct wl_proxy *id;
    id = wl_proxy_marshal_constructor((struct wl_proxy *) wl_compositor,
             WL_COMPOSITOR_CREATE_SURFACE, &wl_surface_interface, NULL);

    return (struct wl_surface *) id;
}

//create_surface,這個請求函數用來創建窗口繪制的實體,但是它不是真正的窗口,只是窗口上面的內容,意思就是,可能存在很多的窗口,這些窗口上面的內容都是這個surface。后面我會專門拿一章來詳細說明這一點。這個接口返回wl_surface對象。

static inline struct wl_region * wl_compositor_create_region(struct wl_compositor *wl_compositor)
{
    struct wl_proxy *id;

    id = wl_proxy_marshal_constructor((struct wl_proxy *) wl_compositor,
             WL_COMPOSITOR_CREATE_REGION, &wl_region_interface, NULL);

    return (struct wl_region *) id;
}

這里看到wl_surface和wl_region都是client發起的request得到的,這里不禁讓我思考,記得之前說client的buffer都是自己這邊分配管理的?這里打上一個問號繼續往下看:

wl_shm這個服務,是wayland提供的客戶端和服務器端共享內存的服務,共享內存一般是作為窗口繪制內容的容器。

wl_shm_create_pool 原理是客戶端傳給服務器端內存的文件fd, 服務器再通過這個fd操作那塊內存

這個接口返回一個wl_shm_pool, 這個就是共享內存對象,結合上面的說法就是客戶端創建一個fd,然后mmap到一段內存,這段內存就是客戶端用來渲染的,最后把這個fd傳遞給服務器,讓服務器端去讀取它。但是對于窗口的繪制卻不是直接操作的這個wl_shm_pool 而是通過wl_shm_pool_create_buffer返回的wl_buffer作為保存繪制內容的真正實體。wl_shm_pool 和wl_buffer一般是1:1的關系

wl_buffer有一個請求函數wl_buffer_destroy和一個事件函數 void (*release) (void* data, struct wl_buffer* wl_buffer ).

再看看wl_surface的幾個接口:

destroy

attach , 綁定一個wl_buffer

dmage, invalidate surface的一塊區域

frame 申請幀繪制回調,每當繪制完一幀就發送wl_callback::done消息

==================================================

struct callback* frame_callback = wl_surface_frame(surface);

wl_callback_add_listener(frame_callback, &frame_listener, NULL);

===================================================

set_opaque_region

commit

...

好了,有了上述這些知識儲備,我們就可以分析wayland-wsegl這塊代碼了,我們通過分析來double check一下

先看下client端創建buffer的操作,簡單起見,我們先看下soft版本的

在client的初始化中creat_window(), 然后是create_buffer(), 然后是真正分配了一個ion buffer, 然后是通過

duss_hal_mem_share(fb.buffer, &duss_handle) 拿到這個用于共享的fd(duss_handle)

然后就是pool = eagle_shm_create_pool(shm)

然后就是 buffer = eagle_shm_pool_create_buffer(pool, duss_handle& 0xffffffff, duss_handle >> 32, w, h, pstride, fmt)

這個是定義在protocal中的接口。

完成wl_buffer的創建后,反手就是一波 wl_surface_attach(surface, buff, 0,0 , w, h)

然后是wl_suface_commit(surface)

差不多就是這個過程

我們繼續分析wl_shell和wl_shell_surface這倆貨

wl_shell是窗口的服務接口類

wl_shell_get_shell_surface(wl_shell*, wl_surface*) 創建指定wl_surface的顯示窗口對象wl_shell_surface

一般情況下,一個wl_surface對應一個wl_shell_surface

wl_shell_surface 就是真正的窗口,該服務提供了以下接口:

請求函數:

pong 用于響應ping事件函數

move

resize

set_toplevel

transient

set_fullscreen

set_popup

set_maxmized

set_title

..

事件函數

ping, configure, popup_done

再分析一下我們這邊的sample code:
shell_surface = wl_shell_get_shell_surface(shell, surface)

wl_shell_surface_set_toplevel(shell_surface)

wl_shell_surface_add_listener(shell_surface, &shell_surface_listener, NULL);

前面的get和設置為頂層沒啥好說的,著重說一下add_listener這個接口。

static const struct wl_shell_surface_listener shell_surface_listener = {

handle_ping, handle_configure, handle_popup_done};

就是通過add_listener來添加各個回調去響應server端的事件的。

總結

以上是生活随笔為你收集整理的wayland学习笔记(四) 全局服务对象初探的全部內容,希望文章能夠幫你解決所遇到的問題。

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