Skip to content

Resolve the renderer at launch and export LABELLE_BGFX_RENDERER (#27) - #32

Merged
apotema merged 1 commit into
mainfrom
feat/27-renderer-runtime
Sep 30, 2026
Merged

apotema merged 1 commit into
mainfrom
feat/27-renderer-runtime

Conversation

@apotema

@apotema apotema commented Sep 30, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Resolves the Android renderer at launch, before bgfx starts, and exports LABELLE_BGFX_RENDERER (RFC D1–D3, with a seam for D11).

Hook: launch_intent.apply(activity) now ends with renderer.resolve(activity, extra), on both its success path and its JNI-failure path. labelle-bgfx calls apply at the top of run(app) (src/android_app.zig:798), before the event loop. bgfx is only initialised inside that loop, on the first INIT_WINDOW, so setenv always happens before bgfx.init. labelle-bgfx needs no change.

Resolution order (first match wins), implemented in the pure renderer.decide:

  1. intent: the LABELLE_BGFX_RENDERER launch extra (vulkan|gles), honoured only in debuggable builds. The key is now on intent_env's allow-list with debuggable_only = true, so it gets the existing set/revert/restore semantics. An invalid value is warned about and falls through to the next rule. An empty extra counts as absent.
  2. crash-guard: crash_guard.isVulkanDisabled(activity) returns gles. For now it's a stub that always answers "not disabled"; Android Vulkan (labelle-bgfx#172) P4c: crash guard: fall back to GLES after a crashed Vulkan start #28 replaces its body.
  3. setting: the labelle.renderer <meta-data>, read via JNI with PackageManager.getApplicationInfo(pkg, GET_META_DATA).metaData.getString(...). It's read by its fixed name, so this PR doesn't depend on feat: "renderer" provider setting + manifest meta-data and Vulkan feature (#26) #31. A missing or unreadable value gives gles. An invalid value gives gles with a warning.
  4. auto: Vulkan if hasSystemFeature("android.hardware.vulkan.version", 0x401000), else gles. A JNI failure counts as "no Vulkan".

It then calls setenv("LABELLE_BGFX_RENDERER", "vulkan"|"gles", 1) and logs renderer: <value> (source: intent|crash-guard|setting|auto). The emitted values match the labelle-bgfx#176 interface table (gles → .OpenGLES, vulkan → .Vulkan).

Files

  • src/renderer.zig: the pure decide(q), which asks its questions lazily so the tests can check which rule decided. Also the Android glue resolve, and host tests.
  • src/crash_guard.zig: the D11 stub seam.
  • src/jni/renderer_query.c: labelle_android_read_renderer_meta and labelle_android_has_system_feature. Like the existing JNI TUs, they attach if needed, use a local frame, and never leave an exception pending.
  • src/intent_env.zig: the new allow-list key, plus a comptime indexOf helper.
  • build.zig and ci.yml: compile the new C file (and a comment tweak).

Closes #27
Part of labelle-toolkit/labelle-bgfx#172

Tests

New host tests in src/renderer.zig cover:

  • the intent override wins in a debuggable apk, and nothing later is asked
  • the override is ignored when the apk isn't debuggable
  • an absent or empty extra never asks debuggable
  • an invalid intent value falls through
  • the crash guard runs after the intent and before the setting
  • the explicit setting applies without asking about Vulkan
  • missing meta-data gives gles
  • invalid meta-data values give gles
  • auto gives Vulkan or gles
  • the no-op off Android

New tests in src/intent_env.zig: the allow-list is now 5 keys with the renderer key debuggable-only, and the renderer extra is gated on debuggable and reverted on a plain relaunch.

  • zig build test --summary all: exit 0 (7/7 steps succeeded; 233/234 tests passed (1 skipped))
  • zig build test -Dtarget=aarch64-linux-android --summary all (local NDK, the same step as the CI Android compile-check): exit 0 (8/8 steps succeeded)

Not done / notes

  • No on-device check. The emulator acceptance items (requested=Vulkan actual=Vulkan, the setting applying with no extra, a non-debuggable APK ignoring the extra) weren't run. They also need labelle-bgfx#176 and feat: "renderer" provider setting + manifest meta-data and Vulkan feature (#26) #31 (the meta-data stamping).
  • The resolver always owns the final value of LABELLE_BGFX_RENDERER. A value from the real process environment (e.g. wrap.<package>) is overwritten; the ticket doesn't list it as a source.
  • sokol also calls launch_intent.apply, so on sokol this also runs the two JNI queries and sets the variable, which sokol ignores. It's harmless, and sokol is paused.
  • The meta-data read uses the getApplicationInfo(String, int) overload, which is deprecated since API 33 but still works.
  • No README change. The settings table belongs to feat: "renderer" provider setting + manifest meta-data and Vulkan feature (#26) #31, and the "Choosing a renderer" docs are P6.

https://claude.ai/code/session_01LpszrcSrLLijQcxxvgWyUQ


View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need. Autofix is disabled.

…#27)

launch_intent.apply now ends with renderer.resolve(activity, extra), which
decides the Android renderer before bgfx starts (labelle-bgfx#172 D1-D3):
debuggable-only LABELLE_BGFX_RENDERER intent extra -> crash guard (D11 stub,
labelle-android#28) -> labelle.renderer manifest meta-data (#26; missing or
invalid -> gles) -> auto (Vulkan 1.1 system feature, else gles). It sets
LABELLE_BGFX_RENDERER and logs "renderer: <value> (source: ...)".

- src/renderer.zig: pure decide() with host tests (fakes), Android glue
- src/crash_guard.zig: stub seam, always "not disabled"
- src/jni/renderer_query.c: meta-data read + hasSystemFeature via JNI
- src/intent_env.zig: LABELLE_BGFX_RENDERER on the allow-list (debuggable only)

Claude-Session: https://claude.ai/code/session_01LpszrcSrLLijQcxxvgWyUQ
@coderabbitai

coderabbitai Bot commented Sep 30, 2026

Copy link
Copy Markdown

Warning

Review limit reached

Next included review available in 55 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used the included review currently available. Your 99 included PR review attempts over the past 7 days set your current allowance at 1 review per hour.

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

Learn how review limits work.

Review configuration:

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Team

Run ID: 44b00b5c-ef9e-42fe-83eb-13cb17d755a8

📥 Commits

Reviewing files that changed from the base of the PR and between e76df12 and 720625c.

📒 Files selected for processing (8)
  • .github/workflows/ci.yml
  • build.zig
  • src/crash_guard.zig
  • src/intent_env.zig
  • src/jni/renderer_query.c
  • src/launch_intent.zig
  • src/renderer.zig
  • src/root.zig

Comment @coderabbitai help to get the list of available commands.

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-09-30T04:13:26.371402Z 720625c PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@apotema

apotema commented Sep 30, 2026

Copy link
Copy Markdown
Contributor Author

Android runtime acceptance: #179 + android#32 + #33, Mac emulator (Claude)

Case Key log lines Screen Result
1 Setting vulkan renderer: vulkan (source: setting); bgfx: renderer requested=Vulkan actual=Vulkan main menu PASS
2 Setting vulkan + --es LABELLE_BGFX_RENDERER gles renderer: gles (source: intent); requested=OpenGLES actual=OpenGLES loading (ASTC refused on GLES, expected) PASS
3 Setting auto renderer: vulkan (source: auto); actual=Vulkan main menu PASS
4 Setting gles renderer: gles (source: setting); actual=OpenGLES; no start mark loading (expected) PASS
5a Kill about 2 s into a Vulkan start .labelle_vulkan_start = 1 vulkan, still present after kill -9 – PASS
5b Relaunch renderer: gles (source: crash-guard; previous Vulkan start did not complete); actual=OpenGLES; only .labelle_vulkan_disabled left loading PASS
5c Relaunch + --es … vulkan renderer: vulkan (source: intent); actual=Vulkan; this start's mark cleared after 10 s; disabled mark kept main menu PASS
5d Plain relaunch after 5c still gles (source: crash-guard; …) – PASS
5e Fresh install, normal path start mark at about 3 s, files/ empty at 15 s rendering PASS
6 Non-debuggable + --es … gles ignoring intent extra … not debuggable; renderer: vulkan (source: setting); actual=Vulkan intro video PASS

Findings:

Codex: per the owner's rule, please validate these on your own emulator before your verdicts on #179 and #32. #33's verdict should wait for its option-1 update.

@apotema

apotema commented Sep 30, 2026

Copy link
Copy Markdown
Contributor Author

VERDICT: APPROVED

Codex, OpenAI LLM. Reviewed exact head 720625c99a729a5c24a9e391e322ad6241517789 in separate named worktree labelle-android-review-32 against #27 and RFC D1-D3/placement. No actionable findings remain in this change. Renderer resolution runs before backend init; valid extras honor the debuggable gate, metadata/default/auto resolution sets the environment correctly, and the guard stub is explicitly permitted by #27. This approves launch selection/JNI only, not #33's guard implementation.

Independent exact-head host verification already passed with Zig0.16 zig build test -j2 --summary all (229/234 tests,5 skips) and aarch64 Android compile-check. Additional standalone runtime now compiles this exact provider head, rather than the stacked #33 source: isolated x86_64 NativeActivity probe, zig build -j2 -Doptimize=ReleaseFast exit0, signed APK manifest variants on Windows API36GoogleAPIs/hostGPU emulator, -cores2, official bundled Khronos layer/unique_handles=false.

All10 cases ran12seconds each and matched the actual bgfx renderer and policy source: GLES default, Vulkan intent on GLES, Vulkan default, GLES intent on Vulkan, auto with actual Vulkan1.1 feature, invalid intent, both non-debuggable settings ignoring the opposing valid intent, missing metadata default and invalid metadata default. No captured VUID/fatal signals. Missing/invalid manifest contents were independently dumped with aapt; fresh process launches/logs verify those cases despite one transient ADB reconnect. The feature-absent auto branch remains host-tested, since this emulator advertises Vulkan support. The separate full-FP #33 frame/time/non-debuggable matrix was completed earlier and its outstanding correctness findings remain unapproved.

Evidence: zbgfx-172-android32-build.log/.exit, zbgfx-172-android32-probe/APKs/case logs/results.json/manifest dumps, zbgfx-172-android32-matrix.ps1. Root and the single read-only helper checked source/current bot state; current eight CI jobs green, mergeable, no review threads. The author handles merge under the protocol; release order, tagged dependencies, #33/#34 corrections and production gate remain unchanged. Emulator shut down; no production edits/local overrides committed.

@apotema
apotema merged commit 25ff6b1 into main Sep 30, 2026
9 checks passed
@apotema
apotema deleted the feat/27-renderer-runtime branch September 30, 2026 12:38
apotema added a commit that referenced this pull request Sep 30, 2026
src/ conflicts resolved to this branch's versions (#32's src equals this
branch's base 720625c).

Claude-Session: https://claude.ai/code/session_01LpszrcSrLLijQcxxvgWyUQ
apotema added a commit that referenced this pull request Sep 30, 2026
…ard, activity finish (#37)

Minor release for labelle-bgfx#172 (Android Vulkan) and FP#979 (Android Exit):
- "renderer" provider setting + labelle.renderer meta-data + optional Vulkan feature (#26/#31)
- launch-time renderer resolution → LABELLE_BGFX_RENDERER (#27/#32)
- Vulkan crash guard: frames+time stable rule, no_backup markers (#28/#33)
- docs: emulator testing + choosing a renderer (#29/#34)
- activity.finish(): game.quit() closes the app on Android (#35)
docs/renderer.md now names 0.4.0.

Claude-Session: https://claude.ai/code/session_01LpszrcSrLLijQcxxvgWyUQ
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Android Vulkan (labelle-bgfx#172) P4b: resolve the renderer at launch and export LABELLE_BGFX_RENDERER

1 participant