1#include "BaseRasterSource.h"
2#include "JsonSerialization.h"
3#include "ImageDecoder.h"
4#include "StashService.h"
8#include "Services/Services.h"
9#include "Bridge/TerrainFunctions.h"
11#include "Foundation/Logging/Logger.h"
12#include "Foundation/Platform/IO.h"
15 using namespace Cogs::Core::TerrainProvider;
19bool Cogs::Core::TerrainProvider::BaseConfig::compatible(
const BaseConfig* other)
const
21 const float epsilon = 1e-7f;
22 if (epsilon < std::abs(extent.min.x - other->extent.min.x) ||
23 epsilon < std::abs(extent.min.y - other->extent.min.y) ||
24 epsilon < std::abs(extent.max.x - other->extent.max.x) ||
25 epsilon < std::abs(extent.max.y - other->extent.max.y))
27 LOG_ERROR(logger,
"Mismatched extents");
31 if (epsilon < std::abs(tiling.size.x - other->tiling.size.x) ||
32 epsilon < std::abs(tiling.size.y - other->tiling.size.y) ||
33 tiling.width != other->tiling.width ||
34 tiling.height != other->tiling.height ||
35 tiling.overlapStart != other->tiling.overlapStart ||
36 tiling.overlapEnd != other->tiling.overlapEnd ||
37 tiling.levels != other->tiling.levels)
39 LOG_ERROR(logger,
"Mismatched tilings");
43 if (coordsys.kind != other->coordsys.kind ||
44 coordsys.id != other->coordsys.id)
46 LOG_ERROR(logger,
"Mismatched coord sys");
50 if (textureFormat != other->textureFormat)
52 LOG_ERROR(logger,
"Mismatched texture formats");
56 if (mimeType != other->mimeType) {
57 LOG_ERROR(logger,
"Mismatched mime-types");
61 if (cacheKey != other->cacheKey) {
62 LOG_ERROR(logger,
"Mismatched cache keys");
78 auto* stash = provider->stashService->getStash();
80 initializeSharedContext(provider->context, stash->context);
82 MimeType kind = MimeType::None;
83 if (request->failure) {
86 tileData.format = provider->textureFormat;
87 tileData.width = provider->tiling.width;
88 tileData.height = provider->tiling.height;
89 tileData.imageData =
nullptr;
93 request->loadCallback(request->loadData,
94 int(request->id.level),
99 Cogs::LockGuard lock(provider->requests.mutex);
100 provider->requests.inFlight.erase(tileKey(request->id));
101 provider->requests.hasHandleTask.remove(request);
102 provider->requests.store.destroy(request);
106 else if (provider->cache->getTile(stash->contents, kind, request->id)) {
110 stash->decoder.decode(tileData,
113 provider->tiling.width,
114 provider->tiling.height,
115 provider->noDataValue);
117 request->loadCallback(request->loadData,
118 int(request->id.level),
124 Cogs::LockGuard lock(provider->requests.mutex);
125 provider->requests.inFlight.erase(tileKey(request->id));
126 provider->requests.hasHandleTask.remove(request);
127 provider->requests.store.destroy(request);
133 Cogs::LockGuard guard(provider->requests.mutex);
134 provider->requests.hasHandleTask.remove(request);
135 provider->requests.waitingForProvider.pushBack(request);
136 request->task = NoTask;
138 provider->requestTile(request);
145uint64_t Cogs::Core::TerrainProvider::tileKey(
const TileId&
id)
147 return (uint64_t(
id.level) << 56) | (uint64_t(
id.j) << 28) | uint64_t(
id.i);
150Cogs::Core::TerrainProvider::BaseRasterSource::BaseRasterSource(
Context* context) :
154 assert(stashService);
158Cogs::Core::TerrainProvider::BaseRasterSource::~BaseRasterSource()
160 LOG_DEBUG(logger,
"Shutting down %zx",
size_t(
this));
161 setErrorCode(ErrorCode::Done);
163 std::vector<Request*> running;
165 Cogs::LockGuard g(requests.mutex);
166 for (
auto * item : requests.hasHandleTask) {
167 running.push_back(
static_cast<Request*
>(item));
170 for (
auto& req : running) {
171 context->taskManager->wait(req->task);
175Cogs::Core::TerrainProvider::IRasterSource::ErrorCode Cogs::Core::TerrainProvider::BaseRasterSource::getErrorCode()
const
177 Cogs::LockGuard guard(state.mutex);
178 return state.errorCode;
181void Cogs::Core::TerrainProvider::BaseRasterSource::setErrorCode(ErrorCode newErrorCode)
183 Cogs::LockGuard guard(state.mutex);
184 if (state.errorCode == ErrorCode::NoError) {
185 state.errorCode = newErrorCode;
189bool Cogs::Core::TerrainProvider::BaseRasterSource::init(
const BaseConfig& conf, std::unique_ptr<ICache>&& icache)
191 cache = std::move(icache);
194 extent = conf.extent;
195 tiling = conf.tiling;
196 coordsys = conf.coordsys;
197 textureFormat = conf.textureFormat;
198 if (textureFormat == TextureFormat::Unknown) {
199 LOG_ERROR(logger,
"Unknown texture format");
203 noDataValue = conf.noData;
204 if (!std::isfinite(conf.extent.min.x) ||
205 !std::isfinite(conf.extent.min.y) ||
206 !std::isfinite(conf.extent.max.x) ||
207 !std::isfinite(conf.extent.max.y) ||
208 (conf.extent.max.x <= conf.extent.min.x) ||
209 (conf.extent.max.y <= conf.extent.min.y))
211 LOG_ERROR(logger,
"Illegal extent [%f,%f]x[%f,%f]",
212 conf.extent.min.x, conf.extent.min.y,
213 conf.extent.max.x, conf.extent.max.y);
217 if (!std::isfinite(conf.tiling.size.x) ||
218 !std::isfinite(conf.tiling.size.y) ||
219 (conf.tiling.size.x <= 0.0) ||
220 (conf.tiling.size.y <= 0.0) ||
221 (conf.tiling.width == 0) ||
222 (conf.tiling.height == 0) ||
223 (conf.tiling.levels == 0))
225 LOG_ERROR(logger,
"Illegal tiling");
232void Cogs::Core::TerrainProvider::BaseRasterSource::getConfig(
BaseConfig& conf)
const
234 conf.extent = extent;
235 conf.tiling = tiling;
236 conf.coordsys = coordsys;
237 conf.textureFormat = textureFormat;
245 assert(tiling.overlapStart == 0 &&
"nonezero overlapStart not handled");
246 assert(tiling.overlapEnd == 0 &&
"nonzero overlapEnd not handled");
250 params.format = textureFormat;
251 params.noData = std::numeric_limits<float>::quiet_NaN();
252 params.minX = extent.min.x;
253 params.minY = extent.min.y;
254 params.maxX = extent.max.x;
255 params.maxY = extent.max.y;
256 params.numLevels = tiling.levels;
257 params.tileWidth = tiling.width;
258 params.tileHeight = tiling.height;
259 params.deltaX = tiling.size.x;
260 params.deltaY = tiling.size.y;
261 params.cacheSize = 128 * 1024 * 1024;
263 params.tileRequestCallback = tileRequestCallbackFunc;
270 auto& tm = context->taskManager;
271 cache->storeTile(contents, kind, req->id, debugLog);
272 LOG_DEBUG(logger,
"%s: Updated tile %u:%u,%u", Strings::getC(name), req->id.level, req->id.i, req->id.j);
274 Cogs::LockGuard guard(requests.mutex);
275 requests.waitingForProvider.remove((
Request*)req);
276 requests.hasHandleTask.pushBack((
Request*)req);
279 tm->enqueue(req->task);
284void Cogs::Core::TerrainProvider::BaseRasterSource::addTileFailure(
Request* req,
StringView debugLog)
286 auto& tm = context->taskManager;
288 cache->storeTile(empty, MimeType::None, req->id, debugLog);
290 LOG_DEBUG(logger,
"%s: Flagged tile %u:%u,%u as failed", Strings::getC(name), req->id.level, req->id.i, req->id.j);
292 Cogs::LockGuard guard(requests.mutex);
293 requests.waitingForProvider.remove((
Request*)req);
294 requests.hasHandleTask.pushBack((
Request*)req);
297 tm->enqueue(req->task);
302bool Cogs::Core::TerrainProvider::BaseRasterSource::tileRequestCallbackFunc(
void* tileLoadData, TileLoadCallback tileLoadCallback,
int level,
int x,
int y)
310 struct TerrainEngineRequestClosure
312 uint64_t providerId = 0;
314 auto* closure =
reinterpret_cast<TerrainEngineRequestClosure*
>(tileLoadData);
319 auto& tm = provider->context->taskManager;
321 if (provider->getErrorCode() == IRasterSource::ErrorCode::NoError) {
324 if (0 <= level && 0 <= x && 0 <= y) {
326 TileId id{ unsigned(level), unsigned(x), unsigned(y) };
327 auto h = tileKey(
id);
329 Cogs::UniqueLock guard(provider->requests.mutex);
332 if (provider->requests.inFlight.count(h) == 0) {
335 provider->requests.inFlight.insert(h);
336 auto* request = provider->requests.store.create();
337 request->loadCallback = tileLoadCallback;
338 request->loadData = tileLoadData;
340 request->task = tm->create(tm->ResourceQueue,
HandleRequestTask{ provider, request });
341 provider->requests.hasHandleTask.pushBack(request);
344 tm->enqueue(request->task);
A Context instance contains all the services, systems and runtime components needed to use Cogs.
std::unique_ptr< class Services > services
Services.
Log implementation class.
Provides a weakly referenced view over the contents of a string.
constexpr Log getLogger(const char(&name)[LEN]) noexcept
@ IsHeight
Tile contains height data, min/max values should be provided.