feat: admit settled Symbol render results to retained cache
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:
@@ -10,8 +10,10 @@
|
||||
#include <mln/renderer/render_source.hpp>
|
||||
#include <mln/renderer/render_source_observer.hpp>
|
||||
#include <mln/renderer/tile_render_data.hpp>
|
||||
#include <mln/renderer/symbol_render_result.hpp>
|
||||
#include <mln/style/sources/geojson_source_impl.hpp>
|
||||
#include <mln/style/layers/symbol_layer.hpp>
|
||||
#include <mln/style/layers/background_layer.hpp>
|
||||
#include <mln/tile/tile.hpp>
|
||||
#include <mln/tile/tile_observer.hpp>
|
||||
|
||||
@@ -435,3 +437,137 @@ TEST(Step117Safety, RealAsyncCallbacksAndContextStyleCleanupAdvanceContentEpoch)
|
||||
scheduler.runRenderJobs();
|
||||
// Actual callback dispatch, but no network delivery, GPU, or Android assertion.
|
||||
}
|
||||
|
||||
namespace {
|
||||
void step119Certify(SymbolResultCertificate& certificate, SymbolResultBinding binding) {
|
||||
SymbolRenderResult result;
|
||||
result.append(255.0f);
|
||||
EXPECT_FALSE(certificate.observeFull(result, binding, true));
|
||||
certificate.completeFull(binding, true, false);
|
||||
EXPECT_TRUE(certificate.observeFull(result, binding, true));
|
||||
certificate.completeFull(binding, true, true);
|
||||
EXPECT_TRUE(certificate.observeFull(result, binding, true));
|
||||
certificate.completeFull(binding, true, false, true);
|
||||
EXPECT_TRUE(certificate.canFast(binding));
|
||||
}
|
||||
} // namespace
|
||||
|
||||
TEST(Step119SymbolResults, RealTileGlyphImageStyleContextCallbacksRejectBuiltCertificate) {
|
||||
TaggedScheduler scheduler{Scheduler::GetBackground(), {}};
|
||||
RenderOrchestrator orchestrator(false, scheduler, std::nullopt);
|
||||
std::atomic<int> deferred{0}, jobs{0}, detached{0};
|
||||
auto source = std::make_unique<TeardownSource>(scheduler, deferred, jobs, detached);
|
||||
const auto rejects = [&](auto event) {
|
||||
SymbolResultBinding binding;
|
||||
binding.content = orchestrator.getRetainedUnderlayContentRevision();
|
||||
SymbolResultCertificate certificate;
|
||||
step119Certify(certificate, binding);
|
||||
event();
|
||||
binding.content = orchestrator.getRetainedUnderlayContentRevision();
|
||||
EXPECT_FALSE(certificate.canFast(binding));
|
||||
};
|
||||
rejects([&] {
|
||||
static_cast<RenderSourceObserver&>(orchestrator).onTileChanged(*source, OverscaledTileID{2, 1, {2, 1, 1}});
|
||||
});
|
||||
rejects([&] { static_cast<GlyphManagerObserver&>(orchestrator).onGlyphsLoaded({}, {0, 255}); });
|
||||
rejects([&] { static_cast<ImageManagerObserver&>(orchestrator).onStyleImageMissing("step119-icon", [] {}); });
|
||||
rejects([&] { orchestrator.markContextLost(); });
|
||||
rejects([&] { orchestrator.clearData(); });
|
||||
source->setObserver(nullptr);
|
||||
source.reset();
|
||||
scheduler.waitForEmpty();
|
||||
scheduler.runRenderJobs();
|
||||
}
|
||||
|
||||
TEST(Step119SymbolResults, AppliedCrossSegmentRegistryRebuildChangesExactEvidence) {
|
||||
TaggedScheduler scheduler{Scheduler::GetBackground(), {}};
|
||||
RenderOrchestrator orchestrator(false, scheduler, std::nullopt);
|
||||
auto runtime = std::make_shared<RetainedUnderlayRuntimeState>();
|
||||
style::BackgroundLayer lower("step119-lower"), continuous("step119-middle"), upper("step119-upper");
|
||||
const Immutable<std::vector<Immutable<style::Layer::Impl>>> layers =
|
||||
makeMutable<std::vector<Immutable<style::Layer::Impl>>>(
|
||||
std::initializer_list<Immutable<style::Layer::Impl>>{lower.baseImpl, continuous.baseImpl, upper.baseImpl});
|
||||
const Immutable<std::vector<Immutable<style::Source::Impl>>> sources =
|
||||
makeMutable<std::vector<Immutable<style::Source::Impl>>>();
|
||||
auto tree = orchestrator.createRenderTree(step117TreeParameters(layers, sources, runtime, TimePoint{}), nullptr);
|
||||
ASSERT_TRUE(tree);
|
||||
orchestrator.processChanges();
|
||||
auto group = std::make_shared<TestLayerGroup>(0);
|
||||
ASSERT_TRUE(orchestrator.addLayerGroup(group));
|
||||
ASSERT_TRUE(orchestrator.addLayerGroup(std::make_shared<TestLayerGroup>(2)));
|
||||
const auto before = orchestrator.retainedSymbolRenderResult(2, 3, 1, 0);
|
||||
ASSERT_TRUE(before.complete);
|
||||
SymbolResultCertificate certificate;
|
||||
SymbolResultBinding binding;
|
||||
step119Certify(certificate, binding);
|
||||
UniqueChangeRequestVec changes;
|
||||
changes.emplace_back(std::make_unique<RemoveLayerGroupRequest>(group));
|
||||
RenderOrchestratorTeardownTestAccess::enqueue(orchestrator, changes);
|
||||
const auto pending = orchestrator.retainedSymbolRenderResult(2, 3, 1, 0);
|
||||
EXPECT_FALSE(pending.complete);
|
||||
EXPECT_FALSE(certificate.observeFull(pending, binding, true));
|
||||
orchestrator.processChanges();
|
||||
EXPECT_EQ(orchestrator.numLayerGroups(), 1u);
|
||||
const auto after = orchestrator.retainedSymbolRenderResult(2, 3, 1, 0);
|
||||
EXPECT_TRUE(after.complete);
|
||||
EXPECT_NE(before.bytes, after.bytes); // actual global count + original ordinal changed
|
||||
EXPECT_FALSE(certificate.canFast(binding));
|
||||
}
|
||||
|
||||
TEST(Step119SymbolResults, RangeDrawFailureInvalidatesContentAndCompletedEvidence) {
|
||||
TaggedScheduler scheduler{Scheduler::GetBackground(), {}};
|
||||
RenderOrchestrator orchestrator(false, scheduler, std::nullopt);
|
||||
ErrorObserver observer;
|
||||
orchestrator.setObserver(&observer);
|
||||
ASSERT_TRUE(orchestrator.addLayerGroup(std::make_shared<TestLayerGroup>(0)));
|
||||
SymbolResultBinding binding;
|
||||
binding.content = orchestrator.getRetainedUnderlayContentRevision();
|
||||
SymbolResultCertificate certificate;
|
||||
step119Certify(certificate, binding);
|
||||
const auto errors = orchestrator.getRenderErrorRevision();
|
||||
bool failed = false;
|
||||
orchestrator.visitLayerGroupsInRange(0, 1, [](LayerGroupBase&, size_t) {
|
||||
throw std::runtime_error("step119-upload-or-draw");
|
||||
}, &failed);
|
||||
EXPECT_TRUE(failed);
|
||||
EXPECT_EQ(observer.errors, 1);
|
||||
EXPECT_GT(orchestrator.getRenderErrorRevision(), errors);
|
||||
binding.content = orchestrator.getRetainedUnderlayContentRevision();
|
||||
EXPECT_FALSE(certificate.canReuse(binding));
|
||||
EXPECT_FALSE(certificate.canFast(binding));
|
||||
}
|
||||
|
||||
TEST(Step119SymbolResults, RealSourceReplacementAndMissingSourceRetainFailClosed) {
|
||||
TaggedScheduler scheduler{Scheduler::GetBackground(), {}};
|
||||
RenderOrchestrator orchestrator(false, scheduler, std::nullopt);
|
||||
auto runtime = std::make_shared<RetainedUnderlayRuntimeState>();
|
||||
ASSERT_TRUE(runtime->setRenderSegmentPlan({1, {{RenderSegmentStrategy::Retained, std::nullopt}}}));
|
||||
style::SymbolLayer symbol("step119-symbol", "step119-source");
|
||||
const Immutable<std::vector<Immutable<style::Layer::Impl>>> layers =
|
||||
makeMutable<std::vector<Immutable<style::Layer::Impl>>>(
|
||||
std::initializer_list<Immutable<style::Layer::Impl>>{symbol.baseImpl});
|
||||
const auto sourceList = []() -> Immutable<std::vector<Immutable<style::Source::Impl>>> {
|
||||
return makeMutable<std::vector<Immutable<style::Source::Impl>>>(
|
||||
std::initializer_list<Immutable<style::Source::Impl>>{
|
||||
makeMutable<style::GeoJSONSource::Impl>("step119-source", style::GeoJSONOptions::defaultOptions())});
|
||||
};
|
||||
auto tree = orchestrator.createRenderTree(step117TreeParameters(layers, sourceList(), runtime, TimePoint{}), nullptr);
|
||||
ASSERT_TRUE(tree);
|
||||
SymbolResultBinding binding;
|
||||
binding.content = orchestrator.getRetainedUnderlayContentRevision();
|
||||
SymbolResultCertificate certificate;
|
||||
step119Certify(certificate, binding);
|
||||
tree.reset();
|
||||
tree = orchestrator.createRenderTree(step117TreeParameters(layers, sourceList(), runtime, TimePoint{} + Seconds(1)), nullptr);
|
||||
ASSERT_TRUE(tree);
|
||||
binding.content = orchestrator.getRetainedUnderlayContentRevision();
|
||||
EXPECT_FALSE(certificate.canFast(binding));
|
||||
tree.reset();
|
||||
const Immutable<std::vector<Immutable<style::Source::Impl>>> absent =
|
||||
makeMutable<std::vector<Immutable<style::Source::Impl>>>();
|
||||
tree = orchestrator.createRenderTree(step117TreeParameters(layers, absent, runtime, TimePoint{} + Seconds(2)), nullptr);
|
||||
ASSERT_TRUE(tree);
|
||||
EXPECT_STREQ(orchestrator.retainedSegmentSourceState(0, 1).reason, "missing-source");
|
||||
binding.content = orchestrator.getRetainedUnderlayContentRevision();
|
||||
EXPECT_FALSE(certificate.canFast(binding));
|
||||
}
|
||||
|
||||
@@ -5,11 +5,18 @@
|
||||
#include <mln/renderer/render_segment_plan.hpp>
|
||||
#include <mln/renderer/update_parameters.hpp>
|
||||
#include <mln/text/placement.hpp>
|
||||
#include <mln/renderer/symbol_render_result.hpp>
|
||||
#include <mln/renderer/symbol_render_inputs.hpp>
|
||||
#include <mln/renderer/buckets/symbol_bucket.hpp>
|
||||
#include <mln/renderer/symbol_shader_provenance.hpp>
|
||||
#include <mln/shaders/symbol_layer_ubo.hpp>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <initializer_list>
|
||||
#include <limits>
|
||||
#include <stdexcept>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
@@ -98,6 +105,265 @@ std::shared_ptr<UpdateParameters> step117PlacementParameters(TimePoint now,
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace {
|
||||
SymbolResultBinding step119Binding() {
|
||||
SymbolResultBinding binding;
|
||||
binding.viewport = {640, 480};
|
||||
binding.camera = key().cameraMatrix;
|
||||
binding.content = binding.topology = binding.config = 1;
|
||||
return binding;
|
||||
}
|
||||
|
||||
SymbolRenderResult step119BufferResult(const SymbolBucket::Buffer& buffer, float fade) {
|
||||
SymbolRenderResult result;
|
||||
const auto& dynamic = buffer.dynamicAttributeData();
|
||||
const auto& opacity = buffer.opacityAttributeData();
|
||||
result.appendBlock(dynamic.getRawData(), dynamic.bytes());
|
||||
result.appendBlock(opacity.getRawData(), opacity.bytes());
|
||||
for (const auto& vertex : opacity.vector()) {
|
||||
result.complete = result.complete && symbolOpacityIsSettled(vertex.a1[0], fade);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void step119Settle(SymbolResultCertificate& certificate, const SymbolRenderResult& result,
|
||||
const SymbolResultBinding& binding) {
|
||||
EXPECT_FALSE(certificate.observeFull(result, binding, true));
|
||||
certificate.completeFull(binding, true, false);
|
||||
EXPECT_TRUE(certificate.observeFull(result, binding, true));
|
||||
EXPECT_FALSE(certificate.candidateHasBuild(binding));
|
||||
certificate.completeFull(binding, true, true);
|
||||
EXPECT_TRUE(certificate.canReuse(binding));
|
||||
EXPECT_FALSE(certificate.canFast(binding));
|
||||
EXPECT_TRUE(certificate.observeFull(result, binding, true));
|
||||
EXPECT_TRUE(certificate.candidateHasBuild(binding));
|
||||
certificate.completeFull(binding, true, false, true);
|
||||
EXPECT_TRUE(certificate.canFast(binding));
|
||||
}
|
||||
} // namespace
|
||||
|
||||
TEST(Step119SymbolResults, FreshSettledBuildReuseWithRealControllerAndBuffer) {
|
||||
const auto start = TimePoint{} + Seconds(10);
|
||||
PlacementController controller;
|
||||
SymbolBucket::Buffer buffer;
|
||||
buffer.dynamicAttributeData().emplace_back(SymbolBucket::dynamicLayoutAttributes({20, 30}, 0));
|
||||
buffer.opacityAttributeData().emplace_back(SymbolBucket::opacityAttributes(true, 1));
|
||||
SymbolResultCertificate certificate;
|
||||
RetainedUnderlayCache cache;
|
||||
const auto binding = step119Binding();
|
||||
unsigned builds = 0, reuses = 0, calculations = 0;
|
||||
for (unsigned frame = 0; frame < 50; ++frame) {
|
||||
const auto now = start + Milliseconds(frame * 30);
|
||||
if (!controller.placementIsRecent(now, 0)) {
|
||||
auto placement = Placement::create(step117PlacementParameters(now), controller.getPlacement());
|
||||
placement->placeLayers({});
|
||||
controller.setPlacement(std::move(placement));
|
||||
++calculations;
|
||||
} else {
|
||||
controller.setPlacementStale();
|
||||
EXPECT_TRUE(controller.hasTransitions(now)); // scheduling preserved
|
||||
EXPECT_FALSE(controller.hasActiveSymbolFade(now));
|
||||
}
|
||||
const auto result = step119BufferResult(buffer, controller.getPlacement()->symbolFadeChange(now));
|
||||
const bool stable = certificate.observeFull(result, binding, !controller.hasActiveSymbolFade(now));
|
||||
const auto decision = cache.evaluate(key(), certificate.current(), stable, "static-placement");
|
||||
EXPECT_FALSE(certificate.canFast(binding)); // Full still in flight
|
||||
if (decision == RetainedUnderlayDecision::Build) { cache.markBuildSucceeded(); ++builds; }
|
||||
if (decision == RetainedUnderlayDecision::Reuse) ++reuses;
|
||||
certificate.completeFull(binding, true, decision == RetainedUnderlayDecision::Build,
|
||||
decision == RetainedUnderlayDecision::Reuse);
|
||||
}
|
||||
EXPECT_GT(calculations, 1u);
|
||||
EXPECT_EQ(builds, 1u);
|
||||
EXPECT_GT(reuses, 0u);
|
||||
EXPECT_TRUE(certificate.canFast(binding));
|
||||
// Cache submission here is a state-machine fixture, not a GPU draw proof.
|
||||
}
|
||||
|
||||
TEST(Step119SymbolResults, ActualPackedOpacityRejectsFadeAndAcceptsShaderEndpoints) {
|
||||
for (unsigned opacity = 0; opacity <= 127; ++opacity) {
|
||||
const float packedIn = static_cast<float>(opacity * 2 + 1);
|
||||
const float packedOut = static_cast<float>(opacity * 2);
|
||||
EXPECT_EQ(symbolOpacityIsSettled(packedIn, 0), opacity == 127);
|
||||
EXPECT_EQ(symbolOpacityIsSettled(packedOut, 0), opacity == 0);
|
||||
EXPECT_TRUE(symbolOpacityIsSettled(packedIn, 1));
|
||||
EXPECT_TRUE(symbolOpacityIsSettled(packedOut, 1));
|
||||
EXPECT_TRUE(symbolOpacityIsSettled(packedIn, 5));
|
||||
}
|
||||
EXPECT_FALSE(symbolOpacityIsSettled(1, 0.5f));
|
||||
EXPECT_FALSE(symbolOpacityIsSettled(254, 0.5f));
|
||||
EXPECT_FALSE(symbolOpacityIsSettled(1.5f, 1));
|
||||
EXPECT_FALSE(symbolOpacityIsSettled(256, 1));
|
||||
EXPECT_FALSE(symbolOpacityIsSettled(1, std::numeric_limits<float>::infinity()));
|
||||
EXPECT_FALSE(symbolOpacityIsSettled(1, std::numeric_limits<float>::quiet_NaN()));
|
||||
EXPECT_FALSE(symbolOpacityIsSettled(255, -1));
|
||||
SymbolBucket::Buffer buffer;
|
||||
buffer.opacityAttributeData().emplace_back(SymbolBucket::opacityAttributes(true, 0));
|
||||
SymbolResultCertificate certificate;
|
||||
const auto binding = step119Binding();
|
||||
const auto fading = step119BufferResult(buffer, 0.5f);
|
||||
ASSERT_FALSE(fading.complete);
|
||||
EXPECT_FALSE(certificate.observeFull(fading, binding, true));
|
||||
certificate.completeFull(binding, true, true);
|
||||
EXPECT_FALSE(certificate.canReuse(binding));
|
||||
}
|
||||
|
||||
TEST(Step119SymbolResults, SamePlacedBooleanDoesNotProveVariableAnchorOrOrientation) {
|
||||
SymbolBucket::Buffer buffer;
|
||||
buffer.dynamicAttributeData().emplace_back(SymbolBucket::dynamicLayoutAttributes({20, 30}, 0));
|
||||
buffer.opacityAttributeData().emplace_back(SymbolBucket::opacityAttributes(true, 1));
|
||||
const auto binding = step119Binding();
|
||||
for (const auto changed : {SymbolBucket::dynamicLayoutAttributes({21, 30}, 0),
|
||||
SymbolBucket::dynamicLayoutAttributes({20, 30}, 1)}) {
|
||||
buffer.dynamicAttributeData().at(0) = SymbolBucket::dynamicLayoutAttributes({20, 30}, 0);
|
||||
SymbolResultCertificate certificate;
|
||||
step119Settle(certificate, step119BufferResult(buffer, 1), binding);
|
||||
buffer.dynamicAttributeData().at(0) = changed;
|
||||
EXPECT_FALSE(certificate.observeFull(step119BufferResult(buffer, 1), binding, true));
|
||||
EXPECT_FALSE(certificate.canFast(binding));
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Step119SymbolResults, CameraViewportPixelRatioAndCollisionConfigurationInvalidate) {
|
||||
SymbolRenderResult result;
|
||||
result.append(255.0f);
|
||||
const auto original = step119Binding();
|
||||
std::vector<SymbolResultBinding> updates(7, original);
|
||||
updates[0].camera[12] += 1; // pan
|
||||
updates[1].camera[0] *= 2; // zoom
|
||||
updates[2].camera[1] = 0.5; // rotation/pitch projection
|
||||
updates[3].viewport.width += 1;
|
||||
updates[4].pixelRatio = 2;
|
||||
updates[5].crossSourceCollisions = false;
|
||||
updates[6].config += 1;
|
||||
for (const auto& update : updates) {
|
||||
SymbolResultCertificate certificate;
|
||||
step119Settle(certificate, result, original);
|
||||
EXPECT_FALSE(certificate.canFast(update));
|
||||
EXPECT_FALSE(certificate.observeFull(result, update, true));
|
||||
}
|
||||
CollisionGroups shared(true), isolated(false);
|
||||
EXPECT_EQ(shared.get("A").first, shared.get("B").first);
|
||||
EXPECT_NE(isolated.get("A").first, isolated.get("B").first);
|
||||
}
|
||||
|
||||
TEST(Step119SymbolResults, FailedUploadDrawSubmissionAndUnreadableResultsCannotCertify) {
|
||||
SymbolRenderResult result;
|
||||
result.append(255.0f);
|
||||
const auto binding = step119Binding();
|
||||
SymbolResultCertificate certificate;
|
||||
EXPECT_FALSE(certificate.observeFull(result, binding, true));
|
||||
certificate.completeFull(binding, false, false);
|
||||
EXPECT_FALSE(certificate.observeFull(result, binding, true));
|
||||
certificate.completeFull(binding, true, false);
|
||||
EXPECT_TRUE(certificate.observeFull(result, binding, true));
|
||||
certificate.completeFull(binding, true, false); // resource/compositor failed
|
||||
EXPECT_FALSE(certificate.canReuse(binding));
|
||||
result.complete = false;
|
||||
EXPECT_FALSE(certificate.observeFull(result, binding, true));
|
||||
certificate.completeFull(binding, true, true);
|
||||
EXPECT_FALSE(certificate.canFast(binding));
|
||||
SymbolRenderResult oversize;
|
||||
oversize.appendBytes(nullptr, SymbolRenderResult::maxBytes + 1);
|
||||
EXPECT_FALSE(oversize.complete);
|
||||
auto attributes = std::make_shared<gfx::VertexAttributeArray>();
|
||||
const auto& attribute = attributes->set(shaders::idSymbolFadeOpacityAttribute);
|
||||
ASSERT_TRUE(attribute);
|
||||
auto opacity = std::make_shared<SymbolBucket::OpacityAttributeVector>();
|
||||
opacity->emplace_back(SymbolBucket::opacityAttributes(true, 1));
|
||||
attribute->setSharedRawData(opacity, 0, 0, sizeof(SymbolOpacityAttributes), gfx::AttributeDataType::Float);
|
||||
SymbolRenderResult notUploaded;
|
||||
appendSymbolAttributes(notUploaded, attributes);
|
||||
EXPECT_FALSE(notUploaded.complete); // real CPU vector without a GPU buffer
|
||||
opacity->release();
|
||||
SymbolRenderResult releasedWithoutBacking;
|
||||
appendSymbolAttributes(releasedWithoutBacking, attributes);
|
||||
EXPECT_FALSE(releasedWithoutBacking.complete);
|
||||
}
|
||||
|
||||
TEST(Step119SymbolResults, ExactPayloadAndAtlasIdentityRequireNewResultRevision) {
|
||||
const auto binding = step119Binding();
|
||||
SymbolRenderResult original;
|
||||
original.append(255.0f);
|
||||
original.append(0.0f); // uniform / draw ordering test payload
|
||||
for (unsigned component = 0; component < original.bytes.size(); ++component) {
|
||||
SymbolResultCertificate certificate;
|
||||
step119Settle(certificate, original, binding);
|
||||
auto changed = original;
|
||||
changed.bytes[component] ^= 1;
|
||||
const auto revision = certificate.current();
|
||||
EXPECT_FALSE(certificate.observeFull(changed, binding, true));
|
||||
EXPECT_FALSE(certificate.candidateHasBuild(binding));
|
||||
EXPECT_GT(certificate.current(), revision);
|
||||
EXPECT_FALSE(certificate.matchesCandidate(original));
|
||||
}
|
||||
// Shader/texture identities are kept alive as part of the exact evidence.
|
||||
auto oldAtlas = std::make_shared<unsigned>(1), newAtlas = std::make_shared<unsigned>(1);
|
||||
SymbolRenderResult oldResult, newResult;
|
||||
oldResult.retain(oldAtlas);
|
||||
newResult.retain(newAtlas);
|
||||
SymbolResultCertificate certificate;
|
||||
step119Settle(certificate, oldResult, binding);
|
||||
EXPECT_FALSE(certificate.observeFull(newResult, binding, true));
|
||||
// Payload coverage is not a texture readback or real wrap/collision draw.
|
||||
}
|
||||
|
||||
TEST(Step119SymbolResults, ActualUniformAndWrappedTileInputsDifferEvenWithSamePlacement) {
|
||||
shaders::SymbolDrawableUBO uniform{};
|
||||
uniform.matrix[0] = 1;
|
||||
uniform.opacity_t = 0.5;
|
||||
const auto payload = [](const shaders::SymbolDrawableUBO& ubo, const OverscaledTileID& tile) {
|
||||
SymbolRenderResult result;
|
||||
result.appendBytes(&ubo, offsetof(shaders::SymbolDrawableUBO, halo_blur_t) + sizeof(float));
|
||||
const auto name = util::toString(tile);
|
||||
result.appendBlock(name.data(), name.size());
|
||||
return result;
|
||||
};
|
||||
const auto binding = step119Binding();
|
||||
const OverscaledTileID tile{2, 0, {2, 1, 1}}, wrapped{2, 1, {2, 1, 1}};
|
||||
const auto original = payload(uniform, tile);
|
||||
SymbolResultCertificate certificate;
|
||||
step119Settle(certificate, original, binding);
|
||||
EXPECT_FALSE(certificate.matchesCandidate(payload(uniform, wrapped)));
|
||||
uniform.opacity_t = 0.75;
|
||||
EXPECT_FALSE(certificate.observeFull(payload(uniform, tile), binding, true));
|
||||
EXPECT_FALSE(certificate.canFast(binding));
|
||||
}
|
||||
|
||||
TEST(Step119SymbolResults, AnnotationGateBlocksOtherwiseCertifiedResultAndKeeps24GateAgreement) {
|
||||
SymbolRenderResult result;
|
||||
result.append(255.0f);
|
||||
const auto binding = step119Binding();
|
||||
SymbolResultCertificate certificate;
|
||||
step119Settle(certificate, result, binding);
|
||||
auto input = fastPathInput();
|
||||
input.staticStable = certificate.canFast(binding);
|
||||
ASSERT_TRUE(evaluateParticleFastPath(input).candidate);
|
||||
input.annotationMutation = true;
|
||||
EXPECT_FALSE(evaluateParticleFastPath(input).candidate);
|
||||
EXPECT_EQ(evaluateParticleFastPath(input).reason, ParticleFastPathMissReason::AnnotationMutation);
|
||||
EXPECT_EQ(particleFastGateFailureMask(input), 1u << 23);
|
||||
}
|
||||
|
||||
namespace {
|
||||
class Step119UnknownSymbolProgram final : public gfx::ShaderProgramBase {
|
||||
public:
|
||||
const std::string_view typeName() const noexcept override { return "GenericGLShader"; }
|
||||
std::optional<size_t> getSamplerLocation(size_t) const override { return std::nullopt; }
|
||||
const gfx::VertexAttributeArray& getVertexAttributes() const override { throw std::logic_error("unknown shader"); }
|
||||
const gfx::VertexAttributeArray& getInstanceAttributes() const override { throw std::logic_error("unknown shader"); }
|
||||
};
|
||||
} // namespace
|
||||
|
||||
TEST(Step119SymbolResults, UnknownShaderCannotBorrowNativeFadeContractByName) {
|
||||
Step119UnknownSymbolProgram replacement;
|
||||
EXPECT_FALSE(SymbolShaderProvenance::get().supports(replacement));
|
||||
EXPECT_TRUE(symbolUniformDefine("HAS_UNIFORM_u_opacity"));
|
||||
EXPECT_TRUE(symbolUniformDefine("HAS_UNIFORM_u_sorted_instance"));
|
||||
EXPECT_FALSE(symbolUniformDefine("HAS_UNIFORM_u_opacity 1\n#define main custom"));
|
||||
EXPECT_FALSE(symbolUniformDefine("HAS_UNIFORM_u_custom_animation"));
|
||||
}
|
||||
|
||||
TEST(RetainedDynamicBoundary, SelectsFirstCandidate) {
|
||||
RetainedDynamicBoundaryTracker none;
|
||||
none.consider(0, false);
|
||||
|
||||
Reference in New Issue
Block a user