File indexing completed on 2024-11-10 04:57:06

0001 /*
0002     SPDX-FileCopyrightText: 2022 Aleix Pol Gonzalez <aleixpol@kde.org>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 #include "regionscreencastsource.h"
0008 #include "screencastutils.h"
0009 
0010 #include "opengl/gltexture.h"
0011 #include "opengl/glutils.h"
0012 #include <compositor.h>
0013 #include <core/output.h>
0014 #include <drm_fourcc.h>
0015 #include <scene/workspacescene.h>
0016 #include <workspace.h>
0017 
0018 #include <QPainter>
0019 
0020 namespace KWin
0021 {
0022 
0023 RegionScreenCastSource::RegionScreenCastSource(const QRect &region, qreal scale, QObject *parent)
0024     : ScreenCastSource(parent)
0025     , m_region(region)
0026     , m_scale(scale)
0027 {
0028     Q_ASSERT(m_region.isValid());
0029     Q_ASSERT(m_scale > 0);
0030 }
0031 
0032 QSize RegionScreenCastSource::textureSize() const
0033 {
0034     return m_region.size() * m_scale;
0035 }
0036 
0037 bool RegionScreenCastSource::hasAlphaChannel() const
0038 {
0039     return true;
0040 }
0041 
0042 quint32 RegionScreenCastSource::drmFormat() const
0043 {
0044     return DRM_FORMAT_ARGB8888;
0045 }
0046 
0047 void RegionScreenCastSource::updateOutput(Output *output)
0048 {
0049     m_last = output->renderLoop()->lastPresentationTimestamp();
0050 
0051     if (m_renderedTexture) {
0052         const auto [outputTexture, colorDescription] = Compositor::self()->scene()->textureForOutput(output);
0053         const auto outputGeometry = output->geometry();
0054         if (!outputTexture || !m_region.intersects(output->geometry())) {
0055             return;
0056         }
0057 
0058         GLFramebuffer::pushFramebuffer(m_target.get());
0059 
0060         ShaderBinder shaderBinder(ShaderTrait::MapTexture | ShaderTrait::TransformColorspace);
0061         QMatrix4x4 projectionMatrix;
0062         projectionMatrix.ortho(m_region);
0063         projectionMatrix.translate(outputGeometry.left(), outputGeometry.top());
0064 
0065         shaderBinder.shader()->setUniform(GLShader::Mat4Uniform::ModelViewProjectionMatrix, projectionMatrix);
0066         shaderBinder.shader()->setColorspaceUniformsToSRGB(colorDescription);
0067 
0068         outputTexture->render(outputGeometry.size());
0069         GLFramebuffer::popFramebuffer();
0070     }
0071 }
0072 
0073 std::chrono::nanoseconds RegionScreenCastSource::clock() const
0074 {
0075     return m_last;
0076 }
0077 
0078 void RegionScreenCastSource::ensureTexture()
0079 {
0080     if (!m_renderedTexture) {
0081         m_renderedTexture = GLTexture::allocate(GL_RGBA8, textureSize());
0082         if (!m_renderedTexture) {
0083             return;
0084         }
0085         m_renderedTexture->setFilter(GL_LINEAR);
0086         m_renderedTexture->setWrapMode(GL_CLAMP_TO_EDGE);
0087 
0088         m_target = std::make_unique<GLFramebuffer>(m_renderedTexture.get());
0089         const auto allOutputs = workspace()->outputs();
0090         for (auto output : allOutputs) {
0091             if (output->geometry().intersects(m_region)) {
0092                 updateOutput(output);
0093             }
0094         }
0095     }
0096 }
0097 
0098 void RegionScreenCastSource::render(GLFramebuffer *target)
0099 {
0100     ensureTexture();
0101 
0102     GLFramebuffer::pushFramebuffer(target);
0103     auto shader = ShaderManager::instance()->pushShader(ShaderTrait::MapTexture);
0104 
0105     QMatrix4x4 projectionMatrix;
0106     projectionMatrix.scale(1, -1);
0107     projectionMatrix.ortho(QRect(QPoint(), target->size()));
0108     shader->setUniform(GLShader::Mat4Uniform::ModelViewProjectionMatrix, projectionMatrix);
0109 
0110     m_renderedTexture->render(target->size());
0111 
0112     ShaderManager::instance()->popShader();
0113     GLFramebuffer::popFramebuffer();
0114 }
0115 
0116 void RegionScreenCastSource::render(spa_data *spa, spa_video_format format)
0117 {
0118     ensureTexture();
0119     grabTexture(m_renderedTexture.get(), spa, format);
0120 }
0121 
0122 uint RegionScreenCastSource::refreshRate() const
0123 {
0124     uint ret = 0;
0125     const auto allOutputs = workspace()->outputs();
0126     for (auto output : allOutputs) {
0127         if (output->geometry().intersects(m_region)) {
0128             ret = std::max<uint>(ret, output->refreshRate());
0129         }
0130     }
0131     return ret;
0132 }
0133 }
0134 
0135 #include "moc_regionscreencastsource.cpp"