diff --git a/libweston/renderer-gl/fragment.glsl b/libweston/renderer-gl/fragment.glsl index 63a20cd6..c49a6cd4 100644 --- a/libweston/renderer-gl/fragment.glsl +++ b/libweston/renderer-gl/fragment.glsl @@ -2,6 +2,7 @@ * Copyright 2012 Intel Corporation * Copyright 2015,2019,2021 Collabora, Ltd. * Copyright 2016 NVIDIA Corporation + * Copyright 2021 Advanced Micro Devices, Inc. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the @@ -46,10 +47,18 @@ #define SHADER_COLOR_CURVE_IDENTITY 0 #define SHADER_COLOR_CURVE_LUT_3x1D 1 +/* enum gl_shader_color_mapping */ +#define SHADER_COLOR_MAPPING_IDENTITY 0 +#define SHADER_COLOR_MAPPING_3DLUT 1 + #if DEF_VARIANT == SHADER_VARIANT_EXTERNAL #extension GL_OES_EGL_image_external : require #endif +#if DEF_COLOR_MAPPING == SHADER_COLOR_MAPPING_3DLUT +#extension GL_OES_texture_3D : require +#endif + #ifdef GL_FRAGMENT_PRECISION_HIGH #define HIGHPRECISION highp #else @@ -66,6 +75,7 @@ compile_const int c_variant = DEF_VARIANT; compile_const bool c_input_is_premult = DEF_INPUT_IS_PREMULT; compile_const bool c_green_tint = DEF_GREEN_TINT; compile_const int c_color_pre_curve = DEF_COLOR_PRE_CURVE; +compile_const int c_color_mapping = DEF_COLOR_MAPPING; vec4 yuva2rgba(vec4 yuva) @@ -110,6 +120,11 @@ uniform vec4 unicolor; uniform HIGHPRECISION sampler2D color_pre_curve_lut_2d; uniform HIGHPRECISION vec2 color_pre_curve_lut_scale_offset; +#if DEF_COLOR_MAPPING == SHADER_COLOR_MAPPING_3DLUT +uniform HIGHPRECISION sampler3D color_mapping_lut_3d; +uniform HIGHPRECISION vec2 color_mapping_lut_scale_offset; +#endif + vec4 sample_input_texture() { @@ -168,6 +183,12 @@ lut_texcoord(float x, vec2 scale_offset) return x * scale_offset.s + scale_offset.t; } +vec3 +lut_texcoord(vec3 pos, vec2 scale_offset) +{ + return pos * scale_offset.s + scale_offset.t; +} + /* * Sample a 1D LUT which is a single row of a 2D texture. The 2D texture has * four rows so that the centers of texels have precise y-coordinates. @@ -199,6 +220,28 @@ color_pre_curve(vec3 color) } } +vec3 +sample_color_mapping_lut_3d(vec3 color) +{ + vec3 pos, ret = vec3(0.0, 0.0, 0.0); +#if DEF_COLOR_MAPPING == SHADER_COLOR_MAPPING_3DLUT + pos = lut_texcoord(color, color_mapping_lut_scale_offset); + ret = texture3D(color_mapping_lut_3d, pos).rgb; +#endif + return ret; +} + +vec3 +color_mapping(vec3 color) +{ + if (c_color_mapping == SHADER_COLOR_MAPPING_IDENTITY) + return color; + else if (c_color_mapping == SHADER_COLOR_MAPPING_3DLUT) + return sample_color_mapping_lut_3d(color); + else /* Never reached, bad c_color_mapping. */ + return vec3(1.0, 0.3, 1.0); +} + vec4 color_pipeline(vec4 color) { @@ -206,6 +249,7 @@ color_pipeline(vec4 color) color.a *= alpha; color.rgb = color_pre_curve(color.rgb); + color.rgb = color_mapping(color.rgb); return color; } diff --git a/libweston/renderer-gl/gl-renderer.c b/libweston/renderer-gl/gl-renderer.c index 501a6802..e7cd06a9 100644 --- a/libweston/renderer-gl/gl-renderer.c +++ b/libweston/renderer-gl/gl-renderer.c @@ -3977,7 +3977,8 @@ gl_renderer_setup(struct weston_compositor *ec, EGLSurface egl_surface) if (gr->gl_version >= gr_gl_version(3, 0) && weston_check_egl_extension(extensions, "GL_OES_texture_float_linear") && - weston_check_egl_extension(extensions, "GL_EXT_color_buffer_half_float")) { + weston_check_egl_extension(extensions, "GL_EXT_color_buffer_half_float") && + weston_check_egl_extension(extensions, "GL_OES_texture_3D")) { gr->gl_supports_color_transforms = true; } diff --git a/libweston/renderer-gl/gl-shader-config-color-transformation.c b/libweston/renderer-gl/gl-shader-config-color-transformation.c index 21a45653..7f858dd1 100644 --- a/libweston/renderer-gl/gl-shader-config-color-transformation.c +++ b/libweston/renderer-gl/gl-shader-config-color-transformation.c @@ -1,5 +1,6 @@ /* * Copyright 2021 Collabora, Ltd. + * Copyright 2021 Advanced Micro Devices, Inc. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the @@ -44,11 +45,22 @@ struct gl_renderer_color_curve { float offset; }; +struct gl_renderer_color_mapping { + enum gl_shader_color_mapping type; + union { + struct { + GLuint tex3d; + float scale; + float offset; + } lut3d; + }; +} ; + struct gl_renderer_color_transform { struct weston_color_transform *owner; struct wl_listener destroy_listener; - struct gl_renderer_color_curve pre_curve; + struct gl_renderer_color_mapping mapping; }; static void @@ -58,10 +70,19 @@ gl_renderer_color_curve_fini(struct gl_renderer_color_curve *gl_curve) glDeleteTextures(1, &gl_curve->tex); } +static void +gl_renderer_color_mapping_fini(struct gl_renderer_color_mapping *gl_mapping) +{ + if (gl_mapping->type == SHADER_COLOR_MAPPING_3DLUT && + gl_mapping->lut3d.tex3d) + glDeleteTextures(1, &gl_mapping->lut3d.tex3d); +} + static void gl_renderer_color_transform_destroy(struct gl_renderer_color_transform *gl_xform) { gl_renderer_color_curve_fini(&gl_xform->pre_curve); + gl_renderer_color_mapping_fini(&gl_xform->mapping); wl_list_remove(&gl_xform->destroy_listener.link); free(gl_xform); } @@ -152,6 +173,47 @@ gl_color_curve_lut_3x1d(struct gl_renderer_color_curve *gl_curve, return true; } +static bool +gl_3d_lut(struct gl_renderer_color_transform *gl_xform, + struct weston_color_transform *xform) +{ + + GLuint tex3d; + float *lut; + const unsigned dim_size = xform->mapping.u.lut3d.optimal_len; + + lut = calloc(3 * dim_size * dim_size * dim_size, sizeof *lut); + if (!lut) + return false; + + xform->mapping.u.lut3d.fill_in(xform, lut, dim_size); + + glActiveTexture(GL_TEXTURE0); + glGenTextures(1, &tex3d); + glBindTexture(GL_TEXTURE_3D, tex3d); + glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + 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); + glPixelStorei(GL_UNPACK_SKIP_PIXELS_EXT, 0); + glPixelStorei(GL_UNPACK_SKIP_ROWS_EXT, 0); + glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, 0); + glTexImage3D(GL_TEXTURE_3D, 0, GL_RGB32F, dim_size, dim_size, dim_size, 0, + GL_RGB, GL_FLOAT, lut); + + glBindTexture(GL_TEXTURE_3D, 0); + gl_xform->mapping.type = SHADER_COLOR_MAPPING_3DLUT; + gl_xform->mapping.lut3d.tex3d = tex3d; + gl_xform->mapping.lut3d.scale = (float)(dim_size - 1) / dim_size; + gl_xform->mapping.lut3d.offset = 0.5f / dim_size; + + free(lut); + + return true; +} + + static const struct gl_renderer_color_transform * gl_renderer_color_transform_from(struct weston_color_transform *xform) { @@ -160,6 +222,7 @@ gl_renderer_color_transform_from(struct weston_color_transform *xform) .pre_curve.tex = 0, .pre_curve.scale = 0.0f, .pre_curve.offset = 0.0f, + .mapping.type = SHADER_COLOR_MAPPING_IDENTITY, }; struct gl_renderer_color_transform *gl_xform; bool ok = false; @@ -190,6 +253,19 @@ gl_renderer_color_transform_from(struct weston_color_transform *xform) break; } + if (!ok) { + gl_renderer_color_transform_destroy(gl_xform); + return NULL; + } + switch (xform->mapping.type) { + case WESTON_COLOR_MAPPING_TYPE_IDENTITY: + gl_xform->mapping = no_op_gl_xform.mapping; + ok = true; + break; + case WESTON_COLOR_MAPPING_TYPE_3D_LUT: + ok = gl_3d_lut(gl_xform, xform); + break; + } if (!ok) { gl_renderer_color_transform_destroy(gl_xform); return NULL; @@ -203,6 +279,7 @@ gl_shader_config_set_color_transform(struct gl_shader_config *sconf, struct weston_color_transform *xform) { const struct gl_renderer_color_transform *gl_xform; + bool ret = false; gl_xform = gl_renderer_color_transform_from(xform); if (!gl_xform) @@ -213,5 +290,22 @@ gl_shader_config_set_color_transform(struct gl_shader_config *sconf, sconf->color_pre_curve_lut_scale_offset[0] = gl_xform->pre_curve.scale; sconf->color_pre_curve_lut_scale_offset[1] = gl_xform->pre_curve.offset; - return true; + sconf->req.color_mapping = gl_xform->mapping.type; + switch (gl_xform->mapping.type) { + case SHADER_COLOR_MAPPING_3DLUT: + sconf->color_mapping.lut3d.tex = gl_xform->mapping.lut3d.tex3d; + sconf->color_mapping.lut3d.scale_offset[0] = + gl_xform->mapping.lut3d.scale; + sconf->color_mapping.lut3d.scale_offset[1] = + gl_xform->mapping.lut3d.offset; + assert(sconf->color_mapping.lut3d.scale_offset[0] > 0.0); + assert(sconf->color_mapping.lut3d.scale_offset[1] > 0.0); + ret = true; + break; + case SHADER_COLOR_MAPPING_IDENTITY: + ret = true; + break; + } + + return ret; } diff --git a/libweston/renderer-gl/gl-shaders.c b/libweston/renderer-gl/gl-shaders.c index 97f288c0..f46386f5 100644 --- a/libweston/renderer-gl/gl-shaders.c +++ b/libweston/renderer-gl/gl-shaders.c @@ -4,6 +4,7 @@ * Copyright 2016 NVIDIA Corporation * Copyright 2019 Harish Krupo * Copyright 2019 Intel Corporation + * Copyright 2021 Advanced Micro Devices, Inc. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the @@ -60,6 +61,12 @@ struct gl_shader { GLint color_uniform; GLint color_pre_curve_lut_2d_uniform; GLint color_pre_curve_lut_scale_offset_uniform; + union { + struct { + GLint tex_uniform; + GLint scale_offset_uniform; + } lut3d; + } color_mapping; struct wl_list link; /* gl_renderer::shader_list */ struct timespec last_used; }; @@ -97,6 +104,19 @@ gl_shader_color_curve_to_string(enum gl_shader_color_curve kind) return "!?!?"; /* never reached */ } +static const char * +gl_shader_color_mapping_to_string(enum gl_shader_color_mapping kind) +{ + switch (kind) { +#define CASERET(x) case x: return #x; + CASERET(SHADER_COLOR_MAPPING_IDENTITY) + CASERET(SHADER_COLOR_MAPPING_3DLUT) +#undef CASERET + } + + return "!?!?"; /* never reached */ +} + static void dump_program_with_line_numbers(int count, const char **sources) { @@ -162,9 +182,10 @@ create_shader_description_string(const struct gl_shader_requirements *req) int size; char *str; - size = asprintf(&str, "%s %s %cinput_is_premult %cgreen", + size = asprintf(&str, "%s %s %s %cinput_is_premult %cgreen", gl_shader_texture_variant_to_string(req->variant), gl_shader_color_curve_to_string(req->color_pre_curve), + gl_shader_color_mapping_to_string(req->color_mapping), req->input_is_premult ? '+' : '-', req->green_tint ? '+' : '-'); if (size < 0) @@ -182,10 +203,12 @@ create_shader_config_string(const struct gl_shader_requirements *req) "#define DEF_GREEN_TINT %s\n" "#define DEF_INPUT_IS_PREMULT %s\n" "#define DEF_COLOR_PRE_CURVE %s\n" + "#define DEF_COLOR_MAPPING %s\n" "#define DEF_VARIANT %s\n", req->green_tint ? "true" : "false", req->input_is_premult ? "true" : "false", gl_shader_color_curve_to_string(req->color_pre_curve), + gl_shader_color_mapping_to_string(req->color_mapping), gl_shader_texture_variant_to_string(req->variant)); if (size < 0) return NULL; @@ -268,6 +291,16 @@ gl_shader_create(struct gl_renderer *gr, shader->color_pre_curve_lut_scale_offset_uniform = glGetUniformLocation(shader->program, "color_pre_curve_lut_scale_offset"); + switch(requirements->color_mapping) { + case SHADER_COLOR_MAPPING_3DLUT: + shader->color_mapping.lut3d.tex_uniform = + glGetUniformLocation(shader->program, "color_mapping_lut_3d"); + shader->color_mapping.lut3d.scale_offset_uniform = + glGetUniformLocation(shader->program,"color_mapping_lut_scale_offset"); + break; + case SHADER_COLOR_MAPPING_IDENTITY: + break; + } free(conf); wl_list_insert(&gr->shader_list, &shader->link); @@ -376,6 +409,7 @@ gl_renderer_create_fallback_shader(struct gl_renderer *gr) .variant = SHADER_VARIANT_SOLID, .input_is_premult = true, .color_pre_curve = SHADER_COLOR_CURVE_IDENTITY, + .color_mapping = SHADER_COLOR_MAPPING_IDENTITY, }; struct gl_shader *shader; @@ -497,9 +531,8 @@ gl_shader_load_config(struct gl_shader *shader, glTexParameteri(in_tgt, GL_TEXTURE_MAG_FILTER, in_filter); } - /* Fixed texture unit for color_pre_curve LUT */ + /* Fixed texture unit for color_pre_curve LUT if it is available */ i = GL_SHADER_INPUT_TEX_MAX; - glActiveTexture(GL_TEXTURE0 + i); switch (sconf->req.color_pre_curve) { case SHADER_COLOR_CURVE_IDENTITY: assert(sconf->color_pre_curve_lut_tex == 0); @@ -508,13 +541,32 @@ gl_shader_load_config(struct gl_shader *shader, assert(sconf->color_pre_curve_lut_tex != 0); assert(shader->color_pre_curve_lut_2d_uniform != -1); assert(shader->color_pre_curve_lut_scale_offset_uniform != -1); - + glActiveTexture(GL_TEXTURE0 + i); glBindTexture(GL_TEXTURE_2D, sconf->color_pre_curve_lut_tex); glUniform1i(shader->color_pre_curve_lut_2d_uniform, i); + i++; glUniform2fv(shader->color_pre_curve_lut_scale_offset_uniform, 1, sconf->color_pre_curve_lut_scale_offset); break; } + + switch (sconf->req.color_mapping) { + case SHADER_COLOR_MAPPING_IDENTITY: + break; + case SHADER_COLOR_MAPPING_3DLUT: + assert(shader->color_mapping.lut3d.tex_uniform != -1); + assert(sconf->color_mapping.lut3d.tex != 0); + assert(shader->color_mapping.lut3d.scale_offset_uniform != -1); + glActiveTexture(GL_TEXTURE0 + i); + glBindTexture(GL_TEXTURE_3D, sconf->color_mapping.lut3d.tex); + glUniform1i(shader->color_mapping.lut3d.tex_uniform, i); + glUniform2fv(shader->color_mapping.lut3d.scale_offset_uniform, + 1, sconf->color_mapping.lut3d.scale_offset); + break; + default: + assert(false); + break; + } } bool