backends/drm: fail atomic tests gracefully when buffer allocations fail

This should fix the crash. However, it's still unclear to me why allocations
fail in the first place

CCBUG: 452572
This commit is contained in:
Xaver Hugl 2022-04-21 17:11:24 +02:00
parent 2b7fa206e8
commit 941bae2810
11 changed files with 61 additions and 60 deletions

View file

@ -36,12 +36,7 @@ class DrmPipelineLayer : public DrmOutputLayer
public:
DrmPipelineLayer(DrmPipeline *pipeline);
/**
* @returns a buffer for atomic test commits
* If no fitting buffer is available, a new current buffer is created
*/
virtual QSharedPointer<DrmBuffer> testBuffer() = 0;
virtual bool checkTestBuffer() = 0;
virtual QSharedPointer<DrmBuffer> currentBuffer() const = 0;
virtual bool hasDirectScanoutBuffer() const;

View file

@ -27,7 +27,7 @@ DrmLeaseEglGbmLayer::DrmLeaseEglGbmLayer(EglGbmBackend *backend, DrmPipeline *pi
});
}
QSharedPointer<DrmBuffer> DrmLeaseEglGbmLayer::testBuffer()
bool DrmLeaseEglGbmLayer::checkTestBuffer()
{
const auto mods = m_pipeline->formats().value(DRM_FORMAT_XRGB8888);
const auto size = m_pipeline->bufferSize();
@ -49,7 +49,7 @@ QSharedPointer<DrmBuffer> DrmLeaseEglGbmLayer::testBuffer()
qCWarning(KWIN_DRM) << "Failed to create gbm_bo for lease output";
}
}
return m_buffer;
return m_buffer && m_buffer->bufferId() != 0;
}
QSharedPointer<DrmBuffer> DrmLeaseEglGbmLayer::currentBuffer() const

View file

@ -24,7 +24,7 @@ public:
OutputLayerBeginFrameInfo beginFrame() override;
void endFrame(const QRegion &damagedRegion, const QRegion &renderedRegion) override;
QSharedPointer<DrmBuffer> testBuffer() override;
bool checkTestBuffer() override;
QSharedPointer<DrmBuffer> currentBuffer() const override;
private:

View file

