This makes weston_color_transform object be able to express three-channel one-dimensional look-up table transformations. They are useful for applying EOTF and EOTF^-1 mapping, or, gamma curves. They will also be useful in optimizing a following 3D LUT tap distribution once support for 3D LUT is added. The code added here translates from the lut_3x1d fill_in() interface to a GL texture to be used with SHADER_COLOR_CURVE_LUT_3x1D for weston_surfaces. It demonstrates how renderer data is attached to weston_color_transform and cached. GL_OES_texture_float_linear is required to be able to use bilinear texture filtering with 32-bit floating-point textures, used for the LUT. As the size of the LUT depends on what implements it, lut_3x1d fill_in() interface is a callback to the color management component to ask for an arbitrary size. For GL-renderer this is not important as it can easily realize any LUT size, but when DRM-backend wants to offload the EOTF^-1 mapping to KMS (GAMMA_LUT), the LUT size comes from KMS. Nothing actually implements lut_3x1d fill_in() yet, that will come in a later patch. Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>dev
parent
9a6a4e7032
commit
92f2367e58
@ -0,0 +1,217 @@ |
|||||||
|
/*
|
||||||
|
* Copyright 2021 Collabora, Ltd. |
||||||
|
* |
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining |
||||||
|
* a copy of this software and associated documentation files (the |
||||||
|
* "Software"), to deal in the Software without restriction, including |
||||||
|
* without limitation the rights to use, copy, modify, merge, publish, |
||||||
|
* distribute, sublicense, and/or sell copies of the Software, and to |
||||||
|
* permit persons to whom the Software is furnished to do so, subject to |
||||||
|
* the following conditions: |
||||||
|
* |
||||||
|
* The above copyright notice and this permission notice (including the |
||||||
|
* next paragraph) shall be included in all copies or substantial |
||||||
|
* portions of the Software. |
||||||
|
* |
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
||||||
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
||||||
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
||||||
|
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS |
||||||
|
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN |
||||||
|
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN |
||||||
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
||||||
|
* SOFTWARE. |
||||||
|
*/ |
||||||
|
|
||||||
|
#include "config.h" |
||||||
|
|
||||||
|
#include <GLES3/gl3.h> |
||||||
|
#include <GLES2/gl2ext.h> |
||||||
|
|
||||||
|
#include <assert.h> |
||||||
|
|
||||||
|
#include <libweston/libweston.h> |
||||||
|
#include "color.h" |
||||||
|
#include "gl-renderer.h" |
||||||
|
#include "gl-renderer-internal.h" |
||||||
|
|
||||||
|
#include "shared/weston-egl-ext.h" |
||||||
|
|
||||||
|
struct gl_renderer_color_curve { |
||||||
|
enum gl_shader_color_curve type; |
||||||
|
GLuint tex; |
||||||
|
float scale; |
||||||
|
float offset; |
||||||
|
}; |
||||||
|
|
||||||
|
struct gl_renderer_color_transform { |
||||||
|
struct weston_color_transform *owner; |
||||||
|
struct wl_listener destroy_listener; |
||||||
|
|
||||||
|
struct gl_renderer_color_curve pre_curve; |
||||||
|
}; |
||||||
|
|
||||||
|
static void |
||||||
|
gl_renderer_color_curve_fini(struct gl_renderer_color_curve *gl_curve) |
||||||
|
{ |
||||||
|
if (gl_curve->tex) |
||||||
|
glDeleteTextures(1, &gl_curve->tex); |
||||||
|
} |
||||||
|
|
||||||
|
static void |
||||||
|
gl_renderer_color_transform_destroy(struct gl_renderer_color_transform *gl_xform) |
||||||
|
{ |
||||||
|
gl_renderer_color_curve_fini(&gl_xform->pre_curve); |
||||||
|
wl_list_remove(&gl_xform->destroy_listener.link); |
||||||
|
free(gl_xform); |
||||||
|
} |
||||||
|
|
||||||
|
static void |
||||||
|
color_transform_destroy_handler(struct wl_listener *l, void *data) |
||||||
|
{ |
||||||
|
struct gl_renderer_color_transform *gl_xform; |
||||||
|
|
||||||
|
gl_xform = wl_container_of(l, gl_xform, destroy_listener); |
||||||
|
assert(gl_xform->owner == data); |
||||||
|
|
||||||
|
gl_renderer_color_transform_destroy(gl_xform); |
||||||
|
} |
||||||
|
|
||||||
|
static struct gl_renderer_color_transform * |
||||||
|
gl_renderer_color_transform_create(struct weston_color_transform *xform) |
||||||
|
{ |
||||||
|
struct gl_renderer_color_transform *gl_xform; |
||||||
|
|
||||||
|
gl_xform = zalloc(sizeof *gl_xform); |
||||||
|
if (!gl_xform) |
||||||
|
return NULL; |
||||||
|
|
||||||
|
gl_xform->owner = xform; |
||||||
|
gl_xform->destroy_listener.notify = color_transform_destroy_handler; |
||||||
|
wl_signal_add(&xform->destroy_signal, &gl_xform->destroy_listener); |
||||||
|
|
||||||
|
return gl_xform; |
||||||
|
} |
||||||
|
|
||||||
|
static struct gl_renderer_color_transform * |
||||||
|
gl_renderer_color_transform_get(struct weston_color_transform *xform) |
||||||
|
{ |
||||||
|
struct wl_listener *l; |
||||||
|
|
||||||
|
l = wl_signal_get(&xform->destroy_signal, |
||||||
|
color_transform_destroy_handler); |
||||||
|
if (!l) |
||||||
|
return NULL; |
||||||
|
|
||||||
|
return container_of(l, struct gl_renderer_color_transform, |
||||||
|
destroy_listener); |
||||||
|
} |
||||||
|
|
||||||
|
static bool |
||||||
|
gl_color_curve_lut_3x1d(struct gl_renderer_color_curve *gl_curve, |
||||||
|
const struct weston_color_curve *curve, |
||||||
|
struct weston_color_transform *xform) |
||||||
|
{ |
||||||
|
const unsigned lut_len = curve->u.lut_3x1d.optimal_len; |
||||||
|
const unsigned nr_rows = 4; |
||||||
|
GLuint tex; |
||||||
|
float *lut; |
||||||
|
|
||||||
|
/*
|
||||||
|
* Four rows, see fragment.glsl sample_color_pre_curve_lut_2d(). |
||||||
|
* The fourth row is unused in fragment.glsl color_pre_curve(). |
||||||
|
*/ |
||||||
|
lut = calloc(lut_len * nr_rows, sizeof *lut); |
||||||
|
if (!lut) |
||||||
|
return false; |
||||||
|
|
||||||
|
curve->u.lut_3x1d.fill_in(xform, lut, lut_len); |
||||||
|
|
||||||
|
glActiveTexture(GL_TEXTURE0); |
||||||
|
glGenTextures(1, &tex); |
||||||
|
glBindTexture(GL_TEXTURE_2D, tex); |
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); |
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); |
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); |
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); |
||||||
|
glPixelStorei(GL_UNPACK_ALIGNMENT, sizeof (float)); |
||||||
|
glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, 0); |
||||||
|
glPixelStorei(GL_UNPACK_SKIP_PIXELS_EXT, 0); |
||||||
|
glPixelStorei(GL_UNPACK_SKIP_ROWS_EXT, 0); |
||||||
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_R32F, lut_len, nr_rows, 0, |
||||||
|
GL_RED_EXT, GL_FLOAT, lut); |
||||||
|
|
||||||
|
glBindTexture(GL_TEXTURE_2D, 0); |
||||||
|
free(lut); |
||||||
|
|
||||||
|
gl_curve->type = SHADER_COLOR_CURVE_LUT_3x1D; |
||||||
|
gl_curve->tex = tex; |
||||||
|
gl_curve->scale = (float)(lut_len - 1) / lut_len; |
||||||
|
gl_curve->offset = 0.5f / lut_len; |
||||||
|
|
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
static const struct gl_renderer_color_transform * |
||||||
|
gl_renderer_color_transform_from(struct weston_color_transform *xform) |
||||||
|
{ |
||||||
|
static const struct gl_renderer_color_transform no_op_gl_xform = { |
||||||
|
.pre_curve.type = SHADER_COLOR_CURVE_IDENTITY, |
||||||
|
.pre_curve.tex = 0, |
||||||
|
.pre_curve.scale = 0.0f, |
||||||
|
.pre_curve.offset = 0.0f, |
||||||
|
}; |
||||||
|
struct gl_renderer_color_transform *gl_xform; |
||||||
|
bool ok = false; |
||||||
|
|
||||||
|
/* Identity transformation */ |
||||||
|
if (!xform) |
||||||
|
return &no_op_gl_xform; |
||||||
|
|
||||||
|
/* Cached transformation */ |
||||||
|
gl_xform = gl_renderer_color_transform_get(xform); |
||||||
|
if (gl_xform) |
||||||
|
return gl_xform; |
||||||
|
|
||||||
|
/* New transformation */ |
||||||
|
|
||||||
|
gl_xform = gl_renderer_color_transform_create(xform); |
||||||
|
if (!gl_xform) |
||||||
|
return NULL; |
||||||
|
|
||||||
|
switch (xform->pre_curve.type) { |
||||||
|
case WESTON_COLOR_CURVE_TYPE_IDENTITY: |
||||||
|
gl_xform->pre_curve = no_op_gl_xform.pre_curve; |
||||||
|
ok = true; |
||||||
|
break; |
||||||
|
case WESTON_COLOR_CURVE_TYPE_LUT_3x1D: |
||||||
|
ok = gl_color_curve_lut_3x1d(&gl_xform->pre_curve, |
||||||
|
&xform->pre_curve, xform); |
||||||
|
break; |
||||||
|
} |
||||||
|
|
||||||
|
if (!ok) { |
||||||
|
gl_renderer_color_transform_destroy(gl_xform); |
||||||
|
return NULL; |
||||||
|
} |
||||||
|
|
||||||
|
return gl_xform; |
||||||
|
} |
||||||
|
|
||||||
|
bool |
||||||
|
gl_shader_config_set_color_transform(struct gl_shader_config *sconf, |
||||||
|
struct weston_color_transform *xform) |
||||||
|
{ |
||||||
|
const struct gl_renderer_color_transform *gl_xform; |
||||||
|
|
||||||
|
gl_xform = gl_renderer_color_transform_from(xform); |
||||||
|
if (!gl_xform) |
||||||
|
return false; |
||||||
|
|
||||||
|
sconf->req.color_pre_curve = gl_xform->pre_curve.type; |
||||||
|
sconf->color_pre_curve_lut_tex = gl_xform->pre_curve.tex; |
||||||
|
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; |
||||||
|
} |
Loading…
Reference in new issue