fix: finalize GPU particle time interpolation
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:
@@ -193,7 +193,8 @@ ParticleFieldSnapshot OfflineFixtureParticleAdapter::load(const std::string& fix
|
||||
if (bytes.size() != expected || member(integrity, "fieldByteLength").GetUint64() != expected) {
|
||||
throw std::invalid_argument("fixture field length mismatch: " + fixtureID);
|
||||
}
|
||||
if (sha256(bytes) != member(integrity, "fieldSha256").GetString()) {
|
||||
field.fieldSha256 = member(integrity, "fieldSha256").GetString();
|
||||
if (sha256(bytes) != field.fieldSha256) {
|
||||
throw std::invalid_argument("fixture field checksum mismatch: " + fixtureID);
|
||||
}
|
||||
field.velocity.resize(expected / sizeof(float));
|
||||
|
||||
@@ -21,6 +21,9 @@ struct ParticleFieldSnapshot {
|
||||
float noData = -9999.0f;
|
||||
uint64_t dataVersion = 0;
|
||||
uint64_t generation = 0;
|
||||
// Verified integrity.fieldSha256 identifies immutable GPU-upload content
|
||||
// across source reloads; generation remains a separate runtime revision.
|
||||
std::string fieldSha256;
|
||||
// Row-major, little-endian contract decoded as interleaved canonical
|
||||
// U-east/V-north values. A noData component makes the cell invalid.
|
||||
std::vector<float> velocity;
|
||||
@@ -41,6 +44,11 @@ inline bool fieldIdentityChanged(const ParticleFieldSnapshot& current, const Par
|
||||
current.dataVersion != next.dataVersion;
|
||||
}
|
||||
|
||||
inline bool sameFieldGpuContent(const ParticleFieldSnapshot& current, const ParticleFieldSnapshot& next) {
|
||||
return current.fixtureID == next.fixtureID && current.dataVersion == next.dataVersion &&
|
||||
current.fieldSha256 == next.fieldSha256 && current.isTimeInterpolationCompatibleWith(next);
|
||||
}
|
||||
|
||||
// A formal source time window. T0/T1 remain independent immutable snapshots;
|
||||
// the renderer uploads and samples them independently on the GPU.
|
||||
struct ParticleFieldTimeWindow {
|
||||
|
||||
@@ -732,10 +732,10 @@ void RenderRasterParticleLayer::update(gfx::ShaderRegistry& shaders,
|
||||
Log::Error(Event::Render, "ParticleGPU: rejected incompatible time-window fields");
|
||||
return;
|
||||
}
|
||||
const bool reuseOldT0 = !particle::fieldIdentityChanged(oldT0, nextT0);
|
||||
const bool reuseOldT1 = !particle::fieldIdentityChanged(oldT1, nextT0);
|
||||
const bool reuseNewT0 = !particle::fieldIdentityChanged(oldT0, nextT1);
|
||||
const bool reuseNewT1 = !particle::fieldIdentityChanged(oldT1, nextT1);
|
||||
const bool reuseOldT0 = particle::sameFieldGpuContent(oldT0, nextT0);
|
||||
const bool reuseOldT1 = particle::sameFieldGpuContent(oldT1, nextT0);
|
||||
const bool reuseNewT0 = particle::sameFieldGpuContent(oldT0, nextT1);
|
||||
const bool reuseNewT1 = particle::sameFieldGpuContent(oldT1, nextT1);
|
||||
const bool windowOverlap = reuseOldT0 || reuseOldT1 || reuseNewT0 || reuseNewT1;
|
||||
const auto upload = [&](const particle::ParticleFieldSnapshot& field,
|
||||
std::shared_ptr<PremultipliedImage>& image,
|
||||
@@ -754,13 +754,13 @@ void RenderRasterParticleLayer::update(gfx::ShaderRegistry& shaders,
|
||||
particle::ParticleFieldSnapshot& assigned,
|
||||
std::shared_ptr<PremultipliedImage>& image,
|
||||
gfx::Texture2DPtr& texture) {
|
||||
if (!particle::fieldIdentityChanged(oldT0, wanted)) {
|
||||
if (particle::sameFieldGpuContent(oldT0, wanted)) {
|
||||
assigned = oldT0;
|
||||
image = resources->fieldImage;
|
||||
texture = resources->fieldTexture;
|
||||
return true;
|
||||
}
|
||||
if (!particle::fieldIdentityChanged(oldT1, wanted)) {
|
||||
if (particle::sameFieldGpuContent(oldT1, wanted)) {
|
||||
assigned = oldT1;
|
||||
image = resources->nextFieldImage;
|
||||
texture = resources->nextFieldTexture;
|
||||
|
||||
Reference in New Issue
Block a user