This commit is contained in:
firestar5683
2026-04-12 20:51:49 -05:00
parent 541c4d4735
commit 7568ab4e3d
46 changed files with 197 additions and 83 deletions
Binary file not shown.
+1 -1
View File
@@ -192,7 +192,7 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
{"CEStatus", {CLEAR_ON_OFFROAD_TRANSITION, INT, "0", "0"}},
{"CEStopLights", {PERSISTENT, BOOL, "1", "0", 1}},
{"CEStoppedLead", {PERSISTENT, BOOL, "1", "0", 1}},
{"ClusterOffset", {PERSISTENT, FLOAT, "1.015", "1.015", 2}},
{"ClusterOffset", {PERSISTENT, FLOAT, "1.0", "1.0", 2}},
{"ColorScheme", {PERSISTENT, STRING, "frog", "stock", 0}},
{"ColorToDownload", {CLEAR_ON_MANAGER_START, STRING, "", ""}},
{"BootLogoToDownload", {CLEAR_ON_MANAGER_START, STRING, "", ""}},
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+1 -1
View File
@@ -1,2 +1,2 @@
extern const uint8_t gitversion[19];
const uint8_t gitversion[19] = "DEV-abd64084-DEBUG";
const uint8_t gitversion[19] = "DEV-541c4d47-DEBUG";
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+1 -1
View File
@@ -1 +1 @@
DEV-abd64084-DEBUG
DEV-541c4d47-DEBUG
Binary file not shown.
+64 -64
View File
@@ -37,63 +37,61 @@ void main() {
}
"""
# Choose fragment shader based on platform capabilities
if TICI:
FRAME_FRAGMENT_SHADER = """
#version 300 es
#extension GL_OES_EGL_image_external_essl3 : enable
precision mediump float;
in vec2 fragTexCoord;
uniform samplerExternalOES texture0;
out vec4 fragColor;
uniform int engaged;
uniform int enhance_driver;
FRAME_FRAGMENT_SHADER_EXTERNAL = """
#version 300 es
#extension GL_OES_EGL_image_external_essl3 : enable
precision mediump float;
in vec2 fragTexCoord;
uniform samplerExternalOES texture0;
out vec4 fragColor;
uniform int engaged;
uniform int enhance_driver;
void main() {
vec4 color = texture(texture0, fragTexCoord);
// Keep the onroad camera feed full-color in every driving state.
if (engaged == 1) {
color.rgb = color.rgb;
}
if (enhance_driver == 1) {
float brightness = 1.1;
color.rgb = color.rgb + 0.15;
color.rgb = clamp((color.rgb - 0.5) * (brightness * 0.8) + 0.5, 0.0, 1.0);
color.rgb = color.rgb * color.rgb * (3.0 - 2.0 * color.rgb);
color.rgb = pow(color.rgb, vec3(0.8));
}
fragColor = vec4(color.rgb, color.a);
void main() {
vec4 color = texture(texture0, fragTexCoord);
// Keep the onroad camera feed full-color in every driving state.
if (engaged == 1) {
color.rgb = color.rgb;
}
"""
else:
FRAME_FRAGMENT_SHADER = VERSION + """
in vec2 fragTexCoord;
uniform sampler2D texture0;
uniform sampler2D texture1;
out vec4 fragColor;
uniform int engaged;
uniform int enhance_driver;
if (enhance_driver == 1) {
float brightness = 1.1;
color.rgb = color.rgb + 0.15;
color.rgb = clamp((color.rgb - 0.5) * (brightness * 0.8) + 0.5, 0.0, 1.0);
color.rgb = color.rgb * color.rgb * (3.0 - 2.0 * color.rgb);
color.rgb = pow(color.rgb, vec3(0.8));
}
fragColor = vec4(color.rgb, color.a);
}
"""
void main() {
float y = texture(texture0, fragTexCoord).r;
vec2 uv = texture(texture1, fragTexCoord).ra - 0.5;
vec3 rgb = vec3(y + 1.402*uv.y, y - 0.344*uv.x - 0.714*uv.y, y + 1.772*uv.x);
// Keep the onroad camera feed full-color in every driving state.
if (engaged == 1) {
rgb = rgb;
}
// TODO: the images out of camerad need some more correction and
// the ui should apply a gamma curve for the device display
if (enhance_driver == 1) {
float brightness = 1.1;
rgb = rgb + 0.15;
rgb = clamp((rgb - 0.5) * (brightness * 0.8) + 0.5, 0.0, 1.0);
rgb = rgb * rgb * (3.0 - 2.0 * rgb);
rgb = pow(rgb, vec3(0.8));
}
fragColor = vec4(rgb, 1.0);
FRAME_FRAGMENT_SHADER_YUV = VERSION + """
in vec2 fragTexCoord;
uniform sampler2D texture0;
uniform sampler2D texture1;
out vec4 fragColor;
uniform int engaged;
uniform int enhance_driver;
void main() {
float y = texture(texture0, fragTexCoord).r;
vec2 uv = texture(texture1, fragTexCoord).ra - 0.5;
vec3 rgb = vec3(y + 1.402*uv.y, y - 0.344*uv.x - 0.714*uv.y, y + 1.772*uv.x);
// Keep the onroad camera feed full-color in every driving state.
if (engaged == 1) {
rgb = rgb;
}
"""
// TODO: the images out of camerad need some more correction and
// the ui should apply a gamma curve for the device display
if (enhance_driver == 1) {
float brightness = 1.1;
rgb = rgb + 0.15;
rgb = clamp((rgb - 0.5) * (brightness * 0.8) + 0.5, 0.0, 1.0);
rgb = rgb * rgb * (3.0 - 2.0 * rgb);
rgb = pow(rgb, vec3(0.8));
}
fragColor = vec4(rgb, 1.0);
}
"""
class CameraView(Widget):
@@ -112,8 +110,13 @@ class CameraView(Widget):
self._texture_needs_update = True
self.last_connection_attempt: float = 0.0
self.shader = rl.load_shader_from_memory(VERTEX_SHADER, FRAME_FRAGMENT_SHADER)
self._texture1_loc: int = rl.get_shader_location(self.shader, "texture1") if not TICI else -1
self._use_egl = TICI and init_egl()
if TICI and not self._use_egl:
cloudlog.error("CameraView EGL init failed, falling back to texture rendering")
frame_shader = FRAME_FRAGMENT_SHADER_EXTERNAL if self._use_egl else FRAME_FRAGMENT_SHADER_YUV
self.shader = rl.load_shader_from_memory(VERTEX_SHADER, frame_shader)
self._texture1_loc: int = rl.get_shader_location(self.shader, "texture1") if not self._use_egl else -1
self._engaged_loc = rl.get_shader_location(self.shader, "engaged")
self._engaged_val = rl.ffi.new("int[1]", [1])
self._enhance_driver_loc = rl.get_shader_location(self.shader, "enhance_driver")
@@ -129,11 +132,8 @@ class CameraView(Widget):
self._placeholder_color: rl.Color | None = None
# Initialize EGL for zero-copy rendering on TICI
if TICI:
if not init_egl():
raise RuntimeError("Failed to initialize EGL")
# Initialize EGL for zero-copy rendering when available.
if self._use_egl:
# Create a 1x1 pixel placeholder texture for EGL image binding
temp_image = rl.gen_image_color(1, 1, rl.BLACK)
self.egl_texture = rl.load_texture_from_image(temp_image)
@@ -181,7 +181,7 @@ class CameraView(Widget):
self._clear_textures()
# Clean up EGL texture
if TICI and self.egl_texture:
if self.egl_texture:
rl.unload_texture(self.egl_texture)
self.egl_texture = None
@@ -256,7 +256,7 @@ class CameraView(Widget):
dst_rect = rl.Rectangle(x_offset, y_offset, scale_x, scale_y)
# Render with appropriate method
if TICI:
if self._use_egl:
self._render_egl(src_rect, dst_rect)
else:
self._render_textures(src_rect, dst_rect)
@@ -382,7 +382,7 @@ class CameraView(Widget):
def _initialize_textures(self):
self._clear_textures()
if not TICI:
if not self._use_egl:
self.texture_y = rl.load_texture_from_image(rl.Image(None, int(self.client.stride),
int(self.client.height), 1, rl.PixelFormat.PIXELFORMAT_UNCOMPRESSED_GRAYSCALE))
self.texture_uv = rl.load_texture_from_image(rl.Image(None, int(self.client.stride // 2),
@@ -398,7 +398,7 @@ class CameraView(Widget):
self.texture_uv = None
# Clean up EGL resources
if TICI:
if self._use_egl:
for data in self.egl_images.values():
destroy_egl_image(data)
self.egl_images = {}
BIN
View File
Binary file not shown.
+38 -16
View File
@@ -3,7 +3,9 @@ import os
from openpilot.system.hardware import TICI
from openpilot.common.realtime import config_realtime_process, set_core_affinity
from openpilot.common.watchdog import kick_watchdog
from openpilot.system.ui.lib.application import gui_app
from openpilot.selfdrive.ui.stall_monitor import UIStallMonitor
from openpilot.selfdrive.ui.ui_state import ui_state
BIG_UI = gui_app.big_ui()
@@ -13,23 +15,43 @@ def main():
cores = {5, }
config_realtime_process(0, 51)
gui_app.init_window("UI")
if BIG_UI:
from openpilot.selfdrive.ui.layouts.main import MainLayout
MainLayout()
else:
from openpilot.selfdrive.ui.mici.layouts.main import MiciMainLayout
MiciMainLayout()
stall_monitor = UIStallMonitor("raylib_ui")
stall_monitor.progress("ui.before_init_window")
stall_monitor.start()
for should_render in gui_app.render():
ui_state.update()
if should_render:
# reaffine after power save offlines our core
if TICI and os.sched_getaffinity(0) != cores:
try:
set_core_affinity(list(cores))
except OSError:
pass
try:
gui_app.init_window("UI")
stall_monitor.progress("ui.after_init_window")
gui_app.set_progress_hook(stall_monitor.progress)
kick_watchdog()
stall_monitor.progress("ui.before_layout_init")
if BIG_UI:
from openpilot.selfdrive.ui.layouts.main import MainLayout
MainLayout()
else:
from openpilot.selfdrive.ui.mici.layouts.main import MiciMainLayout
MiciMainLayout()
stall_monitor.progress("ui.after_layout_init")
kick_watchdog()
stall_monitor.progress("ui.loop_ready")
for should_render in gui_app.render():
stall_monitor.progress("ui.loop_iteration")
kick_watchdog()
stall_monitor.progress("ui.after_watchdog")
ui_state.update()
stall_monitor.progress("ui.after_state_update")
if should_render:
# reaffine after power save offlines our core
if TICI and os.sched_getaffinity(0) != cores:
try:
set_core_affinity(list(cores))
except OSError:
pass
stall_monitor.progress("ui.loop_idle")
finally:
gui_app.set_progress_hook(None)
stall_monitor.stop()
if __name__ == "__main__":
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+33
View File
@@ -35,6 +35,7 @@ from openpilot.starpilot.common.starpilot_variables import (
LEGACY_BOLT_FP_MIGRATION_FLAG = Path("/data") / "legacy_bolt_fp_migration_v1"
STARPILOT_DEFAULTS_PARITY_MIGRATION_FLAG = Path("/data") / "starpilot_defaults_parity_v1"
STARPILOT_HUMANLIKE_DISABLE_MIGRATION_FLAG = Path("/data") / "starpilot_humanlike_disable_v1"
STARPILOT_CLUSTER_OFFSET_MIGRATION_FLAG = Path("/data") / "starpilot_cluster_offset_v1"
STARPILOT_PARAM_RENAME_MIGRATION_FLAG = Path("/data") / "starpilot_param_rename_v1"
STARPILOT_PARAM_CANONICALIZATION_MIGRATION_FLAG = Path("/data") / "starpilot_param_canonicalization_v1"
STARPILOT_PC_ROOT_MIGRATION_FLAG = Path("/data") / "starpilot_pc_root_v1"
@@ -401,6 +402,37 @@ def migrate_disable_humanlike_defaults(params: Params, params_cache: Params) ->
cloudlog.exception(f"Failed to write migration flag: {STARPILOT_HUMANLIKE_DISABLE_MIGRATION_FLAG}")
def migrate_cluster_offset_default(params: Params, params_cache: Params) -> None:
if STARPILOT_CLUSTER_OFFSET_MIGRATION_FLAG.exists():
return
legacy_default_detected = False
for params_obj in (params, params_cache):
raw_value = _read_raw_param_bytes(params_obj, "ClusterOffset")
if not raw_value:
continue
try:
parsed_value = float(raw_value.decode("utf-8", errors="strict").strip())
except Exception:
continue
if abs(parsed_value - 1.015) < 1e-6:
legacy_default_detected = True
break
if legacy_default_detected:
params.put_float("ClusterOffset", 1.0)
params_cache.put_float("ClusterOffset", 1.0)
cloudlog.warning("Applied one-time ClusterOffset migration from 1.015 to 1.0")
try:
STARPILOT_CLUSTER_OFFSET_MIGRATION_FLAG.parent.mkdir(parents=True, exist_ok=True)
STARPILOT_CLUSTER_OFFSET_MIGRATION_FLAG.write_text(f"{datetime.datetime.now(datetime.UTC).isoformat()}\n")
except Exception:
cloudlog.exception(f"Failed to write migration flag: {STARPILOT_CLUSTER_OFFSET_MIGRATION_FLAG}")
def _read_raw_param_bytes(params: Params, key: str | bytes):
try:
path = params.get_param_path(key)
@@ -568,6 +600,7 @@ def manager_init() -> None:
migrate_param_type_canonicalization(params)
migrate_starpilot_default_parity(params, params_cache)
migrate_disable_humanlike_defaults(params, params_cache)
migrate_cluster_offset_default(params, params_cache)
# set unset params to their default value
for k in params.all_keys():
+26
View File
@@ -191,6 +191,32 @@ class TestManager:
assert not params_cache.get_bool("HumanFollowing")
assert not params_cache.get_bool("HumanLaneChanges")
def test_migrate_cluster_offset_default_resets_legacy_default_only(self, tmp_path, monkeypatch):
monkeypatch.setattr(manager, "STARPILOT_CLUSTER_OFFSET_MIGRATION_FLAG", tmp_path / "starpilot_cluster_offset_v1")
params = FileBackedFakeParams(tmp_path / "params", {
"ClusterOffset": 1.015,
})
params_cache = FileBackedFakeParams(tmp_path / "cache", {})
manager.migrate_cluster_offset_default(params, params_cache)
assert params.get("ClusterOffset") == "1.0"
assert params_cache.get("ClusterOffset") == "1.0"
def test_migrate_cluster_offset_default_preserves_custom_values(self, tmp_path, monkeypatch):
monkeypatch.setattr(manager, "STARPILOT_CLUSTER_OFFSET_MIGRATION_FLAG", tmp_path / "starpilot_cluster_offset_v1")
params = FileBackedFakeParams(tmp_path / "params", {
"ClusterOffset": 1.02,
})
params_cache = FileBackedFakeParams(tmp_path / "cache", {})
manager.migrate_cluster_offset_default(params, params_cache)
assert params.get("ClusterOffset") == "1.02"
assert params_cache.get("ClusterOffset") is None
@pytest.mark.skip("this test is flaky the way it's currently written, should be moved to test_onroad")
def test_clean_exit(self, subtests):
"""
+33
View File
@@ -218,6 +218,7 @@ class GuiApplication:
self._ffmpeg_queue: queue.Queue | None = None
self._ffmpeg_thread: threading.Thread | None = None
self._ffmpeg_stop_event: threading.Event | None = None
self._progress_hook: Callable[[str], None] | None = None
self._textures: dict[str, rl.Texture] = {}
self._target_fps: int = _DEFAULT_FPS
self._last_fps_log_time: float = time.monotonic()
@@ -447,6 +448,13 @@ class GuiApplication:
if tick_function in self._nav_stack_ticks:
self._nav_stack_ticks.remove(tick_function)
def set_progress_hook(self, hook: Callable[[str], None] | None) -> None:
self._progress_hook = hook
def _mark_progress(self, phase: str) -> None:
if self._progress_hook is not None:
self._progress_hook(phase)
def set_should_render(self, should_render: bool):
self._should_render = should_render
@@ -585,6 +593,7 @@ class GuiApplication:
self._render_profiler.enable()
while not (self._window_close_requested or rl.window_should_close()):
self._mark_progress("gui_app.loop_start")
if PC:
# Thread is not used on PC, need to manually add mouse events
self._mouse._handle_mouse_event()
@@ -596,6 +605,7 @@ class GuiApplication:
# Skip rendering when screen is off
if not self._should_render:
self._mark_progress("gui_app.skip_render")
if PC:
rl.poll_input_events()
time.sleep(1 / self._target_fps)
@@ -603,43 +613,63 @@ class GuiApplication:
continue
if self._render_texture:
self._mark_progress("gui_app.before_begin_texture_mode")
rl.begin_texture_mode(self._render_texture)
self._mark_progress("gui_app.after_begin_texture_mode")
self._mark_progress("gui_app.before_clear_background")
rl.clear_background(rl.BLACK)
self._mark_progress("gui_app.after_clear_background")
else:
self._mark_progress("gui_app.before_begin_drawing")
rl.begin_drawing()
self._mark_progress("gui_app.after_begin_drawing")
self._mark_progress("gui_app.before_clear_background")
rl.clear_background(rl.BLACK)
self._mark_progress("gui_app.after_clear_background")
if self._scale != 1.0:
rl.rl_push_matrix()
rl.rl_scalef(self._scale, self._scale, 1.0)
# Allow a Widget to still run a function regardless of the stack depth
self._mark_progress("gui_app.before_nav_ticks")
for tick in self._nav_stack_ticks:
tick()
self._mark_progress("gui_app.after_nav_ticks")
# Only render top widgets
self._mark_progress("gui_app.before_widget_render")
for widget in self._nav_stack[-self._nav_stack_widgets_to_render:]:
widget.render(rl.Rectangle(0, 0, self.width, self.height))
self._mark_progress("gui_app.after_widget_render")
self._mark_progress("gui_app.frame_ready")
yield True
if self._scale != 1.0:
rl.rl_pop_matrix()
if self._render_texture:
self._mark_progress("gui_app.end_texture_mode")
rl.end_texture_mode()
self._mark_progress("gui_app.before_present_begin_drawing")
rl.begin_drawing()
self._mark_progress("gui_app.after_present_begin_drawing")
self._mark_progress("gui_app.before_present_clear_background")
rl.clear_background(rl.BLACK)
self._mark_progress("gui_app.after_present_clear_background")
src_rect = rl.Rectangle(0, 0, float(self._scaled_width), -float(self._scaled_height))
dst_rect = rl.Rectangle(0, 0, float(self._scaled_width), float(self._scaled_height))
texture = self._render_texture.texture
if texture:
self._mark_progress("gui_app.before_present_draw_texture")
if BURN_IN_MODE and self._burn_in_shader:
rl.begin_shader_mode(self._burn_in_shader)
rl.draw_texture_pro(texture, src_rect, dst_rect, rl.Vector2(0, 0), 0.0, rl.WHITE)
rl.end_shader_mode()
else:
rl.draw_texture_pro(texture, src_rect, dst_rect, rl.Vector2(0, 0), 0.0, rl.WHITE)
self._mark_progress("gui_app.after_present_draw_texture")
if self._show_fps:
rl.draw_fps(10, 10)
@@ -650,7 +680,9 @@ class GuiApplication:
if self._grid_size > 0:
self._draw_grid()
self._mark_progress("gui_app.before_end_drawing")
rl.end_drawing()
self._mark_progress("gui_app.after_end_drawing")
if RECORD:
image = rl.load_image_from_texture(self._render_texture.texture)
@@ -661,6 +693,7 @@ class GuiApplication:
self._monitor_fps()
self._frame += 1
self._mark_progress("gui_app.loop_idle")
if self._profile_render_frames > 0 and self._frame >= self._profile_render_frames:
self._output_render_profile()