diff options
Diffstat (limited to 'render')
-rw-r--r-- | render/egl.c | 58 | ||||
-rw-r--r-- | render/gles2/pixel_format.c | 20 | ||||
-rw-r--r-- | render/gles2/renderer.c | 105 | ||||
-rw-r--r-- | render/gles2/texture.c | 17 | ||||
-rw-r--r-- | render/meson.build | 8 | ||||
-rw-r--r-- | render/wlr_renderer.c | 9 | ||||
-rw-r--r-- | render/wlr_texture.c | 8 |
7 files changed, 185 insertions, 40 deletions
diff --git a/render/egl.c b/render/egl.c index 96e48c06..644f94ac 100644 --- a/render/egl.c +++ b/render/egl.c @@ -3,6 +3,7 @@ #include <EGL/egl.h> #include <EGL/eglext.h> #include <stdlib.h> +#include <drm_fourcc.h> #include <wlr/render/egl.h> #include <wlr/util/log.h> #include "glapi.h" @@ -120,7 +121,7 @@ bool wlr_egl_init(struct wlr_egl *egl, EGLenum platform, void *remote_display, if (platform == EGL_PLATFORM_SURFACELESS_MESA) { assert(remote_display == NULL); - egl->display = eglGetDisplay(EGL_DEFAULT_DISPLAY); + egl->display = eglGetPlatformDisplayEXT(platform, EGL_DEFAULT_DISPLAY, NULL); } else { egl->display = eglGetPlatformDisplayEXT(platform, remote_display, NULL); } @@ -129,6 +130,8 @@ bool wlr_egl_init(struct wlr_egl *egl, EGLenum platform, void *remote_display, goto error; } + egl->platform = platform; + EGLint major, minor; if (eglInitialize(egl->display, &major, &minor) == EGL_FALSE) { wlr_log(WLR_ERROR, "Failed to initialize EGL"); @@ -318,6 +321,11 @@ bool wlr_egl_is_current(struct wlr_egl *egl) { bool wlr_egl_swap_buffers(struct wlr_egl *egl, EGLSurface surface, pixman_region32_t *damage) { + // Never block when swapping buffers on Wayland + if (egl->platform == EGL_PLATFORM_WAYLAND_EXT) { + eglSwapInterval(egl->display, 0); + } + EGLBoolean ret; if (damage != NULL && (egl->exts.swap_buffers_with_damage_ext || egl->exts.swap_buffers_with_damage_khr)) { @@ -382,13 +390,21 @@ EGLImageKHR wlr_egl_create_image_from_wl_drm(struct wlr_egl *egl, EGLImageKHR wlr_egl_create_image_from_dmabuf(struct wlr_egl *egl, struct wlr_dmabuf_attributes *attributes) { - if (!egl->exts.image_base_khr) { + if (!egl->exts.image_base_khr || !egl->exts.image_dmabuf_import_ext) { + wlr_log(WLR_ERROR, "dmabuf import extension not present"); return NULL; } bool has_modifier = false; - if (attributes->modifier != DRM_FORMAT_MOD_INVALID) { + + // we assume the same way we assumed formats without the import_modifiers + // extension that mod_linear is supported. The special mod mod_invalid + // is sometimes used to signal modifier unawareness which is what we + // have here + if (attributes->modifier != DRM_FORMAT_MOD_INVALID && + attributes->modifier != DRM_FORMAT_MOD_LINEAR) { if (!egl->exts.image_dmabuf_import_modifiers_ext) { + wlr_log(WLR_ERROR, "dmabuf modifiers extension not present"); return NULL; } has_modifier = true; @@ -460,12 +476,34 @@ EGLImageKHR wlr_egl_create_image_from_dmabuf(struct wlr_egl *egl, int wlr_egl_get_dmabuf_formats(struct wlr_egl *egl, int **formats) { - if (!egl->exts.image_dmabuf_import_ext || - !egl->exts.image_dmabuf_import_modifiers_ext) { - wlr_log(WLR_DEBUG, "dmabuf extension not present"); + if (!egl->exts.image_dmabuf_import_ext) { + wlr_log(WLR_DEBUG, "dmabuf import extension not present"); return -1; } + // when we only have the image_dmabuf_import extension we can't query + // which formats are supported. These two are on almost always + // supported; it's the intended way to just try to create buffers. + // Just a guess but better than not supporting dmabufs at all, + // given that the modifiers extension isn't supported everywhere. + if (!egl->exts.image_dmabuf_import_modifiers_ext) { + static const int fallback_formats[] = { + DRM_FORMAT_ARGB8888, + DRM_FORMAT_XRGB8888, + }; + static unsigned num = sizeof(fallback_formats) / + sizeof(fallback_formats[0]); + + *formats = calloc(num, sizeof(int)); + if (!*formats) { + wlr_log_errno(WLR_ERROR, "Allocation failed"); + return -1; + } + + memcpy(*formats, fallback_formats, num * sizeof(**formats)); + return num; + } + EGLint num; if (!eglQueryDmaBufFormatsEXT(egl->display, 0, NULL, &num)) { wlr_log(WLR_ERROR, "failed to query number of dmabuf formats"); @@ -488,12 +526,16 @@ int wlr_egl_get_dmabuf_formats(struct wlr_egl *egl, int wlr_egl_get_dmabuf_modifiers(struct wlr_egl *egl, int format, uint64_t **modifiers) { - if (!egl->exts.image_dmabuf_import_ext || - !egl->exts.image_dmabuf_import_modifiers_ext) { + if (!egl->exts.image_dmabuf_import_ext) { wlr_log(WLR_DEBUG, "dmabuf extension not present"); return -1; } + if(!egl->exts.image_dmabuf_import_modifiers_ext) { + *modifiers = NULL; + return 0; + } + EGLint num; if (!eglQueryDmaBufModifiersEXT(egl->display, format, 0, NULL, NULL, &num)) { diff --git a/render/gles2/pixel_format.c b/render/gles2/pixel_format.c index 6f42e72e..a4b4c101 100644 --- a/render/gles2/pixel_format.c +++ b/render/gles2/pixel_format.c @@ -3,9 +3,9 @@ #include "render/gles2.h" /* -* 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. -*/ + * 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. + */ static const struct wlr_gles2_pixel_format formats[] = { { .wl_format = WL_SHM_FORMAT_ARGB8888, @@ -60,7 +60,19 @@ const struct wlr_gles2_pixel_format *get_gles2_format_from_wl( return NULL; } -const enum wl_shm_format *get_gles2_formats(size_t *len) { +const struct wlr_gles2_pixel_format *get_gles2_format_from_gl( + GLint gl_format, GLint gl_type, bool alpha) { + for (size_t i = 0; i < sizeof(formats) / sizeof(*formats); ++i) { + if (formats[i].gl_format == gl_format && + formats[i].gl_type == gl_type && + formats[i].has_alpha == alpha) { + return &formats[i]; + } + } + return NULL; +} + +const enum wl_shm_format *get_gles2_wl_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 b6e97041..a5521909 100644 --- a/render/gles2/renderer.c +++ b/render/gles2/renderer.c @@ -135,6 +135,12 @@ static bool gles2_render_texture_with_matrix(struct wlr_renderer *wlr_renderer, case WLR_GLES2_TEXTURE_DMABUF: shader = &renderer->shaders.tex_ext; target = GL_TEXTURE_EXTERNAL_OES; + + if (!renderer->exts.egl_image_external_oes) { + wlr_log(WLR_ERROR, "Failed to render texture: " + "GL_TEXTURE_EXTERNAL_OES not supported"); + return false; + } break; } @@ -207,13 +213,17 @@ static void gles2_render_ellipse_with_matrix(struct wlr_renderer *wlr_renderer, static const enum wl_shm_format *gles2_renderer_formats( struct wlr_renderer *wlr_renderer, size_t *len) { - return get_gles2_formats(len); + return get_gles2_wl_formats(len); +} + +static bool gles2_format_supported(struct wlr_renderer *wlr_renderer, + enum wl_shm_format wl_fmt) { + return get_gles2_format_from_wl(wl_fmt) != NULL; } static bool gles2_resource_is_wl_drm_buffer(struct wlr_renderer *wlr_renderer, struct wl_resource *resource) { - struct wlr_gles2_renderer *renderer = - gles2_get_renderer(wlr_renderer); + struct wlr_gles2_renderer *renderer = gles2_get_renderer(wlr_renderer); if (!eglQueryWaylandBufferWL) { return false; @@ -249,6 +259,33 @@ static int gles2_get_dmabuf_modifiers(struct wlr_renderer *wlr_renderer, return wlr_egl_get_dmabuf_modifiers(renderer->egl, format, modifiers); } +static enum wl_shm_format gles2_preferred_read_format( + struct wlr_renderer *wlr_renderer) { + struct wlr_gles2_renderer *renderer = + gles2_get_renderer_in_context(wlr_renderer); + + GLint gl_format = -1, gl_type = -1; + PUSH_GLES2_DEBUG; + glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_FORMAT, &gl_format); + glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_TYPE, &gl_type); + POP_GLES2_DEBUG; + + EGLint alpha_size = -1; + eglGetConfigAttrib(renderer->egl->display, renderer->egl->config, + EGL_ALPHA_SIZE, &alpha_size); + + const struct wlr_gles2_pixel_format *fmt = + get_gles2_format_from_gl(gl_format, gl_type, alpha_size > 0); + if (fmt != NULL) { + return fmt->wl_format; + } + + if (renderer->exts.read_format_bgra_ext) { + return WL_SHM_FORMAT_XRGB8888; + } + return WL_SHM_FORMAT_XBGR8888; +} + static bool gles2_read_pixels(struct wlr_renderer *wlr_renderer, enum wl_shm_format wl_fmt, uint32_t *flags, uint32_t stride, uint32_t width, uint32_t height, uint32_t src_x, uint32_t src_y, @@ -262,6 +299,12 @@ static bool gles2_read_pixels(struct wlr_renderer *wlr_renderer, return false; } + if (fmt->gl_format == GL_BGRA_EXT && !renderer->exts.read_format_bgra_ext) { + wlr_log(WLR_ERROR, + "Cannot read pixels: missing GL_EXT_read_format_bgra extension"); + return false; + } + PUSH_GLES2_DEBUG; // Make sure any pending drawing is finished before we try to read it @@ -294,11 +337,6 @@ static bool gles2_read_pixels(struct wlr_renderer *wlr_renderer, return glGetError() == GL_NO_ERROR; } -static bool gles2_format_supported(struct wlr_renderer *wlr_renderer, - enum wl_shm_format wl_fmt) { - return get_gles2_format_from_wl(wl_fmt) != NULL; -} - static struct wlr_texture *gles2_texture_from_pixels( struct wlr_renderer *wlr_renderer, enum wl_shm_format wl_fmt, uint32_t stride, uint32_t width, uint32_t height, const void *data) { @@ -342,7 +380,7 @@ static void gles2_destroy(struct wlr_renderer *wlr_renderer) { glDeleteProgram(renderer->shaders.tex_ext.program); POP_GLES2_DEBUG; - if (glDebugMessageCallbackKHR) { + if (renderer->exts.debug_khr) { glDisable(GL_DEBUG_OUTPUT_KHR); glDebugMessageCallbackKHR(NULL, NULL); } @@ -360,12 +398,13 @@ static const struct wlr_renderer_impl renderer_impl = { .render_quad_with_matrix = gles2_render_quad_with_matrix, .render_ellipse_with_matrix = gles2_render_ellipse_with_matrix, .formats = gles2_renderer_formats, + .format_supported = gles2_format_supported, .resource_is_wl_drm_buffer = gles2_resource_is_wl_drm_buffer, .wl_drm_buffer_get_size = gles2_wl_drm_buffer_get_size, .get_dmabuf_formats = gles2_get_dmabuf_formats, .get_dmabuf_modifiers = gles2_get_dmabuf_modifiers, + .preferred_read_format = gles2_preferred_read_format, .read_pixels = gles2_read_pixels, - .format_supported = gles2_format_supported, .texture_from_pixels = gles2_texture_from_pixels, .texture_from_wl_drm = gles2_texture_from_wl_drm, .texture_from_dmabuf = gles2_texture_from_dmabuf, @@ -466,6 +505,24 @@ error: return 0; } +static bool check_gl_ext(const char *exts, const char *ext) { + size_t extlen = strlen(ext); + const char *end = exts + strlen(exts); + + while (exts < end) { + if (exts[0] == ' ') { + exts++; + continue; + } + size_t n = strcspn(exts, " "); + if (n == extlen && strncmp(ext, exts, n) == 0) { + return true; + } + exts += n; + } + return false; +} + extern const GLchar quad_vertex_src[]; extern const GLchar quad_fragment_src[]; extern const GLchar ellipse_fragment_src[]; @@ -487,14 +544,32 @@ struct wlr_renderer *wlr_gles2_renderer_create(struct wlr_egl *egl) { wlr_renderer_init(&renderer->wlr_renderer, &renderer_impl); renderer->egl = egl; - wlr_egl_make_current(renderer->egl, EGL_NO_SURFACE, NULL); + if (!wlr_egl_make_current(renderer->egl, EGL_NO_SURFACE, NULL)) { + free(renderer); + return NULL; + } - renderer->exts_str = (const char*) glGetString(GL_EXTENSIONS); + renderer->exts_str = (const char *)glGetString(GL_EXTENSIONS); wlr_log(WLR_INFO, "Using %s", glGetString(GL_VERSION)); wlr_log(WLR_INFO, "GL vendor: %s", glGetString(GL_VENDOR)); wlr_log(WLR_INFO, "Supported GLES2 extensions: %s", renderer->exts_str); - if (glDebugMessageCallbackKHR && glDebugMessageControlKHR) { + if (!check_gl_ext(renderer->exts_str, "GL_EXT_texture_format_BGRA8888")) { + wlr_log(WLR_ERROR, "BGRA8888 format not supported by GLES2"); + free(renderer); + return NULL; + } + + renderer->exts.read_format_bgra_ext = + check_gl_ext(renderer->exts_str, "GL_EXT_read_format_bgra"); + renderer->exts.debug_khr = + check_gl_ext(renderer->exts_str, "GL_KHR_debug") && + glDebugMessageCallbackKHR && glDebugMessageControlKHR; + renderer->exts.egl_image_external_oes = + check_gl_ext(renderer->exts_str, "GL_OES_EGL_image_external") && + glEGLImageTargetTexture2DOES; + + if (renderer->exts.debug_khr) { glEnable(GL_DEBUG_OUTPUT_KHR); glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS_KHR); glDebugMessageCallbackKHR(gles2_log, NULL); @@ -545,7 +620,7 @@ struct wlr_renderer *wlr_gles2_renderer_create(struct wlr_egl *egl) { renderer->shaders.tex_rgbx.tex = glGetUniformLocation(prog, "tex"); renderer->shaders.tex_rgbx.alpha = glGetUniformLocation(prog, "alpha"); - if (glEGLImageTargetTexture2DOES) { + if (renderer->exts.egl_image_external_oes) { renderer->shaders.tex_ext.program = prog = link_program(tex_vertex_src, tex_fragment_src_external); if (!renderer->shaders.tex_ext.program) { @@ -570,7 +645,7 @@ error: POP_GLES2_DEBUG; - if (glDebugMessageCallbackKHR) { + if (renderer->exts.debug_khr) { glDisable(GL_DEBUG_OUTPUT_KHR); glDebugMessageCallbackKHR(NULL, NULL); } diff --git a/render/gles2/texture.c b/render/gles2/texture.c index 22d02cde..d035841e 100644 --- a/render/gles2/texture.c +++ b/render/gles2/texture.c @@ -44,9 +44,9 @@ static bool gles2_texture_is_opaque(struct wlr_texture *wlr_texture) { } static bool gles2_texture_write_pixels(struct wlr_texture *wlr_texture, - 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, const void *data) { + 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, + const void *data) { struct wlr_gles2_texture *texture = get_gles2_texture_in_context(wlr_texture); @@ -55,11 +55,9 @@ static bool gles2_texture_write_pixels(struct wlr_texture *wlr_texture, return false; } - const struct wlr_gles2_pixel_format *fmt = get_gles2_format_from_wl(wl_fmt); - if (fmt == NULL) { - wlr_log(WLR_ERROR, "Unsupported pixel format %"PRIu32, wl_fmt); - return false; - } + const struct wlr_gles2_pixel_format *fmt = + get_gles2_format_from_wl(texture->wl_format); + assert(fmt); // TODO: what if the unpack subimage extension isn't supported? PUSH_GLES2_DEBUG; @@ -167,6 +165,7 @@ struct wlr_texture *wlr_gles2_texture_from_pixels(struct wlr_egl *egl, texture->height = height; texture->type = WLR_GLES2_TEXTURE_GLTEX; texture->has_alpha = fmt->has_alpha; + texture->wl_format = fmt->wl_format; PUSH_GLES2_DEBUG; @@ -203,6 +202,7 @@ struct wlr_texture *wlr_gles2_texture_from_wl_drm(struct wlr_egl *egl, texture->wl_drm = data; EGLint fmt; + texture->wl_format = 0xFFFFFFFF; // texture can't be written anyways texture->image = wlr_egl_create_image_from_wl_drm(egl, data, &fmt, &texture->width, &texture->height, &texture->inverted_y); if (texture->image == NULL) { @@ -283,6 +283,7 @@ struct wlr_texture *wlr_gles2_texture_from_dmabuf(struct wlr_egl *egl, texture->height = attribs->height; texture->type = WLR_GLES2_TEXTURE_DMABUF; texture->has_alpha = true; + texture->wl_format = 0xFFFFFFFF; // texture can't be written anyways texture->inverted_y = (attribs->flags & WLR_DMABUF_ATTRIBUTES_FLAGS_Y_INVERT) != 0; diff --git a/render/meson.build b/render/meson.build index ab66eab0..e45ea90b 100644 --- a/render/meson.build +++ b/render/meson.build @@ -22,7 +22,13 @@ lib_wlr_render = static_library( ), glapi, include_directories: wlr_inc, - dependencies: [egl, glesv2, pixman, wayland_server], + dependencies: [ + egl, + drm.partial_dependency(compile_args: true), # <drm_fourcc.h> + glesv2, + pixman, + wayland_server + ], ) wlr_render = declare_dependency( diff --git a/render/wlr_renderer.c b/render/wlr_renderer.c index 31bf2b18..10dc6db2 100644 --- a/render/wlr_renderer.c +++ b/render/wlr_renderer.c @@ -139,6 +139,15 @@ int wlr_renderer_get_dmabuf_modifiers(struct wlr_renderer *r, int format, return r->impl->get_dmabuf_modifiers(r, format, modifiers); } +bool wlr_renderer_preferred_read_format(struct wlr_renderer *r, + enum wl_shm_format *fmt) { + if (!r->impl->preferred_read_format || !r->impl->read_pixels) { + return false; + } + *fmt = r->impl->preferred_read_format(r); + return true; +} + bool wlr_renderer_read_pixels(struct wlr_renderer *r, enum wl_shm_format fmt, uint32_t *flags, 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, diff --git a/render/wlr_texture.c b/render/wlr_texture.c index 06872f1e..833032c9 100644 --- a/render/wlr_texture.c +++ b/render/wlr_texture.c @@ -55,10 +55,10 @@ bool wlr_texture_is_opaque(struct wlr_texture *texture) { } bool wlr_texture_write_pixels(struct wlr_texture *texture, - 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, const void *data) { - return texture->impl->write_pixels(texture, wl_fmt, stride, width, height, + 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, + const void *data) { + return texture->impl->write_pixels(texture, stride, width, height, src_x, src_y, dst_x, dst_y, data); } |