mirror of
https://gitlab.freedesktop.org/wayland/weston.git
synced 2026-05-07 03:48:02 +02:00
Merge branch 'offload-pre-blend' into 'main'
Introduce support to KMS color pipelines to offload pre-blend xform See merge request wayland/weston!1702
This commit is contained in:
commit
229743ca53
19 changed files with 2158 additions and 181 deletions
|
|
@ -4076,9 +4076,13 @@ load_drm_backend(struct weston_compositor *c, int *argc, char **argv,
|
|||
weston_config_section_get_bool(section, "offload-blend-to-output",
|
||||
&offload_blend_to_output, false);
|
||||
|
||||
if (!c->color_manager && offload_blend_to_output)
|
||||
if (!c->color_manager)
|
||||
offload_blend_to_output = false;
|
||||
|
||||
#if !CAN_OFFLOAD_COLOR_PIPELINE
|
||||
offload_blend_to_output = false;
|
||||
#endif
|
||||
|
||||
config.offload_blend_to_output = offload_blend_to_output;
|
||||
|
||||
weston_config_section_get_string(section,
|
||||
|
|
|
|||
1322
libweston/backend-drm/colorops.c
Normal file
1322
libweston/backend-drm/colorops.c
Normal file
File diff suppressed because it is too large
Load diff
204
libweston/backend-drm/colorops.h
Normal file
204
libweston/backend-drm/colorops.h
Normal file
|
|
@ -0,0 +1,204 @@
|
|||
/*
|
||||
* Copyright © 2025-2026 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "drm-internal.h"
|
||||
#include "drm-kms-enums.h"
|
||||
|
||||
struct drm_colorop_clut_blob {
|
||||
/* drm_device::drm_colorop_clut_blob_list */
|
||||
struct wl_list link;
|
||||
struct drm_device *device;
|
||||
|
||||
/* Lifetime matches the xform. */
|
||||
struct weston_color_transform *xform;
|
||||
struct wl_listener destroy_listener;
|
||||
|
||||
uint32_t shaper_len;
|
||||
uint32_t clut_len;
|
||||
|
||||
uint32_t shaper_blob_id;
|
||||
uint32_t clut_blob_id;
|
||||
};
|
||||
|
||||
struct drm_colorop_matrix_blob {
|
||||
/* drm_device::drm_colorop_matrix_blob_list */
|
||||
struct wl_list link;
|
||||
struct drm_device *device;
|
||||
|
||||
/* Lifetime matches the xform. */
|
||||
struct weston_color_transform *xform;
|
||||
struct wl_listener destroy_listener;
|
||||
|
||||
uint32_t blob_id;
|
||||
};
|
||||
|
||||
struct drm_colorop {
|
||||
struct drm_color_pipeline *pipeline;
|
||||
struct wl_list link; /* drm_pipeline::colorop_list */
|
||||
|
||||
enum wdrm_colorop_type type;
|
||||
|
||||
uint32_t id;
|
||||
|
||||
/* Some colorop's can be bypassed. */
|
||||
bool can_bypass;
|
||||
|
||||
/* Only useful for 1D and 3D LUT colorop's. */
|
||||
uint32_t size;
|
||||
|
||||
/* Holds the properties for the colorop. */
|
||||
struct drm_property_info props[WDRM_COLOROP__COUNT];
|
||||
};
|
||||
|
||||
enum colorop_object_type {
|
||||
COLOROP_OBJECT_TYPE_CURVE = 0,
|
||||
COLOROP_OBJECT_TYPE_MATRIX,
|
||||
COLOROP_OBJECT_TYPE_3x1D_LUT,
|
||||
COLOROP_OBJECT_TYPE_3D_LUT,
|
||||
COLOROP_OBJECT_TYPE_MULTIPLIER,
|
||||
};
|
||||
|
||||
struct drm_colorop_state_object {
|
||||
/* Defines which of the below is valid. The others are zero. */
|
||||
enum colorop_object_type type;
|
||||
|
||||
uint64_t curve_type_prop_val;
|
||||
uint32_t matrix_blob_id;
|
||||
uint32_t lut_3x1d_blob_id;
|
||||
uint32_t lut_3d_blob_id;
|
||||
uint64_t multiplier;
|
||||
};
|
||||
|
||||
struct drm_colorop_state {
|
||||
struct drm_colorop *colorop;
|
||||
/* struct drm_color_pipeline_state::colorop_state_list */
|
||||
struct wl_list link;
|
||||
|
||||
/* Object that should be programmed through the colorop. */
|
||||
struct drm_colorop_state_object object;
|
||||
};
|
||||
|
||||
struct drm_color_pipeline {
|
||||
struct drm_plane *plane;
|
||||
struct wl_list colorop_list; /* drm_colorop::link */
|
||||
uint32_t id;
|
||||
};
|
||||
|
||||
struct drm_color_pipeline_state {
|
||||
struct drm_color_pipeline *pipeline;
|
||||
|
||||
/* struct drm_colorop_state::link */
|
||||
struct wl_list colorop_state_list;
|
||||
};
|
||||
|
||||
#if CAN_OFFLOAD_COLOR_PIPELINE
|
||||
|
||||
void
|
||||
drm_color_pipeline_state_destroy(struct drm_color_pipeline_state *state);
|
||||
|
||||
struct drm_color_pipeline_state *
|
||||
drm_color_pipeline_state_from_xform(struct drm_plane *plane,
|
||||
struct weston_color_transform *xform,
|
||||
const char *indent);
|
||||
|
||||
struct drm_colorop_3x1d_lut_blob *
|
||||
drm_colorop_3x1d_lut_blob_create(struct drm_device *device,
|
||||
struct weston_color_transform *xform,
|
||||
enum weston_color_curve_step curve_step,
|
||||
enum drm_colorop_3x1d_lut_blob_quantization quantization,
|
||||
struct weston_vec3f *cm_lut, uint32_t lut_len);
|
||||
|
||||
struct drm_colorop_3x1d_lut_blob *
|
||||
drm_colorop_3x1d_lut_blob_search(struct drm_device *device,
|
||||
struct weston_color_transform *xform,
|
||||
enum weston_color_curve_step curve_step,
|
||||
enum drm_colorop_3x1d_lut_blob_quantization quantization,
|
||||
uint32_t lut_len);
|
||||
|
||||
const char *
|
||||
drm_colorop_type_to_str(struct drm_colorop *colorop);
|
||||
|
||||
void
|
||||
drm_plane_populate_color_pipelines(struct drm_plane *plane,
|
||||
drmModeObjectPropertiesPtr plane_props);
|
||||
|
||||
void
|
||||
drm_plane_release_color_pipelines(struct drm_plane *plane);
|
||||
|
||||
#else /* CAN_OFFLOAD_COLOR_PIPELINE */
|
||||
|
||||
static inline void
|
||||
drm_color_pipeline_state_destroy(struct drm_color_pipeline_state *state)
|
||||
{
|
||||
}
|
||||
|
||||
static inline struct drm_color_pipeline_state *
|
||||
drm_color_pipeline_state_from_xform(struct drm_plane *plane,
|
||||
struct weston_color_transform *xform,
|
||||
const char *indent)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline struct drm_colorop_3x1d_lut_blob *
|
||||
drm_colorop_3x1d_lut_blob_create(struct drm_device *device,
|
||||
struct weston_color_transform *xform,
|
||||
enum weston_color_curve_step curve_step,
|
||||
enum drm_colorop_3x1d_lut_blob_quantization quantization,
|
||||
struct weston_vec3f *cm_lut, uint32_t lut_len)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline struct drm_colorop_3x1d_lut_blob *
|
||||
drm_colorop_3x1d_lut_blob_search(struct drm_device *device,
|
||||
struct weston_color_transform *xform,
|
||||
enum weston_color_curve_step curve_step,
|
||||
enum drm_colorop_3x1d_lut_blob_quantization quantization,
|
||||
uint32_t lut_len)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline const char *
|
||||
drm_colorop_type_to_str(struct drm_colorop *colorop)
|
||||
{
|
||||
return "undefined";
|
||||
}
|
||||
|
||||
static inline void
|
||||
drm_plane_populate_color_pipelines(struct drm_plane *plane,
|
||||
drmModeObjectPropertiesPtr plane_props)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void
|
||||
drm_plane_release_color_pipelines(struct drm_plane *plane)
|
||||
{
|
||||
}
|
||||
|
||||
#endif /* CAN_OFFLOAD_COLOR_PIPELINE */
|
||||
|
|
@ -27,6 +27,8 @@
|
|||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <errno.h>
|
||||
|
|
@ -227,6 +229,8 @@ struct drm_device {
|
|||
|
||||
bool aspect_ratio_supported;
|
||||
|
||||
bool color_pipeline_supported;
|
||||
|
||||
int32_t cursor_width;
|
||||
int32_t cursor_height;
|
||||
|
||||
|
|
@ -247,8 +251,12 @@ struct drm_device {
|
|||
/* drm_backend::kms_list */
|
||||
struct wl_list link;
|
||||
|
||||
/* struct drm_colorop_3x1d_lut::link */
|
||||
struct wl_list drm_colorop_3x1d_lut_list;
|
||||
/* struct drm_colorop_3x1d_lut_blob::link */
|
||||
struct wl_list drm_colorop_3x1d_lut_blob_list;
|
||||
/* struct drm_colorop_clut_blob::link */
|
||||
struct wl_list drm_colorop_clut_blob_list;
|
||||
/* struct drm_colorop_matrix_blob::link */
|
||||
struct wl_list drm_colorop_matrix_blob_list;
|
||||
|
||||
int reused_state_failures;
|
||||
};
|
||||
|
|
@ -393,6 +401,30 @@ struct drm_output_state {
|
|||
bool planes_enabled;
|
||||
};
|
||||
|
||||
enum drm_colorop_3x1d_lut_blob_quantization {
|
||||
DRM_COLOROP_3X1D_LUT_BLOB_QUANTIZATION_U16 = 0,
|
||||
DRM_COLOROP_3X1D_LUT_BLOB_QUANTIZATION_U32,
|
||||
};
|
||||
|
||||
struct drm_colorop_3x1d_lut_blob {
|
||||
/* drm_device::drm_colorop_3x1d_lut_blob_list */
|
||||
struct wl_list link;
|
||||
struct drm_device *device;
|
||||
|
||||
/* Lifetime matches the xform. */
|
||||
struct weston_color_transform *xform;
|
||||
struct wl_listener destroy_listener;
|
||||
|
||||
/* Which curve of the xform the 3x1D LUT was generated from. */
|
||||
enum weston_color_curve_step curve_step;
|
||||
|
||||
enum drm_colorop_3x1d_lut_blob_quantization quantization;
|
||||
|
||||
uint32_t lut_len;
|
||||
|
||||
uint32_t blob_id;
|
||||
};
|
||||
|
||||
/**
|
||||
* Plane state holds the dynamic state for a plane: where it is positioned,
|
||||
* and which buffer it is currently displaying.
|
||||
|
|
@ -413,6 +445,9 @@ struct drm_plane_state {
|
|||
|
||||
struct weston_paint_node *paint_node; /**< maintained for drm_assign_planes only */
|
||||
|
||||
/* only when a color transformation is being offloaded */
|
||||
struct drm_color_pipeline_state *pipeline_state;
|
||||
|
||||
int32_t src_x, src_y;
|
||||
uint32_t src_w, src_h;
|
||||
int32_t dest_x, dest_y;
|
||||
|
|
@ -477,6 +512,10 @@ struct drm_plane {
|
|||
struct wl_list link;
|
||||
|
||||
struct weston_drm_format_array formats;
|
||||
|
||||
uint32_t pipeline_props_id;
|
||||
uint32_t num_color_pipelines;
|
||||
struct drm_color_pipeline *pipelines;
|
||||
};
|
||||
|
||||
struct drm_plane_handle {
|
||||
|
|
@ -548,19 +587,6 @@ struct drm_writeback {
|
|||
struct weston_drm_format_array formats;
|
||||
};
|
||||
|
||||
struct drm_colorop_3x1d_lut {
|
||||
/* drm_device::drm_colorop_3x1d_lut_list */
|
||||
struct wl_list link;
|
||||
struct drm_device *device;
|
||||
|
||||
uint64_t lut_size;
|
||||
|
||||
struct weston_color_transform *xform;
|
||||
struct wl_listener destroy_listener;
|
||||
|
||||
uint32_t blob_id;
|
||||
};
|
||||
|
||||
struct drm_head {
|
||||
struct weston_head base;
|
||||
struct drm_connector connector;
|
||||
|
|
@ -643,7 +669,7 @@ struct drm_output {
|
|||
|
||||
bool legacy_gamma_not_supported;
|
||||
uint16_t legacy_gamma_size;
|
||||
struct drm_colorop_3x1d_lut *blend_to_output_xform;
|
||||
struct drm_colorop_3x1d_lut_blob *blend_to_output_xform;
|
||||
|
||||
/* Plane being displayed directly on the CRTC */
|
||||
struct drm_plane_handle *scanout_handle;
|
||||
|
|
@ -868,6 +894,7 @@ extern struct drm_property_enum_info content_protection_enums[];
|
|||
extern struct drm_property_enum_info hdcp_content_type_enums[];
|
||||
extern const struct drm_property_info connector_props[];
|
||||
extern const struct drm_property_info crtc_props[];
|
||||
extern const struct drm_property_info colorop_props[];
|
||||
|
||||
int
|
||||
init_kms_caps(struct drm_device *device);
|
||||
|
|
|
|||
|
|
@ -57,6 +57,7 @@ enum wdrm_plane_property {
|
|||
WDRM_PLANE_ROTATION,
|
||||
WDRM_PLANE_ALPHA,
|
||||
WDRM_PLANE_COLOR_ENCODING,
|
||||
WDRM_PLANE_COLOR_PIPELINE,
|
||||
WDRM_PLANE_COLOR_RANGE,
|
||||
WDRM_PLANE__COUNT
|
||||
};
|
||||
|
|
@ -95,6 +96,20 @@ enum wdrm_plane_color_encoding {
|
|||
};
|
||||
#define WDRM_PLANE_COLOR_ENCODING_DEFAULT WDRM_PLANE_COLOR_ENCODING_BT709
|
||||
|
||||
/**
|
||||
* Possible values for the WDRM_PLANE_COLOR_PIPELINE property.
|
||||
*
|
||||
* This property is special: the enum values are not deterministic. Each enum
|
||||
* value corresponds to the id of a colorop created at runtime by the KMS
|
||||
* driver. drm_property_info_populate() expects well-known values for enum
|
||||
* properties, so a dummy value is defined to allow it to populate plane->props
|
||||
* correctly.
|
||||
*/
|
||||
enum wdrm_plane_color_pipeline {
|
||||
WDRM_PLANE_COLOR_PIPELINE_DUMMY = 0,
|
||||
WDRM_PLANE_COLOR_PIPELINE__COUNT
|
||||
};
|
||||
|
||||
/**
|
||||
* Possible values for the WDRM_PLANE_COLOR_RANGE property.
|
||||
*/
|
||||
|
|
@ -105,6 +120,65 @@ enum wdrm_plane_color_range {
|
|||
};
|
||||
#define WDRM_PLANE_COLOR_RANGE_DEFAULT WDRM_PLANE_COLOR_RANGE_LIMITED
|
||||
|
||||
/**
|
||||
* List of properties attached to a DRM colorop.
|
||||
*/
|
||||
enum wdrm_colorop_property {
|
||||
WDRM_COLOROP_TYPE = 0,
|
||||
WDRM_COLOROP_NEXT,
|
||||
WDRM_COLOROP_BYPASS,
|
||||
WDRM_COLOROP_SIZE,
|
||||
WDRM_COLOROP_DATA,
|
||||
WDRM_COLOROP_MULTIPLIER,
|
||||
WDRM_COLOROP_LUT1D_INTERPOLATION,
|
||||
WDRM_COLOROP_LUT3D_INTERPOLATION,
|
||||
WDRM_COLOROP_CURVE_1D,
|
||||
WDRM_COLOROP__COUNT,
|
||||
};
|
||||
|
||||
/**
|
||||
* Possible values for the WDRM_COLOROP_TYPE property.
|
||||
*/
|
||||
enum wdrm_colorop_type {
|
||||
WDRM_COLOROP_TYPE_1D_CURVE = 0,
|
||||
WDRM_COLOROP_TYPE_1D_LUT,
|
||||
WDRM_COLOROP_TYPE_CTM_3X4,
|
||||
WDRM_COLOROP_TYPE_MULTIPLIER,
|
||||
WDRM_COLOROP_TYPE_3D_LUT,
|
||||
WDRM_COLOROP_TYPE__COUNT,
|
||||
};
|
||||
|
||||
/**
|
||||
* Possible values for the WDRM_COLOROP_CURVE_1D property.
|
||||
*/
|
||||
enum wdrm_colorop_curve_1d {
|
||||
WDRM_COLOROP_CURVE_1D_SRGB_EOTF = 0,
|
||||
WDRM_COLOROP_CURVE_1D_SRGB_INV_EOTF,
|
||||
WDRM_COLOROP_CURVE_1D_PQ_125_EOTF,
|
||||
WDRM_COLOROP_CURVE_1D_PQ_125_INV_EOTF,
|
||||
WDRM_COLOROP_CURVE_1D_BT2020_INV_OETF,
|
||||
WDRM_COLOROP_CURVE_1D_BT2020_OETF,
|
||||
WDRM_COLOROP_CURVE_1D_GAMMA_22,
|
||||
WDRM_COLOROP_CURVE_1D_GAMMA_22_INV,
|
||||
WDRM_COLOROP_CURVE_1D__COUNT,
|
||||
};
|
||||
|
||||
/**
|
||||
* Possible values for the WDRM_COLOROP_LUT1D_INTERPOLATION property.
|
||||
*/
|
||||
enum wdrm_colorop_lut1d_interpolation {
|
||||
WDRM_COLOROP_LUT1D_INTERPOLATION_LINEAR = 0,
|
||||
WDRM_COLOROP_LUT1D_INTERPOLATION__COUNT,
|
||||
};
|
||||
|
||||
/**
|
||||
* Possible values for the WDRM_COLOROP_LUT3D_INTERPOLATION property.
|
||||
*/
|
||||
enum wdrm_colorop_lut3d_interpolation {
|
||||
WDRM_COLOROP_LUT3D_INTERPOLATION_TETRAHEDRAL = 0,
|
||||
WDRM_COLOROP_LUT3D_INTERPOLATION__COUNT,
|
||||
};
|
||||
|
||||
/**
|
||||
* List of properties attached to a DRM connector
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -51,6 +51,7 @@
|
|||
#include <libweston/libweston.h>
|
||||
#include <libweston/backend-drm.h>
|
||||
#include <libweston/weston-log.h>
|
||||
#include "colorops.h"
|
||||
#include "drm-internal.h"
|
||||
#include "shared/hash.h"
|
||||
#include "shared/helpers.h"
|
||||
|
|
@ -1485,6 +1486,8 @@ drm_plane_create(struct drm_device *device, const drmModePlane *kplane)
|
|||
goto err;
|
||||
}
|
||||
|
||||
drm_plane_populate_color_pipelines(plane, props);
|
||||
|
||||
drmModeFreeObjectProperties(props);
|
||||
|
||||
if (plane->type == WDRM_PLANE_TYPE__COUNT)
|
||||
|
|
@ -1588,6 +1591,7 @@ drm_plane_destroy(struct drm_plane *plane)
|
|||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
|
||||
drm_plane_state_free(plane->state_cur, true);
|
||||
drm_property_info_free(plane->props, WDRM_PLANE__COUNT);
|
||||
drm_plane_release_color_pipelines(plane);
|
||||
weston_plane_release(&plane->base);
|
||||
weston_drm_format_array_fini(&plane->formats);
|
||||
wl_list_remove(&plane->link);
|
||||
|
|
@ -2231,62 +2235,6 @@ drm_output_init_legacy_gamma_size(struct drm_output *output)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
drm_colorop_3x1d_lut_destroy(struct drm_colorop_3x1d_lut *lut)
|
||||
{
|
||||
wl_list_remove(&lut->destroy_listener.link);
|
||||
wl_list_remove(&lut->link);
|
||||
drmModeDestroyPropertyBlob(lut->device->kms_device->fd, lut->blob_id);
|
||||
free(lut);
|
||||
}
|
||||
|
||||
static void
|
||||
drm_colorop_3x1d_lut_destroy_handler(struct wl_listener *l, void *data)
|
||||
{
|
||||
struct drm_colorop_3x1d_lut *lut;
|
||||
|
||||
lut = wl_container_of(l, lut, destroy_listener);
|
||||
assert(lut->xform == data);
|
||||
|
||||
drm_colorop_3x1d_lut_destroy(lut);
|
||||
}
|
||||
|
||||
static struct drm_colorop_3x1d_lut *
|
||||
drm_colorop_3x1d_lut_search(struct drm_device *device,
|
||||
struct weston_color_transform *xform,
|
||||
uint64_t lut_size)
|
||||
{
|
||||
struct drm_colorop_3x1d_lut *colorop_lut;
|
||||
|
||||
wl_list_for_each(colorop_lut, &device->drm_colorop_3x1d_lut_list, link)
|
||||
if (colorop_lut->xform == xform && colorop_lut->lut_size == lut_size)
|
||||
return colorop_lut;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct drm_colorop_3x1d_lut *
|
||||
drm_colorop_3x1d_lut_create(struct weston_color_transform *xform,
|
||||
struct drm_device *device, uint64_t lut_size,
|
||||
uint32_t blob_id)
|
||||
{
|
||||
struct drm_colorop_3x1d_lut *lut;
|
||||
|
||||
lut = xzalloc(sizeof(*lut));
|
||||
|
||||
lut->device = device;
|
||||
lut->blob_id = blob_id;
|
||||
lut->xform = xform;
|
||||
lut->lut_size = lut_size;
|
||||
|
||||
wl_list_insert(&device->drm_colorop_3x1d_lut_list, &lut->link);
|
||||
|
||||
lut->destroy_listener.notify = drm_colorop_3x1d_lut_destroy_handler;
|
||||
wl_signal_add(&lut->xform->destroy_signal, &lut->destroy_listener);
|
||||
|
||||
return lut;
|
||||
}
|
||||
|
||||
static struct weston_vec3f *
|
||||
lut_3x1d_from_blend_to_output(struct weston_compositor *compositor,
|
||||
struct weston_color_transform *xform,
|
||||
|
|
@ -2295,8 +2243,8 @@ lut_3x1d_from_blend_to_output(struct weston_compositor *compositor,
|
|||
/**
|
||||
* We expect steps to be valid for blend-to-output, as LittleCMS is
|
||||
* always able to optimize such xform. If that's invalid, we'd need to
|
||||
* use to_shaper_plus_3dlut() to offload the xform, but the DRM API
|
||||
* currently only supports us programming a LUT after blending.
|
||||
* use to_clut() to offload the xform, but the DRM API currently only
|
||||
* supports us programming a LUT after blending.
|
||||
*/
|
||||
if (!xform->steps_valid) {
|
||||
str_printf(err_msg, "xform color steps are invalid");
|
||||
|
|
@ -2333,15 +2281,12 @@ drm_output_pick_blend_to_output(struct drm_output *output)
|
|||
struct weston_compositor *compositor = output->base.compositor;
|
||||
struct drm_device *device = output->device;
|
||||
struct drm_backend *b = device->backend;
|
||||
struct drm_colorop_3x1d_lut *colorop_lut;
|
||||
struct drm_colorop_3x1d_lut_blob *colorop_lut;
|
||||
struct weston_color_transform *xform;
|
||||
struct drm_color_lut *drm_lut;
|
||||
size_t lut_size;
|
||||
uint32_t gamma_lut_blob_id;
|
||||
enum weston_color_curve_step curve_step;
|
||||
size_t lut_len;
|
||||
struct weston_vec3f *cm_lut;
|
||||
char *err_msg;
|
||||
unsigned int i;
|
||||
int ret;
|
||||
|
||||
/* Check if there's actually something to offload. */
|
||||
weston_assert_ptr_not_null(compositor, output->base.color_outcome);
|
||||
|
|
@ -2349,23 +2294,32 @@ drm_output_pick_blend_to_output(struct drm_output *output)
|
|||
if (!xform)
|
||||
return 0;
|
||||
|
||||
lut_size = output->crtc->lut_size;
|
||||
if (lut_size == 0) {
|
||||
lut_len = output->crtc->lut_size;
|
||||
if (lut_len == 0) {
|
||||
drm_debug(b, "[output] can't offload blend-to-output: GAMMA_LUT_SIZE unsupported\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* First let's check if the xform has already been cached. If that's the
|
||||
* For now we expect blend-to-output to be composed of pre-curve only,
|
||||
* so lut_3x1d_from_blend_to_output() will return a LUT it creates from
|
||||
* the xform pre-curve.
|
||||
*/
|
||||
curve_step = WESTON_COLOR_CURVE_STEP_PRE;
|
||||
|
||||
/**
|
||||
* First let's check if the LUT has already been cached. If that's the
|
||||
* case, we make use of it.
|
||||
*/
|
||||
colorop_lut = drm_colorop_3x1d_lut_search(device, xform, lut_size);
|
||||
colorop_lut = drm_colorop_3x1d_lut_blob_search(device, xform, curve_step,
|
||||
DRM_COLOROP_3X1D_LUT_BLOB_QUANTIZATION_U16,
|
||||
lut_len);
|
||||
if (colorop_lut) {
|
||||
output->blend_to_output_xform = colorop_lut;
|
||||
return 0;
|
||||
}
|
||||
|
||||
cm_lut = lut_3x1d_from_blend_to_output(compositor, xform, lut_size, &err_msg);
|
||||
cm_lut = lut_3x1d_from_blend_to_output(compositor, xform, lut_len, &err_msg);
|
||||
if (!cm_lut) {
|
||||
drm_debug(b, "[output] failed to create 3x1D LUT for blend-to-output: %s\n",
|
||||
err_msg);
|
||||
|
|
@ -2373,24 +2327,16 @@ drm_output_pick_blend_to_output(struct drm_output *output)
|
|||
return -1;
|
||||
}
|
||||
|
||||
drm_lut = xzalloc(lut_size * sizeof(*drm_lut));
|
||||
for (i = 0; i < lut_size; i++) {
|
||||
drm_lut[i].red = cm_lut[i].r * 0xffff;
|
||||
drm_lut[i].green = cm_lut[i].g * 0xffff;
|
||||
drm_lut[i].blue = cm_lut[i].b * 0xffff;
|
||||
}
|
||||
output->blend_to_output_xform =
|
||||
drm_colorop_3x1d_lut_blob_create(device, xform, curve_step,
|
||||
DRM_COLOROP_3X1D_LUT_BLOB_QUANTIZATION_U16,
|
||||
cm_lut, lut_len);
|
||||
free(cm_lut);
|
||||
ret = drmModeCreatePropertyBlob(device->kms_device->fd, drm_lut, lut_size * sizeof(*drm_lut),
|
||||
&gamma_lut_blob_id);
|
||||
free(drm_lut);
|
||||
if (ret < 0) {
|
||||
drm_debug(b, "[output] failed to create blob for gamma LUT\n");
|
||||
if (!output->blend_to_output_xform) {
|
||||
drm_debug(b, "[output] failed to create colorop 3x1D LUT");
|
||||
return -1;
|
||||
}
|
||||
|
||||
output->blend_to_output_xform =
|
||||
drm_colorop_3x1d_lut_create(xform, device, lut_size,
|
||||
gamma_lut_blob_id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -4200,6 +4146,7 @@ drm_kms_device_destroy(struct drm_kms_device *kms_device)
|
|||
static void
|
||||
drm_device_destroy(struct drm_device *device)
|
||||
{
|
||||
struct weston_compositor *ec = device->backend->compositor;
|
||||
struct drm_crtc *crtc, *crtc_tmp;
|
||||
struct drm_writeback *writeback, *writeback_tmp;
|
||||
|
||||
|
|
@ -4214,7 +4161,9 @@ drm_device_destroy(struct drm_device *device)
|
|||
&device->writeback_connector_list, link)
|
||||
drm_writeback_destroy(writeback);
|
||||
|
||||
weston_assert_true(ec, wl_list_empty(&device->drm_colorop_3x1d_lut_list));
|
||||
weston_assert_list_empty(ec, &device->drm_colorop_3x1d_lut_blob_list);
|
||||
weston_assert_list_empty(ec, &device->drm_colorop_clut_blob_list);
|
||||
weston_assert_list_empty(ec, &device->drm_colorop_matrix_blob_list);
|
||||
|
||||
if (device->drm_event_source)
|
||||
wl_event_source_remove(device->drm_event_source);
|
||||
|
|
@ -4554,7 +4503,9 @@ drm_device_create(struct drm_backend *backend,
|
|||
wl_list_init(&device->plane_list);
|
||||
create_planes(device);
|
||||
|
||||
wl_list_init(&device->drm_colorop_3x1d_lut_list);
|
||||
wl_list_init(&device->drm_colorop_3x1d_lut_blob_list);
|
||||
wl_list_init(&device->drm_colorop_clut_blob_list);
|
||||
wl_list_init(&device->drm_colorop_matrix_blob_list);
|
||||
|
||||
wl_list_init(&device->writeback_connector_list);
|
||||
if (drm_backend_discover_connectors(device, device->kms_device->udev_device, res) < 0) {
|
||||
|
|
|
|||
|
|
@ -37,7 +37,10 @@
|
|||
#include <libweston/libweston.h>
|
||||
#include <libweston/backend-drm.h>
|
||||
#include "shared/helpers.h"
|
||||
#include "shared/string-helpers.h"
|
||||
#include "shared/weston-assert.h"
|
||||
#include "shared/weston-drm-fourcc.h"
|
||||
#include "colorops.h"
|
||||
#include "drm-internal.h"
|
||||
#include "pixel-formats.h"
|
||||
#include "presentation-time-server-protocol.h"
|
||||
|
|
@ -91,6 +94,12 @@ struct drm_property_enum_info plane_color_encoding_enums[] = {
|
|||
},
|
||||
};
|
||||
|
||||
struct drm_property_enum_info plane_color_pipeline_enums[] = {
|
||||
[WDRM_PLANE_COLOR_PIPELINE_DUMMY] = {
|
||||
.name = "dummy",
|
||||
},
|
||||
};
|
||||
|
||||
struct drm_property_enum_info plane_color_range_enums[] = {
|
||||
[WDRM_PLANE_COLOR_RANGE_LIMITED] = {
|
||||
.name = "YCbCr limited range",
|
||||
|
|
@ -131,6 +140,11 @@ const struct drm_property_info plane_props[] = {
|
|||
.enum_values = plane_color_encoding_enums,
|
||||
.num_enum_values = WDRM_PLANE_COLOR_ENCODING__COUNT,
|
||||
},
|
||||
[WDRM_PLANE_COLOR_PIPELINE] = {
|
||||
.name = "COLOR_PIPELINE",
|
||||
.enum_values = plane_color_pipeline_enums,
|
||||
.num_enum_values = WDRM_PLANE_COLOR_PIPELINE__COUNT,
|
||||
},
|
||||
[WDRM_PLANE_COLOR_RANGE] = {
|
||||
.name = "COLOR_RANGE",
|
||||
.enum_values = plane_color_range_enums,
|
||||
|
|
@ -138,6 +152,61 @@ const struct drm_property_info plane_props[] = {
|
|||
},
|
||||
};
|
||||
|
||||
static struct drm_property_enum_info colorop_type_enums[] = {
|
||||
[WDRM_COLOROP_TYPE_1D_CURVE] = { .name = "1D Curve", },
|
||||
[WDRM_COLOROP_TYPE_1D_LUT] = { .name = "1D LUT", },
|
||||
[WDRM_COLOROP_TYPE_CTM_3X4] = { .name = "3x4 Matrix", },
|
||||
[WDRM_COLOROP_TYPE_MULTIPLIER] = { .name = "Multiplier", },
|
||||
[WDRM_COLOROP_TYPE_3D_LUT] = { .name = "3D LUT", },
|
||||
};
|
||||
|
||||
static struct drm_property_enum_info colorop_curve_1d_enums[] = {
|
||||
[WDRM_COLOROP_CURVE_1D_SRGB_EOTF] = { .name = "sRGB EOTF", },
|
||||
[WDRM_COLOROP_CURVE_1D_SRGB_INV_EOTF] = { .name = "sRGB Inverse EOTF", },
|
||||
[WDRM_COLOROP_CURVE_1D_PQ_125_EOTF] = { .name = "PQ 125 EOTF", },
|
||||
[WDRM_COLOROP_CURVE_1D_PQ_125_INV_EOTF] = { .name = "PQ 125 Inverse EOTF", },
|
||||
[WDRM_COLOROP_CURVE_1D_BT2020_INV_OETF] = { .name = "BT.2020 Inverse OETF", },
|
||||
[WDRM_COLOROP_CURVE_1D_BT2020_OETF] = { .name = "BT.2020 OETF", },
|
||||
[WDRM_COLOROP_CURVE_1D_GAMMA_22] = { .name = "Gamma 2.2", },
|
||||
[WDRM_COLOROP_CURVE_1D_GAMMA_22_INV] = { .name = "Gamma 2.2 Inverse", },
|
||||
};
|
||||
|
||||
static struct drm_property_enum_info colorop_lut1d_interpolation_enums[] = {
|
||||
[WDRM_COLOROP_LUT1D_INTERPOLATION_LINEAR] = { .name = "Linear", },
|
||||
};
|
||||
|
||||
static struct drm_property_enum_info colorop_lut3d_interpolation_enums[] = {
|
||||
[WDRM_COLOROP_LUT3D_INTERPOLATION_TETRAHEDRAL] = { .name = "Tetrahedral", },
|
||||
};
|
||||
|
||||
const struct drm_property_info colorop_props[] = {
|
||||
[WDRM_COLOROP_TYPE] = {
|
||||
.name = "TYPE",
|
||||
.enum_values = colorop_type_enums,
|
||||
.num_enum_values = WDRM_COLOROP_TYPE__COUNT,
|
||||
},
|
||||
[WDRM_COLOROP_NEXT] = { .name = "NEXT", },
|
||||
[WDRM_COLOROP_BYPASS] = { .name = "BYPASS", },
|
||||
[WDRM_COLOROP_SIZE] = { .name = "SIZE", },
|
||||
[WDRM_COLOROP_DATA] = { .name = "DATA", },
|
||||
[WDRM_COLOROP_MULTIPLIER] = { .name = "MULTIPLIER", },
|
||||
[WDRM_COLOROP_CURVE_1D] = {
|
||||
.name = "CURVE_1D_TYPE",
|
||||
.enum_values = colorop_curve_1d_enums,
|
||||
.num_enum_values = WDRM_COLOROP_CURVE_1D__COUNT,
|
||||
},
|
||||
[WDRM_COLOROP_LUT1D_INTERPOLATION] = {
|
||||
.name = "LUT1D_INTERPOLATION",
|
||||
.enum_values = colorop_lut1d_interpolation_enums,
|
||||
.num_enum_values = WDRM_COLOROP_LUT1D_INTERPOLATION__COUNT,
|
||||
},
|
||||
[WDRM_COLOROP_LUT3D_INTERPOLATION] = {
|
||||
.name = "LUT3D_INTERPOLATION",
|
||||
.enum_values = colorop_lut3d_interpolation_enums,
|
||||
.num_enum_values = WDRM_COLOROP_LUT3D_INTERPOLATION__COUNT,
|
||||
},
|
||||
};
|
||||
|
||||
struct drm_property_enum_info dpms_state_enums[] = {
|
||||
[WDRM_DPMS_STATE_OFF] = {
|
||||
.name = "Off",
|
||||
|
|
@ -1093,6 +1162,28 @@ plane_add_prop(drmModeAtomicReq *req, struct drm_plane *plane,
|
|||
return (ret <= 0) ? -1 : 0;
|
||||
}
|
||||
|
||||
static int
|
||||
colorop_add_prop(drmModeAtomicReq *req, struct drm_colorop *colorop,
|
||||
enum wdrm_colorop_property prop, uint64_t val)
|
||||
{
|
||||
struct drm_plane *plane = colorop->pipeline->plane;
|
||||
struct drm_device *device = plane->device;
|
||||
struct drm_backend *b = device->backend;
|
||||
struct drm_property_info *info = &colorop->props[prop];
|
||||
int ret;
|
||||
|
||||
drm_debug(b, "\t\t\t[COLOROP:%lu] %lu (%s) -> %llu (0x%llx)\n",
|
||||
(unsigned long) colorop->id,
|
||||
(unsigned long) info->prop_id, info->name,
|
||||
(unsigned long long) val, (unsigned long long) val);
|
||||
|
||||
if (info->prop_id == 0)
|
||||
return -1;
|
||||
|
||||
ret = drmModeAtomicAddProperty(req, colorop->id, info->prop_id, val);
|
||||
return (ret <= 0) ? -1 : 0;
|
||||
}
|
||||
|
||||
static bool
|
||||
drm_connector_has_prop(struct drm_connector *connector,
|
||||
enum wdrm_connector_property prop)
|
||||
|
|
@ -1294,6 +1385,168 @@ drm_plane_set_color_range(struct drm_plane *plane,
|
|||
return plane_add_prop(req, plane, WDRM_PLANE_COLOR_RANGE, color_range);
|
||||
}
|
||||
|
||||
static bool
|
||||
colorop_program(drmModeAtomicReq *req, struct drm_colorop *colorop,
|
||||
enum wdrm_colorop_property colorop_prop,
|
||||
uint64_t prop_val, char **err_msg)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (colorop->can_bypass) {
|
||||
ret = colorop_add_prop(req, colorop, WDRM_COLOROP_BYPASS, 0);
|
||||
if (ret < 0) {
|
||||
str_printf(err_msg, "failed to set colorop id %u bypass == false",
|
||||
colorop->id);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
ret = colorop_add_prop(req, colorop, colorop_prop, prop_val);
|
||||
if (ret < 0) {
|
||||
str_printf(err_msg, "failed to program colorop id %u type %s",
|
||||
colorop->id, drm_colorop_type_to_str(colorop));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
set_interp(drmModeAtomicReq *req, struct drm_colorop *colorop,
|
||||
enum wdrm_colorop_property interp_prop, uint64_t interp_val)
|
||||
{
|
||||
struct drm_property_info *info = &colorop->props[interp_prop];
|
||||
int ret;
|
||||
|
||||
if (info->enum_values[interp_val].valid) {
|
||||
ret = colorop_add_prop(req, colorop, interp_prop, interp_val);
|
||||
if (ret >= 0)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool
|
||||
drm_colorop_program(drmModeAtomicReq *req, struct drm_colorop_state *colorop_state,
|
||||
const char *indent, char **err_msg)
|
||||
{
|
||||
struct drm_colorop *colorop = colorop_state->colorop;
|
||||
struct drm_color_pipeline *pipeline = colorop->pipeline;
|
||||
struct drm_backend *b = pipeline->plane->device->backend;
|
||||
struct weston_compositor *compositor = pipeline->plane->base.compositor;
|
||||
enum wdrm_colorop_property colorop_prop;
|
||||
uint64_t prop_val;
|
||||
|
||||
switch (colorop_state->object.type) {
|
||||
case COLOROP_OBJECT_TYPE_CURVE:
|
||||
colorop_prop = WDRM_COLOROP_CURVE_1D;
|
||||
prop_val = colorop_state->object.curve_type_prop_val;
|
||||
return colorop_program(req, colorop, colorop_prop, prop_val, err_msg);
|
||||
case COLOROP_OBJECT_TYPE_MATRIX:
|
||||
colorop_prop = WDRM_COLOROP_DATA;
|
||||
prop_val = colorop_state->object.matrix_blob_id;
|
||||
return colorop_program(req, colorop, colorop_prop, prop_val, err_msg);
|
||||
case COLOROP_OBJECT_TYPE_3x1D_LUT:
|
||||
if (!set_interp(req, colorop, WDRM_COLOROP_LUT1D_INTERPOLATION,
|
||||
WDRM_COLOROP_LUT1D_INTERPOLATION_LINEAR))
|
||||
drm_debug(b, "%s[colorop] linear LUT1D interpolation not supported or failed to set;\n"
|
||||
"%susing current value set on driver\n", indent, indent);
|
||||
colorop_prop = WDRM_COLOROP_DATA;
|
||||
prop_val = colorop_state->object.lut_3x1d_blob_id;
|
||||
return colorop_program(req, colorop, colorop_prop, prop_val, err_msg);
|
||||
case COLOROP_OBJECT_TYPE_3D_LUT:
|
||||
if (!set_interp(req, colorop, WDRM_COLOROP_LUT3D_INTERPOLATION,
|
||||
WDRM_COLOROP_LUT3D_INTERPOLATION_TETRAHEDRAL))
|
||||
drm_debug(b, "%s[colorop] tetrahedral LUT3D interpolation not supported or failed to set;\n"
|
||||
"%susing current value set on driver\n", indent, indent);
|
||||
colorop_prop = WDRM_COLOROP_DATA;
|
||||
prop_val = colorop_state->object.lut_3d_blob_id;
|
||||
return colorop_program(req, colorop, colorop_prop, prop_val, err_msg);
|
||||
case COLOROP_OBJECT_TYPE_MULTIPLIER:
|
||||
colorop_prop = WDRM_COLOROP_MULTIPLIER;
|
||||
prop_val = colorop_state->object.multiplier;
|
||||
return colorop_program(req, colorop, colorop_prop, prop_val, err_msg);
|
||||
}
|
||||
weston_assert_not_reached(compositor,
|
||||
"unknown drm_colorop_state object type");
|
||||
}
|
||||
|
||||
static struct drm_colorop_state *
|
||||
drm_colorop_state_iter(struct drm_color_pipeline_state *pipeline_state,
|
||||
struct drm_colorop_state *iter)
|
||||
{
|
||||
struct wl_list *list = &pipeline_state->colorop_state_list;
|
||||
struct wl_list *node;
|
||||
|
||||
if (iter)
|
||||
node = iter->link.next;
|
||||
else
|
||||
node = list->next;
|
||||
|
||||
if (node == list)
|
||||
return NULL;
|
||||
|
||||
return container_of(node, struct drm_colorop_state, link);
|
||||
}
|
||||
|
||||
static int
|
||||
drm_color_pipeline_program(drmModeAtomicReq *req,
|
||||
struct drm_color_pipeline_state *pipeline_state,
|
||||
const char *indent)
|
||||
{
|
||||
struct drm_color_pipeline *pipeline = pipeline_state->pipeline;
|
||||
struct drm_plane *plane = pipeline->plane;
|
||||
struct drm_backend *b = plane->device->backend;
|
||||
struct drm_colorop_state *colorop_state;
|
||||
struct drm_colorop *colorop;
|
||||
char *err_msg;
|
||||
int ret_drm;
|
||||
bool ret;
|
||||
|
||||
drm_debug(b, "%s[PLANE:%lu] %lu (%s) -> %llu (0x%llx)\n",
|
||||
indent, (unsigned long) plane->plane_id,
|
||||
(unsigned long) plane->pipeline_props_id, "COLOR_PIPELINE",
|
||||
(unsigned long long) pipeline_state->pipeline->id,
|
||||
(unsigned long long) pipeline_state->pipeline->id);
|
||||
|
||||
colorop_state = drm_colorop_state_iter(pipeline_state,
|
||||
NULL /* previous colorop state (none) */);
|
||||
wl_list_for_each(colorop, &pipeline->colorop_list, link) {
|
||||
/* If a colorop is not in the colorop state list, bypass it. */
|
||||
if (!colorop_state || colorop != colorop_state->colorop) {
|
||||
weston_assert_true(b->compositor, colorop->can_bypass);
|
||||
|
||||
ret_drm = colorop_add_prop(req, colorop, WDRM_COLOROP_BYPASS, 1);
|
||||
if (ret_drm >= 0)
|
||||
continue;
|
||||
|
||||
drm_debug(b, "%s%s[colorop] failed to set colorop id %u bypass == true",
|
||||
indent, indent, colorop->id);
|
||||
goto err;
|
||||
}
|
||||
|
||||
ret = drm_colorop_program(req, colorop_state, indent, &err_msg);
|
||||
if (!ret) {
|
||||
drm_debug(b, "%s%s[colorop] %s\n", indent, indent, err_msg);
|
||||
free(err_msg);
|
||||
goto err;
|
||||
}
|
||||
|
||||
colorop_state = drm_colorop_state_iter(pipeline_state, colorop_state);
|
||||
}
|
||||
weston_assert_ptr_null(b->compositor, colorop_state);
|
||||
|
||||
/* Set plane pipeline. */
|
||||
drmModeAtomicAddProperty(req, plane->plane_id,
|
||||
plane->pipeline_props_id, pipeline->id);
|
||||
return 0;
|
||||
|
||||
err:
|
||||
drm_debug(b, "%s%s[colorop] failed to program pipeline\n", indent, indent);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int
|
||||
drm_output_apply_state_atomic(struct drm_output_state *state,
|
||||
drmModeAtomicReq *req,
|
||||
|
|
@ -1455,6 +1708,16 @@ drm_output_apply_state_atomic(struct drm_output_state *state,
|
|||
ret |= plane_add_prop(req, plane, WDRM_PLANE_FB_DAMAGE_CLIPS,
|
||||
plane_state->damage_blob_id);
|
||||
|
||||
if (plane->props[WDRM_PLANE_COLOR_PIPELINE].prop_id != 0) {
|
||||
if (plane_state->pipeline_state) {
|
||||
ret |= drm_color_pipeline_program(req, plane_state->pipeline_state,
|
||||
"\t\t\t");
|
||||
} else {
|
||||
ret |= plane_add_prop(req, plane,
|
||||
WDRM_PLANE_COLOR_PIPELINE, 0);
|
||||
}
|
||||
}
|
||||
|
||||
if (plane_state->fb && plane_state->fb->format)
|
||||
pinfo = plane_state->fb->format;
|
||||
|
||||
|
|
@ -2079,6 +2342,13 @@ init_kms_caps(struct drm_device *device)
|
|||
|
||||
drmSetClientCap(device->kms_device->fd, DRM_CLIENT_CAP_WRITEBACK_CONNECTORS, 1);
|
||||
|
||||
#ifdef DRM_CLIENT_CAP_PLANE_COLOR_PIPELINE
|
||||
ret = drmSetClientCap(device->kms_device->fd, DRM_CLIENT_CAP_PLANE_COLOR_PIPELINE, 1);
|
||||
device->color_pipeline_supported = (ret == 0);
|
||||
#else
|
||||
device->color_pipeline_supported = false;
|
||||
#endif
|
||||
|
||||
ret = drmGetCap(device->kms_device->fd, DRM_CAP_ATOMIC_ASYNC_PAGE_FLIP, &cap);
|
||||
if (ret == 0)
|
||||
device->tearing_supported = cap;
|
||||
|
|
|
|||
|
|
@ -32,6 +32,10 @@ srcs_drm = [
|
|||
presentation_time_server_protocol_h,
|
||||
]
|
||||
|
||||
if (libdrm_supports_color_pipeline)
|
||||
srcs_drm += 'colorops.c'
|
||||
endif
|
||||
|
||||
deps_drm = [
|
||||
dep_egl, # optional
|
||||
dep_vulkan, # optional
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@
|
|||
#include <xf86drm.h>
|
||||
#include <xf86drmMode.h>
|
||||
|
||||
#include "colorops.h"
|
||||
#include "drm-internal.h"
|
||||
#include "shared/weston-assert.h"
|
||||
#include "shared/weston-drm-fourcc.h"
|
||||
|
|
@ -95,6 +96,8 @@ drm_plane_state_free(struct drm_plane_state *state, bool force)
|
|||
state->in_fence_fd = -1;
|
||||
state->zpos = DRM_PLANE_ZPOS_INVALID_PLANE;
|
||||
state->alpha = DRM_PLANE_ALPHA_OPAQUE;
|
||||
drm_color_pipeline_state_destroy(state->pipeline_state);
|
||||
state->pipeline_state = NULL;
|
||||
|
||||
/* Once the damage blob has been submitted, it is refcounted internally
|
||||
* by the kernel, which means we can safely discard it.
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@
|
|||
#include "drm-internal.h"
|
||||
|
||||
#include "color.h"
|
||||
#include "colorops.h"
|
||||
#include "color-representation.h"
|
||||
#include "linux-dmabuf.h"
|
||||
#include "presentation-time-server-protocol.h"
|
||||
|
|
@ -141,6 +142,21 @@ drm_output_try_paint_node_on_plane(struct drm_plane_handle *handle,
|
|||
state->fb = drm_fb_ref(fb);
|
||||
state->in_fence_fd = surface->acquire_fence_fd;
|
||||
|
||||
drm_color_pipeline_state_destroy(state->pipeline_state);
|
||||
state->pipeline_state = NULL;
|
||||
if (pnode->surf_xform.transform) {
|
||||
state->pipeline_state =
|
||||
drm_color_pipeline_state_from_xform(plane,
|
||||
pnode->surf_xform.transform,
|
||||
"\t\t\t\t");
|
||||
if (!state->pipeline_state) {
|
||||
drm_debug(b, "\t\t\t\t[view] not placing paint node %s on plane %lu: "
|
||||
"not compatible with surface color xform\n",
|
||||
pnode->internal_name, (unsigned long) plane->plane_id);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
if (fb->format && fb->format->color_model == COLOR_MODEL_YUV) {
|
||||
struct weston_color_representation color_rep;
|
||||
const struct weston_color_matrix_coef_info *matrix_coef_info;
|
||||
|
|
@ -584,6 +600,14 @@ pnode_can_use_plane(struct drm_output_state *output_state,
|
|||
return false;
|
||||
}
|
||||
|
||||
/* If we have a surf color xform we need to be able to offload that to KMS. */
|
||||
if (pnode->surf_xform.transform && plane->num_color_pipelines == 0) {
|
||||
drm_debug(b, "\t\t\t\t[plane] not trying plane %d: surf_xform present "
|
||||
"but plane has no color pipelines\n",
|
||||
plane->plane_id);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* If the surface buffer has an in-fence fd, but the plane doesn't
|
||||
* support fences, we can't place the buffer on this plane. */
|
||||
if (pnode->surface->acquire_fence_fd >= 0 &&
|
||||
|
|
@ -1371,8 +1395,8 @@ drm_output_propose_state(struct weston_output *output_base,
|
|||
pnode->try_view_on_plane_failure_reasons |=
|
||||
FAILURE_REASONS_OUTPUT_COLOR_EFFECT;
|
||||
|
||||
if (pnode->surf_xform.transform != NULL ||
|
||||
!pnode->surf_xform.identity_pipeline)
|
||||
if (pnode->surf_xform.transform && (!device->color_pipeline_supported ||
|
||||
!pnode->output->from_blend_to_output_by_backend))
|
||||
pnode->try_view_on_plane_failure_reasons |=
|
||||
FAILURE_REASONS_NO_COLOR_TRANSFORM;
|
||||
|
||||
|
|
|
|||
|
|
@ -417,8 +417,7 @@ lcms_curve_matches_any_tf(struct weston_compositor *compositor,
|
|||
const float lcms_curve_params[3][MAX_PARAMS_LCMS_PARAM_CURVE])
|
||||
{
|
||||
struct weston_color_curve_parametric curve = { 0 };
|
||||
unsigned int i, j;
|
||||
uint32_t n_lcms_curve_params;
|
||||
unsigned int i;
|
||||
|
||||
curve.clamped_input = clamped_input;
|
||||
|
||||
|
|
@ -428,28 +427,34 @@ lcms_curve_matches_any_tf(struct weston_compositor *compositor,
|
|||
* LittleCMS type 1 is the pure power-law curve, which is a
|
||||
* special case of LINPOW. See init_curve_from_type_1().
|
||||
*/
|
||||
n_lcms_curve_params = 1;
|
||||
curve.type = WESTON_COLOR_CURVE_PARAMETRIC_TYPE_LINPOW;
|
||||
for (i = 0; i < 3; i++) {
|
||||
curve.params.chan[i].g = lcms_curve_params[i][0];
|
||||
/* a = 1, b = 0, c = 1, d = 0 */
|
||||
curve.params.chan[i].a = 1.0f;
|
||||
curve.params.chan[i].b = 0.0f;
|
||||
curve.params.chan[i].c = 1.0f;
|
||||
curve.params.chan[i].d = 0.0f;
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
/**
|
||||
* LittleCMS type 4 is almost exactly the same as LINPOW. See
|
||||
* init_curve_from_type_4().
|
||||
*/
|
||||
n_lcms_curve_params = 5;
|
||||
curve.type = WESTON_COLOR_CURVE_PARAMETRIC_TYPE_LINPOW;
|
||||
for (i = 0; i < 3; i++) {
|
||||
curve.params.chan[i].g = lcms_curve_params[i][0];
|
||||
curve.params.chan[i].a = lcms_curve_params[i][1];
|
||||
curve.params.chan[i].b = lcms_curve_params[i][2];
|
||||
curve.params.chan[i].c = lcms_curve_params[i][3];
|
||||
curve.params.chan[i].d = lcms_curve_params[i][4];
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
weston_assert_u32_le(compositor,
|
||||
n_lcms_curve_params, MAX_PARAMS_LCMS_PARAM_CURVE);
|
||||
|
||||
for (i = 0; i < 3; i++)
|
||||
for (j = 0; j < n_lcms_curve_params; j++)
|
||||
curve.params.chan[i].data[j] = lcms_curve_params[i][j];
|
||||
|
||||
return weston_color_tf_info_from_parametric_curve(&curve);
|
||||
}
|
||||
|
||||
|
|
@ -2058,10 +2063,10 @@ cmlcms_color_transform_recipe_string(const struct cmlcms_color_transform_recipe
|
|||
}
|
||||
|
||||
static bool
|
||||
build_3d_lut(struct weston_compositor *compositor,
|
||||
const struct cmlcms_color_transformer *transformer,
|
||||
unsigned int len_shaper, const float *shaper,
|
||||
unsigned int len_lut3d, float *lut3d)
|
||||
build_clut(struct weston_compositor *compositor,
|
||||
const struct cmlcms_color_transformer *transformer,
|
||||
unsigned int len_shaper, const float *shaper,
|
||||
unsigned int len_clut, float *clut)
|
||||
{
|
||||
const float *const red_curve = &shaper[0];
|
||||
const float *const green_curve = &shaper[len_shaper];
|
||||
|
|
@ -2077,27 +2082,26 @@ build_3d_lut(struct weston_compositor *compositor,
|
|||
* Ensure the indices and byte counts cannot overflow,
|
||||
* and memory usage does not get ridiculous. Arbitrary limit.
|
||||
*/
|
||||
weston_assert_u32_lt(compositor, len_lut3d, 100);
|
||||
weston_assert_u32_lt(compositor, len_clut, 100);
|
||||
|
||||
/*
|
||||
* A temporary allocation that holds two 1D LUTs of length len_lut3d
|
||||
* and one scratch array of vec3f of length len_lut3d.
|
||||
* A temporary allocation that holds two 1D LUTs of length len_clut
|
||||
* and one scratch array of vec3f of length len_clut.
|
||||
*/
|
||||
const uint32_t bytes_per_elem = 2 * sizeof (float) + sizeof *rgb_in;
|
||||
tmp = malloc(len_lut3d * bytes_per_elem);
|
||||
tmp = malloc(len_clut * bytes_per_elem);
|
||||
|
||||
inverse_r = &tmp[0];
|
||||
inverse_g = &tmp[len_lut3d];
|
||||
rgb_in = (struct weston_vec3f *)&tmp[2 * len_lut3d];
|
||||
|
||||
inverse_g = &tmp[len_clut];
|
||||
rgb_in = (struct weston_vec3f *)&tmp[2 * len_clut];
|
||||
/*
|
||||
* For each channel, use the shaper to compute the value x such that
|
||||
* y(x) = index / (len - 1). As the shaper is a LUT, we find the closest
|
||||
* neighbors of such point (x, y) and then use linear interpolation to
|
||||
* estimate x.
|
||||
*/
|
||||
for (i = 0; i < len_lut3d; i++) {
|
||||
float y = (float)i / (len_lut3d - 1);
|
||||
for (i = 0; i < len_clut; i++) {
|
||||
float y = (float)i / (len_clut - 1);
|
||||
inverse_r[i] = weston_inverse_evaluate_lut1d(compositor,
|
||||
len_shaper,
|
||||
red_curve,
|
||||
|
|
@ -2109,9 +2113,9 @@ build_3d_lut(struct weston_compositor *compositor,
|
|||
}
|
||||
|
||||
/*
|
||||
* Fill in the 3D LUT: LUT(Rin, Gin, Bin) = { Rout, Gout, Bout }
|
||||
* Fill in the 3D cLUT: LUT(Rin, Gin, Bin) = { Rout, Gout, Bout }
|
||||
* Each of Rin, Gin and Bin varies from 0.0 to 1.0. The range [0.0, 1.0]
|
||||
* is evenly divided into len_lut3d number of sampling points. The
|
||||
* is evenly divided into len_clut number of sampling points. The
|
||||
* indices of the sampling points are index_r, index_g, index_b.
|
||||
*
|
||||
* To compute { Rout, Gout, Bout }, first Rin, Gin, Bin must go through
|
||||
|
|
@ -2121,29 +2125,29 @@ build_3d_lut(struct weston_compositor *compositor,
|
|||
* separable.
|
||||
*
|
||||
* The next step is not separable, so we iterate through all points in
|
||||
* the 3D volume. The points are transformed len_lut3d points at a time
|
||||
* the 3D volume. The points are transformed len_clut points at a time
|
||||
* (rgb_in array) to strike a balance between the number of function
|
||||
* calls and the memory requirements.
|
||||
*/
|
||||
for (index_b = 0; index_b < len_lut3d; index_b++) {
|
||||
for (index_b = 0; index_b < len_clut; index_b++) {
|
||||
float inverse_b = weston_inverse_evaluate_lut1d(compositor,
|
||||
len_shaper,
|
||||
blue_curve,
|
||||
(float)index_b / (len_lut3d - 1));
|
||||
for (i = 0; i < len_lut3d; i++)
|
||||
(float)index_b / (len_clut - 1));
|
||||
for (i = 0; i < len_clut; i++)
|
||||
rgb_in[i].b = inverse_b;
|
||||
|
||||
for (index_g = 0; index_g < len_lut3d; index_g++) {
|
||||
for (index_r = 0; index_r < len_lut3d; index_r++) {
|
||||
for (index_g = 0; index_g < len_clut; index_g++) {
|
||||
for (index_r = 0; index_r < len_clut; index_r++) {
|
||||
rgb_in[index_r].g = inverse_g[index_g];
|
||||
rgb_in[index_r].r = inverse_r[index_r];
|
||||
}
|
||||
|
||||
index_r = 0;
|
||||
i = 3 * (index_r + len_lut3d * (index_g + len_lut3d * index_b));
|
||||
i = 3 * (index_r + len_clut * (index_g + len_clut * index_b));
|
||||
cmlcms_color_transformer_eval(compositor, transformer,
|
||||
(struct weston_vec3f *)&lut3d[i],
|
||||
rgb_in, len_lut3d);
|
||||
(struct weston_vec3f *)&clut[i],
|
||||
rgb_in, len_clut);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2256,16 +2260,16 @@ out:
|
|||
|
||||
/**
|
||||
* Based on [1]. We get the transformer and decompose into a shaper
|
||||
* (3x1D LUT) + 3D LUT. With that, we can reduce the 3D LUT dimension size
|
||||
* (3x1D LUT) + 3D cLUT. With that, we can reduce the 3D LUT dimension size
|
||||
* without losing precision. 3D LUT dimension size is problematic because it
|
||||
* demands n³ memory.
|
||||
*
|
||||
* [1] https://www.littlecms.com/ASICprelinerization_CGIV08.pdf
|
||||
*/
|
||||
static bool
|
||||
xform_to_shaper_plus_3dlut(struct weston_color_transform *xform_base,
|
||||
uint32_t len_shaper, float *shaper,
|
||||
uint32_t len_lut3d, float *lut3d)
|
||||
xform_to_clut(struct weston_color_transform *xform_base,
|
||||
uint32_t len_shaper, float *shaper,
|
||||
uint32_t len_clut, float *clut)
|
||||
{
|
||||
struct cmlcms_color_transform *xform = to_cmlcms_xform(xform_base);
|
||||
struct weston_compositor *compositor = xform_base->cm->compositor;
|
||||
|
|
@ -2276,8 +2280,8 @@ xform_to_shaper_plus_3dlut(struct weston_color_transform *xform_base,
|
|||
if (!ret)
|
||||
return false;
|
||||
|
||||
ret = build_3d_lut(compositor, &xform->transformer,
|
||||
len_shaper, shaper, len_lut3d, lut3d);
|
||||
ret = build_clut(compositor, &xform->transformer,
|
||||
len_shaper, shaper, len_clut, clut);
|
||||
if (!ret)
|
||||
return false;
|
||||
|
||||
|
|
@ -2306,7 +2310,7 @@ cmlcms_color_transform_create(struct weston_color_manager_lcms *cm,
|
|||
xform = xzalloc(sizeof *xform);
|
||||
weston_color_transform_init(&xform->base, &cm->base);
|
||||
wl_list_init(&xform->link);
|
||||
xform->base.to_shaper_plus_3dlut = xform_to_shaper_plus_3dlut;
|
||||
xform->base.to_clut = xform_to_clut;
|
||||
cmlcms_color_transform_recipe_copy(&xform->search_key, recipe);
|
||||
|
||||
weston_log_scope_printf(cm->transforms_scope,
|
||||
|
|
|
|||
|
|
@ -279,6 +279,8 @@ static const struct weston_color_tf_info color_tf_info_table[] = {
|
|||
.tf = WESTON_TF_BT1886,
|
||||
.desc = "BT.1886",
|
||||
.protocol_tf = WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_BT1886,
|
||||
.kms_colorop = WDRM_COLOROP_CURVE_1D__COUNT,
|
||||
.kms_colorop_inverse = WDRM_COLOROP_CURVE_1D__COUNT,
|
||||
.count_parameters = 0,
|
||||
/**
|
||||
* NOTE: This is the BT.1886 special case of L_B = 0 and
|
||||
|
|
@ -292,6 +294,8 @@ static const struct weston_color_tf_info color_tf_info_table[] = {
|
|||
.tf = WESTON_TF_GAMMA22,
|
||||
.desc = "assumed display gamma 2.2",
|
||||
.protocol_tf = WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_GAMMA22,
|
||||
.kms_colorop = WDRM_COLOROP_CURVE_1D_GAMMA_22,
|
||||
.kms_colorop_inverse = WDRM_COLOROP_CURVE_1D_GAMMA_22_INV,
|
||||
.count_parameters = 0,
|
||||
.curve_params_valid = true,
|
||||
.curve = POWER_LAW(2.2, true),
|
||||
|
|
@ -301,6 +305,8 @@ static const struct weston_color_tf_info color_tf_info_table[] = {
|
|||
.tf = WESTON_TF_GAMMA28,
|
||||
.desc = "assumed display gamma 2.8",
|
||||
.protocol_tf = WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_GAMMA28,
|
||||
.kms_colorop = WDRM_COLOROP_CURVE_1D__COUNT,
|
||||
.kms_colorop_inverse = WDRM_COLOROP_CURVE_1D__COUNT,
|
||||
.count_parameters = 0,
|
||||
.curve_params_valid = true,
|
||||
.curve = POWER_LAW(2.8, true),
|
||||
|
|
@ -310,12 +316,16 @@ static const struct weston_color_tf_info color_tf_info_table[] = {
|
|||
.tf = WESTON_TF_EXT_LINEAR,
|
||||
.desc = "extended linear",
|
||||
.protocol_tf = WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_EXT_LINEAR,
|
||||
.kms_colorop = WDRM_COLOROP_CURVE_1D__COUNT,
|
||||
.kms_colorop_inverse = WDRM_COLOROP_CURVE_1D__COUNT,
|
||||
.count_parameters = 0,
|
||||
},
|
||||
{
|
||||
.tf = WESTON_TF_SRGB,
|
||||
.desc = "sRGB piece-wise",
|
||||
.protocol_tf = WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_SRGB,
|
||||
.kms_colorop = WDRM_COLOROP_CURVE_1D_SRGB_EOTF,
|
||||
.kms_colorop_inverse = WDRM_COLOROP_CURVE_1D_SRGB_INV_EOTF,
|
||||
.count_parameters = 0,
|
||||
.curve_params_valid = true,
|
||||
.curve = SRGB_PIECE_WISE(true),
|
||||
|
|
@ -325,6 +335,8 @@ static const struct weston_color_tf_info color_tf_info_table[] = {
|
|||
.tf = WESTON_TF_EXT_SRGB,
|
||||
.desc = "Extended sRGB piece-wise",
|
||||
.protocol_tf = WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_EXT_SRGB,
|
||||
.kms_colorop = WDRM_COLOROP_CURVE_1D__COUNT,
|
||||
.kms_colorop_inverse = WDRM_COLOROP_CURVE_1D__COUNT,
|
||||
.count_parameters = 0,
|
||||
.curve_params_valid = true,
|
||||
.curve = SRGB_PIECE_WISE(false),
|
||||
|
|
@ -334,47 +346,63 @@ static const struct weston_color_tf_info color_tf_info_table[] = {
|
|||
.tf = WESTON_TF_ST240,
|
||||
.desc = "SMPTE ST 240",
|
||||
.protocol_tf = WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_ST240,
|
||||
.kms_colorop = WDRM_COLOROP_CURVE_1D__COUNT,
|
||||
.kms_colorop_inverse = WDRM_COLOROP_CURVE_1D__COUNT,
|
||||
.count_parameters = 0,
|
||||
},
|
||||
{
|
||||
.tf = WESTON_TF_ST428,
|
||||
.desc = "SMPTE ST 428",
|
||||
.protocol_tf = WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_ST428,
|
||||
.kms_colorop = WDRM_COLOROP_CURVE_1D__COUNT,
|
||||
.kms_colorop_inverse = WDRM_COLOROP_CURVE_1D__COUNT,
|
||||
.count_parameters = 0,
|
||||
},
|
||||
{
|
||||
.tf = WESTON_TF_ST2084_PQ,
|
||||
.desc = "Perceptual Quantizer",
|
||||
.protocol_tf = WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_ST2084_PQ,
|
||||
.kms_colorop = WDRM_COLOROP_CURVE_1D__COUNT,
|
||||
.kms_colorop_inverse = WDRM_COLOROP_CURVE_1D__COUNT,
|
||||
.count_parameters = 0,
|
||||
},
|
||||
{
|
||||
.tf = WESTON_TF_LOG_100,
|
||||
.desc = "logarithmic 100:1",
|
||||
.protocol_tf = WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_LOG_100,
|
||||
.kms_colorop = WDRM_COLOROP_CURVE_1D__COUNT,
|
||||
.kms_colorop_inverse = WDRM_COLOROP_CURVE_1D__COUNT,
|
||||
.count_parameters = 0,
|
||||
},
|
||||
{
|
||||
.tf = WESTON_TF_LOG_316,
|
||||
.desc = "logarithmic (100*Sqrt(10) : 1)",
|
||||
.protocol_tf = WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_LOG_316,
|
||||
.kms_colorop = WDRM_COLOROP_CURVE_1D__COUNT,
|
||||
.kms_colorop_inverse = WDRM_COLOROP_CURVE_1D__COUNT,
|
||||
.count_parameters = 0,
|
||||
},
|
||||
{
|
||||
.tf = WESTON_TF_XVYCC,
|
||||
.desc = "IEC 61966-2-4 (xvYCC)",
|
||||
.protocol_tf = WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_XVYCC,
|
||||
.kms_colorop = WDRM_COLOROP_CURVE_1D__COUNT,
|
||||
.kms_colorop_inverse = WDRM_COLOROP_CURVE_1D__COUNT,
|
||||
.count_parameters = 0,
|
||||
},
|
||||
{
|
||||
.tf = WESTON_TF_HLG,
|
||||
.desc = "Hybrid log-gamma",
|
||||
.protocol_tf = WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_HLG,
|
||||
.kms_colorop = WDRM_COLOROP_CURVE_1D__COUNT,
|
||||
.kms_colorop_inverse = WDRM_COLOROP_CURVE_1D__COUNT,
|
||||
.count_parameters = 0,
|
||||
},
|
||||
{
|
||||
.tf = WESTON_TF_POWER,
|
||||
.desc = "power-law with custom exponent",
|
||||
.kms_colorop = WDRM_COLOROP_CURVE_1D__COUNT,
|
||||
.kms_colorop_inverse = WDRM_COLOROP_CURVE_1D__COUNT,
|
||||
.count_parameters = 1,
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -110,6 +110,10 @@ struct weston_color_tf_info {
|
|||
/** CM&HDR protocol extension value representing the tf. */
|
||||
uint32_t protocol_tf;
|
||||
|
||||
/** KMS 1D curve colorop value representing the tf. */
|
||||
uint32_t kms_colorop;
|
||||
uint32_t kms_colorop_inverse;
|
||||
|
||||
/* The protocol also has support for parameterized functions, i.e.
|
||||
* certain known functions that clients can define passing arbitrary
|
||||
* parameters. */
|
||||
|
|
|
|||
|
|
@ -383,8 +383,8 @@ struct weston_color_transform {
|
|||
/**
|
||||
* When this is true, users are allowed to use the steps described below
|
||||
* (pre curve, color mapping and post curve) and implement the color
|
||||
* transformation themselves. Otherwise this is forbidden and
|
||||
* to_shaper_plus_3dlut() must be used.
|
||||
* transformation themselves. Otherwise this is forbidden and to_clut()
|
||||
* must be used.
|
||||
*/
|
||||
bool steps_valid;
|
||||
|
||||
|
|
@ -403,23 +403,23 @@ struct weston_color_transform {
|
|||
struct weston_color_curve post_curve;
|
||||
|
||||
/**
|
||||
* Decompose the color transformation into a shaper (3x1D LUT) and a 3D
|
||||
* LUT.
|
||||
* Decompose the color transformation into a shaper (3x1D LUT) followed
|
||||
* by a 3D cLUT.
|
||||
*
|
||||
* \param xform_base The color transformation to decompose.
|
||||
* \param len_shaper Number of taps in each of the 1D LUT.
|
||||
* \param shaper Where the shaper is saved, caller's responsibility to
|
||||
* allocate.
|
||||
* \param len_lut3d The 3D LUT's length for each dimension.
|
||||
* \param lut3d Where the 3D LUT is saved, caller's responsibility to
|
||||
* allocate. Its layout on memory is: lut3d[B][G][R], i.e. R is the
|
||||
* \param len_clut The 3D cLUT's length for each dimension.
|
||||
* \param clut Where the 3D cLUT is saved, caller's responsibility to
|
||||
* allocate. Its layout on memory is: clut[B][G][R], i.e. R is the
|
||||
* innermost and its index grow faster, followed by G and then B.
|
||||
* \return True on success, false otherwise.
|
||||
*/
|
||||
bool
|
||||
(*to_shaper_plus_3dlut)(struct weston_color_transform *xform_base,
|
||||
uint32_t len_shaper, float *shaper,
|
||||
uint32_t len_lut3d, float *lut3d);
|
||||
(*to_clut)(struct weston_color_transform *xform_base,
|
||||
uint32_t len_shaper, float *shaper,
|
||||
uint32_t len_clut, float *clut);
|
||||
};
|
||||
|
||||
struct weston_cvd_correction {
|
||||
|
|
|
|||
|
|
@ -800,7 +800,7 @@ weston_dmabuf_feedback_send_all(struct weston_compositor *compositor,
|
|||
{
|
||||
struct wl_resource *res;
|
||||
|
||||
weston_assert_true(compositor, !wl_list_empty(&dmabuf_feedback->resource_list));
|
||||
weston_assert_list_not_empty(compositor, &dmabuf_feedback->resource_list);
|
||||
wl_resource_for_each(res, &dmabuf_feedback->resource_list)
|
||||
weston_dmabuf_feedback_send(dmabuf_feedback,
|
||||
format_table, res, false);
|
||||
|
|
|
|||
|
|
@ -208,6 +208,10 @@ if get_option('backend-drm')
|
|||
dep_session_helper = declare_dependency(link_with: lib_session_helper)
|
||||
endif
|
||||
|
||||
libdrm_version = dep_libdrm.version()
|
||||
libdrm_supports_color_pipeline = libdrm_version.version_compare('>=2.4.130')
|
||||
config_h.set10('CAN_OFFLOAD_COLOR_PIPELINE', libdrm_supports_color_pipeline)
|
||||
|
||||
lib_libinput_backend = static_library(
|
||||
'libinput-backend',
|
||||
[
|
||||
|
|
|
|||
|
|
@ -376,9 +376,9 @@ gl_renderer_color_transform_create_3dlut(struct gl_renderer *gr,
|
|||
{
|
||||
struct gl_renderer_color_transform *gl_xform = NULL;
|
||||
float *shaper = NULL;
|
||||
float *lut3d = NULL;
|
||||
float len_shaper;
|
||||
float len_lut3d;
|
||||
float *clut = NULL;
|
||||
uint32_t len_shaper;
|
||||
uint32_t len_clut;
|
||||
bool ok;
|
||||
|
||||
/**
|
||||
|
|
@ -386,22 +386,21 @@ gl_renderer_color_transform_create_3dlut(struct gl_renderer *gr,
|
|||
* excessive memory consumption.
|
||||
*/
|
||||
len_shaper = 1024;
|
||||
len_lut3d = 33;
|
||||
len_clut = 33;
|
||||
|
||||
shaper = zalloc(len_shaper * 3 * sizeof(*shaper));
|
||||
if (!shaper)
|
||||
goto err;
|
||||
|
||||
lut3d = zalloc(3 * len_lut3d * len_lut3d * len_lut3d * sizeof(*lut3d));
|
||||
if (!lut3d)
|
||||
clut = zalloc(3 * len_clut * len_clut * len_clut * sizeof(*clut));
|
||||
if (!clut)
|
||||
goto err;
|
||||
|
||||
gl_xform = gl_renderer_color_transform_create(xform);
|
||||
if (!gl_xform)
|
||||
goto err;
|
||||
|
||||
ok = xform->to_shaper_plus_3dlut(xform, len_shaper, shaper,
|
||||
len_lut3d, lut3d);
|
||||
ok = xform->to_clut(xform, len_shaper, shaper, len_clut, clut);
|
||||
if (!ok)
|
||||
goto err;
|
||||
|
||||
|
|
@ -411,18 +410,18 @@ gl_renderer_color_transform_create_3dlut(struct gl_renderer *gr,
|
|||
goto err;
|
||||
|
||||
gl_color_mapping_lut_3d_init(gr, &gl_xform->mapping,
|
||||
len_lut3d, lut3d);
|
||||
len_clut, clut);
|
||||
|
||||
free(shaper);
|
||||
free(lut3d);
|
||||
free(clut);
|
||||
|
||||
return gl_xform;
|
||||
|
||||
err:
|
||||
if (shaper)
|
||||
free(shaper);
|
||||
if (lut3d)
|
||||
free(lut3d);
|
||||
if (clut)
|
||||
free(clut);
|
||||
if (gl_xform)
|
||||
gl_renderer_color_transform_destroy(gl_xform);
|
||||
return NULL;
|
||||
|
|
|
|||
|
|
@ -32,6 +32,8 @@
|
|||
#include <stdbool.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#include <wayland-util.h>
|
||||
|
||||
struct weston_compositor;
|
||||
|
||||
__attribute__((noreturn, format(printf, 2, 3)))
|
||||
|
|
@ -53,24 +55,24 @@ weston_assert_fail_(const struct weston_compositor *compositor, const char *fmt,
|
|||
|
||||
#define weston_assert_(compositor, a, b, val_type, val_fmt, cmp) \
|
||||
({ \
|
||||
struct weston_compositor *ec = compositor; \
|
||||
struct weston_compositor *wc_ = compositor; \
|
||||
val_type a_ = (a); \
|
||||
val_type b_ = (b); \
|
||||
bool cond = a_ cmp b_; \
|
||||
if (!cond) \
|
||||
custom_assert_fail_(ec, "%s:%u: Assertion %s %s %s (" val_fmt " %s " val_fmt ") failed!\n", \
|
||||
custom_assert_fail_(wc_, "%s:%u: Assertion %s %s %s (" val_fmt " %s " val_fmt ") failed!\n", \
|
||||
__FILE__, __LINE__, #a, #cmp, #b, a_, #cmp, b_); \
|
||||
cond; \
|
||||
})
|
||||
|
||||
#define weston_assert_fn_(compositor, fn, a, b, val_type, val_fmt, cmp) \
|
||||
({ \
|
||||
struct weston_compositor *ec = compositor; \
|
||||
struct weston_compositor *wc_ = compositor; \
|
||||
val_type a_ = (a); \
|
||||
val_type b_ = (b); \
|
||||
bool cond = fn(a_, b_) cmp 0; \
|
||||
if (!cond) \
|
||||
custom_assert_fail_(ec, "%s:%u: Assertion %s %s %s (" val_fmt " %s " val_fmt ") failed!\n", \
|
||||
custom_assert_fail_(wc_, "%s:%u: Assertion %s %s %s (" val_fmt " %s " val_fmt ") failed!\n", \
|
||||
__FILE__, __LINE__, #a, #cmp, #b, a_, #cmp, b_); \
|
||||
cond; \
|
||||
})
|
||||
|
|
@ -185,51 +187,75 @@ weston_assert_fail_(const struct weston_compositor *compositor, const char *fmt,
|
|||
|
||||
#define weston_assert_bit_set(compositor, value, bit) \
|
||||
({ \
|
||||
struct weston_compositor *ec = compositor; \
|
||||
struct weston_compositor *wc_ = compositor; \
|
||||
uint64_t v = (value); \
|
||||
uint64_t b = (bit); \
|
||||
bool cond = (v & b) == b; \
|
||||
weston_assert_true(compositor, is_pow2_64(bit)); \
|
||||
if (!cond) \
|
||||
custom_assert_fail_(ec, "%s:%u: Assertion failed! Bit \"%s\" (%" PRIu64 ") of \"%s\" (0x%" PRIx64 ") is not set.\n", \
|
||||
custom_assert_fail_(wc_, "%s:%u: Assertion failed! Bit \"%s\" (%" PRIu64 ") of \"%s\" (0x%" PRIx64 ") is not set.\n", \
|
||||
__FILE__, __LINE__, #bit, b, #value, v); \
|
||||
cond; \
|
||||
})
|
||||
|
||||
#define weston_assert_bit_not_set(compositor, value, bit) \
|
||||
({ \
|
||||
struct weston_compositor *ec = compositor; \
|
||||
struct weston_compositor *wc_ = compositor; \
|
||||
uint64_t v = (value); \
|
||||
uint64_t b = (bit); \
|
||||
bool cond = (v & b) == 0; \
|
||||
weston_assert_true(compositor, is_pow2_64(bit)); \
|
||||
if (!cond) \
|
||||
custom_assert_fail_(ec, "%s:%u: Assertion failed! Bit \"%s\" (%" PRIu64 ") of \"%s\" (0x%" PRIx64 ") is set.\n", \
|
||||
custom_assert_fail_(wc_, "%s:%u: Assertion failed! Bit \"%s\" (%" PRIu64 ") of \"%s\" (0x%" PRIx64 ") is set.\n", \
|
||||
__FILE__, __LINE__, #bit, b, #value, v); \
|
||||
cond; \
|
||||
})
|
||||
|
||||
#define weston_assert_legal_bits(compositor, value, mask) \
|
||||
({ \
|
||||
struct weston_compositor *ec = compositor; \
|
||||
struct weston_compositor *wc_ = compositor; \
|
||||
uint64_t v_ = (value); \
|
||||
uint64_t m_ = (mask); \
|
||||
uint64_t ill = v_ & ~m_; \
|
||||
bool cond = ill == 0; \
|
||||
if (!cond) \
|
||||
custom_assert_fail_(ec, "%s:%u: Assertion failed! " \
|
||||
custom_assert_fail_(wc_, "%s:%u: Assertion failed! " \
|
||||
"Value %s (0x%" PRIx64 ") contains illegal bits 0x%" PRIx64 ". " \
|
||||
"Legal mask is %s (0x%" PRIx64 ").\n", \
|
||||
__FILE__, __LINE__, #value, v_, ill, #mask, m_); \
|
||||
cond; \
|
||||
})
|
||||
|
||||
/* wl_list asserts */
|
||||
|
||||
#define weston_assert_list_empty(compositor, list) \
|
||||
({ \
|
||||
struct weston_compositor *wc_ = compositor; \
|
||||
struct wl_list *l_ = list; \
|
||||
bool cond = wl_list_empty(l_); \
|
||||
if (!cond) \
|
||||
custom_assert_fail_(wc_, "%s:%u: Assertion failed! wl_list '%s' is not empty.\n", \
|
||||
__FILE__, __LINE__, #list); \
|
||||
cond; \
|
||||
})
|
||||
|
||||
#define weston_assert_list_not_empty(compositor, list) \
|
||||
({ \
|
||||
struct weston_compositor *wc_ = compositor; \
|
||||
struct wl_list *l_ = list; \
|
||||
bool cond = !wl_list_empty(l_); \
|
||||
if (!cond) \
|
||||
custom_assert_fail_(wc_, "%s:%u: Assertion failed! wl_list '%s' is empty.\n", \
|
||||
__FILE__, __LINE__, #list); \
|
||||
cond; \
|
||||
})
|
||||
|
||||
/* Misc asserts. */
|
||||
|
||||
#define weston_assert_not_reached(compositor, reason) \
|
||||
do { \
|
||||
struct weston_compositor *ec = compositor; \
|
||||
custom_assert_fail_(ec, "%s:%u: Assertion failed! This should not be reached: %s\n", \
|
||||
struct weston_compositor *wc_ = compositor; \
|
||||
custom_assert_fail_(wc_, "%s:%u: Assertion failed! This should not be reached: %s\n", \
|
||||
__FILE__, __LINE__, reason); \
|
||||
} while (0)
|
||||
|
||||
|
|
|
|||
|
|
@ -110,6 +110,35 @@ TEST(asserts_boolean)
|
|||
return RESULT_OK;
|
||||
}
|
||||
|
||||
TEST(asserts_list)
|
||||
{
|
||||
/* Unused by the macros for now, so let's just use NULL. */
|
||||
struct weston_compositor *compositor = NULL;
|
||||
struct wl_list list;
|
||||
struct wl_list link;
|
||||
bool ret;
|
||||
|
||||
wl_list_init(&list);
|
||||
|
||||
ret = weston_assert_list_empty(compositor, &list);
|
||||
abort_if_not(ret);
|
||||
ret = weston_assert_list_not_empty(compositor, &list);
|
||||
abort_if_not(ret == false);
|
||||
|
||||
wl_list_insert(&list, &link);
|
||||
|
||||
ret = weston_assert_list_empty(compositor, &list);
|
||||
abort_if_not(ret == false);
|
||||
ret = weston_assert_list_not_empty(compositor, &list);
|
||||
abort_if_not(ret);
|
||||
|
||||
/* If we reach that point, it's a success so reset the assert counter
|
||||
* that's been incremented to check that assertions work. */
|
||||
weston_assert_counter_reset();
|
||||
|
||||
return RESULT_OK;
|
||||
}
|
||||
|
||||
TEST(asserts_pointer)
|
||||
{
|
||||
/* Unused by the macros for now, so let's just use NULL. */
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue