bleh
All checks were successful
Build / Build (push) Successful in 1m47s

This commit is contained in:
2026-05-24 12:13:08 -04:00
parent 26a392b1d0
commit 2f1f196d6b
10 changed files with 94 additions and 407 deletions

1
.gitignore vendored
View File

@@ -3,6 +3,5 @@ build/
.zed .zed
!deps/JoltPhysics/Build !deps/JoltPhysics/Build
.cache .cache
.vscode
build-clion/ build-clion/
bin/ bin/

77
.vscode/tasks.json vendored Normal file
View File

@@ -0,0 +1,77 @@
{
"version": "2.0.0",
"tasks": [
{
"label": "Configure: Debug",
"type": "shell",
"command": "cd scripts; ./configure-debug.sh",
"group": {
"isDefault": false
},
"problemMatcher": [],
"detail": "Configure Debug"
},
{
"label": "Build: Debug",
"type": "shell",
"command": "cd scripts; ./build-debug.sh",
"group": {
"kind": "build",
"isDefault": true
},
"problemMatcher": [],
"detail": "Build Debug"
},
{
"label": "Configure: Relwithdeb",
"type": "shell",
"command": "cd scripts; ./configure-relwithdeb.sh",
"group": {
"isDefault": false
},
"problemMatcher": [],
"detail": "Configure Release with debug info"
},
{
"label": "Build: Relwithdeb",
"type": "shell",
"command": "cd scripts; ./build-relwithdeb.sh",
"group": {
"kind": "build",
"isDefault": true
},
"problemMatcher": [],
"detail": "Build Release with debug info"
},
{
"label": "Clean: Debug",
"type": "shell",
"command": "cd build/debug; ninja clean",
"group": {
"isDefault": false
},
"detail": "Clean debug files"
},
{
"label": "Build: All",
"type": "shell",
"command": "cd scripts; ./build.sh",
"group": {
"kind": "build",
"isDefault": true
},
"problemMatcher": [],
"detail": "Build all types"
},
{
"label": "Clean: All",
"type": "shell",
"command": "cd scripts; ./clean.sh",
"group": {
"isDefault": false
},
"problemMatcher": [],
"detail": "Clean All files"
}
]
}

View File

