weston渲染流程

wl_surface.attach assigns the given wl_buffer as the pending wl_buffer. wl_surface.commit makes the pending wl_buffer the new surface contents, and the size of the surface becomes the size calculated from the wl_buffer, as described above. After commit, there is no pending buffer until the next attach.

1.attach將wl_buffer設置爲pending wl_buffer而不是currect。

2.commit將pending wl_buffer設置爲currect surface的buffer。

3.surface的大小由buffer決定。

    Committing a pending wl_buffer allows the compositor to read the pixels in the wl_buffer. The compositor may access the pixels at any time after the wl_surface.commit request. When the compositor will not access the pixels anymore, it will send the wl_buffer.release event. Only after receiving wl_buffer.release, the client may reuse the wl_buffer. A wl_buffer that has been attached and then replaced by another attach instead of committed will not receive a release event, and is not used by the compositor.

    If wl_surface.attach is sent with a NULL wl_buffer, the following wl_surface.commit will remove the surface content. 

    看wayland官方文檔的內容,是允許attch一個NULLbuffer隨後commit的。但是我測試下來client會死等callback消息【卡死】;猜測是否爲client端自己定義timer進行commit的提交能夠實現透明效果,不應該等待server的callback消息。


 

參考weston-simple-shm

1.buffer

fd = os_create_anonymous_file(size);   
    用戶空間創建size大小文件,取得fd。
data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
    將用戶空間buffer映射到進程內核空間。
pool = wl_shm_create_pool(display->shm, fd, size);
    pool->data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);[server]
    創建pool[pool保證公用同一個內核空間]。映射同一個fd;此時client與weston達成共享內存。
buffer->buffer = wl_shm_pool_create_buffer(pool, 0, width, height, stride, format);
    buffer->pool = pool;[server]
    通過pool獲取wl_buffer。
wl_shm_pool_destroy(pool);
    !!!不明白此操作!!!
buffer->shm_data = data;
    提供給client的繪畫地址。

 隨即client會對buffer->shm_data空間執行繪畫

2.attach

client:
wl_surface_attach(window->surface, buffer->buffer, 0, 0);
    buffer->buffer是一個指向struct wl_buffer的指針
server:
surface_attach
    weston_surface_state_set_buffer(&surface->pending, buffer);
        state->buffer = buffer;
    把weston_surface_state->buffer與weston_buffer對象綁定;buffer是一個指向weston_buffer的指針
    實際上是:weston_surface->pending->buffer = buffer;
    /* All the pending state, that wl_surface.commit will apply. */
    對此我理解當wl_surface.commit執行時,會用到這些pending->buffer

本質上是需要window->surface與buffer->buffer 綁定

3.damage

This request is used to describe the regions where the pending buffer is different from the current surface contents, and where the surface therefore needs to be repainted. The compositor ignores the parts of the damage that fall outside of the surface.

client:
wl_surface_damage(window->surface, x, y, window->width - 40, window->height - 40);
此請求用於描述掛起緩衝區與當前表面內容不同的區域,以及表面因此需要重新繪製的位置。合成器忽略掉落在表面之外的部分損壞。
損壞是雙緩衝狀態,其中x和y指定損壞矩形的左上角。
server:
surface_damage
    pixman_region32_union_rect(&surface->pending.damage_surface,
 				   &surface->pending.damage_surface,
 				   x, y, width, height);
    獲取surface後,將新的damage區域與原有的damage區域進行組合,得到新的damage區域。

4.frame

 Request a notification when it is a good time to start drawing a new frame, by creating a frame callback. This is useful for throttling redrawing operations, and driving animations.

如果客戶端提交的更新時間早於某個更新,則某些更新可能無法顯示,並且客戶端通過過於頻繁的繪製而浪費資源。【callback的作用就是解決上述問題】

    A server should avoid signaling the frame callbacks if the surface is not visible in any way, e.g. the surface is off-screen, or completely obscured by other opaque surfaces.

