1#include "ClipmapUpsampler.h"
2#include "ClipmapLevel.h"
4#include "RenderContext.h"
5#include "Raster/RasterSource.h"
7#include "Rendering/IGraphicsDevice.h"
8#include "Rendering/IEffects.h"
9#include "Rendering/IContext.h"
10#include "Rendering/IBuffers.h"
11#include "Rendering/IRenderTargets.h"
15#include "Foundation/Logging/Logger.h"
21 struct LevelParameters
23 glm::mat4 projectionMatrix;
24 glm::vec2 oneOverTextureSize;
25 glm::vec2 coarseRatio;
28 struct UpsampleParameters
30 glm::vec2 sourceOrigin;
32 glm::vec2 destinationOffset;
38 struct UpsampleTileParameters
40 glm::mat4 projectionMatrix;
41 glm::vec2 sourceOrigin;
45void Cogs::ClipmapUpsampler::initialize(IGraphicsDevice * device)
47 IEffects * effects = device->getEffects();
50 VertexFormatHandle positionFormat = device->getBuffers()->createVertexFormat(&positionElement, 1);
51 vertexBufferHandle = device->getBuffers()->loadVertexBuffer(quadVertices, 6, positionFormat);
53 LOG_DEBUG(logger,
"Loading clipmap upsample effect.");
55 upsampleEffectHandle = Terrain::EffectLoader::loadEffect(effects,
"ClipmapUpsampleVS",
"ClipmapUpsamplePS");
58 LOG_ERROR(logger,
"Error loading clipmap upsample effect.");
64 coarseImageryBinding = effects->getTextureBinding(upsampleEffectHandle,
"coarseImagery", 0);
65 coarseImagerySamplerBinding = effects->getSamplerStateBinding(upsampleEffectHandle,
"coarseImagerySampler", 0);
67 levelParameterBinding = effects->getConstantBufferBinding(upsampleEffectHandle,
"LevelParameters");
70 upsampleParameterBinding = effects->getConstantBufferBinding(upsampleEffectHandle,
"UpsampleParameters");
73 upsampleLayoutHandle = device->getBuffers()->loadInputLayout(&positionFormat, 1, upsampleEffectHandle);
75 LOG_DEBUG(logger,
"Loading clipmap upsample tile effect.");
77 upsampleTileEffectHandle = Terrain::EffectLoader::loadEffect(effects,
"ClipmapUpsampleTileVS",
"ClipmapUpsampleTilePS");
80 upsampleTileLayoutHandle = device->getBuffers()->loadInputLayout(&positionFormat, 1, upsampleTileEffectHandle);
82 upsampleTileParameterBinding = effects->getConstantBufferBinding(upsampleTileEffectHandle,
"UpsampleTileParameters");
85 SamplerState linearRepeatState = {
90 SamplerState::ComparisonFunction::Never,
92 { 0.0f, 0.0f, 0.0f, 0.0f },
95 linearRepeatStateHandle = device->getTextures()->loadSamplerState(linearRepeatState);
97 SamplerState pointRepeatState = {
102 SamplerState::ComparisonFunction::Never,
104 { 0.0f, 0.0f, 0.0f, 0.0f },
107 pointRepeatStateHandle = device->getTextures()->loadSamplerState(pointRepeatState);
109 SamplerState linearClampState = {
114 SamplerState::ComparisonFunction::Never,
116 { 0.0f, 0.0f, 0.0f, 0.0f },
119 linearClampStateHandle = device->getTextures()->loadSamplerState(linearClampState);
122void Cogs::ClipmapUpsampler::upsampleLevelRegions(RenderContext & renderContext,
123 ClipmapLevel * level,
124 const RasterTileRegion ** regions,
125 const size_t numRegions)
127 IContext * context = renderContext.context;
129 ClipmapLevel * coarserLevel = level->coarserLevel;
131 if (coarserLevel ==
nullptr || !numRegions) {
135 const RenderTexture * levelTexture = &level->renderTexture;
136 const RenderTexture * coarserLevelTexture = &coarserLevel->renderTexture;
138 if (coarserLevelTexture == levelTexture)
return;
140 const TextureOrigin & originInTextures = level->origin;
141 const TextureOrigin & coarserOriginInTextures = coarserLevel->origin;
143 const Extent & nextExtent = level->nextExtent;
144 const Extent & coarserNextExtent = coarserLevel->nextExtent;
146 const float noData = level->rasterLevel->getNoData();
147 const bool enableNoData = !std::isnan(noData);
149 const double ratioX = level->rasterLevel->getPostDeltaLongitude() / coarserLevel->rasterLevel->getPostDeltaLongitude();
150 const double ratioY = level->rasterLevel->getPostDeltaLatitude() / coarserLevel->rasterLevel->getPostDeltaLatitude();
154 context->setEffect(upsampleEffectHandle);
156 const float width =
static_cast<float>(levelTexture->width);
157 const float height =
static_cast<float>(levelTexture->height);
159 Matrix projection = glm::ortho<float>(0, width, 0, height, -1.0f, 1.0f);
161 context->setViewport(0, 0, width, height);
163 const uint32_t strides[] = { 2 *
sizeof(float) };
164 context->setVertexBuffers(&vertexBufferHandle, 1, strides,
nullptr);
165 context->setInputLayout(upsampleLayoutHandle);
167 context->setConstantBuffer(levelParameterBinding, levelParameterBufferHandle);
168 context->setConstantBuffer(upsampleParameterBinding, upsampleParameterBufferHandle);
170 context->setTexture(coarseImageryBinding, coarserLevelTexture->handle);
171 context->setSamplerState(coarseImagerySamplerBinding, enableNoData ? pointRepeatStateHandle : linearRepeatStateHandle);
173 const int fineClipmapWidth = nextExtent.getWidth();
174 const int fineClipmapHeight = nextExtent.getHeight();
176 const int coarseClipmapWidth = coarserNextExtent.getWidth();
177 const int coarseClipmapHeight = coarserNextExtent.getHeight();
179 const glm::vec2 oneOverTextureSize = { 1.0f / coarserLevelTexture->width, 1.0f / coarserLevelTexture->height };
180 const glm::vec2 coarseRatio = {
static_cast<float>(ratioX),
static_cast<float>(ratioY) };
183 MappedBuffer<LevelParameters> levelParameters(context, levelParameterBufferHandle,
MapMode::WriteDiscard);
185 if (levelParameters) {
186 levelParameters->projectionMatrix = projection;
187 levelParameters->oneOverTextureSize = oneOverTextureSize;
188 levelParameters->coarseRatio = coarseRatio;
192 for (
size_t i = 0; i < numRegions; ++i) {
193 const RasterTileRegion * region = regions[i];
195 const int destWest = (originInTextures[0] + (region->tile->extent.west + region->extent.west - nextExtent.west)) % fineClipmapWidth;
196 const int destSouth = (originInTextures[1] + (region->tile->extent.south + region->extent.south - nextExtent.south)) % fineClipmapHeight;
198 const double sourceWest = (int)(coarserOriginInTextures.x + ((region->tile->extent.west + region->extent.west) * ratioX - coarserNextExtent.west)) % coarseClipmapWidth;
199 const double sourceSouth = (int)(coarserOriginInTextures.y + ((region->tile->extent.south + region->extent.south) * ratioY - coarserNextExtent.south)) % coarseClipmapHeight;
201 const int regionWidth = region->extent.getWidth();
202 const int regionHeight = region->extent.getHeight();
204 const glm::vec2 sourceOrigin = {
static_cast<float>(sourceWest),
static_cast<float>(sourceSouth) };
205 const glm::vec2 updateSize = {
static_cast<float>(regionWidth),
static_cast<float>(regionHeight) };
206 const glm::vec2 destinationOffset = {
static_cast<float>(destWest),
static_cast<float>(destSouth) };
209 MappedBuffer<UpsampleParameters> upsampleParameters(context, upsampleParameterBufferHandle,
MapMode::WriteDiscard);
211 if (upsampleParameters) {
212 upsampleParameters->sourceOrigin = sourceOrigin;
213 upsampleParameters->updateSize = updateSize;
214 upsampleParameters->destinationOffset = destinationOffset;
216 upsampleParameters->enableNoData = enableNoData;
217 upsampleParameters->noData = noData;
232 float linear(
const float a,
const float b,
float amount)
234 return a * (1.0f - amount) + b * amount;
238Cogs::TextureHandle Cogs::ClipmapUpsampler::upsampleTile(RenderContext & renderContext, RasterSource * source, RasterTile * parentTile, RasterTile * tile)
240 IContext * context = renderContext.context;
241 IRenderTargets * renderTargets = renderContext.device->getRenderTargets();
243 const auto tileId = tile->identifier;
245 auto tileData = source->getTileData(tile);
246 const auto parentTileData = source->getTileData(parentTile);
248 if (!tileData || !parentTileData) {
252 const size_t width =
static_cast<size_t>(tile->getWidth());
253 const size_t height =
static_cast<size_t>(tile->getHeight());
254 const auto bpp = Cogs::getBlockSize(parentTileData->format);
255 const auto textureSize = Cogs::getTextureSize(
static_cast<int>(width),
static_cast<int>(height), parentTileData->format);
257 bool useMemCopyUpsample =
true;
259 if (useMemCopyUpsample) {
264 source->allocateTileStorage(textureSize, tileData->data);
266 auto bytes = tileData->data.data();
268 if (parentTileData->format == TextureFormat::R32_FLOAT) {
269 const float * parentData =
reinterpret_cast<float *
>(parentTileData->data.data());
271 for (
size_t y = 0; y < height; ++y) {
272 for (
size_t x = 0; x < width; ++x) {
273 size_t xx = x / 2 + ((tileId.x % 2) ? width / 2 : 0);
274 size_t yy = y / 2 + ((tileId.y % 2) ? height / 2 : 0);
276 float v1 = parentData[yy * width + xx];
277 float v2 = parentData[yy * width + xx + ((xx < width - 1) ? 1 : 0)];
279 float v3 = parentData[(yy + ((yy < height - 1) ? 1 : 0)) * width + xx];
280 float v4 = parentData[(yy + ((yy < height - 1) ? 1 : 0)) * width + xx + ((xx < width - 1) ? 1 : 0)];
282 ((
float *)bytes)[y * width + x] = linear(
283 linear(v1, v2, (x % 2) ? 0.5f : 0.0f),
284 linear(v3, v4, (x % 2) ? 0.5f : 0.0f),
285 (y % 2) ? 0.5f : 0.0f);
289 const auto parentBytes = parentTileData->data.data();
291 for (
size_t y = 0; y < height; ++y) {
292 for (
size_t x = 0; x < width; ++x) {
293 size_t xx = x / 2 + ((tileId.x % 2) ? width / 2 : 0);
294 size_t yy = y / 2 + ((tileId.y % 2) ? height / 2 : 0);
296 std::memcpy(bytes + (y * width + x) * bpp, parentBytes + (yy * width + xx) * bpp, bpp);
301 auto tileTexture = source->loadTexture(bytes,
static_cast<int>(width),
static_cast<int>(height), parentTileData->format, textureSize);
303 tileData->size = textureSize;
304 tileData->format = parentTileData->format;
305 tileData->textureHandle = tileTexture;
309 auto tileTexture = source->loadTexture(
nullptr,
static_cast<int>(width),
static_cast<int>(height), parentTileData->format, textureSize);
311 auto renderTarget = renderTargets->createRenderTarget(&tileTexture, 1);
312 auto depthTarget = renderTargets->createDepthStencilTarget(renderTarget);
314 context->setRenderTarget(renderTarget, depthTarget);
316 float color[] = { 0, 1, 0, 1, };
317 context->clearRenderTarget(color);
319 context->setEffect(upsampleTileEffectHandle);
321 Matrix projection = glm::ortho(0.0f, 1.0f, 0.0f, 1.0f, -1.0f, 1.0f);
322 const float sourceOrigin[] = { (tileId.x % 2) ? 0.5f : 0.0f, (tileId.y % 2) ? 0.5f : 0.0f };
324 MappedBuffer<UpsampleTileParameters> upsampleTileParameters(context, upsampleTileParameterBufferHandle,
MapMode::WriteDiscard);
325 if (upsampleTileParameters) {
326 upsampleTileParameters->projectionMatrix = projection;
327 upsampleTileParameters->sourceOrigin.x = sourceOrigin[0];
328 upsampleTileParameters->sourceOrigin.y = sourceOrigin[1];
331 context->setConstantBuffer(upsampleTileParameterBinding, upsampleTileParameterBufferHandle);
333 context->setViewport(0, 0,
static_cast<float>(width),
static_cast<float>(height));
335 const uint32_t strides[] = { 2 *
sizeof(float) };
336 context->setVertexBuffers(&vertexBufferHandle, 1, strides,
nullptr);
337 context->setInputLayout(upsampleTileLayoutHandle);
339 context->setTexture(
"coarseImagery", 0, parentTileData->textureHandle);
340 context->setSamplerState(
"TextureSampler", 0, linearClampStateHandle);
344 tileData->size = textureSize;
345 tileData->format = parentTileData->format;
346 tileData->textureHandle = tileTexture;
347 tileData->data.clear();
349 renderTargets->releaseDepthStencilTarget(depthTarget);
350 renderTargets->releaseRenderTarget(renderTarget);
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
@ Ready
The resource has loaded successfully and is ready for use.
@ VertexData
Per vertex data.
@ TriangleList
List of triangles.
@ Position
Position semantic.
@ Write
The buffer can be mapped and written to by the CPU after creation.
@ ConstantBuffer
The buffer can be bound as input to effects as a constant buffer.
static const Handle_t NoHandle
Represents a handle to nothing.
static const Handle_t InvalidHandle
Represents an invalid handle.
@ WriteDiscard
Write access. When unmapping the graphics system will discard the old contents of the resource.
@ Clamp
Texture coordinates are clamped to the [0, 1] range.
@ Wrap
Texture coordinates automatically wrap around to [0, 1] range.
@ MinMagMipPoint
Point sampling for both minification and magnification.
@ MinMagMipLinear
Linear sampling for both minification and magnification.
@ Dynamic
Buffer will be loaded and modified with some frequency.