diff --git a/src/backends/drm/egl_gbm_layer.cpp b/src/backends/drm/egl_gbm_layer.cpp index 2f5def84c8..7cf3c71ed0 100644 --- a/src/backends/drm/egl_gbm_layer.cpp +++ b/src/backends/drm/egl_gbm_layer.cpp @@ -96,21 +96,24 @@ std::optional EglGbmLayer::startRendering() } } } + + GLRenderTarget::pushRenderTarget(m_gbmSurface->renderTarget()); if (m_shadowBuffer) { - m_shadowBuffer->bind(); // the blit after rendering will completely overwrite the back buffer anyways repaintRegion = QRegion(); + GLRenderTarget::pushRenderTarget(m_shadowBuffer->renderTarget()); } - glViewport(0, 0, m_output->sourceSize().width(), m_output->sourceSize().height()); return repaintRegion; } bool EglGbmLayer::endRendering(const QRegion &damagedRegion) { if (m_shadowBuffer) { + GLRenderTarget::popRenderTarget(); m_shadowBuffer->render(m_output); } + GLRenderTarget::popRenderTarget(); const auto buffer = m_gbmSurface->swapBuffersForDrm(damagedRegion.intersected(m_output->geometry())); if (buffer) { m_currentBuffer = buffer; @@ -198,7 +201,7 @@ bool EglGbmLayer::doesGbmSurfaceFit(GbmSurface *surf) const bool EglGbmLayer::doesShadowBufferFit(ShadowBuffer *buffer) const { if (m_output->needsSoftwareTransformation()) { - return buffer && buffer->textureSize() == m_output->sourceSize() && buffer->drmFormat() == m_gbmSurface->format(); + return buffer && buffer->texture()->size() == m_output->sourceSize() && buffer->drmFormat() == m_gbmSurface->format(); } else { return buffer == nullptr; } @@ -212,9 +215,7 @@ bool EglGbmLayer::doesSwapchainFit(DumbSwapchain *swapchain) const QSharedPointer EglGbmLayer::texture() const { if (m_shadowBuffer) { - const auto glTexture = QSharedPointer::create(m_shadowBuffer->texture(), GL_RGBA8, m_shadowBuffer->textureSize()); - glTexture->setYInverted(true); - return glTexture; + return m_shadowBuffer->texture(); } GbmBuffer *gbmBuffer = m_gbmSurface->currentBuffer().get(); if (!gbmBuffer) { diff --git a/src/backends/drm/gbm_surface.cpp b/src/backends/drm/gbm_surface.cpp index 8f798f0b2f..404ce9095f 100644 --- a/src/backends/drm/gbm_surface.cpp +++ b/src/backends/drm/gbm_surface.cpp @@ -25,6 +25,7 @@ GbmSurface::GbmSurface(DrmGpu *gpu, const QSize &size, uint32_t format, uint32_t , m_gpu(gpu) , m_size(size) , m_format(format) + , m_renderTarget(new GLRenderTarget(0, size)) { if (!m_surface) { qCCritical(KWIN_DRM) << "Could not create gbm surface!" << strerror(errno); @@ -42,6 +43,7 @@ GbmSurface::GbmSurface(DrmGpu *gpu, const QSize &size, uint32_t format, QVector< , m_size(size) , m_format(format) , m_modifiers(modifiers) + , m_renderTarget(new GLRenderTarget(0, size)) { if (!m_surface) { qCCritical(KWIN_DRM) << "Could not create gbm surface!" << strerror(errno); @@ -140,6 +142,11 @@ QSharedPointer GbmSurface::currentDrmBuffer() const return m_currentDrmBuffer; } +GLRenderTarget *GbmSurface::renderTarget() const +{ + return m_renderTarget.data(); +} + EGLSurface GbmSurface::eglSurface() const { return m_eglSurface; diff --git a/src/backends/drm/gbm_surface.h b/src/backends/drm/gbm_surface.h index 09f659a0b4..367e55260d 100644 --- a/src/backends/drm/gbm_surface.h +++ b/src/backends/drm/gbm_surface.h @@ -23,6 +23,8 @@ struct gbm_surface; namespace KWin { +class GLRenderTarget; + class GbmSurface { public: @@ -38,6 +40,7 @@ public: QSharedPointer currentBuffer() const; QSharedPointer currentDrmBuffer() const; + GLRenderTarget *renderTarget() const; EGLSurface eglSurface() const; QSize size() const; @@ -60,6 +63,7 @@ private: QSharedPointer m_currentBuffer; QSharedPointer m_currentDrmBuffer; QVector m_lockedBuffers; + QScopedPointer m_renderTarget; }; } diff --git a/src/backends/drm/shadowbuffer.cpp b/src/backends/drm/shadowbuffer.cpp index 97672fae48..768817bf0b 100644 --- a/src/backends/drm/shadowbuffer.cpp +++ b/src/backends/drm/shadowbuffer.cpp @@ -38,44 +38,26 @@ ShadowBuffer::ShadowBuffer(const QSize &size, const GbmFormat &format) : m_size(size) , m_drmFormat(format.drmFormat) { - glGenFramebuffers(1, &m_framebuffer); - glBindFramebuffer(GL_FRAMEBUFFER, m_framebuffer); - GLRenderTarget::setKWinFramebuffer(m_framebuffer); + m_texture.reset(new GLTexture(internalFormat(format), size)); + m_texture->setFilter(GL_NEAREST); - glGenTextures(1, &m_texture); - glBindTexture(GL_TEXTURE_2D, m_texture); - glTexImage2D(GL_TEXTURE_2D, 0, internalFormat(format), size.width(), size.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glBindTexture(GL_TEXTURE_2D, 0); - - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_texture, 0); - if(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { + m_renderTarget.reset(new GLRenderTarget(*m_texture)); + if (!m_renderTarget->valid()) { qCCritical(KWIN_DRM) << "Error: framebuffer not complete!"; return; } - glBindFramebuffer(GL_FRAMEBUFFER, 0); - GLRenderTarget::setKWinFramebuffer(0); - m_vbo.reset(new GLVertexBuffer(KWin::GLVertexBuffer::Static)); m_vbo->setData(6, 2, vertices, texCoords); } ShadowBuffer::~ShadowBuffer() { - glDeleteTextures(1, &m_texture); - glDeleteFramebuffers(1, &m_framebuffer); } void ShadowBuffer::render(DrmAbstractOutput *output) { - const auto size = output->modeSize(); - glViewport(0, 0, size.width(), size.height()); - auto shader = ShaderManager::instance()->pushShader(ShaderTrait::MapTexture); - QMatrix4x4 mvpMatrix; - switch (output->transform()) { case DrmOutput::Transform::Normal: case DrmOutput::Transform::Flipped: @@ -104,35 +86,27 @@ void ShadowBuffer::render(DrmAbstractOutput *output) break; } + auto shader = ShaderManager::instance()->pushShader(ShaderTrait::MapTexture); shader->setUniform(GLShader::ModelViewProjectionMatrix, mvpMatrix); - glBindFramebuffer(GL_FRAMEBUFFER, 0); - GLRenderTarget::setKWinFramebuffer(0); - glBindTexture(GL_TEXTURE_2D, m_texture); + m_texture->bind(); m_vbo->render(GL_TRIANGLES); ShaderManager::instance()->popShader(); - glBindTexture(GL_TEXTURE_2D, 0); } -void ShadowBuffer::bind() +GLRenderTarget *ShadowBuffer::renderTarget() const { - glBindFramebuffer(GL_FRAMEBUFFER, m_framebuffer); - GLRenderTarget::setKWinFramebuffer(m_framebuffer); + return m_renderTarget.data(); } -bool ShadowBuffer::isComplete() const -{ - return m_texture && m_framebuffer && m_vbo; -} - -int ShadowBuffer::texture() const +QSharedPointer ShadowBuffer::texture() const { return m_texture; } -QSize ShadowBuffer::textureSize() const +bool ShadowBuffer::isComplete() const { - return m_size; + return m_renderTarget->valid() && m_vbo; } uint32_t ShadowBuffer::drmFormat() const diff --git a/src/backends/drm/shadowbuffer.h b/src/backends/drm/shadowbuffer.h index 1d18f00ed7..8c4ecd7ac3 100644 --- a/src/backends/drm/shadowbuffer.h +++ b/src/backends/drm/shadowbuffer.h @@ -26,18 +26,16 @@ public: bool isComplete() const; - void bind(); void render(DrmAbstractOutput *output); - int texture() const; - - QSize textureSize() const; + GLRenderTarget *renderTarget() const; + QSharedPointer texture() const; uint32_t drmFormat() const; private: GLint internalFormat(const GbmFormat &format) const; - GLuint m_texture; - GLuint m_framebuffer; + QSharedPointer m_texture; + QScopedPointer m_renderTarget; QScopedPointer m_vbo; const QSize m_size; const uint32_t m_drmFormat; diff --git a/src/backends/wayland/egl_wayland_backend.cpp b/src/backends/wayland/egl_wayland_backend.cpp index c954dc1a14..155fce727d 100644 --- a/src/backends/wayland/egl_wayland_backend.cpp +++ b/src/backends/wayland/egl_wayland_backend.cpp @@ -17,6 +17,7 @@ #include "wayland_output.h" #include "composite.h" +#include "kwinglutils.h" #include "logging.h" #include "options.h" @@ -59,6 +60,7 @@ bool EglWaylandOutput::init(EglWaylandBackend *backend) return false; } m_overlay = overlay; + m_renderTarget.reset(new GLRenderTarget(0, nativeSize)); EGLSurface eglSurface = EGL_NO_SURFACE; if (backend->havePlatformBase()) { @@ -79,9 +81,20 @@ bool EglWaylandOutput::init(EglWaylandBackend *backend) return true; } +EglWaylandOutput::~EglWaylandOutput() +{ +} + +GLRenderTarget *EglWaylandOutput::renderTarget() const +{ + return m_renderTarget.data(); +} + void EglWaylandOutput::updateSize() { const QSize nativeSize = m_waylandOutput->geometry().size() * m_waylandOutput->scale(); + m_renderTarget.reset(new GLRenderTarget(0, nativeSize)); + wl_egl_window_resize(m_overlay, nativeSize.width(), nativeSize.height(), 0, 0); resetBufferAge(); } @@ -245,8 +258,6 @@ bool EglWaylandBackend::makeContextCurrent(EglWaylandOutput *output) return false; } - const QSize size = output->m_waylandOutput->pixelSize(); - glViewport(0, 0, size.width(), size.height()); return true; } @@ -358,9 +369,13 @@ QRegion EglWaylandBackend::beginFrame(AbstractOutput *output) const auto &eglOutput = m_outputs[output]; makeContextCurrent(eglOutput); + + GLRenderTarget::pushRenderTarget(eglOutput->renderTarget()); + if (supportsBufferAge()) { return eglOutput->m_damageJournal.accumulate(eglOutput->m_bufferAge, eglOutput->m_waylandOutput->geometry()); } + return QRegion(); } @@ -368,6 +383,9 @@ void EglWaylandBackend::endFrame(AbstractOutput *output, const QRegion &rendered { Q_ASSERT(m_outputs.contains(output)); Q_UNUSED(renderedRegion); + + GLRenderTarget::popRenderTarget(); + const auto &eglOutput = m_outputs[output]; QRegion damage = damagedRegion.intersected(eglOutput->m_waylandOutput->geometry()); presentOnSurface(eglOutput, damage); diff --git a/src/backends/wayland/egl_wayland_backend.h b/src/backends/wayland/egl_wayland_backend.h index 4ff9bb866c..6496a93dbd 100644 --- a/src/backends/wayland/egl_wayland_backend.h +++ b/src/backends/wayland/egl_wayland_backend.h @@ -20,6 +20,7 @@ struct wl_shm; namespace KWin { +class GLRenderTarget; namespace Wayland { @@ -32,11 +33,13 @@ class EglWaylandOutput : public QObject Q_OBJECT public: EglWaylandOutput(WaylandOutput *output, QObject *parent = nullptr); - ~EglWaylandOutput() override = default; + ~EglWaylandOutput() override; bool init(EglWaylandBackend *backend); void updateSize(); + GLRenderTarget *renderTarget() const; + private: void resetBufferAge(); @@ -45,6 +48,7 @@ private: EGLSurface m_eglSurface = EGL_NO_SURFACE; int m_bufferAge = 0; DamageJournal m_damageJournal; + QScopedPointer m_renderTarget; friend class EglWaylandBackend; }; diff --git a/src/backends/x11/standalone/eglbackend.cpp b/src/backends/x11/standalone/eglbackend.cpp index 161f64d7f0..5143b5f2ed 100644 --- a/src/backends/x11/standalone/eglbackend.cpp +++ b/src/backends/x11/standalone/eglbackend.cpp @@ -76,6 +76,8 @@ void EglBackend::init() return; } + m_renderTarget.reset(new GLRenderTarget(0, screens()->size())); + kwinApp()->platform()->setSceneEglDisplay(shareDisplay); kwinApp()->platform()->setSceneEglGlobalShareContext(shareContext); EglOnXBackend::init(); @@ -87,6 +89,7 @@ void EglBackend::screenGeometryChanged() // The back buffer contents are now undefined m_bufferAge = 0; + m_renderTarget.reset(new GLRenderTarget(0, screens()->size())); } QRegion EglBackend::beginFrame(AbstractOutput *output) @@ -94,9 +97,6 @@ QRegion EglBackend::beginFrame(AbstractOutput *output) Q_UNUSED(output) makeCurrent(); - const QSize size = screens()->size(); - glViewport(0, 0, size.width(), size.height()); - QRegion repaint; if (supportsBufferAge()) { repaint = m_damageJournal.accumulate(m_bufferAge, screens()->geometry()); @@ -104,6 +104,8 @@ QRegion EglBackend::beginFrame(AbstractOutput *output) eglWaitNative(EGL_CORE_NATIVE_ENGINE); + // Push the default framebuffer to the render target stack. + GLRenderTarget::pushRenderTarget(m_renderTarget.data()); return repaint; } @@ -126,6 +128,9 @@ void EglBackend::endFrame(AbstractOutput *output, const QRegion &renderedRegion, } } + // Pop the default render target from the render target stack. + GLRenderTarget::popRenderTarget(); + presentSurface(surface(), effectiveRenderedRegion, screens()->geometry()); if (overlayWindow() && overlayWindow()->window()) { // show the window only after the first pass, diff --git a/src/backends/x11/standalone/eglbackend.h b/src/backends/x11/standalone/eglbackend.h index 5fa202cf14..aadff3a270 100644 --- a/src/backends/x11/standalone/eglbackend.h +++ b/src/backends/x11/standalone/eglbackend.h @@ -42,6 +42,7 @@ private: X11StandalonePlatform *m_backend; SoftwareVsyncMonitor *m_vsyncMonitor; DamageJournal m_damageJournal; + QScopedPointer m_renderTarget; int m_bufferAge = 0; }; diff --git a/src/backends/x11/standalone/glxbackend.cpp b/src/backends/x11/standalone/glxbackend.cpp index c38c0f025a..6546342b52 100644 --- a/src/backends/x11/standalone/glxbackend.cpp +++ b/src/backends/x11/standalone/glxbackend.cpp @@ -202,6 +202,8 @@ void GlxBackend::init() glPlatform->printResults(); initGL(&getProcAddress); + m_renderTarget.reset(new GLRenderTarget(0, screens()->size())); + bool supportsSwapEvent = false; if (hasExtension(QByteArrayLiteral("GLX_INTEL_swap_event"))) { @@ -721,6 +723,7 @@ void GlxBackend::screenGeometryChanged() // The back buffer contents are now undefined m_bufferAge = 0; + m_renderTarget.reset(new GLRenderTarget(0, size)); } SurfaceTexture *GlxBackend::createSurfaceTextureX11(SurfacePixmapX11 *pixmap) @@ -735,9 +738,7 @@ QRegion GlxBackend::beginFrame(AbstractOutput *output) QRegion repaint; makeCurrent(); - const QSize size = screens()->size(); - glViewport(0, 0, size.width(), size.height()); - + GLRenderTarget::pushRenderTarget(m_renderTarget.data()); if (supportsBufferAge()) { repaint = m_damageJournal.accumulate(m_bufferAge, screens()->geometry()); } @@ -767,6 +768,8 @@ void GlxBackend::endFrame(AbstractOutput *output, const QRegion &renderedRegion, effectiveRenderedRegion = displayRegion; } + GLRenderTarget::popRenderTarget(); + present(effectiveRenderedRegion); if (overlayWindow()->window()) // show the window only after the first pass, diff --git a/src/backends/x11/standalone/glxbackend.h b/src/backends/x11/standalone/glxbackend.h index 8eaeef9e01..9b017a3276 100644 --- a/src/backends/x11/standalone/glxbackend.h +++ b/src/backends/x11/standalone/glxbackend.h @@ -107,6 +107,7 @@ private: QHash m_fbconfigHash; QHash m_visualDepthHash; std::unique_ptr m_swapEventFilter; + QScopedPointer m_renderTarget; DamageJournal m_damageJournal; int m_bufferAge; bool m_haveMESACopySubBuffer = false; diff --git a/src/backends/x11/windowed/egl_x11_backend.cpp b/src/backends/x11/windowed/egl_x11_backend.cpp index ebe6671df7..d5e31eb645 100644 --- a/src/backends/x11/windowed/egl_x11_backend.cpp +++ b/src/backends/x11/windowed/egl_x11_backend.cpp @@ -40,9 +40,10 @@ void EglX11Backend::init() void EglX11Backend::cleanupSurfaces() { - for (auto it = m_surfaces.begin(); it != m_surfaces.end(); ++it) { - eglDestroySurface(eglDisplay(), *it); + for (auto it = m_outputs.begin(); it != m_outputs.end(); ++it) { + eglDestroySurface(eglDisplay(), (*it)->m_eglSurface); } + qDeleteAll(m_outputs); } bool EglX11Backend::createSurfaces() @@ -53,35 +54,34 @@ bool EglX11Backend::createSurfaces() if (s == EGL_NO_SURFACE) { return false; } - m_surfaces.insert(output, s); + EglX11Output *rendererOutput = new EglX11Output; + rendererOutput->m_eglSurface = s; + rendererOutput->m_renderTarget.reset(new GLRenderTarget(0, output->pixelSize())); + m_outputs[output] = rendererOutput; } - if (m_surfaces.isEmpty()) { + if (m_outputs.isEmpty()) { return false; } - setSurface(m_surfaces.first()); + setSurface(m_outputs.first()->m_eglSurface); return true; } QRegion EglX11Backend::beginFrame(AbstractOutput *output) { - makeContextCurrent(m_surfaces[output]); - setupViewport(output); + const EglX11Output *rendererOutput = m_outputs[output]; + makeContextCurrent(rendererOutput->m_eglSurface); + GLRenderTarget::pushRenderTarget(rendererOutput->m_renderTarget.data()); return output->geometry(); } -void EglX11Backend::setupViewport(AbstractOutput *output) -{ - const QSize size = output->pixelSize() * output->scale(); - glViewport(0, 0, size.width(), size.height()); -} - void EglX11Backend::endFrame(AbstractOutput *output, const QRegion &renderedRegion, const QRegion &damagedRegion) { Q_UNUSED(damagedRegion) static_cast(output)->vsyncMonitor()->arm(); + GLRenderTarget::popRenderTarget(); - presentSurface(m_surfaces[output], renderedRegion, output->geometry()); + presentSurface(m_outputs[output]->m_eglSurface, renderedRegion, output->geometry()); } void EglX11Backend::presentSurface(EGLSurface surface, const QRegion &damage, const QRect &screenGeometry) diff --git a/src/backends/x11/windowed/egl_x11_backend.h b/src/backends/x11/windowed/egl_x11_backend.h index 0ec6aab10e..7a4affc0b4 100644 --- a/src/backends/x11/windowed/egl_x11_backend.h +++ b/src/backends/x11/windowed/egl_x11_backend.h @@ -9,6 +9,7 @@ #ifndef KWIN_EGL_X11_BACKEND_H #define KWIN_EGL_X11_BACKEND_H #include "eglonxbackend.h" +#include "kwinglutils.h" #include @@ -17,6 +18,13 @@ namespace KWin class X11WindowedBackend; +class EglX11Output +{ +public: + EGLSurface m_eglSurface; + QScopedPointer m_renderTarget; +}; + /** * @brief OpenGL Backend using Egl windowing system over an X overlay window. */ @@ -39,10 +47,9 @@ protected: bool createSurfaces() override; private: - void setupViewport(AbstractOutput *output); void presentSurface(EGLSurface surface, const QRegion &damage, const QRect &screenGeometry); - QMap m_surfaces; + QMap m_outputs; X11WindowedBackend *m_backend; }; diff --git a/src/effects.cpp b/src/effects.cpp index 32e5321ca4..29e5c6dde4 100644 --- a/src/effects.cpp +++ b/src/effects.cpp @@ -1784,6 +1784,16 @@ bool EffectsHandlerImpl::isCursorHidden() const return Cursors::self()->isCursorHidden(); } +QRect EffectsHandlerImpl::renderTargetRect() const +{ + return m_scene->renderTargetRect(); +} + +qreal EffectsHandlerImpl::renderTargetScale() const +{ + return m_scene->renderTargetScale(); +} + //**************************************** // EffectScreenImpl //**************************************** diff --git a/src/effects.h b/src/effects.h index 08fb215e76..ecb86867d5 100644 --- a/src/effects.h +++ b/src/effects.h @@ -274,6 +274,8 @@ public: EffectScreen *findScreen(int screenId) const override; void renderScreen(EffectScreen *screen) override; bool isCursorHidden() const override; + QRect renderTargetRect() const override; + qreal renderTargetScale() const override; public Q_SLOTS: void slotCurrentTabAboutToChange(EffectWindow* from, EffectWindow* to); diff --git a/src/effects/backgroundcontrast/contrast.cpp b/src/effects/backgroundcontrast/contrast.cpp index f42af9bff2..67099ad3d6 100644 --- a/src/effects/backgroundcontrast/contrast.cpp +++ b/src/effects/backgroundcontrast/contrast.cpp @@ -427,8 +427,8 @@ bool ContrastEffect::shouldContrast(const EffectWindow *w, int mask, const Windo void ContrastEffect::drawWindow(EffectWindow *w, int mask, const QRegion ®ion, WindowPaintData &data) { - const QRect screen = GLRenderTarget::virtualScreenGeometry(); if (shouldContrast(w, mask, data)) { + const QRect screen = effects->renderTargetRect(); QRegion shape = region & contrastRegion(w).translated(w->pos()) & screen; // let's do the evil parts - someone wants to blur behind a transformed window @@ -472,7 +472,7 @@ void ContrastEffect::doContrast(EffectWindow *w, const QRegion& shape, const QRe const QRegion actualShape = shape & screen; const QRect r = actualShape.boundingRect(); - qreal scale = GLRenderTarget::virtualScreenScale(); + const qreal scale = effects->renderTargetScale(); // Upload geometry for the horizontal and vertical passes GLVertexBuffer *vbo = GLVertexBuffer::streamingBuffer(); @@ -487,7 +487,7 @@ void ContrastEffect::doContrast(EffectWindow *w, const QRegion& shape, const QRe scratch.setWrapMode(GL_CLAMP_TO_EDGE); scratch.bind(); - const QRect sg = GLRenderTarget::virtualScreenGeometry(); + const QRect sg = effects->renderTargetRect(); glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, (r.x() - sg.x()) * scale, (sg.height() - (r.y() - sg.y() + r.height())) * scale, scratch.width(), scratch.height()); diff --git a/src/effects/blur/blur.cpp b/src/effects/blur/blur.cpp index e2fc6194bb..9a455f0d54 100644 --- a/src/effects/blur/blur.cpp +++ b/src/effects/blur/blur.cpp @@ -607,8 +607,8 @@ bool BlurEffect::shouldBlur(const EffectWindow *w, int mask, const WindowPaintDa void BlurEffect::drawWindow(EffectWindow *w, int mask, const QRegion ®ion, WindowPaintData &data) { - const QRect screen = GLRenderTarget::virtualScreenGeometry(); if (shouldBlur(w, mask, data)) { + const QRect screen = effects->renderTargetRect(); QRegion shape = region & blurRegion(w).translated(w->pos()) & screen; // let's do the evil parts - someone wants to blur behind a transformed window @@ -704,8 +704,6 @@ void BlurEffect::doBlur(const QRegion& shape, const QRect& screen, const float o const QRect sourceRect = expandedBlurRegion.boundingRect() & screen; const QRect destRect = sourceRect.translated(xTranslate, yTranslate); - - GLRenderTarget::pushRenderTargets(m_renderTargetStack); int blurRectCount = expandedBlurRegion.rectCount() * 6; /* @@ -716,7 +714,8 @@ void BlurEffect::doBlur(const QRegion& shape, const QRect& screen, const float o * when maximized windows or windows near the panel affect the dock blur. */ if (isDock) { - m_renderTargets.last()->blitFromFramebuffer(sourceRect, destRect); + m_renderTargets.last()->blitFromFramebuffer(effects->mapToRenderTarget(sourceRect), destRect); + GLRenderTarget::pushRenderTargets(m_renderTargetStack); if (useSRGB) { glEnable(GL_FRAMEBUFFER_SRGB); @@ -727,7 +726,8 @@ void BlurEffect::doBlur(const QRegion& shape, const QRect& screen, const float o mvp.ortho(0, screenRect.width(), screenRect.height(), 0, 0, 65535); copyScreenSampleTexture(vbo, blurRectCount, shape.translated(xTranslate, yTranslate), mvp); } else { - m_renderTargets.first()->blitFromFramebuffer(sourceRect, destRect); + m_renderTargets.first()->blitFromFramebuffer(effects->mapToRenderTarget(sourceRect), destRect); + GLRenderTarget::pushRenderTargets(m_renderTargetStack); if (useSRGB) { glEnable(GL_FRAMEBUFFER_SRGB); @@ -793,7 +793,7 @@ void BlurEffect::upscaleRenderToScreen(GLVertexBuffer *vbo, int vboStart, int bl m_renderTextures[1].bind(); m_shader->bind(BlurShader::UpSampleType); - m_shader->setTargetTextureSize(m_renderTextures[0].size() * GLRenderTarget::virtualScreenScale()); + m_shader->setTargetTextureSize(m_renderTextures[0].size() * effects->renderTargetScale()); m_shader->setOffset(m_offset); m_shader->setModelViewProjectionMatrix(screenProjection); @@ -806,9 +806,9 @@ void BlurEffect::upscaleRenderToScreen(GLVertexBuffer *vbo, int vboStart, int bl void BlurEffect::applyNoise(GLVertexBuffer *vbo, int vboStart, int blurRectCount, const QMatrix4x4 &screenProjection, QPoint windowPosition) { m_shader->bind(BlurShader::NoiseSampleType); - m_shader->setTargetTextureSize(m_renderTextures[0].size() * GLRenderTarget::virtualScreenScale()); - m_shader->setNoiseTextureSize(m_noiseTexture->size() * GLRenderTarget::virtualScreenScale()); - m_shader->setTexturePosition(windowPosition * GLRenderTarget::virtualScreenScale()); + m_shader->setTargetTextureSize(m_renderTextures[0].size() * effects->renderTargetScale()); + m_shader->setNoiseTextureSize(m_noiseTexture->size() * effects->renderTargetScale()); + m_shader->setTexturePosition(windowPosition * effects->renderTargetScale()); m_noiseTexture->bind(); diff --git a/src/effects/colorpicker/colorpicker.cpp b/src/effects/colorpicker/colorpicker.cpp index bc60225838..eb921c7512 100644 --- a/src/effects/colorpicker/colorpicker.cpp +++ b/src/effects/colorpicker/colorpicker.cpp @@ -62,9 +62,9 @@ void ColorPickerEffect::postPaintScreen() if (m_scheduledPosition != QPoint(-1, -1) && (!m_paintedScreen || m_paintedScreen->geometry().contains(m_scheduledPosition))) { uint8_t data[3]; - const QRect geo = GLRenderTarget::virtualScreenGeometry(); + const QRect geo = effects->renderTargetRect(); const QPoint screenPosition(m_scheduledPosition.x() - geo.x(), m_scheduledPosition.y() - geo.y()); - const QPoint texturePosition(screenPosition.x() * GLRenderTarget::virtualScreenScale(), (geo.height() - screenPosition.y()) * GLRenderTarget::virtualScreenScale()); + const QPoint texturePosition(screenPosition.x() * effects->renderTargetScale(), (geo.height() - screenPosition.y()) * effects->renderTargetScale()); glReadnPixels(texturePosition.x(), texturePosition.y(), 1, 1, GL_RGB, GL_UNSIGNED_BYTE, 3, data); QDBusConnection::sessionBus().send(m_replyMessage.createReply(QColor(data[0], data[1], data[2]))); diff --git a/src/effects/glide/glide.cpp b/src/effects/glide/glide.cpp index 8a67f60900..70edca759f 100644 --- a/src/effects/glide/glide.cpp +++ b/src/effects/glide/glide.cpp @@ -12,7 +12,6 @@ // own #include "glide.h" -#include "kwinglutils.h" // KConfigSkeleton #include "glideconfig.h" @@ -121,7 +120,7 @@ void GlideEffect::paintWindow(EffectWindow *w, int mask, QRegion region, WindowP data.setProjectionMatrix(invOffsetMatrix * oldProjMatrix); // Move the center of the window to the origin. - const QRectF screenGeo = GLRenderTarget::virtualScreenGeometry(); + const QRectF screenGeo = effects->renderTargetRect(); const QPointF offset = screenGeo.center() - windowGeo.center(); data.translate(offset.x(), offset.y()); diff --git a/src/effects/magnifier/magnifier.cpp b/src/effects/magnifier/magnifier.cpp index 0feccdcad6..f9f954e120 100644 --- a/src/effects/magnifier/magnifier.cpp +++ b/src/effects/magnifier/magnifier.cpp @@ -126,7 +126,7 @@ void MagnifierEffect::paintScreen(int mask, const QRegion ®ion, ScreenPaintDa cursor.y() - (double)area.height() / (zoom*2), (double)area.width() / zoom, (double)area.height() / zoom); if (effects->isOpenGLCompositing()) { - m_fbo->blitFromFramebuffer(srcArea); + m_fbo->blitFromFramebuffer(effects->mapToRenderTarget(srcArea)); // paint magnifier m_texture->bind(); auto s = ShaderManager::instance()->pushShader(ShaderTrait::MapTexture); diff --git a/src/effects/screenshot/screenshot.cpp b/src/effects/screenshot/screenshot.cpp index a2e0732b9e..eadd66129c 100644 --- a/src/effects/screenshot/screenshot.cpp +++ b/src/effects/screenshot/screenshot.cpp @@ -364,7 +364,7 @@ QImage ScreenShotEffect::blitScreenshot(const QRect &geometry, qreal devicePixel image = QImage(nativeSize.width(), nativeSize.height(), QImage::Format_ARGB32); GLTexture texture(GL_RGBA8, nativeSize.width(), nativeSize.height()); GLRenderTarget target(texture); - target.blitFromFramebuffer(geometry); + target.blitFromFramebuffer(effects->mapToRenderTarget(geometry)); // copy content from framebuffer into image texture.bind(); glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, diff --git a/src/effects/screentransform/screentransform.cpp b/src/effects/screentransform/screentransform.cpp index a8cd5ab2ed..4fac726e21 100644 --- a/src/effects/screentransform/screentransform.cpp +++ b/src/effects/screentransform/screentransform.cpp @@ -68,11 +68,6 @@ void ScreenTransformEffect::addScreen(EffectScreen *screen) GLRenderTarget renderTarget(*state.m_texture); GLRenderTarget::pushRenderTarget(&renderTarget); - GLVertexBuffer::setVirtualScreenGeometry(screen->geometry()); - GLRenderTarget::setVirtualScreenGeometry(screen->geometry()); - GLVertexBuffer::setVirtualScreenScale(screen->devicePixelRatio()); - GLRenderTarget::setVirtualScreenScale(screen->devicePixelRatio()); - effects->renderScreen(screen); state.m_captured = true; GLRenderTarget::popRenderTarget(); @@ -146,7 +141,7 @@ void ScreenTransformEffect::paintScreen(int mask, const QRegion ®ion, KWin::S shader->setUniform(GLShader::ModelViewProjectionMatrix, matrix); state.m_texture->bind(); - state.m_texture->render(screen->geometry(), textureRect); + state.m_texture->render(infiniteRegion(), textureRect); state.m_texture->unbind(); } effects->addRepaintFull(); diff --git a/src/effects/showfps/showfps.cpp b/src/effects/showfps/showfps.cpp index 7ff2a99245..e4c5d4fc42 100644 --- a/src/effects/showfps/showfps.cpp +++ b/src/effects/showfps/showfps.cpp @@ -229,7 +229,7 @@ void ShowFpsEffect::paintGL(int fps, const QMatrix4x4 &projectionMatrix) QMatrix4x4 mvp = projectionMatrix; mvp.translate(fpsTextRect.x(), fpsTextRect.y()); binder.shader()->setUniform(GLShader::ModelViewProjectionMatrix, mvp); - fpsText->render(QRegion(fpsTextRect), fpsTextRect); + fpsText->render(infiniteRegion(), fpsTextRect); fpsText->unbind(); effects->addRepaint(fpsTextRect); } diff --git a/src/effects/startupfeedback/startupfeedback.cpp b/src/effects/startupfeedback/startupfeedback.cpp index 064823e7fb..29e501067a 100644 --- a/src/effects/startupfeedback/startupfeedback.cpp +++ b/src/effects/startupfeedback/startupfeedback.cpp @@ -229,7 +229,7 @@ void StartupFeedbackEffect::paintScreen(int mask, const QRegion ®ion, ScreenP QMatrix4x4 mvp = data.projectionMatrix(); mvp.translate(m_currentGeometry.x(), m_currentGeometry.y()); ShaderManager::instance()->getBoundShader()->setUniform(GLShader::ModelViewProjectionMatrix, mvp); - texture->render(m_currentGeometry, m_currentGeometry); + texture->render(infiniteRegion(), m_currentGeometry); ShaderManager::instance()->popShader(); texture->unbind(); glDisable(GL_BLEND); diff --git a/src/effects/trackmouse/trackmouse.cpp b/src/effects/trackmouse/trackmouse.cpp index cbb283021f..0fc473fa6b 100644 --- a/src/effects/trackmouse/trackmouse.cpp +++ b/src/effects/trackmouse/trackmouse.cpp @@ -119,7 +119,7 @@ void TrackMouseEffect::paintScreen(int mask, const QRegion ®ion, ScreenPaintD mvp.translate(m_lastRect[i].x(), m_lastRect[i].y()); shader->setUniform(GLShader::ModelViewProjectionMatrix, mvp); m_texture[i]->bind(); - m_texture[i]->render(region, m_lastRect[i]); + m_texture[i]->render(infiniteRegion(), m_lastRect[i]); m_texture[i]->unbind(); } glDisable(GL_BLEND); diff --git a/src/effects/zoom/zoom.cpp b/src/effects/zoom/zoom.cpp index 9b80fb3484..97276a8b06 100644 --- a/src/effects/zoom/zoom.cpp +++ b/src/effects/zoom/zoom.cpp @@ -344,7 +344,7 @@ void ZoomEffect::paintScreen(int mask, const QRegion ®ion, ScreenPaintData& d QMatrix4x4 mvp = data.projectionMatrix(); mvp.translate(rect.x(), rect.y()); s->setUniform(GLShader::ModelViewProjectionMatrix, mvp); - cursorTexture->render(region, rect); + cursorTexture->render(infiniteRegion(), rect); ShaderManager::instance()->popShader(); cursorTexture->unbind(); glDisable(GL_BLEND); diff --git a/src/libkwineffects/kwindeformeffect.cpp b/src/libkwineffects/kwindeformeffect.cpp index a14d905df4..54b97bd879 100644 --- a/src/libkwineffects/kwindeformeffect.cpp +++ b/src/libkwineffects/kwindeformeffect.cpp @@ -155,7 +155,7 @@ void DeformEffectPrivate::paint(EffectWindow *window, GLTexture *texture, const shader->setUniform(GLShader::Saturation, data.saturation()); texture->bind(); - vbo->draw(region, primitiveType, 0, verticesPerQuad * quads.count(), true); + vbo->draw(effects->mapToRenderTarget(region), primitiveType, 0, verticesPerQuad * quads.count(), true); texture->unbind(); glDisable(GL_BLEND); diff --git a/src/libkwineffects/kwineffects.cpp b/src/libkwineffects/kwineffects.cpp index 88401d5222..a038ffa1c2 100644 --- a/src/libkwineffects/kwineffects.cpp +++ b/src/libkwineffects/kwineffects.cpp @@ -780,6 +780,26 @@ bool EffectsHandler::isOpenGLCompositing() const return compositing_type & OpenGLCompositing; } +QRect EffectsHandler::mapToRenderTarget(const QRect &rect) const +{ + const QRect targetRect = renderTargetRect(); + const qreal targetScale = renderTargetScale(); + + return QRect((rect.x() - targetRect.x()) * targetScale, + (rect.y() - targetRect.y()) * targetScale, + rect.width() * targetScale, + rect.height() * targetScale); +} + +QRegion EffectsHandler::mapToRenderTarget(const QRegion ®ion) const +{ + QRegion result; + for (const QRect &rect : region) { + result += mapToRenderTarget(rect); + } + return result; +} + EffectsHandler* effects = nullptr; EffectScreen::EffectScreen(QObject *parent) diff --git a/src/libkwineffects/kwineffects.h b/src/libkwineffects/kwineffects.h index bcfd01829d..1a43ac636b 100644 --- a/src/libkwineffects/kwineffects.h +++ b/src/libkwineffects/kwineffects.h @@ -1433,6 +1433,26 @@ public: */ virtual void renderScreen(EffectScreen *screen) = 0; + /** + * Returns the rect that's currently being repainted, in the logical pixels. + */ + virtual QRect renderTargetRect() const = 0; + /** + * Returns the device pixel ratio of the current render target. + */ + virtual qreal renderTargetScale() const = 0; + + /** + * Maps the given @a rect from the global screen cordinates to the render + * target local coordinate system. + */ + QRect mapToRenderTarget(const QRect &rect) const; + /** + * Maps the given @a region from the global screen coordinates to the render + * target local coordinate system. + */ + QRegion mapToRenderTarget(const QRegion ®ion) const; + Q_SIGNALS: /** * This signal is emitted whenever a new @a screen is added to the system. diff --git a/src/libkwineffects/kwinglutils.cpp b/src/libkwineffects/kwinglutils.cpp index c39fdb13f3..201afddef2 100644 --- a/src/libkwineffects/kwinglutils.cpp +++ b/src/libkwineffects/kwinglutils.cpp @@ -910,11 +910,6 @@ GLShader *ShaderManager::loadShaderFromCode(const QByteArray &vertexSource, cons bool GLRenderTarget::sSupported = false; bool GLRenderTarget::s_blitSupported = false; QStack GLRenderTarget::s_renderTargets = QStack(); -QSize GLRenderTarget::s_virtualScreenSize; -QRect GLRenderTarget::s_virtualScreenGeometry; -qreal GLRenderTarget::s_virtualScreenScale = 1.0; -GLint GLRenderTarget::s_virtualScreenViewport[4]; -GLuint GLRenderTarget::s_kwinFramebuffer = 0; void GLRenderTarget::initStatic() { @@ -949,21 +944,20 @@ bool GLRenderTarget::blitSupported() return s_blitSupported; } +GLRenderTarget *GLRenderTarget::currentRenderTarget() +{ + return s_renderTargets.isEmpty() ? nullptr : s_renderTargets.top(); +} + void GLRenderTarget::pushRenderTarget(GLRenderTarget* target) { - if (s_renderTargets.isEmpty()) { - glGetIntegerv(GL_VIEWPORT, s_virtualScreenViewport); - } - target->enable(); + target->bind(); s_renderTargets.push(target); } void GLRenderTarget::pushRenderTargets(QStack targets) { - if (s_renderTargets.isEmpty()) { - glGetIntegerv(GL_VIEWPORT, s_virtualScreenViewport); - } - targets.top()->enable(); + targets.top()->bind(); s_renderTargets.append(targets); } @@ -973,10 +967,7 @@ GLRenderTarget* GLRenderTarget::popRenderTarget() ret->setTextureDirty(); if (!s_renderTargets.isEmpty()) { - s_renderTargets.top()->enable(); - } else { - ret->disable(); - glViewport (s_virtualScreenViewport[0], s_virtualScreenViewport[1], s_virtualScreenViewport[2], s_virtualScreenViewport[3]); + s_renderTargets.top()->bind(); } return ret; @@ -984,13 +975,12 @@ GLRenderTarget* GLRenderTarget::popRenderTarget() GLRenderTarget::GLRenderTarget() : mTexture(GL_TEXTURE_2D) - , mValid(false) { } GLRenderTarget::GLRenderTarget(const GLTexture& color) : mTexture(color) - , mValid(false) + , mSize(color.size()) { // Make sure FBO is supported if (sSupported && !mTexture.isNull()) { @@ -999,35 +989,31 @@ GLRenderTarget::GLRenderTarget(const GLTexture& color) qCCritical(LIBKWINGLUTILS) << "Render targets aren't supported!"; } +GLRenderTarget::GLRenderTarget(GLuint handle, const QSize &size) + : mTexture({}) + , mFramebuffer(handle) + , mSize(size) + , mValid(true) + , mForeign(true) +{ +} + GLRenderTarget::~GLRenderTarget() { - if (mValid) { + if (!mForeign && mValid) { glDeleteFramebuffers(1, &mFramebuffer); } } -bool GLRenderTarget::enable() +bool GLRenderTarget::bind() { if (!valid()) { qCCritical(LIBKWINGLUTILS) << "Can't enable invalid render target!"; return false; } - glBindFramebuffer(GL_FRAMEBUFFER, mFramebuffer); - glViewport(0, 0, mTexture.width(), mTexture.height()); - mTexture.setDirty(); - - return true; -} - -bool GLRenderTarget::disable() -{ - if (!valid()) { - qCCritical(LIBKWINGLUTILS) << "Can't disable invalid render target!"; - return false; - } - - glBindFramebuffer(GL_FRAMEBUFFER, s_kwinFramebuffer); + glBindFramebuffer(GL_FRAMEBUFFER, handle()); + glViewport(0, 0, mSize.width(), mSize.height()); mTexture.setDirty(); return true; @@ -1073,6 +1059,11 @@ void GLRenderTarget::initFBO() qCCritical(LIBKWINGLUTILS) << "Error status when entering GLRenderTarget::initFBO: " << formatGLError(err); #endif + GLuint prevFbo = 0; + if (const GLRenderTarget *current = currentRenderTarget()) { + prevFbo = current->handle(); + } + glGenFramebuffers(1, &mFramebuffer); #if DEBUG_GLRENDERTARGET @@ -1098,7 +1089,7 @@ void GLRenderTarget::initFBO() #if DEBUG_GLRENDERTARGET if ((err = glGetError()) != GL_NO_ERROR) { qCCritical(LIBKWINGLUTILS) << "glFramebufferTexture2D failed: " << formatGLError(err); - glBindFramebuffer(GL_FRAMEBUFFER, s_kwinFramebuffer); + glBindFramebuffer(GL_FRAMEBUFFER, prevFbo); glDeleteFramebuffers(1, &mFramebuffer); return; } @@ -1106,7 +1097,7 @@ void GLRenderTarget::initFBO() const GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); - glBindFramebuffer(GL_FRAMEBUFFER, s_kwinFramebuffer); + glBindFramebuffer(GL_FRAMEBUFFER, prevFbo); if (status != GL_FRAMEBUFFER_COMPLETE) { // We have an incomplete framebuffer, consider it invalid @@ -1127,18 +1118,27 @@ void GLRenderTarget::blitFromFramebuffer(const QRect &source, const QRect &desti return; } + const GLRenderTarget *top = currentRenderTarget(); GLRenderTarget::pushRenderTarget(this); - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, mFramebuffer); - glBindFramebuffer(GL_READ_FRAMEBUFFER, s_kwinFramebuffer); - const QRect s = source.isNull() ? s_virtualScreenGeometry : source; - const QRect d = destination.isNull() ? QRect(0, 0, mTexture.width(), mTexture.height()) : destination; - glBlitFramebuffer((s.x() - s_virtualScreenGeometry.x()) * s_virtualScreenScale, - (s_virtualScreenGeometry.height() - (s.y() - s_virtualScreenGeometry.y() + s.height())) * s_virtualScreenScale, - (s.x() - s_virtualScreenGeometry.x() + s.width()) * s_virtualScreenScale, - (s_virtualScreenGeometry.height() - (s.y() - s_virtualScreenGeometry.y())) * s_virtualScreenScale, - d.x(), mTexture.height() - d.y() - d.height(), d.x() + d.width(), mTexture.height() - d.y(), - GL_COLOR_BUFFER_BIT, filter); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, handle()); + glBindFramebuffer(GL_READ_FRAMEBUFFER, top->handle()); + + const QRect s = source.isNull() ? QRect(QPoint(0, 0), top->size()) : source; + const QRect d = destination.isNull() ? QRect(QPoint(0, 0), size()) : destination; + + const GLuint srcX0 = s.x(); + const GLuint srcY0 = top->size().height() - (s.y() + s.height()); + const GLuint srcX1 = s.x() + s.width(); + const GLuint srcY1 = top->size().height() - s.y(); + + const GLuint dstX0 = d.x(); + const GLuint dstY0 = mSize.height() - (d.y() + d.height()); + const GLuint dstX1 = d.x() + d.width(); + const GLuint dstY1 = mSize.height() - d.y(); + + glBlitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, GL_COLOR_BUFFER_BIT, filter); + GLRenderTarget::popRenderTarget(); } @@ -1811,8 +1811,6 @@ GLvoid *GLVertexBufferPrivate::mapNextFreeRange(size_t size) //********************************* // GLVertexBuffer //********************************* -QRect GLVertexBuffer::s_virtualScreenGeometry; -qreal GLVertexBuffer::s_virtualScreenScale; GLVertexBuffer::GLVertexBuffer(UsageHint hint) : d(new GLVertexBufferPrivate(hint)) @@ -1985,11 +1983,9 @@ void GLVertexBuffer::draw(const QRegion ®ion, GLenum primitiveMode, int first glDrawElementsBaseVertex(GL_TRIANGLES, count, GL_UNSIGNED_SHORT, nullptr, first); } else { // Clip using scissoring + const GLRenderTarget *renderTarget = GLRenderTarget::currentRenderTarget(); for (const QRect &r : region) { - glScissor((r.x() - s_virtualScreenGeometry.x()) * s_virtualScreenScale, - (s_virtualScreenGeometry.height() + s_virtualScreenGeometry.y() - r.y() - r.height()) * s_virtualScreenScale, - r.width() * s_virtualScreenScale, - r.height() * s_virtualScreenScale); + glScissor(r.x(), renderTarget->size().height() - (r.y() + r.height()), r.width(), r.height()); glDrawElementsBaseVertex(GL_TRIANGLES, count, GL_UNSIGNED_SHORT, nullptr, first); } } @@ -2000,11 +1996,9 @@ void GLVertexBuffer::draw(const QRegion ®ion, GLenum primitiveMode, int first glDrawArrays(primitiveMode, first, count); } else { // Clip using scissoring + const GLRenderTarget *renderTarget = GLRenderTarget::currentRenderTarget(); for (const QRect &r : region) { - glScissor((r.x() - s_virtualScreenGeometry.x()) * s_virtualScreenScale, - (s_virtualScreenGeometry.height() + s_virtualScreenGeometry.y() - r.y() - r.height()) * s_virtualScreenScale, - r.width() * s_virtualScreenScale, - r.height() * s_virtualScreenScale); + glScissor(r.x(), renderTarget->size().height() - (r.y() + r.height()), r.width(), r.height()); glDrawArrays(primitiveMode, first, count); } } diff --git a/src/libkwineffects/kwinglutils.h b/src/libkwineffects/kwinglutils.h index f8dacec79b..45b98184fd 100644 --- a/src/libkwineffects/kwinglutils.h +++ b/src/libkwineffects/kwinglutils.h @@ -401,21 +401,27 @@ public: * @param color texture where the scene will be rendered onto */ explicit GLRenderTarget(const GLTexture& color); + + /** + * Constructs a wrapper for an already created render target object. The GLRenderTarget + * does not take the ownership of the framebuffer object handle. + */ + GLRenderTarget(GLuint handle, const QSize &size); ~GLRenderTarget(); /** - * Enables this render target. - * All OpenGL commands from now on affect this render target until the - * @ref disable method is called + * Returns the framebuffer object handle to this render target object. */ - bool enable(); + GLuint handle() const { + return mFramebuffer; + } /** - * Disables this render target, activating whichever target was active - * when @ref enable was called. + * Returns the size of the color attachment to this render target object. */ - bool disable(); - - bool valid() const { + QSize size() const { + return mSize; + } + bool valid() const { return mValid; } @@ -428,6 +434,11 @@ public: return sSupported; } + /** + * Returns the last bound render target, or @c null if no render target is current. + */ + static GLRenderTarget *currentRenderTarget(); + /** * Pushes the render target stack of the input parameter in reverse order. * @param targets The stack of GLRenderTargets @@ -448,92 +459,37 @@ public: static bool blitSupported(); /** - * Blits the content of the current draw framebuffer into the texture attached to this FBO. + * Blits from @a source rectangle in the current render target to the @a destination rectangle in + * this render target. + * + * Be aware that framebuffer blitting may not be supported on all hardware. Use blitSupported() + * to check whether it is supported. + * + * The @a source and the @a destination rectangles can have different sizes. The @a filter indicates + * what filter will be used in case scaling needs to be performed. * - * Be aware that framebuffer blitting may not be supported on all hardware. Use blitSupported to check whether - * it is supported. - * @param source Geometry in screen coordinates which should be blitted, if not specified complete framebuffer is used - * @param destination Geometry in attached texture, if not specified complete texture is used as destination - * @param filter The filter to use if blitted content needs to be scaled. * @see blitSupported * @since 4.8 */ void blitFromFramebuffer(const QRect &source = QRect(), const QRect &destination = QRect(), GLenum filter = GL_LINEAR); - /** - * Sets the virtual screen size to @p s. - * @since 5.2 - */ - static void setVirtualScreenSize(const QSize &s) { - s_virtualScreenSize = s; - } - - /** - * Sets the virtual screen geometry to @p g. - * This is the geometry of the OpenGL window currently being rendered to - * in the virtual geometry space the rendering geometries use. - * @see virtualScreenGeometry - * @since 5.9 - */ - static void setVirtualScreenGeometry(const QRect &g) { - s_virtualScreenGeometry = g; - } - - /** - * The geometry of the OpenGL window currently being rendered to - * in the virtual geometry space the rendering system uses. - * @see setVirtualScreenGeometry - * @since 5.9 - */ - static QRect virtualScreenGeometry() { - return s_virtualScreenGeometry; - } - - /** - * The scale of the OpenGL window currently being rendered to - * - * @returns the ratio between the virtual geometry space the rendering - * system uses and the target - * @since 5.10 - */ - static void setVirtualScreenScale(qreal scale) { - s_virtualScreenScale = scale; - } - - static qreal virtualScreenScale() { - return s_virtualScreenScale; - } - - /** - * The framebuffer of KWin's OpenGL window or other object currently being rendered to - * - * @since 5.18 - */ - static void setKWinFramebuffer(GLuint fb) { - s_kwinFramebuffer = fb; - } - - protected: void initFBO(); - private: + bool bind(); + friend void KWin::cleanupGL(); static void cleanup(); static bool sSupported; static bool s_blitSupported; static QStack s_renderTargets; - static QSize s_virtualScreenSize; - static QRect s_virtualScreenGeometry; - static qreal s_virtualScreenScale; - static GLint s_virtualScreenViewport[4]; - static GLuint s_kwinFramebuffer; GLTexture mTexture; - bool mValid; - - GLuint mFramebuffer; + GLuint mFramebuffer = 0; + QSize mSize; + bool mValid = false; + bool mForeign = false; }; enum VertexAttributeType { @@ -759,31 +715,8 @@ public: */ static GLVertexBuffer *streamingBuffer(); - /** - * Sets the virtual screen geometry to @p g. - * This is the geometry of the OpenGL window currently being rendered to - * in the virtual geometry space the rendering geometries use. - * @since 5.9 - */ - static void setVirtualScreenGeometry(const QRect &g) { - s_virtualScreenGeometry = g; - } - - /** - * The scale of the OpenGL window currently being rendered to - * - * @returns the ratio between the virtual geometry space the rendering - * system uses and the target - * @since 5.11.3 - */ - static void setVirtualScreenScale(qreal s) { - s_virtualScreenScale = s; - } - private: GLVertexBufferPrivate* const d; - static QRect s_virtualScreenGeometry; - static qreal s_virtualScreenScale; }; } // namespace diff --git a/src/platformsupport/scenes/opengl/abstract_egl_backend.cpp b/src/platformsupport/scenes/opengl/abstract_egl_backend.cpp index 430ea82923..f3964494b3 100644 --- a/src/platformsupport/scenes/opengl/abstract_egl_backend.cpp +++ b/src/platformsupport/scenes/opengl/abstract_egl_backend.cpp @@ -370,10 +370,7 @@ QSharedPointer AbstractEglBackend::textureForOutput(AbstractOutput *r { QSharedPointer texture(new GLTexture(GL_RGBA8, requestedOutput->pixelSize())); GLRenderTarget renderTarget(*texture); - - const QRect geo = requestedOutput->geometry(); - QRect invGeo(geo.left(), geo.bottom(), geo.width(), -geo.height()); - renderTarget.blitFromFramebuffer(invGeo); + renderTarget.blitFromFramebuffer(QRect(0, texture->height(), texture->width(), -texture->height())); return texture; } diff --git a/src/plugins/screencast/outputscreencastsource.cpp b/src/plugins/screencast/outputscreencastsource.cpp index cefb728836..30e9edd454 100644 --- a/src/plugins/screencast/outputscreencastsource.cpp +++ b/src/plugins/screencast/outputscreencastsource.cpp @@ -58,7 +58,7 @@ void OutputScreenCastSource::render(GLRenderTarget *target) GLRenderTarget::pushRenderTarget(target); outputTexture->bind(); - outputTexture->render(geometry, geometry, true); + outputTexture->render(infiniteRegion(), geometry); outputTexture->unbind(); GLRenderTarget::popRenderTarget(); } diff --git a/src/plugins/screencast/screencaststream.cpp b/src/plugins/screencast/screencaststream.cpp index 260ef3aee7..e9b1a1e1df 100644 --- a/src/plugins/screencast/screencaststream.cpp +++ b/src/plugins/screencast/screencaststream.cpp @@ -11,6 +11,7 @@ #include "composite.h" #include "dmabuftexture.h" #include "eglnativefence.h" +#include "kwineffects.h" #include "kwinglplatform.h" #include "kwingltexture.h" #include "kwinglutils.h" @@ -426,7 +427,7 @@ void ScreenCastStream::recordFrame(const QRegion &damagedRegion) glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - m_cursor.texture->render(cursorRect, cursorRect, true); + m_cursor.texture->render(infiniteRegion(), cursorRect); glDisable(GL_BLEND); m_cursor.texture->unbind(); m_cursor.lastRect = cursorRect; diff --git a/src/scene.cpp b/src/scene.cpp index 53b6ca2006..935af25608 100644 --- a/src/scene.cpp +++ b/src/scene.cpp @@ -214,17 +214,51 @@ QMatrix4x4 Scene::createProjectionMatrix(const QRect &rect) return ret; } +QRect Scene::renderTargetRect() const +{ + return m_renderTargetRect; +} + +void Scene::setRenderTargetRect(const QRect &rect) +{ + m_renderTargetRect = rect; +} + +qreal Scene::renderTargetScale() const +{ + return m_renderTargetScale; +} + +void Scene::setRenderTargetScale(qreal scale) +{ + m_renderTargetScale = scale; +} + +QRegion Scene::mapToRenderTarget(const QRegion ®ion) const +{ + QRegion result; + for (const QRect &rect : region) { + result += QRect((rect.x() - m_renderTargetRect.x()) * m_renderTargetScale, + (rect.y() - m_renderTargetRect.y()) * m_renderTargetScale, + rect.width() * m_renderTargetScale, + rect.height() * m_renderTargetScale); + } + return result; +} + void Scene::paintScreen(AbstractOutput *output, const QList &toplevels) { createStackingOrder(toplevels); - - const QRect geo = output->geometry(); - QRegion update = geo, repaint = geo, valid; painted_screen = output; - paintScreen(geo, repaint, &update, &valid, output->renderLoop(), createProjectionMatrix(output->geometry())); + setRenderTargetRect(output->geometry()); + setRenderTargetScale(output->scale()); + + QRegion update, valid; + paintScreen(renderTargetRect(), QRect(), &update, &valid, output->renderLoop(), createProjectionMatrix(renderTargetRect())); clearStackingOrder(); } + // returns mask and possibly modified region void Scene::paintScreen(const QRegion &damage, const QRegion &repaint, QRegion *updateRegion, QRegion *validRegion, RenderLoop *renderLoop, diff --git a/src/scene.h b/src/scene.h index 14411fdca3..d1f94e9d81 100644 --- a/src/scene.h +++ b/src/scene.h @@ -191,6 +191,13 @@ public: static QMatrix4x4 createProjectionMatrix(const QRect &rect); + QRect renderTargetRect() const; + void setRenderTargetRect(const QRect &rect); + qreal renderTargetScale() const; + void setRenderTargetScale(qreal scale); + + QRegion mapToRenderTarget(const QRegion ®ion) const; + Q_SIGNALS: void frameRendered(); @@ -266,6 +273,8 @@ private: QHash< Toplevel*, Window* > m_windows; QMap m_repaints; QRect m_geometry; + QRect m_renderTargetRect; + qreal m_renderTargetScale = 1; // how many times finalPaintScreen() has been called int m_paintScreenCount = 0; QRect m_lastCursorGeometry; diff --git a/src/scenes/opengl/lanczosfilter.cpp b/src/scenes/opengl/lanczosfilter.cpp index afd7207715..4d80cb09e3 100644 --- a/src/scenes/opengl/lanczosfilter.cpp +++ b/src/scenes/opengl/lanczosfilter.cpp @@ -184,6 +184,11 @@ void LanczosFilter::performPaint(EffectWindowImpl* w, int mask, QRegion region, int sw = width; int sh = height; + QRegion scissor = infiniteRegion(); + if (hardwareClipping) { + scissor = m_scene->mapToRenderTarget(region); + } + GLTexture *cachedTexture = static_cast< GLTexture*>(w->data(LanczosCacheRole).value()); if (cachedTexture) { if (cachedTexture->width() == tw && cachedTexture->height() == th) { @@ -206,7 +211,7 @@ void LanczosFilter::performPaint(EffectWindowImpl* w, int mask, QRegion region, shader->setUniform(GLShader::ModulationConstant, QVector4D(rgb, rgb, rgb, a)); shader->setUniform(GLShader::Saturation, data.saturation()); - cachedTexture->render(region, textureRect, hardwareClipping); + cachedTexture->render(scissor, textureRect, hardwareClipping); glDisable(GL_BLEND); if (hardwareClipping) { @@ -344,7 +349,7 @@ void LanczosFilter::performPaint(EffectWindowImpl* w, int mask, QRegion region, shader->setUniform(GLShader::ModulationConstant, QVector4D(rgb, rgb, rgb, a)); shader->setUniform(GLShader::Saturation, data.saturation()); - cache->render(region, textureRect, hardwareClipping); + cache->render(scissor, textureRect, hardwareClipping); glDisable(GL_BLEND); diff --git a/src/scenes/opengl/scene_opengl.cpp b/src/scenes/opengl/scene_opengl.cpp index 8e585f64c7..f1acc6b0aa 100644 --- a/src/scenes/opengl/scene_opengl.cpp +++ b/src/scenes/opengl/scene_opengl.cpp @@ -194,14 +194,13 @@ void SceneOpenGL::paint(AbstractOutput *output, const QRegion &damage, const QLi QRegion update; QRegion valid; QRegion repaint; - QRect geo; - qreal scaling; + if (output) { - geo = output->geometry(); - scaling = output->scale(); + setRenderTargetRect(output->geometry()); + setRenderTargetScale(output->scale()); } else { - geo = geometry(); - scaling = 1; + setRenderTargetRect(geometry()); + setRenderTargetScale(1); } renderLoop->beginFrame(); @@ -249,14 +248,9 @@ void SceneOpenGL::paint(AbstractOutput *output, const QRegion &damage, const QLi repaint = m_backend->beginFrame(output); GLVertexBuffer::streamingBuffer()->beginFrame(); - GLVertexBuffer::setVirtualScreenGeometry(geo); - GLRenderTarget::setVirtualScreenGeometry(geo); - GLVertexBuffer::setVirtualScreenScale(scaling); - GLRenderTarget::setVirtualScreenScale(scaling); + updateProjectionMatrix(renderTargetRect()); - updateProjectionMatrix(geo); - - paintScreen(damage.intersected(geo), repaint, &update, &valid, + paintScreen(damage.intersected(renderTargetRect()), repaint, &update, &valid, renderLoop, projectionMatrix()); // call generic implementation paintCursor(output, valid); @@ -815,6 +809,12 @@ void OpenGLWindow::performPaint(int mask, const QRegion ®ion, const WindowPai float opacity = -1.0; + // The scissor region must be in the render target local coordinate system. + QRegion scissorRegion = infiniteRegion(); + if (renderContext.hardwareClipping) { + scissorRegion = m_scene->mapToRenderTarget(region); + } + const QMatrix4x4 modelViewProjection = modelViewProjectionMatrix(mask, data); for (int i = 0; i < renderContext.renderNodes.count(); i++) { const RenderNode &renderNode = renderContext.renderNodes[i]; @@ -835,7 +835,7 @@ void OpenGLWindow::performPaint(int mask, const QRegion ®ion, const WindowPai renderNode.texture->setWrapMode(GL_CLAMP_TO_EDGE); renderNode.texture->bind(); - vbo->draw(region, primitiveType, renderNode.firstVertex, + vbo->draw(scissorRegion, primitiveType, renderNode.firstVertex, renderNode.vertexCount, renderContext.hardwareClipping); }