kwineffects: Make GLRenderTarget and GLVertexBuffer work without global coords and scale

Because the GLRenderTarget and the GLVertexBuffer use the global
coordinate system, they are not ergonomic in render layers.

Assigning the device pixel ratio to GLRenderTarget and GLVertexBuffer is
an interesting api design choice too. Scaling is a window system
abstraction, which is absent in OpenGL or Vulkan. For example, it's not
possible to create an OpenGL texture with a scale factor of 2. It only
works with device pixels.

This change makes the GLRenderTarget and the GLVertexBuffer more
ergonomic for usages other than rendering the workspace by removing all
the global coordinate system and scaling stuff. That's the
responsibility of the users of those two classes.
This commit is contained in:
Vlad Zahorodnii 2022-02-06 14:07:48 +02:00
parent d92afc849e
commit 52beb213e7
38 changed files with 330 additions and 288 deletions

View file

@ -96,21 +96,24 @@ std::optional<QRegion> 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<GLTexture> EglGbmLayer::texture() const
{
if (m_shadowBuffer) {
const auto glTexture = QSharedPointer<KWin::GLTexture>::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) {

View file

@ -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<DrmGbmBuffer> GbmSurface::currentDrmBuffer() const
return m_currentDrmBuffer;
}
GLRenderTarget *GbmSurface::renderTarget() const
{
return m_renderTarget.data();
}
EGLSurface GbmSurface::eglSurface() const
{
return m_eglSurface;

View file

@ -23,6 +23,8 @@ struct gbm_surface;
namespace KWin
{
class GLRenderTarget;
class GbmSurface
{
public:
@ -38,6 +40,7 @@ public:
QSharedPointer<GbmBuffer> currentBuffer() const;
QSharedPointer<DrmGbmBuffer> currentDrmBuffer() const;
GLRenderTarget *renderTarget() const;
EGLSurface eglSurface() const;
QSize size() const;
@ -60,6 +63,7 @@ private:
QSharedPointer<GbmBuffer> m_currentBuffer;
QSharedPointer<DrmGbmBuffer> m_currentDrmBuffer;
QVector<GbmBuffer*> m_lockedBuffers;
QScopedPointer<GLRenderTarget> m_renderTarget;
};
}

View file

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

View file

@ -26,18 +26,16 @@ public:
bool isComplete() const;
void bind();
void render(DrmAbstractOutput *output);
int texture() const;
QSize textureSize() const;
GLRenderTarget *renderTarget() const;
QSharedPointer<GLTexture> texture() const;
uint32_t drmFormat() const;
private:
GLint internalFormat(const GbmFormat &format) const;
GLuint m_texture;
GLuint m_framebuffer;
QSharedPointer<GLTexture> m_texture;
QScopedPointer<GLRenderTarget> m_renderTarget;
QScopedPointer<GLVertexBuffer> m_vbo;
const QSize m_size;
const uint32_t m_drmFormat;

View file

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

View file

@ -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<GLRenderTarget> m_renderTarget;
friend class EglWaylandBackend;
};

View file

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

View file

@ -42,6 +42,7 @@ private:
X11StandalonePlatform *m_backend;
SoftwareVsyncMonitor *m_vsyncMonitor;
DamageJournal m_damageJournal;
QScopedPointer<GLRenderTarget> m_renderTarget;
int m_bufferAge = 0;
};

View file

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

View file

@ -107,6 +107,7 @@ private:
QHash<xcb_visualid_t, FBConfigInfo *> m_fbconfigHash;
QHash<xcb_visualid_t, int> m_visualDepthHash;
std::unique_ptr<SwapEventFilter> m_swapEventFilter;
QScopedPointer<GLRenderTarget> m_renderTarget;
DamageJournal m_damageJournal;
int m_bufferAge;
bool m_haveMESACopySubBuffer = false;

View file

@ -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<X11WindowedOutput *>(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)

View file

@ -9,6 +9,7 @@
#ifndef KWIN_EGL_X11_BACKEND_H
#define KWIN_EGL_X11_BACKEND_H
#include "eglonxbackend.h"
#include "kwinglutils.h"
#include <QMap>
@ -17,6 +18,13 @@ namespace KWin
class X11WindowedBackend;
class EglX11Output
{
public:
EGLSurface m_eglSurface;
QScopedPointer<GLRenderTarget> 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<AbstractOutput *, EGLSurface> m_surfaces;
QMap<AbstractOutput *, EglX11Output *> m_outputs;
X11WindowedBackend *m_backend;
};

View file

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

View file

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

View file

@ -427,8 +427,8 @@ bool ContrastEffect::shouldContrast(const EffectWindow *w, int mask, const Windo
void ContrastEffect::drawWindow(EffectWindow *w, int mask, const QRegion &region, 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());

View file

@ -607,8 +607,8 @@ bool BlurEffect::shouldBlur(const EffectWindow *w, int mask, const WindowPaintDa
void BlurEffect::drawWindow(EffectWindow *w, int mask, const QRegion &region, 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();

View file

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

View file

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

View file

@ -126,7 +126,7 @@ void MagnifierEffect::paintScreen(int mask, const QRegion &region, 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);

View file

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

View file

@ -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 &region, 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();

View file

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

View file

@ -229,7 +229,7 @@ void StartupFeedbackEffect::paintScreen(int mask, const QRegion &region, 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);

View file

@ -119,7 +119,7 @@ void TrackMouseEffect::paintScreen(int mask, const QRegion &region, 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);

View file

@ -344,7 +344,7 @@ void ZoomEffect::paintScreen(int mask, const QRegion &region, 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);

View file

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

View file

@ -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 &region) const
{
QRegion result;
for (const QRect &rect : region) {
result += mapToRenderTarget(rect);
}
return result;
}
EffectsHandler* effects = nullptr;
EffectScreen::EffectScreen(QObject *parent)

View file

@ -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 &region) const;
Q_SIGNALS:
/**
* This signal is emitted whenever a new @a screen is added to the system.

View file

@ -910,11 +910,6 @@ GLShader *ShaderManager::loadShaderFromCode(const QByteArray &vertexSource, cons
bool GLRenderTarget::sSupported = false;
bool GLRenderTarget::s_blitSupported = false;
QStack<GLRenderTarget*> GLRenderTarget::s_renderTargets = QStack<GLRenderTarget*>();
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 <GLRenderTarget*> 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 &region, 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 &region, 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);
}
}

View file

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

View file

@ -370,10 +370,7 @@ QSharedPointer<GLTexture> AbstractEglBackend::textureForOutput(AbstractOutput *r
{
QSharedPointer<GLTexture> 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;
}

View file

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

View file

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

View file

@ -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 &region) 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<Toplevel *> &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,

View file

@ -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 &region) const;
Q_SIGNALS:
void frameRendered();
@ -266,6 +273,8 @@ private:
QHash< Toplevel*, Window* > m_windows;
QMap<AbstractOutput *, QRegion> 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;

View file

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

View file

@ -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 &region, 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 &region, 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);
}