Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

preroll waveformrenderer using rendergraph #14190

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
148 changes: 68 additions & 80 deletions src/waveform/renderers/allshader/waveformrendererpreroll.cpp
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
#include "waveform/renderers/allshader/waveformrendererpreroll.h"

#include <QDomNode>
#include <QOpenGLTexture>
#include <QPainterPath>
#include <array>

#include "rendergraph/geometry.h"
#include "rendergraph/material/patternmaterial.h"
#include "rendergraph/vertexupdaters/texturedvertexupdater.h"
#include "skin/legacy/skincontext.h"
#include "waveform/renderers/allshader/matrixforwidgetgeometry.h"
#include "waveform/renderers/waveformwidgetrenderer.h"
#include "widget/wskincolor.h"

Expand All @@ -20,7 +21,7 @@ QImage drawPrerollImage(float markerLength,
const float imageW = static_cast<float>(imagePixelW) / devicePixelRatio;
const float imageH = static_cast<float>(imagePixelH) / devicePixelRatio;

QImage image(imagePixelW, imagePixelH, QImage::Format_ARGB32_Premultiplied);
QImage image(imagePixelW, imagePixelH, QImage::Format_RGBA8888_Premultiplied);
Comment on lines -23 to +24
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you quickly explain your rationale behind this?
According to the QImage docs:

Note: Avoid most rendering directly to most of these formats using QPainter. Rendering is best optimized to the Format_RGB32 and Format_ARGB32_Premultiplied formats, and secondarily for rendering to the Format_RGB16, Format_RGBX8888, Format_RGBA8888_Premultiplied, Format_RGBX64 and Format_RGBA64_Premultiplied formats

image.setDevicePixelRatio(devicePixelRatio);

const float penWidth = 1.5f;
Expand All @@ -47,7 +48,7 @@ QImage drawPrerollImage(float markerLength,
path.lineTo(p0);
path.closeSubpath();
QColor fillColor = color;
fillColor.setAlphaF(0.5f);
fillColor.setAlphaF(0.25f);
painter.fillPath(path, QBrush(fillColor));

painter.drawPath(path);
Expand All @@ -57,31 +58,52 @@ QImage drawPrerollImage(float markerLength,
}
} // anonymous namespace

using namespace rendergraph;

namespace allshader {

WaveformRendererPreroll::WaveformRendererPreroll(
WaveformWidgetRenderer* waveformWidget,
::WaveformRendererAbstract::PositionSource type)
: WaveformRenderer(waveformWidget),
: ::WaveformRendererAbstract(waveformWidget),
m_isSlipRenderer(type == ::WaveformRendererAbstract::Slip) {
setGeometry(std::make_unique<Geometry>(PatternMaterial::attributes(), 0));
setMaterial(std::make_unique<PatternMaterial>());
setUsePreprocess(true);
geometry().setDrawingMode(Geometry::DrawingMode::Triangles);
}

WaveformRendererPreroll::~WaveformRendererPreroll() = default;

void WaveformRendererPreroll::setup(
const QDomNode& node, const SkinContext& context) {
m_color = QColor(context.selectString(node, "SignalColor"));
const QDomNode& node, const SkinContext& skinContext) {
m_color = QColor(skinContext.selectString(node, QStringLiteral("SignalColor")));
m_color = WSkinColor::getCorrectColor(m_color);
}

void WaveformRendererPreroll::initializeGL() {
m_shader.init();
void WaveformRendererPreroll::draw(QPainter* painter, QPaintEvent* event) {
Q_UNUSED(painter);
Q_UNUSED(event);
DEBUG_ASSERT(false);
}

void WaveformRendererPreroll::preprocess() {
if (!preprocessInner()) {
if (geometry().vertexCount() != 0) {
geometry().allocate(0);
markDirtyGeometry();
}
} else {
markDirtyMaterial();
markDirtyGeometry();
}
}

void WaveformRendererPreroll::paintGL() {
const TrackPointer track = m_waveformRenderer->getTrackInfo();
if (!track || (m_isSlipRenderer && !m_waveformRenderer->isSlipActive())) {
return;
bool WaveformRendererPreroll::preprocessInner() {
const TrackPointer trackInfo = m_waveformRenderer->getTrackInfo();

if (!trackInfo || (m_isSlipRenderer && !m_waveformRenderer->isSlipActive())) {
return false;
}

auto positionType = m_isSlipRenderer ? ::WaveformRendererAbstract::Slip
Expand All @@ -95,11 +117,15 @@ void WaveformRendererPreroll::paintGL() {
// to indicate the respective zones.
const bool preRollVisible = firstDisplayedPosition < 0;
const bool postRollVisible = lastDisplayedPosition > 1;
const int numVerticesPerRectangle = 6;

if (!(preRollVisible || postRollVisible)) {
return;
if (!preRollVisible && !postRollVisible) {
return false;
}

const int reserved = (preRollVisible ? numVerticesPerRectangle : 0) +
(postRollVisible ? numVerticesPerRectangle : 0);
Comment on lines +126 to +127
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

does it make sense to move closer to the first use? and potentially give it a better name?


const double playMarkerPosition = m_waveformRenderer->getPlayMarkerPosition();
const double vSamplesPerPixel = m_waveformRenderer->getVisualSamplePerPixel();
const double numberOfVSamples = m_waveformRenderer->getLength() * vSamplesPerPixel;
Expand All @@ -125,36 +151,20 @@ void WaveformRendererPreroll::paintGL() {
// has changed size last time.
m_markerLength = markerLength;
m_markerBreadth = markerBreadth;
m_texture.setData(drawPrerollImage(m_markerLength,
m_markerBreadth,
m_waveformRenderer->getDevicePixelRatio(),
m_color));
dynamic_cast<PatternMaterial&>(material())
.setTexture(std::make_unique<Texture>(m_waveformRenderer->getContext(),
drawPrerollImage(m_markerLength,
Comment on lines +154 to +156
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

does this allocate continuously in the hot paintGL path?

m_markerBreadth,
m_waveformRenderer->getDevicePixelRatio(),
m_color)));
}

if (!m_texture.isStorageAllocated()) {
return;
}

const int matrixLocation = m_shader.matrixLocation();
const int textureLocation = m_shader.textureLocation();
const int positionLocation = m_shader.positionLocation();
const int texcoordLocation = m_shader.texcoordLocation();

// Set up the shader
m_shader.bind();

m_shader.enableAttributeArray(positionLocation);
m_shader.enableAttributeArray(texcoordLocation);

const QMatrix4x4 matrix = matrixForWidgetGeometry(m_waveformRenderer, false);

m_shader.setUniformValue(matrixLocation, matrix);
m_shader.setUniformValue(textureLocation, 0);

m_texture.bind();
geometry().allocate(reserved);

const float end = m_waveformRenderer->getLength();

TexturedVertexUpdater vertexUpdater{geometry().vertexDataAs<Geometry::TexturedPoint2D>()};

if (preRollVisible) {
// VSample position of the right-most triangle's tip
const double triangleTipVSamplePosition =
Expand All @@ -168,11 +178,14 @@ void WaveformRendererPreroll::paintGL() {
x -= std::ceil((x - limit) / markerLength) * markerLength;
}

drawPattern(x,
halfBreadth - halfMarkerBreadth,
0.f,
m_isSlipRenderer ? halfBreadth : halfBreadth + halfMarkerBreadth,
x / markerLength);
const float repetitions = x / markerLength;

vertexUpdater.addRectangle({x, halfBreadth - halfMarkerBreadth},
{0,
m_isSlipRenderer ? halfBreadth
: halfBreadth + halfMarkerBreadth},
{0.f, 0.f},
{repetitions, m_isSlipRenderer ? 0.5f : 1.f});
}

if (postRollVisible) {
Expand All @@ -189,44 +202,19 @@ void WaveformRendererPreroll::paintGL() {
x += std::ceil((limit - x) / markerLength) * markerLength;
}

drawPattern(x,
halfBreadth - halfMarkerBreadth,
end,
m_isSlipRenderer ? halfBreadth : halfBreadth + halfMarkerBreadth,
(end - x) / markerLength);
}
const float repetitions = (end - x) / markerLength;

m_texture.release();
vertexUpdater.addRectangle({x, halfBreadth - halfMarkerBreadth},
{end,
m_isSlipRenderer ? halfBreadth
: halfBreadth + halfMarkerBreadth},
{0.f, 0.f},
{repetitions, m_isSlipRenderer ? 0.5f : 1.f});
}

m_shader.disableAttributeArray(positionLocation);
m_shader.disableAttributeArray(texcoordLocation);
m_shader.release();
}
DEBUG_ASSERT(reserved == vertexUpdater.index());

void WaveformRendererPreroll::drawPattern(
float x1, float y1, float x2, float y2, float repetitions) {
// Draw a large rectangle with a repeating pattern of the texture
const int repetitionsLocation = m_shader.repetitionsLocation();
const int positionLocation = m_shader.positionLocation();
const int texcoordLocation = m_shader.texcoordLocation();

const std::array<float, 8> positionArray = {x1, y1, x2, y1, x1, y2, x2, y2};
const std::array<float, 8> texcoordArray = {0.f,
0.f,
1.f,
0.f,
0.f,
m_isSlipRenderer ? 0.5f : 1.f,
1.f,
m_isSlipRenderer ? 0.5f : 1.f};
m_shader.setUniformValue(repetitionsLocation, QVector2D(repetitions, 1.0));

m_shader.setAttributeArray(
positionLocation, GL_FLOAT, positionArray.data(), 2);
m_shader.setAttributeArray(
texcoordLocation, GL_FLOAT, texcoordArray.data(), 2);

glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
return true;
}

} // namespace allshader
28 changes: 12 additions & 16 deletions src/waveform/renderers/allshader/waveformrendererpreroll.h
Original file line number Diff line number Diff line change
@@ -1,48 +1,44 @@
#pragma once

#include <QColor>
#include <QImage>
#include <memory>

#include "rendergraph/openglnode.h"
#include "shaders/patternshader.h"
#include "rendergraph/geometrynode.h"
#include "util/class.h"
#include "util/opengltexture2d.h"
#include "waveform/renderers/allshader/vertexdata.h"
#include "waveform/renderers/allshader/waveformrenderer.h"
#include "waveform/renderers/waveformrendererabstract.h"

class QDomNode;
class SkinContext;
class QOpenGLTexture;

namespace allshader {
class WaveformRendererPreroll;
}

class allshader::WaveformRendererPreroll final
: public allshader::WaveformRenderer,
public rendergraph::OpenGLNode {
: public ::WaveformRendererAbstract,
public rendergraph::GeometryNode {
public:
explicit WaveformRendererPreroll(
WaveformWidgetRenderer* waveformWidget,
::WaveformRendererAbstract::PositionSource type =
::WaveformRendererAbstract::Play);
~WaveformRendererPreroll() override;

// Pure virtual from WaveformRendererAbstract, not used
void draw(QPainter* painter, QPaintEvent* event) override final;

void setup(const QDomNode& node, const SkinContext& skinContext) override;
void paintGL() override;
void initializeGL() override;

private:
void drawPattern(float x1, float y1, float x2, float y2, float repetitions);
// Virtual for rendergraph::Node
void preprocess() override;

mixxx::PatternShader m_shader;
private:
QColor m_color;
float m_markerBreadth{};
float m_markerLength{};
OpenGLTexture2D m_texture;

bool m_isSlipRenderer;

bool preprocessInner();

DISALLOW_COPY_AND_ASSIGN(WaveformRendererPreroll);
};
24 changes: 9 additions & 15 deletions src/waveform/renderers/waveformwidgetrenderer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,13 +39,11 @@ WaveformWidgetRenderer::WaveformWidgetRenderer(const QString& group)
// Really create some to manage those;
m_visualPlayPosition(nullptr),
m_totalVSamples(0),
m_pRateRatioCO(nullptr),
m_pGainControlObject(nullptr),
m_gain(1.0),
m_pTrackSamplesControlObject(nullptr),
m_trackSamples(0),
m_trackSamples(0.0),
m_scaleFactor(1.0),
m_playMarkerPosition(s_defaultPlayMarkerPosition),
m_pContext(nullptr),
m_passthroughEnabled(false) {
//qDebug() << "WaveformWidgetRenderer";
for (int type = ::WaveformRendererAbstract::Play;
Expand Down Expand Up @@ -79,10 +77,6 @@ WaveformWidgetRenderer::~WaveformWidgetRenderer() {
delete m_rendererStack[i];
}

delete m_pRateRatioCO;
delete m_pGainControlObject;
delete m_pTrackSamplesControlObject;

#ifdef WAVEFORMWIDGETRENDERER_DEBUG
delete m_timer;
#endif
Expand All @@ -93,12 +87,12 @@ bool WaveformWidgetRenderer::init() {

m_visualPlayPosition = VisualPlayPosition::getVisualPlayPosition(m_group);

m_pRateRatioCO = new ControlProxy(
m_group, "rate_ratio");
m_pGainControlObject = new ControlProxy(
m_group, "total_gain");
m_pTrackSamplesControlObject = new ControlProxy(
m_group, "track_samples");
m_pRateRatioCO = std::make_unique<ControlProxy>(
m_group, QStringLiteral("rate_ratio"));
m_pGainControlObject = std::make_unique<ControlProxy>(
m_group, QStringLiteral("total_gain"));
m_pTrackSamplesControlObject = std::make_unique<ControlProxy>(
m_group, QStringLiteral("track_samples"));

for (int i = 0; i < m_rendererStack.size(); ++i) {
if (!m_rendererStack[i]->init()) {
Expand Down Expand Up @@ -428,7 +422,7 @@ void WaveformWidgetRenderer::selectStem(mixxx::StemChannelSelection stemMask) {
void WaveformWidgetRenderer::setTrack(TrackPointer track) {
m_pTrack = track;
//used to postpone first display until track sample is actually available
m_trackSamples = -1;
m_trackSamples = -1.0;

for (int i = 0; i < m_rendererStack.size(); ++i) {
m_rendererStack[i]->onSetTrack();
Expand Down
21 changes: 18 additions & 3 deletions src/waveform/renderers/waveformwidgetrenderer.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ class VSyncThread;
class QPainter;
class WaveformRendererAbstract;

namespace rendergraph {
class Context;
}

class WaveformWidgetRenderer {
public:
static const double s_waveformMinZoom;
Expand Down Expand Up @@ -201,6 +205,14 @@ class WaveformWidgetRenderer {
return m_trackSamples <= 0.0 || m_pos[::WaveformRendererAbstract::Play] == -1;
}

void setContext(rendergraph::Context* pContext) {
m_pContext = pContext;
}

rendergraph::Context* getContext() const {
return m_pContext;
}

protected:
const QString m_group;
TrackPointer m_pTrack;
Expand Down Expand Up @@ -231,14 +243,17 @@ class WaveformWidgetRenderer {
QSharedPointer<VisualPlayPosition> m_visualPlayPosition;
int m_posVSample[2];
int m_totalVSamples;
ControlProxy* m_pRateRatioCO;
ControlProxy* m_pGainControlObject;
std::unique_ptr<ControlProxy> m_pRateRatioCO;
std::unique_ptr<ControlProxy> m_pGainControlObject;
std::unique_ptr<ControlProxy> m_pTrackSamplesControlObject;
double m_gain;
ControlProxy* m_pTrackSamplesControlObject;
double m_trackSamples;
double m_scaleFactor;
double m_playMarkerPosition; // 0.0 - left, 0.5 - center, 1.0 - right

// used by allshader waveformrenderers when used with rendergraph nodes
rendergraph::Context* m_pContext;

#ifdef WAVEFORMWIDGETRENDERER_DEBUG
PerformanceTimer* m_timer;
int m_lastFrameTime;
Expand Down
Loading