libkwineffects: handle GLTexture allocation failures
This is required for properly dealing with GPU resets
This commit is contained in:
parent
bfc8bcb24a
commit
572bc75de4
21 changed files with 165 additions and 103 deletions
|
@ -104,7 +104,10 @@ std::optional<OutputLayerBeginFrameInfo> EglGbmLayerSurface::startRendering(cons
|
|||
}
|
||||
if (enableColormanagement) {
|
||||
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());
|
||||
}
|
||||
return OutputLayerBeginFrameInfo{
|
||||
|
|
|
@ -205,7 +205,10 @@ std::optional<OutputLayerBeginFrameInfo> 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<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());
|
||||
}
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
*/
|
||||
|
||||
#include "libkwineffects/kwineglimagetexture.h"
|
||||
#include "libkwineffects/kwingltexture_p.h"
|
||||
|
||||
#include <QDebug>
|
||||
#include <epoxy/egl.h>
|
||||
|
@ -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> 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
|
||||
|
|
|
@ -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<EGLImageTexture> create(::EGLDisplay display, EGLImageKHR image, int internalFormat, const QSize &size);
|
||||
|
||||
EGLImageKHR m_image;
|
||||
::EGLDisplay m_display;
|
||||
};
|
||||
|
|
|
@ -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 <QImage>
|
||||
#include <QPixmap>
|
||||
|
@ -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> 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
|
||||
|
|
|
@ -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<GLTexture> allocate(GLenum internalFormat, const QSize &size, int levels = 1, bool needsMutability = false);
|
||||
|
||||
protected:
|
||||
const std::unique_ptr<GLTexturePrivate> d_ptr;
|
||||
GLTexture(std::unique_ptr<GLTexturePrivate> &&dd);
|
||||
|
|
|
@ -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()));
|
||||
|
|
11
src/main.cpp
11
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());
|
||||
|
|
|
@ -208,9 +208,9 @@ std::shared_ptr<GLTexture> EglContext::importDmaBufAsTexture(const DmaBufAttribu
|
|||
{
|
||||
EGLImageKHR image = m_display->importDmaBufAsImage(attributes);
|
||||
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 {
|
||||
qCWarning(KWIN_OPENGL) << "Failed to record frame: Error creating EGLImageKHR - " << getEglErrorString();
|
||||
qCWarning(KWIN_OPENGL) << "Error creating EGLImageKHR: " << getEglErrorString();
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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<GLTexture>(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<GLTexture>(textureFormat, screenSize));
|
||||
data.renderTargetTextures.push_back(GLTexture::allocate(textureFormat, screenSize));
|
||||
data.renderTargetTextures.back()->setFilter(GL_LINEAR);
|
||||
data.renderTargetTextures.back()->setWrapMode(GL_CLAMP_TO_EDGE);
|
||||
|
||||
|
|
|
@ -201,7 +201,10 @@ void MagnifierEffect::zoomIn()
|
|||
}
|
||||
if (effects->isOpenGLCompositing() && !m_texture) {
|
||||
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_fbo = std::make_unique<GLFramebuffer>(m_texture.get());
|
||||
}
|
||||
|
@ -238,7 +241,10 @@ void MagnifierEffect::toggle()
|
|||
}
|
||||
if (effects->isOpenGLCompositing() && !m_texture) {
|
||||
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_fbo = std::make_unique<GLFramebuffer>(m_texture.get());
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -240,7 +240,10 @@ void ScreenShotEffect::takeScreenShot(ScreenShotWindowData *screenshot)
|
|||
std::unique_ptr<GLTexture> offscreenTexture;
|
||||
std::unique_ptr<GLFramebuffer> 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<GLvoid *>(image.bits()));
|
||||
texture.unbind();
|
||||
texture->unbind();
|
||||
} else {
|
||||
glReadPixels(0, 0, nativeSize.width(), nativeSize.height(), GL_RGBA,
|
||||
GL_UNSIGNED_BYTE, static_cast<GLvoid *>(image.bits()));
|
||||
|
|
|
@ -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()));
|
||||
}
|
||||
|
||||
|
|
|
@ -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<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 ®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());
|
||||
|
|
|
@ -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<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());
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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()));
|
||||
|
|
Loading…
Reference in a new issue