diff options
author | Drew DeVault <sir@cmpwn.com> | 2018-03-22 19:59:15 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-03-22 19:59:15 -0400 |
commit | 77d3be66eaabca4309794536984c54a5e94e9eb5 (patch) | |
tree | 50bde81f0a3b4a9a66f1e029823c391cb7345657 | |
parent | ef3769851f1b8586951cdf3ae71c3529f95a8fd6 (diff) | |
parent | a854c2f24677595110859373c75eb8ec5e50f91e (diff) |
Merge pull request #738 from emersion/gles2-renderer-redesign
Redesign GLES2 renderer
-rw-r--r-- | backend/drm/drm.c | 25 | ||||
-rw-r--r-- | backend/drm/renderer.c | 23 | ||||
-rw-r--r-- | backend/headless/output.c | 14 | ||||
-rw-r--r-- | backend/wayland/output.c | 21 | ||||
-rw-r--r-- | examples/output-layout.c | 2 | ||||
-rw-r--r-- | examples/rotation.c | 2 | ||||
-rw-r--r-- | examples/tablet.c | 2 | ||||
-rw-r--r-- | examples/touch.c | 2 | ||||
-rw-r--r-- | include/render/gles2.h | 45 | ||||
-rw-r--r-- | include/wlr/render/interface.h | 13 | ||||
-rw-r--r-- | include/wlr/render/wlr_renderer.h | 2 | ||||
-rw-r--r-- | include/wlr/render/wlr_texture.h | 2 | ||||
-rw-r--r-- | render/glapi.txt | 4 | ||||
-rw-r--r-- | render/gles2/pixel_format.c | 25 | ||||
-rw-r--r-- | render/gles2/renderer.c | 456 | ||||
-rw-r--r-- | render/gles2/shaders.c | 148 | ||||
-rw-r--r-- | render/gles2/texture.c | 224 | ||||
-rw-r--r-- | render/wlr_renderer.c | 6 | ||||
-rw-r--r-- | render/wlr_texture.c | 6 | ||||
-rw-r--r-- | rootston/output.c | 2 | ||||
-rw-r--r-- | wlroots.syms | 2 |
21 files changed, 590 insertions, 436 deletions
diff --git a/backend/drm/drm.c b/backend/drm/drm.c index 344756f8..524e80bb 100644 --- a/backend/drm/drm.c +++ b/backend/drm/drm.c @@ -582,11 +582,8 @@ static bool wlr_drm_connector_set_cursor(struct wlr_output *output, return false; } - // OpenGL will read the pixels out upside down, - // so we need to flip the image vertically - enum wl_output_transform transform = wlr_output_transform_compose( - wlr_output_transform_invert(output->transform), - WL_OUTPUT_TRANSFORM_FLIPPED_180); + enum wl_output_transform transform = + wlr_output_transform_invert(output->transform); wlr_matrix_projection(plane->matrix, plane->surf.width, plane->surf.height, transform); @@ -643,18 +640,14 @@ static bool wlr_drm_connector_set_cursor(struct wlr_output *output, wlr_texture_upload_pixels(plane->wlr_tex, WL_SHM_FORMAT_ARGB8888, stride, width, height, buf); - glViewport(0, 0, plane->surf.width, plane->surf.height); - glClearColor(0.0, 0.0, 0.0, 0.0); - glClear(GL_COLOR_BUFFER_BIT); + struct wlr_renderer *rend = plane->surf.renderer->wlr_rend; + wlr_renderer_begin(rend, plane->surf.width, plane->surf.height); + wlr_renderer_clear(rend, (float[]){ 0.0, 0.0, 0.0, 0.0 }); + wlr_render_texture(rend, plane->wlr_tex, plane->matrix, 0, 0, 1.0f); + wlr_renderer_end(rend); - wlr_render_texture(plane->surf.renderer->wlr_rend, plane->wlr_tex, - plane->matrix, 0, 0, 1.0f); - - glFinish(); - glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, bo_stride); - glReadPixels(0, 0, plane->surf.width, plane->surf.height, GL_BGRA_EXT, - GL_UNSIGNED_BYTE, bo_data); - glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, 0); + wlr_renderer_read_pixels(rend, WL_SHM_FORMAT_ARGB8888, bo_stride, + plane->surf.width, plane->surf.height, 0, 0, 0, 0, bo_data); wlr_drm_surface_swap_buffers(&plane->surf, NULL); diff --git a/backend/drm/renderer.c b/backend/drm/renderer.c index 528cd26c..b2998b5f 100644 --- a/backend/drm/renderer.c +++ b/backend/drm/renderer.c @@ -2,7 +2,6 @@ #include <EGL/egl.h> #include <EGL/eglext.h> #include <gbm.h> -#include <GLES2/gl2.h> #include <stdbool.h> #include <stdlib.h> #include <unistd.h> @@ -107,9 +106,6 @@ void wlr_drm_surface_finish(struct wlr_drm_surface *surf) { return; } - eglMakeCurrent(surf->renderer->egl.display, EGL_NO_SURFACE, EGL_NO_SURFACE, - EGL_NO_CONTEXT); - if (surf->front) { gbm_surface_release_buffer(surf->gbm, surf->front); } @@ -151,9 +147,10 @@ struct gbm_bo *wlr_drm_surface_get_front(struct wlr_drm_surface *surf) { } wlr_drm_surface_make_current(surf, NULL); - glViewport(0, 0, surf->width, surf->height); - glClearColor(0.0, 0.0, 0.0, 1.0); - glClear(GL_COLOR_BUFFER_BIT); + struct wlr_renderer *renderer = surf->renderer->wlr_rend; + wlr_renderer_begin(renderer, surf->width, surf->height); + wlr_renderer_clear(renderer, (float[]){ 0.0, 0.0, 0.0, 1.0 }); + wlr_renderer_end(renderer); return wlr_drm_surface_swap_buffers(surf, NULL); } @@ -185,6 +182,8 @@ static struct wlr_texture *get_tex_for_bo(struct wlr_drm_renderer *renderer, return tex->tex; } + // TODO: use wlr_texture_upload_dmabuf instead + tex = malloc(sizeof(*tex)); if (!tex) { wlr_log_errno(L_ERROR, "Allocation failed"); @@ -230,14 +229,14 @@ struct gbm_bo *wlr_drm_surface_mgpu_copy(struct wlr_drm_surface *dest, struct wlr_texture *tex = get_tex_for_bo(dest->renderer, src); assert(tex); - static const float color[] = {0.0, 0.0, 0.0, 1.0}; - float mat[9]; wlr_matrix_projection(mat, 1, 1, WL_OUTPUT_TRANSFORM_FLIPPED_180); - glViewport(0, 0, dest->width, dest->height); - wlr_renderer_clear(dest->renderer->wlr_rend, color); - wlr_render_texture_with_matrix(dest->renderer->wlr_rend, tex, mat, 1.0f); + struct wlr_renderer *renderer = dest->renderer->wlr_rend; + wlr_renderer_begin(renderer, dest->width, dest->height); + wlr_renderer_clear(renderer, (float[]){ 0.0, 0.0, 0.0, 1.0 }); + wlr_render_texture_with_matrix(renderer, tex, mat, 1.0f); + wlr_renderer_end(renderer); return wlr_drm_surface_swap_buffers(dest, NULL); } diff --git a/backend/headless/output.c b/backend/headless/output.c index fc275eaf..a13ed22c 100644 --- a/backend/headless/output.c +++ b/backend/headless/output.c @@ -1,8 +1,8 @@ #include <EGL/egl.h> #include <EGL/eglext.h> -#include <GLES2/gl2.h> #include <stdlib.h> #include <wlr/interfaces/wlr_output.h> +#include <wlr/render/wlr_renderer.h> #include <wlr/util/log.h> #include "backend/headless.h" #include "util/signal.h" @@ -120,16 +120,14 @@ struct wlr_output *wlr_headless_add_output(struct wlr_backend *wlr_backend, snprintf(wlr_output->name, sizeof(wlr_output->name), "HEADLESS-%d", wl_list_length(&backend->outputs) + 1); - if (!eglMakeCurrent(output->backend->egl.display, - output->egl_surface, output->egl_surface, - output->backend->egl.context)) { - wlr_log(L_ERROR, "eglMakeCurrent failed"); + if (!wlr_egl_make_current(&output->backend->egl, output->egl_surface, + NULL)) { goto error; } - glViewport(0, 0, wlr_output->width, wlr_output->height); - glClearColor(1.0, 1.0, 1.0, 1.0); - glClear(GL_COLOR_BUFFER_BIT); + wlr_renderer_begin(backend->renderer, wlr_output->width, wlr_output->height); + wlr_renderer_clear(backend->renderer, (float[]){ 1.0, 1.0, 1.0, 1.0 }); + wlr_renderer_end(backend->renderer); struct wl_event_loop *ev = wl_display_get_event_loop(backend->display); output->frame_timer = wl_event_loop_add_timer(ev, signal_frame, output); diff --git a/backend/wayland/output.c b/backend/wayland/output.c index 6becceb7..d528c888 100644 --- a/backend/wayland/output.c +++ b/backend/wayland/output.c @@ -1,5 +1,4 @@ #include <assert.h> -#include <GLES2/gl2.h> #include <stdint.h> #include <stdio.h> #include <stdlib.h> @@ -9,6 +8,7 @@ #include <unistd.h> #include <wayland-client.h> #include <wlr/interfaces/wlr_output.h> +#include <wlr/render/wlr_renderer.h> #include <wlr/util/log.h> #include "backend/wayland.h" #include "util/signal.h" @@ -313,27 +313,26 @@ struct wlr_output *wlr_wl_output_create(struct wlr_backend *_backend) { output->egl_window = wl_egl_window_create(output->surface, wlr_output->width, wlr_output->height); - output->egl_surface = wlr_egl_create_surface(&backend->egl, output->egl_window); + output->egl_surface = wlr_egl_create_surface(&backend->egl, + output->egl_window); wl_display_roundtrip(output->backend->remote_display); // start rendering loop per callbacks by rendering first frame - if (!eglMakeCurrent(output->backend->egl.display, - output->egl_surface, output->egl_surface, - output->backend->egl.context)) { - wlr_log(L_ERROR, "eglMakeCurrent failed"); + if (!wlr_egl_make_current(&output->backend->egl, output->egl_surface, + NULL)) { goto error; } - glViewport(0, 0, wlr_output->width, wlr_output->height); - glClearColor(1.0, 1.0, 1.0, 1.0); - glClear(GL_COLOR_BUFFER_BIT); + wlr_renderer_begin(backend->renderer, wlr_output->width, wlr_output->height); + wlr_renderer_clear(backend->renderer, (float[]){ 1.0, 1.0, 1.0, 1.0 }); + wlr_renderer_end(backend->renderer); output->frame_callback = wl_surface_frame(output->surface); wl_callback_add_listener(output->frame_callback, &frame_listener, output); - if (!eglSwapBuffers(output->backend->egl.display, output->egl_surface)) { - wlr_log(L_ERROR, "eglSwapBuffers failed"); + if (!wlr_egl_swap_buffers(&output->backend->egl, output->egl_surface, + NULL)) { goto error; } diff --git a/examples/output-layout.c b/examples/output-layout.c index de134a71..45d896b0 100644 --- a/examples/output-layout.c +++ b/examples/output-layout.c @@ -101,7 +101,7 @@ static void handle_output_frame(struct output_state *output, struct wlr_output *wlr_output = output->output; wlr_output_make_current(wlr_output, NULL); - wlr_renderer_begin(sample->renderer, wlr_output); + wlr_renderer_begin(sample->renderer, wlr_output->width, wlr_output->height); wlr_renderer_clear(sample->renderer, (float[]){0.25f, 0.25f, 0.25f, 1}); animate_cat(sample, output->output); diff --git a/examples/rotation.c b/examples/rotation.c index 7f50b620..cbff09a1 100644 --- a/examples/rotation.c +++ b/examples/rotation.c @@ -43,7 +43,7 @@ static void handle_output_frame(struct output_state *output, struct timespec *ts wlr_output_effective_resolution(wlr_output, &width, &height); wlr_output_make_current(wlr_output, NULL); - wlr_renderer_begin(sample->renderer, wlr_output); + wlr_renderer_begin(sample->renderer, wlr_output->width, wlr_output->height); wlr_renderer_clear(sample->renderer, (float[]){0.25f, 0.25f, 0.25f, 1}); for (int y = -128 + (int)odata->y_offs; y < height; y += 128) { diff --git a/examples/tablet.c b/examples/tablet.c index 1b995003..65c559cb 100644 --- a/examples/tablet.c +++ b/examples/tablet.c @@ -46,7 +46,7 @@ static void handle_output_frame(struct output_state *output, struct timespec *ts wlr_output_effective_resolution(wlr_output, &width, &height); wlr_output_make_current(wlr_output, NULL); - wlr_renderer_begin(sample->renderer, wlr_output); + wlr_renderer_begin(sample->renderer, wlr_output->width, wlr_output->height); wlr_renderer_clear(sample->renderer, (float[]){0.25f, 0.25f, 0.25f, 1}); float matrix[9]; diff --git a/examples/touch.c b/examples/touch.c index 0968e82a..f9c496cf 100644 --- a/examples/touch.c +++ b/examples/touch.c @@ -42,7 +42,7 @@ static void handle_output_frame(struct output_state *output, struct timespec *ts wlr_output_effective_resolution(wlr_output, &width, &height); wlr_output_make_current(wlr_output, NULL); - wlr_renderer_begin(sample->renderer, wlr_output); + wlr_renderer_begin(sample->renderer, wlr_output->width, wlr_output->height); wlr_renderer_clear(sample->renderer, (float[]){0.25f, 0.25f, 0.25f, 1}); struct touch_point *p; diff --git a/include/render/gles2.h b/include/render/gles2.h index 0a4fb49f..43a8d648 100644 --- a/include/render/gles2.h +++ b/include/render/gles2.h @@ -17,17 +17,25 @@ extern PFNGLEGLIMAGETARGETTEXTURE2DOESPROC glEGLImageTargetTexture2DOES; -struct pixel_format { +struct gles2_pixel_format { uint32_t wl_format; GLint gl_format, gl_type; int depth, bpp; - GLuint *shader; + bool has_alpha; }; struct wlr_gles2_renderer { struct wlr_renderer wlr_renderer; struct wlr_egl *egl; + + struct { + GLuint quad; + GLuint ellipse; + GLuint tex_rgba; + GLuint tex_rgbx; + GLuint tex_ext; + } shaders; }; struct wlr_gles2_texture { @@ -35,37 +43,20 @@ struct wlr_gles2_texture { struct wlr_egl *egl; GLuint tex_id; - const struct pixel_format *pixel_format; + const struct gles2_pixel_format *pixel_format; EGLImageKHR image; GLenum target; }; -struct shaders { - bool initialized; - GLuint rgba, rgbx; - GLuint quad; - GLuint ellipse; - GLuint external; -}; - -extern struct shaders shaders; - -const struct pixel_format *gl_format_for_wl_format(enum wl_shm_format fmt); +const struct gles2_pixel_format *gles2_format_from_wl(enum wl_shm_format fmt); +const enum wl_shm_format *gles2_formats(size_t *len); struct wlr_texture *gles2_texture_create(); +struct wlr_gles2_texture *gles2_get_texture(struct wlr_texture *wlr_texture); -extern const GLchar quad_vertex_src[]; -extern const GLchar quad_fragment_src[]; -extern const GLchar ellipse_fragment_src[]; -extern const GLchar vertex_src[]; -extern const GLchar fragment_src_rgba[]; -extern const GLchar fragment_src_rgbx[]; -extern const GLchar fragment_src_external[]; - -bool _gles2_flush_errors(const char *file, int line); -#define gles2_flush_errors(...) \ - _gles2_flush_errors(wlr_strip_path(__FILE__), __LINE__) - -#define GL_CALL(func) func; gles2_flush_errors() +void gles2_push_marker(const char *file, const char *func); +void gles2_pop_marker(void); +#define GLES2_DEBUG_PUSH gles2_push_marker(wlr_strip_path(__FILE__), __func__) +#define GLES2_DEBUG_POP gles2_pop_marker() #endif diff --git a/include/wlr/render/interface.h b/include/wlr/render/interface.h index f0307230..7f25c0ff 100644 --- a/include/wlr/render/interface.h +++ b/include/wlr/render/interface.h @@ -14,11 +14,12 @@ struct wlr_renderer_impl; struct wlr_renderer { - struct wlr_renderer_impl *impl; + const struct wlr_renderer_impl *impl; }; struct wlr_renderer_impl { - void (*begin)(struct wlr_renderer *renderer, struct wlr_output *output); + void (*begin)(struct wlr_renderer *renderer, uint32_t width, + uint32_t height); void (*end)(struct wlr_renderer *renderer); void (*clear)(struct wlr_renderer *renderer, const float color[static 4]); void (*scissor)(struct wlr_renderer *renderer, struct wlr_box *box); @@ -44,7 +45,7 @@ struct wlr_renderer_impl { }; void wlr_renderer_init(struct wlr_renderer *renderer, - struct wlr_renderer_impl *impl); + const struct wlr_renderer_impl *impl); struct wlr_texture_impl { bool (*upload_pixels)(struct wlr_texture *texture, @@ -65,14 +66,12 @@ struct wlr_texture_impl { struct wl_resource *dmabuf_resource); void (*get_buffer_size)(struct wlr_texture *texture, struct wl_resource *resource, int *width, int *height); - void (*bind)(struct wlr_texture *texture); void (*destroy)(struct wlr_texture *texture); }; void wlr_texture_init(struct wlr_texture *texture, - struct wlr_texture_impl *impl); -void wlr_texture_bind(struct wlr_texture *texture); + const struct wlr_texture_impl *impl); void wlr_texture_get_buffer_size(struct wlr_texture *texture, - struct wl_resource *resource, int *width, int *height); + struct wl_resource *resource, int *width, int *height); #endif diff --git a/include/wlr/render/wlr_renderer.h b/include/wlr/render/wlr_renderer.h index d5f3cf70..6f0d2ecc 100644 --- a/include/wlr/render/wlr_renderer.h +++ b/include/wlr/render/wlr_renderer.h @@ -12,7 +12,7 @@ struct wlr_output; struct wlr_renderer; -void wlr_renderer_begin(struct wlr_renderer *r, struct wlr_output *output); +void wlr_renderer_begin(struct wlr_renderer *r, int width, int height); void wlr_renderer_end(struct wlr_renderer *r); void wlr_renderer_clear(struct wlr_renderer *r, const float color[static 4]); /** diff --git a/include/wlr/render/wlr_texture.h b/include/wlr/render/wlr_texture.h index 49aa93d7..095097e6 100644 --- a/include/wlr/render/wlr_texture.h +++ b/include/wlr/render/wlr_texture.h @@ -9,7 +9,7 @@ struct wlr_texture_impl; struct wlr_texture { - struct wlr_texture_impl *impl; + const struct wlr_texture_impl *impl; bool valid; uint32_t format; diff --git a/render/glapi.txt b/render/glapi.txt index 2077d1c3..a8e4aaba 100644 --- a/render/glapi.txt +++ b/render/glapi.txt @@ -11,3 +11,7 @@ eglCreatePlatformWindowSurfaceEXT -eglQueryDmaBufFormatsEXT -eglQueryDmaBufModifiersEXT -eglDebugMessageControlKHR +-glDebugMessageCallbackKHR +-glDebugMessageControlKHR +-glPopDebugGroupKHR +-glPushDebugGroupKHR diff --git a/render/gles2/pixel_format.c b/render/gles2/pixel_format.c index a544077b..89ba762f 100644 --- a/render/gles2/pixel_format.c +++ b/render/gles2/pixel_format.c @@ -6,14 +6,14 @@ * The wayland formats are little endian while the GL formats are big endian, * so WL_SHM_FORMAT_ARGB8888 is actually compatible with GL_BGRA_EXT. */ -struct pixel_format formats[] = { +static const struct gles2_pixel_format formats[] = { { .wl_format = WL_SHM_FORMAT_ARGB8888, .depth = 32, .bpp = 32, .gl_format = GL_BGRA_EXT, .gl_type = GL_UNSIGNED_BYTE, - .shader = &shaders.rgba + .has_alpha = true, }, { .wl_format = WL_SHM_FORMAT_XRGB8888, @@ -21,7 +21,7 @@ struct pixel_format formats[] = { .bpp = 32, .gl_format = GL_BGRA_EXT, .gl_type = GL_UNSIGNED_BYTE, - .shader = &shaders.rgbx + .has_alpha = false, }, { .wl_format = WL_SHM_FORMAT_XBGR8888, @@ -29,7 +29,7 @@ struct pixel_format formats[] = { .bpp = 32, .gl_format = GL_RGBA, .gl_type = GL_UNSIGNED_BYTE, - .shader = &shaders.rgbx + .has_alpha = false, }, { .wl_format = WL_SHM_FORMAT_ABGR8888, @@ -37,12 +37,20 @@ struct pixel_format formats[] = { .bpp = 32, .gl_format = GL_RGBA, .gl_type = GL_UNSIGNED_BYTE, - .shader = &shaders.rgba + .has_alpha = true, }, }; + +static const enum wl_shm_format wl_formats[] = { + WL_SHM_FORMAT_ARGB8888, + WL_SHM_FORMAT_XRGB8888, + WL_SHM_FORMAT_ABGR8888, + WL_SHM_FORMAT_XBGR8888, +}; + // TODO: more pixel formats -const struct pixel_format *gl_format_for_wl_format(enum wl_shm_format fmt) { +const struct gles2_pixel_format *gles2_format_from_wl(enum wl_shm_format fmt) { for (size_t i = 0; i < sizeof(formats) / sizeof(*formats); ++i) { if (formats[i].wl_format == fmt) { return &formats[i]; @@ -50,3 +58,8 @@ const struct pixel_format *gl_format_for_wl_format(enum wl_shm_format fmt) { } return NULL; } + +const enum wl_shm_format *gles2_formats(size_t *len) { + *len = sizeof(wl_formats) / sizeof(wl_formats[0]); + return wl_formats; +} diff --git a/render/gles2/renderer.c b/render/gles2/renderer.c index f525869d..9403c0ed 100644 --- a/render/gles2/renderer.c +++ b/render/gles2/renderer.c @@ -2,145 +2,80 @@ #include <GLES2/gl2.h> #include <GLES2/gl2ext.h> #include <stdint.h> +#include <stdio.h> #include <stdlib.h> #include <wayland-server-protocol.h> #include <wayland-util.h> #include <wlr/backend.h> -#include <wlr/render/wlr_renderer.h> #include <wlr/render/egl.h> #include <wlr/render/interface.h> +#include <wlr/render/wlr_renderer.h> #include <wlr/types/wlr_matrix.h> #include <wlr/util/log.h> #include "render/gles2.h" #include "glapi.h" -struct shaders shaders; - -static bool compile_shader(GLuint type, const GLchar *src, GLuint *shader) { - *shader = GL_CALL(glCreateShader(type)); - int len = strlen(src); - GL_CALL(glShaderSource(*shader, 1, &src, &len)); - GL_CALL(glCompileShader(*shader)); - GLint success; - GL_CALL(glGetShaderiv(*shader, GL_COMPILE_STATUS, &success)); - if (success == GL_FALSE) { - GLint loglen; - GL_CALL(glGetShaderiv(*shader, GL_INFO_LOG_LENGTH, &loglen)); - GLchar msg[loglen]; - GL_CALL(glGetShaderInfoLog(*shader, loglen, &loglen, msg)); - wlr_log(L_ERROR, "Shader compilation failed"); - wlr_log(L_ERROR, "%s", msg); - glDeleteShader(*shader); - return false; - } - return true; -} +static const struct wlr_renderer_impl renderer_impl; -static bool compile_program(const GLchar *vert_src, - const GLchar *frag_src, GLuint *program) { - GLuint vertex, fragment; - if (!compile_shader(GL_VERTEX_SHADER, vert_src, &vertex)) { - return false; - } - if (!compile_shader(GL_FRAGMENT_SHADER, frag_src, &fragment)) { - glDeleteShader(vertex); - return false; - } - *program = GL_CALL(glCreateProgram()); - GL_CALL(glAttachShader(*program, vertex)); - GL_CALL(glAttachShader(*program, fragment)); - GL_CALL(glLinkProgram(*program)); - GLint success; - GL_CALL(glGetProgramiv(*program, GL_LINK_STATUS, &success)); - if (success == GL_FALSE) { - GLint loglen; - GL_CALL(glGetProgramiv(*program, GL_INFO_LOG_LENGTH, &loglen)); - GLchar msg[loglen]; - GL_CALL(glGetProgramInfoLog(*program, loglen, &loglen, msg)); - wlr_log(L_ERROR, "Program link failed"); - wlr_log(L_ERROR, "%s", msg); - glDeleteProgram(*program); - glDeleteShader(vertex); - glDeleteShader(fragment); - return false; - } - glDetachShader(*program, vertex); - glDetachShader(*program, fragment); - glDeleteShader(vertex); - glDeleteShader(fragment); - - return true; +static struct wlr_gles2_renderer *gles2_get_renderer( + struct wlr_renderer *wlr_renderer) { + assert(wlr_renderer->impl == &renderer_impl); + struct wlr_gles2_renderer *renderer = + (struct wlr_gles2_renderer *)wlr_renderer; + assert(eglGetCurrentContext() == renderer->egl->context); + return renderer; } -static void init_default_shaders() { - if (shaders.initialized) { - return; - } - if (!compile_program(vertex_src, fragment_src_rgba, &shaders.rgba)) { - goto error; - } - if (!compile_program(vertex_src, fragment_src_rgbx, &shaders.rgbx)) { - goto error; - } - if (!compile_program(quad_vertex_src, quad_fragment_src, &shaders.quad)) { - goto error; - } - if (!compile_program(quad_vertex_src, ellipse_fragment_src, - &shaders.ellipse)) { - goto error; - } - if (glEGLImageTargetTexture2DOES) { - if (!compile_program(vertex_src, fragment_src_external, - &shaders.external)) { - goto error; - } - } - - wlr_log(L_DEBUG, "Compiled default shaders"); - shaders.initialized = true; - return; -error: - wlr_log(L_ERROR, "Failed to set up default shaders!"); -} +static void gles2_begin(struct wlr_renderer *wlr_renderer, uint32_t width, + uint32_t height) { + gles2_get_renderer(wlr_renderer); -static void init_globals() { - init_default_shaders(); -} + GLES2_DEBUG_PUSH; -static void wlr_gles2_begin(struct wlr_renderer *wlr_renderer, - struct wlr_output *output) { - GL_CALL(glViewport(0, 0, output->width, output->height)); + glViewport(0, 0, width, height); // enable transparency - GL_CALL(glEnable(GL_BLEND)); - GL_CALL(glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)); + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - // Note: maybe we should save output projection and remove some of the need + // XXX: maybe we should save output projection and remove some of the need // for users to sling matricies themselves + + GLES2_DEBUG_POP; } -static void wlr_gles2_end(struct wlr_renderer *wlr_renderer) { +static void gles2_end(struct wlr_renderer *wlr_renderer) { + gles2_get_renderer(wlr_renderer); // no-op } -static void wlr_gles2_clear(struct wlr_renderer *wlr_renderer, +static void gles2_clear(struct wlr_renderer *wlr_renderer, const float color[static 4]) { + gles2_get_renderer(wlr_renderer); + + GLES2_DEBUG_PUSH; glClearColor(color[0], color[1], color[2], color[3]); glClear(GL_COLOR_BUFFER_BIT); + GLES2_DEBUG_POP; } -static void wlr_gles2_scissor(struct wlr_renderer *wlr_renderer, +static void gles2_scissor(struct wlr_renderer *wlr_renderer, struct wlr_box *box) { + gles2_get_renderer(wlr_renderer); + + GLES2_DEBUG_PUSH; if (box != NULL) { glScissor(box->x, box->y, box->width, box->height); glEnable(GL_SCISSOR_TEST); } else { glDisable(GL_SCISSOR_TEST); } + GLES2_DEBUG_POP; } -static struct wlr_texture *wlr_gles2_texture_create( +static struct wlr_texture *gles2_renderer_texture_create( struct wlr_renderer *wlr_renderer) { + assert(wlr_renderer->impl == &renderer_impl); struct wlr_gles2_renderer *renderer = (struct wlr_gles2_renderer *)wlr_renderer; return gles2_texture_create(renderer->egl); @@ -160,97 +95,117 @@ static void draw_quad() { 0, 1, // bottom left }; - GL_CALL(glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, verts)); - GL_CALL(glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, texcoord)); + glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, verts); + glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, texcoord); - GL_CALL(glEnableVertexAttribArray(0)); - GL_CALL(glEnableVertexAttribArray(1)); + glEnableVertexAttribArray(0); + glEnableVertexAttribArray(1); - GL_CALL(glDrawArrays(GL_TRIANGLE_STRIP, 0, 4)); + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); - GL_CALL(glDisableVertexAttribArray(0)); - GL_CALL(glDisableVertexAttribArray(1)); + glDisableVertexAttribArray(0); + glDisableVertexAttribArray(1); } -static bool wlr_gles2_render_texture_with_matrix( - struct wlr_renderer *wlr_renderer, struct wlr_texture *texture, +static bool gles2_render_texture_with_matrix( + struct wlr_renderer *wlr_renderer, struct wlr_texture *wlr_texture, const float matrix[static 9], float alpha) { - if (!texture || !texture->valid) { + struct wlr_gles2_renderer *renderer = gles2_get_renderer(wlr_renderer); + struct wlr_gles2_texture *texture = gles2_get_texture(wlr_texture); + if (!wlr_texture->valid) { wlr_log(L_ERROR, "attempt to render invalid texture"); return false; } + GLuint prog = renderer->shaders.tex_rgba; + if (texture->target == GL_TEXTURE_EXTERNAL_OES) { + prog = renderer->shaders.tex_ext; + } else if (!texture->pixel_format->has_alpha) { + prog = renderer->shaders.tex_rgbx; + } + // OpenGL ES 2 requires the glUniformMatrix3fv transpose parameter to be set // to GL_FALSE float transposition[9]; wlr_matrix_transpose(transposition, matrix); - wlr_texture_bind(texture); - GL_CALL(glUniformMatrix3fv(0, 1, GL_FALSE, transposition)); - GL_CALL(glUniform1i(1, texture->inverted_y)); - GL_CALL(glUniform1f(3, alpha)); + GLES2_DEBUG_PUSH; + glBindTexture(texture->target, texture->tex_id); + glTexParameteri(texture->target, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(texture->target, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glUseProgram(prog); + + glUniformMatrix3fv(0, 1, GL_FALSE, transposition); + glUniform1i(1, wlr_texture->inverted_y); + glUniform1f(3, alpha); draw_quad(); + GLES2_DEBUG_POP; return true; } -static void wlr_gles2_render_quad(struct wlr_renderer *wlr_renderer, +static void gles2_render_quad(struct wlr_renderer *wlr_renderer, const float color[static 4], const float matrix[static 9]) { + struct wlr_gles2_renderer *renderer = gles2_get_renderer(wlr_renderer); + // OpenGL ES 2 requires the glUniformMatrix3fv transpose parameter to be set // to GL_FALSE float transposition[9]; wlr_matrix_transpose(transposition, matrix); - GL_CALL(glUseProgram(shaders.quad)); - GL_CALL(glUniformMatrix3fv(0, 1, GL_FALSE, transposition)); - GL_CALL(glUniform4f(1, color[0], color[1], color[2], color[3])); + GLES2_DEBUG_PUSH; + glUseProgram(renderer->shaders.quad); + glUniformMatrix3fv(0, 1, GL_FALSE, transposition); + glUniform4f(1, color[0], color[1], color[2], color[3]); draw_quad(); + GLES2_DEBUG_POP; } -static void wlr_gles2_render_ellipse(struct wlr_renderer *wlr_renderer, +static void gles2_render_ellipse(struct wlr_renderer *wlr_renderer, const float color[static 4], const float matrix[static 9]) { + struct wlr_gles2_renderer *renderer = gles2_get_renderer(wlr_renderer); + // OpenGL ES 2 requires the glUniformMatrix3fv transpose parameter to be set // to GL_FALSE float transposition[9]; wlr_matrix_transpose(transposition, matrix); - GL_CALL(glUseProgram(shaders.ellipse)); - GL_CALL(glUniformMatrix3fv(0, 1, GL_FALSE, transposition)); - GL_CALL(glUniform4f(1, color[0], color[1], color[2], color[3])); + GLES2_DEBUG_PUSH; + glUseProgram(renderer->shaders.ellipse); + glUniformMatrix3fv(0, 1, GL_FALSE, transposition); + glUniform4f(1, color[0], color[1], color[2], color[3]); draw_quad(); + GLES2_DEBUG_POP; } -static const enum wl_shm_format *wlr_gles2_formats( - struct wlr_renderer *renderer, size_t *len) { - static enum wl_shm_format formats[] = { - WL_SHM_FORMAT_ARGB8888, - WL_SHM_FORMAT_XRGB8888, - WL_SHM_FORMAT_ABGR8888, - WL_SHM_FORMAT_XBGR8888, - }; - *len = sizeof(formats) / sizeof(formats[0]); - return formats; +static const enum wl_shm_format *gles2_renderer_formats( + struct wlr_renderer *wlr_renderer, size_t *len) { + return gles2_formats(len); } -static bool wlr_gles2_buffer_is_drm(struct wlr_renderer *wlr_renderer, +static bool gles2_buffer_is_drm(struct wlr_renderer *wlr_renderer, struct wl_resource *buffer) { - struct wlr_gles2_renderer *renderer = - (struct wlr_gles2_renderer *)wlr_renderer; + struct wlr_gles2_renderer *renderer = gles2_get_renderer(wlr_renderer); + EGLint format; - return wlr_egl_query_buffer(renderer->egl, buffer, - EGL_TEXTURE_FORMAT, &format); + return wlr_egl_query_buffer(renderer->egl, buffer, EGL_TEXTURE_FORMAT, + &format); } -static bool wlr_gles2_read_pixels(struct wlr_renderer *renderer, +static bool gles2_read_pixels(struct wlr_renderer *wlr_renderer, enum wl_shm_format wl_fmt, uint32_t stride, uint32_t width, uint32_t height, uint32_t src_x, uint32_t src_y, uint32_t dst_x, uint32_t dst_y, void *data) { - const struct pixel_format *fmt = gl_format_for_wl_format(wl_fmt); + gles2_get_renderer(wlr_renderer); + + const struct gles2_pixel_format *fmt = gles2_format_from_wl(wl_fmt); if (fmt == NULL) { wlr_log(L_ERROR, "Cannot read pixels: unsupported pixel format"); return false; } + GLES2_DEBUG_PUSH; + // Make sure any pending drawing is finished before we try to read it glFinish(); @@ -262,38 +217,225 @@ static bool wlr_gles2_read_pixels(struct wlr_renderer *renderer, fmt->gl_type, p + i * stride + dst_x * fmt->bpp / 8); } + GLES2_DEBUG_POP; + return true; } -static bool wlr_gles2_format_supported(struct wlr_renderer *r, +static bool gles2_format_supported(struct wlr_renderer *r, enum wl_shm_format wl_fmt) { - return gl_format_for_wl_format(wl_fmt); + return gles2_format_from_wl(wl_fmt) != NULL; +} + +static void gles2_destroy(struct wlr_renderer *wlr_renderer) { + struct wlr_gles2_renderer *renderer = gles2_get_renderer(wlr_renderer); + + wlr_egl_make_current(renderer->egl, EGL_NO_SURFACE, NULL); + + GLES2_DEBUG_PUSH; + glDeleteProgram(renderer->shaders.quad); + glDeleteProgram(renderer->shaders.ellipse); + glDeleteProgram(renderer->shaders.tex_rgba); + glDeleteProgram(renderer->shaders.tex_rgbx); + glDeleteProgram(renderer->shaders.tex_ext); + GLES2_DEBUG_POP; + + if (glDebugMessageCallbackKHR) { + glDisable(GL_DEBUG_OUTPUT_KHR); + glDebugMessageCallbackKHR(NULL, NULL); + } + + free(renderer); } -static struct wlr_renderer_impl wlr_renderer_impl = { - .begin = wlr_gles2_begin, - .end = wlr_gles2_end, - .clear = wlr_gles2_clear, - .scissor = wlr_gles2_scissor, - .texture_create = wlr_gles2_texture_create, - .render_texture_with_matrix = wlr_gles2_render_texture_with_matrix, - .render_quad = wlr_gles2_render_quad, - .render_ellipse = wlr_gles2_render_ellipse, - .formats = wlr_gles2_formats, - .buffer_is_drm = wlr_gles2_buffer_is_drm, - .read_pixels = wlr_gles2_read_pixels, - .format_supported = wlr_gles2_format_supported, +static const struct wlr_renderer_impl renderer_impl = { + .destroy = gles2_destroy, + .begin = gles2_begin, + .end = gles2_end, + .clear = gles2_clear, + .scissor = gles2_scissor, + .texture_create = gles2_renderer_texture_create, + .render_texture_with_matrix = gles2_render_texture_with_matrix, + .render_quad = gles2_render_quad, + .render_ellipse = gles2_render_ellipse, + .formats = gles2_renderer_formats, + .buffer_is_drm = gles2_buffer_is_drm, + .read_pixels = gles2_read_pixels, + .format_supported = gles2_format_supported, }; +void gles2_push_marker(const char *file, const char *func) { + if (!glPushDebugGroupKHR) { + return; + } + + int len = snprintf(NULL, 0, "%s:%s", file, func) + 1; + char str[len]; + snprintf(str, len, "%s:%s", file, func); + glPushDebugGroupKHR(GL_DEBUG_SOURCE_APPLICATION_KHR, 1, -1, str); +} + +void gles2_pop_marker(void) { + if (glPopDebugGroupKHR) { + glPopDebugGroupKHR(); + } +} + +static log_importance_t gles2_log_importance_to_wlr(GLenum type) { + switch (type) { + case GL_DEBUG_TYPE_ERROR_KHR: return L_ERROR; + case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_KHR: return L_DEBUG; + case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_KHR: return L_ERROR; + case GL_DEBUG_TYPE_PORTABILITY_KHR: return L_DEBUG; + case GL_DEBUG_TYPE_PERFORMANCE_KHR: return L_DEBUG; + case GL_DEBUG_TYPE_OTHER_KHR: return L_INFO; + case GL_DEBUG_TYPE_MARKER_KHR: return L_DEBUG; + case GL_DEBUG_TYPE_PUSH_GROUP_KHR: return L_DEBUG; + case GL_DEBUG_TYPE_POP_GROUP_KHR: return L_DEBUG; + default: return L_INFO; + } +} + +static void gles2_log(GLenum src, GLenum type, GLuint id, GLenum severity, + GLsizei len, const GLchar *msg, const void *user) { + _wlr_log(gles2_log_importance_to_wlr(type), "[GLES2] %s", msg); +} + +static GLuint compile_shader(GLuint type, const GLchar *src) { + GLES2_DEBUG_PUSH; + + GLuint shader = glCreateShader(type); + glShaderSource(shader, 1, &src, NULL); + glCompileShader(shader); + + GLint ok; + glGetShaderiv(shader, GL_COMPILE_STATUS, &ok); + if (ok == GL_FALSE) { + glDeleteShader(shader); + shader = 0; + } + + GLES2_DEBUG_POP; + return shader; +} + +static GLuint link_program(const GLchar *vert_src, const GLchar *frag_src) { + GLES2_DEBUG_PUSH; + + GLuint vert = compile_shader(GL_VERTEX_SHADER, vert_src); + if (!vert) { + goto error; + } + + GLuint frag = compile_shader(GL_FRAGMENT_SHADER, frag_src); + if (!frag) { + glDeleteShader(vert); + goto error; + } + + GLuint prog = glCreateProgram(); + glAttachShader(prog, vert); + glAttachShader(prog, frag); + glLinkProgram(prog); + + glDetachShader(prog, vert); + glDetachShader(prog, frag); + glDeleteShader(vert); + glDeleteShader(frag); + + GLint ok; + glGetProgramiv(prog, GL_LINK_STATUS, &ok); + if (ok == GL_FALSE) { + glDeleteProgram(prog); + goto error; + } + + GLES2_DEBUG_POP; + return prog; + +error: + GLES2_DEBUG_POP; + return 0; +} + +extern const GLchar quad_vertex_src[]; +extern const GLchar quad_fragment_src[]; +extern const GLchar ellipse_fragment_src[]; +extern const GLchar tex_vertex_src[]; +extern const GLchar tex_fragment_src_rgba[]; +extern const GLchar tex_fragment_src_rgbx[]; +extern const GLchar tex_fragment_src_external[]; + struct wlr_renderer *wlr_gles2_renderer_create(struct wlr_backend *backend) { - init_globals(); - struct wlr_gles2_renderer *renderer; - if (!(renderer = calloc(1, sizeof(struct wlr_gles2_renderer)))) { + struct wlr_gles2_renderer *renderer = + calloc(1, sizeof(struct wlr_gles2_renderer)); + if (renderer == NULL) { return NULL; } - wlr_renderer_init(&renderer->wlr_renderer, &wlr_renderer_impl); + wlr_renderer_init(&renderer->wlr_renderer, &renderer_impl); renderer->egl = wlr_backend_get_egl(backend); + wlr_egl_make_current(renderer->egl, EGL_NO_SURFACE, NULL); + + if (glDebugMessageCallbackKHR && glDebugMessageControlKHR) { + glEnable(GL_DEBUG_OUTPUT_KHR); + glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS_KHR); + glDebugMessageCallbackKHR(gles2_log, NULL); + + // Silence unwanted message types + glDebugMessageControlKHR(GL_DONT_CARE, GL_DEBUG_TYPE_POP_GROUP_KHR, + GL_DONT_CARE, 0, NULL, GL_FALSE); + glDebugMessageControlKHR(GL_DONT_CARE, GL_DEBUG_TYPE_PUSH_GROUP_KHR, + GL_DONT_CARE, 0, NULL, GL_FALSE); + } + + GLES2_DEBUG_PUSH; + + renderer->shaders.quad = link_program(quad_vertex_src, quad_fragment_src); + if (!renderer->shaders.quad) { + goto error; + } + renderer->shaders.ellipse = + link_program(quad_vertex_src, ellipse_fragment_src); + if (!renderer->shaders.ellipse) { + goto error; + } + renderer->shaders.tex_rgba = + link_program(tex_vertex_src, tex_fragment_src_rgba); + if (!renderer->shaders.tex_rgba) { + goto error; + } + renderer->shaders.tex_rgbx = + link_program(tex_vertex_src, tex_fragment_src_rgbx); + if (!renderer->shaders.tex_rgbx) { + goto error; + } + if (glEGLImageTargetTexture2DOES) { + renderer->shaders.tex_ext = + link_program(tex_vertex_src, tex_fragment_src_external); + if (!renderer->shaders.tex_ext) { + goto error; + } + } + + GLES2_DEBUG_POP; return &renderer->wlr_renderer; + +error: + glDeleteProgram(renderer->shaders.quad); + glDeleteProgram(renderer->shaders.ellipse); + glDeleteProgram(renderer->shaders.tex_rgba); + glDeleteProgram(renderer->shaders.tex_rgbx); + glDeleteProgram(renderer->shaders.tex_ext); + + GLES2_DEBUG_POP; + + if (glDebugMessageCallbackKHR) { + glDisable(GL_DEBUG_OUTPUT_KHR); + glDebugMessageCallbackKHR(NULL, NULL); + } + + free(renderer); + return NULL; } diff --git a/render/gles2/shaders.c b/render/gles2/shaders.c index 30e12e4c..ba3bd971 100644 --- a/render/gles2/shaders.c +++ b/render/gles2/shaders.c @@ -3,86 +3,88 @@ // Colored quads const GLchar quad_vertex_src[] = -"uniform mat3 proj;" -"uniform vec4 color;" -"attribute vec2 pos;" -"attribute vec2 texcoord;" -"varying vec4 v_color;" -"varying vec2 v_texcoord;" -"" -"void main() {" -" gl_Position = vec4(proj * vec3(pos, 1.0), 1.0);" -" v_color = color;" -" v_texcoord = texcoord;" -"}"; +"uniform mat3 proj;\n" +"uniform vec4 color;\n" +"attribute vec2 pos;\n" +"attribute vec2 texcoord;\n" +"varying vec4 v_color;\n" +"varying vec2 v_texcoord;\n" +"\n" +"void main() {\n" +" gl_Position = vec4(proj * vec3(pos, 1.0), 1.0);\n" +" v_color = color;\n" +" v_texcoord = texcoord;\n" +"}\n"; const GLchar quad_fragment_src[] = -"precision mediump float;" -"varying vec4 v_color;" -"varying vec2 v_texcoord;" -"" -"void main() {" -" gl_FragColor = v_color;" -"}"; +"precision mediump float;\n" +"varying vec4 v_color;\n" +"varying vec2 v_texcoord;\n" +"\n" +"void main() {\n" +" gl_FragColor = v_color;\n" +"}\n"; // Colored ellipses const GLchar ellipse_fragment_src[] = -"precision mediump float;" -"varying vec4 v_color;" -"varying vec2 v_texcoord;" -"" -"void main() {" -" float l = length(v_texcoord - vec2(0.5, 0.5));" -" if (l > 0.5) discard;" -" gl_FragColor = v_color;" -"}"; +"precision mediump float;\n" +"varying vec4 v_color;\n" +"varying vec2 v_texcoord;\n" +"\n" +"void main() {\n" +" float l = length(v_texcoord - vec2(0.5, 0.5));\n" +" if (l > 0.5) {\n" +" discard;\n" +" }\n" +" gl_FragColor = v_color;\n" +"}\n"; // Textured quads -const GLchar vertex_src[] = -"uniform mat3 proj;" -"uniform bool invert_y;" -"attribute vec2 pos;" -"attribute vec2 texcoord;" -"varying vec2 v_texcoord;" -"" -"void main() {" -" gl_Position = vec4(proj * vec3(pos, 1.0), 1.0);" -" if (invert_y) {" -" v_texcoord = vec2(texcoord.s, 1.0 - texcoord.t);" -" } else {" -" v_texcoord = texcoord;" -" }" -"}"; +const GLchar tex_vertex_src[] = +"uniform mat3 proj;\n" +"uniform bool invert_y;\n" +"attribute vec2 pos;\n" +"attribute vec2 texcoord;\n" +"varying vec2 v_texcoord;\n" +"\n" +"void main() {\n" +" gl_Position = vec4(proj * vec3(pos, 1.0), 1.0);\n" +" if (invert_y) {\n" +" v_texcoord = vec2(texcoord.s, 1.0 - texcoord.t);\n" +" } else {\n" +" v_texcoord = texcoord;\n" +" }\n" +"}\n"; -const GLchar fragment_src_rgba[] = -"precision mediump float;" -"varying vec2 v_texcoord;" -"uniform sampler2D tex;" -"uniform float alpha;" -"" -"void main() {" -" gl_FragColor = alpha * texture2D(tex, v_texcoord);" -"}"; +const GLchar tex_fragment_src_rgba[] = +"precision mediump float;\n" +"varying vec2 v_texcoord;\n" +"uniform sampler2D tex;\n" +"uniform float alpha;\n" +"\n" +"void main() {\n" +" gl_FragColor = alpha * texture2D(tex, v_texcoord);\n" +"}\n"; -const GLchar fragment_src_rgbx[] = -"precision mediump float;" -"varying vec2 v_texcoord;" -"uniform sampler2D tex;" -"uniform float alpha;" -"" -"void main() {" -" gl_FragColor.rgb = alpha * texture2D(tex, v_texcoord).rgb;" -" gl_FragColor.a = alpha;" -"}"; +const GLchar tex_fragment_src_rgbx[] = +"precision mediump float;\n" +"varying vec2 v_texcoord;\n" +"uniform sampler2D tex;\n" +"uniform float alpha;\n" +"\n" +"void main() {\n" +" gl_FragColor.rgb = alpha * texture2D(tex, v_texcoord).rgb;\n" +" gl_FragColor.a = alpha;\n" +"}\n"; -const GLchar fragment_src_external[] = -"#extension GL_OES_EGL_image_external : require\n" -"precision mediump float;" -"varying vec2 v_texcoord;" -"uniform samplerExternalOES texture0;" -"uniform float alpha;" -"" -"void main() {" -" vec4 col = texture2D(texture0, v_texcoord);" -" gl_FragColor = vec4(col.rgb, col.a * alpha);" -"}"; +const GLchar tex_fragment_src_external[] = +"#extension GL_OES_EGL_image_external : require\n\n" +"precision mediump float;\n" +"varying vec2 v_texcoord;\n" +"uniform samplerExternalOES texture0;\n" +"uniform float alpha;\n" +"\n" +"void main() {\n" +" vec4 col = texture2D(texture0, v_texcoord);\n" +" gl_FragColor = vec4(col.rgb, col.a * alpha);\n" +"}\n"; diff --git a/render/gles2/texture.c b/render/gles2/texture.c index 8da40032..766c0b15 100644 --- a/render/gles2/texture.c +++ b/render/gles2/texture.c @@ -13,33 +13,39 @@ #include "render/gles2.h" #include "util/signal.h" -static struct pixel_format external_pixel_format = { +static struct gles2_pixel_format external_pixel_format = { .wl_format = 0, .depth = 0, .bpp = 0, .gl_format = 0, .gl_type = 0, - .shader = &shaders.external }; -static void gles2_texture_ensure_texture(struct wlr_gles2_texture *texture, +static void gles2_texture_ensure(struct wlr_gles2_texture *texture, GLenum target) { if (texture->tex_id) { return; } texture->target = target; - GL_CALL(glGenTextures(1, &texture->tex_id)); - GL_CALL(glBindTexture(target, texture->tex_id)); - GL_CALL(glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)); - GL_CALL(glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)); + glGenTextures(1, &texture->tex_id); + glBindTexture(target, texture->tex_id); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); } -static bool gles2_texture_upload_pixels(struct wlr_texture *_texture, +static const struct wlr_texture_impl texture_impl; + +struct wlr_gles2_texture *gles2_get_texture(struct wlr_texture *wlr_texture) { + assert(wlr_texture->impl == &texture_impl); + return (struct wlr_gles2_texture *)wlr_texture; +} + +static bool gles2_texture_upload_pixels(struct wlr_texture *wlr_texture, enum wl_shm_format format, int stride, int width, int height, const unsigned char *pixels) { - struct wlr_gles2_texture *texture = (struct wlr_gles2_texture *)_texture; - assert(texture); - const struct pixel_format *fmt = gl_format_for_wl_format(format); + struct wlr_gles2_texture *texture = gles2_get_texture(wlr_texture); + + const struct gles2_pixel_format *fmt = gles2_format_from_wl(format); if (!fmt || !fmt->gl_format) { wlr_log(L_ERROR, "No supported pixel format for this texture"); return false; @@ -49,44 +55,50 @@ static bool gles2_texture_upload_pixels(struct wlr_texture *_texture, texture->wlr_texture.format = format; texture->pixel_format = fmt; - gles2_texture_ensure_texture(texture, GL_TEXTURE_2D); - GL_CALL(glBindTexture(GL_TEXTURE_2D, texture->tex_id)); - GL_CALL(glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, stride)); - GL_CALL(glTexImage2D(GL_TEXTURE_2D, 0, fmt->gl_format, width, height, 0, - fmt->gl_format, fmt->gl_type, pixels)); + GLES2_DEBUG_PUSH; + gles2_texture_ensure(texture, GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D, texture->tex_id); + glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, stride); + glTexImage2D(GL_TEXTURE_2D, 0, fmt->gl_format, width, height, 0, + fmt->gl_format, fmt->gl_type, pixels); + GLES2_DEBUG_POP; + texture->wlr_texture.valid = true; return true; } -static bool gles2_texture_update_pixels(struct wlr_texture *_texture, +static bool gles2_texture_update_pixels(struct wlr_texture *wlr_texture, enum wl_shm_format format, int stride, int x, int y, int width, int height, const unsigned char *pixels) { - struct wlr_gles2_texture *texture = (struct wlr_gles2_texture *)_texture; - assert(texture); + struct wlr_gles2_texture *texture = gles2_get_texture(wlr_texture); + // TODO: Test if the unpack subimage extension is supported and adjust the // upload strategy if not if (!texture->wlr_texture.valid || texture->wlr_texture.format != format /* || unpack not supported */) { - return gles2_texture_upload_pixels(&texture->wlr_texture, - format, stride, width, height, pixels); + return gles2_texture_upload_pixels(&texture->wlr_texture, format, + stride, width, height, pixels); } - const struct pixel_format *fmt = texture->pixel_format; - GL_CALL(glBindTexture(GL_TEXTURE_2D, texture->tex_id)); - GL_CALL(glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, stride)); - GL_CALL(glPixelStorei(GL_UNPACK_SKIP_PIXELS_EXT, x)); - GL_CALL(glPixelStorei(GL_UNPACK_SKIP_ROWS_EXT, y)); - GL_CALL(glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, width, height, - fmt->gl_format, fmt->gl_type, pixels)); - GL_CALL(glPixelStorei(GL_UNPACK_SKIP_PIXELS_EXT, 0)); - GL_CALL(glPixelStorei(GL_UNPACK_SKIP_ROWS_EXT, 0)); + const struct gles2_pixel_format *fmt = texture->pixel_format; + GLES2_DEBUG_PUSH; + glBindTexture(GL_TEXTURE_2D, texture->tex_id); + glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, stride); + glPixelStorei(GL_UNPACK_SKIP_PIXELS_EXT, x); + glPixelStorei(GL_UNPACK_SKIP_ROWS_EXT, y); + glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, width, height, fmt->gl_format, + fmt->gl_type, pixels); + glPixelStorei(GL_UNPACK_SKIP_PIXELS_EXT, 0); + glPixelStorei(GL_UNPACK_SKIP_ROWS_EXT, 0); + GLES2_DEBUG_POP; return true; } -static bool gles2_texture_upload_shm(struct wlr_texture *_texture, +static bool gles2_texture_upload_shm(struct wlr_texture *wlr_texture, uint32_t format, struct wl_shm_buffer *buffer) { - struct wlr_gles2_texture *texture = (struct wlr_gles2_texture *)_texture; - const struct pixel_format *fmt = gl_format_for_wl_format(format); + struct wlr_gles2_texture *texture = gles2_get_texture(wlr_texture); + + const struct gles2_pixel_format *fmt = gles2_format_from_wl(format); if (!fmt || !fmt->gl_format) { wlr_log(L_ERROR, "Unsupported pixel format %"PRIu32" for this texture", format); @@ -102,23 +114,26 @@ static bool gles2_texture_upload_shm(struct wlr_texture *_texture, texture->wlr_texture.format = format; texture->pixel_format = fmt; - gles2_texture_ensure_texture(texture, GL_TEXTURE_2D); - GL_CALL(glBindTexture(GL_TEXTURE_2D, texture->tex_id)); - GL_CALL(glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, pitch)); - GL_CALL(glPixelStorei(GL_UNPACK_SKIP_PIXELS_EXT, 0)); - GL_CALL(glPixelStorei(GL_UNPACK_SKIP_ROWS_EXT, 0)); - GL_CALL(glTexImage2D(GL_TEXTURE_2D, 0, fmt->gl_format, width, height, 0, - fmt->gl_format, fmt->gl_type, pixels)); + GLES2_DEBUG_PUSH; + gles2_texture_ensure(texture, GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D, texture->tex_id); + glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, pitch); + glPixelStorei(GL_UNPACK_SKIP_PIXELS_EXT, 0); + glPixelStorei(GL_UNPACK_SKIP_ROWS_EXT, 0); + glTexImage2D(GL_TEXTURE_2D, 0, fmt->gl_format, width, height, 0, + fmt->gl_format, fmt->gl_type, pixels); + GLES2_DEBUG_POP; texture->wlr_texture.valid = true; wl_shm_buffer_end_access(buffer); return true; } -static bool gles2_texture_update_shm(struct wlr_texture *_texture, +static bool gles2_texture_update_shm(struct wlr_texture *wlr_texture, uint32_t format, int x, int y, int width, int height, struct wl_shm_buffer *buffer) { - struct wlr_gles2_texture *texture = (struct wlr_gles2_texture *)_texture; + struct wlr_gles2_texture *texture = gles2_get_texture(wlr_texture); + // TODO: Test if the unpack subimage extension is supported and adjust the // upload strategy if not assert(texture); @@ -127,28 +142,30 @@ static bool gles2_texture_update_shm(struct wlr_texture *_texture, /* || unpack not supported */) { return gles2_texture_upload_shm(&texture->wlr_texture, format, buffer); } - const struct pixel_format *fmt = texture->pixel_format; + const struct gles2_pixel_format *fmt = texture->pixel_format; wl_shm_buffer_begin_access(buffer); uint8_t *pixels = wl_shm_buffer_get_data(buffer); int pitch = wl_shm_buffer_get_stride(buffer) / (fmt->bpp / 8); - GL_CALL(glBindTexture(GL_TEXTURE_2D, texture->tex_id)); - GL_CALL(glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, pitch)); - GL_CALL(glPixelStorei(GL_UNPACK_SKIP_PIXELS_EXT, x)); - GL_CALL(glPixelStorei(GL_UNPACK_SKIP_ROWS_EXT, y)); - GL_CALL(glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, width, height, - fmt->gl_format, fmt->gl_type, pixels)); - GL_CALL(glPixelStorei(GL_UNPACK_SKIP_PIXELS_EXT, 0)); - GL_CALL(glPixelStorei(GL_UNPACK_SKIP_ROWS_EXT, 0)); + GLES2_DEBUG_PUSH; + glBindTexture(GL_TEXTURE_2D, texture->tex_id); + glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, pitch); + glPixelStorei(GL_UNPACK_SKIP_PIXELS_EXT, x); + glPixelStorei(GL_UNPACK_SKIP_ROWS_EXT, y); + glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, width, height, + fmt->gl_format, fmt->gl_type, pixels); + glPixelStorei(GL_UNPACK_SKIP_PIXELS_EXT, 0); + glPixelStorei(GL_UNPACK_SKIP_ROWS_EXT, 0); + GLES2_DEBUG_POP; wl_shm_buffer_end_access(buffer); return true; } -static bool gles2_texture_upload_drm(struct wlr_texture *_tex, +static bool gles2_texture_upload_drm(struct wlr_texture *wlr_texture, struct wl_resource *buf) { - struct wlr_gles2_texture *tex = (struct wlr_gles2_texture *)_tex; + struct wlr_gles2_texture *tex = gles2_get_texture(wlr_texture); if (!glEGLImageTargetTexture2DOES) { return false; } @@ -160,9 +177,9 @@ static bool gles2_texture_upload_drm(struct wlr_texture *_tex, } wlr_egl_query_buffer(tex->egl, buf, EGL_WIDTH, - (EGLint*)&tex->wlr_texture.width); + (EGLint*)&tex->wlr_texture.width); wlr_egl_query_buffer(tex->egl, buf, EGL_HEIGHT, - (EGLint*)&tex->wlr_texture.height); + (EGLint*)&tex->wlr_texture.height); EGLint inverted_y; if (wlr_egl_query_buffer(tex->egl, buf, EGL_WAYLAND_Y_INVERTED_WL, @@ -171,12 +188,12 @@ static bool gles2_texture_upload_drm(struct wlr_texture *_tex, } GLenum target; - const struct pixel_format *pf; + const struct gles2_pixel_format *pf; switch (format) { case EGL_TEXTURE_RGB: case EGL_TEXTURE_RGBA: target = GL_TEXTURE_2D; - pf = gl_format_for_wl_format(WL_SHM_FORMAT_ARGB8888); + pf = gles2_format_from_wl(WL_SHM_FORMAT_ARGB8888); break; case EGL_TEXTURE_EXTERNAL_WL: target = GL_TEXTURE_EXTERNAL_OES; @@ -187,8 +204,11 @@ static bool gles2_texture_upload_drm(struct wlr_texture *_tex, return false; } - gles2_texture_ensure_texture(tex, target); - GL_CALL(glBindTexture(GL_TEXTURE_2D, tex->tex_id)); + GLES2_DEBUG_PUSH; + gles2_texture_ensure(tex, target); + glBindTexture(GL_TEXTURE_2D, tex->tex_id); + GLES2_DEBUG_POP; + EGLint attribs[] = { EGL_WAYLAND_PLANE_WL, 0, EGL_NONE }; if (tex->image) { @@ -202,18 +222,20 @@ static bool gles2_texture_upload_drm(struct wlr_texture *_tex, return false; } - GL_CALL(glActiveTexture(GL_TEXTURE0)); - GL_CALL(glBindTexture(target, tex->tex_id)); - GL_CALL(glEGLImageTargetTexture2DOES(target, tex->image)); + GLES2_DEBUG_PUSH; + glActiveTexture(GL_TEXTURE0); + glBindTexture(target, tex->tex_id); + glEGLImageTargetTexture2DOES(target, tex->image); + GLES2_DEBUG_POP; tex->wlr_texture.valid = true; tex->pixel_format = pf; return true; } -static bool gles2_texture_upload_eglimage(struct wlr_texture *wlr_tex, +static bool gles2_texture_upload_eglimage(struct wlr_texture *wlr_texture, EGLImageKHR image, uint32_t width, uint32_t height) { - struct wlr_gles2_texture *tex = (struct wlr_gles2_texture *)wlr_tex; + struct wlr_gles2_texture *tex = gles2_get_texture(wlr_texture); tex->image = image; tex->pixel_format = &external_pixel_format; @@ -221,20 +243,21 @@ static bool gles2_texture_upload_eglimage(struct wlr_texture *wlr_tex, tex->wlr_texture.width = width; tex->wlr_texture.height = height; - gles2_texture_ensure_texture(tex, GL_TEXTURE_2D); - - GL_CALL(glActiveTexture(GL_TEXTURE0)); - GL_CALL(glBindTexture(GL_TEXTURE_EXTERNAL_OES, tex->tex_id)); - GL_CALL(glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, tex->image)); + GLES2_DEBUG_PUSH; + gles2_texture_ensure(tex, GL_TEXTURE_2D); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_EXTERNAL_OES, tex->tex_id); + glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, tex->image); + GLES2_DEBUG_POP; return true; } -static bool gles2_texture_upload_dmabuf(struct wlr_texture *_tex, +static bool gles2_texture_upload_dmabuf(struct wlr_texture *wlr_texture, struct wl_resource *dmabuf_resource) { - struct wlr_gles2_texture *tex = (struct wlr_gles2_texture *)_tex; - struct wlr_dmabuf_buffer *dmabuf = wlr_dmabuf_buffer_from_buffer_resource( - dmabuf_resource); + struct wlr_gles2_texture *tex = gles2_get_texture(wlr_texture); + struct wlr_dmabuf_buffer *dmabuf = + wlr_dmabuf_buffer_from_buffer_resource(dmabuf_resource); if (!tex->egl->egl_exts.dmabuf_import) { wlr_log(L_ERROR, "Want dmabuf but extension not present"); @@ -249,17 +272,19 @@ static bool gles2_texture_upload_dmabuf(struct wlr_texture *_tex, } if (wlr_dmabuf_buffer_has_inverted_y(dmabuf)) { - _tex->inverted_y = true; + wlr_texture->inverted_y = true; } GLenum target = GL_TEXTURE_2D; - const struct pixel_format *pf = - gl_format_for_wl_format(WL_SHM_FORMAT_ARGB8888); - gles2_texture_ensure_texture(tex, target); - GL_CALL(glBindTexture(target, tex->tex_id)); + const struct gles2_pixel_format *pf = + gles2_format_from_wl(WL_SHM_FORMAT_ARGB8888); + GLES2_DEBUG_PUSH; + gles2_texture_ensure(tex, target); + glBindTexture(target, tex->tex_id); tex->image = wlr_egl_create_image_from_dmabuf(tex->egl, &dmabuf->attributes); - GL_CALL(glActiveTexture(GL_TEXTURE0)); - GL_CALL(glEGLImageTargetTexture2DOES(target, tex->image)); + glActiveTexture(GL_TEXTURE0); + glEGLImageTargetTexture2DOES(target, tex->image); + GLES2_DEBUG_POP; tex->pixel_format = pf; tex->wlr_texture.valid = true; return true; @@ -271,15 +296,15 @@ static bool gles2_texture_get_dmabuf_size(struct wlr_texture *texture, struct return false; } - struct wlr_dmabuf_buffer *dmabuf = wlr_dmabuf_buffer_from_buffer_resource( - resource); + struct wlr_dmabuf_buffer *dmabuf = + wlr_dmabuf_buffer_from_buffer_resource(resource); *width = dmabuf->attributes.width; *height = dmabuf->attributes.height; return true; } -static void gles2_texture_get_buffer_size(struct wlr_texture *texture, struct - wl_resource *resource, int *width, int *height) { +static void gles2_texture_get_buffer_size(struct wlr_texture *texture, + struct wl_resource *resource, int *width, int *height) { struct wl_shm_buffer *buffer = wl_shm_buffer_get(resource); if (!buffer) { struct wlr_gles2_texture *tex = (struct wlr_gles2_texture *)texture; @@ -288,14 +313,13 @@ static void gles2_texture_get_buffer_size(struct wlr_texture *texture, struct } if (!wlr_egl_query_buffer(tex->egl, resource, EGL_WIDTH, (EGLint*)width)) { - if (!gles2_texture_get_dmabuf_size(texture, resource, - width, height)) { + if (!gles2_texture_get_dmabuf_size(texture, resource, width, + height)) { wlr_log(L_ERROR, "could not get size of the buffer"); return; } } - wlr_egl_query_buffer(tex->egl, resource, EGL_HEIGHT, - (EGLint*)height); + wlr_egl_query_buffer(tex->egl, resource, EGL_HEIGHT, (EGLint*)height); return; } @@ -304,20 +328,15 @@ static void gles2_texture_get_buffer_size(struct wlr_texture *texture, struct *height = wl_shm_buffer_get_height(buffer); } -static void gles2_texture_bind(struct wlr_texture *_texture) { - struct wlr_gles2_texture *texture = (struct wlr_gles2_texture *)_texture; - - GL_CALL(glBindTexture(texture->target, texture->tex_id)); - GL_CALL(glTexParameteri(texture->target, GL_TEXTURE_MIN_FILTER, GL_LINEAR)); - GL_CALL(glTexParameteri(texture->target, GL_TEXTURE_MAG_FILTER, GL_LINEAR)); - GL_CALL(glUseProgram(*texture->pixel_format->shader)); -} +static void gles2_texture_destroy(struct wlr_texture *wlr_texture) { + struct wlr_gles2_texture *texture = gles2_get_texture(wlr_texture); -static void gles2_texture_destroy(struct wlr_texture *_texture) { - struct wlr_gles2_texture *texture = (struct wlr_gles2_texture *)_texture; - wlr_signal_emit_safe(&texture->wlr_texture.destroy_signal, &texture->wlr_texture); + wlr_signal_emit_safe(&texture->wlr_texture.destroy_signal, + &texture->wlr_texture); if (texture->tex_id) { - GL_CALL(glDeleteTextures(1, &texture->tex_id)); + GLES2_DEBUG_PUSH; + glDeleteTextures(1, &texture->tex_id); + GLES2_DEBUG_POP; } if (texture->image) { @@ -327,7 +346,7 @@ static void gles2_texture_destroy(struct wlr_texture *_texture) { free(texture); } -static struct wlr_texture_impl wlr_texture_impl = { +static const struct wlr_texture_impl texture_impl = { .upload_pixels = gles2_texture_upload_pixels, .update_pixels = gles2_texture_update_pixels, .upload_shm = gles2_texture_upload_shm, @@ -336,7 +355,6 @@ static struct wlr_texture_impl wlr_texture_impl = { .upload_dmabuf = gles2_texture_upload_dmabuf, .upload_eglimage = gles2_texture_upload_eglimage, .get_buffer_size = gles2_texture_get_buffer_size, - .bind = gles2_texture_bind, .destroy = gles2_texture_destroy, }; @@ -345,7 +363,7 @@ struct wlr_texture *gles2_texture_create(struct wlr_egl *egl) { if (!(texture = calloc(1, sizeof(struct wlr_gles2_texture)))) { return NULL; } - wlr_texture_init(&texture->wlr_texture, &wlr_texture_impl); + wlr_texture_init(&texture->wlr_texture, &texture_impl); texture->egl = egl; return &texture->wlr_texture; } diff --git a/render/wlr_renderer.c b/render/wlr_renderer.c index 21a7901a..622aa1dd 100644 --- a/render/wlr_renderer.c +++ b/render/wlr_renderer.c @@ -5,7 +5,7 @@ #include <wlr/types/wlr_matrix.h> void wlr_renderer_init(struct wlr_renderer *renderer, - struct wlr_renderer_impl *impl) { + const struct wlr_renderer_impl *impl) { renderer->impl = impl; } @@ -17,8 +17,8 @@ void wlr_renderer_destroy(struct wlr_renderer *r) { } } -void wlr_renderer_begin(struct wlr_renderer *r, struct wlr_output *o) { - r->impl->begin(r, o); +void wlr_renderer_begin(struct wlr_renderer *r, int width, int height) { + r->impl->begin(r, width, height); } void wlr_renderer_end(struct wlr_renderer *r) { diff --git a/render/wlr_texture.c b/render/wlr_texture.c index a5d0abde..33c91822 100644 --- a/render/wlr_texture.c +++ b/render/wlr_texture.c @@ -4,7 +4,7 @@ #include <wlr/render/wlr_texture.h> void wlr_texture_init(struct wlr_texture *texture, - struct wlr_texture_impl *impl) { + const struct wlr_texture_impl *impl) { texture->impl = impl; wl_signal_init(&texture->destroy_signal); } @@ -17,10 +17,6 @@ void wlr_texture_destroy(struct wlr_texture *texture) { } } -void wlr_texture_bind(struct wlr_texture *texture) { - texture->impl->bind(texture); -} - bool wlr_texture_upload_pixels(struct wlr_texture *texture, uint32_t format, int stride, int width, int height, const unsigned char *pixels) { return texture->impl->upload_pixels(texture, format, stride, diff --git a/rootston/output.c b/rootston/output.c index 22c0d7ed..1284c928 100644 --- a/rootston/output.c +++ b/rootston/output.c @@ -479,7 +479,7 @@ static void render_output(struct roots_output *output) { goto damage_finish; } - wlr_renderer_begin(renderer, wlr_output); + wlr_renderer_begin(renderer, wlr_output->width, wlr_output->height); if (!pixman_region32_not_empty(&damage)) { // Output isn't damaged but needs buffer swap diff --git a/wlroots.syms b/wlroots.syms index 3f45e045..cb030a6d 100644 --- a/wlroots.syms +++ b/wlroots.syms @@ -15,8 +15,8 @@ WLROOTS_0_0_0 { wlr_drm_get_connector_props; wlr_drm_get_crtc_props; wlr_drm_get_plane_props; - wlr_drm_get_prop; wlr_drm_get_prop_blob; + wlr_drm_get_prop; wlr_drm_plane_surfaces_init; wlr_drm_renderer_finish; wlr_drm_renderer_init; |