From 10bf68b928c1dc463b600703c148edcbba64939d Mon Sep 17 00:00:00 2001 From: Devin Bayer Date: Tue, 14 Jul 2020 17:01:25 +0000 Subject: [PATCH] color management --- include/render/gles2.h | 22 +++ include/wlr/render/color.h | 19 +++ include/wlr/render/wlr_renderer.h | 1 + include/wlr/render/wlr_texture.h | 4 + include/wlr/types/wlr_surface.h | 2 + meson.build | 2 + render/gles2/color.c | 241 ++++++++++++++++++++++++++++++ render/gles2/renderer.c | 98 +++++++----- render/gles2/shaders.c | 66 +++++--- render/gles2/texture.c | 1 + render/meson.build | 1 + render/wlr_renderer.c | 2 + types/wlr_surface.c | 1 + 13 files changed, 401 insertions(+), 59 deletions(-) create mode 100644 include/wlr/render/color.h create mode 100644 render/gles2/color.c diff --git a/include/render/gles2.h b/include/render/gles2.h index 6d25bea05..f58485e47 100644 --- a/include/render/gles2.h +++ b/include/render/gles2.h @@ -33,6 +33,7 @@ struct wlr_gles2_pixel_format { }; struct wlr_gles2_tex_shader { + // attribute locations GLuint program; GLint proj; GLint invert_y; @@ -40,6 +41,11 @@ struct wlr_gles2_tex_shader { GLint alpha; GLint pos_attrib; GLint tex_attrib; + GLuint color_table; + GLint color_enable; + + // source components + const GLchar *head, *util, *main; }; struct wlr_gles2_renderer { @@ -110,4 +116,20 @@ void pop_gles2_marker(void); #define PUSH_GLES2_DEBUG push_gles2_marker(_WLR_FILENAME, __func__) #define POP_GLES2_DEBUG pop_gles2_marker() +// color engine + +void color_engine_setup(void); +GLuint color_build_lut(struct wlr_color_config *input, struct wlr_color_config *output); +void color_convert(struct wlr_color_config *ic, struct wlr_color_config *oc, const float input[static 4], float output[static 4]); + +#define COLOR_LUT_SIZE 64 + +/** + * Ignore half a texel near every edge because those + * areas are not interpolated. See GPU Gems 2, Ch. 24 for details. + * + * offset = (0.5 / COLOR_LUT_SIZE) + */ +#define COLOR_OFFSET "0.007813" + #endif diff --git a/include/wlr/render/color.h b/include/wlr/render/color.h new file mode 100644 index 000000000..b2ef284e5 --- /dev/null +++ b/include/wlr/render/color.h @@ -0,0 +1,19 @@ +#ifndef _WLR_COLOR_H +#define _WLR_COLOR_H + +struct wlr_color_config { + char *icc_profile_path; // not null +}; + +/** + * Create a color config. + * + * icc_profile_path should not be NULL. + * It will be copied into the config. + */ +struct wlr_color_config *wlr_color_config_load(const char *icc_profile_path); + +struct wlr_color_config *wlr_color_config_copy(struct wlr_color_config *value); +void wlr_color_config_free(struct wlr_color_config *config); + +#endif diff --git a/include/wlr/render/wlr_renderer.h b/include/wlr/render/wlr_renderer.h index 513f412a1..d9e64c099 100644 --- a/include/wlr/render/wlr_renderer.h +++ b/include/wlr/render/wlr_renderer.h @@ -24,6 +24,7 @@ struct wlr_drm_format_set; struct wlr_renderer { const struct wlr_renderer_impl *impl; + struct wlr_color_config *color; bool rendering; diff --git a/include/wlr/render/wlr_texture.h b/include/wlr/render/wlr_texture.h index 71ce5e7c9..bba9668c0 100644 --- a/include/wlr/render/wlr_texture.h +++ b/include/wlr/render/wlr_texture.h @@ -12,12 +12,16 @@ #include #include #include +#include struct wlr_renderer; struct wlr_texture_impl; struct wlr_texture { const struct wlr_texture_impl *impl; + struct wlr_color_config *color; + struct wlr_texture *colored; + uint32_t width, height; }; diff --git a/include/wlr/types/wlr_surface.h b/include/wlr/types/wlr_surface.h index 2cd4ac5db..1a99d4b97 100644 --- a/include/wlr/types/wlr_surface.h +++ b/include/wlr/types/wlr_surface.h @@ -128,6 +128,8 @@ struct wlr_surface { struct wl_listener renderer_destroy; + struct wlr_color_config *color; + void *data; }; diff --git a/meson.build b/meson.build index a6dad5d6c..749a16da4 100644 --- a/meson.build +++ b/meson.build @@ -107,6 +107,7 @@ libinput = dependency('libinput', version: '>=1.9.0') xkbcommon = dependency('xkbcommon') udev = dependency('libudev') pixman = dependency('pixman-1') +lcms2 = dependency('lcms2') math = cc.find_library('m') rt = cc.find_library('rt') @@ -128,6 +129,7 @@ wlr_deps = [ xkbcommon, udev, pixman, + lcms2, math, rt, ] diff --git a/render/gles2/color.c b/render/gles2/color.c new file mode 100644 index 000000000..fe844d68d --- /dev/null +++ b/render/gles2/color.c @@ -0,0 +1,241 @@ +// OpenGL Color conversion + +#define _XOPEN_SOURCE 500 // for strdup + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include "render/gles2.h" + +// GL3+ or GL_EXT_texture_norm16 on ES 3.2 +#define GL_RGBA16 0x805B + +struct lut { + GLuint tex_id; + struct wlr_color_config *input, *output; + cmsHTRANSFORM transform; +}; + +#define LUTS_MAX 100 + +static struct wlr_list luts; + +static int color_compare(void *av, void *bv) { + struct wlr_color_config *a = av, *b = bv; + if(a == b) + return 0; + if(!a) + return 1; + if(!b) + return -1; + + return strcmp(a->icc_profile_path, b->icc_profile_path); +} + +struct wlr_color_config *wlr_color_config_copy(struct wlr_color_config *value) { + if(! value) + return NULL; + + struct wlr_color_config *copy = calloc(1, sizeof(*copy)); + copy->icc_profile_path = strdup(value->icc_profile_path); + return copy; +} + +static cmsHPROFILE color_load(struct wlr_color_config *color) { + if(color) { + cmsHPROFILE pro = cmsOpenProfileFromFile (color->icc_profile_path, "r"); + if (pro == NULL) { + wlr_log(WLR_ERROR, "error loading icc profile %s", color->icc_profile_path); + } else { + return pro; + } + } + return cmsCreate_sRGBProfile(); + +} + +static const char *color_describe(struct wlr_color_config *color) { + if(! color) + return "sRGB"; + + char *base = strrchr(color->icc_profile_path, '/'); + return base ? base + 1 : color->icc_profile_path; +} + +struct wlr_color_config *wlr_color_config_load(const char *icc_profile_path) { + assert(icc_profile_path); + + if(0 == strlen(icc_profile_path)) { + return NULL; + } + + bool can_access = access(icc_profile_path, F_OK) != -1; + if (!can_access) { + wlr_log(WLR_ERROR, "Unable to access color profile '%s'", icc_profile_path); + return NULL; + } + + struct wlr_color_config *color = calloc(1, sizeof(*color)); + color->icc_profile_path = strdup(icc_profile_path); + return color; +} + +void wlr_color_config_free(struct wlr_color_config *color) { + if(! color) + return; + free(color->icc_profile_path); + free(color); +} + +static struct lut *load_lut(struct wlr_color_config *input, struct wlr_color_config *output) { + if(0 == color_compare(input, output)) + return NULL; + + struct lut *lut; + + // find an existing cached lut + for (size_t i = 0; i < luts.length; i++) { + lut = luts.items[i]; + if(color_compare(lut->input, input) || color_compare(lut->output, output)) + continue; + + // move to head to list + if(i > 5) { + wlr_list_del(&luts, i); + wlr_list_insert(&luts, 0, lut); + } + return lut; + } + + // clean an old LUT to avoid memory leak + if(luts.length > LUTS_MAX) { + struct lut *lut = wlr_list_pop(&luts); + wlr_log(WLR_DEBUG, "destroy CLUT %s -> %s", color_describe(lut->input), color_describe(lut->output)); + wlr_color_config_free(lut->input); + wlr_color_config_free(lut->output); + cmsDeleteTransform(lut->transform); + glDeleteTextures(1, &lut->tex_id); + free(lut); + } + + wlr_log(WLR_INFO, "create CLUT %s -> %s", color_describe(input), color_describe(output)); + cmsHPROFILE inp = color_load(input); + cmsHPROFILE outp = color_load(output); + + // According to lcms docs, black point compensation does not apply to perceptual intent, so we omit the flag. + cmsHTRANSFORM xform = cmsCreateTransform( + inp, TYPE_RGB_16, + outp, TYPE_RGB_16, + INTENT_PERCEPTUAL, + cmsFLAGS_HIGHRESPRECALC | cmsFLAGS_NOCACHE); + + cmsCloseProfile(inp); + cmsCloseProfile(outp); + + if (xform == NULL) { + wlr_log(WLR_ERROR, "failed to create color transform"); + return NULL; + } + + // save the new LUT + lut = malloc(sizeof(*lut)); + *lut = (struct lut){ + .input = wlr_color_config_copy(input), + .output = wlr_color_config_copy(output), + .transform = xform, + }; + wlr_list_insert(&luts, 0, lut); + return lut; +} + +void color_convert(struct wlr_color_config *ic, struct wlr_color_config *oc, const float input[static 4], float output[static 4]) { + struct lut *lut = load_lut(ic, oc); + if(! lut) { + memcpy(output, input, 4 * sizeof(float)); + return; + } + + uint16_t out[3], in[3] = { + input[0] * UINT16_MAX, + input[1] * UINT16_MAX, + input[2] * UINT16_MAX, + }; + cmsDoTransform(lut->transform, in, out, 1); + output[0] = (float)out[0] / UINT16_MAX; + output[1] = (float)out[1] / UINT16_MAX; + output[2] = (float)out[2] / UINT16_MAX; + output[3] = input[3]; +} + +GLuint color_build_lut(struct wlr_color_config *input, struct wlr_color_config *output) { + struct lut *lut = load_lut(input, output); + if(! lut) + return 0; + + if(lut->tex_id) + return lut->tex_id; + + // 3D array: [B][G][R] = [R,G,B,A] + // Notes: + // - The first dimension is blue + // - The alpha channel is unused but needed since GL_RGB16 does not work. + uint16_t table[COLOR_LUT_SIZE][COLOR_LUT_SIZE][COLOR_LUT_SIZE][4]; + + int n = COLOR_LUT_SIZE; + int r, g, b; + for (r = 0; r < n; r++) { + for (g = 0; g < n; g++) { + for (b = 0; b < n; b++) { + uint16_t in[3]; + in[0] = floor((double) r / (n - 1) * UINT16_MAX + 0.5); + in[1] = floor((double) g / (n - 1) * UINT16_MAX + 0.5); + in[2] = floor((double) b / (n - 1) * UINT16_MAX + 0.5); + + cmsDoTransform(lut->transform, in, table[b][g][r], 1); + } + } + } + + glGenTextures (1, &lut->tex_id); + glActiveTexture(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_3D, lut->tex_id); + + glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); + + // we must use linear interpolation for small LUTs + glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + + glTexImage3D(GL_TEXTURE_3D, 0, GL_RGBA16, n, n, n, + 0, GL_RGBA, GL_UNSIGNED_SHORT, table); + + // cleanup + glBindTexture(GL_TEXTURE_3D, 0); + glActiveTexture(GL_TEXTURE0); + + return lut->tex_id; +} + +static void lcms_error_handler(cmsContext ctx, cmsUInt32Number code, const char *msg) { + wlr_log(WLR_ERROR, "color management: [%i] %s", code, msg); +} + +void color_engine_setup(void) { + wlr_list_init(&luts); + cmsSetLogErrorHandler(lcms_error_handler); +} + diff --git a/render/gles2/renderer.c b/render/gles2/renderer.c index 914f5b77f..50bfa740e 100644 --- a/render/gles2/renderer.c +++ b/render/gles2/renderer.c @@ -161,6 +161,15 @@ static bool gles2_render_subtexture_with_matrix( glEnableVertexAttribArray(shader->pos_attrib); glEnableVertexAttribArray(shader->tex_attrib); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + + GLuint color_table = color_build_lut(wlr_texture->color, wlr_renderer->color); + glActiveTexture(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_3D, color_table); + glUniform1i(shader->color_table, 1); + glUniform1i(shader->color_enable, color_table != 0); + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); glDisableVertexAttribArray(shader->pos_attrib); @@ -182,11 +191,14 @@ static void gles2_render_quad_with_matrix(struct wlr_renderer *wlr_renderer, float transposition[9]; wlr_matrix_transpose(transposition, matrix); + float converted[4]; + color_convert(NULL, wlr_renderer->color, color, converted); + PUSH_GLES2_DEBUG; glUseProgram(renderer->shaders.quad.program); glUniformMatrix3fv(renderer->shaders.quad.proj, 1, GL_FALSE, transposition); - glUniform4f(renderer->shaders.quad.color, color[0], color[1], color[2], color[3]); + glUniform4f(renderer->shaders.quad.color, converted[0], converted[1], converted[2], converted[3]); glVertexAttribPointer(renderer->shaders.quad.pos_attrib, 2, GL_FLOAT, GL_FALSE, 0, verts); @@ -217,11 +229,14 @@ static void gles2_render_ellipse_with_matrix(struct wlr_renderer *wlr_renderer, 0, 1, // bottom left }; + float converted[4]; + color_convert(NULL, wlr_renderer->color, color, converted); + PUSH_GLES2_DEBUG; glUseProgram(renderer->shaders.ellipse.program); glUniformMatrix3fv(renderer->shaders.ellipse.proj, 1, GL_FALSE, transposition); - glUniform4f(renderer->shaders.ellipse.color, color[0], color[1], color[2], color[3]); + glUniform4f(renderer->shaders.ellipse.color, converted[0], converted[1], converted[2], converted[3]); glVertexAttribPointer(renderer->shaders.ellipse.pos_attrib, 2, GL_FLOAT, GL_FALSE, 0, verts); @@ -258,7 +273,7 @@ static bool gles2_resource_is_wl_drm_buffer(struct wlr_renderer *wlr_renderer, EGLint fmt; return renderer->egl->procs.eglQueryWaylandBufferWL(renderer->egl->display, - resource, EGL_TEXTURE_FORMAT, &fmt); + resource, EGL_TEXTURE_FORMAT, &fmt); } static void gles2_wl_drm_buffer_get_size(struct wlr_renderer *wlr_renderer, @@ -665,9 +680,41 @@ 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[]; +extern struct wlr_gles2_tex_shader + tex_fragment_src_rgba, + tex_fragment_src_rgbx, + tex_fragment_src_external; + +// return true on success +static bool build_tex_shader(struct wlr_gles2_tex_shader *shader) +{ + GLuint prog; + + char fragsrc[100000] = ""; + int n = snprintf(fragsrc, sizeof(fragsrc), "%s\n%s\nvoid main() {\n%s\n}\n", + shader->head, + shader->util, + shader->main); + + assert(n < (int)sizeof(fragsrc)); + + shader->program = prog = link_program(tex_vertex_src, fragsrc); + if (!prog) { + return false; + } + + shader->proj = glGetUniformLocation(prog, "proj"); + shader->invert_y = glGetUniformLocation(prog, "invert_y"); + shader->tex = glGetUniformLocation(prog, "tex"); + shader->alpha = glGetUniformLocation(prog, "alpha"); + shader->pos_attrib = glGetAttribLocation(prog, "pos"); + shader->tex_attrib = glGetAttribLocation(prog, "texcoord"); + + shader->color_table = glGetUniformLocation(prog, "color_table"); + shader->color_enable = glGetUniformLocation(prog, "color_enable"); + + return true; +} struct wlr_renderer *wlr_gles2_renderer_create(struct wlr_egl *egl) { if (!wlr_egl_make_current(egl, EGL_NO_SURFACE, NULL)) { @@ -695,6 +742,8 @@ struct wlr_renderer *wlr_gles2_renderer_create(struct wlr_egl *egl) { wlr_log(WLR_INFO, "GL renderer: %s", glGetString(GL_RENDERER)); wlr_log(WLR_INFO, "Supported GLES2 extensions: %s", exts_str); + color_engine_setup(); + if (!check_gl_ext(exts_str, "GL_EXT_texture_format_BGRA8888")) { wlr_log(WLR_ERROR, "BGRA8888 format not supported by GLES2"); free(renderer); @@ -731,9 +780,9 @@ struct wlr_renderer *wlr_gles2_renderer_create(struct wlr_egl *egl) { // Silence unwanted message types gles2_procs.glDebugMessageControlKHR(GL_DONT_CARE, - GL_DEBUG_TYPE_POP_GROUP_KHR, GL_DONT_CARE, 0, NULL, GL_FALSE); + GL_DEBUG_TYPE_POP_GROUP_KHR, GL_DONT_CARE, 0, NULL, GL_FALSE); gles2_procs.glDebugMessageControlKHR(GL_DONT_CARE, - GL_DEBUG_TYPE_PUSH_GROUP_KHR, GL_DONT_CARE, 0, NULL, GL_FALSE); + GL_DEBUG_TYPE_PUSH_GROUP_KHR, GL_DONT_CARE, 0, NULL, GL_FALSE); } PUSH_GLES2_DEBUG; @@ -758,42 +807,21 @@ struct wlr_renderer *wlr_gles2_renderer_create(struct wlr_egl *egl) { renderer->shaders.ellipse.pos_attrib = glGetAttribLocation(prog, "pos"); renderer->shaders.ellipse.tex_attrib = glGetAttribLocation(prog, "texcoord"); - renderer->shaders.tex_rgba.program = prog = - link_program(tex_vertex_src, tex_fragment_src_rgba); - if (!renderer->shaders.tex_rgba.program) { + renderer->shaders.tex_rgba = tex_fragment_src_rgba; + if(! build_tex_shader(&renderer->shaders.tex_rgba)) { goto error; } - renderer->shaders.tex_rgba.proj = glGetUniformLocation(prog, "proj"); - renderer->shaders.tex_rgba.invert_y = glGetUniformLocation(prog, "invert_y"); - renderer->shaders.tex_rgba.tex = glGetUniformLocation(prog, "tex"); - renderer->shaders.tex_rgba.alpha = glGetUniformLocation(prog, "alpha"); - renderer->shaders.tex_rgba.pos_attrib = glGetAttribLocation(prog, "pos"); - renderer->shaders.tex_rgba.tex_attrib = glGetAttribLocation(prog, "texcoord"); - renderer->shaders.tex_rgbx.program = prog = - link_program(tex_vertex_src, tex_fragment_src_rgbx); - if (!renderer->shaders.tex_rgbx.program) { + renderer->shaders.tex_rgbx = tex_fragment_src_rgbx; + if(! build_tex_shader(&renderer->shaders.tex_rgbx)) { goto error; } - renderer->shaders.tex_rgbx.proj = glGetUniformLocation(prog, "proj"); - renderer->shaders.tex_rgbx.invert_y = glGetUniformLocation(prog, "invert_y"); - renderer->shaders.tex_rgbx.tex = glGetUniformLocation(prog, "tex"); - renderer->shaders.tex_rgbx.alpha = glGetUniformLocation(prog, "alpha"); - renderer->shaders.tex_rgbx.pos_attrib = glGetAttribLocation(prog, "pos"); - renderer->shaders.tex_rgbx.tex_attrib = glGetAttribLocation(prog, "texcoord"); if (renderer->exts.egl_image_external_oes) { - renderer->shaders.tex_ext.program = prog = - link_program(tex_vertex_src, tex_fragment_src_external); - if (!renderer->shaders.tex_ext.program) { + renderer->shaders.tex_ext = tex_fragment_src_external; + if(! build_tex_shader(&renderer->shaders.tex_ext)) { goto error; } - renderer->shaders.tex_ext.proj = glGetUniformLocation(prog, "proj"); - renderer->shaders.tex_ext.invert_y = glGetUniformLocation(prog, "invert_y"); - renderer->shaders.tex_ext.tex = glGetUniformLocation(prog, "tex"); - renderer->shaders.tex_ext.alpha = glGetUniformLocation(prog, "alpha"); - renderer->shaders.tex_ext.pos_attrib = glGetAttribLocation(prog, "pos"); - renderer->shaders.tex_ext.tex_attrib = glGetAttribLocation(prog, "texcoord"); } POP_GLES2_DEBUG; diff --git a/render/gles2/shaders.c b/render/gles2/shaders.c index 4ebfc0bc7..9a323dcca 100644 --- a/render/gles2/shaders.c +++ b/render/gles2/shaders.c @@ -56,33 +56,51 @@ const GLchar tex_vertex_src[] = " }\n" "}\n"; -const GLchar tex_fragment_src_rgba[] = +static const GLchar tex_fragment_head[] = +"#extension GL_OES_texture_3D : require\n" +"\n" "precision mediump float;\n" "varying vec2 v_texcoord;\n" "uniform sampler2D tex;\n" -"uniform float alpha;\n" -"\n" -"void main() {\n" -" gl_FragColor = texture2D(tex, v_texcoord) * alpha;\n" -"}\n"; +"uniform float alpha;\n"; -const GLchar tex_fragment_src_rgbx[] = -"precision mediump float;\n" -"varying vec2 v_texcoord;\n" -"uniform sampler2D tex;\n" -"uniform float alpha;\n" +static const GLchar tex_fragment_util[] = +"uniform mediump sampler3D color_table;\n" +"uniform bool color_enable;\n" +"#define offset " COLOR_OFFSET "\n" "\n" -"void main() {\n" -" gl_FragColor = vec4(texture2D(tex, v_texcoord).rgb, 1.0) * alpha;\n" -"}\n"; +"#ifdef GL_OES_texture_3D\n" +"vec4 lookup(vec4 c) {\n" +" if(! color_enable)\n" +" return c;\n" +" vec4 m = texture3D(color_table, offset + c.rgb * (1.0 - offset*2.0));\n" +" return vec4(m.rgb, c.a);\n" +"}\n" +"#else\n" +"#define lookup(c) c\n" +"#endif\n" +; -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" -" gl_FragColor = texture2D(texture0, v_texcoord) * alpha;\n" -"}\n"; +struct wlr_gles2_tex_shader tex_fragment_src_rgba = { + .head = tex_fragment_head, + .util = tex_fragment_util, + .main = "gl_FragColor = lookup(texture2D(tex, v_texcoord)) * alpha;" +}; + +struct wlr_gles2_tex_shader tex_fragment_src_rgbx = { + .head = tex_fragment_head, + .util = tex_fragment_util, + .main = "gl_FragColor = lookup(vec4(texture2D(tex, v_texcoord).rgb, 1.0)) * alpha;" +}; + +struct wlr_gles2_tex_shader tex_fragment_src_external = { + .head = "#extension GL_OES_EGL_image_external : require\n" + "#extension GL_OES_texture_3D : enable\n" + "\n" + "precision mediump float;\n" + "varying vec2 v_texcoord;\n" + "uniform samplerExternalOES texture0;\n" + "uniform float alpha;\n", + .util = tex_fragment_util, + .main = "gl_FragColor = lookup(texture2D(texture0, v_texcoord)) * alpha;\n" +}; diff --git a/render/gles2/texture.c b/render/gles2/texture.c index 0187a462f..784290762 100644 --- a/render/gles2/texture.c +++ b/render/gles2/texture.c @@ -137,6 +137,7 @@ static const struct wlr_texture_impl texture_impl = { struct wlr_texture *wlr_gles2_texture_from_pixels(struct wlr_egl *egl, enum wl_shm_format wl_fmt, uint32_t stride, uint32_t width, uint32_t height, const void *data) { + wlr_egl_make_current(egl, EGL_NO_SURFACE, NULL); const struct wlr_gles2_pixel_format *fmt = get_gles2_format_from_wl(wl_fmt); diff --git a/render/meson.build b/render/meson.build index 9486c22de..7c212d44a 100644 --- a/render/meson.build +++ b/render/meson.build @@ -6,6 +6,7 @@ wlr_files += files( 'gles2/renderer.c', 'gles2/shaders.c', 'gles2/texture.c', + 'gles2/color.c', 'wlr_renderer.c', 'wlr_texture.c', ) diff --git a/render/wlr_renderer.c b/render/wlr_renderer.c index 593d165f4..ebf3c5348 100644 --- a/render/wlr_renderer.c +++ b/render/wlr_renderer.c @@ -30,6 +30,8 @@ void wlr_renderer_destroy(struct wlr_renderer *r) { } wlr_signal_emit_safe(&r->events.destroy, r); + wlr_color_config_free(r->color); + if (r->impl && r->impl->destroy) { r->impl->destroy(r); } else { diff --git a/types/wlr_surface.c b/types/wlr_surface.c index f0a0b1fb1..30546431f 100644 --- a/types/wlr_surface.c +++ b/types/wlr_surface.c @@ -697,6 +697,7 @@ struct wlr_texture *wlr_surface_get_texture(struct wlr_surface *surface) { if (surface->buffer == NULL) { return NULL; } + surface->buffer->texture->color = surface->color; return surface->buffer->texture; }