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

stem waveformrenderer using rendergraph #14192

Merged
merged 2 commits into from
Feb 3, 2025
Merged
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
115 changes: 56 additions & 59 deletions src/waveform/renderers/allshader/waveformrendererstem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,77 +6,94 @@

#include "engine/channels/enginedeck.h"
#include "engine/engine.h"
#include "rendergraph/material/rgbamaterial.h"
#include "rendergraph/vertexupdaters/rgbavertexupdater.h"
#include "track/track.h"
#include "util/assert.h"
#include "util/math.h"
#include "waveform/renderers/allshader/matrixforwidgetgeometry.h"
#include "waveform/renderers/allshader/rgbdata.h"
#include "waveform/renderers/waveformwidgetrenderer.h"
#include "waveform/waveform.h"

using namespace rendergraph;

namespace allshader {

WaveformRendererStem::WaveformRendererStem(
WaveformWidgetRenderer* waveformWidget,
::WaveformRendererAbstract::PositionSource type)
: WaveformRendererSignalBase(waveformWidget),
m_isSlipRenderer(type == ::WaveformRendererAbstract::Slip) {
initForRectangles<RGBAMaterial>(0);
setUsePreprocess(true);
}

void WaveformRendererStem::onSetup(const QDomNode&) {
}

void WaveformRendererStem::initializeGL() {
m_shader.init();
m_textureShader.init();
bool WaveformRendererStem::init() {
auto group = m_pEQEnabled->getKey().group;
for (int stemIdx = 0; stemIdx < mixxx::kMaxSupportedStems; stemIdx++) {
QString stemGroup = EngineDeck::getGroupForStem(group, stemIdx);
m_pStemGain.emplace_back(
std::make_unique<ControlProxy>(stemGroup,
std::make_unique<PollingControlProxy>(stemGroup,
QStringLiteral("volume")));
m_pStemMute.emplace_back(
std::make_unique<ControlProxy>(stemGroup,
std::make_unique<PollingControlProxy>(stemGroup,
QStringLiteral("mute")));
}
return true;
}

void WaveformRendererStem::paintGL() {
void WaveformRendererStem::preprocess() {
if (!preprocessInner()) {
if (geometry().vertexCount() != 0) {
geometry().allocate(0);
markDirtyGeometry();
}
}
}

bool WaveformRendererStem::preprocessInner() {
TrackPointer pTrack = m_waveformRenderer->getTrackInfo();

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

auto stemInfo = pTrack->getStemInfo();
// If this track isn't a stem track, skip the rendering
if (stemInfo.isEmpty()) {
return;
return false;
}
auto positionType = m_isSlipRenderer ? ::WaveformRendererAbstract::Slip
: ::WaveformRendererAbstract::Play;

ConstWaveformPointer waveform = pTrack->getWaveform();
if (waveform.isNull()) {
return;
return false;
}

const int dataSize = waveform->getDataSize();
if (dataSize <= 1) {
return;
return false;
}

const WaveformData* data = waveform->data();
if (data == nullptr) {
return;
return false;
}
// If this waveform doesn't contain stem data, skip the rendering
if (!waveform->hasStem()) {
return;
return false;
}

uint selectedStems = m_waveformRenderer->getSelectedStems();

const float devicePixelRatio = m_waveformRenderer->getDevicePixelRatio();
const int length = static_cast<int>(m_waveformRenderer->getLength() * devicePixelRatio);
const int length = static_cast<int>(m_waveformRenderer->getLength());
const int pixelLength = static_cast<int>(m_waveformRenderer->getLength() * devicePixelRatio);
const float invDevicePixelRatio = 1.f / devicePixelRatio;
const float halfPixelSize = 0.5f / devicePixelRatio;

// See waveformrenderersimple.cpp for a detailed explanation of the frame and index calculation
const int visualFramesSize = dataSize / 2;
Expand All @@ -87,14 +104,14 @@ void WaveformRendererStem::paintGL() {

// Represents the # of visual frames per horizontal pixel.
const double visualIncrementPerPixel =
(lastVisualFrame - firstVisualFrame) / static_cast<double>(length);
(lastVisualFrame - firstVisualFrame) / static_cast<double>(pixelLength);

// Per-band gain from the EQ knobs.
float allGain(1.0);
// applyCompensation = true, as we scale to match filtered.all
getGains(&allGain, false, nullptr, nullptr, nullptr);

const float breadth = static_cast<float>(m_waveformRenderer->getBreadth()) * devicePixelRatio;
const float breadth = static_cast<float>(m_waveformRenderer->getBreadth());
const float halfBreadth = breadth / 2.0f;

const float heightFactor = allGain * halfBreadth / m_maxValue;
Expand All @@ -105,22 +122,22 @@ void WaveformRendererStem::paintGL() {

const int numVerticesPerLine = 6; // 2 triangles

const int reserved = numVerticesPerLine * (8 * length + 1);
const int reserved = numVerticesPerLine * (8 * pixelLength + 1);

m_vertices.clear();
m_vertices.reserve(reserved);
m_colors.clear();
m_colors.reserve(reserved);
geometry().setDrawingMode(Geometry::DrawingMode::Triangles);
geometry().allocate(reserved);
markDirtyGeometry();

m_vertices.addRectangle(0.f,
halfBreadth - 0.5f * devicePixelRatio,
static_cast<float>(length),
m_isSlipRenderer ? halfBreadth : halfBreadth + 0.5f * devicePixelRatio);
m_colors.addForRectangle(0.f, 0.f, 0.f, 0.f);
RGBAVertexUpdater vertexUpdater{geometry().vertexDataAs<Geometry::RGBAColoredPoint2D>()};
vertexUpdater.addRectangle({0.f,
halfBreadth - 0.5f},
{static_cast<float>(length),
m_isSlipRenderer ? halfBreadth : halfBreadth + 0.5f},
{0.f, 0.f, 0.f, 0.f});

const double maxSamplingRange = visualIncrementPerPixel / 2.0;

for (int visualIdx = 0; visualIdx < length; ++visualIdx) {
for (int visualIdx = 0; visualIdx < pixelLength; ++visualIdx) {
for (int stemIdx = 0; stemIdx < mixxx::kMaxSupportedStems; stemIdx++) {
// Stem is drawn twice with different opacity level, this allow to
// see the maximum signal by transparency
Expand All @@ -137,7 +154,7 @@ void WaveformRendererStem::paintGL() {
const int visualIndexStop =
std::min(std::max(visualFrameStop, visualFrameStart + 1) * 2, dataSize - 1);

const float fVisualIdx = static_cast<float>(visualIdx);
const float fVisualIdx = static_cast<float>(visualIdx) * invDevicePixelRatio;

// Find the max values for current eq in the waveform data.
// - Max of left and right
Expand All @@ -164,43 +181,23 @@ void WaveformRendererStem::paintGL() {
}

// Lines are thin rectangles
// shawdow
m_vertices.addRectangle(fVisualIdx - 0.5f,
halfBreadth - heightFactor * max,
fVisualIdx + 0.5f,
m_isSlipRenderer ? halfBreadth : halfBreadth + heightFactor * max);

m_colors.addForRectangle(color_r, color_g, color_b, color_a);
// shadow
vertexUpdater.addRectangle({fVisualIdx - halfPixelSize,
halfBreadth - heightFactor * max},
{fVisualIdx + halfPixelSize,
m_isSlipRenderer ? halfBreadth : halfBreadth + heightFactor * max},
{color_r, color_g, color_b, color_a});
}
}

xVisualFrame += visualIncrementPerPixel;
}

DEBUG_ASSERT(reserved == m_vertices.size());
DEBUG_ASSERT(reserved == m_colors.size());

const QMatrix4x4 matrix = matrixForWidgetGeometry(m_waveformRenderer, true);

const int matrixLocation = m_shader.matrixLocation();
const int positionLocation = m_shader.positionLocation();
const int colorLocation = m_shader.colorLocation();

m_shader.bind();
m_shader.enableAttributeArray(positionLocation);
m_shader.enableAttributeArray(colorLocation);

m_shader.setUniformValue(matrixLocation, matrix);

m_shader.setAttributeArray(
positionLocation, GL_FLOAT, m_vertices.constData(), 2);
m_shader.setAttributeArray(
colorLocation, GL_FLOAT, m_colors.constData(), 4);
DEBUG_ASSERT(reserved == vertexUpdater.index());

glDrawArrays(GL_TRIANGLES, 0, m_vertices.size());
markDirtyMaterial();

m_shader.disableAttributeArray(positionLocation);
m_shader.disableAttributeArray(colorLocation);
m_shader.release();
return true;
}

} // namespace allshader
32 changes: 15 additions & 17 deletions src/waveform/renderers/allshader/waveformrendererstem.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,9 @@

#include <vector>

#include "rendergraph/openglnode.h"
#include "shaders/rgbashader.h"
#include "shaders/textureshader.h"
#include "control/pollingcontrolproxy.h"
#include "rendergraph/geometrynode.h"
#include "util/class.h"
#include "waveform/renderers/allshader/rgbadata.h"
#include "waveform/renderers/allshader/vertexdata.h"
#include "waveform/renderers/allshader/waveformrenderersignalbase.h"

class QOpenGLTexture;
Expand All @@ -18,30 +15,31 @@ class WaveformRendererStem;

class allshader::WaveformRendererStem final
: public allshader::WaveformRendererSignalBase,
public rendergraph::OpenGLNode {
public rendergraph::GeometryNode {
public:
explicit WaveformRendererStem(WaveformWidgetRenderer* waveformWidget,
::WaveformRendererAbstract::PositionSource type =
::WaveformRendererAbstract::Play);

// override ::WaveformRendererSignalBase
// Pure virtual from WaveformRendererSignalBase, not used
void onSetup(const QDomNode& node) override;

void initializeGL() override;
void paintGL() override;
bool init() override;

private:
mixxx::RGBAShader m_shader;
mixxx::TextureShader m_textureShader;
VertexData m_vertices;
RGBAData m_colors;
bool supportsSlip() const override {
return true;
acolombier marked this conversation as resolved.
Show resolved Hide resolved
}

// Virtuals for rendergraph::Node
void preprocess() override;

private:
bool m_isSlipRenderer;

std::vector<std::unique_ptr<ControlProxy>> m_pStemGain;
std::vector<std::unique_ptr<ControlProxy>> m_pStemMute;
std::vector<std::unique_ptr<PollingControlProxy>> m_pStemGain;
std::vector<std::unique_ptr<PollingControlProxy>> m_pStemMute;

void drawTexture(float x, float y, QOpenGLTexture* texture);
bool preprocessInner();

DISALLOW_COPY_AND_ASSIGN(WaveformRendererStem);
};