mirror of
https://gitlab.freedesktop.org/wlroots/wlroots.git
synced 2026-06-13 14:32:57 -04:00
Merge branch 'kms-plane-color-pipeline' into 'master'
Draft: backend/drm: add support for plane color pipelines See merge request wlroots/wlroots!5220
This commit is contained in:
commit
e3a6813e38
11 changed files with 549 additions and 36 deletions
|
|
@ -292,6 +292,237 @@ static uint64_t pick_max_bpc(struct wlr_drm_connector *conn, struct wlr_drm_fb *
|
|||
return target_bpc;
|
||||
}
|
||||
|
||||
/** Convert a double to S31.32 sign-magnitude format */
|
||||
static uint64_t to_fixed_s31_32(double v) {
|
||||
uint64_t u = fabs(v) * ((uint64_t)1 << 32);
|
||||
if (v < 0) {
|
||||
u |= (uint64_t)1 << 63;
|
||||
}
|
||||
return u;
|
||||
}
|
||||
|
||||
enum colorop_setup_status {
|
||||
COLOROP_SETUP_SUCCESS,
|
||||
COLOROP_SETUP_FAILURE,
|
||||
COLOROP_SETUP_INCOMPATIBLE,
|
||||
};
|
||||
|
||||
static enum colorop_setup_status setup_inverse_eotf_colorop(struct wlr_drm_backend *drm,
|
||||
struct wlr_drm_colorop *colorop,
|
||||
struct wlr_color_transform_inverse_eotf *inv_eotf,
|
||||
struct wlr_drm_colorop_state *state) {
|
||||
if (colorop->type != DRM_COLOROP_1D_CURVE) {
|
||||
return COLOROP_SETUP_INCOMPATIBLE;
|
||||
}
|
||||
|
||||
enum wlr_drm_colorop_curve_1d_type type = (uint32_t)-1;
|
||||
switch (inv_eotf->tf) {
|
||||
case WLR_COLOR_TRANSFER_FUNCTION_SRGB:
|
||||
type = WLR_DRM_COLOROP_1D_CURVE_SRGB_INV_EOTF;
|
||||
break;
|
||||
case WLR_COLOR_TRANSFER_FUNCTION_ST2084_PQ:
|
||||
break; // TODO: account for 125x scale
|
||||
case WLR_COLOR_TRANSFER_FUNCTION_EXT_LINEAR:
|
||||
if (!colorop->props.bypass) {
|
||||
return COLOROP_SETUP_INCOMPATIBLE;
|
||||
}
|
||||
state->bypass = true;
|
||||
return COLOROP_SETUP_SUCCESS;
|
||||
case WLR_COLOR_TRANSFER_FUNCTION_GAMMA22:
|
||||
type = WLR_DRM_COLOROP_1D_CURVE_GAMMA22_INV;
|
||||
break;
|
||||
case WLR_COLOR_TRANSFER_FUNCTION_BT1886:
|
||||
break; // not supported by KMS yet
|
||||
}
|
||||
assert(type != (uint32_t)-1);
|
||||
|
||||
if (!(colorop->curve_1d_types & (1 << type))) {
|
||||
return COLOROP_SETUP_INCOMPATIBLE;
|
||||
}
|
||||
|
||||
state->curve_1d_type = type;
|
||||
return COLOROP_SETUP_SUCCESS;
|
||||
}
|
||||
|
||||
static enum colorop_setup_status setup_matrix_colorop(struct wlr_drm_backend *drm,
|
||||
struct wlr_drm_colorop *colorop,
|
||||
const struct wlr_color_transform_matrix *tr_matrix,
|
||||
struct wlr_drm_colorop_state *state) {
|
||||
if (colorop->type != DRM_COLOROP_CTM_3X4) {
|
||||
return COLOROP_SETUP_INCOMPATIBLE;
|
||||
}
|
||||
const float *matrix = tr_matrix->matrix;
|
||||
struct drm_color_ctm_3x4 data = {
|
||||
.matrix = {
|
||||
to_fixed_s31_32(matrix[0]), to_fixed_s31_32(matrix[1]), to_fixed_s31_32(matrix[2]), 0,
|
||||
to_fixed_s31_32(matrix[3]), to_fixed_s31_32(matrix[4]), to_fixed_s31_32(matrix[5]), 0,
|
||||
to_fixed_s31_32(matrix[6]), to_fixed_s31_32(matrix[7]), to_fixed_s31_32(matrix[8]), 0,
|
||||
},
|
||||
};
|
||||
uint32_t blob_id = 0;
|
||||
if (drmModeCreatePropertyBlob(drm->fd, &data, sizeof(data), &blob_id) != 0) {
|
||||
wlr_log_errno(WLR_ERROR, "Failed to create DATA property");
|
||||
return COLOROP_SETUP_FAILURE;
|
||||
}
|
||||
state->data = blob_id;
|
||||
return COLOROP_SETUP_SUCCESS;
|
||||
}
|
||||
|
||||
static enum colorop_setup_status setup_lut_3x1d_colorop(struct wlr_drm_backend *drm,
|
||||
struct wlr_drm_colorop *colorop,
|
||||
const struct wlr_color_transform_lut_3x1d *lut_3x1d,
|
||||
struct wlr_drm_colorop_state *state) {
|
||||
if (colorop->type != DRM_COLOROP_1D_LUT || colorop->size != lut_3x1d->dim) {
|
||||
return COLOROP_SETUP_INCOMPATIBLE;
|
||||
}
|
||||
|
||||
size_t size = lut_3x1d->dim * sizeof(struct drm_color_lut32);
|
||||
struct drm_color_lut32 *data = malloc(size);
|
||||
if (data == NULL) {
|
||||
return COLOROP_SETUP_FAILURE;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < lut_3x1d->dim; i++) {
|
||||
uint32_t factor = UINT32_MAX / UINT16_MAX;
|
||||
data[i] = (struct drm_color_lut32){
|
||||
.red = lut_3x1d->lut_3x1d[0 * lut_3x1d->dim + i] * factor,
|
||||
.green = lut_3x1d->lut_3x1d[1 * lut_3x1d->dim + i] * factor,
|
||||
.blue = lut_3x1d->lut_3x1d[2 * lut_3x1d->dim + i] * factor,
|
||||
};
|
||||
}
|
||||
|
||||
uint32_t blob_id = 0;
|
||||
int ret = drmModeCreatePropertyBlob(drm->fd, data, size, &blob_id);
|
||||
free(data);
|
||||
if (ret != 0) {
|
||||
wlr_log_errno(WLR_ERROR, "Failed to create DATA property");
|
||||
return COLOROP_SETUP_FAILURE;
|
||||
}
|
||||
|
||||
state->data = blob_id;
|
||||
return COLOROP_SETUP_SUCCESS;
|
||||
}
|
||||
|
||||
static enum colorop_setup_status setup_colorop(struct wlr_drm_backend *drm,
|
||||
struct wlr_drm_colorop *colorop, struct wlr_color_transform *tr,
|
||||
struct wlr_drm_colorop_state *state) {
|
||||
switch (tr->type) {
|
||||
case COLOR_TRANSFORM_INVERSE_EOTF:;
|
||||
struct wlr_color_transform_inverse_eotf *inv_eotf =
|
||||
wl_container_of(tr, inv_eotf, base);
|
||||
return setup_inverse_eotf_colorop(drm, colorop, inv_eotf, state);
|
||||
case COLOR_TRANSFORM_LCMS2:
|
||||
return COLOROP_SETUP_INCOMPATIBLE; // TODO: setup 3D LUT
|
||||
case COLOR_TRANSFORM_LUT_3X1D:;
|
||||
struct wlr_color_transform_lut_3x1d *lut_3x1d =
|
||||
wl_container_of(tr, lut_3x1d, base);
|
||||
return setup_lut_3x1d_colorop(drm, colorop, lut_3x1d, state);
|
||||
case COLOR_TRANSFORM_MATRIX:;
|
||||
struct wlr_color_transform_matrix *matrix =
|
||||
wl_container_of(tr, matrix, base);
|
||||
return setup_matrix_colorop(drm, colorop, matrix, state);
|
||||
case COLOR_TRANSFORM_PIPELINE:
|
||||
break; // nested pipelines are not supported
|
||||
}
|
||||
return COLOROP_SETUP_INCOMPATIBLE;
|
||||
}
|
||||
|
||||
static enum colorop_setup_status setup_color_pipeline(struct wlr_drm_backend *drm,
|
||||
struct wl_list *pipeline, struct wlr_color_transform **transforms,
|
||||
size_t transforms_len, struct wl_array *out_state_arr) {
|
||||
struct wl_array state_arr = {0};
|
||||
|
||||
size_t i = 0;
|
||||
struct wlr_drm_colorop *colorop;
|
||||
wl_list_for_each(colorop, pipeline, link) {
|
||||
struct wlr_drm_colorop_state *state = wl_array_add(&state_arr, sizeof(*state));
|
||||
if (state == NULL) {
|
||||
wl_array_release(&state_arr);
|
||||
return COLOROP_SETUP_FAILURE;
|
||||
}
|
||||
state->colorop = colorop;
|
||||
|
||||
enum colorop_setup_status status = COLOROP_SETUP_INCOMPATIBLE;
|
||||
if (i < transforms_len) {
|
||||
status = setup_colorop(drm, colorop, transforms[i], state);
|
||||
}
|
||||
switch (status) {
|
||||
case COLOROP_SETUP_SUCCESS:
|
||||
i++;
|
||||
break;
|
||||
case COLOROP_SETUP_FAILURE:
|
||||
return status;
|
||||
case COLOROP_SETUP_INCOMPATIBLE:
|
||||
if (!colorop->props.bypass) {
|
||||
wl_array_release(&state_arr);
|
||||
return COLOROP_SETUP_INCOMPATIBLE;
|
||||
}
|
||||
state->bypass = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (i < transforms_len) {
|
||||
wl_array_release(&state_arr);
|
||||
return COLOROP_SETUP_INCOMPATIBLE;
|
||||
}
|
||||
|
||||
*out_state_arr = state_arr;
|
||||
return COLOROP_SETUP_SUCCESS;
|
||||
}
|
||||
|
||||
static bool pick_plane_color_pipeline(struct wlr_drm_backend *drm,
|
||||
struct wlr_drm_plane *plane, struct wlr_drm_connector_state *state,
|
||||
uint32_t *out_pipeline_id) {
|
||||
struct wlr_color_transform *base_tr = state->base->pre_color_transform;
|
||||
struct wlr_color_transform *tr = NULL;
|
||||
if (!color_transform_compose(&tr, &base_tr, 1)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (tr == NULL) {
|
||||
*out_pipeline_id = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
struct wlr_color_transform **transforms;
|
||||
size_t transforms_len;
|
||||
if (tr->type == COLOR_TRANSFORM_PIPELINE) {
|
||||
struct wlr_color_transform_pipeline *tr_pipeline =
|
||||
wl_container_of(tr, tr_pipeline, base);
|
||||
transforms = tr_pipeline->transforms;
|
||||
transforms_len = tr_pipeline->len;
|
||||
} else {
|
||||
transforms = &tr;
|
||||
transforms_len = 1;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < plane->color_pipelines_len; i++) {
|
||||
struct wl_list *pipeline = &plane->color_pipelines[i];
|
||||
struct wl_array colorops = {0};
|
||||
enum colorop_setup_status status =
|
||||
setup_color_pipeline(drm, pipeline, transforms, transforms_len, &colorops);
|
||||
switch (status) {
|
||||
case COLOROP_SETUP_SUCCESS:;
|
||||
struct wlr_drm_colorop *colorop =
|
||||
wl_container_of(&pipeline->next, colorop, link);
|
||||
*out_pipeline_id = colorop->id;
|
||||
assert(state->colorops.size == 0);
|
||||
state->colorops = colorops;
|
||||
wlr_color_transform_unref(tr);
|
||||
return true;
|
||||
case COLOROP_SETUP_FAILURE:
|
||||
wlr_color_transform_unref(tr);
|
||||
return false;
|
||||
case COLOROP_SETUP_INCOMPATIBLE:
|
||||
break; // try the next pipeline
|
||||
}
|
||||
}
|
||||
|
||||
wlr_color_transform_unref(tr);
|
||||
return false;
|
||||
}
|
||||
|
||||
static void destroy_blob(struct wlr_drm_backend *drm, uint32_t id) {
|
||||
if (id == 0) {
|
||||
return;
|
||||
|
|
@ -332,12 +563,12 @@ bool drm_atomic_connector_prepare(struct wlr_drm_connector_state *state, bool mo
|
|||
}
|
||||
|
||||
uint32_t gamma_lut = crtc->gamma_lut;
|
||||
if (state->base->committed & WLR_OUTPUT_STATE_COLOR_TRANSFORM) {
|
||||
if (state->base->committed & WLR_OUTPUT_STATE_POST_COLOR_TRANSFORM) {
|
||||
size_t dim = 0;
|
||||
uint16_t *lut = NULL;
|
||||
if (state->base->color_transform != NULL) {
|
||||
if (state->base->post_color_transform != NULL) {
|
||||
struct wlr_color_transform_lut_3x1d *tr =
|
||||
color_transform_lut_3x1d_from_base(state->base->color_transform);
|
||||
color_transform_lut_3x1d_from_base(state->base->post_color_transform);
|
||||
dim = tr->dim;
|
||||
lut = tr->lut_3x1d;
|
||||
}
|
||||
|
|
@ -356,6 +587,13 @@ bool drm_atomic_connector_prepare(struct wlr_drm_connector_state *state, bool mo
|
|||
}
|
||||
}
|
||||
|
||||
uint32_t primary_color_pipeline = crtc->primary->color_pipeline;
|
||||
if (state->base->committed & WLR_OUTPUT_STATE_PRE_COLOR_TRANSFORM) {
|
||||
if (!pick_plane_color_pipeline(drm, crtc->primary, state, &primary_color_pipeline)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t fb_damage_clips = 0;
|
||||
if ((state->base->committed & WLR_OUTPUT_STATE_DAMAGE) &&
|
||||
crtc->primary->props.fb_damage_clips != 0) {
|
||||
|
|
@ -401,6 +639,7 @@ bool drm_atomic_connector_prepare(struct wlr_drm_connector_state *state, bool mo
|
|||
state->vrr_enabled = vrr_enabled;
|
||||
state->colorspace = colorspace;
|
||||
state->hdr_output_metadata = hdr_output_metadata;
|
||||
state->primary_color_pipeline = primary_color_pipeline;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -426,6 +665,13 @@ void drm_atomic_connector_apply_commit(struct wlr_drm_connector_state *state) {
|
|||
}
|
||||
|
||||
conn->colorspace = state->colorspace;
|
||||
crtc->primary->color_pipeline = state->primary_color_pipeline;
|
||||
|
||||
struct wlr_drm_colorop_state *colorop_state;
|
||||
wl_array_for_each(colorop_state, &state->colorops) {
|
||||
commit_blob(drm, &colorop_state->colorop->data, colorop_state->data);
|
||||
}
|
||||
wl_array_release(&state->colorops);
|
||||
}
|
||||
|
||||
void drm_atomic_connector_rollback_commit(struct wlr_drm_connector_state *state) {
|
||||
|
|
@ -441,6 +687,12 @@ void drm_atomic_connector_rollback_commit(struct wlr_drm_connector_state *state)
|
|||
if (state->primary_in_fence_fd >= 0) {
|
||||
close(state->primary_in_fence_fd);
|
||||
}
|
||||
|
||||
struct wlr_drm_colorop_state *colorop_state;
|
||||
wl_array_for_each(colorop_state, &state->colorops) {
|
||||
destroy_blob(drm, colorop_state->data);
|
||||
}
|
||||
wl_array_release(&state->colorops);
|
||||
}
|
||||
|
||||
static void plane_disable(struct atomic *atom, struct wlr_drm_plane *plane) {
|
||||
|
|
@ -596,6 +848,10 @@ static void atomic_connector_add(struct atomic *atom,
|
|||
if (state->primary_in_fence_fd >= 0) {
|
||||
set_plane_in_fence_fd(atom, crtc->primary, state->primary_in_fence_fd);
|
||||
}
|
||||
if (crtc->primary->props.color_pipeline != 0) {
|
||||
atomic_add(atom, crtc->primary->id,
|
||||
crtc->primary->props.color_pipeline, state->primary_color_pipeline);
|
||||
}
|
||||
if (crtc->cursor) {
|
||||
if (drm_connector_is_cursor_visible(conn)) {
|
||||
struct wlr_fbox cursor_src = {
|
||||
|
|
@ -620,6 +876,23 @@ static void atomic_connector_add(struct atomic *atom,
|
|||
plane_disable(atom, crtc->cursor);
|
||||
}
|
||||
}
|
||||
|
||||
struct wlr_drm_colorop_state *colorop_state;
|
||||
wl_array_for_each(colorop_state, &state->colorops) {
|
||||
struct wlr_drm_colorop *colorop = colorop_state->colorop;
|
||||
if (colorop->props.bypass != 0) {
|
||||
atomic_add(atom, colorop->id, colorop->props.bypass,
|
||||
colorop_state->bypass);
|
||||
}
|
||||
if (colorop->props.curve_1d_type != 0) {
|
||||
atomic_add(atom, colorop->id, colorop->props.curve_1d_type,
|
||||
colorop_state->curve_1d_type);
|
||||
}
|
||||
if (colorop->props.data != 0) {
|
||||
atomic_add(atom, colorop->id, colorop->props.data,
|
||||
colorop_state->data);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
plane_disable(atom, crtc->primary);
|
||||
if (crtc->cursor) {
|
||||
|
|
|
|||
|
|
@ -42,7 +42,8 @@ static const uint32_t COMMIT_OUTPUT_STATE =
|
|||
WLR_OUTPUT_STATE_LAYERS |
|
||||
WLR_OUTPUT_STATE_WAIT_TIMELINE |
|
||||
WLR_OUTPUT_STATE_SIGNAL_TIMELINE |
|
||||
WLR_OUTPUT_STATE_COLOR_TRANSFORM |
|
||||
WLR_OUTPUT_STATE_PRE_COLOR_TRANSFORM |
|
||||
WLR_OUTPUT_STATE_POST_COLOR_TRANSFORM |
|
||||
WLR_OUTPUT_STATE_IMAGE_DESCRIPTION |
|
||||
WLR_OUTPUT_STATE_COLOR_REPRESENTATION;
|
||||
|
||||
|
|
@ -158,6 +159,86 @@ static bool init_plane_cursor_sizes(struct wlr_drm_plane *plane,
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool init_color_pipeline(struct wlr_drm_backend *drm,
|
||||
uint32_t head_id, struct wl_list *list) {
|
||||
uint32_t id = head_id;
|
||||
while (id != 0) {
|
||||
struct wlr_drm_colorop *colorop = calloc(1, sizeof(*colorop));
|
||||
if (colorop == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
colorop->id = id;
|
||||
wl_list_insert(list->prev, &colorop->link);
|
||||
|
||||
if (!get_drm_colorop_props(drm->fd, id, &colorop->props)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint64_t type = 0, next = 0;
|
||||
if (!get_drm_prop(drm->fd, id, colorop->props.type, &type) ||
|
||||
!get_drm_prop(drm->fd, id, colorop->props.next, &next)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
colorop->type = (uint32_t)type;
|
||||
|
||||
switch (type) {
|
||||
case DRM_COLOROP_1D_LUT:
|
||||
case DRM_COLOROP_3D_LUT:;
|
||||
uint64_t size = 0;
|
||||
if (!get_drm_prop(drm->fd, id, colorop->props.size, &size)) {
|
||||
return false;
|
||||
}
|
||||
colorop->size = size;
|
||||
break;
|
||||
case DRM_COLOROP_1D_CURVE:
|
||||
if (!introspect_drm_prop_enum(drm->fd, colorop->props.curve_1d_type,
|
||||
&colorop->curve_1d_types)) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
id = (uint32_t)next;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool init_plane_color_pipelines(struct wlr_drm_backend *drm,
|
||||
struct wlr_drm_plane *plane) {
|
||||
if (plane->props.color_pipeline == 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
drmModePropertyRes *prop = drmModeGetProperty(drm->fd, plane->props.color_pipeline);
|
||||
if (prop == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
plane->color_pipelines = calloc(prop->count_enums, sizeof(plane->color_pipelines[0]));
|
||||
if (plane->color_pipelines == NULL) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
for (int i = 0; i < prop->count_enums; i++) {
|
||||
wl_list_init(&plane->color_pipelines[i]);
|
||||
plane->color_pipelines_len++;
|
||||
|
||||
if (!init_color_pipeline(drm, prop->enums[i].value, &plane->color_pipelines[i])) {
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
drmModeFreeProperty(prop);
|
||||
return true;
|
||||
|
||||
error:
|
||||
drmModeFreeProperty(prop);
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool init_plane(struct wlr_drm_backend *drm,
|
||||
struct wlr_drm_plane *p, const drmModePlane *drm_plane) {
|
||||
uint32_t id = drm_plane->plane_id;
|
||||
|
|
@ -240,6 +321,10 @@ static bool init_plane(struct wlr_drm_backend *drm,
|
|||
}
|
||||
}
|
||||
|
||||
if (!init_plane_color_pipelines(drm, p)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
assert(drm->num_crtcs <= 32);
|
||||
for (size_t j = 0; j < drm->num_crtcs; j++) {
|
||||
uint32_t crtc_bit = 1 << j;
|
||||
|
|
@ -383,6 +468,14 @@ static void drm_plane_finish_surface(struct wlr_drm_plane *plane) {
|
|||
finish_drm_surface(&plane->mgpu_surf);
|
||||
}
|
||||
|
||||
static void finish_color_pipeline(struct wl_list *list) {
|
||||
struct wlr_drm_colorop *colorop, *tmp;
|
||||
wl_list_for_each_safe(colorop, tmp, list, link) {
|
||||
wl_list_remove(&colorop->link);
|
||||
free(colorop);
|
||||
}
|
||||
}
|
||||
|
||||
void finish_drm_resources(struct wlr_drm_backend *drm) {
|
||||
if (!drm) {
|
||||
return;
|
||||
|
|
@ -407,9 +500,15 @@ void finish_drm_resources(struct wlr_drm_backend *drm) {
|
|||
|
||||
for (size_t i = 0; i < drm->num_planes; ++i) {
|
||||
struct wlr_drm_plane *plane = &drm->planes[i];
|
||||
|
||||
drm_plane_finish_surface(plane);
|
||||
wlr_drm_format_set_finish(&plane->formats);
|
||||
free(plane->cursor_sizes);
|
||||
|
||||
for (size_t j = 0; j < plane->color_pipelines_len; j++) {
|
||||
finish_color_pipeline(&plane->color_pipelines[j]);
|
||||
}
|
||||
free(plane->color_pipelines);
|
||||
}
|
||||
|
||||
free(drm->planes);
|
||||
|
|
@ -880,8 +979,8 @@ 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) {
|
||||
if ((state->committed & WLR_OUTPUT_STATE_POST_COLOR_TRANSFORM) && state->post_color_transform != NULL &&
|
||||
state->post_color_transform->type != COLOR_TRANSFORM_LUT_3X1D) {
|
||||
wlr_drm_conn_log(conn, WLR_DEBUG,
|
||||
"Only 3x1D LUT color transforms are supported");
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -79,6 +79,12 @@ static bool legacy_crtc_test(const struct wlr_drm_connector_state *state,
|
|||
}
|
||||
}
|
||||
|
||||
if (state->base->committed & WLR_OUTPUT_STATE_PRE_COLOR_TRANSFORM) {
|
||||
wlr_drm_conn_log(conn, WLR_DEBUG,
|
||||
"Pre-blending color pipeline not supported for legacy KMS API");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -125,12 +131,12 @@ static bool legacy_crtc_commit(const struct wlr_drm_connector_state *state,
|
|||
}
|
||||
}
|
||||
|
||||
if (state->base->committed & WLR_OUTPUT_STATE_COLOR_TRANSFORM) {
|
||||
if (state->base->committed & WLR_OUTPUT_STATE_POST_COLOR_TRANSFORM) {
|
||||
size_t dim = 0;
|
||||
uint16_t *lut = NULL;
|
||||
if (state->base->color_transform != NULL) {
|
||||
if (state->base->post_color_transform != NULL) {
|
||||
struct wlr_color_transform_lut_3x1d *tr =
|
||||
color_transform_lut_3x1d_from_base(state->base->color_transform);
|
||||
color_transform_lut_3x1d_from_base(state->base->post_color_transform);
|
||||
dim = tr->dim;
|
||||
lut = tr->lut_3x1d;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -51,6 +51,7 @@ static const struct prop_info crtc_info[] = {
|
|||
static const struct prop_info plane_info[] = {
|
||||
#define INDEX(name) (offsetof(struct wlr_drm_plane_props, name) / sizeof(uint32_t))
|
||||
{ "COLOR_ENCODING", INDEX(color_encoding) },
|
||||
{ "COLOR_PIPELINE", INDEX(color_pipeline) },
|
||||
{ "COLOR_RANGE", INDEX(color_range) },
|
||||
{ "CRTC_H", INDEX(crtc_h) },
|
||||
{ "CRTC_ID", INDEX(crtc_id) },
|
||||
|
|
@ -73,6 +74,18 @@ static const struct prop_info plane_info[] = {
|
|||
#undef INDEX
|
||||
};
|
||||
|
||||
static const struct prop_info colorop_info[] = {
|
||||
#define INDEX(name) (offsetof(struct wlr_drm_colorop_props, name) / sizeof(uint32_t))
|
||||
{ "BYPASS", INDEX(bypass) },
|
||||
{ "CURVE_1D_TYPE", INDEX(curve_1d_type) },
|
||||
{ "DATA", INDEX(data) },
|
||||
{ "MULTIPLIER", INDEX(multiplier) },
|
||||
{ "NEXT", INDEX(next) },
|
||||
{ "SIZE", INDEX(size) },
|
||||
{ "TYPE", INDEX(type) },
|
||||
#undef INDEX
|
||||
};
|
||||
|
||||
static int cmp_prop_info(const void *arg1, const void *arg2) {
|
||||
const char *key = arg1;
|
||||
const struct prop_info *elem = arg2;
|
||||
|
|
@ -123,6 +136,11 @@ bool get_drm_plane_props(int fd, uint32_t id, struct wlr_drm_plane_props *out) {
|
|||
plane_info, sizeof(plane_info) / sizeof(plane_info[0]));
|
||||
}
|
||||
|
||||
bool get_drm_colorop_props(int fd, uint32_t id, struct wlr_drm_colorop_props *out) {
|
||||
return scan_properties(fd, id, DRM_MODE_OBJECT_COLOROP, (uint32_t *)out,
|
||||
colorop_info, sizeof(colorop_info) / sizeof(colorop_info[0]));
|
||||
}
|
||||
|
||||
bool get_drm_prop(int fd, uint32_t obj, uint32_t prop, uint64_t *ret) {
|
||||
drmModeObjectProperties *props =
|
||||
drmModeObjectGetProperties(fd, obj, DRM_MODE_OBJECT_ANY);
|
||||
|
|
@ -216,3 +234,25 @@ bool introspect_drm_prop_range(int fd, uint32_t prop_id,
|
|||
drmModeFreeProperty(prop);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool introspect_drm_prop_enum(int fd, uint32_t prop_id, uint64_t *bitmask) {
|
||||
drmModePropertyRes *prop = drmModeGetProperty(fd, prop_id);
|
||||
if (!prop) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (drmModeGetPropertyType(prop) != DRM_MODE_PROP_ENUM) {
|
||||
drmModeFreeProperty(prop);
|
||||
return false;
|
||||
}
|
||||
|
||||
*bitmask = 0;
|
||||
for (int i = 0; i < prop->count_enums; i++) {
|
||||
uint64_t value = prop->enums[i].value;
|
||||
assert(value < 64);
|
||||
*bitmask |= 1 << value;
|
||||
}
|
||||
|
||||
drmModeFreeProperty(prop);
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,6 +20,18 @@ struct wlr_drm_viewport {
|
|||
struct wlr_box dst_box;
|
||||
};
|
||||
|
||||
struct wlr_drm_colorop {
|
||||
uint32_t id;
|
||||
uint32_t type; // enum drm_colorop_type
|
||||
uint32_t size; // for 1D_LUT, 3D_LUT
|
||||
uint64_t curve_1d_types; // for 1D_CURVE, bitmask of 1 << WLR_DRM_COLOROP_1D_CURVE_*
|
||||
|
||||
struct wlr_drm_colorop_props props;
|
||||
struct wl_list link; // wlr_drm_plane.color_pipelines
|
||||
|
||||
uint32_t data; // for 1D_LUT, CTM_3X4, 3D_LUT
|
||||
};
|
||||
|
||||
struct wlr_drm_plane {
|
||||
uint32_t type;
|
||||
uint32_t id;
|
||||
|
|
@ -43,11 +55,17 @@ struct wlr_drm_plane {
|
|||
struct wlr_output_cursor_size *cursor_sizes;
|
||||
size_t cursor_sizes_len;
|
||||
|
||||
struct wl_list *color_pipelines; // wlr_drm_colorop.link
|
||||
size_t color_pipelines_len;
|
||||
|
||||
struct wlr_drm_plane_props props;
|
||||
|
||||
uint32_t initial_crtc_id;
|
||||
struct liftoff_plane *liftoff;
|
||||
struct liftoff_layer *liftoff_layer;
|
||||
|
||||
// Atomic modesetting only
|
||||
uint32_t color_pipeline;
|
||||
};
|
||||
|
||||
struct wlr_drm_layer {
|
||||
|
|
@ -164,6 +182,15 @@ struct wlr_drm_connector_state {
|
|||
bool vrr_enabled;
|
||||
uint32_t colorspace;
|
||||
uint32_t hdr_output_metadata;
|
||||
uint32_t primary_color_pipeline;
|
||||
struct wl_array colorops; // struct wlr_drm_colorop_state
|
||||
};
|
||||
|
||||
struct wlr_drm_colorop_state {
|
||||
struct wlr_drm_colorop *colorop;
|
||||
bool bypass;
|
||||
uint32_t curve_1d_type; // for 1D_CURVE
|
||||
uint32_t data; // for 1D_LUT, CTM_3X4, 3D_LUT
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -68,6 +68,7 @@ struct wlr_drm_plane_props {
|
|||
|
||||
uint32_t color_encoding; // Not guaranteed to exist
|
||||
uint32_t color_range; // Not guaranteed to exist
|
||||
uint32_t color_pipeline; // Not guaranteed to exist
|
||||
};
|
||||
|
||||
// Equivalent to wlr_drm_color_encoding defined in the kernel (but not exported)
|
||||
|
|
@ -83,10 +84,33 @@ enum wlr_drm_color_range {
|
|||
WLR_DRM_COLOR_YCBCR_LIMITED_RANGE,
|
||||
};
|
||||
|
||||
// Equivalent to drm_colorop_curve_1d_type defined in the kernel (but not exported)
|
||||
enum wlr_drm_colorop_curve_1d_type {
|
||||
WLR_DRM_COLOROP_1D_CURVE_SRGB_EOTF,
|
||||
WLR_DRM_COLOROP_1D_CURVE_SRGB_INV_EOTF,
|
||||
WLR_DRM_COLOROP_1D_CURVE_PQ_125_EOTF,
|
||||
WLR_DRM_COLOROP_1D_CURVE_PQ_125_INV_EOTF,
|
||||
WLR_DRM_COLOROP_1D_CURVE_BT2020_INV_OETF,
|
||||
WLR_DRM_COLOROP_1D_CURVE_BT2020_OETF,
|
||||
WLR_DRM_COLOROP_1D_CURVE_GAMMA22,
|
||||
WLR_DRM_COLOROP_1D_CURVE_GAMMA22_INV,
|
||||
};
|
||||
|
||||
struct wlr_drm_colorop_props {
|
||||
uint32_t type;
|
||||
uint32_t next;
|
||||
uint32_t bypass;
|
||||
uint32_t data; // for 1D_LUT, CTM_3X4, 3D_LUT
|
||||
uint32_t size; // for 1D_LUT, 3D_LUT
|
||||
uint32_t curve_1d_type; // for 1D_CURVE
|
||||
uint32_t multiplier; // for MULTIPLIER
|
||||
};
|
||||
|
||||
bool get_drm_connector_props(int fd, uint32_t id,
|
||||
struct wlr_drm_connector_props *out);
|
||||
bool get_drm_crtc_props(int fd, uint32_t id, struct wlr_drm_crtc_props *out);
|
||||
bool get_drm_plane_props(int fd, uint32_t id, struct wlr_drm_plane_props *out);
|
||||
bool get_drm_colorop_props(int fd, uint32_t id, struct wlr_drm_colorop_props *out);
|
||||
|
||||
bool get_drm_prop(int fd, uint32_t obj, uint32_t prop, uint64_t *ret);
|
||||
void *get_drm_prop_blob(int fd, uint32_t obj, uint32_t prop, size_t *ret_len);
|
||||
|
|
@ -94,5 +118,6 @@ char *get_drm_prop_enum(int fd, uint32_t obj, uint32_t prop);
|
|||
|
||||
bool introspect_drm_prop_range(int fd, uint32_t prop_id,
|
||||
uint64_t *min, uint64_t *max);
|
||||
bool introspect_drm_prop_enum(int fd, uint32_t prop_id, uint64_t *bitmask);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -75,9 +75,10 @@ enum wlr_output_state_field {
|
|||
WLR_OUTPUT_STATE_LAYERS = 1 << 9,
|
||||
WLR_OUTPUT_STATE_WAIT_TIMELINE = 1 << 10,
|
||||
WLR_OUTPUT_STATE_SIGNAL_TIMELINE = 1 << 11,
|
||||
WLR_OUTPUT_STATE_COLOR_TRANSFORM = 1 << 12,
|
||||
WLR_OUTPUT_STATE_POST_COLOR_TRANSFORM = 1 << 12,
|
||||
WLR_OUTPUT_STATE_IMAGE_DESCRIPTION = 1 << 13,
|
||||
WLR_OUTPUT_STATE_COLOR_REPRESENTATION = 1 << 14,
|
||||
WLR_OUTPUT_STATE_PRE_COLOR_TRANSFORM = 1 << 15,
|
||||
};
|
||||
|
||||
enum wlr_output_state_mode_type {
|
||||
|
|
@ -162,7 +163,10 @@ struct wlr_output_state {
|
|||
struct wlr_drm_syncobj_timeline *signal_timeline;
|
||||
uint64_t signal_point;
|
||||
|
||||
struct wlr_color_transform *color_transform;
|
||||
// Pre-blending color transform
|
||||
struct wlr_color_transform *pre_color_transform;
|
||||
// Post-blending color transform
|
||||
struct wlr_color_transform *post_color_transform;
|
||||
|
||||
struct wlr_output_image_description *image_description;
|
||||
};
|
||||
|
|
@ -276,7 +280,8 @@ struct wlr_output {
|
|||
struct {
|
||||
struct wl_listener display_destroy;
|
||||
struct wlr_output_image_description image_description_value;
|
||||
struct wlr_color_transform *color_transform;
|
||||
struct wlr_color_transform *pre_color_transform;
|
||||
struct wlr_color_transform *post_color_transform;
|
||||
struct wlr_color_primaries default_primaries_value;
|
||||
} WLR_PRIVATE;
|
||||
};
|
||||
|
|
@ -619,11 +624,18 @@ void wlr_output_state_set_wait_timeline(struct wlr_output_state *state,
|
|||
void wlr_output_state_set_signal_timeline(struct wlr_output_state *state,
|
||||
struct wlr_drm_syncobj_timeline *timeline, uint64_t dst_point);
|
||||
/**
|
||||
* Set the color transform for an output.
|
||||
* Set the pre-blending color transform for an output.
|
||||
*
|
||||
* The color transform is applied before blending output layers.
|
||||
*/
|
||||
void wlr_output_state_set_pre_color_transform(struct wlr_output_state *state,
|
||||
struct wlr_color_transform *tr);
|
||||
/**
|
||||
* Set the post-blending color transform for an output.
|
||||
*
|
||||
* The color transform is applied after blending output layers.
|
||||
*/
|
||||
void wlr_output_state_set_color_transform(struct wlr_output_state *state,
|
||||
void wlr_output_state_set_post_color_transform(struct wlr_output_state *state,
|
||||
struct wlr_color_transform *tr);
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -252,12 +252,21 @@ static void output_apply_state(struct wlr_output *output,
|
|||
}
|
||||
}
|
||||
|
||||
if (state->committed & WLR_OUTPUT_STATE_COLOR_TRANSFORM) {
|
||||
wlr_color_transform_unref(output->color_transform);
|
||||
if (state->color_transform != NULL) {
|
||||
output->color_transform = wlr_color_transform_ref(state->color_transform);
|
||||
if (state->committed & WLR_OUTPUT_STATE_PRE_COLOR_TRANSFORM) {
|
||||
wlr_color_transform_unref(output->pre_color_transform);
|
||||
if (state->pre_color_transform != NULL) {
|
||||
output->pre_color_transform = wlr_color_transform_ref(state->pre_color_transform);
|
||||
} else {
|
||||
output->color_transform = NULL;
|
||||
output->pre_color_transform = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (state->committed & WLR_OUTPUT_STATE_POST_COLOR_TRANSFORM) {
|
||||
wlr_color_transform_unref(output->post_color_transform);
|
||||
if (state->post_color_transform != NULL) {
|
||||
output->post_color_transform = wlr_color_transform_ref(state->post_color_transform);
|
||||
} else {
|
||||
output->post_color_transform = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -426,7 +435,8 @@ void wlr_output_finish(struct wlr_output *output) {
|
|||
|
||||
wlr_swapchain_destroy(output->cursor_swapchain);
|
||||
wlr_buffer_unlock(output->cursor_front_buffer);
|
||||
wlr_color_transform_unref(output->color_transform);
|
||||
wlr_color_transform_unref(output->pre_color_transform);
|
||||
wlr_color_transform_unref(output->post_color_transform);
|
||||
|
||||
wlr_swapchain_destroy(output->swapchain);
|
||||
|
||||
|
|
@ -581,9 +591,13 @@ static uint32_t output_compare_state(struct wlr_output *output,
|
|||
output->subpixel == state->subpixel) {
|
||||
fields |= WLR_OUTPUT_STATE_SUBPIXEL;
|
||||
}
|
||||
if ((state->committed & WLR_OUTPUT_STATE_COLOR_TRANSFORM) &&
|
||||
output->color_transform == state->color_transform) {
|
||||
fields |= WLR_OUTPUT_STATE_COLOR_TRANSFORM;
|
||||
if ((state->committed & WLR_OUTPUT_STATE_PRE_COLOR_TRANSFORM) &&
|
||||
output->pre_color_transform == state->pre_color_transform) {
|
||||
fields |= WLR_OUTPUT_STATE_PRE_COLOR_TRANSFORM;
|
||||
}
|
||||
if ((state->committed & WLR_OUTPUT_STATE_POST_COLOR_TRANSFORM) &&
|
||||
output->post_color_transform == state->post_color_transform) {
|
||||
fields |= WLR_OUTPUT_STATE_POST_COLOR_TRANSFORM;
|
||||
}
|
||||
if ((state->committed & WLR_OUTPUT_STATE_COLOR_REPRESENTATION) &&
|
||||
output->color_encoding == state->color_encoding &&
|
||||
|
|
@ -685,7 +699,8 @@ static bool output_basic_test(struct wlr_output *output,
|
|||
{ WLR_OUTPUT_STATE_ADAPTIVE_SYNC_ENABLED, "adaptive sync" },
|
||||
{ WLR_OUTPUT_STATE_RENDER_FORMAT, "render format" },
|
||||
{ WLR_OUTPUT_STATE_SUBPIXEL, "subpixel" },
|
||||
{ WLR_OUTPUT_STATE_COLOR_TRANSFORM, "color transform" },
|
||||
{ WLR_OUTPUT_STATE_PRE_COLOR_TRANSFORM, "pre color transform" },
|
||||
{ WLR_OUTPUT_STATE_POST_COLOR_TRANSFORM, "post color transform" },
|
||||
{ WLR_OUTPUT_STATE_IMAGE_DESCRIPTION, "image description" },
|
||||
};
|
||||
if (!enabled) {
|
||||
|
|
|
|||
|
|
@ -19,7 +19,8 @@ void wlr_output_state_finish(struct wlr_output_state *state) {
|
|||
pixman_region32_fini(&state->damage);
|
||||
wlr_drm_syncobj_timeline_unref(state->wait_timeline);
|
||||
wlr_drm_syncobj_timeline_unref(state->signal_timeline);
|
||||
wlr_color_transform_unref(state->color_transform);
|
||||
wlr_color_transform_unref(state->pre_color_transform);
|
||||
wlr_color_transform_unref(state->post_color_transform);
|
||||
free(state->image_description);
|
||||
}
|
||||
|
||||
|
|
@ -113,14 +114,25 @@ void wlr_output_state_set_signal_timeline(struct wlr_output_state *state,
|
|||
state->signal_point = dst_point;
|
||||
}
|
||||
|
||||
void wlr_output_state_set_color_transform(struct wlr_output_state *state,
|
||||
void wlr_output_state_set_pre_color_transform(struct wlr_output_state *state,
|
||||
struct wlr_color_transform *tr) {
|
||||
state->committed |= WLR_OUTPUT_STATE_COLOR_TRANSFORM;
|
||||
wlr_color_transform_unref(state->color_transform);
|
||||
state->committed |= WLR_OUTPUT_STATE_PRE_COLOR_TRANSFORM;
|
||||
wlr_color_transform_unref(state->pre_color_transform);
|
||||
if (tr) {
|
||||
state->color_transform = wlr_color_transform_ref(tr);
|
||||
state->pre_color_transform = wlr_color_transform_ref(tr);
|
||||
} else {
|
||||
state->color_transform = NULL;
|
||||
state->pre_color_transform = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void wlr_output_state_set_post_color_transform(struct wlr_output_state *state,
|
||||
struct wlr_color_transform *tr) {
|
||||
state->committed |= WLR_OUTPUT_STATE_POST_COLOR_TRANSFORM;
|
||||
wlr_color_transform_unref(state->post_color_transform);
|
||||
if (tr) {
|
||||
state->post_color_transform = wlr_color_transform_ref(tr);
|
||||
} else {
|
||||
state->post_color_transform = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -156,7 +168,7 @@ bool wlr_output_state_copy(struct wlr_output_state *dst,
|
|||
WLR_OUTPUT_STATE_DAMAGE |
|
||||
WLR_OUTPUT_STATE_WAIT_TIMELINE |
|
||||
WLR_OUTPUT_STATE_SIGNAL_TIMELINE |
|
||||
WLR_OUTPUT_STATE_COLOR_TRANSFORM |
|
||||
WLR_OUTPUT_STATE_POST_COLOR_TRANSFORM |
|
||||
WLR_OUTPUT_STATE_IMAGE_DESCRIPTION);
|
||||
copy.buffer = NULL;
|
||||
copy.buffer_src_box = (struct wlr_fbox){0};
|
||||
|
|
@ -164,7 +176,8 @@ bool wlr_output_state_copy(struct wlr_output_state *dst,
|
|||
pixman_region32_init(©.damage);
|
||||
copy.wait_timeline = NULL;
|
||||
copy.signal_timeline = NULL;
|
||||
copy.color_transform = NULL;
|
||||
copy.pre_color_transform = NULL;
|
||||
copy.post_color_transform = NULL;
|
||||
copy.image_description = NULL;
|
||||
|
||||
if (src->committed & WLR_OUTPUT_STATE_BUFFER) {
|
||||
|
|
@ -186,8 +199,11 @@ bool wlr_output_state_copy(struct wlr_output_state *dst,
|
|||
src->signal_point);
|
||||
}
|
||||
|
||||
if (src->committed & WLR_OUTPUT_STATE_COLOR_TRANSFORM) {
|
||||
wlr_output_state_set_color_transform(©, src->color_transform);
|
||||
if (src->committed & WLR_OUTPUT_STATE_PRE_COLOR_TRANSFORM) {
|
||||
wlr_output_state_set_pre_color_transform(©, src->pre_color_transform);
|
||||
}
|
||||
if (src->committed & WLR_OUTPUT_STATE_POST_COLOR_TRANSFORM) {
|
||||
wlr_output_state_set_post_color_transform(©, src->post_color_transform);
|
||||
}
|
||||
if (src->committed & WLR_OUTPUT_STATE_IMAGE_DESCRIPTION) {
|
||||
if (!wlr_output_state_set_image_description(©, src->image_description)) {
|
||||
|
|
|
|||
|
|
@ -2180,7 +2180,7 @@ static void scene_output_state_attempt_gamma(struct wlr_scene_output *scene_outp
|
|||
return;
|
||||
}
|
||||
|
||||
wlr_output_state_set_color_transform(&gamma_pending, scene_output->gamma_lut_color_transform);
|
||||
wlr_output_state_set_post_color_transform(&gamma_pending, scene_output->gamma_lut_color_transform);
|
||||
scene_output->gamma_lut_changed = false;
|
||||
|
||||
if (!wlr_output_test_state(scene_output->output, &gamma_pending)) {
|
||||
|
|
|
|||
|
|
@ -288,7 +288,7 @@ bool wlr_gamma_control_v1_apply(struct wlr_gamma_control_v1 *gamma_control,
|
|||
}
|
||||
}
|
||||
|
||||
wlr_output_state_set_color_transform(output_state, tr);
|
||||
wlr_output_state_set_post_color_transform(output_state, tr);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue