vertex buffers done
This commit is contained in:
parent
1c01c2a4f1
commit
1387ac4f27
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -1,2 +1,3 @@
|
||||||
cmake-build-debug/
|
cmake-build-debug/
|
||||||
|
cmake-build-release/
|
||||||
.idea/
|
.idea/
|
||||||
|
|
@ -15,6 +15,8 @@ find_package(spirv_cross_msl CONFIG REQUIRED)
|
||||||
find_package(spirv_cross_reflect CONFIG REQUIRED)
|
find_package(spirv_cross_reflect CONFIG REQUIRED)
|
||||||
find_package(spirv_cross_util CONFIG REQUIRED)
|
find_package(spirv_cross_util CONFIG REQUIRED)
|
||||||
find_package(unofficial-shaderc CONFIG REQUIRED)
|
find_package(unofficial-shaderc CONFIG REQUIRED)
|
||||||
|
find_package(glm CONFIG REQUIRED)
|
||||||
|
find_package(VulkanMemoryAllocator CONFIG REQUIRED)
|
||||||
|
|
||||||
foreach (file ${sourceFiles})
|
foreach (file ${sourceFiles})
|
||||||
message("Source File Found ${file}")
|
message("Source File Found ${file}")
|
||||||
|
|
@ -24,8 +26,11 @@ add_executable(Dyn ${sourceFiles})
|
||||||
|
|
||||||
target_include_directories(Dyn PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/inc")
|
target_include_directories(Dyn PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/inc")
|
||||||
|
|
||||||
target_link_libraries(Dyn PRIVATE Vulkan::Vulkan)
|
target_link_libraries(Dyn PRIVATE
|
||||||
target_link_libraries(Dyn PRIVATE glfw)
|
Vulkan::Vulkan
|
||||||
target_link_libraries(Dyn PRIVATE Vulkan::SafeStruct Vulkan::LayerSettings Vulkan::UtilityHeaders Vulkan::CompilerConfiguration)
|
glfw
|
||||||
target_link_libraries(Dyn PRIVATE spirv-cross-core spirv-cross-glsl spirv-cross-hlsl spirv-cross-msl spirv-cross-reflect spirv-cross-util)
|
Vulkan::SafeStruct Vulkan::LayerSettings Vulkan::UtilityHeaders Vulkan::CompilerConfiguration
|
||||||
target_link_libraries(Dyn PRIVATE unofficial::shaderc::shaderc)
|
spirv-cross-core spirv-cross-glsl spirv-cross-hlsl spirv-cross-msl spirv-cross-reflect spirv-cross-util
|
||||||
|
unofficial::shaderc::shaderc
|
||||||
|
glm::glm
|
||||||
|
GPUOpen::VulkanMemoryAllocator)
|
||||||
|
|
@ -12,7 +12,7 @@ namespace dyn::core {
|
||||||
public:
|
public:
|
||||||
command_queue() = default;
|
command_queue() = default;
|
||||||
|
|
||||||
void submit(FuncT func) {
|
void submit(const FuncT &func) {
|
||||||
_command_list.push_back(func);
|
_command_list.push_back(func);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -12,14 +12,16 @@
|
||||||
|
|
||||||
#define DYN_WARNING_LOG(...) ::dyn::core::warnln(__VA_ARGS__)
|
#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__)
|
||||||
|
|
||||||
|
#ifdef DYN_DEBUG
|
||||||
#define DYN_DEBUG_LOG(...) ::dyn::core::debugln(__VA_ARGS__)
|
#define DYN_DEBUG_LOG(...) ::dyn::core::debugln(__VA_ARGS__)
|
||||||
|
#else
|
||||||
|
#define DYN_DEBUG_LOG(...)
|
||||||
|
#endif
|
||||||
|
|
||||||
#define DYN_ERROR_LOG(...) ::dyn::core::errorln(__VA_ARGS__)
|
#define DYN_ERROR_LOG(...) ::dyn::core::errorln(__VA_ARGS__)
|
||||||
#define DYN_INFO_LOG(...) ::dyn::core::logln(__VA_ARGS__)
|
#define DYN_INFO_LOG(...) ::dyn::core::logln(__VA_ARGS__)
|
||||||
|
|
||||||
#ifdef WIN32
|
|
||||||
#define _WIN_VER
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef DYN_ENABLE_BREAKPOINT
|
#ifdef DYN_ENABLE_BREAKPOINT
|
||||||
|
|
||||||
#ifdef _WIN_VER
|
#ifdef _WIN_VER
|
||||||
|
|
@ -44,11 +46,6 @@
|
||||||
|
|
||||||
#ifdef DYN_DEBUG
|
#ifdef DYN_DEBUG
|
||||||
#define DYN_ENABLE_ASSERTIONS
|
#define DYN_ENABLE_ASSERTIONS
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
#define DYN_DEBUG_LOG(...)
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef DYN_ENABLE_ASSERTIONS
|
#ifdef DYN_ENABLE_ASSERTIONS
|
||||||
|
|
@ -57,6 +54,6 @@
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
#define DYN_ASSERT(...)
|
#define DYN_ASSERT(cond, ...) if (!(cond)) { DYN_ERROR_LOG("Assert failed", __VA_ARGS__); }
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
41
inc/dyn/core/event.h
Normal file
41
inc/dyn/core/event.h
Normal file
|
|
@ -0,0 +1,41 @@
|
||||||
|
//
|
||||||
|
// Created by nepge on 6/2/2025.
|
||||||
|
//
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
|
namespace dyn::core {
|
||||||
|
enum class event_type {
|
||||||
|
WindowEventResize
|
||||||
|
};
|
||||||
|
|
||||||
|
#define DYN_EVENT_TYPE(type) static event_type get_static_event_type() { return event_type::type; } \
|
||||||
|
event_type get_event_type() const override { return get_static_event_type(); }
|
||||||
|
|
||||||
|
class event {
|
||||||
|
public:
|
||||||
|
virtual ~event() = default;
|
||||||
|
[[nodiscard]] virtual event_type get_event_type() const = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class event_dispatcher {
|
||||||
|
public:
|
||||||
|
explicit event_dispatcher(event& event);
|
||||||
|
~event_dispatcher() = default;
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
using event_fn = std::function<void(T&)>;
|
||||||
|
|
||||||
|
template<typename Event, typename = std::is_base_of<event, Event>>
|
||||||
|
void dispatch(event_fn<Event> func) {
|
||||||
|
if (_event.get_event_type() == Event::get_static_event_type()) {
|
||||||
|
func(*static_cast<Event*>(&_event));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
event& _event;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
@ -12,12 +12,12 @@
|
||||||
namespace dyn::core {
|
namespace dyn::core {
|
||||||
class file {
|
class file {
|
||||||
public:
|
public:
|
||||||
file(const std::string& path);
|
explicit file(const std::string& path);
|
||||||
file(const std::filesystem::path& path);
|
explicit file(const std::filesystem::path& path);
|
||||||
~file() = default;
|
~file() = default;
|
||||||
|
|
||||||
[[nodiscard]] std::string text() const { return _contents; }
|
[[nodiscard]] std::string text() const { return _contents; }
|
||||||
[[nodiscard]] std::vector<uint8_t> bytes() const { return std::vector<uint8_t>(_contents.begin(), _contents.end()); }
|
[[nodiscard]] std::vector<uint8_t> bytes() const { return {_contents.begin(), _contents.end()}; }
|
||||||
[[nodiscard]] size_t size() const { return _contents.size(); }
|
[[nodiscard]] size_t size() const { return _contents.size(); }
|
||||||
[[nodiscard]] bool empty() const { return _contents.empty(); }
|
[[nodiscard]] bool empty() const { return _contents.empty(); }
|
||||||
[[nodiscard]] std::string path() const { return _file_path; }
|
[[nodiscard]] std::string path() const { return _file_path; }
|
||||||
|
|
|
||||||
|
|
@ -11,8 +11,8 @@
|
||||||
namespace dyn::core {
|
namespace dyn::core {
|
||||||
class logger {
|
class logger {
|
||||||
public:
|
public:
|
||||||
explicit logger(const std::string& name) : m_name(name) {}
|
explicit logger(std::string name) : m_name(std::move(name)) {}
|
||||||
virtual ~logger() = default;
|
~logger() = default;
|
||||||
|
|
||||||
template <typename... Args>
|
template <typename... Args>
|
||||||
void log(const std::string& msg, Args&&... args) {
|
void log(const std::string& msg, Args&&... args) {
|
||||||
|
|
|
||||||
|
|
@ -5,10 +5,15 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <functional>
|
||||||
#define GLFW_INCLUDE_VULKAN
|
#define GLFW_INCLUDE_VULKAN
|
||||||
#include <glfw/glfw3.h>
|
#include <glfw/glfw3.h>
|
||||||
|
|
||||||
#include "base.h"
|
#include "base.h"
|
||||||
|
#include "event.h"
|
||||||
|
|
||||||
|
#define glfw_verify(f) f; { const char* desc; uint32_t code = glfwGetError(&desc); \
|
||||||
|
if (desc != nullptr) { DYN_FATAL_LOG("GLFW error occured", desc, "at line", __LINE__, "in file", __FILE__, "at function call", #f); }}
|
||||||
|
|
||||||
namespace dyn::core {
|
namespace dyn::core {
|
||||||
class vulkan_context;
|
class vulkan_context;
|
||||||
|
|
@ -20,6 +25,18 @@ namespace dyn::core {
|
||||||
bool fullscreen;
|
bool fullscreen;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class window_resize_event : public event {
|
||||||
|
public:
|
||||||
|
window_resize_event(uint32_t width, uint32_t height);
|
||||||
|
|
||||||
|
uint32_t width;
|
||||||
|
uint32_t height;
|
||||||
|
|
||||||
|
DYN_EVENT_TYPE(WindowEventResize);
|
||||||
|
};
|
||||||
|
|
||||||
|
using event_callback_fn = std::function<void(event&)>;
|
||||||
|
|
||||||
class window {
|
class window {
|
||||||
public:
|
public:
|
||||||
explicit window(window_spec spec);
|
explicit window(window_spec spec);
|
||||||
|
|
@ -30,6 +47,10 @@ namespace dyn::core {
|
||||||
|
|
||||||
[[nodiscard]] static std::vector<const char*> get_required_extensions();
|
[[nodiscard]] static std::vector<const char*> get_required_extensions();
|
||||||
|
|
||||||
|
void set_event_callback(const event_callback_fn& callback);
|
||||||
|
|
||||||
|
void get_size(int* width, int* height) const;
|
||||||
|
|
||||||
static ref<window> create(const window_spec& spec);
|
static ref<window> create(const window_spec& spec);
|
||||||
|
|
||||||
void destroy();
|
void destroy();
|
||||||
|
|
@ -41,11 +62,16 @@ namespace dyn::core {
|
||||||
[[nodiscard]] GLFWwindow* get_window_handle() { return _window; }
|
[[nodiscard]] GLFWwindow* get_window_handle() { return _window; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
VkSurfaceKHR _surface = VK_NULL_HANDLE;
|
|
||||||
window_spec _spec;
|
window_spec _spec;
|
||||||
|
|
||||||
GLFWwindow* _window;
|
GLFWwindow* _window;
|
||||||
|
|
||||||
|
struct window_mem {
|
||||||
|
event_callback_fn event_callback;
|
||||||
|
};
|
||||||
|
|
||||||
|
window_mem _window_mem;
|
||||||
|
|
||||||
friend class vulkan_context;
|
friend class vulkan_context;
|
||||||
friend class vulkan_swap_chain;
|
friend class vulkan_swap_chain;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <vulkan/vulkan.h>
|
#include <vulkan/vulkan.h>
|
||||||
|
|
||||||
#include <dyn/core/debug.h>
|
#include <dyn/core/debug.h>
|
||||||
#include <vulkan/vk_enum_string_helper.h>
|
#include <vulkan/vk_enum_string_helper.h>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
|
||||||
|
|
@ -5,31 +5,28 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <vulkan/vulkan.h>
|
#include <vulkan/vulkan.h>
|
||||||
|
#include <vk_mem_alloc.h>
|
||||||
#include <dyn/core/base.h>
|
#include <dyn/core/base.h>
|
||||||
|
|
||||||
#include <dyn/renderer/render_context.h>
|
#include <dyn/renderer/render_context.h>
|
||||||
|
|
||||||
#include "vulkan_devices.h"
|
#include "vulkan_devices.h"
|
||||||
#include "vulkan_swap_chain.h"
|
#include "vulkan_swap_chain.h"
|
||||||
|
|
||||||
#define VK_CMD(name, context, ...) vkCmd ## name (context->get_command_buffer(), __VA_ARGS__);
|
#define VK_CMD(name, context, ...) vkCmd ## name (context->get_current_command_buffer(), __VA_ARGS__);
|
||||||
|
|
||||||
namespace dyn::core {
|
namespace dyn::core {
|
||||||
|
|
||||||
extern ref<vulkan_context> g_vulkan_context;
|
|
||||||
|
|
||||||
ref<vulkan_context> get_current_vulkan_context();
|
|
||||||
|
|
||||||
class vulkan_context : public render_context {
|
class vulkan_context : public render_context {
|
||||||
public:
|
public:
|
||||||
explicit vulkan_context(const ref<window>& window);
|
explicit vulkan_context(const ref<window>& window);
|
||||||
~vulkan_context() override;
|
~vulkan_context() override;
|
||||||
|
|
||||||
[[nodiscard]] static bool check_api_version_support(uint32_t api_version);
|
[[nodiscard]] static bool check_api_version_support(uint32_t api_version);
|
||||||
[[nodiscard]] static ref<vulkan_device> get_last_selected_logical_device() { return s_current_device; }
|
[[nodiscard]] static ref<vulkan_device> get_last_selected_logical_device() { return s_current_device; }
|
||||||
|
|
||||||
void init() override;
|
void init() override;
|
||||||
|
|
||||||
void cmd_begin() override;
|
bool cmd_begin() override;
|
||||||
|
|
||||||
void render_mesh_source(ref<mesh_source> mesh) override;
|
void render_mesh_source(ref<mesh_source> mesh) override;
|
||||||
|
|
||||||
|
|
@ -38,8 +35,9 @@ namespace dyn::core {
|
||||||
[[nodiscard]] ref<window> get_window() override { return _window; }
|
[[nodiscard]] ref<window> get_window() override { return _window; }
|
||||||
[[nodiscard]] ref<vulkan_device> get_current_device() const { return _device; }
|
[[nodiscard]] ref<vulkan_device> get_current_device() const { return _device; }
|
||||||
[[nodiscard]] ref<vulkan_swap_chain> get_swap_chain() const { return _swap_chain; }
|
[[nodiscard]] ref<vulkan_swap_chain> get_swap_chain() const { return _swap_chain; }
|
||||||
|
[[nodiscard]] VmaAllocator get_allocator() const { return _allocator; }
|
||||||
|
|
||||||
[[nodiscard]] VkCommandBuffer get_command_buffer() const { return _command_buffer; }
|
[[nodiscard]] VkCommandBuffer get_current_command_buffer() const { return _command_buffers[_swap_chain->current_frame()]; }
|
||||||
|
|
||||||
[[nodiscard]] VkInstance get_instance() const { return _instance; }
|
[[nodiscard]] VkInstance get_instance() const { return _instance; }
|
||||||
VkSurfaceKHR get_surface() const;
|
VkSurfaceKHR get_surface() const;
|
||||||
|
|
@ -49,6 +47,10 @@ namespace dyn::core {
|
||||||
|
|
||||||
void destroy() override;
|
void destroy() override;
|
||||||
|
|
||||||
|
void resize(uint32_t width, uint32_t height) override;
|
||||||
|
|
||||||
|
void set_vsync(bool vsync) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
VkInstance _instance = VK_NULL_HANDLE;
|
VkInstance _instance = VK_NULL_HANDLE;
|
||||||
ref<vulkan_physical_device> _physical_device;
|
ref<vulkan_physical_device> _physical_device;
|
||||||
|
|
@ -57,12 +59,14 @@ namespace dyn::core {
|
||||||
ref<vulkan_swap_chain> _swap_chain;
|
ref<vulkan_swap_chain> _swap_chain;
|
||||||
|
|
||||||
VkCommandPool _command_pool = VK_NULL_HANDLE;
|
VkCommandPool _command_pool = VK_NULL_HANDLE;
|
||||||
VkCommandBuffer _command_buffer = VK_NULL_HANDLE;
|
std::array<VkCommandBuffer, VULKAN_FRAMES_IN_FLIGHT> _command_buffers{};
|
||||||
|
|
||||||
VkDebugUtilsMessengerEXT _debug_messenger = VK_NULL_HANDLE;
|
VkDebugUtilsMessengerEXT _debug_messenger = VK_NULL_HANDLE;
|
||||||
|
|
||||||
VkSurfaceKHR _surface = VK_NULL_HANDLE;
|
VkSurfaceKHR _surface = VK_NULL_HANDLE;
|
||||||
|
|
||||||
|
VmaAllocator _allocator = VK_NULL_HANDLE;
|
||||||
|
|
||||||
ref<window> _window;
|
ref<window> _window;
|
||||||
|
|
||||||
inline static ref<vulkan_device> s_current_device = nullptr;
|
inline static ref<vulkan_device> s_current_device = nullptr;
|
||||||
|
|
|
||||||
|
|
@ -55,5 +55,7 @@ namespace dyn::core {
|
||||||
|
|
||||||
VkPipelineLayout _pipeline_layout = VK_NULL_HANDLE;
|
VkPipelineLayout _pipeline_layout = VK_NULL_HANDLE;
|
||||||
VkPipeline _pipeline = VK_NULL_HANDLE;
|
VkPipeline _pipeline = VK_NULL_HANDLE;
|
||||||
|
VkVertexInputBindingDescription _vertex_binding_desc;
|
||||||
|
std::array<VkVertexInputAttributeDescription, 2> _vertex_attribute_desc;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@
|
||||||
#include <dyn/platform/vulkan/vulkan_swap_chain.h>
|
#include <dyn/platform/vulkan/vulkan_swap_chain.h>
|
||||||
|
|
||||||
#include "vulkan_devices.h"
|
#include "vulkan_devices.h"
|
||||||
#include "dyn/renderer/swapchain.h"
|
#include "dyn/renderer/swap_chain.h"
|
||||||
|
|
||||||
namespace dyn::core {
|
namespace dyn::core {
|
||||||
struct swap_chain_support_details {
|
struct swap_chain_support_details {
|
||||||
|
|
@ -20,7 +20,9 @@ namespace dyn::core {
|
||||||
std::vector<VkPresentModeKHR> present_modes;
|
std::vector<VkPresentModeKHR> present_modes;
|
||||||
};
|
};
|
||||||
|
|
||||||
class vulkan_swap_chain : public swapchain {
|
inline const int VULKAN_FRAMES_IN_FLIGHT = 2;
|
||||||
|
|
||||||
|
class vulkan_swap_chain : public swap_chain {
|
||||||
public:
|
public:
|
||||||
explicit vulkan_swap_chain(const ref<vulkan_context>& ctx);
|
explicit vulkan_swap_chain(const ref<vulkan_context>& ctx);
|
||||||
~vulkan_swap_chain() override;
|
~vulkan_swap_chain() override;
|
||||||
|
|
@ -28,9 +30,11 @@ namespace dyn::core {
|
||||||
void prepare() override;
|
void prepare() override;
|
||||||
void present() override;
|
void present() override;
|
||||||
|
|
||||||
void next_frame();
|
bool next_frame();
|
||||||
|
|
||||||
void resize(uint32_t _width, uint32_t _height) override {}
|
uint32_t current_frame() const { return _current_frame; }
|
||||||
|
|
||||||
|
void resize(uint32_t width, uint32_t height) override;
|
||||||
|
|
||||||
static ref<vulkan_swap_chain> create(const ref<vulkan_context>& ctx);
|
static ref<vulkan_swap_chain> create(const ref<vulkan_context>& ctx);
|
||||||
|
|
||||||
|
|
@ -39,12 +43,15 @@ namespace dyn::core {
|
||||||
|
|
||||||
[[nodiscard]] static swap_chain_support_details get_support_details(VkSurfaceKHR surface, VkPhysicalDevice physical_device);
|
[[nodiscard]] static swap_chain_support_details get_support_details(VkSurfaceKHR surface, VkPhysicalDevice physical_device);
|
||||||
[[nodiscard]] static VkSurfaceFormatKHR get_format(const std::vector<VkSurfaceFormatKHR>& formats);
|
[[nodiscard]] static VkSurfaceFormatKHR get_format(const std::vector<VkSurfaceFormatKHR>& formats);
|
||||||
[[nodiscard]] static VkPresentModeKHR get_present_mode(const std::vector<VkPresentModeKHR>& modes);
|
[[nodiscard]] static VkPresentModeKHR get_present_mode(const std::vector<VkPresentModeKHR> &modes, bool vsync);
|
||||||
[[nodiscard]] static VkExtent2D get_extent(ref<vulkan_context> ctx, const VkSurfaceCapabilitiesKHR& capabilities);
|
[[nodiscard]] static VkExtent2D get_extent(ref<vulkan_context> ctx, const VkSurfaceCapabilitiesKHR& capabilities);
|
||||||
|
|
||||||
void rebuild() {}
|
void rebuild(bool fresh = false);
|
||||||
|
|
||||||
|
void invalidate() { _invalidated = true; }
|
||||||
|
|
||||||
void destroy();
|
void destroy();
|
||||||
|
void set_vsync(bool vsync) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
|
@ -52,6 +59,9 @@ namespace dyn::core {
|
||||||
void create_render_pass();
|
void create_render_pass();
|
||||||
void create_framebuffers();
|
void create_framebuffers();
|
||||||
|
|
||||||
|
void destroy_framebuffers();
|
||||||
|
|
||||||
|
private:
|
||||||
struct swap_image {
|
struct swap_image {
|
||||||
VkImage image;
|
VkImage image;
|
||||||
VkImageView view;
|
VkImageView view;
|
||||||
|
|
@ -63,17 +73,23 @@ namespace dyn::core {
|
||||||
VkFormat _image_format;
|
VkFormat _image_format;
|
||||||
VkExtent2D _extent;
|
VkExtent2D _extent;
|
||||||
|
|
||||||
uint32_t _current_frame = 0;
|
uint32_t _new_width = 0;
|
||||||
|
uint32_t _new_height = 0;
|
||||||
|
|
||||||
VkSemaphore _image_available = VK_NULL_HANDLE;
|
uint32_t _current_frame = 0;
|
||||||
VkSemaphore _render_finished = VK_NULL_HANDLE;
|
std::array<uint32_t, VULKAN_FRAMES_IN_FLIGHT> _image_indices = {0, 0};
|
||||||
VkFence _in_flight = VK_NULL_HANDLE;
|
|
||||||
|
std::array<VkSemaphore, VULKAN_FRAMES_IN_FLIGHT> _image_available_semaphores{};
|
||||||
|
std::array<VkSemaphore, VULKAN_FRAMES_IN_FLIGHT> _render_finished_semaphores{};
|
||||||
|
std::array<VkFence, VULKAN_FRAMES_IN_FLIGHT> _in_flight_fences{};
|
||||||
|
|
||||||
VkSwapchainKHR _swap_chain = VK_NULL_HANDLE;
|
VkSwapchainKHR _swap_chain = VK_NULL_HANDLE;
|
||||||
VkFramebuffer _frame_buffer = VK_NULL_HANDLE;
|
|
||||||
VkRenderPass _render_pass = VK_NULL_HANDLE;
|
VkRenderPass _render_pass = VK_NULL_HANDLE;
|
||||||
ref<vulkan_device> _logical_device = nullptr;
|
ref<vulkan_device> _logical_device = nullptr;
|
||||||
|
|
||||||
|
bool _invalidated = false;
|
||||||
|
bool _vsync = false;
|
||||||
|
|
||||||
friend class vulkan_context;
|
friend class vulkan_context;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
30
inc/dyn/platform/vulkan/vulkan_vertex_buffer.h
Normal file
30
inc/dyn/platform/vulkan/vulkan_vertex_buffer.h
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
//
|
||||||
|
// Created by nepge on 6/3/2025.
|
||||||
|
//
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <vk_mem_alloc.h>
|
||||||
|
|
||||||
|
#include <dyn/renderer/vertex_buffer.h>
|
||||||
|
|
||||||
|
namespace dyn::core {
|
||||||
|
|
||||||
|
class vulkan_vertex_buffer : public vertex_buffer {
|
||||||
|
public:
|
||||||
|
vulkan_vertex_buffer(const std::vector<vertex_pack>& vertices);
|
||||||
|
~vulkan_vertex_buffer() = default;
|
||||||
|
|
||||||
|
[[nodiscard]] VkBuffer get_handle() { return _buffer; }
|
||||||
|
|
||||||
|
void destroy() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
VkBuffer _buffer;
|
||||||
|
VmaAllocation _buffer_allocation;
|
||||||
|
|
||||||
|
std::vector<vertex_pack> _vertices;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -9,39 +9,39 @@
|
||||||
|
|
||||||
namespace dyn::core {
|
namespace dyn::core {
|
||||||
enum class PolygonMode {
|
enum class PolygonMode {
|
||||||
FILL,
|
Fill,
|
||||||
LINE,
|
Line,
|
||||||
POINT
|
Point
|
||||||
};
|
};
|
||||||
|
|
||||||
inline std::string cvt_string_polygon_mode(PolygonMode mode) {
|
inline std::string cvt_string_polygon_mode(PolygonMode mode) {
|
||||||
switch (mode) {
|
switch (mode) {
|
||||||
case PolygonMode::FILL:
|
case PolygonMode::Fill:
|
||||||
return "PolygonMode::FILL";
|
return "PolygonMode::Fill";
|
||||||
case PolygonMode::LINE:
|
case PolygonMode::Line:
|
||||||
return "PolygonMode::LINE";
|
return "PolygonMode::Line";
|
||||||
case PolygonMode::POINT:
|
case PolygonMode::Point:
|
||||||
return "PolygonMode::POINT";
|
return "PolygonMode::Point";
|
||||||
}
|
}
|
||||||
return "INVALID POLYGON MODE";
|
return "INVALID POLYGON MODE";
|
||||||
}
|
}
|
||||||
|
|
||||||
enum class MSAASamples {
|
enum class MSAASamples {
|
||||||
SAMPLES_1,
|
Samples1,
|
||||||
SAMPLES_2,
|
Samples2,
|
||||||
SAMPLES_4,
|
Samples4,
|
||||||
SAMPLES_8,
|
Samples8,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class CullMode {
|
enum class CullMode {
|
||||||
FRONT,
|
Front,
|
||||||
BACK,
|
Back,
|
||||||
FRONT_AND_BACK,
|
FrontAndBack,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class FrontFace {
|
enum class FrontFace {
|
||||||
CLOCKWISE,
|
Clockwise,
|
||||||
COUNTERCLOCKWISE,
|
CounterClockwise,
|
||||||
};
|
};
|
||||||
|
|
||||||
class graphics_pipeline {
|
class graphics_pipeline {
|
||||||
|
|
@ -49,7 +49,7 @@ namespace dyn::core {
|
||||||
virtual ~graphics_pipeline() = default;
|
virtual ~graphics_pipeline() = default;
|
||||||
|
|
||||||
virtual void set_polygon_mode(PolygonMode mode) = 0;
|
virtual void set_polygon_mode(PolygonMode mode) = 0;
|
||||||
virtual void set_line_width(float line_width = 1.0f) = 0;
|
virtual void set_line_width(float line_width) = 0;
|
||||||
virtual void set_msaa_samples(MSAASamples samples) = 0;
|
virtual void set_msaa_samples(MSAASamples samples) = 0;
|
||||||
virtual void set_cull_mode(CullMode mode, FrontFace face) = 0;
|
virtual void set_cull_mode(CullMode mode, FrontFace face) = 0;
|
||||||
virtual void set_depth_bias_enabled(bool enable) = 0;
|
virtual void set_depth_bias_enabled(bool enable) = 0;
|
||||||
|
|
|
||||||
|
|
@ -22,13 +22,6 @@ namespace dyn::core {
|
||||||
using cleanup_command = std::function<void()>;
|
using cleanup_command = std::function<void()>;
|
||||||
using cleanup_command_queue = command_queue<cleanup_command>;
|
using cleanup_command_queue = command_queue<cleanup_command>;
|
||||||
|
|
||||||
extern ref<render_context> g_context;
|
|
||||||
void set_current_context(const ref<render_context>& context);
|
|
||||||
|
|
||||||
inline ref<render_context> get_current_context() {
|
|
||||||
return g_context;
|
|
||||||
}
|
|
||||||
|
|
||||||
class render_context : public std::enable_shared_from_this<render_context> {
|
class render_context : public std::enable_shared_from_this<render_context> {
|
||||||
public:
|
public:
|
||||||
render_context() = default;
|
render_context() = default;
|
||||||
|
|
@ -36,11 +29,13 @@ namespace dyn::core {
|
||||||
|
|
||||||
virtual void init() = 0;
|
virtual void init() = 0;
|
||||||
|
|
||||||
|
virtual void set_vsync(bool vsync) = 0;
|
||||||
|
|
||||||
// begin a new render command
|
// begin a new render command
|
||||||
virtual void cmd_begin() = 0;
|
virtual bool cmd_begin() = 0;
|
||||||
|
|
||||||
// submit a render cmd to the queue
|
// submit a render cmd to the queue
|
||||||
void submit(render_command func);
|
void submit(const render_command &func);
|
||||||
|
|
||||||
// submit a mesh source to be renderered
|
// submit a mesh source to be renderered
|
||||||
virtual void render_mesh_source(ref<mesh_source> mesh) = 0;
|
virtual void render_mesh_source(ref<mesh_source> mesh) = 0;
|
||||||
|
|
@ -50,19 +45,33 @@ namespace dyn::core {
|
||||||
|
|
||||||
virtual void destroy() = 0;
|
virtual void destroy() = 0;
|
||||||
|
|
||||||
|
virtual void resize(uint32_t width, uint32_t height) = 0;
|
||||||
|
|
||||||
virtual ref<window> get_window() = 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();
|
||||||
|
|
||||||
void run_at_cleanup(cleanup_command cmd);
|
void run_at_cleanup(const cleanup_command &cmd);
|
||||||
|
|
||||||
static ref<render_context> create(const ref<window> &window);
|
static ref<render_context> create(const ref<window> &window);
|
||||||
|
|
||||||
|
static ref<render_context> current();
|
||||||
|
template <typename T, typename = std::is_base_of<render_context, T>>
|
||||||
|
static ref<T> current_as() {
|
||||||
|
return ref_as<T>(g_current_context);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void submit_current(render_command func);
|
||||||
|
|
||||||
|
static void set_current(const ref<render_context> &ctx);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
render_command_queue _render_command_queue;
|
render_command_queue _render_command_queue;
|
||||||
cleanup_command_queue _cleanup_command_queue;
|
cleanup_command_queue _cleanup_command_queue;
|
||||||
|
|
||||||
|
inline static ref<render_context> g_current_context;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static RenderPlatform s_api;
|
static RenderPlatform s_api;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -38,21 +38,21 @@ namespace dyn::core {
|
||||||
virtual ~shader() = default;
|
virtual ~shader() = default;
|
||||||
|
|
||||||
enum ShaderType {
|
enum ShaderType {
|
||||||
VERTEX,
|
Vertex,
|
||||||
FRAGMENT,
|
Fragment,
|
||||||
GEOMETRY,
|
Geometry,
|
||||||
COMPUTE
|
Compute
|
||||||
};
|
};
|
||||||
|
|
||||||
[[nodiscard]] static shaderc_shader_kind convert_shader_type(ShaderType type) noexcept {
|
[[nodiscard]] static shaderc_shader_kind convert_shader_type(ShaderType type) noexcept {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case VERTEX:
|
case Vertex:
|
||||||
return shaderc_vertex_shader;
|
return shaderc_vertex_shader;
|
||||||
case FRAGMENT:
|
case Fragment:
|
||||||
return shaderc_fragment_shader;
|
return shaderc_fragment_shader;
|
||||||
case GEOMETRY:
|
case Geometry:
|
||||||
return shaderc_geometry_shader;
|
return shaderc_geometry_shader;
|
||||||
case COMPUTE:
|
case Compute:
|
||||||
return shaderc_compute_shader;
|
return shaderc_compute_shader;
|
||||||
}
|
}
|
||||||
return shaderc_vertex_shader;
|
return shaderc_vertex_shader;
|
||||||
|
|
|
||||||
|
|
@ -9,15 +9,17 @@
|
||||||
#include <dyn/renderer/render_context.h>
|
#include <dyn/renderer/render_context.h>
|
||||||
|
|
||||||
namespace dyn::core {
|
namespace dyn::core {
|
||||||
class swapchain {
|
class swap_chain {
|
||||||
public:
|
public:
|
||||||
swapchain() = default;
|
swap_chain() = default;
|
||||||
virtual ~swapchain() = default;
|
virtual ~swap_chain() = default;
|
||||||
|
|
||||||
virtual void resize(uint32_t width, uint32_t height) = 0;
|
virtual void resize(uint32_t width, uint32_t height) = 0;
|
||||||
virtual void prepare() = 0;
|
virtual void prepare() = 0;
|
||||||
virtual void present() = 0;
|
virtual void present() = 0;
|
||||||
|
|
||||||
ref<swapchain> create(const ref<render_context>& ctx);
|
virtual void set_vsync(bool vsync) = 0;
|
||||||
|
|
||||||
|
ref<swap_chain> create(const ref<render_context>& ctx);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
37
inc/dyn/renderer/vertex_buffer.h
Normal file
37
inc/dyn/renderer/vertex_buffer.h
Normal file
|
|
@ -0,0 +1,37 @@
|
||||||
|
//
|
||||||
|
// Created by nepge on 6/3/2025.
|
||||||
|
//
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <glm/glm.hpp>
|
||||||
|
#include <vulkan/vulkan_core.h>
|
||||||
|
#include <array>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "dyn/core/base.h"
|
||||||
|
|
||||||
|
namespace dyn::core {
|
||||||
|
class vulkan_graphics_pipeline;
|
||||||
|
|
||||||
|
struct vertex_pack {
|
||||||
|
glm::vec3 position;
|
||||||
|
glm::vec3 color;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
static VkVertexInputBindingDescription get_binding_description();
|
||||||
|
static std::array<VkVertexInputAttributeDescription, 2> get_vertex_attribute_descriptions();
|
||||||
|
|
||||||
|
friend vulkan_graphics_pipeline;
|
||||||
|
};
|
||||||
|
|
||||||
|
class vertex_buffer {
|
||||||
|
public:
|
||||||
|
virtual ~vertex_buffer() = default;
|
||||||
|
|
||||||
|
virtual void destroy() = 0;
|
||||||
|
|
||||||
|
static ref<vertex_buffer> create(const std::vector<vertex_pack>& vertices);
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -5,5 +5,5 @@ layout(location = 0) in vec3 fragColor;
|
||||||
layout(location = 0) out vec4 outColor;
|
layout(location = 0) out vec4 outColor;
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
outColor = vec4(fragColor, 0.2);
|
outColor = vec4(fragColor, 0.5);
|
||||||
}
|
}
|
||||||
|
|
@ -1,26 +1,11 @@
|
||||||
#version 450
|
#version 450
|
||||||
|
|
||||||
|
layout(location = 0) in vec3 in_pos;
|
||||||
|
layout(location = 1) in vec3 in_color;
|
||||||
|
|
||||||
layout(location = 0) out vec3 fragColor;
|
layout(location = 0) out vec3 fragColor;
|
||||||
|
|
||||||
vec2 positions[6] = vec2[](
|
|
||||||
vec2(-0.5, -0.5),
|
|
||||||
vec2(0.5, 0.5),
|
|
||||||
vec2(-0.5, 0.5),
|
|
||||||
vec2(-0.5, -0.5),
|
|
||||||
vec2(0.5, -0.5),
|
|
||||||
vec2(0.5, 0.5)
|
|
||||||
);
|
|
||||||
|
|
||||||
vec3 colors[6] = vec3[](
|
|
||||||
vec3(1.0, 0.0, 1.0),
|
|
||||||
vec3(1.0, 1.0, 0.0),
|
|
||||||
vec3(0.0, 1.0, 1.0),
|
|
||||||
vec3(1.0, 0.0, 1.0),
|
|
||||||
vec3(0.0, 1.0, 1.0),
|
|
||||||
vec3(1.0, 1.0, 0.0)
|
|
||||||
);
|
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
gl_Position = vec4(positions[gl_VertexIndex], 0.0, 1.0);
|
gl_Position = vec4(in_pos.xyz, 1.0);
|
||||||
fragColor = colors[gl_VertexIndex];
|
fragColor = in_color;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
10
src/core/event.cpp
Normal file
10
src/core/event.cpp
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
//
|
||||||
|
// Created by nepge on 6/2/2025.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include <dyn/core/event.h>
|
||||||
|
|
||||||
|
namespace dyn::core {
|
||||||
|
event_dispatcher::event_dispatcher(event &event) : _event(event) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -10,26 +10,40 @@
|
||||||
#include "dyn/renderer/render_context.h"
|
#include "dyn/renderer/render_context.h"
|
||||||
|
|
||||||
namespace dyn::core {
|
namespace dyn::core {
|
||||||
|
window_resize_event::window_resize_event(uint32_t width, uint32_t height) : width(width), height(height) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
window::window(window_spec spec): _spec(std::move(spec)) {
|
window::window(window_spec spec): _spec(std::move(spec)) {
|
||||||
DYN_ASSERT(glfwInit(), "GLFW failed to initialize");
|
auto glfw_init_result = glfw_verify(glfwInit());
|
||||||
|
DYN_ASSERT(glfw_init_result, "GLFW failed to initialize");
|
||||||
|
|
||||||
set_window_hints();
|
set_window_hints();
|
||||||
const char* title = _spec.title.c_str();
|
const char* title = _spec.title.c_str();
|
||||||
|
|
||||||
_window = glfwCreateWindow(
|
_window = glfw_verify(glfwCreateWindow(
|
||||||
static_cast<int>(_spec.width),
|
static_cast<int>(_spec.width),
|
||||||
static_cast<int>(_spec.height),
|
static_cast<int>(_spec.height),
|
||||||
title,
|
title,
|
||||||
nullptr, nullptr);
|
nullptr, nullptr));
|
||||||
|
|
||||||
auto monitor = glfwGetPrimaryMonitor();
|
DYN_ASSERT(_window != nullptr, "Failed to create GLFW window");
|
||||||
auto vidMode = glfwGetVideoMode(monitor);
|
|
||||||
|
auto monitor = glfw_verify(glfwGetPrimaryMonitor());
|
||||||
|
DYN_ASSERT(monitor != nullptr, "Failed to get primary monitor");
|
||||||
|
auto vidMode = glfw_verify(glfwGetVideoMode(monitor));
|
||||||
|
|
||||||
auto x = (vidMode->width/2) - spec.width/2;
|
auto x = (vidMode->width/2) - spec.width/2;
|
||||||
auto y = (vidMode->height/2) - spec.height/2;
|
auto y = (vidMode->height/2) - spec.height/2;
|
||||||
glfwSetWindowPos(_window, x, y);
|
glfwSetWindowPos(_window, x, y);
|
||||||
|
|
||||||
DYN_ASSERT(_window != nullptr, "Failed to create GLFW window");
|
glfwSetWindowUserPointer(_window, &_window_mem);
|
||||||
|
|
||||||
|
glfwSetWindowSizeCallback(_window, [](GLFWwindow* window, int width, int height) {
|
||||||
|
auto win_mem = (window_mem*)glfwGetWindowUserPointer(window);
|
||||||
|
auto resize_event = window_resize_event(width, height);
|
||||||
|
win_mem->event_callback(resize_event);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
window::~window() {
|
window::~window() {
|
||||||
|
|
@ -52,11 +66,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);
|
||||||
|
#ifdef __APPLE__
|
||||||
// support MoltenVK (https://stackoverflow.com/questions/58732459/vk-error-incompatible-driver-with-mac-os-and-vulkan-moltenvk)
|
// support MoltenVK (https://stackoverflow.com/questions/58732459/vk-error-incompatible-driver-with-mac-os-and-vulkan-moltenvk)
|
||||||
result.push_back("VK_KHR_portability_enumeration");
|
result.push_back("VK_KHR_portability_enumeration");
|
||||||
|
#endif
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void window::set_event_callback(const event_callback_fn &callback) {
|
||||||
|
_window_mem.event_callback = callback;
|
||||||
|
}
|
||||||
|
|
||||||
|
void window::get_size(int *width, int *height) const {
|
||||||
|
glfwGetFramebufferSize(_window, width, height);
|
||||||
|
}
|
||||||
|
|
||||||
void window::set_window_hints() {
|
void window::set_window_hints() {
|
||||||
auto render_api = render_context::get_api();
|
auto render_api = render_context::get_api();
|
||||||
|
|
||||||
|
|
|
||||||
46
src/main.cpp
46
src/main.cpp
|
|
@ -1,8 +1,10 @@
|
||||||
#include "dyn/core/window.h"
|
#include "dyn/core/window.h"
|
||||||
#include "dyn/platform/vulkan/vulkan_context.h"
|
#include "dyn/platform/vulkan/vulkan_context.h"
|
||||||
|
#include "dyn/platform/vulkan/vulkan_vertex_buffer.h"
|
||||||
#include "dyn/renderer/graphics_pipeline.h"
|
#include "dyn/renderer/graphics_pipeline.h"
|
||||||
#include "dyn/renderer/render_context.h"
|
#include "dyn/renderer/render_context.h"
|
||||||
#include "dyn/renderer/shader.h"
|
#include "dyn/renderer/shader.h"
|
||||||
|
#include "dyn/renderer/vertex_buffer.h"
|
||||||
|
|
||||||
using namespace dyn;
|
using namespace dyn;
|
||||||
using namespace dyn::core;
|
using namespace dyn::core;
|
||||||
|
|
@ -18,16 +20,25 @@ int main() {
|
||||||
});
|
});
|
||||||
|
|
||||||
ref<render_context> ctx = render_context::create(win);
|
ref<render_context> ctx = render_context::create(win);
|
||||||
set_current_context(ctx);
|
render_context::set_current(ctx);
|
||||||
auto vulkan_ctx = ref_as<vulkan_context>(ctx);
|
auto vulkan_ctx = ref_as<vulkan_context>(ctx);
|
||||||
ctx->init();
|
ctx->init();
|
||||||
|
|
||||||
|
ctx->set_vsync(true);
|
||||||
|
|
||||||
ref<shader> vert_shader = shader::create_from_file("resources/shaders/basic.vert.glsl", shader::VERTEX);
|
win->set_event_callback([=](event& ev) {
|
||||||
|
event_dispatcher dispatcher(ev);
|
||||||
|
dispatcher.dispatch<window_resize_event>([=](window_resize_event& e) {
|
||||||
|
ctx->resize(e.width, e.height);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
ref<shader> vert_shader = shader::create_from_file("resources/shaders/basic.vert.glsl", shader::Vertex);
|
||||||
if (vert_shader != nullptr) {
|
if (vert_shader != nullptr) {
|
||||||
vert_shader->build(ctx);
|
vert_shader->build(ctx);
|
||||||
}
|
}
|
||||||
auto frag_shader = shader::create_from_file("resources/shaders/basic.frag.glsl", shader::FRAGMENT);
|
auto frag_shader = shader::create_from_file("resources/shaders/basic.frag.glsl", shader::Fragment);
|
||||||
if (frag_shader != nullptr) {
|
if (frag_shader != nullptr) {
|
||||||
frag_shader->build(ctx);
|
frag_shader->build(ctx);
|
||||||
}
|
}
|
||||||
|
|
@ -41,17 +52,40 @@ int main() {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<vertex_pack> vertices = {
|
||||||
|
{{0.0f, -0.2f, 1.0f}, {91.f/255.f, 206.f/250.f, 250.f/255.f}},
|
||||||
|
{{0.2f, 0.2f, 0.0f}, {245.f/255.f, 169.f/255.f, 184.f/255.f}},
|
||||||
|
{{-0.2f, 0.2f, 0.0f}, {245.f/255.f, 169.f/255.f, 184.f/255.f}},
|
||||||
|
{{-0.4f, -0.4f, 0.f}, {245.f/255.f, 169.f/255.f, 184.f/255.f}},
|
||||||
|
{{0.4f, -0.4f, 0.0f}, {245.f/255.f, 169.f/255.f, 184.f/255.f}},
|
||||||
|
{{0.0f, -0.2f, 0.0f}, {91.f/255.f, 206.f/250.f, 250.f/255.f}},
|
||||||
|
};
|
||||||
|
|
||||||
|
auto buffer = ref_as<vulkan_vertex_buffer>(vertex_buffer::create(vertices));
|
||||||
|
|
||||||
|
VkBuffer vertex_buffers[] = {buffer->get_handle()};
|
||||||
|
VkDeviceSize offsets[] = {0};
|
||||||
|
|
||||||
|
|
||||||
while (win->is_open()) {
|
while (win->is_open()) {
|
||||||
win->poll_events();
|
win->poll_events();
|
||||||
ctx->cmd_begin();
|
auto start = std::chrono::high_resolution_clock::now();
|
||||||
|
if (ctx->cmd_begin()) {
|
||||||
|
|
||||||
pipeline->bind();
|
pipeline->bind();
|
||||||
|
|
||||||
ctx->submit([=] {
|
render_context::submit_current([=] {
|
||||||
VK_CMD(Draw, vulkan_ctx, 6, 1, 0, 0);
|
VK_CMD(BindVertexBuffers, vulkan_ctx, 0, 1, vertex_buffers, offsets);
|
||||||
|
VK_CMD(Draw, vulkan_ctx, static_cast<uint32_t>(vertices.size()), 1, 0, 0);
|
||||||
});
|
});
|
||||||
|
|
||||||
ctx->cmd_end();
|
ctx->cmd_end();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
auto end = std::chrono::high_resolution_clock::now();
|
||||||
|
auto duration = std::chrono::duration_cast<std::chrono::microseconds>(end - start);
|
||||||
|
//DYN_INFO_LOG("Frame time:", static_cast<double>(duration.count()) / 1000.0, "ms");
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx->destroy();
|
ctx->destroy();
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,9 @@
|
||||||
// Created by Neo on 2/24/25.
|
// Created by Neo on 2/24/25.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
#define VMA_IMPLEMENTATION
|
||||||
|
#include <vk_mem_alloc.h>
|
||||||
|
|
||||||
#include <dyn/platform/vulkan/vulkan.h>
|
#include <dyn/platform/vulkan/vulkan.h>
|
||||||
|
|
||||||
namespace dyn::utils {
|
namespace dyn::utils {
|
||||||
|
|
|
||||||
|
|
@ -10,10 +10,6 @@
|
||||||
namespace dyn::core {
|
namespace dyn::core {
|
||||||
ref<vulkan_context> g_vulkan_context = nullptr;
|
ref<vulkan_context> g_vulkan_context = nullptr;
|
||||||
|
|
||||||
ref<vulkan_context> get_current_vulkan_context() {
|
|
||||||
return g_vulkan_context;
|
|
||||||
}
|
|
||||||
|
|
||||||
vulkan_context::vulkan_context(const ref<window>& window) : _window(window) {}
|
vulkan_context::vulkan_context(const ref<window>& window) : _window(window) {}
|
||||||
|
|
||||||
vulkan_context::~vulkan_context() {
|
vulkan_context::~vulkan_context() {
|
||||||
|
|
@ -45,8 +41,10 @@ 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;
|
||||||
|
#ifdef __APPLE__
|
||||||
// support MoltenVK (https://stackoverflow.com/questions/58732459/vk-error-incompatible-driver-with-mac-os-and-vulkan-moltenvk)
|
// 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;
|
create_info.flags = VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR;
|
||||||
|
#endif
|
||||||
|
|
||||||
// extensions
|
// extensions
|
||||||
auto extensions = window::get_required_extensions();
|
auto extensions = window::get_required_extensions();
|
||||||
|
|
@ -110,6 +108,17 @@ namespace dyn::core {
|
||||||
s_current_device = _device;
|
s_current_device = _device;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
VmaAllocatorCreateInfo allocator_ci{};
|
||||||
|
allocator_ci.flags = VMA_ALLOCATOR_CREATE_EXT_MEMORY_BUDGET_BIT;
|
||||||
|
allocator_ci.vulkanApiVersion = VK_API_VERSION_1_2;
|
||||||
|
allocator_ci.physicalDevice = _device->get_physical_device()->get_handle();
|
||||||
|
allocator_ci.device = _device->get_handle();
|
||||||
|
allocator_ci.instance = _instance;
|
||||||
|
|
||||||
|
vmaCreateAllocator(&allocator_ci, &_allocator);
|
||||||
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
_swap_chain = vulkan_swap_chain::create(self);
|
_swap_chain = vulkan_swap_chain::create(self);
|
||||||
}
|
}
|
||||||
|
|
@ -127,24 +136,28 @@ namespace dyn::core {
|
||||||
allocate_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
|
allocate_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
|
||||||
allocate_info.commandPool = _command_pool;
|
allocate_info.commandPool = _command_pool;
|
||||||
allocate_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
|
allocate_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
|
||||||
allocate_info.commandBufferCount = 1;
|
allocate_info.commandBufferCount = VULKAN_FRAMES_IN_FLIGHT;
|
||||||
|
|
||||||
dyn_vk_verify(vkAllocateCommandBuffers(_device->get_handle(), &allocate_info, &_command_buffer));
|
dyn_vk_verify(vkAllocateCommandBuffers(_device->get_handle(), &allocate_info, _command_buffers.data()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void vulkan_context::cmd_begin() {
|
bool vulkan_context::cmd_begin() {
|
||||||
_swap_chain->next_frame();
|
if (!_swap_chain->next_frame()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
_render_command_queue.clear();
|
_render_command_queue.clear();
|
||||||
vkResetCommandBuffer(_command_buffer, 0);
|
vkResetCommandBuffer(_command_buffers[_swap_chain->current_frame()], 0);
|
||||||
|
|
||||||
VkCommandBufferBeginInfo begin_info{};
|
VkCommandBufferBeginInfo begin_info{};
|
||||||
begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
|
begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
|
||||||
|
|
||||||
dyn_vk_verify(vkBeginCommandBuffer(_command_buffer, &begin_info));
|
dyn_vk_verify(vkBeginCommandBuffer(_command_buffers[_swap_chain->current_frame()], &begin_info));
|
||||||
|
|
||||||
_swap_chain->prepare();
|
_swap_chain->prepare();
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void vulkan_context::render_mesh_source(ref<mesh_source> mesh) {
|
void vulkan_context::render_mesh_source(ref<mesh_source> mesh) {
|
||||||
|
|
@ -152,8 +165,8 @@ namespace dyn::core {
|
||||||
|
|
||||||
void vulkan_context::cmd_end() {
|
void vulkan_context::cmd_end() {
|
||||||
_render_command_queue.execute();
|
_render_command_queue.execute();
|
||||||
vkCmdEndRenderPass(_command_buffer);
|
vkCmdEndRenderPass(_command_buffers[_swap_chain->current_frame()]);
|
||||||
if (auto result = vkEndCommandBuffer(_command_buffer); result != VK_SUCCESS) {
|
if (auto result = vkEndCommandBuffer(_command_buffers[_swap_chain->current_frame()]); result != VK_SUCCESS) {
|
||||||
DYN_ERROR_LOG("Failed to end command buffer. Error:", string_VkResult(result));
|
DYN_ERROR_LOG("Failed to end command buffer. Error:", string_VkResult(result));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -209,14 +222,16 @@ namespace dyn::core {
|
||||||
void vulkan_context::destroy() {
|
void vulkan_context::destroy() {
|
||||||
vkDeviceWaitIdle(_device->get_handle());
|
vkDeviceWaitIdle(_device->get_handle());
|
||||||
|
|
||||||
DYN_DEBUG_LOG("vulkan_context::~vulkan_context()");
|
DYN_DEBUG_LOG("vulkan_context::destroy()");
|
||||||
|
|
||||||
|
_swap_chain->destroy();
|
||||||
|
|
||||||
_cleanup_command_queue.execute();
|
_cleanup_command_queue.execute();
|
||||||
|
|
||||||
vkFreeCommandBuffers(_device->get_handle(), _command_pool, 1, &_command_buffer);
|
vkFreeCommandBuffers(_device->get_handle(), _command_pool, VULKAN_FRAMES_IN_FLIGHT, _command_buffers.data());
|
||||||
vkDestroyCommandPool(_device->get_handle(), _command_pool, nullptr);
|
vkDestroyCommandPool(_device->get_handle(), _command_pool, nullptr);
|
||||||
|
|
||||||
_swap_chain->destroy();
|
vmaDestroyAllocator(_allocator);
|
||||||
|
|
||||||
_device->destroy();
|
_device->destroy();
|
||||||
|
|
||||||
|
|
@ -227,4 +242,12 @@ namespace dyn::core {
|
||||||
vkDestroySurfaceKHR(_instance, _surface, nullptr);
|
vkDestroySurfaceKHR(_instance, _surface, nullptr);
|
||||||
vkDestroyInstance(_instance, nullptr);
|
vkDestroyInstance(_instance, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void vulkan_context::resize(uint32_t width, uint32_t height) {
|
||||||
|
_swap_chain->resize(width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
void vulkan_context::set_vsync(bool vsync) {
|
||||||
|
_swap_chain->set_vsync(vsync);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,14 +5,16 @@
|
||||||
#include <dyn/platform/vulkan/vulkan_graphics_pipeline.h>
|
#include <dyn/platform/vulkan/vulkan_graphics_pipeline.h>
|
||||||
#include <dyn/platform/vulkan/vulkan_context.h>
|
#include <dyn/platform/vulkan/vulkan_context.h>
|
||||||
|
|
||||||
|
#include "dyn/renderer/vertex_buffer.h"
|
||||||
|
|
||||||
namespace dyn::core {
|
namespace dyn::core {
|
||||||
VkPolygonMode get_vulkan_polygon_mode(PolygonMode mode) {
|
VkPolygonMode get_vulkan_polygon_mode(PolygonMode mode) {
|
||||||
switch (mode) {
|
switch (mode) {
|
||||||
case PolygonMode::FILL:
|
case PolygonMode::Fill:
|
||||||
return VK_POLYGON_MODE_FILL;
|
return VK_POLYGON_MODE_FILL;
|
||||||
case PolygonMode::LINE:
|
case PolygonMode::Line:
|
||||||
return VK_POLYGON_MODE_LINE;
|
return VK_POLYGON_MODE_LINE;
|
||||||
case PolygonMode::POINT:
|
case PolygonMode::Point:
|
||||||
return VK_POLYGON_MODE_POINT;
|
return VK_POLYGON_MODE_POINT;
|
||||||
}
|
}
|
||||||
return VK_POLYGON_MODE_MAX_ENUM;
|
return VK_POLYGON_MODE_MAX_ENUM;
|
||||||
|
|
@ -24,7 +26,15 @@ namespace dyn::core {
|
||||||
_dynamic_state_ci.pDynamicStates = g_vulkan_dynamic_states.data();
|
_dynamic_state_ci.pDynamicStates = g_vulkan_dynamic_states.data();
|
||||||
|
|
||||||
_vertex_input_ci.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
|
_vertex_input_ci.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
|
||||||
_vertex_input_ci.vertexBindingDescriptionCount = 0;
|
|
||||||
|
_vertex_binding_desc = vertex_pack::get_binding_description();
|
||||||
|
_vertex_attribute_desc = vertex_pack::get_vertex_attribute_descriptions();
|
||||||
|
|
||||||
|
_vertex_input_ci.vertexBindingDescriptionCount = 1;
|
||||||
|
_vertex_input_ci.vertexAttributeDescriptionCount = static_cast<uint32_t>(_vertex_attribute_desc.size());
|
||||||
|
|
||||||
|
_vertex_input_ci.pVertexBindingDescriptions = &_vertex_binding_desc;
|
||||||
|
_vertex_input_ci.pVertexAttributeDescriptions = _vertex_attribute_desc.data();
|
||||||
|
|
||||||
_input_assembly_ci.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
|
_input_assembly_ci.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
|
||||||
_input_assembly_ci.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
|
_input_assembly_ci.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
|
||||||
|
|
@ -150,7 +160,7 @@ namespace dyn::core {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
get_current_context()->run_at_cleanup([=] {
|
render_context::current()->run_at_cleanup([=] {
|
||||||
this->destroy();
|
this->destroy();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -158,10 +168,21 @@ namespace dyn::core {
|
||||||
}
|
}
|
||||||
|
|
||||||
void vulkan_graphics_pipeline::bind() {
|
void vulkan_graphics_pipeline::bind() {
|
||||||
get_current_context()->submit([=] {
|
render_context::submit_current([=] {
|
||||||
auto ctx = get_current_vulkan_context();
|
auto ctx = render_context::current_as<vulkan_context>();
|
||||||
VK_CMD(BindPipeline, ctx, VK_PIPELINE_BIND_POINT_GRAPHICS, _pipeline);
|
VK_CMD(BindPipeline, ctx, VK_PIPELINE_BIND_POINT_GRAPHICS, _pipeline);
|
||||||
|
|
||||||
|
_viewport.x = 0.0f;
|
||||||
|
_viewport.y = 0.0f;
|
||||||
|
auto swap_extent = ctx->get_swap_chain()->get_extent();
|
||||||
|
_viewport.width = static_cast<float>(swap_extent.width);
|
||||||
|
_viewport.height = static_cast<float>(swap_extent.height);
|
||||||
|
_viewport.minDepth = 0.0f;
|
||||||
|
_viewport.maxDepth = 1.0f;
|
||||||
|
|
||||||
|
_scissor.offset = {0, 0};
|
||||||
|
_scissor.extent = swap_extent;
|
||||||
|
|
||||||
VK_CMD(SetViewport, ctx, 0, 1, &_viewport);
|
VK_CMD(SetViewport, ctx, 0, 1, &_viewport);
|
||||||
VK_CMD(SetScissor, ctx, 0, 1, &_scissor);
|
VK_CMD(SetScissor, ctx, 0, 1, &_scissor);
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,9 @@ namespace dyn::core {
|
||||||
vulkan_shader::vulkan_shader(
|
vulkan_shader::vulkan_shader(
|
||||||
const std::vector<uint32_t>&source,
|
const std::vector<uint32_t>&source,
|
||||||
const std::string& filename, ShaderType type)
|
const std::string& filename, ShaderType type)
|
||||||
: _binary(source.begin(), source.end()), _filename(filename), _type(type), _stage(vulkan_stage_from_type(type)) {}
|
: _binary(source.begin(), source.end()), _filename(filename), _type(type), _stage(vulkan_stage_from_type(type)) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
vulkan_shader::~vulkan_shader() {
|
vulkan_shader::~vulkan_shader() {
|
||||||
|
|
||||||
|
|
@ -19,13 +21,13 @@ namespace dyn::core {
|
||||||
|
|
||||||
VkShaderStageFlagBits vulkan_shader::vulkan_stage_from_type(ShaderType type) {
|
VkShaderStageFlagBits vulkan_shader::vulkan_stage_from_type(ShaderType type) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case VERTEX:
|
case Vertex:
|
||||||
return VK_SHADER_STAGE_VERTEX_BIT;
|
return VK_SHADER_STAGE_VERTEX_BIT;
|
||||||
case FRAGMENT:
|
case Fragment:
|
||||||
return VK_SHADER_STAGE_FRAGMENT_BIT;
|
return VK_SHADER_STAGE_FRAGMENT_BIT;
|
||||||
case GEOMETRY:
|
case Geometry:
|
||||||
return VK_SHADER_STAGE_GEOMETRY_BIT;
|
return VK_SHADER_STAGE_GEOMETRY_BIT;
|
||||||
case COMPUTE:
|
case Compute:
|
||||||
return VK_SHADER_STAGE_COMPUTE_BIT;
|
return VK_SHADER_STAGE_COMPUTE_BIT;
|
||||||
}
|
}
|
||||||
return static_cast<VkShaderStageFlagBits>(0);
|
return static_cast<VkShaderStageFlagBits>(0);
|
||||||
|
|
|
||||||
|
|
@ -9,76 +9,7 @@
|
||||||
|
|
||||||
namespace dyn::core {
|
namespace dyn::core {
|
||||||
vulkan_swap_chain::vulkan_swap_chain(const ref<vulkan_context> &ctx) : _logical_device(ctx->get_current_device()) {
|
vulkan_swap_chain::vulkan_swap_chain(const ref<vulkan_context> &ctx) : _logical_device(ctx->get_current_device()) {
|
||||||
auto phy_device = _logical_device->get_physical_device();
|
this->rebuild(true);
|
||||||
|
|
||||||
auto dev_handle = _logical_device->get_handle();
|
|
||||||
|
|
||||||
auto support_details = vulkan_swap_chain::get_support_details(
|
|
||||||
ctx->get_surface(),
|
|
||||||
phy_device->get_handle());
|
|
||||||
|
|
||||||
auto surface_format = get_format(support_details.formats);
|
|
||||||
auto present_mode = get_present_mode(support_details.present_modes);
|
|
||||||
auto extent = get_extent(ctx, support_details.capabilities);
|
|
||||||
|
|
||||||
uint32_t image_count = support_details.capabilities.minImageCount + 2;
|
|
||||||
if (support_details.capabilities.maxImageCount > 0 && image_count > support_details.capabilities.maxImageCount) {
|
|
||||||
image_count = support_details.capabilities.maxImageCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
_swap_images.resize(image_count);
|
|
||||||
|
|
||||||
VkSwapchainCreateInfoKHR create_info = {};
|
|
||||||
create_info.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
|
|
||||||
create_info.surface = ctx->get_surface();
|
|
||||||
create_info.minImageCount = image_count;
|
|
||||||
create_info.imageFormat = surface_format.format;
|
|
||||||
create_info.imageColorSpace = surface_format.colorSpace;
|
|
||||||
create_info.imageExtent = extent;
|
|
||||||
create_info.presentMode = present_mode;
|
|
||||||
create_info.imageArrayLayers = 1;
|
|
||||||
create_info.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
|
|
||||||
|
|
||||||
auto indices = phy_device->get_queue_families();
|
|
||||||
uint32_t family_indices[] = {indices.graphics_family.value(), indices.present_family.value()};
|
|
||||||
|
|
||||||
if (indices.graphics_family.value() != indices.present_family.value()) {
|
|
||||||
create_info.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
|
||||||
create_info.queueFamilyIndexCount = 2;
|
|
||||||
create_info.pQueueFamilyIndices = family_indices;
|
|
||||||
} else {
|
|
||||||
create_info.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
|
||||||
create_info.queueFamilyIndexCount = 0;
|
|
||||||
create_info.pQueueFamilyIndices = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
create_info.preTransform = support_details.capabilities.currentTransform;
|
|
||||||
create_info.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
|
|
||||||
create_info.presentMode = present_mode;
|
|
||||||
create_info.clipped = VK_TRUE;
|
|
||||||
create_info.oldSwapchain = VK_NULL_HANDLE;
|
|
||||||
|
|
||||||
_image_format = surface_format.format;
|
|
||||||
_extent = extent;
|
|
||||||
|
|
||||||
dyn_vk_verify(vkCreateSwapchainKHR(dev_handle, &create_info, nullptr, &_swap_chain));
|
|
||||||
|
|
||||||
VkSemaphoreCreateInfo semaphore_info{};
|
|
||||||
semaphore_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
|
|
||||||
VkFenceCreateInfo fence_info{};
|
|
||||||
fence_info.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
|
|
||||||
fence_info.flags = VK_FENCE_CREATE_SIGNALED_BIT;
|
|
||||||
|
|
||||||
dyn_vk_verify(vkCreateSemaphore(dev_handle, &semaphore_info, nullptr, &_image_available));
|
|
||||||
dyn_vk_verify(vkCreateSemaphore(dev_handle, &semaphore_info, nullptr, &_render_finished));
|
|
||||||
dyn_vk_verify(vkCreateFence(dev_handle, &fence_info, nullptr, &_in_flight));
|
|
||||||
|
|
||||||
// create swap chain images
|
|
||||||
build_swap_images();
|
|
||||||
|
|
||||||
create_render_pass();
|
|
||||||
|
|
||||||
create_framebuffers();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
vulkan_swap_chain::~vulkan_swap_chain() {
|
vulkan_swap_chain::~vulkan_swap_chain() {
|
||||||
|
|
@ -86,11 +17,11 @@ namespace dyn::core {
|
||||||
}
|
}
|
||||||
|
|
||||||
void vulkan_swap_chain::prepare() {
|
void vulkan_swap_chain::prepare() {
|
||||||
get_current_context()->submit([=] {
|
render_context::submit_current([=] {
|
||||||
VkRenderPassBeginInfo render_pass_info{};
|
VkRenderPassBeginInfo render_pass_info{};
|
||||||
render_pass_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
|
render_pass_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
|
||||||
render_pass_info.renderPass = _render_pass;
|
render_pass_info.renderPass = _render_pass;
|
||||||
render_pass_info.framebuffer = _framebuffers[_current_frame];
|
render_pass_info.framebuffer = _framebuffers[_image_indices[_current_frame]];
|
||||||
render_pass_info.renderArea.offset = {0, 0};
|
render_pass_info.renderArea.offset = {0, 0};
|
||||||
render_pass_info.renderArea.extent = _extent;
|
render_pass_info.renderArea.extent = _extent;
|
||||||
|
|
||||||
|
|
@ -98,16 +29,16 @@ namespace dyn::core {
|
||||||
render_pass_info.clearValueCount = 1;
|
render_pass_info.clearValueCount = 1;
|
||||||
render_pass_info.pClearValues = &clear_value;
|
render_pass_info.pClearValues = &clear_value;
|
||||||
|
|
||||||
VK_CMD(BeginRenderPass, get_current_vulkan_context(), &render_pass_info, VK_SUBPASS_CONTENTS_INLINE);
|
VK_CMD(BeginRenderPass, render_context::current_as<vulkan_context>(), &render_pass_info, VK_SUBPASS_CONTENTS_INLINE);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void vulkan_swap_chain::present() {
|
void vulkan_swap_chain::present() {
|
||||||
auto cmd_buffer = get_current_vulkan_context()->get_command_buffer();
|
auto cmd_buffer = render_context::current_as<vulkan_context>()->get_current_command_buffer();
|
||||||
VkSubmitInfo submit_info{};
|
VkSubmitInfo submit_info{};
|
||||||
submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
|
submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
|
||||||
|
|
||||||
VkSemaphore wait_semaphores[] = {_image_available};
|
VkSemaphore wait_semaphores[] = {_image_available_semaphores[_current_frame]};
|
||||||
VkPipelineStageFlags wait_stages[] = {VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT};
|
VkPipelineStageFlags wait_stages[] = {VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT};
|
||||||
submit_info.waitSemaphoreCount = 1;
|
submit_info.waitSemaphoreCount = 1;
|
||||||
submit_info.pWaitSemaphores = wait_semaphores;
|
submit_info.pWaitSemaphores = wait_semaphores;
|
||||||
|
|
@ -116,11 +47,11 @@ namespace dyn::core {
|
||||||
submit_info.pCommandBuffers = &cmd_buffer;
|
submit_info.pCommandBuffers = &cmd_buffer;
|
||||||
submit_info.signalSemaphoreCount = 1;
|
submit_info.signalSemaphoreCount = 1;
|
||||||
|
|
||||||
VkSemaphore signal_semaphores[] = {_render_finished};
|
VkSemaphore signal_semaphores[] = {_render_finished_semaphores[_current_frame]};
|
||||||
submit_info.signalSemaphoreCount = 1;
|
submit_info.signalSemaphoreCount = 1;
|
||||||
submit_info.pSignalSemaphores = signal_semaphores;
|
submit_info.pSignalSemaphores = signal_semaphores;
|
||||||
|
|
||||||
if (auto result = vkQueueSubmit(_logical_device->get_graphics_queue(), 1, &submit_info, _in_flight); result != VK_SUCCESS) {
|
if (auto result = vkQueueSubmit(_logical_device->get_graphics_queue(), 1, &submit_info, _in_flight_fences[_current_frame]); result != VK_SUCCESS) {
|
||||||
DYN_ERROR_LOG("Failed to submit queue. Error:", string_VkResult(result));
|
DYN_ERROR_LOG("Failed to submit queue. Error:", string_VkResult(result));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -133,16 +64,49 @@ namespace dyn::core {
|
||||||
VkSwapchainKHR swap_chains[] = {_swap_chain};
|
VkSwapchainKHR swap_chains[] = {_swap_chain};
|
||||||
present_info.swapchainCount = 1;
|
present_info.swapchainCount = 1;
|
||||||
present_info.pSwapchains = swap_chains;
|
present_info.pSwapchains = swap_chains;
|
||||||
present_info.pImageIndices = &_current_frame;
|
present_info.pImageIndices = &_image_indices[_current_frame];
|
||||||
|
|
||||||
vkQueuePresentKHR(_logical_device->get_present_queue(), &present_info);
|
auto result = vkQueuePresentKHR(_logical_device->get_present_queue(), &present_info);
|
||||||
|
if (
|
||||||
|
result == VK_ERROR_OUT_OF_DATE_KHR ||
|
||||||
|
result == VK_SUBOPTIMAL_KHR ||
|
||||||
|
_invalidated) {
|
||||||
|
|
||||||
|
_invalidated = false;
|
||||||
|
rebuild();
|
||||||
|
} else if (result != VK_SUCCESS) {
|
||||||
|
DYN_DEBUG_LOG("Failed to present swap chain image. Error:", string_VkResult(result));
|
||||||
|
}
|
||||||
|
|
||||||
|
_current_frame = (_current_frame + 1) % VULKAN_FRAMES_IN_FLIGHT;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool vulkan_swap_chain::next_frame() {
|
||||||
|
if (_new_width == 0 || _new_height == 0) {
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void vulkan_swap_chain::next_frame() {
|
|
||||||
auto dev_handle = _logical_device->get_handle();
|
auto dev_handle = _logical_device->get_handle();
|
||||||
vkWaitForFences(dev_handle, 1, &_in_flight, VK_TRUE, UINT64_MAX);
|
vkWaitForFences(dev_handle, 1, &_in_flight_fences[_current_frame], VK_TRUE, UINT64_MAX);
|
||||||
vkResetFences(dev_handle, 1, &_in_flight);
|
auto result = vkAcquireNextImageKHR(dev_handle, _swap_chain, UINT64_MAX, _image_available_semaphores[_current_frame], VK_NULL_HANDLE, &_image_indices[_current_frame]);
|
||||||
vkAcquireNextImageKHR(dev_handle, _swap_chain, UINT64_MAX, _image_available, VK_NULL_HANDLE, &_current_frame);
|
|
||||||
|
if (result == VK_ERROR_OUT_OF_DATE_KHR) {
|
||||||
|
rebuild();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (result != VK_SUCCESS && result != VK_SUBOPTIMAL_KHR) {
|
||||||
|
DYN_ERROR_LOG("Acquisition of swap chain image failed with error:", string_VkResult(result));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
vkResetFences(dev_handle, 1, &_in_flight_fences[_current_frame]);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void vulkan_swap_chain::resize(uint32_t width, uint32_t height) {
|
||||||
|
_new_width = width;
|
||||||
|
_new_height = height;
|
||||||
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
swap_chain_support_details vulkan_swap_chain::get_support_details(VkSurfaceKHR surface, VkPhysicalDevice physical_device) {
|
swap_chain_support_details vulkan_swap_chain::get_support_details(VkSurfaceKHR surface, VkPhysicalDevice physical_device) {
|
||||||
|
|
@ -183,10 +147,14 @@ namespace dyn::core {
|
||||||
return formats[0];
|
return formats[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
VkPresentModeKHR vulkan_swap_chain::get_present_mode(const std::vector<VkPresentModeKHR> &modes) {
|
VkPresentModeKHR vulkan_swap_chain::get_present_mode(const std::vector<VkPresentModeKHR> &modes, bool vsync) {
|
||||||
for (const auto &mode : modes) {
|
for (const auto &mode : modes) {
|
||||||
// mailbox khr is preferred.
|
// mailbox khr is preferred.
|
||||||
if (mode == VK_PRESENT_MODE_MAILBOX_KHR) {
|
if (vsync && mode == VK_PRESENT_MODE_MAILBOX_KHR) {
|
||||||
|
return mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!vsync && mode == VK_PRESENT_MODE_IMMEDIATE_KHR) {
|
||||||
return mode;
|
return mode;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -198,11 +166,10 @@ namespace dyn::core {
|
||||||
VkExtent2D vulkan_swap_chain::get_extent(ref<vulkan_context> ctx, const VkSurfaceCapabilitiesKHR &capabilities) {
|
VkExtent2D vulkan_swap_chain::get_extent(ref<vulkan_context> ctx, const VkSurfaceCapabilitiesKHR &capabilities) {
|
||||||
if (capabilities.currentExtent.width != std::numeric_limits<uint32_t>::max()) {
|
if (capabilities.currentExtent.width != std::numeric_limits<uint32_t>::max()) {
|
||||||
return capabilities.currentExtent;
|
return capabilities.currentExtent;
|
||||||
} else {
|
}
|
||||||
|
|
||||||
int32_t width, height;
|
int32_t width, height;
|
||||||
glfwGetFramebufferSize(
|
ctx->get_window()->get_size(&width, &height);
|
||||||
ctx->get_window()->get_window_handle(),
|
|
||||||
&width, &height);
|
|
||||||
|
|
||||||
VkExtent2D actual_extent = {
|
VkExtent2D actual_extent = {
|
||||||
static_cast<uint32_t>(width),
|
static_cast<uint32_t>(width),
|
||||||
|
|
@ -219,19 +186,104 @@ namespace dyn::core {
|
||||||
capabilities.minImageExtent.height,
|
capabilities.minImageExtent.height,
|
||||||
capabilities.maxImageExtent.height);
|
capabilities.maxImageExtent.height);
|
||||||
|
|
||||||
return actual_extent;
|
return actual_extent;;
|
||||||
};
|
}
|
||||||
|
|
||||||
|
void vulkan_swap_chain::rebuild(bool fresh) {
|
||||||
|
auto ctx = render_context::current_as<vulkan_context>();
|
||||||
|
|
||||||
|
if (!fresh) {
|
||||||
|
vkDeviceWaitIdle(_logical_device->get_handle());
|
||||||
|
|
||||||
|
this->destroy_framebuffers();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto phy_device = _logical_device->get_physical_device();
|
||||||
|
|
||||||
|
auto dev_handle = _logical_device->get_handle();
|
||||||
|
|
||||||
|
auto support_details = vulkan_swap_chain::get_support_details(
|
||||||
|
ctx->get_surface(),
|
||||||
|
phy_device->get_handle());
|
||||||
|
|
||||||
|
auto surface_format = get_format(support_details.formats);
|
||||||
|
auto present_mode = get_present_mode(support_details.present_modes, _vsync);
|
||||||
|
auto extent = get_extent(ctx, support_details.capabilities);
|
||||||
|
|
||||||
|
uint32_t image_count = support_details.capabilities.minImageCount + 2;
|
||||||
|
if (support_details.capabilities.maxImageCount > 0 && image_count > support_details.capabilities.maxImageCount) {
|
||||||
|
image_count = support_details.capabilities.maxImageCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
VkSwapchainCreateInfoKHR create_info = {};
|
||||||
|
create_info.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
|
||||||
|
create_info.surface = ctx->get_surface();
|
||||||
|
create_info.minImageCount = image_count;
|
||||||
|
create_info.imageFormat = surface_format.format;
|
||||||
|
create_info.imageColorSpace = surface_format.colorSpace;
|
||||||
|
create_info.imageExtent = extent;
|
||||||
|
create_info.presentMode = present_mode;
|
||||||
|
create_info.imageArrayLayers = 1;
|
||||||
|
create_info.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
|
||||||
|
|
||||||
|
_new_width = extent.width;
|
||||||
|
_new_height = extent.height;
|
||||||
|
|
||||||
|
auto indices = phy_device->get_queue_families();
|
||||||
|
uint32_t family_indices[] = {indices.graphics_family.value(), indices.present_family.value()};
|
||||||
|
|
||||||
|
if (indices.graphics_family.value() != indices.present_family.value()) {
|
||||||
|
create_info.imageSharingMode = VK_SHARING_MODE_CONCURRENT;
|
||||||
|
create_info.queueFamilyIndexCount = 2;
|
||||||
|
create_info.pQueueFamilyIndices = family_indices;
|
||||||
|
} else {
|
||||||
|
create_info.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||||||
|
create_info.queueFamilyIndexCount = 0;
|
||||||
|
create_info.pQueueFamilyIndices = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
create_info.preTransform = support_details.capabilities.currentTransform;
|
||||||
|
create_info.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
|
||||||
|
create_info.presentMode = present_mode;
|
||||||
|
create_info.clipped = VK_TRUE;
|
||||||
|
create_info.oldSwapchain = VK_NULL_HANDLE;
|
||||||
|
|
||||||
|
_image_format = surface_format.format;
|
||||||
|
_extent = extent;
|
||||||
|
|
||||||
|
dyn_vk_verify(vkCreateSwapchainKHR(dev_handle, &create_info, nullptr, &_swap_chain));
|
||||||
|
|
||||||
|
VkSemaphoreCreateInfo semaphore_info{};
|
||||||
|
semaphore_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
|
||||||
|
VkFenceCreateInfo fence_info{};
|
||||||
|
fence_info.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
|
||||||
|
fence_info.flags = VK_FENCE_CREATE_SIGNALED_BIT;
|
||||||
|
|
||||||
|
// create swap chain images
|
||||||
|
build_swap_images();
|
||||||
|
|
||||||
|
if (fresh) {
|
||||||
|
for (auto i = 0; i < VULKAN_FRAMES_IN_FLIGHT; i++) {
|
||||||
|
dyn_vk_verify(vkCreateSemaphore(dev_handle, &semaphore_info, nullptr, &_image_available_semaphores[i]));
|
||||||
|
dyn_vk_verify(vkCreateSemaphore(dev_handle, &semaphore_info, nullptr, &_render_finished_semaphores[i]));
|
||||||
|
dyn_vk_verify(vkCreateFence(dev_handle, &fence_info, nullptr, &_in_flight_fences[i]));
|
||||||
|
}
|
||||||
|
|
||||||
|
create_render_pass();
|
||||||
|
}
|
||||||
|
|
||||||
|
create_framebuffers();
|
||||||
}
|
}
|
||||||
|
|
||||||
void vulkan_swap_chain::build_swap_images() {
|
void vulkan_swap_chain::build_swap_images() {
|
||||||
auto hogical_device = _logical_device->get_handle();
|
auto logical_device = _logical_device->get_handle();
|
||||||
|
|
||||||
uint32_t image_count = static_cast<uint32_t>(_swap_images.size());
|
uint32_t image_count = static_cast<uint32_t>(_swap_images.size());
|
||||||
|
|
||||||
std::vector<VkImage> temp_img_buf;
|
std::vector<VkImage> temp_img_buf;
|
||||||
vkGetSwapchainImagesKHR(hogical_device, _swap_chain, &image_count, nullptr);
|
vkGetSwapchainImagesKHR(logical_device, _swap_chain, &image_count, nullptr);
|
||||||
temp_img_buf.resize(image_count);
|
temp_img_buf.resize(image_count);
|
||||||
vkGetSwapchainImagesKHR(hogical_device, _swap_chain, &image_count, temp_img_buf.data());
|
vkGetSwapchainImagesKHR(logical_device, _swap_chain, &image_count, temp_img_buf.data());
|
||||||
|
|
||||||
_swap_images.resize(image_count);
|
_swap_images.resize(image_count);
|
||||||
for (uint32_t i = 0; i < image_count; i++) {
|
for (uint32_t i = 0; i < image_count; i++) {
|
||||||
|
|
@ -254,7 +306,7 @@ namespace dyn::core {
|
||||||
create_info.subresourceRange.baseArrayLayer = 0;
|
create_info.subresourceRange.baseArrayLayer = 0;
|
||||||
create_info.subresourceRange.layerCount = 1;
|
create_info.subresourceRange.layerCount = 1;
|
||||||
|
|
||||||
dyn_vk_verify(vkCreateImageView(hogical_device, &create_info, nullptr, &_swap_images[i].view));
|
dyn_vk_verify(vkCreateImageView(logical_device, &create_info, nullptr, &_swap_images[i].view));
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -318,24 +370,37 @@ namespace dyn::core {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void vulkan_swap_chain::destroy() {
|
void vulkan_swap_chain::destroy_framebuffers() {
|
||||||
auto dev_handle = _logical_device->get_handle();
|
auto dev_handle = _logical_device->get_handle();
|
||||||
|
|
||||||
vkDestroySemaphore(_logical_device->get_handle(), _image_available, nullptr);
|
|
||||||
vkDestroySemaphore(_logical_device->get_handle(), _render_finished, nullptr);
|
|
||||||
vkDestroyFence(_logical_device->get_handle(), _in_flight, nullptr);
|
|
||||||
|
|
||||||
for (auto framebuffer : _framebuffers) {
|
for (auto framebuffer : _framebuffers) {
|
||||||
vkDestroyFramebuffer(dev_handle, framebuffer, nullptr);
|
vkDestroyFramebuffer(dev_handle, framebuffer, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
vkDestroyRenderPass(dev_handle, _render_pass, nullptr);
|
|
||||||
|
|
||||||
vkDestroySwapchainKHR(dev_handle, _swap_chain, nullptr);
|
|
||||||
|
|
||||||
for (auto img : _swap_images) {
|
for (auto img : _swap_images) {
|
||||||
vkDestroyImageView(dev_handle, img.view, nullptr);
|
vkDestroyImageView(dev_handle, img.view, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
vkDestroySwapchainKHR(dev_handle, _swap_chain, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void vulkan_swap_chain::destroy() {
|
||||||
|
auto dev_handle = _logical_device->get_handle();
|
||||||
|
|
||||||
|
this->destroy_framebuffers();
|
||||||
|
|
||||||
|
for (auto i = 0; i < VULKAN_FRAMES_IN_FLIGHT; i++) {
|
||||||
|
vkDestroySemaphore(_logical_device->get_handle(), _image_available_semaphores[i], nullptr);
|
||||||
|
vkDestroySemaphore(_logical_device->get_handle(), _render_finished_semaphores[i], nullptr);
|
||||||
|
vkDestroyFence(_logical_device->get_handle(), _in_flight_fences[i], nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
vkDestroyRenderPass(dev_handle, _render_pass, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void vulkan_swap_chain::set_vsync(bool vsync) {
|
||||||
|
_vsync = vsync;
|
||||||
|
this->invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
ref<vulkan_swap_chain> vulkan_swap_chain::create(const ref<vulkan_context> &ctx) {
|
ref<vulkan_swap_chain> vulkan_swap_chain::create(const ref<vulkan_context> &ctx) {
|
||||||
|
|
|
||||||
44
src/platform/vulkan/vulkan_vertex_buffer.cpp
Normal file
44
src/platform/vulkan/vulkan_vertex_buffer.cpp
Normal file
|
|
@ -0,0 +1,44 @@
|
||||||
|
//
|
||||||
|
// Created by nepge on 6/3/2025.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include <dyn/platform/vulkan/vulkan_vertex_buffer.h>
|
||||||
|
#include <vulkan/vk_enum_string_helper.h>
|
||||||
|
|
||||||
|
#include "dyn/platform/vulkan/vulkan_context.h"
|
||||||
|
#include "dyn/renderer/render_context.h"
|
||||||
|
|
||||||
|
namespace dyn::core {
|
||||||
|
vulkan_vertex_buffer::vulkan_vertex_buffer(const std::vector<vertex_pack>& vertices): _buffer(nullptr) {
|
||||||
|
auto allocator = render_context::current_as<vulkan_context>()->get_allocator();
|
||||||
|
_vertices.resize(vertices.size());
|
||||||
|
_vertices.assign(vertices.begin(), vertices.end());
|
||||||
|
|
||||||
|
VkBufferCreateInfo buffer_ci{};
|
||||||
|
buffer_ci.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
|
||||||
|
buffer_ci.size = _vertices.size() * sizeof(_vertices[0]);
|
||||||
|
buffer_ci.usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT;
|
||||||
|
buffer_ci.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||||||
|
|
||||||
|
VmaAllocationCreateInfo allocation_info{};
|
||||||
|
allocation_info.usage = VMA_MEMORY_USAGE_AUTO_PREFER_HOST;
|
||||||
|
allocation_info.flags = VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT;
|
||||||
|
|
||||||
|
if (auto result = vmaCreateBuffer(allocator, &buffer_ci, &allocation_info, &_buffer, &_buffer_allocation, nullptr); result != VK_SUCCESS) {
|
||||||
|
DYN_ERROR_LOG("Failed to creat vertex buffer with error result:", string_VkResult(result));
|
||||||
|
}
|
||||||
|
|
||||||
|
vmaCopyMemoryToAllocation(allocator, vertices.data(), _buffer_allocation, 0, buffer_ci.size);
|
||||||
|
|
||||||
|
render_context::current()->run_at_cleanup([=] {
|
||||||
|
this->destroy();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void vulkan_vertex_buffer::destroy() {
|
||||||
|
if (_buffer != nullptr) {
|
||||||
|
auto allocator = render_context::current_as<vulkan_context>()->get_allocator();
|
||||||
|
vmaDestroyBuffer(allocator, _buffer, _buffer_allocation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -8,14 +8,7 @@
|
||||||
namespace dyn::core {
|
namespace dyn::core {
|
||||||
RenderPlatform render_context::s_api = RenderPlatform::None;
|
RenderPlatform render_context::s_api = RenderPlatform::None;
|
||||||
|
|
||||||
ref<render_context> g_context = nullptr;
|
void render_context::submit(const render_command &func) {
|
||||||
|
|
||||||
void set_current_context(const ref<render_context> &context) {
|
|
||||||
g_context = std::move(context);
|
|
||||||
DYN_BREAKPOINT;
|
|
||||||
}
|
|
||||||
|
|
||||||
void render_context::submit(render_command func) {
|
|
||||||
_render_command_queue.submit(func);
|
_render_command_queue.submit(func);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -27,7 +20,7 @@ namespace dyn::core {
|
||||||
return s_api;
|
return s_api;
|
||||||
}
|
}
|
||||||
|
|
||||||
void render_context::run_at_cleanup(cleanup_command cmd) {
|
void render_context::run_at_cleanup(const cleanup_command &cmd) {
|
||||||
_cleanup_command_queue.submit(cmd);
|
_cleanup_command_queue.submit(cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -36,4 +29,19 @@ namespace dyn::core {
|
||||||
DYN_PLATFORM_CREATE_VK(vulkan_context, window);
|
DYN_PLATFORM_CREATE_VK(vulkan_context, window);
|
||||||
DYN_PLATFORM_CREATE_END(render_context)
|
DYN_PLATFORM_CREATE_END(render_context)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ref<render_context> render_context::current() {
|
||||||
|
if (g_current_context == nullptr) {
|
||||||
|
DYN_ERROR_LOG("Attempt to access null render context. Make sure render context is set properly.");
|
||||||
|
}
|
||||||
|
return g_current_context;
|
||||||
|
}
|
||||||
|
|
||||||
|
void render_context::submit_current(render_command func) {
|
||||||
|
current()->submit(func);
|
||||||
|
}
|
||||||
|
|
||||||
|
void render_context::set_current(const ref<render_context> &ctx) {
|
||||||
|
g_current_context = ctx;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
45
src/renderer/vertex_buffer.cpp
Normal file
45
src/renderer/vertex_buffer.cpp
Normal file
|
|
@ -0,0 +1,45 @@
|
||||||
|
//
|
||||||
|
// Created by nepge on 6/3/2025.
|
||||||
|
//
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <dyn/renderer/vertex_buffer.h>
|
||||||
|
|
||||||
|
#include "dyn/platform/vulkan/vulkan_vertex_buffer.h"
|
||||||
|
#include "dyn/renderer/render_context.h"
|
||||||
|
#include "dyn/renderer/shader.h"
|
||||||
|
|
||||||
|
namespace dyn::core {
|
||||||
|
VkVertexInputBindingDescription vertex_pack::get_binding_description() {
|
||||||
|
VkVertexInputBindingDescription binding_description{};
|
||||||
|
|
||||||
|
binding_description.binding = 0;
|
||||||
|
binding_description.stride = sizeof(vertex_pack);
|
||||||
|
binding_description.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
|
||||||
|
|
||||||
|
return binding_description;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::array<VkVertexInputAttributeDescription, 2> vertex_pack::get_vertex_attribute_descriptions() {
|
||||||
|
std::array<VkVertexInputAttributeDescription, 2> vertex_attribute_descriptions{};
|
||||||
|
|
||||||
|
vertex_attribute_descriptions[0].binding = 0;
|
||||||
|
vertex_attribute_descriptions[0].location = 0;
|
||||||
|
vertex_attribute_descriptions[0].format = VK_FORMAT_R32G32B32_SFLOAT;
|
||||||
|
vertex_attribute_descriptions[0].offset = offsetof(vertex_pack, position);
|
||||||
|
|
||||||
|
vertex_attribute_descriptions[1].binding = 0;
|
||||||
|
vertex_attribute_descriptions[1].location = 1;
|
||||||
|
vertex_attribute_descriptions[1].format = VK_FORMAT_R32G32B32_SFLOAT;
|
||||||
|
vertex_attribute_descriptions[1].offset = offsetof(vertex_pack, color);
|
||||||
|
|
||||||
|
return vertex_attribute_descriptions;
|
||||||
|
}
|
||||||
|
|
||||||
|
ref<vertex_buffer> vertex_buffer::create(const std::vector<vertex_pack> &vertices) {
|
||||||
|
DYN_PLATFORM_CREATE_BEGIN(render_context::get_api())
|
||||||
|
DYN_PLATFORM_CREATE_VK(vulkan_vertex_buffer, vertices);
|
||||||
|
DYN_PLATFORM_CREATE_END(vertex_buffer)
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user