Skip to content

Commit

Permalink
Improve performance with vertex buffer updates
Browse files Browse the repository at this point in the history
In wave/shape drawing code, we now preallocate the vertex buffer once for the maximum number of sides and only update the existing buffer instead of reallocating it over and over again. Trades a few KB of additional RAM for a good amount of drawing performance.

In the motion vector grid code, we only reallocate the buffer if we draw more vertices than in the previous draw call.

Also changed the drawing hint to GL_STREAM_DRAW, which is slightly better suited for this kind of usage (update once, draw once, repeat).

These changes should hopefully improve performance, especially when large numbers of custom shapes are drawn.
  • Loading branch information
kblaschke committed Feb 12, 2024
1 parent f22cc42 commit fcafa56
Show file tree
Hide file tree
Showing 5 changed files with 35 additions and 6 deletions.
17 changes: 14 additions & 3 deletions src/libprojectM/MilkdropPreset/CustomShape.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ CustomShape::CustomShape(PresetState& presetState)
: m_presetState(presetState)
, m_perFrameContext(presetState.globalMemory, &presetState.globalRegisters)
{
std::vector<TexturedPoint> vertexData;
vertexData.resize(102);

glGenVertexArrays(1, &m_vaoIdTextured);
glGenBuffers(1, &m_vboIdTextured);

Expand All @@ -30,6 +33,8 @@ CustomShape::CustomShape(PresetState& presetState)
glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, sizeof(TexturedPoint), reinterpret_cast<void*>(offsetof(TexturedPoint, r))); // Color
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(TexturedPoint), reinterpret_cast<void*>(offsetof(TexturedPoint, u))); // Texture coordinate

glBufferData(GL_ARRAY_BUFFER, sizeof(TexturedPoint) * vertexData.size(), vertexData.data(), GL_STREAM_DRAW);

glBindVertexArray(m_vaoIdUntextured);
glBindBuffer(GL_ARRAY_BUFFER, m_vboIdUntextured);

Expand All @@ -39,6 +44,8 @@ CustomShape::CustomShape(PresetState& presetState)
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(TexturedPoint), reinterpret_cast<void*>(offsetof(TexturedPoint, x))); // Position
glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, sizeof(TexturedPoint), reinterpret_cast<void*>(offsetof(TexturedPoint, r))); // Color

glBufferData(GL_ARRAY_BUFFER, sizeof(TexturedPoint) * vertexData.size(), vertexData.data(), GL_STREAM_DRAW);

RenderItem::Init();

m_perFrameContext.RegisterBuiltinVariables();
Expand All @@ -58,6 +65,10 @@ void CustomShape::InitVertexAttrib()
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, nullptr); // points
glDisableVertexAttribArray(1);

std::vector<Point> vertexData;
vertexData.resize(100);
glBufferData(GL_ARRAY_BUFFER, sizeof(Point) * vertexData.size(), vertexData.data(), GL_STREAM_DRAW);
}

void CustomShape::Initialize(PresetFileParser& parsedFile, int index)
Expand Down Expand Up @@ -217,7 +228,7 @@ void CustomShape::Draw()

glBindBuffer(GL_ARRAY_BUFFER, m_vboIdTextured);

glBufferData(GL_ARRAY_BUFFER, sizeof(TexturedPoint) * (sides + 2), vertexData.data(), GL_DYNAMIC_DRAW);
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(TexturedPoint) * (sides + 2), vertexData.data());

glBindVertexArray(m_vaoIdTextured);
glDrawArrays(GL_TRIANGLE_FAN, 0, sides + 2);
Expand All @@ -231,7 +242,7 @@ void CustomShape::Draw()
// Untextured (creates a color gradient: center=r/g/b/a to border=r2/b2/g2/a2)
glBindBuffer(GL_ARRAY_BUFFER, m_vboIdUntextured);

glBufferData(GL_ARRAY_BUFFER, sizeof(TexturedPoint) * (sides + 2), vertexData.data(), GL_DYNAMIC_DRAW);
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(TexturedPoint) * (sides + 2), vertexData.data());

m_presetState.untexturedShader.Bind();
m_presetState.untexturedShader.SetUniformMat4x4("vertex_transformation", PresetState::orthogonalProjection);
Expand Down Expand Up @@ -304,7 +315,7 @@ void CustomShape::Draw()
break;
}

