mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-04-19 07:37:11 +02:00
Start OpenGL renderer for group calls.
This commit is contained in:
parent
ca4b1e6ae0
commit
3e79b67032
2 changed files with 238 additions and 2 deletions
|
@ -20,6 +20,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "lang/lang_keys.h"
|
||||
#include "styles/style_calls.h"
|
||||
|
||||
#include "core/application.h"
|
||||
|
||||
#include <QtGui/QWindow>
|
||||
|
||||
namespace Calls::Group {
|
||||
|
@ -43,6 +45,41 @@ struct LargeVideo::PinButton {
|
|||
bool shown = false;
|
||||
};
|
||||
|
||||
class LargeVideo::RendererGL : public Ui::GL::Renderer {
|
||||
public:
|
||||
explicit RendererGL(not_null<LargeVideo*> owner) : _owner(owner) {
|
||||
}
|
||||
~RendererGL();
|
||||
|
||||
void init(
|
||||
not_null<QOpenGLWidget*> widget,
|
||||
not_null<QOpenGLFunctions*> f) override;
|
||||
|
||||
void resize(
|
||||
not_null<QOpenGLWidget*> widget,
|
||||
not_null<QOpenGLFunctions*> f,
|
||||
int w,
|
||||
int h) override;
|
||||
|
||||
void paint(
|
||||
not_null<QOpenGLWidget*> widget,
|
||||
not_null<QOpenGLFunctions*> f) override;
|
||||
|
||||
private:
|
||||
void deinit(not_null<QOpenGLContext*> context);
|
||||
|
||||
const not_null<LargeVideo*> _owner;
|
||||
|
||||
std::array<GLuint, 3> _textures = {};
|
||||
GLuint _vertexBuffer = 0;
|
||||
GLuint _vertexShader = 0;
|
||||
GLuint _fragmentShader = 0;
|
||||
GLuint _shaderProgram = 0;
|
||||
qint64 _key = 0;
|
||||
QMetaObject::Connection _connection;
|
||||
|
||||
};
|
||||
|
||||
LargeVideo::PinButton::PinButton(
|
||||
not_null<QWidget*> parent,
|
||||
const style::GroupCallLargeVideo &st)
|
||||
|
@ -55,6 +92,198 @@ LargeVideo::PinButton::PinButton(
|
|||
st::radialBg) {
|
||||
}
|
||||
|
||||
LargeVideo::RendererGL::~RendererGL() {
|
||||
}
|
||||
|
||||
void LargeVideo::RendererGL::init(
|
||||
not_null<QOpenGLWidget*> widget,
|
||||
not_null<QOpenGLFunctions*> f) {
|
||||
if (_connection) {
|
||||
QObject::disconnect(_connection);
|
||||
}
|
||||
const auto context = widget->context();
|
||||
_connection = QObject::connect(
|
||||
context,
|
||||
&QOpenGLContext::aboutToBeDestroyed,
|
||||
[=] { deinit(context); });
|
||||
|
||||
f->glGenTextures(3, _textures.data());
|
||||
for (const auto texture : _textures) {
|
||||
f->glBindTexture(GL_TEXTURE_2D, texture);
|
||||
const auto clamp = GL_CLAMP_TO_EDGE;
|
||||
f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, clamp);
|
||||
f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, clamp);
|
||||
f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
}
|
||||
f->glGenBuffers(1, &_vertexBuffer);
|
||||
|
||||
const char *vertexShaderSource = R"(
|
||||
#version 130
|
||||
in vec2 position;
|
||||
in vec2 texcoord;
|
||||
out vec2 v_texcoord;
|
||||
void main() {
|
||||
gl_Position = vec4(position.x, position.y, 0.0, 1.0);
|
||||
v_texcoord = texcoord;
|
||||
}
|
||||
)";
|
||||
_vertexShader = f->glCreateShader(GL_VERTEX_SHADER);
|
||||
f->glShaderSource(_vertexShader, 1, &vertexShaderSource, NULL);
|
||||
f->glCompileShader(_vertexShader);
|
||||
|
||||
{
|
||||
int success;
|
||||
char infoLog[512];
|
||||
f->glGetShaderiv(_vertexShader, GL_COMPILE_STATUS, &success);
|
||||
if (!success) {
|
||||
f->glGetShaderInfoLog(_vertexShader, 512, NULL, infoLog);
|
||||
}
|
||||
int a = 0;
|
||||
}
|
||||
|
||||
const char *fragmentShaderSource = R"(
|
||||
#version 130
|
||||
in vec2 v_texcoord;
|
||||
uniform sampler2D s_texture;
|
||||
out vec4 fragColor;
|
||||
void main() {
|
||||
vec4 color = texture(s_texture, v_texcoord);
|
||||
fragColor = vec4(color.b, color.g, color.r, color.a);
|
||||
}
|
||||
)";
|
||||
// ;
|
||||
_fragmentShader = f->glCreateShader(GL_FRAGMENT_SHADER);
|
||||
f->glShaderSource(_fragmentShader, 1, &fragmentShaderSource, NULL);
|
||||
f->glCompileShader(_fragmentShader);
|
||||
|
||||
{
|
||||
int success;
|
||||
char infoLog[512];
|
||||
f->glGetShaderiv(_fragmentShader, GL_COMPILE_STATUS, &success);
|
||||
if (!success) {
|
||||
f->glGetShaderInfoLog(_fragmentShader, 512, NULL, infoLog);
|
||||
}
|
||||
int a = 0;
|
||||
}
|
||||
|
||||
_shaderProgram = f->glCreateProgram();
|
||||
f->glAttachShader(_shaderProgram, _vertexShader);
|
||||
f->glAttachShader(_shaderProgram, _fragmentShader);
|
||||
f->glLinkProgram(_shaderProgram);
|
||||
|
||||
{
|
||||
int success;
|
||||
char infoLog[512];
|
||||
f->glGetProgramiv(_shaderProgram, GL_LINK_STATUS, &success);
|
||||
if (!success) {
|
||||
f->glGetProgramInfoLog(_shaderProgram, 512, NULL, infoLog);
|
||||
}
|
||||
int a = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void LargeVideo::RendererGL::deinit(not_null<QOpenGLContext*> context) {
|
||||
context->functions()->glDeleteTextures(_textures.size(), _textures.data());
|
||||
context->functions()->glDeleteBuffers(1, &_vertexBuffer);
|
||||
context->functions()->glDeleteProgram(_shaderProgram);
|
||||
context->functions()->glDeleteShader(_vertexShader);
|
||||
context->functions()->glDeleteShader(_fragmentShader);
|
||||
}
|
||||
|
||||
void LargeVideo::RendererGL::resize(
|
||||
not_null<QOpenGLWidget*> widget,
|
||||
not_null<QOpenGLFunctions*> f,
|
||||
int w,
|
||||
int h) {
|
||||
f->glViewport(0, 0, w, h);
|
||||
}
|
||||
|
||||
void LargeVideo::RendererGL::paint(
|
||||
not_null<QOpenGLWidget*> widget,
|
||||
not_null<QOpenGLFunctions*> f) {
|
||||
const auto bg = st::groupCallMembersFg->c;
|
||||
const auto fill = [&](QRect rect) {
|
||||
//p.fillRect(rect, st::groupCallMembersBg);
|
||||
};
|
||||
const auto [image, rotation] = _owner->_track
|
||||
? _owner->_track.track->frameOriginalWithRotation()
|
||||
: std::pair<QImage, int>();
|
||||
if (image.isNull()) {
|
||||
f->glClearColor(bg.redF(), bg.greenF(), bg.blueF(), 1.);
|
||||
f->glClear(GL_COLOR_BUFFER_BIT);
|
||||
return;
|
||||
}
|
||||
f->glUseProgram(_shaderProgram);
|
||||
f->glActiveTexture(GL_TEXTURE0);
|
||||
f->glBindTexture(GL_TEXTURE_2D, _textures[0]);
|
||||
|
||||
// #TODO calls check stride, upload with stride or from copy of an image.
|
||||
const auto key = image.cacheKey();
|
||||
if (_key != key) {
|
||||
_key = key;
|
||||
f->glPixelStorei(GL_UNPACK_ROW_LENGTH, image.bytesPerLine() / 4);
|
||||
f->glTexImage2D(
|
||||
GL_TEXTURE_2D,
|
||||
0,
|
||||
GL_RGB,
|
||||
image.width(),
|
||||
image.height(),
|
||||
0,
|
||||
GL_RGBA,
|
||||
GL_UNSIGNED_BYTE,
|
||||
image.constBits());
|
||||
f->glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
|
||||
}
|
||||
_owner->_track.track->markFrameShown();
|
||||
|
||||
f->glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer);
|
||||
std::array<std::array<GLfloat, 2>, 4> UVCoords = { {
|
||||
{{0, 1}}, // Lower left.
|
||||
{{1, 1}}, // Lower right.
|
||||
{{1, 0}}, // Upper right.
|
||||
{{0, 0}}, // Upper left.
|
||||
} };
|
||||
|
||||
const auto rotation_offset = (rotation / 90);
|
||||
std::rotate(
|
||||
UVCoords.begin(),
|
||||
UVCoords.begin() + rotation_offset,
|
||||
UVCoords.end());
|
||||
const GLfloat vertices[] = {
|
||||
-1, -1, UVCoords[0][0], UVCoords[0][1],
|
||||
1, -1, UVCoords[1][0], UVCoords[1][1],
|
||||
1, 1, UVCoords[2][0], UVCoords[2][1],
|
||||
-1, 1, UVCoords[3][0], UVCoords[3][1],
|
||||
};
|
||||
f->glBufferData(
|
||||
GL_ARRAY_BUFFER,
|
||||
sizeof(vertices),
|
||||
vertices,
|
||||
GL_DYNAMIC_DRAW);
|
||||
|
||||
GLint sampler = f->glGetUniformLocation(_shaderProgram, "s_texture");
|
||||
GLint position = f->glGetAttribLocation(_shaderProgram, "position");
|
||||
GLint texcoord = f->glGetAttribLocation(_shaderProgram, "texcoord");
|
||||
if (position < 0 || texcoord < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
f->glUniform1i(sampler, 0);
|
||||
|
||||
// Read position attribute with size of 2 and stride of 4 beginning at the start of the array. The
|
||||
// last argument indicates offset of data within the vertex buffer.
|
||||
f->glVertexAttribPointer(position, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(GLfloat), (void *)0);
|
||||
f->glEnableVertexAttribArray(position);
|
||||
|
||||
// Read texcoord attribute with size of 2 and stride of 4 beginning at the first texcoord in the
|
||||
// array. The last argument indicates offset of data within the vertex buffer.
|
||||
f->glVertexAttribPointer(texcoord, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(GLfloat), (void *)(2 * sizeof(GLfloat)));
|
||||
f->glEnableVertexAttribArray(texcoord);
|
||||
|
||||
f->glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
|
||||
}
|
||||
|
||||
LargeVideo::LargeVideo(
|
||||
QWidget *parent,
|
||||
const style::GroupCallLargeVideo &st,
|
||||
|
@ -84,7 +313,7 @@ Ui::GL::ChosenRenderer LargeVideo::chooseRenderer(
|
|||
Ui::GL::Capabilities capabilities) {
|
||||
class Renderer : public Ui::GL::Renderer {
|
||||
public:
|
||||
Renderer(not_null<LargeVideo*> owner) : _owner(owner) {
|
||||
explicit Renderer(not_null<LargeVideo*> owner) : _owner(owner) {
|
||||
}
|
||||
|
||||
void paintFallback(
|
||||
|
@ -108,9 +337,15 @@ Ui::GL::ChosenRenderer LargeVideo::chooseRenderer(
|
|||
? capabilities.supported
|
||||
: capabilities.transparency;
|
||||
LOG(("OpenGL: %1 (LargeVideo)").arg(Logs::b(use)));
|
||||
if (use) {
|
||||
return {
|
||||
.renderer = std::make_unique<RendererGL>(this),
|
||||
.backend = Ui::GL::Backend::OpenGL,
|
||||
};
|
||||
}
|
||||
return {
|
||||
.renderer = std::make_unique<Renderer>(this),
|
||||
.backend = (use ? Ui::GL::Backend::OpenGL : Ui::GL::Backend::Raster),
|
||||
.backend = Ui::GL::Backend::Raster,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -80,6 +80,7 @@ public:
|
|||
|
||||
private:
|
||||
struct PinButton;
|
||||
class RendererGL;
|
||||
|
||||
[[nodiscard]] not_null<QWidget*> widget() const;
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue