1#include "Renderer/RenderStateUpdater.h"
2#include "../Systems/OctSystem.h"
5#include "Foundation/Logging/Logger.h"
14void Cogs::Core::Volumetric::OctAtlas::reset(
const DrawContext * renderingContext,
const OctData& octData,
const uint32_t tileSize,
const uint32_t gpuCacheSize,
const uint32_t currentTimestamp)
16 auto * device = renderingContext->device;
18 auto * iContext = device->getImmediateContext();
19 auto * textures = device->getTextures();
21 if (
HandleIsValid(textureAtlas0)) textures->releaseTexture(textureAtlas0);
24 if (
HandleIsValid(textureAtlas1)) textures->releaseTexture(textureAtlas1);
27 slots.resize(gpuCacheSize * gpuCacheSize * gpuCacheSize);
28 for (
size_t i = 0; i < slots.size(); i++) {
29 slots[i].tileKey = ~uint64_t(0);
30 slots[i].timestampNeeded = currentTimestamp - 1u;
31 slots[i].timestapUpdated = currentTimestamp - 1u;
32 slots[i].flags = Slot::None;
38 for (
size_t i = 1; i < slots.size(); i++) {
39 slotsLRU.push_back(uint32_t(i));
43 TextureDescription desc;
44 auto size = tileSize * gpuCacheSize;
45 desc.target = ResourceDimensions::Texture3D;
54 desc.format = TextureFormat::R32G32B32A32_FLOAT;
55 textureAtlas0 = textures->loadTexture(desc,
nullptr);
56 switch (octData.source)
58 case OctSource::Value:
break;
59 case OctSource::ValueAge:
60 desc.format = TextureFormat::R32_FLOAT;
61 textureAtlas1 = textures->loadTexture(desc,
nullptr);
68 for (
auto & h : toCopy) {
69 textures->releaseTexture(h.texture0);
70 if(
HandleIsValid(h.texture1)) textures->releaseTexture(h.texture1);
73 for (
auto & h : stagingUnused) {
74 textures->releaseTexture(h.texture0);
75 if (
HandleIsValid(h.texture1)) textures->releaseTexture(h.texture1);
77 stagingUnused.clear();
80 while (stagingUnused.size() < 10) {
81 TextureDescription stagingDesc;
82 stagingDesc.target = ResourceDimensions::Texture3D;
83 stagingDesc.width = tileSize;
84 stagingDesc.height = tileSize;
85 stagingDesc.depth = tileSize;
86 stagingDesc.layers = 1;
87 stagingDesc.faces = 1;
88 stagingDesc.levels = 1;
89 stagingDesc.samples = 1;
90 stagingDesc.format = TextureFormat::R32G32B32A32_FLOAT;
91 stagingDesc.flags = TextureFlags::UsageWriteStaging;
92 auto tex0 = textures->loadTexture(stagingDesc,
nullptr);
94 switch (octData.source)
96 case OctSource::Value:
break;
97 case OctSource::ValueAge:
98 stagingDesc.format = TextureFormat::R32_FLOAT;
99 tex1 = textures->loadTexture(stagingDesc,
nullptr);
102 stagingUnused.push_back(Item{ tex0, tex1, {}, {} });
104 assert(!stagingUnused.empty() &&
"Must have at least one staging texture");
107 toCopy.push_back(stagingUnused.back());
108 stagingUnused.pop_back();
109 uint32_t rowPitch, depthPitch;
110 if (
auto* ptr =
reinterpret_cast<char*
>(iContext->map(toCopy.back().texture0,
MapMode::Write, &rowPitch, &depthPitch)); ptr !=
nullptr) {
111 for (
size_t k = 0; k < tileSize; k++) {
112 for (
size_t j = 0; j < tileSize; j++) {
113 auto * p =
reinterpret_cast<glm::vec4*
>(ptr + k*depthPitch + j*rowPitch);
114 for (
size_t i = 0; i < tileSize; i++) {
115 auto ii = (i >> 3) & 1;
116 auto jj = (j >> 3) & 1;
117 auto kk = (k >> 3) & 1;
118 *p++ = glm::vec4(1, 1, 1, (ii ^ jj ^ kk) ? 1.f : 0.f);
122 iContext->unmap(toCopy.back().texture0);
125 if (
auto* ptr =
reinterpret_cast<char*
>(iContext->map(toCopy.back().texture0,
MapMode::Write, &rowPitch, &depthPitch)); ptr !=
nullptr) {
126 for (
size_t k = 0; k < tileSize; k++) {
127 for (
size_t j = 0; j < tileSize; j++) {
128 auto * p =
reinterpret_cast<float*
>(ptr + k*depthPitch + j*rowPitch);
129 for (
size_t i = 0; i < tileSize; i++) {
130 auto ii = (i >> 3) & 1;
131 auto jj = (j >> 3) & 1;
132 auto kk = (k >> 3) & 1;
133 *p++ = (ii ^ jj ^ kk) ? 1.f : 0.f;
137 iContext->unmap(toCopy.back().texture1);
140 toCopy.back().slot = 0;
141 toCopy.back().delay = 1;
145unsigned Cogs::Core::Volumetric::OctAtlas::checkTile(
const uint64_t tileKey,
const uint32_t nodeTimestamp,
const uint32_t currentTimestamp)
147 auto it = slotsLUT.find(tileKey);
148 if (it != slotsLUT.end()) {
149 auto & slot = slots[it->second];
150 slot.timestampNeeded = currentTimestamp;
152 auto nodeAge = currentTimestamp - nodeTimestamp;
153 auto cacheAge = currentTimestamp - slot.timestapUpdated;
155 if ((slot.flags & Slot::InStaging) != 0) {
159 else if (nodeAge < cacheAge || (slot.flags & Slot::Invalid) != 0) {
161 slot.flags = (Slot::Flags)(slot.flags | Slot::Invalid);
171 return std::numeric_limits<unsigned>::max();
175void Cogs::Core::Volumetric::OctAtlas::enforceOrder(
const uint32_t currentTimestamp)
177 slotsLRU.sort([&](
const auto& a,
const auto& b) ->
bool
179 return (currentTimestamp - slots[a].timestampNeeded) > (currentTimestamp - slots[b].timestampNeeded);
184glm::uvec4 Cogs::Core::Volumetric::OctAtlas::slotPosition(
const OctComponent& octComp,
const uint64_t tileKey)
const
187 auto it = slotsLUT.find(tileKey);
188 if (it != slotsLUT.end()) {
190 if ((slots[it->second].flags & Slot::NoData) == 0) {
195 return glm::uvec4(slot % octComp.gpuCacheSize,
196 (slot / octComp.gpuCacheSize) % octComp.gpuCacheSize,
197 (slot / octComp.gpuCacheSize) / octComp.gpuCacheSize,
203void Cogs::Core::Volumetric::OctAtlas::handleStaging(
const DrawContext * renderingContext, OctComponent& octComp, OctData& octData,
const uint32_t currentTimestamp,
unsigned delay)
205 delay = std::max(1u, delay);
207 auto * device = renderingContext->device;
208 auto * iContext = device->getImmediateContext();
212 for (
auto & item : toCopy) {
215 if (item.delay == 0) {
216 unsigned i = octComp.tileSize*(item.slot % octComp.gpuCacheSize);
217 unsigned j = octComp.tileSize*((item.slot / octComp.gpuCacheSize) % octComp.gpuCacheSize);
218 unsigned k = octComp.tileSize*((item.slot / octComp.gpuCacheSize) / octComp.gpuCacheSize);
219 iContext->copyTexture(octData.atlas.textureAtlas0, 0, i, j, k, item.texture0, 0);
221 iContext->copyTexture(octData.atlas.textureAtlas1, 0, i, j, k, item.texture1, 0);
224 slots[item.slot].flags = OctAtlas::Slot::None;
229 enforceOrder(octData.currentTimestamp);
232 if (!stagingUnused.empty()) {
233 while (!octData.tileResponses.empty() && !stagingUnused.empty()) {
236 auto res = std::move(octData.tileResponses.back());
237 octData.tileResponses.pop_back();
239 auto it = slotsLUT.find(res->tileKey);
240 if (it != slotsLUT.end()) {
244 else if (slots[slotsLRU.front()].timestampNeeded != currentTimestamp) {
245 slot = slotsLRU.front();
246 slotsLRU.pop_front();
247 slotsLRU.push_back(slot);
249 octData.atlas.slotsLUT.erase(slots[slot].tileKey);
250 octData.atlas.slotsLUT[res->tileKey] = slot;
256 assert(res->data0.size() == octComp.tileSize * octComp.tileSize * octComp.tileSize);
258 slots[slot].tileKey = res->tileKey;
259 slots[slot].clientData = res->clientData;
260 slots[slot].timestapUpdated = res->timestamp;
263 toCopy.push_back(stagingUnused.back());
264 stagingUnused.pop_back();
265 auto & stage = toCopy.back();
269 uint32_t rowPitch, depthPitch;
270 if (
auto* ptr =
reinterpret_cast<char*
>(iContext->map(stage.texture0,
MapMode::Write, &rowPitch, &depthPitch)); ptr !=
nullptr) {
271 for (
size_t k = 0; k < octComp.tileSize; k++) {
272 for (
size_t j = 0; j < octComp.tileSize; j++) {
273 std::memcpy(ptr + k*depthPitch + j*rowPitch,
274 res->data0.data() + ((k*octComp.tileSize + j)*octComp.tileSize),
275 sizeof(glm::vec4)*octComp.tileSize);
279 iContext->unmap(stage.texture0);
282 assert(res->data1.size() ==
size_t(octComp.tileSize) *
size_t(octComp.tileSize) *
size_t(octComp.tileSize));
283 if (
auto* ptr =
reinterpret_cast<char*
>(iContext->map(stage.texture1,
MapMode::Write, &rowPitch, &depthPitch)); ptr !=
nullptr) {
284 for (
size_t k = 0; k < octComp.tileSize; k++) {
285 for (
size_t j = 0; j < octComp.tileSize; j++) {
286 std::memcpy(ptr + k*depthPitch + j*rowPitch,
287 res->data1.data() + ((k*octComp.tileSize + j)*octComp.tileSize),
288 sizeof(
float)*octComp.tileSize);
291 iContext->unmap(stage.texture0);
297 LOG_DEBUG(logger,
"Trashing");
300 octData.tileResponsesStash.push_back(std::move(res));
308 std::vector<Item> unfinishedCopies;
309 unfinishedCopies.reserve(toCopy.size());
310 for (
auto & item : toCopy) {
311 if (item.delay == 0) {
312 stagingUnused.push_back(item);
315 unfinishedCopies.push_back(item);
319 toCopy.swap(unfinishedCopies);
Log implementation class.
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
@ NoData
Set when data is for a fresh tile when we don't even have outdated data.
@ InStaging
Set while the tile is in the staging queue. It has updated data, but it isn't available yet.
static const Handle_t NoHandle
Represents a handle to nothing.
@ Default
Default usage, the texture can be loaded once and bound and sampled in shaders.