Start OpenGL media viewer renderer.

This commit is contained in:
John Preston 2021-06-02 20:36:24 +04:00
parent fc78769e9c
commit 24f8a88625
18 changed files with 1019 additions and 578 deletions

View file

@ -777,6 +777,11 @@ PRIVATE
media/streaming/media_streaming_video_track.h
media/view/media_view_group_thumbs.cpp
media/view/media_view_group_thumbs.h
media/view/media_view_overlay_opengl.cpp
media/view/media_view_overlay_opengl.h
media/view/media_view_overlay_raster.cpp
media/view/media_view_overlay_raster.h
media/view/media_view_overlay_renderer.h
media/view/media_view_overlay_widget.cpp
media/view/media_view_overlay_widget.h
media/view/media_view_pip.cpp

View file

@ -349,7 +349,9 @@ EditColorBox::Slider::Slider(
, _type(type)
, _color(color.red(), color.green(), color.blue())
, _value(valueFromColor(color))
, _transparent((_type == Type::Opacity) ? style::transparentPlaceholderBrush() : QBrush()) {
, _transparent((_type == Type::Opacity)
? style::TransparentPlaceholder()
: QBrush()) {
prepareMinSize();
}
@ -758,7 +760,7 @@ EditColorBox::EditColorBox(
, _greenField(this, st::colorValueInput, "G", 255)
, _blueField(this, st::colorValueInput, "B", 255)
, _result(this, st::colorResultInput)
, _transparent(style::transparentPlaceholderBrush())
, _transparent(style::TransparentPlaceholder())
, _current(current)
, _new(current) {
if (_mode == Mode::RGBA) {

View file

@ -798,7 +798,7 @@ Ui::GL::ChosenRenderer Viewport::chooseRenderer(
};
}
return {
.renderer = std::make_unique<Renderer>(this),
.renderer = std::make_unique<RendererSW>(this),
.backend = Ui::GL::Backend::Raster,
};
}

View file

@ -90,7 +90,7 @@ public:
private:
struct Textures;
class VideoTile;
class Renderer;
class RendererSW;
class RendererGL;
using TileId = quintptr;

View file

@ -174,90 +174,6 @@ vec4 background() {
} };
}
void FillRectVertices(GLfloat *coords, Rect rect) {
coords[0] = coords[10] = rect.left();
coords[1] = coords[11] = rect.top();
coords[2] = rect.right();
coords[3] = rect.top();
coords[4] = coords[6] = rect.right();
coords[5] = coords[7] = rect.bottom();
coords[8] = rect.left();
coords[9] = rect.bottom();
}
void FillTriangles(
QOpenGLFunctions &f,
gsl::span<const GLfloat> coords,
not_null<QOpenGLBuffer*> buffer,
not_null<QOpenGLShaderProgram*> program,
QSize viewportWithFactor,
const QColor &color,
Fn<void()> additional = nullptr) {
Expects(coords.size() % 6 == 0);
if (coords.empty()) {
return;
}
buffer->bind();
buffer->allocate(coords.data(), coords.size() * sizeof(GLfloat));
f.glUseProgram(program->programId());
program->setUniformValue("viewport", QSizeF(viewportWithFactor));
program->setUniformValue("s_color", Uniform(color));
GLint position = program->attributeLocation("position");
f.glVertexAttribPointer(
position,
2,
GL_FLOAT,
GL_FALSE,
2 * sizeof(GLfloat),
nullptr);
f.glEnableVertexAttribArray(position);
if (additional) {
additional();
}
f.glDrawArrays(GL_TRIANGLES, 0, coords.size() / 2);
f.glDisableVertexAttribArray(position);
}
void FillTexturedRectangle(
QOpenGLFunctions &f,
not_null<QOpenGLShaderProgram*> program,
int skipVertices = 0) {
const auto shift = [&](int elements) {
return reinterpret_cast<const void*>(
(skipVertices * 4 + elements) * sizeof(GLfloat));
};
GLint position = program->attributeLocation("position");
f.glVertexAttribPointer(
position,
2,
GL_FLOAT,
GL_FALSE,
4 * sizeof(GLfloat),
shift(0));
f.glEnableVertexAttribArray(position);
GLint texcoord = program->attributeLocation("v_texcoordIn");
f.glVertexAttribPointer(
texcoord,
2,
GL_FLOAT,
GL_FALSE,
4 * sizeof(GLfloat),
shift(2));
f.glEnableVertexAttribArray(texcoord);
f.glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
f.glDisableVertexAttribArray(position);
f.glDisableVertexAttribArray(texcoord);
}
} // namespace
Viewport::RendererGL::RendererGL(not_null<Viewport*> owner)
@ -319,14 +235,7 @@ void Viewport::RendererGL::init(
FragmentRoundCorners(),
})).vertex;
_bgBuffer.emplace();
_bgBuffer->setUsagePattern(QOpenGLBuffer::DynamicDraw);
_bgBuffer->create();
_bgProgram.emplace();
LinkProgram(
&*_bgProgram,
VertexShader({ VertexViewportTransform() }),
FragmentShader({ FragmentStaticColor() }));
_background.init(f);
_imageProgram.emplace();
LinkProgram(
@ -366,10 +275,8 @@ void Viewport::RendererGL::ensureARGB32Program() {
void Viewport::RendererGL::deinit(
not_null<QOpenGLWidget*> widget,
QOpenGLFunctions &f) {
_bgBuffer = std::nullopt;
_frameBuffer = std::nullopt;
_frameVertexShader = nullptr;
_bgProgram = std::nullopt;
_imageProgram = std::nullopt;
_downscaleProgram.argb32 = std::nullopt;
_downscaleProgram.yuv420 = std::nullopt;
@ -381,6 +288,7 @@ void Viewport::RendererGL::deinit(
}
_tileData.clear();
_tileDataIndices.clear();
_background.deinit(f);
_buttons.destroy(f);
}
@ -422,28 +330,13 @@ void Viewport::RendererGL::paint(
void Viewport::RendererGL::fillBackground(QOpenGLFunctions &f) {
const auto radius = st::roundRadiusLarge;
const auto radiuses = QMargins{ radius, radius, radius, radius };
auto bg = QRegion(QRect(QPoint(), _viewport));
auto region = QRegion(QRect(QPoint(), _viewport));
for (const auto &tile : _owner->_tiles) {
if (tile->shown()) {
bg -= tile->geometry().marginsRemoved(radiuses);
region -= tile->geometry().marginsRemoved(radiuses);
}
}
if (bg.isEmpty()) {
return;
}
_bgTriangles.resize((bg.end() - bg.begin()) * 12);
auto coords = _bgTriangles.data();
for (const auto rect : bg) {
FillRectVertices(coords, transformRect(rect));
coords += 12;
}
FillTriangles(
f,
_bgTriangles,
&*_bgBuffer,
&*_bgProgram,
_viewport * _factor,
st::groupCallBg->c);
_background.fill(f, region, _viewport, _factor, st::groupCallBg);
}
void Viewport::RendererGL::paintTile(
@ -957,12 +850,7 @@ void Viewport::RendererGL::drawFirstBlurPass(
}
Rect Viewport::RendererGL::transformRect(const Rect &raster) const {
return {
raster.left() * _factor,
float(_viewport.height() - raster.bottom()) * _factor,
raster.width() * _factor,
raster.height() * _factor,
};
return TransformRect(raster, _viewport, _factor);
}
Rect Viewport::RendererGL::transformRect(const QRect &raster) const {

View file

@ -11,6 +11,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/round_rect.h"
#include "ui/effects/animations.h"
#include "ui/effects/cross_line.h"
#include "ui/gl/gl_primitives.h"
#include "ui/gl/gl_surface.h"
#include "ui/gl/gl_image.h"
@ -116,13 +117,12 @@ private:
GLfloat _factor = 1.;
QSize _viewport;
bool _rgbaFrame = false;
Ui::GL::BackgroundFiller _background;
std::optional<QOpenGLBuffer> _frameBuffer;
std::optional<QOpenGLBuffer> _bgBuffer;
Program _downscaleProgram;
std::optional<QOpenGLShaderProgram> _blurProgram;
Program _frameProgram;
std::optional<QOpenGLShaderProgram> _imageProgram;
std::optional<QOpenGLShaderProgram> _bgProgram;
QOpenGLShader *_downscaleVertexShader = nullptr;
QOpenGLShader *_frameVertexShader = nullptr;
@ -137,7 +137,6 @@ private:
std::vector<TileData> _tileData;
std::vector<int> _tileDataIndices;
std::vector<GLfloat> _bgTriangles;
Ui::CrossLineAnimation _pinIcon;
Ui::CrossLineAnimation _muteIcon;
Ui::RoundRect _pinBackground;

View file

@ -18,7 +18,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
namespace Calls::Group {
Viewport::Renderer::Renderer(not_null<Viewport*> owner)
Viewport::RendererSW::RendererSW(not_null<Viewport*> owner)
: _owner(owner)
, _pinIcon(st::groupCallVideoTile.pin)
, _pinBackground(
@ -28,27 +28,25 @@ Viewport::Renderer::Renderer(not_null<Viewport*> owner)
st::radialBg) {
}
void Viewport::Renderer::paintFallback(
void Viewport::RendererSW::paintFallback(
Painter &&p,
const QRegion &clip,
Ui::GL::Backend backend) {
auto bg = clip;
auto hq = PainterHighQualityEnabler(p);
const auto bounding = clip.boundingRect();
const auto opengl = (backend == Ui::GL::Backend::OpenGL);
for (const auto &tile : _owner->_tiles) {
paintTile(p, tile.get(), bounding, opengl, bg);
paintTile(p, tile.get(), bounding, bg);
}
for (const auto rect : bg) {
p.fillRect(rect, st::groupCallBg);
}
}
void Viewport::Renderer::paintTile(
void Viewport::RendererSW::paintTile(
Painter &p,
not_null<VideoTile*> tile,
const QRect &clip,
bool opengl,
QRegion &bg) {
const auto track = tile->track();
const auto data = track->frameWithInfo(true);
@ -79,7 +77,7 @@ void Viewport::Renderer::paintTile(
const auto left = (width - scaled.width()) / 2;
const auto top = (height - scaled.height()) / 2;
const auto target = QRect(QPoint(x + left, y + top), scaled);
if (UsePainterRotation(rotation, opengl)) {
if (UsePainterRotation(rotation, false)) {
if (rotation) {
p.save();
p.rotate(rotation);
@ -113,7 +111,7 @@ void Viewport::Renderer::paintTile(
paintTileOutline(p, x, y, width, height, tile);
}
void Viewport::Renderer::paintTileOutline(
void Viewport::RendererSW::paintTileOutline(
Painter &p,
int x,
int y,
@ -137,7 +135,7 @@ void Viewport::Renderer::paintTileOutline(
p.fillRect(x, y + height - outline, width - outline, outline, color);
}
void Viewport::Renderer::paintTileControls(
void Viewport::RendererSW::paintTileControls(
Painter &p,
int x,
int y,

View file

@ -15,9 +15,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
namespace Calls::Group {
class Viewport::Renderer final : public Ui::GL::Renderer {
class Viewport::RendererSW final : public Ui::GL::Renderer {
public:
explicit Renderer(not_null<Viewport*> owner);
explicit RendererSW(not_null<Viewport*> owner);
void paintFallback(
Painter &&p,
@ -29,7 +29,6 @@ private:
Painter &p,
not_null<VideoTile*> tile,
const QRect &clip,
bool opengl,
QRegion &bg);
void paintTileOutline(
Painter &p,

View file

@ -237,7 +237,7 @@ mediaviewTextOpacity: 0.5;
mediaviewTextOverOpacity: 1;
mediaviewIconOpacity: 0.45;
mediaviewIconOverOpacity: 1;
mediaviewIconOverOpacity: 1.;
mediaviewControlBgOpacity: 0.3;
mediaviewControlMargin: 0px;
mediaviewControlSize: 90px;

View file

@ -0,0 +1,183 @@
/*
This file is part of Telegram Desktop,
the official desktop application for the Telegram messaging service.
For license and copyright information please follow this link:
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#include "media/view/media_view_overlay_opengl.h"
#include "base/platform/base_platform_info.h"
namespace Media::View {
void OverlayWidget::RendererGL::init(
not_null<QOpenGLWidget*> widget,
QOpenGLFunctions &f) {
_background.init(f);
}
void OverlayWidget::RendererGL::deinit(
not_null<QOpenGLWidget*> widget,
QOpenGLFunctions &f) {
_background.deinit(f);
}
void OverlayWidget::RendererGL::resize(
not_null<QOpenGLWidget*> widget,
QOpenGLFunctions &f,
int w,
int h) {
_factor = widget->devicePixelRatio();
_viewport = QSize(w, h);
setDefaultViewport(f);
}
void OverlayWidget::RendererGL::setDefaultViewport(QOpenGLFunctions &f) {
const auto size = _viewport * _factor;
f.glViewport(0, 0, size.width(), size.height());
}
void OverlayWidget::RendererGL::paint(
not_null<QOpenGLWidget*> widget,
QOpenGLFunctions &f) {
if (handleHideWorkaround(f)) {
return;
}
_f = &f;
_owner->paint(this);
}
bool OverlayWidget::RendererGL::handleHideWorkaround(QOpenGLFunctions &f) {
if (!Platform::IsWindows() || !_owner->_hideWorkaround) {
return false;
}
// This is needed on Windows,
// because on reopen it blinks with the last shown content.
f.glClearColor(0., 0., 0., 0.);
f.glClear(GL_COLOR_BUFFER_BIT);
return true;
}
void OverlayWidget::RendererGL::paintBackground() {
const auto &bg = _owner->_fullScreenVideo
? st::mediaviewVideoBg
: st::mediaviewBg;
auto fill = QRegion(QRect(QPoint(), _viewport));
if (_owner->opaqueContentShown()) {
fill -= _owner->contentRect();
}
_background.fill(
*_f,
fill,
_viewport,
_factor,
bg);
}
void OverlayWidget::RendererGL::paintTransformedVideoFrame(
QRect rect,
int rotation) {
}
void OverlayWidget::RendererGL::paintTransformedStaticContent(
const QImage &image,
QRect rect,
int rotation,
bool fillTransparentBackground) {
}
void OverlayWidget::RendererGL::paintRadialLoading(
QRect inner,
bool radial,
float64 radialOpacity) {
paintToCache(_radialCache, inner.size(), [&](Painter &&p) {
const auto newInner = QRect(QPoint(), inner.size());
_owner->paintRadialLoadingContent(p, newInner, radial, radialOpacity);
}, true);
//p.drawImage(inner.topLeft(), _radialCache);
}
void OverlayWidget::RendererGL::paintThemePreview(QRect outer) {
paintToCache(_themePreviewCache, outer.size(), [&](Painter &&p) {
const auto newOuter = QRect(QPoint(), outer.size());
_owner->paintThemePreviewContent(p, newOuter, newOuter);
});
}
void OverlayWidget::RendererGL::paintDocumentBubble(
QRect outer,
QRect icon) {
paintToCache(_documentBubbleCache, outer.size(), [&](Painter &&p) {
const auto newOuter = QRect(QPoint(), outer.size());
const auto newIcon = icon.translated(-outer.topLeft());
_owner->paintDocumentBubbleContent(p, newOuter, newIcon, newOuter);
});
//p.drawImage(outer.topLeft(), _documentBubbleCache);
_owner->paintRadialLoading(this);
}
void OverlayWidget::RendererGL::paintSaveMsg(QRect outer) {
paintToCache(_saveMsgCache, outer.size(), [&](Painter &&p) {
const auto newOuter = QRect(QPoint(), outer.size());
_owner->paintSaveMsgContent(p, newOuter, newOuter);
}, true);
//p.drawImage(outer.topLeft(), _saveMsgCache);
}
void OverlayWidget::RendererGL::paintControl(
OverState control,
QRect outer,
float64 outerOpacity,
QRect inner,
float64 innerOpacity,
const style::icon &icon) {
}
void OverlayWidget::RendererGL::paintFooter(QRect outer, float64 opacity) {
paintToCache(_footerCache, outer.size(), [&](Painter &&p) {
const auto newOuter = QRect(QPoint(), outer.size());
_owner->paintFooterContent(p, newOuter, newOuter, opacity);
}, true);
//p.drawImage(outer, _footerCache, QRect(QPoint(), outer.size()) * factor);
}
void OverlayWidget::RendererGL::paintCaption(QRect outer, float64 opacity) {
paintToCache(_captionCache, outer.size(), [&](Painter &&p) {
const auto newOuter = QRect(QPoint(), outer.size());
_owner->paintCaptionContent(p, newOuter, newOuter, opacity);
});
//p.drawImage(outer, _captionCache, ...);
}
void OverlayWidget::RendererGL::paintGroupThumbs(
QRect outer,
float64 opacity) {
paintToCache(_groupThumbsCache, outer.size(), [&](Painter &&p) {
const auto newOuter = QRect(QPoint(), outer.size());
_owner->paintGroupThumbsContent(p, newOuter, newOuter, opacity);
});
}
void OverlayWidget::RendererGL::paintToCache(
QImage &cache,
QSize size,
Fn<void(Painter&&)> method,
bool clear) {
if (cache.width() < size.width() * _factor
|| cache.height() < size.height() * _factor) {
cache = QImage(
size * _factor,
QImage::Format_ARGB32_Premultiplied);
cache.setDevicePixelRatio(_factor);
} else if (cache.devicePixelRatio() != _factor) {
cache.setDevicePixelRatio(_factor);
}
if (clear) {
cache.fill(Qt::transparent);
}
method(Painter(&cache));
}
} // namespace Media::View

View file

@ -0,0 +1,91 @@
/*
This file is part of Telegram Desktop,
the official desktop application for the Telegram messaging service.
For license and copyright information please follow this link:
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#pragma once
#include "media/view/media_view_overlay_renderer.h"
#include "ui/gl/gl_surface.h"
#include "ui/gl/gl_primitives.h"
namespace Media::View {
class OverlayWidget::RendererGL final : public OverlayWidget::Renderer {
public:
RendererGL(not_null<OverlayWidget*> owner) : _owner(owner) {
}
void init(
not_null<QOpenGLWidget*> widget,
QOpenGLFunctions &f) override;
void deinit(
not_null<QOpenGLWidget*> widget,
QOpenGLFunctions &f) override;
void resize(
not_null<QOpenGLWidget*> widget,
QOpenGLFunctions &f,
int w,
int h);
void paint(
not_null<QOpenGLWidget*> widget,
QOpenGLFunctions &f) override;
private:
bool handleHideWorkaround(QOpenGLFunctions &f);
void setDefaultViewport(QOpenGLFunctions &f);
void paintBackground();
void paintTransformedVideoFrame(QRect rect, int rotation) override;
void paintTransformedStaticContent(
const QImage &image,
QRect rect,
int rotation,
bool fillTransparentBackground) override;
void paintRadialLoading(
QRect inner,
bool radial,
float64 radialOpacity) override;
void paintThemePreview(QRect outer) override;
void paintDocumentBubble(QRect outer, QRect icon) override;
void paintSaveMsg(QRect outer) override;
void paintControl(
OverState control,
QRect outer,
float64 outerOpacity,
QRect inner,
float64 innerOpacity,
const style::icon &icon) override;
void paintFooter(QRect outer, float64 opacity) override;
void paintCaption(QRect outer, float64 opacity) override;
void paintGroupThumbs(QRect outer, float64 opacity) override;
void paintToCache(
QImage &cache,
QSize size,
Fn<void(Painter&&)> method,
bool clear = false);
const not_null<OverlayWidget*> _owner;
QOpenGLFunctions *_f = nullptr;
Ui::GL::BackgroundFiller _background;
QSize _viewport;
float _factor = 1.;
QImage _radialCache;
QImage _documentBubbleCache;
QImage _themePreviewCache;
QImage _saveMsgCache;
QImage _footerCache;
QImage _captionCache;
QImage _groupThumbsCache;
};
} // namespace Media::View

View file

@ -0,0 +1,166 @@
/*
This file is part of Telegram Desktop,
the official desktop application for the Telegram messaging service.
For license and copyright information please follow this link:
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#include "media/view/media_view_overlay_raster.h"
#include "media/view/media_view_pip.h"
namespace Media::View {
OverlayWidget::RendererSW::RendererSW(not_null<OverlayWidget*> owner)
: _owner(owner)
, _transparentBrush(style::TransparentPlaceholder()) {
}
void OverlayWidget::RendererSW::paintFallback(
Painter &&p,
const QRegion &clip,
Ui::GL::Backend backend) {
_p = &p;
_clip = &clip;
_clipOuter = clip.boundingRect();
_owner->paint(this);
}
void OverlayWidget::RendererSW::paintBackground() {
const auto region = _owner->opaqueContentShown()
? (*_clip - _owner->contentRect())
: *_clip;
const auto m = _p->compositionMode();
_p->setCompositionMode(QPainter::CompositionMode_Source);
const auto &bg = _owner->_fullScreenVideo
? st::mediaviewVideoBg
: st::mediaviewBg;
for (const auto rect : region) {
_p->fillRect(rect, bg);
}
_p->setCompositionMode(m);
}
void OverlayWidget::RendererSW::paintTransformedVideoFrame(
QRect rect,
int rotation) {
Expects(_owner->_streamed != nullptr);
if (!rect.intersects(_clipOuter)) {
return;
}
paintTransformedImage(_owner->videoFrame(), rect, rotation);
}
void OverlayWidget::RendererSW::paintTransformedStaticContent(
const QImage &image,
QRect rect,
int rotation,
bool fillTransparentBackground) {
if (!rect.intersects(_clipOuter)) {
return;
}
if (fillTransparentBackground) {
_p->fillRect(rect, _transparentBrush);
}
if (image.isNull()) {
return;
}
paintTransformedImage(image, rect, rotation);
}
void OverlayWidget::RendererSW::paintTransformedImage(
const QImage &image,
QRect rect,
int rotation) {
PainterHighQualityEnabler hq(*_p);
if (UsePainterRotation(rotation, false)) {
if (rotation) {
_p->save();
_p->rotate(rotation);
}
_p->drawImage(RotatedRect(rect, rotation), image);
if (rotation) {
_p->restore();
}
} else {
_p->drawImage(rect, _owner->transformShownContent(image, rotation));
}
}
void OverlayWidget::RendererSW::paintRadialLoading(
QRect inner,
bool radial,
float64 radialOpacity) {
_owner->paintRadialLoadingContent(*_p, inner, radial, radialOpacity);
}
void OverlayWidget::RendererSW::paintThemePreview(QRect outer) {
_owner->paintThemePreviewContent(*_p, outer, _clipOuter);
}
void OverlayWidget::RendererSW::paintDocumentBubble(
QRect outer,
QRect icon) {
if (outer.intersects(_clipOuter)) {
_owner->paintDocumentBubbleContent(*_p, outer, icon, _clipOuter);
if (icon.intersects(_clipOuter)) {
_owner->paintRadialLoading(this);
}
}
}
void OverlayWidget::RendererSW::paintSaveMsg(QRect outer) {
if (outer.intersects(_clipOuter)) {
_owner->paintSaveMsgContent(*_p, outer, _clipOuter);
}
}
void OverlayWidget::RendererSW::paintControl(
OverState control,
QRect outer,
float64 outerOpacity,
QRect inner,
float64 innerOpacity,
const style::icon &icon) {
if (!outer.isEmpty() && !outer.intersects(_clipOuter)) {
return;
}
if (!outer.isEmpty() && outerOpacity > 0) {
_p->setOpacity(outerOpacity);
for (const auto &rect : *_clip) {
const auto fill = outer.intersected(rect);
if (!fill.isEmpty()) {
_p->fillRect(fill, st::mediaviewControlBg);
}
}
}
if (inner.intersects(_clipOuter)) {
_p->setOpacity(innerOpacity);
icon.paintInCenter(*_p, inner);
}
}
void OverlayWidget::RendererSW::paintFooter(QRect outer, float64 opacity) {
if (outer.intersects(_clipOuter)) {
_owner->paintFooterContent(*_p, outer, _clipOuter, opacity);
}
}
void OverlayWidget::RendererSW::paintCaption(QRect outer, float64 opacity) {
if (outer.intersects(_clipOuter)) {
_owner->paintCaptionContent(*_p, outer, _clipOuter, opacity);
}
}
void OverlayWidget::RendererSW::paintGroupThumbs(
QRect outer,
float64 opacity) {
if (outer.intersects(_clipOuter)) {
_owner->paintGroupThumbsContent(*_p, outer, _clipOuter, opacity);
}
}
} // namespace Media::View

View file

@ -0,0 +1,63 @@
/*
This file is part of Telegram Desktop,
the official desktop application for the Telegram messaging service.
For license and copyright information please follow this link:
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#pragma once
#include "media/view/media_view_overlay_renderer.h"
#include "ui/gl/gl_surface.h"
namespace Media::View {
class OverlayWidget::RendererSW final : public OverlayWidget::Renderer {
public:
RendererSW(not_null<OverlayWidget*> owner);
void paintFallback(
Painter &&p,
const QRegion &clip,
Ui::GL::Backend backend) override;
private:
void paintBackground() override;
void paintTransformedVideoFrame(QRect rect, int rotation) override;
void paintTransformedStaticContent(
const QImage &image,
QRect rect,
int rotation,
bool fillTransparentBackground) override;
void paintTransformedImage(
const QImage &image,
QRect rect,
int rotation);
void paintRadialLoading(
QRect inner,
bool radial,
float64 radialOpacity) override;
void paintThemePreview(QRect outer) override;
void paintDocumentBubble(QRect outer, QRect icon) override;
void paintSaveMsg(QRect outer) override;
void paintControl(
OverState control,
QRect outer,
float64 outerOpacity,
QRect inner,
float64 innerOpacity,
const style::icon &icon) override;
void paintFooter(QRect outer, float64 opacity) override;
void paintCaption(QRect outer, float64 opacity) override;
void paintGroupThumbs(QRect outer, float64 opacity) override;
const not_null<OverlayWidget*> _owner;
QBrush _transparentBrush;
Painter *_p = nullptr;
const QRegion *_clip = nullptr;
QRect _clipOuter;
};
} // namespace Media::View

View file

@ -0,0 +1,43 @@
/*
This file is part of Telegram Desktop,
the official desktop application for the Telegram messaging service.
For license and copyright information please follow this link:
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#pragma once
#include "media/view/media_view_overlay_widget.h"
namespace Media::View {
class OverlayWidget::Renderer : public Ui::GL::Renderer {
public:
virtual void paintBackground() = 0;
virtual void paintTransformedVideoFrame(QRect rect, int rotation) = 0;
virtual void paintTransformedStaticContent(
const QImage &image,
QRect rect,
int rotation,
bool fillTransparentBackground) = 0;
virtual void paintRadialLoading(
QRect inner,
bool radial,
float64 radialOpacity) = 0;
virtual void paintThemePreview(QRect outer) = 0;
virtual void paintDocumentBubble(QRect outer, QRect icon) = 0;
virtual void paintSaveMsg(QRect outer) = 0;
virtual void paintControl(
OverState control,
QRect outer,
float64 outerOpacity,
QRect inner,
float64 innerOpacity,
const style::icon &icon) = 0;
virtual void paintFooter(QRect outer, float64 opacity) = 0;
virtual void paintCaption(QRect outer, float64 opacity) = 0;
virtual void paintGroupThumbs(QRect outer, float64 opacity) = 0;
};
} // namespace Media::View

File diff suppressed because it is too large Load diff

View file

@ -9,6 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "base/timer.h"
#include "ui/rp_widget.h"
#include "ui/gl/gl_surface.h"
#include "ui/widgets/dropdown_menu.h"
#include "ui/effects/animations.h"
#include "ui/effects/radial_animation.h"
@ -50,8 +51,7 @@ enum class Error;
} // namespace Streaming
} // namespace Media
namespace Media {
namespace View {
namespace Media::View {
class GroupThumbs;
class Pip;
@ -111,7 +111,11 @@ public:
private:
struct Streamed;
struct PipWrap;
class Renderer;
class RendererSW;
class RendererGL;
// If changing, see paintControls()!
enum OverState {
OverNone,
OverLeftNav,
@ -147,7 +151,7 @@ private:
[[nodiscard]] Ui::GL::ChosenRenderer chooseRenderer(
Ui::GL::Capabilities capabilities);
void paint(Painter &p, const QRegion &clip);
void paint(not_null<Renderer*> renderer);
void handleMousePress(QPoint position, Qt::MouseButton button);
void handleMouseRelease(QPoint position, Qt::MouseButton button);
@ -342,13 +346,39 @@ private:
void zoomReset();
void zoomUpdate(int32 &newZoom);
void paintRadialLoading(Painter &p, bool radial, float64 radialOpacity);
void paintRadialLoading(not_null<Renderer*> renderer);
void paintRadialLoadingContent(
Painter &p,
QRect inner,
bool radial,
float64 radialOpacity) const;
void paintThemePreview(Painter &p, QRect clip);
void paintThemePreviewContent(Painter &p, QRect outer, QRect clip);
void paintDocumentBubbleContent(
Painter &p,
QRect outer,
QRect icon,
QRect clip) const;
void paintSaveMsgContent(Painter &p, QRect outer, QRect clip);
void paintControls(not_null<Renderer*> renderer, float64 opacity);
void paintFooterContent(
Painter &p,
QRect outer,
QRect clip,
float64 opacity);
[[nodiscard]] QRect footerGeometry() const;
void paintCaptionContent(
Painter &p,
QRect outer,
QRect clip,
float64 opacity);
[[nodiscard]] QRect captionGeometry() const;
void paintGroupThumbsContent(
Painter &p,
QRect outer,
QRect clip,
float64 opacity);
void updateSaveMsgState();
void updateOverRect(OverState state);
bool updateOverState(OverState newState);
@ -367,13 +397,14 @@ private:
[[nodiscard]] QSize videoSize() const;
[[nodiscard]] bool videoIsGifOrUserpic() const;
[[nodiscard]] QImage videoFrame() const;
[[nodiscard]] QImage videoFrameForDirectPaint() const;
[[nodiscard]] QImage transformVideoFrame(QImage frame) const;
[[nodiscard]] QImage transformStaticContent(QPixmap content) const;
[[nodiscard]] QImage transformedShownContent() const;
[[nodiscard]] QImage transformShownContent(
QImage content,
int rotation) const;
[[nodiscard]] bool documentContentShown() const;
[[nodiscard]] bool documentBubbleShown() const;
void paintTransformedVideoFrame(Painter &p);
void paintTransformedStaticContent(Painter &p);
[[nodiscard]] bool contentShown() const;
[[nodiscard]] bool opaqueContentShown() const;
void clearStreaming(bool savePosition = true);
bool canInitStreaming() const;
@ -382,7 +413,6 @@ private:
bool _opengl = false;
const std::unique_ptr<Ui::RpWidgetWrap> _surface;
const not_null<QWidget*> _widget;
QBrush _transparentBrush;
Main::Session *_session = nullptr;
rpl::lifetime _sessionLifetime;
@ -436,7 +466,7 @@ private:
QPoint _mStart;
bool _pressed = false;
int32 _dragging = 0;
QPixmap _staticContent;
QImage _staticContent;
bool _blurred = true;
rpl::lifetime _screenGeometryLifetime;
@ -451,6 +481,7 @@ private:
QString _docName, _docSize, _docExt;
int _docNameWidth = 0, _docSizeWidth = 0, _docExtWidth = 0;
QRect _docRect, _docIconRect;
QImage _docRectImage;
int _docThumbx = 0, _docThumby = 0, _docThumbw = 0;
object_ptr<Ui::LinkButton> _docDownload;
object_ptr<Ui::LinkButton> _docSaveAs;
@ -458,7 +489,6 @@ private:
QRect _photoRadialRect;
Ui::RadialAnimation _radial;
QImage _radialCache;
History *_migrated = nullptr;
History *_history = nullptr; // if conversation photos or files overview
@ -519,6 +549,7 @@ private:
crl::time _saveMsgStarted = 0;
anim::value _saveMsgOpacity;
QRect _saveMsg;
QImage _saveMsgImage;
base::Timer _saveMsgUpdater;
Ui::Text::String _saveMsgText;
SavePhotoVideo _savePhotoVideoWhenLoaded = SavePhotoVideo::None;
@ -545,5 +576,4 @@ private:
};
} // namespace View
} // namespace Media
} // namespace Media::View

View file

@ -165,7 +165,7 @@ void EditorBlock::Row::fillSearchIndex() {
EditorBlock::EditorBlock(QWidget *parent, Type type, Context *context) : TWidget(parent)
, _type(type)
, _context(context)
, _transparent(style::transparentPlaceholderBrush()) {
, _transparent(style::TransparentPlaceholder()) {
setMouseTracking(true);
subscribe(_context->updated, [this] {
if (_mouseSelection) {

@ -1 +1 @@
Subproject commit e6b736e718abd783e0ca32b471846f0ec38d0750
Subproject commit 8b7aa442268a4928f7582d97b33cb624b29d0cde