From 393f96274a79c65d6cbcc29e52db5adc300c1463 Mon Sep 17 00:00:00 2001 From: YaoBing Xiao Date: Mon, 23 Mar 2026 21:09:13 +0800 Subject: [PATCH] examples: add render-pass-ext exmaple --- examples/meson.build | 2 + examples/render-pass-ext/gles2/meson.build | 6 + .../render-pass-ext/gles2/shaders/meson.build | 22 ++ .../gles2/shaders/triangle.frag | 11 + .../gles2/shaders/triangle.vert | 8 + .../render-pass-ext/gles2/triangle_pass.c | 135 ++++++++++++ .../render-pass-ext/gles2/triangle_pass.h | 27 +++ examples/render-pass-ext/meson.build | 26 +++ examples/render-pass-ext/pixman/meson.build | 3 + .../render-pass-ext/pixman/triangle_pass.c | 107 +++++++++ .../render-pass-ext/pixman/triangle_pass.h | 16 ++ examples/render-pass-ext/render-pass-ext.c | 206 ++++++++++++++++++ examples/render-pass-ext/triangle_pass.c | 95 ++++++++ examples/render-pass-ext/triangle_pass.h | 41 ++++ 14 files changed, 705 insertions(+) create mode 100644 examples/render-pass-ext/gles2/meson.build create mode 100644 examples/render-pass-ext/gles2/shaders/meson.build create mode 100644 examples/render-pass-ext/gles2/shaders/triangle.frag create mode 100644 examples/render-pass-ext/gles2/shaders/triangle.vert create mode 100644 examples/render-pass-ext/gles2/triangle_pass.c create mode 100644 examples/render-pass-ext/gles2/triangle_pass.h create mode 100644 examples/render-pass-ext/meson.build create mode 100644 examples/render-pass-ext/pixman/meson.build create mode 100644 examples/render-pass-ext/pixman/triangle_pass.c create mode 100644 examples/render-pass-ext/pixman/triangle_pass.h create mode 100644 examples/render-pass-ext/render-pass-ext.c create mode 100644 examples/render-pass-ext/triangle_pass.c create mode 100644 examples/render-pass-ext/triangle_pass.h diff --git a/examples/meson.build b/examples/meson.build index 28a83cccc..524c91d2d 100644 --- a/examples/meson.build +++ b/examples/meson.build @@ -49,6 +49,8 @@ compositors = { }, } +subdir('render-pass-ext') + foreach name, info : compositors extra_src = [] foreach p : info.get('proto', []) diff --git a/examples/render-pass-ext/gles2/meson.build b/examples/render-pass-ext/gles2/meson.build new file mode 100644 index 000000000..b317d51c6 --- /dev/null +++ b/examples/render-pass-ext/gles2/meson.build @@ -0,0 +1,6 @@ +subdir('shaders') + +gles2_sources = [ + files('triangle_pass.c'), + gles2_shader_sources, +] diff --git a/examples/render-pass-ext/gles2/shaders/meson.build b/examples/render-pass-ext/gles2/shaders/meson.build new file mode 100644 index 000000000..96a52bfca --- /dev/null +++ b/examples/render-pass-ext/gles2/shaders/meson.build @@ -0,0 +1,22 @@ +custom_pass_embed = find_program('../../../../render/gles2/shaders/embed.sh', native: true) +triangle_vert = custom_target( + 'custom-render-pass-triangle-vert', + command: [custom_pass_embed, 'custom_triangle_vert'], + input: 'triangle.vert', + output: 'triangle_vert.h', + feed: true, + capture: true, +) +triangle_frag = custom_target( + 'custom-render-pass-triangle-frag', + command: [custom_pass_embed, 'custom_triangle_frag'], + input: 'triangle.frag', + output: 'triangle_frag.h', + feed: true, + capture: true, +) + +gles2_shader_sources = [ + triangle_vert, + triangle_frag, +] diff --git a/examples/render-pass-ext/gles2/shaders/triangle.frag b/examples/render-pass-ext/gles2/shaders/triangle.frag new file mode 100644 index 000000000..0b0cbc968 --- /dev/null +++ b/examples/render-pass-ext/gles2/shaders/triangle.frag @@ -0,0 +1,11 @@ +#ifdef GL_FRAGMENT_PRECISION_HIGH +precision highp float; +#else +precision mediump float; +#endif + +varying vec3 v_color; + +void main() { + gl_FragColor = vec4(v_color, 1.0); +} diff --git a/examples/render-pass-ext/gles2/shaders/triangle.vert b/examples/render-pass-ext/gles2/shaders/triangle.vert new file mode 100644 index 000000000..e0c51f3c0 --- /dev/null +++ b/examples/render-pass-ext/gles2/shaders/triangle.vert @@ -0,0 +1,8 @@ +attribute vec2 pos; +attribute vec3 color; +varying vec3 v_color; + +void main() { + gl_Position = vec4(pos, 0.0, 1.0); + v_color = color; +} diff --git a/examples/render-pass-ext/gles2/triangle_pass.c b/examples/render-pass-ext/gles2/triangle_pass.c new file mode 100644 index 000000000..c7e53062f --- /dev/null +++ b/examples/render-pass-ext/gles2/triangle_pass.c @@ -0,0 +1,135 @@ +#include +#include +#include +#include +#include + +#include "triangle_pass.h" + +#include "triangle_vert.h" +#include "triangle_frag.h" + +static void custom_triangle_render(struct wlr_render_pass *render_pass, + const struct custom_render_triangle_options *options) { + struct wlr_gles2_render_pass *wlr_gles2_pass = + wlr_gles2_render_pass_from_render_pass(render_pass); + struct render_triangle_pass *base = + wlr_gles2_pass->buffer->renderer->wlr_renderer.data; + struct gles2_render_triangle_pass *triangle_pass = + gles2_render_triangle_pass_from_pass(base); + struct wlr_gles2_renderer *renderer = wlr_gles2_pass->buffer->renderer; + + struct wlr_box box; + struct wlr_buffer *wlr_buffer = wlr_gles2_pass->buffer->buffer; + custom_render_triangle_options_get_box(options, wlr_buffer, &box); + + int width = wlr_gles2_pass->buffer->buffer->width; + int height = wlr_gles2_pass->buffer->buffer->height; + + float x0 = options->box.x + options->box.width * 0.50f; + float y0 = options->box.y + options->box.height * 0.10f; + float x1 = options->box.x + options->box.width * 0.10f; + float y1 = options->box.y + options->box.height * 0.90f; + float x2 = options->box.x + options->box.width * 0.90f; + float y2 = options->box.y + options->box.height * 0.90f; + + GLfloat verts[3][5] = { + { x0 / width * 2.0f - 1.0f, 1.0f - y0 / height * 2.0f, 1.0f, 0.1f, 0.1f }, + { x1 / width * 2.0f - 1.0f, 1.0f - y1 / height * 2.0f, 0.1f, 1.0f, 0.1f }, + { x2 / width * 2.0f - 1.0f, 1.0f - y2 / height * 2.0f, 0.1f, 0.2f, 1.0f }, + }; + + wlr_gles2_push_debug(renderer); + glDisable(GL_SCISSOR_TEST); + glDisable(GL_BLEND); + + glUseProgram(triangle_pass->shader.program); + wlr_gles_set_proj_matrix(triangle_pass->shader.proj, wlr_gles2_pass->projection_matrix, &box); + glEnableVertexAttribArray(triangle_pass->shader.pos_attrib); + glVertexAttribPointer(triangle_pass->shader.pos_attrib, 2, GL_FLOAT, GL_FALSE, + 5 * sizeof(GLfloat), verts); + glEnableVertexAttribArray(triangle_pass->shader.color_attrib); + glVertexAttribPointer(triangle_pass->shader.color_attrib, 3, GL_FLOAT, GL_FALSE, + 5 * sizeof(GLfloat), &verts[0][2]); + + glDrawArrays(GL_TRIANGLES, 0, 3); + + glDisableVertexAttribArray(triangle_pass->shader.pos_attrib); + glDisableVertexAttribArray(triangle_pass->shader.color_attrib); + wlr_gles2_pop_debug(renderer); +} + +static void custom_triangle_destroy(struct render_triangle_pass *pass) { + struct gles2_render_triangle_pass *gles2_pass = + gles2_render_triangle_pass_from_pass(pass); + if (gles2_pass->shader.program != 0) { + glDeleteProgram(gles2_pass->shader.program); + } + + free(gles2_pass); +} + +static const struct render_triangle_pass_impl custom_triangle_impl = { + .destroy = custom_triangle_destroy, + .render = custom_triangle_render, +}; + +struct render_triangle_pass *gles2_render_triangle_pass_create( + struct wlr_renderer *wlr_renderer) { + struct gles2_render_triangle_pass *pass = calloc(1, sizeof(*pass)); + if (pass == NULL) { + wlr_log_errno(WLR_ERROR, "failed to allocate gles2_render_triangle_pass"); + return NULL; + } + + struct wlr_gles2_renderer *renderer = wlr_gles2_renderer_from_renderer(wlr_renderer); + if (!wlr_egl_make_current(renderer->egl, NULL)) { + free(pass); + return NULL; + } + + render_triangle_pass_init(&pass->base, &custom_triangle_impl); + wlr_gles2_push_debug(renderer); + GLuint prog; + pass->shader.program = prog = + wlr_gles2_link_program(renderer, custom_triangle_vert, custom_triangle_frag); + if (!pass->shader.program) { + goto error; + } + + pass->shader.proj = -1; + pass->shader.color_attrib = glGetAttribLocation(pass->shader.program, "color"); + pass->shader.pos_attrib = glGetAttribLocation(pass->shader.program, "pos"); + if (pass->shader.pos_attrib < 0 || pass->shader.color_attrib < 0) { + wlr_log(WLR_ERROR, "triangle shader attribute lookup failed: pos=%d color=%d", + pass->shader.pos_attrib, pass->shader.color_attrib); + goto error; + } + wlr_gles2_pop_debug(renderer); + wlr_egl_unset_current(renderer->egl); + pass->renderer = renderer; + return &pass->base; + +error: + render_triangle_pass_destroy(&pass->base); + wlr_gles2_pop_debug(renderer); + wlr_egl_unset_current(renderer->egl); + + return NULL; +} + +bool render_triangle_pass_is_gles2(const struct render_triangle_pass *triangle_pass) { + return triangle_pass->impl == & custom_triangle_impl; +} + +struct gles2_render_triangle_pass *gles2_render_triangle_pass_from_pass( + struct render_triangle_pass *triangle_pass) { + if (!render_triangle_pass_is_gles2(triangle_pass)) { + return NULL; + } + + struct gles2_render_triangle_pass *gles2_pass = + wl_container_of(triangle_pass, gles2_pass, base); + + return gles2_pass; +} diff --git a/examples/render-pass-ext/gles2/triangle_pass.h b/examples/render-pass-ext/gles2/triangle_pass.h new file mode 100644 index 000000000..2e22339cc --- /dev/null +++ b/examples/render-pass-ext/gles2/triangle_pass.h @@ -0,0 +1,27 @@ +#ifndef GLES2_TRIANGLE_PASS_PASS_H +#define GLES2_TRIANGLE_PASS_PASS_H + +#include "../triangle_pass.h" + +#include + +#include + +struct gles2_render_triangle_pass { + struct render_triangle_pass base; + struct wlr_gles2_renderer *renderer; + struct { + GLuint program; + GLint proj; + GLint pos_attrib; + GLint color_attrib; + } shader; +}; + +struct render_triangle_pass *gles2_render_triangle_pass_create( + struct wlr_renderer *wlr_renderer); +bool render_triangle_pass_is_gles2(const struct render_triangle_pass *triangle_pass); +struct gles2_render_triangle_pass *gles2_render_triangle_pass_from_pass( + struct render_triangle_pass *triangle_pass); + +#endif // GLES2_TRIANGLE_PASS_PASS_H diff --git a/examples/render-pass-ext/meson.build b/examples/render-pass-ext/meson.build new file mode 100644 index 000000000..0ae142af6 --- /dev/null +++ b/examples/render-pass-ext/meson.build @@ -0,0 +1,26 @@ +gles2_sources = [] +pixman_sources = [] +vulkan_sources = [] + + if features.get('gles2-renderer') + subdir('gles2') + endif + +subdir('pixman') + +# if features.get('vulkan-renderer') +# subdir('vulkan') +# endif + +executable( + 'render-pass-ext', + [ + 'triangle_pass.c', + 'render-pass-ext.c', + gles2_sources, + pixman_sources, + vulkan_sources, + ], + dependencies: [wlroots, libdrm_header], + build_by_default: get_option('examples'), +) diff --git a/examples/render-pass-ext/pixman/meson.build b/examples/render-pass-ext/pixman/meson.build new file mode 100644 index 000000000..cdcd0763f --- /dev/null +++ b/examples/render-pass-ext/pixman/meson.build @@ -0,0 +1,3 @@ +pixman_sources = [ + files('triangle_pass.c'), +] diff --git a/examples/render-pass-ext/pixman/triangle_pass.c b/examples/render-pass-ext/pixman/triangle_pass.c new file mode 100644 index 000000000..3d4fada44 --- /dev/null +++ b/examples/render-pass-ext/pixman/triangle_pass.c @@ -0,0 +1,107 @@ +#include +#include + +#include +#include + +#include "render/pixman.h" +#include "triangle_pass.h" + +static bool triangle_contains(float px, float py, + float x0, float y0, float x1, float y1, float x2, float y2, + float *w0, float *w1, float *w2) { + float denom = (y1 - y2) * (x0 - x2) + (x2 - x1) * (y0 - y2); + if (denom == 0.0f) { + return false; + } + + *w0 = ((y1 - y2) * (px - x2) + (x2 - x1) * (py - y2)) / denom; + *w1 = ((y2 - y0) * (px - x2) + (x0 - x2) * (py - y2)) / denom; + *w2 = 1.0f - *w0 - *w1; + return *w0 >= 0.0f && *w1 >= 0.0f && *w2 >= 0.0f; +} + +static void custom_triangle_pixman_render(struct wlr_render_pass *render_pass, + const struct custom_render_triangle_options *options) { + struct wlr_pixman_render_pass *pixman_pass = + wlr_pixman_render_pass_from_render_pass(render_pass); + pixman_image_t *dst = pixman_pass->buffer->image; + int w = options->box.width; + int h = options->box.height; + if (w <= 0 || h <= 0) { + pixman_image_set_clip_region32(dst, NULL); + return; + } + + uint32_t *pixels = calloc((size_t)w * (size_t)h, sizeof(uint32_t)); + if (pixels == NULL) { + pixman_image_set_clip_region32(dst, NULL); + return; + } + + float x0 = w * 0.50f, y0 = h * 0.10f; + float x1 = w * 0.10f, y1 = h * 0.90f; + float x2 = w * 0.90f, y2 = h * 0.90f; + + for (int y = 0; y < h; y++) { + for (int x = 0; x < w; x++) { + float w0, w1, w2; + if (!triangle_contains(x + 0.5f, y + 0.5f, + x0, y0, x1, y1, x2, y2, &w0, &w1, &w2)) { + continue; + } + + uint8_t r = (uint8_t)(w0 * 255.0f); + uint8_t g = (uint8_t)(w1 * 255.0f); + uint8_t b = (uint8_t)(w2 * 255.0f); + pixels[y * w + x] = 0xFF000000u | ((uint32_t)r << 16) | + ((uint32_t)g << 8) | (uint32_t)b; + } + } + + pixman_image_t *triangle = pixman_image_create_bits(PIXMAN_a8r8g8b8, + w, h, pixels, w * sizeof(uint32_t)); + pixman_image_composite32(PIXMAN_OP_OVER, triangle, NULL, dst, + 0, 0, 0, 0, options->box.x, options->box.y, w, h); + pixman_image_unref(triangle); + pixman_image_set_clip_region32(dst, NULL); + free(pixels); +} + +static void custom_triangle_pixman_destroy(struct render_triangle_pass *pass) { + struct pixman_render_triangle_pass *pixman_pass = + pixman_render_triangle_pass_from_pass(pass); + free(pixman_pass); +} + +static const struct render_triangle_pass_impl render_triangle_pass_impl = { + .destroy = custom_triangle_pixman_destroy, + .render = custom_triangle_pixman_render, +}; + +struct render_triangle_pass *pixman_render_triangle_pass_create( + struct wlr_renderer *renderer) { + struct pixman_render_triangle_pass *pass = malloc(sizeof(*pass)); + if (pass == NULL) { + wlr_log_errno(WLR_ERROR, "failed to allocate wlr_pixman_render_submit_pass"); + return NULL; + } + + render_triangle_pass_init(&pass->base, &render_triangle_pass_impl); + + return &pass->base; +} + +bool render_triangle_pass_is_pixman(const struct render_triangle_pass *triangle_pass) { + return triangle_pass->impl == &render_triangle_pass_impl; +} + +struct pixman_render_triangle_pass *pixman_render_triangle_pass_from_pass( + struct render_triangle_pass *triangle_pass) { + assert(render_triangle_pass_is_pixman(triangle_pass)); + struct pixman_render_triangle_pass *pixman_pass = + wl_container_of(triangle_pass, pixman_pass, base); + + return pixman_pass; +} + diff --git a/examples/render-pass-ext/pixman/triangle_pass.h b/examples/render-pass-ext/pixman/triangle_pass.h new file mode 100644 index 000000000..5267799a8 --- /dev/null +++ b/examples/render-pass-ext/pixman/triangle_pass.h @@ -0,0 +1,16 @@ +#ifndef PIXMAN_TRIANGLE_PASS_PASS_H +#define PIXMAN_TRIANGLE_PASS_PASS_H + +#include "../triangle_pass.h" + +struct pixman_render_triangle_pass { + struct render_triangle_pass base; +}; + +struct render_triangle_pass *pixman_render_triangle_pass_create( + struct wlr_renderer *renderer); +bool render_triangle_pass_is_pixman(const struct render_triangle_pass *triangle_pass); +struct pixman_render_triangle_pass *pixman_render_triangle_pass_from_pass( + struct render_triangle_pass *triangle_pass); + +#endif // PIXMAN_TRIANGLE_PASS_PASS_H diff --git a/examples/render-pass-ext/render-pass-ext.c b/examples/render-pass-ext/render-pass-ext.c new file mode 100644 index 000000000..eb09abd55 --- /dev/null +++ b/examples/render-pass-ext/render-pass-ext.c @@ -0,0 +1,206 @@ +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "triangle_pass.h" + +struct sample_state { + struct wl_display *display; + struct wl_listener new_output; + struct wl_listener new_input; + struct wl_listener renderer_destroy; + struct wlr_renderer *renderer; + struct wlr_allocator *allocator; +}; + +struct sample_output { + struct sample_state *sample; + struct wlr_output *output; + struct wl_listener frame; + struct wl_listener destroy; +}; + +struct sample_keyboard { + struct sample_state *sample; + struct wlr_keyboard *wlr_keyboard; + struct wl_listener key; + struct wl_listener destroy; +}; + +static void output_frame_notify(struct wl_listener *listener, void *data) { + struct sample_output *sample_output = + wl_container_of(listener, sample_output, frame); + struct wlr_output *wlr_output = sample_output->output; + + struct wlr_output_state state; + wlr_output_state_init(&state); + struct wlr_render_pass *pass = + wlr_output_begin_render_pass(wlr_output, &state, NULL); + + int size = wlr_output->height < wlr_output->width ? + (wlr_output->height * 3) / 4 : (wlr_output->width * 3) / 4; + struct wlr_box triangle_box = { + .x = (wlr_output->width - size) / 2, + .y = (wlr_output->height - size) / 2, + .width = size, + .height = size, + }; + render_triangle_pass_add(pass, + &(struct custom_render_triangle_options){ + .box = triangle_box, + }); + + wlr_render_pass_submit(pass); + wlr_output_commit_state(wlr_output, &state); + wlr_output_state_finish(&state); +} + +static void output_remove_notify(struct wl_listener *listener, void *data) { + struct sample_output *sample_output = + wl_container_of(listener, sample_output, destroy); + wlr_log(WLR_DEBUG, "Output removed"); + wl_list_remove(&sample_output->frame.link); + wl_list_remove(&sample_output->destroy.link); + free(sample_output); +} + +static void new_output_notify(struct wl_listener *listener, void *data) { + struct wlr_output *output = data; + struct sample_state *sample = + wl_container_of(listener, sample, new_output); + + wlr_output_init_render(output, sample->allocator, sample->renderer); + sample->renderer->data = get_or_create_render_triangle_pass(sample->renderer); + struct sample_output *sample_output = calloc(1, sizeof(*sample_output)); + sample_output->output = output; + sample_output->sample = sample; + wl_signal_add(&output->events.frame, &sample_output->frame); + sample_output->frame.notify = output_frame_notify; + wl_signal_add(&output->events.destroy, &sample_output->destroy); + sample_output->destroy.notify = output_remove_notify; + + 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(output); + if (mode != NULL) { + wlr_output_state_set_mode(&state, mode); + } + wlr_output_commit_state(output, &state); + wlr_output_state_finish(&state); +} + +static void keyboard_key_notify(struct wl_listener *listener, void *data) { + struct sample_keyboard *keyboard = wl_container_of(listener, keyboard, key); + struct sample_state *sample = keyboard->sample; + struct wlr_keyboard_key_event *event = data; + uint32_t keycode = event->keycode + 8; + const xkb_keysym_t *syms; + int nsyms = xkb_state_key_get_syms(keyboard->wlr_keyboard->xkb_state, + keycode, &syms); + for (int i = 0; i < nsyms; i++) { + xkb_keysym_t sym = syms[i]; + if (sym == XKB_KEY_Escape) { + wl_display_terminate(sample->display); + } + } +} + +static void keyboard_destroy_notify(struct wl_listener *listener, void *data) { + struct sample_keyboard *keyboard = + wl_container_of(listener, keyboard, destroy); + wl_list_remove(&keyboard->destroy.link); + wl_list_remove(&keyboard->key.link); + free(keyboard); +} + +static void new_input_notify(struct wl_listener *listener, void *data) { + struct wlr_input_device *device = data; + struct sample_state *sample = wl_container_of(listener, sample, new_input); + switch (device->type) { + case WLR_INPUT_DEVICE_KEYBOARD:; + struct sample_keyboard *keyboard = calloc(1, sizeof(*keyboard)); + keyboard->wlr_keyboard = wlr_keyboard_from_input_device(device); + keyboard->sample = sample; + wl_signal_add(&device->events.destroy, &keyboard->destroy); + keyboard->destroy.notify = keyboard_destroy_notify; + wl_signal_add(&keyboard->wlr_keyboard->events.key, &keyboard->key); + keyboard->key.notify = keyboard_key_notify; + struct xkb_context *context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); + if (!context) { + wlr_log(WLR_ERROR, "Failed to create XKB context"); + exit(1); + } + struct xkb_keymap *keymap = xkb_keymap_new_from_names(context, NULL, + XKB_KEYMAP_COMPILE_NO_FLAGS); + if (!keymap) { + wlr_log(WLR_ERROR, "Failed to create XKB keymap"); + exit(1); + } + wlr_keyboard_set_keymap(keyboard->wlr_keyboard, keymap); + xkb_keymap_unref(keymap); + xkb_context_unref(context); + break; + default: + break; + } +} + +static void renderer_destroy_notify(struct wl_listener *listener, void *data) { + struct sample_state *sample = wl_container_of(listener, sample, renderer_destroy); + render_triangle_pass_destroy(sample->renderer->data); +} + +int main(void) { + wlr_log_init(WLR_DEBUG, NULL); + struct wl_display *display = wl_display_create(); + struct sample_state state = { + .display = display, + }; + + struct wlr_backend *backend = wlr_backend_autocreate( + wl_display_get_event_loop(display), NULL); + if (backend == NULL) { + return 1; + } + + state.renderer = wlr_renderer_autocreate(backend); + if (state.renderer == NULL) { + wlr_log(WLR_ERROR, "Failed to create renderer"); + wlr_backend_destroy(backend); + return 1; + } + + wl_signal_add(&state.renderer->events.destroy, &state.renderer_destroy); + state.renderer_destroy.notify = renderer_destroy_notify; + + state.allocator = wlr_allocator_autocreate(backend, state.renderer); + if (state.allocator == NULL) { + wlr_log(WLR_ERROR, "Failed to create allocator"); + wlr_backend_destroy(backend); + return 1; + } + + wl_signal_add(&backend->events.new_output, &state.new_output); + state.new_output.notify = new_output_notify; + wl_signal_add(&backend->events.new_input, &state.new_input); + state.new_input.notify = new_input_notify; + + if (!wlr_backend_start(backend)) { + wlr_log(WLR_ERROR, "Failed to start backend"); + wlr_backend_destroy(backend); + return 1; + } + + wl_display_run(display); + wl_display_destroy(display); + return 0; +} diff --git a/examples/render-pass-ext/triangle_pass.c b/examples/render-pass-ext/triangle_pass.c new file mode 100644 index 000000000..404e3e00e --- /dev/null +++ b/examples/render-pass-ext/triangle_pass.c @@ -0,0 +1,95 @@ +#include +#include +#include +#include +#if WLR_HAS_GLES2_RENDERER +#include +#endif +#if WLR_HAS_VULKAN_RENDERER +#include +#endif +#include +#include + +#include "triangle_pass.h" +#include "pixman/triangle_pass.h" +#if WLR_HAS_GLES2_RENDERER +#include "gles2/triangle_pass.h" +#endif + +void render_triangle_pass_init(struct render_triangle_pass *pass, + const struct render_triangle_pass_impl *impl) { + assert(impl->render); + *pass = (struct render_triangle_pass){ + .impl = impl, + }; + + wl_signal_init(&pass->events.destroy); +} + +void render_triangle_pass_destroy(struct render_triangle_pass *pass) { + if (pass == NULL) { + return; + } + + pass->impl->destroy(pass); +} + +struct render_triangle_pass *get_or_create_render_triangle_pass( + struct wlr_renderer *renderer) { + if (renderer == NULL) { + return NULL; + } + + if (renderer->data == NULL) { + struct render_triangle_pass *pass = NULL; + if (wlr_renderer_is_pixman(renderer)) { + pass = pixman_render_triangle_pass_create(renderer); + } + +#if WLR_HAS_GLES2_RENDERER + else if (wlr_renderer_is_gles2(renderer)) { + pass = gles2_render_triangle_pass_create(renderer); + } +#endif + +// #if WLR_HAS_VULKAN_RENDERER +// else if (wlr_renderer_is_vk(renderer)) { +// pass = wlr_vk_render_triangle_pass_create(renderer); +// } +// #endif + + renderer->data = pass; + return pass; + } else { + return renderer->data; + } +} + +void render_triangle_pass_add(struct wlr_render_pass *render_pass, + const struct custom_render_triangle_options *options) { + struct wlr_renderer *renderer = + wlr_get_wlr_renderer_from_render_pass(render_pass); + + struct render_triangle_pass *pass = renderer->data; + if (pass == NULL) { + wlr_log(WLR_ERROR, "No triangle pass is available for this renderer"); + return; + } + return pass->impl->render(render_pass, options); +} + +void custom_render_triangle_options_get_box(const struct custom_render_triangle_options *options, + const struct wlr_buffer *buffer, struct wlr_box *box) { + if (wlr_box_empty(&options->box)) { + *box = (struct wlr_box){ + .width = buffer->width, + .height = buffer->height, + }; + + return; + } + + *box = options->box; +} + diff --git a/examples/render-pass-ext/triangle_pass.h b/examples/render-pass-ext/triangle_pass.h new file mode 100644 index 000000000..f3ecfb040 --- /dev/null +++ b/examples/render-pass-ext/triangle_pass.h @@ -0,0 +1,41 @@ +#ifndef RENDER_PASS_EXT_H +#define RENDER_PASS_EXT_H + +#include + +#include +#include + +#include + +struct custom_render_triangle_options { + struct wlr_box box; +}; + +struct render_triangle_pass; + +struct render_triangle_pass_impl { + void (*destroy)(struct render_triangle_pass *pass); + void (*render)(struct wlr_render_pass *render_pass, + const struct custom_render_triangle_options *options); +}; + +struct render_triangle_pass { + const struct render_triangle_pass_impl *impl; + struct { + struct wl_signal destroy; + } events; +}; + +void render_triangle_pass_init(struct render_triangle_pass *pass, + const struct render_triangle_pass_impl *impl); +void render_triangle_pass_destroy(struct render_triangle_pass *pass); + +struct render_triangle_pass *get_or_create_render_triangle_pass( + struct wlr_renderer *renderer); +void render_triangle_pass_add(struct wlr_render_pass *render_pass, + const struct custom_render_triangle_options *options); +void custom_render_triangle_options_get_box(const struct custom_render_triangle_options *options, + const struct wlr_buffer *buffer, struct wlr_box *box); + +#endif // RENDER_PASS_EXT_H