backends/drm: handle broken legacy drivers better

Some legacy drivers either don't accept gbm buffers suitable for cursors,
or don't handle them properly. In order to work around that, always do a
CPU import with legacy and use dumb buffers instead.

BUG: 453860
CCBUG: 456306
This commit is contained in:
Xaver Hugl 2022-07-13 09:46:38 +02:00
parent e09ca74295
commit 7f04ea578f
3 changed files with 34 additions and 24 deletions

View file

@ -24,7 +24,9 @@ EglGbmCursorLayer::EglGbmCursorLayer(EglGbmBackend *eglBackend, DrmPipeline *pip
OutputLayerBeginFrameInfo EglGbmCursorLayer::beginFrame()
{
return m_surface.startRendering(m_pipeline->gpu()->cursorSize(), m_pipeline->renderOrientation(), DrmPlane::Transformation::Rotate0, m_pipeline->cursorFormats(), GBM_BO_USE_LINEAR);
// some legacy drivers don't work with linear gbm buffers for the cursor
const auto target = m_pipeline->gpu()->atomicModeSetting() ? EglGbmLayerSurface::BufferTarget::Linear : EglGbmLayerSurface::BufferTarget::Dumb;
return m_surface.startRendering(m_pipeline->gpu()->cursorSize(), m_pipeline->renderOrientation(), DrmPlane::Transformation::Rotate0, m_pipeline->cursorFormats(), target);
}
void EglGbmCursorLayer::aboutToStartPainting(const QRegion &damagedRegion)
@ -35,7 +37,9 @@ void EglGbmCursorLayer::aboutToStartPainting(const QRegion &damagedRegion)
bool EglGbmCursorLayer::endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion)
{
Q_UNUSED(renderedRegion)
const auto ret = m_surface.endRendering(m_pipeline->renderOrientation(), damagedRegion);
// some legacy drivers don't work with linear gbm buffers for the cursor
const auto target = m_pipeline->gpu()->atomicModeSetting() ? EglGbmLayerSurface::BufferTarget::Linear : EglGbmLayerSurface::BufferTarget::Dumb;
const auto ret = m_surface.endRendering(m_pipeline->renderOrientation(), damagedRegion, target);
if (ret.has_value()) {
QRegion throwaway;
std::tie(m_currentBuffer, throwaway) = ret.value();

View file

@ -55,9 +55,9 @@ void EglGbmLayerSurface::destroyResources()
m_oldGbmSurface.reset();
}
OutputLayerBeginFrameInfo EglGbmLayerSurface::startRendering(const QSize &bufferSize, DrmPlane::Transformations renderOrientation, DrmPlane::Transformations bufferOrientation, const QMap<uint32_t, QVector<uint64_t>> &formats, uint32_t additionalFlags)
OutputLayerBeginFrameInfo EglGbmLayerSurface::startRendering(const QSize &bufferSize, DrmPlane::Transformations renderOrientation, DrmPlane::Transformations bufferOrientation, const QMap<uint32_t, QVector<uint64_t>> &formats, BufferTarget target)
{
if (!checkGbmSurface(bufferSize, formats, additionalFlags)) {
if (!checkGbmSurface(bufferSize, formats, target == BufferTarget::Linear)) {
return {};
}
if (!m_gbmSurface->makeContextCurrent()) {
@ -118,7 +118,7 @@ void EglGbmLayerSurface::aboutToStartPainting(DrmOutput *output, const QRegion &
}
}
std::optional<std::tuple<std::shared_ptr<DrmFramebuffer>, QRegion>> EglGbmLayerSurface::endRendering(DrmPlane::Transformations renderOrientation, const QRegion &damagedRegion)
std::optional<std::tuple<std::shared_ptr<DrmFramebuffer>, QRegion>> EglGbmLayerSurface::endRendering(DrmPlane::Transformations renderOrientation, const QRegion &damagedRegion, BufferTarget target)
{
if (m_shadowBuffer) {
GLFramebuffer::popFramebuffer();
@ -126,7 +126,7 @@ std::optional<std::tuple<std::shared_ptr<DrmFramebuffer>, QRegion>> EglGbmLayerS
m_shadowBuffer->render(renderOrientation);
}
GLFramebuffer::popFramebuffer();
if (m_gpu == m_eglBackend->gpu()) {
if (m_gpu == m_eglBackend->gpu() && target != BufferTarget::Dumb) {
if (const auto buffer = m_gbmSurface->swapBuffers(damagedRegion)) {
m_currentBuffer = buffer;
auto ret = DrmFramebuffer::createFramebuffer(buffer);
@ -138,7 +138,7 @@ std::optional<std::tuple<std::shared_ptr<DrmFramebuffer>, QRegion>> EglGbmLayerS
} else {
if (const auto gbmBuffer = m_gbmSurface->swapBuffers(damagedRegion)) {
m_currentBuffer = gbmBuffer;
const auto buffer = importBuffer();
const auto buffer = target == BufferTarget::Dumb ? importWithCpu() : importBuffer();
if (buffer) {
return std::tuple(buffer, damagedRegion);
}
@ -147,7 +147,7 @@ std::optional<std::tuple<std::shared_ptr<DrmFramebuffer>, QRegion>> EglGbmLayerS
return {};
}
bool EglGbmLayerSurface::checkGbmSurface(const QSize &bufferSize, const QMap<uint32_t, QVector<uint64_t>> &formats, uint32_t flags)
bool EglGbmLayerSurface::checkGbmSurface(const QSize &bufferSize, const QMap<uint32_t, QVector<uint64_t>> &formats, bool forceLinear)
{
if (doesGbmSurfaceFit(m_gbmSurface.get(), bufferSize, formats)) {
m_oldGbmSurface.reset();
@ -155,7 +155,7 @@ bool EglGbmLayerSurface::checkGbmSurface(const QSize &bufferSize, const QMap<uin
if (doesGbmSurfaceFit(m_oldGbmSurface.get(), bufferSize, formats)) {
m_gbmSurface = m_oldGbmSurface;
} else {
if (!createGbmSurface(bufferSize, formats, flags)) {
if (!createGbmSurface(bufferSize, formats, forceLinear)) {
return false;
}
// dmabuf might work with the new surface
@ -167,7 +167,7 @@ bool EglGbmLayerSurface::checkGbmSurface(const QSize &bufferSize, const QMap<uin
return m_gbmSurface != nullptr;
}
bool EglGbmLayerSurface::createGbmSurface(const QSize &size, uint32_t format, const QVector<uint64_t> &modifiers, uint32_t flags)
bool EglGbmLayerSurface::createGbmSurface(const QSize &size, uint32_t format, const QVector<uint64_t> &modifiers, bool forceLinear)
{
static bool modifiersEnvSet = false;
static const bool modifiersEnv = qEnvironmentVariableIntValue("KWIN_DRM_USE_MODIFIERS", &modifiersEnvSet) != 0;
@ -190,10 +190,11 @@ bool EglGbmLayerSurface::createGbmSurface(const QSize &size, uint32_t format, co
return false;
}
}
int gbmFlags = flags | GBM_BO_USE_RENDERING;
uint32_t gbmFlags = GBM_BO_USE_RENDERING;
if (m_gpu == m_eglBackend->gpu()) {
gbmFlags |= GBM_BO_USE_SCANOUT;
} else {
}
if (forceLinear || m_gpu != m_eglBackend->gpu()) {
gbmFlags |= GBM_BO_USE_LINEAR;
}
const auto ret = GbmSurface::createSurface(m_eglBackend, size, format, gbmFlags, config);
@ -206,7 +207,7 @@ bool EglGbmLayerSurface::createGbmSurface(const QSize &size, uint32_t format, co
}
}
bool EglGbmLayerSurface::createGbmSurface(const QSize &size, const QMap<uint32_t, QVector<uint64_t>> &formats, uint32_t flags)
bool EglGbmLayerSurface::createGbmSurface(const QSize &size, const QMap<uint32_t, QVector<uint64_t>> &formats, bool forceLinear)
{
QVector<GbmFormat> sortedFormats;
for (auto it = formats.begin(); it != formats.end(); it++) {
@ -231,7 +232,7 @@ bool EglGbmLayerSurface::createGbmSurface(const QSize &size, const QMap<uint32_t
if (m_importMode == MultiGpuImportMode::DumbBufferXrgb8888 && format.drmFormat != DRM_FORMAT_XRGB8888) {
continue;
}
if (formats.contains(format.drmFormat) && createGbmSurface(size, format.drmFormat, formats[format.drmFormat], flags)) {
if (formats.contains(format.drmFormat) && createGbmSurface(size, format.drmFormat, formats[format.drmFormat], forceLinear)) {
return true;
}
}
@ -355,9 +356,9 @@ std::shared_ptr<GLTexture> EglGbmLayerSurface::texture() const
return m_eglBackend->importBufferObjectAsTexture(m_currentBuffer->bo());
}
std::shared_ptr<DrmFramebuffer> EglGbmLayerSurface::renderTestBuffer(const QSize &bufferSize, const QMap<uint32_t, QVector<uint64_t>> &formats, uint32_t additionalFlags)
std::shared_ptr<DrmFramebuffer> EglGbmLayerSurface::renderTestBuffer(const QSize &bufferSize, const QMap<uint32_t, QVector<uint64_t>> &formats, BufferTarget target)
{
if (!checkGbmSurface(bufferSize, formats, additionalFlags) || !m_gbmSurface->makeContextCurrent()) {
if (!checkGbmSurface(bufferSize, formats, target == BufferTarget::Linear) || !m_gbmSurface->makeContextCurrent()) {
return nullptr;
}
glClear(GL_COLOR_BUFFER_BIT);
@ -365,13 +366,13 @@ std::shared_ptr<DrmFramebuffer> EglGbmLayerSurface::renderTestBuffer(const QSize
if (m_currentBuffer) {
if (m_gpu != m_eglBackend->gpu()) {
auto oldImportMode = m_importMode;
auto buffer = importBuffer();
auto buffer = target == BufferTarget::Dumb ? importWithCpu() : importBuffer();
if (buffer) {
return buffer;
} else if (m_importMode != oldImportMode) {
// try again with the new import mode
// recursion depth is limited by the number of import modes
return renderTestBuffer(bufferSize, formats, additionalFlags);
return renderTestBuffer(bufferSize, formats);
} else {
return nullptr;
}

View file

@ -41,20 +41,25 @@ public:
EglGbmLayerSurface(DrmGpu *gpu, EglGbmBackend *eglBackend);
~EglGbmLayerSurface();
OutputLayerBeginFrameInfo startRendering(const QSize &bufferSize, DrmPlane::Transformations renderOrientation, DrmPlane::Transformations bufferOrientation, const QMap<uint32_t, QVector<uint64_t>> &formats, uint32_t additionalFlags = 0);
enum class BufferTarget {
Normal,
Linear,
Dumb
};
OutputLayerBeginFrameInfo startRendering(const QSize &bufferSize, DrmPlane::Transformations renderOrientation, DrmPlane::Transformations bufferOrientation, const QMap<uint32_t, QVector<uint64_t>> &formats, BufferTarget target = BufferTarget::Normal);
void aboutToStartPainting(DrmOutput *output, const QRegion &damagedRegion);
std::optional<std::tuple<std::shared_ptr<DrmFramebuffer>, QRegion>> endRendering(DrmPlane::Transformations renderOrientation, const QRegion &damagedRegion);
std::optional<std::tuple<std::shared_ptr<DrmFramebuffer>, QRegion>> endRendering(DrmPlane::Transformations renderOrientation, const QRegion &damagedRegion, BufferTarget target = BufferTarget::Normal);
bool doesSurfaceFit(const QSize &size, const QMap<uint32_t, QVector<uint64_t>> &formats) const;
std::shared_ptr<GLTexture> texture() const;
void destroyResources();
EglGbmBackend *eglBackend() const;
std::shared_ptr<DrmFramebuffer> renderTestBuffer(const QSize &bufferSize, const QMap<uint32_t, QVector<uint64_t>> &formats, uint32_t additionalFlags = 0);
std::shared_ptr<DrmFramebuffer> renderTestBuffer(const QSize &bufferSize, const QMap<uint32_t, QVector<uint64_t>> &formats, BufferTarget target = BufferTarget::Normal);
private:
bool checkGbmSurface(const QSize &size, const QMap<uint32_t, QVector<uint64_t>> &formats, uint32_t flags);
bool createGbmSurface(const QSize &size, uint32_t format, const QVector<uint64_t> &modifiers, uint32_t flags);
bool createGbmSurface(const QSize &size, const QMap<uint32_t, QVector<uint64_t>> &formats, uint32_t flags);
bool checkGbmSurface(const QSize &size, const QMap<uint32_t, QVector<uint64_t>> &formats, bool forceLinear);
bool createGbmSurface(const QSize &size, uint32_t format, const QVector<uint64_t> &modifiers, bool forceLinear);
bool createGbmSurface(const QSize &size, const QMap<uint32_t, QVector<uint64_t>> &formats, bool forceLinear);
bool doesGbmSurfaceFit(GbmSurface *surf, const QSize &size, const QMap<uint32_t, QVector<uint64_t>> &formats) const;
bool doesShadowBufferFit(ShadowBuffer *buffer, const QSize &size, DrmPlane::Transformations renderOrientation, DrmPlane::Transformations bufferOrientation) const;