@ -113,7 +113,7 @@ bool DrmPipeline::commitPipelinesAtomic(const QVector<DrmPipeline *> &pipelines,
return false;
};
for (const auto &pipeline : pipelines) {
if (!pipeline->pending.layer->testBuffer()) {
if (!pipeline->pending.layer->checkTestBuffer()) {
qCWarning(KWIN_DRM) << "Checking test buffer failed for" << mode;
return failed();
}

View file

@ -38,7 +38,7 @@ bool DrmPipeline::presentLegacy()
bool DrmPipeline::legacyModeset()
{
uint32_t connId = m_connector->id();
if (!pending.layer->testBuffer() || drmModeSetCrtc(gpu()->fd(), pending.crtc->id(), pending.layer->currentBuffer()->bufferId(), 0, 0, &connId, 1, pending.mode->nativeMode()) != 0) {
if (!pending.layer->checkTestBuffer() || drmModeSetCrtc(gpu()->fd(), pending.crtc->id(), pending.layer->currentBuffer()->bufferId(), 0, 0, &connId, 1, pending.mode->nativeMode()) != 0) {
qCWarning(KWIN_DRM) << "Modeset failed!" << strerror(errno);
pending = m_next;
return false;

View file

@ -52,12 +52,12 @@ void DrmQPainterLayer::endFrame(const QRegion &renderedRegion, const QRegion &da
m_swapchain->releaseBuffer(m_swapchain->currentBuffer(), damagedRegion);
}
QSharedPointer<DrmBuffer> DrmQPainterLayer::testBuffer()
bool DrmQPainterLayer::checkTestBuffer()
{
if (!doesSwapchainFit()) {
m_swapchain = QSharedPointer<DumbSwapchain>::create(m_pipeline->gpu(), m_pipeline->bufferSize(), DRM_FORMAT_XRGB8888);
}
return m_swapchain->currentBuffer();
return !m_swapchain->isEmpty();
}
bool DrmQPainterLayer::doesSwapchainFit() const
@ -110,13 +110,13 @@ DrmLeaseQPainterLayer::DrmLeaseQPainterLayer(DrmQPainterBackend *backend, DrmPip
});
}
QSharedPointer<DrmBuffer> DrmLeaseQPainterLayer::testBuffer()
bool DrmLeaseQPainterLayer::checkTestBuffer()
{
const auto size = m_pipeline->bufferSize();
if (!m_buffer || m_buffer->size() != size) {
m_buffer = QSharedPointer<DrmDumbBuffer>::create(m_pipeline->gpu(), size, DRM_FORMAT_XRGB8888);
}
return m_buffer;
return m_buffer->bufferId() != 0;
}
QSharedPointer<DrmBuffer> DrmLeaseQPainterLayer::currentBuffer() const

View file

@ -27,7 +27,7 @@ public:
OutputLayerBeginFrameInfo beginFrame() override;
void endFrame(const QRegion &damagedRegion, const QRegion &renderedRegion) override;
QSharedPointer<DrmBuffer> testBuffer() override;
bool checkTestBuffer() override;
QSharedPointer<DrmBuffer> currentBuffer() const override;
QRegion currentDamage() const override;
@ -62,7 +62,7 @@ public:
OutputLayerBeginFrameInfo beginFrame() override;
void endFrame(const QRegion &damagedRegion, const QRegion &renderedRegion) override;
QSharedPointer<DrmBuffer> testBuffer() override;
bool checkTestBuffer() override;
QSharedPointer<DrmBuffer> currentBuffer() const override;
private:

View file

@ -34,17 +34,6 @@ EglGbmLayer::EglGbmLayer(EglGbmBackend *eglBackend, DrmPipeline *pipeline)
, m_surface(pipeline->gpu(), eglBackend)
, m_dmabufFeedback(pipeline->gpu(), eglBackend)
{
connect(eglBackend, &EglGbmBackend::aboutToBeDestroyed, this, &EglGbmLayer::destroyResources);
}
EglGbmLayer::~EglGbmLayer()
{
destroyResources();
}
void EglGbmLayer::destroyResources()
{
m_surface.destroyResources();
}
OutputLayerBeginFrameInfo EglGbmLayer::beginFrame()
@ -74,21 +63,17 @@ QRegion EglGbmLayer::currentDamage() const
return m_currentDamage;
}
QSharedPointer<DrmBuffer> EglGbmLayer::testBuffer()
bool EglGbmLayer::checkTestBuffer()
{
if (!m_surface.doesSurfaceFit(m_pipeline->bufferSize(), m_pipeline->formats())) {
renderTestBuffer();
const auto buffer = m_surface.renderTestBuffer(m_pipeline->bufferSize(), m_pipeline->formats());
if (!buffer) {
return false;
} else {
m_currentBuffer = buffer;
}
}
return m_currentBuffer;
}
bool EglGbmLayer::renderTestBuffer()
{
const auto oldBuffer = m_currentBuffer;
beginFrame();
glClear(GL_COLOR_BUFFER_BIT);
endFrame(QRegion(), infiniteRegion());
return m_currentBuffer != oldBuffer;
return true;
}
QSharedPointer<GLTexture> EglGbmLayer::texture() const

View file

@ -35,22 +35,18 @@ class EglGbmLayer : public DrmPipelineLayer
{
public:
EglGbmLayer(EglGbmBackend *eglBackend, DrmPipeline *pipeline);
~EglGbmLayer();
OutputLayerBeginFrameInfo beginFrame() override;
void aboutToStartPainting(const QRegion &damagedRegion) override;
void endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) override;
bool scanout(SurfaceItem *surfaceItem) override;
QSharedPointer<DrmBuffer> testBuffer() override;
bool checkTestBuffer() override;
QSharedPointer<DrmBuffer> currentBuffer() const override;
bool hasDirectScanoutBuffer() const override;
QRegion currentDamage() const override;
QSharedPointer<GLTexture> texture() const override;
private:
bool renderTestBuffer();
void destroyResources();
QSharedPointer<DrmGbmBuffer> m_scanoutBuffer;
QSharedPointer<DrmBuffer> m_currentBuffer;
QRegion m_currentDamage;

View file

@ -54,21 +54,8 @@ void EglGbmLayerSurface::destroyResources()
OutputLayerBeginFrameInfo EglGbmLayerSurface::startRendering(const QSize &bufferSize, DrmPlane::Transformations renderOrientation, DrmPlane::Transformations bufferOrientation, const QMap<uint32_t, QVector<uint64_t>> &formats)
{
// gbm surface
if (doesGbmSurfaceFit(m_gbmSurface.data(), bufferSize, formats)) {
m_oldGbmSurface.reset();
} else {
if (doesGbmSurfaceFit(m_oldGbmSurface.data(), bufferSize, formats)) {
m_gbmSurface = m_oldGbmSurface;
} else {
if (!createGbmSurface(bufferSize, formats)) {
return {};
}
// dmabuf might work with the new surface
m_importMode = MultiGpuImportMode::Dmabuf;
m_importSwapchain.reset();
m_oldImportSwapchain.reset();
}
if (!checkGbmSurface(bufferSize, formats)) {
return {};
}
if (!m_gbmSurface->makeContextCurrent()) {
return {};
@ -147,6 +134,26 @@ std::optional<std::tuple<QSharedPointer<DrmBuffer>, QRegion>> EglGbmLayerSurface
}
}
bool EglGbmLayerSurface::checkGbmSurface(const QSize &bufferSize, const QMap<uint32_t, QVector<uint64_t>> &formats)
{
if (doesGbmSurfaceFit(m_gbmSurface.data(), bufferSize, formats)) {
m_oldGbmSurface.reset();
} else {
if (doesGbmSurfaceFit(m_oldGbmSurface.data(), bufferSize, formats)) {
m_gbmSurface = m_oldGbmSurface;
} else {
if (!createGbmSurface(bufferSize, formats)) {
return false;
}
// dmabuf might work with the new surface
m_importMode = MultiGpuImportMode::Dmabuf;
m_importSwapchain.reset();
m_oldImportSwapchain.reset();
}
}
return m_gbmSurface != nullptr;
}
bool EglGbmLayerSurface::createGbmSurface(const QSize &size, uint32_t format, const QVector<uint64_t> &modifiers)
{
static bool modifiersEnvSet = false;
@ -374,4 +381,20 @@ QSharedPointer<GLTexture> EglGbmLayerSurface::texture() const
}
return gbmBuffer->createTexture(m_eglBackend->eglDisplay());
}
QSharedPointer<DrmBuffer> EglGbmLayerSurface::renderTestBuffer(const QSize &bufferSize, const QMap<uint32_t, QVector<uint64_t>> &formats)
{
if (!checkGbmSurface(bufferSize, formats) || !m_gbmSurface->makeContextCurrent()) {
return nullptr;
}
glClear(GL_COLOR_BUFFER_BIT);
if (m_gpu == m_eglBackend->gpu()) {
return m_gbmSurface->swapBuffersForDrm(infiniteRegion());
} else {
if (m_gbmSurface->swapBuffers(infiniteRegion())) {
return importBuffer();
}
}
return nullptr;
}
}

View file

@ -49,8 +49,10 @@ public:
QSharedPointer<GLTexture> texture() const;
void destroyResources();
EglGbmBackend *eglBackend() const;
QSharedPointer<DrmBuffer> renderTestBuffer(const QSize &bufferSize, const QMap<uint32_t, QVector<uint64_t>> &formats);
private:
bool checkGbmSurface(const QSize &size, const QMap<uint32_t, QVector<uint64_t>> &formats);
bool createGbmSurface(const QSize &size, uint32_t format, const QVector<uint64_t> &modifiers);
bool createGbmSurface(const QSize &size, const QMap<uint32_t, QVector<uint64_t>> &formats);
bool doesGbmSurfaceFit(GbmSurface *surf, const QSize &size, const QMap<uint32_t, QVector<uint64_t>> &formats) const;