Cleanup repo
This commit is contained in:
commit
4755371ffa
18 files changed
+20826
No files matched your search
@@ -0,0 +1,32 @@
|
|||||||
|
BasedOnStyle: Google
|
||||||
|
IndentWidth: 4
|
||||||
|
|
||||||
|
# Add missing namespace comment on the closing bracket
|
||||||
|
FixNamespaceComments: true
|
||||||
|
|
||||||
|
# Do not indent everything in namespace
|
||||||
|
NamespaceIndentation: None
|
||||||
|
|
||||||
|
# Disable single line functions
|
||||||
|
AllowShortFunctionsOnASingleLine: None
|
||||||
|
|
||||||
|
# Braces configuration
|
||||||
|
BreakBeforeBraces: Custom
|
||||||
|
BraceWrapping:
|
||||||
|
AfterCaseLabel: true
|
||||||
|
AfterClass: false
|
||||||
|
AfterControlStatement: Never
|
||||||
|
AfterEnum: true
|
||||||
|
AfterFunction: true
|
||||||
|
AfterNamespace: true
|
||||||
|
AfterStruct: true
|
||||||
|
AfterUnion: true
|
||||||
|
AfterExternBlock: true
|
||||||
|
BeforeCatch: false
|
||||||
|
BeforeElse: false
|
||||||
|
|
||||||
|
ColumnLimit: 120
|
||||||
|
|
||||||
|
# Pointer star next to type, not variable name
|
||||||
|
DerivePointerAlignment: false
|
||||||
|
PointerAlignment: Left
|
||||||
+39
@@ -0,0 +1,39 @@
|
|||||||
|
# Prerequisites
|
||||||
|
*.d
|
||||||
|
|
||||||
|
# Compiled Object files
|
||||||
|
*.slo
|
||||||
|
*.lo
|
||||||
|
*.o
|
||||||
|
*.obj
|
||||||
|
|
||||||
|
# Precompiled Headers
|
||||||
|
*.gch
|
||||||
|
*.pch
|
||||||
|
|
||||||
|
# Compiled Dynamic libraries
|
||||||
|
*.so
|
||||||
|
*.dylib
|
||||||
|
*.dll
|
||||||
|
|
||||||
|
# Fortran module files
|
||||||
|
*.mod
|
||||||
|
*.smod
|
||||||
|
|
||||||
|
# Compiled Static libraries
|
||||||
|
*.lai
|
||||||
|
*.la
|
||||||
|
*.a
|
||||||
|
*.lib
|
||||||
|
|
||||||
|
# Executables
|
||||||
|
*.exe
|
||||||
|
*.out
|
||||||
|
*.app
|
||||||
|
|
||||||
|
# Build and bin folder contents
|
||||||
|
build/*
|
||||||
|
bin/*
|
||||||
|
|
||||||
|
# VSCode configurations
|
||||||
|
.vscode/
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.10)
|
||||||
|
|
||||||
|
# set the project name
|
||||||
|
project(RedScarfEngine VERSION 0.1.0)
|
||||||
|
|
||||||
|
# specify the C++ standard
|
||||||
|
set(CMAKE_C++_STANDARD 14)
|
||||||
|
set(CMAKE_C_STANDARD 11)
|
||||||
|
set(CMAKE_C_STANDARD_REQUIRED True)
|
||||||
|
|
||||||
|
if (MSVC)
|
||||||
|
# warning level 4 and all warnings as errors
|
||||||
|
add_compile_options(/W4 /WX)
|
||||||
|
else()
|
||||||
|
# lots of warnings and all warnings as errors
|
||||||
|
add_compile_options(-Wall -Wextra -pedantic -Werror)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
add_subdirectory(Graphics)
|
||||||
|
add_subdirectory(RedScarfEngine)
|
||||||
|
|
||||||
|
install(TARGETS RedScarfEngine GraphicsEngine
|
||||||
|
DESTINATION ${PROJECT_SOURCE_DIR}/bin)
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.10)
|
||||||
|
|
||||||
|
project(GraphicsEngine)
|
||||||
|
|
||||||
|
add_library(${PROJECT_NAME} SHARED
|
||||||
|
src/window.c
|
||||||
|
src/vmaInit.cpp
|
||||||
|
src/vulkanBase.c)
|
||||||
|
|
||||||
|
target_include_directories(${PROJECT_NAME} PUBLIC
|
||||||
|
${PROJECT_SOURCE_DIR}/include
|
||||||
|
${PROJECT_SOURCE_DIR}/locales
|
||||||
|
${CMAKE_SOURCE_DIR}/third_party/vma/include
|
||||||
|
${CMAKE_SOURCE_DIR}/Utilities/include)
|
||||||
|
|
||||||
|
target_link_libraries(${PROJECT_NAME}
|
||||||
|
vulkan
|
||||||
|
glfw)
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
/**
|
||||||
|
* @file vulkanBase.h
|
||||||
|
* @author Piotr Krygier (everyonecancode@gmail.com)
|
||||||
|
* @brief Vulkan wrapper functions used by other parts of Graphics component
|
||||||
|
* @version 0.1
|
||||||
|
* @date 2022-05-13
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2022
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef VULKAN_BASE_H
|
||||||
|
#define VULKAN_BASE_H
|
||||||
|
|
||||||
|
int initVulkan();
|
||||||
|
void deinitVulkan();
|
||||||
|
|
||||||
|
#endif /* VULKAN_BASE_H */
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
/**
|
||||||
|
* @file window.h
|
||||||
|
* @author Piotr Krygier (everyonencancode@gmail.com)
|
||||||
|
* @brief Window control system
|
||||||
|
* @version 0.1
|
||||||
|
* @date 2022-02-15
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2022
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef WINDOW_HANDLER_H
|
||||||
|
#define WINDOW_HANDLER_H
|
||||||
|
|
||||||
|
/* Vulkan header MUST be included before glfw */
|
||||||
|
#include <vulkan/vulkan.h>
|
||||||
|
|
||||||
|
#include <GLFW/glfw3.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Initialize window
|
||||||
|
*
|
||||||
|
* @return uint16_t WINDOW_SUCCESS on success. Possible errors:
|
||||||
|
* WINDOW_VULKAN_NOT_LOADED
|
||||||
|
* WINDOW_WINDOW_NOT_CREATED
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
uint16_t windowInit();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Main window loop
|
||||||
|
*
|
||||||
|
* @return uint16_t WINDOW_SUCCESS or error code
|
||||||
|
*/
|
||||||
|
uint16_t windowLoop();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Closes window and terminates GLFW
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void windowTerminate();
|
||||||
|
|
||||||
|
GLFWwindow* getWindowHandle();
|
||||||
|
|
||||||
|
#endif /* WINDOW_HANDLER_H */
|
||||||
@@ -0,0 +1,104 @@
|
|||||||
|
/**
|
||||||
|
* @file localeVulkan.h
|
||||||
|
* @author Piotr Krygier (everyonecancode@gmail.com)
|
||||||
|
* @brief Error messages for Vulkan initializers
|
||||||
|
* @version 0.1
|
||||||
|
* @date 2022-05-13
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2022
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef LOCALE_VULKAN_H
|
||||||
|
#define LOCALE_VULKAN_H
|
||||||
|
|
||||||
|
#include "localization.h"
|
||||||
|
|
||||||
|
enum Errors
|
||||||
|
{
|
||||||
|
VULKAN_INTANCE_INIT_FAILED,
|
||||||
|
VULKAN_NO_PHYSICAL_DEVICES,
|
||||||
|
VULKAN_NO_SUITABLE_PHYSICAL_DEVICES,
|
||||||
|
VULKAN_QUEUE_NOT_SUPPORTED,
|
||||||
|
VULKAN_FAILED_TO_CREATE_DEVICE,
|
||||||
|
VULKAN_ALLOCATOR_CREATION_FAILED,
|
||||||
|
VULKAN_COMMAND_POOL_CREATION_FAILED,
|
||||||
|
VULKAN_COMMAND_BUFFER_ALLOCATION_FAILED,
|
||||||
|
VULKAN_SURFACE_CREATION_FAILED,
|
||||||
|
VULKAN_SWAPCHAIN_CREATION_FAILED,
|
||||||
|
VULKAN_SWAPCHAIN_IMVIEW_CREATION_FAILED,
|
||||||
|
LAST_MESSAGE
|
||||||
|
};
|
||||||
|
|
||||||
|
const struct MessageString_t vulkanErrorMesssages[LAST_MESSAGE] =
|
||||||
|
{
|
||||||
|
{
|
||||||
|
38,
|
||||||
|
{/* VULKAN_INTANCE_INIT_FAILED */
|
||||||
|
"Vulkan instance initialization failed"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
55,
|
||||||
|
{/* VULKAN_NO_PHYSICAL_DEVICES */
|
||||||
|
"No physical graphical physical devices found in system"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
35,
|
||||||
|
{/* VULKAN_NO_SUITABLE_PHYSICAL_DEVICES */
|
||||||
|
"No suitable physical device found"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
70,
|
||||||
|
{/* VULKAN_QUEUE_NOT_SUPPORTED */
|
||||||
|
"Selected physical device does not support required queue capabilities"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
23,
|
||||||
|
{/* VULKAN_FAILED_TO_CREATE_DEVICE */
|
||||||
|
"Failed to create logical device"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
41,
|
||||||
|
{/* VULKAN_ALLOCATOR_CREATION_FAILED */
|
||||||
|
"Failed to create Vulkan Memory Allocator"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
30,
|
||||||
|
{/* VULKAN_COMMAND_POOL_CREATION_FAILED */
|
||||||
|
"Failed to create command pool"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
35,
|
||||||
|
{/* VULKAN_COMMAND_BUFFER_ALLOCATION_FAILED */
|
||||||
|
"Failed to allocate command buffers"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
32,
|
||||||
|
{/* VULKAN_SURFACE_CREATION_FAILED */
|
||||||
|
"Failed to create window surface"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
27,
|
||||||
|
{/* VULKAN_SWAPCHAIN_CREATION_FAILED */
|
||||||
|
"Failed to create swapchain"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
38,
|
||||||
|
{/* VULKAN_SWAPCHAIN_IMVIEW_CREATION_FAILED */
|
||||||
|
"Failed to create swapchain image view"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
/**
|
||||||
|
* @file localeWindow.hxx
|
||||||
|
* @author Piotr Krygier (everyonencancode@gmail.com)
|
||||||
|
* @brief Error messages
|
||||||
|
* @version 0.1
|
||||||
|
* @date 2022-02-15
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2022
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "localization.h"
|
||||||
|
|
||||||
|
enum Errors
|
||||||
|
{
|
||||||
|
WINDOW_GLFW_INIT_FAILED,
|
||||||
|
WINDOW_VULKAN_NOT_SUPPORTED,
|
||||||
|
WINDOW_NOT_CREATED,
|
||||||
|
LAST_MESSAGE
|
||||||
|
};
|
||||||
|
|
||||||
|
const struct MessageString_t windowErrorMesssages[LAST_MESSAGE] =
|
||||||
|
{
|
||||||
|
{
|
||||||
|
17,
|
||||||
|
{/* WINDOW_GLFW_INIT_FAILED */
|
||||||
|
"GLFW init failed!"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
22,
|
||||||
|
{/* WINDOW_VULKAN_NOT_SUPPORTED */
|
||||||
|
"Unable to load Vulkan"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
31,
|
||||||
|
{/*WINDOW_NOT_CREATED*/
|
||||||
|
"Window context creation failed"
|
||||||
|
}}
|
||||||
|
};
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
/**
|
||||||
|
* @file vmaInit.cpp
|
||||||
|
* @author Piotr Krygier (everyonecancode@gmail.com)
|
||||||
|
* @brief VMA is written in C, but has C++ compatible interface. It still needs to compiled as C++ though, hence the
|
||||||
|
* file
|
||||||
|
* @version 0.1
|
||||||
|
* @date 2022-05-23
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2022
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma GCC diagnostic push
|
||||||
|
# pragma GCC diagnostic warning "-Wunused"
|
||||||
|
# pragma GCC diagnostic warning "-Wpedantic"
|
||||||
|
# pragma GCC diagnostic warning "-Wignored-qualifiers"
|
||||||
|
# pragma GCC diagnostic warning "-Wmissing-field-initializers"
|
||||||
|
# pragma GCC diagnostic warning "-Wimplicit-fallthrough"
|
||||||
|
# pragma GCC diagnostic warning "-Wswitch"
|
||||||
|
# pragma GCC diagnostic warning "-Wparentheses"
|
||||||
|
#define VMA_IMPLEMENTATION
|
||||||
|
#define VMA_STATIC_VULKAN_FUNCTIONS 0
|
||||||
|
#define VMA_DYNAMIC_VULKAN_FUNCTIONS 1
|
||||||
|
#define VMA_STATS_STRING_ENABLED 0
|
||||||
|
#include <vk_mem_alloc.h>
|
||||||
|
#pragma GCC diagnostic pop
|
||||||
@@ -0,0 +1,610 @@
|
|||||||
|
/**
|
||||||
|
* @file vulkanBase.c
|
||||||
|
* @author Piotr Krygier (everyonecancode@gmail.com)
|
||||||
|
* @brief Base configuration for Vulkan API
|
||||||
|
* @version 0.1
|
||||||
|
* @date 2022-05-13
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2022
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* TODO: Replace with more dynamic include */
|
||||||
|
#define VK_USE_PLATFORM_XCB_KHR
|
||||||
|
|
||||||
|
#include "vulkanBase.h"
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <vulkan/vulkan.h>
|
||||||
|
#include <vk_mem_alloc.h>
|
||||||
|
#include <GLFW/glfw3.h>
|
||||||
|
|
||||||
|
#include "localeVulkan.h"
|
||||||
|
#include "log.h"
|
||||||
|
#include "window.h"
|
||||||
|
|
||||||
|
enum VULKAN_ERROR
|
||||||
|
{
|
||||||
|
VULKAN_ERROR_NO_ERROR = 0x0U,
|
||||||
|
VULKAN_ERROR_INSTANCE_INIT_FAILED,
|
||||||
|
VULKAN_ERROR_NO_PHYSICAL_DEVICE_FOUND,
|
||||||
|
VULKAN_ERROR_NO_SUITABLE_PHYSICAL_DEVICE_FOUND,
|
||||||
|
VULKAN_ERROR_QUEUE_NOT_SUPPORTED,
|
||||||
|
VULKAN_ERROR_DEVICE_CREATION_FAILED,
|
||||||
|
VULKAN_ERROR_ALLOCATOR_CREATION_FAILED,
|
||||||
|
VULKAN_ERROR_COMMAND_POOL_CREATION_FAILED,
|
||||||
|
VULKAN_ERROR_COMMAND_BUFFER_ALLOCATION_FAILED,
|
||||||
|
VULKAN_ERROR_SURFACE_CREATION_FAILED,
|
||||||
|
VULKAN_ERROR_SWAPCHAIN_CREATION_FAILED,
|
||||||
|
VULKAN_ERROR_SWAPCHAIN_IMVIEW_CREATION_FAILED,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Macro for checking status of function execution in initVulkan. Created to avoid writing boilerplate code */
|
||||||
|
#define STATUS_CHECK(FUNC) \
|
||||||
|
status = FUNC; \
|
||||||
|
if (VULKAN_ERROR_NO_ERROR != status) { \
|
||||||
|
return status; \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define APPLICATION_NAME "RedScarfEngine PoC"
|
||||||
|
#define ENGINE_NAME "RedScarf Engine"
|
||||||
|
#define SWAP_BUFFER_COUNT 2U
|
||||||
|
|
||||||
|
/* Define Validation Layers for debug build */
|
||||||
|
#ifndef NDEBUG
|
||||||
|
#define ENABLED_INSTANCE_LAYERS_COUNT 1U
|
||||||
|
#else
|
||||||
|
#define ENABLED_INSTANCE_LAYERS_COUNT 0U
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define ENABLED_INSTANCE_EXTENSIONS_COUNT 4U
|
||||||
|
#define ENABLED_DEVICE_EXTENSIONS_COUNT 1U
|
||||||
|
|
||||||
|
#ifndef NDEBUG
|
||||||
|
const char* gEnabledInstanceLayersNames[ENABLED_INSTANCE_LAYERS_COUNT] = {"VK_LAYER_KHRONOS_validation"};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Extensions required by GLFW. TODO: Check for extensions required on other platforms */
|
||||||
|
const char* gEnabledInstanceExtensionsNames[ENABLED_INSTANCE_EXTENSIONS_COUNT] = {
|
||||||
|
"VK_KHR_surface",
|
||||||
|
"VK_KHR_xcb_surface",
|
||||||
|
"VK_KHR_device_group_creation",
|
||||||
|
#ifndef NDEBUG
|
||||||
|
"VK_EXT_debug_utils",
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
const char* gEnabledDeviceExtensionsNames[ENABLED_DEVICE_EXTENSIONS_COUNT] = {
|
||||||
|
"VK_KHR_swapchain",
|
||||||
|
};
|
||||||
|
|
||||||
|
uint32_t gQueueFamilyIndices[1] = {0U}; /* TODO: Change when more families are needed */
|
||||||
|
uint32_t gSwapchainImagesCount = 0U;
|
||||||
|
VkInstance gVulkanInstance = VK_NULL_HANDLE;
|
||||||
|
VkSurfaceKHR gSurface = VK_NULL_HANDLE;
|
||||||
|
VkDebugUtilsMessengerEXT gDebugMessenger = VK_NULL_HANDLE;
|
||||||
|
VkPhysicalDevice gPhysicalDevice = VK_NULL_HANDLE;
|
||||||
|
VkDevice gDevice = VK_NULL_HANDLE;
|
||||||
|
VmaAllocator gAllocator = VK_NULL_HANDLE;
|
||||||
|
VkCommandPool gCommandPool = VK_NULL_HANDLE;
|
||||||
|
VkCommandBuffer* gpCommandBuffers = NULL; /* This one is an array. Allocated during runtime */
|
||||||
|
VkSwapchainKHR gSwapchain = VK_NULL_HANDLE;
|
||||||
|
VkImage* gpSwapChainImages = NULL;
|
||||||
|
VkImageView* gpSwapChainImageViews = NULL;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Create the Vulkan Instance object
|
||||||
|
*
|
||||||
|
* @return int VULKAN_ERROR_NO_ERROR on success. Possible errors:
|
||||||
|
* VULKAN_ERROR_INSTANCE_INIT_FAILED
|
||||||
|
*/
|
||||||
|
static int createInstance();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Create a Surface, connection between Vulkan and actual window
|
||||||
|
*
|
||||||
|
* @return int VULKAN_ERROR_NO_ERROR on success. Possible errors:
|
||||||
|
*/
|
||||||
|
static int createSurface();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Choose physical device. Used later for vkDevice
|
||||||
|
*
|
||||||
|
* @return int VULKAN_ERROR_NO_ERROR on success. Possible errors:
|
||||||
|
* VULKAN_ERROR_NO_PHYSICAL_DEVICE_FOUND
|
||||||
|
* VULKAN_ERROR_NO_SUITABLE_PHYSICAL_DEVICE_FOUND
|
||||||
|
*/
|
||||||
|
static int pickPhysicalDevice();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Create vkDevice object
|
||||||
|
*
|
||||||
|
* @return int VULKAN_ERROR_NO_ERROR on success. Possible errors:
|
||||||
|
* VULKAN_ERROR_QUEUE_NOT_SUPPORTED
|
||||||
|
* VULKAN_ERROR_DEVICE_CREATION_FAILED
|
||||||
|
*/
|
||||||
|
static int createDevice();
|
||||||
|
|
||||||
|
#ifndef NDEBUG
|
||||||
|
/**
|
||||||
|
* @brief Setup debugging system for Vulkan API
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
static void setupDebugMessenger();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Create a Memory Allocator object
|
||||||
|
*
|
||||||
|
* @return int VULKAN_ERROR_NO_ERROR on success. Possible errors:
|
||||||
|
* VULKAN_ERROR_ALLOCATOR_CREATION_FAILED
|
||||||
|
*/
|
||||||
|
static int createMemoryAllocator();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Create Command Pools
|
||||||
|
*
|
||||||
|
* @return int VULKAN_ERROR_NO_ERROR on success. Possible errors:
|
||||||
|
* VULKAN_ERROR_COMMAND_POOL_CREATION_FAILED
|
||||||
|
*/
|
||||||
|
static int createCommandPools();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Allocate Command Buffers
|
||||||
|
*
|
||||||
|
* @return int VULKAN_ERROR_NO_ERROR on success. Possible errors:
|
||||||
|
* VULKAN_ERROR_COMMAND_BUFFER_ALLOCATION_FAILED
|
||||||
|
*/
|
||||||
|
static int allocateCommandBuffers();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Create a Swapchain
|
||||||
|
*
|
||||||
|
* @return int VULKAN_ERROR_NO_ERROR on success. Possible errors:
|
||||||
|
* VULKAN_ERROR_SWAPCHAIN_CREATION_FAILED
|
||||||
|
*/
|
||||||
|
static int createSwapchain();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Create a Swapchain Image Views
|
||||||
|
*
|
||||||
|
* @return int int VULKAN_ERROR_NO_ERROR on success. Possible errors:
|
||||||
|
*/
|
||||||
|
static int createSwapchainImageViews();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Calback for debug messenger
|
||||||
|
*
|
||||||
|
* @param messageSeverity Message severity
|
||||||
|
* @param messageType Type of a message
|
||||||
|
* @param pCallbackData Contains all the callback related data in the VkDebugUtilsMessengerCallbackDataEXT structure
|
||||||
|
* @param pUserData Data provided by the user
|
||||||
|
* @return VkBool32 Should always return VK_FALSE. The VK_TRUE value is reserved for use in layer development
|
||||||
|
*/
|
||||||
|
static VKAPI_ATTR VkBool32 VKAPI_CALL debugCallback(VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
|
||||||
|
VkDebugUtilsMessageTypeFlagsEXT messageType,
|
||||||
|
const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData,
|
||||||
|
void* pUserData)
|
||||||
|
{
|
||||||
|
(void)messageSeverity;
|
||||||
|
(void)messageType;
|
||||||
|
(void)pUserData;
|
||||||
|
|
||||||
|
fprintf(stderr, "validation layer: %s\n", pCallbackData->pMessage);
|
||||||
|
|
||||||
|
return VK_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Proxy for vkCreateDebugUtilsMessengerEXT
|
||||||
|
*
|
||||||
|
* @param instance Vulkan instance object
|
||||||
|
* @param pCreateInfo VkDebugUtilsMessengerCreateInfoEXT structure
|
||||||
|
* @param pAllocator Memory allocator
|
||||||
|
* @param pDebugMessenger Debug messanger handle
|
||||||
|
* @return VkResult VK_SUCCESS on success
|
||||||
|
*/
|
||||||
|
static VkResult CreateDebugUtilsMessengerEXT(VkInstance instance, const VkDebugUtilsMessengerCreateInfoEXT* pCreateInfo,
|
||||||
|
const VkAllocationCallbacks* pAllocator,
|
||||||
|
VkDebugUtilsMessengerEXT* pDebugMessenger)
|
||||||
|
{
|
||||||
|
PFN_vkCreateDebugUtilsMessengerEXT func = NULL;
|
||||||
|
|
||||||
|
func = (PFN_vkCreateDebugUtilsMessengerEXT)vkGetInstanceProcAddr(instance, "vkCreateDebugUtilsMessengerEXT");
|
||||||
|
if (func != NULL) {
|
||||||
|
return func(instance, pCreateInfo, pAllocator, pDebugMessenger);
|
||||||
|
} else {
|
||||||
|
return VK_ERROR_EXTENSION_NOT_PRESENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
return VK_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Proxy for vkDestroyDebugUtilsMessengerEXT
|
||||||
|
*
|
||||||
|
* @param instance Vulkan instance object
|
||||||
|
* @param debugMessenger Debug messanger handle
|
||||||
|
* @param pAllocator Memory allocator
|
||||||
|
*/
|
||||||
|
static void DestroyDebugUtilsMessengerEXT(VkInstance instance, VkDebugUtilsMessengerEXT debugMessenger,
|
||||||
|
const VkAllocationCallbacks* pAllocator)
|
||||||
|
{
|
||||||
|
PFN_vkDestroyDebugUtilsMessengerEXT func =
|
||||||
|
(PFN_vkDestroyDebugUtilsMessengerEXT)vkGetInstanceProcAddr(instance, "vkDestroyDebugUtilsMessengerEXT");
|
||||||
|
if (func != NULL) {
|
||||||
|
func(instance, debugMessenger, pAllocator);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void setupDebugMessenger()
|
||||||
|
{
|
||||||
|
VkDebugUtilsMessengerCreateInfoEXT createInfo;
|
||||||
|
|
||||||
|
createInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT;
|
||||||
|
createInfo.messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT |
|
||||||
|
VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT |
|
||||||
|
VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT;
|
||||||
|
createInfo.messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT |
|
||||||
|
VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT |
|
||||||
|
VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT;
|
||||||
|
createInfo.pfnUserCallback = debugCallback;
|
||||||
|
createInfo.pUserData = NULL; // Optional
|
||||||
|
createInfo.flags = 0U;
|
||||||
|
|
||||||
|
if (CreateDebugUtilsMessengerEXT(gVulkanInstance, &createInfo, NULL, &gDebugMessenger) != VK_SUCCESS) {
|
||||||
|
fprintf(stderr, "failed to set up debug messenger!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static int createInstance()
|
||||||
|
{
|
||||||
|
uint32_t extensionCount = 0;
|
||||||
|
uint32_t layersCount = 0;
|
||||||
|
VkApplicationInfo applicationInfo;
|
||||||
|
VkInstanceCreateInfo createInfo;
|
||||||
|
VkLayerProperties* layerProperties = NULL;
|
||||||
|
VkExtensionProperties* extensionsProperties = NULL;
|
||||||
|
|
||||||
|
/* TODO: Remove or use later layer and extension properties */
|
||||||
|
vkEnumerateInstanceLayerProperties(&layersCount, NULL);
|
||||||
|
layerProperties = malloc(sizeof(VkLayerProperties) * layersCount);
|
||||||
|
vkEnumerateInstanceLayerProperties(&layersCount, layerProperties);
|
||||||
|
|
||||||
|
vkEnumerateInstanceExtensionProperties(NULL, &extensionCount, NULL);
|
||||||
|
extensionsProperties = malloc(sizeof(VkExtensionProperties) * extensionCount);
|
||||||
|
vkEnumerateInstanceExtensionProperties(NULL, &extensionCount, extensionsProperties);
|
||||||
|
|
||||||
|
printf("Supported Layers: \n");
|
||||||
|
for (size_t i = 0; i < layersCount; i++) {
|
||||||
|
printf("%s\n", layerProperties[i].layerName);
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("Supported Extensions: \n");
|
||||||
|
for (size_t i = 0; i < extensionCount; i++) {
|
||||||
|
printf("%s\n", extensionsProperties[i].extensionName);
|
||||||
|
}
|
||||||
|
|
||||||
|
applicationInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
|
||||||
|
applicationInfo.pNext = NULL;
|
||||||
|
applicationInfo.pApplicationName = APPLICATION_NAME;
|
||||||
|
applicationInfo.applicationVersion = VK_MAKE_VERSION(0, 1, 0);
|
||||||
|
applicationInfo.pEngineName = ENGINE_NAME;
|
||||||
|
applicationInfo.engineVersion = VK_MAKE_VERSION(0, 1, 0);
|
||||||
|
applicationInfo.apiVersion = VK_API_VERSION_1_2; /* TODO: Wait for package update to 1.3 */
|
||||||
|
|
||||||
|
createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
|
||||||
|
createInfo.pNext = NULL;
|
||||||
|
createInfo.flags = 0U;
|
||||||
|
createInfo.pApplicationInfo = &applicationInfo;
|
||||||
|
createInfo.enabledLayerCount = ENABLED_INSTANCE_LAYERS_COUNT;
|
||||||
|
#ifndef NDEBUG
|
||||||
|
createInfo.ppEnabledLayerNames = gEnabledInstanceLayersNames;
|
||||||
|
#else
|
||||||
|
createInfo.ppEnabledLayerNames = NULL;
|
||||||
|
#endif
|
||||||
|
createInfo.enabledExtensionCount = ENABLED_INSTANCE_EXTENSIONS_COUNT;
|
||||||
|
createInfo.ppEnabledExtensionNames = gEnabledInstanceExtensionsNames;
|
||||||
|
|
||||||
|
VkResult result = vkCreateInstance(&createInfo, NULL, &gVulkanInstance);
|
||||||
|
if (VK_SUCCESS != result) {
|
||||||
|
LOG(FATAL, "%s", LOCALIZE(vulkanErrorMesssages[VULKAN_INTANCE_INIT_FAILED]));
|
||||||
|
return VULKAN_ERROR_INSTANCE_INIT_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
return VULKAN_ERROR_NO_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int createSurface()
|
||||||
|
{
|
||||||
|
if (VK_SUCCESS != glfwCreateWindowSurface(gVulkanInstance, getWindowHandle(), NULL, &gSurface)) {
|
||||||
|
LOG(FATAL, "%s", LOCALIZE(vulkanErrorMesssages[VULKAN_SURFACE_CREATION_FAILED]));
|
||||||
|
return VULKAN_ERROR_SURFACE_CREATION_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
return VULKAN_ERROR_NO_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int pickPhysicalDevice()
|
||||||
|
{
|
||||||
|
uint32_t physicalDeviceCount = 0U;
|
||||||
|
VkPhysicalDevice* pPhysicalDevices = NULL;
|
||||||
|
|
||||||
|
/* Get number of existing physical devices */
|
||||||
|
vkEnumeratePhysicalDevices(gVulkanInstance, &physicalDeviceCount, NULL);
|
||||||
|
|
||||||
|
if (0 == physicalDeviceCount) {
|
||||||
|
LOG(FATAL, "%s", LOCALIZE(vulkanErrorMesssages[VULKAN_ERROR_NO_PHYSICAL_DEVICE_FOUND]));
|
||||||
|
return VULKAN_ERROR_NO_PHYSICAL_DEVICE_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
pPhysicalDevices = malloc(sizeof(VkPhysicalDevice) * physicalDeviceCount);
|
||||||
|
vkEnumeratePhysicalDevices(gVulkanInstance, &physicalDeviceCount, pPhysicalDevices);
|
||||||
|
|
||||||
|
/* Check for suitability */
|
||||||
|
for (size_t physicalDeviceIdx = 0U; physicalDeviceIdx < physicalDeviceCount; ++physicalDeviceIdx) {
|
||||||
|
/* TODO: Check for support */
|
||||||
|
VkPhysicalDeviceProperties deviceProperties;
|
||||||
|
VkPhysicalDeviceFeatures deviceFeatures;
|
||||||
|
vkGetPhysicalDeviceProperties(pPhysicalDevices[physicalDeviceIdx], &deviceProperties);
|
||||||
|
vkGetPhysicalDeviceFeatures(pPhysicalDevices[physicalDeviceIdx], &deviceFeatures);
|
||||||
|
|
||||||
|
/* Expect discrete graphics device type */
|
||||||
|
if (deviceProperties.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU) {
|
||||||
|
gPhysicalDevice = pPhysicalDevices[physicalDeviceIdx];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
free(pPhysicalDevices);
|
||||||
|
|
||||||
|
if (VK_NULL_HANDLE == gPhysicalDevice) {
|
||||||
|
/* No suitable device found */
|
||||||
|
LOG(FATAL, "%s", LOCALIZE(vulkanErrorMesssages[VULKAN_NO_SUITABLE_PHYSICAL_DEVICES]));
|
||||||
|
return VULKAN_ERROR_NO_SUITABLE_PHYSICAL_DEVICE_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
return VULKAN_ERROR_NO_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int createDevice()
|
||||||
|
{
|
||||||
|
uint32_t queueFamiliesPropertyCount = 0U;
|
||||||
|
ssize_t supportingQueueFamilityIdx = -1;
|
||||||
|
VkQueueFamilyProperties* pQueueFamilyProperties = NULL;
|
||||||
|
VkDeviceCreateInfo deviceCreateInfo = {0};
|
||||||
|
VkDeviceQueueCreateInfo deviceQueueCreateInfos[1] = {0}; /* TODO: Change when we want more queues */
|
||||||
|
float* pQueuePriorities = NULL;
|
||||||
|
|
||||||
|
/* Get information about supported queue families */
|
||||||
|
vkGetPhysicalDeviceQueueFamilyProperties(gPhysicalDevice, &queueFamiliesPropertyCount, NULL);
|
||||||
|
pQueueFamilyProperties = malloc(sizeof(VkQueueFamilyProperties) * queueFamiliesPropertyCount);
|
||||||
|
vkGetPhysicalDeviceQueueFamilyProperties(gPhysicalDevice, &queueFamiliesPropertyCount, pQueueFamilyProperties);
|
||||||
|
|
||||||
|
/* Get queue families that support graphics operations AND have most
|
||||||
|
* queues. */
|
||||||
|
{
|
||||||
|
size_t numberOfQueues = 0;
|
||||||
|
for (size_t familyIdx = 0; familyIdx < queueFamiliesPropertyCount; ++familyIdx) {
|
||||||
|
if (pQueueFamilyProperties[familyIdx].queueFlags & VK_QUEUE_GRAPHICS_BIT) {
|
||||||
|
if (pQueueFamilyProperties[familyIdx].queueCount > numberOfQueues) {
|
||||||
|
supportingQueueFamilityIdx = familyIdx;
|
||||||
|
numberOfQueues = pQueueFamilyProperties[familyIdx].queueCount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This is not magic number ;P. We want to support exact number of required queues flags */
|
||||||
|
if (0 > supportingQueueFamilityIdx) {
|
||||||
|
LOG(FATAL, "%s", LOCALIZE(vulkanErrorMesssages[VULKAN_QUEUE_NOT_SUPPORTED]));
|
||||||
|
return VULKAN_ERROR_QUEUE_NOT_SUPPORTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
gQueueFamilyIndices[0] = supportingQueueFamilityIdx; /* TODO: Change when more families are needed */
|
||||||
|
|
||||||
|
pQueuePriorities = malloc(pQueueFamilyProperties[supportingQueueFamilityIdx].queueCount * sizeof(float));
|
||||||
|
for (size_t i = 0; i < pQueueFamilyProperties[supportingQueueFamilityIdx].queueCount; i++) {
|
||||||
|
pQueuePriorities[i] = 1.0f; /* TODO: When queues have different tasks, change this if needed */
|
||||||
|
}
|
||||||
|
|
||||||
|
deviceQueueCreateInfos[0].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
|
||||||
|
deviceQueueCreateInfos[0].pNext = NULL;
|
||||||
|
deviceQueueCreateInfos[0].flags = 0;
|
||||||
|
deviceQueueCreateInfos[0].queueFamilyIndex = supportingQueueFamilityIdx;
|
||||||
|
deviceQueueCreateInfos[0].queueCount = pQueueFamilyProperties[supportingQueueFamilityIdx].queueCount;
|
||||||
|
deviceQueueCreateInfos[0].pQueuePriorities = pQueuePriorities;
|
||||||
|
|
||||||
|
free(pQueueFamilyProperties); /* Not needed anymore */
|
||||||
|
|
||||||
|
deviceCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
|
||||||
|
deviceCreateInfo.pNext = NULL;
|
||||||
|
deviceCreateInfo.flags = 0U;
|
||||||
|
deviceCreateInfo.queueCreateInfoCount = 1u; /* For now one is enough. TODO: Change when needed. */
|
||||||
|
deviceCreateInfo.pQueueCreateInfos = deviceQueueCreateInfos;
|
||||||
|
deviceCreateInfo.enabledLayerCount = 0;
|
||||||
|
deviceCreateInfo.ppEnabledLayerNames = NULL;
|
||||||
|
deviceCreateInfo.enabledExtensionCount = ENABLED_DEVICE_EXTENSIONS_COUNT;
|
||||||
|
deviceCreateInfo.ppEnabledExtensionNames = gEnabledDeviceExtensionsNames;
|
||||||
|
deviceCreateInfo.pEnabledFeatures = NULL; /* TODO: Enable features, when needed */
|
||||||
|
|
||||||
|
if (VK_SUCCESS != vkCreateDevice(gPhysicalDevice, &deviceCreateInfo, NULL, &gDevice)) {
|
||||||
|
LOG(FATAL, "%s", LOCALIZE(vulkanErrorMesssages[VULKAN_FAILED_TO_CREATE_DEVICE]));
|
||||||
|
free(pQueuePriorities);
|
||||||
|
return VULKAN_ERROR_DEVICE_CREATION_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(pQueuePriorities);
|
||||||
|
|
||||||
|
return VULKAN_ERROR_NO_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int createMemoryAllocator()
|
||||||
|
{
|
||||||
|
VmaVulkanFunctions vulkanFunctions = {0};
|
||||||
|
vulkanFunctions.vkGetInstanceProcAddr = &vkGetInstanceProcAddr;
|
||||||
|
vulkanFunctions.vkGetDeviceProcAddr = &vkGetDeviceProcAddr;
|
||||||
|
|
||||||
|
VmaAllocatorCreateInfo allocatorCreateInfo = {0};
|
||||||
|
allocatorCreateInfo.vulkanApiVersion = VK_API_VERSION_1_2;
|
||||||
|
allocatorCreateInfo.physicalDevice = gPhysicalDevice;
|
||||||
|
allocatorCreateInfo.device = gDevice;
|
||||||
|
allocatorCreateInfo.instance = gVulkanInstance;
|
||||||
|
allocatorCreateInfo.pVulkanFunctions = &vulkanFunctions;
|
||||||
|
|
||||||
|
if (VK_SUCCESS != vmaCreateAllocator(&allocatorCreateInfo, &gAllocator)) {
|
||||||
|
LOG(FATAL, "%s", LOCALIZE(vulkanErrorMesssages[VULKAN_ERROR_ALLOCATOR_CREATION_FAILED]));
|
||||||
|
return VULKAN_ERROR_ALLOCATOR_CREATION_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
return VULKAN_ERROR_NO_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int createCommandPools()
|
||||||
|
{
|
||||||
|
VkCommandPoolCreateInfo createInfo;
|
||||||
|
|
||||||
|
createInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
|
||||||
|
createInfo.pNext = NULL;
|
||||||
|
createInfo.flags = 0U;
|
||||||
|
createInfo.queueFamilyIndex = gQueueFamilyIndices[0]; /* TODO: Change when more families are needed */
|
||||||
|
|
||||||
|
if (VK_SUCCESS != vkCreateCommandPool(gDevice, &createInfo, NULL, &gCommandPool)) {
|
||||||
|
LOG(FATAL, "%s", LOCALIZE(vulkanErrorMesssages[VULKAN_COMMAND_POOL_CREATION_FAILED]));
|
||||||
|
return VULKAN_ERROR_COMMAND_POOL_CREATION_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
return VULKAN_ERROR_NO_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int allocateCommandBuffers()
|
||||||
|
{
|
||||||
|
VkCommandBufferAllocateInfo allocateInfo;
|
||||||
|
|
||||||
|
/* Allocate memory for command buffers */
|
||||||
|
gpCommandBuffers = malloc(sizeof(VkCommandBuffer) * SWAP_BUFFER_COUNT);
|
||||||
|
|
||||||
|
allocateInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
|
||||||
|
allocateInfo.pNext = NULL;
|
||||||
|
allocateInfo.commandPool = gCommandPool;
|
||||||
|
allocateInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; /* TODO: When needed, add secondary command buffer */
|
||||||
|
allocateInfo.commandBufferCount = SWAP_BUFFER_COUNT;
|
||||||
|
|
||||||
|
if (VK_SUCCESS != vkAllocateCommandBuffers(gDevice, &allocateInfo, gpCommandBuffers)) {
|
||||||
|
LOG(FATAL, "%s", LOCALIZE(vulkanErrorMesssages[VULKAN_COMMAND_BUFFER_ALLOCATION_FAILED]));
|
||||||
|
return VULKAN_ERROR_COMMAND_BUFFER_ALLOCATION_FAILED;
|
||||||
|
}
|
||||||
|
return VULKAN_ERROR_NO_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int createSwapchain()
|
||||||
|
{
|
||||||
|
VkSwapchainCreateInfoKHR createInfo;
|
||||||
|
VkSurfaceCapabilitiesKHR physicalDeviceSurfaceCapabilities;
|
||||||
|
VkBool32 surfaceSupported;
|
||||||
|
|
||||||
|
vkGetPhysicalDeviceSurfaceCapabilitiesKHR(gPhysicalDevice, gSurface, &physicalDeviceSurfaceCapabilities);
|
||||||
|
|
||||||
|
/* Check if device supports surface for presentation */
|
||||||
|
vkGetPhysicalDeviceSurfaceSupportKHR(gPhysicalDevice, gQueueFamilyIndices[0], gSurface, &surfaceSupported);
|
||||||
|
|
||||||
|
createInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
|
||||||
|
createInfo.pNext = NULL;
|
||||||
|
createInfo.flags = 0U;
|
||||||
|
createInfo.surface = gSurface;
|
||||||
|
createInfo.minImageCount = SWAP_BUFFER_COUNT;
|
||||||
|
createInfo.imageFormat = VK_FORMAT_B8G8R8A8_SRGB; /* TODO: Check for supported formats */
|
||||||
|
createInfo.imageColorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR; /* TODO: Check for supported color space */
|
||||||
|
createInfo.imageExtent = physicalDeviceSurfaceCapabilities.currentExtent;
|
||||||
|
createInfo.imageArrayLayers = 1U; /* For non-stereoscopic-3D applications, this value is 1. */
|
||||||
|
createInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; /* TODO: Probably change later? Dunno */
|
||||||
|
createInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; /* Using only one queue family, so this is ok */
|
||||||
|
createInfo.queueFamilyIndexCount = 1U;
|
||||||
|
createInfo.pQueueFamilyIndices = gQueueFamilyIndices;
|
||||||
|
createInfo.preTransform = physicalDeviceSurfaceCapabilities.currentTransform;
|
||||||
|
createInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
|
||||||
|
createInfo.presentMode = VK_PRESENT_MODE_FIFO_KHR; /* TODO: Choose present mode from VkPresentModeKHR */
|
||||||
|
createInfo.clipped = VK_TRUE;
|
||||||
|
createInfo.oldSwapchain = VK_NULL_HANDLE;
|
||||||
|
|
||||||
|
if (VK_SUCCESS != vkCreateSwapchainKHR(gDevice, &createInfo, NULL, &gSwapchain)) {
|
||||||
|
LOG(FATAL, "%s", LOCALIZE(vulkanErrorMesssages[VULKAN_SWAPCHAIN_CREATION_FAILED]));
|
||||||
|
return VULKAN_ERROR_SWAPCHAIN_CREATION_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Obtain swapchain images */
|
||||||
|
vkGetSwapchainImagesKHR(gDevice, gSwapchain, &gSwapchainImagesCount, NULL);
|
||||||
|
gpSwapChainImages = malloc(sizeof(VkImage) * gSwapchainImagesCount);
|
||||||
|
vkGetSwapchainImagesKHR(gDevice, gSwapchain, &gSwapchainImagesCount, gpSwapChainImages);
|
||||||
|
|
||||||
|
return VULKAN_ERROR_NO_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int createSwapchainImageViews()
|
||||||
|
{
|
||||||
|
gpSwapChainImageViews = malloc(sizeof(VkImageView) * gSwapchainImagesCount);
|
||||||
|
for (size_t i = 0; i < gSwapchainImagesCount; i++) {
|
||||||
|
VkImageViewCreateInfo createInfo;
|
||||||
|
|
||||||
|
createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
|
||||||
|
createInfo.pNext = NULL;
|
||||||
|
createInfo.flags = 0U;
|
||||||
|
createInfo.image = gpSwapChainImages[i];
|
||||||
|
createInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; /* 2D Texture */
|
||||||
|
createInfo.format = VK_FORMAT_B8G8R8A8_SRGB;
|
||||||
|
createInfo.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;
|
||||||
|
createInfo.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;
|
||||||
|
createInfo.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;
|
||||||
|
createInfo.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;
|
||||||
|
createInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||||
|
createInfo.subresourceRange.baseMipLevel = 0U;
|
||||||
|
createInfo.subresourceRange.levelCount = 1U;
|
||||||
|
createInfo.subresourceRange.baseArrayLayer = 0U;
|
||||||
|
createInfo.subresourceRange.layerCount = 1U;
|
||||||
|
|
||||||
|
if(VK_SUCCESS != vkCreateImageView(gDevice, &createInfo, NULL, &gpSwapChainImageViews[i]))
|
||||||
|
{
|
||||||
|
LOG(FATAL, "%s", LOCALIZE(vulkanErrorMesssages[VULKAN_SWAPCHAIN_IMVIEW_CREATION_FAILED]));
|
||||||
|
return VULKAN_ERROR_SWAPCHAIN_IMVIEW_CREATION_FAILED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return VULKAN_ERROR_NO_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
int initVulkan()
|
||||||
|
{
|
||||||
|
int status = VULKAN_ERROR_NO_ERROR;
|
||||||
|
|
||||||
|
STATUS_CHECK(createInstance());
|
||||||
|
#ifndef NDEBUG
|
||||||
|
setupDebugMessenger();
|
||||||
|
#endif
|
||||||
|
STATUS_CHECK(createSurface());
|
||||||
|
STATUS_CHECK(pickPhysicalDevice());
|
||||||
|
STATUS_CHECK(createDevice());
|
||||||
|
STATUS_CHECK(createMemoryAllocator());
|
||||||
|
STATUS_CHECK(createCommandPools());
|
||||||
|
STATUS_CHECK(allocateCommandBuffers());
|
||||||
|
STATUS_CHECK(createSwapchain());
|
||||||
|
STATUS_CHECK(createSwapchainImageViews());
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
void deinitVulkan()
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < gSwapchainImagesCount; i++) {
|
||||||
|
vkDestroyImageView(gDevice ,gpSwapChainImageViews[i], NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
vkDestroySwapchainKHR(gDevice, gSwapchain, NULL);
|
||||||
|
vkDestroyCommandPool(gDevice, gCommandPool, NULL);
|
||||||
|
vmaDestroyAllocator(gAllocator);
|
||||||
|
vkDestroyDevice(gDevice, NULL);
|
||||||
|
#ifndef NDEBUG
|
||||||
|
DestroyDebugUtilsMessengerEXT(gVulkanInstance, gDebugMessenger, NULL);
|
||||||
|
#endif
|
||||||
|
vkDestroySurfaceKHR(gVulkanInstance, gSurface, NULL);
|
||||||
|
vkDestroyInstance(gVulkanInstance, NULL);
|
||||||
|
}
|
||||||
@@ -0,0 +1,111 @@
|
|||||||
|
/**
|
||||||
|
* @file window.cxx
|
||||||
|
* @author Piotr Krygier (everyonencancode@gmail.com)
|
||||||
|
* @brief
|
||||||
|
* @version 0.1
|
||||||
|
* @date 2022-02-15
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2022
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "window.h"
|
||||||
|
|
||||||
|
#include "localeWindow.h"
|
||||||
|
#include "log.h"
|
||||||
|
|
||||||
|
/* Error codes */
|
||||||
|
typedef enum {
|
||||||
|
WINDOW_ERROR_NO_ERROR = 0U,
|
||||||
|
WINDOW_ERROR_GLFW_INIT_FAILED,
|
||||||
|
WINDOW_ERROR_VULKAN_NOT_LOADED,
|
||||||
|
WINDOW_ERROR_WINDOW_NOT_CREATED
|
||||||
|
} WINDOW_ERROR;
|
||||||
|
|
||||||
|
GLFWwindow *gpWindowHandle = NULL;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief GLFW erro callback
|
||||||
|
*
|
||||||
|
* @param error Error code
|
||||||
|
* @param description Error description
|
||||||
|
*/
|
||||||
|
static void errrorCallback(int error, const char* description)
|
||||||
|
{
|
||||||
|
(void)error;
|
||||||
|
LOG(ERROR, "Error: %s", description);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Pressed key callback
|
||||||
|
*
|
||||||
|
* @param window Window in which contex the key has been pressed
|
||||||
|
* @param key The keyboard key that was pressed or released
|
||||||
|
* @param scancode The system-specific scancode of the key.
|
||||||
|
* @param action GLFW_PRESS, GLFW_RELEASE or GLFW_REPEAT
|
||||||
|
* @param mods Bit field describing which modifier keys were held down
|
||||||
|
*/
|
||||||
|
static void keyCallback(GLFWwindow* window, int key, int scancode, int action, int mods)
|
||||||
|
{
|
||||||
|
(void)scancode;
|
||||||
|
(void)action;
|
||||||
|
(void)mods;
|
||||||
|
if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS) {
|
||||||
|
glfwSetWindowShouldClose(window, GLFW_TRUE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t windowInit()
|
||||||
|
{
|
||||||
|
/* Initiliaze GLFW AP */
|
||||||
|
if (GLFW_TRUE != glfwInit())
|
||||||
|
{
|
||||||
|
LOG(FATAL, "%s", LOCALIZE(windowErrorMesssages[WINDOW_GLFW_INIT_FAILED]));
|
||||||
|
return WINDOW_ERROR_GLFW_INIT_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Check for Vulkan support */
|
||||||
|
if (GLFW_FALSE == glfwVulkanSupported()) {
|
||||||
|
LOG(FATAL, "%s", LOCALIZE(windowErrorMesssages[WINDOW_VULKAN_NOT_SUPPORTED]));
|
||||||
|
return WINDOW_ERROR_VULKAN_NOT_LOADED;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set error callback */
|
||||||
|
glfwSetErrorCallback(errrorCallback);
|
||||||
|
|
||||||
|
/* Create window */
|
||||||
|
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
|
||||||
|
|
||||||
|
gpWindowHandle = glfwCreateWindow(640, 480, "RedScarfEngine", NULL, NULL);
|
||||||
|
|
||||||
|
if (NULL == gpWindowHandle) {
|
||||||
|
LOG(FATAL, "%s", LOCALIZE(windowErrorMesssages[WINDOW_NOT_CREATED]));
|
||||||
|
return WINDOW_ERROR_WINDOW_NOT_CREATED;
|
||||||
|
}
|
||||||
|
|
||||||
|
glfwSetKeyCallback(gpWindowHandle, keyCallback);
|
||||||
|
|
||||||
|
return WINDOW_ERROR_NO_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t windowLoop()
|
||||||
|
{
|
||||||
|
while (!glfwWindowShouldClose(gpWindowHandle)) {
|
||||||
|
glfwPollEvents();
|
||||||
|
}
|
||||||
|
|
||||||
|
return WINDOW_ERROR_NO_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
void windowTerminate()
|
||||||
|
{
|
||||||
|
glfwDestroyWindow(gpWindowHandle);
|
||||||
|
glfwTerminate();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
GLFWwindow* getWindowHandle()
|
||||||
|
{
|
||||||
|
return gpWindowHandle;
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2022 Piotr Krygier
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.10)
|
||||||
|
|
||||||
|
add_executable(${PROJECT_NAME} src/main.c)
|
||||||
|
|
||||||
|
target_include_directories(${PROJECT_NAME} PRIVATE
|
||||||
|
${CMAKE_SOURCE_DIR}/Utilities/include)
|
||||||
|
|
||||||
|
|
||||||
|
target_link_libraries(${PROJECT_NAME}
|
||||||
|
GraphicsEngine)
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
#include "log.h"
|
||||||
|
#include "window.h"
|
||||||
|
#include "vulkanBase.h"
|
||||||
|
|
||||||
|
|
||||||
|
int main(int argc, char** argv)
|
||||||
|
{
|
||||||
|
(void)argc;
|
||||||
|
(void)argv;
|
||||||
|
|
||||||
|
windowInit();
|
||||||
|
|
||||||
|
initVulkan();
|
||||||
|
|
||||||
|
windowLoop();
|
||||||
|
|
||||||
|
deinitVulkan();
|
||||||
|
|
||||||
|
windowTerminate();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
/**
|
||||||
|
* @file localization.h
|
||||||
|
* @author Piotr Krygier (everyonencancode@gmail.com)
|
||||||
|
* @brief Simple localization header
|
||||||
|
* @version 0.1
|
||||||
|
* @date 2022-02-15
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2022
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef LOCALIZATION_H
|
||||||
|
#define LOCALIZATION_H
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#define SELECTED_LANGUAGE EN_US
|
||||||
|
|
||||||
|
#define LOCALIZE(string) string.message[SELECTED_LANGUAGE]
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Available languages
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
enum Languages_t
|
||||||
|
{
|
||||||
|
EN_US = 0,
|
||||||
|
LAST_LANGUAGE
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
struct MessageString_t
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @brief Maximum message length. I.e. if French version is longer than English, use French length.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
size_t maxMessageLength;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @brief Array holding list of translations for specific message
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
const char* const message[LAST_LANGUAGE];
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* LOCALIZATION_H */
|
||||||
@@ -0,0 +1,90 @@
|
|||||||
|
/**
|
||||||
|
* @file log.hxx
|
||||||
|
* @author Piotr Krygier (everyonencancode@gmail.com)
|
||||||
|
* @brief Logging interfaces
|
||||||
|
* @version 0.1
|
||||||
|
* @date 2022-02-11
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2022
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef LOG_H
|
||||||
|
#define LOG_H
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
/* Controls level of logging. TODO: Move this to cmake or some config */
|
||||||
|
#define LOG_LEVEL 6
|
||||||
|
|
||||||
|
#define LOG(level, ...) _LOG_##level(__VA_ARGS__)
|
||||||
|
|
||||||
|
#if LOG_LEVEL >= 1
|
||||||
|
#define _LOG_FATAL(...) __LOG(FATAL, __VA_ARGS__)
|
||||||
|
#else
|
||||||
|
#define _LOG_FATAL(...)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if LOG_LEVEL >= 2
|
||||||
|
#define _LOG_ERROR(...) __LOG(ERROR, __VA_ARGS__)
|
||||||
|
#else
|
||||||
|
#define _LOG_ERROR(...)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if LOG_LEVEL >= 3
|
||||||
|
#define _LOG_WARNING(...) __LOG(WARNING, __VA_ARGS__)
|
||||||
|
#else
|
||||||
|
#define _LOG_WARNING(...)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if LOG_LEVEL >= 4
|
||||||
|
#define _LOG_INFO(...) __LOG(INFO, __VA_ARGS__)
|
||||||
|
#else
|
||||||
|
#define _LOG_INFO(...)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if LOG_LEVEL >= 5
|
||||||
|
#define _LOG_DEBUG(...) __LOG(DEBUG, __VA_ARGS__)
|
||||||
|
#else
|
||||||
|
#define _LOG_DEBUG(...)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if LOG_LEVEL >= 6
|
||||||
|
#define _LOG_TRACE(...) __LOG(TRACE, __VA_ARGS__)
|
||||||
|
#else
|
||||||
|
#define _LOG_TRACE(...)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Macro magic, that makes logging work. It's better than C++ solution anyway... */
|
||||||
|
#define _LOG_SIZEOF(...) __LOG_SIZEOF(__VA_ARGS__, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 0)
|
||||||
|
#define __LOG_SIZEOF(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20, N, \
|
||||||
|
...) \
|
||||||
|
N
|
||||||
|
#define _LOG_EVAL(x) x
|
||||||
|
#define __LOG(level, ...) ___LOG(_LOG_SIZEOF(__VA_ARGS__), level, __VA_ARGS__)
|
||||||
|
#define ___LOG(n, ...) ____LOG(n, __VA_ARGS__)
|
||||||
|
#define ____LOG(n, ...) ____LOG##n(__VA_ARGS__)
|
||||||
|
#define ____LOG1(level, format) \
|
||||||
|
fprintf(stdout, \
|
||||||
|
"[" #level \
|
||||||
|
"]" \
|
||||||
|
"\t%s:%d\t" format "\n", \
|
||||||
|
__builtin_strrchr(__FILE__, '/') ? __builtin_strrchr(__FILE__, '/') + 1 : __FILE__, __LINE__)
|
||||||
|
#define ____LOG2(level, format, ...) \
|
||||||
|
fprintf(stdout, \
|
||||||
|
"[" #level \
|
||||||
|
"]" \
|
||||||
|
"\t%s:%d\t" format "\n", \
|
||||||
|
__builtin_strrchr(__FILE__, '/') ? __builtin_strrchr(__FILE__, '/') + 1 : __FILE__, __LINE__, __VA_ARGS__)
|
||||||
|
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
TRACE = 1,
|
||||||
|
DEBUG = 2,
|
||||||
|
INFO = 3,
|
||||||
|
WARNING = 4,
|
||||||
|
ERROR = 5,
|
||||||
|
FATAL = 6
|
||||||
|
} LogLevel;
|
||||||
|
|
||||||
|
#endif /* LOG_H */
|
||||||
+19564
File diff suppressed because it is too large.
Load diff
Reference in new issue
Block a user