meltygui 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- meltygui/__init__.py +107 -0
- meltygui/accounts/__init__.py +0 -0
- meltygui/accounts/internet_accounts.py +1355 -0
- meltygui/chat/__init__.py +91 -0
- meltygui/chat/activity.py +75 -0
- meltygui/chat/backends.py +36 -0
- meltygui/chat/chat_interface.py +732 -0
- meltygui/chat/chat_proxy.py +352 -0
- meltygui/chat/codex_proxy.py +592 -0
- meltygui/chat/codex_settings.py +100 -0
- meltygui/chat/codex_transport.py +60 -0
- meltygui/chat/command_parser.py +204 -0
- meltygui/chat/images.py +227 -0
- meltygui/chat/messages.py +417 -0
- meltygui/chat/metadata.py +139 -0
- meltygui/chat/writer_locks.py +64 -0
- meltygui/code/__init__.py +0 -0
- meltygui/code/basic_converters.py +533 -0
- meltygui/code/chain_converters.py +2111 -0
- meltygui/code/code_checks.py +2209 -0
- meltygui/code/core_syntax.py +1430 -0
- meltygui/code/file_converters.py +1933 -0
- meltygui/code/fileref.py +702 -0
- meltygui/code/hotswap_guard.py +144 -0
- meltygui/code/libcst_conversion.py +9724 -0
- meltygui/code/live_instrument.py +392 -0
- meltygui/code/live_view.py +2490 -0
- meltygui/code/melty_scan.py +2684 -0
- meltygui/code/new_codecs.py +1255 -0
- meltygui/code/new_converters.py +3017 -0
- meltygui/code/project_code.py +278 -0
- meltygui/code/source_context.py +63 -0
- meltygui/code/symbol_roster.py +1588 -0
- meltygui/code/syntax_check.py +34 -0
- meltygui/code/syntax_check_worker.py +114 -0
- meltygui/completion/__init__.py +0 -0
- meltygui/completion/fim.py +1232 -0
- meltygui/completion/fim_context.py +481 -0
- meltygui/completion/providers/__init__.py +0 -0
- meltygui/completion/providers/anthropic_oauth.py +446 -0
- meltygui/completion/providers/anthropic_requests.py +69 -0
- meltygui/completion/providers/claude.py +203 -0
- meltygui/completion/providers/claude_usage.py +499 -0
- meltygui/completion/providers/codex_accounts.py +180 -0
- meltygui/completion/providers/copilot.py +617 -0
- meltygui/completion/providers/oauth_popup.py +220 -0
- meltygui/completion/providers/ollama.py +320 -0
- meltygui/completion/providers/profiles.py +23 -0
- meltygui/core/README.md +88 -0
- meltygui/core/__init__.py +1 -0
- meltygui/core/automation/__init__.py +1 -0
- meltygui/core/automation/action_core.py +153 -0
- meltygui/core/automation/collection_action.py +45 -0
- meltygui/core/automation/mcp_eval.py +167 -0
- meltygui/core/automation/mcp_hotswap.py +107 -0
- meltygui/core/automation/mcp_query.py +552 -0
- meltygui/core/automation/mcp_server.py +657 -0
- meltygui/core/automation/orchestration_core.py +2636 -0
- meltygui/core/automation/query_core.py +124 -0
- meltygui/core/automation/search_core.py +26 -0
- meltygui/core/automation/selector_core.py +340 -0
- meltygui/core/automation/value_core.py +1752 -0
- meltygui/core/cache/__init__.py +1 -0
- meltygui/core/cache/cache_diagnostics.py +0 -0
- meltygui/core/cache/invalidation_decoration.py +153 -0
- meltygui/core/cache/invalidation_tracker.py +43 -0
- meltygui/core/cache/tile_cache.py +5968 -0
- meltygui/core/conversion/__init__.py +1 -0
- meltygui/core/conversion/bubbling.py +599 -0
- meltygui/core/conversion/cache_tree.py +188 -0
- meltygui/core/conversion/chain.py +113 -0
- meltygui/core/conversion/converter_register.py +145 -0
- meltygui/core/conversion/data_decoration.py +67 -0
- meltygui/core/conversion/dict_conversion.py +1815 -0
- meltygui/core/conversion/dict_conversion_util.py +177 -0
- meltygui/core/conversion/dynamic_obj.py +89 -0
- meltygui/core/conversion/graph_compare.py +183 -0
- meltygui/core/conversion/load_save_v2.py +1032 -0
- meltygui/core/conversion/missing_saved_class.py +39 -0
- meltygui/core/conversion/path_finder.py +606 -0
- meltygui/core/conversion/render_host.py +1083 -0
- meltygui/core/core_render.py +6537 -0
- meltygui/core/definition_hotswap.py +231 -0
- meltygui/core/diagnostics/__init__.py +1 -0
- meltygui/core/diagnostics/attribute_churn.py +38 -0
- meltygui/core/diagnostics/fps_counter.py +39 -0
- meltygui/core/diagnostics/gpu_frame_timer.py +103 -0
- meltygui/core/diagnostics/inspection_core.py +169 -0
- meltygui/core/diagnostics/monitor_core.py +105 -0
- meltygui/core/diagnostics/notifications.py +706 -0
- meltygui/core/diagnostics/perf_trace.py +281 -0
- meltygui/core/diagnostics/profile_decoration.py +88 -0
- meltygui/core/diagnostics/resize_trace.py +62 -0
- meltygui/core/diagnostics/screenshot_core.py +247 -0
- meltygui/core/diagnostics/session_status.py +98 -0
- meltygui/core/diagnostics/trace_core.py +445 -0
- meltygui/core/files/__init__.py +1 -0
- meltygui/core/files/file_core.py +208 -0
- meltygui/core/files/file_explorer_core.py +104 -0
- meltygui/core/files/file_tree_core.py +198 -0
- meltygui/core/files/file_watch_core.py +43 -0
- meltygui/core/files/import_graph_core.py +43 -0
- meltygui/core/files/metadata_core.py +51 -0
- meltygui/core/graphics/__init__.py +1 -0
- meltygui/core/graphics/cuda_context_core.py +166 -0
- meltygui/core/graphics/cuda_interop_core.py +136 -0
- meltygui/core/graphics/cuda_kernel_core.py +91 -0
- meltygui/core/graphics/framebuffer_recorder.py +337 -0
- meltygui/core/graphics/gl_state.py +658 -0
- meltygui/core/graphics/lut_core.py +52 -0
- meltygui/core/graphics/overlay_renderer.py +984 -0
- meltygui/core/graphics/scene_target.py +180 -0
- meltygui/core/graphics/screenshot.py +439 -0
- meltygui/core/graphics/shader_func.py +478 -0
- meltygui/core/graphics/tensor_core.py +45 -0
- meltygui/core/graphics/text_texture.py +329 -0
- meltygui/core/graphics/wayland_color.py +635 -0
- meltygui/core/input/__init__.py +1 -0
- meltygui/core/input/collision.py +165 -0
- meltygui/core/input/drag_drop_core.py +1525 -0
- meltygui/core/input/hypr_left_drag.py +323 -0
- meltygui/core/input/input_core.py +245 -0
- meltygui/core/input/input_handler.py +1101 -0
- meltygui/core/input/mouse_cursor.py +355 -0
- meltygui/core/input/pynput_backend.py +1054 -0
- meltygui/core/input/space_mouse.py +338 -0
- meltygui/core/input/touchpad_backend.py +393 -0
- meltygui/core/input/view_selection.py +177 -0
- meltygui/core/layout/__init__.py +1 -0
- meltygui/core/layout/column_core.py +2153 -0
- meltygui/core/layout/cursor_core.py +161 -0
- meltygui/core/layout/dropdown_core.py +278 -0
- meltygui/core/layout/edge_constraints.py +155 -0
- meltygui/core/layout/grid_core.py +117 -0
- meltygui/core/layout/header_core.py +23 -0
- meltygui/core/layout/header_runtime.py +67 -0
- meltygui/core/layout/layout_core.py +87 -0
- meltygui/core/layout/tile_manager_core.py +591 -0
- meltygui/core/melty.py +6726 -0
- meltygui/core/module_map.json +896 -0
- meltygui/core/module_names.py +19 -0
- meltygui/core/rendering/__init__.py +1 -0
- meltygui/core/rendering/core_decoration.py +431 -0
- meltygui/core/rendering/core_render_helpers.py +328 -0
- meltygui/core/rendering/func_metadata.py +398 -0
- meltygui/core/rendering/mode.py +818 -0
- meltygui/core/rendering/mode_defaults.py +41 -0
- meltygui/core/rendering/modes.py +136 -0
- meltygui/core/rendering/parameter_core.py +1665 -0
- meltygui/core/rendering/render_dispatch.py +1891 -0
- meltygui/core/rendering/render_funcs.py +273 -0
- meltygui/core/rendering/shaped.py +312 -0
- meltygui/core/rendering/window_decoration.py +25 -0
- meltygui/core/runtime/__init__.py +1 -0
- meltygui/core/runtime/app.py +735 -0
- meltygui/core/runtime/app_session.py +140 -0
- meltygui/core/runtime/background.py +564 -0
- meltygui/core/runtime/extensions.py +53 -0
- meltygui/core/runtime/gc_manager.py +1163 -0
- meltygui/core/runtime/lifecycle.py +21 -0
- meltygui/core/runtime/paths.py +27 -0
- meltygui/core/runtime/settings.py +14 -0
- meltygui/core/runtime/singleton.py +16 -0
- meltygui/core/runtime/thread_safe_bool.py +24 -0
- meltygui/core/runtime/thread_signal.py +30 -0
- meltygui/core/runtime/toggles.py +3115 -0
- meltygui/core/services/__init__.py +1 -0
- meltygui/core/services/account_core.py +10 -0
- meltygui/core/services/chat_core.py +19 -0
- meltygui/core/services/claude_terminal_core.py +346 -0
- meltygui/core/services/terminal_core.py +458 -0
- meltygui/core/services/terminal_runtime.py +78 -0
- meltygui/core/styling/__init__.py +1 -0
- meltygui/core/styling/color_core.py +46 -0
- meltygui/core/styling/fonts.py +639 -0
- meltygui/core/styling/global_style.py +338 -0
- meltygui/core/styling/style.py +198 -0
- meltygui/core/styling/style_core.py +522 -0
- meltygui/core/styling/warm_start.py +149 -0
- meltygui/core/windowing/__init__.py +1 -0
- meltygui/core/windowing/backends/PYIMGUI_LICENSE +28 -0
- meltygui/core/windowing/backends/__init__.py +1 -0
- meltygui/core/windowing/backends/imgui_renderer.py +138 -0
- meltygui/core/windowing/backends/native_wayland.py +850 -0
- meltygui/core/windowing/backends/protocols/xdg-decoration-unstable-v1.xml +156 -0
- meltygui/core/windowing/backends/protocols/xdg-shell.xml +1420 -0
- meltygui/core/windowing/backends/wayland_protocol.py +101 -0
- meltygui/core/windowing/dock_core.py +182 -0
- meltygui/core/windowing/frame_geometry.py +42 -0
- meltygui/core/windowing/geometry_feed.py +864 -0
- meltygui/core/windowing/glfw_utils.py +1343 -0
- meltygui/core/windowing/os_frame.py +1552 -0
- meltygui/core/windowing/surface.py +643 -0
- meltygui/core/windowing/titlebar.py +1560 -0
- meltygui/core/windowing/titlebar_buttons.py +281 -0
- meltygui/core/windowing/wayland_move.py +932 -0
- meltygui/core/windowing/window_api.py +62 -0
- meltygui/core/windowing/window_constants.py +339 -0
- meltygui/core/windowing/window_visibility.py +162 -0
- meltygui/debug/__init__.py +0 -0
- meltygui/debug/app_view_utils.py +9 -0
- meltygui/editor/__init__.py +0 -0
- meltygui/editor/bash_syntax.py +30 -0
- meltygui/editor/code_line_fast.py +152 -0
- meltygui/editor/diff.py +139 -0
- meltygui/editor/external_changes.py +159 -0
- meltygui/editor/file_header.py +41 -0
- meltygui/editor/live_usage.py +169 -0
- meltygui/editor/live_view_views.py +1803 -0
- meltygui/editor/pending_save.py +1351 -0
- meltygui/editor/roster_tints.py +547 -0
- meltygui/editor/source_preview.py +16 -0
- meltygui/editor/source_tools.py +10 -0
- meltygui/editor/source_ui.py +70 -0
- meltygui/editor/spell_check.py +77 -0
- meltygui/editor/text_editor.py +9076 -0
- meltygui/editor/usage_picker.py +538 -0
- meltygui/events/__init__.py +0 -0
- meltygui/events/example.py +118 -0
- meltygui/examples/__init__.py +0 -0
- meltygui/examples/columns_demo.py +33 -0
- meltygui/examples/columns_window_demo.py +60 -0
- meltygui/examples/context_menu_demo.py +24 -0
- meltygui/examples/context_menu_window_demo.py +49 -0
- meltygui/examples/gui_playground.py +127 -0
- meltygui/examples/live_view_playground.py +256 -0
- meltygui/examples/lora.py +43 -0
- meltygui/examples/lora_data.py +59 -0
- meltygui/examples/lora_policies.py +67 -0
- meltygui/examples/mode_demo.py +49 -0
- meltygui/examples/modifies_demo.py +119 -0
- meltygui/examples/scalar_policies.py +60 -0
- meltygui/examples/style_layouts.py +149 -0
- meltygui/examples/tile_manager_demo.py +74 -0
- meltygui/examples/tint_demo.py +160 -0
- meltygui/examples/tint_functions.py +56 -0
- meltygui/examples/trace_demo.py +88 -0
- meltygui/examples/two_windows.py +36 -0
- meltygui/files/__init__.py +0 -0
- meltygui/files/fast_file_explorer.py +439 -0
- meltygui/gnome_extension/lsd-window-geometry@latent-descent/extension.js +237 -0
- meltygui/gnome_extension/lsd-window-geometry@latent-descent/lsd-window-geometry@latent-descent.iml +9 -0
- meltygui/gnome_extension/lsd-window-geometry@latent-descent/metadata.json +7 -0
- meltygui/graphics/__init__.py +6 -0
- meltygui/graphics/base.py +85 -0
- meltygui/graphics/examples.py +507 -0
- meltygui/graphics/executor.py +520 -0
- meltygui/graphics/filter.py +667 -0
- meltygui/graphics/filter.pyi +856 -0
- meltygui/graphics/generate_stubs.py +22 -0
- meltygui/graphics/registry.py +203 -0
- meltygui/graphics/shader_compiler.py +155 -0
- meltygui/graphics/shaders.py +1302 -0
- meltygui/graphics/stub_generator.py +250 -0
- meltygui/graphics/texture_manager.py +170 -0
- meltygui/graphics/texture_min_max.py +295 -0
- meltygui/hdr_color.py +757 -0
- meltygui/image_load.py +308 -0
- meltygui/model/__init__.py +1 -0
- meltygui/model/account_model.py +142 -0
- meltygui/model/camera_model.py +159 -0
- meltygui/model/chat_model.py +86 -0
- meltygui/model/code_model.py +62 -0
- meltygui/model/code_proxy_model.py +876 -0
- meltygui/model/collection_model.py +41 -0
- meltygui/model/color_model.py +127 -0
- meltygui/model/cuda_tensor_model.py +36 -0
- meltygui/model/cuda_texture_model.py +149 -0
- meltygui/model/dropdown_model.py +137 -0
- meltygui/model/file_metadata_model.py +73 -0
- meltygui/model/file_model.py +289 -0
- meltygui/model/format_model.py +390 -0
- meltygui/model/graph_model.py +98 -0
- meltygui/model/icon_model.py +1024 -0
- meltygui/model/import_graph_model.py +468 -0
- meltygui/model/layout_model.py +15 -0
- meltygui/model/lut_model.py +266 -0
- meltygui/model/search_model.py +173 -0
- meltygui/model/tensor_model.py +402 -0
- meltygui/model/terminal_model.py +329 -0
- meltygui/model/texture_model.py +146 -0
- meltygui/model/tile_model.py +24 -0
- meltygui/model/trace_model.py +198 -0
- meltygui/model/trace_report_model.py +146 -0
- meltygui/models/__init__.py +0 -0
- meltygui/models/file_meta.py +613 -0
- meltygui/models/function_console.py +184 -0
- meltygui/models/orchestration.py +48 -0
- meltygui/pbr.py +1576 -0
- meltygui/png_unfilter.c +49 -0
- meltygui/resources/JetBrainsMono-Regular.ttf +0 -0
- meltygui/resources/THIRD_PARTY_NOTICES.md +21 -0
- meltygui/resources/dejavu/DejaVuSans-Bold.ttf +0 -0
- meltygui/resources/dejavu/DejaVuSans-ExtraLight.ttf +0 -0
- meltygui/resources/dejavu/DejaVuSans.ttf +0 -0
- meltygui/resources/dejavu/LICENSE.txt +78 -0
- meltygui/resources/fontawesome-LICENSE.txt +121 -0
- meltygui/resources/fontawesome-webfont.ttf +0 -0
- meltygui/resources/hdri/studio_small_09_1k.hdr +0 -0
- meltygui/resources/jetbrains-weights/JetBrainsMono-Bold.ttf +0 -0
- meltygui/resources/jetbrains-weights/JetBrainsMono-ExtraBold.ttf +0 -0
- meltygui/resources/jetbrains-weights/JetBrainsMono-ExtraLight.ttf +0 -0
- meltygui/resources/jetbrains-weights/JetBrainsMono-Light.ttf +0 -0
- meltygui/resources/jetbrains-weights/JetBrainsMono-Medium.ttf +0 -0
- meltygui/resources/jetbrains-weights/JetBrainsMono-SemiBold.ttf +0 -0
- meltygui/resources/jetbrains-weights/JetBrainsMono-Thin.ttf +0 -0
- meltygui/resources/jetbrains-weights/OFL.txt +93 -0
- meltygui/resources/jetbrains-weights/README.md +2 -0
- meltygui/state/__init__.py +0 -0
- meltygui/state/account_state.py +22 -0
- meltygui/state/animation_state.py +97 -0
- meltygui/state/annotation_state.py +22 -0
- meltygui/state/chat_state.py +36 -0
- meltygui/state/code_state.py +10 -0
- meltygui/state/core_enums.py +59 -0
- meltygui/state/core_markers.py +115 -0
- meltygui/state/core_undo.py +1075 -0
- meltygui/state/file_state.py +75 -0
- meltygui/state/graph_state.py +26 -0
- meltygui/state/inspection_state.py +47 -0
- meltygui/state/menu_state.py +10 -0
- meltygui/state/model_enums.py +11 -0
- meltygui/state/new_core_model.py +2394 -0
- meltygui/state/orchestration_state.py +14 -0
- meltygui/state/query_state.py +24 -0
- meltygui/state/tensor_state.py +10 -0
- meltygui/state/terminal_state.py +23 -0
- meltygui/state/trace_state.py +32 -0
- meltygui/state/voxel_state.py +12 -0
- meltygui/text_index.py +816 -0
- meltygui/utils/__init__.py +0 -0
- meltygui/utils/jump_to_code.py +344 -0
- meltygui/utils/pkl_inspect.py +90 -0
- meltygui/utils/render_utils.py +1419 -0
- meltygui/view/__init__.py +1 -0
- meltygui/view/account_view.py +524 -0
- meltygui/view/action_view.py +73 -0
- meltygui/view/chat_decoration_view.py +112 -0
- meltygui/view/chat_view.py +1703 -0
- meltygui/view/code_view.py +2677 -0
- meltygui/view/collection_view.py +1185 -0
- meltygui/view/color_view.py +824 -0
- meltygui/view/control_view.py +559 -0
- meltygui/view/decoration_view.py +439 -0
- meltygui/view/diagnostic_view.py +177 -0
- meltygui/view/dropdown_view.py +1082 -0
- meltygui/view/file_view.py +1599 -0
- meltygui/view/graph_cuda_view.py +105 -0
- meltygui/view/graph_view.py +882 -0
- meltygui/view/header_view.py +848 -0
- meltygui/view/input_view.py +238 -0
- meltygui/view/inspection_view.py +1783 -0
- meltygui/view/layout_view.py +596 -0
- meltygui/view/lut_view.py +45 -0
- meltygui/view/menu_view.py +212 -0
- meltygui/view/orchestration_view.py +658 -0
- meltygui/view/query_view.py +118 -0
- meltygui/view/search_view.py +342 -0
- meltygui/view/tab_view.py +258 -0
- meltygui/view/tensor_view.py +430 -0
- meltygui/view/terminal_view.py +355 -0
- meltygui/view/text_view.py +8031 -0
- meltygui/view/texture_view.py +480 -0
- meltygui/view/tile_view.py +38 -0
- meltygui/view/trace_view.py +923 -0
- meltygui/view/voxel_cuda_view.py +824 -0
- meltygui/view/voxel_view.py +1860 -0
- meltygui/view/window_view.py +111 -0
- meltygui-0.1.0.dist-info/METADATA +143 -0
- meltygui-0.1.0.dist-info/RECORD +372 -0
- meltygui-0.1.0.dist-info/WHEEL +4 -0
- meltygui-0.1.0.dist-info/licenses/LICENSE +202 -0
|
@@ -0,0 +1,295 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
from OpenGL.GL import *
|
|
3
|
+
from OpenGL.GL import shaders
|
|
4
|
+
import ctypes
|
|
5
|
+
|
|
6
|
+
# Module-level state
|
|
7
|
+
_program = None
|
|
8
|
+
_ssbo = None
|
|
9
|
+
_ssbo_size = 0
|
|
10
|
+
|
|
11
|
+
# Stage-2 (final reduction) state. _reduce_program collapses the per-workgroup
|
|
12
|
+
# partials into a single (min, max) written into a 1x1 RGBA32F texture via
|
|
13
|
+
# imageStore, so the value never leaves the GPU (no glMapBufferRange readback /
|
|
14
|
+
# CPU-GPU sync stall). _result_textures holds one such texture per input texture
|
|
15
|
+
# id - keyed so two normalize calls in the same frame don't write/read the same
|
|
16
|
+
# result texel.
|
|
17
|
+
_reduce_program = None
|
|
18
|
+
_result_textures = {}
|
|
19
|
+
|
|
20
|
+
_COMPUTE_SHADER_SOURCE = """
|
|
21
|
+
#version 430
|
|
22
|
+
layout(local_size_x = 16, local_size_y = 16) in;
|
|
23
|
+
|
|
24
|
+
uniform sampler2D inputTexture;
|
|
25
|
+
|
|
26
|
+
layout(std430, binding = 1) buffer ResultBuffer {
|
|
27
|
+
vec2 workgroupResults[]; // Each workgroup writes (min, max)
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
uniform ivec2 numWorkgroups;
|
|
31
|
+
|
|
32
|
+
shared float localMin[256];
|
|
33
|
+
shared float localMax[256];
|
|
34
|
+
|
|
35
|
+
void main() {
|
|
36
|
+
ivec2 pos = ivec2(gl_GlobalInvocationID.xy);
|
|
37
|
+
ivec2 size = textureSize(inputTexture, 0);
|
|
38
|
+
uint lid = gl_LocalInvocationIndex;
|
|
39
|
+
|
|
40
|
+
// Initialize with extreme values
|
|
41
|
+
float myMin = 1e38;
|
|
42
|
+
float myMax = -1e38;
|
|
43
|
+
|
|
44
|
+
if (pos.x < size.x && pos.y < size.y) {
|
|
45
|
+
vec4 pixel = texelFetch(inputTexture, pos, 0);
|
|
46
|
+
// Get min/max across RGB channels (ignore alpha)
|
|
47
|
+
myMin = min(min(pixel.r, pixel.g), pixel.b);
|
|
48
|
+
myMax = max(max(pixel.r, pixel.g), pixel.b);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
localMin[lid] = myMin;
|
|
52
|
+
localMax[lid] = myMax;
|
|
53
|
+
barrier();
|
|
54
|
+
|
|
55
|
+
// Parallel reduction in shared memory
|
|
56
|
+
for (uint s = 128; s > 0; s >>= 1) {
|
|
57
|
+
if (lid < s) {
|
|
58
|
+
localMin[lid] = min(localMin[lid], localMin[lid + s]);
|
|
59
|
+
localMax[lid] = max(localMax[lid], localMax[lid + s]);
|
|
60
|
+
}
|
|
61
|
+
barrier();
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Workgroup leader writes result
|
|
65
|
+
if (lid == 0) {
|
|
66
|
+
uint workgroupIndex = gl_WorkGroupID.y * numWorkgroups.x + gl_WorkGroupID.x;
|
|
67
|
+
workgroupResults[workgroupIndex] = vec2(localMin[0], localMax[0]);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
"""
|
|
71
|
+
|
|
72
|
+
# Stage 2: a single workgroup reduces the per-workgroup partials (binding 1, the
|
|
73
|
+
# same SSBO stage 1 filled) down to one (min, max) and stores it into the 0,0
|
|
74
|
+
# texel of a 1x1 RGBA32F texture. The normalize_remap fragment shader just samples
|
|
75
|
+
# that texel - the range is read straight off the GPU, never mapped to the CPU.
|
|
76
|
+
_REDUCE_SHADER_SOURCE = """
|
|
77
|
+
#version 430
|
|
78
|
+
layout(local_size_x = 256) in;
|
|
79
|
+
|
|
80
|
+
layout(std430, binding = 1) readonly buffer ResultBuffer {
|
|
81
|
+
vec2 workgroupResults[];
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
layout(rgba32f, binding = 0) writeonly uniform image2D outImage;
|
|
85
|
+
|
|
86
|
+
uniform int count;
|
|
87
|
+
|
|
88
|
+
shared float localMin[256];
|
|
89
|
+
shared float localMax[256];
|
|
90
|
+
|
|
91
|
+
void main() {
|
|
92
|
+
uint lid = gl_LocalInvocationIndex;
|
|
93
|
+
|
|
94
|
+
float myMin = 1e38;
|
|
95
|
+
float myMax = -1e38;
|
|
96
|
+
for (uint i = lid; i < uint(count); i += 256u) {
|
|
97
|
+
myMin = min(myMin, workgroupResults[i].x);
|
|
98
|
+
myMax = max(myMax, workgroupResults[i].y);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
localMin[lid] = myMin;
|
|
102
|
+
localMax[lid] = myMax;
|
|
103
|
+
barrier();
|
|
104
|
+
|
|
105
|
+
for (uint s = 128u; s > 0u; s >>= 1u) {
|
|
106
|
+
if (lid < s) {
|
|
107
|
+
localMin[lid] = min(localMin[lid], localMin[lid + s]);
|
|
108
|
+
localMax[lid] = max(localMax[lid], localMax[lid + s]);
|
|
109
|
+
}
|
|
110
|
+
barrier();
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
if (lid == 0u) {
|
|
114
|
+
imageStore(outImage, ivec2(0, 0), vec4(localMin[0], localMax[0], 0.0, 1.0));
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
"""
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def _ensure_initialized():
|
|
121
|
+
"""Lazy initialization of shader and buffer."""
|
|
122
|
+
global _program, _ssbo, _ssbo_size
|
|
123
|
+
|
|
124
|
+
if _program is not None:
|
|
125
|
+
return
|
|
126
|
+
|
|
127
|
+
compute_shader = shaders.compileShader(_COMPUTE_SHADER_SOURCE, GL_COMPUTE_SHADER)
|
|
128
|
+
_program = shaders.compileProgram(compute_shader)
|
|
129
|
+
_ssbo = glGenBuffers(1)
|
|
130
|
+
_ssbo_size = 0
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
def _ensure_reduce_initialized():
|
|
134
|
+
"""Lazy initialization of the stage-2 reduction program."""
|
|
135
|
+
global _reduce_program
|
|
136
|
+
|
|
137
|
+
if _reduce_program is not None:
|
|
138
|
+
return
|
|
139
|
+
|
|
140
|
+
reduce_shader = shaders.compileShader(_REDUCE_SHADER_SOURCE, GL_COMPUTE_SHADER)
|
|
141
|
+
_reduce_program = shaders.compileProgram(reduce_shader)
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
def _dispatch_stage1(texture_id: int) -> tuple[int, int]:
|
|
145
|
+
"""Run the per-workgroup reduction into the SSBO (no readback).
|
|
146
|
+
|
|
147
|
+
Returns (total_workgroups, required_size) describing the SSBO contents, so
|
|
148
|
+
callers can either map it (CPU path) or reduce it further on the GPU.
|
|
149
|
+
"""
|
|
150
|
+
global _ssbo_size
|
|
151
|
+
|
|
152
|
+
_ensure_initialized()
|
|
153
|
+
|
|
154
|
+
# Query texture dimensions
|
|
155
|
+
glBindTexture(GL_TEXTURE_2D, texture_id)
|
|
156
|
+
width = glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH)
|
|
157
|
+
height = glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT)
|
|
158
|
+
|
|
159
|
+
# Calculate workgroup dimensions
|
|
160
|
+
workgroup_size = 16
|
|
161
|
+
num_workgroups_x = (width + workgroup_size - 1) // workgroup_size
|
|
162
|
+
num_workgroups_y = (height + workgroup_size - 1) // workgroup_size
|
|
163
|
+
total_workgroups = num_workgroups_x * num_workgroups_y
|
|
164
|
+
|
|
165
|
+
# Resize SSBO if needed (2 floats per workgroup: min and max)
|
|
166
|
+
required_size = total_workgroups * 2 * 4
|
|
167
|
+
if required_size > _ssbo_size:
|
|
168
|
+
glBindBuffer(GL_SHADER_STORAGE_BUFFER, _ssbo)
|
|
169
|
+
glBufferData(GL_SHADER_STORAGE_BUFFER, required_size, None, GL_DYNAMIC_READ)
|
|
170
|
+
_ssbo_size = required_size
|
|
171
|
+
|
|
172
|
+
# Bind resources
|
|
173
|
+
glUseProgram(_program)
|
|
174
|
+
|
|
175
|
+
# Bind texture to texture unit 0
|
|
176
|
+
glActiveTexture(GL_TEXTURE0)
|
|
177
|
+
glBindTexture(GL_TEXTURE_2D, texture_id)
|
|
178
|
+
glUniform1i(glGetUniformLocation(_program, "inputTexture"), 0)
|
|
179
|
+
|
|
180
|
+
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, _ssbo)
|
|
181
|
+
|
|
182
|
+
# Set uniforms
|
|
183
|
+
loc = glGetUniformLocation(_program, "numWorkgroups")
|
|
184
|
+
glUniform2i(loc, num_workgroups_x, num_workgroups_y)
|
|
185
|
+
|
|
186
|
+
# Dispatch compute shader
|
|
187
|
+
glDispatchCompute(num_workgroups_x, num_workgroups_y, 1)
|
|
188
|
+
glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT)
|
|
189
|
+
|
|
190
|
+
return total_workgroups, required_size
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
def get_texture_min_max(texture_id: int) -> tuple[float, float]:
|
|
194
|
+
"""
|
|
195
|
+
Compute min/max pixel values of an OpenGL texture (CPU readback).
|
|
196
|
+
|
|
197
|
+
Reads the result back to the CPU via glMapBufferRange — this synchronizes
|
|
198
|
+
the GPU and stalls. Prefer compute_min_max_to_texture() in hot paths where
|
|
199
|
+
the value only needs to feed another GPU pass.
|
|
200
|
+
|
|
201
|
+
Args:
|
|
202
|
+
texture_id: OpenGL texture ID (any format - will be converted to float)
|
|
203
|
+
|
|
204
|
+
Returns:
|
|
205
|
+
Tuple of (min_value, max_value) across RGB channels
|
|
206
|
+
"""
|
|
207
|
+
total_workgroups, required_size = _dispatch_stage1(texture_id)
|
|
208
|
+
|
|
209
|
+
# Read back results with glMapBufferRange
|
|
210
|
+
glBindBuffer(GL_SHADER_STORAGE_BUFFER, _ssbo)
|
|
211
|
+
ptr = glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, required_size, GL_MAP_READ_BIT)
|
|
212
|
+
results = np.ctypeslib.as_array(ctypes.cast(ptr, ctypes.POINTER(ctypes.c_float)),
|
|
213
|
+
shape=(total_workgroups * 2,)).copy()
|
|
214
|
+
glUnmapBuffer(GL_SHADER_STORAGE_BUFFER)
|
|
215
|
+
|
|
216
|
+
# Final reduction on CPU
|
|
217
|
+
results = results.reshape(-1, 2)
|
|
218
|
+
min_val = float(np.min(results[:, 0]))
|
|
219
|
+
max_val = float(np.max(results[:, 1]))
|
|
220
|
+
|
|
221
|
+
return min_val, max_val
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
def _get_result_tex(input_texture_id: int) -> int:
|
|
225
|
+
"""Get or create the 1x1 RGBA32F texture that holds (min, max) for an input."""
|
|
226
|
+
tex = _result_textures.get(input_texture_id)
|
|
227
|
+
if tex is not None:
|
|
228
|
+
return tex
|
|
229
|
+
|
|
230
|
+
tex = glGenTextures(1)
|
|
231
|
+
glBindTexture(GL_TEXTURE_2D, tex)
|
|
232
|
+
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, 1, 1, 0, GL_RGBA, GL_FLOAT, None)
|
|
233
|
+
# texelFetch ignores filtering, but NEAREST makes a float texture valid as a
|
|
234
|
+
# sampler everywhere (linear filtering of 32F is an optional GL extension).
|
|
235
|
+
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST)
|
|
236
|
+
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST)
|
|
237
|
+
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)
|
|
238
|
+
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)
|
|
239
|
+
_result_textures[input_texture_id] = tex
|
|
240
|
+
return tex
|
|
241
|
+
|
|
242
|
+
|
|
243
|
+
def compute_min_max_to_texture(input_texture_id: int) -> int:
|
|
244
|
+
"""
|
|
245
|
+
Compute (min, max) of a texture entirely on the GPU and store it in the 0,0
|
|
246
|
+
texel of a 1x1 RGBA32F texture (.r = min, .g = max). No CPU readback.
|
|
247
|
+
|
|
248
|
+
Returns the result texture id, ready to be sampled by a downstream shader.
|
|
249
|
+
"""
|
|
250
|
+
total_workgroups, _ = _dispatch_stage1(input_texture_id)
|
|
251
|
+
|
|
252
|
+
_ensure_reduce_initialized()
|
|
253
|
+
out_tex = _get_result_tex(input_texture_id)
|
|
254
|
+
|
|
255
|
+
glUseProgram(_reduce_program)
|
|
256
|
+
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, _ssbo)
|
|
257
|
+
glBindImageTexture(0, out_tex, 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_RGBA32F)
|
|
258
|
+
glUniform1i(glGetUniformLocation(_reduce_program, "count"), total_workgroups)
|
|
259
|
+
glDispatchCompute(1, 1, 1)
|
|
260
|
+
# Make the imageStore visible before the sampler fetch in the following draw.
|
|
261
|
+
glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT | GL_TEXTURE_FETCH_BARRIER_BIT)
|
|
262
|
+
|
|
263
|
+
return out_tex
|
|
264
|
+
|
|
265
|
+
|
|
266
|
+
def set_min_max_texture(input_texture_id: int, min_value: float, max_value: float) -> int:
|
|
267
|
+
"""
|
|
268
|
+
Write an explicit (min, max) into the 1x1 result texture (no GPU reduction,
|
|
269
|
+
no readback — a tiny upload). Returns the result texture id so the explicit
|
|
270
|
+
path feeds normalize_remap through the same sampler as the computed path.
|
|
271
|
+
"""
|
|
272
|
+
out_tex = _get_result_tex(input_texture_id)
|
|
273
|
+
data = np.array([min_value, max_value, 0.0, 1.0], dtype=np.float32)
|
|
274
|
+
glBindTexture(GL_TEXTURE_2D, out_tex)
|
|
275
|
+
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 1, 1, GL_RGBA, GL_FLOAT, data)
|
|
276
|
+
return out_tex
|
|
277
|
+
|
|
278
|
+
|
|
279
|
+
def cleanup():
|
|
280
|
+
"""Delete OpenGL resources. Call before destroying GL context."""
|
|
281
|
+
global _program, _ssbo, _ssbo_size, _reduce_program, _result_textures
|
|
282
|
+
|
|
283
|
+
if _ssbo is not None:
|
|
284
|
+
glDeleteBuffers(1, [_ssbo])
|
|
285
|
+
_ssbo = None
|
|
286
|
+
if _program is not None:
|
|
287
|
+
glDeleteProgram(_program)
|
|
288
|
+
_program = None
|
|
289
|
+
if _reduce_program is not None:
|
|
290
|
+
glDeleteProgram(_reduce_program)
|
|
291
|
+
_reduce_program = None
|
|
292
|
+
if _result_textures:
|
|
293
|
+
glDeleteTextures(list(_result_textures.values()))
|
|
294
|
+
_result_textures = {}
|
|
295
|
+
_ssbo_size = 0
|