Compare commits
10 Commits
385c6740e0
...
31efa504a3
| Author | SHA1 | Date |
|---|---|---|
|
|
31efa504a3 | |
|
|
7f8e18ff97 | |
|
|
60a7609963 | |
|
|
131a55c868 | |
|
|
688b34c926 | |
|
|
6e8e2c6c80 | |
|
|
3032b9a43d | |
|
|
8a4138eec3 | |
|
|
cd8ab16ad2 | |
|
|
e9da60c056 |
|
|
@ -1,13 +1,13 @@
|
||||||
# CMakeLists.txt ; Top-level CMake project file.
|
# CMakeLists.txt ; Top-level CMake project file.
|
||||||
|
|
||||||
cmake_minimum_required( VERSION 3.13 )
|
cmake_minimum_required(VERSION 3.13)
|
||||||
|
|
||||||
project( Aster VERSION 0.1.0 )
|
project(Aster VERSION 0.1.0)
|
||||||
|
|
||||||
set( CMAKE_CXX_STANDARD 20 )
|
set(CMAKE_CXX_STANDARD 23)
|
||||||
set( CMAKE_CXX_STANDARD_REQUIRED ON )
|
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||||
set( CMAKE_CXX_EXTENSIONS OFF )
|
set(CMAKE_CXX_EXTENSIONS OFF)
|
||||||
|
|
||||||
|
set(CMAKE_CXX_FLAGS -Wall)
|
||||||
|
|
||||||
|
add_subdirectory("aster_core")
|
||||||
add_subdirectory( "aster_core" )
|
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,42 @@
|
||||||
# CMakeList.txt ; CMake project for Blaze
|
# CMakeList.txt ; CMake project for Aster Core
|
||||||
|
|
||||||
cmake_minimum_required( VERSION 3.13 )
|
cmake_minimum_required(VERSION 3.13)
|
||||||
|
|
||||||
find_package( glm CONFIG REQUIRED )
|
find_package(glm CONFIG REQUIRED)
|
||||||
find_path( SCOTTT_DEBUGBREAK_INCLUDE_DIRS "debugbreak.h" )
|
find_package(glfw3 CONFIG REQUIRED)
|
||||||
find_package( VulkanHeaders CONFIG REQUIRED )
|
find_path(SCOTTT_DEBUGBREAK_INCLUDE_DIRS "debugbreak.h")
|
||||||
find_package( VulkanMemoryAllocator CONFIG REQUIRED )
|
find_package(Vulkan REQUIRED)
|
||||||
|
# find_package( VulkanHeaders CONFIG REQUIRED )
|
||||||
|
find_package(VulkanMemoryAllocator CONFIG REQUIRED)
|
||||||
|
find_package(fmt CONFIG REQUIRED)
|
||||||
|
|
||||||
set( HEADER_FILES "constants.h" "config.h" "logger.h" "global.h" )
|
set(HEADER_FILES
|
||||||
set( SOURCE_FILES "logger.cpp" "global.cpp" )
|
constants.h
|
||||||
|
config.h
|
||||||
|
logger.h
|
||||||
|
global.h
|
||||||
|
context.h
|
||||||
|
window.h
|
||||||
|
device.h
|
||||||
|
physical_device.h)
|
||||||
|
|
||||||
add_library( aster_core "aster.cpp" ${SOURCE_FILES} ${HEADER_FILES} )
|
set(SOURCE_FILES
|
||||||
set_property( TARGET aster_core PROPERTY CXX_STANDARD 20 )
|
logger.cpp
|
||||||
|
global.cpp
|
||||||
|
context.cpp
|
||||||
|
window.cpp
|
||||||
|
device.cpp
|
||||||
|
physical_device.cpp)
|
||||||
|
|
||||||
target_link_libraries( aster_core PRIVATE glm::glm-header-only )
|
add_library(aster_core ${SOURCE_FILES} ${HEADER_FILES})
|
||||||
target_include_directories( aster_core PRIVATE ${SCOTTT_DEBUGBREAK_INCLUDE_DIRS})
|
set_property(TARGET aster_core PROPERTY CXX_STANDARD 23)
|
||||||
target_link_libraries( aster_core PRIVATE Vulkan::Headers GPUOpen::VulkanMemoryAllocator )
|
|
||||||
|
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)
|
||||||
|
target_link_libraries(aster_core PRIVATE fmt::fmt)
|
||||||
|
|
||||||
|
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,10 +1,38 @@
|
||||||
#include <iostream>
|
#include "constants.h"
|
||||||
#include <glm/glm.hpp>
|
#include "glfw_context.h"
|
||||||
|
#include "physical_device.h"
|
||||||
|
#include "window.h"
|
||||||
|
|
||||||
int main(int, char**) {
|
bool suitable_device(const PhysicalDevice *physical_device) {
|
||||||
|
constexpr auto required_support = QueueSupportFlags{} | QueueSupportFlagBits::eGraphics | QueueSupportFlagBits::ePresent | QueueSupportFlagBits::eTransfer;
|
||||||
printf("Hello World\n");
|
|
||||||
|
|
||||||
return 0;
|
return physical_device->properties.deviceType != vk::PhysicalDeviceType::eCpu &&
|
||||||
|
!physical_device->surface_formats.empty() &&
|
||||||
|
!physical_device->present_modes.empty() &&
|
||||||
|
cast<bool>(physical_device->queue_support & required_support);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PhysicalDevice find_suitable_device(PhysicalDevices &&_physical_devices) {
|
||||||
|
for (auto physdev : _physical_devices) {
|
||||||
|
VERBOSE(fmt::format("Checking device: {}", physdev.properties.deviceName.data()));
|
||||||
|
if (suitable_device(&physdev)) {
|
||||||
|
VERBOSE(fmt::format("Found suitable device {}.", physdev.properties.deviceName.data()));
|
||||||
|
return physdev;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw std::runtime_error("No suitable physical device found.");
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int, char **) {
|
||||||
|
GlfwContext glfw = {};
|
||||||
|
Context context = { "Aster", VERSION };
|
||||||
|
Window window = { "Aster1", &context, { 640, 480 } };
|
||||||
|
|
||||||
|
PhysicalDevice physical_device = find_suitable_device({ &window, &context });
|
||||||
|
INFO(fmt::format("Using Device {}", physical_device.properties.deviceName.data()));
|
||||||
|
|
||||||
|
while (window.poll()) {
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,6 @@
|
||||||
#define GLFW_INCLUDE_VULKAN
|
#define GLFW_INCLUDE_VULKAN
|
||||||
#define VULKAN_HPP_DISPATCH_LOADER_DYNAMIC 1
|
#define VULKAN_HPP_DISPATCH_LOADER_DYNAMIC 1
|
||||||
#define VULKAN_HPP_NO_STRUCT_CONSTRUCTORS
|
#define VULKAN_HPP_NO_STRUCT_CONSTRUCTORS
|
||||||
#define VULKAN_HPP_NO_EXCEPTIONS
|
|
||||||
|
|
||||||
#if defined(NDEBUG)
|
#if defined(NDEBUG)
|
||||||
#define USE_OPTICK (0)
|
#define USE_OPTICK (0)
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,13 @@ using usize = size_t;
|
||||||
using p64 = intptr_t;
|
using p64 = intptr_t;
|
||||||
|
|
||||||
constexpr usize strlen_c(const char *s) {
|
constexpr usize strlen_c(const char *s) {
|
||||||
return *s == '\0' ? 0 : 1 + strlen_c(s + 1);
|
usize len = 0;
|
||||||
|
char c = '\0';
|
||||||
|
do {
|
||||||
|
c = s[len];
|
||||||
|
len++;
|
||||||
|
} while (c != '\0');
|
||||||
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr auto ANSI_Black = "\u001b[30m";
|
constexpr auto ANSI_Black = "\u001b[30m";
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@
|
||||||
|
|
||||||
#include "context.h"
|
#include "context.h"
|
||||||
|
|
||||||
VKAPI_ATTR b32 VKAPI_CALL Context::debug_callback(VkDebugUtilsMessageSeverityFlagBitsEXT _message_severity, VkDebugUtilsMessageTypeFlagsEXT _message_type, const VkDebugUtilsMessengerCallbackDataEXT *_callback_data, [[maybe_unused]] void *_user_data) {
|
VKAPI_ATTR b32 VKAPI_CALL Context::debug_callback(const VkDebugUtilsMessageSeverityFlagBitsEXT _message_severity, const VkDebugUtilsMessageTypeFlagsEXT _message_type, const VkDebugUtilsMessengerCallbackDataEXT *_callback_data, [[maybe_unused]] void *_user_data) {
|
||||||
using Severity = vk::DebugUtilsMessageSeverityFlagsEXT;
|
using Severity = vk::DebugUtilsMessageSeverityFlagsEXT;
|
||||||
using SeverityBits = vk::DebugUtilsMessageSeverityFlagBitsEXT;
|
using SeverityBits = vk::DebugUtilsMessageSeverityFlagBitsEXT;
|
||||||
using MessageType = vk::DebugUtilsMessageTypeFlagsEXT;
|
using MessageType = vk::DebugUtilsMessageTypeFlagsEXT;
|
||||||
|
|
@ -29,8 +29,6 @@ VKAPI_ATTR b32 VKAPI_CALL Context::debug_callback(VkDebugUtilsMessageSeverityFla
|
||||||
}
|
}
|
||||||
|
|
||||||
void Context::init(const std::string_view &_app_name, const Version &_app_version) {
|
void Context::init(const std::string_view &_app_name, const Version &_app_version) {
|
||||||
vk::Result result;
|
|
||||||
|
|
||||||
INFO_IF(enable_validation_layers, "Validation Layers enabled");
|
INFO_IF(enable_validation_layers, "Validation Layers enabled");
|
||||||
|
|
||||||
// Creating Instance
|
// Creating Instance
|
||||||
|
|
@ -54,9 +52,7 @@ void Context::init(const std::string_view &_app_name, const Version &_app_versio
|
||||||
};
|
};
|
||||||
|
|
||||||
u32 glfw_extension_count = 0;
|
u32 glfw_extension_count = 0;
|
||||||
const char **glfw_extensions = nullptr;
|
const char **glfw_extensions = glfwGetRequiredInstanceExtensions(&glfw_extension_count);
|
||||||
|
|
||||||
glfw_extensions = glfwGetRequiredInstanceExtensions(&glfw_extension_count);
|
|
||||||
std::vector<const char *> vulkan_extensions(glfw_extensions, glfw_extensions + glfw_extension_count);
|
std::vector<const char *> vulkan_extensions(glfw_extensions, glfw_extensions + glfw_extension_count);
|
||||||
if (enable_validation_layers) {
|
if (enable_validation_layers) {
|
||||||
vulkan_extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
|
vulkan_extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
|
||||||
|
|
@ -67,33 +63,31 @@ void Context::init(const std::string_view &_app_name, const Version &_app_versio
|
||||||
const auto vkGetInstanceProcAddr = dl.getProcAddress<PFN_vkGetInstanceProcAddr>("vkGetInstanceProcAddr");
|
const auto vkGetInstanceProcAddr = dl.getProcAddress<PFN_vkGetInstanceProcAddr>("vkGetInstanceProcAddr");
|
||||||
VULKAN_HPP_DEFAULT_DISPATCHER.init(vkGetInstanceProcAddr);
|
VULKAN_HPP_DEFAULT_DISPATCHER.init(vkGetInstanceProcAddr);
|
||||||
|
|
||||||
tie(result, instance) = vk::createInstance({
|
try {
|
||||||
.pNext = enable_validation_layers ? &debug_messenger_create_info : nullptr,
|
instance = vk::raii::Instance{ raii_context, {
|
||||||
.pApplicationInfo = &app_info,
|
.pNext = enable_validation_layers ? &debug_messenger_create_info : nullptr,
|
||||||
.enabledLayerCount = enable_validation_layers ? cast<u32>(validation_layers.size()) : 0,
|
.pApplicationInfo = &app_info,
|
||||||
.ppEnabledLayerNames = enable_validation_layers ? validation_layers.data() : nullptr,
|
.enabledLayerCount = enable_validation_layers ? cast<u32>(validation_layers.size()) : 0,
|
||||||
.enabledExtensionCount = cast<u32>(vulkan_extensions.size()),
|
.ppEnabledLayerNames = enable_validation_layers ? validation_layers.data() : nullptr,
|
||||||
.ppEnabledExtensionNames = vulkan_extensions.data(),
|
.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)
|
} catch (const std::exception &err) {
|
||||||
ELSE_INFO("Instance Created.");
|
ERROR("Failed to create Vulkan instance with "s + err.what());
|
||||||
VULKAN_HPP_DEFAULT_DISPATCHER.init(instance);
|
throw;
|
||||||
|
}
|
||||||
|
INFO("Instance Created.");
|
||||||
|
|
||||||
// Debug Messenger
|
// Debug Messenger
|
||||||
if (enable_validation_layers) {
|
if (enable_validation_layers) {
|
||||||
tie(result, debug_messenger) = instance.createDebugUtilsMessengerEXT(debug_messenger_create_info);
|
try {
|
||||||
ERROR_IF(failed(result), "Debug Messenger creation failed with "s + to_string(result))
|
debug_messenger = vk::raii::DebugUtilsMessengerEXT{ instance, debug_messenger_create_info };
|
||||||
ELSE_INFO("Debug Messenger Created.");
|
} catch (const std::exception &err) {
|
||||||
|
ERROR("Debug Messenger creation failed with "s + err.what());
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
INFO("Debug Messenger Created.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Context::~Context() {
|
Context::~Context() = default;
|
||||||
if (instance) {
|
|
||||||
if (enable_validation_layers && debug_messenger) {
|
|
||||||
instance.destroyDebugUtilsMessengerEXT(debug_messenger);
|
|
||||||
}
|
|
||||||
instance.destroy();
|
|
||||||
INFO("Context destroyed");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -73,8 +73,9 @@ public:
|
||||||
VK_KHR_MULTIVIEW_EXTENSION_NAME,
|
VK_KHR_MULTIVIEW_EXTENSION_NAME,
|
||||||
};
|
};
|
||||||
|
|
||||||
vk::Instance instance;
|
vk::raii::Context raii_context;
|
||||||
vk::DebugUtilsMessengerEXT debug_messenger;
|
vk::raii::Instance instance{ nullptr };
|
||||||
|
vk::raii::DebugUtilsMessengerEXT debug_messenger{ nullptr };
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void init(const std::string_view &_app_name, const Version &_app_version);
|
void init(const std::string_view &_app_name, const Version &_app_version);
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,94 @@
|
||||||
|
// =============================================
|
||||||
|
// Aster: device.cpp
|
||||||
|
// Copyright (c) 2020-2024 Anish Bhobe
|
||||||
|
// =============================================
|
||||||
|
|
||||||
|
#include "device.h"
|
||||||
|
|
||||||
|
#include "context.h"
|
||||||
|
#include "window.h"
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
#include <set>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
Device::Device(Device &&_other) noexcept :
|
||||||
|
physical_device{ std::move(_other.physical_device) },
|
||||||
|
device{ std::exchange(_other.device, nullptr) },
|
||||||
|
allocator{ std::exchange(_other.allocator, nullptr) },
|
||||||
|
name{ std::move(_other.name) } {}
|
||||||
|
|
||||||
|
Device &Device::operator=(Device &&_other) noexcept {
|
||||||
|
if (this == &_other)
|
||||||
|
return *this;
|
||||||
|
physical_device = std::move(_other.physical_device);
|
||||||
|
device = std::exchange(_other.device, nullptr);
|
||||||
|
allocator = std::exchange(_other.allocator, nullptr);
|
||||||
|
name = std::move(_other.name);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Device::Device(const std::string_view &_name, Context *_context, const PhysicalDevice &_physical_device_info, const vk::PhysicalDeviceFeatures &_enabled_features, std::set<QueueAllocation> &&_enabled_queues) :
|
||||||
|
physical_device{ _physical_device_info },
|
||||||
|
name{ _name } {
|
||||||
|
const auto &physical_device = _physical_device_info.device;
|
||||||
|
|
||||||
|
// Logical Device
|
||||||
|
std::vector queue_priority(_enabled_queues.size(), 1.0f);
|
||||||
|
std::vector<vk::DeviceQueueCreateInfo> queue_create_infos;
|
||||||
|
queue_create_infos.reserve(_enabled_queues.size());
|
||||||
|
for (auto &[family_, count_] : _enabled_queues) {
|
||||||
|
queue_create_infos.push_back({
|
||||||
|
.queueFamilyIndex = family_,
|
||||||
|
.queueCount = count_,
|
||||||
|
.pQueuePriorities = queue_priority.data(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
device = physical_device.createDevice({
|
||||||
|
.queueCreateInfoCount = cast<u32>(queue_create_infos.size()),
|
||||||
|
.pQueueCreateInfos = queue_create_infos.data(),
|
||||||
|
.enabledLayerCount = _context->enable_validation_layers ? cast<u32>(_context->validation_layers.size()) : 0,
|
||||||
|
.ppEnabledLayerNames = _context->enable_validation_layers ? _context->validation_layers.data() : nullptr,
|
||||||
|
.enabledExtensionCount = cast<u32>(_context->device_extensions.size()),
|
||||||
|
.ppEnabledExtensionNames = _context->device_extensions.data(),
|
||||||
|
.pEnabledFeatures = &_enabled_features,
|
||||||
|
});
|
||||||
|
} catch (const std::exception &err) {
|
||||||
|
ERROR("Failed to create a logical device with "s + err.what());
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
INFO("Logical Device Created!");
|
||||||
|
|
||||||
|
const VmaAllocatorCreateInfo allocator_create_info = {
|
||||||
|
.physicalDevice = *physical_device,
|
||||||
|
.device = *device,
|
||||||
|
.instance = *_context->instance,
|
||||||
|
};
|
||||||
|
|
||||||
|
allocator = nullptr;
|
||||||
|
const auto result = cast<vk::Result>(vmaCreateAllocator(&allocator_create_info, &allocator));
|
||||||
|
if (failed(result)) {
|
||||||
|
ERROR("Memory allocator creation failed with "s + vk::to_string(result));
|
||||||
|
throw std::runtime_error("Memory allocator creation failed with "s + vk::to_string(result));
|
||||||
|
}
|
||||||
|
VERBOSE("Memory Allocator Created");
|
||||||
|
|
||||||
|
INFO(fmt::format("Created Device '{}' Successfully", _name));
|
||||||
|
|
||||||
|
set_name(_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
Device::~Device() {
|
||||||
|
if (allocator) {
|
||||||
|
vmaDestroyAllocator(allocator);
|
||||||
|
}
|
||||||
|
INFO("Device '" + name + "' Destroyed");
|
||||||
|
}
|
||||||
|
|
||||||
|
void Device::set_name(const std::string_view &_name) {
|
||||||
|
VERBOSE(fmt::format("Device {} -> {}", name.data(), _name.data()));
|
||||||
|
name = _name;
|
||||||
|
set_object_name(*physical_device.device, fmt::format("{} GPU", _name.data()));
|
||||||
|
set_object_name(*device, fmt::format("{} Device", _name.data()));
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,57 @@
|
||||||
|
// =============================================
|
||||||
|
// Aster: device.h
|
||||||
|
// Copyright (c) 2020-2024 Anish Bhobe
|
||||||
|
// =============================================
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "context.h"
|
||||||
|
#include "global.h"
|
||||||
|
#include "physical_device.h"
|
||||||
|
#include "window.h"
|
||||||
|
|
||||||
|
#include <iterator>
|
||||||
|
#include <set>
|
||||||
|
#include <span>
|
||||||
|
#include <string_view>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
struct QueueAllocation {
|
||||||
|
u32 family;
|
||||||
|
u32 count;
|
||||||
|
};
|
||||||
|
|
||||||
|
class Device {
|
||||||
|
public:
|
||||||
|
Device(const Device &_other) = delete;
|
||||||
|
Device(Device &&_other) noexcept;
|
||||||
|
Device &operator=(const Device &_other) = delete;
|
||||||
|
Device &operator=(Device &&_other) noexcept;
|
||||||
|
|
||||||
|
Device(const std::string_view &_name, Context *_context, const PhysicalDevice &_physical_device_info, const vk::PhysicalDeviceFeatures &_enabled_features, std::set<QueueAllocation> &&_enabled_queues);
|
||||||
|
|
||||||
|
~Device();
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
requires vk::isVulkanHandleType<T>::value void set_object_name(const T &_obj, const std::string_view &_name) const {
|
||||||
|
try {
|
||||||
|
device.setDebugUtilsObjectNameEXT({
|
||||||
|
.objectType = _obj.objectType,
|
||||||
|
.objectHandle = get_vk_handle(_obj),
|
||||||
|
.pObjectName = _name.data(),
|
||||||
|
});
|
||||||
|
} catch (const std::exception &err) {
|
||||||
|
WARN("Debug Utils name setting failed with "s + err.what());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// fields
|
||||||
|
PhysicalDevice physical_device;
|
||||||
|
vk::raii::Device device{ nullptr };
|
||||||
|
VmaAllocator allocator;
|
||||||
|
|
||||||
|
std::string name;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void set_name(const std::string_view &_name);
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1,34 @@
|
||||||
|
// =============================================
|
||||||
|
// Aster: glfw_context.h
|
||||||
|
// Copyright (c) 2020-2024 Anish Bhobe
|
||||||
|
// =============================================
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "global.h"
|
||||||
|
|
||||||
|
struct GlfwContext {
|
||||||
|
static i32 post_error() noexcept {
|
||||||
|
static const char *error_ = nullptr;
|
||||||
|
const auto code = glfwGetError(&error_);
|
||||||
|
ERROR("GLFW "s + error_);
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline static u32 count = 0;
|
||||||
|
|
||||||
|
GlfwContext() {
|
||||||
|
if (count++ > 0)
|
||||||
|
return;
|
||||||
|
if (glfwInit() == GLFW_FALSE) {
|
||||||
|
CRASH(post_error());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
~GlfwContext() {
|
||||||
|
if (--count == 0) {
|
||||||
|
glfwTerminate();
|
||||||
|
}
|
||||||
|
count = 0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
@ -8,67 +8,8 @@
|
||||||
#include <cstdarg>
|
#include <cstdarg>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
|
|
||||||
#pragma warning(push, 0)
|
|
||||||
#define VMA_IMPLEMENTATION
|
#define VMA_IMPLEMENTATION
|
||||||
#include <vma/vk_mem_alloc.h>
|
#include <vma/vk_mem_alloc.h>
|
||||||
#pragma warning(pop)
|
|
||||||
|
|
||||||
// NOTE: Vulkan Dispatch Loader Storage - Should only appear once.
|
// NOTE: Vulkan Dispatch Loader Storage - Should only appear once.
|
||||||
VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
|
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;
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -10,33 +10,20 @@
|
||||||
#include "logger.h"
|
#include "logger.h"
|
||||||
|
|
||||||
#include <GLFW/glfw3.h>
|
#include <GLFW/glfw3.h>
|
||||||
|
#include <fmt/core.h>
|
||||||
#include <glm/glm.hpp>
|
#include <glm/glm.hpp>
|
||||||
#include <glm/gtc/matrix_transform.hpp>
|
#include <glm/gtc/matrix_transform.hpp>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#define VULKAN_HPP_ASSERT(expr) DEBUG_IF(!(expr), "Vulkan assert failed")
|
#define VULKAN_HPP_ASSERT(expr) DEBUG_IF(!(expr), "Vulkan assert failed")
|
||||||
#include <vulkan/vulkan.hpp>
|
|
||||||
|
|
||||||
#pragma warning(push, 0)
|
|
||||||
#include <vk_mem_alloc.h>
|
#include <vk_mem_alloc.h>
|
||||||
#pragma warning(pop)
|
#include <vulkan/vulkan_raii.hpp>
|
||||||
|
|
||||||
#define CODE_LOC " @ " __FILE__ ":" VULKAN_HPP_STRINGIFY(__LINE__)
|
#define CODE_LOC " @ " __FILE__ ":" VULKAN_HPP_STRINGIFY(__LINE__)
|
||||||
[[nodiscard]] inline bool failed(const vk::Result _result) {
|
[[nodiscard]] inline bool failed(const vk::Result _result) {
|
||||||
return _result != vk::Result::eSuccess;
|
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>
|
template <typename T>
|
||||||
concept IsVkEnum = requires(T _t) {
|
concept IsVkEnum = requires(T _t) {
|
||||||
{ std::is_enum_v<T> };
|
{ std::is_enum_v<T> };
|
||||||
|
|
@ -57,7 +44,7 @@ using namespace std::literals::string_view_literals;
|
||||||
template <typename T>
|
template <typename T>
|
||||||
requires vk::isVulkanHandleType<T>::value [[nodiscard]] constexpr u64
|
requires vk::isVulkanHandleType<T>::value [[nodiscard]] constexpr u64
|
||||||
get_vk_handle(const T &_vk_handle) noexcept {
|
get_vk_handle(const T &_vk_handle) noexcept {
|
||||||
return reinterpret_cast<u64>(cast<T::CType>(_vk_handle));
|
return reinterpret_cast<u64>(cast<typename T::CType>(_vk_handle));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename F>
|
template <typename F>
|
||||||
|
|
|
||||||
|
|
@ -5,13 +5,4 @@
|
||||||
|
|
||||||
#include "logger.h"
|
#include "logger.h"
|
||||||
|
|
||||||
Logger g_logger = Logger();
|
auto g_logger = Logger();
|
||||||
|
|
||||||
/* Credits to Const-me */
|
|
||||||
//namespace eastl {
|
|
||||||
// void __cdecl AssertionFailure(const char* af)
|
|
||||||
// {
|
|
||||||
// ERROR(af);
|
|
||||||
// __debugbreak();
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
|
|
|
||||||
|
|
@ -36,6 +36,7 @@ struct Logger {
|
||||||
return "[DEBUG]:";
|
return "[DEBUG]:";
|
||||||
if constexpr (LogLevel == LogType::eVerbose)
|
if constexpr (LogLevel == LogType::eVerbose)
|
||||||
return "[VERB]: ";
|
return "[VERB]: ";
|
||||||
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
template <LogType LogLevel>
|
template <LogType LogLevel>
|
||||||
|
|
@ -50,6 +51,7 @@ struct Logger {
|
||||||
return ANSI_White;
|
return ANSI_White;
|
||||||
if constexpr (LogLevel == LogType::eVerbose)
|
if constexpr (LogLevel == LogType::eVerbose)
|
||||||
return ANSI_Blue;
|
return ANSI_Blue;
|
||||||
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
template <LogType LogLevel>
|
template <LogType LogLevel>
|
||||||
|
|
@ -65,7 +67,7 @@ struct Logger {
|
||||||
}
|
}
|
||||||
|
|
||||||
template <LogType LogLevel>
|
template <LogType LogLevel>
|
||||||
void log_cond(const char *_expr_str, const std::string_view &_message, const char *_loc, u32 _line) const {
|
void log_cond(const char *_expr_str, const std::string_view &_message, const char *_loc, const u32 _line) const {
|
||||||
if (cast<u32>(LogLevel) <= minimum_logging_level) {
|
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);
|
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);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,49 @@
|
||||||
|
// =============================================
|
||||||
|
// Aster: physical_device.cpp
|
||||||
|
// Copyright (c) 2020-2024 Anish Bhobe
|
||||||
|
// =============================================
|
||||||
|
|
||||||
|
#include "physical_device.h"
|
||||||
|
|
||||||
|
std::vector<QueueFamilyInfo> PhysicalDevice::get_queue_families(const Window *_window) const {
|
||||||
|
auto queue_families_ = device.getQueueFamilyProperties();
|
||||||
|
|
||||||
|
std::vector<QueueFamilyInfo> queue_family_infos;
|
||||||
|
queue_family_infos.reserve(queue_families_.size());
|
||||||
|
|
||||||
|
u32 family_index = 0;
|
||||||
|
for (const auto &queue_family : queue_families_) {
|
||||||
|
QueueSupportFlags support;
|
||||||
|
|
||||||
|
if (queue_family.queueFlags & vk::QueueFlagBits::eGraphics) {
|
||||||
|
support |= QueueSupportFlagBits::eGraphics;
|
||||||
|
}
|
||||||
|
if (queue_family.queueFlags & vk::QueueFlagBits::eCompute) {
|
||||||
|
support |= QueueSupportFlagBits::eCompute;
|
||||||
|
}
|
||||||
|
if (queue_family.queueFlags & vk::QueueFlagBits::eTransfer) {
|
||||||
|
support |= QueueSupportFlagBits::eTransfer;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (device.getSurfaceSupportKHR(family_index, *_window->surface)) {
|
||||||
|
support |= QueueSupportFlagBits::ePresent;
|
||||||
|
}
|
||||||
|
} catch (const std::exception &err) {
|
||||||
|
ERROR("Failure in finding surface support, all possibilities fatal. Failed with "s + err.what());
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
|
||||||
|
VERBOSE(fmt::format("Queue({}): {}", family_index, to_string(support)));
|
||||||
|
|
||||||
|
queue_family_infos.push_back({
|
||||||
|
.index = family_index,
|
||||||
|
.count = queue_family.queueCount,
|
||||||
|
.queue_support = support,
|
||||||
|
});
|
||||||
|
|
||||||
|
++family_index;
|
||||||
|
}
|
||||||
|
|
||||||
|
return queue_family_infos;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,84 @@
|
||||||
|
// =============================================
|
||||||
|
// Aster: physical_device.h
|
||||||
|
// Copyright (c) 2020-2024 Anish Bhobe
|
||||||
|
// =============================================
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "global.h"
|
||||||
|
#include "window.h"
|
||||||
|
|
||||||
|
enum class QueueSupportFlagBits {
|
||||||
|
eGraphics = 0b0000'0001,
|
||||||
|
eTransfer = 0b0000'0010,
|
||||||
|
eCompute = 0b0000'0100,
|
||||||
|
ePresent = 0b0000'1000,
|
||||||
|
};
|
||||||
|
|
||||||
|
using QueueSupportFlags = vk::Flags<QueueSupportFlagBits>;
|
||||||
|
|
||||||
|
inline std::string to_string(QueueSupportFlags queue_support) {
|
||||||
|
if (! queue_support)
|
||||||
|
return {};
|
||||||
|
|
||||||
|
std::string result = "";
|
||||||
|
if (queue_support & QueueSupportFlagBits::eGraphics) {
|
||||||
|
result += "Graphics | ";
|
||||||
|
}
|
||||||
|
if (queue_support & QueueSupportFlagBits::eTransfer) {
|
||||||
|
result += "Transfer | ";
|
||||||
|
}
|
||||||
|
if (queue_support & QueueSupportFlagBits::eCompute) {
|
||||||
|
result += "Compute | ";
|
||||||
|
}
|
||||||
|
if (queue_support & QueueSupportFlagBits::ePresent) {
|
||||||
|
result += "Present | ";
|
||||||
|
}
|
||||||
|
|
||||||
|
return "{ " + result.substr( 0, result.size() - 3 ) + " }";
|
||||||
|
}
|
||||||
|
|
||||||
|
struct QueueFamilyInfo {
|
||||||
|
u32 index;
|
||||||
|
u32 count;
|
||||||
|
QueueSupportFlags queue_support;
|
||||||
|
|
||||||
|
[[nodiscard]] bool has_support(const QueueSupportFlags &support) const {
|
||||||
|
return cast<bool>(queue_support & support);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PhysicalDevice {
|
||||||
|
vk::raii::PhysicalDevice device;
|
||||||
|
vk::PhysicalDeviceProperties properties;
|
||||||
|
vk::PhysicalDeviceFeatures features;
|
||||||
|
std::vector<vk::SurfaceFormatKHR> surface_formats;
|
||||||
|
std::vector<vk::PresentModeKHR> present_modes;
|
||||||
|
std::vector<QueueFamilyInfo> queue_family_infos;
|
||||||
|
QueueSupportFlags queue_support;
|
||||||
|
|
||||||
|
PhysicalDevice(const Window *const _window, vk::raii::PhysicalDevice &&_device) :
|
||||||
|
device{ std::move(_device) } {
|
||||||
|
properties = device.getProperties();
|
||||||
|
features = device.getFeatures();
|
||||||
|
surface_formats = device.getSurfaceFormatsKHR(*_window->surface);
|
||||||
|
present_modes = device.getSurfacePresentModesKHR(*_window->surface);
|
||||||
|
queue_family_infos = get_queue_families(_window);
|
||||||
|
for (auto [family, count, support] : queue_family_infos) {
|
||||||
|
queue_support |= support;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<QueueFamilyInfo> get_queue_families(const Window *_window) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PhysicalDevices : std::vector<PhysicalDevice> {
|
||||||
|
PhysicalDevices(const Window *const _window, const Context *_context) {
|
||||||
|
auto phys_devs = vk::raii::PhysicalDevices(_context->instance);
|
||||||
|
reserve(phys_devs.size());
|
||||||
|
|
||||||
|
for (auto physdev : phys_devs) {
|
||||||
|
emplace_back(_window, std::move(physdev));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1,75 @@
|
||||||
|
// =============================================
|
||||||
|
// Aster: window.cpp
|
||||||
|
// Copyright (c) 2020-2024 Anish Bhobe
|
||||||
|
// =============================================
|
||||||
|
|
||||||
|
#include "window.h"
|
||||||
|
#include "context.h"
|
||||||
|
#include "glfw_context.h"
|
||||||
|
#include "logger.h"
|
||||||
|
|
||||||
|
Window::Window(const std::string_view &_title, Context *_context, const vk::Extent2D _extent, const bool _full_screen) :
|
||||||
|
extent{ _extent }, name{ _title } {
|
||||||
|
full_screen = _full_screen;
|
||||||
|
monitor = glfwGetPrimaryMonitor();
|
||||||
|
ERROR_IF(monitor == nullptr, "No monitor found");
|
||||||
|
|
||||||
|
i32 x_, y_, w_, h_;
|
||||||
|
glfwGetMonitorWorkarea(monitor, &x_, &y_, &w_, &h_);
|
||||||
|
|
||||||
|
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
|
||||||
|
glfwWindowHint(GLFW_CENTER_CURSOR, GLFW_TRUE);
|
||||||
|
|
||||||
|
window = glfwCreateWindow(cast<i32>(extent.width), cast<i32>(extent.height), name.c_str(), (_full_screen ? monitor : nullptr), nullptr);
|
||||||
|
ERROR_IF(window == nullptr, "Window creation failed")
|
||||||
|
ELSE_INFO(fmt::format("Window '{}' created with resolution '{}x{}'", name.data(), extent.width, extent.height));
|
||||||
|
if (window == nullptr) {
|
||||||
|
auto code = GlfwContext::post_error();
|
||||||
|
glfwTerminate();
|
||||||
|
CRASH(code);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (full_screen == false) {
|
||||||
|
glfwSetWindowPos(window, cast<i32>(w_ - extent.width) / 2, cast<i32>(h_ - extent.height) / 2);
|
||||||
|
}
|
||||||
|
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_NORMAL);
|
||||||
|
|
||||||
|
VkSurfaceKHR surface_;
|
||||||
|
auto result = cast<vk::Result>(glfwCreateWindowSurface(cast<VkInstance>(*_context->instance), window, nullptr, &surface_));
|
||||||
|
if (failed(result)) {
|
||||||
|
ERROR("Failed to create Surface with "s + to_string(result));
|
||||||
|
throw std::runtime_error("Failed to create Surface with "s + to_string(result));
|
||||||
|
}
|
||||||
|
INFO("Surface Created");
|
||||||
|
surface = vk::raii::SurfaceKHR{ _context->instance, surface_ };
|
||||||
|
}
|
||||||
|
|
||||||
|
Window::Window(Window &&_other) noexcept :
|
||||||
|
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;
|
||||||
|
window = _other.window;
|
||||||
|
monitor = _other.monitor;
|
||||||
|
surface = std::exchange(_other.surface, nullptr);
|
||||||
|
extent = _other.extent;
|
||||||
|
name = std::move(_other.name);
|
||||||
|
full_screen = _other.full_screen;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Window::~Window() {
|
||||||
|
if (window != nullptr) {
|
||||||
|
glfwDestroyWindow(window);
|
||||||
|
window = nullptr;
|
||||||
|
}
|
||||||
|
monitor = nullptr;
|
||||||
|
|
||||||
|
INFO(fmt::format("Window '{}' Destroyed", name));
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,47 @@
|
||||||
|
// =============================================
|
||||||
|
// Aster: window.h
|
||||||
|
// Copyright (c) 2020-2024 Anish Bhobe
|
||||||
|
// =============================================
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "global.h"
|
||||||
|
|
||||||
|
#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;
|
||||||
|
Window(Window &&_other) noexcept;
|
||||||
|
Window &operator=(const Window &_other) = delete;
|
||||||
|
Window &operator=(Window &&_other) noexcept;
|
||||||
|
|
||||||
|
~Window();
|
||||||
|
|
||||||
|
[[nodiscard]] bool should_close() const noexcept {
|
||||||
|
return glfwWindowShouldClose(window);
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] bool poll() const noexcept {
|
||||||
|
glfwPollEvents();
|
||||||
|
return !glfwWindowShouldClose(window);
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_window_size(const vk::Extent2D &_extent) noexcept {
|
||||||
|
extent = _extent;
|
||||||
|
glfwSetWindowSize(window, cast<i32>(extent.width), cast<i32>(extent.height));
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_window_size(const u32 _width, const u32 _height) noexcept {
|
||||||
|
set_window_size({ _width, _height });
|
||||||
|
}
|
||||||
|
|
||||||
|
// fields
|
||||||
|
GLFWwindow *window{ nullptr };
|
||||||
|
GLFWmonitor *monitor{ nullptr };
|
||||||
|
vk::raii::SurfaceKHR surface{ nullptr };
|
||||||
|
vk::Extent2D extent;
|
||||||
|
std::string name;
|
||||||
|
b8 full_screen{ false };
|
||||||
|
};
|
||||||
2
run.sh
2
run.sh
|
|
@ -1,7 +1,7 @@
|
||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
if [ -d "out" ]; then
|
if [ -d "out" ]; then
|
||||||
pushd ./out/ > /dev/null || exit
|
pushd ./build/ > /dev/null || exit
|
||||||
if echo "$@" | grep -e "debug" -q
|
if echo "$@" | grep -e "debug" -q
|
||||||
then
|
then
|
||||||
lldb aster-exe
|
lldb aster-exe
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
"glfw3",
|
"glfw3",
|
||||||
"glm",
|
"glm",
|
||||||
"scottt-debugbreak",
|
"scottt-debugbreak",
|
||||||
"vulkan-memory-allocator"
|
"vulkan-memory-allocator",
|
||||||
|
"fmt"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue