Small tweaks

This commit is contained in:
macmacmac 2025-08-08 13:42:13 -04:00
parent 65cd03961d
commit e82355d05d
8 changed files with 106 additions and 131 deletions

4
.gitignore vendored
View File

@ -103,7 +103,9 @@ CMakeUserPresets.json
# Other # Other
.cache/ .cache/
.vscode/ .vscode/
build/ build*/
.kdev4/ .kdev4/
*.kdev4 *.kdev4
*_old.*

3
.gitmodules vendored
View File

@ -1,6 +1,3 @@
[submodule "thirdparty/vk-bootstrap"]
path = thirdparty/vk-bootstrap
url = https://github.com/charles-lunarg/vk-bootstrap.git
[submodule "thirdparty/SDL"] [submodule "thirdparty/SDL"]
path = thirdparty/SDL path = thirdparty/SDL
url = https://github.com/libsdl-org/SDL.git url = https://github.com/libsdl-org/SDL.git

View File

@ -1,10 +1,11 @@
cmake_minimum_required(VERSION 3.10) cmake_minimum_required(VERSION 3.10)
project(vksdlproj VERSION 0.2.0 LANGUAGES C CXX) project(vksdlproj VERSION 0.2.0 LANGUAGES C CXX)
SET(CMAKE_BUILD_RPATH_USE_ORIGIN TRUE) #set(CMAKE_BUILD_RPATH_USE_ORIGIN TRUE)
set(EXE_NAME project) #set(CMAKE_POSITION_INDEPENDENT_CODE TRUE)
set(EXE_NAME sdl3vkgame)
set(PROGRAM_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src/vulkanapp.cc) set(PROGRAM_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src/vk_app.cc)
option(SDL3_NONSYSTEM "Use SDL3 from folder in source tree" ON) option(SDL3_NONSYSTEM "Use SDL3 from folder in source tree" ON)
@ -31,8 +32,6 @@ else()
find_package(SDL3 REQUIRED CONFIG REQUIRED COMPONENTS SDL3-shared) find_package(SDL3 REQUIRED CONFIG REQUIRED COMPONENTS SDL3-shared)
endif() endif()
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/thirdparty/vk-bootstrap)
find_package(Vulkan REQUIRED COMPONENTS glslc) find_package(Vulkan REQUIRED COMPONENTS glslc)
# Compile each shader # Compile each shader
@ -76,5 +75,4 @@ endif()
# Linking # Linking
target_link_libraries(${EXE_NAME} PRIVATE SDL3::SDL3) target_link_libraries(${EXE_NAME} PRIVATE SDL3::SDL3)
target_link_libraries(${EXE_NAME} PRIVATE Vulkan::Vulkan) target_link_libraries(${EXE_NAME} PRIVATE Vulkan::Vulkan) # TODO: change this to Vulkna::Headers and use loader
target_link_libraries(${EXE_NAME} PRIVATE vk-bootstrap::vk-bootstrap)

View File

