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