GCC Code Coverage Report


./
Coverage:
low: ≥ 0%
medium: ≥ 75.0%
high: ≥ 90.0%
Lines:
0 of 97, 0 excluded
0.0%
Functions:
0 of 14, 0 excluded
0.0%
Branches:
0 of 107, 0 excluded
0.0%

libs/render/src/render/uniform_buffer.cc
Line Branch Exec Source
1 #include "render/uniform_buffer.h"
2
3 #include "base/mat4.h"
4 #include "render/opengl_labels.h"
5 #include "render/opengl_utils.h"
6
7 namespace eu::render
8 {
9
10 using UniformBufferDescription = std::vector<UniformProp>;
11
12 /// returns the size in bytes
13 int size_of(const UniformProp& prop, bool align)
14 {
15 constexpr int n = 4; // in bytes
16 constexpr int n2 = n * 2;
17 constexpr int n4 = n * 4;
18 switch (prop.array_count == 1 ? prop.type : UniformType::vec4)
19 {
20 case UniformType::bool_type:
21 case UniformType::int_type:
22 case UniformType::float_type:
23 return n;
24 case UniformType::vec2: return n2;
25 case UniformType::vec3:
26 case UniformType::vec4:
27 return n4;
28 case UniformType::mat4: return n4 * (align ? 1 : 4);
29 default: DIE("invalid uniform type"); return 0;
30 }
31 }
32
33 int calculate_alignment_bytes(int current_size, const UniformProp& prop)
34 {
35 const auto size = size_of(prop, true);
36 const auto mod = current_size % size;
37 if (mod == 0)
38 {
39 return 0;
40 }
41
42 const auto to_add = size - mod;
43 ASSERT((to_add + mod) % size == 0);
44 return to_add;
45 }
46
47 std::string source_from(const std::string& name, const UniformBufferDescription& desc)
48 {
49 const auto string_from_type = [](UniformType t)
50 {
51 switch (t)
52 {
53 case UniformType::bool_type: return "bool";
54 case UniformType::int_type: return "int";
55 case UniformType::float_type: return "float";
56 case UniformType::vec2: return "vec2";
57 case UniformType::vec3: return "vec3";
58 case UniformType::vec4: return "vec4";
59 case UniformType::mat4: return "mat4";
60 default: DIE("invalid uniform type"); return "unhandled_type";
61 }
62 };
63 std::ostringstream ss;
64 ss << "layout (std140) uniform " << name << "\n";
65 ss << "{"
66 << "\n";
67 for (const auto& p: desc)
68 {
69 ss << "\t" << string_from_type(p.type) << " " << p.name;
70 if (p.array_count > 1)
71 {
72 ss << "[" << p.array_count << "]";
73 }
74 ss << ";\n";
75 }
76 ss << "};"
77 << "\n";
78 return ss.str();
79 }
80
81 void UniformBufferCompiler::add(CompiledUniformProp* target, UniformType type, const std::string& name, int array_count)
82 {
83 props.emplace_back(UniformProp{target, type, name, array_count});
84 }
85
86 UniformBufferSetup UniformBufferCompiler::compile(const std::string& name, int binding_point) const
87 {
88 UniformBufferSetup target;
89 target.size = 0;
90 target.binding_point = binding_point;
91 target.name = name;
92 target.source = source_from(name, props);
93 for (const auto& p: props)
94 {
95 const auto size = size_of(p, false);
96 target.size += calculate_alignment_bytes(target.size, p);
97 *p.target = {target.size, p.type, p.array_count};
98 target.size += size * p.array_count;
99 }
100
101 return target;
102 }
103
104 namespace
105 {
106 const UniformBuffer* bound_buffer = nullptr;
107 } // namespace
108
109 BoundUniformBuffer::BoundUniformBuffer(UniformBuffer* b)
110 : buffer(b)
111 {
112 ASSERT(bound_buffer == nullptr);
113 bound_buffer = b;
114 glBindBuffer(GL_UNIFORM_BUFFER, b->id);
115 }
116
117 BoundUniformBuffer::~BoundUniformBuffer()
118 {
119 ASSERT(bound_buffer == buffer);
120 bound_buffer = nullptr;
121 glBindBuffer(GL_UNIFORM_BUFFER, 0);
122 }
123
124 UniformBuffer::UniformBuffer(DEBUG_LABEL_ARG_MANY const UniformBufferSetup& setup)
125 : id(create_buffer())
126 {
127 auto bound = BoundUniformBuffer{this};
128 SET_DEBUG_LABEL_NAMED(id, DebugLabelFor::Buffer, fmt::format("UNI B {}", debug_label));
129
130 // Changed to a dynamic draw due to:
131 // Using glBufferSubData(...) to update a GL_STATIC_DRAW buffer
132 // Performance Severity: medium
133 // todo(Gustav): profile? provide a hint in an argument?
134 glBufferData(GL_UNIFORM_BUFFER, setup.size, nullptr, GL_DYNAMIC_DRAW);
135 glBindBufferBase(GL_UNIFORM_BUFFER, gluint_from_int(setup.binding_point), id);
136 }
137
138 UniformBuffer::~UniformBuffer()
139 {
140 unload();
141 }
142
143 UniformBuffer::UniformBuffer(UniformBuffer&& rhs) noexcept
144 : id(rhs.id)
145 {
146 rhs.id = 0;
147 }
148
149 UniformBuffer& UniformBuffer::operator=(UniformBuffer&& rhs) noexcept
150 {
151 unload();
152 id = rhs.id;
153 rhs.id = 0;
154 return *this;
155 }
156
157 // clears the loaded buffer to a invalid buffer
158 void UniformBuffer::unload()
159 {
160 if (id == 0)
161 {
162 return;
163 }
164
165 destroy_buffer(id);
166 id = 0;
167 }
168
169 void UniformBuffer::set_mat4(const CompiledUniformProp& prop, const m4& m) // NOLINT(readability-convert-member-functions-to-static)
170 {
171 // todo(Gustav): verify that the prop belongs to self
172 ASSERT(prop.type == UniformType::mat4 && prop.array_count == 1);
173 glBufferSubData(GL_UNIFORM_BUFFER, prop.offset, 16 * sizeof(float), m.get_column_major_data_ptr());
174 }
175
176 } // namespace klotter
177