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.
Files changed (372) hide show
  1. meltygui/__init__.py +107 -0
  2. meltygui/accounts/__init__.py +0 -0
  3. meltygui/accounts/internet_accounts.py +1355 -0
  4. meltygui/chat/__init__.py +91 -0
  5. meltygui/chat/activity.py +75 -0
  6. meltygui/chat/backends.py +36 -0
  7. meltygui/chat/chat_interface.py +732 -0
  8. meltygui/chat/chat_proxy.py +352 -0
  9. meltygui/chat/codex_proxy.py +592 -0
  10. meltygui/chat/codex_settings.py +100 -0
  11. meltygui/chat/codex_transport.py +60 -0
  12. meltygui/chat/command_parser.py +204 -0
  13. meltygui/chat/images.py +227 -0
  14. meltygui/chat/messages.py +417 -0
  15. meltygui/chat/metadata.py +139 -0
  16. meltygui/chat/writer_locks.py +64 -0
  17. meltygui/code/__init__.py +0 -0
  18. meltygui/code/basic_converters.py +533 -0
  19. meltygui/code/chain_converters.py +2111 -0
  20. meltygui/code/code_checks.py +2209 -0
  21. meltygui/code/core_syntax.py +1430 -0
  22. meltygui/code/file_converters.py +1933 -0
  23. meltygui/code/fileref.py +702 -0
  24. meltygui/code/hotswap_guard.py +144 -0
  25. meltygui/code/libcst_conversion.py +9724 -0
  26. meltygui/code/live_instrument.py +392 -0
  27. meltygui/code/live_view.py +2490 -0
  28. meltygui/code/melty_scan.py +2684 -0
  29. meltygui/code/new_codecs.py +1255 -0
  30. meltygui/code/new_converters.py +3017 -0
  31. meltygui/code/project_code.py +278 -0
  32. meltygui/code/source_context.py +63 -0
  33. meltygui/code/symbol_roster.py +1588 -0
  34. meltygui/code/syntax_check.py +34 -0
  35. meltygui/code/syntax_check_worker.py +114 -0
  36. meltygui/completion/__init__.py +0 -0
  37. meltygui/completion/fim.py +1232 -0
  38. meltygui/completion/fim_context.py +481 -0
  39. meltygui/completion/providers/__init__.py +0 -0
  40. meltygui/completion/providers/anthropic_oauth.py +446 -0
  41. meltygui/completion/providers/anthropic_requests.py +69 -0
  42. meltygui/completion/providers/claude.py +203 -0
  43. meltygui/completion/providers/claude_usage.py +499 -0
  44. meltygui/completion/providers/codex_accounts.py +180 -0
  45. meltygui/completion/providers/copilot.py +617 -0
  46. meltygui/completion/providers/oauth_popup.py +220 -0
  47. meltygui/completion/providers/ollama.py +320 -0
  48. meltygui/completion/providers/profiles.py +23 -0
  49. meltygui/core/README.md +88 -0
  50. meltygui/core/__init__.py +1 -0
  51. meltygui/core/automation/__init__.py +1 -0
  52. meltygui/core/automation/action_core.py +153 -0
  53. meltygui/core/automation/collection_action.py +45 -0
  54. meltygui/core/automation/mcp_eval.py +167 -0
  55. meltygui/core/automation/mcp_hotswap.py +107 -0
  56. meltygui/core/automation/mcp_query.py +552 -0
  57. meltygui/core/automation/mcp_server.py +657 -0
  58. meltygui/core/automation/orchestration_core.py +2636 -0
  59. meltygui/core/automation/query_core.py +124 -0
  60. meltygui/core/automation/search_core.py +26 -0
  61. meltygui/core/automation/selector_core.py +340 -0
  62. meltygui/core/automation/value_core.py +1752 -0
  63. meltygui/core/cache/__init__.py +1 -0
  64. meltygui/core/cache/cache_diagnostics.py +0 -0
  65. meltygui/core/cache/invalidation_decoration.py +153 -0
  66. meltygui/core/cache/invalidation_tracker.py +43 -0
  67. meltygui/core/cache/tile_cache.py +5968 -0
  68. meltygui/core/conversion/__init__.py +1 -0
  69. meltygui/core/conversion/bubbling.py +599 -0
  70. meltygui/core/conversion/cache_tree.py +188 -0
  71. meltygui/core/conversion/chain.py +113 -0
  72. meltygui/core/conversion/converter_register.py +145 -0
  73. meltygui/core/conversion/data_decoration.py +67 -0
  74. meltygui/core/conversion/dict_conversion.py +1815 -0
  75. meltygui/core/conversion/dict_conversion_util.py +177 -0
  76. meltygui/core/conversion/dynamic_obj.py +89 -0
  77. meltygui/core/conversion/graph_compare.py +183 -0
  78. meltygui/core/conversion/load_save_v2.py +1032 -0
  79. meltygui/core/conversion/missing_saved_class.py +39 -0
  80. meltygui/core/conversion/path_finder.py +606 -0
  81. meltygui/core/conversion/render_host.py +1083 -0
  82. meltygui/core/core_render.py +6537 -0
  83. meltygui/core/definition_hotswap.py +231 -0
  84. meltygui/core/diagnostics/__init__.py +1 -0
  85. meltygui/core/diagnostics/attribute_churn.py +38 -0
  86. meltygui/core/diagnostics/fps_counter.py +39 -0
  87. meltygui/core/diagnostics/gpu_frame_timer.py +103 -0
  88. meltygui/core/diagnostics/inspection_core.py +169 -0
  89. meltygui/core/diagnostics/monitor_core.py +105 -0
  90. meltygui/core/diagnostics/notifications.py +706 -0
  91. meltygui/core/diagnostics/perf_trace.py +281 -0
  92. meltygui/core/diagnostics/profile_decoration.py +88 -0
  93. meltygui/core/diagnostics/resize_trace.py +62 -0
  94. meltygui/core/diagnostics/screenshot_core.py +247 -0
  95. meltygui/core/diagnostics/session_status.py +98 -0
  96. meltygui/core/diagnostics/trace_core.py +445 -0
  97. meltygui/core/files/__init__.py +1 -0
  98. meltygui/core/files/file_core.py +208 -0
  99. meltygui/core/files/file_explorer_core.py +104 -0
  100. meltygui/core/files/file_tree_core.py +198 -0
  101. meltygui/core/files/file_watch_core.py +43 -0
  102. meltygui/core/files/import_graph_core.py +43 -0
  103. meltygui/core/files/metadata_core.py +51 -0
  104. meltygui/core/graphics/__init__.py +1 -0
  105. meltygui/core/graphics/cuda_context_core.py +166 -0
  106. meltygui/core/graphics/cuda_interop_core.py +136 -0
  107. meltygui/core/graphics/cuda_kernel_core.py +91 -0
  108. meltygui/core/graphics/framebuffer_recorder.py +337 -0
  109. meltygui/core/graphics/gl_state.py +658 -0
  110. meltygui/core/graphics/lut_core.py +52 -0
  111. meltygui/core/graphics/overlay_renderer.py +984 -0
  112. meltygui/core/graphics/scene_target.py +180 -0
  113. meltygui/core/graphics/screenshot.py +439 -0
  114. meltygui/core/graphics/shader_func.py +478 -0
  115. meltygui/core/graphics/tensor_core.py +45 -0
  116. meltygui/core/graphics/text_texture.py +329 -0
  117. meltygui/core/graphics/wayland_color.py +635 -0
  118. meltygui/core/input/__init__.py +1 -0
  119. meltygui/core/input/collision.py +165 -0
  120. meltygui/core/input/drag_drop_core.py +1525 -0
  121. meltygui/core/input/hypr_left_drag.py +323 -0
  122. meltygui/core/input/input_core.py +245 -0
  123. meltygui/core/input/input_handler.py +1101 -0
  124. meltygui/core/input/mouse_cursor.py +355 -0
  125. meltygui/core/input/pynput_backend.py +1054 -0
  126. meltygui/core/input/space_mouse.py +338 -0
  127. meltygui/core/input/touchpad_backend.py +393 -0
  128. meltygui/core/input/view_selection.py +177 -0
  129. meltygui/core/layout/__init__.py +1 -0
  130. meltygui/core/layout/column_core.py +2153 -0
  131. meltygui/core/layout/cursor_core.py +161 -0
  132. meltygui/core/layout/dropdown_core.py +278 -0
  133. meltygui/core/layout/edge_constraints.py +155 -0
  134. meltygui/core/layout/grid_core.py +117 -0
  135. meltygui/core/layout/header_core.py +23 -0
  136. meltygui/core/layout/header_runtime.py +67 -0
  137. meltygui/core/layout/layout_core.py +87 -0
  138. meltygui/core/layout/tile_manager_core.py +591 -0
  139. meltygui/core/melty.py +6726 -0
  140. meltygui/core/module_map.json +896 -0
  141. meltygui/core/module_names.py +19 -0
  142. meltygui/core/rendering/__init__.py +1 -0
  143. meltygui/core/rendering/core_decoration.py +431 -0
  144. meltygui/core/rendering/core_render_helpers.py +328 -0
  145. meltygui/core/rendering/func_metadata.py +398 -0
  146. meltygui/core/rendering/mode.py +818 -0
  147. meltygui/core/rendering/mode_defaults.py +41 -0
  148. meltygui/core/rendering/modes.py +136 -0
  149. meltygui/core/rendering/parameter_core.py +1665 -0
  150. meltygui/core/rendering/render_dispatch.py +1891 -0
  151. meltygui/core/rendering/render_funcs.py +273 -0
  152. meltygui/core/rendering/shaped.py +312 -0
  153. meltygui/core/rendering/window_decoration.py +25 -0
  154. meltygui/core/runtime/__init__.py +1 -0
  155. meltygui/core/runtime/app.py +735 -0
  156. meltygui/core/runtime/app_session.py +140 -0
  157. meltygui/core/runtime/background.py +564 -0
  158. meltygui/core/runtime/extensions.py +53 -0
  159. meltygui/core/runtime/gc_manager.py +1163 -0
  160. meltygui/core/runtime/lifecycle.py +21 -0
  161. meltygui/core/runtime/paths.py +27 -0
  162. meltygui/core/runtime/settings.py +14 -0
  163. meltygui/core/runtime/singleton.py +16 -0
  164. meltygui/core/runtime/thread_safe_bool.py +24 -0
  165. meltygui/core/runtime/thread_signal.py +30 -0
  166. meltygui/core/runtime/toggles.py +3115 -0
  167. meltygui/core/services/__init__.py +1 -0
  168. meltygui/core/services/account_core.py +10 -0
  169. meltygui/core/services/chat_core.py +19 -0
  170. meltygui/core/services/claude_terminal_core.py +346 -0
  171. meltygui/core/services/terminal_core.py +458 -0
  172. meltygui/core/services/terminal_runtime.py +78 -0
  173. meltygui/core/styling/__init__.py +1 -0
  174. meltygui/core/styling/color_core.py +46 -0
  175. meltygui/core/styling/fonts.py +639 -0
  176. meltygui/core/styling/global_style.py +338 -0
  177. meltygui/core/styling/style.py +198 -0
  178. meltygui/core/styling/style_core.py +522 -0
  179. meltygui/core/styling/warm_start.py +149 -0
  180. meltygui/core/windowing/__init__.py +1 -0
  181. meltygui/core/windowing/backends/PYIMGUI_LICENSE +28 -0
  182. meltygui/core/windowing/backends/__init__.py +1 -0
  183. meltygui/core/windowing/backends/imgui_renderer.py +138 -0
  184. meltygui/core/windowing/backends/native_wayland.py +850 -0
  185. meltygui/core/windowing/backends/protocols/xdg-decoration-unstable-v1.xml +156 -0
  186. meltygui/core/windowing/backends/protocols/xdg-shell.xml +1420 -0
  187. meltygui/core/windowing/backends/wayland_protocol.py +101 -0
  188. meltygui/core/windowing/dock_core.py +182 -0
  189. meltygui/core/windowing/frame_geometry.py +42 -0
  190. meltygui/core/windowing/geometry_feed.py +864 -0
  191. meltygui/core/windowing/glfw_utils.py +1343 -0
  192. meltygui/core/windowing/os_frame.py +1552 -0
  193. meltygui/core/windowing/surface.py +643 -0
  194. meltygui/core/windowing/titlebar.py +1560 -0
  195. meltygui/core/windowing/titlebar_buttons.py +281 -0
  196. meltygui/core/windowing/wayland_move.py +932 -0
  197. meltygui/core/windowing/window_api.py +62 -0
  198. meltygui/core/windowing/window_constants.py +339 -0
  199. meltygui/core/windowing/window_visibility.py +162 -0
  200. meltygui/debug/__init__.py +0 -0
  201. meltygui/debug/app_view_utils.py +9 -0
  202. meltygui/editor/__init__.py +0 -0
  203. meltygui/editor/bash_syntax.py +30 -0
  204. meltygui/editor/code_line_fast.py +152 -0
  205. meltygui/editor/diff.py +139 -0
  206. meltygui/editor/external_changes.py +159 -0
  207. meltygui/editor/file_header.py +41 -0
  208. meltygui/editor/live_usage.py +169 -0
  209. meltygui/editor/live_view_views.py +1803 -0
  210. meltygui/editor/pending_save.py +1351 -0
  211. meltygui/editor/roster_tints.py +547 -0
  212. meltygui/editor/source_preview.py +16 -0
  213. meltygui/editor/source_tools.py +10 -0
  214. meltygui/editor/source_ui.py +70 -0
  215. meltygui/editor/spell_check.py +77 -0
  216. meltygui/editor/text_editor.py +9076 -0
  217. meltygui/editor/usage_picker.py +538 -0
  218. meltygui/events/__init__.py +0 -0
  219. meltygui/events/example.py +118 -0
  220. meltygui/examples/__init__.py +0 -0
  221. meltygui/examples/columns_demo.py +33 -0
  222. meltygui/examples/columns_window_demo.py +60 -0
  223. meltygui/examples/context_menu_demo.py +24 -0
  224. meltygui/examples/context_menu_window_demo.py +49 -0
  225. meltygui/examples/gui_playground.py +127 -0
  226. meltygui/examples/live_view_playground.py +256 -0
  227. meltygui/examples/lora.py +43 -0
  228. meltygui/examples/lora_data.py +59 -0
  229. meltygui/examples/lora_policies.py +67 -0
  230. meltygui/examples/mode_demo.py +49 -0
  231. meltygui/examples/modifies_demo.py +119 -0
  232. meltygui/examples/scalar_policies.py +60 -0
  233. meltygui/examples/style_layouts.py +149 -0
  234. meltygui/examples/tile_manager_demo.py +74 -0
  235. meltygui/examples/tint_demo.py +160 -0
  236. meltygui/examples/tint_functions.py +56 -0
  237. meltygui/examples/trace_demo.py +88 -0
  238. meltygui/examples/two_windows.py +36 -0
  239. meltygui/files/__init__.py +0 -0
  240. meltygui/files/fast_file_explorer.py +439 -0
  241. meltygui/gnome_extension/lsd-window-geometry@latent-descent/extension.js +237 -0
  242. meltygui/gnome_extension/lsd-window-geometry@latent-descent/lsd-window-geometry@latent-descent.iml +9 -0
  243. meltygui/gnome_extension/lsd-window-geometry@latent-descent/metadata.json +7 -0
  244. meltygui/graphics/__init__.py +6 -0
  245. meltygui/graphics/base.py +85 -0
  246. meltygui/graphics/examples.py +507 -0
  247. meltygui/graphics/executor.py +520 -0
  248. meltygui/graphics/filter.py +667 -0
  249. meltygui/graphics/filter.pyi +856 -0
  250. meltygui/graphics/generate_stubs.py +22 -0
  251. meltygui/graphics/registry.py +203 -0
  252. meltygui/graphics/shader_compiler.py +155 -0
  253. meltygui/graphics/shaders.py +1302 -0
  254. meltygui/graphics/stub_generator.py +250 -0
  255. meltygui/graphics/texture_manager.py +170 -0
  256. meltygui/graphics/texture_min_max.py +295 -0
  257. meltygui/hdr_color.py +757 -0
  258. meltygui/image_load.py +308 -0
  259. meltygui/model/__init__.py +1 -0
  260. meltygui/model/account_model.py +142 -0
  261. meltygui/model/camera_model.py +159 -0
  262. meltygui/model/chat_model.py +86 -0
  263. meltygui/model/code_model.py +62 -0
  264. meltygui/model/code_proxy_model.py +876 -0
  265. meltygui/model/collection_model.py +41 -0
  266. meltygui/model/color_model.py +127 -0
  267. meltygui/model/cuda_tensor_model.py +36 -0
  268. meltygui/model/cuda_texture_model.py +149 -0
  269. meltygui/model/dropdown_model.py +137 -0
  270. meltygui/model/file_metadata_model.py +73 -0
  271. meltygui/model/file_model.py +289 -0
  272. meltygui/model/format_model.py +390 -0
  273. meltygui/model/graph_model.py +98 -0
  274. meltygui/model/icon_model.py +1024 -0
  275. meltygui/model/import_graph_model.py +468 -0
  276. meltygui/model/layout_model.py +15 -0
  277. meltygui/model/lut_model.py +266 -0
  278. meltygui/model/search_model.py +173 -0
  279. meltygui/model/tensor_model.py +402 -0
  280. meltygui/model/terminal_model.py +329 -0
  281. meltygui/model/texture_model.py +146 -0
  282. meltygui/model/tile_model.py +24 -0
  283. meltygui/model/trace_model.py +198 -0
  284. meltygui/model/trace_report_model.py +146 -0
  285. meltygui/models/__init__.py +0 -0
  286. meltygui/models/file_meta.py +613 -0
  287. meltygui/models/function_console.py +184 -0
  288. meltygui/models/orchestration.py +48 -0
  289. meltygui/pbr.py +1576 -0
  290. meltygui/png_unfilter.c +49 -0
  291. meltygui/resources/JetBrainsMono-Regular.ttf +0 -0
  292. meltygui/resources/THIRD_PARTY_NOTICES.md +21 -0
  293. meltygui/resources/dejavu/DejaVuSans-Bold.ttf +0 -0
  294. meltygui/resources/dejavu/DejaVuSans-ExtraLight.ttf +0 -0
  295. meltygui/resources/dejavu/DejaVuSans.ttf +0 -0
  296. meltygui/resources/dejavu/LICENSE.txt +78 -0
  297. meltygui/resources/fontawesome-LICENSE.txt +121 -0
  298. meltygui/resources/fontawesome-webfont.ttf +0 -0
  299. meltygui/resources/hdri/studio_small_09_1k.hdr +0 -0
  300. meltygui/resources/jetbrains-weights/JetBrainsMono-Bold.ttf +0 -0
  301. meltygui/resources/jetbrains-weights/JetBrainsMono-ExtraBold.ttf +0 -0
  302. meltygui/resources/jetbrains-weights/JetBrainsMono-ExtraLight.ttf +0 -0
  303. meltygui/resources/jetbrains-weights/JetBrainsMono-Light.ttf +0 -0
  304. meltygui/resources/jetbrains-weights/JetBrainsMono-Medium.ttf +0 -0
  305. meltygui/resources/jetbrains-weights/JetBrainsMono-SemiBold.ttf +0 -0
  306. meltygui/resources/jetbrains-weights/JetBrainsMono-Thin.ttf +0 -0
  307. meltygui/resources/jetbrains-weights/OFL.txt +93 -0
  308. meltygui/resources/jetbrains-weights/README.md +2 -0
  309. meltygui/state/__init__.py +0 -0
  310. meltygui/state/account_state.py +22 -0
  311. meltygui/state/animation_state.py +97 -0
  312. meltygui/state/annotation_state.py +22 -0
  313. meltygui/state/chat_state.py +36 -0
  314. meltygui/state/code_state.py +10 -0
  315. meltygui/state/core_enums.py +59 -0
  316. meltygui/state/core_markers.py +115 -0
  317. meltygui/state/core_undo.py +1075 -0
  318. meltygui/state/file_state.py +75 -0
  319. meltygui/state/graph_state.py +26 -0
  320. meltygui/state/inspection_state.py +47 -0
  321. meltygui/state/menu_state.py +10 -0
  322. meltygui/state/model_enums.py +11 -0
  323. meltygui/state/new_core_model.py +2394 -0
  324. meltygui/state/orchestration_state.py +14 -0
  325. meltygui/state/query_state.py +24 -0
  326. meltygui/state/tensor_state.py +10 -0
  327. meltygui/state/terminal_state.py +23 -0
  328. meltygui/state/trace_state.py +32 -0
  329. meltygui/state/voxel_state.py +12 -0
  330. meltygui/text_index.py +816 -0
  331. meltygui/utils/__init__.py +0 -0
  332. meltygui/utils/jump_to_code.py +344 -0
  333. meltygui/utils/pkl_inspect.py +90 -0
  334. meltygui/utils/render_utils.py +1419 -0
  335. meltygui/view/__init__.py +1 -0
  336. meltygui/view/account_view.py +524 -0
  337. meltygui/view/action_view.py +73 -0
  338. meltygui/view/chat_decoration_view.py +112 -0
  339. meltygui/view/chat_view.py +1703 -0
  340. meltygui/view/code_view.py +2677 -0
  341. meltygui/view/collection_view.py +1185 -0
  342. meltygui/view/color_view.py +824 -0
  343. meltygui/view/control_view.py +559 -0
  344. meltygui/view/decoration_view.py +439 -0
  345. meltygui/view/diagnostic_view.py +177 -0
  346. meltygui/view/dropdown_view.py +1082 -0
  347. meltygui/view/file_view.py +1599 -0
  348. meltygui/view/graph_cuda_view.py +105 -0
  349. meltygui/view/graph_view.py +882 -0
  350. meltygui/view/header_view.py +848 -0
  351. meltygui/view/input_view.py +238 -0
  352. meltygui/view/inspection_view.py +1783 -0
  353. meltygui/view/layout_view.py +596 -0
  354. meltygui/view/lut_view.py +45 -0
  355. meltygui/view/menu_view.py +212 -0
  356. meltygui/view/orchestration_view.py +658 -0
  357. meltygui/view/query_view.py +118 -0
  358. meltygui/view/search_view.py +342 -0
  359. meltygui/view/tab_view.py +258 -0
  360. meltygui/view/tensor_view.py +430 -0
  361. meltygui/view/terminal_view.py +355 -0
  362. meltygui/view/text_view.py +8031 -0
  363. meltygui/view/texture_view.py +480 -0
  364. meltygui/view/tile_view.py +38 -0
  365. meltygui/view/trace_view.py +923 -0
  366. meltygui/view/voxel_cuda_view.py +824 -0
  367. meltygui/view/voxel_view.py +1860 -0
  368. meltygui/view/window_view.py +111 -0
  369. meltygui-0.1.0.dist-info/METADATA +143 -0
  370. meltygui-0.1.0.dist-info/RECORD +372 -0
  371. meltygui-0.1.0.dist-info/WHEEL +4 -0
  372. meltygui-0.1.0.dist-info/licenses/LICENSE +202 -0
