@@ -20,6 +20,5 @@ add_subdirectory(FastRTTI)
|
|||||||
add_subdirectory(glfw)
|
add_subdirectory(glfw)
|
||||||
add_subdirectory(Core)
|
add_subdirectory(Core)
|
||||||
add_subdirectory(ModuleLib)
|
add_subdirectory(ModuleLib)
|
||||||
add_subdirectory(RenderModule)
|
|
||||||
add_subdirectory(TestGame)
|
add_subdirectory(TestGame)
|
||||||
add_subdirectory(ProjectGenerator)
|
add_subdirectory(ProjectGenerator)
|
||||||
|
|||||||
@@ -2,8 +2,6 @@ set(CORE_NAME Core)
|
|||||||
|
|
||||||
find_package(Vulkan REQUIRED)
|
find_package(Vulkan REQUIRED)
|
||||||
|
|
||||||
set(CORE_NAME Core)
|
|
||||||
|
|
||||||
file(GLOB_RECURSE SRC "*.cpp" "*.c" "*.h" "*.hpp")
|
file(GLOB_RECURSE SRC "*.cpp" "*.c" "*.h" "*.hpp")
|
||||||
|
|
||||||
add_library(${CORE_NAME} STATIC ${SRC})
|
add_library(${CORE_NAME} STATIC ${SRC})
|
||||||
|
|||||||
+50
-31
@@ -1,17 +1,22 @@
|
|||||||
#include "CoreInstance.h"
|
#include "CoreInstance.h"
|
||||||
|
|
||||||
#include "SystemCalls.h"
|
#include "SystemCalls.h"
|
||||||
#include "GLFW/glfw3.h"
|
|
||||||
|
|
||||||
#include <exception>
|
#include <exception>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
|
#include "RenderEngine.h"
|
||||||
|
#include "Game/GameInstance.h"
|
||||||
#include "Log/Log.h"
|
#include "Log/Log.h"
|
||||||
|
#include "Game/SaveMap/SaveMap.h"
|
||||||
|
|
||||||
CoreInstance* CoreInstance::self = nullptr;
|
CoreInstance* CoreInstance::self = nullptr;
|
||||||
|
|
||||||
|
extern GameInstance* GameFactory(CoreInstance&);
|
||||||
|
|
||||||
std::shared_ptr<SaveMap> CoreInstance::MainConfig::save()
|
std::shared_ptr<SaveMap> CoreInstance::MainConfig::save()
|
||||||
{
|
{
|
||||||
return std::make_shared<SaveMap>("MainConfig");
|
return std::make_shared<SaveMap>("MainConfig");
|
||||||
@@ -28,7 +33,7 @@ void CoreInstance::MainConfig::load(std::shared_ptr<SaveMap> save)
|
|||||||
|
|
||||||
void CoreInstance::Quit_callback()
|
void CoreInstance::Quit_callback()
|
||||||
{
|
{
|
||||||
self->game->quit();
|
self->game_->quit();
|
||||||
}
|
}
|
||||||
|
|
||||||
CoreInstance::CoreInstance()
|
CoreInstance::CoreInstance()
|
||||||
@@ -37,16 +42,8 @@ CoreInstance::CoreInstance()
|
|||||||
|
|
||||||
callbacks_.Quit = &Quit_callback;
|
callbacks_.Quit = &Quit_callback;
|
||||||
|
|
||||||
countCPU = System::getCountCPU();
|
countCPU_ = System::getCountCPU();
|
||||||
memorySize = System::getMemorySize();
|
memorySize_ = System::getMemorySize();
|
||||||
|
|
||||||
if (!glfwInit())
|
|
||||||
{
|
|
||||||
std::string msg;
|
|
||||||
const char* error;
|
|
||||||
glfwGetError(&error);
|
|
||||||
throw std::runtime_error("Fail initialize GLFW");
|
|
||||||
}
|
|
||||||
|
|
||||||
std::ifstream main_config_file(main_config_name);
|
std::ifstream main_config_file(main_config_name);
|
||||||
if (main_config_file.fail())
|
if (main_config_file.fail())
|
||||||
@@ -56,35 +53,51 @@ CoreInstance::CoreInstance()
|
|||||||
std::getline(main_config_file, payload);
|
std::getline(main_config_file, payload);
|
||||||
SaveMap load_main_config(payload);
|
SaveMap load_main_config(payload);
|
||||||
|
|
||||||
main_config.load(std::make_shared<SaveMap>(load_main_config));
|
main_config_.load(std::make_shared<SaveMap>(load_main_config));
|
||||||
|
|
||||||
|
if (glfwInit() == GLFW_FALSE)
|
||||||
|
throw std::runtime_error("Fail init glfw");
|
||||||
|
|
||||||
|
glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);
|
||||||
|
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
|
||||||
|
window_ = glfwCreateWindow(800, 600, main_config_.game_name.c_str(), nullptr, nullptr);
|
||||||
|
if (window_ == nullptr)
|
||||||
|
{
|
||||||
|
glfwTerminate();
|
||||||
|
throw std::runtime_error("Fail create window");
|
||||||
|
}
|
||||||
|
render_engine_ = new RenderEngine(*this, window_);
|
||||||
|
|
||||||
|
game_ = GameFactory(*this);
|
||||||
|
if (game_ == nullptr)
|
||||||
|
throw std::runtime_error("Fail create game instance!");
|
||||||
}
|
}
|
||||||
|
|
||||||
CoreInstance::~CoreInstance()
|
CoreInstance::~CoreInstance()
|
||||||
{
|
{
|
||||||
delete game;
|
for (auto& module : modules_)
|
||||||
|
|
||||||
for (auto& module : modules)
|
|
||||||
System::QuitModule(module.handler);
|
System::QuitModule(module.handler);
|
||||||
modules.clear();
|
modules_.clear();
|
||||||
}
|
|
||||||
|
|
||||||
extern GameInstance* GameFactory(CoreInstance&);
|
delete render_engine_;
|
||||||
|
delete game_;
|
||||||
|
}
|
||||||
|
|
||||||
void CoreInstance::start()
|
void CoreInstance::start()
|
||||||
{
|
{
|
||||||
for (auto& name : main_config.modules_names)
|
for (auto& name : main_config_.modules_names)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
void* handler = System::InitModule(name.c_str(), &callbacks_);
|
void* handler = System::InitModule(name.c_str(), &callbacks_);
|
||||||
modules.push_back(Module {name.c_str(), handler});
|
modules_.push_back(Module {name.c_str(), handler});
|
||||||
} catch (const std::exception& e)
|
} catch (const std::exception& e)
|
||||||
{
|
{
|
||||||
std::cout << e.what() << '\n';
|
std::cout << e.what() << '\n';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto& module : modules)
|
for (auto& module : modules_)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -95,15 +108,21 @@ void CoreInstance::start()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
game = GameFactory(*this);
|
std::thread game_thread(&GameInstance::start, game_);
|
||||||
if (game == nullptr)
|
render_engine_->start();
|
||||||
throw std::runtime_error("Fail create game instance!");
|
game_->stop();
|
||||||
game->start();
|
game_thread.join();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CoreInstance::quit()
|
||||||
|
{
|
||||||
|
// Stop the main loop
|
||||||
|
render_engine_->stop_render();
|
||||||
}
|
}
|
||||||
|
|
||||||
void* CoreInstance::getHandlerModule(const char* name) const
|
void* CoreInstance::getHandlerModule(const char* name) const
|
||||||
{
|
{
|
||||||
for (const auto& module : modules)
|
for (const auto& module : modules_)
|
||||||
{
|
{
|
||||||
if (std::strcmp(module.name, name) == 0)
|
if (std::strcmp(module.name, name) == 0)
|
||||||
return module.handler;
|
return module.handler;
|
||||||
@@ -113,25 +132,25 @@ void* CoreInstance::getHandlerModule(const char* name) const
|
|||||||
|
|
||||||
void* CoreInstance::enableModule(const char* name)
|
void* CoreInstance::enableModule(const char* name)
|
||||||
{
|
{
|
||||||
for (const auto& module : modules)
|
for (const auto& module : modules_)
|
||||||
{
|
{
|
||||||
if (std::strcmp(module.name, name) == 0)
|
if (std::strcmp(module.name, name) == 0)
|
||||||
throw std::runtime_error("Module already enabled");
|
throw std::runtime_error("Module already enabled");
|
||||||
}
|
}
|
||||||
|
|
||||||
void* module = System::InitModule(name, &callbacks_);
|
void* module = System::InitModule(name, &callbacks_);
|
||||||
modules.push_back({ name, module });
|
modules_.push_back({ name, module });
|
||||||
return module;
|
return module;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CoreInstance::disableModule(const char* name)
|
void CoreInstance::disableModule(const char* name)
|
||||||
{
|
{
|
||||||
for (auto i = modules.cbegin(); i != modules.cend(); ++i)
|
for (auto i = modules_.cbegin(); i != modules_.cend(); ++i)
|
||||||
{
|
{
|
||||||
if (std::strcmp(i->name, name) == 0)
|
if (std::strcmp(i->name, name) == 0)
|
||||||
{
|
{
|
||||||
System::QuitModule(i->handler);
|
System::QuitModule(i->handler);
|
||||||
modules.erase(i);
|
modules_.erase(i);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+24
-20
@@ -2,13 +2,18 @@
|
|||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <list>
|
#include <list>
|
||||||
|
#include <memory>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include "Game/GameInstance.h"
|
#include "Game/SaveMap/ISave.h"
|
||||||
#include "Game/SaveMap/SaveMap.h"
|
|
||||||
#include "Core/CoreCallBacks.h"
|
#include "Core/CoreCallBacks.h"
|
||||||
|
|
||||||
|
class SaveMap;
|
||||||
|
class RenderEngine;
|
||||||
|
class GameInstance;
|
||||||
|
struct GLFWwindow;
|
||||||
|
|
||||||
class CoreInstance {
|
class CoreInstance {
|
||||||
static CoreInstance* self;
|
|
||||||
struct Module {
|
struct Module {
|
||||||
const char* name;
|
const char* name;
|
||||||
void* handler;
|
void* handler;
|
||||||
@@ -21,21 +26,25 @@ class CoreInstance {
|
|||||||
std::vector<std::string> modules_names;
|
std::vector<std::string> modules_names;
|
||||||
|
|
||||||
double min_memory_size = -1;
|
double min_memory_size = -1;
|
||||||
int min_CPU_count = -1;
|
long long min_CPU_count = -1;
|
||||||
|
|
||||||
std::shared_ptr<SaveMap> save() override;
|
std::shared_ptr<SaveMap> save() override;
|
||||||
void load(std::shared_ptr<SaveMap> save) override;
|
void load(std::shared_ptr<SaveMap> save) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
const char* main_config_name = "main_config.conf";
|
const char* main_config_name = "main_config.conf";
|
||||||
MainConfig main_config;
|
MainConfig main_config_;
|
||||||
|
|
||||||
int countCPU;
|
int countCPU_;
|
||||||
// Memory in MB
|
// Memory in MB
|
||||||
double memorySize;
|
double memorySize_;
|
||||||
std::list<Module> modules;
|
std::list<Module> modules_;
|
||||||
|
|
||||||
GameInstance* game = nullptr;
|
GLFWwindow* window_ = nullptr;
|
||||||
|
RenderEngine* render_engine_;
|
||||||
|
GameInstance* game_;
|
||||||
|
|
||||||
|
static CoreInstance* self;
|
||||||
CoreCallBacks callbacks_;
|
CoreCallBacks callbacks_;
|
||||||
|
|
||||||
#pragma region Callbacks
|
#pragma region Callbacks
|
||||||
@@ -46,15 +55,13 @@ public:
|
|||||||
~CoreInstance();
|
~CoreInstance();
|
||||||
|
|
||||||
void start();
|
void start();
|
||||||
|
void quit();
|
||||||
/**
|
|
||||||
* This method quit game
|
int getCountCPU() const { return countCPU_; }
|
||||||
* Async
|
double getMemorySize() const { return memorySize_; }
|
||||||
*/
|
const std::string& getBaseWorldName() const { return main_config_.base_world; }
|
||||||
|
const std::string& getGameName() const { return main_config_.game_name; }
|
||||||
|
|
||||||
int getCountCPU() const { return countCPU; }
|
|
||||||
double getMemorySize() const { return memorySize; }
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @throws std::runtime_error if module isn't enabled
|
* @throws std::runtime_error if module isn't enabled
|
||||||
* @throws std::runtime_error if module not found
|
* @throws std::runtime_error if module not found
|
||||||
@@ -73,7 +80,4 @@ public:
|
|||||||
* @throws std::runtime_error module isn't contain QuitModule function
|
* @throws std::runtime_error module isn't contain QuitModule function
|
||||||
*/
|
*/
|
||||||
void disableModule(const char* name) noexcept(false);
|
void disableModule(const char* name) noexcept(false);
|
||||||
|
|
||||||
const std::string& getBaseWorldName() const { return main_config.base_world; }
|
|
||||||
const std::string& getGameName() const { return main_config.game_name; }
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,64 +0,0 @@
|
|||||||
#ifdef __linux__
|
|
||||||
|
|
||||||
#include "SystemCalls.h"
|
|
||||||
|
|
||||||
#include <sys/sysinfo.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <dlfcn.h>
|
|
||||||
|
|
||||||
#include <exception>
|
|
||||||
#include <stdexcept>
|
|
||||||
|
|
||||||
int System::getCountCPU()
|
|
||||||
{
|
|
||||||
int num_cores = sysconf(_SC_NPROCESSORS_ONLN);
|
|
||||||
if(num_cores <= 0)
|
|
||||||
throw std::runtime_error("Fail get number of cores");
|
|
||||||
|
|
||||||
return num_cores;
|
|
||||||
}
|
|
||||||
|
|
||||||
double System::getMemorySize()
|
|
||||||
{
|
|
||||||
struct sysinfo info{};
|
|
||||||
if(sysinfo(&info) == -1)
|
|
||||||
std::runtime_error("Fail get system info");
|
|
||||||
return info.totalram / 1024 / 1024;
|
|
||||||
}
|
|
||||||
|
|
||||||
void* System::InitModule(const char* ModuleName, CoreInstance& core)
|
|
||||||
{
|
|
||||||
std::string fileName = "./lib";
|
|
||||||
fileName += ModuleName;
|
|
||||||
fileName += ".so";
|
|
||||||
|
|
||||||
void* handler = dlopen(fileName.c_str(), RTLD_NOW);
|
|
||||||
if(handler == nullptr)
|
|
||||||
throw std::runtime_error("Module not found");
|
|
||||||
|
|
||||||
void(*init)(CoreInstance&) = reinterpret_cast<void(*)(CoreInstance&)>(dlsym(handler, "InitModule"));
|
|
||||||
if(init == nullptr)
|
|
||||||
throw std::runtime_error("Module not contains InitModule");
|
|
||||||
init(core);
|
|
||||||
|
|
||||||
return handler;
|
|
||||||
}
|
|
||||||
|
|
||||||
void System::StartModule(void* handler)
|
|
||||||
{
|
|
||||||
void(*start)() = reinterpret_cast<void(*)()>(dlsym(handler, "StartModule"));
|
|
||||||
if(start == nullptr)
|
|
||||||
throw std::runtime_error("Module not contins StartModule");
|
|
||||||
start();
|
|
||||||
}
|
|
||||||
|
|
||||||
void System::QuitModule(void* handler)
|
|
||||||
{
|
|
||||||
void(*quit)() = reinterpret_cast<void(*)()>(dlsym(handler, "QuitModule"));
|
|
||||||
if(quit == nullptr)
|
|
||||||
throw std::runtime_error("Module not contains QuitModule");
|
|
||||||
quit();
|
|
||||||
dlclose(handler);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -0,0 +1,994 @@
|
|||||||
|
#include "RenderEngine.h"
|
||||||
|
|
||||||
|
#include <queue>
|
||||||
|
#include <set>
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <fstream>
|
||||||
|
|
||||||
|
#include "CoreInstance.h"
|
||||||
|
#include "Log/Log.h"
|
||||||
|
|
||||||
|
#include "GLFW/glfw3.h"
|
||||||
|
|
||||||
|
const std::vector<const char*> RenderEngine::deviceExtensions = {
|
||||||
|
VK_KHR_SWAPCHAIN_EXTENSION_NAME
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef _DEBUG
|
||||||
|
static VKAPI_ATTR VkBool32 VKAPI_CALL debugCallback(
|
||||||
|
VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
|
||||||
|
VkDebugUtilsMessageTypeFlagsEXT messageType,
|
||||||
|
const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData,
|
||||||
|
void* pUserData) {
|
||||||
|
|
||||||
|
std::string msg = "validation layer: ";
|
||||||
|
msg += pCallbackData->pMessage;
|
||||||
|
Log(msg);
|
||||||
|
|
||||||
|
return VK_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
VkResult RenderEngine::enable_layer_validation(const VkDebugUtilsMessengerCreateInfoEXT* create_info)
|
||||||
|
{
|
||||||
|
PFN_vkCreateDebugUtilsMessengerEXT debug_creator = reinterpret_cast<PFN_vkCreateDebugUtilsMessengerEXT>(vkGetInstanceProcAddr(instance_, "vkCreateDebugUtilsMessengerEXT"));
|
||||||
|
return debug_creator(instance_, create_info, nullptr, &debug_messenger_);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
RenderEngine::SwapchainSupportDetails RenderEngine::query_swapchain_details() const
|
||||||
|
{
|
||||||
|
SwapchainSupportDetails details;
|
||||||
|
|
||||||
|
vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physical_device_, surface_, &details.capabilities);
|
||||||
|
|
||||||
|
uint32_t surface_format_cnt = 0;
|
||||||
|
VK_CHECK(vkGetPhysicalDeviceSurfaceFormatsKHR(physical_device_, surface_, &surface_format_cnt, nullptr));
|
||||||
|
details.formats.resize(surface_format_cnt);
|
||||||
|
VK_CHECK(vkGetPhysicalDeviceSurfaceFormatsKHR(physical_device_, surface_, &surface_format_cnt, details.formats.data()));
|
||||||
|
|
||||||
|
uint32_t present_modes_cnt = 0;
|
||||||
|
VK_CHECK(vkGetPhysicalDeviceSurfacePresentModesKHR(physical_device_, surface_, &present_modes_cnt, nullptr));
|
||||||
|
details.present_modes.resize(surface_format_cnt);
|
||||||
|
VK_CHECK(vkGetPhysicalDeviceSurfacePresentModesKHR(physical_device_, surface_, &present_modes_cnt, details.present_modes.data()));
|
||||||
|
|
||||||
|
return details;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<const char*> RenderEngine::get_required_extensions()
|
||||||
|
{
|
||||||
|
uint32_t extensions_count = 0;
|
||||||
|
const char** glfw_extension = glfwGetRequiredInstanceExtensions(&extensions_count);
|
||||||
|
std::vector<const char*> extensions(glfw_extension, glfw_extension + extensions_count);
|
||||||
|
|
||||||
|
#ifdef _DEBUG
|
||||||
|
extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
|
||||||
|
#endif
|
||||||
|
return extensions;
|
||||||
|
}
|
||||||
|
|
||||||
|
VkVertexInputBindingDescription RenderEngine::Vertex::get_binding_description()
|
||||||
|
{
|
||||||
|
VkVertexInputBindingDescription description;
|
||||||
|
description.binding = 0;
|
||||||
|
description.stride = sizeof(Vertex);
|
||||||
|
description.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
|
||||||
|
return description;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::array<VkVertexInputAttributeDescription, 2> RenderEngine::Vertex::get_vertex_attribute_descriptions()
|
||||||
|
{
|
||||||
|
std::array<VkVertexInputAttributeDescription, 2> descriptions;
|
||||||
|
descriptions[0].binding = 0;
|
||||||
|
descriptions[0].location = 0;
|
||||||
|
descriptions[0].format = VK_FORMAT_R32G32_SFLOAT;
|
||||||
|
descriptions[0].offset = offsetof(Vertex, pos);
|
||||||
|
descriptions[1].binding = 0;
|
||||||
|
descriptions[1].location = 1;
|
||||||
|
descriptions[1].format = VK_FORMAT_R32G32B32_SFLOAT;
|
||||||
|
descriptions[1].offset = offsetof(Vertex, color);
|
||||||
|
|
||||||
|
return descriptions;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RenderEngine::is_device_suitable(VkPhysicalDevice device, VkSurfaceKHR surface)
|
||||||
|
{
|
||||||
|
VkPhysicalDeviceProperties device_properties;
|
||||||
|
VkPhysicalDeviceFeatures device_features;
|
||||||
|
vkGetPhysicalDeviceProperties(device, &device_properties);
|
||||||
|
vkGetPhysicalDeviceFeatures(device, &device_features);
|
||||||
|
|
||||||
|
try {
|
||||||
|
QueueFamilyIndices indices = find_queue_family_indices(device, surface);
|
||||||
|
} catch (...) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return check_device_extensions_support(device);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RenderEngine::check_device_extensions_support(VkPhysicalDevice device)
|
||||||
|
{
|
||||||
|
uint32_t extension_count;
|
||||||
|
VK_CHECK(vkEnumerateDeviceExtensionProperties(device, nullptr, &extension_count, nullptr));
|
||||||
|
std::vector<VkExtensionProperties> available_extensions(extension_count);
|
||||||
|
VK_CHECK(vkEnumerateDeviceExtensionProperties(device, nullptr, &extension_count, available_extensions.data()));
|
||||||
|
|
||||||
|
for (const auto& extension : deviceExtensions)
|
||||||
|
{
|
||||||
|
bool isFind = false;
|
||||||
|
for (const auto& i : available_extensions)
|
||||||
|
{
|
||||||
|
if (std::strcmp(i.extensionName, extension) == 0)
|
||||||
|
{
|
||||||
|
isFind = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!isFind)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
RenderEngine::QueueFamilyIndices RenderEngine::find_queue_family_indices(VkPhysicalDevice physical_device, VkSurfaceKHR surface)
|
||||||
|
{
|
||||||
|
QueueFamilyIndices queue_family_indices;
|
||||||
|
|
||||||
|
uint32_t queueFamilyCount = 0;
|
||||||
|
vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &queueFamilyCount, nullptr);
|
||||||
|
std::vector<VkQueueFamilyProperties> family_properties(queueFamilyCount);
|
||||||
|
vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &queueFamilyCount, family_properties.data());
|
||||||
|
|
||||||
|
// Find graphics
|
||||||
|
for(uint32_t i = 0; i < family_properties.size(); ++i)
|
||||||
|
{
|
||||||
|
if (family_properties[i].queueFlags & VK_QUEUE_GRAPHICS_BIT)
|
||||||
|
{
|
||||||
|
queue_family_indices.graphics_family = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (queue_family_indices.graphics_family.has_value() == false)
|
||||||
|
throw std::runtime_error("Failed to find a graphics queue family");
|
||||||
|
|
||||||
|
// Find present
|
||||||
|
VkBool32 present_support = false;
|
||||||
|
VK_CHECK(vkGetPhysicalDeviceSurfaceSupportKHR(physical_device, queue_family_indices.graphics_family.value(), surface, &present_support));
|
||||||
|
if (present_support == VK_TRUE)
|
||||||
|
queue_family_indices.present_family = queue_family_indices.graphics_family;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for(uint32_t i = 0; i < family_properties.size(); ++i)
|
||||||
|
{
|
||||||
|
present_support = false;
|
||||||
|
VK_CHECK(vkGetPhysicalDeviceSurfaceSupportKHR(physical_device, i, surface, &present_support));
|
||||||
|
if (present_support == VK_TRUE)
|
||||||
|
{
|
||||||
|
queue_family_indices.present_family = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (queue_family_indices.present_family.has_value() == false)
|
||||||
|
throw std::runtime_error("Failed to find a present queue family");
|
||||||
|
|
||||||
|
for(uint32_t i = 0; i < family_properties.size(); ++i)
|
||||||
|
{
|
||||||
|
if (i == queue_family_indices.graphics_family.value())
|
||||||
|
continue;
|
||||||
|
if (family_properties[i].queueFlags & VK_QUEUE_TRANSFER_BIT)
|
||||||
|
queue_family_indices.transfer_family = i;
|
||||||
|
}
|
||||||
|
if (queue_family_indices.transfer_family.has_value() == false)
|
||||||
|
queue_family_indices.transfer_family = queue_family_indices.graphics_family;
|
||||||
|
return queue_family_indices;
|
||||||
|
}
|
||||||
|
|
||||||
|
VkSurfaceFormatKHR RenderEngine::choose_surface_format(const std::vector<VkSurfaceFormatKHR>& surface_formats)
|
||||||
|
{
|
||||||
|
for (const auto& i : surface_formats)
|
||||||
|
{
|
||||||
|
if (i.format == VK_FORMAT_B8G8R8A8_SRGB && i.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR)
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
return surface_formats[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
VkPresentModeKHR RenderEngine::choose_present_mode(const std::vector<VkPresentModeKHR>& present_modes, VkPresentModeKHR desired_present_mode)
|
||||||
|
{
|
||||||
|
for (const auto& i : present_modes)
|
||||||
|
{
|
||||||
|
if (i == desired_present_mode)
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
return VK_PRESENT_MODE_FIFO_KHR;
|
||||||
|
}
|
||||||
|
|
||||||
|
VkExtent2D RenderEngine::choose_extent(const VkSurfaceCapabilitiesKHR& capabilities, GLFWwindow* window)
|
||||||
|
{
|
||||||
|
if (capabilities.currentExtent.width != std::numeric_limits<uint32_t>::max())
|
||||||
|
return capabilities.currentExtent;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int width, height;
|
||||||
|
glfwGetFramebufferSize(window, &width, &height);
|
||||||
|
VkExtent2D actualExtent = {
|
||||||
|
static_cast<uint32_t>(width),
|
||||||
|
static_cast<uint32_t>(height)
|
||||||
|
};
|
||||||
|
actualExtent.width = std::max(capabilities.minImageExtent.width, std::min(capabilities.maxImageExtent.width, actualExtent.width));
|
||||||
|
return actualExtent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
VkShaderModule RenderEngine::create_shader_module(const std::string& code) const
|
||||||
|
{
|
||||||
|
VkShaderModuleCreateInfo shader_module_info{};
|
||||||
|
shader_module_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
|
||||||
|
shader_module_info.codeSize = code.size();
|
||||||
|
shader_module_info.pCode = reinterpret_cast<const uint32_t*>(code.c_str());
|
||||||
|
|
||||||
|
VkShaderModule shader_module;
|
||||||
|
VK_CHECK(vkCreateShaderModule(device_, &shader_module_info, nullptr, &shader_module));
|
||||||
|
return shader_module;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderEngine::create_buffer(VkDeviceSize size, VkBufferUsageFlags usage,
|
||||||
|
VkBuffer* buffer, const std::vector<uint32_t>& queue_families)
|
||||||
|
{
|
||||||
|
VkBufferCreateInfo buffer_info{};
|
||||||
|
buffer_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
|
||||||
|
buffer_info.size = size;
|
||||||
|
buffer_info.usage = usage;
|
||||||
|
|
||||||
|
if (queue_families.size() > 1)
|
||||||
|
{
|
||||||
|
buffer_info.sharingMode = VK_SHARING_MODE_CONCURRENT;
|
||||||
|
buffer_info.queueFamilyIndexCount = static_cast<uint32_t>(queue_families.size());
|
||||||
|
buffer_info.pQueueFamilyIndices = queue_families.data();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
buffer_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||||||
|
buffer_info.queueFamilyIndexCount = 0;
|
||||||
|
buffer_info.pQueueFamilyIndices = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
VK_CHECK(vkCreateBuffer(device_, &buffer_info, nullptr, buffer));
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderEngine::allocate_memory(VkBuffer buffer, VkMemoryPropertyFlags property, VkDeviceMemory* device_memory)
|
||||||
|
{
|
||||||
|
VkMemoryRequirements requirements{};
|
||||||
|
vkGetBufferMemoryRequirements(device_, buffer, &requirements);
|
||||||
|
|
||||||
|
VkMemoryAllocateInfo allocate_info{};
|
||||||
|
allocate_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
|
||||||
|
allocate_info.allocationSize = requirements.size;
|
||||||
|
allocate_info.memoryTypeIndex = find_memory_type(requirements.memoryTypeBits, property);
|
||||||
|
|
||||||
|
VK_CHECK(vkAllocateMemory(device_, &allocate_info, nullptr, device_memory));
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderEngine::create_instance()
|
||||||
|
{
|
||||||
|
std::vector<const char*> extensions = get_required_extensions();
|
||||||
|
|
||||||
|
VkApplicationInfo app_info{};
|
||||||
|
app_info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
|
||||||
|
app_info.apiVersion = VK_API_VERSION_1_0;
|
||||||
|
app_info.applicationVersion = VK_MAKE_VERSION(0, 0, 0);
|
||||||
|
app_info.pApplicationName = core_.getGameName().c_str();
|
||||||
|
app_info.pEngineName = "UwU Engine";
|
||||||
|
app_info.engineVersion = VK_MAKE_VERSION(0, 0, 0);
|
||||||
|
|
||||||
|
|
||||||
|
VkInstanceCreateInfo instance_create_info{};
|
||||||
|
instance_create_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
|
||||||
|
instance_create_info.pApplicationInfo = &app_info;
|
||||||
|
instance_create_info.enabledExtensionCount = static_cast<uint32_t>(extensions.size());
|
||||||
|
instance_create_info.ppEnabledExtensionNames = extensions.data();
|
||||||
|
#ifdef _DEBUG
|
||||||
|
const std::vector<const char*> layers_validation = {
|
||||||
|
"VK_LAYER_KHRONOS_validation"
|
||||||
|
};
|
||||||
|
instance_create_info.enabledLayerCount = static_cast<uint32_t>(layers_validation.size());
|
||||||
|
instance_create_info.ppEnabledLayerNames = layers_validation.data();
|
||||||
|
VkDebugUtilsMessengerCreateInfoEXT debug_messenger_create_info{};
|
||||||
|
debug_messenger_create_info.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT;
|
||||||
|
debug_messenger_create_info.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;
|
||||||
|
debug_messenger_create_info.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;
|
||||||
|
debug_messenger_create_info.pfnUserCallback = &debugCallback;
|
||||||
|
instance_create_info.pNext = &debug_messenger_create_info;
|
||||||
|
#endif
|
||||||
|
VK_CHECK(vkCreateInstance(&instance_create_info, nullptr, &instance_));
|
||||||
|
#ifdef _DEBUG
|
||||||
|
VK_CHECK(enable_layer_validation(&debug_messenger_create_info));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderEngine::pick_physical_device()
|
||||||
|
{
|
||||||
|
uint32_t device_count = 0;
|
||||||
|
std::vector<VkPhysicalDevice> devices;
|
||||||
|
VK_CHECK(vkEnumeratePhysicalDevices(instance_, &device_count, nullptr));
|
||||||
|
devices.resize(device_count);
|
||||||
|
VK_CHECK(vkEnumeratePhysicalDevices(instance_, &device_count, devices.data()));
|
||||||
|
|
||||||
|
for (const auto& device : devices)
|
||||||
|
{
|
||||||
|
if (is_device_suitable(device, surface_))
|
||||||
|
{
|
||||||
|
physical_device_ = device;
|
||||||
|
VkPhysicalDeviceProperties device_properties;
|
||||||
|
vkGetPhysicalDeviceProperties(physical_device_, &device_properties);
|
||||||
|
Log("Using device: " + std::string(device_properties.deviceName));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (VK_NULL_HANDLE == physical_device_)
|
||||||
|
throw std::runtime_error("No suitable device found");
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderEngine::create_logical_device()
|
||||||
|
{
|
||||||
|
QueueFamilyIndices indices = find_queue_family_indices(physical_device_, surface_);
|
||||||
|
|
||||||
|
VkPhysicalDeviceFeatures device_features{};
|
||||||
|
|
||||||
|
std::vector<VkDeviceQueueCreateInfo> queue_create_infos;
|
||||||
|
std::set<uint32_t> unique_queue_families = {indices.graphics_family.value(),
|
||||||
|
indices.present_family.value(),
|
||||||
|
indices.transfer_family.value()};
|
||||||
|
|
||||||
|
float queue_priority = 1.0f;
|
||||||
|
VkDeviceQueueCreateInfo device_queue_create_info{};
|
||||||
|
device_queue_create_info.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
|
||||||
|
device_queue_create_info.pQueuePriorities = &queue_priority;
|
||||||
|
for (auto queue_family : unique_queue_families)
|
||||||
|
{
|
||||||
|
device_queue_create_info.queueFamilyIndex = queue_family;
|
||||||
|
device_queue_create_info.queueCount = 1;
|
||||||
|
queue_create_infos.push_back(device_queue_create_info);
|
||||||
|
}
|
||||||
|
|
||||||
|
VkDeviceCreateInfo device_create_info{};
|
||||||
|
device_create_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
|
||||||
|
device_create_info.queueCreateInfoCount = static_cast<uint32_t>(unique_queue_families.size());
|
||||||
|
device_create_info.pQueueCreateInfos = queue_create_infos.data();
|
||||||
|
device_create_info.pEnabledFeatures = &device_features;
|
||||||
|
device_create_info.enabledExtensionCount = static_cast<uint32_t>(deviceExtensions.size());
|
||||||
|
device_create_info.ppEnabledExtensionNames = deviceExtensions.data();
|
||||||
|
|
||||||
|
#ifdef _DEBUG
|
||||||
|
const std::vector<const char*> layers_validation = {
|
||||||
|
"VK_LAYER_KHRONOS_validation"
|
||||||
|
};
|
||||||
|
device_create_info.enabledLayerCount = static_cast<uint32_t>(layers_validation.size());
|
||||||
|
device_create_info.ppEnabledLayerNames = layers_validation.data();
|
||||||
|
#else
|
||||||
|
device_create_info.enabledLayerCount = 0;
|
||||||
|
device_create_info.ppEnabledLayerNames = nullptr;
|
||||||
|
|
||||||
|
#endif
|
||||||
|
VK_CHECK(vkCreateDevice(physical_device_, &device_create_info, nullptr, &device_));
|
||||||
|
vkGetDeviceQueue(device_, indices.graphics_family.value(), 0, &graphics_queue_);
|
||||||
|
vkGetDeviceQueue(device_, indices.present_family.value(), 0, &present_queue_);
|
||||||
|
vkGetDeviceQueue(device_, indices.transfer_family.value(), 0, &transfer_queue_);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderEngine::create_swapchain(VkPresentModeKHR desired_present_mode)
|
||||||
|
{
|
||||||
|
SwapchainSupportDetails swapchain_support = query_swapchain_details();
|
||||||
|
VkSurfaceFormatKHR surface_format = choose_surface_format(swapchain_support.formats);
|
||||||
|
VkPresentModeKHR present_mode = choose_present_mode(swapchain_support.present_modes, desired_present_mode);
|
||||||
|
VkExtent2D extent = choose_extent(swapchain_support.capabilities, window_);
|
||||||
|
|
||||||
|
uint32_t image_count = swapchain_support.capabilities.minImageCount + 1;
|
||||||
|
if (swapchain_support.capabilities.maxImageCount > 0 && image_count > swapchain_support.capabilities.maxImageCount)
|
||||||
|
image_count = swapchain_support.capabilities.maxImageCount;
|
||||||
|
|
||||||
|
VkSwapchainCreateInfoKHR swapchain_create_info{};
|
||||||
|
swapchain_create_info.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
|
||||||
|
swapchain_create_info.surface = surface_;
|
||||||
|
swapchain_create_info.minImageCount = image_count;
|
||||||
|
swapchain_create_info.imageFormat = surface_format.format;
|
||||||
|
swapchain_create_info.imageColorSpace = surface_format.colorSpace;
|
||||||
|
swapchain_create_info.imageExtent = extent;
|
||||||
|
swapchain_create_info.imageArrayLayers = 1;
|
||||||
|
swapchain_create_info.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
|
||||||
|
swapchain_create_info.preTransform = swapchain_support.capabilities.currentTransform;
|
||||||
|
swapchain_create_info.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
|
||||||
|
swapchain_create_info.presentMode = present_mode;
|
||||||
|
swapchain_create_info.clipped = VK_TRUE;
|
||||||
|
swapchain_create_info.oldSwapchain = VK_NULL_HANDLE;
|
||||||
|
|
||||||
|
QueueFamilyIndices family_indices = find_queue_family_indices(physical_device_, surface_);
|
||||||
|
const std::set<uint32_t> queue_family_indices = { family_indices.graphics_family.value(),
|
||||||
|
family_indices.present_family.value(),
|
||||||
|
family_indices.transfer_family.value() };
|
||||||
|
std::vector<uint32_t> arr_families;
|
||||||
|
if (queue_family_indices.size() > 1)
|
||||||
|
{
|
||||||
|
arr_families.reserve(queue_family_indices.size());
|
||||||
|
for(auto& i : queue_family_indices)
|
||||||
|
arr_families.push_back(i);
|
||||||
|
|
||||||
|
|
||||||
|
swapchain_create_info.imageSharingMode = VK_SHARING_MODE_CONCURRENT;
|
||||||
|
swapchain_create_info.queueFamilyIndexCount = static_cast<uint32_t>(arr_families.size());
|
||||||
|
swapchain_create_info.pQueueFamilyIndices = arr_families.data();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
swapchain_create_info.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||||||
|
swapchain_create_info.queueFamilyIndexCount = 0;
|
||||||
|
swapchain_create_info.pQueueFamilyIndices = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
VK_CHECK(vkCreateSwapchainKHR(device_, &swapchain_create_info, nullptr, &swapchain_));
|
||||||
|
|
||||||
|
vkGetSwapchainImagesKHR(device_, swapchain_, &image_count, nullptr);
|
||||||
|
swapchain_images_.resize(image_count);
|
||||||
|
vkGetSwapchainImagesKHR(device_, swapchain_, &image_count, swapchain_images_.data());
|
||||||
|
|
||||||
|
swapchain_image_format_ = surface_format.format;
|
||||||
|
swapchain_extent_ = extent;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderEngine::create_image_views()
|
||||||
|
{
|
||||||
|
VkImageViewCreateInfo image_view_info{};
|
||||||
|
image_view_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
|
||||||
|
image_view_info.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
||||||
|
image_view_info.format = swapchain_image_format_;
|
||||||
|
image_view_info.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;
|
||||||
|
image_view_info.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;
|
||||||
|
image_view_info.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;
|
||||||
|
image_view_info.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;
|
||||||
|
image_view_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||||
|
image_view_info.subresourceRange.baseMipLevel = 0;
|
||||||
|
image_view_info.subresourceRange.levelCount = 1;
|
||||||
|
image_view_info.subresourceRange.baseArrayLayer = 0;
|
||||||
|
image_view_info.subresourceRange.layerCount = 1;
|
||||||
|
|
||||||
|
swapchain_image_views_.resize(swapchain_images_.size());
|
||||||
|
for (uint32_t i = 0; i < swapchain_images_.size(); ++i)
|
||||||
|
{
|
||||||
|
image_view_info.image = swapchain_images_[i];
|
||||||
|
VK_CHECK(vkCreateImageView(device_, &image_view_info, nullptr, &swapchain_image_views_[i]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderEngine::create_render_pass()
|
||||||
|
{
|
||||||
|
VkAttachmentDescription attachment_description{};
|
||||||
|
attachment_description.format = swapchain_image_format_;
|
||||||
|
attachment_description.samples = VK_SAMPLE_COUNT_1_BIT;
|
||||||
|
attachment_description.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
|
||||||
|
attachment_description.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
|
||||||
|
attachment_description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
|
||||||
|
attachment_description.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
|
||||||
|
attachment_description.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||||
|
attachment_description.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
|
||||||
|
|
||||||
|
VkAttachmentReference attachment_reference;
|
||||||
|
attachment_reference.attachment = 0;
|
||||||
|
attachment_reference.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||||
|
|
||||||
|
VkSubpassDescription subpass_description{};
|
||||||
|
subpass_description.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
|
||||||
|
subpass_description.colorAttachmentCount = 1;
|
||||||
|
subpass_description.pColorAttachments = &attachment_reference;
|
||||||
|
|
||||||
|
VkSubpassDependency dependency{};
|
||||||
|
dependency.srcSubpass = VK_SUBPASS_EXTERNAL;
|
||||||
|
dependency.dstSubpass = 0;
|
||||||
|
dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
|
||||||
|
dependency.srcAccessMask = 0;
|
||||||
|
dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
|
||||||
|
dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
|
||||||
|
|
||||||
|
VkRenderPassCreateInfo render_pass_info{};
|
||||||
|
render_pass_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
|
||||||
|
render_pass_info.attachmentCount = 1;
|
||||||
|
render_pass_info.pAttachments = &attachment_description;
|
||||||
|
render_pass_info.subpassCount = 1;
|
||||||
|
render_pass_info.pSubpasses = &subpass_description;
|
||||||
|
render_pass_info.dependencyCount = 1;
|
||||||
|
render_pass_info.pDependencies = &dependency;
|
||||||
|
|
||||||
|
VK_CHECK(vkCreateRenderPass(device_, &render_pass_info, nullptr, &render_pass_));
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderEngine::create_graphics_pipeline()
|
||||||
|
{
|
||||||
|
std::ifstream vertex_shader_file("Shaders/vertex.spv", std::ios::binary);
|
||||||
|
if (!vertex_shader_file.is_open())
|
||||||
|
throw std::runtime_error("Vertex shader not found");
|
||||||
|
std::ifstream fragment_shader_file("Shaders/fragment.spv", std::ios::binary);
|
||||||
|
if (!fragment_shader_file.is_open()) {
|
||||||
|
vertex_shader_file.close();
|
||||||
|
throw std::runtime_error("Fragment shader not found");
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string vertex_shader_code((std::istreambuf_iterator<char>(vertex_shader_file)), std::istreambuf_iterator<char>());
|
||||||
|
std::string fragment_shader_code((std::istreambuf_iterator<char>(fragment_shader_file)), std::istreambuf_iterator<char>());
|
||||||
|
vertex_shader_file.close();
|
||||||
|
fragment_shader_file.close();
|
||||||
|
|
||||||
|
VkShaderModule vertex_shader = create_shader_module(vertex_shader_code);
|
||||||
|
VkShaderModule fragment_shader = create_shader_module(fragment_shader_code);
|
||||||
|
|
||||||
|
VkPipelineShaderStageCreateInfo vertex_shader_stage_info{};
|
||||||
|
vertex_shader_stage_info.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
|
||||||
|
vertex_shader_stage_info.stage = VK_SHADER_STAGE_VERTEX_BIT;
|
||||||
|
vertex_shader_stage_info.module = vertex_shader;
|
||||||
|
vertex_shader_stage_info.pName = "main";
|
||||||
|
|
||||||
|
VkPipelineShaderStageCreateInfo fragment_shader_stage_info{};
|
||||||
|
fragment_shader_stage_info.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
|
||||||
|
fragment_shader_stage_info.stage = VK_SHADER_STAGE_FRAGMENT_BIT;
|
||||||
|
fragment_shader_stage_info.module = fragment_shader;
|
||||||
|
fragment_shader_stage_info.pName = "main";
|
||||||
|
|
||||||
|
VkPipelineShaderStageCreateInfo shader_stages[] = {vertex_shader_stage_info, fragment_shader_stage_info};
|
||||||
|
const std::vector<VkDynamicState> dynamic_states = {
|
||||||
|
VK_DYNAMIC_STATE_VIEWPORT,
|
||||||
|
VK_DYNAMIC_STATE_SCISSOR
|
||||||
|
};
|
||||||
|
|
||||||
|
VkPipelineDynamicStateCreateInfo dynamic_state_info{};
|
||||||
|
dynamic_state_info.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
|
||||||
|
dynamic_state_info.dynamicStateCount = static_cast<uint32_t>(dynamic_states.size());
|
||||||
|
dynamic_state_info.pDynamicStates = dynamic_states.data();
|
||||||
|
|
||||||
|
VkVertexInputBindingDescription binding_description = Vertex::get_binding_description();
|
||||||
|
std::array<VkVertexInputAttributeDescription, 2> attribute_descriptions = Vertex::get_vertex_attribute_descriptions();
|
||||||
|
|
||||||
|
VkPipelineVertexInputStateCreateInfo vertex_input_info{};
|
||||||
|
vertex_input_info.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
|
||||||
|
vertex_input_info.vertexBindingDescriptionCount = 1;
|
||||||
|
vertex_input_info.pVertexBindingDescriptions = &binding_description;
|
||||||
|
vertex_input_info.vertexAttributeDescriptionCount = static_cast<uint32_t>(attribute_descriptions.size());
|
||||||
|
vertex_input_info.pVertexAttributeDescriptions = attribute_descriptions.data();
|
||||||
|
|
||||||
|
VkPipelineInputAssemblyStateCreateInfo input_assembly_info{};
|
||||||
|
input_assembly_info.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
|
||||||
|
input_assembly_info.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
|
||||||
|
input_assembly_info.primitiveRestartEnable = VK_FALSE;
|
||||||
|
|
||||||
|
VkViewport viewport{};
|
||||||
|
viewport.x = 0.0f;
|
||||||
|
viewport.y = 0.0f;
|
||||||
|
viewport.width = static_cast<float>(swapchain_extent_.width);
|
||||||
|
viewport.height = static_cast<float>(swapchain_extent_.height);
|
||||||
|
viewport.minDepth = 0.0f;
|
||||||
|
viewport.maxDepth = 1.0f;
|
||||||
|
|
||||||
|
VkRect2D scissor{};
|
||||||
|
scissor.offset = {0, 0};
|
||||||
|
scissor.extent = swapchain_extent_;
|
||||||
|
|
||||||
|
VkPipelineViewportStateCreateInfo viewport_info{};
|
||||||
|
viewport_info.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
|
||||||
|
viewport_info.viewportCount = 1;
|
||||||
|
viewport_info.pViewports = &viewport;
|
||||||
|
viewport_info.scissorCount = 1;
|
||||||
|
viewport_info.pScissors = &scissor;
|
||||||
|
|
||||||
|
VkPipelineRasterizationStateCreateInfo rasterization_info{};
|
||||||
|
rasterization_info.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
|
||||||
|
rasterization_info.depthClampEnable = VK_FALSE;
|
||||||
|
rasterization_info.rasterizerDiscardEnable = VK_FALSE;
|
||||||
|
rasterization_info.polygonMode = VK_POLYGON_MODE_FILL;
|
||||||
|
rasterization_info.lineWidth = 1.0f;
|
||||||
|
rasterization_info.cullMode = VK_CULL_MODE_BACK_BIT;
|
||||||
|
rasterization_info.frontFace = VK_FRONT_FACE_CLOCKWISE;
|
||||||
|
rasterization_info.depthBiasEnable = VK_FALSE;
|
||||||
|
|
||||||
|
VkPipelineMultisampleStateCreateInfo multisample_info{};
|
||||||
|
multisample_info.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
|
||||||
|
multisample_info.sampleShadingEnable = VK_FALSE;
|
||||||
|
multisample_info.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
|
||||||
|
|
||||||
|
VkPipelineColorBlendAttachmentState color_blend_attachment_state{};
|
||||||
|
color_blend_attachment_state.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
|
||||||
|
color_blend_attachment_state.blendEnable = VK_TRUE;
|
||||||
|
color_blend_attachment_state.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA;
|
||||||
|
color_blend_attachment_state.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
|
||||||
|
color_blend_attachment_state.colorBlendOp = VK_BLEND_OP_ADD;
|
||||||
|
color_blend_attachment_state.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE;
|
||||||
|
color_blend_attachment_state.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO;
|
||||||
|
color_blend_attachment_state.alphaBlendOp = VK_BLEND_OP_ADD;
|
||||||
|
|
||||||
|
VkPipelineColorBlendStateCreateInfo color_blend_info{};
|
||||||
|
color_blend_info.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
|
||||||
|
color_blend_info.logicOpEnable = VK_FALSE;
|
||||||
|
color_blend_info.attachmentCount = 1;
|
||||||
|
color_blend_info.pAttachments = &color_blend_attachment_state;
|
||||||
|
color_blend_info.blendConstants[0] = 0.0f;
|
||||||
|
color_blend_info.blendConstants[1] = 0.0f;
|
||||||
|
color_blend_info.blendConstants[2] = 0.0f;
|
||||||
|
color_blend_info.blendConstants[3] = 0.0f;
|
||||||
|
|
||||||
|
VkPipelineLayoutCreateInfo pipeline_layout_info{};
|
||||||
|
pipeline_layout_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
|
||||||
|
|
||||||
|
VK_CHECK(vkCreatePipelineLayout(device_, &pipeline_layout_info, nullptr, &pipeline_layout_));
|
||||||
|
|
||||||
|
VkGraphicsPipelineCreateInfo graphics_pipeline_info{};
|
||||||
|
graphics_pipeline_info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
|
||||||
|
graphics_pipeline_info.stageCount = 2;
|
||||||
|
graphics_pipeline_info.pStages = shader_stages;
|
||||||
|
graphics_pipeline_info.layout = pipeline_layout_;
|
||||||
|
graphics_pipeline_info.pColorBlendState = &color_blend_info;
|
||||||
|
graphics_pipeline_info.pDynamicState = &dynamic_state_info;
|
||||||
|
graphics_pipeline_info.pInputAssemblyState = &input_assembly_info;
|
||||||
|
graphics_pipeline_info.pMultisampleState = &multisample_info;
|
||||||
|
graphics_pipeline_info.pRasterizationState = &rasterization_info;
|
||||||
|
graphics_pipeline_info.pViewportState = &viewport_info;
|
||||||
|
graphics_pipeline_info.pVertexInputState = &vertex_input_info;
|
||||||
|
graphics_pipeline_info.pDepthStencilState = nullptr;
|
||||||
|
graphics_pipeline_info.renderPass = render_pass_;
|
||||||
|
graphics_pipeline_info.subpass = 0;
|
||||||
|
graphics_pipeline_info.basePipelineHandle = nullptr;
|
||||||
|
graphics_pipeline_info.basePipelineIndex = -1;
|
||||||
|
|
||||||
|
VK_CHECK(vkCreateGraphicsPipelines(device_, nullptr, 1, &graphics_pipeline_info, nullptr, &graphics_pipeline_));
|
||||||
|
|
||||||
|
vkDestroyShaderModule(device_, vertex_shader, nullptr);
|
||||||
|
vkDestroyShaderModule(device_, fragment_shader, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderEngine::create_framebuffers()
|
||||||
|
{
|
||||||
|
framebuffers_.resize(swapchain_images_.size());
|
||||||
|
|
||||||
|
VkFramebufferCreateInfo framebuffer_info{};
|
||||||
|
framebuffer_info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
|
||||||
|
framebuffer_info.renderPass = render_pass_;
|
||||||
|
framebuffer_info.attachmentCount = 1;
|
||||||
|
framebuffer_info.width = swapchain_extent_.width;
|
||||||
|
framebuffer_info.height = swapchain_extent_.height;
|
||||||
|
framebuffer_info.layers = 1;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < framebuffers_.size(); ++i)
|
||||||
|
{
|
||||||
|
framebuffer_info.pAttachments = &swapchain_image_views_[i];
|
||||||
|
VK_CHECK(vkCreateFramebuffer(device_, &framebuffer_info, nullptr, &framebuffers_[i]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderEngine::create_command_pool()
|
||||||
|
{
|
||||||
|
QueueFamilyIndices queue_family_indices = find_queue_family_indices(physical_device_, surface_);
|
||||||
|
|
||||||
|
VkCommandPoolCreateInfo command_pool_info{};
|
||||||
|
command_pool_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
|
||||||
|
command_pool_info.queueFamilyIndex = queue_family_indices.graphics_family.value();
|
||||||
|
command_pool_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
|
||||||
|
|
||||||
|
VK_CHECK(vkCreateCommandPool(device_, &command_pool_info, nullptr, &command_pool_));
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t RenderEngine::find_memory_type(uint32_t typeFilter, VkMemoryPropertyFlags properties) const
|
||||||
|
{
|
||||||
|
VkPhysicalDeviceMemoryProperties memory_properties{};
|
||||||
|
vkGetPhysicalDeviceMemoryProperties(physical_device_, &memory_properties);
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < memory_properties.memoryTypeCount; ++i)
|
||||||
|
{
|
||||||
|
if (typeFilter & (1 << i) && (memory_properties.memoryTypes[i].propertyFlags & properties) == properties)
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw std::runtime_error("failed to find suitable memory type!");
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderEngine::allocate_vertex_buffer()
|
||||||
|
{
|
||||||
|
QueueFamilyIndices indices = find_queue_family_indices(physical_device_, surface_);
|
||||||
|
std::set<uint32_t> set_indices = {indices.graphics_family.value(),
|
||||||
|
indices.present_family.value(),
|
||||||
|
indices.transfer_family.value()};
|
||||||
|
std::vector<uint32_t> arr_indices;
|
||||||
|
std::vector<uint32_t> transfer_index = {indices.transfer_family.value()};
|
||||||
|
arr_indices.reserve(set_indices.size());
|
||||||
|
for (auto& i : set_indices)
|
||||||
|
arr_indices.push_back(i);
|
||||||
|
|
||||||
|
|
||||||
|
VkBuffer staging_buffer = VK_NULL_HANDLE;
|
||||||
|
VkDeviceMemory staging_buffer_memory = VK_NULL_HANDLE;
|
||||||
|
|
||||||
|
VkDeviceSize size_buffer = sizeof(vertices[0]) * vertices.size();
|
||||||
|
create_buffer(size_buffer, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, &staging_buffer, transfer_index);
|
||||||
|
allocate_memory(staging_buffer, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, &staging_buffer_memory);
|
||||||
|
|
||||||
|
create_buffer(size_buffer, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, &vertex_buffer_, arr_indices);
|
||||||
|
allocate_memory(vertex_buffer_, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &vertex_buffer_memory_);
|
||||||
|
|
||||||
|
VK_CHECK(vkBindBufferMemory(device_, staging_buffer, staging_buffer_memory, 0));
|
||||||
|
VK_CHECK(vkBindBufferMemory(device_, vertex_buffer_, vertex_buffer_memory_, 0));
|
||||||
|
|
||||||
|
void* data;
|
||||||
|
VK_CHECK(vkMapMemory(device_, staging_buffer_memory, 0, size_buffer, 0, &data));
|
||||||
|
memcpy(data, vertices.data(), size_buffer);
|
||||||
|
vkUnmapMemory(device_, staging_buffer_memory);
|
||||||
|
|
||||||
|
copy_memory(staging_buffer, vertex_buffer_, size_buffer);
|
||||||
|
|
||||||
|
vkFreeMemory(device_, staging_buffer_memory, nullptr);
|
||||||
|
vkDestroyBuffer(device_, staging_buffer, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderEngine::copy_memory(VkBuffer src, VkBuffer dst, VkDeviceSize size)
|
||||||
|
{
|
||||||
|
QueueFamilyIndices indices = find_queue_family_indices(physical_device_, surface_);
|
||||||
|
VkCommandPool copy_pool;
|
||||||
|
VkCommandPoolCreateInfo copy_pool_info{};
|
||||||
|
copy_pool_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
|
||||||
|
copy_pool_info.queueFamilyIndex = indices.transfer_family.value();
|
||||||
|
copy_pool_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
|
||||||
|
VK_CHECK(vkCreateCommandPool(device_, ©_pool_info, nullptr, ©_pool));
|
||||||
|
|
||||||
|
VkCommandBufferAllocateInfo command_buffer_allocate_info{};
|
||||||
|
command_buffer_allocate_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
|
||||||
|
command_buffer_allocate_info.commandPool = copy_pool;
|
||||||
|
command_buffer_allocate_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
|
||||||
|
command_buffer_allocate_info.commandBufferCount = 1;
|
||||||
|
|
||||||
|
VkCommandBuffer copy_buffer;
|
||||||
|
VK_CHECK(vkAllocateCommandBuffers(device_, &command_buffer_allocate_info, ©_buffer));
|
||||||
|
|
||||||
|
VkCommandBufferBeginInfo command_buffer_begin_info{};
|
||||||
|
command_buffer_begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
|
||||||
|
command_buffer_begin_info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
|
||||||
|
|
||||||
|
VK_CHECK(vkBeginCommandBuffer(copy_buffer, &command_buffer_begin_info));
|
||||||
|
|
||||||
|
VkBufferCopy buffer_copy{};
|
||||||
|
buffer_copy.srcOffset = 0;
|
||||||
|
buffer_copy.dstOffset = 0;
|
||||||
|
buffer_copy.size = size;
|
||||||
|
vkCmdCopyBuffer(copy_buffer, src, dst, 1, &buffer_copy);
|
||||||
|
|
||||||
|
vkEndCommandBuffer(copy_buffer);
|
||||||
|
|
||||||
|
VkSubmitInfo submit_info{};
|
||||||
|
submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
|
||||||
|
submit_info.commandBufferCount = 1;
|
||||||
|
submit_info.pCommandBuffers = ©_buffer;
|
||||||
|
|
||||||
|
vkQueueSubmit(transfer_queue_, 1, &submit_info, VK_NULL_HANDLE);
|
||||||
|
vkQueueWaitIdle(transfer_queue_);
|
||||||
|
|
||||||
|
vkFreeCommandBuffers(device_, copy_pool, 1, ©_buffer);
|
||||||
|
vkDestroyCommandPool(device_, copy_pool, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderEngine::allocate_command_buffers()
|
||||||
|
{
|
||||||
|
command_buffers_.resize(swapchain_images_.size());
|
||||||
|
|
||||||
|
VkCommandBufferAllocateInfo command_buffer_allocate_info{};
|
||||||
|
command_buffer_allocate_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
|
||||||
|
command_buffer_allocate_info.commandPool = command_pool_;
|
||||||
|
command_buffer_allocate_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
|
||||||
|
command_buffer_allocate_info.commandBufferCount = static_cast<uint32_t>(command_buffers_.size());
|
||||||
|
|
||||||
|
VK_CHECK(vkAllocateCommandBuffers(device_, &command_buffer_allocate_info, command_buffers_.data()));
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderEngine::create_sync_objects()
|
||||||
|
{
|
||||||
|
image_available_semaphores_.resize(swapchain_images_.size());
|
||||||
|
render_finished_semaphores_.resize(swapchain_images_.size());
|
||||||
|
in_flight_fences_.resize(swapchain_images_.size());
|
||||||
|
|
||||||
|
VkSemaphoreCreateInfo semaphore_info{};
|
||||||
|
semaphore_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
|
||||||
|
|
||||||
|
VkFenceCreateInfo fence_info{};
|
||||||
|
fence_info.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
|
||||||
|
fence_info.flags = VK_FENCE_CREATE_SIGNALED_BIT;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < swapchain_images_.size(); ++i)
|
||||||
|
{
|
||||||
|
VK_CHECK(vkCreateSemaphore(device_, &semaphore_info, nullptr, &image_available_semaphores_[i]));
|
||||||
|
VK_CHECK(vkCreateSemaphore(device_, &semaphore_info, nullptr, &render_finished_semaphores_[i]));
|
||||||
|
VK_CHECK(vkCreateFence(device_, &fence_info, nullptr, &in_flight_fences_[i]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderEngine::record_command_buffer(VkCommandBuffer command_buffer, uint32_t image_index) const
|
||||||
|
{
|
||||||
|
VkCommandBufferBeginInfo command_buffer_begin_info{};
|
||||||
|
command_buffer_begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
|
||||||
|
VK_CHECK(vkBeginCommandBuffer(command_buffer, &command_buffer_begin_info));
|
||||||
|
|
||||||
|
constexpr VkClearValue clear_color = {{{0.0f, 0.0f, 0.0f, 1.0f}}};
|
||||||
|
VkRenderPassBeginInfo render_pass_begin_info{};
|
||||||
|
render_pass_begin_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
|
||||||
|
render_pass_begin_info.renderPass = render_pass_;
|
||||||
|
render_pass_begin_info.framebuffer = framebuffers_[image_index];
|
||||||
|
render_pass_begin_info.renderArea.offset = {0, 0};
|
||||||
|
render_pass_begin_info.renderArea.extent = swapchain_extent_;
|
||||||
|
render_pass_begin_info.clearValueCount = 1;
|
||||||
|
render_pass_begin_info.pClearValues = &clear_color;
|
||||||
|
vkCmdBeginRenderPass(command_buffer, &render_pass_begin_info, VK_SUBPASS_CONTENTS_INLINE);
|
||||||
|
|
||||||
|
vkCmdBindPipeline(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, graphics_pipeline_);
|
||||||
|
|
||||||
|
VkBuffer vertex_buffers[] = {vertex_buffer_};
|
||||||
|
VkDeviceSize offset[] = {0};
|
||||||
|
vkCmdBindVertexBuffers(command_buffer, 0, 1, vertex_buffers, offset);
|
||||||
|
|
||||||
|
VkViewport viewport;
|
||||||
|
viewport.x = 0.0f;
|
||||||
|
viewport.y = 0.0f;
|
||||||
|
viewport.width = static_cast<float>(swapchain_extent_.width);
|
||||||
|
viewport.height = static_cast<float>(swapchain_extent_.height);
|
||||||
|
viewport.minDepth = 0.0f;
|
||||||
|
viewport.maxDepth = 1.0f;
|
||||||
|
vkCmdSetViewport(command_buffer, 0, 1, &viewport);
|
||||||
|
|
||||||
|
VkRect2D scissor;
|
||||||
|
scissor.offset = {0, 0};
|
||||||
|
scissor.extent = swapchain_extent_;
|
||||||
|
vkCmdSetScissor(command_buffer, 0, 1, &scissor);
|
||||||
|
|
||||||
|
vkCmdDraw(command_buffer, static_cast<uint32_t>(vertices.size()), 1, 0, 0);
|
||||||
|
|
||||||
|
vkCmdEndRenderPass(command_buffer);
|
||||||
|
VK_CHECK(vkEndCommandBuffer(command_buffer));
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderEngine::draw_frame()
|
||||||
|
{
|
||||||
|
vkWaitForFences(device_, 1, &in_flight_fences_[current_frame_], VK_TRUE, UINT64_MAX);
|
||||||
|
vkResetFences(device_, 1, &in_flight_fences_[current_frame_]);
|
||||||
|
|
||||||
|
uint32_t image_index;
|
||||||
|
vkAcquireNextImageKHR(device_, swapchain_, UINT64_MAX, image_available_semaphores_[current_frame_], VK_NULL_HANDLE, &image_index);
|
||||||
|
|
||||||
|
vkResetCommandBuffer(command_buffers_[current_frame_], 0);
|
||||||
|
record_command_buffer(command_buffers_[current_frame_], image_index);
|
||||||
|
|
||||||
|
VkPipelineStageFlags wait_stage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
|
||||||
|
VkSubmitInfo submit_info{};
|
||||||
|
submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
|
||||||
|
submit_info.commandBufferCount = 1;
|
||||||
|
submit_info.pCommandBuffers = &command_buffers_[current_frame_];
|
||||||
|
submit_info.waitSemaphoreCount = 1;
|
||||||
|
submit_info.pWaitSemaphores = &image_available_semaphores_[current_frame_];
|
||||||
|
submit_info.pWaitDstStageMask = &wait_stage;
|
||||||
|
submit_info.signalSemaphoreCount = 1;
|
||||||
|
submit_info.pSignalSemaphores = &render_finished_semaphores_[current_frame_];
|
||||||
|
|
||||||
|
VK_CHECK(vkQueueSubmit(graphics_queue_, 1, &submit_info, in_flight_fences_[current_frame_]));
|
||||||
|
|
||||||
|
VkPresentInfoKHR present_info{};
|
||||||
|
present_info.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
|
||||||
|
present_info.waitSemaphoreCount = 1;
|
||||||
|
present_info.pWaitSemaphores = &render_finished_semaphores_[current_frame_];
|
||||||
|
present_info.swapchainCount = 1;
|
||||||
|
present_info.pSwapchains = &swapchain_;
|
||||||
|
present_info.pImageIndices = &image_index;
|
||||||
|
present_info.pResults = nullptr;
|
||||||
|
|
||||||
|
vkQueuePresentKHR(present_queue_, &present_info);
|
||||||
|
|
||||||
|
current_frame_ = (current_frame_ + 1) % static_cast<int>(swapchain_images_.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderEngine::create_surface()
|
||||||
|
{
|
||||||
|
VK_CHECK(glfwCreateWindowSurface(instance_, window_, nullptr, &surface_));
|
||||||
|
}
|
||||||
|
|
||||||
|
RenderEngine::RenderEngine(CoreInstance& core, GLFWwindow* window, VkPresentModeKHR desired_present_mode):
|
||||||
|
core_(core),
|
||||||
|
window_(window)
|
||||||
|
#ifdef _DEBUG
|
||||||
|
,debug_messenger_(nullptr)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
create_instance();
|
||||||
|
create_surface();
|
||||||
|
pick_physical_device();
|
||||||
|
create_logical_device();
|
||||||
|
create_swapchain(desired_present_mode);
|
||||||
|
create_image_views();
|
||||||
|
create_render_pass();
|
||||||
|
create_graphics_pipeline();
|
||||||
|
create_framebuffers();
|
||||||
|
create_command_pool();
|
||||||
|
allocate_vertex_buffer();
|
||||||
|
allocate_command_buffers();
|
||||||
|
create_sync_objects();
|
||||||
|
}
|
||||||
|
|
||||||
|
RenderEngine::~RenderEngine()
|
||||||
|
{
|
||||||
|
vkDeviceWaitIdle(device_);
|
||||||
|
|
||||||
|
if (vertex_buffer_memory_ != VK_NULL_HANDLE)
|
||||||
|
vkFreeMemory(device_, vertex_buffer_memory_, nullptr);
|
||||||
|
|
||||||
|
if (vertex_buffer_ != VK_NULL_HANDLE)
|
||||||
|
vkDestroyBuffer(device_, vertex_buffer_, nullptr);
|
||||||
|
|
||||||
|
for (auto& i : image_available_semaphores_)
|
||||||
|
vkDestroySemaphore(device_, i, nullptr);
|
||||||
|
|
||||||
|
for (auto& i : render_finished_semaphores_)
|
||||||
|
vkDestroySemaphore(device_, i, nullptr);
|
||||||
|
|
||||||
|
for (auto& i : in_flight_fences_)
|
||||||
|
vkDestroyFence(device_, i, nullptr);
|
||||||
|
|
||||||
|
if (command_buffers_.empty() == false)
|
||||||
|
vkFreeCommandBuffers(device_, command_pool_, static_cast<uint32_t>(command_buffers_.size()), command_buffers_.data());
|
||||||
|
|
||||||
|
if (command_pool_ != VK_NULL_HANDLE)
|
||||||
|
vkDestroyCommandPool(device_, command_pool_, nullptr);
|
||||||
|
|
||||||
|
for (auto& i : framebuffers_)
|
||||||
|
vkDestroyFramebuffer(device_, i, nullptr);
|
||||||
|
|
||||||
|
if (graphics_pipeline_ != VK_NULL_HANDLE)
|
||||||
|
vkDestroyPipeline(device_, graphics_pipeline_, nullptr);
|
||||||
|
|
||||||
|
if (pipeline_layout_ != VK_NULL_HANDLE)
|
||||||
|
vkDestroyPipelineLayout(device_, pipeline_layout_, nullptr);
|
||||||
|
|
||||||
|
if (render_pass_ != VK_NULL_HANDLE)
|
||||||
|
vkDestroyRenderPass(device_, render_pass_, nullptr);
|
||||||
|
|
||||||
|
for (auto image_view : swapchain_image_views_)
|
||||||
|
vkDestroyImageView(device_, image_view, nullptr);
|
||||||
|
swapchain_image_views_.clear();
|
||||||
|
|
||||||
|
if (swapchain_ != VK_NULL_HANDLE)
|
||||||
|
vkDestroySwapchainKHR(device_, swapchain_, nullptr);
|
||||||
|
|
||||||
|
if (device_ != VK_NULL_HANDLE)
|
||||||
|
vkDestroyDevice(device_, nullptr);
|
||||||
|
|
||||||
|
if (surface_ != VK_NULL_HANDLE)
|
||||||
|
vkDestroySurfaceKHR(instance_, surface_, nullptr);
|
||||||
|
|
||||||
|
#ifdef _DEBUG
|
||||||
|
if (debug_messenger_ != nullptr && instance_ != nullptr) {
|
||||||
|
PFN_vkDestroyDebugUtilsMessengerEXT destroyer_messenger = reinterpret_cast<PFN_vkDestroyDebugUtilsMessengerEXT>(vkGetInstanceProcAddr(instance_, "vkDestroyDebugUtilsMessengerEXT"));
|
||||||
|
destroyer_messenger(instance_, debug_messenger_, nullptr);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (instance_ != VK_NULL_HANDLE)
|
||||||
|
vkDestroyInstance(instance_, nullptr);
|
||||||
|
|
||||||
|
if (window_ != nullptr)
|
||||||
|
glfwDestroyWindow(window_);
|
||||||
|
glfwTerminate();
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderEngine::start()
|
||||||
|
{
|
||||||
|
while (!glfwWindowShouldClose(window_))
|
||||||
|
{
|
||||||
|
glfwPollEvents();
|
||||||
|
draw_frame();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderEngine::stop_render() const
|
||||||
|
{
|
||||||
|
if (window_ != nullptr && !glfwWindowShouldClose(window_))
|
||||||
|
glfwSetWindowShouldClose(window_, true);
|
||||||
|
}
|
||||||
@@ -0,0 +1,126 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
#include <vector>
|
||||||
|
#include <optional>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#define GLFW_INCLUDE_VULKAN
|
||||||
|
#include <GLFW/glfw3.h>
|
||||||
|
|
||||||
|
#include <vulkan/vulkan.h>
|
||||||
|
#include <glm/glm.hpp>
|
||||||
|
|
||||||
|
#ifdef _DEBUG
|
||||||
|
#include <assert.h>
|
||||||
|
#define VK_CHECK(res) assert(res == VK_SUCCESS)
|
||||||
|
#else
|
||||||
|
#define VK_CHECK(res) if ((res) != VK_SUCCESS) throw std::runtime_error("Vulkan error: " + std::to_string(res))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
class CoreInstance;
|
||||||
|
|
||||||
|
class RenderEngine
|
||||||
|
{
|
||||||
|
struct QueueFamilyIndices
|
||||||
|
{
|
||||||
|
std::optional<uint32_t> graphics_family;
|
||||||
|
std::optional<uint32_t> present_family;
|
||||||
|
std::optional<uint32_t> transfer_family;
|
||||||
|
};
|
||||||
|
struct SwapchainSupportDetails
|
||||||
|
{
|
||||||
|
VkSurfaceCapabilitiesKHR capabilities;
|
||||||
|
std::vector<VkSurfaceFormatKHR> formats;
|
||||||
|
std::vector<VkPresentModeKHR> present_modes;
|
||||||
|
};
|
||||||
|
|
||||||
|
#pragma region Experemental
|
||||||
|
struct Vertex
|
||||||
|
{
|
||||||
|
glm::vec2 pos;
|
||||||
|
glm::vec3 color;
|
||||||
|
static VkVertexInputBindingDescription get_binding_description();
|
||||||
|
static std::array<VkVertexInputAttributeDescription, 2> get_vertex_attribute_descriptions();
|
||||||
|
};
|
||||||
|
std::vector<Vertex> vertices = {
|
||||||
|
{{0.0f, -0.5f}, {1.0f, 0.0f, 0.0f}},
|
||||||
|
{{0.5f, 0.5f}, {0.0f, 1.0f, 0.0f}},
|
||||||
|
{{-0.5f, 0.5f}, {0.0f, 0.0f, 1.0f}}
|
||||||
|
};
|
||||||
|
VkBuffer vertex_buffer_ = VK_NULL_HANDLE;
|
||||||
|
VkDeviceMemory vertex_buffer_memory_ = VK_NULL_HANDLE;
|
||||||
|
uint32_t find_memory_type(uint32_t typeFilter, VkMemoryPropertyFlags properties) const;
|
||||||
|
void allocate_vertex_buffer();
|
||||||
|
void copy_memory(VkBuffer src, VkBuffer dst, VkDeviceSize size);
|
||||||
|
#pragma endregion
|
||||||
|
|
||||||
|
static const std::vector<const char*> deviceExtensions;
|
||||||
|
|
||||||
|
int current_frame_ = 0;
|
||||||
|
|
||||||
|
CoreInstance& core_;
|
||||||
|
GLFWwindow* window_;
|
||||||
|
VkInstance instance_ = VK_NULL_HANDLE;
|
||||||
|
VkSurfaceKHR surface_ = VK_NULL_HANDLE;
|
||||||
|
VkPhysicalDevice physical_device_ = VK_NULL_HANDLE;
|
||||||
|
VkDevice device_ = VK_NULL_HANDLE;
|
||||||
|
VkQueue graphics_queue_ = VK_NULL_HANDLE;
|
||||||
|
VkQueue present_queue_ = VK_NULL_HANDLE;
|
||||||
|
VkQueue transfer_queue_ = VK_NULL_HANDLE;
|
||||||
|
VkSwapchainKHR swapchain_ = VK_NULL_HANDLE;
|
||||||
|
std::vector<VkImage> swapchain_images_;
|
||||||
|
VkFormat swapchain_image_format_;
|
||||||
|
VkExtent2D swapchain_extent_;
|
||||||
|
std::vector<VkImageView> swapchain_image_views_;
|
||||||
|
VkRenderPass render_pass_ = VK_NULL_HANDLE;
|
||||||
|
VkPipelineLayout pipeline_layout_ = VK_NULL_HANDLE;
|
||||||
|
VkPipeline graphics_pipeline_ = VK_NULL_HANDLE;
|
||||||
|
std::vector<VkFramebuffer> framebuffers_;
|
||||||
|
VkCommandPool command_pool_ = VK_NULL_HANDLE;
|
||||||
|
std::vector<VkCommandBuffer> command_buffers_;
|
||||||
|
|
||||||
|
std::vector<VkSemaphore> image_available_semaphores_, render_finished_semaphores_;
|
||||||
|
std::vector<VkFence> in_flight_fences_;
|
||||||
|
|
||||||
|
#ifdef _DEBUG
|
||||||
|
VkResult enable_layer_validation(const VkDebugUtilsMessengerCreateInfoEXT* create_info);
|
||||||
|
VkDebugUtilsMessengerEXT debug_messenger_;
|
||||||
|
#endif
|
||||||
|
SwapchainSupportDetails query_swapchain_details() const;
|
||||||
|
|
||||||
|
static std::vector<const char*> get_required_extensions();
|
||||||
|
static bool is_device_suitable(VkPhysicalDevice device, VkSurfaceKHR surface);
|
||||||
|
static bool check_device_extensions_support(VkPhysicalDevice device);
|
||||||
|
static QueueFamilyIndices find_queue_family_indices(VkPhysicalDevice physical_device, VkSurfaceKHR surface);
|
||||||
|
static VkSurfaceFormatKHR choose_surface_format(const std::vector<VkSurfaceFormatKHR>& surface_formats);
|
||||||
|
static VkPresentModeKHR choose_present_mode(const std::vector<VkPresentModeKHR>& present_modes, VkPresentModeKHR desired_present_mode);
|
||||||
|
static VkExtent2D choose_extent(const VkSurfaceCapabilitiesKHR& capabilities, GLFWwindow* window);
|
||||||
|
VkShaderModule create_shader_module(const std::string& code) const;
|
||||||
|
void create_buffer(VkDeviceSize size, VkBufferUsageFlags usage,
|
||||||
|
VkBuffer* buffer, const std::vector<uint32_t>& queue_families);
|
||||||
|
void allocate_memory(VkBuffer buffer, VkMemoryPropertyFlags property, VkDeviceMemory* device_memory);
|
||||||
|
|
||||||
|
void create_instance();
|
||||||
|
void create_surface();
|
||||||
|
void pick_physical_device();
|
||||||
|
void create_logical_device();
|
||||||
|
void create_swapchain(VkPresentModeKHR desired_present_mode);
|
||||||
|
void create_image_views();
|
||||||
|
void create_render_pass();
|
||||||
|
void create_graphics_pipeline();
|
||||||
|
void create_framebuffers();
|
||||||
|
void create_command_pool();
|
||||||
|
void allocate_command_buffers();
|
||||||
|
void create_sync_objects();
|
||||||
|
|
||||||
|
void record_command_buffer(VkCommandBuffer command_buffer, uint32_t image_index) const;
|
||||||
|
void draw_frame();
|
||||||
|
public:
|
||||||
|
// Can throw the exception
|
||||||
|
RenderEngine(CoreInstance& core, GLFWwindow* window, VkPresentModeKHR desired_present_mode = VK_PRESENT_MODE_MAILBOX_KHR);
|
||||||
|
~RenderEngine();
|
||||||
|
|
||||||
|
void start();
|
||||||
|
void stop_render() const;
|
||||||
|
};
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
|
|
||||||
#include "SystemCalls.h"
|
#include "../SystemCalls.h"
|
||||||
|
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
|
|
||||||
@@ -38,7 +38,7 @@ double System::getMemorySize() {
|
|||||||
memStatus.dwLength = sizeof(memStatus);
|
memStatus.dwLength = sizeof(memStatus);
|
||||||
|
|
||||||
GlobalMemoryStatusEx(&memStatus);
|
GlobalMemoryStatusEx(&memStatus);
|
||||||
return memStatus.ullTotalPhys / 1024 / 1024;
|
return static_cast<double>(memStatus.ullTotalPhys) / 1024. / 1024.;
|
||||||
}
|
}
|
||||||
|
|
||||||
void* System::InitModule(const char* ModuleName, CoreCallBacks* callbacks) {
|
void* System::InitModule(const char* ModuleName, CoreCallBacks* callbacks) {
|
||||||
@@ -63,7 +63,13 @@ void GameInstance::start()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void GameInstance::quit()
|
void GameInstance::stop()
|
||||||
{
|
{
|
||||||
is_running = false;
|
is_running = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GameInstance::quit()
|
||||||
|
{
|
||||||
|
stop();
|
||||||
|
core.quit();
|
||||||
|
}
|
||||||
|
|||||||
@@ -16,11 +16,8 @@ class GameInstance
|
|||||||
|
|
||||||
std::atomic<bool> is_running = true;
|
std::atomic<bool> is_running = true;
|
||||||
|
|
||||||
// Create a window
|
|
||||||
// Render
|
|
||||||
// Pull events
|
|
||||||
void start();
|
void start();
|
||||||
|
void stop();
|
||||||
public:
|
public:
|
||||||
void quit();
|
void quit();
|
||||||
|
|
||||||
|
|||||||
@@ -66,7 +66,11 @@ SaveMap::SaveMap(const std::string& json_data)
|
|||||||
size_t begin = json_data.find(':', i) + 2;
|
size_t begin = json_data.find(':', i) + 2;
|
||||||
size_t end = i = json_data.find('\"', begin);
|
size_t end = i = json_data.find('\"', begin);
|
||||||
i++;
|
i++;
|
||||||
std::string value = json_data.substr(begin, end - begin);
|
std::string value;
|
||||||
|
if (begin != end)
|
||||||
|
value = json_data.substr(begin, end - begin);
|
||||||
|
else
|
||||||
|
value = "";
|
||||||
save_string[name.c_str() + 1] = value;
|
save_string[name.c_str() + 1] = value;
|
||||||
} else if (name[0] == 'o')
|
} else if (name[0] == 'o')
|
||||||
{
|
{
|
||||||
@@ -147,12 +151,16 @@ SaveMap::SaveMap(const std::string& json_data)
|
|||||||
continue;
|
continue;
|
||||||
std::vector<std::string>& vector_strings = save_vector_strings[key];
|
std::vector<std::string>& vector_strings = save_vector_strings[key];
|
||||||
|
|
||||||
size_t j = 2;
|
size_t j = 0;
|
||||||
while (j < arr_data.length())
|
while (j < arr_data.length())
|
||||||
{
|
{
|
||||||
size_t begin = j;
|
size_t begin = arr_data.find('\"', j) + 1;
|
||||||
size_t end = j = arr_data.find('\"', begin + 1);
|
size_t end = j = arr_data.find('\"', begin);
|
||||||
std::string value = arr_data.substr(begin, end - begin);
|
std::string value;
|
||||||
|
if (begin != end)
|
||||||
|
value = arr_data.substr(begin, end - begin);
|
||||||
|
else
|
||||||
|
value = "";
|
||||||
vector_strings.push_back(value);
|
vector_strings.push_back(value);
|
||||||
j += 3;
|
j += 3;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,23 +0,0 @@
|
|||||||
find_package(Vulkan REQUIRED)
|
|
||||||
|
|
||||||
file(GLOB_RECURSE SRC "*.cpp" "*.c" "*.h" "*.hpp")
|
|
||||||
add_library(RenderModule SHARED ${SRC})
|
|
||||||
|
|
||||||
target_compile_features(RenderModule PRIVATE cxx_std_17)
|
|
||||||
|
|
||||||
target_include_directories(RenderModule
|
|
||||||
PRIVATE
|
|
||||||
${PROJECT_SOURCE_DIR}/ModuleLib
|
|
||||||
${PROJECT_SOURCE_DIR}/Core
|
|
||||||
${PROJECT_SOURCE_DIR}/FastRTTI
|
|
||||||
${PROJECT_SOURCE_DIR}/Delegate
|
|
||||||
${PROJECT_SOURCE_DIR}/glfw/Include
|
|
||||||
${Vulkan_INCLUDE_DIRS}
|
|
||||||
)
|
|
||||||
|
|
||||||
target_link_libraries(RenderModule PRIVATE
|
|
||||||
ModuleLib
|
|
||||||
FastRTTI
|
|
||||||
glfw
|
|
||||||
Vulkan::Vulkan
|
|
||||||
)
|
|
||||||
@@ -1,150 +0,0 @@
|
|||||||
#include "RenderEngine.h"
|
|
||||||
|
|
||||||
#include <stdexcept>
|
|
||||||
#include <vector>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
#include "Core/CoreInstance.h"
|
|
||||||
|
|
||||||
PROTECTION_FROM_GB(RenderEngine)
|
|
||||||
|
|
||||||
#ifdef _DEBUG
|
|
||||||
//#include "Log/Log.h"
|
|
||||||
#include <assert.h>
|
|
||||||
#define VK_CHECK(res) assert(res == VK_SUCCESS)
|
|
||||||
|
|
||||||
static VKAPI_ATTR VkBool32 VKAPI_CALL debugCallback(
|
|
||||||
VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
|
|
||||||
VkDebugUtilsMessageTypeFlagsEXT messageType,
|
|
||||||
const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData,
|
|
||||||
void* pUserData) {
|
|
||||||
|
|
||||||
std::string msg = "validation layer: ";
|
|
||||||
msg += pCallbackData->pMessage;
|
|
||||||
//Log(msg);
|
|
||||||
|
|
||||||
return VK_FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
VkResult RenderEngine::enable_layer_validation(VkInstance instance, VkDebugUtilsMessengerCreateInfoEXT* create_info)
|
|
||||||
{
|
|
||||||
PFN_vkCreateDebugUtilsMessengerEXT debug_creator = reinterpret_cast<PFN_vkCreateDebugUtilsMessengerEXT>(vkGetInstanceProcAddr(instance, "vkCreateDebugUtilsMessengerEXT"));
|
|
||||||
return debug_creator(instance, create_info, nullptr, &debug_messenger_);
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
#define VK_CHECK(res) if ((res) != VK_SUCCESS) throw std::runtime_error("Vulkan error: " + std::to_string(res))
|
|
||||||
#endif
|
|
||||||
|
|
||||||
std::vector<const char*> RenderEngine::get_required_extensions()
|
|
||||||
{
|
|
||||||
uint32_t extensions_count = 0;
|
|
||||||
const char** glfw_extension = glfwGetRequiredInstanceExtensions(&extensions_count);
|
|
||||||
std::vector<const char*> extensions(glfw_extension, glfw_extension + extensions_count);
|
|
||||||
|
|
||||||
#ifdef _DEBUG
|
|
||||||
extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
|
|
||||||
#endif
|
|
||||||
return extensions;
|
|
||||||
}
|
|
||||||
|
|
||||||
RenderEngine::RenderEngine() : window(nullptr)
|
|
||||||
#ifdef _DEBUG
|
|
||||||
, debug_messenger_(nullptr)
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
onStop.bind(this, &RenderEngine::stop_render);
|
|
||||||
|
|
||||||
if (glfwInit() == GLFW_FALSE)
|
|
||||||
throw std::runtime_error("Fail init glfw");
|
|
||||||
|
|
||||||
{
|
|
||||||
std::vector<const char*> extensions = get_required_extensions();
|
|
||||||
std::vector<const char*> layers = {
|
|
||||||
#ifdef _DEBUG
|
|
||||||
"VK_LAYER_KHRONOS_validation"
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
VkApplicationInfo app_info{};
|
|
||||||
app_info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
|
|
||||||
app_info.apiVersion = VK_API_VERSION_1_0;
|
|
||||||
app_info.applicationVersion = VK_MAKE_VERSION(0, 0, 0);
|
|
||||||
app_info.pApplicationName = "UwU Engine";
|
|
||||||
app_info.pEngineName = "UwU Engine";
|
|
||||||
app_info.engineVersion = VK_MAKE_VERSION(0, 0, 0);
|
|
||||||
|
|
||||||
|
|
||||||
VkInstanceCreateInfo instance_create_info{};
|
|
||||||
instance_create_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
|
|
||||||
instance_create_info.pApplicationInfo = &app_info;
|
|
||||||
instance_create_info.enabledExtensionCount = extensions.size();
|
|
||||||
instance_create_info.ppEnabledExtensionNames = extensions.data();
|
|
||||||
instance_create_info.enabledLayerCount = layers.size();
|
|
||||||
instance_create_info.ppEnabledLayerNames = layers.data();
|
|
||||||
#ifdef _DEBUG
|
|
||||||
VkDebugUtilsMessengerCreateInfoEXT debug_messenger_create_info{};
|
|
||||||
debug_messenger_create_info.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT;
|
|
||||||
debug_messenger_create_info.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;
|
|
||||||
debug_messenger_create_info.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;
|
|
||||||
debug_messenger_create_info.pfnUserCallback = &debugCallback;
|
|
||||||
instance_create_info.pNext = &debug_messenger_create_info;
|
|
||||||
#endif
|
|
||||||
VK_CHECK(vkCreateInstance(&instance_create_info, nullptr, &instance_));
|
|
||||||
#ifdef _DEBUG
|
|
||||||
VK_CHECK(enable_layer_validation(instance_, &debug_messenger_create_info));
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
uint32_t device_count = 0;
|
|
||||||
std::vector<VkPhysicalDevice> devices;
|
|
||||||
VK_CHECK(vkEnumeratePhysicalDevices(instance_, &device_count, nullptr));
|
|
||||||
VK_CHECK(vkEnumeratePhysicalDevices(instance_, &device_count, devices.data()));
|
|
||||||
|
|
||||||
for (const auto& device : devices)
|
|
||||||
{
|
|
||||||
VkPhysicalDeviceProperties device_properties;
|
|
||||||
vkGetPhysicalDeviceProperties(device, &device_properties);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
RenderEngine::~RenderEngine()
|
|
||||||
{
|
|
||||||
#ifdef _DEBUG
|
|
||||||
if (debug_messenger_ != nullptr && instance_ != nullptr) {
|
|
||||||
PFN_vkDestroyDebugUtilsMessengerEXT destroyer_messenger = reinterpret_cast<PFN_vkDestroyDebugUtilsMessengerEXT>(vkGetInstanceProcAddr(instance_, "vkDestroyDebugUtilsMessengerEXT"));
|
|
||||||
destroyer_messenger(instance_, debug_messenger_, nullptr);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (instance_ != nullptr)
|
|
||||||
vkDestroyInstance(instance_, nullptr);
|
|
||||||
|
|
||||||
if (window != nullptr)
|
|
||||||
glfwDestroyWindow(window);
|
|
||||||
glfwTerminate();
|
|
||||||
}
|
|
||||||
|
|
||||||
void RenderEngine::start()
|
|
||||||
{
|
|
||||||
window = glfwCreateWindow(640, 480, "UwU Engine", nullptr, nullptr);
|
|
||||||
if (!window)
|
|
||||||
{
|
|
||||||
glfwTerminate();
|
|
||||||
throw std::runtime_error("Fail create window");
|
|
||||||
}
|
|
||||||
|
|
||||||
while (!glfwWindowShouldClose(window))
|
|
||||||
{
|
|
||||||
glfwSwapBuffers(window);
|
|
||||||
glfwPollEvents();
|
|
||||||
}
|
|
||||||
QuitGame();
|
|
||||||
}
|
|
||||||
|
|
||||||
void RenderEngine::stop_render()
|
|
||||||
{
|
|
||||||
if (window != nullptr && !glfwWindowShouldClose(window))
|
|
||||||
glfwSetWindowShouldClose(window, true);
|
|
||||||
}
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#define GLFW_INCLUDE_VULKAN
|
|
||||||
#include "GLFW/glfw3.h"
|
|
||||||
|
|
||||||
#include "ModuleInstance.h"
|
|
||||||
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
class Delegate;
|
|
||||||
|
|
||||||
class RenderEngine : public ModuleInstance
|
|
||||||
{
|
|
||||||
GLFWwindow* window;
|
|
||||||
VkInstance instance_;
|
|
||||||
|
|
||||||
#ifdef _DEBUG
|
|
||||||
VkResult enable_layer_validation(VkInstance instance, VkDebugUtilsMessengerCreateInfoEXT* create_info);
|
|
||||||
VkDebugUtilsMessengerEXT debug_messenger_;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static std::vector<const char*> get_required_extensions();
|
|
||||||
|
|
||||||
void stop_render();
|
|
||||||
public:
|
|
||||||
RenderEngine();
|
|
||||||
~RenderEngine() override;
|
|
||||||
|
|
||||||
void start() override;
|
|
||||||
};
|
|
||||||
+26
-1
@@ -2,7 +2,7 @@ set(GAME_NAME TestGame)
|
|||||||
|
|
||||||
set(CMAKE_CXX_STANDARD 20)
|
set(CMAKE_CXX_STANDARD 20)
|
||||||
|
|
||||||
file(GLOB_RECURSE SRC "*.cpp" "*.c" "*.h" "*.hpp" "*.res" "*.world" "*.conf")
|
file(GLOB_RECURSE SRC "*.cpp" "*.c" "*.h" "*.hpp" "*.res" "*.world" "*.conf" "*.frag" "*.vert")
|
||||||
|
|
||||||
add_executable(${GAME_NAME} ${SRC})
|
add_executable(${GAME_NAME} ${SRC})
|
||||||
target_link_libraries(${GAME_NAME} PRIVATE Core)
|
target_link_libraries(${GAME_NAME} PRIVATE Core)
|
||||||
@@ -45,3 +45,28 @@ add_custom_command(
|
|||||||
${OUTPUT_PATH}/Resources
|
${OUTPUT_PATH}/Resources
|
||||||
COMMENT "Copying Resources directory"
|
COMMENT "Copying Resources directory"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
add_custom_command(
|
||||||
|
TARGET ${GAME_NAME}
|
||||||
|
PRE_BUILD
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E make_directory ${OUTPUT_PATH}/Shaders
|
||||||
|
COMMENT "Creating Shaders directory"
|
||||||
|
)
|
||||||
|
|
||||||
|
add_custom_command(
|
||||||
|
TARGET ${GAME_NAME}
|
||||||
|
POST_BUILD
|
||||||
|
COMMAND $ENV{VULKAN_SDK}/Bin/glslc.exe
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/Shaders/vertex.vert
|
||||||
|
-o ${OUTPUT_PATH}/Shaders/vertex.spv
|
||||||
|
COMMENT "Building vertex shader"
|
||||||
|
)
|
||||||
|
|
||||||
|
add_custom_command(
|
||||||
|
TARGET ${GAME_NAME}
|
||||||
|
POST_BUILD
|
||||||
|
COMMAND $ENV{VULKAN_SDK}/Bin/glslc.exe
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/Shaders/fragment.frag
|
||||||
|
-o ${OUTPUT_PATH}/Shaders/fragment.spv
|
||||||
|
COMMENT "Building fragment shader"
|
||||||
|
)
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
#version 450
|
||||||
|
|
||||||
|
layout(location = 0) in vec3 fragColor;
|
||||||
|
layout(location = 0) out vec4 outColor;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
outColor = vec4(fragColor, 1.0);
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
#version 450
|
||||||
|
|
||||||
|
layout(location = 0) in vec2 inPosition;
|
||||||
|
layout(location = 1) in vec3 inColor;
|
||||||
|
|
||||||
|
layout(location = 0) out vec3 fragColor;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
gl_Position = vec4(inPosition, 0.0, 1.0);
|
||||||
|
fragColor = inColor;
|
||||||
|
}
|
||||||
@@ -1 +1 @@
|
|||||||
{"Class name":"MainConfig","dmin_memory_size":"4096.0","imin_CPU_count":"1","sgame_name":"Test Game","sbase_world":"TestWorld","vsmodules_names":["RenderModule"]}
|
{"Class name":"MainConfig","dmin_memory_size":"4096.0","imin_CPU_count":"1","sgame_name":"Test Game","sbase_world":"TestWorld","vsmodules_names":[]}
|
||||||
Reference in New Issue
Block a user