Commit 8e998a7c authored by Xaver Hugl's avatar Xaver Hugl
Browse files

renderbackend: split presentation out of endFrame

With these two actions being separate, RenderLoop can record the time spent
in endFrame (for example for multi-gpu transfers) without risking also recording
blocking swapbuffer calls, and endFrame can later be moved to output layer
parent 9dc5e531
......@@ -243,14 +243,17 @@ void EglGbmBackend::endFrame(AbstractOutput *output, const QRegion &renderedRegi
const auto drmOutput = static_cast<DrmAbstractOutput *>(output);
drmOutput->outputLayer()->endRendering(damagedRegion);
drmOutput->present();
}
void EglGbmBackend::present(AbstractOutput *output)
{
static_cast<DrmAbstractOutput *>(output)->present();
}
bool EglGbmBackend::scanout(AbstractOutput *output, SurfaceItem *surfaceItem)
{
const auto drmOutput = static_cast<DrmAbstractOutput *>(output);
if (drmOutput->outputLayer()->scanout(surfaceItem)) {
drmOutput->present();
return true;
} else {
return false;
......
......@@ -66,6 +66,8 @@ public:
QRegion beginFrame(AbstractOutput *output) override;
void endFrame(AbstractOutput *output, const QRegion &renderedRegion, const QRegion &damagedRegion) override;
void present(AbstractOutput *output) override;
void init() override;
bool scanout(AbstractOutput *output, SurfaceItem *surfaceItem) override;
bool prefer10bpc() const override;
......
......@@ -50,6 +50,10 @@ void DrmQPainterBackend::endFrame(AbstractOutput *output, const QRegion &rendere
Q_UNUSED(renderedRegion)
const auto drmOutput = static_cast<DrmAbstractOutput *>(output);
drmOutput->outputLayer()->endRendering(damage);
}
void DrmQPainterBackend::present(AbstractOutput *output)
{
static_cast<DrmAbstractOutput *>(output)->present();
}
......
......@@ -33,6 +33,8 @@ public:
QImage *bufferForScreen(AbstractOutput *output) override;
QRegion beginFrame(AbstractOutput *output) override;
void endFrame(AbstractOutput *output, const QRegion &renderedRegion, const QRegion &damagedRegion) override;
void present(AbstractOutput *output) override;
QSharedPointer<DrmPipelineLayer> createDrmPipelineLayer(DrmPipeline *pipeline) override;
QSharedPointer<DrmOutputLayer> createLayer(DrmVirtualOutput *output) override;
......
......@@ -199,8 +199,13 @@ static void convertFromGLImage(QImage &img, int w, int h)
void EglGbmBackend::endFrame(AbstractOutput *output, const QRegion &renderedRegion, const QRegion &damagedRegion)
{
Q_UNUSED(output)
Q_UNUSED(renderedRegion)
Q_UNUSED(damagedRegion)
}
void EglGbmBackend::present(AbstractOutput *output)
{
glFlush();
static_cast<VirtualOutput *>(output)->vsyncMonitor()->arm();
......
......@@ -30,6 +30,7 @@ public:
SurfaceTexture *createSurfaceTextureWayland(SurfacePixmapWayland *pixmap) override;
QRegion beginFrame(AbstractOutput *output) override;
void endFrame(AbstractOutput *output, const QRegion &renderedRegion, const QRegion &damagedRegion) override;
void present(AbstractOutput *output) override;
void init() override;
private:
......
......@@ -50,14 +50,17 @@ void VirtualQPainterBackend::createOutputs()
void VirtualQPainterBackend::endFrame(AbstractOutput *output, const QRegion &renderedRegion, const QRegion &damagedRegion)
{
Q_UNUSED(output)
Q_UNUSED(renderedRegion)
Q_UNUSED(damagedRegion)
}
void VirtualQPainterBackend::present(AbstractOutput *output)
{
static_cast<VirtualOutput *>(output)->vsyncMonitor()->arm();
if (m_backend->saveFrames()) {
m_backBuffers[output].save(QStringLiteral("%1/%s-%3.png").arg(m_backend->screenshotDirPath(), output->name(), QString::number(m_frameCounter++)));
}
}
}
......@@ -30,6 +30,7 @@ public:
QImage *bufferForScreen(AbstractOutput *output) override;
QRegion beginFrame(AbstractOutput *output) override;
void endFrame(AbstractOutput *output, const QRegion &renderedRegion, const QRegion &damagedRegion) override;
void present(AbstractOutput *output) override;
private:
void createOutputs();
......
......@@ -396,15 +396,18 @@ void EglWaylandBackend::endFrame(AbstractOutput *output, const QRegion &rendered
Q_ASSERT(m_outputs.contains(output));
Q_UNUSED(renderedRegion);
m_lastDamagedRegion = damagedRegion;
GLRenderTarget::popRenderTarget();
}
void EglWaylandBackend::present(AbstractOutput *output)
{
const auto &eglOutput = m_outputs[output];
presentOnSurface(eglOutput, damagedRegion);
presentOnSurface(eglOutput, m_lastDamagedRegion);
if (supportsBufferAge()) {
eglOutput->m_damageJournal.add(damagedRegion);
eglOutput->m_damageJournal.add(m_lastDamagedRegion);
}
}
}
}
......@@ -77,6 +77,7 @@ public:
QRegion beginFrame(AbstractOutput *output) override;
void endFrame(AbstractOutput *output, const QRegion &renderedRegion, const QRegion &damagedRegion) override;
void present(AbstractOutput *output) override;
void init() override;
bool havePlatformBase() const
......@@ -102,6 +103,7 @@ private:
WaylandBackend *m_backend;
QMap<AbstractOutput *, EglWaylandOutput *> m_outputs;
QRegion m_lastDamagedRegion;
bool m_havePlatformBase;
friend class EglWaylandTexture;
};
......
......@@ -166,11 +166,10 @@ void WaylandQPainterBackend::createOutput(AbstractOutput *waylandOutput)
void WaylandQPainterBackend::endFrame(AbstractOutput *output, const QRegion &renderedRegion, const QRegion &damagedRegion)
{
Q_UNUSED(output)
Q_UNUSED(renderedRegion)
WaylandQPainterOutput *rendererOutput = m_outputs[output];
Q_ASSERT(rendererOutput);
rendererOutput->present(damagedRegion);
m_lastDamagedRegion = damagedRegion;
}
QImage *WaylandQPainterBackend::bufferForScreen(AbstractOutput *output)
......@@ -187,5 +186,9 @@ QRegion WaylandQPainterBackend::beginFrame(AbstractOutput *output)
return rendererOutput->accumulateDamage(slot->age);
}
void WaylandQPainterBackend::present(AbstractOutput *output)
{
m_outputs[output]->present(m_lastDamagedRegion);
}
}
}
......@@ -84,14 +84,16 @@ public:
QImage *bufferForScreen(AbstractOutput *output) override;
void endFrame(AbstractOutput *output, const QRegion &renderedRegion, const QRegion &damagedRegion) override;
QRegion beginFrame(AbstractOutput *output) override;
void endFrame(AbstractOutput *output, const QRegion &renderedRegion, const QRegion &damagedRegion) override;
void present(AbstractOutput *output) override;
private:
void createOutput(AbstractOutput *waylandOutput);
void frameRendered();
WaylandBackend *m_backend;
QRegion m_lastDamagedRegion;
QMap<AbstractOutput *, WaylandQPainterOutput *> m_outputs;
};
......
......@@ -126,16 +126,26 @@ void EglBackend::endFrame(AbstractOutput *output, const QRegion &renderedRegion,
{
Q_UNUSED(output)
// Save the damaged region to history
if (supportsBufferAge()) {
m_damageJournal.add(damagedRegion);
}
m_lastRenderedRegion = renderedRegion;
}
void EglBackend::present(AbstractOutput *output)
{
Q_UNUSED(output)
// Start the software vsync monitor. There is no any reliable way to determine when
// eglSwapBuffers() or eglSwapBuffersWithDamageEXT() completes.
m_vsyncMonitor->arm();
QRegion effectiveRenderedRegion = renderedRegion;
QRegion effectiveRenderedRegion = m_lastRenderedRegion;
if (!GLPlatform::instance()->isGLES()) {
const QRegion displayRegion(screens()->geometry());
if (!supportsBufferAge() && options->glPreferBufferSwap() == Options::CopyFrontBuffer && renderedRegion != displayRegion) {
if (!supportsBufferAge() && options->glPreferBufferSwap() == Options::CopyFrontBuffer && m_lastRenderedRegion != displayRegion) {
glReadBuffer(GL_FRONT);
copyPixels(displayRegion - renderedRegion);
copyPixels(displayRegion - m_lastRenderedRegion);
glReadBuffer(GL_BACK);
effectiveRenderedRegion = displayRegion;
}
......@@ -149,11 +159,6 @@ void EglBackend::endFrame(AbstractOutput *output, const QRegion &renderedRegion,
if (overlayWindow() && overlayWindow()->window()) { // show the window only after the first pass,
overlayWindow()->show(); // since that pass may take long
}
// Save the damaged region to history
if (supportsBufferAge()) {
m_damageJournal.add(damagedRegion);
}
}
void EglBackend::presentSurface(EGLSurface surface, const QRegion &damage, const QRect &screenGeometry)
......
......@@ -33,6 +33,7 @@ public:
SurfaceTexture *createSurfaceTextureX11(SurfacePixmapX11 *texture) override;
QRegion beginFrame(AbstractOutput *output) override;
void endFrame(AbstractOutput *output, const QRegion &renderedRegion, const QRegion &damagedRegion) override;
void present(AbstractOutput *output) override;
private:
void screenGeometryChanged();
......@@ -44,6 +45,7 @@ private:
DamageJournal m_damageJournal;
QScopedPointer<GLRenderTarget> m_renderTarget;
int m_bufferAge = 0;
QRegion m_lastRenderedRegion;
};
class EglPixmapTexture : public GLTexture
......
......@@ -784,6 +784,17 @@ void GlxBackend::endFrame(AbstractOutput *output, const QRegion &renderedRegion,
{
Q_UNUSED(output)
// Save the damaged region to history
if (supportsBufferAge()) {
m_damageJournal.add(damagedRegion);
}
m_lastRenderedRegion = renderedRegion;
}
void GlxBackend::present(AbstractOutput *output)
{
Q_UNUSED(output)
// If the GLX_INTEL_swap_event extension is not used for getting presentation feedback,
// assume that the frame will be presented at the next vblank event, this is racy.
if (m_vsyncMonitor) {
......@@ -792,10 +803,10 @@ void GlxBackend::endFrame(AbstractOutput *output, const QRegion &renderedRegion,
const QRegion displayRegion(screens()->geometry());
QRegion effectiveRenderedRegion = renderedRegion;
if (!supportsBufferAge() && options->glPreferBufferSwap() == Options::CopyFrontBuffer && renderedRegion != displayRegion) {
QRegion effectiveRenderedRegion = m_lastRenderedRegion;
if (!supportsBufferAge() && options->glPreferBufferSwap() == Options::CopyFrontBuffer && m_lastRenderedRegion != displayRegion) {
glReadBuffer(GL_FRONT);
copyPixels(displayRegion - renderedRegion);
copyPixels(displayRegion - m_lastRenderedRegion);
glReadBuffer(GL_BACK);
effectiveRenderedRegion = displayRegion;
}
......@@ -807,11 +818,6 @@ void GlxBackend::endFrame(AbstractOutput *output, const QRegion &renderedRegion,
if (overlayWindow()->window()) { // show the window only after the first pass,
overlayWindow()->show(); // since that pass may take long
}
// Save the damaged region to history
if (supportsBufferAge()) {
m_damageJournal.add(damagedRegion);
}
}
void GlxBackend::vblank(std::chrono::nanoseconds timestamp)
......
......@@ -71,6 +71,7 @@ public:
SurfaceTexture *createSurfaceTextureX11(SurfacePixmapX11 *pixmap) override;
QRegion beginFrame(AbstractOutput *output) override;
void endFrame(AbstractOutput *output, const QRegion &renderedRegion, const QRegion &damagedRegion) override;
void present(AbstractOutput *output) override;
bool makeCurrent() override;
void doneCurrent() override;
OverlayWindow *overlayWindow() const override;
......@@ -109,6 +110,7 @@ private:
std::unique_ptr<SwapEventFilter> m_swapEventFilter;
QScopedPointer<GLRenderTarget> m_renderTarget;
DamageJournal m_damageJournal;
QRegion m_lastRenderedRegion;
int m_bufferAge;
bool m_haveMESACopySubBuffer = false;
bool m_haveMESASwapControl = false;
......
......@@ -80,8 +80,12 @@ void EglX11Backend::endFrame(AbstractOutput *output, const QRegion &renderedRegi
static_cast<X11WindowedOutput *>(output)->vsyncMonitor()->arm();
GLRenderTarget::popRenderTarget();
m_lastRenderedRegion = renderedRegion;
}
presentSurface(m_outputs[output]->m_eglSurface, renderedRegion, output->geometry());
void EglX11Backend::present(AbstractOutput *output)
{
presentSurface(m_outputs[output]->m_eglSurface, m_lastRenderedRegion, output->geometry());
}
void EglX11Backend::presentSurface(EGLSurface surface, const QRegion &damage, const QRect &screenGeometry)
......
......@@ -41,6 +41,7 @@ public:
void init() override;
QRegion beginFrame(AbstractOutput *output) override;
void endFrame(AbstractOutput *output, const QRegion &renderedRegion, const QRegion &damagedRegion) override;
void present(AbstractOutput *output) override;
protected:
void cleanupSurfaces() override;
......@@ -50,6 +51,7 @@ private:
void presentSurface(EGLSurface surface, const QRegion &damage, const QRect &screenGeometry);
QMap<AbstractOutput *, EglX11Output *> m_outputs;
QRegion m_lastRenderedRegion;
X11WindowedBackend *m_backend;
};
......
......@@ -57,9 +57,13 @@ QRegion X11WindowedQPainterBackend::beginFrame(AbstractOutput *output)
void X11WindowedQPainterBackend::endFrame(AbstractOutput *output, const QRegion &renderedRegion, const QRegion &damagedRegion)
{
Q_UNUSED(output)
Q_UNUSED(renderedRegion)
Q_UNUSED(damagedRegion)
}
void X11WindowedQPainterBackend::present(AbstractOutput *output)
{
static_cast<X11WindowedOutput *>(output)->vsyncMonitor()->arm();
xcb_connection_t *c = m_backend->connection();
......@@ -78,5 +82,4 @@ void X11WindowedQPainterBackend::endFrame(AbstractOutput *output, const QRegion
m_gc, buffer.width(), buffer.height(), 0, 0, 0, 24,
buffer.sizeInBytes(), buffer.constBits());
}
}
......@@ -33,6 +33,7 @@ public:
QImage *bufferForScreen(AbstractOutput *output) override;
QRegion beginFrame(AbstractOutput *output) override;
void endFrame(AbstractOutput *output, const QRegion &renderedRegion, const QRegion &damagedRegion) override;
void present(AbstractOutput *output) override;
private:
void createOutputs();
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment