backends/drm: add another multi gpu fallback
With the dmabuf multi-gpu path, a buffer is imported to the secondary GPU and presented directly, but importing a buffer that's usable for scanout is not possible that way on most hardware. To prevent CPU copy from being needed in those cases, this commit introduces a fallback where the buffer is imported for rendering only, and then copied to a local buffer that's presented on the screen. CCBUG: 452219 CCBUG: 465809
This commit is contained in:
parent
7bb56eb363
commit
b14f7959eb
8 changed files with 208 additions and 69 deletions
|
@ -48,11 +48,15 @@ EglGbmBackend::EglGbmBackend(DrmBackend *drmBackend)
|
|||
{
|
||||
drmBackend->setRenderBackend(this);
|
||||
setIsDirectRendering(true);
|
||||
connect(m_backend, &DrmBackend::gpuRemoved, this, [this](DrmGpu *gpu) {
|
||||
m_contexts.erase(gpu->eglDisplay());
|
||||
});
|
||||
}
|
||||
|
||||
EglGbmBackend::~EglGbmBackend()
|
||||
{
|
||||
m_backend->releaseBuffers();
|
||||
m_contexts.clear();
|
||||
cleanup();
|
||||
m_backend->setRenderBackend(nullptr);
|
||||
}
|
||||
|
@ -65,23 +69,7 @@ bool EglGbmBackend::initializeEgl()
|
|||
// Use eglGetPlatformDisplayEXT() to get the display pointer
|
||||
// if the implementation supports it.
|
||||
if (!display) {
|
||||
const bool hasMesaGBM = hasClientExtension(QByteArrayLiteral("EGL_MESA_platform_gbm"));
|
||||
const bool hasKHRGBM = hasClientExtension(QByteArrayLiteral("EGL_KHR_platform_gbm"));
|
||||
const GLenum platform = hasMesaGBM ? EGL_PLATFORM_GBM_MESA : EGL_PLATFORM_GBM_KHR;
|
||||
|
||||
if (!hasClientExtension(QByteArrayLiteral("EGL_EXT_platform_base")) || (!hasMesaGBM && !hasKHRGBM)) {
|
||||
setFailed("Missing one or more extensions between EGL_EXT_platform_base, "
|
||||
"EGL_MESA_platform_gbm, EGL_KHR_platform_gbm");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!m_backend->primaryGpu()->gbmDevice()) {
|
||||
setFailed("Could not create gbm device");
|
||||
return false;
|
||||
}
|
||||
|
||||
m_backend->primaryGpu()->setEglDisplay(EglDisplay::create(eglGetPlatformDisplayEXT(platform, m_backend->primaryGpu()->gbmDevice(), nullptr)));
|
||||
display = m_backend->primaryGpu()->eglDisplay();
|
||||
display = createEglDisplay(m_backend->primaryGpu());
|
||||
if (!display) {
|
||||
return false;
|
||||
}
|
||||
|
@ -90,6 +78,25 @@ bool EglGbmBackend::initializeEgl()
|
|||
return true;
|
||||
}
|
||||
|
||||
EglDisplay *EglGbmBackend::createEglDisplay(DrmGpu *gpu) const
|
||||
{
|
||||
const bool hasMesaGBM = hasClientExtension(QByteArrayLiteral("EGL_MESA_platform_gbm"));
|
||||
const bool hasKHRGBM = hasClientExtension(QByteArrayLiteral("EGL_KHR_platform_gbm"));
|
||||
const GLenum platform = hasMesaGBM ? EGL_PLATFORM_GBM_MESA : EGL_PLATFORM_GBM_KHR;
|
||||
|
||||
if (!hasClientExtension(QByteArrayLiteral("EGL_EXT_platform_base")) || (!hasMesaGBM && !hasKHRGBM)) {
|
||||
qCWarning(KWIN_DRM, "Missing one or more extensions between EGL_EXT_platform_base, EGL_MESA_platform_gbm, EGL_KHR_platform_gbm");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!gpu->gbmDevice()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
gpu->setEglDisplay(EglDisplay::create(eglGetPlatformDisplayEXT(platform, gpu->gbmDevice(), nullptr)));
|
||||
return gpu->eglDisplay();
|
||||
}
|
||||
|
||||
void EglGbmBackend::init()
|
||||
{
|
||||
if (!initializeEgl()) {
|
||||
|
@ -107,10 +114,29 @@ void EglGbmBackend::init()
|
|||
|
||||
bool EglGbmBackend::initRenderingContext()
|
||||
{
|
||||
return initBufferConfigs() && createContext(EGL_NO_CONFIG_KHR) && makeCurrent();
|
||||
return initBufferConfigs(eglDisplayObject()) && createContext(EGL_NO_CONFIG_KHR) && makeCurrent();
|
||||
}
|
||||
|
||||
bool EglGbmBackend::initBufferConfigs()
|
||||
EglContext *EglGbmBackend::contextForGpu(DrmGpu *gpu)
|
||||
{
|
||||
if (gpu == m_backend->primaryGpu()) {
|
||||
return contextObject();
|
||||
}
|
||||
auto display = gpu->eglDisplay();
|
||||
if (!display) {
|
||||
display = createEglDisplay(gpu);
|
||||
if (!display) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
auto &context = m_contexts[display];
|
||||
if (!context) {
|
||||
context = EglContext::create(display, EGL_NO_CONFIG_KHR, EGL_NO_CONTEXT);
|
||||
}
|
||||
return context.get();
|
||||
}
|
||||
|
||||
bool EglGbmBackend::initBufferConfigs(EglDisplay *display)
|
||||
{
|
||||
const EGLint config_attribs[] = {
|
||||
EGL_SURFACE_TYPE,
|
||||
|
@ -132,7 +158,7 @@ bool EglGbmBackend::initBufferConfigs()
|
|||
|
||||
EGLint count;
|
||||
EGLConfig configs[1024];
|
||||
if (!eglChooseConfig(eglDisplay(), config_attribs, configs,
|
||||
if (!eglChooseConfig(display->handle(), config_attribs, configs,
|
||||
sizeof(configs) / sizeof(EGLConfig),
|
||||
&count)) {
|
||||
qCCritical(KWIN_DRM) << "eglChooseConfig failed:" << getEglErrorString();
|
||||
|
@ -140,36 +166,37 @@ bool EglGbmBackend::initBufferConfigs()
|
|||
}
|
||||
|
||||
// Loop through all configs, choosing the first one that has suitable format.
|
||||
auto &formats = m_formats[display];
|
||||
for (EGLint i = 0; i < count; i++) {
|
||||
EGLint gbmFormat;
|
||||
eglGetConfigAttrib(eglDisplay(), configs[i], EGL_NATIVE_VISUAL_ID, &gbmFormat);
|
||||
eglGetConfigAttrib(display->handle(), configs[i], EGL_NATIVE_VISUAL_ID, &gbmFormat);
|
||||
|
||||
GbmFormat format;
|
||||
format.drmFormat = gbmFormat;
|
||||
EGLint red, green, blue;
|
||||
// Query number of bits for color channel
|
||||
eglGetConfigAttrib(eglDisplay(), configs[i], EGL_RED_SIZE, &red);
|
||||
eglGetConfigAttrib(eglDisplay(), configs[i], EGL_GREEN_SIZE, &green);
|
||||
eglGetConfigAttrib(eglDisplay(), configs[i], EGL_BLUE_SIZE, &blue);
|
||||
eglGetConfigAttrib(eglDisplay(), configs[i], EGL_ALPHA_SIZE, &format.alphaSize);
|
||||
eglGetConfigAttrib(display->handle(), configs[i], EGL_RED_SIZE, &red);
|
||||
eglGetConfigAttrib(display->handle(), configs[i], EGL_GREEN_SIZE, &green);
|
||||
eglGetConfigAttrib(display->handle(), configs[i], EGL_BLUE_SIZE, &blue);
|
||||
eglGetConfigAttrib(display->handle(), configs[i], EGL_ALPHA_SIZE, &format.alphaSize);
|
||||
format.bpp = red + green + blue;
|
||||
if (m_formats.contains(gbmFormat)) {
|
||||
if (formats.contains(gbmFormat)) {
|
||||
continue;
|
||||
}
|
||||
m_formats[gbmFormat] = format;
|
||||
formats[gbmFormat] = format;
|
||||
}
|
||||
if (!m_formats.isEmpty()) {
|
||||
if (!formats.isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
qCCritical(KWIN_DRM, "Choosing EGL config did not return a supported config. There were %u configs", count);
|
||||
for (EGLint i = 0; i < count; i++) {
|
||||
EGLint gbmFormat, blueSize, redSize, greenSize, alphaSize;
|
||||
eglGetConfigAttrib(eglDisplay(), configs[i], EGL_NATIVE_VISUAL_ID, &gbmFormat);
|
||||
eglGetConfigAttrib(eglDisplay(), configs[i], EGL_RED_SIZE, &redSize);
|
||||
eglGetConfigAttrib(eglDisplay(), configs[i], EGL_GREEN_SIZE, &greenSize);
|
||||
eglGetConfigAttrib(eglDisplay(), configs[i], EGL_BLUE_SIZE, &blueSize);
|
||||
eglGetConfigAttrib(eglDisplay(), configs[i], EGL_ALPHA_SIZE, &alphaSize);
|
||||
eglGetConfigAttrib(display->handle(), configs[i], EGL_NATIVE_VISUAL_ID, &gbmFormat);
|
||||
eglGetConfigAttrib(display->handle(), configs[i], EGL_RED_SIZE, &redSize);
|
||||
eglGetConfigAttrib(display->handle(), configs[i], EGL_GREEN_SIZE, &greenSize);
|
||||
eglGetConfigAttrib(display->handle(), configs[i], EGL_BLUE_SIZE, &blueSize);
|
||||
eglGetConfigAttrib(display->handle(), configs[i], EGL_ALPHA_SIZE, &alphaSize);
|
||||
gbm_format_name_desc name;
|
||||
gbm_format_get_name(gbmFormat, &name);
|
||||
qCCritical(KWIN_DRM, "EGL config %d has format %s with %d,%d,%d,%d bits for r,g,b,a", i, name.name, redSize, greenSize, blueSize, alphaSize);
|
||||
|
@ -210,9 +237,18 @@ std::shared_ptr<GLTexture> EglGbmBackend::textureForOutput(Output *output) const
|
|||
|
||||
std::optional<GbmFormat> EglGbmBackend::gbmFormatForDrmFormat(uint32_t format) const
|
||||
{
|
||||
// TODO use a hardcoded lookup table where needed instead?
|
||||
const auto it = m_formats.constFind(format);
|
||||
return it == m_formats.constEnd() ? std::optional<GbmFormat>() : *it;
|
||||
const auto it = m_formats.find(eglDisplayObject());
|
||||
if (it == m_formats.end()) {
|
||||
return std::nullopt;
|
||||
} else {
|
||||
const auto &formats = *it;
|
||||
const auto formatIt = formats.find(format);
|
||||
if (formatIt == formats.end()) {
|
||||
return std::nullopt;
|
||||
} else {
|
||||
return *formatIt;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool EglGbmBackend::prefer10bpc() const
|
||||
|
@ -254,13 +290,7 @@ EGLImageKHR EglGbmBackend::importBufferObjectAsImage(gbm_bo *bo)
|
|||
|
||||
std::shared_ptr<GLTexture> EglGbmBackend::importBufferObjectAsTexture(gbm_bo *bo)
|
||||
{
|
||||
EGLImageKHR image = importBufferObjectAsImage(bo);
|
||||
if (image != EGL_NO_IMAGE_KHR) {
|
||||
return std::make_shared<EGLImageTexture>(eglDisplay(), image, GL_RGBA8, QSize(gbm_bo_get_width(bo), gbm_bo_get_height(bo)));
|
||||
} else {
|
||||
qCWarning(KWIN_DRM) << "Failed to record frame: Error creating EGLImageKHR - " << getEglErrorString();
|
||||
return nullptr;
|
||||
}
|
||||
return importDmaBufAsTexture(dmaBufAttributesForBo(bo));
|
||||
}
|
||||
|
||||
} // namespace KWin
|
||||
|
|
|
@ -73,20 +73,22 @@ public:
|
|||
|
||||
std::shared_ptr<GLTexture> textureForOutput(Output *requestedOutput) const override;
|
||||
|
||||
std::shared_ptr<DrmBuffer> testBuffer(DrmAbstractOutput *output);
|
||||
std::optional<GbmFormat> gbmFormatForDrmFormat(uint32_t format) const;
|
||||
DrmGpu *gpu() const;
|
||||
|
||||
EGLImageKHR importBufferObjectAsImage(gbm_bo *bo);
|
||||
std::shared_ptr<GLTexture> importBufferObjectAsTexture(gbm_bo *bo);
|
||||
EglContext *contextForGpu(DrmGpu *gpu);
|
||||
|
||||
private:
|
||||
bool initializeEgl();
|
||||
bool initBufferConfigs();
|
||||
bool initBufferConfigs(EglDisplay *display);
|
||||
bool initRenderingContext();
|
||||
EglDisplay *createEglDisplay(DrmGpu *gpu) const;
|
||||
|
||||
DrmBackend *m_backend;
|
||||
QHash<uint32_t, GbmFormat> m_formats;
|
||||
std::map<EglDisplay *, std::unique_ptr<EglContext>> m_contexts;
|
||||
QHash<EglDisplay *, QHash<uint32_t, GbmFormat>> m_formats;
|
||||
|
||||
friend class EglGbmTexture;
|
||||
};
|
||||
|
|
|
@ -65,7 +65,7 @@ std::optional<OutputLayerBeginFrameInfo> EglGbmLayerSurface::startRendering(cons
|
|||
if (!checkSurface(bufferSize, formats)) {
|
||||
return std::nullopt;
|
||||
}
|
||||
if (eglMakeCurrent(m_eglBackend->eglDisplay(), EGL_NO_SURFACE, EGL_NO_SURFACE, m_eglBackend->context()) != EGL_TRUE) {
|
||||
if (!m_eglBackend->contextObject()->makeCurrent()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
|
@ -89,7 +89,6 @@ std::optional<OutputLayerBeginFrameInfo> EglGbmLayerSurface::startRendering(cons
|
|||
}
|
||||
}
|
||||
m_surface.currentBuffer = buffer;
|
||||
m_surface.texture = texture;
|
||||
|
||||
return OutputLayerBeginFrameInfo{
|
||||
.renderTarget = RenderTarget(fbo.get()),
|
||||
|
@ -127,7 +126,7 @@ bool EglGbmLayerSurface::doesSurfaceFit(const QSize &size, const QMap<uint32_t,
|
|||
|
||||
std::shared_ptr<GLTexture> EglGbmLayerSurface::texture() const
|
||||
{
|
||||
return m_surface.texture;
|
||||
return m_surface.textureCache[m_surface.currentBuffer->bo()].first;
|
||||
}
|
||||
|
||||
std::shared_ptr<DrmFramebuffer> EglGbmLayerSurface::renderTestBuffer(const QSize &bufferSize, const QMap<uint32_t, QVector<uint64_t>> &formats)
|
||||
|
@ -216,6 +215,10 @@ std::optional<EglGbmLayerSurface::Surface> EglGbmLayerSurface::createSurface(con
|
|||
qCDebug(KWIN_DRM) << "chose linear dmabuf import with format" << formatName(surface->gbmSwapchain->format()).name << "and modifier" << surface->gbmSwapchain->modifier();
|
||||
return surface;
|
||||
}
|
||||
if (const auto surface = doTestFormats(formats, MultiGpuImportMode::Egl)) {
|
||||
qCDebug(KWIN_DRM) << "chose egl import with format" << formatName(surface->gbmSwapchain->format()).name << "and modifier" << surface->gbmSwapchain->modifier();
|
||||
return surface;
|
||||
}
|
||||
if (const auto surface = doTestFormats(formats, MultiGpuImportMode::DumbBuffer)) {
|
||||
qCDebug(KWIN_DRM) << "chose cpu import with format" << formatName(surface->gbmSwapchain->format()).name << "and modifier" << surface->gbmSwapchain->modifier();
|
||||
return surface;
|
||||
|
@ -234,16 +237,29 @@ std::optional<EglGbmLayerSurface::Surface> EglGbmLayerSurface::createSurface(con
|
|||
|
||||
std::optional<EglGbmLayerSurface::Surface> EglGbmLayerSurface::createSurface(const QSize &size, uint32_t format, const QVector<uint64_t> &modifiers, MultiGpuImportMode importMode) const
|
||||
{
|
||||
QVector<uint64_t> renderModifiers = modifiers;
|
||||
if (importMode == MultiGpuImportMode::Egl) {
|
||||
const auto context = m_eglBackend->contextForGpu(m_gpu);
|
||||
if (!context || context->isSoftwareRenderer()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
renderModifiers = context->displayObject()->supportedDrmFormats()[format];
|
||||
}
|
||||
Surface ret;
|
||||
ret.importMode = importMode;
|
||||
ret.forceLinear = importMode == MultiGpuImportMode::DumbBuffer || importMode == MultiGpuImportMode::LinearDmabuf || m_bufferTarget != BufferTarget::Normal;
|
||||
ret.gbmSwapchain = createGbmSwapchain(size, format, modifiers, ret.forceLinear);
|
||||
ret.gbmSwapchain = createGbmSwapchain(m_eglBackend->gpu(), size, format, renderModifiers, ret.forceLinear);
|
||||
if (!ret.gbmSwapchain) {
|
||||
return std::nullopt;
|
||||
}
|
||||
if (importMode == MultiGpuImportMode::DumbBuffer || m_bufferTarget == BufferTarget::Dumb) {
|
||||
ret.importSwapchain = std::make_shared<DumbSwapchain>(m_gpu, size, format);
|
||||
if (ret.importSwapchain->isEmpty()) {
|
||||
ret.importDumbSwapchain = std::make_shared<DumbSwapchain>(m_gpu, size, format);
|
||||
if (ret.importDumbSwapchain->isEmpty()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
} else if (importMode == MultiGpuImportMode::Egl) {
|
||||
ret.importGbmSwapchain = createGbmSwapchain(m_gpu, size, format, modifiers, false);
|
||||
if (!ret.importGbmSwapchain) {
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
|
@ -253,17 +269,17 @@ std::optional<EglGbmLayerSurface::Surface> EglGbmLayerSurface::createSurface(con
|
|||
return ret;
|
||||
}
|
||||
|
||||
std::shared_ptr<GbmSwapchain> EglGbmLayerSurface::createGbmSwapchain(const QSize &size, uint32_t format, const QVector<uint64_t> &modifiers, bool forceLinear) const
|
||||
std::shared_ptr<GbmSwapchain> EglGbmLayerSurface::createGbmSwapchain(DrmGpu *gpu, const QSize &size, uint32_t format, const QVector<uint64_t> &modifiers, bool forceLinear) const
|
||||
{
|
||||
static bool modifiersEnvSet = false;
|
||||
static const bool modifiersEnv = qEnvironmentVariableIntValue("KWIN_DRM_USE_MODIFIERS", &modifiersEnvSet) != 0;
|
||||
bool allowModifiers = m_gpu->addFB2ModifiersSupported() && (!modifiersEnvSet || (modifiersEnvSet && modifiersEnv)) && !modifiers.isEmpty();
|
||||
bool allowModifiers = gpu->addFB2ModifiersSupported() && (!modifiersEnvSet || (modifiersEnvSet && modifiersEnv)) && !modifiers.isEmpty();
|
||||
#if !HAVE_GBM_BO_GET_FD_FOR_PLANE
|
||||
allowModifiers &= m_gpu == m_eglBackend->gpu();
|
||||
allowModifiers &= m_gpu == gpu;
|
||||
#endif
|
||||
|
||||
if (allowModifiers) {
|
||||
const auto ret = GbmSwapchain::createSwapchain(m_eglBackend->gpu(), size, format, forceLinear ? linearModifier : modifiers);
|
||||
const auto ret = GbmSwapchain::createSwapchain(gpu, size, format, forceLinear ? linearModifier : modifiers);
|
||||
if (const auto surface = std::get_if<std::shared_ptr<GbmSwapchain>>(&ret)) {
|
||||
return *surface;
|
||||
} else if (std::get<GbmSwapchain::Error>(ret) != GbmSwapchain::Error::ModifiersUnsupported) {
|
||||
|
@ -271,13 +287,13 @@ std::shared_ptr<GbmSwapchain> EglGbmLayerSurface::createGbmSwapchain(const QSize
|
|||
}
|
||||
}
|
||||
uint32_t gbmFlags = GBM_BO_USE_RENDERING;
|
||||
if (m_gpu == m_eglBackend->gpu()) {
|
||||
if (m_gpu == gpu) {
|
||||
gbmFlags |= GBM_BO_USE_SCANOUT;
|
||||
}
|
||||
if (forceLinear || m_gpu != m_eglBackend->gpu()) {
|
||||
if (forceLinear || m_gpu != gpu) {
|
||||
gbmFlags |= GBM_BO_USE_LINEAR;
|
||||
}
|
||||
const auto ret = GbmSwapchain::createSwapchain(m_eglBackend->gpu(), size, format, gbmFlags);
|
||||
const auto ret = GbmSwapchain::createSwapchain(gpu, size, format, gbmFlags);
|
||||
const auto swapchain = std::get_if<std::shared_ptr<GbmSwapchain>>(&ret);
|
||||
return swapchain ? *swapchain : nullptr;
|
||||
}
|
||||
|
@ -301,6 +317,8 @@ std::shared_ptr<DrmFramebuffer> EglGbmLayerSurface::importBuffer(Surface &surfac
|
|||
{
|
||||
if (m_bufferTarget == BufferTarget::Dumb || surface.importMode == MultiGpuImportMode::DumbBuffer) {
|
||||
return importWithCpu(surface, sourceBuffer.get());
|
||||
} else if (surface.importMode == MultiGpuImportMode::Egl) {
|
||||
return importWithEgl(surface, sourceBuffer.get());
|
||||
} else if (m_gpu != m_eglBackend->gpu()) {
|
||||
return importDmabuf(sourceBuffer.get());
|
||||
} else {
|
||||
|
@ -326,14 +344,73 @@ std::shared_ptr<DrmFramebuffer> EglGbmLayerSurface::importDmabuf(GbmBuffer *sour
|
|||
return ret;
|
||||
}
|
||||
|
||||
std::shared_ptr<DrmFramebuffer> EglGbmLayerSurface::importWithEgl(Surface &surface, GbmBuffer *sourceBuffer) const
|
||||
{
|
||||
Q_ASSERT(surface.importGbmSwapchain);
|
||||
|
||||
const auto context = m_eglBackend->contextForGpu(m_gpu);
|
||||
if (!context || context->isSoftwareRenderer()) {
|
||||
return nullptr;
|
||||
}
|
||||
context->makeCurrent();
|
||||
auto &sourceTexture = surface.importedTextureCache[sourceBuffer->bo()];
|
||||
if (!sourceTexture) {
|
||||
sourceTexture = context->importDmaBufAsTexture(dmaBufAttributesForBo(sourceBuffer->bo()));
|
||||
}
|
||||
if (!sourceTexture) {
|
||||
qCWarning(KWIN_DRM, "failed to import the source texture!");
|
||||
return nullptr;
|
||||
}
|
||||
const auto [localBuffer, repaint] = surface.importGbmSwapchain->acquire();
|
||||
auto &[texture, fbo] = surface.importTextureCache[localBuffer->bo()];
|
||||
if (!texture) {
|
||||
texture = context->importDmaBufAsTexture(dmaBufAttributesForBo(localBuffer->bo()));
|
||||
if (!texture) {
|
||||
qCWarning(KWIN_DRM, "failed to import the local texture!");
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
if (!fbo) {
|
||||
fbo = std::make_shared<GLFramebuffer>(texture.get());
|
||||
if (!fbo->valid()) {
|
||||
qCWarning(KWIN_DRM, "failed to create the fbo!");
|
||||
fbo.reset();
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, fbo->handle());
|
||||
glViewport(0, 0, fbo->size().width(), fbo->size().height());
|
||||
glClearColor(0, 1, 0, 0);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
|
||||
const auto shader = context->shaderManager()->pushShader(ShaderTrait::MapTexture);
|
||||
QMatrix4x4 mat;
|
||||
mat.scale(1, -1);
|
||||
mat.ortho(QRect(QPoint(), fbo->size()));
|
||||
shader->setUniform(GLShader::ModelViewProjectionMatrix, mat);
|
||||
|
||||
sourceTexture->bind();
|
||||
sourceTexture->render(fbo->size(), 1);
|
||||
sourceTexture->unbind();
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
|
||||
context->shaderManager()->popShader();
|
||||
glFlush();
|
||||
// restore the old context
|
||||
context->doneCurrent();
|
||||
m_eglBackend->makeCurrent();
|
||||
return DrmFramebuffer::createFramebuffer(localBuffer);
|
||||
}
|
||||
|
||||
std::shared_ptr<DrmFramebuffer> EglGbmLayerSurface::importWithCpu(Surface &surface, GbmBuffer *sourceBuffer) const
|
||||
{
|
||||
Q_ASSERT(surface.importSwapchain && !surface.importSwapchain->isEmpty());
|
||||
Q_ASSERT(surface.importDumbSwapchain && !surface.importDumbSwapchain->isEmpty());
|
||||
if (!sourceBuffer->map(GBM_BO_TRANSFER_READ)) {
|
||||
qCWarning(KWIN_DRM, "mapping a %s gbm_bo failed: %s", formatName(sourceBuffer->format()).name, strerror(errno));
|
||||
return nullptr;
|
||||
}
|
||||
const auto importBuffer = surface.importSwapchain->acquireBuffer();
|
||||
const auto importBuffer = surface.importDumbSwapchain->acquireBuffer();
|
||||
if (sourceBuffer->planeCount() != 1 || sourceBuffer->strides()[0] != importBuffer->strides()[0]) {
|
||||
qCCritical(KWIN_DRM, "stride of gbm_bo (%d) and dumb buffer (%d) with format %s don't match!",
|
||||
sourceBuffer->strides()[0], importBuffer->strides()[0], formatName(sourceBuffer->format()).name);
|
||||
|
|
|
@ -69,13 +69,16 @@ private:
|
|||
enum class MultiGpuImportMode {
|
||||
Dmabuf,
|
||||
LinearDmabuf,
|
||||
Egl,
|
||||
DumbBuffer
|
||||
};
|
||||
struct Surface
|
||||
{
|
||||
std::shared_ptr<GbmSwapchain> gbmSwapchain;
|
||||
std::shared_ptr<GLTexture> texture;
|
||||
std::shared_ptr<DumbSwapchain> importSwapchain;
|
||||
std::shared_ptr<DumbSwapchain> importDumbSwapchain;
|
||||
std::shared_ptr<GbmSwapchain> importGbmSwapchain;
|
||||
QHash<gbm_bo *, std::shared_ptr<GLTexture>> importedTextureCache;
|
||||
QHash<gbm_bo *, std::pair<std::shared_ptr<GLTexture>, std::shared_ptr<GLFramebuffer>>> importTextureCache;
|
||||
MultiGpuImportMode importMode;
|
||||
std::shared_ptr<GbmBuffer> currentBuffer;
|
||||
std::shared_ptr<DrmFramebuffer> currentFramebuffer;
|
||||
|
@ -86,11 +89,12 @@ private:
|
|||
bool doesSurfaceFit(const Surface &surface, const QSize &size, const QMap<uint32_t, QVector<uint64_t>> &formats) const;
|
||||
std::optional<Surface> createSurface(const QSize &size, const QMap<uint32_t, QVector<uint64_t>> &formats) const;
|
||||
std::optional<Surface> createSurface(const QSize &size, uint32_t format, const QVector<uint64_t> &modifiers, MultiGpuImportMode importMode) const;
|
||||
std::shared_ptr<GbmSwapchain> createGbmSwapchain(const QSize &size, uint32_t format, const QVector<uint64_t> &modifiers, bool forceLinear) const;
|
||||
std::shared_ptr<GbmSwapchain> createGbmSwapchain(DrmGpu *gpu, const QSize &size, uint32_t format, const QVector<uint64_t> &modifiers, bool forceLinear) const;
|
||||
|
||||
std::shared_ptr<DrmFramebuffer> doRenderTestBuffer(Surface &surface) const;
|
||||
std::shared_ptr<DrmFramebuffer> importBuffer(Surface &surface, const std::shared_ptr<GbmBuffer> &sourceBuffer) const;
|
||||
std::shared_ptr<DrmFramebuffer> importDmabuf(GbmBuffer *sourceBuffer) const;
|
||||
std::shared_ptr<DrmFramebuffer> importWithEgl(Surface &surface, GbmBuffer *sourceBuffer) const;
|
||||
std::shared_ptr<DrmFramebuffer> importWithCpu(Surface &surface, GbmBuffer *sourceBuffer) const;
|
||||
|
||||
Surface m_surface;
|
||||
|
|
|
@ -506,6 +506,11 @@ void Compositor::stop()
|
|||
disconnect(workspace(), &Workspace::outputRemoved, this, &Compositor::removeOutput);
|
||||
}
|
||||
|
||||
if (m_backend->compositingType() == OpenGLCompositing) {
|
||||
// some layers need a context current for destruction
|
||||
static_cast<OpenGLBackend *>(m_backend.get())->makeCurrent();
|
||||
}
|
||||
|
||||
const auto superlayers = m_superlayers;
|
||||
for (auto it = superlayers.begin(); it != superlayers.end(); ++it) {
|
||||
removeSuperLayer(*it);
|
||||
|
|
|
@ -194,6 +194,7 @@ Q_DECLARE_FLAGS(ShaderTraits, ShaderTrait)
|
|||
class KWINGLUTILS_EXPORT ShaderManager
|
||||
{
|
||||
public:
|
||||
explicit ShaderManager();
|
||||
~ShaderManager();
|
||||
|
||||
/**
|
||||
|
@ -295,8 +296,6 @@ public:
|
|||
static void cleanup();
|
||||
|
||||
private:
|
||||
ShaderManager();
|
||||
|
||||
void bindFragDataLocations(GLShader *shader);
|
||||
void bindAttributeLocations(GLShader *shader) const;
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include "egldisplay.h"
|
||||
#include "kwineglimagetexture.h"
|
||||
#include "kwineglutils_p.h"
|
||||
#include "kwinglutils.h"
|
||||
#include "utils/common.h"
|
||||
#include "utils/egl_context_attribute_builder.h"
|
||||
|
||||
|
@ -23,6 +24,7 @@ std::unique_ptr<EglContext> EglContext::create(EglDisplay *display, EGLConfig co
|
|||
{
|
||||
auto context = createContext(display, config, sharedContext);
|
||||
if (context) {
|
||||
eglMakeCurrent(display->handle(), EGL_NO_SURFACE, EGL_NO_SURFACE, context);
|
||||
return std::make_unique<EglContext>(display, config, context);
|
||||
} else {
|
||||
return nullptr;
|
||||
|
@ -33,11 +35,23 @@ EglContext::EglContext(EglDisplay *display, EGLConfig config, ::EGLContext conte
|
|||
: m_display(display)
|
||||
, m_handle(context)
|
||||
, m_config(config)
|
||||
, m_shaderManager(std::make_unique<ShaderManager>())
|
||||
{
|
||||
// It is not legal to not have a vertex array object bound in a core context
|
||||
// to make code handling old and new OpenGL versions easier, bind a dummy vao that's used for everything
|
||||
if (!isOpenglES() && hasOpenglExtension(QByteArrayLiteral("GL_ARB_vertex_array_object"))) {
|
||||
makeCurrent();
|
||||
glGenVertexArrays(1, &m_vao);
|
||||
glBindVertexArray(m_vao);
|
||||
}
|
||||
}
|
||||
|
||||
EglContext::~EglContext()
|
||||
{
|
||||
if (m_vao) {
|
||||
makeCurrent();
|
||||
glDeleteVertexArrays(1, &m_vao);
|
||||
}
|
||||
doneCurrent();
|
||||
eglDestroyContext(m_display->handle(), m_handle);
|
||||
}
|
||||
|
@ -182,4 +196,8 @@ std::shared_ptr<GLTexture> EglContext::importDmaBufAsTexture(const DmaBufAttribu
|
|||
}
|
||||
}
|
||||
|
||||
ShaderManager *EglContext::shaderManager() const
|
||||
{
|
||||
return m_shaderManager.get();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@ namespace KWin
|
|||
{
|
||||
|
||||
class EglDisplay;
|
||||
class ShaderManager;
|
||||
|
||||
class KWIN_EXPORT EglContext : public OpenGlContext
|
||||
{
|
||||
|
@ -36,15 +37,18 @@ public:
|
|||
::EGLContext handle() const;
|
||||
EGLConfig config() const;
|
||||
bool isValid() const;
|
||||
ShaderManager *shaderManager() const;
|
||||
|
||||
static std::unique_ptr<EglContext> create(EglDisplay *display, EGLConfig config, ::EGLContext sharedContext);
|
||||
|
||||
private:
|
||||
static ::EGLContext createContext(EglDisplay *display, EGLConfig config, ::EGLContext sharedContext);
|
||||
|
||||
EglDisplay *m_display = nullptr;
|
||||
::EGLContext m_handle = EGL_NO_CONTEXT;
|
||||
EGLConfig m_config = EGL_NO_CONFIG_KHR;
|
||||
EglDisplay *const m_display;
|
||||
const ::EGLContext m_handle;
|
||||
const EGLConfig m_config;
|
||||
const std::unique_ptr<ShaderManager> m_shaderManager;
|
||||
uint32_t m_vao = 0;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue