Compare commits

...

6 Commits

Author SHA1 Message Date
26a392b1d0 example - shared ptr
All checks were successful
Build / Build (push) Successful in 26m42s
2026-04-14 18:56:40 -04:00
b90c980bee ctx - device
Some checks failed
Build / Build (push) Has been cancelled
2026-04-14 18:49:35 -04:00
f5c4ac0790 ctx - max sample usage 2026-04-14 18:20:52 -04:00
bd6c4523dd ctx - physical device
All checks were successful
Build / Build (push) Successful in 3m14s
2026-04-13 17:41:56 -04:00
7d50f6c148 Surface
All checks were successful
Build / Build (push) Successful in 3m15s
2026-04-13 17:08:31 -04:00
aa39f81bb1 examples - bug fix in window.h
All checks were successful
Build / Build (push) Successful in 2m58s
2026-04-12 23:47:37 -04:00
9 changed files with 226 additions and 7 deletions

View File

@@ -5,6 +5,7 @@
#include <cstdlib> #include <cstdlib>
#include <exception> #include <exception>
#include <memory>
#include "GLFW/glfw3.h" #include "GLFW/glfw3.h"
#include "shared/logger.h" #include "shared/logger.h"
#include "shared/window.h" #include "shared/window.h"
@@ -17,14 +18,21 @@ int main() {
GLFWwindow *window = OatmealUtils::initWindow("Oatmeal - createContext", 800, 600); GLFWwindow *window = OatmealUtils::initWindow("Oatmeal - createContext", 800, 600);
std::shared_ptr<Oatmeal::ctx> ctx = nullptr;
OatmealUtils::getLogger("context")->info("Creating context");
try { try {
Oatmeal::ctx ctx(window); ctx = std::make_shared<Oatmeal::ctx>(window);
} 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 Type: {}", ctx->getDeviceType());
OatmealUtils::getLogger("context")->info("Starting main loop");
while (!glfwWindowShouldClose(window)) { while (!glfwWindowShouldClose(window)) {
glfwPollEvents(); glfwPollEvents();
} }

View File

@@ -6,16 +6,16 @@
namespace OatmealUtils { namespace OatmealUtils {
inline GLFWwindow *initWindow(const char *title, uint32_t width, uint32_t height) { inline GLFWwindow *initWindow(const char *title, uint32_t width, uint32_t height) {
OatmealUtils::createLogger("window", nullptr); OatmealUtils::createLogger("window", nullptr);
OatmealUtils::get("window")->debug("Initializing window backend"); OatmealUtils::getLogger("window")->debug("Initializing window backend");
glfwInit(); glfwInit();
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE); glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);
OatmealUtils::get("window")->debug("Creating window"); OatmealUtils::getLogger("window")->debug("Creating window");
GLFWwindow *window = glfwCreateWindow(width, height, title, nullptr, nullptr); GLFWwindow *window = glfwCreateWindow(width, height, title, nullptr, nullptr);
if (window == nullptr) { if (window == nullptr) {
const char *desc; const char *desc;
uint32_t code = glfwGetError(&desc); uint32_t code = glfwGetError(&desc);
OatmealUtils::get("window")->critical("Failed to create window: ({}) {}", code, desc); OatmealUtils::getLogger("window")->critical("Failed to create window: ({}) {}", code, desc);
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }

View File

@@ -0,0 +1,64 @@
#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,8 +1,14 @@
#include "ctx.h" #include "ctx.h"
#include <cstdint>
namespace Oatmeal { namespace Oatmeal {
ctx::ctx(GLFWwindow *window) { createInstance(); } ctx::ctx(GLFWwindow *window) {
createInstance();
m_window = window;
createSurface();
pickPhysicalDevice();
m_msaaSamples = getMaxUsableSampleCount();
createLogicalDevice();
}
ctx::~ctx() {} ctx::~ctx() {}

View File

@@ -41,11 +41,17 @@ namespace Oatmeal {
class ctx { class ctx {
public: public:
ctx(GLFWwindow *window); ctx(GLFWwindow *window);
std::string getDeviceName() const;
std::string getDeviceType() const;
~ctx(); ~ctx();
private: private:
// Members // // Members //
GLFWwindow *m_window = nullptr;
vk::raii::Context m_context; vk::raii::Context m_context;
vk::raii::Instance m_instance = nullptr; vk::raii::Instance m_instance = nullptr;
vk::DebugUtilsMessengerEXT m_debugMessenger = nullptr; vk::DebugUtilsMessengerEXT m_debugMessenger = nullptr;
@@ -81,5 +87,14 @@ namespace Oatmeal {
void createInstance(); void createInstance();
std::vector<const char *> getRequiredExtensions(); std::vector<const char *> getRequiredExtensions();
void setupDebugMessenger(); 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

@@ -0,0 +1,27 @@
#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,5 +1,4 @@
#include <GLFW/glfw3.h> #include <GLFW/glfw3.h>
#include <X11/Xlib.h>
#include <cstdint> #include <cstdint>
#include <iostream> #include <iostream>
#include <stdexcept> #include <stdexcept>

View File

@@ -0,0 +1,83 @@
#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

@@ -0,0 +1,17 @@
#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