Skip to content

Commit a85ebc3

Browse files
committed
Use Mesh class in Warp effect
Now using the generated grid vertices and indices directly, drawing the warp mesh in a single draw call. This will increase the number of drawn vertices, but all GPUs made in the past decade can easily deal with 100K triangles or more.
1 parent 90e158d commit a85ebc3

File tree

3 files changed

+116
-140
lines changed

3 files changed

+116
-140
lines changed

src/libprojectM/MilkdropPreset/PerPixelMesh.cpp

Lines changed: 86 additions & 110 deletions
Original file line numberDiff line numberDiff line change
@@ -18,44 +18,31 @@
1818
namespace libprojectM {
1919
namespace MilkdropPreset {
2020

21-
static constexpr uint32_t VerticesPerDrawCall = 1024 * 3;
22-
2321
PerPixelMesh::PerPixelMesh()
24-
: RenderItem()
25-
{
26-
RenderItem::Init();
27-
}
28-
29-
void PerPixelMesh::InitVertexAttrib()
22+
: m_warpMesh(Renderer::VertexBufferUsage::StreamDraw)
3023
{
31-
m_drawVertices.resize(VerticesPerDrawCall); // Fixed size, may scale it later depending on GPU caps.
32-
33-
glGenVertexArrays(1, &m_vaoID);
34-
glGenBuffers(1, &m_vboID);
35-
36-
glBindVertexArray(m_vaoID);
37-
glBindBuffer(GL_ARRAY_BUFFER, m_vboID);
38-
39-
glEnableVertexAttribArray(0);
40-
glEnableVertexAttribArray(1);
41-
glEnableVertexAttribArray(2);
42-
glEnableVertexAttribArray(3);
43-
glEnableVertexAttribArray(4);
44-
glEnableVertexAttribArray(5);
45-
46-
// Only position & texture coordinates are per-vertex, colors are equal all over the grid (used for decay).
47-
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(MeshVertex), reinterpret_cast<void*>(offsetof(MeshVertex, x))); // Position, radius & angle
48-
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(MeshVertex), reinterpret_cast<void*>(offsetof(MeshVertex, radius))); // Position, radius & angle
49-
glVertexAttribPointer(2, 4, GL_FLOAT, GL_FALSE, sizeof(MeshVertex), reinterpret_cast<void*>(offsetof(MeshVertex, zoom))); // zoom, zoom exponent, rotation & warp
50-
glVertexAttribPointer(3, 2, GL_FLOAT, GL_FALSE, sizeof(MeshVertex), reinterpret_cast<void*>(offsetof(MeshVertex, centerX))); // Center coord
51-
glVertexAttribPointer(4, 2, GL_FLOAT, GL_FALSE, sizeof(MeshVertex), reinterpret_cast<void*>(offsetof(MeshVertex, distanceX))); // Distance
52-
glVertexAttribPointer(5, 2, GL_FLOAT, GL_FALSE, sizeof(MeshVertex), reinterpret_cast<void*>(offsetof(MeshVertex, stretchX))); // Stretch
53-
54-
// Pre-allocate vertex buffer
55-
glBufferData(GL_ARRAY_BUFFER, sizeof(MeshVertex) * m_drawVertices.size(), m_drawVertices.data(), GL_STREAM_DRAW);
56-
57-
glBindVertexArray(0);
58-
glBindBuffer(GL_ARRAY_BUFFER, 0);
24+
m_warpMesh.SetRenderPrimitiveType(Renderer::Mesh::PrimitiveType::Triangles);
25+
26+
m_warpMesh.Bind();
27+
m_radiusAngleBuffer.Bind();
28+
m_zoomRotWarpBuffer.Bind();
29+
m_centerBuffer.Bind();
30+
m_distanceBuffer.Bind();
31+
m_stretchBuffer.Bind();
32+
33+
m_radiusAngleBuffer.InitializeAttributePointer(3);
34+
m_zoomRotWarpBuffer.InitializeAttributePointer(4);
35+
m_centerBuffer.InitializeAttributePointer(5);
36+
m_distanceBuffer.InitializeAttributePointer(6);
37+
m_stretchBuffer.InitializeAttributePointer(7);
38+
39+
Renderer::VertexBuffer<Renderer::Point>::SetEnableAttributeArray(3, true);
40+
Renderer::VertexBuffer<Renderer::Point>::SetEnableAttributeArray(4, true);
41+
Renderer::VertexBuffer<Renderer::Point>::SetEnableAttributeArray(5, true);
42+
Renderer::VertexBuffer<Renderer::Point>::SetEnableAttributeArray(6, true);
43+
Renderer::VertexBuffer<Renderer::Point>::SetEnableAttributeArray(7, true);
44+
45+
Renderer::Mesh::Unbind();
5946
}
6047