@@ -23,14 +23,14 @@ int main() {
OatmealUtils::getLogger("context")->info("Creating context"); OatmealUtils::getLogger("context")->info("Creating context");
try { try {
ctx = std::make_shared<Oatmeal::ctx>(window); ctx = std::make_shared<Oatmeal::ctx>(window, Oatmeal::CtxCfg{.backend = Oatmeal::BACKEND_VULKAN});
} catch (const std::exception &e) { } catch (const std::exception &e) {
OatmealUtils::getLogger("context")->critical("{}", e.what()); OatmealUtils::getLogger("context")->critical("{}", e.what());
return EXIT_FAILURE; return EXIT_FAILURE;
} }
OatmealUtils::getLogger("context")->info("Device name: {}", ctx->getDeviceName()); // OatmealUtils::getLogger("context")->info("Device name: {}", ctx->getDeviceName());
OatmealUtils::getLogger("context")->info("Device Type: {}", ctx->getDeviceType()); // OatmealUtils::getLogger("context")->info("Device Type: {}", ctx->getDeviceType());
OatmealUtils::getLogger("context")->info("Starting main loop"); OatmealUtils::getLogger("context")->info("Starting main loop");
while (!glfwWindowShouldClose(window)) { while (!glfwWindowShouldClose(window)) {

View File

@@ -1,64 +0,0 @@
#include <stdexcept>
#include "ctx.h"
#include "vulkan/vulkan.hpp"
#include "vulkan/vulkan_raii.hpp"
namespace Oatmeal {
void ctx::createLogicalDevice() {
std::vector<vk::QueueFamilyProperties> queueFamilyProperties = m_physicalDevice.getQueueFamilyProperties();
m_queueIndex = ~0;
for (uint32_t qfpIndex = 0; qfpIndex < queueFamilyProperties.size(); qfpIndex++) {
if ((queueFamilyProperties[qfpIndex].queueFlags & vk::QueueFlagBits::eGraphics) &&
m_physicalDevice.getSurfaceSupportKHR(qfpIndex, *m_surface)) {
m_queueIndex = qfpIndex;
break;
}
}
if (m_queueIndex == ~0) {
// TODO: Find a better solution then just throwing a fit
throw std::runtime_error("Failed to find a queue that supports graphics and presentation");
}
vk::PhysicalDeviceFeatures deviceFeatures;
vk::StructureChain<vk::PhysicalDeviceFeatures2, vk::PhysicalDeviceVulkan13Features,
vk::PhysicalDeviceExtendedDynamicStateFeaturesEXT>
featureChain = {
{.features = {.samplerAnisotropy = true}},
{.synchronization2 = true, .dynamicRendering = true},
{.extendedDynamicState = true},
};
float queuePriority = 0.5f;
vk::DeviceQueueCreateInfo deviceQueueCreateInfo = {
.queueFamilyIndex = m_queueIndex,
.queueCount = 1,
.pQueuePriorities = &queuePriority,
};
vk::DeviceCreateInfo deviceCreateInfo = {
.pNext = &featureChain.get<vk::PhysicalDeviceFeatures2>(),
.queueCreateInfoCount = 1,
.pQueueCreateInfos = &deviceQueueCreateInfo,
.enabledExtensionCount = static_cast<uint32_t>(requiredDeviceExtensions.size()),
.ppEnabledExtensionNames = requiredDeviceExtensions.data(),
};
m_device = vk::raii::Device(m_physicalDevice, deviceCreateInfo);
m_queue = vk::raii::Queue(m_device, m_queueIndex, 0);
}
std::string ctx::getDeviceName() const {
const vk::PhysicalDeviceProperties deviceProperties = m_physicalDevice.getProperties();
return deviceProperties.deviceName;
}
std::string ctx::getDeviceType() const {
const vk::PhysicalDeviceProperties deviceProperties = m_physicalDevice.getProperties();
return vk::to_string(deviceProperties.deviceType);
}
} // namespace Oatmeal

View File

@@ -1,16 +1,9 @@
#include "ctx.h" #include "ctx.h"
namespace Oatmeal { namespace Oatmeal {
ctx::ctx(GLFWwindow *window) {
createInstance(); ctx::ctx(GLFWwindow *window, CtxCfg ctxCfg) {}
m_window = window;
createSurface();
pickPhysicalDevice();
m_msaaSamples = getMaxUsableSampleCount();
createLogicalDevice();
}
ctx::~ctx() {} ctx::~ctx() {}
} // namespace Oatmeal } // namespace Oatmeal

View File

@@ -1,100 +1,23 @@
#include <sys/types.h>
#include "vulkan/vulkan.hpp"
#if defined(__INTELLISENSE__) || !defined(USE_CPP20_MODULES)
#include <vulkan/vulkan_raii.hpp>
#else
import vulkan_hpp;
#endif
#define GLFW_INCLUDE_VULKAN
#if defined(PLATFORM_WINDOWS)
#define VK_USE_PLATFORM_WIN32_KHR
#define GLFW_EXPOSE_NATIVE_WIN32
#elif defined(PLATFORM_LINUX)
#define VK_USE_PLATFORM_XLIB_KHR
#define GLFW_EXPOSE_NATIVE_X11
#elif defined(PLATFORM_MACOS)
#define VK_USE_PLATFORM_MACOS_MVK
#define GLFW_EXPOSE_NATIVE_COCOA
#endif
#define GLM_FORCE_DEFAULT_ALIGNED_GENTYPES
#define GLM_FORCE_DEPTH_ZERO_TO_ONE
#define GLM_ENABLE_EXPERIMENTAL
#include <GLFW/glfw3.h> #include <GLFW/glfw3.h>
#include <GLFW/glfw3native.h>
#include <cstdint>
constexpr int MAX_FRAMES_IN_FLIGHT = 2;
const std::vector<char const *> validationLayers = {"VK_LAYER_KHRONOS_validation"};
const std::vector<const char *> requiredDeviceExtensions = {vk::KHRSwapchainExtensionName};
#ifndef NDEBUG
constexpr bool enableValidationLayers = false;
#else
constexpr bool enableValidationLayers = true;
#endif
namespace Oatmeal { namespace Oatmeal {
enum Backend {
BACKEND_VULKAN,
};
struct CtxCfg {
Backend backend;
};
class ctx { class ctx {
public: public:
ctx(GLFWwindow *window); ctx(GLFWwindow *window, CtxCfg cfg);
std::string getDeviceName() const;
std::string getDeviceType() const;
~ctx(); ~ctx();
private: private:
// Members //
GLFWwindow *m_window = nullptr;
vk::raii::Context m_context;
vk::raii::Instance m_instance = nullptr;
vk::DebugUtilsMessengerEXT m_debugMessenger = nullptr;
vk::raii::PhysicalDevice m_physicalDevice = nullptr;
vk::raii::Device m_device = nullptr;
vk::raii::Queue m_queue = nullptr;
uint32_t m_queueIndex;
vk::raii::SurfaceKHR m_surface = nullptr;
vk::raii::SwapchainKHR m_swapchain = nullptr;
std::vector<vk::Image> m_swapchainImages;
vk::SurfaceFormatKHR m_swapchainSurfaceFormat;
vk::Extent2D m_swapchainExtent;
std::vector<vk::raii::ImageView> m_swapchainImageViews;
std::vector<vk::raii::Semaphore> m_presentCompleteSemaphores;
std::vector<vk::raii::Semaphore> m_renderFinishSemaphores;
std::vector<vk::raii::Fence> m_inFlightFences;
bool m_framebufferResized = false;
uint32_t m_frameIndex = 0;
vk::SampleCountFlagBits m_msaaSamples = vk::SampleCountFlagBits::e1;
vk::raii::Image m_colorImage = nullptr;
vk::raii::DeviceMemory m_colorImageMemory = nullptr;
vk::raii::ImageView m_colorImageView = nullptr;
vk::raii::Image m_depthImage = nullptr;
vk::raii::DeviceMemory m_depthImageMemory = nullptr;
vk::raii::ImageView m_depthImageView = nullptr;
vk::Format m_depthFormat;
// Functions //
void createInstance();
std::vector<const char *> getRequiredExtensions();
void setupDebugMessenger();
void createSurface();
void pickPhysicalDevice();
bool isPhysicalDeviceSupported(vk::raii::PhysicalDevice device);
uint32_t scorePhysicalDevice(vk::raii::PhysicalDevice device);
vk::SampleCountFlagBits getMaxUsableSampleCount();
void createLogicalDevice();
}; };
} // namespace Oatmeal } // namespace Oatmeal

View File

@@ -1,27 +0,0 @@
#include "ctx.h"
#include "vulkan/vulkan.hpp"
namespace Oatmeal {
vk::SampleCountFlagBits ctx::getMaxUsableSampleCount() {
vk::PhysicalDeviceProperties physicalDeviceProperties = m_physicalDevice.getProperties();
vk::SampleCountFlags count = physicalDeviceProperties.limits.framebufferColorSampleCounts &
physicalDeviceProperties.limits.framebufferDepthSampleCounts;
if (count & vk::SampleCountFlagBits::e16) {
return vk::SampleCountFlagBits::e16;
}
if (count & vk::SampleCountFlagBits::e8) {
return vk::SampleCountFlagBits::e8;
}
if (count & vk::SampleCountFlagBits::e4) {
return vk::SampleCountFlagBits::e4;
}
if (count & vk::SampleCountFlagBits::e2) {
return vk::SampleCountFlagBits::e2;
}
return vk::SampleCountFlagBits::e1;
}
} // namespace Oatmeal

View File

@@ -1,114 +0,0 @@
#include <GLFW/glfw3.h>
#include <cstdint>
#include <iostream>
#include <stdexcept>
#include <vulkan/vk_platform.h>
#include <vulkan/vulkan_core.h>
#include "ctx.h"
#include "vulkan/vulkan.hpp"
namespace Oatmeal {
void ctx::createInstance() {
// Create the application info
constexpr vk::ApplicationInfo appInfo{
.pApplicationName = "Oatmeal",
.applicationVersion = VK_MAKE_VERSION(1, 0, 0),
.pEngineName = "No engine",
.engineVersion = VK_MAKE_API_VERSION(1, 0, 0, 0),
.apiVersion = vk::ApiVersion14,
};
// Loop through the required layers, making sure they are supported
std::vector<char const *> requiredLayers;
if (enableValidationLayers) {
requiredLayers.assign(validationLayers.begin(), validationLayers.end());
}
auto layerProperties = m_context.enumerateInstanceLayerProperties();
for (auto const &requiredLayer: requiredLayers) {
bool found = false;
for (auto const &layerProperty: layerProperties) {
if (strcmp(layerProperty.layerName, requiredLayer)) {
found = true;
}
}
if (!found) {
// TODO: Not sure i like throwing runtime errors, might need to find a better solution
throw std::runtime_error("Required layer not supported: " + std::string(requiredLayer));
}
}
// Loop through the required extensions, making sure they are supported
auto requiredExtensions = getRequiredExtensions();
auto extensionProperties = m_context.enumerateInstanceExtensionProperties();
for (auto const &requiredExtension: requiredExtensions) {
bool found = false;
for (auto const &extensionProperty: extensionProperties) {
if (strcmp(extensionProperty.extensionName, requiredExtension)) {
found = true;
}
}
if (!found) {
// TODO: Not sure i like just throwing a runtime error, might need to find a better solution for error
// handling
throw std::runtime_error("Required extension not found: " + std::string(requiredExtension));
}
}
// Create the instance
vk::InstanceCreateInfo createInfo{
.pApplicationInfo = &appInfo,
.enabledLayerCount = static_cast<uint32_t>(requiredLayers.size()),
.ppEnabledLayerNames = requiredLayers.data(),
.enabledExtensionCount = static_cast<uint32_t>(requiredExtensions.size()),
.ppEnabledExtensionNames = requiredExtensions.data(),
};
m_instance = vk::raii::Instance(m_context, createInfo);
}
std::vector<const char *> ctx::getRequiredExtensions() {
uint32_t glfwExtensionCount = 0;
auto glfwExtensions = glfwGetRequiredInstanceExtensions(&glfwExtensionCount);
std::vector extensions(glfwExtensions, glfwExtensions + glfwExtensionCount);
if (enableValidationLayers) {
extensions.push_back(vk::EXTDebugUtilsExtensionName);
}
return extensions;
}
static VKAPI_ATTR vk::Bool32 VKAPI_CALL debugCallback(vk::DebugUtilsMessageSeverityFlagBitsEXT severity,
vk::DebugUtilsMessageTypeFlagsEXT type,
const vk::DebugUtilsMessengerCallbackDataEXT *pCallbackData,
void *) {
std::cerr << "Validation layer: type " << vk::to_string(type) << "msg: " << pCallbackData->pMessage
<< std::endl;
return 0;
}
void ctx::setupDebugMessenger() {
if (!enableValidationLayers) {
return;
}
vk::DebugUtilsMessageSeverityFlagsEXT severityFlags(vk::DebugUtilsMessageSeverityFlagBitsEXT::eWarning |
vk::DebugUtilsMessageSeverityFlagBitsEXT::eError);
vk::DebugUtilsMessageTypeFlagsEXT typeFlags(vk::DebugUtilsMessageTypeFlagBitsEXT::eGeneral |
vk::DebugUtilsMessageTypeFlagBitsEXT::eValidation |
vk::DebugUtilsMessageTypeFlagBitsEXT::ePerformance);
vk::DebugUtilsMessengerCreateInfoEXT createInfo{
.messageSeverity = severityFlags,
.messageType = typeFlags,
.pfnUserCallback = &debugCallback,
};
m_debugMessenger = m_instance.createDebugUtilsMessengerEXT(createInfo);
}
} // namespace Oatmeal

View File

@@ -1,83 +0,0 @@
#include <algorithm>
#include <cstdint>
#include <map>
#include <stdexcept>
#include <utility>
#include <vulkan/vulkan_core.h>
#include <vulkan/vulkan_raii.hpp>
#include "ctx.h"
#include "vulkan/vulkan.hpp"
namespace Oatmeal {
void ctx::pickPhysicalDevice() {
std::vector<vk::raii::PhysicalDevice> physicalDevices = m_instance.enumeratePhysicalDevices();
std::vector<vk::raii::PhysicalDevice> supportedDevices{};
for (const auto device: physicalDevices) {
if (isPhysicalDeviceSupported(device)) {
supportedDevices.emplace_back(device);
}
}
if (supportedDevices.empty()) {
throw std::runtime_error("Failed to find a supported device");
}
std::multimap<uint32_t, vk::raii::PhysicalDevice> scores;
for (const auto device: supportedDevices) {
uint32_t score = scorePhysicalDevice(device);
scores.insert(std::make_pair(score, device));
}
m_physicalDevice = scores.rbegin()->second;
}
bool ctx::isPhysicalDeviceSupported(vk::raii::PhysicalDevice device) {
// Check for vulkan 1.4 support
bool supportsVulkan14 = device.getProperties().apiVersion >= VK_API_VERSION_1_4;
// Check for graphics queue support
auto queueFamilies = device.getQueueFamilyProperties();
bool supportsGraphics = std::ranges::any_of(
queueFamilies, [](auto const &qfp) { return !!(qfp.queueFlags & vk::QueueFlagBits::eGraphics); });
// Check for extension support
auto availableDeviceExtensions = device.enumerateDeviceExtensionProperties();
bool supportsAllRequiredExtensions = std::ranges::all_of(
requiredDeviceExtensions, [&availableDeviceExtensions](auto const &requiredDeviceExtension) {
return std::ranges::any_of(
availableDeviceExtensions, [requiredDeviceExtension](auto const &availableDeviceExtension) {
return strcmp(availableDeviceExtension.extensionName, requiredDeviceExtension) == 0;
});
});
// Check for feature support
auto features = device.template getFeatures2<vk::PhysicalDeviceFeatures2, vk::PhysicalDeviceVulkan13Features,
vk::PhysicalDeviceExtendedDynamicStateFeaturesEXT>();
bool supportsRequiredFeatures =
features.template get<vk::PhysicalDeviceFeatures2>().features.samplerAnisotropy &&
features.template get<vk::PhysicalDeviceVulkan13Features>().dynamicRendering &&
features.template get<vk::PhysicalDeviceVulkan13Features>().synchronization2 &&
features.template get<vk::PhysicalDeviceExtendedDynamicStateFeaturesEXT>().extendedDynamicState;
return supportsVulkan14 && supportsGraphics && supportsAllRequiredExtensions && supportsRequiredFeatures;
}
uint32_t ctx::scorePhysicalDevice(vk::raii::PhysicalDevice device) {
uint32_t score = 0;
vk::PhysicalDeviceProperties physicalDeviceProperties = device.getProperties();
if (physicalDeviceProperties.deviceType == vk::PhysicalDeviceType::eDiscreteGpu) {
score += 100;
} else if (physicalDeviceProperties.deviceType == vk::PhysicalDeviceType::eIntegratedGpu) {
score += 50;
} else if (physicalDeviceProperties.deviceType == vk::PhysicalDeviceType::eVirtualGpu) {
score += 10;
}
return score;
}
} // namespace Oatmeal

View File

@@ -1,17 +0,0 @@
#include "ctx.h"
#include <GLFW/glfw3.h>
#include <GLFW/glfw3native.h>
#include <vulkan/vulkan_core.h>
#include <vulkan/vulkan_raii.hpp>
namespace Oatmeal {
void ctx::createSurface() {
VkSurfaceKHR _surface;
if (glfwCreateWindowSurface(*m_instance, m_window, nullptr, &_surface)) {
throw std::runtime_error("Failed to create window surface");
}
m_surface = vk::raii::SurfaceKHR(m_instance, _surface);
}
} // namespace Oatmeal