mirror of
https://gitlab.freedesktop.org/wlroots/wlroots.git
synced 2026-02-05 04:06:11 -05:00
backend/drm: add support for CTM
This commit is contained in:
parent
92ba6ffdf8
commit
2db00a9872
8 changed files with 96 additions and 12 deletions
|
|
@ -154,6 +154,31 @@ static bool create_gamma_lut_blob(struct wlr_drm_backend *drm,
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool create_ctm_blob(struct wlr_drm_backend *drm,
|
||||
const float *matrix, uint32_t *blob_id) {
|
||||
if (matrix == NULL) {
|
||||
*blob_id = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Convert to S31.32 sign-magnitude fixed floating-point encoding
|
||||
struct drm_color_ctm ctm = {0};
|
||||
for (size_t i = 0; i < 9; i++) {
|
||||
uint64_t v = fabs(matrix[i]) * ((uint64_t)1 << 32);
|
||||
if (matrix[i] < 0) {
|
||||
v |= (uint64_t)1 << 63;
|
||||
}
|
||||
ctm.matrix[i] = v;
|
||||
}
|
||||
|
||||
if (drmModeCreatePropertyBlob(drm->fd, &ctm, sizeof(ctm), blob_id) != 0) {
|
||||
wlr_log_errno(WLR_ERROR, "Unable to create CTM property blob");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool create_fb_damage_clips_blob(struct wlr_drm_backend *drm,
|
||||
int width, int height, const pixman_region32_t *damage, uint32_t *blob_id) {
|
||||
pixman_region32_t clipped;
|
||||
|
|
@ -332,26 +357,39 @@ bool drm_atomic_connector_prepare(struct wlr_drm_connector_state *state, bool mo
|
|||
}
|
||||
|
||||
uint32_t gamma_lut = crtc->gamma_lut;
|
||||
uint32_t ctm = crtc->ctm;
|
||||
if (state->base->committed & WLR_OUTPUT_STATE_COLOR_TRANSFORM) {
|
||||
size_t dim = 0;
|
||||
size_t lut_dim = 0;
|
||||
uint16_t *lut = NULL;
|
||||
const float *matrix = NULL;
|
||||
if (state->crtc_color_transform != NULL) {
|
||||
dim = state->crtc_color_transform->lut_3x1d->dim;
|
||||
lut_dim = state->crtc_color_transform->lut_3x1d->dim;
|
||||
lut = state->crtc_color_transform->lut_3x1d->lut_3x1d;
|
||||
if (state->crtc_color_transform->has_matrix) {
|
||||
matrix = state->crtc_color_transform->matrix;
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback to legacy gamma interface when gamma properties are not
|
||||
// available (can happen on older Intel GPUs that support gamma but not
|
||||
// degamma).
|
||||
if (crtc->props.gamma_lut == 0) {
|
||||
if (!drm_legacy_crtc_set_gamma(drm, crtc, dim, lut)) {
|
||||
if (!drm_legacy_crtc_set_gamma(drm, crtc, lut_dim, lut)) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (!create_gamma_lut_blob(drm, dim, lut, &gamma_lut)) {
|
||||
if (!create_gamma_lut_blob(drm, lut_dim, lut, &gamma_lut)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (matrix != NULL && crtc->props.ctm == 0) {
|
||||
wlr_log(WLR_DEBUG, "CRTC %"PRIu32" doesn't support CTM", crtc->id);
|
||||
return false;
|
||||
}
|
||||
if (!create_ctm_blob(drm, matrix, &ctm)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t fb_damage_clips = 0;
|
||||
|
|
@ -394,6 +432,7 @@ bool drm_atomic_connector_prepare(struct wlr_drm_connector_state *state, bool mo
|
|||
|
||||
state->mode_id = mode_id;
|
||||
state->gamma_lut = gamma_lut;
|
||||
state->ctm = ctm;
|
||||
state->fb_damage_clips = fb_damage_clips;
|
||||
state->primary_in_fence_fd = in_fence_fd;
|
||||
state->vrr_enabled = vrr_enabled;
|
||||
|
|
@ -413,6 +452,7 @@ void drm_atomic_connector_apply_commit(struct wlr_drm_connector_state *state) {
|
|||
crtc->own_mode_id = true;
|
||||
commit_blob(drm, &crtc->mode_id, state->mode_id);
|
||||
commit_blob(drm, &crtc->gamma_lut, state->gamma_lut);
|
||||
commit_blob(drm, &crtc->ctm, state->ctm);
|
||||
commit_blob(drm, &conn->hdr_output_metadata, state->hdr_output_metadata);
|
||||
|
||||
conn->output.adaptive_sync_status = state->vrr_enabled ?
|
||||
|
|
@ -439,6 +479,7 @@ void drm_atomic_connector_rollback_commit(struct wlr_drm_connector_state *state)
|
|||
|
||||
rollback_blob(drm, &crtc->mode_id, state->mode_id);
|
||||
rollback_blob(drm, &crtc->gamma_lut, state->gamma_lut);
|
||||
rollback_blob(drm, &crtc->ctm, state->ctm);
|
||||
rollback_blob(drm, &conn->hdr_output_metadata, state->hdr_output_metadata);
|
||||
|
||||
destroy_blob(drm, state->fb_damage_clips);
|
||||
|
|
@ -543,6 +584,9 @@ static void atomic_connector_add(struct atomic *atom,
|
|||
if (crtc->props.gamma_lut != 0) {
|
||||
atomic_add(atom, crtc->id, crtc->props.gamma_lut, state->gamma_lut);
|
||||
}
|
||||
if (crtc->props.ctm != 0) {
|
||||
atomic_add(atom, crtc->id, crtc->props.ctm, state->ctm);
|
||||
}
|
||||
if (crtc->props.vrr_enabled != 0) {
|
||||
atomic_add(atom, crtc->id, crtc->props.vrr_enabled, state->vrr_enabled);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,12 @@
|
|||
#include "backend/drm/color.h"
|
||||
#include "backend/drm/drm.h"
|
||||
#include "render/color.h"
|
||||
#include "util/matrix.h"
|
||||
|
||||
enum wlr_drm_crtc_color_transform_stage {
|
||||
WLR_DRM_CRTC_COLOR_TRANSFORM_MATRIX,
|
||||
WLR_DRM_CRTC_COLOR_TRANSFORM_LUT_3X1D,
|
||||
};
|
||||
|
||||
static struct wlr_color_transform_lut_3x1d *create_identity_3x1dlut(size_t dim) {
|
||||
if (dim == 0) {
|
||||
|
|
@ -21,8 +27,21 @@ static struct wlr_color_transform_lut_3x1d *create_identity_3x1dlut(size_t dim)
|
|||
return color_transform_lut_3x1d_from_base(out);
|
||||
}
|
||||
|
||||
static bool set_stage(enum wlr_drm_crtc_color_transform_stage *current,
|
||||
enum wlr_drm_crtc_color_transform_stage next) {
|
||||
// Enforce that we fill the pipeline in order: first CTM then GAMMA_LUT
|
||||
if (*current > next) {
|
||||
return false;
|
||||
}
|
||||
*current = next;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool drm_crtc_color_transform_init_lut_3x1d(struct wlr_drm_crtc_color_transform *out,
|
||||
size_t dim) {
|
||||
enum wlr_drm_crtc_color_transform_stage *stage, size_t dim) {
|
||||
if (!set_stage(stage, WLR_DRM_CRTC_COLOR_TRANSFORM_LUT_3X1D)) {
|
||||
return false;
|
||||
}
|
||||
if (out->lut_3x1d != NULL) {
|
||||
return true;
|
||||
}
|
||||
|
|
@ -31,13 +50,14 @@ static bool drm_crtc_color_transform_init_lut_3x1d(struct wlr_drm_crtc_color_tra
|
|||
}
|
||||
|
||||
static bool drm_crtc_color_transform_convert(struct wlr_drm_crtc_color_transform *out,
|
||||
struct wlr_color_transform *in, size_t lut_3x1d_dim) {
|
||||
struct wlr_color_transform *in, enum wlr_drm_crtc_color_transform_stage *stage,
|
||||
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)) {
|
||||
if (!drm_crtc_color_transform_init_lut_3x1d(out, stage, lut_3x1d_dim)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -58,7 +78,7 @@ static bool drm_crtc_color_transform_convert(struct wlr_drm_crtc_color_transform
|
|||
return false;
|
||||
}
|
||||
|
||||
if (!drm_crtc_color_transform_init_lut_3x1d(out, lut_3x1d_dim)) {
|
||||
if (!drm_crtc_color_transform_init_lut_3x1d(out, stage, lut_3x1d_dim)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -68,15 +88,21 @@ static bool drm_crtc_color_transform_convert(struct wlr_drm_crtc_color_transform
|
|||
}
|
||||
|
||||
return true;
|
||||
case COLOR_TRANSFORM_MATRIX:
|
||||
return false; // TODO: add support for CTM
|
||||
case COLOR_TRANSFORM_MATRIX:;
|
||||
struct wlr_color_transform_matrix *matrix = wl_container_of(in, matrix, base);
|
||||
if (!set_stage(stage, WLR_DRM_CRTC_COLOR_TRANSFORM_MATRIX)) {
|
||||
return false;
|
||||
}
|
||||
wlr_matrix_multiply(out->matrix, matrix->matrix, out->matrix);
|
||||
out->has_matrix = true;
|
||||
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)) {
|
||||
if (!drm_crtc_color_transform_convert(out, pipeline->transforms[i], stage, lut_3x1d_dim)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
@ -109,9 +135,11 @@ static struct wlr_drm_crtc_color_transform *drm_crtc_color_transform_create(
|
|||
|
||||
tr->base = base;
|
||||
wlr_addon_init(&tr->addon, &base->addons, crtc, &addon_impl);
|
||||
wlr_matrix_identity(tr->matrix);
|
||||
|
||||
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);
|
||||
enum wlr_drm_crtc_color_transform_stage stage = WLR_DRM_CRTC_COLOR_TRANSFORM_MATRIX;
|
||||
tr->failed = !drm_crtc_color_transform_convert(tr, base, &stage, lut_3x1d_dim);
|
||||
|
||||
return tr;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -391,6 +391,9 @@ void finish_drm_resources(struct wlr_drm_backend *drm) {
|
|||
if (crtc->gamma_lut) {
|
||||
drmModeDestroyPropertyBlob(drm->fd, crtc->gamma_lut);
|
||||
}
|
||||
if (crtc->ctm) {
|
||||
drmModeDestroyPropertyBlob(drm->fd, crtc->ctm);
|
||||
}
|
||||
}
|
||||
|
||||
free(drm->crtcs);
|
||||
|
|
|
|||
|
|
@ -328,6 +328,9 @@ static bool add_connector(drmModeAtomicReq *req,
|
|||
if (crtc->props.gamma_lut != 0) {
|
||||
ok = ok && add_prop(req, crtc->id, crtc->props.gamma_lut, state->gamma_lut);
|
||||
}
|
||||
if (crtc->props.ctm != 0) {
|
||||
ok = ok && add_prop(req, crtc->id, crtc->props.ctm, state->ctm);
|
||||
}
|
||||
if (crtc->props.vrr_enabled != 0) {
|
||||
ok = ok && add_prop(req, crtc->id, crtc->props.vrr_enabled, state->vrr_enabled);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ static const struct prop_info connector_info[] = {
|
|||
static const struct prop_info crtc_info[] = {
|
||||
#define INDEX(name) (offsetof(struct wlr_drm_crtc_props, name) / sizeof(uint32_t))
|
||||
{ "ACTIVE", INDEX(active) },
|
||||
{ "CTM", INDEX(ctm) },
|
||||
{ "GAMMA_LUT", INDEX(gamma_lut) },
|
||||
{ "GAMMA_LUT_SIZE", INDEX(gamma_lut_size) },
|
||||
{ "MODE_ID", INDEX(mode_id) },
|
||||
|
|
|
|||
|
|
@ -12,6 +12,8 @@ struct wlr_drm_crtc_color_transform {
|
|||
struct wlr_addon addon; // wlr_color_transform.addons
|
||||
bool failed;
|
||||
struct wlr_color_transform_lut_3x1d *lut_3x1d;
|
||||
float matrix[9];
|
||||
bool has_matrix;
|
||||
};
|
||||
|
||||
struct wlr_drm_crtc_color_transform *drm_crtc_color_transform_import(
|
||||
|
|
|
|||
|
|
@ -76,6 +76,7 @@ struct wlr_drm_crtc {
|
|||
bool own_mode_id;
|
||||
uint32_t mode_id;
|
||||
uint32_t gamma_lut;
|
||||
uint32_t ctm;
|
||||
|
||||
// Legacy only
|
||||
int legacy_gamma_size;
|
||||
|
|
@ -159,6 +160,7 @@ struct wlr_drm_connector_state {
|
|||
// used by atomic
|
||||
uint32_t mode_id;
|
||||
uint32_t gamma_lut;
|
||||
uint32_t ctm;
|
||||
uint32_t fb_damage_clips;
|
||||
int primary_in_fence_fd, out_fence_fd;
|
||||
bool vrr_enabled;
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ struct wlr_drm_crtc_props {
|
|||
uint32_t vrr_enabled;
|
||||
uint32_t gamma_lut;
|
||||
uint32_t gamma_lut_size;
|
||||
uint32_t ctm;
|
||||
|
||||
// atomic-modesetting only
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue