From 572bc75de4d49add94b0336e994cb06621dd913b Mon Sep 17 00:00:00 2001 From: Xaver Hugl Date: Mon, 15 May 2023 01:03:26 +0200 Subject: [PATCH] libkwineffects: handle GLTexture allocation failures This is required for properly dealing with GPU resets --- src/backends/drm/drm_egl_layer_surface.cpp | 5 +- .../x11/windowed/x11_windowed_egl_backend.cpp | 5 +- src/libkwineffects/kwineglimagetexture.cpp | 28 ++++-- src/libkwineffects/kwineglimagetexture.h | 5 +- src/libkwineffects/kwingltexture.cpp | 94 +++++++++---------- src/libkwineffects/kwingltexture.h | 6 +- src/libkwineffects/kwinoffscreeneffect.cpp | 5 +- src/main.cpp | 11 ++- .../scenes/opengl/eglcontext.cpp | 4 +- src/plugins/backgroundcontrast/contrast.cpp | 15 +-- src/plugins/blur/blur.cpp | 4 +- src/plugins/magnifier/magnifier.cpp | 10 +- .../screencast/regionscreencastsource.cpp | 5 +- src/plugins/screencast/screencastutils.h | 9 +- .../screencast/windowscreencastsource.cpp | 9 +- src/plugins/screenshot/screenshot.cpp | 16 +++- .../screentransform/screentransform.cpp | 12 ++- src/plugins/zoom/zoom.cpp | 8 +- src/scene/cursordelegate_opengl.cpp | 5 +- src/scene/workspacescene_opengl.cpp | 7 +- src/scripting/windowthumbnailitem.cpp | 5 +- 21 files changed, 165 insertions(+), 103 deletions(-) diff --git a/src/backends/drm/drm_egl_layer_surface.cpp b/src/backends/drm/drm_egl_layer_surface.cpp index ea086ec938..e6e23d02b7 100644 --- a/src/backends/drm/drm_egl_layer_surface.cpp +++ b/src/backends/drm/drm_egl_layer_surface.cpp @@ -104,7 +104,10 @@ std::optional EglGbmLayerSurface::startRendering(cons } if (enableColormanagement) { if (!m_surface.shadowBuffer) { - m_surface.shadowTexture = std::make_shared(GL_RGBA16F, m_surface.gbmSwapchain->size()); + m_surface.shadowTexture = GLTexture::allocate(GL_RGBA16F, m_surface.gbmSwapchain->size()); + if (!m_surface.shadowTexture) { + return std::nullopt; + } m_surface.shadowBuffer = std::make_shared(m_surface.shadowTexture.get()); } return OutputLayerBeginFrameInfo{ diff --git a/src/backends/x11/windowed/x11_windowed_egl_backend.cpp b/src/backends/x11/windowed/x11_windowed_egl_backend.cpp index 1f343d5931..9708ba4847 100644 --- a/src/backends/x11/windowed/x11_windowed_egl_backend.cpp +++ b/src/backends/x11/windowed/x11_windowed_egl_backend.cpp @@ -205,7 +205,10 @@ std::optional X11WindowedEglCursorLayer::beginFrame() const auto tmp = size().expandedTo(QSize(64, 64)); const QSize bufferSize(std::ceil(tmp.width()), std::ceil(tmp.height())); if (!m_texture || m_texture->size() != bufferSize) { - m_texture = std::make_unique(GL_RGBA8, bufferSize); + m_texture = GLTexture::allocate(GL_RGBA8, bufferSize); + if (!m_texture) { + return std::nullopt; + } m_framebuffer = std::make_unique(m_texture.get()); } diff --git a/src/libkwineffects/kwineglimagetexture.cpp b/src/libkwineffects/kwineglimagetexture.cpp index 841f98e8e8..86ec9097c3 100644 --- a/src/libkwineffects/kwineglimagetexture.cpp +++ b/src/libkwineffects/kwineglimagetexture.cpp @@ -8,6 +8,7 @@ */ #include "libkwineffects/kwineglimagetexture.h" +#include "libkwineffects/kwingltexture_p.h" #include #include @@ -15,18 +16,13 @@ namespace KWin { -EGLImageTexture::EGLImageTexture(::EGLDisplay display, EGLImage image, int internalFormat, const QSize &size) - : GLTexture(internalFormat, size, 1, true) +EGLImageTexture::EGLImageTexture(::EGLDisplay display, EGLImage image, uint textureId, int internalFormat, const QSize &size) + : GLTexture(textureId, internalFormat, size, 1, true) , m_image(image) , m_display(display) { - if (m_image == EGL_NO_IMAGE_KHR) { - return; - } - + d_ptr->m_foreign = false; setContentTransform(TextureTransform::MirrorY); - bind(); - glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, m_image); } EGLImageTexture::~EGLImageTexture() @@ -34,4 +30,20 @@ EGLImageTexture::~EGLImageTexture() eglDestroyImageKHR(m_display, m_image); } +std::shared_ptr EGLImageTexture::create(::EGLDisplay display, EGLImageKHR image, int internalFormat, const QSize &size) +{ + if (image == EGL_NO_IMAGE) { + return nullptr; + } + GLuint texture = 0; + glGenTextures(1, &texture); + if (!texture) { + return nullptr; + } + glBindTexture(GL_TEXTURE_2D, texture); + glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, image); + glBindTexture(GL_TEXTURE_2D, 0); + return std::make_shared(display, image, texture, internalFormat, size); +} + } // namespace KWin diff --git a/src/libkwineffects/kwineglimagetexture.h b/src/libkwineffects/kwineglimagetexture.h index db825571df..c9da5d41d1 100644 --- a/src/libkwineffects/kwineglimagetexture.h +++ b/src/libkwineffects/kwineglimagetexture.h @@ -22,10 +22,11 @@ namespace KWin class KWINGLUTILS_EXPORT EGLImageTexture : public GLTexture { public: - EGLImageTexture(::EGLDisplay display, EGLImageKHR image, int internalFormat, const QSize &size); + explicit EGLImageTexture(::EGLDisplay display, EGLImageKHR image, uint textureId, int internalFormat, const QSize &size); ~EGLImageTexture() override; -private: + static std::shared_ptr create(::EGLDisplay display, EGLImageKHR image, int internalFormat, const QSize &size); + EGLImageKHR m_image; ::EGLDisplay m_display; }; diff --git a/src/libkwineffects/kwingltexture.cpp b/src/libkwineffects/kwingltexture.cpp index 89ad1dcbaf..865e5a8050 100644 --- a/src/libkwineffects/kwingltexture.cpp +++ b/src/libkwineffects/kwingltexture.cpp @@ -9,13 +9,13 @@ SPDX-License-Identifier: GPL-2.0-or-later */ +#include "kwingltexture_p.h" #include "libkwineffects/kwinconfig.h" // KWIN_HAVE_OPENGL #include "libkwineffects/kwineffects.h" #include "libkwineffects/kwinglplatform.h" #include "libkwineffects/kwinglutils.h" #include "libkwineffects/kwinglutils_funcs.h" - -#include "kwingltexture_p.h" +#include "logging_p.h" #include #include @@ -185,56 +185,7 @@ GLTexture::GLTexture(const QString &fileName) { } -GLTexture::GLTexture(GLenum internalFormat, int width, int height, int levels, bool needsMutability) - : d_ptr(new GLTexturePrivate()) -{ - Q_D(GLTexture); - - d->m_target = GL_TEXTURE_2D; - d->m_scale.setWidth(1.0 / width); - d->m_scale.setHeight(1.0 / height); - d->m_size = QSize(width, height); - d->m_canUseMipmaps = levels > 1; - d->m_mipLevels = levels; - d->m_filter = levels > 1 ? GL_NEAREST_MIPMAP_LINEAR : GL_NEAREST; - - d->updateMatrix(); - - create(); - bind(); - - if (!GLPlatform::instance()->isGLES()) { - if (d->s_supportsTextureStorage && !needsMutability) { - glTexStorage2D(d->m_target, levels, internalFormat, width, height); - d->m_immutable = true; - } else { - glTexParameteri(d->m_target, GL_TEXTURE_MAX_LEVEL, levels - 1); - glTexImage2D(d->m_target, 0, internalFormat, width, height, 0, - GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, nullptr); - } - d->m_internalFormat = internalFormat; - } else { - // The format parameter in glTexSubImage() must match the internal format - // of the texture, so it's important that we allocate the texture with - // the format that will be used in update() and clear(). - const GLenum format = d->s_supportsARGB32 ? GL_BGRA_EXT : GL_RGBA; - glTexImage2D(d->m_target, 0, format, width, height, 0, - format, GL_UNSIGNED_BYTE, nullptr); - - // This is technically not true, but it means that code that calls - // internalFormat() won't need to be specialized for GLES2. - d->m_internalFormat = GL_RGBA8; - } - - unbind(); -} - -GLTexture::GLTexture(GLenum internalFormat, const QSize &size, int levels, bool needsMutability) - : GLTexture(internalFormat, size.width(), size.height(), levels, needsMutability) -{ -} - -GLTexture::GLTexture(GLuint textureId, GLenum internalFormat, const QSize &size, int levels) +GLTexture::GLTexture(GLuint textureId, GLenum internalFormat, const QSize &size, int levels, bool isImmutable) : d_ptr(new GLTexturePrivate()) { Q_D(GLTexture); @@ -248,6 +199,7 @@ GLTexture::GLTexture(GLuint textureId, GLenum internalFormat, const QSize &size, d->m_mipLevels = levels; d->m_filter = levels > 1 ? GL_NEAREST_MIPMAP_LINEAR : GL_NEAREST; d->m_internalFormat = internalFormat; + d->m_immutable = isImmutable; d->updateMatrix(); } @@ -777,4 +729,42 @@ QImage GLTexture::toImage() const return ret; } +std::unique_ptr GLTexture::allocate(GLenum internalFormat, const QSize &size, int levels, bool needsMutability) +{ + GLuint texture = 0; + glGenTextures(1, &texture); + if (texture == 0) { + qCWarning(LIBKWINGLUTILS, "generating OpenGL texture handle failed"); + return nullptr; + } + glBindTexture(GL_TEXTURE_2D, texture); + + bool immutable = false; + + if (!GLPlatform::instance()->isGLES()) { + if (GLTexturePrivate::s_supportsTextureStorage && !needsMutability) { + glTexStorage2D(GL_TEXTURE_2D, levels, internalFormat, size.width(), size.height()); + immutable = true; + } else { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, levels - 1); + glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, size.width(), size.height(), 0, + GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, nullptr); + } + } else { + // The format parameter in glTexSubImage() must match the internal format + // of the texture, so it's important that we allocate the texture with + // the format that will be used in update() and clear(). + const GLenum format = GLTexturePrivate::s_supportsARGB32 ? GL_BGRA_EXT : GL_RGBA; + glTexImage2D(GL_TEXTURE_2D, 0, format, size.width(), size.height(), 0, + format, GL_UNSIGNED_BYTE, nullptr); + + // The internalFormat is technically not correct, but it means that code that calls + // internalFormat() won't need to be specialized for GLES2. + } + glBindTexture(GL_TEXTURE_2D, 0); + auto ret = std::make_unique(texture, internalFormat, size, levels, immutable); + ret->d_ptr->m_foreign = false; + return ret; +} + } // namespace KWin diff --git a/src/libkwineffects/kwingltexture.h b/src/libkwineffects/kwingltexture.h index d5dd339128..61fd7cbb12 100644 --- a/src/libkwineffects/kwingltexture.h +++ b/src/libkwineffects/kwingltexture.h @@ -52,8 +52,6 @@ public: explicit GLTexture(const QImage &image, GLenum target = GL_TEXTURE_2D); explicit GLTexture(const QPixmap &pixmap, GLenum target = GL_TEXTURE_2D); explicit GLTexture(const QString &fileName); - GLTexture(GLenum internalFormat, int width, int height, int levels = 1, bool needsMutability = false); - explicit GLTexture(GLenum internalFormat, const QSize &size, int levels = 1, bool needsMutability = false); /** * Creates the underlying texture object. Returns @c true if the texture has been created @@ -67,7 +65,7 @@ public: * Management of the underlying texture remains the responsibility of the caller. * @since 5.18 */ - explicit GLTexture(GLuint textureId, GLenum internalFormat, const QSize &size, int levels = 1); + explicit GLTexture(GLuint textureId, GLenum internalFormat, const QSize &size, int levels = 1, bool isImmutable = false); virtual ~GLTexture(); bool isNull() const; @@ -158,6 +156,8 @@ public: */ static bool supportsFormatRG(); + static std::unique_ptr allocate(GLenum internalFormat, const QSize &size, int levels = 1, bool needsMutability = false); + protected: const std::unique_ptr d_ptr; GLTexture(std::unique_ptr &&dd); diff --git a/src/libkwineffects/kwinoffscreeneffect.cpp b/src/libkwineffects/kwinoffscreeneffect.cpp index 46023dac5a..8a2c150716 100644 --- a/src/libkwineffects/kwinoffscreeneffect.cpp +++ b/src/libkwineffects/kwinoffscreeneffect.cpp @@ -97,7 +97,10 @@ void OffscreenData::maybeRender(EffectWindow *window) QSize textureSize = logicalGeometry.toAlignedRect().size(); if (!m_texture || m_texture->size() != textureSize) { - m_texture.reset(new GLTexture(GL_RGBA8, textureSize)); + m_texture = GLTexture::allocate(GL_RGBA8, textureSize); + if (!m_texture) { + return; + } m_texture->setFilter(GL_LINEAR); m_texture->setWrapMode(GL_CLAMP_TO_EDGE); m_fbo.reset(new GLFramebuffer(m_texture.get())); diff --git a/src/main.cpp b/src/main.cpp index ab30be8962..528d836f6f 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -653,9 +653,12 @@ static PlatformCursorImage grabCursorOpenGL() Cursor *cursor = Cursors::self()->currentCursor(); Output *output = workspace()->outputAt(cursor->pos()); - GLTexture texture(GL_RGBA8, (cursor->geometry().size() * output->scale()).toSize()); - texture.setContentTransform(TextureTransform::MirrorY); - GLFramebuffer framebuffer(&texture); + const auto texture = GLTexture::allocate(GL_RGBA8, (cursor->geometry().size() * output->scale()).toSize()); + if (!texture) { + return PlatformCursorImage{}; + } + texture->setContentTransform(TextureTransform::MirrorY); + GLFramebuffer framebuffer(texture.get()); RenderTarget renderTarget(&framebuffer); SceneDelegate delegate(scene, output); @@ -663,7 +666,7 @@ static PlatformCursorImage grabCursorOpenGL() scene->paint(renderTarget, infiniteRegion()); scene->postPaint(); - QImage image = texture.toImage(); + QImage image = texture->toImage(); image.setDevicePixelRatio(output->scale()); return PlatformCursorImage(image, cursor->hotspot()); diff --git a/src/platformsupport/scenes/opengl/eglcontext.cpp b/src/platformsupport/scenes/opengl/eglcontext.cpp index 2176e8d85e..5eec5a1e97 100644 --- a/src/platformsupport/scenes/opengl/eglcontext.cpp +++ b/src/platformsupport/scenes/opengl/eglcontext.cpp @@ -208,9 +208,9 @@ std::shared_ptr EglContext::importDmaBufAsTexture(const DmaBufAttribu { EGLImageKHR image = m_display->importDmaBufAsImage(attributes); if (image != EGL_NO_IMAGE_KHR) { - return std::make_shared(m_display->handle(), image, glFormatForDrmFormat(attributes.format), QSize(attributes.width, attributes.height)); + return EGLImageTexture::create(m_display->handle(), image, glFormatForDrmFormat(attributes.format), QSize(attributes.width, attributes.height)); } else { - qCWarning(KWIN_OPENGL) << "Failed to record frame: Error creating EGLImageKHR - " << getEglErrorString(); + qCWarning(KWIN_OPENGL) << "Error creating EGLImageKHR: " << getEglErrorString(); return nullptr; } } diff --git a/src/plugins/backgroundcontrast/contrast.cpp b/src/plugins/backgroundcontrast/contrast.cpp index 8a9cd7434d..e01035506e 100644 --- a/src/plugins/backgroundcontrast/contrast.cpp +++ b/src/plugins/backgroundcontrast/contrast.cpp @@ -430,14 +430,17 @@ void ContrastEffect::doContrast(const RenderTarget &renderTarget, const RenderVi // Create a scratch texture and copy the area in the back buffer that we're // going to blur into it - GLTexture scratch(GL_RGBA8, r.width(), r.height()); - scratch.setFilter(GL_LINEAR); - scratch.setWrapMode(GL_CLAMP_TO_EDGE); - scratch.bind(); + const auto scratch = GLTexture::allocate(GL_RGBA8, r.size().toSize()); + if (!scratch) { + return; + } + scratch->setFilter(GL_LINEAR); + scratch->setWrapMode(GL_CLAMP_TO_EDGE); + scratch->bind(); const QRectF sg = viewport.mapToRenderTarget(viewport.renderRect()); glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, (r.x() - sg.x()), (sg.height() - (r.y() - sg.y() + r.height())), - scratch.width(), scratch.height()); + scratch->width(), scratch->height()); // Draw the texture on the offscreen framebuffer object, while blurring it horizontally @@ -465,7 +468,7 @@ void ContrastEffect::doContrast(const RenderTarget &renderTarget, const RenderVi vbo->draw(GL_TRIANGLES, 0, actualShape.rectCount() * 6); - scratch.unbind(); + scratch->unbind(); vbo->unbindArrays(); diff --git a/src/plugins/blur/blur.cpp b/src/plugins/blur/blur.cpp index af9cf2e062..8833fab9e1 100644 --- a/src/plugins/blur/blur.cpp +++ b/src/plugins/blur/blur.cpp @@ -181,7 +181,7 @@ bool BlurEffect::updateTexture(EffectScreen *screen, const RenderTarget &renderT data.renderTargetTextures.reserve(m_downSampleIterations + 2); for (int i = 0; i <= m_downSampleIterations; i++) { - data.renderTargetTextures.push_back(std::make_unique(textureFormat, screenSize / (1 << i))); + data.renderTargetTextures.push_back(GLTexture::allocate(textureFormat, screenSize / (1 << i))); data.renderTargetTextures.back()->setFilter(GL_LINEAR); data.renderTargetTextures.back()->setWrapMode(GL_CLAMP_TO_EDGE); @@ -189,7 +189,7 @@ bool BlurEffect::updateTexture(EffectScreen *screen, const RenderTarget &renderT } // This last set is used as a temporary helper texture - data.renderTargetTextures.push_back(std::make_unique(textureFormat, screenSize)); + data.renderTargetTextures.push_back(GLTexture::allocate(textureFormat, screenSize)); data.renderTargetTextures.back()->setFilter(GL_LINEAR); data.renderTargetTextures.back()->setWrapMode(GL_CLAMP_TO_EDGE); diff --git a/src/plugins/magnifier/magnifier.cpp b/src/plugins/magnifier/magnifier.cpp index 75508c01f2..50c99fb477 100644 --- a/src/plugins/magnifier/magnifier.cpp +++ b/src/plugins/magnifier/magnifier.cpp @@ -201,7 +201,10 @@ void MagnifierEffect::zoomIn() } if (effects->isOpenGLCompositing() && !m_texture) { effects->makeOpenGLContextCurrent(); - m_texture = std::make_unique(GL_RGBA8, m_magnifierSize.width(), m_magnifierSize.height()); + m_texture = GLTexture::allocate(GL_RGBA8, m_magnifierSize); + if (!m_texture) { + return; + } m_texture->setContentTransform(TextureTransforms()); m_fbo = std::make_unique(m_texture.get()); } @@ -238,7 +241,10 @@ void MagnifierEffect::toggle() } if (effects->isOpenGLCompositing() && !m_texture) { effects->makeOpenGLContextCurrent(); - m_texture = std::make_unique(GL_RGBA8, m_magnifierSize.width(), m_magnifierSize.height()); + m_texture = GLTexture::allocate(GL_RGBA8, m_magnifierSize); + if (!m_texture) { + return; + } m_texture->setContentTransform(TextureTransforms()); m_fbo = std::make_unique(m_texture.get()); } diff --git a/src/plugins/screencast/regionscreencastsource.cpp b/src/plugins/screencast/regionscreencastsource.cpp index 4e5d641283..ff3811fad0 100644 --- a/src/plugins/screencast/regionscreencastsource.cpp +++ b/src/plugins/screencast/regionscreencastsource.cpp @@ -78,7 +78,10 @@ std::chrono::nanoseconds RegionScreenCastSource::clock() const void RegionScreenCastSource::ensureTexture() { if (!m_renderedTexture) { - m_renderedTexture.reset(new GLTexture(GL_RGBA8, textureSize())); + m_renderedTexture = GLTexture::allocate(GL_RGBA8, textureSize()); + if (!m_renderedTexture) { + return; + } m_target.reset(new GLFramebuffer(m_renderedTexture.get())); const auto allOutputs = workspace()->outputs(); for (auto output : allOutputs) { diff --git a/src/plugins/screencast/screencastutils.h b/src/plugins/screencast/screencastutils.h index f3bc7e0844..e65f8d7064 100644 --- a/src/plugins/screencast/screencastutils.h +++ b/src/plugins/screencast/screencastutils.h @@ -83,8 +83,11 @@ static void grabTexture(GLTexture *texture, spa_data *spa, spa_video_format form constexpr auto everythingExceptY = TextureTransforms() | TextureTransform::MirrorX | TextureTransform::Rotate90 | TextureTransform::Rotate180 | TextureTransform::Rotate270; if (texture->contentTransforms() & everythingExceptY) { // need to transform the texture to a usable transformation first - GLTexture backingTexture(GL_RGBA8, size); - GLFramebuffer fbo(&backingTexture); + const auto backingTexture = GLTexture::allocate(GL_RGBA8, size); + if (!backingTexture) { + return; + } + GLFramebuffer fbo(backingTexture.get()); ShaderBinder shaderBinder(ShaderTrait::MapTexture); QMatrix4x4 projectionMatrix; @@ -94,7 +97,7 @@ static void grabTexture(GLTexture *texture, spa_data *spa, spa_video_format form GLFramebuffer::pushFramebuffer(&fbo); texture->render(size, 1); GLFramebuffer::popFramebuffer(); - doGrabTexture(&backingTexture, spa, format); + doGrabTexture(backingTexture.get(), spa, format); } else { doGrabTexture(texture, spa, format); } diff --git a/src/plugins/screencast/windowscreencastsource.cpp b/src/plugins/screencast/windowscreencastsource.cpp index edbfeae04a..abe4a6908f 100644 --- a/src/plugins/screencast/windowscreencastsource.cpp +++ b/src/plugins/screencast/windowscreencastsource.cpp @@ -49,11 +49,14 @@ QSize WindowScreenCastSource::textureSize() const void WindowScreenCastSource::render(spa_data *spa, spa_video_format format) { - GLTexture offscreenTexture(hasAlphaChannel() ? GL_RGBA8 : GL_RGB8, textureSize()); - GLFramebuffer offscreenTarget(&offscreenTexture); + const auto offscreenTexture = GLTexture::allocate(hasAlphaChannel() ? GL_RGBA8 : GL_RGB8, textureSize()); + if (!offscreenTexture) { + return; + } + GLFramebuffer offscreenTarget(offscreenTexture.get()); render(&offscreenTarget); - grabTexture(&offscreenTexture, spa, format); + grabTexture(offscreenTexture.get(), spa, format); } void WindowScreenCastSource::render(GLFramebuffer *target) diff --git a/src/plugins/screenshot/screenshot.cpp b/src/plugins/screenshot/screenshot.cpp index 9aa98122ce..8646c041a4 100644 --- a/src/plugins/screenshot/screenshot.cpp +++ b/src/plugins/screenshot/screenshot.cpp @@ -240,7 +240,10 @@ void ScreenShotEffect::takeScreenShot(ScreenShotWindowData *screenshot) std::unique_ptr offscreenTexture; std::unique_ptr target; if (effects->isOpenGLCompositing()) { - offscreenTexture.reset(new GLTexture(GL_RGBA8, QSizeF(geometry.size() * devicePixelRatio).toSize())); + offscreenTexture = GLTexture::allocate(GL_RGBA8, QSizeF(geometry.size() * devicePixelRatio).toSize()); + if (!offscreenTexture) { + return; + } offscreenTexture->setFilter(GL_LINEAR); offscreenTexture->setWrapMode(GL_CLAMP_TO_EDGE); target.reset(new GLFramebuffer(offscreenTexture.get())); @@ -364,14 +367,17 @@ QImage ScreenShotEffect::blitScreenshot(const RenderTarget &renderTarget, const image = QImage(nativeSize, QImage::Format_ARGB32); if (GLFramebuffer::blitSupported() && !GLPlatform::instance()->isGLES()) { - GLTexture texture(GL_RGBA8, nativeSize.width(), nativeSize.height()); - GLFramebuffer target(&texture); + const auto texture = GLTexture::allocate(GL_RGBA8, nativeSize); + if (!texture) { + return {}; + } + GLFramebuffer target(texture.get()); target.blitFromFramebuffer(viewport.mapToRenderTarget(geometry)); // copy content from framebuffer into image - texture.bind(); + texture->bind(); glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, static_cast(image.bits())); - texture.unbind(); + texture->unbind(); } else { glReadPixels(0, 0, nativeSize.width(), nativeSize.height(), GL_RGBA, GL_UNSIGNED_BYTE, static_cast(image.bits())); diff --git a/src/plugins/screentransform/screentransform.cpp b/src/plugins/screentransform/screentransform.cpp index 0559d79ac6..634db36e42 100644 --- a/src/plugins/screentransform/screentransform.cpp +++ b/src/plugins/screentransform/screentransform.cpp @@ -84,7 +84,11 @@ void ScreenTransformEffect::addScreen(EffectScreen *screen) auto &state = m_states[screen]; state.m_oldTransform = screen->transform(); state.m_oldGeometry = screen->geometry(); - state.m_prev.texture.reset(new GLTexture(GL_RGBA8, screen->geometry().size() * screen->devicePixelRatio())); + state.m_prev.texture = GLTexture::allocate(GL_RGBA8, screen->geometry().size() * screen->devicePixelRatio()); + if (!state.m_prev.texture) { + m_states.remove(screen); + return; + } state.m_prev.framebuffer.reset(new GLFramebuffer(state.m_prev.texture.get())); // Rendering the current scene into a texture @@ -193,7 +197,11 @@ void ScreenTransformEffect::paintScreen(const RenderTarget &renderTarget, const // Render the screen in an offscreen texture. const QSize nativeSize = screen->geometry().size() * screen->devicePixelRatio(); if (!it->m_current.texture || it->m_current.texture->size() != nativeSize) { - it->m_current.texture.reset(new GLTexture(GL_RGBA8, nativeSize)); + it->m_current.texture = GLTexture::allocate(GL_RGBA8, nativeSize); + if (!it->m_current.texture) { + m_states.remove(screen); + return; + } it->m_current.framebuffer.reset(new GLFramebuffer(it->m_current.texture.get())); } diff --git a/src/plugins/zoom/zoom.cpp b/src/plugins/zoom/zoom.cpp index 914df23b2e..825295ed37 100644 --- a/src/plugins/zoom/zoom.cpp +++ b/src/plugins/zoom/zoom.cpp @@ -266,7 +266,10 @@ ZoomEffect::OffscreenData *ZoomEffect::ensureOffscreenData(const RenderTarget &r const GLenum textureFormat = renderTarget.colorDescription() == ColorDescription::sRGB ? GL_RGBA8 : GL_RGBA16F; if (!data.texture || data.texture->size() != nativeSize || data.texture->internalFormat() != textureFormat) { - data.texture.reset(new GLTexture(textureFormat, nativeSize)); + data.texture = GLTexture::allocate(textureFormat, nativeSize); + if (!data.texture) { + return nullptr; + } data.texture->setFilter(GL_LINEAR); data.texture->setWrapMode(GL_CLAMP_TO_EDGE); data.framebuffer = std::make_unique(data.texture.get()); @@ -278,6 +281,9 @@ ZoomEffect::OffscreenData *ZoomEffect::ensureOffscreenData(const RenderTarget &r void ZoomEffect::paintScreen(const RenderTarget &renderTarget, const RenderViewport &viewport, int mask, const QRegion ®ion, EffectScreen *screen) { OffscreenData *offscreenData = ensureOffscreenData(renderTarget, viewport, screen); + if (!offscreenData) { + return; + } // Render the scene in an offscreen texture and then upscale it. RenderTarget offscreenRenderTarget(offscreenData->framebuffer.get(), renderTarget.colorDescription()); diff --git a/src/scene/cursordelegate_opengl.cpp b/src/scene/cursordelegate_opengl.cpp index 31e4579555..1b03ccc4ac 100644 --- a/src/scene/cursordelegate_opengl.cpp +++ b/src/scene/cursordelegate_opengl.cpp @@ -42,7 +42,10 @@ void CursorDelegateOpenGL::paint(const RenderTarget &renderTarget, const QRegion // Render the cursor scene in an offscreen render target. const QSize bufferSize = (Cursors::self()->currentCursor()->rect().size() * scale).toSize(); if (!m_texture || m_texture->size() != bufferSize) { - m_texture = std::make_unique(renderTarget.framebuffer()->colorAttachment()->internalFormat(), bufferSize); + m_texture = GLTexture::allocate(renderTarget.framebuffer()->colorAttachment()->internalFormat(), bufferSize); + if (!m_texture) { + return; + } m_framebuffer = std::make_unique(m_texture.get()); } diff --git a/src/scene/workspacescene_opengl.cpp b/src/scene/workspacescene_opengl.cpp index 22d387efae..fe9f0c4f99 100644 --- a/src/scene/workspacescene_opengl.cpp +++ b/src/scene/workspacescene_opengl.cpp @@ -363,7 +363,7 @@ void SceneOpenGLDecorationRenderer::renderPart(const QRect &rect, const QRect &p const QPoint &textureOffset, qreal devicePixelRatio, bool rotated) { - if (!rect.isValid()) { + if (!rect.isValid() || !m_texture) { return; } // We allow partial decoration updates and it might just so happen that the @@ -457,7 +457,10 @@ void SceneOpenGLDecorationRenderer::resizeTexture() } if (!size.isEmpty()) { - m_texture.reset(new GLTexture(GL_RGBA8, size.width(), size.height())); + m_texture = GLTexture::allocate(GL_RGBA8, size); + if (!m_texture) { + return; + } m_texture->setContentTransform(TextureTransform::MirrorY); m_texture->setFilter(GL_LINEAR); m_texture->setWrapMode(GL_CLAMP_TO_EDGE); diff --git a/src/scripting/windowthumbnailitem.cpp b/src/scripting/windowthumbnailitem.cpp index d76e6bdbe5..1dc9837bd4 100644 --- a/src/scripting/windowthumbnailitem.cpp +++ b/src/scripting/windowthumbnailitem.cpp @@ -380,7 +380,10 @@ void WindowThumbnailItem::updateOffscreenTexture() textureSize *= m_devicePixelRatio; if (!m_offscreenTexture || m_offscreenTexture->size() != textureSize) { - m_offscreenTexture.reset(new GLTexture(GL_RGBA8, textureSize)); + m_offscreenTexture = GLTexture::allocate(GL_RGBA8, textureSize); + if (!m_offscreenTexture) { + return; + } m_offscreenTexture->setFilter(GL_LINEAR); m_offscreenTexture->setWrapMode(GL_CLAMP_TO_EDGE); m_offscreenTarget.reset(new GLFramebuffer(m_offscreenTexture.get()));