fix: close STEP-085 V4 renderer efficiency
Some checks failed
validate-scripts / validate-scripts (push) Has been cancelled

This commit is contained in:
tei
2026-09-19 22:16:36 +09:00
parent bc6b8dd84b
commit 70f112ea27
19 changed files with 501 additions and 111 deletions

View File

@@ -7,6 +7,8 @@ import android.os.Handler;
import android.os.Looper;
import java.util.List;
import java.util.HashSet;
import java.util.Set;
import org.json.JSONException;
import org.json.JSONObject;
@@ -59,6 +61,12 @@ public final class WeatherRuntime {
private boolean particleVisible = true;
private PlaybackState playbackState = PlaybackState.PAUSE;
private TargetFps targetFps = TargetFps.AUTO;
// V4 owns its window in Core, so it never transitions the legacy V3 state
// to READY. This only owns Android's next-frame wake, not a second timeline.
// This is a Host-command bookkeeping hint for scheduling only. Core still
// decides whether a resolved V4 window may actually advance simulation.
@Nullable private String v4ParticleBindingFieldKey;
private final Set<String> submittedEncodedFieldKeys = new HashSet<>();
private boolean disposed;
private Handler cadenceHandler;
private final Runnable cadenceWake = new Runnable() {
@@ -91,7 +99,9 @@ public final class WeatherRuntime {
if (!WeatherRuntimeV4Guards.hasValidEncodedIdUtf8Length(fieldKey) || !WeatherRuntimeV4Guards.hasValidEncodedIdUtf8Length(fieldId) || !WeatherRuntimeV4Guards.hasValidEncodedContractUtf8Length(contractJson) || !hasValidEncodedContractProfileId(contractJson) || generation <= 0 || dataVersion < 0 || !WeatherRuntimeV4Guards.hasValidEncodedQbin(qbin)) throw new IllegalArgumentException("invalid encoded field argument");
int code = map.submitRasterArraySourceEncodedField(config.sourceId, fieldKey, fieldId, generation, dataVersion, contractJson, qbin);
if (code == 0) throw new IllegalStateException("SOURCE_MISSING");
return EncodedFieldSubmitResult.fromCode(code);
EncodedFieldSubmitResult result = EncodedFieldSubmitResult.fromCode(code);
if (result.code > 0) { submittedEncodedFieldKeys.add(fieldKey); cancelCadenceWake(); scheduleCadenceWake(); }
return result;
}
private static boolean hasValidEncodedContractProfileId(String contractJson) {
if (contractJson == null) return false;
@@ -101,15 +111,15 @@ public final class WeatherRuntime {
return false;
}
}
public CommandResult clearEncodedField(@NonNull String fieldKey) { requireAttached(); return !WeatherRuntimeV4Guards.hasValidEncodedIdUtf8Length(fieldKey) ? CommandResult.REJECTED : encodedCommand(map.clearRasterArraySourceEncodedField(config.sourceId, fieldKey)); }
public CommandResult clearAllEncodedFields() { requireAttached(); return encodedCommand(map.clearAllRasterArraySourceEncodedFields(config.sourceId)); }
public CommandResult clearEncodedField(@NonNull String fieldKey) { requireAttached(); if (!WeatherRuntimeV4Guards.hasValidEncodedIdUtf8Length(fieldKey)) return CommandResult.REJECTED; CommandResult result = encodedCommand(map.clearRasterArraySourceEncodedField(config.sourceId, fieldKey)); if (result == CommandResult.ACCEPTED) { submittedEncodedFieldKeys.remove(fieldKey); cancelCadenceWake(); scheduleCadenceWake(); } return result; }
public CommandResult clearAllEncodedFields() { requireAttached(); CommandResult result = encodedCommand(map.clearAllRasterArraySourceEncodedFields(config.sourceId)); if (result == CommandResult.ACCEPTED) { submittedEncodedFieldKeys.clear(); cancelCadenceWake(); scheduleCadenceWake(); } return result; }
/** V4 binding intent; unit and all mode selectors reach Core unchanged. */
public CommandResult setEncodedColorBinding(@NonNull String fieldKey, int semanticID, int groupID, int valueClass, int expectedUnitID) {
requireAttached(); return !WeatherRuntimeV4Guards.hasValidEncodedIdUtf8Length(fieldKey) ? CommandResult.REJECTED : encodedCommand(map.setRasterArraySourceEncodedColorBinding(config.sourceId, fieldKey, semanticID, groupID, valueClass, expectedUnitID));
}
/** ABI reserves all selector slots: inactive slots must be exactly (0, 0). */
public CommandResult setEncodedParticleBinding(@NonNull String fieldKey, int mode, int uSemanticID, int uGroupID, int vSemanticID, int vGroupID, int directionSemanticID, int directionGroupID, int expectedUnitID) {
requireAttached(); return !WeatherRuntimeV4Guards.hasValidEncodedIdUtf8Length(fieldKey) ? CommandResult.REJECTED : encodedCommand(map.setRasterArraySourceEncodedParticleBinding(config.sourceId, fieldKey, mode, uSemanticID, uGroupID, vSemanticID, vGroupID, directionSemanticID, directionGroupID, expectedUnitID));
requireAttached(); if (!WeatherRuntimeV4Guards.hasValidEncodedIdUtf8Length(fieldKey)) return CommandResult.REJECTED; CommandResult result = encodedCommand(map.setRasterArraySourceEncodedParticleBinding(config.sourceId, fieldKey, mode, uSemanticID, uGroupID, vSemanticID, vGroupID, directionSemanticID, directionGroupID, expectedUnitID)); if (result == CommandResult.ACCEPTED) { v4ParticleBindingFieldKey = fieldKey; cancelCadenceWake(); scheduleCadenceWake(); } return result;
}
public CommandResult setEncodedForecastTime(long timestamp) { requireAttached(); return timestamp < 0 ? CommandResult.REJECTED : encodedCommand(map.setRasterArraySourceEncodedForecastTime(config.sourceId, timestamp)); }
/** State and speed intentionally remain independent V4 Core commands. */
@@ -153,6 +163,8 @@ public final class WeatherRuntime {
boolean color = map.setStyleLayerVisibility(config.weatherColorLayerId, weatherColorVisible);
boolean particle = map.setStyleLayerVisibility(config.particleLayerId, particleVisible);
state = stateAfterEnable(state, color && particle);
cancelCadenceWake();
scheduleCadenceWake();
return result(color && particle);
}
public CommandResult setWeatherColorVisible(boolean visible) { if (disposed) return CommandResult.REJECTED; weatherColorVisible = visible; CommandResult result = result(map.setStyleLayerVisibility(config.weatherColorLayerId, visible && state != State.DISABLED)); cancelCadenceWake(); scheduleCadenceWake(); return result; }
@@ -211,7 +223,10 @@ public final class WeatherRuntime {
private static CommandResult encodedCommand(int code) { if (code == 0) throw new IllegalStateException("SOURCE_MISSING"); return code > 0 ? CommandResult.ACCEPTED : CommandResult.REJECTED; }
public enum FieldValueSource { SCALAR(0f), VECTOR_MAGNITUDE(1f); final float code; FieldValueSource(float code) { this.code = code; } }
private boolean shouldWakeWeather() {
return !disposed && targetFps != TargetFps.AUTO && state == State.READY && (particleVisible || (weatherColorVisible && playbackState == PlaybackState.PLAY));
if (disposed || state == State.DISABLED || targetFps == TargetFps.AUTO) return false;
final boolean v4ParticleFieldReady = v4ParticleBindingFieldKey != null && submittedEncodedFieldKeys.contains(v4ParticleBindingFieldKey);
return (v4ParticleFieldReady && particleVisible) ||
(state == State.READY && (particleVisible || (weatherColorVisible && playbackState == PlaybackState.PLAY)));
}
private void scheduleCadenceWake() {
if (!shouldWakeWeather()) return;