Swapchain almost finished.
This commit is contained in:
parent
ce5fd7e93d
commit
11725fb9f4
|
|
@ -8,12 +8,14 @@ file(GLOB_RECURSE SourceFiles "${CMAKE_CURRENT_SOURCE_DIR}/Source/*.cpp" "${CMAK
|
||||||
find_package(spdlog CONFIG REQUIRED)
|
find_package(spdlog CONFIG REQUIRED)
|
||||||
find_package(Vulkan REQUIRED)
|
find_package(Vulkan REQUIRED)
|
||||||
find_package(glm CONFIG REQUIRED)
|
find_package(glm CONFIG REQUIRED)
|
||||||
|
find_package(glfw3 CONFIG REQUIRED)
|
||||||
|
|
||||||
add_library (Nitric STATIC ${SourceFiles})
|
add_library (Nitric STATIC ${SourceFiles})
|
||||||
|
|
||||||
target_link_libraries(Nitric PRIVATE glm::glm)
|
target_link_libraries(Nitric PRIVATE glm::glm)
|
||||||
target_link_libraries(Nitric PRIVATE spdlog::spdlog)
|
target_link_libraries(Nitric PRIVATE spdlog::spdlog)
|
||||||
target_link_libraries(Nitric PRIVATE Vulkan::Vulkan)
|
target_link_libraries(Nitric PRIVATE Vulkan::Vulkan)
|
||||||
|
target_link_libraries(Nitric PRIVATE glfw)
|
||||||
target_include_directories(Nitric PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/Source")
|
target_include_directories(Nitric PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/Source")
|
||||||
|
|
||||||
set(NITRIC_LIBRARY "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/Nitric.lib")
|
set(NITRIC_LIBRARY "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/Nitric.lib")
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,53 @@
|
||||||
#include <Core/Application.h>
|
#include <Core/Application.h>
|
||||||
|
|
||||||
namespace Nitric {
|
namespace Nitric {
|
||||||
Application::Application(const ApplicationSettings& settings) {
|
Application* Application::s_Instance = nullptr;
|
||||||
|
|
||||||
|
Application::Application(const ApplicationSettings& settings) {
|
||||||
|
if (s_Instance != nullptr) {
|
||||||
|
LogInternal::Fatal("Application already created.");
|
||||||
|
}
|
||||||
|
|
||||||
|
s_Instance = this;
|
||||||
|
|
||||||
|
WindowProperties winProps{};
|
||||||
|
winProps.Width = settings.Width;
|
||||||
|
winProps.Height = settings.Height;
|
||||||
|
winProps.Title = settings.Title;
|
||||||
|
|
||||||
|
m_Window = Window::Create(winProps);
|
||||||
|
|
||||||
|
m_Context = GraphicsContext::Create(m_Window);
|
||||||
|
|
||||||
|
m_Running = true;
|
||||||
|
m_Window->AttachEventHandler([this](EventData& event) {
|
||||||
|
switch (event.Event) {
|
||||||
|
case WindowEvent::CLOSE:
|
||||||
|
m_Running = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
m_Context->Init();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::Run() {
|
void Application::Run() {
|
||||||
|
while (m_Running) {
|
||||||
|
this->PollEvents();
|
||||||
|
this->RenderFrame();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Application::PollEvents() {
|
||||||
|
m_Window->Update();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Application::RenderFrame() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Application::~Application() {
|
||||||
|
m_Context.reset();
|
||||||
|
m_Window.reset();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -5,6 +5,7 @@
|
||||||
|
|
||||||
#include <Render/GraphicsContext.h>
|
#include <Render/GraphicsContext.h>
|
||||||
#include <Core/Window.h>
|
#include <Core/Window.h>
|
||||||
|
#include <Core/LogInternal.h>
|
||||||
|
|
||||||
namespace Nitric {
|
namespace Nitric {
|
||||||
|
|
||||||
|
|
@ -17,11 +18,22 @@ namespace Nitric {
|
||||||
class Application {
|
class Application {
|
||||||
public:
|
public:
|
||||||
explicit Application(const ApplicationSettings& settings);
|
explicit Application(const ApplicationSettings& settings);
|
||||||
|
~Application();
|
||||||
|
|
||||||
void Run();
|
void Run();
|
||||||
|
|
||||||
private:
|
static Application* Get();
|
||||||
|
|
||||||
|
private:
|
||||||
|
static Application* s_Instance;
|
||||||
|
|
||||||
|
void PollEvents();
|
||||||
|
void RenderFrame();
|
||||||
|
|
||||||
|
Scope<GraphicsContext> m_Context;
|
||||||
|
Ref<Window> m_Window;
|
||||||
|
|
||||||
|
bool m_Running;
|
||||||
};
|
};
|
||||||
|
|
||||||
static Application* CreateApplication();
|
static Application* CreateApplication();
|
||||||
|
|
|
||||||
|
|
@ -14,5 +14,10 @@ int main(int argc, char** argv) {
|
||||||
Nitric::LogInternal::Info("Creating Nitric Application");
|
Nitric::LogInternal::Info("Creating Nitric Application");
|
||||||
auto application = Nitric::CreateApplication();
|
auto application = Nitric::CreateApplication();
|
||||||
|
|
||||||
|
Nitric::LogInternal::Info("Starting Nitric Application");
|
||||||
|
application->Run();
|
||||||
|
|
||||||
|
Nitric::LogInternal::Info("Stopping Nitric Application");
|
||||||
|
delete application;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -5,6 +5,7 @@ namespace Nitric {
|
||||||
|
|
||||||
void LogInternal::Init() {
|
void LogInternal::Init() {
|
||||||
s_Logger = spdlog::stdout_color_mt("Nitric Internal");
|
s_Logger = spdlog::stdout_color_mt("Nitric Internal");
|
||||||
|
s_Logger->set_level(spdlog::level::debug);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ref<spdlog::logger> LogInternal::Get() {
|
Ref<spdlog::logger> LogInternal::Get() {
|
||||||
|
|
|
||||||
|
|
@ -13,13 +13,13 @@ namespace Nitric {
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
static void Debug(T& msg) {
|
static void Debug(T& msg) {
|
||||||
Get()->debug(msg);
|
Get()->log(spdlog::level::debug, msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
static void Debug(spdlog::format_string_t<Args...> fmt, Args &&...args)
|
static void Debug(spdlog::format_string_t<Args...> fmt, Args &&...args)
|
||||||
{
|
{
|
||||||
Debug(fmt::format(fmt, std::forward(args)...));
|
Get()->log(spdlog::level::debug, fmt, std::forward<Args>(args)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
|
|
@ -30,7 +30,7 @@ namespace Nitric {
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
static void Info(spdlog::format_string_t<Args...> fmt, Args &&...args)
|
static void Info(spdlog::format_string_t<Args...> fmt, Args &&...args)
|
||||||
{
|
{
|
||||||
Info(fmt::format(fmt, std::forward(args)...));
|
Get()->info(fmt, std::forward<Args>(args)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
|
|
@ -41,14 +41,14 @@ namespace Nitric {
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
static void Critical(spdlog::format_string_t<Args...> fmt, Args &&...args)
|
static void Critical(spdlog::format_string_t<Args...> fmt, Args &&...args)
|
||||||
{
|
{
|
||||||
Critical(fmt::format(fmt, std::forward(args)...));
|
Get()->critical(fmt, std::forward<Args>(args)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
static void Fatal(T& msg) {
|
static void Fatal(T& msg) {
|
||||||
LogInternal::Error("The next error is fatal. This will terminate the program");
|
LogInternal::Error("The next error is fatal. This will terminate the program");
|
||||||
Get()->log(spdlog::level::from_str("fatal"), msg);
|
Get()->log(spdlog::level::critical, msg);
|
||||||
auto api = GraphicsAPI::APIToString(GraphicsAPI::GetAPI());
|
auto api = GraphicsAPI::APIToString(GraphicsAPI::NoErrGetAPI());
|
||||||
Info("GraphicsAPI is set to {}", api);
|
Info("GraphicsAPI is set to {}", api);
|
||||||
throw std::runtime_error(msg);
|
throw std::runtime_error(msg);
|
||||||
}
|
}
|
||||||
|
|
@ -56,7 +56,11 @@ namespace Nitric {
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
static void Fatal(spdlog::format_string_t<Args...> fmt, Args &&...args)
|
static void Fatal(spdlog::format_string_t<Args...> fmt, Args &&...args)
|
||||||
{
|
{
|
||||||
Fatal(fmt::format(fmt, std::forward(args)...));
|
LogInternal::Error("The next error is fatal. This will terminate the program");
|
||||||
|
Get()->log(spdlog::level::critical, fmt, std::forward<Args>(args)...);
|
||||||
|
auto api = GraphicsAPI::APIToString(GraphicsAPI::NoErrGetAPI());
|
||||||
|
Info("GraphicsAPI is set to {}", api);
|
||||||
|
throw std::runtime_error(fmt::format(fmt, std::forward<Args>(args)...));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
|
|
@ -67,7 +71,18 @@ namespace Nitric {
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
static void Error(spdlog::format_string_t<Args...> fmt, Args &&...args)
|
static void Error(spdlog::format_string_t<Args...> fmt, Args &&...args)
|
||||||
{
|
{
|
||||||
Error(fmt::format(fmt, std::forward(args)...));
|
Get()->error(fmt, std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
static void Warn(T& msg) {
|
||||||
|
Get()->warn(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename... Args>
|
||||||
|
static void Warn(spdlog::format_string_t<Args...> fmt, Args &&...args)
|
||||||
|
{
|
||||||
|
Get()->warn(fmt, std::forward<Args>(args)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
||||||
16
Nitric/Source/Core/Window.cpp
Normal file
16
Nitric/Source/Core/Window.cpp
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
#include <Core/Window.h>
|
||||||
|
#include <Render/GraphicsAPI.h>
|
||||||
|
|
||||||
|
#include <Platform/Vulkan/VkWindow.h>
|
||||||
|
|
||||||
|
namespace Nitric {
|
||||||
|
Ref<Window> Window::Create(const WindowProperties &properties) {
|
||||||
|
switch (GraphicsAPI::GetAPI()) {
|
||||||
|
case GraphicsAPI::Vulkan:
|
||||||
|
return CreateRef<VkWindow>(properties);
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -5,6 +5,7 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <glm/glm.hpp>
|
#include <glm/glm.hpp>
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
namespace Nitric {
|
namespace Nitric {
|
||||||
struct WindowProperties {
|
struct WindowProperties {
|
||||||
|
|
@ -12,9 +13,27 @@ namespace Nitric {
|
||||||
uint32_t Height;
|
uint32_t Height;
|
||||||
std::string Title;
|
std::string Title;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class WindowEvent {
|
||||||
|
CLOSE
|
||||||
|
};
|
||||||
|
|
||||||
|
struct EventData {
|
||||||
|
WindowEvent Event;
|
||||||
|
};
|
||||||
|
|
||||||
|
using EventHandler =
|
||||||
|
std::function<void(EventData&)>;
|
||||||
|
|
||||||
class Window {
|
class Window {
|
||||||
public:
|
public:
|
||||||
|
virtual ~Window() = default;
|
||||||
|
|
||||||
virtual void SetSize(const glm::vec2& size) = 0;
|
virtual void SetSize(const glm::vec2& size) = 0;
|
||||||
virtual glm::vec2 GetSize() const = 0;
|
virtual glm::vec2 GetSize() = 0;
|
||||||
|
virtual void Update() = 0;
|
||||||
|
virtual void AttachEventHandler(EventHandler handler) = 0;
|
||||||
|
|
||||||
|
static Ref<Window> Create(const WindowProperties& properties);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
223
Nitric/Source/Platform/Vulkan/VkBase.cpp
Normal file
223
Nitric/Source/Platform/Vulkan/VkBase.cpp
Normal file
|
|
@ -0,0 +1,223 @@
|
||||||
|
#include <Platform/Vulkan/VkBase.h>
|
||||||
|
|
||||||
|
#include <Platform/Vulkan/VkWindow.h>
|
||||||
|
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
namespace Nitric {
|
||||||
|
namespace Vk {
|
||||||
|
|
||||||
|
void Validate(VkResult result, bool fatal, const std::string &msg) {
|
||||||
|
if (result != VK_SUCCESS) {
|
||||||
|
const char* error = string_VkResult(result);
|
||||||
|
if (fatal) {
|
||||||
|
LogInternal::Fatal("({}) -> {}", error, msg);
|
||||||
|
} else {
|
||||||
|
LogInternal::Error("({}) -> {}", error, msg);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
LogInternal::Debug("Vk::Validate success.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PopulateDebugCreateInfo(VkDebugUtilsMessengerCreateInfoEXT& createInfo) {
|
||||||
|
createInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT;
|
||||||
|
createInfo.messageSeverity =
|
||||||
|
VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT |
|
||||||
|
VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT |
|
||||||
|
VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT |
|
||||||
|
VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_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 = DebugCallbacks;
|
||||||
|
}
|
||||||
|
|
||||||
|
VKAPI_ATTR VkBool32 VKAPI_CALL DebugCallbacks(VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
|
||||||
|
VkDebugUtilsMessageTypeFlagsEXT messageType,
|
||||||
|
const VkDebugUtilsMessengerCallbackDataEXT *pCallbackData, void *pUserData) {
|
||||||
|
switch (messageSeverity) {
|
||||||
|
case VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT:
|
||||||
|
LogInternal::Info("Validation Layer -> {}", pCallbackData->pMessage);
|
||||||
|
break;
|
||||||
|
case VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT:
|
||||||
|
LogInternal::Warn("Validation Layer -> {}", pCallbackData->pMessage);
|
||||||
|
break;
|
||||||
|
case VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT:
|
||||||
|
LogInternal::Error("Validation Layer -> {}", pCallbackData->pMessage);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
LogInternal::Debug("Validation Layer -> {}", pCallbackData->pMessage);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return VK_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
VkResult CreateDebugUtilsMessenger(VkInstance instance, const VkDebugUtilsMessengerCreateInfoEXT *pCreateInfo,
|
||||||
|
const VkAllocationCallbacks *pAllocator, VkDebugUtilsMessengerEXT *pMessenger) {
|
||||||
|
auto func = (PFN_vkCreateDebugUtilsMessengerEXT) vkGetInstanceProcAddr(instance, "vkCreateDebugUtilsMessengerEXT");
|
||||||
|
if (func != nullptr) {
|
||||||
|
return func(instance, pCreateInfo, pAllocator, pMessenger);
|
||||||
|
}
|
||||||
|
return VK_ERROR_EXTENSION_NOT_PRESENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DestroyDebugUtilsMessenger(VkInstance instance, VkDebugUtilsMessengerEXT messenger,
|
||||||
|
const VkAllocationCallbacks *pAllocator) {
|
||||||
|
auto func = (PFN_vkDestroyDebugUtilsMessengerEXT) vkGetInstanceProcAddr(instance, "vkDestroyDebugUtilsMessengerEXT");
|
||||||
|
if (func != nullptr) {
|
||||||
|
func(instance, messenger, pAllocator);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScorePhysicalDevice(VkPhysicalDevice physicalDevice, uint32_t* pScore) {
|
||||||
|
if (pScore == nullptr) {
|
||||||
|
LogInternal::Error("pScore == nullptr");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
VkPhysicalDeviceFeatures features{};
|
||||||
|
vkGetPhysicalDeviceFeatures(physicalDevice, &features);
|
||||||
|
|
||||||
|
VkPhysicalDeviceProperties properties{};
|
||||||
|
vkGetPhysicalDeviceProperties(physicalDevice, &properties);
|
||||||
|
|
||||||
|
if (!features.geometryShader) {
|
||||||
|
*pScore = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
*pScore += properties.limits.maxImageDimension2D;
|
||||||
|
|
||||||
|
if (properties.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU) {
|
||||||
|
*pScore += 2500;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QueueFamilyIndices FindQueueFamilies(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface) {
|
||||||
|
uint32_t queueCount;
|
||||||
|
vkGetPhysicalDeviceQueueFamilyProperties(
|
||||||
|
physicalDevice, &queueCount,
|
||||||
|
nullptr);
|
||||||
|
|
||||||
|
std::vector<VkQueueFamilyProperties> properties(queueCount);
|
||||||
|
vkGetPhysicalDeviceQueueFamilyProperties(
|
||||||
|
physicalDevice, &queueCount,
|
||||||
|
properties.data());
|
||||||
|
QueueFamilyIndices indices{};
|
||||||
|
for (uint32_t i = 0; i < queueCount; i++) {
|
||||||
|
VkQueueFamilyProperties property = properties[i];
|
||||||
|
if (property.queueFlags & VK_QUEUE_GRAPHICS_BIT) {
|
||||||
|
indices.GraphicsFamily = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
VkBool32 presentSupport = false;
|
||||||
|
vkGetPhysicalDeviceSurfaceSupportKHR(physicalDevice, i, surface, &presentSupport);
|
||||||
|
if (presentSupport) {
|
||||||
|
indices.PresentFamily = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (indices.IsComplete()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return indices;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string GetPhysicalDeviceName(VkPhysicalDevice physicalDevice) {
|
||||||
|
VkPhysicalDeviceProperties properties{};
|
||||||
|
vkGetPhysicalDeviceProperties(physicalDevice, &properties);
|
||||||
|
return {properties.deviceName};
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsDeviceSuitable(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface) {
|
||||||
|
QueueFamilyIndices indices = FindQueueFamilies(physicalDevice, surface);
|
||||||
|
bool extensionSupport = CheckDeviceExtensionSupport(physicalDevice);
|
||||||
|
|
||||||
|
bool swapChainAdequate = false;
|
||||||
|
if (extensionSupport) {
|
||||||
|
SwapChainSupportDetails swapChainSupport = QuerySwapChainSupport(physicalDevice, surface);
|
||||||
|
swapChainAdequate = !swapChainSupport.Formats.empty() && !swapChainSupport.PresentModes.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
return indices.IsComplete() && extensionSupport && swapChainAdequate;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CheckDeviceExtensionSupport(VkPhysicalDevice physicalDevice) {
|
||||||
|
uint32_t extensionCount = 0;
|
||||||
|
vkEnumerateDeviceExtensionProperties(physicalDevice, nullptr, &extensionCount, nullptr);
|
||||||
|
|
||||||
|
std::vector<VkExtensionProperties> availableExtensions(extensionCount);
|
||||||
|
vkEnumerateDeviceExtensionProperties(physicalDevice, nullptr, &extensionCount, availableExtensions.data());
|
||||||
|
|
||||||
|
std::set<std::string> requiredExtensions(DeviceExtensions.begin(), DeviceExtensions.end());
|
||||||
|
|
||||||
|
for (const auto& extension : availableExtensions) {
|
||||||
|
requiredExtensions.erase(extension.extensionName);
|
||||||
|
}
|
||||||
|
|
||||||
|
return requiredExtensions.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
SwapChainSupportDetails QuerySwapChainSupport(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface) {
|
||||||
|
SwapChainSupportDetails details;
|
||||||
|
|
||||||
|
vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physicalDevice, surface, &details.Capabilities);
|
||||||
|
|
||||||
|
uint32_t formatCount;
|
||||||
|
vkGetPhysicalDeviceSurfaceFormatsKHR(physicalDevice, surface, &formatCount, nullptr);
|
||||||
|
|
||||||
|
if (formatCount != 0) {
|
||||||
|
details.Formats.resize(formatCount);
|
||||||
|
vkGetPhysicalDeviceSurfaceFormatsKHR(physicalDevice, surface, &formatCount, details.Formats.data());
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t presentModeCount;
|
||||||
|
vkGetPhysicalDeviceSurfacePresentModesKHR(physicalDevice, surface, &presentModeCount, details.PresentModes.data());
|
||||||
|
|
||||||
|
if (presentModeCount != 0) {
|
||||||
|
details.PresentModes.resize(presentModeCount);
|
||||||
|
vkGetPhysicalDeviceSurfacePresentModesKHR(physicalDevice, surface, &presentModeCount, details.PresentModes.data());
|
||||||
|
}
|
||||||
|
|
||||||
|
return details;
|
||||||
|
}
|
||||||
|
|
||||||
|
VkSurfaceFormatKHR ChooseSwapSurfaceFormat(const std::vector<VkSurfaceFormatKHR> &availableFormats) {
|
||||||
|
for (const auto& format : availableFormats) {
|
||||||
|
if (format.format == VK_FORMAT_B8G8R8A8_SRGB && format.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) {
|
||||||
|
return format;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return availableFormats[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
VkPresentModeKHR ChooseSwapPresentMode(const std::vector<VkPresentModeKHR> &availablePresentModes) {
|
||||||
|
for (const auto& presentMode : availablePresentModes) {
|
||||||
|
if (presentMode == VK_PRESENT_MODE_MAILBOX_KHR) {
|
||||||
|
return presentMode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return VK_PRESENT_MODE_FIFO_KHR;
|
||||||
|
}
|
||||||
|
|
||||||
|
VkExtent2D ChooseSwapExtent(Ref<Window> window, const VkSurfaceCapabilitiesKHR &capabilities) {
|
||||||
|
if (capabilities.currentExtent.width != std::numeric_limits<uint32_t>::max()) {
|
||||||
|
return capabilities.currentExtent;
|
||||||
|
} else {
|
||||||
|
auto vulkanWindow = CastPtr<VkWindow>(std::move(window));
|
||||||
|
auto size = vulkanWindow->GetFramebufferSize();
|
||||||
|
VkExtent2D actualExtent = {
|
||||||
|
static_cast<uint32_t>(size.x),
|
||||||
|
static_cast<uint32_t>(size.y)
|
||||||
|
};
|
||||||
|
actualExtent.width = std::clamp(actualExtent.width, capabilities.minImageExtent.width, capabilities.maxImageExtent.width);
|
||||||
|
actualExtent.height = std::clamp(actualExtent.height, capabilities.minImageExtent.height, capabilities.maxImageExtent.height);
|
||||||
|
|
||||||
|
return actualExtent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -2,7 +2,12 @@
|
||||||
|
|
||||||
#include <vulkan/vulkan.h>
|
#include <vulkan/vulkan.h>
|
||||||
#include <vulkan/vk_enum_string_helper.h>
|
#include <vulkan/vk_enum_string_helper.h>
|
||||||
|
#include <set>
|
||||||
|
#include <limits>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
#include <Core/LogInternal.h>
|
#include <Core/LogInternal.h>
|
||||||
|
#include <Core/Window.h>
|
||||||
|
|
||||||
namespace Nitric {
|
namespace Nitric {
|
||||||
#ifdef NDEBUG
|
#ifdef NDEBUG
|
||||||
|
|
@ -12,18 +17,55 @@ namespace Nitric {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace Vk {
|
namespace Vk {
|
||||||
template <typename ...Args>
|
void Validate(VkResult result, bool fatal, const std::string& msg);
|
||||||
void Validate(VkResult result, bool fatal, spdlog::format_string_t<Args...> fmt, Args &&...args) {
|
void PopulateDebugCreateInfo(VkDebugUtilsMessengerCreateInfoEXT& createInfo);
|
||||||
if (result != VK_SUCCESS) {
|
|
||||||
auto error = string_VkResult(result);
|
static VKAPI_ATTR VkBool32 VKAPI_CALL DebugCallbacks(
|
||||||
if (fatal) {
|
VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
|
||||||
LogInternal::Fatal("({}) -> {}", error, fmt::format(fmt, std::forward<Args>(args)...))
|
VkDebugUtilsMessageTypeFlagsEXT messageType,
|
||||||
} else {
|
const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData,
|
||||||
LogInternal::Error("({}) -> {}", error, fmt::format(fmt, std::forward<Args>(args)...))
|
void* pUserData);
|
||||||
}
|
|
||||||
} else {
|
VkResult CreateDebugUtilsMessenger(
|
||||||
LogInternal::Debug("Vk::Validate success.")
|
VkInstance instance,
|
||||||
|
const VkDebugUtilsMessengerCreateInfoEXT* pCreateInfo,
|
||||||
|
const VkAllocationCallbacks* pAllocator,
|
||||||
|
VkDebugUtilsMessengerEXT* pMessenger);
|
||||||
|
|
||||||
|
void DestroyDebugUtilsMessenger(
|
||||||
|
VkInstance instance,
|
||||||
|
VkDebugUtilsMessengerEXT messenger,
|
||||||
|
const VkAllocationCallbacks* pAllocator);
|
||||||
|
|
||||||
|
void ScorePhysicalDevice(VkPhysicalDevice physicalDevice, uint32_t* pScore);
|
||||||
|
std::string GetPhysicalDeviceName(VkPhysicalDevice physicalDevice);
|
||||||
|
bool IsDeviceSuitable(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface);
|
||||||
|
bool CheckDeviceExtensionSupport(VkPhysicalDevice device);
|
||||||
|
const static std::vector<const char*> DeviceExtensions = {
|
||||||
|
VK_KHR_SWAPCHAIN_EXTENSION_NAME
|
||||||
|
};
|
||||||
|
|
||||||
|
struct QueueFamilyIndices {
|
||||||
|
std::optional<uint32_t> GraphicsFamily;
|
||||||
|
std::optional<uint32_t> PresentFamily;
|
||||||
|
|
||||||
|
bool IsComplete() {
|
||||||
|
return this->GraphicsFamily.has_value() && this->PresentFamily.has_value();
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
|
QueueFamilyIndices FindQueueFamilies(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface);
|
||||||
|
|
||||||
|
struct SwapChainSupportDetails {
|
||||||
|
VkSurfaceCapabilitiesKHR Capabilities;
|
||||||
|
std::vector<VkSurfaceFormatKHR> Formats;
|
||||||
|
std::vector<VkPresentModeKHR> PresentModes;
|
||||||
|
};
|
||||||
|
|
||||||
|
SwapChainSupportDetails QuerySwapChainSupport(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface);
|
||||||
|
|
||||||
|
VkSurfaceFormatKHR ChooseSwapSurfaceFormat(const std::vector<VkSurfaceFormatKHR>& availableFormats);
|
||||||
|
VkPresentModeKHR ChooseSwapPresentMode(const std::vector<VkPresentModeKHR>& availablePresentModes);
|
||||||
|
VkExtent2D ChooseSwapExtent(Ref<Window> window, const VkSurfaceCapabilitiesKHR& capabilities);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -9,12 +9,21 @@ namespace Nitric {
|
||||||
}
|
}
|
||||||
|
|
||||||
void VkGraphicsContext::Init() {
|
void VkGraphicsContext::Init() {
|
||||||
|
LogInternal::Debug("Creating instance");
|
||||||
this->CreateInstance();
|
this->CreateInstance();
|
||||||
|
LogInternal::Debug("Creating debug messenger");
|
||||||
|
this->CreateDebugMessenger();
|
||||||
|
LogInternal::Debug("Creating surface");
|
||||||
|
m_Window->CreateSurface(m_Instance, &m_Surface);
|
||||||
|
LogInternal::Debug("Getting physical device");
|
||||||
|
this->PickPhysicalDevice();
|
||||||
|
LogInternal::Debug("Creating logical device");
|
||||||
|
this->CreateLogicalDevice();
|
||||||
}
|
}
|
||||||
|
|
||||||
void VkGraphicsContext::CreateInstance() {
|
void VkGraphicsContext::CreateInstance() {
|
||||||
if (!CheckValidationLayerSupport() && VkValidationLayersEnabled) {
|
if (!CheckValidationLayerSupport() && VkValidationLayersEnabled) {
|
||||||
|
LogInternal::Fatal("Requested validation layers but they were not available.");
|
||||||
}
|
}
|
||||||
VkApplicationInfo appInfo{};
|
VkApplicationInfo appInfo{};
|
||||||
appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
|
appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
|
||||||
|
|
@ -36,13 +45,19 @@ namespace Nitric {
|
||||||
if (VkValidationLayersEnabled) {
|
if (VkValidationLayersEnabled) {
|
||||||
createInfo.enabledLayerCount = static_cast<uint32_t>(s_ValidationLayers.size());
|
createInfo.enabledLayerCount = static_cast<uint32_t>(s_ValidationLayers.size());
|
||||||
createInfo.ppEnabledLayerNames = s_ValidationLayers.data();
|
createInfo.ppEnabledLayerNames = s_ValidationLayers.data();
|
||||||
|
VkDebugUtilsMessengerCreateInfoEXT debugCreateInfo{};
|
||||||
|
Vk::PopulateDebugCreateInfo(debugCreateInfo);
|
||||||
|
createInfo.pNext = &debugCreateInfo;
|
||||||
} else {
|
} else {
|
||||||
createInfo.enabledLayerCount = 0;
|
createInfo.enabledLayerCount = 0;
|
||||||
createInfo.ppEnabledLayerNames = nullptr;
|
createInfo.ppEnabledLayerNames = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
Vk::Validate(vkCreateInstance(&createInfo, nullptr, &m_Instance), true, "VkInstance VkGraphicsContext::m_Instance failed on creation.")
|
Vk::Validate(
|
||||||
}
|
vkCreateInstance(&createInfo, nullptr, &m_Instance),
|
||||||
|
true,
|
||||||
|
"VkInstance VkGraphicsContext::m_Instance failed on creation.");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool VkGraphicsContext::CheckValidationLayerSupport() {
|
bool VkGraphicsContext::CheckValidationLayerSupport() {
|
||||||
|
|
@ -71,5 +86,124 @@ namespace Nitric {
|
||||||
"VK_LAYER_KHRONOS_validation"
|
"VK_LAYER_KHRONOS_validation"
|
||||||
};
|
};
|
||||||
|
|
||||||
VkGraphicsContext::~VkGraphicsContext() = default;
|
VkGraphicsContext::~VkGraphicsContext() {
|
||||||
|
LogInternal::Debug("Destroying Vulkan Device");
|
||||||
|
vkDestroyDevice(m_Device, nullptr);
|
||||||
|
LogInternal::Debug("Destroying Vulkan Surface");
|
||||||
|
vkDestroySurfaceKHR(m_Instance, m_Surface, nullptr);
|
||||||
|
if (VkValidationLayersEnabled) {
|
||||||
|
LogInternal::Debug("Destroying Vulkan Debug Messenger");
|
||||||
|
Vk::DestroyDebugUtilsMessenger(m_Instance, m_DebugMessenger, nullptr);
|
||||||
|
}
|
||||||
|
LogInternal::Debug("Destroying Vulkan Instance");
|
||||||
|
vkDestroyInstance(m_Instance, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void VkGraphicsContext::CreateDebugMessenger() {
|
||||||
|
if (!VkValidationLayersEnabled) return;
|
||||||
|
VkDebugUtilsMessengerCreateInfoEXT createInfo{};
|
||||||
|
Vk::PopulateDebugCreateInfo(createInfo);
|
||||||
|
|
||||||
|
Vk::Validate(
|
||||||
|
Vk::CreateDebugUtilsMessenger(
|
||||||
|
m_Instance,&createInfo,
|
||||||
|
nullptr,&m_DebugMessenger),
|
||||||
|
false,
|
||||||
|
"Failed to create debug messenger. This is not fatal, however it should be investigated.");
|
||||||
|
}
|
||||||
|
|
||||||
|
void VkGraphicsContext::PickPhysicalDevice() {
|
||||||
|
uint32_t physicalDeviceCount = 0;
|
||||||
|
vkEnumeratePhysicalDevices(m_Instance, &physicalDeviceCount, nullptr);
|
||||||
|
|
||||||
|
std::vector<VkPhysicalDevice> physicalDevices(physicalDeviceCount);
|
||||||
|
vkEnumeratePhysicalDevices(m_Instance, &physicalDeviceCount, physicalDevices.data());
|
||||||
|
|
||||||
|
std::multimap<uint32_t, VkPhysicalDevice> devices;
|
||||||
|
for (const auto& device : physicalDevices) {
|
||||||
|
if (Vk::IsDeviceSuitable(device, m_Surface)) {
|
||||||
|
uint32_t score = 0;
|
||||||
|
Vk::ScorePhysicalDevice(device, &score);
|
||||||
|
devices.insert(std::make_pair(score, device));
|
||||||
|
LogInternal::Debug("Device \"{}\" scored {}", Vk::GetPhysicalDeviceName(device), score);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (devices.rbegin()->first > 0) {
|
||||||
|
m_PhysicalDevice = devices.rbegin()->second;
|
||||||
|
} else {
|
||||||
|
LogInternal::Fatal("Failed to find a physical device that can support this engine.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void VkGraphicsContext::CreateLogicalDevice() {
|
||||||
|
VkDeviceCreateInfo createInfo{};
|
||||||
|
createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
|
||||||
|
|
||||||
|
VkPhysicalDeviceFeatures deviceFeatures{};
|
||||||
|
deviceFeatures.geometryShader = true;
|
||||||
|
|
||||||
|
createInfo.pEnabledFeatures = &deviceFeatures;
|
||||||
|
|
||||||
|
Vk::QueueFamilyIndices indices = Vk::FindQueueFamilies(m_PhysicalDevice, m_Surface);
|
||||||
|
std::set<uint32_t> queueFamilies = {indices.GraphicsFamily.value(), indices.PresentFamily.value()};
|
||||||
|
std::vector<VkDeviceQueueCreateInfo> queueCreateInfos;
|
||||||
|
|
||||||
|
float queuePriorities = 1.0f;
|
||||||
|
for (const auto& queueFamily : queueFamilies) {
|
||||||
|
VkDeviceQueueCreateInfo queueCreateInfo{};
|
||||||
|
queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
|
||||||
|
queueCreateInfo.pQueuePriorities = &queuePriorities;
|
||||||
|
queueCreateInfo.queueFamilyIndex = queueFamily;
|
||||||
|
queueCreateInfo.queueCount = 1;
|
||||||
|
queueCreateInfos.push_back(queueCreateInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
createInfo.queueCreateInfoCount = static_cast<uint32_t>(queueCreateInfos.size());
|
||||||
|
createInfo.pQueueCreateInfos = queueCreateInfos.data();
|
||||||
|
|
||||||
|
Vk::Validate(
|
||||||
|
vkCreateDevice(m_PhysicalDevice, &createInfo, nullptr, &m_Device),
|
||||||
|
true,
|
||||||
|
"VkDevice VkGraphicsQueue::m_Device failed to create.");
|
||||||
|
|
||||||
|
vkGetDeviceQueue(m_Device, indices.GraphicsFamily.value(), 0, &m_GraphicsQueue);
|
||||||
|
vkGetDeviceQueue(m_Device, indices.PresentFamily.value(), 0, &m_PresentQueue);
|
||||||
|
}
|
||||||
|
|
||||||
|
void VkGraphicsContext::CreateSwapchain() {
|
||||||
|
Vk::SwapChainSupportDetails swapChainSupport = Vk::QuerySwapChainSupport(m_PhysicalDevice, m_Surface);
|
||||||
|
|
||||||
|
VkSurfaceFormatKHR surfaceFormat = Vk::ChooseSwapSurfaceFormat(swapChainSupport.Formats);
|
||||||
|
VkPresentModeKHR presentMode = Vk::ChooseSwapPresentMode(swapChainSupport.PresentModes);
|
||||||
|
VkExtent2D extent = Vk::ChooseSwapExtent(m_Window, swapChainSupport.Capabilities);
|
||||||
|
|
||||||
|
uint32_t imageCount = swapChainSupport.Capabilities.minImageCount + 1;
|
||||||
|
if (swapChainSupport.Capabilities.maxImageCount > 0 && imageCount > swapChainSupport.Capabilities.maxImageCount) {
|
||||||
|
imageCount = swapChainSupport.Capabilities.maxImageCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
VkSwapchainCreateInfoKHR createInfo{};
|
||||||
|
createInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
|
||||||
|
createInfo.surface = m_Surface;
|
||||||
|
createInfo.minImageCount = imageCount;
|
||||||
|
createInfo.imageFormat = surfaceFormat.format;
|
||||||
|
createInfo.imageColorSpace = surfaceFormat.colorSpace;
|
||||||
|
createInfo.imageArrayLayers = 1;
|
||||||
|
createInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
|
||||||
|
|
||||||
|
Vk::QueueFamilyIndices indices = Vk::FindQueueFamilies(m_PhysicalDevice, m_Surface);
|
||||||
|
uint32_t queueFamilyIncices[] = {indices.GraphicsFamily.value(), indices.PresentFamily.value()};
|
||||||
|
|
||||||
|
if (indices.GraphicsFamily != indices.PresentFamily) {
|
||||||
|
createInfo.imageSharingMode = VK_SHARING_MODE_CONCURRENT;
|
||||||
|
createInfo.queueFamilyIndexCount = 2;
|
||||||
|
createInfo.pQueueFamilyIndices = queueFamilyIncices;
|
||||||
|
} else {
|
||||||
|
createInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||||||
|
}
|
||||||
|
|
||||||
|
createInfo.preTransform = swapChainSupport.Capabilities.currentTransform;
|
||||||
|
createInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -6,23 +6,41 @@
|
||||||
#include <Platform/Vulkan/VkBase.h>
|
#include <Platform/Vulkan/VkBase.h>
|
||||||
|
|
||||||
#include <vulkan/vulkan.h>
|
#include <vulkan/vulkan.h>
|
||||||
|
#include <map>
|
||||||
|
#include <set>
|
||||||
|
|
||||||
namespace Nitric {
|
namespace Nitric {
|
||||||
class VkGraphicsContext : public GraphicsContext {
|
class VkGraphicsContext : public GraphicsContext {
|
||||||
public:
|
public:
|
||||||
explicit VkGraphicsContext(Ref<VkWindow> window);
|
explicit VkGraphicsContext(Ref<VkWindow> window);
|
||||||
~VkGraphicsContext();
|
~VkGraphicsContext() override;
|
||||||
|
|
||||||
void Init() override;
|
void Init() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void CreateInstance();
|
void CreateInstance();
|
||||||
|
void CreateDebugMessenger();
|
||||||
|
void PickPhysicalDevice();
|
||||||
|
void CreateLogicalDevice();
|
||||||
|
|
||||||
|
void CreateSwapchain();
|
||||||
|
|
||||||
static bool CheckValidationLayerSupport();
|
static bool CheckValidationLayerSupport();
|
||||||
|
|
||||||
static std::vector<const char*> s_ValidationLayers;
|
static std::vector<const char*> s_ValidationLayers;
|
||||||
|
|
||||||
Ref<VkWindow> m_Window;
|
Ref<VkWindow> m_Window;
|
||||||
|
|
||||||
VkInstance m_Instance{};
|
VkInstance m_Instance{};
|
||||||
|
VkPhysicalDevice m_PhysicalDevice;
|
||||||
|
|
||||||
|
VkSurfaceKHR m_Surface;
|
||||||
|
|
||||||
|
VkDevice m_Device;
|
||||||
|
|
||||||
|
VkQueue m_GraphicsQueue;
|
||||||
|
VkQueue m_PresentQueue;
|
||||||
|
|
||||||
|
VkDebugUtilsMessengerEXT m_DebugMessenger{};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
@ -2,17 +2,87 @@
|
||||||
|
|
||||||
namespace Nitric {
|
namespace Nitric {
|
||||||
VkWindow::VkWindow(const WindowProperties& properties) {
|
VkWindow::VkWindow(const WindowProperties& properties) {
|
||||||
|
m_Size = glm::vec2(properties.Width, properties.Height);
|
||||||
|
m_Title = properties.Title;
|
||||||
|
|
||||||
|
if (!glfwInit()) {
|
||||||
|
LogInternal::Fatal("glfwInit() failed to create. This is critical for making a window.");
|
||||||
|
}
|
||||||
|
|
||||||
|
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
|
||||||
|
m_Window = glfwCreateWindow(
|
||||||
|
static_cast<int>(m_Size.x),
|
||||||
|
static_cast<int>(m_Size.y),
|
||||||
|
m_Title.c_str(),
|
||||||
|
nullptr,
|
||||||
|
nullptr);
|
||||||
|
|
||||||
|
glfwSetWindowUserPointer(m_Window, this);
|
||||||
|
|
||||||
|
glfwSetWindowCloseCallback(m_Window, [](GLFWwindow* window) {
|
||||||
|
EventData data{};
|
||||||
|
data.Event = WindowEvent::CLOSE;
|
||||||
|
auto self = static_cast<VkWindow *>(glfwGetWindowUserPointer(window));
|
||||||
|
self->DispatchEvent(data);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
std::vector<const char *> VkWindow::GetExtensions() {
|
std::vector<const char *> VkWindow::GetExtensions() {
|
||||||
uint32_t extensionCount;
|
uint32_t extensionCount = 0;
|
||||||
auto extensions = glfwGetRequiredInstanceExtensions(&extensionCount);
|
auto extensions = glfwGetRequiredInstanceExtensions(&extensionCount);
|
||||||
std::vector<const char*> returnExt(extensionCount);
|
std::vector<const char*> returnExt(extensions, extensions + extensionCount);
|
||||||
for (int i = 0; i < extensionCount; i++) {
|
if (VkValidationLayersEnabled) {
|
||||||
returnExt.push_back(extensions[i]);
|
returnExt.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
|
||||||
}
|
}
|
||||||
|
|
||||||
return returnExt;
|
return returnExt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
glm::vec2 VkWindow::GetSize() {
|
||||||
|
return m_Size;
|
||||||
|
}
|
||||||
|
|
||||||
|
void VkWindow::SetSize(const glm::vec2 &size) {
|
||||||
|
m_Size = size;
|
||||||
|
glfwSetWindowSize(
|
||||||
|
m_Window,
|
||||||
|
static_cast<int>(size.x),
|
||||||
|
static_cast<int>(size.y));
|
||||||
|
}
|
||||||
|
|
||||||
|
void VkWindow::Update() {
|
||||||
|
glfwPollEvents();
|
||||||
|
}
|
||||||
|
|
||||||
|
void VkWindow::AttachEventHandler(EventHandler handler) {
|
||||||
|
m_Handlers.push_back(handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
void VkWindow::DispatchEvent(EventData& event) {
|
||||||
|
for (const auto& handler : m_Handlers) {
|
||||||
|
handler(event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
VkWindow::~VkWindow() {
|
||||||
|
glfwDestroyWindow(m_Window);
|
||||||
|
glfwTerminate();
|
||||||
|
}
|
||||||
|
|
||||||
|
void VkWindow::CreateSurface(VkInstance instance, VkSurfaceKHR *pSurface) {
|
||||||
|
Vk::Validate(
|
||||||
|
glfwCreateWindowSurface(instance, this->m_Window, nullptr, pSurface),
|
||||||
|
true,
|
||||||
|
"VkWindow::CreateSurface(VkInstance, VkSurfaceKHR*) failed to create vulkan surface.");
|
||||||
|
}
|
||||||
|
|
||||||
|
glm::vec2 VkWindow::GetFramebufferSize() {
|
||||||
|
int width, height;
|
||||||
|
glfwGetFramebufferSize(m_Window, &width, &height);
|
||||||
|
|
||||||
|
return glm::vec2(width, height);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <Core/Window.h>
|
#include <Core/Window.h>
|
||||||
|
#include <Core/LogInternal.h>
|
||||||
|
#include <Platform/Vulkan/VkBase.h>
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#define GLFW_INCLUDE_VULKAN
|
#define GLFW_INCLUDE_VULKAN
|
||||||
|
|
@ -10,7 +12,26 @@ namespace Nitric {
|
||||||
class VkWindow : public Window {
|
class VkWindow : public Window {
|
||||||
public:
|
public:
|
||||||
explicit VkWindow(const WindowProperties& properties);
|
explicit VkWindow(const WindowProperties& properties);
|
||||||
|
~VkWindow() override;
|
||||||
|
|
||||||
virtual std::vector<const char*> GetExtensions() = 0;
|
std::vector<const char*> GetExtensions();
|
||||||
|
glm::vec2 GetSize() override;
|
||||||
|
void SetSize(const glm::vec2& size) override;
|
||||||
|
|
||||||
|
void Update() override;
|
||||||
|
|
||||||
|
void AttachEventHandler(EventHandler handler) override;
|
||||||
|
|
||||||
|
void CreateSurface(VkInstance instance, VkSurfaceKHR* pSurface);
|
||||||
|
|
||||||
|
glm::vec2 GetFramebufferSize();
|
||||||
|
private:
|
||||||
|
|
||||||
|
void DispatchEvent(EventData& event);
|
||||||
|
glm::vec2 m_Size;
|
||||||
|
std::string m_Title;
|
||||||
|
GLFWwindow* m_Window;
|
||||||
|
|
||||||
|
std::vector<EventHandler> m_Handlers;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
@ -1,4 +1,6 @@
|
||||||
#include "GraphicsAPI.h"
|
#include <Render/GraphicsAPI.h>
|
||||||
|
|
||||||
|
#include <Core/LogInternal.h>
|
||||||
|
|
||||||
namespace Nitric {
|
namespace Nitric {
|
||||||
GraphicsAPI::API GraphicsAPI::s_API = None;
|
GraphicsAPI::API GraphicsAPI::s_API = None;
|
||||||
|
|
@ -9,9 +11,12 @@ namespace Nitric {
|
||||||
|
|
||||||
GraphicsAPI::API GraphicsAPI::GetAPI() {
|
GraphicsAPI::API GraphicsAPI::GetAPI() {
|
||||||
if (s_API == None) {
|
if (s_API == None) {
|
||||||
spdlog::critical("Graphics API requested but not set. Failing here.");
|
LogInternal::Fatal("Graphics API requested but not set. Failing here.");
|
||||||
throw std::runtime_error("GraphicsAPI = None;");
|
|
||||||
}
|
}
|
||||||
return s_API;
|
return s_API;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GraphicsAPI::API GraphicsAPI::NoErrGetAPI() {
|
||||||
|
return s_API;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,7 +1,5 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <spdlog/spdlog.h>
|
|
||||||
|
|
||||||
namespace Nitric {
|
namespace Nitric {
|
||||||
|
|
||||||
class GraphicsAPI {
|
class GraphicsAPI {
|
||||||
|
|
@ -11,7 +9,7 @@ namespace Nitric {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline std::string& APIToString(API api) {
|
static inline const char* APIToString(API api) {
|
||||||
switch (api) {
|
switch (api) {
|
||||||
case Vulkan:
|
case Vulkan:
|
||||||
return "Vulkan";
|
return "Vulkan";
|
||||||
|
|
@ -22,6 +20,7 @@ namespace Nitric {
|
||||||
|
|
||||||
static void SetAPI(API api);
|
static void SetAPI(API api);
|
||||||
static API GetAPI();
|
static API GetAPI();
|
||||||
|
static API NoErrGetAPI();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static API s_API;
|
static API s_API;
|
||||||
|
|
|
||||||
17
Nitric/Source/Render/GraphicsContext.cpp
Normal file
17
Nitric/Source/Render/GraphicsContext.cpp
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
#include <Render/GraphicsContext.h>
|
||||||
|
|
||||||
|
#include <Platform/Vulkan/VkGraphicsContext.h>
|
||||||
|
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
namespace Nitric {
|
||||||
|
Scope<GraphicsContext> GraphicsContext::Create(Ref<Window> window) {
|
||||||
|
switch (GraphicsAPI::GetAPI()) {
|
||||||
|
case GraphicsAPI::Vulkan:
|
||||||
|
return CreateScope<VkGraphicsContext>(CastPtr<VkWindow>(std::move(window)));
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,11 +1,17 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <Core/Base.h>
|
||||||
|
#include <Render/GraphicsAPI.h>
|
||||||
|
#include <Core/Window.h>
|
||||||
|
|
||||||
namespace Nitric {
|
namespace Nitric {
|
||||||
|
|
||||||
class GraphicsContext {
|
class GraphicsContext {
|
||||||
public:
|
public:
|
||||||
|
virtual ~GraphicsContext() = default;
|
||||||
virtual void Init() = 0;
|
virtual void Init() = 0;
|
||||||
|
|
||||||
|
static Scope<GraphicsContext> Create(Ref<Window> window);
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -1,10 +1,12 @@
|
||||||
#include <Core/Application.h>
|
#include <Core/Application.h>
|
||||||
#include <Core/EntryPoint.h>
|
#include <Core/EntryPoint.h>
|
||||||
|
|
||||||
|
#include <Render/GraphicsAPI.h>
|
||||||
|
|
||||||
class NitricEngine : public Nitric::Application {
|
class NitricEngine : public Nitric::Application {
|
||||||
public:
|
public:
|
||||||
NitricEngine(const Nitric::ApplicationSettings& settings) : Application(settings) {
|
NitricEngine(const Nitric::ApplicationSettings& settings) : Application(settings) {
|
||||||
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -14,5 +16,7 @@ Nitric::Application* Nitric::CreateApplication() {
|
||||||
settings.Height = 720;
|
settings.Height = 720;
|
||||||
settings.Title = "Nitric Engine";
|
settings.Title = "Nitric Engine";
|
||||||
|
|
||||||
|
Nitric::GraphicsAPI::SetAPI(Nitric::GraphicsAPI::Vulkan);
|
||||||
|
|
||||||
return new NitricEngine(settings);
|
return new NitricEngine(settings);
|
||||||
}
|
}
|
||||||
Loading…
Reference in New Issue
Block a user