@ -1,15 +1,19 @@
#pragma once #pragma once
#include <SDL3/SDL_video.h> #include <SDL3/SDL_init.h>
#include <SDL3/SDL_events.h> #include <SDL3/SDL_log.h>
#include <SDL3/SDL_vulkan.h>
#include <cstdint> #include <vulkan/vulkan.h>
#include <stdexcept>
#include <set>
#include <limits>
#include <algorithm>
#include <vector> #include <vector>
#include <optional> #include <optional>
#include <cstdio> #include "vk_types.hh"
#include <vulkan/vulkan.h>
const std::vector<const char*> validationLayers = { const std::vector<const char*> validationLayers = {
"VK_LAYER_KHRONOS_validation" "VK_LAYER_KHRONOS_validation"
@ -21,56 +25,42 @@ const std::vector<const char*> deviceExtensions = {
const int MAX_FRAMES_IN_FLIGHT = 2; const int MAX_FRAMES_IN_FLIGHT = 2;
#ifdef NDEBUG
const bool enableValidationLayers = false;
#else
const bool enableValidationLayers = true;
#endif
VkResult CreateDebugUtilsMessengerEXT(VkInstance, const VkDebugUtilsMessengerCreateInfoEXT*, const VkAllocationCallbacks*, VkDebugUtilsMessengerEXT*); VkResult CreateDebugUtilsMessengerEXT(VkInstance, const VkDebugUtilsMessengerCreateInfoEXT*, const VkAllocationCallbacks*, VkDebugUtilsMessengerEXT*);
void DestroyDebugUtilsMessengerEXT(VkInstance, VkDebugUtilsMessengerEXT, const VkAllocationCallbacks*); void DestroyDebugUtilsMessengerEXT(VkInstance, VkDebugUtilsMessengerEXT, const VkAllocationCallbacks*);
struct QueueFamilyIndices {
std::optional<uint32_t> graphicsFamily;
std::optional<uint32_t> presentFamily;
bool complete() {
return graphicsFamily.has_value() && presentFamily.has_value();
}
};
struct SwapChainSupportDetails {
VkSurfaceCapabilitiesKHR capabilities;
std::vector<VkSurfaceFormatKHR> formats;
std::vector<VkPresentModeKHR> presentModes;
};
class VulkanApp { class VulkanApp {
public: public:
VulkanApp(const uint32_t& _w, const uint32_t& _h) : VulkanApp(const char *_t, const uint32_t& _w, const uint32_t& _h) :
mWin(nullptr), mWidth(_w), mHeight(_h) {} mWin(nullptr), mWidth(_w), mHeight(_h), mTitle(_t),
mResized(false), mMinimized(false),
mPhysicalDevice(nullptr) {}
~VulkanApp() { cleanup(); }
void init(); SDL_AppResult mAppState = SDL_APP_CONTINUE;
void loop(); SDL_AppResult init();
void cleanup(); SDL_AppResult loop();
inline bool minimized() { return mMinimized; } inline bool minimized() { return mMinimized; }
inline void minimized(bool v) { mMinimized = v; } inline void minimized(bool _v) { mMinimized = _v; }
inline void resized(bool v) { mResized = v; } inline void resized(bool _v) { mResized = _v; }
private: private:
// SDL2 // SDL3
SDL_Window *mWin; SDL_Window *mWin;
SDL_Event mEvent;
// Not tied to library
uint32_t mWidth; uint32_t mWidth;
uint32_t mHeight; uint32_t mHeight;
// bool mActive = false; const char *mTitle;
bool mResized = false; bool mResized;
bool mMinimized = false; bool mMinimized;
#ifdef NDEBUG
const bool mEnableValidationLayers = false;
#else
const bool mEnableValidationLayers = true;
#endif
// Vulkan // Vulkan
VkInstance mInstance; VkInstance mInstance;
VkPhysicalDevice mPhysicalDevice = VK_NULL_HANDLE; VkPhysicalDevice mPhysicalDevice;
VkDevice mLogicalDevice; VkDevice mLogicalDevice;
VkSurfaceKHR mSurface; VkSurfaceKHR mSurface;
@ -95,7 +85,6 @@ private:
std::vector<VkSemaphore> mRenderFinishedSemaphores; std::vector<VkSemaphore> mRenderFinishedSemaphores;
std::vector<VkFence> mInFlightFences; std::vector<VkFence> mInFlightFences;
VkDebugUtilsMessengerEXT mDebugMessenger; VkDebugUtilsMessengerEXT mDebugMessenger;
void createInstance(); void createInstance();
@ -116,6 +105,7 @@ private:
void recordCommandBuffer(VkCommandBuffer, uint32_t); void recordCommandBuffer(VkCommandBuffer, uint32_t);
void drawFrame(); void drawFrame();
void cleanup();
QueueFamilyIndices findQueueFamilies(VkPhysicalDevice); QueueFamilyIndices findQueueFamilies(VkPhysicalDevice);
bool isDeviceSuitable(VkPhysicalDevice); bool isDeviceSuitable(VkPhysicalDevice);
@ -135,11 +125,11 @@ private:
(void)pUserData; (void)pUserData;
if(messageSeverity >= VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT) { if(messageSeverity >= VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT) {
fprintf(stderr, "Validation Layer [Error/Warning]: %s \n", pCallbackData->pMessage); SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Validation Layer [Error/Warning]: %s \n", pCallbackData->pMessage);
} else if(messageType & VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT) { } else if(messageType & VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT) {
fprintf(stderr, "Validation Layer [General]: %s \n", pCallbackData->pMessage); SDL_Log("Validation Layer [General]: %s \n", pCallbackData->pMessage);
} else { } else {
fprintf(stderr, "Validation Layer: %s \n", pCallbackData->pMessage); SDL_Log("Validation Layer: %s \n", pCallbackData->pMessage);
} }
return VK_FALSE; return VK_FALSE;

18
include/vk_types.hh Normal file
View File

@ -0,0 +1,18 @@
#pragma once
#include <vulkan/vulkan.hpp>
struct QueueFamilyIndices {
std::optional<uint32_t> graphicsFamily;
std::optional<uint32_t> presentFamily;
bool complete() {
return graphicsFamily.has_value() && presentFamily.has_value();
}
};
struct SwapChainSupportDetails {
VkSurfaceCapabilitiesKHR capabilities;
std::vector<VkSurfaceFormatKHR> formats;
std::vector<VkPresentModeKHR> presentModes;
};

View File

@ -1,95 +1,61 @@
#define SDL_MAIN_USE_CALLBACKS #define SDL_MAIN_USE_CALLBACKS
#include <SDL3/SDL_main.h> #include <SDL3/SDL_main.h>
#include <SDL3/SDL_init.h>
#include <SDL3/SDL.h>
#include "vulkanapp.hh" #include "vk_app.hh"
#include <exception>
constexpr uint32_t winInitWidth = 1024; constexpr uint32_t winInitWidth = 1024;
constexpr uint32_t winInitHeight = 1024; constexpr uint32_t winInitHeight = 1024;
struct AppContext {
VulkanApp vkapp;
SDL_AppResult appQuit = SDL_APP_CONTINUE;
AppContext(const uint32_t& _w, const uint32_t& _h) : vkapp(_w, _h) {
this->vkapp.init();
}
~AppContext() {
this->vkapp.cleanup();
}
};
SDL_AppResult SDL_Fail() {
SDL_LogError(SDL_LOG_CATEGORY_ERROR, "Error: %s", SDL_GetError());
return SDL_APP_FAILURE;
}
SDL_AppResult SDL_AppInit(void **appstate, int argc, char **argv) { SDL_AppResult SDL_AppInit(void **appstate, int argc, char **argv) {
(void)argc; (void)argc;
(void)argv; (void)argv;
if(!SDL_Init(SDL_INIT_VIDEO)) *appstate = new VulkanApp("Vulkan+SDL3 App", winInitWidth, winInitHeight);
return SDL_Fail(); VulkanApp* app = static_cast<VulkanApp*>(*appstate);
try { return app->init();
*appstate = new AppContext(winInitWidth, winInitHeight);
} catch(const std::exception& except) {
fprintf(stderr, "Error! %s\n", except.what());
return SDL_APP_FAILURE;
}
return SDL_APP_CONTINUE;
} }
SDL_AppResult SDL_AppEvent(void *appstate, SDL_Event *event) { SDL_AppResult SDL_AppEvent(void *appstate, SDL_Event *event) {
AppContext* app = static_cast<AppContext*>(appstate); VulkanApp* app = static_cast<VulkanApp*>(appstate);
switch(event->type) { switch(event->type) {
case SDL_EVENT_QUIT: case SDL_EVENT_QUIT:
app->appQuit = SDL_APP_SUCCESS; app->mAppState = SDL_APP_SUCCESS;
break; break;
case SDL_EVENT_WINDOW_RESIZED: case SDL_EVENT_WINDOW_RESIZED:
app->vkapp.resized(true); app->resized(true);
break; break;
case SDL_EVENT_WINDOW_MINIMIZED: case SDL_EVENT_WINDOW_MINIMIZED:
app->vkapp.minimized(true); app->minimized(true);
break; break;
case SDL_EVENT_WINDOW_RESTORED: case SDL_EVENT_WINDOW_RESTORED:
app->vkapp.minimized(false); app->minimized(false);
break; break;
default: default:
break; break;
} }
return SDL_APP_CONTINUE; return app->mAppState;
} }
SDL_AppResult SDL_AppIterate(void *appstate) { SDL_AppResult SDL_AppIterate(void *appstate) {
AppContext* app = static_cast<AppContext*>(appstate); VulkanApp* app = static_cast<VulkanApp*>(appstate);
try { return app->loop();
app->vkapp.loop();
} catch(const std::exception& except) {
fprintf(stderr, "Error! %s\n", except.what());
return SDL_APP_FAILURE;
}
return app->appQuit;
} }
void SDL_AppQuit(void *appstate, SDL_AppResult result) { void SDL_AppQuit(void *appstate, SDL_AppResult result) {
AppContext* app = static_cast<AppContext*>(appstate); VulkanApp* app = static_cast<VulkanApp*>(appstate);
#ifndef NDEBUG
if(result == SDL_APP_FAILURE) if(result == SDL_APP_FAILURE)
fputs("Program failure, shutting down\n", stderr); SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Program failure occured, shutting down");
else else
puts("Program shutting down, no errors."); SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "Program shutting down, no errors.");
#endif
if(app)
delete app;
// Cleanup
if(app) delete app;
SDL_Quit(); SDL_Quit();
} }

View File

@ -1,12 +1,4 @@
#include "vulkanapp.hh" #include "vk_app.hh"
#include <SDL3/SDL.h>
#include <SDL3/SDL_vulkan.h>
#include <stdexcept>
#include <set>
#include <limits>
#include <algorithm>
// Validator stuff // Validator stuff
VkResult CreateDebugUtilsMessengerEXT(VkInstance instance, VkResult CreateDebugUtilsMessengerEXT(VkInstance instance,
@ -159,7 +151,7 @@ VkSurfaceFormatKHR VulkanApp::chooseSwapSurfaceFormat(const std::vector<VkSurfac
VkPresentModeKHR VulkanApp::chooseSwapPresentMode(const std::vector<VkPresentModeKHR>& availablePresentModes) { VkPresentModeKHR VulkanApp::chooseSwapPresentMode(const std::vector<VkPresentModeKHR>& availablePresentModes) {
for (const VkPresentModeKHR& availablePresentMode : availablePresentModes) { for (const VkPresentModeKHR& availablePresentMode : availablePresentModes) {
if (availablePresentMode == VK_PRESENT_MODE_MAILBOX_KHR) { if (availablePresentMode == VK_PRESENT_MODE_FIFO_KHR) {
return availablePresentMode; return availablePresentMode;
} }
} }
@ -303,12 +295,18 @@ void VulkanApp::drawFrame() {
currentFrame = (currentFrame + 1) % MAX_FRAMES_IN_FLIGHT; currentFrame = (currentFrame + 1) % MAX_FRAMES_IN_FLIGHT;
} }
void VulkanApp::init() { SDL_AppResult VulkanApp::init() {
// Initialize SDL3 // Initialize SDL3
SDL_Init(SDL_INIT_VIDEO); SDL_Init(SDL_INIT_VIDEO);
// if(!SDL_Vulkan_LoadLibrary(nullptr)) {
// std::string err = "Could not load vulkan library! " + std::string(SDL_GetError()) + "\n";
//
// throw std::runtime_error(err);
// }
// Create the window // Create the window
mWin = SDL_CreateWindow("Vulkan+SDL2 Application", mWin = SDL_CreateWindow(mTitle,
mWidth, mWidth,
mHeight, mHeight,
SDL_WINDOW_VULKAN | SDL_WINDOW_RESIZABLE SDL_WINDOW_VULKAN | SDL_WINDOW_RESIZABLE
@ -319,6 +317,9 @@ void VulkanApp::init() {
throw std::runtime_error(err); throw std::runtime_error(err);
} }
SDL_SetWindowMaximumSize(mWin, mWidth, mHeight);
SDL_SetWindowMinimumSize(mWin, mWidth / 2, mHeight / 2);
// Vulkan stuff from here // Vulkan stuff from here
createInstance(); createInstance();
setupDebugMessenger(); setupDebugMessenger();
@ -328,7 +329,7 @@ void VulkanApp::init() {
throw std::runtime_error("Could not create Vulkan surface!"); throw std::runtime_error("Could not create Vulkan surface!");
} }
// TODO: Replace some of this crap with vkbootstrap code // TODO: Replace some of this crap with vulkan hpp code
selectPhysicalDevice(); selectPhysicalDevice();
createLogicalDevice(); createLogicalDevice();
createSwapChain(); createSwapChain();
@ -339,10 +340,12 @@ void VulkanApp::init() {
createCommandPool(); createCommandPool();
createCommandBuffer(); createCommandBuffer();
createSyncObjects(); createSyncObjects();
return SDL_APP_CONTINUE;
} }
void VulkanApp::createInstance() { void VulkanApp::createInstance() {
if (enableValidationLayers && !checkValidationLayerSupport()) { if (mEnableValidationLayers && !checkValidationLayerSupport()) {
throw std::runtime_error("Validation layers requested, but not available!"); throw std::runtime_error("Validation layers requested, but not available!");
} }
@ -352,7 +355,7 @@ void VulkanApp::createInstance() {
// Put extensions into vector // Put extensions into vector
std::vector<const char*> extensionNames(extensionArr, extensionArr + extensionCount); std::vector<const char*> extensionNames(extensionArr, extensionArr + extensionCount);
if(enableValidationLayers) if(mEnableValidationLayers)
extensionNames.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME); extensionNames.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
// App info // App info
@ -362,7 +365,7 @@ void VulkanApp::createInstance() {
appInfo.applicationVersion = VK_MAKE_VERSION(1, 1, 0); appInfo.applicationVersion = VK_MAKE_VERSION(1, 1, 0);
appInfo.pEngineName = "RAPT2"; appInfo.pEngineName = "RAPT2";
appInfo.engineVersion = VK_MAKE_VERSION(1, 1, 0); appInfo.engineVersion = VK_MAKE_VERSION(1, 1, 0);
appInfo.apiVersion = VK_API_VERSION_1_3; appInfo.apiVersion = VK_API_VERSION_1_1;
// Extensions // Extensions
VkInstanceCreateInfo createInfo{}; VkInstanceCreateInfo createInfo{};
@ -374,7 +377,7 @@ void VulkanApp::createInstance() {
// Debug handling // Debug handling
VkDebugUtilsMessengerCreateInfoEXT debugCreateInfo{}; VkDebugUtilsMessengerCreateInfoEXT debugCreateInfo{};
if(enableValidationLayers) { if(mEnableValidationLayers) {
createInfo.enabledLayerCount = static_cast<uint32_t>(validationLayers.size()); createInfo.enabledLayerCount = static_cast<uint32_t>(validationLayers.size());
createInfo.ppEnabledLayerNames = validationLayers.data(); createInfo.ppEnabledLayerNames = validationLayers.data();
@ -456,7 +459,7 @@ void VulkanApp::createLogicalDevice() {
createInfo.enabledExtensionCount = static_cast<uint32_t>(deviceExtensions.size()); createInfo.enabledExtensionCount = static_cast<uint32_t>(deviceExtensions.size());
createInfo.ppEnabledExtensionNames = deviceExtensions.data(); createInfo.ppEnabledExtensionNames = deviceExtensions.data();
if (enableValidationLayers) { if (mEnableValidationLayers) {
createInfo.enabledLayerCount = static_cast<uint32_t>(validationLayers.size()); createInfo.enabledLayerCount = static_cast<uint32_t>(validationLayers.size());
createInfo.ppEnabledLayerNames = validationLayers.data(); createInfo.ppEnabledLayerNames = validationLayers.data();
} else { } else {
@ -836,7 +839,7 @@ bool VulkanApp::checkValidationLayerSupport() {
} }
void VulkanApp::setupDebugMessenger() { void VulkanApp::setupDebugMessenger() {
if (!enableValidationLayers) return; if (!mEnableValidationLayers) return;
VkDebugUtilsMessengerCreateInfoEXT createInfo; VkDebugUtilsMessengerCreateInfoEXT createInfo;
createInfo = {}; createInfo = {};
@ -854,7 +857,7 @@ void VulkanApp::setupDebugMessenger() {
} }
} }
void VulkanApp::loop() { SDL_AppResult VulkanApp::loop() {
if(mWin == nullptr) { if(mWin == nullptr) {
std::string err = "Could not find window " + std::string(SDL_GetError()) + "\n"; std::string err = "Could not find window " + std::string(SDL_GetError()) + "\n";
throw std::runtime_error(err); throw std::runtime_error(err);
@ -863,6 +866,8 @@ void VulkanApp::loop() {
if(!mMinimized) drawFrame(); if(!mMinimized) drawFrame();
vkDeviceWaitIdle(mLogicalDevice); vkDeviceWaitIdle(mLogicalDevice);
return SDL_APP_CONTINUE;
} }
void VulkanApp::cleanup() { void VulkanApp::cleanup() {
@ -883,7 +888,7 @@ void VulkanApp::cleanup() {
vkDestroyDevice(mLogicalDevice, nullptr); vkDestroyDevice(mLogicalDevice, nullptr);
if (enableValidationLayers) if (mEnableValidationLayers)
DestroyDebugUtilsMessengerEXT(mInstance, mDebugMessenger, nullptr); DestroyDebugUtilsMessengerEXT(mInstance, mDebugMessenger, nullptr);
vkDestroySurfaceKHR(mInstance, mSurface, nullptr); vkDestroySurfaceKHR(mInstance, mSurface, nullptr);

@ -1 +0,0 @@
Subproject commit 0437431fd055ac362d388a006a0fd861a6c945f2