Compare commits
7 Commits
e9da60c056
...
44173ffdbc
| Author | SHA1 | Date |
|---|---|---|
|
|
44173ffdbc | |
|
|
2f4db7ffaf | |
|
|
20cf0876eb | |
|
|
7f66176895 | |
|
|
39732c1a27 | |
|
|
8b0a7f2622 | |
|
|
a0a84f30f8 |
|
|
@ -4,10 +4,11 @@ cmake_minimum_required( VERSION 3.13 )
|
|||
|
||||
project(Aster VERSION 0.1.0)
|
||||
|
||||
set( CMAKE_CXX_STANDARD 23 )
|
||||
set(CMAKE_CXX_STANDARD 20)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
set(CMAKE_CXX_EXTENSIONS OFF)
|
||||
|
||||
set(CMAKE_CXX_FLAGS -Wall)
|
||||
|
||||
add_subdirectory( "aster_core" )
|
||||
add_subdirectory("aster")
|
||||
add_subdirectory("triangle")
|
||||
|
|
|
|||
|
|
@ -0,0 +1,28 @@
|
|||
# CMakeList.txt ; CMake project for Aster Core
|
||||
|
||||
cmake_minimum_required(VERSION 3.13)
|
||||
|
||||
find_package(glm CONFIG REQUIRED)
|
||||
find_package(glfw3 CONFIG REQUIRED)
|
||||
find_path(SCOTTT_DEBUGBREAK_INCLUDE_DIRS "debugbreak.h")
|
||||
find_package(Vulkan REQUIRED)
|
||||
# find_package( VulkanHeaders CONFIG REQUIRED )
|
||||
find_package(fmt CONFIG REQUIRED)
|
||||
find_package(VulkanMemoryAllocator CONFIG REQUIRED)
|
||||
|
||||
set(HEADER_FILES constants.h config.h logger.h global.h context.h window.h
|
||||
physical_device.h)
|
||||
set(SOURCE_FILES logger.cpp global.cpp context.cpp window.cpp
|
||||
physical_device.cpp)
|
||||
|
||||
add_library(aster_core STATIC ${SOURCE_FILES} ${HEADER_FILES})
|
||||
set_property(TARGET aster_core PROPERTY CXX_STANDARD 20)
|
||||
|
||||
target_include_directories(aster_core PUBLIC ${CMAKE_SOURCE_DIR})
|
||||
|
||||
target_link_libraries(aster_core PUBLIC glm::glm-header-only)
|
||||
target_link_libraries(aster_core PRIVATE glfw)
|
||||
target_include_directories(aster_core PRIVATE ${SCOTTT_DEBUGBREAK_INCLUDE_DIRS})
|
||||
target_link_libraries(aster_core PRIVATE fmt::fmt)
|
||||
target_link_libraries(aster_core PRIVATE Vulkan::Vulkan Vulkan::Headers GPUOpen::VulkanMemoryAllocator)
|
||||
|
||||
|
|
@ -11,7 +11,6 @@
|
|||
#define GLFW_INCLUDE_VULKAN
|
||||
#define VULKAN_HPP_DISPATCH_LOADER_DYNAMIC 1
|
||||
#define VULKAN_HPP_NO_STRUCT_CONSTRUCTORS
|
||||
#define VULKAN_HPP_NO_EXCEPTIONS
|
||||
|
||||
#if defined(NDEBUG)
|
||||
#define USE_OPTICK (0)
|
||||
|
|
@ -93,7 +93,7 @@ using glm::mat2;
|
|||
using glm::mat3;
|
||||
using glm::mat4;
|
||||
|
||||
constexpr const char *PROJECT_NAME = "Aster";
|
||||
constexpr auto *PROJECT_NAME = "Aster";
|
||||
|
||||
struct Version {
|
||||
u32 major;
|
||||
|
|
@ -103,13 +103,8 @@ struct Version {
|
|||
|
||||
constexpr Version VERSION = {
|
||||
.major = 0,
|
||||
.minor = 0,
|
||||
.patch = 1,
|
||||
};
|
||||
|
||||
enum class Error {
|
||||
eUnknown = 1000,
|
||||
eNoDevices = 1001,
|
||||
.minor = 1,
|
||||
.patch = 0,
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
|
|
@ -16,25 +16,23 @@ VKAPI_ATTR b32 VKAPI_CALL Context::debug_callback(VkDebugUtilsMessageSeverityFla
|
|||
|
||||
if (message_type & MessageTypeBits::eValidation) {
|
||||
if (severity & SeverityBits::eError)
|
||||
ERROR(_callback_data->pMessage);
|
||||
ERROR("{}", _callback_data->pMessage);
|
||||
if (severity & SeverityBits::eWarning)
|
||||
WARN(_callback_data->pMessage);
|
||||
WARN("{}", _callback_data->pMessage);
|
||||
if (severity & SeverityBits::eInfo)
|
||||
INFO(_callback_data->pMessage);
|
||||
INFO("{}", _callback_data->pMessage);
|
||||
if (severity & SeverityBits::eVerbose)
|
||||
VERBOSE(_callback_data->pMessage);
|
||||
VERBOSE("{}", _callback_data->pMessage);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void Context::init(const std::string_view &_app_name, const Version &_app_version) {
|
||||
vk::Result result;
|
||||
|
||||
INFO_IF(enable_validation_layers, "Validation Layers enabled");
|
||||
|
||||
// Creating Instance
|
||||
vk::ApplicationInfo app_info = {
|
||||
const vk::ApplicationInfo app_info = {
|
||||
.pApplicationName = _app_name.data(),
|
||||
.applicationVersion = VK_MAKE_VERSION(_app_version.major, _app_version.minor, _app_version.patch),
|
||||
.pEngineName = PROJECT_NAME,
|
||||
|
|
@ -54,10 +52,8 @@ void Context::init(const std::string_view &_app_name, const Version &_app_versio
|
|||
};
|
||||
|
||||
u32 glfw_extension_count = 0;
|
||||
const char **glfw_extensions = nullptr;
|
||||
|
||||
glfw_extensions = glfwGetRequiredInstanceExtensions(&glfw_extension_count);
|
||||
std::vector<const char *> vulkan_extensions(glfw_extensions, glfw_extensions + glfw_extension_count);
|
||||
const char **glfw_extensions = glfwGetRequiredInstanceExtensions(&glfw_extension_count);
|
||||
std::vector vulkan_extensions(glfw_extensions, glfw_extensions + glfw_extension_count);
|
||||
if (enable_validation_layers) {
|
||||
vulkan_extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
|
||||
}
|
||||
|
|
@ -67,24 +63,29 @@ void Context::init(const std::string_view &_app_name, const Version &_app_versio
|
|||
const auto vkGetInstanceProcAddr = dl.getProcAddress<PFN_vkGetInstanceProcAddr>("vkGetInstanceProcAddr");
|
||||
VULKAN_HPP_DEFAULT_DISPATCHER.init(vkGetInstanceProcAddr);
|
||||
|
||||
tie(result, instance) = vk::createInstance({
|
||||
const auto instance_create_info = vk::InstanceCreateInfo{
|
||||
.pNext = enable_validation_layers ? &debug_messenger_create_info : nullptr,
|
||||
.pApplicationInfo = &app_info,
|
||||
.enabledLayerCount = enable_validation_layers ? cast<u32>(validation_layers.size()) : 0,
|
||||
.ppEnabledLayerNames = enable_validation_layers ? validation_layers.data() : nullptr,
|
||||
.enabledExtensionCount = cast<u32>(vulkan_extensions.size()),
|
||||
.ppEnabledExtensionNames = vulkan_extensions.data(),
|
||||
});
|
||||
ERROR_IF(failed(result), "Failed to create Vulkan instance with "s + to_string(result))
|
||||
THEN_CRASH(result)
|
||||
ELSE_INFO("Instance Created.");
|
||||
};
|
||||
|
||||
// May throw. Irrecoverable.
|
||||
instance = vk::createInstance(instance_create_info);
|
||||
INFO("Instance Created.");
|
||||
VULKAN_HPP_DEFAULT_DISPATCHER.init(instance);
|
||||
|
||||
// Debug Messenger
|
||||
if (enable_validation_layers) {
|
||||
tie(result, debug_messenger) = instance.createDebugUtilsMessengerEXT(debug_messenger_create_info);
|
||||
ERROR_IF(failed(result), "Debug Messenger creation failed with "s + to_string(result))
|
||||
ELSE_INFO("Debug Messenger Created.");
|
||||
try {
|
||||
debug_messenger = instance.createDebugUtilsMessengerEXT(debug_messenger_create_info);
|
||||
} catch (const std::exception &_err) {
|
||||
ERROR("Debug Messenger creation failed. Cause: {}", _err.what());
|
||||
// Non-critical. Continue.
|
||||
}
|
||||
INFO("Debug Messenger Created.");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -11,14 +11,15 @@ struct GlfwContext {
|
|||
static i32 post_error() noexcept {
|
||||
static const char *error_ = nullptr;
|
||||
const auto code = glfwGetError(&error_);
|
||||
ERROR("GLFW "s + error_);
|
||||
ERROR("GLFW {}", error_);
|
||||
return code;
|
||||
}
|
||||
|
||||
inline static u32 count = 0;
|
||||
|
||||
GlfwContext() {
|
||||
if (count++ > 0) return;
|
||||
if (count++ > 0)
|
||||
return;
|
||||
if (glfwInit() == GLFW_FALSE) {
|
||||
CRASH(post_error());
|
||||
}
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
// =============================================
|
||||
// Aster: global.cpp
|
||||
// Copyright (c) 2020-2024 Anish Bhobe
|
||||
// =============================================
|
||||
|
||||
#include "global.h"
|
||||
|
||||
#include <cstdarg>
|
||||
#include <cstdio>
|
||||
|
||||
#define VMA_IMPLEMENTATION
|
||||
#include <vma/vk_mem_alloc.h>
|
||||
|
||||
// NOTE: Vulkan Dispatch Loader Storage - Should only appear once.
|
||||
VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
|
||||
|
|
@ -15,25 +15,14 @@
|
|||
#include <string>
|
||||
|
||||
#define VULKAN_HPP_ASSERT(expr) DEBUG_IF(!(expr), "Vulkan assert failed")
|
||||
#include <vulkan/vulkan.hpp>
|
||||
#include <vk_mem_alloc.h>
|
||||
#include <vulkan/vulkan.hpp>
|
||||
|
||||
#define CODE_LOC " @ " __FILE__ ":" VULKAN_HPP_STRINGIFY(__LINE__)
|
||||
[[nodiscard]] inline bool failed(const vk::Result _result) {
|
||||
return _result != vk::Result::eSuccess;
|
||||
}
|
||||
|
||||
namespace std {
|
||||
namespace impl {
|
||||
string format(const char *_fmt, ...);
|
||||
}
|
||||
|
||||
template <typename... Ts>
|
||||
[[nodiscard]] string fmt(const char *_fmt, Ts &&..._args) {
|
||||
return impl::format(_fmt, forward<Ts>(_args)...);
|
||||
}
|
||||
} // namespace std
|
||||
|
||||
template <typename T>
|
||||
concept IsVkEnum = requires(T _t) {
|
||||
{ std::is_enum_v<T> };
|
||||
|
|
@ -7,6 +7,8 @@
|
|||
|
||||
#include "constants.h"
|
||||
#include <debugbreak.h>
|
||||
#include <fmt/core.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
struct Logger {
|
||||
|
|
@ -55,7 +57,7 @@ struct Logger {
|
|||
template <LogType LogLevel>
|
||||
void log(const std::string_view &_message, const char *_loc, u32 _line) const {
|
||||
if (cast<u32>(LogLevel) <= minimum_logging_level) {
|
||||
printf("%s%s %s%s| at %s:%u%s\n", to_color_cstr<LogLevel>(), to_cstr<LogLevel>(), _message.data(), ANSI_Black, _loc, _line, ANSI_Reset);
|
||||
fmt::println("{}{} {}{}| at {}:{}{}", to_color_cstr<LogLevel>(), to_cstr<LogLevel>(), _message.data(), ANSI_Black, _loc, _line, ANSI_Reset);
|
||||
}
|
||||
#if !defined(NDEBUG)
|
||||
if constexpr (LogLevel == LogType::eError) {
|
||||
|
|
@ -67,7 +69,7 @@ struct Logger {
|
|||
template <LogType LogLevel>
|
||||
void log_cond(const char *_expr_str, const std::string_view &_message, const char *_loc, u32 _line) const {
|
||||
if (cast<u32>(LogLevel) <= minimum_logging_level) {
|
||||
printf("%s%s (%s) %s%s| at %s:%u%s\n", to_color_cstr<LogLevel>(), to_cstr<LogLevel>(), _expr_str, _message.data(), ANSI_Black, _loc, _line, ANSI_Reset);
|
||||
fmt::println("{}{} ({}) {}{}| at {}:{}{}", to_color_cstr<LogLevel>(), to_cstr<LogLevel>(), _expr_str, _message.data(), ANSI_Black, _loc, _line, ANSI_Reset);
|
||||
}
|
||||
#if !defined(NDEBUG)
|
||||
if constexpr (LogLevel == LogType::eError) {
|
||||
|
|
@ -79,52 +81,53 @@ struct Logger {
|
|||
|
||||
extern Logger g_logger;
|
||||
|
||||
#define ERROR(msg) g_logger.log<Logger::LogType::eError>(msg, __FILE__, __LINE__)
|
||||
#define WARN(msg) g_logger.log<Logger::LogType::eWarning>(msg, __FILE__, __LINE__)
|
||||
#define INFO(msg) g_logger.log<Logger::LogType::eInfo>(msg, __FILE__, __LINE__)
|
||||
#define MIN_LOG_LEVEL(LOG_LVL) g_logger.set_minimum_logging_level(LOG_LVL)
|
||||
#define ERROR(...) g_logger.log<Logger::LogType::eError>(fmt::format(__VA_ARGS__), __FILE__, __LINE__)
|
||||
#define WARN(...) g_logger.log<Logger::LogType::eWarning>(fmt::format(__VA_ARGS__), __FILE__, __LINE__)
|
||||
#define INFO(...) g_logger.log<Logger::LogType::eInfo>(fmt::format(__VA_ARGS__), __FILE__, __LINE__)
|
||||
|
||||
#define ERROR_IF(expr, msg) \
|
||||
#define ERROR_IF(expr, ...) \
|
||||
if (cast<bool>(expr)) [[unlikely]] \
|
||||
g_logger.log_cond<Logger::LogType::eError>(#expr, msg, __FILE__, __LINE__)
|
||||
#define WARN_IF(expr, msg) \
|
||||
g_logger.log_cond<Logger::LogType::eError>(#expr, fmt::format(__VA_ARGS__), __FILE__, __LINE__)
|
||||
#define WARN_IF(expr, ...) \
|
||||
if (cast<bool>(expr)) [[unlikely]] \
|
||||
g_logger.log_cond<Logger::LogType::eWarning>(#expr, msg, __FILE__, __LINE__)
|
||||
#define INFO_IF(expr, msg) \
|
||||
g_logger.log_cond<Logger::LogType::eWarning>(#expr, fmt::format(__VA_ARGS__), __FILE__, __LINE__)
|
||||
#define INFO_IF(expr, ...) \
|
||||
if (cast<bool>(expr)) \
|
||||
g_logger.log_cond<Logger::LogType::eInfo>(#expr, msg, __FILE__, __LINE__)
|
||||
g_logger.log_cond<Logger::LogType::eInfo>(#expr, fmt::format(__VA_ARGS__), __FILE__, __LINE__)
|
||||
|
||||
#define ELSE_IF_ERROR(expr, msg) \
|
||||
#define ELSE_IF_ERROR(expr, ...) \
|
||||
; \
|
||||
else if (cast<bool>(expr)) [[unlikely]] g_logger.log_cond<Logger::LogType::eError>(#expr, msg, __FILE__, __LINE__)
|
||||
#define ELSE_IF_WARN(expr, msg) \
|
||||
else if (cast<bool>(expr)) [[unlikely]] g_logger.log_cond<Logger::LogType::eError>(#expr, fmt::format(__VA_ARGS__), __FILE__, __LINE__)
|
||||
#define ELSE_IF_WARN(expr, ...) \
|
||||
; \
|
||||
else if (cast<bool>(expr)) [[unlikely]] g_logger.log_cond<Logger::LogType::eWarning>(#expr, msg, __FILE__, __LINE__)
|
||||
#define ELSE_IF_INFO(expr, msg) \
|
||||
else if (cast<bool>(expr)) [[unlikely]] g_logger.log_cond<Logger::LogType::eWarning>(#expr, fmt::format(__VA_ARGS__), __FILE__, __LINE__)
|
||||
#define ELSE_IF_INFO(expr, ...) \
|
||||
; \
|
||||
else if (cast<bool>(expr)) g_logger.log_cond<Logger::LogType::eInfo>(#expr, msg, __FILE__, __LINE__)
|
||||
else if (cast<bool>(expr)) g_logger.log_cond<Logger::LogType::eInfo>(#expr, fmt::format(__VA_ARGS__), __FILE__, __LINE__)
|
||||
|
||||
#define ELSE_ERROR(msg) \
|
||||
#define ELSE_ERROR(...) \
|
||||
; \
|
||||
else [[unlikely]] g_logger.log<Logger::LogType::eError>(msg, __FILE__, __LINE__)
|
||||
#define ELSE_WARN(msg) \
|
||||
else [[unlikely]] g_logger.log<Logger::LogType::eError>(fmt::format(__VA_ARGS__), __FILE__, __LINE__)
|
||||
#define ELSE_WARN(...) \
|
||||
; \
|
||||
else [[unlikely]] g_logger.log<Logger::LogType::eWarning>(msg, __FILE__, __LINE__)
|
||||
#define ELSE_INFO(msg) \
|
||||
else [[unlikely]] g_logger.log<Logger::LogType::eWarning>(fmt::format(__VA_ARGS__), __FILE__, __LINE__)
|
||||
#define ELSE_INFO(...) \
|
||||
; \
|
||||
else g_logger.log<Logger::LogType::eInfo>(msg, __FILE__, __LINE__)
|
||||
else g_logger.log<Logger::LogType::eInfo>(fmt::format(__VA_ARGS__), __FILE__, __LINE__)
|
||||
|
||||
#if !defined(DEBUG_LOG_DISABLED) && !defined(NDEBUG)
|
||||
|
||||
#define DEBUG(msg) g_logger.log<Logger::LogType::eDebug>(msg, __FILE__, __LINE__)
|
||||
#define DEBUG_IF(expr, msg) \
|
||||
#define DEBUG(...) g_logger.log<Logger::LogType::eDebug>(fmt::format(__VA_ARGS__), __FILE__, __LINE__)
|
||||
#define DEBUG_IF(expr, ...) \
|
||||
if (cast<bool>(expr)) \
|
||||
g_logger.log_cond<Logger::LogType::eDebug>(#expr, msg, __FILE__, __LINE__)
|
||||
#define ELSE_IF_DEBUG(expr, msg) \
|
||||
g_logger.log_cond<Logger::LogType::eDebug>(#expr, fmt::format(__VA_ARGS__), __FILE__, __LINE__)
|
||||
#define ELSE_IF_DEBUG(expr, ...) \
|
||||
; \
|
||||
else if (cast<bool>(expr)) g_logger.log_cond<Logger::LogType::eDebug>(#expr, msg, __FILE__, __LINE__)
|
||||
#define ELSE_DEBUG(msg) \
|
||||
else if (cast<bool>(expr)) g_logger.log_cond<Logger::LogType::eDebug>(#expr, fmt::format(__VA_ARGS__), __FILE__, __LINE__)
|
||||
#define ELSE_DEBUG(...) \
|
||||
; \
|
||||
else [[unlikely]] g_logger.log<Logger::LogType::eDebug>(msg, __FILE__, __LINE__)
|
||||
else [[unlikely]] g_logger.log<Logger::LogType::eDebug>(fmt::format(__VA_ARGS__), __FILE__, __LINE__)
|
||||
|
||||
#else // !defined(DEBUG_LOG_DISABLED)
|
||||
|
||||
|
|
@ -145,16 +148,16 @@ extern Logger g_logger;
|
|||
|
||||
#if !defined(VERBOSE_LOG_DISABLED) && !defined(NDEBUG)
|
||||
|
||||
#define VERBOSE(msg) g_logger.log<Logger::LogType::eVerbose>(msg, __FILE__, __LINE__)
|
||||
#define VERBOSE_IF(expr, msg) \
|
||||
#define VERBOSE(...) g_logger.log<Logger::LogType::eVerbose>(fmt::format(__VA_ARGS__), __FILE__, __LINE__)
|
||||
#define VERBOSE_IF(expr, ...) \
|
||||
if (cast<bool>(expr)) \
|
||||
g_logger.log_cond<Logger::LogType::eVerbose>(#expr, msg, __FILE__, __LINE__)
|
||||
#define ELSE_IF_VERBOSE(expr, msg) \
|
||||
g_logger.log_cond<Logger::LogType::eVerbose>(#expr, fmt::format(__VA_ARGS__), __FILE__, __LINE__)
|
||||
#define ELSE_IF_VERBOSE(expr, ...) \
|
||||
; \
|
||||
else if (cast<bool>(expr)) g_logger.log_cond<Logger::LogType::eVerbose>(#expr, msg, __FILE__, __LINE__)
|
||||
#define ELSE_VERBOSE(msg) \
|
||||
else if (cast<bool>(expr)) g_logger.log_cond<Logger::LogType::eVerbose>(#expr, fmt::format(__VA_ARGS__), __FILE__, __LINE__)
|
||||
#define ELSE_VERBOSE(...) \
|
||||
; \
|
||||
else g_logger.log<Logger::LogType::eVerbose>(msg, __FILE__, __LINE__)
|
||||
else g_logger.log<Logger::LogType::eVerbose>(fmt::format(__VA_ARGS__), __FILE__, __LINE__)
|
||||
|
||||
#else // !defined(DEBUG_LOG_DISABLED)
|
||||
|
||||
|
|
@ -0,0 +1,99 @@
|
|||
// =============================================
|
||||
// Aster: physical_device.cpp
|
||||
// Copyright (c) 2020-2024 Anish Bhobe
|
||||
// =============================================
|
||||
|
||||
#include "physical_device.h"
|
||||
|
||||
[[nodiscard]] std::vector<vk::SurfaceFormatKHR> get_surface_formats(const Window *_window, const vk::PhysicalDevice *_physical_device) {
|
||||
try {
|
||||
return _physical_device->getSurfaceFormatsKHR(_window->surface);
|
||||
} catch (const std::exception &_err) {
|
||||
ERROR("Could not get surface formats. Cause: {}", _err.what());
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] std::vector<vk::PresentModeKHR> get_present_modes(const Window *_window, const vk::PhysicalDevice *_physical_device) {
|
||||
try {
|
||||
return _physical_device->getSurfacePresentModesKHR(_window->surface);
|
||||
} catch (const std::exception &_err) {
|
||||
ERROR("Could not get present modes. Cause: {}", _err.what());
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] bool get_present_support(const u32 _family_index, const Window *_window, const vk::PhysicalDevice *_device) {
|
||||
try {
|
||||
return _device->getSurfaceSupportKHR(_family_index, _window->surface);
|
||||
} catch (const std::exception &_err) {
|
||||
ERROR("Could not get queue family surface support. Cause: {}", _err.what());
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] std::vector<QueueFamilyInfo> get_queue_families(const Window *_window, const vk::PhysicalDevice *_device) {
|
||||
auto queue_family_props = _device->getQueueFamilyProperties();
|
||||
|
||||
std::vector<QueueFamilyInfo> queue_family_infos;
|
||||
queue_family_infos.reserve(queue_family_props.size());
|
||||
|
||||
u32 family_index = 0;
|
||||
for (auto qfp : queue_family_props) {
|
||||
QueueSupportFlags support = {};
|
||||
|
||||
if (qfp.queueFlags | vk::QueueFlagBits::eGraphics) {
|
||||
support |= QueueSupportFlagBits::eGraphics;
|
||||
}
|
||||
|
||||
if (qfp.queueFlags | vk::QueueFlagBits::eTransfer) {
|
||||
support |= QueueSupportFlagBits::eTransfer;
|
||||
}
|
||||
|
||||
if (qfp.queueFlags | vk::QueueFlagBits::eCompute) {
|
||||
support |= QueueSupportFlagBits::eCompute;
|
||||
}
|
||||
|
||||
if (get_present_support(family_index, _window, _device)) {
|
||||
support |= QueueSupportFlagBits::ePresent;
|
||||
}
|
||||
|
||||
queue_family_infos.push_back({
|
||||
.index = family_index,
|
||||
.count = qfp.queueCount,
|
||||
.support = support,
|
||||
});
|
||||
|
||||
family_index++;
|
||||
}
|
||||
|
||||
return queue_family_infos;
|
||||
}
|
||||
|
||||
PhysicalDevice::PhysicalDevice(const Window *_window, vk::PhysicalDevice _physical_device) {
|
||||
_physical_device.getProperties(&properties);
|
||||
_physical_device.getFeatures(&features);
|
||||
|
||||
surface_formats = get_surface_formats(_window, &_physical_device);
|
||||
present_modes = get_present_modes(_window, &_physical_device);
|
||||
queue_families = get_queue_families(_window, &_physical_device);
|
||||
|
||||
device = _physical_device;
|
||||
}
|
||||
|
||||
std::vector<vk::PhysicalDevice> enumerate_physical_devices(const Context *_context) {
|
||||
try {
|
||||
return _context->instance.enumeratePhysicalDevices();
|
||||
} catch (const std::exception &_err) {
|
||||
ERROR("Could not fetch vulkan devices. Cause: {}", _err.what());
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
PhysicalDevices::PhysicalDevices(const Window *_window, const Context *_context) {
|
||||
auto physical_devices = enumerate_physical_devices(_context);
|
||||
this->reserve(physical_devices.size());
|
||||
for (auto physical_device : physical_devices) {
|
||||
this->emplace_back(_window, physical_device);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
// =============================================
|
||||
// Aster: physical_device.h
|
||||
// Copyright (c) 2020-2024 Anish Bhobe
|
||||
// =============================================
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "global.h"
|
||||
#include "window.h"
|
||||
|
||||
enum class QueueSupportFlagBits {
|
||||
eGraphics = 0b0001,
|
||||
eTransfer = 0b0010,
|
||||
eCompute = 0b0100,
|
||||
ePresent = 0b1000,
|
||||
};
|
||||
|
||||
using QueueSupportFlags = vk::Flags<QueueSupportFlagBits>;
|
||||
|
||||
struct QueueFamilyInfo {
|
||||
u32 index;
|
||||
u32 count;
|
||||
QueueSupportFlags support;
|
||||
};
|
||||
|
||||
struct PhysicalDevice {
|
||||
vk::PhysicalDevice device;
|
||||
vk::PhysicalDeviceProperties properties;
|
||||
vk::PhysicalDeviceFeatures features;
|
||||
std::vector<vk::SurfaceFormatKHR> surface_formats;
|
||||
std::vector<vk::PresentModeKHR> present_modes;
|
||||
std::vector<QueueFamilyInfo> queue_families;
|
||||
|
||||
PhysicalDevice(const Window *_window, vk::PhysicalDevice _physical_device);
|
||||
};
|
||||
|
||||
class PhysicalDevices : public std::vector<PhysicalDevice> {
|
||||
public:
|
||||
PhysicalDevices(const Window *_window, const Context *_context);
|
||||
};
|
||||
|
|
@ -4,16 +4,12 @@
|
|||
// =============================================
|
||||
|
||||
#include "window.h"
|
||||
#include "logger.h"
|
||||
#include "context.h"
|
||||
#include "glfw_context.h"
|
||||
#include "logger.h"
|
||||
|
||||
Window::Window(const std::string_view& _title, Context* _context, vk::Extent2D _extent, b8 _full_screen)
|
||||
: parent_context{ std::move(_context) }
|
||||
, extent{ _extent }
|
||||
, name{ _title }
|
||||
, full_screen{ _full_screen } {
|
||||
|
||||
Window::Window(const std::string_view &_title, Context *_context, vk::Extent2D _extent, b8 _full_screen) :
|
||||
parent_context{ std::move(_context) }, extent{ _extent }, name{ _title }, full_screen{ _full_screen } {
|
||||
monitor = glfwGetPrimaryMonitor();
|
||||
ERROR_IF(monitor == nullptr, "No monitor found");
|
||||
|
||||
|
|
@ -24,7 +20,8 @@ Window::Window(const std::string_view& _title, Context* _context, vk::Extent2D _
|
|||
glfwWindowHint(GLFW_CENTER_CURSOR, GLFW_TRUE);
|
||||
|
||||
window = glfwCreateWindow(extent.width, extent.height, name.data(), full_screen ? monitor : nullptr, nullptr);
|
||||
ERROR_IF(window == nullptr, "Window creation failed") ELSE_INFO(std::fmt("Window '%s' created with resolution '%dx%d'", name.data(), extent.width, extent.height));
|
||||
ERROR_IF(window == nullptr, "Window creation failed")
|
||||
ELSE_INFO("Window '{}' created with resolution '{}x{}'", name, extent.width, extent.height);
|
||||
if (window == nullptr) {
|
||||
auto code = GlfwContext::post_error();
|
||||
glfwTerminate();
|
||||
|
|
@ -38,20 +35,17 @@ Window::Window(const std::string_view& _title, Context* _context, vk::Extent2D _
|
|||
|
||||
VkSurfaceKHR surface_;
|
||||
auto result = cast<vk::Result>(glfwCreateWindowSurface(cast<VkInstance>(_context->instance), window, nullptr, &surface_));
|
||||
ERROR_IF(failed(result), "Failed to create Surface with "s + to_string(result)) THEN_CRASH(result) ELSE_INFO("Surface Created");
|
||||
ERROR_IF(failed(result), "Failed to create Surface with {}", to_string(result))
|
||||
THEN_CRASH(result) ELSE_INFO("Surface Created");
|
||||
surface = vk::SurfaceKHR(surface_);
|
||||
}
|
||||
|
||||
Window::Window(Window&& _other) noexcept: parent_context{ std::move(_other.parent_context) }
|
||||
, window{ std::exchange(_other.window, nullptr) }
|
||||
, monitor{ _other.monitor }
|
||||
, surface{ std::exchange(_other.surface, nullptr) }
|
||||
, extent{ _other.extent }
|
||||
, name{ std::move(_other.name) }
|
||||
, full_screen{ _other.full_screen } {}
|
||||
Window::Window(Window &&_other) noexcept :
|
||||
parent_context{ std::move(_other.parent_context) }, window{ std::exchange(_other.window, nullptr) }, monitor{ _other.monitor }, surface{ std::exchange(_other.surface, nullptr) }, extent{ _other.extent }, name{ std::move(_other.name) }, full_screen{ _other.full_screen } {}
|
||||
|
||||
Window &Window::operator=(Window &&_other) noexcept {
|
||||
if (this == &_other) return *this;
|
||||
if (this == &_other)
|
||||
return *this;
|
||||
parent_context = std::move(_other.parent_context);
|
||||
window = _other.window;
|
||||
monitor = _other.monitor;
|
||||
|
|
@ -74,5 +68,5 @@ Window::~Window() {
|
|||
}
|
||||
monitor = nullptr;
|
||||
|
||||
INFO("Window '" + name + "' Destroyed");
|
||||
INFO("Window '{}' Destroyed", name);
|
||||
}
|
||||
|
|
@ -10,7 +10,6 @@
|
|||
#include "context.h"
|
||||
|
||||
struct Window final {
|
||||
|
||||
Window(const std::string_view &_title, Context *_context, vk::Extent2D _extent, b8 _full_screen = false);
|
||||
|
||||
Window(const Window &_other) = delete;
|
||||
|
|
@ -20,7 +19,7 @@ struct Window final {
|
|||
|
||||
~Window();
|
||||
|
||||
bool should_close() const noexcept {
|
||||
[[nodiscard]] bool should_close() const noexcept {
|
||||
return glfwWindowShouldClose(window);
|
||||
}
|
||||
|
||||
|
|
@ -1,25 +0,0 @@
|
|||
# CMakeList.txt ; CMake project for Aster Core
|
||||
|
||||
cmake_minimum_required( VERSION 3.13 )
|
||||
|
||||
find_package( glm CONFIG REQUIRED )
|
||||
find_package( glfw3 CONFIG REQUIRED )
|
||||
find_path( SCOTTT_DEBUGBREAK_INCLUDE_DIRS "debugbreak.h" )
|
||||
find_package( Vulkan REQUIRED )
|
||||
# find_package( VulkanHeaders CONFIG REQUIRED )
|
||||
find_package( VulkanMemoryAllocator CONFIG REQUIRED )
|
||||
|
||||
set( HEADER_FILES "constants.h" "config.h" "logger.h" "global.h" "context.h" "window.h" )
|
||||
set( SOURCE_FILES "logger.cpp" "global.cpp" "context.cpp" "window.cpp" )
|
||||
|
||||
add_library( aster_core ${SOURCE_FILES} ${HEADER_FILES} )
|
||||
set_property( TARGET aster_core PROPERTY CXX_STANDARD 23 )
|
||||
|
||||
target_link_libraries( aster_core PRIVATE glm::glm-header-only )
|
||||
target_link_libraries( aster_core PRIVATE glfw )
|
||||
target_include_directories( aster_core PRIVATE ${SCOTTT_DEBUGBREAK_INCLUDE_DIRS})
|
||||
target_link_libraries( aster_core PRIVATE Vulkan::Vulkan Vulkan::Headers GPUOpen::VulkanMemoryAllocator )
|
||||
|
||||
add_executable( aster_exe "aster.cpp" )
|
||||
target_link_libraries( aster_exe PRIVATE aster_core )
|
||||
target_link_libraries( aster_exe PRIVATE glm::glm-header-only )
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
#include <iostream>
|
||||
#include "constants.h"
|
||||
#include "glfw_context.h"
|
||||
#include "window.h"
|
||||
|
||||
int main(int, char**) {
|
||||
|
||||
GlfwContext* glfw = new GlfwContext();
|
||||
Context* context = new Context("Aster", VERSION);
|
||||
Window* window = new Window("Aster1", context, { 640, 480 });
|
||||
|
||||
delete window;
|
||||
delete context;
|
||||
delete glfw;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -1,72 +0,0 @@
|
|||
// =============================================
|
||||
// Aster: global.cpp
|
||||
// Copyright (c) 2020-2024 Anish Bhobe
|
||||
// =============================================
|
||||
|
||||
#include "global.h"
|
||||
|
||||
#include <cstdarg>
|
||||
#include <cstdio>
|
||||
|
||||
#define VMA_IMPLEMENTATION
|
||||
#include <vma/vk_mem_alloc.h>
|
||||
|
||||
// NOTE: Vulkan Dispatch Loader Storage - Should only appear once.
|
||||
VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
|
||||
|
||||
//int Vsnprintf8(char* pDestination, size_t n, const char* pFormat, va_list arguments) {
|
||||
// //ERROR_IF(pDestination == nullptr, "Null buffer") THEN_CRASH(1) ELSE_IF_ERROR(n == 0, "Empty buffer") THEN_CRASH(1);
|
||||
//#ifdef _MSC_VER
|
||||
// auto v = vsnprintf(pDestination, n, pFormat, arguments);
|
||||
// ERROR_IF(v == 0, "Final requirement cannot be 0") THEN_CRASH(1);
|
||||
// return v;
|
||||
//#else
|
||||
// return vsnprintf(pDestination, n, pFormat, arguments);
|
||||
//#endif
|
||||
//}
|
||||
//
|
||||
//int VsnprintfW(wchar_t* pDestination, size_t n, const wchar_t* pFormat, va_list arguments) {
|
||||
// //ERROR_IF(pDestination == nullptr, "Null buffer") THEN_CRASH(1) ELSE_IF_ERROR(n == 0, "Empty buffer") THEN_CRASH(1);
|
||||
//#ifdef _MSC_VER
|
||||
// if (pDestination == nullptr && n == 0) {
|
||||
// return _vscwprintf(pFormat, arguments);
|
||||
// } else {
|
||||
// return _vsnwprintf_s(pDestination, n, _TRUNCATE, pFormat, arguments);
|
||||
// }
|
||||
//#else
|
||||
// char* d = new char[n + 1];
|
||||
// int r = vsnprintf(d, n, convertstring<char16_t, char>(pFormat).c_str(), arguments);
|
||||
// memcpy(pDestination, convertstring<char, char16_t>(d).c_str(), (n + 1) * sizeof(char16_t));
|
||||
// delete[] d;
|
||||
// return r;
|
||||
//#endif
|
||||
//}
|
||||
//
|
||||
//int Vsnprintf16(char16_t* pDestination, size_t n, const char16_t* pFormat, va_list arguments) {
|
||||
// //ERROR_IF(pDestination == nullptr, "Null buffer") THEN_CRASH(1) ELSE_IF_ERROR(n == 0, "Empty buffer") THEN_CRASH(1);
|
||||
//#ifdef _MSC_VER
|
||||
// if (pDestination == nullptr && n == 0) {
|
||||
// return _vscwprintf((wchar_t*)pFormat, arguments);
|
||||
// } else {
|
||||
// return _vsnwprintf_s((wchar_t*)pDestination, n, _TRUNCATE, (wchar_t*)pFormat, arguments);
|
||||
// }
|
||||
//#else
|
||||
// char* d = new char[n + 1];
|
||||
// int r = vsnprintf(d, n, convertstring<char16_t, char>(pFormat).c_str(), arguments);
|
||||
// memcpy(pDestination, convertstring<char, char16_t>(d).c_str(), (n + 1) * sizeof(char16_t));
|
||||
// delete[] d;
|
||||
// return r;
|
||||
//#endif
|
||||
//}
|
||||
|
||||
std::string std::impl::format(const char *_fmt, ...) {
|
||||
va_list args;
|
||||
va_start(args, _fmt);
|
||||
|
||||
const auto req = vsnprintf(nullptr, 0, _fmt, args) + 1;
|
||||
string buf(req, '\0');
|
||||
vsnprintf(buf.data(), buf.size(), _fmt, args);
|
||||
|
||||
va_end(args);
|
||||
return buf;
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
# CMakeList.txt ; CMake project for Aster Core
|
||||
|
||||
cmake_minimum_required(VERSION 3.13)
|
||||
|
||||
add_executable(aster_exe "aster.cpp")
|
||||
add_dependencies(aster_exe aster_core)
|
||||
|
||||
target_link_libraries(aster_exe PRIVATE aster_core)
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
#include "aster/constants.h"
|
||||
#include "aster/glfw_context.h"
|
||||
#include "aster/physical_device.h"
|
||||
#include "aster/window.h"
|
||||
|
||||
constexpr QueueSupportFlags required_queue_support = QueueSupportFlags{} | QueueSupportFlagBits::eGraphics | QueueSupportFlagBits::eCompute | QueueSupportFlagBits::ePresent | QueueSupportFlagBits::eCompute;
|
||||
|
||||
[[nodiscard]] bool is_suitable_device(const PhysicalDevice *_physical_device) {
|
||||
const bool all_required_queues = std::ranges::any_of(_physical_device->queue_families, [](const auto &_qfp) {
|
||||
return (_qfp.support & required_queue_support) == required_queue_support;
|
||||
});
|
||||
|
||||
const bool device_type_check = _physical_device->properties.deviceType != vk::PhysicalDeviceType::eCpu;
|
||||
|
||||
const bool supported_present_mode = !_physical_device->present_modes.empty();
|
||||
|
||||
const bool supported_format = !_physical_device->surface_formats.empty();
|
||||
|
||||
return supported_format && supported_present_mode && device_type_check && all_required_queues;
|
||||
}
|
||||
|
||||
PhysicalDevice find_suitable_device(const PhysicalDevices &_physical_devices) {
|
||||
for (auto &_physical_device : _physical_devices) {
|
||||
if (is_suitable_device(&_physical_device)) {
|
||||
return _physical_device;
|
||||
}
|
||||
}
|
||||
throw std::runtime_error("No suitable device found.");
|
||||
}
|
||||
|
||||
int main(int, char **) {
|
||||
const auto *glfw = new GlfwContext();
|
||||
auto *context = new Context("Aster", VERSION);
|
||||
auto *window = new Window("Aster1", context, { 640, 480 });
|
||||
|
||||
PhysicalDevices physical_devices = { window, context };
|
||||
PhysicalDevice device_to_use = find_suitable_device(physical_devices);
|
||||
|
||||
INFO("Using {} as the primary device.", device_to_use.properties.deviceName.data());
|
||||
|
||||
while (window->poll()) {
|
||||
}
|
||||
|
||||
delete window;
|
||||
delete context;
|
||||
delete glfw;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -3,6 +3,7 @@
|
|||
"glfw3",
|
||||
"glm",
|
||||
"scottt-debugbreak",
|
||||
"vulkan-memory-allocator"
|
||||
"vulkan-memory-allocator",
|
||||
"fmt"
|
||||
]
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue