Allow support dmabuf formats that we have conversions for.

If there's a supported mechanism to handle the format, announce them as
supported.
If there are modifiers supported by the graphics card (even though as
external only), offer them as well.
wilder/Plasma/6.2
Aleix Pol Gonzalez 2 years ago committed by Aleix Pol
parent 3568829216
commit b860439be5
  1. 10
      src/backends/drm/drm_egl_layer_surface.cpp
  2. 54
      src/platformsupport/scenes/opengl/abstract_egl_backend.cpp
  3. 34
      src/platformsupport/scenes/opengl/basiceglsurfacetexture_wayland.cpp
  4. 58
      src/platformsupport/scenes/opengl/egldisplay.cpp
  5. 26
      src/platformsupport/scenes/opengl/egldisplay.h
  6. 2
      src/plugins/qpa/eglplatformcontext.cpp

@ -363,20 +363,22 @@ std::unique_ptr<EglGbmLayerSurface::Surface> EglGbmLayerSurface::createSurface(c
const bool cpuCopy = importMode == MultiGpuImportMode::DumbBuffer || m_bufferTarget == BufferTarget::Dumb;
QList<uint64_t> renderModifiers;
auto ret = std::make_unique<Surface>();
const auto drmFormat = m_eglBackend->eglDisplayObject()->allSupportedDrmFormats()[format];
if (importMode == MultiGpuImportMode::Egl) {
ret->importContext = m_eglBackend->contextForGpu(m_gpu);
if (!ret->importContext || ret->importContext->isSoftwareRenderer()) {
return nullptr;
}
renderModifiers = filterModifiers(ret->importContext->displayObject()->allSupportedDrmFormats()[format],
m_eglBackend->eglDisplayObject()->supportedDrmFormats().value(format));
const auto importDrmFormat = ret->importContext->displayObject()->allSupportedDrmFormats()[format];
renderModifiers = filterModifiers(importDrmFormat.allModifiers,
drmFormat.nonExternalOnlyModifiers);
} else if (cpuCopy) {
if (!cpuCopyFormats.contains(format)) {
return nullptr;
}
renderModifiers = m_eglBackend->eglDisplayObject()->supportedDrmFormats().value(format);
renderModifiers = drmFormat.nonExternalOnlyModifiers;
} else {
renderModifiers = filterModifiers(modifiers, m_eglBackend->eglDisplayObject()->supportedDrmFormats().value(format));
renderModifiers = filterModifiers(modifiers, drmFormat.nonExternalOnlyModifiers);
}
if (renderModifiers.empty()) {
return nullptr;

@ -149,40 +149,72 @@ void AbstractEglBackend::initWayland()
}
}
auto filterFormats = [this](std::optional<uint32_t> bpc) {
const auto formats = m_display->supportedDrmFormats();
const auto formats = m_display->allSupportedDrmFormats();
auto filterFormats = [this, &formats](std::optional<uint32_t> bpc, bool withExternalOnlyYUV) {
QHash<uint32_t, QList<uint64_t>> set;
for (auto it = formats.constBegin(); it != formats.constEnd(); it++) {
const auto info = formatInfo(it.key());
if (!info || (bpc && bpc != info->bitsPerColor)) {
continue;
}
const bool duplicate = std::any_of(m_tranches.begin(), m_tranches.end(), [fmt = it.key()](const auto &tranche) {
return tranche.formatTable.contains(fmt);
});
if (duplicate) {
const bool externalOnlySupported = withExternalOnlyYUV && info->yuvConversion();
QList<uint64_t> modifiers = externalOnlySupported ? it->allModifiers : it->nonExternalOnlyModifiers;
if (externalOnlySupported && !modifiers.isEmpty()) {
if (auto yuv = info->yuvConversion()) {
for (auto plane : std::as_const(yuv->plane)) {
const auto planeModifiers = formats.value(plane.format).allModifiers;
modifiers.erase(std::remove_if(modifiers.begin(), modifiers.end(), [&planeModifiers](uint64_t mod) {
return !planeModifiers.contains(mod);
}),
modifiers.end());
}
}
}
for (const auto &tranche : std::as_const(m_tranches)) {
if (modifiers.isEmpty()) {
break;
}
const auto trancheModifiers = tranche.formatTable.value(it.key());
for (auto trancheModifier : trancheModifiers) {
modifiers.removeAll(trancheModifier);
}
}
if (modifiers.isEmpty()) {
continue;
}
set.insert(it.key(), it.value());
set.insert(it.key(), modifiers);
}
return set;
};
auto includeShaderConversions = [](QHash<uint32_t, QList<uint64_t>> &&formats) -> QHash<uint32_t, QList<uint64_t>> {
for (auto format : s_drmConversions.keys()) {
auto &modifiers = formats[format];
if (modifiers.isEmpty()) {
modifiers = {DRM_FORMAT_MOD_LINEAR};
}
}
return formats;
};
if (prefer10bpc()) {
m_tranches.append({
.device = deviceId(),
.flags = {},
.formatTable = filterFormats(10),
.formatTable = filterFormats(10, false),
});
}
m_tranches.append({
.device = deviceId(),
.flags = {},
.formatTable = filterFormats(8),
.formatTable = filterFormats(8, false),
});
m_tranches.append({
.device = deviceId(),
.flags = {},
.formatTable = filterFormats(std::nullopt),
.formatTable = includeShaderConversions(filterFormats({}, true)),
});
LinuxDmaBufV1ClientBufferIntegration *dmabuf = waylandServer()->linuxDmabuf();
@ -323,7 +355,7 @@ bool AbstractEglBackend::testImportBuffer(GraphicsBuffer *buffer)
QHash<uint32_t, QList<uint64_t>> AbstractEglBackend::supportedFormats() const
{
return m_display->supportedDrmFormats();
return m_display->nonExternalOnlySupportedDrmFormats();
}
EGLSurface AbstractEglBackend::surface() const

@ -103,19 +103,20 @@ void BasicEGLSurfaceTextureWayland::updateShmTexture(GraphicsBuffer *buffer, con
bool BasicEGLSurfaceTextureWayland::loadDmabufTexture(GraphicsBuffer *buffer)
{
auto createTexture = [this](EGLImageKHR image, const QSize &size) {
auto createTexture = [this](EGLImageKHR image, const QSize &size, bool isExternalOnly) {
if (Q_UNLIKELY(image == EGL_NO_IMAGE_KHR)) {
qCritical(KWIN_OPENGL) << "Invalid dmabuf-based wl_buffer";
return std::shared_ptr<GLTexture>();
}
auto texture = std::make_shared<GLTexture>(GL_TEXTURE_2D);
GLint target = isExternalOnly ? GL_TEXTURE_EXTERNAL_OES : GL_TEXTURE_2D;
auto texture = std::make_shared<GLTexture>(target);
texture->setSize(size);
texture->create();
texture->setWrapMode(GL_CLAMP_TO_EDGE);
texture->setFilter(GL_LINEAR);
texture->bind();
glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, static_cast<GLeglImageOES>(image));
glEGLImageTargetTexture2DOES(target, static_cast<GLeglImageOES>(image));
texture->unbind();
if (m_pixmap->bufferOrigin() == GraphicsBufferOrigin::TopLeft) {
texture->setContentTransform(TextureTransform::MirrorY);
@ -123,17 +124,20 @@ bool BasicEGLSurfaceTextureWayland::loadDmabufTexture(GraphicsBuffer *buffer)
return texture;
};
auto format = formatInfo(buffer->dmabufAttributes()->format);
if (format && format->yuvConversion) {
const auto attribs = buffer->dmabufAttributes();
auto format = formatInfo(attribs->format);
if (auto itConv = s_drmConversions.find(buffer->dmabufAttributes()->format); itConv != s_drmConversions.end()) {
QList<std::shared_ptr<GLTexture>> textures;
Q_ASSERT(format->yuvConversion->plane.count() == uint(buffer->dmabufAttributes()->planeCount));
for (uint plane = 0; plane < format->yuvConversion->plane.count(); ++plane) {
const auto &currentPlane = format->yuvConversion->plane[plane];
Q_ASSERT(itConv->plane.count() == uint(buffer->dmabufAttributes()->planeCount));
for (uint plane = 0; plane < itConv->plane.count(); ++plane) {
const auto &currentPlane = itConv->plane[plane];
QSize size = buffer->size();
size.rwidth() /= currentPlane.widthDivisor;
size.rheight() /= currentPlane.heightDivisor;
auto t = createTexture(backend()->importBufferAsImage(buffer, plane, currentPlane.format, size), size);
const bool isExternal = backend()->eglDisplayObject()->isExternalOnly(currentPlane.format, attribs->modifier);
auto t = createTexture(backend()->importBufferAsImage(buffer, plane, currentPlane.format, size), size, isExternal);
if (!t) {
return false;
}
@ -141,7 +145,8 @@ bool BasicEGLSurfaceTextureWayland::loadDmabufTexture(GraphicsBuffer *buffer)
}
m_texture = {textures};
} else {
auto texture = createTexture(backend()->importBufferAsImage(buffer), buffer->size());
const bool isExternal = backend()->eglDisplayObject()->isExternalOnly(attribs->format, attribs->modifier);
auto texture = createTexture(backend()->importBufferAsImage(buffer), buffer->size(), isExternal);
if (!texture) {
return false;
}
@ -161,11 +166,10 @@ void BasicEGLSurfaceTextureWayland::updateDmabufTexture(GraphicsBuffer *buffer)
}
const GLint target = GL_TEXTURE_2D;
auto format = formatInfo(buffer->dmabufAttributes()->format);
if (format && format->yuvConversion) {
Q_ASSERT(format->yuvConversion->plane.count() == uint(buffer->dmabufAttributes()->planeCount));
for (uint plane = 0; plane < format->yuvConversion->plane.count(); ++plane) {
const auto &currentPlane = format->yuvConversion->plane[plane];
if (auto itConv = s_drmConversions.find(buffer->dmabufAttributes()->format); itConv != s_drmConversions.end()) {
Q_ASSERT(itConv->plane.count() == uint(buffer->dmabufAttributes()->planeCount));
for (uint plane = 0; plane < itConv->plane.count(); ++plane) {
const auto &currentPlane = itConv->plane[plane];
QSize size = buffer->size();
size.rwidth() /= currentPlane.widthDivisor;
size.rheight() /= currentPlane.heightDivisor;

@ -80,9 +80,7 @@ EglDisplay::EglDisplay(::EGLDisplay display, const QList<QByteArray> &extensions
, m_owning(owning)
, m_supportsBufferAge(extensions.contains(QByteArrayLiteral("EGL_EXT_buffer_age")) && qgetenv("KWIN_USE_BUFFER_AGE") != "0")
, m_supportsNativeFence(extensions.contains(QByteArrayLiteral("EGL_ANDROID_native_fence_sync")))
, m_importFormats(queryImportFormats(Filter::Normal))
, m_externalOnlyFormats(queryImportFormats(Filter::ExternalOnly))
, m_allImportFormats(queryImportFormats(Filter::None))
, m_importFormats(queryImportFormats())
{
}
@ -241,26 +239,31 @@ EGLImageKHR EglDisplay::importDmaBufAsImage(const DmaBufAttributes &dmabuf, int
return img;
}
QHash<uint32_t, QList<uint64_t>> EglDisplay::supportedDrmFormats() const
QHash<uint32_t, EglDisplay::DrmFormatInfo> EglDisplay::allSupportedDrmFormats() const
{
return m_importFormats;
}
QHash<uint32_t, QList<uint64_t>> EglDisplay::allSupportedDrmFormats() const
QHash<uint32_t, QList<uint64_t>> EglDisplay::nonExternalOnlySupportedDrmFormats() const
{
return m_allImportFormats;
QHash<uint32_t, QList<uint64_t>> ret;
ret.reserve(m_importFormats.size());
for (auto it = m_importFormats.constBegin(), itEnd = m_importFormats.constEnd(); it != itEnd; ++it) {
ret[it.key()] = it->nonExternalOnlyModifiers;
}
return ret;
}
bool EglDisplay::isExternalOnly(uint32_t format, uint64_t modifier) const
{
if (const auto it = m_externalOnlyFormats.find(format); it != m_externalOnlyFormats.end()) {
return it->contains(modifier);
if (const auto it = m_importFormats.find(format); it != m_importFormats.end()) {
return it->externalOnlyModifiers.contains(modifier);
} else {
return false;
}
}
QHash<uint32_t, QList<uint64_t>> EglDisplay::queryImportFormats(Filter filter) const
QHash<uint32_t, EglDisplay::DrmFormatInfo> EglDisplay::queryImportFormats() const
{
if (!hasExtension(QByteArrayLiteral("EGL_EXT_image_dma_buf_import")) || !hasExtension(QByteArrayLiteral("EGL_EXT_image_dma_buf_import_modifiers"))) {
return {};
@ -287,37 +290,40 @@ QHash<uint32_t, QList<uint64_t>> EglDisplay::queryImportFormats(Filter filter) c
qCCritical(KWIN_OPENGL) << "eglQueryDmaBufFormatsEXT with count" << count << "failed!" << getEglErrorString();
return {};
}
QHash<uint32_t, QList<uint64_t>> ret;
QHash<uint32_t, DrmFormatInfo> ret;
for (const auto format : std::as_const(formats)) {
if (eglQueryDmaBufModifiersEXT != nullptr) {
EGLint count = 0;
const EGLBoolean success = eglQueryDmaBufModifiersEXT(m_handle, format, 0, nullptr, nullptr, &count);
if (success && count > 0) {
QList<uint64_t> modifiers(count);
DrmFormatInfo drmFormatInfo;
drmFormatInfo.allModifiers.resize(count);
QList<EGLBoolean> externalOnly(count);
if (eglQueryDmaBufModifiersEXT(m_handle, format, count, modifiers.data(), externalOnly.data(), &count)) {
if (filter != Filter::None) {
const bool external = filter == Filter::Normal;
for (int i = modifiers.size() - 1; i >= 0; i--) {
if (externalOnly[i] == external) {
modifiers.remove(i);
externalOnly.remove(i);
}
if (eglQueryDmaBufModifiersEXT(m_handle, format, count, drmFormatInfo.allModifiers.data(), externalOnly.data(), &count)) {
drmFormatInfo.externalOnlyModifiers = drmFormatInfo.allModifiers;
drmFormatInfo.nonExternalOnlyModifiers = drmFormatInfo.allModifiers;
for (int i = drmFormatInfo.allModifiers.size() - 1; i >= 0; i--) {
if (externalOnly[i]) {
drmFormatInfo.nonExternalOnlyModifiers.removeAll(drmFormatInfo.allModifiers[i]);
} else {
drmFormatInfo.externalOnlyModifiers.removeAll(drmFormatInfo.allModifiers[i]);
}
}
if (!modifiers.empty()) {
if (filter != Filter::ExternalOnly && !modifiers.contains(DRM_FORMAT_MOD_INVALID)) {
modifiers.push_back(DRM_FORMAT_MOD_INVALID);
if (!drmFormatInfo.allModifiers.empty()) {
if (!drmFormatInfo.allModifiers.contains(DRM_FORMAT_MOD_INVALID)) {
drmFormatInfo.allModifiers.push_back(DRM_FORMAT_MOD_INVALID);
drmFormatInfo.nonExternalOnlyModifiers.push_back(DRM_FORMAT_MOD_INVALID);
}
ret.insert(format, modifiers);
ret.insert(format, drmFormatInfo);
}
continue;
}
}
}
if (filter != Filter::ExternalOnly) {
ret.insert(format, {DRM_FORMAT_MOD_INVALID, DRM_FORMAT_MOD_LINEAR});
}
DrmFormatInfo drmFormat;
drmFormat.allModifiers = {DRM_FORMAT_MOD_INVALID, DRM_FORMAT_MOD_LINEAR};
drmFormat.nonExternalOnlyModifiers = {DRM_FORMAT_MOD_INVALID, DRM_FORMAT_MOD_LINEAR};
ret.insert(format, drmFormat);
}
return ret;
}

@ -25,6 +25,13 @@ class GLTexture;
class KWIN_EXPORT EglDisplay
{
public:
struct DrmFormatInfo
{
QList<uint64_t> allModifiers;
QList<uint64_t> nonExternalOnlyModifiers;
QList<uint64_t> externalOnlyModifiers;
};
EglDisplay(::EGLDisplay display, const QList<QByteArray> &extensions, bool owning = true);
~EglDisplay();
@ -36,11 +43,9 @@ public:
bool supportsBufferAge() const;
bool supportsNativeFence() const;
QHash<uint32_t, QList<uint64_t>> supportedDrmFormats() const;
/**
* includes external formats
*/
QHash<uint32_t, QList<uint64_t>> allSupportedDrmFormats() const;
QHash<uint32_t, QList<uint64_t>> nonExternalOnlySupportedDrmFormats() const;
QHash<uint32_t, DrmFormatInfo> allSupportedDrmFormats() const;
bool isExternalOnly(uint32_t format, uint64_t modifier) const;
EGLImageKHR importDmaBufAsImage(const DmaBufAttributes &dmabuf) const;
@ -49,12 +54,7 @@ public:
static std::unique_ptr<EglDisplay> create(::EGLDisplay display, bool owning = true);
private:
enum class Filter {
None,
Normal,
ExternalOnly
};
QHash<uint32_t, QList<uint64_t>> queryImportFormats(Filter filter) const;
QHash<uint32_t, DrmFormatInfo> queryImportFormats() const;
const ::EGLDisplay m_handle;
const QList<QByteArray> m_extensions;
@ -62,9 +62,7 @@ private:
const bool m_supportsBufferAge;
const bool m_supportsNativeFence;
const QHash<uint32_t, QList<uint64_t>> m_importFormats;
const QHash<uint32_t, QList<uint64_t>> m_externalOnlyFormats;
const QHash<uint32_t, QList<uint64_t>> m_allImportFormats;
const QHash<uint32_t, DrmFormatInfo> m_importFormats;
};
}

@ -75,7 +75,7 @@ bool EGLPlatformContext::makeCurrent(QPlatformSurface *surface)
QOpenGLContextPrivate::setCurrentContext(context());
Window *window = static_cast<Window *>(surface);
Swapchain *swapchain = window->swapchain(m_eglDisplay->supportedDrmFormats());
Swapchain *swapchain = window->swapchain(m_eglDisplay->nonExternalOnlySupportedDrmFormats());
GraphicsBuffer *buffer = swapchain->acquire();
if (!buffer) {

Loading…
Cancel
Save