Cogs.Core
OctProviderBuildTileTask.cpp
1#include "Services/TaskManager.h"
2#include "OctProviderBuildTileTask.h"
3#include "../../../Volumetric/Source/Components/OctComponent.h"
4#include "../BeamUtils.h"
5
6#include <glm/glm.hpp>
7
8void Cogs::Core::EchoSounder::OctProviderBuildTileTask::operator()()
9{
10 CpuInstrumentationScope(SCOPE_ECHOSOUNDER, "OctBuild");
11 auto & res = persistent->responses[index];
12 const auto & N = res->N;
13 auto * context = persistent->context;
14
15 std::vector<Misc> m;
16 setup(m);
17
19 age.resize(N.x*N.y*N.z, false);
20 res->data1.resize(N.x*N.y*N.z, false);
21
22 auto group = context->taskManager->createGroup(Cogs::Core::TaskManager::ResourceQueue);
23 const auto taskCount = persistent->taskCount[index];
24 for (unsigned subTask = 0; subTask < taskCount; subTask++) {
25 auto a = (subTask * N.z) / taskCount;
26 auto b = std::min(N.z, ((subTask + 1)*N.z) / taskCount);
27 context->taskManager->enqueueChild(group,
28 OctProviderBuildSubTileTask{this,
29 &age,
30 &m,
31 a,
32 b});
33 }
34 persistent->context->taskManager->wait(group);
35
36 res->data0.resize(N.x*N.y*N.z, false);
37 calcGradients(res->data0, res->data1, age, N);
38}
39
40void Cogs::Core::EchoSounder::OctProviderBuildSubTileTask::operator()()
41{
42 sample();
43}
44
45
46void Cogs::Core::EchoSounder::OctProviderBuildTileTask::setup(std::vector<Misc>& m)
47{
48 CpuInstrumentationScope(SCOPE_ECHOSOUNDER, "OctBuild_setup");
49 auto & res = persistent->responses[index];
50
51 // Pull ping data from cache and organize them from most recent to least recent.
52 std::vector<SrcPing> pings;
53 pings.reserve(res->regionKeys.size());
54 for (auto regionKey : res->regionKeys) {
55 uint32_t src, ping;
56 decodeKey2(src, ping, regionKey);
57 auto it = persistent->pingCache.find(encodeKey2(persistent->groupCache[src].dataId, ping));
58 assert(it != persistent->pingCache.end());
59 assert(it->second->linearized);
60 pings.push_back(SrcPing{ it->second.get(), src });
61 }
62 std::sort(pings.begin(), pings.end(), [](const auto &a, const auto & b) { return a.ping->timestamp > b.ping->timestamp; });
63 res->clientData = pings[0].ping->timestamp;
64
65 std::vector<Misc> tmp;
66 tmp.resize(pings.size());
67 for (size_t i = 0; i <tmp.size(); i++) {
68 auto & misc = tmp[i];
69
70 misc.ping = pings[i].ping;
71 const auto & grp = persistent->groupCache[pings[i].src];
72
73 const auto minDistance = misc.ping->depthOffset;
74 const auto maxDistance = minDistance + misc.ping->sampleCount * misc.ping->depthStep;
75
76 glm::vec4 frustum[6];
77 getBoundingFrustum(frustum,
78 misc.ping->metaPing.arrayOrientationGlobal,
79 misc.ping->metaPing.arrayPositionGlobal,
80 0, // FIXME - Assume EK/ME/MS for now.
81 grp.minDirectionX, grp.maxDirectionX,
82 grp.minDirectionY, grp.maxDirectionY,
83 minDistance, maxDistance);
84
85 for (unsigned k = 0; k < 4; k++) {
86 misc.boundingFrustumNormals[k] = glm::vec3(frustum[k]);
87 }
88 misc.inverseOrientation = glm::inverse(misc.ping->metaPing.arrayOrientationGlobal);
89 misc.shift = misc.ping->metaPing.arrayPositionGlobal - res->min;
90 misc.minDistanceSquared = minDistance * minDistance;
91 misc.maxDistanceSquared = maxDistance * maxDistance;
92
93 misc.maxIndices = glm::uvec3(glm::max(1u, grp.minorCount) - 1u,
94 glm::max(1u, grp.majorCount) - 1u,
95 glm::max(1u, misc.ping->sampleCount) - 1u);
96
97 misc.polarShift = glm::vec3(grp.minDirectionY,
98 grp.minDirectionX,
99 minDistance);
100 misc.polarScale = glm::vec3((glm::max(2u, grp.minorCount) - 2u) / (grp.maxDirectionY - grp.minDirectionY),
101 (glm::max(2u, grp.majorCount) - 2u) / (grp.maxDirectionX - grp.minDirectionX),
102 (glm::max(2u, misc.ping->sampleCount) - 2u) / (maxDistance - minDistance));
103 misc.minorCount = grp.minorCount;
104 misc.sampleCount = misc.ping->sampleCount;
105 misc.v = misc.ping->linear.data();
106 }
107
108 // Reduce ping count: TODO do earlier
109 // m.clear();
110 // unsigned max_pings = 128u;
111 // unsigned l_inc = std::max(1u, 1+unsigned((tmp.size()-1)/max_pings));
112 // for (unsigned t=0; t < l_inc && m.size() < max_pings; t++){
113 // for (unsigned l=t; l < tmp.size() && m.size() < max_pings; l+=l_inc){
114 // m.push_back(tmp[l]);
115 // }
116 // }
117
118 m = std::move(tmp);
119}
120
121void Cogs::Core::EchoSounder::OctProviderBuildSubTileTask::sample()
122{
123 CpuInstrumentationScope(SCOPE_ECHOSOUNDER, "OctBuild_sample");
124 auto & res = parent->persistent->responses[parent->index];
125 auto & value = res->data1;
126
127 const auto & N = res->N;
128 const unsigned Np = static_cast<unsigned>(m->size());
129
130 auto scale = (res->max - res->min)*glm::vec3(1.f / N.x,
131 1.f / N.y,
132 1.f / N.z);
133
134 //for (unsigned k = 0; k < N.z; k++) {
135 for (size_t k = a; k < b; k++) {
136 for (size_t j = 0; j < N.y; j++) {
137 for (size_t i = 0; i < N.x; i++) {
138 auto p = scale * glm::vec3(i + 0.5f, // Sample pos with origin in res->min.
139 j + 0.5f,
140 k + 0.5f);
141
142 float v = 0.f;
143 float e = 1.f;
144 for (size_t l = 0; l < Np; l++) {
145 const auto & misc = (*m)[l];
146 const auto q = p - misc.shift; // Sample pos with origin in beam bundle origin.
147 const auto r2 = glm::dot(q, q);
148
149 bool in_0 = 0.f <= glm::dot(misc.boundingFrustumNormals[0], q);
150 bool in_1 = 0.f <= glm::dot(misc.boundingFrustumNormals[1], q);
151 bool in_2 = 0.f <= glm::dot(misc.boundingFrustumNormals[2], q);
152 bool in_3 = 0.f <= glm::dot(misc.boundingFrustumNormals[3], q);
153 bool in_4 = misc.minDistanceSquared <= r2;
154 bool in_5 = r2 <= misc.maxDistanceSquared;
155 if (!in_0 || !in_1 || !in_2 || !in_3 || !in_4 || !in_5) {
156 continue;
157 }
158
159 const auto a = misc.inverseOrientation * q;
160 const float r = std::sqrt(r2);
161
162 const float dirX = std::asin(a.x / r);
163 const float dirY = std::asin(a.y / r);
164 const auto polarPos = glm::vec3(dirY, dirX, r); // Polar coordinate.
165 const auto xi = glm::max(glm::vec3(0.f), misc.polarScale*(polarPos - misc.polarShift)); // Initial float index.
166
167 // Figure out interpolation parameters.
168 const auto tau = glm::floor(xi);
169 const auto t = xi - tau;
170 const auto ii = glm::min(misc.maxIndices, glm::uvec3(tau));
171 const auto jj = glm::min(glm::uvec2(misc.maxIndices), glm::uvec2(ii) + glm::uvec2(1));
172
173 const auto val00 = misc.v[(ii.y*misc.minorCount + ii.x)*misc.sampleCount + ii.z];
174 const auto val01 = misc.v[(jj.y*misc.minorCount + ii.x)*misc.sampleCount + ii.z];
175 const auto val0 = (1.f - t.y)*val00 + t.y*val01;
176
177 const auto val10 = misc.v[(ii.y*misc.minorCount + jj.x)*misc.sampleCount + ii.z];
178 const auto val11 = misc.v[(jj.y*misc.minorCount + jj.x)*misc.sampleCount + ii.z];
179 const auto val1 = (1.f - t.y)*val10 + t.y*val11;
180
181 v = (1.f - t.x)*val0 + t.x*val1;
182 e = float(10e-7*((*m)[0].ping->timestamp - misc.ping->timestamp));
183 break;
184 }
185
186 value[(k*N.y + j)*N.x + i] = v;
187 (*age)[(k*N.y + j)*N.x + i] = e;
188 }
189 }
190 }
191}
192
193void Cogs::Core::EchoSounder::OctProviderBuildTileTask::calcGradients(Cogs::Memory::TypedBuffer<glm::vec4>& out, const Cogs::Memory::TypedBuffer<float>& in, const Cogs::Memory::TypedBuffer<float>& age, const glm::uvec3& N)
194{
195 CpuInstrumentationScope(SCOPE_ECHOSOUNDER, "OctBuild_gradients");
196
197 for (unsigned k = 0; k < N.z; k++) {
198 for (unsigned j = 0; j < N.y; j++) {
199 for (unsigned i = 0; i < N.x; i++) {
200
201 unsigned km = std::max(k, 1u) - 1;
202 unsigned kp = std::min(k + 1, N.z - 1);
203 unsigned jm = std::max(j, 1u) - 1;
204 unsigned jp = std::min(j + 1, N.y - 1);
205 unsigned im = std::max(i, 1u) - 1;
206 unsigned ip = std::min(i + 1, N.x - 1);
207
208 out[(k*N.y + j)*N.x + i] = glm::vec4((1.0 / (ip - im))*(in[(k*N.y + j)*N.x + ip] - in[(k*N.y + j)*N.x + im]),
209 (1.0 / (jp - jm))*(in[(k*N.y + jp)*N.x + i] - in[(k*N.y + jm)*N.x + i]),
210 (1.0 / (kp - km))*(in[(kp*N.y + j)*N.x + i] - in[(km*N.y + j)*N.x + i]),
211 age[(k*N.y + j)*N.x + i]);
212
213 }
214 }
215 }
216}
static constexpr TaskQueueId ResourceQueue
Resource task queue.
Definition: TaskManager.h:232