Weird MacOS MoltenVK EXC_BAD_ACCESS on destruction of vulkan objects.
This commit is contained in:
parent
d0e0718b1e
commit
14f0c05b68
|
|
@ -1,4 +1,4 @@
|
||||||
cmake_minimum_required(VERSION 3.31)
|
cmake_minimum_required(VERSION 3.30.5)
|
||||||
project(Dyn)
|
project(Dyn)
|
||||||
|
|
||||||
set(CMAKE_CXX_STANDARD 26)
|
set(CMAKE_CXX_STANDARD 26)
|
||||||
|
|
@ -8,6 +8,7 @@ include_directories("${CMAKE_CURRENT_SOURCE_DIR}/inc")
|
||||||
|
|
||||||
find_package(Vulkan REQUIRED)
|
find_package(Vulkan REQUIRED)
|
||||||
find_package(glfw3 CONFIG REQUIRED)
|
find_package(glfw3 CONFIG REQUIRED)
|
||||||
|
find_package(VulkanUtilityLibraries CONFIG REQUIRED)
|
||||||
|
|
||||||
foreach (file ${sourceFiles})
|
foreach (file ${sourceFiles})
|
||||||
message("Source File Found ${file}")
|
message("Source File Found ${file}")
|
||||||
|
|
@ -17,3 +18,4 @@ add_executable(Dyn ${sourceFiles})
|
||||||
|
|
||||||
target_link_libraries(Dyn PRIVATE Vulkan::Vulkan)
|
target_link_libraries(Dyn PRIVATE Vulkan::Vulkan)
|
||||||
target_link_libraries(Dyn PRIVATE glfw)
|
target_link_libraries(Dyn PRIVATE glfw)
|
||||||
|
target_link_libraries(Dyn PRIVATE Vulkan::SafeStruct Vulkan::LayerSettings Vulkan::UtilityHeaders Vulkan::CompilerConfiguration)
|
||||||
|
|
@ -15,6 +15,11 @@ namespace dyn {
|
||||||
return std::dynamic_pointer_cast<To>(from);
|
return std::dynamic_pointer_cast<To>(from);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename T, typename ...Args>
|
||||||
|
ref<T> create_ref(Args&&... args) {
|
||||||
|
return std::make_shared<T>(std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
namespace core {
|
namespace core {
|
||||||
enum class RenderPlatform {
|
enum class RenderPlatform {
|
||||||
None,
|
None,
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,11 @@
|
||||||
#define DYN_DEBUG
|
#define DYN_DEBUG
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define DYN_WARNING_LOG(...) ::dyn::core::warnln(__VA_ARGS__)
|
||||||
#define DYN_FATAL_LOG(...) ::dyn::core::fatalln(__VA_ARGS__)
|
#define DYN_FATAL_LOG(...) ::dyn::core::fatalln(__VA_ARGS__)
|
||||||
|
#define DYN_DEBUG_LOG(...) ::dyn::core::debugln(__VA_ARGS__)
|
||||||
|
#define DYN_ERROR_LOG(...) ::dyn::core::errorln(__VA_ARGS__)
|
||||||
|
#define DYN_INFO_LOG(...) ::dyn::core::logln(__VA_ARGS__)
|
||||||
|
|
||||||
#ifdef _WIN_VER
|
#ifdef _WIN_VER
|
||||||
#define DYN_BREAKPOINT __debugbreak()
|
#define DYN_BREAKPOINT __debugbreak()
|
||||||
|
|
@ -29,8 +33,6 @@
|
||||||
#ifdef DYN_DEBUG
|
#ifdef DYN_DEBUG
|
||||||
#define DYN_ENABLE_ASSERTIONS
|
#define DYN_ENABLE_ASSERTIONS
|
||||||
|
|
||||||
#define DYN_DEBUG_LOG(...) ::dyn::core::debugln(__VA_ARGS__)
|
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
#define DYN_DEBUG_LOG(...)
|
#define DYN_DEBUG_LOG(...)
|
||||||
|
|
@ -39,7 +41,7 @@
|
||||||
|
|
||||||
#ifdef DYN_ENABLE_ASSERTIONS
|
#ifdef DYN_ENABLE_ASSERTIONS
|
||||||
|
|
||||||
#define DYN_ASSERT(cond, ...) if (!cond) { DYN_FATAL_LOG("Assert failed", ##__VA_ARGS__); DYN_BREAKPOINT; }
|
#define DYN_ASSERT(cond, ...) if (!(cond)) { DYN_FATAL_LOG("Assert failed", __VA_ARGS__); DYN_BREAKPOINT; }
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
|
|
@ -23,6 +23,16 @@ namespace dyn::core {
|
||||||
print("fatal", msg, std::forward<Args>(args)...);
|
print("fatal", msg, std::forward<Args>(args)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename... Args>
|
||||||
|
void warn(const std::string& msg, Args&&... args) {
|
||||||
|
print("warn", msg, std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename... Args>
|
||||||
|
void error(const std::string& msg, Args&&... args) {
|
||||||
|
print("error", msg, std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
template <typename... Args>
|
template <typename... Args>
|
||||||
void debug(const std::string& msg, Args&&... args) {
|
void debug(const std::string& msg, Args&&... args) {
|
||||||
print("debug", msg, std::forward<Args>(args)...);
|
print("debug", msg, std::forward<Args>(args)...);
|
||||||
|
|
@ -35,7 +45,7 @@ namespace dyn::core {
|
||||||
void print(const std::string& type, const std::string& msg, Args&&... args) {
|
void print(const std::string& type, const std::string& msg, Args&&... args) {
|
||||||
std::array<char, sizeof...(Args) * 3 + 4> buffer{};
|
std::array<char, sizeof...(Args) * 3 + 4> buffer{};
|
||||||
constexpr char c[4] = "{} ";
|
constexpr char c[4] = "{} ";
|
||||||
for (auto i = 0; i != buffer.size() - 1; ++i) {
|
for (size_t i = 0; i != buffer.size() - 1; ++i) {
|
||||||
buffer[i] = c[i % 3];
|
buffer[i] = c[i % 3];
|
||||||
}
|
}
|
||||||
buffer.back() = '\0';
|
buffer.back() = '\0';
|
||||||
|
|
@ -62,4 +72,14 @@ namespace dyn::core {
|
||||||
void debugln(const std::string& msg, Args&&... args) {
|
void debugln(const std::string& msg, Args&&... args) {
|
||||||
logger::def().debug(msg, std::forward<Args>(args)...);
|
logger::def().debug(msg, std::forward<Args>(args)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename... Args>
|
||||||
|
void warnln(const std::string& msg, Args&&... args) {
|
||||||
|
logger::def().warn(msg, std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename... Args>
|
||||||
|
void errorln(const std::string& msg, Args&&... args) {
|
||||||
|
logger::def().error(msg, std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -8,7 +8,11 @@
|
||||||
#define GLFW_INCLUDE_VULKAN
|
#define GLFW_INCLUDE_VULKAN
|
||||||
#include <glfw/glfw3.h>
|
#include <glfw/glfw3.h>
|
||||||
|
|
||||||
|
#include "base.h"
|
||||||
|
|
||||||
namespace dyn::core {
|
namespace dyn::core {
|
||||||
|
class vulkan_context;
|
||||||
|
|
||||||
struct window_spec {
|
struct window_spec {
|
||||||
uint32_t width;
|
uint32_t width;
|
||||||
uint32_t height;
|
uint32_t height;
|
||||||
|
|
@ -18,11 +22,25 @@ namespace dyn::core {
|
||||||
|
|
||||||
class window {
|
class window {
|
||||||
public:
|
public:
|
||||||
window(const window_spec& spec);
|
explicit window(window_spec spec);
|
||||||
~window();
|
~window();
|
||||||
|
|
||||||
static std::vector<const char*> get_required_extensions();
|
[[nodiscard]] static std::vector<const char*> get_required_extensions();
|
||||||
|
|
||||||
|
static ref<window> create(const window_spec& spec);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
static void set_window_hints();
|
||||||
|
|
||||||
|
[[nodiscard]] GLFWwindow* get_window_handle() { return _window; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
window_spec spec;
|
VkSurfaceKHR _surface = VK_NULL_HANDLE;
|
||||||
|
window_spec _spec;
|
||||||
|
|
||||||
|
GLFWwindow* _window;
|
||||||
|
|
||||||
|
friend class vulkan_context;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,8 +5,41 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <vulkan/vulkan.h>
|
#include <vulkan/vulkan.h>
|
||||||
#include <dyn/core/assertion.h>
|
#include <dyn/core/debug.h>
|
||||||
|
#include <vulkan/vk_enum_string_helper.h>
|
||||||
|
|
||||||
|
namespace dyn::utils {
|
||||||
|
VkResult vkCreateDebugUtilsMessengerEXT(VkInstance instance,
|
||||||
|
const VkDebugUtilsMessengerCreateInfoEXT* pCreateInfo,
|
||||||
|
const VkAllocationCallbacks* pAllocator,
|
||||||
|
VkDebugUtilsMessengerEXT* pMessenger);
|
||||||
|
|
||||||
|
void vkDestroyDebugUtilsMessengerEXT(VkInstance instance,
|
||||||
|
VkDebugUtilsMessengerEXT messenger,
|
||||||
|
const VkAllocationCallbacks* pAllocator);
|
||||||
|
|
||||||
|
void populate_debug_messenger_create_info(VkDebugUtilsMessengerCreateInfoEXT* pCreateInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace dyn::utils {
|
||||||
|
extern const std::vector<const char*> vk_validation_layers;
|
||||||
|
|
||||||
|
VkBool32 vk_debug_message_callback(
|
||||||
|
VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
|
||||||
|
VkDebugUtilsMessageTypeFlagsEXT messageTypes,
|
||||||
|
const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData,
|
||||||
|
void* pUserData);
|
||||||
|
|
||||||
|
[[nodiscard]] bool check_validation_support();
|
||||||
|
|
||||||
|
#ifdef DYN_DEBUG
|
||||||
|
constexpr bool vk_enable_validation_layers = true;
|
||||||
|
#else
|
||||||
|
constexpr bool vk_enable_validation_layers = false;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#define dyn_vk_verify(f) { \
|
#define dyn_vk_verify(f) { \
|
||||||
VkResult res = f; \
|
VkResult res = f; \
|
||||||
DYN_ASSERT(res == VK_SUCCESS, __FILE__, "at line", __LINE__); }
|
DYN_ASSERT(res == VK_SUCCESS, "Vulkan error occured", string_VkResult(res), "at line", __LINE__, "in file", __FILE__); }
|
||||||
|
|
@ -5,13 +5,16 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <vulkan/vulkan.h>
|
#include <vulkan/vulkan.h>
|
||||||
|
#include <dyn/core/base.h>
|
||||||
#include <dyn/renderer/render_context.h>
|
#include <dyn/renderer/render_context.h>
|
||||||
|
|
||||||
|
#include "vulkan_devices.h"
|
||||||
|
|
||||||
namespace dyn::core {
|
namespace dyn::core {
|
||||||
|
|
||||||
class vulkan_context : public render_context {
|
class vulkan_context : public render_context {
|
||||||
public:
|
public:
|
||||||
vulkan_context();
|
explicit vulkan_context(const ref<window>& window);
|
||||||
~vulkan_context() override;
|
~vulkan_context() override;
|
||||||
|
|
||||||
void init() override;
|
void init() override;
|
||||||
|
|
@ -22,12 +25,22 @@ namespace dyn::core {
|
||||||
|
|
||||||
void cmd_end() override;
|
void cmd_end() override;
|
||||||
|
|
||||||
VkInstance get_instance();
|
[[nodiscard]] ref<window> get_window() override { return _window; }
|
||||||
|
|
||||||
static bool check_api_version_support(uint32_t api_version);
|
[[nodiscard]] VkInstance get_instance() const { return _instance; }
|
||||||
|
|
||||||
|
VkSurfaceKHR& get_surface();
|
||||||
|
|
||||||
|
[[nodiscard]] static bool check_api_version_support(uint32_t api_version);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
VkInstance _instance = nullptr;
|
VkInstance _instance = nullptr;
|
||||||
|
ref<vulkan_physical_device> _physical_device;
|
||||||
|
VkDebugUtilsMessengerEXT _debug_messenger = nullptr;
|
||||||
|
|
||||||
|
VkSurfaceKHR _surface = nullptr;
|
||||||
|
|
||||||
|
ref<window> _window;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
41
inc/dyn/platform/vulkan/vulkan_devices.h
Normal file
41
inc/dyn/platform/vulkan/vulkan_devices.h
Normal file
|
|
@ -0,0 +1,41 @@
|
||||||
|
//
|
||||||
|
// Created by Neo on 2/24/25.
|
||||||
|
//
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include <vulkan/vulkan.h>
|
||||||
|
#include <dyn/core/debug.h>
|
||||||
|
#include <dyn/core/base.h>
|
||||||
|
|
||||||
|
namespace dyn::core {
|
||||||
|
class vulkan_context;
|
||||||
|
|
||||||
|
class vulkan_physical_device {
|
||||||
|
public:
|
||||||
|
explicit vulkan_physical_device(const ref<vulkan_context>& ctx);
|
||||||
|
~vulkan_physical_device();
|
||||||
|
|
||||||
|
struct queue_families {
|
||||||
|
std::optional<uint32_t> graphics_family;
|
||||||
|
std::optional<uint32_t> present_family;
|
||||||
|
|
||||||
|
[[nodiscard]] bool is_complete() const;
|
||||||
|
|
||||||
|
static queue_families find(const VkPhysicalDevice& physical_device, const VkSurfaceKHR& surface);
|
||||||
|
};
|
||||||
|
|
||||||
|
[[nodiscard]] VkPhysicalDevice get_physical_device() const { return _physical_device; }
|
||||||
|
|
||||||
|
[[nodiscard]] queue_families get_queue_families() const { return _queue_families; }
|
||||||
|
|
||||||
|
static VkPhysicalDevice determine_suitable_device(const std::vector<VkPhysicalDevice>& available_devices, const VkSurfaceKHR& surface);
|
||||||
|
static uint32_t score_device(const VkPhysicalDevice& device);
|
||||||
|
|
||||||
|
static ref<vulkan_physical_device> create(const ref<vulkan_context>& ctx);
|
||||||
|
|
||||||
|
private:
|
||||||
|
VkPhysicalDevice _physical_device = nullptr;
|
||||||
|
queue_families _queue_families;
|
||||||
|
ref<vulkan_context> _ctx;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
@ -10,10 +10,12 @@
|
||||||
#include <dyn/core/base.h>
|
#include <dyn/core/base.h>
|
||||||
#include <dyn/renderer/mesh.h>
|
#include <dyn/renderer/mesh.h>
|
||||||
|
|
||||||
|
#include "dyn/core/window.h"
|
||||||
|
|
||||||
namespace dyn::core {
|
namespace dyn::core {
|
||||||
class render_context;
|
class render_context;
|
||||||
|
|
||||||
using render_command = std::function<void(ref<render_context>)>;
|
using render_command = std::function<void()>;
|
||||||
using render_command_queue = command_queue<render_command>;
|
using render_command_queue = command_queue<render_command>;
|
||||||
|
|
||||||
class render_context {
|
class render_context {
|
||||||
|
|
@ -35,10 +37,12 @@ namespace dyn::core {
|
||||||
// end the frame, render to the screen
|
// end the frame, render to the screen
|
||||||
virtual void cmd_end() = 0;
|
virtual void cmd_end() = 0;
|
||||||
|
|
||||||
|
virtual ref<window> get_window() = 0;
|
||||||
|
|
||||||
static void set_api(RenderPlatform platform);
|
static void set_api(RenderPlatform platform);
|
||||||
static RenderPlatform get_api();
|
static RenderPlatform get_api();
|
||||||
|
|
||||||
static ref<render_context> create();
|
static ref<render_context> create(const ref<window> &window);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
render_command_queue _render_command_queue;
|
render_command_queue _render_command_queue;
|
||||||
|
|
|
||||||
|
|
@ -3,16 +3,29 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
#include <utility>
|
||||||
#include <dyn/core/window.h>
|
#include <dyn/core/window.h>
|
||||||
|
|
||||||
#include "dyn/core/assertion.h"
|
#include "dyn/core/debug.h"
|
||||||
|
#include "dyn/renderer/render_context.h"
|
||||||
|
|
||||||
namespace dyn::core {
|
namespace dyn::core {
|
||||||
window::window(const window_spec &spec) {
|
window::window(window_spec spec): _spec(std::move(spec)) {
|
||||||
DYN_ASSERT(glfwInit(), "GLFW failed to initialize");
|
DYN_ASSERT(glfwInit(), "GLFW failed to initialize");
|
||||||
|
|
||||||
|
set_window_hints();
|
||||||
|
|
||||||
|
_window = glfwCreateWindow(
|
||||||
|
static_cast<int>(spec.width),
|
||||||
|
static_cast<int>(spec.height),
|
||||||
|
spec.title.c_str(),
|
||||||
|
nullptr, nullptr);
|
||||||
|
DYN_ASSERT(_window != nullptr, "Failed to create GLFW window");
|
||||||
}
|
}
|
||||||
|
|
||||||
window::~window() {
|
window::~window() {
|
||||||
|
glfwDestroyWindow(_window);
|
||||||
|
glfwTerminate();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<const char *> window::get_required_extensions() {
|
std::vector<const char *> window::get_required_extensions() {
|
||||||
|
|
@ -23,8 +36,21 @@ namespace dyn::core {
|
||||||
std::vector<const char *> result;
|
std::vector<const char *> result;
|
||||||
result.reserve(extensions_count);
|
result.reserve(extensions_count);
|
||||||
result.insert(result.begin(), extensions, extensions + extensions_count);
|
result.insert(result.begin(), extensions, extensions + extensions_count);
|
||||||
|
// support MoltenVK (https://stackoverflow.com/questions/58732459/vk-error-incompatible-driver-with-mac-os-and-vulkan-moltenvk)
|
||||||
|
result.push_back("VK_KHR_portability_enumeration");
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void window::set_window_hints() {
|
||||||
|
auto render_api = render_context::get_api();
|
||||||
|
|
||||||
|
if (render_api == RenderPlatform::Vulkan) {
|
||||||
|
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
|
||||||
|
}
|
||||||
|
glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
ref<window> window::create(const window_spec &spec) {
|
||||||
|
return create_ref<window>(spec);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
17
src/main.cpp
17
src/main.cpp
|
|
@ -4,29 +4,30 @@
|
||||||
#include <dyn/core/logging.h>
|
#include <dyn/core/logging.h>
|
||||||
#include <dyn/core/command_queue.h>
|
#include <dyn/core/command_queue.h>
|
||||||
|
|
||||||
#include "../inc/dyn/core/assertion.h"
|
#include "../inc/dyn/core/debug.h"
|
||||||
#include "dyn/core/window.h"
|
#include "dyn/core/window.h"
|
||||||
|
#include "dyn/platform/vulkan/vulkan.h"
|
||||||
|
#include "dyn/platform/vulkan/vulkan_context.h"
|
||||||
#include "dyn/renderer/render_context.h"
|
#include "dyn/renderer/render_context.h"
|
||||||
|
|
||||||
using namespace dyn;
|
using namespace dyn;
|
||||||
using namespace dyn::core;
|
using namespace dyn::core;
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
// render_context::set_api(RenderPlatform::Vulkan);
|
render_context::set_api(RenderPlatform::Vulkan);
|
||||||
// ref<render_context> ctx = render_context::create();
|
// ref<render_context> ctx = render_context::create();
|
||||||
//
|
//
|
||||||
// ctx->init();
|
// ctx->init();
|
||||||
|
|
||||||
window win = window({
|
ref<window> win = window::create({
|
||||||
.width = 1280,
|
.width = 1280,
|
||||||
.height = 720,
|
.height = 720,
|
||||||
.title = "Dyn Engine",
|
.title = "Dyn Engine",
|
||||||
.fullscreen = false
|
.fullscreen = false
|
||||||
});
|
});
|
||||||
|
|
||||||
auto extensions = window::get_required_extensions();
|
ref<render_context> ctx = render_context::create(win);
|
||||||
DYN_DEBUG_LOG("Extensions Found:", extensions.size());
|
ctx->init();
|
||||||
for (auto extension : extensions) {
|
auto vkctx = ref_as<vulkan_context>(ctx);
|
||||||
DYN_DEBUG_LOG("Extension Found:", extension);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
80
src/platform/vulkan/vulkan.cpp
Normal file
80
src/platform/vulkan/vulkan.cpp
Normal file
|
|
@ -0,0 +1,80 @@
|
||||||
|
//
|
||||||
|
// Created by Neo on 2/24/25.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include <dyn/platform/vulkan/vulkan.h>
|
||||||
|
|
||||||
|
namespace dyn::utils {
|
||||||
|
const std::vector<const char*> vk_validation_layers = {
|
||||||
|
"VK_LAYER_KHRONOS_validation"
|
||||||
|
};
|
||||||
|
|
||||||
|
VkResult vkCreateDebugUtilsMessengerEXT(VkInstance instance, const VkDebugUtilsMessengerCreateInfoEXT *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkDebugUtilsMessengerEXT *pMessenger) {
|
||||||
|
auto func = (PFN_vkCreateDebugUtilsMessengerEXT) vkGetInstanceProcAddr(instance, "vkCreateDebugUtilsMessengerEXT");
|
||||||
|
if (func != nullptr) {
|
||||||
|
return func(instance, pCreateInfo, pAllocator, pMessenger);
|
||||||
|
}
|
||||||
|
return VK_ERROR_EXTENSION_NOT_PRESENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
void vkDestroyDebugUtilsMessengerEXT(VkInstance instance, VkDebugUtilsMessengerEXT messenger, const VkAllocationCallbacks *pAllocator) {
|
||||||
|
auto func = (PFN_vkDestroyDebugUtilsMessengerEXT) vkGetInstanceProcAddr(instance, "vkDestroyDebugUtilsMessengerEXT");
|
||||||
|
if (func != nullptr) {
|
||||||
|
func(instance, messenger, pAllocator);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void populate_debug_messenger_create_info(VkDebugUtilsMessengerCreateInfoEXT *create_info) {
|
||||||
|
create_info->sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT;
|
||||||
|
create_info->messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT;
|
||||||
|
create_info->messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT;
|
||||||
|
create_info->pUserData = nullptr;
|
||||||
|
create_info->pfnUserCallback = vk_debug_message_callback;
|
||||||
|
}
|
||||||
|
|
||||||
|
VkBool32 vk_debug_message_callback(VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
|
||||||
|
VkDebugUtilsMessageTypeFlagsEXT messageType, const VkDebugUtilsMessengerCallbackDataEXT *pCallbackData,
|
||||||
|
void *pUserData) {
|
||||||
|
|
||||||
|
switch (messageSeverity) {
|
||||||
|
case VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT:
|
||||||
|
DYN_DEBUG_LOG("[VkValidation Layer Verbose]", pCallbackData->pMessage);
|
||||||
|
break;
|
||||||
|
case VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT:
|
||||||
|
DYN_WARNING_LOG("[VkValidation Layer Warn]", pCallbackData->pMessage);
|
||||||
|
break;
|
||||||
|
case VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT:
|
||||||
|
DYN_ERROR_LOG("[VkValidation Layer Error]", pCallbackData->pMessage);
|
||||||
|
break;
|
||||||
|
case VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT:
|
||||||
|
DYN_INFO_LOG("[VkValidation Layer Info]", pCallbackData->pMessage);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
DYN_WARNING_LOG("[VkValidation Layer Uncaptured]", pCallbackData->pMessage);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return VK_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool check_validation_support() {
|
||||||
|
uint32_t layer_count = 0;
|
||||||
|
vkEnumerateInstanceLayerProperties(&layer_count, nullptr);
|
||||||
|
std::vector<VkLayerProperties> available_layers(layer_count);
|
||||||
|
vkEnumerateInstanceLayerProperties(&layer_count, available_layers.data());
|
||||||
|
|
||||||
|
for (const auto &layer : vk_validation_layers) {
|
||||||
|
bool layer_found = false;
|
||||||
|
for (const auto& property : available_layers) {
|
||||||
|
if (strcmp(layer, property.layerName) == 0) {
|
||||||
|
layer_found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!layer_found) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -9,9 +9,15 @@
|
||||||
|
|
||||||
namespace dyn::core {
|
namespace dyn::core {
|
||||||
|
|
||||||
vulkan_context::vulkan_context() {}
|
vulkan_context::vulkan_context(const ref<window>& window) : _window(window) {}
|
||||||
|
|
||||||
vulkan_context::~vulkan_context() {
|
vulkan_context::~vulkan_context() {
|
||||||
|
|
||||||
|
if (utils::vk_enable_validation_layers) {
|
||||||
|
utils::vkDestroyDebugUtilsMessengerEXT(_instance, _debug_messenger, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
vkDestroySurfaceKHR(_instance, _surface, nullptr);
|
||||||
vkDestroyInstance(_instance, nullptr);
|
vkDestroyInstance(_instance, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -19,6 +25,9 @@ namespace dyn::core {
|
||||||
if (!check_api_version_support(VK_API_VERSION_1_2)) {
|
if (!check_api_version_support(VK_API_VERSION_1_2)) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto self = ref<vulkan_context>(this);
|
||||||
|
|
||||||
// create vulkan instance
|
// create vulkan instance
|
||||||
{
|
{
|
||||||
DYN_DEBUG_LOG("Creating Vulkan context");
|
DYN_DEBUG_LOG("Creating Vulkan context");
|
||||||
|
|
@ -33,20 +42,58 @@ namespace dyn::core {
|
||||||
VkInstanceCreateInfo create_info{};
|
VkInstanceCreateInfo create_info{};
|
||||||
create_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
|
create_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
|
||||||
create_info.pApplicationInfo = &app_info;
|
create_info.pApplicationInfo = &app_info;
|
||||||
|
// support MoltenVK (https://stackoverflow.com/questions/58732459/vk-error-incompatible-driver-with-mac-os-and-vulkan-moltenvk)
|
||||||
|
create_info.flags = VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR;
|
||||||
|
|
||||||
// extensions
|
// extensions
|
||||||
{
|
|
||||||
auto extensions = window::get_required_extensions();
|
auto extensions = window::get_required_extensions();
|
||||||
|
for (const auto& ext : extensions) {
|
||||||
|
DYN_DEBUG_LOG(ext);
|
||||||
|
}
|
||||||
|
DYN_DEBUG_LOG("Extensions Found: ", extensions.size());
|
||||||
|
if (utils::vk_enable_validation_layers) {
|
||||||
|
extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
|
||||||
|
}
|
||||||
create_info.enabledExtensionCount = static_cast<uint32_t>(extensions.size());
|
create_info.enabledExtensionCount = static_cast<uint32_t>(extensions.size());
|
||||||
create_info.ppEnabledExtensionNames = extensions.data();
|
create_info.ppEnabledExtensionNames = extensions.data();
|
||||||
}
|
|
||||||
|
|
||||||
create_info.enabledLayerCount = 0;
|
create_info.enabledLayerCount = 0;
|
||||||
create_info.ppEnabledLayerNames = nullptr;
|
create_info.ppEnabledLayerNames = nullptr;
|
||||||
|
|
||||||
|
if (utils::vk_enable_validation_layers) {
|
||||||
|
create_info.enabledLayerCount = static_cast<uint32_t>(utils::vk_validation_layers.size());
|
||||||
|
create_info.ppEnabledLayerNames = utils::vk_validation_layers.data();
|
||||||
|
|
||||||
|
VkDebugUtilsMessengerCreateInfoEXT debug_utils_create_info{};
|
||||||
|
utils::populate_debug_messenger_create_info(&debug_utils_create_info);
|
||||||
|
|
||||||
|
create_info.pNext = &debug_utils_create_info;
|
||||||
|
}
|
||||||
|
|
||||||
dyn_vk_verify(vkCreateInstance(&create_info, nullptr, &_instance));
|
dyn_vk_verify(vkCreateInstance(&create_info, nullptr, &_instance));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// debug messenger
|
||||||
|
{
|
||||||
|
if (utils::vk_enable_validation_layers && utils::check_validation_support()) {
|
||||||
|
DYN_DEBUG_LOG("Creating debug messenger");
|
||||||
|
VkDebugUtilsMessengerCreateInfoEXT create_info{};
|
||||||
|
utils::populate_debug_messenger_create_info(&create_info);
|
||||||
|
dyn_vk_verify(utils::vkCreateDebugUtilsMessengerEXT(_instance, &create_info, nullptr, &_debug_messenger));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// surface
|
||||||
|
{
|
||||||
|
glfwCreateWindowSurface(_instance, _window->get_window_handle(), nullptr, &_surface);
|
||||||
|
}
|
||||||
|
|
||||||
|
// physical device
|
||||||
|
{
|
||||||
|
|
||||||
|
_physical_device = vulkan_physical_device::create(self);
|
||||||
|
DYN_DEBUG_LOG("Physical Device Created");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void vulkan_context::cmd_begin() {
|
void vulkan_context::cmd_begin() {
|
||||||
|
|
@ -58,8 +105,8 @@ namespace dyn::core {
|
||||||
void vulkan_context::cmd_end() {
|
void vulkan_context::cmd_end() {
|
||||||
}
|
}
|
||||||
|
|
||||||
VkInstance vulkan_context::get_instance() {
|
VkSurfaceKHR& vulkan_context::get_surface() {
|
||||||
return _instance;
|
return _surface;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool vulkan_context::check_api_version_support(uint32_t requested_version) {
|
bool vulkan_context::check_api_version_support(uint32_t requested_version) {
|
||||||
|
|
|
||||||
116
src/platform/vulkan/vulkan_device.cpp
Normal file
116
src/platform/vulkan/vulkan_device.cpp
Normal file
|
|
@ -0,0 +1,116 @@
|
||||||
|
//
|
||||||
|
// Created by Neo on 2/24/25.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
#include "dyn/platform/vulkan/vulkan_context.h"
|
||||||
|
#include "dyn/platform/vulkan/vulkan_devices.h"
|
||||||
|
|
||||||
|
namespace dyn::core {
|
||||||
|
vulkan_physical_device::vulkan_physical_device(const ref<vulkan_context>& ctx) :
|
||||||
|
_ctx(ctx) {
|
||||||
|
auto instance = ref_as<vulkan_context>(_ctx)->get_instance();
|
||||||
|
|
||||||
|
uint32_t device_count = 0;
|
||||||
|
vkEnumeratePhysicalDevices(instance, &device_count, nullptr);
|
||||||
|
DYN_ASSERT(device_count > 0, "No devices found.");
|
||||||
|
|
||||||
|
std::vector<VkPhysicalDevice> devices(device_count);
|
||||||
|
vkEnumeratePhysicalDevices(instance, &device_count, devices.data());
|
||||||
|
|
||||||
|
_physical_device = determine_suitable_device(devices, ctx->get_surface());
|
||||||
|
_queue_families = queue_families::find(_physical_device, ctx->get_surface());
|
||||||
|
}
|
||||||
|
|
||||||
|
vulkan_physical_device::~vulkan_physical_device() = default;
|
||||||
|
|
||||||
|
bool vulkan_physical_device::queue_families::is_complete() const {
|
||||||
|
return this->graphics_family.has_value() && this->present_family.has_value();
|
||||||
|
}
|
||||||
|
|
||||||
|
vulkan_physical_device::queue_families vulkan_physical_device::queue_families::find(
|
||||||
|
const VkPhysicalDevice &physical_device,
|
||||||
|
const VkSurfaceKHR &surface) {
|
||||||
|
uint32_t queue_family_count = 0;
|
||||||
|
vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &queue_family_count, nullptr);
|
||||||
|
DYN_ASSERT(queue_family_count > 0, "No queue families found.");
|
||||||
|
std::vector<VkQueueFamilyProperties> found_families(queue_family_count);
|
||||||
|
vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &queue_family_count, found_families.data());
|
||||||
|
|
||||||
|
queue_families families{};
|
||||||
|
|
||||||
|
uint32_t idx = 0;
|
||||||
|
for (const auto &queue_family : found_families) {
|
||||||
|
if (queue_family.queueFlags & VK_QUEUE_GRAPHICS_BIT) {
|
||||||
|
families.graphics_family = idx;
|
||||||
|
}
|
||||||
|
|
||||||
|
VkBool32 present_support = false;
|
||||||
|
vkGetPhysicalDeviceSurfaceSupportKHR(physical_device, idx, surface, &present_support);
|
||||||
|
|
||||||
|
if (present_support) {
|
||||||
|
families.present_family = idx;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (families.is_complete()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
idx++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return families;
|
||||||
|
}
|
||||||
|
|
||||||
|
VkPhysicalDevice vulkan_physical_device::determine_suitable_device(
|
||||||
|
const std::vector<VkPhysicalDevice> &available_devices,
|
||||||
|
const VkSurfaceKHR &surface) {
|
||||||
|
uint32_t prev_score = 0;
|
||||||
|
VkPhysicalDevice current_device = VK_NULL_HANDLE;
|
||||||
|
for (const auto& device : available_devices) {
|
||||||
|
if (queue_families::find(device, surface).is_complete()) {
|
||||||
|
auto score = score_device(device);
|
||||||
|
if (prev_score < score) {
|
||||||
|
prev_score = score;
|
||||||
|
current_device = device;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return current_device;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t vulkan_physical_device::score_device(const VkPhysicalDevice &device) {
|
||||||
|
uint32_t score = 0;
|
||||||
|
VkPhysicalDeviceProperties properties;
|
||||||
|
VkPhysicalDeviceFeatures features;
|
||||||
|
vkGetPhysicalDeviceProperties(device, &properties);
|
||||||
|
vkGetPhysicalDeviceFeatures(device, &features);
|
||||||
|
|
||||||
|
if (properties.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU) {
|
||||||
|
score += 1000;
|
||||||
|
} else if (properties.deviceType == VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU) {
|
||||||
|
score += 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
score += properties.limits.maxImageDimension2D;
|
||||||
|
|
||||||
|
if (properties.apiVersion >= VK_API_VERSION_1_2) {
|
||||||
|
score += 80;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (features.geometryShader == VK_TRUE) {
|
||||||
|
score = 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
DYN_DEBUG_LOG("Device Name:", std::string_view{properties.deviceName});
|
||||||
|
DYN_DEBUG_LOG("Device Score:", score);
|
||||||
|
|
||||||
|
return score;
|
||||||
|
}
|
||||||
|
|
||||||
|
ref<vulkan_physical_device> vulkan_physical_device::create(const ref<vulkan_context>& ctx) {
|
||||||
|
return create_ref<vulkan_physical_device>(ctx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -20,9 +20,9 @@ namespace dyn::core {
|
||||||
return s_api;
|
return s_api;
|
||||||
}
|
}
|
||||||
|
|
||||||
ref<render_context> render_context::create() {
|
ref<render_context> render_context::create(const ref<window>& window) {
|
||||||
DYN_PLATFORM_CREATE_BEGIN(get_api())
|
DYN_PLATFORM_CREATE_BEGIN(get_api())
|
||||||
DYN_PLATFORM_CREATE_VK(vulkan_context);
|
DYN_PLATFORM_CREATE_VK(vulkan_context, window);
|
||||||
DYN_PLATFORM_CREATE_END(render_context)
|
DYN_PLATFORM_CREATE_END(render_context)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user