backends/drm: test direct scanout with the same code as presentation
This means that we prefer direct scanout over a specific presentation mode (tearing), which usually just means we first engage direct scanout and program the relevant properties, and then switch to tearing afterwards. It also removes a hack for direct scanout with legacy, and is one step less for implementing overlay plane support.
This commit is contained in:
parent
df184ebd11
commit
7ab825cba1
33 changed files with 94 additions and 82 deletions
|
@ -31,7 +31,6 @@ void DrmAbstractOutput::updateEnabled(bool enabled)
|
|||
next.enabled = enabled;
|
||||
setState(next);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#include "moc_drm_abstract_output.cpp"
|
||||
|
|
|
@ -141,9 +141,16 @@ DrmDevice *EglGbmBackend::drmDevice() const
|
|||
return gpu()->drmDevice();
|
||||
}
|
||||
|
||||
void EglGbmBackend::present(Output *output, const std::shared_ptr<OutputFrame> &frame)
|
||||
bool EglGbmBackend::present(Output *output, const std::shared_ptr<OutputFrame> &frame)
|
||||
{
|
||||
static_cast<DrmAbstractOutput *>(output)->present(frame);
|
||||
return static_cast<DrmAbstractOutput *>(output)->present(frame);
|
||||
}
|
||||
|
||||
void EglGbmBackend::repairPresentation(Output *output)
|
||||
{
|
||||
// read back drm properties, most likely our info is out of date somehow
|
||||
// or we need a modeset
|
||||
QTimer::singleShot(0, m_backend, &DrmBackend::updateOutputs);
|
||||
}
|
||||
|
||||
OutputLayer *EglGbmBackend::primaryLayer(Output *output)
|
||||
|
|
|
@ -46,7 +46,8 @@ public:
|
|||
|
||||
DrmDevice *drmDevice() const override;
|
||||
|
||||
void present(Output *output, const std::shared_ptr<OutputFrame> &frame) override;
|
||||
bool present(Output *output, const std::shared_ptr<OutputFrame> &frame) override;
|
||||
void repairPresentation(Output *output) override;
|
||||
OutputLayer *primaryLayer(Output *output) override;
|
||||
OutputLayer *cursorLayer(Output *output) override;
|
||||
|
||||
|
|
|
@ -86,13 +86,18 @@ ColorDescription EglGbmLayer::colorDescription() const
|
|||
return m_surface.colorDescription();
|
||||
}
|
||||
|
||||
bool EglGbmLayer::doAttemptScanout(GraphicsBuffer *buffer, const ColorDescription &color, RenderingIntent intent, const std::shared_ptr<OutputFrame> &frame)
|
||||
bool EglGbmLayer::doImportScanoutBuffer(GraphicsBuffer *buffer, const ColorDescription &color, RenderingIntent intent, const std::shared_ptr<OutputFrame> &frame)
|
||||
{
|
||||
static bool valid;
|
||||
static const bool directScanoutDisabled = qEnvironmentVariableIntValue("KWIN_DRM_NO_DIRECT_SCANOUT", &valid) == 1 && valid;
|
||||
if (directScanoutDisabled) {
|
||||
return false;
|
||||
}
|
||||
if (m_pipeline->gpu()->needsModeset()) {
|
||||
// don't do direct scanout with modeset, it might lead to locking
|
||||
// the hardware to some buffer format we can't switch away from
|
||||
return false;
|
||||
}
|
||||
if (m_pipeline->output()->colorProfileSource() == Output::ColorProfileSource::ICC && !m_pipeline->output()->highDynamicRange() && m_pipeline->iccProfile()) {
|
||||
// TODO make the icc profile output a color pipeline too?
|
||||
return false;
|
||||
|
@ -119,13 +124,10 @@ bool EglGbmLayer::doAttemptScanout(GraphicsBuffer *buffer, const ColorDescriptio
|
|||
return false;
|
||||
}
|
||||
m_scanoutBuffer = m_pipeline->gpu()->importBuffer(buffer, FileDescriptor{});
|
||||
if (m_scanoutBuffer && m_pipeline->testScanout(frame)) {
|
||||
if (m_scanoutBuffer) {
|
||||
m_surface.forgetDamage(); // TODO: Use absolute frame sequence numbers for indexing the DamageJournal. It's more flexible and less error-prone
|
||||
return true;
|
||||
} else {
|
||||
m_scanoutBuffer.reset();
|
||||
return false;
|
||||
}
|
||||
return m_scanoutBuffer != nullptr;
|
||||
}
|
||||
|
||||
std::shared_ptr<DrmFramebuffer> EglGbmLayer::currentBuffer() const
|
||||
|
|
|
@ -40,7 +40,7 @@ public:
|
|||
const ColorPipeline &colorPipeline() const override;
|
||||
|
||||
private:
|
||||
bool doAttemptScanout(GraphicsBuffer *buffer, const ColorDescription &color, RenderingIntent intent, const std::shared_ptr<OutputFrame> &frame) override;
|
||||
bool doImportScanoutBuffer(GraphicsBuffer *buffer, const ColorDescription &color, RenderingIntent intent, const std::shared_ptr<OutputFrame> &frame) override;
|
||||
|
||||
std::shared_ptr<DrmFramebuffer> m_scanoutBuffer;
|
||||
ColorPipeline m_colorPipeline;
|
||||
|
|
|
@ -302,18 +302,12 @@ bool DrmOutput::present(const std::shared_ptr<OutputFrame> &frame)
|
|||
err = m_pipeline->present(frame);
|
||||
}
|
||||
success = err == DrmPipeline::Error::None;
|
||||
if (err == DrmPipeline::Error::InvalidArguments) {
|
||||
QTimer::singleShot(0, m_gpu->platform(), &DrmBackend::updateOutputs);
|
||||
}
|
||||
}
|
||||
m_renderLoop->setPresentationMode(m_pipeline->presentationMode());
|
||||
if (success) {
|
||||
Q_EMIT outputChange(frame->damage());
|
||||
return true;
|
||||
} else if (!needsModeset) {
|
||||
qCWarning(KWIN_DRM) << "Presentation failed!" << strerror(errno);
|
||||
}
|
||||
return false;
|
||||
return success;
|
||||
}
|
||||
|
||||
DrmConnector *DrmOutput::connector() const
|
||||
|
|
|
@ -51,28 +51,6 @@ DrmPipeline::~DrmPipeline()
|
|||
}
|
||||
}
|
||||
|
||||
bool DrmPipeline::testScanout(const std::shared_ptr<OutputFrame> &frame)
|
||||
{
|
||||
if (gpu()->needsModeset()) {
|
||||
return false;
|
||||
}
|
||||
if (gpu()->atomicModeSetting()) {
|
||||
return DrmPipeline::commitPipelinesAtomic({this}, CommitMode::Test, frame, {}) == Error::None;
|
||||
} else {
|
||||
if (m_primaryLayer->currentBuffer()->buffer()->size() != m_pending.mode->size()) {
|
||||
// scaling isn't supported with the legacy API
|
||||
return false;
|
||||
}
|
||||
// no other way to test than to do it.
|
||||
// As we only have a maximum of one test per scanout cycle, this is fine
|
||||
const bool ret = presentLegacy(frame) == Error::None;
|
||||
if (ret) {
|
||||
m_didLegacyScanoutHack = true;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
DrmPipeline::Error DrmPipeline::present(const std::shared_ptr<OutputFrame> &frame)
|
||||
{
|
||||
Q_ASSERT(m_pending.crtc);
|
||||
|
@ -93,11 +71,6 @@ DrmPipeline::Error DrmPipeline::present(const std::shared_ptr<OutputFrame> &fram
|
|||
m_commitThread->addCommit(std::move(primaryPlaneUpdate));
|
||||
return Error::None;
|
||||
} else {
|
||||
if (m_didLegacyScanoutHack) {
|
||||
// already presented
|
||||
m_didLegacyScanoutHack = false;
|
||||
return Error::None;
|
||||
}
|
||||
return presentLegacy(frame);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -57,7 +57,6 @@ public:
|
|||
* if the test fails, there is a guarantee for no lasting changes
|
||||
*/
|
||||
Error present(const std::shared_ptr<OutputFrame> &frame);
|
||||
bool testScanout(const std::shared_ptr<OutputFrame> &frame);
|
||||
bool maybeModeset(const std::shared_ptr<OutputFrame> &frame);
|
||||
void forceLegacyModeset();
|
||||
|
||||
|
@ -150,7 +149,6 @@ private:
|
|||
DrmConnector *m_connector = nullptr;
|
||||
|
||||
bool m_modesetPresentPending = false;
|
||||
bool m_didLegacyScanoutHack = false;
|
||||
ColorPipeline m_currentLegacyGamma;
|
||||
|
||||
struct State
|
||||
|
|
|
@ -37,9 +37,16 @@ DrmDevice *DrmQPainterBackend::drmDevice() const
|
|||
return m_backend->primaryGpu()->drmDevice();
|
||||
}
|
||||
|
||||
void DrmQPainterBackend::present(Output *output, const std::shared_ptr<OutputFrame> &frame)
|
||||
bool DrmQPainterBackend::present(Output *output, const std::shared_ptr<OutputFrame> &frame)
|
||||
{
|
||||
static_cast<DrmAbstractOutput *>(output)->present(frame);
|
||||
return static_cast<DrmAbstractOutput *>(output)->present(frame);
|
||||
}
|
||||
|
||||
void DrmQPainterBackend::repairPresentation(Output *output)
|
||||
{
|
||||
// read back drm properties, most likely our info is out of date somehow
|
||||
// or we need a modeset
|
||||
QTimer::singleShot(0, m_backend, &DrmBackend::updateOutputs);
|
||||
}
|
||||
|
||||
OutputLayer *DrmQPainterBackend::primaryLayer(Output *output)
|
||||
|
|
|
@ -30,7 +30,8 @@ public:
|
|||
|
||||
DrmDevice *drmDevice() const override;
|
||||
|
||||
void present(Output *output, const std::shared_ptr<OutputFrame> &frame) override;
|
||||
bool present(Output *output, const std::shared_ptr<OutputFrame> &frame) override;
|
||||
void repairPresentation(Output *output) override;
|
||||
OutputLayer *primaryLayer(Output *output) override;
|
||||
OutputLayer *cursorLayer(Output *output) override;
|
||||
|
||||
|
|
|
@ -133,7 +133,7 @@ std::shared_ptr<GLTexture> VirtualEglGbmLayer::texture() const
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
bool VirtualEglGbmLayer::doAttemptScanout(GraphicsBuffer *buffer, const ColorDescription &color, RenderingIntent intent, const std::shared_ptr<OutputFrame> &frame)
|
||||
bool VirtualEglGbmLayer::doImportScanoutBuffer(GraphicsBuffer *buffer, const ColorDescription &color, RenderingIntent intent, const std::shared_ptr<OutputFrame> &frame)
|
||||
{
|
||||
static bool valid;
|
||||
static const bool directScanoutDisabled = qEnvironmentVariableIntValue("KWIN_DRM_NO_DIRECT_SCANOUT", &valid) == 1 && valid;
|
||||
|
|
|
@ -44,7 +44,7 @@ public:
|
|||
const ColorDescription &colorDescription() const;
|
||||
|
||||
private:
|
||||
bool doAttemptScanout(GraphicsBuffer *buffer, const ColorDescription &color, RenderingIntent intent, const std::shared_ptr<OutputFrame> &frame) override;
|
||||
bool doImportScanoutBuffer(GraphicsBuffer *buffer, const ColorDescription &color, RenderingIntent intent, const std::shared_ptr<OutputFrame> &frame) override;
|
||||
std::shared_ptr<EglSwapchain> createGbmSwapchain() const;
|
||||
bool doesGbmSwapchainFit(EglSwapchain *swapchain) const;
|
||||
|
||||
|
|
|
@ -178,9 +178,10 @@ OutputLayer *VirtualEglBackend::primaryLayer(Output *output)
|
|||
return m_outputs[output].get();
|
||||
}
|
||||
|
||||
void VirtualEglBackend::present(Output *output, const std::shared_ptr<OutputFrame> &frame)
|
||||
bool VirtualEglBackend::present(Output *output, const std::shared_ptr<OutputFrame> &frame)
|
||||
{
|
||||
static_cast<VirtualOutput *>(output)->present(frame);
|
||||
return true;
|
||||
}
|
||||
|
||||
std::pair<std::shared_ptr<KWin::GLTexture>, ColorDescription> VirtualEglBackend::textureForOutput(Output *output) const
|
||||
|
|
|
@ -57,7 +57,7 @@ public:
|
|||
std::unique_ptr<SurfaceTexture> createSurfaceTextureWayland(SurfacePixmap *pixmap) override;
|
||||
std::pair<std::shared_ptr<KWin::GLTexture>, ColorDescription> textureForOutput(Output *output) const override;
|
||||
OutputLayer *primaryLayer(Output *output) override;
|
||||
void present(Output *output, const std::shared_ptr<OutputFrame> &frame) override;
|
||||
bool present(Output *output, const std::shared_ptr<OutputFrame> &frame) override;
|
||||
void init() override;
|
||||
|
||||
VirtualBackend *backend() const;
|
||||
|
|
|
@ -100,9 +100,10 @@ GraphicsBufferAllocator *VirtualQPainterBackend::graphicsBufferAllocator() const
|
|||
return m_allocator.get();
|
||||
}
|
||||
|
||||
void VirtualQPainterBackend::present(Output *output, const std::shared_ptr<OutputFrame> &frame)
|
||||
bool VirtualQPainterBackend::present(Output *output, const std::shared_ptr<OutputFrame> &frame)
|
||||
{
|
||||
static_cast<VirtualOutput *>(output)->present(frame);
|
||||
return true;
|
||||
}
|
||||
|
||||
VirtualQPainterLayer *VirtualQPainterBackend::primaryLayer(Output *output)
|
||||
|
|
|
@ -55,7 +55,7 @@ public:
|
|||
|
||||
GraphicsBufferAllocator *graphicsBufferAllocator() const;
|
||||
|
||||
void present(Output *output, const std::shared_ptr<OutputFrame> &frame) override;
|
||||
bool present(Output *output, const std::shared_ptr<OutputFrame> &frame) override;
|
||||
VirtualQPainterLayer *primaryLayer(Output *output) override;
|
||||
|
||||
private:
|
||||
|
|
|
@ -111,7 +111,7 @@ bool WaylandEglPrimaryLayer::doEndFrame(const QRegion &renderedRegion, const QRe
|
|||
return true;
|
||||
}
|
||||
|
||||
bool WaylandEglPrimaryLayer::doAttemptScanout(GraphicsBuffer *buffer, const ColorDescription &color, RenderingIntent intent, const std::shared_ptr<OutputFrame> &frame)
|
||||
bool WaylandEglPrimaryLayer::doImportScanoutBuffer(GraphicsBuffer *buffer, const ColorDescription &color, RenderingIntent intent, const std::shared_ptr<OutputFrame> &frame)
|
||||
{
|
||||
Q_ASSERT(!m_presentationBuffer);
|
||||
// TODO use viewporter to relax this check
|
||||
|
@ -347,11 +347,12 @@ std::unique_ptr<SurfaceTexture> WaylandEglBackend::createSurfaceTextureWayland(S
|
|||
return std::make_unique<BasicEGLSurfaceTextureWayland>(this, pixmap);
|
||||
}
|
||||
|
||||
void WaylandEglBackend::present(Output *output, const std::shared_ptr<OutputFrame> &frame)
|
||||
bool WaylandEglBackend::present(Output *output, const std::shared_ptr<OutputFrame> &frame)
|
||||
{
|
||||
m_outputs[output].primaryLayer->present();
|
||||
static_cast<WaylandOutput *>(output)->setPendingFrame(frame);
|
||||
Q_EMIT static_cast<WaylandOutput *>(output)->outputChange(frame->damage());
|
||||
return true;
|
||||
}
|
||||
|
||||
OutputLayer *WaylandEglBackend::primaryLayer(Output *output)
|
||||
|
|
|
@ -44,7 +44,7 @@ public:
|
|||
|
||||
std::optional<OutputLayerBeginFrameInfo> doBeginFrame() override;
|
||||
bool doEndFrame(const QRegion &renderedRegion, const QRegion &damagedRegion, OutputFrame *frame) override;
|
||||
bool doAttemptScanout(GraphicsBuffer *buffer, const ColorDescription &color, RenderingIntent intent, const std::shared_ptr<OutputFrame> &frame) override;
|
||||
bool doImportScanoutBuffer(GraphicsBuffer *buffer, const ColorDescription &color, RenderingIntent intent, const std::shared_ptr<OutputFrame> &frame) override;
|
||||
DrmDevice *scanoutDevice() const override;
|
||||
QHash<uint32_t, QList<uint64_t>> supportedDrmFormats() const override;
|
||||
|
||||
|
@ -104,7 +104,7 @@ public:
|
|||
std::unique_ptr<SurfaceTexture> createSurfaceTextureWayland(SurfacePixmap *pixmap) override;
|
||||
|
||||
void init() override;
|
||||
void present(Output *output, const std::shared_ptr<OutputFrame> &frame) override;
|
||||
bool present(Output *output, const std::shared_ptr<OutputFrame> &frame) override;
|
||||
OutputLayer *primaryLayer(Output *output) override;
|
||||
OutputLayer *cursorLayer(Output *output) override;
|
||||
|
||||
|
|
|
@ -178,10 +178,11 @@ GraphicsBufferAllocator *WaylandQPainterBackend::graphicsBufferAllocator() const
|
|||
return m_allocator.get();
|
||||
}
|
||||
|
||||
void WaylandQPainterBackend::present(Output *output, const std::shared_ptr<OutputFrame> &frame)
|
||||
bool WaylandQPainterBackend::present(Output *output, const std::shared_ptr<OutputFrame> &frame)
|
||||
{
|
||||
m_outputs[output].primaryLayer->present();
|
||||
static_cast<WaylandOutput *>(output)->setPendingFrame(frame);
|
||||
return true;
|
||||
}
|
||||
|
||||
OutputLayer *WaylandQPainterBackend::primaryLayer(Output *output)
|
||||
|
|
|
@ -87,7 +87,7 @@ public:
|
|||
|
||||
GraphicsBufferAllocator *graphicsBufferAllocator() const;
|
||||
|
||||
void present(Output *output, const std::shared_ptr<OutputFrame> &frame) override;
|
||||
bool present(Output *output, const std::shared_ptr<OutputFrame> &frame) override;
|
||||
OutputLayer *primaryLayer(Output *output) override;
|
||||
OutputLayer *cursorLayer(Output *output) override;
|
||||
|
||||
|
|
|
@ -380,7 +380,7 @@ void EglBackend::endFrame(const QRegion &renderedRegion, const QRegion &damagedR
|
|||
m_lastRenderedRegion = renderedRegion;
|
||||
}
|
||||
|
||||
void EglBackend::present(Output *output, const std::shared_ptr<OutputFrame> &frame)
|
||||
bool EglBackend::present(Output *output, const std::shared_ptr<OutputFrame> &frame)
|
||||
{
|
||||
m_frame = frame;
|
||||
// Start the software vsync monitor. There is no any reliable way to determine when
|
||||
|
@ -403,6 +403,7 @@ void EglBackend::present(Output *output, const std::shared_ptr<OutputFrame> &fra
|
|||
if (overlayWindow() && overlayWindow()->window()) { // show the window only after the first pass,
|
||||
overlayWindow()->show(); // since that pass may take long
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void EglBackend::presentSurface(EGLSurface surface, const QRegion &damage, const QRect &screenGeometry)
|
||||
|
|
|
@ -56,7 +56,7 @@ public:
|
|||
std::unique_ptr<SurfaceTexture> createSurfaceTextureX11(SurfacePixmapX11 *texture) override;
|
||||
OutputLayerBeginFrameInfo beginFrame();
|
||||
void endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion, OutputFrame *frame);
|
||||
void present(Output *output, const std::shared_ptr<OutputFrame> &frame) override;
|
||||
bool present(Output *output, const std::shared_ptr<OutputFrame> &frame) override;
|
||||
OverlayWindow *overlayWindow() const override;
|
||||
OutputLayer *primaryLayer(Output *output) override;
|
||||
EglDisplay *eglDisplayObject() const override;
|
||||
|
|
|
@ -681,7 +681,7 @@ void GlxBackend::endFrame(const QRegion &renderedRegion, const QRegion &damagedR
|
|||
m_lastRenderedRegion = renderedRegion;
|
||||
}
|
||||
|
||||
void GlxBackend::present(Output *output, const std::shared_ptr<OutputFrame> &frame)
|
||||
bool GlxBackend::present(Output *output, const std::shared_ptr<OutputFrame> &frame)
|
||||
{
|
||||
m_frame = frame;
|
||||
// If the GLX_INTEL_swap_event extension is not used for getting presentation feedback,
|
||||
|
@ -705,6 +705,7 @@ void GlxBackend::present(Output *output, const std::shared_ptr<OutputFrame> &fra
|
|||
if (overlayWindow()->window()) { // show the window only after the first pass,
|
||||
overlayWindow()->show(); // since that pass may take long
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void GlxBackend::vblank(std::chrono::nanoseconds timestamp)
|
||||
|
|
|
@ -85,7 +85,7 @@ public:
|
|||
std::unique_ptr<SurfaceTexture> createSurfaceTextureX11(SurfacePixmapX11 *pixmap) override;
|
||||
OutputLayerBeginFrameInfo doBeginFrame();
|
||||
void endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion, OutputFrame *frame);
|
||||
void present(Output *output, const std::shared_ptr<OutputFrame> &frame) override;
|
||||
bool present(Output *output, const std::shared_ptr<OutputFrame> &frame) override;
|
||||
bool makeCurrent() override;
|
||||
void doneCurrent() override;
|
||||
OpenGlContext *openglContext() const override;
|
||||
|
|
|
@ -265,11 +265,12 @@ void X11WindowedEglBackend::init()
|
|||
}
|
||||
}
|
||||
|
||||
void X11WindowedEglBackend::present(Output *output, const std::shared_ptr<OutputFrame> &frame)
|
||||
bool X11WindowedEglBackend::present(Output *output, const std::shared_ptr<OutputFrame> &frame)
|
||||
{
|
||||
m_outputs[output].primaryLayer->present();
|
||||
Q_EMIT static_cast<X11WindowedOutput *>(output)->outputChange(frame->damage());
|
||||
static_cast<X11WindowedOutput *>(output)->framePending(frame);
|
||||
return true;
|
||||
}
|
||||
|
||||
OutputLayer *X11WindowedEglBackend::primaryLayer(Output *output)
|
||||
|
|
|
@ -82,7 +82,7 @@ public:
|
|||
std::pair<std::shared_ptr<GLTexture>, ColorDescription> textureForOutput(Output *output) const override;
|
||||
void init() override;
|
||||
void endFrame(Output *output, const QRegion &renderedRegion, const QRegion &damagedRegion);
|
||||
void present(Output *output, const std::shared_ptr<OutputFrame> &frame) override;
|
||||
bool present(Output *output, const std::shared_ptr<OutputFrame> &frame) override;
|
||||
OutputLayer *primaryLayer(Output *output) override;
|
||||
OutputLayer *cursorLayer(Output *output) override;
|
||||
|
||||
|
|
|
@ -181,10 +181,11 @@ GraphicsBufferAllocator *X11WindowedQPainterBackend::graphicsBufferAllocator() c
|
|||
return m_allocator.get();
|
||||
}
|
||||
|
||||
void X11WindowedQPainterBackend::present(Output *output, const std::shared_ptr<OutputFrame> &frame)
|
||||
bool X11WindowedQPainterBackend::present(Output *output, const std::shared_ptr<OutputFrame> &frame)
|
||||
{
|
||||
m_outputs[output].primaryLayer->present();
|
||||
static_cast<X11WindowedOutput *>(output)->framePending(frame);
|
||||
return true;
|
||||
}
|
||||
|
||||
OutputLayer *X11WindowedQPainterBackend::primaryLayer(Output *output)
|
||||
|
|
|
@ -76,7 +76,7 @@ public:
|
|||
|
||||
GraphicsBufferAllocator *graphicsBufferAllocator() const;
|
||||
|
||||
void present(Output *output, const std::shared_ptr<OutputFrame> &frame) override;
|
||||
bool present(Output *output, const std::shared_ptr<OutputFrame> &frame) override;
|
||||
OutputLayer *primaryLayer(Output *output) override;
|
||||
OutputLayer *cursorLayer(Output *output) override;
|
||||
|
||||
|
|
|
@ -312,6 +312,7 @@ void WaylandCompositor::composite(RenderLoop *renderLoop)
|
|||
|
||||
renderLoop->prepareNewFrame();
|
||||
auto frame = std::make_shared<OutputFrame>(renderLoop, std::chrono::nanoseconds(1'000'000'000'000 / output->refreshRate()));
|
||||
bool directScanout = false;
|
||||
|
||||
if (primaryLayer->needsRepaint() || superLayer->needsRepaint()) {
|
||||
auto totalTimeQuery = std::make_unique<CpuRenderTimeQuery>();
|
||||
|
@ -347,7 +348,16 @@ void WaylandCompositor::composite(RenderLoop *renderLoop)
|
|||
}
|
||||
if (scanoutPossible) {
|
||||
primaryLayer->setTargetRect(centerBuffer(output->transform().map(scanoutCandidates.front()->size()), output->modeSize()));
|
||||
directScanout = primaryLayer->attemptScanout(scanoutCandidates.front(), frame);
|
||||
directScanout = primaryLayer->importScanoutBuffer(scanoutCandidates.front(), frame);
|
||||
if (directScanout) {
|
||||
// if present works, we don't want to touch the frame object again afterwards,
|
||||
// so end the time query here instead of later
|
||||
totalTimeQuery->end();
|
||||
frame->addRenderTimeQuery(std::move(totalTimeQuery));
|
||||
totalTimeQuery = std::make_unique<CpuRenderTimeQuery>();
|
||||
|
||||
directScanout &= m_backend->present(output, frame);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
primaryLayer->notifyNoScanoutCandidate();
|
||||
|
@ -366,11 +376,17 @@ void WaylandCompositor::composite(RenderLoop *renderLoop)
|
|||
}
|
||||
|
||||
postPaintPass(superLayer);
|
||||
totalTimeQuery->end();
|
||||
frame->addRenderTimeQuery(std::move(totalTimeQuery));
|
||||
if (!directScanout) {
|
||||
totalTimeQuery->end();
|
||||
frame->addRenderTimeQuery(std::move(totalTimeQuery));
|
||||
}
|
||||
}
|
||||
|
||||
m_backend->present(output, frame);
|
||||
if (!directScanout) {
|
||||
if (!m_backend->present(output, frame)) {
|
||||
m_backend->repairPresentation(output);
|
||||
}
|
||||
}
|
||||
|
||||
framePass(superLayer, frame.get());
|
||||
|
||||
|
|
|
@ -62,12 +62,12 @@ bool OutputLayer::needsRepaint() const
|
|||
return !m_repaints.isEmpty();
|
||||
}
|
||||
|
||||
bool OutputLayer::doAttemptScanout(GraphicsBuffer *buffer, const ColorDescription &color, RenderingIntent intent, const std::shared_ptr<OutputFrame> &frame)
|
||||
bool OutputLayer::doImportScanoutBuffer(GraphicsBuffer *buffer, const ColorDescription &color, RenderingIntent intent, const std::shared_ptr<OutputFrame> &frame)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool OutputLayer::attemptScanout(SurfaceItem *surfaceItem, const std::shared_ptr<OutputFrame> &frame)
|
||||
bool OutputLayer::importScanoutBuffer(SurfaceItem *surfaceItem, const std::shared_ptr<OutputFrame> &frame)
|
||||
{
|
||||
SurfaceItemWayland *wayland = qobject_cast<SurfaceItemWayland *>(surfaceItem);
|
||||
if (!wayland || !wayland->surface()) {
|
||||
|
@ -91,7 +91,7 @@ bool OutputLayer::attemptScanout(SurfaceItem *surfaceItem, const std::shared_ptr
|
|||
m_bufferTransform = surfaceItem->bufferTransform();
|
||||
const auto desiredTransform = m_output ? m_output->transform() : OutputTransform::Kind::Normal;
|
||||
m_offloadTransform = m_bufferTransform.combine(desiredTransform.inverted());
|
||||
const bool ret = doAttemptScanout(buffer, surfaceItem->colorDescription(), surfaceItem->renderingIntent(), frame);
|
||||
const bool ret = doImportScanoutBuffer(buffer, surfaceItem->colorDescription(), surfaceItem->renderingIntent(), frame);
|
||||
if (ret) {
|
||||
surfaceItem->resetDamage();
|
||||
// ensure the pixmap is updated when direct scanout ends
|
||||
|
|
|
@ -62,10 +62,11 @@ public:
|
|||
bool endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion, OutputFrame *frame);
|
||||
|
||||
/**
|
||||
* Tries to import the newest buffer of the surface for direct scanout
|
||||
* Returns @c true if scanout succeeds, @c false if rendering is necessary
|
||||
* Tries to import the newest buffer of the surface for direct scanout and does some early checks
|
||||
* for whether or not direct scanout *could* be successful
|
||||
* A presentation request on the output must however be used afterwards to find out if it's actually successful!
|
||||
*/
|
||||
bool attemptScanout(SurfaceItem *item, const std::shared_ptr<OutputFrame> &frame);
|
||||
bool importScanoutBuffer(SurfaceItem *item, const std::shared_ptr<OutputFrame> &frame);
|
||||
|
||||
/**
|
||||
* Notify that there's no scanout candidate this frame
|
||||
|
@ -95,7 +96,7 @@ public:
|
|||
OutputTransform bufferTransform() const;
|
||||
|
||||
protected:
|
||||
virtual bool doAttemptScanout(GraphicsBuffer *buffer, const ColorDescription &color, RenderingIntent intent, const std::shared_ptr<OutputFrame> &frame);
|
||||
virtual bool doImportScanoutBuffer(GraphicsBuffer *buffer, const ColorDescription &color, RenderingIntent intent, const std::shared_ptr<OutputFrame> &frame);
|
||||
virtual std::optional<OutputLayerBeginFrameInfo> doBeginFrame() = 0;
|
||||
virtual bool doEndFrame(const QRegion &renderedRegion, const QRegion &damagedRegion, OutputFrame *frame) = 0;
|
||||
|
||||
|
|
|
@ -187,6 +187,10 @@ std::unique_ptr<SurfaceTexture> RenderBackend::createSurfaceTextureWayland(Surfa
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
void RenderBackend::repairPresentation(Output *output)
|
||||
{
|
||||
}
|
||||
|
||||
} // namespace KWin
|
||||
|
||||
#include "moc_renderbackend.cpp"
|
||||
|
|
|
@ -126,7 +126,8 @@ public:
|
|||
|
||||
virtual OutputLayer *primaryLayer(Output *output) = 0;
|
||||
virtual OutputLayer *cursorLayer(Output *output);
|
||||
virtual void present(Output *output, const std::shared_ptr<OutputFrame> &frame) = 0;
|
||||
virtual bool present(Output *output, const std::shared_ptr<OutputFrame> &frame) = 0;
|
||||
virtual void repairPresentation(Output *output);
|
||||
|
||||
virtual DrmDevice *drmDevice() const;
|
||||
|
||||
|
|
Loading…
Reference in a new issue