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