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 diff --git a/include/meson.build b/include/meson.build index 165166c33..2881b97c1 100644 --- a/include/meson.build +++ b/include/meson.build @@ -29,6 +29,29 @@ install_subdir('wlr', exclude_files: exclude_files, ) +internal_render_headers = [ + 'render/pixman.h', + 'render/pixel_format.h', +] +if features.get('gles2-renderer') + internal_render_headers += [ + 'render/egl.h', + 'render/gles2.h', + ] +endif +if features.get('vulkan-renderer') + internal_render_headers += 'render/vulkan.h' +endif + +install_headers(internal_render_headers, + subdir: versioned_name, + preserve_path: true, +) + +install_headers('util/rect_union.h', + subdir: versioned_name / 'util', +) + foreach name, have : internal_features internal_config.set10('HAVE_' + name.underscorify().to_upper(), have) endforeach diff --git a/include/render/gles2.h b/include/render/gles2.h index 6b852dcb7..a2479e82e 100644 --- a/include/render/gles2.h +++ b/include/render/gles2.h @@ -73,18 +73,6 @@ struct wlr_gles2_renderer { PFNGLGETINTEGER64VEXTPROC glGetInteger64vEXT; } procs; - struct { - struct { - GLuint program; - GLint proj; - GLint color; - GLint pos_attrib; - } quad; - struct wlr_gles2_tex_shader tex_rgba; - struct wlr_gles2_tex_shader tex_rgbx; - struct wlr_gles2_tex_shader tex_ext; - } shaders; - struct wl_list buffers; // wlr_gles2_buffer.link struct wl_list textures; // wlr_gles2_texture.link }; @@ -151,7 +139,7 @@ void get_gles2_shm_formats(const struct wlr_gles2_renderer *renderer, GLuint gles2_buffer_get_fbo(struct wlr_gles2_buffer *buffer); -struct wlr_gles2_renderer *gles2_get_renderer( +struct wlr_gles2_renderer *wlr_gles2_renderer_from_renderer( struct wlr_renderer *wlr_renderer); struct wlr_gles2_render_timer *gles2_get_render_timer( struct wlr_render_timer *timer); @@ -164,13 +152,57 @@ struct wlr_texture *gles2_texture_from_buffer(struct wlr_renderer *wlr_renderer, struct wlr_buffer *buffer); void gles2_texture_destroy(struct wlr_gles2_texture *texture); -void push_gles2_debug_(struct wlr_gles2_renderer *renderer, +void wlr_gles2_push_debug_(struct wlr_gles2_renderer *renderer, const char *file, const char *func); -#define push_gles2_debug(renderer) push_gles2_debug_(renderer, _WLR_FILENAME, __func__) -void pop_gles2_debug(struct wlr_gles2_renderer *renderer); +#define wlr_gles2_push_debug(renderer) wlr_gles2_push_debug_(renderer, _WLR_FILENAME, __func__) +void wlr_gles2_pop_debug(struct wlr_gles2_renderer *renderer); struct wlr_gles2_render_pass *begin_gles2_buffer_pass(struct wlr_gles2_buffer *buffer, struct wlr_egl_context *prev_ctx, struct wlr_gles2_render_timer *timer, struct wlr_drm_syncobj_timeline *signal_timeline, uint64_t signal_point); +struct wlr_gles2_render_rect_pass { + struct wlr_render_rect_pass base; + struct wlr_gles2_renderer *renderer; + struct { + GLuint program; + GLint proj; + GLint color; + GLint pos_attrib; + } shader; +}; + +bool wlr_render_rect_pass_is_gles2(const struct wlr_render_rect_pass *rect_pass); +struct wlr_gles2_render_rect_pass *wlr_gles2_render_rect_pass_from_pass( + struct wlr_render_rect_pass *rect_pass); + +struct wlr_gles2_render_texture_pass { + struct wlr_render_texture_pass base; + struct wlr_gles2_renderer *renderer; + struct { + struct wlr_gles2_tex_shader tex_rgba; + struct wlr_gles2_tex_shader tex_rgbx; + struct wlr_gles2_tex_shader tex_ext; + } shaders; +}; + +bool wlr_render_texture_pass_is_gles2(const struct wlr_render_texture_pass *texture_pass); +struct wlr_gles2_render_texture_pass *wlr_gles2_render_texture_pass_from_pass( + struct wlr_render_texture_pass *texture_pass); + +struct wlr_gles2_render_submit_pass { + struct wlr_render_submit_pass base; +}; + +bool wlr_render_submit_pass_is_gles2(const struct wlr_render_submit_pass *submit_pass); +struct wlr_gles2_render_submit_pass *wlr_gles2_render_submit_pass_from_pass( + struct wlr_render_submit_pass *submit_pass); + +GLuint wlr_gles2_link_program(struct wlr_gles2_renderer *renderer, + const GLchar *vert_src, const GLchar *frag_src); + +struct wlr_gles2_render_pass *wlr_gles2_render_pass_from_render_pass( + struct wlr_render_pass *wlr_pass); +void wlr_gles_set_proj_matrix(GLint loc, float proj[9], const struct wlr_box *box); + #endif diff --git a/include/render/pixman.h b/include/render/pixman.h index 098421447..7e60b5f4a 100644 --- a/include/render/pixman.h +++ b/include/render/pixman.h @@ -61,4 +61,30 @@ bool begin_pixman_data_ptr_access(struct wlr_buffer *buffer, pixman_image_t **im struct wlr_pixman_render_pass *begin_pixman_render_pass( struct wlr_pixman_buffer *buffer); +struct wlr_pixman_render_rect_pass { + struct wlr_render_rect_pass base; +}; + +bool wlr_render_rect_pass_is_pixman(const struct wlr_render_rect_pass *rect_pass); +struct wlr_pixman_render_rect_pass *wlr_pixman_render_rect_pass_from_pass( + struct wlr_render_rect_pass *rect_pass); + +struct wlr_pixman_render_texture_pass { + struct wlr_render_texture_pass base; +}; + +bool wlr_render_texture_pass_is_pixman(const struct wlr_render_texture_pass *texture_pass); +struct wlr_pixman_render_texture_pass *wlr_pixman_render_texture_pass_from_pass( + struct wlr_render_texture_pass *texture_pass); + +struct wlr_pixman_render_submit_pass { + struct wlr_render_submit_pass base; +}; + +bool wlr_render_submit_pass_is_pixman(const struct wlr_render_submit_pass *submit_pass); +struct wlr_pixman_render_submit_pass *wlr_pixman_render_submit_pass_from_pass( + struct wlr_render_submit_pass *submit_pass); +struct wlr_pixman_render_pass *wlr_pixman_render_pass_from_render_pass( + struct wlr_render_pass *wlr_pass); + #endif diff --git a/include/render/vulkan.h b/include/render/vulkan.h index 021749c27..f173fa45a 100644 --- a/include/render/vulkan.h +++ b/include/render/vulkan.h @@ -305,31 +305,8 @@ struct wlr_vk_renderer { VkCommandPool command_pool; - VkShaderModule vert_module; - VkShaderModule tex_frag_module; - VkShaderModule quad_frag_module; - VkShaderModule output_module; - struct wl_list pipeline_layouts; // struct wlr_vk_pipeline_layout.link - // for blend->output subpass - VkPipelineLayout output_pipe_layout; - VkDescriptorSetLayout output_ds_srgb_layout; - VkDescriptorSetLayout output_ds_lut3d_layout; - VkSampler output_sampler_lut3d; - // descriptor set indicating dummy 1x1x1 image, for use in the lut3d slot - VkDescriptorSet output_ds_lut3d_dummy; - struct wlr_vk_descriptor_pool *output_ds_lut3d_dummy_pool; - - size_t last_output_pool_size; - struct wl_list output_descriptor_pools; // wlr_vk_descriptor_pool.link - - // dummy sampler to bind when output shader is not using a lookup table - VkImage dummy3d_image; - VkDeviceMemory dummy3d_mem; - VkImageView dummy3d_image_view; - bool dummy3d_image_transitioned; - VkSemaphore timeline_semaphore; uint64_t timeline_point; @@ -395,7 +372,8 @@ struct wlr_vk_texture_view { struct wlr_vk_pipeline *setup_get_or_create_pipeline( struct wlr_vk_render_format_setup *setup, - const struct wlr_vk_pipeline_key *key); + const struct wlr_vk_pipeline_key *key, + VkShaderModule vert_module, VkShaderModule frag_module); struct wlr_vk_pipeline_layout *get_or_create_pipeline_layout( struct wlr_vk_renderer *renderer, const struct wlr_vk_pipeline_layout_key *key); @@ -479,6 +457,7 @@ void vulkan_free_ds(struct wlr_vk_renderer *renderer, struct wlr_vk_format_props *vulkan_format_props_from_drm( struct wlr_vk_device *dev, uint32_t drm_format); struct wlr_vk_renderer *vulkan_get_renderer(struct wlr_renderer *r); +VkShaderModule vulkan_create_common_vert_module(struct wlr_vk_renderer *renderer); struct wlr_vk_command_buffer *vulkan_acquire_command_buffer( struct wlr_vk_renderer *renderer); @@ -606,4 +585,64 @@ void vulkan_change_layout(VkCommandBuffer cb, VkImage img, #endif +struct wlr_vk_render_rect_pass { + struct wlr_render_rect_pass base; + struct wlr_vk_renderer *renderer; + struct { + VkShaderModule vert_module; + VkShaderModule frag_module; + } shader; +}; + +bool wlr_render_rect_pass_is_vk(const struct wlr_render_rect_pass *rect_pass); +struct wlr_vk_render_rect_pass *wlr_vk_render_rect_pass_from_pass( + struct wlr_render_rect_pass *rect_pass); + +struct wlr_vk_render_texture_pass { + struct wlr_render_texture_pass base; + struct wlr_vk_renderer *renderer; + struct { + VkShaderModule vert_module; + VkShaderModule frag_module; + } shader; +}; + +bool wlr_render_texture_pass_is_vk(const struct wlr_render_texture_pass *texture_pass); +struct wlr_vk_render_texture_pass *wlr_vk_render_texture_pass_from_pass( + const struct wlr_render_texture_pass *texture_pass); + +struct wlr_vk_render_submit_pass { + struct wlr_render_submit_pass base; + struct wlr_vk_renderer *renderer; + + struct { + VkShaderModule vert_module; + VkShaderModule frag_module; + + VkPipelineLayout pipe_layout; + VkDescriptorSetLayout ds_srgb_layout; + VkDescriptorSetLayout ds_lut3d_layout; + VkSampler sampler_lut3d; + // descriptor set indicating dummy 1x1x1 image, for use in the lut3d slot + VkDescriptorSet ds_lut3d_dummy; + struct wlr_vk_descriptor_pool *ds_lut3d_dummy_pool; + + size_t last_pool_size; + struct wl_list descriptor_pools; // wlr_vk_descriptor_pool.link + + // dummy sampler to bind when output shader is not using a lookup table + VkImage dummy3d_image; + VkDeviceMemory dummy3d_mem; + VkImageView dummy3d_image_view; + bool dummy3d_image_transitioned; + } output; +}; + +bool wlr_render_submit_pass_is_vk(const struct wlr_render_submit_pass *submit_pass); +struct wlr_vk_render_submit_pass *wlr_vk_render_submit_pass_from_pass( + struct wlr_render_submit_pass *submit_pass); + +bool vulkan_init_submit_pass_output(struct wlr_vk_renderer *renderer, + struct wlr_vk_render_submit_pass *submit_pass); + #endif // RENDER_VULKAN_H diff --git a/include/wlr/render/interface.h b/include/wlr/render/interface.h index 89f6de970..89ce62171 100644 --- a/include/wlr/render/interface.h +++ b/include/wlr/render/interface.h @@ -48,21 +48,22 @@ struct wlr_texture_impl { void wlr_texture_init(struct wlr_texture *texture, struct wlr_renderer *rendener, const struct wlr_texture_impl *impl, uint32_t width, uint32_t height); +struct wlr_render_pass; + +struct wlr_render_pass_impl { + void (*destroy)(struct wlr_render_pass *pass); + struct wlr_renderer *(*get_renderer)(struct wlr_render_pass *pass); +}; + struct wlr_render_pass { const struct wlr_render_pass_impl *impl; }; void wlr_render_pass_init(struct wlr_render_pass *pass, const struct wlr_render_pass_impl *impl); - -struct wlr_render_pass_impl { - bool (*submit)(struct wlr_render_pass *pass); - void (*add_texture)(struct wlr_render_pass *pass, - const struct wlr_render_texture_options *options); - /* Implementers are also guaranteed that options->box is nonempty */ - void (*add_rect)(struct wlr_render_pass *pass, - const struct wlr_render_rect_options *options); -}; +void wlr_render_pass_destroy(struct wlr_render_pass *pass); +struct wlr_renderer *wlr_get_wlr_renderer_from_render_pass( + struct wlr_render_pass *wlr_pass); struct wlr_render_timer { const struct wlr_render_timer_impl *impl; @@ -87,4 +88,84 @@ void wlr_texture_read_pixels_options_get_src_box( void *wlr_texture_read_pixel_options_get_data( const struct wlr_texture_read_pixels_options *options); +struct wlr_render_rect_pass; + +struct wlr_render_rect_pass_impl { + void (*destroy)(struct wlr_render_rect_pass *pass); + void (*render)(struct wlr_render_pass *pass, + const struct wlr_render_rect_options *options); +}; + +struct wlr_render_rect_pass { + const struct wlr_render_rect_pass_impl *impl; + struct { + struct wl_signal destroy; + } events; +}; + +void wlr_render_rect_pass_init(struct wlr_render_rect_pass *pass, + const struct wlr_render_rect_pass_impl *impl); +void wlr_render_rect_pass_destroy(struct wlr_render_rect_pass *pass); + +struct wlr_render_rect_pass *get_or_create_render_rect_pass( + struct wlr_renderer *renderer); +struct wlr_render_rect_pass *wlr_pixman_render_rect_pass_create(void); +struct wlr_render_rect_pass *wlr_gles2_render_rect_pass_create( + struct wlr_renderer *wlr_renderer); +struct wlr_render_rect_pass *wlr_vk_render_rect_pass_create( + struct wlr_renderer *wlr_renderer); + +struct wlr_render_texture_pass; + +struct wlr_render_texture_pass_impl { + void (*destroy)(struct wlr_render_texture_pass *pass); + void (*render)(struct wlr_render_pass *pass, + const struct wlr_render_texture_options *options); +}; + +struct wlr_render_texture_pass { + const struct wlr_render_texture_pass_impl *impl; + struct { + struct wl_signal destroy; + } events; +}; + +void wlr_render_texture_pass_init(struct wlr_render_texture_pass *pass, + const struct wlr_render_texture_pass_impl *impl); +void wlr_render_texture_pass_destroy(struct wlr_render_texture_pass *pass); + +struct wlr_render_texture_pass *get_or_create_render_texture_pass( + struct wlr_renderer *renderer); +struct wlr_render_texture_pass *wlr_pixman_render_texture_pass_create(void); +struct wlr_render_texture_pass *wlr_gles2_render_texture_pass_create( + struct wlr_renderer *wlr_renderer); +struct wlr_render_texture_pass *wlr_vk_render_texture_pass_create( + struct wlr_renderer *wlr_renderer); + +struct wlr_render_submit_pass; + +struct wlr_render_submit_pass_impl { + void (*destroy)(struct wlr_render_submit_pass *pass); + bool (*render)(struct wlr_render_pass *pass); +}; + +struct wlr_render_submit_pass { + const struct wlr_render_submit_pass_impl *impl; + struct { + struct wl_signal destroy; + } events; +}; + +void wlr_render_submit_pass_init(struct wlr_render_submit_pass *pass, + const struct wlr_render_submit_pass_impl *impl); +void wlr_render_submit_pass_destroy(struct wlr_render_submit_pass *pass); +struct wlr_render_submit_pass *get_or_create_render_submit_pass( + struct wlr_renderer *renderer); +struct wlr_render_submit_pass *wlr_pixman_render_submit_pass_create(void); +struct wlr_render_submit_pass *wlr_gles2_render_submit_pass_create(void); +struct wlr_render_submit_pass *wlr_vk_render_submit_pass_create( + struct wlr_renderer *wlr_renderer); +struct wlr_vk_render_pass *wlr_vk_render_pass_from_render_pass( + struct wlr_render_pass *wlr_pass); + #endif diff --git a/include/wlr/render/wlr_renderer.h b/include/wlr/render/wlr_renderer.h index 902d7564d..259bfc5a9 100644 --- a/include/wlr/render/wlr_renderer.h +++ b/include/wlr/render/wlr_renderer.h @@ -26,6 +26,11 @@ struct wlr_fbox; * A renderer for basic 2D operations. */ struct wlr_renderer { + struct wlr_render_rect_pass *rect_pass; + struct wlr_render_texture_pass *texture_pass; + struct wlr_render_submit_pass *submit_pass; + void *data; + // Capabilities required for the buffer used as a render target (bitmask of // enum wlr_buffer_cap) uint32_t render_buffer_caps; diff --git a/include/wlr/types/wlr_output.h b/include/wlr/types/wlr_output.h index c8e44b0e6..d8a8e9965 100644 --- a/include/wlr/types/wlr_output.h +++ b/include/wlr/types/wlr_output.h @@ -250,6 +250,8 @@ struct wlr_output { struct wl_signal description; struct wl_signal request_state; // struct wlr_output_event_request_state struct wl_signal destroy; + // Emitted when the output's rendering subsystem is initialized or reinitialized + struct wl_signal render_inited; } events; struct wl_event_source *idle_frame; diff --git a/render/gles2/pass.c b/render/gles2/pass.c index a70ea1320..b832ad11f 100644 --- a/render/gles2/pass.c +++ b/render/gles2/pass.c @@ -9,23 +9,30 @@ #include "render/gles2.h" #include "util/matrix.h" +#include "common_vert_src.h" +#include "quad_frag_src.h" +#include "tex_rgba_frag_src.h" +#include "tex_rgbx_frag_src.h" +#include "tex_external_frag_src.h" + #define MAX_QUADS 86 // 4kb static const struct wlr_render_pass_impl render_pass_impl; -static struct wlr_gles2_render_pass *get_render_pass(struct wlr_render_pass *wlr_pass) { +struct wlr_gles2_render_pass *wlr_gles2_render_pass_from_render_pass( + struct wlr_render_pass *wlr_pass) { assert(wlr_pass->impl == &render_pass_impl); struct wlr_gles2_render_pass *pass = wl_container_of(wlr_pass, pass, base); return pass; } static bool render_pass_submit(struct wlr_render_pass *wlr_pass) { - struct wlr_gles2_render_pass *pass = get_render_pass(wlr_pass); + struct wlr_gles2_render_pass *pass = wlr_gles2_render_pass_from_render_pass(wlr_pass); struct wlr_gles2_renderer *renderer = pass->buffer->renderer; struct wlr_gles2_render_timer *timer = pass->timer; bool ok = false; - push_gles2_debug(renderer); + wlr_gles2_push_debug(renderer); if (timer) { // clear disjoint flag @@ -65,7 +72,7 @@ static bool render_pass_submit(struct wlr_render_pass *wlr_pass) { out: glBindFramebuffer(GL_FRAMEBUFFER, 0); - pop_gles2_debug(renderer); + wlr_gles2_pop_debug(renderer); wlr_egl_restore_context(&pass->prev_ctx); wlr_drm_syncobj_timeline_unref(pass->signal_timeline); @@ -124,7 +131,7 @@ static void render(const struct wlr_box *box, const pixman_region32_t *clip, GLi pixman_region32_fini(®ion); } -static void set_proj_matrix(GLint loc, float proj[9], const struct wlr_box *box) { +void wlr_gles_set_proj_matrix(GLint loc, float proj[9], const struct wlr_box *box) { float gl_matrix[9]; wlr_matrix_identity(gl_matrix); wlr_matrix_translate(gl_matrix, box->x, box->y); @@ -166,25 +173,26 @@ static void setup_blending(enum wlr_render_blend_mode mode) { static void render_pass_add_texture(struct wlr_render_pass *wlr_pass, const struct wlr_render_texture_options *options) { - struct wlr_gles2_render_pass *pass = get_render_pass(wlr_pass); + struct wlr_gles2_render_pass *pass = wlr_gles2_render_pass_from_render_pass(wlr_pass); struct wlr_gles2_renderer *renderer = pass->buffer->renderer; struct wlr_gles2_texture *texture = gles2_get_texture(options->texture); - + struct wlr_gles2_render_texture_pass *texture_pass = + wlr_gles2_render_texture_pass_from_pass(renderer->wlr_renderer.texture_pass); struct wlr_gles2_tex_shader *shader = NULL; switch (texture->target) { case GL_TEXTURE_2D: if (texture->has_alpha) { - shader = &renderer->shaders.tex_rgba; + shader = &texture_pass->shaders.tex_rgba; } else { - shader = &renderer->shaders.tex_rgbx; + shader = &texture_pass->shaders.tex_rgbx; } break; case GL_TEXTURE_EXTERNAL_OES: // EGL_EXT_image_dma_buf_import_modifiers requires // GL_OES_EGL_image_external assert(renderer->exts.OES_egl_image_external); - shader = &renderer->shaders.tex_ext; + shader = &texture_pass->shaders.tex_ext; break; default: abort(); @@ -201,7 +209,7 @@ static void render_pass_add_texture(struct wlr_render_pass *wlr_pass, src_fbox.width /= options->texture->width; src_fbox.height /= options->texture->height; - push_gles2_debug(renderer); + wlr_gles2_push_debug(renderer); if (options->wait_timeline != NULL) { int sync_file_fd = @@ -244,26 +252,28 @@ static void render_pass_add_texture(struct wlr_render_pass *wlr_pass, glUniform1i(shader->tex, 0); glUniform1f(shader->alpha, alpha); - set_proj_matrix(shader->proj, pass->projection_matrix, &dst_box); + wlr_gles_set_proj_matrix(shader->proj, pass->projection_matrix, &dst_box); set_tex_matrix(shader->tex_proj, options->transform, &src_fbox); render(&dst_box, options->clip, shader->pos_attrib); glBindTexture(texture->target, 0); - pop_gles2_debug(renderer); + wlr_gles2_pop_debug(renderer); } static void render_pass_add_rect(struct wlr_render_pass *wlr_pass, const struct wlr_render_rect_options *options) { - struct wlr_gles2_render_pass *pass = get_render_pass(wlr_pass); + struct wlr_gles2_render_pass *pass = wlr_gles2_render_pass_from_render_pass(wlr_pass); struct wlr_gles2_renderer *renderer = pass->buffer->renderer; + struct wlr_gles2_render_rect_pass *rect_pass = + wlr_gles2_render_rect_pass_from_pass(renderer->wlr_renderer.rect_pass); const struct wlr_render_color *color = &options->color; struct wlr_box box; struct wlr_buffer *wlr_buffer = pass->buffer->buffer; wlr_render_rect_options_get_box(options, wlr_buffer, &box); - push_gles2_debug(renderer); + wlr_gles2_push_debug(renderer); enum wlr_render_blend_mode blend_mode = color->a == 1.0 ? WLR_RENDER_BLEND_MODE_NONE : options->blend_mode; if (blend_mode == WLR_RENDER_BLEND_MODE_NONE && @@ -275,19 +285,29 @@ static void render_pass_add_rect(struct wlr_render_pass *wlr_pass, glClear(GL_COLOR_BUFFER_BIT); } else { setup_blending(blend_mode); - glUseProgram(renderer->shaders.quad.program); - set_proj_matrix(renderer->shaders.quad.proj, pass->projection_matrix, &box); - glUniform4f(renderer->shaders.quad.color, color->r, color->g, color->b, color->a); - render(&box, options->clip, renderer->shaders.quad.pos_attrib); + glUseProgram(rect_pass->shader.program); + wlr_gles_set_proj_matrix(rect_pass->shader.proj, pass->projection_matrix, &box); + glUniform4f(rect_pass->shader.color, color->r, color->g, color->b, color->a); + render(&box, options->clip, rect_pass->shader.pos_attrib); } - pop_gles2_debug(renderer); + wlr_gles2_pop_debug(renderer); +} + +static void render_pass_destory(struct wlr_render_pass *wlr_pass) { + (void)wlr_pass; +} + +static struct wlr_renderer *render_pass_get_renderer(struct wlr_render_pass *wlr_pass) { + struct wlr_gles2_render_pass *pass = wlr_gles2_render_pass_from_render_pass(wlr_pass); + struct wlr_gles2_renderer *renderer = pass->buffer->renderer; + + return &renderer->wlr_renderer; } static const struct wlr_render_pass_impl render_pass_impl = { - .submit = render_pass_submit, - .add_texture = render_pass_add_texture, - .add_rect = render_pass_add_rect, + .destroy = render_pass_destory, + .get_renderer = render_pass_get_renderer, }; static const char *reset_status_str(GLenum status) { @@ -341,13 +361,217 @@ struct wlr_gles2_render_pass *begin_gles2_buffer_pass(struct wlr_gles2_buffer *b matrix_projection(pass->projection_matrix, wlr_buffer->width, wlr_buffer->height, WL_OUTPUT_TRANSFORM_FLIPPED_180); - push_gles2_debug(renderer); + wlr_gles2_push_debug(renderer); glBindFramebuffer(GL_FRAMEBUFFER, fbo); glViewport(0, 0, wlr_buffer->width, wlr_buffer->height); glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); glDisable(GL_SCISSOR_TEST); - pop_gles2_debug(renderer); + wlr_gles2_pop_debug(renderer); + + return pass; +} + +static void render_rect_pass_destroy(struct wlr_render_rect_pass *pass) { + struct wlr_gles2_render_rect_pass *gles2_pass = + wlr_gles2_render_rect_pass_from_pass(pass); + wlr_gles2_push_debug(gles2_pass->renderer); + glDeleteProgram(gles2_pass->shader.program); + wlr_gles2_pop_debug(gles2_pass->renderer); + free(gles2_pass); +} + +static const struct wlr_render_rect_pass_impl render_rect_pass_impl = { + .destroy = render_rect_pass_destroy, + .render = render_pass_add_rect, +}; + +struct wlr_render_rect_pass *wlr_gles2_render_rect_pass_create( + struct wlr_renderer *wlr_renderer) { + struct wlr_gles2_render_rect_pass *pass = calloc(1, sizeof(*pass)); + if (pass == NULL) { + wlr_log_errno(WLR_ERROR, "failed to allocate wlr_gles2_render_rect_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; + } + + wlr_render_rect_pass_init(&pass->base, &render_rect_pass_impl); + wlr_gles2_push_debug(renderer); + GLuint prog; + pass->shader.program = prog = + wlr_gles2_link_program(renderer, common_vert_src, quad_frag_src); + if (!pass->shader.program) { + goto error; + } + + pass->shader.proj = glGetUniformLocation(pass->shader.program, "proj"); + pass->shader.color = glGetUniformLocation(pass->shader.program, "color"); + pass->shader.pos_attrib = glGetAttribLocation(pass->shader.program, "pos"); + wlr_gles2_pop_debug(renderer); + wlr_egl_unset_current(renderer->egl); + pass->renderer = renderer; + return &pass->base; + +error: + render_rect_pass_destroy(&pass->base); + wlr_gles2_pop_debug(renderer); + wlr_egl_unset_current(renderer->egl); + + return NULL; +} + +bool wlr_render_rect_pass_is_gles2(const struct wlr_render_rect_pass *rect_pass) { + return rect_pass != NULL && rect_pass->impl == &render_rect_pass_impl; +} + +struct wlr_gles2_render_rect_pass *wlr_gles2_render_rect_pass_from_pass( + struct wlr_render_rect_pass *rect_pass) { + if (!wlr_render_rect_pass_is_gles2(rect_pass)) { + return NULL; + } + + struct wlr_gles2_render_rect_pass *pass = + wl_container_of(rect_pass, pass, base); + + return pass; +} + +static void render_texture_pass_destroy(struct wlr_render_texture_pass *pass) { + struct wlr_gles2_render_texture_pass *gles2_pass = + wlr_gles2_render_texture_pass_from_pass(pass); + wlr_gles2_push_debug(gles2_pass->renderer); + glDeleteProgram(gles2_pass->shaders.tex_rgba.program); + glDeleteProgram(gles2_pass->shaders.tex_rgbx.program); + glDeleteProgram(gles2_pass->shaders.tex_ext.program); + wlr_gles2_pop_debug(gles2_pass->renderer); + free(gles2_pass); +} + +static const struct wlr_render_texture_pass_impl render_texture_pass_impl = { + .destroy = render_texture_pass_destroy, + .render = render_pass_add_texture, +}; + +struct wlr_render_texture_pass *wlr_gles2_render_texture_pass_create( + struct wlr_renderer *wlr_renderer) { + struct wlr_gles2_render_texture_pass *pass = calloc(1, sizeof(*pass)); + if (pass == NULL) { + wlr_log_errno(WLR_ERROR, "failed to allocate wlr_gles2_render_texture_pass"); + return NULL; + } + wlr_render_texture_pass_init(&pass->base, &render_texture_pass_impl); + struct wlr_gles2_renderer *renderer = wlr_gles2_renderer_from_renderer(wlr_renderer); + if (!wlr_egl_make_current(renderer->egl, NULL)) { + free(pass); + return NULL; + } + wlr_gles2_push_debug(renderer); + GLuint prog; + pass->shaders.tex_rgba.program = prog = + wlr_gles2_link_program(renderer, common_vert_src, tex_rgba_frag_src); + if (!pass->shaders.tex_rgba.program) { + goto error; + } + pass->shaders.tex_rgba.proj = glGetUniformLocation(prog, "proj"); + pass->shaders.tex_rgba.tex_proj = glGetUniformLocation(prog, "tex_proj"); + pass->shaders.tex_rgba.tex = glGetUniformLocation(prog, "tex"); + pass->shaders.tex_rgba.alpha = glGetUniformLocation(prog, "alpha"); + pass->shaders.tex_rgba.pos_attrib = glGetAttribLocation(prog, "pos"); + + pass->shaders.tex_rgbx.program = prog = + wlr_gles2_link_program(renderer, common_vert_src, tex_rgbx_frag_src); + if (!pass->shaders.tex_rgbx.program) { + goto error; + } + pass->shaders.tex_rgbx.proj = glGetUniformLocation(prog, "proj"); + pass->shaders.tex_rgbx.tex_proj = glGetUniformLocation(prog, "tex_proj"); + pass->shaders.tex_rgbx.tex = glGetUniformLocation(prog, "tex"); + pass->shaders.tex_rgbx.alpha = glGetUniformLocation(prog, "alpha"); + pass->shaders.tex_rgbx.pos_attrib = glGetAttribLocation(prog, "pos"); + + if (renderer->exts.OES_egl_image_external) { + pass->shaders.tex_ext.program = prog = + wlr_gles2_link_program(renderer, common_vert_src, tex_external_frag_src); + if (!pass->shaders.tex_ext.program) { + goto error; + } + pass->shaders.tex_ext.proj = glGetUniformLocation(prog, "proj"); + pass->shaders.tex_ext.tex_proj = glGetUniformLocation(prog, "tex_proj"); + pass->shaders.tex_ext.tex = glGetUniformLocation(prog, "tex"); + pass->shaders.tex_ext.alpha = glGetUniformLocation(prog, "alpha"); + pass->shaders.tex_ext.pos_attrib = glGetAttribLocation(prog, "pos"); + } + + wlr_gles2_pop_debug(renderer); + + wlr_egl_unset_current(renderer->egl); + pass->renderer = renderer; + return &pass->base; + +error: + render_texture_pass_destroy(&pass->base); + wlr_gles2_pop_debug(renderer); + wlr_egl_unset_current(renderer->egl); + + return NULL; +} + +bool wlr_render_texture_pass_is_gles2(const struct wlr_render_texture_pass *texture_pass) { + return texture_pass != NULL && texture_pass->impl == &render_texture_pass_impl; +} + +struct wlr_gles2_render_texture_pass *wlr_gles2_render_texture_pass_from_pass( + struct wlr_render_texture_pass *texture_pass) { + if (!wlr_render_texture_pass_is_gles2(texture_pass)) { + return NULL; + } + + struct wlr_gles2_render_texture_pass *pass = + wl_container_of(texture_pass, pass, base); + + return pass; +} + +static void render_submit_pass_destroy(struct wlr_render_submit_pass *pass) { + struct wlr_gles2_render_submit_pass *gles2_pass = + wlr_gles2_render_submit_pass_from_pass(pass); + free(gles2_pass); +} + +static const struct wlr_render_submit_pass_impl gles2_render_submit_pass_impl = { + .destroy = render_submit_pass_destroy, + .render = render_pass_submit, +}; + +struct wlr_render_submit_pass *wlr_gles2_render_submit_pass_create(void) { + struct wlr_gles2_render_submit_pass *pass = calloc(1, sizeof(*pass)); + if (pass == NULL) { + wlr_log_errno(WLR_ERROR, "failed to allocate wlr_gles2_render_submit_pass"); + return NULL; + } + + wlr_render_submit_pass_init(&pass->base, &gles2_render_submit_pass_impl); + + return &pass->base; +} + +bool wlr_render_submit_pass_is_gles2(const struct wlr_render_submit_pass *submit_pass) { + return submit_pass->impl == &gles2_render_submit_pass_impl; +} + +struct wlr_gles2_render_submit_pass *wlr_gles2_render_submit_pass_from_pass( + struct wlr_render_submit_pass *submit_pass) { + if (!wlr_render_submit_pass_is_gles2(submit_pass)) { + return NULL; + } + + struct wlr_gles2_render_submit_pass *pass = + wl_container_of(submit_pass, pass, base); return pass; } diff --git a/render/gles2/renderer.c b/render/gles2/renderer.c index 7f01b8acd..9c8a4955c 100644 --- a/render/gles2/renderer.c +++ b/render/gles2/renderer.c @@ -20,12 +20,6 @@ #include "render/pixel_format.h" #include "util/time.h" -#include "common_vert_src.h" -#include "quad_frag_src.h" -#include "tex_rgba_frag_src.h" -#include "tex_rgbx_frag_src.h" -#include "tex_external_frag_src.h" - static const struct wlr_renderer_impl renderer_impl; static const struct wlr_render_timer_impl render_timer_impl; @@ -33,7 +27,7 @@ bool wlr_renderer_is_gles2(const struct wlr_renderer *wlr_renderer) { return wlr_renderer->impl == &renderer_impl; } -struct wlr_gles2_renderer *gles2_get_renderer( +struct wlr_gles2_renderer *wlr_gles2_renderer_from_renderer( struct wlr_renderer *wlr_renderer) { assert(wlr_renderer_is_gles2(wlr_renderer)); struct wlr_gles2_renderer *renderer = wl_container_of(wlr_renderer, renderer, wlr_renderer); @@ -57,13 +51,13 @@ static void destroy_buffer(struct wlr_gles2_buffer *buffer) { struct wlr_egl_context prev_ctx; wlr_egl_make_current(buffer->renderer->egl, &prev_ctx); - push_gles2_debug(buffer->renderer); + wlr_gles2_push_debug(buffer->renderer); glDeleteFramebuffers(1, &buffer->fbo); glDeleteRenderbuffers(1, &buffer->rbo); glDeleteTextures(1, &buffer->tex); - pop_gles2_debug(buffer->renderer); + wlr_gles2_pop_debug(buffer->renderer); wlr_egl_destroy_image(buffer->renderer->egl, buffer->image); @@ -93,7 +87,7 @@ GLuint gles2_buffer_get_fbo(struct wlr_gles2_buffer *buffer) { return buffer->fbo; } - push_gles2_debug(buffer->renderer); + wlr_gles2_push_debug(buffer->renderer); if (!buffer->rbo) { glGenRenderbuffers(1, &buffer->rbo); @@ -116,7 +110,7 @@ GLuint gles2_buffer_get_fbo(struct wlr_gles2_buffer *buffer) { buffer->fbo = 0; } - pop_gles2_debug(buffer->renderer); + wlr_gles2_pop_debug(buffer->renderer); return buffer->fbo; } @@ -166,7 +160,7 @@ error_buffer: static const struct wlr_drm_format_set *gles2_get_texture_formats( struct wlr_renderer *wlr_renderer, uint32_t buffer_caps) { - struct wlr_gles2_renderer *renderer = gles2_get_renderer(wlr_renderer); + struct wlr_gles2_renderer *renderer = wlr_gles2_renderer_from_renderer(wlr_renderer); if (buffer_caps & WLR_BUFFER_CAP_DMABUF) { return wlr_egl_get_dmabuf_texture_formats(renderer->egl); } else if (buffer_caps & WLR_BUFFER_CAP_DATA_PTR) { @@ -178,13 +172,13 @@ static const struct wlr_drm_format_set *gles2_get_texture_formats( static const struct wlr_drm_format_set *gles2_get_render_formats( struct wlr_renderer *wlr_renderer) { - struct wlr_gles2_renderer *renderer = gles2_get_renderer(wlr_renderer); + struct wlr_gles2_renderer *renderer = wlr_gles2_renderer_from_renderer(wlr_renderer); return wlr_egl_get_dmabuf_render_formats(renderer->egl); } static int gles2_get_drm_fd(struct wlr_renderer *wlr_renderer) { struct wlr_gles2_renderer *renderer = - gles2_get_renderer(wlr_renderer); + wlr_gles2_renderer_from_renderer(wlr_renderer); if (renderer->drm_fd < 0) { renderer->drm_fd = wlr_egl_dup_drm_fd(renderer->egl); @@ -195,12 +189,12 @@ static int gles2_get_drm_fd(struct wlr_renderer *wlr_renderer) { struct wlr_egl *wlr_gles2_renderer_get_egl(struct wlr_renderer *wlr_renderer) { struct wlr_gles2_renderer *renderer = - gles2_get_renderer(wlr_renderer); + wlr_gles2_renderer_from_renderer(wlr_renderer); return renderer->egl; } static void gles2_destroy(struct wlr_renderer *wlr_renderer) { - struct wlr_gles2_renderer *renderer = gles2_get_renderer(wlr_renderer); + struct wlr_gles2_renderer *renderer = wlr_gles2_renderer_from_renderer(wlr_renderer); wlr_egl_make_current(renderer->egl, NULL); @@ -214,13 +208,6 @@ static void gles2_destroy(struct wlr_renderer *wlr_renderer) { destroy_buffer(buffer); } - push_gles2_debug(renderer); - glDeleteProgram(renderer->shaders.quad.program); - glDeleteProgram(renderer->shaders.tex_rgba.program); - glDeleteProgram(renderer->shaders.tex_rgbx.program); - glDeleteProgram(renderer->shaders.tex_ext.program); - pop_gles2_debug(renderer); - if (renderer->exts.KHR_debug) { glDisable(GL_DEBUG_OUTPUT_KHR); renderer->procs.glDebugMessageCallbackKHR(NULL, NULL); @@ -240,7 +227,7 @@ static void gles2_destroy(struct wlr_renderer *wlr_renderer) { static struct wlr_render_pass *gles2_begin_buffer_pass(struct wlr_renderer *wlr_renderer, struct wlr_buffer *wlr_buffer, const struct wlr_buffer_pass_options *options) { - struct wlr_gles2_renderer *renderer = gles2_get_renderer(wlr_renderer); + struct wlr_gles2_renderer *renderer = wlr_gles2_renderer_from_renderer(wlr_renderer); struct wlr_egl_context prev_ctx = {0}; if (!wlr_egl_make_current(renderer->egl, &prev_ctx)) { @@ -268,7 +255,7 @@ static struct wlr_render_pass *gles2_begin_buffer_pass(struct wlr_renderer *wlr_ GLuint wlr_gles2_renderer_get_buffer_fbo(struct wlr_renderer *wlr_renderer, struct wlr_buffer *wlr_buffer) { - struct wlr_gles2_renderer *renderer = gles2_get_renderer(wlr_renderer); + struct wlr_gles2_renderer *renderer = wlr_gles2_renderer_from_renderer(wlr_renderer); GLuint fbo = 0; struct wlr_egl_context prev_ctx = {0}; @@ -286,7 +273,7 @@ GLuint wlr_gles2_renderer_get_buffer_fbo(struct wlr_renderer *wlr_renderer, } static struct wlr_render_timer *gles2_render_timer_create(struct wlr_renderer *wlr_renderer) { - struct wlr_gles2_renderer *renderer = gles2_get_renderer(wlr_renderer); + struct wlr_gles2_renderer *renderer = wlr_gles2_renderer_from_renderer(wlr_renderer); if (!renderer->exts.EXT_disjoint_timer_query) { wlr_log(WLR_ERROR, "can't create timer, EXT_disjoint_timer_query not available"); return NULL; @@ -367,7 +354,7 @@ static const struct wlr_render_timer_impl render_timer_impl = { .destroy = gles2_render_timer_destroy, }; -void push_gles2_debug_(struct wlr_gles2_renderer *renderer, +void wlr_gles2_push_debug_(struct wlr_gles2_renderer *renderer, const char *file, const char *func) { if (!renderer->procs.glPushDebugGroupKHR) { return; @@ -379,7 +366,7 @@ void push_gles2_debug_(struct wlr_gles2_renderer *renderer, renderer->procs.glPushDebugGroupKHR(GL_DEBUG_SOURCE_APPLICATION_KHR, 1, -1, str); } -void pop_gles2_debug(struct wlr_gles2_renderer *renderer) { +void wlr_gles2_pop_debug(struct wlr_gles2_renderer *renderer) { if (renderer->procs.glPopDebugGroupKHR) { renderer->procs.glPopDebugGroupKHR(); } @@ -407,7 +394,7 @@ static void gles2_log(GLenum src, GLenum type, GLuint id, GLenum severity, static GLuint compile_shader(struct wlr_gles2_renderer *renderer, GLenum type, const GLchar *src) { - push_gles2_debug(renderer); + wlr_gles2_push_debug(renderer); GLuint shader = glCreateShader(type); glShaderSource(shader, 1, &src, NULL); @@ -421,13 +408,13 @@ static GLuint compile_shader(struct wlr_gles2_renderer *renderer, shader = 0; } - pop_gles2_debug(renderer); + wlr_gles2_pop_debug(renderer); return shader; } -static GLuint link_program(struct wlr_gles2_renderer *renderer, +GLuint wlr_gles2_link_program(struct wlr_gles2_renderer *renderer, const GLchar *vert_src, const GLchar *frag_src) { - push_gles2_debug(renderer); + wlr_gles2_push_debug(renderer); GLuint vert = compile_shader(renderer, GL_VERTEX_SHADER, vert_src); if (!vert) { @@ -458,11 +445,11 @@ static GLuint link_program(struct wlr_gles2_renderer *renderer, goto error; } - pop_gles2_debug(renderer); + wlr_gles2_pop_debug(renderer); return prog; error: - pop_gles2_debug(renderer); + wlr_gles2_pop_debug(renderer); return 0; } @@ -630,57 +617,6 @@ struct wlr_renderer *wlr_gles2_renderer_create(struct wlr_egl *egl) { GL_DEBUG_TYPE_PUSH_GROUP_KHR, GL_DONT_CARE, 0, NULL, GL_FALSE); } - push_gles2_debug(renderer); - - GLuint prog; - renderer->shaders.quad.program = prog = - link_program(renderer, common_vert_src, quad_frag_src); - if (!renderer->shaders.quad.program) { - goto error; - } - renderer->shaders.quad.proj = glGetUniformLocation(prog, "proj"); - renderer->shaders.quad.color = glGetUniformLocation(prog, "color"); - renderer->shaders.quad.pos_attrib = glGetAttribLocation(prog, "pos"); - - renderer->shaders.tex_rgba.program = prog = - link_program(renderer, common_vert_src, tex_rgba_frag_src); - if (!renderer->shaders.tex_rgba.program) { - goto error; - } - renderer->shaders.tex_rgba.proj = glGetUniformLocation(prog, "proj"); - renderer->shaders.tex_rgba.tex_proj = glGetUniformLocation(prog, "tex_proj"); - renderer->shaders.tex_rgba.tex = glGetUniformLocation(prog, "tex"); - renderer->shaders.tex_rgba.alpha = glGetUniformLocation(prog, "alpha"); - renderer->shaders.tex_rgba.pos_attrib = glGetAttribLocation(prog, "pos"); - - renderer->shaders.tex_rgbx.program = prog = - link_program(renderer, common_vert_src, tex_rgbx_frag_src); - if (!renderer->shaders.tex_rgbx.program) { - goto error; - } - renderer->shaders.tex_rgbx.proj = glGetUniformLocation(prog, "proj"); - renderer->shaders.tex_rgbx.tex_proj = glGetUniformLocation(prog, "tex_proj"); - renderer->shaders.tex_rgbx.tex = glGetUniformLocation(prog, "tex"); - renderer->shaders.tex_rgbx.alpha = glGetUniformLocation(prog, "alpha"); - renderer->shaders.tex_rgbx.pos_attrib = glGetAttribLocation(prog, "pos"); - - if (renderer->exts.OES_egl_image_external) { - renderer->shaders.tex_ext.program = prog = - link_program(renderer, common_vert_src, tex_external_frag_src); - if (!renderer->shaders.tex_ext.program) { - goto error; - } - renderer->shaders.tex_ext.proj = glGetUniformLocation(prog, "proj"); - renderer->shaders.tex_ext.tex_proj = glGetUniformLocation(prog, "tex_proj"); - renderer->shaders.tex_ext.tex = glGetUniformLocation(prog, "tex"); - renderer->shaders.tex_ext.alpha = glGetUniformLocation(prog, "alpha"); - renderer->shaders.tex_ext.pos_attrib = glGetAttribLocation(prog, "pos"); - } - - pop_gles2_debug(renderer); - - wlr_egl_unset_current(renderer->egl); - get_gles2_shm_formats(renderer, &renderer->shm_texture_formats); int drm_fd = wlr_renderer_get_drm_fd(&renderer->wlr_renderer); @@ -691,28 +627,10 @@ struct wlr_renderer *wlr_gles2_renderer_create(struct wlr_egl *egl) { } return &renderer->wlr_renderer; - -error: - glDeleteProgram(renderer->shaders.quad.program); - glDeleteProgram(renderer->shaders.tex_rgba.program); - glDeleteProgram(renderer->shaders.tex_rgbx.program); - glDeleteProgram(renderer->shaders.tex_ext.program); - - pop_gles2_debug(renderer); - - if (renderer->exts.KHR_debug) { - glDisable(GL_DEBUG_OUTPUT_KHR); - renderer->procs.glDebugMessageCallbackKHR(NULL, NULL); - } - - wlr_egl_unset_current(renderer->egl); - - free(renderer); - return NULL; } bool wlr_gles2_renderer_check_ext(struct wlr_renderer *wlr_renderer, const char *ext) { - struct wlr_gles2_renderer *renderer = gles2_get_renderer(wlr_renderer); + struct wlr_gles2_renderer *renderer = wlr_gles2_renderer_from_renderer(wlr_renderer); return check_gl_ext(renderer->exts_str, ext); } diff --git a/render/gles2/texture.c b/render/gles2/texture.c index 575a11fca..f40191341 100644 --- a/render/gles2/texture.c +++ b/render/gles2/texture.c @@ -71,7 +71,7 @@ static bool gles2_texture_update_from_buffer(struct wlr_texture *wlr_texture, struct wlr_egl_context prev_ctx; wlr_egl_make_current(texture->renderer->egl, &prev_ctx); - push_gles2_debug(texture->renderer); + wlr_gles2_push_debug(texture->renderer); glBindTexture(GL_TEXTURE_2D, texture->tex); @@ -97,7 +97,7 @@ static bool gles2_texture_update_from_buffer(struct wlr_texture *wlr_texture, glBindTexture(GL_TEXTURE_2D, 0); - pop_gles2_debug(texture->renderer); + wlr_gles2_pop_debug(texture->renderer); wlr_egl_restore_context(&prev_ctx); @@ -114,12 +114,12 @@ void gles2_texture_destroy(struct wlr_gles2_texture *texture) { struct wlr_egl_context prev_ctx; wlr_egl_make_current(texture->renderer->egl, &prev_ctx); - push_gles2_debug(texture->renderer); + wlr_gles2_push_debug(texture->renderer); glDeleteTextures(1, &texture->tex); glDeleteFramebuffers(1, &texture->fbo); - pop_gles2_debug(texture->renderer); + wlr_gles2_pop_debug(texture->renderer); wlr_egl_restore_context(&prev_ctx); } @@ -193,7 +193,7 @@ static bool gles2_texture_read_pixels(struct wlr_texture *wlr_texture, return false; } - push_gles2_debug(texture->renderer); + wlr_gles2_push_debug(texture->renderer); struct wlr_egl_context prev_ctx; if (!wlr_egl_make_current(texture->renderer->egl, &prev_ctx)) { return false; @@ -249,7 +249,7 @@ static bool gles2_texture_read_pixels(struct wlr_texture *wlr_texture, } wlr_egl_restore_context(&prev_ctx); - pop_gles2_debug(texture->renderer); + wlr_gles2_pop_debug(texture->renderer); return glGetError() == GL_NO_ERROR; } @@ -257,7 +257,7 @@ static bool gles2_texture_read_pixels(struct wlr_texture *wlr_texture, static uint32_t gles2_texture_preferred_read_format(struct wlr_texture *wlr_texture) { struct wlr_gles2_texture *texture = gles2_get_texture(wlr_texture); - push_gles2_debug(texture->renderer); + wlr_gles2_push_debug(texture->renderer); uint32_t fmt = DRM_FORMAT_INVALID; @@ -276,7 +276,7 @@ static uint32_t gles2_texture_preferred_read_format(struct wlr_texture *wlr_text glGetIntegerv(GL_ALPHA_BITS, &alpha_size); glBindFramebuffer(GL_FRAMEBUFFER, 0); - pop_gles2_debug(texture->renderer); + wlr_gles2_pop_debug(texture->renderer); const struct wlr_gles2_pixel_format *pix_fmt = get_gles2_format_from_gl(gl_format, gl_type, alpha_size > 0); @@ -320,7 +320,7 @@ static struct wlr_texture *gles2_texture_from_pixels( struct wlr_renderer *wlr_renderer, uint32_t drm_format, uint32_t stride, uint32_t width, uint32_t height, const void *data) { - struct wlr_gles2_renderer *renderer = gles2_get_renderer(wlr_renderer); + struct wlr_gles2_renderer *renderer = wlr_gles2_renderer_from_renderer(wlr_renderer); const struct wlr_gles2_pixel_format *fmt = get_gles2_format_from_drm(drm_format); @@ -358,7 +358,7 @@ static struct wlr_texture *gles2_texture_from_pixels( struct wlr_egl_context prev_ctx; wlr_egl_make_current(renderer->egl, &prev_ctx); - push_gles2_debug(renderer); + wlr_gles2_push_debug(renderer); glGenTextures(1, &texture->tex); glBindTexture(GL_TEXTURE_2D, texture->tex); @@ -372,7 +372,7 @@ static struct wlr_texture *gles2_texture_from_pixels( glBindTexture(GL_TEXTURE_2D, 0); - pop_gles2_debug(renderer); + wlr_gles2_pop_debug(renderer); wlr_egl_restore_context(&prev_ctx); @@ -404,7 +404,7 @@ static struct wlr_texture *gles2_texture_from_dmabuf( struct wlr_egl_context prev_ctx; wlr_egl_make_current(renderer->egl, &prev_ctx); - push_gles2_debug(texture->renderer); + wlr_gles2_push_debug(texture->renderer); bool invalid; if (!buffer->tex) { @@ -423,7 +423,7 @@ static struct wlr_texture *gles2_texture_from_dmabuf( glBindTexture(texture->target, 0); } - pop_gles2_debug(texture->renderer); + wlr_gles2_pop_debug(texture->renderer); wlr_egl_restore_context(&prev_ctx); texture->tex = buffer->tex; @@ -433,7 +433,7 @@ static struct wlr_texture *gles2_texture_from_dmabuf( struct wlr_texture *gles2_texture_from_buffer(struct wlr_renderer *wlr_renderer, struct wlr_buffer *buffer) { - struct wlr_gles2_renderer *renderer = gles2_get_renderer(wlr_renderer); + struct wlr_gles2_renderer *renderer = wlr_gles2_renderer_from_renderer(wlr_renderer); void *data; uint32_t format; diff --git a/render/pass.c b/render/pass.c index 23bdf96dd..35f467eb1 100644 --- a/render/pass.c +++ b/render/pass.c @@ -1,17 +1,46 @@ #include #include +#include #include +#include +#include -void wlr_render_pass_init(struct wlr_render_pass *render_pass, +#include + +#if WLR_HAS_GLES2_RENDERER +#include +#endif + +#if WLR_HAS_VULKAN_RENDERER +#include +#endif + +void wlr_render_pass_init(struct wlr_render_pass *pass, const struct wlr_render_pass_impl *impl) { - assert(impl->submit && impl->add_texture && impl->add_rect); - *render_pass = (struct wlr_render_pass){ + assert(impl->destroy); + *pass = (struct wlr_render_pass){ .impl = impl, }; } +void wlr_render_pass_destroy(struct wlr_render_pass *pass) { + if (pass == NULL) { + return; + } + + pass->impl->destroy(pass); +} + +struct wlr_renderer *wlr_get_wlr_renderer_from_render_pass( + struct wlr_render_pass *wlr_pass) { + return wlr_pass->impl->get_renderer(wlr_pass); +} + bool wlr_render_pass_submit(struct wlr_render_pass *render_pass) { - return render_pass->impl->submit(render_pass); + struct wlr_renderer *renderer = + wlr_get_wlr_renderer_from_render_pass(render_pass); + + return renderer->submit_pass->impl->render(render_pass); } void wlr_render_pass_add_texture(struct wlr_render_pass *render_pass, @@ -25,13 +54,19 @@ void wlr_render_pass_add_texture(struct wlr_render_pass *render_pass, (uint32_t)(box->y + box->height) <= options->texture->height); } - render_pass->impl->add_texture(render_pass, options); + struct wlr_renderer *renderer = + wlr_get_wlr_renderer_from_render_pass(render_pass); + + renderer->texture_pass->impl->render(render_pass, options); } void wlr_render_pass_add_rect(struct wlr_render_pass *render_pass, const struct wlr_render_rect_options *options) { assert(options->box.width >= 0 && options->box.height >= 0); - render_pass->impl->add_rect(render_pass, options); + struct wlr_renderer *renderer = + wlr_get_wlr_renderer_from_render_pass(render_pass); + + renderer->rect_pass->impl->render(render_pass, options); } void wlr_render_texture_options_get_src_box(const struct wlr_render_texture_options *options, @@ -74,3 +109,168 @@ void wlr_render_rect_options_get_box(const struct wlr_render_rect_options *optio *box = options->box; } + +void wlr_render_rect_pass_init(struct wlr_render_rect_pass *render_pass, + const struct wlr_render_rect_pass_impl *impl) { + assert(impl->render); + *render_pass = (struct wlr_render_rect_pass){ + .impl = impl, + }; + wl_signal_init(&render_pass->events.destroy); +} + +void wlr_render_rect_pass_destroy(struct wlr_render_rect_pass *render_pass) { + if (render_pass == NULL) { + return; + } + + wl_signal_emit_mutable(&render_pass->events.destroy, NULL); + assert(wl_list_empty(&render_pass->events.destroy.listener_list)); + + if (render_pass->impl->destroy != NULL) { + render_pass->impl->destroy(render_pass); + } else { + free(render_pass); + } +} + +struct wlr_render_rect_pass *get_or_create_render_rect_pass( + struct wlr_renderer *renderer) { + if (renderer == NULL) { + return NULL; + } + + if (renderer->rect_pass == NULL) { + struct wlr_render_rect_pass *pass = NULL; + if (wlr_renderer_is_pixman(renderer)) { + pass = wlr_pixman_render_rect_pass_create(); + } + +#if WLR_HAS_GLES2_RENDERER + else if (wlr_renderer_is_gles2(renderer)) { + pass = wlr_gles2_render_rect_pass_create(renderer); + } +#endif + +#if WLR_HAS_VULKAN_RENDERER + else if (wlr_renderer_is_vk(renderer)) { + pass = wlr_vk_render_rect_pass_create(renderer); + } +#endif + + renderer->rect_pass = pass; + return pass; + } else { + return renderer->rect_pass; + } +} + +void wlr_render_texture_pass_init(struct wlr_render_texture_pass *render_pass, + const struct wlr_render_texture_pass_impl *impl) { + assert(impl->render); + *render_pass = (struct wlr_render_texture_pass){ + .impl = impl, + }; + wl_signal_init(&render_pass->events.destroy); +} +void wlr_render_texture_pass_destroy(struct wlr_render_texture_pass *render_pass) { + if (render_pass == NULL) { + return; + } + + wl_signal_emit_mutable(&render_pass->events.destroy, NULL); + assert(wl_list_empty(&render_pass->events.destroy.listener_list)); + + if (render_pass->impl->destroy != NULL) { + render_pass->impl->destroy(render_pass); + } +} + +struct wlr_render_texture_pass *get_or_create_render_texture_pass( + struct wlr_renderer *renderer) { + if (renderer == NULL) { + return NULL; + } + + if (renderer->texture_pass == NULL) { + struct wlr_render_texture_pass *pass = NULL; + if (wlr_renderer_is_pixman(renderer)) { + pass = wlr_pixman_render_texture_pass_create(); + } + +#if WLR_HAS_GLES2_RENDERER + else if (wlr_renderer_is_gles2(renderer)) { + pass = wlr_gles2_render_texture_pass_create(renderer); + } +#endif + +#if WLR_HAS_VULKAN_RENDERER + else if (wlr_renderer_is_vk(renderer)) { + pass = wlr_vk_render_texture_pass_create(renderer); + } +#endif + + renderer->texture_pass = pass; + return pass; + } else { + return renderer->texture_pass; + } +} + +void wlr_render_submit_pass_init(struct wlr_render_submit_pass *pass, + const struct wlr_render_submit_pass_impl *impl) { + assert(impl->render); + *pass = (struct wlr_render_submit_pass){ + .impl = impl, + }; + wl_signal_init(&pass->events.destroy); +} + +void wlr_render_submit_pass_destroy(struct wlr_render_submit_pass *pass) { + if (pass == NULL) { + return; + } + + wl_signal_emit_mutable(&pass->events.destroy, NULL); + assert(wl_list_empty(&pass->events.destroy.listener_list)); + + if (pass->impl->destroy != NULL) { + pass->impl->destroy(pass); + } +} + +struct wlr_render_submit_pass *get_or_create_render_submit_pass( + struct wlr_renderer *renderer) { + if (renderer == NULL) { + return NULL; + } + + if (renderer->submit_pass == NULL) { + struct wlr_render_submit_pass *pass = NULL; + if (wlr_renderer_is_pixman(renderer)) { + pass = wlr_pixman_render_submit_pass_create(); + } + +#if WLR_HAS_GLES2_RENDERER + else if (wlr_renderer_is_gles2(renderer)) { + pass = wlr_gles2_render_submit_pass_create(); + } +#endif + +#if WLR_HAS_VULKAN_RENDERER + else if (wlr_renderer_is_vk(renderer)) { + pass = wlr_vk_render_submit_pass_create(renderer); + } +#endif + + if (pass == NULL) { + wlr_log_errno(WLR_ERROR, "Failed to allocate wlr_render_submit_pass"); + return NULL; + } + + renderer->submit_pass = pass; + return pass; + } else { + return renderer->submit_pass; + } +} diff --git a/render/pixman/pass.c b/render/pixman/pass.c index af738bb42..d05c85d2b 100644 --- a/render/pixman/pass.c +++ b/render/pixman/pass.c @@ -1,10 +1,14 @@ #include #include + +#include + #include "render/pixman.h" static const struct wlr_render_pass_impl render_pass_impl; -static struct wlr_pixman_render_pass *get_render_pass(struct wlr_render_pass *wlr_pass) { +struct wlr_pixman_render_pass *wlr_pixman_render_pass_from_render_pass( + struct wlr_render_pass *wlr_pass) { assert(wlr_pass->impl == &render_pass_impl); struct wlr_pixman_render_pass *pass = wl_container_of(wlr_pass, pass, base); return pass; @@ -17,7 +21,7 @@ static struct wlr_pixman_texture *get_texture(struct wlr_texture *wlr_texture) { } static bool render_pass_submit(struct wlr_render_pass *wlr_pass) { - struct wlr_pixman_render_pass *pass = get_render_pass(wlr_pass); + struct wlr_pixman_render_pass *pass = wlr_pixman_render_pass_from_render_pass(wlr_pass); wlr_buffer_end_data_ptr_access(pass->buffer->buffer); wlr_buffer_unlock(pass->buffer->buffer); @@ -38,7 +42,7 @@ static pixman_op_t get_pixman_blending(enum wlr_render_blend_mode mode) { static void render_pass_add_texture(struct wlr_render_pass *wlr_pass, const struct wlr_render_texture_options *options) { - struct wlr_pixman_render_pass *pass = get_render_pass(wlr_pass); + struct wlr_pixman_render_pass *pass = wlr_pixman_render_pass_from_render_pass(wlr_pass); struct wlr_pixman_texture *texture = get_texture(options->texture); struct wlr_pixman_buffer *buffer = pass->buffer; @@ -201,7 +205,7 @@ static void render_pass_add_texture(struct wlr_render_pass *wlr_pass, static void render_pass_add_rect(struct wlr_render_pass *wlr_pass, const struct wlr_render_rect_options *options) { - struct wlr_pixman_render_pass *pass = get_render_pass(wlr_pass); + struct wlr_pixman_render_pass *pass = wlr_pixman_render_pass_from_render_pass(wlr_pass); struct wlr_pixman_buffer *buffer = pass->buffer; struct wlr_box box; wlr_render_rect_options_get_box(options, pass->buffer->buffer, &box); @@ -226,12 +230,100 @@ static void render_pass_add_rect(struct wlr_render_pass *wlr_pass, pixman_image_unref(fill); } +static void render_pass_destory(struct wlr_render_pass *wlr_pass) { + (void)wlr_pass; +} + +static struct wlr_renderer *render_pass_get_renderer(struct wlr_render_pass *wlr_pass) { + struct wlr_pixman_render_pass *pass = wlr_pixman_render_pass_from_render_pass(wlr_pass); + struct wlr_pixman_renderer *renderer = pass->buffer->renderer; + + return &renderer->wlr_renderer; +} + static const struct wlr_render_pass_impl render_pass_impl = { - .submit = render_pass_submit, - .add_texture = render_pass_add_texture, - .add_rect = render_pass_add_rect, + .destroy = render_pass_destory, + .get_renderer = render_pass_get_renderer, }; +static void render_rect_pass_destroy(struct wlr_render_rect_pass *pass) { + struct wlr_pixman_render_rect_pass *pixman_pass = + wlr_pixman_render_rect_pass_from_pass(pass); + free(pixman_pass); +} + +static const struct wlr_render_rect_pass_impl render_rect_pass_impl = { + .destroy = render_rect_pass_destroy, + .render = render_pass_add_rect, +}; + +struct wlr_render_rect_pass *wlr_pixman_render_rect_pass_create(void) { + struct wlr_pixman_render_rect_pass *pass = malloc(sizeof(*pass)); + if (pass == NULL) { + wlr_log_errno(WLR_ERROR, "failed to allocate wlr_pixman_render_rect_pass"); + return NULL; + } + + wlr_render_rect_pass_init(&pass->base, &render_rect_pass_impl); + + return &pass->base; +} + +bool wlr_render_rect_pass_is_pixman(const struct wlr_render_rect_pass *rect_pass) { + return rect_pass->impl == &render_rect_pass_impl; +} + +struct wlr_pixman_render_rect_pass *wlr_pixman_render_rect_pass_from_pass( + struct wlr_render_rect_pass *rect_pass) { + if (!wlr_render_rect_pass_is_pixman(rect_pass)) { + return NULL; + } + + struct wlr_pixman_render_rect_pass *pass = + wl_container_of(rect_pass, pass, base); + + return pass; +} + +static void render_texture_pass_destroy(struct wlr_render_texture_pass *pass) { + struct wlr_pixman_render_texture_pass *pixman_pass = + wlr_pixman_render_texture_pass_from_pass(pass); + free(pixman_pass); +} + +static const struct wlr_render_texture_pass_impl render_texture_pass_impl = { + .destroy = render_texture_pass_destroy, + .render = render_pass_add_texture, +}; + +struct wlr_render_texture_pass *wlr_pixman_render_texture_pass_create(void) { + struct wlr_pixman_render_texture_pass *pass = malloc(sizeof(*pass)); + if (pass == NULL) { + wlr_log_errno(WLR_ERROR, "failed to allocate wlr_pixman_render_texture_pass"); + return NULL; + } + + wlr_render_texture_pass_init(&pass->base, &render_texture_pass_impl); + + return &pass->base; +} + +bool wlr_render_texture_pass_is_pixman(const struct wlr_render_texture_pass *texture_pass) { + return texture_pass->impl == &render_texture_pass_impl; +} + +struct wlr_pixman_render_texture_pass *wlr_pixman_render_texture_pass_from_pass( + struct wlr_render_texture_pass *texture_pass) { + if (!wlr_render_texture_pass_is_pixman(texture_pass)) { + return NULL; + } + + struct wlr_pixman_render_texture_pass *pixman_pass = + wl_container_of(texture_pass, pixman_pass, base); + + return pixman_pass; +} + struct wlr_pixman_render_pass *begin_pixman_render_pass( struct wlr_pixman_buffer *buffer) { struct wlr_pixman_render_pass *pass = calloc(1, sizeof(*pass)); @@ -252,3 +344,42 @@ struct wlr_pixman_render_pass *begin_pixman_render_pass( return pass; } + +static void render_submit_pass_destroy(struct wlr_render_submit_pass *pass) { + struct wlr_pixman_render_submit_pass *pixman_pass = + wlr_pixman_render_submit_pass_from_pass(pass); + free(pixman_pass); +} + +static const struct wlr_render_submit_pass_impl pixman_render_submit_pass_impl = { + .destroy = render_submit_pass_destroy, + .render = render_pass_submit, +}; + +struct wlr_render_submit_pass *wlr_pixman_render_submit_pass_create(void) { + struct wlr_pixman_render_submit_pass *pass = malloc(sizeof(*pass)); + if (pass == NULL) { + wlr_log_errno(WLR_ERROR, "failed to allocate wlr_pixman_render_submit_pass"); + return NULL; + } + + wlr_render_submit_pass_init(&pass->base, &pixman_render_submit_pass_impl); + + return &pass->base; +} + +bool wlr_render_submit_pass_is_pixman(const struct wlr_render_submit_pass *submit_pass) { + return submit_pass->impl == &pixman_render_submit_pass_impl; +} + +struct wlr_pixman_render_submit_pass *wlr_pixman_render_submit_pass_from_pass( + struct wlr_render_submit_pass *submit_pass) { + if (!wlr_render_submit_pass_is_pixman(submit_pass)) { + return NULL; + } + + struct wlr_pixman_render_submit_pass *pass = + wl_container_of(submit_pass, pass, base); + + return pass; +} diff --git a/render/vulkan/pass.c b/render/vulkan/pass.c index 01e8fbd7a..8769ccaa0 100644 --- a/render/vulkan/pass.c +++ b/render/vulkan/pass.c @@ -3,17 +3,37 @@ #include #include #include -#include #include #include "render/color.h" #include "render/vulkan.h" +#include "render/vulkan/shaders/quad.frag.h" +#include "render/vulkan/shaders/texture.frag.h" #include "util/matrix.h" static const struct wlr_render_pass_impl render_pass_impl; static const struct wlr_addon_interface vk_color_transform_impl; -static struct wlr_vk_render_pass *get_render_pass(struct wlr_render_pass *wlr_pass) { +static bool create_shader_module(VkDevice dev, const uint32_t *code, + size_t code_size, const char *name, VkShaderModule *out) { + VkShaderModuleCreateInfo sinfo = { + .sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, + .codeSize = code_size, + .pCode = code, + }; + + VkResult res = vkCreateShaderModule(dev, &sinfo, NULL, out); + if (res != VK_SUCCESS) { + wlr_log(WLR_ERROR, "Failed to create %s shader module: %s (%d)", + name, vulkan_strerror(res), res); + return false; + } + + return true; +} + +struct wlr_vk_render_pass *wlr_vk_render_pass_from_render_pass( + struct wlr_render_pass *wlr_pass) { assert(wlr_pass->impl == &render_pass_impl); struct wlr_vk_render_pass *pass = wl_container_of(wlr_pass, pass, base); return pass; @@ -175,8 +195,11 @@ static bool unwrap_color_transform(struct wlr_color_transform *transform, } static bool render_pass_submit(struct wlr_render_pass *wlr_pass) { - struct wlr_vk_render_pass *pass = get_render_pass(wlr_pass); + struct wlr_vk_render_pass *pass = wlr_vk_render_pass_from_render_pass(wlr_pass); struct wlr_vk_renderer *renderer = pass->renderer; + struct wlr_vk_render_submit_pass *submit_pass = + wlr_vk_render_submit_pass_from_pass(renderer->wlr_renderer.submit_pass); + assert(submit_pass != NULL); struct wlr_vk_command_buffer *render_cb = pass->command_buffer; struct wlr_vk_render_buffer *render_buffer = pass->render_buffer; struct wlr_vk_command_buffer *stage_cb = NULL; @@ -260,9 +283,9 @@ static bool render_pass_submit(struct wlr_render_pass *wlr_pass) { } } bind_pipeline(pass, pipeline); - vkCmdPushConstants(render_cb->vk, renderer->output_pipe_layout, + vkCmdPushConstants(render_cb->vk, submit_pass->output.pipe_layout, VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(vert_pcr_data), &vert_pcr_data); - vkCmdPushConstants(render_cb->vk, renderer->output_pipe_layout, + vkCmdPushConstants(render_cb->vk, submit_pass->output.pipe_layout, VK_SHADER_STAGE_FRAGMENT_BIT, sizeof(vert_pcr_data), sizeof(frag_pcr_data), &frag_pcr_data); @@ -270,7 +293,7 @@ static bool render_pass_submit(struct wlr_render_pass *wlr_pass) { if (need_lut) { lut_ds = transform->lut_3d.ds; } else { - lut_ds = renderer->output_ds_lut3d_dummy; + lut_ds = submit_pass->output.ds_lut3d_dummy; } VkDescriptorSet ds[] = { render_buffer->two_pass.blend_descriptor_set, // set 0 @@ -278,7 +301,7 @@ static bool render_pass_submit(struct wlr_render_pass *wlr_pass) { }; size_t ds_len = sizeof(ds) / sizeof(ds[0]); vkCmdBindDescriptorSets(render_cb->vk, - VK_PIPELINE_BIND_POINT_GRAPHICS, renderer->output_pipe_layout, + VK_PIPELINE_BIND_POINT_GRAPHICS, submit_pass->output.pipe_layout, 0, ds_len, ds, 0, NULL); const pixman_region32_t *clip = rect_union_evaluate(&pass->updated_region); @@ -643,7 +666,10 @@ static void render_pass_mark_box_updated(struct wlr_vk_render_pass *pass, static void render_pass_add_rect(struct wlr_render_pass *wlr_pass, const struct wlr_render_rect_options *options) { - struct wlr_vk_render_pass *pass = get_render_pass(wlr_pass); + struct wlr_vk_render_pass *pass = wlr_vk_render_pass_from_render_pass(wlr_pass); + struct wlr_vk_render_rect_pass *rect_pass = + wlr_vk_render_rect_pass_from_pass(pass->renderer->wlr_renderer.rect_pass); + assert(rect_pass != NULL); VkCommandBuffer cb = pass->command_buffer->vk; // Input color values are given in sRGB space, shader expects @@ -693,7 +719,9 @@ static void render_pass_add_rect(struct wlr_render_pass *wlr_pass, &(struct wlr_vk_pipeline_key) { .source = WLR_VK_SHADER_SOURCE_SINGLE_COLOR, .layout = {0}, - }); + }, + rect_pass->shader.vert_module, + rect_pass->shader.frag_module); if (!pipe) { pass->failed = true; break; @@ -745,8 +773,11 @@ static void render_pass_add_rect(struct wlr_render_pass *wlr_pass, static void render_pass_add_texture(struct wlr_render_pass *wlr_pass, const struct wlr_render_texture_options *options) { - struct wlr_vk_render_pass *pass = get_render_pass(wlr_pass); + struct wlr_vk_render_pass *pass = wlr_vk_render_pass_from_render_pass(wlr_pass); struct wlr_vk_renderer *renderer = pass->renderer; + struct wlr_vk_render_texture_pass *texture_pass = + wlr_vk_render_texture_pass_from_pass(renderer->wlr_renderer.texture_pass); + assert(texture_pass != NULL); VkCommandBuffer cb = pass->command_buffer->vk; struct wlr_vk_texture *texture = vulkan_get_texture(options->texture); @@ -844,7 +875,9 @@ static void render_pass_add_texture(struct wlr_render_pass *wlr_pass, .texture_transform = tex_transform, .blend_mode = !texture->has_alpha && alpha == 1.0 ? WLR_RENDER_BLEND_MODE_NONE : options->blend_mode, - }); + }, + texture_pass->shader.vert_module, + texture_pass->shader.frag_module); if (!pipe) { pass->failed = true; return; @@ -941,12 +974,21 @@ static void render_pass_add_texture(struct wlr_render_pass *wlr_pass, } } -static const struct wlr_render_pass_impl render_pass_impl = { - .submit = render_pass_submit, - .add_rect = render_pass_add_rect, - .add_texture = render_pass_add_texture, -}; +static void render_pass_destory(struct wlr_render_pass *wlr_pass) { + (void)wlr_pass; +} +static struct wlr_renderer *render_pass_get_renderer(struct wlr_render_pass *wlr_pass) { + struct wlr_vk_render_pass *pass = wlr_vk_render_pass_from_render_pass(wlr_pass); + struct wlr_vk_renderer *renderer = pass->renderer; + + return &renderer->wlr_renderer; +} + +static const struct wlr_render_pass_impl render_pass_impl = { + .destroy = render_pass_destory, + .get_renderer = render_pass_get_renderer, +}; void vk_color_transform_destroy(struct wlr_addon *addon) { struct wlr_vk_renderer *renderer = (struct wlr_vk_renderer *)addon->owner; @@ -970,6 +1012,12 @@ static bool create_3d_lut_image(struct wlr_vk_renderer *renderer, VkImage *image, VkImageView *image_view, VkDeviceMemory *memory, VkDescriptorSet *ds, struct wlr_vk_descriptor_pool **ds_pool) { + struct wlr_vk_render_submit_pass *submit_pass = + wlr_vk_render_submit_pass_from_pass(renderer->wlr_renderer.submit_pass);; + if (submit_pass == NULL) { + return false; + } + VkDevice dev = renderer->dev->dev; VkResult res; @@ -1108,7 +1156,7 @@ static bool create_3d_lut_image(struct wlr_vk_renderer *renderer, VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, VK_ACCESS_SHADER_READ_BIT); *ds_pool = vulkan_alloc_texture_ds(renderer, - renderer->output_ds_lut3d_layout, ds); + submit_pass->output.ds_lut3d_layout, ds); if (!*ds_pool) { wlr_log(WLR_ERROR, "Failed to allocate descriptor"); goto fail_imageview; @@ -1277,9 +1325,12 @@ struct wlr_vk_render_pass *vulkan_begin_render_pass(struct wlr_vk_renderer *rend return NULL; } - if (!renderer->dummy3d_image_transitioned) { - renderer->dummy3d_image_transitioned = true; - vulkan_change_layout(cb->vk, renderer->dummy3d_image, + struct wlr_vk_render_submit_pass *submit_pass = + wlr_vk_render_submit_pass_from_pass(renderer->wlr_renderer.submit_pass); + assert(submit_pass != NULL); + if (!submit_pass->output.dummy3d_image_transitioned) { + submit_pass->output.dummy3d_image_transitioned = true; + vulkan_change_layout(cb->vk, submit_pass->output.dummy3d_image, VK_IMAGE_LAYOUT_UNDEFINED, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, 0, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, VK_ACCESS_SHADER_READ_BIT); @@ -1324,3 +1375,190 @@ struct wlr_vk_render_pass *vulkan_begin_render_pass(struct wlr_vk_renderer *rend pass->timer = timer; return pass; } + +static void render_rect_pass_destroy(struct wlr_render_rect_pass *pass) { + struct wlr_vk_render_rect_pass *vk_pass = + wlr_vk_render_rect_pass_from_pass(pass); + if (vk_pass->shader.vert_module != VK_NULL_HANDLE) { + vkDestroyShaderModule(vk_pass->renderer->dev->dev, + vk_pass->shader.vert_module, NULL); + } + if (vk_pass->shader.frag_module != VK_NULL_HANDLE) { + vkDestroyShaderModule(vk_pass->renderer->dev->dev, + vk_pass->shader.frag_module, NULL); + } + free(vk_pass); +} + +static const struct wlr_render_rect_pass_impl render_rect_pass_impl = { + .destroy = render_rect_pass_destroy, + .render = render_pass_add_rect, +}; + +struct wlr_render_rect_pass *wlr_vk_render_rect_pass_create( + struct wlr_renderer *wlr_renderer) { + struct wlr_vk_render_rect_pass *pass = calloc(1, sizeof(*pass)); + if (pass == NULL) { + wlr_log_errno(WLR_ERROR, "failed to allocate wlr_vk_render_rect_pass"); + return NULL; + } + wlr_render_rect_pass_init(&pass->base, &render_rect_pass_impl); + + struct wlr_vk_renderer *renderer = vulkan_get_renderer(wlr_renderer); + pass->renderer = renderer; + pass->shader.vert_module = vulkan_create_common_vert_module(renderer); + if (pass->shader.vert_module == VK_NULL_HANDLE) { + render_rect_pass_destroy(&pass->base); + return NULL; + } + + VkDevice dev = renderer->dev->dev; + if (!create_shader_module(dev, quad_frag_data, sizeof(quad_frag_data), + "quad fragment", &pass->shader.frag_module)) { + render_rect_pass_destroy(&pass->base); + return NULL; + } + + return &pass->base; +} + +bool wlr_render_rect_pass_is_vk(const struct wlr_render_rect_pass *rect_pass) { + return rect_pass->impl == &render_rect_pass_impl; +} + +struct wlr_vk_render_rect_pass *wlr_vk_render_rect_pass_from_pass( + struct wlr_render_rect_pass *rect_pass) { + if (!wlr_render_rect_pass_is_vk(rect_pass)) { + return NULL; + } + + struct wlr_vk_render_rect_pass *pass = + wl_container_of(rect_pass, pass, base); + + return pass; +} + +static void render_texture_pass_destroy(struct wlr_render_texture_pass *pass) { + struct wlr_vk_render_texture_pass *vk_pass = + wlr_vk_render_texture_pass_from_pass(pass); + if (vk_pass->shader.vert_module != VK_NULL_HANDLE) { + vkDestroyShaderModule(vk_pass->renderer->dev->dev, + vk_pass->shader.vert_module, NULL); + } + if (vk_pass->shader.frag_module != VK_NULL_HANDLE) { + vkDestroyShaderModule(vk_pass->renderer->dev->dev, + vk_pass->shader.frag_module, NULL); + } + free(vk_pass); +} + +static const struct wlr_render_texture_pass_impl render_texture_pass_impl = { + .destroy = render_texture_pass_destroy, + .render = render_pass_add_texture, +}; + +struct wlr_render_texture_pass *wlr_vk_render_texture_pass_create( + struct wlr_renderer *wlr_renderer) { + struct wlr_vk_render_texture_pass *pass = calloc(1, sizeof(*pass)); + if (pass == NULL) { + wlr_log_errno(WLR_ERROR, "failed to allocate wlr_vk_render_texture_pass"); + return NULL; + } + wlr_render_texture_pass_init(&pass->base, &render_texture_pass_impl); + + struct wlr_vk_renderer *renderer = vulkan_get_renderer(wlr_renderer); + pass->renderer = renderer; + pass->shader.vert_module = vulkan_create_common_vert_module(renderer); + if (pass->shader.vert_module == VK_NULL_HANDLE) { + render_texture_pass_destroy(&pass->base); + return NULL; + } + + VkDevice dev = renderer->dev->dev; + if (!create_shader_module(dev, texture_frag_data, sizeof(texture_frag_data), + "texture fragment", &pass->shader.frag_module)) { + render_texture_pass_destroy(&pass->base); + return NULL; + } + + return &pass->base; +} +bool wlr_render_texture_pass_is_vk(const struct wlr_render_texture_pass *texture_pass) { + return texture_pass->impl == &render_texture_pass_impl; +} + +struct wlr_vk_render_texture_pass *wlr_vk_render_texture_pass_from_pass( + const struct wlr_render_texture_pass *texture_pass) { + if (!wlr_render_texture_pass_is_vk(texture_pass)) { + return NULL; + } + + struct wlr_vk_render_texture_pass *vk_pass = wl_container_of(texture_pass, vk_pass, base); + + return vk_pass; +} + +static void render_submit_pass_destroy(struct wlr_render_submit_pass *pass) { + struct wlr_vk_render_submit_pass *vk_pass = + wlr_vk_render_submit_pass_from_pass(pass); + VkDevice dev = vk_pass->renderer->dev->dev; + + struct wlr_vk_descriptor_pool *pool, *tmp_pool; + wl_list_for_each_safe(pool, tmp_pool, &vk_pass->output.descriptor_pools, link) { + vkDestroyDescriptorPool(dev, pool->pool, NULL); + free(pool); + } + + vkDestroyShaderModule(dev, vk_pass->output.vert_module, NULL); + vkDestroyShaderModule(dev, vk_pass->output.frag_module, NULL); + vkDestroyImageView(dev, vk_pass->output.dummy3d_image_view, NULL); + vkDestroyImage(dev, vk_pass->output.dummy3d_image, NULL); + vkFreeMemory(dev, vk_pass->output.dummy3d_mem, NULL); + vkDestroyPipelineLayout(dev, vk_pass->output.pipe_layout, NULL); + vkDestroyDescriptorSetLayout(dev, vk_pass->output.ds_srgb_layout, NULL); + vkDestroyDescriptorSetLayout(dev, vk_pass->output.ds_lut3d_layout, NULL); + vkDestroySampler(dev, vk_pass->output.sampler_lut3d, NULL); + + free(vk_pass); +} + +static const struct wlr_render_submit_pass_impl vk_render_submit_pass_impl = { + .destroy = render_submit_pass_destroy, + .render = render_pass_submit, +}; + +struct wlr_render_submit_pass *wlr_vk_render_submit_pass_create( + struct wlr_renderer *wlr_renderer) { + struct wlr_vk_render_submit_pass *pass = calloc(1, sizeof(*pass)); + if (pass == NULL) { + wlr_log_errno(WLR_ERROR, "failed to allocate wlr_vk_render_submit_pass"); + return NULL; + } + + wlr_render_submit_pass_init(&pass->base, &vk_render_submit_pass_impl); + pass->renderer = vulkan_get_renderer(wlr_renderer); + wl_list_init(&pass->output.descriptor_pools); + + if (!vulkan_init_submit_pass_output(pass->renderer, pass)) { + render_submit_pass_destroy(&pass->base); + return NULL; + } + + return &pass->base; +} + +bool wlr_render_submit_pass_is_vk(const struct wlr_render_submit_pass *submit_pass) { + return submit_pass->impl == &vk_render_submit_pass_impl; +} + +struct wlr_vk_render_submit_pass *wlr_vk_render_submit_pass_from_pass( + struct wlr_render_submit_pass *submit_pass) { + if (!wlr_render_submit_pass_is_vk(submit_pass)) { + return NULL; + } + + struct wlr_vk_render_submit_pass *pass = + wl_container_of(submit_pass, pass, base); + + return pass; +} diff --git a/render/vulkan/renderer.c b/render/vulkan/renderer.c index 434ab4769..d5a6fea95 100644 --- a/render/vulkan/renderer.c +++ b/render/vulkan/renderer.c @@ -23,8 +23,6 @@ #include "render/pixel_format.h" #include "render/vulkan.h" #include "render/vulkan/shaders/common.vert.h" -#include "render/vulkan/shaders/texture.frag.h" -#include "render/vulkan/shaders/quad.frag.h" #include "render/vulkan/shaders/output.frag.h" #include "types/wlr_buffer.h" #include "util/time.h" @@ -56,6 +54,23 @@ struct wlr_vk_renderer *vulkan_get_renderer(struct wlr_renderer *wlr_renderer) { return renderer; } +VkShaderModule vulkan_create_common_vert_module(struct wlr_vk_renderer *renderer) { + VkShaderModuleCreateInfo sinfo = { + .sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, + .codeSize = sizeof(common_vert_data), + .pCode = common_vert_data, + }; + + VkShaderModule module = VK_NULL_HANDLE; + VkResult res = vkCreateShaderModule(renderer->dev->dev, &sinfo, NULL, &module); + if (res != VK_SUCCESS) { + wlr_vk_error("Failed to create vertex shader module", res); + return VK_NULL_HANDLE; + } + + return module; +} + static struct wlr_vk_render_format_setup *find_or_create_render_setup( struct wlr_vk_renderer *renderer, const struct wlr_vk_format *format, bool has_blending_buffer, bool srgb); @@ -152,9 +167,14 @@ struct wlr_vk_descriptor_pool *vulkan_alloc_texture_ds( struct wlr_vk_descriptor_pool *vulkan_alloc_blend_ds( struct wlr_vk_renderer *renderer, VkDescriptorSet *ds) { + struct wlr_vk_render_submit_pass *submit_pass = + wlr_vk_render_submit_pass_from_pass(renderer->wlr_renderer.submit_pass);; + assert(submit_pass != NULL); + return alloc_ds(renderer, ds, VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, - &renderer->output_ds_srgb_layout, &renderer->output_descriptor_pools, - &renderer->last_output_pool_size); + &submit_pass->output.ds_srgb_layout, + &submit_pass->output.descriptor_pools, + &submit_pass->output.last_pool_size); } void vulkan_free_ds(struct wlr_vk_renderer *renderer, @@ -1232,15 +1252,6 @@ static void vulkan_destroy(struct wlr_renderer *wlr_renderer) { vkDestroyDescriptorPool(dev->dev, pool->pool, NULL); free(pool); } - wl_list_for_each_safe(pool, tmp_pool, &renderer->output_descriptor_pools, link) { - vkDestroyDescriptorPool(dev->dev, pool->pool, NULL); - free(pool); - } - - vkDestroyShaderModule(dev->dev, renderer->vert_module, NULL); - vkDestroyShaderModule(dev->dev, renderer->tex_frag_module, NULL); - vkDestroyShaderModule(dev->dev, renderer->quad_frag_module, NULL); - vkDestroyShaderModule(dev->dev, renderer->output_module, NULL); struct wlr_vk_pipeline_layout *pipeline_layout, *pipeline_layout_tmp; wl_list_for_each_safe(pipeline_layout, pipeline_layout_tmp, @@ -1252,16 +1263,8 @@ static void vulkan_destroy(struct wlr_renderer *wlr_renderer) { free(pipeline_layout); } - vkDestroyImageView(dev->dev, renderer->dummy3d_image_view, NULL); - vkDestroyImage(dev->dev, renderer->dummy3d_image, NULL); - vkFreeMemory(dev->dev, renderer->dummy3d_mem, NULL); - vkDestroySemaphore(dev->dev, renderer->timeline_semaphore, NULL); - vkDestroyPipelineLayout(dev->dev, renderer->output_pipe_layout, NULL); - vkDestroyDescriptorSetLayout(dev->dev, renderer->output_ds_srgb_layout, NULL); - vkDestroyDescriptorSetLayout(dev->dev, renderer->output_ds_lut3d_layout, NULL); vkDestroyCommandPool(dev->dev, renderer->command_pool, NULL); - vkDestroySampler(dev->dev, renderer->output_sampler_lut3d, NULL); if (renderer->read_pixels_cache.initialized) { vkFreeMemory(dev->dev, renderer->read_pixels_cache.dst_img_memory, NULL); @@ -1697,7 +1700,8 @@ static bool init_tex_layouts(struct wlr_vk_renderer *renderer, return true; } -static bool init_blend_to_output_layouts(struct wlr_vk_renderer *renderer) { +static bool init_blend_to_output_layouts(struct wlr_vk_renderer *renderer, + struct wlr_vk_render_submit_pass *submit_pass) { VkResult res; VkDevice dev = renderer->dev->dev; @@ -1715,7 +1719,8 @@ static bool init_blend_to_output_layouts(struct wlr_vk_renderer *renderer) { .pBindings = &ds_binding_input, }; - res = vkCreateDescriptorSetLayout(dev, &ds_info, NULL, &renderer->output_ds_srgb_layout); + res = vkCreateDescriptorSetLayout(dev, &ds_info, NULL, + &submit_pass->output.ds_srgb_layout); if (res != VK_SUCCESS) { wlr_vk_error("vkCreateDescriptorSetLayout", res); return false; @@ -1734,7 +1739,7 @@ static bool init_blend_to_output_layouts(struct wlr_vk_renderer *renderer) { }; res = vkCreateSampler(renderer->dev->dev, &sampler_create_info, NULL, - &renderer->output_sampler_lut3d); + &submit_pass->output.sampler_lut3d); if (res != VK_SUCCESS) { wlr_vk_error("vkCreateSampler", res); return false; @@ -1745,7 +1750,7 @@ static bool init_blend_to_output_layouts(struct wlr_vk_renderer *renderer) { .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, .descriptorCount = 1, .stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT, - .pImmutableSamplers = &renderer->output_sampler_lut3d, + .pImmutableSamplers = &submit_pass->output.sampler_lut3d, }; VkDescriptorSetLayoutCreateInfo ds_lut3d_info = { @@ -1755,7 +1760,7 @@ static bool init_blend_to_output_layouts(struct wlr_vk_renderer *renderer) { }; res = vkCreateDescriptorSetLayout(dev, &ds_lut3d_info, NULL, - &renderer->output_ds_lut3d_layout); + &submit_pass->output.ds_lut3d_layout); if (res != VK_SUCCESS) { wlr_vk_error("vkCreateDescriptorSetLayout", res); return false; @@ -1776,8 +1781,8 @@ static bool init_blend_to_output_layouts(struct wlr_vk_renderer *renderer) { }; VkDescriptorSetLayout out_ds_layouts[] = { - renderer->output_ds_srgb_layout, - renderer->output_ds_lut3d_layout, + submit_pass->output.ds_srgb_layout, + submit_pass->output.ds_lut3d_layout, }; VkPipelineLayoutCreateInfo pl_info = { @@ -1788,7 +1793,8 @@ static bool init_blend_to_output_layouts(struct wlr_vk_renderer *renderer) { .pPushConstantRanges = pc_ranges, }; - res = vkCreatePipelineLayout(dev, &pl_info, NULL, &renderer->output_pipe_layout); + res = vkCreatePipelineLayout(dev, &pl_info, NULL, + &submit_pass->output.pipe_layout); if (res != VK_SUCCESS) { wlr_vk_error("vkCreatePipelineLayout", res); return false; @@ -1842,7 +1848,8 @@ static bool pipeline_key_equals(const struct wlr_vk_pipeline_key *a, // VkRenderPass and VkPipelineLayout. struct wlr_vk_pipeline *setup_get_or_create_pipeline( struct wlr_vk_render_format_setup *setup, - const struct wlr_vk_pipeline_key *key) { + const struct wlr_vk_pipeline_key *key, + VkShaderModule vert_module, VkShaderModule frag_module) { struct wlr_vk_pipeline *pipeline; wl_list_for_each(pipeline, &setup->pipelines, link) { if (pipeline_key_equals(&pipeline->key, key)) { @@ -1889,7 +1896,7 @@ struct wlr_vk_pipeline *setup_get_or_create_pipeline( stages[0] = (VkPipelineShaderStageCreateInfo) { .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, .stage = VK_SHADER_STAGE_VERTEX_BIT, - .module = renderer->vert_module, + .module = vert_module, .pName = "main", }; @@ -1898,7 +1905,7 @@ struct wlr_vk_pipeline *setup_get_or_create_pipeline( stages[1] = (VkPipelineShaderStageCreateInfo) { .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, .stage = VK_SHADER_STAGE_FRAGMENT_BIT, - .module = renderer->quad_frag_module, + .module = frag_module, .pName = "main", }; break; @@ -1906,7 +1913,7 @@ struct wlr_vk_pipeline *setup_get_or_create_pipeline( stages[1] = (VkPipelineShaderStageCreateInfo) { .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, .stage = VK_SHADER_STAGE_FRAGMENT_BIT, - .module = renderer->tex_frag_module, + .module = frag_module, .pName = "main", .pSpecializationInfo = &specialization, }; @@ -2003,6 +2010,7 @@ struct wlr_vk_pipeline *setup_get_or_create_pipeline( } static bool init_blend_to_output_pipeline(struct wlr_vk_renderer *renderer, + struct wlr_vk_render_submit_pass *submit_pass, VkRenderPass rp, VkPipelineLayout pipe_layout, VkPipeline *pipe, enum wlr_vk_output_transform transform) { VkResult res; @@ -2025,13 +2033,13 @@ static bool init_blend_to_output_pipeline(struct wlr_vk_renderer *renderer, { .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, .stage = VK_SHADER_STAGE_VERTEX_BIT, - .module = renderer->vert_module, + .module = submit_pass->output.vert_module, .pName = "main", }, { .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, .stage = VK_SHADER_STAGE_FRAGMENT_BIT, - .module = renderer->output_module, + .module = submit_pass->output.frag_module, .pName = "main", .pSpecializationInfo = &specialization, }, @@ -2235,7 +2243,8 @@ struct wlr_vk_pipeline_layout *get_or_create_pipeline_layout( * the sampler, a valid descriptor set should be bound. Create that here, linked to * a 1x1x1 image. */ -static bool init_dummy_images(struct wlr_vk_renderer *renderer) { +static bool init_dummy_images(struct wlr_vk_renderer *renderer, + struct wlr_vk_render_submit_pass *submit_pass) { VkResult res; VkDevice dev = renderer->dev->dev; @@ -2254,14 +2263,14 @@ static bool init_dummy_images(struct wlr_vk_renderer *renderer) { .tiling = VK_IMAGE_TILING_OPTIMAL, .usage = VK_IMAGE_USAGE_SAMPLED_BIT, }; - res = vkCreateImage(dev, &img_info, NULL, &renderer->dummy3d_image); + res = vkCreateImage(dev, &img_info, NULL, &submit_pass->output.dummy3d_image); if (res != VK_SUCCESS) { wlr_vk_error("vkCreateImage failed", res); return false; } VkMemoryRequirements mem_reqs = {0}; - vkGetImageMemoryRequirements(dev, renderer->dummy3d_image, &mem_reqs); + vkGetImageMemoryRequirements(dev, submit_pass->output.dummy3d_image, &mem_reqs); int mem_type_index = vulkan_find_mem_type(renderer->dev, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, mem_reqs.memoryTypeBits); if (mem_type_index == -1) { @@ -2273,12 +2282,13 @@ static bool init_dummy_images(struct wlr_vk_renderer *renderer) { .allocationSize = mem_reqs.size, .memoryTypeIndex = mem_type_index, }; - res = vkAllocateMemory(dev, &mem_info, NULL, &renderer->dummy3d_mem); + res = vkAllocateMemory(dev, &mem_info, NULL, &submit_pass->output.dummy3d_mem); if (res != VK_SUCCESS) { wlr_vk_error("vkAllocateMemory failed", res); return false; } - res = vkBindImageMemory(dev, renderer->dummy3d_image, renderer->dummy3d_mem, 0); + res = vkBindImageMemory(dev, submit_pass->output.dummy3d_image, + submit_pass->output.dummy3d_mem, 0); if (res != VK_SUCCESS) { wlr_vk_error("vkBindMemory failed", res); return false; @@ -2299,29 +2309,31 @@ static bool init_dummy_images(struct wlr_vk_renderer *renderer) { .baseArrayLayer = 0, .layerCount = 1, }, - .image = renderer->dummy3d_image, + .image = submit_pass->output.dummy3d_image, }; - res = vkCreateImageView(dev, &view_info, NULL, &renderer->dummy3d_image_view); + res = vkCreateImageView(dev, &view_info, NULL, + &submit_pass->output.dummy3d_image_view); if (res != VK_SUCCESS) { wlr_vk_error("vkCreateImageView failed", res); return false; } - renderer->output_ds_lut3d_dummy_pool = vulkan_alloc_texture_ds(renderer, - renderer->output_ds_lut3d_layout, &renderer->output_ds_lut3d_dummy); - if (!renderer->output_ds_lut3d_dummy_pool) { + submit_pass->output.ds_lut3d_dummy_pool = vulkan_alloc_texture_ds(renderer, + submit_pass->output.ds_lut3d_layout, + &submit_pass->output.ds_lut3d_dummy); + if (!submit_pass->output.ds_lut3d_dummy_pool) { wlr_log(WLR_ERROR, "Failed to allocate descriptor"); return false; } VkDescriptorImageInfo ds_img_info = { - .imageView = renderer->dummy3d_image_view, + .imageView = submit_pass->output.dummy3d_image_view, .imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, }; VkWriteDescriptorSet ds_write = { .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, .descriptorCount = 1, .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, - .dstSet = renderer->output_ds_lut3d_dummy, + .dstSet = submit_pass->output.ds_lut3d_dummy, .pImageInfo = &ds_img_info, }; vkUpdateDescriptorSets(dev, 1, &ds_write, 0, NULL); @@ -2329,53 +2341,30 @@ static bool init_dummy_images(struct wlr_vk_renderer *renderer) { return true; } -// Creates static render data, such as sampler, layouts and shader modules -// for the given renderer. -// Cleanup is done by destroying the renderer. -static bool init_static_render_data(struct wlr_vk_renderer *renderer) { +// Creates static blend->output render data for the given submit pass. +// Cleanup is done by destroying the submit pass. +bool vulkan_init_submit_pass_output(struct wlr_vk_renderer *renderer, + struct wlr_vk_render_submit_pass *submit_pass) { + VkResult res; VkDevice dev = renderer->dev->dev; - if (!init_blend_to_output_layouts(renderer)) { + if (!init_blend_to_output_layouts(renderer, submit_pass)) { return false; } - if (!init_dummy_images(renderer)) { + if (!init_dummy_images(renderer, submit_pass)) { return false; } - // load vert module and tex frag module since they are needed to - // initialize the tex pipeline VkShaderModuleCreateInfo sinfo = { .sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, .codeSize = sizeof(common_vert_data), .pCode = common_vert_data, }; - res = vkCreateShaderModule(dev, &sinfo, NULL, &renderer->vert_module); + res = vkCreateShaderModule(dev, &sinfo, NULL, &submit_pass->output.vert_module); if (res != VK_SUCCESS) { - wlr_vk_error("Failed to create vertex shader module", res); - return false; - } - - sinfo = (VkShaderModuleCreateInfo){ - .sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, - .codeSize = sizeof(texture_frag_data), - .pCode = texture_frag_data, - }; - res = vkCreateShaderModule(dev, &sinfo, NULL, &renderer->tex_frag_module); - if (res != VK_SUCCESS) { - wlr_vk_error("Failed to create tex fragment shader module", res); - return false; - } - - sinfo = (VkShaderModuleCreateInfo){ - .sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, - .codeSize = sizeof(quad_frag_data), - .pCode = quad_frag_data, - }; - res = vkCreateShaderModule(dev, &sinfo, NULL, &renderer->quad_frag_module); - if (res != VK_SUCCESS) { - wlr_vk_error("Failed to create quad fragment shader module", res); + wlr_vk_error("Failed to create blend->output vertex shader module", res); return false; } @@ -2384,7 +2373,7 @@ static bool init_static_render_data(struct wlr_vk_renderer *renderer) { .codeSize = sizeof(output_frag_data), .pCode = output_frag_data, }; - res = vkCreateShaderModule(dev, &sinfo, NULL, &renderer->output_module); + res = vkCreateShaderModule(dev, &sinfo, NULL, &submit_pass->output.frag_module); if (res != VK_SUCCESS) { wlr_vk_error("Failed to create blend->output fragment shader module", res); return false; @@ -2421,6 +2410,12 @@ static struct wlr_vk_render_format_setup *find_or_create_render_setup( VkResult res; if (use_blending_buffer) { + struct wlr_vk_render_submit_pass *submit_pass = + wlr_vk_render_submit_pass_from_pass(renderer->wlr_renderer.submit_pass);; + if (submit_pass == NULL) { + goto error; + } + VkAttachmentDescription attachments[] = { { .format = VK_FORMAT_R16G16B16A16_SFLOAT, @@ -2532,32 +2527,38 @@ static struct wlr_vk_render_format_setup *find_or_create_render_setup( // this is only well defined if render pass has a 2nd subpass if (!init_blend_to_output_pipeline( - renderer, setup->render_pass, renderer->output_pipe_layout, + renderer, submit_pass, setup->render_pass, + submit_pass->output.pipe_layout, &setup->output_pipe_identity, WLR_VK_OUTPUT_TRANSFORM_IDENTITY)) { goto error; } if (!init_blend_to_output_pipeline( - renderer, setup->render_pass, renderer->output_pipe_layout, + renderer, submit_pass, setup->render_pass, + submit_pass->output.pipe_layout, &setup->output_pipe_lut3d, WLR_VK_OUTPUT_TRANSFORM_LUT3D)) { goto error; } if (!init_blend_to_output_pipeline( - renderer, setup->render_pass, renderer->output_pipe_layout, + renderer, submit_pass, setup->render_pass, + submit_pass->output.pipe_layout, &setup->output_pipe_srgb, WLR_VK_OUTPUT_TRANSFORM_INVERSE_SRGB)) { goto error; } if (!init_blend_to_output_pipeline( - renderer, setup->render_pass, renderer->output_pipe_layout, + renderer, submit_pass, setup->render_pass, + submit_pass->output.pipe_layout, &setup->output_pipe_pq, WLR_VK_OUTPUT_TRANSFORM_INVERSE_ST2084_PQ)) { goto error; } if (!init_blend_to_output_pipeline( - renderer, setup->render_pass, renderer->output_pipe_layout, + renderer, submit_pass, setup->render_pass, + submit_pass->output.pipe_layout, &setup->output_pipe_gamma22, WLR_VK_OUTPUT_TRANSFORM_INVERSE_GAMMA22)) { goto error; } if (!init_blend_to_output_pipeline( - renderer, setup->render_pass, renderer->output_pipe_layout, + renderer, submit_pass, setup->render_pass, + submit_pass->output.pipe_layout, &setup->output_pipe_bt1886, WLR_VK_OUTPUT_TRANSFORM_INVERSE_BT1886)) { goto error; } @@ -2634,29 +2635,6 @@ static struct wlr_vk_render_format_setup *find_or_create_render_setup( } } - if (!setup_get_or_create_pipeline(setup, &(struct wlr_vk_pipeline_key){ - .source = WLR_VK_SHADER_SOURCE_SINGLE_COLOR, - .layout = {0}, - })) { - goto error; - } - - if (!setup_get_or_create_pipeline(setup, &(struct wlr_vk_pipeline_key){ - .source = WLR_VK_SHADER_SOURCE_TEXTURE, - .texture_transform = WLR_VK_TEXTURE_TRANSFORM_IDENTITY, - .layout = {0}, - })) { - goto error; - } - - if (!setup_get_or_create_pipeline(setup, &(struct wlr_vk_pipeline_key){ - .source = WLR_VK_SHADER_SOURCE_TEXTURE, - .texture_transform = WLR_VK_TEXTURE_TRANSFORM_SRGB, - .layout = {0}, - })) { - goto error; - } - wl_list_insert(&renderer->render_format_setups, &setup->link); return setup; @@ -2681,7 +2659,6 @@ struct wlr_renderer *vulkan_renderer_create_for_device(struct wlr_vk_device *dev wl_list_init(&renderer->foreign_textures); wl_list_init(&renderer->textures); wl_list_init(&renderer->descriptor_pools); - wl_list_init(&renderer->output_descriptor_pools); wl_list_init(&renderer->render_format_setups); wl_list_init(&renderer->render_buffers); wl_list_init(&renderer->color_transforms); @@ -2697,10 +2674,6 @@ struct wlr_renderer *vulkan_renderer_create_for_device(struct wlr_vk_device *dev renderer->wlr_renderer.features.timeline = dev->sync_file_import_export && cap_syncobj_timeline != 0; } - if (!init_static_render_data(renderer)) { - goto error; - } - VkCommandPoolCreateInfo cpool_info = { .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, .flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, diff --git a/render/wlr_renderer.c b/render/wlr_renderer.c index e65314ccc..296c276df 100644 --- a/render/wlr_renderer.c +++ b/render/wlr_renderer.c @@ -53,6 +53,9 @@ void wlr_renderer_destroy(struct wlr_renderer *r) { assert(wl_list_empty(&r->events.destroy.listener_list)); assert(wl_list_empty(&r->events.lost.listener_list)); + wlr_render_rect_pass_destroy(r->rect_pass); + wlr_render_texture_pass_destroy(r->texture_pass); + wlr_render_submit_pass_destroy(r->submit_pass); if (r->impl && r->impl->destroy) { r->impl->destroy(r); } else { diff --git a/tinywl/Makefile b/tinywl/Makefile index 0f1c4cb13..c8f38d999 100644 --- a/tinywl/Makefile +++ b/tinywl/Makefile @@ -1,8 +1,9 @@ PKG_CONFIG?=pkg-config PKGS="wlroots-0.21" wayland-server xkbcommon +CFLAGS_PIXMAN!=$(PKG_CONFIG) --cflags pixman-1 CFLAGS_PKG_CONFIG!=$(PKG_CONFIG) --cflags $(PKGS) -CFLAGS+=$(CFLAGS_PKG_CONFIG) +CFLAGS+=$(CFLAGS_PIXMAN) $(CFLAGS_PKG_CONFIG) LIBS!=$(PKG_CONFIG) --libs $(PKGS) all: tinywl diff --git a/types/output/output.c b/types/output/output.c index 46da1f425..80fc0680b 100644 --- a/types/output/output.c +++ b/types/output/output.c @@ -377,6 +377,7 @@ void wlr_output_init(struct wlr_output *output, struct wlr_backend *backend, wl_signal_init(&output->events.description); wl_signal_init(&output->events.request_state); wl_signal_init(&output->events.destroy); + wl_signal_init(&output->events.render_inited); output->software_cursor_locks = env_parse_bool("WLR_NO_HARDWARE_CURSORS"); if (output->software_cursor_locks) { @@ -407,6 +408,7 @@ void wlr_output_finish(struct wlr_output *output) { assert(wl_list_empty(&output->events.description.listener_list)); assert(wl_list_empty(&output->events.request_state.listener_list)); assert(wl_list_empty(&output->events.destroy.listener_list)); + assert(wl_list_empty(&output->events.render_inited.listener_list)); wlr_output_destroy_global(output); diff --git a/types/output/render.c b/types/output/render.c index 155da5cf8..78daa3d48 100644 --- a/types/output/render.c +++ b/types/output/render.c @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include "render/drm_format_set.h" @@ -35,6 +36,12 @@ bool wlr_output_init_render(struct wlr_output *output, output->allocator = allocator; output->renderer = renderer; + get_or_create_render_rect_pass(renderer); + get_or_create_render_texture_pass(renderer); + get_or_create_render_submit_pass(renderer); + + wl_signal_emit_mutable(&output->events.render_inited, output); + return true; }