Add struct weston_drm_format, which contains a DRM format and a list of modifiers. The patch also adds struct weston_drm_format_array and some helper functions to handle these two new structs: init/fini, find elements, add elements, etc. This will be useful in the next commits in which we add support to dmabuf-hints. It also allows a cleanup in the DRM-backend, where we currently have a similar struct in drm_plane but with no helper functions, so the code to handle it is scattered throughout the functions and there is a lot of repetition. This patch is based on previous work of Scott Anderson (@ascent). Signed-off-by: Scott Anderson <scott.anderson@collabora.com> Signed-off-by: Leandro Ribeiro <leandro.ribeiro@collabora.com>dev
parent
4b5df8b39f
commit
78f01927b6
@ -0,0 +1,516 @@ |
|||||||
|
/*
|
||||||
|
* Copyright © 2021 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. |
||||||
|
*/ |
||||||
|
|
||||||
|
#include "config.h" |
||||||
|
|
||||||
|
#include <assert.h> |
||||||
|
|
||||||
|
#include <libweston/libweston.h> |
||||||
|
#include "libweston-internal.h" |
||||||
|
#include "shared/weston-drm-fourcc.h" |
||||||
|
|
||||||
|
/**
|
||||||
|
* Create and initialize a weston_drm_format_array |
||||||
|
* |
||||||
|
* @return The weston_drm_format_array, or NULL on failure |
||||||
|
*/ |
||||||
|
WL_EXPORT struct weston_drm_format_array * |
||||||
|
weston_drm_format_array_create(void) |
||||||
|
{ |
||||||
|
struct weston_drm_format_array *formats; |
||||||
|
|
||||||
|
formats = zalloc(sizeof(*formats)); |
||||||
|
if (!formats) { |
||||||
|
weston_log("%s: out of memory\n", __func__); |
||||||
|
return NULL; |
||||||
|
} |
||||||
|
|
||||||
|
weston_drm_format_array_init(formats); |
||||||
|
|
||||||
|
return formats; |
||||||
|
} |
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize a weston_drm_format_array |
||||||
|
* |
||||||
|
* @param formats The weston_drm_format_array to initialize |
||||||
|
*/ |
||||||
|
WL_EXPORT void |
||||||
|
weston_drm_format_array_init(struct weston_drm_format_array *formats) |
||||||
|
{ |
||||||
|
wl_array_init(&formats->arr); |
||||||
|
} |
||||||
|
|
||||||
|
/**
|
||||||
|
* Fini and destroy a weston_drm_format_array |
||||||
|
* |
||||||
|
* @param formats The weston_drm_format_array to destroy |
||||||
|
*/ |
||||||
|
WL_EXPORT void |
||||||
|
weston_drm_format_array_destroy(struct weston_drm_format_array *formats) |
||||||
|
{ |
||||||
|
weston_drm_format_array_fini(formats); |
||||||
|
free(formats); |
||||||
|
} |
||||||
|
|
||||||
|
/**
|
||||||
|
* Finish a weston_drm_format_array |
||||||
|
* |
||||||
|
* It releases the modifiers set for each format and then the |
||||||
|
* formats array itself. |
||||||
|
* |
||||||
|
* @param formats The weston_drm_format_array to finish |
||||||
|
*/ |
||||||
|
WL_EXPORT void |
||||||
|
weston_drm_format_array_fini(struct weston_drm_format_array *formats) |
||||||
|
{ |
||||||
|
struct weston_drm_format *fmt; |
||||||
|
|
||||||
|
wl_array_for_each(fmt, &formats->arr) |
||||||
|
wl_array_release(&fmt->modifiers); |
||||||
|
|
||||||
|
wl_array_release(&formats->arr); |
||||||
|
} |
||||||
|
|
||||||
|
static int |
||||||
|
add_format_and_modifiers(struct weston_drm_format_array *formats, |
||||||
|
uint32_t format, struct wl_array *modifiers) |
||||||
|
{ |
||||||
|
struct weston_drm_format *fmt; |
||||||
|
int ret; |
||||||
|
|
||||||
|
fmt = weston_drm_format_array_add_format(formats, format); |
||||||
|
if (!fmt) |
||||||
|
return -1; |
||||||
|
|
||||||
|
ret = wl_array_copy(&fmt->modifiers, modifiers); |
||||||
|
if (ret < 0) { |
||||||
|
weston_log("%s: out of memory\n", __func__); |
||||||
|
return -1; |
||||||
|
} |
||||||
|
|
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
/**
|
||||||
|
* Replace the content of a weston_drm_format_array |
||||||
|
* |
||||||
|
* Frees the content of the array and then perform a deep copy using |
||||||
|
* source_formats. It duplicates the array of formats and for each format it |
||||||
|
* duplicates the modifiers set as well. |
||||||
|
* |
||||||
|
* @param formats The weston_drm_format_array that gets its content replaced |
||||||
|
* @param source_formats The weston_drm_format_array to copy |
||||||
|
* @return 0 on success, -1 on failure |
||||||
|
*/ |
||||||
|
WL_EXPORT int |
||||||
|
weston_drm_format_array_replace(struct weston_drm_format_array *formats, |
||||||
|
const struct weston_drm_format_array *source_formats) |
||||||
|
{ |
||||||
|
struct weston_drm_format *source_fmt; |
||||||
|
int ret; |
||||||
|
|
||||||
|
weston_drm_format_array_fini(formats); |
||||||
|
weston_drm_format_array_init(formats); |
||||||
|
|
||||||
|
wl_array_for_each(source_fmt, &source_formats->arr) { |
||||||
|
ret = add_format_and_modifiers(formats, source_fmt->format, |
||||||
|
&source_fmt->modifiers); |
||||||
|
if (ret < 0) |
||||||
|
return -1; |
||||||
|
} |
||||||
|
|
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
/**
|
||||||
|
* Add format to weston_drm_format_array |
||||||
|
* |
||||||
|
* Adding repeated formats is considered an error. |
||||||
|
* |
||||||
|
* @param formats The weston_drm_format_array that receives the format |
||||||
|
* @param format The format to add to the array |
||||||
|
* @return The weston_drm_format, or NULL on failure |
||||||
|
*/ |
||||||
|
WL_EXPORT struct weston_drm_format * |
||||||
|
weston_drm_format_array_add_format(struct weston_drm_format_array *formats, |
||||||
|
uint32_t format) |
||||||
|
{ |
||||||
|
struct weston_drm_format *fmt; |
||||||
|
|
||||||
|
/* We should not try to add repeated formats to an array. */ |
||||||
|
assert(!weston_drm_format_array_find_format(formats, format)); |
||||||
|
|
||||||
|
fmt = wl_array_add(&formats->arr, sizeof(*fmt)); |
||||||
|
if (!fmt) { |
||||||
|
weston_log("%s: out of memory\n", __func__); |
||||||
|
return NULL; |
||||||
|
} |
||||||
|
|
||||||
|
fmt->format = format; |
||||||
|
wl_array_init(&fmt->modifiers); |
||||||
|
|
||||||
|
return fmt; |
||||||
|
} |
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove latest format added to a weston_drm_format_array |
||||||
|
* |
||||||
|
* Calling this function for an empty array is an error, at least one element |
||||||
|
* must be in the array. |
||||||
|
* |
||||||
|
* @param formats The weston_drm_format_array from which the format is removed |
||||||
|
*/ |
||||||
|
WL_EXPORT void |
||||||
|
weston_drm_format_array_remove_latest_format(struct weston_drm_format_array *formats) |
||||||
|
{ |
||||||
|
struct wl_array *array = &formats->arr; |
||||||
|
struct weston_drm_format *fmt; |
||||||
|
|
||||||
|
assert(array->size >= sizeof(*fmt)); |
||||||
|
|
||||||
|
array->size -= sizeof(*fmt); |
||||||
|
|
||||||
|
fmt = array->data + array->size; |
||||||
|
wl_array_release(&fmt->modifiers); |
||||||
|
} |
||||||
|
|
||||||
|
/**
|
||||||
|
* Find format in a weston_drm_format_array |
||||||
|
* |
||||||
|
* @param formats The weston_drm_format_array where to look for the format |
||||||
|
* @param format The format to look for |
||||||
|
* @return The weston_drm_format if format was found, or NULL otherwise |
||||||
|
*/ |
||||||
|
WL_EXPORT struct weston_drm_format * |
||||||
|
weston_drm_format_array_find_format(const struct weston_drm_format_array *formats, |
||||||
|
uint32_t format) |
||||||
|
{ |
||||||
|
struct weston_drm_format *fmt; |
||||||
|
|
||||||
|
wl_array_for_each(fmt, &formats->arr) |
||||||
|
if (fmt->format == format) |
||||||
|
return fmt; |
||||||
|
|
||||||
|
return NULL; |
||||||
|
} |
||||||
|
|
||||||
|
/**
|
||||||
|
* Compare the content of two weston_drm_format_array |
||||||
|
* |
||||||
|
* @param formats_A One of the weston_drm_format_array to compare |
||||||
|
* @param formats_B The other weston_drm_format_array to compare |
||||||
|
* @return True if both sets are equivalent, false otherwise |
||||||
|
*/ |
||||||
|
WL_EXPORT bool |
||||||
|
weston_drm_format_array_equal(const struct weston_drm_format_array *formats_A, |
||||||
|
const struct weston_drm_format_array *formats_B) |
||||||
|
{ |
||||||
|
struct weston_drm_format *fmt_A, *fmt_B; |
||||||
|
const uint64_t *modifiers_A; |
||||||
|
unsigned num_modifiers_A, num_modifiers_B; |
||||||
|
unsigned int i; |
||||||
|
|
||||||
|
if (formats_A->arr.size != formats_B->arr.size) |
||||||
|
return false; |
||||||
|
|
||||||
|
wl_array_for_each(fmt_A, &formats_A->arr) { |
||||||
|
fmt_B = weston_drm_format_array_find_format(formats_B, |
||||||
|
fmt_A->format); |
||||||
|
if (!fmt_B) |
||||||
|
return false; |
||||||
|
|
||||||
|
modifiers_A = weston_drm_format_get_modifiers(fmt_A, &num_modifiers_A); |
||||||
|
weston_drm_format_get_modifiers(fmt_B, &num_modifiers_B); |
||||||
|
if (num_modifiers_A != num_modifiers_B) |
||||||
|
return false; |
||||||
|
for (i = 0; i < num_modifiers_A; i++) |
||||||
|
if (!weston_drm_format_has_modifier(fmt_B, modifiers_A[i])) |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
/**
|
||||||
|
* Joins two weston_drm_format_array, keeping the result in A |
||||||
|
* |
||||||
|
* @param formats_A The weston_drm_format_array that receives the formats from B |
||||||
|
* @param formats_B The weston_drm_format_array whose formats are added to A |
||||||
|
* @return 0 on success, -1 on failure |
||||||
|
*/ |
||||||
|
WL_EXPORT int |
||||||
|
weston_drm_format_array_join(struct weston_drm_format_array *formats_A, |
||||||
|
const struct weston_drm_format_array *formats_B) |
||||||
|
{ |
||||||
|
struct weston_drm_format *fmt_A, *fmt_B; |
||||||
|
const uint64_t *modifiers; |
||||||
|
unsigned int num_modifiers; |
||||||
|
unsigned int i; |
||||||
|
int ret; |
||||||
|
|
||||||
|
wl_array_for_each(fmt_B, &formats_B->arr) { |
||||||
|
fmt_A = weston_drm_format_array_find_format(formats_A, |
||||||
|
fmt_B->format); |
||||||
|
if (!fmt_A) { |
||||||
|
fmt_A = weston_drm_format_array_add_format(formats_A, |
||||||
|
fmt_B->format); |
||||||
|
if (!fmt_A) |
||||||
|
return -1; |
||||||
|
} |
||||||
|
|
||||||
|
modifiers = weston_drm_format_get_modifiers(fmt_B, &num_modifiers); |
||||||
|
for (i = 0; i < num_modifiers; i++) { |
||||||
|
if (weston_drm_format_has_modifier(fmt_A, modifiers[i])) |
||||||
|
continue; |
||||||
|
ret = weston_drm_format_add_modifier(fmt_A, modifiers[i]); |
||||||
|
if (ret < 0) |
||||||
|
return -1; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
static int |
||||||
|
modifiers_intersect(const struct weston_drm_format *fmt_A, |
||||||
|
const struct weston_drm_format *fmt_B, |
||||||
|
struct wl_array *modifiers_result) |
||||||
|
{ |
||||||
|
const uint64_t *modifiers; |
||||||
|
unsigned int num_modifiers; |
||||||
|
uint64_t *mod; |
||||||
|
unsigned int i; |
||||||
|
|
||||||
|
modifiers = weston_drm_format_get_modifiers(fmt_A, &num_modifiers); |
||||||
|
for (i = 0; i < num_modifiers; i++) { |
||||||
|
if (!weston_drm_format_has_modifier(fmt_B, modifiers[i])) |
||||||
|
continue; |
||||||
|
mod = wl_array_add(modifiers_result, sizeof(modifiers[i])); |
||||||
|
if (!mod) { |
||||||
|
weston_log("%s: out of memory\n", __func__); |
||||||
|
return -1; |
||||||
|
} |
||||||
|
*mod = modifiers[i]; |
||||||
|
} |
||||||
|
|
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
/**
|
||||||
|
* Compute the intersection between two DRM-format arrays |
||||||
|
* |
||||||
|
* Callers are responsible for destroying the returned array. |
||||||
|
* |
||||||
|
* @param formats_A One of the weston_drm_format_array |
||||||
|
* @param formats_B The other weston_drm_format_array |
||||||
|
* @return Array with formats and modifiers that are present |
||||||
|
* on both A and B, or NULL on failure |
||||||
|
*/ |
||||||
|
WL_EXPORT struct weston_drm_format_array * |
||||||
|
weston_drm_format_array_intersect(const struct weston_drm_format_array *formats_A, |
||||||
|
const struct weston_drm_format_array *formats_B) |
||||||
|
{ |
||||||
|
struct weston_drm_format_array *formats_result; |
||||||
|
struct weston_drm_format *fmt_result, *fmt_A, *fmt_B; |
||||||
|
int ret; |
||||||
|
|
||||||
|
formats_result = weston_drm_format_array_create(); |
||||||
|
if (!formats_result) |
||||||
|
return NULL; |
||||||
|
|
||||||
|
wl_array_for_each(fmt_A, &formats_A->arr) { |
||||||
|
fmt_B = weston_drm_format_array_find_format(formats_B, |
||||||
|
fmt_A->format); |
||||||
|
if (!fmt_B) |
||||||
|
continue; |
||||||
|
|
||||||
|
fmt_result = weston_drm_format_array_add_format(formats_result, |
||||||
|
fmt_A->format); |
||||||
|
if (!fmt_result) |
||||||
|
goto err; |
||||||
|
|
||||||
|
ret = modifiers_intersect(fmt_A, fmt_B, &fmt_result->modifiers); |
||||||
|
if (ret < 0) |
||||||
|
goto err; |
||||||
|
|
||||||
|
if (fmt_result->modifiers.size == 0) |
||||||
|
weston_drm_format_array_remove_latest_format(formats_result); |
||||||
|
} |
||||||
|
|
||||||
|
return formats_result; |
||||||
|
|
||||||
|
err: |
||||||
|
weston_drm_format_array_destroy(formats_result); |
||||||
|
return NULL; |
||||||
|
} |
||||||
|
|
||||||
|
static int |
||||||
|
modifiers_subtract(const struct weston_drm_format *fmt_A, |
||||||
|
const struct weston_drm_format *fmt_B, |
||||||
|
struct wl_array *modifiers_result) |
||||||
|
{ |
||||||
|
const uint64_t *modifiers; |
||||||
|
unsigned int num_modifiers; |
||||||
|
uint64_t *mod; |
||||||
|
unsigned int i; |
||||||
|
|
||||||
|
modifiers = weston_drm_format_get_modifiers(fmt_A, &num_modifiers); |
||||||
|
for (i = 0; i < num_modifiers; i++) { |
||||||
|
if (weston_drm_format_has_modifier(fmt_B, modifiers[i])) |
||||||
|
continue; |
||||||
|
mod = wl_array_add(modifiers_result, sizeof(modifiers[i])); |
||||||
|
if (!mod) { |
||||||
|
weston_log("%s: out of memory\n", __func__); |
||||||
|
return -1; |
||||||
|
} |
||||||
|
*mod = modifiers[i]; |
||||||
|
} |
||||||
|
|
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
/**
|
||||||
|
* Compute the subtraction between two DRM-format arrays, keeping the result in A |
||||||
|
* |
||||||
|
* @param formats_A The minuend weston_drm_format_array |
||||||
|
* @param formats_B The subtrahend weston_drm_format_array |
||||||
|
* @return 0 on success, -1 on failure |
||||||
|
*/ |
||||||
|
WL_EXPORT int |
||||||
|
weston_drm_format_array_subtract(struct weston_drm_format_array *formats_A, |
||||||
|
const struct weston_drm_format_array *formats_B) |
||||||
|
{ |
||||||
|
struct weston_drm_format_array *formats_result; |
||||||
|
struct weston_drm_format *fmt_result, *fmt_A, *fmt_B; |
||||||
|
int ret; |
||||||
|
|
||||||
|
formats_result = weston_drm_format_array_create(); |
||||||
|
if (!formats_result) |
||||||
|
return -1; |
||||||
|
|
||||||
|
wl_array_for_each(fmt_A, &formats_A->arr) { |
||||||
|
fmt_B = weston_drm_format_array_find_format(formats_B, |
||||||
|
fmt_A->format); |
||||||
|
if (!fmt_B) { |
||||||
|
ret = add_format_and_modifiers(formats_result, fmt_A->format, |
||||||
|
&fmt_A->modifiers); |
||||||
|
if (ret < 0) |
||||||
|
goto err; |
||||||
|
|
||||||
|
continue; |
||||||
|
} |
||||||
|
|
||||||
|
fmt_result = weston_drm_format_array_add_format(formats_result, |
||||||
|
fmt_A->format); |
||||||
|
if (!fmt_result) |
||||||
|
goto err; |
||||||
|
|
||||||
|
ret = modifiers_subtract(fmt_A, fmt_B, &fmt_result->modifiers); |
||||||
|
if (ret < 0) |
||||||
|
goto err; |
||||||
|
|
||||||
|
if (fmt_result->modifiers.size == 0) |
||||||
|
weston_drm_format_array_remove_latest_format(formats_result); |
||||||
|
} |
||||||
|
|
||||||
|
ret = weston_drm_format_array_replace(formats_A, formats_result); |
||||||
|
if (ret < 0) |
||||||
|
goto err; |
||||||
|
|
||||||
|
return 0; |
||||||
|
|
||||||
|
err: |
||||||
|
weston_drm_format_array_destroy(formats_result); |
||||||
|
return -1; |
||||||
|
} |
||||||
|
|
||||||
|
/**
|
||||||
|
* Add modifier to modifier set of a weston_drm_format. |
||||||
|
* |
||||||
|
* Adding repeated modifiers is considered an error. |
||||||
|
* |
||||||
|
* @param format The weston_drm_format that owns the modifier set to which |
||||||
|
* the modifier should be added |
||||||
|
* @param modifier The modifier to add |
||||||
|
* @return 0 on success, -1 on failure |
||||||
|
*/ |
||||||
|
WL_EXPORT int |
||||||
|
weston_drm_format_add_modifier(struct weston_drm_format *format, |
||||||
|
uint64_t modifier) |
||||||
|
{ |
||||||
|
uint64_t *mod; |
||||||
|
|
||||||
|
/* We should not try to add repeated modifiers to a set. */ |
||||||
|
assert(!weston_drm_format_has_modifier(format, modifier)); |
||||||
|
|
||||||
|
mod = wl_array_add(&format->modifiers, sizeof(*mod)); |
||||||
|
if (!mod) { |
||||||
|
weston_log("%s: out of memory\n", __func__); |
||||||
|
return -1; |
||||||
|
} |
||||||
|
*mod = modifier; |
||||||
|
|
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if modifier set of a weston_drm_format contains a certain modifier |
||||||
|
* |
||||||
|
* @param format The weston_drm_format that owns the modifier set where to |
||||||
|
* look for the modifier |
||||||
|
* @param modifier The modifier to look for |
||||||
|
* @return True if modifier was found, false otherwise |
||||||
|
*/ |
||||||
|
WL_EXPORT bool |
||||||
|
weston_drm_format_has_modifier(const struct weston_drm_format *format, |
||||||
|
uint64_t modifier) |
||||||
|
{ |
||||||
|
const uint64_t *modifiers; |
||||||
|
unsigned int num_modifiers; |
||||||
|
unsigned int i; |
||||||
|
|
||||||
|
modifiers = weston_drm_format_get_modifiers(format, &num_modifiers); |
||||||
|
for (i = 0; i < num_modifiers; i++) |
||||||
|
if (modifiers[i] == modifier) |
||||||
|
return true; |
||||||
|
|
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
/**
|
||||||
|
* Get array of modifiers and modifiers count from a weston_drm_format |
||||||
|
* |
||||||
|
* @param format The weston_drm_format that contains the modifiers |
||||||
|
* @param count_out Parameter that receives the modifiers count |
||||||
|
* @return The array of modifiers |
||||||
|
*/ |
||||||
|
WL_EXPORT const uint64_t * |
||||||
|
weston_drm_format_get_modifiers(const struct weston_drm_format *format, |
||||||
|
unsigned int *count_out) |
||||||
|
{ |
||||||
|
*count_out = format->modifiers.size / sizeof(uint64_t); |
||||||
|
return format->modifiers.data; |
||||||
|
} |
Loading…
Reference in new issue