Skip to content

Commit 00081d1

Browse files
committed
RenderLoop optimization
Avoid std::vector on render loop: Buffer3 + BufferGL. std::vector -> array pointer. Result: Perf improvement from 30 FPS -> 500 FPS.
1 parent 99cba64 commit 00081d1

15 files changed

+106
-50
lines changed

source/CMakeLists.txt

+2
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ set(forth_common_srcs
1212
set(forth_extras_srcs
1313
extras/MeshGen.h
1414
extras/MeshGen.cpp
15+
extras/Utils.h
1516
)
1617

1718
set(forth_math_srcs
@@ -33,6 +34,7 @@ set(forth_rendering_srcs
3334
rendering/Model4.h
3435
rendering/Projector4.cpp
3536
rendering/Projector4.h
37+
rendering/Scene4.h
3638
rendering/Visualizer4.h
3739
)
3840

source/common/Buffer3.h

+18-12
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
#include "../math/Vector3.h"
44
#include "../common/Color.h"
5+
#include "../extras/Utils.h"
56
#include "VertexProfile.h"
67
#include "Enums.h"
78
#include <vector>
@@ -10,44 +11,49 @@ namespace Forth
1011
{
1112
struct Buffer3
1213
{
13-
std::vector<Vector3> vertices;
14-
std::vector<int> indices;
14+
FORTH_ARRAY(vertices, Vector3);
15+
FORTH_ARRAY(indices, int);
1516
Forth::SimplexMode simplex;
1617

1718
Buffer3() { simplex = SM_Triangle; }
1819

1920
~Buffer3(void)
2021
{
21-
Clear();
22+
delete[] vertices;
23+
delete[] indices;
2224
}
2325

2426
void Clear(void)
2527
{
26-
vertices.clear();
27-
indices.clear();
28+
vertices_count = 0;
29+
indices_count = 0;
2830
}
2931

3032
void AddVert(const Vector3 &v)
3133
{
32-
vertices.push_back(v);
34+
EnsureCapacity(&vertices, vertices_count, &vertices_cap, vertices_count + 1);
35+
vertices[vertices_count++] = v;
3336
}
3437

3538
void AddTris(const int a)
3639
{
37-
indices.push_back(a);
40+
EnsureCapacity(&indices, indices_count, &indices_cap, indices_count + 1);
41+
indices[indices_count++] = a;
3842
}
3943

4044
void AddTris(const int a, const int b)
4145
{
42-
indices.push_back(a);
43-
indices.push_back(b);
46+
EnsureCapacity(&indices, indices_count, &indices_cap, indices_count + 2);
47+
indices[indices_count++] = a;
48+
indices[indices_count++] = b;
4449
}
4550

4651
void AddTris(const int a, const int b, const int c)
4752
{
48-
indices.push_back(a);
49-
indices.push_back(b);
50-
indices.push_back(c);
53+
EnsureCapacity(&indices, indices_count, &indices_cap, indices_count + 3);
54+
indices[indices_count++] = a;
55+
indices[indices_count++] = b;
56+
indices[indices_count++] = c;
5157
}
5258

5359
};

source/common/BufferGL.h

+17-6
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
#include "../common/Color.h"
44
#include "../math/Vector3.h"
5+
#include "../extras/Utils.h"
56
#include "Buffer3.h"
67
#include "Enums.h"
78
#include <vector>
@@ -11,26 +12,32 @@ namespace Forth
1112
struct BufferGL
1213
{
1314
// Layout: 0-2 Position. 3-5 Normal
14-
std::vector<float> vb;
15+
FORTH_ARRAY(vb, float);
1516

1617
BufferGL(void) {}
1718

1819
~BufferGL(void)
1920
{
20-
Clear();
21+
delete[] vb;
2122
}
2223

2324
void Clear(void)
2425
{
25-
vb.clear();
26+
vb_count = 0;
2627
}
2728

2829
void Copy(const Buffer3 &v)
2930
{
3031
Clear();
31-
size_t len = v.indices.size();
3232

33-
for (size_t i = 0; i < len;)
33+
int len = v.indices_count;
34+
35+
const int BUFFER_PER_VERTEX = 6;
36+
const int BUFFER_PER_TRIS = BUFFER_PER_VERTEX * 3;
37+
38+
EnsureCapacity(&vb, 0, &vb_cap, len * BUFFER_PER_VERTEX);
39+
40+
for (int i = 0; i < len;)
3441
{
3542
const int a = v.indices[i++],
3643
b = v.indices[i++],
@@ -49,7 +56,11 @@ namespace Forth
4956
};
5057
// clang-format on
5158

52-
vb.insert(vb.end(), arr, arr + 18);
59+
for(int j = 0; j < BUFFER_PER_TRIS;)
60+
{
61+
vb[vb_count++] = arr[j++];
62+
}
63+
5364
}
5465
}
5566
};

source/extras/Utils.h

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
#pragma once
2+
#include "../math/Math.h"
3+
4+
namespace Forth
5+
{
6+
template <typename T>
7+
void EnsureCapacity(T **arr, const int count, int *cap, const int target)
8+
{
9+
if (*cap < target)
10+
{
11+
*cap = Max(target, *cap << 1);
12+
T *newArr = new T[*cap];
13+
14+
if (count > 0)
15+
{
16+
memcpy(newArr, *arr, count * sizeof(T));
17+
}
18+
19+
delete[] * arr;
20+
*arr = newArr;
21+
}
22+
}
23+
24+
#define FORTH_ARRAY(name, T) \
25+
T *name = new T[4]; \
26+
int name##_cap = 4; \
27+
int name##_count = 0
28+
29+
} // namespace Forth

source/math/Vector3.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ namespace Forth
5252
return *this;
5353
}
5454

55-
Vector3& operator*=(float f)
55+
Vector3& operator*=(const float f)
5656
{
5757
x *= f;
5858
y *= f;

source/math/Vector4.h

+4-4
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ namespace Forth
9494
return *this;
9595
}
9696

97-
Vector4& operator*=(float f)
97+
Vector4& operator*=(const float f)
9898
{
9999
x *= f;
100100
y *= f;
@@ -148,7 +148,7 @@ namespace Forth
148148
/// <summary>
149149
/// Axis-wisely scale vector values with a number.
150150
/// </summary>
151-
const Vector4 operator*(float f) const
151+
const Vector4 operator*(const float f) const
152152
{
153153
return Vector4(x * f, y * f, z * f, w * f);
154154
}
@@ -233,7 +233,7 @@ namespace Forth
233233
/// Interpolate two vector by T and clamp.
234234
/// </summary>
235235
/// <remarks> The interpolation is clamped between zero to one </remarks>
236-
inline Vector4 Lerp(const Vector4& a, const Vector4& b, float t)
236+
inline Vector4 Lerp(const Vector4& a, const Vector4& b, const float t)
237237
{
238238
return a + (b - a) * Clamp01(t);
239239
}
@@ -242,7 +242,7 @@ namespace Forth
242242
/// Interpolate two vector by T.
243243
/// </summary>
244244
/// <remarks> The interpolation is **not** clamped. </remarks>
245-
inline Vector4 LerpUnclamped(const Vector4& a, const Vector4& b, float t)
245+
inline Vector4 LerpUnclamped(const Vector4& a, const Vector4& b, const float t)
246246
{
247247
return a + (b - a) * t;
248248
}

source/rendering/CrossSection.cpp

+5-4
Original file line numberDiff line numberDiff line change
@@ -85,13 +85,14 @@ namespace Forth
8585
void CrossSection::Project(const Buffer4 &source, const Transform4 &transform, Visualizer4 *dest)
8686
{
8787
viewmodel = view * transform;
88-
sides.clear();
88+
89+
EnsureCapacity(&sides, 0, &sides_cap, source.verticeCount);
8990
{
9091
// faster than "sides[i] = viewmodel * source.vertices[i] > 0"
9192
Vector4 &vmw = viewmodel.rotation.ew;
92-
float vmwp = -viewmodel.position.w;
93-
for (int i = 0; i < source.verticeCount; i++)
94-
sides.push_back(Dot(vmw, source.vertices[i]) > vmwp);
93+
float vmwp = viewmodel.position.w;
94+
for (int i = 0; i < source.verticeCount; ++i)
95+
sides[i] = (Dot(vmw, source.vertices[i]) < vmwp);
9596
}
9697

9798
{

source/rendering/CrossSection.h

+4-2
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
#include "../math/Transform4.h"
44
#include "Projector4.h"
5+
#include "../extras/Utils.h"
56
#include <vector>
67

78
namespace Forth
@@ -10,7 +11,8 @@ namespace Forth
1011
{
1112

1213
Transform4 view, viewmodel;
13-
std::vector<bool> sides;
14+
bool* sides = new bool[4];
15+
int sides_cap = 4;
1416
Vector4 _temp[4];
1517
VertexProfile _temp2[4];
1618

@@ -28,7 +30,7 @@ namespace Forth
2830

2931
~CrossSection(void)
3032
{
31-
sides.clear();
33+
delete[] sides;
3234
}
3335

3436
/// <summary>

source/rendering/Model4.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,12 @@
1818
do \
1919
{ \
2020
glBindBuffer(GL_ARRAY_BUFFER, vb); \
21-
glBufferData(GL_ARRAY_BUFFER, model.driver.vb.size() * sizeof(float), &model.driver.vb[0], GL_STREAM_DRAW); \
21+
glBufferData(GL_ARRAY_BUFFER, model.driver.vb_count * sizeof(float), &model.driver.vb[0], GL_STREAM_DRAW); \
2222
glEnableVertexAttribArray(0); \
2323
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void *)(0)); \
2424
glEnableVertexAttribArray(1); \
2525
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void *)(3 * sizeof(float))); \
26-
glDrawArrays(GL_TRIANGLES, 0, model.driver.vb.size() / 6); \
26+
glDrawArrays(GL_TRIANGLES, 0, model.driver.vb_count / 6); \
2727
} while (0)
2828

2929
namespace Forth

source/rendering/Projector4.cpp

+3-4
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
#pragma once
21

32
#include "Projector4.h"
43

@@ -21,8 +20,8 @@ namespace Forth
2120

2221
Projector4::~Projector4()
2322
{
24-
delete defaultVisualizers[SM_Point];
25-
delete defaultVisualizers[SM_Line];
26-
delete defaultVisualizers[SM_Triangle];
23+
delete (ParticleVisualizer*)(defaultVisualizers[SM_Point]);
24+
delete (WireVisualizer*)(defaultVisualizers[SM_Line]);
25+
delete (SolidVisualizer*)(defaultVisualizers[SM_Triangle]);
2726
}
2827
}

