diff options
Diffstat (limited to 'render')
-rw-r--r-- | render/egl.c | 277 | ||||
-rw-r--r-- | render/glapi.txt | 7 | ||||
-rw-r--r-- | render/gles2/pixel_format.c | 25 | ||||
-rw-r--r-- | render/gles2/renderer.c | 479 | ||||
-rw-r--r-- | render/gles2/shaders.c | 162 | ||||
-rw-r--r-- | render/gles2/texture.c | 278 | ||||
-rw-r--r-- | render/matrix.c | 210 | ||||
-rw-r--r-- | render/meson.build | 1 | ||||
-rw-r--r-- | render/wlr_renderer.c | 61 | ||||
-rw-r--r-- | render/wlr_texture.c | 13 |
10 files changed, 877 insertions, 636 deletions
diff --git a/render/egl.c b/render/egl.c index 0a68d6e5..e582b6d3 100644 --- a/render/egl.c +++ b/render/egl.c @@ -1,4 +1,5 @@ #include <assert.h> +#include <stdio.h> #include <EGL/egl.h> #include <EGL/eglext.h> #include <GLES2/gl2.h> @@ -11,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; @@ -83,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); @@ -101,14 +80,45 @@ static bool check_egl_ext(const char *egl_exts, const char *ext) { return false; } +static void print_dmabuf_formats(struct wlr_egl *egl) { + /* Avoid log msg if extension is not present */ + if (!egl->egl_exts.dmabuf_import_modifiers) { + return; + } + + int *formats; + int num = wlr_egl_get_dmabuf_formats(egl, &formats); + if (num < 0) { + return; + } + + char str_formats[num * 5 + 1]; + for (int i = 0; i < num; i++) { + snprintf(&str_formats[i*5], (num - i) * 5 + 1, "%.4s ", (char*)&formats[i]); + } + wlr_log(L_INFO, "Supported dmabuf buffer formats: %s", str_formats); + free(formats); +} + bool wlr_egl_init(struct wlr_egl *egl, EGLenum platform, void *remote_display, EGLint *config_attribs, EGLint visual_id) { if (!load_glapi()) { 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; } @@ -119,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; } @@ -140,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; } @@ -167,16 +177,29 @@ bool wlr_egl_init(struct wlr_egl *egl, EGLenum platform, void *remote_display, check_egl_ext(egl->egl_exts_str, "EGL_EXT_swap_buffers_with_damage") || check_egl_ext(egl->egl_exts_str, "EGL_KHR_swap_buffers_with_damage"); + egl->egl_exts.dmabuf_import = + check_egl_ext(egl->egl_exts_str, "EGL_EXT_image_dma_buf_import"); + egl->egl_exts.dmabuf_import_modifiers = + check_egl_ext(egl->egl_exts_str, "EGL_EXT_image_dma_buf_import_modifiers") + && eglQueryDmaBufFormatsEXT && eglQueryDmaBufModifiersEXT; + print_dmabuf_formats(egl); + return true; 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); @@ -231,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; @@ -246,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; } @@ -256,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; } @@ -294,8 +317,170 @@ 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; } + +EGLImage wlr_egl_create_image_from_dmabuf(struct wlr_egl *egl, + struct wlr_dmabuf_buffer_attribs *attributes) { + bool has_modifier = false; + if (attributes->modifier[0] != DRM_FORMAT_MOD_INVALID) { + if (!egl->egl_exts.dmabuf_import_modifiers) { + return NULL; + } + has_modifier = true; + } + + 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; + + 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); +} + +#ifndef DRM_FORMAT_BIG_ENDIAN +# define DRM_FORMAT_BIG_ENDIAN 0x80000000 +#endif +bool wlr_egl_check_import_dmabuf(struct wlr_egl *egl, + struct wlr_dmabuf_buffer *dmabuf) { + switch (dmabuf->attributes.format & ~DRM_FORMAT_BIG_ENDIAN) { + /* 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: + case WL_SHM_FORMAT_VYUY: + case WL_SHM_FORMAT_AYUV: + return false; + default: + break; + } + + EGLImage egl_image = wlr_egl_create_image_from_dmabuf(egl, + &dmabuf->attributes); + if (egl_image) { + /* We can import the image, good. No need to keep it + since wlr_texture_upload_dmabuf will import it again */ + wlr_egl_destroy_image(egl, egl_image); + return true; + } + /* TODO: import yuv dmabufs */ + return false; +} + +int wlr_egl_get_dmabuf_formats(struct wlr_egl *egl, + int **formats) { + if (!egl->egl_exts.dmabuf_import || + !egl->egl_exts.dmabuf_import_modifiers) { + wlr_log(L_ERROR, "dmabuf extension not present"); + return -1; + } + + EGLint num; + if (!eglQueryDmaBufFormatsEXT(egl->display, 0, NULL, &num)) { + wlr_log(L_ERROR, "failed to query number of dmabuf formats"); + return -1; + } + + *formats = calloc(num, sizeof(int)); + if (*formats == NULL) { + wlr_log(L_ERROR, "Allocation failed: %s", strerror(errno)); + return -1; + } + + if (!eglQueryDmaBufFormatsEXT(egl->display, num, *formats, &num)) { + wlr_log(L_ERROR, "failed to query dmabuf format"); + free(*formats); + return -1; + } + return num; +} + +int wlr_egl_get_dmabuf_modifiers(struct wlr_egl *egl, + int format, uint64_t **modifiers) { + if (!egl->egl_exts.dmabuf_import || + !egl->egl_exts.dmabuf_import_modifiers) { + wlr_log(L_ERROR, "dmabuf extension not present"); + return -1; + } + + EGLint num; + if (!eglQueryDmaBufModifiersEXT(egl->display, format, 0, + NULL, NULL, &num)) { + wlr_log(L_ERROR, "failed to query dmabuf number of modifiers"); + return -1; + } + + *modifiers = calloc(num, sizeof(uint64_t)); + if (*modifiers == NULL) { + wlr_log(L_ERROR, "Allocation failed: %s", strerror(errno)); + return -1; + } + + if (!eglQueryDmaBufModifiersEXT(egl->display, format, num, + *modifiers, NULL, &num)) { + wlr_log(L_ERROR, "failed to query dmabuf modifiers"); + free(*modifiers); + return -1; + } + return num; +} diff --git a/render/glapi.txt b/render/glapi.txt index 0b0b452c..a8e4aaba 100644 --- a/render/glapi.txt +++ b/render/glapi.txt @@ -8,3 +8,10 @@ eglCreatePlatformWindowSurfaceEXT -glEGLImageTargetTexture2DOES -eglSwapBuffersWithDamageEXT -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 ad739cf8..61665a07 100644 --- a/render/gles2/renderer.c +++ b/render/gles2/renderer.c @@ -2,143 +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.h> #include <wlr/render/egl.h> #include <wlr/render/interface.h> -#include <wlr/render/matrix.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(quad_vertex_src, fragment_src_external, &shaders.external)) { - goto error; - } - } +static void gles2_begin(struct wlr_renderer *wlr_renderer, uint32_t width, + uint32_t height) { + gles2_get_renderer(wlr_renderer); - wlr_log(L_DEBUG, "Compiled default shaders"); - shaders.initialized = true; - return; -error: - wlr_log(L_ERROR, "Failed to set up default shaders!"); -} - -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, - const float (*color)[4]) { - glClearColor((*color)[0], (*color)[1], (*color)[2], (*color)[3]); +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); @@ -158,80 +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(struct wlr_renderer *wlr_renderer, - struct wlr_texture *texture, const float (*matrix)[16], float alpha) { - if (!texture || !texture->valid) { +static bool gles2_render_texture_with_matrix( + struct wlr_renderer *wlr_renderer, struct wlr_texture *wlr_texture, + const float matrix[static 9], float alpha) { + 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; } - wlr_texture_bind(texture); - GL_CALL(glUniformMatrix4fv(0, 1, GL_FALSE, *matrix)); - GL_CALL(glUniform1f(2, alpha)); + 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); + + 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, - const float (*color)[4], const float (*matrix)[16]) { - GL_CALL(glUseProgram(shaders.quad)); - GL_CALL(glUniformMatrix4fv(0, 1, GL_FALSE, *matrix)); - GL_CALL(glUniform4f(1, (*color)[0], (*color)[1], (*color)[2], (*color)[3])); +static void gles2_render_quad_with_matrix(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); + + 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, - const float (*color)[4], const float (*matrix)[16]) { - GL_CALL(glUseProgram(shaders.ellipse)); - GL_CALL(glUniformMatrix4fv(0, 1, GL_TRUE, *matrix)); - GL_CALL(glUniform4f(1, (*color)[0], (*color)[1], (*color)[2], (*color)[3])); +static void gles2_render_ellipse_with_matrix(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); + + 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(); @@ -243,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_with_matrix = wlr_gles2_render_texture, - .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_with_matrix = gles2_render_quad_with_matrix, + .render_ellipse_with_matrix = gles2_render_ellipse_with_matrix, + .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 46a10248..ba3bd971 100644 --- a/render/gles2/shaders.c +++ b/render/gles2/shaders.c @@ -3,100 +3,88 @@ // Colored quads const GLchar quad_vertex_src[] = -"uniform mat4 proj;" -"uniform vec4 color;" -"attribute vec2 pos;" -"attribute vec2 texcoord;" -"varying vec4 v_color;" -"varying vec2 v_texcoord;" -"mat4 transpose(in mat4 inMatrix) {" -" vec4 i0 = inMatrix[0];" -" vec4 i1 = inMatrix[1];" -" vec4 i2 = inMatrix[2];" -" vec4 i3 = inMatrix[3];" -" mat4 outMatrix = mat4(" -" vec4(i0.x, i1.x, i2.x, i3.x)," -" vec4(i0.y, i1.y, i2.y, i3.y)," -" vec4(i0.z, i1.z, i2.z, i3.z)," -" vec4(i0.w, i1.w, i2.w, i3.w)" -" );" -" return outMatrix;" -"}" -"void main() {" -" gl_Position = transpose(proj) * vec4(pos, 0.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 mat4 proj;" -"attribute vec2 pos;" -"attribute vec2 texcoord;" -"varying vec2 v_texcoord;" -"mat4 transpose(in mat4 inMatrix) {" -" vec4 i0 = inMatrix[0];" -" vec4 i1 = inMatrix[1];" -" vec4 i2 = inMatrix[2];" -" vec4 i3 = inMatrix[3];" -" mat4 outMatrix = mat4(" -" vec4(i0.x, i1.x, i2.x, i3.x)," -" vec4(i0.y, i1.y, i2.y, i3.y)," -" vec4(i0.z, i1.z, i2.z, i3.z)," -" vec4(i0.w, i1.w, i2.w, i3.w)" -" );" -"" -" return outMatrix;" -"}" -"void main() {" -" gl_Position = transpose(proj) * vec4(pos, 0.0, 1.0);" -" 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;" -"void main() {" -" vec4 col = texture2D(texture0, v_texcoord);" -" gl_FragColor = vec4(col.rgb, col.a);" -"}"; +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 241b94a8..46193c78 100644 --- a/render/gles2/texture.c +++ b/render/gles2/texture.c @@ -5,39 +5,47 @@ #include <stdlib.h> #include <wayland-server-protocol.h> #include <wayland-util.h> -#include <wlr/render.h> +#include <wlr/render/wlr_texture.h> #include <wlr/render/egl.h> #include <wlr/render/interface.h> -#include <wlr/render/matrix.h> +#include <wlr/types/wlr_matrix.h> #include <wlr/util/log.h> #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; } - GL_CALL(glGenTextures(1, &texture->tex_id)); - GL_CALL(glBindTexture(GL_TEXTURE_2D, texture->tex_id)); - GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)); - GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)); + texture->target = target; + 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; @@ -47,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_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); @@ -100,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_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); @@ -125,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; } @@ -158,20 +177,23 @@ 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; - wlr_egl_query_buffer(tex->egl, buf, EGL_WAYLAND_Y_INVERTED_WL, &inverted_y); + if (wlr_egl_query_buffer(tex->egl, buf, EGL_WAYLAND_Y_INVERTED_WL, + &inverted_y)) { + tex->wlr_texture.inverted_y = !!inverted_y; + } 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; @@ -182,8 +204,10 @@ static bool gles2_texture_upload_drm(struct wlr_texture *_tex, return false; } - gles2_texture_ensure_texture(tex); - 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 }; @@ -194,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; @@ -217,30 +243,74 @@ 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_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 void gles2_texture_get_matrix(struct wlr_texture *_texture, - float (*matrix)[16], const float (*projection)[16], int x, int y) { - struct wlr_gles2_texture *texture = (struct wlr_gles2_texture *)_texture; - float world[16]; - wlr_matrix_identity(matrix); - wlr_matrix_translate(&world, x, y, 0); - wlr_matrix_mul(matrix, &world, matrix); - wlr_matrix_scale(&world, - texture->wlr_texture.width, texture->wlr_texture.height, 1); - wlr_matrix_mul(matrix, &world, matrix); - wlr_matrix_mul(projection, matrix, matrix); +static bool gles2_texture_upload_dmabuf(struct wlr_texture *wlr_texture, + struct wl_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"); + return false; + } + + tex->wlr_texture.width = dmabuf->attributes.width; + tex->wlr_texture.height = dmabuf->attributes.height; + + if (tex->image) { + wlr_egl_destroy_image(tex->egl, tex->image); + } + + if (wlr_dmabuf_buffer_has_inverted_y(dmabuf)) { + wlr_texture->inverted_y = true; + } + + 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); + glActiveTexture(GL_TEXTURE0); + glEGLImageTargetTexture2DOES(target, tex->image); + GLES2_DEBUG_POP; + tex->pixel_format = pf; + tex->wlr_texture.valid = true; + return true; } -static void gles2_texture_get_buffer_size(struct wlr_texture *texture, struct +static bool gles2_texture_get_dmabuf_size(struct wlr_texture *texture, struct wl_resource *resource, int *width, int *height) { + if (!wlr_dmabuf_resource_is_buffer(resource)) { + return false; + } + + 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) { struct wl_shm_buffer *buffer = wl_shm_buffer_get(resource); if (!buffer) { struct wlr_gles2_texture *tex = (struct wlr_gles2_texture *)texture; @@ -249,12 +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)) { - wlr_log(L_ERROR, "could not get size of the buffer " - "(no buffer found)"); - return; - }; - wlr_egl_query_buffer(tex->egl, resource, EGL_HEIGHT, - (EGLint*)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); return; } @@ -263,19 +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(GL_TEXTURE_2D, texture->tex_id)); - GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)); - GL_CALL(glTexParameteri(GL_TEXTURE_2D, 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) { @@ -285,16 +352,15 @@ 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, .update_shm = gles2_texture_update_shm, .upload_drm = gles2_texture_upload_drm, + .upload_dmabuf = gles2_texture_upload_dmabuf, .upload_eglimage = gles2_texture_upload_eglimage, - .get_matrix = gles2_texture_get_matrix, .get_buffer_size = gles2_texture_get_buffer_size, - .bind = gles2_texture_bind, .destroy = gles2_texture_destroy, }; @@ -303,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/matrix.c b/render/matrix.c deleted file mode 100644 index d5d7f49d..00000000 --- a/render/matrix.c +++ /dev/null @@ -1,210 +0,0 @@ -#include <math.h> -#include <string.h> -#include <wayland-server-protocol.h> -#include <wlr/render/matrix.h> -#include <wlr/types/wlr_box.h> -#include <wlr/types/wlr_output.h> - -/* Obtains the index for the given row/column */ -static inline int mind(int row, int col) { - return (row - 1) * 4 + col - 1; -} - -void wlr_matrix_identity(float (*output)[16]) { - static const float identity[16] = { - 1.0f, 0.0f, 0.0f, 0.0f, - 0.0f, 1.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 1.0f, 0.0f, - 0.0f, 0.0f, 0.0f, 1.0f - }; - memcpy(*output, identity, sizeof(identity)); -} - -void wlr_matrix_translate(float (*output)[16], float x, float y, float z) { - wlr_matrix_identity(output); - (*output)[mind(1, 4)] = x; - (*output)[mind(2, 4)] = y; - (*output)[mind(3, 4)] = z; -} - -void wlr_matrix_scale(float (*output)[16], float x, float y, float z) { - wlr_matrix_identity(output); - (*output)[mind(1, 1)] = x; - (*output)[mind(2, 2)] = y; - (*output)[mind(3, 3)] = z; -} - -void wlr_matrix_rotate(float (*output)[16], float radians) { - wlr_matrix_identity(output); - float _cos = cosf(radians); - float _sin = sinf(radians); - (*output)[mind(1, 1)] = _cos; - (*output)[mind(1, 2)] = _sin; - (*output)[mind(2, 1)] = -_sin; - (*output)[mind(2, 2)] = _cos; -} - -void wlr_matrix_mul(const float (*x)[16], const float (*y)[16], float (*product)[16]) { - float _product[16] = { - (*x)[mind(1, 1)] * (*y)[mind(1, 1)] + (*x)[mind(1, 2)] * (*y)[mind(2, 1)] + - (*x)[mind(1, 3)] * (*y)[mind(3, 1)] + (*x)[mind(1, 4)] * (*y)[mind(4, 1)], - (*x)[mind(1, 1)] * (*y)[mind(1, 2)] + (*x)[mind(1, 2)] * (*y)[mind(2, 2)] + - (*x)[mind(1, 3)] * (*y)[mind(3, 2)] + (*x)[mind(1, 4)] * (*y)[mind(4, 2)], - (*x)[mind(1, 1)] * (*y)[mind(1, 3)] + (*x)[mind(1, 2)] * (*y)[mind(2, 3)] + - (*x)[mind(1, 3)] * (*y)[mind(3, 3)] + (*x)[mind(1, 4)] * (*y)[mind(4, 3)], - (*x)[mind(1, 1)] * (*y)[mind(1, 4)] + (*x)[mind(1, 2)] * (*y)[mind(2, 4)] + - (*x)[mind(1, 4)] * (*y)[mind(3, 4)] + (*x)[mind(1, 4)] * (*y)[mind(4, 4)], - - (*x)[mind(2, 1)] * (*y)[mind(1, 1)] + (*x)[mind(2, 2)] * (*y)[mind(2, 1)] + - (*x)[mind(2, 3)] * (*y)[mind(3, 1)] + (*x)[mind(2, 4)] * (*y)[mind(4, 1)], - (*x)[mind(2, 1)] * (*y)[mind(1, 2)] + (*x)[mind(2, 2)] * (*y)[mind(2, 2)] + - (*x)[mind(2, 3)] * (*y)[mind(3, 2)] + (*x)[mind(2, 4)] * (*y)[mind(4, 2)], - (*x)[mind(2, 1)] * (*y)[mind(1, 3)] + (*x)[mind(2, 2)] * (*y)[mind(2, 3)] + - (*x)[mind(2, 3)] * (*y)[mind(3, 3)] + (*x)[mind(2, 4)] * (*y)[mind(4, 3)], - (*x)[mind(2, 1)] * (*y)[mind(1, 4)] + (*x)[mind(2, 2)] * (*y)[mind(2, 4)] + - (*x)[mind(2, 4)] * (*y)[mind(3, 4)] + (*x)[mind(2, 4)] * (*y)[mind(4, 4)], - - (*x)[mind(3, 1)] * (*y)[mind(1, 1)] + (*x)[mind(3, 2)] * (*y)[mind(2, 1)] + - (*x)[mind(3, 3)] * (*y)[mind(3, 1)] + (*x)[mind(3, 4)] * (*y)[mind(4, 1)], - (*x)[mind(3, 1)] * (*y)[mind(1, 2)] + (*x)[mind(3, 2)] * (*y)[mind(2, 2)] + - (*x)[mind(3, 3)] * (*y)[mind(3, 2)] + (*x)[mind(3, 4)] * (*y)[mind(4, 2)], - (*x)[mind(3, 1)] * (*y)[mind(1, 3)] + (*x)[mind(3, 2)] * (*y)[mind(2, 3)] + - (*x)[mind(3, 3)] * (*y)[mind(3, 3)] + (*x)[mind(3, 4)] * (*y)[mind(4, 3)], - (*x)[mind(3, 1)] * (*y)[mind(1, 4)] + (*x)[mind(3, 2)] * (*y)[mind(2, 4)] + - (*x)[mind(3, 4)] * (*y)[mind(3, 4)] + (*x)[mind(3, 4)] * (*y)[mind(4, 4)], - - (*x)[mind(4, 1)] * (*y)[mind(1, 1)] + (*x)[mind(4, 2)] * (*y)[mind(2, 1)] + - (*x)[mind(4, 3)] * (*y)[mind(3, 1)] + (*x)[mind(4, 4)] * (*y)[mind(4, 1)], - (*x)[mind(4, 1)] * (*y)[mind(1, 2)] + (*x)[mind(4, 2)] * (*y)[mind(2, 2)] + - (*x)[mind(4, 3)] * (*y)[mind(3, 2)] + (*x)[mind(4, 4)] * (*y)[mind(4, 2)], - (*x)[mind(4, 1)] * (*y)[mind(1, 3)] + (*x)[mind(4, 2)] * (*y)[mind(2, 3)] + - (*x)[mind(4, 3)] * (*y)[mind(3, 3)] + (*x)[mind(4, 4)] * (*y)[mind(4, 3)], - (*x)[mind(4, 1)] * (*y)[mind(1, 4)] + (*x)[mind(4, 2)] * (*y)[mind(2, 4)] + - (*x)[mind(4, 4)] * (*y)[mind(3, 4)] + (*x)[mind(4, 4)] * (*y)[mind(4, 4)], - }; - memcpy(*product, _product, sizeof(_product)); -} - -static const float transforms[][4] = { - [WL_OUTPUT_TRANSFORM_NORMAL] = { - 1.0f, 0.0f, - 0.0f, 1.0f, - }, - [WL_OUTPUT_TRANSFORM_90] = { - 0.0f, -1.0f, - 1.0f, 0.0f, - }, - [WL_OUTPUT_TRANSFORM_180] = { - -1.0f, 0.0f, - 0.0f, -1.0f, - }, - [WL_OUTPUT_TRANSFORM_270] = { - 0.0f, 1.0f, - -1.0f, 0.0f, - }, - [WL_OUTPUT_TRANSFORM_FLIPPED] = { - -1.0f, 0.0f, - 0.0f, 1.0f, - }, - [WL_OUTPUT_TRANSFORM_FLIPPED_90] = { - 0.0f, -1.0f, - -1.0f, 0.0f, - }, - [WL_OUTPUT_TRANSFORM_FLIPPED_180] = { - 1.0f, 0.0f, - 0.0f, -1.0f, - }, - [WL_OUTPUT_TRANSFORM_FLIPPED_270] = { - 0.0f, 1.0f, - 1.0f, 0.0f, - }, -}; - -void wlr_matrix_transform(float mat[static 16], - enum wl_output_transform transform) { - memset(mat, 0, sizeof(*mat) * 16); - - const float *t = transforms[transform]; - - // Rotation + reflection - mat[0] = t[0]; - mat[1] = t[1]; - mat[4] = t[2]; - mat[5] = t[3]; - - // Identity - mat[10] = 1.0f; - mat[15] = 1.0f; -} - -// Equivilent to glOrtho(0, width, 0, height, 1, -1) with the transform applied -void wlr_matrix_texture(float mat[static 16], int32_t width, int32_t height, - enum wl_output_transform transform) { - memset(mat, 0, sizeof(*mat) * 16); - - const float *t = transforms[transform]; - float x = 2.0f / width; - float y = 2.0f / height; - - // Rotation + reflection - mat[0] = x * t[0]; - mat[1] = x * t[1]; - mat[4] = y * -t[2]; - mat[5] = y * -t[3]; - - // Translation - mat[3] = -copysign(1.0f, mat[0] + mat[1]); - mat[7] = -copysign(1.0f, mat[4] + mat[5]); - - // Identity - mat[10] = 1.0f; - mat[15] = 1.0f; -} - -void wlr_matrix_project_box(float (*mat)[16], struct wlr_box *box, - enum wl_output_transform transform, float rotation, - float (*projection)[16]) { - int x = box->x; - int y = box->y; - int width = box->width; - int height = box->height; - - wlr_matrix_translate(mat, x, y, 0); - - if (rotation != 0) { - float translate_center[16]; - wlr_matrix_translate(&translate_center, width/2, height/2, 0); - - float rotate[16]; - wlr_matrix_rotate(&rotate, rotation); - - float translate_origin[16]; - wlr_matrix_translate(&translate_origin, -width/2, -height/2, 0); - - wlr_matrix_mul(mat, &translate_center, mat); - wlr_matrix_mul(mat, &rotate, mat); - wlr_matrix_mul(mat, &translate_origin, mat); - } - - float scale[16]; - wlr_matrix_scale(&scale, width, height, 1); - - wlr_matrix_mul(mat, &scale, mat); - - if (transform != WL_OUTPUT_TRANSFORM_NORMAL) { - float surface_translate_center[16]; - wlr_matrix_translate(&surface_translate_center, 0.5, 0.5, 0); - - float surface_transform[16]; - wlr_matrix_transform(surface_transform, transform); - - float surface_translate_origin[16]; - wlr_matrix_translate(&surface_translate_origin, -0.5, -0.5, 0); - - wlr_matrix_mul(mat, &surface_translate_center, mat); - wlr_matrix_mul(mat, &surface_transform, mat); - wlr_matrix_mul(mat, &surface_translate_origin, mat); - } - - wlr_matrix_mul(projection, mat, mat); -} diff --git a/render/meson.build b/render/meson.build index 8aa70cea..4fe9ea67 100644 --- a/render/meson.build +++ b/render/meson.build @@ -15,7 +15,6 @@ lib_wlr_render = static_library( 'gles2/shaders.c', 'gles2/texture.c', 'gles2/util.c', - 'matrix.c', 'wlr_renderer.c', 'wlr_texture.c', ), diff --git a/render/wlr_renderer.c b/render/wlr_renderer.c index ce8fbe36..5598a0e7 100644 --- a/render/wlr_renderer.c +++ b/render/wlr_renderer.c @@ -1,9 +1,11 @@ #include <stdbool.h> #include <stdlib.h> #include <wlr/render/interface.h> +#include <wlr/render/wlr_renderer.h> +#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; } @@ -15,15 +17,15 @@ 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) { r->impl->end(r); } -void wlr_renderer_clear(struct wlr_renderer *r, const float (*color)[4]) { +void wlr_renderer_clear(struct wlr_renderer *r, const float color[static 4]) { r->impl->clear(r, color); } @@ -35,19 +37,52 @@ struct wlr_texture *wlr_render_texture_create(struct wlr_renderer *r) { return r->impl->texture_create(r); } -bool wlr_render_with_matrix(struct wlr_renderer *r, - struct wlr_texture *texture, const float (*matrix)[16], float alpha) { - return r->impl->render_with_matrix(r, texture, matrix, alpha); +bool wlr_render_texture(struct wlr_renderer *r, struct wlr_texture *texture, + const float projection[static 9], int x, int y, float alpha) { + const struct wlr_box box = { + .x = x, .y = y, + .width = texture->width, .height = texture->height, + }; + + float matrix[9]; + wlr_matrix_project_box(matrix, &box, WL_OUTPUT_TRANSFORM_NORMAL, 0, + projection); + + return wlr_render_texture_with_matrix(r, texture, matrix, alpha); +} + +bool wlr_render_texture_with_matrix(struct wlr_renderer *r, + struct wlr_texture *texture, const float matrix[static 9], + float alpha) { + return r->impl->render_texture_with_matrix(r, texture, matrix, alpha); +} + +void wlr_render_rect(struct wlr_renderer *r, const struct wlr_box *box, + const float color[static 4], const float projection[static 9]) { + float matrix[9]; + wlr_matrix_project_box(matrix, box, WL_OUTPUT_TRANSFORM_NORMAL, 0, + projection); + + wlr_render_quad_with_matrix(r, color, matrix); } -void wlr_render_colored_quad(struct wlr_renderer *r, - const float (*color)[4], const float (*matrix)[16]) { - r->impl->render_quad(r, color, matrix); +void wlr_render_quad_with_matrix(struct wlr_renderer *r, + const float color[static 4], const float matrix[static 9]) { + r->impl->render_quad_with_matrix(r, color, matrix); +} + +void wlr_render_ellipse(struct wlr_renderer *r, const struct wlr_box *box, + const float color[static 4], const float projection[static 9]) { + float matrix[9]; + wlr_matrix_project_box(matrix, box, WL_OUTPUT_TRANSFORM_NORMAL, 0, + projection); + + wlr_render_ellipse_with_matrix(r, color, matrix); } -void wlr_render_colored_ellipse(struct wlr_renderer *r, - const float (*color)[4], const float (*matrix)[16]) { - r->impl->render_ellipse(r, color, matrix); +void wlr_render_ellipse_with_matrix(struct wlr_renderer *r, + const float color[static 4], const float matrix[static 9]) { + r->impl->render_ellipse_with_matrix(r, color, matrix); } const enum wl_shm_format *wlr_renderer_get_formats( diff --git a/render/wlr_texture.c b/render/wlr_texture.c index a82a16b2..33c91822 100644 --- a/render/wlr_texture.c +++ b/render/wlr_texture.c @@ -1,9 +1,10 @@ #include <stdbool.h> #include <stdlib.h> #include <wlr/render/interface.h> +#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); } @@ -16,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, @@ -53,9 +50,9 @@ bool wlr_texture_upload_eglimage(struct wlr_texture *texture, return texture->impl->upload_eglimage(texture, image, width, height); } -void wlr_texture_get_matrix(struct wlr_texture *texture, - float (*matrix)[16], const float (*projection)[16], int x, int y) { - texture->impl->get_matrix(texture, matrix, projection, x, y); +bool wlr_texture_upload_dmabuf(struct wlr_texture *texture, + struct wl_resource *dmabuf_resource) { + return texture->impl->upload_dmabuf(texture, dmabuf_resource); } void wlr_texture_get_buffer_size(struct wlr_texture *texture, struct wl_resource |