1#include "BridgeRasterSource.h"
2#include "RasterConversion.h"
3#include "RasterSourceSubscription.h"
5#include "../ClipmapTerrainTypes.h"
7#include "Rendering/ITextures.h"
8#include "Rendering/IContext.h"
10#include "Foundation/Logging/Logger.h"
23 RequestClosure(
size_t generation,
size_t tileGeneration) : generation(generation), tileGeneration(tileGeneration) {}
25 uint64_t providerId = 0;
27 size_t generation = 0;
29 size_t rasterLevel = 0;
30 size_t tileGeneration = 0;
35 const size_t requestGeneration,
36 const size_t rasterLevel,
42 bool isHeight =
false,
47 source->device->initializeThread();
50 const size_t cacheLimit = source->cacheSize;
52 while (source->textureBufferSize > cacheLimit) {
53 WriteLock sourceLock(*source);
55 source->evictLruTile();
59 TextureHandle textureHandle;
61 const bool supportQuery = (source->getFlags() & RasterSourceFlags::Queryable) != 0;
62 bool compressCache = (source->getFlags() & RasterSourceFlags::CompressCache) != 0;
63 const bool isCompressible = Cogs::isCompressible(format);
65 if (compressCache && !isCompressible) {
66 if (!source->suppressCompressionError) {
67 source->suppressCompressionError =
true;
68 LOG_ERROR(logger,
"Compression only supported for R8G8B8A8_UNORM or R8G8B8A8_UNORM_SRGB format.");
71 compressCache =
false;
72 }
else if (compressCache && (width % 4 != 0 || height % 4 != 0)) {
73 if (!source->suppressDimensionError) {
74 LOG_ERROR(logger,
"Tile dimensions must be a multiple of 4 to support block compression.");
75 source->suppressDimensionError =
true;
78 compressCache =
false;
82 textureSize = Cogs::getTextureSize(width, height, format) / 4;
84 std::vector<uint8_t> compressed(textureSize);
85 auto compressedFormat = compressTileData(compressed, data, format, width, height);
87 textureHandle = source->loadTexture(compressed.data(), width, height, compressedFormat, textureSize);
89 textureSize = Cogs::getTextureSize(width, height, format);
90 textureHandle = source->loadTexture(data, width, height, format, textureSize);
93 source->device->waitForCommandSync();
95 TileLoadResponse response{};
96 response.rasterLevel =
static_cast<int>(rasterLevel);
99 std::vector<uint8_t> buffer;
102 source->allocateTileStorage(textureSize, buffer);
103 buffer.assign(data, data + textureSize);
107 WriteLock lock(*source);
109 source->loadTileData(tile, requestGeneration, buffer, textureHandle, format, textureSize);
112 source->isHeight =
true;
114 tile->data->minZ = minZ;
115 tile->data->maxZ = maxZ;
117 source->minZ = std::min(source->minZ, minZ);
118 source->maxZ = std::max(source->maxZ, maxZ);
122 std::lock_guard<std::mutex> lock(source->subscriberMutex);
124 for (
auto handler : source->subscribers) {
125 handler->postResponse(response);
129 void loadCallbackInternal(
void * userData,
int ,
int ,
int , TileData * dataPtr)
131 assert(userData &&
"User data must point to valid closure.");
132 assert(dataPtr &&
"Tile data must point to valid structure.");
134 std::unique_ptr<RequestClosure> closure(
static_cast<RequestClosure *
>(userData));
135 BridgeRasterSource * source = closure->source;
139 std::lock_guard<RasterSource::Processing> processingLock(source->processing);
142 if (closure->generation < source->generation) {
147 RasterTile * tile =
nullptr;
149 ReadLock lock(*source);
151 tile = source->getTile(closure->id);
154 if (!tile || (tile->data && (closure->tileGeneration < tile->data->generation))) {
159 auto tileData =
reinterpret_cast<const TileData *
>(dataPtr);
160 auto data =
reinterpret_cast<const uint8_t *
>(tileData->imageData);
161 auto format = tileData->format;
164 if (tileData->shouldConvert() || tileData->shouldFlip()) {
165 std::vector<uint8_t> convertedData;
166 auto targetFormat = convertBitmapData(data, tileData, convertedData);
168 if (targetFormat == TextureFormat::Unknown) {
169 LOG_ERROR(logger,
"Texture format %hu not convertible.", tileData->format);
173 loadTileData(closure->source, tile, closure->tileGeneration, closure->rasterLevel, closure->id, convertedData.data(), tileData->width, tileData->height, targetFormat, tileData->isHeight(), tileData->minZ, tileData->maxZ);
175 loadTileData(closure->source, tile, closure->tileGeneration, closure->rasterLevel, closure->id, data, tileData->width, tileData->height, format, tileData->isHeight(), tileData->minZ, tileData->maxZ);
178 WriteLock lock(*source);
180 source->loadEmptyTileData(tile);
184#define CHECKED(c, p) p
186 void loadCallback(
void * userData,
int level,
int x,
int y, TileData * dataPtr)
188 RequestClosure * closure =
reinterpret_cast<RequestClosure *
>(userData);
189 BridgeRasterSource * source = closure->source;
191 assert(closure &&
"Invalid closure in tile load callback.");
192 assert(source &&
"Invalid raster source in tile load closure.");
195 CHECKED(source->context, loadCallbackInternal(userData, level, x, y, dataPtr));
199Cogs::BridgeRasterSource::BridgeRasterSource(CogsContext * context, RasterSourceParameters * parameters) :
201 cacheSize(parameters->cacheSize),
202 providerId(parameters->id),
203 flags(parameters->flags),
204 requestCallback(parameters->tileRequestCallback),
205 allocationCallback(parameters->allocationCallback),
206 deallocationCallback(parameters->deallocationCallback)
208 const bool supportQuery = (flags & RasterSourceFlags::Queryable) != 0;
209 const bool compressCache = (flags & RasterSourceFlags::CompressCache) != 0;
211 if (supportQuery && compressCache) {
212 LOG_ERROR(logger,
"Raster source cannot support queries on compressed data.");
215 format =
static_cast<TextureFormat
>(parameters->format);
216 name = std::string(parameters->name);
218 GeodeticExtent geodeticExtent(parameters->minX, parameters->minY, parameters->maxX, parameters->maxY);
220 tileLongitudePosts = parameters->tileWidth;
221 tileLatitudePosts = parameters->tileHeight;
223 const size_t numLevels = parameters->numLevels;
225 double deltaLongitude = parameters->deltaX;
226 double deltaLatitude = parameters->deltaY;
228 const double extentX = geodeticExtent.getEast() - geodeticExtent.getWest();
229 const double extentY = geodeticExtent.getNorth() - geodeticExtent.getSouth();
231 double tilePostDeltaLongitude = deltaLongitude / (double)tileLongitudePosts;
232 double tilePostDeltaLatitude = deltaLatitude / (double)tileLatitudePosts;
234 for (
size_t i = 0; i < numLevels; ++i) {
235 const int longitudePosts =
static_cast<int>(std::ceil(extentX / deltaLongitude)) * tileLongitudePosts;
236 const int latitudePosts =
static_cast<int>(std::ceil(extentY / deltaLatitude)) * tileLatitudePosts;
238 assert(longitudePosts > 0 &&
"Number of longitude posts must be a positive integer.");
239 assert(latitudePosts > 0 &&
"Number of latitude posts must be a positive integer.");
241 levels.emplace_back(
this,
249 tilePostDeltaLongitude,
250 tilePostDeltaLatitude);
252 deltaLongitude /= 2.0;
253 deltaLatitude /= 2.0;
255 tilePostDeltaLongitude /= 2.0;
256 tilePostDeltaLatitude /= 2.0;
260Cogs::BridgeRasterSource::~BridgeRasterSource()
262 assert(!processing.getCount() &&
"Request processing should be completed before destruction.");
265void Cogs::BridgeRasterSource::requestTile(
const TileLoadRequest & request)
267 const RasterTileIdentifier & identifier = request.tile->identifier;
269 if (request.tile->isResident()) {
273 if (request.tile->isOOB()) {
274 loadInvalidTile(request.tile);
279 auto closure = std::make_unique<RequestClosure>(generation, request.tile->generation);
280 closure->providerId = this->providerId;
281 closure->source =
this;
282 closure->rasterLevel = request.tile->identifier.level;
283 closure->id = identifier.getHashCode();
287 if (!requestCallback(closure.get(), loadCallback, identifier.level, identifier.x, identifier.y)) {
295void Cogs::BridgeRasterSource::allocateTileStorage(
const size_t textureSize, std::vector<uint8_t> & buffer)
297 if (allocationCallback) {
298 allocationCallback(
nullptr,
static_cast<unsigned int>(textureSize));
301 buffer.resize(textureSize);
304void Cogs::BridgeRasterSource::deallocateTileStorage(std::vector<uint8_t> & buffer)
307 if (deallocationCallback) {
308 deallocationCallback(
nullptr,
static_cast<unsigned int>(buffer.size()));
312 buffer.shrink_to_fit();
318 static std::vector<uint8_t> emptyBuffer;
321void Cogs::BridgeRasterSource::loadInvalidTile(RasterTile * tile)
331 invalidTileHandle = device->getTextures()->loadTexture(bytes, 2, 2, TextureFormat::R8G8B8A8_UNORM);
334 loadTileData(tile, tile->generation, emptyBuffer, invalidTileHandle, TextureFormat::R8G8B8A8_UNORM, 0);
337void Cogs::BridgeRasterSource::loadEmptyTileData(RasterTile * tile)
Log implementation class.
constexpr Log getLogger(const char(&name)[LEN]) noexcept
Contains all Cogs related functionality.
static const Handle_t NoHandle
Represents a handle to nothing.
static const Handle_t InvalidHandle
Represents an invalid handle.