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.
This commit is contained in:
parent
3568829216
commit
b860439be5
6 changed files with 113 additions and 71 deletions
|
@ -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 ¤tPlane = format->yuvConversion->plane[plane];
|
||||
Q_ASSERT(itConv->plane.count() == uint(buffer->dmabufAttributes()->planeCount));
|
||||
|
||||
for (uint plane = 0; plane < itConv->plane.count(); ++plane) {
|
||||
const auto ¤tPlane = 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 ¤tPlane = 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 ¤tPlane = 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…
Reference in a new issue