12#include <condition_variable>
18#include <mxvk/mxvk_version.hpp>
25#ifdef ENABLE_VALIDATION
26#define MXVK_VALIDATION true
28#define MXVK_VALIDATION false
73 VK_Window(
const std::string &title,
int width,
int height,
bool full,
bool validiation,
bool enableVsync);
93 virtual void event(SDL_Event &e);
135 void setFont(
const std::string &fontPath,
int fontSize = 24);
138 void setPreviewFont(
const std::string &fontPath,
int fontSize = 24);
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);
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);
170 void setClearColor(
float r,
float g,
float b,
float a = 1.0f);
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);
274 VK_Sprite *
createSprite(
const std::string &pngPath,
const std::string &vertexShaderPath =
"",
const std::string &fragmentShaderPath =
"");
294 VK_Sprite *
createSprite(
int width,
int height,
const std::string &vertexShaderPath =
"",
const std::string &fragmentShaderPath =
"", uint32_t spectrumBinCount = 0);
306 VK_Sprite *
createSprite(
int width,
int height,
const std::string &vertexShaderPath,
const std::string &fragmentShaderPath, uint32_t spectrumBinCount, uint32_t spectrumHistoryLayerCount);
366 VK_Sprite3D *
createSprite3D(
const std::string &pngPath,
const std::string &vertexShaderPath =
"",
const std::string &fragmentShaderPath =
"");
383 static VKAPI_ATTR VkBool32 VKAPI_CALL
debugCallback(VkDebugUtilsMessageSeverityFlagBitsEXT severity, [[maybe_unused]] VkDebugUtilsMessageTypeFlagsEXT type,
const VkDebugUtilsMessengerCallbackDataEXT *callback_data, [[maybe_unused]]
void *user_data);
396 static std::vector<char>
loadSpv(
const std::string &path);
415 bool initWindow(
const std::string &title,
int width,
int height, SDL_WindowFlags flags);
484 void captureSnapshotPixels(std::vector<std::uint8_t> &rgba_pixels, uint32_t &width, uint32_t &height);
507 virtual void onFrameReadback(std::vector<std::uint8_t> &rgba_pixels, uint32_t width, uint32_t height);
510 virtual void onFrameReadbackRgba16(std::vector<std::uint16_t> &rgba_pixels, uint32_t width, uint32_t height);
522 static constexpr uint32_t invalid_queue_index = std::numeric_limits<uint32_t>::max();
523 static constexpr uint32_t max_frames_in_flight = 2;
525 static constexpr const char *validation_layer_name =
"VK_LAYER_KHRONOS_validation";
527 struct SwapchainSupport {
528 VkSurfaceCapabilitiesKHR capabilities{};
529 std::vector<VkSurfaceFormatKHR> formats{};
530 std::vector<VkPresentModeKHR> present_modes{};
533 struct FrameReadbackSlot {
534 VkBuffer buffer = VK_NULL_HANDLE;
535 VkDeviceMemory memory = VK_NULL_HANDLE;
536 void *mapped =
nullptr;
537 VkDeviceSize size = 0;
540 VkFormat format = VK_FORMAT_UNDEFINED;
541 bool pending =
false;
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();
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();
595 if (ptr !=
nullptr) {
596 SDL_DestroyWindow(ptr);
601 std::unique_ptr<SDL_Window, SDLWindowDeleter>
window{};
646 std::vector<std::uint8_t>
rgba;
677 std::vector<std::unique_ptr<VK_Sprite>>
sprites{};
Small RAII wrapper for an SDL_ttf font handle.
Depth-tested 3D billboard sprite batch.
std::vector< ShaderStage > post_process_effect_stages
VkPipelineLayout sprite_pipeline_layout
bool post_process_enabled
bool force_swapchain_recreate
VkExtent2D getSwapchainExtent() const noexcept
Get the current swapchain extent.
std::mutex screenshot_queue_mutex
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.
virtual void event(SDL_Event &e)
Handle one SDL event.
bool screenshotEnabled() const noexcept
Check whether F10 screenshot capture is enabled.
void pickDevice()
Pick a suitable Vulkan physical device.
void dispatchFrameReadback(FrameReadbackSlot &slot)
static constexpr std::chrono::seconds MEMORY_TRIM_INTERVAL
VkDescriptorSetLayout sprite_descriptor_set_layout
std::vector< std::vector< bool > > post_process_initialized
void loop()
Run the main event/render loop.
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.
std::condition_variable screenshot_queue_cv
VkDevice getDevice() const noexcept
Get the Vulkan logical device handle.
VkDebugUtilsMessengerEXT debug_messenger
static VkBool32 debugCallback(VkDebugUtilsMessageSeverityFlagBitsEXT severity, VkDebugUtilsMessageTypeFlagsEXT type, const VkDebugUtilsMessengerCallbackDataEXT *callback_data, void *user_data)
std::chrono::steady_clock::time_point fps_counter_sample_time
uint32_t screenshot_index
void createLogicalDevice()
Create a logical Vulkan device from the selected physical device.
uint32_t fps_counter_frame_count
virtual bool initVulkan(bool validiation)
Initialize Vulkan state.
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.
VkClearColorValue clear_color
VkQueue getGraphicsQueue() const noexcept
Get the graphics queue handle.
std::string screenshot_prefix
virtual void onSwapchainRecreated()
Called after swapchain and render resources are recreated.
VkFormat swapchain_format
VkCommandPool getCommandPool() const noexcept
Get the command pool used for graphics/upload work.
VkExtent2D swapchain_extent
virtual void onSwapchainAboutToRecreate()
Called right before swapchain-dependent resources are recreated.
std::vector< std::uint16_t > latest_frame_readback_rgba16
std::vector< bool > post_process_effect_time_enabled
VulkanContext context() const
bool vulkan_library_loaded
VkExtent2D requested_headless_extent
bool screenshot_worker_stop
std::vector< std::array< float, 4 > > post_process_effect_params
std::vector< std::vector< VkDeviceMemory > > post_process_memories
VkDescriptorSetLayout text_descriptor_set_layout
static constexpr uint64_t resize_settle_delay_ms
std::vector< std::vector< VkImageView > > post_process_views
std::unique_ptr< VK_Text > preview_text_renderer
void setFrameReadbackRgba16Enabled(bool enabled) noexcept
Request normalized RGBA16 callbacks from the final HDR intermediate.
std::chrono::steady_clock::time_point post_process_start_time
uint32_t present_queue_family
void enablePostProcessing(VK_Sprite *sprite)
uint32_t last_presented_image_index
std::vector< VkImageView > swapchain_image_views
std::vector< VK_Sprite * > owned_post_process_sprites
static VkShaderModule createShaderModule(VkDevice device, const std::vector< char > &spv_bytes)
Create a shader module from SPIR-V bytecode.
std::chrono::steady_clock::time_point last_memory_trim_time
void setRenderExtent(uint32_t width, uint32_t height)
Render post-processing at a fixed extent independent of the preview window.
void ensureFrameReadbackResources()
void createDevice()
Create final device resources.
bool getTextDimensions(const std::string &text, int &width, int &height)
Measure text dimensions in pixels.
VK_Window & operator=(const VK_Window &)=delete
std::vector< bool > swapchain_image_initialized
std::vector< VkImage > swapchain_images
std::vector< VkFence > image_fences
void clearTextQueue()
Clear all queued text draw calls for the current frame.
void flushFrameReadbacks()
Wait for and deliver all pending pipelined frame readbacks.
size_t getSwapchainImageCount() const noexcept
Get the number of swapchain images currently allocated.
std::vector< VkSwapchainKHR > retired_swapchains
std::vector< VkImageView > depth_image_views
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.
bool post_process_time_enabled
SDL_Window * getSDLWindow() const noexcept
Get the underlying SDL window handle.
std::unique_ptr< VK_Text > text_renderer
void saveSnapshot(const std::string &path)
Save the most recently rendered window contents as a PNG file.
uint32_t graphics_queue_family
void setClearColor(float r, float g, float b, float a=1.0f)
Set the per-frame color attachment clear color.
std::vector< VK_Sprite * > attachPostProcessingShaders(const std::vector< PostProcessingEffect > &effects)
virtual void onPrepareFrameRendering(VkCommandBuffer cmd, uint32_t image_index)
Record resource transitions that must happen before dynamic rendering begins.
std::vector< VkCommandBuffer > command_buffers
void renderStandaloneSprite(VK_Sprite &sprite, VkCommandBuffer cmd)
Render one standalone sprite using the window's shared sprite pipeline.
std::thread screenshot_worker
std::vector< VkSemaphore > render_finished
void setHdrRenderIntermediatesEnabled(bool enabled)
Select RGBA16F scene/effect intermediates while retaining the presentation format.
VkPipelineCache pipeline_cache
std::unique_ptr< SDL_Window, SDLWindowDeleter > window
VK_Sprite * post_process_composite_sprite
VkFormat getSceneColorFormat() const noexcept
Get the active scene/effect color-attachment format.
std::vector< std::chrono::steady_clock::time_point > post_process_effect_start_times
VkPipeline sprite_pipeline
void exit()
Request loop termination.
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.
VkCommandPool command_pool
void setFrameReadbackEnabled(bool enabled) noexcept
Enable or disable readback of each rendered swapchain frame.
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.
uint32_t latest_frame_readback_width
bool frame_readback_enabled
void printPreviewText(const std::string &text, int x, int y, const SDL_Color &col)
Queue preview-only text after frame readback.
bool hdr_render_intermediates_enabled
bool frame_readback_rgba16_enabled
VK_Window(VK_Window &&)=delete
bool ensureRenderResources()
Ensure deferred render resources are initialized.
VK_Window()=default
Construct an empty window object.
VkPhysicalDevice physical_device
VK_Sprite * post_process_present_sprite
VkPipelineLayout text_pipeline_layout
virtual void onRecordCustomRendering(VkCommandBuffer cmd, uint32_t image_index)
Optional hook for derived classes to record extra draw commands.
std::array< float, 4 > post_process_params
void detachPostProcessingShader()
Detach the current post-processing shader and return to direct swapchain rendering.
std::vector< bool > depth_image_initialized
bool fps_counter_font_ready
uint32_t next_headless_image
void setPostProcessingTextureConsumerEnabled(bool enabled) noexcept
Route the completed effect chain to a derived renderer as a sampled texture.
VkFormat getDepthFormat() const noexcept
Get the depth format used for dynamic rendering attachments.
VkPipelineCache getPipelineCache() const noexcept
Get the persistent Vulkan pipeline cache used by framework pipelines.
std::deque< ScreenshotSaveTask > screenshot_save_queue
void release()
Release Vulkan and SDL resources.
std::array< FrameReadbackSlot, max_frames_in_flight > frame_readback_slots
void setFont(const std::string &fontPath, int fontSize=24)
Set the active text-render font.
void setPostProcessingEnabled(bool enabled)
std::vector< VkDeviceMemory > depth_image_memories
std::vector< std::uint8_t > latest_frame_readback_rgba
PresentModePreference present_mode_preference
void printText(const std::string &text, int x, int y, const SDL_Color &col)
Queue a text string for rendering during the current frame.
static std::vector< char > loadSpv(const std::string &path)
Load a SPIR-V file from disk.
std::vector< std::unique_ptr< VK_Sprite3D > > sprites3d
VkExtent2D render_extent_override
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.
std::vector< VK_Sprite * > post_process_sprites
void trimMemory()
Return transient Vulkan command-pool allocations to the driver when supported.
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.
VK_Sprite * post_process_sprite
uint32_t latest_frame_readback_height
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.
void destroyFrameReadbackResources()
std::string fps_counter_text
virtual void render()
Render one frame.
bool initWindow(const std::string &title, int width, int height, SDL_WindowFlags flags)
Initialize SDL window resources.
bool headless() const noexcept
Return true when rendering without SDL video, a surface, or presentation.
std::vector< VkImage > depth_images
std::vector< VkDeviceMemory > headless_image_memories
bool post_process_texture_consumer_enabled
void setPostProcessingPresentFragmentShader(const std::string &path)
Set an optional fragment shader used only when presenting the final post-processing texture to a wind...
virtual void proc()
Execute one processing/update step.
bool validationEnabled() const
Check whether Vulkan validation layers are currently enabled.
VK_Window(const VK_Window &)=delete
virtual void onFrameReadbackScheduled()
Called after a presented frame has scheduled a readback.
std::vector< std::unique_ptr< VK_Sprite > > sprites
uint64_t last_resize_event_ms
VkExtent2D getRenderExtent() const noexcept
Get the active scene/post-processing extent.
VkPhysicalDevice getPhysicalDevice() const noexcept
Get the Vulkan physical device handle.
void setPostProcessingShaderTimeEnabled(bool enabled)
Keep shader param 1 updated with elapsed render time in seconds.
std::vector< std::vector< VkImage > > post_process_images
void setEnableScreenshot(bool enabled) noexcept
Enable or disable F10 screenshot capture.
std::string post_process_present_shader_path
void setPreviewFont(const std::string &fontPath, int fontSize=24)
Set the preview-only HUD font independently of output text.
VK_Sprite * owned_post_process_sprite
std::array< VkSemaphore, max_frames_in_flight > image_available
bool swapchain_supports_transfer_src
std::array< VkFence, max_frames_in_flight > in_flight_fences
VkFormat getSwapchainFormat() const noexcept
Get the swapchain color format.
VkFormat postProcessIntermediateFormat() const noexcept
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.
bool defaultEnableScreenshot()
const std::string & defaultExecutableName()
std::array< float, 4 > params
uint32_t spectrumHistoryLayerCount
VK_Sprite * historySource
uint32_t spectrumBinCount
std::string fragmentShaderPath
void operator()(SDL_Window *ptr) const
std::vector< std::uint8_t > rgba
Minimal Vulkan handles required by MXVK resource helpers.