xf86drm: add iterator API for DRM/KMS IN_FORMATS blobs

Add support for parsing IN_FORMATS property blobs. Providing libdrm
with this functionality helps to standardise how user-space reads
kernel blobs and decreases duplication on the client side.

drmModeFormatModifierBlobIterNext() allows the caller to view
formats and associated modifiers given a valid property blob.
An example is available inside the libdrm unit test, modetest.c.

Signed-off-by: Luigi Santivetti <luigi.santivetti@imgtec.com>
Reviewed-by: Simon Ser <contact@emersion.fr>
main
Luigi Santivetti 2021-03-25 22:42:38 +00:00 committed by Simon Ser
parent f256bb9afd
commit e641e2a632
4 changed files with 130 additions and 18 deletions

View File

@ -110,6 +110,7 @@ drmModeCrtcSetGamma
drmModeDestroyPropertyBlob drmModeDestroyPropertyBlob
drmModeDetachMode drmModeDetachMode
drmModeDirtyFB drmModeDirtyFB
drmModeFormatModifierBlobIterNext
drmModeFreeConnector drmModeFreeConnector
drmModeFreeCrtc drmModeFreeCrtc
drmModeFreeEncoder drmModeFreeEncoder

View File

@ -300,11 +300,9 @@ static const char *modifier_to_string(uint64_t modifier)
static void dump_in_formats(struct device *dev, uint32_t blob_id) static void dump_in_formats(struct device *dev, uint32_t blob_id)
{ {
uint32_t i, j; drmModeFormatModifierIterator iter = {0};
drmModePropertyBlobPtr blob; drmModePropertyBlobPtr blob;
struct drm_format_modifier_blob *header; uint32_t fmt = 0;
uint32_t *formats;
struct drm_format_modifier *modifiers;
printf("\t\tin_formats blob decoded:\n"); printf("\t\tin_formats blob decoded:\n");
blob = drmModeGetPropertyBlob(dev->fd, blob_id); blob = drmModeGetPropertyBlob(dev->fd, blob_id);
@ -313,23 +311,19 @@ static void dump_in_formats(struct device *dev, uint32_t blob_id)
return; return;
} }
header = blob->data; while (drmModeFormatModifierBlobIterNext(blob, &iter)) {
formats = (uint32_t *) ((char *) header + header->formats_offset); if (!fmt || fmt != iter.fmt) {
modifiers = (struct drm_format_modifier *) printf("%s\t\t\t", !fmt ? "" : "\n");
((char *) header + header->modifiers_offset); fmt = iter.fmt;
dump_fourcc(fmt);
for (i = 0; i < header->count_formats; i++) { printf(": ");
printf("\t\t\t");
dump_fourcc(formats[i]);
printf(": ");
for (j = 0; j < header->count_modifiers; j++) {
uint64_t mask = 1ULL << i;
if (modifiers[j].formats & mask)
printf(" %s", modifier_to_string(modifiers[j].modifier));
} }
printf("\n");
printf(" %s", modifier_to_string(iter.mod));
} }
printf("\n");
drmModeFreePropertyBlob(blob); drmModeFreePropertyBlob(blob);
} }

View File