glBufferData(GL_ARRAY_BUFFER, static_cast<GLsizei>(sizeof(Point) * sides), points.data(), GL_DYNAMIC_DRAW);
glBufferSubData(GL_ARRAY_BUFFER, 0, static_cast<GLsizei>(sizeof(Point) * sides), points.data());
glDrawArrays(GL_LINE_LOOP, 0, sides);
}
}
Expand Down
6 changes: 5 additions & 1 deletion src/libprojectM/MilkdropPreset/CustomWaveform.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ void CustomWaveform::InitVertexAttrib()

glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(ColoredPoint), nullptr); // points
glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, sizeof(ColoredPoint), reinterpret_cast<void*>(sizeof(float) * 2)); // colors

std::vector<ColoredPoint> vertexData;
vertexData.resize(std::max(libprojectM::Audio::SpectrumSamples, libprojectM::Audio::WaveformSamples) * 2 + 2);
glBufferData(GL_ARRAY_BUFFER, sizeof(ColoredPoint) * vertexData.size(), vertexData.data(), GL_STREAM_DRAW);
}

void CustomWaveform::Initialize(PresetFileParser& parsedFile, int index)
Expand Down Expand Up @@ -224,7 +228,7 @@ void CustomWaveform::Draw(const PerFrameContext& presetPerFrameContext)
break;
}

glBufferData(GL_ARRAY_BUFFER, sizeof(ColoredPoint) * smoothedVertexCount, pointsSmoothed.data(), GL_DYNAMIC_DRAW);
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(ColoredPoint) * smoothedVertexCount, pointsSmoothed.data());
glDrawArrays(drawType, 0, smoothedVertexCount);
}

Expand Down
10 changes: 9 additions & 1 deletion src/libprojectM/MilkdropPreset/MotionVectors.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,15 @@ void MotionVectors::Draw(const PerFrameContext& presetPerFrameContext, std::shar
}

// Draw a row of lines.
glBufferData(GL_ARRAY_BUFFER, sizeof(MotionVectorVertex) * vertex, lineVertices.data(), GL_DYNAMIC_DRAW);
if (m_lastVertexCount >= vertex)
{
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(MotionVectorVertex) * vertex, lineVertices.data());
}
else
{
glBufferData(GL_ARRAY_BUFFER, sizeof(MotionVectorVertex) * vertex, lineVertices.data(), GL_STREAM_DRAW);
m_lastVertexCount = vertex;
}
glDrawArrays(GL_LINES, 0, static_cast<GLsizei>(vertex));
}
}
Expand Down
2 changes: 2 additions & 0 deletions src/libprojectM/MilkdropPreset/MotionVectors.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ class MotionVectors : public Renderer::RenderItem

Renderer::Shader m_motionVectorShader; //!< The motion vector shader, calculates the trace positions in the GPU.
std::shared_ptr<Renderer::Sampler> m_sampler{std::make_shared<Renderer::Sampler>(GL_CLAMP_TO_EDGE, GL_LINEAR)}; //!< The texture sampler.

int m_lastVertexCount{}; //!< Number of vertices drawn in the previous draw call.
};

} // namespace MilkdropPreset
Expand Down
6 changes: 5 additions & 1 deletion src/libprojectM/MilkdropPreset/Waveform.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ void Waveform::InitVertexAttrib()
glDisableVertexAttribArray(1);

glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, nullptr);

std::vector<Point> vertexData;
vertexData.resize(std::max(libprojectM::Audio::SpectrumSamples, libprojectM::Audio::WaveformSamples) * 2 + 2);
glBufferData(GL_ARRAY_BUFFER, sizeof(Point) * vertexData.size(), vertexData.data(), GL_STREAM_DRAW);
}

void Waveform::Draw(const PerFrameContext& presetPerFrameContext)
Expand Down Expand Up @@ -118,7 +122,7 @@ void Waveform::Draw(const PerFrameContext& presetPerFrameContext)
break;
}

glBufferData(GL_ARRAY_BUFFER, sizeof(Point) * smoothedWave.size(), smoothedWave.data(), GL_DYNAMIC_DRAW);
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(Point) * smoothedWave.size(), smoothedWave.data());
glDrawArrays(drawType, 0, static_cast<GLsizei>(smoothedWave.size()));
}
}
Expand Down

0 comments on commit fcafa56

Please sign in to comment.