2016-02-16 15:07:25 +01:00
/*
* Vulkan Example base class
*
2025-02-06 21:25:43 +01:00
* Copyright ( C ) 2016 - 2025 by Sascha Willems - www . saschawillems . de
2016-02-16 15:07:25 +01:00
*
* This code is licensed under the MIT license ( MIT ) ( http : //opensource.org/licenses/MIT)
*/
# include "vulkanexamplebase.h"
2024-05-04 07:53:08 -04:00
# if defined(VK_EXAMPLE_XCODE_GENERATED)
# if (defined(VK_USE_PLATFORM_MACOS_MVK) || defined(VK_USE_PLATFORM_METAL_EXT))
2020-09-12 03:19:28 +09:00
# include <Cocoa/Cocoa.h>
# include <QuartzCore/CAMetalLayer.h>
# include <CoreVideo/CVDisplayLink.h>
# endif
2024-05-04 07:53:08 -04:00
# else // !defined(VK_EXAMPLE_XCODE_GENERATED)
# if defined(VK_USE_PLATFORM_METAL_EXT)
// SRS - Metal layer is defined externally when using iOS/macOS displayLink-driven examples project
extern CAMetalLayer * layer ;
# endif
# endif
2020-09-12 03:19:28 +09:00
2016-11-10 22:56:15 +01:00
std : : vector < const char * > VulkanExampleBase : : args ;
2016-11-10 22:29:55 +01:00
2024-05-25 18:02:38 +02:00
VkResult VulkanExampleBase : : createInstance ( )
2016-02-16 15:07:25 +01:00
{
2017-02-09 19:22:48 +01:00
std : : vector < const char * > instanceExtensions = { VK_KHR_SURFACE_EXTENSION_NAME } ;
2016-02-16 15:07:25 +01:00
2016-03-20 14:55:46 +01:00
// Enable surface extensions depending on os
# if defined(_WIN32)
2017-02-09 19:22:48 +01:00
instanceExtensions . push_back ( VK_KHR_WIN32_SURFACE_EXTENSION_NAME ) ;
2017-08-13 10:24:25 +02:00
# elif defined(VK_USE_PLATFORM_ANDROID_KHR)
2017-02-09 19:22:48 +01:00
instanceExtensions . push_back ( VK_KHR_ANDROID_SURFACE_EXTENSION_NAME ) ;
2016-11-04 13:32:58 -07:00
# elif defined(_DIRECT2DISPLAY)
2017-02-09 19:22:48 +01:00
instanceExtensions . push_back ( VK_KHR_DISPLAY_EXTENSION_NAME ) ;
2020-09-13 10:12:33 +02:00
# elif defined(VK_USE_PLATFORM_DIRECTFB_EXT)
instanceExtensions . push_back ( VK_EXT_DIRECTFB_SURFACE_EXTENSION_NAME ) ;
2017-02-02 08:54:56 +00:00
# elif defined(VK_USE_PLATFORM_WAYLAND_KHR)
2017-02-09 19:22:48 +01:00
instanceExtensions . push_back ( VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME ) ;
2017-08-13 10:24:25 +02:00
# elif defined(VK_USE_PLATFORM_XCB_KHR)
2017-02-09 19:22:48 +01:00
instanceExtensions . push_back ( VK_KHR_XCB_SURFACE_EXTENSION_NAME ) ;
2017-06-30 21:55:17 -04:00
# elif defined(VK_USE_PLATFORM_IOS_MVK)
2017-07-29 19:31:00 +02:00
instanceExtensions . push_back ( VK_MVK_IOS_SURFACE_EXTENSION_NAME ) ;
2017-06-30 21:55:17 -04:00
# elif defined(VK_USE_PLATFORM_MACOS_MVK)
2017-07-29 19:31:00 +02:00
instanceExtensions . push_back ( VK_MVK_MACOS_SURFACE_EXTENSION_NAME ) ;
2024-05-04 07:53:08 -04:00
# elif defined(VK_USE_PLATFORM_METAL_EXT)
instanceExtensions . push_back ( VK_EXT_METAL_SURFACE_EXTENSION_NAME ) ;
2021-04-27 13:52:27 +02:00
# elif defined(VK_USE_PLATFORM_HEADLESS_EXT)
instanceExtensions . push_back ( VK_EXT_HEADLESS_SURFACE_EXTENSION_NAME ) ;
2023-09-01 11:12:08 -04:00
# elif defined(VK_USE_PLATFORM_SCREEN_QNX)
instanceExtensions . push_back ( VK_QNX_SCREEN_SURFACE_EXTENSION_NAME ) ;
2016-02-16 15:07:25 +01:00
# endif
2024-01-21 05:07:35 -08:00
2020-08-27 19:56:02 +02:00
// Get extensions supported by the instance and store for later use
uint32_t extCount = 0 ;
2020-08-27 19:36:24 +02:00
vkEnumerateInstanceExtensionProperties ( nullptr , & extCount , nullptr ) ;
if ( extCount > 0 )
{
2020-08-27 19:56:02 +02:00
std : : vector < VkExtensionProperties > extensions ( extCount ) ;
if ( vkEnumerateInstanceExtensionProperties ( nullptr , & extCount , & extensions . front ( ) ) = = VK_SUCCESS )
{
2023-12-30 13:30:16 +01:00
for ( VkExtensionProperties & extension : extensions )
2020-08-27 19:56:02 +02:00
{
2020-08-27 22:24:43 +02:00
supportedInstanceExtensions . push_back ( extension . extensionName ) ;
2020-08-27 19:56:02 +02:00
}
}
2020-08-27 19:36:24 +02:00
}
2024-05-04 07:53:08 -04:00
# if (defined(VK_USE_PLATFORM_IOS_MVK) || defined(VK_USE_PLATFORM_MACOS_MVK) || defined(VK_USE_PLATFORM_METAL_EXT))
2022-07-08 15:17:56 -04:00
// SRS - When running on iOS/macOS with MoltenVK, enable VK_KHR_get_physical_device_properties2 if not already enabled by the example (required by VK_KHR_portability_subset)
if ( std : : find ( enabledInstanceExtensions . begin ( ) , enabledInstanceExtensions . end ( ) , VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME ) = = enabledInstanceExtensions . end ( ) )
2022-05-09 14:16:16 -04:00
{
2022-07-08 15:17:56 -04:00
enabledInstanceExtensions . push_back ( VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME ) ;
2022-05-09 14:16:16 -04:00
}
# endif
2020-08-27 19:56:02 +02:00
// Enabled requested instance extensions
2025-02-28 18:18:49 +01:00
if ( ! enabledInstanceExtensions . empty ( ) )
2020-08-27 19:56:02 +02:00
{
2024-01-21 05:07:35 -08:00
for ( const char * enabledExtension : enabledInstanceExtensions )
2020-08-27 19:56:02 +02:00
{
// Output message if requested extension is not available
if ( std : : find ( supportedInstanceExtensions . begin ( ) , supportedInstanceExtensions . end ( ) , enabledExtension ) = = supportedInstanceExtensions . end ( ) )
{
std : : cerr < < " Enabled instance extension \" " < < enabledExtension < < " \" is not present at instance level \n " ;
}
2018-03-03 11:49:46 +01:00
instanceExtensions . push_back ( enabledExtension ) ;
}
}
2025-04-23 19:32:14 +02:00
// Shaders generated by Slang require a certain SPIR-V environment that can't be satisfied by Vulkan 1.0, so we need to expliclity up that to at least 1.1 and enable some required extensions
if ( shaderDir = = " slang " ) {
if ( apiVersion < VK_API_VERSION_1_1 ) {
apiVersion = VK_API_VERSION_1_1 ;
}
enabledDeviceExtensions . push_back ( VK_KHR_SPIRV_1_4_EXTENSION_NAME ) ;
enabledDeviceExtensions . push_back ( VK_KHR_SHADER_FLOAT_CONTROLS_EXTENSION_NAME ) ;
}
2024-05-25 18:02:38 +02:00
VkApplicationInfo appInfo { } ;
appInfo . sType = VK_STRUCTURE_TYPE_APPLICATION_INFO ;
appInfo . pApplicationName = name . c_str ( ) ;
appInfo . pEngineName = name . c_str ( ) ;
appInfo . apiVersion = apiVersion ;
VkInstanceCreateInfo instanceCreateInfo { } ;
2016-02-16 15:07:25 +01:00
instanceCreateInfo . sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO ;
instanceCreateInfo . pApplicationInfo = & appInfo ;
2022-06-23 15:21:14 -05:00
2024-01-21 05:07:35 -08:00
VkDebugUtilsMessengerCreateInfoEXT debugUtilsMessengerCI { } ;
if ( settings . validation ) {
vks : : debug : : setupDebugingMessengerCreateInfo ( debugUtilsMessengerCI ) ;
debugUtilsMessengerCI . pNext = instanceCreateInfo . pNext ;
instanceCreateInfo . pNext = & debugUtilsMessengerCI ;
}
2024-05-04 07:53:08 -04:00
# if (defined(VK_USE_PLATFORM_IOS_MVK) || defined(VK_USE_PLATFORM_MACOS_MVK) || defined(VK_USE_PLATFORM_METAL_EXT)) && defined(VK_KHR_portability_enumeration)
2022-07-08 15:17:56 -04:00
// SRS - When running on iOS/macOS with MoltenVK and VK_KHR_portability_enumeration is defined and supported by the instance, enable the extension and the flag
if ( std : : find ( supportedInstanceExtensions . begin ( ) , supportedInstanceExtensions . end ( ) , VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME ) ! = supportedInstanceExtensions . end ( ) )
{
instanceExtensions . push_back ( VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME ) ;
2025-03-29 11:21:37 -04:00
instanceCreateInfo . flags | = VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR ;
2022-07-08 15:17:56 -04:00
}
2022-06-23 15:21:14 -05:00
# endif
2023-05-09 20:04:34 +02:00
// Enable the debug utils extension if available (e.g. when debugging tools are present)
if ( settings . validation | | std : : find ( supportedInstanceExtensions . begin ( ) , supportedInstanceExtensions . end ( ) , VK_EXT_DEBUG_UTILS_EXTENSION_NAME ) ! = supportedInstanceExtensions . end ( ) ) {
instanceExtensions . push_back ( VK_EXT_DEBUG_UTILS_EXTENSION_NAME ) ;
}
2025-02-28 18:18:49 +01:00
if ( ! instanceExtensions . empty ( ) ) {
2017-02-09 19:22:48 +01:00
instanceCreateInfo . enabledExtensionCount = ( uint32_t ) instanceExtensions . size ( ) ;
instanceCreateInfo . ppEnabledExtensionNames = instanceExtensions . data ( ) ;
2016-02-16 15:07:25 +01:00
}
2021-01-18 17:41:41 +01:00
// The VK_LAYER_KHRONOS_validation contains all current validation functionality.
// Note that on Android this layer requires at least NDK r20
const char * validationLayerName = " VK_LAYER_KHRONOS_validation " ;
2024-05-25 18:02:38 +02:00
if ( settings . validation ) {
2019-10-18 20:28:54 +02:00
// Check if this layer is available at instance level
uint32_t instanceLayerCount ;
vkEnumerateInstanceLayerProperties ( & instanceLayerCount , nullptr ) ;
std : : vector < VkLayerProperties > instanceLayerProperties ( instanceLayerCount ) ;
vkEnumerateInstanceLayerProperties ( & instanceLayerCount , instanceLayerProperties . data ( ) ) ;
bool validationLayerPresent = false ;
2023-12-30 13:30:16 +01:00
for ( VkLayerProperties & layer : instanceLayerProperties ) {
2019-10-18 20:28:54 +02:00
if ( strcmp ( layer . layerName , validationLayerName ) = = 0 ) {
validationLayerPresent = true ;
break ;
}
}
if ( validationLayerPresent ) {
instanceCreateInfo . ppEnabledLayerNames = & validationLayerName ;
instanceCreateInfo . enabledLayerCount = 1 ;
} else {
std : : cerr < < " Validation layer VK_LAYER_KHRONOS_validation not present, validation is disabled " ;
}
2016-02-16 15:07:25 +01:00
}
2025-03-29 11:21:37 -04:00
// If layer settings are defined, then activate the sample's required layer settings during instance creation.
// Layer settings are typically used to activate specific features of a layer, such as the Validation Layer's
// printf feature, or to configure specific capabilities of drivers such as MoltenVK on macOS and/or iOS.
VkLayerSettingsCreateInfoEXT layerSettingsCreateInfo { VK_STRUCTURE_TYPE_LAYER_SETTINGS_CREATE_INFO_EXT } ;
if ( enabledLayerSettings . size ( ) > 0 ) {
layerSettingsCreateInfo . settingCount = static_cast < uint32_t > ( enabledLayerSettings . size ( ) ) ;
layerSettingsCreateInfo . pSettings = enabledLayerSettings . data ( ) ;
layerSettingsCreateInfo . pNext = instanceCreateInfo . pNext ;
instanceCreateInfo . pNext = & layerSettingsCreateInfo ;
}
2023-05-09 20:04:34 +02:00
VkResult result = vkCreateInstance ( & instanceCreateInfo , nullptr , & instance ) ;
2024-01-01 16:41:38 +01:00
// If the debug utils extension is present we set up debug functions, so samples can label objects for debugging
2023-05-09 20:04:34 +02:00
if ( std : : find ( supportedInstanceExtensions . begin ( ) , supportedInstanceExtensions . end ( ) , VK_EXT_DEBUG_UTILS_EXTENSION_NAME ) ! = supportedInstanceExtensions . end ( ) ) {
vks : : debugutils : : setup ( instance ) ;
}
return result ;
2016-02-16 15:07:25 +01:00
}
2020-04-19 10:05:47 +02:00
void VulkanExampleBase : : renderFrame ( )
2020-04-19 09:17:53 +02:00
{
VulkanExampleBase : : prepareFrame ( ) ;
submitInfo . commandBufferCount = 1 ;
submitInfo . pCommandBuffers = & drawCmdBuffers [ currentBuffer ] ;
VK_CHECK_RESULT ( vkQueueSubmit ( queue , 1 , & submitInfo , VK_NULL_HANDLE ) ) ;
VulkanExampleBase : : submitFrame ( ) ;
}
2024-11-23 15:37:57 +01:00
std : : string VulkanExampleBase : : getWindowTitle ( ) const
2016-03-13 16:51:00 +01:00
{
2024-05-25 18:02:38 +02:00
std : : string windowTitle { title + " - " + deviceProperties . deviceName } ;
2017-10-29 11:41:43 +01:00
if ( ! settings . overlay ) {
2016-07-24 21:18:25 +02:00
windowTitle + = " - " + std : : to_string ( frameCounter ) + " fps " ;
}
2016-03-13 16:51:00 +01:00
return windowTitle ;
}
2016-02-16 15:07:25 +01:00
void VulkanExampleBase : : createCommandBuffers ( )
{
2024-05-25 18:02:38 +02:00
// Create one command buffer for each swap chain image
2024-12-19 21:29:22 +01:00
drawCmdBuffers . resize ( swapChain . images . size ( ) ) ;
2024-05-25 18:02:38 +02:00
VkCommandBufferAllocateInfo cmdBufAllocateInfo = vks : : initializers : : commandBufferAllocateInfo ( cmdPool , VK_COMMAND_BUFFER_LEVEL_PRIMARY , static_cast < uint32_t > ( drawCmdBuffers . size ( ) ) ) ;
2016-05-22 20:27:06 +02:00
VK_CHECK_RESULT ( vkAllocateCommandBuffers ( device , & cmdBufAllocateInfo , drawCmdBuffers . data ( ) ) ) ;
2016-02-16 15:07:25 +01:00
}
void VulkanExampleBase : : destroyCommandBuffers ( )
{
2016-06-21 23:07:16 +02:00
vkFreeCommandBuffers ( device , cmdPool , static_cast < uint32_t > ( drawCmdBuffers . size ( ) ) , drawCmdBuffers . data ( ) ) ;
2016-02-16 15:07:25 +01:00
}
2020-05-29 16:36:27 +01:00
std : : string VulkanExampleBase : : getShadersPath ( ) const
{
2023-05-10 20:34:09 +02:00
return getShaderBasePath ( ) + shaderDir + " / " ;
2020-05-29 16:36:27 +01:00
}
2016-02-16 15:07:25 +01:00
void VulkanExampleBase : : createPipelineCache ( )
{
VkPipelineCacheCreateInfo pipelineCacheCreateInfo = { } ;
pipelineCacheCreateInfo . sType = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO ;
2016-05-22 20:27:06 +02:00
VK_CHECK_RESULT ( vkCreatePipelineCache ( device , & pipelineCacheCreateInfo , nullptr , & pipelineCache ) ) ;
2016-02-16 15:07:25 +01:00
}
void VulkanExampleBase : : prepare ( )
{
2024-11-30 21:21:07 +01:00
createSurface ( ) ;
2016-02-16 15:07:25 +01:00
createCommandPool ( ) ;
2024-11-30 21:21:07 +01:00
createSwapChain ( ) ;
2016-02-16 15:07:25 +01:00
createCommandBuffers ( ) ;
2018-06-03 09:38:14 +02:00
createSynchronizationPrimitives ( ) ;
2016-02-16 15:07:25 +01:00
setupDepthStencil ( ) ;
setupRenderPass ( ) ;
createPipelineCache ( ) ;
setupFrameBuffer ( ) ;
2017-10-29 11:41:43 +01:00
settings . overlay = settings . overlay & & ( ! benchmark . active ) ;
if ( settings . overlay ) {
2024-05-23 21:56:42 +02:00
ui . device = vulkanDevice ;
ui . queue = queue ;
ui . shaders = {
2024-05-23 22:20:44 +02:00
loadShader ( getShadersPath ( ) + " base/uioverlay.vert.spv " , VK_SHADER_STAGE_VERTEX_BIT ) ,
loadShader ( getShadersPath ( ) + " base/uioverlay.frag.spv " , VK_SHADER_STAGE_FRAGMENT_BIT ) ,
2018-08-31 21:15:43 +02:00
} ;
2024-05-23 21:56:42 +02:00
ui . prepareResources ( ) ;
ui . preparePipeline ( pipelineCache , renderPass , swapChain . colorFormat , depthFormat ) ;
2016-05-15 18:31:31 +02:00
}
2016-02-16 15:07:25 +01:00
}
2016-03-21 20:10:09 +01:00
VkPipelineShaderStageCreateInfo VulkanExampleBase : : loadShader ( std : : string fileName , VkShaderStageFlagBits stage )
2016-02-16 15:07:25 +01:00
{
VkPipelineShaderStageCreateInfo shaderStage = { } ;
shaderStage . sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO ;
shaderStage . stage = stage ;
2017-08-13 10:24:25 +02:00
# if defined(VK_USE_PLATFORM_ANDROID_KHR)
2017-04-23 11:51:31 +02:00
shaderStage . module = vks : : tools : : loadShader ( androidApp - > activity - > assetManager , fileName . c_str ( ) , device ) ;
2016-03-20 15:45:40 +01:00
# else
2017-04-23 11:51:31 +02:00
shaderStage . module = vks : : tools : : loadShader ( fileName . c_str ( ) , device ) ;
2016-03-20 15:45:40 +01:00
# endif
2020-08-08 13:25:58 +02:00
shaderStage . pName = " main " ;
2017-02-15 10:42:39 +00:00
assert ( shaderStage . module ! = VK_NULL_HANDLE ) ;
2016-02-16 15:07:25 +01:00
shaderModules . push_back ( shaderStage . module ) ;
return shaderStage ;
}
2020-04-19 10:05:47 +02:00
void VulkanExampleBase : : nextFrame ( )
2017-04-14 12:00:05 -04:00
{
2022-06-11 20:14:55 -04:00
auto tStart = std : : chrono : : high_resolution_clock : : now ( ) ;
2017-07-29 19:31:00 +02:00
if ( viewUpdated )
{
viewUpdated = false ;
}
render ( ) ;
frameCounter + + ;
auto tEnd = std : : chrono : : high_resolution_clock : : now ( ) ;
2024-05-04 07:53:08 -04:00
# if (defined(VK_USE_PLATFORM_IOS_MVK) || defined(VK_USE_PLATFORM_MACOS_MVK) || defined(VK_USE_PLATFORM_METAL_EXT)) && !defined(VK_EXAMPLE_XCODE_GENERATED)
2022-06-11 20:14:55 -04:00
// SRS - Calculate tDiff as time between frames vs. rendering time for iOS/macOS displayLink-driven examples project
2022-06-01 12:46:41 -04:00
auto tDiff = std : : chrono : : duration < double , std : : milli > ( tEnd - tPrevEnd ) . count ( ) ;
2022-06-11 20:14:55 -04:00
# else
auto tDiff = std : : chrono : : duration < double , std : : milli > ( tEnd - tStart ) . count ( ) ;
# endif
2017-07-29 19:31:00 +02:00
frameTimer = ( float ) tDiff / 1000.0f ;
camera . update ( frameTimer ) ;
if ( camera . moving ( ) )
{
viewUpdated = true ;
}
// Convert to clamped timer value
if ( ! paused )
{
timer + = timerSpeed * frameTimer ;
if ( timer > 1.0 )
{
timer - = 1.0f ;
}
}
2019-08-18 18:33:16 +02:00
float fpsTimer = ( float ) ( std : : chrono : : duration < double , std : : milli > ( tEnd - lastTimestamp ) . count ( ) ) ;
2017-07-29 19:31:00 +02:00
if ( fpsTimer > 1000.0f )
{
2018-01-21 18:27:06 +01:00
lastFPS = static_cast < uint32_t > ( ( float ) frameCounter * ( 1000.0f / fpsTimer ) ) ;
2017-07-29 19:31:00 +02:00
# if defined(_WIN32)
2017-10-29 11:41:43 +01:00
if ( ! settings . overlay ) {
2017-07-29 19:31:00 +02:00
std : : string windowTitle = getWindowTitle ( ) ;
SetWindowText ( window , windowTitle . c_str ( ) ) ;
}
2017-04-14 12:00:05 -04:00
# endif
2017-07-29 19:31:00 +02:00
frameCounter = 0 ;
2019-02-23 20:38:09 +00:00
lastTimestamp = tEnd ;
2017-07-29 19:31:00 +02:00
}
2022-06-01 12:46:41 -04:00
tPrevEnd = tEnd ;
2024-01-21 05:07:35 -08:00
2017-10-29 11:41:43 +01:00
updateOverlay ( ) ;
2017-07-29 19:31:00 +02:00
}
2016-02-16 15:07:25 +01:00
void VulkanExampleBase : : renderLoop ( )
{
2022-08-01 16:52:06 -04:00
// SRS - for non-apple plaforms, handle benchmarking here within VulkanExampleBase::renderLoop()
// - for macOS, handle benchmarking within NSApp rendering loop via displayLinkOutputCb()
2024-05-04 07:53:08 -04:00
# if !(defined(VK_USE_PLATFORM_IOS_MVK) || defined(VK_USE_PLATFORM_MACOS_MVK) || defined(VK_USE_PLATFORM_METAL_EXT))
2017-07-29 19:31:00 +02:00
if ( benchmark . active ) {
2023-06-13 14:52:30 +08:00
# if defined(VK_USE_PLATFORM_WAYLAND_KHR)
while ( ! configured )
2024-10-08 14:31:28 -04:00
{
if ( wl_display_dispatch ( display ) = = - 1 )
break ;
}
2023-06-13 14:52:30 +08:00
while ( wl_display_prepare_read ( display ) ! = 0 )
2024-10-08 14:31:28 -04:00
{
if ( wl_display_dispatch_pending ( display ) = = - 1 )
break ;
}
2023-06-13 14:52:30 +08:00
wl_display_flush ( display ) ;
wl_display_read_events ( display ) ;
2024-10-08 14:31:28 -04:00
if ( wl_display_dispatch_pending ( display ) = = - 1 )
return ;
2023-06-13 14:52:30 +08:00
# endif
2018-01-19 21:43:00 +01:00
benchmark . run ( [ = ] { render ( ) ; } , vulkanDevice - > properties ) ;
2017-08-26 14:05:48 +02:00
vkDeviceWaitIdle ( device ) ;
2025-02-28 18:18:49 +01:00
if ( ! benchmark . filename . empty ( ) ) {
2018-01-19 21:43:00 +01:00
benchmark . saveResults ( ) ;
}
2017-07-29 19:31:00 +02:00
return ;
}
2022-08-01 16:52:06 -04:00
# endif
2017-07-29 19:31:00 +02:00
2016-05-03 21:22:45 +02:00
destWidth = width ;
destHeight = height ;
2019-02-23 20:38:09 +00:00
lastTimestamp = std : : chrono : : high_resolution_clock : : now ( ) ;
2022-06-01 12:46:41 -04:00
tPrevEnd = lastTimestamp ;
2016-03-20 14:55:46 +01:00
# if defined(_WIN32)
2016-02-16 15:07:25 +01:00
MSG msg ;
2017-06-27 09:03:26 +02:00
bool quitMessageReceived = false ;
2017-07-29 19:31:00 +02:00
while ( ! quitMessageReceived ) {
while ( PeekMessage ( & msg , NULL , 0 , 0 , PM_REMOVE ) ) {
2016-07-31 12:41:50 +02:00
TranslateMessage ( & msg ) ;
DispatchMessage ( & msg ) ;
2017-07-29 19:31:00 +02:00
if ( msg . message = = WM_QUIT ) {
2017-06-27 09:03:26 +02:00
quitMessageReceived = true ;
break ;
}
2016-07-31 12:41:50 +02:00
}
2020-04-19 09:17:53 +02:00
if ( prepared & & ! IsIconic ( window ) ) {
2020-04-19 10:05:47 +02:00
nextFrame ( ) ;
2018-06-30 21:56:23 +02:00
}
2016-02-16 15:07:25 +01:00
}
2017-08-13 10:24:25 +02:00
# elif defined(VK_USE_PLATFORM_ANDROID_KHR)
2025-02-28 18:18:49 +01:00
while ( true )
2016-03-20 20:04:27 +01:00
{
int ident ;
int events ;
struct android_poll_source * source ;
2016-03-26 12:58:35 +01:00
bool destroy = false ;
2016-03-20 20:04:27 +01:00
2016-03-26 12:58:35 +01:00
focused = true ;
2025-02-28 18:18:49 +01:00
while ( ( ident = ALooper_pollOnce ( focused ? 0 : - 1 , nullptr , & events , ( void * * ) & source ) ) > ALOOPER_POLL_TIMEOUT )
2016-03-20 20:04:27 +01:00
{
2025-02-28 18:18:49 +01:00
if ( source ! = nullptr )
2016-03-20 20:04:27 +01:00
{
source - > process ( androidApp , source ) ;
}
if ( androidApp - > destroyRequested ! = 0 )
{
2016-03-26 12:58:35 +01:00
LOGD ( " Android app destroy requested " ) ;
destroy = true ;
break ;
2016-03-20 20:04:27 +01:00
}
}
2016-03-26 12:58:35 +01:00
// App destruction requested
// Exit loop, example will be destroyed in application main
if ( destroy )
{
2018-06-01 18:41:26 +02:00
ANativeActivity_finish ( androidApp - > activity ) ;
2016-03-26 12:58:35 +01:00
break ;
}
2016-03-20 20:04:27 +01:00
// Render frame
if ( prepared )
{
2016-03-23 22:16:05 +01:00
auto tStart = std : : chrono : : high_resolution_clock : : now ( ) ;
2016-03-20 20:04:27 +01:00
render ( ) ;
2016-03-23 22:16:05 +01:00
frameCounter + + ;
auto tEnd = std : : chrono : : high_resolution_clock : : now ( ) ;
auto tDiff = std : : chrono : : duration < double , std : : milli > ( tEnd - tStart ) . count ( ) ;
frameTimer = tDiff / 1000.0f ;
2016-06-11 15:54:16 +02:00
camera . update ( frameTimer ) ;
2016-03-24 22:43:33 +01:00
// Convert to clamped timer value
if ( ! paused )
{
timer + = timerSpeed * frameTimer ;
if ( timer > 1.0 )
{
timer - = 1.0f ;
}
}
2019-02-23 20:38:09 +00:00
float fpsTimer = std : : chrono : : duration < double , std : : milli > ( tEnd - lastTimestamp ) . count ( ) ;
2016-04-15 21:24:50 +02:00
if ( fpsTimer > 1000.0f )
{
2017-12-01 13:10:07 +01:00
lastFPS = ( float ) frameCounter * ( 1000.0f / fpsTimer ) ;
2016-05-22 20:27:06 +02:00
frameCounter = 0 ;
2019-02-23 20:38:09 +00:00
lastTimestamp = tEnd ;
2016-04-15 21:24:50 +02:00
}
2017-03-06 22:11:19 +01:00
2017-11-01 13:29:57 +01:00
updateOverlay ( ) ;
2017-03-06 22:11:19 +01:00
// Check touch state (for movement)
if ( touchDown ) {
touchTimer + = frameTimer ;
}
if ( touchTimer > = 1.0 ) {
camera . keys . up = true ;
}
2016-03-20 21:46:49 +01:00
// Check gamepad state
2016-03-26 00:07:12 +01:00
const float deadZone = 0.0015f ;
2016-06-20 22:08:50 +02:00
if ( camera . type ! = Camera : : CameraType : : firstperson )
2016-03-20 21:46:49 +01:00
{
2016-06-20 22:08:50 +02:00
// Rotate
if ( std : : abs ( gamePadState . axisLeft . x ) > deadZone )
{
camera . rotate ( glm : : vec3 ( 0.0f , gamePadState . axisLeft . x * 0.5f , 0.0f ) ) ;
}
if ( std : : abs ( gamePadState . axisLeft . y ) > deadZone )
{
camera . rotate ( glm : : vec3 ( gamePadState . axisLeft . y * 0.5f , 0.0f , 0.0f ) ) ;
}
// Zoom
if ( std : : abs ( gamePadState . axisRight . y ) > deadZone )
{
2020-04-22 20:58:24 +02:00
camera . translate ( glm : : vec3 ( 0.0f , 0.0f , gamePadState . axisRight . y * 0.01f ) ) ;
2016-06-20 22:08:50 +02:00
}
2016-03-20 21:46:49 +01:00
}
2016-06-20 22:08:50 +02:00
else
2016-03-20 21:46:49 +01:00
{
2025-02-28 18:18:49 +01:00
camera . updatePad ( gamePadState . axisLeft , gamePadState . axisRight , frameTimer ) ;
2016-03-20 21:46:49 +01:00
}
2016-03-20 20:04:27 +01:00
}
}
2016-11-04 13:32:58 -07:00
# elif defined(_DIRECT2DISPLAY)
while ( ! quit )
{
auto tStart = std : : chrono : : high_resolution_clock : : now ( ) ;
if ( viewUpdated )
{
viewUpdated = false ;
}
render ( ) ;
frameCounter + + ;
auto tEnd = std : : chrono : : high_resolution_clock : : now ( ) ;
auto tDiff = std : : chrono : : duration < double , std : : milli > ( tEnd - tStart ) . count ( ) ;
frameTimer = tDiff / 1000.0f ;
camera . update ( frameTimer ) ;
if ( camera . moving ( ) )
{
viewUpdated = true ;
}
// Convert to clamped timer value
if ( ! paused )
{
timer + = timerSpeed * frameTimer ;
if ( timer > 1.0 )
{
timer - = 1.0f ;
}
}
2019-02-23 20:38:09 +00:00
float fpsTimer = std : : chrono : : duration < double , std : : milli > ( tEnd - lastTimestamp ) . count ( ) ;
2016-11-04 13:32:58 -07:00
if ( fpsTimer > 1000.0f )
{
2017-12-01 13:10:07 +01:00
lastFPS = ( float ) frameCounter * ( 1000.0f / fpsTimer ) ;
2016-11-04 13:32:58 -07:00
frameCounter = 0 ;
2019-02-23 20:38:09 +00:00
lastTimestamp = tEnd ;
2016-11-04 13:32:58 -07:00
}
2017-11-01 13:29:57 +01:00
updateOverlay ( ) ;
2016-11-04 13:32:58 -07:00
}
2020-09-13 10:12:33 +02:00
# elif defined(VK_USE_PLATFORM_DIRECTFB_EXT)
while ( ! quit )
{
auto tStart = std : : chrono : : high_resolution_clock : : now ( ) ;
if ( viewUpdated )
{
viewUpdated = false ;
}
DFBWindowEvent event ;
while ( ! event_buffer - > GetEvent ( event_buffer , DFB_EVENT ( & event ) ) )
{
handleEvent ( & event ) ;
}
render ( ) ;
frameCounter + + ;
auto tEnd = std : : chrono : : high_resolution_clock : : now ( ) ;
auto tDiff = std : : chrono : : duration < double , std : : milli > ( tEnd - tStart ) . count ( ) ;
frameTimer = tDiff / 1000.0f ;
camera . update ( frameTimer ) ;
if ( camera . moving ( ) )
{
viewUpdated = true ;
}
// Convert to clamped timer value
if ( ! paused )
{
timer + = timerSpeed * frameTimer ;
if ( timer > 1.0 )
{
timer - = 1.0f ;
}
}
float fpsTimer = std : : chrono : : duration < double , std : : milli > ( tEnd - lastTimestamp ) . count ( ) ;
if ( fpsTimer > 1000.0f )
{
lastFPS = ( float ) frameCounter * ( 1000.0f / fpsTimer ) ;
frameCounter = 0 ;
lastTimestamp = tEnd ;
}
updateOverlay ( ) ;
}
2017-02-02 08:54:56 +00:00
# elif defined(VK_USE_PLATFORM_WAYLAND_KHR)
while ( ! quit )
{
auto tStart = std : : chrono : : high_resolution_clock : : now ( ) ;
if ( viewUpdated )
{
viewUpdated = false ;
}
2017-02-14 18:52:02 +00:00
2019-01-16 01:16:58 -07:00
while ( ! configured )
2024-10-08 14:31:28 -04:00
{
if ( wl_display_dispatch ( display ) = = - 1 )
break ;
}
2017-02-14 18:52:02 +00:00
while ( wl_display_prepare_read ( display ) ! = 0 )
2024-10-08 14:31:28 -04:00
{
if ( wl_display_dispatch_pending ( display ) = = - 1 )
break ;
}
2017-02-14 18:52:02 +00:00
wl_display_flush ( display ) ;
wl_display_read_events ( display ) ;
2024-10-08 14:31:28 -04:00
if ( wl_display_dispatch_pending ( display ) = = - 1 )
break ;
2017-02-14 18:52:02 +00:00
2017-02-02 08:54:56 +00:00
render ( ) ;
frameCounter + + ;
auto tEnd = std : : chrono : : high_resolution_clock : : now ( ) ;
auto tDiff = std : : chrono : : duration < double , std : : milli > ( tEnd - tStart ) . count ( ) ;
frameTimer = tDiff / 1000.0f ;
camera . update ( frameTimer ) ;
if ( camera . moving ( ) )
{
viewUpdated = true ;
}
// Convert to clamped timer value
if ( ! paused )
{
timer + = timerSpeed * frameTimer ;
if ( timer > 1.0 )
{
timer - = 1.0f ;
}
}
2019-02-23 20:38:09 +00:00
float fpsTimer = std : : chrono : : duration < double , std : : milli > ( tEnd - lastTimestamp ) . count ( ) ;
2017-02-02 08:54:56 +00:00
if ( fpsTimer > 1000.0f )
{
2017-10-30 18:03:48 +01:00
if ( ! settings . overlay )
2017-02-02 08:54:56 +00:00
{
std : : string windowTitle = getWindowTitle ( ) ;
2019-01-16 01:16:58 -07:00
xdg_toplevel_set_title ( xdg_toplevel , windowTitle . c_str ( ) ) ;
2017-02-02 08:54:56 +00:00
}
2017-12-01 13:10:07 +01:00
lastFPS = ( float ) frameCounter * ( 1000.0f / fpsTimer ) ;
2017-02-02 08:54:56 +00:00
frameCounter = 0 ;
2019-02-23 20:38:09 +00:00
lastTimestamp = tEnd ;
2017-02-02 08:54:56 +00:00
}
2017-11-01 13:29:57 +01:00
updateOverlay ( ) ;
2017-02-02 08:54:56 +00:00
}
2017-08-13 10:24:25 +02:00
# elif defined(VK_USE_PLATFORM_XCB_KHR)
2016-02-16 15:07:25 +01:00
xcb_flush ( connection ) ;
while ( ! quit )
{
auto tStart = std : : chrono : : high_resolution_clock : : now ( ) ;
2016-08-03 20:44:31 +02:00
if ( viewUpdated )
{
viewUpdated = false ;
}
2016-02-16 15:07:25 +01:00
xcb_generic_event_t * event ;
2016-08-03 20:44:31 +02:00
while ( ( event = xcb_poll_for_event ( connection ) ) )
2016-02-16 15:07:25 +01:00
{
handleEvent ( event ) ;
free ( event ) ;
}
render ( ) ;
2016-03-13 17:15:44 +01:00
frameCounter + + ;
2016-02-16 15:07:25 +01:00
auto tEnd = std : : chrono : : high_resolution_clock : : now ( ) ;
auto tDiff = std : : chrono : : duration < double , std : : milli > ( tEnd - tStart ) . count ( ) ;
frameTimer = tDiff / 1000.0f ;
2016-06-11 15:54:16 +02:00
camera . update ( frameTimer ) ;
2016-08-03 20:44:31 +02:00
if ( camera . moving ( ) )
{
viewUpdated = true ;
}
2016-03-13 17:15:44 +01:00
// Convert to clamped timer value
if ( ! paused )
{
timer + = timerSpeed * frameTimer ;
if ( timer > 1.0 )
{
timer - = 1.0f ;
}
}
2019-02-23 20:38:09 +00:00
float fpsTimer = std : : chrono : : duration < double , std : : milli > ( tEnd - lastTimestamp ) . count ( ) ;
2016-03-13 17:15:44 +01:00
if ( fpsTimer > 1000.0f )
{
2017-10-30 18:03:48 +01:00
if ( ! settings . overlay )
2016-05-15 18:31:31 +02:00
{
std : : string windowTitle = getWindowTitle ( ) ;
xcb_change_property ( connection , XCB_PROP_MODE_REPLACE ,
window , XCB_ATOM_WM_NAME , XCB_ATOM_STRING , 8 ,
windowTitle . size ( ) , windowTitle . c_str ( ) ) ;
}
2017-12-01 13:10:07 +01:00
lastFPS = ( float ) frameCounter * ( 1000.0f / fpsTimer ) ;
2016-05-22 20:27:06 +02:00
frameCounter = 0 ;
2019-02-23 20:38:09 +00:00
lastTimestamp = tEnd ;
2016-03-13 17:15:44 +01:00
}
2017-11-01 13:29:57 +01:00
updateOverlay ( ) ;
2016-03-20 14:55:46 +01:00
}
2021-04-27 13:52:27 +02:00
# elif defined(VK_USE_PLATFORM_HEADLESS_EXT)
while ( ! quit )
{
auto tStart = std : : chrono : : high_resolution_clock : : now ( ) ;
if ( viewUpdated )
{
viewUpdated = false ;
}
render ( ) ;
frameCounter + + ;
auto tEnd = std : : chrono : : high_resolution_clock : : now ( ) ;
auto tDiff = std : : chrono : : duration < double , std : : milli > ( tEnd - tStart ) . count ( ) ;
frameTimer = tDiff / 1000.0f ;
camera . update ( frameTimer ) ;
if ( camera . moving ( ) )
{
viewUpdated = true ;
}
// Convert to clamped timer value
timer + = timerSpeed * frameTimer ;
if ( timer > 1.0 )
{
timer - = 1.0f ;
}
float fpsTimer = std : : chrono : : duration < double , std : : milli > ( tEnd - lastTimestamp ) . count ( ) ;
if ( fpsTimer > 1000.0f )
{
lastFPS = ( float ) frameCounter * ( 1000.0f / fpsTimer ) ;
frameCounter = 0 ;
lastTimestamp = tEnd ;
}
updateOverlay ( ) ;
}
2024-05-04 07:53:08 -04:00
# elif (defined(VK_USE_PLATFORM_MACOS_MVK) || defined(VK_USE_PLATFORM_METAL_EXT)) && defined(VK_EXAMPLE_XCODE_GENERATED)
2020-09-12 03:19:28 +09:00
[ NSApp run ] ;
2023-09-01 11:12:08 -04:00
# elif defined(VK_USE_PLATFORM_SCREEN_QNX)
while ( ! quit ) {
handleEvent ( ) ;
if ( prepared ) {
nextFrame ( ) ;
}
}
2016-02-16 15:07:25 +01:00
# endif
2018-05-01 11:23:36 +02:00
// Flush device to make sure all resources can be freed
2018-06-01 18:41:26 +02:00
if ( device ! = VK_NULL_HANDLE ) {
vkDeviceWaitIdle ( device ) ;
}
2016-02-16 15:07:25 +01:00
}
2017-10-29 11:41:43 +01:00
void VulkanExampleBase : : updateOverlay ( )
2016-05-15 18:31:31 +02:00
{
2017-10-29 11:41:43 +01:00
if ( ! settings . overlay )
2016-05-15 18:31:31 +02:00
return ;
2024-05-23 21:52:24 +02:00
// The overlay does not need to be updated with each frame, so we limit the update rate
// Not only does this save performance but it also makes display of fast changig values like fps more stable
2024-05-23 21:56:42 +02:00
ui . updateTimer - = frameTimer ;
if ( ui . updateTimer > = 0.0f ) {
2024-05-23 21:52:24 +02:00
return ;
}
// Update at max. rate of 30 fps
2024-05-23 21:56:42 +02:00
ui . updateTimer = 1.0f / 30.0f ;
2024-05-23 21:52:24 +02:00
2017-10-29 11:41:43 +01:00
ImGuiIO & io = ImGui : : GetIO ( ) ;
2016-05-15 18:31:31 +02:00
2017-10-29 11:41:43 +01:00
io . DisplaySize = ImVec2 ( ( float ) width , ( float ) height ) ;
io . DeltaTime = frameTimer ;
2016-05-15 18:31:31 +02:00
2024-03-20 07:49:06 +01:00
io . MousePos = ImVec2 ( mouseState . position . x , mouseState . position . y ) ;
2024-05-23 21:56:42 +02:00
io . MouseDown [ 0 ] = mouseState . buttons . left & & ui . visible ;
io . MouseDown [ 1 ] = mouseState . buttons . right & & ui . visible ;
io . MouseDown [ 2 ] = mouseState . buttons . middle & & ui . visible ;
2016-05-15 18:31:31 +02:00
2017-10-29 11:41:43 +01:00
ImGui : : NewFrame ( ) ;
ImGui : : PushStyleVar ( ImGuiStyleVar_WindowRounding , 0 ) ;
2024-05-23 21:56:42 +02:00
ImGui : : SetNextWindowPos ( ImVec2 ( 10 * ui . scale , 10 * ui . scale ) ) ;
2017-10-29 11:41:43 +01:00
ImGui : : SetNextWindowSize ( ImVec2 ( 0 , 0 ) , ImGuiSetCond_FirstUseEver ) ;
ImGui : : Begin ( " Vulkan Example " , nullptr , ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove ) ;
2017-11-02 09:08:47 +01:00
ImGui : : TextUnformatted ( title . c_str ( ) ) ;
ImGui : : TextUnformatted ( deviceProperties . deviceName ) ;
2017-11-03 16:35:38 +01:00
ImGui : : Text ( " %.2f ms/frame (%.1d fps) " , ( 1000.0f / lastFPS ) , lastFPS ) ;
2017-10-29 11:41:43 +01:00
2017-11-02 09:08:47 +01:00
# if defined(VK_USE_PLATFORM_ANDROID_KHR)
2024-05-23 21:56:42 +02:00
ImGui : : PushStyleVar ( ImGuiStyleVar_ItemSpacing , ImVec2 ( 0.0f , 5.0f * ui . scale ) ) ;
2017-11-02 09:08:47 +01:00
# endif
2024-05-23 21:56:42 +02:00
ImGui : : PushItemWidth ( 110.0f * ui . scale ) ;
OnUpdateUIOverlay ( & ui ) ;
2017-10-30 12:36:44 +01:00
ImGui : : PopItemWidth ( ) ;
2017-11-02 09:08:47 +01:00
# if defined(VK_USE_PLATFORM_ANDROID_KHR)
ImGui : : PopStyleVar ( ) ;
# endif
2016-05-15 18:31:31 +02:00
2017-10-29 11:41:43 +01:00
ImGui : : End ( ) ;
ImGui : : PopStyleVar ( ) ;
ImGui : : Render ( ) ;
2024-05-23 21:56:42 +02:00
if ( ui . update ( ) | | ui . updated ) {
2018-08-29 20:49:13 +02:00
buildCommandBuffers ( ) ;
2024-05-23 21:56:42 +02:00
ui . updated = false ;
2018-08-29 20:49:13 +02:00
}
2017-11-02 17:07:07 +01:00
# if defined(VK_USE_PLATFORM_ANDROID_KHR)
2024-03-20 07:49:06 +01:00
if ( mouseState . buttons . left ) {
mouseState . buttons . left = false ;
2017-11-02 17:07:07 +01:00
}
# endif
2016-05-15 18:31:31 +02:00
}
2018-08-29 20:49:13 +02:00
void VulkanExampleBase : : drawUI ( const VkCommandBuffer commandBuffer )
{
2024-05-23 21:56:42 +02:00
if ( settings . overlay & & ui . visible ) {
2018-08-30 21:02:10 +02:00
const VkViewport viewport = vks : : initializers : : viewport ( ( float ) width , ( float ) height , 0.0f , 1.0f ) ;
const VkRect2D scissor = vks : : initializers : : rect2D ( width , height , 0 , 0 ) ;
vkCmdSetViewport ( commandBuffer , 0 , 1 , & viewport ) ;
vkCmdSetScissor ( commandBuffer , 0 , 1 , & scissor ) ;
2024-05-23 21:56:42 +02:00
ui . draw ( commandBuffer ) ;
2018-08-29 20:49:13 +02:00
}
}
2016-05-15 20:11:28 +02:00
void VulkanExampleBase : : prepareFrame ( )
{
2017-04-15 10:27:12 +02:00
// Acquire the next image from the swap chain
2024-12-19 21:29:22 +01:00
VkResult result = swapChain . acquireNextImage ( semaphores . presentComplete , currentBuffer ) ;
2022-06-01 12:46:41 -04:00
// Recreate the swapchain if it's no longer compatible with the surface (OUT_OF_DATE)
// SRS - If no longer optimal (VK_SUBOPTIMAL_KHR), wait until submitFrame() in case number of swapchain images will change on resize
2019-08-18 18:33:16 +02:00
if ( ( result = = VK_ERROR_OUT_OF_DATE_KHR ) | | ( result = = VK_SUBOPTIMAL_KHR ) ) {
2022-06-01 12:46:41 -04:00
if ( result = = VK_ERROR_OUT_OF_DATE_KHR ) {
windowResize ( ) ;
}
2022-06-11 20:14:55 -04:00
return ;
2017-04-15 10:27:12 +02:00
}
else {
2019-08-18 18:33:16 +02:00
VK_CHECK_RESULT ( result ) ;
2017-04-15 10:27:12 +02:00
}
2016-05-15 20:11:28 +02:00
}
void VulkanExampleBase : : submitFrame ( )
{
2019-08-18 18:33:16 +02:00
VkResult result = swapChain . queuePresent ( queue , currentBuffer , semaphores . renderComplete ) ;
2022-06-01 12:46:41 -04:00
// Recreate the swapchain if it's no longer compatible with the surface (OUT_OF_DATE) or no longer optimal for presentation (SUBOPTIMAL)
if ( ( result = = VK_ERROR_OUT_OF_DATE_KHR ) | | ( result = = VK_SUBOPTIMAL_KHR ) ) {
windowResize ( ) ;
2019-08-18 18:33:16 +02:00
if ( result = = VK_ERROR_OUT_OF_DATE_KHR ) {
2018-06-30 21:55:29 +02:00
return ;
}
}
2022-06-01 12:46:41 -04:00
else {
VK_CHECK_RESULT ( result ) ;
}
2016-05-15 20:11:28 +02:00
VK_CHECK_RESULT ( vkQueueWaitIdle ( queue ) ) ;
}
2023-12-30 13:15:37 +01:00
VulkanExampleBase : : VulkanExampleBase ( )
2016-02-16 15:07:25 +01:00
{
2021-01-29 15:40:52 +01:00
// Command line arguments
2022-12-31 09:45:01 +01:00
commandLineParser . add ( " help " , { " --help " } , 0 , " Show help " ) ;
commandLineParser . add ( " validation " , { " -v " , " --validation " } , 0 , " Enable validation layers " ) ;
commandLineParser . add ( " vsync " , { " -vs " , " --vsync " } , 0 , " Enable V-Sync " ) ;
commandLineParser . add ( " fullscreen " , { " -f " , " --fullscreen " } , 0 , " Start in fullscreen mode " ) ;
commandLineParser . add ( " width " , { " -w " , " --width " } , 1 , " Set window width " ) ;
commandLineParser . add ( " height " , { " -h " , " --height " } , 1 , " Set window height " ) ;
2025-02-06 21:25:43 +01:00
commandLineParser . add ( " shaders " , { " -s " , " --shaders " } , 1 , " Select shader type to use (gls, hlsl or slang) " ) ;
2022-12-31 09:45:01 +01:00
commandLineParser . add ( " gpuselection " , { " -g " , " --gpu " } , 1 , " Select GPU to run on " ) ;
commandLineParser . add ( " gpulist " , { " -gl " , " --listgpus " } , 0 , " Display a list of available Vulkan devices " ) ;
commandLineParser . add ( " benchmark " , { " -b " , " --benchmark " } , 0 , " Run example in benchmark mode " ) ;
commandLineParser . add ( " benchmarkwarmup " , { " -bw " , " --benchwarmup " } , 1 , " Set warmup time for benchmark mode in seconds " ) ;
commandLineParser . add ( " benchmarkruntime " , { " -br " , " --benchruntime " } , 1 , " Set duration time for benchmark mode in seconds " ) ;
commandLineParser . add ( " benchmarkresultfile " , { " -bf " , " --benchfilename " } , 1 , " Set file name for benchmark results " ) ;
commandLineParser . add ( " benchmarkresultframes " , { " -bt " , " --benchframetimes " } , 0 , " Save frame times to benchmark results file " ) ;
commandLineParser . add ( " benchmarkframes " , { " -bfs " , " --benchmarkframes " } , 1 , " Only render the given number of frames " ) ;
2024-11-23 19:31:17 +05:30
# if (!(defined(VK_USE_PLATFORM_IOS_MVK) || defined(VK_USE_PLATFORM_MACOS_MVK) || defined(VK_USE_PLATFORM_METAL_EXT)))
commandLineParser . add ( " resourcepath " , { " -rp " , " --resourcepath " } , 1 , " Set path for dir where assets and shaders folder is present " ) ;
# endif
2021-01-29 15:40:52 +01:00
commandLineParser . parse ( args ) ;
if ( commandLineParser . isSet ( " help " ) ) {
# if defined(_WIN32)
setupConsole ( " Vulkan example " ) ;
# endif
commandLineParser . printHelp ( ) ;
std : : cin . get ( ) ;
exit ( 0 ) ;
}
if ( commandLineParser . isSet ( " validation " ) ) {
settings . validation = true ;
}
if ( commandLineParser . isSet ( " vsync " ) ) {
settings . vsync = true ;
}
if ( commandLineParser . isSet ( " height " ) ) {
2023-07-16 13:44:46 +02:00
height = commandLineParser . getValueAsInt ( " height " , height ) ;
2021-01-29 15:40:52 +01:00
}
if ( commandLineParser . isSet ( " width " ) ) {
width = commandLineParser . getValueAsInt ( " width " , width ) ;
}
if ( commandLineParser . isSet ( " fullscreen " ) ) {
settings . fullscreen = true ;
}
if ( commandLineParser . isSet ( " shaders " ) ) {
std : : string value = commandLineParser . getValueAsString ( " shaders " , " glsl " ) ;
2025-02-06 21:25:43 +01:00
if ( ( value ! = " glsl " ) & & ( value ! = " hlsl " ) & & ( value ! = " slang " ) ) {
std : : cerr < < " Shader type must be one of 'glsl', 'hlsl' or 'slang' \n " ;
2017-07-29 19:31:00 +02:00
}
2021-01-29 15:40:52 +01:00
else {
shaderDir = value ;
2018-01-13 10:39:03 +01:00
}
2016-02-16 15:07:25 +01:00
}
2021-01-29 15:40:52 +01:00
if ( commandLineParser . isSet ( " benchmark " ) ) {
benchmark . active = true ;
vks : : tools : : errorModeSilent = true ;
}
if ( commandLineParser . isSet ( " benchmarkwarmup " ) ) {
2024-03-19 21:28:19 +01:00
benchmark . warmup = commandLineParser . getValueAsInt ( " benchmarkwarmup " , 0 ) ;
2021-01-29 15:40:52 +01:00
}
if ( commandLineParser . isSet ( " benchmarkruntime " ) ) {
benchmark . duration = commandLineParser . getValueAsInt ( " benchmarkruntime " , benchmark . duration ) ;
}
if ( commandLineParser . isSet ( " benchmarkresultfile " ) ) {
benchmark . filename = commandLineParser . getValueAsString ( " benchmarkresultfile " , benchmark . filename ) ;
2024-01-21 05:07:35 -08:00
}
2021-03-13 14:12:35 +01:00
if ( commandLineParser . isSet ( " benchmarkresultframes " ) ) {
2021-01-29 15:40:52 +01:00
benchmark . outputFrameTimes = true ;
}
2021-07-29 12:15:58 +02:00
if ( commandLineParser . isSet ( " benchmarkframes " ) ) {
benchmark . outputFrames = commandLineParser . getValueAsInt ( " benchmarkframes " , benchmark . outputFrames ) ;
}
2024-11-23 19:31:17 +05:30
# if (!(defined(VK_USE_PLATFORM_IOS_MVK) || defined(VK_USE_PLATFORM_MACOS_MVK) || defined(VK_USE_PLATFORM_METAL_EXT)))
if ( commandLineParser . isSet ( " resourcepath " ) ) {
2024-11-23 15:09:18 +01:00
vks : : tools : : resourcePath = commandLineParser . getValueAsString ( " resourcepath " , " " ) ;
2024-11-23 19:31:17 +05:30
}
2025-03-29 11:21:37 -04:00
# else
// On Apple platforms, use layer settings extension to configure MoltenVK with common project config settings
enabledInstanceExtensions . push_back ( VK_EXT_LAYER_SETTINGS_EXTENSION_NAME ) ;
// Configure MoltenVK to use to use a dedicated compute queue (see compute[*] and timelinesemaphore samples)
VkLayerSettingEXT layerSetting ;
layerSetting . pLayerName = " MoltenVK " ;
layerSetting . pSettingName = " MVK_CONFIG_SPECIALIZED_QUEUE_FAMILIES " ;
layerSetting . type = VK_LAYER_SETTING_TYPE_BOOL32_EXT ;
layerSetting . valueCount = 1 ;
// Make this static so layer setting reference remains valid after leaving constructor scope
static const VkBool32 layerSettingOn = VK_TRUE ;
layerSetting . pValues = & layerSettingOn ;
enabledLayerSettings . push_back ( layerSetting ) ;
2024-11-23 19:31:17 +05:30
# endif
# if !defined(VK_USE_PLATFORM_ANDROID_KHR)
// Check for a valid asset path
struct stat info ;
if ( stat ( getAssetPath ( ) . c_str ( ) , & info ) ! = 0 )
{
# if defined(_WIN32)
std : : string msg = " Could not locate asset path in \" " + getAssetPath ( ) + " \" ! " ;
MessageBox ( NULL , msg . c_str ( ) , " Fatal error " , MB_OK | MB_ICONERROR ) ;
# else
std : : cerr < < " Error: Could not find asset path in " < < getAssetPath ( ) < < " \n " ;
# endif
exit ( - 1 ) ;
}
# endif
// Validation for all samples can be forced at compile time using the FORCE_VALIDATION define
# if defined(FORCE_VALIDATION)
settings . validation = true ;
# endif
2020-05-29 16:08:53 +01:00
2017-08-13 10:24:25 +02:00
# if defined(VK_USE_PLATFORM_ANDROID_KHR)
2016-03-20 14:55:46 +01:00
// Vulkan library is loaded dynamically on Android
2017-03-10 17:23:17 +01:00
bool libLoaded = vks : : android : : loadVulkanLibrary ( ) ;
2016-03-20 14:55:46 +01:00
assert ( libLoaded ) ;
2016-11-04 13:32:58 -07:00
# elif defined(_DIRECT2DISPLAY)
2017-02-02 08:54:56 +00:00
# elif defined(VK_USE_PLATFORM_WAYLAND_KHR)
initWaylandConnection ( ) ;
2017-08-13 10:24:25 +02:00
# elif defined(VK_USE_PLATFORM_XCB_KHR)
2016-02-16 15:07:25 +01:00
initxcbConnection ( ) ;
# endif
2016-03-20 14:55:46 +01:00
# if defined(_WIN32)
2021-01-29 15:40:52 +01:00
// Enable console if validation is active, debug message callback will output to it
2017-01-22 13:38:57 +01:00
if ( this - > settings . validation )
2016-02-16 15:07:25 +01:00
{
2021-01-29 15:40:52 +01:00
setupConsole ( " Vulkan example " ) ;
2016-02-16 15:07:25 +01:00
}
2018-04-23 21:28:35 +03:00
setupDPIAwareness ( ) ;
2016-02-16 15:07:25 +01:00
# endif
}
VulkanExampleBase : : ~ VulkanExampleBase ( )
{
// Clean up Vulkan resources
swapChain . cleanup ( ) ;
2016-04-02 12:47:08 +02:00
if ( descriptorPool ! = VK_NULL_HANDLE )
{
vkDestroyDescriptorPool ( device , descriptorPool , nullptr ) ;
}
2016-02-16 15:07:25 +01:00
destroyCommandBuffers ( ) ;
2021-11-06 19:45:22 +01:00
if ( renderPass ! = VK_NULL_HANDLE )
{
vkDestroyRenderPass ( device , renderPass , nullptr ) ;
}
2025-02-28 18:18:49 +01:00
for ( auto & frameBuffer : frameBuffers )
2016-02-16 15:07:25 +01:00
{
2025-02-28 18:18:49 +01:00
vkDestroyFramebuffer ( device , frameBuffer , nullptr ) ;
2016-02-16 15:07:25 +01:00
}
for ( auto & shaderModule : shaderModules )
{
vkDestroyShaderModule ( device , shaderModule , nullptr ) ;
}
vkDestroyImageView ( device , depthStencil . view , nullptr ) ;
vkDestroyImage ( device , depthStencil . image , nullptr ) ;
2024-03-19 21:51:27 +01:00
vkFreeMemory ( device , depthStencil . memory , nullptr ) ;
2016-02-16 15:07:25 +01:00
vkDestroyPipelineCache ( device , pipelineCache , nullptr ) ;
vkDestroyCommandPool ( device , cmdPool , nullptr ) ;
2016-03-06 19:22:41 +01:00
vkDestroySemaphore ( device , semaphores . presentComplete , nullptr ) ;
vkDestroySemaphore ( device , semaphores . renderComplete , nullptr ) ;
2018-06-03 09:38:14 +02:00
for ( auto & fence : waitFences ) {
vkDestroyFence ( device , fence , nullptr ) ;
}
2016-05-15 18:31:31 +02:00
2018-08-31 21:15:43 +02:00
if ( settings . overlay ) {
2024-05-23 21:56:42 +02:00
ui . freeResources ( ) ;
2016-05-15 18:31:31 +02:00
}
2016-03-06 12:57:23 +01:00
2016-07-22 20:45:48 +02:00
delete vulkanDevice ;
2016-02-16 15:07:25 +01:00
2017-01-22 13:38:57 +01:00
if ( settings . validation )
2016-02-16 15:07:25 +01:00
{
2017-02-12 11:33:04 +01:00
vks : : debug : : freeDebugCallback ( instance ) ;
2016-02-16 15:07:25 +01:00
}
vkDestroyInstance ( instance , nullptr ) ;
2016-11-04 13:32:58 -07:00
# if defined(_DIRECT2DISPLAY)
2020-09-13 10:12:33 +02:00
# elif defined(VK_USE_PLATFORM_DIRECTFB_EXT)
if ( event_buffer )
event_buffer - > Release ( event_buffer ) ;
if ( surface )
surface - > Release ( surface ) ;
if ( window )
window - > Release ( window ) ;
if ( layer )
layer - > Release ( layer ) ;
if ( dfb )
dfb - > Release ( dfb ) ;
2017-02-02 08:54:56 +00:00
# elif defined(VK_USE_PLATFORM_WAYLAND_KHR)
2019-01-16 01:16:58 -07:00
xdg_toplevel_destroy ( xdg_toplevel ) ;
xdg_surface_destroy ( xdg_surface ) ;
2017-02-02 08:54:56 +00:00
wl_surface_destroy ( surface ) ;
if ( keyboard )
wl_keyboard_destroy ( keyboard ) ;
if ( pointer )
wl_pointer_destroy ( pointer ) ;
2021-05-04 16:37:57 +01:00
if ( seat )
wl_seat_destroy ( seat ) ;
2019-01-16 01:16:58 -07:00
xdg_wm_base_destroy ( shell ) ;
2017-02-02 08:54:56 +00:00
wl_compositor_destroy ( compositor ) ;
wl_registry_destroy ( registry ) ;
wl_display_disconnect ( display ) ;
2017-08-13 10:24:25 +02:00
# elif defined(VK_USE_PLATFORM_XCB_KHR)
2016-02-16 15:07:25 +01:00
xcb_destroy_window ( connection , window ) ;
xcb_disconnect ( connection ) ;
2023-09-01 11:12:08 -04:00
# elif defined(VK_USE_PLATFORM_SCREEN_QNX)
screen_destroy_event ( screen_event ) ;
screen_destroy_window ( screen_window ) ;
screen_destroy_context ( screen_context ) ;
2016-03-13 17:15:44 +01:00
# endif
2016-02-16 15:07:25 +01:00
}
2018-05-01 11:23:36 +02:00
bool VulkanExampleBase : : initVulkan ( )
2016-02-16 15:07:25 +01:00
{
2024-05-25 18:02:38 +02:00
// Instead of checking for the command line switch, validation can be forced via a define
# if defined(_VALIDATION)
this - > settings . validation = true ;
# endif
2016-02-16 15:07:25 +01:00
2024-05-25 18:02:38 +02:00
// Create the instance
VkResult result = createInstance ( ) ;
if ( result ! = VK_SUCCESS ) {
vks : : tools : : exitFatal ( " Could not create Vulkan instance : \n " + vks : : tools : : errorString ( result ) , result ) ;
2018-05-01 11:23:36 +02:00
return false ;
2016-02-16 15:07:25 +01:00
}
2017-08-13 10:24:25 +02:00
# if defined(VK_USE_PLATFORM_ANDROID_KHR)
2017-03-10 17:23:17 +01:00
vks : : android : : loadVulkanFunctions ( instance ) ;
2016-03-20 14:55:46 +01:00
# endif
2016-07-22 22:24:27 +02:00
// If requested, we enable the default validation layers for debugging
2017-01-22 13:38:57 +01:00
if ( settings . validation )
2016-07-22 22:24:27 +02:00
{
2023-01-22 10:07:29 +01:00
vks : : debug : : setupDebugging ( instance ) ;
2016-07-22 22:24:27 +02:00
}
2016-02-16 15:07:25 +01:00
// Physical device
2016-02-17 18:37:36 +01:00
uint32_t gpuCount = 0 ;
// Get number of available physical devices
2016-05-22 20:27:06 +02:00
VK_CHECK_RESULT ( vkEnumeratePhysicalDevices ( instance , & gpuCount , nullptr ) ) ;
2021-01-29 15:40:52 +01:00
if ( gpuCount = = 0 ) {
vks : : tools : : exitFatal ( " No device with Vulkan support found " , - 1 ) ;
return false ;
}
2016-02-17 18:37:36 +01:00
// Enumerate devices
std : : vector < VkPhysicalDevice > physicalDevices ( gpuCount ) ;
2024-05-25 18:02:38 +02:00
result = vkEnumeratePhysicalDevices ( instance , & gpuCount , physicalDevices . data ( ) ) ;
if ( result ! = VK_SUCCESS ) {
vks : : tools : : exitFatal ( " Could not enumerate physical devices : \n " + vks : : tools : : errorString ( result ) , result ) ;
2018-05-01 11:23:36 +02:00
return false ;
2016-02-16 15:07:25 +01:00
}
2017-02-04 13:52:41 +01:00
// GPU selection
// Select physical device to be used for the Vulkan example
// Defaults to the first device unless specified by command line
uint32_t selectedDevice = 0 ;
2020-05-29 16:08:53 +01:00
# if !defined(VK_USE_PLATFORM_ANDROID_KHR)
2017-02-04 13:52:41 +01:00
// GPU selection via command line argument
2021-01-29 15:40:52 +01:00
if ( commandLineParser . isSet ( " gpuselection " ) ) {
uint32_t index = commandLineParser . getValueAsInt ( " gpuselection " , 0 ) ;
if ( index > gpuCount - 1 ) {
std : : cerr < < " Selected device index " < < index < < " is out of range, reverting to device 0 (use -listgpus to show available Vulkan devices) " < < " \n " ;
} else {
selectedDevice = index ;
2017-02-04 13:52:41 +01:00
}
2021-01-29 15:40:52 +01:00
}
if ( commandLineParser . isSet ( " gpulist " ) ) {
std : : cout < < " Available Vulkan devices " < < " \n " ;
for ( uint32_t i = 0 ; i < gpuCount ; i + + ) {
VkPhysicalDeviceProperties deviceProperties ;
vkGetPhysicalDeviceProperties ( physicalDevices [ i ] , & deviceProperties ) ;
std : : cout < < " Device [ " < < i < < " ] : " < < deviceProperties . deviceName < < std : : endl ;
std : : cout < < " Type: " < < vks : : tools : : physicalDeviceTypeString ( deviceProperties . deviceType ) < < " \n " ;
std : : cout < < " API: " < < ( deviceProperties . apiVersion > > 22 ) < < " . " < < ( ( deviceProperties . apiVersion > > 12 ) & 0x3ff ) < < " . " < < ( deviceProperties . apiVersion & 0xfff ) < < " \n " ;
2017-02-04 13:52:41 +01:00
}
}
# endif
physicalDevice = physicalDevices [ selectedDevice ] ;
2016-02-17 18:37:36 +01:00
2020-08-08 13:25:58 +02:00
// Store properties (including limits), features and memory properties of the physical device (so that examples can check against them)
2017-03-08 21:29:38 +01:00
vkGetPhysicalDeviceProperties ( physicalDevice , & deviceProperties ) ;
vkGetPhysicalDeviceFeatures ( physicalDevice , & deviceFeatures ) ;
vkGetPhysicalDeviceMemoryProperties ( physicalDevice , & deviceMemoryProperties ) ;
// Derived examples can override this to set actual features (based on above readings) to enable for logical device creation
getEnabledFeatures ( ) ;
2016-07-16 17:36:35 +02:00
// Vulkan device creation
2016-07-22 22:24:27 +02:00
// This is handled by a separate class that gets a logical device representation
// and encapsulates functions related to a device
2017-02-12 10:16:07 +01:00
vulkanDevice = new vks : : VulkanDevice ( physicalDevice ) ;
2022-10-02 15:46:06 +02:00
// Derived examples can enable extensions based on the list of supported extensions read from the physical device
getEnabledExtensions ( ) ;
2024-05-25 18:02:38 +02:00
result = vulkanDevice - > createLogicalDevice ( enabledFeatures , enabledDeviceExtensions , deviceCreatepNextChain ) ;
if ( result ! = VK_SUCCESS ) {
vks : : tools : : exitFatal ( " Could not create Vulkan device: \n " + vks : : tools : : errorString ( result ) , result ) ;
2018-05-01 11:23:36 +02:00
return false ;
2017-02-09 19:22:48 +01:00
}
2016-07-22 20:45:48 +02:00
device = vulkanDevice - > logicalDevice ;
2016-02-16 15:07:25 +01:00
2016-07-22 22:24:27 +02:00
// Get a graphics queue from the device
vkGetDeviceQueue ( device , vulkanDevice - > queueFamilyIndices . graphics , 0 , & queue ) ;
2016-02-16 15:07:25 +01:00
2023-05-09 18:03:51 +02:00
// Find a suitable depth and/or stencil format
VkBool32 validFormat { false } ;
2024-01-01 16:41:38 +01:00
// Samples that make use of stencil will require a depth + stencil format, so we select from a different list
2023-05-09 18:03:51 +02:00
if ( requiresStencil ) {
validFormat = vks : : tools : : getSupportedDepthStencilFormat ( physicalDevice , & depthFormat ) ;
} else {
validFormat = vks : : tools : : getSupportedDepthFormat ( physicalDevice , & depthFormat ) ;
}
assert ( validFormat ) ;
2016-02-16 15:07:25 +01:00
2024-05-02 20:17:00 +02:00
swapChain . setContext ( instance , physicalDevice , device ) ;
2016-03-06 12:57:23 +01:00
2016-03-06 19:22:41 +01:00
// Create synchronization objects
2017-02-12 11:12:42 +01:00
VkSemaphoreCreateInfo semaphoreCreateInfo = vks : : initializers : : semaphoreCreateInfo ( ) ;
2016-03-06 12:57:23 +01:00
// Create a semaphore used to synchronize image presentation
2020-08-08 13:25:58 +02:00
// Ensures that the image is displayed before we start submitting new commands to the queue
2016-05-15 18:31:31 +02:00
VK_CHECK_RESULT ( vkCreateSemaphore ( device , & semaphoreCreateInfo , nullptr , & semaphores . presentComplete ) ) ;
2016-03-06 19:22:41 +01:00
// Create a semaphore used to synchronize command submission
2020-08-08 13:25:58 +02:00
// Ensures that the image is not presented until all commands have been submitted and executed
2016-05-15 18:31:31 +02:00
VK_CHECK_RESULT ( vkCreateSemaphore ( device , & semaphoreCreateInfo , nullptr , & semaphores . renderComplete ) ) ;
2016-03-06 19:22:41 +01:00
// Set up submit info structure
// Semaphores will stay the same during application lifetime
// Command buffer submission info is set by each example
2017-02-12 11:12:42 +01:00
submitInfo = vks : : initializers : : submitInfo ( ) ;
2016-03-06 19:22:41 +01:00
submitInfo . pWaitDstStageMask = & submitPipelineStages ;
submitInfo . waitSemaphoreCount = 1 ;
submitInfo . pWaitSemaphores = & semaphores . presentComplete ;
submitInfo . signalSemaphoreCount = 1 ;
submitInfo . pSignalSemaphores = & semaphores . renderComplete ;
2017-03-06 21:54:06 +01:00
2018-05-01 11:23:36 +02:00
return true ;
2016-02-16 15:07:25 +01:00
}
2016-03-20 14:55:46 +01:00
# if defined(_WIN32)
2016-02-16 15:07:25 +01:00
// Win32 : Sets up a console window and redirects standard output to it
void VulkanExampleBase : : setupConsole ( std : : string title )
{
AllocConsole ( ) ;
AttachConsole ( GetCurrentProcessId ( ) ) ;
2016-05-22 20:27:06 +02:00
FILE * stream ;
2021-01-29 15:40:52 +01:00
freopen_s ( & stream , " CONIN$ " , " r " , stdin ) ;
2016-05-22 20:27:06 +02:00
freopen_s ( & stream , " CONOUT$ " , " w+ " , stdout ) ;
2017-02-04 13:52:41 +01:00
freopen_s ( & stream , " CONOUT$ " , " w+ " , stderr ) ;
2023-11-01 11:38:28 +01:00
// Enable flags so we can color the output
HANDLE consoleHandle = GetStdHandle ( STD_OUTPUT_HANDLE ) ;
DWORD dwMode = 0 ;
GetConsoleMode ( consoleHandle , & dwMode ) ;
dwMode | = ENABLE_VIRTUAL_TERMINAL_PROCESSING ;
SetConsoleMode ( consoleHandle , dwMode ) ;
2016-02-16 15:07:25 +01:00
SetConsoleTitle ( TEXT ( title . c_str ( ) ) ) ;
}
2018-04-23 21:28:35 +03:00
void VulkanExampleBase : : setupDPIAwareness ( )
{
2019-03-31 21:24:45 +02:00
typedef HRESULT * ( __stdcall * SetProcessDpiAwarenessFunc ) ( PROCESS_DPI_AWARENESS ) ;
2018-04-23 21:28:35 +03:00
HMODULE shCore = LoadLibraryA ( " Shcore.dll " ) ;
if ( shCore )
{
SetProcessDpiAwarenessFunc setProcessDpiAwareness =
( SetProcessDpiAwarenessFunc ) GetProcAddress ( shCore , " SetProcessDpiAwareness " ) ;
if ( setProcessDpiAwareness ! = nullptr )
{
setProcessDpiAwareness ( PROCESS_PER_MONITOR_DPI_AWARE ) ;
}
FreeLibrary ( shCore ) ;
}
}
2016-02-16 15:07:25 +01:00
HWND VulkanExampleBase : : setupWindow ( HINSTANCE hinstance , WNDPROC wndproc )
{
this - > windowInstance = hinstance ;
2024-11-23 15:37:57 +01:00
WNDCLASSEX wndClass { } ;
2016-02-16 15:07:25 +01:00
wndClass . cbSize = sizeof ( WNDCLASSEX ) ;
wndClass . style = CS_HREDRAW | CS_VREDRAW ;
wndClass . lpfnWndProc = wndproc ;
wndClass . cbClsExtra = 0 ;
wndClass . cbWndExtra = 0 ;
wndClass . hInstance = hinstance ;
wndClass . hIcon = LoadIcon ( NULL , IDI_APPLICATION ) ;
wndClass . hCursor = LoadCursor ( NULL , IDC_ARROW ) ;
2016-02-27 22:27:09 +01:00
wndClass . hbrBackground = ( HBRUSH ) GetStockObject ( BLACK_BRUSH ) ;
2016-02-16 15:07:25 +01:00
wndClass . lpszMenuName = NULL ;
wndClass . lpszClassName = name . c_str ( ) ;
wndClass . hIconSm = LoadIcon ( NULL , IDI_WINLOGO ) ;
if ( ! RegisterClassEx ( & wndClass ) )
{
std : : cout < < " Could not register window class! \n " ;
fflush ( stdout ) ;
exit ( 1 ) ;
}
int screenWidth = GetSystemMetrics ( SM_CXSCREEN ) ;
int screenHeight = GetSystemMetrics ( SM_CYSCREEN ) ;
2017-01-22 13:38:57 +01:00
if ( settings . fullscreen )
2016-02-16 15:07:25 +01:00
{
2017-04-22 16:54:25 +02:00
if ( ( width ! = ( uint32_t ) screenWidth ) & & ( height ! = ( uint32_t ) screenHeight ) )
2016-02-16 15:07:25 +01:00
{
2020-08-24 20:04:46 +02:00
DEVMODE dmScreenSettings ;
memset ( & dmScreenSettings , 0 , sizeof ( dmScreenSettings ) ) ;
dmScreenSettings . dmSize = sizeof ( dmScreenSettings ) ;
dmScreenSettings . dmPelsWidth = width ;
dmScreenSettings . dmPelsHeight = height ;
dmScreenSettings . dmBitsPerPel = 32 ;
dmScreenSettings . dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT ;
2016-02-16 15:07:25 +01:00
if ( ChangeDisplaySettings ( & dmScreenSettings , CDS_FULLSCREEN ) ! = DISP_CHANGE_SUCCESSFUL )
{
if ( MessageBox ( NULL , " Fullscreen Mode not supported! \n Switch to window mode? " , " Error " , MB_YESNO | MB_ICONEXCLAMATION ) = = IDYES )
{
2017-01-22 13:38:57 +01:00
settings . fullscreen = false ;
2016-02-16 15:07:25 +01:00
}
else
{
2017-04-22 11:47:34 +02:00
return nullptr ;
2016-02-16 15:07:25 +01:00
}
}
2020-08-24 20:04:46 +02:00
screenWidth = width ;
screenHeight = height ;
2016-02-16 15:07:25 +01:00
}
}
DWORD dwExStyle ;
DWORD dwStyle ;
2017-01-22 13:38:57 +01:00
if ( settings . fullscreen )
2016-02-16 15:07:25 +01:00
{
dwExStyle = WS_EX_APPWINDOW ;
dwStyle = WS_POPUP | WS_CLIPSIBLINGS | WS_CLIPCHILDREN ;
}
else
{
dwExStyle = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE ;
dwStyle = WS_OVERLAPPEDWINDOW | WS_CLIPSIBLINGS | WS_CLIPCHILDREN ;
}
2024-05-23 22:20:44 +02:00
RECT windowRect = {
0L ,
0L ,
settings . fullscreen ? ( long ) screenWidth : ( long ) width ,
settings . fullscreen ? ( long ) screenHeight : ( long ) height
} ;
2016-02-16 15:07:25 +01:00
AdjustWindowRectEx ( & windowRect , dwStyle , FALSE , dwExStyle ) ;
2016-03-13 16:51:00 +01:00
std : : string windowTitle = getWindowTitle ( ) ;
2016-02-16 15:07:25 +01:00
window = CreateWindowEx ( 0 ,
name . c_str ( ) ,
2016-03-13 16:51:00 +01:00
windowTitle . c_str ( ) ,
2016-02-16 15:07:25 +01:00
dwStyle | WS_CLIPSIBLINGS | WS_CLIPCHILDREN ,
2016-07-28 23:07:04 +02:00
0 ,
0 ,
windowRect . right - windowRect . left ,
windowRect . bottom - windowRect . top ,
2016-02-16 15:07:25 +01:00
NULL ,
NULL ,
hinstance ,
NULL ) ;
2024-05-23 22:20:44 +02:00
if ( ! window )
{
std : : cerr < < " Could not create window! \n " ;
fflush ( stdout ) ;
return nullptr ;
}
2017-01-22 13:38:57 +01:00
if ( ! settings . fullscreen )
2016-07-28 23:07:04 +02:00
{
// Center on screen
uint32_t x = ( GetSystemMetrics ( SM_CXSCREEN ) - windowRect . right ) / 2 ;
uint32_t y = ( GetSystemMetrics ( SM_CYSCREEN ) - windowRect . bottom ) / 2 ;
SetWindowPos ( window , 0 , x , y , 0 , 0 , SWP_NOZORDER | SWP_NOSIZE ) ;
}
2016-02-16 15:07:25 +01:00
ShowWindow ( window , SW_SHOW ) ;
SetForegroundWindow ( window ) ;
SetFocus ( window ) ;
return window ;
}
void VulkanExampleBase : : handleMessages ( HWND hWnd , UINT uMsg , WPARAM wParam , LPARAM lParam )
{
switch ( uMsg )
{
case WM_CLOSE :
prepared = false ;
DestroyWindow ( hWnd ) ;
PostQuitMessage ( 0 ) ;
break ;
case WM_PAINT :
ValidateRect ( window , NULL ) ;
break ;
case WM_KEYDOWN :
switch ( wParam )
{
2016-08-04 20:58:02 +02:00
case KEY_P :
2016-02-16 15:07:25 +01:00
paused = ! paused ;
break ;
2016-08-04 20:58:02 +02:00
case KEY_F1 :
2024-05-23 21:56:42 +02:00
ui . visible = ! ui . visible ;
ui . updated = true ;
2016-05-15 20:11:28 +02:00
break ;
2024-03-20 07:49:06 +01:00
case KEY_F2 :
if ( camera . type = = Camera : : CameraType : : lookat ) {
camera . type = Camera : : CameraType : : firstperson ;
} else {
camera . type = Camera : : CameraType : : lookat ;
}
break ;
2016-08-04 21:18:48 +02:00
case KEY_ESCAPE :
2016-05-19 20:25:09 +02:00
PostQuitMessage ( 0 ) ;
2016-02-16 15:07:25 +01:00
break ;
}
2016-06-11 15:54:16 +02:00
2020-08-09 15:10:28 +02:00
if ( camera . type = = Camera : : firstperson )
2016-06-11 15:54:16 +02:00
{
switch ( wParam )
{
2016-08-04 21:18:48 +02:00
case KEY_W :
2016-06-11 15:54:16 +02:00
camera . keys . up = true ;
break ;
2016-08-04 21:18:48 +02:00
case KEY_S :
2016-06-11 15:54:16 +02:00
camera . keys . down = true ;
break ;
2016-08-04 21:18:48 +02:00
case KEY_A :
2016-06-11 15:54:16 +02:00
camera . keys . left = true ;
break ;
2016-08-04 21:18:48 +02:00
case KEY_D :
2016-06-11 15:54:16 +02:00
camera . keys . right = true ;
break ;
}
}
2016-03-03 16:41:57 +01:00
keyPressed ( ( uint32_t ) wParam ) ;
2016-02-16 15:07:25 +01:00
break ;
2016-06-11 15:54:16 +02:00
case WM_KEYUP :
2020-08-09 15:10:28 +02:00
if ( camera . type = = Camera : : firstperson )
2016-06-11 15:54:16 +02:00
{
switch ( wParam )
{
2016-08-04 21:18:48 +02:00
case KEY_W :
2016-06-11 15:54:16 +02:00
camera . keys . up = false ;
break ;
2016-08-04 21:18:48 +02:00
case KEY_S :
2016-06-11 15:54:16 +02:00
camera . keys . down = false ;
break ;
2016-08-04 21:18:48 +02:00
case KEY_A :
2016-06-11 15:54:16 +02:00
camera . keys . left = false ;
break ;
2016-08-04 21:18:48 +02:00
case KEY_D :
2016-06-11 15:54:16 +02:00
camera . keys . right = false ;
break ;
}
}
break ;
2016-02-16 15:07:25 +01:00
case WM_LBUTTONDOWN :
2024-03-20 07:49:06 +01:00
mouseState . position = glm : : vec2 ( ( float ) LOWORD ( lParam ) , ( float ) HIWORD ( lParam ) ) ;
mouseState . buttons . left = true ;
2017-10-05 21:22:10 +02:00
break ;
case WM_RBUTTONDOWN :
2024-03-20 07:49:06 +01:00
mouseState . position = glm : : vec2 ( ( float ) LOWORD ( lParam ) , ( float ) HIWORD ( lParam ) ) ;
mouseState . buttons . right = true ;
2017-10-05 21:22:10 +02:00
break ;
2016-03-30 22:48:58 +02:00
case WM_MBUTTONDOWN :
2024-03-20 07:49:06 +01:00
mouseState . position = glm : : vec2 ( ( float ) LOWORD ( lParam ) , ( float ) HIWORD ( lParam ) ) ;
mouseState . buttons . middle = true ;
2017-10-05 21:22:10 +02:00
break ;
case WM_LBUTTONUP :
2024-03-20 07:49:06 +01:00
mouseState . buttons . left = false ;
2017-10-05 21:22:10 +02:00
break ;
case WM_RBUTTONUP :
2024-03-20 07:49:06 +01:00
mouseState . buttons . right = false ;
2017-10-05 21:22:10 +02:00
break ;
case WM_MBUTTONUP :
2024-03-20 07:49:06 +01:00
mouseState . buttons . middle = false ;
2016-02-16 15:07:25 +01:00
break ;
2016-03-17 20:20:43 +01:00
case WM_MOUSEWHEEL :
{
short wheelDelta = GET_WHEEL_DELTA_WPARAM ( wParam ) ;
2020-04-22 20:58:24 +02:00
camera . translate ( glm : : vec3 ( 0.0f , 0.0f , ( float ) wheelDelta * 0.005f ) ) ;
2016-07-31 12:41:50 +02:00
viewUpdated = true ;
2016-03-17 20:20:43 +01:00
break ;
}
2016-02-16 15:07:25 +01:00
case WM_MOUSEMOVE :
2017-10-05 21:22:10 +02:00
{
2017-11-02 13:40:27 +01:00
handleMouseMove ( LOWORD ( lParam ) , HIWORD ( lParam ) ) ;
2016-02-16 15:07:25 +01:00
break ;
2017-10-05 21:22:10 +02:00
}
2016-04-10 11:12:04 +02:00
case WM_SIZE :
if ( ( prepared ) & & ( wParam ! = SIZE_MINIMIZED ) )
{
2016-10-16 17:39:30 +02:00
if ( ( resizing ) | | ( ( wParam = = SIZE_MAXIMIZED ) | | ( wParam = = SIZE_RESTORED ) ) )
2016-04-10 11:12:04 +02:00
{
2016-10-16 17:39:30 +02:00
destWidth = LOWORD ( lParam ) ;
destHeight = HIWORD ( lParam ) ;
2016-04-10 11:12:04 +02:00
windowResize ( ) ;
}
}
break ;
2020-01-24 09:52:26 +01:00
case WM_GETMINMAXINFO :
{
LPMINMAXINFO minMaxInfo = ( LPMINMAXINFO ) lParam ;
minMaxInfo - > ptMinTrackSize . x = 64 ;
minMaxInfo - > ptMinTrackSize . y = 64 ;
break ;
}
2016-10-16 17:39:30 +02:00
case WM_ENTERSIZEMOVE :
resizing = true ;
break ;
2016-04-10 11:12:04 +02:00
case WM_EXITSIZEMOVE :
2016-10-16 17:39:30 +02:00
resizing = false ;
2016-04-10 11:12:04 +02:00
break ;
2016-02-16 15:07:25 +01:00
}
2023-02-25 09:37:08 +01:00
OnHandleMessage ( hWnd , uMsg , wParam , lParam ) ;
2016-02-16 15:07:25 +01:00
}
2017-08-13 10:24:25 +02:00
# elif defined(VK_USE_PLATFORM_ANDROID_KHR)
2016-03-20 21:46:49 +01:00
int32_t VulkanExampleBase : : handleAppInput ( struct android_app * app , AInputEvent * event )
{
2016-08-02 20:41:16 +02:00
VulkanExampleBase * vulkanExample = reinterpret_cast < VulkanExampleBase * > ( app - > userData ) ;
2016-03-20 21:46:49 +01:00
if ( AInputEvent_getType ( event ) = = AINPUT_EVENT_TYPE_MOTION )
{
2017-03-06 21:16:51 +01:00
int32_t eventSource = AInputEvent_getSource ( event ) ;
switch ( eventSource ) {
case AINPUT_SOURCE_JOYSTICK : {
// Left thumbstick
vulkanExample - > gamePadState . axisLeft . x = AMotionEvent_getAxisValue ( event , AMOTION_EVENT_AXIS_X , 0 ) ;
vulkanExample - > gamePadState . axisLeft . y = AMotionEvent_getAxisValue ( event , AMOTION_EVENT_AXIS_Y , 0 ) ;
// Right thumbstick
vulkanExample - > gamePadState . axisRight . x = AMotionEvent_getAxisValue ( event , AMOTION_EVENT_AXIS_Z , 0 ) ;
vulkanExample - > gamePadState . axisRight . y = AMotionEvent_getAxisValue ( event , AMOTION_EVENT_AXIS_RZ , 0 ) ;
break ;
}
case AINPUT_SOURCE_TOUCHSCREEN : {
int32_t action = AMotionEvent_getAction ( event ) ;
switch ( action ) {
2017-03-06 22:11:19 +01:00
case AMOTION_EVENT_ACTION_UP : {
2017-03-25 11:51:32 +01:00
vulkanExample - > lastTapTime = AMotionEvent_getEventTime ( event ) ;
vulkanExample - > touchPos . x = AMotionEvent_getX ( event , 0 ) ;
vulkanExample - > touchPos . y = AMotionEvent_getY ( event , 0 ) ;
2017-03-06 22:11:19 +01:00
vulkanExample - > touchTimer = 0.0 ;
vulkanExample - > touchDown = false ;
vulkanExample - > camera . keys . up = false ;
2017-11-02 17:07:07 +01:00
// Detect single tap
int64_t eventTime = AMotionEvent_getEventTime ( event ) ;
int64_t downTime = AMotionEvent_getDownTime ( event ) ;
if ( eventTime - downTime < = vks : : android : : TAP_TIMEOUT ) {
float deadZone = ( 160.f / vks : : android : : screenDensity ) * vks : : android : : TAP_SLOP * vks : : android : : TAP_SLOP ;
float x = AMotionEvent_getX ( event , 0 ) - vulkanExample - > touchPos . x ;
float y = AMotionEvent_getY ( event , 0 ) - vulkanExample - > touchPos . y ;
if ( ( x * x + y * y ) < deadZone ) {
2024-03-20 07:49:06 +01:00
vulkanExample - > mouseState . buttons . left = true ;
2017-11-02 17:07:07 +01:00
}
} ;
2017-03-06 22:11:19 +01:00
return 1 ;
break ;
}
2017-03-06 21:16:51 +01:00
case AMOTION_EVENT_ACTION_DOWN : {
2017-03-25 11:51:32 +01:00
// Detect double tap
int64_t eventTime = AMotionEvent_getEventTime ( event ) ;
if ( eventTime - vulkanExample - > lastTapTime < = vks : : android : : DOUBLE_TAP_TIMEOUT ) {
float deadZone = ( 160.f / vks : : android : : screenDensity ) * vks : : android : : DOUBLE_TAP_SLOP * vks : : android : : DOUBLE_TAP_SLOP ;
float x = AMotionEvent_getX ( event , 0 ) - vulkanExample - > touchPos . x ;
float y = AMotionEvent_getY ( event , 0 ) - vulkanExample - > touchPos . y ;
if ( ( x * x + y * y ) < deadZone ) {
vulkanExample - > keyPressed ( TOUCH_DOUBLE_TAP ) ;
vulkanExample - > touchDown = false ;
}
}
else {
vulkanExample - > touchDown = true ;
}
2017-03-06 21:16:51 +01:00
vulkanExample - > touchPos . x = AMotionEvent_getX ( event , 0 ) ;
vulkanExample - > touchPos . y = AMotionEvent_getY ( event , 0 ) ;
2024-03-20 07:49:06 +01:00
vulkanExample - > mouseState . position . x = AMotionEvent_getX ( event , 0 ) ;
vulkanExample - > mouseState . position . y = AMotionEvent_getY ( event , 0 ) ;
2017-03-06 21:16:51 +01:00
break ;
2020-02-07 18:28:20 +01:00
}
2017-03-06 21:16:51 +01:00
case AMOTION_EVENT_ACTION_MOVE : {
2017-11-02 17:07:07 +01:00
bool handled = false ;
if ( vulkanExample - > settings . overlay ) {
ImGuiIO & io = ImGui : : GetIO ( ) ;
2024-05-23 21:56:42 +02:00
handled = io . WantCaptureMouse & & vulkanExample - > ui . visible ;
2020-02-07 18:28:20 +01:00
}
2017-11-02 17:07:07 +01:00
if ( ! handled ) {
int32_t eventX = AMotionEvent_getX ( event , 0 ) ;
int32_t eventY = AMotionEvent_getY ( event , 0 ) ;
2017-03-06 21:16:51 +01:00
2020-04-22 20:58:24 +02:00
float deltaX = ( float ) ( vulkanExample - > touchPos . y - eventY ) * vulkanExample - > camera . rotationSpeed * 0.5f ;
float deltaY = ( float ) ( vulkanExample - > touchPos . x - eventX ) * vulkanExample - > camera . rotationSpeed * 0.5f ;
2017-03-06 21:22:11 +01:00
2017-11-02 17:07:07 +01:00
vulkanExample - > camera . rotate ( glm : : vec3 ( deltaX , 0.0f , 0.0f ) ) ;
vulkanExample - > camera . rotate ( glm : : vec3 ( 0.0f , - deltaY , 0.0f ) ) ;
2017-03-06 21:22:11 +01:00
2017-11-02 17:07:07 +01:00
vulkanExample - > touchPos . x = eventX ;
vulkanExample - > touchPos . y = eventY ;
}
2017-03-06 21:16:51 +01:00
break ;
}
default :
return 1 ;
break ;
}
}
return 1 ;
2016-03-20 21:46:49 +01:00
}
}
2016-05-15 11:13:14 +02:00
if ( AInputEvent_getType ( event ) = = AINPUT_EVENT_TYPE_KEY )
{
int32_t keyCode = AKeyEvent_getKeyCode ( ( const AInputEvent * ) event ) ;
int32_t action = AKeyEvent_getAction ( ( const AInputEvent * ) event ) ;
if ( action = = AKEY_EVENT_ACTION_UP )
return 0 ;
switch ( keyCode )
{
case AKEYCODE_BUTTON_A :
vulkanExample - > keyPressed ( GAMEPAD_BUTTON_A ) ;
break ;
case AKEYCODE_BUTTON_B :
vulkanExample - > keyPressed ( GAMEPAD_BUTTON_B ) ;
break ;
case AKEYCODE_BUTTON_X :
vulkanExample - > keyPressed ( GAMEPAD_BUTTON_X ) ;
break ;
case AKEYCODE_BUTTON_Y :
vulkanExample - > keyPressed ( GAMEPAD_BUTTON_Y ) ;
break ;
2022-08-01 16:11:57 -04:00
case AKEYCODE_1 : // support keyboards with no function keys
case AKEYCODE_F1 :
2016-05-15 11:13:14 +02:00
case AKEYCODE_BUTTON_L1 :
2024-05-23 21:56:42 +02:00
vulkanExample - > ui . visible = ! vulkanExample - > ui . visible ;
vulkanExample - > ui . updated = true ;
2016-05-15 11:13:14 +02:00
break ;
case AKEYCODE_BUTTON_R1 :
vulkanExample - > keyPressed ( GAMEPAD_BUTTON_R1 ) ;
break ;
2022-08-01 16:11:57 -04:00
case AKEYCODE_P :
2016-05-15 11:13:14 +02:00
case AKEYCODE_BUTTON_START :
2016-07-18 21:33:59 +02:00
vulkanExample - > paused = ! vulkanExample - > paused ;
2016-05-15 11:13:14 +02:00
break ;
2022-08-01 16:11:57 -04:00
default :
vulkanExample - > keyPressed ( keyCode ) ; // handle example-specific key press events
break ;
2016-05-15 11:13:14 +02:00
} ;
LOGD ( " Button %d pressed " , keyCode ) ;
}
2016-03-20 21:46:49 +01:00
return 0 ;
}
2016-03-20 17:35:54 +01:00
void VulkanExampleBase : : handleAppCommand ( android_app * app , int32_t cmd )
{
2025-02-28 18:18:49 +01:00
assert ( app - > userData ! = nullptr ) ;
2016-08-02 20:41:16 +02:00
VulkanExampleBase * vulkanExample = reinterpret_cast < VulkanExampleBase * > ( app - > userData ) ;
2016-03-20 17:35:54 +01:00
switch ( cmd )
{
case APP_CMD_SAVE_STATE :
2016-03-26 12:58:35 +01:00
LOGD ( " APP_CMD_SAVE_STATE " ) ;
2016-03-20 17:35:54 +01:00
/*
vulkanExample - > app - > savedState = malloc ( sizeof ( struct saved_state ) ) ;
* ( ( struct saved_state * ) vulkanExample - > app - > savedState ) = vulkanExample - > state ;
vulkanExample - > app - > savedStateSize = sizeof ( struct saved_state ) ;
*/
break ;
case APP_CMD_INIT_WINDOW :
LOGD ( " APP_CMD_INIT_WINDOW " ) ;
2025-02-28 18:18:49 +01:00
if ( androidApp - > window ! = nullptr )
2016-03-20 17:35:54 +01:00
{
2018-05-01 11:23:36 +02:00
if ( vulkanExample - > initVulkan ( ) ) {
vulkanExample - > prepare ( ) ;
assert ( vulkanExample - > prepared ) ;
}
else {
LOGE ( " Could not initialize Vulkan, exiting! " ) ;
2018-06-01 18:41:26 +02:00
androidApp - > destroyRequested = 1 ;
2018-05-01 11:23:36 +02:00
}
2016-03-20 17:35:54 +01:00
}
else
{
LOGE ( " No window assigned! " ) ;
}
break ;
case APP_CMD_LOST_FOCUS :
2016-03-26 12:58:35 +01:00
LOGD ( " APP_CMD_LOST_FOCUS " ) ;
vulkanExample - > focused = false ;
break ;
case APP_CMD_GAINED_FOCUS :
LOGD ( " APP_CMD_GAINED_FOCUS " ) ;
vulkanExample - > focused = true ;
2016-03-20 17:35:54 +01:00
break ;
2016-08-31 20:41:32 +02:00
case APP_CMD_TERM_WINDOW :
// Window is hidden or closed, clean up resources
LOGD ( " APP_CMD_TERM_WINDOW " ) ;
2018-05-01 11:23:36 +02:00
if ( vulkanExample - > prepared ) {
vulkanExample - > swapChain . cleanup ( ) ;
}
2016-08-31 20:41:32 +02:00
break ;
2016-03-20 17:35:54 +01:00
}
}
2024-05-04 07:53:08 -04:00
# elif (defined(VK_USE_PLATFORM_IOS_MVK) || defined(VK_USE_PLATFORM_MACOS_MVK) || defined(VK_USE_PLATFORM_METAL_EXT))
2020-09-12 03:19:28 +09:00
# if defined(VK_EXAMPLE_XCODE_GENERATED)
@ interface AppDelegate : NSObject < NSApplicationDelegate >
{
2022-06-01 12:46:41 -04:00
@ public
VulkanExampleBase * vulkanExample ;
2020-09-12 03:19:28 +09:00
}
@ end
@ implementation AppDelegate
{
}
2022-06-01 12:46:41 -04:00
// SRS - Dispatch rendering loop onto a queue for max frame rate concurrent rendering vs displayLink vsync rendering
// - vsync command line option (-vs) on macOS now works like other platforms (using VK_PRESENT_MODE_FIFO_KHR)
dispatch_group_t concurrentGroup ;
- ( void ) applicationDidFinishLaunching : ( NSNotification * ) aNotification
{
2022-07-06 21:35:07 -04:00
[ NSApp activateIgnoringOtherApps : YES ] ; // SRS - Make sure app window launches in front of Xcode window
2024-01-21 05:07:35 -08:00
2022-06-01 12:46:41 -04:00
concurrentGroup = dispatch_group_create ( ) ;
dispatch_queue_t concurrentQueue = dispatch_get_global_queue ( QOS_CLASS_USER_INTERACTIVE , 0 ) ;
dispatch_group_async ( concurrentGroup , concurrentQueue , ^ {
while ( ! vulkanExample - > quit ) {
vulkanExample - > displayLinkOutputCb ( ) ;
}
} ) ;
2024-01-21 05:07:35 -08:00
2022-08-01 16:52:06 -04:00
// SRS - When benchmarking, set up termination notification on main thread when concurrent queue completes
if ( vulkanExample - > benchmark . active ) {
dispatch_queue_t notifyQueue = dispatch_get_main_queue ( ) ;
dispatch_group_notify ( concurrentGroup , notifyQueue , ^ { [ NSApp terminate : nil ] ; } ) ;
}
2022-06-01 12:46:41 -04:00
}
2020-09-12 03:19:28 +09:00
- ( BOOL ) applicationShouldTerminateAfterLastWindowClosed : ( NSApplication * ) sender
{
return YES ;
}
2022-06-01 12:46:41 -04:00
// SRS - Tell rendering loop to quit, then wait for concurrent queue to terminate before deleting vulkanExample
- ( void ) applicationWillTerminate : ( NSNotification * ) aNotification
{
vulkanExample - > quit = YES ;
dispatch_group_wait ( concurrentGroup , DISPATCH_TIME_FOREVER ) ;
2022-07-27 01:11:20 -04:00
vkDeviceWaitIdle ( vulkanExample - > vulkanDevice - > logicalDevice ) ;
delete ( vulkanExample ) ;
2022-06-01 12:46:41 -04:00
}
2020-09-12 03:19:28 +09:00
@ end
2022-05-04 00:43:14 -04:00
const std : : string getAssetPath ( ) {
2024-05-04 07:53:08 -04:00
# if defined(VK_EXAMPLE_ASSETS_DIR)
return VK_EXAMPLE_ASSETS_DIR ;
# else
2023-07-16 18:14:36 +01:00
return [ NSBundle . mainBundle . resourcePath stringByAppendingString : @ " /../../assets/ " ] . UTF8String ;
2024-05-04 07:53:08 -04:00
# endif
2022-05-04 00:43:14 -04:00
}
2024-05-04 07:53:08 -04:00
const std : : string getShaderBasePath ( ) {
# if defined(VK_EXAMPLE_SHADERS_DIR)
return VK_EXAMPLE_SHADERS_DIR ;
# else
return [ NSBundle . mainBundle . resourcePath stringByAppendingString : @ " /../../shaders/ " ] . UTF8String ;
# endif
}
2023-07-15 10:44:22 +01:00
2020-09-12 03:19:28 +09:00
static CVReturn displayLinkOutputCallback ( CVDisplayLinkRef displayLink , const CVTimeStamp * inNow ,
const CVTimeStamp * inOutputTime , CVOptionFlags flagsIn , CVOptionFlags * flagsOut ,
void * displayLinkContext )
{
@ autoreleasepool
{
auto vulkanExample = static_cast < VulkanExampleBase * > ( displayLinkContext ) ;
vulkanExample - > displayLinkOutputCb ( ) ;
}
return kCVReturnSuccess ;
}
@ interface View : NSView < NSWindowDelegate >
{
@ public
VulkanExampleBase * vulkanExample ;
}
@ end
@ implementation View
{
CVDisplayLinkRef displayLink ;
}
- ( instancetype ) initWithFrame : ( NSRect ) frameRect
{
self = [ super initWithFrame : ( frameRect ) ] ;
if ( self )
{
self . wantsLayer = YES ;
self . layer = [ CAMetalLayer layer ] ;
}
return self ;
}
- ( void ) viewDidMoveToWindow
{
CVDisplayLinkCreateWithActiveCGDisplays ( & displayLink ) ;
2022-06-01 12:46:41 -04:00
// SRS - Disable displayLink vsync rendering in favour of max frame rate concurrent rendering
// - vsync command line option (-vs) on macOS now works like other platforms (using VK_PRESENT_MODE_FIFO_KHR)
//CVDisplayLinkSetOutputCallback(displayLink, &displayLinkOutputCallback, vulkanExample);
2020-09-12 03:19:28 +09:00
CVDisplayLinkStart ( displayLink ) ;
}
- ( BOOL ) acceptsFirstResponder
{
return YES ;
}
2022-07-06 21:35:07 -04:00
- ( BOOL ) acceptsFirstMouse : ( NSEvent * ) event
{
return YES ;
}
2020-09-12 03:19:28 +09:00
- ( void ) keyDown : ( NSEvent * ) event
{
switch ( event . keyCode )
{
2022-08-01 16:11:57 -04:00
case KEY_P :
2020-09-12 03:19:28 +09:00
vulkanExample - > paused = ! vulkanExample - > paused ;
break ;
2022-08-01 16:11:57 -04:00
case KEY_1 : // support keyboards with no function keys
case KEY_F1 :
2024-05-23 21:56:42 +02:00
vulkanExample - > ui . visible = ! vulkanExample - > ui . visible ;
vulkanExample - > ui . updated = true ;
2022-08-01 16:11:57 -04:00
break ;
case KEY_DELETE : // support keyboards with no escape key
case KEY_ESCAPE :
2020-09-12 03:19:28 +09:00
[ NSApp terminate : nil ] ;
break ;
2022-08-01 16:11:57 -04:00
case KEY_W :
2020-09-12 03:19:28 +09:00
vulkanExample - > camera . keys . up = true ;
break ;
2022-08-01 16:11:57 -04:00
case KEY_S :
2020-09-12 03:19:28 +09:00
vulkanExample - > camera . keys . down = true ;
break ;
2022-08-01 16:11:57 -04:00
case KEY_A :
2020-09-12 03:19:28 +09:00
vulkanExample - > camera . keys . left = true ;
break ;
2022-08-01 16:11:57 -04:00
case KEY_D :
2020-09-12 03:19:28 +09:00
vulkanExample - > camera . keys . right = true ;
break ;
default :
2022-05-13 21:57:30 -04:00
vulkanExample - > keyPressed ( event . keyCode ) ; // handle example-specific key press events
2020-09-12 03:19:28 +09:00
break ;
}
}
- ( void ) keyUp : ( NSEvent * ) event
{
switch ( event . keyCode )
{
2022-08-01 16:11:57 -04:00
case KEY_W :
2020-09-12 03:19:28 +09:00
vulkanExample - > camera . keys . up = false ;
break ;
2022-08-01 16:11:57 -04:00
case KEY_S :
2020-09-12 03:19:28 +09:00
vulkanExample - > camera . keys . down = false ;
break ;
2022-08-01 16:11:57 -04:00
case KEY_A :
2020-09-12 03:19:28 +09:00
vulkanExample - > camera . keys . left = false ;
2022-05-13 21:57:30 -04:00
break ;
2022-08-01 16:11:57 -04:00
case KEY_D :
2022-05-13 21:57:30 -04:00
vulkanExample - > camera . keys . right = false ;
2020-09-12 03:19:28 +09:00
break ;
default :
break ;
}
}
- ( NSPoint ) getMouseLocalPoint : ( NSEvent * ) event
{
NSPoint location = [ event locationInWindow ] ;
NSPoint point = [ self convertPoint : location fromView : nil ] ;
point . y = self . frame . size . height - point . y ;
return point ;
}
- ( void ) mouseDown : ( NSEvent * ) event
{
auto point = [ self getMouseLocalPoint : event ] ;
2024-03-20 07:49:06 +01:00
vulkanExample - > mouseState . position = glm : : vec2 ( point . x , point . y ) ;
vulkanExample - > mouseState . buttons . left = true ;
2020-09-12 03:19:28 +09:00
}
- ( void ) mouseUp : ( NSEvent * ) event
{
2024-03-20 07:49:06 +01:00
vulkanExample - > mouseState . buttons . left = false ;
2020-09-12 03:19:28 +09:00
}
2022-05-04 00:43:14 -04:00
- ( void ) rightMouseDown : ( NSEvent * ) event
2020-09-12 03:19:28 +09:00
{
2022-06-01 12:46:41 -04:00
auto point = [ self getMouseLocalPoint : event ] ;
2024-03-20 07:49:06 +01:00
vulkanExample - > mouseState . position = glm : : vec2 ( point . x , point . y ) ;
vulkanExample - > mouseState . buttons . right = true ;
2020-09-12 03:19:28 +09:00
}
2022-05-04 00:43:14 -04:00
- ( void ) rightMouseUp : ( NSEvent * ) event
2020-09-12 03:19:28 +09:00
{
2024-03-20 07:49:06 +01:00
vulkanExample - > mouseState . buttons . right = false ;
2020-09-12 03:19:28 +09:00
}
2022-05-04 00:43:14 -04:00
- ( void ) otherMouseDown : ( NSEvent * ) event
{
2022-06-01 12:46:41 -04:00
auto point = [ self getMouseLocalPoint : event ] ;
2024-03-20 07:49:06 +01:00
vulkanExample - > mouseState . position = glm : : vec2 ( point . x , point . y ) ;
vulkanExample - > mouseState . buttons . middle = true ;
2022-05-04 00:43:14 -04:00
}
- ( void ) otherMouseUp : ( NSEvent * ) event
{
2024-03-20 07:49:06 +01:00
vulkanExample - > mouseState . buttons . middle = false ;
2022-05-04 00:43:14 -04:00
}
2020-09-12 03:19:28 +09:00
- ( void ) mouseDragged : ( NSEvent * ) event
{
auto point = [ self getMouseLocalPoint : event ] ;
vulkanExample - > mouseDragged ( point . x , point . y ) ;
}
2022-05-04 00:43:14 -04:00
- ( void ) rightMouseDragged : ( NSEvent * ) event
{
auto point = [ self getMouseLocalPoint : event ] ;
vulkanExample - > mouseDragged ( point . x , point . y ) ;
}
- ( void ) otherMouseDragged : ( NSEvent * ) event
{
auto point = [ self getMouseLocalPoint : event ] ;
vulkanExample - > mouseDragged ( point . x , point . y ) ;
}
2020-09-12 03:19:28 +09:00
- ( void ) mouseMoved : ( NSEvent * ) event
{
auto point = [ self getMouseLocalPoint : event ] ;
vulkanExample - > mouseDragged ( point . x , point . y ) ;
}
- ( void ) scrollWheel : ( NSEvent * ) event
{
short wheelDelta = [ event deltaY ] ;
vulkanExample - > camera . translate ( glm : : vec3 ( 0.0f , 0.0f ,
- ( float ) wheelDelta * 0.05f * vulkanExample - > camera . movementSpeed ) ) ;
2022-07-06 21:35:07 -04:00
vulkanExample - > viewUpdated = true ;
2020-09-12 03:19:28 +09:00
}
2022-06-01 12:46:41 -04:00
// SRS - Window resizing already handled by windowResize() in VulkanExampleBase::submitFrame()
2022-06-11 20:14:55 -04:00
// - handling window resize events here is redundant and can cause thread interaction problems
2022-06-01 12:46:41 -04:00
/*
2020-09-12 03:19:28 +09:00
- ( NSSize ) windowWillResize : ( NSWindow * ) sender toSize : ( NSSize ) frameSize
{
CVDisplayLinkStop ( displayLink ) ;
vulkanExample - > windowWillResize ( frameSize . width , frameSize . height ) ;
return frameSize ;
}
- ( void ) windowDidResize : ( NSNotification * ) notification
{
vulkanExample - > windowDidResize ( ) ;
CVDisplayLinkStart ( displayLink ) ;
}
2022-06-01 12:46:41 -04:00
*/
- ( void ) windowWillEnterFullScreen : ( NSNotification * ) notification
{
vulkanExample - > settings . fullscreen = true ;
}
- ( void ) windowWillExitFullScreen : ( NSNotification * ) notification
{
vulkanExample - > settings . fullscreen = false ;
}
2020-09-12 03:19:28 +09:00
- ( BOOL ) windowShouldClose : ( NSWindow * ) sender
{
return TRUE ;
}
- ( void ) windowWillClose : ( NSNotification * ) notification
{
CVDisplayLinkStop ( displayLink ) ;
2022-06-01 12:46:41 -04:00
CVDisplayLinkRelease ( displayLink ) ;
2020-09-12 03:19:28 +09:00
}
@ end
# endif
2017-04-14 12:00:05 -04:00
void * VulkanExampleBase : : setupWindow ( void * view )
{
2020-09-12 03:19:28 +09:00
# if defined(VK_EXAMPLE_XCODE_GENERATED)
NSApp = [ NSApplication sharedApplication ] ;
[ NSApp setActivationPolicy : NSApplicationActivationPolicyRegular ] ;
2022-06-01 12:46:41 -04:00
auto nsAppDelegate = [ AppDelegate new ] ;
nsAppDelegate - > vulkanExample = this ;
[ NSApp setDelegate : nsAppDelegate ] ;
2020-09-12 03:19:28 +09:00
const auto kContentRect = NSMakeRect ( 0.0f , 0.0f , width , height ) ;
const auto kWindowStyle = NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | NSWindowStyleMaskResizable ;
auto window = [ [ NSWindow alloc ] initWithContentRect : kContentRect
styleMask : kWindowStyle
backing : NSBackingStoreBuffered
defer : NO ] ;
[ window setTitle : @ ( title . c_str ( ) ) ] ;
[ window setAcceptsMouseMovedEvents : YES ] ;
[ window center ] ;
[ window makeKeyAndOrderFront : nil ] ;
2022-06-01 12:46:41 -04:00
if ( settings . fullscreen ) {
[ window toggleFullScreen : nil ] ;
}
2020-09-12 03:19:28 +09:00
auto nsView = [ [ View alloc ] initWithFrame : kContentRect ] ;
nsView - > vulkanExample = this ;
[ window setDelegate : nsView ] ;
[ window setContentView : nsView ] ;
this - > view = ( __bridge void * ) nsView ;
2024-05-04 07:53:08 -04:00
# if defined(VK_USE_PLATFORM_METAL_EXT)
this - > metalLayer = ( CAMetalLayer * ) nsView . layer ;
# endif
2020-09-12 03:19:28 +09:00
# else
2017-07-29 19:31:00 +02:00
this - > view = view ;
2024-05-04 07:53:08 -04:00
# if defined(VK_USE_PLATFORM_METAL_EXT)
this - > metalLayer = ( CAMetalLayer * ) layer ;
# endif
2020-09-12 03:19:28 +09:00
# endif
2017-07-29 19:31:00 +02:00
return view ;
2017-04-14 12:00:05 -04:00
}
2020-09-12 03:19:28 +09:00
void VulkanExampleBase : : displayLinkOutputCb ( )
{
2022-08-01 16:52:06 -04:00
# if defined(VK_EXAMPLE_XCODE_GENERATED)
if ( benchmark . active ) {
benchmark . run ( [ = ] { render ( ) ; } , vulkanDevice - > properties ) ;
if ( benchmark . filename ! = " " ) {
benchmark . saveResults ( ) ;
}
quit = true ; // SRS - quit NSApp rendering loop when benchmarking complete
return ;
}
# endif
2020-09-12 03:19:28 +09:00
if ( prepared )
nextFrame ( ) ;
}
void VulkanExampleBase : : mouseDragged ( float x , float y )
{
handleMouseMove ( static_cast < uint32_t > ( x ) , static_cast < uint32_t > ( y ) ) ;
}
void VulkanExampleBase : : windowWillResize ( float x , float y )
{
resizing = true ;
if ( prepared )
{
destWidth = x ;
destHeight = y ;
windowResize ( ) ;
}
}
void VulkanExampleBase : : windowDidResize ( )
{
resizing = false ;
}
2016-11-04 13:32:58 -07:00
# elif defined(_DIRECT2DISPLAY)
2020-09-13 10:12:33 +02:00
# elif defined(VK_USE_PLATFORM_DIRECTFB_EXT)
IDirectFBSurface * VulkanExampleBase : : setupWindow ( )
{
DFBResult ret ;
int posx = 0 , posy = 0 ;
ret = DirectFBInit ( NULL , NULL ) ;
if ( ret )
{
std : : cout < < " Could not initialize DirectFB! \n " ;
fflush ( stdout ) ;
exit ( 1 ) ;
}
ret = DirectFBCreate ( & dfb ) ;
if ( ret )
{
std : : cout < < " Could not create main interface of DirectFB! \n " ;
fflush ( stdout ) ;
exit ( 1 ) ;
}
ret = dfb - > GetDisplayLayer ( dfb , DLID_PRIMARY , & layer ) ;
if ( ret )
{
std : : cout < < " Could not get DirectFB display layer interface! \n " ;
fflush ( stdout ) ;
exit ( 1 ) ;
}
DFBDisplayLayerConfig layer_config ;
ret = layer - > GetConfiguration ( layer , & layer_config ) ;
if ( ret )
{
std : : cout < < " Could not get DirectFB display layer configuration! \n " ;
fflush ( stdout ) ;
exit ( 1 ) ;
}
if ( settings . fullscreen )
{
width = layer_config . width ;
height = layer_config . height ;
}
else
{
if ( layer_config . width > width )
posx = ( layer_config . width - width ) / 2 ;
if ( layer_config . height > height )
posy = ( layer_config . height - height ) / 2 ;
}
DFBWindowDescription desc ;
desc . flags = ( DFBWindowDescriptionFlags ) ( DWDESC_WIDTH | DWDESC_HEIGHT | DWDESC_POSX | DWDESC_POSY ) ;
desc . width = width ;
desc . height = height ;
desc . posx = posx ;
desc . posy = posy ;
ret = layer - > CreateWindow ( layer , & desc , & window ) ;
if ( ret )
{
std : : cout < < " Could not create DirectFB window interface! \n " ;
fflush ( stdout ) ;
exit ( 1 ) ;
}
ret = window - > GetSurface ( window , & surface ) ;
if ( ret )
{
std : : cout < < " Could not get DirectFB surface interface! \n " ;
fflush ( stdout ) ;
exit ( 1 ) ;
}
ret = window - > CreateEventBuffer ( window , & event_buffer ) ;
if ( ret )
{
std : : cout < < " Could not create DirectFB event buffer interface! \n " ;
fflush ( stdout ) ;
exit ( 1 ) ;
}
ret = window - > SetOpacity ( window , 0xFF ) ;
if ( ret )
{
std : : cout < < " Could not set DirectFB window opacity! \n " ;
fflush ( stdout ) ;
exit ( 1 ) ;
}
return surface ;
}
void VulkanExampleBase : : handleEvent ( const DFBWindowEvent * event )
{
switch ( event - > type )
{
case DWET_CLOSE :
quit = true ;
break ;
case DWET_MOTION :
handleMouseMove ( event - > x , event - > y ) ;
break ;
case DWET_BUTTONDOWN :
switch ( event - > button )
{
case DIBI_LEFT :
2024-03-20 07:49:06 +01:00
mouseState . buttons . left = true ;
2020-09-13 10:12:33 +02:00
break ;
case DIBI_MIDDLE :
2024-03-20 07:49:06 +01:00
mouseState . buttons . middle = true ;
2020-09-13 10:12:33 +02:00
break ;
case DIBI_RIGHT :
2024-03-20 07:49:06 +01:00
mouseState . buttons . right = true ;
2020-09-13 10:12:33 +02:00
break ;
default :
break ;
}
break ;
case DWET_BUTTONUP :
switch ( event - > button )
{
case DIBI_LEFT :
2024-03-20 07:49:06 +01:00
mouseState . buttons . left = false ;
2020-09-13 10:12:33 +02:00
break ;
case DIBI_MIDDLE :
2024-03-20 07:49:06 +01:00
mouseState . buttons . middle = false ;
2020-09-13 10:12:33 +02:00
break ;
case DIBI_RIGHT :
2024-03-20 07:49:06 +01:00
mouseState . buttons . right = false ;
2020-09-13 10:12:33 +02:00
break ;
default :
break ;
}
break ;
case DWET_KEYDOWN :
switch ( event - > key_symbol )
{
case KEY_W :
camera . keys . up = true ;
break ;
case KEY_S :
camera . keys . down = true ;
break ;
case KEY_A :
camera . keys . left = true ;
break ;
case KEY_D :
camera . keys . right = true ;
break ;
case KEY_P :
paused = ! paused ;
break ;
case KEY_F1 :
2024-05-23 21:56:42 +02:00
ui . visible = ! ui . visible ;
ui . updated = true ;
2020-09-13 10:12:33 +02:00
break ;
default :
break ;
}
break ;
case DWET_KEYUP :
switch ( event - > key_symbol )
{
case KEY_W :
camera . keys . up = false ;
break ;
case KEY_S :
camera . keys . down = false ;
break ;
case KEY_A :
camera . keys . left = false ;
break ;
case KEY_D :
camera . keys . right = false ;
break ;
case KEY_ESCAPE :
quit = true ;
break ;
default :
break ;
}
keyPressed ( event - > key_symbol ) ;
break ;
case DWET_SIZE :
destWidth = event - > w ;
destHeight = event - > h ;
windowResize ( ) ;
break ;
default :
break ;
}
}
2017-02-02 08:54:56 +00:00
# elif defined(VK_USE_PLATFORM_WAYLAND_KHR)
/*static*/ void VulkanExampleBase : : registryGlobalCb ( void * data ,
wl_registry * registry , uint32_t name , const char * interface ,
uint32_t version )
{
VulkanExampleBase * self = reinterpret_cast < VulkanExampleBase * > ( data ) ;
self - > registryGlobal ( registry , name , interface , version ) ;
}
/*static*/ void VulkanExampleBase : : seatCapabilitiesCb ( void * data , wl_seat * seat ,
uint32_t caps )
{
VulkanExampleBase * self = reinterpret_cast < VulkanExampleBase * > ( data ) ;
self - > seatCapabilities ( seat , caps ) ;
}
/*static*/ void VulkanExampleBase : : pointerEnterCb ( void * data ,
wl_pointer * pointer , uint32_t serial , wl_surface * surface ,
wl_fixed_t sx , wl_fixed_t sy )
{
}
/*static*/ void VulkanExampleBase : : pointerLeaveCb ( void * data ,
wl_pointer * pointer , uint32_t serial , wl_surface * surface )
{
}
/*static*/ void VulkanExampleBase : : pointerMotionCb ( void * data ,
wl_pointer * pointer , uint32_t time , wl_fixed_t sx , wl_fixed_t sy )
{
VulkanExampleBase * self = reinterpret_cast < VulkanExampleBase * > ( data ) ;
self - > pointerMotion ( pointer , time , sx , sy ) ;
}
2017-11-02 13:40:27 +01:00
void VulkanExampleBase : : pointerMotion ( wl_pointer * pointer , uint32_t time , wl_fixed_t sx , wl_fixed_t sy )
2017-02-02 08:54:56 +00:00
{
2017-11-02 13:40:27 +01:00
handleMouseMove ( wl_fixed_to_int ( sx ) , wl_fixed_to_int ( sy ) ) ;
2017-02-02 08:54:56 +00:00
}
/*static*/ void VulkanExampleBase : : pointerButtonCb ( void * data ,
wl_pointer * pointer , uint32_t serial , uint32_t time , uint32_t button ,
uint32_t state )
{
VulkanExampleBase * self = reinterpret_cast < VulkanExampleBase * > ( data ) ;
self - > pointerButton ( pointer , serial , time , button , state ) ;
}
void VulkanExampleBase : : pointerButton ( struct wl_pointer * pointer ,
uint32_t serial , uint32_t time , uint32_t button , uint32_t state )
{
switch ( button )
{
case BTN_LEFT :
2024-03-20 07:49:06 +01:00
mouseState . buttons . left = ! ! state ;
2017-02-02 08:54:56 +00:00
break ;
case BTN_MIDDLE :
2024-03-20 07:49:06 +01:00
mouseState . buttons . middle = ! ! state ;
2017-02-02 08:54:56 +00:00
break ;
case BTN_RIGHT :
2024-03-20 07:49:06 +01:00
mouseState . buttons . right = ! ! state ;
2017-02-02 08:54:56 +00:00
break ;
default :
break ;
}
}
/*static*/ void VulkanExampleBase : : pointerAxisCb ( void * data ,
wl_pointer * pointer , uint32_t time , uint32_t axis ,
wl_fixed_t value )
{
VulkanExampleBase * self = reinterpret_cast < VulkanExampleBase * > ( data ) ;
self - > pointerAxis ( pointer , time , axis , value ) ;
}
void VulkanExampleBase : : pointerAxis ( wl_pointer * pointer , uint32_t time ,
uint32_t axis , wl_fixed_t value )
{
double d = wl_fixed_to_double ( value ) ;
switch ( axis )
{
case REL_X :
2020-04-22 20:58:24 +02:00
camera . translate ( glm : : vec3 ( 0.0f , 0.0f , d * 0.005f ) ) ;
2017-02-02 08:54:56 +00:00
viewUpdated = true ;
break ;
default :
break ;
}
}
/*static*/ void VulkanExampleBase : : keyboardKeymapCb ( void * data ,
struct wl_keyboard * keyboard , uint32_t format , int fd , uint32_t size )
{
}
/*static*/ void VulkanExampleBase : : keyboardEnterCb ( void * data ,
struct wl_keyboard * keyboard , uint32_t serial ,
struct wl_surface * surface , struct wl_array * keys )
{
}
/*static*/ void VulkanExampleBase : : keyboardLeaveCb ( void * data ,
struct wl_keyboard * keyboard , uint32_t serial ,
struct wl_surface * surface )
{
}
/*static*/ void VulkanExampleBase : : keyboardKeyCb ( void * data ,
struct wl_keyboard * keyboard , uint32_t serial , uint32_t time ,
uint32_t key , uint32_t state )
{
VulkanExampleBase * self = reinterpret_cast < VulkanExampleBase * > ( data ) ;
self - > keyboardKey ( keyboard , serial , time , key , state ) ;
}
void VulkanExampleBase : : keyboardKey ( struct wl_keyboard * keyboard ,
uint32_t serial , uint32_t time , uint32_t key , uint32_t state )
{
switch ( key )
{
case KEY_W :
camera . keys . up = ! ! state ;
break ;
case KEY_S :
camera . keys . down = ! ! state ;
break ;
case KEY_A :
camera . keys . left = ! ! state ;
break ;
case KEY_D :
camera . keys . right = ! ! state ;
break ;
case KEY_P :
if ( state )
paused = ! paused ;
break ;
case KEY_F1 :
2022-08-01 16:11:57 -04:00
if ( state ) {
2024-05-23 21:56:42 +02:00
ui . visible = ! ui . visible ;
ui . updated = true ;
2022-08-01 16:11:57 -04:00
}
2017-02-02 08:54:56 +00:00
break ;
2022-08-01 16:11:57 -04:00
case KEY_ESCAPE :
2017-02-02 08:54:56 +00:00
quit = true ;
break ;
}
if ( state )
keyPressed ( key ) ;
}
/*static*/ void VulkanExampleBase : : keyboardModifiersCb ( void * data ,
struct wl_keyboard * keyboard , uint32_t serial , uint32_t mods_depressed ,
uint32_t mods_latched , uint32_t mods_locked , uint32_t group )
{
}
void VulkanExampleBase : : seatCapabilities ( wl_seat * seat , uint32_t caps )
{
if ( ( caps & WL_SEAT_CAPABILITY_POINTER ) & & ! pointer )
{
pointer = wl_seat_get_pointer ( seat ) ;
static const struct wl_pointer_listener pointer_listener =
{ pointerEnterCb , pointerLeaveCb , pointerMotionCb , pointerButtonCb ,
pointerAxisCb , } ;
wl_pointer_add_listener ( pointer , & pointer_listener , this ) ;
}
else if ( ! ( caps & WL_SEAT_CAPABILITY_POINTER ) & & pointer )
{
wl_pointer_destroy ( pointer ) ;
pointer = nullptr ;
}
if ( ( caps & WL_SEAT_CAPABILITY_KEYBOARD ) & & ! keyboard )
{
keyboard = wl_seat_get_keyboard ( seat ) ;
static const struct wl_keyboard_listener keyboard_listener =
{ keyboardKeymapCb , keyboardEnterCb , keyboardLeaveCb , keyboardKeyCb ,
keyboardModifiersCb , } ;
wl_keyboard_add_listener ( keyboard , & keyboard_listener , this ) ;
}
else if ( ! ( caps & WL_SEAT_CAPABILITY_KEYBOARD ) & & keyboard )
{
wl_keyboard_destroy ( keyboard ) ;
keyboard = nullptr ;
}
}
2019-01-16 01:16:58 -07:00
static void xdg_wm_base_ping ( void * data , struct xdg_wm_base * shell , uint32_t serial )
{
xdg_wm_base_pong ( shell , serial ) ;
}
static const struct xdg_wm_base_listener xdg_wm_base_listener = {
xdg_wm_base_ping ,
} ;
2017-02-02 08:54:56 +00:00
void VulkanExampleBase : : registryGlobal ( wl_registry * registry , uint32_t name ,
const char * interface , uint32_t version )
{
if ( strcmp ( interface , " wl_compositor " ) = = 0 )
{
compositor = ( wl_compositor * ) wl_registry_bind ( registry , name ,
& wl_compositor_interface , 3 ) ;
}
2019-01-16 01:16:58 -07:00
else if ( strcmp ( interface , " xdg_wm_base " ) = = 0 )
2017-02-02 08:54:56 +00:00
{
2019-01-16 01:16:58 -07:00
shell = ( xdg_wm_base * ) wl_registry_bind ( registry , name ,
& xdg_wm_base_interface , 1 ) ;
xdg_wm_base_add_listener ( shell , & xdg_wm_base_listener , nullptr ) ;
2017-02-02 08:54:56 +00:00
}
else if ( strcmp ( interface , " wl_seat " ) = = 0 )
{
seat = ( wl_seat * ) wl_registry_bind ( registry , name , & wl_seat_interface ,
1 ) ;
static const struct wl_seat_listener seat_listener =
{ seatCapabilitiesCb , } ;
wl_seat_add_listener ( seat , & seat_listener , this ) ;
}
}
/*static*/ void VulkanExampleBase : : registryGlobalRemoveCb ( void * data ,
struct wl_registry * registry , uint32_t name )
{
}
void VulkanExampleBase : : initWaylandConnection ( )
{
display = wl_display_connect ( NULL ) ;
if ( ! display )
{
std : : cout < < " Could not connect to Wayland display! \n " ;
fflush ( stdout ) ;
exit ( 1 ) ;
}
registry = wl_display_get_registry ( display ) ;
if ( ! registry )
{
std : : cout < < " Could not get Wayland registry! \n " ;
fflush ( stdout ) ;
exit ( 1 ) ;
}
static const struct wl_registry_listener registry_listener =
{ registryGlobalCb , registryGlobalRemoveCb } ;
wl_registry_add_listener ( registry , & registry_listener , this ) ;
wl_display_dispatch ( display ) ;
2017-02-14 18:52:02 +00:00
wl_display_roundtrip ( display ) ;
2021-05-04 16:37:57 +01:00
if ( ! compositor | | ! shell )
2017-02-02 08:54:56 +00:00
{
std : : cout < < " Could not bind Wayland protocols! \n " ;
fflush ( stdout ) ;
exit ( 1 ) ;
}
2021-05-04 16:37:57 +01:00
if ( ! seat )
{
std : : cout < < " WARNING: Input handling not available! \n " ;
fflush ( stdout ) ;
}
2017-02-02 08:54:56 +00:00
}
2019-01-16 01:16:58 -07:00
void VulkanExampleBase : : setSize ( int width , int height )
{
if ( width < = 0 | | height < = 0 )
return ;
destWidth = width ;
destHeight = height ;
windowResize ( ) ;
}
static void
xdg_surface_handle_configure ( void * data , struct xdg_surface * surface ,
uint32_t serial )
2017-02-02 08:54:56 +00:00
{
2019-01-16 01:16:58 -07:00
VulkanExampleBase * base = ( VulkanExampleBase * ) data ;
xdg_surface_ack_configure ( surface , serial ) ;
base - > configured = true ;
2017-02-02 08:54:56 +00:00
}
2019-01-16 01:16:58 -07:00
static const struct xdg_surface_listener xdg_surface_listener = {
xdg_surface_handle_configure ,
} ;
static void
xdg_toplevel_handle_configure ( void * data , struct xdg_toplevel * toplevel ,
int32_t width , int32_t height ,
struct wl_array * states )
2017-02-02 08:54:56 +00:00
{
2019-01-16 01:16:58 -07:00
VulkanExampleBase * base = ( VulkanExampleBase * ) data ;
base - > setSize ( width , height ) ;
2017-02-02 08:54:56 +00:00
}
2019-01-16 01:16:58 -07:00
static void
xdg_toplevel_handle_close ( void * data , struct xdg_toplevel * xdg_toplevel )
2017-02-02 08:54:56 +00:00
{
2019-01-16 01:16:58 -07:00
VulkanExampleBase * base = ( VulkanExampleBase * ) data ;
base - > quit = true ;
2017-02-02 08:54:56 +00:00
}
2019-01-16 01:16:58 -07:00
static const struct xdg_toplevel_listener xdg_toplevel_listener = {
xdg_toplevel_handle_configure ,
xdg_toplevel_handle_close ,
} ;
struct xdg_surface * VulkanExampleBase : : setupWindow ( )
2017-02-02 08:54:56 +00:00
{
surface = wl_compositor_create_surface ( compositor ) ;
2019-01-16 01:16:58 -07:00
xdg_surface = xdg_wm_base_get_xdg_surface ( shell , surface ) ;
2017-02-02 08:54:56 +00:00
2019-01-16 01:16:58 -07:00
xdg_surface_add_listener ( xdg_surface , & xdg_surface_listener , this ) ;
xdg_toplevel = xdg_surface_get_toplevel ( xdg_surface ) ;
xdg_toplevel_add_listener ( xdg_toplevel , & xdg_toplevel_listener , this ) ;
2017-02-02 08:54:56 +00:00
std : : string windowTitle = getWindowTitle ( ) ;
2019-01-16 01:16:58 -07:00
xdg_toplevel_set_title ( xdg_toplevel , windowTitle . c_str ( ) ) ;
2024-08-02 18:11:48 +01:00
if ( settings . fullscreen )
{
xdg_toplevel_set_fullscreen ( xdg_toplevel , NULL ) ;
}
2019-01-16 01:16:58 -07:00
wl_surface_commit ( surface ) ;
2024-08-02 18:11:48 +01:00
wl_display_flush ( display ) ;
2019-01-16 01:16:58 -07:00
return xdg_surface ;
2017-02-02 08:54:56 +00:00
}
2017-08-13 10:24:25 +02:00
# elif defined(VK_USE_PLATFORM_XCB_KHR)
2017-01-23 10:49:27 +01:00
static inline xcb_intern_atom_reply_t * intern_atom_helper ( xcb_connection_t * conn , bool only_if_exists , const char * str )
{
xcb_intern_atom_cookie_t cookie = xcb_intern_atom ( conn , only_if_exists , strlen ( str ) , str ) ;
return xcb_intern_atom_reply ( conn , cookie , NULL ) ;
}
2016-03-03 16:41:57 +01:00
// Set up a window using XCB and request event types
2016-02-16 15:07:25 +01:00
xcb_window_t VulkanExampleBase : : setupWindow ( )
{
uint32_t value_mask , value_list [ 32 ] ;
window = xcb_generate_id ( connection ) ;
value_mask = XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK ;
value_list [ 0 ] = screen - > black_pixel ;
2016-03-13 17:15:44 +01:00
value_list [ 1 ] =
2016-03-03 16:41:57 +01:00
XCB_EVENT_MASK_KEY_RELEASE |
2016-08-03 20:44:31 +02:00
XCB_EVENT_MASK_KEY_PRESS |
2016-02-16 15:07:25 +01:00
XCB_EVENT_MASK_EXPOSURE |
XCB_EVENT_MASK_STRUCTURE_NOTIFY |
XCB_EVENT_MASK_POINTER_MOTION |
XCB_EVENT_MASK_BUTTON_PRESS |
XCB_EVENT_MASK_BUTTON_RELEASE ;
2017-01-23 10:49:27 +01:00
if ( settings . fullscreen )
{
width = destWidth = screen - > width_in_pixels ;
height = destHeight = screen - > height_in_pixels ;
}
2016-02-16 15:07:25 +01:00
xcb_create_window ( connection ,
XCB_COPY_FROM_PARENT ,
window , screen - > root ,
0 , 0 , width , height , 0 ,
XCB_WINDOW_CLASS_INPUT_OUTPUT ,
screen - > root_visual ,
value_mask , value_list ) ;
/* Magic code that will send notification when window is destroyed */
2017-01-23 10:49:27 +01:00
xcb_intern_atom_reply_t * reply = intern_atom_helper ( connection , true , " WM_PROTOCOLS " ) ;
atom_wm_delete_window = intern_atom_helper ( connection , false , " WM_DELETE_WINDOW " ) ;
2016-02-16 15:07:25 +01:00
xcb_change_property ( connection , XCB_PROP_MODE_REPLACE ,
window , ( * reply ) . atom , 4 , 32 , 1 ,
& ( * atom_wm_delete_window ) . atom ) ;
2016-03-13 17:15:44 +01:00
std : : string windowTitle = getWindowTitle ( ) ;
2016-02-16 15:07:25 +01:00
xcb_change_property ( connection , XCB_PROP_MODE_REPLACE ,
window , XCB_ATOM_WM_NAME , XCB_ATOM_STRING , 8 ,
2016-03-13 17:15:44 +01:00
title . size ( ) , windowTitle . c_str ( ) ) ;
2016-02-16 15:07:25 +01:00
free ( reply ) ;
2020-04-30 11:29:50 -04:00
/**
* Set the WM_CLASS property to display
* title in dash tooltip and application menu
* on GNOME and other desktop environments
*/
std : : string wm_class ;
wm_class = wm_class . insert ( 0 , name ) ;
wm_class = wm_class . insert ( name . size ( ) , 1 , ' \0 ' ) ;
wm_class = wm_class . insert ( name . size ( ) + 1 , title ) ;
wm_class = wm_class . insert ( wm_class . size ( ) , 1 , ' \0 ' ) ;
xcb_change_property ( connection , XCB_PROP_MODE_REPLACE , window , XCB_ATOM_WM_CLASS , XCB_ATOM_STRING , 8 , wm_class . size ( ) + 2 , wm_class . c_str ( ) ) ;
2017-01-23 10:49:27 +01:00
if ( settings . fullscreen )
{
xcb_intern_atom_reply_t * atom_wm_state = intern_atom_helper ( connection , false , " _NET_WM_STATE " ) ;
xcb_intern_atom_reply_t * atom_wm_fullscreen = intern_atom_helper ( connection , false , " _NET_WM_STATE_FULLSCREEN " ) ;
xcb_change_property ( connection ,
XCB_PROP_MODE_REPLACE ,
window , atom_wm_state - > atom ,
XCB_ATOM_ATOM , 32 , 1 ,
& ( atom_wm_fullscreen - > atom ) ) ;
free ( atom_wm_fullscreen ) ;
free ( atom_wm_state ) ;
2020-05-29 16:08:53 +01:00
}
2017-01-23 10:49:27 +01:00
2016-02-16 15:07:25 +01:00
xcb_map_window ( connection , window ) ;
return ( window ) ;
}
// Initialize XCB connection
void VulkanExampleBase : : initxcbConnection ( )
{
const xcb_setup_t * setup ;
xcb_screen_iterator_t iter ;
int scr ;
2020-08-24 08:01:23 +02:00
// xcb_connect always returns a non-NULL pointer to a xcb_connection_t,
// even on failure. Callers need to use xcb_connection_has_error() to
// check for failure. When finished, use xcb_disconnect() to close the
// connection and free the structure.
2016-02-16 15:07:25 +01:00
connection = xcb_connect ( NULL , & scr ) ;
2020-08-24 08:01:23 +02:00
assert ( connection ) ;
if ( xcb_connection_has_error ( connection ) ) {
2016-02-16 15:07:25 +01:00
printf ( " Could not find a compatible Vulkan ICD! \n " ) ;
fflush ( stdout ) ;
exit ( 1 ) ;
}
setup = xcb_get_setup ( connection ) ;
iter = xcb_setup_roots_iterator ( setup ) ;
while ( scr - - > 0 )
xcb_screen_next ( & iter ) ;
screen = iter . data ;
}
void VulkanExampleBase : : handleEvent ( const xcb_generic_event_t * event )
{
switch ( event - > response_type & 0x7f )
{
case XCB_CLIENT_MESSAGE :
if ( ( * ( xcb_client_message_event_t * ) event ) . data . data32 [ 0 ] = =
( * atom_wm_delete_window ) . atom ) {
quit = true ;
}
break ;
case XCB_MOTION_NOTIFY :
{
xcb_motion_notify_event_t * motion = ( xcb_motion_notify_event_t * ) event ;
2017-11-02 13:40:27 +01:00
handleMouseMove ( ( int32_t ) motion - > event_x , ( int32_t ) motion - > event_y ) ;
break ;
2016-02-16 15:07:25 +01:00
}
break ;
case XCB_BUTTON_PRESS :
{
xcb_button_press_event_t * press = ( xcb_button_press_event_t * ) event ;
2016-03-30 22:48:58 +02:00
if ( press - > detail = = XCB_BUTTON_INDEX_1 )
2024-03-20 07:49:06 +01:00
mouseState . buttons . left = true ;
2016-03-30 23:00:53 +02:00
if ( press - > detail = = XCB_BUTTON_INDEX_2 )
2024-03-20 07:49:06 +01:00
mouseState . buttons . middle = true ;
2016-03-30 22:48:58 +02:00
if ( press - > detail = = XCB_BUTTON_INDEX_3 )
2024-03-20 07:49:06 +01:00
mouseState . buttons . right = true ;
2016-02-16 15:07:25 +01:00
}
break ;
case XCB_BUTTON_RELEASE :
{
xcb_button_press_event_t * press = ( xcb_button_press_event_t * ) event ;
2016-03-30 22:48:58 +02:00
if ( press - > detail = = XCB_BUTTON_INDEX_1 )
2024-03-20 07:49:06 +01:00
mouseState . buttons . left = false ;
2016-03-30 23:00:53 +02:00
if ( press - > detail = = XCB_BUTTON_INDEX_2 )
2024-03-20 07:49:06 +01:00
mouseState . buttons . middle = false ;
2016-03-30 22:48:58 +02:00
if ( press - > detail = = XCB_BUTTON_INDEX_3 )
2024-03-20 07:49:06 +01:00
mouseState . buttons . right = false ;
2016-02-16 15:07:25 +01:00
}
break ;
2016-08-03 21:44:04 +02:00
case XCB_KEY_PRESS :
{
const xcb_key_release_event_t * keyEvent = ( const xcb_key_release_event_t * ) event ;
switch ( keyEvent - > detail )
{
case KEY_W :
camera . keys . up = true ;
break ;
case KEY_S :
camera . keys . down = true ;
break ;
case KEY_A :
camera . keys . left = true ;
break ;
case KEY_D :
camera . keys . right = true ;
break ;
2016-08-04 20:58:02 +02:00
case KEY_P :
paused = ! paused ;
break ;
case KEY_F1 :
2024-05-23 21:56:42 +02:00
ui . visible = ! ui . visible ;
ui . updated = true ;
2020-02-07 18:28:20 +01:00
break ;
2016-08-03 21:44:04 +02:00
}
}
2020-05-29 16:08:53 +01:00
break ;
2016-02-16 15:07:25 +01:00
case XCB_KEY_RELEASE :
{
2016-03-03 16:41:57 +01:00
const xcb_key_release_event_t * keyEvent = ( const xcb_key_release_event_t * ) event ;
2016-08-03 20:44:31 +02:00
switch ( keyEvent - > detail )
{
2016-08-03 21:44:04 +02:00
case KEY_W :
camera . keys . up = false ;
break ;
case KEY_S :
camera . keys . down = false ;
break ;
case KEY_A :
camera . keys . left = false ;
break ;
case KEY_D :
camera . keys . right = false ;
2020-02-07 18:28:20 +01:00
break ;
2016-08-03 21:44:04 +02:00
case KEY_ESCAPE :
2016-08-03 20:44:31 +02:00
quit = true ;
break ;
}
2016-03-03 16:41:57 +01:00
keyPressed ( keyEvent - > detail ) ;
2016-02-16 15:07:25 +01:00
}
break ;
case XCB_DESTROY_NOTIFY :
quit = true ;
break ;
2016-04-11 19:44:03 +02:00
case XCB_CONFIGURE_NOTIFY :
{
const xcb_configure_notify_event_t * cfgEvent = ( const xcb_configure_notify_event_t * ) event ;
if ( ( prepared ) & & ( ( cfgEvent - > width ! = width ) | | ( cfgEvent - > height ! = height ) ) )
{
destWidth = cfgEvent - > width ;
destHeight = cfgEvent - > height ;
if ( ( destWidth > 0 ) & & ( destHeight > 0 ) )
{
windowResize ( ) ;
}
}
}
break ;
2016-02-16 15:07:25 +01:00
default :
break ;
}
}
2023-09-01 11:12:08 -04:00
# elif defined(VK_USE_PLATFORM_SCREEN_QNX)
void VulkanExampleBase : : handleEvent ( )
{
int size [ 2 ] = { 0 , 0 } ;
screen_window_t win ;
static int mouse_buttons = 0 ;
int pos [ 2 ] ;
int val ;
int keyflags ;
int rc ;
while ( ! screen_get_event ( screen_context , screen_event , paused ? ~ 0 : 0 ) ) {
rc = screen_get_event_property_iv ( screen_event , SCREEN_PROPERTY_TYPE , & val ) ;
if ( rc ) {
printf ( " Cannot get SCREEN_PROPERTY_TYPE of the event! (%s) \n " , strerror ( errno ) ) ;
fflush ( stdout ) ;
quit = true ;
break ;
}
if ( val = = SCREEN_EVENT_NONE ) {
break ;
}
switch ( val ) {
case SCREEN_EVENT_KEYBOARD :
rc = screen_get_event_property_iv ( screen_event , SCREEN_PROPERTY_FLAGS , & keyflags ) ;
if ( rc ) {
printf ( " Cannot get SCREEN_PROPERTY_FLAGS of the event! (%s) \n " , strerror ( errno ) ) ;
fflush ( stdout ) ;
quit = true ;
break ;
}
rc = screen_get_event_property_iv ( screen_event , SCREEN_PROPERTY_SYM , & val ) ;
if ( rc ) {
printf ( " Cannot get SCREEN_PROPERTY_SYM of the event! (%s) \n " , strerror ( errno ) ) ;
fflush ( stdout ) ;
quit = true ;
break ;
}
if ( ( keyflags & KEY_SYM_VALID ) = = KEY_SYM_VALID ) {
switch ( val ) {
case KEYCODE_ESCAPE :
quit = true ;
break ;
case KEYCODE_W :
if ( keyflags & KEY_DOWN ) {
camera . keys . up = true ;
} else {
camera . keys . up = false ;
}
break ;
case KEYCODE_S :
if ( keyflags & KEY_DOWN ) {
camera . keys . down = true ;
} else {
camera . keys . down = false ;
}
break ;
case KEYCODE_A :
if ( keyflags & KEY_DOWN ) {
camera . keys . left = true ;
} else {
camera . keys . left = false ;
}
break ;
case KEYCODE_D :
if ( keyflags & KEY_DOWN ) {
camera . keys . right = true ;
} else {
camera . keys . right = false ;
}
break ;
case KEYCODE_P :
paused = ! paused ;
break ;
case KEYCODE_F1 :
2024-05-23 21:56:42 +02:00
ui . visible = ! ui . visible ;
ui . updated = true ;
2023-09-01 11:12:08 -04:00
break ;
default :
break ;
}
if ( ( keyflags & KEY_DOWN ) = = KEY_DOWN ) {
if ( ( val > = 0x20 ) & & ( val < = 0xFF ) ) {
keyPressed ( val ) ;
}
}
}
break ;
case SCREEN_EVENT_PROPERTY :
rc = screen_get_event_property_pv ( screen_event , SCREEN_PROPERTY_WINDOW , ( void * * ) & win ) ;
if ( rc ) {
printf ( " Cannot get SCREEN_PROPERTY_WINDOW of the event! (%s) \n " , strerror ( errno ) ) ;
fflush ( stdout ) ;
quit = true ;
break ;
}
rc = screen_get_event_property_iv ( screen_event , SCREEN_PROPERTY_NAME , & val ) ;
if ( rc ) {
printf ( " Cannot get SCREEN_PROPERTY_NAME of the event! (%s) \n " , strerror ( errno ) ) ;
fflush ( stdout ) ;
quit = true ;
break ;
}
if ( win = = screen_window ) {
switch ( val ) {
case SCREEN_PROPERTY_SIZE :
rc = screen_get_window_property_iv ( win , SCREEN_PROPERTY_SIZE , size ) ;
if ( rc ) {
printf ( " Cannot get SCREEN_PROPERTY_SIZE of the window in the event! (%s) \n " , strerror ( errno ) ) ;
fflush ( stdout ) ;
quit = true ;
break ;
}
width = size [ 0 ] ;
height = size [ 1 ] ;
windowResize ( ) ;
break ;
default :
/* We are not interested in any other events for now */
break ;
}
}
break ;
case SCREEN_EVENT_POINTER :
rc = screen_get_event_property_iv ( screen_event , SCREEN_PROPERTY_BUTTONS , & val ) ;
if ( rc ) {
printf ( " Cannot get SCREEN_PROPERTY_BUTTONS of the event! (%s) \n " , strerror ( errno ) ) ;
fflush ( stdout ) ;
quit = true ;
break ;
}
if ( ( mouse_buttons & SCREEN_LEFT_MOUSE_BUTTON ) = = 0 ) {
if ( ( val & SCREEN_LEFT_MOUSE_BUTTON ) = = SCREEN_LEFT_MOUSE_BUTTON ) {
2024-03-20 07:49:06 +01:00
mouseState . buttons . left = true ;
2023-09-01 11:12:08 -04:00
}
} else {
if ( ( val & SCREEN_LEFT_MOUSE_BUTTON ) = = 0 ) {
2024-03-20 07:49:06 +01:00
mouseState . buttons . left = false ;
2023-09-01 11:12:08 -04:00
}
}
if ( ( mouse_buttons & SCREEN_RIGHT_MOUSE_BUTTON ) = = 0 ) {
if ( ( val & SCREEN_RIGHT_MOUSE_BUTTON ) = = SCREEN_RIGHT_MOUSE_BUTTON ) {
2024-03-20 07:49:06 +01:00
mouseState . buttons . right = true ;
2023-09-01 11:12:08 -04:00
}
} else {
if ( ( val & SCREEN_RIGHT_MOUSE_BUTTON ) = = 0 ) {
2024-03-20 07:49:06 +01:00
mouseState . buttons . right = false ;
2023-09-01 11:12:08 -04:00
}
}
if ( ( mouse_buttons & SCREEN_MIDDLE_MOUSE_BUTTON ) = = 0 ) {
if ( ( val & SCREEN_MIDDLE_MOUSE_BUTTON ) = = SCREEN_MIDDLE_MOUSE_BUTTON ) {
2024-03-20 07:49:06 +01:00
mouseState . buttons . middle = true ;
2023-09-01 11:12:08 -04:00
}
} else {
if ( ( val & SCREEN_MIDDLE_MOUSE_BUTTON ) = = 0 ) {
2024-03-20 07:49:06 +01:00
mouseState . buttons . middle = false ;
2023-09-01 11:12:08 -04:00
}
}
mouse_buttons = val ;
rc = screen_get_event_property_iv ( screen_event , SCREEN_PROPERTY_MOUSE_WHEEL , & val ) ;
if ( rc ) {
printf ( " Cannot get SCREEN_PROPERTY_MOUSE_WHEEL of the event! (%s) \n " , strerror ( errno ) ) ;
fflush ( stdout ) ;
quit = true ;
break ;
}
if ( val ! = 0 ) {
camera . translate ( glm : : vec3 ( 0.0f , 0.0f , ( float ) val * 0.005f ) ) ;
viewUpdated = true ;
}
rc = screen_get_event_property_iv ( screen_event , SCREEN_PROPERTY_POSITION , pos ) ;
if ( rc ) {
printf ( " Cannot get SCREEN_PROPERTY_DISPLACEMENT of the event! (%s) \n " , strerror ( errno ) ) ;
fflush ( stdout ) ;
quit = true ;
break ;
}
if ( ( pos [ 0 ] ! = 0 ) | | ( pos [ 1 ] ! = 0 ) ) {
handleMouseMove ( pos [ 0 ] , pos [ 1 ] ) ;
}
updateOverlay ( ) ;
break ;
}
}
}
void VulkanExampleBase : : setupWindow ( )
{
const char * idstr = name . c_str ( ) ;
int size [ 2 ] ;
int usage = SCREEN_USAGE_VULKAN ;
int rc ;
if ( screen_pipeline_set ) {
usage | = SCREEN_USAGE_OVERLAY ;
}
rc = screen_create_context ( & screen_context , 0 ) ;
if ( rc ) {
printf ( " Cannot create QNX Screen context! \n " ) ;
fflush ( stdout ) ;
exit ( EXIT_FAILURE ) ;
}
rc = screen_create_window ( & screen_window , screen_context ) ;
if ( rc ) {
printf ( " Cannot create QNX Screen window! \n " ) ;
fflush ( stdout ) ;
exit ( EXIT_FAILURE ) ;
}
rc = screen_create_event ( & screen_event ) ;
if ( rc ) {
printf ( " Cannot create QNX Screen event! \n " ) ;
fflush ( stdout ) ;
exit ( EXIT_FAILURE ) ;
}
/* Set window caption */
screen_set_window_property_cv ( screen_window , SCREEN_PROPERTY_ID_STRING , strlen ( idstr ) , idstr ) ;
/* Setup VULKAN usage flags */
rc = screen_set_window_property_iv ( screen_window , SCREEN_PROPERTY_USAGE , & usage ) ;
if ( rc ) {
printf ( " Cannot set SCREEN_USAGE_VULKAN flag! \n " ) ;
fflush ( stdout ) ;
exit ( EXIT_FAILURE ) ;
}
if ( ( width = = 0 ) | | ( height = = 0 ) | | ( settings . fullscreen ) | | use_window_size ) {
rc = screen_get_window_property_iv ( screen_window , SCREEN_PROPERTY_SIZE , size ) ;
if ( rc ) {
printf ( " Cannot obtain current window size! \n " ) ;
fflush ( stdout ) ;
exit ( EXIT_FAILURE ) ;
}
width = size [ 0 ] ;
height = size [ 1 ] ;
} else {
size [ 0 ] = width ;
size [ 1 ] = height ;
rc = screen_set_window_property_iv ( screen_window , SCREEN_PROPERTY_SIZE , size ) ;
if ( rc ) {
printf ( " Cannot set window size! \n " ) ;
fflush ( stdout ) ;
exit ( EXIT_FAILURE ) ;
}
}
if ( screen_pos_set ) {
rc = screen_set_window_property_iv ( screen_window , SCREEN_PROPERTY_POSITION , screen_pos ) ;
if ( rc ) {
printf ( " Cannot set window position! \n " ) ;
fflush ( stdout ) ;
exit ( EXIT_FAILURE ) ;
}
}
if ( screen_pipeline_set ) {
rc = screen_set_window_property_iv ( screen_window , SCREEN_PROPERTY_PIPELINE , & screen_pipeline ) ;
if ( rc ) {
printf ( " Cannot set pipeline id! \n " ) ;
fflush ( stdout ) ;
exit ( EXIT_FAILURE ) ;
}
}
if ( screen_zorder_set ) {
rc = screen_set_window_property_iv ( screen_window , SCREEN_PROPERTY_ZORDER , & screen_zorder ) ;
if ( rc ) {
printf ( " Cannot set z-order of the window! \n " ) ;
fflush ( stdout ) ;
exit ( EXIT_FAILURE ) ;
}
}
}
2021-04-27 13:52:27 +02:00
# else
void VulkanExampleBase : : setupWindow ( )
{
}
2016-02-16 15:07:25 +01:00
# endif
2017-04-22 16:02:39 +02:00
void VulkanExampleBase : : keyPressed ( uint32_t ) { }
2016-02-16 15:07:25 +01:00
2017-10-05 21:22:10 +02:00
void VulkanExampleBase : : mouseMoved ( double x , double y , bool & handled ) { }
2017-04-22 16:02:39 +02:00
void VulkanExampleBase : : buildCommandBuffers ( ) { }
2016-04-10 11:12:04 +02:00
2018-06-03 09:38:14 +02:00
void VulkanExampleBase : : createSynchronizationPrimitives ( )
{
// Wait fences to sync command buffer access
VkFenceCreateInfo fenceCreateInfo = vks : : initializers : : fenceCreateInfo ( VK_FENCE_CREATE_SIGNALED_BIT ) ;
waitFences . resize ( drawCmdBuffers . size ( ) ) ;
for ( auto & fence : waitFences ) {
VK_CHECK_RESULT ( vkCreateFence ( device , & fenceCreateInfo , nullptr , & fence ) ) ;
}
}
2016-02-16 15:07:25 +01:00
void VulkanExampleBase : : createCommandPool ( )
{
VkCommandPoolCreateInfo cmdPoolInfo = { } ;
cmdPoolInfo . sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO ;
cmdPoolInfo . queueFamilyIndex = swapChain . queueNodeIndex ;
cmdPoolInfo . flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT ;
2016-05-22 20:27:06 +02:00
VK_CHECK_RESULT ( vkCreateCommandPool ( device , & cmdPoolInfo , nullptr , & cmdPool ) ) ;
2016-02-16 15:07:25 +01:00
}
void VulkanExampleBase : : setupDepthStencil ( )
{
2019-02-20 19:56:42 +01:00
VkImageCreateInfo imageCI { } ;
imageCI . sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO ;
imageCI . imageType = VK_IMAGE_TYPE_2D ;
imageCI . format = depthFormat ;
imageCI . extent = { width , height , 1 } ;
imageCI . mipLevels = 1 ;
imageCI . arrayLayers = 1 ;
imageCI . samples = VK_SAMPLE_COUNT_1_BIT ;
imageCI . tiling = VK_IMAGE_TILING_OPTIMAL ;
2020-01-24 09:39:44 +01:00
imageCI . usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT ;
2019-02-20 19:56:42 +01:00
VK_CHECK_RESULT ( vkCreateImage ( device , & imageCI , nullptr , & depthStencil . image ) ) ;
VkMemoryRequirements memReqs { } ;
2016-02-16 15:07:25 +01:00
vkGetImageMemoryRequirements ( device , depthStencil . image , & memReqs ) ;
2019-02-20 19:56:42 +01:00
VkMemoryAllocateInfo memAllloc { } ;
memAllloc . sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO ;
memAllloc . allocationSize = memReqs . size ;
memAllloc . memoryTypeIndex = vulkanDevice - > getMemoryType ( memReqs . memoryTypeBits , VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT ) ;
2024-03-19 21:51:27 +01:00
VK_CHECK_RESULT ( vkAllocateMemory ( device , & memAllloc , nullptr , & depthStencil . memory ) ) ;
VK_CHECK_RESULT ( vkBindImageMemory ( device , depthStencil . image , depthStencil . memory , 0 ) ) ;
2016-02-16 15:07:25 +01:00
2019-02-20 19:56:42 +01:00
VkImageViewCreateInfo imageViewCI { } ;
imageViewCI . sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO ;
imageViewCI . viewType = VK_IMAGE_VIEW_TYPE_2D ;
imageViewCI . image = depthStencil . image ;
imageViewCI . format = depthFormat ;
imageViewCI . subresourceRange . baseMipLevel = 0 ;
imageViewCI . subresourceRange . levelCount = 1 ;
imageViewCI . subresourceRange . baseArrayLayer = 0 ;
imageViewCI . subresourceRange . layerCount = 1 ;
imageViewCI . subresourceRange . aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT ;
// Stencil aspect should only be set on depth + stencil formats (VK_FORMAT_D16_UNORM_S8_UINT..VK_FORMAT_D32_SFLOAT_S8_UINT
if ( depthFormat > = VK_FORMAT_D16_UNORM_S8_UINT ) {
imageViewCI . subresourceRange . aspectMask | = VK_IMAGE_ASPECT_STENCIL_BIT ;
}
VK_CHECK_RESULT ( vkCreateImageView ( device , & imageViewCI , nullptr , & depthStencil . view ) ) ;
2016-02-16 15:07:25 +01:00
}
void VulkanExampleBase : : setupFrameBuffer ( )
{
// Create frame buffers for every swap chain image
2024-12-19 21:29:22 +01:00
frameBuffers . resize ( swapChain . images . size ( ) ) ;
2016-02-16 15:07:25 +01:00
for ( uint32_t i = 0 ; i < frameBuffers . size ( ) ; i + + )
{
2024-11-23 15:37:57 +01:00
const VkImageView attachments [ 2 ] = {
2024-12-19 21:29:22 +01:00
swapChain . imageViews [ i ] ,
2024-11-23 15:37:57 +01:00
// Depth/Stencil attachment is the same for all frame buffers
depthStencil . view
} ;
VkFramebufferCreateInfo frameBufferCreateInfo { } ;
frameBufferCreateInfo . sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO ;
frameBufferCreateInfo . renderPass = renderPass ;
frameBufferCreateInfo . attachmentCount = 2 ;
frameBufferCreateInfo . pAttachments = attachments ;
frameBufferCreateInfo . width = width ;
frameBufferCreateInfo . height = height ;
frameBufferCreateInfo . layers = 1 ;
2016-05-22 20:27:06 +02:00
VK_CHECK_RESULT ( vkCreateFramebuffer ( device , & frameBufferCreateInfo , nullptr , & frameBuffers [ i ] ) ) ;
2016-02-16 15:07:25 +01:00
}
}
void VulkanExampleBase : : setupRenderPass ( )
{
2016-08-10 20:39:01 +02:00
std : : array < VkAttachmentDescription , 2 > attachments = { } ;
2016-04-30 10:45:39 +02:00
// Color attachment
2017-01-25 18:54:09 +01:00
attachments [ 0 ] . format = swapChain . colorFormat ;
2016-02-16 15:07:25 +01:00
attachments [ 0 ] . samples = VK_SAMPLE_COUNT_1_BIT ;
attachments [ 0 ] . loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR ;
attachments [ 0 ] . storeOp = VK_ATTACHMENT_STORE_OP_STORE ;
attachments [ 0 ] . stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE ;
attachments [ 0 ] . stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE ;
2016-08-10 20:39:01 +02:00
attachments [ 0 ] . initialLayout = VK_IMAGE_LAYOUT_UNDEFINED ;
attachments [ 0 ] . finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR ;
2016-04-30 10:45:39 +02:00
// Depth attachment
2016-02-16 15:07:25 +01:00
attachments [ 1 ] . format = depthFormat ;
attachments [ 1 ] . samples = VK_SAMPLE_COUNT_1_BIT ;
attachments [ 1 ] . loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR ;
attachments [ 1 ] . storeOp = VK_ATTACHMENT_STORE_OP_STORE ;
2017-08-16 21:00:17 +02:00
attachments [ 1 ] . stencilLoadOp = VK_ATTACHMENT_LOAD_OP_CLEAR ;
2016-02-16 15:07:25 +01:00
attachments [ 1 ] . stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE ;
2016-08-10 20:39:01 +02:00
attachments [ 1 ] . initialLayout = VK_IMAGE_LAYOUT_UNDEFINED ;
2016-02-16 15:07:25 +01:00
attachments [ 1 ] . finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL ;
VkAttachmentReference colorReference = { } ;
colorReference . attachment = 0 ;
colorReference . layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL ;
VkAttachmentReference depthReference = { } ;
depthReference . attachment = 1 ;
depthReference . layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL ;
2016-08-10 20:39:01 +02:00
VkSubpassDescription subpassDescription = { } ;
subpassDescription . pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS ;
subpassDescription . colorAttachmentCount = 1 ;
subpassDescription . pColorAttachments = & colorReference ;
subpassDescription . pDepthStencilAttachment = & depthReference ;
subpassDescription . inputAttachmentCount = 0 ;
subpassDescription . pInputAttachments = nullptr ;
subpassDescription . preserveAttachmentCount = 0 ;
subpassDescription . pPreserveAttachments = nullptr ;
subpassDescription . pResolveAttachments = nullptr ;
// Subpass dependencies for layout transitions
2024-11-23 15:37:57 +01:00
std : : array < VkSubpassDependency , 2 > dependencies { } ;
2016-08-10 20:39:01 +02:00
dependencies [ 0 ] . srcSubpass = VK_SUBPASS_EXTERNAL ;
dependencies [ 0 ] . dstSubpass = 0 ;
2023-01-01 09:14:25 +01:00
dependencies [ 0 ] . srcStageMask = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT ;
dependencies [ 0 ] . dstStageMask = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT ;
dependencies [ 0 ] . srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT ;
dependencies [ 0 ] . dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT ;
2023-01-05 13:28:40 +01:00
dependencies [ 0 ] . dependencyFlags = 0 ;
2023-01-01 09:14:25 +01:00
dependencies [ 1 ] . srcSubpass = VK_SUBPASS_EXTERNAL ;
dependencies [ 1 ] . dstSubpass = 0 ;
2016-08-10 20:39:01 +02:00
dependencies [ 1 ] . srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT ;
2023-01-01 09:14:25 +01:00
dependencies [ 1 ] . dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT ;
dependencies [ 1 ] . srcAccessMask = 0 ;
dependencies [ 1 ] . dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT ;
2023-01-05 13:28:40 +01:00
dependencies [ 1 ] . dependencyFlags = 0 ;
2016-02-16 15:07:25 +01:00
VkRenderPassCreateInfo renderPassInfo = { } ;
renderPassInfo . sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO ;
2016-08-10 20:39:01 +02:00
renderPassInfo . attachmentCount = static_cast < uint32_t > ( attachments . size ( ) ) ;
renderPassInfo . pAttachments = attachments . data ( ) ;
2016-02-16 15:07:25 +01:00
renderPassInfo . subpassCount = 1 ;
2016-08-10 20:39:01 +02:00
renderPassInfo . pSubpasses = & subpassDescription ;
renderPassInfo . dependencyCount = static_cast < uint32_t > ( dependencies . size ( ) ) ;
renderPassInfo . pDependencies = dependencies . data ( ) ;
2016-02-16 15:07:25 +01:00
2016-05-22 20:27:06 +02:00
VK_CHECK_RESULT ( vkCreateRenderPass ( device , & renderPassInfo , nullptr , & renderPass ) ) ;
2016-02-16 15:07:25 +01:00
}
2020-08-08 13:25:58 +02:00
void VulkanExampleBase : : getEnabledFeatures ( ) { }
2017-03-08 21:29:38 +01:00
2022-10-02 15:46:06 +02:00
void VulkanExampleBase : : getEnabledExtensions ( ) { }
2016-04-10 11:12:04 +02:00
void VulkanExampleBase : : windowResize ( )
{
if ( ! prepared )
{
return ;
}
prepared = false ;
2020-08-16 10:22:45 +02:00
resized = true ;
2016-04-10 11:12:04 +02:00
2017-02-04 15:58:46 +01:00
// Ensure all operations on the device have been finished before destroying resources
vkDeviceWaitIdle ( device ) ;
2016-04-10 11:12:04 +02:00
// Recreate swap chain
width = destWidth ;
height = destHeight ;
2024-11-30 21:21:07 +01:00
createSwapChain ( ) ;
2016-04-10 11:12:04 +02:00
// Recreate the frame buffers
vkDestroyImageView ( device , depthStencil . view , nullptr ) ;
vkDestroyImage ( device , depthStencil . image , nullptr ) ;
2024-03-19 21:51:27 +01:00
vkFreeMemory ( device , depthStencil . memory , nullptr ) ;
2020-05-29 16:08:53 +01:00
setupDepthStencil ( ) ;
2025-02-28 18:18:49 +01:00
for ( auto & frameBuffer : frameBuffers ) {
vkDestroyFramebuffer ( device , frameBuffer , nullptr ) ;
2016-04-10 11:12:04 +02:00
}
setupFrameBuffer ( ) ;
2018-08-29 20:49:13 +02:00
if ( ( width > 0.0f ) & & ( height > 0.0f ) ) {
if ( settings . overlay ) {
2024-05-23 21:56:42 +02:00
ui . resize ( width , height ) ;
2018-08-29 20:49:13 +02:00
}
}
2016-04-10 11:12:04 +02:00
// Command buffers need to be recreated as they may store
// references to the recreated frame buffer
destroyCommandBuffers ( ) ;
createCommandBuffers ( ) ;
buildCommandBuffers ( ) ;
2024-01-21 05:07:35 -08:00
2022-06-01 12:46:41 -04:00
// SRS - Recreate fences in case number of swapchain images has changed on resize
for ( auto & fence : waitFences ) {
vkDestroyFence ( device , fence , nullptr ) ;
}
createSynchronizationPrimitives ( ) ;
2016-04-10 11:12:04 +02:00
vkDeviceWaitIdle ( device ) ;
2018-06-30 21:56:23 +02:00
if ( ( width > 0.0f ) & & ( height > 0.0f ) ) {
camera . updateAspectRatio ( ( float ) width / ( float ) height ) ;
2016-05-15 18:31:31 +02:00
}
2016-04-10 11:12:04 +02:00
// Notify derived class
windowResized ( ) ;
prepared = true ;
}
2017-11-02 13:40:27 +01:00
void VulkanExampleBase : : handleMouseMove ( int32_t x , int32_t y )
{
2024-03-20 07:49:06 +01:00
int32_t dx = ( int32_t ) mouseState . position . x - x ;
int32_t dy = ( int32_t ) mouseState . position . y - y ;
2017-11-02 13:40:27 +01:00
bool handled = false ;
if ( settings . overlay ) {
ImGuiIO & io = ImGui : : GetIO ( ) ;
2024-05-23 21:56:42 +02:00
handled = io . WantCaptureMouse & & ui . visible ;
2017-11-02 13:40:27 +01:00
}
mouseMoved ( ( float ) x , ( float ) y , handled ) ;
if ( handled ) {
2024-03-20 07:49:06 +01:00
mouseState . position = glm : : vec2 ( ( float ) x , ( float ) y ) ;
2017-11-02 13:40:27 +01:00
return ;
}
2024-03-20 07:49:06 +01:00
if ( mouseState . buttons . left ) {
2017-11-02 13:40:27 +01:00
camera . rotate ( glm : : vec3 ( dy * camera . rotationSpeed , - dx * camera . rotationSpeed , 0.0f ) ) ;
viewUpdated = true ;
}
2024-03-20 07:49:06 +01:00
if ( mouseState . buttons . right ) {
2020-04-22 20:58:24 +02:00
camera . translate ( glm : : vec3 ( - 0.0f , 0.0f , dy * .005f ) ) ;
2017-11-02 13:40:27 +01:00
viewUpdated = true ;
}
2024-03-20 07:49:06 +01:00
if ( mouseState . buttons . middle ) {
2022-05-13 11:58:46 -04:00
camera . translate ( glm : : vec3 ( - dx * 0.005f , - dy * 0.005f , 0.0f ) ) ;
2017-11-02 13:40:27 +01:00
viewUpdated = true ;
}
2024-03-20 07:49:06 +01:00
mouseState . position = glm : : vec2 ( ( float ) x , ( float ) y ) ;
2017-11-02 13:40:27 +01:00
}
2020-08-08 13:25:58 +02:00
void VulkanExampleBase : : windowResized ( ) { }
2016-04-10 11:12:04 +02:00
2024-11-30 21:21:07 +01:00
void VulkanExampleBase : : createSurface ( )
2016-02-16 15:07:25 +01:00
{
2016-03-20 14:55:46 +01:00
# if defined(_WIN32)
2016-02-23 21:55:37 +01:00
swapChain . initSurface ( windowInstance , window ) ;
2020-05-29 16:08:53 +01:00
# elif defined(VK_USE_PLATFORM_ANDROID_KHR)
2016-03-20 15:45:40 +01:00
swapChain . initSurface ( androidApp - > window ) ;
2017-04-14 12:00:05 -04:00
# elif (defined(VK_USE_PLATFORM_IOS_MVK) || defined(VK_USE_PLATFORM_MACOS_MVK))
2017-07-29 19:31:00 +02:00
swapChain . initSurface ( view ) ;
2024-05-04 07:53:08 -04:00
# elif defined(VK_USE_PLATFORM_METAL_EXT)
swapChain . initSurface ( metalLayer ) ;
2020-09-13 10:12:33 +02:00
# elif defined(VK_USE_PLATFORM_DIRECTFB_EXT)
swapChain . initSurface ( dfb , surface ) ;
2017-02-02 08:54:56 +00:00
# elif defined(VK_USE_PLATFORM_WAYLAND_KHR)
swapChain . initSurface ( display , surface ) ;
2017-08-13 10:24:25 +02:00
# elif defined(VK_USE_PLATFORM_XCB_KHR)
2016-02-23 21:55:37 +01:00
swapChain . initSurface ( connection , window ) ;
2021-04-27 13:52:27 +02:00
# elif (defined(_DIRECT2DISPLAY) || defined(VK_USE_PLATFORM_HEADLESS_EXT))
swapChain . initSurface ( width , height ) ;
2023-09-01 11:12:08 -04:00
# elif defined(VK_USE_PLATFORM_SCREEN_QNX)
swapChain . initSurface ( screen_context , screen_window ) ;
2016-02-16 15:07:25 +01:00
# endif
}
2024-11-30 21:21:07 +01:00
void VulkanExampleBase : : createSwapChain ( )
2016-02-16 15:07:25 +01:00
{
2024-12-19 21:29:22 +01:00
swapChain . create ( width , height , settings . vsync , settings . fullscreen ) ;
2016-02-16 15:07:25 +01:00
}
2017-10-29 11:41:43 +01:00
2020-08-24 08:01:23 +02:00
void VulkanExampleBase : : OnUpdateUIOverlay ( vks : : UIOverlay * overlay ) { }
2023-02-25 09:37:08 +01:00
# if defined(_WIN32)
void VulkanExampleBase : : OnHandleMessage ( HWND hWnd , UINT uMsg , WPARAM wParam , LPARAM lParam ) { } ;
# endif