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

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