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 ®ion, 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"