Introduce DamageJournal helper
This commit is contained in:
parent
2fe102768a
commit
501298b0e0
9 changed files with 88 additions and 66 deletions
|
@ -35,30 +35,6 @@ void OpenGLBackend::setFailed(const QString &reason)
|
|||
m_failed = true;
|
||||
}
|
||||
|
||||
void OpenGLBackend::addToDamageHistory(const QRegion ®ion)
|
||||
{
|
||||
if (m_damageHistory.count() > 10)
|
||||
m_damageHistory.removeLast();
|
||||
|
||||
m_damageHistory.prepend(region);
|
||||
}
|
||||
|
||||
QRegion OpenGLBackend::accumulatedDamageHistory(int bufferAge) const
|
||||
{
|
||||
QRegion region;
|
||||
|
||||
// Note: An age of zero means the buffer contents are undefined
|
||||
if (bufferAge > 0 && bufferAge <= m_damageHistory.count()) {
|
||||
for (int i = 0; i < bufferAge - 1; i++)
|
||||
region |= m_damageHistory[i];
|
||||
} else {
|
||||
const QSize &s = screens()->size();
|
||||
region = QRegion(0, 0, s.width(), s.height());
|
||||
}
|
||||
|
||||
return region;
|
||||
}
|
||||
|
||||
OverlayWindow* OpenGLBackend::overlayWindow() const
|
||||
{
|
||||
return nullptr;
|
||||
|
|
|
@ -129,16 +129,6 @@ public:
|
|||
}
|
||||
virtual bool directScanoutAllowed(int screen) const;
|
||||
|
||||
/**
|
||||
* Returns the damage that has accumulated since a buffer of the given age was presented.
|
||||
*/
|
||||
QRegion accumulatedDamageHistory(int bufferAge) const;
|
||||
|
||||
/**
|
||||
* Saves the given region to damage history.
|
||||
*/
|
||||
void addToDamageHistory(const QRegion ®ion);
|
||||
|
||||
/**
|
||||
* The backend specific extensions (e.g. EGL/GLX extensions).
|
||||
*
|
||||
|
@ -244,10 +234,6 @@ private:
|
|||
* @brief Whether the initialization failed, of course default to @c false.
|
||||
*/
|
||||
bool m_failed;
|
||||
/**
|
||||
* @brief The damage history for the past 10 frames.
|
||||
*/
|
||||
QList<QRegion> m_damageHistory;
|
||||
QList<QByteArray> m_extensions;
|
||||
};
|
||||
|
||||
|
|
|
@ -528,20 +528,13 @@ QRegion EglGbmBackend::prepareRenderingForOutput(Output &output)
|
|||
}
|
||||
setViewport(output);
|
||||
|
||||
const QRect geometry = output.output->geometry();
|
||||
if (supportsBufferAge()) {
|
||||
QRegion region;
|
||||
|
||||
// Note: An age of zero means the buffer contents are undefined
|
||||
if (output.current.bufferAge > 0 && output.current.bufferAge <= output.current.damageHistory.count()) {
|
||||
for (int i = 0; i < output.current.bufferAge - 1; i++)
|
||||
region |= output.current.damageHistory[i];
|
||||
} else {
|
||||
region = output.output->geometry();
|
||||
}
|
||||
|
||||
return region;
|
||||
auto current = &output.current;
|
||||
return current->damageJournal.accumulate(current->bufferAge, geometry);
|
||||
}
|
||||
return output.output->geometry();
|
||||
|
||||
return geometry;
|
||||
}
|
||||
|
||||
QSharedPointer<DrmBuffer> EglGbmBackend::endFrameWithBuffer(int screenId, const QRegion &dirty)
|
||||
|
@ -581,10 +574,7 @@ void EglGbmBackend::updateBufferAge(Output &output, const QRegion &dirty)
|
|||
{
|
||||
if (supportsBufferAge()) {
|
||||
eglQuerySurface(eglDisplay(), output.current.gbmSurface->eglSurface(), EGL_BUFFER_AGE_EXT, &output.current.bufferAge);
|
||||
if (output.current.damageHistory.count() > 10) {
|
||||
output.current.damageHistory.removeLast();
|
||||
}
|
||||
output.current.damageHistory.prepend(dirty);
|
||||
output.current.damageJournal.add(dirty);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -665,7 +655,7 @@ bool EglGbmBackend::scanout(int screenId, SurfaceItem *surfaceItem)
|
|||
// ensure that a context is current like with normal presentation
|
||||
makeCurrent();
|
||||
if (output.output->present(bo, damage)) {
|
||||
output.current.damageHistory.clear();
|
||||
output.current.damageJournal.clear();
|
||||
if (output.surfaceInterface != surface) {
|
||||
auto path = surface->client()->executablePath();
|
||||
qCDebug(KWIN_DRM).nospace() << "Direct scanout starting on output " << output.output->name() << " for application \"" << path << "\"";
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#ifndef KWIN_EGL_GBM_BACKEND_H
|
||||
#define KWIN_EGL_GBM_BACKEND_H
|
||||
#include "abstract_egl_drm_backend.h"
|
||||
#include "utils.h"
|
||||
|
||||
#include <kwinglutils.h>
|
||||
|
||||
|
@ -87,10 +88,7 @@ private:
|
|||
QSharedPointer<ShadowBuffer> shadowBuffer;
|
||||
QSharedPointer<GbmSurface> gbmSurface;
|
||||
int bufferAge = 0;
|
||||
/**
|
||||
* @brief The damage history for the past 10 frames.
|
||||
*/
|
||||
QList<QRegion> damageHistory;
|
||||
DamageJournal damageJournal;
|
||||
|
||||
// for secondary GPU import
|
||||
ImportMode importMode = ImportMode::Dmabuf;
|
||||
|
|
|
@ -98,8 +98,9 @@ QRegion EglBackend::beginFrame(int screenId)
|
|||
glViewport(0, 0, size.width(), size.height());
|
||||
|
||||
QRegion repaint;
|
||||
if (supportsBufferAge())
|
||||
repaint = accumulatedDamageHistory(m_bufferAge);
|
||||
if (supportsBufferAge()) {
|
||||
repaint = m_damageJournal.accumulate(m_bufferAge, screens()->geometry());
|
||||
}
|
||||
|
||||
eglWaitNative(EGL_CORE_NATIVE_ENGINE);
|
||||
|
||||
|
@ -122,7 +123,7 @@ void EglBackend::endFrame(int screenId, const QRegion &renderedRegion, const QRe
|
|||
|
||||
// Save the damaged region to history
|
||||
if (supportsBufferAge()) {
|
||||
addToDamageHistory(damagedRegion);
|
||||
m_damageJournal.add(damagedRegion);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -40,6 +40,7 @@ private:
|
|||
|
||||
X11StandalonePlatform *m_backend;
|
||||
SoftwareVsyncMonitor *m_vsyncMonitor;
|
||||
DamageJournal m_damageJournal;
|
||||
int m_bufferAge = 0;
|
||||
};
|
||||
|
||||
|
|
|
@ -746,8 +746,9 @@ QRegion GlxBackend::beginFrame(int screenId)
|
|||
const QSize size = screens()->size();
|
||||
glViewport(0, 0, size.width(), size.height());
|
||||
|
||||
if (supportsBufferAge())
|
||||
repaint = accumulatedDamageHistory(m_bufferAge);
|
||||
if (supportsBufferAge()) {
|
||||
repaint = m_damageJournal.accumulate(m_bufferAge, screens()->geometry());
|
||||
}
|
||||
|
||||
glXWaitX();
|
||||
|
||||
|
@ -770,8 +771,9 @@ void GlxBackend::endFrame(int screenId, const QRegion &renderedRegion, const QRe
|
|||
overlayWindow()->show(); // since that pass may take long
|
||||
|
||||
// Save the damaged region to history
|
||||
if (supportsBufferAge())
|
||||
addToDamageHistory(damagedRegion);
|
||||
if (supportsBufferAge()) {
|
||||
m_damageJournal.add(damagedRegion);
|
||||
}
|
||||
}
|
||||
|
||||
void GlxBackend::vblank(std::chrono::nanoseconds timestamp)
|
||||
|
|
|
@ -106,6 +106,7 @@ private:
|
|||
QHash<xcb_visualid_t, FBConfigInfo *> m_fbconfigHash;
|
||||
QHash<xcb_visualid_t, int> m_visualDepthHash;
|
||||
std::unique_ptr<SwapEventFilter> m_swapEventFilter;
|
||||
DamageJournal m_damageJournal;
|
||||
int m_bufferAge;
|
||||
bool m_haveMESACopySubBuffer = false;
|
||||
bool m_haveMESASwapControl = false;
|
||||
|
|
67
src/utils.h
67
src/utils.h
|
@ -210,6 +210,73 @@ protected:
|
|||
#endif
|
||||
};
|
||||
|
||||
/**
|
||||
* The DamageJournal class is a helper that tracks last N damage regions.
|
||||
*/
|
||||
class KWIN_EXPORT DamageJournal
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Returns the maximum number of damage regions that can be stored in the journal.
|
||||
*/
|
||||
int capacity() const
|
||||
{
|
||||
return m_capacity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the maximum number of damage regions that can be stored in the journal
|
||||
* to @a capacity.
|
||||
*/
|
||||
void setCapacity(int capacity)
|
||||
{
|
||||
m_capacity = capacity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the specified @a region to the journal.
|
||||
*/
|
||||
void add(const QRegion ®ion)
|
||||
{
|
||||
while (m_log.size() >= m_capacity) {
|
||||
m_log.takeLast();
|
||||
}
|
||||
m_log.prepend(region);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the damage journal. Typically, one would want to clear the damage journal
|
||||
* if a buffer swap fails for some reason.
|
||||
*/
|
||||
void clear()
|
||||
{
|
||||
m_log.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Accumulates the damage regions in the log up to the specified @a bufferAge.
|
||||
*
|
||||
* If the specified buffer age value refers to a damage region older than the last
|
||||
* one in the journal, @a fallback will be returned.
|
||||
*/
|
||||
QRegion accumulate(int bufferAge, const QRegion &fallback = QRegion()) const
|
||||
{
|
||||
QRegion region;
|
||||
if (bufferAge > 0 && bufferAge <= m_log.size()) {
|
||||
for (int i = 0; i < bufferAge - 1; ++i) {
|
||||
region |= m_log[i];
|
||||
}
|
||||
} else {
|
||||
region = fallback;
|
||||
}
|
||||
return region;
|
||||
}
|
||||
|
||||
private:
|
||||
QList<QRegion> m_log;
|
||||
int m_capacity = 10;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
// Must be outside namespace
|
||||
|
|
Loading…
Reference in a new issue