Summary: The gbm_surface is owned by the EglGbmBackend, but it's not the only one using it. The DrmSurfaceBuffer is also using it and needs it to destroy the gbm_bo. Now this can become a problem in the following situation: * a page flip is still pending * the EglGbmBackend destroys the gbm_surface -> when the page flip happens the DrmSurfaceBuffer will try to destroy the gbm_bo and crash as the gbm_surface is no longer valid. This situation can happen when switching screens or when switching compositing backend (OpenGL 2 -> OpenGL 3). To address this problem a class GbmSurface is added which wrapps the gbm_surface pointer. The EglGbmBackend creates and holds a shared pointer to the GbmSurface and passes that one to the DrmSurfaceBuffer. So when cleaning up the gbm_surface only the shared pointer is reset and in case the DrmSurfaceBuffer still needs it, it can access it without problems. BUG: 385372 FIXED-IN: 5.11.0 Test Plan: Not yet Reviewers: #kwin, #plasma, subdiff Subscribers: plasma-devel, kwin Tags: #kwin Differential Revision: https://phabricator.kde.org/D8152remotes/origin/Plasma/5.11
parent
31b5b7f9f9
commit
47343fb8f7
11 changed files with 261 additions and 19 deletions
@ -0,0 +1,119 @@ |
||||
/********************************************************************
|
||||
KWin - the KDE window manager |
||||
This file is part of the KDE project. |
||||
|
||||
Copyright (C) 2017 Martin Flöser <mgraesslin@kde.org> |
||||
|
||||
This program is free software; you can redistribute it and/or modify |
||||
it under the terms of the GNU General Public License as published by |
||||
the Free Software Foundation; either version 2 of the License, or |
||||
(at your option) any later version. |
||||
|
||||
This program is distributed in the hope that it will be useful, |
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
GNU General Public License for more details. |
||||
|
||||
You should have received a copy of the GNU General Public License |
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*********************************************************************/ |
||||
#include "../plugins/platforms/drm/gbm_surface.h" |
||||
#include <QtTest/QtTest> |
||||
|
||||
#include <gbm.h> |
||||
|
||||
// mocking
|
||||
|
||||
struct gbm_device { |
||||
bool surfaceShouldFail = false; |
||||
}; |
||||
|
||||
struct gbm_surface { |
||||
uint32_t width; |
||||
uint32_t height; |
||||
uint32_t format; |
||||
uint32_t flags; |
||||
}; |
||||
|
||||
struct gbm_bo { |
||||
}; |
||||
|
||||
struct gbm_surface *gbm_surface_create(struct gbm_device *gbm, uint32_t width, uint32_t height, uint32_t format, uint32_t flags) |
||||
{ |
||||
if (gbm && gbm->surfaceShouldFail) { |
||||
return nullptr; |
||||
} |
||||
auto ret = new gbm_surface{width, height, format, flags}; |
||||
return ret; |
||||
} |
||||
|
||||
void gbm_surface_destroy(struct gbm_surface *surface) |
||||
{ |
||||
delete surface; |
||||
} |
||||
|
||||
struct gbm_bo *gbm_surface_lock_front_buffer(struct gbm_surface *surface) |
||||
{ |
||||
Q_UNUSED(surface) |
||||
return new gbm_bo; |
||||
} |
||||
|
||||
void gbm_surface_release_buffer(struct gbm_surface *surface, struct gbm_bo *bo) |
||||
{ |
||||
Q_UNUSED(surface) |
||||
delete bo; |
||||
} |
||||
|
||||
using KWin::GbmSurface; |
||||
|
||||
class GbmSurfaceTest : public QObject |
||||
{ |
||||
Q_OBJECT |
||||
private Q_SLOTS: |
||||
void testCreate(); |
||||
void testCreateFailure(); |
||||
void testBo(); |
||||
}; |
||||
|
||||
void GbmSurfaceTest::testCreate() |
||||
{ |
||||
GbmSurface surface(nullptr, 2, 3, 4, 5); |
||||
gbm_surface *native = surface; |
||||
QVERIFY(surface); |
||||
QCOMPARE(native->width, 2u); |
||||
QCOMPARE(native->height, 3u); |
||||
QCOMPARE(native->format, 4u); |
||||
QCOMPARE(native->flags, 5u); |
||||
} |
||||
|
||||
void GbmSurfaceTest::testCreateFailure() |
||||
{ |
||||
gbm_device dev{true}; |
||||
GbmSurface surface(&dev, 2, 3, 4, 5); |
||||
QVERIFY(!surface); |
||||
gbm_surface *native = surface; |
||||
QVERIFY(!native); |
||||
} |
||||
|
||||
void GbmSurfaceTest::testBo() |
||||
{ |
||||
GbmSurface surface(nullptr, 2, 3, 4, 5); |
||||
// release buffer on nullptr should not be a problem
|
||||
surface.releaseBuffer(nullptr); |
||||
// now an actual buffer
|
||||
auto bo = surface.lockFrontBuffer(); |
||||
surface.releaseBuffer(bo); |
||||
|
||||
// and a surface which fails
|
||||
gbm_device dev{true}; |
||||
GbmSurface surface2(&dev, 2, 3, 4, 5); |
||||
QVERIFY(!surface2.lockFrontBuffer()); |
||||
auto bo2 = surface.lockFrontBuffer(); |
||||
// this won't do anything
|
||||
surface2.releaseBuffer(bo2); |
||||
// so we need to clean up properly
|
||||
surface.releaseBuffer(bo2); |
||||
} |
||||
|
||||
QTEST_GUILESS_MAIN(GbmSurfaceTest) |
||||
#include "test_gbm_surface.moc" |
||||
@ -0,0 +1,55 @@ |
||||
/********************************************************************
|
||||
KWin - the KDE window manager |
||||
This file is part of the KDE project. |
||||
|
||||
Copyright (C) 2017 Martin Flöser <mgraesslin@kde.org> |
||||
|
||||
This program is free software; you can redistribute it and/or modify |
||||
it under the terms of the GNU General Public License as published by |
||||
the Free Software Foundation; either version 2 of the License, or |
||||
(at your option) any later version. |
||||
|
||||
This program is distributed in the hope that it will be useful, |
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
GNU General Public License for more details. |
||||
|
||||
You should have received a copy of the GNU General Public License |
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*********************************************************************/ |
||||
#include "gbm_surface.h" |
||||
|
||||
#include <gbm.h> |
||||
|
||||
namespace KWin |
||||
{ |
||||
|
||||
GbmSurface::GbmSurface(gbm_device *gbm, uint32_t width, uint32_t height, uint32_t format, uint32_t flags) |
||||
: m_surface(gbm_surface_create(gbm, width, height, format, flags)) |
||||
{ |
||||
} |
||||
|
||||
GbmSurface::~GbmSurface() |
||||
{ |
||||
if (m_surface) { |
||||
gbm_surface_destroy(m_surface); |
||||
} |
||||
} |
||||
|
||||
gbm_bo *GbmSurface::lockFrontBuffer() |
||||
{ |
||||
if (!m_surface) { |
||||
return nullptr; |
||||
} |
||||
return gbm_surface_lock_front_buffer(m_surface); |
||||
} |
||||
|
||||
void GbmSurface::releaseBuffer(gbm_bo *bo) |
||||
{ |
||||
if (!bo || !m_surface) { |
||||
return; |
||||
} |
||||
gbm_surface_release_buffer(m_surface, bo); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,55 @@ |
||||
/********************************************************************
|
||||
KWin - the KDE window manager |
||||
This file is part of the KDE project. |
||||
|
||||
Copyright (C) 2017 Martin Flöser <mgraesslin@kde.org> |
||||
|
||||
This program is free software; you can redistribute it and/or modify |
||||
it under the terms of the GNU General Public License as published by |
||||
the Free Software Foundation; either version 2 of the License, or |
||||
(at your option) any later version. |
||||
|
||||
This program is distributed in the hope that it will be useful, |
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
GNU General Public License for more details. |
||||
|
||||
You should have received a copy of the GNU General Public License |
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*********************************************************************/ |
||||
#ifndef KWIN_DRM_GBM_SURFACE_H |
||||
#define KWIN_DRM_GBM_SURFACE_H |
||||
|
||||
#include <stdint.h> |
||||
|
||||
struct gbm_bo; |
||||
struct gbm_device; |
||||
struct gbm_surface; |
||||
|
||||
namespace KWin |
||||
{ |
||||
|
||||
class GbmSurface |
||||
{ |
||||
public: |
||||
explicit GbmSurface(gbm_device *gbm, uint32_t width, uint32_t height, uint32_t format, uint32_t flags); |
||||
~GbmSurface(); |
||||
|
||||
gbm_bo *lockFrontBuffer(); |
||||
void releaseBuffer(gbm_bo *bo); |
||||
|
||||
operator bool() const { |
||||
return m_surface != nullptr; |
||||
} |
||||
|
||||
operator gbm_surface*() const { |
||||
return m_surface; |
||||
} |
||||
|
||||
private: |
||||
gbm_surface *m_surface; |
||||
}; |
||||
|
||||
} |
||||
|
||||
#endif |
||||
Loading…
Reference in new issue