Cogs.Core
Renderer.cpp
1#include "Renderer.h"
2
3#include "Foundation/Logging/Logger.h"
4
5#include "Context.h"
6#include "MemoryContext.h"
7#include "Types.h"
8
9#include "RenderPipelineManager.h"
10#include "RenderStateUpdater.h"
11#include "RenderTarget.h"
12
13#include "CustomRenderer/BoundsRenderer.h"
14#include "CustomRenderer/DebugGeometryRenderers.h"
15
16#include "Rendering/Factory.h"
17#include "Rendering/ICapabilities.h"
18#include "Rendering/IContext.h"
19#include "Rendering/IGraphicsDevice.h"
20#include "Rendering/ITextures.h"
21#include "Rendering/IRenderTargets.h"
22
23#include "Resources/ResourceStore.h"
24#include "Resources/Texture.h"
25#include "Services/Variables.h"
26#include "Systems/Core/CameraSystem.h"
27#include "Systems/Core/EnvironmentSystem.h"
28#include "Systems/Core/LightSystem.h"
29#include "Utilities/Parsing.h"
30
31#include "InspectorGui/InspectorGuiRenderer.h"
32
33#include <glm/gtc/color_space.hpp>
34
35namespace {
36 using namespace Cogs::Core;
38
39 void addLights(std::vector<const LightComponent*>& dst, size_t& freeSlots, uint32_t& srcCount, const std::vector<const LightComponent*>& src)
40 {
41 srcCount = static_cast<uint32_t>(std::min(freeSlots, src.size()));
42 freeSlots -= srcCount;
43
44 for (size_t i = 0; i < srcCount; i++) {
45 dst.push_back(src[i]);
46 }
47 }
48
49 void buildSortedListOfActiveLights(Context* context, ActiveLights& activeLights, const size_t maxLights)
50 {
51 LightSystem& lightSystem = *context->lightSystem;
52
53 // Bucket sort active lights
54 std::vector<const LightComponent*> directionalShadowLights;
55 std::vector<const LightComponent*> pointShadowLights;
56 std::vector<const LightComponent*> directionalLights;
57 std::vector<const LightComponent*> pointLights;
58 const bool shadowsEnabled = context->variables->get("renderer.shadowsEnabled", false);
59 for (const LightComponent& light : lightSystem.pool) {
60
61 if (!light.enabled) continue;
62
63 if (shadowsEnabled && light.castShadows) {
64 if (light.lightType == LightType::Directional) {
65 directionalShadowLights.push_back(&light);
66 }
67 else if (light.lightType == LightType::Point) {
68 pointShadowLights.push_back(&light);
69 }
70 }
71 else {
72 if (light.lightType == LightType::Directional) {
73 directionalLights.push_back(&light);
74 }
75 else if (light.lightType == LightType::Point) {
76 pointLights.push_back(&light);
77 }
78 }
79 }
80
81 size_t numLightsTotal = directionalShadowLights.size() + directionalLights.size() + pointShadowLights.size() + pointLights.size();
82 if (maxLights < numLightsTotal) {
83 LOG_WARNING_ONCE(logger, "More active lights (=%zu) than supported (=%zu)", numLightsTotal, maxLights);
84 }
85
86 activeLights.lights.clear();
87 size_t freeLightSlots = maxLights;
88 addLights(activeLights.lights, freeLightSlots, activeLights.numDirectionalShadowLights, directionalShadowLights);
89 addLights(activeLights.lights, freeLightSlots, activeLights.numDirectionalLights, directionalLights);
90 addLights(activeLights.lights, freeLightSlots, activeLights.numPointShadowLights, pointShadowLights);
91 addLights(activeLights.lights, freeLightSlots, activeLights.numPointLights, pointLights);
92
93 assert(activeLights.lights.size() <= maxLights);
94 }
95
96}
97
98namespace Cogs
99{
100 namespace Core
101 {
103 {
104 BoundsRenderer boundsRenderer;
105 DebugGeometryRenderer debugGeometryRenderer;
106 ImguiRenderer imguiRenderer;
107 InspectorGuiRenderer engineInspectorGuiRenderer;
108 };
109
110 // Setup default render context content.
111 RenderTaskContext getRenderTaskContext(Renderer * renderer)
112 {
113 RenderTaskContext renderContext = {};
114
115 renderContext.context = renderer->context;
116 renderContext.renderer = renderer;
117 renderContext.device = renderer->device;
118 renderContext.resources = &renderer->resources;
119 renderContext.states = &renderer->renderStates;
120 renderContext.engineBuffers = &renderer->engineBuffers;
121 renderContext.defaultRenderTarget = renderer->defaultTarget;
122
123 return renderContext;
124 }
125
126 DrawContext getDrawContext(RenderTaskContext * renderContext)
127 {
128 DrawContext drawContext = {};
129
130 drawContext.context = renderContext->context;
131 drawContext.renderer = renderContext->renderer;
132 drawContext.device = renderContext->device;
133 drawContext.deviceContext = renderContext->device->getImmediateContext();
134 drawContext.cameraData = renderContext->cameraData;
135 drawContext.renderTarget = renderContext->defaultRenderTarget;
136 drawContext.engineBuffers = renderContext->engineBuffers;
137 drawContext.taskContext = renderContext;
138 drawContext.permutationIndex = 0;
139
140 return drawContext;
141 }
142 }
143}
144
145Cogs::Core::Renderer::Renderer(Context * context) :
146 context(context),
147 resources(context),
148 enginePermutations(context),
149 effectBindings(context->memory.get()),
150 renderers(std::make_unique<Renderers>()),
151 pipelineManager(std::make_unique<RenderPipelineManager>())
152{
153 updateEffectFlags();
154}
155
156Cogs::Core::Renderer::~Renderer()
157{
158}
159
160void Cogs::Core::Renderer::initialize(IGraphicsDevice * device)
161{
162 if (!device) {
163 LOG_FATAL(logger, "Cannot initialize renderer with nullptr device.");
164 return;
165 }
166
167 Instrumentation::initializeGpu(context);
168 Instrumentation::beginGpuThread(device->getImmediateContext());
169
170 this->device = device;
171
172 auto backColor = context->variables->get("renderer.backgroundColor", glm::vec4(0.5, 0.5, 0.5, 1));
173 setBackgroundColor(backColor);
174
175 {
176 const GraphicsDeviceCapabilities& device_capabilities = device->getCapabilities()->getDeviceCapabilities();
177
178 context->variables->set("renderer.DedicatedVideoMemoryMB", (int)(device_capabilities.DedicatedVideoMemory/(1024*1024)));
179 context->variables->set("renderer.DedicatedSystemMemoryMB", (int)(device_capabilities.DedicatedSystemMemory/(1024*1024)));
180 context->variables->set("renderer.SharedSystemMemoryMB", (int)(device_capabilities.SharedSystemMemory/(1024*1024)));
181 }
182
183 enginePermutations.initialize(context);
184 renderStates.initialize(device);
185
186 resources.initialize(context, this);
187
188 defaultTarget = resources.createRenderTarget();
189
190 initializeEngineBuffers(device->getBuffers(), device->getCapabilities(), engineBuffers);
191
192 renderContext = getRenderTaskContext(this);
193 pipelineManager->initialize(&renderContext);
194
195 renderers->boundsRenderer.initialize(this, device);
196 renderers->debugGeometryRenderer.initialize(this, device);
197 renderers->imguiRenderer.initialize(context);
198 renderers->engineInspectorGuiRenderer.initialize(context, this);
199 context->variables->set("renderer.device", device->getIdentifier());
200
201 settings.anisotropicFiltering = context->variables->get("renderer.anisotropicFiltering");
202
203 for (auto & extension : extensions) {
204 extension->initialize(context, device);
205 }
206}
207
209{
210 renderers->debugGeometryRenderer.cleanup();
211
212 if (defaultTarget) {
213 resources.releaseResource(defaultTarget);
214 }
215
216 pipelineManager->cleanup(&renderContext);
217
218 renderers->engineInspectorGuiRenderer.cleanup(context, this);
219 renderers->imguiRenderer.cleanup();
220
221 if (context && context->variables->get("renderer.reportLeaks", false)) {
222 resources.cleanup(context);
223 }
224
225 renderStates.cleanup();
226}
227
229{
230 // Since we do not control the main thread we need to set the GPU profiling context every time
231 // we begin rendering.
232 Instrumentation::beginGpuThread(device->getImmediateContext());
233
234 auto renderTargets = device->getRenderTargets();
235 auto textures = device->getTextures();
236
237 bool reverseDepth = context->variables->get("renderer.reverseDepth", false);
238 if(renderStates.reverseDepth != reverseDepth){
239 renderStates.reverseDepth = reverseDepth;
240 pipelineManager->dirty = true;
241
243 if (reverseDepth) defaultState.depthFunction = DepthStencilState::Greater;
244 renderStates.defaultDepthStencilStateHandle = renderTargets->loadDepthStencilState(defaultState);
245 renderStates.commonDepthStates[(int)DepthMode::Default] = renderStates.defaultDepthStencilStateHandle;
246 renderStates.setupDepthStates(device);
247
250 renderStates.leqDepthStencilStateHandle = renderTargets->loadDepthStencilState(leqState);
251
252 SamplerState comparisonSamplerState{};
253 comparisonSamplerState.addressModeS = SamplerState::Border;
254 comparisonSamplerState.addressModeT = SamplerState::Border;
255 comparisonSamplerState.addressModeW = SamplerState::Border;
256 if(reverseDepth) comparisonSamplerState.comparisonFunction = SamplerState::GreaterEqual;
257 else comparisonSamplerState.comparisonFunction = SamplerState::LessEqual;
258 comparisonSamplerState.filter = SamplerState::ComparisonMinMagMipLinear;
259 for (unsigned i = 0; i < 4; i++) {
260 if(reverseDepth) comparisonSamplerState.borderColor[i] = 0.f;
261 else comparisonSamplerState.borderColor[i] = 1.f;
262 }
263
264 renderStates.shadowSampler = textures->loadSamplerState(comparisonSamplerState);
265 }
266
267 updateEffectFlags();
268 updateSettings();
269
270 renderContext.cameraData = &context->cameraSystem->getMainCameraData();
271
272 defaultTarget->setName("Cogs.BackBuffer");
273 defaultTarget->setOverride();
274 defaultTarget->renderTargetHandle = RenderTargetHandle::NoHandle;
275 defaultTarget->depthTargetHandle = DepthStencilHandle::NoHandle;
276 defaultTarget->width = static_cast<int>(renderContext.cameraData->viewportSize.x);
277 defaultTarget->height = static_cast<int>(renderContext.cameraData->viewportSize.y);
278 defaultTarget->samples = device->getSettings().numSamples;
279 defaultTarget->clearColors = { backgroundColor };
280
281 const bool reloadEffects = context->variables->get("renderer.reloadEffects", false);
282
283 if (reloadEffects) {
284 effectCache.reload(&renderContext);
285 context->variables->set("renderer.reloadEffects", false);
286 }
287
288 pipelineManager->setupPipeline(&renderContext);
289
290 buildSortedListOfActiveLights(context, activeLights, maxLights);
291
292 {
293 const auto eventContext = getDrawContext(&renderContext);
294
295 emitEvent(RenderingEvent::PreRender, &eventContext);
296 }
297
298 {
299 int samples = context->variables->get("renderer.samples", 1);
300 context->variables->set("impl.multiSample", samples > 1);
301 }
302
303 pipelineManager->initializeFrame(&renderContext);
304 pipelineManager->applyPipeline(&renderContext);
305
306 device->getImmediateContext()->setRenderTarget(defaultTarget->renderTargetHandle, defaultTarget->depthTargetHandle);
307
308 if (mode == RenderMode::Box) {
309 renderers->boundsRenderer.renderBounds(this, context, *pipelineManager->getRenderList());
310 }
311
312 {
313 const auto eventContext = getDrawContext(&renderContext);
314
315 emitEvent(RenderingEvent::RenderGui, &eventContext);
316 }
317
318 renderers->engineInspectorGuiRenderer.beginRender(context, this);
319 renderers->engineInspectorGuiRenderer.render(context, this);
320
321 if (context->callbacks.postRenderCallback) {
322 context->callbacks.postRenderCallback(context);
323 }
324
325 renderers->engineInspectorGuiRenderer.endRender(context, this);
326
327 {
328 const DrawContext eventContext = getDrawContext(&renderContext);
329
330 context->cameraSystem->postRender(context);
331 emitEvent(RenderingEvent::PostRender, &eventContext);
332 }
333 pipelineManager->cleanupFrame(&renderContext);
334}
335
336void Cogs::Core::Renderer::setBackgroundColor(const glm::vec4 & backgroundColor)
337{
338 // Background color is expected to be in sRGB color space, renderer works in linear space.
339 this->backgroundColor = glm::vec4(glm::convertSRGBToLinear(glm::vec3(backgroundColor)),
340 backgroundColor.a);
341}
342
343void Cogs::Core::Renderer::updateEffectFlags()
344{
345 effectFlags = EffectFlags::None;
346 if (context->variables->get("effects.logShaderInfo", false)) {
347 effectFlags = static_cast<EffectFlags::EEffectFlags>(effectFlags | EffectFlags::LogShaderInfo);
348 }
349 if (context->variables->get("effects.logShaderSource", false)) {
350 effectFlags = static_cast<EffectFlags::EEffectFlags>(effectFlags | EffectFlags::LogShaderSource);
351 }
352}
353
354
355void Cogs::Core::Renderer::updateSettings()
356{
357
358 if(context->variables->exist("renderer.enableDeferred")){
359 static uint32_t t = 0;
360 if(t<6){
361 t++;
362 LOG_WARNING(logger, "Variable \"renderer.enableDeferred\" deprecated. Use \"renderer.pipeline\": \"Pipelines/Deferred.pipeline\".");
363 }
364 if(context->variables->get("renderer.enableDeferred", false))
365 context->variables->set("renderer.pipeline", "Pipelines/Deferred.pipeline");
366 }
367
368 switch (StringView(context->variables->get("renderer.transparencyAlgorithm", "Regular")).hash())
369 {
370 case Cogs::hash("OIT"): settings.transparencyAlgorithm = RenderSettings::TransparencyAlgorithm::OIT; break;
371 default: settings.transparencyAlgorithm = RenderSettings::TransparencyAlgorithm::Regular; break;
372 }
373
374 switch (StringView(context->variables->get("renderer.blendKernel", "Alpha")).hash())
375 {
376 case Cogs::hash("DepthWeighted"): settings.blendKernel = RenderSettings::BlendKernel::DepthWeighted; break;
377 case Cogs::hash("Max"): settings.blendKernel = RenderSettings::BlendKernel::Max; break;
378 case Cogs::hash("Max2"): settings.blendKernel = RenderSettings::BlendKernel::Max2; break;
379 case Cogs::hash("Beers"): settings.blendKernel = RenderSettings::BlendKernel::Beers; break;
380 default: settings.blendKernel = RenderSettings::BlendKernel::Alpha; break;
381 }
382
383 settings.defaultRenderTargetClear = context->variables->get("renderer.backBuffer.clear.enable", true);
384
385 if (Variable* var = context->variables->get("renderer.backBuffer.sRGB"); var->isEmpty()) {
386 switch (context->device->getType()) {
388 settings.defaultRenderTargetExpectsSRGB = true;
389 break;
390 default:
391 settings.defaultRenderTargetExpectsSRGB = false;
392 break;
393 }
394 var->setBool(settings.defaultRenderTargetExpectsSRGB);
395 }
396 else {
397 settings.defaultRenderTargetExpectsSRGB = var->getBool();
398 }
399
400 {
401 Variable* var = context->variables->get("renderer.sRGBConversion");
402 if (var->isEmpty()) {
403 var->setValue("Exact");
404 }
405 switch (StringView(var->getCString()).hashLowercase()) {
406 case Cogs::hash("fast"):
407 settings.sRGBConversion = RenderSettings::SRGBConversion::Fast;
408 break;
409 case Cogs::hash("approx"):
410 settings.sRGBConversion = RenderSettings::SRGBConversion::Approx;
411 break;
412 case Cogs::hash("exact"):
413 settings.sRGBConversion = RenderSettings::SRGBConversion::Exact;
414 break;
415 default:
416 settings.sRGBConversion = RenderSettings::SRGBConversion::Exact;
417 break;
418 }
419 }
420 {
421 Variable* var = context->variables->get("renderer.tonemapper");
422 if (var->isEmpty()) {
423 var->setValue("Filmic");
424 }
425 switch (StringView(var->getCString()).hashLowercase()) {
426 case Cogs::hash("reinhard"):
427 settings.tonemapper = RenderSettings::Tonemapper::Reinhard;
428 break;
429 case Cogs::hash("filmic"):
430 settings.tonemapper = RenderSettings::Tonemapper::Filmic;
431 break;
432 case Cogs::hash("acesluminance"):
433 settings.tonemapper = RenderSettings::Tonemapper::ACESLuminance;
434 break;
435 case Cogs::hash("pbrneutral"):
436 settings.tonemapper = RenderSettings::Tonemapper::PBRNeutral;
437 break;
438 default:
439 settings.tonemapper = RenderSettings::Tonemapper::Filmic;
440 break;
441 }
442 }
443 settings.beersScaleFactor = context->variables->get("renderer.beers.scaleFactor", 1.f);
444
445 settings.ambientIntensity = context->variables->get("renderer.ambientLightIntensity", 0.f);
446 std::string acStr = context->variables->get("renderer.ambientLightColor", "1 1 1");
447 static std::string prev;
448
449 if (prev != acStr) {
450 auto acTokens = tokenize(acStr);
451 parseValues(glm::value_ptr(settings.ambientColor), acTokens, 3);
452
453 // Ambient color is expected to be in sRGB color space, renderer works in linear space.
454 settings.ambientColor = glm::convertSRGBToLinear(settings.ambientColor);
455 prev = acStr;
456 }
457}
458
459glm::mat4 Cogs::Core::Renderer::getProjectionMatrix(glm::mat4 projectionMatrix)
460{
461 if (!device) {
462 return projectionMatrix;
463 }
464
465 if(context->variables->get("renderer.reverseDepth", false)){
466 static glm::mat4 reverse(
467 1, 0, 0, 0,
468 0, 1, 0, 0,
469 0, 0, -1, 0,
470 0, 0, 0, 1
471 );
472 projectionMatrix = reverse * projectionMatrix;
473 }
474
475 switch (device->getType())
476 {
480 {
481 static glm::mat4 depthScale = glm::scale(glm::mat4(1.0f), glm::vec3(1, 1, 0.5f));
482 static glm::mat4 bias(
483 1, 0, 0, 0,
484 0, 1, 0, 0,
485 0, 0, 1, 0,
486 0, 0, 1, 1
487 );
488
489 glm::mat4 projection = depthScale * bias * projectionMatrix;
490
491 return projection;
492 }
494 {
495 static glm::mat4 depthScale = glm::scale(glm::mat4(1.0f), glm::vec3(1, -1, 0.5f));
496 static glm::mat4 bias(
497 1, 0, 0, 0,
498 0, 1, 0, 0,
499 0, 0, 1, 0,
500 0, 0, 1, 1
501 );
502
503 glm::mat4 projection = depthScale * bias * projectionMatrix;
504
505 return projection;
506 }
510 return projectionMatrix;
511 }
512 else{
513 static glm::mat4 depthScale = glm::scale(glm::mat4(1.0f), glm::vec3(1, 1, 0.5f));
514 static glm::mat4 bias(
515 1, 0, 0, 0,
516 0, 1, 0, 0,
517 0, 0, 1, 0,
518 0, 0, 1, 1
519 );
520
521 glm::mat4 projection = depthScale * bias * projectionMatrix;
522
523 return projection;
524 }
526 return projectionMatrix;
527
528 default:
529 LOG_WARNING(logger, "Unknown device type.");
530 return projectionMatrix;
531 }
532}
533glm::mat4 Cogs::Core::Renderer::getViewFromViewportMatrix(glm::mat4 inverseProjectionMatrix)
534{
535 if (!device) {
536 return inverseProjectionMatrix;
537 }
538 switch (device->getType())
539 {
543 {
544 glm::vec4 x = glm::vec4(0.1, 0.2, 0.3, 1.0);
545 glm::mat4 clipFromViewport (
546 2, 0, 0, 0,
547 0, -2, 0, 0,
548 0, 0, 1, 0,
549 -1, 1, 0, 1
550 );
551 return inverseProjectionMatrix * clipFromViewport;
552 }
554 {
555 // TODO: Verify this
556 return inverseProjectionMatrix;
557 }
561 glm::mat4 scale = glm::scale(glm::mat4(1.0), glm::vec3(2.0, 2.0, 2.0));
562 static glm::mat4 bias(
563 1, 0, 0, 0,
564 0, 1, 0, 0,
565 0, 0, 1, 0,
566 -1, -1, -1, 1
567 );
568 return inverseProjectionMatrix * bias * scale;
569 }
570 else {
571 glm::mat4 scale = glm::scale(glm::mat4(1.0), glm::vec3(2.0, 2.0, 1.0));
572 static glm::mat4 bias(
573 1, 0, 0, 0,
574 0, 1, 0, 0,
575 0, 0, 1, 0,
576 -1, -1, 0, 1
577 );
578 return inverseProjectionMatrix * bias * scale;
579 }
581 return inverseProjectionMatrix;
582
583 default:
584 LOG_WARNING(logger, "Unknown device type.");
585 return inverseProjectionMatrix;
586 }
587}
589{
590 if(context->variables->get("renderer.reverseDepth", false)) {
591 return 0.0f;
592 }
593 return 1.0f;
594}
596{
597 if(context->variables->get("renderer.reverseDepth", false)) {
598 return 1.0f;
599 }
601 return -1.0f;
602 }
603 else{
604 return 0.0f;
605 }
606}
607
609{
610 if (!device) return;
611
612 device->beginFrame();
613}
614
615void Cogs::Core::Renderer::endFrame(uint32_t syncInterval, Cogs::PresentFlags presentFlags)
616{
617 if (!device) return;
618
619 device->endFrame(syncInterval, presentFlags);
620}
621
623{
624 return &resources;
625}
626
628{
629 extensions.push_back(extension);
630
631 if (context) {
632 extension->initialize(context, device);
633 }
634}
635
637{
638 auto it = std::find(extensions.begin(), extensions.end(), extension);
639 assert(it != extensions.end() && "Unregistering unknown IRendererExtension");
640 if (it != extensions.end()) {
641 extensions.erase(it);
642 }
643}
644
645
646void Cogs::Core::Renderer::renderScreenshot(const ScreenshotSettings & settings, std::vector<uint8_t> & bytes, uint32_t * stride)
647{
648 auto deviceContext = device->getImmediateContext();
649 auto renderTargets = device->getRenderTargets();
650 auto textures = device->getTextures();
651 auto buffers = device->getBuffers();
652 auto format = TextureFormat::R8G8B8A8_UNORM_SRGB;
653
654 const size_t size = (size_t)settings.width * (size_t)settings.height * Cogs::getBlockSize(format);
655
656 auto readBuffer = buffers->loadBuffer(nullptr, size, Usage::Staging, AccessMode::Read, BindFlags::None);
657
658 Cogs::TextureHandle texture;
659 {
661 if(settings.numSamples > 1)
662 desc.target = ResourceDimensions::Texture2DMS;
663 else
664 desc.target = ResourceDimensions::Texture2D;
665 desc.width = settings.width;
666 desc.height = settings.height;
667 desc.format = format;
668 desc.samples = settings.numSamples;
669 desc.flags = TextureFlags::RenderTarget;
670 texture = textures->loadTexture(desc, nullptr);
671 }
672
673 auto renderTarget = renderTargets->createRenderTarget(&texture, 1);
674 auto depthStencilTarget = renderTargets->createDepthStencilTarget(renderTarget);
675
676 auto camera = context->cameraSystem->getMainCamera();
677 auto restoreViewport = camera->viewportSize;
678 camera->viewportSize = glm::vec2(settings.width, settings.height);
679 context->cameraSystem->update(context);
680
681 renderContext.cameraData = &context->cameraSystem->getMainCameraData();
682
683 pipelineManager->setupPipeline(&renderContext);
684
685 auto restoreRenderTargetHandle = defaultTarget->renderTargetHandle;
686 auto restoreDepthTargetHandle = defaultTarget->depthTargetHandle;
687 auto restoreWidth = defaultTarget->width;
688 auto restoreHeight = defaultTarget->height;
689 auto restoreSamples = defaultTarget->samples;
690 auto restoreColors = std::move(defaultTarget->clearColors);
691
692 defaultTarget->renderTargetHandle = renderTarget;
693 defaultTarget->depthTargetHandle = depthStencilTarget;
694 defaultTarget->width = settings.width;
695 defaultTarget->height = settings.height;
696 defaultTarget->samples = settings.numSamples;
697 defaultTarget->clearColors = { backgroundColor };
698
699 pipelineManager->initializeFrame(&renderContext);
700 pipelineManager->applyPipeline(&renderContext);
701 pipelineManager->cleanupFrame(&renderContext);
702
703 if (settings.numSamples > 1) {
704 auto resolveTexture = textures->loadTexture(nullptr, settings.width, settings.height, format, Cogs::TextureFlags::RenderTarget);
705 auto resolveRt = renderTargets->createRenderTarget(&resolveTexture, 1);
706 auto resolveDt = renderTargets->createDepthStencilTarget(resolveRt);
707
708 deviceContext->resolveResource(texture, resolveTexture);
709
710 deviceContext->setRenderTarget(resolveRt, resolveDt);
711
712 deviceContext->readColorBuffer(readBuffer, 0, 0, settings.width, settings.height, Framebuffer::Front);
713
714 renderTargets->releaseDepthStencilTarget(resolveDt);
715 renderTargets->releaseRenderTarget(resolveRt);
716 textures->releaseTexture(resolveTexture);
717 } else {
718 deviceContext->setRenderTarget(renderTarget, depthStencilTarget);
719
720 deviceContext->readColorBuffer(readBuffer, 0, 0, settings.width, settings.height, Framebuffer::Front);
721 }
722
723 {
724 MappedBuffer<uint8_t> data(deviceContext, readBuffer, MapMode::Read, size);
725
726 if (data) {
727 const size_t bufferSize = data.getStride() ? data.getStride() * settings.height : size;
728 bytes.assign(data.get(), data.get() + bufferSize);
729
730 if (stride) {
731 *stride = data.getStride();
732 }
733 }
734 }
735
736 defaultTarget->renderTargetHandle = restoreRenderTargetHandle;
737 defaultTarget->depthTargetHandle = restoreDepthTargetHandle;
738 defaultTarget->width = restoreWidth;
739 defaultTarget->height = restoreHeight;
740 defaultTarget->samples = restoreSamples;
741 defaultTarget->clearColors = std::move(restoreColors);
742
743 camera->viewportSize = restoreViewport;
744
745 buffers->releaseBuffer(readBuffer);
746 renderTargets->releaseDepthStencilTarget(depthStencilTarget);
747 renderTargets->releaseRenderTarget(renderTarget);
748 textures->releaseTexture(texture);
749}
750
751void Cogs::Core::Renderer::emitEvent(uint32_t eventId, const DrawContext * renderingContext)
752{
753 for (auto extension : extensions) {
754 extension->handleEvent(eventId, renderingContext);
755 }
756}
757
759{
760 const bool ditherEnabled = context->variables->get("renderer.ditherEnabled", false);
761 if(permutation->hasVariant("Dither"))
762 permutation->setVariant("Dither", ditherEnabled);
763
764 const bool reverseDepth = context->variables->get("renderer.reverseDepth", false);
765 if(permutation->hasVariant("ReverseDepth"))
766 permutation->setVariant("ReverseDepth", reverseDepth);
767
768 if(permutation->hasVariant("DepthNegativeOneToOne"))
769 permutation->setVariant("DepthNegativeOneToOne", device->getCapabilities()->getDeviceCapabilities().DepthNegativeOneToOne);
770
771 if (!permutation->hasBuiltins()) return;
772 if (!permutation->isShadingPass() || permutation->isDepthOnly()) return;
773
774 if (auto ec = context->environmentSystem->getGlobalEnvironment(); ec != nullptr) {
775 permutation->setVariant("SubseaSupport", ec->subseaSupport);
776 if(ec->imageBasedLighting) {
777 if(ec->PBR) {
778 permutation->setVariant("ImageBasedLighting", "PBR");
779 } else {
780 permutation->setVariant("ImageBasedLighting", "Phong");
781 }
782 } else {
783 permutation->setVariant("ImageBasedLighting", "Disabled");
784 }
785 }
786
787
788 const bool shadowsEnabled = (activeLights.numDirectionalShadowLights != 0) || (activeLights.numPointShadowLights != 0);
789 permutation->setVariant("NumDirectionalShadowLights", static_cast<int>(activeLights.numDirectionalShadowLights));
790 permutation->setVariant("NumPointShadowLights", static_cast<int>(activeLights.numPointShadowLights));
791 permutation->setVariant("NumDirectionalLights", static_cast<int>(activeLights.numDirectionalLights));
792 permutation->setVariant("NumPointLights", static_cast<int>(activeLights.numPointLights));
793 permutation->setVariant("ShadowsEnabled", shadowsEnabled);
794 if (shadowsEnabled) {
795 const Cogs::Core::SoftShadows softShadows = parseEnum<SoftShadows>(context->variables->get("shadows.softShadows", "Default"));
796 permutation->setVariant("SoftShadows", (int)softShadows);
797 }
798
799 if(permutation->hasVariant("sRGBConversion")) {
800 switch (settings.sRGBConversion) {
801 case RenderSettings::SRGBConversion::Fast:
802 permutation->setVariant("sRGBConversion", "Fast");
803 break;
804 case RenderSettings::SRGBConversion::Approx:
805 permutation->setVariant("sRGBConversion", "Approx");
806 break;
807 case RenderSettings::SRGBConversion::Exact:
808 permutation->setVariant("sRGBConversion", "Exact");
809 break;
810 default:
811 assert(false && "Invalid enum");
812 break;
813 }
814 }
815
816 if (permutation->hasVariant("Tonemapper")) {
817 switch (settings.tonemapper) {
818 case RenderSettings::Tonemapper::Reinhard:
819 permutation->setVariant("Tonemapper", "Reinhard");
820 break;
821 case RenderSettings::Tonemapper::Filmic:
822 permutation->setVariant("Tonemapper", "Filmic");
823 break;
824 case RenderSettings::Tonemapper::ACESLuminance:
825 permutation->setVariant("Tonemapper", "ACESLuminance");
826 break;
827 case RenderSettings::Tonemapper::PBRNeutral:
828 permutation->setVariant("Tonemapper", "PBRNeutral");
829 break;
830 default:
831 assert(false && "Invalid enum");
832 break;
833 }
834 }
835
836}
837
838Cogs::Core::ImguiRenderer* Cogs::Core::Renderer::getGuiRenderer() {
839 return &renderers->imguiRenderer;
840}
841
842Cogs::Core::InspectorGuiRenderer * Cogs::Core::Renderer::getEngineInspectorGuiRenderer()
843{
844 return &renderers->engineInspectorGuiRenderer;
845}
ComponentPool< ComponentType > pool
Pool of components managed by the system.
A Context instance contains all the services, systems and runtime components needed to use Cogs.
Definition: Context.h:83
std::unique_ptr< class Variables > variables
Variables service instance.
Definition: Context.h:180
Interface to the render resources.
Definition: IRenderer.h:64
Defines an extension to the renderer, capable of doing custom rendering.
Definition: IRenderer.h:123
Defines a single light source and its behavior.
LightType lightType
The type of light.
bool castShadows
If this light should cast shadows.
bool enabled
If the light is enabled.
Holds all LightComponent instances in the system.
Definition: LightSystem.h:78
Core renderer system.
Definition: Renderer.h:28
void updatePermutation(EnginePermutation *permutation) override
Updates the EnginePermutation.
Definition: Renderer.cpp:758
float getNearDepth() override
Get adjusted near plane depth.
Definition: Renderer.cpp:595
IRenderResources * getResources() override
Get the render resources interface.
Definition: Renderer.cpp:622
void registerExtension(IRendererExtension *extension) override
Registers the given extension with the renderer. Doesn not take ownership of pointer.
Definition: Renderer.cpp:627
void setBackgroundColor(const glm::vec4 &backgroundColor) override
Set the background color applied to the output surface before rendering.
Definition: Renderer.cpp:336
void renderScreenshot(const ScreenshotSettings &settings, std::vector< uint8_t > &bytes, uint32_t *stride=nullptr) override
Render screenshot.
Definition: Renderer.cpp:646
glm::mat4 getViewFromViewportMatrix(glm::mat4 inverseProjectionMatrix) override
Get an adjusted inverse projection matrix mainly used in post processing.
Definition: Renderer.cpp:533
void emitEvent(uint32_t eventId, const DrawContext *renderingContext)
Emits the given render event to all registered extensions.
Definition: Renderer.cpp:751
void endFrame(uint32_t syncInterval=0, Cogs::PresentFlags presentFlags=PresentFlags::None) override
Signals the end of the current frame.
Definition: Renderer.cpp:615
void unregisterExtension(IRendererExtension *extension) override
Unregister an extension with the renderer.
Definition: Renderer.cpp:636
void cleanup() override
Cleanup the renderer, releasing all resources held.
Definition: Renderer.cpp:208
float getClearDepth() override
Get adjusted clear depth used to render.
Definition: Renderer.cpp:588
glm::mat4 getProjectionMatrix(const glm::mat4 projectionMatrix) override
Get an adjusted projection matrix used to render.
Definition: Renderer.cpp:459
void render() override
Kick off the actual rendering, allowing the renderer to produce its output.
Definition: Renderer.cpp:228
void beginFrame() override
Signals the beginning of a new frame.
Definition: Renderer.cpp:608
Represents a graphics device used to manage graphics resources and issue drawing commands.
virtual ITextures * getTextures()=0
Get a pointer to the texture management interface.
virtual ICapabilities * getCapabilities()=0
Get a pointer to the capability management interface used to query the graphics device capability fla...
virtual IContext * getImmediateContext()=0
Get a pointer to the immediate context used to issue commands to the graphics device.
virtual void beginFrame()=0
Signal the beginning of a new frame to the graphics device.
virtual IBuffers * getBuffers()=0
Get a pointer to the buffer management interface.
virtual std::string getIdentifier() const
Get the graphics device identifier.
virtual GraphicsDeviceType getType() const
Get the type of the graphics device.
virtual void endFrame(uint32_t syncInterval=0, PresentFlags presentFlags=PresentFlags::None)=0
Signal the end of a frame to the graphics device.
virtual IRenderTargets * getRenderTargets()=0
Get a pointer to the render target management interface.
Log implementation class.
Definition: LogManager.h:140
Provides a weakly referenced view over the contents of a string.
Definition: StringView.h:24
size_t hashLowercase(size_t hashValue=Cogs::hash()) const noexcept
Get the hash code of the string converted to lowercase.
Definition: StringView.cpp:13
constexpr size_t hash() const noexcept
Get the hash code of the string.
Definition: StringView.h:200
Contains the Engine, Renderer, resource managers and other systems needed to run Cogs....
@ Box
Bounding-box rendering over regular rendering.
@ Default
Default, depth test & write enabled.
constexpr Log getLogger(const char(&name)[LEN]) noexcept
Definition: LogManager.h:181
Contains all Cogs related functionality.
Definition: FieldSetter.h:23
@ Direct3D12
Graphics device using the Direct3D 12 API.
@ OpenGLES30
Graphics device using the OpenGLES 3.0 API.
@ Vulkan
Graphics device using the Vulkan API.
@ Direct3D11
Graphics device using the Direct3D 11 API.
@ OpenGL20
Graphics device using OpenGL, supporting at least OpenGL 2.0.
@ Null
Null device that implements no rendering functionality.
@ WebGPU
Graphics device using the WebGPU API Backend.
constexpr size_t hash() noexcept
Simple getter function that returns the initial value for fnv1a hashing.
Definition: HashFunctions.h:62
@ Front
Front buffer.
PresentFlags
Flags controlling presentation.
Definition: Common.h:166
STL namespace.
@ Read
The buffer can be mapped and read from by the CPU after creation.
Definition: Flags.h:48
@ None
The buffer will not be bound to the graphics pipeline. Suitable for staging resources.
Definition: Flags.h:66
Active lights settings.
Definition: IRenderer.h:47
Render settings variables.
@ RenderGui
Rendering GUI elements.
Definition: IRenderer.h:99
@ PostRender
Rendering has finished for a given rendering context.
Definition: IRenderer.h:101
@ PreRender
Pre rendering happening for a given rendering context.
Definition: IRenderer.h:93
Screenshot render settings.
Definition: IRenderer.h:28
Runtime control variable.
Definition: Variables.h:27
Encapsulates state for depth buffer usage and stencil buffer usage in a state object.
@ GreaterOrEqual
Greater or equal depth.
@ LessOrEqual
Less or equal depth.
DepthFunction depthFunction
The depth function to use for depth testing.
static DepthStencilState DefaultState()
Constructs a depth stencil state object initialized with the default values.
EEffectFlags
Effect source flags.
Definition: IEffects.h:20
@ LogShaderSource
Log the contents of the shader on error.
Definition: IEffects.h:34
@ LogShaderInfo
Log detailed info about shaders.
Definition: IEffects.h:32
Contains device capabilities.
Definition: ICapabilities.h:67
bool DepthNegativeOneToOne
If true, min z depth=-1 otherwise it is min z depth = 0 (max z depth = 1).
int numSamples
Number of samples to use for back buffer MSAA.
static const Handle_t NoHandle
Represents a handle to nothing.
Definition: Common.h:78
virtual const GraphicsDeviceCapabilities & getDeviceCapabilities() const
Gets the device capabilities in a structure.
virtual void setRenderTarget(const RenderTargetHandle handle, const DepthStencilHandle depthStencilHandle)=0
Sets the current render target and an associated depth stencil target.
Provides RAII style mapping of a buffer resource.
Definition: IBuffers.h:160
Encapsulates state for texture sampling in a state object.
Definition: SamplerState.h:12
AddressMode addressModeS
Specifies the addressing mode along the S axis in texture coordinate space.
Definition: SamplerState.h:63
@ Border
Texture color is set to the border color when outside [0, 1] range.
Definition: SamplerState.h:23
@ ComparisonMinMagMipLinear
Comparison filter for depth sample comparisons using linear interpolation sampling.
Definition: SamplerState.h:40
@ RenderTarget
The texture can be used as a render target and drawn into.
Definition: Flags.h:120
@ Staging
Definition: Flags.h:33