Cogs.Core
MeshManager.cpp
1#include "MeshManager.h"
2#include "Context.h"
3#include "Mesh.h"
4
5#include "Platform/Instrumentation.h"
6
7#include "Renderer/IRenderer.h"
8#include "Renderer/Renderer.h"
9#include "Renderer/RenderMesh.h"
10#include "Resources/BufferManager.h"
11
12#include "Rendering/ICapabilities.h"
13
14#include "Foundation/Logging/Logger.h"
15#include "Foundation/Platform/Timer.h"
16
17using namespace Cogs::Core;
18using namespace Cogs::Geometry;
19
20namespace
21{
22 Cogs::Logging::Log logger = Cogs::Logging::getLogger("MeshManager");
23
24 void generateCube(Mesh * mesh, float size = 1.0f)
25 {
26 float vertexes[] = {
27 -size, -size, size,
28 size, -size, size,
29 size, size, size,
30 -size, -size, size,
31 size, size, size,
32 -size, size, size,
33
34 -size, -size, -size,
35 -size, -size, size,
36 -size, size, size,
37 -size, -size, -size,
38 -size, size, size,
39 -size, size, -size,
40
41 size, -size, size,
42 size, -size, -size,
43 size, size, -size,
44 size, -size, size,
45 size, size, -size,
46 size, size, size,
47
48 size, -size, -size,
49 -size, -size, -size,
50 -size, size, -size,
51 size, -size, -size,
52 -size, size, -size,
53 size, size, -size,
54
55 -size, size, size,
56 size, size, size,
57 size, size, -size,
58 -size, size, size,
59 size, size, -size,
60 -size, size, -size,
61
62 -size, -size, -size,
63 size, -size, -size,
64 size, -size, size,
65 -size, -size, -size,
66 size, -size, size,
67 -size, -size, size
68 };
69
70 mesh->setPositions(reinterpret_cast<glm::vec3 *>(vertexes), reinterpret_cast<glm::vec3 *>(vertexes) + 36);
71
72 float normals[] = {
73 0, 0, 1,
74 0, 0, 1,
75 0, 0, 1,
76 0, 0, 1,
77 0, 0, 1,
78 0, 0, 1,
79
80 -1, 0, 0,
81 -1, 0, 0,
82 -1, 0, 0,
83 -1, 0, 0,
84 -1, 0, 0,
85 -1, 0, 0,
86
87 1, 0, 0,
88 1, 0, 0,
89 1, 0, 0,
90 1, 0, 0,
91 1, 0, 0,
92 1, 0, 0,
93
94 0, 0, -1,
95 0, 0, -1,
96 0, 0, -1,
97 0, 0, -1,
98 0, 0, -1,
99 0, 0, -1,
100
101 0, 1, 0,
102 0, 1, 0,
103 0, 1, 0,
104 0, 1, 0,
105 0, 1, 0,
106 0, 1, 0,
107
108 0, -1, 0,
109 0, -1, 0,
110 0, -1, 0,
111 0, -1, 0,
112 0, -1, 0,
113 0, -1, 0,
114 };
115
116 mesh->setNormals(reinterpret_cast<glm::vec3 *>(normals), reinterpret_cast<glm::vec3 *>(normals) + 36);
117
118 float texCoords[] = {
119 0, 1,
120 1, 1,
121 1, 0,
122 0, 1,
123 1, 0,
124 0, 0,
125
126 0, 1,
127 1, 1,
128 1, 0,
129 0, 1,
130 1, 0,
131 0, 0,
132
133 0, 1,
134 1, 1,
135 1, 0,
136 0, 1,
137 1, 0,
138 0, 0,
139
140 0, 1,
141 1, 1,
142 1, 0,
143 0, 1,
144 1, 0,
145 0, 0,
146
147 0, 1,
148 1, 1,
149 1, 0,
150 0, 1,
151 1, 0,
152 0, 0,
153
154 0, 1,
155 1, 1,
156 1, 0,
157 0, 1,
158 1, 0,
159 0, 0,
160 };
161
162 mesh->setTexCoords(reinterpret_cast<glm::vec2 *>(texCoords), reinterpret_cast<glm::vec2 *>(texCoords) + 36);
163 }
164
165}
166
167namespace Cogs::Core
168{
170 {
172 {
173 RenderMesh * renderMesh = nullptr;
174 Mesh proxy;
175 MeshHandle mesh;
176 };
177
178 bool updateAsync = false;
179 bool ready = true;
180 TaskId meshGroup;
181 std::vector<UpdatedMesh> updatedMeshes;
182
183 struct Deletion
184 {
185 Mesh * mesh = nullptr;
186 RenderResource * attachment = nullptr;
187 };
188
189 struct Swapped
190 {
191 RenderResource * attachment = nullptr;
192 };
193
194 std::vector<Deletion> deletionQueue;
195 std::vector<Swapped> swappedQueue;
196 std::deque<Cogs::Core::MeshManager::SwapOperation> swappingResources;
197 };
198}
199
201{
202 data->meshGroup = context->taskManager->createGroup(TaskManager::ResourceQueue);
203}
204
206{
207 context->taskManager->wait(data->meshGroup);
208 processSwapping(); // TODO Make more elegant. Protects against crash in destruction of meshes in udateMeshes.
209 context->taskManager->wait(data->meshGroup);
210 reportLeaks("Mesh");
211}
212
214{
215 ResourceManager::initialize();
216 VertexFormats::initialize();
217
218 auto mesh = create();
219
220 defaultResource = mesh;
221
222 generateCube(mesh.resolve(), 0.5f);
223
224 setResourceId(mesh.get(), getNextResourceId());
225}
226
227Cogs::Core::MeshHandle Cogs::Core::MeshManager::getMesh(const StringView & name)
228{
229 return getByName(name);
230}
231
233{
234 loadInfo->handle->setChanged();
235 setProcessed(loadInfo);
236}
237
239{
240 if (!data->updateAsync) {
241 context->renderer->getResources()->releaseResource(mesh);
242 }
243}
244
245void Cogs::Core::MeshManager::destroyInternal(ResourceBase * resource)
246{
247 if (!data->updateAsync) {
248 ResourceManager::destroyInternal(resource);
249 }
250}
251
252Cogs::Core::ResourceBufferHandle Cogs::Core::MeshManager::createBuffer()
253{
254 return context->bufferManager->create();
255}
256
258{
259 if (!context->device->getCapabilities()->getDeviceCapabilities().SupportsMultipleThreads || !context->variables->get("resources.meshes.updateAsync", false)) {
260 ResourceManager::processDeletion();
261 return;
262 }
263
264 CpuInstrumentationScope(SCOPE_RESOURCES, "MeshManager::processDeletion");
265
266 data->updateAsync = context->variables->get("resources.meshes.updateAsync", false);
267
268 auto t = Timer::startNew();
269
270 if (data->updateAsync) {
271 std::vector<ResourceBase *> deletion;
272 fillDeletionQueue(deletion);
273
274 data->deletionQueue.reserve(deletion.size());
275
276 for (auto & d : deletion) {
277 auto mesh = (Mesh *)d;
278 data->deletionQueue.emplace_back(MeshManagerData::Deletion{ mesh, mesh->getAttachedResource() });
279 }
280 } else {
281 ResourceManager::processDeletion();
282 }
283
284 if (data->deletionQueue.size()) {
285 context->taskManager->enqueueChild(data->meshGroup, [this, deletionQueue = std::move(data->deletionQueue)]() mutable
286 {
287 CpuInstrumentationScope(SCOPE_RESOURCES, "MeshManager::processDeletionTask");
288
289 Renderer * renderer = dynamic_cast<Cogs::Core::Renderer*>(context->renderer);
290
291 for (auto & deletion : deletionQueue) {
292 if (!deletion.attachment) continue;
293 auto renderMesh = (RenderMesh *)deletion.attachment;
294 renderMesh->release(renderer);
295 renderer->getRenderResources().destroyRenderMesh(renderMesh);
296 deletion.mesh->attachResource(nullptr);
297 }
298
299 for (auto & deletion : deletionQueue) {
300 safeDestroy(deletion.mesh);
301 destroyLocked(deletion.mesh);
302 }
303 });
304 }
305
306 if (data->swappedQueue.size()) {
307 context->taskManager->enqueueChild(data->meshGroup, [this, swappedQueue = std::move(data->swappedQueue)]()
308 {
309 CpuInstrumentationScope(SCOPE_RESOURCES, "MeshManager::processSwappedMeshTask");
310
311 Renderer * renderer = dynamic_cast<Cogs::Core::Renderer*>(context->renderer);
312
313 for (auto & swapped : swappedQueue) {
314 if (!swapped.attachment) continue;
315 auto renderMesh = (RenderMesh *)swapped.attachment;
316 renderMesh->release(renderer);
317 renderer->getRenderResources().destroyRenderMesh(renderMesh);
318 }
319 });
320 }
321
322 auto elapsed = t.elapsedSeconds();
323
324 if (elapsed > 0.005) {
325 LOG_DEBUG(logger, "MeshManager::processDeletion elapsed: %f", elapsed);
326 }
327}
328
330{
331 if (!context->device->getCapabilities()->getDeviceCapabilities().SupportsMultipleThreads || !context->variables->get("resources.meshes.updateAsync", false)) {
333 return;
334 }
335
336 bool isBatch = !context->variables->get("editor.batch")->getValue().empty();
337
338 float uploadBatchMaxTime = context->variables->get("resources.meshes.uploadBatchMaxTime", 0.f);
339
340 LockGuard swapLock(swapMutex);
341
342 auto context = this->context;
343 if (data->ready) {
344 data->ready = false;
345
346 for (auto & updatedMesh : data->updatedMeshes) {
347 auto mesh = updatedMesh.mesh.resolve();
348
349 if (mesh->hasAttachedResource()) {
350 data->swappedQueue.emplace_back(MeshManagerData::Swapped{ mesh->getAttachedResource() });
351 mesh->attachResource(nullptr);
352 }
353
354 *mesh = std::move(updatedMesh.proxy);
355
356 if (!isBatch) {
357 updatedMesh.renderMesh->setResource(mesh);
358 mesh->attachResource(updatedMesh.renderMesh);
359 }
360
361 mesh->incrementGeneration();
362 mesh->setResident();
363 mesh->setLoaded();
364 }
365
366 data->updatedMeshes.clear();
367
368 for (Cogs::Core::MeshManager::SwapOperation& resource : swapQueue) {
369 data->swappingResources.push_back(std::move(resource));
370 }
371 swapQueue.clear();
372 if (data->swappingResources.empty()) {
373 data->ready = true;
374 return;
375 }
376
377 context->taskManager->enqueueChild(data->meshGroup, [context, data = this->data.get(), isBatch, uploadBatchMaxTime]() mutable
378 {
379 CpuInstrumentationScope(SCOPE_RESOURCES, "MeshManager::asyncUpdate");
380
381 auto t = Timer::startNew();
382 while(!data->swappingResources.empty()) {
383 Cogs::Core::MeshManager::SwapOperation swapResource = std::move(data->swappingResources.front());
384 data->swappingResources.pop_front();
385
386 Renderer * renderer = dynamic_cast<Cogs::Core::Renderer*>(context->renderer);
387 auto & renderResources = renderer->getRenderResources();
388
389 auto & updatedMesh = data->updatedMeshes.emplace_back();
390
391 if (!isBatch) {
392 auto renderMesh = renderResources.createRenderMesh();
393
394 renderMesh->update(swapResource.source.resolve(), renderer->getDevice(), &renderResources);
395
396 updatedMesh.renderMesh = renderMesh;
397 }
398
399 updatedMesh.mesh = swapResource.destinationHandle;
400 updatedMesh.proxy = std::move(*swapResource.source.resolve());
401
402 if (!isBatch && 0.0 < uploadBatchMaxTime && uploadBatchMaxTime < t.elapsedSeconds()) {
403 break;
404 }
405
406 }
407
408 LOG_TRACE(logger, "Async mesh processing elapsed: %f", t.elapsedSeconds());
409
410 data->ready = true;
411
412 context->engine->setDirty();
413 });
414 }
415}
416
418{
419 return context->renderer->getResources()->updateResource(meshHandle);
420}
A Context instance contains all the services, systems and runtime components needed to use Cogs.
Definition: Context.h:83
std::unique_ptr< class TaskManager > taskManager
TaskManager service instance.
Definition: Context.h:186
void processDeletion() override
Process resources pending deallocation.
ActivationResult handleActivation(ResourceHandle handle, Mesh *mesh) override
Overridden to handle mesh activation, updating the resource in the renderer.
void handleLoad(ResourceLoadInfoBase *loadInfo) override
Handler for resource loading.
void initialize() override
MeshManager(Context *context)
Constructs a MeshManager in the given context.
void handleDeletion(Mesh *mesh) override
Overridden to handle mesh deletion, removing the resource from the renderer.
~MeshManager() override
Destructs the MeshManager.
void processSwapping() override
Overridden to dispatch async updates for swapping resources if enabled.
Core renderer system.
Definition: Renderer.h:28
The generic resource manager provides a base implementation for specialized resource managers to buil...
void processSwapping() override
Process queued swap operations, exchanging resource contents of the destination resources by those in...
static constexpr TaskQueueId ResourceQueue
Resource task queue.
Definition: TaskManager.h:232
Log implementation class.
Definition: LogManager.h:139
Provides a weakly referenced view over the contents of a string.
Definition: StringView.h:24
Contains the Engine, Renderer, resource managers and other systems needed to run Cogs....
ActivationResult
Defines results for resource activation.
Definition: ResourceBase.h:14
Contains geometry calculations and generation.
constexpr Log getLogger(const char(&name)[LEN]) noexcept
Definition: LogManager.h:180
STL namespace.
Meshes contain streams of vertex data in addition to index data and options defining geometry used fo...
Definition: Mesh.h:265
void setTexCoords(std::span< const glm::vec2 > texCoords)
Set the texture coordinate data of the Mesh.
Definition: Mesh.h:504
void setNormals(std::span< const glm::vec3 > normals)
Set the normal data of the Mesh.
Definition: Mesh.h:392
void setPositions(std::span< const glm::vec3 > positions)
Set the position data of the Mesh.
Definition: Mesh.h:315
Base class for engine resources.
Definition: ResourceBase.h:107
void incrementGeneration()
Increment the generation count.
Definition: ResourceBase.h:367
void attachResource(RenderResource *attachment)
Attach the given GPU resource to the resource.
Definition: ResourceBase.h:261
RenderResource * getAttachedResource() const
Get the attached resource.
Definition: ResourceBase.h:275
bool hasAttachedResource() const
Check if the resource has an attachment.
Definition: ResourceBase.h:268
ResourceHandleBase handle
Handle to resource structure for holding actual resource data.
Task id struct used to identify unique Task instances.
Definition: TaskManager.h:20