6148
void PerPixelMesh::LoadWarpShader(const PresetState& presetState)
@@ -139,9 +126,17 @@ void PerPixelMesh::InitializeMesh(const PresetState& presetState)
139126
m_gridSizeX = presetState.renderContext.perPixelMeshX;
140127
m_gridSizeY = presetState.renderContext.perPixelMeshY;
141128

142-
// Grid size has changed, reallocate vertex buffers
143-
m_vertices.resize((m_gridSizeX + 1) * (m_gridSizeY + 1));
144-
m_listIndices.resize(m_gridSizeX * m_gridSizeY * 6);
129+
// Grid size has changed, resize buffers accordingly
130+
const size_t vertexCount = (m_gridSizeX + 1) * (m_gridSizeY + 1);
131+
132+
m_warpMesh.SetVertexCount(vertexCount);
133+
m_radiusAngleBuffer.Resize(vertexCount);
134+
m_zoomRotWarpBuffer.Resize(vertexCount);
135+
m_centerBuffer.Resize(vertexCount);
136+
m_distanceBuffer.Resize(vertexCount);
137+
m_stretchBuffer.Resize(vertexCount);
138+
139+
m_warpMesh.Indices().Resize(m_gridSizeX * m_gridSizeY * 6);
145140
}
146141
else if (m_viewportWidth == presetState.renderContext.viewportSizeX &&
147142
m_viewportHeight == presetState.renderContext.viewportSizeY)
@@ -150,29 +145,29 @@ void PerPixelMesh::InitializeMesh(const PresetState& presetState)
150145
return;
151146
}
152147

153-
float aspectX = static_cast<float>(presetState.renderContext.aspectX);
154-
float aspectY = static_cast<float>(presetState.renderContext.aspectY);
148+
const float aspectX = presetState.renderContext.aspectX;
149+
const float aspectY = presetState.renderContext.aspectY;
155150

