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:
Xaver Hugl 2023-03-21 18:27:43 +01:00
parent 7bb56eb363
commit b14f7959eb
8 changed files with 208 additions and 69 deletions

View file

@ -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

View file

@ -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;
};

View file

@ -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);

View file

@ -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;

View file

@ -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);

View file

@ -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;

View file

@ -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();
}
}

View file

@ -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;
};
}