@@ -0,0 +1,166 @@
1
+ """Shared CUDA context ownership for rendering and GL interop.
2
+
3
+ Per-device kernel leases live as long as compiled kernels; the standalone display
4
+ stack entry has a separate lease so popping it cannot invalidate cached kernels.
5
+ Both use CUDA primary contexts, so Torch storage remains directly accessible.
6
+ """
7
+ import atexit
8
+ from contextlib import contextmanager
9
+ import ctypes
10
+ import sys
11
+ import threading
12
+
13
+ from meltygui.core.melty import Melty
14
+ from meltygui.core.graphics.gl_state import is_gl_thread
15
+
16
+
17
+ class CudaContextRuntime:
18
+ def __init__(self):
19
+ self.contexts = {}
20
+ self.kernels = {}
21
+ self.legacy_kernels = None
22
+ self.primary_context = None
23
+ self.primary_thread = None
24
+ self.last_logged = None
25
+ self.driver_library = None
26
+
27
+
28
+ def runtime():
29
+ if Melty.cuda_interop is None:
30
+ Melty.cuda_interop = CudaContextRuntime()
31
+ state = Melty.cuda_interop
32
+ # Transfer the old cache's context leases without reacquiring resources.
33
+ # Existing interop runtime objects gain the pool on first use after hotswap.
34
+ if 'contexts' not in state.__dict__:
35
+ state.contexts = {}
36
+ state.contexts.update(sys.__dict__.pop('_lsd_cuda_march_contexts', {}))
37
+ return state
38
+
39
+
40
+ def primary_context_for(device):
41
+ """Retain a render-thread primary context for compiled kernels on a device."""
42
+ if not is_gl_thread():
43
+ raise RuntimeError('rendering CUDA contexts belong to the render thread')
44
+ device = int(device)
45
+ contexts = runtime().contexts
46
+ if device not in contexts:
47
+ import meltygui_pycuda.driver as cuda
48
+ cuda.init()
49
+ contexts[device] = cuda.Device(device).retain_primary_context()
50
+ return contexts[device]
51
+
52
+
53
+ @contextmanager
54
+ def using_device(device):
55
+ """Run on a tensor's GPU and restore PyCUDA and native caller contexts."""
56
+ with using_context(primary_context_for(device)):
57
+ yield
58
+
59
+
60
+ def ensure_primary_context(device):
61
+ """Install the standalone render-thread stack entry when none exists."""
62
+ if not is_gl_thread():
63
+ return False
64
+ import meltygui_pycuda.driver as cuda
65
+ cuda.init()
66
+ state = runtime()
67
+ if cuda.Context.get_current() is not None or state.primary_context is not None:
68
+ return False
69
+ context = cuda.Device(int(device)).retain_primary_context()
70
+ try:
71
+ context.push()
72
+ except Exception:
73
+ detach_inactive_primary(context)
74
+ raise
75
+ state.primary_context = context
76
+ state.primary_thread = threading.current_thread()
77
+ atexit.register(_detach_primary)
78
+ return True
79
+
80
+
81
+ def _driver_library():
82
+ state = runtime()
83
+ if state.driver_library is None:
84
+ library = ctypes.CDLL('libcuda.so.1')
85
+ query = library.cuGLGetDevices_v2
86
+ query.argtypes = (ctypes.POINTER(ctypes.c_uint), ctypes.POINTER(ctypes.c_int),
87
+ ctypes.c_uint, ctypes.c_uint)
88
+ query.restype = ctypes.c_int
89
+ for name in ('cuCtxGetCurrent', 'cuCtxPopCurrent_v2'):
90
+ function = getattr(library, name)
91
+ function.argtypes = (ctypes.POINTER(ctypes.c_void_p),)
92
+ function.restype = ctypes.c_int
93
+ library.cuCtxSetCurrent.argtypes = (ctypes.c_void_p,)
94
+ library.cuCtxSetCurrent.restype = ctypes.c_int
95
+ state.driver_library = library
96
+ return state.driver_library
97
+
98
+
99
+ def _native_context():
100
+ context = ctypes.c_void_p()
101
+ result = _driver_library().cuCtxGetCurrent(ctypes.byref(context))
102
+ if result != 0:
103
+ raise RuntimeError(f"cuCtxGetCurrent failed: {result}")
104
+ return context.value
105
+
106
+
107
+ def current_device_index():
108
+ """The CUDA ordinal of the context current on this thread, or None."""
109
+ import meltygui_pycuda.driver as cuda
110
+ if cuda.Context.get_current() is None:
111
+ return None
112
+ bus = cuda.Context.get_device().pci_bus_id()
113
+ for index in range(cuda.Device.count()):
114
+ if cuda.Device(index).pci_bus_id() == bus:
115
+ return index
116
+ return None
117
+
118
+
119
+ def _detach_primary():
120
+ state = runtime()
121
+ if state.primary_context is None:
122
+ return
123
+ import meltygui_pycuda.driver as cuda
124
+ if (threading.current_thread() is not state.primary_thread
125
+ or cuda.Context.get_current() != state.primary_context):
126
+ # Popping someone else's stack entry corrupts its owner's lifetime.
127
+ return
128
+ cuda.Context.pop()
129
+ detach_inactive_primary(state.primary_context)
130
+ state.primary_context = None
131
+ state.primary_thread = None
132
+
133
+
134
+ def detach_inactive_primary(context):
135
+ """Release an owned primary-context lease AFTER removing its PyCUDA entry.
136
+
137
+ PyCUDA's inactive-context detach pushes the native context and assumes that
138
+ releasing it also pops it. cuDevicePrimaryCtxRelease explicitly does not pop
139
+ (cuda.h); balance that native push without touching PyCUDA's restored stack.
140
+ """
141
+ context.detach()
142
+ popped = ctypes.c_void_p()
143
+ result = _driver_library().cuCtxPopCurrent_v2(ctypes.byref(popped))
144
+ if result != 0:
145
+ raise RuntimeError(f"cuCtxPopCurrent after primary release failed: {result}")
146
+
147
+
148
+ @contextmanager
149
+ def using_context(context):
150
+ """Temporarily restore a registration's CUDA context, preserving the stack."""
151
+ import meltygui_pycuda.driver as cuda
152
+ previous_native = _native_context()
153
+ pushed = cuda.Context.get_current() != context or previous_native != context.handle
154
+ if pushed:
155
+ context.push()
156
+ try:
157
+ yield
158
+ finally:
159
+ if pushed:
160
+ cuda.Context.pop()
161
+ # Torch may also switch the native context inside an already-current
162
+ # scope, where no PyCUDA push/pop was needed on entry.
163
+ if _native_context() != previous_native:
164
+ result = _driver_library().cuCtxSetCurrent(previous_native)
165
+ if result != 0:
166
+ raise RuntimeError(f"restoring CUDA context failed: {result}")
@@ -0,0 +1,136 @@
1
+ """CUDA context selection and registered-buffer operations for OpenGL interop.
2
+
3
+ The rendering context determines the device. Never register GL resources from an
4
+ unrelated CUDA device, even when Torch's current device happens to be that device.
5
+ Tensor adaptation and texture ownership live in model/cuda_texture_model.py.
6
+ """
7
+ from contextlib import contextmanager
8
+ import ctypes
9
+
10
+ from meltygui.core.graphics import cuda_context_core
11
+ from meltygui.core.graphics.gl_state import (
12
+ ResourceDeletionDeferred, current_context, is_gl_thread,
13
+ )
14
+
15
+
16
+ def log_once(message):
17
+ state = cuda_context_core.runtime()
18
+ if message != state.last_logged:
19
+ print(f"[cuda_interop] {message}")
20
+ state.last_logged = message
21
+
22
+
23
+ def gl_devices():
24
+ """CUDA ordinals associated with the current GL context, or none.
25
+
26
+ PyCUDA does not expose cuGLGetDevices; use the CUDA driver's public API.
27
+ The versioned symbol and enum values are declared in CUDA's cudaGL.h.
28
+ """
29
+ if not is_gl_thread() or current_context() is None:
30
+ return ()
31
+ import meltygui_pycuda.driver as cuda
32
+ cuda.init()
33
+ capacity = cuda.Device.count()
34
+ devices = (ctypes.c_int * capacity)()
35
+ count = ctypes.c_uint()
36
+ # CU_GL_DEVICE_LIST_ALL: all GPUs used by the current GL context.
37
+ result = cuda_context_core._driver_library().cuGLGetDevices_v2(ctypes.byref(count), devices, capacity, 1)
38
+ if result != 0:
39
+ return ()
40
+ return tuple(devices[:count.value])
41
+
42
+
43
+ def cuda_ready():
44
+ """Whether GL interop is safe in the current thread and context pair."""
45
+ if not is_gl_thread() or current_context() is None:
46
+ return False
47
+ try:
48
+ import meltygui_pycuda.driver as cuda
49
+ import meltygui_pycuda.gl
50
+ context = cuda.Context.get_current()
51
+ if context is None or context.handle != cuda_context_core._native_context():
52
+ return False
53
+ device = cuda_context_core.current_device_index()
54
+ return device is not None and device in gl_devices()
55
+ except Exception:
56
+ return False
57
+
58
+
59
+ def ensure_context():
60
+ """For standalone/test setup, retain the GL device's primary context.
61
+
62
+ An existing compatible context is left alone. An incompatible one is
63
+ rejected, not silently replaced. Only the context retained here is detached.
64
+ """
65
+ if not is_gl_thread() or current_context() is None:
66
+ return False
67
+ try:
68
+ import meltygui_pycuda.driver as cuda
69
+ import meltygui_pycuda.gl
70
+ devices = gl_devices()
71
+ if not devices:
72
+ return False
73
+ if cuda.Context.get_current() is not None:
74
+ return cuda_ready()
75
+ return cuda_context_core.ensure_primary_context(devices[0])
76
+ except Exception as error:
77
+ log_once(f"ensure_context failed: {error}")
78
+ return False
79
+
80
+
81
+ def register_buffer(buffer):
82
+ if not cuda_ready():
83
+ raise RuntimeError("CUDA registration requires a compatible current GL/CUDA context pair")
84
+ from meltygui_pycuda import gl as cuda_gl
85
+ return cuda_gl.RegisteredBuffer(buffer, cuda_gl.graphics_map_flags.WRITE_DISCARD)
86
+
87
+
88
+ @contextmanager
89
+ def interop_context():
90
+ """Activate a GL-compatible context for one adapter operation.
91
+
92
+ Torch can change the native context while PyCUDA still records the rendering
93
+ context. Reactivate that context locally, validate its GL device, and restore
94
+ the caller's native context afterward. A genuinely incompatible PyCUDA context
95
+ is rejected. Standalone callers with no PyCUDA context get lazy setup.
96
+ """
97
+ if not is_gl_thread() or current_context() is None:
98
+ yield None
99
+ return
100
+ try:
101
+ import meltygui_pycuda.driver as cuda
102
+ import meltygui_pycuda.gl
103
+ context = cuda.Context.get_current()
104
+ if context is None and ensure_context():
105
+ context = cuda.Context.get_current()
106
+ except Exception:
107
+ context = None
108
+ if context is None:
109
+ yield None
110
+ return
111
+ with cuda_context_core.using_context(context):
112
+ yield context if cuda_ready() else None
113
+
114
+
115
+ def copy_to_buffer(registered, context, pointer, nbytes):
116
+ """Copy ready device storage into a mapped GL buffer and unmap on failure."""
117
+ import meltygui_pycuda.driver as cuda
118
+ with cuda_context_core.using_context(context):
119
+ mapping = registered.map()
120
+ try:
121
+ destination, capacity = mapping.device_ptr_and_size()
122
+ if capacity < nbytes:
123
+ raise ValueError(f"CUDA buffer has {capacity} bytes; upload needs {nbytes}")
124
+ cuda.memcpy_dtod(destination, pointer, nbytes)
125
+ cuda.Context.synchronize()
126
+ finally:
127
+ mapping.unmap()
128
+
129
+
130
+ def unregister_buffer(registered, context):
131
+ try:
132
+ with cuda_context_core.using_context(context):
133
+ registered.unregister()
134
+ except Exception as error:
135
+ log_once(f"unregister deferred: {error}")
136
+ raise ResourceDeletionDeferred from error
@@ -0,0 +1,91 @@
1
+ """Render-thread CUDA compilation and process-lifetime kernel ownership.
2
+
3
+ Feature views supply CUDA source and entry points. Melty's CUDA runtime retains
4
+ modules alongside their primary contexts, including across definition hotswaps.
5
+ """
6
+ import sys
7
+
8
+ from meltygui.core.graphics.cuda_context_core import runtime, using_device
9
+
10
+
11
+ def available():
12
+ try:
13
+ import meltygui_pycuda.driver
14
+ import meltygui_pycuda as pycuda # noqa: F401
15
+ return True
16
+ except Exception:
17
+ return False
18
+
19
+
20
+ def host_compiler_flags():
21
+ """Use an installed CUDA-12-compatible C++ compiler when available."""
22
+ import shutil
23
+ for version in ("12", "11", "10"):
24
+ if shutil.which("gcc-" + version) and shutil.which("g++-" + version):
25
+ return ["-ccbin", "g++-" + version]
26
+ return ["-allow-unsupported-compiler"]
27
+
28
+
29
+ class CudaKernel:
30
+ def __init__(self, source, module, functions):
31
+ self.source = source
32
+ self.module = module
33
+ self.functions = functions
34
+
35
+
36
+ def _cache():
37
+ state = runtime()
38
+ if 'kernels' not in state.__dict__:
39
+ state.kernels = {}
40
+ # One-time runtime transfer, not import compatibility. Keep existing compiled
41
+ # functions alive until their feature is next requested under its context.
42
+ if 'legacy_kernels' not in state.__dict__ or state.legacy_kernels is None:
43
+ state.legacy_kernels = {
44
+ 'voxels': sys.__dict__.pop('_lsd_cuda_march_kernels', {}),
45
+ 'lines': sys.__dict__.pop('_melty_cuda_line_kernels', {}),
46
+ }
47
+ return state.kernels
48
+
49
+
50
+ def kernel_functions(feature, device, source, names):
51
+ """Compile a feature's entry points once per source/device.
52
+
53
+ A failed replacement leaves the last good module owned by the runtime.
54
+ Replacement and destruction happen with the owning device context active.
55
+ Unchanged source after hotswap retains the same function objects.
56
+ """
57
+ device = int(device)
58
+ names = tuple(names)
59
+ # This also enforces the render-thread contract on hits and before adopting
60
+ # old entries; none of the runtime dictionaries can be mutated by workers.
61
+ with using_device(device):
62
+ cache = _cache()
63
+ key = (feature, device, names)
64
+ entry = cache.get(key)
65
+ if entry is not None and entry.source == source:
66
+ return entry.functions
67
+ legacy = runtime().legacy_kernels.get(feature, {}).get(device)
68
+ if legacy is not None:
69
+ if feature == 'voxels' and isinstance(legacy, dict) and legacy.get('__source__') == hash(source):
70
+ entry = CudaKernel(source, None, {name: legacy[name] for name in names})
71
+ elif feature == 'lines' and legacy[0] == source:
72
+ entry = CudaKernel(source, legacy[1], dict(zip(names, legacy[2:])))
73
+ if entry is not None and entry.source == source:
74
+ cache[key] = entry
75
+ runtime().legacy_kernels[feature].pop(device)
76
+ return entry.functions
77
+ import meltygui_pycuda.driver as cuda
78
+ from meltygui_pycuda.compiler import SourceModule
79
+ capability = cuda.Device(device).compute_capability()
80
+ module = SourceModule(source, no_extern_c=True, arch='sm_%d%d' % capability,
81
+ options=['-O3'] + host_compiler_flags())
82
+ try:
83
+ functions = {name: module.get_function(name) for name in names}
84
+ except Exception:
85
+ del module
86
+ raise
87
+ cache[key] = CudaKernel(source, module, functions)
88
+ runtime().legacy_kernels.get(feature, {}).pop(device, None)
89
+ # Drop replaced and transferred references while the context is active.
90
+ del entry, legacy
91
+ return functions