Cleanup repo

This commit is contained in:
Piotr Krygier committed 2022-06-28 09:54:41 +02:00
commit 4755371ffa
18 files changed
+20826

No files matched your search

+32
View File
@@ -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
View File
@@ -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/
+23
View File
@@ -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)
+18
View File
@@ -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)
+18
View File
@@ -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 */
+45
View File
@@ -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 */
+104
View File
@@ -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
+41
View File
@@ -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"
}}
};
+26
View File
@@ -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
+610
View File
@@ -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);
}
+111
View File
@@ -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;
}
+21
View File
@@ -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.
+1
View File
@@ -0,0 +1 @@
# Red Scarf Engine
+10
View File
@@ -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)
+22
View File
@@ -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;
}
+51
View File
@@ -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 */
+90
View File
@@ -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 */
File diff suppressed because it is too large. Load diff