From 017c7fdef6fc945ac95a527af9cbae9cc963a8b7 Mon Sep 17 00:00:00 2001 From: Owen Williams Date: Fri, 19 Jul 2024 13:02:22 -0400 Subject: [PATCH] fix high details waveforms wrapping around after visual index 65K Fixes https://github.com/mixxxdj/mixxx/issues/13472 --- res/shaders/filteredsignal.frag | 5 ----- res/shaders/rgbsignal.frag | 15 ++------------- res/shaders/stackedsignal.frag | 5 ----- .../allshader/waveformrenderertextured.cpp | 17 ++++++++++++----- .../allshader/waveformrenderertextured.h | 10 ++++++++++ src/waveform/waveform.h | 14 ++++++++------ 6 files changed, 32 insertions(+), 34 deletions(-) diff --git a/res/shaders/filteredsignal.frag b/res/shaders/filteredsignal.frag index 7a6747b428f..ce0f0631df7 100644 --- a/res/shaders/filteredsignal.frag +++ b/res/shaders/filteredsignal.frag @@ -21,11 +21,6 @@ uniform sampler2D waveformDataTexture; vec4 getWaveformData(float index) { vec2 uv_data; - // The Waveform data is composed of 8 bytes per sample, (low, mid, high, all, - // stem1, stem2, stem3, stem4), see WaveformData struct. Currently, shaders - // don't support stem rendering. - index = 2 * index; - uv_data.y = floor(index / float(textureStride)); uv_data.x = floor(index - uv_data.y * float(textureStride)); // Divide again to convert to normalized UV coordinates. diff --git a/res/shaders/rgbsignal.frag b/res/shaders/rgbsignal.frag index 718918bd6f2..f60dd9e3774 100644 --- a/res/shaders/rgbsignal.frag +++ b/res/shaders/rgbsignal.frag @@ -22,19 +22,8 @@ uniform sampler2D waveformDataTexture; vec4 getWaveformData(float index) { vec2 uv_data; - // The Waveform data is composed of 8 bytes per sample, (low, mid, high, - // all, stem1, stem2, stem3, stem4), see WaveformData struct. Currently, - // shaders don't support stem rendering. - index = 2 * index; - - uv_data.y = splitStereoSignal - ? floor(index / float(textureStride)) - : max(floor(index / float(textureStride)), - floor((index + 2) / float(textureStride))); - uv_data.x = splitStereoSignal - ? floor(index - uv_data.y * float(textureStride)) - : max(floor(index - uv_data.y * float(textureStride)), - floor((index + 2) - uv_data.y * float(textureStride))); + uv_data.y = splitStereoSignal ? floor(index / float(textureStride)) : max(floor(index / float(textureStride)), floor((index + 1) / float(textureStride))); + uv_data.x = splitStereoSignal ? floor(index - uv_data.y * float(textureStride)) : max(floor(index - uv_data.y * float(textureStride)), floor((index + 1) - uv_data.y * float(textureStride))); // Divide again to convert to normalized UV coordinates. return texture2D(waveformDataTexture, uv_data / float(textureStride)); } diff --git a/res/shaders/stackedsignal.frag b/res/shaders/stackedsignal.frag index 1e5bf79d05f..d5207ac6ef2 100644 --- a/res/shaders/stackedsignal.frag +++ b/res/shaders/stackedsignal.frag @@ -24,11 +24,6 @@ uniform sampler2D waveformDataTexture; vec4 getWaveformData(float index) { vec2 uv_data; - // The Waveform data is composed of 8 bytes per sample, (low, mid, high, all, - // stem1, stem2, stem3, stem4), see WaveformData struct. Currently, shaders - // don't support stem rendering. - index = 2 * index; - uv_data.y = floor(index / float(textureStride)); uv_data.x = floor(index - uv_data.y * float(textureStride)); // Divide again to convert to normalized UV coordinates. diff --git a/src/waveform/renderers/allshader/waveformrenderertextured.cpp b/src/waveform/renderers/allshader/waveformrenderertextured.cpp index 7b47f466cc8..9dfcb1d6b73 100644 --- a/src/waveform/renderers/allshader/waveformrenderertextured.cpp +++ b/src/waveform/renderers/allshader/waveformrenderertextured.cpp @@ -8,7 +8,6 @@ #include "moc_waveformrenderertextured.cpp" #include "track/track.h" #include "waveform/renderers/waveformwidgetrenderer.h" -#include "waveform/waveform.h" namespace allshader { @@ -130,6 +129,15 @@ bool WaveformRendererTextured::loadTexture() { glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); if (pWaveform != nullptr && data != nullptr) { + // Make a copy of the waveform data, stripping the stems portion. Note that the datasize is + // different from the texture size -- we want the full texture size so the upload works. See + // m_data in waveform/waveform.h. + if (m_data.size() == 0 || static_cast(m_data.size()) != pWaveform->getTextureSize()) { + m_data.resize(pWaveform->getTextureSize()); + } + for (int i = 0; i < pWaveform->getDataSize(); i++) { + m_data[i] = data[i].filtered; + } // Waveform ensures that getTextureSize is a multiple of // getTextureStride so there is no rounding here. int textureWidth = pWaveform->getTextureStride(); @@ -143,7 +151,7 @@ bool WaveformRendererTextured::loadTexture() { 0, GL_RGBA, GL_UNSIGNED_BYTE, - data); + m_data.data()); int error = glGetError(); if (error) { qDebug() << "WaveformRendererTextured::loadTexture - glTexImage2D error" << error; @@ -296,8 +304,7 @@ void WaveformRendererTextured::paintGL() { return; } - const WaveformData* data = pWaveform->data(); - if (data == nullptr) { + if (pWaveform->data() == nullptr) { return; } @@ -307,7 +314,7 @@ void WaveformRendererTextured::paintGL() { } // NOTE(vRince): completion can change during loadTexture - // do not remove currenCompletion temp variable ! + // do not remove currentCompletion temp variable ! const int currentCompletion = pWaveform->getCompletion(); if (m_textureRenderedWaveformCompletion < currentCompletion) { loadTexture(); diff --git a/src/waveform/renderers/allshader/waveformrenderertextured.h b/src/waveform/renderers/allshader/waveformrenderertextured.h index 0e9f5531a84..16680f1bc5d 100644 --- a/src/waveform/renderers/allshader/waveformrenderertextured.h +++ b/src/waveform/renderers/allshader/waveformrenderertextured.h @@ -8,6 +8,7 @@ #include "waveform/renderers/allshader/rgbdata.h" #include "waveform/renderers/allshader/vertexdata.h" #include "waveform/renderers/allshader/waveformrenderersignalbase.h" +#include "waveform/waveform.h" #include "waveform/widgets/waveformwidgettype.h" class QOpenGLFramebufferObject; @@ -43,6 +44,13 @@ class allshader::WaveformRendererTextured : public QObject, void slotWaveformUpdated(); private: + struct WaveformTexture { + unsigned char low; + unsigned char mid; + unsigned char high; + unsigned char all; + }; + static QString fragShaderForType(WaveformWidgetType::Type t); bool loadShaders(); bool loadTexture(); @@ -56,6 +64,8 @@ class allshader::WaveformRendererTextured : public QObject, TrackPointer m_loadedTrack; int m_textureRenderedWaveformCompletion; + std::vector m_data; + // Frame buffer for two pass rendering. std::unique_ptr m_framebuffer; diff --git a/src/waveform/waveform.h b/src/waveform/waveform.h index 027c53904b7..6b27d8e8ee2 100644 --- a/src/waveform/waveform.h +++ b/src/waveform/waveform.h @@ -15,13 +15,15 @@ enum FilterIndex { Low = 0, Mid = 1, High = 2, FilterCount = 3}; enum ChannelIndex { Left = 0, Right = 1, ChannelCount = 2}; +struct WaveformFilteredData { + unsigned char low; + unsigned char mid; + unsigned char high; + unsigned char all; +}; + struct WaveformData { - struct { - unsigned char low; - unsigned char mid; - unsigned char high; - unsigned char all; - } filtered; + WaveformFilteredData filtered; unsigned char stems[mixxx::kMaxSupportedStem]; };