11#include <condition_variable>
17#include <mxvk/mxvk_version.hpp>
24#ifdef ENABLE_VALIDATION
25#define MXVK_VALIDATION true
27#define MXVK_VALIDATION false
71 VK_Window(
const std::string &title,
int width,
int height,
bool full,
bool validiation,
bool enableVsync);
91 virtual void event(SDL_Event &e);
133 void setFont(
const std::string &fontPath,
int fontSize = 24);
142 void printText(
const std::string &text,
int x,
int y,
const SDL_Color &col);
143 void printText(
const std::string &text,
int x,
int y,
const SDL_Color &col, TTF_Font *font);
144 void printText(
const std::string &text,
int x,
int y,
const SDL_Color &col,
const Font &font);
156 void setClearColor(
float r,
float g,
float b,
float a = 1.0f);
216 [[nodiscard]]
bool getTextDimensions(
const std::string &text,
int &width,
int &height);
217 [[nodiscard]]
bool getTextDimensions(
const std::string &text,
int &width,
int &height, TTF_Font *font);
218 [[nodiscard]]
bool getTextDimensions(
const std::string &text,
int &width,
int &height,
const Font &font);
227 VK_Sprite *
createSprite(
const std::string &pngPath,
const std::string &vertexShaderPath =
"",
const std::string &fragmentShaderPath =
"");
246 VK_Sprite *
createSprite(
int width,
int height,
const std::string &vertexShaderPath =
"",
const std::string &fragmentShaderPath =
"");
293 VK_Sprite3D *
createSprite3D(
const std::string &pngPath,
const std::string &vertexShaderPath =
"",
const std::string &fragmentShaderPath =
"");
310 static VKAPI_ATTR VkBool32 VKAPI_CALL
debugCallback(VkDebugUtilsMessageSeverityFlagBitsEXT severity, [[maybe_unused]] VkDebugUtilsMessageTypeFlagsEXT type,
const VkDebugUtilsMessengerCallbackDataEXT *callback_data, [[maybe_unused]]
void *user_data);
323 static std::vector<char>
loadSpv(
const std::string &path);
342 bool initWindow(
const std::string &title,
int width,
int height, SDL_WindowFlags flags);
396 VkRenderingAttachmentInfo &stencil_attachment,
397 uint32_t image_index);
405 void captureSnapshotPixels(std::vector<std::uint8_t> &rgba_pixels, uint32_t &width, uint32_t &height);
416 static constexpr uint32_t invalid_queue_index = std::numeric_limits<uint32_t>::max();
417 static constexpr uint32_t max_frames_in_flight = 2;
419 static constexpr const char *validation_layer_name =
"VK_LAYER_KHRONOS_validation";
421 struct SwapchainSupport {
422 VkSurfaceCapabilitiesKHR capabilities{};
423 std::vector<VkSurfaceFormatKHR> formats{};
424 std::vector<VkPresentModeKHR> present_modes{};
427 static SwapchainSupport querySwapchainSupport(VkPhysicalDevice
device, VkSurfaceKHR
surface);
428 static VkSurfaceFormatKHR chooseSurfaceFormat(
const std::vector<VkSurfaceFormatKHR> &available_formats);
429 VkPresentModeKHR choosePresentMode(
const std::vector<VkPresentModeKHR> &available_present_modes)
const;
430 static VkExtent2D chooseExtent(
const VkSurfaceCapabilitiesKHR &capabilities, SDL_Window *
window);
431 static bool hasValidationLayerSupport();
432 static std::optional<VkDebugUtilsMessengerCreateInfoEXT> makeDebugMessengerCreateInfo();
433 void setupDebugMessenger();
434 void cleanupDebugMessenger();
435 bool createSwapchain(VkSwapchainKHR old_swapchain);
436 bool createRenderResources();
437 bool createSyncObjects();
438 void cleanupSyncObjects();
439 void cleanupSwapchain(
bool preserveCommandPool =
true);
440 void recreateSwapchain();
442 [[nodiscard]] std::string pipelineCachePath()
const;
443 void createPipelineCache();
444 void savePipelineCache()
const;
445 void destroyPipelineCache();
446 [[nodiscard]] std::string resolveRuntimeShaderPath(
const std::string &shaderFileName,
const char *fallbackDir)
const;
447 void createSpriteDescriptorSetLayout();
448 void createSpritePipeline();
449 void destroySpritePipeline();
450 void createPostProcessTargets();
451 void destroyPostProcessTargets();
452 void ensureTextRenderer();
453 void createTextDescriptorSetLayout();
454 void createTextPipeline();
455 void destroyTextPipeline();
456 void maybeTrimMemory();
457 void saveScreenshot();
458 [[nodiscard]] std::string makeScreenshotPath();
459 void enqueueScreenshotSave(std::string path, std::vector<std::uint8_t> rgba, uint32_t width, uint32_t height);
460 void startScreenshotWorker();
461 void stopScreenshotWorker();
462 void screenshotWorkerLoop();
463 [[nodiscard]]
bool isPostProcessSprite(
const VK_Sprite *sprite)
const;
464 [[nodiscard]] std::string resolveDefaultFontPath()
const;
465 void ensureTextRenderer(
const std::string &fallbackFontPath,
int fallbackFontSize);
466 void toggleFpsCounter();
467 void updateFpsCounter();
474 if (ptr !=
nullptr) {
475 SDL_DestroyWindow(ptr);
480 std::unique_ptr<SDL_Window, SDLWindowDeleter>
window{};
522 std::vector<std::uint8_t>
rgba;
540 std::vector<std::unique_ptr<VK_Sprite>>
sprites{};
Small RAII wrapper for an SDL_ttf font handle.
Depth-tested 3D billboard sprite batch.
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.
virtual ~VK_Window()
Destroy owned Vulkan and SDL resources.
void pickDevice()
Pick a suitable Vulkan physical device.
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< bool > post_process_effect_time_enabled
VulkanContext context() const
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::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 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.
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
VkPipelineCache pipeline_cache
std::unique_ptr< SDL_Window, SDLWindowDeleter > window
std::vector< std::chrono::steady_clock::time_point > post_process_effect_start_times
VkPipeline sprite_pipeline
void exit()
Request loop termination.
VkCommandPool command_pool
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.
VK_Window(VK_Window &&)=delete
bool ensureRenderResources()
Ensure deferred render resources are initialized.
VK_Window()=default
Construct an empty window object.
VkPhysicalDevice physical_device
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
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.
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
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
std::vector< VK_Sprite * > post_process_sprites
void trimMemory()
Return transient Vulkan command-pool allocations to the driver when supported.
VK_Sprite * post_process_sprite
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.
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.
std::vector< VkImage > depth_images
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
std::vector< std::unique_ptr< VK_Sprite > > sprites
uint64_t last_resize_event_ms
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.
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.
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
std::string fragmentShaderPath
void operator()(SDL_Window *ptr) const
std::vector< std::uint8_t > rgba
Minimal Vulkan handles required by MXVK resource helpers.