Cogs.Core
RenderStateUpdater.cpp
1#include "Foundation/Logging/Logger.h"
2
3#include "Rendering/ICapabilities.h"
4
5#include "Context.h"
6
7#include "Systems/Core/LightSystem.h"
8#include "Systems/Core/EnvironmentSystem.h"
9
10#include "Resources/Mesh.h"
11#include "Resources/Skeleton.h"
12#include "Resources/Animation.h"
13#include "Resources/BasicBlueNoiseManager.h"
14#include "RenderStateUpdater.h"
15#include "RenderList.h"
16
17#include "Tasks/RenderTask.h"
18#include "Tasks/GenerateListTask.h"
19
20#include "Resources/TextureManager.h"
21
22namespace
23{
24 Cogs::Logging::Log logger = Cogs::Logging::getLogger("RenderStateUpdater");
25}
26
27
28void Cogs::Core::applyMaterialProperties(const DrawContext * drawContext,
29 const Material * /*material*/,
30 const ConstantBufferBindingHandle & bufferBinding,
31 const BufferHandle & constantBuffer)
32{
33 auto deviceContext = drawContext->deviceContext;
34 if (HandleIsValid(bufferBinding)) {
35 deviceContext->setConstantBuffer(bufferBinding, constantBuffer);
36 }
37}
38
39void Cogs::Core::updateSceneBindings(const DrawContext * drawContext, const CameraData * /*cameraData*/, const EffectBinding * bindings)
40{
41 assert(drawContext->taskContext && "Invalid rendering context.");
42
43 updateSceneBindings(drawContext->taskContext, bindings);
44}
45
46void Cogs::Core::updateSceneBindings(const RenderTaskContext * taskContext, const EffectBinding * bindings)
47{
48 const EngineBuffers* engineBuffers = &taskContext->renderer->getEngineBuffers();
49 IGraphicsDevice* device = taskContext->renderer->getDevice();
50 IContext* deviceContext = device->getImmediateContext();
51
52 if (HandleIsValid(bindings->sceneBufferBinding)) {
53 deviceContext->setConstantBuffer(bindings->sceneBufferBinding, engineBuffers->sceneBufferHandle);
54 }
55 if (HandleIsValid(bindings->viewBufferBinding)) {
56 deviceContext->setConstantBuffer(bindings->viewBufferBinding, engineBuffers->viewBufferHandle);
57 }
58
59 if (HandleIsValid(bindings->blueNoise)) {
60 auto& blueNoiseManager = taskContext->context->blueNoiseManager;
61 blueNoiseManager->enable();
62 TextureHandle blueNoise = blueNoiseManager->getBlueNoiseHandle(false)->texture;
63 RenderTexture * blueNoiseTexture = taskContext->renderer->getRenderResources().getRenderTexture(blueNoise);
64 if (blueNoiseTexture) {
65 deviceContext->setTexture(bindings->blueNoise, blueNoiseTexture->textureHandle);
66 }
67 }
68 if (HandleIsValid(bindings->blueNoiseStable)) {
69 auto& blueNoiseManager = taskContext->context->blueNoiseManager;
70 blueNoiseManager->enable();
71 TextureHandle blueNoise = blueNoiseManager->getBlueNoiseHandle(true)->texture;
72 RenderTexture * blueNoiseTexture = taskContext->renderer->getRenderResources().getRenderTexture(blueNoise);
73 if (blueNoiseTexture) {
74 deviceContext->setTexture(bindings->blueNoiseStable, blueNoiseTexture->textureHandle);
75 }
76 }
77}
78
79void Cogs::Core::updateEnvironmentBindings(const DrawContext * drawContext, const EffectBinding * bindings)
80{
81 IContext *deviceContext = drawContext->deviceContext;
82 LightSystem *lightSystem = drawContext->context->lightSystem;
83
84 bool needSkyBinding = true;
85 bool needRadianceBinding = true;
86 bool needIrradianceBinding = true;
87 bool needAmbientIrradianceBinding = true;
88
89 if (!drawContext->permutation->isShadowPass()) {
90 if (HandleIsValid(bindings->shadowArrayBinding)) {
91 RenderTexture * shadowTexture = drawContext->renderer->getRenderResources().getRenderTexture(lightSystem->cascadeArray);
92
93 if (shadowTexture) {
94 deviceContext->setTexture(bindings->shadowArrayBinding, shadowTexture->textureHandle);
95 deviceContext->setSamplerState("", 1, drawContext->taskContext->states->shadowSampler);
96 }
97 }
98 if (HandleIsValid(bindings->shadowArrayBinding_1)) {
99 RenderTexture * shadowTexture = drawContext->renderer->getRenderResources().getRenderTexture(lightSystem->cascadeArray);
100
101 if (shadowTexture) {
102 deviceContext->setTexture(bindings->shadowArrayBinding_1, shadowTexture->textureHandle);
103 deviceContext->setSamplerState("", 1, drawContext->taskContext->states->shadowSampler);
104 }
105 }
106
107 if (HandleIsValid(bindings->shadowCubeArrayBinding)) {
108 RenderTexture * shadowTexture = drawContext->renderer->getRenderResources().getRenderTexture(lightSystem->cubeArray);
109
110 if (shadowTexture) {
111 deviceContext->setTexture(bindings->shadowCubeArrayBinding, shadowTexture->textureHandle);
112 deviceContext->setSamplerState("", 2, drawContext->taskContext->states->shadowSampler);
113 }
114 }
115 if (HandleIsValid(bindings->shadowCubeArrayBinding_1)) {
116 auto shadowTexture = drawContext->renderer->getRenderResources().getRenderTexture(lightSystem->cubeArray);
117
118 if (shadowTexture) {
119 deviceContext->setTexture(bindings->shadowCubeArrayBinding_1, shadowTexture->textureHandle);
120 deviceContext->setSamplerState("", 2, drawContext->taskContext->states->shadowSampler);
121 }
122 }
123
124 if (HandleIsValid(bindings->shadowSamplerBinding)) {
125 deviceContext->setSamplerState(bindings->shadowSamplerBinding, drawContext->taskContext->states->shadowSampler);
126 }
127 if (HandleIsValid(bindings->shadowArraySamplerBinding)) {
128 deviceContext->setSamplerState(bindings->shadowArraySamplerBinding, drawContext->taskContext->states->shadowSampler);
129 }
130 if (HandleIsValid(bindings->shadowCubeArraySamplerBinding)) {
131 deviceContext->setSamplerState(bindings->shadowCubeArraySamplerBinding, drawContext->taskContext->states->shadowSampler);
132 }
133 }
134 else {
135 if (HandleIsValid(bindings->shadowSamplerBinding)) {
136 deviceContext->setSamplerState(bindings->shadowSamplerBinding, drawContext->taskContext->states->shadowSampler);
137 }
138 }
139
140 auto environmentComponent = drawContext->cameraData->environment.resolveComponent<EnvironmentComponent>();
141
142 if (environmentComponent) {
143 if (environmentComponent->isSubmerged(drawContext->cameraData)) {
144
145 if (environmentComponent->subseaRadiance) {
146 RenderTexture * subseaRadianceTexture = drawContext->renderer->getRenderResources().getRenderTexture(environmentComponent->subseaRadiance);
147 if (subseaRadianceTexture) {
148 if (subseaRadianceTexture->description.target != ResourceDimensions::TextureCube) {
149 static int count = 0;
150 if (count < 10) {
151 LOG_ERROR(logger, "environment.subseaRadiance is not a cube texture.");
152 count++;
153 }
154 }
155 else {
156 if (HandleIsValid(bindings->skyBinding)) {
157 deviceContext->setTexture(bindings->skyBinding, subseaRadianceTexture->textureHandle);
158 needSkyBinding = false;
159 }
160 if (HandleIsValid(bindings->radianceBinding)) {
161 deviceContext->setTexture(bindings->radianceBinding, subseaRadianceTexture->textureHandle);
162 needRadianceBinding = false;
163 }
164 if (HandleIsValid(bindings->irradianceBinding)) {
165 deviceContext->setTexture(bindings->irradianceBinding, subseaRadianceTexture->textureHandle);
166 needIrradianceBinding = false;
167 }
168 if (HandleIsValid(bindings->ambientIrradianceBinding)) {
169 deviceContext->setTexture(bindings->ambientIrradianceBinding, subseaRadianceTexture->textureHandle);
170 needAmbientIrradianceBinding = false;
171 }
172 }
173 }
174 }
175 } else {
176 if (environmentComponent->skyDome && HandleIsValid(bindings->skyBinding)) {
177
178 if (RenderTexture * skyTexture = drawContext->renderer->getRenderResources().getRenderTexture(environmentComponent->skyDome); skyTexture) {
179
180 if (skyTexture->description.target != ResourceDimensions::TextureCube) {
181 static int warningCount = 0;
182 if (warningCount < 10) {
183 LOG_ERROR(logger, "environment.skyDome is not a cube texture.");
184 warningCount++;
185 }
186 }
187 else {
188 deviceContext->setTexture(bindings->skyBinding, skyTexture->textureHandle);
189 needSkyBinding = false;
190 }
191 }
192 }
193
194 if (environmentComponent->radiance && HandleIsValid(bindings->radianceBinding)) {
195
196 if (RenderTexture * radianceTexture = drawContext->renderer->getRenderResources().getRenderTexture(environmentComponent->radiance); radianceTexture) {
197
198 if (radianceTexture->description.target != ResourceDimensions::TextureCube) {
199 static int warningCount = 0;
200 if (warningCount < 10) {
201 LOG_ERROR(logger, "environment.radiance is not a cube texture.");
202 warningCount++;
203 }
204 }
205 else {
206 deviceContext->setTexture(bindings->radianceBinding, radianceTexture->textureHandle);
207 needRadianceBinding = false;
208 }
209 }
210 }
211
212 if (environmentComponent->irradiance && HandleIsValid(bindings->irradianceBinding)) {
213
214 if (RenderTexture * irradianceTexture = drawContext->renderer->getRenderResources().getRenderTexture(environmentComponent->irradiance); irradianceTexture) {
215
216 if (irradianceTexture->description.target != ResourceDimensions::TextureCube) {
217 static int warningCount = 0;
218 if (warningCount < 10) {
219 LOG_ERROR(logger, "environment.irradiance is not a cube texture.");
220 warningCount++;
221 }
222 }
223 else {
224 deviceContext->setTexture(bindings->irradianceBinding, irradianceTexture->textureHandle);
225 needIrradianceBinding = false;
226 }
227 }
228 }
229
230 if (environmentComponent->ambientIrradiance && HandleIsValid(bindings->ambientIrradianceBinding)) {
231 RenderTexture * ambientIrradianceTexture = drawContext->renderer->getRenderResources().getRenderTexture(environmentComponent->ambientIrradiance);
232 if (ambientIrradianceTexture) {
233
234 if (ambientIrradianceTexture->description.target != ResourceDimensions::TextureCube) {
235 static int warningCount = 0;
236 if (warningCount < 10) {
237 LOG_ERROR(logger, "environment.ambientIrradiance is not a cube texture.");
238 warningCount++;
239 }
240 }
241 else {
242 deviceContext->setTexture(bindings->ambientIrradianceBinding, ambientIrradianceTexture->textureHandle);
243 needAmbientIrradianceBinding = false;
244 }
245 }
246 }
247
248 if (environmentComponent->brdfLUT && HandleIsValid(bindings->brdfLUTBinding)) {
249 RenderTexture* brdfLUTTexture = drawContext->renderer->getRenderResources().getRenderTexture(environmentComponent->brdfLUT);
250 if (brdfLUTTexture) {
251
252 if (brdfLUTTexture->description.target != ResourceDimensions::Texture2D) {
253 static int warningCount = 0;
254 if (warningCount < 10) {
255 LOG_ERROR(logger, "environment.brdfLUT is not a 2D texture.");
256 warningCount++;
257 }
258 }
259 else {
260 deviceContext->setTexture(bindings->brdfLUTBinding, brdfLUTTexture->textureHandle);
261 }
262 }
263 } else if (HandleIsValid(bindings->brdfLUTBinding)) {
264 RenderTexture * white = drawContext->renderer->getRenderResources().getRenderTexture(drawContext->context->textureManager->white);
265 deviceContext->setTexture(bindings->brdfLUTBinding, white->textureHandle);
266 }
267
268 }
269 }
270
271 if (drawContext->device->getType() == GraphicsDeviceType::WebGPU){
272 // Set Dymmy textures requered for WebGPU
273
274 // skyBinding
275 if(HandleIsValid(bindings->skyBinding) && needSkyBinding){
276 TextureHandle whiteCube = drawContext->context->textureManager->whiteCube;
277 RenderTexture* skyTexture = drawContext->renderer->getRenderResources().getRenderTexture(whiteCube);
278 if (skyTexture) {
279 LOG_INFO_ONCE(logger, "Setting dummy environment.skyDome.");
280 deviceContext->setTexture(bindings->skyBinding, skyTexture->textureHandle);
281 }
282 }
283
284 // radianceBinding
285 if(HandleIsValid(bindings->radianceBinding) && needRadianceBinding) {
286 TextureHandle whiteCube = drawContext->context->textureManager->whiteCube;
287 RenderTexture* radianceTexture = drawContext->renderer->getRenderResources().getRenderTexture(whiteCube);
288 if (radianceTexture) {
289 LOG_INFO_ONCE(logger, "Setting dummy environment.radiance.");
290 deviceContext->setTexture(bindings->radianceBinding, radianceTexture->textureHandle);
291 }
292 }
293
294 // irradianceBinding
295 if(HandleIsValid(bindings->irradianceBinding) && needIrradianceBinding) {
296 TextureHandle whiteCube = drawContext->context->textureManager->whiteCube;
297 RenderTexture* irradianceTexture = drawContext->renderer->getRenderResources().getRenderTexture(whiteCube);
298 if (irradianceTexture) {
299 LOG_INFO_ONCE(logger, "Setting dummy environment.irradiance.");
300 deviceContext->setTexture(bindings->irradianceBinding, irradianceTexture->textureHandle);
301 }
302 }
303
304 // ambientIrradianceBinding
305 if(HandleIsValid(bindings->ambientIrradianceBinding) && needAmbientIrradianceBinding) {
306 TextureHandle whiteCube = drawContext->context->textureManager->whiteCube;
307 RenderTexture* ambientIrradianceTexture = drawContext->renderer->getRenderResources().getRenderTexture(whiteCube);
308 if (ambientIrradianceTexture) {
309 LOG_INFO_ONCE(logger, "Setting dummy environment.ambientIrradiance.");
310 deviceContext->setTexture(bindings->ambientIrradianceBinding, ambientIrradianceTexture->textureHandle);
311 }
312 }
313 }
314
315 SamplerState linearFiltering = {
316 SamplerState::AddressMode::Clamp,
317 SamplerState::AddressMode::Clamp,
318 SamplerState::AddressMode::Clamp,
319 SamplerState::FilterMode::MinMagMipLinear,
320 SamplerState::ComparisonFunction::Never,
321 1,
322 { 0, 0, 0, 1 }
323 };
324
325 if (HandleIsValid(bindings->skySamplerBinding)) {
326 deviceContext->setSamplerState(bindings->skySamplerBinding, drawContext->taskContext->states->getSamplerState(linearFiltering));
327 }
328
329
330 if (HandleIsValid(bindings->radianceSamplerBinding)) {
331 deviceContext->setSamplerState(bindings->radianceSamplerBinding, drawContext->taskContext->states->getSamplerState(linearFiltering));
332 }
333 if (HandleIsValid(bindings->irradianceSamplerBinding)) {
334 deviceContext->setSamplerState(bindings->irradianceSamplerBinding, drawContext->taskContext->states->getSamplerState(linearFiltering));
335 }
336 if (HandleIsValid(bindings->ambientIrradianceSamplerBinding)) {
337 deviceContext->setSamplerState(bindings->ambientIrradianceSamplerBinding, drawContext->taskContext->states->getSamplerState(SamplerState::DefaultState()));
338 }
339 if (HandleIsValid(bindings->brdfLUTSamplerBinding)) {
340 SamplerState lutSamplerState = {
341 SamplerState::AddressMode::Clamp,
342 SamplerState::AddressMode::Clamp,
343 SamplerState::AddressMode::Clamp,
344 SamplerState::FilterMode::MinMagMipLinear,
345 SamplerState::ComparisonFunction::Never,
346 1,
347 { 0, 0, 0, 1 }
348 };
349 deviceContext->setSamplerState(bindings->brdfLUTSamplerBinding, drawContext->taskContext->states->getSamplerState(lutSamplerState));
350 }
351}
352
353void Cogs::Core::updateMaterialBindings(const DrawContext * drawContext, const RenderMaterialInstance * renderMaterialInstance, const EffectBinding * bindings, bool perInstance)
354{
355 auto deviceContext = drawContext->deviceContext;
356
357 auto materialInstance = renderMaterialInstance->getResource();
358 auto material = materialInstance->material;
359
360 for (auto & buffer : material->constantBuffers.buffers) {
361 if (buffer.isPerInstance != perInstance) continue;
362
363 auto & bufferBinding = bindings->bufferBindings[buffer.index];
364
365 if (perInstance) {
366 applyMaterialProperties(drawContext, material, bufferBinding, renderMaterialInstance->buffers[buffer.index].handle);
367 }
368 else {
369 applyMaterialProperties(drawContext, material, bufferBinding, bindings->buffers[buffer.index].handle);
370 }
371 }
372
373 if (perInstance) {
374 for (const TextureValue& textureProperty : materialInstance->textureVariables) {
375 if (textureProperty.property->isPerInstance) {
376 const Cogs::TextureBindingHandle& textureBinding = bindings->textureBindings[textureProperty.key];
377 const Cogs::SamplerStateBindingHandle& samplerBinding = bindings->samplerBindings[textureProperty.key];
378
379 RenderTexture* renderTexture = drawContext->renderer->getRenderResources().getRenderTexture(textureProperty.texture.handle);
380
381 if (renderTexture) {
382 deviceContext->setTexture(textureBinding, renderTexture->textureHandle);
383 }
384 else {
385 if (HandleIsValid(textureProperty.property->texture.handle)) {
386 // Render texture is not ready, fall back to default value if available.
387 renderTexture = drawContext->renderer->getRenderResources().getRenderTexture(textureProperty.property->texture.handle);
388 deviceContext->setTexture(textureBinding, renderTexture ? renderTexture->textureHandle : Cogs::TextureHandle::NoHandle);
389 }
390 else {
391 deviceContext->setTexture(textureBinding, Cogs::TextureHandle::NoHandle);
392 }
393 }
394 if (HandleIsValid(renderMaterialInstance->samplerStates[textureProperty.key])) {
395 deviceContext->setSamplerState(samplerBinding, renderMaterialInstance->samplerStates[textureProperty.key]);
396 }
397 else {
398 deviceContext->setSamplerState(samplerBinding, Cogs::SamplerStateHandle::NoHandle);
399 }
400 }
401 }
402 }
403 else {
404 RenderMaterial* renderMaterial = renderMaterialInstance->renderMaterial;
405
406 for (size_t i = 0, N = material->textureProperties.size(); i < N; i++) {
407 const TextureProperty& textureProperty = material->textureProperties[i];
408 if (!textureProperty.isPerInstance) {
409
410 RenderTexture* renderTexture = drawContext->renderer->getRenderResources().getRenderTexture(textureProperty.texture.handle);
411 if (renderTexture) {
412 deviceContext->setTexture(bindings->textureBindings[textureProperty.key], renderTexture->textureHandle);
413 }
414 else {
415 deviceContext->setTexture(bindings->textureBindings[textureProperty.key], Cogs::TextureHandle::NoHandle);
416 }
417
418 const RenderMaterial::TexturePropertyState& state = renderMaterial->texturePropertyStates[i];
419 if (HandleIsValid(state.samplerState)) {
420 deviceContext->setSamplerState(bindings->samplerBindings[textureProperty.key], state.samplerState);
421 }
422 else {
423 deviceContext->setSamplerState(bindings->samplerBindings[textureProperty.key], Cogs::SamplerStateHandle::NoHandle);
424 }
425
426 }
427 }
428 }
429}
430
431void Cogs::Core::applyMaterialPermutation(RenderTaskContext * taskContext, const DrawContext * drawContext, const EffectBinding * bindings, const RenderMaterialInstance * renderMaterialInstance)
432{
433 drawContext->deviceContext->setEffect(bindings->renderEffect->effectHandle);
434 drawContext->deviceContext->setInputLayout(bindings->renderEffect->inputHandle);
435 updateSceneBindings(taskContext, bindings);
436 updateMaterialBindings(drawContext, renderMaterialInstance, bindings, false);
437}
438
439void Cogs::Core::applyMaterialInstance(const DrawContext * drawContext, const EffectBinding * bindings, const RenderMaterialInstance * renderMaterialInstance)
440{
441 updateMaterialBindings(drawContext, renderMaterialInstance, bindings, true);
442}
443
444size_t Cogs::Core::populateObjectBuffer(const DrawContext * drawContext, const RenderItem* items, size_t o, size_t n)
445{
446 auto deviceContext = drawContext->deviceContext;
447 auto & engineBuffers = *drawContext->engineBuffers;
448 assert(engineBuffers.objectBatch.count != 0);
449
450 const auto stride = engineBuffers.objectBatch.stride;
451 auto m = std::min(n - o, size_t(engineBuffers.objectBatch.count));
452 if (m) {
453 MappedBuffer<char> objectBatch(deviceContext, engineBuffers.objectBatch.bufferHandle, MapMode::WriteDiscard);
454
455 if (objectBatch) {
456 for (size_t i = 0; i < m; i++) {
457 if (items[o + i].isCustom()) continue;
458 auto * obj = (ObjectBuffer*)(objectBatch.get() + stride * i);
459 obj->worldMatrix = *items[o + i].worldMatrix;
460 obj->objectId = items[o + i].objectId;
461 }
462 }
463 }
464 return o + m;
465}
466
467void Cogs::Core::applyMaterialPerObjectBatched(const DrawContext * drawContext, const RenderMaterialInstance * /*renderMaterialInstance*/, const RenderItem & renderItem, size_t o)
468{
469 auto deviceContext = drawContext->deviceContext;
470 auto & engineBuffers = *drawContext->engineBuffers;
471 auto & batch = engineBuffers.objectBatch;
472
473 const auto bindings = renderItem.binding;
474
475 if (HandleIsValid(bindings->objectBufferBinding)) {
476 deviceContext->setConstantBuffer(bindings->objectBufferBinding,
477 batch.bufferHandle,
478 batch.stride * uint32_t(o),
479 batch.stride);
480 }
481
482 if (renderItem.poseData) {
483 if (HandleIsValid(bindings->animationBufferBinding)) {
484 deviceContext->updateBuffer(engineBuffers.animationBuffer, renderItem.poseData->transforms, sizeof(glm::mat4) * renderItem.poseData->numPoses);
485 deviceContext->setConstantBuffer(bindings->animationBufferBinding, engineBuffers.animationBuffer);
486 }
487 }
488}
489
490
491void Cogs::Core::applyMaterialPerObject(const DrawContext * drawContext, const RenderMaterialInstance * /*renderMaterialInstance*/, const RenderItem & renderItem)
492{
493 auto deviceContext = drawContext->deviceContext;
494 auto & engineBuffers = *drawContext->engineBuffers;
495
496 const auto bindings = renderItem.binding;
497
498 if (HandleIsValid(bindings->objectBufferBinding)) {
499 ListObjectBuffer* unifiedObjectBuffer = drawContext->listObjectBuffer;
500
501 if (unifiedObjectBuffer && renderItem.hasObjectBufferSlot() && HandleIsValid(unifiedObjectBuffer->gpu)) {
502 deviceContext->setConstantBuffer(bindings->objectBufferBinding,
503 unifiedObjectBuffer->gpu,
504 unifiedObjectBuffer->stride * renderItem.objectBufferSlot,
505 unifiedObjectBuffer->stride);
506 }
507 else {
508 MappedBuffer<ObjectBuffer> objectBuffer(deviceContext, engineBuffers.objectBufferHandle, MapMode::WriteDiscard);
509 if (objectBuffer) {
510 objectBuffer->worldMatrix = *renderItem.worldMatrix;
511 objectBuffer->objectId = renderItem.objectId;
512 }
513 deviceContext->setConstantBuffer(bindings->objectBufferBinding, engineBuffers.objectBufferHandle);
514 }
515 }
516
517 if (renderItem.poseData) {
518 if (HandleIsValid(bindings->animationBufferBinding)) {
519 deviceContext->updateBuffer(engineBuffers.animationBuffer, renderItem.poseData->transforms, sizeof(glm::mat4) * renderItem.poseData->numPoses);
520 deviceContext->setConstantBuffer(bindings->animationBufferBinding, engineBuffers.animationBuffer);
521 }
522 }
523}
Log implementation class.
Definition: LogManager.h:140
bool HandleIsValid(const ResourceHandle_t< T > &handle)
Check if the given resource is valid, that is not equal to NoHandle or InvalidHandle.
constexpr Log getLogger(const char(&name)[LEN]) noexcept
Definition: LogManager.h:181
static const Handle_t NoHandle
Represents a handle to nothing.
Definition: Common.h:78