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