platforms/drm: Make frame scheduling robust
If there is a pending frame, the RenderLoop will delay all schedule repaint requests to the next vblank event. This means that the render loop needs to be notified when a frame has been presented or failed. At the moment, the RenderLoop is notified only about successfully presented frames. If some frame fails, no repaints will be scheduled on that output. In order to make frame scheduling robust, the RenderLoop has to be notified if a frame has failed.icc-effect-5.26.4
parent
ad5f8c5c59
commit
ee3515680a
|
@ -14,6 +14,7 @@
|
|||
#include "gbm_surface.h"
|
||||
#include "logging.h"
|
||||
#include "options.h"
|
||||
#include "renderloop_p.h"
|
||||
#include "screens.h"
|
||||
#include "drm_gpu.h"
|
||||
// kwin libs
|
||||
|
@ -589,30 +590,39 @@ void EglGbmBackend::aboutToStartPainting(int screenId, const QRegion &damagedReg
|
|||
}
|
||||
}
|
||||
|
||||
void EglGbmBackend::presentOnOutput(Output &output, const QRegion &damagedRegion)
|
||||
bool EglGbmBackend::presentOnOutput(Output &output, const QRegion &damagedRegion)
|
||||
{
|
||||
if (isPrimary()) {
|
||||
if (supportsSwapBuffersWithDamage()) {
|
||||
QVector<EGLint> rects = regionToRects(output.damageHistory.constFirst(), output.output);
|
||||
eglSwapBuffersWithDamageEXT(eglDisplay(), output.eglSurface,
|
||||
rects.data(), rects.count()/4);
|
||||
if (!eglSwapBuffersWithDamageEXT(eglDisplay(), output.eglSurface,
|
||||
rects.data(), rects.count() / 4)) {
|
||||
qCCritical(KWIN_DRM, "eglSwapBuffersWithDamageEXT() failed: %x", eglGetError());
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
eglSwapBuffers(eglDisplay(), output.eglSurface);
|
||||
if (!eglSwapBuffers(eglDisplay(), output.eglSurface)) {
|
||||
qCCritical(KWIN_DRM, "eglSwapBuffers() failed: %x", eglGetError());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
output.buffer = new DrmSurfaceBuffer(m_gpu->fd(), output.gbmSurface);
|
||||
} else if (output.importedGbmBo == nullptr) {
|
||||
qCDebug(KWIN_DRM) << "imported gbm_bo does not exist!";
|
||||
return;
|
||||
return false;
|
||||
} else {
|
||||
output.buffer = new DrmSurfaceBuffer(m_gpu->fd(), output.importedGbmBo);
|
||||
}
|
||||
|
||||
Q_EMIT output.output->outputChange(damagedRegion);
|
||||
m_backend->present(output.buffer, output.output);
|
||||
if (!m_backend->present(output.buffer, output.output)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (supportsBufferAge()) {
|
||||
eglQuerySurface(eglDisplay(), output.eglSurface, EGL_BUFFER_AGE_EXT, &output.bufferAge);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
SceneOpenGLTexturePrivate *EglGbmBackend::createBackendTexture(SceneOpenGLTexture *texture)
|
||||
|
@ -664,10 +674,19 @@ QRegion EglGbmBackend::prepareRenderingForOutput(const Output &output) const
|
|||
void EglGbmBackend::endFrame(int screenId, const QRegion &renderedRegion,
|
||||
const QRegion &damagedRegion)
|
||||
{
|
||||
Q_UNUSED(renderedRegion)
|
||||
|
||||
Output &output = m_outputs[screenId];
|
||||
DrmOutput *drmOutput = output.output;
|
||||
|
||||
renderFramebufferToSurface(output);
|
||||
|
||||
presentOnOutput(output, damagedRegion);
|
||||
if (!presentOnOutput(output, damagedRegion)) {
|
||||
output.damageHistory.clear();
|
||||
RenderLoopPrivate *renderLoopPrivate = RenderLoopPrivate::get(drmOutput->renderLoop());
|
||||
renderLoopPrivate->notifyFrameFailed();
|
||||
return;
|
||||
}
|
||||
|
||||
if (supportsBufferAge()) {
|
||||
const QRegion dirty = damagedRegion.intersected(output.output->geometry());
|
||||
|
|
|
@ -95,7 +95,7 @@ private:
|
|||
void renderFramebufferToSurface(Output &output);
|
||||
QRegion prepareRenderingForOutput(const Output &output) const;
|
||||
|
||||
void presentOnOutput(Output &output, const QRegion &damagedRegion);
|
||||
bool presentOnOutput(Output &output, const QRegion &damagedRegion);
|
||||
|
||||
void cleanupOutput(Output &output);
|
||||
void cleanupFramebuffer(Output &output);
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include "logging.h"
|
||||
#include "logind.h"
|
||||
#include "options.h"
|
||||
#include "renderloop_p.h"
|
||||
#include "scene.h"
|
||||
#include "screens.h"
|
||||
#include "wayland_server.h"
|
||||
|
@ -438,20 +439,14 @@ bool EglStreamBackend::initBufferConfigs()
|
|||
return true;
|
||||
}
|
||||
|
||||
void EglStreamBackend::presentOnOutput(EglStreamBackend::Output &o)
|
||||
bool EglStreamBackend::presentOnOutput(EglStreamBackend::Output &o)
|
||||
{
|
||||
eglSwapBuffers(eglDisplay(), o.eglSurface);
|
||||
if (!m_backend->present(o.buffer, o.output)) {
|
||||
return;
|
||||
if (!eglSwapBuffers(eglDisplay(), o.eglSurface)) {
|
||||
qCCritical(KWIN_DRM, "eglSwapBuffers() failed: %x", eglGetError());
|
||||
return false;
|
||||
}
|
||||
|
||||
EGLAttrib acquireAttribs[] = {
|
||||
EGL_DRM_FLIP_EVENT_DATA_NV, (EGLAttrib)o.output,
|
||||
EGL_NONE,
|
||||
};
|
||||
if (!pEglStreamConsumerAcquireAttribNV(eglDisplay(), o.eglStream, acquireAttribs)) {
|
||||
qCWarning(KWIN_DRM) << "Failed to acquire output EGL stream frame";
|
||||
}
|
||||
return m_backend->present(o.buffer, o.output);
|
||||
}
|
||||
|
||||
SceneOpenGLTexturePrivate *EglStreamBackend::createBackendTexture(SceneOpenGLTexture *texture)
|
||||
|
@ -470,8 +465,23 @@ void EglStreamBackend::endFrame(int screenId, const QRegion &renderedRegion, con
|
|||
{
|
||||
Q_UNUSED(renderedRegion);
|
||||
Q_UNUSED(damagedRegion);
|
||||
Output &o = m_outputs[screenId];
|
||||
presentOnOutput(o);
|
||||
|
||||
Output &renderOutput = m_outputs[screenId];
|
||||
DrmOutput *drmOutput = renderOutput.output;
|
||||
|
||||
if (!presentOnOutput(renderOutput)) {
|
||||
RenderLoopPrivate *renderLoopPrivate = RenderLoopPrivate::get(drmOutput->renderLoop());
|
||||
renderLoopPrivate->notifyFrameFailed();
|
||||
return;
|
||||
}
|
||||
|
||||
EGLAttrib acquireAttribs[] = {
|
||||
EGL_DRM_FLIP_EVENT_DATA_NV, (EGLAttrib)drmOutput,
|
||||
EGL_NONE,
|
||||
};
|
||||
if (!pEglStreamConsumerAcquireAttribNV(eglDisplay(), renderOutput.eglStream, acquireAttribs)) {
|
||||
qCWarning(KWIN_DRM) << "Failed to acquire output EGL stream frame";
|
||||
}
|
||||
}
|
||||
|
||||
/************************************************
|
||||
|
|
|
@ -64,7 +64,7 @@ private:
|
|||
};
|
||||
bool resetOutput(Output &output, DrmOutput *drmOutput);
|
||||
bool makeContextCurrent(const Output &output);
|
||||
void presentOnOutput(Output &output);
|
||||
bool presentOnOutput(Output &output);
|
||||
void cleanupOutput(const Output &output);
|
||||
|
||||
QVector<Output> m_outputs;
|
||||
|
|
|
@ -9,8 +9,8 @@
|
|||
#include "scene_qpainter_drm_backend.h"
|
||||
#include "drm_backend.h"
|
||||
#include "drm_output.h"
|
||||
#include "logind.h"
|
||||
#include "drm_gpu.h"
|
||||
#include "renderloop_p.h"
|
||||
|
||||
namespace KWin
|
||||
{
|
||||
|
@ -110,12 +110,14 @@ void DrmQPainterBackend::endFrame(int screenId, int mask, const QRegion &damage)
|
|||
{
|
||||
Q_UNUSED(mask)
|
||||
Q_UNUSED(damage)
|
||||
if (!LogindIntegration::self()->isActiveSession()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const Output &rendererOutput = m_outputs[screenId];
|
||||
m_backend->present(rendererOutput.buffer[rendererOutput.index], rendererOutput.output);
|
||||
DrmOutput *drmOutput = rendererOutput.output;
|
||||
|
||||
if (!m_backend->present(rendererOutput.buffer[rendererOutput.index], drmOutput)) {
|
||||
RenderLoopPrivate *renderLoopPrivate = RenderLoopPrivate::get(drmOutput->renderLoop());
|
||||
renderLoopPrivate->notifyFrameFailed();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -101,6 +101,16 @@ void RenderLoopPrivate::maybeScheduleRepaint()
|
|||
}
|
||||
}
|
||||
|
||||
void RenderLoopPrivate::notifyFrameFailed()
|
||||
{
|
||||
Q_ASSERT(pendingFrameCount > 0);
|
||||
pendingFrameCount--;
|
||||
|
||||
if (!inhibitCount) {
|
||||
maybeScheduleRepaint();
|
||||
}
|
||||
}
|
||||
|
||||
void RenderLoopPrivate::notifyFrameCompleted(std::chrono::nanoseconds timestamp)
|
||||
{
|
||||
Q_ASSERT(pendingFrameCount > 0);
|
||||
|
|
|
@ -27,6 +27,7 @@ public:
|
|||
void scheduleRepaint();
|
||||
void maybeScheduleRepaint();
|
||||
|
||||
void notifyFrameFailed();
|
||||
void notifyFrameCompleted(std::chrono::nanoseconds timestamp);
|
||||
|
||||
RenderLoop *q;
|
||||
|
|
Loading…
Reference in New Issue