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"
13#include "Foundation/Logging/Logger.h"
19 struct LevelParameters
21 glm::mat4 projectionMatrix;
22 glm::vec2 oneOverTextureSize;
23 glm::vec2 coarseRatio;
26 struct UpsampleParameters
28 glm::vec2 sourceOrigin;
30 glm::vec2 destinationOffset;
36 struct UpsampleTileParameters
38 glm::mat4 projectionMatrix;
39 glm::vec2 sourceOrigin;
43void Cogs::ClipmapUpsampler::initialize(IGraphicsDevice * device)
45 IEffects * effects = device->getEffects();
48 VertexFormatHandle positionFormat = device->getBuffers()->createVertexFormat(&positionElement, 1);
49 vertexBufferHandle = device->getBuffers()->loadVertexBuffer(quadVertices, 6, positionFormat);
51 LOG_DEBUG(logger,
"Loading clipmap upsample effect.");
53 upsampleEffectHandle = Terrain::EffectLoader::loadEffect(effects,
"ClipmapUpsampleVS",
"ClipmapUpsamplePS");
56 LOG_ERROR(logger,
"Error loading clipmap upsample effect.");
61 coarseImageryBinding = effects->getTextureBinding(upsampleEffectHandle,
"coarseImagery", 0);
62 coarseImagerySamplerBinding = effects->getSamplerStateBinding(upsampleEffectHandle,
"coarseImagerySampler", 0);
64 levelParameterBinding = effects->getConstantBufferBinding(upsampleEffectHandle,
"LevelParameters");
67 upsampleParameterBinding = effects->getConstantBufferBinding(upsampleEffectHandle,
"UpsampleParameters");
70 upsampleLayoutHandle = device->getBuffers()->loadInputLayout(&positionFormat, 1, upsampleEffectHandle);
72 LOG_DEBUG(logger,
"Loading clipmap upsample tile effect.");
74 upsampleTileEffectHandle = Terrain::EffectLoader::loadEffect(effects,
"ClipmapUpsampleTileVS",
"ClipmapUpsampleTilePS");
76 upsampleTileLayoutHandle = device->getBuffers()->loadInputLayout(&positionFormat, 1, upsampleTileEffectHandle);
78 upsampleTileParameterBinding = effects->getConstantBufferBinding(upsampleTileEffectHandle,
"UpsampleTileParameters");
81 SamplerState linearRepeatState = {
86 SamplerState::ComparisonFunction::Never,
88 { 0.0f, 0.0f, 0.0f, 0.0f },
91 linearRepeatStateHandle = device->getTextures()->loadSamplerState(linearRepeatState);
93 SamplerState pointRepeatState = {
98 SamplerState::ComparisonFunction::Never,
100 { 0.0f, 0.0f, 0.0f, 0.0f },
103 pointRepeatStateHandle = device->getTextures()->loadSamplerState(pointRepeatState);
105 SamplerState linearClampState = {
110 SamplerState::ComparisonFunction::Never,
112 { 0.0f, 0.0f, 0.0f, 0.0f },
115 linearClampStateHandle = device->getTextures()->loadSamplerState(linearClampState);
118void Cogs::ClipmapUpsampler::upsampleLevelRegions(RenderContext & renderContext,
119 ClipmapLevel * level,
120 const RasterTileRegion ** regions,
121 const size_t numRegions)
123 IContext * context = renderContext.context;
125 ClipmapLevel * coarserLevel = level->coarserLevel;
127 if (coarserLevel ==
nullptr || !numRegions) {
131 const RenderTexture * levelTexture = &level->renderTexture;
132 const RenderTexture * coarserLevelTexture = &coarserLevel->renderTexture;
134 if (coarserLevelTexture == levelTexture)
return;
136 const TextureOrigin & originInTextures = level->origin;
137 const TextureOrigin & coarserOriginInTextures = coarserLevel->origin;
139 const Extent & nextExtent = level->nextExtent;
140 const Extent & coarserNextExtent = coarserLevel->nextExtent;
142 const float noData = level->rasterLevel->getNoData();
143 const bool enableNoData = !std::isnan(noData);
145 const double ratioX = level->rasterLevel->getPostDeltaLongitude() / coarserLevel->rasterLevel->getPostDeltaLongitude();
146 const double ratioY = level->rasterLevel->getPostDeltaLatitude() / coarserLevel->rasterLevel->getPostDeltaLatitude();
150 context->setEffect(upsampleEffectHandle);
152 const float width =
static_cast<float>(levelTexture->width);
153 const float height =
static_cast<float>(levelTexture->height);
155 Matrix projection = glm::ortho<float>(0, width, 0, height, -1.0f, 1.0f);
157 context->setViewport(0, 0, width, height);
159 const uint32_t strides[] = { 2 *
sizeof(float) };
160 context->setVertexBuffers(&vertexBufferHandle, 1, strides,
nullptr);
161 context->setInputLayout(upsampleLayoutHandle);
163 context->setConstantBuffer(levelParameterBinding, levelParameterBufferHandle);
164 context->setConstantBuffer(upsampleParameterBinding, upsampleParameterBufferHandle);
166 context->setTexture(coarseImageryBinding, coarserLevelTexture->handle);
167 context->setSamplerState(coarseImagerySamplerBinding, enableNoData ? pointRepeatStateHandle : linearRepeatStateHandle);
169 const int fineClipmapWidth = nextExtent.getWidth();
170 const int fineClipmapHeight = nextExtent.getHeight();
172 const int coarseClipmapWidth = coarserNextExtent.getWidth();
173 const int coarseClipmapHeight = coarserNextExtent.getHeight();
175 const glm::vec2 oneOverTextureSize = { 1.0f / coarserLevelTexture->width, 1.0f / coarserLevelTexture->height };
176 const glm::vec2 coarseRatio = {
static_cast<float>(ratioX),
static_cast<float>(ratioY) };
179 MappedBuffer<LevelParameters> levelParameters(context, levelParameterBufferHandle,
MapMode::WriteDiscard);
181 if (levelParameters) {
182 levelParameters->projectionMatrix = projection;
183 levelParameters->oneOverTextureSize = oneOverTextureSize;
184 levelParameters->coarseRatio = coarseRatio;
188 for (
size_t i = 0; i < numRegions; ++i) {
189 const RasterTileRegion * region = regions[i];
191 const int destWest = (originInTextures[0] + (region->tile->extent.west + region->extent.west - nextExtent.west)) % fineClipmapWidth;
192 const int destSouth = (originInTextures[1] + (region->tile->extent.south + region->extent.south - nextExtent.south)) % fineClipmapHeight;
194 const double sourceWest = (int)(coarserOriginInTextures.x + ((region->tile->extent.west + region->extent.west) * ratioX - coarserNextExtent.west)) % coarseClipmapWidth;
195 const double sourceSouth = (int)(coarserOriginInTextures.y + ((region->tile->extent.south + region->extent.south) * ratioY - coarserNextExtent.south)) % coarseClipmapHeight;
197 const int regionWidth = region->extent.getWidth();
198 const int regionHeight = region->extent.getHeight();
200 const glm::vec2 sourceOrigin = {
static_cast<float>(sourceWest),
static_cast<float>(sourceSouth) };
201 const glm::vec2 updateSize = {
static_cast<float>(regionWidth),
static_cast<float>(regionHeight) };
202 const glm::vec2 destinationOffset = {
static_cast<float>(destWest),
static_cast<float>(destSouth) };
205 MappedBuffer<UpsampleParameters> upsampleParameters(context, upsampleParameterBufferHandle,
MapMode::WriteDiscard);
207 if (upsampleParameters) {
208 upsampleParameters->sourceOrigin = sourceOrigin;
209 upsampleParameters->updateSize = updateSize;
210 upsampleParameters->destinationOffset = destinationOffset;
212 upsampleParameters->enableNoData = enableNoData;
213 upsampleParameters->noData = noData;
228 float linear(
const float a,
const float b,
float amount)
230 return a * (1.0f - amount) + b * amount;
234Cogs::TextureHandle Cogs::ClipmapUpsampler::upsampleTile(RenderContext & renderContext, RasterSource * source, RasterTile * parentTile, RasterTile * tile)
236 IContext * context = renderContext.context;
237 IRenderTargets * renderTargets = renderContext.device->getRenderTargets();
239 const auto tileId = tile->identifier;
241 auto tileData = source->getTileData(tile);
242 const auto parentTileData = source->getTileData(parentTile);
244 if (!tileData || !parentTileData) {
248 const size_t width =
static_cast<size_t>(tile->getWidth());
249 const size_t height =
static_cast<size_t>(tile->getHeight());
250 const auto bpp = Cogs::getBlockSize(parentTileData->format);
251 const auto textureSize = Cogs::getTextureSize(
static_cast<int>(width),
static_cast<int>(height), parentTileData->format);
253 bool useMemCopyUpsample =
true;
255 if (useMemCopyUpsample) {
260 source->allocateTileStorage(textureSize, tileData->data);
262 auto bytes = tileData->data.data();
264 if (parentTileData->format == TextureFormat::R32_FLOAT) {
265 const float * parentData =
reinterpret_cast<float *
>(parentTileData->data.data());
267 for (
size_t y = 0; y < height; ++y) {
268 for (
size_t x = 0; x < width; ++x) {
269 size_t xx = x / 2 + ((tileId.x % 2) ? width / 2 : 0);
270 size_t yy = y / 2 + ((tileId.y % 2) ? height / 2 : 0);
272 float v1 = parentData[yy * width + xx];
273 float v2 = parentData[yy * width + xx + ((xx < width - 1) ? 1 : 0)];
275 float v3 = parentData[(yy + ((yy < height - 1) ? 1 : 0)) * width + xx];
276 float v4 = parentData[(yy + ((yy < height - 1) ? 1 : 0)) * width + xx + ((xx < width - 1) ? 1 : 0)];
278 ((
float *)bytes)[y * width + x] = linear(
279 linear(v1, v2, (x % 2) ? 0.5f : 0.0f),
280 linear(v3, v4, (x % 2) ? 0.5f : 0.0f),
281 (y % 2) ? 0.5f : 0.0f);
285 const auto parentBytes = parentTileData->data.data();
287 for (
size_t y = 0; y < height; ++y) {
288 for (
size_t x = 0; x < width; ++x) {
289 size_t xx = x / 2 + ((tileId.x % 2) ? width / 2 : 0);
290 size_t yy = y / 2 + ((tileId.y % 2) ? height / 2 : 0);
292 std::memcpy(bytes + (y * width + x) * bpp, parentBytes + (yy * width + xx) * bpp, bpp);
297 auto tileTexture = source->loadTexture(bytes,
static_cast<int>(width),
static_cast<int>(height), parentTileData->format, textureSize);
299 tileData->size = textureSize;
300 tileData->format = parentTileData->format;
301 tileData->textureHandle = tileTexture;
305 auto tileTexture = source->loadTexture(
nullptr,
static_cast<int>(width),
static_cast<int>(height), parentTileData->format, textureSize);
307 auto renderTarget = renderTargets->createRenderTarget(&tileTexture, 1);
308 auto depthTarget = renderTargets->createDepthStencilTarget(renderTarget);
310 context->setRenderTarget(renderTarget, depthTarget);
312 float color[] = { 0, 1, 0, 1, };
313 context->clearRenderTarget(color);
315 context->setEffect(upsampleTileEffectHandle);
317 Matrix projection = glm::ortho(0.0f, 1.0f, 0.0f, 1.0f, -1.0f, 1.0f);
318 const float sourceOrigin[] = { (tileId.x % 2) ? 0.5f : 0.0f, (tileId.y % 2) ? 0.5f : 0.0f };
320 MappedBuffer<UpsampleTileParameters> upsampleTileParameters(context, upsampleTileParameterBufferHandle,
MapMode::WriteDiscard);
321 if (upsampleTileParameters) {
322 upsampleTileParameters->projectionMatrix = projection;
323 upsampleTileParameters->sourceOrigin.x = sourceOrigin[0];
324 upsampleTileParameters->sourceOrigin.y = sourceOrigin[1];
327 context->setConstantBuffer(upsampleTileParameterBinding, upsampleTileParameterBufferHandle);
329 context->setViewport(0, 0,
static_cast<float>(width),
static_cast<float>(height));
331 const uint32_t strides[] = { 2 *
sizeof(float) };
332 context->setVertexBuffers(&vertexBufferHandle, 1, strides,
nullptr);
333 context->setInputLayout(upsampleTileLayoutHandle);
335 context->setTexture(
"coarseImagery", 0, parentTileData->textureHandle);
336 context->setSamplerState(
"TextureSampler", 0, linearClampStateHandle);
340 tileData->size = textureSize;
341 tileData->format = parentTileData->format;
342 tileData->textureHandle = tileTexture;
343 tileData->data.clear();
345 renderTargets->releaseDepthStencilTarget(depthTarget);
346 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
@ VertexData
Per vertex data.
@ 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.
@ TriangleList
List of triangles.
@ 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.