display:weston的client端繪畫[subsurface,fullscreen]

weston的源代碼裏面有關於client的繪畫例子

建議追蹤https://github.com/wayland-project/weston/blob/master/clients/

client端的例子一直在變,最近的一次改動將ivi的支持拿掉。

增加一種功能的操作例子shm.c[增加subsurface支持]

需要注意的是:
weston 本身來說並不支持surface去指定自己在屏幕上的位置。那如果我們希望固定surface的位置,我們需要繪畫一個full-screen的主surface+subsurface,這樣我們就一個固定subsurface的位置;
切記要用full-screen,而不是自己去確認屏幕的分辨率,不然多個不一樣分辨率的情況,你無法確認主surface的大小。
另外一般來說你可以繪畫一個透明的主surface,一般是在設置

                ret = create_shm_buffer(window->display, buffer,
                                        window->width, window->height,
-                                       WL_SHM_FORMAT_XRGB8888);
+                                       WL_SHM_FORMAT_ARGB8888);

當然也可以調用gl-api去實現。

struct display {
	struct wl_display *display;
	struct wl_registry *registry;
	struct wl_compositor *compositor;
#if 1
	struct wl_subcompositor *subcompositor;
#endif
	struct zxdg_shell_v6 *shell;
	struct zwp_fullscreen_shell_v1 *fshell;
	struct wl_shm *shm;
	bool has_xrgb;
	struct ivi_application *ivi_application;
};

struct window {
	struct display *display;
	int width, height;
	struct wl_surface *surface;
#if 1
	struct wl_surface *main_surface;
	struct wl_subsurface *subsurface;

	struct wl_surface *main1_surface;
	struct wl_subsurface *subsurface1;
#endif
	struct zxdg_surface_v6 *xdg_surface;
	struct zxdg_toplevel_v6 *xdg_toplevel;
	struct ivi_surface *ivi_surface;
	struct buffer buffers[4];
	struct buffer *prev_buffer;
	struct wl_callback *callback;
	bool wait_for_configure;
};


static struct window *
create_window(struct display *display, int width, int height)
{
	struct window *window;
#if 1
    struct wl_subcompositor *subcompo = display->subcompositor;
#endif

	window = zalloc(sizeof *window);
	if (!window)
		return NULL;

	window->callback = NULL;
	window->display = display;
	window->width = width;
	window->height = height;
    window->surface = wl_compositor_create_surface(display->compositor);
#if 1
	window->main_surface = wl_compositor_create_surface(display->compositor);
	window->subsurface = wl_subcompositor_get_subsurface(subcompo, window->main_surface, window->surface);

    wl_subsurface_set_position(window->subsurface, 100, 100);
    wl_subsurface_set_desync(window->subsurface);

	window->main1_surface = wl_compositor_create_surface(display->compositor);
	window->subsurface1 = wl_subcompositor_get_subsurface(subcompo, window->main1_surface, window->surface);

    wl_subsurface_set_position(window->subsurface1, 500, 500);
    wl_subsurface_set_desync(window->subsurface1);
#endif

	if (display->shell) {
		window->xdg_surface =
			zxdg_shell_v6_get_xdg_surface(display->shell,
						  window->surface);
		assert(window->xdg_surface);
		zxdg_surface_v6_add_listener(window->xdg_surface,
					     &xdg_surface_listener, window);

		window->xdg_toplevel =
			zxdg_surface_v6_get_toplevel(window->xdg_surface);
		assert(window->xdg_toplevel);
		zxdg_toplevel_v6_add_listener(window->xdg_toplevel,
					      &xdg_toplevel_listener, window);

		zxdg_toplevel_v6_set_title(window->xdg_toplevel, "simple-shm");
		zxdg_toplevel_v6_set_fullscreen(window->xdg_toplevel, NULL);
		wl_surface_commit(window->surface);
		window->wait_for_configure = true;
	} else if (display->fshell) {
		zwp_fullscreen_shell_v1_present_surface(display->fshell,
							window->surface,
							ZWP_FULLSCREEN_SHELL_V1_PRESENT_METHOD_DEFAULT,
							NULL);
	} else if (display->ivi_application ) {
		uint32_t id_ivisurf = IVI_SURFACE_ID + (uint32_t)getpid();
		window->ivi_surface =
			ivi_application_surface_create(display->ivi_application,
						       id_ivisurf, window->surface);
		if (window->ivi_surface == NULL) {
			fprintf(stderr, "Failed to create ivi_client_surface\n");
			abort();
		}

		ivi_surface_add_listener(window->ivi_surface,
					 &ivi_surface_listener, window);

	} else {
		assert(0);
	}

	return window;
}

