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
parent
f256bb9afd
commit
e641e2a632
|
@ -110,6 +110,7 @@ drmModeCrtcSetGamma
|
|||
drmModeDestroyPropertyBlob
|
||||
drmModeDetachMode
|
||||
drmModeDirtyFB
|
||||
drmModeFormatModifierBlobIterNext
|
||||
drmModeFreeConnector
|
||||
drmModeFreeCrtc
|
||||
drmModeFreeEncoder
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
uint32_t i, j;
|
||||
drmModeFormatModifierIterator iter = {0};
|
||||
drmModePropertyBlobPtr blob;
|
||||
struct drm_format_modifier_blob *header;
|
||||
uint32_t *formats;
|
||||
struct drm_format_modifier *modifiers;
|
||||
uint32_t fmt = 0;
|
||||
|
||||
printf("\t\tin_formats blob decoded:\n");
|
||||
blob = drmModeGetPropertyBlob(dev->fd, blob_id);
|
||||
|
@ -313,22 +311,18 @@ static void dump_in_formats(struct device *dev, uint32_t blob_id)
|
|||
return;
|
||||
}
|
||||
|
||||
header = blob->data;
|
||||
formats = (uint32_t *) ((char *) header + header->formats_offset);
|
||||
modifiers = (struct drm_format_modifier *)
|
||||
((char *) header + header->modifiers_offset);
|
||||
|
||||
for (i = 0; i < header->count_formats; i++) {
|
||||
printf("\t\t\t");
|
||||
dump_fourcc(formats[i]);
|
||||
while (drmModeFormatModifierBlobIterNext(blob, &iter)) {
|
||||
if (!fmt || fmt != iter.fmt) {
|
||||
printf("%s\t\t\t", !fmt ? "" : "\n");
|
||||
fmt = iter.fmt;
|
||||
dump_fourcc(fmt);
|
||||
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(" %s", modifier_to_string(iter.mod));
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
drmModeFreePropertyBlob(blob);
|
||||
}
|
||||
|
|
108
xf86drmMode.c
108
xf86drmMode.c
|
@ -33,6 +33,7 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <limits.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
@ -50,6 +51,7 @@
|
|||
#include "xf86drmMode.h"
|
||||
#include "xf86drm.h"
|
||||
#include <drm.h>
|
||||
#include <drm_fourcc.h>
|
||||
#include <string.h>
|
||||
#include <dirent.h>
|
||||
#include <unistd.h>
|
||||
|
@ -727,6 +729,112 @@ err_allocs:
|
|||
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)
|
||||
{
|
||||
if (!ptr)
|
||||
|
|
|
@ -42,6 +42,7 @@ extern "C" {
|
|||
|
||||
#include <drm.h>
|
||||
#include <drm_mode.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
|
@ -231,6 +232,12 @@ typedef struct _drmModeObjectProperties {
|
|||
uint64_t *prop_values;
|
||||
} drmModeObjectProperties, *drmModeObjectPropertiesPtr;
|
||||
|
||||
typedef struct _drmModeFormatModifierIterator {
|
||||
uint32_t fmt_idx, mod_idx;
|
||||
uint32_t fmt;
|
||||
uint64_t mod;
|
||||
} drmModeFormatModifierIterator;
|
||||
|
||||
typedef struct _drmModePlane {
|
||||
uint32_t count_formats;
|
||||
uint32_t *formats;
|
||||
|
@ -388,6 +395,8 @@ extern drmModePropertyPtr drmModeGetProperty(int fd, uint32_t propertyId);
|
|||
extern void drmModeFreeProperty(drmModePropertyPtr ptr);
|
||||
|
||||
extern drmModePropertyBlobPtr drmModeGetPropertyBlob(int fd, uint32_t blob_id);
|
||||
extern bool drmModeFormatModifierBlobIterNext(const drmModePropertyBlobRes *blob,
|
||||
drmModeFormatModifierIterator *iter);
|
||||
extern void drmModeFreePropertyBlob(drmModePropertyBlobPtr ptr);
|
||||
extern int drmModeConnectorSetProperty(int fd, uint32_t connector_id, uint32_t property_id,
|
||||
uint64_t value);
|
||||
|
|
Loading…
Reference in New Issue