Cogs.Core
RendererExtension.cpp
1#include "ExtensionRegistry.h"
2#include "Renderer/Renderer.h"
3#include "Renderer/RenderList.h"
4#include "Renderer/RenderStateUpdater.h"
5#include "Renderer/RenderTarget.h"
6#include "Renderer/Tasks/RenderListTask.h"
7#include "Renderer/Tasks/FilterListTask.h"
8#include "Renderer/Tasks/GenerateListTask.h"
9
10#include "Image360System.h"
11
12#include "Rendering/IGraphicsDevice.h"
13#include "Rendering/ITextures.h"
14#include "Rendering/ICapabilities.h"
15#include "Rendering/IRenderTargets.h"
16#include "Foundation/Logging/Logger.h"
17
18#include <glm/glm.hpp>
19
20#include <array>
21
22
23namespace {
24 using namespace Cogs::Core;
25 using namespace Cogs::Core::Image360;
26
28
29 struct Constants
30 {
31 glm::mat4 worldFromLocal;
32 glm::mat4 localFromWorld;
33 float clipSpaceNearPlane;
34 float valueScale;
35 float valueBias;
36 float depthScale;
37 float depthBias;
38 float baseSize;
39 uint32_t noDataDepth;
40 };
41
42 void image360RenderCallback(RenderTaskContext* taskContext, DrawContext* drawContext, const RenderItem* renderItem)
43 {
44 const auto* camData = drawContext->cameraData;
45 if (camData == nullptr) return;
46
47 Renderer* renderer = taskContext->renderer;
48
49 Cogs::IGraphicsDevice* device = renderer->getDevice();
50 Cogs::IContext* iContext = device->getImmediateContext();
51 RendererExtension* im360Renderer = renderItem->getCallbackData<RendererExtension>();
52 RendererExtensionData* rendererData = renderItem->getCallbackData2<RendererExtensionData>();
53 if (!HandleIsValid(rendererData->encodedTreesTex)) {
54 return;
55 }
56 if (!HandleIsValid(rendererData->value.tilesTex)) {
57 return;
58 }
59
60 if (drawContext->task->viewportFromTarget && drawContext->renderTarget) {
61 iContext->setViewport(0.f, 0.f, float(drawContext->renderTarget->width), float(drawContext->renderTarget->height));
62 }
63 else {
64 iContext->setViewport(camData->viewportOrigin.x, camData->viewportOrigin.y, camData->viewportSize.x, camData->viewportSize.y);
65 }
66
67 iContext->setDepthStencilState(taskContext->states->commonDepthStates[renderItem->depthState]);
68 iContext->setBlendState(taskContext->states->blendStates[renderItem->blendState].handle);
69
70 const RenderPassOptions passOptions = initRenderPassOptions(*camData , renderItem->materialInstance);
71 iContext->setRasterizerState(taskContext->states->rasterizerStateHandles[getRasterizerState(renderer, *renderItem, passOptions, camData->flipWindingOrder, true)]);
72
73 // Invokes updateSceneBindings
74 // Invokes updateMaterialBindings(instance=false)
75 applyMaterialPermutation(taskContext, drawContext, drawContext->binding, renderItem->renderMaterialInstance);
76
77 // INvokes updateEnvironmentBindings,
78 // Updates permutation->constant buffers
79 drawContext->task->applyMaterial(*drawContext, *renderItem, drawContext->binding);
80
81 // Invokes updateMaterialBindings -> applyMaterialProperties
82 applyMaterialInstance(drawContext, drawContext->binding, renderItem->renderMaterialInstance);
83
84 updateSceneBindings(drawContext, drawContext->cameraData, drawContext->binding);
85
86 updateMaterialBindings(drawContext, renderItem->renderMaterialInstance, drawContext->binding, true);
87
88 Cogs::IEffects* effects = device->getEffects();
89
90 const glm::mat3 viewFromLocal = glm::mat3(drawContext->cameraData->viewMatrix) * rendererData->worldFromLocal;
91 const glm::mat3 localFromView = rendererData->localFromWorld * glm::mat3(drawContext->cameraData->inverseViewMatrix);
92 const float clipSpaceNearPlane = drawContext->context->variables->get("renderer.reverseDepth", false) ? 1.f : -1.f;
93 const EffectBinding* bindings = drawContext->binding;
94 const EngineBuffers& engineBuffers = *drawContext->engineBuffers;
95
96 if (Cogs::ConstantBufferBindingHandle constantsBinding = effects->getConstantBufferBinding(bindings->renderEffect->effectHandle, "Constants"); HandleIsValid(constantsBinding)) {
97 Constants constants{
98 .worldFromLocal = rendererData->worldFromLocal,
99 .localFromWorld = rendererData->localFromWorld,
100 .clipSpaceNearPlane = clipSpaceNearPlane,
101 .valueScale = rendererData->value.scale,
102 .valueBias = rendererData->value.bias,
103 .depthScale = rendererData->depth.scale,
104 .depthBias = rendererData->depth.bias,
105 .baseSize = float(rendererData->baseSize),
106 .noDataDepth = rendererData->noDataDepth
107 };
108 iContext->updateBuffer(rendererData->constants, &constants, sizeof(constants));
109 iContext->setConstantBuffer(constantsBinding, rendererData->constants);
110 }
111
112 if (HandleIsValid(bindings->objectBufferBinding)) {
113 ObjectBuffer objectBuffer = {};
114 objectBuffer.encodeObjectId(renderItem->objectId);
115 iContext->updateBuffer(rendererData->constants, &objectBuffer, sizeof(objectBuffer));
116 iContext->setConstantBuffer(bindings->objectBufferBinding, engineBuffers.objectBufferHandle);
117 }
118
119 iContext->setTexture("encodedTrees", 0, rendererData->encodedTreesTex);
120 iContext->setSamplerState("encodedTreesSampler", 0, renderer->getRenderStates().commonSamplerStates[3]);
121
122 if (rendererData->isValueUint) {
123 iContext->setTexture("tilesValue_uint", 1, rendererData->value.tilesTex);
124 iContext->setSamplerState("tilesValue_uintSampler", 1, renderer->getRenderStates().commonSamplerStates[rendererData->value.sampler]);
125 }
126 else
127 {
128 iContext->setTexture("tilesValue_srgb", 1, rendererData->value.tilesTex);
129 iContext->setSamplerState("tilesValue_srgbSampler", 1, renderer->getRenderStates().commonSamplerStates[rendererData->value.sampler]);
130 }
131
132 iContext->setTexture("tilesDepth", 2, rendererData->depth.tilesTex);
133 iContext->setSamplerState("tilesDepthSampler", 2, renderer->getRenderStates().commonSamplerStates[rendererData->depth.sampler]);
134
135 iContext->setVertexBuffers(&im360Renderer->fullScreenTriangle.vertices, 1);
137 }
138
139
140 constexpr const char* atlasBlitVS_es30 = R"(#version 300 es
141precision highp float;
142in vec2 a_POSITION;
143void main()
144{
145 gl_Position = vec4(a_POSITION, 0, 1);
146}
147)";
148
149 constexpr const char* atlasBlitFloatPS_es30 = R"(#version 300 es
150precision highp float;
151precision highp sampler2DArray;
152uniform Params {
153 int sourceLayer;
154};
155uniform sampler2DArray source;
156out vec4 destination;
157void main()
158{
159 destination = texelFetch(source, ivec3(floor(gl_FragCoord.xy), sourceLayer), 0);
160}
161)";
162
163 constexpr const char* atlasBlitUIntPS_es30 = R"(#version 300 es
164precision highp float;
165precision highp int;
166precision highp usampler2DArray;
167uniform Params {
168 int sourceLayer;
169};
170uniform usampler2DArray source;
171out uvec4 destination;
172void main()
173{
174 destination = texelFetch(source, ivec3(floor(gl_FragCoord.xy), sourceLayer), 0);
175}
176)";
177
178
179 void atlasBlitInit(Context* context, Image360::RendererExtension* rendererExtension)
180 {
181 if (context->device->getType() != Cogs::GraphicsDeviceType::OpenGLES30) {
182 return;
183 }
184 auto& atlasBlit = rendererExtension->atlasBlit;
185
186 Cogs::IGraphicsDevice* device = context->device;
187 Cogs::IEffects* effects = device->getEffects();
188 Cogs::IBuffers* buffers = device->getBuffers();
189 Cogs::ITextures* textures = device->getTextures();
190 Cogs::IRenderTargets* renderTargets = device->getRenderTargets();
191
192 // Reflection-dependent setup (input layout, bindings) for atlasBlit.f/.u is deferred to
193 // RendererExtension::isReady(), which is polled until each effect's compile has settled.
194 atlasBlit.f.effect = effects->loadEffectSource(atlasBlitVS_es30, atlasBlitFloatPS_es30);
195 atlasBlit.u.effect = effects->loadEffectSource(atlasBlitVS_es30, atlasBlitUIntPS_es30);
196
197 atlasBlit.paramBuffer = buffers->loadBuffer(nullptr, sizeof(uint32_t), Cogs::Usage::Dynamic, Cogs::AccessMode::Write, Cogs::BindFlags::ConstantBuffer);
198
199 atlasBlit.samplerState = textures->loadSamplerState({
204 .comparisonFunction = Cogs::SamplerState::ComparisonFunction::Never,
205 .maxAnisotropy = 1,
206 .borderColor = { 0, 0, 0, 1 }
207 });
208
209 atlasBlit.depthStencilState = renderTargets->loadDepthStencilState({
210 .depthEnabled = false,
211 .writeEnabled = true,
212 .depthFunction = Cogs::DepthStencilState::Always
213 });
214
215 atlasBlit.blendState = renderTargets->loadBlendState({
216 .enabled = 0,
217 .sourceBlend = Cogs::BlendState::Blend::One,
218 .destinationBlend = Cogs::BlendState::Blend::Zero,
219 .operation = Cogs::BlendState::BlendOperation::Add
220 });
221 }
222
223 bool atlasTileBlit(Context* context, const Image360::RendererExtension* rendererExtension,
224 Cogs::TextureHandle dstTex, uint32_t dstLayer,
225 Cogs::TextureHandle srcTex, uint32_t srcLayer,
226 uint32_t w, uint32_t h, Cogs::TextureFormat fmt)
227 {
228 bool formatIsFloat = true;
229 switch (fmt) {
230 case Cogs::DataFormat::R8G8B8A8_UNORM:
231 case Cogs::DataFormat::R8G8B8A8_UNORM_SRGB:
232 formatIsFloat = true;
233 if (rendererExtension->atlasBlit.f.effectStatus != Cogs::ResourceStatus::Ready) {
234 return false;
235 }
236 break;
237 case Cogs::DataFormat::R16_UINT:
238 formatIsFloat = false;
239 if (rendererExtension->atlasBlit.u.effectStatus != Cogs::ResourceStatus::Ready) {
240 return false;
241 }
242 break;
243 default:
244 LOG_ERROR_ONCE(logger, "Trying to blit unsupported format: %d", static_cast<uint32_t>(fmt));
245 return false;
246 }
247
248 Cogs::IGraphicsDevice* device = context->device;
249 Cogs::IRenderTargets* renderTargets = device->getRenderTargets();
250 Cogs::IContext* immediateContext = device->getImmediateContext();
251
253 .texture = dstTex,
254 .layerIndex = static_cast<uint16_t>(dstLayer),
255 .numLayers = 1,
256 .levelIndex = 0
257 };
258 Cogs::RenderTargetHandle renderTarget = renderTargets->createRenderTarget(&view, 1);
259
260 if(device->getCapabilities()->getDeviceCapabilities().RenderPass){
262 info.renderTargetHandle = renderTarget;
263 info.depthStencilHandle = Cogs::DepthStencilHandle::NoHandle;
264 info.loadOp[0] = Cogs::LoadOp::Clear;
265 info.storeOp[0] = Cogs::StoreOp::Store;
266 info.clearValue[0][0] = 0.0;
267 info.clearValue[0][1] = 0.0;
268 info.clearValue[0][2] = 0.0;
269 info.clearValue[0][3] = 0.0;
270 info.depthLoadOp = Cogs::LoadOp::Undefined;
271 info.depthStoreOp = Cogs::StoreOp::Discard;
272 immediateContext->beginRenderPass(info);
273 }
274 else{
275 immediateContext->setRenderTarget(renderTarget, Cogs::DepthStencilHandle::NoHandle);
276 }
277 immediateContext->setViewport(0.f, 0.f, static_cast<float>(w), static_cast<float>(h));
278 immediateContext->updateBuffer(rendererExtension->atlasBlit.paramBuffer, &srcLayer, sizeof(uint32_t));
279 if (formatIsFloat) {
280 immediateContext->setEffect(rendererExtension->atlasBlit.f.effect);
281 immediateContext->setInputLayout(rendererExtension->atlasBlit.f.inputLayout);
282 immediateContext->setConstantBuffer(rendererExtension->atlasBlit.f.paramBinding, rendererExtension->atlasBlit.paramBuffer);
283 immediateContext->setTexture(rendererExtension->atlasBlit.f.srcTexBinding, srcTex);
284 immediateContext->setSamplerState(rendererExtension->atlasBlit.f.srcSamplerBinding, rendererExtension->atlasBlit.samplerState);
285 }
286 else {
287 immediateContext->setEffect(rendererExtension->atlasBlit.u.effect);
288 immediateContext->setInputLayout(rendererExtension->atlasBlit.u.inputLayout);
289 immediateContext->setConstantBuffer(rendererExtension->atlasBlit.u.paramBinding, rendererExtension->atlasBlit.paramBuffer);
290 immediateContext->setTexture(rendererExtension->atlasBlit.u.srcTexBinding, srcTex);
291 immediateContext->setSamplerState(rendererExtension->atlasBlit.u.srcSamplerBinding, rendererExtension->atlasBlit.samplerState);
292 }
293 immediateContext->setVertexBuffers(&rendererExtension->fullScreenTriangle.vertices, 1);
294 immediateContext->setDepthStencilState(rendererExtension->atlasBlit.depthStencilState);
295 immediateContext->setBlendState(rendererExtension->atlasBlit.blendState);
296 immediateContext->draw(Cogs::PrimitiveType::TriangleStrip, 0, 4);
297
298 if(!device->getCapabilities()->getDeviceCapabilities().RenderPass){
300 }
301 renderTargets->releaseRenderTarget(renderTarget);
302
303 return true;
304 }
305
306 // Polls a single atlasBlit shader variant (f or u) and lazily finishes its reflection-dependent
307 // setup once compiled. Returns true once the variant has settled (either Ready or permanently
308 // Error) so callers do not wait forever.
309 bool pollAtlasBlitVariant(Image360::RendererExtension* rendererExtension, Image360::RendererExtension::AtlasBlitVariant& variant)
310 {
311 Cogs::IEffects* effects = rendererExtension->device->getEffects();
312 Cogs::IBuffers* buffers = rendererExtension->device->getBuffers();
313
314 Cogs::ResourceStatus status = effects->checkEffect(variant.effect);
315
316 if (status == Cogs::ResourceStatus::Ready && variant.effectStatus != Cogs::ResourceStatus::Ready) {
317 variant.inputLayout = buffers->loadInputLayout(&rendererExtension->fullScreenTriangle.streamsLayout.vertexFormats[0], 1, variant.effect);
318 variant.srcTexBinding = effects->getTextureBinding(variant.effect, "source", 0);
319 variant.srcSamplerBinding = effects->getSamplerStateBinding(variant.effect, "sourceSampler", 0);
320 variant.paramBinding = effects->getConstantBufferBinding(variant.effect, "Params");
321 }
322
323 if (status == Cogs::ResourceStatus::Error && variant.effectStatus != Cogs::ResourceStatus::Error) {
324 LOG_ERROR(logger, "Image360::RendererExtension: Failed to build atlas blit effect.");
325 }
326
327 variant.effectStatus = status;
328
329 // Treat a permanently failed compile as settled too, so callers waiting for readiness don't
330 // block forever - atlasTileBlit() falls back to a plain copyTexture() when status is Error.
331 return status != Cogs::ResourceStatus::Pending;
332 }
333
334}
335
336
338{
339 if (context->device->getType() != Cogs::GraphicsDeviceType::OpenGLES30) {
340 // atlasBlit isn't used on this device type (atlasBlitInit didn't load any effects), nothing to wait for.
341 return true;
342 }
343
344 bool fSettled = pollAtlasBlitVariant(this, atlasBlit.f);
345 bool uSettled = pollAtlasBlitVariant(this, atlasBlit.u);
346 return fSettled && uSettled;
347}
348
349
351{
352 this->device = device;
353 this->context = context;
354 im360System = ExtensionRegistry::getExtensionSystem<Image360System>(context);
355
356 IBuffers* buffers = device->getBuffers();
357
358
359 Cogs::VertexElement element{
361 };
362 fullScreenTriangle.streamsLayout.vertexFormats[0] = VertexFormats::createVertexFormat(element);
363 fullScreenTriangle.streamsLayout.numStreams = 1;
364 fullScreenTriangle.streamsLayout.updateHash();
365
366 static const float fullScreenTriangleVertexData[] = {
367 -1.f, -1.f,
368 3.f, -1.f,
369 -1.f, 3.f
370 };
371 fullScreenTriangle.vertices = buffers->loadVertexBuffer(fullScreenTriangleVertexData,
372 sizeof(fullScreenTriangleVertexData) / sizeof(fullScreenTriangleVertexData[0]),
373 fullScreenTriangle.streamsLayout.vertexFormats[0]);
374 atlasBlitInit(context, this);
375}
376
377
378void Cogs::Core::Image360::RendererExtension::release()
379{
380 IGraphicsDevice* device = context->renderer->getDevice();
381 IBuffers* buffers = device->getBuffers();
382 ITextures* textures = device->getTextures();
383 if (HandleIsValid(fullScreenTriangle.vertices)) {
384 buffers->releaseBuffer(fullScreenTriangle.vertices);
385 fullScreenTriangle.vertices = BufferHandle::NoHandle;
386 }
387 for (Cogs::TextureHandle handle : texturesToRelease) {
388 textures->releaseTexture(handle);
389 }
390 texturesToRelease.clear();
391}
392
393
394void Cogs::Core::Image360::RendererExtension::releaseRenderingResources(RendererExtensionData& rendererData)
395{
396 IGraphicsDevice* device = context->renderer->getDevice();
397 ITextures* textures = device->getTextures();
398 IBuffers* buffers = device->getBuffers();
399
400 if (HandleIsValid(rendererData.constants)) {
401 buffers->releaseBuffer(rendererData.constants);
402 rendererData.constants = Cogs::BufferHandle::NoHandle;
403 }
404
405 if (HandleIsValid(rendererData.encodedTreesTex)) {
406 textures->releaseTexture(rendererData.encodedTreesTex);
407 rendererData.encodedTreesTex = Cogs::TextureHandle::NoHandle;
408 }
409
410 if (HandleIsValid(rendererData.value.tilesTex)) {
411 textures->releaseTexture(rendererData.value.tilesTex);
412 rendererData.value.tilesTex = Cogs::TextureHandle::NoHandle;
413 }
414
415 if (HandleIsValid(rendererData.depth.tilesTex)) {
416 textures->releaseTexture(rendererData.depth.tilesTex);
417 rendererData.depth.tilesTex = Cogs::TextureHandle::NoHandle;
418 }
419 rendererData.depth.tilesData.clear();
420}
421
422
423void Cogs::Core::Image360::RendererExtension::handleEvent(uint32_t eventId, const DrawContext * renderingContext)
424{
425 if (!renderingContext) return;
426
427 switch (eventId) {
429 RenderResources & resources = renderingContext->renderer->getRenderResources();
430
431 IContext* deviceContext = renderingContext->deviceContext;
432 ITextures* textures = renderingContext->device->getTextures();
433 IBuffers* buffers = renderingContext->device->getBuffers();
434
435 // Release last frame's textures;
436 for (Cogs::TextureHandle handle : texturesToRelease) {
437 textures->releaseTexture(handle);
438 }
439 texturesToRelease.clear();
440
441
442 for (Image360Component& im360Comp : im360System->pool) {
443
444 Image360Data& im360Data = im360System->getData(&im360Comp);
445 RendererExtensionData& rendererData = im360Data.rendererData;
446
447 if ((im360Data.state == Image360Data::State::WaitingForBaseLevel) || (im360Data.state == Image360Data::State::Running))
448 {
449 im360Data.rendererData.baseSize = im360Data.config.baseSize;
450 im360Data.rendererData.noDataDepth = im360Data.config.noDataDepth;
451 if (im360Data.config.valueChannel < im360Data.config.channels.size()) {
452 const Config::Channel& channel = im360Data.config.channels[im360Data.config.valueChannel];
453 rendererData.value.scale = channel.scale;
454 rendererData.value.bias = channel.bias;
455 switch (channel.dataType) {
456 case Config::Channel::DataType::U16: [[fallthrough]];
458 rendererData.value.sampler = 3;
459 break;
460 default:
461 rendererData.value.sampler = 1;
462 break;
463 }
464 }
465 else {
466 rendererData.value.scale = 1.f;
467 rendererData.value.bias = 0.f;
468 }
469 rendererData.value.scale /= (im360Comp.valueDomainMax - im360Comp.valueDomainMin);
470 rendererData.value.bias = (rendererData.value.bias - im360Comp.valueDomainMin) / (im360Comp.valueDomainMax - im360Comp.valueDomainMin);
471
472
473 if (im360Data.config.hasDepth) {
474 const Config::Channel& channel = im360Data.config.channels[im360Data.config.depthChannel];
475 rendererData.depth.scale = channel.scale;
476 rendererData.depth.bias = channel.bias;
477 switch (channel.dataType) {
478 case Config::Channel::DataType::U16: [[fallthrough]];
480 rendererData.depth.sampler = 3;
481 break;
482 default:
483 rendererData.depth.sampler = 1;
484 break;
485 }
486 }
487
488 if (!HandleIsValid(rendererData.constants)) {
489 rendererData.constants = buffers->loadBuffer(nullptr, sizeof(Constants), Cogs::Usage::Dynamic, Cogs::AccessMode::Write, Cogs::BindFlags::ConstantBuffer, 0);
490 }
491
492 if (HandleIsValid(rendererData.encodedTreesTex)) {
493 texturesToRelease.push_back(rendererData.encodedTreesTex);
494 rendererData.encodedTreesTex = Cogs::TextureHandle::NoHandle;
495 }
496
497 if(!im360Data.lodTree.data.empty()) {
498 TextureDescription desc{};
499 desc.target = Cogs::ResourceDimensions::Texture2D;
500 desc.width = static_cast<uint32_t>(im360Data.lodTree.data.size());
501 desc.height = 1;
502 desc.format = Cogs::TextureFormat::R16_SINT;
503 desc.flags = Cogs::TextureFlags::Default;
504
505 TextureData textureData(im360Data.lodTree.data.data(), TextureExtent{ desc.width, 1, 1 }, 1, 1, 1, desc.format);
506 rendererData.encodedTreesTex = textures->loadTexture(desc, &textureData);
507
508 if (rendererData.currentTreeSize != desc.width) {
509 rendererData.currentTreeSize = desc.width;
510 LOG_TRACE(logger, "Current tree size: %u", rendererData.currentTreeSize);
511 }
512 }
513
514
515 uint32_t cacheItemCount = std::max(6u, static_cast<uint32_t>(im360Data.cache.items.size()));
516 bool resizeCache = (!HandleIsValid(im360Data.rendererData.value.tilesTex) ||
517 (rendererData.gpuAllocatedCacheItemCount < cacheItemCount) ||
518 (cacheItemCount < rendererData.gpuAllocatedCacheItemCount / 2));
519
520 if (resizeCache) {
521
522 Cogs::ResourceDimensions target = Cogs::ResourceDimensions::Unknown;
523 rendererData.gpuAllocatedCacheItemCount = cacheItemCount + (cacheItemCount + 9) / 10; // No aggressive over-allocation since we don't grow one-by-one.
524
525 rendererData.cacheLayout.cols = 1;
526 rendererData.cacheLayout.rows = 1;
527 rendererData.cacheLayout.layers = rendererData.gpuAllocatedCacheItemCount;
528 target = Cogs::ResourceDimensions::Texture2DArray;
529
530 // ------- Resize value texture
531 {
532 TextureDescription desc{};
533 desc.target = target;
534 desc.width = rendererData.cacheLayout.cols * im360Data.config.baseSize;
535 desc.height = rendererData.cacheLayout.rows * im360Data.config.baseSize;
536 desc.layers = rendererData.cacheLayout.layers;
537 desc.flags = Cogs::TextureFlags::Default;
538
539 assert(im360Data.config.valueChannel < im360Data.config.channels.size());
540 switch (im360Data.config.channels[im360Data.config.valueChannel].dataType) {
541
542 case Config::Channel::DataType::SRGB8_JPEG: [[fallthrough]];
543 case Config::Channel::DataType::SRGB8_PNG: [[fallthrough]]; // D3D11 doesn't support 3-channel 8-bit format, probably promoted in GL anyways.
545 desc.format = Cogs::DataFormat::R8G8B8A8_UNORM_SRGB;
546 break;
547 case Config::Channel::DataType::U16: [[fallthrough]];
549 desc.format = Cogs::DataFormat::R16_UINT;
550 break;
551 default:
552 assert(false && "Invalid enum value");
553 break;
554 }
555 Cogs::TextureHandle tilesValueOldTex = rendererData.value.tilesTex;
556 rendererData.value.tilesTex = textures->loadTexture(desc, nullptr);
557 if (HandleIsValid(tilesValueOldTex)) {
558 uint32_t toCopy = std::min(rendererData.gpuActiveCacheItemCount, rendererData.gpuAllocatedCacheItemCount);
559 for (uint32_t i = 0; i < toCopy; i++) {
560 if (im360Data.cache.items[i].value.state == Cache::Item::State::Resident) {
561 if (!atlasTileBlit(context, this,
562 rendererData.value.tilesTex, i,
563 tilesValueOldTex, i,
564 im360Data.config.baseSize, im360Data.config.baseSize, desc.format))
565 {
566 deviceContext->copyTexture(rendererData.value.tilesTex,
567 i, 0, 0, 0,
568 tilesValueOldTex, i);
569 }
570 }
571 }
572 texturesToRelease.push_back(tilesValueOldTex);
573 }
574 }
575
576 // ------- Resize depth texture if enabled
577 if (im360Data.config.hasDepth) {
578
579 TextureDescription desc{};
580 desc.target = target;
581 desc.width = rendererData.cacheLayout.cols * im360Data.config.baseSize;
582 desc.height = rendererData.cacheLayout.rows * im360Data.config.baseSize;
583 desc.layers = rendererData.cacheLayout.layers;
584 desc.flags = Cogs::TextureFlags::Default;
585 switch (im360Data.config.channels[im360Data.config.depthChannel].dataType) {
586 case Config::Channel::DataType::U16: [[fallthrough]];
588 desc.format = Cogs::DataFormat::R16_UINT;
589 break;
590 default:
591 assert(false && "Invalid enum value");
592 break;
593 }
594 Cogs::TextureHandle tilesDepthOldTex = rendererData.depth.tilesTex;
595 rendererData.depth.tilesTex = textures->loadTexture(desc, nullptr);
596 if (HandleIsValid(tilesDepthOldTex)) {
597 uint32_t toCopy = std::min(rendererData.gpuActiveCacheItemCount, rendererData.gpuAllocatedCacheItemCount);
598 for (uint32_t i = 0; i < toCopy; i++) {
599 if (im360Data.cache.items[i].depth.state == Cache::Item::State::Resident) {
600 if (!atlasTileBlit(context, this,
601 rendererData.depth.tilesTex, i,
602 tilesDepthOldTex, i,
603 im360Data.config.baseSize, im360Data.config.baseSize, desc.format))
604 {
605 deviceContext->copyTexture(rendererData.depth.tilesTex,
606 i, 0, 0, 0,
607 tilesDepthOldTex, i);
608 }
609 }
610 }
611 texturesToRelease.push_back(tilesDepthOldTex);
612 }
613
614 rendererData.depth.tilesData.resize(rendererData.gpuAllocatedCacheItemCount);
615 }
616
617 LOG_DEBUG(logger, "gpuAllocatedCacheItemCount=%u", rendererData.gpuAllocatedCacheItemCount);
618 }
619
620 for (Fetcher::LoadItem& loadItem : im360Data.fetcher.itemsUploading) {
621 Cache::Item& item = im360Data.cache.items[loadItem.slotIx];
622
623 bool consumed = false;
624 if (loadItem.channelIx == im360Data.config.valueChannel) {
625 if (item.value.state == Cache::Item::State::Loaded) {
626 uint32_t x = 0;
627 uint32_t y = 0;
628 uint32_t slice = loadItem.slotIx;
629
630 RenderTexture* texture = resources.getRenderTexture(loadItem.texture);
631 deviceContext->copyTexture(rendererData.value.tilesTex,
632 slice, x, y, 0,
633 texture->textureHandle, 0);
634 item.value.state = Cache::Item::State::Resident;
635 }
636 consumed = true;
637 }
638
639 if (loadItem.channelIx == im360Data.config.depthChannel) {
640 if (item.depth.state == Cache::Item::State::Loaded) {
641 uint32_t x = 0;
642 uint32_t y = 0;
643 uint32_t slice = loadItem.slotIx;
644
645 RenderTexture* texture = resources.getRenderTexture(loadItem.texture);
646 deviceContext->copyTexture(rendererData.depth.tilesTex,
647 slice, x, y, 0,
648 texture->textureHandle, 0);
649 item.depth.state = Cache::Item::State::Resident;
650
651 size_t tileByteSize = sizeof(uint16_t) * im360Data.config.baseSize * im360Data.config.baseSize;
652 if (loadItem.buffer && loadItem.buffer->size() == tileByteSize) {
653
654 if (0 <= loadItem.slotIx && size_t(loadItem.slotIx) < rendererData.depth.tilesData.size()) {
655 rendererData.depth.tilesData[loadItem.slotIx] = std::move(loadItem.buffer);
656 }
657 }
658 }
659 consumed = true;
660 }
661
662 if (!consumed) {
663 LOG_WARNING(logger, "Unexpected load item not uploaded to GPU");
664 }
665 }
666 im360Data.fetcher.itemsUploading.clear();
667
668 rendererData.gpuActiveCacheItemCount = static_cast<uint32_t>(im360Data.cache.items.size());
669 }
670 else {
671 releaseRenderingResources(rendererData);
672 }
673 }
674 break;
675 }
676
678 break;
679
680 default:
681 break;
682 }
683}
684
685void Cogs::Core::Image360::RendererExtension::generateCommands(const RenderTaskContext * renderingContext, RenderList * renderList)
686{
687 if (!renderingContext) return;
688 if (!HandleIsValid(im360System->material)) return;
689
690 for (const Image360Component& im360Comp : im360System->pool) {
691 if (!im360Comp.isVisible()) continue;
692
693 Image360Data& im360Data = im360System->getData(&im360Comp);
694 if (im360Data.state != Image360Data::State::Running) continue;
695
696 if (!HandleIsValid(im360Data.materialInstance)) continue;
697 const MaterialInstance* materialInstance = im360Data.materialInstance.resolve();
698
699 RenderItem& renderItem = renderList->createCustom(&fullScreenTriangle.streamsLayout);
700 renderItem.lod = im360Comp.lod;
701 renderItem.layer = im360Comp.layer;
702 renderItem.cullingIndex = ~0u;;
703 renderItem.objectId = im360Comp.objectId;
704 renderItem.flags |= (materialInstance->instanceFlags & MaterialFlags::CustomBucket) != 0 ? RenderItemFlags::CustomBucket : RenderItemFlags::None;
705 renderItem.flags |= materialInstance->hasTransparency() ? RenderItemFlags::Transparent : RenderItemFlags::None;
706 if (materialInstance->isBackdrop() || ((renderItem.layer & RenderLayers::Sky)) != RenderLayers::None) {
707 renderItem.flags |= RenderItemFlags::Backdrop;
708 }
709 renderItem.materialInstance = materialInstance;
710 getTransparencyState(renderingContext->renderer->getRenderStates(), materialInstance, renderItem);
711 renderItem.drawOrder = materialInstance->options.drawOrder != 0 ? materialInstance->options.drawOrder : im360Comp.drawOrder;
712 renderItem.setCallbackData(this);
713 renderItem.setCallbackData2(&im360Data.rendererData);
714 renderItem.callback = image360RenderCallback;
715 }
716}
A Context instance contains all the services, systems and runtime components needed to use Cogs.
Definition: Context.h:83
class IRenderer * renderer
Renderer.
Definition: Context.h:228
std::unique_ptr< class Variables > variables
Variables service instance.
Definition: Context.h:180
virtual IGraphicsDevice * getDevice()=0
Get the graphics device used by the renderer.
RenderLayers layer
Layer mask used to determine visibility for a given camera viewport.
int32_t drawOrder
Draw order within a render bucke.
constexpr bool isVisible() const
Check if the entity is visible or not.
uint32_t objectId
Object identifier passed to rendering commands.
Contains render resources used by the renderer.
Core renderer system.
Definition: Renderer.h:29
RenderStates & getRenderStates() override
Get the reference to the RenderStates structure.
Definition: Renderer.h:70
IGraphicsDevice * getDevice() override
Get the graphics device used by the renderer.
Definition: Renderer.h:46
Represents a graphics device used to manage graphics resources and issue drawing commands.
virtual IEffects * getEffects()=0
Get a pointer to the effect management interface.
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 IBuffers * getBuffers()=0
Get a pointer to the buffer management interface.
virtual IRenderTargets * getRenderTargets()=0
Get a pointer to the render target management interface.
Log implementation class.
Definition: LogManager.h:140
Contains the Engine, Renderer, resource managers and other systems needed to run Cogs....
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
@ OpenGLES30
Graphics device using the OpenGLES 3.0 API.
ResourceStatus
Status of an asynchronously loaded resource, such as an effect or a pipeline.
Definition: Common.h:198
@ Pending
The resource is still loading.
@ Error
The resource failed to load.
@ Ready
The resource has loaded successfully and is ready for use.
@ VertexData
Per vertex data.
@ TriangleStrip
Triangle strip.
@ TriangleList
List of triangles.
@ Position
Position semantic.
@ Write
The buffer can be mapped and written to by the CPU after creation.
Definition: Flags.h:50
@ ConstantBuffer
The buffer can be bound as input to effects as a constant buffer.
Definition: Flags.h:72
float valueDomainMin
Set the source domain for scalar values, see 360.json's bias and scale to account for datatype.
float valueDomainMax
Set the source domain for scalar values, see 360.json's bias and scale to account for datatype.
@ SRGB8_JPEG
8-bit colors in SRGB color space stored as JPEG (.jpg).
@ U16_ZST
16-bit unsigned values stored as little endian raw values that are subsequently zstd compressed.
@ SRGBA8_PNG
8-bit colors in SRGB color space and a alpha channel (zero is transparent) stored as PNG (....
@ SRGB8_PNG
8-bit colors in SRGB color space stored as PNG (.png).
@ U16
16-bit unsigned values stored as little endian raw values.
uint32_t noDataDepth
Depth value that corresponds to noData.
Definition: Image360.h:47
uint32_t baseSize
Base image size of a cached tile. From json.
Definition: Image360.h:46
uint8_t valueChannel
Data channel to be used as value data. From component.
Definition: Image360.h:49
uint8_t depthChannel
Data channel that contains depth data. From json.
Definition: Image360.h:50
std::vector< Channel > channels
Data channels to use. From json.
Definition: Image360.h:51
bool hasDepth
If data has depth and component wants depth.
Definition: Image360.h:58
uint32_t gpuAllocatedCacheItemCount
Number of tiles allocated in current GPU cache texture.
Definition: Image360.h:175
uint32_t gpuActiveCacheItemCount
Number of tiles in current GPU cache that contain data.
Definition: Image360.h:174
void handleEvent(uint32_t eventId, const DrawContext *renderingContext) override
Called when rendering events occur.
void initialize(Context *context, IGraphicsDevice *device) override
Initialize the extension using the given context and device.
@ CustomBucket
Items with this flag should be put in Custom rendering buckets.
Definition: Material.h:64
Material instances represent a specialized Material combined with state for all its buffers and prope...
bool hasTransparency() const
Get if this instance has any transparency and should be rendered with blending enabled.
bool isBackdrop() const
Get if geometry rendered with this material instance is to be treated as backdrops.
MaterialOptions options
Material rendering options used by this instance.
uint16_t instanceFlags
Material instance flags.
VertexFormatHandle vertexFormats[maxStreams]
int32_t drawOrder
Ordering of draw items within a bucket.
Definition: RenderList.h:174
uint32_t objectId
Lower 6 of upper 8 bits are instance id bits, lower 24 bits are object id.
Definition: RenderList.h:176
RenderLayers layer
Visibility mask.
Definition: RenderList.h:172
@ 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
ResourceType * resolve() const
Resolve the handle, returning a pointer to the actual resource.
@ Always
Always evaluates to true.
static const Handle_t NoHandle
Represents a handle to nothing.
Definition: Common.h:78
Provides buffer management functionality.
Definition: IBuffers.h:13
virtual InputLayoutHandle loadInputLayout(const VertexFormatHandle *vertexFormats, const size_t count, EffectHandle effectHandle)=0
Loads a new input layout to map vertex flow between vertex buffers with the given vertexFormats to ef...
virtual BufferHandle loadBuffer(const void *data, const size_t size, Usage::EUsage usage, uint32_t accessMode, uint32_t bindFlags, uint32_t stride=0)=0
Loads a new buffer using the given data to populate the buffer.
virtual void releaseBuffer(BufferHandle bufferHandle)=0
Releases the buffer with the given bufferHandle.
virtual VertexBufferHandle loadVertexBuffer(const void *vertexData, const size_t count, const VertexFormat &vertexFormat)=0
Loads a new vertex buffer and populates it with the given data.
virtual const GraphicsDeviceCapabilities & getDeviceCapabilities() const
Gets the device capabilities in a structure.
Represents a graphics device context which can receive rendering commands.
Definition: IContext.h:43
virtual void setTexture(const StringView &name, unsigned int unit, TextureHandle textureHandle)=0
Sets the texture slot given by unit with the given name to contain the given texture.
virtual void setRasterizerState(const RasterizerStateHandle handle)=0
Set the current rasterizer state.
virtual void setBlendState(const BlendStateHandle handle, const float *constant=nullptr)=0
Set the current blend state.
virtual void setInputLayout(const InputLayoutHandle inputLayoutHandle)=0
Sets the current input layout.
virtual void setDepthStencilState(const DepthStencilStateHandle handle)=0
Set the current depth stencil state.
virtual void setConstantBuffer(const StringView &name, const BufferHandle bufferHandle, const uint32_t offset=0, const uint32_t size=~0u)=0
Sets a constant buffer to be bound to the given name and slot.
virtual void updateBuffer(BufferHandle bufferHandle, const void *data, size_t size)=0
Replace contents of buffer with new data.
virtual void setViewport(const float x, const float y, const float width, const float height)=0
Sets the current viewport to the given location and dimensions.
virtual void draw(PrimitiveType primitiveType, const size_t startVertex, const size_t numVertexes)=0
Draws non-indexed, non-instanced primitives.
virtual void beginRenderPass(const RenderPassInfo &info)=0
Begin a render pass.
virtual void setSamplerState(const StringView &name, unsigned int unit, SamplerStateHandle samplerStateHandle)=0
Sets the sampler slot given by unit with the given name to contain the given sampler state.
virtual void setVertexBuffers(const VertexBufferHandle *vertexBufferHandles, const size_t count, const uint32_t *strides, const uint32_t *offsets)=0
Sets the current vertex buffers.
virtual void setEffect(EffectHandle handle)=0
Set the current effect.
virtual void setRenderTarget(const RenderTargetHandle handle, const DepthStencilHandle depthStencilHandle)=0
Sets the current render target and an associated depth stencil target.
Provides effects and shader management functionality.
Definition: IEffects.h:158
virtual SamplerStateBindingHandle getSamplerStateBinding(EffectHandle effectHandle, const StringView &name, const unsigned int slot)=0
Get a handle to a sampler state object binding, mapping how to bind the sampler state to the given ef...
virtual ConstantBufferBindingHandle getConstantBufferBinding(EffectHandle effectHandle, const StringView &name)=0
Get a handle to a constant buffer binding, mapping how to bind a constant buffer to the given effect.
virtual TextureBindingHandle getTextureBinding(EffectHandle effectHandle, const StringView &name, const unsigned int slot)=0
Get a handle to a texture object binding, mapping how to bind textures to the given effect.
virtual EffectHandle loadEffectSource(const StringView &vsSource, const StringView &psSource, EffectFlags::EEffectFlags effectFlags=EffectFlags::None)=0
Load an effect created from the vertex and pixel shader sources given.
virtual ResourceStatus checkEffect(EffectHandle effectHandle)=0
Check the load status of the effect with the given effectHandle.
Provides render target management functionality.
virtual BlendStateHandle loadBlendState(const BlendState &blendState)=0
Load a blend state object.
virtual DepthStencilStateHandle loadDepthStencilState(const DepthStencilState &depthStencilState)=0
Load a depth stencil state object.
virtual void releaseRenderTarget(RenderTargetHandle renderTargetHandle)=0
Release the render target with the given renderTargetHandle.
virtual RenderTargetHandle createRenderTarget(TextureHandle textureHandle)
Create a render target using the given texture to render into.
Provides texture management functionality.
Definition: ITextures.h:40
virtual SamplerStateHandle loadSamplerState(const SamplerState &state)=0
Load a sampler state object.
virtual void releaseTexture(TextureHandle textureHandle)=0
Release the texture with the given textureHandle.
virtual TextureHandle loadTexture(const unsigned char *bytes, unsigned int width, unsigned int height, TextureFormat format, unsigned int flags=0)=0
Load a texture using the given data to populate the texture contents.
Describes a single render target view and which resources to use from the underlying texture.
TextureHandle texture
Texture handle.
@ Clamp
Texture coordinates are clamped to the [0, 1] range.
Definition: SamplerState.h:17
@ MinMagMipPoint
Point sampling for both minification and magnification.
Definition: SamplerState.h:33
@ Default
Default usage, the texture can be loaded once and bound and sampled in shaders.
Definition: Flags.h:116
@ Dynamic
Buffer will be loaded and modified with some frequency.
Definition: Flags.h:30
Vertex element structure used to describe a single data element in a vertex for the input assembler.
Definition: VertexFormat.h:38