feat: establish android particle field rendering loop
Some checks failed
validate-scripts / validate-scripts (push) Has been cancelled
Some checks failed
validate-scripts / validate-scripts (push) Has been cancelled
This commit is contained in:
@@ -9,6 +9,7 @@
|
||||
#include <mbgl/gfx/shader_registry.hpp>
|
||||
#include <mbgl/gfx/texture2d.hpp>
|
||||
#include <mbgl/map/transform_state.hpp>
|
||||
#include <mbgl/particle/field/offline_fixture_particle_adapter.hpp>
|
||||
#include <mbgl/renderer/buckets/heatmap_bucket.hpp>
|
||||
#include <mbgl/renderer/change_request.hpp>
|
||||
#include <mbgl/renderer/layer_group.hpp>
|
||||
@@ -42,6 +43,7 @@ constexpr Size MaskSize{16, 16};
|
||||
|
||||
std::atomic_uint64_t nextGpuGeneration{0};
|
||||
std::atomic_uint64_t nextMaskGeneration{0};
|
||||
std::atomic_uint64_t nextFieldGeneration{0};
|
||||
|
||||
const style::ParticleValidationLayer::Impl& impl(const Immutable<style::Layer::Impl>& value) {
|
||||
assert(value->getTypeInfo() == style::ParticleValidationLayer::Impl::staticTypeInfo());
|
||||
@@ -63,6 +65,34 @@ Size validViewportSize(const Size size) {
|
||||
return {std::max<uint32_t>(1, size.width), std::max<uint32_t>(1, size.height)};
|
||||
}
|
||||
|
||||
const char* fixtureID(const uint8_t mode) {
|
||||
switch (mode) {
|
||||
case 0:
|
||||
return "uniform-east";
|
||||
case 1:
|
||||
return "uniform-north";
|
||||
default:
|
||||
return "vortex";
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<PremultipliedImage> makeVelocityFieldImage(const particle::ParticleFieldSnapshot& field) {
|
||||
auto image = std::make_shared<PremultipliedImage>(Size{field.width, field.height});
|
||||
for (uint32_t y = 0; y < field.height; ++y) {
|
||||
for (uint32_t x = 0; x < field.width; ++x) {
|
||||
const auto cell = (static_cast<size_t>(y) * field.width + x) * 2;
|
||||
const auto pixel = (static_cast<size_t>(y) * field.width + x) * PremultipliedImage::channels;
|
||||
image->data[pixel + 0] = static_cast<uint8_t>(std::clamp(field.velocity[cell] * 0.5f + 0.5f, 0.0f, 1.0f) *
|
||||
255.0f);
|
||||
image->data[pixel + 1] = static_cast<uint8_t>(
|
||||
std::clamp(field.velocity[cell + 1] * 0.5f + 0.5f, 0.0f, 1.0f) * 255.0f);
|
||||
image->data[pixel + 2] = 0;
|
||||
image->data[pixel + 3] = 255;
|
||||
}
|
||||
}
|
||||
return image;
|
||||
}
|
||||
|
||||
// VALIDATION ONLY: deterministic global fixture with a diagonal coast. Alpha
|
||||
// 255 means OCEAN, alpha 0 means LAND. It is intentionally tiny and is not a
|
||||
// production coastline source.
|
||||
@@ -104,6 +134,7 @@ public:
|
||||
bool stateSeeded = false;
|
||||
bool trailSeeded = false;
|
||||
bool pending = false;
|
||||
bool bootstrapPending = false;
|
||||
bool contextDestroyed = false;
|
||||
bool staticFreezeLogged = false;
|
||||
bool cameraDrawLogged = false;
|
||||
@@ -111,6 +142,9 @@ public:
|
||||
bool antimeridianLogged = false;
|
||||
uint64_t lastCameraLogFrame = 0;
|
||||
uint64_t maskGeneration = 0;
|
||||
uint64_t fieldGeneration = 0;
|
||||
uint64_t gpuFieldGeneration = 0;
|
||||
uint8_t fixtureMode = 255;
|
||||
uint8_t loggedMaskMode = 255;
|
||||
Size trailSize{};
|
||||
|
||||
@@ -119,6 +153,10 @@ public:
|
||||
std::vector<RenderTargetPtr> registeredTargets;
|
||||
gfx::ShaderProgramBasePtr shader;
|
||||
gfx::Texture2DPtr maskTexture;
|
||||
gfx::Texture2DPtr fieldTexture;
|
||||
gfx::Texture2DPtr stateTexture;
|
||||
particle::ParticleFieldSnapshot field;
|
||||
std::shared_ptr<PremultipliedImage> fieldImage;
|
||||
std::shared_ptr<PremultipliedImage> maskFixture;
|
||||
std::shared_ptr<gfx::VertexVector<HeatmapTextureLayoutVertex>> vertices;
|
||||
SegmentVector segments;
|
||||
@@ -153,7 +191,10 @@ public:
|
||||
trailRead = trailWrite();
|
||||
stateSeeded = true;
|
||||
trailSeeded = true;
|
||||
++committedFrame;
|
||||
if (!bootstrapPending) {
|
||||
++committedFrame;
|
||||
}
|
||||
bootstrapPending = false;
|
||||
pending = false;
|
||||
}
|
||||
};
|
||||
@@ -169,6 +210,8 @@ public:
|
||||
gfx::Texture2DPtr source_,
|
||||
gfx::Texture2DPtr target_,
|
||||
gfx::Texture2DPtr mask_,
|
||||
gfx::Texture2DPtr stateTexture_,
|
||||
float simulationStep_,
|
||||
int16_t worldWrap_,
|
||||
uint8_t maskMode_)
|
||||
: state(std::move(state_)),
|
||||
@@ -178,6 +221,8 @@ public:
|
||||
source(std::move(source_)),
|
||||
target(std::move(target_)),
|
||||
mask(std::move(mask_)),
|
||||
stateTexture(std::move(stateTexture_)),
|
||||
simulationStep(simulationStep_),
|
||||
worldWrap(worldWrap_),
|
||||
maskMode(maskMode_) {}
|
||||
|
||||
@@ -193,9 +238,14 @@ public:
|
||||
if (mask) {
|
||||
drawable.setTexture(mask, shaders::idParticleGpuValidationMaskTexture);
|
||||
}
|
||||
if (resources->fieldTexture) {
|
||||
drawable.setTexture(resources->fieldTexture, shaders::idParticleGpuValidationFieldTexture);
|
||||
}
|
||||
if (stateTexture) {
|
||||
drawable.setTexture(stateTexture, shaders::idParticleGpuValidationStateTexture);
|
||||
}
|
||||
|
||||
const bool frozen = pass == ValidationPass::FrozenComposite;
|
||||
const float frame = static_cast<float>(resources->committedFrame + (frozen ? 0 : 1));
|
||||
const float frame = simulationStep;
|
||||
const float markerX = 0.5f + 0.32f * std::sin(frame * 0.071f);
|
||||
const float markerY = 0.5f + 0.32f * std::cos(frame * 0.053f);
|
||||
const shaders::ParticleGpuValidationUBO ubo = {
|
||||
@@ -308,6 +358,8 @@ private:
|
||||
gfx::Texture2DPtr source;
|
||||
gfx::Texture2DPtr target;
|
||||
gfx::Texture2DPtr mask;
|
||||
gfx::Texture2DPtr stateTexture;
|
||||
float simulationStep;
|
||||
int16_t worldWrap;
|
||||
uint8_t maskMode;
|
||||
};
|
||||
@@ -336,6 +388,8 @@ bool buildQuad(gfx::Context& context,
|
||||
const gfx::Texture2DPtr& source,
|
||||
const gfx::Texture2DPtr& target,
|
||||
const gfx::Texture2DPtr& mask,
|
||||
const gfx::Texture2DPtr& stateTexture,
|
||||
const float simulationStep,
|
||||
const ValidationPass pass,
|
||||
const uint8_t readSlot,
|
||||
const uint8_t writeSlot,
|
||||
@@ -372,8 +426,14 @@ bool buildQuad(gfx::Context& context,
|
||||
if (mask) {
|
||||
builder->setTexture(mask, shaders::idParticleGpuValidationMaskTexture);
|
||||
}
|
||||
if (resources->fieldTexture) {
|
||||
builder->setTexture(resources->fieldTexture, shaders::idParticleGpuValidationFieldTexture);
|
||||
}
|
||||
if (stateTexture) {
|
||||
builder->setTexture(stateTexture, shaders::idParticleGpuValidationStateTexture);
|
||||
}
|
||||
builder->addTweaker(std::make_shared<ParticleGpuValidationTweaker>(
|
||||
resources, pass, readSlot, writeSlot, source, target, mask, worldWrap, maskMode));
|
||||
resources, pass, readSlot, writeSlot, source, target, mask, stateTexture, simulationStep, worldWrap, maskMode));
|
||||
|
||||
// DrawableBuilder owns the current drawable until flush finalizes it.
|
||||
builder->flush(context);
|
||||
@@ -389,7 +449,8 @@ bool buildQuad(gfx::Context& context,
|
||||
} // namespace
|
||||
|
||||
RenderParticleValidationLayer::RenderParticleValidationLayer(Immutable<style::ParticleValidationLayer::Impl> impl_)
|
||||
: RenderLayer(makeMutable<style::ParticleValidationLayerProperties>(impl_, impl_->active, impl_->maskMode)) {
|
||||
: RenderLayer(makeMutable<style::ParticleValidationLayerProperties>(
|
||||
impl_, impl_->active, impl_->maskMode, impl_->fixtureMode)) {
|
||||
Log::Info(
|
||||
Event::Render,
|
||||
"ParticleValidation: RenderLayer create id=" + getID() + " source-less=true pass=translucent stage=30-02");
|
||||
@@ -407,16 +468,17 @@ RenderParticleValidationLayer::~RenderParticleValidationLayer() {
|
||||
void RenderParticleValidationLayer::evaluate(const PropertyEvaluationParameters&) {
|
||||
const bool active = impl(baseImpl).active;
|
||||
const uint8_t maskMode = impl(baseImpl).maskMode;
|
||||
const uint8_t fixtureMode = impl(baseImpl).fixtureMode;
|
||||
auto properties = makeMutable<style::ParticleValidationLayerProperties>(
|
||||
staticImmutableCast<style::ParticleValidationLayer::Impl>(baseImpl), active, maskMode);
|
||||
staticImmutableCast<style::ParticleValidationLayer::Impl>(baseImpl), active, maskMode, fixtureMode);
|
||||
passes = RenderPass::Translucent;
|
||||
properties->renderPasses = mbgl::underlying_type(passes);
|
||||
evaluatedProperties = std::move(properties);
|
||||
|
||||
Log::Info(Event::Render,
|
||||
"ParticleValidation: state=" + std::string(active ? "ACTIVE" : "STATIC") +
|
||||
" maskMode=" + std::to_string(maskMode) + " id=" + getID() +
|
||||
" layerIndex=" + std::to_string(getLayerIndex()) + " stage=30-03");
|
||||
" maskMode=" + std::to_string(maskMode) + " id=" + getID() + " fixture=" + fixtureID(fixtureMode) +
|
||||
" layerIndex=" + std::to_string(getLayerIndex()) + " stage=40-01");
|
||||
}
|
||||
|
||||
bool RenderParticleValidationLayer::needsRepaint() const {
|
||||
@@ -471,6 +533,7 @@ void RenderParticleValidationLayer::update(gfx::ShaderRegistry& shaders,
|
||||
const auto& properties = static_cast<const style::ParticleValidationLayerProperties&>(*evaluatedProperties);
|
||||
const bool active = properties.active;
|
||||
const uint8_t maskMode = properties.maskMode;
|
||||
const uint8_t fixtureMode = properties.fixtureMode;
|
||||
auto resources = gpuValidation;
|
||||
if (resources && resources->contextDestroyed) {
|
||||
// VALIDATION ONLY: follow the 30-02 resource-generation rule. No stale
|
||||
@@ -479,13 +542,6 @@ void RenderParticleValidationLayer::update(gfx::ShaderRegistry& shaders,
|
||||
resources.reset();
|
||||
}
|
||||
if (!resources) {
|
||||
if (!active) {
|
||||
// STATIC without a preceding ACTIVE frame has no trail to show. Do not create,
|
||||
// clear, or advance offscreen resources merely because the map redraws.
|
||||
static_cast<LayerGroup&>(*layerGroup).clearDrawables();
|
||||
return;
|
||||
}
|
||||
|
||||
auto owned = std::make_shared<ParticleGpuValidationResources>();
|
||||
owned->generation = ++nextGpuGeneration;
|
||||
owned->shader = context.getGenericShader(shaders, ShaderName);
|
||||
@@ -511,11 +567,51 @@ void RenderParticleValidationLayer::update(gfx::ShaderRegistry& shaders,
|
||||
.wrapU = gfx::TextureWrapType::Clamp,
|
||||
.wrapV = gfx::TextureWrapType::Clamp});
|
||||
owned->maskGeneration = ++nextMaskGeneration;
|
||||
try {
|
||||
owned->fieldGeneration = ++nextFieldGeneration;
|
||||
owned->field = particle::OfflineFixtureParticleAdapter::load(fixtureID(fixtureMode),
|
||||
owned->fieldGeneration);
|
||||
owned->fieldImage = makeVelocityFieldImage(owned->field);
|
||||
owned->fieldTexture = context.createTexture2D();
|
||||
if (!owned->fieldImage || !owned->fieldTexture) {
|
||||
Log::Error(Event::Render, "ParticleGPU: field resource creation failed");
|
||||
return;
|
||||
}
|
||||
owned->fieldTexture->setImage(owned->fieldImage);
|
||||
owned->fieldTexture->setSamplerConfiguration({.filter = gfx::TextureFilterType::Nearest,
|
||||
.wrapU = gfx::TextureWrapType::Repeat,
|
||||
.wrapV = gfx::TextureWrapType::Clamp});
|
||||
owned->gpuFieldGeneration = owned->fieldGeneration;
|
||||
owned->fixtureMode = fixtureMode;
|
||||
} catch (const std::exception& error) {
|
||||
Log::Error(Event::Render, "ParticleField: fixture load failed: " + std::string(error.what()));
|
||||
return;
|
||||
}
|
||||
gpuValidation = std::move(owned);
|
||||
resources = gpuValidation;
|
||||
Log::Info(Event::Render,
|
||||
"ParticleValidation30_02: State A/B create generation=" + std::to_string(resources->generation) +
|
||||
" size=16x16 independent=true");
|
||||
Log::Info(
|
||||
Event::Render,
|
||||
"ParticleField: fixture loaded id=" + resources->field.fixtureID + " type=" + resources->field.fieldType +
|
||||
" bounds=[" + std::to_string(resources->field.west) + ',' + std::to_string(resources->field.east) +
|
||||
"]x[" + std::to_string(resources->field.south) + ',' + std::to_string(resources->field.north) +
|
||||
"] grid=" + std::to_string(resources->field.width) + 'x' + std::to_string(resources->field.height) +
|
||||
" dataVersion=" + std::to_string(resources->field.dataVersion) +
|
||||
" fieldGeneration=" + std::to_string(resources->fieldGeneration));
|
||||
Log::Info(Event::Render,
|
||||
"ParticleField: fixture validated id=" + resources->field.fixtureID +
|
||||
" noData=" + std::to_string(resources->field.noData) +
|
||||
" velocityCount=" + std::to_string(resources->field.velocity.size()));
|
||||
Log::Info(Event::Render,
|
||||
"ParticleField: created id=" + resources->field.fixtureID +
|
||||
" generation=" + std::to_string(resources->fieldGeneration));
|
||||
Log::Info(Event::Render,
|
||||
"ParticleGPU: field upload reason=RESOURCE_RECREATE fixture=" + resources->field.fixtureID +
|
||||
" fieldGeneration=" + std::to_string(resources->fieldGeneration) +
|
||||
" gpuFieldGeneration=" + std::to_string(resources->gpuFieldGeneration) +
|
||||
" resourceGeneration=" + std::to_string(resources->generation));
|
||||
Log::Info(
|
||||
Event::Render,
|
||||
"ParticleValidation30_03: mask fixture ready id=coastal-mask-validation-v1 bounds=[-180,180]x[-85,85] "
|
||||
@@ -525,6 +621,41 @@ void RenderParticleValidationLayer::update(gfx::ShaderRegistry& shaders,
|
||||
"ParticleValidation30_03: anchors A=0,0 B=0,-90 C=0,-172.8 D=0,172.8 canonical=Mercator-z0");
|
||||
}
|
||||
|
||||
if (resources->fixtureMode != fixtureMode) {
|
||||
try {
|
||||
const auto fieldGeneration = ++nextFieldGeneration;
|
||||
auto field = particle::OfflineFixtureParticleAdapter::load(fixtureID(fixtureMode), fieldGeneration);
|
||||
auto image = makeVelocityFieldImage(field);
|
||||
auto texture = context.createTexture2D();
|
||||
if (!image || !texture) {
|
||||
Log::Error(Event::Render, "ParticleGPU: field switch resource creation failed");
|
||||
return;
|
||||
}
|
||||
texture->setImage(image);
|
||||
texture->setSamplerConfiguration({.filter = gfx::TextureFilterType::Nearest,
|
||||
.wrapU = gfx::TextureWrapType::Repeat,
|
||||
.wrapV = gfx::TextureWrapType::Clamp});
|
||||
resources->field = std::move(field);
|
||||
resources->fieldImage = std::move(image);
|
||||
resources->fieldTexture = std::move(texture);
|
||||
resources->fieldGeneration = fieldGeneration;
|
||||
resources->gpuFieldGeneration = fieldGeneration;
|
||||
resources->fixtureMode = fixtureMode;
|
||||
resources->resetSequence();
|
||||
Log::Info(Event::Render,
|
||||
"ParticleRender: fixture switched id=" + resources->field.fixtureID +
|
||||
" fieldGeneration=" + std::to_string(resources->fieldGeneration) + " gpuFieldGeneration=" +
|
||||
std::to_string(resources->gpuFieldGeneration) + " upload reason=FIELD_CHANGED trail=cleared");
|
||||
Log::Info(Event::Render,
|
||||
"ParticleField: fixture validated id=" + resources->field.fixtureID +
|
||||
" noData=" + std::to_string(resources->field.noData) +
|
||||
" velocityCount=" + std::to_string(resources->field.velocity.size()));
|
||||
} catch (const std::exception& error) {
|
||||
Log::Error(Event::Render, "ParticleField: fixture switch failed: " + std::string(error.what()));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (resources->loggedMaskMode != maskMode) {
|
||||
Log::Info(Event::Render,
|
||||
"ParticleValidation30_03: mask mode=" + std::to_string(maskMode) + " consumer=" +
|
||||
@@ -536,13 +667,119 @@ void RenderParticleValidationLayer::update(gfx::ShaderRegistry& shaders,
|
||||
removeTargets(resources->registeredTargets, changes);
|
||||
resources->registeredTargets.clear();
|
||||
|
||||
const auto viewport = validViewportSize(transformState.getSize());
|
||||
const auto ensureTrailTargets = [&] {
|
||||
if (resources->trailTargets[0] && resources->trailTargets[1] && resources->trailSize == viewport) {
|
||||
return true;
|
||||
}
|
||||
const auto previousSize = resources->trailSize;
|
||||
resources->trailTargets = {};
|
||||
for (uint8_t i = 0; i < 2; ++i) {
|
||||
resources->trailTargets[i] = createValidationTarget(
|
||||
context, viewport, getID() + "-trail-" + slotName(i), gfx::TextureFilterType::Linear);
|
||||
}
|
||||
if (!resources->trailTargets[0] || !resources->trailTargets[1]) {
|
||||
Log::Error(Event::Render, "ParticleGPU: Trail resource creation failed");
|
||||
return false;
|
||||
}
|
||||
resources->trailSize = viewport;
|
||||
resources->trailRead = 0;
|
||||
resources->trailSeeded = false;
|
||||
Log::Info(Event::Render,
|
||||
"ParticleGPU: Trail A/B " + std::string(previousSize.isEmpty() ? "create" : "resize") +
|
||||
" resourceGeneration=" + std::to_string(resources->generation) +
|
||||
" old=" + std::to_string(previousSize.width) + "x" + std::to_string(previousSize.height) +
|
||||
" new=" + std::to_string(viewport.width) + "x" + std::to_string(viewport.height) +
|
||||
" StatePreserved=true");
|
||||
return true;
|
||||
};
|
||||
|
||||
if (!active) {
|
||||
// Map gestures must still redraw the main pass, but STATIC is a simulation freeze:
|
||||
// no State/Trail RenderTarget is registered, no pending swap survives, and the
|
||||
// composite samples the last committed Trail slot with the current map frame.
|
||||
// STATIC freezes simulation only. A recreated activity still needs the
|
||||
// resource bootstrap and first current-frame composite without a button tap.
|
||||
if (!ensureTrailTargets()) {
|
||||
static_cast<LayerGroup&>(*layerGroup).clearDrawables();
|
||||
return;
|
||||
}
|
||||
resources->pending = false;
|
||||
auto& compositeGroup = static_cast<LayerGroup&>(*layerGroup);
|
||||
if (resources->trailSeeded && resources->trailTargets[resources->trailRead]) {
|
||||
if (!resources->stateSeeded || !resources->trailSeeded) {
|
||||
const auto stateWrite = resources->stateWrite();
|
||||
const auto trailWrite = resources->trailWrite();
|
||||
auto& stateGroup = static_cast<LayerGroup&>(*resources->stateTargets[stateWrite]->getLayerGroup(0));
|
||||
auto& trailGroup = static_cast<LayerGroup&>(*resources->trailTargets[trailWrite]->getLayerGroup(0));
|
||||
const bool stateBuilt = buildQuad(context,
|
||||
resources,
|
||||
stateGroup,
|
||||
getID() + "-static-bootstrap-state-pass",
|
||||
resources->stateTargets[resources->stateRead]->getTexture(),
|
||||
resources->stateTargets[stateWrite]->getTexture(),
|
||||
resources->maskTexture,
|
||||
{},
|
||||
0.0f,
|
||||
ValidationPass::State,
|
||||
resources->stateRead,
|
||||
stateWrite,
|
||||
0,
|
||||
maskMode,
|
||||
true);
|
||||
const bool trailBuilt = buildQuad(context,
|
||||
resources,
|
||||
trailGroup,
|
||||
getID() + "-static-bootstrap-trail-pass",
|
||||
resources->trailTargets[resources->trailRead]->getTexture(),
|
||||
resources->trailTargets[trailWrite]->getTexture(),
|
||||
resources->maskTexture,
|
||||
resources->stateTargets[stateWrite]->getTexture(),
|
||||
0.0f,
|
||||
ValidationPass::Trail,
|
||||
resources->trailRead,
|
||||
trailWrite,
|
||||
0,
|
||||
maskMode,
|
||||
true);
|
||||
compositeGroup.clearDrawables();
|
||||
bool compositeBuilt = true;
|
||||
const auto center = transformState.getLatLng(LatLng::Unwrapped);
|
||||
const auto centerWrap = wrapForLongitude(center.longitude());
|
||||
for (int16_t wrap = static_cast<int16_t>(centerWrap - 1); wrap <= centerWrap + 1; ++wrap) {
|
||||
compositeBuilt = buildQuad(context,
|
||||
resources,
|
||||
compositeGroup,
|
||||
getID() + "-static-bootstrap-composite-pass-" + std::to_string(wrap),
|
||||
resources->trailTargets[trailWrite]->getTexture(),
|
||||
{},
|
||||
resources->maskTexture,
|
||||
{},
|
||||
0.0f,
|
||||
ValidationPass::Composite,
|
||||
resources->trailRead,
|
||||
trailWrite,
|
||||
wrap,
|
||||
maskMode,
|
||||
false) &&
|
||||
compositeBuilt;
|
||||
}
|
||||
if (!stateBuilt || !trailBuilt || !compositeBuilt) {
|
||||
compositeGroup.clearDrawables();
|
||||
return;
|
||||
}
|
||||
resources->registeredTargets.emplace_back(resources->stateTargets[resources->stateRead]);
|
||||
resources->registeredTargets.emplace_back(resources->stateTargets[stateWrite]);
|
||||
resources->registeredTargets.emplace_back(resources->trailTargets[resources->trailRead]);
|
||||
resources->registeredTargets.emplace_back(resources->trailTargets[trailWrite]);
|
||||
for (const auto& target : resources->registeredTargets) {
|
||||
changes.emplace_back(std::make_unique<AddRenderTargetRequest>(target));
|
||||
}
|
||||
resources->bootstrapPending = true;
|
||||
resources->pending = true;
|
||||
Log::Info(Event::Render,
|
||||
"ParticleRender: STATIC bootstrap scheduled resourceGeneration=" +
|
||||
std::to_string(resources->generation) + " fixture=" + resources->field.fixtureID +
|
||||
" simulationFrame=" + std::to_string(resources->committedFrame));
|
||||
return;
|
||||
}
|
||||
if (resources->trailTargets[resources->trailRead]) {
|
||||
compositeGroup.clearDrawables();
|
||||
const auto center = transformState.getLatLng(LatLng::Unwrapped);
|
||||
const auto centerWrap = wrapForLongitude(center.longitude());
|
||||
@@ -554,6 +791,8 @@ void RenderParticleValidationLayer::update(gfx::ShaderRegistry& shaders,
|
||||
resources->trailTargets[resources->trailRead]->getTexture(),
|
||||
{},
|
||||
resources->maskTexture,
|
||||
{},
|
||||
0.0f,
|
||||
ValidationPass::FrozenComposite,
|
||||
resources->trailRead,
|
||||
resources->trailRead,
|
||||
@@ -567,28 +806,8 @@ void RenderParticleValidationLayer::update(gfx::ShaderRegistry& shaders,
|
||||
return;
|
||||
}
|
||||
resources->staticFreezeLogged = false;
|
||||
|
||||
const auto viewport = validViewportSize(transformState.getSize());
|
||||
if (!resources->trailTargets[0] || !resources->trailTargets[1] || resources->trailSize != viewport) {
|
||||
const auto previousSize = resources->trailSize;
|
||||
resources->trailTargets = {};
|
||||
for (uint8_t i = 0; i < 2; ++i) {
|
||||
resources->trailTargets[i] = createValidationTarget(
|
||||
context, viewport, getID() + "-trail-" + slotName(i), gfx::TextureFilterType::Linear);
|
||||
}
|
||||
if (!resources->trailTargets[0] || !resources->trailTargets[1]) {
|
||||
Log::Error(Event::Render, "ParticleValidation30_02: Trail resource creation failed");
|
||||
return;
|
||||
}
|
||||
resources->trailSize = viewport;
|
||||
resources->trailRead = 0;
|
||||
resources->trailSeeded = false;
|
||||
Log::Info(Event::Render,
|
||||
"ParticleValidation30_02: Trail A/B " + std::string(previousSize.isEmpty() ? "create" : "resize") +
|
||||
" generation=" + std::to_string(resources->generation) +
|
||||
" old=" + std::to_string(previousSize.width) + "x" + std::to_string(previousSize.height) +
|
||||
" new=" + std::to_string(viewport.width) + "x" + std::to_string(viewport.height) +
|
||||
" StatePreserved=true");
|
||||
if (!ensureTrailTargets()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto stateWrite = resources->stateWrite();
|
||||
@@ -604,6 +823,8 @@ void RenderParticleValidationLayer::update(gfx::ShaderRegistry& shaders,
|
||||
resources->stateTargets[resources->stateRead]->getTexture(),
|
||||
resources->stateTargets[stateWrite]->getTexture(),
|
||||
resources->maskTexture,
|
||||
{},
|
||||
1.0f,
|
||||
ValidationPass::State,
|
||||
resources->stateRead,
|
||||
stateWrite,
|
||||
@@ -617,6 +838,8 @@ void RenderParticleValidationLayer::update(gfx::ShaderRegistry& shaders,
|
||||
resources->trailTargets[resources->trailRead]->getTexture(),
|
||||
resources->trailTargets[trailWrite]->getTexture(),
|
||||
resources->maskTexture,
|
||||
resources->stateTargets[stateWrite]->getTexture(),
|
||||
1.0f,
|
||||
ValidationPass::Trail,
|
||||
resources->trailRead,
|
||||
trailWrite,
|
||||
@@ -635,6 +858,8 @@ void RenderParticleValidationLayer::update(gfx::ShaderRegistry& shaders,
|
||||
resources->trailTargets[trailWrite]->getTexture(),
|
||||
{},
|
||||
resources->maskTexture,
|
||||
{},
|
||||
0.0f,
|
||||
ValidationPass::Composite,
|
||||
resources->trailRead,
|
||||
trailWrite,
|
||||
|
||||
Reference in New Issue
Block a user