diff --git a/libweston/backend-drm/colorops.c b/libweston/backend-drm/colorops.c index dbe2a2f4d..05f4f330a 100644 --- a/libweston/backend-drm/colorops.c +++ b/libweston/backend-drm/colorops.c @@ -58,24 +58,53 @@ drm_colorop_3x1d_lut_blob_destroy_handler(struct wl_listener *l, void *data) * \param device The DRM device in which we want to look for the blob. * \param xform The xform from which the LUT comes from. * \param curve_step What curve step from the xform originated the 3x1D LUT. + * \param quantization The colorop 3x1D LUT quantization (U32 or U16). * \param lut_len How many taps each of the 1D LUT has. */ 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) { struct drm_colorop_3x1d_lut_blob *lut; wl_list_for_each(lut, &device->drm_colorop_3x1d_lut_blob_list, link) if (lut->xform == xform && lut->curve_step == curve_step && - lut->lut_len == lut_len) + lut->lut_len == lut_len && lut->quantization == quantization) return lut; return NULL; } +static struct drm_color_lut32 +drm_vec3f_to_u32(struct weston_vec3f vec) +{ + struct drm_color_lut32 res; + + /* UINT32_MAX exceeds the 24-bit integer precision of floats and could + * be rounded incorrectly if multiplied in float. */ + + res.red = (double) vec.r * UINT32_MAX; + res.green = (double) vec.g * UINT32_MAX; + res.blue = (double) vec.b * UINT32_MAX; + + return res; +} + +static struct drm_color_lut +drm_vec3f_to_u16(struct weston_vec3f vec) +{ + struct drm_color_lut res; + + res.red = vec.r * UINT16_MAX; + res.green = vec.g * UINT16_MAX; + res.blue = vec.b * UINT16_MAX; + + return res; +} + /** * Create a 3x1D LUT colorop blob. * @@ -88,23 +117,64 @@ drm_colorop_3x1d_lut_blob_search(struct drm_device *device, * \param xform The xform from which the LUT comes from. This object matches its * lifetime. * \param curve_step What xform curve step originated the 3x1D LUT. + * \param quantization The colorop 3x1D LUT quantization (U32 or U16). + * \param cm_lut The 3x1D LUT from which the colorop will be created. * \param lut_len The number of taps for each of the 1D LUT. - * \param blob_id The KMS blob id (associated to the DRM device). * \return The 3x1D LUT colorop blob. */ 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, - uint32_t lut_len, uint32_t blob_id) + enum drm_colorop_3x1d_lut_blob_quantization quantization, + struct weston_vec3f *cm_lut, uint32_t lut_len) { + struct drm_backend *b = device->backend; struct drm_colorop_3x1d_lut_blob *lut; + uint32_t blob_id; + unsigned int i; + int ret = -1; + + switch (quantization) { + case DRM_COLOROP_3X1D_LUT_BLOB_QUANTIZATION_U16: { + struct drm_color_lut *drm_lut = + xcalloc(lut_len, sizeof(*drm_lut)); + + for (i = 0; i < lut_len; i++) + drm_lut[i] = drm_vec3f_to_u16(cm_lut[i]); + + ret = drmModeCreatePropertyBlob(device->kms_device->fd, drm_lut, lut_len * sizeof(*drm_lut), + &blob_id); + free(drm_lut); + break; + } + case DRM_COLOROP_3X1D_LUT_BLOB_QUANTIZATION_U32: { + struct drm_color_lut32 *drm_lut = + xcalloc(lut_len, sizeof(*drm_lut)); + + for (i = 0; i < lut_len; i++) + drm_lut[i] = drm_vec3f_to_u32(cm_lut[i]); + + ret = drmModeCreatePropertyBlob(device->kms_device->fd, drm_lut, lut_len * sizeof(*drm_lut), + &blob_id); + free(drm_lut); + break; + }} + + if (ret < 0) { + drm_debug(b, "[colorop] failed to create blob for colorop 3x1D LUT;\n" \ + " lut_len %u, quantization %s", + lut_len, + quantization == DRM_COLOROP_3X1D_LUT_BLOB_QUANTIZATION_U16 ? "u16" : "u32"); + return NULL; + } lut = xzalloc(sizeof(*lut)); lut->device = device; lut->xform = xform; lut->curve_step = curve_step; + lut->quantization = quantization; lut->lut_len = lut_len; lut->blob_id = blob_id; diff --git a/libweston/backend-drm/colorops.h b/libweston/backend-drm/colorops.h index 7b7b2b8c8..f95ddb2ba 100644 --- a/libweston/backend-drm/colorops.h +++ b/libweston/backend-drm/colorops.h @@ -58,12 +58,14 @@ 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, - uint32_t lut_len, uint32_t blob_id); + 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); void @@ -79,7 +81,8 @@ 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, - uint32_t lut_len, uint32_t blob_id) + enum drm_colorop_3x1d_lut_blob_quantization quantization, + struct weston_vec3f *cm_lut, uint32_t lut_len) { return NULL; } @@ -88,6 +91,7 @@ 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; diff --git a/libweston/backend-drm/drm-internal.h b/libweston/backend-drm/drm-internal.h index 47a058bf2..ac298c1d5 100644 --- a/libweston/backend-drm/drm-internal.h +++ b/libweston/backend-drm/drm-internal.h @@ -397,6 +397,11 @@ 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; @@ -409,6 +414,8 @@ struct drm_colorop_3x1d_lut_blob { /* 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; diff --git a/libweston/backend-drm/drm.c b/libweston/backend-drm/drm.c index 14508eb2f..4b44e2689 100644 --- a/libweston/backend-drm/drm.c +++ b/libweston/backend-drm/drm.c @@ -2284,13 +2284,9 @@ drm_output_pick_blend_to_output(struct drm_output *output) struct drm_colorop_3x1d_lut_blob *colorop_lut; struct weston_color_transform *xform; enum weston_color_curve_step curve_step; - struct drm_color_lut *drm_lut; size_t lut_len; - uint32_t gamma_lut_blob_id; 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); @@ -2315,7 +2311,9 @@ drm_output_pick_blend_to_output(struct drm_output *output) * 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_blob_search(device, xform, curve_step, lut_len); + 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; @@ -2329,24 +2327,16 @@ drm_output_pick_blend_to_output(struct drm_output *output) return -1; } - drm_lut = xzalloc(lut_len * sizeof(*drm_lut)); - for (i = 0; i < lut_len; 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_len * 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_blob_create(device, xform, curve_step, - lut_len, gamma_lut_blob_id); return 0; }