Draw all except controls in OpenGL media viewer.
This commit is contained in:
parent
24f8a88625
commit
68ae40ee56
|
@ -28,6 +28,11 @@ constexpr auto kBlurTextureSizeFactor = 1.7;
|
||||||
constexpr auto kBlurOpacity = 0.7;
|
constexpr auto kBlurOpacity = 0.7;
|
||||||
constexpr auto kMinCameraVisiblePart = 0.75;
|
constexpr auto kMinCameraVisiblePart = 0.75;
|
||||||
|
|
||||||
|
constexpr auto kQuads = 7;
|
||||||
|
constexpr auto kQuadVertices = kQuads * 4;
|
||||||
|
constexpr auto kQuadValues = kQuadVertices * 4;
|
||||||
|
constexpr auto kValues = kQuadValues + 8; // Blur texture coordinates.
|
||||||
|
|
||||||
[[nodiscard]] ShaderPart FragmentBlurTexture(
|
[[nodiscard]] ShaderPart FragmentBlurTexture(
|
||||||
bool vertical,
|
bool vertical,
|
||||||
char prefix = 'v') {
|
char prefix = 'v') {
|
||||||
|
@ -200,10 +205,6 @@ void Viewport::RendererGL::init(
|
||||||
_frameBuffer->setUsagePattern(QOpenGLBuffer::DynamicDraw);
|
_frameBuffer->setUsagePattern(QOpenGLBuffer::DynamicDraw);
|
||||||
_frameBuffer->create();
|
_frameBuffer->create();
|
||||||
_frameBuffer->bind();
|
_frameBuffer->bind();
|
||||||
constexpr auto kQuads = 7;
|
|
||||||
constexpr auto kQuadVertices = kQuads * 4;
|
|
||||||
constexpr auto kQuadValues = kQuadVertices * 4;
|
|
||||||
constexpr auto kValues = kQuadValues + 8; // Blur texture coordinates.
|
|
||||||
_frameBuffer->allocate(kValues * sizeof(GLfloat));
|
_frameBuffer->allocate(kValues * sizeof(GLfloat));
|
||||||
_downscaleProgram.yuv420.emplace();
|
_downscaleProgram.yuv420.emplace();
|
||||||
_downscaleVertexShader = LinkProgram(
|
_downscaleVertexShader = LinkProgram(
|
||||||
|
@ -235,8 +236,6 @@ void Viewport::RendererGL::init(
|
||||||
FragmentRoundCorners(),
|
FragmentRoundCorners(),
|
||||||
})).vertex;
|
})).vertex;
|
||||||
|
|
||||||
_background.init(f);
|
|
||||||
|
|
||||||
_imageProgram.emplace();
|
_imageProgram.emplace();
|
||||||
LinkProgram(
|
LinkProgram(
|
||||||
&*_imageProgram,
|
&*_imageProgram,
|
||||||
|
@ -247,6 +246,8 @@ void Viewport::RendererGL::init(
|
||||||
FragmentShader({
|
FragmentShader({
|
||||||
FragmentSampleARGB32Texture(),
|
FragmentSampleARGB32Texture(),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
_background.init(f);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Viewport::RendererGL::ensureARGB32Program() {
|
void Viewport::RendererGL::ensureARGB32Program() {
|
||||||
|
@ -275,6 +276,8 @@ void Viewport::RendererGL::ensureARGB32Program() {
|
||||||
void Viewport::RendererGL::deinit(
|
void Viewport::RendererGL::deinit(
|
||||||
not_null<QOpenGLWidget*> widget,
|
not_null<QOpenGLWidget*> widget,
|
||||||
QOpenGLFunctions &f) {
|
QOpenGLFunctions &f) {
|
||||||
|
_background.deinit(f);
|
||||||
|
|
||||||
_frameBuffer = std::nullopt;
|
_frameBuffer = std::nullopt;
|
||||||
_frameVertexShader = nullptr;
|
_frameVertexShader = nullptr;
|
||||||
_imageProgram = std::nullopt;
|
_imageProgram = std::nullopt;
|
||||||
|
@ -288,7 +291,6 @@ void Viewport::RendererGL::deinit(
|
||||||
}
|
}
|
||||||
_tileData.clear();
|
_tileData.clear();
|
||||||
_tileDataIndices.clear();
|
_tileDataIndices.clear();
|
||||||
_background.deinit(f);
|
|
||||||
_buttons.destroy(f);
|
_buttons.destroy(f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -545,13 +547,13 @@ void Viewport::RendererGL::paintTile(
|
||||||
name.texture.left(), name.texture.top(),
|
name.texture.left(), name.texture.top(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
_frameBuffer->bind();
|
||||||
|
_frameBuffer->write(0, coords, sizeof(coords));
|
||||||
|
|
||||||
const auto blurSize = CountBlurredSize(unscaled, _viewport, _factor);
|
const auto blurSize = CountBlurredSize(unscaled, _viewport, _factor);
|
||||||
prepareObjects(f, tileData, blurSize);
|
prepareObjects(f, tileData, blurSize);
|
||||||
f.glViewport(0, 0, blurSize.width(), blurSize.height());
|
f.glViewport(0, 0, blurSize.width(), blurSize.height());
|
||||||
|
|
||||||
_frameBuffer->bind();
|
|
||||||
_frameBuffer->write(0, coords, sizeof(coords));
|
|
||||||
|
|
||||||
bindFrame(f, data, tileData, _downscaleProgram);
|
bindFrame(f, data, tileData, _downscaleProgram);
|
||||||
tile->track()->markFrameShown();
|
tile->track()->markFrameShown();
|
||||||
|
|
||||||
|
@ -716,52 +718,17 @@ void Viewport::RendererGL::bindFrame(
|
||||||
Program &program) {
|
Program &program) {
|
||||||
const auto upload = (tileData.trackIndex != data.index);
|
const auto upload = (tileData.trackIndex != data.index);
|
||||||
tileData.trackIndex = data.index;
|
tileData.trackIndex = data.index;
|
||||||
const auto uploadOne = [&](
|
|
||||||
GLint internalformat,
|
|
||||||
GLint format,
|
|
||||||
QSize size,
|
|
||||||
QSize hasSize,
|
|
||||||
int stride,
|
|
||||||
const void *data) {
|
|
||||||
f.glPixelStorei(GL_UNPACK_ROW_LENGTH, stride);
|
|
||||||
if (hasSize != size) {
|
|
||||||
f.glTexImage2D(
|
|
||||||
GL_TEXTURE_2D,
|
|
||||||
0,
|
|
||||||
internalformat,
|
|
||||||
size.width(),
|
|
||||||
size.height(),
|
|
||||||
0,
|
|
||||||
format,
|
|
||||||
GL_UNSIGNED_BYTE,
|
|
||||||
data);
|
|
||||||
} else {
|
|
||||||
f.glTexSubImage2D(
|
|
||||||
GL_TEXTURE_2D,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
size.width(),
|
|
||||||
size.height(),
|
|
||||||
format,
|
|
||||||
GL_UNSIGNED_BYTE,
|
|
||||||
data);
|
|
||||||
}
|
|
||||||
f.glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
|
|
||||||
};
|
|
||||||
//if (upload) {
|
|
||||||
// tileData.textureIndex = 1 - tileData.textureIndex;
|
|
||||||
//}
|
|
||||||
if (_rgbaFrame) {
|
if (_rgbaFrame) {
|
||||||
ensureARGB32Program();
|
ensureARGB32Program();
|
||||||
f.glUseProgram(program.argb32->programId());
|
f.glUseProgram(program.argb32->programId());
|
||||||
f.glActiveTexture(GL_TEXTURE0);
|
f.glActiveTexture(GL_TEXTURE0);
|
||||||
tileData.textures.bind(f, tileData.textureIndex);
|
tileData.textures.bind(f, tileData.textureIndex * 5 + 0);
|
||||||
if (upload) {
|
if (upload) {
|
||||||
const auto &image = data.original;
|
const auto &image = data.original;
|
||||||
const auto stride = image.bytesPerLine() / 4;
|
const auto stride = image.bytesPerLine() / 4;
|
||||||
const auto data = image.constBits();
|
const auto data = image.constBits();
|
||||||
uploadOne(
|
uploadTexture(
|
||||||
|
f,
|
||||||
GL_RGBA,
|
GL_RGBA,
|
||||||
GL_RGBA,
|
GL_RGBA,
|
||||||
image.size(),
|
image.size(),
|
||||||
|
@ -769,6 +736,7 @@ void Viewport::RendererGL::bindFrame(
|
||||||
stride,
|
stride,
|
||||||
data);
|
data);
|
||||||
tileData.rgbaSize = image.size();
|
tileData.rgbaSize = image.size();
|
||||||
|
tileData.textureSize = QSize();
|
||||||
}
|
}
|
||||||
program.argb32->setUniformValue("s_texture", GLint(0));
|
program.argb32->setUniformValue("s_texture", GLint(0));
|
||||||
} else {
|
} else {
|
||||||
|
@ -778,7 +746,8 @@ void Viewport::RendererGL::bindFrame(
|
||||||
tileData.textures.bind(f, tileData.textureIndex * 5 + 0);
|
tileData.textures.bind(f, tileData.textureIndex * 5 + 0);
|
||||||
if (upload) {
|
if (upload) {
|
||||||
f.glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
f.glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||||
uploadOne(
|
uploadTexture(
|
||||||
|
f,
|
||||||
GL_RED,
|
GL_RED,
|
||||||
GL_RED,
|
GL_RED,
|
||||||
yuv->size,
|
yuv->size,
|
||||||
|
@ -786,11 +755,13 @@ void Viewport::RendererGL::bindFrame(
|
||||||
yuv->y.stride,
|
yuv->y.stride,
|
||||||
yuv->y.data);
|
yuv->y.data);
|
||||||
tileData.textureSize = yuv->size;
|
tileData.textureSize = yuv->size;
|
||||||
|
tileData.rgbaSize = QSize();
|
||||||
}
|
}
|
||||||
f.glActiveTexture(GL_TEXTURE1);
|
f.glActiveTexture(GL_TEXTURE1);
|
||||||
tileData.textures.bind(f, tileData.textureIndex * 5 + 1);
|
tileData.textures.bind(f, tileData.textureIndex * 5 + 1);
|
||||||
if (upload) {
|
if (upload) {
|
||||||
uploadOne(
|
uploadTexture(
|
||||||
|
f,
|
||||||
GL_RED,
|
GL_RED,
|
||||||
GL_RED,
|
GL_RED,
|
||||||
yuv->chromaSize,
|
yuv->chromaSize,
|
||||||
|
@ -801,7 +772,8 @@ void Viewport::RendererGL::bindFrame(
|
||||||
f.glActiveTexture(GL_TEXTURE2);
|
f.glActiveTexture(GL_TEXTURE2);
|
||||||
tileData.textures.bind(f, tileData.textureIndex * 5 + 2);
|
tileData.textures.bind(f, tileData.textureIndex * 5 + 2);
|
||||||
if (upload) {
|
if (upload) {
|
||||||
uploadOne(
|
uploadTexture(
|
||||||
|
f,
|
||||||
GL_RED,
|
GL_RED,
|
||||||
GL_RED,
|
GL_RED,
|
||||||
yuv->chromaSize,
|
yuv->chromaSize,
|
||||||
|
@ -817,6 +789,41 @@ void Viewport::RendererGL::bindFrame(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Viewport::RendererGL::uploadTexture(
|
||||||
|
QOpenGLFunctions &f,
|
||||||
|
GLint internalformat,
|
||||||
|
GLint format,
|
||||||
|
QSize size,
|
||||||
|
QSize hasSize,
|
||||||
|
int stride,
|
||||||
|
const void *data) const {
|
||||||
|
f.glPixelStorei(GL_UNPACK_ROW_LENGTH, stride);
|
||||||
|
if (hasSize != size) {
|
||||||
|
f.glTexImage2D(
|
||||||
|
GL_TEXTURE_2D,
|
||||||
|
0,
|
||||||
|
internalformat,
|
||||||
|
size.width(),
|
||||||
|
size.height(),
|
||||||
|
0,
|
||||||
|
format,
|
||||||
|
GL_UNSIGNED_BYTE,
|
||||||
|
data);
|
||||||
|
} else {
|
||||||
|
f.glTexSubImage2D(
|
||||||
|
GL_TEXTURE_2D,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
size.width(),
|
||||||
|
size.height(),
|
||||||
|
format,
|
||||||
|
GL_UNSIGNED_BYTE,
|
||||||
|
data);
|
||||||
|
}
|
||||||
|
f.glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
|
||||||
|
}
|
||||||
|
|
||||||
void Viewport::RendererGL::drawDownscalePass(
|
void Viewport::RendererGL::drawDownscalePass(
|
||||||
QOpenGLFunctions &f,
|
QOpenGLFunctions &f,
|
||||||
TileData &tileData) {
|
TileData &tileData) {
|
||||||
|
@ -854,12 +861,7 @@ Rect Viewport::RendererGL::transformRect(const Rect &raster) const {
|
||||||
}
|
}
|
||||||
|
|
||||||
Rect Viewport::RendererGL::transformRect(const QRect &raster) const {
|
Rect Viewport::RendererGL::transformRect(const QRect &raster) const {
|
||||||
return {
|
return TransformRect(Rect(raster), _viewport, _factor);
|
||||||
raster.x() * _factor,
|
|
||||||
(_viewport.height() - raster.y() - raster.height()) * _factor,
|
|
||||||
raster.width() * _factor,
|
|
||||||
raster.height() * _factor,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Viewport::RendererGL::ensureButtonsImage() {
|
void Viewport::RendererGL::ensureButtonsImage() {
|
||||||
|
|
|
@ -103,6 +103,15 @@ private:
|
||||||
not_null<VideoTile*> tile,
|
not_null<VideoTile*> tile,
|
||||||
TileData &data);
|
TileData &data);
|
||||||
|
|
||||||
|
void uploadTexture(
|
||||||
|
QOpenGLFunctions &f,
|
||||||
|
GLint internalformat,
|
||||||
|
GLint format,
|
||||||
|
QSize size,
|
||||||
|
QSize hasSize,
|
||||||
|
int stride,
|
||||||
|
const void *data) const;
|
||||||
|
|
||||||
[[nodiscard]] bool isExpanded(
|
[[nodiscard]] bool isExpanded(
|
||||||
not_null<VideoTile*> tile,
|
not_null<VideoTile*> tile,
|
||||||
QSize unscaled,
|
QSize unscaled,
|
||||||
|
|
|
@ -7,13 +7,68 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
*/
|
*/
|
||||||
#include "media/view/media_view_overlay_opengl.h"
|
#include "media/view/media_view_overlay_opengl.h"
|
||||||
|
|
||||||
|
#include "ui/gl/gl_shader.h"
|
||||||
#include "base/platform/base_platform_info.h"
|
#include "base/platform/base_platform_info.h"
|
||||||
|
|
||||||
namespace Media::View {
|
namespace Media::View {
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
using namespace Ui::GL;
|
||||||
|
|
||||||
|
constexpr auto kQuads = 8;
|
||||||
|
constexpr auto kQuadVertices = kQuads * 4;
|
||||||
|
constexpr auto kQuadValues = kQuadVertices * 4;
|
||||||
|
constexpr auto kControls = 6;
|
||||||
|
constexpr auto kControlValues = 2 * 4 + 4 * 4;
|
||||||
|
constexpr auto kControlsValues = kControls * kControlValues;
|
||||||
|
constexpr auto kValues = kQuadValues + kControlsValues;
|
||||||
|
|
||||||
|
constexpr auto kRadialLoadingOffset = 4;
|
||||||
|
constexpr auto kThemePreviewOffset = kRadialLoadingOffset + 4;
|
||||||
|
constexpr auto kDocumentBubbleOffset = kThemePreviewOffset + 4;
|
||||||
|
constexpr auto kSaveMsgOffset = kDocumentBubbleOffset + 4;
|
||||||
|
constexpr auto kFooterOffset = kSaveMsgOffset + 4;
|
||||||
|
constexpr auto kCaptionOffset = kFooterOffset + 4;
|
||||||
|
constexpr auto kGroupThumbsOffset = kCaptionOffset + 4;
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
OverlayWidget::RendererGL::RendererGL(not_null<OverlayWidget*> owner)
|
||||||
|
: _owner(owner) {
|
||||||
|
style::PaletteChanged(
|
||||||
|
) | rpl::start_with_next([=] {
|
||||||
|
_radialImage.invalidate();
|
||||||
|
_documentBubbleImage.invalidate();
|
||||||
|
_themePreviewImage.invalidate();
|
||||||
|
_saveMsgImage.invalidate();
|
||||||
|
_footerImage.invalidate();
|
||||||
|
_captionImage.invalidate();
|
||||||
|
}, _lifetime);
|
||||||
|
}
|
||||||
|
|
||||||
void OverlayWidget::RendererGL::init(
|
void OverlayWidget::RendererGL::init(
|
||||||
not_null<QOpenGLWidget*> widget,
|
not_null<QOpenGLWidget*> widget,
|
||||||
QOpenGLFunctions &f) {
|
QOpenGLFunctions &f) {
|
||||||
|
_factor = widget->devicePixelRatio();
|
||||||
|
_contentBuffer.emplace();
|
||||||
|
_contentBuffer->setUsagePattern(QOpenGLBuffer::DynamicDraw);
|
||||||
|
_contentBuffer->create();
|
||||||
|
_contentBuffer->bind();
|
||||||
|
_contentBuffer->allocate(kValues * sizeof(GLfloat));
|
||||||
|
|
||||||
|
_textures.ensureCreated(f);
|
||||||
|
|
||||||
|
_imageProgram.emplace();
|
||||||
|
LinkProgram(
|
||||||
|
&*_imageProgram,
|
||||||
|
VertexShader({
|
||||||
|
VertexViewportTransform(),
|
||||||
|
VertexPassTextureCoord(),
|
||||||
|
}),
|
||||||
|
FragmentShader({
|
||||||
|
FragmentSampleARGB32Texture(),
|
||||||
|
}));
|
||||||
|
|
||||||
_background.init(f);
|
_background.init(f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,6 +76,9 @@ void OverlayWidget::RendererGL::deinit(
|
||||||
not_null<QOpenGLWidget*> widget,
|
not_null<QOpenGLWidget*> widget,
|
||||||
QOpenGLFunctions &f) {
|
QOpenGLFunctions &f) {
|
||||||
_background.deinit(f);
|
_background.deinit(f);
|
||||||
|
_textures.destroy(f);
|
||||||
|
_imageProgram = std::nullopt;
|
||||||
|
_contentBuffer = std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
void OverlayWidget::RendererGL::resize(
|
void OverlayWidget::RendererGL::resize(
|
||||||
|
@ -46,6 +104,7 @@ void OverlayWidget::RendererGL::paint(
|
||||||
}
|
}
|
||||||
_f = &f;
|
_f = &f;
|
||||||
_owner->paint(this);
|
_owner->paint(this);
|
||||||
|
_f = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool OverlayWidget::RendererGL::handleHideWorkaround(QOpenGLFunctions &f) {
|
bool OverlayWidget::RendererGL::handleHideWorkaround(QOpenGLFunctions &f) {
|
||||||
|
@ -67,6 +126,7 @@ void OverlayWidget::RendererGL::paintBackground() {
|
||||||
if (_owner->opaqueContentShown()) {
|
if (_owner->opaqueContentShown()) {
|
||||||
fill -= _owner->contentRect();
|
fill -= _owner->contentRect();
|
||||||
}
|
}
|
||||||
|
toggleBlending(false);
|
||||||
_background.fill(
|
_background.fill(
|
||||||
*_f,
|
*_f,
|
||||||
fill,
|
fill,
|
||||||
|
@ -78,6 +138,11 @@ void OverlayWidget::RendererGL::paintBackground() {
|
||||||
void OverlayWidget::RendererGL::paintTransformedVideoFrame(
|
void OverlayWidget::RendererGL::paintTransformedVideoFrame(
|
||||||
QRect rect,
|
QRect rect,
|
||||||
int rotation) {
|
int rotation) {
|
||||||
|
paintTransformedStaticContent(
|
||||||
|
_owner->videoFrame(),
|
||||||
|
rect,
|
||||||
|
rotation,
|
||||||
|
false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void OverlayWidget::RendererGL::paintTransformedStaticContent(
|
void OverlayWidget::RendererGL::paintTransformedStaticContent(
|
||||||
|
@ -85,44 +150,131 @@ void OverlayWidget::RendererGL::paintTransformedStaticContent(
|
||||||
QRect rect,
|
QRect rect,
|
||||||
int rotation,
|
int rotation,
|
||||||
bool fillTransparentBackground) {
|
bool fillTransparentBackground) {
|
||||||
|
AssertIsDebug(fillTransparentBackground);
|
||||||
|
auto texCoords = std::array<std::array<GLfloat, 2>, 4> { {
|
||||||
|
{ { 0.f, 1.f } },
|
||||||
|
{ { 1.f, 1.f } },
|
||||||
|
{ { 1.f, 0.f } },
|
||||||
|
{ { 0.f, 0.f } },
|
||||||
|
} };
|
||||||
|
if (const auto shift = (rotation / 90); shift > 0) {
|
||||||
|
std::rotate(
|
||||||
|
texCoords.begin(),
|
||||||
|
texCoords.begin() + shift,
|
||||||
|
texCoords.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto geometry = transformRect(rect);
|
||||||
|
const GLfloat coords[] = {
|
||||||
|
geometry.left(), geometry.top(),
|
||||||
|
texCoords[0][0], texCoords[0][1],
|
||||||
|
|
||||||
|
geometry.right(), geometry.top(),
|
||||||
|
texCoords[1][0], texCoords[1][1],
|
||||||
|
|
||||||
|
geometry.right(), geometry.bottom(),
|
||||||
|
texCoords[2][0], texCoords[2][1],
|
||||||
|
|
||||||
|
geometry.left(), geometry.bottom(),
|
||||||
|
texCoords[3][0], texCoords[3][1],
|
||||||
|
};
|
||||||
|
|
||||||
|
_contentBuffer->bind();
|
||||||
|
_contentBuffer->write(0, coords, sizeof(coords));
|
||||||
|
|
||||||
|
_f->glUseProgram(_imageProgram->programId());
|
||||||
|
_imageProgram->setUniformValue("viewport", QSizeF(_viewport * _factor));
|
||||||
|
_imageProgram->setUniformValue("s_texture", GLint(0));
|
||||||
|
|
||||||
|
_f->glActiveTexture(GL_TEXTURE0);
|
||||||
|
_textures.bind(*_f, 0);
|
||||||
|
const auto cacheKey = image.cacheKey();
|
||||||
|
const auto upload = (_cacheKey != cacheKey);
|
||||||
|
if (upload) {
|
||||||
|
const auto stride = image.bytesPerLine() / 4;
|
||||||
|
const auto data = image.constBits();
|
||||||
|
uploadTexture(
|
||||||
|
GL_RGBA,
|
||||||
|
GL_RGBA,
|
||||||
|
image.size(),
|
||||||
|
_rgbaSize,
|
||||||
|
stride,
|
||||||
|
data);
|
||||||
|
_rgbaSize = image.size();
|
||||||
|
_ySize = QSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
toggleBlending(false);
|
||||||
|
FillTexturedRectangle(*_f, &*_imageProgram);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OverlayWidget::RendererGL::uploadTexture(
|
||||||
|
GLint internalformat,
|
||||||
|
GLint format,
|
||||||
|
QSize size,
|
||||||
|
QSize hasSize,
|
||||||
|
int stride,
|
||||||
|
const void *data) const {
|
||||||
|
_f->glPixelStorei(GL_UNPACK_ROW_LENGTH, stride);
|
||||||
|
if (hasSize != size) {
|
||||||
|
_f->glTexImage2D(
|
||||||
|
GL_TEXTURE_2D,
|
||||||
|
0,
|
||||||
|
internalformat,
|
||||||
|
size.width(),
|
||||||
|
size.height(),
|
||||||
|
0,
|
||||||
|
format,
|
||||||
|
GL_UNSIGNED_BYTE,
|
||||||
|
data);
|
||||||
|
} else {
|
||||||
|
_f->glTexSubImage2D(
|
||||||
|
GL_TEXTURE_2D,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
size.width(),
|
||||||
|
size.height(),
|
||||||
|
format,
|
||||||
|
GL_UNSIGNED_BYTE,
|
||||||
|
data);
|
||||||
|
}
|
||||||
|
_f->glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void OverlayWidget::RendererGL::paintRadialLoading(
|
void OverlayWidget::RendererGL::paintRadialLoading(
|
||||||
QRect inner,
|
QRect inner,
|
||||||
bool radial,
|
bool radial,
|
||||||
float64 radialOpacity) {
|
float64 radialOpacity) {
|
||||||
paintToCache(_radialCache, inner.size(), [&](Painter &&p) {
|
paintUsingRaster(_radialImage, inner, [&](Painter &&p) {
|
||||||
const auto newInner = QRect(QPoint(), inner.size());
|
const auto newInner = QRect(QPoint(), inner.size());
|
||||||
_owner->paintRadialLoadingContent(p, newInner, radial, radialOpacity);
|
_owner->paintRadialLoadingContent(p, newInner, radial, radialOpacity);
|
||||||
}, true);
|
}, kRadialLoadingOffset, true);
|
||||||
//p.drawImage(inner.topLeft(), _radialCache);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void OverlayWidget::RendererGL::paintThemePreview(QRect outer) {
|
void OverlayWidget::RendererGL::paintThemePreview(QRect outer) {
|
||||||
paintToCache(_themePreviewCache, outer.size(), [&](Painter &&p) {
|
paintUsingRaster(_themePreviewImage, outer, [&](Painter &&p) {
|
||||||
const auto newOuter = QRect(QPoint(), outer.size());
|
const auto newOuter = QRect(QPoint(), outer.size());
|
||||||
_owner->paintThemePreviewContent(p, newOuter, newOuter);
|
_owner->paintThemePreviewContent(p, newOuter, newOuter);
|
||||||
});
|
}, kThemePreviewOffset);
|
||||||
}
|
}
|
||||||
|
|
||||||
void OverlayWidget::RendererGL::paintDocumentBubble(
|
void OverlayWidget::RendererGL::paintDocumentBubble(
|
||||||
QRect outer,
|
QRect outer,
|
||||||
QRect icon) {
|
QRect icon) {
|
||||||
paintToCache(_documentBubbleCache, outer.size(), [&](Painter &&p) {
|
paintUsingRaster(_documentBubbleImage, outer, [&](Painter &&p) {
|
||||||
const auto newOuter = QRect(QPoint(), outer.size());
|
const auto newOuter = QRect(QPoint(), outer.size());
|
||||||
const auto newIcon = icon.translated(-outer.topLeft());
|
const auto newIcon = icon.translated(-outer.topLeft());
|
||||||
_owner->paintDocumentBubbleContent(p, newOuter, newIcon, newOuter);
|
_owner->paintDocumentBubbleContent(p, newOuter, newIcon, newOuter);
|
||||||
});
|
}, kDocumentBubbleOffset);
|
||||||
//p.drawImage(outer.topLeft(), _documentBubbleCache);
|
|
||||||
_owner->paintRadialLoading(this);
|
_owner->paintRadialLoading(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void OverlayWidget::RendererGL::paintSaveMsg(QRect outer) {
|
void OverlayWidget::RendererGL::paintSaveMsg(QRect outer) {
|
||||||
paintToCache(_saveMsgCache, outer.size(), [&](Painter &&p) {
|
paintUsingRaster(_saveMsgImage, outer, [&](Painter &&p) {
|
||||||
const auto newOuter = QRect(QPoint(), outer.size());
|
const auto newOuter = QRect(QPoint(), outer.size());
|
||||||
_owner->paintSaveMsgContent(p, newOuter, newOuter);
|
_owner->paintSaveMsgContent(p, newOuter, newOuter);
|
||||||
}, true);
|
}, kSaveMsgOffset, true);
|
||||||
//p.drawImage(outer.topLeft(), _saveMsgCache);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void OverlayWidget::RendererGL::paintControl(
|
void OverlayWidget::RendererGL::paintControl(
|
||||||
|
@ -132,52 +284,109 @@ void OverlayWidget::RendererGL::paintControl(
|
||||||
QRect inner,
|
QRect inner,
|
||||||
float64 innerOpacity,
|
float64 innerOpacity,
|
||||||
const style::icon &icon) {
|
const style::icon &icon) {
|
||||||
|
AssertIsDebug(controls);
|
||||||
}
|
}
|
||||||
|
|
||||||
void OverlayWidget::RendererGL::paintFooter(QRect outer, float64 opacity) {
|
void OverlayWidget::RendererGL::paintFooter(QRect outer, float64 opacity) {
|
||||||
paintToCache(_footerCache, outer.size(), [&](Painter &&p) {
|
paintUsingRaster(_footerImage, outer, [&](Painter &&p) {
|
||||||
const auto newOuter = QRect(QPoint(), outer.size());
|
const auto newOuter = QRect(QPoint(), outer.size());
|
||||||
_owner->paintFooterContent(p, newOuter, newOuter, opacity);
|
_owner->paintFooterContent(p, newOuter, newOuter, opacity);
|
||||||
}, true);
|
}, kFooterOffset, true);
|
||||||
//p.drawImage(outer, _footerCache, QRect(QPoint(), outer.size()) * factor);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void OverlayWidget::RendererGL::paintCaption(QRect outer, float64 opacity) {
|
void OverlayWidget::RendererGL::paintCaption(QRect outer, float64 opacity) {
|
||||||
paintToCache(_captionCache, outer.size(), [&](Painter &&p) {
|
paintUsingRaster(_captionImage, outer, [&](Painter &&p) {
|
||||||
const auto newOuter = QRect(QPoint(), outer.size());
|
const auto newOuter = QRect(QPoint(), outer.size());
|
||||||
_owner->paintCaptionContent(p, newOuter, newOuter, opacity);
|
_owner->paintCaptionContent(p, newOuter, newOuter, opacity);
|
||||||
});
|
}, kCaptionOffset, true);
|
||||||
//p.drawImage(outer, _captionCache, ...);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void OverlayWidget::RendererGL::paintGroupThumbs(
|
void OverlayWidget::RendererGL::paintGroupThumbs(
|
||||||
QRect outer,
|
QRect outer,
|
||||||
float64 opacity) {
|
float64 opacity) {
|
||||||
paintToCache(_groupThumbsCache, outer.size(), [&](Painter &&p) {
|
paintUsingRaster(_groupThumbsImage, outer, [&](Painter &&p) {
|
||||||
const auto newOuter = QRect(QPoint(), outer.size());
|
const auto newOuter = QRect(QPoint(), outer.size());
|
||||||
_owner->paintGroupThumbsContent(p, newOuter, newOuter, opacity);
|
_owner->paintGroupThumbsContent(p, newOuter, newOuter, opacity);
|
||||||
});
|
}, kGroupThumbsOffset, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void OverlayWidget::RendererGL::paintToCache(
|
void OverlayWidget::RendererGL::paintUsingRaster(
|
||||||
QImage &cache,
|
Ui::GL::Image &image,
|
||||||
QSize size,
|
QRect rect,
|
||||||
Fn<void(Painter&&)> method,
|
Fn<void(Painter&&)> method,
|
||||||
bool clear) {
|
int bufferOffset,
|
||||||
if (cache.width() < size.width() * _factor
|
bool transparent) {
|
||||||
|| cache.height() < size.height() * _factor) {
|
auto raster = image.takeImage();
|
||||||
cache = QImage(
|
const auto size = rect.size() * _factor;
|
||||||
size * _factor,
|
if (raster.width() < size.width() || raster.height() < size.height()) {
|
||||||
QImage::Format_ARGB32_Premultiplied);
|
raster = QImage(size, QImage::Format_ARGB32_Premultiplied);
|
||||||
cache.setDevicePixelRatio(_factor);
|
raster.setDevicePixelRatio(_factor);
|
||||||
} else if (cache.devicePixelRatio() != _factor) {
|
if (!transparent
|
||||||
cache.setDevicePixelRatio(_factor);
|
&& (raster.width() > size.width()
|
||||||
|
|| raster.height() > size.height())) {
|
||||||
|
raster.fill(Qt::transparent);
|
||||||
|
}
|
||||||
|
} else if (raster.devicePixelRatio() != _factor) {
|
||||||
|
raster.setDevicePixelRatio(_factor);
|
||||||
}
|
}
|
||||||
if (clear) {
|
|
||||||
cache.fill(Qt::transparent);
|
if (transparent) {
|
||||||
|
raster.fill(Qt::transparent);
|
||||||
}
|
}
|
||||||
method(Painter(&cache));
|
method(Painter(&raster));
|
||||||
|
|
||||||
|
image.setImage(std::move(raster));
|
||||||
|
image.bind(*_f, size);
|
||||||
|
|
||||||
|
const auto textured = image.texturedRect(rect, QRect(QPoint(), size));
|
||||||
|
const auto geometry = transformRect(textured.geometry);
|
||||||
|
const GLfloat coords[] = {
|
||||||
|
geometry.left(), geometry.top(),
|
||||||
|
textured.texture.left(), textured.texture.bottom(),
|
||||||
|
|
||||||
|
geometry.right(), geometry.top(),
|
||||||
|
textured.texture.right(), textured.texture.bottom(),
|
||||||
|
|
||||||
|
geometry.right(), geometry.bottom(),
|
||||||
|
textured.texture.right(), textured.texture.top(),
|
||||||
|
|
||||||
|
geometry.left(), geometry.bottom(),
|
||||||
|
textured.texture.left(), textured.texture.top(),
|
||||||
|
};
|
||||||
|
_contentBuffer->write(
|
||||||
|
bufferOffset * 4 * sizeof(GLfloat),
|
||||||
|
coords,
|
||||||
|
sizeof(coords));
|
||||||
|
|
||||||
|
_f->glUseProgram(_imageProgram->programId());
|
||||||
|
_imageProgram->setUniformValue("viewport", QSizeF(_viewport * _factor));
|
||||||
|
_imageProgram->setUniformValue("s_texture", GLint(0));
|
||||||
|
|
||||||
|
_f->glActiveTexture(GL_TEXTURE0);
|
||||||
|
image.bind(*_f, size);
|
||||||
|
|
||||||
|
toggleBlending(transparent);
|
||||||
|
FillTexturedRectangle(*_f, &*_imageProgram, bufferOffset);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OverlayWidget::RendererGL::toggleBlending(bool enabled) {
|
||||||
|
if (_blendingEnabled == enabled) {
|
||||||
|
return;
|
||||||
|
} else if (enabled) {
|
||||||
|
_f->glEnable(GL_BLEND);
|
||||||
|
_f->glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
|
||||||
|
} else {
|
||||||
|
_f->glDisable(GL_BLEND);
|
||||||
|
}
|
||||||
|
_blendingEnabled = enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
Rect OverlayWidget::RendererGL::transformRect(const Rect &raster) const {
|
||||||
|
return TransformRect(raster, _viewport, _factor);
|
||||||
|
}
|
||||||
|
|
||||||
|
Rect OverlayWidget::RendererGL::transformRect(const QRect &raster) const {
|
||||||
|
return TransformRect(Rect(raster), _viewport, _factor);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Media::View
|
} // namespace Media::View
|
||||||
|
|
|
@ -9,14 +9,16 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
|
|
||||||
#include "media/view/media_view_overlay_renderer.h"
|
#include "media/view/media_view_overlay_renderer.h"
|
||||||
#include "ui/gl/gl_surface.h"
|
#include "ui/gl/gl_surface.h"
|
||||||
|
#include "ui/gl/gl_image.h"
|
||||||
#include "ui/gl/gl_primitives.h"
|
#include "ui/gl/gl_primitives.h"
|
||||||
|
|
||||||
|
#include <QtGui/QOpenGLBuffer>
|
||||||
|
|
||||||
namespace Media::View {
|
namespace Media::View {
|
||||||
|
|
||||||
class OverlayWidget::RendererGL final : public OverlayWidget::Renderer {
|
class OverlayWidget::RendererGL final : public OverlayWidget::Renderer {
|
||||||
public:
|
public:
|
||||||
RendererGL(not_null<OverlayWidget*> owner) : _owner(owner) {
|
explicit RendererGL(not_null<OverlayWidget*> owner);
|
||||||
}
|
|
||||||
|
|
||||||
void init(
|
void init(
|
||||||
not_null<QOpenGLWidget*> widget,
|
not_null<QOpenGLWidget*> widget,
|
||||||
|
@ -65,11 +67,26 @@ private:
|
||||||
void paintCaption(QRect outer, float64 opacity) override;
|
void paintCaption(QRect outer, float64 opacity) override;
|
||||||
void paintGroupThumbs(QRect outer, float64 opacity) override;
|
void paintGroupThumbs(QRect outer, float64 opacity) override;
|
||||||
|
|
||||||
void paintToCache(
|
void paintUsingRaster(
|
||||||
QImage &cache,
|
Ui::GL::Image &image,
|
||||||
QSize size,
|
QRect rect,
|
||||||
Fn<void(Painter&&)> method,
|
Fn<void(Painter&&)> method,
|
||||||
bool clear = false);
|
int bufferOffset,
|
||||||
|
bool transparent = false);
|
||||||
|
|
||||||
|
void toggleBlending(bool enabled);
|
||||||
|
|
||||||
|
[[nodiscard]] Ui::GL::Rect transformRect(const QRect &raster) const;
|
||||||
|
[[nodiscard]] Ui::GL::Rect transformRect(
|
||||||
|
const Ui::GL::Rect &raster) const;
|
||||||
|
|
||||||
|
void uploadTexture(
|
||||||
|
GLint internalformat,
|
||||||
|
GLint format,
|
||||||
|
QSize size,
|
||||||
|
QSize hasSize,
|
||||||
|
int stride,
|
||||||
|
const void *data) const;
|
||||||
|
|
||||||
const not_null<OverlayWidget*> _owner;
|
const not_null<OverlayWidget*> _owner;
|
||||||
|
|
||||||
|
@ -78,13 +95,24 @@ private:
|
||||||
QSize _viewport;
|
QSize _viewport;
|
||||||
float _factor = 1.;
|
float _factor = 1.;
|
||||||
|
|
||||||
QImage _radialCache;
|
std::optional<QOpenGLBuffer> _contentBuffer;
|
||||||
QImage _documentBubbleCache;
|
std::optional<QOpenGLShaderProgram> _imageProgram;
|
||||||
QImage _themePreviewCache;
|
|
||||||
QImage _saveMsgCache;
|
Ui::GL::Textures<3> _textures;
|
||||||
QImage _footerCache;
|
QSize _rgbaSize;
|
||||||
QImage _captionCache;
|
QSize _ySize;
|
||||||
QImage _groupThumbsCache;
|
quint64 _cacheKey = 0;
|
||||||
|
|
||||||
|
Ui::GL::Image _radialImage;
|
||||||
|
Ui::GL::Image _documentBubbleImage;
|
||||||
|
Ui::GL::Image _themePreviewImage;
|
||||||
|
Ui::GL::Image _saveMsgImage;
|
||||||
|
Ui::GL::Image _footerImage;
|
||||||
|
Ui::GL::Image _captionImage;
|
||||||
|
Ui::GL::Image _groupThumbsImage;
|
||||||
|
bool _blendingEnabled = false;
|
||||||
|
|
||||||
|
rpl::lifetime _lifetime;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -24,6 +24,8 @@ void OverlayWidget::RendererSW::paintFallback(
|
||||||
_clip = &clip;
|
_clip = &clip;
|
||||||
_clipOuter = clip.boundingRect();
|
_clipOuter = clip.boundingRect();
|
||||||
_owner->paint(this);
|
_owner->paint(this);
|
||||||
|
_p = nullptr;
|
||||||
|
_clip = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void OverlayWidget::RendererSW::paintBackground() {
|
void OverlayWidget::RendererSW::paintBackground() {
|
||||||
|
|
|
@ -14,7 +14,7 @@ namespace Media::View {
|
||||||
|
|
||||||
class OverlayWidget::RendererSW final : public OverlayWidget::Renderer {
|
class OverlayWidget::RendererSW final : public OverlayWidget::Renderer {
|
||||||
public:
|
public:
|
||||||
RendererSW(not_null<OverlayWidget*> owner);
|
explicit RendererSW(not_null<OverlayWidget*> owner);
|
||||||
|
|
||||||
void paintFallback(
|
void paintFallback(
|
||||||
Painter &&p,
|
Painter &&p,
|
||||||
|
|
|
@ -3121,7 +3121,7 @@ Ui::GL::ChosenRenderer OverlayWidget::chooseRenderer(
|
||||||
? true
|
? true
|
||||||
: capabilities.transparency;
|
: capabilities.transparency;
|
||||||
LOG(("OpenGL: %1 (OverlayWidget)").arg(Logs::b(use)));
|
LOG(("OpenGL: %1 (OverlayWidget)").arg(Logs::b(use)));
|
||||||
if (use && false) {
|
if (use) {
|
||||||
auto renderer = std::make_unique<RendererGL>(this);
|
auto renderer = std::make_unique<RendererGL>(this);
|
||||||
_opengl = true;
|
_opengl = true;
|
||||||
return {
|
return {
|
||||||
|
@ -3160,7 +3160,7 @@ void OverlayWidget::paint(not_null<Renderer*> renderer) {
|
||||||
paintRadialLoading(renderer);
|
paintRadialLoading(renderer);
|
||||||
} else if (_themePreviewShown) {
|
} else if (_themePreviewShown) {
|
||||||
renderer->paintThemePreview(_themePreviewRect);
|
renderer->paintThemePreview(_themePreviewRect);
|
||||||
} else if (documentBubbleShown()) {
|
} else if (documentBubbleShown() && !_docRect.isEmpty()) {
|
||||||
renderer->paintDocumentBubble(_docRect, _docIconRect);
|
renderer->paintDocumentBubble(_docRect, _docIconRect);
|
||||||
}
|
}
|
||||||
updateSaveMsgState();
|
updateSaveMsgState();
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit 8b7aa442268a4928f7582d97b33cb624b29d0cde
|
Subproject commit 0df1579d4a2fe7b18419e5025db380250c86cc53
|
Loading…
Reference in New Issue