mirror of
https://gitlab.freedesktop.org/wlroots/wlroots.git
synced 2026-02-23 01:40:31 -05:00
backend/drm: generalize color transform handling
This commit is contained in:
parent
f9a27c5b6f
commit
2984b011b6
7 changed files with 194 additions and 15 deletions
|
|
@ -6,6 +6,7 @@
|
|||
#include <wlr/util/box.h>
|
||||
#include <wlr/util/log.h>
|
||||
#include <xf86drmMode.h>
|
||||
#include "backend/drm/color.h"
|
||||
#include "backend/drm/drm.h"
|
||||
#include "backend/drm/fb.h"
|
||||
#include "backend/drm/iface.h"
|
||||
|
|
@ -334,11 +335,9 @@ bool drm_atomic_connector_prepare(struct wlr_drm_connector_state *state, bool mo
|
|||
if (state->base->committed & WLR_OUTPUT_STATE_COLOR_TRANSFORM) {
|
||||
size_t dim = 0;
|
||||
uint16_t *lut = NULL;
|
||||
if (state->base->color_transform != NULL) {
|
||||
struct wlr_color_transform_lut_3x1d *tr =
|
||||
color_transform_lut_3x1d_from_base(state->base->color_transform);
|
||||
dim = tr->dim;
|
||||
lut = tr->lut_3x1d;
|
||||
if (state->crtc_color_transform != NULL) {
|
||||
dim = state->crtc_color_transform->lut_3x1d->dim;
|
||||
lut = state->crtc_color_transform->lut_3x1d->lut_3x1d;
|
||||
}
|
||||
|
||||
// Fallback to legacy gamma interface when gamma properties are not
|
||||
|
|
|
|||
147
backend/drm/color.c
Normal file
147
backend/drm/color.c
Normal file
|
|
@ -0,0 +1,147 @@
|
|||
#include <stdlib.h>
|
||||
|
||||
#include "backend/drm/color.h"
|
||||
#include "backend/drm/drm.h"
|
||||
#include "render/color.h"
|
||||
|
||||
static struct wlr_color_transform_lut_3x1d *create_identity_3x1dlut(size_t dim) {
|
||||
if (dim == 0) {
|
||||
return NULL;
|
||||
}
|
||||
uint16_t *lut = malloc(dim * sizeof(lut[0]));
|
||||
if (lut == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
for (size_t i = 0; i < dim; i++) {
|
||||
float x = (float)i / (dim - 1);
|
||||
lut[i] = (uint16_t)roundf(UINT16_MAX * x);
|
||||
}
|
||||
struct wlr_color_transform *out = wlr_color_transform_init_lut_3x1d(dim, lut, lut, lut);
|
||||
free(lut);
|
||||
return color_transform_lut_3x1d_from_base(out);
|
||||
}
|
||||
|
||||
static bool drm_crtc_color_transform_init_lut_3x1d(struct wlr_drm_crtc_color_transform *out,
|
||||
size_t dim) {
|
||||
if (out->lut_3x1d != NULL) {
|
||||
return true;
|
||||
}
|
||||
out->lut_3x1d = create_identity_3x1dlut(dim);
|
||||
return out->lut_3x1d != NULL;
|
||||
}
|
||||
|
||||
static bool drm_crtc_color_transform_convert(struct wlr_drm_crtc_color_transform *out,
|
||||
struct wlr_color_transform *in, size_t lut_3x1d_dim) {
|
||||
switch (in->type) {
|
||||
case COLOR_TRANSFORM_INVERSE_EOTF:;
|
||||
struct wlr_color_transform_inverse_eotf *inv_eotf =
|
||||
wlr_color_transform_inverse_eotf_from_base(in);
|
||||
|
||||
if (!drm_crtc_color_transform_init_lut_3x1d(out, lut_3x1d_dim)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < 3; i++) {
|
||||
for (size_t j = 0; j < lut_3x1d_dim; j++) {
|
||||
size_t offset = i * lut_3x1d_dim + j;
|
||||
float v = (float)out->lut_3x1d->lut_3x1d[offset] / UINT16_MAX;
|
||||
v = wlr_color_transfer_function_eval_inverse_eotf(inv_eotf->tf, v);
|
||||
out->lut_3x1d->lut_3x1d[offset] = (uint16_t)roundf(UINT16_MAX * v);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
case COLOR_TRANSFORM_LUT_3X1D:;
|
||||
struct wlr_color_transform_lut_3x1d *lut_3x1d =
|
||||
color_transform_lut_3x1d_from_base(in);
|
||||
if (lut_3x1d->dim != lut_3x1d_dim) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!drm_crtc_color_transform_init_lut_3x1d(out, lut_3x1d_dim)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO: we loose precision when the input color transform is a lone 3×1D LUT
|
||||
for (size_t i = 0; i < 3 * lut_3x1d->dim; i++) {
|
||||
out->lut_3x1d->lut_3x1d[i] *= lut_3x1d->lut_3x1d[i];
|
||||
}
|
||||
|
||||
return true;
|
||||
case COLOR_TRANSFORM_LCMS2:
|
||||
return false; // unsupported
|
||||
case COLOR_TRANSFORM_PIPELINE:;
|
||||
struct wlr_color_transform_pipeline *pipeline = wl_container_of(in, pipeline, base);
|
||||
|
||||
for (size_t i = 0; i < pipeline->len; i++) {
|
||||
if (!drm_crtc_color_transform_convert(out, pipeline->transforms[i], lut_3x1d_dim)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
abort(); // unreachable
|
||||
}
|
||||
|
||||
static void addon_destroy(struct wlr_addon *addon) {
|
||||
struct wlr_drm_crtc_color_transform *tr = wl_container_of(addon, tr, addon);
|
||||
if (tr->lut_3x1d != NULL) {
|
||||
wlr_color_transform_unref(&tr->lut_3x1d->base);
|
||||
}
|
||||
free(tr);
|
||||
}
|
||||
|
||||
static const struct wlr_addon_interface addon_impl = {
|
||||
.name = "wlr_drm_crtc_color_transform",
|
||||
.destroy = addon_destroy,
|
||||
};
|
||||
|
||||
static struct wlr_drm_crtc_color_transform *drm_crtc_color_transform_create(
|
||||
struct wlr_drm_backend *backend, struct wlr_drm_crtc *crtc,
|
||||
struct wlr_color_transform *base) {
|
||||
struct wlr_drm_crtc_color_transform *tr = calloc(1, sizeof(*tr));
|
||||
if (tr == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
tr->base = base;
|
||||
wlr_addon_init(&tr->addon, &base->addons, crtc, &addon_impl);
|
||||
|
||||
size_t lut_3x1d_dim = drm_crtc_get_gamma_lut_size(backend, crtc);
|
||||
tr->failed = !drm_crtc_color_transform_convert(tr, base, lut_3x1d_dim);
|
||||
|
||||
return tr;
|
||||
}
|
||||
|
||||
struct wlr_drm_crtc_color_transform *drm_crtc_color_transform_import(
|
||||
struct wlr_drm_backend *backend, struct wlr_drm_crtc *crtc,
|
||||
struct wlr_color_transform *base) {
|
||||
struct wlr_drm_crtc_color_transform *tr;
|
||||
struct wlr_addon *addon = wlr_addon_find(&base->addons, crtc, &addon_impl);
|
||||
if (addon != NULL) {
|
||||
tr = wl_container_of(addon, tr, addon);
|
||||
} else {
|
||||
tr = drm_crtc_color_transform_create(backend, crtc, base);
|
||||
if (tr == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (tr->failed) {
|
||||
// We failed to convert the color transform to a 3×1D LUT. Keep the
|
||||
// addon attached so that we remember that this color transform cannot
|
||||
// be imported next time a commit contains it.
|
||||
return NULL;
|
||||
}
|
||||
|
||||
wlr_color_transform_ref(tr->base);
|
||||
return tr;
|
||||
}
|
||||
|
||||
void drm_crtc_color_transform_unref(struct wlr_drm_crtc_color_transform *tr) {
|
||||
if (tr == NULL) {
|
||||
return;
|
||||
}
|
||||
wlr_color_transform_unref(tr->base);
|
||||
}
|
||||
|
|
@ -20,6 +20,7 @@
|
|||
#include <wlr/util/transform.h>
|
||||
#include <xf86drm.h>
|
||||
#include <xf86drmMode.h>
|
||||
#include "backend/drm/color.h"
|
||||
#include "backend/drm/drm.h"
|
||||
#include "backend/drm/fb.h"
|
||||
#include "backend/drm/iface.h"
|
||||
|
|
@ -707,6 +708,7 @@ static void drm_connector_state_finish(struct wlr_drm_connector_state *state) {
|
|||
drm_fb_clear(&state->primary_fb);
|
||||
drm_fb_clear(&state->cursor_fb);
|
||||
wlr_drm_syncobj_timeline_unref(state->wait_timeline);
|
||||
drm_crtc_color_transform_unref(state->crtc_color_transform);
|
||||
}
|
||||
|
||||
static bool drm_connector_state_update_primary_fb(struct wlr_drm_connector *conn,
|
||||
|
|
@ -858,11 +860,15 @@ static bool drm_connector_prepare(struct wlr_drm_connector_state *conn_state, bo
|
|||
}
|
||||
}
|
||||
|
||||
if ((state->committed & WLR_OUTPUT_STATE_COLOR_TRANSFORM) && state->color_transform != NULL &&
|
||||
state->color_transform->type != COLOR_TRANSFORM_LUT_3X1D) {
|
||||
wlr_drm_conn_log(conn, WLR_DEBUG,
|
||||
"Only 3x1D LUT color transforms are supported");
|
||||
return false;
|
||||
if ((state->committed & WLR_OUTPUT_STATE_COLOR_TRANSFORM) && state->color_transform != NULL) {
|
||||
assert(conn_state->crtc_color_transform == NULL);
|
||||
conn_state->crtc_color_transform = drm_crtc_color_transform_import(conn->backend,
|
||||
conn->crtc, state->color_transform);
|
||||
if (conn_state->crtc_color_transform == NULL) {
|
||||
wlr_drm_conn_log(conn, WLR_DEBUG,
|
||||
"Failed to import color transform");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if ((state->committed & WLR_OUTPUT_STATE_IMAGE_DESCRIPTION) &&
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
#include <wlr/util/log.h>
|
||||
#include <xf86drm.h>
|
||||
#include <xf86drmMode.h>
|
||||
#include "backend/drm/color.h"
|
||||
#include "backend/drm/drm.h"
|
||||
#include "backend/drm/fb.h"
|
||||
#include "backend/drm/iface.h"
|
||||
|
|
@ -128,11 +129,9 @@ static bool legacy_crtc_commit(const struct wlr_drm_connector_state *state,
|
|||
if (state->base->committed & WLR_OUTPUT_STATE_COLOR_TRANSFORM) {
|
||||
size_t dim = 0;
|
||||
uint16_t *lut = NULL;
|
||||
if (state->base->color_transform != NULL) {
|
||||
struct wlr_color_transform_lut_3x1d *tr =
|
||||
color_transform_lut_3x1d_from_base(state->base->color_transform);
|
||||
dim = tr->dim;
|
||||
lut = tr->lut_3x1d;
|
||||
if (state->crtc_color_transform != NULL) {
|
||||
dim = state->crtc_color_transform->lut_3x1d->dim;
|
||||
lut = state->crtc_color_transform->lut_3x1d->lut_3x1d;
|
||||
}
|
||||
|
||||
if (!drm_legacy_crtc_set_gamma(drm, crtc, dim, lut)) {
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@ wlr_files += pnpids_c
|
|||
wlr_files += files(
|
||||
'atomic.c',
|
||||
'backend.c',
|
||||
'color.c',
|
||||
'drm.c',
|
||||
'fb.c',
|
||||
'legacy.c',
|
||||
|
|
|
|||
23
include/backend/drm/color.h
Normal file
23
include/backend/drm/color.h
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
#ifndef BACKEND_DRN_COLOR_H
|
||||
#define BACKEND_DRN_COLOR_H
|
||||
|
||||
#include <wlr/util/addon.h>
|
||||
|
||||
struct wlr_drm_backend;
|
||||
struct wlr_drm_crtc;
|
||||
struct wlr_color_transform;
|
||||
|
||||
struct wlr_drm_crtc_color_transform {
|
||||
struct wlr_color_transform *base;
|
||||
struct wlr_addon addon; // wlr_color_transform.addons
|
||||
bool failed;
|
||||
struct wlr_color_transform_lut_3x1d *lut_3x1d;
|
||||
};
|
||||
|
||||
struct wlr_drm_crtc_color_transform *drm_crtc_color_transform_import(
|
||||
struct wlr_drm_backend *backend, struct wlr_drm_crtc *crtc,
|
||||
struct wlr_color_transform *base);
|
||||
|
||||
void drm_crtc_color_transform_unref(struct wlr_drm_crtc_color_transform *tr);
|
||||
|
||||
#endif
|
||||
|
|
@ -15,6 +15,8 @@
|
|||
#include "backend/drm/properties.h"
|
||||
#include "backend/drm/renderer.h"
|
||||
|
||||
struct wlr_drm_crtc_color_transform;
|
||||
|
||||
struct wlr_drm_viewport {
|
||||
struct wlr_fbox src_box;
|
||||
struct wlr_box dst_box;
|
||||
|
|
@ -152,6 +154,8 @@ struct wlr_drm_connector_state {
|
|||
struct wlr_drm_syncobj_timeline *wait_timeline;
|
||||
uint64_t wait_point;
|
||||
|
||||
struct wlr_drm_crtc_color_transform *crtc_color_transform;
|
||||
|
||||
// used by atomic
|
||||
uint32_t mode_id;
|
||||
uint32_t gamma_lut;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue