3 Commits

Author SHA1 Message Date
65d21cd3c4 basic create surface
Some checks failed
Build and Test verification / build (push) Failing after 25s
Build and Test verification / test (push) Has been skipped
2026-05-23 18:29:44 -05:00
Preston McGee
bcd19f1e60 Feature: VkDevice Creation (#5)
* update contributing with goals

* add required extensions to vulkan instance

* add validation layers + debug callback

* add device class which enumerates availble gpu devices

* improve device selection logic

* add logical device creation
2026-05-22 21:48:51 -05:00
Preston McGee
a63c271f92 Feature/VkExtensions+VkLayers (#2) 2026-05-16 12:48:39 -07:00
10 changed files with 118 additions and 12 deletions

View File

@@ -34,6 +34,8 @@ add_library(maiden_core STATIC
src/Window.cpp src/Window.cpp
src/Engine.cpp src/Engine.cpp
src/Device.cpp src/Device.cpp
src/Pipeline.cpp
src/Swapchain.cpp
# include extra source files here # include extra source files here
) )

View File

@@ -3,7 +3,10 @@
#include <iostream> #include <iostream>
Device::Device(vk::raii::Instance* instance): instance_(instance) { Device::Device(vk::raii::Instance* instance, Window* window): instance_(instance), window_(window) {
std::cout << "[" << __FUNCTION__ << ": " << __LINE__ << "] Device constructor" << std::endl;
createSurface();
} }
@@ -55,7 +58,7 @@ uint32_t Device::evaluatePhysicalDevice(vk::raii::PhysicalDevice& device) {
if(deviceProperties.deviceType == vk::PhysicalDeviceType::eDiscreteGpu) { if(deviceProperties.deviceType == vk::PhysicalDeviceType::eDiscreteGpu) {
score += 2; score += 2;
} else { } else {
std::cout << "[" << __FUNCTION__ << ": " << __LINE__ << "] Warning: physical device " << deviceProperties.deviceName << " is not a discrete device!" << std::endl; std::cout << "[" << __FUNCTION__ << ": " << __LINE__ << "] Warning: physical device " << deviceProperties.deviceName << " is not a discrete device!" << std::endl;
} }
// prefer devices that support vulkan 1.3 // prefer devices that support vulkan 1.3
@@ -107,6 +110,11 @@ uint32_t Device::evaluatePhysicalDevice(vk::raii::PhysicalDevice& device) {
bool Device::createLogicalDevice() { bool Device::createLogicalDevice() {
if(surface_ == nullptr) {
std::cout << "[" << __FUNCTION__ << ": " << __LINE__ << "] Error: cannot create logical device without a valid presentation surface." << std::endl;
return false;
}
if(physicalDevice_ == nullptr) { if(physicalDevice_ == nullptr) {
std::cout << "[" << __FUNCTION__ << ": " << __LINE__ << "] Error: cannot create logical device without a valid physical device." << std::endl; std::cout << "[" << __FUNCTION__ << ": " << __LINE__ << "] Error: cannot create logical device without a valid physical device." << std::endl;
return false; return false;
@@ -114,11 +122,20 @@ bool Device::createLogicalDevice() {
// specify queue family requirements // specify queue family requirements
std::vector<vk::QueueFamilyProperties> queueFamilyProperties = physicalDevice_.getQueueFamilyProperties(); std::vector<vk::QueueFamilyProperties> queueFamilyProperties = physicalDevice_.getQueueFamilyProperties();
auto graphicsQueueFamilyProperty = std::ranges::find_if(queueFamilyProperties, [](auto const &qfp) { return (qfp.queueFlags & vk::QueueFlagBits::eGraphics) != static_cast<vk::QueueFlags>(0); }); int32_t queueIndex = -1;
auto graphicsIndex = static_cast<uint32_t>(std::distance(queueFamilyProperties.begin(), graphicsQueueFamilyProperty)); for(uint32_t qfpIndex = 0; qfpIndex < queueFamilyProperties.size(); qfpIndex++) {
float queuePriority = 1.0f; if((queueFamilyProperties[qfpIndex].queueFlags & vk::QueueFlagBits::eGraphics) && physicalDevice_.getSurfaceSupportKHR(qfpIndex, *surface_)) {
queueIndex = static_cast<int32_t>(qfpIndex);
break;
}
}
if(queueIndex == -1) {
std::cout << "[" << __FUNCTION__ << ": " << __LINE__ << "] Error: could not locate valid graphics queues." << std::endl;
}
float queuePriority = 0.5f;
vk::DeviceQueueCreateInfo deviceQueueCreateInfo { vk::DeviceQueueCreateInfo deviceQueueCreateInfo {
.queueFamilyIndex = graphicsIndex, .queueFamilyIndex = queueIndex,
.queueCount = 1, .queueCount = 1,
.pQueuePriorities = &queuePriority .pQueuePriorities = &queuePriority
}; };
@@ -143,7 +160,7 @@ bool Device::createLogicalDevice() {
logicalDevice_ = vk::raii::Device(physicalDevice_, deviceCreateInfo); logicalDevice_ = vk::raii::Device(physicalDevice_, deviceCreateInfo);
// initialize the graphics queue // initialize the graphics queue
graphicsQueue_ = vk::raii::Queue(logicalDevice_, graphicsIndex, 0); graphicsQueue_ = vk::raii::Queue(logicalDevice_, queueIndex, 0);
if(logicalDevice_ != nullptr) { if(logicalDevice_ != nullptr) {
return true; return true;
@@ -153,3 +170,9 @@ bool Device::createLogicalDevice() {
} }
} }
void Device::createSurface() {
(void)window_->createSurface(&surface_);
}

View File

@@ -3,11 +3,13 @@
#include <vulkan/vulkan_raii.hpp> #include <vulkan/vulkan_raii.hpp>
#include "Window.hpp"
class Device { class Device {
public: public:
Device(vk::raii::Instance* instance); Device(vk::raii::Instance* instance, Window* window);
~Device(); ~Device();
// assigns a capable gpu vkdevice to physicalDevice // assigns a capable gpu vkdevice to physicalDevice
@@ -21,10 +23,18 @@ class Device {
// gives a device a score to attempt to select the most capable device // gives a device a score to attempt to select the most capable device
uint32_t evaluatePhysicalDevice(vk::raii::PhysicalDevice& device); uint32_t evaluatePhysicalDevice(vk::raii::PhysicalDevice& device);
// internal create surface
void createSurface();
// vulkan objects
vk::raii::Instance* instance_ = nullptr; vk::raii::Instance* instance_ = nullptr;
vk::raii::PhysicalDevice physicalDevice_ = nullptr; vk::raii::PhysicalDevice physicalDevice_ = nullptr;
vk::raii::Device logicalDevice_ = nullptr; vk::raii::Device logicalDevice_ = nullptr;
vk::raii::Queue graphicsQueue_ = nullptr; vk::raii::Queue graphicsQueue_ = nullptr;
vk::raii::SurfaceKHR surface_ = nullptr;
// ptrs to other engine objects
Window* window_ = nullptr;
// required extensions for the physical device // required extensions for the physical device
std::vector<const char*> requiredDeviceExtensions_ = { vk::KHRSwapchainExtensionName }; std::vector<const char*> requiredDeviceExtensions_ = { vk::KHRSwapchainExtensionName };

View File

@@ -22,7 +22,7 @@ void Engine::init() {
} }
// device selection and setup // device selection and setup
Device device(&instance_); Device device(&instance_, window_);
(void)device.selectPhysicalDevice(); (void)device.selectPhysicalDevice();
(void)device.createLogicalDevice(); (void)device.createLogicalDevice();

6
src/Pipeline.cpp Normal file
View File

@@ -0,0 +1,6 @@
#include "Pipeline.hpp"
Pipeline::Pipeline(Device* device) : device_(device) {
}

19
src/Pipeline.hpp Normal file
View File

@@ -0,0 +1,19 @@
#pragma once
#include "Device.hpp"
// the Pipeline lays out the rendering steps for the vulkan engine to follow
class Pipeline {
public:
Pipeline(Device* device);
~Pipeline() = default;
private:
Device* device_ = nullptr;
// will include shaders eventually
};

6
src/Swapchain.cpp Normal file
View File

@@ -0,0 +1,6 @@
#include "Swapchain.hpp"
Swapchain::Swapchain() {
}

14
src/Swapchain.hpp Normal file
View File

@@ -0,0 +1,14 @@
#pragma once
// the swapchain functions as the layout for framebuffers that get written to by the gpu and read from to present to the screen
class Swapchain {
public:
Swapchain();
~Swapchain() = default;
private:
};

View File

@@ -2,6 +2,7 @@
#include "Window.hpp" #include "Window.hpp"
#include <SDL3/SDL_events.h> #include <SDL3/SDL_events.h>
#include <iostream>
Window::Window() { Window::Window() {
@@ -43,3 +44,26 @@ void Window::handleEvent(SDL_Event& event) {
rendering_ = true; rendering_ = true;
} }
} }
bool Window::createSurface(vk::raii::SurfaceKHR* surface) {
std::cout << "[" << __FUNCTION__ << ": " << __LINE__ << "] createSurface()" << std::endl;
#ifdef __WIN32
vk::Win32SurfaceCreateInfoKHR createInfo {
.hinstance = GetModuleHandle(nullptr),
.hwnd = (HWND)SDL_GetPointerProperty(SDL_GetWindowProperties(sdlWindow_), "SDL.window.win32.hwnd", nullptr);
}
surface = &instance_.createWin32SurfaceKHR(createInfo);
#else // __WIN32
#endif // __WIN32
std::cout << "[" << __FUNCTION__ << ": " << __LINE__ << "] attempted to createSurface" << std::endl;
if(surface != nullptr) {
return true;
} else {
std::cout << "[" << __FUNCTION__ << ": " << __LINE__ << "] Error: unable to create window surface." << std::endl;
return false;
}
}

View File

@@ -1,8 +1,9 @@
#pragma once #pragma once
#include "SDL3/SDL.h" #include <SDL3/SDL.h>
#include "SDL3/SDL_vulkan.h" #include <SDL3/SDL_vulkan.h>
#include <vulkan/vulkan_raii.hpp>
// reference: https://wiki.libsdl.org/SDL3/SDL_CreateWindow // reference: https://wiki.libsdl.org/SDL3/SDL_CreateWindow
class Window { class Window {
@@ -17,6 +18,7 @@ public:
bool rendering() { return rendering_; } bool rendering() { return rendering_; }
bool open() { return open_; } bool open() { return open_; }
bool createSurface(vk::raii::SurfaceKHR* surface);
private: private: