[
  {
    "path": ".github/FUNDING.yml",
    "content": "# These are supported funding model platforms\n\ngithub: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]\npatreon: # Replace with a single Patreon username\nopen_collective: # Replace with a single Open Collective username\nko_fi: # Replace with a single Ko-fi username\ntidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel\ncommunity_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry\nliberapay: # Replace with a single Liberapay username\nissuehunt: # Replace with a single IssueHunt username\notechie: # Replace with a single Otechie username\ncustom: ['https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=6NRLHTNEP8GH8&item_name=For+Petr+Kraus+%28aka+krOoze%29+if+you+appreciate+any+of+my+work+done+for+free.&currency_code=USD&source=url', 'https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=6NRLHTNEP8GH8&item_name=For+Petr+Kraus+%28aka+krOoze%29+if+you+appreciate+any+of+my+work+done+for+free.&currency_code=EUR&source=url']\n"
  },
  {
    "path": ".github/workflows/buildCI.yml",
    "content": "name: build CI\n\non:\n  push:\n    branches: [ '*' ]\n  pull_request:\n    branches: [ master ]\n  workflow_dispatch:\n\njobs:\n  Win_jorb:\n    runs-on: windows-latest\n    strategy:\n      matrix:\n        build_config: ['Debug', 'Release']\n        arch: ['x64', 'Win32']\n    defaults:\n      run:\n        shell: cmd\n    env:\n      VULKAN_SDK: ${{ github.workspace }}\\VulkanSDK\n\n    steps:\n    - uses: actions/checkout@v2\n      with:\n        repository: 'krOoze/vk_sdk_lite'\n        path: ${{ env.VULKAN_SDK }}\n        ref: windows\n        persist-credentials: false\n    - uses: actions/checkout@v2\n      with:\n        path: 'source'\n        submodules: 'recursive'\n        persist-credentials: false\n    - run: md source\\build\n    - run: cmake -G \"Visual Studio 16 2019\" -A ${{ matrix.arch }} ..\n      working-directory: source\\build\n    - run: cmake --build . --config ${{ matrix.build_config }}\n      working-directory: source\\build\n    - uses: actions/upload-artifact@v1\n      with:\n        name: Hello Vulkan Triangle -- Windows ${{ matrix.build_config }}\n        path: source\\build\\${{ matrix.build_config }}\\HelloTriangle.exe\n\n  linux_jorb:\n    if: endsWith( github.ref, 'dxgi_interop' ) == false\n    runs-on: ubuntu-latest\n    strategy:\n      matrix:\n        build_config: ['Debug', 'Release']\n    defaults:\n      run:\n        shell: bash\n    env:\n      VULKAN_SDK: ${{ github.workspace }}/VulkanSDK/x86_64\n\n    steps:\n    - uses: actions/checkout@v2\n      with:\n        repository: 'krOoze/vk_sdk_lite'\n        path: 'VulkanSDK'\n        ref: linux\n        persist-credentials: false\n    - run: echo \"${{ env.VULKAN_SDK }}/bin\" >> $GITHUB_PATH\n    - run: sudo apt update && sudo apt install xorg-dev\n    - uses: actions/checkout@v2\n      with:\n        path: 'source'\n        submodules: 'recursive'\n        persist-credentials: false\n    - run: mkdir -p source/build\n    - run: cmake -DCMAKE_BUILD_TYPE=${{ matrix.build_config }} -G \"Unix Makefiles\" ..\n      working-directory: source/build\n    - run: cmake --build .\n      working-directory: source/build\n    - uses: actions/upload-artifact@v1\n      with:\n        name: Hello Vulkan Triangle App -- Linux ${{ matrix.build_config }}\n        path: source/build/HelloTriangle\n\n  mac_jorb:\n    if: endsWith( github.ref, 'dxgi_interop' ) == false\n    runs-on: macos-latest\n    strategy:\n      matrix:\n        build_config: ['Debug', 'Release']\n    defaults:\n      run:\n        shell: bash\n    env:\n      VULKAN_SDK: ${{ github.workspace }}/VulkanSDK/macOS\n\n    steps:\n    - uses: actions/checkout@v2\n      with:\n        repository: 'krOoze/vk_sdk_lite'\n        path: 'VulkanSDK'\n        ref: macos\n        persist-credentials: false\n    - run: echo \"${{ env.VULKAN_SDK }}/bin\" >> $GITHUB_PATH\n    - uses: actions/checkout@v2\n      with:\n        path: 'source'\n        submodules: 'recursive'\n        persist-credentials: false\n    - run: mkdir -p source/build\n    - run: cmake -DCMAKE_BUILD_TYPE=${{ matrix.build_config }} ..\n      working-directory: source/build\n    - run: cmake --build .\n      working-directory: source/build\n    - uses: actions/upload-artifact@v1\n      with:\n        name: Hello Vulkan Triangle App -- macOS ${{ matrix.build_config }}\n        path: source/build/HelloTriangle\n"
  },
  {
    "path": ".gitignore",
    "content": "#CMake\r\n/CMakeCache.txt\r\n/CMakeFiles/\r\n/cmake_install.cmake\r\n\r\n#Visual Studio\r\n/.vs/\r\n/*.sln\r\n/*.vcxproj\r\n/*.vcxproj.filters\r\n/*.vcxproj.user\r\n/HelloTriangle.dir/\r\n/Debug/\r\n/Release/\r\n/Win32/\r\n/x64/\r\n\r\n\r\n#linux\r\n/Makefile\r\n\r\n#autogenerated shaders\r\n**/*.spv.inl\r\n\r\n#output\r\n/*.exe\r\n/HelloTriangle\r\n/build/\r\n/build32/\r\n/build64/\r\n/out/"
  },
  {
    "path": ".gitmodules",
    "content": "[submodule \"glfw\"]\n\tpath = external/glfw\n\turl = https://github.com/glfw/glfw.git\n"
  },
  {
    "path": "CMakeLists.txt",
    "content": "cmake_minimum_required( VERSION 3.5.1 )\r\nproject( HelloTriangle )\r\n\r\nset( TODO ON CACHE BOOL \"Enable compiletime TODO messages\" )\r\n\r\n# Select WSI platform (can use cmake -D)\r\nset( WSI \"USE_PLATFORM_GLFW\" CACHE STRING \"WSI type used by this app\" )\r\nmessage( \"WSI: \" ${WSI} )\r\n\r\n# Find Vulkan SDK\r\nif( NOT DEFINED {VULKAN_SDK} )\r\n\tif( NOT DEFINED ENV{VULKAN_SDK} )\r\n\t\tmessage( FATAL_ERROR \"VULKAN_SDK not found!\" )\r\n\tendif()\r\n\r\n\tif( CYGWIN )\r\n\t\texecute_process( COMMAND cygpath \"$ENV{VULKAN_SDK}\" OUTPUT_VARIABLE VULKAN_SDK )\r\n\t\tstring( STRIP ${VULKAN_SDK} VULKAN_SDK )\r\n\telse()\r\n\t\tset( VULKAN_SDK \"$ENV{VULKAN_SDK}\" )\r\n\tendif()\r\nendif()\r\nmessage( \"Vulkan SDK path: \" ${VULKAN_SDK} )\r\n\r\n# Compile shaders\r\nset( GLSL_DEBUG_FLAG $<$<CONFIG:Debug>:-g> )\r\nset( GLSL_COMPILER ${VULKAN_SDK}/bin/glslc -mfmt=num ${GLSL_DEBUG_FLAG} )\r\n\r\nset(VERT_SHADER \"${CMAKE_SOURCE_DIR}/src/shaders/hello_triangle.vert\")\r\nset(VERT_SHADER_INCLUDE ${VERT_SHADER}.spv.inl)\r\nadd_custom_command(\r\n\tCOMMENT \"Compiling vertex shader\"\r\n\tMAIN_DEPENDENCY ${VERT_SHADER}\r\n\tOUTPUT ${VERT_SHADER_INCLUDE}\r\n\tCOMMAND ${GLSL_COMPILER} -o ${VERT_SHADER_INCLUDE} ${VERT_SHADER}\r\n\t#VERBATIM -- TODO breaks empty generator-expression\r\n)\r\n\r\nset(FRAG_SHADER \"${CMAKE_SOURCE_DIR}/src/shaders/hello_triangle.frag\")\r\nset(FRAG_SHADER_INCLUDE ${FRAG_SHADER}.spv.inl)\r\nadd_custom_command(\r\n\tCOMMENT \"Compiling fragment shader\"\r\n\tMAIN_DEPENDENCY ${FRAG_SHADER}\r\n\tOUTPUT ${FRAG_SHADER_INCLUDE}\r\n\tCOMMAND ${GLSL_COMPILER} -o ${FRAG_SHADER_INCLUDE} ${FRAG_SHADER}\r\n\t#VERBATIM -- TODO breaks empty generator-expression\r\n)\r\n\r\nadd_custom_target(\r\n\tHelloTriangle_shaders\r\n\tCOMMENT \"Compiling shaders\"\r\n\tDEPENDS ${VERT_SHADER_INCLUDE} ${FRAG_SHADER_INCLUDE}\r\n)\r\n\r\n# Build GLFW\r\nif( ${WSI} STREQUAL \"USE_PLATFORM_GLFW\" )\r\n\tset( GLFW_BUILD_DOCS OFF CACHE BOOL \"\" FORCE )\r\n\tset( GLFW_BUILD_TESTS OFF CACHE BOOL \"\" FORCE )\r\n\tset( GLFW_BUILD_EXAMPLES OFF CACHE BOOL \"\" FORCE )\r\n\r\n\tif( CYGWIN )\r\n\t\t# Hack to make GLFW use Win32 WSI instead of X11\r\n\t\t# TODO: Might be cleaner to use cross-compiling\r\n\t\tunset( UNIX )\r\n\t\tset( WIN32 1 )\r\n\tendif()\r\n\r\n\tadd_subdirectory( external/glfw )\r\nendif()\r\n\r\n# HelloTriangle binary\r\nset_property( DIRECTORY PROPERTY VS_STARTUP_PROJECT HelloTriangle )\r\nfile(GLOB SOURCE_HEADERS \"src/*.h\" \"src/WSI/*.h\")\r\nadd_executable( HelloTriangle WIN32 src/HelloTriangle.cpp ${SOURCE_HEADERS} )\r\nadd_dependencies( HelloTriangle HelloTriangle_shaders )\r\n\r\nif( NOT TODO )\r\n\tadd_definitions( -DNO_TODO )\r\nendif()\r\n\r\nif( MSVC )\r\n\ttarget_compile_definitions( HelloTriangle PRIVATE $<$<CONFIG:Debug>:_CONSOLE> )\r\n\tset_target_properties( HelloTriangle PROPERTIES LINK_FLAGS_DEBUG \"/SUBSYSTEM:CONSOLE\" )\r\nendif()\r\n\r\nif(\"${CMAKE_VERSION}\" VERSION_LESS 3.8.2)\r\n\tset_target_properties(\r\n\t\tHelloTriangle\r\n\t\tPROPERTIES\r\n\t\t\tCXX_STANDARD 14\r\n\t\t\tCXX_STANDARD_REQUIRED YES\r\n\t\t\tCXX_EXTENSIONS NO\r\n\t)\r\nelse()\r\n\ttarget_compile_features( HelloTriangle PRIVATE cxx_std_14 )\r\nendif()\r\n\r\nfind_path(\r\n\tVULKAN_INCLUDE vulkan/vulkan.h\r\n\tPATHS \"${VULKAN_SDK}/Include\" \"${VULKAN_SDK}/include\"\r\n\tNO_DEFAULT_PATH\r\n)\r\nmessage( \"Vulkan include dir: \" ${VULKAN_INCLUDE} )\r\ninclude_directories( \"${VULKAN_INCLUDE}\" \"src/\" \"src/WSI/\" )\r\n\r\nif( CYGWIN )\r\n\tset( CMAKE_FIND_LIBRARY_PREFIXES \"\" )\r\n\tset( CMAKE_FIND_LIBRARY_SUFFIXES \".lib\" \".dll\" )\r\nendif()\r\n\r\nif(CMAKE_SIZEOF_VOID_P EQUAL 8)\r\n\tset(VULKAN_LIBRARY_DIRS \"${VULKAN_SDK}/lib\" \"${VULKAN_SDK}/Lib\")\r\nelseif(CMAKE_SIZEOF_VOID_P EQUAL 4)\r\n\tset(VULKAN_LIBRARY_DIRS \"${VULKAN_SDK}/Lib32\")\r\nendif()\r\nfind_library(\r\n\tVULKAN_LIBRARY\r\n\tNAMES vulkan vulkan-1\r\n\tPATHS ${VULKAN_LIBRARY_DIRS}\r\n\tNO_DEFAULT_PATH\r\n)\r\nmessage( \"Vulkan libs: \" ${VULKAN_LIBRARY} )\r\n\r\nif( ${WSI} STREQUAL \"USE_PLATFORM_GLFW\" )\r\n\tset( WSI_LIBS glfw )\r\nelseif( ${WSI} STREQUAL \"VK_USE_PLATFORM_WIN32_KHR\" )\r\n\tset( WSI_LIBS )\r\n\tadd_definitions( -DUNICODE )\r\nelseif( ${WSI} STREQUAL \"VK_USE_PLATFORM_XLIB_KHR\" )\r\n\tset( WSI_LIBS X11 )\r\nelseif( ${WSI} STREQUAL \"VK_USE_PLATFORM_XCB_KHR\" )\r\n\tset( WSI_LIBS xcb xcb-keysyms )\r\nelseif( ${WSI} STREQUAL \"VK_USE_PLATFORM_WAYLAND_KHR\" )\r\n\tset( WSI_LIBS wayland-client xkbcommon )\r\nendif()\r\nadd_definitions( -D${WSI} )\r\n\r\ntarget_link_libraries( HelloTriangle \"${VULKAN_LIBRARY}\" \"${WSI_LIBS}\" )\r\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "Contributions to this project are welcome.\n\nCopyright\n---------\nThis project is meant as an educational source without any strings attached to the learner (read [LICENSE](LICENSE)). All contributions are made under the same lincense.\n\nIssues\n------\nCatching bugs is important and so your Issue reports are very welcome.\n\n- Issues about specific bugs in the source code should contain specification rule quote it violates.\n- Other kinds of issues should contain info about OS, driver version, used Vulkan SDK and the output from validation layers.\n- Relevant questions are also welcome as long as the trafic is low.\n- New feature suggestions are pointless, unless you are willing to implement them yourself\n\nProject goals and conventions\n------------------------\nThis project aims to be a starting point in learning Vulkan API. It aims at people that are bad with tutorials. It tries not to insult the readers inteligence; it tries to do things the right/hard way and it tries not to hide things from the reader. Vulkan is a learning staircase; this is above all meant to be the first stair.\n\n- Assume the reader has only vague idea about how Vulkan works. Show the actual commands; do not abstract too much. It should be readable even outsite an IDE.\n  - There is a flat 2 level design. The top level shows the stream of actions using Vulkan terminology (strongly hinting at what Vulkan commands will be used). The second level contains the verbose Vulkan stuff (setting `CreateInfo`s and such).\n  - Assume reader has some computer graphics knowledge; show specific Vulkan features, not effects or algorithms.\n- The code must be valid and reasonably optimal Vulkan code. This requires carefully reading the [Vulkan specification](https://www.khronos.org/registry/vulkan/specs/1.0-extensions/html/vkspec.html) itself.\n  - Suboptimal constructs (like `vkDeviceWaitIdle`s, or suboptimally set barriers) should be avoided.\n- The code must not be platform dependent (unless it shows a specific non-universally supported feature).\n- For now examples showing additional Vulkan features are kept as a diff (git branch) to the `master` (which represents the simplest viable Vulkan app). This is to allow easy comparison.\n\nPull requests\n-------------\nPull requests following the conventions above are welcome.\n\nBuilding should be straightforward and is outlined in [README.md](README.md).\n\nIf you need a new Branch just PR against `master`. It should be changeable later when new branch is created.\n"
  },
  {
    "path": "LICENSE",
    "content": "This is free and unencumbered software released into the public domain.\n\nAnyone is free to copy, modify, publish, use, compile, sell, or\ndistribute this software, either in source code form or as a compiled\nbinary, for any purpose, commercial or non-commercial, and by any\nmeans.\n\nIn jurisdictions that recognize copyright laws, the author or authors\nof this software dedicate any and all copyright interest in the\nsoftware to the public domain. We make this dedication for the benefit\nof the public at large and to the detriment of our heirs and\nsuccessors. We intend this dedication to be an overt act of\nrelinquishment in perpetuity of all present and future rights to this\nsoftware under copyright law.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\nIN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR\nOTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,\nARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR\nOTHER DEALINGS IN THE SOFTWARE.\n\nFor more information, please refer to <https://unlicense.org>\n"
  },
  {
    "path": "README.md",
    "content": "Hello Triangle Vulkan demo\r\n=========================\r\n\r\nThis is a traditional Hello World style application for the Vulkan API. It\r\nrenders a RGB shaded equilateral triangle (well, if the resolution is a square).\r\n\r\nThe code is relatively flat and basic, so I think it's good enough for learning.\r\nNo tutorial or even much comments are provided though (comments do lie anyway\r\n:smirk:). Though some things I found noteworthy are in the `doc/` folder.\r\n\r\nMy goal here is to be perfectly conformant to the Vulkan specification. Also I\r\ndo handle all the Vulkan `VkResult`s (with app termination though). And I try to\r\ndo things in the efficient way, rather than simplify. But I am only human.\r\n:innocent:\r\n\r\nIf you appriciate any of my free work or help (e.g. hosting this), you can send\r\nme some sweet sweet money:\r\n\r\n<a href=\"https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=6NRLHTNEP8GH8&item_name=For+Petr+Kraus+%28aka+krOoze%29+if+you+appreciate+any+of+my+work+done+for+free.&currency_code=USD&source=url\">\r\n<img width=\"145\" height=\"30\" src=\"http://vulkan.hys.cz/donate.png\" alt=\"Donate $ to krOoze\" /></a>\r\n<a href=\"https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=6NRLHTNEP8GH8&item_name=For+Petr+Kraus+%28aka+krOoze%29+if+you+appreciate+any+of+my+work+done+for+free.&currency_code=EUR&source=url\">\r\n<img width=\"145\" height=\"30\" src=\"http://vulkan.hys.cz/donateEur.png\" alt=\"Donate € to krOoze\" /></a>\r\n\r\nBranches\r\n-----------------\r\n\r\nThe git branches demonstrate some basic Vulkan features which can be easily\r\ngrafted on this basic example (it is nice to see a diff of what exactly needs to\r\nbe changed to make it work). Their `README.md` should be edited to reflect the\r\nchanges.\r\n\r\n| branch | diff link | description |\r\n|---|---|---|\r\n| [master](https://github.com/krOoze/Hello_Triangle/tree/master)| -- | Your regular Hello Triangle app, and base for the others\r\n| [MSAA](https://github.com/krOoze/Hello_Triangle/tree/MSAA)  | [diff](https://github.com/krOoze/Hello_Triangle/compare/MSAA) | Antialiasing (i.e. Vulkan's multisample image resolve) |\r\n| [queue_transfer](https://github.com/krOoze/Hello_Triangle/tree/queue_transfer) | [diff](https://github.com/krOoze/Hello_Triangle/compare/queue_transfer) | Transfer of `EXCLUSIVE` image between queue families (separate graphics and compute queue family) |\r\n| [vertex_offset](https://github.com/krOoze/Hello_Triangle/tree/vertex_offset) | [diff](https://github.com/krOoze/Hello_Triangle/compare/vertex_offset) | Demonstrates how offset in `vkCmdBindVertexBuffers()` works |\r\n| [dxgi_interop](https://github.com/krOoze/Hello_Triangle/tree/dxgi_interop) | [diff](https://github.com/krOoze/Hello_Triangle/compare/dxgi_interop) | An experiment that shows how to import swapchain images from DXGI (Direct3D 12 Swapchain) |\r\n\r\nRequirements\r\n----------------------------\r\n\r\n**OS**: Windows or Linux  \r\n**Language**: C++14  \r\n**Build environment**: (latest) [Vulkan SDK](https://vulkan.lunarg.com/sdk/home) (requires `VULKAN_SDK` variable being set)  \r\n**Build environment[Windows]**: Visual Studio, Cygwin, or MinGW (or IDEs running on top of them)  \r\n**Build environment[Linux]**: CMake compatible compiler and build system and `libxcb-dev` and `libxcb-keysyms-dev`  \r\n**Build environment[MacOS]**: CMake compatible compiler and build system  \r\n**Build Environment[GLFW]**: GLFW 3.2+ (already included as a git submodule), requires `xorg-dev` (or XCB) package on Linux  \r\n**Build environment[Xlib]**: Requires `xorg-dev` package  \r\n**Build environment[XCB]**: Requires `libxcb1-dev`, `libxcb-util-dev`, `libxcb-keysyms1-dev`, and `x11proto-dev` packages  \r\n**Build environment[Wayland]**: Requires `libwayland-dev` and `libxkbcommon-dev` packages  \r\n**Target Environment**: installed (latest) Vulkan capable drivers (to see anything)  \r\n**Target Environment**: GLFW(recommended), XCB, Xlib, or Wayland based windowing system\r\n\r\nOn Unix-like environment refer to\r\n[SDK docs](https://vulkan.lunarg.com/doc/sdk/latest/linux/getting_started.html)\r\non how to set `VULKAN_SDK` variable.\r\n\r\nAdding `VkSurface` support for other platforms should be straightforward using\r\nthe provided ones as a template for it.\r\n\r\nFiles\r\n----------------------------------\r\n\r\n| file | description |\r\n|---|---|\r\n| [doc/synchronizationTutorial.md](doc/synchronizationTutorial.md) | Short explanation of Vulkan synchronization in the context of trivial applications |\r\n| [doc/Schema.pdf](doc/Schema.pdf) | Bunch of diagrams explaining the app architecture and synchronization in a graphical form |\r\n| external/glfw/ | GLFW git submodule |\r\n| src/HelloTriangle.cpp | The app souce code, including the `main()` function |\r\n| src/CompilerMessages.h | Allows to make compile-time messages shown in the compiler output |\r\n| src/EnumerateScheme.h | A scheme to unify usage of most Vulkan `vkEnumerate*` and `vkGet*` commands |\r\n| src/ErrorHandling.h | `VkResult` check helpers + `VK_EXT_debug_utils` extension related stuff |\r\n| src/ExtensionLoader.h | Functions handling loading of select Vulkan extension commands |\r\n| src/LeanWindowsEnvironment.h | Included conditionally by `VulkanEnvironment.h` and includes lean `windows.h` header |\r\n| src/Vertex.h | Just simple Vertex definitions |\r\n| src/VulkanEnvironment.h | Contains header configuration, such platform-specific as `VK_USE_PLATFORM_*` |\r\n| src/VulkanIntrospection.h | Introspection of Vulkan entities; e.g. convert Vulkan enumerants to strings |\r\n| src/Wsi.h | Meta-header including one of the platform-specific headers in WSI directory |\r\n| src/WSI/Glfw.h | WSI platform-dependent stuff via GLFW3 library |\r\n| src/WSI/Win32.h | Win32 WSI platform-dependent stuff |\r\n| src/WSI/Xcb.h | XCB WSI platform-dependent stuff |\r\n| src/WSI/Xlib.h | Xlib WSI platform-dependent stuff |\r\n| src/WSI/Wayland.h | Wayland WSI platform-dependent stuff |\r\n| src/WSI/private/ | Stuff the WSI headers need; currently just generated Wayland protocols |\r\n| src/shaders/hello_triangle.vert | The vertex shader program in GLSL |\r\n| src/shaders/hello_triangle.frag | The fragment shader program in GLSL |\r\n| .gitignore | Git filter file ignoring most probable outputs messing up the local repo |\r\n| .gitmodules | Git submodules file describing the dependency on GLFW |\r\n| CMakeLists.txt | CMake makefile |\r\n| CONTRIBUTING.md | Extra info about contributing code, ideas, and bug reports |\r\n| LICENSE | Copyright licence for this project |\r\n| README.md | This file |\r\n\r\nConfig\r\n---------------------------------------\r\n\r\nYou can change the application configuration by simply changing following\r\nvariables in `HelloTriangle.cpp`.\r\n\r\n| config variable | purpose | default |\r\n|---|---|---|\r\n| `appName` | Application name; might show up in title of the window | whatever it is in code |\r\n| `debugSeverity` | Which kinds of debug message severites will be shown | `WARNING` \\| `ERROR` |\r\n| `debugType` | Which kinds of debug message types will be shown | all types |\r\n| `useAssistantLayer` | Enable Assistant Layer too when debugging (TODO: does not support new way of enabling) | `false` |\r\n| `fpsCounter` | Enable FPS counter via `VK_LAYER_LUNARG_monitor` layer | `true` |\r\n| `initialWindowWidth` | The initial width of the rendered window | `800` |\r\n| `initialWindowHeight` | The initial height of the rendered window | `800` |\r\n| `presentMode` | The presentation mode of Vulkan used in swapchain | `VK_PRESENT_MODE_FIFO_KHR` <sup>1</sup>|\r\n| `clearColor` | Background color of the rendering | gray (`{0.1f, 0.1f, 0.1f, 1.0f}`) |\r\n| `forceSeparatePresentQueue` | By default the app prioritizes single Graphics and Present queue. This will create separate queues for testing purposes. There are virtually no platforms currently that naturally have separate Present queue family. |\r\n\r\n<sup>1</sup> I preferred `VK_PRESENT_MODE_IMMEDIATE_KHR` before but it tends to\r\nmake coil whine because of the extreme FPS (which could be unnecessarily\r\ndangerous to the PCB in the long term).\r\n\r\nBuild\r\n----------------------------------------------\r\n\r\nFirst just get everything:\r\n\r\n    $ git clone --recurse-submodules https://github.com/krOoze/Hello_Triangle.git\r\n\r\nIn many platforms CMake style build should work just fine:\r\n\r\n    $ cmake -G\"Your preferred generator\"\r\n\r\nor even just\r\n\r\n    $ cmake .\r\n\r\nThen use `make`, or the generated Visual Studio `*.sln`, or whatever it created.\r\n\r\nThere are two cmake options (supplied by `-D`):\r\n - `WSI` -- set this to `USE_PLATFORM_GLFW` or any `VK_USE_PLATFORM_*_KHR` to\r\n    select the WSI to be used. Default is GLFW.\r\n - `TODO` -- set this to `OFF` to remove TODO messages during compilation.\r\n\r\nYou also might want to add `-DCMAKE_BUILD_TYPE=Debug`.\r\n\r\nManual Build\r\n----------------------------------------------\r\n\r\nThe code base is quite simple and it can be built manually. It only assumes that\r\nthe `src` folder is in the include path, that you link the GLFW dependency, and\r\nthat you compile the GLSL shader files into SPIR-V.\r\n\r\nIn Visual Studio you can simply import the code and add the things mentioned\r\nabove. Either \"console\" or \"window\" subsystem is a valid choice on Windows.\r\n\r\nIn Linux distro you would do e.g.:\r\n\r\n    $ g++ --std=c++14 -Wall -m64 -D_DEBUG -DNO_TODO -I$VULKAN_SDK/include -I./src/ -o./HelloTriangle src/HelloTriangle.cpp -ldl -L$VULKAN_SDK/lib -lvulkan -lglfw\r\n\r\nGLSL shaders can be compiled using `glslc` from LunarG Vulkan SDK like so:  \r\nOn Windows-like environment:\r\n\r\n    %VULKAN_SDK%/Bin/glslc -mfmt=c -o ./src/shaders/hello_triangle.vert.spv.inl ./src/shaders/hello_triangle.vert\r\n    %VULKAN_SDK%/Bin/glslc -mfmt=c -o ./src/shaders/hello_triangle.frag.spv.inl ./src/shaders/hello_triangle.frag\r\n\r\nOr on Unix-like environment you would use just `$VULKAN_SDK` instead:\r\n\r\n    $VULKAN_SDK/Bin/glslc -mfmt=c -o ./src/shaders/hello_triangle.vert.spv.inl ./src/shaders/hello_triangle.vert\r\n    $VULKAN_SDK/Bin/glslc -mfmt=c -o ./src/shaders/hello_triangle.frag.spv.inl ./src/shaders/hello_triangle.frag\r\n\r\nThere are annoying (on purpose) TODOs generated on build. They can be disabled\r\nby defining `NO_TODO` preprocessor macro.\r\n\r\nUsing GLFW is optional. You may choose another windowing platform by modifying\r\n`VulkanEnvironment.h`, or supplying it via preprocessor. By default, all\r\nplatforms use GLFW.\r\n\r\nRun\r\n------------------------\r\n\r\nYou just run it as you would anything else.\r\n\r\n<kbd>Esc</kbd> does terminate the app.  \r\n<kbd>Alt</kbd> + <kbd>Enter</kbd> toggles fullscreen (might not work on some WSI\r\nplatforms).\r\n"
  },
  {
    "path": "doc/synchronizationTutorial.md",
    "content": "up to [README.md](../README.md)\r\n\r\nQuick Tutorial of basic synchronization of typical renderloop\r\n-------------------------------------------------------------------\r\n\r\nYou will probably have two semaphors: e.g. `imageAcquired` and `renderingDone`.\r\n\r\n(You would need more `imageAcquired` semaphores to prevent `vkAcquireNextImage`\r\nto signal the same semaphore twice, but let's ignore this aspect for now.)\r\n\r\nLet's cover it in an order in which things should actually get\r\n**executed** (i.e. **not** necesserily in the order we called or recorded the\r\ncommands):\r\n\r\n1. You provide `imageAcquired` semaphore to the `vkAcquireNextImageKHR` to be\r\nsignalled by it.\r\n\r\n2. You provide `imageAcquired` semaphore to the command buffer submit to be\r\nwaited on. As a `pWaitDstStageMask` you provide the stage where your first write\r\naccess to the swapchain `VkImage` happens. Most often it will be\r\n`VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT` (but could be something different\r\nbased on your command buffer contents).\r\n\r\n3. In the command buffer you change the layout of the swapchain image \r\n(Subpasses, Pipeline Barriers, or Events can do that) **from** the present one (\r\nuse `VK_IMAGE_LAYOUT_UNDEFINED` as an old layout, which means \"sacrifice data\"\r\n&mdash; there's rarely ever need to read it after present ). For source stage\r\nchoose the exact same one as in step 2 and source access mask should be `0` (\r\nbecause memory dependency is already part of the previous semaphore wait). For\r\nefficient loop, destination stage should also be the same as in step 2 and the\r\nnew layout and destination access mask should be appropriate for whatever you\r\nplan to do (likely `VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL` and\r\n`VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT`).\r\n\r\n   In the case this is done with Render Pass (which should be the preferred\r\nmethod when we need to draw something), the first use of the `VkImage` would be\r\nthe automatic layout transition followed by `loadOp` you provided during creation.\r\nFor color attachment load operation does occur in the\r\n`VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT` stage (so providing that value as\r\n`dstStageMask` makes sure the layout transition does not clash with the load\r\noperation). Access mask depends on the `loadOp` value chosen.\r\n\r\n   The layout transition in render pass (and in Pipeline Barriers too) happens\r\nbetween `srcStageMask` and `dstStageMask` stages. So we do not need to worry\r\nabout it too much, assuming our barrier\\subpass dependency is otherwisely\r\ncorrect.\r\n\r\n4. You would write to your `VkImage`. Let's assume that is\r\ndone with a draw command like `vkCmdDraw` (which implies use of a Render Pass).\r\nNow the `loadOp` guarantees that it happens before our first use of an attachment\r\nin a render pass. So, no additional synchronization is needed here.\r\n\r\n5. In the command buffer you change the layout of the swapchain image \r\n(again Subpasses, Pipeline Barriers, or Events can do that) **to** the present\r\none (`VK_IMAGE_LAYOUT_PRESENT_SRC_KHR`). As your source stage, old layout and\r\nsource access mask choose whatever your last use of the swapchain image was.\r\nDestination stage should be `VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT` (i.e.\r\nnon-blocking, becose that is instead handled by folowing semaphore signal) and\r\nthe destination access mask should be `0`.\r\n\r\n   In the case of this being a render pass, first a `storeOp` happens after the\r\nlast use of your image in a render pass. Again that is guaranteed and needs no\r\nadditional synchronization to order these two. The Store Operation for color\r\nattachment happens in `VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT` stage and\r\nuses `VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT` access. The Store Operation is\r\nfollowed by the automatic layout transition to `finalLayout`. So, to prevent\r\n`storeOp` and this transition to clash, `srcStageMask` should be stage the Store\r\nOp happens (`VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT` as said above).\r\n\r\n6. You provide `renderingDone` semaphore to the command buffer submit to be\r\nsignalled.\r\n\r\n7. You provide `renderingDone` semaphore to the present command to be waited on.\r\n\r\n8. The circle is now complete! :mask:\r\n\r\n   From this it should be evident we are just declaring dependencies between\r\nmemory accesses (otherwisely Vulkan is allowed to mercilessly\r\noverlap execution of commands). When there is any kind of memory read or write,\r\nwe must make sure any previous write to the same location has finished.\r\nUsually, value used in `dstStageMask` subsequently appears in\r\nfollowing `srcStageMask` &mdash; so for a simple application it forms a nice\r\ndependency chain or path or lifetime of image that is not so hard to reason\r\nabout:\r\n\r\nImage Acquire  \r\n=> Semaphore Signal  \r\n=> Semaphore Unsignal in `VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT`  \r\n=> `srcStage=VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT` stage of Subpass Dependency\\Barrier  \r\n=> Layout Transition From Present Layout  \r\n=> `dstStage=VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT` stage of Subpass Dependency\\Barrier  \r\n=> Load Op (`VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT` stage) => (Implicit Dependency)  \r\n=> Draw (`VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT` stage again\\still)  \r\n=> (Implicit Dependency) => Store Op (`VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT` stage again\\still)  \r\n=> `srcStage` stage of Subpass Dependency\\Barrier  \r\n=> Layout Transition to Present Layout  \r\n=> `dstStage=VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT` stage of Subpass Dependency\\Barrier  \r\n=> Semaphore Signal  \r\n=> Semaphore Unsignal  \r\n=> Presenting\r\n\r\nFrom this diagram I can be sure the synchronization is correct:\r\n- The pipeline stage of previous and next step matches\r\n- or it is how the given primitive works (e.g. Semaphore wait does cover any\r\npreviously submitted semaphore signal)\r\n- or I am given (relatively rare) specification guarantee that things implicitly\r\nhappen in specific order (e.g. the Load Op vs first subpass attachment use)."
  },
  {
    "path": "src/CompilerMessages.h",
    "content": "// Allows to show messages during compilation -- somewhat platform dependent\r\n\r\n#ifndef COMMON_COMPILER_MESSAGES_H\r\n#define COMMON_COMPILER_MESSAGES_H\r\n\r\n\r\n// compiler messages -- should work in MSVC and GCC and is ignored by unsupporting compilers\r\n#define STRINGIZE_HELPER(x) #x\r\n#define STRINGIZE(x) STRINGIZE_HELPER(x)\r\n\r\n#ifdef NO_TODO\r\n\t#define TODO(desc) \r\n#else\r\n\r\n#if defined(_MSC_VER)\r\n\t#define TODO(desc) __pragma( message(__FILE__ \"(\" STRINGIZE(__LINE__) \")\" \": warning T: TODO: \"  desc) )\r\n#elif defined(__GNUG__)\r\n\t#define DO_PRAGMA(x) _Pragma (#x)\r\n\t#define TODO(desc) DO_PRAGMA(message \"TODO: \" desc)\r\n#else\r\n\t#define TODO(desc)\r\n#endif\r\n\r\n#endif // NO_TODO\r\n\r\n// usage:\r\n//TODO(\"Don't forget to do X.\")\r\n\r\n#endif //COMMON_COMPILER_MESSAGES_H"
  },
  {
    "path": "src/EnumerateScheme.h",
    "content": "// Scheme for the various vkGet* and vkEnumerate* commands\r\n//\r\n// Following the DRY principle, this implements getting a vector of enumerants\r\n// from the similar enumeration commands that return VK_INCOMPELTE.\r\n\r\n#ifndef COMMON_ENUMERATE_SCHEME_H\r\n#define COMMON_ENUMERATE_SCHEME_H\r\n\r\n#include <functional>\r\n#include <type_traits>\r\n#include <vector>\r\n\r\n#include <vulkan/vulkan.h>\r\n\r\n#include \"CompilerMessages.h\"\r\n#include \"ErrorHandling.h\"\r\n\r\n// the enumeration scheme\r\n// takes function VkResult cmd( uint32_t count, Element* pArray ) and Vulkan command name (for debugging purposes)\r\n// returns vector<Element> which contains the enumerants, or throws\r\ntemplate< typename Element, typename Cmd >\r\nstd::vector<Element> enumerateScheme( Cmd cmd, const char* cmdName ){\r\n\tstd::vector<Element> enumerants;\r\n\r\n\tVkResult errorCode;\r\n\tuint32_t enumerantsCount;\r\n\r\n\t// repeat until complete array is returned, or error\r\n\tdo{\r\n\t\terrorCode = cmd( &enumerantsCount, nullptr ); RESULT_HANDLER( errorCode, cmdName ); // get current array size\r\n\r\n\t\tenumerants.resize( enumerantsCount );\r\n\t\terrorCode = cmd( &enumerantsCount, enumerants.data() ); // get current array up to enumerantsCount\r\n\t} while( errorCode == VK_INCOMPLETE );\r\n\r\n\tRESULT_HANDLER( errorCode, cmdName );\r\n\r\n\tenumerants.resize( enumerantsCount ); // shrink in case of enumerantsCount1 > enumerantsCount2\r\n\tenumerants.shrink_to_fit(); // unlikely the vector will grow from this point on anyway\r\n\r\n\treturn enumerants;\r\n}\r\n\r\n\r\n// Adapters for specific Vulkan commands\r\n///////////////////////////////////////////////\r\n\r\ntemplate< typename Element, typename... Ts, typename = std::enable_if_t<!std::is_same<Element, VkInstance>::value>  >\r\nstd::vector<Element> enumerate( Ts... );\r\n\r\n// Tag will be VkInstance if to disambiguate commands that also work on device\r\ntemplate< typename Tag, typename Element, typename... Ts, typename = std::enable_if_t<std::is_same<Tag, VkInstance>::value> >\r\nstd::vector<Element> enumerate( Ts... );\r\n\r\n// for vkEnumerateInstanceLayerProperties -- auto v = enumerate<VkInstance, VkLayerProperties>();\r\ntemplate<>\r\nstd::vector<VkLayerProperties> enumerate<VkInstance, VkLayerProperties>(){\r\n\treturn enumerateScheme<VkLayerProperties>( vkEnumerateInstanceLayerProperties, \"vkEnumerateInstanceLayerProperties\" );\r\n}\r\n\r\n// for vkEnumerateDeviceLayerProperties -- auto v = enumerate<VkLayerProperties>( pd );\r\ntemplate<>\r\nstd::vector<VkLayerProperties> enumerate<VkLayerProperties, VkPhysicalDevice>( VkPhysicalDevice physicalDevice ){\r\n\tusing namespace std::placeholders;\r\n\tconst auto cmd = vkEnumerateDeviceLayerProperties;\r\n\tconst auto adapterCmd = std::bind( cmd, physicalDevice, _1, _2 );\r\n\r\n\treturn enumerateScheme<VkLayerProperties>( adapterCmd, \"vkEnumerateDeviceLayerProperties\" );\r\n}\r\n\r\n// for vkEnumerateInstanceExtensionProperties -- auto v = enumerate<VkInstance, VkExtensionProperties>( \"ln\" );\r\ntemplate<>\r\nstd::vector<VkExtensionProperties> enumerate<VkInstance, VkExtensionProperties, const char*>( const char* pLayerName ){\r\n\tusing namespace std::placeholders;\r\n\tconst auto cmd = vkEnumerateInstanceExtensionProperties;\r\n\tconst auto adapterCmd = std::bind( cmd, pLayerName, _1, _2 );\r\n\r\n\treturn enumerateScheme<VkExtensionProperties>( adapterCmd, \"vkEnumerateInstanceExtensionProperties\" );\r\n}\r\n\r\n// for vkEnumerateInstanceExtensionProperties with nullptr layer -- auto v = enumerate<VkInstance, VkExtensionProperties>();\r\ntemplate<>\r\nstd::vector<VkExtensionProperties> enumerate<VkInstance, VkExtensionProperties>(){\r\n\tusing namespace std::placeholders;\r\n\tconst auto cmd = vkEnumerateInstanceExtensionProperties;\r\n\tconst auto adapterCmd = std::bind( cmd, nullptr, _1, _2 );\r\n\r\n\treturn enumerateScheme<VkExtensionProperties>( adapterCmd, \"vkEnumerateInstanceExtensionProperties\" );\r\n}\r\n\r\n// for vkEnumerateDeviceExtensionProperties -- auto v = enumerate<VkExtensionProperties>( pd, \"ln\" );\r\ntemplate<>\r\nstd::vector<VkExtensionProperties> enumerate<VkExtensionProperties, VkPhysicalDevice, const char*>( VkPhysicalDevice physicalDevice, const char* pLayerName ){\r\n\tusing namespace std::placeholders;\r\n\tconst auto cmd = vkEnumerateDeviceExtensionProperties;\r\n\tconst auto adapterCmd = std::bind( cmd, physicalDevice, pLayerName, _1, _2 );\r\n\r\n\treturn enumerateScheme<VkExtensionProperties>( adapterCmd, \"vkEnumerateDeviceExtensionProperties\" );\r\n}\r\n\r\n// for vkEnumerateInstanceExtensionProperties with nullptr layer -- auto v = enumerate<VkExtensionProperties>( pd );\r\ntemplate<>\r\nstd::vector<VkExtensionProperties> enumerate<VkExtensionProperties, VkPhysicalDevice>( VkPhysicalDevice physicalDevice ){\r\n\tusing namespace std::placeholders;\r\n\tconst auto cmd = vkEnumerateDeviceExtensionProperties;\r\n\tconst auto adapterCmd = std::bind( cmd, physicalDevice, nullptr, _1, _2 );\r\n\r\n\treturn enumerateScheme<VkExtensionProperties>( adapterCmd, \"vkEnumerateDeviceExtensionProperties\" );\r\n}\r\n\r\n// for vkEnumeratePhysicalDevices -- auto v = enumerate<VkPhysicalDevice>( i );\r\ntemplate<>\r\nstd::vector<VkPhysicalDevice> enumerate<VkPhysicalDevice, VkInstance>( VkInstance instance ){\r\n\tusing namespace std::placeholders;\r\n\tconst auto cmd = vkEnumeratePhysicalDevices;\r\n\tconst auto adapterCmd = std::bind( cmd, instance, _1, _2 );\r\n\r\n\treturn enumerateScheme<VkPhysicalDevice>( adapterCmd, \"vkEnumeratePhysicalDevices\" );\r\n}\r\n\r\n// for vkGetPhysicalDeviceSurfaceFormatsKHR -- auto v = enumerate<VkSurfaceFormatKHR>( pd, s );\r\ntemplate<>\r\nstd::vector<VkSurfaceFormatKHR> enumerate<VkSurfaceFormatKHR, VkPhysicalDevice, VkSurfaceKHR>( VkPhysicalDevice physicalDevice, VkSurfaceKHR surface ){\r\n\tusing namespace std::placeholders;\r\n\tconst auto cmd = vkGetPhysicalDeviceSurfaceFormatsKHR;\r\n\tconst auto adapterCmd = std::bind( cmd, physicalDevice, surface, _1, _2 );\r\n\r\n\treturn enumerateScheme<VkSurfaceFormatKHR>( adapterCmd, \"vkGetPhysicalDeviceSurfaceFormatsKHR\" );\r\n}\r\n\r\n// for vkGetPhysicalDeviceSurfacePresentModesKHR -- auto v = enumerate<VkSurfaceFormatKHR>( pd, s );\r\ntemplate<>\r\nstd::vector<VkPresentModeKHR> enumerate<VkPresentModeKHR, VkPhysicalDevice, VkSurfaceKHR>( VkPhysicalDevice physicalDevice, VkSurfaceKHR surface ){\r\n\tusing namespace std::placeholders;\r\n\tconst auto cmd = vkGetPhysicalDeviceSurfacePresentModesKHR;\r\n\tconst auto adapterCmd = std::bind( cmd, physicalDevice, surface, _1, _2 );\r\n\r\n\treturn enumerateScheme<VkPresentModeKHR>( adapterCmd, \"vkGetPhysicalDeviceSurfacePresentModesKHR\" );\r\n}\r\n\r\n// for vkGetSwapchainImagesKHR -- auto v = enumerate<VkSurfaceFormatKHR>( d, s );\r\ntemplate<>\r\nstd::vector<VkImage> enumerate<VkImage, VkDevice, VkSwapchainKHR>( VkDevice device, VkSwapchainKHR swapchain ){\r\n\tusing namespace std::placeholders;\r\n\tconst auto cmd = vkGetSwapchainImagesKHR;\r\n\tconst auto adapterCmd = std::bind( cmd, device, swapchain, _1, _2 );\r\n\r\n\treturn enumerateScheme<VkImage>( adapterCmd, \"vkGetSwapchainImagesKHR\" );\r\n}\r\n\r\n// ... others to be added as needed\r\n\r\n#endif //COMMON_ENUMERATE_SCHEME_H"
  },
  {
    "path": "src/ErrorHandling.h",
    "content": "// Reusable error handling primitives for Vulkan\r\n\r\n#ifndef COMMON_ERROR_HANDLING_H\r\n#define COMMON_ERROR_HANDLING_H\r\n\r\n#include <iostream>\r\n#include <string>\r\n#include <sstream>\r\n\r\n#include <vulkan/vulkan.h>\r\n\r\n#include \"VulkanIntrospection.h\"\r\n\r\nstruct VulkanResultException{\r\n\tconst char* file;\r\n\tunsigned line;\r\n\tconst char* func;\r\n\tconst char* source;\r\n\tVkResult result;\r\n\r\n\tVulkanResultException( const char* file, unsigned line, const char* func, const char* source, VkResult result )\r\n\t: file( file ), line( line ), func( func ), source( source ), result( result ){}\r\n};\r\n\r\n#define RESULT_HANDLER( errorCode, source )  if( errorCode ) throw VulkanResultException( __FILE__, __LINE__, __func__, source, errorCode )\r\n#define RESULT_HANDLER_EX( cond, errorCode, source )  if( cond ) throw VulkanResultException( __FILE__, __LINE__, __func__, source, errorCode )\r\n\r\n#define RUNTIME_ASSERT( cond, source )  if( !(cond) ) throw source \" failed\";\r\n\r\n// just use cout for logging now\r\nstd::ostream& logger = std::cout;\r\n\r\nenum class Highlight{ off, on };\r\nvoid genericDebugCallback( std::string flags, Highlight highlight, std::string msgCode, std::string object, const char* message );\r\n\r\nVKAPI_ATTR VkBool32 VKAPI_CALL genericDebugReportCallback(\r\n\tVkDebugReportFlagsEXT msgFlags,\r\n\tVkDebugReportObjectTypeEXT objType,\r\n\tuint64_t srcObject,\r\n\tsize_t /*location*/,\r\n\tint32_t msgCode,\r\n\tconst char* pLayerPrefix,\r\n\tconst char* pMsg,\r\n\tvoid* /*pUserData*/\r\n);\r\n\r\nVKAPI_ATTR VkBool32 VKAPI_CALL genericDebugUtilsCallback(\r\n\tVkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,\r\n\tVkDebugUtilsMessageTypeFlagsEXT messageTypes,\r\n\tconst VkDebugUtilsMessengerCallbackDataEXT* pCallbackData,\r\n\tvoid* /*pUserData*/\r\n);\r\n\r\nenum class DebugObjectType{ debugReport, debugUtils } tag;\r\nstruct DebugObjectVariant{\r\n\tDebugObjectType tag;\r\n\tunion{\r\n\t\tVkDebugReportCallbackEXT debugReportCallback;\r\n\t\tVkDebugUtilsMessengerEXT debugUtilsMessenger;\r\n\t};\r\n};\r\n\r\nDebugObjectVariant initDebug( const VkInstance instance, const DebugObjectType debugExtension, const VkDebugUtilsMessageSeverityFlagsEXT debugSeverity, const VkDebugUtilsMessageTypeFlagsEXT debugType );\r\nvoid killDebug( VkInstance instance, DebugObjectVariant debug );\r\n\r\nVkDebugReportFlagsEXT translateFlags( const VkDebugUtilsMessageSeverityFlagsEXT debugSeverity, const VkDebugUtilsMessageTypeFlagsEXT debugType );\r\n\r\n// Implementation\r\n//////////////////////////////////\r\n\r\nvoid genericDebugCallback( std::string flags, Highlight highlight, std::string msgCode, std::string object, const char* message ){\r\n\tusing std::endl;\r\n\tusing std::string;\r\n\r\n\tconst string report = flags + \": \" + object + \": \" + msgCode + \", \\\"\" + message + '\"';\r\n\r\n\tif( highlight != Highlight::off ){\r\n\t\t\tconst string border( 80, '!' );\r\n\r\n\t\t\tlogger << border << endl;\r\n\t\t\tlogger << report << endl;\r\n\t\t\tlogger << border << endl << endl;\r\n\t}\r\n\telse{\r\n\t\tlogger << report << endl;\r\n\t}\r\n}\r\n\r\nVKAPI_ATTR VkBool32 VKAPI_CALL genericDebugReportCallback(\r\n\tVkDebugReportFlagsEXT flags,\r\n\tVkDebugReportObjectTypeEXT objectType,\r\n\tuint64_t object,\r\n\tsize_t /*location*/,\r\n\tint32_t messageCode,\r\n\tconst char* pLayerPrefix,\r\n\tconst char* pMessage,\r\n\tvoid* /*pUserData*/\r\n){\r\n\tusing std::to_string;\r\n\tusing std::string;\r\n\r\n\tHighlight highlight;\r\n\tif( (flags & VK_DEBUG_REPORT_ERROR_BIT_EXT) || (flags & VK_DEBUG_REPORT_WARNING_BIT_EXT) || (flags & VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT) ){\r\n\t\thighlight = Highlight::on;\r\n\t}\r\n\telse highlight = Highlight::off;\r\n\r\n\r\n\tgenericDebugCallback(  dbrflags_to_string( flags ), highlight, string(pLayerPrefix) + \", \" + to_string( messageCode ), to_string( objectType ) + \"(\" + to_string_hex( object ) + \")\", pMessage  );\r\n\r\n\treturn VK_FALSE; // no abort on misbehaving command\r\n}\r\n\r\nVKAPI_ATTR VkBool32 VKAPI_CALL genericDebugUtilsCallback(\r\n\tVkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,\r\n\tVkDebugUtilsMessageTypeFlagsEXT messageTypes,\r\n\tconst VkDebugUtilsMessengerCallbackDataEXT* pCallbackData,\r\n\tvoid* /*pUserData*/\r\n){\r\n\tusing std::to_string;\r\n\tusing std::string;\r\n\r\n\tHighlight highlight;\r\n\tif( (messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT) || (messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT)){\r\n\t\thighlight = Highlight::on;\r\n\t}\r\n\telse highlight = Highlight::off;\r\n\r\n\tstring objects;\r\n\tbool first = true;\r\n\tfor( uint32_t i = 0; i < pCallbackData->objectCount; ++i ){\r\n\t\tconst auto& obj = pCallbackData->pObjects[i];\r\n\r\n\t\tif( first ) first = false;\r\n\t\telse objects += \", \";\r\n\t\tobjects +=  to_string( obj.objectType ) + \"(\" + to_string_hex( obj.objectHandle ) + \")\";\r\n\t}\r\n\tobjects = \"[\" + objects + \"]\";\r\n\r\n\tgenericDebugCallback(  dbutype_to_string( messageTypes ) + \"+\" + to_string( messageSeverity ), highlight, string(pCallbackData->pMessageIdName) + \"(\" + to_string( pCallbackData->messageIdNumber ) + \")\", objects, pCallbackData->pMessage  );\r\n\r\n\treturn VK_FALSE; // no abort on misbehaving command\r\n}\r\n\r\nVkDebugReportFlagsEXT translateFlags( const VkDebugUtilsMessageSeverityFlagsEXT debugSeverity, const VkDebugUtilsMessageTypeFlagsEXT debugType ){\r\n\tVkDebugReportFlagsEXT flags = 0;\r\n\tif( (debugType & VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT) || (debugType & VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT) ){\r\n\t\tif( debugSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT ) flags |= VK_DEBUG_REPORT_ERROR_BIT_EXT;\r\n\t\tif( debugSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT ) flags |= VK_DEBUG_REPORT_WARNING_BIT_EXT;\r\n\t\tif( (debugSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT) && (debugType & VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT) ) flags |= VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT;\r\n\t\tif( debugSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT ) flags |= VK_DEBUG_REPORT_INFORMATION_BIT_EXT;\r\n\t\tif( debugSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT ) flags |= VK_DEBUG_REPORT_DEBUG_BIT_EXT;\r\n\t}\r\n\r\n\treturn flags;\r\n}\r\n\r\nDebugObjectVariant initDebug( const VkInstance instance, const DebugObjectType debugExtension, const VkDebugUtilsMessageSeverityFlagsEXT debugSeverity, const VkDebugUtilsMessageTypeFlagsEXT debugType ){\r\n\tDebugObjectVariant debug;\r\n\tdebug.tag = debugExtension;\r\n\r\n\tif( debugExtension == DebugObjectType::debugUtils ){\r\n\t\tconst VkDebugUtilsMessengerCreateInfoEXT dmci = {\r\n\t\t\tVK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT,\r\n\t\t\tnullptr, // pNext\r\n\t\t\t0, // flags\r\n\t\t\tdebugSeverity,\r\n\t\t\tdebugType,\r\n\t\t\t::genericDebugUtilsCallback,\r\n\t\t\tnullptr // pUserData\r\n\t\t};\r\n\r\n\t\tconst VkResult errorCode = vkCreateDebugUtilsMessengerEXT( instance, &dmci, nullptr, &debug.debugUtilsMessenger ); RESULT_HANDLER( errorCode, \"vkCreateDebugUtilsMessengerEXT\" );\r\n\t}\r\n\telse if( debugExtension == DebugObjectType::debugReport ){\r\n\t\tconst VkDebugReportCallbackCreateInfoEXT debugCreateInfo{\r\n\t\t\tVK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT,\r\n\t\t\tnullptr, // pNext\r\n\t\t\ttranslateFlags( debugSeverity, debugType ),\r\n\t\t\t::genericDebugReportCallback,\r\n\t\t\tnullptr // pUserData\r\n\t\t};\r\n\r\n\t\tconst VkResult errorCode = vkCreateDebugReportCallbackEXT( instance, &debugCreateInfo, nullptr, &debug.debugReportCallback ); RESULT_HANDLER( errorCode, \"vkCreateDebugReportCallbackEXT\" );\r\n\t}\r\n\telse{\r\n\t\tthrow \"initDebug: unknown debug extension\";\r\n\t}\r\n\r\n\treturn debug;\r\n}\r\n\r\nvoid killDebug( const VkInstance instance, const DebugObjectVariant debug ){\r\n\tif( debug.tag == DebugObjectType::debugUtils ){\r\n\t\tvkDestroyDebugUtilsMessengerEXT( instance, debug.debugUtilsMessenger, nullptr );\r\n\t}\r\n\telse if( debug.tag == DebugObjectType::debugReport ){\r\n\t\tvkDestroyDebugReportCallbackEXT( instance, debug.debugReportCallback, nullptr );\r\n\t}\r\n\telse{\r\n\t\tthrow \"initDebug: unknown debug extension\";\r\n\t}\r\n}\r\n\r\n#endif //COMMON_ERROR_HANDLING_H\r\n"
  },
  {
    "path": "src/ExtensionLoader.h",
    "content": "// Vulkan extensions commands loader\r\n\r\n#ifndef EXTENSION_LOADER_H\r\n#define EXTENSION_LOADER_H\r\n\r\n#include <vector>\r\n\r\n#include <unordered_map>\r\n\r\n#include<cstring>\r\n\r\n#include <vulkan/vulkan.h>\r\n\r\n#include \"CompilerMessages.h\"\r\n#include \"EnumerateScheme.h\"\r\n\r\nvoid loadInstanceExtensionsCommands( VkInstance instance, const std::vector<const char*>& instanceExtensions );\r\nvoid unloadInstanceExtensionsCommands( VkInstance instance );\r\n\r\nvoid loadDeviceExtensionsCommands( VkDevice device, const std::vector<const char*>& instanceExtensions );\r\nvoid unloadDeviceExtensionsCommands( VkDevice device );\r\n\r\nvoid loadPDProps2Commands( VkInstance instance );\r\nvoid unloadPDProps2Commands( VkInstance instance );\r\n\r\nvoid loadDebugReportCommands( VkInstance instance );\r\nvoid unloadDebugReportCommands( VkInstance instance );\r\n\r\nvoid loadDebugUtilsCommands( VkInstance instance );\r\nvoid unloadDebugUtilsCommands( VkInstance instance );\r\n\r\nvoid loadExternalMemoryCapsCommands( VkInstance instance );\r\nvoid unloadExternalMemoryCapsCommands( VkInstance instance );\r\n\r\n\r\nvoid loadExternalMemoryCommands( VkDevice device );\r\nvoid unloadExternalMemoryCommands( VkDevice device );\r\n\r\n#ifdef VK_USE_PLATFORM_WIN32_KHR\r\nvoid loadExternalMemoryWin32Commands( VkDevice device );\r\nvoid unloadExternalMemoryWin32Commands( VkDevice device );\r\n#endif\r\n\r\nvoid loadDedicatedAllocationCommands( VkDevice device );\r\nvoid unloadDedicatedAllocationCommands( VkDevice device );\r\n\r\n////////////////////////////////////////////////////////\r\n\r\nstd::unordered_map< VkInstance, std::vector<const char*> > instanceExtensionsMap;\r\nstd::unordered_map< VkPhysicalDevice, VkInstance > physicalDeviceInstanceMap;\r\n\r\nTODO( \"Leaks destroyed instances\" );\r\nvoid populatePhysicalDeviceInstaceMap( const VkInstance instance ){\r\n\tconst std::vector<VkPhysicalDevice> physicalDevices = enumerate<VkPhysicalDevice>( instance );\r\n\tfor( const auto pd : physicalDevices ) physicalDeviceInstanceMap[pd] = instance;\r\n}\r\n\r\nvoid loadInstanceExtensionsCommands( const VkInstance instance, const std::vector<const char*>& instanceExtensions ){\r\n\tusing std::strcmp;\r\n\r\n\tinstanceExtensionsMap[instance] = instanceExtensions;\r\n\r\n\tfor( const auto e : instanceExtensions ){\r\n\t\tif( strcmp( e, VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME ) == 0 ) loadPDProps2Commands( instance );\r\n\t\tif( strcmp( e, VK_EXT_DEBUG_REPORT_EXTENSION_NAME ) == 0 ) loadDebugReportCommands( instance );\r\n\t\tif( strcmp( e, VK_EXT_DEBUG_UTILS_EXTENSION_NAME ) == 0 ) loadDebugUtilsCommands( instance );\r\n\t\tif( strcmp( e, VK_KHR_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME ) == 0 ) loadExternalMemoryCapsCommands( instance );\r\n\t\t// ...\r\n\t}\r\n}\r\n\r\nvoid unloadInstanceExtensionsCommands( const VkInstance instance ){\r\n\tusing std::strcmp;\r\n\r\n\tfor(  const auto e : instanceExtensionsMap.at( instance )  ){\r\n\t\tif( strcmp( e, VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME ) == 0 ) unloadPDProps2Commands( instance );\r\n\t\tif( strcmp( e, VK_EXT_DEBUG_REPORT_EXTENSION_NAME ) == 0 ) unloadDebugReportCommands( instance );\r\n\t\tif( strcmp( e, VK_EXT_DEBUG_UTILS_EXTENSION_NAME ) == 0 ) unloadDebugUtilsCommands( instance );\r\n\t\tif( strcmp( e, VK_KHR_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME ) == 0 ) unloadExternalMemoryCapsCommands( instance );\r\n\t\t// ...\r\n\t}\r\n\r\n\tinstanceExtensionsMap.erase( instance );\r\n}\r\n\r\nstd::unordered_map< VkDevice, std::vector<const char*> > deviceExtensionsMap;\r\n\r\nvoid loadDeviceExtensionsCommands( const VkDevice device, const std::vector<const char*>& deviceExtensions ){\r\n\tusing std::strcmp;\r\n\r\n\tdeviceExtensionsMap[device] = deviceExtensions;\r\n\r\n\tfor( const auto e : deviceExtensions ){\r\n\t\tif( strcmp( e, VK_KHR_EXTERNAL_MEMORY_EXTENSION_NAME ) == 0 ) loadExternalMemoryCommands( device );\r\n#ifdef VK_USE_PLATFORM_WIN32_KHR\r\n\t\tif( strcmp( e, VK_KHR_EXTERNAL_MEMORY_WIN32_EXTENSION_NAME ) == 0 ) loadExternalMemoryWin32Commands( device );\r\n#endif\r\n\t\tif( strcmp( e, VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME ) == 0 ) loadDedicatedAllocationCommands( device );\r\n\t\t// ...\r\n\t}\r\n}\r\n\r\nvoid unloadDeviceExtensionsCommands( const VkDevice device ){\r\n\tusing std::strcmp;\r\n\r\n\tfor(  const auto e : deviceExtensionsMap.at( device )  ){\r\n\t\tif( strcmp( e, VK_KHR_EXTERNAL_MEMORY_EXTENSION_NAME ) == 0 ) unloadExternalMemoryCommands( device );\r\n#ifdef VK_USE_PLATFORM_WIN32_KHR\r\n\t\tif( strcmp( e, VK_KHR_EXTERNAL_MEMORY_WIN32_EXTENSION_NAME ) == 0 ) unloadExternalMemoryWin32Commands( device );\r\n#endif\r\n\t\tif( strcmp( e, VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME ) == 0 ) unloadDedicatedAllocationCommands( device );\r\n\t\t// ...\r\n\t}\r\n\r\n\tdeviceExtensionsMap.erase( device );\r\n}\r\n\r\n\r\n// VK_KHR_get_physical_device_properties2\r\n///////////////////////////////////////////\r\n\r\nstd::unordered_map< VkInstance, PFN_vkGetPhysicalDeviceFeatures2KHR > GetPhysicalDeviceFeatures2KHRDispatchTable;\r\nstd::unordered_map< VkInstance, PFN_vkGetPhysicalDeviceProperties2KHR > GetPhysicalDeviceProperties2KHRDispatchTable;\r\nstd::unordered_map< VkInstance, PFN_vkGetPhysicalDeviceFormatProperties2KHR > GetPhysicalDeviceFormatProperties2KHRDispatchTable;\r\nstd::unordered_map< VkInstance, PFN_vkGetPhysicalDeviceImageFormatProperties2KHR > GetPhysicalDeviceImageFormatProperties2KHRDispatchTable;\r\nstd::unordered_map< VkInstance, PFN_vkGetPhysicalDeviceQueueFamilyProperties2KHR > GetPhysicalDeviceQueueFamilyProperties2KHRDispatchTable;\r\nstd::unordered_map< VkInstance, PFN_vkGetPhysicalDeviceMemoryProperties2KHR > GetPhysicalDeviceMemoryProperties2KHRDispatchTable;\r\nstd::unordered_map< VkInstance, PFN_vkGetPhysicalDeviceSparseImageFormatProperties2KHR > GetPhysicalDeviceSparseImageFormatProperties2KHRDispatchTable;\r\n\r\nvoid loadPDProps2Commands( VkInstance instance ){\r\n\tpopulatePhysicalDeviceInstaceMap( instance );\r\n\r\n\tPFN_vkVoidFunction temp_fp;\r\n\r\n\ttemp_fp = vkGetInstanceProcAddr( instance, \"vkGetPhysicalDeviceFeatures2KHR\" );\r\n\tif( !temp_fp ) throw \"Failed to load vkGetPhysicalDeviceFeatures2KHR\"; // check shouldn't be necessary (based on spec)\r\n\tGetPhysicalDeviceFeatures2KHRDispatchTable[instance] = reinterpret_cast<PFN_vkGetPhysicalDeviceFeatures2KHR>( temp_fp );\r\n\r\n\ttemp_fp = vkGetInstanceProcAddr( instance, \"vkGetPhysicalDeviceProperties2KHR\" );\r\n\tif( !temp_fp ) throw \"Failed to load vkGetPhysicalDeviceProperties2KHR\"; // check shouldn't be necessary (based on spec)\r\n\tGetPhysicalDeviceProperties2KHRDispatchTable[instance] = reinterpret_cast<PFN_vkGetPhysicalDeviceProperties2KHR>( temp_fp );\r\n\r\n\ttemp_fp = vkGetInstanceProcAddr( instance, \"vkGetPhysicalDeviceFormatProperties2KHR\" );\r\n\tif( !temp_fp ) throw \"Failed to load vkGetPhysicalDeviceFormatProperties2KHR\"; // check shouldn't be necessary (based on spec)\r\n\tGetPhysicalDeviceFormatProperties2KHRDispatchTable[instance] = reinterpret_cast<PFN_vkGetPhysicalDeviceFormatProperties2KHR>( temp_fp );\r\n\r\n\ttemp_fp = vkGetInstanceProcAddr( instance, \"vkGetPhysicalDeviceImageFormatProperties2KHR\" );\r\n\tif( !temp_fp ) throw \"Failed to load vkGetPhysicalDeviceImageFormatProperties2KHR\"; // check shouldn't be necessary (based on spec)\r\n\tGetPhysicalDeviceImageFormatProperties2KHRDispatchTable[instance] = reinterpret_cast<PFN_vkGetPhysicalDeviceImageFormatProperties2KHR>( temp_fp );\r\n\r\n\ttemp_fp = vkGetInstanceProcAddr( instance, \"vkGetPhysicalDeviceQueueFamilyProperties2KHR\" );\r\n\tif( !temp_fp ) throw \"Failed to load vkGetPhysicalDeviceQueueFamilyProperties2KHR\"; // check shouldn't be necessary (based on spec)\r\n\tGetPhysicalDeviceQueueFamilyProperties2KHRDispatchTable[instance] = reinterpret_cast<PFN_vkGetPhysicalDeviceQueueFamilyProperties2KHR>( temp_fp );\r\n\r\n\ttemp_fp = vkGetInstanceProcAddr( instance, \"vkGetPhysicalDeviceMemoryProperties2KHR\" );\r\n\tif( !temp_fp ) throw \"Failed to load vkGetPhysicalDeviceMemoryProperties2KHR\"; // check shouldn't be necessary (based on spec)\r\n\tGetPhysicalDeviceMemoryProperties2KHRDispatchTable[instance] = reinterpret_cast<PFN_vkGetPhysicalDeviceMemoryProperties2KHR>( temp_fp );\r\n\r\n\ttemp_fp = vkGetInstanceProcAddr( instance, \"vkGetPhysicalDeviceSparseImageFormatProperties2KHR\" );\r\n\tif( !temp_fp ) throw \"Failed to load vkGetPhysicalDeviceSparseImageFormatProperties2KHR\"; // check shouldn't be necessary (based on spec)\r\n\tGetPhysicalDeviceSparseImageFormatProperties2KHRDispatchTable[instance] = reinterpret_cast<PFN_vkGetPhysicalDeviceSparseImageFormatProperties2KHR>( temp_fp );\r\n}\r\n\r\nvoid unloadPDProps2Commands( VkInstance instance ){\r\n\tGetPhysicalDeviceFeatures2KHRDispatchTable.erase( instance );\r\n\tGetPhysicalDeviceProperties2KHRDispatchTable.erase( instance );\r\n\tGetPhysicalDeviceFormatProperties2KHRDispatchTable.erase( instance );\r\n\tGetPhysicalDeviceImageFormatProperties2KHRDispatchTable.erase( instance );\r\n\tGetPhysicalDeviceQueueFamilyProperties2KHRDispatchTable.erase( instance );\r\n\tGetPhysicalDeviceMemoryProperties2KHRDispatchTable.erase( instance );\r\n\tGetPhysicalDeviceSparseImageFormatProperties2KHRDispatchTable.erase( instance );\r\n}\r\n\r\nVKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceFeatures2KHR( VkPhysicalDevice physicalDevice, VkPhysicalDeviceFeatures2* pFeatures ){\r\n\tconst VkInstance instance = physicalDeviceInstanceMap.at( physicalDevice );\r\n\tauto dispatched_cmd = GetPhysicalDeviceFeatures2KHRDispatchTable.at( instance );\r\n\treturn dispatched_cmd( physicalDevice, pFeatures );\r\n}\r\n\r\nVKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceProperties2KHR( VkPhysicalDevice physicalDevice, VkPhysicalDeviceProperties2* pProperties ){\r\n\tconst VkInstance instance = physicalDeviceInstanceMap.at( physicalDevice );\r\n\tauto dispatched_cmd = GetPhysicalDeviceProperties2KHRDispatchTable.at( instance );\r\n\treturn dispatched_cmd( physicalDevice, pProperties );\r\n}\r\n\r\nVKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceFormatProperties2KHR( VkPhysicalDevice physicalDevice, VkFormat format, VkFormatProperties2* pFormatProperties ){\r\n\tconst VkInstance instance = physicalDeviceInstanceMap.at( physicalDevice );\r\n\tauto dispatched_cmd = GetPhysicalDeviceFormatProperties2KHRDispatchTable.at( instance );\r\n\treturn dispatched_cmd( physicalDevice, format, pFormatProperties );\r\n}\r\n\r\nVKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceImageFormatProperties2KHR( VkPhysicalDevice physicalDevice, const VkPhysicalDeviceImageFormatInfo2* pImageFormatInfo, VkImageFormatProperties2* pImageFormatProperties ){\r\n\tconst VkInstance instance = physicalDeviceInstanceMap.at( physicalDevice );\r\n\tauto dispatched_cmd = GetPhysicalDeviceImageFormatProperties2KHRDispatchTable.at( instance );\r\n\treturn dispatched_cmd( physicalDevice, pImageFormatInfo, pImageFormatProperties );\r\n}\r\n\r\nVKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceQueueFamilyProperties2KHR( VkPhysicalDevice physicalDevice, uint32_t* pQueueFamilyPropertyCount, VkQueueFamilyProperties2* pQueueFamilyProperties ){\r\n\tconst VkInstance instance = physicalDeviceInstanceMap.at( physicalDevice );\r\n\tauto dispatched_cmd = GetPhysicalDeviceQueueFamilyProperties2KHRDispatchTable.at( instance );\r\n\treturn dispatched_cmd( physicalDevice, pQueueFamilyPropertyCount, pQueueFamilyProperties );\r\n}\r\n\r\nVKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceMemoryProperties2KHR( VkPhysicalDevice physicalDevice, VkPhysicalDeviceMemoryProperties2* pMemoryProperties ){\r\n\tconst VkInstance instance = physicalDeviceInstanceMap.at( physicalDevice );\r\n\tauto dispatched_cmd = GetPhysicalDeviceMemoryProperties2KHRDispatchTable.at( instance );\r\n\treturn dispatched_cmd( physicalDevice, pMemoryProperties );\r\n}\r\n\r\nVKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceSparseImageFormatProperties2KHR( VkPhysicalDevice physicalDevice, const VkPhysicalDeviceSparseImageFormatInfo2* pFormatInfo, uint32_t* pPropertyCount, VkSparseImageFormatProperties2* pProperties ){\r\n\tconst VkInstance instance = physicalDeviceInstanceMap.at( physicalDevice );\r\n\tauto dispatched_cmd = GetPhysicalDeviceSparseImageFormatProperties2KHRDispatchTable.at( instance );\r\n\treturn dispatched_cmd( physicalDevice, pFormatInfo, pPropertyCount, pProperties );\r\n}\r\n\r\n// VK_EXT_debug_report\r\n//////////////////////////////////\r\n\r\nstd::unordered_map< VkInstance, PFN_vkCreateDebugReportCallbackEXT > CreateDebugReportCallbackEXTDispatchTable;\r\nstd::unordered_map< VkInstance, PFN_vkDestroyDebugReportCallbackEXT > DestroyDebugReportCallbackEXTDispatchTable;\r\nstd::unordered_map< VkInstance, PFN_vkDebugReportMessageEXT > DebugReportMessageEXTDispatchTable;\r\n\r\nvoid loadDebugReportCommands( VkInstance instance ){\r\n\tPFN_vkVoidFunction temp_fp;\r\n\r\n\ttemp_fp = vkGetInstanceProcAddr( instance, \"vkCreateDebugReportCallbackEXT\" );\r\n\tif( !temp_fp ) throw \"Failed to load vkCreateDebugReportCallbackEXT\"; // check shouldn't be necessary (based on spec)\r\n\tCreateDebugReportCallbackEXTDispatchTable[instance] = reinterpret_cast<PFN_vkCreateDebugReportCallbackEXT>( temp_fp );\r\n\r\n\ttemp_fp = vkGetInstanceProcAddr( instance, \"vkDestroyDebugReportCallbackEXT\" );\r\n\tif( !temp_fp ) throw \"Failed to load vkDestroyDebugReportCallbackEXT\"; // check shouldn't be necessary (based on spec)\r\n\tDestroyDebugReportCallbackEXTDispatchTable[instance] = reinterpret_cast<PFN_vkDestroyDebugReportCallbackEXT>( temp_fp );\r\n\r\n\ttemp_fp = vkGetInstanceProcAddr( instance, \"vkDebugReportMessageEXT\" );\r\n\tif( !temp_fp ) throw \"Failed to load vkDebugReportMessageEXT\"; // check shouldn't be necessary (based on spec)\r\n\tDebugReportMessageEXTDispatchTable[instance] = reinterpret_cast<PFN_vkDebugReportMessageEXT>( temp_fp );\r\n}\r\n\r\nvoid unloadDebugReportCommands( VkInstance instance ){\r\n\tCreateDebugReportCallbackEXTDispatchTable.erase( instance );\r\n\tDestroyDebugReportCallbackEXTDispatchTable.erase( instance );\r\n\tDebugReportMessageEXTDispatchTable.erase( instance );\r\n}\r\n\r\nVKAPI_ATTR VkResult VKAPI_CALL vkCreateDebugReportCallbackEXT(\r\n\tVkInstance instance,\r\n\tconst VkDebugReportCallbackCreateInfoEXT* pCreateInfo,\r\n\tconst VkAllocationCallbacks* pAllocator,\r\n\tVkDebugReportCallbackEXT* pCallback\r\n){\r\n\tauto dispatched_cmd = CreateDebugReportCallbackEXTDispatchTable.at( instance );\r\n\treturn dispatched_cmd( instance, pCreateInfo, pAllocator, pCallback );\r\n}\r\n\r\nVKAPI_ATTR void VKAPI_CALL vkDestroyDebugReportCallbackEXT(\r\n\tVkInstance instance,\r\n\tVkDebugReportCallbackEXT callback,\r\n\tconst VkAllocationCallbacks* pAllocator\r\n){\r\n\tauto dispatched_cmd = DestroyDebugReportCallbackEXTDispatchTable.at( instance );\r\n\treturn dispatched_cmd( instance, callback, pAllocator );\r\n}\r\n\r\nVKAPI_ATTR void VKAPI_CALL vkDebugReportMessageEXT(\r\n\tVkInstance instance,\r\n\tVkDebugReportFlagsEXT flags,\r\n\tVkDebugReportObjectTypeEXT objectType,\r\n\tuint64_t object,\r\n\tsize_t location,\r\n\tint32_t messageCode,\r\n\tconst char* pLayerPrefix,\r\n\tconst char* pMessage\r\n){\r\n\tauto dispatched_cmd = DebugReportMessageEXTDispatchTable.at( instance );\r\n\treturn dispatched_cmd( instance, flags, objectType, object, location, messageCode, pLayerPrefix, pMessage );\r\n}\r\n\r\n// VK_EXT_debug_utils\r\n//////////////////////////////////\r\n\r\nstd::unordered_map< VkInstance, PFN_vkCreateDebugUtilsMessengerEXT > CreateDebugUtilsMessengerEXTDispatchTable;\r\nstd::unordered_map< VkInstance, PFN_vkDestroyDebugUtilsMessengerEXT > DestroyDebugUtilsMessengerEXTDispatchTable;\r\nstd::unordered_map< VkInstance, PFN_vkSubmitDebugUtilsMessageEXT > SubmitDebugUtilsMessageEXTDispatchTable;\r\n\r\nvoid loadDebugUtilsCommands( VkInstance instance ){\r\n\tPFN_vkVoidFunction temp_fp;\r\n\r\n\ttemp_fp = vkGetInstanceProcAddr( instance, \"vkCreateDebugUtilsMessengerEXT\" );\r\n\tif( !temp_fp ) throw \"Failed to load vkCreateDebugUtilsMessengerEXT\"; // check shouldn't be necessary (based on spec)\r\n\tCreateDebugUtilsMessengerEXTDispatchTable[instance] = reinterpret_cast<PFN_vkCreateDebugUtilsMessengerEXT>( temp_fp );\r\n\r\n\ttemp_fp = vkGetInstanceProcAddr( instance, \"vkDestroyDebugUtilsMessengerEXT\" );\r\n\tif( !temp_fp ) throw \"Failed to load vkDestroyDebugUtilsMessengerEXT\"; // check shouldn't be necessary (based on spec)\r\n\tDestroyDebugUtilsMessengerEXTDispatchTable[instance] = reinterpret_cast<PFN_vkDestroyDebugUtilsMessengerEXT>( temp_fp );\r\n\r\n\ttemp_fp = vkGetInstanceProcAddr( instance, \"vkSubmitDebugUtilsMessageEXT\" );\r\n\tif( !temp_fp ) throw \"Failed to load vkSubmitDebugUtilsMessageEXT\"; // check shouldn't be necessary (based on spec)\r\n\tSubmitDebugUtilsMessageEXTDispatchTable[instance] = reinterpret_cast<PFN_vkSubmitDebugUtilsMessageEXT>( temp_fp );\r\n}\r\n\r\nvoid unloadDebugUtilsCommands( VkInstance instance ){\r\n\tCreateDebugUtilsMessengerEXTDispatchTable.erase( instance );\r\n\tDestroyDebugUtilsMessengerEXTDispatchTable.erase( instance );\r\n\tSubmitDebugUtilsMessageEXTDispatchTable.erase( instance );\r\n}\r\n\r\nVKAPI_ATTR VkResult VKAPI_CALL vkCreateDebugUtilsMessengerEXT(\r\n\tVkInstance instance,\r\n\tconst VkDebugUtilsMessengerCreateInfoEXT* pCreateInfo,\r\n\tconst VkAllocationCallbacks* pAllocator,\r\n\tVkDebugUtilsMessengerEXT* pMessenger\r\n){\r\n\tauto dispatched_cmd = CreateDebugUtilsMessengerEXTDispatchTable.at( instance );\r\n\treturn dispatched_cmd( instance, pCreateInfo, pAllocator, pMessenger );\r\n}\r\n\r\nVKAPI_ATTR void VKAPI_CALL vkDestroyDebugUtilsMessengerEXT(\r\n\tVkInstance instance,\r\n\tVkDebugUtilsMessengerEXT messenger,\r\n\tconst VkAllocationCallbacks* pAllocator\r\n){\r\n\tauto dispatched_cmd = DestroyDebugUtilsMessengerEXTDispatchTable.at( instance );\r\n\treturn dispatched_cmd( instance, messenger, pAllocator );\r\n}\r\n\r\nVKAPI_ATTR void VKAPI_CALL vkSubmitDebugUtilsMessageEXT(\r\n\tVkInstance instance,\r\n\tVkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,\r\n\tVkDebugUtilsMessageTypeFlagsEXT messageTypes,\r\n\tconst VkDebugUtilsMessengerCallbackDataEXT* pCallbackData\r\n){\r\n\tauto dispatched_cmd = SubmitDebugUtilsMessageEXTDispatchTable.at( instance );\r\n\treturn dispatched_cmd( instance, messageSeverity, messageTypes, pCallbackData );\r\n}\r\n\r\n// VK_KHR_external_memory_capabilities\r\n///////////////////////////////////////////\r\n\r\nstd::unordered_map< VkInstance, PFN_vkGetPhysicalDeviceExternalBufferPropertiesKHR > GetPhysicalDeviceExternalBufferPropertiesKHRDispatchTable;\r\n\r\nvoid loadExternalMemoryCapsCommands( VkInstance instance ){\r\n\tpopulatePhysicalDeviceInstaceMap( instance );\r\n\r\n\tPFN_vkVoidFunction temp_fp;\r\n\r\n\ttemp_fp = vkGetInstanceProcAddr( instance, \"vkGetPhysicalDeviceExternalBufferPropertiesKHR\" );\r\n\tif( !temp_fp ) throw \"Failed to load vkGetPhysicalDeviceExternalBufferPropertiesKHR\"; // check shouldn't be necessary (based on spec)\r\n\tGetPhysicalDeviceExternalBufferPropertiesKHRDispatchTable[instance] = reinterpret_cast<PFN_vkGetPhysicalDeviceExternalBufferPropertiesKHR>( temp_fp );\r\n}\r\n\r\nvoid unloadExternalMemoryCapsCommands( VkInstance instance ){\r\n\tGetPhysicalDeviceExternalBufferPropertiesKHRDispatchTable.erase( instance );\r\n}\r\n\r\nVKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceExternalBufferPropertiesKHR(\r\n\tVkPhysicalDevice physicalDevice,\r\n\tconst VkPhysicalDeviceExternalBufferInfo* pExternalBufferInfo,\r\n\tVkExternalBufferProperties* pExternalBufferProperties\r\n){\r\n\tconst VkInstance instance = physicalDeviceInstanceMap.at( physicalDevice );\r\n\tauto dispatched_cmd = GetPhysicalDeviceExternalBufferPropertiesKHRDispatchTable.at( instance );\r\n\treturn dispatched_cmd( physicalDevice, pExternalBufferInfo, pExternalBufferProperties );\r\n}\r\n\r\n\r\n// VK_KHR_external_memory\r\n///////////////////////////////////////////\r\n\r\nvoid loadExternalMemoryCommands( VkDevice ){\r\n\t// no commands\r\n}\r\n\r\nvoid unloadExternalMemoryCommands( VkDevice ){\r\n\t// no commands\r\n}\r\n\r\n\r\n#ifdef VK_USE_PLATFORM_WIN32_KHR\r\n// VK_KHR_external_memory_win32\r\n///////////////////////////////////////////\r\n\r\nstd::unordered_map< VkDevice, PFN_vkGetMemoryWin32HandleKHR > GetMemoryWin32HandleKHRDispatchTable;\r\nstd::unordered_map< VkDevice, PFN_vkGetMemoryWin32HandlePropertiesKHR > GetMemoryWin32HandlePropertiesKHRDispatchTable;\r\n\r\nvoid loadExternalMemoryWin32Commands( VkDevice device ){\r\n\tPFN_vkVoidFunction temp_fp;\r\n\r\n\ttemp_fp = vkGetDeviceProcAddr( device, \"vkGetMemoryWin32HandleKHR\" );\r\n\tif( !temp_fp ) throw \"Failed to load vkGetMemoryWin32HandleKHR\"; // check shouldn't be necessary (based on spec)\r\n\tGetMemoryWin32HandleKHRDispatchTable[device] = reinterpret_cast<PFN_vkGetMemoryWin32HandleKHR>( temp_fp );\r\n\r\n\ttemp_fp = vkGetDeviceProcAddr( device, \"vkGetMemoryWin32HandlePropertiesKHR\" );\r\n\tif( !temp_fp ) throw \"Failed to load vkGetMemoryWin32HandlePropertiesKHR\"; // check shouldn't be necessary (based on spec)\r\n\tGetMemoryWin32HandlePropertiesKHRDispatchTable[device] = reinterpret_cast<PFN_vkGetMemoryWin32HandlePropertiesKHR>( temp_fp );\r\n}\r\n\r\nvoid unloadExternalMemoryWin32Commands( VkDevice device ){\r\n\tGetMemoryWin32HandleKHRDispatchTable.erase( device );\r\n\tGetMemoryWin32HandlePropertiesKHRDispatchTable.erase( device );\r\n}\r\n\r\nVKAPI_ATTR VkResult VKAPI_CALL vkGetMemoryWin32HandleKHR(\r\n\tVkDevice device,\r\n\tconst VkMemoryGetWin32HandleInfoKHR* pGetWin32HandleInfo,\r\n\tHANDLE* pHandle\r\n){\r\n\tauto dispatched_cmd = GetMemoryWin32HandleKHRDispatchTable.at( device );\r\n\treturn dispatched_cmd( device, pGetWin32HandleInfo, pHandle );\r\n}\r\n\r\nVKAPI_ATTR VkResult VKAPI_CALL vkGetMemoryWin32HandlePropertiesKHR(\r\n\tVkDevice device,\r\n\tVkExternalMemoryHandleTypeFlagBits handleType,\r\n\tHANDLE handle,\r\n\tVkMemoryWin32HandlePropertiesKHR* pMemoryWin32HandleProperties\r\n){\r\n\tauto dispatched_cmd = GetMemoryWin32HandlePropertiesKHRDispatchTable.at( device );\r\n\treturn dispatched_cmd( device, handleType, handle, pMemoryWin32HandleProperties );\r\n}\r\n#endif\r\n\r\n// VK_KHR_dedicated_allocation\r\n///////////////////////////////////////////\r\n\r\nvoid loadDedicatedAllocationCommands( VkDevice ){\r\n\t// no commands\r\n}\r\n\r\nvoid unloadDedicatedAllocationCommands( VkDevice ){\r\n\t// no commands\r\n}\r\n\r\n#endif //EXTENSION_LOADER_H"
  },
  {
    "path": "src/HelloTriangle.cpp",
    "content": "// Vulkan hello world triangle rendering demo\r\n\r\n\r\n// Global header settings\r\n//////////////////////////////////////////////////////////////////////////////////\r\n\r\n#include \"VulkanEnvironment.h\" // first include must be before vulkan.h and platform header\r\n\r\n\r\n// Includes\r\n//////////////////////////////////////////////////////////////////////////////////\r\n\r\n#include <algorithm>\r\n#include <cassert>\r\n#include <cmath>\r\n#include <cstdlib>\r\n#include <cstring>\r\n#include <exception>\r\n#include <fstream>\r\n#include <functional>\r\n#include <iterator>\r\n#include <stdexcept>\r\n#include <string>\r\n#include <tuple>\r\n#include <utility>\r\n#include <vector>\r\n\r\n#include <vulkan/vulkan.h> // also assume core+WSI commands are loaded\r\nstatic_assert( VK_HEADER_VERSION >= REQUIRED_HEADER_VERSION, \"Update your SDK! This app is written against Vulkan header version \" STRINGIZE(REQUIRED_HEADER_VERSION) \".\" );\r\n\r\n#include \"EnumerateScheme.h\"\r\n#include \"ErrorHandling.h\"\r\n#include \"ExtensionLoader.h\"\r\n#include \"Vertex.h\"\r\n#include \"Wsi.h\"\r\n\r\n\r\nusing std::exception;\r\nusing std::runtime_error;\r\nusing std::string;\r\nusing std::to_string;\r\nusing std::vector;\r\n\r\n\r\n// Config\r\n//////////////////////////////////////////////////////////////////////////////////\r\n\r\nconst char appName[] = u8\"Hello Vulkan Triangle\";\r\n\r\n// layers and debug\r\n#if VULKAN_VALIDATION\r\n\tconstexpr VkDebugUtilsMessageSeverityFlagsEXT debugSeverity =\r\n\t\t0\r\n\t\t//| VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT\r\n\t\t//| VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT\r\n\t\t| VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT\r\n\t\t| VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT\r\n\t;\r\n\tconstexpr VkDebugUtilsMessageTypeFlagsEXT debugType =\r\n\t\t0\r\n\t\t| VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT\r\n\t\t| VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT\r\n\t\t| VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT\r\n\t;\r\n\r\n\tconstexpr bool useAssistantLayer = false;\r\n#endif\r\n\r\nconstexpr bool fpsCounter = true;\r\n\r\n// window and swapchain\r\nconstexpr uint32_t initialWindowWidth = 800;\r\nconstexpr uint32_t initialWindowHeight = 800;\r\n\r\n//constexpr VkPresentModeKHR presentMode = VK_PRESENT_MODE_IMMEDIATE_KHR; // better not be used often because of coil whine\r\nconstexpr VkPresentModeKHR presentMode = VK_PRESENT_MODE_FIFO_KHR;\r\n//constexpr VkPresentModeKHR presentMode = VK_PRESENT_MODE_MAILBOX_KHR;\r\n\r\n// pipeline settings\r\nconstexpr VkClearValue clearColor = {  { {0.1f, 0.1f, 0.1f, 1.0f} }  };\r\n\r\n// Makes present queue from different Queue Family than Graphics, for testing purposes\r\nconstexpr bool forceSeparatePresentQueue = false;\r\n\r\n// needed stuff for main() -- forward declarations\r\n//////////////////////////////////////////////////////////////////////////////////\r\n\r\nbool isLayerSupported( const char* layer, const vector<VkLayerProperties>& supportedLayers );\r\nbool isExtensionSupported( const char* extension, const vector<VkExtensionProperties>& supportedExtensions );\r\n// treat layers as optional; app can always run without em -- i.e. return those supported\r\nvector<const char*> checkInstanceLayerSupport( const vector<const char*>& requestedLayers, const vector<VkLayerProperties>& supportedLayers );\r\nvector<VkExtensionProperties> getSupportedInstanceExtensions( const vector<const char*>& providingLayers );\r\nbool checkExtensionSupport( const vector<const char*>& extensions, const vector<VkExtensionProperties>& supportedExtensions );\r\n\r\nVkInstance initInstance( const vector<const char*>& layers = {}, const vector<const char*>& extensions = {} );\r\nvoid killInstance( VkInstance instance );\r\n\r\nVkPhysicalDevice getPhysicalDevice( VkInstance instance, VkSurfaceKHR surface = VK_NULL_HANDLE /*seek presentation support if !NULL*/ ); // destroyed with instance\r\nVkPhysicalDeviceProperties getPhysicalDeviceProperties( VkPhysicalDevice physicalDevice );\r\nVkPhysicalDeviceMemoryProperties getPhysicalDeviceMemoryProperties( VkPhysicalDevice physicalDevice );\r\n\r\nstd::pair<uint32_t, uint32_t> getQueueFamilies( VkPhysicalDevice physDevice, VkSurfaceKHR surface );\r\nvector<VkQueueFamilyProperties> getQueueFamilyProperties( VkPhysicalDevice device );\r\n\r\nVkDevice initDevice(\r\n\tVkPhysicalDevice physDevice,\r\n\tconst VkPhysicalDeviceFeatures& features,\r\n\tuint32_t graphicsQueueFamily,\r\n\tuint32_t presentQueueFamily,\r\n\tconst vector<const char*>& layers = {},\r\n\tconst vector<const char*>& extensions = {}\r\n);\r\nvoid killDevice( VkDevice device );\r\n\r\nVkQueue getQueue( VkDevice device, uint32_t queueFamily, uint32_t queueIndex );\r\n\r\n\r\nenum class ResourceType{ Buffer, Image };\r\n\r\ntemplate< ResourceType resourceType, class T >\r\nVkDeviceMemory initMemory(\r\n\tVkDevice device,\r\n\tVkPhysicalDeviceMemoryProperties physicalDeviceMemoryProperties,\r\n\tT resource,\r\n\tconst std::vector<VkMemoryPropertyFlags>& memoryTypePriority\r\n);\r\nvoid setMemoryData( VkDevice device, VkDeviceMemory memory, void* begin, size_t size );\r\nvoid killMemory( VkDevice device, VkDeviceMemory memory );\r\n\r\nVkBuffer initBuffer( VkDevice device, VkDeviceSize size, VkBufferUsageFlags usage );\r\nvoid killBuffer( VkDevice device, VkBuffer buffer );\r\n\r\nVkImage initImage(\r\n\tVkDevice device,\r\n\tVkFormat format,\r\n\tuint32_t width, uint32_t height,\r\n\tVkSampleCountFlagBits samples,\r\n\tVkImageUsageFlags usage\r\n);\r\nvoid killImage( VkDevice device, VkImage image );\r\n\r\nVkImageView initImageView( VkDevice device, VkImage image, VkFormat format );\r\nvoid killImageView( VkDevice device, VkImageView imageView );\r\n\r\n// initSurface() is platform dependent\r\nvoid killSurface( VkInstance instance, VkSurfaceKHR surface );\r\n\r\nVkSurfaceCapabilitiesKHR getSurfaceCapabilities( VkPhysicalDevice physicalDevice, VkSurfaceKHR surface );\r\nVkSurfaceFormatKHR getSurfaceFormat( VkPhysicalDevice physicalDevice, VkSurfaceKHR surface );\r\n\r\nVkSwapchainKHR initSwapchain(\r\n\tVkPhysicalDevice physicalDevice,\r\n\tVkDevice device,\r\n\tVkSurfaceKHR surface,\r\n\tVkSurfaceFormatKHR surfaceFormat,\r\n\tVkSurfaceCapabilitiesKHR capabilities,\r\n\tuint32_t graphicsQueueFamily,\r\n\tuint32_t presentQueueFamily,\r\n\tVkSwapchainKHR oldSwapchain = VK_NULL_HANDLE\r\n);\r\nvoid killSwapchain( VkDevice device, VkSwapchainKHR swapchain );\r\n\r\nuint32_t getNextImageIndex( VkDevice device, VkSwapchainKHR swapchain, VkSemaphore imageReadyS );\r\n\r\nvector<VkImageView> initSwapchainImageViews( VkDevice device, vector<VkImage> images, VkFormat format );\r\nvoid killSwapchainImageViews( VkDevice device, vector<VkImageView>& imageViews );\r\n\r\n\r\nVkRenderPass initRenderPass( VkDevice device, VkSurfaceFormatKHR surfaceFormat );\r\nvoid killRenderPass( VkDevice device, VkRenderPass renderPass );\r\n\r\nvector<VkFramebuffer> initFramebuffers(\r\n\tVkDevice device,\r\n\tVkRenderPass renderPass,\r\n\tvector<VkImageView> imageViews,\r\n\tuint32_t width, uint32_t height\r\n);\r\nvoid killFramebuffers( VkDevice device, vector<VkFramebuffer>& framebuffers );\r\n\r\n\r\nVkShaderModule initShaderModule( VkDevice device, const vector<uint32_t>& shaderCode );\r\nVkShaderModule initShaderModule( VkDevice device, string filename );\r\nvoid killShaderModule( VkDevice device, VkShaderModule shaderModule );\r\n\r\nVkPipelineLayout initPipelineLayout( VkDevice device );\r\nvoid killPipelineLayout( VkDevice device, VkPipelineLayout pipelineLayout );\r\n\r\nVkPipeline initPipeline(\r\n\tVkDevice device,\r\n\tVkPhysicalDeviceLimits limits,\r\n\tVkPipelineLayout pipelineLayout,\r\n\tVkRenderPass renderPass,\r\n\tVkShaderModule vertexShader,\r\n\tVkShaderModule fragmentShader,\r\n\tconst uint32_t vertexBufferBinding,\r\n\tuint32_t width, uint32_t height\r\n);\r\nvoid killPipeline( VkDevice device, VkPipeline pipeline );\r\n\r\n\r\nvoid setVertexData( VkDevice device, VkDeviceMemory memory, vector<Vertex2D_ColorF_pack> vertices );\r\n\r\nVkSemaphore initSemaphore( VkDevice device );\r\nvector<VkSemaphore> initSemaphores( VkDevice device, size_t count );\r\nvoid killSemaphore( VkDevice device, VkSemaphore semaphore );\r\nvoid killSemaphores( VkDevice device, vector<VkSemaphore>& semaphores );\r\n\r\nVkCommandPool initCommandPool( VkDevice device, const uint32_t queueFamily );\r\nvoid killCommandPool( VkDevice device, VkCommandPool commandPool );\r\n\r\nvector<VkFence> initFences( VkDevice device, size_t count, VkFenceCreateFlags flags = 0 );\r\nvoid killFences( VkDevice device, vector<VkFence>& fences );\r\n\r\nvoid acquireCommandBuffers( VkDevice device, VkCommandPool commandPool, uint32_t count, vector<VkCommandBuffer>& commandBuffers );\r\nvoid beginCommandBuffer( VkCommandBuffer commandBuffer );\r\nvoid endCommandBuffer( VkCommandBuffer commandBuffer );\r\n\r\nvoid recordBeginRenderPass(\r\n\tVkCommandBuffer commandBuffer,\r\n\tVkRenderPass renderPass,\r\n\tVkFramebuffer framebuffer,\r\n\tVkClearValue clearValue,\r\n\tuint32_t width, uint32_t height\r\n);\r\nvoid recordEndRenderPass( VkCommandBuffer commandBuffer );\r\n\r\nvoid recordBindPipeline( VkCommandBuffer commandBuffer, VkPipeline pipeline );\r\nvoid recordBindVertexBuffer( VkCommandBuffer commandBuffer, const uint32_t vertexBufferBinding, VkBuffer vertexBuffer );\r\n\r\nvoid recordDraw( VkCommandBuffer commandBuffer, uint32_t vertexCount );\r\n\r\nvoid submitToQueue( VkQueue queue, VkCommandBuffer commandBuffer, VkSemaphore imageReadyS, VkSemaphore renderDoneS, VkFence fence = VK_NULL_HANDLE );\r\nvoid present( VkQueue queue, VkSwapchainKHR swapchain, uint32_t swapchainImageIndex, VkSemaphore renderDoneS );\r\n\r\n// cleanup dangerous semaphore with signal pending from vkAcquireNextImageKHR\r\nvoid cleanupUnsafeSemaphore( VkQueue queue, VkSemaphore semaphore );\r\n\r\n\r\n// main()!\r\n//////////////////////////////////////////////////////////////////////////////////\r\n\r\nint helloTriangle() try{\r\n\tconst uint32_t vertexBufferBinding = 0;\r\n\r\n\tconst float triangleSize = 1.6f;\r\n\tconst vector<Vertex2D_ColorF_pack> triangle = {\r\n\t\t{ /*rb*/ { { 0.5f * triangleSize,  sqrtf( 3.0f ) * 0.25f * triangleSize} }, /*R*/{ {1.0f, 0.0f, 0.0f} }  },\r\n\t\t{ /* t*/ { {                0.0f, -sqrtf( 3.0f ) * 0.25f * triangleSize} }, /*G*/{ {0.0f, 1.0f, 0.0f} }  },\r\n\t\t{ /*lb*/ { {-0.5f * triangleSize,  sqrtf( 3.0f ) * 0.25f * triangleSize} }, /*B*/{ {0.0f, 0.0f, 1.0f} }  }\r\n\t};\r\n\r\n\tconst auto supportedLayers = enumerate<VkInstance, VkLayerProperties>();\r\n\tvector<const char*> requestedLayers;\r\n\r\n#if VULKAN_VALIDATION\r\n\tif(  isLayerSupported( \"VK_LAYER_KHRONOS_validation\", supportedLayers )  ) requestedLayers.push_back( \"VK_LAYER_KHRONOS_validation\" );\r\n\telse throw \"VULKAN_VALIDATION is enabled but VK_LAYER_KHRONOS_validation layers are not supported!\";\r\n\r\n\tif( ::useAssistantLayer ){\r\n\t\tif(  isLayerSupported( \"VK_LAYER_LUNARG_assistant_layer\", supportedLayers )  ) requestedLayers.push_back( \"VK_LAYER_LUNARG_assistant_layer\" );\r\n\t\telse throw \"VULKAN_VALIDATION is enabled but VK_LAYER_LUNARG_assistant_layer layer is not supported!\";\r\n\t}\r\n#endif\r\n\r\n\tif( ::fpsCounter ) requestedLayers.push_back( \"VK_LAYER_LUNARG_monitor\" );\r\n\trequestedLayers = checkInstanceLayerSupport( requestedLayers, supportedLayers );\r\n\r\n\r\n\tconst auto supportedInstanceExtensions = getSupportedInstanceExtensions( requestedLayers );\r\n\tconst auto platformSurfaceExtension = getPlatformSurfaceExtensionName();\r\n\tvector<const char*> requestedInstanceExtensions = {\r\n\t\tVK_KHR_SURFACE_EXTENSION_NAME,\r\n\t\tplatformSurfaceExtension.c_str()\r\n\t};\r\n\r\n#if VULKAN_VALIDATION\r\n\tDebugObjectType debugExtensionTag;\r\n\tif(  isExtensionSupported( VK_EXT_DEBUG_UTILS_EXTENSION_NAME, supportedInstanceExtensions )  ){\r\n\t\tdebugExtensionTag = DebugObjectType::debugUtils;\r\n\t\trequestedInstanceExtensions.push_back( VK_EXT_DEBUG_UTILS_EXTENSION_NAME );\r\n\t}\r\n\telse if(  isExtensionSupported( VK_EXT_DEBUG_REPORT_EXTENSION_NAME, supportedInstanceExtensions )  ){\r\n\t\tdebugExtensionTag = DebugObjectType::debugReport;\r\n\t\trequestedInstanceExtensions.push_back( VK_EXT_DEBUG_REPORT_EXTENSION_NAME );\r\n\t}\r\n\telse throw \"VULKAN_VALIDATION is enabled but neither VK_EXT_debug_utils nor VK_EXT_debug_report extension is supported!\";\r\n#endif\r\n\r\n\tcheckExtensionSupport( requestedInstanceExtensions, supportedInstanceExtensions );\r\n\r\n\r\n\tconst VkInstance instance = initInstance( requestedLayers, requestedInstanceExtensions );\r\n\r\n#if VULKAN_VALIDATION\r\n\tconst auto debugHandle = initDebug( instance, debugExtensionTag, ::debugSeverity, ::debugType );\r\n\r\n\tconst int32_t uncoded = 0;\r\n\tconst char* introMsg = \"Validation Layers are enabled!\";\r\n\tif( debugExtensionTag == DebugObjectType::debugUtils ){\r\n\t\tVkDebugUtilsObjectNameInfoEXT object = {\r\n\t\t\tVK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT,\r\n\t\t\tnullptr, // pNext\r\n\t\t\tVK_OBJECT_TYPE_INSTANCE,\r\n\t\t\thandleToUint64(instance),\r\n\t\t\t\"instance\"\r\n\t\t};\r\n\t\tconst VkDebugUtilsMessengerCallbackDataEXT dumcd = {\r\n\t\t\tVK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CALLBACK_DATA_EXT,\r\n\t\t\tnullptr, // pNext\r\n\t\t\t0, // flags\r\n\t\t\t\"VULKAN_VALIDATION\", // VUID\r\n\t\t\t0, // VUID hash\r\n\t\t\tintroMsg,\r\n\t\t\t0, nullptr, 0, nullptr,\r\n\t\t\t1, &object\r\n\t\t};\r\n\t\tvkSubmitDebugUtilsMessageEXT( instance, VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT, VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT, &dumcd );\r\n\t}\r\n\telse if( debugExtensionTag == DebugObjectType::debugReport ){\r\n\t\tvkDebugReportMessageEXT( instance, VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_INSTANCE_EXT, (uint64_t)instance, __LINE__, uncoded, \"Application\", introMsg );\r\n\t}\r\n#endif\r\n\r\n\r\n\tconst PlatformWindow window = initWindow( ::appName, ::initialWindowWidth, ::initialWindowHeight );\r\n\tconst VkSurfaceKHR surface = initSurface( instance, window );\r\n\r\n\tconst VkPhysicalDevice physicalDevice = getPhysicalDevice( instance, surface );\r\n\tconst VkPhysicalDeviceProperties physicalDeviceProperties = getPhysicalDeviceProperties( physicalDevice );\r\n\tconst VkPhysicalDeviceMemoryProperties physicalDeviceMemoryProperties = getPhysicalDeviceMemoryProperties( physicalDevice );\r\n\r\n\tuint32_t graphicsQueueFamily, presentQueueFamily;\r\n\tstd::tie( graphicsQueueFamily, presentQueueFamily ) = getQueueFamilies( physicalDevice, surface );\r\n\r\n\tconst VkPhysicalDeviceFeatures features = {}; // don't need any special feature for this demo\r\n\tconst vector<const char*> deviceExtensions = { VK_KHR_SWAPCHAIN_EXTENSION_NAME };\r\n\r\n\tconst VkDevice device = initDevice( physicalDevice, features, graphicsQueueFamily, presentQueueFamily, requestedLayers, deviceExtensions );\r\n\tconst VkQueue graphicsQueue = getQueue( device, graphicsQueueFamily, 0 );\r\n\tconst VkQueue presentQueue = getQueue( device, presentQueueFamily, 0 );\r\n\r\n\r\n\tVkSurfaceFormatKHR surfaceFormat = getSurfaceFormat( physicalDevice, surface );\r\n\tVkRenderPass renderPass = initRenderPass( device, surfaceFormat );\r\n\r\n\tvector<uint32_t> vertexShaderBinary = {\r\n#include \"shaders/hello_triangle.vert.spv.inl\"\r\n\t};\r\n\tvector<uint32_t> fragmentShaderBinary = {\r\n#include \"shaders/hello_triangle.frag.spv.inl\"\r\n\t};\r\n\tVkShaderModule vertexShader = initShaderModule( device, vertexShaderBinary );\r\n\tVkShaderModule fragmentShader = initShaderModule( device, fragmentShaderBinary );\r\n\tVkPipelineLayout pipelineLayout = initPipelineLayout( device );\r\n\r\n\tVkBuffer vertexBuffer = initBuffer( device, sizeof( decltype( triangle )::value_type ) * triangle.size(), VK_BUFFER_USAGE_VERTEX_BUFFER_BIT );\r\n\tconst std::vector<VkMemoryPropertyFlags> memoryTypePriority{\r\n\t\tVK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, // preferably wanna device-side memory that can be updated from host without hassle\r\n\t\tVK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT // guaranteed to allways be supported\r\n\t};\r\n\tVkDeviceMemory vertexBufferMemory = initMemory<ResourceType::Buffer>(\r\n\t\tdevice,\r\n\t\tphysicalDeviceMemoryProperties,\r\n\t\tvertexBuffer,\r\n\t\tmemoryTypePriority\r\n\t);\r\n\tsetVertexData( device, vertexBufferMemory, triangle ); // Writes throug memory map. Synchronization is implicit for any subsequent vkQueueSubmit batches.\r\n\r\n\tVkCommandPool commandPool = initCommandPool( device, graphicsQueueFamily );\r\n\r\n\t// might need synchronization if init is more advanced than this\r\n\t//VkResult errorCode = vkDeviceWaitIdle( device ); RESULT_HANDLER( errorCode, \"vkDeviceWaitIdle\" );\r\n\r\n\r\n\t// place-holder swapchain dependent objects\r\n\tVkSwapchainKHR swapchain = VK_NULL_HANDLE; // has to be NULL -- signifies that there's no swapchain\r\n\tvector<VkImageView> swapchainImageViews;\r\n\tvector<VkFramebuffer> framebuffers;\r\n\r\n\tVkPipeline pipeline = VK_NULL_HANDLE; // has to be NULL for the case the app ends before even first swapchain\r\n\tvector<VkCommandBuffer> commandBuffers;\r\n\r\n\tvector<VkSemaphore> imageReadySs;\r\n\tvector<VkSemaphore> renderDoneSs;\r\n\r\n\t// workaround for validation layer \"memory leak\" + might also help the driver to cleanup old resources\r\n\t// this should not be needed for a real-word app, because they are likely to use fences naturaly (e.g. responding to user input )\r\n\t// read https://github.com/KhronosGroup/Vulkan-LoaderAndValidationLayers/issues/1628\r\n\tconst uint32_t maxInflightSubmissions = 2; // more than 2 probably does not make much sense\r\n\tuint32_t submissionNr = 0; // index of the current submission modulo maxInflightSubmission\r\n\tvector<VkFence> submissionFences;\r\n\r\n\r\n\tconst std::function<bool(void)> recreateSwapchain = [&](){\r\n\t\t// swapchain recreation -- will be done before the first frame too;\r\n\t\tTODO( \"This may be triggered from many sources (e.g. WM_SIZE event, and VK_ERROR_OUT_OF_DATE_KHR too). Should prevent duplicate swapchain recreation.\" )\r\n\r\n\t\tconst VkSwapchainKHR oldSwapchain = swapchain;\r\n\t\tswapchain = VK_NULL_HANDLE;\r\n\r\n\t\tVkSurfaceCapabilitiesKHR capabilities = getSurfaceCapabilities( physicalDevice, surface );\r\n\r\n\t\tif( capabilities.currentExtent.width == UINT32_MAX && capabilities.currentExtent.height == UINT32_MAX ){\r\n\t\t\tcapabilities.currentExtent.width = getWindowWidth( window );\r\n\t\t\tcapabilities.currentExtent.height = getWindowHeight( window );\r\n\t\t}\r\n\t\tVkExtent2D surfaceSize = { capabilities.currentExtent.width, capabilities.currentExtent.height };\r\n\r\n\t\tconst bool swapchainCreatable = {\r\n\t\t\t   surfaceSize.width >= capabilities.minImageExtent.width\r\n\t\t\t&& surfaceSize.width <= capabilities.maxImageExtent.width\r\n\t\t\t&& surfaceSize.width > 0\r\n\t\t\t&& surfaceSize.height >= capabilities.minImageExtent.height\r\n\t\t\t&& surfaceSize.height <= capabilities.maxImageExtent.height\r\n\t\t\t&& surfaceSize.height > 0\r\n\t\t};\r\n\r\n\r\n\t\t// cleanup old\r\n\t\tvector<VkSemaphore> oldImageReadySs = imageReadySs; imageReadySs.clear();\r\n\t\tif( oldSwapchain ){\r\n\t\t\t{VkResult errorCode = vkDeviceWaitIdle( device ); RESULT_HANDLER( errorCode, \"vkDeviceWaitIdle\" );}\r\n\r\n\t\t\t// fences might be in unsignaled state, so kill them too to get fresh signaled\r\n\t\t\tkillFences( device, submissionFences );\r\n\r\n\t\t\t// semaphores might be in signaled state, so kill them too to get fresh unsignaled\r\n\t\t\tkillSemaphores( device, renderDoneSs );\r\n\t\t\t// kill imageReadySs later when oldSwapchain is destroyed\r\n\r\n\t\t\t// only reset + later reuse already allocated and create new only if needed\r\n\t\t\t{VkResult errorCode = vkResetCommandPool( device, commandPool, 0 ); RESULT_HANDLER( errorCode, \"vkResetCommandPool\" );}\r\n\r\n\t\t\tkillPipeline( device, pipeline );\r\n\t\t\tkillFramebuffers( device, framebuffers );\r\n\t\t\tkillSwapchainImageViews( device, swapchainImageViews );\r\n\r\n\t\t\t// kill oldSwapchain later, after it is potentially used by vkCreateSwapchainKHR\r\n\t\t}\r\n\r\n\t\t// creating new\r\n\t\tif( swapchainCreatable ){\r\n\t\t\t// reuses & destroys the oldSwapchain\r\n\t\t\tswapchain = initSwapchain( physicalDevice, device, surface, surfaceFormat, capabilities, graphicsQueueFamily, presentQueueFamily, oldSwapchain );\r\n\r\n\t\t\tvector<VkImage> swapchainImages = enumerate<VkImage>( device, swapchain );\r\n\t\t\tswapchainImageViews = initSwapchainImageViews( device, swapchainImages, surfaceFormat.format );\r\n\t\t\tframebuffers = initFramebuffers( device, renderPass, swapchainImageViews, surfaceSize.width, surfaceSize.height );\r\n\r\n\t\t\tpipeline = initPipeline(\r\n\t\t\t\tdevice,\r\n\t\t\t\tphysicalDeviceProperties.limits,\r\n\t\t\t\tpipelineLayout,\r\n\t\t\t\trenderPass,\r\n\t\t\t\tvertexShader,\r\n\t\t\t\tfragmentShader,\r\n\t\t\t\tvertexBufferBinding,\r\n\t\t\t\tsurfaceSize.width, surfaceSize.height\r\n\t\t\t);\r\n\r\n\t\t\tacquireCommandBuffers(  device, commandPool, static_cast<uint32_t>( swapchainImages.size() ), commandBuffers  );\r\n\t\t\tfor( size_t i = 0; i < swapchainImages.size(); ++i ){\r\n\t\t\t\tbeginCommandBuffer( commandBuffers[i] );\r\n\t\t\t\t\trecordBeginRenderPass( commandBuffers[i], renderPass, framebuffers[i], ::clearColor, surfaceSize.width, surfaceSize.height );\r\n\r\n\t\t\t\t\trecordBindPipeline( commandBuffers[i], pipeline );\r\n\t\t\t\t\trecordBindVertexBuffer( commandBuffers[i], vertexBufferBinding, vertexBuffer );\r\n\r\n\t\t\t\t\trecordDraw(  commandBuffers[i], static_cast<uint32_t>( triangle.size() )  );\r\n\r\n\t\t\t\t\trecordEndRenderPass( commandBuffers[i] );\r\n\t\t\t\tendCommandBuffer( commandBuffers[i] );\r\n\t\t\t}\r\n\r\n\t\t\timageReadySs = initSemaphores( device, maxInflightSubmissions );\r\n\t\t\t// per https://github.com/KhronosGroup/Vulkan-Docs/issues/1150 need upto swapchain-image count\r\n\t\t\trenderDoneSs = initSemaphores( device, swapchainImages.size());\r\n\r\n\t\t\tsubmissionFences = initFences( device, maxInflightSubmissions, VK_FENCE_CREATE_SIGNALED_BIT ); // signaled fence means previous execution finished, so we start rendering presignaled\r\n\t\t\tsubmissionNr = 0;\r\n\t\t}\r\n\r\n\t\tif( oldSwapchain ){\r\n\t\t\tkillSwapchain( device, oldSwapchain );\r\n\r\n\t\t\t// per current spec, we can't really be sure these are not used :/ at least kill them after the swapchain\r\n\t\t\t// https://github.com/KhronosGroup/Vulkan-Docs/issues/152\r\n\t\t\tkillSemaphores( device, oldImageReadySs );\r\n\t\t}\r\n\r\n\t\treturn swapchain != VK_NULL_HANDLE;\r\n\t};\r\n\r\n\r\n\t// Finally, rendering! Yay!\r\n\tconst std::function<void(void)> render = [&](){\r\n\t\tassert( swapchain ); // should be always true; should have yielded CPU if false\r\n\r\n\t\t// vkAcquireNextImageKHR produces unsafe semaphore that needs extra cleanup. Track that with this variable.\r\n\t\tbool unsafeSemaphore = false;\r\n\r\n\t\ttry{\r\n\t\t\t// remove oldest frame from being in flight before starting new one\r\n\t\t\t// refer to doc/, which talks about the cycle of how the synch primitives are (re)used here\r\n\t\t\t{VkResult errorCode = vkWaitForFences( device, 1, &submissionFences[submissionNr], VK_TRUE, UINT64_MAX ); RESULT_HANDLER( errorCode, \"vkWaitForFences\" );}\r\n\t\t\t{VkResult errorCode = vkResetFences( device, 1, &submissionFences[submissionNr] ); RESULT_HANDLER( errorCode, \"vkResetFences\" );}\r\n\r\n\t\t\tunsafeSemaphore = true;\r\n\t\t\tuint32_t nextSwapchainImageIndex = getNextImageIndex( device, swapchain, imageReadySs[submissionNr] );\r\n\t\t\tunsafeSemaphore = false;\r\n\r\n\t\t\tsubmitToQueue( graphicsQueue, commandBuffers[nextSwapchainImageIndex], imageReadySs[submissionNr], renderDoneSs[nextSwapchainImageIndex], submissionFences[submissionNr] );\r\n\t\t\tpresent( presentQueue, swapchain, nextSwapchainImageIndex, renderDoneSs[nextSwapchainImageIndex] );\r\n\r\n\t\t\tsubmissionNr = (submissionNr + 1) % maxInflightSubmissions;\r\n\t\t}\r\n\t\tcatch( VulkanResultException ex ){\r\n\t\t\tif( ex.result == VK_SUBOPTIMAL_KHR || ex.result == VK_ERROR_OUT_OF_DATE_KHR ){\r\n\t\t\t\tif( unsafeSemaphore && ex.result == VK_SUBOPTIMAL_KHR ){\r\n\t\t\t\t\tcleanupUnsafeSemaphore( graphicsQueue, imageReadySs[submissionNr] );\r\n\t\t\t\t\t// no way to sanitize vkQueuePresentKHR semaphores, really\r\n\t\t\t\t}\r\n\t\t\t\trecreateSwapchain();\r\n\r\n\t\t\t\t// we need to start over...\r\n\t\t\t\trender();\r\n\t\t\t}\r\n\t\t\telse throw;\r\n\t\t}\r\n\t};\r\n\r\n\r\n\tsetSizeEventHandler( recreateSwapchain );\r\n\tsetPaintEventHandler( render );\r\n\r\n\r\n\t// Finally start the main message loop (and so render too)\r\n\tshowWindow( window );\r\n\tint exitStatus = messageLoop( window );\r\n\r\n\r\n\t// proper Vulkan cleanup\r\n\tVkResult errorCode = vkDeviceWaitIdle( device ); RESULT_HANDLER( errorCode, \"vkDeviceWaitIdle\" );\r\n\r\n\r\n\t// kill swapchain\r\n\tkillSemaphores( device, renderDoneSs );\r\n\t// imageReadySs killed after the swapchain\r\n\r\n\t// command buffers killed with pool\r\n\r\n\tkillPipeline( device, pipeline );\r\n\r\n\tkillFramebuffers( device, framebuffers );\r\n\r\n\tkillSwapchainImageViews( device, swapchainImageViews );\r\n\tkillSwapchain( device, swapchain );\r\n\r\n\t// per current spec, we can't really be sure these are not used :/ at least kill them after the swapchain\r\n\t// https://github.com/KhronosGroup/Vulkan-Docs/issues/152\r\n\tkillSemaphores( device, imageReadySs );\r\n\r\n\r\n\t// kill vulkan\r\n\tkillFences( device, submissionFences );\r\n\r\n\tkillCommandPool( device,  commandPool );\r\n\r\n\tkillBuffer( device, vertexBuffer );\r\n\tkillMemory( device, vertexBufferMemory );\r\n\r\n\tkillPipelineLayout( device, pipelineLayout );\r\n\tkillShaderModule( device, fragmentShader );\r\n\tkillShaderModule( device, vertexShader );\r\n\r\n\tkillRenderPass( device, renderPass );\r\n\r\n\tkillDevice( device );\r\n\r\n\tkillSurface( instance, surface );\r\n\tkillWindow( window );\r\n\r\n#if VULKAN_VALIDATION\r\n\tkillDebug( instance, debugHandle );\r\n#endif\r\n\tkillInstance( instance );\r\n\r\n\treturn exitStatus;\r\n}\r\ncatch( VulkanResultException vkE ){\r\n\tlogger << \"ERROR: Terminated due to an uncaught VkResult exception: \"\r\n\t       << vkE.file << \":\" << vkE.line << \":\" << vkE.func << \"() \" << vkE.source << \"() returned \" << to_string( vkE.result )\r\n\t       << std::endl;\r\n\treturn EXIT_FAILURE;\r\n}\r\ncatch( const char* e ){\r\n\tlogger << \"ERROR: Terminated due to an uncaught exception: \" << e << std::endl;\r\n\treturn EXIT_FAILURE;\r\n}\r\ncatch( string e ){\r\n\tlogger << \"ERROR: Terminated due to an uncaught exception: \" << e << std::endl;\r\n\treturn EXIT_FAILURE;\r\n}\r\ncatch( std::exception e ){\r\n\tlogger << \"ERROR: Terminated due to an uncaught exception: \" << e.what() << std::endl;\r\n\treturn EXIT_FAILURE;\r\n}\r\ncatch( ... ){\r\n\tlogger << \"ERROR: Terminated due to an unrecognized uncaught exception.\" << std::endl;\r\n\treturn EXIT_FAILURE;\r\n}\r\n\r\n\r\n#if defined(_WIN32) && !defined(_CONSOLE)\r\nint WINAPI WinMain( HINSTANCE, HINSTANCE, LPSTR, int ){\r\n\treturn helloTriangle();\r\n}\r\n#else\r\nint main(){\r\n\treturn helloTriangle();\r\n}\r\n#endif\r\n\r\n// Implementation\r\n//////////////////////////////////////////////////////////////////////////////////\r\n\r\nbool isLayerSupported( const char* layer, const vector<VkLayerProperties>& supportedLayers ){\r\n\tconst auto isSupportedPred = [layer]( const VkLayerProperties& prop ) -> bool{\r\n\t\treturn std::strcmp( layer, prop.layerName ) == 0;\r\n\t};\r\n\r\n\treturn std::any_of( supportedLayers.begin(), supportedLayers.end(), isSupportedPred );\r\n}\r\n\r\nbool isExtensionSupported( const char* extension, const vector<VkExtensionProperties>& supportedExtensions ){\r\n\tconst auto isSupportedPred = [extension]( const VkExtensionProperties& prop ) -> bool{\r\n\t\treturn std::strcmp( extension, prop.extensionName ) == 0;\r\n\t};\r\n\r\n\treturn std::any_of( supportedExtensions.begin(), supportedExtensions.end(), isSupportedPred );\r\n}\r\n\r\nvector<const char*> checkInstanceLayerSupport( const vector<const char*>& requestedLayers, const vector<VkLayerProperties>& supportedLayers ){\r\n\tvector<const char*> compiledLayerList;\r\n\r\n\tfor( const auto layer : requestedLayers ){\r\n\t\tif(  isLayerSupported( layer, supportedLayers )  ) compiledLayerList.push_back( layer );\r\n\t\telse logger << \"WARNING: Requested layer \" << layer << \" is not supported. It will not be enabled.\" << std::endl;\r\n\t}\r\n\r\n\treturn compiledLayerList;\r\n}\r\n\r\nvector<const char*> checkInstanceLayerSupport( const vector<const char*>& optionalLayers ){\r\n\treturn checkInstanceLayerSupport( optionalLayers, enumerate<VkInstance, VkLayerProperties>() );\r\n}\r\n\r\nvector<VkExtensionProperties> getSupportedInstanceExtensions( const vector<const char*>& providingLayers ){\r\n\tauto supportedExtensions = enumerate<VkInstance, VkExtensionProperties>();\r\n\r\n\tfor( const auto pl : providingLayers ){\r\n\t\tconst auto providedExtensions = enumerate<VkInstance, VkExtensionProperties>( pl );\r\n\t\tsupportedExtensions.insert( supportedExtensions.end(), providedExtensions.begin(), providedExtensions.end() );\r\n\t}\r\n\r\n\treturn supportedExtensions;\r\n}\r\n\r\nvector<VkExtensionProperties> getSupportedDeviceExtensions( const VkPhysicalDevice physDevice, const vector<const char*>& providingLayers ){\r\n\tauto supportedExtensions = enumerate<VkExtensionProperties>( physDevice );\r\n\r\n\tfor( const auto pl : providingLayers ){\r\n\t\tconst auto providedExtensions = enumerate<VkExtensionProperties>( physDevice, pl );\r\n\t\tsupportedExtensions.insert( supportedExtensions.end(), providedExtensions.begin(), providedExtensions.end() );\r\n\t}\r\n\r\n\treturn supportedExtensions;\r\n}\r\n\r\nbool checkExtensionSupport( const vector<const char*>& extensions, const vector<VkExtensionProperties>& supportedExtensions ){\r\n\tbool allSupported = true;\r\n\r\n\tfor( const auto extension : extensions ){\r\n\t\tif(  !isExtensionSupported( extension, supportedExtensions )  ){\r\n\t\t\tallSupported = false;\r\n\t\t\tlogger << \"WARNING: Requested extension \" << extension << \" is not supported. Trying to enable it will likely fail.\" << std::endl;\r\n\t\t}\r\n\t}\r\n\r\n\treturn allSupported;\r\n}\r\n\r\nbool checkDeviceExtensionSupport( const VkPhysicalDevice physDevice, const vector<const char*>& extensions, const vector<const char*>& providingLayers ){\r\n\treturn checkExtensionSupport(  extensions, getSupportedDeviceExtensions( physDevice, providingLayers )  );\r\n}\r\n\r\nVkInstance initInstance( const vector<const char*>& layers, const vector<const char*>& extensions ){\r\n\tconst VkApplicationInfo appInfo = {\r\n\t\tVK_STRUCTURE_TYPE_APPLICATION_INFO,\r\n\t\tnullptr, // pNext\r\n\t\t::appName, // Nice to meetcha, and what's your name driver?\r\n\t\t0, // app version\r\n\t\tnullptr, // engine name\r\n\t\t0, // engine version\r\n\t\tVK_API_VERSION_1_0 // this app is written against the Vulkan 1.0 spec\r\n\t};\r\n\r\n#if VULKAN_VALIDATION\r\n\t// in effect during vkCreateInstance and vkDestroyInstance duration (because callback object cannot be created without instance)\r\n\tconst VkDebugReportCallbackCreateInfoEXT debugReportCreateInfo{\r\n\t\tVK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT,\r\n\t\tnullptr, // pNext\r\n\t\ttranslateFlags( ::debugSeverity, ::debugType ),\r\n\t\t::genericDebugReportCallback,\r\n\t\tnullptr // pUserData\r\n\t};\r\n\r\n\tconst VkDebugUtilsMessengerCreateInfoEXT debugUtilsCreateInfo = {\r\n\t\tVK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT,\r\n\t\tnullptr, // pNext\r\n\t\t0, // flags\r\n\t\tdebugSeverity,\r\n\t\tdebugType,\r\n\t\t::genericDebugUtilsCallback,\r\n\t\tnullptr // pUserData\r\n\t};\r\n\r\n\tbool debugUtils = std::find_if( extensions.begin(), extensions.end(), [](const char* e){ return std::strcmp( e, VK_EXT_DEBUG_UTILS_EXTENSION_NAME ) == 0; } ) != extensions.end();\r\n\tbool debugReport = std::find_if( extensions.begin(), extensions.end(), [](const char* e){ return std::strcmp( e, VK_EXT_DEBUG_REPORT_EXTENSION_NAME ) == 0; } ) != extensions.end();\r\n\tif( !debugUtils && !debugReport ) throw \"VULKAN_VALIDATION is enabled but neither VK_EXT_debug_utils nor VK_EXT_debug_report extension is being enabled!\";\r\n\tconst void* debugpNext = debugUtils ? (void*)&debugUtilsCreateInfo : (void*)&debugReportCreateInfo;\r\n#endif\r\n\r\n\tconst VkInstanceCreateInfo instanceInfo{\r\n\t\tVK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,\r\n#if VULKAN_VALIDATION\r\n\t\tdebugpNext,\r\n#else\r\n\t\tnullptr, // pNext\r\n#endif\r\n\t\t0, // flags - reserved for future use\r\n\t\t&appInfo,\r\n\t\tstatic_cast<uint32_t>( layers.size() ),\r\n\t\tlayers.data(),\r\n\t\tstatic_cast<uint32_t>( extensions.size() ),\r\n\t\textensions.data()\r\n\t};\r\n\r\n\tVkInstance instance;\r\n\tconst VkResult errorCode = vkCreateInstance( &instanceInfo, nullptr, &instance ); RESULT_HANDLER( errorCode, \"vkCreateInstance\" );\r\n\r\n\tloadInstanceExtensionsCommands( instance, extensions );\r\n\r\n\treturn instance;\r\n}\r\n\r\nvoid killInstance( const VkInstance instance ){\r\n\tunloadInstanceExtensionsCommands( instance );\r\n\r\n\tvkDestroyInstance( instance, nullptr );\r\n}\r\n\r\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n\r\nbool isPresentationSupported( const VkPhysicalDevice physDevice, const uint32_t queueFamily, const VkSurfaceKHR surface ){\r\n\tVkBool32 supported;\r\n\tconst VkResult errorCode = vkGetPhysicalDeviceSurfaceSupportKHR( physDevice, queueFamily, surface, &supported ); RESULT_HANDLER( errorCode, \"vkGetPhysicalDeviceSurfaceSupportKHR\" );\r\n\r\n\treturn supported == VK_TRUE;\r\n}\r\n\r\nbool isPresentationSupported( const VkPhysicalDevice physDevice, const VkSurfaceKHR surface ){\r\n\tuint32_t qfCount;\r\n\tvkGetPhysicalDeviceQueueFamilyProperties( physDevice, &qfCount, nullptr );\r\n\r\n\tfor( uint32_t qf = 0; qf < qfCount; ++qf ){\r\n\t\tif(  isPresentationSupported( physDevice, qf, surface )  ) return true;\r\n\t}\r\n\r\n\treturn false;\r\n}\r\n\r\nVkPhysicalDevice getPhysicalDevice( const VkInstance instance, const VkSurfaceKHR surface ){\r\n\tvector<VkPhysicalDevice> devices = enumerate<VkPhysicalDevice>( instance );\r\n\r\n\tif( surface ){\r\n\t\tfor( auto it = devices.begin(); it != devices.end(); ){\r\n\t\t\tconst auto& pd = *it;\r\n\r\n\t\t\tif(  !isPresentationSupported( pd, surface )  ) it = devices.erase( it );\r\n\t\t\telse ++it;\r\n\t\t}\r\n\t}\r\n\r\n\tif( devices.empty() ) throw string(\"ERROR: No Physical Devices (GPUs) \") + (surface ? \"with presentation support \" : \"\") + \"detected!\";\r\n\telse if( devices.size() == 1 ){\r\n\t\treturn devices[0];\r\n\t}\r\n\telse{\r\n\t\tfor( const auto pd : devices ){\r\n\t\t\tconst VkPhysicalDeviceProperties pdp = getPhysicalDeviceProperties( pd );\r\n\r\n\t\t\tif( pdp.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU ){\r\n#if VULKAN_VALIDATION\r\n\t\t\t\tvkDebugReportMessageEXT(\r\n\t\t\t\t\tinstance, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_INSTANCE_EXT, handleToUint64(instance), __LINE__, \r\n\t\t\t\t\t1, u8\"application\", u8\"More than one Physical Devices (GPU) found. Choosing the first dedicated one.\"\r\n\t\t\t\t);\r\n#endif\r\n\r\n\t\t\t\treturn pd;\r\n\t\t\t}\r\n\t\t}\r\n\r\n#if VULKAN_VALIDATION\r\n\t\tvkDebugReportMessageEXT(\r\n\t\t\tinstance, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_INSTANCE_EXT, handleToUint64(instance), __LINE__, \r\n\t\t\t1, u8\"application\", u8\"More than one Physical Devices (GPU) found. Just choosing the first one.\"\r\n\t\t);\r\n#endif\r\n\r\n\t\treturn devices[0];\r\n\t}\r\n}\r\n\r\nVkPhysicalDeviceProperties getPhysicalDeviceProperties( VkPhysicalDevice physicalDevice ){\r\n\tVkPhysicalDeviceProperties properties;\r\n\tvkGetPhysicalDeviceProperties( physicalDevice, &properties );\r\n\treturn properties;\r\n}\r\n\r\nVkPhysicalDeviceMemoryProperties getPhysicalDeviceMemoryProperties( VkPhysicalDevice physicalDevice ){\r\n\tVkPhysicalDeviceMemoryProperties memoryInfo;\r\n\tvkGetPhysicalDeviceMemoryProperties( physicalDevice, &memoryInfo );\r\n\treturn memoryInfo;\r\n}\r\n\r\nvector<VkQueueFamilyProperties> getQueueFamilyProperties( VkPhysicalDevice device ){\r\n\tuint32_t queueFamiliesCount;\r\n\tvkGetPhysicalDeviceQueueFamilyProperties( device, &queueFamiliesCount, nullptr );\r\n\r\n\tvector<VkQueueFamilyProperties> queueFamilies( queueFamiliesCount );\r\n\tvkGetPhysicalDeviceQueueFamilyProperties( device, &queueFamiliesCount, queueFamilies.data() );\r\n\r\n\treturn queueFamilies;\r\n}\r\n\r\nstd::pair<uint32_t, uint32_t> getQueueFamilies( const VkPhysicalDevice physDevice, const VkSurfaceKHR surface ){\r\n\tconstexpr uint32_t notFound = VK_QUEUE_FAMILY_IGNORED;\r\n\tconst auto qfps = getQueueFamilyProperties( physDevice );\r\n\tconst auto findQueueFamilyThat = [&qfps, notFound](std::function<bool (const VkQueueFamilyProperties&, const uint32_t)> predicate) -> uint32_t{\r\n\t\tfor( uint32_t qf = 0; qf < qfps.size(); ++qf ) if( predicate(qfps[qf], qf) ) return qf;\r\n\t\treturn notFound;\r\n\t};\r\n\r\n\tconst auto isGraphics = [](const VkQueueFamilyProperties& props, const uint32_t = 0){\r\n\t\treturn props.queueFlags & VK_QUEUE_GRAPHICS_BIT;\r\n\t};\r\n\tconst auto isPresent = [=](const VkQueueFamilyProperties&, const uint32_t queueFamily){\r\n\t\treturn isPresentationSupported( physDevice, queueFamily, surface );\r\n\t};\r\n\tconst auto isFusedGraphicsAndPresent = [=](const VkQueueFamilyProperties& props, const uint32_t queueFamily){\r\n\t\treturn isGraphics( props ) && isPresent( props, queueFamily );\r\n\t};\r\n\r\n\tuint32_t graphicsQueueFamily = notFound;\r\n\tuint32_t presentQueueFamily = notFound;\r\n\tif( ::forceSeparatePresentQueue ){\r\n\t\tgraphicsQueueFamily = findQueueFamilyThat( isGraphics );\r\n\r\n\t\tconst auto isSeparatePresent = [graphicsQueueFamily, isPresent](const VkQueueFamilyProperties& props, const uint32_t queueFamily){\r\n\t\t\treturn queueFamily != graphicsQueueFamily && isPresent( props, queueFamily );\r\n\t\t};\r\n\t\tpresentQueueFamily = findQueueFamilyThat( isSeparatePresent );\r\n\t}\r\n\telse{\r\n\t\tgraphicsQueueFamily = presentQueueFamily = findQueueFamilyThat( isFusedGraphicsAndPresent );\r\n\t\tif( graphicsQueueFamily == notFound || presentQueueFamily == notFound ){\r\n\t\t\tgraphicsQueueFamily = findQueueFamilyThat( isGraphics );\r\n\t\t\tpresentQueueFamily = findQueueFamilyThat( isPresent );\r\n\t\t}\r\n\t}\r\n\r\n\tif( graphicsQueueFamily == notFound ) throw \"Cannot find a graphics queue family!\";\r\n\tif( presentQueueFamily == notFound ) throw \"Cannot find a presentation queue family!\";\r\n\r\n\treturn std::make_pair( graphicsQueueFamily, presentQueueFamily );\r\n}\r\n\r\nVkDevice initDevice(\r\n\tconst VkPhysicalDevice physDevice,\r\n\tconst VkPhysicalDeviceFeatures& features,\r\n\tconst uint32_t graphicsQueueFamily,\r\n\tconst uint32_t presentQueueFamily,\r\n\tconst vector<const char*>& layers,\r\n\tconst vector<const char*>& extensions\r\n){\r\n\tcheckDeviceExtensionSupport( physDevice, extensions, layers );\r\n\r\n\tconst float priority[] = {1.0f};\r\n\r\n\tvector<VkDeviceQueueCreateInfo> queues = {\r\n\t\t{\r\n\t\t\tVK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,\r\n\t\t\tnullptr, // pNext\r\n\t\t\t0, // flags\r\n\t\t\tgraphicsQueueFamily,\r\n\t\t\t1, // queue count\r\n\t\t\tpriority\r\n\t\t}\r\n\t};\r\n\r\n\tif( presentQueueFamily != graphicsQueueFamily ){\r\n\t\tqueues.push_back({\r\n\t\t\tVK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,\r\n\t\t\tnullptr, // pNext\r\n\t\t\t0, // flags\r\n\t\t\tpresentQueueFamily,\r\n\t\t\t1, // queue count\r\n\t\t\tpriority\r\n\t\t});\r\n\t}\r\n\r\n\tconst VkDeviceCreateInfo deviceInfo{\r\n\t\tVK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,\r\n\t\tnullptr, // pNext\r\n\t\t0, // flags\r\n\t\tstatic_cast<uint32_t>( queues.size() ),\r\n\t\tqueues.data(),\r\n\t\tstatic_cast<uint32_t>( layers.size() ),\r\n\t\tlayers.data(),\r\n\t\tstatic_cast<uint32_t>( extensions.size() ),\r\n\t\textensions.data(),\r\n\t\t&features\r\n\t};\r\n\r\n\r\n\tVkDevice device;\r\n\tconst VkResult errorCode = vkCreateDevice( physDevice, &deviceInfo, nullptr, &device ); RESULT_HANDLER( errorCode, \"vkCreateDevice\" );\r\n\r\n\tloadDeviceExtensionsCommands( device, extensions );\r\n\r\n\treturn device;\r\n}\r\n\r\nvoid killDevice( const VkDevice device ){\r\n\tunloadDeviceExtensionsCommands( device );\r\n\r\n\tvkDestroyDevice( device, nullptr );\r\n}\r\n\r\nVkQueue getQueue( const VkDevice device, const uint32_t queueFamily, const uint32_t queueIndex ){\r\n\tVkQueue queue;\r\n\tvkGetDeviceQueue( device, queueFamily, queueIndex, &queue );\r\n\r\n\treturn queue;\r\n}\r\n\r\n/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\ntemplate< ResourceType resourceType, class T >\r\nVkMemoryRequirements getMemoryRequirements( VkDevice device, T resource );\r\n\r\ntemplate<>\r\nVkMemoryRequirements getMemoryRequirements< ResourceType::Buffer >( VkDevice device, VkBuffer buffer ){\r\n\tVkMemoryRequirements memoryRequirements;\r\n\tvkGetBufferMemoryRequirements( device, buffer, &memoryRequirements );\r\n\r\n\treturn memoryRequirements;\r\n}\r\n\r\ntemplate<>\r\nVkMemoryRequirements getMemoryRequirements< ResourceType::Image >( VkDevice device, VkImage image ){\r\n\tVkMemoryRequirements memoryRequirements;\r\n\tvkGetImageMemoryRequirements( device, image, &memoryRequirements );\r\n\r\n\treturn memoryRequirements;\r\n}\r\n\r\ntemplate< ResourceType resourceType, class T >\r\nvoid bindMemory( VkDevice device, T buffer, VkDeviceMemory memory, VkDeviceSize offset );\r\n\r\ntemplate<>\r\nvoid bindMemory< ResourceType::Buffer >( VkDevice device, VkBuffer buffer, VkDeviceMemory memory, VkDeviceSize offset ){\r\n\tVkResult errorCode = vkBindBufferMemory( device, buffer, memory, offset ); RESULT_HANDLER( errorCode, \"vkBindBufferMemory\" );\r\n}\r\n\r\ntemplate<>\r\nvoid bindMemory< ResourceType::Image >( VkDevice device, VkImage image, VkDeviceMemory memory, VkDeviceSize offset ){\r\n\tVkResult errorCode = vkBindImageMemory( device, image, memory, offset ); RESULT_HANDLER( errorCode, \"vkBindImageMemory\" );\r\n}\r\n\r\ntemplate< ResourceType resourceType, class T >\r\nVkDeviceMemory initMemory(\r\n\tVkDevice device,\r\n\tVkPhysicalDeviceMemoryProperties physicalDeviceMemoryProperties,\r\n\tT resource,\r\n\tconst std::vector<VkMemoryPropertyFlags>& memoryTypePriority\r\n){\r\n\tconst VkMemoryRequirements memoryRequirements = getMemoryRequirements<resourceType>( device, resource );\r\n\r\n\tconst auto indexToBit = []( const uint32_t index ){ return 0x1 << index; };\r\n\r\n\tconst uint32_t memoryTypeNotFound = UINT32_MAX;\r\n\tuint32_t memoryType = memoryTypeNotFound;\r\n\tfor( const auto desiredMemoryType : memoryTypePriority ){\r\n\t\tconst uint32_t maxMemoryTypeCount = 32;\r\n\t\tfor( uint32_t i = 0; memoryType == memoryTypeNotFound && i < maxMemoryTypeCount; ++i ){\r\n\t\t\tif( memoryRequirements.memoryTypeBits & indexToBit(i) ){\r\n\t\t\t\tif( (physicalDeviceMemoryProperties.memoryTypes[i].propertyFlags & desiredMemoryType) == desiredMemoryType ){\r\n\t\t\t\t\tmemoryType = i;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tif( memoryType == memoryTypeNotFound ) throw \"Can't find compatible mappable memory for the resource\";\r\n\r\n\tVkMemoryAllocateInfo memoryInfo{\r\n\t\tVK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,\r\n\t\tnullptr, // pNext\r\n\t\tmemoryRequirements.size,\r\n\t\tmemoryType\r\n\t};\r\n\r\n\tVkDeviceMemory memory;\r\n\tVkResult errorCode = vkAllocateMemory( device, &memoryInfo, nullptr, &memory ); RESULT_HANDLER( errorCode, \"vkAllocateMemory\" );\r\n\r\n\tbindMemory<resourceType>( device, resource, memory, 0 /*offset*/ );\r\n\r\n\treturn memory;\r\n}\r\n\r\nvoid setMemoryData( VkDevice device, VkDeviceMemory memory, void* begin, size_t size ){\r\n\tvoid* data;\r\n\tVkResult errorCode = vkMapMemory( device, memory, 0 /*offset*/, VK_WHOLE_SIZE, 0 /*flags - reserved*/, &data ); RESULT_HANDLER( errorCode, \"vkMapMemory\" );\r\n\tmemcpy( data, begin, size );\r\n\tvkUnmapMemory( device, memory );\r\n}\r\n\r\nvoid killMemory( VkDevice device, VkDeviceMemory memory ){\r\n\tvkFreeMemory( device, memory, nullptr );\r\n}\r\n\r\n\r\nVkBuffer initBuffer( VkDevice device, VkDeviceSize size, VkBufferUsageFlags usage ){\r\n\tVkBufferCreateInfo bufferInfo{\r\n\t\tVK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,\r\n\t\tnullptr, // pNext\r\n\t\t0, // flags\r\n\t\tsize,\r\n\t\tusage,\r\n\t\tVK_SHARING_MODE_EXCLUSIVE,\r\n\t\t0, // queue family count -- ignored for EXCLUSIVE\r\n\t\tnullptr // queue families -- ignored for EXCLUSIVE\r\n\t};\r\n\r\n\tVkBuffer buffer;\r\n\tVkResult errorCode = vkCreateBuffer( device, &bufferInfo, nullptr, &buffer ); RESULT_HANDLER( errorCode, \"vkCreateBuffer\" );\r\n\treturn buffer;\r\n}\r\n\r\nvoid killBuffer( VkDevice device, VkBuffer buffer ){\r\n\tvkDestroyBuffer( device, buffer, nullptr );\r\n}\r\n\r\nVkImage initImage( VkDevice device, VkFormat format, uint32_t width, uint32_t height, VkSampleCountFlagBits samples, VkImageUsageFlags usage ){\r\n\tVkExtent3D size{\r\n\t\twidth,\r\n\t\theight,\r\n\t\t1 // depth\r\n\t};\r\n\r\n\tVkImageCreateInfo ici{\r\n\t\tVK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,\r\n\t\tnullptr, // pNext\r\n\t\t0, // flags\r\n\t\tVK_IMAGE_TYPE_2D,\r\n\t\tformat,\r\n\t\tsize,\r\n\t\t1, // mipLevels\r\n\t\t1, // arrayLayers\r\n\t\tsamples,\r\n\t\tVK_IMAGE_TILING_OPTIMAL,\r\n\t\tusage,\r\n\t\tVK_SHARING_MODE_EXCLUSIVE,\r\n\t\t0, // queueFamilyIndexCount -- ignored for EXCLUSIVE\r\n\t\tnullptr, // pQueueFamilyIndices -- ignored for EXCLUSIVE\r\n\t\tVK_IMAGE_LAYOUT_UNDEFINED\r\n\t};\r\n\r\n\tVkImage image;\r\n\tVkResult errorCode = vkCreateImage( device, &ici, nullptr, &image ); RESULT_HANDLER( errorCode, \"vkCreateImage\" );\r\n\r\n\treturn image;\r\n}\r\n\r\nvoid killImage( VkDevice device, VkImage image ){\r\n\tvkDestroyImage( device, image, nullptr );\r\n}\r\n\r\nVkImageView initImageView( VkDevice device, VkImage image, VkFormat format ){\r\n\tVkImageViewCreateInfo iciv{\r\n\t\tVK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,\r\n\t\tnullptr, // pNext\r\n\t\t0, // flags\r\n\t\timage,\r\n\t\tVK_IMAGE_VIEW_TYPE_2D,\r\n\t\tformat,\r\n\t\t{ VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY },\r\n\t\t{\r\n\t\t\tVK_IMAGE_ASPECT_COLOR_BIT,\r\n\t\t\t0, // base mip-level\r\n\t\t\tVK_REMAINING_MIP_LEVELS, // level count\r\n\t\t\t0, // base array layer\r\n\t\t\tVK_REMAINING_ARRAY_LAYERS // array layer count\r\n\t\t}\r\n\t};\r\n\r\n\tVkImageView imageView;\r\n\tVkResult errorCode = vkCreateImageView( device, &iciv, nullptr, &imageView ); RESULT_HANDLER( errorCode, \"vkCreateImageView\" );\r\n\r\n\treturn imageView;\r\n}\r\n\r\nvoid killImageView( VkDevice device, VkImageView imageView ){\r\n\tvkDestroyImageView( device, imageView, nullptr );\r\n}\r\n\r\n/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n\r\n// initSurface is platform dependent\r\n\r\nvoid killSurface( VkInstance instance, VkSurfaceKHR surface ){\r\n\tvkDestroySurfaceKHR( instance, surface, nullptr );\r\n}\r\n\r\nVkSurfaceFormatKHR getSurfaceFormat( VkPhysicalDevice physicalDevice, VkSurfaceKHR surface ){\r\n\tconst VkFormat preferredFormat1 = VK_FORMAT_B8G8R8A8_UNORM; \r\n\tconst VkFormat preferredFormat2 = VK_FORMAT_B8G8R8A8_SRGB;\r\n\r\n\tvector<VkSurfaceFormatKHR> formats = enumerate<VkSurfaceFormatKHR>( physicalDevice, surface );\r\n\r\n\tif( formats.empty() ) throw \"No surface formats offered by Vulkan!\";\r\n\r\n\tif( formats.size() == 1 && formats[0].format == VK_FORMAT_UNDEFINED ){\r\n\t\tformats[0].format = preferredFormat1;\r\n\t}\r\n\r\n\tVkSurfaceFormatKHR chosenFormat1 = {VK_FORMAT_UNDEFINED};\r\n\tVkSurfaceFormatKHR chosenFormat2 = {VK_FORMAT_UNDEFINED};\r\n\r\n\tfor( auto f : formats ){\r\n\t\tif( f.format == preferredFormat1 ){\r\n\t\t\tchosenFormat1 = f;\r\n\t\t\tbreak;\r\n\t\t}\r\n\r\n\t\tif( f.format == preferredFormat2 ){\r\n\t\t\tchosenFormat2 = f;\r\n\t\t}\r\n\t}\r\n\r\n\tif( chosenFormat1.format ) return chosenFormat1;\r\n\telse if( chosenFormat2.format ) return chosenFormat2;\r\n\telse return formats[0];\r\n}\r\n\r\nVkSurfaceCapabilitiesKHR getSurfaceCapabilities( VkPhysicalDevice physicalDevice, VkSurfaceKHR surface ){\r\n\tVkSurfaceCapabilitiesKHR capabilities;\r\n\tVkResult errorCode = vkGetPhysicalDeviceSurfaceCapabilitiesKHR( physicalDevice, surface, &capabilities ); RESULT_HANDLER( errorCode, \"vkGetPhysicalDeviceSurfaceCapabilitiesKHR\" );\r\n\r\n\treturn capabilities;\r\n}\r\n\r\nint selectedMode = 0;\r\n\r\nTODO( \"Could use debug_report instead of log\" )\r\nVkPresentModeKHR getSurfacePresentMode( VkPhysicalDevice physicalDevice, VkSurfaceKHR surface ){\r\n\tvector<VkPresentModeKHR> modes = enumerate<VkPresentModeKHR>( physicalDevice, surface );\r\n\r\n\tfor( auto m : modes ){\r\n\t\tif( m == ::presentMode ){\r\n\t\t\tif( selectedMode != 0 ){\r\n\t\t\t\tlogger << \"INFO: Your preferred present mode became supported. Switching to it.\\n\";\r\n\t\t\t}\r\n\r\n\t\t\tselectedMode = 0;\r\n\t\t\treturn m;\r\n\t\t}\r\n\t}\r\n\r\n\tfor( auto m : modes ){\r\n\t\tif( m == VK_PRESENT_MODE_FIFO_KHR ){\r\n\t\t\tif( selectedMode != 1 ){\r\n\t\t\t\tlogger << \"WARNING: Your preferred present mode is not supported. Switching to VK_PRESENT_MODE_FIFO_KHR.\\n\";\r\n\t\t\t}\r\n\r\n\t\t\tselectedMode = 1;\r\n\t\t\treturn m;\r\n\t\t}\r\n\t}\r\n\r\n\tTODO( \"Workaround for bad (Intel Linux Mesa) drivers\" )\r\n\tif( modes.empty() ) throw \"Bugged driver reports no supported present modes.\";\r\n\telse{\r\n\t\tif( selectedMode != 2 ){\r\n\t\t\tlogger << \"WARNING: Bugged drivers. VK_PRESENT_MODE_FIFO_KHR not supported. Switching to whatever is.\\n\";\r\n\t\t}\r\n\r\n\t\tselectedMode = 2;\r\n\t\treturn modes[0];\r\n\t}\r\n}\r\n\r\nVkSwapchainKHR initSwapchain(\r\n\tVkPhysicalDevice physicalDevice,\r\n\tVkDevice device,\r\n\tVkSurfaceKHR surface,\r\n\tVkSurfaceFormatKHR surfaceFormat,\r\n\tVkSurfaceCapabilitiesKHR capabilities,\r\n\tuint32_t graphicsQueueFamily,\r\n\tuint32_t presentQueueFamily,\r\n\tVkSwapchainKHR oldSwapchain\r\n){\r\n\t// we don't care as we are always setting alpha to 1.0\r\n\tVkCompositeAlphaFlagBitsKHR compositeAlphaFlag;\r\n\tif( capabilities.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR ) compositeAlphaFlag = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;\r\n\telse if( capabilities.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR ) compositeAlphaFlag = VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR;\r\n\telse if( capabilities.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR ) compositeAlphaFlag = VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR;\r\n\telse if( capabilities.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR ) compositeAlphaFlag = VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR;\r\n\telse throw \"Unknown composite alpha reported.\";\r\n\r\n\t// minImageCount + 1 seems a sensible default. It means 2 images should always be readily available without blocking. May lead to memory waste though if we care about that.\r\n\tuint32_t myMinImageCount = capabilities.minImageCount + 1;\r\n\tif( capabilities.maxImageCount ) myMinImageCount = std::min<uint32_t>( myMinImageCount, capabilities.maxImageCount );\r\n\r\n\tstd::vector<uint32_t> queueFamilies = { graphicsQueueFamily };\r\n\tif(graphicsQueueFamily != presentQueueFamily) queueFamilies.push_back( presentQueueFamily );\r\n\r\n\tVkSwapchainCreateInfoKHR swapchainInfo{\r\n\t\tVK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,\r\n\t\tnullptr, // pNext for extensions use\r\n\t\t0, // flags - reserved for future use\r\n\t\tsurface,\r\n\t\tmyMinImageCount, // minImageCount\r\n\t\tsurfaceFormat.format,\r\n\t\tsurfaceFormat.colorSpace,\r\n\t\tcapabilities.currentExtent,\r\n\t\t1,\r\n\t\tVK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, // VkImage usage flags\r\n\t\t// It should be fine to just use CONCURRENT in the off chance we encounter the elusive GPU with separate present queue\r\n\t\tqueueFamilies.size() > 1 ? VK_SHARING_MODE_CONCURRENT : VK_SHARING_MODE_EXCLUSIVE,\r\n\t\tstatic_cast<uint32_t>( queueFamilies.size() ),\r\n\t\tqueueFamilies.data(),\r\n\t\tcapabilities.currentTransform,\r\n\t\tcompositeAlphaFlag,\r\n\t\tgetSurfacePresentMode( physicalDevice, surface ),\r\n\t\tVK_TRUE, // clipped\r\n\t\toldSwapchain\r\n\t};\r\n\r\n\tVkSwapchainKHR swapchain;\r\n\tVkResult errorCode = vkCreateSwapchainKHR( device, &swapchainInfo, nullptr, &swapchain ); RESULT_HANDLER( errorCode, \"vkCreateSwapchainKHR\" );\r\n\r\n\treturn swapchain;\r\n}\r\n\r\nvoid killSwapchain( VkDevice device, VkSwapchainKHR swapchain ){\r\n\tvkDestroySwapchainKHR( device, swapchain, nullptr );\r\n}\r\n\r\nuint32_t getNextImageIndex( VkDevice device, VkSwapchainKHR swapchain, VkSemaphore imageReadyS ){\r\n\tuint32_t nextImageIndex;\r\n\tVkResult errorCode = vkAcquireNextImageKHR(\r\n\t\tdevice,\r\n\t\tswapchain,\r\n\t\tUINT64_MAX /* no timeout */,\r\n\t\timageReadyS,\r\n\t\tVK_NULL_HANDLE,\r\n\t\t&nextImageIndex\r\n\t); RESULT_HANDLER( errorCode, \"vkAcquireNextImageKHR\" );\r\n\r\n\treturn nextImageIndex;\r\n}\r\n\r\nvector<VkImageView> initSwapchainImageViews( VkDevice device, vector<VkImage> images, VkFormat format ){\r\n\tvector<VkImageView> imageViews;\r\n\r\n\tfor( auto image : images ){\r\n\t\tVkImageView imageView = initImageView( device, image, format );\r\n\r\n\t\timageViews.push_back( imageView );\r\n\t}\r\n\r\n\treturn imageViews;\r\n}\r\n\r\nvoid killSwapchainImageViews( VkDevice device, vector<VkImageView>& imageViews ){\r\n\tfor( auto imageView : imageViews ) vkDestroyImageView( device, imageView, nullptr );\r\n\timageViews.clear();\r\n}\r\n\r\n///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n\r\nVkRenderPass initRenderPass( VkDevice device, VkSurfaceFormatKHR surfaceFormat ){\r\n\tVkAttachmentDescription colorAtachment{\r\n\t\t0, // flags\r\n\t\tsurfaceFormat.format,\r\n\t\tVK_SAMPLE_COUNT_1_BIT,\r\n\t\tVK_ATTACHMENT_LOAD_OP_CLEAR, // color + depth\r\n\t\tVK_ATTACHMENT_STORE_OP_STORE, // color + depth\r\n\t\tVK_ATTACHMENT_LOAD_OP_DONT_CARE, // stencil\r\n\t\tVK_ATTACHMENT_STORE_OP_DONT_CARE, // stencil\r\n\t\tVK_IMAGE_LAYOUT_UNDEFINED,\r\n\t\tVK_IMAGE_LAYOUT_PRESENT_SRC_KHR\r\n\t};\r\n\r\n\tVkAttachmentReference colorReference{\r\n\t\t0, // attachment\r\n\t\tVK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL\r\n\t};\r\n\r\n\tVkSubpassDescription subpass{\r\n\t\t0, // flags - reserved for future use\r\n\t\tVK_PIPELINE_BIND_POINT_GRAPHICS,\r\n\t\t0, // input attachment count\r\n\t\tnullptr, // input attachments\r\n\t\t1, // color attachment count\r\n\t\t&colorReference, // color attachments\r\n\t\tnullptr, // resolve attachments\r\n\t\tnullptr, // depth stencil attachment\r\n\t\t0, // preserve attachment count\r\n\t\tnullptr // preserve attachments\r\n\t};\r\n\r\n\tVkSubpassDependency srcDependency{\r\n\t\tVK_SUBPASS_EXTERNAL, // srcSubpass\r\n\t\t0, // dstSubpass\r\n\t\tVK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, // srcStageMask\r\n\t\tVK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, // dstStageMask\r\n\t\t0, // srcAccessMask\r\n\t\tVK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, // dstAccessMask\r\n\t\tVK_DEPENDENCY_BY_REGION_BIT, // dependencyFlags\r\n\t};\r\n\r\n\t// implicitly defined dependency would cover this, but let's replace it with this explicitly defined dependency!\r\n\tVkSubpassDependency dstDependency{\r\n\t\t0, // srcSubpass\r\n\t\tVK_SUBPASS_EXTERNAL, // dstSubpass\r\n\t\tVK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, // srcStageMask\r\n\t\tVK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, // dstStageMask\r\n\t\tVK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, // srcAccessMask\r\n\t\t0, // dstAccessMask\r\n\t\tVK_DEPENDENCY_BY_REGION_BIT, // dependencyFlags\r\n\t};\r\n\r\n\tVkSubpassDependency dependencies[] = {srcDependency, dstDependency};\r\n\r\n\tVkRenderPassCreateInfo renderPassInfo{\r\n\t\tVK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,\r\n\t\tnullptr, // pNext\r\n\t\t0, // flags - reserved for future use\r\n\t\t1, // attachment count\r\n\t\t&colorAtachment, // attachments\r\n\t\t1, // subpass count\r\n\t\t&subpass, // subpasses\r\n\t\t2, // dependency count\r\n\t\tdependencies // dependencies\r\n\t};\r\n\r\n\tVkRenderPass renderPass;\r\n\tVkResult errorCode = vkCreateRenderPass( device, &renderPassInfo, nullptr, &renderPass ); RESULT_HANDLER( errorCode, \"vkCreateRenderPass\" );\r\n\r\n\treturn renderPass;\r\n}\r\n\r\nvoid killRenderPass( VkDevice device, VkRenderPass renderPass ){\r\n\tvkDestroyRenderPass( device, renderPass, nullptr );\r\n}\r\n\r\nvector<VkFramebuffer> initFramebuffers(\r\n\tVkDevice device,\r\n\tVkRenderPass renderPass,\r\n\tvector<VkImageView> imageViews,\r\n\tuint32_t width, uint32_t height\r\n){\r\n\tvector<VkFramebuffer> framebuffers;\r\n\r\n\tfor( auto imageView : imageViews ){\r\n\t\tVkFramebufferCreateInfo framebufferInfo{\r\n\t\t\tVK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,\r\n\t\t\tnullptr, // pNext\r\n\t\t\t0, // flags - reserved for future use\r\n\t\t\trenderPass,\r\n\t\t\t1, // ImageView count\r\n\t\t\t&imageView,\r\n\t\t\twidth, // width\r\n\t\t\theight, // height\r\n\t\t\t1 // layers\r\n\t\t};\r\n\r\n\t\tVkFramebuffer framebuffer;\r\n\t\tVkResult errorCode = vkCreateFramebuffer( device, &framebufferInfo, nullptr, &framebuffer ); RESULT_HANDLER( errorCode, \"vkCreateFramebuffer\" );\r\n\t\tframebuffers.push_back( framebuffer );\r\n\t}\r\n\r\n\treturn framebuffers;\r\n}\r\n\r\nvoid killFramebuffers( VkDevice device, vector<VkFramebuffer>& framebuffers ){\r\n\tfor( auto framebuffer : framebuffers ) vkDestroyFramebuffer( device, framebuffer, nullptr );\r\n\tframebuffers.clear();\r\n}\r\n\r\n/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n\r\ntemplate<typename Type = uint8_t>\r\nvector<Type> loadBinaryFile( string filename ){\r\n\tusing std::ifstream;\r\n\tusing std::istreambuf_iterator;\r\n\r\n\tvector<Type> data;\r\n\r\n\ttry{\r\n\t\tifstream ifs;\r\n\t\tifs.exceptions( ifs.failbit | ifs.badbit | ifs.eofbit );\r\n\t\tifs.open( filename, ifs.in | ifs.binary | ifs.ate );\r\n\r\n\t\tconst auto fileSize = static_cast<size_t>( ifs.tellg() );\r\n\r\n\t\tif( fileSize > 0 && (fileSize % sizeof(Type) == 0) ){\r\n\t\t\tifs.seekg( ifs.beg );\r\n\t\t\tdata.resize( fileSize / sizeof(Type) );\r\n\t\t\tifs.read( reinterpret_cast<char*>(data.data()), fileSize );\r\n\t\t}\r\n\t}\r\n\tcatch( ... ){\r\n\t\tdata.clear();\r\n\t}\r\n\r\n\treturn data;\r\n}\r\n\r\nVkShaderModule initShaderModule( VkDevice device, string filename ){\r\n\tconst auto shaderCode = loadBinaryFile<uint32_t>( filename );\r\n\tif( shaderCode.empty() ) throw \"SPIR-V shader file \" + filename + \" is invalid or read failed!\";\r\n\treturn initShaderModule( device, shaderCode );\r\n}\r\n\r\nVkShaderModule initShaderModule( VkDevice device, const vector<uint32_t>& shaderCode ){\r\n\tVkShaderModuleCreateInfo shaderModuleInfo{\r\n\t\tVK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO,\r\n\t\tnullptr, // pNext\r\n\t\t0, // flags - reserved for future use\r\n\t\tshaderCode.size() * sizeof(uint32_t),\r\n\t\tshaderCode.data()\r\n\t};\r\n\r\n\tVkShaderModule shaderModule;\r\n\tVkResult errorCode = vkCreateShaderModule( device, &shaderModuleInfo, nullptr, &shaderModule ); RESULT_HANDLER( errorCode, \"vkCreateShaderModule\" );\r\n\r\n\treturn shaderModule;\r\n}\r\n\r\nvoid killShaderModule( VkDevice device, VkShaderModule shaderModule ){\r\n\tvkDestroyShaderModule( device, shaderModule, nullptr );\r\n}\r\n\r\nVkPipelineLayout initPipelineLayout( VkDevice device ){\r\n\tVkPipelineLayoutCreateInfo pipelineLayoutInfo{\r\n\t\tVK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,\r\n\t\tnullptr, // pNext\r\n\t\t0, // flags - reserved for future use\r\n\t\t0, // descriptorSetLayout count\r\n\t\tnullptr,\r\n\t\t0, // push constant range count\r\n\t\tnullptr // push constant ranges\r\n\t};\r\n\r\n\tVkPipelineLayout pipelineLayout;\r\n\tVkResult errorCode = vkCreatePipelineLayout( device, &pipelineLayoutInfo, nullptr, &pipelineLayout ); RESULT_HANDLER( errorCode, \"vkCreatePipelineLayout\" );\r\n\r\n\treturn pipelineLayout;\r\n}\r\n\r\nvoid killPipelineLayout( VkDevice device, VkPipelineLayout pipelineLayout ){\r\n\tvkDestroyPipelineLayout( device, pipelineLayout, nullptr );\r\n}\r\n\r\nVkPipeline initPipeline(\r\n\tVkDevice device,\r\n\tVkPhysicalDeviceLimits limits,\r\n\tVkPipelineLayout pipelineLayout,\r\n\tVkRenderPass renderPass,\r\n\tVkShaderModule vertexShader,\r\n\tVkShaderModule fragmentShader,\r\n\tconst uint32_t vertexBufferBinding,\r\n\tuint32_t width, uint32_t height\r\n){/*\r\n\tconst VkPipelineShaderStageCreateInfo vertexShaderStage{\r\n\t\tVK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,\r\n\t\tnullptr, // pNext\r\n\t\t0, // flags - reserved for future use\r\n\t\tVK_SHADER_STAGE_VERTEX_BIT,\r\n\t\tvertexShader,\r\n\t\tu8\"main\",\r\n\t\tnullptr // SpecializationInfo - constants pushed to shader on pipeline creation time\r\n\t};\r\n\r\n\tconst VkPipelineShaderStageCreateInfo fragmentShaderStage{\r\n\t\tVK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,\r\n\t\tnullptr, // pNext\r\n\t\t0, // flags - reserved for future use\r\n\t\tVK_SHADER_STAGE_FRAGMENT_BIT,\r\n\t\tfragmentShader,\r\n\t\tu8\"main\",\r\n\t\tnullptr // SpecializationInfo - constants pushed to shader on pipeline creation time\r\n\t};*/\r\n\r\n\tVkPipelineShaderStageCreateInfo shaderStageStates[] = { \r\n\t\t{\r\n\t\t\tVK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,\r\n\t\t\tnullptr, // pNext\r\n\t\t\t0, // flags - reserved for future use\r\n\t\t\tVK_SHADER_STAGE_VERTEX_BIT,\r\n\t\t\tvertexShader,\r\n\t\t\tu8\"main\",\r\n\t\t\tnullptr // SpecializationInfo - constants pushed to shader on pipeline creation time\r\n\t\t}, \r\n\t\t{\r\n\t\t\tVK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,\r\n\t\t\tnullptr, // pNext\r\n\t\t\t0, // flags - reserved for future use\r\n\t\t\tVK_SHADER_STAGE_FRAGMENT_BIT,\r\n\t\t\tfragmentShader,\r\n\t\t\tu8\"main\",\r\n\t\t\tnullptr // SpecializationInfo - constants pushed to shader on pipeline creation time\r\n\t\t}\r\n\t};\r\n\r\n\tconst uint32_t vertexBufferStride = sizeof( Vertex2D_ColorF_pack );\r\n\tif( vertexBufferBinding > limits.maxVertexInputBindings ){\r\n\t\tthrow string(\"Implementation does not allow enough input bindings. Needed: \")\r\n\t\t    + to_string( vertexBufferBinding ) + string(\", max: \")\r\n\t\t    + to_string( limits.maxVertexInputBindings );\r\n\t}\r\n\tif( vertexBufferStride > limits.maxVertexInputBindingStride ){\r\n\t\tthrow string(\"Implementation does not allow big enough vertex buffer stride: \")\r\n\t\t    + to_string( vertexBufferStride ) \r\n\t\t    + string(\", max: \")\r\n\t\t    + to_string( limits.maxVertexInputBindingStride );\r\n\t}\r\n\r\n\tVkVertexInputBindingDescription vertexInputBindingDescription{\r\n\t\tvertexBufferBinding,\r\n\t\tsizeof( Vertex2D_ColorF_pack ), // stride in bytes\r\n\t\tVK_VERTEX_INPUT_RATE_VERTEX\r\n\t};\r\n\r\n\tvector<VkVertexInputBindingDescription> inputBindingDescriptions = { vertexInputBindingDescription };\r\n\tif( inputBindingDescriptions.size() > limits.maxVertexInputBindings ){\r\n\t\tthrow \"Implementation does not allow enough input bindings.\";\r\n\t}\r\n\r\n\tconst uint32_t positionLocation = 0;\r\n\tconst uint32_t colorLocation = 1;\r\n\r\n\tif( colorLocation >= limits.maxVertexInputAttributes ){\r\n\t\tthrow \"Implementation does not allow enough input attributes.\";\r\n\t}\r\n\tif( offsetof( Vertex2D_ColorF_pack, color ) > limits.maxVertexInputAttributeOffset ){\r\n\t\tthrow \"Implementation does not allow sufficient attribute offset.\";\r\n\t}\r\n\r\n\tVkVertexInputAttributeDescription positionInputAttributeDescription{\r\n\t\tpositionLocation,\r\n\t\tvertexBufferBinding,\r\n\t\tVK_FORMAT_R32G32_SFLOAT,\r\n\t\toffsetof( Vertex2D_ColorF_pack, position ) // offset in bytes\r\n\t};\r\n\r\n\tVkVertexInputAttributeDescription colorInputAttributeDescription{\r\n\t\tcolorLocation,\r\n\t\tvertexBufferBinding,\r\n\t\tVK_FORMAT_R32G32B32_SFLOAT,\r\n\t\toffsetof( Vertex2D_ColorF_pack, color ) // offset in bytes\r\n\t};\r\n\r\n\tvector<VkVertexInputAttributeDescription> inputAttributeDescriptions = {\r\n\t\tpositionInputAttributeDescription,\r\n\t\tcolorInputAttributeDescription\r\n\t};\r\n\r\n\tVkPipelineVertexInputStateCreateInfo vertexInputState{\r\n\t\tVK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,\r\n\t\tnullptr, // pNext\r\n\t\t0, // flags - reserved for future use\r\n\t\tstatic_cast<uint32_t>( inputBindingDescriptions.size() ),\r\n\t\tinputBindingDescriptions.data(),\r\n\t\tstatic_cast<uint32_t>( inputAttributeDescriptions.size() ),\r\n\t\tinputAttributeDescriptions.data()\r\n\t};\r\n\r\n\tVkPipelineInputAssemblyStateCreateInfo inputAssemblyState{\r\n\t\tVK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,\r\n\t\tnullptr, // pNext\r\n\t\t0, // flags - reserved for future use\r\n\t\tVK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,\r\n\t\tVK_FALSE // primitive restart\r\n\t};\r\n\r\n\tVkViewport viewport{\r\n\t\t0.0f, // x\r\n\t\t0.0f, // y\r\n\t\tstatic_cast<float>( width ? width : 1 ),\r\n\t\tstatic_cast<float>( height ? height : 1 ),\r\n\t\t0.0f, // min depth\r\n\t\t1.0f // max depth\r\n\t};\r\n\r\n\tVkRect2D scissor{\r\n\t\t{0, 0}, // offset\r\n\t\t{width, height}\r\n\t};\r\n\r\n\tVkPipelineViewportStateCreateInfo viewportState{\r\n\t\tVK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,\r\n\t\tnullptr, // pNext\r\n\t\t0, // flags - reserved for future use\r\n\t\t1, // Viewport count\r\n\t\t&viewport,\r\n\t\t1, // scisor count,\r\n\t\t&scissor\r\n\t};\r\n\r\n\tVkPipelineRasterizationStateCreateInfo rasterizationState{\r\n\t\tVK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,\r\n\t\tnullptr, // pNext\r\n\t\t0, // flags - reserved for future use\r\n\t\tVK_FALSE, // depth clamp\r\n\t\tVK_FALSE, // rasterizer discard\r\n\t\tVK_POLYGON_MODE_FILL,\r\n\t\tVK_CULL_MODE_BACK_BIT,\r\n\t\tVK_FRONT_FACE_COUNTER_CLOCKWISE,\r\n\t\tVK_FALSE, // depth bias\r\n\t\t0.0f, // bias constant factor\r\n\t\t0.0f, // bias clamp\r\n\t\t0.0f, // bias slope factor\r\n\t\t1.0f // line width\r\n\t};\r\n\r\n\tVkPipelineMultisampleStateCreateInfo multisampleState{\r\n\t\tVK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,\r\n\t\tnullptr, // pNext\r\n\t\t0, // flags - reserved for future use\r\n\t\tVK_SAMPLE_COUNT_1_BIT,\r\n\t\tVK_FALSE, // no sample shading\r\n\t\t0.0f, // min sample shading - ignored if disabled\r\n\t\tnullptr, // sample mask\r\n\t\tVK_FALSE, // alphaToCoverage\r\n\t\tVK_FALSE // alphaToOne\r\n\t};\r\n\r\n\tVkPipelineColorBlendAttachmentState blendAttachmentState{\r\n\t\tVK_FALSE, // blending enabled?\r\n\t\tVK_BLEND_FACTOR_ZERO, // src blend factor -ignored?\r\n\t\tVK_BLEND_FACTOR_ZERO, // dst blend factor\r\n\t\tVK_BLEND_OP_ADD, // blend op\r\n\t\tVK_BLEND_FACTOR_ZERO, // src alpha blend factor\r\n\t\tVK_BLEND_FACTOR_ZERO, // dst alpha blend factor\r\n\t\tVK_BLEND_OP_ADD, // alpha blend op\r\n\t\tVK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT // color write mask\r\n\t};\r\n\r\n\tVkPipelineColorBlendStateCreateInfo colorBlendState{\r\n\t\tVK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,\r\n\t\tnullptr, // pNext\r\n\t\t0, // flags - reserved for future use\r\n\t\tVK_FALSE, // logic ops\r\n\t\tVK_LOGIC_OP_COPY,\r\n\t\t1, // attachment count - must be same as color attachment count in renderpass subpass!\r\n\t\t&blendAttachmentState,\r\n\t\t{0.0f, 0.0f, 0.0f, 0.0f} // blend constants\r\n\t};\r\n\r\n\tVkGraphicsPipelineCreateInfo pipelineInfo{\r\n\t\tVK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,\r\n\t\tnullptr, // pNext\r\n\t\t0, // flags - e.g. disable optimization\r\n\t\t2, // shader stages count - vertex and fragment\r\n\t\tshaderStageStates,\r\n\t\t&vertexInputState,\r\n\t\t&inputAssemblyState,\r\n\t\tnullptr, // tesselation\r\n\t\t&viewportState,\r\n\t\t&rasterizationState,\r\n\t\t&multisampleState,\r\n\t\tnullptr, // depth stencil\r\n\t\t&colorBlendState,\r\n\t\tnullptr, // dynamic state\r\n\t\tpipelineLayout,\r\n\t\trenderPass,\r\n\t\t0, // subpass index in renderpass\r\n\t\tVK_NULL_HANDLE, // base pipeline\r\n\t\t-1 // base pipeline index\r\n\t};\r\n\r\n\tVkPipeline pipeline;\r\n\tVkResult errorCode = vkCreateGraphicsPipelines(\r\n\t\tdevice,\r\n\t\tVK_NULL_HANDLE /* pipeline cache */,\r\n\t\t1 /* info count */,\r\n\t\t&pipelineInfo,\r\n\t\tnullptr,\r\n\t\t&pipeline\r\n\t); RESULT_HANDLER( errorCode, \"vkCreateGraphicsPipelines\" );\r\n\treturn pipeline;\r\n}\r\n\r\nvoid killPipeline( VkDevice device, VkPipeline pipeline ){\r\n\tvkDestroyPipeline( device, pipeline, nullptr );\r\n}\r\n\r\n/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r\n\r\nvoid setVertexData( VkDevice device, VkDeviceMemory memory, vector<Vertex2D_ColorF_pack> vertices ){\r\n\tTODO( \"Should be in Device Local memory instead\" )\r\n\tsetMemoryData(  device, memory, vertices.data(), sizeof( decltype(vertices)::value_type ) * vertices.size()  );\r\n}\r\n\r\nVkSemaphore initSemaphore( VkDevice device ){\r\n\tconst VkSemaphoreCreateInfo semaphoreInfo{\r\n\t\tVK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,\r\n\t\tnullptr, // pNext\r\n\t\t0 // flags - reserved for future use\r\n\t};\r\n\r\n\tVkSemaphore semaphore;\r\n\tVkResult errorCode = vkCreateSemaphore( device, &semaphoreInfo, nullptr, &semaphore ); RESULT_HANDLER( errorCode, \"vkCreateSemaphore\" );\r\n\treturn semaphore;\r\n}\r\n\r\nvector<VkSemaphore> initSemaphores( VkDevice device, size_t count ){\r\n\tvector<VkSemaphore> semaphores;\r\n\tstd::generate_n(  std::back_inserter( semaphores ), count, [device]{ return initSemaphore( device ); }  );\r\n\treturn semaphores;\r\n}\r\n\r\nvoid killSemaphore( VkDevice device, VkSemaphore semaphore ){\r\n\tvkDestroySemaphore( device, semaphore, nullptr );\r\n}\r\n\r\nvoid killSemaphores( VkDevice device, vector<VkSemaphore>& semaphores ){\r\n\tfor( const auto s : semaphores ) killSemaphore( device, s );\r\n\tsemaphores.clear();\r\n}\r\n\r\nVkCommandPool initCommandPool( VkDevice device, const uint32_t queueFamily ){\r\n\tconst VkCommandPoolCreateInfo commandPoolInfo{\r\n\t\tVK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,\r\n\t\tnullptr, // pNext\r\n\t\t0, // flags\r\n\t\tqueueFamily\r\n\t};\r\n\r\n\tVkCommandPool commandPool;\r\n\tVkResult errorCode = vkCreateCommandPool( device, &commandPoolInfo, nullptr, &commandPool ); RESULT_HANDLER( errorCode, \"vkCreateCommandPool\" );\r\n\treturn commandPool;\r\n}\r\n\r\nvoid killCommandPool( VkDevice device, VkCommandPool commandPool ){\r\n\tvkDestroyCommandPool( device, commandPool, nullptr );\r\n}\r\n\r\nVkFence initFence( const VkDevice device, const VkFenceCreateFlags flags = 0 ){\r\n\tconst VkFenceCreateInfo fci{\r\n\t\tVK_STRUCTURE_TYPE_FENCE_CREATE_INFO,\r\n\t\tnullptr, // pNext\r\n\t\tflags\r\n\t};\r\n\r\n\tVkFence fence;\r\n\tVkResult errorCode = vkCreateFence( device, &fci, nullptr, &fence ); RESULT_HANDLER( errorCode, \"vkCreateFence\" );\r\n\treturn fence;\r\n}\r\n\r\nvoid killFence( const VkDevice device, const VkFence fence ){\r\n\tvkDestroyFence( device, fence, nullptr );\r\n}\r\n\r\nvector<VkFence> initFences( const VkDevice device, const size_t count, const VkFenceCreateFlags flags ){\r\n\tvector<VkFence> fences;\r\n\tstd::generate_n(  std::back_inserter( fences ), count, [=]{return initFence( device, flags );}  );\r\n\treturn fences;\r\n}\r\n\r\nvoid killFences( const VkDevice device, vector<VkFence>& fences ){\r\n\tfor( const auto f : fences ) killFence( device, f );\r\n\tfences.clear();\r\n}\r\n\r\nvoid acquireCommandBuffers( VkDevice device, VkCommandPool commandPool, uint32_t count, vector<VkCommandBuffer>& commandBuffers ){\r\n\tconst auto oldSize = static_cast<uint32_t>( commandBuffers.size() );\r\n\r\n\tif( count > oldSize ){\r\n\t\tVkCommandBufferAllocateInfo commandBufferInfo{\r\n\t\t\tVK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,\r\n\t\t\tnullptr, // pNext\r\n\t\t\tcommandPool,\r\n\t\t\tVK_COMMAND_BUFFER_LEVEL_PRIMARY,\r\n\t\t\tcount - oldSize // count\r\n\t\t};\r\n\r\n\t\tcommandBuffers.resize( count );\r\n\t\tVkResult errorCode = vkAllocateCommandBuffers( device, &commandBufferInfo, &commandBuffers[oldSize] ); RESULT_HANDLER( errorCode, \"vkAllocateCommandBuffers\" );\r\n\t}\r\n\r\n\tif( count < oldSize ) {\r\n\t\tvkFreeCommandBuffers( device, commandPool, oldSize - count, &commandBuffers[count] );\r\n\t\tcommandBuffers.resize( count );\r\n\t}\r\n}\r\n\r\nvoid beginCommandBuffer( VkCommandBuffer commandBuffer ){\r\n\tVkCommandBufferBeginInfo commandBufferInfo{\r\n\t\tVK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,\r\n\t\tnullptr, // pNext\r\n\t\t// same buffer can be re-executed before it finishes from last submit\r\n\t\tVK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT, // flags\r\n\t\tnullptr // inheritance\r\n\t};\r\n\r\n\tVkResult errorCode = vkBeginCommandBuffer( commandBuffer, &commandBufferInfo ); RESULT_HANDLER( errorCode, \"vkBeginCommandBuffer\" );\r\n}\r\n\r\nvoid endCommandBuffer( VkCommandBuffer commandBuffer ){\r\n\tVkResult errorCode = vkEndCommandBuffer( commandBuffer ); RESULT_HANDLER( errorCode, \"vkEndCommandBuffer\" );\r\n}\r\n\r\n\r\nvoid recordBeginRenderPass(\r\n\tVkCommandBuffer commandBuffer,\r\n\tVkRenderPass renderPass,\r\n\tVkFramebuffer framebuffer,\r\n\tVkClearValue clearValue,\r\n\tuint32_t width, uint32_t height\r\n){\r\n\tVkRenderPassBeginInfo renderPassInfo{\r\n\t\tVK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,\r\n\t\tnullptr, // pNext\r\n\t\trenderPass,\r\n\t\tframebuffer,\r\n\t\t{{0,0}, {width,height}}, //render area - offset plus extent\r\n\t\t1, // clear value count\r\n\t\t&clearValue\r\n\t};\r\n\r\n\tvkCmdBeginRenderPass( commandBuffer, &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE );\r\n}\r\n\r\nvoid recordEndRenderPass( VkCommandBuffer commandBuffer ){\r\n\tvkCmdEndRenderPass( commandBuffer );\r\n}\r\n\r\nvoid recordBindPipeline( VkCommandBuffer commandBuffer, VkPipeline pipeline ){\r\n\tvkCmdBindPipeline( commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline );\r\n}\r\n\r\nvoid recordBindVertexBuffer( VkCommandBuffer commandBuffer, const uint32_t vertexBufferBinding, VkBuffer vertexBuffer ){\r\n\tVkDeviceSize offsets[] = {0};\r\n\tvkCmdBindVertexBuffers( commandBuffer, vertexBufferBinding, 1 /*binding count*/, &vertexBuffer, offsets );\r\n}\r\n\r\nvoid recordDraw( VkCommandBuffer commandBuffer, const uint32_t vertexCount ){\r\n\tvkCmdDraw( commandBuffer, vertexCount, 1 /*instance count*/, 0 /*first vertex*/, 0 /*first instance*/ );\r\n}\r\n\r\nvoid submitToQueue( VkQueue queue, VkCommandBuffer commandBuffer, VkSemaphore imageReadyS, VkSemaphore renderDoneS, VkFence fence ){\r\n\tconst VkPipelineStageFlags psw = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;\r\n\r\n\tconst VkSubmitInfo submit{\r\n\t\tVK_STRUCTURE_TYPE_SUBMIT_INFO,\r\n\t\tnullptr, // pNext\r\n\t\t1, &imageReadyS, // wait semaphores\r\n\t\t&psw, // pipeline stages to wait for semaphore\r\n\t\t1, &commandBuffer,\r\n\t\t1, &renderDoneS // signal semaphores\r\n\t};\r\n\r\n\tconst VkResult errorCode = vkQueueSubmit( queue, 1 /*submit count*/, &submit, fence ); RESULT_HANDLER( errorCode, \"vkQueueSubmit\" );\r\n}\r\n\r\nvoid present( VkQueue queue, VkSwapchainKHR swapchain, uint32_t swapchainImageIndex, VkSemaphore renderDoneS ){\r\n\tconst VkPresentInfoKHR presentInfo{\r\n\t\tVK_STRUCTURE_TYPE_PRESENT_INFO_KHR,\r\n\t\tnullptr, // pNext\r\n\t\t1, &renderDoneS, // wait semaphores\r\n\t\t1, &swapchain, &swapchainImageIndex,\r\n\t\tnullptr // pResults\r\n\t};\r\n\r\n\tconst VkResult errorCode = vkQueuePresentKHR( queue, &presentInfo ); RESULT_HANDLER( errorCode, \"vkQueuePresentKHR\" );\r\n}\r\n\r\n// cleanup dangerous semaphore with signal pending from vkAcquireNextImageKHR (tie it to a specific queue)\r\n// https://github.com/KhronosGroup/Vulkan-Docs/issues/1059\r\nvoid cleanupUnsafeSemaphore( VkQueue queue, VkSemaphore semaphore ){\r\n\tVkPipelineStageFlags psw = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;\r\n\r\n\tconst VkSubmitInfo submit{\r\n\t\tVK_STRUCTURE_TYPE_SUBMIT_INFO,\r\n\t\tnullptr, // pNext\r\n\t\t1, &semaphore, // wait semaphores\r\n\t\t&psw, // pipeline stages to wait for semaphore\r\n\t\t0, nullptr, // command buffers\r\n\t\t0, nullptr // signal semaphores\r\n\t};\r\n\r\n\tconst VkResult errorCode = vkQueueSubmit( queue, 1 /*submit count*/, &submit, VK_NULL_HANDLE ); RESULT_HANDLER( errorCode, \"vkQueueSubmit\" );\r\n}\r\n"
  },
  {
    "path": "src/LeanWindowsEnvironment.h",
    "content": "// As lean as possible Windows.h header global settings\r\n\r\n// Should be included as soon as possible (first line in translation unit preferably)\r\n\r\n#ifndef COMMON_LEAN_WINDOWS_ENVIRONMENT_H\r\n#define COMMON_LEAN_WINDOWS_ENVIRONMENT_H\r\n\r\n#ifdef _INC_WINDOWS\r\n\t#error Some Windows.h is already included before this file!\r\n#endif //_INC_WINDOWS\r\n\r\n\r\n#define WIN32_LEAN_AND_MEAN\r\n\r\n#define NOGDICAPMASKS\r\n//#define NOVIRTUALKEYCODES // need virtual keys e.g. VK_ESCAPE\r\n//#define NOWINMESSAGES // need window message definitions\r\n//#define NOWINSTYLES // need window styles to create windows\r\n#define NOSYSMETRICS\r\n#define NOMENUS\r\n//#define NOICONS // need icons to create window\r\n#define NOKEYSTATES\r\n//#define NOSYSCOMMANDS // need to manage LAlt key events\r\n#define NORASTEROPS\r\n//#define NOSHOWWINDOW // need to show windows\r\n#define OEMRESOURCE\r\n#define NOATOM\r\n#define NOCLIPBOARD\r\n//#define NOCOLOR // need default colors\r\n#define NOCTLMGR\r\n#define NODRAWTEXT\r\n#define NOGDI\r\n#define NOKERNEL\r\n//#define NOUSER // need it - contains MSG and lot other things\r\n//#define NONLS // need CP_UTF8\r\n#define NOMB\r\n#define NOMEMMGR\r\n#define NOMETAFILE\r\n#define NOMINMAX\r\n//#define NOMSG // need MSG for event loop\r\n#define NOOPENFILE\r\n#define NOSCROLL\r\n#define NOSERVICE\r\n#define NOSOUND\r\n#define NOTEXTMETRIC\r\n#define NOWH\r\n//#define NOWINOFFSETS // need for GetWindowLongW\r\n#define NOCOMM\r\n#define NOKANJI\r\n#define NOHELP\r\n#define NOPROFILER\r\n#define NODEFERWINDOWPOS\r\n#define NOMCX\r\n\r\n// rip ANSI mode\r\n#ifndef UNICODE\r\n\t#define UNICODE\r\n#endif\r\n\r\n#endif //COMMON_LEAN_WINDOWS_ENVIRONMENT_H"
  },
  {
    "path": "src/Vertex.h",
    "content": "// Basic vertex data definitions\r\n\r\n#ifndef COMMON_VERTEX_H\r\n#define COMMON_VERTEX_H\r\n\r\nstruct Vertex2D{\r\n\tfloat position[2];\r\n};\r\n\r\nstruct ColorF{\r\n\tfloat color[3];\r\n};\r\n\r\nstruct Vertex2D_ColorF_pack{\r\n\tVertex2D position;\r\n\tColorF color;\r\n};\r\n\r\n#endif //COMMON_VERTEX_H\r\n"
  },
  {
    "path": "src/VulkanEnvironment.h",
    "content": "// vulkan.h header global settings\r\n\r\n// Should be included as soon as possible (first line in translation unit preferably)\r\n\r\n#ifndef COMMON_VULKAN_ENVIRONMENT_H\r\n#define COMMON_VULKAN_ENVIRONMENT_H\r\n\r\n// detect premature vulkan.h\r\n#ifdef VULKAN_H_\r\n\t#error \"vulkan.h is included before VulkanEnvironment.h!\"\r\n#endif //VULKAN_H_\r\n\r\n#include \"CompilerMessages.h\"\r\n\r\n#define REQUIRED_HEADER_VERSION 176\r\n\r\n#ifdef NDEBUG\r\n\t#ifndef VULKAN_VALIDATION\r\n\t\t#define VULKAN_VALIDATION 0\r\n\t#endif\r\n#else\r\n\t#ifndef VULKAN_VALIDATION\r\n\t\t#define VULKAN_VALIDATION 1\r\n\t#endif\r\n#endif\r\n\r\n#if  defined(USE_PLATFORM_NONE) \\\r\n  || defined(USE_PLATFORM_GLFW) \\\r\n  || defined(VK_USE_PLATFORM_ANDROID_KHR) \\\r\n  || defined(VK_USE_PLATFORM_MIR_KHR) \\\r\n  || defined(VK_USE_PLATFORM_WAYLAND_KHR) \\\r\n  || defined(VK_USE_PLATFORM_WIN32_KHR) \\\r\n  || defined(VK_USE_PLATFORM_XCB_KHR) \\\r\n  || defined(VK_USE_PLATFORM_XLIB_KHR) \\\r\n  || defined(VK_USE_PLATFORM_IOS_MVK) \\\r\n  || defined(VK_USE_PLATFORM_MACOS_MVK) \\\r\n  || defined(VK_USE_PLATFORM_VI_NN)\r\n\t#define WSI_CHOSEN_EXTERNALLY\r\n#endif\r\n\r\n#if defined(_WIN32) && !defined(_CONSOLE)\r\n\t#include \"LeanWindowsEnvironment.h\"\r\n\t#include <Windows.h>\r\n#endif\r\n\r\n// platform specific settings\r\n#if defined(__CYGWIN__)\r\n\t#ifndef WSI_CHOSEN_EXTERNALLY\r\n\t\t#define USE_PLATFORM_GLFW\r\n\t\t//#define VK_USE_PLATFORM_WIN32_KHR\r\n\t#endif\r\n\t#include \"LeanWindowsEnvironment.h\" // Windows.h settings must be first -- vulkan.h does include Windows.h\r\n#elif defined(__MINGW32__)\r\n\t#ifndef WSI_CHOSEN_EXTERNALLY\r\n\t\t#define USE_PLATFORM_GLFW\r\n\t\t//#define VK_USE_PLATFORM_WIN32_KHR\r\n\t#endif\r\n\t#include \"LeanWindowsEnvironment.h\" // Windows.h settings must be first -- vulkan.h does include Windows.h\r\n#elif defined(_WIN32)\r\n\t#ifndef WSI_CHOSEN_EXTERNALLY\r\n\t\t#define USE_PLATFORM_GLFW\r\n\t\t//#define VK_USE_PLATFORM_WIN32_KHR\r\n\t#endif\r\n#elif defined(__linux__)\r\n\t#ifndef WSI_CHOSEN_EXTERNALLY\r\n\t\t#define USE_PLATFORM_GLFW\r\n\t\t//#define VK_USE_PLATFORM_XCB_KHR\r\n\t\t//#define VK_USE_PLATFORM_XLIB_KHR\r\n\t\t//#define VK_USE_PLATFORM_WAYLAND_KHR\r\n\t#endif\r\n#else\r\n\t//#error \"Unsupported OS platform.\" // caught in main.cpp instead\r\n#endif\r\n\r\n#endif //COMMON_VULKAN_ENVIRONMENT_H\r\n"
  },
  {
    "path": "src/VulkanIntrospection.h",
    "content": "// Introspection for Vulkan enums -- mostly to_string\n\n#ifndef COMMON_VULKAN_INTROSPECTION_H\n#define COMMON_VULKAN_INTROSPECTION_H\n\n#include <string>\n#include <sstream>\n\n#include <vulkan/vulkan.h>\n\n\ntemplate <typename PHANDLE_T>\ninline uint64_t handleToUint64(const PHANDLE_T *h) { return reinterpret_cast<uint64_t>(h); }\ninline uint64_t handleToUint64(const uint64_t h) { return h; }\n\nconst char* to_string( const VkResult r ){\n\tswitch( r ){\n\t\tcase VK_SUCCESS:                                            return \"VK_SUCCESS\";\n\t\tcase VK_NOT_READY:                                          return \"VK_NOT_READY\";\n\t\tcase VK_TIMEOUT:                                            return \"VK_TIMEOUT\";\n\t\tcase VK_EVENT_SET:                                          return \"VK_EVENT_SET\";\n\t\tcase VK_EVENT_RESET:                                        return \"VK_EVENT_RESET\";\n\t\tcase VK_INCOMPLETE:                                         return \"VK_INCOMPLETE\";\n\t\tcase VK_ERROR_OUT_OF_HOST_MEMORY:                           return \"VK_ERROR_OUT_OF_HOST_MEMORY\";\n\t\tcase VK_ERROR_OUT_OF_DEVICE_MEMORY:                         return \"VK_ERROR_OUT_OF_DEVICE_MEMORY\";\n\t\tcase VK_ERROR_INITIALIZATION_FAILED:                        return \"VK_ERROR_INITIALIZATION_FAILED\";\n\t\tcase VK_ERROR_DEVICE_LOST:                                  return \"VK_ERROR_DEVICE_LOST\";\n\t\tcase VK_ERROR_MEMORY_MAP_FAILED:                            return \"VK_ERROR_MEMORY_MAP_FAILED\";\n\t\tcase VK_ERROR_LAYER_NOT_PRESENT:                            return \"VK_ERROR_LAYER_NOT_PRESENT\";\n\t\tcase VK_ERROR_EXTENSION_NOT_PRESENT:                        return \"VK_ERROR_EXTENSION_NOT_PRESENT\";\n\t\tcase VK_ERROR_FEATURE_NOT_PRESENT:                          return \"VK_ERROR_FEATURE_NOT_PRESENT\";\n\t\tcase VK_ERROR_INCOMPATIBLE_DRIVER:                          return \"VK_ERROR_INCOMPATIBLE_DRIVER\";\n\t\tcase VK_ERROR_TOO_MANY_OBJECTS:                             return \"VK_ERROR_TOO_MANY_OBJECTS\";\n\t\tcase VK_ERROR_FORMAT_NOT_SUPPORTED:                         return \"VK_ERROR_FORMAT_NOT_SUPPORTED\";\n\t\tcase VK_ERROR_FRAGMENTED_POOL:                              return \"VK_ERROR_FRAGMENTED_POOL\";\n\t\tcase VK_ERROR_UNKNOWN:                                      return \"VK_ERROR_UNKNOWN\";\n\t\tcase VK_ERROR_OUT_OF_POOL_MEMORY:                           return \"VK_ERROR_OUT_OF_POOL_MEMORY\";\n\t\tcase VK_ERROR_INVALID_EXTERNAL_HANDLE:                      return \"VK_ERROR_INVALID_EXTERNAL_HANDLE\";\n\t\tcase VK_ERROR_FRAGMENTATION:                                return \"VK_ERROR_FRAGMENTATION\";\n\t\tcase VK_ERROR_INVALID_OPAQUE_CAPTURE_ADDRESS:               return \"VK_ERROR_INVALID_OPAQUE_CAPTURE_ADDRESS\";\n\t\tcase VK_ERROR_SURFACE_LOST_KHR:                             return \"VK_ERROR_SURFACE_LOST_KHR\";\n\t\tcase VK_ERROR_NATIVE_WINDOW_IN_USE_KHR:                     return \"VK_ERROR_NATIVE_WINDOW_IN_USE_KHR\";\n\t\tcase VK_SUBOPTIMAL_KHR:                                     return \"VK_SUBOPTIMAL_KHR\";\n\t\tcase VK_ERROR_OUT_OF_DATE_KHR:                              return \"VK_ERROR_OUT_OF_DATE_KHR\";\n\t\tcase VK_ERROR_INCOMPATIBLE_DISPLAY_KHR:                     return \"VK_ERROR_INCOMPATIBLE_DISPLAY_KHR\";\n\t\tcase VK_ERROR_VALIDATION_FAILED_EXT:                        return \"VK_ERROR_VALIDATION_FAILED_EXT\";\n\t\tcase VK_ERROR_INVALID_SHADER_NV:                            return \"VK_ERROR_INVALID_SHADER_NV\";\n\t\tcase VK_ERROR_INVALID_DRM_FORMAT_MODIFIER_PLANE_LAYOUT_EXT: return \"VK_ERROR_INVALID_DRM_FORMAT_MODIFIER_PLANE_LAYOUT_EXT\";\n\t\tcase VK_ERROR_NOT_PERMITTED_EXT:                            return \"VK_ERROR_NOT_PERMITTED_EXT\";\n\t\tcase VK_ERROR_FULL_SCREEN_EXCLUSIVE_MODE_LOST_EXT:          return \"VK_ERROR_FULL_SCREEN_EXCLUSIVE_MODE_LOST_EXT\";\n\t\tcase VK_THREAD_IDLE_KHR:                                    return \"VK_THREAD_IDLE_KHR\";\n\t\tcase VK_THREAD_DONE_KHR:                                    return \"VK_THREAD_DONE_KHR\";\n\t\tcase VK_OPERATION_DEFERRED_KHR:                             return \"VK_OPERATION_DEFERRED_KHR\";\n\t\tcase VK_OPERATION_NOT_DEFERRED_KHR:                         return \"VK_OPERATION_NOT_DEFERRED_KHR\";\n\t\tcase VK_PIPELINE_COMPILE_REQUIRED_EXT:                      return \"VK_PIPELINE_COMPILE_REQUIRED_EXT\";\n\t\tdefault:                                                    return \"unrecognized VkResult code\";\n\t}\n}\n\nstd::string to_string( const VkDebugReportObjectTypeEXT o ){\n\tswitch( o ){\n\t\tcase VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT:                    return \"unknown\";\n\t\tcase VK_DEBUG_REPORT_OBJECT_TYPE_INSTANCE_EXT:                   return \"Instance\";\n\t\tcase VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT:            return \"PhysicalDevice\";\n\t\tcase VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT:                     return \"Device\";\n\t\tcase VK_DEBUG_REPORT_OBJECT_TYPE_QUEUE_EXT:                      return \"Queue\";\n\t\tcase VK_DEBUG_REPORT_OBJECT_TYPE_SEMAPHORE_EXT:                  return \"Semaphore\";\n\t\tcase VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT:             return \"CommandBuffer\";\n\t\tcase VK_DEBUG_REPORT_OBJECT_TYPE_FENCE_EXT:                      return \"Fence\";\n\t\tcase VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT:              return \"DeviceMemory\";\n\t\tcase VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT:                     return \"Buffer\";\n\t\tcase VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT:                      return \"Image\";\n\t\tcase VK_DEBUG_REPORT_OBJECT_TYPE_EVENT_EXT:                      return \"Event\";\n\t\tcase VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT:                 return \"QueryPool\";\n\t\tcase VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_VIEW_EXT:                return \"BufferView\";\n\t\tcase VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_VIEW_EXT:                 return \"ImageView\";\n\t\tcase VK_DEBUG_REPORT_OBJECT_TYPE_SHADER_MODULE_EXT:              return \"ShaderModule\";\n\t\tcase VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_CACHE_EXT:             return \"PipelineCache\";\n\t\tcase VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_LAYOUT_EXT:            return \"PipelineLayout\";\n\t\tcase VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT:                return \"RenderPass\";\n\t\tcase VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT:                   return \"Pipeline\";\n\t\tcase VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT_EXT:      return \"DescriptorSetLayout\";\n\t\tcase VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_EXT:                    return \"Sampler\";\n\t\tcase VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_POOL_EXT:            return \"DescriptorPool\";\n\t\tcase VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT:             return \"DescriptorSet\";\n\t\tcase VK_DEBUG_REPORT_OBJECT_TYPE_FRAMEBUFFER_EXT:                return \"Framebuffer\";\n\t\tcase VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_POOL_EXT:               return \"Command pool\";\n\t\tcase VK_DEBUG_REPORT_OBJECT_TYPE_SURFACE_KHR_EXT:                return \"SurfaceKHR\";\n\t\tcase VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT:              return \"SwapchainKHR\";\n\t\tcase VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_CALLBACK_EXT_EXT:  return \"DebugReportCallbackEXT\";\n\t\tcase VK_DEBUG_REPORT_OBJECT_TYPE_DISPLAY_KHR_EXT:                return \"DisplayKHR\";\n\t\tcase VK_DEBUG_REPORT_OBJECT_TYPE_DISPLAY_MODE_KHR_EXT:           return \"DisplayModeKHR\";\n\t\tcase VK_DEBUG_REPORT_OBJECT_TYPE_VALIDATION_CACHE_EXT_EXT:       return \"ValidationCacheEXT\";\n\t\tcase VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION_EXT:   return \"SamplerYcbcrConversion\";\n\t\tcase VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_EXT: return \"DescriptorUpdateTemplate\";\n\t\tcase VK_DEBUG_REPORT_OBJECT_TYPE_ACCELERATION_STRUCTURE_KHR_EXT: return \"AccelerationStructureKHR\";\n\t\tcase VK_DEBUG_REPORT_OBJECT_TYPE_ACCELERATION_STRUCTURE_NV_EXT:  return \"AccelerationStructureNV\";\n\t\tdefault:                                                         return \"unrecognized type\";\n\t}\n}\n\nstd::string to_string( const VkObjectType o ){\n\tswitch( o ){\n\t\tcase VK_OBJECT_TYPE_UNKNOWN:                         return \"unknown\";\n\t\tcase VK_OBJECT_TYPE_INSTANCE:                        return \"Instance\";\n\t\tcase VK_OBJECT_TYPE_PHYSICAL_DEVICE:                 return \"PhysicalDevice\";\n\t\tcase VK_OBJECT_TYPE_DEVICE:                          return \"Device\";\n\t\tcase VK_OBJECT_TYPE_QUEUE:                           return \"Queue\";\n\t\tcase VK_OBJECT_TYPE_SEMAPHORE:                       return \"Semaphore\";\n\t\tcase VK_OBJECT_TYPE_COMMAND_BUFFER:                  return \"CommandBuffer\";\n\t\tcase VK_OBJECT_TYPE_FENCE:                           return \"Fence\";\n\t\tcase VK_OBJECT_TYPE_DEVICE_MEMORY:                   return \"DeviceMemory\";\n\t\tcase VK_OBJECT_TYPE_BUFFER:                          return \"Buffer\";\n\t\tcase VK_OBJECT_TYPE_IMAGE:                           return \"Image\";\n\t\tcase VK_OBJECT_TYPE_EVENT:                           return \"Event\";\n\t\tcase VK_OBJECT_TYPE_QUERY_POOL:                      return \"QueryPool\";\n\t\tcase VK_OBJECT_TYPE_BUFFER_VIEW:                     return \"BufferView\";\n\t\tcase VK_OBJECT_TYPE_IMAGE_VIEW:                      return \"ImageView\";\n\t\tcase VK_OBJECT_TYPE_SHADER_MODULE:                   return \"ShaderModule\";\n\t\tcase VK_OBJECT_TYPE_PIPELINE_CACHE:                  return \"PipelineCache\";\n\t\tcase VK_OBJECT_TYPE_PIPELINE_LAYOUT:                 return \"PipelineLayout\";\n\t\tcase VK_OBJECT_TYPE_RENDER_PASS:                     return \"RenderPass\";\n\t\tcase VK_OBJECT_TYPE_PIPELINE:                        return \"Pipeline\";\n\t\tcase VK_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT:           return \"DescriptorSetLayout\";\n\t\tcase VK_OBJECT_TYPE_SAMPLER:                         return \"Sampler\";\n\t\tcase VK_OBJECT_TYPE_DESCRIPTOR_POOL:                 return \"DescriptorPool\";\n\t\tcase VK_OBJECT_TYPE_DESCRIPTOR_SET:                  return \"DescriptorSet\";\n\t\tcase VK_OBJECT_TYPE_FRAMEBUFFER:                     return \"Framebuffer\";\n\t\tcase VK_OBJECT_TYPE_COMMAND_POOL:                    return \"Command pool\";\n\t\tcase VK_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION:        return \"SamplerYcbcrConversion\";\n\t\tcase VK_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE:      return \"DescriptorUpdateTemplateKHR\";\n\t\tcase VK_OBJECT_TYPE_SURFACE_KHR:                     return \"SurfaceKHR\";\n\t\tcase VK_OBJECT_TYPE_SWAPCHAIN_KHR:                   return \"SwapchainKHR\";\n\t\tcase VK_OBJECT_TYPE_DISPLAY_KHR:                     return \"DisplayKHR\";\n\t\tcase VK_OBJECT_TYPE_DISPLAY_MODE_KHR:                return \"DisplayModeKHR\";\n\t\tcase VK_OBJECT_TYPE_DEBUG_REPORT_CALLBACK_EXT:       return \"DebugReportCallbackEXT\";\n#ifdef VK_ENABLE_BETA_EXTENSIONS\n\t\tcase VK_OBJECT_TYPE_VIDEO_SESSION_KHR: return \"VideoSessionKHR\";\n\t\tcase VK_OBJECT_TYPE_VIDEO_SESSION_PARAMETERS_KHR: return \"VideoSessionParametersKHR\";\n#endif\n\t\tcase VK_OBJECT_TYPE_DEBUG_UTILS_MESSENGER_EXT:       return \"DebugUtilsMessengerEXT\";\n\t\tcase VK_OBJECT_TYPE_ACCELERATION_STRUCTURE_KHR:      return \"AccelerationStructureKHR\";\n\t\tcase VK_OBJECT_TYPE_VALIDATION_CACHE_EXT:            return \"ValidationCacheEXT\";\n\t\tcase VK_OBJECT_TYPE_ACCELERATION_STRUCTURE_NV:       return \"AccelerationStructureNV\";\n\t\tcase VK_OBJECT_TYPE_PERFORMANCE_CONFIGURATION_INTEL: return \"PerformanceConfigurationINTEL\";\n\t\tcase VK_OBJECT_TYPE_DEFERRED_OPERATION_KHR:          return \"DeferredOperationKHR\";\n\t\tcase VK_OBJECT_TYPE_INDIRECT_COMMANDS_LAYOUT_NV:     return \"IndirectCommandsLayoutNV\";\n\t\tcase VK_OBJECT_TYPE_PRIVATE_DATA_SLOT_EXT:           return \"PrivateDataSlotEXT\";\n\t\tdefault:                                             return \"unrecognized type\";\n\t}\n}\n\nstd::string dbrflags_to_string( VkDebugReportFlagsEXT msgFlags ){\n\tstd::string res;\n\tbool first = true;\n\n\tif( msgFlags & VK_DEBUG_REPORT_ERROR_BIT_EXT ){\n\t\tif( !first ) res += \" | \";\n\t\tres += \"ERROR\";\n\t\tfirst = false;\n\t}\n\n\tif( msgFlags & VK_DEBUG_REPORT_WARNING_BIT_EXT ){\n\t\tif( !first ) res += \" | \";\n\t\tres += \"WARNING\";\n\t\tfirst = false;\n\t}\n\n\tif( msgFlags & VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT ){\n\t\tif( !first ) res += \" | \";\n\t\tres += \"PERFORMANCE\";\n\t\tfirst = false;\n\t}\n\n\tif( msgFlags & VK_DEBUG_REPORT_INFORMATION_BIT_EXT ){\n\t\tif( !first ) res += \" | \";\n\t\tres += \"Info\";\n\t\tfirst = false;\n\t}\n\n\tif( msgFlags & VK_DEBUG_REPORT_DEBUG_BIT_EXT ){\n\t\tif( !first ) res += \" | \";\n\t\tres += \"Debug\";\n\t\tfirst = false;\n\t}\n\n\tVkDebugReportFlagsEXT known = VK_DEBUG_REPORT_ERROR_BIT_EXT | VK_DEBUG_REPORT_WARNING_BIT_EXT | VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT | VK_DEBUG_REPORT_INFORMATION_BIT_EXT | VK_DEBUG_REPORT_DEBUG_BIT_EXT;\n\tif( msgFlags & ~known ){\n\t\tif( !first ) res += \" | \";\n\t\tres += \"UNRECOGNIZED_FLAG\";\n\t\tfirst = false;\n\t}\n\n\treturn res;\n}\n\nstd::string dbuseverity_to_string( const VkDebugUtilsMessageSeverityFlagsEXT debugSeverity ){\n\tstd::string res;\n\tbool first = true;\n\n\tif( debugSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT ){\n\t\tif( !first ) res += \" | \";\n\t\tres += \"ERROR\";\n\t\tfirst = false;\n\t}\n\n\tif( debugSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT ){\n\t\tif( !first ) res += \" | \";\n\t\tres += \"WARNING\";\n\t\tfirst = false;\n\t}\n\n\tif( debugSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT ){\n\t\tif( !first ) res += \" | \";\n\t\tres += \"Info\";\n\t\tfirst = false;\n\t}\n\n\tif( debugSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT ){\n\t\tif( !first ) res += \" | \";\n\t\tres += \"Verbose\";\n\t\tfirst = false;\n\t}\n\n\tVkDebugUtilsMessageSeverityFlagsEXT known = VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT;\n\tif( debugSeverity & ~known ){\n\t\tif( !first ) res += \" | \";\n\t\tres += \"UNRECOGNIZED_FLAG\";\n\t\tfirst = false;\n\t}\n\n\treturn res;\n}\n\nstd::string to_string( const VkDebugUtilsMessageSeverityFlagBitsEXT debugSeverity ){\n\treturn dbuseverity_to_string( debugSeverity );\n}\n\nstd::string dbutype_to_string( const VkDebugUtilsMessageTypeFlagsEXT debugType ){\n\tstd::string res;\n\tbool first = true;\n\n\tif( debugType & VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT ){\n\t\tif( !first ) res += \" | \";\n\t\tres += \"GENERAL\";\n\t\tfirst = false;\n\t}\n\n\tif( debugType & VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT ){\n\t\tif( !first ) res += \" | \";\n\t\tres += \"VALIDATION\";\n\t\tfirst = false;\n\t}\n\n\tif( debugType & VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT ){\n\t\tif( !first ) res += \" | \";\n\t\tres += \"PERFORMANCE\";\n\t\tfirst = false;\n\t}\n\n\tVkDebugUtilsMessageSeverityFlagsEXT known = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT;\n\tif( debugType & ~known ){\n\t\tif( !first ) res += \" | \";\n\t\tres += \"UNRECOGNIZED_FLAG\";\n\t\tfirst = false;\n\t}\n\n\treturn res;\n}\n\nstd::string to_string_hex( const uint64_t n ){\n\tstd::stringstream ss;\n\tss << std::hex << std::noshowbase << std::uppercase << n;\n\treturn \"0x\" + ss.str();\n}\n\n#endif //COMMON_VULKAN_INTROSPECTION_H"
  },
  {
    "path": "src/WSI/Glfw.h",
    "content": "// GLFW platform dependent WSI handling and event loop\r\n\r\n#ifndef COMMON_GLFW_WSI_H\r\n#define COMMON_GLFW_WSI_H\r\n\r\n#include <functional>\r\n#include <string>\r\n#include <queue>\r\n\r\n#include <vulkan/vulkan.h>\r\n\r\n#define GLFW_INCLUDE_NONE // Actually means include no OpenGL header\r\n#define GLFW_INCLUDE_VULKAN\r\n#include <GLFW/glfw3.h>\r\n\r\n#include \"CompilerMessages.h\"\r\n#include \"ErrorHandling.h\"\r\n\r\n\r\nTODO( \"Easier to use, but might prevent platform co-existence. Could be namespaced. Make all of this a class?\" )\r\nstruct PlatformWindow{ GLFWwindow* window; };\r\n\r\nstd::string getPlatformSurfaceExtensionName();\r\n\r\nint messageLoop( PlatformWindow window );\r\n\r\nbool platformPresentationSupport( VkInstance instance, VkPhysicalDevice device, uint32_t queueFamilyIndex, PlatformWindow window );\r\n\r\nPlatformWindow initWindow( const std::string& name, uint32_t canvasWidth, uint32_t canvasHeight );\r\nvoid killWindow( PlatformWindow window );\r\n\r\nVkSurfaceKHR initSurface( VkInstance instance, PlatformWindow window );\r\n// killSurface() is not platform dependent\r\n\r\nvoid setSizeEventHandler( std::function<void(void)> newSizeEventHandler );\r\nvoid setPaintEventHandler( std::function<void(void)> newPaintEventHandler );\r\n\r\nvoid showWindow( PlatformWindow window );\r\n\r\n\r\n// Implementation\r\n//////////////////////////////////\r\n\r\nbool nullHandler(){ return false; }\r\n\r\nstd::function<bool(void)> sizeEventHandler = nullHandler;\r\n\r\nvoid setSizeEventHandler( std::function<bool(void)> newSizeEventHandler ){\r\n\tif( !newSizeEventHandler ) sizeEventHandler = nullHandler;\r\n\tsizeEventHandler = newSizeEventHandler;\r\n}\r\n\r\nstd::function<void(void)> paintEventHandler = nullHandler;\r\n\r\nvoid setPaintEventHandler( std::function<void(void)> newPaintEventHandler ){\r\n\tif( !newPaintEventHandler ) paintEventHandler = nullHandler;\r\n\tpaintEventHandler = newPaintEventHandler;\r\n}\r\n\r\nstruct GlfwError{\r\n\tint error;\r\n\tstd::string description;\r\n};\r\n\r\nstd::queue<GlfwError> errors;\r\n\r\nvoid glfwErrorCallback( int error, const char* description ){\r\n\terrors.push( {error, description} ); // postpone errors because I don't want to throw into C API\r\n}\r\n\r\n\r\n// just make the global glfw instialization\\destruction static\r\nclass GlfwSingleton{\r\n\tstatic const GlfwSingleton glfwInstance;\r\n\r\n\tvoid destroyGlfw() noexcept{\r\n\t\tglfwTerminate();\r\n\t\tglfwSetErrorCallback( nullptr );\r\n\t}\r\n\r\n\t~GlfwSingleton(){\r\n\t\tthis->destroyGlfw();\r\n\t}\r\n\r\n\tGlfwSingleton(){\r\n\t\tglfwSetErrorCallback( glfwErrorCallback );\r\n\r\n\t\tconst auto success = glfwInit();\r\n\t\tif( !success ){\r\n\t\t\tglfwSetErrorCallback( nullptr );\r\n\t\t\tthrow \"Trouble initializing GLFW!\";\r\n\t\t}\r\n\r\n\t\tif( !glfwVulkanSupported() ){\r\n\t\t\tthis->destroyGlfw();\r\n\t\t\tthrow \"GLFW has trouble acquiring Vulkan support!\";\r\n\t\t}\r\n\t}\r\n};\r\nconst GlfwSingleton GlfwSingleton::glfwInstance;\r\n\r\nbool hasSwapchain = false;\r\n\r\nvoid showWindow( PlatformWindow window ){\r\n\tglfwShowWindow( window.window );\r\n\r\n\t// on linux there is no automatic initial size event -- need to call explicitly\r\n\tif( !hasSwapchain ) hasSwapchain = sizeEventHandler(); \r\n}\r\n\r\nstd::string getPlatformSurfaceExtensionName(){\r\n\tusing std::string;\r\n\r\n\tuint32_t count;\r\n\tconst char** extensions = glfwGetRequiredInstanceExtensions( &count ); // GLFW owns **extensions!!!\r\n\r\n\tif( !count || !extensions ) throw \"GLFW failed to return required Vulkan extensions!\";\r\n\r\n\tif( count != 2 ) throw \"GLFW returned unexpected number of required Vulkan extensions!\";\r\n\r\n\tif(  extensions[0] != string( VK_KHR_SURFACE_EXTENSION_NAME )  ) throw VK_KHR_SURFACE_EXTENSION_NAME \" is not a 1st required GLFW extension!\";\r\n\r\n\tstring surfaceExtension = string( extensions[1] );\r\n\r\n\treturn string( extensions[1] );\r\n}\r\n\r\nGLFWmonitor* getCurrentMonitor( GLFWwindow* window ){\r\n\tusing std::max;\r\n\tusing std::min;\r\n\r\n\tint bestoverlap = 0;\r\n\tGLFWmonitor* bestmonitor = NULL;\r\n\r\n\tint wx, wy;\r\n\tglfwGetWindowPos( window, &wx, &wy );\r\n\tint ww, wh;\r\n\tglfwGetWindowSize( window, &ww, &wh );\r\n\r\n\tint nmonitors;\r\n\tauto monitors = glfwGetMonitors( &nmonitors );\r\n\r\n\tfor( int i = 0; i < nmonitors; ++i ){\r\n\t\tauto mode = glfwGetVideoMode( monitors[i] );\r\n\r\n\t\tint mw = mode->width;\r\n\t\tint mh = mode->height;\r\n\r\n\t\tint mx, my;\r\n\t\tglfwGetMonitorPos( monitors[i], &mx, &my );\r\n\r\n\t\tint overlap = max(0, min(wx + ww, mx + mw) - max(wx, mx)) * max(0, min(wy + wh, my + mh) - max(wy, my));\r\n\r\n\t\tif( bestoverlap < overlap ){\r\n\t\t\tbestoverlap = overlap;\r\n\t\t\tbestmonitor = monitors[i];\r\n\t\t}\r\n\t}\r\n\r\n\treturn bestmonitor;\r\n}\r\n\r\nvoid windowSizeCallback( GLFWwindow*, int, int ) noexcept{\r\n\thasSwapchain = sizeEventHandler();\r\n}\r\n\r\nvoid windowRefreshCallback( GLFWwindow* ) noexcept{\r\n\t//logger << \"refresh\" << std::endl;\r\n\tif( hasSwapchain ) paintEventHandler();\r\n}\r\n\r\nvoid toggleFullscreen( GLFWwindow* window ){\r\n\tbool fullscreen = glfwGetWindowMonitor( window ) != NULL;\r\n\r\n\tTODO( \"All of this needs to be made a class... death to the static!\" )\r\n\tstatic int wx = 100;\r\n\tstatic int wy = 100;\r\n\tstatic int ww = 800;\r\n\tstatic int wh = 800;\r\n\r\n\tif( !fullscreen ){\r\n\t\tglfwGetWindowPos( window, &wx, &wy );\r\n\t\tglfwGetWindowSize( window, &ww, &wh );\r\n\r\n\t\tGLFWmonitor* monitor = getCurrentMonitor( window );\r\n\t\tconst GLFWvidmode* vmode = glfwGetVideoMode( monitor );\r\n\t\tglfwSetWindowMonitor( window, monitor, 0, 0, vmode->width, vmode->height, vmode->refreshRate );\r\n\t}\r\n\telse{\r\n\t\tglfwSetWindowMonitor( window, NULL, wx, wy, ww, wh, GLFW_DONT_CARE );\r\n\t}\r\n}\r\n\r\nTODO( \"Fullscreen window seem to become unresponsive in Wayland session Ubuntu\" )\r\nvoid keyCallback( GLFWwindow* window, int key, int /*scancode*/, int action, int mods ) noexcept{\r\n\tif( key == GLFW_KEY_ESCAPE && action == GLFW_PRESS ) glfwSetWindowShouldClose( window, GLFW_TRUE );\r\n\r\n\tif( key == GLFW_KEY_ENTER && action == GLFW_PRESS && mods == GLFW_MOD_ALT ) toggleFullscreen( window );\r\n}\r\n\r\nint messageLoop( PlatformWindow window ){\r\n\tusing std::to_string;\r\n\r\n\twhile(  errors.empty() && !glfwWindowShouldClose( window.window )  ){\r\n\t\tif( hasSwapchain ) glfwPollEvents(); // do not block so I can paint\r\n\t\telse glfwWaitEvents(); // allows blocking if no events\r\n\r\n\t\tif( hasSwapchain ) paintEventHandler(); // repaint always even without OS repaint event\r\n\t}\r\n\r\n\tif( !errors.empty() ) throw to_string( errors.size() ) + \" GLFW error(s) on backlog; 1st error: \" + to_string( errors.front().error ) + \": \" + errors.front().description;\r\n\r\n\treturn EXIT_SUCCESS;\r\n}\r\n\r\n\r\nbool platformPresentationSupport( VkInstance instance, VkPhysicalDevice device, uint32_t queueFamilyIndex, PlatformWindow ){\r\n\treturn glfwGetPhysicalDevicePresentationSupport( instance, device, queueFamilyIndex ) == GLFW_TRUE;\r\n}\r\n\r\nPlatformWindow initWindow( const std::string& name, const uint32_t canvasWidth, const uint32_t canvasHeight ){\r\n\tstd::string title = name + \" -- GLFW\";\r\n\r\n\tglfwWindowHint( GLFW_CLIENT_API, GLFW_NO_API );\r\n\tglfwWindowHint( GLFW_VISIBLE, GLFW_FALSE );\r\n\tGLFWwindow* window = glfwCreateWindow( static_cast<int>(canvasWidth), static_cast<int>(canvasHeight), title.c_str(), NULL, NULL );\r\n\r\n\tif( !window ) throw \"Trouble creating GLFW window!\";\r\n\r\n\tglfwSetInputMode( window, GLFW_STICKY_KEYS, GLFW_TRUE );\r\n\r\n\tglfwSetFramebufferSizeCallback( window, windowSizeCallback );\r\n\tglfwSetWindowRefreshCallback( window, windowRefreshCallback );\r\n\tglfwSetKeyCallback( window, keyCallback );\r\n\r\n\treturn { window };\r\n}\r\n\r\nvoid killWindow( PlatformWindow window ){\r\n\tglfwDestroyWindow( window.window );\r\n}\r\n\r\nVkSurfaceKHR initSurface( const VkInstance instance, const PlatformWindow window ){\r\n\tVkSurfaceKHR surface;\r\n\tconst VkResult errorCode = glfwCreateWindowSurface( instance, window.window, nullptr, &surface ); RESULT_HANDLER( errorCode, \"glfwCreateWindowSurface\" );\r\n\r\n\treturn surface;\r\n}\r\n\r\n\r\n#endif //COMMON_GLFW_WSI_H\r\n"
  },
  {
    "path": "src/WSI/Wayland.h",
    "content": "// Wayland platform dependent WSI handling and event loop\n\n#ifndef COMMON_WAYLAND_WSI_H\n#define COMMON_WAYLAND_WSI_H\n\n#include <functional>\n#include <cstring>\n#include <string>\n#include <vector>\n#include <memory>\n\n#include <wayland-client.h>\n#include <xkbcommon/xkbcommon.h>\n#include <linux/input-event-codes.h>\n#include <sys/mman.h>\n#include <unistd.h>\n#include <vulkan/vulkan.h>\n\n#include \"private/xdg-shell-client-protocol.h\"\n#include \"private/xdg-shell-client-protocol-private.inl\"\n#include \"CompilerMessages.h\"\n#include \"ErrorHandling.h\"\n\n\nTODO( \"Easier to use, but might prevent platform co-existence. Could be namespaced. Make all of this a class?\" )\nstruct PlatformWindowImpl{\n\twl_display* display = nullptr;\n\twl_registry* registry = nullptr;\n\twl_compositor* compositor = nullptr; uint32_t compositorName;\n\txdg_wm_base* wmBase = nullptr; uint32_t wmBaseName;\n\twl_surface* surface = nullptr;\n\txdg_surface* xdgSurface = nullptr;\n\txdg_toplevel* toplevel = nullptr;\n\n\twl_seat* seat = nullptr; uint32_t seatName;\n\txkb_context* xkbContext = nullptr;\n\txkb_keymap* keymap = nullptr;\n\txkb_state* xkbState = nullptr;\n\twl_keyboard* keyboard = nullptr;\n\tbool alt = false;\n\twl_pointer* pointer = nullptr;\n\n\tbool quit = false;\n\tstd::string title;\n\tbool inited = false;\n\tbool hasSwapchain = false;\n\n\tbool maximized = false, fullscreen = false;\n\tuint32_t width, height;\n\tuint32_t restoredWidth, restoredHeight;\n};\n\nstruct PlatformWindow{\n\tstd::shared_ptr<PlatformWindowImpl> impl;\n};\n\nstd::string getPlatformSurfaceExtensionName(){ return VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME; };\n\nint messageLoop( PlatformWindow window );\n\nbool platformPresentationSupport( VkInstance instance, VkPhysicalDevice device, uint32_t queueFamilyIndex, PlatformWindow window );\n\nPlatformWindow initWindow( const std::string& name, uint32_t canvasWidth, uint32_t canvasHeight );\nvoid killWindow( PlatformWindow window );\n\nVkSurfaceKHR initSurface( VkInstance instance, PlatformWindow window );\n// killSurface() is not platform dependent\n\nvoid setSizeEventHandler( std::function<void(void)> newSizeEventHandler );\nvoid setPaintEventHandler( std::function<void(void)> newPaintEventHandler );\n\nvoid showWindow( PlatformWindow window );\n\nuint32_t getWindowWidth( PlatformWindow window ){ return window.impl->width; }\nuint32_t getWindowHeight( PlatformWindow window ){ return window.impl->height; }\n\n// Implementation\n//////////////////////////////////\n\nbool nullHandler(){ return false; }\n\nstd::function<bool(void)> sizeEventHandler = nullHandler;\n\nvoid setSizeEventHandler( std::function<bool(void)> newSizeEventHandler ){\n\tif( !newSizeEventHandler ) sizeEventHandler = nullHandler;\n\tsizeEventHandler = newSizeEventHandler;\n}\n\nstd::function<void(void)> paintEventHandler = nullHandler;\n\nvoid setPaintEventHandler( std::function<void(void)> newPaintEventHandler ){\n\tif( !newPaintEventHandler ) paintEventHandler = nullHandler;\n\tpaintEventHandler = newPaintEventHandler;\n}\n\nbool platformPresentationSupport( VkInstance instance, VkPhysicalDevice device, uint32_t queueFamilyIndex, PlatformWindow window ){\n\treturn vkGetPhysicalDeviceWaylandPresentationSupportKHR( device, queueFamilyIndex, window.impl->display ) == VK_TRUE;\n}\n\nvoid registryGlobalHandler( void* data, wl_registry* registry, uint32_t name, const char* interface, uint32_t version ) noexcept{\n\t//logger << \"registry: \" << interface << std::endl;\n\tPlatformWindowImpl* window = (PlatformWindowImpl*)data;\n\n\tif(  std::strcmp( interface, \"wl_compositor\" ) == 0 && !window->compositor  ){\n\t\twindow->compositor = (wl_compositor*)wl_registry_bind( registry, name, &wl_compositor_interface, 1 );\n\t\twindow->compositorName = name;\n\t}\n\telse if(  std::strcmp( interface, \"xdg_wm_base\" ) == 0 && !window->wmBase  ){\n\t\twindow->wmBase = (xdg_wm_base*)wl_registry_bind( registry, name, &xdg_wm_base_interface, 1 );\n\t\twindow->wmBaseName = name;\n\t}\n\telse if(  std::strcmp( interface, \"wl_seat\" ) == 0 && !window->seat ){\n\t\twindow->seat = (wl_seat*)wl_registry_bind( registry, name, &wl_seat_interface, 1 );\n\t\twindow->seatName = name;\n\t}\n\n\tTODO( \"Add Wayland server side decorations when supported.\" );\n}\n\nvoid registryGlobalRemoveHandler( void* data, wl_registry* registry, uint32_t name ) noexcept{\n\t//logger << \"registry remove \" << name << std::endl;\n\tPlatformWindowImpl* window = (PlatformWindowImpl*)data;\n\n\tif( name == window->compositorName ) throw \"Needed wl_compositor removed from registry.\";\n\tif( name == window->wmBaseName ) throw \"Needed xdg_wm_base removed from registry.\";\n\tif( name == window->seatName ) throw \"Needed wl_seat removed from registry.\";\n}\n\nvoid seatCapsHandler( void* data, wl_seat* seat, uint32_t caps ) noexcept{\n\t//logger << \"wl_seat caps: \" << caps << std::endl;\n\n\tRUNTIME_ASSERT( caps & WL_SEAT_CAPABILITY_POINTER, \"Obtaining pointer wl_seat\" );\n\tRUNTIME_ASSERT( caps & WL_SEAT_CAPABILITY_KEYBOARD, \"Obtaining keyboard wl_seat\" );\n}\n\nvoid keyboardKeymapHandler( void* data, wl_keyboard* keyboard, uint32_t format, int32_t fd, uint32_t size ) noexcept{\n\t//logger << \"wl_keyboard format: \" << format << \", keymap size: \" << size << std::endl;\n\n\tRUNTIME_ASSERT( format == WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1, \"Obtaining XKB V1 keymap\" );\n\n\tPlatformWindowImpl* wnd = (PlatformWindowImpl*)data;\n\tassert( wnd->xkbContext );\n\n\txkb_state_unref( wnd->xkbState );\n\txkb_keymap_unref( wnd->keymap );\n\n\tconst char* keymapBuffer = (const char*)mmap( nullptr, size, PROT_READ, MAP_PRIVATE, fd, 0 ); RUNTIME_ASSERT( keymapBuffer != MAP_FAILED, \"mmap of keymap\")\n\twnd->keymap = xkb_keymap_new_from_string( wnd->xkbContext, keymapBuffer, XKB_KEYMAP_FORMAT_TEXT_V1, XKB_KEYMAP_COMPILE_NO_FLAGS ); RUNTIME_ASSERT( wnd->keymap, \"xkb_keymap_new_from_string\" );\n\t{const auto err = munmap( (void*)keymapBuffer, size ); RUNTIME_ASSERT( !err, \"munmap of keymap\" );}\n\t{const auto err = close( fd ); RUNTIME_ASSERT( !err, \"close of keymap fd\" );}\n\twnd->xkbState  = xkb_state_new( wnd->keymap );\n}\n\nvoid keyboardKeyHandler( void* data, wl_keyboard* keyboard, uint32_t serial, uint32_t time, uint32_t key, uint32_t state ) noexcept{\n\t//logger << \"wl_keyboard key: key=\" << key << \", state=\" << state << std::endl;\n\n\tPlatformWindowImpl* wnd = (PlatformWindowImpl*)data;\n\n\tconst xkb_keycode_t keycode = key + 8; // +8 per Wayland spec\n\tconst xkb_keysym_t keysym = xkb_state_key_get_one_sym( wnd->xkbState, keycode );\n\n\tif( state == WL_KEYBOARD_KEY_STATE_PRESSED ){\n\t\tswitch( keysym ){\n\t\t\tcase XKB_KEY_Escape:\n\t\t\t\twnd->quit = true;\n\t\t\t\tbreak;\n\t\t\tcase XKB_KEY_Alt_L:\n\t\t\t\twnd->alt = true;\n\t\t\t\tbreak;\n\t\t\tcase XKB_KEY_Return:\n\t\t\t\tif( wnd->alt ){\n\t\t\t\t\tif( wnd->fullscreen ) xdg_toplevel_unset_fullscreen( wnd->toplevel );\n\t\t\t\t\telse xdg_toplevel_set_fullscreen( wnd->toplevel, nullptr );\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t}\n\t}\n\telse if( state == WL_KEYBOARD_KEY_STATE_RELEASED ){\n\t\tswitch( keysym ){\n\t\t\tcase XKB_KEY_Alt_L:\n\t\t\t\twnd->alt = false;\n\t\t\t\tbreak;\n\t\t}\n\t}\n}\n\nvoid pointerButtonHandler( void* data, wl_pointer* wl_pointer, uint32_t serial, uint32_t time, uint32_t button, uint32_t state ){\n\tPlatformWindowImpl* wnd = (PlatformWindowImpl*)data;\n\n\tif( state == WL_POINTER_BUTTON_STATE_PRESSED ){\n\t\tswitch( button ){\n\t\t\tcase BTN_LEFT:\n\t\t\t\txdg_toplevel_move( wnd->toplevel, wnd->seat, serial );\n\t\t\t\tbreak;\n\t\t\tcase BTN_RIGHT:\n\t\t\t\txdg_toplevel_resize( wnd->toplevel, wnd->seat, serial, XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_RIGHT );\n\t\t\t\tbreak;\n\t\t}\n\t}\n}\n\nvoid xdgSurfaceConfigureHandler( void* data, xdg_surface* xdg_surface, uint32_t serial ) noexcept{\n\t//logger << \"xdg_surface config\" << std::endl;\n\tPlatformWindowImpl* window = (PlatformWindowImpl*)data;\n\tassert( window->inited );\n\n\txdg_surface_ack_configure( xdg_surface, serial );\n}\n\nconst char* state_to_string( uint32_t state ){\n\tswitch( state ){\n\t\tcase XDG_TOPLEVEL_STATE_MAXIMIZED:    return \"maximized\";\n\t\tcase XDG_TOPLEVEL_STATE_FULLSCREEN:   return \"fullscreen\";\n\t\tcase XDG_TOPLEVEL_STATE_RESIZING:     return \"resizing\";\n\t\tcase XDG_TOPLEVEL_STATE_ACTIVATED:    return \"activated\";\n\t\t// v2:\n\t\tcase XDG_TOPLEVEL_STATE_TILED_LEFT:   return \"tiled_left\";\n\t\tcase XDG_TOPLEVEL_STATE_TILED_RIGHT:  return \"tiled_right\";\n\t\tcase XDG_TOPLEVEL_STATE_TILED_TOP:    return \"tiled_top\";\n\t\tcase XDG_TOPLEVEL_STATE_TILED_BOTTOM: return \"tiled_bottom\";\n\t\tdefault: return \"unrecognized state\";\n\t}\n}\n\nbool hasState( const std::vector<uint32_t>& states, const uint32_t state ){\n\tfor( const auto s : states ) if( s == state ) return true;\n\treturn false;\n}\n\nvoid toplevelConfigureHandler( void* data, xdg_toplevel* toplevel, int32_t width, int32_t height, wl_array* states ) noexcept{\n\t//logger << \"toplevel config: w=\" << width << \", h=\" << height << \", states={\";\n\n\tstd::vector<uint32_t> statesv;\n\tfor( uint32_t* state = (uint32_t*)states->data; (const uint8_t*) state < ((const uint8_t*) states->data + states->size); ++state ){\n\t\tstatesv.push_back( *state );\n\t}\n\n/*\n\tbool first = true;\n\tfor( const auto state : statesv ){\n\t\tif( !first ) logger << \", \";\n\t\telse first = false;\n\t\tlogger << state_to_string( state );\n\t}\n\tlogger << \"}\\n\";\n*/\n\n\tPlatformWindowImpl* wnd = (PlatformWindowImpl*)data;\n\tassert( wnd->inited );\n\n\tif( width != wnd->width || height != wnd->height ){\n\t\tif( !(width == 0 && height == 0) ){\n\t\t\twnd->width = static_cast<uint32_t>( width );\n\t\t\twnd->height = static_cast<uint32_t>( height );\n\n\t\t\tif(  !hasState( statesv, XDG_TOPLEVEL_STATE_MAXIMIZED )\n\t\t\t  && !hasState( statesv, XDG_TOPLEVEL_STATE_FULLSCREEN )  ){\n\t\t\t\twnd->restoredWidth = static_cast<uint32_t>( width );\n\t\t\t\twnd->restoredHeight = static_cast<uint32_t>( height );\n\t\t\t}\n\t\t}\n\t\telse{\n\t\t\twnd->width = wnd->restoredWidth;\n\t\t\twnd->height = wnd->restoredHeight;\n\t\t}\n\n\t\twnd->hasSwapchain = sizeEventHandler();\n\t}\n\n\tif(  hasState( statesv, XDG_TOPLEVEL_STATE_FULLSCREEN )  ) wnd->fullscreen = true;\n\telse wnd->fullscreen = false;\n\n\tif(  hasState( statesv, XDG_TOPLEVEL_STATE_MAXIMIZED )  ) wnd->maximized = true;\n\telse wnd->maximized = false;\n}\n\nvoid toplevelCloseHandler( void* data, xdg_toplevel* xdg_toplevel ) noexcept{\n\t//logger << \"toplevel close\" << std::endl;\n\n\tPlatformWindowImpl* window = (PlatformWindowImpl*)data;\n\twindow->quit = true;\n}\n\nvoid wmBasePingHandler( void* data, xdg_wm_base* xdg_wm_base, uint32_t serial ) noexcept{\n\t//logger << \"wm_base ping\" << std::endl;\n\txdg_wm_base_pong( xdg_wm_base, serial );\n}\n\nconst wl_registry_listener registryListener = { registryGlobalHandler, registryGlobalRemoveHandler };\nconst wl_seat_listener seatListener = { seatCapsHandler, [](void*, wl_seat*, const char*){} };\nTODO( \"Should probably implement some of these callbacks.\");\nconst wl_keyboard_listener keyboardListener = { keyboardKeymapHandler, [](void*, wl_keyboard*, uint32_t, wl_surface*, wl_array*){}, [](void*, wl_keyboard*, uint32_t, wl_surface*){}, keyboardKeyHandler, [](void*, wl_keyboard*, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t){} };\nconst wl_pointer_listener pointerListener = { [](void*, wl_pointer*, uint32_t, wl_surface*, wl_fixed_t, wl_fixed_t){}, [](void*, wl_pointer*, uint32_t, wl_surface*){}, [](void*, wl_pointer*, uint32_t, wl_fixed_t, wl_fixed_t){}, pointerButtonHandler, [](void*, wl_pointer*, uint32_t, uint32_t, wl_fixed_t){} };\nconst xdg_wm_base_listener xdgWmBaseListerner = { wmBasePingHandler };\nconst xdg_surface_listener xdgSurfaceListener = { xdgSurfaceConfigureHandler };\nconst xdg_toplevel_listener xdgToplevelListener = { toplevelConfigureHandler, toplevelCloseHandler };\n\nPlatformWindow initWindow( const std::string& name, uint32_t canvasWidth, uint32_t canvasHeight ){\n\tauto wnd = std::make_shared<PlatformWindowImpl>();\n\n\twnd->width = canvasWidth;\n\twnd->restoredWidth = canvasWidth;\n\twnd->height = canvasHeight;\n\twnd->restoredHeight = canvasHeight;\n\n\twnd->display = wl_display_connect( nullptr ); RUNTIME_ASSERT( wnd->display, \"wl_display_connect\" );\n\twnd->registry = wl_display_get_registry( wnd->display ); RUNTIME_ASSERT( wnd->registry, \"wl_display_get_registry\" );\n\t{const auto err = wl_registry_add_listener( wnd->registry, &::registryListener, wnd.get() ); RUNTIME_ASSERT( !err, \"wl_registry_add_listener\" );}\n\n\t{const auto dispatched = wl_display_roundtrip( wnd->display ); RUNTIME_ASSERT( dispatched != -1, \"wl_display_roundtrip\" );}\n\t// dispatch should be redundant to the roundtrip, but I like it explicit\n\t{const auto dispatched = wl_display_dispatch_pending( wnd->display ); RUNTIME_ASSERT( dispatched != -1, \"wl_display_dispatch_pending\" );}\n\tRUNTIME_ASSERT( wnd->compositor, \"wl_registry_bind(\\\"wl_compositor\\\")\" );\n\tRUNTIME_ASSERT( wnd->wmBase, \"wl_registry_bind(\\\"xdg_wm_base\\\")\" );\n\tRUNTIME_ASSERT( wnd->seat, \"wl_registry_bind(\\\"wl_seat\\\")\" );\n\n\twnd->xkbContext = xkb_context_new( XKB_CONTEXT_NO_FLAGS ); RUNTIME_ASSERT( wnd->xkbContext, \"xkb_context_new\" );\n\n\t{const auto err = wl_seat_add_listener( wnd->seat, &seatListener, wnd.get() ); RUNTIME_ASSERT( !err, \"wl_seat_add_listener\" );}\n\t{const auto dispatched = wl_display_roundtrip( wnd->display ); RUNTIME_ASSERT( dispatched != -1, \"wl_display_roundtrip\" );}\n\t{const auto dispatched = wl_display_dispatch_pending( wnd->display ); RUNTIME_ASSERT( dispatched != -1, \"wl_display_dispatch_pending\" );}\n\n\twnd->keyboard = wl_seat_get_keyboard( wnd->seat ); RUNTIME_ASSERT( wnd->keyboard, \"wl_seat_get_keyboard\" );\n\t{const auto err = wl_keyboard_add_listener( wnd->keyboard, &keyboardListener, wnd.get() ); RUNTIME_ASSERT( !err, \"wl_keyboard_add_listener\" );}\n\twnd->pointer = wl_seat_get_pointer( wnd->seat ); RUNTIME_ASSERT( wnd->pointer, \"wl_seat_get_pointer\" );\n\t{const auto err = wl_pointer_add_listener( wnd->pointer, &pointerListener, wnd.get() ); RUNTIME_ASSERT( !err, \"wl_pointer_add_listener\" );}\n\n\twnd->surface = wl_compositor_create_surface( wnd->compositor ); RUNTIME_ASSERT( wnd->surface, \"wl_compositor_create_surface\" );\n\n\t{const auto err = xdg_wm_base_add_listener( wnd->wmBase, &xdgWmBaseListerner, wnd.get() ); RUNTIME_ASSERT( !err, \"xdg_wm_base_add_listener\" );}\n\twnd->xdgSurface = xdg_wm_base_get_xdg_surface( wnd->wmBase, wnd->surface ); RUNTIME_ASSERT( wnd->xdgSurface, \"xdg_wm_base_get_xdg_surface\" );\n\twnd->toplevel = xdg_surface_get_toplevel( wnd->xdgSurface ); RUNTIME_ASSERT( wnd->toplevel, \"xdg_surface_get_toplevel\" );\n\t{const auto err = xdg_surface_add_listener( wnd->xdgSurface, &xdgSurfaceListener, wnd.get() ); RUNTIME_ASSERT( !err, \"xdg_surface_add_listener\" );}\n\t{const auto err = xdg_toplevel_add_listener( wnd->toplevel, &xdgToplevelListener, wnd.get() ); RUNTIME_ASSERT( !err, \"xdg_toplevel_add_listener\" );}\n\n\twnd->title = name + \" -- Wayland\";\n\txdg_toplevel_set_title( wnd->toplevel, \"wnd->title.c_str()\" );\n\tTODO( \"Shows \\\"Unknown\\\" in Ubuntu on taskbar.\")\n\n\twl_surface_commit( wnd->surface );\n\t{const auto sent = wl_display_flush( wnd->display ); RUNTIME_ASSERT( sent != -1, \"wl_display_flush\" );}\n\n\twnd->inited = true;\n\treturn {wnd};\n}\n\nvoid killWindow( PlatformWindow window ){\n\tconst auto wnd = window.impl;\n\twnd->inited = false;\n\n\txkb_state_unref( wnd->xkbState );\n\txkb_keymap_unref( wnd->keymap );\n\txkb_context_unref( wnd->xkbContext );\n\n\tTODO( \"Explicitly kill all Wayland stuff\" );\n\twl_display_disconnect( wnd->display );\n}\n\nvoid showWindow( PlatformWindow windowh ){\n\tauto wnd = windowh.impl;\n\n\t// wait for first size event\n\t{const auto dispatched = wl_display_roundtrip( wnd->display ); RUNTIME_ASSERT( dispatched != -1, \"wl_display_roundtrip\" );}\n\t// dispatch should be redundant to the roundtrip, but I like it explicit\n\t{const auto dispatched = wl_display_dispatch_pending( wnd->display ); RUNTIME_ASSERT( dispatched != -1, \"wl_display_dispatch_pending\" );}\n\n\tassert( wnd->hasSwapchain );\n\n\t// In Wayland window is mapped with first present\n\tpaintEventHandler();\n}\n\nint messageLoop( PlatformWindow windowh ){\n\tauto wnd = windowh.impl;\n\twnd->quit = false;\n\n\twhile( !wnd->quit ){\n\t\t{const auto dispatched = wl_display_dispatch_pending( wnd->display ); RUNTIME_ASSERT( dispatched != -1, \"wl_display_dispatch_pending\" );}\n\n\t\tif( wnd->hasSwapchain ){\n\t\t\tTODO( \"Use frame callback instead?\" );\n\t\t\tpaintEventHandler();\n\t\t}\n\t}\n\n\treturn 0;\n}\n\nVkSurfaceKHR initSurface( VkInstance instance, PlatformWindow windowh ){\n\tauto wnd = windowh.impl;\n\n\tconst VkWaylandSurfaceCreateInfoKHR surfaceInfo{\n\t\tVK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR,\n\t\tnullptr, // pNext for extensions use\n\t\t0, // flags - reserved for future use\n\t\twnd->display,\n\t\twnd->surface\n\t};\n\n\tVkSurfaceKHR surface;\n\tVkResult errorCode = vkCreateWaylandSurfaceKHR( instance, &surfaceInfo, nullptr, &surface ); RESULT_HANDLER( errorCode, \"vkCreateWaylandSurfaceKHR\" );\n\treturn surface;\n}\n\n\n#endif //COMMON_WAYLAND_WSI_H"
  },
  {
    "path": "src/WSI/Win32.h",
    "content": "// win32 platform dependent WSI handling and event loop\r\n\r\n#ifndef COMMON_WIN32_WSI_H\r\n#define COMMON_WIN32_WSI_H\r\n\r\n#include <functional>\r\n#include <string>\r\n#include <vector>\r\n#include <cassert>\r\n\r\n#include <Windows.h>\r\n#include <vulkan/vulkan.h>\r\n\r\n#include \"CompilerMessages.h\"\r\n#include \"ErrorHandling.h\"\r\n\r\n\r\nTODO( \"Easier to use, but might prevent platform co-existence. Could be namespaced. Make all of this a class?\" )\r\nstruct PlatformWindow{ HINSTANCE hInstance; HWND hWnd; };\r\n\r\nDWORD windowedStyle = WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS;\r\nDWORD windowedExStyle = WS_EX_OVERLAPPEDWINDOW;\r\n\r\nstd::string getPlatformSurfaceExtensionName(){ return VK_KHR_WIN32_SURFACE_EXTENSION_NAME; };\r\n\r\nint messageLoop( PlatformWindow window );\r\n\r\nbool platformPresentationSupport( VkInstance instance, VkPhysicalDevice device, uint32_t queueFamilyIndex, PlatformWindow window );\r\n\r\nPlatformWindow initWindow( const std::string& name, uint32_t canvasWidth, uint32_t canvasHeight );\r\nvoid killWindow( PlatformWindow window );\r\n\r\nVkSurfaceKHR initSurface( VkInstance instance, PlatformWindow window );\r\n// killSurface() is not platform dependent\r\n\r\nvoid setSizeEventHandler( std::function<void(void)> newSizeEventHandler );\r\nvoid setPaintEventHandler( std::function<void(void)> newPaintEventHandler );\r\n\r\nvoid showWindow( PlatformWindow window );\r\n\r\n// Implementation\r\n//////////////////////////////////\r\n\r\nbool nullHandler(){ return false; }\r\n\r\nstd::function<bool(void)> sizeEventHandler = nullHandler;\r\n\r\nvoid setSizeEventHandler( std::function<bool(void)> newSizeEventHandler ){\r\n\tif( !newSizeEventHandler ) sizeEventHandler = nullHandler;\r\n\tsizeEventHandler = newSizeEventHandler;\r\n}\r\n\r\nstd::function<void(void)> paintEventHandler = nullHandler;\r\n\r\nvoid setPaintEventHandler( std::function<void(void)> newPaintEventHandler ){\r\n\tif( !newPaintEventHandler ) paintEventHandler = nullHandler;\r\n\tpaintEventHandler = newPaintEventHandler;\r\n}\r\n\r\nvoid showWindow( PlatformWindow window ){\r\n\tShowWindow( window.hWnd, SW_SHOW );\r\n\tSetForegroundWindow( window.hWnd );\r\n}\r\n\r\nbool hasSwapchain = false;\r\n\r\nint messageLoop( PlatformWindow window ){\r\n\tUNREFERENCED_PARAMETER( window );\r\n\r\n\tMSG msg;\r\n\tBOOL ret = GetMessageW( &msg, NULL, 0, 0 );\r\n\r\n\tfor( ; ret; ret = GetMessageW( &msg, NULL, 0, 0 ) ){\r\n\t\t\tTranslateMessage( &msg );\r\n\t\t\tDispatchMessageW( &msg ); //dispatch to wndProc; ignore return from wndProc\r\n\t}\r\n\r\n\tif( ret == -1 ) throw std::string( \"Trouble getting message: \" ) + std::to_string( GetLastError() );\r\n\r\n\treturn static_cast<int>( msg.wParam );\r\n}\r\n\r\nvoid toggleFullscreen( HWND hWnd ){\r\n\tTODO( \"All of this needs to be made a class... death to the static!\" )\r\n\tstatic bool isFullscreen = false;\r\n\tstatic int wx = 100;\r\n\tstatic int wy = 100;\r\n\tstatic int ww = 800;\r\n\tstatic int wh = 800;\r\n\r\n\tDWORD style, exStyle;\r\n\tint x, y, width, height;\r\n\r\n\tif( !isFullscreen ){\r\n\t\twindowedStyle = GetWindowLongW( hWnd, GWL_STYLE );\r\n\t\tif( !windowedStyle && GetLastError() != ERROR_SUCCESS ) throw std::string( \"Trouble setting window style: \" ) + std::to_string( GetLastError() );\r\n\r\n\t\twindowedExStyle = GetWindowLongW( hWnd, GWL_EXSTYLE );\r\n\t\tif( !windowedExStyle && GetLastError() != ERROR_SUCCESS ) throw std::string( \"Trouble setting window ex style: \" ) + std::to_string( GetLastError() );\r\n\r\n\t\tconst DWORD fullscreenStyle = ::windowedStyle & ~(WS_CAPTION | WS_THICKFRAME);\r\n\t\tconst DWORD fullscreenExStyle = ::windowedExStyle & ~(WS_EX_DLGMODALFRAME | WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE | WS_EX_STATICEDGE);\r\n\r\n\t\tstyle = fullscreenStyle;\r\n\t\texStyle = fullscreenExStyle;\r\n\r\n\t\tMONITORINFO monitorInfo;\r\n\t\tmonitorInfo.cbSize = sizeof( MONITORINFO );\r\n\t\t{\r\n\t\t\tconst auto succ = GetMonitorInfo(  MonitorFromWindow( hWnd, MONITOR_DEFAULTTOPRIMARY ), &monitorInfo  );\r\n\t\t\tif( !succ ) throw std::string( \"Trouble getting window monitor info: \" ) + std::to_string( GetLastError() );\r\n\t\t}\r\n\t\tx = monitorInfo.rcMonitor.left;\r\n\t\ty = monitorInfo.rcMonitor.top;\r\n\t\twidth = monitorInfo.rcMonitor.right - x; assert( width >= 0 );\r\n\t\theight = monitorInfo.rcMonitor.bottom - y; assert( height >= 0 );\r\n\r\n\t\tRECT wndRect;\r\n\t\t{\r\n\t\t\tconst auto succ = GetWindowRect( hWnd, &wndRect );\r\n\t\t\tif( !succ ) throw std::string( \"Trouble getting window dimensions: \" ) + std::to_string( GetLastError() );\r\n\t\t}\r\n\t\twx = wndRect.left;\r\n\t\twy = wndRect.top;\r\n\t\tww = wndRect.right - wx;\r\n\t\twh = wndRect.bottom - wy;\r\n\t}\r\n\telse {\r\n\t\tstyle = ::windowedStyle;\r\n\t\texStyle = ::windowedExStyle;\r\n\r\n\t\tx = wx;\r\n\t\ty = wy;\r\n\t\twidth = ww;\r\n\t\theight = wh;\r\n\t}\r\n\r\n\tisFullscreen = !isFullscreen;\r\n\r\n\tassert( GetLastError() == ERROR_SUCCESS );\r\n\t{\r\n\t\tconst auto succ = SetWindowLongW( hWnd, GWL_STYLE, style );\r\n\t\tif( !succ && GetLastError() != ERROR_SUCCESS ) throw std::string( \"Trouble setting window style: \" ) + std::to_string( GetLastError() );\r\n\t}\r\n\t{\r\n\t\tconst auto succ = SetWindowLongW( hWnd, GWL_EXSTYLE, exStyle );\r\n\t\tif( !succ && GetLastError() != ERROR_SUCCESS ) throw std::string( \"Trouble setting window ex style: \" ) + std::to_string( GetLastError() );\r\n\t}\r\n\t{\r\n\t\tconst auto succ = SetWindowPos( hWnd, HWND_TOP, x, y, width, height, SWP_FRAMECHANGED | SWP_NOACTIVATE | SWP_NOCOPYBITS | SWP_NOZORDER );\r\n\t\tif( !succ ) throw std::string( \"Trouble resizing window to fullscreen: \" ) + std::to_string( GetLastError() );\r\n\t}\r\n}\r\n\r\nLRESULT CALLBACK wndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam ){\r\n\tswitch( uMsg ){\r\n\t\tcase WM_CLOSE:\r\n\t\t\tPostQuitMessage( 0 );\r\n\t\t\treturn 0;\r\n\r\n\t\tcase WM_ERASEBKGND:\r\n\t\t\t//logger << \"erase\\n\";\r\n\t\t\t//return DefWindowProc( hWnd, uMsg, wParam, lParam );\r\n\t\t\treturn 0; // background will be cleared by Vulkan in WM_PAINT instead\r\n\r\n\t\t//case WM_NCCALCSIZE:\r\n\t\t//\t//logger << \"nccalcsize \" << wParam << \" \" << lParam << endl;\r\n\t\t//\treturn DefWindowProc( hWnd, uMsg, wParam, lParam );\r\n\r\n\t\tcase WM_SIZE:\r\n\t\t\t//logger << \"size \" << wParam << \" \" << LOWORD( lParam ) << \"x\" << HIWORD( lParam ) << std::endl;\r\n\t\t\thasSwapchain = sizeEventHandler();\r\n\t\t\tif( !hasSwapchain ) ValidateRect( hWnd, NULL ); // prevent WM_PAINT on minimized window\r\n\t\t\treturn 0;\r\n\r\n\t\tcase WM_PAINT: // sent after WM_SIZE -- react to this immediately to resize seamlessly\r\n\t\t\t//logger << \"paint\\n\";\r\n\t\t\tpaintEventHandler();\r\n\t\t\t//ValidateRect( hWnd, NULL ); // never validate so window always gets redrawn\r\n\t\t\treturn 0;\r\n\r\n\t\tcase WM_KEYDOWN:\r\n\t\t\tswitch( wParam ){\r\n\t\t\tcase VK_ESCAPE:\r\n\t\t\t\tPostQuitMessage( 0 );\r\n\t\t\t\treturn 0;\r\n\t\t\tdefault:\r\n\t\t\t\treturn DefWindowProc( hWnd, uMsg, wParam, lParam );\r\n\t\t\t}\r\n\r\n\t\tcase WM_SYSCOMMAND:\r\n\t\t\tswitch( wParam ){\r\n\t\t\tcase SC_KEYMENU:\r\n\t\t\t\tif( lParam == VK_RETURN ){ // Alt-Enter without \"no sysmenu hotkey exists\" beep\r\n\t\t\t\t\ttoggleFullscreen( hWnd );\r\n\t\t\t\t\treturn 0;\r\n\t\t\t\t}\r\n\t\t\t\telse return DefWindowProc( hWnd, uMsg, wParam, lParam );\r\n\t\t\tdefault:\r\n\t\t\t\treturn DefWindowProc( hWnd, uMsg, wParam, lParam );\r\n\t\t\t}\r\n\r\n\t\tdefault:\r\n\t\t\t//logger << \"unknown \" << std::hex << std::showbase << uMsg  << std::endl;\r\n\t\t\treturn DefWindowProc( hWnd, uMsg, wParam, lParam );\r\n\t}\r\n}\r\n\r\n\r\nbool platformPresentationSupport( VkInstance instance, VkPhysicalDevice device, uint32_t queueFamilyIndex, PlatformWindow ){\r\n\tUNREFERENCED_PARAMETER( instance );\r\n\r\n\treturn vkGetPhysicalDeviceWin32PresentationSupportKHR( device, queueFamilyIndex ) == VK_TRUE;\r\n}\r\n\r\nATOM classAtom = 0;\r\nuint64_t classAtomRefCount = 0;\r\n\r\nATOM initWindowClass(){\r\n\tHINSTANCE hInstance = GetModuleHandleW( NULL );\r\n\r\n\tif( classAtom == 0 ){\r\n\t\tWNDCLASSEXW windowClass = {\r\n\t\t\tsizeof( WNDCLASSEXW ), // cbSize\r\n\t\t\tCS_OWNDC /*| CS_HREDRAW | CS_VREDRAW*/, // style -- some window behavior\r\n\t\t\twndProc, // lpfnWndProc -- set event handler\r\n\t\t\t0, // cbClsExtra -- set 0 extra bytes after class\r\n\t\t\t0, // cbWndExtra -- set 0 extra bytes after class instance\r\n\t\t\thInstance, // hInstance\r\n\t\t\tLoadIconW( NULL, IDI_APPLICATION ), // hIcon -- application icon\r\n\t\t\tLoadCursorW( NULL, IDC_ARROW ), // hCursor -- cursor inside\r\n\t\t\tNULL, //(HBRUSH)( COLOR_WINDOW + 1 ), // hbrBackground\r\n\t\t\tNULL, // lpszMenuName -- menu class name\r\n\t\t\tTEXT(\"vkwc\"), // lpszClassName -- window class name/identificator\r\n\t\t\tLoadIconW( NULL, IDI_APPLICATION ) // hIconSm\r\n\t\t};\r\n\r\n\t\t// register window class\r\n\t\tclassAtom = RegisterClassExW( &windowClass );\r\n\t\tif( !classAtom ){\r\n\t\t\tthrow std::string( \"Trouble registering window class: \" ) + std::to_string( GetLastError() );\r\n\t\t}\r\n\t}\r\n\r\n\t++classAtomRefCount;\r\n\treturn classAtom;\r\n}\r\n\r\nPlatformWindow initWindow( const std::string& name, uint32_t canvasWidth, uint32_t canvasHeight ){\r\n\tusing std::string;\r\n\tusing std::to_string;\r\n\r\n\tconst string title = name + \" -- Win32\";\r\n\tconst auto titleU16Size = MultiByteToWideChar( CP_UTF8, 0, title.c_str(), -1, nullptr, 0 );\r\n\tstd::vector<wchar_t> titleU16( titleU16Size );\r\n\tconst auto success = MultiByteToWideChar( CP_UTF8, 0, title.c_str(), -1, titleU16.data(), titleU16Size );\r\n\r\n\tHINSTANCE hInstance = GetModuleHandleW( NULL );\r\n\r\n\tATOM wndClassAtom = initWindowClass();\r\n\r\n\t// adjust size of window to contain given size canvas\r\n\tRECT windowRect = { 0, 0, static_cast<LONG>(canvasWidth), static_cast<LONG>(canvasHeight) };\r\n\tif(  !AdjustWindowRectEx( &windowRect, ::windowedStyle, FALSE, ::windowedExStyle )  ){\r\n\t\tthrow string( \"Trouble adjusting window size: \" ) + to_string( GetLastError() );\r\n\t}\r\n\r\n\t// create window instance\r\n\tHWND hWnd =  CreateWindowExW(\r\n\t\t::windowedExStyle,\r\n\t\tMAKEINTATOM(wndClassAtom),\r\n\t\ttitleU16.data(),\r\n\t\t::windowedStyle,\r\n\t\tCW_USEDEFAULT, CW_USEDEFAULT,\r\n\t\twindowRect.right - windowRect.left, windowRect.bottom - windowRect.top,\r\n\t\tNULL,\r\n\t\tNULL,\r\n\t\thInstance,\r\n\t\tNULL\r\n\t);\r\n\tif( !hWnd  ){\r\n\t\tthrow string( \"Trouble creating window instance: \" ) + to_string( GetLastError() );\r\n\t}\r\n\r\n\treturn { hInstance, hWnd };\r\n}\r\n\r\nvoid killWindow( PlatformWindow window ){\r\n\tusing std::string;\r\n\tusing std::to_string;\r\n\r\n\tif(  !DestroyWindow( window.hWnd )  ) throw string( \"Trouble destroying window instance: \" ) + to_string( GetLastError() );\r\n\r\n\t--classAtomRefCount;\r\n\tif( classAtomRefCount == 0 ){\r\n\t\tif(  !UnregisterClassW( MAKEINTATOM(classAtom), window.hInstance )  ){\r\n\t\t\tthrow string( \"Trouble unregistering window class: \" ) + to_string( GetLastError() );\r\n\t\t}\r\n\t}\r\n}\r\n\r\nVkSurfaceKHR initSurface( VkInstance instance, PlatformWindow window ){\r\n\tVkWin32SurfaceCreateInfoKHR surfaceInfo{\r\n\t\tVK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR,\r\n\t\tnullptr, // pNext for extensions use\r\n\t\t0, // flags - reserved for future use\r\n\t\twindow.hInstance,\r\n\t\twindow.hWnd\r\n\t};\r\n\r\n\r\n\tVkSurfaceKHR surface;\r\n\tVkResult errorCode = vkCreateWin32SurfaceKHR( instance, &surfaceInfo, nullptr, &surface ); RESULT_HANDLER( errorCode, \"vkCreateWin32SurfaceKHR\" );\r\n\r\n\treturn surface;\r\n}\r\n\r\n\r\n#endif //COMMON_WIN32_WSI_H"
  },
  {
    "path": "src/WSI/Xcb.h",
    "content": "// XCB linux platform dependent WSI handling and event loop\r\n\r\n#ifndef COMMON_XCB_WSI_H\r\n#define COMMON_XCB_WSI_H\r\n\r\n#include <functional>\r\n#include <string>\r\n#include <cstring>\r\n\r\n#include <xcb/xcb.h>\r\n#include <xcb/xcb_util.h>\r\n#include <xcb/xcb_keysyms.h>\r\n#include <X11/keysym.h>\r\n#include <vulkan/vulkan.h>\r\n\r\n#include \"CompilerMessages.h\"\r\n#include \"ErrorHandling.h\"\r\n\r\n\r\nTODO( \"Easier to use, but might prevent platform co-existence. Could be namespaced. Make all of this a class?\" )\r\nstruct PlatformWindow{ xcb_connection_t* connection; xcb_window_t window; xcb_visualid_t visual_id; };\r\n\r\nstd::string getPlatformSurfaceExtensionName(){ return VK_KHR_XCB_SURFACE_EXTENSION_NAME; };\r\n\r\nint messageLoop( PlatformWindow window );\r\n\r\nbool platformPresentationSupport( VkInstance instance, VkPhysicalDevice device, uint32_t queueFamilyIndex, PlatformWindow window );\r\n\r\nPlatformWindow initWindow( const std::string& name, uint32_t canvasWidth, uint32_t canvasHeight );\r\nvoid killWindow( PlatformWindow window );\r\n\r\nVkSurfaceKHR initSurface( VkInstance instance, PlatformWindow window );\r\n// killSurface() is not platform dependent\r\n\r\nvoid setSizeEventHandler( std::function<void(void)> newSizeEventHandler );\r\nvoid setPaintEventHandler( std::function<void(void)> newPaintEventHandler );\r\n\r\nvoid showWindow( PlatformWindow window );\r\n\r\n// Implementation\r\n//////////////////////////////////\r\n\r\nbool nullHandler(){ return false; }\r\n\r\nstd::function<bool(void)> sizeEventHandler = nullHandler;\r\n\r\nvoid setSizeEventHandler( std::function<bool(void)> newSizeEventHandler ){\r\n\tif( !newSizeEventHandler ) sizeEventHandler = nullHandler;\r\n\tsizeEventHandler = newSizeEventHandler;\r\n}\r\n\r\nstd::function<void(void)> paintEventHandler = nullHandler;\r\n\r\nvoid setPaintEventHandler( std::function<void(void)> newPaintEventHandler ){\r\n\tif( !newPaintEventHandler ) paintEventHandler = nullHandler;\r\n\tpaintEventHandler = newPaintEventHandler;\r\n}\r\n\r\nvoid showWindow( PlatformWindow window ){\r\n\txcb_map_window( window.connection, window.window );\r\n\txcb_flush( window.connection );\r\n}\r\n\r\nint messageLoop( PlatformWindow window ){\r\n\tint width = -1;\r\n\tint height = -1;\r\n\tbool hasSwapchain = false;\r\n\r\n\tbool quit = false;\r\n\r\n\twhile( !quit ){\r\n\t\txcb_generic_event_t* e = hasSwapchain ? xcb_poll_for_event( window.connection ) : xcb_wait_for_event( window.connection );\r\n\r\n\t\tif( e ){\r\n\t\t\tswitch( e->response_type & ~0x80 ){\r\n\t\t\t\tcase XCB_EXPOSE:\r\n\t\t\t\t\tpaintEventHandler();\r\n\t\t\t\t\tbreak;\r\n\r\n\t\t\t\tcase XCB_CONFIGURE_NOTIFY:{\r\n\t\t\t\t\txcb_configure_notify_event_t* ce = (xcb_configure_notify_event_t*)e;\r\n\t\t\t\t\tif( ce->width != width || ce->height != height ){\r\n\t\t\t\t\t\twidth = ce->width;\r\n\t\t\t\t\t\theight = ce->height;\r\n\r\n\t\t\t\t\t\thasSwapchain = sizeEventHandler();\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tbreak;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tcase XCB_KEY_PRESS:{\r\n\t\t\t\t\txcb_key_press_event_t* kpe = (xcb_key_release_event_t*)e;\r\n\r\n\t\t\t\t\txcb_key_symbols_t* keysyms = xcb_key_symbols_alloc( window.connection );\r\n\r\n\t\t\t\t\tswitch(  xcb_key_press_lookup_keysym( keysyms, kpe, 0 )  ){\r\n\t\t\t\t\t\tcase XK_Escape:\r\n\t\t\t\t\t\t\tquit = true;\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\txcb_key_symbols_free( keysyms );\r\n\r\n\t\t\t\t\t/*\r\n\t\t\t\t\tswitch( kpe->detail ){\r\n\t\t\t\t\t\tcase 9: // ESC\r\n\t\t\t\t\t\t\tquit = true;\r\n\t\t\t\t\t}\r\n\t\t\t\t\t*/\r\n\t\t\t\t\tbreak;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tcase XCB_CLIENT_MESSAGE:{\r\n\t\t\t\t\txcb_client_message_event_t* cme = (xcb_client_message_event_t*)e;\r\n\r\n\t\t\t\t\txcb_intern_atom_cookie_t wmdelCookie = xcb_intern_atom( window.connection, 1, 16, \"WM_DELETE_WINDOW\" );\r\n\t\t\t\t\txcb_intern_atom_reply_t* wmdelReply = xcb_intern_atom_reply( window.connection, wmdelCookie, 0 );\r\n\t\t\t\t\txcb_atom_t ATOM_WM_DELETE_WINDOW = wmdelReply->atom;\r\n\t\t\t\t\tfree( wmdelReply );\r\n\r\n\t\t\t\t\tif( cme->data.data32[0] == ATOM_WM_DELETE_WINDOW ){\r\n\t\t\t\t\t\tquit = true;\r\n\t\t\t\t\t}\r\n\t\t\t\t\tbreak;\r\n\t\t\t\t}\r\n\r\n\t\t\t\t//default:\r\n\t\t\t\t//\tthrow \"Unrecognized event type!\";\r\n\t\t\t}\r\n\r\n\t\t\tfree( e );\r\n\t\t}\r\n\t\telse if( hasSwapchain ){ // no events pending\r\n\t\t\tpaintEventHandler();\r\n\t\t}\r\n\t}\r\n\r\n\treturn 0;\r\n}\r\n\r\n\r\nbool platformPresentationSupport( VkInstance instance, VkPhysicalDevice device, uint32_t queueFamilyIndex, PlatformWindow window ){\r\n\treturn vkGetPhysicalDeviceXcbPresentationSupportKHR( device, queueFamilyIndex, window.connection, window.visual_id ) == VK_TRUE;\r\n}\r\n\r\nstd::string to_string_xcb_conn( int error ){\r\n\tswitch( error ){\r\n\t\tcase 0: return \"XCB_CONN_SUCCESS\";\r\n\t\tcase XCB_CONN_ERROR: return \"XCB_CONN_ERROR\";\r\n\t\tcase XCB_CONN_CLOSED_EXT_NOTSUPPORTED: return \"XCB_CONN_CLOSED_EXT_NOTSUPPORTED\";\r\n\t\tcase XCB_CONN_CLOSED_MEM_INSUFFICIENT: return \"XCB_CONN_CLOSED_MEM_INSUFFICIENT\";\r\n\t\tcase XCB_CONN_CLOSED_REQ_LEN_EXCEED: return \"XCB_CONN_CLOSED_REQ_LEN_EXCEED\";\r\n\t\tcase XCB_CONN_CLOSED_PARSE_ERR: return \"XCB_CONN_CLOSED_PARSE_ERR\";\r\n\t\tcase XCB_CONN_CLOSED_INVALID_SCREEN: return \"XCB_CONN_CLOSED_INVALID_SCREEN\";\r\n\t\tdefault: return \"unrecognized XCB connection error\";\r\n\t}\r\n}\r\n\r\nxcb_connection_t* initXcbConnection(){\r\n\txcb_connection_t* connection = xcb_connect( nullptr, nullptr );\r\n\r\n\tint err = xcb_connection_has_error( connection );\r\n\tif( err ){\r\n\t\txcb_disconnect( connection );\r\n\t\tthrow std::string( \"Failed to create XCB connection: \" ) + to_string_xcb_conn( err );\r\n\t}\r\n\r\n\treturn connection;\r\n}\r\n\r\nvoid killXcbConnection( xcb_connection_t* connection ){\r\n\txcb_disconnect( connection );\r\n}\r\n\r\nPlatformWindow initWindow( const std::string& name, uint32_t canvasWidth, uint32_t canvasHeight ){\r\n\txcb_connection_t* connection = initXcbConnection();\r\n\r\n\txcb_screen_t* screen = xcb_setup_roots_iterator(  xcb_get_setup( connection )  ).data;\r\n\r\n\tuint32_t masks =\r\n\t\t/*  XCB_CW_BACK_PIXMAP\r\n\t\t| XCB_CW_BACK_PIXEL\r\n\t\t| XCB_CW_BORDER_PIXMAP\r\n\t\t| XCB_CW_BORDER_PIXEL\r\n\t\t| XCB_CW_BIT_GRAVITY\r\n\t\t| XCB_CW_WIN_GRAVITY\r\n\t\t| XCB_CW_BACKING_STORE\r\n\t\t| XCB_CW_BACKING_PLANES\r\n\t\t| XCB_CW_BACKING_PIXEL\r\n\t\t| XCB_CW_OVERRIDE_REDIRECT\r\n\t\t| XCB_CW_SAVE_UNDER\r\n\t\t|*/ XCB_CW_EVENT_MASK\r\n\t\t/*| XCB_CW_DONT_PROPAGATE\r\n\t\t| XCB_CW_COLORMAP\r\n\t\t| XCB_CW_CURSOR*/\r\n\t;\r\n\r\n\tuint32_t values[] = {\r\n\t\tXCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_KEY_PRESS | XCB_EVENT_MASK_STRUCTURE_NOTIFY\r\n\t};\r\n\r\n\r\n\txcb_window_t window = xcb_generate_id( connection );\r\n\txcb_create_window(\r\n\t\tconnection,\r\n\t\tXCB_COPY_FROM_PARENT,\r\n\t\twindow,\r\n\t\tscreen->root,\r\n\t\t0, 0, // x, y\r\n\t\tstatic_cast<uint16_t>( canvasWidth ), static_cast<uint16_t>( canvasHeight ),\r\n\t\t1, //border_width\r\n\t\tXCB_WINDOW_CLASS_INPUT_OUTPUT,\r\n\t\tscreen->root_visual,\r\n\t\tmasks,\r\n\t\tvalues\r\n\t); \r\n\r\n\tstd::string title = name + \" -- XCB\";\r\n\r\n\txcb_change_property(  connection, XCB_PROP_MODE_REPLACE, window, XCB_ATOM_WM_NAME, XCB_ATOM_STRING, 8, title.size(), title.c_str()  );\r\n\txcb_change_property(  connection, XCB_PROP_MODE_REPLACE, window, XCB_ATOM_WM_ICON_NAME, XCB_ATOM_STRING, 8, title.size(), title.c_str()  );\r\n\r\n\r\n\txcb_intern_atom_cookie_t wmprotCookie = xcb_intern_atom( connection, 1, 12, \"WM_PROTOCOLS\" );\r\n\txcb_intern_atom_reply_t* wmprotReply = xcb_intern_atom_reply( connection, wmprotCookie, 0 );\r\n\txcb_atom_t ATOM_WM_PROTOCOLS = wmprotReply->atom;\r\n\tfree( wmprotReply );\r\n\r\n\txcb_intern_atom_cookie_t wmdelCookie = xcb_intern_atom( connection, 0, 16, \"WM_DELETE_WINDOW\" );\r\n\txcb_intern_atom_reply_t* wmdelReply = xcb_intern_atom_reply( connection, wmdelCookie, 0 );\r\n\txcb_atom_t ATOM_WM_DELETE_WINDOW = wmdelReply->atom;\r\n\tfree( wmdelReply );\r\n\r\n\t// undocumented magic from random mailing list everybody seems to use\r\n\txcb_change_property( connection, XCB_PROP_MODE_REPLACE, window, ATOM_WM_PROTOCOLS, XCB_ATOM_ATOM, 32, 1, &ATOM_WM_DELETE_WINDOW );\r\n\r\n\txcb_flush( connection );\r\n\treturn { connection, window, screen->root_visual };\r\n}\r\n\r\nvoid killWindow( PlatformWindow window ){\r\n\txcb_destroy_window( window.connection, window.window );\r\n\txcb_flush( window.connection );\r\n\r\n\tkillXcbConnection( window.connection );\r\n}\r\n\r\nVkSurfaceKHR initSurface( VkInstance instance, PlatformWindow window ){\r\n\tVkXcbSurfaceCreateInfoKHR surfaceInfo{\r\n\t\tVK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR,\r\n\t\tnullptr, // pNext for extensions use\r\n\t\t0, // flags - reserved for future use\r\n\t\twindow.connection,\r\n\t\twindow.window\r\n\t};\r\n\r\n\r\n\tVkSurfaceKHR surface;\r\n\tVkResult errorCode = vkCreateXcbSurfaceKHR( instance, &surfaceInfo, nullptr, &surface ); RESULT_HANDLER( errorCode, \"vkCreateXcbSurfaceKHR\" );\r\n\r\n\treturn surface;\r\n}\r\n\r\n\r\n#endif //COMMON_XCB_WSI_H\r\n"
  },
  {
    "path": "src/WSI/Xlib.h",
    "content": "// Xlib linux platform dependent WSI handling and event loop\r\n\r\n#ifndef COMMON_XLIB_WSI_H\r\n#define COMMON_XLIB_WSI_H\r\n\r\n#include <functional>\r\n#include <string>\r\n\r\n#include <X11/Xlib.h>\r\n#include <X11/Xutil.h>\r\n#include <vulkan/vulkan.h>\r\n\r\n#include \"CompilerMessages.h\"\r\n#include \"ErrorHandling.h\"\r\n\r\n\r\nTODO( \"Easier to use, but might prevent platform co-existence. Could be namespaced. Make all of this a class?\" )\r\nstruct PlatformWindow{ Display* display; Window window; VisualID visual_id; };\r\n\r\nstd::string getPlatformSurfaceExtensionName(){ return VK_KHR_XLIB_SURFACE_EXTENSION_NAME; };\r\n\r\nPlatformWindow initWindow( const std::string& name, uint32_t canvasWidth, uint32_t canvasHeight );\r\nvoid killWindow( PlatformWindow window );\r\n\r\nbool platformPresentationSupport( VkInstance instance, VkPhysicalDevice device, uint32_t queueFamilyIndex, PlatformWindow window );\r\n\r\nVkSurfaceKHR initSurface( VkInstance instance, PlatformWindow window );\r\n// killSurface() is not platform dependent\r\n\r\nvoid setSizeEventHandler( std::function<void(void)> newSizeEventHandler );\r\nvoid setPaintEventHandler( std::function<void(void)> newPaintEventHandler );\r\n\r\nvoid showWindow( PlatformWindow window );\r\n\r\nint messageLoop( PlatformWindow window );\r\n\r\n// Implementation\r\n//////////////////////////////////\r\n\r\nclass XlibSingleton{\r\n\tstatic const XlibSingleton xlibInstance;\r\n\r\n\tXlibSingleton(){\r\n\t\tconst auto success = XInitThreads();\r\n\t\tif( !success ) throw \"Failed to XInitThreads().\";\r\n\t}\r\n\r\n\t~XlibSingleton(){}\r\n};\r\nconst XlibSingleton XlibSingleton::xlibInstance;\r\n\r\nDisplay* initXlibDisplay(){\r\n\tDisplay* display = XOpenDisplay( nullptr );\r\n\r\n\tif( !display ) throw \"Failed to create Xlib Display*.\";\r\n\r\n\treturn display;\r\n}\r\n\r\nvoid killXlibDisplay( Display* display ){\r\n\tXCloseDisplay( display );\r\n}\r\n\r\nPlatformWindow initWindow( const std::string& name, uint32_t canvasWidth, uint32_t canvasHeight ){\r\n\tDisplay* display = initXlibDisplay();\r\n\r\n\tXLockDisplay( display );\r\n\r\n\t\tScreen* screen = XDefaultScreenOfDisplay( display );\r\n\r\n\t\tVisualID visual_id = XVisualIDFromVisual(  XDefaultVisualOfScreen( screen )  );\r\n\r\n\t\tWindow root_window = XRootWindowOfScreen( screen );\r\n\r\n\t\t//auto black = XBlackPixelOfScreen( screen );\r\n\t\t//auto white = XWhitePixelOfScreen( screen );\r\n\r\n\t\tunsigned long masks =\r\n\t\t\t/*  CWBackPixmap\r\n\t\t\t| CWBackPixel\r\n\t\t\t| CWBorderPixmap\r\n\t\t\t| CWBorderPixel\r\n\t\t\t| CWBitGravity\r\n\t\t\t| CWWinGravity\r\n\t\t\t| CWBackingStore\r\n\t\t\t| CWBackingPlanes\r\n\t\t\t| CWBackingPixel\r\n\t\t\t| CWOverrideRedirect\r\n\t\t\t| CWSaveUnder\r\n\t\t\t|*/ CWEventMask\r\n\t\t\t/*| CWDontPropagate\r\n\t\t\t| CWColormap\r\n\t\t\t| CWCursor*/\r\n\t\t;\r\n\r\n\t\tXSetWindowAttributes values;\r\n\t\tvalues.event_mask = ExposureMask | KeyPressMask | StructureNotifyMask;\r\n\r\n\r\n\t\tWindow window = XCreateWindow(\r\n\t\t\tdisplay,\r\n\t\t\troot_window,\r\n\t\t\t0, 0, // x, y\r\n\t\t\tstatic_cast<unsigned int>( canvasWidth ), static_cast<unsigned int>( canvasHeight ),\r\n\t\t\t1, //border_width\r\n\t\t\tCopyFromParent,\r\n\t\t\tInputOutput,\r\n\t\t\tCopyFromParent,\r\n\t\t\tmasks,\r\n\t\t\t&values\r\n\t\t); \r\n\r\n\t\tconst std::string title = name + \" -- Xlib\";\r\n\r\n\t\tXStoreName( display, window, title.c_str() );\r\n\t\tXSetIconName( display, window, title.c_str() );\r\n\r\n\t\tAtom WM_DELETE_WINDOW = XInternAtom( display, \"WM_DELETE_WINDOW\", False );\r\n\t\tXSetWMProtocols( display, window, &WM_DELETE_WINDOW, 1 );\r\n\r\n\t\tXFlush( display );\r\n\tXUnlockDisplay( display );\r\n\treturn { display, window, visual_id };\r\n}\r\n\r\nvoid killWindow( PlatformWindow window ){\r\n\tXLockDisplay( window.display );\r\n\t\tXDestroyWindow( window.display, window.window );\r\n\t\tXFlush( window.display );\r\n\tXUnlockDisplay( window.display );\t\r\n\r\n\tkillXlibDisplay( window.display );\r\n}\r\n\r\nbool platformPresentationSupport( VkInstance instance, VkPhysicalDevice device, uint32_t queueFamilyIndex, PlatformWindow window ){\r\n\treturn vkGetPhysicalDeviceXlibPresentationSupportKHR( device, queueFamilyIndex, window.display, window.visual_id ) == VK_TRUE;\r\n}\r\n\r\nVkSurfaceKHR initSurface( VkInstance instance, PlatformWindow window ){\r\n\tVkXlibSurfaceCreateInfoKHR surfaceInfo{\r\n\t\tVK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR,\r\n\t\tnullptr, // pNext for extensions use\r\n\t\t0, // flags - reserved for future use\r\n\t\twindow.display,\r\n\t\twindow.window\r\n\t};\r\n\r\n\r\n\tVkSurfaceKHR surface;\r\n\tVkResult errorCode = vkCreateXlibSurfaceKHR( instance, &surfaceInfo, nullptr, &surface ); RESULT_HANDLER( errorCode, \"vkCreateXlibSurfaceKHR\" );\r\n\r\n\treturn surface;\r\n}\r\n\r\n\r\nbool nullHandler(){ return false; }\r\n\r\nstd::function<bool(void)> sizeEventHandler = nullHandler;\r\n\r\nvoid setSizeEventHandler( std::function<bool(void)> newSizeEventHandler ){\r\n\tif( !newSizeEventHandler ) sizeEventHandler = nullHandler;\r\n\tsizeEventHandler = newSizeEventHandler;\r\n}\r\n\r\nstd::function<void(void)> paintEventHandler = nullHandler;\r\n\r\nvoid setPaintEventHandler( std::function<void(void)> newPaintEventHandler ){\r\n\tif( !newPaintEventHandler ) paintEventHandler = nullHandler;\r\n\tpaintEventHandler = newPaintEventHandler;\r\n}\r\n\r\nvoid showWindow( PlatformWindow window ){\r\n\tXLockDisplay( window.display );\r\n\t\tXMapWindow( window.display, window.window );\r\n\t\tXFlush( window.display );\r\n\tXUnlockDisplay( window.display );\r\n}\r\n\r\nint messageLoop( PlatformWindow window ){\r\n\tint width = -1;\r\n\tint height = -1;\r\n\tbool hasSwapchain = false;\r\n\r\n\tbool quit = false;\r\n\r\n\twhile( !quit ){\r\n\t\tXEvent e;\r\n\t\tbool hasEvent = true;\r\n\t\tconst auto always = []( Display*, XEvent*, XPointer ) -> Bool{return true;};\r\n\t\tXLockDisplay( window.display );\r\n\t\t\tif( hasSwapchain ) hasEvent = XCheckIfEvent( window.display, &e, always, nullptr );\r\n\t\t\telse XNextEvent( window.display, &e );\r\n\t\tXUnlockDisplay( window.display );\r\n\r\n\t\tif( hasEvent ){\r\n\t\t\tswitch( e.type  ){\r\n\t\t\t\tcase Expose:\r\n\t\t\t\t\tpaintEventHandler();\r\n\t\t\t\t\tbreak;\r\n\r\n\t\t\t\tcase ConfigureNotify:{\r\n\t\t\t\t\tXConfigureEvent ce = e.xconfigure;\r\n\t\t\t\t\tif( ce.width != width || ce.height != height ){\r\n\t\t\t\t\t\twidth = ce.width;\r\n\t\t\t\t\t\theight = ce.height;\r\n\r\n\t\t\t\t\t\thasSwapchain = sizeEventHandler();\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tbreak;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tcase KeyPress:{\r\n\t\t\t\t\tXKeyPressedEvent kpe = e.xkey;\r\n\r\n\t\t\t\t\tXLockDisplay( window.display );\r\n\t\t\t\t\t\tKeySym key = XLookupKeysym( &kpe, 0 );\r\n\t\t\t\t\tXUnlockDisplay( window.display );\r\n\r\n\t\t\t\t\tswitch( key ){\r\n\t\t\t\t\t\tcase XK_Escape:\r\n\t\t\t\t\t\t\tquit = true;\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tbreak;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tcase ClientMessage:{\r\n\t\t\t\t\tXClientMessageEvent cme = e.xclient;\r\n\r\n\t\t\t\t\tXLockDisplay( window.display );\r\n\t\t\t\t\t\tAtom WM_DELETE_WINDOW = XInternAtom( window.display, \"WM_DELETE_WINDOW\", True );\r\n\t\t\t\t\tXUnlockDisplay( window.display );\r\n\r\n\t\t\t\t\tif( (Atom)cme.data.l[0] == WM_DELETE_WINDOW ){\r\n\t\t\t\t\t\tquit = true;\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tbreak;\r\n\t\t\t\t}\r\n\r\n\t\t\t\t//default:\r\n\t\t\t\t//\tthrow \"Unrecognized event type!\";\r\n\t\t\t}\r\n\t\t}\r\n\t\telse if( hasSwapchain ){\r\n\t\t\tpaintEventHandler();\r\n\t\t}\r\n\r\n\t}\r\n\r\n\treturn 0;\r\n}\r\n\r\n\r\n#endif //COMMON_XLIB_WSI_H\r\n"
  },
  {
    "path": "src/WSI/private/xdg-shell-client-protocol-private.inl",
    "content": "/* Generated by wayland-scanner 1.16.0 */\n\n/*\n * Copyright © 2008-2013 Kristian Høgsberg\n * Copyright © 2013      Rafael Antognolli\n * Copyright © 2013      Jasper St. Pierre\n * Copyright © 2010-2013 Intel Corporation\n * Copyright © 2015-2017 Samsung Electronics Co., Ltd\n * Copyright © 2015-2017 Red Hat Inc.\n *\n * Permission is hereby granted, free of charge, to any person obtaining a\n * copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation\n * the rights to use, copy, modify, merge, publish, distribute, sublicense,\n * and/or sell copies of the Software, and to permit persons to whom the\n * Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice (including the next\n * paragraph) shall be included in all copies or substantial portions of the\n * Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL\n * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n * DEALINGS IN THE SOFTWARE.\n */\n\n#include <stdlib.h>\n#include <stdint.h>\n#include \"wayland-util.h\"\n\n#ifndef __has_attribute\n# define __has_attribute(x) 0  /* Compatibility with non-clang compilers. */\n#endif\n\n#if (__has_attribute(visibility) || defined(__GNUC__) && __GNUC__ >= 4)\n#define WL_PRIVATE __attribute__ ((visibility(\"hidden\")))\n#else\n#define WL_PRIVATE\n#endif\n\nextern const struct wl_interface wl_output_interface;\nextern const struct wl_interface wl_seat_interface;\nextern const struct wl_interface wl_surface_interface;\nextern const struct wl_interface xdg_popup_interface;\nextern const struct wl_interface xdg_positioner_interface;\nextern const struct wl_interface xdg_surface_interface;\nextern const struct wl_interface xdg_toplevel_interface;\n\nstatic const struct wl_interface *types[] = {\n\tNULL,\n\tNULL,\n\tNULL,\n\tNULL,\n\t&xdg_positioner_interface,\n\t&xdg_surface_interface,\n\t&wl_surface_interface,\n\t&xdg_toplevel_interface,\n\t&xdg_popup_interface,\n\t&xdg_surface_interface,\n\t&xdg_positioner_interface,\n\t&xdg_toplevel_interface,\n\t&wl_seat_interface,\n\tNULL,\n\tNULL,\n\tNULL,\n\t&wl_seat_interface,\n\tNULL,\n\t&wl_seat_interface,\n\tNULL,\n\tNULL,\n\t&wl_output_interface,\n\t&wl_seat_interface,\n\tNULL,\n};\n\nstatic const struct wl_message xdg_wm_base_requests[] = {\n\t{ \"destroy\", \"\", types + 0 },\n\t{ \"create_positioner\", \"n\", types + 4 },\n\t{ \"get_xdg_surface\", \"no\", types + 5 },\n\t{ \"pong\", \"u\", types + 0 },\n};\n\nstatic const struct wl_message xdg_wm_base_events[] = {\n\t{ \"ping\", \"u\", types + 0 },\n};\n\nWL_PRIVATE const struct wl_interface xdg_wm_base_interface = {\n\t\"xdg_wm_base\", 2,\n\t4, xdg_wm_base_requests,\n\t1, xdg_wm_base_events,\n};\n\nstatic const struct wl_message xdg_positioner_requests[] = {\n\t{ \"destroy\", \"\", types + 0 },\n\t{ \"set_size\", \"ii\", types + 0 },\n\t{ \"set_anchor_rect\", \"iiii\", types + 0 },\n\t{ \"set_anchor\", \"u\", types + 0 },\n\t{ \"set_gravity\", \"u\", types + 0 },\n\t{ \"set_constraint_adjustment\", \"u\", types + 0 },\n\t{ \"set_offset\", \"ii\", types + 0 },\n};\n\nWL_PRIVATE const struct wl_interface xdg_positioner_interface = {\n\t\"xdg_positioner\", 2,\n\t7, xdg_positioner_requests,\n\t0, NULL,\n};\n\nstatic const struct wl_message xdg_surface_requests[] = {\n\t{ \"destroy\", \"\", types + 0 },\n\t{ \"get_toplevel\", \"n\", types + 7 },\n\t{ \"get_popup\", \"n?oo\", types + 8 },\n\t{ \"set_window_geometry\", \"iiii\", types + 0 },\n\t{ \"ack_configure\", \"u\", types + 0 },\n};\n\nstatic const struct wl_message xdg_surface_events[] = {\n\t{ \"configure\", \"u\", types + 0 },\n};\n\nWL_PRIVATE const struct wl_interface xdg_surface_interface = {\n\t\"xdg_surface\", 2,\n\t5, xdg_surface_requests,\n\t1, xdg_surface_events,\n};\n\nstatic const struct wl_message xdg_toplevel_requests[] = {\n\t{ \"destroy\", \"\", types + 0 },\n\t{ \"set_parent\", \"?o\", types + 11 },\n\t{ \"set_title\", \"s\", types + 0 },\n\t{ \"set_app_id\", \"s\", types + 0 },\n\t{ \"show_window_menu\", \"ouii\", types + 12 },\n\t{ \"move\", \"ou\", types + 16 },\n\t{ \"resize\", \"ouu\", types + 18 },\n\t{ \"set_max_size\", \"ii\", types + 0 },\n\t{ \"set_min_size\", \"ii\", types + 0 },\n\t{ \"set_maximized\", \"\", types + 0 },\n\t{ \"unset_maximized\", \"\", types + 0 },\n\t{ \"set_fullscreen\", \"?o\", types + 21 },\n\t{ \"unset_fullscreen\", \"\", types + 0 },\n\t{ \"set_minimized\", \"\", types + 0 },\n};\n\nstatic const struct wl_message xdg_toplevel_events[] = {\n\t{ \"configure\", \"iia\", types + 0 },\n\t{ \"close\", \"\", types + 0 },\n};\n\nWL_PRIVATE const struct wl_interface xdg_toplevel_interface = {\n\t\"xdg_toplevel\", 2,\n\t14, xdg_toplevel_requests,\n\t2, xdg_toplevel_events,\n};\n\nstatic const struct wl_message xdg_popup_requests[] = {\n\t{ \"destroy\", \"\", types + 0 },\n\t{ \"grab\", \"ou\", types + 22 },\n};\n\nstatic const struct wl_message xdg_popup_events[] = {\n\t{ \"configure\", \"iiii\", types + 0 },\n\t{ \"popup_done\", \"\", types + 0 },\n};\n\nWL_PRIVATE const struct wl_interface xdg_popup_interface = {\n\t\"xdg_popup\", 2,\n\t2, xdg_popup_requests,\n\t2, xdg_popup_events,\n};\n\n"
  },
  {
    "path": "src/WSI/private/xdg-shell-client-protocol.h",
    "content": "/* Generated by wayland-scanner 1.16.0 */\n\n#ifndef XDG_SHELL_CLIENT_PROTOCOL_H\n#define XDG_SHELL_CLIENT_PROTOCOL_H\n\n#include <stdint.h>\n#include <stddef.h>\n#include \"wayland-client.h\"\n\n#ifdef  __cplusplus\nextern \"C\" {\n#endif\n\n/**\n * @page page_xdg_shell The xdg_shell protocol\n * @section page_ifaces_xdg_shell Interfaces\n * - @subpage page_iface_xdg_wm_base - create desktop-style surfaces\n * - @subpage page_iface_xdg_positioner - child surface positioner\n * - @subpage page_iface_xdg_surface - desktop user interface surface base interface\n * - @subpage page_iface_xdg_toplevel - toplevel surface\n * - @subpage page_iface_xdg_popup - short-lived, popup surfaces for menus\n * @section page_copyright_xdg_shell Copyright\n * <pre>\n *\n * Copyright © 2008-2013 Kristian Høgsberg\n * Copyright © 2013      Rafael Antognolli\n * Copyright © 2013      Jasper St. Pierre\n * Copyright © 2010-2013 Intel Corporation\n * Copyright © 2015-2017 Samsung Electronics Co., Ltd\n * Copyright © 2015-2017 Red Hat Inc.\n *\n * Permission is hereby granted, free of charge, to any person obtaining a\n * copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation\n * the rights to use, copy, modify, merge, publish, distribute, sublicense,\n * and/or sell copies of the Software, and to permit persons to whom the\n * Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice (including the next\n * paragraph) shall be included in all copies or substantial portions of the\n * Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL\n * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n * DEALINGS IN THE SOFTWARE.\n * </pre>\n */\nstruct wl_output;\nstruct wl_seat;\nstruct wl_surface;\nstruct xdg_popup;\nstruct xdg_positioner;\nstruct xdg_surface;\nstruct xdg_toplevel;\nstruct xdg_wm_base;\n\n/**\n * @page page_iface_xdg_wm_base xdg_wm_base\n * @section page_iface_xdg_wm_base_desc Description\n *\n * The xdg_wm_base interface is exposed as a global object enabling clients\n * to turn their wl_surfaces into windows in a desktop environment. It\n * defines the basic functionality needed for clients and the compositor to\n * create windows that can be dragged, resized, maximized, etc, as well as\n * creating transient windows such as popup menus.\n * @section page_iface_xdg_wm_base_api API\n * See @ref iface_xdg_wm_base.\n */\n/**\n * @defgroup iface_xdg_wm_base The xdg_wm_base interface\n *\n * The xdg_wm_base interface is exposed as a global object enabling clients\n * to turn their wl_surfaces into windows in a desktop environment. It\n * defines the basic functionality needed for clients and the compositor to\n * create windows that can be dragged, resized, maximized, etc, as well as\n * creating transient windows such as popup menus.\n */\nextern const struct wl_interface xdg_wm_base_interface;\n/**\n * @page page_iface_xdg_positioner xdg_positioner\n * @section page_iface_xdg_positioner_desc Description\n *\n * The xdg_positioner provides a collection of rules for the placement of a\n * child surface relative to a parent surface. Rules can be defined to ensure\n * the child surface remains within the visible area's borders, and to\n * specify how the child surface changes its position, such as sliding along\n * an axis, or flipping around a rectangle. These positioner-created rules are\n * constrained by the requirement that a child surface must intersect with or\n * be at least partially adjacent to its parent surface.\n *\n * See the various requests for details about possible rules.\n *\n * At the time of the request, the compositor makes a copy of the rules\n * specified by the xdg_positioner. Thus, after the request is complete the\n * xdg_positioner object can be destroyed or reused; further changes to the\n * object will have no effect on previous usages.\n *\n * For an xdg_positioner object to be considered complete, it must have a\n * non-zero size set by set_size, and a non-zero anchor rectangle set by\n * set_anchor_rect. Passing an incomplete xdg_positioner object when\n * positioning a surface raises an error.\n * @section page_iface_xdg_positioner_api API\n * See @ref iface_xdg_positioner.\n */\n/**\n * @defgroup iface_xdg_positioner The xdg_positioner interface\n *\n * The xdg_positioner provides a collection of rules for the placement of a\n * child surface relative to a parent surface. Rules can be defined to ensure\n * the child surface remains within the visible area's borders, and to\n * specify how the child surface changes its position, such as sliding along\n * an axis, or flipping around a rectangle. These positioner-created rules are\n * constrained by the requirement that a child surface must intersect with or\n * be at least partially adjacent to its parent surface.\n *\n * See the various requests for details about possible rules.\n *\n * At the time of the request, the compositor makes a copy of the rules\n * specified by the xdg_positioner. Thus, after the request is complete the\n * xdg_positioner object can be destroyed or reused; further changes to the\n * object will have no effect on previous usages.\n *\n * For an xdg_positioner object to be considered complete, it must have a\n * non-zero size set by set_size, and a non-zero anchor rectangle set by\n * set_anchor_rect. Passing an incomplete xdg_positioner object when\n * positioning a surface raises an error.\n */\nextern const struct wl_interface xdg_positioner_interface;\n/**\n * @page page_iface_xdg_surface xdg_surface\n * @section page_iface_xdg_surface_desc Description\n *\n * An interface that may be implemented by a wl_surface, for\n * implementations that provide a desktop-style user interface.\n *\n * It provides a base set of functionality required to construct user\n * interface elements requiring management by the compositor, such as\n * toplevel windows, menus, etc. The types of functionality are split into\n * xdg_surface roles.\n *\n * Creating an xdg_surface does not set the role for a wl_surface. In order\n * to map an xdg_surface, the client must create a role-specific object\n * using, e.g., get_toplevel, get_popup. The wl_surface for any given\n * xdg_surface can have at most one role, and may not be assigned any role\n * not based on xdg_surface.\n *\n * A role must be assigned before any other requests are made to the\n * xdg_surface object.\n *\n * The client must call wl_surface.commit on the corresponding wl_surface\n * for the xdg_surface state to take effect.\n *\n * Creating an xdg_surface from a wl_surface which has a buffer attached or\n * committed is a client error, and any attempts by a client to attach or\n * manipulate a buffer prior to the first xdg_surface.configure call must\n * also be treated as errors.\n *\n * Mapping an xdg_surface-based role surface is defined as making it\n * possible for the surface to be shown by the compositor. Note that\n * a mapped surface is not guaranteed to be visible once it is mapped.\n *\n * For an xdg_surface to be mapped by the compositor, the following\n * conditions must be met:\n * (1) the client has assigned an xdg_surface-based role to the surface\n * (2) the client has set and committed the xdg_surface state and the\n * role-dependent state to the surface\n * (3) the client has committed a buffer to the surface\n *\n * A newly-unmapped surface is considered to have met condition (1) out\n * of the 3 required conditions for mapping a surface if its role surface\n * has not been destroyed.\n * @section page_iface_xdg_surface_api API\n * See @ref iface_xdg_surface.\n */\n/**\n * @defgroup iface_xdg_surface The xdg_surface interface\n *\n * An interface that may be implemented by a wl_surface, for\n * implementations that provide a desktop-style user interface.\n *\n * It provides a base set of functionality required to construct user\n * interface elements requiring management by the compositor, such as\n * toplevel windows, menus, etc. The types of functionality are split into\n * xdg_surface roles.\n *\n * Creating an xdg_surface does not set the role for a wl_surface. In order\n * to map an xdg_surface, the client must create a role-specific object\n * using, e.g., get_toplevel, get_popup. The wl_surface for any given\n * xdg_surface can have at most one role, and may not be assigned any role\n * not based on xdg_surface.\n *\n * A role must be assigned before any other requests are made to the\n * xdg_surface object.\n *\n * The client must call wl_surface.commit on the corresponding wl_surface\n * for the xdg_surface state to take effect.\n *\n * Creating an xdg_surface from a wl_surface which has a buffer attached or\n * committed is a client error, and any attempts by a client to attach or\n * manipulate a buffer prior to the first xdg_surface.configure call must\n * also be treated as errors.\n *\n * Mapping an xdg_surface-based role surface is defined as making it\n * possible for the surface to be shown by the compositor. Note that\n * a mapped surface is not guaranteed to be visible once it is mapped.\n *\n * For an xdg_surface to be mapped by the compositor, the following\n * conditions must be met:\n * (1) the client has assigned an xdg_surface-based role to the surface\n * (2) the client has set and committed the xdg_surface state and the\n * role-dependent state to the surface\n * (3) the client has committed a buffer to the surface\n *\n * A newly-unmapped surface is considered to have met condition (1) out\n * of the 3 required conditions for mapping a surface if its role surface\n * has not been destroyed.\n */\nextern const struct wl_interface xdg_surface_interface;\n/**\n * @page page_iface_xdg_toplevel xdg_toplevel\n * @section page_iface_xdg_toplevel_desc Description\n *\n * This interface defines an xdg_surface role which allows a surface to,\n * among other things, set window-like properties such as maximize,\n * fullscreen, and minimize, set application-specific metadata like title and\n * id, and well as trigger user interactive operations such as interactive\n * resize and move.\n *\n * Unmapping an xdg_toplevel means that the surface cannot be shown\n * by the compositor until it is explicitly mapped again.\n * All active operations (e.g., move, resize) are canceled and all\n * attributes (e.g. title, state, stacking, ...) are discarded for\n * an xdg_toplevel surface when it is unmapped.\n *\n * Attaching a null buffer to a toplevel unmaps the surface.\n * @section page_iface_xdg_toplevel_api API\n * See @ref iface_xdg_toplevel.\n */\n/**\n * @defgroup iface_xdg_toplevel The xdg_toplevel interface\n *\n * This interface defines an xdg_surface role which allows a surface to,\n * among other things, set window-like properties such as maximize,\n * fullscreen, and minimize, set application-specific metadata like title and\n * id, and well as trigger user interactive operations such as interactive\n * resize and move.\n *\n * Unmapping an xdg_toplevel means that the surface cannot be shown\n * by the compositor until it is explicitly mapped again.\n * All active operations (e.g., move, resize) are canceled and all\n * attributes (e.g. title, state, stacking, ...) are discarded for\n * an xdg_toplevel surface when it is unmapped.\n *\n * Attaching a null buffer to a toplevel unmaps the surface.\n */\nextern const struct wl_interface xdg_toplevel_interface;\n/**\n * @page page_iface_xdg_popup xdg_popup\n * @section page_iface_xdg_popup_desc Description\n *\n * A popup surface is a short-lived, temporary surface. It can be used to\n * implement for example menus, popovers, tooltips and other similar user\n * interface concepts.\n *\n * A popup can be made to take an explicit grab. See xdg_popup.grab for\n * details.\n *\n * When the popup is dismissed, a popup_done event will be sent out, and at\n * the same time the surface will be unmapped. See the xdg_popup.popup_done\n * event for details.\n *\n * Explicitly destroying the xdg_popup object will also dismiss the popup and\n * unmap the surface. Clients that want to dismiss the popup when another\n * surface of their own is clicked should dismiss the popup using the destroy\n * request.\n *\n * A newly created xdg_popup will be stacked on top of all previously created\n * xdg_popup surfaces associated with the same xdg_toplevel.\n *\n * The parent of an xdg_popup must be mapped (see the xdg_surface\n * description) before the xdg_popup itself.\n *\n * The x and y arguments passed when creating the popup object specify\n * where the top left of the popup should be placed, relative to the\n * local surface coordinates of the parent surface. See\n * xdg_surface.get_popup. An xdg_popup must intersect with or be at least\n * partially adjacent to its parent surface.\n *\n * The client must call wl_surface.commit on the corresponding wl_surface\n * for the xdg_popup state to take effect.\n * @section page_iface_xdg_popup_api API\n * See @ref iface_xdg_popup.\n */\n/**\n * @defgroup iface_xdg_popup The xdg_popup interface\n *\n * A popup surface is a short-lived, temporary surface. It can be used to\n * implement for example menus, popovers, tooltips and other similar user\n * interface concepts.\n *\n * A popup can be made to take an explicit grab. See xdg_popup.grab for\n * details.\n *\n * When the popup is dismissed, a popup_done event will be sent out, and at\n * the same time the surface will be unmapped. See the xdg_popup.popup_done\n * event for details.\n *\n * Explicitly destroying the xdg_popup object will also dismiss the popup and\n * unmap the surface. Clients that want to dismiss the popup when another\n * surface of their own is clicked should dismiss the popup using the destroy\n * request.\n *\n * A newly created xdg_popup will be stacked on top of all previously created\n * xdg_popup surfaces associated with the same xdg_toplevel.\n *\n * The parent of an xdg_popup must be mapped (see the xdg_surface\n * description) before the xdg_popup itself.\n *\n * The x and y arguments passed when creating the popup object specify\n * where the top left of the popup should be placed, relative to the\n * local surface coordinates of the parent surface. See\n * xdg_surface.get_popup. An xdg_popup must intersect with or be at least\n * partially adjacent to its parent surface.\n *\n * The client must call wl_surface.commit on the corresponding wl_surface\n * for the xdg_popup state to take effect.\n */\nextern const struct wl_interface xdg_popup_interface;\n\n#ifndef XDG_WM_BASE_ERROR_ENUM\n#define XDG_WM_BASE_ERROR_ENUM\nenum xdg_wm_base_error {\n\t/**\n\t * given wl_surface has another role\n\t */\n\tXDG_WM_BASE_ERROR_ROLE = 0,\n\t/**\n\t * xdg_wm_base was destroyed before children\n\t */\n\tXDG_WM_BASE_ERROR_DEFUNCT_SURFACES = 1,\n\t/**\n\t * the client tried to map or destroy a non-topmost popup\n\t */\n\tXDG_WM_BASE_ERROR_NOT_THE_TOPMOST_POPUP = 2,\n\t/**\n\t * the client specified an invalid popup parent surface\n\t */\n\tXDG_WM_BASE_ERROR_INVALID_POPUP_PARENT = 3,\n\t/**\n\t * the client provided an invalid surface state\n\t */\n\tXDG_WM_BASE_ERROR_INVALID_SURFACE_STATE = 4,\n\t/**\n\t * the client provided an invalid positioner\n\t */\n\tXDG_WM_BASE_ERROR_INVALID_POSITIONER = 5,\n};\n#endif /* XDG_WM_BASE_ERROR_ENUM */\n\n/**\n * @ingroup iface_xdg_wm_base\n * @struct xdg_wm_base_listener\n */\nstruct xdg_wm_base_listener {\n\t/**\n\t * check if the client is alive\n\t *\n\t * The ping event asks the client if it's still alive. Pass the\n\t * serial specified in the event back to the compositor by sending\n\t * a \"pong\" request back with the specified serial. See\n\t * xdg_wm_base.ping.\n\t *\n\t * Compositors can use this to determine if the client is still\n\t * alive. It's unspecified what will happen if the client doesn't\n\t * respond to the ping request, or in what timeframe. Clients\n\t * should try to respond in a reasonable amount of time.\n\t *\n\t * A compositor is free to ping in any way it wants, but a client\n\t * must always respond to any xdg_wm_base object it created.\n\t * @param serial pass this to the pong request\n\t */\n\tvoid (*ping)(void *data,\n\t\t     struct xdg_wm_base *xdg_wm_base,\n\t\t     uint32_t serial);\n};\n\n/**\n * @ingroup iface_xdg_wm_base\n */\nstatic inline int\nxdg_wm_base_add_listener(struct xdg_wm_base *xdg_wm_base,\n\t\t\t const struct xdg_wm_base_listener *listener, void *data)\n{\n\treturn wl_proxy_add_listener((struct wl_proxy *) xdg_wm_base,\n\t\t\t\t     (void (**)(void)) listener, data);\n}\n\n#define XDG_WM_BASE_DESTROY 0\n#define XDG_WM_BASE_CREATE_POSITIONER 1\n#define XDG_WM_BASE_GET_XDG_SURFACE 2\n#define XDG_WM_BASE_PONG 3\n\n/**\n * @ingroup iface_xdg_wm_base\n */\n#define XDG_WM_BASE_PING_SINCE_VERSION 1\n\n/**\n * @ingroup iface_xdg_wm_base\n */\n#define XDG_WM_BASE_DESTROY_SINCE_VERSION 1\n/**\n * @ingroup iface_xdg_wm_base\n */\n#define XDG_WM_BASE_CREATE_POSITIONER_SINCE_VERSION 1\n/**\n * @ingroup iface_xdg_wm_base\n */\n#define XDG_WM_BASE_GET_XDG_SURFACE_SINCE_VERSION 1\n/**\n * @ingroup iface_xdg_wm_base\n */\n#define XDG_WM_BASE_PONG_SINCE_VERSION 1\n\n/** @ingroup iface_xdg_wm_base */\nstatic inline void\nxdg_wm_base_set_user_data(struct xdg_wm_base *xdg_wm_base, void *user_data)\n{\n\twl_proxy_set_user_data((struct wl_proxy *) xdg_wm_base, user_data);\n}\n\n/** @ingroup iface_xdg_wm_base */\nstatic inline void *\nxdg_wm_base_get_user_data(struct xdg_wm_base *xdg_wm_base)\n{\n\treturn wl_proxy_get_user_data((struct wl_proxy *) xdg_wm_base);\n}\n\nstatic inline uint32_t\nxdg_wm_base_get_version(struct xdg_wm_base *xdg_wm_base)\n{\n\treturn wl_proxy_get_version((struct wl_proxy *) xdg_wm_base);\n}\n\n/**\n * @ingroup iface_xdg_wm_base\n *\n * Destroy this xdg_wm_base object.\n *\n * Destroying a bound xdg_wm_base object while there are surfaces\n * still alive created by this xdg_wm_base object instance is illegal\n * and will result in a protocol error.\n */\nstatic inline void\nxdg_wm_base_destroy(struct xdg_wm_base *xdg_wm_base)\n{\n\twl_proxy_marshal((struct wl_proxy *) xdg_wm_base,\n\t\t\t XDG_WM_BASE_DESTROY);\n\n\twl_proxy_destroy((struct wl_proxy *) xdg_wm_base);\n}\n\n/**\n * @ingroup iface_xdg_wm_base\n *\n * Create a positioner object. A positioner object is used to position\n * surfaces relative to some parent surface. See the interface description\n * and xdg_surface.get_popup for details.\n */\nstatic inline struct xdg_positioner *\nxdg_wm_base_create_positioner(struct xdg_wm_base *xdg_wm_base)\n{\n\tstruct wl_proxy *id;\n\n\tid = wl_proxy_marshal_constructor((struct wl_proxy *) xdg_wm_base,\n\t\t\t XDG_WM_BASE_CREATE_POSITIONER, &xdg_positioner_interface, NULL);\n\n\treturn (struct xdg_positioner *) id;\n}\n\n/**\n * @ingroup iface_xdg_wm_base\n *\n * This creates an xdg_surface for the given surface. While xdg_surface\n * itself is not a role, the corresponding surface may only be assigned\n * a role extending xdg_surface, such as xdg_toplevel or xdg_popup.\n *\n * This creates an xdg_surface for the given surface. An xdg_surface is\n * used as basis to define a role to a given surface, such as xdg_toplevel\n * or xdg_popup. It also manages functionality shared between xdg_surface\n * based surface roles.\n *\n * See the documentation of xdg_surface for more details about what an\n * xdg_surface is and how it is used.\n */\nstatic inline struct xdg_surface *\nxdg_wm_base_get_xdg_surface(struct xdg_wm_base *xdg_wm_base, struct wl_surface *surface)\n{\n\tstruct wl_proxy *id;\n\n\tid = wl_proxy_marshal_constructor((struct wl_proxy *) xdg_wm_base,\n\t\t\t XDG_WM_BASE_GET_XDG_SURFACE, &xdg_surface_interface, NULL, surface);\n\n\treturn (struct xdg_surface *) id;\n}\n\n/**\n * @ingroup iface_xdg_wm_base\n *\n * A client must respond to a ping event with a pong request or\n * the client may be deemed unresponsive. See xdg_wm_base.ping.\n */\nstatic inline void\nxdg_wm_base_pong(struct xdg_wm_base *xdg_wm_base, uint32_t serial)\n{\n\twl_proxy_marshal((struct wl_proxy *) xdg_wm_base,\n\t\t\t XDG_WM_BASE_PONG, serial);\n}\n\n#ifndef XDG_POSITIONER_ERROR_ENUM\n#define XDG_POSITIONER_ERROR_ENUM\nenum xdg_positioner_error {\n\t/**\n\t * invalid input provided\n\t */\n\tXDG_POSITIONER_ERROR_INVALID_INPUT = 0,\n};\n#endif /* XDG_POSITIONER_ERROR_ENUM */\n\n#ifndef XDG_POSITIONER_ANCHOR_ENUM\n#define XDG_POSITIONER_ANCHOR_ENUM\nenum xdg_positioner_anchor {\n\tXDG_POSITIONER_ANCHOR_NONE = 0,\n\tXDG_POSITIONER_ANCHOR_TOP = 1,\n\tXDG_POSITIONER_ANCHOR_BOTTOM = 2,\n\tXDG_POSITIONER_ANCHOR_LEFT = 3,\n\tXDG_POSITIONER_ANCHOR_RIGHT = 4,\n\tXDG_POSITIONER_ANCHOR_TOP_LEFT = 5,\n\tXDG_POSITIONER_ANCHOR_BOTTOM_LEFT = 6,\n\tXDG_POSITIONER_ANCHOR_TOP_RIGHT = 7,\n\tXDG_POSITIONER_ANCHOR_BOTTOM_RIGHT = 8,\n};\n#endif /* XDG_POSITIONER_ANCHOR_ENUM */\n\n#ifndef XDG_POSITIONER_GRAVITY_ENUM\n#define XDG_POSITIONER_GRAVITY_ENUM\nenum xdg_positioner_gravity {\n\tXDG_POSITIONER_GRAVITY_NONE = 0,\n\tXDG_POSITIONER_GRAVITY_TOP = 1,\n\tXDG_POSITIONER_GRAVITY_BOTTOM = 2,\n\tXDG_POSITIONER_GRAVITY_LEFT = 3,\n\tXDG_POSITIONER_GRAVITY_RIGHT = 4,\n\tXDG_POSITIONER_GRAVITY_TOP_LEFT = 5,\n\tXDG_POSITIONER_GRAVITY_BOTTOM_LEFT = 6,\n\tXDG_POSITIONER_GRAVITY_TOP_RIGHT = 7,\n\tXDG_POSITIONER_GRAVITY_BOTTOM_RIGHT = 8,\n};\n#endif /* XDG_POSITIONER_GRAVITY_ENUM */\n\n#ifndef XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_ENUM\n#define XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_ENUM\n/**\n * @ingroup iface_xdg_positioner\n * vertically resize the surface\n *\n * Resize the surface vertically so that it is completely unconstrained.\n */\nenum xdg_positioner_constraint_adjustment {\n\tXDG_POSITIONER_CONSTRAINT_ADJUSTMENT_NONE = 0,\n\tXDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_X = 1,\n\tXDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_Y = 2,\n\tXDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_X = 4,\n\tXDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_Y = 8,\n\tXDG_POSITIONER_CONSTRAINT_ADJUSTMENT_RESIZE_X = 16,\n\tXDG_POSITIONER_CONSTRAINT_ADJUSTMENT_RESIZE_Y = 32,\n};\n#endif /* XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_ENUM */\n\n#define XDG_POSITIONER_DESTROY 0\n#define XDG_POSITIONER_SET_SIZE 1\n#define XDG_POSITIONER_SET_ANCHOR_RECT 2\n#define XDG_POSITIONER_SET_ANCHOR 3\n#define XDG_POSITIONER_SET_GRAVITY 4\n#define XDG_POSITIONER_SET_CONSTRAINT_ADJUSTMENT 5\n#define XDG_POSITIONER_SET_OFFSET 6\n\n\n/**\n * @ingroup iface_xdg_positioner\n */\n#define XDG_POSITIONER_DESTROY_SINCE_VERSION 1\n/**\n * @ingroup iface_xdg_positioner\n */\n#define XDG_POSITIONER_SET_SIZE_SINCE_VERSION 1\n/**\n * @ingroup iface_xdg_positioner\n */\n#define XDG_POSITIONER_SET_ANCHOR_RECT_SINCE_VERSION 1\n/**\n * @ingroup iface_xdg_positioner\n */\n#define XDG_POSITIONER_SET_ANCHOR_SINCE_VERSION 1\n/**\n * @ingroup iface_xdg_positioner\n */\n#define XDG_POSITIONER_SET_GRAVITY_SINCE_VERSION 1\n/**\n * @ingroup iface_xdg_positioner\n */\n#define XDG_POSITIONER_SET_CONSTRAINT_ADJUSTMENT_SINCE_VERSION 1\n/**\n * @ingroup iface_xdg_positioner\n */\n#define XDG_POSITIONER_SET_OFFSET_SINCE_VERSION 1\n\n/** @ingroup iface_xdg_positioner */\nstatic inline void\nxdg_positioner_set_user_data(struct xdg_positioner *xdg_positioner, void *user_data)\n{\n\twl_proxy_set_user_data((struct wl_proxy *) xdg_positioner, user_data);\n}\n\n/** @ingroup iface_xdg_positioner */\nstatic inline void *\nxdg_positioner_get_user_data(struct xdg_positioner *xdg_positioner)\n{\n\treturn wl_proxy_get_user_data((struct wl_proxy *) xdg_positioner);\n}\n\nstatic inline uint32_t\nxdg_positioner_get_version(struct xdg_positioner *xdg_positioner)\n{\n\treturn wl_proxy_get_version((struct wl_proxy *) xdg_positioner);\n}\n\n/**\n * @ingroup iface_xdg_positioner\n *\n * Notify the compositor that the xdg_positioner will no longer be used.\n */\nstatic inline void\nxdg_positioner_destroy(struct xdg_positioner *xdg_positioner)\n{\n\twl_proxy_marshal((struct wl_proxy *) xdg_positioner,\n\t\t\t XDG_POSITIONER_DESTROY);\n\n\twl_proxy_destroy((struct wl_proxy *) xdg_positioner);\n}\n\n/**\n * @ingroup iface_xdg_positioner\n *\n * Set the size of the surface that is to be positioned with the positioner\n * object. The size is in surface-local coordinates and corresponds to the\n * window geometry. See xdg_surface.set_window_geometry.\n *\n * If a zero or negative size is set the invalid_input error is raised.\n */\nstatic inline void\nxdg_positioner_set_size(struct xdg_positioner *xdg_positioner, int32_t width, int32_t height)\n{\n\twl_proxy_marshal((struct wl_proxy *) xdg_positioner,\n\t\t\t XDG_POSITIONER_SET_SIZE, width, height);\n}\n\n/**\n * @ingroup iface_xdg_positioner\n *\n * Specify the anchor rectangle within the parent surface that the child\n * surface will be placed relative to. The rectangle is relative to the\n * window geometry as defined by xdg_surface.set_window_geometry of the\n * parent surface.\n *\n * When the xdg_positioner object is used to position a child surface, the\n * anchor rectangle may not extend outside the window geometry of the\n * positioned child's parent surface.\n *\n * If a negative size is set the invalid_input error is raised.\n */\nstatic inline void\nxdg_positioner_set_anchor_rect(struct xdg_positioner *xdg_positioner, int32_t x, int32_t y, int32_t width, int32_t height)\n{\n\twl_proxy_marshal((struct wl_proxy *) xdg_positioner,\n\t\t\t XDG_POSITIONER_SET_ANCHOR_RECT, x, y, width, height);\n}\n\n/**\n * @ingroup iface_xdg_positioner\n *\n * Defines the anchor point for the anchor rectangle. The specified anchor\n * is used derive an anchor point that the child surface will be\n * positioned relative to. If a corner anchor is set (e.g. 'top_left' or\n * 'bottom_right'), the anchor point will be at the specified corner;\n * otherwise, the derived anchor point will be centered on the specified\n * edge, or in the center of the anchor rectangle if no edge is specified.\n */\nstatic inline void\nxdg_positioner_set_anchor(struct xdg_positioner *xdg_positioner, uint32_t anchor)\n{\n\twl_proxy_marshal((struct wl_proxy *) xdg_positioner,\n\t\t\t XDG_POSITIONER_SET_ANCHOR, anchor);\n}\n\n/**\n * @ingroup iface_xdg_positioner\n *\n * Defines in what direction a surface should be positioned, relative to\n * the anchor point of the parent surface. If a corner gravity is\n * specified (e.g. 'bottom_right' or 'top_left'), then the child surface\n * will be placed towards the specified gravity; otherwise, the child\n * surface will be centered over the anchor point on any axis that had no\n * gravity specified.\n */\nstatic inline void\nxdg_positioner_set_gravity(struct xdg_positioner *xdg_positioner, uint32_t gravity)\n{\n\twl_proxy_marshal((struct wl_proxy *) xdg_positioner,\n\t\t\t XDG_POSITIONER_SET_GRAVITY, gravity);\n}\n\n/**\n * @ingroup iface_xdg_positioner\n *\n * Specify how the window should be positioned if the originally intended\n * position caused the surface to be constrained, meaning at least\n * partially outside positioning boundaries set by the compositor. The\n * adjustment is set by constructing a bitmask describing the adjustment to\n * be made when the surface is constrained on that axis.\n *\n * If no bit for one axis is set, the compositor will assume that the child\n * surface should not change its position on that axis when constrained.\n *\n * If more than one bit for one axis is set, the order of how adjustments\n * are applied is specified in the corresponding adjustment descriptions.\n *\n * The default adjustment is none.\n */\nstatic inline void\nxdg_positioner_set_constraint_adjustment(struct xdg_positioner *xdg_positioner, uint32_t constraint_adjustment)\n{\n\twl_proxy_marshal((struct wl_proxy *) xdg_positioner,\n\t\t\t XDG_POSITIONER_SET_CONSTRAINT_ADJUSTMENT, constraint_adjustment);\n}\n\n/**\n * @ingroup iface_xdg_positioner\n *\n * Specify the surface position offset relative to the position of the\n * anchor on the anchor rectangle and the anchor on the surface. For\n * example if the anchor of the anchor rectangle is at (x, y), the surface\n * has the gravity bottom|right, and the offset is (ox, oy), the calculated\n * surface position will be (x + ox, y + oy). The offset position of the\n * surface is the one used for constraint testing. See\n * set_constraint_adjustment.\n *\n * An example use case is placing a popup menu on top of a user interface\n * element, while aligning the user interface element of the parent surface\n * with some user interface element placed somewhere in the popup surface.\n */\nstatic inline void\nxdg_positioner_set_offset(struct xdg_positioner *xdg_positioner, int32_t x, int32_t y)\n{\n\twl_proxy_marshal((struct wl_proxy *) xdg_positioner,\n\t\t\t XDG_POSITIONER_SET_OFFSET, x, y);\n}\n\n#ifndef XDG_SURFACE_ERROR_ENUM\n#define XDG_SURFACE_ERROR_ENUM\nenum xdg_surface_error {\n\tXDG_SURFACE_ERROR_NOT_CONSTRUCTED = 1,\n\tXDG_SURFACE_ERROR_ALREADY_CONSTRUCTED = 2,\n\tXDG_SURFACE_ERROR_UNCONFIGURED_BUFFER = 3,\n};\n#endif /* XDG_SURFACE_ERROR_ENUM */\n\n/**\n * @ingroup iface_xdg_surface\n * @struct xdg_surface_listener\n */\nstruct xdg_surface_listener {\n\t/**\n\t * suggest a surface change\n\t *\n\t * The configure event marks the end of a configure sequence. A\n\t * configure sequence is a set of one or more events configuring\n\t * the state of the xdg_surface, including the final\n\t * xdg_surface.configure event.\n\t *\n\t * Where applicable, xdg_surface surface roles will during a\n\t * configure sequence extend this event as a latched state sent as\n\t * events before the xdg_surface.configure event. Such events\n\t * should be considered to make up a set of atomically applied\n\t * configuration states, where the xdg_surface.configure commits\n\t * the accumulated state.\n\t *\n\t * Clients should arrange their surface for the new states, and\n\t * then send an ack_configure request with the serial sent in this\n\t * configure event at some point before committing the new surface.\n\t *\n\t * If the client receives multiple configure events before it can\n\t * respond to one, it is free to discard all but the last event it\n\t * received.\n\t * @param serial serial of the configure event\n\t */\n\tvoid (*configure)(void *data,\n\t\t\t  struct xdg_surface *xdg_surface,\n\t\t\t  uint32_t serial);\n};\n\n/**\n * @ingroup iface_xdg_surface\n */\nstatic inline int\nxdg_surface_add_listener(struct xdg_surface *xdg_surface,\n\t\t\t const struct xdg_surface_listener *listener, void *data)\n{\n\treturn wl_proxy_add_listener((struct wl_proxy *) xdg_surface,\n\t\t\t\t     (void (**)(void)) listener, data);\n}\n\n#define XDG_SURFACE_DESTROY 0\n#define XDG_SURFACE_GET_TOPLEVEL 1\n#define XDG_SURFACE_GET_POPUP 2\n#define XDG_SURFACE_SET_WINDOW_GEOMETRY 3\n#define XDG_SURFACE_ACK_CONFIGURE 4\n\n/**\n * @ingroup iface_xdg_surface\n */\n#define XDG_SURFACE_CONFIGURE_SINCE_VERSION 1\n\n/**\n * @ingroup iface_xdg_surface\n */\n#define XDG_SURFACE_DESTROY_SINCE_VERSION 1\n/**\n * @ingroup iface_xdg_surface\n */\n#define XDG_SURFACE_GET_TOPLEVEL_SINCE_VERSION 1\n/**\n * @ingroup iface_xdg_surface\n */\n#define XDG_SURFACE_GET_POPUP_SINCE_VERSION 1\n/**\n * @ingroup iface_xdg_surface\n */\n#define XDG_SURFACE_SET_WINDOW_GEOMETRY_SINCE_VERSION 1\n/**\n * @ingroup iface_xdg_surface\n */\n#define XDG_SURFACE_ACK_CONFIGURE_SINCE_VERSION 1\n\n/** @ingroup iface_xdg_surface */\nstatic inline void\nxdg_surface_set_user_data(struct xdg_surface *xdg_surface, void *user_data)\n{\n\twl_proxy_set_user_data((struct wl_proxy *) xdg_surface, user_data);\n}\n\n/** @ingroup iface_xdg_surface */\nstatic inline void *\nxdg_surface_get_user_data(struct xdg_surface *xdg_surface)\n{\n\treturn wl_proxy_get_user_data((struct wl_proxy *) xdg_surface);\n}\n\nstatic inline uint32_t\nxdg_surface_get_version(struct xdg_surface *xdg_surface)\n{\n\treturn wl_proxy_get_version((struct wl_proxy *) xdg_surface);\n}\n\n/**\n * @ingroup iface_xdg_surface\n *\n * Destroy the xdg_surface object. An xdg_surface must only be destroyed\n * after its role object has been destroyed.\n */\nstatic inline void\nxdg_surface_destroy(struct xdg_surface *xdg_surface)\n{\n\twl_proxy_marshal((struct wl_proxy *) xdg_surface,\n\t\t\t XDG_SURFACE_DESTROY);\n\n\twl_proxy_destroy((struct wl_proxy *) xdg_surface);\n}\n\n/**\n * @ingroup iface_xdg_surface\n *\n * This creates an xdg_toplevel object for the given xdg_surface and gives\n * the associated wl_surface the xdg_toplevel role.\n *\n * See the documentation of xdg_toplevel for more details about what an\n * xdg_toplevel is and how it is used.\n */\nstatic inline struct xdg_toplevel *\nxdg_surface_get_toplevel(struct xdg_surface *xdg_surface)\n{\n\tstruct wl_proxy *id;\n\n\tid = wl_proxy_marshal_constructor((struct wl_proxy *) xdg_surface,\n\t\t\t XDG_SURFACE_GET_TOPLEVEL, &xdg_toplevel_interface, NULL);\n\n\treturn (struct xdg_toplevel *) id;\n}\n\n/**\n * @ingroup iface_xdg_surface\n *\n * This creates an xdg_popup object for the given xdg_surface and gives\n * the associated wl_surface the xdg_popup role.\n *\n * If null is passed as a parent, a parent surface must be specified using\n * some other protocol, before committing the initial state.\n *\n * See the documentation of xdg_popup for more details about what an\n * xdg_popup is and how it is used.\n */\nstatic inline struct xdg_popup *\nxdg_surface_get_popup(struct xdg_surface *xdg_surface, struct xdg_surface *parent, struct xdg_positioner *positioner)\n{\n\tstruct wl_proxy *id;\n\n\tid = wl_proxy_marshal_constructor((struct wl_proxy *) xdg_surface,\n\t\t\t XDG_SURFACE_GET_POPUP, &xdg_popup_interface, NULL, parent, positioner);\n\n\treturn (struct xdg_popup *) id;\n}\n\n/**\n * @ingroup iface_xdg_surface\n *\n * The window geometry of a surface is its \"visible bounds\" from the\n * user's perspective. Client-side decorations often have invisible\n * portions like drop-shadows which should be ignored for the\n * purposes of aligning, placing and constraining windows.\n *\n * The window geometry is double buffered, and will be applied at the\n * time wl_surface.commit of the corresponding wl_surface is called.\n *\n * When maintaining a position, the compositor should treat the (x, y)\n * coordinate of the window geometry as the top left corner of the window.\n * A client changing the (x, y) window geometry coordinate should in\n * general not alter the position of the window.\n *\n * Once the window geometry of the surface is set, it is not possible to\n * unset it, and it will remain the same until set_window_geometry is\n * called again, even if a new subsurface or buffer is attached.\n *\n * If never set, the value is the full bounds of the surface,\n * including any subsurfaces. This updates dynamically on every\n * commit. This unset is meant for extremely simple clients.\n *\n * The arguments are given in the surface-local coordinate space of\n * the wl_surface associated with this xdg_surface.\n *\n * The width and height must be greater than zero. Setting an invalid size\n * will raise an error. When applied, the effective window geometry will be\n * the set window geometry clamped to the bounding rectangle of the\n * combined geometry of the surface of the xdg_surface and the associated\n * subsurfaces.\n */\nstatic inline void\nxdg_surface_set_window_geometry(struct xdg_surface *xdg_surface, int32_t x, int32_t y, int32_t width, int32_t height)\n{\n\twl_proxy_marshal((struct wl_proxy *) xdg_surface,\n\t\t\t XDG_SURFACE_SET_WINDOW_GEOMETRY, x, y, width, height);\n}\n\n/**\n * @ingroup iface_xdg_surface\n *\n * When a configure event is received, if a client commits the\n * surface in response to the configure event, then the client\n * must make an ack_configure request sometime before the commit\n * request, passing along the serial of the configure event.\n *\n * For instance, for toplevel surfaces the compositor might use this\n * information to move a surface to the top left only when the client has\n * drawn itself for the maximized or fullscreen state.\n *\n * If the client receives multiple configure events before it\n * can respond to one, it only has to ack the last configure event.\n *\n * A client is not required to commit immediately after sending\n * an ack_configure request - it may even ack_configure several times\n * before its next surface commit.\n *\n * A client may send multiple ack_configure requests before committing, but\n * only the last request sent before a commit indicates which configure\n * event the client really is responding to.\n */\nstatic inline void\nxdg_surface_ack_configure(struct xdg_surface *xdg_surface, uint32_t serial)\n{\n\twl_proxy_marshal((struct wl_proxy *) xdg_surface,\n\t\t\t XDG_SURFACE_ACK_CONFIGURE, serial);\n}\n\n#ifndef XDG_TOPLEVEL_RESIZE_EDGE_ENUM\n#define XDG_TOPLEVEL_RESIZE_EDGE_ENUM\n/**\n * @ingroup iface_xdg_toplevel\n * edge values for resizing\n *\n * These values are used to indicate which edge of a surface\n * is being dragged in a resize operation.\n */\nenum xdg_toplevel_resize_edge {\n\tXDG_TOPLEVEL_RESIZE_EDGE_NONE = 0,\n\tXDG_TOPLEVEL_RESIZE_EDGE_TOP = 1,\n\tXDG_TOPLEVEL_RESIZE_EDGE_BOTTOM = 2,\n\tXDG_TOPLEVEL_RESIZE_EDGE_LEFT = 4,\n\tXDG_TOPLEVEL_RESIZE_EDGE_TOP_LEFT = 5,\n\tXDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_LEFT = 6,\n\tXDG_TOPLEVEL_RESIZE_EDGE_RIGHT = 8,\n\tXDG_TOPLEVEL_RESIZE_EDGE_TOP_RIGHT = 9,\n\tXDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_RIGHT = 10,\n};\n#endif /* XDG_TOPLEVEL_RESIZE_EDGE_ENUM */\n\n#ifndef XDG_TOPLEVEL_STATE_ENUM\n#define XDG_TOPLEVEL_STATE_ENUM\n/**\n * @ingroup iface_xdg_toplevel\n * the surface is tiled\n *\n * The window is currently in a tiled layout and the bottom edge is\n * considered to be adjacent to another part of the tiling grid.\n */\nenum xdg_toplevel_state {\n\t/**\n\t * the surface is maximized\n\t */\n\tXDG_TOPLEVEL_STATE_MAXIMIZED = 1,\n\t/**\n\t * the surface is fullscreen\n\t */\n\tXDG_TOPLEVEL_STATE_FULLSCREEN = 2,\n\t/**\n\t * the surface is being resized\n\t */\n\tXDG_TOPLEVEL_STATE_RESIZING = 3,\n\t/**\n\t * the surface is now activated\n\t */\n\tXDG_TOPLEVEL_STATE_ACTIVATED = 4,\n\t/**\n\t * @since 2\n\t */\n\tXDG_TOPLEVEL_STATE_TILED_LEFT = 5,\n\t/**\n\t * @since 2\n\t */\n\tXDG_TOPLEVEL_STATE_TILED_RIGHT = 6,\n\t/**\n\t * @since 2\n\t */\n\tXDG_TOPLEVEL_STATE_TILED_TOP = 7,\n\t/**\n\t * @since 2\n\t */\n\tXDG_TOPLEVEL_STATE_TILED_BOTTOM = 8,\n};\n/**\n * @ingroup iface_xdg_toplevel\n */\n#define XDG_TOPLEVEL_STATE_TILED_LEFT_SINCE_VERSION 2\n/**\n * @ingroup iface_xdg_toplevel\n */\n#define XDG_TOPLEVEL_STATE_TILED_RIGHT_SINCE_VERSION 2\n/**\n * @ingroup iface_xdg_toplevel\n */\n#define XDG_TOPLEVEL_STATE_TILED_TOP_SINCE_VERSION 2\n/**\n * @ingroup iface_xdg_toplevel\n */\n#define XDG_TOPLEVEL_STATE_TILED_BOTTOM_SINCE_VERSION 2\n#endif /* XDG_TOPLEVEL_STATE_ENUM */\n\n/**\n * @ingroup iface_xdg_toplevel\n * @struct xdg_toplevel_listener\n */\nstruct xdg_toplevel_listener {\n\t/**\n\t * suggest a surface change\n\t *\n\t * This configure event asks the client to resize its toplevel\n\t * surface or to change its state. The configured state should not\n\t * be applied immediately. See xdg_surface.configure for details.\n\t *\n\t * The width and height arguments specify a hint to the window\n\t * about how its surface should be resized in window geometry\n\t * coordinates. See set_window_geometry.\n\t *\n\t * If the width or height arguments are zero, it means the client\n\t * should decide its own window dimension. This may happen when the\n\t * compositor needs to configure the state of the surface but\n\t * doesn't have any information about any previous or expected\n\t * dimension.\n\t *\n\t * The states listed in the event specify how the width/height\n\t * arguments should be interpreted, and possibly how it should be\n\t * drawn.\n\t *\n\t * Clients must send an ack_configure in response to this event.\n\t * See xdg_surface.configure and xdg_surface.ack_configure for\n\t * details.\n\t */\n\tvoid (*configure)(void *data,\n\t\t\t  struct xdg_toplevel *xdg_toplevel,\n\t\t\t  int32_t width,\n\t\t\t  int32_t height,\n\t\t\t  struct wl_array *states);\n\t/**\n\t * surface wants to be closed\n\t *\n\t * The close event is sent by the compositor when the user wants\n\t * the surface to be closed. This should be equivalent to the user\n\t * clicking the close button in client-side decorations, if your\n\t * application has any.\n\t *\n\t * This is only a request that the user intends to close the\n\t * window. The client may choose to ignore this request, or show a\n\t * dialog to ask the user to save their data, etc.\n\t */\n\tvoid (*close)(void *data,\n\t\t      struct xdg_toplevel *xdg_toplevel);\n};\n\n/**\n * @ingroup iface_xdg_toplevel\n */\nstatic inline int\nxdg_toplevel_add_listener(struct xdg_toplevel *xdg_toplevel,\n\t\t\t  const struct xdg_toplevel_listener *listener, void *data)\n{\n\treturn wl_proxy_add_listener((struct wl_proxy *) xdg_toplevel,\n\t\t\t\t     (void (**)(void)) listener, data);\n}\n\n#define XDG_TOPLEVEL_DESTROY 0\n#define XDG_TOPLEVEL_SET_PARENT 1\n#define XDG_TOPLEVEL_SET_TITLE 2\n#define XDG_TOPLEVEL_SET_APP_ID 3\n#define XDG_TOPLEVEL_SHOW_WINDOW_MENU 4\n#define XDG_TOPLEVEL_MOVE 5\n#define XDG_TOPLEVEL_RESIZE 6\n#define XDG_TOPLEVEL_SET_MAX_SIZE 7\n#define XDG_TOPLEVEL_SET_MIN_SIZE 8\n#define XDG_TOPLEVEL_SET_MAXIMIZED 9\n#define XDG_TOPLEVEL_UNSET_MAXIMIZED 10\n#define XDG_TOPLEVEL_SET_FULLSCREEN 11\n#define XDG_TOPLEVEL_UNSET_FULLSCREEN 12\n#define XDG_TOPLEVEL_SET_MINIMIZED 13\n\n/**\n * @ingroup iface_xdg_toplevel\n */\n#define XDG_TOPLEVEL_CONFIGURE_SINCE_VERSION 1\n/**\n * @ingroup iface_xdg_toplevel\n */\n#define XDG_TOPLEVEL_CLOSE_SINCE_VERSION 1\n\n/**\n * @ingroup iface_xdg_toplevel\n */\n#define XDG_TOPLEVEL_DESTROY_SINCE_VERSION 1\n/**\n * @ingroup iface_xdg_toplevel\n */\n#define XDG_TOPLEVEL_SET_PARENT_SINCE_VERSION 1\n/**\n * @ingroup iface_xdg_toplevel\n */\n#define XDG_TOPLEVEL_SET_TITLE_SINCE_VERSION 1\n/**\n * @ingroup iface_xdg_toplevel\n */\n#define XDG_TOPLEVEL_SET_APP_ID_SINCE_VERSION 1\n/**\n * @ingroup iface_xdg_toplevel\n */\n#define XDG_TOPLEVEL_SHOW_WINDOW_MENU_SINCE_VERSION 1\n/**\n * @ingroup iface_xdg_toplevel\n */\n#define XDG_TOPLEVEL_MOVE_SINCE_VERSION 1\n/**\n * @ingroup iface_xdg_toplevel\n */\n#define XDG_TOPLEVEL_RESIZE_SINCE_VERSION 1\n/**\n * @ingroup iface_xdg_toplevel\n */\n#define XDG_TOPLEVEL_SET_MAX_SIZE_SINCE_VERSION 1\n/**\n * @ingroup iface_xdg_toplevel\n */\n#define XDG_TOPLEVEL_SET_MIN_SIZE_SINCE_VERSION 1\n/**\n * @ingroup iface_xdg_toplevel\n */\n#define XDG_TOPLEVEL_SET_MAXIMIZED_SINCE_VERSION 1\n/**\n * @ingroup iface_xdg_toplevel\n */\n#define XDG_TOPLEVEL_UNSET_MAXIMIZED_SINCE_VERSION 1\n/**\n * @ingroup iface_xdg_toplevel\n */\n#define XDG_TOPLEVEL_SET_FULLSCREEN_SINCE_VERSION 1\n/**\n * @ingroup iface_xdg_toplevel\n */\n#define XDG_TOPLEVEL_UNSET_FULLSCREEN_SINCE_VERSION 1\n/**\n * @ingroup iface_xdg_toplevel\n */\n#define XDG_TOPLEVEL_SET_MINIMIZED_SINCE_VERSION 1\n\n/** @ingroup iface_xdg_toplevel */\nstatic inline void\nxdg_toplevel_set_user_data(struct xdg_toplevel *xdg_toplevel, void *user_data)\n{\n\twl_proxy_set_user_data((struct wl_proxy *) xdg_toplevel, user_data);\n}\n\n/** @ingroup iface_xdg_toplevel */\nstatic inline void *\nxdg_toplevel_get_user_data(struct xdg_toplevel *xdg_toplevel)\n{\n\treturn wl_proxy_get_user_data((struct wl_proxy *) xdg_toplevel);\n}\n\nstatic inline uint32_t\nxdg_toplevel_get_version(struct xdg_toplevel *xdg_toplevel)\n{\n\treturn wl_proxy_get_version((struct wl_proxy *) xdg_toplevel);\n}\n\n/**\n * @ingroup iface_xdg_toplevel\n *\n * This request destroys the role surface and unmaps the surface;\n * see \"Unmapping\" behavior in interface section for details.\n */\nstatic inline void\nxdg_toplevel_destroy(struct xdg_toplevel *xdg_toplevel)\n{\n\twl_proxy_marshal((struct wl_proxy *) xdg_toplevel,\n\t\t\t XDG_TOPLEVEL_DESTROY);\n\n\twl_proxy_destroy((struct wl_proxy *) xdg_toplevel);\n}\n\n/**\n * @ingroup iface_xdg_toplevel\n *\n * Set the \"parent\" of this surface. This surface should be stacked\n * above the parent surface and all other ancestor surfaces.\n *\n * Parent windows should be set on dialogs, toolboxes, or other\n * \"auxiliary\" surfaces, so that the parent is raised when the dialog\n * is raised.\n *\n * Setting a null parent for a child window removes any parent-child\n * relationship for the child. Setting a null parent for a window which\n * currently has no parent is a no-op.\n *\n * If the parent is unmapped then its children are managed as\n * though the parent of the now-unmapped parent has become the\n * parent of this surface. If no parent exists for the now-unmapped\n * parent then the children are managed as though they have no\n * parent surface.\n */\nstatic inline void\nxdg_toplevel_set_parent(struct xdg_toplevel *xdg_toplevel, struct xdg_toplevel *parent)\n{\n\twl_proxy_marshal((struct wl_proxy *) xdg_toplevel,\n\t\t\t XDG_TOPLEVEL_SET_PARENT, parent);\n}\n\n/**\n * @ingroup iface_xdg_toplevel\n *\n * Set a short title for the surface.\n *\n * This string may be used to identify the surface in a task bar,\n * window list, or other user interface elements provided by the\n * compositor.\n *\n * The string must be encoded in UTF-8.\n */\nstatic inline void\nxdg_toplevel_set_title(struct xdg_toplevel *xdg_toplevel, const char *title)\n{\n\twl_proxy_marshal((struct wl_proxy *) xdg_toplevel,\n\t\t\t XDG_TOPLEVEL_SET_TITLE, title);\n}\n\n/**\n * @ingroup iface_xdg_toplevel\n *\n * Set an application identifier for the surface.\n *\n * The app ID identifies the general class of applications to which\n * the surface belongs. The compositor can use this to group multiple\n * surfaces together, or to determine how to launch a new application.\n *\n * For D-Bus activatable applications, the app ID is used as the D-Bus\n * service name.\n *\n * The compositor shell will try to group application surfaces together\n * by their app ID. As a best practice, it is suggested to select app\n * ID's that match the basename of the application's .desktop file.\n * For example, \"org.freedesktop.FooViewer\" where the .desktop file is\n * \"org.freedesktop.FooViewer.desktop\".\n *\n * See the desktop-entry specification [0] for more details on\n * application identifiers and how they relate to well-known D-Bus\n * names and .desktop files.\n *\n * [0] http://standards.freedesktop.org/desktop-entry-spec/\n */\nstatic inline void\nxdg_toplevel_set_app_id(struct xdg_toplevel *xdg_toplevel, const char *app_id)\n{\n\twl_proxy_marshal((struct wl_proxy *) xdg_toplevel,\n\t\t\t XDG_TOPLEVEL_SET_APP_ID, app_id);\n}\n\n/**\n * @ingroup iface_xdg_toplevel\n *\n * Clients implementing client-side decorations might want to show\n * a context menu when right-clicking on the decorations, giving the\n * user a menu that they can use to maximize or minimize the window.\n *\n * This request asks the compositor to pop up such a window menu at\n * the given position, relative to the local surface coordinates of\n * the parent surface. There are no guarantees as to what menu items\n * the window menu contains.\n *\n * This request must be used in response to some sort of user action\n * like a button press, key press, or touch down event.\n */\nstatic inline void\nxdg_toplevel_show_window_menu(struct xdg_toplevel *xdg_toplevel, struct wl_seat *seat, uint32_t serial, int32_t x, int32_t y)\n{\n\twl_proxy_marshal((struct wl_proxy *) xdg_toplevel,\n\t\t\t XDG_TOPLEVEL_SHOW_WINDOW_MENU, seat, serial, x, y);\n}\n\n/**\n * @ingroup iface_xdg_toplevel\n *\n * Start an interactive, user-driven move of the surface.\n *\n * This request must be used in response to some sort of user action\n * like a button press, key press, or touch down event. The passed\n * serial is used to determine the type of interactive move (touch,\n * pointer, etc).\n *\n * The server may ignore move requests depending on the state of\n * the surface (e.g. fullscreen or maximized), or if the passed serial\n * is no longer valid.\n *\n * If triggered, the surface will lose the focus of the device\n * (wl_pointer, wl_touch, etc) used for the move. It is up to the\n * compositor to visually indicate that the move is taking place, such as\n * updating a pointer cursor, during the move. There is no guarantee\n * that the device focus will return when the move is completed.\n */\nstatic inline void\nxdg_toplevel_move(struct xdg_toplevel *xdg_toplevel, struct wl_seat *seat, uint32_t serial)\n{\n\twl_proxy_marshal((struct wl_proxy *) xdg_toplevel,\n\t\t\t XDG_TOPLEVEL_MOVE, seat, serial);\n}\n\n/**\n * @ingroup iface_xdg_toplevel\n *\n * Start a user-driven, interactive resize of the surface.\n *\n * This request must be used in response to some sort of user action\n * like a button press, key press, or touch down event. The passed\n * serial is used to determine the type of interactive resize (touch,\n * pointer, etc).\n *\n * The server may ignore resize requests depending on the state of\n * the surface (e.g. fullscreen or maximized).\n *\n * If triggered, the client will receive configure events with the\n * \"resize\" state enum value and the expected sizes. See the \"resize\"\n * enum value for more details about what is required. The client\n * must also acknowledge configure events using \"ack_configure\". After\n * the resize is completed, the client will receive another \"configure\"\n * event without the resize state.\n *\n * If triggered, the surface also will lose the focus of the device\n * (wl_pointer, wl_touch, etc) used for the resize. It is up to the\n * compositor to visually indicate that the resize is taking place,\n * such as updating a pointer cursor, during the resize. There is no\n * guarantee that the device focus will return when the resize is\n * completed.\n *\n * The edges parameter specifies how the surface should be resized,\n * and is one of the values of the resize_edge enum. The compositor\n * may use this information to update the surface position for\n * example when dragging the top left corner. The compositor may also\n * use this information to adapt its behavior, e.g. choose an\n * appropriate cursor image.\n */\nstatic inline void\nxdg_toplevel_resize(struct xdg_toplevel *xdg_toplevel, struct wl_seat *seat, uint32_t serial, uint32_t edges)\n{\n\twl_proxy_marshal((struct wl_proxy *) xdg_toplevel,\n\t\t\t XDG_TOPLEVEL_RESIZE, seat, serial, edges);\n}\n\n/**\n * @ingroup iface_xdg_toplevel\n *\n * Set a maximum size for the window.\n *\n * The client can specify a maximum size so that the compositor does\n * not try to configure the window beyond this size.\n *\n * The width and height arguments are in window geometry coordinates.\n * See xdg_surface.set_window_geometry.\n *\n * Values set in this way are double-buffered. They will get applied\n * on the next commit.\n *\n * The compositor can use this information to allow or disallow\n * different states like maximize or fullscreen and draw accurate\n * animations.\n *\n * Similarly, a tiling window manager may use this information to\n * place and resize client windows in a more effective way.\n *\n * The client should not rely on the compositor to obey the maximum\n * size. The compositor may decide to ignore the values set by the\n * client and request a larger size.\n *\n * If never set, or a value of zero in the request, means that the\n * client has no expected maximum size in the given dimension.\n * As a result, a client wishing to reset the maximum size\n * to an unspecified state can use zero for width and height in the\n * request.\n *\n * Requesting a maximum size to be smaller than the minimum size of\n * a surface is illegal and will result in a protocol error.\n *\n * The width and height must be greater than or equal to zero. Using\n * strictly negative values for width and height will result in a\n * protocol error.\n */\nstatic inline void\nxdg_toplevel_set_max_size(struct xdg_toplevel *xdg_toplevel, int32_t width, int32_t height)\n{\n\twl_proxy_marshal((struct wl_proxy *) xdg_toplevel,\n\t\t\t XDG_TOPLEVEL_SET_MAX_SIZE, width, height);\n}\n\n/**\n * @ingroup iface_xdg_toplevel\n *\n * Set a minimum size for the window.\n *\n * The client can specify a minimum size so that the compositor does\n * not try to configure the window below this size.\n *\n * The width and height arguments are in window geometry coordinates.\n * See xdg_surface.set_window_geometry.\n *\n * Values set in this way are double-buffered. They will get applied\n * on the next commit.\n *\n * The compositor can use this information to allow or disallow\n * different states like maximize or fullscreen and draw accurate\n * animations.\n *\n * Similarly, a tiling window manager may use this information to\n * place and resize client windows in a more effective way.\n *\n * The client should not rely on the compositor to obey the minimum\n * size. The compositor may decide to ignore the values set by the\n * client and request a smaller size.\n *\n * If never set, or a value of zero in the request, means that the\n * client has no expected minimum size in the given dimension.\n * As a result, a client wishing to reset the minimum size\n * to an unspecified state can use zero for width and height in the\n * request.\n *\n * Requesting a minimum size to be larger than the maximum size of\n * a surface is illegal and will result in a protocol error.\n *\n * The width and height must be greater than or equal to zero. Using\n * strictly negative values for width and height will result in a\n * protocol error.\n */\nstatic inline void\nxdg_toplevel_set_min_size(struct xdg_toplevel *xdg_toplevel, int32_t width, int32_t height)\n{\n\twl_proxy_marshal((struct wl_proxy *) xdg_toplevel,\n\t\t\t XDG_TOPLEVEL_SET_MIN_SIZE, width, height);\n}\n\n/**\n * @ingroup iface_xdg_toplevel\n *\n * Maximize the surface.\n *\n * After requesting that the surface should be maximized, the compositor\n * will respond by emitting a configure event. Whether this configure\n * actually sets the window maximized is subject to compositor policies.\n * The client must then update its content, drawing in the configured\n * state. The client must also acknowledge the configure when committing\n * the new content (see ack_configure).\n *\n * It is up to the compositor to decide how and where to maximize the\n * surface, for example which output and what region of the screen should\n * be used.\n *\n * If the surface was already maximized, the compositor will still emit\n * a configure event with the \"maximized\" state.\n *\n * If the surface is in a fullscreen state, this request has no direct\n * effect. It may alter the state the surface is returned to when\n * unmaximized unless overridden by the compositor.\n */\nstatic inline void\nxdg_toplevel_set_maximized(struct xdg_toplevel *xdg_toplevel)\n{\n\twl_proxy_marshal((struct wl_proxy *) xdg_toplevel,\n\t\t\t XDG_TOPLEVEL_SET_MAXIMIZED);\n}\n\n/**\n * @ingroup iface_xdg_toplevel\n *\n * Unmaximize the surface.\n *\n * After requesting that the surface should be unmaximized, the compositor\n * will respond by emitting a configure event. Whether this actually\n * un-maximizes the window is subject to compositor policies.\n * If available and applicable, the compositor will include the window\n * geometry dimensions the window had prior to being maximized in the\n * configure event. The client must then update its content, drawing it in\n * the configured state. The client must also acknowledge the configure\n * when committing the new content (see ack_configure).\n *\n * It is up to the compositor to position the surface after it was\n * unmaximized; usually the position the surface had before maximizing, if\n * applicable.\n *\n * If the surface was already not maximized, the compositor will still\n * emit a configure event without the \"maximized\" state.\n *\n * If the surface is in a fullscreen state, this request has no direct\n * effect. It may alter the state the surface is returned to when\n * unmaximized unless overridden by the compositor.\n */\nstatic inline void\nxdg_toplevel_unset_maximized(struct xdg_toplevel *xdg_toplevel)\n{\n\twl_proxy_marshal((struct wl_proxy *) xdg_toplevel,\n\t\t\t XDG_TOPLEVEL_UNSET_MAXIMIZED);\n}\n\n/**\n * @ingroup iface_xdg_toplevel\n *\n * Make the surface fullscreen.\n *\n * After requesting that the surface should be fullscreened, the\n * compositor will respond by emitting a configure event. Whether the\n * client is actually put into a fullscreen state is subject to compositor\n * policies. The client must also acknowledge the configure when\n * committing the new content (see ack_configure).\n *\n * The output passed by the request indicates the client's preference as\n * to which display it should be set fullscreen on. If this value is NULL,\n * it's up to the compositor to choose which display will be used to map\n * this surface.\n *\n * If the surface doesn't cover the whole output, the compositor will\n * position the surface in the center of the output and compensate with\n * with border fill covering the rest of the output. The content of the\n * border fill is undefined, but should be assumed to be in some way that\n * attempts to blend into the surrounding area (e.g. solid black).\n *\n * If the fullscreened surface is not opaque, the compositor must make\n * sure that other screen content not part of the same surface tree (made\n * up of subsurfaces, popups or similarly coupled surfaces) are not\n * visible below the fullscreened surface.\n */\nstatic inline void\nxdg_toplevel_set_fullscreen(struct xdg_toplevel *xdg_toplevel, struct wl_output *output)\n{\n\twl_proxy_marshal((struct wl_proxy *) xdg_toplevel,\n\t\t\t XDG_TOPLEVEL_SET_FULLSCREEN, output);\n}\n\n/**\n * @ingroup iface_xdg_toplevel\n *\n * Make the surface no longer fullscreen.\n *\n * After requesting that the surface should be unfullscreened, the\n * compositor will respond by emitting a configure event.\n * Whether this actually removes the fullscreen state of the client is\n * subject to compositor policies.\n *\n * Making a surface unfullscreen sets states for the surface based on the following:\n * * the state(s) it may have had before becoming fullscreen\n * * any state(s) decided by the compositor\n * * any state(s) requested by the client while the surface was fullscreen\n *\n * The compositor may include the previous window geometry dimensions in\n * the configure event, if applicable.\n *\n * The client must also acknowledge the configure when committing the new\n * content (see ack_configure).\n */\nstatic inline void\nxdg_toplevel_unset_fullscreen(struct xdg_toplevel *xdg_toplevel)\n{\n\twl_proxy_marshal((struct wl_proxy *) xdg_toplevel,\n\t\t\t XDG_TOPLEVEL_UNSET_FULLSCREEN);\n}\n\n/**\n * @ingroup iface_xdg_toplevel\n *\n * Request that the compositor minimize your surface. There is no\n * way to know if the surface is currently minimized, nor is there\n * any way to unset minimization on this surface.\n *\n * If you are looking to throttle redrawing when minimized, please\n * instead use the wl_surface.frame event for this, as this will\n * also work with live previews on windows in Alt-Tab, Expose or\n * similar compositor features.\n */\nstatic inline void\nxdg_toplevel_set_minimized(struct xdg_toplevel *xdg_toplevel)\n{\n\twl_proxy_marshal((struct wl_proxy *) xdg_toplevel,\n\t\t\t XDG_TOPLEVEL_SET_MINIMIZED);\n}\n\n#ifndef XDG_POPUP_ERROR_ENUM\n#define XDG_POPUP_ERROR_ENUM\nenum xdg_popup_error {\n\t/**\n\t * tried to grab after being mapped\n\t */\n\tXDG_POPUP_ERROR_INVALID_GRAB = 0,\n};\n#endif /* XDG_POPUP_ERROR_ENUM */\n\n/**\n * @ingroup iface_xdg_popup\n * @struct xdg_popup_listener\n */\nstruct xdg_popup_listener {\n\t/**\n\t * configure the popup surface\n\t *\n\t * This event asks the popup surface to configure itself given\n\t * the configuration. The configured state should not be applied\n\t * immediately. See xdg_surface.configure for details.\n\t *\n\t * The x and y arguments represent the position the popup was\n\t * placed at given the xdg_positioner rule, relative to the upper\n\t * left corner of the window geometry of the parent surface.\n\t * @param x x position relative to parent surface window geometry\n\t * @param y y position relative to parent surface window geometry\n\t * @param width window geometry width\n\t * @param height window geometry height\n\t */\n\tvoid (*configure)(void *data,\n\t\t\t  struct xdg_popup *xdg_popup,\n\t\t\t  int32_t x,\n\t\t\t  int32_t y,\n\t\t\t  int32_t width,\n\t\t\t  int32_t height);\n\t/**\n\t * popup interaction is done\n\t *\n\t * The popup_done event is sent out when a popup is dismissed by\n\t * the compositor. The client should destroy the xdg_popup object\n\t * at this point.\n\t */\n\tvoid (*popup_done)(void *data,\n\t\t\t   struct xdg_popup *xdg_popup);\n};\n\n/**\n * @ingroup iface_xdg_popup\n */\nstatic inline int\nxdg_popup_add_listener(struct xdg_popup *xdg_popup,\n\t\t       const struct xdg_popup_listener *listener, void *data)\n{\n\treturn wl_proxy_add_listener((struct wl_proxy *) xdg_popup,\n\t\t\t\t     (void (**)(void)) listener, data);\n}\n\n#define XDG_POPUP_DESTROY 0\n#define XDG_POPUP_GRAB 1\n\n/**\n * @ingroup iface_xdg_popup\n */\n#define XDG_POPUP_CONFIGURE_SINCE_VERSION 1\n/**\n * @ingroup iface_xdg_popup\n */\n#define XDG_POPUP_POPUP_DONE_SINCE_VERSION 1\n\n/**\n * @ingroup iface_xdg_popup\n */\n#define XDG_POPUP_DESTROY_SINCE_VERSION 1\n/**\n * @ingroup iface_xdg_popup\n */\n#define XDG_POPUP_GRAB_SINCE_VERSION 1\n\n/** @ingroup iface_xdg_popup */\nstatic inline void\nxdg_popup_set_user_data(struct xdg_popup *xdg_popup, void *user_data)\n{\n\twl_proxy_set_user_data((struct wl_proxy *) xdg_popup, user_data);\n}\n\n/** @ingroup iface_xdg_popup */\nstatic inline void *\nxdg_popup_get_user_data(struct xdg_popup *xdg_popup)\n{\n\treturn wl_proxy_get_user_data((struct wl_proxy *) xdg_popup);\n}\n\nstatic inline uint32_t\nxdg_popup_get_version(struct xdg_popup *xdg_popup)\n{\n\treturn wl_proxy_get_version((struct wl_proxy *) xdg_popup);\n}\n\n/**\n * @ingroup iface_xdg_popup\n *\n * This destroys the popup. Explicitly destroying the xdg_popup\n * object will also dismiss the popup, and unmap the surface.\n *\n * If this xdg_popup is not the \"topmost\" popup, a protocol error\n * will be sent.\n */\nstatic inline void\nxdg_popup_destroy(struct xdg_popup *xdg_popup)\n{\n\twl_proxy_marshal((struct wl_proxy *) xdg_popup,\n\t\t\t XDG_POPUP_DESTROY);\n\n\twl_proxy_destroy((struct wl_proxy *) xdg_popup);\n}\n\n/**\n * @ingroup iface_xdg_popup\n *\n * This request makes the created popup take an explicit grab. An explicit\n * grab will be dismissed when the user dismisses the popup, or when the\n * client destroys the xdg_popup. This can be done by the user clicking\n * outside the surface, using the keyboard, or even locking the screen\n * through closing the lid or a timeout.\n *\n * If the compositor denies the grab, the popup will be immediately\n * dismissed.\n *\n * This request must be used in response to some sort of user action like a\n * button press, key press, or touch down event. The serial number of the\n * event should be passed as 'serial'.\n *\n * The parent of a grabbing popup must either be an xdg_toplevel surface or\n * another xdg_popup with an explicit grab. If the parent is another\n * xdg_popup it means that the popups are nested, with this popup now being\n * the topmost popup.\n *\n * Nested popups must be destroyed in the reverse order they were created\n * in, e.g. the only popup you are allowed to destroy at all times is the\n * topmost one.\n *\n * When compositors choose to dismiss a popup, they may dismiss every\n * nested grabbing popup as well. When a compositor dismisses popups, it\n * will follow the same dismissing order as required from the client.\n *\n * The parent of a grabbing popup must either be another xdg_popup with an\n * active explicit grab, or an xdg_popup or xdg_toplevel, if there are no\n * explicit grabs already taken.\n *\n * If the topmost grabbing popup is destroyed, the grab will be returned to\n * the parent of the popup, if that parent previously had an explicit grab.\n *\n * If the parent is a grabbing popup which has already been dismissed, this\n * popup will be immediately dismissed. If the parent is a popup that did\n * not take an explicit grab, an error will be raised.\n *\n * During a popup grab, the client owning the grab will receive pointer\n * and touch events for all their surfaces as normal (similar to an\n * \"owner-events\" grab in X11 parlance), while the top most grabbing popup\n * will always have keyboard focus.\n */\nstatic inline void\nxdg_popup_grab(struct xdg_popup *xdg_popup, struct wl_seat *seat, uint32_t serial)\n{\n\twl_proxy_marshal((struct wl_proxy *) xdg_popup,\n\t\t\t XDG_POPUP_GRAB, seat, serial);\n}\n\n#ifdef  __cplusplus\n}\n#endif\n\n#endif\n"
  },
  {
    "path": "src/Wsi.h",
    "content": "#ifndef HELLO_TRIANGLE_WSI_PLATFORM_H\r\n#define HELLO_TRIANGLE_WSI_PLATFORM_H\r\n\r\n#if  !defined(USE_PLATFORM_GLFW) \\\r\n  && !defined(VK_USE_PLATFORM_ANDROID_KHR) \\\r\n  && !defined(VK_USE_PLATFORM_WAYLAND_KHR) \\\r\n  && !defined(VK_USE_PLATFORM_WIN32_KHR) \\\r\n  && !defined(VK_USE_PLATFORM_XCB_KHR) \\\r\n  && !defined(VK_USE_PLATFORM_XLIB_KHR) \\\r\n  && !defined(VK_USE_PLATFORM_IOS_MVK) \\\r\n  && !defined(VK_USE_PLATFORM_MACOS_MVK) \\\r\n  && !defined(VK_USE_PLATFORM_VI_NN)\r\n\t#error \"Exactly one Vulkan WSI platform must be defined.\"\r\n#endif\r\n\r\n#if defined(USE_PLATFORM_GLFW)\r\n\t#include \"WSI/Glfw.h\"\r\n#elif defined(VK_USE_PLATFORM_WIN32_KHR)\r\n\t#include \"WSI/Win32.h\"\r\n#elif defined(VK_USE_PLATFORM_XLIB_KHR)\r\n\t#include \"WSI/Xlib.h\"\r\n#elif defined(VK_USE_PLATFORM_XCB_KHR)\r\n\t#include \"WSI/Xcb.h\"\r\n#elif defined(VK_USE_PLATFORM_WAYLAND_KHR)\r\n\t#include \"WSI/Wayland.h\"\r\n#else\r\n\t#error \"Unsupported Vulkan WSI platform, or none selected.\"\r\n#endif\r\n\r\n#ifndef VK_USE_PLATFORM_WAYLAND_KHR\r\n// dummy impl for platforms that do not need these functions\r\nuint32_t getWindowWidth( PlatformWindow ){ return 0; }\r\nuint32_t getWindowHeight( PlatformWindow ){ return 0; }\r\n#endif\r\n\r\n#endif //HELLO_TRIANGLE_WSI_PLATFORM_H"
  },
  {
    "path": "src/shaders/hello_triangle.frag",
    "content": "#version 450\r\n\r\nlayout (location = 0) smooth in vec3 inColor;\r\n\r\nlayout (location = 0) out vec4 outFragColor;\r\n\r\nvoid main(){\r\n\toutFragColor = vec4( inColor, 1.0 );\r\n}"
  },
  {
    "path": "src/shaders/hello_triangle.vert",
    "content": "#version 450\r\n\r\nlayout (location = 0) in vec2 inPos;\r\nlayout (location = 1) in vec3 inColor;\r\n\r\nlayout (location = 0) smooth out vec3 outColor;\r\n\r\nvoid main(){\r\n\toutColor = inColor;\r\n\tgl_Position = vec4( inPos.xy, 0.0, 1.0 );\r\n}\r\n"
  }
]