diff --git a/CMakeLists.txt b/CMakeLists.txt index 8dae3ac..98324d1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -34,6 +34,8 @@ add_library(maiden_core STATIC src/Window.cpp src/Engine.cpp src/Device.cpp + src/Pipeline.cpp + src/Swapchain.cpp # include extra source files here ) diff --git a/src/Device.cpp b/src/Device.cpp index 41d2cdd..f3efab8 100644 --- a/src/Device.cpp +++ b/src/Device.cpp @@ -3,7 +3,10 @@ #include -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) { score += 2; } 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 @@ -107,6 +110,11 @@ uint32_t Device::evaluatePhysicalDevice(vk::raii::PhysicalDevice& device) { 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) { std::cout << "[" << __FUNCTION__ << ": " << __LINE__ << "] Error: cannot create logical device without a valid physical device." << std::endl; return false; @@ -114,11 +122,20 @@ bool Device::createLogicalDevice() { // specify queue family requirements std::vector queueFamilyProperties = physicalDevice_.getQueueFamilyProperties(); - auto graphicsQueueFamilyProperty = std::ranges::find_if(queueFamilyProperties, [](auto const &qfp) { return (qfp.queueFlags & vk::QueueFlagBits::eGraphics) != static_cast(0); }); - auto graphicsIndex = static_cast(std::distance(queueFamilyProperties.begin(), graphicsQueueFamilyProperty)); - float queuePriority = 1.0f; + int32_t queueIndex = -1; + for(uint32_t qfpIndex = 0; qfpIndex < queueFamilyProperties.size(); qfpIndex++) { + if((queueFamilyProperties[qfpIndex].queueFlags & vk::QueueFlagBits::eGraphics) && physicalDevice_.getSurfaceSupportKHR(qfpIndex, *surface_)) { + queueIndex = static_cast(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 { - .queueFamilyIndex = graphicsIndex, + .queueFamilyIndex = queueIndex, .queueCount = 1, .pQueuePriorities = &queuePriority }; @@ -143,7 +160,7 @@ bool Device::createLogicalDevice() { logicalDevice_ = vk::raii::Device(physicalDevice_, deviceCreateInfo); // initialize the graphics queue - graphicsQueue_ = vk::raii::Queue(logicalDevice_, graphicsIndex, 0); + graphicsQueue_ = vk::raii::Queue(logicalDevice_, queueIndex, 0); if(logicalDevice_ != nullptr) { return true; @@ -153,3 +170,9 @@ bool Device::createLogicalDevice() { } } + +void Device::createSurface() { + + (void)window_->createSurface(&surface_); + +} diff --git a/src/Device.hpp b/src/Device.hpp index 61bd35b..8eb363d 100644 --- a/src/Device.hpp +++ b/src/Device.hpp @@ -3,11 +3,13 @@ #include -class Device { +#include "Window.hpp" + +class Device { public: - Device(vk::raii::Instance* instance); + Device(vk::raii::Instance* instance, Window* window); ~Device(); // 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 uint32_t evaluatePhysicalDevice(vk::raii::PhysicalDevice& device); + // internal create surface + void createSurface(); + + // vulkan objects vk::raii::Instance* instance_ = nullptr; vk::raii::PhysicalDevice physicalDevice_ = nullptr; vk::raii::Device logicalDevice_ = 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 std::vector requiredDeviceExtensions_ = { vk::KHRSwapchainExtensionName }; diff --git a/src/Engine.cpp b/src/Engine.cpp index ad7ca36..c7ee7e9 100644 --- a/src/Engine.cpp +++ b/src/Engine.cpp @@ -22,7 +22,7 @@ void Engine::init() { } // device selection and setup - Device device(&instance_); + Device device(&instance_, window_); (void)device.selectPhysicalDevice(); (void)device.createLogicalDevice(); diff --git a/src/Pipeline.cpp b/src/Pipeline.cpp new file mode 100644 index 0000000..cc8a850 --- /dev/null +++ b/src/Pipeline.cpp @@ -0,0 +1,6 @@ + +#include "Pipeline.hpp" + +Pipeline::Pipeline(Device* device) : device_(device) { + +} diff --git a/src/Pipeline.hpp b/src/Pipeline.hpp new file mode 100644 index 0000000..64caa07 --- /dev/null +++ b/src/Pipeline.hpp @@ -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 +}; diff --git a/src/Swapchain.cpp b/src/Swapchain.cpp new file mode 100644 index 0000000..8be4204 --- /dev/null +++ b/src/Swapchain.cpp @@ -0,0 +1,6 @@ + +#include "Swapchain.hpp" + +Swapchain::Swapchain() { + +} diff --git a/src/Swapchain.hpp b/src/Swapchain.hpp new file mode 100644 index 0000000..cba4749 --- /dev/null +++ b/src/Swapchain.hpp @@ -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: + +}; \ No newline at end of file diff --git a/src/Window.cpp b/src/Window.cpp index 2e43b87..3636d14 100644 --- a/src/Window.cpp +++ b/src/Window.cpp @@ -2,6 +2,7 @@ #include "Window.hpp" #include +#include Window::Window() { @@ -43,3 +44,26 @@ void Window::handleEvent(SDL_Event& event) { 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; + } +} diff --git a/src/Window.hpp b/src/Window.hpp index a8889e8..47badf2 100644 --- a/src/Window.hpp +++ b/src/Window.hpp @@ -1,8 +1,9 @@ #pragma once -#include "SDL3/SDL.h" -#include "SDL3/SDL_vulkan.h" +#include +#include +#include // reference: https://wiki.libsdl.org/SDL3/SDL_CreateWindow class Window { @@ -17,6 +18,7 @@ public: bool rendering() { return rendering_; } bool open() { return open_; } + bool createSurface(vk::raii::SurfaceKHR* surface); private: