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
248 SamplerState comparisonSamplerState{};
249 comparisonSamplerState.addressModeS = SamplerState::Border;
250 comparisonSamplerState.addressModeT = SamplerState::Border;
251 comparisonSamplerState.addressModeW = SamplerState::Border;
252 if(reverseDepth) comparisonSamplerState.comparisonFunction = SamplerState::GreaterEqual;
253 else comparisonSamplerState.comparisonFunction = SamplerState::LessEqual;
254 comparisonSamplerState.filter = SamplerState::ComparisonMinMagMipLinear;
255 for (unsigned i = 0; i < 4; i++) {
256 if(reverseDepth) comparisonSamplerState.borderColor[i] = 0.f;
257 else comparisonSamplerState.borderColor[i] = 1.f;
258 }
259
260 renderStates.shadowSampler = textures->loadSamplerState(comparisonSamplerState);
261 }
262
263 updateEffectFlags();
264 updateSettings();
265
266 renderContext.cameraData = &context->cameraSystem->getMainCameraData();
267
268 defaultTarget->setName("Cogs.BackBuffer");
269 defaultTarget->setOverride();
270 defaultTarget->renderTargetHandle = RenderTargetHandle::NoHandle;
271 defaultTarget->depthTargetHandle = DepthStencilHandle::NoHandle;
272 defaultTarget->width = static_cast<int>(renderContext.cameraData->viewportSize.x);
273 defaultTarget->height = static_cast<int>(renderContext.cameraData->viewportSize.y);
274 defaultTarget->samples = device->getSettings().numSamples;
275 defaultTarget->clearColors = { backgroundColor };
276
277 const bool reloadEffects = context->variables->get("renderer.reloadEffects", false);
278
279 if (reloadEffects) {
280 effectCache.reload(&renderContext);
281 context->variables->set("renderer.reloadEffects", false);
282 }
283
284 pipelineManager->setupPipeline(&renderContext);
285
286 buildSortedListOfActiveLights(context, activeLights, maxLights);
287
288 {
289 const auto eventContext = getDrawContext(&renderContext);
290
291 emitEvent(RenderingEvent::PreRender, &eventContext);
292 }
293
294 {
295 int samples = context->variables->get("renderer.samples", 1);
296 context->variables->set("impl.multiSample", samples > 1);
297 }
298
299 pipelineManager->initializeFrame(&renderContext);
300 pipelineManager->applyPipeline(&renderContext);
301
302 device->getImmediateContext()->setRenderTarget(defaultTarget->renderTargetHandle, defaultTarget->depthTargetHandle);
303
304 if (mode == RenderMode::Box) {
305 renderers->boundsRenderer.renderBounds(this, context, *pipelineManager->getRenderList());
306 }
307
308 {
309 const auto eventContext = getDrawContext(&renderContext);
310
311 emitEvent(RenderingEvent::RenderGui, &eventContext);
312 }
313
314 renderers->engineInspectorGuiRenderer.beginRender(context, this);
315 renderers->engineInspectorGuiRenderer.render(context, this);
316
317 if (context->callbacks.postRenderCallback) {
318 context->callbacks.postRenderCallback(context);
319 }
320
321 renderers->engineInspectorGuiRenderer.endRender(context, this);
322
323 {
324 const DrawContext eventContext = getDrawContext(&renderContext);
325
326 context->cameraSystem->postRender(context);
327 emitEvent(RenderingEvent::PostRender, &eventContext);
328 }
329 pipelineManager->cleanupFrame(&renderContext);
330}
331
332void Cogs::Core::Renderer::setBackgroundColor(const glm::vec4 & backgroundColor)
333{
334 // Background color is expected to be in sRGB color space, renderer works in linear space.
335 this->backgroundColor = glm::vec4(glm::convertSRGBToLinear(glm::vec3(backgroundColor)),
336 backgroundColor.a);
337}
338
339void Cogs::Core::Renderer::updateEffectFlags()
340{
341 effectFlags = EffectFlags::None;
342 if (context->variables->get("effects.logShaderInfo", false)) {
343 effectFlags = static_cast<EffectFlags::EEffectFlags>(effectFlags | EffectFlags::LogShaderInfo);
344 }
345 if (context->variables->get("effects.logShaderSource", false)) {
346 effectFlags = static_cast<EffectFlags::EEffectFlags>(effectFlags | EffectFlags::LogShaderSource);
347 }
348}
349
350
351void Cogs::Core::Renderer::updateSettings()
352{
353
354 if(context->variables->exist("renderer.enableDeferred")){
355 static uint32_t t = 0;
356 if(t<6){
357 t++;
358 LOG_WARNING(logger, "Variable \"renderer.enableDeferred\" deprecated. Use \"renderer.pipeline\": \"Pipelines/Deferred.pipeline\".");
359 }
360 if(context->variables->get("renderer.enableDeferred", false))
361 context->variables->set("renderer.pipeline", "Pipelines/Deferred.pipeline");
362 }
363
364 switch (StringView(context->variables->get("renderer.transparencyAlgorithm", "Regular")).hash())
365 {
366 case Cogs::hash("OIT"): settings.transparencyAlgorithm = RenderSettings::TransparencyAlgorithm::OIT; break;
367 default: settings.transparencyAlgorithm = RenderSettings::TransparencyAlgorithm::Regular; break;
368 }
369
370 switch (StringView(context->variables->get("renderer.blendKernel", "Alpha")).hash())
371 {
372 case Cogs::hash("DepthWeighted"): settings.blendKernel = RenderSettings::BlendKernel::DepthWeighted; break;
373 case Cogs::hash("Max"): settings.blendKernel = RenderSettings::BlendKernel::Max; break;
374 case Cogs::hash("Max2"): settings.blendKernel = RenderSettings::BlendKernel::Max2; break;
375 case Cogs::hash("Beers"): settings.blendKernel = RenderSettings::BlendKernel::Beers; break;
376 default: settings.blendKernel = RenderSettings::BlendKernel::Alpha; break;
377 }
378
379 settings.defaultRenderTargetClear = context->variables->get("renderer.backBuffer.clear.enable", true);
380
381 if (Variable* var = context->variables->get("renderer.backBuffer.sRGB"); var->isEmpty()) {
382 switch (context->device->getType()) {
384 settings.defaultRenderTargetExpectsSRGB = true;
385 break;
386 default:
387 settings.defaultRenderTargetExpectsSRGB = false;
388 break;
389 }
390 var->setBool(settings.defaultRenderTargetExpectsSRGB);
391 }
392 else {
393 settings.defaultRenderTargetExpectsSRGB = var->getBool();
394 }
395
396 {
397 Variable* var = context->variables->get("renderer.sRGBConversion");
398 if (var->isEmpty()) {
399 var->setValue("Exact");
400 }
401 switch (StringView(var->getCString()).hashLowercase()) {
402 case Cogs::hash("fast"):
403 settings.sRGBConversion = RenderSettings::SRGBConversion::Fast;
404 break;
405 case Cogs::hash("approx"):
406 settings.sRGBConversion = RenderSettings::SRGBConversion::Approx;
407 break;
408 case Cogs::hash("exact"):
409 settings.sRGBConversion = RenderSettings::SRGBConversion::Exact;
410 break;
411 default:
412 settings.sRGBConversion = RenderSettings::SRGBConversion::Exact;
413 break;
414 }
415 }
416 {
417 Variable* var = context->variables->get("renderer.tonemapper");
418 if (var->isEmpty()) {
419 var->setValue("Filmic");
420 }
421 switch (StringView(var->getCString()).hashLowercase()) {
422 case Cogs::hash("reinhard"):
423 settings.tonemapper = RenderSettings::Tonemapper::Reinhard;
424 break;
425 case Cogs::hash("filmic"):
426 settings.tonemapper = RenderSettings::Tonemapper::Filmic;
427 break;
428 case Cogs::hash("acesluminance"):
429 settings.tonemapper = RenderSettings::Tonemapper::ACESLuminance;
430 break;
431 case Cogs::hash("pbrneutral"):
432 settings.tonemapper = RenderSettings::Tonemapper::PBRNeutral;
433 break;
434 default:
435 settings.tonemapper = RenderSettings::Tonemapper::Filmic;
436 break;
437 }
438 }
439 settings.beersScaleFactor = context->variables->get("renderer.beers.scaleFactor", 1.f);
440
441 settings.ambientIntensity = context->variables->get("renderer.ambientLightIntensity", 0.f);
442 std::string acStr = context->variables->get("renderer.ambientLightColor", "1 1 1");
443 static std::string prev;
444
445 if (prev != acStr) {
446 auto acTokens = tokenize(acStr);
447 parseValues(glm::value_ptr(settings.ambientColor), acTokens, 3);
448
449 // Ambient color is expected to be in sRGB color space, renderer works in linear space.
450 settings.ambientColor = glm::convertSRGBToLinear(settings.ambientColor);
451 prev = acStr;
452 }
453}
454
455glm::mat4 Cogs::Core::Renderer::getProjectionMatrix(glm::mat4 projectionMatrix)
456{
457 if (!device) {
458 return projectionMatrix;
459 }
460
461 if(context->variables->get("renderer.reverseDepth", false)){
462 static glm::mat4 reverse(
463 1, 0, 0, 0,
464 0, 1, 0, 0,
465 0, 0, -1, 0,
466 0, 0, 0, 1
467 );
468 projectionMatrix = reverse * projectionMatrix;
469 }
470
471 switch (device->getType())
472 {
476 {
477 static glm::mat4 depthScale = glm::scale(glm::mat4(1.0f), glm::vec3(1, 1, 0.5f));
478 static glm::mat4 bias(
479 1, 0, 0, 0,
480 0, 1, 0, 0,
481 0, 0, 1, 0,
482 0, 0, 1, 1
483 );
484
485 glm::mat4 projection = depthScale * bias * projectionMatrix;
486
487 return projection;
488 }
490 {
491 static glm::mat4 depthScale = glm::scale(glm::mat4(1.0f), glm::vec3(1, -1, 0.5f));
492 static glm::mat4 bias(
493 1, 0, 0, 0,
494 0, 1, 0, 0,
495 0, 0, 1, 0,
496 0, 0, 1, 1
497 );
498
499 glm::mat4 projection = depthScale * bias * projectionMatrix;
500
501 return projection;
502 }
506 return projectionMatrix;
507 }
508 else{
509 static glm::mat4 depthScale = glm::scale(glm::mat4(1.0f), glm::vec3(1, 1, 0.5f));
510 static glm::mat4 bias(
511 1, 0, 0, 0,
512 0, 1, 0, 0,
513 0, 0, 1, 0,
514 0, 0, 1, 1
515 );
516
517 glm::mat4 projection = depthScale * bias * projectionMatrix;
518
519 return projection;
520 }
522 return projectionMatrix;
523
524 default:
525 LOG_WARNING(logger, "Unknown device type.");
526 return projectionMatrix;
527 }
528}
529glm::mat4 Cogs::Core::Renderer::getViewFromViewportMatrix(glm::mat4 inverseProjectionMatrix)
530{
531 if (!device) {
532 return inverseProjectionMatrix;
533 }
534 switch (device->getType())
535 {
539 {
540 glm::vec4 x = glm::vec4(0.1, 0.2, 0.3, 1.0);
541 glm::mat4 clipFromViewport (
542 2, 0, 0, 0,
543 0, -2, 0, 0,
544 0, 0, 1, 0,
545 -1, 1, 0, 1
546 );
547 return inverseProjectionMatrix * clipFromViewport;
548 }
550 {
551 // TODO: Verify this
552 return inverseProjectionMatrix;
553 }
557 glm::mat4 scale = glm::scale(glm::mat4(1.0), glm::vec3(2.0, 2.0, 2.0));
558 static glm::mat4 bias(
559 1, 0, 0, 0,
560 0, 1, 0, 0,
561 0, 0, 1, 0,
562 -1, -1, -1, 1
563 );
564 return inverseProjectionMatrix * bias * scale;
565 }
566 else {
567 glm::mat4 scale = glm::scale(glm::mat4(1.0), glm::vec3(2.0, 2.0, 1.0));
568 static glm::mat4 bias(
569 1, 0, 0, 0,
570 0, 1, 0, 0,
571 0, 0, 1, 0,
572 -1, -1, 0, 1
573 );
574 return inverseProjectionMatrix * bias * scale;
575 }
577 return inverseProjectionMatrix;
578
579 default:
580 LOG_WARNING(logger, "Unknown device type.");
581 return inverseProjectionMatrix;
582 }
583}
585{
586 if(context->variables->get("renderer.reverseDepth", false)) {
587 return 0.0f;
588 }
589 return 1.0f;
590}
592{
593 if(context->variables->get("renderer.reverseDepth", false)) {
594 return 1.0f;
595 }
597 return -1.0f;
598 }
599 else{
600 return 0.0f;
601 }
602}
603
605{
606 if (!device) return;
607
608 device->beginFrame();
609}
610
611void Cogs::Core::Renderer::endFrame(uint32_t syncInterval, Cogs::PresentFlags presentFlags)
612{
613 if (!device) return;
614
615 device->endFrame(syncInterval, presentFlags);
616}
617
619{
620 return &resources;
621}
622
624{
625 extensions.push_back(extension);
626
627 if (context) {
628 extension->initialize(context, device);
629 }
630}
631
633{
634 auto it = std::find(extensions.begin(), extensions.end(), extension);
635 assert(it != extensions.end() && "Unregistering unknown IRendererExtension");
636 if (it != extensions.end()) {
637 extensions.erase(it);
638 }
639}
640
641
642void Cogs::Core::Renderer::renderScreenshot(const ScreenshotSettings & settings, std::vector<uint8_t> & bytes, uint32_t * stride)
643{
644 auto deviceContext = device->getImmediateContext();
645 auto renderTargets = device->getRenderTargets();
646 auto textures = device->getTextures();
647 auto buffers = device->getBuffers();
648 auto format = TextureFormat::R8G8B8A8_UNORM_SRGB;
649
650 const size_t size = (size_t)settings.width * (size_t)settings.height * Cogs::getBlockSize(format);
651
652 auto readBuffer = buffers->loadBuffer(nullptr, size, Usage::Staging, AccessMode::Read, BindFlags::None);
653
654 Cogs::TextureHandle texture;
655 {
657 if(settings.numSamples > 1)
658 desc.target = ResourceDimensions::Texture2DMS;
659 else
660 desc.target = ResourceDimensions::Texture2D;
661 desc.width = settings.width;
662 desc.height = settings.height;
663 desc.format = format;
664 desc.samples = settings.numSamples;
665 desc.flags = TextureFlags::RenderTarget;
666 texture = textures->loadTexture(desc, nullptr);
667 }
668
669 auto renderTarget = renderTargets->createRenderTarget(&texture, 1);
670 auto depthStencilTarget = renderTargets->createDepthStencilTarget(renderTarget);
671
672 auto camera = context->cameraSystem->getMainCamera();
673 auto restoreViewport = camera->viewportSize;
674 camera->viewportSize = glm::vec2(settings.width, settings.height);
675 context->cameraSystem->update(context);
676
677 renderContext.cameraData = &context->cameraSystem->getMainCameraData();
678
679 pipelineManager->setupPipeline(&renderContext);
680
681 auto restoreRenderTargetHandle = defaultTarget->renderTargetHandle;
682 auto restoreDepthTargetHandle = defaultTarget->depthTargetHandle;
683 auto restoreWidth = defaultTarget->width;
684 auto restoreHeight = defaultTarget->height;
685 auto restoreSamples = defaultTarget->samples;
686 auto restoreColors = std::move(defaultTarget->clearColors);
687
688 defaultTarget->renderTargetHandle = renderTarget;
689 defaultTarget->depthTargetHandle = depthStencilTarget;
690 defaultTarget->width = settings.width;
691 defaultTarget->height = settings.height;
692 defaultTarget->samples = settings.numSamples;
693 defaultTarget->clearColors = { backgroundColor };
694
695 pipelineManager->initializeFrame(&renderContext);
696 pipelineManager->applyPipeline(&renderContext);
697 pipelineManager->cleanupFrame(&renderContext);
698
699 if (settings.numSamples > 1) {
700 auto resolveTexture = textures->loadTexture(nullptr, settings.width, settings.height, format, Cogs::TextureFlags::RenderTarget);
701 auto resolveRt = renderTargets->createRenderTarget(&resolveTexture, 1);
702 auto resolveDt = renderTargets->createDepthStencilTarget(resolveRt);
703
704 deviceContext->resolveResource(texture, resolveTexture);
705
706 deviceContext->setRenderTarget(resolveRt, resolveDt);
707
708 deviceContext->readColorBuffer(readBuffer, 0, 0, settings.width, settings.height, Framebuffer::Front);
709
710 renderTargets->releaseDepthStencilTarget(resolveDt);
711 renderTargets->releaseRenderTarget(resolveRt);
712 textures->releaseTexture(resolveTexture);
713 } else {
714 deviceContext->setRenderTarget(renderTarget, depthStencilTarget);
715
716 deviceContext->readColorBuffer(readBuffer, 0, 0, settings.width, settings.height, Framebuffer::Front);
717 }
718
719 {
720 MappedBuffer<uint8_t> data(deviceContext, readBuffer, MapMode::Read, size);
721
722 if (data) {
723 const size_t bufferSize = data.getStride() ? data.getStride() * settings.height : size;
724 bytes.assign(data.get(), data.get() + bufferSize);
725
726 if (stride) {
727 *stride = data.getStride();
728 }
729 }
730 }
731
732 defaultTarget->renderTargetHandle = restoreRenderTargetHandle;
733 defaultTarget->depthTargetHandle = restoreDepthTargetHandle;
734 defaultTarget->width = restoreWidth;
735 defaultTarget->height = restoreHeight;
736 defaultTarget->samples = restoreSamples;
737 defaultTarget->clearColors = std::move(restoreColors);
738
739 camera->viewportSize = restoreViewport;
740
741 buffers->releaseBuffer(readBuffer);
742 renderTargets->releaseDepthStencilTarget(depthStencilTarget);
743 renderTargets->releaseRenderTarget(renderTarget);
744 textures->releaseTexture(texture);
745}
746
747void Cogs::Core::Renderer::emitEvent(uint32_t eventId, const DrawContext * renderingContext)
748{
749 for (auto extension : extensions) {
750 extension->handleEvent(eventId, renderingContext);
751 }
752}
753
755{
756 const bool ditherEnabled = context->variables->get("renderer.ditherEnabled", false);
757 if(permutation->hasVariant("Dither"))
758 permutation->setVariant("Dither", ditherEnabled);
759
760 const bool reverseDepth = context->variables->get("renderer.reverseDepth", false);
761 if(permutation->hasVariant("ReverseDepth"))
762 permutation->setVariant("ReverseDepth", reverseDepth);
763
764 if(permutation->hasVariant("DepthNegativeOneToOne"))
765 permutation->setVariant("DepthNegativeOneToOne", device->getCapabilities()->getDeviceCapabilities().DepthNegativeOneToOne);
766
767 if (!permutation->hasBuiltins()) return;
768 if (!permutation->isShadingPass() || permutation->isDepthOnly()) return;
769
770 if (auto ec = context->environmentSystem->getGlobalEnvironment(); ec != nullptr) {
771 permutation->setVariant("SubseaSupport", ec->subseaSupport);
772 if(ec->imageBasedLighting) {
773 if(ec->PBR) {
774 permutation->setVariant("ImageBasedLighting", "PBR");
775 } else {
776 permutation->setVariant("ImageBasedLighting", "Phong");
777 }
778 } else {
779 permutation->setVariant("ImageBasedLighting", "Disabled");
780 }
781 }
782
783
784 const bool shadowsEnabled = (activeLights.numDirectionalShadowLights != 0) || (activeLights.numPointShadowLights != 0);
785 permutation->setVariant("NumDirectionalShadowLights", static_cast<int>(activeLights.numDirectionalShadowLights));
786 permutation->setVariant("NumPointShadowLights", static_cast<int>(activeLights.numPointShadowLights));
787 permutation->setVariant("NumDirectionalLights", static_cast<int>(activeLights.numDirectionalLights));
788 permutation->setVariant("NumPointLights", static_cast<int>(activeLights.numPointLights));
789 permutation->setVariant("ShadowsEnabled", shadowsEnabled);
790 if (shadowsEnabled) {
791 const Cogs::Core::SoftShadows softShadows = parseEnum<SoftShadows>(context->variables->get("shadows.softShadows", "Default"));
792 permutation->setVariant("SoftShadows", (int)softShadows);
793 }
794
795 if(permutation->hasVariant("sRGBConversion")) {
796 switch (settings.sRGBConversion) {
797 case RenderSettings::SRGBConversion::Fast:
798 permutation->setVariant("sRGBConversion", "Fast");
799 break;
800 case RenderSettings::SRGBConversion::Approx:
801 permutation->setVariant("sRGBConversion", "Approx");
802 break;
803 case RenderSettings::SRGBConversion::Exact:
804 permutation->setVariant("sRGBConversion", "Exact");
805 break;
806 default:
807 assert(false && "Invalid enum");
808 break;
809 }
810 }
811
812 if (permutation->hasVariant("Tonemapper")) {
813 switch (settings.tonemapper) {
814 case RenderSettings::Tonemapper::Reinhard:
815 permutation->setVariant("Tonemapper", "Reinhard");
816 break;
817 case RenderSettings::Tonemapper::Filmic:
818 permutation->setVariant("Tonemapper", "Filmic");
819 break;
820 case RenderSettings::Tonemapper::ACESLuminance:
821 permutation->setVariant("Tonemapper", "ACESLuminance");
822 break;
823 case RenderSettings::Tonemapper::PBRNeutral:
824 permutation->setVariant("Tonemapper", "PBRNeutral");
825 break;
826 default:
827 assert(false && "Invalid enum");
828 break;
829 }
830 }
831
832}
833
834Cogs::Core::ImguiRenderer* Cogs::Core::Renderer::getGuiRenderer() {
835 return &renderers->imguiRenderer;
836}
837
838Cogs::Core::InspectorGuiRenderer * Cogs::Core::Renderer::getEngineInspectorGuiRenderer()
839{
840 return &renderers->engineInspectorGuiRenderer;
841}
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:754
float getNearDepth() override
Get adjusted near plane depth.
Definition: Renderer.cpp:591
IRenderResources * getResources() override
Get the render resources interface.
Definition: Renderer.cpp:618
void registerExtension(IRendererExtension *extension) override
Registers the given extension with the renderer. Doesn not take ownership of pointer.
Definition: Renderer.cpp:623
void setBackgroundColor(const glm::vec4 &backgroundColor) override
Set the background color applied to the output surface before rendering.
Definition: Renderer.cpp:332
void renderScreenshot(const ScreenshotSettings &settings, std::vector< uint8_t > &bytes, uint32_t *stride=nullptr) override
Render screenshot.
Definition: Renderer.cpp:642
glm::mat4 getViewFromViewportMatrix(glm::mat4 inverseProjectionMatrix) override
Get an adjusted inverse projection matrix mainly used in post processing.
Definition: Renderer.cpp:529
void emitEvent(uint32_t eventId, const DrawContext *renderingContext)
Emits the given render event to all registered extensions.
Definition: Renderer.cpp:747
void endFrame(uint32_t syncInterval=0, Cogs::PresentFlags presentFlags=PresentFlags::None) override
Signals the end of the current frame.
Definition: Renderer.cpp:611
void unregisterExtension(IRendererExtension *extension) override
Unregister an extension with the renderer.
Definition: Renderer.cpp:632
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:584
glm::mat4 getProjectionMatrix(const glm::mat4 projectionMatrix) override
Get an adjusted projection matrix used to render.
Definition: Renderer.cpp:455
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:604
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.
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