156151
// Either viewport size or mesh size changed, reinitialize the vertices.
152+
auto& vertices = m_warpMesh.Vertices();
157153
int vertexIndex{0};
158154
for (int gridY = 0; gridY <= m_gridSizeY; gridY++)
159155
{
160156
for (int gridX = 0; gridX <= m_gridSizeX; gridX++)
161157
{
162-
auto& vertex = m_vertices.at(vertexIndex);
163-
164-
vertex.x = static_cast<float>(gridX) / static_cast<float>(m_gridSizeX) * 2.0f - 1.0f;
165-
vertex.y = static_cast<float>(gridY) / static_cast<float>(m_gridSizeY) * 2.0f - 1.0f;
158+
const float x = static_cast<float>(gridX) / static_cast<float>(m_gridSizeX) * 2.0f - 1.0f;
159+
const float y = static_cast<float>(gridY) / static_cast<float>(m_gridSizeY) * 2.0f - 1.0f;
160+
vertices[vertexIndex] = {x, y};
166161

167162
// Milkdrop uses sqrtf, but hypotf is probably safer.
168-
vertex.radius = hypotf(vertex.x * aspectX, vertex.y * aspectY);
163+
m_radiusAngleBuffer[vertexIndex].radius = hypotf(x * aspectX, y * aspectY);
169164
if (gridY == m_gridSizeY / 2 && gridX == m_gridSizeX / 2)
170165
{
171-
vertex.angle = 0.0f;
166+
m_radiusAngleBuffer[vertexIndex].angle = 0.0f;
172167
}
173168
else
174169
{
175-
vertex.angle = atan2f(vertex.y * aspectY, vertex.x * aspectX);
170+
m_radiusAngleBuffer[vertexIndex].angle = atan2f(y * aspectY, x * aspectX);
176171
}
177172

178173
vertexIndex++;
@@ -204,12 +199,12 @@ void PerPixelMesh::InitializeMesh(const PresetState& presetState)
204199
// 0 - 1 3
205200
// / /
206201
// 2 4 - 5
207-
m_listIndices.at(vertexListIndex++) = vertex;
208-
m_listIndices.at(vertexListIndex++) = vertex + 1;
209-
m_listIndices.at(vertexListIndex++) = vertex + m_gridSizeX + 1;
210-
m_listIndices.at(vertexListIndex++) = vertex + 1;
211-
m_listIndices.at(vertexListIndex++) = vertex + m_gridSizeX + 1;
212-
m_listIndices.at(vertexListIndex++) = vertex + m_gridSizeX + 2;
202+
m_warpMesh.Indices()[vertexListIndex++] = vertex;
203+
m_warpMesh.Indices()[vertexListIndex++] = vertex + 1;
204+
m_warpMesh.Indices()[vertexListIndex++] = vertex + m_gridSizeX + 1;
205+
m_warpMesh.Indices()[vertexListIndex++] = vertex + 1;
206+
m_warpMesh.Indices()[vertexListIndex++] = vertex + m_gridSizeX + 1;
207+
m_warpMesh.Indices()[vertexListIndex++] = vertex + m_gridSizeX + 2;
213208
}
214209
}
215210
}
@@ -232,19 +227,25 @@ void PerPixelMesh::CalculateMesh(const PresetState& presetState, const PerFrameC
232227
int vertex = 0;
233228

234229
// Can't make this multithreaded as per-pixel code may use gmegabuf or regXX vars.
230+
auto& vertices = m_warpMesh.Vertices();
235231
for (int y = 0; y <= m_gridSizeY; y++)
236232
{
237233
for (int x = 0; x <= m_gridSizeX; x++)
238234
{
239-
auto& curVertex = m_vertices[vertex];
235+
auto& curVertex = vertices[vertex];
236+
auto& curRadiusAngle = m_radiusAngleBuffer[vertex];
237+
auto& curZoomRotWarp = m_zoomRotWarpBuffer[vertex];
238+
auto& curCenter = m_centerBuffer[vertex];
239+
auto& curDistance = m_distanceBuffer[vertex];
240+
auto& curStretch = m_stretchBuffer[vertex];
240241

241242
// Execute per-vertex/per-pixel code if the preset uses it.
242243
if (perPixelContext.perPixelCodeHandle)
243244
{
244-
*perPixelContext.x = static_cast<double>(curVertex.x * 0.5f * presetState.renderContext.aspectX + 0.5f);
245-
*perPixelContext.y = static_cast<double>(curVertex.y * -0.5f * presetState.renderContext.aspectY + 0.5f);
246-
*perPixelContext.rad = static_cast<double>(curVertex.radius);
247-
*perPixelContext.ang = static_cast<double>(curVertex.angle);
245+
*perPixelContext.x = static_cast<double>(curVertex.X() * 0.5f * presetState.renderContext.aspectX + 0.5f);
246+
*perPixelContext.y = static_cast<double>(curVertex.Y() * -0.5f * presetState.renderContext.aspectY + 0.5f);
247+
*perPixelContext.rad = static_cast<double>(curRadiusAngle.radius);
248+
*perPixelContext.ang = static_cast<double>(curRadiusAngle.angle);
248249
*perPixelContext.zoom = static_cast<double>(*perFrameContext.zoom);
249250
*perPixelContext.zoomexp = static_cast<double>(*perFrameContext.zoomexp);
250251
*perPixelContext.rot = static_cast<double>(*perFrameContext.rot);
@@ -258,34 +259,38 @@ void PerPixelMesh::CalculateMesh(const PresetState& presetState, const PerFrameC
258259

259260
perPixelContext.ExecutePerPixelCode();
260261

261-
curVertex.zoom = static_cast<float>(*perPixelContext.zoom);
262-
curVertex.zoomExp = static_cast<float>(*perPixelContext.zoomexp);
263-
curVertex.rot = static_cast<float>(*perPixelContext.rot);
264-
curVertex.warp = static_cast<float>(*perPixelContext.warp);
265-
curVertex.centerX = static_cast<float>(*perPixelContext.cx);
266-
curVertex.centerY = static_cast<float>(*perPixelContext.cy);
267-
curVertex.distanceX = static_cast<float>(*perPixelContext.dx);
268-
curVertex.distanceY = static_cast<float>(*perPixelContext.dy);
269-
curVertex.stretchX = static_cast<float>(*perPixelContext.sx);
270-
curVertex.stretchY = static_cast<float>(*perPixelContext.sy);
262+
curZoomRotWarp.zoom = static_cast<float>(*perPixelContext.zoom);
263+
curZoomRotWarp.zoomExp = static_cast<float>(*perPixelContext.zoomexp);
264+
curZoomRotWarp.rot = static_cast<float>(*perPixelContext.rot);
265+
curZoomRotWarp.warp = static_cast<float>(*perPixelContext.warp);
266+
curCenter = {static_cast<float>(*perPixelContext.cx),
267+
static_cast<float>(*perPixelContext.cy)};
268+
curDistance = {static_cast<float>(*perPixelContext.dx),
269+
static_cast<float>(*perPixelContext.dy)};
270+
curStretch = {static_cast<float>(*perPixelContext.sx),
271+
static_cast<float>(*perPixelContext.sy)};
271272
}
272273
else
273274
{
274-
curVertex.zoom = zoom;
275-
curVertex.zoomExp = zoomExp;
276-
curVertex.rot = rot;
277-
curVertex.warp = warp;
278-
curVertex.centerX = cx;
279-
curVertex.centerY = cy;
280-
curVertex.distanceX = dx;
281-
curVertex.distanceY = dy;
282-
curVertex.stretchX = sx;
283-
curVertex.stretchY = sy;
275+
curZoomRotWarp.zoom = zoom;
276+
curZoomRotWarp.zoomExp = zoomExp;
277+
curZoomRotWarp.rot = rot;
278+
curZoomRotWarp.warp = warp;
279+
curCenter = { cx, cy};
280+
curDistance = {dx, dy};
281+
curStretch = {sx, sy};
284282
}
285283

286284
vertex++;
287285
}
288286
}
287+
288+
m_warpMesh.Update();
289+
m_radiusAngleBuffer.Update();
290+
m_zoomRotWarpBuffer.Update();
291+
m_centerBuffer.Update();
292+
m_distanceBuffer.Update();
293+
m_stretchBuffer.Update();
289294
}
290295

291296
void PerPixelMesh::WarpedBlit(const PresetState& presetState,
@@ -362,38 +367,9 @@ void PerPixelMesh::WarpedBlit(const PresetState& presetState,
362367
}
363368
m_perPixelSampler.Bind(0);
364369

365-
glBindVertexArray(m_vaoID);
366-
glBindBuffer(GL_ARRAY_BUFFER, m_vboID);
367-
368-
int trianglesPerBatch = static_cast<int>(m_drawVertices.size() / 3 - 4);
369-
int triangleCount = m_gridSizeX * m_gridSizeY * 2; // Two triangles per quad/grid cell.
370-
int sourceIndex = 0;
371-
372-
while (sourceIndex < triangleCount * 3)
373-
{
374-
int trianglesQueued = 0;
375-
int vertex = 0;
376-
while (trianglesQueued < trianglesPerBatch && sourceIndex < triangleCount * 3)
377-
{
378-
// Copy one triangle/3 vertices
379-
for (int i = 0; i < 3; i++)
380-
{
381-
m_drawVertices[vertex++] = m_vertices[m_listIndices[sourceIndex++]];
382-
}
383-
384-
trianglesQueued++;
385-
}
386-
387-
if (trianglesQueued > 0)
388-
{
389-
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(MeshVertex) * trianglesQueued * 3, m_drawVertices.data());
390-
glDrawArrays(GL_TRIANGLES, 0, trianglesQueued * 3);
391-
}
392-
}
393-
394-
glBindVertexArray(0);
395-
glBindBuffer(GL_ARRAY_BUFFER, 0);
370+
m_warpMesh.Draw();
396371

372+
Renderer::Mesh::Unbind();
397373
Renderer::Sampler::Unbind(0);
398374
Renderer::Shader::Unbind();
399375
}