source/rendering/Scene4.h

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#pragma once
2+
3+
namespace Forth
4+
{
5+
6+
}

source/visualizer/ParticleVisualizer.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ namespace Forth
3030
// Because it's a segment, count is expected to be 2
3131
void Render(const Vector4 *buffer, int count) override
3232
{
33-
buff->AddTris((int)buff->vertices.size());
33+
buff->AddTris((int)buff->vertices_count);
3434
buff->AddVert(buffer[0].ToVec3());
3535
}
3636

source/visualizer/SolidVisualizer.cpp

+12-12
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,21 @@
11
#include "SolidVisualizer.h"
22

3-
namespace Forth {
3+
namespace Forth
4+
{
45

56
SolidVisualizer::SolidVisualizer() {}
67

7-
void SolidVisualizer::Initialize(Buffer3 & buffer)
8+
void SolidVisualizer::Initialize(Buffer3 &buffer)
89
{
910
buff = &buffer;
1011
buff->Clear();
1112
buff->simplex = SimplexMode::SM_Triangle;
1213
}
1314

14-
void SolidVisualizer::Render(const Vector4 * buffer, int count)
15+
void SolidVisualizer::Render(const Vector4 *buffer, int count)
1516
{
1617
Buffer3 &b = *buff;
17-
int o = (int)b.vertices.size();
18+
int o = b.vertices_count;
1819
b.AddVert(buffer[0].ToVec3());
1920
b.AddVert(buffer[1].ToVec3());
2021
for (int i = 2; i < count; i++)
@@ -31,17 +32,17 @@ namespace Forth {
3132

3233
void SolidVisualizer::RefineTriangleOrder()
3334
{
34-
std::vector<int> &t = buff->indices;
35-
std::vector<Vector3> &v = buff->vertices;
35+
int *t = buff->indices;
36+
Vector3 *v = buff->vertices;
3637

37-
Vector3 median = GetAverage(v);
38+
Vector3 median = GetAverage(buff->vertices, buff->vertices_count) - Vector3(.1e-4f);
3839

39-
for (size_t i = 0; i < t.size(); i += 3)
40+
for (int i = 0; i < buff->indices_count; i += 3)
4041
{
4142
int a = t[i], b = t[i + 1], c = t[i + 2];
4243
Vector3 &va = v[a];
4344
Vector3 N = Cross(v[c] - va, v[b] - va);
44-
if (Dot(N, median) < Dot(N, va))
45+
if (Dot(N, median - va) < 0)
4546
{
4647
// Flip
4748
t[i] = c;
@@ -50,13 +51,12 @@ namespace Forth {
5051
}
5152
}
5253

53-
Vector3 SolidVisualizer::GetAverage(const std::vector<Vector3>& v)
54+
Vector3 SolidVisualizer::GetAverage(const Vector3 *v, const int size)
5455
{
5556
Vector3 median = Vector3();
56-
size_t size = v.size();
5757
for (size_t i = size; i-- > 0;)
5858
median += v[i];
5959
return median / (float)size;
6060
}
6161

62-
}
62+
} // namespace Forth

source/visualizer/SolidVisualizer.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ namespace Forth
3232
/// </summary>
3333
void RefineTriangleOrder(void);
3434

35-
Vector3 GetAverage(const std::vector<Vector3> &v);
35+
Vector3 GetAverage(const Vector3* v, const int size);
3636
};
3737

3838
} // namespace Forth

source/visualizer/WireVisualizer.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ namespace Forth
3030
{
3131
for (int i = 0; i < count; i++)
3232
{
33-
buff->AddTris((int)buff->vertices.size());
33+
buff->AddTris(buff->vertices_count);
3434
buff->AddVert(buffer[i].ToVec3());
3535
}
3636
}

0 commit comments

Comments
 (0)