File indexing completed on 2024-05-12 05:32:05

0001 /*
0002     SPDX-FileCopyrightText: 2022 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 #include "scene/cursordelegate_opengl.h"
0008 #include "compositor.h"
0009 #include "core/output.h"
0010 #include "core/pixelgrid.h"
0011 #include "core/renderlayer.h"
0012 #include "core/rendertarget.h"
0013 #include "core/renderviewport.h"
0014 #include "cursor.h"
0015 #include "opengl/gltexture.h"
0016 #include "opengl/glutils.h"
0017 #include "scene/cursorscene.h"
0018 
0019 #include <cmath>
0020 
0021 namespace KWin
0022 {
0023 
0024 CursorDelegateOpenGL::CursorDelegateOpenGL(Output *output)
0025     : m_output(output)
0026 {
0027 }
0028 
0029 CursorDelegateOpenGL::~CursorDelegateOpenGL()
0030 {
0031 }
0032 
0033 void CursorDelegateOpenGL::paint(const RenderTarget &renderTarget, const QRegion &region)
0034 {
0035     const QRegion dirty = region.intersected(layer()->mapToGlobal(layer()->rect()).toAlignedRect());
0036     if (dirty.isEmpty()) {
0037         return;
0038     }
0039 
0040     // Show the rendered cursor scene on the screen.
0041     const QRect cursorRect = snapToPixelGrid(scaledRect(layer()->mapToGlobal(layer()->rect()), m_output->scale()));
0042 
0043     // Render the cursor scene in an offscreen render target.
0044     const QSize bufferSize = cursorRect.size();
0045     const GLenum bufferFormat = renderTarget.colorDescription() == ColorDescription::sRGB ? GL_RGBA8 : GL_RGBA16F;
0046     if (!m_texture || m_texture->size() != bufferSize || m_texture->internalFormat() != bufferFormat) {
0047         m_texture = GLTexture::allocate(bufferFormat, bufferSize);
0048         if (!m_texture) {
0049             return;
0050         }
0051         m_framebuffer = std::make_unique<GLFramebuffer>(m_texture.get());
0052     }
0053 
0054     RenderTarget offscreenRenderTarget(m_framebuffer.get(), renderTarget.colorDescription());
0055 
0056     RenderLayer renderLayer(layer()->loop());
0057     renderLayer.setDelegate(std::make_unique<SceneDelegate>(Compositor::self()->cursorScene(), m_output));
0058     renderLayer.delegate()->prePaint();
0059     renderLayer.delegate()->paint(offscreenRenderTarget, infiniteRegion());
0060     renderLayer.delegate()->postPaint();
0061 
0062     QMatrix4x4 mvp;
0063     mvp.scale(1, -1); // flip the y axis back
0064     mvp *= renderTarget.transform().toMatrix();
0065     mvp.scale(1, -1); // undo ortho() flipping the y axis
0066     mvp.ortho(QRectF(QPointF(0, 0), m_output->transform().map(renderTarget.size())));
0067     mvp.translate(cursorRect.x(), cursorRect.y());
0068 
0069     GLFramebuffer *fbo = renderTarget.framebuffer();
0070     GLFramebuffer::pushFramebuffer(fbo);
0071 
0072     const bool clipping = region != infiniteRegion();
0073     const QRegion clipRegion = clipping ? RenderViewport(m_output->rectF(), m_output->scale(), renderTarget).mapToRenderTarget(dirty) : infiniteRegion();
0074 
0075     if (clipping) {
0076         glEnable(GL_SCISSOR_TEST);
0077     }
0078 
0079     // Don't need to call GLVertexBuffer::beginFrame() and GLVertexBuffer::endOfFrame() because
0080     // the GLVertexBuffer::streamingBuffer() is not being used when painting cursor.
0081     glEnable(GL_BLEND);
0082     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
0083 
0084     ShaderBinder binder(ShaderTrait::MapTexture);
0085     binder.shader()->setUniform(GLShader::Mat4Uniform::ModelViewProjectionMatrix, mvp);
0086     m_texture->render(clipRegion, cursorRect.size(), clipping);
0087     glDisable(GL_BLEND);
0088 
0089     if (clipping) {
0090         glDisable(GL_SCISSOR_TEST);
0091     }
0092 
0093     GLFramebuffer::popFramebuffer();
0094 }
0095 
0096 } // namespace KWin
0097 
0098 #include "moc_cursordelegate_opengl.cpp"