summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core-symbols.txt1
-rw-r--r--tests/modetest/modetest.c30
-rw-r--r--xf86drmMode.c108
-rw-r--r--xf86drmMode.h9
4 files changed, 130 insertions, 18 deletions
diff --git a/core-symbols.txt b/core-symbols.txt
index ed0d8035..8e725132 100644
--- a/core-symbols.txt
+++ b/core-symbols.txt
@@ -110,6 +110,7 @@ drmModeCrtcSetGamma
drmModeDestroyPropertyBlob
drmModeDetachMode
drmModeDirtyFB
+drmModeFormatModifierBlobIterNext
drmModeFreeConnector
drmModeFreeCrtc
drmModeFreeEncoder
diff --git a/tests/modetest/modetest.c b/tests/modetest/modetest.c
index 5746357f..5fd22f79 100644
--- a/tests/modetest/modetest.c
+++ b/tests/modetest/modetest.c
@@ -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,23 +311,19 @@ 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]);
- 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));
+ while (drmModeFormatModifierBlobIterNext(blob, &iter)) {
+ if (!fmt || fmt != iter.fmt) {
+ printf("%s\t\t\t", !fmt ? "" : "\n");
+ fmt = iter.fmt;
+ dump_fourcc(fmt);
+ printf(": ");
}
- printf("\n");
+
+ printf(" %s", modifier_to_string(iter.mod));
}
+ printf("\n");
+
drmModeFreePropertyBlob(blob);
}
diff --git a/xf86drmMode.c b/xf86drmMode.c
index 0106954b..84d3c771 100644
--- a/xf86drmMode.c
+++ b/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)
diff --git a/xf86drmMode.h b/xf86drmMode.h
index de0e2fdb..19bf91dd 100644
--- a/xf86drmMode.h
+++ b/xf86drmMode.h
@@ -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);