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:
parent
d92afc849e
commit
52beb213e7
38 changed files with 330 additions and 288 deletions
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -42,6 +42,7 @@ private:
|
|||
X11StandalonePlatform *m_backend;
|
||||
SoftwareVsyncMonitor *m_vsyncMonitor;
|
||||
DamageJournal m_damageJournal;
|
||||
QScopedPointer<GLRenderTarget> m_renderTarget;
|
||||
int m_bufferAge = 0;
|
||||
};
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
@ -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
|
||||
//****************************************
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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());
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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])));
|
||||
|
|
|
@ -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());
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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 ®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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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<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,
|
||||
|
|
|
@ -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<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;
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue