MXVK Vulkan Framework 0.35.0
C++20 Vulkan rendering framework for practical 2D and 3D application development with SDL3.
Loading...
Searching...
No Matches
main.py
Go to the documentation of this file.
1#!/usr/bin/env python3
2## @file main.py
3## @brief MXVK Python compute-shader post-processing example.
4## @details Loads an image sprite, attaches a compute post-processing shader,
5## and updates shader mouse, timing, frame-rate, and audio-style uniforms.
6## The shader is inspected before use, preventing a fragment or vertex SPIR-V
7## module from being attached as a compute effect.
8##
9## @section compute_run Running the example
10## @code{.sh}
11## python3 python-examples/compute/main.py --filename inter.comp.spv --vsync
12## @endcode
13## @section compute_controls Controls
14## - Move the mouse to update the shader mouse position.
15## - Hold the left mouse button to set the shader pressed state.
16## - Escape: exit.
17## @section compute_flow Rendering flow
18## @c SpriteWindow queues the source sprite in @c proc(), then MXVK runs the
19## @c PostProcessingEffect compute stage and presents its output. The explicit
20## @c close() method detaches the effect before releasing native resources.
21
22import argparse
23import time
24from pathlib import Path
25
26import mxvk_ext as mxvk
27
28
29EXAMPLE_DIR = Path(__file__).resolve().parent
30DATA_DIR = EXAMPLE_DIR / "data"
31
32
34 def __init__(self, filename: str, width: int, height: int, fullscreen: bool, enable_vsync: bool) -> None:
35 super().__init__("VK_Example", width, height, fullscreen, False, enable_vsync)
36
37 self.fallback_width = width
38 self.fallback_height = height
39 self._closed = False
40 self.start_time = time.monotonic()
42 self.frame_count = 0
43 self.mouse_x = 0.0
44 self.mouse_y = 0.0
45 self.mouse_pressed = False
46 self.alpha = 1.0
47 self.alpha_direction = 1.0
48 self.amp = 0.0
49 self.iamp = 0.0
50 self.amp_peak = 0.0
51 self.amp_rms = 0.0
52 self.amp_smooth = 0.0
53 self.amp_low = 0.0
54 self.amp_mid = 0.0
55 self.amp_high = 0.0
56 self.sample_rate = 44100.0
57 self.set_font(str(DATA_DIR / "font.ttf"), 24)
58 self.sprite = self.create_sprite(str(DATA_DIR / "intro.png"), str(DATA_DIR / "sprite.vert.spv"), str(DATA_DIR / "fragment.frag.spv"))
59 compute_path = DATA_DIR / filename
60 info = mxvk.inspect_spirv_file(str(compute_path))
61
62 if(info.stage != mxvk.ShaderStage.compute):
63 raise RuntimeError(f"{compute_path} is not a compute shader")
64
65 effect = mxvk.PostProcessingEffect()
66 effect.fragment_shader_path = str(compute_path)
67 effect.stage = mxvk.ShaderStage.compute
68 effect.time_enabled = False
69 self.effects = [effect]
70 self.post_sprites = self.attach_post_processing_shaders(self.effects)
72 self.compute_sprite.set_custom_uniforms([1.0, 0.018, 0.35, 0.12])
73 self.set_post_processing_enabled(True)
74
75 def close(self) -> None:
76 if(self._closed):
77 return
78
79 self._closed = True
80
81 try:
82 self.detach_post_processing_shader()
83 self.compute_sprite = None
84 self.post_sprites = None
85 self.effects = None
86 self.sprite = None
87 finally:
88 self.release()
89
90 def update_uniforms(self, width: int, height: int) -> None:
91 now = time.monotonic()
92 elapsed = now - self.start_time
93 delta_time = now - self.last_time
94 self.last_time = now
95
96 if(delta_time > 0.0):
97 frame_rate = 1.0 / delta_time
98 else:
99 frame_rate = 0.0
100
101 self.alpha += 0.1 * self.alpha_direction
102
103 if(self.alpha >= 6.0):
104 self.alpha = 6.0
105 self.alpha_direction = -1.0
106 elif(self.alpha <= 1.0):
107 self.alpha = 1.0
108 self.alpha_direction = 1.0
109
110 self.compute_sprite.set_mouse_state(self.mouse_x, self.mouse_y, 1.0 if self.mouse_pressed else 0.0, 0.0)
111 self.compute_sprite.set_uniform0(self.alpha, elapsed, float(width), float(height))
112 self.compute_sprite.set_uniform1(delta_time, self.amp, self.iamp, frame_rate)
113 self.compute_sprite.set_uniform2(float(self.frame_count), elapsed, self.sample_rate, self.amp_peak)
114 self.compute_sprite.set_uniform3(0.0, 0.0, self.amp_rms, self.amp_smooth)
115 self.compute_sprite.set_audio_bands(self.amp_low, self.amp_mid, self.amp_high, 0.0)
116
117 def proc(self) -> None:
118 width, height = self.swapchain_extent
119
120 if(width <= 0 or height <= 0):
121 width = self.fallback_width
122 height = self.fallback_height
123
124 self.update_uniforms(width, height)
125 self.sprite.draw_rect(0, 0, width, height)
126 self.print_text("MXVK Compute Shader", 15, 15, mxvk.Color(255, 255, 255, 255))
127 self.frame_count += 1
128
129 def event(self, event: mxvk.Event) -> None:
130 if(event.type == mxvk.EVENT_KEY_DOWN):
131 if(event.key == mxvk.KEY_ESCAPE):
132 self.request_exit()
133 return
134
135 if(event.mouse_motion):
136 self.mouse_x = event.x
137 self.mouse_y = event.y
138 return
139
140 if(event.mouse_button_down):
141 if(event.button == mxvk.MOUSE_BUTTON_LEFT):
142 self.mouse_x = event.x
143 self.mouse_y = event.y
144 self.mouse_pressed = True
145 return
146
147 if(event.mouse_button_up):
148 if(event.button == mxvk.MOUSE_BUTTON_LEFT):
149 self.mouse_x = event.x
150 self.mouse_y = event.y
151 self.mouse_pressed = False
152 return
153
154
155def parse_args() -> argparse.Namespace:
156 parser = argparse.ArgumentParser(description="MXVK Python compute shader example")
157 parser.add_argument("--filename", type=str, default="inter.comp.spv")
158 parser.add_argument("--width", type=int, default=1280)
159 parser.add_argument("--height", type=int, default=720)
160 parser.add_argument("--fullscreen", action="store_true")
161 parser.add_argument("--vsync", action="store_true")
162 return parser.parse_args()
163
164
165def main() -> int:
166 args = parse_args()
167 window = None
168
169 try:
170 window = SpriteWindow(args.filename, args.width, args.height, args.fullscreen, args.vsync)
171 window.loop()
172 except mxvk.MXVKError as exception:
173 print(f"mxvk: Exception: {exception}")
174 return 1
175 finally:
176 if(window is not None):
177 window.close()
178
179 return 0
180
181
182if(__name__ == "__main__"):
183 raise SystemExit(main())
float amp_high
Definition main.py:55
float alpha
Definition main.py:46
float alpha_direction
Definition main.py:47
float sample_rate
Definition main.py:56
None close(self)
Definition main.py:75
float amp_rms
Definition main.py:51
None event(self, mxvk.Event event)
Definition main.py:129
float amp_low
Definition main.py:53
float amp_smooth
Definition main.py:52
None __init__(self, str filename, int width, int height, bool fullscreen, bool enable_vsync)
Definition main.py:34
float amp_peak
Definition main.py:50
bool mouse_pressed
Definition main.py:45
None update_uniforms(self, int width, int height)
Definition main.py:90
float mouse_y
Definition main.py:44
float amp_mid
Definition main.py:54
int frame_count
Definition main.py:42
float mouse_x
Definition main.py:43
Main Vulkan window wrapper for MXVK.
Definition mxvk.hpp:39
VkExtent2D swapchain_extent
Definition mxvk.hpp:616
void release()
Release Vulkan and SDL resources.
Definition mxvk.cpp:247
virtual void proc()
Execute one processing/update step.
Definition mxvk.cpp:1278
Definition main.py:1
int main()
Definition main.py:165
argparse.Namespace parse_args()
Definition main.py:155