libkwineffects: handle GLTexture allocation failures

This is required for properly dealing with GPU resets
This commit is contained in:
Xaver Hugl 2023-05-15 01:03:26 +02:00
parent bfc8bcb24a
commit 572bc75de4
21 changed files with 165 additions and 103 deletions

View file

@ -104,7 +104,10 @@ std::optional<OutputLayerBeginFrameInfo> EglGbmLayerSurface::startRendering(cons
} }
if (enableColormanagement) { if (enableColormanagement) {
if (!m_surface.shadowBuffer) { if (!m_surface.shadowBuffer) {
m_surface.shadowTexture = std::make_shared<GLTexture>(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<GLFramebuffer>(m_surface.shadowTexture.get()); m_surface.shadowBuffer = std::make_shared<GLFramebuffer>(m_surface.shadowTexture.get());
} }
return OutputLayerBeginFrameInfo{ return OutputLayerBeginFrameInfo{

View file

@ -205,7 +205,10 @@ std::optional<OutputLayerBeginFrameInfo> X11WindowedEglCursorLayer::beginFrame()
const auto tmp = size().expandedTo(QSize(64, 64)); const auto tmp = size().expandedTo(QSize(64, 64));
const QSize bufferSize(std::ceil(tmp.width()), std::ceil(tmp.height())); const QSize bufferSize(std::ceil(tmp.width()), std::ceil(tmp.height()));
if (!m_texture || m_texture->size() != bufferSize) { if (!m_texture || m_texture->size() != bufferSize) {
m_texture = std::make_unique<GLTexture>(GL_RGBA8, bufferSize); m_texture = GLTexture::allocate(GL_RGBA8, bufferSize);
if (!m_texture) {
return std::nullopt;
}
m_framebuffer = std::make_unique<GLFramebuffer>(m_texture.get()); m_framebuffer = std::make_unique<GLFramebuffer>(m_texture.get());
} }

View file

@ -8,6 +8,7 @@
*/ */
#include "libkwineffects/kwineglimagetexture.h" #include "libkwineffects/kwineglimagetexture.h"
#include "libkwineffects/kwingltexture_p.h"
#include <QDebug> #include <QDebug>
#include <epoxy/egl.h> #include <epoxy/egl.h>
@ -15,18 +16,13 @@
namespace KWin namespace KWin
{ {
EGLImageTexture::EGLImageTexture(::EGLDisplay display, EGLImage image, int internalFormat, const QSize &size) EGLImageTexture::EGLImageTexture(::EGLDisplay display, EGLImage image, uint textureId, int internalFormat, const QSize &size)
: GLTexture(internalFormat, size, 1, true) : GLTexture(textureId, internalFormat, size, 1, true)
, m_image(image) , m_image(image)
, m_display(display) , m_display(display)
{ {
if (m_image == EGL_NO_IMAGE_KHR) { d_ptr->m_foreign = false;
return;
}
setContentTransform(TextureTransform::MirrorY); setContentTransform(TextureTransform::MirrorY);
bind();
glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, m_image);
} }
EGLImageTexture::~EGLImageTexture() EGLImageTexture::~EGLImageTexture()
@ -34,4 +30,20 @@ EGLImageTexture::~EGLImageTexture()
eglDestroyImageKHR(m_display, m_image); eglDestroyImageKHR(m_display, m_image);
} }
std::shared_ptr<EGLImageTexture> 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<EGLImageTexture>(display, image, texture, internalFormat, size);
}
} // namespace KWin } // namespace KWin

View file

@ -22,10 +22,11 @@ namespace KWin
class KWINGLUTILS_EXPORT EGLImageTexture : public GLTexture class KWINGLUTILS_EXPORT EGLImageTexture : public GLTexture
{ {
public: 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; ~EGLImageTexture() override;
private: static std::shared_ptr<EGLImageTexture> create(::EGLDisplay display, EGLImageKHR image, int internalFormat, const QSize &size);
EGLImageKHR m_image; EGLImageKHR m_image;
::EGLDisplay m_display; ::EGLDisplay m_display;
}; };

View file

@ -9,13 +9,13 @@
SPDX-License-Identifier: GPL-2.0-or-later SPDX-License-Identifier: GPL-2.0-or-later
*/ */
#include "kwingltexture_p.h"
#include "libkwineffects/kwinconfig.h" // KWIN_HAVE_OPENGL #include "libkwineffects/kwinconfig.h" // KWIN_HAVE_OPENGL
#include "libkwineffects/kwineffects.h" #include "libkwineffects/kwineffects.h"
#include "libkwineffects/kwinglplatform.h" #include "libkwineffects/kwinglplatform.h"
#include "libkwineffects/kwinglutils.h" #include "libkwineffects/kwinglutils.h"
#include "libkwineffects/kwinglutils_funcs.h" #include "libkwineffects/kwinglutils_funcs.h"
#include "logging_p.h"
#include "kwingltexture_p.h"
#include <QImage> #include <QImage>
#include <QPixmap> #include <QPixmap>
@ -185,56 +185,7 @@ GLTexture::GLTexture(const QString &fileName)
{ {
} }
GLTexture::GLTexture(GLenum internalFormat, int width, int height, int levels, bool needsMutability) GLTexture::GLTexture(GLuint textureId, GLenum internalFormat, const QSize &size, int levels, bool isImmutable)
: 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)
: d_ptr(new GLTexturePrivate()) : d_ptr(new GLTexturePrivate())
{ {
Q_D(GLTexture); Q_D(GLTexture);
@ -248,6 +199,7 @@ GLTexture::GLTexture(GLuint textureId, GLenum internalFormat, const QSize &size,
d->m_mipLevels = levels; d->m_mipLevels = levels;
d->m_filter = levels > 1 ? GL_NEAREST_MIPMAP_LINEAR : GL_NEAREST; d->m_filter = levels > 1 ? GL_NEAREST_MIPMAP_LINEAR : GL_NEAREST;
d->m_internalFormat = internalFormat; d->m_internalFormat = internalFormat;
d->m_immutable = isImmutable;
d->updateMatrix(); d->updateMatrix();
} }
@ -777,4 +729,42 @@ QImage GLTexture::toImage() const
return ret; return ret;
} }
std::unique_ptr<GLTexture> 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<GLTexture>(texture, internalFormat, size, levels, immutable);
ret->d_ptr->m_foreign = false;
return ret;
}
} // namespace KWin } // namespace KWin

