summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--examples/meson.build24
-rw-r--r--examples/scene-graph.c210
-rw-r--r--meson.build2
-rw-r--r--render/fx_renderer/gles2/shaders/box_shadow.frag7
4 files changed, 237 insertions, 6 deletions
diff --git a/examples/meson.build b/examples/meson.build
new file mode 100644
index 0000000..da32934
--- /dev/null
+++ b/examples/meson.build
@@ -0,0 +1,24 @@
+# Only needed for drm_fourcc.h
+libdrm_header = dependency('libdrm').partial_dependency(compile_args: true, includes: true)
+
+compositors = {
+ 'scene-graph': {
+ 'src': 'scene-graph.c',
+ 'proto': ['xdg-shell'],
+ },
+}
+
+foreach name, info : compositors
+ extra_src = []
+ foreach p : info.get('proto', [])
+ extra_src += protocols_server_header[p]
+ endforeach
+
+ executable(
+ name,
+ [info.get('src'), extra_src],
+ dependencies: [wlroots, scenefx, libdrm_header, info.get('dep', [])],
+ build_by_default: get_option('examples'),
+ )
+endforeach
+
diff --git a/examples/scene-graph.c b/examples/scene-graph.c
new file mode 100644
index 0000000..562f72e
--- /dev/null
+++ b/examples/scene-graph.c
@@ -0,0 +1,210 @@
+#define _POSIX_C_SOURCE 200112L
+#include <assert.h>
+#include <getopt.h>
+#include <scenefx/render/fx_renderer/fx_renderer.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include <unistd.h>
+#include <wayland-server-core.h>
+#include <wlr/backend.h>
+#include <wlr/render/allocator.h>
+#include <wlr/render/wlr_renderer.h>
+#include <wlr/types/wlr_compositor.h>
+#include <wlr/types/wlr_output.h>
+#include <wlr/types/wlr_scene.h>
+#include <wlr/types/wlr_xdg_shell.h>
+#include <wlr/util/log.h>
+
+/* Simple compositor making use of the scene-graph API. Input is unimplemented.
+ *
+ * New surfaces are stacked on top of the existing ones as they appear. */
+
+static const int border_width = 3;
+
+struct server {
+ struct wl_display *display;
+ struct wlr_backend *backend;
+ struct wlr_renderer *renderer;
+ struct wlr_allocator *allocator;
+ struct wlr_scene *scene;
+
+ uint32_t surface_offset;
+
+ struct wl_listener new_output;
+ struct wl_listener new_surface;
+};
+
+struct surface {
+ struct wlr_surface *wlr;
+ struct wlr_scene_surface *scene_surface;
+ struct wlr_scene_rect *border;
+ struct wl_list link;
+
+ struct wl_listener commit;
+ struct wl_listener destroy;
+};
+
+struct output {
+ struct wl_list link;
+ struct server *server;
+ struct wlr_output *wlr;
+ struct wlr_scene_output *scene_output;
+
+ struct wl_listener frame;
+};
+
+static void output_handle_frame(struct wl_listener *listener, void *data) {
+ struct output *output = wl_container_of(listener, output, frame);
+
+ if (!wlr_scene_output_commit(output->scene_output, NULL)) {
+ return;
+ }
+
+ struct timespec now;
+ clock_gettime(CLOCK_MONOTONIC, &now);
+ wlr_scene_output_send_frame_done(output->scene_output, &now);
+}
+
+static void server_handle_new_output(struct wl_listener *listener, void *data) {
+ struct server *server = wl_container_of(listener, server, new_output);
+ struct wlr_output *wlr_output = data;
+
+ wlr_output_init_render(wlr_output, server->allocator, server->renderer);
+
+ struct output *output = calloc(1, sizeof(*output));
+ output->wlr = wlr_output;
+ output->server = server;
+ output->frame.notify = output_handle_frame;
+ wl_signal_add(&wlr_output->events.frame, &output->frame);
+
+ output->scene_output = wlr_scene_output_create(server->scene, wlr_output);
+
+ struct wlr_output_state state;
+ wlr_output_state_init(&state);
+ wlr_output_state_set_enabled(&state, true);
+ struct wlr_output_mode *mode = wlr_output_preferred_mode(wlr_output);
+ if (mode != NULL) {
+ wlr_output_state_set_mode(&state, mode);
+ }
+ wlr_output_commit_state(wlr_output, &state);
+ wlr_output_state_finish(&state);
+
+ wlr_output_create_global(wlr_output);
+}
+
+static void surface_handle_commit(struct wl_listener *listener, void *data) {
+ struct surface *surface = wl_container_of(listener, surface, commit);
+ wlr_scene_rect_set_size(surface->border,
+ surface->wlr->current.width + 2 * border_width,
+ surface->wlr->current.height + 2 * border_width);
+}
+
+static void surface_handle_destroy(struct wl_listener *listener, void *data) {
+ struct surface *surface = wl_container_of(listener, surface, destroy);
+ wlr_scene_node_destroy(&surface->scene_surface->buffer->node);
+ wlr_scene_node_destroy(&surface->border->node);
+ wl_list_remove(&surface->destroy.link);
+ wl_list_remove(&surface->link);
+ free(surface);
+}
+
+static void server_handle_new_surface(struct wl_listener *listener,
+ void *data) {
+ struct server *server = wl_container_of(listener, server, new_surface);
+ struct wlr_surface *wlr_surface = data;
+
+ int pos = server->surface_offset;
+ server->surface_offset += 50;
+
+ struct surface *surface = calloc(1, sizeof(*surface));
+ surface->wlr = wlr_surface;
+ surface->commit.notify = surface_handle_commit;
+ wl_signal_add(&wlr_surface->events.commit, &surface->commit);
+ surface->destroy.notify = surface_handle_destroy;
+ wl_signal_add(&wlr_surface->events.destroy, &surface->destroy);
+
+ /* Border dimensions will be set in surface.commit handler */
+ surface->border = wlr_scene_rect_create(&server->scene->tree,
+ 0, 0, (float[4]){ 0.5f, 0.5f, 0.5f, 1 });
+ wlr_scene_node_set_position(&surface->border->node, pos, pos);
+
+ surface->scene_surface =
+ wlr_scene_surface_create(&server->scene->tree, wlr_surface);
+
+ wlr_scene_node_set_position(&surface->scene_surface->buffer->node,
+ pos + border_width, pos + border_width);
+}
+
+int main(int argc, char *argv[]) {
+ wlr_log_init(WLR_DEBUG, NULL);
+
+ char *startup_cmd = NULL;
+
+ int c;
+ while ((c = getopt(argc, argv, "s:")) != -1) {
+ switch (c) {
+ case 's':
+ startup_cmd = optarg;
+ break;
+ default:
+ printf("usage: %s [-s startup-command]\n", argv[0]);
+ return EXIT_FAILURE;
+ }
+ }
+ if (optind < argc) {
+ printf("usage: %s [-s startup-command]\n", argv[0]);
+ return EXIT_FAILURE;
+ }
+
+ struct server server = {0};
+ server.surface_offset = 0;
+ server.display = wl_display_create();
+ server.backend = wlr_backend_autocreate(server.display, NULL);
+ server.scene = wlr_scene_create();
+
+ server.renderer = fx_renderer_create(server.backend);
+ wlr_renderer_init_wl_display(server.renderer, server.display);
+
+ server.allocator = wlr_allocator_autocreate(server.backend,
+ server.renderer);
+
+ struct wlr_compositor *compositor =
+ wlr_compositor_create(server.display, 5, server.renderer);
+
+ wlr_xdg_shell_create(server.display, 2);
+
+ server.new_output.notify = server_handle_new_output;
+ wl_signal_add(&server.backend->events.new_output, &server.new_output);
+
+ server.new_surface.notify = server_handle_new_surface;
+ wl_signal_add(&compositor->events.new_surface, &server.new_surface);
+
+ const char *socket = wl_display_add_socket_auto(server.display);
+ if (!socket) {
+ wl_display_destroy(server.display);
+ return EXIT_FAILURE;
+ }
+
+ if (!wlr_backend_start(server.backend)) {
+ wl_display_destroy(server.display);
+ return EXIT_FAILURE;
+ }
+
+ setenv("WAYLAND_DISPLAY", socket, true);
+ if (startup_cmd != NULL) {
+ if (fork() == 0) {
+ execl("/bin/sh", "/bin/sh", "-c", startup_cmd, (void *)NULL);
+ }
+ }
+
+ wlr_log(WLR_INFO, "Running Wayland compositor on WAYLAND_DISPLAY=%s",
+ socket);
+ wl_display_run(server.display);
+
+ wl_display_destroy_clients(server.display);
+ wl_display_destroy(server.display);
+ return EXIT_SUCCESS;
+}
+
diff --git a/meson.build b/meson.build
index fadad55..4451149 100644
--- a/meson.build
+++ b/meson.build
@@ -178,7 +178,7 @@ scenefx = declare_dependency(
meson.override_dependency('scenefx', scenefx)
if get_option('examples')
- # TODO: subdir('examples')
+ subdir('examples')
subdir('tinywl')
endif
diff --git a/render/fx_renderer/gles2/shaders/box_shadow.frag b/render/fx_renderer/gles2/shaders/box_shadow.frag
index d318c93..1980434 100644
--- a/render/fx_renderer/gles2/shaders/box_shadow.frag
+++ b/render/fx_renderer/gles2/shaders/box_shadow.frag
@@ -80,11 +80,8 @@ void main() {
// dither the alpha to break up color bands
shadow_alpha += (random() - 0.5) / 128.0;
- // get the window alpha so we can render around the window
- float window_alpha = 1.0 - smoothstep(-1.0, 1.0,
- roundRectSDF((size * 0.5) - blur_sigma,
- vec2(position.x + blur_sigma - offset.x, position.y + blur_sigma - offset.y),
- corner_radius));
+ // get the window alpha so we can render around the window (fix pixel gap by adding 0.5 to radius)
+ float window_alpha = 1.0 - smoothstep(-1.0, 1.0, roundRectSDF((size * 0.5) - blur_sigma, position + blur_sigma, corner_radius + 0.5));
gl_FragColor = vec4(v_color.rgb, shadow_alpha) * (1.0 - window_alpha);
}