@ -33,6 +33,7 @@
* *
*/ */
#include <assert.h>
#include <limits.h> #include <limits.h>
#include <stdint.h> #include <stdint.h>
#include <stdlib.h> #include <stdlib.h>
@ -50,6 +51,7 @@
#include "xf86drmMode.h" #include "xf86drmMode.h"
#include "xf86drm.h" #include "xf86drm.h"
#include <drm.h> #include <drm.h>
#include <drm_fourcc.h>
#include <string.h> #include <string.h>
#include <dirent.h> #include <dirent.h>
#include <unistd.h> #include <unistd.h>
@ -727,6 +729,112 @@ err_allocs:
return r; return r;
} }
static inline const uint32_t *
get_formats_ptr(const struct drm_format_modifier_blob *blob)
{
return (const uint32_t *)(((uint8_t *)blob) + blob->formats_offset);
}
static inline const struct drm_format_modifier *
get_modifiers_ptr(const struct drm_format_modifier_blob *blob)
{
return (const struct drm_format_modifier *)(((uint8_t *)blob) +
blob->modifiers_offset);
}
static bool _drmModeFormatModifierGetNext(const drmModePropertyBlobRes *blob,
drmModeFormatModifierIterator *iter)
{
const struct drm_format_modifier *blob_modifiers, *mod;
const struct drm_format_modifier_blob *fmt_mod_blob;
const uint32_t *blob_formats;
assert(blob && iter);
fmt_mod_blob = blob->data;
blob_modifiers = get_modifiers_ptr(fmt_mod_blob);
blob_formats = get_formats_ptr(fmt_mod_blob);
/* fmt_idx and mod_idx designate the number of processed formats
* and modifiers.
*/
if (iter->fmt_idx >= fmt_mod_blob->count_formats ||
iter->mod_idx >= fmt_mod_blob->count_modifiers)
return false;
iter->fmt = blob_formats[iter->fmt_idx];
iter->mod = DRM_FORMAT_MOD_INVALID;
/* From the latest valid found, get the next valid modifier */
while (iter->mod_idx < fmt_mod_blob->count_modifiers) {
mod = &blob_modifiers[iter->mod_idx++];
/* Check if the format that fmt_idx designates, belongs to
* this modifier 64-bit window selected via mod->offset.
*/
if (iter->fmt_idx < mod->offset ||
iter->fmt_idx >= mod->offset + 64)
continue;
if (!(mod->formats & (1 << (iter->fmt_idx - mod->offset))))
continue;
iter->mod = mod->modifier;
break;
}
if (iter->mod_idx == fmt_mod_blob->count_modifiers) {
iter->mod_idx = 0;
iter->fmt_idx++;
}
/* Since mod_idx reset, in order for the caller to iterate over
* the last modifier of the last format, always return true here
* and early return from the next call.
*/
return true;
}
/**
* Iterate over formats first and then over modifiers. On each call, iter->fmt
* is retained until all associated modifiers are returned. Then, either update
* iter->fmt with the next format, or exit if there aren't any left.
*
* NOTE: clients should not make any assumption on mod_idx and fmt_idx values
*
* @blob: valid kernel blob holding formats and modifiers
* @iter: input and output iterator data. Iter data must be initialised to zero
* @return: false, on error or there aren't any further formats or modifiers left.
* true, on success and there are more formats or modifiers.
*/
drm_public bool drmModeFormatModifierBlobIterNext(const drmModePropertyBlobRes *blob,
drmModeFormatModifierIterator *iter)
{
drmModeFormatModifierIterator tmp;
bool has_fmt;
if (!blob || !iter)
return false;
tmp.fmt_idx = iter->fmt_idx;
tmp.mod_idx = iter->mod_idx;
/* With the current state of things, DRM/KMS drivers are allowed to
* construct blobs having formats and no modifiers. Userspace can't
* legitimately abort in such cases.
*
* While waiting for the kernel to perhaps disallow formats with no
* modifiers in IN_FORMATS blobs, skip the format altogether.
*/
do {
has_fmt = _drmModeFormatModifierGetNext(blob, &tmp);
if (has_fmt && tmp.mod != DRM_FORMAT_MOD_INVALID)
*iter = tmp;
} while (has_fmt && tmp.mod == DRM_FORMAT_MOD_INVALID);
return has_fmt;
}
drm_public void drmModeFreePropertyBlob(drmModePropertyBlobPtr ptr) drm_public void drmModeFreePropertyBlob(drmModePropertyBlobPtr ptr)
{ {
if (!ptr) if (!ptr)

View File

@ -42,6 +42,7 @@ extern "C" {
#include <drm.h> #include <drm.h>
#include <drm_mode.h> #include <drm_mode.h>
#include <stdbool.h>
#include <stddef.h> #include <stddef.h>
#include <stdint.h> #include <stdint.h>
@ -231,6 +232,12 @@ typedef struct _drmModeObjectProperties {
uint64_t *prop_values; uint64_t *prop_values;
} drmModeObjectProperties, *drmModeObjectPropertiesPtr; } drmModeObjectProperties, *drmModeObjectPropertiesPtr;
typedef struct _drmModeFormatModifierIterator {
uint32_t fmt_idx, mod_idx;
uint32_t fmt;
uint64_t mod;
} drmModeFormatModifierIterator;
typedef struct _drmModePlane { typedef struct _drmModePlane {
uint32_t count_formats; uint32_t count_formats;
uint32_t *formats; uint32_t *formats;
@ -388,6 +395,8 @@ extern drmModePropertyPtr drmModeGetProperty(int fd, uint32_t propertyId);
extern void drmModeFreeProperty(drmModePropertyPtr ptr); extern void drmModeFreeProperty(drmModePropertyPtr ptr);
extern drmModePropertyBlobPtr drmModeGetPropertyBlob(int fd, uint32_t blob_id); extern drmModePropertyBlobPtr drmModeGetPropertyBlob(int fd, uint32_t blob_id);
extern bool drmModeFormatModifierBlobIterNext(const drmModePropertyBlobRes *blob,
drmModeFormatModifierIterator *iter);
extern void drmModeFreePropertyBlob(drmModePropertyBlobPtr ptr); extern void drmModeFreePropertyBlob(drmModePropertyBlobPtr ptr);
extern int drmModeConnectorSetProperty(int fd, uint32_t connector_id, uint32_t property_id, extern int drmModeConnectorSetProperty(int fd, uint32_t connector_id, uint32_t property_id,
uint64_t value); uint64_t value);