View file

@ -52,8 +52,6 @@ public:
explicit GLTexture(const QImage &image, GLenum target = GL_TEXTURE_2D); explicit GLTexture(const QImage &image, GLenum target = GL_TEXTURE_2D);
explicit GLTexture(const QPixmap &pixmap, GLenum target = GL_TEXTURE_2D); explicit GLTexture(const QPixmap &pixmap, GLenum target = GL_TEXTURE_2D);
explicit GLTexture(const QString &fileName); 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 * 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. * Management of the underlying texture remains the responsibility of the caller.
* @since 5.18 * @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(); virtual ~GLTexture();
bool isNull() const; bool isNull() const;
@ -158,6 +156,8 @@ public:
*/ */
static bool supportsFormatRG(); static bool supportsFormatRG();
static std::unique_ptr<GLTexture> allocate(GLenum internalFormat, const QSize &size, int levels = 1, bool needsMutability = false);
protected: protected:
const std::unique_ptr<GLTexturePrivate> d_ptr; const std::unique_ptr<GLTexturePrivate> d_ptr;
GLTexture(std::unique_ptr<GLTexturePrivate> &&dd); GLTexture(std::unique_ptr<GLTexturePrivate> &&dd);

View file

@ -97,7 +97,10 @@ void OffscreenData::maybeRender(EffectWindow *window)
QSize textureSize = logicalGeometry.toAlignedRect().size(); QSize textureSize = logicalGeometry.toAlignedRect().size();
if (!m_texture || m_texture->size() != textureSize) { 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->setFilter(GL_LINEAR);
m_texture->setWrapMode(GL_CLAMP_TO_EDGE); m_texture->setWrapMode(GL_CLAMP_TO_EDGE);
m_fbo.reset(new GLFramebuffer(m_texture.get())); m_fbo.reset(new GLFramebuffer(m_texture.get()));

View file

@ -653,9 +653,12 @@ static PlatformCursorImage grabCursorOpenGL()
Cursor *cursor = Cursors::self()->currentCursor(); Cursor *cursor = Cursors::self()->currentCursor();
Output *output = workspace()->outputAt(cursor->pos()); Output *output = workspace()->outputAt(cursor->pos());
GLTexture texture(GL_RGBA8, (cursor->geometry().size() * output->scale()).toSize()); const auto texture = GLTexture::allocate(GL_RGBA8, (cursor->geometry().size() * output->scale()).toSize());
texture.setContentTransform(TextureTransform::MirrorY); if (!texture) {
GLFramebuffer framebuffer(&texture); return PlatformCursorImage{};
}
texture->setContentTransform(TextureTransform::MirrorY);
GLFramebuffer framebuffer(texture.get());
RenderTarget renderTarget(&framebuffer); RenderTarget renderTarget(&framebuffer);
SceneDelegate delegate(scene, output); SceneDelegate delegate(scene, output);
@ -663,7 +666,7 @@ static PlatformCursorImage grabCursorOpenGL()
scene->paint(renderTarget, infiniteRegion()); scene->paint(renderTarget, infiniteRegion());
scene->postPaint(); scene->postPaint();
QImage image = texture.toImage(); QImage image = texture->toImage();
image.setDevicePixelRatio(output->scale()); image.setDevicePixelRatio(output->scale());
return PlatformCursorImage(image, cursor->hotspot()); return PlatformCursorImage(image, cursor->hotspot());

View file

@ -208,9 +208,9 @@ std::shared_ptr<GLTexture> EglContext::importDmaBufAsTexture(const DmaBufAttribu
{ {
EGLImageKHR image = m_display->importDmaBufAsImage(attributes); EGLImageKHR image = m_display->importDmaBufAsImage(attributes);
if (image != EGL_NO_IMAGE_KHR) { if (image != EGL_NO_IMAGE_KHR) {
return std::make_shared<EGLImageTexture>(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 { } else {
qCWarning(KWIN_OPENGL) << "Failed to record frame: Error creating EGLImageKHR - " << getEglErrorString(); qCWarning(KWIN_OPENGL) << "Error creating EGLImageKHR: " << getEglErrorString();
return nullptr; return nullptr;
} }
} }

View file

@ -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 // Create a scratch texture and copy the area in the back buffer that we're
// going to blur into it // going to blur into it
GLTexture scratch(GL_RGBA8, r.width(), r.height()); const auto scratch = GLTexture::allocate(GL_RGBA8, r.size().toSize());
scratch.setFilter(GL_LINEAR); if (!scratch) {
scratch.setWrapMode(GL_CLAMP_TO_EDGE); return;
scratch.bind(); }
scratch->setFilter(GL_LINEAR);
scratch->setWrapMode(GL_CLAMP_TO_EDGE);
scratch->bind();
const QRectF sg = viewport.mapToRenderTarget(viewport.renderRect()); 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())), 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 // 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); vbo->draw(GL_TRIANGLES, 0, actualShape.rectCount() * 6);
scratch.unbind(); scratch->unbind();
vbo->unbindArrays(); vbo->unbindArrays();

View file

@ -181,7 +181,7 @@ bool BlurEffect::updateTexture(EffectScreen *screen, const RenderTarget &renderT
data.renderTargetTextures.reserve(m_downSampleIterations + 2); data.renderTargetTextures.reserve(m_downSampleIterations + 2);
for (int i = 0; i <= m_downSampleIterations; i++) { for (int i = 0; i <= m_downSampleIterations; i++) {
data.renderTargetTextures.push_back(std::make_unique<GLTexture>(textureFormat, screenSize / (1 << i))); data.renderTargetTextures.push_back(GLTexture::allocate(textureFormat, screenSize / (1 << i)));
data.renderTargetTextures.back()->setFilter(GL_LINEAR); data.renderTargetTextures.back()->setFilter(GL_LINEAR);
data.renderTargetTextures.back()->setWrapMode(GL_CLAMP_TO_EDGE); 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 // This last set is used as a temporary helper texture
data.renderTargetTextures.push_back(std::make_unique<GLTexture>(textureFormat, screenSize)); data.renderTargetTextures.push_back(GLTexture::allocate(textureFormat, screenSize));
data.renderTargetTextures.back()->setFilter(GL_LINEAR); data.renderTargetTextures.back()->setFilter(GL_LINEAR);
data.renderTargetTextures.back()->setWrapMode(GL_CLAMP_TO_EDGE); data.renderTargetTextures.back()->setWrapMode(GL_CLAMP_TO_EDGE);

View file

@ -201,7 +201,10 @@ void MagnifierEffect::zoomIn()
} }
if (effects->isOpenGLCompositing() && !m_texture) { if (effects->isOpenGLCompositing() && !m_texture) {
effects->makeOpenGLContextCurrent(); effects->makeOpenGLContextCurrent();
m_texture = std::make_unique<GLTexture>(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_texture->setContentTransform(TextureTransforms());
m_fbo = std::make_unique<GLFramebuffer>(m_texture.get()); m_fbo = std::make_unique<GLFramebuffer>(m_texture.get());
} }
@ -238,7 +241,10 @@ void MagnifierEffect::toggle()
} }
if (effects->isOpenGLCompositing() && !m_texture) { if (effects->isOpenGLCompositing() && !m_texture) {
effects->makeOpenGLContextCurrent(); effects->makeOpenGLContextCurrent();
m_texture = std::make_unique<GLTexture>(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_texture->setContentTransform(TextureTransforms());
m_fbo = std::make_unique<GLFramebuffer>(m_texture.get()); m_fbo = std::make_unique<GLFramebuffer>(m_texture.get());
} }

View file

@ -78,7 +78,10 @@ std::chrono::nanoseconds RegionScreenCastSource::clock() const
void RegionScreenCastSource::ensureTexture() void RegionScreenCastSource::ensureTexture()
{ {
if (!m_renderedTexture) { 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())); m_target.reset(new GLFramebuffer(m_renderedTexture.get()));
const auto allOutputs = workspace()->outputs(); const auto allOutputs = workspace()->outputs();
for (auto output : allOutputs) { for (auto output : allOutputs) {

View file

@ -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; constexpr auto everythingExceptY = TextureTransforms() | TextureTransform::MirrorX | TextureTransform::Rotate90 | TextureTransform::Rotate180 | TextureTransform::Rotate270;
if (texture->contentTransforms() & everythingExceptY) { if (texture->contentTransforms() & everythingExceptY) {
// need to transform the texture to a usable transformation first // need to transform the texture to a usable transformation first
GLTexture backingTexture(GL_RGBA8, size); const auto backingTexture = GLTexture::allocate(GL_RGBA8, size);
GLFramebuffer fbo(&backingTexture); if (!backingTexture) {
return;
}
GLFramebuffer fbo(backingTexture.get());
ShaderBinder shaderBinder(ShaderTrait::MapTexture); ShaderBinder shaderBinder(ShaderTrait::MapTexture);
QMatrix4x4 projectionMatrix; QMatrix4x4 projectionMatrix;
@ -94,7 +97,7 @@ static void grabTexture(GLTexture *texture, spa_data *spa, spa_video_format form
GLFramebuffer::pushFramebuffer(&fbo); GLFramebuffer::pushFramebuffer(&fbo);
texture->render(size, 1); texture->render(size, 1);
GLFramebuffer::popFramebuffer(); GLFramebuffer::popFramebuffer();
doGrabTexture(&backingTexture, spa, format); doGrabTexture(backingTexture.get(), spa, format);
} else { } else {
doGrabTexture(texture, spa, format); doGrabTexture(texture, spa, format);
} }

View file

@ -49,11 +49,14 @@ QSize WindowScreenCastSource::textureSize() const
void WindowScreenCastSource::render(spa_data *spa, spa_video_format format) void WindowScreenCastSource::render(spa_data *spa, spa_video_format format)
{ {
GLTexture offscreenTexture(hasAlphaChannel() ? GL_RGBA8 : GL_RGB8, textureSize()); const auto offscreenTexture = GLTexture::allocate(hasAlphaChannel() ? GL_RGBA8 : GL_RGB8, textureSize());
GLFramebuffer offscreenTarget(&offscreenTexture); if (!offscreenTexture) {
return;
}
GLFramebuffer offscreenTarget(offscreenTexture.get());
render(&offscreenTarget); render(&offscreenTarget);
grabTexture(&offscreenTexture, spa, format); grabTexture(offscreenTexture.get(), spa, format);
} }
void WindowScreenCastSource::render(GLFramebuffer *target) void WindowScreenCastSource::render(GLFramebuffer *target)

View file

@ -240,7 +240,10 @@ void ScreenShotEffect::takeScreenShot(ScreenShotWindowData *screenshot)
std::unique_ptr<GLTexture> offscreenTexture; std::unique_ptr<GLTexture> offscreenTexture;
std::unique_ptr<GLFramebuffer> target; std::unique_ptr<GLFramebuffer> target;
if (effects->isOpenGLCompositing()) { 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->setFilter(GL_LINEAR);
offscreenTexture->setWrapMode(GL_CLAMP_TO_EDGE); offscreenTexture->setWrapMode(GL_CLAMP_TO_EDGE);
target.reset(new GLFramebuffer(offscreenTexture.get())); target.reset(new GLFramebuffer(offscreenTexture.get()));
@ -364,14 +367,17 @@ QImage ScreenShotEffect::blitScreenshot(const RenderTarget &renderTarget, const
image = QImage(nativeSize, QImage::Format_ARGB32); image = QImage(nativeSize, QImage::Format_ARGB32);
if (GLFramebuffer::blitSupported() && !GLPlatform::instance()->isGLES()) { if (GLFramebuffer::blitSupported() && !GLPlatform::instance()->isGLES()) {
GLTexture texture(GL_RGBA8, nativeSize.width(), nativeSize.height()); const auto texture = GLTexture::allocate(GL_RGBA8, nativeSize);
GLFramebuffer target(&texture); if (!texture) {
return {};
}
GLFramebuffer target(texture.get());
target.blitFromFramebuffer(viewport.mapToRenderTarget(geometry)); target.blitFromFramebuffer(viewport.mapToRenderTarget(geometry));
// copy content from framebuffer into image // copy content from framebuffer into image
texture.bind(); texture->bind();
glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE,
static_cast<GLvoid *>(image.bits())); static_cast<GLvoid *>(image.bits()));
texture.unbind(); texture->unbind();
} else { } else {
glReadPixels(0, 0, nativeSize.width(), nativeSize.height(), GL_RGBA, glReadPixels(0, 0, nativeSize.width(), nativeSize.height(), GL_RGBA,
GL_UNSIGNED_BYTE, static_cast<GLvoid *>(image.bits())); GL_UNSIGNED_BYTE, static_cast<GLvoid *>(image.bits()));

View file

@ -84,7 +84,11 @@ void ScreenTransformEffect::addScreen(EffectScreen *screen)
auto &state = m_states[screen]; auto &state = m_states[screen];
state.m_oldTransform = screen->transform(); state.m_oldTransform = screen->transform();
state.m_oldGeometry = screen->geometry(); 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())); state.m_prev.framebuffer.reset(new GLFramebuffer(state.m_prev.texture.get()));
// Rendering the current scene into a texture // 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. // Render the screen in an offscreen texture.
const QSize nativeSize = screen->geometry().size() * screen->devicePixelRatio(); const QSize nativeSize = screen->geometry().size() * screen->devicePixelRatio();
if (!it->m_current.texture || it->m_current.texture->size() != nativeSize) { 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())); it->m_current.framebuffer.reset(new GLFramebuffer(it->m_current.texture.get()));
} }

View file

@ -266,7 +266,10 @@ ZoomEffect::OffscreenData *ZoomEffect::ensureOffscreenData(const RenderTarget &r
const GLenum textureFormat = renderTarget.colorDescription() == ColorDescription::sRGB ? GL_RGBA8 : GL_RGBA16F; const GLenum textureFormat = renderTarget.colorDescription() == ColorDescription::sRGB ? GL_RGBA8 : GL_RGBA16F;
if (!data.texture || data.texture->size() != nativeSize || data.texture->internalFormat() != textureFormat) { 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->setFilter(GL_LINEAR);
data.texture->setWrapMode(GL_CLAMP_TO_EDGE); data.texture->setWrapMode(GL_CLAMP_TO_EDGE);
data.framebuffer = std::make_unique<GLFramebuffer>(data.texture.get()); data.framebuffer = std::make_unique<GLFramebuffer>(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 &region, EffectScreen *screen) void ZoomEffect::paintScreen(const RenderTarget &renderTarget, const RenderViewport &viewport, int mask, const QRegion &region, EffectScreen *screen)
{ {
OffscreenData *offscreenData = ensureOffscreenData(renderTarget, viewport, screen); OffscreenData *offscreenData = ensureOffscreenData(renderTarget, viewport, screen);
if (!offscreenData) {
return;
}
// Render the scene in an offscreen texture and then upscale it. // Render the scene in an offscreen texture and then upscale it.
RenderTarget offscreenRenderTarget(offscreenData->framebuffer.get(), renderTarget.colorDescription()); RenderTarget offscreenRenderTarget(offscreenData->framebuffer.get(), renderTarget.colorDescription());

View file

@ -42,7 +42,10 @@ void CursorDelegateOpenGL::paint(const RenderTarget &renderTarget, const QRegion
// Render the cursor scene in an offscreen render target. // Render the cursor scene in an offscreen render target.
const QSize bufferSize = (Cursors::self()->currentCursor()->rect().size() * scale).toSize(); const QSize bufferSize = (Cursors::self()->currentCursor()->rect().size() * scale).toSize();
if (!m_texture || m_texture->size() != bufferSize) { if (!m_texture || m_texture->size() != bufferSize) {
m_texture = std::make_unique<GLTexture>(renderTarget.framebuffer()->colorAttachment()->internalFormat(), bufferSize); m_texture = GLTexture::allocate(renderTarget.framebuffer()->colorAttachment()->internalFormat(), bufferSize);
if (!m_texture) {
return;
}
m_framebuffer = std::make_unique<GLFramebuffer>(m_texture.get()); m_framebuffer = std::make_unique<GLFramebuffer>(m_texture.get());
} }

View file

@ -363,7 +363,7 @@ void SceneOpenGLDecorationRenderer::renderPart(const QRect &rect, const QRect &p
const QPoint &textureOffset, const QPoint &textureOffset,
qreal devicePixelRatio, bool rotated) qreal devicePixelRatio, bool rotated)
{ {
if (!rect.isValid()) { if (!rect.isValid() || !m_texture) {
return; return;
} }
// We allow partial decoration updates and it might just so happen that the // We allow partial decoration updates and it might just so happen that the
@ -457,7 +457,10 @@ void SceneOpenGLDecorationRenderer::resizeTexture()
} }
if (!size.isEmpty()) { 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->setContentTransform(TextureTransform::MirrorY);
m_texture->setFilter(GL_LINEAR); m_texture->setFilter(GL_LINEAR);
m_texture->setWrapMode(GL_CLAMP_TO_EDGE); m_texture->setWrapMode(GL_CLAMP_TO_EDGE);

View file

@ -380,7 +380,10 @@ void WindowThumbnailItem::updateOffscreenTexture()
textureSize *= m_devicePixelRatio; textureSize *= m_devicePixelRatio;
if (!m_offscreenTexture || m_offscreenTexture->size() != textureSize) { 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->setFilter(GL_LINEAR);
m_offscreenTexture->setWrapMode(GL_CLAMP_TO_EDGE); m_offscreenTexture->setWrapMode(GL_CLAMP_TO_EDGE);
m_offscreenTarget.reset(new GLFramebuffer(m_offscreenTexture.get())); m_offscreenTarget.reset(new GLFramebuffer(m_offscreenTexture.get()));