MXVK Vulkan Framework 0.35.0
C++20 Vulkan rendering framework for practical 2D and 3D application development with SDL3.
Loading...
Searching...
No Matches
mxvk.hpp
Go to the documentation of this file.
1#pragma once
2
3#include "mxvk_context.hpp"
6#include "mxvk_sprite.hpp"
7#include "mxvk_sprite3d.hpp"
8#include "mxvk_text.hpp"
9#include <SDL3/SDL.h>
10#include <array>
11#include <chrono>
12#include <condition_variable>
13#include <cstdint>
14#include <deque>
15#include <limits>
16#include <memory>
17#include <mutex>
18#include <mxvk/mxvk_version.hpp>
19#include <optional>
20#include <string>
21#include <thread>
22#include <vector>
23#include <volk/volk.h>
24
25#ifdef ENABLE_VALIDATION
26#define MXVK_VALIDATION true
27#else
28#define MXVK_VALIDATION false
29#endif
30
31namespace mxvk {
32 /**
33 * @brief Main Vulkan window wrapper for MXVK.
34 *
35 * In windowed mode the class owns SDL window and Vulkan presentation
36 * resources. Headless mode renders to owned Vulkan images without
37 * initializing SDL video or creating a surface/swapchain.
38 */
39 class VK_Window {
40 public:
41 enum class PresentModePreference { LowLatency, Vsync };
42
43 enum class RuntimeMode { Windowed, Headless };
44
45 /**
46 * @brief Construct an empty window object.
47 */
48 VK_Window() = default;
49
50 /**
51 * @brief Destroy owned Vulkan and SDL resources.
52 */
53 virtual ~VK_Window();
54
55 /**
56 * @brief Release Vulkan and SDL resources.
57 *
58 * Safe to call multiple times.
59 */
60 void release();
61
62 /**
63 * @brief Construct and initialize a window and Vulkan context.
64 * @param title Window title string.
65 * @param width Window width in pixels.
66 * @param height Window height in pixels.
67 * @param full Enables fullscreen mode when true.
68 * @param validiation Enables validation-related behavior when true.
69 * @param presentModePreference Preferred swapchain present-mode policy.
70 * @param runtimeMode Selects windowed presentation or surface-free rendering.
71 */
72 VK_Window(const std::string &title, int width, int height, bool full = false, bool validiation = true, PresentModePreference presentModePreference = PresentModePreference::LowLatency, RuntimeMode runtimeMode = RuntimeMode::Windowed);
73 VK_Window(const std::string &title, int width, int height, bool full, bool validiation, bool enableVsync);
74
75 // no copy
76 VK_Window(const VK_Window &) = delete;
77 VK_Window(VK_Window &&) = delete;
78 VK_Window &operator=(const VK_Window &) = delete;
80
81 /**
82 * @brief Initialize Vulkan state.
83 * @param validiation Enables validation-related behavior when true.
84 * @return true on success, false otherwise.
85 */
86
87 virtual bool initVulkan(bool validiation);
88
89 /**
90 * @brief Handle one SDL event.
91 * @param e SDL event to process.
92 */
93 virtual void event(SDL_Event &e);
94
95 /**
96 * @brief Run the main event/render loop.
97 */
98 void loop();
99
100 /**
101 * @brief Render one frame.
102 */
103 virtual void render();
104
105 /**
106 * @brief Save the most recently rendered window contents as a PNG file.
107 * @param path Destination PNG path.
108 *
109 * This performs a synchronous GPU readback and may briefly stall rendering.
110 */
111 void saveSnapshot(const std::string &path);
112
113 /**
114 * @brief Record resource transitions that must happen before dynamic rendering begins.
115 *
116 * This callback is invoked after the command buffer begins recording and before
117 * vkCmdBeginRendering. Override this for resources that need per-frame image
118 * transitions or uploads before they are sampled by custom rendering.
119 *
120 * @param cmd Active command buffer in recording state, outside a rendering scope.
121 * @param image_index Current swapchain image index.
122 */
123 virtual void onPrepareFrameRendering(VkCommandBuffer cmd, uint32_t image_index);
124
125 /**
126 * @brief Execute one processing/update step.
127 */
128 virtual void proc();
129
130 /**
131 * @brief Set the active text-render font.
132 * @param fontPath Path to a TTF font file.
133 * @param fontSize Font point size.
134 */
135 void setFont(const std::string &fontPath, int fontSize = 24);
136
137 /** @brief Set the preview-only HUD font independently of output text. */
138 void setPreviewFont(const std::string &fontPath, int fontSize = 24);
139
140 /**
141 * @brief Queue a text string for rendering during the current frame.
142 * @param text UTF-8 text.
143 * @param x Pixel X coordinate.
144 * @param y Pixel Y coordinate.
145 * @param col Text color.
146 */
147 void printText(const std::string &text, int x, int y, const SDL_Color &col);
148 void printText(const std::string &text, int x, int y, const SDL_Color &col, TTF_Font *font);
149 void printText(const std::string &text, int x, int y, const SDL_Color &col, const Font &font);
150
151 /**
152 * @brief Queue preview-only text after frame readback.
153 *
154 * Unlike printText(), this text is visible in the presentation window
155 * but excluded from screenshots and frame-readback consumers.
156 */
157 void printPreviewText(const std::string &text, int x, int y, const SDL_Color &col);
158 void printPreviewText(const std::string &text, int x, int y, const SDL_Color &col, const Font &font);
159
160 /** @brief Clear all queued text draw calls for the current frame. */
161 void clearTextQueue();
162
163 /**
164 * @brief Set the per-frame color attachment clear color.
165 * @param r Red channel [0, 1].
166 * @param g Green channel [0, 1].
167 * @param b Blue channel [0, 1].
168 * @param a Alpha channel [0, 1].
169 */
170 void setClearColor(float r, float g, float b, float a = 1.0f);
171
172 /** @brief Enable or disable F10 screenshot capture. */
173 void setEnableScreenshot(bool enabled) noexcept;
174
175 /** @brief Check whether F10 screenshot capture is enabled. */
176 [[nodiscard]] bool screenshotEnabled() const noexcept { return screenshot_enabled; }
177
178 /**
179 * @brief Enable or disable readback of each rendered swapchain frame.
180 *
181 * Readback is recorded while the swapchain image is acquired and delivered
182 * through onFrameReadback() after the corresponding frame-in-flight fence
183 * completes. Readbacks are pipelined so recording does not add a same-frame
184 * GPU wait.
185 */
186 void setFrameReadbackEnabled(bool enabled) noexcept { frame_readback_enabled = enabled; }
187
188 /** @brief Request normalized RGBA16 callbacks from the final HDR intermediate. */
189 void setFrameReadbackRgba16Enabled(bool enabled) noexcept { frame_readback_rgba16_enabled = enabled; }
190
191 /** @brief Get the underlying SDL window handle. */
192 [[nodiscard]] SDL_Window *getSDLWindow() const noexcept { return window.get(); }
193
194 /** @brief Return true when rendering without SDL video, a surface, or presentation. */
195 [[nodiscard]] bool headless() const noexcept { return runtime_mode == RuntimeMode::Headless; }
196
197 /** @brief Get the Vulkan logical device handle. */
198 [[nodiscard]] VkDevice getDevice() const noexcept { return device; }
199
200 /** @brief Get the Vulkan physical device handle. */
201 [[nodiscard]] VkPhysicalDevice getPhysicalDevice() const noexcept { return physical_device; }
202
203 /** @brief Get the graphics queue handle. */
204 [[nodiscard]] VkQueue getGraphicsQueue() const noexcept { return graphics_queue; }
205
206 /** @brief Get the command pool used for graphics/upload work. */
207 [[nodiscard]] VkCommandPool getCommandPool() const noexcept { return command_pool; }
208
209 /** @brief Get the persistent Vulkan pipeline cache used by framework pipelines. */
210 [[nodiscard]] VkPipelineCache getPipelineCache() const noexcept { return pipeline_cache; }
211
212 /** @brief Get the swapchain color format. */
213 [[nodiscard]] VkFormat getSwapchainFormat() const noexcept { return swapchain_format; }
214
215 /** @brief Select RGBA16F scene/effect intermediates while retaining the presentation format. */
216 void setHdrRenderIntermediatesEnabled(bool enabled);
217
218 /** @brief Get the active scene/effect color-attachment format. */
219 [[nodiscard]] VkFormat getSceneColorFormat() const noexcept { return hdr_render_intermediates_enabled ? VK_FORMAT_R16G16B16A16_SFLOAT : swapchain_format; }
220
221 /** @brief Get the current swapchain extent. */
222 [[nodiscard]] VkExtent2D getSwapchainExtent() const noexcept { return swapchain_extent; }
223
224 /**
225 * @brief Render post-processing at a fixed extent independent of the preview window.
226 *
227 * The final source-sized image is read back before a fitted copy is presented
228 * to the swapchain. Pass zero dimensions to return to swapchain-sized rendering.
229 */
230 void setRenderExtent(uint32_t width, uint32_t height);
231
232 /** @brief Get the active scene/post-processing extent. */
233 [[nodiscard]] VkExtent2D getRenderExtent() const noexcept;
234
235 /** @brief Get the depth format used for dynamic rendering attachments. */
236 [[nodiscard]] VkFormat getDepthFormat() const noexcept { return depth_format; }
237
238 /** @brief Get the number of swapchain images currently allocated. */
239 [[nodiscard]] size_t getSwapchainImageCount() const noexcept { return swapchain_images.size(); }
240
241 /**
242 * @brief Ensure deferred render resources are initialized.
243 * @return true when swapchain, command pool, and sync objects are ready.
244 */
246
247 /**
248 * @brief Return transient Vulkan command-pool allocations to the driver when supported.
249 *
250 * MXVK currently uses direct Vulkan memory allocations rather than VMA, so VMA
251 * defragmentation is not applicable. This hook schedules the available Vulkan
252 * memory maintenance operation and is safe to call during idle/loading points.
253 */
254 void trimMemory();
255
256 /**
257 * @brief Measure text dimensions in pixels.
258 * @param text Text string to measure.
259 * @param width Output width in pixels.
260 * @param height Output height in pixels.
261 * @return true when measurement succeeded.
262 */
263 [[nodiscard]] bool getTextDimensions(const std::string &text, int &width, int &height);
264 [[nodiscard]] bool getTextDimensions(const std::string &text, int &width, int &height, TTF_Font *font);
265 [[nodiscard]] bool getTextDimensions(const std::string &text, int &width, int &height, const Font &font);
266
267 /**
268 * @brief Create a sprite from a PNG file and register it with this window.
269 * @param pngPath Path to the PNG file.
270 * @param vertexShaderPath Optional custom vertex shader SPIR-V path.
271 * @param fragmentShaderPath Optional custom fragment shader SPIR-V path.
272 * @return Non-owning pointer to the created sprite.
273 */
274 VK_Sprite *createSprite(const std::string &pngPath, const std::string &vertexShaderPath = "", const std::string &fragmentShaderPath = "");
275
276 /**
277 * @brief Create a sprite from an SDL surface and register it with this window.
278 * @param surface Source surface pointer.
279 * @param vertexShaderPath Optional custom vertex shader SPIR-V path.
280 * @param fragmentShaderPath Optional custom fragment shader SPIR-V path.
281 * @return Non-owning pointer to the created sprite.
282 */
283 VK_Sprite *createSprite(SDL_Surface *surface, const std::string &vertexShaderPath = "", const std::string &fragmentShaderPath = "");
284
285 /**
286 * @brief Create a blank sprite texture and register it with this window.
287 * @param width Texture width in pixels.
288 * @param height Texture height in pixels.
289 * @param vertexShaderPath Optional custom vertex shader SPIR-V path.
290 * @param fragmentShaderPath Optional custom fragment shader SPIR-V path.
291 * @param spectrumBinCount Optional binding-3 1-D spectrum size to create before the pipeline.
292 * @return Non-owning pointer to the created sprite.
293 */
294 VK_Sprite *createSprite(int width, int height, const std::string &vertexShaderPath = "", const std::string &fragmentShaderPath = "", uint32_t spectrumBinCount = 0);
295
296 /**
297 * @brief Create a blank sprite with live FFT and FFT-history descriptors.
298 * @param width Texture width in pixels.
299 * @param height Texture height in pixels.
300 * @param vertexShaderPath Optional custom vertex shader SPIR-V path.
301 * @param fragmentShaderPath Optional custom fragment shader SPIR-V path.
302 * @param spectrumBinCount Binding-3 1-D spectrum size.
303 * @param spectrumHistoryLayerCount Requested binding-4 history depth.
304 * @return Non-owning pointer to the created sprite.
305 */
306 VK_Sprite *createSprite(int width, int height, const std::string &vertexShaderPath, const std::string &fragmentShaderPath, uint32_t spectrumBinCount, uint32_t spectrumHistoryLayerCount);
307
309 std::string fragmentShaderPath{};
310 std::array<float, 4> params{};
311 bool timeEnabled = false;
312 uint32_t spectrumBinCount = 0;
316 };
317
318 /**
319 * @brief Attach a full-screen post-processing fragment shader.
320 *
321 * The window renders the normal scene into an offscreen color target, then draws that
322 * target through the supplied sprite-compatible fragment shader into the swapchain.
323 * Shader params are passed through the existing sprite push-constant vec4.
324 *
325 * @param fragmentShaderPath Post-process fragment shader SPIR-V path.
326 * @param p1 First shader parameter.
327 * @param p2 Second shader parameter.
328 * @param p3 Third shader parameter.
329 * @param p4 Fourth shader parameter.
330 * @return Non-owning pointer to the internal post-process sprite for advanced setup.
331 */
332 VK_Sprite *attachPostProcessingShader(const std::string &fragmentShaderPath, float p1 = 0.0f, float p2 = 0.0f, float p3 = 0.0f, float p4 = 0.0f);
333 std::vector<VK_Sprite *> attachPostProcessingShaders(const std::vector<PostProcessingEffect> &effects);
334
335 /** @brief Detach the current post-processing shader and return to direct swapchain rendering. */
337
338 /** @brief Set the post-processing shader params passed as a vec4 push constant. */
339 void setPostProcessingShaderParams(float p1 = 0.0f, float p2 = 0.0f, float p3 = 0.0f, float p4 = 0.0f);
340 void setPostProcessingShaderParams(size_t effectIndex, float p1 = 0.0f, float p2 = 0.0f, float p3 = 0.0f, float p4 = 0.0f);
341
342 /** @brief Keep shader param 1 updated with elapsed render time in seconds. */
343 void setPostProcessingShaderTimeEnabled(bool enabled);
344 void setPostProcessingShaderTimeEnabled(size_t effectIndex, bool enabled);
345
346 void enablePostProcessing(VK_Sprite *sprite);
347
348 void setPostProcessingEnabled(bool enabled) { post_process_enabled = enabled; }
349
350 /** Route the completed effect chain to a derived renderer as a sampled texture. */
352
353 /** Set an optional fragment shader used only when presenting the final
354 * post-processing texture to a window. The offscreen texture and frame
355 * readback remain unchanged. Pass an empty path for the normal copy.
356 */
357 void setPostProcessingPresentFragmentShader(const std::string &path);
358
359 /**
360 * @brief Create a world-space billboard sprite from a PNG file.
361 * @param pngPath Path to the PNG file.
362 * @param vertexShaderPath Optional custom vertex shader SPIR-V path.
363 * @param fragmentShaderPath Optional custom fragment shader SPIR-V path.
364 * @return Non-owning pointer to the created 3D sprite batch.
365 */
366 VK_Sprite3D *createSprite3D(const std::string &pngPath, const std::string &vertexShaderPath = "", const std::string &fragmentShaderPath = "");
367
368 /**
369 * @brief Create a world-space billboard sprite from an SDL surface.
370 * @param surface Source surface pointer.
371 * @param vertexShaderPath Optional custom vertex shader SPIR-V path.
372 * @param fragmentShaderPath Optional custom fragment shader SPIR-V path.
373 * @return Non-owning pointer to the created 3D sprite batch.
374 */
375 VK_Sprite3D *createSprite3D(SDL_Surface *surface, const std::string &vertexShaderPath = "", const std::string &fragmentShaderPath = "");
376
377 /**
378 * @brief Check whether Vulkan validation layers are currently enabled.
379 * @return true if validation layers are enabled, false otherwise.
380 */
381 [[nodiscard]] bool validationEnabled() const;
382
383 static VKAPI_ATTR VkBool32 VKAPI_CALL debugCallback(VkDebugUtilsMessageSeverityFlagBitsEXT severity, [[maybe_unused]] VkDebugUtilsMessageTypeFlagsEXT type, const VkDebugUtilsMessengerCallbackDataEXT *callback_data, [[maybe_unused]] void *user_data);
384
385 void showCursor(bool on);
386
387 VulkanContext context() const;
388
389 protected:
390 /**
391 * @brief Load a SPIR-V file from disk.
392 * @param path Absolute or relative path to a .spv file.
393 * @return Raw bytes loaded from file.
394 * @throws mxvk::Exception when the file cannot be opened, is empty, or is not 4-byte aligned.
395 */
396 static std::vector<char> loadSpv(const std::string &path);
397
398 /**
399 * @brief Create a shader module from SPIR-V bytecode.
400 * @param device Logical Vulkan device used to create the module.
401 * @param spv_bytes SPIR-V bytecode payload.
402 * @return Created shader module handle.
403 * @throws mxvk::Exception when inputs are invalid or module creation fails.
404 */
405 static VkShaderModule createShaderModule(VkDevice device, const std::vector<char> &spv_bytes);
406
407 /**
408 * @brief Initialize SDL window resources.
409 * @param title Window title string.
410 * @param width Window width in pixels.
411 * @param height Window height in pixels.
412 * @param flags Additional SDL window creation flags.
413 * @return true on success, false otherwise.
414 */
415 bool initWindow(const std::string &title, int width, int height, SDL_WindowFlags flags);
416
417 /**
418 * @brief Pick a suitable Vulkan physical device.
419 */
420 void pickDevice();
421
422 /**
423 * @brief Create a logical Vulkan device from the selected physical device.
424 */
425 void createLogicalDevice();
426
427 /**
428 * @brief Create final device resources.
429 */
430 void createDevice();
431
432 /**
433 * @brief Request loop termination.
434 */
435 void exit();
436
437 /**
438 * @brief Called right before swapchain-dependent resources are recreated.
439 *
440 * Derived classes can release swapchain-dependent resources here.
441 */
442 virtual void onSwapchainAboutToRecreate();
443
444 /**
445 * @brief Called after swapchain and render resources are recreated.
446 *
447 * Derived classes can rebuild swapchain-dependent resources here.
448 */
449 virtual void onSwapchainRecreated();
450
451 /**
452 * @brief Optional hook for derived classes to record extra draw commands.
453 *
454 * This callback is invoked inside the dynamic-rendering scope started by
455 * the window, after viewport/scissor are configured and before rendering ends.
456 *
457 * @param cmd Active command buffer in recording state.
458 * @param image_index Current swapchain image index.
459 */
460 virtual void onRecordCustomRendering(VkCommandBuffer cmd, uint32_t image_index);
461
462 /**
463 * @brief Render a completed post-processing chain as custom scene input.
464 *
465 * Called inside a fresh final-color rendering scope when texture-consumer
466 * mode is enabled. The supplied view is in shader-read-only layout.
467 */
468 virtual void onRecordPostProcessingTexture(VkCommandBuffer cmd, uint32_t image_index, VkImageView texture_view, VkExtent2D texture_extent);
469
470 /**
471 * @brief Allow derived classes to customize depth/stencil attachments for the main dynamic rendering pass.
472 *
473 * Override this when custom rendering needs hardware stencil testing or a custom depth/stencil image.
474 * The callback is invoked immediately before vkCmdBeginRendering.
475 */
476 virtual void onConfigureDepthStencilAttachments(VkRenderingAttachmentInfo &depth_attachment, VkRenderingAttachmentInfo &stencil_attachment, uint32_t image_index);
477
478 protected:
479 /**
480 * @brief Capture the most recently presented swapchain image as tightly packed RGBA8 pixels.
481 *
482 * This performs a synchronous GPU readback and may briefly stall rendering.
483 */
484 void captureSnapshotPixels(std::vector<std::uint8_t> &rgba_pixels, uint32_t &width, uint32_t &height);
485
486 /**
487 * @brief Wait for and deliver all pending pipelined frame readbacks.
488 *
489 * Derived recorders should call this before closing their output writer.
490 */
491 void flushFrameReadbacks();
492
493 /**
494 * @brief Called after a presented frame has scheduled a readback.
495 *
496 * Derived classes can use this hook to queue frame-specific metadata that
497 * must remain associated with the later onFrameReadback() callback.
498 */
499 virtual void onFrameReadbackScheduled();
500
501 /**
502 * @brief Receive one tightly packed RGBA8 copy of the rendered frame.
503 * @param rgba_pixels Frame pixels in top-to-bottom row order.
504 * @param width Frame width in pixels.
505 * @param height Frame height in pixels.
506 */
507 virtual void onFrameReadback(std::vector<std::uint8_t> &rgba_pixels, uint32_t width, uint32_t height);
508
509 /** @brief Receive normalized RGBA16 pixels from an RGBA16F HDR target. */
510 virtual void onFrameReadbackRgba16(std::vector<std::uint16_t> &rgba_pixels, uint32_t width, uint32_t height);
511
512 /**
513 * @brief Render one standalone sprite using the window's shared sprite pipeline.
514 *
515 * This is intended for derived classes that want to draw a sprite before or after
516 * their own scene content without registering it in the window-managed sprite list.
517 */
518 void renderStandaloneSprite(VK_Sprite &sprite, VkCommandBuffer cmd);
519 void renderStandaloneSprite(VK_Sprite &sprite, VkCommandBuffer cmd, VkExtent2D extent);
520
521 private:
522 static constexpr uint32_t invalid_queue_index = std::numeric_limits<uint32_t>::max();
523 static constexpr uint32_t max_frames_in_flight = 2;
524
525 static constexpr const char *validation_layer_name = "VK_LAYER_KHRONOS_validation";
526
527 struct SwapchainSupport {
528 VkSurfaceCapabilitiesKHR capabilities{};
529 std::vector<VkSurfaceFormatKHR> formats{};
530 std::vector<VkPresentModeKHR> present_modes{};
531 };
532
533 struct FrameReadbackSlot {
534 VkBuffer buffer = VK_NULL_HANDLE;
535 VkDeviceMemory memory = VK_NULL_HANDLE;
536 void *mapped = nullptr;
537 VkDeviceSize size = 0;
538 uint32_t width = 0;
539 uint32_t height = 0;
540 VkFormat format = VK_FORMAT_UNDEFINED;
541 bool pending = false;
542 };
543
544 static SwapchainSupport querySwapchainSupport(VkPhysicalDevice device, VkSurfaceKHR surface);
545 static VkSurfaceFormatKHR chooseSurfaceFormat(const std::vector<VkSurfaceFormatKHR> &available_formats);
546 VkPresentModeKHR choosePresentMode(const std::vector<VkPresentModeKHR> &available_present_modes) const;
547 static VkExtent2D chooseExtent(const VkSurfaceCapabilitiesKHR &capabilities, SDL_Window *window);
548 static bool hasValidationLayerSupport();
549 static std::optional<VkDebugUtilsMessengerCreateInfoEXT> makeDebugMessengerCreateInfo();
550 void setupDebugMessenger();
551 void cleanupDebugMessenger();
552 bool createSwapchain(VkSwapchainKHR old_swapchain);
553 bool createHeadlessTargets();
554 [[nodiscard]] bool renderTargetsReady() const noexcept;
555 bool createRenderResources();
556 bool createSyncObjects();
557 void cleanupSyncObjects();
558 void cleanupSwapchain(bool preserveCommandPool = true);
559 void recreateSwapchain();
560 void drawFrame();
561 [[nodiscard]] std::string pipelineCachePath() const;
562 void createPipelineCache();
563 void savePipelineCache() const;
564 void destroyPipelineCache();
565 [[nodiscard]] std::string resolveRuntimeShaderPath(const std::string &shaderFileName, const char *fallbackDir) const;
566 void createSpriteDescriptorSetLayout();
567 void createSpritePipeline();
568 void destroySpritePipeline();
569 void createPostProcessTargets();
570 void destroyPostProcessTargets();
571 void ensureTextRenderer();
572 void ensurePreviewTextRenderer();
573 void ensurePreviewTextRenderer(const std::string &fallbackFontPath, int fallbackFontSize);
574 void createTextDescriptorSetLayout();
575 void createTextPipeline();
576 void destroyTextPipeline();
577 void maybeTrimMemory();
578 void saveScreenshot();
579 [[nodiscard]] std::string makeScreenshotPath();
580 void enqueueScreenshotSave(std::string path, std::vector<std::uint8_t> rgba, uint32_t width, uint32_t height);
581 void startScreenshotWorker();
582 void stopScreenshotWorker();
583 void screenshotWorkerLoop();
584 [[nodiscard]] bool isPostProcessSprite(const VK_Sprite *sprite) const;
585 [[nodiscard]] std::string resolveDefaultFontPath() const;
586 void ensureTextRenderer(const std::string &fallbackFontPath, int fallbackFontSize);
587 void toggleFpsCounter();
588 void updateFpsCounter();
589
590 protected:
591 // Protected state allows subclasses to implement custom rendering paths.
592
594 void operator()(SDL_Window *ptr) const {
595 if (ptr != nullptr) {
596 SDL_DestroyWindow(ptr);
597 }
598 }
599 };
600
601 std::unique_ptr<SDL_Window, SDLWindowDeleter> window{};
602 VkInstance instance = VK_NULL_HANDLE;
603 VkDebugUtilsMessengerEXT debug_messenger = VK_NULL_HANDLE;
604 VkSurfaceKHR surface = VK_NULL_HANDLE;
605 VkPhysicalDevice physical_device = VK_NULL_HANDLE;
606 VkDevice device = VK_NULL_HANDLE;
607 uint32_t graphics_queue_family = invalid_queue_index;
608 uint32_t present_queue_family = invalid_queue_index;
609 VkQueue graphics_queue = VK_NULL_HANDLE;
610 VkQueue present_queue = VK_NULL_HANDLE;
611 VkPipelineCache pipeline_cache = VK_NULL_HANDLE;
612
613 VkSwapchainKHR swapchain = VK_NULL_HANDLE;
614 VkFormat swapchain_format = VK_FORMAT_UNDEFINED;
615 VkFormat depth_format = VK_FORMAT_UNDEFINED;
616 VkExtent2D swapchain_extent{};
618 std::vector<VkImage> swapchain_images{};
619 std::vector<VkDeviceMemory> headless_image_memories{};
620 std::vector<VkImageView> swapchain_image_views{};
621 std::vector<bool> swapchain_image_initialized{};
622 std::vector<VkImage> depth_images{};
623 std::vector<VkDeviceMemory> depth_image_memories{};
624 std::vector<VkImageView> depth_image_views{};
625 std::vector<bool> depth_image_initialized{};
626
627 VkCommandPool command_pool = VK_NULL_HANDLE;
628 std::vector<VkCommandBuffer> command_buffers{};
629
630 std::array<VkSemaphore, max_frames_in_flight> image_available{};
631 std::vector<VkSemaphore> render_finished{};
632 std::array<VkFence, max_frames_in_flight> in_flight_fences{};
633 std::vector<VkFence> image_fences{};
634 uint32_t current_frame = 0;
635 uint32_t last_presented_image_index = invalid_queue_index;
637
638 bool sdl_initialized = false;
640 bool active = false;
643 uint32_t screenshot_index = 0;
645 std::string path;
646 std::vector<std::uint8_t> rgba;
647 uint32_t width = 0;
648 uint32_t height = 0;
649 };
651 std::condition_variable screenshot_queue_cv;
652 std::deque<ScreenshotSaveTask> screenshot_save_queue;
653 std::thread screenshot_worker;
657 std::array<FrameReadbackSlot, max_frames_in_flight> frame_readback_slots{};
658 std::vector<std::uint8_t> latest_frame_readback_rgba{};
659 std::vector<std::uint16_t> latest_frame_readback_rgba16{};
663 void dispatchFrameReadback(FrameReadbackSlot &slot);
665 bool validation_enabled = false;
673 static constexpr uint64_t resize_settle_delay_ms = 150;
674 std::chrono::steady_clock::time_point last_memory_trim_time = std::chrono::steady_clock::now();
675 static constexpr std::chrono::seconds MEMORY_TRIM_INTERVAL{30};
676
677 std::vector<std::unique_ptr<VK_Sprite>> sprites{};
678 std::vector<std::unique_ptr<VK_Sprite3D>> sprites3d{};
679 VkDescriptorSetLayout sprite_descriptor_set_layout = VK_NULL_HANDLE;
680 VkPipelineLayout sprite_pipeline_layout = VK_NULL_HANDLE;
681 VkPipeline sprite_pipeline = VK_NULL_HANDLE;
682 bool sprite_state_dirty = false;
688 std::array<float, 4> post_process_params{};
689 std::chrono::steady_clock::time_point post_process_start_time = std::chrono::steady_clock::now();
690 std::vector<VK_Sprite *> post_process_sprites{};
691 std::vector<VK_Sprite *> owned_post_process_sprites{};
695 std::vector<ShaderStage> post_process_effect_stages{};
696 std::vector<std::array<float, 4>> post_process_effect_params{};
698 std::vector<std::chrono::steady_clock::time_point> post_process_effect_start_times{};
699 std::vector<std::vector<VkImage>> post_process_images{};
700 std::vector<std::vector<VkDeviceMemory>> post_process_memories{};
701 std::vector<std::vector<VkImageView>> post_process_views{};
702 std::vector<std::vector<bool>> post_process_initialized{};
703 [[nodiscard]] VkFormat postProcessIntermediateFormat() const noexcept { return hdr_render_intermediates_enabled ? VK_FORMAT_R16G16B16A16_SFLOAT : VK_FORMAT_R8G8B8A8_UNORM; }
705
706 std::unique_ptr<VK_Text> text_renderer{};
707 std::unique_ptr<VK_Text> preview_text_renderer{};
708 VkDescriptorSetLayout text_descriptor_set_layout = VK_NULL_HANDLE;
709 VkPipelineLayout text_pipeline_layout = VK_NULL_HANDLE;
710 VkPipeline text_pipeline = VK_NULL_HANDLE;
711 bool text_state_dirty = false;
713 bool font_configured = false;
714 std::string font_path{};
715 int font_size = 24;
719 std::chrono::steady_clock::time_point fps_counter_sample_time{};
721 std::string fps_counter_text = "FPS: --";
722 VkClearColorValue clear_color{{0.0f, 0.0f, 0.0f, 1.0f}};
723 std::vector<VkSwapchainKHR> retired_swapchains;
724 };
725
726} // namespace mxvk
Small RAII wrapper for an SDL_ttf font handle.
Definition mxvk_text.hpp:46
Depth-tested 3D billboard sprite batch.
std::vector< ShaderStage > post_process_effect_stages
Definition mxvk.hpp:695
VkPipelineLayout sprite_pipeline_layout
Definition mxvk.hpp:680
bool post_process_enabled
Definition mxvk.hpp:685
bool force_swapchain_recreate
Definition mxvk.hpp:671
VkExtent2D getSwapchainExtent() const noexcept
Get the current swapchain extent.
Definition mxvk.hpp:222
std::mutex screenshot_queue_mutex
Definition mxvk.hpp:650
void showCursor(bool on)
Definition mxvk.cpp:4620
VkSwapchainKHR swapchain
Definition mxvk.hpp:613
void captureSnapshotPixels(std::vector< std::uint8_t > &rgba_pixels, uint32_t &width, uint32_t &height)
Capture the most recently presented swapchain image as tightly packed RGBA8 pixels.
Definition mxvk.cpp:841
virtual void event(SDL_Event &e)
Handle one SDL event.
Definition mxvk.cpp:626
bool screenshotEnabled() const noexcept
Check whether F10 screenshot capture is enabled.
Definition mxvk.hpp:176
void pickDevice()
Pick a suitable Vulkan physical device.
Definition mxvk.cpp:1808
void dispatchFrameReadback(FrameReadbackSlot &slot)
Definition mxvk.cpp:1095
static constexpr std::chrono::seconds MEMORY_TRIM_INTERVAL
Definition mxvk.hpp:675
VkDescriptorSetLayout sprite_descriptor_set_layout
Definition mxvk.hpp:679
std::vector< std::vector< bool > > post_process_initialized
Definition mxvk.hpp:702
void loop()
Run the main event/render loop.
Definition mxvk.cpp:651
VK_Sprite3D * createSprite3D(const std::string &pngPath, const std::string &vertexShaderPath="", const std::string &fragmentShaderPath="")
Create a world-space billboard sprite from a PNG file.
Definition mxvk.cpp:4573
std::condition_variable screenshot_queue_cv
Definition mxvk.hpp:651
VkDevice getDevice() const noexcept
Get the Vulkan logical device handle.
Definition mxvk.hpp:198
VkDebugUtilsMessengerEXT debug_messenger
Definition mxvk.hpp:603
VkDevice device
Definition mxvk.hpp:606
static VkBool32 debugCallback(VkDebugUtilsMessageSeverityFlagBitsEXT severity, VkDebugUtilsMessageTypeFlagsEXT type, const VkDebugUtilsMessengerCallbackDataEXT *callback_data, void *user_data)
Definition mxvk.cpp:67
std::chrono::steady_clock::time_point fps_counter_sample_time
Definition mxvk.hpp:719
uint32_t screenshot_index
Definition mxvk.hpp:643
void createLogicalDevice()
Create a logical Vulkan device from the selected physical device.
Definition mxvk.cpp:1898
uint32_t fps_counter_frame_count
Definition mxvk.hpp:720
virtual bool initVulkan(bool validiation)
Initialize Vulkan state.
Definition mxvk.cpp:365
VK_Sprite * createSprite(const std::string &pngPath, const std::string &vertexShaderPath="", const std::string &fragmentShaderPath="")
Create a sprite from a PNG file and register it with this window.
Definition mxvk.cpp:4455
VkClearColorValue clear_color
Definition mxvk.hpp:722
VkQueue getGraphicsQueue() const noexcept
Get the graphics queue handle.
Definition mxvk.hpp:204
std::string screenshot_prefix
Definition mxvk.hpp:642
virtual void onSwapchainRecreated()
Called after swapchain and render resources are recreated.
Definition mxvk.cpp:1382
VkInstance instance
Definition mxvk.hpp:602
VkFormat swapchain_format
Definition mxvk.hpp:614
VkCommandPool getCommandPool() const noexcept
Get the command pool used for graphics/upload work.
Definition mxvk.hpp:207
VkExtent2D swapchain_extent
Definition mxvk.hpp:616
virtual void onSwapchainAboutToRecreate()
Called right before swapchain-dependent resources are recreated.
Definition mxvk.cpp:1380
std::vector< std::uint16_t > latest_frame_readback_rgba16
Definition mxvk.hpp:659
std::vector< bool > post_process_effect_time_enabled
Definition mxvk.hpp:697
VulkanContext context() const
Definition mxvk.cpp:80
bool vulkan_library_loaded
Definition mxvk.hpp:639
bool validation_enabled
Definition mxvk.hpp:665
VkExtent2D requested_headless_extent
Definition mxvk.hpp:667
bool screenshot_worker_stop
Definition mxvk.hpp:654
std::vector< std::array< float, 4 > > post_process_effect_params
Definition mxvk.hpp:696
std::vector< std::vector< VkDeviceMemory > > post_process_memories
Definition mxvk.hpp:700
VkDescriptorSetLayout text_descriptor_set_layout
Definition mxvk.hpp:708
static constexpr uint64_t resize_settle_delay_ms
Definition mxvk.hpp:673
std::vector< std::vector< VkImageView > > post_process_views
Definition mxvk.hpp:701
VkPipeline text_pipeline
Definition mxvk.hpp:710
std::unique_ptr< VK_Text > preview_text_renderer
Definition mxvk.hpp:707
void setFrameReadbackRgba16Enabled(bool enabled) noexcept
Request normalized RGBA16 callbacks from the final HDR intermediate.
Definition mxvk.hpp:189
std::chrono::steady_clock::time_point post_process_start_time
Definition mxvk.hpp:689
VkFormat depth_format
Definition mxvk.hpp:615
uint32_t present_queue_family
Definition mxvk.hpp:608
void enablePostProcessing(VK_Sprite *sprite)
Definition mxvk.cpp:1635
uint32_t last_presented_image_index
Definition mxvk.hpp:635
std::vector< VkImageView > swapchain_image_views
Definition mxvk.hpp:620
std::vector< VK_Sprite * > owned_post_process_sprites
Definition mxvk.hpp:691
static VkShaderModule createShaderModule(VkDevice device, const std::vector< char > &spv_bytes)
Create a shader module from SPIR-V bytecode.
Definition mxvk.cpp:154
std::chrono::steady_clock::time_point last_memory_trim_time
Definition mxvk.hpp:674
RuntimeMode runtime_mode
Definition mxvk.hpp:666
void setRenderExtent(uint32_t width, uint32_t height)
Render post-processing at a fixed extent independent of the preview window.
Definition mxvk.cpp:1406
VkQueue present_queue
Definition mxvk.hpp:610
void ensureFrameReadbackResources()
Definition mxvk.cpp:1162
void createDevice()
Create final device resources.
Definition mxvk.cpp:2028
bool text_state_dirty
Definition mxvk.hpp:711
Font fps_counter_font
Definition mxvk.hpp:718
bool getTextDimensions(const std::string &text, int &width, int &height)
Measure text dimensions in pixels.
Definition mxvk.cpp:4004
VK_Window & operator=(const VK_Window &)=delete
std::vector< bool > swapchain_image_initialized
Definition mxvk.hpp:621
std::vector< VkImage > swapchain_images
Definition mxvk.hpp:618
std::vector< VkFence > image_fences
Definition mxvk.hpp:633
std::string font_path
Definition mxvk.hpp:714
void clearTextQueue()
Clear all queued text draw calls for the current frame.
Definition mxvk.cpp:3964
void flushFrameReadbacks()
Wait for and deliver all pending pipelined frame readbacks.
Definition mxvk.cpp:1143
size_t getSwapchainImageCount() const noexcept
Get the number of swapchain images currently allocated.
Definition mxvk.hpp:239
std::vector< VkSwapchainKHR > retired_swapchains
Definition mxvk.hpp:723
std::vector< VkImageView > depth_image_views
Definition mxvk.hpp:624
VK_Window & operator=(VK_Window &&)=delete
virtual void onConfigureDepthStencilAttachments(VkRenderingAttachmentInfo &depth_attachment, VkRenderingAttachmentInfo &stencil_attachment, uint32_t image_index)
Allow derived classes to customize depth/stencil attachments for the main dynamic rendering pass.
Definition mxvk.cpp:1390
bool post_process_time_enabled
Definition mxvk.hpp:687
SDL_Window * getSDLWindow() const noexcept
Get the underlying SDL window handle.
Definition mxvk.hpp:192
std::unique_ptr< VK_Text > text_renderer
Definition mxvk.hpp:706
bool screenshot_enabled
Definition mxvk.hpp:641
void saveSnapshot(const std::string &path)
Save the most recently rendered window contents as a PNG file.
Definition mxvk.cpp:826
uint32_t graphics_queue_family
Definition mxvk.hpp:607
void setClearColor(float r, float g, float b, float a=1.0f)
Set the per-frame color attachment clear color.
Definition mxvk.cpp:637
bool preview_text_queued
Definition mxvk.hpp:712
std::vector< VK_Sprite * > attachPostProcessingShaders(const std::vector< PostProcessingEffect > &effects)
Definition mxvk.cpp:1474
virtual void onPrepareFrameRendering(VkCommandBuffer cmd, uint32_t image_index)
Record resource transitions that must happen before dynamic rendering begins.
Definition mxvk.cpp:1384
std::vector< VkCommandBuffer > command_buffers
Definition mxvk.hpp:628
void renderStandaloneSprite(VK_Sprite &sprite, VkCommandBuffer cmd)
Render one standalone sprite using the window's shared sprite pipeline.
Definition mxvk.cpp:1392
std::thread screenshot_worker
Definition mxvk.hpp:653
uint32_t current_frame
Definition mxvk.hpp:634
std::vector< VkSemaphore > render_finished
Definition mxvk.hpp:631
void setHdrRenderIntermediatesEnabled(bool enabled)
Select RGBA16F scene/effect intermediates while retaining the presentation format.
Definition mxvk.cpp:1453
VkPipelineCache pipeline_cache
Definition mxvk.hpp:611
std::unique_ptr< SDL_Window, SDLWindowDeleter > window
Definition mxvk.hpp:601
bool sdl_initialized
Definition mxvk.hpp:638
VK_Sprite * post_process_composite_sprite
Definition mxvk.hpp:694
VkFormat getSceneColorFormat() const noexcept
Get the active scene/effect color-attachment format.
Definition mxvk.hpp:219
std::vector< std::chrono::steady_clock::time_point > post_process_effect_start_times
Definition mxvk.hpp:698
VkPipeline sprite_pipeline
Definition mxvk.hpp:681
void exit()
Request loop termination.
Definition mxvk.cpp:1378
virtual void onRecordPostProcessingTexture(VkCommandBuffer cmd, uint32_t image_index, VkImageView texture_view, VkExtent2D texture_extent)
Render a completed post-processing chain as custom scene input.
Definition mxvk.cpp:1388
VkCommandPool command_pool
Definition mxvk.hpp:627
void setFrameReadbackEnabled(bool enabled) noexcept
Enable or disable readback of each rendered swapchain frame.
Definition mxvk.hpp:186
VK_Sprite * attachPostProcessingShader(const std::string &fragmentShaderPath, float p1=0.0f, float p2=0.0f, float p3=0.0f, float p4=0.0f)
Attach a full-screen post-processing fragment shader.
Definition mxvk.cpp:1469
uint32_t latest_frame_readback_width
Definition mxvk.hpp:660
bool frame_readback_enabled
Definition mxvk.hpp:655
void printPreviewText(const std::string &text, int x, int y, const SDL_Color &col)
Queue preview-only text after frame readback.
Definition mxvk.cpp:3974
bool hdr_render_intermediates_enabled
Definition mxvk.hpp:704
bool frame_readback_rgba16_enabled
Definition mxvk.hpp:656
VK_Window(VK_Window &&)=delete
bool ensureRenderResources()
Ensure deferred render resources are initialized.
Definition mxvk.cpp:1787
VkSurfaceKHR surface
Definition mxvk.hpp:604
VK_Window()=default
Construct an empty window object.
VkPhysicalDevice physical_device
Definition mxvk.hpp:605
VK_Sprite * post_process_present_sprite
Definition mxvk.hpp:692
VkPipelineLayout text_pipeline_layout
Definition mxvk.hpp:709
virtual void onRecordCustomRendering(VkCommandBuffer cmd, uint32_t image_index)
Optional hook for derived classes to record extra draw commands.
Definition mxvk.cpp:1386
std::array< float, 4 > post_process_params
Definition mxvk.hpp:688
void detachPostProcessingShader()
Detach the current post-processing shader and return to direct swapchain rendering.
Definition mxvk.cpp:1566
std::vector< bool > depth_image_initialized
Definition mxvk.hpp:625
bool fps_counter_font_ready
Definition mxvk.hpp:717
uint32_t next_headless_image
Definition mxvk.hpp:668
void setPostProcessingTextureConsumerEnabled(bool enabled) noexcept
Route the completed effect chain to a derived renderer as a sampled texture.
Definition mxvk.hpp:351
VkFormat getDepthFormat() const noexcept
Get the depth format used for dynamic rendering attachments.
Definition mxvk.hpp:236
VkPipelineCache getPipelineCache() const noexcept
Get the persistent Vulkan pipeline cache used by framework pipelines.
Definition mxvk.hpp:210
std::deque< ScreenshotSaveTask > screenshot_save_queue
Definition mxvk.hpp:652
void release()
Release Vulkan and SDL resources.
Definition mxvk.cpp:247
std::array< FrameReadbackSlot, max_frames_in_flight > frame_readback_slots
Definition mxvk.hpp:657
void setFont(const std::string &fontPath, int fontSize=24)
Set the active text-render font.
Definition mxvk.cpp:3872
void setPostProcessingEnabled(bool enabled)
Definition mxvk.hpp:348
std::vector< VkDeviceMemory > depth_image_memories
Definition mxvk.hpp:623
std::vector< std::uint8_t > latest_frame_readback_rgba
Definition mxvk.hpp:658
PresentModePreference present_mode_preference
Definition mxvk.hpp:669
void printText(const std::string &text, int x, int y, const SDL_Color &col)
Queue a text string for rendering during the current frame.
Definition mxvk.cpp:3919
static std::vector< char > loadSpv(const std::string &path)
Load a SPIR-V file from disk.
Definition mxvk.cpp:152
std::vector< std::unique_ptr< VK_Sprite3D > > sprites3d
Definition mxvk.hpp:678
VkExtent2D render_extent_override
Definition mxvk.hpp:617
virtual void onFrameReadbackRgba16(std::vector< std::uint16_t > &rgba_pixels, uint32_t width, uint32_t height)
Receive normalized RGBA16 pixels from an RGBA16F HDR target.
Definition mxvk.cpp:1091
std::vector< VK_Sprite * > post_process_sprites
Definition mxvk.hpp:690
bool sprite_state_dirty
Definition mxvk.hpp:682
void trimMemory()
Return transient Vulkan command-pool allocations to the driver when supported.
Definition mxvk.cpp:1280
virtual void onFrameReadback(std::vector< std::uint8_t > &rgba_pixels, uint32_t width, uint32_t height)
Receive one tightly packed RGBA8 copy of the rendered frame.
Definition mxvk.cpp:1089
VK_Sprite * post_process_sprite
Definition mxvk.hpp:683
bool framebuffer_resized
Definition mxvk.hpp:670
VkQueue graphics_queue
Definition mxvk.hpp:609
bool font_configured
Definition mxvk.hpp:713
uint32_t latest_frame_readback_height
Definition mxvk.hpp:661
void setPostProcessingShaderParams(float p1=0.0f, float p2=0.0f, float p3=0.0f, float p4=0.0f)
Set the post-processing shader params passed as a vec4 push constant.
Definition mxvk.cpp:1591
void destroyFrameReadbackResources()
Definition mxvk.cpp:1252
std::string fps_counter_text
Definition mxvk.hpp:721
virtual void render()
Render one frame.
Definition mxvk.cpp:824
bool initWindow(const std::string &title, int width, int height, SDL_WindowFlags flags)
Initialize SDL window resources.
Definition mxvk.cpp:1298
bool headless() const noexcept
Return true when rendering without SDL video, a surface, or presentation.
Definition mxvk.hpp:195
std::vector< VkImage > depth_images
Definition mxvk.hpp:622
std::vector< VkDeviceMemory > headless_image_memories
Definition mxvk.hpp:619
bool post_process_texture_consumer_enabled
Definition mxvk.hpp:686
void setPostProcessingPresentFragmentShader(const std::string &path)
Set an optional fragment shader used only when presenting the final post-processing texture to a wind...
Definition mxvk.cpp:1555
virtual void proc()
Execute one processing/update step.
Definition mxvk.cpp:1278
bool validationEnabled() const
Check whether Vulkan validation layers are currently enabled.
Definition mxvk.cpp:3812
VK_Window(const VK_Window &)=delete
virtual void onFrameReadbackScheduled()
Called after a presented frame has scheduled a readback.
Definition mxvk.cpp:1093
std::vector< std::unique_ptr< VK_Sprite > > sprites
Definition mxvk.hpp:677
uint64_t last_resize_event_ms
Definition mxvk.hpp:672
VkExtent2D getRenderExtent() const noexcept
Get the active scene/post-processing extent.
Definition mxvk.cpp:1451
VkPhysicalDevice getPhysicalDevice() const noexcept
Get the Vulkan physical device handle.
Definition mxvk.hpp:201
void setPostProcessingShaderTimeEnabled(bool enabled)
Keep shader param 1 updated with elapsed render time in seconds.
Definition mxvk.cpp:1612
std::vector< std::vector< VkImage > > post_process_images
Definition mxvk.hpp:699
void setEnableScreenshot(bool enabled) noexcept
Enable or disable F10 screenshot capture.
Definition mxvk.cpp:644
std::string post_process_present_shader_path
Definition mxvk.hpp:693
void setPreviewFont(const std::string &fontPath, int fontSize=24)
Set the preview-only HUD font independently of output text.
Definition mxvk.cpp:3902
VK_Sprite * owned_post_process_sprite
Definition mxvk.hpp:684
std::array< VkSemaphore, max_frames_in_flight > image_available
Definition mxvk.hpp:630
bool fps_counter_enabled
Definition mxvk.hpp:716
bool swapchain_supports_transfer_src
Definition mxvk.hpp:636
std::array< VkFence, max_frames_in_flight > in_flight_fences
Definition mxvk.hpp:632
VkFormat getSwapchainFormat() const noexcept
Get the swapchain color format.
Definition mxvk.hpp:213
VkFormat postProcessIntermediateFormat() const noexcept
Definition mxvk.hpp:703
Minimal Vulkan handles shared across MXVK helpers.
World-space textured billboard renderer for MXVK dynamic rendering.
Vulkan 2-D sprite renderer with optional custom shaders and instancing.
Vulkan SDL_ttf text renderer.
Utilities for loading and saving PNG images.
Definition mxvk.hpp:31
bool defaultEnableScreenshot()
const std::string & defaultExecutableName()
std::array< float, 4 > params
Definition mxvk.hpp:310
void operator()(SDL_Window *ptr) const
Definition mxvk.hpp:594
std::vector< std::uint8_t > rgba
Definition mxvk.hpp:646
Minimal Vulkan handles required by MXVK resource helpers.