mirror of
https://github.com/MadeOfJelly/MushMachine.git
synced 2025-04-19 17:52:57 +02:00
start refactoring
This commit is contained in:
parent
e55808b32f
commit
808822e70b
1
external/CMakeLists.txt
vendored
1
external/CMakeLists.txt
vendored
@ -39,6 +39,7 @@ if(NOT MM_HEADLESS)
|
|||||||
endif()
|
endif()
|
||||||
|
|
||||||
add_subdirectory("Vulkan-Headers")
|
add_subdirectory("Vulkan-Headers")
|
||||||
|
target_compile_definitions(Vulkan-Headers INTERFACE VULKAN_HPP_DISPATCH_LOADER_DYNAMIC=1)
|
||||||
|
|
||||||
# stb utilies
|
# stb utilies
|
||||||
add_subdirectory("stb")
|
add_subdirectory("stb")
|
||||||
|
@ -4,11 +4,13 @@
|
|||||||
#include <mm/services/sdl_service.hpp>
|
#include <mm/services/sdl_service.hpp>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#define VULKAN_HPP_DISPATCH_LOADER_DYNAMIC 1
|
|
||||||
#include <vulkan/vulkan.hpp>
|
#include <vulkan/vulkan.hpp>
|
||||||
|
|
||||||
#include <vulkan/vulkan_structs.hpp> // mf
|
#include <vulkan/vulkan_structs.hpp> // mf
|
||||||
#include <vulkan/vulkan_enums.hpp>
|
#include <vulkan/vulkan_enums.hpp>
|
||||||
|
#include "spdlog/spdlog.h"
|
||||||
|
#include "vulkan/vulkan_core.h"
|
||||||
|
#include "vulkan/vulkan_handles.hpp"
|
||||||
|
|
||||||
#include <SDL_vulkan.h>
|
#include <SDL_vulkan.h>
|
||||||
|
|
||||||
@ -16,17 +18,19 @@
|
|||||||
|
|
||||||
VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
|
VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
|
||||||
|
|
||||||
|
// create a dispatcher, based on additional vkDevice/vkGetDeviceProcAddr
|
||||||
void setup_dispacher(void) {
|
void setup_dispacher(void) {
|
||||||
// TODO: investigate why
|
#if 1
|
||||||
// TODO: use SDL?
|
// investigate why this stopped working
|
||||||
vk::DynamicLoader dl;
|
static vk::DynamicLoader dl;
|
||||||
PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr = dl.getProcAddress<PFN_vkGetInstanceProcAddr>("vkGetInstanceProcAddr");
|
PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr = dl.getProcAddress<PFN_vkGetInstanceProcAddr>("vkGetInstanceProcAddr");
|
||||||
VULKAN_HPP_DEFAULT_DISPATCHER.init(vkGetInstanceProcAddr);
|
#else
|
||||||
}
|
auto load_res = SDL_Vulkan_LoadLibrary(nullptr);
|
||||||
|
assert(load_res == 0);
|
||||||
|
PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr = reinterpret_cast<PFN_vkGetInstanceProcAddr>(SDL_Vulkan_GetVkGetInstanceProcAddr());
|
||||||
|
#endif
|
||||||
|
|
||||||
void setup_instance_dispatcher(const vk::Instance& instance) {
|
VULKAN_HPP_DEFAULT_DISPATCHER.init(vkGetInstanceProcAddr);
|
||||||
// initialize function pointers for instance
|
|
||||||
VULKAN_HPP_DEFAULT_DISPATCHER.init(instance);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool can_use_layer(std::string_view layer_want) {
|
bool can_use_layer(std::string_view layer_want) {
|
||||||
@ -131,31 +135,253 @@ vk::Instance create_instance(
|
|||||||
|
|
||||||
vk::Instance instance = vk::createInstance(c.get(), nullptr);
|
vk::Instance instance = vk::createInstance(c.get(), nullptr);
|
||||||
|
|
||||||
setup_instance_dispatcher(instance);
|
// initialize function pointers for instance
|
||||||
|
VULKAN_HPP_DEFAULT_DISPATCHER.init(instance);
|
||||||
|
|
||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setup_device_dispatcher(const vk::Device& device) {
|
namespace MM::Services {
|
||||||
// function pointer specialization for device
|
|
||||||
VULKAN_HPP_DEFAULT_DISPATCHER.init(device);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
class VulkanRenderer : public Service {
|
||||||
|
private:
|
||||||
|
VkInstance _instance{};
|
||||||
|
VkDebugUtilsMessengerEXT _debug_messenger{};
|
||||||
|
|
||||||
|
VkSurfaceKHR _surface{};
|
||||||
|
|
||||||
|
VkPhysicalDevice _physical_device{};
|
||||||
|
VkDevice _device{};
|
||||||
|
|
||||||
|
VkQueue _graphics_queue{};
|
||||||
|
//VkQueue _present_queue{};
|
||||||
|
VkSwapchainKHR _swapchain{};
|
||||||
|
|
||||||
|
public:
|
||||||
|
VulkanRenderer(void) {
|
||||||
|
#if 0
|
||||||
|
MM::Logger::initSectionLogger("VulkanGeneral");
|
||||||
|
// way too noisy otherwise
|
||||||
|
spdlog::get("VulkanGeneral")->set_level(spdlog::level::level_enum::warn);
|
||||||
|
#else
|
||||||
|
// or just dont log to stdio?
|
||||||
|
MM::Logger::initSectionLogger("VulkanGeneral", false);
|
||||||
|
#endif
|
||||||
|
MM::Logger::initSectionLogger("VulkanValidation");
|
||||||
|
MM::Logger::initSectionLogger("VulkanPerformance");
|
||||||
|
|
||||||
|
SPDLOG_INFO("constructed VulkanRenderer");
|
||||||
|
}
|
||||||
|
~VulkanRenderer(void) {};
|
||||||
|
|
||||||
|
bool enable(Engine& engine, std::vector<UpdateStrategies::TaskInfo>& task_array) override {
|
||||||
|
assert(!VULKAN_HPP_DEFAULT_DISPATCHER.vkEnumerateInstanceLayerProperties);
|
||||||
|
setup_dispacher();
|
||||||
|
assert(VULKAN_HPP_DEFAULT_DISPATCHER.vkEnumerateInstanceLayerProperties);
|
||||||
|
|
||||||
|
// create vulkan instance
|
||||||
|
const vk::ApplicationInfo app_info {
|
||||||
|
"app_name",
|
||||||
|
VK_MAKE_VERSION(1, 0, 0), // app version
|
||||||
|
"MushMachine",
|
||||||
|
// TODO: engine version macro or something
|
||||||
|
VK_MAKE_VERSION(0, 8, 0), // engine version
|
||||||
|
VK_API_VERSION_1_1
|
||||||
|
};
|
||||||
|
|
||||||
|
// TODO: make validation layer conditional
|
||||||
|
std::vector<const char*> layers{};
|
||||||
|
if (can_use_validation()) {
|
||||||
|
layers.push_back("VK_LAYER_KHRONOS_validation");
|
||||||
|
SPDLOG_INFO("ENABLED validation layer");
|
||||||
|
} else {
|
||||||
|
SPDLOG_INFO("validation layer NOT AVAILABLE!");
|
||||||
|
}
|
||||||
|
|
||||||
|
vk::Instance instance = create_instance(
|
||||||
|
app_info,
|
||||||
|
{},
|
||||||
|
layers
|
||||||
|
);
|
||||||
|
_instance = instance;
|
||||||
|
|
||||||
|
_debug_messenger = instance.createDebugUtilsMessengerEXT(debug_utils_messenger_create_info);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void disable(Engine&) override {
|
||||||
|
// cleanup
|
||||||
|
if (_device) {
|
||||||
|
vk::Device device{_device};
|
||||||
|
device.destroy(_swapchain);
|
||||||
|
device.destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
vk::Instance instance{_instance};
|
||||||
|
instance.destroy(_surface);
|
||||||
|
instance.destroy(_debug_messenger);
|
||||||
|
instance.destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* name(void) override { return "VulkanRenderer"; }
|
||||||
|
|
||||||
|
public:
|
||||||
|
bool createDevice(Engine& engine) {
|
||||||
|
// the surface for the window (not device dependent)
|
||||||
|
if (SDL_Vulkan_CreateSurface(engine.getService<SDLService>().win, _instance, &_surface) != SDL_TRUE) {
|
||||||
|
SPDLOG_ERROR("creating vulkan surface from window. (is the SDL_WINDOW_VULKAN flag set?)");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// convenience hpp wrapper
|
||||||
|
assert(_surface);
|
||||||
|
vk::SurfaceKHR surface{_surface};
|
||||||
|
assert(_instance);
|
||||||
|
vk::Instance instance{_instance};
|
||||||
|
|
||||||
|
auto physical_devices = instance.enumeratePhysicalDevices();
|
||||||
|
if (physical_devices.empty()) {
|
||||||
|
SPDLOG_ERROR("no physical vulkan devices found");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// list devices
|
||||||
|
for (const auto& ph_device : physical_devices) {
|
||||||
|
auto props = ph_device.getProperties();
|
||||||
|
SPDLOG_INFO(
|
||||||
|
"found device: [{}] ({}) '{}'",
|
||||||
|
props.deviceID,
|
||||||
|
(props.deviceType == vk::PhysicalDeviceType::eDiscreteGpu ? "discrete" : "other"),
|
||||||
|
props.deviceName
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto& selected_phys_dev = physical_devices.front();
|
||||||
|
_physical_device = selected_phys_dev;
|
||||||
|
|
||||||
|
for (const auto& fam_props : selected_phys_dev.getQueueFamilyProperties()) {
|
||||||
|
auto test_bit = [](const auto& flags, const auto& bit) -> bool {
|
||||||
|
return (flags & bit) == bit;
|
||||||
|
};
|
||||||
|
SPDLOG_INFO(
|
||||||
|
"QueueFamily: queueCount:{} graphics:{} compute:{} transfer:{}",
|
||||||
|
fam_props.queueCount,
|
||||||
|
test_bit(fam_props.queueFlags, vk::QueueFlagBits::eGraphics) ? "true" : "false",
|
||||||
|
test_bit(fam_props.queueFlags, vk::QueueFlagBits::eCompute) ? "true" : "false",
|
||||||
|
test_bit(fam_props.queueFlags, vk::QueueFlagBits::eTransfer) ? "true" : "false"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t queue_fam_index = 0;
|
||||||
|
|
||||||
|
// test for support for swapchain
|
||||||
|
if (selected_phys_dev.getSurfaceSupportKHR(queue_fam_index, surface) != VK_TRUE) {
|
||||||
|
SPDLOG_ERROR("selected device does not support the surface");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const float queue_prio = 1.f; // hmmmm
|
||||||
|
vk::DeviceQueueCreateInfo graphics_queue_create_info {
|
||||||
|
{},
|
||||||
|
queue_fam_index, // just pick the first one for now
|
||||||
|
1, // count
|
||||||
|
&queue_prio
|
||||||
|
};
|
||||||
|
|
||||||
|
vk::PhysicalDeviceFeatures device_features {
|
||||||
|
};
|
||||||
|
|
||||||
|
// do i need this?
|
||||||
|
std::vector<const char*> device_extentions{
|
||||||
|
VK_KHR_SWAPCHAIN_EXTENSION_NAME
|
||||||
|
};
|
||||||
|
|
||||||
|
vk::DeviceCreateInfo device_create_info {
|
||||||
|
{},
|
||||||
|
1,
|
||||||
|
&graphics_queue_create_info,
|
||||||
|
// layers
|
||||||
|
0,
|
||||||
|
nullptr,
|
||||||
|
// extensions
|
||||||
|
static_cast<uint32_t>(device_extentions.size()),
|
||||||
|
device_extentions.data(),
|
||||||
|
&device_features
|
||||||
|
};
|
||||||
|
vk::Device device = selected_phys_dev.createDevice(device_create_info, nullptr);
|
||||||
|
_device = device;
|
||||||
|
|
||||||
|
// function pointer specialization for device
|
||||||
|
VULKAN_HPP_DEFAULT_DISPATCHER.init(device);
|
||||||
|
|
||||||
|
//_present_queue = device.getQueue(0, 0);
|
||||||
|
// we assume it also does present
|
||||||
|
_graphics_queue = device.getQueue(0, 0);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool createSwapchain(Engine& engine) {
|
||||||
|
assert(_physical_device);
|
||||||
|
vk::PhysicalDevice physical_device {_physical_device};
|
||||||
|
assert(_device);
|
||||||
|
vk::Device device {_device};
|
||||||
|
|
||||||
|
vk::SurfaceFormatKHR swap_surf_format {
|
||||||
|
vk::Format::eB8G8R8A8Srgb,
|
||||||
|
vk::ColorSpaceKHR::eSrgbNonlinear,
|
||||||
|
};
|
||||||
|
{ // select format
|
||||||
|
//for (const auto& format : selected_phys_dev.getSurfaceFormatsKHR(surface)) {
|
||||||
|
//if (format.colorSpace == vk::ColorSpaceKHR::eSrgbNonlinear) {
|
||||||
|
//if (format.format == vk::Format::eB8G8R8A8Srgb) {
|
||||||
|
|
||||||
|
//}
|
||||||
|
//}
|
||||||
|
//}
|
||||||
|
}
|
||||||
|
|
||||||
|
vk::Extent2D surface_extent {};
|
||||||
|
{
|
||||||
|
int w, h;
|
||||||
|
SDL_Vulkan_GetDrawableSize(engine.getService<SDLService>().win, &w, &h);
|
||||||
|
surface_extent.width = w;
|
||||||
|
surface_extent.height = h;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto phys_surf_caps = physical_device.getSurfaceCapabilitiesKHR(_surface);
|
||||||
|
|
||||||
|
// flush all loggers
|
||||||
|
spdlog::apply_all([](const auto& logger) { logger->flush(); });
|
||||||
|
|
||||||
|
assert(VULKAN_HPP_DEFAULT_DISPATCHER.vkCreateSwapchainKHR);
|
||||||
|
|
||||||
|
// create the swapchain
|
||||||
|
_swapchain = device.createSwapchainKHR({
|
||||||
|
{},
|
||||||
|
_surface,
|
||||||
|
phys_surf_caps.minImageCount,
|
||||||
|
swap_surf_format.format,
|
||||||
|
swap_surf_format.colorSpace,
|
||||||
|
surface_extent,
|
||||||
|
1, // imageArrayLayers
|
||||||
|
vk::ImageUsageFlagBits::eColorAttachment,
|
||||||
|
vk::SharingMode::eExclusive,
|
||||||
|
// TODO: fill in rest
|
||||||
|
});
|
||||||
|
|
||||||
|
auto images = device.getSwapchainImagesKHR(_swapchain);
|
||||||
|
SPDLOG_INFO("have {} swapchain images", images.size());
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // MM::Services
|
||||||
|
|
||||||
TEST(sdl_service, window_vulkan) {
|
TEST(sdl_service, window_vulkan) {
|
||||||
MM::Engine engine;
|
MM::Engine engine;
|
||||||
{ // setup vulkan loggers
|
|
||||||
#if 0
|
|
||||||
MM::Logger::initSectionLogger("VulkanGeneral");
|
|
||||||
// way too noisy otherwise
|
|
||||||
spdlog::get("VulkanGeneral")->set_level(spdlog::level::level_enum::warn);
|
|
||||||
#else
|
|
||||||
// or just dont log to stdio?
|
|
||||||
MM::Logger::initSectionLogger("VulkanGeneral", false);
|
|
||||||
#endif
|
|
||||||
MM::Logger::initSectionLogger("VulkanValidation");
|
|
||||||
MM::Logger::initSectionLogger("VulkanPerformance");
|
|
||||||
}
|
|
||||||
|
|
||||||
engine.addService<MM::Services::SDLService>();
|
engine.addService<MM::Services::SDLService>();
|
||||||
ASSERT_TRUE(engine.enableService<MM::Services::SDLService>());
|
ASSERT_TRUE(engine.enableService<MM::Services::SDLService>());
|
||||||
@ -163,118 +389,21 @@ TEST(sdl_service, window_vulkan) {
|
|||||||
auto* sdl_ss_ptr = engine.tryService<MM::Services::SDLService>();
|
auto* sdl_ss_ptr = engine.tryService<MM::Services::SDLService>();
|
||||||
ASSERT_NE(sdl_ss_ptr, nullptr);
|
ASSERT_NE(sdl_ss_ptr, nullptr);
|
||||||
|
|
||||||
setup_dispacher();
|
|
||||||
|
|
||||||
// create window
|
// create window
|
||||||
ASSERT_EQ(sdl_ss_ptr->win, nullptr);
|
ASSERT_EQ(sdl_ss_ptr->win, nullptr);
|
||||||
ASSERT_TRUE(sdl_ss_ptr->createWindow("test vulkan window", 800, 600, SDL_WINDOW_VULKAN));
|
ASSERT_TRUE(sdl_ss_ptr->createWindow("test vulkan window", 800, 600, SDL_WINDOW_VULKAN));
|
||||||
ASSERT_NE(sdl_ss_ptr->win, nullptr);
|
ASSERT_NE(sdl_ss_ptr->win, nullptr);
|
||||||
|
|
||||||
// create vulkan instance
|
engine.addService<MM::Services::VulkanRenderer>();
|
||||||
|
ASSERT_TRUE(engine.enableService<MM::Services::VulkanRenderer>());
|
||||||
|
|
||||||
const vk::ApplicationInfo app_info {
|
auto& vk_rend = engine.getService<MM::Services::VulkanRenderer>();
|
||||||
"app_name",
|
ASSERT_TRUE(vk_rend.createDevice(engine));
|
||||||
VK_MAKE_VERSION(1, 0, 0), // app version
|
ASSERT_TRUE(vk_rend.createSwapchain(engine));
|
||||||
"MushMachine",
|
|
||||||
// TODO: engine version macro or something
|
|
||||||
VK_MAKE_VERSION(0, 8, 0), // engine version
|
|
||||||
VK_API_VERSION_1_1
|
|
||||||
};
|
|
||||||
|
|
||||||
// TODO: make validation layer conditional
|
engine.run();
|
||||||
std::vector<const char*> layers{};
|
|
||||||
if (can_use_validation()) {
|
|
||||||
layers.push_back("VK_LAYER_KHRONOS_validation");
|
|
||||||
SPDLOG_INFO("ENABLED validation layer");
|
|
||||||
} else {
|
|
||||||
SPDLOG_INFO("validation layer NOT AVAILABLE!");
|
|
||||||
}
|
|
||||||
|
|
||||||
vk::Instance instance = create_instance(
|
|
||||||
app_info,
|
|
||||||
{},
|
|
||||||
layers
|
|
||||||
);
|
|
||||||
ASSERT_NE(static_cast<VkInstance>(instance), nullptr);
|
|
||||||
|
|
||||||
auto debug_messenger = instance.createDebugUtilsMessengerEXT(debug_utils_messenger_create_info);
|
|
||||||
|
|
||||||
// the surface for the window (no device dependent?)
|
|
||||||
VkSurfaceKHR surface;
|
|
||||||
ASSERT_TRUE(
|
|
||||||
SDL_Vulkan_CreateSurface(
|
|
||||||
sdl_ss_ptr->win,
|
|
||||||
instance,
|
|
||||||
&surface
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
// create a dispatcher, based on additional vkDevice/vkGetDeviceProcAddr
|
|
||||||
auto physicalDevices = instance.enumeratePhysicalDevices();
|
|
||||||
ASSERT_TRUE(!physicalDevices.empty()); // make test fail on unsupported machines
|
|
||||||
|
|
||||||
// list devices
|
|
||||||
for (const auto& ph_device : physicalDevices) {
|
|
||||||
auto props = ph_device.getProperties();
|
|
||||||
SPDLOG_INFO(
|
|
||||||
"found device: [{}] ({}) '{}'",
|
|
||||||
props.deviceID,
|
|
||||||
(props.deviceType == vk::PhysicalDeviceType::eDiscreteGpu ? "discrete" : "other"),
|
|
||||||
props.deviceName
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
auto& selected_phys_dev = physicalDevices.front();
|
|
||||||
for (const auto& fam_props : selected_phys_dev.getQueueFamilyProperties()) {
|
|
||||||
auto test_bit = [](const auto& flags, const auto& bit) -> bool {
|
|
||||||
return (flags & bit) == bit;
|
|
||||||
};
|
|
||||||
SPDLOG_INFO(
|
|
||||||
"QueueFamily: queueCount:{} graphics:{} compute:{} transfer:{}",
|
|
||||||
fam_props.queueCount,
|
|
||||||
test_bit(fam_props.queueFlags, vk::QueueFlagBits::eGraphics) ? "true" : "false",
|
|
||||||
test_bit(fam_props.queueFlags, vk::QueueFlagBits::eCompute) ? "true" : "false",
|
|
||||||
test_bit(fam_props.queueFlags, vk::QueueFlagBits::eTransfer) ? "true" : "false"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const float queue_prio = 1.f; // hmmmm
|
|
||||||
vk::DeviceQueueCreateInfo graphics_queue_create_info {
|
|
||||||
{},
|
|
||||||
0, // just pick the first one for now
|
|
||||||
1, // count
|
|
||||||
&queue_prio
|
|
||||||
};
|
|
||||||
|
|
||||||
vk::PhysicalDeviceFeatures device_features {
|
|
||||||
};
|
|
||||||
|
|
||||||
vk::DeviceCreateInfo device_create_info {
|
|
||||||
{},
|
|
||||||
1,
|
|
||||||
&graphics_queue_create_info,
|
|
||||||
// layers
|
|
||||||
0,
|
|
||||||
nullptr,
|
|
||||||
// extensions
|
|
||||||
0,
|
|
||||||
nullptr,
|
|
||||||
&device_features
|
|
||||||
};
|
|
||||||
vk::Device device = selected_phys_dev.createDevice(device_create_info, nullptr);
|
|
||||||
ASSERT_NE(static_cast<VkDevice>(device), nullptr);
|
|
||||||
|
|
||||||
setup_device_dispatcher(device);
|
|
||||||
|
|
||||||
vk::Queue graphics_queue = device.getQueue(0, 0);
|
|
||||||
|
|
||||||
// cleanup
|
|
||||||
device.destroy();
|
|
||||||
|
|
||||||
instance.destroy(surface);
|
|
||||||
instance.destroy(debug_messenger);
|
|
||||||
instance.destroy();
|
|
||||||
|
|
||||||
|
engine.disableService<MM::Services::VulkanRenderer>();
|
||||||
engine.disableService<MM::Services::SDLService>();
|
engine.disableService<MM::Services::SDLService>();
|
||||||
|
|
||||||
ASSERT_EQ(sdl_ss_ptr->win, nullptr);
|
ASSERT_EQ(sdl_ss_ptr->win, nullptr);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user