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(
reinterpret_cast<RequestClosure *
>(userData));
135 BridgeRasterSource * source = closure->source;
139 std::lock_guard<RasterSource::Processing> processingLock(source->processing);
142 assert(source->closures >= 0 &&
"Too many closures received.");
144 if (closure->generation < source->generation) {
149 RasterTile * tile =
nullptr;
151 ReadLock lock(*source);
153 tile = source->getTile(closure->id);
156 if (tile->data && closure->tileGeneration < tile->data->generation) {
161 auto tileData =
reinterpret_cast<const TileData *
>(dataPtr);
162 auto data =
reinterpret_cast<const uint8_t *
>(tileData->imageData);
163 auto format = tileData->format;
166 if (tileData->shouldConvert() || tileData->shouldFlip()) {
167 std::vector<uint8_t> convertedData;
168 auto targetFormat = convertBitmapData(data, tileData, convertedData);
170 if (targetFormat == TextureFormat::Unknown) {
171 LOG_ERROR(logger,
"Texture format %hu not convertible.", tileData->format);
175 loadTileData(closure->source, tile, closure->tileGeneration, closure->rasterLevel, closure->id, convertedData.data(), tileData->width, tileData->height, targetFormat, tileData->isHeight(), tileData->minZ, tileData->maxZ);
177 loadTileData(closure->source, tile, closure->tileGeneration, closure->rasterLevel, closure->id, data, tileData->width, tileData->height, format, tileData->isHeight(), tileData->minZ, tileData->maxZ);
180 WriteLock lock(*source);
182 source->loadEmptyTileData(tile);
186#define CHECKED(c, p) p
188 void loadCallback(
void * userData,
int level,
int x,
int y, TileData * dataPtr)
190 RequestClosure * closure =
reinterpret_cast<RequestClosure *
>(userData);
191 BridgeRasterSource * source = closure->source;
193 assert(closure &&
"Invalid closure in tile load callback.");
194 assert(source &&
"Invalid raster source in tile load closure.");
197 CHECKED(source->context, loadCallbackInternal(userData, level, x, y, dataPtr));
201Cogs::BridgeRasterSource::BridgeRasterSource(CogsContext * context, RasterSourceParameters * parameters) :
203 cacheSize(parameters->cacheSize),
204 providerId(parameters->id),
205 flags(parameters->flags),
206 requestCallback(parameters->tileRequestCallback),
207 allocationCallback(parameters->allocationCallback),
208 deallocationCallback(parameters->deallocationCallback)
210 const bool supportQuery = (flags & RasterSourceFlags::Queryable) != 0;
211 const bool compressCache = (flags & RasterSourceFlags::CompressCache) != 0;
213 if (supportQuery && compressCache) {
214 LOG_ERROR(logger,
"Raster source cannot support queries on compressed data.");
217 format =
static_cast<TextureFormat
>(parameters->format);
218 name = std::string(parameters->name);
220 GeodeticExtent geodeticExtent(parameters->minX, parameters->minY, parameters->maxX, parameters->maxY);
222 tileLongitudePosts = parameters->tileWidth;
223 tileLatitudePosts = parameters->tileHeight;
225 const size_t numLevels = parameters->numLevels;
227 double deltaLongitude = parameters->deltaX;
228 double deltaLatitude = parameters->deltaY;
230 const double extentX = geodeticExtent.getEast() - geodeticExtent.getWest();
231 const double extentY = geodeticExtent.getNorth() - geodeticExtent.getSouth();
233 double tilePostDeltaLongitude = deltaLongitude / (double)tileLongitudePosts;
234 double tilePostDeltaLatitude = deltaLatitude / (double)tileLatitudePosts;
236 for (
size_t i = 0; i < numLevels; ++i) {
237 const int longitudePosts =
static_cast<int>(std::ceil(extentX / deltaLongitude)) * tileLongitudePosts;
238 const int latitudePosts =
static_cast<int>(std::ceil(extentY / deltaLatitude)) * tileLatitudePosts;
240 assert(longitudePosts > 0 &&
"Number of longitude posts must be a positive integer.");
241 assert(latitudePosts > 0 &&
"Number of latitude posts must be a positive integer.");
243 levels.emplace_back(
this,
251 tilePostDeltaLongitude,
252 tilePostDeltaLatitude);
254 deltaLongitude /= 2.0;
255 deltaLatitude /= 2.0;
257 tilePostDeltaLongitude /= 2.0;
258 tilePostDeltaLatitude /= 2.0;
262Cogs::BridgeRasterSource::~BridgeRasterSource()
264 assert(!processing.getCount() &&
"Request processing should be completed before destruction.");
267void Cogs::BridgeRasterSource::requestTile(
const TileLoadRequest & request)
269 const RasterTileIdentifier & identifier = request.tile->identifier;
271 if (request.tile->isResident()) {
275 if (request.tile->isOOB()) {
276 loadInvalidTile(request.tile);
281 auto closure = std::make_unique<RequestClosure>(generation, request.tile->generation);
282 closure->providerId = this->providerId;
283 closure->source =
this;
284 closure->rasterLevel = request.tile->identifier.level;
285 closure->id = identifier.getHashCode();
289 if (!requestCallback(closure.get(), loadCallback, identifier.level, identifier.x, identifier.y)) {
297void Cogs::BridgeRasterSource::allocateTileStorage(
const size_t textureSize, std::vector<uint8_t> & buffer)
299 if (allocationCallback) {
300 allocationCallback(
nullptr,
static_cast<unsigned int>(textureSize));
303 buffer.resize(textureSize);
306void Cogs::BridgeRasterSource::deallocateTileStorage(std::vector<uint8_t> & buffer)
309 if (deallocationCallback) {
310 deallocationCallback(
nullptr,
static_cast<unsigned int>(buffer.size()));
314 buffer.shrink_to_fit();
320 static std::vector<uint8_t> emptyBuffer;
323void Cogs::BridgeRasterSource::loadInvalidTile(RasterTile * tile)
333 invalidTileHandle = device->getTextures()->loadTexture(bytes, 2, 2, TextureFormat::R8G8B8A8_UNORM);
336 loadTileData(tile, tile->generation, emptyBuffer, invalidTileHandle, TextureFormat::R8G8B8A8_UNORM, 0);
339void 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.