Skip to content

Commit d0c6f84

Browse files
ui: add burn in debug mode (#36625)
* ui: add burn in debug mode * scary * lil less * lil cleanup * revert that * cleanup
1 parent 81be78c commit d0c6f84

File tree

3 files changed

+59
-14
lines changed

3 files changed

+59
-14
lines changed

system/ui/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ Quick start:
66
* set `SHOW_FPS=1` to show the FPS
77
* set `STRICT_MODE=1` to kill the app if it drops too much below 60fps
88
* set `SCALE=1.5` to scale the entire UI by 1.5x
9+
* set `BURN_IN=1` to get a burn-in heatmap version of the UI
910
* https://www.raylib.com/cheatsheet/cheatsheet.html
1011
* https://electronstudio.github.io/raylib-python-cffi/README.html#quickstart
1112

system/ui/lib/application.py

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import sys
77
import pyray as rl
88
import threading
9+
import platform
910
from contextlib import contextmanager
1011
from collections.abc import Callable
1112
from collections import deque
@@ -34,6 +35,43 @@
3435
PROFILE_RENDER = int(os.getenv("PROFILE_RENDER", "0"))
3536
PROFILE_STATS = int(os.getenv("PROFILE_STATS", "100")) # Number of functions to show in profile output
3637

38+
GL_VERSION = """
39+
#version 300 es
40+
precision highp float;
41+
"""
42+
if platform.system() == "Darwin":
43+
GL_VERSION = """
44+
#version 330 core
45+
"""
46+
47+
BURN_IN_MODE = "BURN_IN" in os.environ
48+
BURN_IN_VERTEX_SHADER = GL_VERSION + """
49+
in vec3 vertexPosition;
50+
in vec2 vertexTexCoord;
51+
uniform mat4 mvp;
52+
out vec2 fragTexCoord;
53+
void main() {
54+
fragTexCoord = vertexTexCoord;
55+
gl_Position = mvp * vec4(vertexPosition, 1.0);
56+
}
57+
"""
58+
BURN_IN_FRAGMENT_SHADER = GL_VERSION + """
59+
in vec2 fragTexCoord;
60+
uniform sampler2D texture0;
61+
out vec4 fragColor;
62+
void main() {
63+
vec4 sampled = texture(texture0, fragTexCoord);
64+
float intensity = sampled.b;
65+
// Map blue intensity to green -> yellow -> red to highlight burn-in risk.
66+
vec3 start = vec3(0.0, 1.0, 0.0);
67+
vec3 middle = vec3(1.0, 1.0, 0.0);
68+
vec3 end = vec3(1.0, 0.0, 0.0);
69+
vec3 gradient = mix(start, middle, clamp(intensity * 2.0, 0.0, 1.0));
70+
gradient = mix(gradient, end, clamp((intensity - 0.5) * 2.0, 0.0, 1.0));
71+
fragColor = vec4(gradient, sampled.a);
72+
}
73+
"""
74+
3775
DEFAULT_TEXT_SIZE = 60
3876
DEFAULT_TEXT_COLOR = rl.WHITE
3977

@@ -155,6 +193,7 @@ def __init__(self, width: int, height: int):
155193
self._scaled_width = int(self._width * self._scale)
156194
self._scaled_height = int(self._height * self._scale)
157195
self._render_texture: rl.RenderTexture | None = None
196+
self._burn_in_shader: rl.Shader | None = None
158197
self._textures: dict[str, rl.Texture] = {}
159198
self._target_fps: int = _DEFAULT_FPS
160199
self._last_fps_log_time: float = time.monotonic()
@@ -212,8 +251,10 @@ def _close(sig, frame):
212251
rl.set_config_flags(flags)
213252

214253
rl.init_window(self._scaled_width, self._scaled_height, title)
254+
needs_render_texture = self._scale != 1.0 or BURN_IN_MODE
215255
if self._scale != 1.0:
216256
rl.set_mouse_scale(1 / self._scale, 1 / self._scale)
257+
if needs_render_texture:
217258
self._render_texture = rl.load_render_texture(self._width, self._height)
218259
rl.set_texture_filter(self._render_texture.texture, rl.TextureFilter.TEXTURE_FILTER_BILINEAR)
219260
rl.set_target_fps(fps)
@@ -222,6 +263,8 @@ def _close(sig, frame):
222263
self._set_styles()
223264
self._load_fonts()
224265
self._patch_text_functions()
266+
if BURN_IN_MODE and self._burn_in_shader is None:
267+
self._burn_in_shader = rl.load_shader_from_memory(BURN_IN_VERTEX_SHADER, BURN_IN_FRAGMENT_SHADER)
225268

226269
if not PC:
227270
self._mouse.start()
@@ -337,6 +380,10 @@ def close(self):
337380
rl.unload_render_texture(self._render_texture)
338381
self._render_texture = None
339382

383+
if self._burn_in_shader:
384+
rl.unload_shader(self._burn_in_shader)
385+
self._burn_in_shader = None
386+
340387
if not PC:
341388
self._mouse.stop()
342389

@@ -395,7 +442,14 @@ def render(self):
395442
rl.clear_background(rl.BLACK)
396443
src_rect = rl.Rectangle(0, 0, float(self._width), -float(self._height))
397444
dst_rect = rl.Rectangle(0, 0, float(self._scaled_width), float(self._scaled_height))
398-
rl.draw_texture_pro(self._render_texture.texture, src_rect, dst_rect, rl.Vector2(0, 0), 0.0, rl.WHITE)
445+
texture = self._render_texture.texture
446+
if texture:
447+
if BURN_IN_MODE and self._burn_in_shader:
448+
rl.begin_shader_mode(self._burn_in_shader)
449+
rl.draw_texture_pro(texture, src_rect, dst_rect, rl.Vector2(0, 0), 0.0, rl.WHITE)
450+
rl.end_shader_mode()
451+
else:
452+
rl.draw_texture_pro(texture, src_rect, dst_rect, rl.Vector2(0, 0), 0.0, rl.WHITE)
399453

400454
if self._show_fps:
401455
rl.draw_fps(10, 10)

system/ui/lib/shader_polygon.py

Lines changed: 3 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
1-
import platform
21
import pyray as rl
32
import numpy as np
43
from dataclasses import dataclass
54
from typing import Any, Optional, cast
6-
from openpilot.system.ui.lib.application import gui_app
5+
from openpilot.system.ui.lib.application import gui_app, GL_VERSION
76

87
MAX_GRADIENT_COLORS = 20 # includes stops as well
98

@@ -29,16 +28,7 @@ def __post_init__(self):
2928
self.stops = [i / max(1, color_count - 1) for i in range(color_count)]
3029

3130

32-
VERSION = """
33-
#version 300 es
34-
precision highp float;
35-
"""
36-
if platform.system() == "Darwin":
37-
VERSION = """
38-
#version 330 core
39-
"""
40-
41-
FRAGMENT_SHADER = VERSION + """
31+
FRAGMENT_SHADER = GL_VERSION + """
4232
in vec2 fragTexCoord;
4333
out vec4 finalColor;
4434
@@ -83,7 +73,7 @@ def __post_init__(self):
8373
"""
8474

8575
# Default vertex shader
86-
VERTEX_SHADER = VERSION + """
76+
VERTEX_SHADER = GL_VERSION + """
8777
in vec3 vertexPosition;
8878
in vec2 vertexTexCoord;
8979
out vec2 fragTexCoord;

0 commit comments

Comments
 (0)