platforms/drm: support NVidia as secondary GPU with CPU copy
BUG: 431062
This commit is contained in:
parent
605f00d03a
commit
cfd7af0179
10 changed files with 203 additions and 141 deletions
|
@ -25,7 +25,7 @@ public:
|
|||
void screenGeometryChanged(const QSize &size) override;
|
||||
|
||||
virtual int screenCount() const = 0;
|
||||
virtual void addOutput(DrmOutput *output) = 0;
|
||||
virtual bool addOutput(DrmOutput *output) = 0;
|
||||
virtual void removeOutput(DrmOutput *output) = 0;
|
||||
virtual bool swapBuffers(DrmOutput *output) {
|
||||
Q_UNUSED(output)
|
||||
|
|
|
@ -186,8 +186,22 @@ bool DrmBackend::initialize()
|
|||
}
|
||||
} else {
|
||||
const auto devices = m_udev->listGPUs();
|
||||
bool bootVga = false;
|
||||
for (const UdevDevice::Ptr &device : devices) {
|
||||
addGpu(device->devNode());
|
||||
if (addGpu(device->devNode())) {
|
||||
bootVga |= device->isBootVga();
|
||||
}
|
||||
}
|
||||
|
||||
// if a boot device is set, honor that setting
|
||||
// if not, prefer gbm for rendering because that works better
|
||||
if (!bootVga && !m_gpus.isEmpty() && m_gpus[0]->useEglStreams()) {
|
||||
for (int i = 1; i < m_gpus.count(); i++) {
|
||||
if (!m_gpus[i]->useEglStreams()) {
|
||||
m_gpus.swapItemsAt(i, 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -220,11 +234,10 @@ void DrmBackend::handleUdevEvent()
|
|||
}
|
||||
|
||||
if (device->action() == QStringLiteral("add")) {
|
||||
if (m_gpus.isEmpty() || !primaryGpu()->useEglStreams()) {
|
||||
if (addGpu(device->devNode())) {
|
||||
updateOutputs();
|
||||
updateCursor();
|
||||
}
|
||||
qCDebug(KWIN_DRM) << "New gpu found:" << device->devNode();
|
||||
if (addGpu(device->devNode())) {
|
||||
updateOutputs();
|
||||
updateCursor();
|
||||
}
|
||||
} else if (device->action() == QStringLiteral("remove")) {
|
||||
DrmGpu *gpu = findGpu(device->devNum());
|
||||
|
@ -234,6 +247,7 @@ void DrmBackend::handleUdevEvent()
|
|||
kwinApp()->quit();
|
||||
return;
|
||||
} else {
|
||||
qCDebug(KWIN_DRM) << "Removing gpu" << gpu->devNode();
|
||||
emit gpuRemoved(gpu);
|
||||
m_gpus.removeOne(gpu);
|
||||
delete gpu;
|
||||
|
@ -247,7 +261,7 @@ void DrmBackend::handleUdevEvent()
|
|||
gpu = addGpu(device->devNode());
|
||||
}
|
||||
if (gpu) {
|
||||
qCDebug(KWIN_DRM) << "Received hot plug event for monitored drm device";
|
||||
qCDebug(KWIN_DRM) << "Received hot plug event for monitored drm device" << gpu->devNode();
|
||||
updateOutputs();
|
||||
updateCursor();
|
||||
}
|
||||
|
@ -257,6 +271,9 @@ void DrmBackend::handleUdevEvent()
|
|||
|
||||
DrmGpu *DrmBackend::addGpu(const QString &fileName)
|
||||
{
|
||||
if (primaryGpu() && primaryGpu()->useEglStreams()) {
|
||||
return nullptr;
|
||||
}
|
||||
int fd = session()->openRestricted(fileName);
|
||||
if (fd < 0) {
|
||||
qCWarning(KWIN_DRM) << "failed to open drm device at" << fileName;
|
||||
|
@ -280,17 +297,12 @@ DrmGpu *DrmBackend::addGpu(const QString &fileName)
|
|||
}
|
||||
|
||||
DrmGpu *gpu = new DrmGpu(this, fileName, fd, buf.st_rdev);
|
||||
if (!gpu->useEglStreams() || m_gpus.isEmpty()) {
|
||||
m_gpus.append(gpu);
|
||||
m_active = true;
|
||||
connect(gpu, &DrmGpu::outputAdded, this, &DrmBackend::addOutput);
|
||||
connect(gpu, &DrmGpu::outputRemoved, this, &DrmBackend::removeOutput);
|
||||
emit gpuAdded(gpu);
|
||||
return gpu;
|
||||
} else {
|
||||
delete gpu;
|
||||
return nullptr;
|
||||
}
|
||||
m_gpus.append(gpu);
|
||||
m_active = true;
|
||||
connect(gpu, &DrmGpu::outputAdded, this, &DrmBackend::addOutput);
|
||||
connect(gpu, &DrmGpu::outputRemoved, this, &DrmBackend::removeOutput);
|
||||
emit gpuAdded(gpu);
|
||||
return gpu;
|
||||
}
|
||||
|
||||
void DrmBackend::addOutput(DrmOutput *o)
|
||||
|
@ -319,6 +331,7 @@ void DrmBackend::updateOutputs()
|
|||
auto gpu = *it;
|
||||
gpu->updateOutputs();
|
||||
if (gpu->outputs().isEmpty() && gpu != primaryGpu()) {
|
||||
qCDebug(KWIN_DRM) << "removing unused GPU" << gpu->devNode();
|
||||
it = m_gpus.erase(it);
|
||||
emit gpuRemoved(gpu);
|
||||
delete gpu;
|
||||
|
@ -594,8 +607,7 @@ OpenGLBackend *DrmBackend::createOpenGLBackend()
|
|||
AbstractEglBackend::setPrimaryBackend(primaryBackend);
|
||||
EglMultiBackend *backend = new EglMultiBackend(this, primaryBackend);
|
||||
for (int i = 1; i < m_gpus.count(); i++) {
|
||||
auto backendi = new EglGbmBackend(this, m_gpus.at(i));
|
||||
backend->addBackend(backendi);
|
||||
backend->addGpu(m_gpus[i]);
|
||||
}
|
||||
return backend;
|
||||
#else
|
||||
|
|
|
@ -656,14 +656,12 @@ bool DrmOutput::presentAtomically(const QSharedPointer<DrmBuffer> &buffer)
|
|||
return false;
|
||||
}
|
||||
|
||||
#if HAVE_EGL_STREAMS
|
||||
if (m_gpu->useEglStreams() && !m_modesetRequested) {
|
||||
// EglStreamBackend queues normal page flips through EGL,
|
||||
// modesets are still performed through DRM-KMS
|
||||
// EglStreamBackend queues normal page flips through EGL when used as the rendering backend,
|
||||
// modesets are still performed through DRM-KMS
|
||||
if (m_gpu->useEglStreams() && !m_modesetRequested && m_gpu == m_backend->primaryGpu()) {
|
||||
m_pageFlipPending = true;
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
m_primaryPlane->setNext(buffer);
|
||||
m_nextPlanesFlipList << m_primaryPlane;
|
||||
|
@ -814,12 +812,12 @@ bool DrmOutput::doAtomicCommit(AtomicCommitMode mode)
|
|||
flags |= DRM_MODE_ATOMIC_NONBLOCK;
|
||||
}
|
||||
|
||||
#if HAVE_EGL_STREAMS
|
||||
if (!m_gpu->useEglStreams())
|
||||
// EglStreamBackend uses the NV_output_drm_flip_event EGL extension
|
||||
// to register the flip event through eglStreamConsumerAcquireAttribNV
|
||||
#endif
|
||||
// EglStreamBackend uses the NV_output_drm_flip_event EGL extension
|
||||
// to register the flip event through eglStreamConsumerAcquireAttribNV
|
||||
// but only when used as the rendering GPU
|
||||
if (!m_gpu->useEglStreams() || m_gpu != m_backend->primaryGpu()) {
|
||||
flags |= DRM_MODE_PAGE_FLIP_EVENT;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
flags |= DRM_MODE_ATOMIC_TEST_ONLY;
|
||||
|
|
|
@ -32,7 +32,7 @@ DumbSwapchain::DumbSwapchain(DrmGpu *gpu, const QSize &size)
|
|||
m_buffers << buffer;
|
||||
}
|
||||
if (m_buffers.count() < 3) {
|
||||
qCWarning(KWIN_DRM) << "Failed to create gbm buffers for swapchain!";
|
||||
qCWarning(KWIN_DRM) << "Failed to create dumb buffers for swapchain!";
|
||||
m_buffers.clear();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -208,7 +208,7 @@ bool EglGbmBackend::resetOutput(Output &output, DrmOutput *drmOutput)
|
|||
return true;
|
||||
}
|
||||
|
||||
void EglGbmBackend::addOutput(DrmOutput *drmOutput)
|
||||
bool EglGbmBackend::addOutput(DrmOutput *drmOutput)
|
||||
{
|
||||
if (isPrimary()) {
|
||||
Output newOutput;
|
||||
|
@ -228,13 +228,18 @@ void EglGbmBackend::addOutput(DrmOutput *drmOutput)
|
|||
}
|
||||
);
|
||||
outputs << newOutput;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
Output newOutput;
|
||||
newOutput.output = drmOutput;
|
||||
renderingBackend()->addOutput(drmOutput);
|
||||
if (!renderingBackend()->addOutput(drmOutput)) {
|
||||
return false;
|
||||
}
|
||||
m_outputs << newOutput;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void EglGbmBackend::removeOutput(DrmOutput *drmOutput)
|
||||
|
@ -269,7 +274,7 @@ bool EglGbmBackend::swapBuffers(DrmOutput *drmOutput)
|
|||
renderFramebufferToSurface(*it);
|
||||
auto error = eglSwapBuffers(eglDisplay(), it->eglSurface);
|
||||
if (error != EGL_TRUE) {
|
||||
qCDebug(KWIN_DRM) << "an error occurred while swapping buffers" << error;
|
||||
qCCritical(KWIN_DRM) << "an error occurred while swapping buffers" << error;
|
||||
it->secondaryBuffer = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -57,7 +57,7 @@ public:
|
|||
return m_outputs.count();
|
||||
}
|
||||
|
||||
void addOutput(DrmOutput *output) override;
|
||||
bool addOutput(DrmOutput *output) override;
|
||||
void removeOutput(DrmOutput *output) override;
|
||||
bool swapBuffers(DrmOutput *output) override;
|
||||
bool exportFramebuffer(DrmOutput *output, void *data, const QSize &size, uint32_t stride) override;
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include "egl_multi_backend.h"
|
||||
#include "logging.h"
|
||||
#include "egl_gbm_backend.h"
|
||||
#include "egl_stream_backend.h"
|
||||
#include "drm_backend.h"
|
||||
#include "drm_gpu.h"
|
||||
|
||||
|
@ -49,6 +50,7 @@ void EglMultiBackend::init()
|
|||
setExtensions(m_backends[0]->extensions());
|
||||
|
||||
m_backends[0]->makeCurrent();
|
||||
m_initialized = true;
|
||||
}
|
||||
|
||||
QRegion EglMultiBackend::beginFrame(int screenId)
|
||||
|
@ -120,11 +122,6 @@ AbstractEglDrmBackend *EglMultiBackend::findBackend(int screenId, int& internalS
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
void EglMultiBackend::addBackend(AbstractEglDrmBackend *backend)
|
||||
{
|
||||
m_backends.append(backend);
|
||||
}
|
||||
|
||||
bool EglMultiBackend::directScanoutAllowed(int screenId) const
|
||||
{
|
||||
int internalScreenId;
|
||||
|
@ -135,9 +132,15 @@ bool EglMultiBackend::directScanoutAllowed(int screenId) const
|
|||
|
||||
void EglMultiBackend::addGpu(DrmGpu *gpu)
|
||||
{
|
||||
// secondary GPUs are atm guaranteed to be gbm
|
||||
auto backend = new EglGbmBackend(m_platform, gpu);
|
||||
backend->init();
|
||||
AbstractEglDrmBackend *backend;
|
||||
if (gpu->useEglStreams()) {
|
||||
backend = new EglStreamBackend(m_platform, gpu);
|
||||
} else {
|
||||
backend = new EglGbmBackend(m_platform, gpu);
|
||||
}
|
||||
if (m_initialized) {
|
||||
backend->init();
|
||||
}
|
||||
m_backends.append(backend);
|
||||
}
|
||||
|
||||
|
|
|
@ -37,8 +37,6 @@ public:
|
|||
|
||||
void screenGeometryChanged(const QSize &size) override;
|
||||
|
||||
void addBackend(AbstractEglDrmBackend *backend);
|
||||
|
||||
bool directScanoutAllowed(int screen) const override;
|
||||
|
||||
public Q_SLOTS:
|
||||
|
@ -48,6 +46,7 @@ public Q_SLOTS:
|
|||
private:
|
||||
DrmBackend *m_platform;
|
||||
QVector<AbstractEglDrmBackend*> m_backends;
|
||||
bool m_initialized = false;
|
||||
|
||||
AbstractEglDrmBackend *findBackend(int screenId, int& internalScreenId) const;
|
||||
};
|
||||
|
|
|
@ -22,12 +22,14 @@
|
|||
#include "wayland_server.h"
|
||||
#include <kwinglplatform.h>
|
||||
#include <kwingltexture.h>
|
||||
#include "drm_gpu.h"
|
||||
#include "dumb_swapchain.h"
|
||||
|
||||
#include <QOpenGLContext>
|
||||
#include <KWaylandServer/buffer_interface.h>
|
||||
#include <KWaylandServer/display.h>
|
||||
#include <KWaylandServer/eglstream_controller_interface.h>
|
||||
#include <KWaylandServer/resource.h>
|
||||
#include "drm_gpu.h"
|
||||
|
||||
namespace KWin
|
||||
{
|
||||
|
@ -250,23 +252,31 @@ void EglStreamBackend::init()
|
|||
return;
|
||||
}
|
||||
|
||||
if (!initializeEgl()) {
|
||||
setFailed("Failed to initialize EGL api");
|
||||
return;
|
||||
}
|
||||
if (!initRenderingContext()) {
|
||||
setFailed("Failed to initialize rendering context");
|
||||
return;
|
||||
}
|
||||
if (isPrimary()) {
|
||||
if (!initializeEgl()) {
|
||||
setFailed("Failed to initialize EGL api");
|
||||
return;
|
||||
}
|
||||
if (!initRenderingContext()) {
|
||||
setFailed("Failed to initialize rendering context");
|
||||
return;
|
||||
}
|
||||
|
||||
initKWinGL();
|
||||
setSupportsBufferAge(false);
|
||||
initWayland();
|
||||
initKWinGL();
|
||||
setSupportsBufferAge(false);
|
||||
initWayland();
|
||||
|
||||
using namespace KWaylandServer;
|
||||
m_eglStreamControllerInterface = new EglStreamControllerInterface(waylandServer()->display());
|
||||
connect(m_eglStreamControllerInterface, &EglStreamControllerInterface::streamConsumerAttached, this,
|
||||
&EglStreamBackend::attachStreamConsumer);
|
||||
using namespace KWaylandServer;
|
||||
m_eglStreamControllerInterface = new EglStreamControllerInterface(waylandServer()->display());
|
||||
connect(m_eglStreamControllerInterface, &EglStreamControllerInterface::streamConsumerAttached, this,
|
||||
&EglStreamBackend::attachStreamConsumer);
|
||||
} else {
|
||||
// secondary NVidia GPUs only import dumb buffers
|
||||
const auto outputs = m_gpu->outputs();
|
||||
for (DrmOutput *drmOutput : outputs) {
|
||||
addOutput(drmOutput);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool EglStreamBackend::initRenderingContext()
|
||||
|
@ -297,69 +307,80 @@ bool EglStreamBackend::resetOutput(Output &o, DrmOutput *drmOutput)
|
|||
// dumb buffer used for modesetting
|
||||
o.buffer = QSharedPointer<DrmDumbBuffer>::create(m_gpu, drmOutput->pixelSize());
|
||||
|
||||
EGLAttrib streamAttribs[] = {
|
||||
EGL_STREAM_FIFO_LENGTH_KHR, 0, // mailbox mode
|
||||
EGL_CONSUMER_AUTO_ACQUIRE_EXT, EGL_FALSE,
|
||||
EGL_NONE
|
||||
};
|
||||
EGLStreamKHR stream = pEglCreateStreamAttribNV(eglDisplay(), streamAttribs);
|
||||
if (stream == EGL_NO_STREAM_KHR) {
|
||||
qCCritical(KWIN_DRM) << "Failed to create EGL stream for output";
|
||||
return false;
|
||||
}
|
||||
|
||||
EGLAttrib outputAttribs[3];
|
||||
if (drmOutput->primaryPlane()) {
|
||||
outputAttribs[0] = EGL_DRM_PLANE_EXT;
|
||||
outputAttribs[1] = drmOutput->primaryPlane()->id();
|
||||
} else {
|
||||
outputAttribs[0] = EGL_DRM_CRTC_EXT;
|
||||
outputAttribs[1] = drmOutput->crtc()->id();
|
||||
}
|
||||
outputAttribs[2] = EGL_NONE;
|
||||
EGLint numLayers;
|
||||
EGLOutputLayerEXT outputLayer;
|
||||
pEglGetOutputLayersEXT(eglDisplay(), outputAttribs, &outputLayer, 1, &numLayers);
|
||||
if (numLayers == 0) {
|
||||
qCCritical(KWIN_DRM) << "No EGL output layers found";
|
||||
return false;
|
||||
}
|
||||
|
||||
pEglStreamConsumerOutputEXT(eglDisplay(), stream, outputLayer);
|
||||
EGLint streamProducerAttribs[] = {
|
||||
EGL_WIDTH, drmOutput->pixelSize().width(),
|
||||
EGL_HEIGHT, drmOutput->pixelSize().height(),
|
||||
EGL_NONE
|
||||
};
|
||||
EGLSurface eglSurface = pEglCreateStreamProducerSurfaceKHR(eglDisplay(), config(), stream,
|
||||
streamProducerAttribs);
|
||||
if (eglSurface == EGL_NO_SURFACE) {
|
||||
qCCritical(KWIN_DRM) << "Failed to create EGL surface for output";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (o.eglSurface != EGL_NO_SURFACE) {
|
||||
if (surface() == o.eglSurface) {
|
||||
setSurface(eglSurface);
|
||||
if (isPrimary()) {
|
||||
EGLAttrib streamAttribs[] = {
|
||||
EGL_STREAM_FIFO_LENGTH_KHR, 0, // mailbox mode
|
||||
EGL_CONSUMER_AUTO_ACQUIRE_EXT, EGL_FALSE,
|
||||
EGL_NONE
|
||||
};
|
||||
EGLStreamKHR stream = pEglCreateStreamAttribNV(eglDisplay(), streamAttribs);
|
||||
if (stream == EGL_NO_STREAM_KHR) {
|
||||
qCCritical(KWIN_DRM) << "Failed to create EGL stream for output";
|
||||
return false;
|
||||
}
|
||||
eglDestroySurface(eglDisplay(), o.eglSurface);
|
||||
}
|
||||
|
||||
if (o.eglStream != EGL_NO_STREAM_KHR) {
|
||||
pEglDestroyStreamKHR(eglDisplay(), o.eglStream);
|
||||
}
|
||||
EGLAttrib outputAttribs[3];
|
||||
if (drmOutput->primaryPlane()) {
|
||||
outputAttribs[0] = EGL_DRM_PLANE_EXT;
|
||||
outputAttribs[1] = drmOutput->primaryPlane()->id();
|
||||
} else {
|
||||
outputAttribs[0] = EGL_DRM_CRTC_EXT;
|
||||
outputAttribs[1] = drmOutput->crtc()->id();
|
||||
}
|
||||
outputAttribs[2] = EGL_NONE;
|
||||
EGLint numLayers;
|
||||
EGLOutputLayerEXT outputLayer;
|
||||
pEglGetOutputLayersEXT(eglDisplay(), outputAttribs, &outputLayer, 1, &numLayers);
|
||||
if (numLayers == 0) {
|
||||
qCCritical(KWIN_DRM) << "No EGL output layers found";
|
||||
return false;
|
||||
}
|
||||
|
||||
o.eglStream = stream;
|
||||
o.eglSurface = eglSurface;
|
||||
pEglStreamConsumerOutputEXT(eglDisplay(), stream, outputLayer);
|
||||
EGLint streamProducerAttribs[] = {
|
||||
EGL_WIDTH, drmOutput->pixelSize().width(),
|
||||
EGL_HEIGHT, drmOutput->pixelSize().height(),
|
||||
EGL_NONE
|
||||
};
|
||||
EGLSurface eglSurface = pEglCreateStreamProducerSurfaceKHR(eglDisplay(), config(), stream,
|
||||
streamProducerAttribs);
|
||||
if (eglSurface == EGL_NO_SURFACE) {
|
||||
qCCritical(KWIN_DRM) << "Failed to create EGL surface for output";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (o.eglSurface != EGL_NO_SURFACE) {
|
||||
if (surface() == o.eglSurface) {
|
||||
setSurface(eglSurface);
|
||||
}
|
||||
eglDestroySurface(eglDisplay(), o.eglSurface);
|
||||
}
|
||||
|
||||
if (o.eglStream != EGL_NO_STREAM_KHR) {
|
||||
pEglDestroyStreamKHR(eglDisplay(), o.eglStream);
|
||||
}
|
||||
|
||||
o.eglStream = stream;
|
||||
o.eglSurface = eglSurface;
|
||||
} else {
|
||||
QSize size = drmOutput->hardwareTransforms() ? drmOutput->pixelSize() : drmOutput->modeSize();
|
||||
o.dumbSwapchain = QSharedPointer<DumbSwapchain>::create(m_gpu, size);
|
||||
if (o.dumbSwapchain->isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void EglStreamBackend::addOutput(DrmOutput *drmOutput)
|
||||
bool EglStreamBackend::addOutput(DrmOutput *drmOutput)
|
||||
{
|
||||
Q_ASSERT(drmOutput->gpu() == m_gpu);
|
||||
Output o;
|
||||
if (!resetOutput(o, drmOutput)) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
if (!isPrimary() && !renderingBackend()->addOutput(drmOutput)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
connect(drmOutput, &DrmOutput::modeChanged, this,
|
||||
|
@ -376,6 +397,7 @@ void EglStreamBackend::addOutput(DrmOutput *drmOutput)
|
|||
}
|
||||
);
|
||||
m_outputs << o;
|
||||
return true;
|
||||
}
|
||||
|
||||
void EglStreamBackend::removeOutput(DrmOutput *drmOutput)
|
||||
|
@ -391,6 +413,9 @@ void EglStreamBackend::removeOutput(DrmOutput *drmOutput)
|
|||
}
|
||||
cleanupOutput(*it);
|
||||
m_outputs.erase(it);
|
||||
if (!isPrimary()) {
|
||||
renderingBackend()->removeOutput(drmOutput);
|
||||
}
|
||||
}
|
||||
|
||||
bool EglStreamBackend::makeContextCurrent(const Output &output)
|
||||
|
@ -446,16 +471,6 @@ bool EglStreamBackend::initBufferConfigs()
|
|||
return true;
|
||||
}
|
||||
|
||||
bool EglStreamBackend::presentOnOutput(EglStreamBackend::Output &o)
|
||||
{
|
||||
if (!eglSwapBuffers(eglDisplay(), o.eglSurface)) {
|
||||
qCCritical(KWIN_DRM, "eglSwapBuffers() failed: %x", eglGetError());
|
||||
return false;
|
||||
}
|
||||
|
||||
return o.output->present(o.buffer);
|
||||
}
|
||||
|
||||
PlatformSurfaceTexture *EglStreamBackend::createPlatformSurfaceTextureInternal(SurfacePixmapInternal *pixmap)
|
||||
{
|
||||
return new BasicEGLSurfaceTextureInternal(this, pixmap);
|
||||
|
@ -469,8 +484,12 @@ PlatformSurfaceTexture *EglStreamBackend::createPlatformSurfaceTextureWayland(Su
|
|||
QRegion EglStreamBackend::beginFrame(int screenId)
|
||||
{
|
||||
const Output &o = m_outputs.at(screenId);
|
||||
makeContextCurrent(o);
|
||||
return o.output->geometry();
|
||||
if (isPrimary()) {
|
||||
makeContextCurrent(o);
|
||||
return o.output->geometry();
|
||||
} else {
|
||||
return renderingBackend()->beginFrameForSecondaryGpu(o.output);
|
||||
}
|
||||
}
|
||||
|
||||
void EglStreamBackend::endFrame(int screenId, const QRegion &renderedRegion, const QRegion &damagedRegion)
|
||||
|
@ -481,18 +500,41 @@ void EglStreamBackend::endFrame(int screenId, const QRegion &renderedRegion, con
|
|||
Output &renderOutput = m_outputs[screenId];
|
||||
DrmOutput *drmOutput = renderOutput.output;
|
||||
|
||||
if (!presentOnOutput(renderOutput)) {
|
||||
RenderLoopPrivate *renderLoopPrivate = RenderLoopPrivate::get(drmOutput->renderLoop());
|
||||
renderLoopPrivate->notifyFrameFailed();
|
||||
return;
|
||||
bool frameFailed = false;
|
||||
|
||||
QSharedPointer<DrmDumbBuffer> buffer;
|
||||
if (isPrimary()) {
|
||||
buffer = renderOutput.buffer;
|
||||
if (!eglSwapBuffers(eglDisplay(), renderOutput.eglSurface)) {
|
||||
qCCritical(KWIN_DRM, "eglSwapBuffers() failed: %x", eglGetError());
|
||||
frameFailed = true;
|
||||
}
|
||||
} else {
|
||||
if (!renderingBackend()->swapBuffers(drmOutput)) {
|
||||
qCCritical(KWIN_DRM) << "swapping buffers on render backend for" << drmOutput << "failed!";
|
||||
frameFailed = true;
|
||||
}
|
||||
buffer = renderOutput.dumbSwapchain->acquireBuffer();
|
||||
if (!frameFailed && !renderingBackend()->exportFramebuffer(drmOutput, buffer->data(), buffer->size(), buffer->stride())) {
|
||||
qCCritical(KWIN_DRM) << "importing framebuffer from render backend for" << drmOutput << "failed!";
|
||||
frameFailed = true;
|
||||
}
|
||||
}
|
||||
if (!frameFailed && !renderOutput.output->present(buffer)) {
|
||||
frameFailed = true;
|
||||
}
|
||||
|
||||
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";
|
||||
if (frameFailed) {
|
||||
RenderLoopPrivate *renderLoopPrivate = RenderLoopPrivate::get(drmOutput->renderLoop());
|
||||
renderLoopPrivate->notifyFrameFailed();
|
||||
} else if (isPrimary()) {
|
||||
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";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -18,7 +18,8 @@ namespace KWin
|
|||
{
|
||||
|
||||
class DrmOutput;
|
||||
class DrmBuffer;
|
||||
class DrmDumbBuffer;
|
||||
class DumbSwapchain;
|
||||
|
||||
/**
|
||||
* @brief OpenGL Backend using Egl with an EGLDevice.
|
||||
|
@ -39,7 +40,7 @@ public:
|
|||
return m_outputs.count();
|
||||
}
|
||||
|
||||
void addOutput(DrmOutput *output) override;
|
||||
bool addOutput(DrmOutput *output) override;
|
||||
void removeOutput(DrmOutput *output) override;
|
||||
|
||||
protected:
|
||||
|
@ -61,13 +62,15 @@ private:
|
|||
struct Output
|
||||
{
|
||||
DrmOutput *output = nullptr;
|
||||
QSharedPointer<DrmBuffer> buffer;
|
||||
QSharedPointer<DrmDumbBuffer> buffer;
|
||||
EGLSurface eglSurface = EGL_NO_SURFACE;
|
||||
EGLStreamKHR eglStream = EGL_NO_STREAM_KHR;
|
||||
|
||||
// for operation as secondary GPU
|
||||
QSharedPointer<DumbSwapchain> dumbSwapchain;
|
||||
};
|
||||
bool resetOutput(Output &output, DrmOutput *drmOutput);
|
||||
bool makeContextCurrent(const Output &output);
|
||||
bool presentOnOutput(Output &output);
|
||||
void cleanupOutput(const Output &output);
|
||||
|
||||
QVector<Output> m_outputs;
|
||||
|
|
Loading…
Reference in a new issue