diff options
Diffstat (limited to 'render')
-rw-r--r-- | render/egl.c | 172 | ||||
-rw-r--r-- | render/glapi.txt | 5 | ||||
-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 | 234 | ||||
-rw-r--r-- | render/wlr_renderer.c | 6 | ||||
-rw-r--r-- | render/wlr_texture.c | 6 |
8 files changed, 631 insertions, 421 deletions
diff --git a/render/egl.c b/render/egl.c index d60da2ab..e582b6d3 100644 --- a/render/egl.c +++ b/render/egl.c @@ -12,43 +12,6 @@ // https://www.khronos.org/registry/EGL/extensions/KHR/EGL_KHR_image_base.txt. // https://cgit.freedesktop.org/mesa/mesa/tree/docs/specs/WL_bind_wayland_display.spec -const char *egl_error(void) { - switch (eglGetError()) { - case EGL_SUCCESS: - return "Success"; - case EGL_NOT_INITIALIZED: - return "Not initialized"; - case EGL_BAD_ACCESS: - return "Bad access"; - case EGL_BAD_ALLOC: - return "Bad alloc"; - case EGL_BAD_ATTRIBUTE: - return "Bad attribute"; - case EGL_BAD_CONTEXT: - return "Bad Context"; - case EGL_BAD_CONFIG: - return "Bad Config"; - case EGL_BAD_CURRENT_SURFACE: - return "Bad current surface"; - case EGL_BAD_DISPLAY: - return "Bad display"; - case EGL_BAD_SURFACE: - return "Bad surface"; - case EGL_BAD_MATCH: - return "Bad match"; - case EGL_BAD_PARAMETER: - return "Bad parameter"; - case EGL_BAD_NATIVE_PIXMAP: - return "Bad native pixmap"; - case EGL_BAD_NATIVE_WINDOW: - return "Bad native window"; - case EGL_CONTEXT_LOST: - return "Context lost"; - default: - return "Unknown"; - } -} - static bool egl_get_config(EGLDisplay disp, EGLint *attribs, EGLConfig *out, EGLint visual_id) { EGLint count = 0, matched = 0, ret; @@ -84,6 +47,21 @@ static bool egl_get_config(EGLDisplay disp, EGLint *attribs, EGLConfig *out, return false; } +static log_importance_t egl_log_importance_to_wlr(EGLint type) { + switch (type) { + case EGL_DEBUG_MSG_CRITICAL_KHR: return L_ERROR; + case EGL_DEBUG_MSG_ERROR_KHR: return L_ERROR; + case EGL_DEBUG_MSG_WARN_KHR: return L_ERROR; + case EGL_DEBUG_MSG_INFO_KHR: return L_INFO; + default: return L_INFO; + } +} + +static void egl_log(EGLenum error, const char *command, EGLint msg_type, + EGLLabelKHR thread, EGLLabelKHR obj, const char *msg) { + _wlr_log(egl_log_importance_to_wlr(msg_type), "[EGL] %s: %s", command, msg); +} + static bool check_egl_ext(const char *egl_exts, const char *ext) { size_t extlen = strlen(ext); const char *end = egl_exts + strlen(egl_exts); @@ -128,8 +106,19 @@ bool wlr_egl_init(struct wlr_egl *egl, EGLenum platform, void *remote_display, return false; } + if (eglDebugMessageControlKHR) { + static const EGLAttrib debug_attribs[] = { + EGL_DEBUG_MSG_CRITICAL_KHR, EGL_TRUE, + EGL_DEBUG_MSG_ERROR_KHR, EGL_TRUE, + EGL_DEBUG_MSG_WARN_KHR, EGL_TRUE, + EGL_DEBUG_MSG_INFO_KHR, EGL_TRUE, + EGL_NONE, + }; + eglDebugMessageControlKHR(egl_log, debug_attribs); + } + if (eglBindAPI(EGL_OPENGL_ES_API) == EGL_FALSE) { - wlr_log(L_ERROR, "Failed to bind to the OpenGL ES API: %s", egl_error()); + wlr_log(L_ERROR, "Failed to bind to the OpenGL ES API"); goto error; } @@ -140,13 +129,13 @@ bool wlr_egl_init(struct wlr_egl *egl, EGLenum platform, void *remote_display, egl->display = eglGetPlatformDisplayEXT(platform, remote_display, NULL); } if (egl->display == EGL_NO_DISPLAY) { - wlr_log(L_ERROR, "Failed to create EGL display: %s", egl_error()); + wlr_log(L_ERROR, "Failed to create EGL display"); goto error; } EGLint major, minor; if (eglInitialize(egl->display, &major, &minor) == EGL_FALSE) { - wlr_log(L_ERROR, "Failed to initialize EGL: %s", egl_error()); + wlr_log(L_ERROR, "Failed to initialize EGL"); goto error; } @@ -161,7 +150,7 @@ bool wlr_egl_init(struct wlr_egl *egl, EGLenum platform, void *remote_display, EGL_NO_CONTEXT, attribs); if (egl->context == EGL_NO_CONTEXT) { - wlr_log(L_ERROR, "Failed to create EGL context: %s", egl_error()); + wlr_log(L_ERROR, "Failed to create EGL context"); goto error; } @@ -199,12 +188,18 @@ bool wlr_egl_init(struct wlr_egl *egl, EGLenum platform, void *remote_display, error: eglMakeCurrent(EGL_NO_DISPLAY, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); - eglTerminate(egl->display); + if (egl->display) { + eglTerminate(egl->display); + } eglReleaseThread(); return false; } void wlr_egl_finish(struct wlr_egl *egl) { + if (egl == NULL) { + return; + } + eglMakeCurrent(EGL_NO_DISPLAY, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); if (egl->wl_display && eglUnbindWaylandDisplayWL) { eglUnbindWaylandDisplayWL(egl->display, egl->wl_display); @@ -259,7 +254,7 @@ EGLSurface wlr_egl_create_surface(struct wlr_egl *egl, void *window) { EGLSurface surf = eglCreatePlatformWindowSurfaceEXT(egl->display, egl->config, window, NULL); if (surf == EGL_NO_SURFACE) { - wlr_log(L_ERROR, "Failed to create EGL surface: %s", egl_error()); + wlr_log(L_ERROR, "Failed to create EGL surface"); return EGL_NO_SURFACE; } return surf; @@ -274,7 +269,7 @@ int wlr_egl_get_buffer_age(struct wlr_egl *egl, EGLSurface surface) { EGLBoolean ok = eglQuerySurface(egl->display, surface, EGL_BUFFER_AGE_EXT, &buffer_age); if (!ok) { - wlr_log(L_ERROR, "Failed to get EGL surface buffer age: %s", egl_error()); + wlr_log(L_ERROR, "Failed to get EGL surface buffer age"); return -1; } @@ -284,7 +279,7 @@ int wlr_egl_get_buffer_age(struct wlr_egl *egl, EGLSurface surface) { bool wlr_egl_make_current(struct wlr_egl *egl, EGLSurface surface, int *buffer_age) { if (!eglMakeCurrent(egl->display, surface, surface, egl->context)) { - wlr_log(L_ERROR, "eglMakeCurrent failed: %s", egl_error()); + wlr_log(L_ERROR, "eglMakeCurrent failed"); return false; } @@ -322,7 +317,7 @@ bool wlr_egl_swap_buffers(struct wlr_egl *egl, EGLSurface surface, } if (!ret) { - wlr_log(L_ERROR, "eglSwapBuffers failed: %s", egl_error()); + wlr_log(L_ERROR, "eglSwapBuffers failed"); return false; } return true; @@ -330,15 +325,6 @@ bool wlr_egl_swap_buffers(struct wlr_egl *egl, EGLSurface surface, EGLImage wlr_egl_create_image_from_dmabuf(struct wlr_egl *egl, struct wlr_dmabuf_buffer_attribs *attributes) { - int atti = 0; - EGLint attribs[20]; - attribs[atti++] = EGL_WIDTH; - attribs[atti++] = attributes->width; - attribs[atti++] = EGL_HEIGHT; - attribs[atti++] = attributes->height; - attribs[atti++] = EGL_LINUX_DRM_FOURCC_EXT; - attribs[atti++] = attributes->format; - bool has_modifier = false; if (attributes->modifier[0] != DRM_FORMAT_MOD_INVALID) { if (!egl->egl_exts.dmabuf_import_modifiers) { @@ -347,25 +333,66 @@ EGLImage wlr_egl_create_image_from_dmabuf(struct wlr_egl *egl, has_modifier = true; } - /* TODO: YUV planes have up four planes but we only support a - single EGLImage for now */ - if (attributes->n_planes > 1) { - return NULL; - } + unsigned int atti = 0; + EGLint attribs[50]; + attribs[atti++] = EGL_WIDTH; + attribs[atti++] = attributes->width; + attribs[atti++] = EGL_HEIGHT; + attribs[atti++] = attributes->height; + attribs[atti++] = EGL_LINUX_DRM_FOURCC_EXT; + attribs[atti++] = attributes->format; - attribs[atti++] = EGL_DMA_BUF_PLANE0_FD_EXT; - attribs[atti++] = attributes->fd[0]; - attribs[atti++] = EGL_DMA_BUF_PLANE0_OFFSET_EXT; - attribs[atti++] = attributes->offset[0]; - attribs[atti++] = EGL_DMA_BUF_PLANE0_PITCH_EXT; - attribs[atti++] = attributes->stride[0]; - if (has_modifier) { - attribs[atti++] = EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT; - attribs[atti++] = attributes->modifier[0] & 0xFFFFFFFF; - attribs[atti++] = EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT; - attribs[atti++] = attributes->modifier[0] >> 32; + struct { + EGLint fd; + EGLint offset; + EGLint pitch; + EGLint mod_lo; + EGLint mod_hi; + } attr_names[WLR_LINUX_DMABUF_MAX_PLANES] = { + { + EGL_DMA_BUF_PLANE0_FD_EXT, + EGL_DMA_BUF_PLANE0_OFFSET_EXT, + EGL_DMA_BUF_PLANE0_PITCH_EXT, + EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT, + EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT + }, { + EGL_DMA_BUF_PLANE1_FD_EXT, + EGL_DMA_BUF_PLANE1_OFFSET_EXT, + EGL_DMA_BUF_PLANE1_PITCH_EXT, + EGL_DMA_BUF_PLANE1_MODIFIER_LO_EXT, + EGL_DMA_BUF_PLANE1_MODIFIER_HI_EXT + }, { + EGL_DMA_BUF_PLANE2_FD_EXT, + EGL_DMA_BUF_PLANE2_OFFSET_EXT, + EGL_DMA_BUF_PLANE2_PITCH_EXT, + EGL_DMA_BUF_PLANE2_MODIFIER_LO_EXT, + EGL_DMA_BUF_PLANE2_MODIFIER_HI_EXT + }, { + EGL_DMA_BUF_PLANE3_FD_EXT, + EGL_DMA_BUF_PLANE3_OFFSET_EXT, + EGL_DMA_BUF_PLANE3_PITCH_EXT, + EGL_DMA_BUF_PLANE3_MODIFIER_LO_EXT, + EGL_DMA_BUF_PLANE3_MODIFIER_HI_EXT + } + }; + + for (int i=0; i < attributes->n_planes; i++) { + attribs[atti++] = attr_names[i].fd; + attribs[atti++] = attributes->fd[i]; + attribs[atti++] = attr_names[i].offset; + attribs[atti++] = attributes->offset[i]; + attribs[atti++] = attr_names[i].pitch; + attribs[atti++] = attributes->stride[i]; + if (has_modifier) { + attribs[atti++] = attr_names[i].mod_lo; + attribs[atti++] = attributes->modifier[i] & 0xFFFFFFFF; + attribs[atti++] = attr_names[i].mod_hi; + attribs[atti++] = attributes->modifier[i] >> 32; + } } attribs[atti++] = EGL_NONE; + assert(atti < sizeof(attribs)/sizeof(attribs[0])); + return eglCreateImageKHR(egl->display, EGL_NO_CONTEXT, EGL_LINUX_DMA_BUF_EXT, NULL, attribs); } @@ -376,7 +403,8 @@ EGLImage wlr_egl_create_image_from_dmabuf(struct wlr_egl *egl, bool wlr_egl_check_import_dmabuf(struct wlr_egl *egl, struct wlr_dmabuf_buffer *dmabuf) { switch (dmabuf->attributes.format & ~DRM_FORMAT_BIG_ENDIAN) { - /* YUV based formats not yet supported */ + /* TODO: YUV based formats not yet supported, require multiple + * wlr_create_image_from_dmabuf */ case WL_SHM_FORMAT_YUYV: case WL_SHM_FORMAT_YVYU: case WL_SHM_FORMAT_UYVY: diff --git a/render/glapi.txt b/render/glapi.txt index 02ac7dd8..a8e4aaba 100644 --- a/render/glapi.txt +++ b/render/glapi.txt @@ -10,3 +10,8 @@ eglCreatePlatformWindowSurfaceEXT -eglSwapBuffersWithDamageKHR -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 99f153b8..46193c78 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) { @@ -198,22 +218,24 @@ static bool gles2_texture_upload_drm(struct wlr_texture *_tex, tex->image = wlr_egl_create_image(tex->egl, EGL_WAYLAND_BUFFER_WL, (EGLClientBuffer*) buf, attribs); if (!tex->image) { - wlr_log(L_ERROR, "failed to create egl image: %s", egl_error()); + wlr_log(L_ERROR, "failed to create EGL image"); 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,25 @@ 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)); + GLenum target; + const struct gles2_pixel_format *pf; + if (dmabuf->attributes.n_planes > 1) { + target = GL_TEXTURE_EXTERNAL_OES; + pf = &external_pixel_format; + } else { + target = GL_TEXTURE_2D; + 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 +302,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 +319,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 +334,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 +352,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 +361,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 +369,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, |