platforms/drm: change when to reset the output with eglstreams

In order to accomodate crtc or primary plane changes on outputs we
need to dynamically recreate rendering resources with EglStreams as
the stream is tied to the crtc or plane currently in use.
This commit is contained in:
Xaver Hugl 2021-06-24 15:53:06 +02:00
parent d057bd41c9
commit 65b55e2045
2 changed files with 33 additions and 14 deletions

View file

@ -306,6 +306,7 @@ bool EglStreamBackend::resetOutput(Output &o)
if (isPrimary()) {
// dumb buffer used for modesetting
o.buffer = QSharedPointer<DrmDumbBuffer>::create(m_gpu, sourceSize);
o.targetPlane = drmOutput->pipeline()->primaryPlane();
EGLAttrib streamAttribs[] = {
EGL_STREAM_FIFO_LENGTH_KHR, 0, // mailbox mode
@ -319,13 +320,8 @@ bool EglStreamBackend::resetOutput(Output &o)
}
EGLAttrib outputAttribs[3];
if (drmOutput->pipeline()->primaryPlane()) {
outputAttribs[0] = EGL_DRM_PLANE_EXT;
outputAttribs[1] = drmOutput->pipeline()->primaryPlane()->id();
} else {
outputAttribs[0] = EGL_DRM_CRTC_EXT;
outputAttribs[1] = drmOutput->pipeline()->crtc()->id();
}
outputAttribs[0] = EGL_DRM_PLANE_EXT;
outputAttribs[1] = o.targetPlane->id();
outputAttribs[2] = EGL_NONE;
EGLint numLayers;
EGLOutputLayerEXT outputLayer;
@ -392,12 +388,6 @@ bool EglStreamBackend::addOutput(DrmAbstractOutput *output)
if (!isPrimary() && !renderingBackend()->addOutput(drmOutput)) {
return false;
}
connect(drmOutput, &DrmOutput::currentModeChanged, this,
[drmOutput, this] {
resetOutput(m_outputs[drmOutput]);
}
);
m_outputs.insert(output, o);
return true;
} else {
@ -483,11 +473,34 @@ PlatformSurfaceTexture *EglStreamBackend::createPlatformSurfaceTextureWayland(Su
return new EglStreamSurfaceTextureWayland(this, pixmap);
}
bool EglStreamBackend::needsReset(const Output &o) const
{
if (o.targetPlane != o.output->pipeline()->primaryPlane()) {
return true;
}
QSize surfaceSize = o.dumbSwapchain ? o.dumbSwapchain->size() : o.buffer->size();
if (surfaceSize != o.output->sourceSize()) {
return true;
}
bool needsTexture = surfaceSize != o.output->pixelSize();
if (needsTexture) {
return !o.shadowBuffer || o.shadowBuffer->textureSize() != o.output->pixelSize();
} else {
return o.shadowBuffer != nullptr;
}
}
QRegion EglStreamBackend::beginFrame(AbstractOutput *drmOutput)
{
Q_ASSERT(m_outputs.contains(drmOutput));
const Output &o = m_outputs[drmOutput];
Output &o = m_outputs[drmOutput];
if (isPrimary()) {
if (needsReset(o)) {
if (!resetOutput(o)) {
// handle this better?
return {};
}
}
makeContextCurrent(o);
if (o.shadowBuffer) {
o.shadowBuffer->bind();

View file

@ -21,6 +21,8 @@ class DrmAbstractOutput;
class DrmDumbBuffer;
class DumbSwapchain;
class ShadowBuffer;
class DrmCrtc;
class DrmPlane;
/**
* @brief OpenGL Backend using Egl with an EGLDevice.
@ -68,12 +70,16 @@ private:
EGLStreamKHR eglStream = EGL_NO_STREAM_KHR;
QSharedPointer<ShadowBuffer> shadowBuffer;
DrmPlane *targetPlane = nullptr;
// for operation as secondary GPU
QSharedPointer<DumbSwapchain> dumbSwapchain;
};
bool resetOutput(Output &output);
bool createEglSurface(Output &o);
bool makeContextCurrent(const Output &output);
void cleanupOutput(Output &output);
bool needsReset(const Output &o) const;
QMap<AbstractOutput *, Output> m_outputs;
KWaylandServer::EglStreamControllerInterface *m_eglStreamControllerInterface;