src/libprojectM/MilkdropPreset/PerPixelMesh.hpp

Lines changed: 25 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
11
#pragma once
22

3-
#include <Renderer/RenderItem.hpp>
4-
#include <Renderer/Shader.hpp>
3+
#include "Renderer/Mesh.hpp"
54

6-
#include <cstdint>
7-
#include <vector>
5+
#include <Renderer/Shader.hpp>
86

97
namespace libprojectM {
108
namespace MilkdropPreset {
@@ -27,13 +25,11 @@ class MilkdropShader;
2725
*
2826
* The mesh size can be changed between frames, the class will reallocate the buffers if needed.
2927
*/
30-
class PerPixelMesh : public Renderer::RenderItem
28+
class PerPixelMesh
3129
{
3230
public:
3331
PerPixelMesh();
3432

35-
void InitVertexAttrib() override;
36-
3733
/**
3834
* @brief Loads the warp shader, if the preset uses one.
3935
* @param presetState The preset state to retrieve the shader from.
@@ -59,31 +55,33 @@ class PerPixelMesh : public Renderer::RenderItem
5955

6056
private:
6157
/**
62-
* Warp mesh vertex with all required attributes.
58+
* Vertex attributes for radius and angle.
6359
*/
64-
struct MeshVertex {
65-
float x{};
66-
float y{};
60+
struct RadiusAngle {
6761
float radius{};
6862
float angle{};
6963

64+
static void InitializeAttributePointer(uint32_t attributeIndex)
65+
{
66+
glVertexAttribPointer(attributeIndex, sizeof(RadiusAngle) / sizeof(float), GL_FLOAT, GL_FALSE, sizeof(RadiusAngle), nullptr);
67+
}
68+
};
69+
70+
/**
71+
* Vertex attributes for zoom, zoom exponent, rotation and warp strength.
72+
*/
73+
struct ZoomRotWarp {
7074
float zoom{};
7175
float zoomExp{};
7276
float rot{};
7377
float warp{};
7478

75-
float centerX{};
76-
float centerY{};
77-
78-
float distanceX{};
79-
float distanceY{};
80-
81-
float stretchX{};
82-
float stretchY{};
79+
static void InitializeAttributePointer(uint32_t attributeIndex)
80+
{
81+
glVertexAttribPointer(attributeIndex, sizeof(ZoomRotWarp) / sizeof(float), GL_FLOAT, GL_FALSE, sizeof(ZoomRotWarp), nullptr);
82+
}
8383
};
8484

85-
using VertexList = std::vector<MeshVertex>;
86-
8785
/**
8886
* @brief Initializes the vertex array and fills in static data if needed.
8987
*
@@ -124,10 +122,12 @@ class PerPixelMesh : public Renderer::RenderItem
124122
int m_viewportWidth{}; //!< Last known viewport width.
125123
int m_viewportHeight{}; //!< Last known viewport height.
126124

127-
VertexList m_vertices; //!< The calculated mesh vertices.
128-
129-
std::vector<int> m_listIndices; //!< List of vertex indices to render.
130-
VertexList m_drawVertices; //!< Temp data buffer for the vertices to be drawn.
125+
Renderer::Mesh m_warpMesh; //!< The Warp effect mesh
126+
Renderer::VertexBuffer<RadiusAngle> m_radiusAngleBuffer; //!< Vertex attribute buffer for radius and angle values.
127+
Renderer::VertexBuffer<ZoomRotWarp> m_zoomRotWarpBuffer; //!< Vertex attribute buffer for zoom, roation and warp values.
128+
Renderer::VertexBuffer<Renderer::Point> m_centerBuffer; //!< Vertex attribute buffer for center coordinate values.
129+
Renderer::VertexBuffer<Renderer::Point> m_distanceBuffer; //!< Vertex attribute buffer for distance values.
130+
Renderer::VertexBuffer<Renderer::Point> m_stretchBuffer; //!< Vertex attribute buffer for stretch values.
131131

132132
std::weak_ptr<Renderer::Shader> m_perPixelMeshShader; //!< Special shader which calculates the per-pixel UV coordinates.
133133
std::unique_ptr<MilkdropShader> m_warpShader; //!< The warp shader. Either preset-defined or a default shader.

src/libprojectM/MilkdropPreset/Shaders/PresetWarpVertexShaderGlsl330.vert

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,11 @@ precision mediump float;
1414
#define invAspectY aspect.w
1515

1616
layout(location = 0) in vec2 vertex_position;
17-
layout(location = 1) in vec2 rad_ang;
18-
layout(location = 2) in vec4 transforms;
19-
layout(location = 3) in vec2 warp_center;
20-
layout(location = 4) in vec2 warp_distance;
21-
layout(location = 5) in vec2 stretch;
17+
layout(location = 3) in vec2 rad_ang;
18+
layout(location = 4) in vec4 transforms;
19+
layout(location = 5) in vec2 warp_center;
20+
layout(location = 6) in vec2 warp_distance;
21+
layout(location = 7) in vec2 stretch;
2222

2323
uniform mat4 vertex_transformation;
2424
uniform vec4 aspect;

0 commit comments

Comments
 (0)