Revision control
Copy as Markdown
// Copyright (C) 2026 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qmultimedia_drm_support_p.h"
#include <QtCore/qdebug.h>
QT_BEGIN_NAMESPACE
using namespace Qt::StringLiterals;
namespace QtMultimediaPrivate {
namespace {
// see DRM_FORMAT_MOD_VENDOR_* in drm_fourcc.h
QString modifierVendorName(uint8_t vendor)
{
switch (vendor) {
case 0x00:
return u"none"_s;
case 0x01:
return u"Intel"_s;
case 0x02:
return u"AMD"_s;
case 0x03:
return u"NVIDIA"_s;
case 0x04:
return u"Samsung"_s;
case 0x05:
return u"Qualcomm"_s;
case 0x06:
return u"Vivante"_s;
case 0x07:
return u"Broadcom"_s;
case 0x08:
return u"ARM"_s;
case 0x09:
return u"Allwinner"_s;
case 0x0a:
return u"Amlogic"_s;
default:
return u"unknown vendor 0x%1"_s.arg(vendor, 2, 16, u'0');
}
}
// Decodes DRM_FORMAT_MOD_NVIDIA_BLOCK_LINEAR_2D(c, s, g, k, h) per the bitfield
// layout documented in drm_fourcc.h.
QString decodeNvidiaModifier(uint64_t payload)
{
if (payload == 1)
return u"Tegra tiled"_s;
if (!(payload & 0x10))
return u"unknown layout, raw 0x%1"_s.arg(payload, 14, 16, u'0');
const uint32_t h = payload & 0xf;
const uint32_t k = (payload >> 12) & 0xff;
const uint32_t g = (payload >> 20) & 0x3;
const uint32_t s = (payload >> 22) & 0x1;
const uint32_t c = (payload >> 23) & 0x7;
static const QString gobHeights[] = {
u"8, Fermi-Volta/Tegra K1+ page kind mapping"_s,
u"4, G80-GT2XX page kind mapping"_s,
u"8, Turing+ page kind mapping"_s,
u"reserved"_s,
};
static const QString compressionKinds[] = {
u"none"_s, u"ROP/3D layout 1"_s, u"ROP/3D layout 2"_s, u"CDE horizontal"_s,
u"CDE vertical"_s, u"reserved"_s, u"reserved"_s, u"reserved"_s,
};
return u"block-linear, block height 2^%1 GOBs, page kind 0x%2, GOB height %3, "
"sector layout: %4, compression: %5"_s.arg(h)
.arg(k, 2, 16, u'0')
.arg(gobHeights[g])
.arg(s ? u"desktop GPU / Tegra Xavier+"_s : u"Tegra K1 - Parker/TX2"_s)
.arg(compressionKinds[c]);
}
// see I915_FORMAT_MOD_* in drm_fourcc.h
QString decodeIntelModifier(uint64_t payload)
{
switch (payload) {
case 1:
return u"X tiled"_s;
case 2:
return u"Y tiled"_s;
case 3:
return u"Yf tiled"_s;
case 4:
return u"Y tiled, CCS"_s;
case 5:
return u"Yf tiled, CCS"_s;
case 6:
return u"Y tiled, Gen12 render compression CCS"_s;
case 7:
return u"Y tiled, Gen12 media compression CCS"_s;
case 8:
return u"Y tiled, Gen12 render compression CCS with clear color"_s;
case 9:
return u"4 tiled"_s;
case 10:
return u"4 tiled, DG2 render compression CCS"_s;
case 11:
return u"4 tiled, DG2 media compression CCS"_s;
case 12:
return u"4 tiled, DG2 render compression CCS with clear color"_s;
default:
return u"unknown layout, raw 0x%1"_s.arg(payload, 14, 16, u'0');
}
}
// see AMD_FMT_MOD_* in drm_fourcc.h
QString decodeAmdModifier(uint64_t payload)
{
const uint32_t tileVersion = payload & 0xff;
if (tileVersion == 0)
return u"GFX8 or older, linear-compatible"_s;
static const QString tileVersions[] = {
{}, u"GFX9"_s, u"GFX10"_s, u"GFX10 RBPlus"_s, u"GFX11"_s,
};
static const QString dccBlockSizes[] = {
u"64B"_s,
u"128B"_s,
u"256B"_s,
u"reserved"_s,
};
const uint32_t tile = (payload >> 8) & 0x1f;
const bool dcc = (payload >> 13) & 0x1;
QString result = u"tile version %1, tile mode %2"_s
.arg(tileVersion < std::size(tileVersions) ? tileVersions[tileVersion]
: u"unknown"_s)
.arg(tile);
if (dcc) {
const bool dccRetile = (payload >> 14) & 0x1;
const bool dccPipeAlign = (payload >> 15) & 0x1;
const uint32_t dccMaxCompressedBlock = (payload >> 18) & 0x3;
result += u", DCC (retile: %1, pipe-aligned: %2, max compressed block: %3)"_s
.arg(dccRetile ? u"yes"_s : u"no"_s)
.arg(dccPipeAlign ? u"yes"_s : u"no"_s)
.arg(dccBlockSizes[dccMaxCompressedBlock]);
}
return result;
}
// see DRM_FORMAT_MOD_ARM_* and AFBC_FORMAT_MOD_* in drm_fourcc.h
QString decodeArmModifier(uint64_t payload)
{
const uint32_t type = (payload >> 52) & 0xf;
const uint64_t value = payload & 0x000fffffffffffffULL;
if (type != 0x00) // DRM_FORMAT_MOD_ARM_TYPE_AFBC
return u"type 0x%1, raw 0x%2"_s.arg(type).arg(value, 13, 16, u'0');
static const QString blockSizes[] = {
u"none"_s, u"16x16"_s, u"32x8"_s, u"64x4"_s, u"32x8_64x4"_s,
};
const uint32_t blockSize = value & 0xf;
QStringList flags;
if (value & (1ULL << 4))
flags << u"YTR"_s;
if (value & (1ULL << 5))
flags << u"split"_s;
if (value & (1ULL << 6))
flags << u"sparse"_s;
if (value & (1ULL << 7))
flags << u"CBR"_s;
if (value & (1ULL << 8))
flags << u"tiled"_s;
if (value & (1ULL << 9))
flags << u"SC"_s;
if (value & (1ULL << 10))
flags << u"double-buffered"_s;
if (value & (1ULL << 11))
flags << u"block-channel"_s;
if (value & (1ULL << 12))
flags << u"USM"_s;
return u"AFBC, superblock size %1%2"_s
.arg(blockSize < std::size(blockSizes) ? blockSizes[blockSize] : u"unknown"_s)
.arg(flags.isEmpty() ? QString() : u", flags: "_s + flags.join(u'|'));
}
// see DRM_FORMAT_MOD_BROADCOM_* in drm_fourcc.h
QString decodeBroadcomModifier(uint64_t payload)
{
const uint64_t mod = payload & 0xff;
const uint64_t param = (payload >> 8) & 0xffffffffffffULL;
switch (mod) {
case 1:
return u"VC4 T-tiled"_s;
case 2:
return u"SAND32, column height %1"_s.arg(param);
case 3:
return u"SAND64, column height %1"_s.arg(param);
case 4:
return u"SAND128, column height %1"_s.arg(param);
case 5:
return u"SAND256, column height %1"_s.arg(param);
case 6:
return u"UIF"_s;
default:
return u"unknown layout, raw 0x%1"_s.arg(payload, 14, 16, u'0');
}
}
// see DRM_FORMAT_MOD_QCOM_* in drm_fourcc.h
QString decodeQualcommModifier(uint64_t payload)
{
switch (payload) {
case 1:
return u"compressed"_s;
case 2:
return u"alternate tiled"_s;
case 3:
return u"tiled"_s;
default:
return u"unknown layout, raw 0x%1"_s.arg(payload, 14, 16, u'0');
}
}
// see DRM_FORMAT_MOD_VIVANTE_* in drm_fourcc.h
QString decodeVivanteModifier(uint64_t payload)
{
switch (payload) {
case 1:
return u"4x4 tiled"_s;
case 2:
return u"64x64 super-tiled"_s;
case 3:
return u"4x4 tiled, split (dual-pipe)"_s;
case 4:
return u"64x64 super-tiled, split (dual-pipe)"_s;
default:
return u"unknown layout, raw 0x%1"_s.arg(payload, 14, 16, u'0');
}
}
// see DRM_FORMAT_MOD_SAMSUNG_* in drm_fourcc.h
QString decodeSamsungModifier(uint64_t payload)
{
switch (payload) {
case 1:
return u"64x32 tiled"_s;
case 2:
return u"16x16 tiled"_s;
default:
return u"unknown layout, raw 0x%1"_s.arg(payload, 14, 16, u'0');
}
}
// see DRM_FORMAT_MOD_ALLWINNER_TILED in drm_fourcc.h
QString decodeAllwinnerModifier(uint64_t payload)
{
if (payload == 1)
return u"tiled"_s;
return u"unknown layout, raw 0x%1"_s.arg(payload, 14, 16, u'0');
}
// see DRM_FORMAT_MOD_AMLOGIC_FBC in drm_fourcc.h
QString decodeAmlogicModifier(uint64_t payload)
{
const uint32_t layout = payload & 0xff;
const uint32_t options = (payload >> 8) & 0xff;
QString result;
switch (layout) {
case 1:
result = u"FBC basic layout"_s;
break;
case 2:
result = u"FBC scatter layout"_s;
break;
default:
return u"unknown layout, raw 0x%1"_s.arg(payload, 14, 16, u'0');
}
if (options & 0x1)
result += u", memory saving"_s;
return result;
}
} // namespace
QString toString(DRMFormat format)
{
const uint32_t code = qToUnderlying(format);
QString result;
for (int i = 0; i < 4; ++i) {
const char c = char((code >> (8 * i)) & 0xff);
result += QChar(c == ' ' ? u'_' : c);
}
return result;
}
QDebug operator<<(QDebug debug, DRMFormat format)
{
const QDebugStateSaver saver(debug);
debug.nospace().noquote() << "DRMFormat(0x" << Qt::hex << qToUnderlying(format) << Qt::dec
<< ", " << toString(format) << ')';
return debug;
}
QString toString(DRMModifier modifier)
{
if (modifier == DrmFormatModifierLinear)
return u"linear"_s;
if (modifier == DmaBufFormatModifierInvalid)
return u"invalid"_s;
const uint64_t value = qToUnderlying(modifier);
const uint8_t vendor = uint8_t(value >> 56);
const uint64_t payload = value & ((uint64_t(1) << 56) - 1);
const QString vendorName = modifierVendorName(vendor);
switch (vendor) {
case 0x01:
return vendorName + u", "_s + decodeIntelModifier(payload);
case 0x02:
return vendorName + u", "_s + decodeAmdModifier(payload);
case 0x03:
return vendorName + u", "_s + decodeNvidiaModifier(payload);
case 0x04:
return vendorName + u", "_s + decodeSamsungModifier(payload);
case 0x05:
return vendorName + u", "_s + decodeQualcommModifier(payload);
case 0x06:
return vendorName + u", "_s + decodeVivanteModifier(payload);
case 0x07:
return vendorName + u", "_s + decodeBroadcomModifier(payload);
case 0x08:
return vendorName + u", "_s + decodeArmModifier(payload);
case 0x09:
return vendorName + u", "_s + decodeAllwinnerModifier(payload);
case 0x0a:
return vendorName + u", "_s + decodeAmlogicModifier(payload);
default:
return u"%1, vendor-specific payload 0x%2"_s.arg(vendorName).arg(payload, 14, 16, u'0');
}
}
QDebug operator<<(QDebug debug, DRMModifier modifier)
{
const QDebugStateSaver saver(debug);
debug.nospace().noquote() << "DRMModifier(0x" << Qt::hex << qToUnderlying(modifier) << Qt::dec
<< ", " << toString(modifier) << ')';
return debug;
}
} // namespace QtMultimediaPrivate
QT_END_NAMESPACE