feat: add STEP-093 runtime validation tooling
This commit is contained in:
@@ -19,15 +19,33 @@ struct RetainedUnderlayDiagnostics {
|
|||||||
std::string endLayerId;
|
std::string endLayerId;
|
||||||
int32_t startIndex = -1;
|
int32_t startIndex = -1;
|
||||||
int32_t endIndex = -1;
|
int32_t endIndex = -1;
|
||||||
|
int32_t continuousBegin = -1;
|
||||||
|
int32_t continuousEndExclusive = -1;
|
||||||
bool bottomPresent = false;
|
bool bottomPresent = false;
|
||||||
|
std::string bottomCacheState{"disabled"};
|
||||||
uint64_t bottomBuild = 0;
|
uint64_t bottomBuild = 0;
|
||||||
uint64_t bottomReuse = 0;
|
uint64_t bottomReuse = 0;
|
||||||
uint64_t bottomInvalidation = 0;
|
uint64_t bottomInvalidation = 0;
|
||||||
|
std::string bottomLastInvalidationReason{"none"};
|
||||||
|
uint64_t bottomTextureCreate = 0;
|
||||||
|
uint64_t bottomCompositeCreate = 0;
|
||||||
|
uint64_t bottomResourceRelease = 0;
|
||||||
bool topPresent = false;
|
bool topPresent = false;
|
||||||
|
std::string topCacheState{"disabled"};
|
||||||
uint64_t topBuild = 0;
|
uint64_t topBuild = 0;
|
||||||
uint64_t topReuse = 0;
|
uint64_t topReuse = 0;
|
||||||
uint64_t topInvalidation = 0;
|
uint64_t topInvalidation = 0;
|
||||||
|
std::string topLastInvalidationReason{"none"};
|
||||||
|
uint64_t topTextureCreate = 0;
|
||||||
|
uint64_t topCompositeCreate = 0;
|
||||||
|
uint64_t topResourceRelease = 0;
|
||||||
bool rangeFallback = false;
|
bool rangeFallback = false;
|
||||||
|
bool fastPathEligible = false;
|
||||||
|
bool fastPathActive = false;
|
||||||
|
std::string fastPathFallbackReason{"no-prepared-tree"};
|
||||||
|
uint64_t fastPathHit = 0;
|
||||||
|
uint64_t fastPathMiss = 0;
|
||||||
|
uint64_t fullCpuFrame = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ContinuousLayerRangeConfig {
|
struct ContinuousLayerRangeConfig {
|
||||||
|
|||||||
@@ -364,6 +364,14 @@ export default function App() {
|
|||||||
Retained: {retainedSnapshot == null ? "not read" :
|
Retained: {retainedSnapshot == null ? "not read" :
|
||||||
`${retainedSnapshot.enabled ? "ON" : "OFF"} build=${retainedSnapshot.build} reuse=${retainedSnapshot.reuse} fallback=${retainedSnapshot.fallback} invalidation=${retainedSnapshot.invalidation} reason=${retainedSnapshot.lastReason}`}
|
`${retainedSnapshot.enabled ? "ON" : "OFF"} build=${retainedSnapshot.build} reuse=${retainedSnapshot.reuse} fallback=${retainedSnapshot.fallback} invalidation=${retainedSnapshot.invalidation} reason=${retainedSnapshot.lastReason}`}
|
||||||
</Text>
|
</Text>
|
||||||
|
{retainedSnapshot != null && (
|
||||||
|
<Text selectable>
|
||||||
|
{`Range ${retainedSnapshot.rangeValid ? "VALID" : "INVALID"} [${retainedSnapshot.startIndex},${retainedSnapshot.endIndex}] continuous=[${retainedSnapshot.continuousBegin},${retainedSnapshot.continuousEndExclusive})\n`}
|
||||||
|
{`Bottom ${retainedSnapshot.bottomPresent ? retainedSnapshot.bottomCacheState : "absent"} b/r/i=${retainedSnapshot.bottomBuild}/${retainedSnapshot.bottomReuse}/${retainedSnapshot.bottomInvalidation} tex/comp/rel=${retainedSnapshot.bottomTextureCreate}/${retainedSnapshot.bottomCompositeCreate}/${retainedSnapshot.bottomResourceRelease}\n`}
|
||||||
|
{`Top ${retainedSnapshot.topPresent ? retainedSnapshot.topCacheState : "absent"} b/r/i=${retainedSnapshot.topBuild}/${retainedSnapshot.topReuse}/${retainedSnapshot.topInvalidation} tex/comp/rel=${retainedSnapshot.topTextureCreate}/${retainedSnapshot.topCompositeCreate}/${retainedSnapshot.topResourceRelease}\n`}
|
||||||
|
{`Fast eligible=${retainedSnapshot.fastPathEligible} active=${retainedSnapshot.fastPathActive} hit/miss/full=${retainedSnapshot.fastPathHit}/${retainedSnapshot.fastPathMiss}/${retainedSnapshot.fullCpuFrame} reason=${retainedSnapshot.fastPathFallbackReason}`}
|
||||||
|
</Text>
|
||||||
|
)}
|
||||||
<View style={styles.row}>
|
<View style={styles.row}>
|
||||||
<Button
|
<Button
|
||||||
title={`Retained ${retainedSnapshot?.enabled === false ? "OFF" : "ON"}`}
|
title={`Retained ${retainedSnapshot?.enabled === false ? "OFF" : "ON"}`}
|
||||||
|
|||||||
@@ -85,15 +85,33 @@ class WeatherRuntimeBridgeModule(private val context: ReactApplicationContext) :
|
|||||||
putString("endLayerId", value.endLayerId)
|
putString("endLayerId", value.endLayerId)
|
||||||
putInt("startIndex", value.startIndex)
|
putInt("startIndex", value.startIndex)
|
||||||
putInt("endIndex", value.endIndex)
|
putInt("endIndex", value.endIndex)
|
||||||
|
putInt("continuousBegin", value.continuousBegin)
|
||||||
|
putInt("continuousEndExclusive", value.continuousEndExclusive)
|
||||||
putBoolean("bottomPresent", value.bottomPresent)
|
putBoolean("bottomPresent", value.bottomPresent)
|
||||||
|
putString("bottomCacheState", value.bottomCacheState)
|
||||||
putDouble("bottomBuild", value.bottomBuild.toDouble())
|
putDouble("bottomBuild", value.bottomBuild.toDouble())
|
||||||
putDouble("bottomReuse", value.bottomReuse.toDouble())
|
putDouble("bottomReuse", value.bottomReuse.toDouble())
|
||||||
putDouble("bottomInvalidation", value.bottomInvalidation.toDouble())
|
putDouble("bottomInvalidation", value.bottomInvalidation.toDouble())
|
||||||
|
putString("bottomLastInvalidationReason", value.bottomLastInvalidationReason)
|
||||||
|
putDouble("bottomTextureCreate", value.bottomTextureCreate.toDouble())
|
||||||
|
putDouble("bottomCompositeCreate", value.bottomCompositeCreate.toDouble())
|
||||||
|
putDouble("bottomResourceRelease", value.bottomResourceRelease.toDouble())
|
||||||
putBoolean("topPresent", value.topPresent)
|
putBoolean("topPresent", value.topPresent)
|
||||||
|
putString("topCacheState", value.topCacheState)
|
||||||
putDouble("topBuild", value.topBuild.toDouble())
|
putDouble("topBuild", value.topBuild.toDouble())
|
||||||
putDouble("topReuse", value.topReuse.toDouble())
|
putDouble("topReuse", value.topReuse.toDouble())
|
||||||
putDouble("topInvalidation", value.topInvalidation.toDouble())
|
putDouble("topInvalidation", value.topInvalidation.toDouble())
|
||||||
putBoolean("fallback", value.fallback)
|
putString("topLastInvalidationReason", value.topLastInvalidationReason)
|
||||||
|
putDouble("topTextureCreate", value.topTextureCreate.toDouble())
|
||||||
|
putDouble("topCompositeCreate", value.topCompositeCreate.toDouble())
|
||||||
|
putDouble("topResourceRelease", value.topResourceRelease.toDouble())
|
||||||
|
putBoolean("rangeFallback", value.rangeFallback)
|
||||||
|
putBoolean("fastPathEligible", value.fastPathEligible)
|
||||||
|
putBoolean("fastPathActive", value.fastPathActive)
|
||||||
|
putString("fastPathFallbackReason", value.fastPathFallbackReason)
|
||||||
|
putDouble("fastPathHit", value.fastPathHit.toDouble())
|
||||||
|
putDouble("fastPathMiss", value.fastPathMiss.toDouble())
|
||||||
|
putDouble("fullCpuFrame", value.fullCpuFrame.toDouble())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ReactMethod override fun clearWindFields(reactTag: Double, promise: Promise) = command(reactTag, promise) { it.clearWindFields() }
|
@ReactMethod override fun clearWindFields(reactTag: Double, promise: Promise) = command(reactTag, promise) { it.clearWindFields() }
|
||||||
|
|||||||
@@ -177,10 +177,25 @@ RCT_EXPORT_MODULE(WeatherRuntimeBridge)
|
|||||||
@"lastReason": value.lastReason, @"rangeConfigured": @(value.rangeConfigured),
|
@"lastReason": value.lastReason, @"rangeConfigured": @(value.rangeConfigured),
|
||||||
@"rangeValid": @(value.rangeValid), @"startLayerId": value.startLayerId,
|
@"rangeValid": @(value.rangeValid), @"startLayerId": value.startLayerId,
|
||||||
@"endLayerId": value.endLayerId, @"startIndex": @(value.startIndex), @"endIndex": @(value.endIndex),
|
@"endLayerId": value.endLayerId, @"startIndex": @(value.startIndex), @"endIndex": @(value.endIndex),
|
||||||
@"bottomPresent": @(value.bottomPresent), @"bottomBuild": @(value.bottomBuild),
|
@"continuousBegin": @(value.continuousBegin), @"continuousEndExclusive": @(value.continuousEndExclusive),
|
||||||
|
@"bottomPresent": @(value.bottomPresent), @"bottomCacheState": value.bottomCacheState,
|
||||||
|
@"bottomBuild": @(value.bottomBuild),
|
||||||
@"bottomReuse": @(value.bottomReuse), @"bottomInvalidation": @(value.bottomInvalidation),
|
@"bottomReuse": @(value.bottomReuse), @"bottomInvalidation": @(value.bottomInvalidation),
|
||||||
@"topPresent": @(value.topPresent), @"topBuild": @(value.topBuild),
|
@"bottomLastInvalidationReason": value.bottomLastInvalidationReason,
|
||||||
@"topReuse": @(value.topReuse), @"topInvalidation": @(value.topInvalidation) });
|
@"bottomTextureCreate": @(value.bottomTextureCreate),
|
||||||
|
@"bottomCompositeCreate": @(value.bottomCompositeCreate),
|
||||||
|
@"bottomResourceRelease": @(value.bottomResourceRelease),
|
||||||
|
@"topPresent": @(value.topPresent), @"topCacheState": value.topCacheState,
|
||||||
|
@"topBuild": @(value.topBuild), @"topReuse": @(value.topReuse),
|
||||||
|
@"topInvalidation": @(value.topInvalidation),
|
||||||
|
@"topLastInvalidationReason": value.topLastInvalidationReason,
|
||||||
|
@"topTextureCreate": @(value.topTextureCreate),
|
||||||
|
@"topCompositeCreate": @(value.topCompositeCreate),
|
||||||
|
@"topResourceRelease": @(value.topResourceRelease),
|
||||||
|
@"rangeFallback": @(value.rangeFallback), @"fastPathEligible": @(value.fastPathEligible),
|
||||||
|
@"fastPathActive": @(value.fastPathActive), @"fastPathFallbackReason": value.fastPathFallbackReason,
|
||||||
|
@"fastPathHit": @(value.fastPathHit), @"fastPathMiss": @(value.fastPathMiss),
|
||||||
|
@"fullCpuFrame": @(value.fullCpuFrame) });
|
||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,8 +12,14 @@ type RuntimeSnapshot = { state: RuntimeState; playbackState: PlaybackState; targ
|
|||||||
type RetainedUnderlaySnapshot = {
|
type RetainedUnderlaySnapshot = {
|
||||||
enabled: boolean; build: number; reuse: number; fallback: number; invalidation: number; lastReason: string;
|
enabled: boolean; build: number; reuse: number; fallback: number; invalidation: number; lastReason: string;
|
||||||
rangeConfigured: boolean; rangeValid: boolean; startLayerId: string; endLayerId: string;
|
rangeConfigured: boolean; rangeValid: boolean; startLayerId: string; endLayerId: string;
|
||||||
startIndex: number; endIndex: number; bottomPresent: boolean; bottomBuild: number; bottomReuse: number;
|
startIndex: number; endIndex: number; continuousBegin: number; continuousEndExclusive: number;
|
||||||
bottomInvalidation: number; topPresent: boolean; topBuild: number; topReuse: number; topInvalidation: number;
|
bottomPresent: boolean; bottomCacheState: string; bottomBuild: number; bottomReuse: number;
|
||||||
|
bottomInvalidation: number; bottomLastInvalidationReason: string; bottomTextureCreate: number;
|
||||||
|
bottomCompositeCreate: number; bottomResourceRelease: number;
|
||||||
|
topPresent: boolean; topCacheState: string; topBuild: number; topReuse: number; topInvalidation: number;
|
||||||
|
topLastInvalidationReason: string; topTextureCreate: number; topCompositeCreate: number;
|
||||||
|
topResourceRelease: number; rangeFallback: boolean; fastPathEligible: boolean; fastPathActive: boolean;
|
||||||
|
fastPathFallbackReason: string; fastPathHit: number; fastPathMiss: number; fullCpuFrame: number;
|
||||||
};
|
};
|
||||||
export interface Spec extends TurboModule {
|
export interface Spec extends TurboModule {
|
||||||
attach(reactTag: number): Promise<RuntimeSnapshot>;
|
attach(reactTag: number): Promise<RuntimeSnapshot>;
|
||||||
|
|||||||
@@ -34,12 +34,31 @@ export type RetainedUnderlayDiagnostics = Readonly<{
|
|||||||
endLayerId: string;
|
endLayerId: string;
|
||||||
startIndex: number;
|
startIndex: number;
|
||||||
endIndex: number;
|
endIndex: number;
|
||||||
|
continuousBegin: number;
|
||||||
|
continuousEndExclusive: number;
|
||||||
bottomPresent: boolean;
|
bottomPresent: boolean;
|
||||||
|
bottomCacheState: string;
|
||||||
bottomBuild: number;
|
bottomBuild: number;
|
||||||
bottomReuse: number;
|
bottomReuse: number;
|
||||||
bottomInvalidation: number;
|
bottomInvalidation: number;
|
||||||
|
bottomLastInvalidationReason: string;
|
||||||
|
bottomTextureCreate: number;
|
||||||
|
bottomCompositeCreate: number;
|
||||||
|
bottomResourceRelease: number;
|
||||||
topPresent: boolean;
|
topPresent: boolean;
|
||||||
|
topCacheState: string;
|
||||||
topBuild: number;
|
topBuild: number;
|
||||||
topReuse: number;
|
topReuse: number;
|
||||||
topInvalidation: number;
|
topInvalidation: number;
|
||||||
|
topLastInvalidationReason: string;
|
||||||
|
topTextureCreate: number;
|
||||||
|
topCompositeCreate: number;
|
||||||
|
topResourceRelease: number;
|
||||||
|
rangeFallback: boolean;
|
||||||
|
fastPathEligible: boolean;
|
||||||
|
fastPathActive: boolean;
|
||||||
|
fastPathFallbackReason: string;
|
||||||
|
fastPathHit: number;
|
||||||
|
fastPathMiss: number;
|
||||||
|
fullCpuFrame: number;
|
||||||
}>;
|
}>;
|
||||||
|
|||||||
@@ -729,7 +729,7 @@ jni::jboolean NativeMapView::setContinuousLayerRange(JNIEnv& env,
|
|||||||
|
|
||||||
jni::Local<jni::Array<jni::String>> NativeMapView::getRetainedUnderlayDiagnostics(JNIEnv& env) {
|
jni::Local<jni::Array<jni::String>> NativeMapView::getRetainedUnderlayDiagnostics(JNIEnv& env) {
|
||||||
const auto snapshot = map->getRetainedUnderlayDiagnostics();
|
const auto snapshot = map->getRetainedUnderlayDiagnostics();
|
||||||
const std::array<std::string, 20> values = {
|
const std::array<std::string, 39> values = {
|
||||||
snapshot.enabled ? "true" : "false",
|
snapshot.enabled ? "true" : "false",
|
||||||
std::to_string(snapshot.build),
|
std::to_string(snapshot.build),
|
||||||
std::to_string(snapshot.reuse),
|
std::to_string(snapshot.reuse),
|
||||||
@@ -742,14 +742,33 @@ jni::Local<jni::Array<jni::String>> NativeMapView::getRetainedUnderlayDiagnostic
|
|||||||
snapshot.endLayerId,
|
snapshot.endLayerId,
|
||||||
std::to_string(snapshot.startIndex),
|
std::to_string(snapshot.startIndex),
|
||||||
std::to_string(snapshot.endIndex),
|
std::to_string(snapshot.endIndex),
|
||||||
|
std::to_string(snapshot.continuousBegin),
|
||||||
|
std::to_string(snapshot.continuousEndExclusive),
|
||||||
snapshot.bottomPresent ? "true" : "false",
|
snapshot.bottomPresent ? "true" : "false",
|
||||||
|
snapshot.bottomCacheState,
|
||||||
std::to_string(snapshot.bottomBuild),
|
std::to_string(snapshot.bottomBuild),
|
||||||
std::to_string(snapshot.bottomReuse),
|
std::to_string(snapshot.bottomReuse),
|
||||||
std::to_string(snapshot.bottomInvalidation),
|
std::to_string(snapshot.bottomInvalidation),
|
||||||
|
snapshot.bottomLastInvalidationReason,
|
||||||
|
std::to_string(snapshot.bottomTextureCreate),
|
||||||
|
std::to_string(snapshot.bottomCompositeCreate),
|
||||||
|
std::to_string(snapshot.bottomResourceRelease),
|
||||||
snapshot.topPresent ? "true" : "false",
|
snapshot.topPresent ? "true" : "false",
|
||||||
|
snapshot.topCacheState,
|
||||||
std::to_string(snapshot.topBuild),
|
std::to_string(snapshot.topBuild),
|
||||||
std::to_string(snapshot.topReuse),
|
std::to_string(snapshot.topReuse),
|
||||||
std::to_string(snapshot.topInvalidation),
|
std::to_string(snapshot.topInvalidation),
|
||||||
|
snapshot.topLastInvalidationReason,
|
||||||
|
std::to_string(snapshot.topTextureCreate),
|
||||||
|
std::to_string(snapshot.topCompositeCreate),
|
||||||
|
std::to_string(snapshot.topResourceRelease),
|
||||||
|
snapshot.rangeFallback ? "true" : "false",
|
||||||
|
snapshot.fastPathEligible ? "true" : "false",
|
||||||
|
snapshot.fastPathActive ? "true" : "false",
|
||||||
|
snapshot.fastPathFallbackReason,
|
||||||
|
std::to_string(snapshot.fastPathHit),
|
||||||
|
std::to_string(snapshot.fastPathMiss),
|
||||||
|
std::to_string(snapshot.fullCpuFrame),
|
||||||
};
|
};
|
||||||
auto result = jni::Array<jni::String>::New(env, values.size());
|
auto result = jni::Array<jni::String>::New(env, values.size());
|
||||||
for (std::size_t index = 0; index < values.size(); ++index) {
|
for (std::size_t index = 0; index < values.size(); ++index) {
|
||||||
|
|||||||
@@ -18,18 +18,37 @@ public final class RetainedUnderlayDiagnostics {
|
|||||||
@NonNull public final String endLayerId;
|
@NonNull public final String endLayerId;
|
||||||
public final int startIndex;
|
public final int startIndex;
|
||||||
public final int endIndex;
|
public final int endIndex;
|
||||||
|
public final int continuousBegin;
|
||||||
|
public final int continuousEndExclusive;
|
||||||
public final boolean bottomPresent;
|
public final boolean bottomPresent;
|
||||||
|
@NonNull public final String bottomCacheState;
|
||||||
public final long bottomBuild;
|
public final long bottomBuild;
|
||||||
public final long bottomReuse;
|
public final long bottomReuse;
|
||||||
public final long bottomInvalidation;
|
public final long bottomInvalidation;
|
||||||
|
@NonNull public final String bottomLastInvalidationReason;
|
||||||
|
public final long bottomTextureCreate;
|
||||||
|
public final long bottomCompositeCreate;
|
||||||
|
public final long bottomResourceRelease;
|
||||||
public final boolean topPresent;
|
public final boolean topPresent;
|
||||||
|
@NonNull public final String topCacheState;
|
||||||
public final long topBuild;
|
public final long topBuild;
|
||||||
public final long topReuse;
|
public final long topReuse;
|
||||||
public final long topInvalidation;
|
public final long topInvalidation;
|
||||||
|
@NonNull public final String topLastInvalidationReason;
|
||||||
|
public final long topTextureCreate;
|
||||||
|
public final long topCompositeCreate;
|
||||||
|
public final long topResourceRelease;
|
||||||
|
public final boolean rangeFallback;
|
||||||
|
public final boolean fastPathEligible;
|
||||||
|
public final boolean fastPathActive;
|
||||||
|
@NonNull public final String fastPathFallbackReason;
|
||||||
|
public final long fastPathHit;
|
||||||
|
public final long fastPathMiss;
|
||||||
|
public final long fullCpuFrame;
|
||||||
|
|
||||||
RetainedUnderlayDiagnostics(@NonNull String[] values) {
|
RetainedUnderlayDiagnostics(@NonNull String[] values) {
|
||||||
if (values.length != 20) {
|
if (values.length != 39) {
|
||||||
throw new IllegalArgumentException("Retained-range diagnostics require 20 values");
|
throw new IllegalArgumentException("Retained-range diagnostics require 39 values");
|
||||||
}
|
}
|
||||||
enabled = Boolean.parseBoolean(values[0]);
|
enabled = Boolean.parseBoolean(values[0]);
|
||||||
build = Long.parseLong(values[1]);
|
build = Long.parseLong(values[1]);
|
||||||
@@ -43,20 +62,41 @@ public final class RetainedUnderlayDiagnostics {
|
|||||||
endLayerId = values[9];
|
endLayerId = values[9];
|
||||||
startIndex = Integer.parseInt(values[10]);
|
startIndex = Integer.parseInt(values[10]);
|
||||||
endIndex = Integer.parseInt(values[11]);
|
endIndex = Integer.parseInt(values[11]);
|
||||||
bottomPresent = Boolean.parseBoolean(values[12]);
|
continuousBegin = Integer.parseInt(values[12]);
|
||||||
bottomBuild = Long.parseLong(values[13]);
|
continuousEndExclusive = Integer.parseInt(values[13]);
|
||||||
bottomReuse = Long.parseLong(values[14]);
|
bottomPresent = Boolean.parseBoolean(values[14]);
|
||||||
bottomInvalidation = Long.parseLong(values[15]);
|
bottomCacheState = values[15];
|
||||||
topPresent = Boolean.parseBoolean(values[16]);
|
bottomBuild = Long.parseLong(values[16]);
|
||||||
topBuild = Long.parseLong(values[17]);
|
bottomReuse = Long.parseLong(values[17]);
|
||||||
topReuse = Long.parseLong(values[18]);
|
bottomInvalidation = Long.parseLong(values[18]);
|
||||||
topInvalidation = Long.parseLong(values[19]);
|
bottomLastInvalidationReason = values[19];
|
||||||
|
bottomTextureCreate = Long.parseLong(values[20]);
|
||||||
|
bottomCompositeCreate = Long.parseLong(values[21]);
|
||||||
|
bottomResourceRelease = Long.parseLong(values[22]);
|
||||||
|
topPresent = Boolean.parseBoolean(values[23]);
|
||||||
|
topCacheState = values[24];
|
||||||
|
topBuild = Long.parseLong(values[25]);
|
||||||
|
topReuse = Long.parseLong(values[26]);
|
||||||
|
topInvalidation = Long.parseLong(values[27]);
|
||||||
|
topLastInvalidationReason = values[28];
|
||||||
|
topTextureCreate = Long.parseLong(values[29]);
|
||||||
|
topCompositeCreate = Long.parseLong(values[30]);
|
||||||
|
topResourceRelease = Long.parseLong(values[31]);
|
||||||
|
rangeFallback = Boolean.parseBoolean(values[32]);
|
||||||
|
fastPathEligible = Boolean.parseBoolean(values[33]);
|
||||||
|
fastPathActive = Boolean.parseBoolean(values[34]);
|
||||||
|
fastPathFallbackReason = values[35];
|
||||||
|
fastPathHit = Long.parseLong(values[36]);
|
||||||
|
fastPathMiss = Long.parseLong(values[37]);
|
||||||
|
fullCpuFrame = Long.parseLong(values[38]);
|
||||||
}
|
}
|
||||||
|
|
||||||
static RetainedUnderlayDiagnostics unavailable() {
|
static RetainedUnderlayDiagnostics unavailable() {
|
||||||
return new RetainedUnderlayDiagnostics(new String[] {
|
return new RetainedUnderlayDiagnostics(new String[] {
|
||||||
"true", "0", "0", "0", "0", "unavailable", "false", "false", "", "", "-1", "-1",
|
"true", "0", "0", "0", "0", "unavailable", "false", "false", "", "", "-1", "-1",
|
||||||
"false", "0", "0", "0", "false", "0", "0", "0"
|
"-1", "-1", "false", "disabled", "0", "0", "0", "none", "0", "0", "0",
|
||||||
|
"false", "disabled", "0", "0", "0", "none", "0", "0", "0", "false", "false",
|
||||||
|
"false", "no-prepared-tree", "0", "0", "0"
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -288,6 +288,7 @@
|
|||||||
</activity>
|
</activity>
|
||||||
<activity
|
<activity
|
||||||
android:name=".activity.particle.ParticleCoreLayerValidationActivity"
|
android:name=".activity.particle.ParticleCoreLayerValidationActivity"
|
||||||
|
android:configChanges="orientation|keyboardHidden|screenSize"
|
||||||
android:description="@string/description_particle_core_layer_validation"
|
android:description="@string/description_particle_core_layer_validation"
|
||||||
android:exported="true"
|
android:exported="true"
|
||||||
android:label="@string/activity_particle_core_layer_validation">
|
android:label="@string/activity_particle_core_layer_validation">
|
||||||
|
|||||||
@@ -2,6 +2,8 @@ package org.maplibre.android.testapp.activity.particle
|
|||||||
|
|
||||||
import android.graphics.Color
|
import android.graphics.Color
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import android.os.Handler
|
||||||
|
import android.os.Looper
|
||||||
import android.text.InputType
|
import android.text.InputType
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import android.widget.Button
|
import android.widget.Button
|
||||||
@@ -28,6 +30,7 @@ class ParticleCoreLayerValidationActivity : AppCompatActivity() {
|
|||||||
private lateinit var mapView: MapView
|
private lateinit var mapView: MapView
|
||||||
private lateinit var maplibreMap: MapLibreMap
|
private lateinit var maplibreMap: MapLibreMap
|
||||||
private lateinit var status: TextView
|
private lateinit var status: TextView
|
||||||
|
private lateinit var diagnostics: TextView
|
||||||
private var active = true
|
private var active = true
|
||||||
private var enabled = true
|
private var enabled = true
|
||||||
private var maskMode = MASK_GLOBAL
|
private var maskMode = MASK_GLOBAL
|
||||||
@@ -51,6 +54,21 @@ class ParticleCoreLayerValidationActivity : AppCompatActivity() {
|
|||||||
private var navSeaPbfRenderEnabled = true
|
private var navSeaPbfRenderEnabled = true
|
||||||
private var navSeaPbfLayerVisibility = emptyList<NavSeaPbfLayerVisibility>()
|
private var navSeaPbfLayerVisibility = emptyList<NavSeaPbfLayerVisibility>()
|
||||||
private var retainedCacheEnabled = true
|
private var retainedCacheEnabled = true
|
||||||
|
private var step093Mode = false
|
||||||
|
private var step093Topology = Step093Topology.BOTTOM_CONTINUOUS_TOP
|
||||||
|
private var step093Variant = Step093Variant.DEFAULT
|
||||||
|
private var step093StartVisible = true
|
||||||
|
private var step093EndVisible = true
|
||||||
|
private var step093CameraPreset = 0
|
||||||
|
private val step093Handler = Handler(Looper.getMainLooper())
|
||||||
|
private val step093DiagnosticsPoll = object : Runnable {
|
||||||
|
override fun run() {
|
||||||
|
if (step093Mode && this@ParticleCoreLayerValidationActivity::maplibreMap.isInitialized) {
|
||||||
|
refreshStep093Diagnostics(log = false)
|
||||||
|
step093Handler.postDelayed(this, STEP093_DIAGNOSTICS_INTERVAL_MS)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
private var realWeatherTuningMenu: PopupMenu? = null
|
private var realWeatherTuningMenu: PopupMenu? = null
|
||||||
private var realWeatherMenuAnchor: android.view.View? = null
|
private var realWeatherMenuAnchor: android.view.View? = null
|
||||||
private var openRealWeatherTuningAfterStyle = false
|
private var openRealWeatherTuningAfterStyle = false
|
||||||
@@ -88,6 +106,13 @@ class ParticleCoreLayerValidationActivity : AppCompatActivity() {
|
|||||||
?: NavSeaPbfPosition.AFTER_CLIP
|
?: NavSeaPbfPosition.AFTER_CLIP
|
||||||
navSeaPbfRenderEnabled = savedInstanceState?.getBoolean(STATE_NAVSEA_PBF_RENDER_ENABLED, true) ?: true
|
navSeaPbfRenderEnabled = savedInstanceState?.getBoolean(STATE_NAVSEA_PBF_RENDER_ENABLED, true) ?: true
|
||||||
retainedCacheEnabled = savedInstanceState?.getBoolean(STATE_RETAINED_CACHE_ENABLED, true) ?: true
|
retainedCacheEnabled = savedInstanceState?.getBoolean(STATE_RETAINED_CACHE_ENABLED, true) ?: true
|
||||||
|
step093Mode = savedInstanceState?.getBoolean(STATE_STEP093_MODE, false) ?: false
|
||||||
|
step093Topology = savedInstanceState?.getString(STATE_STEP093_TOPOLOGY)
|
||||||
|
?.let { value -> Step093Topology.values().firstOrNull { it.name == value } }
|
||||||
|
?: Step093Topology.BOTTOM_CONTINUOUS_TOP
|
||||||
|
step093Variant = savedInstanceState?.getString(STATE_STEP093_VARIANT)
|
||||||
|
?.let { value -> Step093Variant.values().firstOrNull { it.name == value } }
|
||||||
|
?: Step093Variant.DEFAULT
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
Log.i(
|
Log.i(
|
||||||
TAG,
|
TAG,
|
||||||
@@ -98,6 +123,7 @@ class ParticleCoreLayerValidationActivity : AppCompatActivity() {
|
|||||||
|
|
||||||
mapView = findViewById(R.id.mapView)
|
mapView = findViewById(R.id.mapView)
|
||||||
status = findViewById(R.id.validationStatus)
|
status = findViewById(R.id.validationStatus)
|
||||||
|
diagnostics = findViewById(R.id.validationDiagnostics)
|
||||||
mapView.addOnDidFailLoadingMapListener { errorMessage ->
|
mapView.addOnDidFailLoadingMapListener { errorMessage ->
|
||||||
if (navSeaPbfMode || purePbfMode) {
|
if (navSeaPbfMode || purePbfMode) {
|
||||||
Log.e(TAG, "NAVSEA_PBF_STYLE_ERROR reason=$errorMessage")
|
Log.e(TAG, "NAVSEA_PBF_STYLE_ERROR reason=$errorMessage")
|
||||||
@@ -119,7 +145,8 @@ class ParticleCoreLayerValidationActivity : AppCompatActivity() {
|
|||||||
updateNavSeaPbfButtonState()
|
updateNavSeaPbfButtonState()
|
||||||
updatePbfModeButtonState()
|
updatePbfModeButtonState()
|
||||||
updateRetainedCacheButtonState()
|
updateRetainedCacheButtonState()
|
||||||
loadValidationStyle(active = active, enabled = enabled, reason = "INITIAL")
|
if (step093Mode) loadStep093Style(configureBeforeStyle = false)
|
||||||
|
else loadValidationStyle(active = active, enabled = enabled, reason = "INITIAL")
|
||||||
}
|
}
|
||||||
|
|
||||||
findViewById<Button>(R.id.validationActive).setOnClickListener {
|
findViewById<Button>(R.id.validationActive).setOnClickListener {
|
||||||
@@ -251,6 +278,7 @@ class ParticleCoreLayerValidationActivity : AppCompatActivity() {
|
|||||||
findViewById<Button>(R.id.validationMenuNavSeaPbf).setOnClickListener { showNavSeaPbfMenu(it) }
|
findViewById<Button>(R.id.validationMenuNavSeaPbf).setOnClickListener { showNavSeaPbfMenu(it) }
|
||||||
findViewById<Button>(R.id.validationMenuPbfMode).setOnClickListener { showPbfModeMenu(it) }
|
findViewById<Button>(R.id.validationMenuPbfMode).setOnClickListener { showPbfModeMenu(it) }
|
||||||
findViewById<Button>(R.id.validationMenuRetainedCache).setOnClickListener { showRetainedCacheMenu(it) }
|
findViewById<Button>(R.id.validationMenuRetainedCache).setOnClickListener { showRetainedCacheMenu(it) }
|
||||||
|
findViewById<Button>(R.id.validationMenuStep093).setOnClickListener { showStep093Menu(it) }
|
||||||
findViewById<Button>(R.id.validationMenuMore).setOnClickListener { dismissRealWeatherTuning(); showMenu(it, "MORE", intArrayOf(R.id.validationActive, R.id.validationStatic, R.id.validationDisable, R.id.validationEnable, R.id.validationUniformEast, R.id.validationUniformNorth, R.id.validationVortex, R.id.validationTimeWindow, R.id.validationHostFieldSubmit, R.id.validationProductionInvalid, R.id.validationHostFieldDuplicate, R.id.validationHostFieldInvalid, R.id.validationAdvanceWindow, R.id.validationDuplicateWindow)) }
|
findViewById<Button>(R.id.validationMenuMore).setOnClickListener { dismissRealWeatherTuning(); showMenu(it, "MORE", intArrayOf(R.id.validationActive, R.id.validationStatic, R.id.validationDisable, R.id.validationEnable, R.id.validationUniformEast, R.id.validationUniformNorth, R.id.validationVortex, R.id.validationTimeWindow, R.id.validationHostFieldSubmit, R.id.validationProductionInvalid, R.id.validationHostFieldDuplicate, R.id.validationHostFieldInvalid, R.id.validationAdvanceWindow, R.id.validationDuplicateWindow)) }
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -264,8 +292,32 @@ class ParticleCoreLayerValidationActivity : AppCompatActivity() {
|
|||||||
TOP("TOP")
|
TOP("TOP")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private enum class Step093Topology(val label: String, val bottom: Boolean, val top: Boolean) {
|
||||||
|
BOTTOM_CONTINUOUS_TOP("A BOTTOM + CONTINUOUS + TOP", true, true),
|
||||||
|
BOTTOM_CONTINUOUS("B BOTTOM + CONTINUOUS", true, false),
|
||||||
|
CONTINUOUS_TOP("C CONTINUOUS + TOP", false, true),
|
||||||
|
CONTINUOUS_ONLY("D CONTINUOUS ONLY", false, false),
|
||||||
|
SINGLE_LAYER("E SINGLE-LAYER CONTINUOUS", true, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
private enum class Step093Variant {
|
||||||
|
DEFAULT,
|
||||||
|
CONTINUOUS_ADD,
|
||||||
|
CONTINUOUS_REORDER,
|
||||||
|
BOTTOM_ADD,
|
||||||
|
BOTTOM_REORDER,
|
||||||
|
TOP_ADD,
|
||||||
|
TOP_REORDER,
|
||||||
|
CROSS_BOTTOM,
|
||||||
|
CROSS_CONTINUOUS,
|
||||||
|
CROSS_TOP,
|
||||||
|
START_MISSING,
|
||||||
|
END_MISSING,
|
||||||
|
FAST_PATH_FAIL_CLOSED
|
||||||
|
}
|
||||||
|
|
||||||
private fun activateRealWeather(anchor: android.view.View?) {
|
private fun activateRealWeather(anchor: android.view.View?) {
|
||||||
if (isPbfMatrixMode()) leaveRealWeatherMode()
|
if (isPbfMatrixMode() || step093Mode) leaveRealWeatherMode()
|
||||||
realWeatherMenuAnchor = anchor ?: findViewById(R.id.validationMenuRealWeather)
|
realWeatherMenuAnchor = anchor ?: findViewById(R.id.validationMenuRealWeather)
|
||||||
if (realWeatherMode) {
|
if (realWeatherMode) {
|
||||||
if (realWeatherTuningMenu == null) showRealWeatherTuning(realWeatherMenuAnchor!!) else dismissRealWeatherTuning()
|
if (realWeatherTuningMenu == null) showRealWeatherTuning(realWeatherMenuAnchor!!) else dismissRealWeatherTuning()
|
||||||
@@ -296,6 +348,8 @@ class ParticleCoreLayerValidationActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun leaveRealWeatherMode() {
|
private fun leaveRealWeatherMode() {
|
||||||
|
step093Mode = false
|
||||||
|
step093Handler.removeCallbacks(step093DiagnosticsPoll)
|
||||||
dismissRealWeatherTuning()
|
dismissRealWeatherTuning()
|
||||||
weatherRuntime?.dispose()
|
weatherRuntime?.dispose()
|
||||||
weatherRuntime = null
|
weatherRuntime = null
|
||||||
@@ -381,6 +435,233 @@ class ParticleCoreLayerValidationActivity : AppCompatActivity() {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun showStep093Menu(anchor: android.view.View) {
|
||||||
|
PopupMenu(this, anchor).apply {
|
||||||
|
Step093Topology.values().forEachIndexed { index, topology ->
|
||||||
|
menu.add(0, index, index, topology.label)
|
||||||
|
}
|
||||||
|
menu.add(0, 10, 10, "MUTATION / FAST PATH")
|
||||||
|
menu.add(0, 11, 11, "ENDPOINT / VISIBILITY")
|
||||||
|
menu.add(0, 12, 12, "INVALID RANGE")
|
||||||
|
menu.add(0, 13, 13, "CAMERA NEXT")
|
||||||
|
menu.add(0, 14, 14, "READ DIAGNOSTICS")
|
||||||
|
menu.add(0, 15, 15, "RESET DEFAULT A")
|
||||||
|
setOnMenuItemClickListener { item ->
|
||||||
|
when (item.itemId) {
|
||||||
|
in Step093Topology.values().indices -> applyStep093Scene(Step093Topology.values()[item.itemId])
|
||||||
|
10 -> showStep093MutationMenu(anchor)
|
||||||
|
11 -> showStep093EndpointMenu(anchor)
|
||||||
|
12 -> showStep093InvalidMenu(anchor)
|
||||||
|
13 -> applyStep093CameraPreset()
|
||||||
|
14 -> refreshStep093Diagnostics(log = true)
|
||||||
|
15 -> applyStep093Scene(Step093Topology.BOTTOM_CONTINUOUS_TOP)
|
||||||
|
}
|
||||||
|
true
|
||||||
|
}
|
||||||
|
show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun showStep093MutationMenu(anchor: android.view.View) {
|
||||||
|
val actions = arrayOf(
|
||||||
|
"CONTINUOUS ADD", "CONTINUOUS REORDER", "BOTTOM ADD", "BOTTOM REORDER",
|
||||||
|
"TOP ADD", "TOP REORDER", "CROSS → BOTTOM", "CROSS → CONTINUOUS",
|
||||||
|
"CROSS → TOP", "FAST FAIL-CLOSED", "RESTORE DEFAULT"
|
||||||
|
)
|
||||||
|
PopupMenu(this, anchor).apply {
|
||||||
|
actions.forEachIndexed { index, label -> menu.add(0, index, index, label) }
|
||||||
|
setOnMenuItemClickListener { item ->
|
||||||
|
val variant = when (item.itemId) {
|
||||||
|
0 -> Step093Variant.CONTINUOUS_ADD
|
||||||
|
1 -> Step093Variant.CONTINUOUS_REORDER
|
||||||
|
2 -> Step093Variant.BOTTOM_ADD
|
||||||
|
3 -> Step093Variant.BOTTOM_REORDER
|
||||||
|
4 -> Step093Variant.TOP_ADD
|
||||||
|
5 -> Step093Variant.TOP_REORDER
|
||||||
|
6 -> Step093Variant.CROSS_BOTTOM
|
||||||
|
7 -> Step093Variant.CROSS_CONTINUOUS
|
||||||
|
8 -> Step093Variant.CROSS_TOP
|
||||||
|
9 -> Step093Variant.FAST_PATH_FAIL_CLOSED
|
||||||
|
else -> Step093Variant.DEFAULT
|
||||||
|
}
|
||||||
|
applyStep093Scene(Step093Topology.BOTTOM_CONTINUOUS_TOP, variant)
|
||||||
|
true
|
||||||
|
}
|
||||||
|
show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun showStep093EndpointMenu(anchor: android.view.View) {
|
||||||
|
val actions = arrayOf(
|
||||||
|
"START VISIBLE ↔ HIDDEN", "END VISIBLE ↔ HIDDEN", "DELETE START", "RESTORE START",
|
||||||
|
"DELETE END", "RESTORE END"
|
||||||
|
)
|
||||||
|
PopupMenu(this, anchor).apply {
|
||||||
|
actions.forEachIndexed { index, label -> menu.add(0, index, index, label) }
|
||||||
|
setOnMenuItemClickListener { item ->
|
||||||
|
when (item.itemId) {
|
||||||
|
0 -> toggleStep093Endpoint(start = true)
|
||||||
|
1 -> toggleStep093Endpoint(start = false)
|
||||||
|
2 -> applyStep093Scene(Step093Topology.BOTTOM_CONTINUOUS_TOP, Step093Variant.START_MISSING)
|
||||||
|
3 -> applyStep093Scene(Step093Topology.BOTTOM_CONTINUOUS_TOP)
|
||||||
|
4 -> applyStep093Scene(Step093Topology.BOTTOM_CONTINUOUS_TOP, Step093Variant.END_MISSING)
|
||||||
|
5 -> applyStep093Scene(Step093Topology.BOTTOM_CONTINUOUS_TOP)
|
||||||
|
}
|
||||||
|
true
|
||||||
|
}
|
||||||
|
show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun showStep093InvalidMenu(anchor: android.view.View) {
|
||||||
|
val actions = arrayOf(
|
||||||
|
"MISSING START", "MISSING END", "REVERSED", "CONFIGURE WHILE STYLE LOADING", "EMPTY ID", "RESTORE VALID"
|
||||||
|
)
|
||||||
|
PopupMenu(this, anchor).apply {
|
||||||
|
actions.forEachIndexed { index, label -> menu.add(0, index, index, label) }
|
||||||
|
setOnMenuItemClickListener { item ->
|
||||||
|
if (!ensureStep093Scene()) {
|
||||||
|
Log.i(TAG, "STEP093_ACTION scene initialized; repeat invalid-range action after READY")
|
||||||
|
return@setOnMenuItemClickListener true
|
||||||
|
}
|
||||||
|
when (item.itemId) {
|
||||||
|
0 -> setStep093Range("step093-missing-start", STEP093_PARTICLE_LAYER_ID, "INVALID_MISSING_START")
|
||||||
|
1 -> setStep093Range(STEP093_WEATHER_LAYER_ID, "step093-missing-end", "INVALID_MISSING_END")
|
||||||
|
2 -> setStep093Range(STEP093_PARTICLE_LAYER_ID, STEP093_WEATHER_LAYER_ID, "INVALID_REVERSED")
|
||||||
|
3 -> applyStep093Scene(
|
||||||
|
Step093Topology.BOTTOM_CONTINUOUS_TOP,
|
||||||
|
Step093Variant.DEFAULT,
|
||||||
|
configureBeforeStyle = true
|
||||||
|
)
|
||||||
|
4 -> {
|
||||||
|
val accepted = maplibreMap.setContinuousLayerRange("", STEP093_PARTICLE_LAYER_ID)
|
||||||
|
Log.i(TAG, "STEP093_RANGE action=EMPTY_ID accepted=$accepted expected=false")
|
||||||
|
refreshStep093Diagnostics(log = true)
|
||||||
|
}
|
||||||
|
5 -> setStep093Range(STEP093_WEATHER_LAYER_ID, STEP093_PARTICLE_LAYER_ID, "RESTORE_VALID")
|
||||||
|
}
|
||||||
|
true
|
||||||
|
}
|
||||||
|
show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun ensureStep093Scene(): Boolean {
|
||||||
|
if (step093Mode && styleReady) return true
|
||||||
|
applyStep093Scene(Step093Topology.BOTTOM_CONTINUOUS_TOP)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun applyStep093Scene(
|
||||||
|
topology: Step093Topology,
|
||||||
|
variant: Step093Variant = Step093Variant.DEFAULT,
|
||||||
|
configureBeforeStyle: Boolean = false
|
||||||
|
) {
|
||||||
|
leaveRealWeatherMode()
|
||||||
|
step093Mode = true
|
||||||
|
step093Topology = topology
|
||||||
|
step093Variant = variant
|
||||||
|
step093StartVisible = true
|
||||||
|
step093EndVisible = true
|
||||||
|
timeWindowMode = true
|
||||||
|
productionFeedMode = false
|
||||||
|
hostSubmissionMode = true
|
||||||
|
realWeatherMode = false
|
||||||
|
pureParticleMode = false
|
||||||
|
purePbfMode = false
|
||||||
|
navSeaPbfMode = false
|
||||||
|
active = true
|
||||||
|
enabled = true
|
||||||
|
retainedCacheEnabled = true
|
||||||
|
maplibreMap.setRetainedUnderlayEnabled(true)
|
||||||
|
updateRetainedCacheButtonState()
|
||||||
|
loadStep093Style(configureBeforeStyle)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun loadStep093Style(configureBeforeStyle: Boolean) {
|
||||||
|
weatherRuntime?.dispose()
|
||||||
|
weatherRuntime = null
|
||||||
|
styleReady = false
|
||||||
|
val epoch = ++styleLoadEpoch
|
||||||
|
val range = step093Range()
|
||||||
|
status.text = "STEP-093 · ${step093Topology.label} · ${step093Variant.name} · LOADING"
|
||||||
|
maplibreMap.setStyle(Style.Builder().fromJson(step093StyleJson())) {
|
||||||
|
if (!step093Mode || epoch != styleLoadEpoch) return@setStyle
|
||||||
|
styleReady = true
|
||||||
|
if (!configureBeforeStyle) maplibreMap.setContinuousLayerRange(range.first, range.second)
|
||||||
|
submitHostValidationDataset()
|
||||||
|
fitRealWeatherBounds()
|
||||||
|
status.text = "STEP-093 · ${step093Topology.label} · ${step093Variant.name}"
|
||||||
|
startStep093DiagnosticsPolling()
|
||||||
|
refreshStep093Diagnostics(log = true)
|
||||||
|
Log.i(
|
||||||
|
TAG,
|
||||||
|
"STEP093_SCENE_READY topology=${step093Topology.name} variant=${step093Variant.name} " +
|
||||||
|
"range=${range.first}..${range.second}"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
if (configureBeforeStyle) {
|
||||||
|
maplibreMap.setContinuousLayerRange(range.first, range.second)
|
||||||
|
Log.i(TAG, "STEP093_RANGE action=CONFIGURE_WHILE_STYLE_LOADING start=${range.first} end=${range.second}")
|
||||||
|
refreshStep093Diagnostics(log = true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun step093Range(): Pair<String, String> = if (step093Topology == Step093Topology.SINGLE_LAYER) {
|
||||||
|
STEP093_PARTICLE_LAYER_ID to STEP093_PARTICLE_LAYER_ID
|
||||||
|
} else {
|
||||||
|
STEP093_WEATHER_LAYER_ID to STEP093_PARTICLE_LAYER_ID
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setStep093Range(start: String, end: String, action: String) {
|
||||||
|
val accepted = maplibreMap.setContinuousLayerRange(start, end)
|
||||||
|
Log.i(TAG, "STEP093_RANGE action=$action accepted=$accepted start=$start end=$end")
|
||||||
|
refreshStep093Diagnostics(log = true)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun toggleStep093Endpoint(start: Boolean) {
|
||||||
|
if (!ensureStep093Scene()) return
|
||||||
|
val id = if (start) step093Range().first else step093Range().second
|
||||||
|
val visible = if (start) !step093StartVisible else !step093EndVisible
|
||||||
|
val accepted = maplibreMap.setStyleLayerVisibility(id, visible)
|
||||||
|
if (start) step093StartVisible = visible else step093EndVisible = visible
|
||||||
|
Log.i(TAG, "STEP093_VISIBILITY endpoint=${if (start) "start" else "end"} id=$id visible=$visible accepted=$accepted")
|
||||||
|
refreshStep093Diagnostics(log = true)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun applyStep093CameraPreset() {
|
||||||
|
if (!ensureStep093Scene()) return
|
||||||
|
step093CameraPreset = (step093CameraPreset + 1) % 4
|
||||||
|
val position = when (step093CameraPreset) {
|
||||||
|
1 -> CameraPosition.Builder().target(LatLng(31.0, 139.0)).zoom(3.5).bearing(0.0).tilt(0.0).build()
|
||||||
|
2 -> CameraPosition.Builder().target(LatLng(25.0, 132.0)).zoom(4.5).bearing(55.0).tilt(0.0).build()
|
||||||
|
3 -> CameraPosition.Builder().target(LatLng(37.0, 145.0)).zoom(5.0).bearing(120.0).tilt(45.0).build()
|
||||||
|
else -> CameraPosition.Builder().target(LatLng(28.0, 135.0)).zoom(3.0).bearing(0.0).tilt(0.0).build()
|
||||||
|
}
|
||||||
|
maplibreMap.animateCamera(CameraUpdateFactory.newCameraPosition(position), 700)
|
||||||
|
Log.i(TAG, "STEP093_CAMERA preset=$step093CameraPreset position=$position")
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun startStep093DiagnosticsPolling() {
|
||||||
|
step093Handler.removeCallbacks(step093DiagnosticsPoll)
|
||||||
|
step093Handler.post(step093DiagnosticsPoll)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun refreshStep093Diagnostics(log: Boolean) {
|
||||||
|
val snapshot = maplibreMap.retainedUnderlayDiagnostics
|
||||||
|
val cacheCount = (if (snapshot.bottomPresent) 1 else 0) + (if (snapshot.topPresent) 1 else 0)
|
||||||
|
diagnostics.text = buildString {
|
||||||
|
append("Range cfg=${snapshot.rangeConfigured} valid=${snapshot.rangeValid} fallback=${snapshot.rangeFallback} reason=${snapshot.lastReason}\n")
|
||||||
|
append("${snapshot.startLayerId}[${snapshot.startIndex}]..${snapshot.endLayerId}[${snapshot.endIndex}] C=[${snapshot.continuousBegin},${snapshot.continuousEndExclusive}) caches=$cacheCount\n")
|
||||||
|
append("B ${snapshot.bottomPresent}/${snapshot.bottomCacheState} b/r/i=${snapshot.bottomBuild}/${snapshot.bottomReuse}/${snapshot.bottomInvalidation} res=${snapshot.bottomTextureCreate}/${snapshot.bottomCompositeCreate}/${snapshot.bottomResourceRelease} ${snapshot.bottomLastInvalidationReason}\n")
|
||||||
|
append("T ${snapshot.topPresent}/${snapshot.topCacheState} b/r/i=${snapshot.topBuild}/${snapshot.topReuse}/${snapshot.topInvalidation} res=${snapshot.topTextureCreate}/${snapshot.topCompositeCreate}/${snapshot.topResourceRelease} ${snapshot.topLastInvalidationReason}\n")
|
||||||
|
append("Fast e/a=${snapshot.fastPathEligible}/${snapshot.fastPathActive} h/m/full=${snapshot.fastPathHit}/${snapshot.fastPathMiss}/${snapshot.fullCpuFrame} ${snapshot.fastPathFallbackReason}")
|
||||||
|
}
|
||||||
|
if (log) {
|
||||||
|
Log.i(TAG, "STEP093_DIAGNOSTICS ${diagnostics.text.toString().replace('\n', ' ')}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun dismissRealWeatherTuning() { realWeatherTuningMenu?.dismiss(); realWeatherTuningMenu = null }
|
private fun dismissRealWeatherTuning() { realWeatherTuningMenu?.dismiss(); realWeatherTuningMenu = null }
|
||||||
|
|
||||||
private fun showRealWeatherTuning(anchor: android.view.View) {
|
private fun showRealWeatherTuning(anchor: android.view.View) {
|
||||||
@@ -564,7 +845,7 @@ class ParticleCoreLayerValidationActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun enterPbfMatrix() {
|
private fun enterPbfMatrix() {
|
||||||
if (realWeatherMode) leaveRealWeatherMode()
|
if (realWeatherMode || step093Mode) leaveRealWeatherMode()
|
||||||
if (!isPbfMatrixMode()) {
|
if (!isPbfMatrixMode()) {
|
||||||
preRealWeatherVisuals = ParticleVisuals(particleCount, lineWidth, particleLength, particleOpacity, trailOpacity, trailFade)
|
preRealWeatherVisuals = ParticleVisuals(particleCount, lineWidth, particleLength, particleOpacity, trailOpacity, trailFade)
|
||||||
particleCount = REAL_WEATHER_PARTICLE_COUNT
|
particleCount = REAL_WEATHER_PARTICLE_COUNT
|
||||||
@@ -1277,6 +1558,10 @@ class ParticleCoreLayerValidationActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun statusText(): String {
|
private fun statusText(): String {
|
||||||
|
if (step093Mode) {
|
||||||
|
return "STEP-093 · ${step093Topology.label} · ${step093Variant.name} · " +
|
||||||
|
"CACHE ${if (retainedCacheEnabled) "ON" else "OFF"}"
|
||||||
|
}
|
||||||
val mask = when (maskMode) {
|
val mask = when (maskMode) {
|
||||||
MASK_OCEAN_A -> "OCEAN A"
|
MASK_OCEAN_A -> "OCEAN A"
|
||||||
MASK_OCEAN_B -> "OCEAN B"
|
MASK_OCEAN_B -> "OCEAN B"
|
||||||
@@ -1318,6 +1603,94 @@ class ParticleCoreLayerValidationActivity : AppCompatActivity() {
|
|||||||
|
|
||||||
private fun realWeatherHudValues(): String = "FPS ${realWeatherTargetFps.name.removePrefix("FPS_")} · P $particleCount · W ${"%.2f".format(lineWidth)} · L ${"%.4f".format(particleLength)} · O ${"%.2f".format(particleOpacity)} · T ${"%.2f".format(trailOpacity)} · F ${"%.2f".format(trailFade)}"
|
private fun realWeatherHudValues(): String = "FPS ${realWeatherTargetFps.name.removePrefix("FPS_")} · P $particleCount · W ${"%.2f".format(lineWidth)} · L ${"%.4f".format(particleLength)} · O ${"%.2f".format(particleOpacity)} · T ${"%.2f".format(trailOpacity)} · F ${"%.2f".format(trailFade)}"
|
||||||
|
|
||||||
|
private fun step093StyleJson(): String {
|
||||||
|
val sources = JSONObject()
|
||||||
|
.put(PARTICLE_SOURCE_ID, JSONObject().put("type", "raster-array").put("host-field-submission", true))
|
||||||
|
.put("step093-bottom-shape", step093GeoJsonSource("""{"type":"Polygon","coordinates":[[[112,0],[158,0],[158,56],[112,56],[112,0]]]}"""))
|
||||||
|
.put("step093-semi-shape", step093GeoJsonSource("""{"type":"Polygon","coordinates":[[[134,8],[151,8],[151,49],[134,49],[134,8]]]}"""))
|
||||||
|
.put("step093-opaque-shape", step093GeoJsonSource("""{"type":"Polygon","coordinates":[[[124,18],[136,18],[136,42],[124,42],[124,18]]]}"""))
|
||||||
|
.put("step093-line-shape", step093GeoJsonSource("""{"type":"LineString","coordinates":[[115,6],[154,50],[154,6],[115,50]]}"""))
|
||||||
|
|
||||||
|
fun fill(id: String, source: String, color: String, opacity: Double) = JSONObject()
|
||||||
|
.put("id", id).put("type", "fill").put("source", source)
|
||||||
|
.put("paint", JSONObject().put("fill-color", color).put("fill-opacity", opacity))
|
||||||
|
fun line(id: String, source: String, color: String, width: Double) = JSONObject()
|
||||||
|
.put("id", id).put("type", "line").put("source", source)
|
||||||
|
.put("paint", JSONObject().put("line-color", color).put("line-width", width).put("line-opacity", 0.95))
|
||||||
|
|
||||||
|
val layers = JSONArray()
|
||||||
|
if (step093Topology.bottom) {
|
||||||
|
layers.put(JSONObject().put("id", STEP093_BOTTOM_BACKGROUND_ID).put("type", "background")
|
||||||
|
.put("paint", JSONObject().put("background-color", "#0b2942")))
|
||||||
|
val bottomBase = fill(STEP093_BOTTOM_FILL_ID, "step093-bottom-shape", "#176b87", 0.72)
|
||||||
|
val bottomExtra = fill(STEP093_BOTTOM_EXTRA_ID, "step093-semi-shape", "#2aa198", 0.18)
|
||||||
|
if (step093Variant == Step093Variant.BOTTOM_REORDER) {
|
||||||
|
layers.put(bottomExtra).put(bottomBase)
|
||||||
|
} else {
|
||||||
|
layers.put(bottomBase)
|
||||||
|
if (step093Variant == Step093Variant.BOTTOM_ADD) layers.put(bottomExtra)
|
||||||
|
}
|
||||||
|
if (step093Variant == Step093Variant.CROSS_BOTTOM) {
|
||||||
|
layers.put(fill(STEP093_CROSS_LAYER_ID, "step093-opaque-shape", "#9b59b6", 0.18))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (step093Variant != Step093Variant.START_MISSING) {
|
||||||
|
layers.put(
|
||||||
|
JSONObject().put("id", STEP093_WEATHER_LAYER_ID).put("type", "weather-color")
|
||||||
|
.put("source", PARTICLE_SOURCE_ID)
|
||||||
|
.put("paint", JSONObject().put("weather-color-opacity", 0.32))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
if (step093Variant == Step093Variant.CONTINUOUS_ADD ||
|
||||||
|
step093Variant == Step093Variant.CONTINUOUS_REORDER) {
|
||||||
|
val first = fill(STEP093_CONTINUOUS_A_ID, "step093-semi-shape", "#ff00ff", 0.16)
|
||||||
|
val second = fill(STEP093_CONTINUOUS_B_ID, "step093-opaque-shape", "#00ffff", 0.12)
|
||||||
|
if (step093Variant == Step093Variant.CONTINUOUS_REORDER) layers.put(second).put(first)
|
||||||
|
else layers.put(first).put(second)
|
||||||
|
}
|
||||||
|
if (step093Variant == Step093Variant.CROSS_CONTINUOUS) {
|
||||||
|
layers.put(fill(STEP093_CROSS_LAYER_ID, "step093-opaque-shape", "#9b59b6", 0.18))
|
||||||
|
}
|
||||||
|
if (step093Variant == Step093Variant.FAST_PATH_FAIL_CLOSED) {
|
||||||
|
layers.put(fill(STEP093_UNKNOWN_CONTINUOUS_ID, "step093-semi-shape", "#ff5500", 0.20))
|
||||||
|
}
|
||||||
|
if (step093Variant != Step093Variant.END_MISSING) layers.put(navSeaParticleLayer(active = true))
|
||||||
|
if (step093Variant == Step093Variant.CROSS_TOP) {
|
||||||
|
layers.put(fill(STEP093_CROSS_LAYER_ID, "step093-opaque-shape", "#9b59b6", 0.18))
|
||||||
|
}
|
||||||
|
|
||||||
|
if (step093Topology.top) {
|
||||||
|
val semi = fill(STEP093_TOP_SEMI_ID, "step093-semi-shape", "#ffd166", 0.42)
|
||||||
|
val opaque = fill(STEP093_TOP_OPAQUE_ID, "step093-opaque-shape", "#ef476f", 1.0)
|
||||||
|
val outline = line(STEP093_TOP_LINE_ID, "step093-line-shape", "#ffffff", 6.0)
|
||||||
|
val extra = line(STEP093_TOP_EXTRA_ID, "step093-opaque-shape", "#00ff99", 3.0)
|
||||||
|
if (step093Variant == Step093Variant.TOP_REORDER) {
|
||||||
|
layers.put(outline).put(opaque).put(semi)
|
||||||
|
} else {
|
||||||
|
layers.put(semi).put(opaque).put(outline)
|
||||||
|
if (step093Variant == Step093Variant.TOP_ADD) layers.put(extra)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return JSONObject()
|
||||||
|
.put("version", 8)
|
||||||
|
.put("name", "STEP-093 Continuous Range Runtime Validation")
|
||||||
|
.put("sources", sources)
|
||||||
|
.put("layers", layers)
|
||||||
|
.toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun step093GeoJsonSource(geometryJson: String): JSONObject = JSONObject()
|
||||||
|
.put("type", "geojson")
|
||||||
|
.put(
|
||||||
|
"data",
|
||||||
|
JSONObject()
|
||||||
|
.put("type", "Feature")
|
||||||
|
.put("properties", JSONObject())
|
||||||
|
.put("geometry", JSONObject(geometryJson))
|
||||||
|
)
|
||||||
|
|
||||||
private fun validationStyle(active: Boolean, enabled: Boolean, reason: String): String {
|
private fun validationStyle(active: Boolean, enabled: Boolean, reason: String): String {
|
||||||
val fixtureId = fixtureId()
|
val fixtureId = fixtureId()
|
||||||
val nextFixtureId = if (timeWindowMode) {
|
val nextFixtureId = if (timeWindowMode) {
|
||||||
@@ -1396,11 +1769,11 @@ class ParticleCoreLayerValidationActivity : AppCompatActivity() {
|
|||||||
""".trimIndent()
|
""".trimIndent()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onStart() { super.onStart(); mapView.onStart() }
|
override fun onStart() { super.onStart(); mapView.onStart(); if (step093Mode) startStep093DiagnosticsPolling() }
|
||||||
override fun onResume() { super.onResume(); mapView.onResume() }
|
override fun onResume() { super.onResume(); mapView.onResume() }
|
||||||
override fun onPause() { mapView.onPause(); super.onPause() }
|
override fun onPause() { mapView.onPause(); super.onPause() }
|
||||||
override fun onStop() { mapView.onStop(); super.onStop() }
|
override fun onStop() { step093Handler.removeCallbacks(step093DiagnosticsPoll); mapView.onStop(); super.onStop() }
|
||||||
override fun onDestroy() { weatherRuntime?.dispose(); weatherRuntime = null; mapView.onDestroy(); super.onDestroy() }
|
override fun onDestroy() { step093Handler.removeCallbacks(step093DiagnosticsPoll); weatherRuntime?.dispose(); weatherRuntime = null; mapView.onDestroy(); super.onDestroy() }
|
||||||
override fun onLowMemory() { super.onLowMemory(); mapView.onLowMemory() }
|
override fun onLowMemory() { super.onLowMemory(); mapView.onLowMemory() }
|
||||||
|
|
||||||
override fun onSaveInstanceState(outState: Bundle) {
|
override fun onSaveInstanceState(outState: Bundle) {
|
||||||
@@ -1425,6 +1798,9 @@ class ParticleCoreLayerValidationActivity : AppCompatActivity() {
|
|||||||
outState.putString(STATE_NAVSEA_PBF_POSITION, navSeaPbfPosition.name)
|
outState.putString(STATE_NAVSEA_PBF_POSITION, navSeaPbfPosition.name)
|
||||||
outState.putBoolean(STATE_NAVSEA_PBF_RENDER_ENABLED, navSeaPbfRenderEnabled)
|
outState.putBoolean(STATE_NAVSEA_PBF_RENDER_ENABLED, navSeaPbfRenderEnabled)
|
||||||
outState.putBoolean(STATE_RETAINED_CACHE_ENABLED, retainedCacheEnabled)
|
outState.putBoolean(STATE_RETAINED_CACHE_ENABLED, retainedCacheEnabled)
|
||||||
|
outState.putBoolean(STATE_STEP093_MODE, step093Mode)
|
||||||
|
outState.putString(STATE_STEP093_TOPOLOGY, step093Topology.name)
|
||||||
|
outState.putString(STATE_STEP093_VARIANT, step093Variant.name)
|
||||||
super.onSaveInstanceState(outState)
|
super.onSaveInstanceState(outState)
|
||||||
mapView.onSaveInstanceState(outState)
|
mapView.onSaveInstanceState(outState)
|
||||||
}
|
}
|
||||||
@@ -1458,9 +1834,26 @@ class ParticleCoreLayerValidationActivity : AppCompatActivity() {
|
|||||||
private const val STATE_NAVSEA_PBF_POSITION = "particle_validation.navsea_pbf_position"
|
private const val STATE_NAVSEA_PBF_POSITION = "particle_validation.navsea_pbf_position"
|
||||||
private const val STATE_NAVSEA_PBF_RENDER_ENABLED = "particle_validation.navsea_pbf_render_enabled"
|
private const val STATE_NAVSEA_PBF_RENDER_ENABLED = "particle_validation.navsea_pbf_render_enabled"
|
||||||
private const val STATE_RETAINED_CACHE_ENABLED = "particle_validation.retained_cache_enabled"
|
private const val STATE_RETAINED_CACHE_ENABLED = "particle_validation.retained_cache_enabled"
|
||||||
|
private const val STATE_STEP093_MODE = "particle_validation.step093_mode"
|
||||||
|
private const val STATE_STEP093_TOPOLOGY = "particle_validation.step093_topology"
|
||||||
|
private const val STATE_STEP093_VARIANT = "particle_validation.step093_variant"
|
||||||
private const val PARTICLE_LAYER_ID = "particle-raster-core"
|
private const val PARTICLE_LAYER_ID = "particle-raster-core"
|
||||||
private const val WEATHER_COLOR_LAYER_ID = "weather-color-real"
|
private const val WEATHER_COLOR_LAYER_ID = "weather-color-real"
|
||||||
private const val PARTICLE_SOURCE_ID = "particle-fixture"
|
private const val PARTICLE_SOURCE_ID = "particle-fixture"
|
||||||
|
private const val STEP093_DIAGNOSTICS_INTERVAL_MS = 1000L
|
||||||
|
private const val STEP093_WEATHER_LAYER_ID = WEATHER_COLOR_LAYER_ID
|
||||||
|
private const val STEP093_PARTICLE_LAYER_ID = PARTICLE_LAYER_ID
|
||||||
|
private const val STEP093_BOTTOM_BACKGROUND_ID = "step093-bottom-background"
|
||||||
|
private const val STEP093_BOTTOM_FILL_ID = "step093-bottom-fill"
|
||||||
|
private const val STEP093_BOTTOM_EXTRA_ID = "step093-bottom-extra"
|
||||||
|
private const val STEP093_CONTINUOUS_A_ID = "step093-continuous-a"
|
||||||
|
private const val STEP093_CONTINUOUS_B_ID = "step093-continuous-b"
|
||||||
|
private const val STEP093_UNKNOWN_CONTINUOUS_ID = "step093-unknown-continuous"
|
||||||
|
private const val STEP093_CROSS_LAYER_ID = "step093-cross-layer"
|
||||||
|
private const val STEP093_TOP_SEMI_ID = "step093-top-semi"
|
||||||
|
private const val STEP093_TOP_OPAQUE_ID = "step093-top-opaque"
|
||||||
|
private const val STEP093_TOP_LINE_ID = "step093-top-line"
|
||||||
|
private const val STEP093_TOP_EXTRA_ID = "step093-top-extra"
|
||||||
private const val MASK_GLOBAL = 0
|
private const val MASK_GLOBAL = 0
|
||||||
private const val MASK_OCEAN_A = 1
|
private const val MASK_OCEAN_A = 1
|
||||||
private const val MASK_OCEAN_B = 2
|
private const val MASK_OCEAN_B = 2
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
<org.maplibre.android.maps.MapView android:id="@id/mapView" android:layout_width="match_parent" android:layout_height="match_parent" />
|
<org.maplibre.android.maps.MapView android:id="@id/mapView" android:layout_width="match_parent" android:layout_height="match_parent" />
|
||||||
<LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="bottom" android:background="#DD102030" android:orientation="vertical" android:padding="4dp">
|
<LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="bottom" android:background="#DD102030" android:orientation="vertical" android:padding="4dp">
|
||||||
<TextView android:id="@+id/validationStatus" android:layout_width="match_parent" android:layout_height="42dp" android:gravity="center_vertical" android:maxLines="2" android:paddingLeft="4dp" android:paddingRight="4dp" android:textColor="@android:color/white" android:textSize="12sp" />
|
<TextView android:id="@+id/validationStatus" android:layout_width="match_parent" android:layout_height="42dp" android:gravity="center_vertical" android:maxLines="2" android:paddingLeft="4dp" android:paddingRight="4dp" android:textColor="@android:color/white" android:textSize="12sp" />
|
||||||
|
<TextView android:id="@+id/validationDiagnostics" android:layout_width="match_parent" android:layout_height="92dp" android:fontFamily="monospace" android:gravity="center_vertical" android:maxLines="6" android:paddingLeft="4dp" android:paddingRight="4dp" android:text="STEP-093 diagnostics: open STEP 093" android:textColor="#FFDD88" android:textSize="9sp" />
|
||||||
<LinearLayout android:layout_width="match_parent" android:layout_height="40dp" android:orientation="horizontal">
|
<LinearLayout android:layout_width="match_parent" android:layout_height="40dp" android:orientation="horizontal">
|
||||||
<Button android:id="@+id/validationMenuTime" style="@style/ParticleValidationButton" android:layout_width="0dp" android:layout_weight="1" android:text="TIME" />
|
<Button android:id="@+id/validationMenuTime" style="@style/ParticleValidationButton" android:layout_width="0dp" android:layout_weight="1" android:text="TIME" />
|
||||||
<Button android:id="@+id/validationMenuVisual" style="@style/ParticleValidationButton" android:layout_width="0dp" android:layout_weight="1" android:text="VIS" />
|
<Button android:id="@+id/validationMenuVisual" style="@style/ParticleValidationButton" android:layout_width="0dp" android:layout_weight="1" android:text="VIS" />
|
||||||
@@ -12,6 +13,7 @@
|
|||||||
<Button android:id="@+id/validationMenuPbfMode" style="@style/ParticleValidationButton" android:layout_width="0dp" android:layout_weight="1" android:text="PBF MODE" android:textSize="9sp" />
|
<Button android:id="@+id/validationMenuPbfMode" style="@style/ParticleValidationButton" android:layout_width="0dp" android:layout_weight="1" android:text="PBF MODE" android:textSize="9sp" />
|
||||||
<Button android:id="@+id/validationMenuNavSeaPbf" style="@style/ParticleValidationButton" android:layout_width="0dp" android:layout_weight="1" android:text="NAVSEA PBF" android:textSize="9sp" />
|
<Button android:id="@+id/validationMenuNavSeaPbf" style="@style/ParticleValidationButton" android:layout_width="0dp" android:layout_weight="1" android:text="NAVSEA PBF" android:textSize="9sp" />
|
||||||
<Button android:id="@+id/validationMenuRetainedCache" style="@style/ParticleValidationButton" android:layout_width="0dp" android:layout_weight="1" android:text="CACHE ON" android:textSize="9sp" />
|
<Button android:id="@+id/validationMenuRetainedCache" style="@style/ParticleValidationButton" android:layout_width="0dp" android:layout_weight="1" android:text="CACHE ON" android:textSize="9sp" />
|
||||||
|
<Button android:id="@+id/validationMenuStep093" style="@style/ParticleValidationButton" android:layout_width="0dp" android:layout_weight="1" android:text="STEP 093" android:textSize="9sp" />
|
||||||
<Button android:id="@+id/validationMenuMore" style="@style/ParticleValidationButton" android:layout_width="0dp" android:layout_weight="1" android:text="MORE" />
|
<Button android:id="@+id/validationMenuMore" style="@style/ParticleValidationButton" android:layout_width="0dp" android:layout_weight="1" android:text="MORE" />
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
<!-- Existing action IDs are invisible menu targets; no permanent button grid. -->
|
<!-- Existing action IDs are invisible menu targets; no permanent button grid. -->
|
||||||
|
|||||||
@@ -44,14 +44,33 @@ MLN_EXPORT
|
|||||||
@property (nonatomic, copy, readonly) NSString *endLayerId;
|
@property (nonatomic, copy, readonly) NSString *endLayerId;
|
||||||
@property (nonatomic, readonly) NSInteger startIndex;
|
@property (nonatomic, readonly) NSInteger startIndex;
|
||||||
@property (nonatomic, readonly) NSInteger endIndex;
|
@property (nonatomic, readonly) NSInteger endIndex;
|
||||||
|
@property (nonatomic, readonly) NSInteger continuousBegin;
|
||||||
|
@property (nonatomic, readonly) NSInteger continuousEndExclusive;
|
||||||
@property (nonatomic, readonly) BOOL bottomPresent;
|
@property (nonatomic, readonly) BOOL bottomPresent;
|
||||||
|
@property (nonatomic, copy, readonly) NSString *bottomCacheState;
|
||||||
@property (nonatomic, readonly) uint64_t bottomBuild;
|
@property (nonatomic, readonly) uint64_t bottomBuild;
|
||||||
@property (nonatomic, readonly) uint64_t bottomReuse;
|
@property (nonatomic, readonly) uint64_t bottomReuse;
|
||||||
@property (nonatomic, readonly) uint64_t bottomInvalidation;
|
@property (nonatomic, readonly) uint64_t bottomInvalidation;
|
||||||
|
@property (nonatomic, copy, readonly) NSString *bottomLastInvalidationReason;
|
||||||
|
@property (nonatomic, readonly) uint64_t bottomTextureCreate;
|
||||||
|
@property (nonatomic, readonly) uint64_t bottomCompositeCreate;
|
||||||
|
@property (nonatomic, readonly) uint64_t bottomResourceRelease;
|
||||||
@property (nonatomic, readonly) BOOL topPresent;
|
@property (nonatomic, readonly) BOOL topPresent;
|
||||||
|
@property (nonatomic, copy, readonly) NSString *topCacheState;
|
||||||
@property (nonatomic, readonly) uint64_t topBuild;
|
@property (nonatomic, readonly) uint64_t topBuild;
|
||||||
@property (nonatomic, readonly) uint64_t topReuse;
|
@property (nonatomic, readonly) uint64_t topReuse;
|
||||||
@property (nonatomic, readonly) uint64_t topInvalidation;
|
@property (nonatomic, readonly) uint64_t topInvalidation;
|
||||||
|
@property (nonatomic, copy, readonly) NSString *topLastInvalidationReason;
|
||||||
|
@property (nonatomic, readonly) uint64_t topTextureCreate;
|
||||||
|
@property (nonatomic, readonly) uint64_t topCompositeCreate;
|
||||||
|
@property (nonatomic, readonly) uint64_t topResourceRelease;
|
||||||
|
@property (nonatomic, readonly) BOOL rangeFallback;
|
||||||
|
@property (nonatomic, readonly) BOOL fastPathEligible;
|
||||||
|
@property (nonatomic, readonly) BOOL fastPathActive;
|
||||||
|
@property (nonatomic, copy, readonly) NSString *fastPathFallbackReason;
|
||||||
|
@property (nonatomic, readonly) uint64_t fastPathHit;
|
||||||
|
@property (nonatomic, readonly) uint64_t fastPathMiss;
|
||||||
|
@property (nonatomic, readonly) uint64_t fullCpuFrame;
|
||||||
|
|
||||||
- (instancetype)init NS_UNAVAILABLE;
|
- (instancetype)init NS_UNAVAILABLE;
|
||||||
|
|
||||||
|
|||||||
@@ -267,6 +267,13 @@ int processIsTranslated() {
|
|||||||
_endLayerId = @"";
|
_endLayerId = @"";
|
||||||
_startIndex = -1;
|
_startIndex = -1;
|
||||||
_endIndex = -1;
|
_endIndex = -1;
|
||||||
|
_continuousBegin = -1;
|
||||||
|
_continuousEndExclusive = -1;
|
||||||
|
_bottomCacheState = @"disabled";
|
||||||
|
_bottomLastInvalidationReason = @"none";
|
||||||
|
_topCacheState = @"disabled";
|
||||||
|
_topLastInvalidationReason = @"none";
|
||||||
|
_fastPathFallbackReason = @"no-prepared-tree";
|
||||||
}
|
}
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
@@ -278,14 +285,33 @@ int processIsTranslated() {
|
|||||||
_endLayerId = [NSString stringWithUTF8String:snapshot.endLayerId.c_str()];
|
_endLayerId = [NSString stringWithUTF8String:snapshot.endLayerId.c_str()];
|
||||||
_startIndex = snapshot.startIndex;
|
_startIndex = snapshot.startIndex;
|
||||||
_endIndex = snapshot.endIndex;
|
_endIndex = snapshot.endIndex;
|
||||||
|
_continuousBegin = snapshot.continuousBegin;
|
||||||
|
_continuousEndExclusive = snapshot.continuousEndExclusive;
|
||||||
_bottomPresent = snapshot.bottomPresent;
|
_bottomPresent = snapshot.bottomPresent;
|
||||||
|
_bottomCacheState = [NSString stringWithUTF8String:snapshot.bottomCacheState.c_str()];
|
||||||
_bottomBuild = snapshot.bottomBuild;
|
_bottomBuild = snapshot.bottomBuild;
|
||||||
_bottomReuse = snapshot.bottomReuse;
|
_bottomReuse = snapshot.bottomReuse;
|
||||||
_bottomInvalidation = snapshot.bottomInvalidation;
|
_bottomInvalidation = snapshot.bottomInvalidation;
|
||||||
|
_bottomLastInvalidationReason = [NSString stringWithUTF8String:snapshot.bottomLastInvalidationReason.c_str()];
|
||||||
|
_bottomTextureCreate = snapshot.bottomTextureCreate;
|
||||||
|
_bottomCompositeCreate = snapshot.bottomCompositeCreate;
|
||||||
|
_bottomResourceRelease = snapshot.bottomResourceRelease;
|
||||||
_topPresent = snapshot.topPresent;
|
_topPresent = snapshot.topPresent;
|
||||||
|
_topCacheState = [NSString stringWithUTF8String:snapshot.topCacheState.c_str()];
|
||||||
_topBuild = snapshot.topBuild;
|
_topBuild = snapshot.topBuild;
|
||||||
_topReuse = snapshot.topReuse;
|
_topReuse = snapshot.topReuse;
|
||||||
_topInvalidation = snapshot.topInvalidation;
|
_topInvalidation = snapshot.topInvalidation;
|
||||||
|
_topLastInvalidationReason = [NSString stringWithUTF8String:snapshot.topLastInvalidationReason.c_str()];
|
||||||
|
_topTextureCreate = snapshot.topTextureCreate;
|
||||||
|
_topCompositeCreate = snapshot.topCompositeCreate;
|
||||||
|
_topResourceRelease = snapshot.topResourceRelease;
|
||||||
|
_rangeFallback = snapshot.rangeFallback;
|
||||||
|
_fastPathEligible = snapshot.fastPathEligible;
|
||||||
|
_fastPathActive = snapshot.fastPathActive;
|
||||||
|
_fastPathFallbackReason = [NSString stringWithUTF8String:snapshot.fastPathFallbackReason.c_str()];
|
||||||
|
_fastPathHit = snapshot.fastPathHit;
|
||||||
|
_fastPathMiss = snapshot.fastPathMiss;
|
||||||
|
_fullCpuFrame = snapshot.fullCpuFrame;
|
||||||
}
|
}
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ enum class ParticleFastPathMissReason : uint8_t {
|
|||||||
StillImageRequest,
|
StillImageRequest,
|
||||||
UnsupportedMode,
|
UnsupportedMode,
|
||||||
DebugOptions,
|
DebugOptions,
|
||||||
|
UnsupportedContinuousLayer,
|
||||||
UnsupportedScene,
|
UnsupportedScene,
|
||||||
AnnotationMutation,
|
AnnotationMutation,
|
||||||
};
|
};
|
||||||
@@ -56,6 +57,7 @@ inline const char* particleFastPathMissReasonText(ParticleFastPathMissReason rea
|
|||||||
case ParticleFastPathMissReason::StillImageRequest: return "still-image-request";
|
case ParticleFastPathMissReason::StillImageRequest: return "still-image-request";
|
||||||
case ParticleFastPathMissReason::UnsupportedMode: return "unsupported-mode";
|
case ParticleFastPathMissReason::UnsupportedMode: return "unsupported-mode";
|
||||||
case ParticleFastPathMissReason::DebugOptions: return "debug-options";
|
case ParticleFastPathMissReason::DebugOptions: return "debug-options";
|
||||||
|
case ParticleFastPathMissReason::UnsupportedContinuousLayer: return "unsupported-continuous-layer";
|
||||||
case ParticleFastPathMissReason::UnsupportedScene: return "unsupported-scene";
|
case ParticleFastPathMissReason::UnsupportedScene: return "unsupported-scene";
|
||||||
case ParticleFastPathMissReason::AnnotationMutation: return "annotation-mutation";
|
case ParticleFastPathMissReason::AnnotationMutation: return "annotation-mutation";
|
||||||
}
|
}
|
||||||
@@ -84,6 +86,7 @@ struct ParticleFastPathGateInput {
|
|||||||
bool stillImageRequest = false;
|
bool stillImageRequest = false;
|
||||||
bool continuousMode = false;
|
bool continuousMode = false;
|
||||||
bool debugDisabled = false;
|
bool debugDisabled = false;
|
||||||
|
bool unsupportedContinuousLayer = false;
|
||||||
bool supportedScene = false;
|
bool supportedScene = false;
|
||||||
bool annotationMutation = false;
|
bool annotationMutation = false;
|
||||||
};
|
};
|
||||||
@@ -115,6 +118,9 @@ inline ParticleFastPathDecision evaluateParticleFastPath(const ParticleFastPathG
|
|||||||
if (input.stillImageRequest) return {false, ParticleFastPathMissReason::StillImageRequest};
|
if (input.stillImageRequest) return {false, ParticleFastPathMissReason::StillImageRequest};
|
||||||
if (!input.continuousMode) return {false, ParticleFastPathMissReason::UnsupportedMode};
|
if (!input.continuousMode) return {false, ParticleFastPathMissReason::UnsupportedMode};
|
||||||
if (!input.debugDisabled) return {false, ParticleFastPathMissReason::DebugOptions};
|
if (!input.debugDisabled) return {false, ParticleFastPathMissReason::DebugOptions};
|
||||||
|
if (input.unsupportedContinuousLayer) {
|
||||||
|
return {false, ParticleFastPathMissReason::UnsupportedContinuousLayer};
|
||||||
|
}
|
||||||
if (!input.supportedScene) return {false, ParticleFastPathMissReason::UnsupportedScene};
|
if (!input.supportedScene) return {false, ParticleFastPathMissReason::UnsupportedScene};
|
||||||
if (input.annotationMutation) return {false, ParticleFastPathMissReason::AnnotationMutation};
|
if (input.annotationMutation) return {false, ParticleFastPathMissReason::AnnotationMutation};
|
||||||
return {true, ParticleFastPathMissReason::None};
|
return {true, ParticleFastPathMissReason::None};
|
||||||
|
|||||||
@@ -265,11 +265,13 @@ bool Renderer::Impl::tryRenderParticleFastFrame(const std::shared_ptr<UpdatePara
|
|||||||
.stillImageRequest = updateParameters->stillImageRequest,
|
.stillImageRequest = updateParameters->stillImageRequest,
|
||||||
.continuousMode = updateParameters->mode == MapMode::Continuous,
|
.continuousMode = updateParameters->mode == MapMode::Continuous,
|
||||||
.debugDisabled = updateParameters->debugOptions == MapDebugOptions::NoDebug,
|
.debugDisabled = updateParameters->debugOptions == MapDebugOptions::NoDebug,
|
||||||
|
.unsupportedContinuousLayer = particlePreparedContinuousUnsupported,
|
||||||
.supportedScene = particlePreparedSceneSupported,
|
.supportedScene = particlePreparedSceneSupported,
|
||||||
.annotationMutation = annotationMutation,
|
.annotationMutation = annotationMutation,
|
||||||
};
|
};
|
||||||
const auto decision = evaluateParticleFastPath(input);
|
const auto decision = evaluateParticleFastPath(input);
|
||||||
particleFastPathLastReason = decision.reason;
|
particleFastPathLastReason = decision.reason;
|
||||||
|
retainedUnderlayCache->recordFastPathDecision(decision.candidate, decision.reason);
|
||||||
if (!decision.candidate) {
|
if (!decision.candidate) {
|
||||||
particle::incrementRendererDebugCounter(particle::RendererDebugCounter::ParticleFastFrameMiss);
|
particle::incrementRendererDebugCounter(particle::RendererDebugCounter::ParticleFastFrameMiss);
|
||||||
return false;
|
return false;
|
||||||
@@ -310,6 +312,7 @@ void Renderer::Impl::clearPreparedRenderTree() {
|
|||||||
particlePreparedRangeConfigRevision = 0;
|
particlePreparedRangeConfigRevision = 0;
|
||||||
particlePreparedBottomPresent = false;
|
particlePreparedBottomPresent = false;
|
||||||
particlePreparedTopPresent = false;
|
particlePreparedTopPresent = false;
|
||||||
|
particlePreparedContinuousUnsupported = false;
|
||||||
particlePreparedBackendSize = {};
|
particlePreparedBackendSize = {};
|
||||||
particlePreparedSceneSupported = false;
|
particlePreparedSceneSupported = false;
|
||||||
}
|
}
|
||||||
@@ -321,6 +324,7 @@ void Renderer::Impl::render(const RenderTree& renderTree,
|
|||||||
particle::incrementRendererDebugCounter(particle::RendererDebugCounter::FullRendererFrame);
|
particle::incrementRendererDebugCounter(particle::RendererDebugCounter::FullRendererFrame);
|
||||||
if (!particleFastFrame) {
|
if (!particleFastFrame) {
|
||||||
particle::incrementRendererDebugCounter(particle::RendererDebugCounter::ParticleFullFrame);
|
particle::incrementRendererDebugCounter(particle::RendererDebugCounter::ParticleFullFrame);
|
||||||
|
retainedUnderlayCache->recordFullCpuFrame();
|
||||||
}
|
}
|
||||||
auto& context = backend.getContext();
|
auto& context = backend.getContext();
|
||||||
context.setObserver(this);
|
context.setObserver(this);
|
||||||
@@ -591,6 +595,8 @@ void Renderer::Impl::render(const RenderTree& renderTree,
|
|||||||
? orchestrator.continuousRangeSupportsParticleFastPath(
|
? orchestrator.continuousRangeSupportsParticleFastPath(
|
||||||
ranges.continuousBegin, ranges.continuousEndExclusive)
|
ranges.continuousBegin, ranges.continuousEndExclusive)
|
||||||
: retainedSupported;
|
: retainedSupported;
|
||||||
|
if (!particleFastFrame) particlePreparedContinuousUnsupported = rangeMode && !fastContinuousSupported;
|
||||||
|
retainedUnderlayCache->recordFastPathEligibility(retainedSupported && fastContinuousSupported);
|
||||||
if (!particleFastFrame) particlePreparedSceneSupported = retainedSupported && fastContinuousSupported;
|
if (!particleFastFrame) particlePreparedSceneSupported = retainedSupported && fastContinuousSupported;
|
||||||
const char* retainedFallbackReason = nullptr;
|
const char* retainedFallbackReason = nullptr;
|
||||||
if (!retainedMode) {
|
if (!retainedMode) {
|
||||||
|
|||||||
@@ -112,6 +112,7 @@ private:
|
|||||||
uint64_t particlePreparedRangeConfigRevision = 0;
|
uint64_t particlePreparedRangeConfigRevision = 0;
|
||||||
bool particlePreparedBottomPresent = false;
|
bool particlePreparedBottomPresent = false;
|
||||||
bool particlePreparedTopPresent = false;
|
bool particlePreparedTopPresent = false;
|
||||||
|
bool particlePreparedContinuousUnsupported = false;
|
||||||
Size particlePreparedBackendSize;
|
Size particlePreparedBackendSize;
|
||||||
bool particlePreparedSceneSupported = false;
|
bool particlePreparedSceneSupported = false;
|
||||||
ParticleFastPathMissReason particleFastPathLastReason = ParticleFastPathMissReason::NoPreparedTree;
|
ParticleFastPathMissReason particleFastPathLastReason = ParticleFastPathMissReason::NoPreparedTree;
|
||||||
|
|||||||
@@ -134,11 +134,14 @@ void RetainedUnderlayCache::synchronizeRuntimeState(
|
|||||||
valid = false;
|
valid = false;
|
||||||
lastInvalidationReason = "runtime-disabled";
|
lastInvalidationReason = "runtime-disabled";
|
||||||
runtimeState->recordRangeInvalidation(role == RetainedRangeRole::Top);
|
runtimeState->recordRangeInvalidation(role == RetainedRangeRole::Top);
|
||||||
|
runtimeState->recordRangeInvalidationReason(
|
||||||
|
role == RetainedRangeRole::Top, RetainedUnderlayReason::RuntimeDisabled);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
releaseResources();
|
releaseResources();
|
||||||
if (!runtimeState->isEnabled()) {
|
if (!runtimeState->isEnabled()) {
|
||||||
lastInvalidationReason = "runtime-disabled";
|
lastInvalidationReason = "runtime-disabled";
|
||||||
|
runtimeState->recordRangeCacheState(role == RetainedRangeRole::Top, RetainedRangeCacheState::Fallback);
|
||||||
particle::incrementRendererDebugCounter(particle::RendererDebugCounter::RetainedUnderlayInvalidation);
|
particle::incrementRendererDebugCounter(particle::RendererDebugCounter::RetainedUnderlayInvalidation);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -155,12 +158,14 @@ RetainedUnderlayDecision RetainedUnderlayCache::evaluate(const std::optional<Ret
|
|||||||
invalidate(fallbackReason ? fallbackReason : "no-boundary");
|
invalidate(fallbackReason ? fallbackReason : "no-boundary");
|
||||||
releaseResources();
|
releaseResources();
|
||||||
}
|
}
|
||||||
|
runtimeState->recordRangeCacheState(role == RetainedRangeRole::Top, RetainedRangeCacheState::Disabled);
|
||||||
return RetainedUnderlayDecision::Disabled;
|
return RetainedUnderlayDecision::Disabled;
|
||||||
}
|
}
|
||||||
if (runtimeState && !runtimeState->isEnabled()) {
|
if (runtimeState && !runtimeState->isEnabled()) {
|
||||||
++fallbackCount;
|
++fallbackCount;
|
||||||
runtimeState->recordFallback();
|
runtimeState->recordFallback();
|
||||||
particle::incrementRendererDebugCounter(particle::RendererDebugCounter::RetainedUnderlayFallback);
|
particle::incrementRendererDebugCounter(particle::RendererDebugCounter::RetainedUnderlayFallback);
|
||||||
|
runtimeState->recordRangeCacheState(role == RetainedRangeRole::Top, RetainedRangeCacheState::Fallback);
|
||||||
return RetainedUnderlayDecision::Fallback;
|
return RetainedUnderlayDecision::Fallback;
|
||||||
}
|
}
|
||||||
if (!supported) {
|
if (!supported) {
|
||||||
@@ -169,6 +174,7 @@ RetainedUnderlayDecision RetainedUnderlayCache::evaluate(const std::optional<Ret
|
|||||||
particle::incrementRendererDebugCounter(particle::RendererDebugCounter::RetainedUnderlayFallback);
|
particle::incrementRendererDebugCounter(particle::RendererDebugCounter::RetainedUnderlayFallback);
|
||||||
invalidate(fallbackReason ? fallbackReason : "unsupported");
|
invalidate(fallbackReason ? fallbackReason : "unsupported");
|
||||||
if (revisionChanged) releaseResources();
|
if (revisionChanged) releaseResources();
|
||||||
|
runtimeState->recordRangeCacheState(role == RetainedRangeRole::Top, RetainedRangeCacheState::Fallback);
|
||||||
return RetainedUnderlayDecision::Fallback;
|
return RetainedUnderlayDecision::Fallback;
|
||||||
}
|
}
|
||||||
if (revisionChanged) {
|
if (revisionChanged) {
|
||||||
@@ -193,8 +199,10 @@ RetainedUnderlayDecision RetainedUnderlayCache::evaluate(const std::optional<Ret
|
|||||||
runtimeState->recordReuse();
|
runtimeState->recordReuse();
|
||||||
runtimeState->recordRangeReuse(role == RetainedRangeRole::Top);
|
runtimeState->recordRangeReuse(role == RetainedRangeRole::Top);
|
||||||
particle::incrementRendererDebugCounter(particle::RendererDebugCounter::RetainedUnderlayReuse);
|
particle::incrementRendererDebugCounter(particle::RendererDebugCounter::RetainedUnderlayReuse);
|
||||||
|
runtimeState->recordRangeCacheState(role == RetainedRangeRole::Top, RetainedRangeCacheState::Reuse);
|
||||||
return RetainedUnderlayDecision::Reuse;
|
return RetainedUnderlayDecision::Reuse;
|
||||||
}
|
}
|
||||||
|
runtimeState->recordRangeCacheState(role == RetainedRangeRole::Top, RetainedRangeCacheState::BuildPending);
|
||||||
return RetainedUnderlayDecision::Build;
|
return RetainedUnderlayDecision::Build;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -205,6 +213,7 @@ bool RetainedUnderlayCache::prepareResources(gfx::Context& context,
|
|||||||
if (!offscreenTexture || offscreenTexture->getSize() != nextKey.viewport) {
|
if (!offscreenTexture || offscreenTexture->getSize() != nextKey.viewport) {
|
||||||
offscreenTexture = context.createOffscreenTexture(
|
offscreenTexture = context.createOffscreenTexture(
|
||||||
nextKey.viewport, gfx::TextureChannelDataType::UnsignedByte, true, true);
|
nextKey.viewport, gfx::TextureChannelDataType::UnsignedByte, true, true);
|
||||||
|
runtimeState->recordRangeTextureCreate(role == RetainedRangeRole::Top);
|
||||||
compositeLayerGroup.reset();
|
compositeLayerGroup.reset();
|
||||||
}
|
}
|
||||||
if (!offscreenTexture || !offscreenTexture->isRenderable()) return false;
|
if (!offscreenTexture || !offscreenTexture->isRenderable()) return false;
|
||||||
@@ -248,6 +257,7 @@ bool RetainedUnderlayCache::rebuildComposite(gfx::Context& context, gfx::ShaderR
|
|||||||
builder->flush(context);
|
builder->flush(context);
|
||||||
for (auto& drawable : builder->clearDrawables()) group->addDrawable(std::move(drawable));
|
for (auto& drawable : builder->clearDrawables()) group->addDrawable(std::move(drawable));
|
||||||
compositeLayerGroup = std::move(group);
|
compositeLayerGroup = std::move(group);
|
||||||
|
runtimeState->recordRangeCompositeCreate(role == RetainedRangeRole::Top);
|
||||||
return !compositeLayerGroup->empty();
|
return !compositeLayerGroup->empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -285,6 +295,7 @@ void RetainedUnderlayCache::markBuildSucceeded() {
|
|||||||
++buildCount;
|
++buildCount;
|
||||||
runtimeState->recordBuild();
|
runtimeState->recordBuild();
|
||||||
runtimeState->recordRangeBuild(role == RetainedRangeRole::Top);
|
runtimeState->recordRangeBuild(role == RetainedRangeRole::Top);
|
||||||
|
runtimeState->recordRangeCacheState(role == RetainedRangeRole::Top, RetainedRangeCacheState::Ready);
|
||||||
particle::incrementRendererDebugCounter(particle::RendererDebugCounter::RetainedUnderlayBuild);
|
particle::incrementRendererDebugCounter(particle::RendererDebugCounter::RetainedUnderlayBuild);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -293,6 +304,7 @@ void RetainedUnderlayCache::markBuildFailed(const char* reason) {
|
|||||||
runtimeState->recordFallback();
|
runtimeState->recordFallback();
|
||||||
particle::incrementRendererDebugCounter(particle::RendererDebugCounter::RetainedUnderlayFallback);
|
particle::incrementRendererDebugCounter(particle::RendererDebugCounter::RetainedUnderlayFallback);
|
||||||
invalidate(reason);
|
invalidate(reason);
|
||||||
|
runtimeState->recordRangeCacheState(role == RetainedRangeRole::Top, RetainedRangeCacheState::Fallback);
|
||||||
releaseResources();
|
releaseResources();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -301,10 +313,14 @@ void RetainedUnderlayCache::invalidate(const char* reason) {
|
|||||||
lastInvalidationReason = reason ? reason : "unknown";
|
lastInvalidationReason = reason ? reason : "unknown";
|
||||||
runtimeState->recordInvalidation(retainedReason(reason));
|
runtimeState->recordInvalidation(retainedReason(reason));
|
||||||
runtimeState->recordRangeInvalidation(role == RetainedRangeRole::Top);
|
runtimeState->recordRangeInvalidation(role == RetainedRangeRole::Top);
|
||||||
|
runtimeState->recordRangeInvalidationReason(role == RetainedRangeRole::Top, retainedReason(reason));
|
||||||
particle::incrementRendererDebugCounter(particle::RendererDebugCounter::RetainedUnderlayInvalidation);
|
particle::incrementRendererDebugCounter(particle::RendererDebugCounter::RetainedUnderlayInvalidation);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RetainedUnderlayCache::releaseResources() {
|
void RetainedUnderlayCache::releaseResources() {
|
||||||
|
if (offscreenTexture || compositeLayerGroup) {
|
||||||
|
runtimeState->recordRangeResourceRelease(role == RetainedRangeRole::Top);
|
||||||
|
}
|
||||||
valid = false;
|
valid = false;
|
||||||
buildRevision = 0;
|
buildRevision = 0;
|
||||||
key.reset();
|
key.reset();
|
||||||
|
|||||||
@@ -140,6 +140,11 @@ public:
|
|||||||
uint64_t getBuildRevision() const noexcept { return buildRevision; }
|
uint64_t getBuildRevision() const noexcept { return buildRevision; }
|
||||||
const std::string& getLastInvalidationReason() const noexcept { return lastInvalidationReason; }
|
const std::string& getLastInvalidationReason() const noexcept { return lastInvalidationReason; }
|
||||||
RetainedUnderlayDiagnostics getDiagnostics() const { return runtimeState->snapshot(); }
|
RetainedUnderlayDiagnostics getDiagnostics() const { return runtimeState->snapshot(); }
|
||||||
|
void recordFastPathEligibility(bool eligible) { runtimeState->recordFastPathEligibility(eligible); }
|
||||||
|
void recordFastPathDecision(bool active, ParticleFastPathMissReason reason) {
|
||||||
|
runtimeState->recordFastPathDecision(active, reason);
|
||||||
|
}
|
||||||
|
void recordFullCpuFrame() { runtimeState->recordFullCpuFrame(); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool rebuildComposite(gfx::Context&, gfx::ShaderRegistry&);
|
bool rebuildComposite(gfx::Context&, gfx::ShaderRegistry&);
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <mbgl/renderer/particle_fast_path.hpp>
|
||||||
#include <mbgl/renderer/retained_underlay.hpp>
|
#include <mbgl/renderer/retained_underlay.hpp>
|
||||||
|
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
@@ -8,6 +9,19 @@
|
|||||||
|
|
||||||
namespace mbgl {
|
namespace mbgl {
|
||||||
|
|
||||||
|
enum class RetainedRangeCacheState : uint8_t { Disabled, BuildPending, Ready, Reuse, Fallback };
|
||||||
|
|
||||||
|
inline const char* retainedRangeCacheStateText(RetainedRangeCacheState state) noexcept {
|
||||||
|
switch (state) {
|
||||||
|
case RetainedRangeCacheState::Disabled: return "disabled";
|
||||||
|
case RetainedRangeCacheState::BuildPending: return "build-pending";
|
||||||
|
case RetainedRangeCacheState::Ready: return "ready";
|
||||||
|
case RetainedRangeCacheState::Reuse: return "reuse";
|
||||||
|
case RetainedRangeCacheState::Fallback: return "fallback";
|
||||||
|
}
|
||||||
|
return "disabled";
|
||||||
|
}
|
||||||
|
|
||||||
enum class RetainedUnderlayReason : uint8_t {
|
enum class RetainedUnderlayReason : uint8_t {
|
||||||
None,
|
None,
|
||||||
RuntimeDisabled,
|
RuntimeDisabled,
|
||||||
@@ -152,6 +166,8 @@ public:
|
|||||||
result.endLayerId = rangeResolution.endLayerId;
|
result.endLayerId = rangeResolution.endLayerId;
|
||||||
result.startIndex = rangeResolution.startIndex;
|
result.startIndex = rangeResolution.startIndex;
|
||||||
result.endIndex = rangeResolution.endIndex;
|
result.endIndex = rangeResolution.endIndex;
|
||||||
|
result.continuousBegin = rangeResolution.begin();
|
||||||
|
result.continuousEndExclusive = rangeResolution.endExclusive();
|
||||||
result.bottomPresent = bottomRangePresent;
|
result.bottomPresent = bottomRangePresent;
|
||||||
result.topPresent = topRangePresent;
|
result.topPresent = topRangePresent;
|
||||||
result.rangeFallback = rangeResolution.configured && !rangeResolution.valid;
|
result.rangeFallback = rangeResolution.configured && !rangeResolution.valid;
|
||||||
@@ -159,6 +175,25 @@ public:
|
|||||||
result.lastReason = rangeResolution.reason;
|
result.lastReason = rangeResolution.reason;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
result.bottomCacheState = retainedRangeCacheStateText(bottomCacheState.load(std::memory_order_acquire));
|
||||||
|
result.bottomLastInvalidationReason =
|
||||||
|
retainedUnderlayReasonText(bottomLastInvalidationReason.load(std::memory_order_acquire));
|
||||||
|
result.bottomTextureCreate = bottomTextureCreate.load(std::memory_order_relaxed);
|
||||||
|
result.bottomCompositeCreate = bottomCompositeCreate.load(std::memory_order_relaxed);
|
||||||
|
result.bottomResourceRelease = bottomResourceRelease.load(std::memory_order_relaxed);
|
||||||
|
result.topCacheState = retainedRangeCacheStateText(topCacheState.load(std::memory_order_acquire));
|
||||||
|
result.topLastInvalidationReason =
|
||||||
|
retainedUnderlayReasonText(topLastInvalidationReason.load(std::memory_order_acquire));
|
||||||
|
result.topTextureCreate = topTextureCreate.load(std::memory_order_relaxed);
|
||||||
|
result.topCompositeCreate = topCompositeCreate.load(std::memory_order_relaxed);
|
||||||
|
result.topResourceRelease = topResourceRelease.load(std::memory_order_relaxed);
|
||||||
|
result.fastPathEligible = fastPathEligible.load(std::memory_order_acquire);
|
||||||
|
result.fastPathActive = fastPathActive.load(std::memory_order_acquire);
|
||||||
|
result.fastPathFallbackReason =
|
||||||
|
particleFastPathMissReasonText(fastPathReason.load(std::memory_order_acquire));
|
||||||
|
result.fastPathHit = fastPathHit.load(std::memory_order_relaxed);
|
||||||
|
result.fastPathMiss = fastPathMiss.load(std::memory_order_relaxed);
|
||||||
|
result.fullCpuFrame = fullCpuFrame.load(std::memory_order_relaxed);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -178,6 +213,33 @@ public:
|
|||||||
void recordRangeInvalidation(bool top) noexcept {
|
void recordRangeInvalidation(bool top) noexcept {
|
||||||
(top ? topInvalidation : bottomInvalidation).fetch_add(1, std::memory_order_relaxed);
|
(top ? topInvalidation : bottomInvalidation).fetch_add(1, std::memory_order_relaxed);
|
||||||
}
|
}
|
||||||
|
void recordRangeCacheState(bool top, RetainedRangeCacheState state) noexcept {
|
||||||
|
(top ? topCacheState : bottomCacheState).store(state, std::memory_order_release);
|
||||||
|
}
|
||||||
|
void recordRangeInvalidationReason(bool top, RetainedUnderlayReason reason) noexcept {
|
||||||
|
(top ? topLastInvalidationReason : bottomLastInvalidationReason).store(reason, std::memory_order_release);
|
||||||
|
}
|
||||||
|
void recordRangeTextureCreate(bool top) noexcept {
|
||||||
|
(top ? topTextureCreate : bottomTextureCreate).fetch_add(1, std::memory_order_relaxed);
|
||||||
|
}
|
||||||
|
void recordRangeCompositeCreate(bool top) noexcept {
|
||||||
|
(top ? topCompositeCreate : bottomCompositeCreate).fetch_add(1, std::memory_order_relaxed);
|
||||||
|
}
|
||||||
|
void recordRangeResourceRelease(bool top) noexcept {
|
||||||
|
(top ? topResourceRelease : bottomResourceRelease).fetch_add(1, std::memory_order_relaxed);
|
||||||
|
}
|
||||||
|
void recordFastPathEligibility(bool eligible) noexcept {
|
||||||
|
fastPathEligible.store(eligible, std::memory_order_release);
|
||||||
|
}
|
||||||
|
void recordFastPathDecision(bool active, ParticleFastPathMissReason reason) noexcept {
|
||||||
|
fastPathActive.store(active, std::memory_order_release);
|
||||||
|
fastPathReason.store(reason, std::memory_order_release);
|
||||||
|
(active ? fastPathHit : fastPathMiss).fetch_add(1, std::memory_order_relaxed);
|
||||||
|
}
|
||||||
|
void recordFullCpuFrame() noexcept {
|
||||||
|
fullCpuFrame.fetch_add(1, std::memory_order_relaxed);
|
||||||
|
fastPathActive.store(false, std::memory_order_release);
|
||||||
|
}
|
||||||
private:
|
private:
|
||||||
std::atomic<bool> enabled{true};
|
std::atomic<bool> enabled{true};
|
||||||
std::atomic<uint64_t> controlRevision{0};
|
std::atomic<uint64_t> controlRevision{0};
|
||||||
@@ -192,6 +254,22 @@ private:
|
|||||||
std::atomic<uint64_t> topBuild{0};
|
std::atomic<uint64_t> topBuild{0};
|
||||||
std::atomic<uint64_t> topReuse{0};
|
std::atomic<uint64_t> topReuse{0};
|
||||||
std::atomic<uint64_t> topInvalidation{0};
|
std::atomic<uint64_t> topInvalidation{0};
|
||||||
|
std::atomic<RetainedRangeCacheState> bottomCacheState{RetainedRangeCacheState::Disabled};
|
||||||
|
std::atomic<RetainedUnderlayReason> bottomLastInvalidationReason{RetainedUnderlayReason::None};
|
||||||
|
std::atomic<uint64_t> bottomTextureCreate{0};
|
||||||
|
std::atomic<uint64_t> bottomCompositeCreate{0};
|
||||||
|
std::atomic<uint64_t> bottomResourceRelease{0};
|
||||||
|
std::atomic<RetainedRangeCacheState> topCacheState{RetainedRangeCacheState::Disabled};
|
||||||
|
std::atomic<RetainedUnderlayReason> topLastInvalidationReason{RetainedUnderlayReason::None};
|
||||||
|
std::atomic<uint64_t> topTextureCreate{0};
|
||||||
|
std::atomic<uint64_t> topCompositeCreate{0};
|
||||||
|
std::atomic<uint64_t> topResourceRelease{0};
|
||||||
|
std::atomic<bool> fastPathEligible{false};
|
||||||
|
std::atomic<bool> fastPathActive{false};
|
||||||
|
std::atomic<ParticleFastPathMissReason> fastPathReason{ParticleFastPathMissReason::NoPreparedTree};
|
||||||
|
std::atomic<uint64_t> fastPathHit{0};
|
||||||
|
std::atomic<uint64_t> fastPathMiss{0};
|
||||||
|
std::atomic<uint64_t> fullCpuFrame{0};
|
||||||
mutable std::mutex rangeMutex;
|
mutable std::mutex rangeMutex;
|
||||||
ContinuousLayerRangeConfig rangeConfig;
|
ContinuousLayerRangeConfig rangeConfig;
|
||||||
ContinuousLayerRangeResolution rangeResolution;
|
ContinuousLayerRangeResolution rangeResolution;
|
||||||
|
|||||||
@@ -57,6 +57,7 @@ ParticleFastPathGateInput fastPathInput() {
|
|||||||
.stillImageRequest = false,
|
.stillImageRequest = false,
|
||||||
.continuousMode = true,
|
.continuousMode = true,
|
||||||
.debugDisabled = true,
|
.debugDisabled = true,
|
||||||
|
.unsupportedContinuousLayer = false,
|
||||||
.supportedScene = true,
|
.supportedScene = true,
|
||||||
.annotationMutation = false,
|
.annotationMutation = false,
|
||||||
};
|
};
|
||||||
@@ -124,6 +125,46 @@ TEST(RetainedUnderlayCache, BuildReuseAndInvalidation) {
|
|||||||
EXPECT_EQ(cache.getLastInvalidationReason(), "camera-or-boundary");
|
EXPECT_EQ(cache.getLastInvalidationReason(), "camera-or-boundary");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(RetainedUnderlayCache, RuntimeValidationDiagnosticsExposeRangeResourcesAndFastPath) {
|
||||||
|
RetainedUnderlayRuntimeState state;
|
||||||
|
ASSERT_TRUE(state.setContinuousLayerRange("weather", "particle"));
|
||||||
|
const auto config = state.continuousLayerRangeConfig();
|
||||||
|
state.recordRangeResolution(
|
||||||
|
{.configured = true,
|
||||||
|
.valid = true,
|
||||||
|
.startLayerId = "weather",
|
||||||
|
.endLayerId = "particle",
|
||||||
|
.startIndex = 2,
|
||||||
|
.endIndex = 3,
|
||||||
|
.configRevision = config.revision,
|
||||||
|
.reason = "explicit-range"},
|
||||||
|
true,
|
||||||
|
true);
|
||||||
|
state.recordRangeCacheState(false, RetainedRangeCacheState::Reuse);
|
||||||
|
state.recordRangeInvalidationReason(false, RetainedUnderlayReason::Viewport);
|
||||||
|
state.recordRangeTextureCreate(false);
|
||||||
|
state.recordRangeCompositeCreate(false);
|
||||||
|
state.recordRangeResourceRelease(false);
|
||||||
|
state.recordFastPathEligibility(true);
|
||||||
|
state.recordFastPathDecision(true, ParticleFastPathMissReason::None);
|
||||||
|
state.recordFullCpuFrame();
|
||||||
|
|
||||||
|
const auto snapshot = state.snapshot();
|
||||||
|
EXPECT_TRUE(snapshot.rangeValid);
|
||||||
|
EXPECT_EQ(snapshot.continuousBegin, 2);
|
||||||
|
EXPECT_EQ(snapshot.continuousEndExclusive, 4);
|
||||||
|
EXPECT_EQ(snapshot.bottomCacheState, "reuse");
|
||||||
|
EXPECT_EQ(snapshot.bottomLastInvalidationReason, "viewport");
|
||||||
|
EXPECT_EQ(snapshot.bottomTextureCreate, 1u);
|
||||||
|
EXPECT_EQ(snapshot.bottomCompositeCreate, 1u);
|
||||||
|
EXPECT_EQ(snapshot.bottomResourceRelease, 1u);
|
||||||
|
EXPECT_TRUE(snapshot.fastPathEligible);
|
||||||
|
EXPECT_FALSE(snapshot.fastPathActive);
|
||||||
|
EXPECT_EQ(snapshot.fastPathHit, 1u);
|
||||||
|
EXPECT_EQ(snapshot.fastPathMiss, 0u);
|
||||||
|
EXPECT_EQ(snapshot.fullCpuFrame, 1u);
|
||||||
|
}
|
||||||
|
|
||||||
TEST(RetainedUnderlayRevision, MonotonicAcrossCameraViewportStyleAndSourceChanges) {
|
TEST(RetainedUnderlayRevision, MonotonicAcrossCameraViewportStyleAndSourceChanges) {
|
||||||
RetainedUnderlayRevisionTracker tracker;
|
RetainedUnderlayRevisionTracker tracker;
|
||||||
RetainedUnderlayCache cache;
|
RetainedUnderlayCache cache;
|
||||||
@@ -556,6 +597,10 @@ TEST(ParticleFastPath, PendingStillAndUnsupportedPathsReject) {
|
|||||||
input = fastPathInput();
|
input = fastPathInput();
|
||||||
input.supportedScene = false;
|
input.supportedScene = false;
|
||||||
EXPECT_EQ(evaluateParticleFastPath(input).reason, ParticleFastPathMissReason::UnsupportedScene);
|
EXPECT_EQ(evaluateParticleFastPath(input).reason, ParticleFastPathMissReason::UnsupportedScene);
|
||||||
|
|
||||||
|
input = fastPathInput();
|
||||||
|
input.unsupportedContinuousLayer = true;
|
||||||
|
EXPECT_EQ(evaluateParticleFastPath(input).reason, ParticleFastPathMissReason::UnsupportedContinuousLayer);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(ParticleFastPath, FullFrameCanRestabilizeCandidate) {
|
TEST(ParticleFastPath, FullFrameCanRestabilizeCandidate) {
|
||||||
|
|||||||
Reference in New Issue
Block a user