client:
window->callback = wl_surface_frame(window->surface);
    申請幀繪製回調,每當繪製完一幀就發送wl_callback::done消息給用戶client
server:
surface_frame
    wl_list_insert(surface->pending.frame_callback_list.prev, &cb->link);
    在Server端創建Frame callback,它會被放在該surface下的frame_callback_list列表中。返回它的代理對象wl_callback

5.commit

https://happyseeker.github.io/graphic/2016/11/10/wayland-commit-relative-flow.html

Surface state (input, opaque, and damage regions, attached buffers, etc.) is double-buffered.

表面狀態(輸入,不透明和損壞區域,附加緩衝區等)是雙緩衝的。

commit操作本質上就是爲double buffer而設計,多次操作、一次提交。注意到之前的操作attach,damage,frame等僅僅在commit以後纔會生效。

client:
wl_surface_commit(window->surface);
server:
surface_commit
     if (sub) {
 	weston_subsurface_commit(sub);
 	return;
     }
 	weston_surface_commit(surface);
    如果是subsurface則走subsurface_commit,否則走surface_commit
server:
weston_subsurface_commit(struct weston_subsurface *sub)
    判斷父子surface爲同步或異步
...【todo】
server:
weston_surface_commit
    weston_surface_commit_state(surface, &surface->pending);
      
             
    weston_surface_commit_subsurface_order(surface);
            //更新subsurface的順序,其實也是將subsurface從pending列表換到當前的列表中
            ...【todo】

    weston_surface_schedule_repaint(surface);
            //重繪界面,這塊邏輯複雜
weston_surface_commit_state
1    weston_surface_attach(surface, state->buffer);
        surface->compositor->renderer->attach(surface, buffer);
            gl_renderer_attach(struct weston_surface *es, struct weston_buffer *buffer)
            最終調用gl_renderer_attach;根據buffer->resource的不同,調用不同的attch函數:
                gl_renderer_attach_shm
                gl_renderer_attach_egl
                gl_renderer_attach_dmabuf
                gl_renderer_attach_gbm_buffer
            //綁定buffer;將surface_attch的時候放在weston_surface_state裏的buffer與weston_surface的buffer綁定。
            實際上是將pending-buffer送到currect_buffer。

2    weston_surface_state_set_buffer(state, NULL);
        //將pending-buffer置空。

3    weston_surface_build_buffer_matrix(surface, &surface->surface_to_buffer_matrix);
        //對surface進行旋轉,裁剪,縮放等動作
4    weston_surface_update_size(surface);
        //設置surface大小;這兩個函數不太明白
5    surface->committed(surface, state->sx, state->sy);

 
        //將pending state更新到current state中,state包括前面描述的諸多內容   

 

weston_surface_schedule_repaint(struct weston_surface *surface)
        weston_output_schedule_repaint(struct weston_output *output)
            output->idle_repaint_source = wl_event_loop_add_idle(loop, idle_repaint, output);
                idle_repaint(void *data)
                    output->start_repaint_loop(output);
                        drm_output_start_repaint_loop(struct weston_output *output_base)

 

爲什麼wayland中要有repaint操作?不是號稱都是Client繪圖、wayland負責合成?
確實Client繪圖,compositor(服務端)負責合成。但由於client繪圖實際實現爲double buffer,client最初的繪圖操作都是在pending buffer中進行的,並沒有直接繪製到framebuffer中,所以,在client完成繪製後,需要進行commit操作,commit後,服務端會將相應的buffer會更新到當前的surface中,此時,需要進行repaint操作,將客戶端相應的繪製內容最終拷貝到framebuffer中

這裏的repaint操作,本質上只是將客戶端更新的繪製內容(damage區域)提交給compositor,最後由compositor進行合成後繪製到界面上

 

代碼段小部件

 

 

 

 

 

代碼段小部件

 

 

代碼段小部件

 

 

代碼段小部件

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章