Cogs.Core
GenerateListTask.cpp
1#include "GenerateListTask.h"
2
3#include "Context.h"
4#include "EntityStore.h"
5
6#include "Components/Core/RenderComponent.h"
7
8#include "Foundation/ComponentModel/Entity.h"
9#include "Foundation/Logging/Logger.h"
10
11#include "Rendering/ICapabilities.h"
12#include "Rendering/IBuffers.h"
13
14#include "Renderer/Renderer.h"
15#include "Renderer/RenderResources.h"
16#include "Renderer/RenderStateUpdater.h"
17#include "Renderer/CustomRenderer/DebugGeometryRenderers.h"
18
19#include "Resources/MaterialManager.h"
20#include "Resources/Mesh.h"
21
22#include "Services/Services.h"
23#include "Services/Variables.h"
24#include "Services/PipelineService.h"
25
26#include "Systems/Core/MeshSystem.h"
27#include "Systems/Core/RenderSystem.h"
28#include "Systems/Core/SubMeshRenderSystem.h"
29#include "Systems/Core/InstancedMeshRenderSystem.h"
30#include "Systems/Core/SpriteRenderSystem.h"
31#include "Systems/Core/AnimationSystem.h"
32#include "Systems/Core/StaticModelSystem.h"
33#include "Systems/Core/LightSystem.h"
34#include "Systems/Core/CameraSystem.h"
35#include "Systems/Core/ClipShapeSystem.h"
36
37#ifdef _WIN32
38// TODO: Remove when we update past GLM 0.9.9.7
39#pragma warning(push)
40#pragma warning(disable: 4127) // conditional expression is constant
41#include <glm/ext/matrix_clip_space.hpp>
42#pragma warning(pop)
43#endif
44
45#include <glm/gtx/transform.hpp>
46
47namespace {
48
49 Cogs::Logging::Log logger = Cogs::Logging::getLogger("GenerateListTask");
50
51 constexpr uint32_t minObjectBufferCapacity = 1024;
52}
53
54namespace Cogs::Core
55{
56 const MaterialInstance * getControllingInstance(const MaterialInstance * instance, MaterialFlags::EMaterialFlags overrideFlag)
57 {
58 if (instance->masterInstance && ((instance->masterInstance->getMaterialFlags() & overrideFlag) == overrideFlag)) {
59 return instance->masterInstance.resolve();
60 }
61
62 return instance;
63 }
64
65 void getTransparencyState(RenderStates & /*renderStates*/, const MaterialInstance * materialInstance, RenderItem & renderItem)
66 {
67 const auto instance = getControllingInstance(materialInstance, MaterialFlags::OverrideAlpha);
68 const auto hasTransparency = instance->hasTransparency();
69 auto blendMode = instance->options.blendMode;
70
71 if (blendMode == BlendMode::None && hasTransparency) blendMode = BlendMode::Blend;
72
73 renderItem.blendState = (uint16_t)blendMode;
74 }
75
76 RenderItemFlags getMaterialFlags(const MaterialInstance * materialInstance)
77 {
78 RenderItemFlags flags = RenderItemFlags::None;
79 flags |= (materialInstance->instanceFlags & MaterialFlags::CustomBucket) != 0 ? RenderItemFlags::CustomBucket : RenderItemFlags::None;
80 flags |= materialInstance->hasTransparency() ? RenderItemFlags::Transparent : RenderItemFlags::None;
81 flags |= materialInstance->isBackdrop() ? RenderItemFlags::Backdrop : RenderItemFlags::None;
82 return flags;
83 }
84}
85
86uint8_t Cogs::Core::ClipShapeCache::getIndex(Context* context, ComponentModel::ComponentHandle clipShapeHandle)
87{
89
90 // See if we have already seen this
91 for (size_t i = 1; i < count; i++) {
92 if (handles[i] == clipShapeHandle) {
93 return static_cast<uint8_t>(i);
94 }
95 }
96
97 // Not found, create a new one unless we have created more than 16
98 if (ClipShapeComponent* clipComp = clipShapeHandle.resolveComponent<ClipShapeComponent>(); clipComp) {
99 const ClipShapeData& clipData = context->clipShapeSystem->getData(clipComp);
100
101 switch (clipData.shape) {
103 return 0;
106 if (count < ClipShapeCache::maxClipShapes) {
107 handles[count] = clipShapeHandle;
108 data[count] = {
109 .clipEquations = {
110 clipData.planes[0],
111 clipData.planes[1],
112 clipData.planes[2],
113 clipData.planes[3],
114 clipData.planes[4],
115 clipData.planes[5]
116 },
117 .clipShape = clipData.shape
118 };
119 return static_cast<uint8_t>(count++);
120 }
121 break;
122 default:
123 assert(false && "Invalid enum");
124 }
125 LOG_ERROR_ONCE(logger, "Exceeding max number of clip shapes");
126 }
127 return 0;
128}
129
130
131Cogs::Core::RenderItem& Cogs::Core::GenerateListTask::createRenderItem(Context* context, RenderBatch& batch, const glm::mat4* localToWorld, const RenderComponent* renderComponent)
132{
133 if (renderComponent && (renderComponent->layer&RenderLayers::AllReserved)!=0) {
134 LOG_WARNING_ONCE(logger, "Using a reserved RenderLayer (Consider switching to RenderLayer::Custom).");
135 }
136
137 RenderItem& item = batch.alloc();
138 item = {};
139 item.cullingIndex = (uint32_t)-1;
140 if (localToWorld) {
141 item.worldMatrix = localToWorld;
142 }
143 item.flags = RenderItemFlags::None;
144
145 const uint32_t objectId = renderComponent ? renderComponent->objectId : NoObjectId;
146
147 if (listObjectBuffer.isInUse()) {
148
149 if (listObjectBuffer.cpuCapacity == listObjectBuffer.fill) {
150 listObjectBuffer.cpuCapacity = std::max(minObjectBufferCapacity,
151 listObjectBuffer.cpuCapacity + std::min(1024u * 16u, listObjectBuffer.cpuCapacity / 2));
152 listObjectBuffer.cpu.resize(size_t(listObjectBuffer.stride) * listObjectBuffer.cpuCapacity);
153 }
154
155 item.flags |= RenderItemFlags::ObjectBufferSlot;
156 item.objectBufferSlot = listObjectBuffer.fill++;
157
158 ObjectBuffer* objectBuffer = reinterpret_cast<ObjectBuffer*>((uint8_t*)(listObjectBuffer.cpu.data()) + size_t(listObjectBuffer.stride) * item.objectBufferSlot);
159 if (localToWorld) {
160 objectBuffer->encodeWorldMatrix(*localToWorld);
161 }
162 objectBuffer->encodeObjectId(objectId);
163 }
164 else {
165 item.objectId = objectId;
166 }
167
168 if (renderComponent) {
169 ComponentModel::ComponentHandle clipShapeHandle = renderComponent->clipShapeComponent;
170 if (clipShapeHandle != ComponentModel::ComponentHandle::Empty()) {
171 item.clipShapeIx = clipShapeCache.getIndex(context, clipShapeHandle);
172 }
173 }
174 return item;
175}
176
177size_t Cogs::Core::GenerateListTask::generateItems(Context* context, RenderBatch& batch, Renderer* renderer, RenderSystem* renderSystem, MeshSystem* /*meshSystem*/)
178{
179 size_t missing = 0;
180 for (const auto& renderComponent : renderSystem->pool) {
181 if (!renderComponent.isVisible()) continue;
182
183 auto& renderData = renderSystem->getData<MeshRenderData>(&renderComponent);
184
185 const MeshComponent* meshComponent = renderData.meshComponent.resolveComponent<MeshComponent>();
186 if (meshComponent == nullptr) {
187 LOG_ERROR_ONCE(logger, "No mesh component defined");
188 continue;
189 }
190
191 RenderMesh * renderMesh = renderer->getRenderResources().getRenderMesh(meshComponent->meshHandle);
192
193 if (!renderMesh) {
194 ++missing;
195 continue;
196 }
197
198 Mesh * mesh = meshComponent->meshHandle.resolve();
199
200 MaterialInstance * materialInstance = renderComponent.material.resolve();
201
202 if (!materialInstance) {
203 ++missing;
204 continue;
205 }
206
207 RenderItem& renderBlock = createRenderItem(context, batch, &renderData.localToWorld, &renderComponent);
208 renderBlock.lod = renderComponent.lod;
209 renderBlock.layer = renderComponent.layer;
210 renderBlock.flags |= renderComponent.castShadows() ? RenderItemFlags::CastShadows : RenderItemFlags::None;
211
212 if (renderComponent.disableCulling()) {
213 renderBlock.flags |= RenderItemFlags::DisableCulling;
214 }
215
216 renderBlock.cullingIndex = renderData.cullingIndex;
217
218
219 renderBlock.meshData = renderMesh;
220
221 const uint32_t meshCount = mesh->getCount();
222
223 if (renderComponent.vertexCount == uint32_t(-1)) {
224 renderBlock.startIndex = 0;
225 renderBlock.numIndexes = meshCount;
226 }
227 else {
228 renderBlock.startIndex = renderComponent.startIndex;
229 renderBlock.numIndexes = renderComponent.vertexCount;
230 if (meshCount <= renderBlock.startIndex || meshCount < renderBlock.startIndex + renderBlock.numIndexes) {
231 LOG_ERROR_ONCE(logger, "RenderComponent draw range is out of bounds");
232 continue;
233 }
234 }
235 renderBlock.primitiveType = renderComponent.primitiveType != (PrimitiveType)-1 ? renderComponent.primitiveType : mesh->primitiveType;
236
237 if (mesh->isMeshFlagSet(MeshFlags::Instanced)) {
238 renderBlock.flags |= RenderItemFlags::Instanced;
239 renderBlock.numIndexes = mesh->getCount();
240 renderBlock.numInstances = mesh->getInstanceCount();
241 }
242
243 if (mesh->isMeshFlagSet(MeshFlags::Skinned)) {
244 const AnimationComponent* animationComponent = renderComponent.getComponent<AnimationComponent>();
245 if (animationComponent == nullptr) {
246 LOG_ERROR_ONCE(logger, "No animation component defined");
247 continue;
248 }
249 const AnimationData& animationData = context->animationSystem->getData(animationComponent);
250 renderBlock.poseData = animationData.pose.get();
251 }
252
253 renderBlock.flags |= !mesh->isCCW() ? RenderItemFlags::Clockwise : RenderItemFlags::None;
254 renderBlock.flags |= getMaterialFlags(materialInstance);
255 renderBlock.flags |= ((renderBlock.layer & RenderLayers::Sky) != RenderLayers::None) ? RenderItemFlags::Backdrop : RenderItemFlags::None;
256
257 renderBlock.materialInstance = materialInstance;
258
259 getTransparencyState(renderer->getRenderStates(), materialInstance, renderBlock);
260 renderBlock.drawOrder = materialInstance->options.drawOrder != 0 ? materialInstance->options.drawOrder : renderComponent.drawOrder;
261 }
262
263 return missing;
264}
265
266void Cogs::Core::GenerateListTask::initialize(RenderTaskContext* renderContext)
267{
268 RenderTask::initialize(renderContext);
269}
270
271void Cogs::Core::GenerateListTask::cleanup(RenderTaskContext* renderContext)
272{
273 if (HandleIsValid(listObjectBuffer.gpu)) {
274 IBuffers* buffers = renderContext->device->getBuffers();
275 buffers->releaseBuffer(listObjectBuffer.gpu);
276 listObjectBuffer.gpu = Cogs::BufferHandle::NoHandle;
277 }
278}
279
280void Cogs::Core::GenerateListTask::apply(RenderTaskContext * renderTaskContext)
281{
282 RenderInstrumentationScope(renderTaskContext->device->getImmediateContext(), SCOPE_RENDERING, "GenerateListTask::apply");
283
284 clipShapeCache.handles[0] = ComponentModel::ComponentHandle::Empty();
285 clipShapeCache.data[0] = ClipShapeCache::Item{
286 .clipShape = ClipShapeType::None
287 };
288 clipShapeCache.count = 1;
289
290 auto & renderList = *output.get(RenderResourceType::RenderList)->renderList;
291
292 auto context = renderTaskContext->context;
293 auto renderer = renderTaskContext->renderer;
294
295 ICapabilities* caps = renderTaskContext->device->getCapabilities();
296
297 // Init array object buffer if requested
298 bool useArrayObjectBuffer = false;
299 const StringView arrayObjectBufferKey = "renderer.arrayObjectBuffer";
300 if(renderTaskContext->device->getType() == GraphicsDeviceType::WebGPU){
301 useArrayObjectBuffer = true; // Default on for WebGPU
302 }
303 if (Variable* var = context->variables->get(arrayObjectBufferKey); !var->isEmpty()) {
304 useArrayObjectBuffer = var->getBool();
305 }
306 else {
307 context->variables->set(arrayObjectBufferKey, useArrayObjectBuffer);
308 }
309 if(useArrayObjectBuffer && renderTaskContext->device->getType() != GraphicsDeviceType::WebGPU){
310 LOG_WARNING(logger, "Only WebGPU supports renderer.arrayObjectBuffer. Base instance support lacking in other backends.");
311 context->variables->set(arrayObjectBufferKey, false);
312 useArrayObjectBuffer = false;
313 }
314
315 // Init list object buffer if requested
316 bool useListObjectBuffer = false;
317 const StringView listObjectBufferKey = "renderer.listObjectBuffer";
318 if (Variable* var = context->variables->get(listObjectBufferKey); !var->isEmpty()) {
319 useListObjectBuffer = var->getBool();
320 }
321 else {
322 context->variables->set(listObjectBufferKey, useListObjectBuffer);
323 }
324 if(useArrayObjectBuffer) useListObjectBuffer = false; // Don't use both array and list object buffer
325 if (useListObjectBuffer && caps->getDeviceCapabilities().ConstantBufferRange) {
326 listObjectBuffer.stride = std::max(uint32_t(sizeof(ObjectBuffer)), uint32_t(caps->getDeviceCapabilities().ConstantBufferOffsetAlignment));
327 }
328 else {
329 listObjectBuffer.stride = 0;
330 }
331 listObjectBuffer.fill = 0;
332
333 renderList.clear();
334 generateItems(context, renderList.batch, renderer, context->renderSystem, context->meshSystem);
335
336 for (auto & staticModel : context->staticModelSystem->pool) {
337 if (!staticModel.model) continue;
338
339 auto renderSystem = context->staticModelSystem->getRenderSystem(&staticModel);
340 auto meshSystem = context->staticModelSystem->getMeshSystem(&staticModel);
341
342 if (!renderSystem || !renderSystem->pool.size()) continue;
343
344 auto batch = context->staticModelSystem->getRenderBatch(&staticModel);
345
346 if (batch->generation != renderSystem->getGeneration()) {
347 batch->clear();
348 auto missing = generateItems(context, *batch, renderer, renderSystem, meshSystem);
349 batch->missing = missing;
350 batch->generation = renderSystem->getGeneration();
351 }
352
353 renderList.batches.emplace_back(batch);
354 }
355
356 for (const SubMeshRenderComponent& renderComponent : context->subMeshRenderSystem->pool) {
357 if (!renderComponent.isVisible()) continue;
358
359 auto & renderData = context->subMeshRenderSystem->getData<SubMeshRenderData>(&renderComponent);
360
361 const MeshComponent* meshComponent = renderData.meshComponent.resolveComponent<MeshComponent>();
362 if (meshComponent == nullptr) {
363 LOG_ERROR_ONCE(logger, "No mesh component defined");
364 continue;
365 }
366
367 RenderMesh * renderMesh = renderer->getRenderResources().getRenderMesh(meshComponent->meshHandle);
368
369 if (!renderMesh) continue;
370
371 Mesh * mesh = meshComponent->meshHandle.resolve();
372 const uint32_t meshCount = mesh->getCount();
373
374 size_t subMeshBegin = 0;
375 size_t subMeshEnd = mesh->getSubMeshes().size();
376
377 if ((0 <= renderComponent.subMesh) && (static_cast<size_t>(renderComponent.subMesh) < subMeshEnd)) {
378 subMeshBegin = renderComponent.subMesh;
379 subMeshEnd = subMeshBegin + 1;
380 }
381
382 for (size_t m = subMeshBegin; m < subMeshEnd; ++m) {
383 auto & subMesh = mesh->getSubMeshes()[m];
384
385 if (subMesh.numIndexes && renderMesh->streamsLayout.numStreams) {
386 auto materialInstance = ((renderComponent.materials.size() > m) ? renderComponent.materials[m] : renderComponent.materials.front()).resolve();
387
388 if (!materialInstance) continue;
389
390 RenderItem& renderBlock = createRenderItem(context, renderList.batch, &renderData.localToWorld, &renderComponent);
391 renderBlock.lod = renderComponent.lod;
392 renderBlock.layer = renderComponent.layer;
393 renderBlock.flags |= renderComponent.castShadows() ? RenderItemFlags::CastShadows : RenderItemFlags::None;
394
395 renderBlock.cullingIndex = renderData.cullingIndex;
396
397 renderBlock.meshData = renderMesh;
398 if (subMesh.numIndexes == uint32_t(-1)) {
399 renderBlock.startIndex = 0;
400 renderBlock.numIndexes = meshCount;
401 }
402 else {
403 renderBlock.startIndex = subMesh.startIndex;
404 renderBlock.numIndexes = subMesh.numIndexes;
405 if (meshCount <= renderBlock.startIndex || meshCount < renderBlock.startIndex + renderBlock.numIndexes) {
406 LOG_ERROR_ONCE(logger, "SubMeshRenderComponent draw range is out of bounds");
407 continue;
408 }
409 }
410
411 renderBlock.primitiveType = subMesh.primitiveType;
412
413 if (mesh->isMeshFlagSet(MeshFlags::Skinned)) {
414 auto animationComponent = renderComponent.getComponent<AnimationComponent>();
415 const auto & animationData = context->animationSystem->getData(animationComponent);
416 renderBlock.poseData = animationData.pose.get();
417 }
418
419 renderBlock.flags |= !mesh->isCCW() ? RenderItemFlags::Clockwise : RenderItemFlags::None;
420 renderBlock.flags |= getMaterialFlags(materialInstance);
421 renderBlock.flags |= ((renderBlock.layer & RenderLayers::Sky) != RenderLayers::None) ? RenderItemFlags::Backdrop : RenderItemFlags::None;
422
423 renderBlock.materialInstance = materialInstance;
424
425 getTransparencyState(renderer->getRenderStates(), materialInstance, renderBlock);
426 renderBlock.drawOrder = materialInstance->options.drawOrder != 0 ? materialInstance->options.drawOrder : renderComponent.drawOrder;
427 }
428 }
429 }
430
431 for (const auto & renderComponent : context->instancedMeshRenderSystem->pool) {
432 if (!renderComponent.isVisible()) continue;
433
434 auto & renderData = context->instancedMeshRenderSystem->getData<InstancedMeshRenderData>(&renderComponent);
435
436 const MeshComponent * meshComponent = renderData.meshComponent.resolveComponent<MeshComponent>();
437
438 assert(meshComponent && "No mesh component defined");
439
440 RenderMesh * renderMesh = renderer->getRenderResources().getRenderMesh(meshComponent->meshHandle);
441 if (!renderMesh) continue;
442
443 RenderMesh * instanceRenderMesh = renderer->getRenderResources().getRenderMesh(renderComponent.instanceMesh);
444 if (!instanceRenderMesh) continue;
445
446 Mesh * mesh = meshComponent->meshHandle.resolve();
447 Mesh * instanceMesh = renderComponent.instanceMesh.resolve();
448
449 MaterialInstance * materialInstance = renderComponent.material.resolve();
450 if (!materialInstance) continue;
451
452 const uint32_t instanceCount = InstancedMeshRenderComponent::getRenderCount(renderComponent.startInstance, renderComponent.instanceCount, instanceMesh->getCount());
453 if (instanceCount == 0) {
454 continue;
455 }
456
457 RenderItem& renderBlock = createRenderItem(context, renderList.batch, &renderData.localToWorld, &renderComponent);
458 renderBlock.lod = renderComponent.lod;
459 renderBlock.layer = renderComponent.layer;
460 renderBlock.flags |= renderComponent.castShadows() ? RenderItemFlags::CastShadows : RenderItemFlags::None;
461 renderBlock.flags |= RenderItemFlags::Instanced;
462
463 renderBlock.cullingIndex = renderData.cullingIndex;
464
465 renderBlock.meshData = renderMesh;
466 renderBlock.instanceData = instanceRenderMesh;
467 renderBlock.startIndex = renderComponent.startIndex;
468 renderBlock.numIndexes = InstancedMeshRenderComponent::getRenderCount(renderComponent.startIndex, renderComponent.vertexCount, mesh->getCount());
469 renderBlock.startInstance = renderComponent.startInstance;
470 renderBlock.numInstances = instanceCount;
471 renderBlock.primitiveType = renderComponent.primitiveType != (PrimitiveType) - 1 ? renderComponent.primitiveType : mesh->primitiveType;
472
473 if (mesh->isMeshFlagSet(MeshFlags::Skinned)) {
474 auto animationComponent = renderComponent.getComponent<AnimationComponent>();
475 const auto & animationData = context->animationSystem->getData(animationComponent);
476 renderBlock.poseData = animationData.pose.get();
477 }
478
479 renderBlock.flags |= !mesh->isCCW() ? RenderItemFlags::Clockwise : RenderItemFlags::None;
480 renderBlock.flags |= getMaterialFlags(materialInstance);
481 renderBlock.flags |= ((renderBlock.layer & RenderLayers::Sky) != RenderLayers::None) ? RenderItemFlags::Backdrop : RenderItemFlags::None;
482
483 renderBlock.materialInstance = materialInstance;
484
485 getTransparencyState(renderer->getRenderStates(), materialInstance, renderBlock);
486 renderBlock.drawOrder = materialInstance->options.drawOrder != 0 ? materialInstance->options.drawOrder : renderComponent.drawOrder;
487 }
488
489 for (const SpriteBatch& batch : context->spriteRenderSystem->getSpriteBatches()) {
490 if (!batch.count) continue;
491
492 RenderMesh * renderMesh = renderer->getRenderResources().getRenderMesh(batch.mesh);
493
494 if (!renderMesh || !renderMesh->numVertexes) {
495 continue;
496 }
497
498 MaterialInstance * materialInstance = batch.material.resolve();
499
500 if (!materialInstance) continue;
501
502 RenderItem& renderBlock = createRenderItem(context, renderList.batch, &batch.transform, nullptr);
503 renderBlock.lod = batch.lod;
504 renderBlock.cullingIndex = NoCullingIndex;
505 renderBlock.depth = batch.depth;
506
507 renderBlock.flags |= batch.flags | RenderItemFlags::Sprite;
508 renderBlock.layer = RenderLayers::Overlay;
509
510 renderBlock.setBounds(&batch.bbox);
511
512 renderBlock.materialInstance = materialInstance;
513 renderBlock.blendState = (uint16_t)batch.blendMode;
514
515 renderBlock.meshData = renderMesh;
516 renderBlock.startIndex = static_cast<uint32_t>(batch.start);
517 renderBlock.numIndexes = static_cast<uint32_t>(batch.count);
518 renderBlock.primitiveType = batch.mesh->primitiveType;
519 }
520
521 if (context->variables->getOrAdd("renderer.showCoordSys", false)) {
522
523 static auto renderCallback = [](RenderTaskContext * taskContext, DrawContext * drawContext, const RenderItem * item)
524 {
525 RenderInstrumentationScope(taskContext->device->getImmediateContext(), SCOPE_RENDERING, "showCoordSysRender");
526 auto * renderer = taskContext->renderer;
527 const auto M = renderer->getProjectionMatrix(glm::frustum(-0.7f, 0.7f, -0.7f, 0.7f, 1.0f, 3.0f)) * glm::translate(glm::vec3(0,0,-2.0f)) * glm::mat4(glm::mat3(drawContext->cameraData->viewMatrix));
528 auto b = drawContext->cameraData->viewportOrigin.y + drawContext->cameraData->viewportSize.y;
529 auto * deviceContext = taskContext->device->getImmediateContext();
530 if(renderer->getDevice()->getType() == GraphicsDeviceType::OpenGLES30 ||
531 renderer->getDevice()->getType() == GraphicsDeviceType::OpenGL20)
532 deviceContext->setViewport(0, 0, 80, 80);
533 else
534 deviceContext->setViewport(0, b - 80, 80, 80);
535 drawCoordSys(taskContext, drawContext, item, M, true);
536 auto & o = drawContext->cameraData->viewportOrigin;
537 auto & s = drawContext->cameraData->viewportSize;
538 deviceContext->setViewport(o.x, o.y, s.x, s.y);
539 };
540
541 auto & item = renderList.createCustom(nullptr);
542 item.layer = RenderLayers::Annotations;
543 item.materialInstance = getDefaultMaterialInstance(context).resolve();
544 item.blendState = (uint16_t)BlendMode::None;
545 item.depthState = (uint16_t)DepthMode::Disabled;
546
547 item.flags |= RenderItemFlags::Custom2 | RenderItemFlags::DisableCulling;
548 item.callback = renderCallback;
549 }
550
551 if (context->variables->getOrAdd("renderer.showFrustums", false)) {
552
553 static auto renderCallback = [](RenderTaskContext * taskContext, DrawContext * drawContext, const RenderItem * item)
554 {
555 RenderInstrumentationScope(taskContext->device->getImmediateContext(), SCOPE_RENDERING, "showFrustumsRender");
556 const auto * camData = item->getCallbackData<CameraData>();
557 const auto M = drawContext->cameraData->viewProjection * camData->inverseViewMatrix * glm::inverse(camData->rawProjectionMatrix);
558 drawOneOneWireBox(taskContext, drawContext, item, M, static_cast<unsigned>(reinterpret_cast<size_t>(item->getCallbackData2<void>())));
559 };
560
561 size_t o = 0;
562 auto genFrustumItem = [&](CameraData* cd, size_t i)
563 {
564 auto & item = renderList.createCustom(nullptr);
565 item.layer = RenderLayers::Annotations;
566 item.materialInstance = getDefaultMaterialInstance(context).resolve();
567 item.blendState = (uint16_t)BlendMode::None;
568 item.depthState = (uint16_t)DepthMode::Default;
569
570 item.flags |= RenderItemFlags::Custom2 | RenderItemFlags::DisableCulling;
571 item.setCallbackData(cd);
572 item.setCallbackData2(reinterpret_cast<void*>(i));
573 item.callback = renderCallback;
574 o++;
575 };
576
577 auto* pipeService = context->services->getService<PipelineService>();
578 for (const auto* run : pipeService->runs) {
579 if (run->cameraData) {
580 genFrustumItem(run->cameraData, o);
581 }
582 }
583
584 for (const auto & cameraComp : context->cameraSystem->pool) {
585 if ((cameraComp.flags & CameraFlags::EnableRender) != 0) {
586 auto & camData = context->cameraSystem->getData(&cameraComp);
587 genFrustumItem(&camData, o);
588 }
589 }
590 for (const auto & lightComp : context->lightSystem->pool) {
591 auto & lightData = context->lightSystem->getData(&lightComp);
592 if (lightData.castShadows) {
593 for (unsigned i = 0; i < lightData.numViewports; i++) {
594 genFrustumItem(&lightData.lightCameraData[i], i);
595 }
596 }
597 }
598 }
599
600 for (auto & extension : renderer->getExtensions()) {
601 extension->generateCommands(renderTaskContext, &renderList);
602 }
603
604 // Update list object buffer if active
605 if (listObjectBuffer.isInUse()) {
606
607 if (2 * std::max(minObjectBufferCapacity, listObjectBuffer.fill) < listObjectBuffer.cpuCapacity) {
608 listObjectBuffer.cpuCapacity = listObjectBuffer.cpuCapacity / 2;
609 listObjectBuffer.cpu.resize(size_t(listObjectBuffer.stride)* listObjectBuffer.cpuCapacity);
610 }
611
612 if (listObjectBuffer.gpuCapacity != listObjectBuffer.cpuCapacity) {
613
614 if (listObjectBuffer.gpuCapacity == 0) {
615 LOG_DEBUG(logger, "Setting up list object buffer GPU storage");
616 }
617
618 listObjectBuffer.gpuCapacity = listObjectBuffer.cpuCapacity;
619
620 IBuffers* buffers = renderTaskContext->device->getBuffers();
621
622 if (HandleIsValid(listObjectBuffer.gpu)) {
623 buffers->releaseBuffer(listObjectBuffer.gpu);
624 listObjectBuffer.gpu = Cogs::BufferHandle::NoHandle;
625 }
626
627 listObjectBuffer.gpu = buffers->loadBuffer(nullptr,
628 size_t(listObjectBuffer.stride) * listObjectBuffer.gpuCapacity,
632 buffers->annotate(listObjectBuffer.gpu, "ListObjectBuffer");
633
634 }
635
636 if (listObjectBuffer.fill) {
637 IContext* immediateContext = renderTaskContext->device->getImmediateContext();
638 immediateContext->updateBuffer(listObjectBuffer.gpu,
639 listObjectBuffer.cpu.data(),
640 size_t(listObjectBuffer.stride) * listObjectBuffer.fill);
641 }
642
643 renderList.listObjectBuffer = &listObjectBuffer;
644 }
645 else if (HandleIsValid(listObjectBuffer.gpu)) {
646
647 IBuffers* buffers = renderTaskContext->device->getBuffers();
648 buffers->releaseBuffer(listObjectBuffer.gpu);
649 listObjectBuffer.gpu = Cogs::BufferHandle::NoHandle;
650 listObjectBuffer.gpuCapacity = 0;
651
652 listObjectBuffer.cpu.clear();
653 listObjectBuffer.cpuCapacity = 0;
654
655 LOG_DEBUG(logger, "Released list object buffer GPU storage");
656 }
657
658 renderList.clipShapeCache = &clipShapeCache;
659}
static uint32_t getRenderCount(uint32_t startIndex, uint32_t instanceCount, uint32_t meshCount)
Get number of instanced Meshes to render.
Log implementation class.
Definition: LogManager.h:140
Contains the Engine, Renderer, resource managers and other systems needed to run Cogs....
@ InvertedCube
Clip the inside of a cube.
@ None
No clipping at all.
@ Cube
Clip the outside of a cube,.
bool HandleIsValid(const ResourceHandle_t< T > &handle)
Check if the given resource is valid, that is not equal to NoHandle or InvalidHandle.
@ EnableRender
Renderable.
@ Blend
Render with regular alpha blending.
@ None
No blending enabled for opaque shapes, defaults to Blend for transparent shapes.
@ Default
Default, depth test & write enabled.
@ Disabled
Depth test/write disabled.
constexpr Log getLogger(const char(&name)[LEN]) noexcept
Definition: LogManager.h:181
@ OpenGLES30
Graphics device using the OpenGLES 3.0 API.
@ OpenGL20
Graphics device using OpenGL, supporting at least OpenGL 2.0.
@ WebGPU
Graphics device using the WebGPU API Backend.
PrimitiveType
Primitive types for interpreting vertex data sent to the graphics pipeline.
Definition: Common.h:112
@ Write
The buffer can be mapped and written to by the CPU after creation.
Definition: Flags.h:50
@ ConstantBuffer
The buffer can be bound as input to effects as a constant buffer.
Definition: Flags.h:72
static ComponentHandle Empty()
Returns an empty, invalid handle. Will evaluate to false if tested against using operator bool().
Definition: Component.h:119
EMaterialFlags
Material flags.
Definition: Material.h:41
@ OverrideAlpha
Override alpha of any inheriting materials.
Definition: Material.h:54
@ CustomBucket
Items with this flag should be put in Custom rendering buckets.
Definition: Material.h:64
MaterialInstanceHandle masterInstance
Master material instance overriding properties in this instance if override is enabled.
@ Instanced
Mesh contains instance data.
Definition: Mesh.h:70
ResourceType * resolve() const
Resolve the handle, returning a pointer to the actual resource.
static const Handle_t NoHandle
Represents a handle to nothing.
Definition: Common.h:78
@ Dynamic
Buffer will be loaded and modified with some frequency.
Definition: Flags.h:30