static void
redraw(void *data, struct wl_callback *callback, uint32_t time)
{
	struct window *window = data;
	struct buffer *buffer;
#if 1
    struct buffer *buffer_tmp;
#endif

	buffer = window_next_buffer(window);
	if (!buffer) {
		fprintf(stderr,
			!callback ? "Failed to create the first buffer.\n" :
			"Both buffers busy at redraw(). Server bug?\n");
		abort();
	}

	paint_pixels(buffer->shm_data, 20, window->width, window->height, time);

	wl_surface_attach(window->surface, buffer->buffer, 0, 0);
	wl_surface_damage(window->surface,
			  20, 20, window->width - 40, window->height - 40);

#if 1
	buffer_tmp = &window->buffers[2];
	create_shm_buffer(window->display, buffer_tmp,
				window->width/4, window->height/4,
				WL_SHM_FORMAT_XRGB8888);
		/* paint the padding */
	memset(buffer_tmp->shm_data, 0xff,
		    window->width/4 * window->height/4 * 4);
    wl_surface_attach(window->main_surface, buffer_tmp->buffer, 0, 0);
    wl_surface_damage(window->main_surface,
    		  300, 300, window->width - 40, window->height - 40);

	buffer_tmp = &window->buffers[3];
	create_shm_buffer(window->display, buffer_tmp,
				window->width/4, window->height/4,
				WL_SHM_FORMAT_XRGB8888);
		/* paint the padding */
	memset(buffer_tmp->shm_data, 0x00,
		    window->width/4 * window->height/4 * 4);
    wl_surface_attach(window->main1_surface, buffer_tmp->buffer, 0, 0);
    wl_surface_damage(window->main1_surface,
    		  300, 300, window->width - 40, window->height - 40);
#endif

	if (callback)
		wl_callback_destroy(callback);
	window->callback = wl_surface_frame(window->surface);
	wl_callback_add_listener(window->callback, &frame_listener, window);
	wl_surface_commit(window->surface);
#if 1
	wl_surface_commit(window->main_surface);
	wl_surface_commit(window->main1_surface);
#endif
	buffer->busy = 1;
}

static void
registry_handle_global(void *data, struct wl_registry *registry,
		       uint32_t id, const char *interface, uint32_t version)
{
	struct display *d = data;

	if (strcmp(interface, "wl_compositor") == 0) {
		d->compositor =
			wl_registry_bind(registry,
					 id, &wl_compositor_interface, 1);
	} else if (strcmp(interface, "zxdg_shell_v6") == 0) {
		d->shell = wl_registry_bind(registry,
					    id, &zxdg_shell_v6_interface, 1);
		zxdg_shell_v6_add_listener(d->shell, &xdg_shell_listener, d);
	} else if (strcmp(interface, "zwp_fullscreen_shell_v1") == 0) {
		d->fshell = wl_registry_bind(registry,
					     id, &zwp_fullscreen_shell_v1_interface, 1);
	} else if (strcmp(interface, "wl_shm") == 0) {
		d->shm = wl_registry_bind(registry,
					  id, &wl_shm_interface, 1);
		wl_shm_add_listener(d->shm, &shm_listener, d);
	} else if (strcmp(interface, "ivi_application") == 0) {
		d->ivi_application =
			wl_registry_bind(registry, id,
					 &ivi_application_interface, 1);
#if 1
	} else if (strcmp(interface, "wl_subcompositor") == 0) {
        d->subcompositor = 
            wl_registry_bind(registry, id,
                    &wl_subcompositor_interface, 1);
#endif
    }
}

 關於subsurface的位置設定:

wl_subsurface::set_position - reposition the sub-surface
x
int - x coordinate in the parent surface
y
int - y coordinate in the parent surface
This schedules a sub-surface position change. The sub-surface will be moved so that its 
origin (top left corner pixel) will be at the location x, y of the parent surface 
coordinate system. The coordinates are not restricted to the parent surface area. Negative 
values are allowed.

The scheduled coordinates will take effect whenever the state of the parent surface is 
applied. When this happens depends on whether the parent surface is in synchronized mode or 
not. See wl_subsurface.set_sync and wl_subsurface.set_desync for details.

If more than one set_position request is invoked by the client before the commit of the 
parent surface, the position of a new request always replaces the scheduled position from 
any previous request.

The initial position is 0, 0.

注意:subsurface的位置可以是負數 ,這就意味着你主surface可以只是一個點

 

代碼段小部件

viewport 支持縮放裁剪

subsurface 子表面功能

--- a/clients/simple-shm.c
+++ b/clients/simple-shm.c
@@ -152,6 +152,9 @@ handle_xdg_toplevel_configure(void *data, struct zxdg_toplevel_v6 *xdg_toplevel,
                              int32_t width, int32_t height,
                              struct wl_array *state)
 {
+    struct window *window = data;
+    window->width = width;
+    window->height = height;
 }
 
 static void
@@ -187,8 +190,8 @@ create_window(struct display *display, int width, int height)
 
        window->callback = NULL;
        window->display = display;
-       window->width = width;
-       window->height = height;
+//     window->width = width;
+//     window->height = height;
        window->surface = wl_compositor_create_surface(display->compositor);
 
        if (display->shell) {
@@ -229,6 +232,7 @@ create_window(struct display *display, int width, int height)
        } else {
                assert(0);
        }
+    zxdg_toplevel_v6_set_fullscreen(window->xdg_toplevel,NULL);
 
        return window;
 }

很多時候,我們的繪畫與顯示是放在不同的線程裏面去執行,這種情況下callback很重要,這個是在之前的weston裏面不存在的功能。

Note:
Essentially, there are three conditions to be filled before you
can/should draw:
a) You have something new to show.
b) The previous drawing has been shown already (frame callback is done).
c) You have an available buffer to draw into.
Condition a) is up to you. Rather than something new to show, it could
also be just a desire to keep the feedback loop going. Or maybe you are
running an animation, in which case you always draw once for a frame
callback, but compute the animation state based on the current (or
predicted) time. Driving your animations by the compositor events tends
to produce more fluent motion than driving by a timer.

Condition b) is for throttling. You don't want to draw frames that will
only get discarded by the compositor, that would be wasted work. But,
sometimes you have other reasons to ignore condition b), e.g. if your
window state changes and you want to update ASAP. Then discarding the
old frame could make sense.

Condition c) is for limiting resource usage. If you don't have any
buffers available, you can always allocate a new one. At some point
though, it starts making sense to limit your memory usage and instead
wait for the compositor to release some of your old buffers to re-use
them. Four buffers is a limit that should be practically always enough.


None of this is related to asynchronicity. The conditions apply equally to synchronous and asynchronous drawing loops.

NOTE:

目前代碼裏面相對於simple-shm或者simple-dmabuf-drm,

shm本地創建匿名空間,通過fd進行map,填充數據,走shm-protocol把fd給server

dmabuf-drm本地創建dmabuffer,通過fd進行map,填充數據,走dmabuf-drm把fd給server

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