KWin
Loading...
Searching...
No Matches
screencastutils.h
Go to the documentation of this file.
1/*
2 SPDX-FileCopyrightText: 2021 Aleix Pol Gonzalez <aleixpol@kde.org>
3
4 SPDX-License-Identifier: LGPL-2.0-or-later
5*/
6
7#pragma once
8
9#include "opengl/glplatform.h"
10#include "opengl/gltexture.h"
11#include "opengl/glutils.h"
12#include <spa/buffer/buffer.h>
13#include <spa/param/video/raw.h>
14
15namespace KWin
16{
17
18// in-place vertical mirroring
19static void mirrorVertically(uchar *data, int height, int stride)
20{
21 const int halfHeight = height / 2;
22 std::vector<uchar> temp(stride);
23 for (int y = 0; y < halfHeight; ++y) {
24 auto cur = &data[y * stride], dest = &data[(height - y - 1) * stride];
25 memcpy(temp.data(), cur, stride);
26 memcpy(cur, dest, stride);
27 memcpy(dest, temp.data(), stride);
28 }
29}
30
31static GLenum closestGLType(spa_video_format format)
32{
33 switch (format) {
34 case SPA_VIDEO_FORMAT_RGB:
35 return GL_RGB;
36 case SPA_VIDEO_FORMAT_BGR:
37 return GL_BGR;
38 case SPA_VIDEO_FORMAT_RGBx:
39 case SPA_VIDEO_FORMAT_RGBA:
40 return GL_RGBA;
41 case SPA_VIDEO_FORMAT_BGRA:
42 case SPA_VIDEO_FORMAT_BGRx:
43 return GL_BGRA;
44 default:
45 qDebug() << "unknown format" << format;
46 return GL_RGBA;
47 }
48}
49
50static void doGrabTexture(GLTexture *texture, spa_data *spa, spa_video_format format)
51{
52 const QSize size = texture->size();
53 const bool invertNeeded = GLPlatform::instance()->isGLES() ^ (texture->contentTransform() != OutputTransform::FlipY);
54 const bool invertNeededAndSupported = invertNeeded && GLPlatform::instance()->supports(GLFeature::PackInvert);
55 GLboolean prev;
56 if (invertNeededAndSupported) {
57 glGetBooleanv(GL_PACK_INVERT_MESA, &prev);
58 glPixelStorei(GL_PACK_INVERT_MESA, GL_TRUE);
59 }
60
61 texture->bind();
62 // BUG: The nvidia driver fails to glGetTexImage
63 // Drop driver() == DriverNVidia some time after that's fixed
64 if (GLPlatform::instance()->isGLES() || GLPlatform::instance()->driver() == Driver_NVidia) {
65 GLFramebuffer fbo(texture);
67 glReadPixels(0, 0, size.width(), size.height(), closestGLType(format), GL_UNSIGNED_BYTE, spa->data);
69 } else if (GLPlatform::instance()->glVersion() >= Version(4, 5)) {
70 glGetTextureImage(texture->texture(), 0, closestGLType(format), GL_UNSIGNED_BYTE, spa->chunk->size, spa->data);
71 } else {
72 glGetTexImage(texture->target(), 0, closestGLType(format), GL_UNSIGNED_BYTE, spa->data);
73 }
74
75 if (invertNeededAndSupported) {
76 if (!prev) {
77 glPixelStorei(GL_PACK_INVERT_MESA, prev);
78 }
79 } else if (invertNeeded) {
80 mirrorVertically(static_cast<uchar *>(spa->data), size.height(), spa->chunk->stride);
81 }
82}
83
84static void grabTexture(GLTexture *texture, spa_data *spa, spa_video_format format)
85{
86 const OutputTransform contentTransform = texture->contentTransform();
87 if (contentTransform == OutputTransform::Normal || contentTransform == OutputTransform::FlipY) {
88 doGrabTexture(texture, spa, format);
89 } else {
90 const QSize size = contentTransform.map(texture->size());
91 const auto backingTexture = GLTexture::allocate(GL_RGBA8, size);
92 if (!backingTexture) {
93 return;
94 }
95 backingTexture->setContentTransform(OutputTransform::FlipY);
96
97 ShaderBinder shaderBinder(ShaderTrait::MapTexture);
98 QMatrix4x4 projectionMatrix;
99 projectionMatrix.scale(1, -1);
100 projectionMatrix.ortho(QRect(QPoint(), size));
101 shaderBinder.shader()->setUniform(GLShader::Mat4Uniform::ModelViewProjectionMatrix, projectionMatrix);
102
103 GLFramebuffer fbo(backingTexture.get());
105 texture->render(size);
107 doGrabTexture(backingTexture.get(), spa, format);
108 }
109}
110
111} // namespace KWin
static GLFramebuffer * popFramebuffer()
static void pushFramebuffer(GLFramebuffer *fbo)
static GLPlatform * instance()
Definition glplatform.h:394
bool isGLES() const
bool supports(GLFeature feature) const
static std::unique_ptr< GLTexture > allocate(GLenum internalFormat, const QSize &size, int levels=1)
@ Driver_NVidia
Definition glplatform.h:54
GLenum format
Definition gltexture.cpp:49