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