diff --git a/Eternal/src/core/Camera.cpp b/Eternal/src/core/Camera.cpp new file mode 100644 index 0000000..20410c9 --- /dev/null +++ b/Eternal/src/core/Camera.cpp @@ -0,0 +1,91 @@ +#include "core/Camera.hpp" +#include "core/event/EventDispatcher.h" + +namespace Eternal { + Camera::Camera(Eternal::InputDispatcher* inputDispatcher) : m_InputDispatcher(inputDispatcher) { + } + + void Eternal::Camera::setOrthographicProjection(float left, float right, float top, float bottom, float nearPlane, + float farPlane) { + m_Projection = glm::mat4{1.0f}; + m_Projection[0][0] = 2.f / (right - left); + m_Projection[1][1] = 2.f / (bottom - top); + m_Projection[2][2] = 1.f / (farPlane - nearPlane); + m_Projection[3][0] = -(right + left) / (right - left); + m_Projection[3][1] = -(bottom + top) / (bottom - top); + m_Projection[3][2] = -nearPlane / (farPlane - nearPlane); + } + + void Eternal::Camera::setPerspectiveProjection(float fovy, float aspect, float nearPlane, float farPlane) { + ETERNAL_ASSERT(glm::abs(aspect - std::numeric_limits::epsilon()) > 0.0f, + "something wrong in setPerspectiveProjection(...)"); + glm::mat4 projection = glm::perspective(fovy, aspect, nearPlane, farPlane); + projection[1][1] *= -1; // Invert Y axis Since Vulkan uses a different coordinate system + m_Projection = projection; + } + + void Camera::onEvent(Event& event) { + EventDispatcher dispatcher(event); + dispatcher.dispatch(ETERNAL_BIND_EVENT_FN(Camera::onWindowResize)); + dispatcher.dispatch(ETERNAL_BIND_EVENT_FN(Camera::onMouseMove)); + } + + void Camera::resetMouseTracking() { + m_FirstMouse = true; + } + + void Camera::onUpdate(const Eternal::Timestep& timeStep) { + float velocity = 10.0f * timeStep.seconds(); + + glm::mat4 rotation = getRotation(); + glm::vec3 forward = glm::normalize(glm::vec3(rotation * glm::vec4(0, 0, -1, 0))); + glm::vec3 right = glm::normalize(glm::vec3(rotation * glm::vec4(1, 0, 0, 0))); + glm::vec3 up = glm::normalize(glm::vec3(rotation * glm::vec4(0, 1, 0, 0))); + + if (m_InputDispatcher->isKeyPressed(Key::W)) + m_Position += forward * velocity; + if (m_InputDispatcher->isKeyPressed(Key::S)) + m_Position -= forward * velocity; + if (m_InputDispatcher->isKeyPressed(Key::A)) + m_Position -= right * velocity; + if (m_InputDispatcher->isKeyPressed(Key::D)) + m_Position += right * velocity; + if (m_InputDispatcher->isKeyPressed(Key::Space)) + m_Position += up * velocity; + if (m_InputDispatcher->isKeyPressed(Key::LeftShift)) + m_Position -= up * velocity; + } + + bool Camera::onWindowResize(const Eternal::WindowResizeEvent& event) { + float aspectRatio = static_cast(event.getWidth()) / static_cast(event.getHeight()); + setPerspectiveProjection(glm::radians(50.f), aspectRatio, 0.1f, 1000.f); + return true; + } + + bool Camera::onMouseMove(const Eternal::MouseMovedEvent& event) { + double xpos = event.GetX(); + double ypos = event.GetY(); + + if (m_FirstMouse) { + m_LastX = xpos; + m_LastY = ypos; + m_FirstMouse = false; + } + + float xoffset = static_cast(xpos - m_LastX); + float yoffset = static_cast(m_LastY - ypos); + m_LastX = xpos; + m_LastY = ypos; + + xoffset *= m_MouseSensitivity; + yoffset *= m_MouseSensitivity; + + m_Yaw += xoffset; + m_Pitch += yoffset; + + float pitch = glm::degrees(m_Pitch); + if (pitch > 89.0f) m_Pitch = glm::radians(89.0f); + if (pitch < -89.0f) m_Pitch = glm::radians(-89.0f); + return true; + } +} diff --git a/Eternal/src/core/graphics/Camera.hpp b/Eternal/src/core/Camera.hpp similarity index 69% rename from Eternal/src/core/graphics/Camera.hpp rename to Eternal/src/core/Camera.hpp index 2a10b72..631a608 100644 --- a/Eternal/src/core/graphics/Camera.hpp +++ b/Eternal/src/core/Camera.hpp @@ -1,21 +1,26 @@ #pragma once +#include "utils/Base.h" +#include "core/input/InputDispatcher.h" +#include "core/event/Event.h" +#include "core/event/MouseEvents.h" +#include "core/event/WindowEvent.h" +#include "core/graphics/Timer.h" + #define GLM_ENABLE_EXPERIMENTAL -#include #include #include #include - -#include "core/scene/NameComponent.h" -#include "core/scene/TransformComponent.h" -#include "GLFW/glfw3.h" +#include namespace Eternal { class Camera { public: Camera() = default; + Camera(Eternal::InputDispatcher* inputDispatcher); + ~Camera() = default; void setOrthographicProjection( @@ -42,20 +47,26 @@ namespace Eternal { void setPosition(glm::vec3 position) { m_Position = position; } - float& getPitch() { return m_Pitch; } + float getPitch() const { return m_Pitch; } void setPitch(float pitch) { m_Pitch = pitch; } - float& getYaw() { return m_Yaw; } + float getYaw() const { return m_Yaw; } void setYaw(float yaw) { m_Yaw = yaw; } - void onUpdate(GLFWwindow* window); + void onEvent(Event& event); + + void onUpdate(const Eternal::Timestep& timeStep); + + void resetMouseTracking(); private: - void processMouseMovement(GLFWwindow* window); + bool onWindowResize(const Eternal::WindowResizeEvent& event); + + bool onMouseMove(const Eternal::MouseMovedEvent& event); - void processKeyboad(GLFWwindow* window); + Eternal::InputDispatcher* m_InputDispatcher = nullptr; glm::mat4 m_Projection{1.0f}; glm::vec3 m_Position = {0.0f, 0.0f, 0.0f}; @@ -63,7 +74,7 @@ namespace Eternal { float m_Yaw = 1.0f; float m_Pitch = 0.0f; - float m_AspectRatio; + float m_AspectRatio = 0.0f; float m_MouseSensitivity = 0.002f; // mouse state diff --git a/Eternal/src/core/Engine.cpp b/Eternal/src/core/Engine.cpp deleted file mode 100644 index e4d94be..0000000 --- a/Eternal/src/core/Engine.cpp +++ /dev/null @@ -1,64 +0,0 @@ -#include -#include -#include -#include -#include - -#include -#define GLM_ENABLE_EXPERIMENTAL -#include - -namespace Eternal { - Engine::Engine(const Builder& builder) { - m_ApplicationName = builder->applicationName; - - m_Backend = builder->backend; - ETERNAL_ASSERT(m_Backend == Backend::Vulkan, "Currently Only supported Backend is Vulkan"); - - m_GraphicsPlatform = Eternal::GraphicsPlatform::Builder() - .applicationName(m_ApplicationName) - .backend(m_Backend) - .build(); - } - - Engine::~Engine() { - Memory::Deallocate(m_Renderer); - } - - Renderer* Engine::createRenderer(Window* window, Scene* scene) { - m_Renderer = Eternal::Renderer::Builder() - .backend(m_Backend) - .platform(m_GraphicsPlatform) - .window(window) - .scene(scene) - .build(); - - return m_Renderer; - } - - Engine::Builder::Builder() noexcept = default; - - Engine::Builder::Builder(Builder const& rhs) noexcept = default; - - Engine::Builder::Builder(Builder&& rhs) noexcept = default; - - Engine::Builder::~Builder() noexcept = default; - - Engine::Builder& Engine::Builder::operator=(Builder const& rhs) noexcept = default; - - Engine::Builder& Engine::Builder::operator=(Builder&& rhs) noexcept = default; - - Engine::Builder& Engine::Builder::applicationName(const std::string& applicationName) noexcept { - mImpl->applicationName = applicationName; - return *this; - } - - Engine::Builder& Engine::Builder::backend(Backend backend) noexcept { - mImpl->backend = backend; - return *this; - } - - Engine* Engine::Builder::build() { - return Memory::Allocate(*this); - } -} diff --git a/Eternal/src/core/Engine.h b/Eternal/src/core/Engine.h deleted file mode 100644 index a284219..0000000 --- a/Eternal/src/core/Engine.h +++ /dev/null @@ -1,53 +0,0 @@ -#pragma once -#define GLFW_INCLUDE_VULKAN -#define VK_USE_PLATFORM_WIN32_KHR - -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -namespace Eternal { - - class Engine{ - public: - struct BuilderDetails { - std::string applicationName; - Backend backend = Backend::Vulkan; - }; - - class Builder : public utils::PrivateImplementation { - friend class Engine; - - public: - Builder() noexcept; - Builder(Builder const& rhs) noexcept; - Builder(Builder&& rhs) noexcept; - ~Builder() noexcept; - Builder& operator=(Builder const& rhs) noexcept; - Builder& operator=(Builder&& rhs) noexcept; - Builder& applicationName(const std::string& applicationName) noexcept; - Builder& backend(Backend backend) noexcept; - Engine* build(); - }; - - Engine(const Builder& builder); - ~Engine(); - Renderer* createRenderer(Window* window, Scene* scene); - Renderer* getRenderer() { return m_Renderer; } - Eternal::GraphicsPlatform* getPlatform() { return m_GraphicsPlatform; } - - private: - Renderer* m_Renderer; - std::string m_ApplicationName; - Backend m_Backend = Backend::Vulkan; - GraphicsPlatform* m_GraphicsPlatform = nullptr; - - }; -} \ No newline at end of file diff --git a/Eternal/src/core/ImGuiLayer.h b/Eternal/src/core/ImGuiLayer.h deleted file mode 100644 index b9d391b..0000000 --- a/Eternal/src/core/ImGuiLayer.h +++ /dev/null @@ -1,12 +0,0 @@ -#pragma once -#include - -namespace Eternal { - class ImGuiLayer - { - public: - virtual void beginFrame() = 0; - virtual void render(FrameInfo* frameInfo) = 0; - virtual ~ImGuiLayer() = default; - }; -} \ No newline at end of file diff --git a/Eternal/src/core/Logger.cpp b/Eternal/src/core/Logger.cpp deleted file mode 100644 index 43fc486..0000000 --- a/Eternal/src/core/Logger.cpp +++ /dev/null @@ -1,21 +0,0 @@ -#include "Logger.h" - -#include - -#include - -namespace Eternal { - std::shared_ptr Logger::m_InternalLogger = nullptr; - - void Logger::Init() { - std::vector logSinks; - logSinks.emplace_back(std::make_shared()); - - logSinks[0]->set_pattern("%^Eternal::%l [%T] %v%$"); - - m_InternalLogger = std::make_shared("Eternal", begin(logSinks), end(logSinks)); - spdlog::register_logger(m_InternalLogger); - m_InternalLogger->set_level(spdlog::level::trace); - m_InternalLogger->flush_on(spdlog::level::trace); - } -} \ No newline at end of file diff --git a/Eternal/src/core/Logger.h b/Eternal/src/core/Logger.h deleted file mode 100644 index 54480f6..0000000 --- a/Eternal/src/core/Logger.h +++ /dev/null @@ -1,46 +0,0 @@ -#pragma once -#define FMT_UNICODE 0 -#include "spdlog/spdlog.h" - -#include - -namespace Eternal { - - class Logger { - public: - - static void Init(); - - template - static void Warn(fmt::format_string format, Args&&... args) { - if (m_InternalLogger != nullptr) { - m_InternalLogger->warn(format, std::forward(args)...); - } - } - - template - static void Debug(fmt::format_string format, Args&&... args) { - if (m_InternalLogger != nullptr) { - m_InternalLogger->debug(format, std::forward(args)...); - } - } - - template - static void Info(fmt::format_string format, Args&&... args) { - if (m_InternalLogger != nullptr) { - m_InternalLogger->info(format, std::forward(args)...); - } - } - - template - static void Error(fmt::format_string format, Args&&... args) { - if (m_InternalLogger != nullptr) { - m_InternalLogger->error(format, std::forward(args)...); - } - } - - private: - static std::shared_ptr m_InternalLogger; - }; - -} \ No newline at end of file diff --git a/Eternal/src/core/RenderTarget.h b/Eternal/src/core/RenderTarget.h new file mode 100644 index 0000000..de60378 --- /dev/null +++ b/Eternal/src/core/RenderTarget.h @@ -0,0 +1,21 @@ +#pragma once +#include "utils/Base.h" + +namespace Eternal { + struct RenderTargetDesc { + uint32_t width = 0; + uint32_t height = 0; + bool hasColor = false; + bool hasDepth = false; + bool hasStencil = false; + }; + + class RenderTarget { + public : + RenderTarget(); + virtual ~RenderTarget() = default; + + virtual uint32_t getWidth() const = 0; + virtual uint32_t getHeight() const = 0; + }; +} diff --git a/Eternal/src/core/Window.cpp b/Eternal/src/core/Window.cpp deleted file mode 100644 index 98548f3..0000000 --- a/Eternal/src/core/Window.cpp +++ /dev/null @@ -1,48 +0,0 @@ -#include - -#include -#include - -namespace Eternal { - - Window* Window::create(const Builder& builder) { - System system = Eternal::detectSystem(); - - switch (system) { - case System::WINDOWS: - return Memory::Allocate(builder); - break; - default: - return nullptr; - break; - } - } - - Window::Builder::Builder() noexcept = default; - Window::Builder::Builder(Builder const& rhs) noexcept = default; - Window::Builder::Builder(Builder&& rhs) noexcept = default; - Window::Builder::~Builder() noexcept = default; - Window::Builder& Window::Builder::operator=(Builder const& rhs) noexcept = default; - Window::Builder& Window::Builder::operator=(Builder&& rhs) noexcept = default; - - Window::Builder& Window::Builder::title(const std::string& title) noexcept { - mImpl->title = title; - return *this; - } - - Window::Builder& Window::Builder::height(uint32_t height) noexcept { - mImpl->height = height; - return *this; - } - - Window::Builder& Window::Builder::width(uint32_t width) noexcept { - mImpl->width = width; - return *this; - } - - Window* Window::Builder::build() noexcept { - return Window::create(*this); - } -} - - diff --git a/Eternal/src/core/Window.h b/Eternal/src/core/Window.h deleted file mode 100644 index e6a847c..0000000 --- a/Eternal/src/core/Window.h +++ /dev/null @@ -1,64 +0,0 @@ -#pragma once -#include -#include - -namespace Eternal { - - class Window - { - public: - - using ResizeCallback = std::function; - - virtual ~Window() = default; - virtual void onUpdate() = 0; - virtual uint32_t getHeight() const = 0; - virtual uint32_t getWidth() const = 0; - virtual float getAspectRatio() const = 0; - virtual void* getNativeWindow() const = 0; - virtual bool shouldClose() const = 0; - virtual void shutDown() const = 0; - virtual bool isMinimized() const = 0; - - void setWindowResizeCallback(ResizeCallback callback) noexcept { - m_WindowResizeCallback = callback; - } - - void setWindowResized(bool resized) noexcept { - m_IsWindowResized = resized; - } - - bool isResized() const noexcept { - return m_IsWindowResized; - } - - struct BuilderDetails { - std::string title = ""; - uint32_t height = 0; - uint32_t width = 0; - }; - - class Builder : public utils::PrivateImplementation { - friend class Window; - friend class WindowsWindow; - public: - Builder() noexcept; - Builder(Builder const& rhs) noexcept; - Builder(Builder&& rhs) noexcept; - ~Builder() noexcept; - Builder& operator=(Builder const& rhs) noexcept; - Builder& operator=(Builder&& rhs) noexcept; - Builder& title(const std::string& title) noexcept; - Builder& width(uint32_t witdth) noexcept; - Builder& height(uint32_t height) noexcept; - Window* build() noexcept; - }; - - static Window* create(const Builder& builder); - - protected: - - bool m_IsWindowResized = false; - ResizeCallback m_WindowResizeCallback; - }; -} diff --git a/Eternal/src/core/WindowsWindow.cpp b/Eternal/src/core/WindowsWindow.cpp deleted file mode 100644 index 6665ffe..0000000 --- a/Eternal/src/core/WindowsWindow.cpp +++ /dev/null @@ -1,100 +0,0 @@ -#include "WindowsWindow.h" - -#include "resource/ResourceManager.h" -#include "resource/Image.h" - -namespace Eternal { - - WindowsWindow::WindowsWindow(const Builder& builder) : - m_Title(builder->title), - m_Height(builder->height), - m_Width(builder->width) { - glfwInit(); - - glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); - - glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE); - - m_Window = glfwCreateWindow(m_Width, m_Height, m_Title.c_str(), nullptr, nullptr); - ETERNAL_ASSERT(m_Window != nullptr, "Failed to create GLFW window"); - - glfwSetWindowUserPointer(m_Window, this); - - glfwSetFramebufferSizeCallback(m_Window, - [](GLFWwindow* window, int width, int height) { - auto app = static_cast(glfwGetWindowUserPointer(window)); - app->onWindowResize(window, width, height); - } - ); - - Logger::Info("Current Working Path {} , Accessing Window Icon", std::filesystem::current_path().string()); - setWindowIcon(WINDOW_ICON_PATH, m_Window); - - Eternal::Logger::Info("Window Created"); - } - - void WindowsWindow::onUpdate() { - glfwPollEvents(); - } - - bool WindowsWindow::shouldClose() const { - return glfwWindowShouldClose(m_Window); - } - - void WindowsWindow::shutDown() const { - if (m_Window != nullptr) { - glfwDestroyWindow(m_Window); - } - else { - Eternal::Logger::Error("mWindow Pointer is null"); - } - - glfwTerminate(); - - Eternal::Logger::Info("Window Destroyed"); - } - - vk::SurfaceKHR WindowsWindow::createWindowSurface(vk::Instance instance) const { - ETERNAL_ASSERT(m_Window != nullptr, "Window is null"); - - vk::SurfaceKHR surface = nullptr; - if (glfwCreateWindowSurface(instance, m_Window, nullptr, reinterpret_cast(&surface)) != VK_SUCCESS) { - Eternal::Logger::Error("Failed to create window surface"); - return nullptr; - } - return surface; - } - - vk::Extent2D WindowsWindow::getExtent() const { - ETERNAL_ASSERT(m_Window != nullptr, "Window is null"); - int width = 0, height = 0; - glfwGetFramebufferSize(m_Window, &width, &height); - return { static_cast(width),static_cast(height) }; - } - - void WindowsWindow::setWindowIcon(const std::filesystem::path& path, GLFWwindow* window) { - if (window == nullptr) { - Eternal::Logger::Error("Trying to set icon on null window (GLFW)"); - return; - } - - Image* image = ResourceManager::get().loadResource(path.string()); - GLFWimage icon = image->getGLFWImage(); - glfwSetWindowIcon(window, 1, &icon); - } - - void WindowsWindow::onWindowResize(GLFWwindow* window, int width, int height) { - m_Height = height; - m_Width = width; - - if (m_WindowResizeCallback) { - m_WindowResizeCallback(m_Width, m_Height); - } - - m_IsWindowResized = true; - } - - WindowsWindow::~WindowsWindow() { - WindowsWindow::shutDown(); - } -} diff --git a/Eternal/src/core/WindowsWindow.h b/Eternal/src/core/WindowsWindow.h deleted file mode 100644 index c79eecf..0000000 --- a/Eternal/src/core/WindowsWindow.h +++ /dev/null @@ -1,51 +0,0 @@ -#pragma once - -#include - -#include -#include - -#include - -namespace Eternal { - constexpr const char* WINDOW_ICON_PATH = "res/PNGs/eternal_logo.png"; - - class WindowsWindow : public VulkanWindow { - public: - WindowsWindow(const Builder& builder); - - ~WindowsWindow() override; - - void onUpdate() override; - - virtual uint32_t getHeight() const override { return m_Height; } - - virtual uint32_t getWidth() const override { return m_Width; } - - virtual void* getNativeWindow() const override { return m_Window; } - - virtual bool shouldClose() const override; - - virtual void shutDown() const override; - - bool isMinimized() const override { return m_Width == 0 || m_Height == 0; } - - virtual float getAspectRatio() const override { - return static_cast(m_Width) / static_cast(m_Height); - } - - virtual vk::SurfaceKHR createWindowSurface(vk::Instance instance) const override; - - virtual vk::Extent2D getExtent() const override; - - void setWindowIcon(const std::filesystem::path& path, GLFWwindow* window); - - private: - void onWindowResize(GLFWwindow* window, int width, int height); - - GLFWwindow* m_Window = nullptr; - std::string m_Title = ""; - uint32_t m_Height = 0; - uint32_t m_Width = 0; - }; -} diff --git a/Eternal/src/core/event/Event.h b/Eternal/src/core/event/Event.h new file mode 100644 index 0000000..49fcd25 --- /dev/null +++ b/Eternal/src/core/event/Event.h @@ -0,0 +1,30 @@ +#pragma once + +#include "utils/Base.h" + +namespace Eternal { + enum EventType { + None = 0, + WindowClose, WindowResize, WindowFocus, WindowLostFocus, WindowMoved, + KeyPressed, KeyReleased, KeyTyped, + MouseButtonPressed, MouseButtonReleased, MouseMoved, MouseScrolled + }; + + +#define EVENT_CLASS_TYPE(type) static EventType GetStaticType() { return EventType::type; }\ + virtual EventType getEventType() const override { return EventType::type; }\ + virtual const char* getName() const override { return #type; } + + class Event { + public : + bool handled = false; + + virtual ~Event() = default; + + virtual EventType getEventType() const = 0; + + virtual const char* getName() const = 0; + + virtual std::string toString() { return getName(); } + }; +} diff --git a/Eternal/src/core/event/EventDispatcher.h b/Eternal/src/core/event/EventDispatcher.h new file mode 100644 index 0000000..64365da --- /dev/null +++ b/Eternal/src/core/event/EventDispatcher.h @@ -0,0 +1,23 @@ +#pragma once + +#include "core/event/Event.h" + +namespace Eternal { + class EventDispatcher { + public : + EventDispatcher(Event& event) : m_Event(event) { + } + + template + bool dispatch(const F& func) { + if (m_Event.getEventType() == T::GetStaticType()) { + m_Event.handled |= func(static_cast(m_Event)); + return true; + } + return false; + } + + private : + Event& m_Event; + }; +} diff --git a/Eternal/src/core/event/KeyEvents.h b/Eternal/src/core/event/KeyEvents.h new file mode 100644 index 0000000..48ee60e --- /dev/null +++ b/Eternal/src/core/event/KeyEvents.h @@ -0,0 +1,38 @@ +#pragma once + +#include "core/event/Event.h" +#include "core/input/KeyCodes.h" + +namespace Eternal { + class KeyEvent : public Event { + public : + KeyCode getKeyCode() const { return m_KeyCode; } + + protected: + KeyEvent(const KeyCode keyCode) : m_KeyCode(keyCode) { + } + + KeyCode m_KeyCode; + }; + + class KeyPressedEvent : public KeyEvent { + public : + KeyPressedEvent(const KeyCode keyCode, const bool repeat) : KeyEvent(keyCode), m_IsRepeat(repeat) { + } + + bool isRepeat() const { return m_IsRepeat; } + + EVENT_CLASS_TYPE(KeyPressed) + + private : + bool m_IsRepeat; + }; + + class KeyReleasedEvent : public KeyEvent { + public : + KeyReleasedEvent(const KeyCode keyCode) : KeyEvent(keyCode) { + } + + EVENT_CLASS_TYPE(KeyReleased) + }; +} diff --git a/Eternal/src/core/event/MouseEvents.h b/Eternal/src/core/event/MouseEvents.h new file mode 100644 index 0000000..68786b2 --- /dev/null +++ b/Eternal/src/core/event/MouseEvents.h @@ -0,0 +1,21 @@ +#pragma once + +#include "core/event/Event.h" + +namespace Eternal { + class MouseMovedEvent : public Event { + public : + MouseMovedEvent(const float x, const float y) + : m_MouseX(x), m_MouseY(y) { + } + + float GetX() const { return m_MouseX; } + float GetY() const { return m_MouseY; } + + EVENT_CLASS_TYPE(MouseMoved) + + private: + float m_MouseX = 0; + float m_MouseY = 0; + }; +} diff --git a/Eternal/src/core/event/WindowEvent.h b/Eternal/src/core/event/WindowEvent.h new file mode 100644 index 0000000..6f0d43b --- /dev/null +++ b/Eternal/src/core/event/WindowEvent.h @@ -0,0 +1,20 @@ +#pragma once + +#include "core/event/Event.h" + +namespace Eternal { + class WindowResizeEvent : public Event { + public: + WindowResizeEvent(unsigned int width, unsigned int height) + : m_Width(width), m_Height(height) { + } + + unsigned int getWidth() const { return m_Width; } + unsigned int getHeight() const { return m_Height; } + + EVENT_CLASS_TYPE(WindowResize) + + private: + unsigned int m_Width, m_Height; + }; +} diff --git a/Eternal/src/core/graphics/Camera.cpp b/Eternal/src/core/graphics/Camera.cpp deleted file mode 100644 index d25d4f6..0000000 --- a/Eternal/src/core/graphics/Camera.cpp +++ /dev/null @@ -1,70 +0,0 @@ -#include "Camera.hpp" - -namespace Eternal { - void Eternal::Camera::setOrthographicProjection(float left, float right, float top, float bottom, float nearPlane, - float farPlane) { - m_Projection = glm::mat4{1.0f}; - m_Projection[0][0] = 2.f / (right - left); - m_Projection[1][1] = 2.f / (bottom - top); - m_Projection[2][2] = 1.f / (farPlane - nearPlane); - m_Projection[3][0] = -(right + left) / (right - left); - m_Projection[3][1] = -(bottom + top) / (bottom - top); - m_Projection[3][2] = -nearPlane / (farPlane - nearPlane); - } - - void Eternal::Camera::setPerspectiveProjection(float fovy, float aspect, float nearPlane, float farPlane) { - ETERNAL_ASSERT(glm::abs(aspect - std::numeric_limits::epsilon()) > 0.0f, - "something wrong in setPerspectiveProjection(...)"); - glm::mat4 projection = glm::perspective(fovy, aspect, nearPlane, farPlane); - projection[1][1] *= -1; // Invert Y axis Since Vulkan uses a different coordinate system - m_Projection = projection; - } - - void Camera::onUpdate(GLFWwindow* window) { - processMouseMovement(window); - processKeyboad(window); - } - - void Camera::processMouseMovement(GLFWwindow* window) { - double xpos, ypos; - glfwGetCursorPos(window, &xpos, &ypos); - - if (m_FirstMouse) { - m_LastX = xpos; - m_LastY = ypos; - m_FirstMouse = false; - } - - float xoffset = static_cast(xpos - m_LastX); - float yoffset = static_cast(m_LastY - ypos); // reversed since y-coordinates go bottom to top - m_LastX = xpos; - m_LastY = ypos; - - xoffset *= m_MouseSensitivity; - yoffset *= m_MouseSensitivity; - - m_Yaw += xoffset; - m_Pitch += yoffset; - - if (m_Pitch > 89.0f) m_Pitch = 89.0f; - if (m_Pitch < -89.0f) m_Pitch = -89.0f; - } - - void Camera::processKeyboad(GLFWwindow* window) { - float velocity = 0.1f; - - // Forward vector from yaw/pitch - glm::mat4 rotation = getRotation(); - glm::vec3 forward = glm::normalize(glm::vec3(rotation * glm::vec4(0, 0, -1, 0))); - glm::vec3 right = glm::normalize(glm::vec3(rotation * glm::vec4(1, 0, 0, 0))); - - if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS) - m_Position += forward * velocity; - if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS) - m_Position -= forward * velocity; - if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS) - m_Position -= right * velocity; - if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS) - m_Position += right * velocity; - } -} diff --git a/Eternal/src/core/graphics/FrameInfo.h b/Eternal/src/core/graphics/FrameInfo.h index 8986fb5..de2fd93 100644 --- a/Eternal/src/core/graphics/FrameInfo.h +++ b/Eternal/src/core/graphics/FrameInfo.h @@ -1,9 +1,13 @@ #pragma once -#include + +#include "core/graphics/Timer.h" +#include "core/Camera.hpp" namespace Eternal { - class FrameInfo { - public: - virtual ~FrameInfo() = default; - }; -} \ No newline at end of file + class FrameInfo { + public: + virtual ~FrameInfo() = default; + + Eternal::Timestep* timeStep = nullptr; + }; +} diff --git a/Eternal/src/core/graphics/GraphicsPlatform.cpp b/Eternal/src/core/graphics/GraphicsPlatform.cpp index 02e6035..bb6f7f2 100644 --- a/Eternal/src/core/graphics/GraphicsPlatform.cpp +++ b/Eternal/src/core/graphics/GraphicsPlatform.cpp @@ -1,9 +1,9 @@ -#include "GraphicsPlatform.h" -#include +#include "core/graphics/GraphicsPlatform.h" +#include "core/graphics/vulkan/VulkanPlatform.h" namespace Eternal { - GraphicsPlatform* GraphicsPlatform::create(const Builder& builder) { - return Memory::Allocate(builder); + std::unique_ptr GraphicsPlatform::create(const Builder& builder) { + return std::make_unique(builder); } GraphicsPlatform::Builder::Builder() noexcept = default; @@ -28,7 +28,7 @@ namespace Eternal { return *this; } - GraphicsPlatform* GraphicsPlatform::Builder::build() const noexcept { + std::unique_ptr GraphicsPlatform::Builder::build() const noexcept { return create(*this); } } diff --git a/Eternal/src/core/graphics/GraphicsPlatform.h b/Eternal/src/core/graphics/GraphicsPlatform.h index c5e1934..55ee635 100644 --- a/Eternal/src/core/graphics/GraphicsPlatform.h +++ b/Eternal/src/core/graphics/GraphicsPlatform.h @@ -1,9 +1,8 @@ #pragma once -#include -#include -#include -#include -#include +#include "utils/Base.h" +#include "core/window/Window.h" +#include "core/graphics/SwapChain.h" +#include "core/graphics/Backend.h" namespace Eternal { class GraphicsPlatform { @@ -42,9 +41,9 @@ namespace Eternal { Builder& backend(Backend backend) noexcept; - GraphicsPlatform* build() const noexcept; + std::unique_ptr build() const noexcept; }; - static GraphicsPlatform* create(const Builder& builder); + static std::unique_ptr create(const Builder& builder); }; } diff --git a/Eternal/src/core/graphics/IndexBuffer.h b/Eternal/src/core/graphics/IndexBuffer.h new file mode 100644 index 0000000..b06022a --- /dev/null +++ b/Eternal/src/core/graphics/IndexBuffer.h @@ -0,0 +1,12 @@ +#pragma once +#include "utils/Base.h" + +namespace Eternal { + class IndexBuffer { + public : + virtual ~IndexBuffer() = default; + virtual void bind() = 0; + virtual void unBind() = 0; + virtual uint32_t getCount() = 0; + }; +} diff --git a/Eternal/src/core/graphics/Renderer.cpp b/Eternal/src/core/graphics/Renderer.cpp index ee05f99..ee981d6 100644 --- a/Eternal/src/core/graphics/Renderer.cpp +++ b/Eternal/src/core/graphics/Renderer.cpp @@ -1,11 +1,10 @@ -#include "Renderer.h" - -#include "vulkan/VulkanRenderer.h" +#include "core/graphics/Renderer.h" +#include "core/graphics/vulkan/VulkanRenderer.h" namespace Eternal { - Renderer* Renderer::create(const Builder& builder) { + std::unique_ptr Renderer::create(const Builder& builder) { ETERNAL_ASSERT(builder->backend == Backend::Vulkan, "Currently Only supported Backend is Vulkan"); - return Memory::Allocate(builder); + return std::make_unique(builder); } Renderer::Builder::Builder() noexcept = default; @@ -40,7 +39,7 @@ namespace Eternal { return *this; } - Renderer* Renderer::Builder::build() const noexcept { + std::unique_ptr Renderer::Builder::build() const noexcept { return create(*this); } } diff --git a/Eternal/src/core/graphics/Renderer.h b/Eternal/src/core/graphics/Renderer.h index dad123f..1087c8e 100644 --- a/Eternal/src/core/graphics/Renderer.h +++ b/Eternal/src/core/graphics/Renderer.h @@ -1,11 +1,10 @@ #pragma once -#include -#include -#include - -#include "Backend.h" -#include "GraphicsPlatform.h" +#include "utils/Base.h" +#include "core/graphics/SwapChain.h" +#include "core/graphics/FrameInfo.h" +#include "core/graphics/Backend.h" +#include "core/graphics/GraphicsPlatform.h" #include "core/scene/Scene.h" namespace Eternal { @@ -13,12 +12,14 @@ namespace Eternal { public: virtual FrameInfo* beginFrame() = 0; - virtual void render() = 0; + virtual void render(Eternal::Camera* camera) = 0; virtual void endFrame() = 0; virtual ~Renderer() = default; + virtual SwapChain* getSwapChain() const = 0; + struct BuilderDetails { Backend backend = Vulkan; GraphicsPlatform* platform = nullptr; @@ -51,9 +52,9 @@ namespace Eternal { Builder& scene(Scene* scene) noexcept; - Renderer* build() const noexcept; + std::unique_ptr build() const noexcept; }; - static Renderer* create(Builder const& builder); + static std::unique_ptr create(Builder const& builder); }; } diff --git a/Eternal/src/core/graphics/Timer.h b/Eternal/src/core/graphics/Timer.h index b13a75a..e95e1e3 100644 --- a/Eternal/src/core/graphics/Timer.h +++ b/Eternal/src/core/graphics/Timer.h @@ -3,25 +3,40 @@ #include namespace Eternal { - class Timer { - public: - Timer() { - lastFrameTime = std::chrono::high_resolution_clock::now(); - } - - float getDeltaTime() { - auto deltaTime = getDeltaDuration(); - return deltaTime.count(); - } - - private: - std::chrono::time_point lastFrameTime; - - std::chrono::duration getDeltaDuration() { - auto currentTime = std::chrono::high_resolution_clock::now(); - std::chrono::duration deltaTime = currentTime - lastFrameTime; - lastFrameTime = currentTime; - return deltaTime; - } - }; -} \ No newline at end of file + class Timestep { + public: + Timestep(double time = 0.0f) + : m_Time(time) { + } + + operator double() const { return m_Time; } + + double seconds() const { return m_Time; } + double milliSeconds() const { return m_Time * 1000.0f; } + + private: + double m_Time; + }; + + class Timer { + public: + Timer() = default; + + ~Timer() = default; + + void start() { + m_LastFrameTime = std::chrono::high_resolution_clock::now(); + } + + Timestep tick() { + auto now = std::chrono::high_resolution_clock::now(); + std::chrono::duration delta = now - m_LastFrameTime; + m_LastFrameTime = now; + Timestep timeStep(delta.count()); + return timeStep; + } + + private: + std::chrono::time_point m_LastFrameTime; + }; +} diff --git a/Eternal/src/core/graphics/Vertex.h b/Eternal/src/core/graphics/Vertex.h index 37947a9..c276c42 100644 --- a/Eternal/src/core/graphics/Vertex.h +++ b/Eternal/src/core/graphics/Vertex.h @@ -1,68 +1,74 @@ #pragma once -#include -#include +#include "utils/Base.h" +#include #include namespace Eternal { - struct Vertex { - public: - glm::vec3 position; - glm::vec3 color; - glm::vec3 normal; - glm::vec2 uv; + struct Vertex { + public: + glm::vec3 position = {0.0f, 0.0f, 0.0f}; + glm::vec3 color = {0.0f, 0.0f, 0.0f}; + glm::vec3 normal = {0.0f, 0.0f, 0.0f}; + glm::vec2 uv = {0.0f, 0.0f}; + + public: + Vertex() = default; + + Vertex(float x, float y, float z) : position(x, y, z) { + } + + Vertex(glm::vec3 pos, glm::vec3 color) : position(pos), color(color) { + } - public: - Vertex() = default; - Vertex(float x, float y, float z) : position(x, y, z) {} - Vertex(glm::vec3 pos, glm::vec3 color) : position(pos), color(color) {} - Vertex(float value) : position(value, value, value) {} + Vertex(float value) : position(value, value, value) { + } - bool operator==(const Vertex& other) const { - return position == other.position && color == other.color && normal == other.normal && uv == other.uv; - } + bool operator==(const Vertex& other) const { + return position == other.position && color == other.color && normal == other.normal && uv == other.uv; + } - static std::vector getBindingDescription() { - vk::VertexInputBindingDescription bindingDesc = vk::VertexInputBindingDescription() - .setBinding(0) - .setStride(sizeof(Eternal::Vertex)) - .setInputRate(vk::VertexInputRate::eVertex); + static std::vector getBindingDescription() { + vk::VertexInputBindingDescription bindingDesc = vk::VertexInputBindingDescription() + .setBinding(0) + .setStride(sizeof(Eternal::Vertex)) + .setInputRate(vk::VertexInputRate::eVertex); - return { bindingDesc }; - } + return {bindingDesc}; + } - static std::vector getAttributeDescription() { - std::vector attributeDescs; - vk::VertexInputAttributeDescription positionAttribDesc = vk::VertexInputAttributeDescription() - .setLocation(0) - .setBinding(0) - .setFormat(vk::Format::eR32G32B32Sfloat) - .setOffset(offsetof(Vertex, position)); - attributeDescs.push_back(positionAttribDesc); + static std::vector getAttributeDescription() { + std::vector attributeDescs; + vk::VertexInputAttributeDescription positionAttribDesc = vk::VertexInputAttributeDescription() + .setLocation(0) + .setBinding(0) + .setFormat(vk::Format::eR32G32B32Sfloat) + .setOffset(offsetof(Vertex, position)); + attributeDescs.push_back(positionAttribDesc); - vk::VertexInputAttributeDescription colorAttribDesc = vk::VertexInputAttributeDescription() - .setLocation(1) - .setBinding(0) - .setFormat(vk::Format::eR32G32B32Sfloat) - .setOffset(offsetof(Vertex, color)); - attributeDescs.push_back(colorAttribDesc); + vk::VertexInputAttributeDescription colorAttribDesc = vk::VertexInputAttributeDescription() + .setLocation(1) + .setBinding(0) + .setFormat(vk::Format::eR32G32B32Sfloat) + .setOffset(offsetof(Vertex, color)); + attributeDescs.push_back(colorAttribDesc); - vk::VertexInputAttributeDescription normalAttribDesc = vk::VertexInputAttributeDescription() - .setLocation(2) - .setBinding(0) - .setFormat(vk::Format::eR32G32B32Sfloat) - .setOffset(offsetof(Vertex, normal)); - attributeDescs.push_back(normalAttribDesc); + vk::VertexInputAttributeDescription normalAttribDesc = vk::VertexInputAttributeDescription() + .setLocation(2) + .setBinding(0) + .setFormat(vk::Format::eR32G32B32Sfloat) + .setOffset(offsetof(Vertex, normal)); + attributeDescs.push_back(normalAttribDesc); - vk::VertexInputAttributeDescription uvAttribDesc = vk::VertexInputAttributeDescription() - .setLocation(3) - .setBinding(0) - .setFormat(vk::Format::eR32G32Sfloat) - .setOffset(offsetof(Vertex, uv)); - attributeDescs.push_back(uvAttribDesc); + vk::VertexInputAttributeDescription uvAttribDesc = vk::VertexInputAttributeDescription() + .setLocation(3) + .setBinding(0) + .setFormat(vk::Format::eR32G32Sfloat) + .setOffset(offsetof(Vertex, uv)); + attributeDescs.push_back(uvAttribDesc); - return attributeDescs; - } - }; -} \ No newline at end of file + return attributeDescs; + } + }; +} diff --git a/Eternal/src/core/graphics/VertexBuffer.h b/Eternal/src/core/graphics/VertexBuffer.h new file mode 100644 index 0000000..01caf2e --- /dev/null +++ b/Eternal/src/core/graphics/VertexBuffer.h @@ -0,0 +1,12 @@ +#pragma once +#include "utils/Base.h" + +namespace Eternal { + class VertexBuffer { + public : + virtual ~VertexBuffer() = default; + virtual void bind() = 0; + virtual void unBind() = 0; + virtual uint32_t getCount() = 0; + }; +} diff --git a/Eternal/src/core/graphics/vulkan/VulkanBuffer.cpp b/Eternal/src/core/graphics/vulkan/VulkanBuffer.cpp index 1f0e9ef..104e675 100644 --- a/Eternal/src/core/graphics/vulkan/VulkanBuffer.cpp +++ b/Eternal/src/core/graphics/vulkan/VulkanBuffer.cpp @@ -1,63 +1,71 @@ -#include "VulkanBuffer.h" -#include "VulkanPlatform.h" +#include "core/graphics/vulkan/VulkanBuffer.h" +#include "core/graphics/vulkan/VulkanPlatform.h" namespace Eternal { - void VulkanBuffer::create(uint32_t elementCount, uint32_t elementSize, vk::BufferUsageFlagBits usage) { - m_ElementCount = elementCount; - m_BufferSize = elementSize * m_ElementCount; - - vk::BufferCreateInfo bufferInfo = vk::BufferCreateInfo() - .setSize(m_BufferSize) - .setUsage(usage) - .setSharingMode(vk::SharingMode::eExclusive); - - m_Buffer = m_LogicalDevice.createBuffer(bufferInfo); - } - - void VulkanBuffer::allocate(vk::MemoryPropertyFlags properties) { - vk::MemoryRequirements memRequirements = m_LogicalDevice.getBufferMemoryRequirements(m_Buffer); - - uint32_t memoryTypeIndex = VulkanPlatform::getMemoryType(m_PhysicalDevice, properties, memRequirements.memoryTypeBits); - ETERNAL_ASSERT(memoryTypeIndex != 0xFFFFFFFF, "Failed to find suitable memory type"); - - vk::MemoryAllocateInfo allocInfo = vk::MemoryAllocateInfo() - .setAllocationSize(memRequirements.size) - .setMemoryTypeIndex(memoryTypeIndex); - - m_Memory = m_LogicalDevice.allocateMemory(allocInfo); - m_LogicalDevice.bindBufferMemory(m_Buffer, m_Memory, 0); - } - - void VulkanBuffer::map() { - if (!m_MappedMemory) { - m_MappedMemory = m_LogicalDevice.mapMemory(m_Memory, 0, m_BufferSize); - } - } - - void VulkanBuffer::unMap() { - m_LogicalDevice.unmapMemory(m_Memory); - m_MappedMemory = nullptr; - } - - void VulkanBuffer::write(void* data) { - ETERNAL_ASSERT(m_MappedMemory != nullptr, "Memory should be mapped first, forgot call map(..) maybe ?"); - memcpy(m_MappedMemory, data, (size_t)m_BufferSize); - } - - VulkanBuffer::~VulkanBuffer() { - if (isCurrentlyMapped()) { - Eternal::Logger::Info("Buffer was previously mapped, internally unmapping"); - unMap(); - } - - if (m_Memory) { - m_LogicalDevice.freeMemory(m_Memory); - } - - if (m_Buffer) { - m_LogicalDevice.destroyBuffer(m_Buffer); - } - - m_MappedMemory = nullptr; - } -} \ No newline at end of file + void VulkanBuffer::create(uint32_t elementCount, uint32_t elementSize, vk::BufferUsageFlagBits usage) { + vk::Device logicalDevice = m_VulkanPlatform->getLogicalDevice(); + m_ElementCount = elementCount; + m_BufferSize = elementSize * m_ElementCount; + + vk::BufferCreateInfo bufferInfo = vk::BufferCreateInfo() + .setSize(m_BufferSize) + .setUsage(usage) + .setSharingMode(vk::SharingMode::eExclusive); + + m_Buffer = logicalDevice.createBuffer(bufferInfo); + } + + void VulkanBuffer::allocate(vk::MemoryPropertyFlags properties) { + vk::Device logicalDevice = m_VulkanPlatform->getLogicalDevice(); + vk::PhysicalDevice physicalDevice = m_VulkanPlatform->getPhysicalDevice(); + + vk::MemoryRequirements memRequirements = logicalDevice.getBufferMemoryRequirements(m_Buffer); + + uint32_t memoryTypeIndex = VulkanPlatform::getMemoryType(physicalDevice, properties, + memRequirements.memoryTypeBits); + ETERNAL_ASSERT(memoryTypeIndex != 0xFFFFFFFF, "Failed to find suitable memory type"); + + vk::MemoryAllocateInfo allocInfo = vk::MemoryAllocateInfo() + .setAllocationSize(memRequirements.size) + .setMemoryTypeIndex(memoryTypeIndex); + + m_Memory = logicalDevice.allocateMemory(allocInfo); + logicalDevice.bindBufferMemory(m_Buffer, m_Memory, 0); + } + + void VulkanBuffer::map() { + vk::Device logicalDevice = m_VulkanPlatform->getLogicalDevice(); + if (!m_MappedMemory) { + m_MappedMemory = logicalDevice.mapMemory(m_Memory, 0, m_BufferSize); + } + } + + void VulkanBuffer::unMap() { + vk::Device logicalDevice = m_VulkanPlatform->getLogicalDevice(); + logicalDevice.unmapMemory(m_Memory); + m_MappedMemory = nullptr; + } + + void VulkanBuffer::write(void* data) { + ETERNAL_ASSERT(m_MappedMemory != nullptr, "Memory should be mapped first, forgot call map(..) maybe ?"); + memcpy(m_MappedMemory, data, (size_t) m_BufferSize); + } + + VulkanBuffer::~VulkanBuffer() { + vk::Device logicalDevice = m_VulkanPlatform->getLogicalDevice(); + if (isCurrentlyMapped()) { + Eternal::Logger::Info("Buffer was previously mapped, internally unmapping"); + unMap(); + } + + if (m_Memory) { + logicalDevice.freeMemory(m_Memory); + } + + if (m_Buffer) { + logicalDevice.destroyBuffer(m_Buffer); + } + + m_MappedMemory = nullptr; + } +} diff --git a/Eternal/src/core/graphics/vulkan/VulkanBuffer.h b/Eternal/src/core/graphics/vulkan/VulkanBuffer.h index 9757f67..2383527 100644 --- a/Eternal/src/core/graphics/vulkan/VulkanBuffer.h +++ b/Eternal/src/core/graphics/vulkan/VulkanBuffer.h @@ -1,42 +1,42 @@ #pragma once #include -#include -#include + +#include "core/graphics/vulkan/VulkanPlatform.h" +#include "utils/Base.h" +#include "core/log/Logger.h" namespace Eternal { - class VulkanBuffer { - public: + class VulkanBuffer { + public: + VulkanBuffer(VulkanPlatform* vulkanPlatform) : m_VulkanPlatform(vulkanPlatform) { + } - VulkanBuffer(vk::Device logicalDevice, vk::PhysicalDevice physicalDevice) : - m_LogicalDevice(logicalDevice), m_PhysicalDevice(physicalDevice) { - } - VulkanBuffer(const VulkanBuffer&) = delete; - VulkanBuffer& operator=(const VulkanBuffer&) = delete; - ~VulkanBuffer(); + VulkanBuffer(const VulkanBuffer&) = delete; + VulkanBuffer& operator=(const VulkanBuffer&) = delete; + ~VulkanBuffer(); - void create(uint32_t elementCount, uint32_t elementSize, vk::BufferUsageFlagBits usage); - void allocate(vk::MemoryPropertyFlags properties); - void map(); - void unMap(); - void write(void* data); - bool isCurrentlyMapped() const { return m_MappedMemory != nullptr; } - void* mappedMemory() const { return m_MappedMemory; } - const uint32_t& getElementCount() const { return m_ElementCount; } - uint32_t getBufferSize() const { return m_BufferSize; } + void create(uint32_t elementCount, uint32_t elementSize, vk::BufferUsageFlagBits usage); + void allocate(vk::MemoryPropertyFlags properties); + void map(); + void unMap(); + void write(void* data); + bool isCurrentlyMapped() const { return m_MappedMemory != nullptr; } + void* mappedMemory() const { return m_MappedMemory; } + const uint32_t& getElementCount() const { return m_ElementCount; } + uint32_t getBufferSize() const { return m_BufferSize; } - vk::Buffer* getBuffer() { - ETERNAL_ASSERT_LOG(m_Buffer, "Buffer is not created yet, call create() first"); - return &m_Buffer; - } + vk::Buffer* getVkBuffer() { + ETERNAL_ASSERT_LOG(m_Buffer, "Buffer is not created yet, call create() first"); + return &m_Buffer; + } - private: - vk::Device m_LogicalDevice = nullptr; - vk::PhysicalDevice m_PhysicalDevice = nullptr; - vk::Buffer m_Buffer = nullptr; - vk::DeviceMemory m_Memory = nullptr; - void* m_MappedMemory = nullptr; - uint32_t m_ElementCount = 0; - uint32_t m_BufferSize = 0; - }; -} \ No newline at end of file + private: + vk::Buffer m_Buffer = nullptr; + VulkanPlatform* m_VulkanPlatform = nullptr; + vk::DeviceMemory m_Memory = nullptr; + void* m_MappedMemory = nullptr; + uint32_t m_ElementCount = 0; + uint32_t m_BufferSize = 0; + }; +} diff --git a/Eternal/src/core/graphics/vulkan/VulkanBufferManager.cpp b/Eternal/src/core/graphics/vulkan/VulkanBufferManager.cpp index eed72de..f8dccef 100644 --- a/Eternal/src/core/graphics/vulkan/VulkanBufferManager.cpp +++ b/Eternal/src/core/graphics/vulkan/VulkanBufferManager.cpp @@ -1,75 +1,73 @@ -#include "VulkanBufferManager.h" -#include -#include -#include +#include "core/graphics/vulkan/VulkanBufferManager.h" +#include "core/graphics/vulkan/VulkanPlatform.h" +#include "core/scene/RenderComponent.h" +#include "core/scene/Entity.h" namespace Eternal { - - VulkanBufferManager::VulkanBufferManager(vk::Device device, vk::PhysicalDevice physicalDevice, Scene* scene) { - m_Device = device; - m_Scene = scene; - m_PhysicalDevice = physicalDevice; - - initializeBuffers(); - } - - VulkanBufferManager::~VulkanBufferManager() { - m_VertexBuffers.clear(); - m_IndexBuffers.clear(); - } - - void VulkanBufferManager::initializeBuffers() { - vk::MemoryPropertyFlags bufferProperties = vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent; - - for (auto& e : m_Scene->getAllEntityWith()) { - Eternal::Entity entity = Eternal::Entity(e, m_Scene); - EntityId entityUUID = entity.getUUID(); - - if (m_VertexBuffers.count(entityUUID) >= 1 || m_IndexBuffers.count(entityUUID) >= 1) - continue; - - auto& component = entity.getComponent(); - - addBuffer(entityUUID, component); - } - - for (auto& e : m_Scene->getAllEntityWith()) { - Eternal::Entity entity = Eternal::Entity(e, m_Scene); - EntityId entityUUID = entity.getUUID(); - - if (m_UniformBuffers.count(entityUUID) >= 1 ) - continue; - - auto& component = entity.getComponent(); - - addUniformBuffer(entityUUID, component); - } - } - - void VulkanBufferManager::addBuffer(EntityId entityId, const RenderComponent& renderComponent) { - auto vertexBuffer = std::make_shared(m_Device, m_PhysicalDevice); - vertexBuffer->create(renderComponent.getVertices().size(), sizeof(Eternal::Vertex), vk::BufferUsageFlagBits::eVertexBuffer); - vertexBuffer->allocate(m_BufferProperties); - vertexBuffer->map(); - vertexBuffer->write((void*)(renderComponent.getVertices().data())); - - m_VertexBuffers[entityId] = vertexBuffer; - - auto indexBuffer = std::make_shared(m_Device, m_PhysicalDevice); - indexBuffer->create(renderComponent.getIndices().size(), sizeof(uint32_t), vk::BufferUsageFlagBits::eIndexBuffer); - indexBuffer->allocate(m_BufferProperties); - indexBuffer->map(); - indexBuffer->write((void*)(renderComponent.getIndices().data())); - - m_IndexBuffers[entityId] = indexBuffer; - } - - void VulkanBufferManager::addUniformBuffer(EntityId entityId, const TransformComponent& transformComponent) { - auto uniformBuffer = std::make_shared(m_Device, m_PhysicalDevice); - uniformBuffer->create(1, sizeof(UniformBuffer), vk::BufferUsageFlagBits::eUniformBuffer); - uniformBuffer->allocate(m_UniformBufferProperties); - uniformBuffer->map(); - m_UniformBuffers[entityId] = uniformBuffer; - } + VulkanBufferManager::VulkanBufferManager(VulkanPlatform* vulkanPlatform, Scene* scene) : m_VulkanPlatform(vulkanPlatform) { + m_Scene = scene; + initializeBuffers(); + } + + VulkanBufferManager::~VulkanBufferManager() { + m_VertexBuffers.clear(); + m_IndexBuffers.clear(); + } + + void VulkanBufferManager::initializeBuffers() { + vk::MemoryPropertyFlags bufferProperties = + vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent; + + for (auto& e: m_Scene->getAllEntityWith()) { + Eternal::Entity entity = Eternal::Entity(e, m_Scene); + EntityId entityUUID = entity.getUUID(); + + if (m_VertexBuffers.contains(entityUUID) || m_IndexBuffers.contains(entityUUID)) + continue; + + auto& component = entity.getComponent(); + + addBuffer(entityUUID, component); + } + + for (auto& e: m_Scene->getAllEntityWith()) { + Eternal::Entity entity = Eternal::Entity(e, m_Scene); + EntityId entityUUID = entity.getUUID(); + + if (m_UniformBuffers.contains(entityUUID)) + continue; + + auto& component = entity.getComponent(); + + addUniformBuffer(entityUUID, component); + } + } + + void VulkanBufferManager::addBuffer(EntityId entityId, const RenderComponent& renderComponent) { + auto vertexBuffer = std::make_shared(m_VulkanPlatform); + vertexBuffer->create(renderComponent.getVertices().size(), sizeof(Eternal::Vertex), + vk::BufferUsageFlagBits::eVertexBuffer); + vertexBuffer->allocate(m_BufferProperties); + vertexBuffer->map(); + vertexBuffer->write((void*) (renderComponent.getVertices().data())); + + m_VertexBuffers[entityId] = vertexBuffer; + + auto indexBuffer = std::make_shared(m_VulkanPlatform); + indexBuffer->create(renderComponent.getIndices().size(), sizeof(uint32_t), + vk::BufferUsageFlagBits::eIndexBuffer); + indexBuffer->allocate(m_BufferProperties); + indexBuffer->map(); + indexBuffer->write((void*) (renderComponent.getIndices().data())); + + m_IndexBuffers[entityId] = indexBuffer; + } + + void VulkanBufferManager::addUniformBuffer(EntityId entityId, const TransformComponent& transformComponent) { + auto uniformBuffer = std::make_shared(m_VulkanPlatform); + uniformBuffer->create(1, sizeof(UniformBuffer), vk::BufferUsageFlagBits::eUniformBuffer); + uniformBuffer->allocate(m_UniformBufferProperties); + uniformBuffer->map(); + m_UniformBuffers[entityId] = uniformBuffer; + } } - diff --git a/Eternal/src/core/graphics/vulkan/VulkanBufferManager.h b/Eternal/src/core/graphics/vulkan/VulkanBufferManager.h index 9ca30fb..2906738 100644 --- a/Eternal/src/core/graphics/vulkan/VulkanBufferManager.h +++ b/Eternal/src/core/graphics/vulkan/VulkanBufferManager.h @@ -1,88 +1,86 @@ #pragma once -#include -#include -#include - -#include "VulkanBuffer.h" +#include "utils/Base.h" +#include "core/graphics/vulkan/VulkanPlatform.h" +#include "core/graphics/vulkan/VulkanBuffer.h" +#include "core/scene/Scene.h" +#include "core/scene/RenderComponent.h" namespace Eternal { - - class VulkanPlatform; - - class VulkanBufferManager { - public: - - using EntityId = uint32_t; - using VulkanEntityData = std::unordered_map>; - - struct UniformBuffer { - alignas(16) glm::mat4 projection{ 1.0f }; - alignas(16) glm::mat4 view{ 1.0f }; - alignas(16) glm::mat4 model{ 1.0f }; - }; - - VulkanBufferManager(vk::Device device, vk::PhysicalDevice physicalDevice, Scene* scene); - - std::shared_ptr getVertexBuffer(EntityId entityId) { - auto it = m_VertexBuffers.find(entityId); - if (it != m_VertexBuffers.end()) { - return it->second; - } - return nullptr; - } - - std::shared_ptr getIndexBuffer(EntityId entityId) { - auto it = m_IndexBuffers.find(entityId); - if (it != m_IndexBuffers.end()) { - return it->second; - } - return nullptr; - } - - std::shared_ptr getUniformBuffer(EntityId entityId) { - auto it = m_UniformBuffers.find(entityId); - if (it != m_UniformBuffers.end()) { - return it->second; - } - return nullptr; - } - - uint32_t getVertexBufferCount() const { - return static_cast(m_VertexBuffers.size()); - } - - uint32_t getIndexBufferCount() const { - return static_cast(m_IndexBuffers.size()); - } - - uint32_t getUniformBufferCount() const { - return static_cast(m_UniformBuffers.size()); - } - - const VulkanEntityData& getUniformBuffers() { return m_UniformBuffers; } - const VulkanEntityData& getVertexBuffers() { return m_VertexBuffers; } - const VulkanEntityData& getIndexBuffers() { return m_IndexBuffers; } - - void addBuffer(EntityId entityId, const RenderComponent& renderComponent); - void addUniformBuffer(EntityId entityId, const TransformComponent& transformComponent); - - ~VulkanBufferManager(); - - private: - - void initializeBuffers(); - - Scene* m_Scene; - - vk::Device m_Device; - - vk::PhysicalDevice m_PhysicalDevice; - vk::MemoryPropertyFlags m_BufferProperties = vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent; - vk::MemoryPropertyFlags m_UniformBufferProperties = vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent; - - VulkanEntityData m_VertexBuffers; - VulkanEntityData m_IndexBuffers; - VulkanEntityData m_UniformBuffers; - }; -} \ No newline at end of file + class VulkanPlatform; + + class VulkanBufferManager { + public: + using EntityId = uint32_t; + using VulkanEntityData = std::unordered_map >; + + struct UniformBuffer { + alignas(16) glm::mat4 projection{1.0f}; + alignas(16) glm::mat4 view{1.0f}; + alignas(16) glm::mat4 model{1.0f}; + }; + + VulkanBufferManager(VulkanPlatform* vulkanPlatform, Scene* scene); + + std::shared_ptr getVertexBuffer(EntityId entityId) { + auto it = m_VertexBuffers.find(entityId); + if (it != m_VertexBuffers.end()) { + return it->second; + } + return nullptr; + } + + std::shared_ptr getIndexBuffer(EntityId entityId) { + auto it = m_IndexBuffers.find(entityId); + if (it != m_IndexBuffers.end()) { + return it->second; + } + return nullptr; + } + + std::shared_ptr getUniformBuffer(EntityId entityId) { + auto it = m_UniformBuffers.find(entityId); + if (it != m_UniformBuffers.end()) { + return it->second; + } + return nullptr; + } + + uint32_t getVertexBufferCount() const { + return static_cast(m_VertexBuffers.size()); + } + + uint32_t getIndexBufferCount() const { + return static_cast(m_IndexBuffers.size()); + } + + uint32_t getUniformBufferCount() const { + return static_cast(m_UniformBuffers.size()); + } + + const VulkanEntityData& getUniformBuffers() { return m_UniformBuffers; } + const VulkanEntityData& getVertexBuffers() { return m_VertexBuffers; } + const VulkanEntityData& getIndexBuffers() { return m_IndexBuffers; } + + void addBuffer(EntityId entityId, const RenderComponent& renderComponent); + void addUniformBuffer(EntityId entityId, const TransformComponent& transformComponent); + + ~VulkanBufferManager(); + + private: + void initializeBuffers(); + + Scene* m_Scene; + + vk::MemoryPropertyFlags m_BufferProperties = + vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent; + vk::MemoryPropertyFlags m_UniformBufferProperties = + vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent; + + VulkanPlatform* m_VulkanPlatform; + + VulkanEntityData m_VertexBuffers; + VulkanEntityData m_IndexBuffers; + VulkanEntityData m_UniformBuffers; + }; +} diff --git a/Eternal/src/core/graphics/vulkan/VulkanDescriptorPool.cpp b/Eternal/src/core/graphics/vulkan/VulkanDescriptorPool.cpp index 2213a58..9ec0cd7 100644 --- a/Eternal/src/core/graphics/vulkan/VulkanDescriptorPool.cpp +++ b/Eternal/src/core/graphics/vulkan/VulkanDescriptorPool.cpp @@ -1,109 +1,103 @@ -#include "VulkanDescriptorPool.h" +#include "core/graphics/vulkan/VulkanDescriptorPool.h" namespace Eternal { - VulkanDescriptorPool::Builder::Builder(vk::Device logicalDevice) noexcept - { - mImpl->logicalDevice = logicalDevice; - } + VulkanDescriptorPool::Builder::Builder(vk::Device logicalDevice) noexcept { + mImpl->logicalDevice = logicalDevice; + } - VulkanDescriptorPool::Builder::Builder(Builder const& rhs) noexcept = default; + VulkanDescriptorPool::Builder::Builder(Builder const& rhs) noexcept = default; - VulkanDescriptorPool::Builder::Builder(Builder&& rhs) noexcept = default; + VulkanDescriptorPool::Builder::Builder(Builder&& rhs) noexcept = default; - VulkanDescriptorPool::Builder::~Builder() noexcept = default; + VulkanDescriptorPool::Builder::~Builder() noexcept = default; - VulkanDescriptorPool::Builder& VulkanDescriptorPool::Builder::operator=(Builder const& rhs) noexcept = default; + VulkanDescriptorPool::Builder& VulkanDescriptorPool::Builder::operator=(Builder const& rhs) noexcept = default; - VulkanDescriptorPool::Builder& VulkanDescriptorPool::Builder::operator=(Builder&& rhs) noexcept = default; + VulkanDescriptorPool::Builder& VulkanDescriptorPool::Builder::operator=(Builder&& rhs) noexcept = default; - VulkanDescriptorPool::Builder& VulkanDescriptorPool::Builder::addPoolSize(PoolSize poolSize) { - ETERNAL_ASSERT(mImpl->poolSizes.size() < MAX_DESCRIPTOR_POOL_SIZE, "Pool size limit reached, Seriosuly Brah!"); - mImpl->poolSizes.push_back(poolSize); - return *this; - } + VulkanDescriptorPool::Builder& VulkanDescriptorPool::Builder::addPoolSize(PoolSize poolSize) { + ETERNAL_ASSERT(mImpl->poolSizes.size() < MAX_DESCRIPTOR_POOL_SIZE, "Pool size limit reached, Seriosuly Brah!"); + mImpl->poolSizes.push_back(poolSize); + return *this; + } - VulkanDescriptorPool::Builder& VulkanDescriptorPool::Builder::setMaxSets(uint32_t maxSets) noexcept { - mImpl->maxSets = maxSets; - return *this; - } + VulkanDescriptorPool::Builder& VulkanDescriptorPool::Builder::setMaxSets(uint32_t maxSets) noexcept { + mImpl->maxSets = maxSets; + return *this; + } - VulkanDescriptorPool* VulkanDescriptorPool::Builder::build() noexcept { - return Memory::Allocate(*this); - } + VulkanDescriptorPool* VulkanDescriptorPool::Builder::build() noexcept { + return Memory::Allocate(*this); + } - VulkanDescriptorPool::VulkanDescriptorPool(const Builder& builder) { - m_LogicalDevice = builder->logicalDevice; - m_MaxSets = builder->maxSets; + VulkanDescriptorPool::VulkanDescriptorPool(const Builder& builder) { + m_LogicalDevice = builder->logicalDevice; + m_MaxSets = builder->maxSets; - m_PoolSizes.reserve(m_PoolSizes.size()); + m_PoolSizes.reserve(m_PoolSizes.size()); - for (const auto& poolSize : builder->poolSizes) { - vk::DescriptorPoolSize descriptorPoolSize = vk::DescriptorPoolSize() - .setType(poolSize.type) - .setDescriptorCount(poolSize.descriptorCount); - m_PoolSizes.push_back(descriptorPoolSize); - } + for (const auto& poolSize: builder->poolSizes) { + vk::DescriptorPoolSize descriptorPoolSize = vk::DescriptorPoolSize() + .setType(poolSize.type) + .setDescriptorCount(poolSize.descriptorCount); + m_PoolSizes.push_back(descriptorPoolSize); + } - vk::DescriptorPoolCreateInfo descriptorPoolCreateInfo = vk::DescriptorPoolCreateInfo() - .setMaxSets(m_MaxSets) - .setPoolSizes(m_PoolSizes); + vk::DescriptorPoolCreateInfo descriptorPoolCreateInfo = vk::DescriptorPoolCreateInfo() + .setMaxSets(m_MaxSets) + .setPoolSizes(m_PoolSizes); - m_DescriptorPool = m_LogicalDevice.createDescriptorPool(descriptorPoolCreateInfo); - } + m_DescriptorPool = m_LogicalDevice.createDescriptorPool(descriptorPoolCreateInfo); + } - VulkanDescriptorPool::~VulkanDescriptorPool() { - if (m_DescriptorPool) { - m_LogicalDevice.destroyDescriptorPool(m_DescriptorPool); - m_DescriptorPool = nullptr; - } - m_PoolSizes.clear(); - m_CurrentlyAllocatedSets = 0; - } + VulkanDescriptorPool::~VulkanDescriptorPool() { + if (m_DescriptorPool) { + m_LogicalDevice.destroyDescriptorPool(m_DescriptorPool); + m_DescriptorPool = nullptr; + } + m_PoolSizes.clear(); + } - void VulkanDescriptorPool::reset() { - m_LogicalDevice.resetDescriptorPool(m_DescriptorPool, vk::DescriptorPoolResetFlags()); - m_CurrentlyAllocatedSets = 0; - } + void VulkanDescriptorPool::reset() { + m_LogicalDevice.resetDescriptorPool(m_DescriptorPool, vk::DescriptorPoolResetFlags()); + } - vk::DescriptorSet VulkanDescriptorPool::allocate(const VulkanDescriptorSetLayout& descriptorSetLayout) { - auto descriptorLayout = descriptorSetLayout.getDescriptorSetLayout(); + vk::DescriptorSet VulkanDescriptorPool::allocate(const VulkanDescriptorSetLayout& descriptorSetLayout) { + auto descriptorLayout = descriptorSetLayout.getDescriptorSetLayout(); - vk::DescriptorSetAllocateInfo descriptorSetAllocateInfo = vk::DescriptorSetAllocateInfo() - .setDescriptorPool(m_DescriptorPool) - .setDescriptorSetCount(1) - .setSetLayouts(descriptorLayout); + vk::DescriptorSetAllocateInfo descriptorSetAllocateInfo = vk::DescriptorSetAllocateInfo() + .setDescriptorPool(m_DescriptorPool) + .setDescriptorSetCount(1) + .setSetLayouts(descriptorLayout); - vk::DescriptorSet descriptorSet = m_LogicalDevice.allocateDescriptorSets(descriptorSetAllocateInfo)[0]; - m_CurrentlyAllocatedSets++; - return descriptorSet; - } + vk::DescriptorSet descriptorSet = m_LogicalDevice.allocateDescriptorSets(descriptorSetAllocateInfo)[0]; + return descriptorSet; + } - std::vector VulkanDescriptorPool::allocate(uint32_t descriptorSetCount, const VulkanDescriptorSetLayout& descriptorSetLayout) { - ETERNAL_ASSERT(descriptorSetCount <= m_MaxSets, "Descriptor set count exceeds max sets"); + std::vector VulkanDescriptorPool::allocate(uint32_t descriptorSetCount, + const VulkanDescriptorSetLayout& + descriptorSetLayout) { + ETERNAL_ASSERT(descriptorSetCount <= m_MaxSets, "Descriptor set count exceeds max sets"); - std::vector descriptorLayouts(descriptorSetCount, descriptorSetLayout.getDescriptorSetLayout()); + std::vector descriptorLayouts(descriptorSetCount, + descriptorSetLayout.getDescriptorSetLayout()); - vk::DescriptorSetAllocateInfo descriptorSetAllocateInfo = vk::DescriptorSetAllocateInfo() - .setDescriptorPool(m_DescriptorPool) - .setDescriptorSetCount(descriptorSetCount) - .setSetLayouts(descriptorLayouts); + vk::DescriptorSetAllocateInfo descriptorSetAllocateInfo = vk::DescriptorSetAllocateInfo() + .setDescriptorPool(m_DescriptorPool) + .setDescriptorSetCount(descriptorSetCount) + .setSetLayouts(descriptorLayouts); - auto descSets = m_LogicalDevice.allocateDescriptorSets(descriptorSetAllocateInfo); + auto descSets = m_LogicalDevice.allocateDescriptorSets(descriptorSetAllocateInfo); - ETERNAL_ASSERT(descSets.size() == descriptorSetCount, "Failed to allocate descriptor sets"); + ETERNAL_ASSERT(descSets.size() == descriptorSetCount, "Failed to allocate descriptor sets"); + return descSets; + } - m_CurrentlyAllocatedSets += descriptorSetCount; + void VulkanDescriptorPool::free(vk::DescriptorSet* descriptorSet) { + m_LogicalDevice.freeDescriptorSets(m_DescriptorPool, 1, descriptorSet); + } - return descSets; - } - - void VulkanDescriptorPool::free(vk::DescriptorSet* descriptorSet) { - m_LogicalDevice.freeDescriptorSets(m_DescriptorPool, 1, descriptorSet); - m_CurrentlyAllocatedSets--; - } - - void VulkanDescriptorPool::free(const std::vector& descriptorSets) { - m_CurrentlyAllocatedSets -= descriptorSets.size(); - m_LogicalDevice.freeDescriptorSets(m_DescriptorPool, descriptorSets.size(), descriptorSets.data()); - } -} \ No newline at end of file + void VulkanDescriptorPool::free(const std::vector& descriptorSets) { + m_LogicalDevice.freeDescriptorSets(m_DescriptorPool, descriptorSets.size(), descriptorSets.data()); + } +} diff --git a/Eternal/src/core/graphics/vulkan/VulkanDescriptorPool.h b/Eternal/src/core/graphics/vulkan/VulkanDescriptorPool.h index c22f937..13ec070 100644 --- a/Eternal/src/core/graphics/vulkan/VulkanDescriptorPool.h +++ b/Eternal/src/core/graphics/vulkan/VulkanDescriptorPool.h @@ -1,61 +1,62 @@ -#pragma once +#pragma once -#include -#include -#include +#include "core/graphics/vulkan/VulkanUtils.h" +#include "core/graphics/vulkan/VulkanDescsriptorSetLayout.h" +#include "utils/Base.h" namespace Eternal { - - constexpr uint32_t MAX_DESCRIPTOR_POOL_SIZE = 100; - - class VulkanDescriptorPool { - public: - struct PoolSize { - vk::DescriptorType type; - uint32_t descriptorCount; - }; - - struct BuilderDetails { - vk::Device logicalDevice; - std::vector poolSizes; - uint32_t maxSets = MAX_DESCRIPTOR_POOL_SIZE; - }; - - class Builder : public utils::PrivateImplementation { - friend class VulkanDescriptorPool; - public: - Builder(vk::Device logicalDevice) noexcept; - Builder(Builder const& rhs) noexcept; - Builder(Builder&& rhs) noexcept; - ~Builder() noexcept; - Builder& operator=(Builder const& rhs) noexcept; - Builder& operator=(Builder&& rhs) noexcept; - Builder& addPoolSize(PoolSize poolSize); - Builder& setMaxSets(uint32_t maxSets) noexcept; - VulkanDescriptorPool* build() noexcept; - }; - - VulkanDescriptorPool(const Builder& builder); - VulkanDescriptorPool(const VulkanDescriptorPool&) = delete; - VulkanDescriptorPool& operator=(const VulkanDescriptorPool&) = delete; - ~VulkanDescriptorPool(); - - vk::DescriptorPool getDescriptorPool() const { return m_DescriptorPool; } - uint32_t getCurrentlyAllocatedSets() const { return m_CurrentlyAllocatedSets; } - void reset(); - vk::DescriptorSet allocate(const VulkanDescriptorSetLayout& descriptorSetLayout); - std::vector allocate(uint32_t descriptorSetCount, const VulkanDescriptorSetLayout& descriptorSetLayout); - - void free(vk::DescriptorSet* descriptorSet); - void free(const std::vector& descriptorSets); - - private: - vk::Device m_LogicalDevice; - vk::DescriptorPool m_DescriptorPool; - - std::vector m_PoolSizes; - - uint32_t m_CurrentlyAllocatedSets = 0; - uint32_t m_MaxSets; - }; -} \ No newline at end of file + constexpr uint32_t MAX_DESCRIPTOR_POOL_SIZE = 100; + + class VulkanDescriptorPool { + public: + struct PoolSize { + vk::DescriptorType type; + uint32_t descriptorCount; + }; + + struct BuilderDetails { + vk::Device logicalDevice; + std::vector poolSizes; + uint32_t maxSets = MAX_DESCRIPTOR_POOL_SIZE; + }; + + class Builder : public utils::PrivateImplementation { + friend class VulkanDescriptorPool; + + public: + Builder(vk::Device logicalDevice) noexcept; + Builder(Builder const& rhs) noexcept; + Builder(Builder&& rhs) noexcept; + ~Builder() noexcept; + Builder& operator=(Builder const& rhs) noexcept; + Builder& operator=(Builder&& rhs) noexcept; + Builder& addPoolSize(PoolSize poolSize); + Builder& setMaxSets(uint32_t maxSets) noexcept; + VulkanDescriptorPool* build() noexcept; + }; + + VulkanDescriptorPool(const Builder& builder); + VulkanDescriptorPool(const VulkanDescriptorPool&) = delete; + VulkanDescriptorPool& operator=(const VulkanDescriptorPool&) = delete; + ~VulkanDescriptorPool(); + + vk::DescriptorPool getDescriptorPool() const { return m_DescriptorPool; } + void reset(); + vk::DescriptorSet allocate(const VulkanDescriptorSetLayout& descriptorSetLayout); + std::vector allocate(uint32_t descriptorSetCount, + const VulkanDescriptorSetLayout& descriptorSetLayout); + + void free(vk::DescriptorSet* descriptorSet); + void free(const std::vector& descriptorSets); + + const std::vector& getPoolSizes() const { return m_PoolSizes; } + + private: + vk::Device m_LogicalDevice; + vk::DescriptorPool m_DescriptorPool; + + std::vector m_PoolSizes; + + uint32_t m_MaxSets; + }; +} diff --git a/Eternal/src/core/graphics/vulkan/VulkanDescsriptorSetLayout.cpp b/Eternal/src/core/graphics/vulkan/VulkanDescsriptorSetLayout.cpp index 61bbed6..ed9de92 100644 --- a/Eternal/src/core/graphics/vulkan/VulkanDescsriptorSetLayout.cpp +++ b/Eternal/src/core/graphics/vulkan/VulkanDescsriptorSetLayout.cpp @@ -1,4 +1,4 @@ -#include "VulkanDescsriptorSetLayout.h" +#include "core/graphics/vulkan/VulkanDescsriptorSetLayout.h" namespace Eternal { @@ -13,7 +13,7 @@ namespace Eternal { VulkanDescriptorSetLayout::Builder& VulkanDescriptorSetLayout::Builder::operator=(Builder&& rhs) noexcept = default; VulkanDescriptorSetLayout::Builder& VulkanDescriptorSetLayout::Builder::addBinding(LayoutInfo layoutInfo) { - ETERNAL_ASSERT(mImpl->bindings.count(layoutInfo.binding) == 0, "Binding is in use"); + ETERNAL_ASSERT(!mImpl->bindings.contains(layoutInfo.binding), "Binding is in use"); vk::DescriptorSetLayoutBinding binding = vk::DescriptorSetLayoutBinding() .setBinding(layoutInfo.binding) .setDescriptorType(layoutInfo.type) diff --git a/Eternal/src/core/graphics/vulkan/VulkanDescsriptorSetLayout.h b/Eternal/src/core/graphics/vulkan/VulkanDescsriptorSetLayout.h index 0489c00..bd1f076 100644 --- a/Eternal/src/core/graphics/vulkan/VulkanDescsriptorSetLayout.h +++ b/Eternal/src/core/graphics/vulkan/VulkanDescsriptorSetLayout.h @@ -1,50 +1,49 @@ #pragma once -#include -#include +#include "utils/Base.h" +#include "core/graphics/vulkan/VulkanUtils.h" namespace Eternal { - - using VulkanDesccriptorBinding = std::unordered_map; - - class VulkanDescriptorSetLayout { - public: - struct LayoutInfo { - uint32_t binding; - vk::DescriptorType type; - vk::ShaderStageFlags stageFlags; - uint32_t count = 1; - }; - - struct BuilderDetails { - vk::Device logicalDevice; - VulkanDesccriptorBinding bindings; - }; - - class Builder : public utils::PrivateImplementation { - friend class VulkanDescriptorSetLayout; - public: - Builder(vk::Device logicalDevice) noexcept; - Builder(Builder const& rhs) noexcept; - Builder(Builder&& rhs) noexcept; - ~Builder() noexcept; - Builder& operator=(Builder const& rhs) noexcept; - Builder& operator=(Builder&& rhs) noexcept; - Builder& addBinding(LayoutInfo layoutInfo); - VulkanDescriptorSetLayout* build() noexcept; - }; - - VulkanDescriptorSetLayout(const Builder& builder); - VulkanDescriptorSetLayout(const VulkanDescriptorSetLayout&) = delete; - VulkanDescriptorSetLayout& operator=(const VulkanDescriptorSetLayout&) = delete; - const vk::DescriptorSetLayout& getDescriptorSetLayout() const { return m_DescriptorSetLayout; } - const VulkanDesccriptorBinding& getBindings() const { return m_Binding; } - ~VulkanDescriptorSetLayout(); - - private: - vk::Device m_LogicalDevice; - VulkanDesccriptorBinding m_Binding; - vk::DescriptorSetLayout m_DescriptorSetLayout; - - }; -} \ No newline at end of file + class VulkanDescriptorSetLayout { + public: + using VulkanDescriptorBinding = std::unordered_map; + + struct LayoutInfo { + uint32_t binding; + vk::DescriptorType type; + vk::ShaderStageFlags stageFlags; + uint32_t count = 1; + }; + + struct BuilderDetails { + vk::Device logicalDevice; + VulkanDescriptorBinding bindings; + }; + + class Builder : public utils::PrivateImplementation { + friend class VulkanDescriptorSetLayout; + + public: + Builder(vk::Device logicalDevice) noexcept; + Builder(Builder const& rhs) noexcept; + Builder(Builder&& rhs) noexcept; + ~Builder() noexcept; + Builder& operator=(Builder const& rhs) noexcept; + Builder& operator=(Builder&& rhs) noexcept; + Builder& addBinding(LayoutInfo layoutInfo); + VulkanDescriptorSetLayout* build() noexcept; + }; + + VulkanDescriptorSetLayout(const Builder& builder); + VulkanDescriptorSetLayout(const VulkanDescriptorSetLayout&) = delete; + VulkanDescriptorSetLayout& operator=(const VulkanDescriptorSetLayout&) = delete; + const vk::DescriptorSetLayout& getDescriptorSetLayout() const { return m_DescriptorSetLayout; } + const VulkanDescriptorBinding& getBindings() const { return m_Binding; } + ~VulkanDescriptorSetLayout(); + + private: + vk::Device m_LogicalDevice; + VulkanDescriptorBinding m_Binding; + vk::DescriptorSetLayout m_DescriptorSetLayout; + }; +} diff --git a/Eternal/src/core/graphics/vulkan/VulkanFrameInfo.h b/Eternal/src/core/graphics/vulkan/VulkanFrameInfo.h index a7cb5cf..9e58371 100644 --- a/Eternal/src/core/graphics/vulkan/VulkanFrameInfo.h +++ b/Eternal/src/core/graphics/vulkan/VulkanFrameInfo.h @@ -1,24 +1,22 @@ #pragma once -#include #include +#include "core/graphics/FrameInfo.h" namespace Eternal { - class VulkanFrameInfo : public FrameInfo { - public: - VulkanFrameInfo(vk::CommandBuffer commandBuffer, uint32_t imageIndex) : - commandBuffer(commandBuffer), imageIndex(imageIndex) { + class VulkanFrameInfo : public FrameInfo { + public : + VulkanFrameInfo() = default; - } + VulkanFrameInfo(vk::CommandBuffer cmdBuffer, uint32_t imgIndex) { + this->imageIndex = imgIndex; + this->commandBuffer = cmdBuffer; + } - bool operator==(const VulkanFrameInfo& other) noexcept { - return this->commandBuffer == other.commandBuffer && this->imageIndex == other.imageIndex; - } + ~VulkanFrameInfo() override = default; - vk::CommandBuffer commandBuffer; - uint32_t imageIndex; - - }; + vk::CommandBuffer commandBuffer; + uint32_t imageIndex = INVALID_VK_INDEX; + }; } - diff --git a/Eternal/src/core/graphics/vulkan/VulkanGraphicsContext.h b/Eternal/src/core/graphics/vulkan/VulkanGraphicsContext.h index f40c06d..359c315 100644 --- a/Eternal/src/core/graphics/vulkan/VulkanGraphicsContext.h +++ b/Eternal/src/core/graphics/vulkan/VulkanGraphicsContext.h @@ -1,38 +1,35 @@ #pragma once -#include -#include -#include +#include "core/graphics/GraphicsContext.h" +#include "core/graphics/vulkan/VulkanSwapChain.h" #include namespace Eternal { - class VulkanGraphicsContext : public GraphicsContext - { - public: - VulkanGraphicsContext() = default; - ~VulkanGraphicsContext() = default; - vk::Instance getVkInstance() { return m_VkInstance; } - vk::PhysicalDevice getPhysicalDevice() { return m_PhysicalDevice; } - vk::Device getLogicalDevice() { return m_LogicalDevice; } - vk::Queue getGraphicsQueue() { return m_GraphicsQueue; } - uint32_t getGraphicsQueueFamilyIndex() { return m_GraphicsQueueFamilyIndex; } - uint32_t getGraphicsQueueIndex() { return m_GraphicsQueueIndex; } - vk::Queue getPresentQueue() { return m_PresentQueue; } - uint32_t getPresentQueueFamilyIndex() { return m_PresentQueueFamilyIndex; } - uint32_t getPresentQueueIndex() { return m_PresentQueueIndex; } + class VulkanGraphicsContext : public GraphicsContext { + public: + VulkanGraphicsContext() = default; + ~VulkanGraphicsContext() override = default; + vk::Instance getVkInstance() const { return m_VkInstance; } + vk::PhysicalDevice getPhysicalDevice() const { return m_PhysicalDevice; } + vk::Device getLogicalDevice() const { return m_LogicalDevice; } + vk::Queue getGraphicsQueue() const { return m_GraphicsQueue; } + uint32_t getGraphicsQueueFamilyIndex() const { return m_GraphicsQueueFamilyIndex; } + uint32_t getGraphicsQueueIndex() const { return m_GraphicsQueueIndex; } + vk::Queue getPresentQueue() const { return m_PresentQueue; } + uint32_t getPresentQueueFamilyIndex() const { return m_PresentQueueFamilyIndex; } + uint32_t getPresentQueueIndex() const { return m_PresentQueueIndex; } - protected: - vk::Instance m_VkInstance = nullptr; - vk::PhysicalDevice m_PhysicalDevice = nullptr; - vk::Device m_LogicalDevice = nullptr; - vk::SurfaceKHR m_Surface = nullptr; - vk::Queue m_GraphicsQueue = nullptr; - uint32_t m_GraphicsQueueFamilyIndex = INVALID_VK_INDEX; - uint32_t m_GraphicsQueueIndex = 0; - vk::Queue m_PresentQueue = nullptr; - uint32_t m_PresentQueueFamilyIndex = INVALID_VK_INDEX; - uint32_t m_PresentQueueIndex = 0; - - }; -} \ No newline at end of file + protected: + vk::Instance m_VkInstance = nullptr; + vk::PhysicalDevice m_PhysicalDevice = nullptr; + vk::Device m_LogicalDevice = nullptr; + vk::SurfaceKHR m_Surface = nullptr; + vk::Queue m_GraphicsQueue = nullptr; + uint32_t m_GraphicsQueueFamilyIndex = INVALID_VK_INDEX; + uint32_t m_GraphicsQueueIndex = 0; + vk::Queue m_PresentQueue = nullptr; + uint32_t m_PresentQueueFamilyIndex = INVALID_VK_INDEX; + uint32_t m_PresentQueueIndex = 0; + }; +} diff --git a/Eternal/src/core/graphics/vulkan/VulkanImGuiLayer.cpp b/Eternal/src/core/graphics/vulkan/VulkanImGuiLayer.cpp deleted file mode 100644 index e1082a7..0000000 --- a/Eternal/src/core/graphics/vulkan/VulkanImGuiLayer.cpp +++ /dev/null @@ -1,63 +0,0 @@ -#include "VulkanImGuiLayer.h" -#include "imgui/backends/imgui_impl_vulkan.h" -#include "imgui/backends/imgui_impl_glfw.h" - -namespace Eternal { - - VulkanImGuiLayer::VulkanImGuiLayer(VulkanPlatform* vulkanPlatform, VulkanSwapChain* swapChain, Window* window) - : m_VulkanPlatform(vulkanPlatform), - m_SwapChain(swapChain), m_Window(window) { - init(); - } - - VulkanImGuiLayer::VulkanImGuiLayer(VulkanRenderer* vulkanRenderer, Window* window) { - m_VulkanPlatform = vulkanRenderer->getPlatform(); - m_SwapChain = vulkanRenderer->getSwapChain(); - m_Window = window; - init(); - } - - void VulkanImGuiLayer::init() { - IMGUI_CHECKVERSION(); - ImGui::CreateContext(); - ImGui::StyleColorsDark(); - - ImGui_ImplVulkan_InitInfo initInfo{}; - initInfo.Instance = m_VulkanPlatform->getVkInstance(); - initInfo.PhysicalDevice = m_VulkanPlatform->getPhysicalDevice(); - initInfo.Device = m_VulkanPlatform->getLogicalDevice(); - initInfo.Queue = m_VulkanPlatform->getGraphicsQueue(); - initInfo.RenderPass = m_SwapChain->getRenderPass(); - initInfo.DescriptorPoolSize = 2; - initInfo.MinImageCount = 2; - initInfo.ImageCount = 2; - initInfo.MSAASamples = VK_SAMPLE_COUNT_1_BIT; - initInfo.Allocator = nullptr; - ImGui_ImplVulkan_Init(&initInfo); - - GLFWwindow* nativeWindow = static_cast(m_Window->getNativeWindow()); - ImGui_ImplGlfw_InitForVulkan(nativeWindow, true); - ImGui_ImplVulkan_CreateFontsTexture(); - } - - VulkanImGuiLayer::~VulkanImGuiLayer() { - vk::Device device = m_VulkanPlatform->getLogicalDevice(); - device.waitIdle(); - ImGui_ImplVulkan_Shutdown(); - ImGui_ImplGlfw_Shutdown(); - ImGui::DestroyContext(); - } - - void VulkanImGuiLayer::beginFrame() { - ImGui_ImplVulkan_NewFrame(); - ImGui_ImplGlfw_NewFrame(); - ImGui::NewFrame(); - } - - void VulkanImGuiLayer::render(FrameInfo* frameInfo) { - ImGui::Render(); - auto commandBuffer = static_cast(frameInfo)->commandBuffer; - ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), commandBuffer); - } -} - diff --git a/Eternal/src/core/graphics/vulkan/VulkanImGuiLayer.h b/Eternal/src/core/graphics/vulkan/VulkanImGuiLayer.h deleted file mode 100644 index fb9b520..0000000 --- a/Eternal/src/core/graphics/vulkan/VulkanImGuiLayer.h +++ /dev/null @@ -1,31 +0,0 @@ -#pragma once -#include -#include -#include -#include -#include -#include - -namespace Eternal { - class VulkanImGuiLayer : public ImGuiLayer { - public: - VulkanImGuiLayer(VulkanPlatform* vulkanPlatform, VulkanSwapChain* swapChain, Window* window); - - VulkanImGuiLayer(VulkanRenderer* vulkanRenderer, Window* window); - - ~VulkanImGuiLayer(); - - void beginFrame() override; - - void render(FrameInfo* frameInfo) override; - - private: - VulkanPlatform* m_VulkanPlatform = nullptr; - - VulkanSwapChain* m_SwapChain = nullptr; - - Window* m_Window = nullptr; - - void init(); - }; -} \ No newline at end of file diff --git a/Eternal/src/core/graphics/vulkan/VulkanImGuiOverlay.cpp b/Eternal/src/core/graphics/vulkan/VulkanImGuiOverlay.cpp new file mode 100644 index 0000000..9f9539b --- /dev/null +++ b/Eternal/src/core/graphics/vulkan/VulkanImGuiOverlay.cpp @@ -0,0 +1,64 @@ +#include "core/graphics/vulkan/VulkanImGuiOverlay.h" +#include "core/graphics/vulkan/VulkanFrameInfo.h" +#include "core/graphics/vulkan/VulkanRenderer.h" + +#include +#include + + +namespace Eternal { + VulkanImGuiOverlay::VulkanImGuiOverlay(const Builder& builder) { + m_VulkanPlatform = dynamic_cast(builder->platform); + m_VulkanRenderer = dynamic_cast(builder->renderer); + m_Window = builder->window; + + ETERNAL_ASSERT(m_VulkanPlatform != nullptr, "VulkanImGuiLayer :: VulkanPlatform is null"); + ETERNAL_ASSERT(m_VulkanRenderer != nullptr, "VulkanImGuiLayer :: Renderer is null"); + ETERNAL_ASSERT(m_Window != nullptr, "VulkanImGuiLayer :: Window is null"); + + init(); + } + + void VulkanImGuiOverlay::init() { + IMGUI_CHECKVERSION(); + ImGui::CreateContext(); + ImGui::StyleColorsDark(); + + ImGui_ImplVulkan_InitInfo initInfo{}; + initInfo.Instance = m_VulkanPlatform->getVkInstance(); + initInfo.PhysicalDevice = m_VulkanPlatform->getPhysicalDevice(); + initInfo.Device = m_VulkanPlatform->getLogicalDevice(); + initInfo.Queue = m_VulkanPlatform->getGraphicsQueue(); + initInfo.RenderPass = m_VulkanRenderer->getRenderPass(); + initInfo.DescriptorPoolSize = 2; + initInfo.MinImageCount = 2; + initInfo.ImageCount = 2; + initInfo.MSAASamples = VK_SAMPLE_COUNT_1_BIT; + initInfo.Allocator = nullptr; + ImGui_ImplVulkan_Init(&initInfo); + + GLFWwindow* nativeWindow = static_cast(m_Window->getNativeWindow()); + ImGui_ImplGlfw_InitForVulkan(nativeWindow, true); + ImGui_ImplVulkan_CreateFontsTexture(); + } + + VulkanImGuiOverlay::~VulkanImGuiOverlay() { + vk::Device device = m_VulkanPlatform->getLogicalDevice(); + device.waitIdle(); + ImGui_ImplVulkan_Shutdown(); + ImGui_ImplGlfw_Shutdown(); + ImGui::DestroyContext(); + } + + void VulkanImGuiOverlay::beginFrame() { + ImGui_ImplVulkan_NewFrame(); + ImGui_ImplGlfw_NewFrame(); + ImGui::NewFrame(); + } + + void VulkanImGuiOverlay::render(FrameInfo* frameInfo) { + ImGui::Render(); + auto commandBuffer = static_cast(frameInfo)->commandBuffer; + ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), commandBuffer); + } +} diff --git a/Eternal/src/core/graphics/vulkan/VulkanImGuiOverlay.h b/Eternal/src/core/graphics/vulkan/VulkanImGuiOverlay.h new file mode 100644 index 0000000..ce80a82 --- /dev/null +++ b/Eternal/src/core/graphics/vulkan/VulkanImGuiOverlay.h @@ -0,0 +1,24 @@ +#pragma once + +#include "core/graphics/vulkan/VulkanPlatform.h" +#include "core/graphics/vulkan/VulkanSwapChain.h" +#include "core/imgui/ImGuiOverlay.h" +#include "core/window/Window.h" + +namespace Eternal { + class VulkanImGuiOverlay : public ImGuiOverlay { + public: + VulkanImGuiOverlay(const Builder& builder); + ~VulkanImGuiOverlay() override; + + void beginFrame() override; + void render(FrameInfo* frameInfo) override; + + private: + VulkanPlatform* m_VulkanPlatform = nullptr; + VulkanRenderer* m_VulkanRenderer = nullptr; + Window* m_Window = nullptr; + + void init(); + }; +} diff --git a/Eternal/src/core/graphics/vulkan/VulkanIndexBuffer.cpp b/Eternal/src/core/graphics/vulkan/VulkanIndexBuffer.cpp new file mode 100644 index 0000000..d8f4d4a --- /dev/null +++ b/Eternal/src/core/graphics/vulkan/VulkanIndexBuffer.cpp @@ -0,0 +1,22 @@ +#include "core/graphics/vulkan/VulkanIndexBuffer.h" + +namespace Eternal { + VulkanIndexBuffer::VulkanIndexBuffer(VulkanPlatform* vulkanPlatform, const std::vector& indices) + : m_VulkanPlatform(vulkanPlatform) { + m_Buffer = std::make_unique(m_VulkanPlatform); + m_Buffer->create(indices.size(), sizeof(uint32_t), + vk::BufferUsageFlagBits::eVertexBuffer); + m_Buffer->allocate(m_BufferProperties); + m_Buffer->map(); + m_Buffer->write((void*) (indices.data())); + } + + VulkanIndexBuffer::~VulkanIndexBuffer() { + } + + void VulkanIndexBuffer::bind() { + } + + void VulkanIndexBuffer::unBind() { + } +} diff --git a/Eternal/src/core/graphics/vulkan/VulkanIndexBuffer.h b/Eternal/src/core/graphics/vulkan/VulkanIndexBuffer.h new file mode 100644 index 0000000..c3c9c6c --- /dev/null +++ b/Eternal/src/core/graphics/vulkan/VulkanIndexBuffer.h @@ -0,0 +1,23 @@ +#pragma once +#include "core/graphics/IndexBuffer.h" +#include "core/graphics/vulkan/VulkanBuffer.h" +#include "core/graphics/Vertex.h" +#include "core/graphics/vulkan/VulkanPlatform.h" + +namespace Eternal { + class VulkanIndexBuffer : public IndexBuffer { + public: + VulkanIndexBuffer(VulkanPlatform* vulkanPlatform, const std::vector& indices); + ~VulkanIndexBuffer() override; + void bind() override; + void unBind() override; + uint32_t getCount() override { return m_Buffer->getBufferSize(); }; + vk::Buffer* getVkBuffer() const { return m_Buffer->getVkBuffer(); } + + private : + std::unique_ptr m_Buffer; + vk::MemoryPropertyFlags m_BufferProperties = + vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent; + VulkanPlatform* m_VulkanPlatform; + }; +} diff --git a/Eternal/src/core/graphics/vulkan/VulkanPipeline.cpp b/Eternal/src/core/graphics/vulkan/VulkanPipeline.cpp index 04c1b46..2effa02 100644 --- a/Eternal/src/core/graphics/vulkan/VulkanPipeline.cpp +++ b/Eternal/src/core/graphics/vulkan/VulkanPipeline.cpp @@ -1,4 +1,4 @@ -#include "VulkanPipeline.h" +#include "core/graphics/vulkan/VulkanPipeline.h" namespace Eternal { VulkanPipeline::VulkanPipeline(vk::Device logicalDevice) @@ -120,12 +120,12 @@ namespace Eternal { auto [result, graphicsPipeline] = m_LogicalDevice.createGraphicsPipeline(VK_NULL_HANDLE, graphicsPipelineCreateInfo, nullptr); m_Pipeline = graphicsPipeline; } - catch (vk::SystemError err) { + catch (vk::SystemError& err) { Eternal::Logger::Error("Graphics Pipeline Exception : {}", err.what()); }; } - void VulkanPipeline::bind(vk::CommandBuffer commandBuffer) { + void VulkanPipeline::bind(vk::CommandBuffer commandBuffer) const { commandBuffer.bindPipeline(vk::PipelineBindPoint::eGraphics, m_Pipeline); } diff --git a/Eternal/src/core/graphics/vulkan/VulkanPipeline.h b/Eternal/src/core/graphics/vulkan/VulkanPipeline.h index 60d979a..523e89e 100644 --- a/Eternal/src/core/graphics/vulkan/VulkanPipeline.h +++ b/Eternal/src/core/graphics/vulkan/VulkanPipeline.h @@ -1,44 +1,42 @@ #pragma once -#include +#include "core/graphics/Vertex.h" -#include -#include +#include namespace Eternal { - - class VulkanPipeline { - public: - static constexpr uint32_t const SHADER_MODULE_COUNT = 2; - - struct PipelineCreationRequirements { - vk::PipelineCreateFlags flags = vk::PipelineCreateFlags(); - vk::PipelineBindPoint bindPoint = vk::PipelineBindPoint::eGraphics; - vk::PipelineLayout pipelineLayout = nullptr; - vk::RenderPass renderPass = nullptr; - vk::ShaderModule vertexShader = nullptr; - vk::ShaderModule fragmentShader = nullptr; - std::vector vertexInputBindingDescriptions = Eternal::Vertex::getBindingDescription(); - std::vector vertexInputAttributeDescriptions = Eternal::Vertex::getAttributeDescription(); - }; - - VulkanPipeline(vk::Device logicalDevice); - void bindLayout(vk::PipelineLayout pipelineLayout); - void bindRenderPass(vk::RenderPass renderPass); - void bindVertexShader(vk::ShaderModule vertexShader); - void bindFragmentShader(vk::ShaderModule fragmentShader); - void bindVertexBindingDescriptions(const std::vector& bindingDescriptions); - void bindVertexAttributeDescriptions(const std::vector& attributeDescriptions); - void create(); - void create(const PipelineCreationRequirements& pipelineCreationRequirements); - void bind(vk::CommandBuffer commandBuffer); - vk::Pipeline getPipeline() const { return m_Pipeline; } - ~VulkanPipeline(); - - private: - vk::Device m_LogicalDevice = nullptr; - vk::Pipeline m_Pipeline = nullptr; - PipelineCreationRequirements m_CreationRequirements; - }; - -} \ No newline at end of file + class VulkanPipeline { + public: + struct PipelineCreationRequirements { + vk::PipelineCreateFlags flags = vk::PipelineCreateFlags(); + vk::PipelineBindPoint bindPoint = vk::PipelineBindPoint::eGraphics; + vk::PipelineLayout pipelineLayout = nullptr; + vk::RenderPass renderPass = nullptr; + vk::ShaderModule vertexShader = nullptr; + vk::ShaderModule fragmentShader = nullptr; + std::vector vertexInputBindingDescriptions = + Eternal::Vertex::getBindingDescription(); + std::vector vertexInputAttributeDescriptions = + Eternal::Vertex::getAttributeDescription(); + }; + + VulkanPipeline(vk::Device logicalDevice); + void bindLayout(vk::PipelineLayout pipelineLayout); + void bindRenderPass(vk::RenderPass renderPass); + void bindVertexShader(vk::ShaderModule vertexShader); + void bindFragmentShader(vk::ShaderModule fragmentShader); + void bindVertexBindingDescriptions(const std::vector& bindingDescriptions); + void bindVertexAttributeDescriptions( + const std::vector& attributeDescriptions); + void create(); + void create(const PipelineCreationRequirements& pipelineCreationRequirements); + void bind(vk::CommandBuffer commandBuffer) const; + vk::Pipeline getPipeline() const { return m_Pipeline; } + ~VulkanPipeline(); + + private: + vk::Device m_LogicalDevice = nullptr; + vk::Pipeline m_Pipeline = nullptr; + PipelineCreationRequirements m_CreationRequirements; + }; +} diff --git a/Eternal/src/core/graphics/vulkan/VulkanPipelineCache.cpp b/Eternal/src/core/graphics/vulkan/VulkanPipelineCache.cpp new file mode 100644 index 0000000..d13b5cc --- /dev/null +++ b/Eternal/src/core/graphics/vulkan/VulkanPipelineCache.cpp @@ -0,0 +1,47 @@ +#include "core/graphics/vulkan/VulkanPipelineCache.h" +#include "core/graphics/vulkan/VulkanPipeline.h" +#include "core/scene/MaterialComponent.h" + +#include + +namespace Eternal { + VulkanPipelineCache::VulkanPipelineCache(VulkanPlatform* platform) : m_Platform(platform) { + } + + VulkanPipelineCache::~VulkanPipelineCache() { + m_PipelineCache.clear(); + } + + vk::Pipeline VulkanPipelineCache::getOrCreate(PipelineKey pipelineKey) { + if (m_PipelineCache.contains(pipelineKey)) { + return m_PipelineCache[pipelineKey]->getPipeline(); + } + + vk::Device logicalDevice = m_Platform->getLogicalDevice(); + bool isSamplerAttached = IS_BIT_SET(pipelineKey.pipelineLayoutMask, PipelineParams::SAMPLER); + bool hasMaterial = pipelineKey.material != nullptr; + std::string fragShader = hasMaterial ? "frag_texture_mapping.spv" : "common_fragment.spv"; + + std::string vertexShader = "common_vertex.spv"; + + vk::ShaderModule vertexShaderModule = m_Platform->loadShader( + logicalDevice, "res/shader/bin/" + vertexShader); + + vk::ShaderModule fragmentShaderModule = m_Platform->loadShader( + logicalDevice, "res/shader/bin/" + fragShader); + + vk::PipelineLayout pipelineLayout = pipelineKey.pipelineLayout; + vk::RenderPass renderPass = pipelineKey.renderPass; + + std::shared_ptr vulkanPipeline = std::make_shared(logicalDevice); + vulkanPipeline->bindLayout(pipelineLayout); + vulkanPipeline->bindRenderPass(renderPass); + vulkanPipeline->bindVertexShader(vertexShaderModule); + vulkanPipeline->bindFragmentShader(fragmentShaderModule); + vulkanPipeline->create(); + logicalDevice.destroyShaderModule(vertexShaderModule); + logicalDevice.destroyShaderModule(fragmentShaderModule); + auto [it , inserted] = m_PipelineCache.emplace(pipelineKey, vulkanPipeline); + return it->second->getPipeline(); + } +} diff --git a/Eternal/src/core/graphics/vulkan/VulkanPipelineCache.h b/Eternal/src/core/graphics/vulkan/VulkanPipelineCache.h new file mode 100644 index 0000000..dcab490 --- /dev/null +++ b/Eternal/src/core/graphics/vulkan/VulkanPipelineCache.h @@ -0,0 +1,43 @@ +#pragma once + +#include "core/graphics/vulkan/VulkanPipeline.h" +#include "core/graphics/vulkan/VulkanPlatform.h" +#include "core/scene/MaterialComponent.h" + +#include + +namespace Eternal { + struct PipelineKey { + uint32_t pipelineLayoutMask = 0; + vk::PipelineLayout pipelineLayout = nullptr; + vk::RenderPass renderPass = nullptr; + MaterialComponent* material = nullptr; + bool operator==(const PipelineKey& other) const = default; + }; + + struct PipelineKeyHasher { + std::size_t operator()(const Eternal::PipelineKey& key) const noexcept { + std::size_t seed = 0; + Eternal::hashCombine(seed, key.pipelineLayoutMask); + Eternal::hashCombine(seed, key.material); + Eternal::hashCombine(seed, static_cast(key.pipelineLayout)); + Eternal::hashCombine(seed, static_cast(key.renderPass)); + return seed; + } + }; + + + class VulkanPipelineCache { + public : + using PipelineContainer = std::unordered_map, PipelineKeyHasher>; + + VulkanPipelineCache(VulkanPlatform* platform); + ~VulkanPipelineCache(); + + vk::Pipeline getOrCreate(PipelineKey pipelineKey); + + private : + VulkanPlatform* m_Platform = nullptr; + PipelineContainer m_PipelineCache; + }; +} \ No newline at end of file diff --git a/Eternal/src/core/graphics/vulkan/VulkanPipelineLayoutCache.cpp b/Eternal/src/core/graphics/vulkan/VulkanPipelineLayoutCache.cpp new file mode 100644 index 0000000..4065872 --- /dev/null +++ b/Eternal/src/core/graphics/vulkan/VulkanPipelineLayoutCache.cpp @@ -0,0 +1,49 @@ +#include "core/graphics/vulkan/VulkanPipelineLayoutCache.h" +#include "core/scene/MaterialComponent.h" + +#include + +namespace Eternal { + VulkanPipelineLayoutCache::VulkanPipelineLayoutCache(VulkanDescriptorPool* descriptorPool, VulkanPlatform* platform) + : m_Platform(platform), m_DescriptorPool(descriptorPool) { + m_LogicalDevice = m_Platform->getLogicalDevice(); + m_UniformBufferDescriptorSetLayout = VulkanDescriptorSetLayout::Builder(m_LogicalDevice) + .addBinding({0, vk::DescriptorType::eUniformBuffer, vk::ShaderStageFlagBits::eVertex}) + .build(); + + m_MaterialDescriptorSetLayout = VulkanDescriptorSetLayout::Builder(m_LogicalDevice) + .addBinding({0, vk::DescriptorType::eCombinedImageSampler, vk::ShaderStageFlagBits::eFragment}) + .build(); + } + + VulkanPipelineLayoutCache::~VulkanPipelineLayoutCache() { + m_LogicalDevice.destroyDescriptorSetLayout(m_UniformBufferDescriptorSetLayout->getDescriptorSetLayout()); + m_LogicalDevice.destroyDescriptorSetLayout(m_MaterialDescriptorSetLayout->getDescriptorSetLayout()); + for (auto& pipelineLayout: m_PipelineLayoutCache | std::views::values) { + m_LogicalDevice.destroyPipelineLayout(pipelineLayout); + } + } + + vk::PipelineLayout VulkanPipelineLayoutCache::getOrCreatePipelineLayout( + PipelineLayoutCacheKey pipelineLayoutCacheKey) { + if (m_PipelineLayoutCache.contains(pipelineLayoutCacheKey)) { + return m_PipelineLayoutCache[pipelineLayoutCacheKey]; + } + + std::vector setLayouts; + if (IS_BIT_SET(pipelineLayoutCacheKey.pipelineLayoutMask, PipelineParams::UBO)) { + setLayouts.emplace_back(m_UniformBufferDescriptorSetLayout->getDescriptorSetLayout()); + } + + if (IS_BIT_SET(pipelineLayoutCacheKey.pipelineLayoutMask, PipelineParams::SAMPLER)) { + setLayouts.emplace_back(m_MaterialDescriptorSetLayout->getDescriptorSetLayout()); + } + + vk::PipelineLayoutCreateInfo pipelineLayoutCreateInfo = vk::PipelineLayoutCreateInfo() + .setSetLayouts(setLayouts); + + vk::PipelineLayout pipelineLayout = m_LogicalDevice.createPipelineLayout(pipelineLayoutCreateInfo); + m_PipelineLayoutCache.emplace(pipelineLayoutCacheKey, pipelineLayout); + return pipelineLayout; + } +} diff --git a/Eternal/src/core/graphics/vulkan/VulkanPipelineLayoutCache.h b/Eternal/src/core/graphics/vulkan/VulkanPipelineLayoutCache.h new file mode 100644 index 0000000..505ced0 --- /dev/null +++ b/Eternal/src/core/graphics/vulkan/VulkanPipelineLayoutCache.h @@ -0,0 +1,41 @@ +#pragma once + +#include "core/graphics/vulkan/VulkanDescriptorPool.h" +#include "core/graphics/vulkan/VulkanPlatform.h" + +namespace Eternal { + struct PipelineLayoutCacheKey { + uint32_t pipelineLayoutMask = 0; + bool operator==(const PipelineLayoutCacheKey& other) const = default; + }; + + struct PipelineLayoutCacheKeyHasher { + std::size_t operator()(const Eternal::PipelineLayoutCacheKey& key) const noexcept { + std::size_t seed = 0; + Eternal::hashCombine(seed, key.pipelineLayoutMask); + return seed; + } + }; + + class VulkanPipelineLayoutCache { + public: + using PipelineLayoutContainer = std::unordered_map; + VulkanPipelineLayoutCache(VulkanDescriptorPool* descriptorPool, VulkanPlatform* platform); + + ~VulkanPipelineLayoutCache(); + + vk::PipelineLayout getOrCreatePipelineLayout(PipelineLayoutCacheKey pipelineLayoutCacheKey); + + VulkanDescriptorSetLayout* getUboDescriptorSetLayout() const { return m_UniformBufferDescriptorSetLayout; } + VulkanDescriptorSetLayout* getMaterialDescriptorSetLayout() const { return m_MaterialDescriptorSetLayout; } + + private : + VulkanPlatform* m_Platform = nullptr; + vk::Device m_LogicalDevice; + VulkanDescriptorPool* m_DescriptorPool = nullptr; + PipelineLayoutContainer m_PipelineLayoutCache; + VulkanDescriptorSetLayout* m_UniformBufferDescriptorSetLayout = nullptr; + VulkanDescriptorSetLayout* m_MaterialDescriptorSetLayout = nullptr; + }; +} diff --git a/Eternal/src/core/graphics/vulkan/VulkanPlatform.cpp b/Eternal/src/core/graphics/vulkan/VulkanPlatform.cpp index 11f7e44..f71f795 100644 --- a/Eternal/src/core/graphics/vulkan/VulkanPlatform.cpp +++ b/Eternal/src/core/graphics/vulkan/VulkanPlatform.cpp @@ -1,370 +1,369 @@ -#include "VulkanPlatform.h" -#include "VulkanConstants.h" - -#include -#include -#include -#include -#include +#include "core/graphics/vulkan/VulkanPlatform.h" +#include "core/graphics/vulkan/VulkanConstants.h" +#include "core/graphics/vulkan/VulkanWindow.h" +#include "core/resource/ResourceManager.h" +#include "core/resource/ShaderProgram.h" #include -#include namespace Eternal { + VulkanPlatform::VulkanPlatform(const Builder& builder) { + m_ApplicationName = builder->applicationName; - VulkanPlatform::VulkanPlatform(const Builder& builder) { - m_ApplicationName = builder->applicationName; - - VulkanPlatform::initialize(); - } + VulkanPlatform::initialize(); + } - VulkanPlatform::~VulkanPlatform() { - VulkanPlatform::shutDown(); - } + VulkanPlatform::~VulkanPlatform() { + VulkanPlatform::shutDown(); + } - void VulkanPlatform::initialize() { + void VulkanPlatform::initialize() { + m_VkInstance = createInstance(m_ApplicationName); + m_PhysicalDevice = choosePhysicalDevice(m_VkInstance); + } - m_VkInstance = createInstance(m_ApplicationName); - m_PhysicalDevice = choosePhysicalDevice(m_VkInstance); - } + vk::Instance VulkanPlatform::createInstance(const std::string& applicationName) { + uint32_t version = 0; + vkEnumerateInstanceVersion(&m_Version); - vk::Instance VulkanPlatform::createInstance(const std::string& applicationName) { - uint32_t version = 0; - vkEnumerateInstanceVersion(&version); + Eternal::Logger::Info("Vulkan Variant {}", VK_API_VERSION_VARIANT(m_Version)); + Eternal::Logger::Info("Vulkan Major {}", VK_API_VERSION_MAJOR(m_Version)); + Eternal::Logger::Info("Vulkan Minor {}", VK_API_VERSION_MINOR(m_Version)); + Eternal::Logger::Info("Vulkan Patch {}", VK_API_VERSION_PATCH(m_Version)); - Eternal::Logger::Info("Vulkan Variant {}", VK_API_VERSION_VARIANT(version)); - Eternal::Logger::Info("Vulkan Major {}", VK_API_VERSION_MAJOR(version)); - Eternal::Logger::Info("Vulkan Minor {}", VK_API_VERSION_MINOR(version)); - Eternal::Logger::Info("Vulkan Patch {}", VK_API_VERSION_PATCH(version)); + // Removing Patch + version = m_Version & ~(0xFFFU); - // Removing Patch - version &= ~(0xFFFU); + vk::ApplicationInfo applicationInfo = vk::ApplicationInfo() + .setPApplicationName(applicationName.c_str()) + .setPEngineName("Eternal") + .setApiVersion(version) + .setEngineVersion(version) + .setApplicationVersion(version); - vk::ApplicationInfo applicationInfo = vk::ApplicationInfo() - .setPApplicationName(applicationName.c_str()) - .setPEngineName("Eternal") - .setApiVersion(version) - .setEngineVersion(version) - .setApplicationVersion(version); + uint32_t extensionCount = 0; + VkStringArrayPtr glfwExtensions = glfwGetRequiredInstanceExtensions(&extensionCount); - uint32_t extensionCount = 0; - VkStringArrayPtr glfwExtensions = glfwGetRequiredInstanceExtensions(&extensionCount); + if (glfwExtensions == nullptr) { + Eternal::Logger::Error( + "vulkan glfwExtensions are null , probably before call glfwInit() function before createInstance()"); + return nullptr; + } - if (glfwExtensions == nullptr) { - Eternal::Logger::Error("vulkan glfwExtensions are null , probably before call glfwInit() function before createInstance()"); - return nullptr; - } + VkStringArray extensions(glfwExtensions, glfwExtensions + extensionCount); - VkStringArray extensions(glfwExtensions, glfwExtensions + extensionCount); + for (VkString extensionName: extensions) + Eternal::Logger::Info("extension = {}", extensionName); - for (VkString extensionName : extensions) - Eternal::Logger::Info("extension = {}", extensionName); - - VkStringArray layers; + VkStringArray layers; #if ETERNAL_FLAG_ENABLED(ETERNAL_VULKAN_DEBUG_VALIDATION) - layers.push_back("VK_LAYER_KHRONOS_validation"); -#endif - - if (!validateExtensions(extensions)) { - Eternal::Logger::Error("validation failed for extensions"); - return nullptr; - } + layers.push_back("VK_LAYER_KHRONOS_validation"); +#endif - if (!validateLayers(layers)) { - Eternal::Logger::Error("validation failed for layer"); - return nullptr; - } + if (!validateExtensions(extensions)) { + Eternal::Logger::Error("validation failed for extensions"); + return nullptr; + } - vk::InstanceCreateInfo createInfo = vk::InstanceCreateInfo() - .setFlags(vk::InstanceCreateFlags()) - .setPApplicationInfo(&applicationInfo) - .setPEnabledLayerNames(layers) - .setPEnabledExtensionNames(extensions); + if (!validateLayers(layers)) { + Eternal::Logger::Error("validation failed for layer"); + return nullptr; + } - return vk::createInstance(createInfo, nullptr); - } + vk::InstanceCreateInfo createInfo = vk::InstanceCreateInfo() + .setFlags(vk::InstanceCreateFlags()) + .setPApplicationInfo(&applicationInfo) + .setPEnabledLayerNames(layers) + .setPEnabledExtensionNames(extensions); - vk::PhysicalDevice VulkanPlatform::choosePhysicalDevice(vk::Instance& instance) { - std::vector availableDevices = instance.enumeratePhysicalDevices(); + return vk::createInstance(createInfo, nullptr); + } - for (vk::PhysicalDevice& device : availableDevices) { - if (checkDeviceIsSuitable(device) && device.getProperties().deviceType == vk::PhysicalDeviceType::eDiscreteGpu) { - Eternal::Logger::Info("************ Supported Device Properties ************"); - logDeviceProps(device); - return device; - } - } - - return nullptr; - } - - vk::Device VulkanPlatform::createLogicalDevice(vk::PhysicalDevice& device, uint32_t graphicsQueueFamilyIndex, uint32_t presentQueueFamilyIndex) { - vk::Device logicalDevice; - float queuePriority = 1.0f; - - VkStringArray deviceExtensions = { - VK_KHR_SWAPCHAIN_EXTENSION_NAME - }; - - std::vector uniqueQueueFamilyIndices; - uniqueQueueFamilyIndices.push_back(graphicsQueueFamilyIndex); - if (graphicsQueueFamilyIndex != presentQueueFamilyIndex) { - uniqueQueueFamilyIndices.push_back(presentQueueFamilyIndex); - } - - std::vector queueCreateInfos; - for (uint32_t queueFamilyIndex : uniqueQueueFamilyIndices) { - vk::DeviceQueueCreateInfo queueCreateInfo = vk::DeviceQueueCreateInfo() - .setFlags(vk::DeviceQueueCreateFlags()) - .setQueueFamilyIndex(queueFamilyIndex) - .setQueueCount(1) - .setPQueuePriorities(&queuePriority); - - queueCreateInfos.push_back(queueCreateInfo); - } - - vk::PhysicalDeviceFeatures deviceFeature = vk::PhysicalDeviceFeatures(); - deviceFeature.setSamplerAnisotropy(true); - - vk::DeviceCreateInfo deviceCreateInfo = vk::DeviceCreateInfo() - .setFlags(vk::DeviceCreateFlags()) - .setPEnabledExtensionNames(deviceExtensions) - .setQueueCreateInfos(queueCreateInfos) - .setPEnabledFeatures(&deviceFeature); - - logicalDevice = device.createDevice(deviceCreateInfo); - - return logicalDevice; - } - - void VulkanPlatform::shutDown() { - if (m_Surface) { - m_VkInstance.destroySurfaceKHR(m_Surface); - } - - m_VkInstance.destroy(); - } - - SwapChain* VulkanPlatform::createSwapChain(Window* window) { - VulkanWindow* vkWindow = dynamic_cast(window); - - if (!vkWindow) { - Eternal::Logger::Debug("Returning Null SwapChain, expecting VulkanWindow in createSwapChain(..)"); - return nullptr; - } - - m_Surface = vkWindow->createWindowSurface(m_VkInstance); - - vk::Extent2D fallbackExtent = vkWindow->getExtent(); - - m_PresentQueueFamilyIndex = identifyPresentQueueFamilyIndex(m_PhysicalDevice, m_Surface); - ETERNAL_ASSERT(m_PresentQueueFamilyIndex != INVALID_VK_INDEX, "Present Queue Family Index is Invalid"); - - m_GraphicsQueueFamilyIndex = identifyGraphicsQueueFamilyIndex(m_PhysicalDevice, vk::QueueFlagBits::eGraphics); - ETERNAL_ASSERT(m_GraphicsQueueFamilyIndex != INVALID_VK_INDEX, "Graphics Queue Family Index is Invalid"); - - m_LogicalDevice = createLogicalDevice(m_PhysicalDevice, m_GraphicsQueueFamilyIndex, m_PresentQueueFamilyIndex); - - m_PresentQueue = m_LogicalDevice.getQueue(m_PresentQueueFamilyIndex, m_PresentQueueIndex); - - m_GraphicsQueue = m_LogicalDevice.getQueue(m_GraphicsQueueFamilyIndex, m_GraphicsQueueIndex); - - return Memory::Allocate(m_VkInstance, m_LogicalDevice, m_PhysicalDevice, m_PresentQueue, m_Surface, fallbackExtent, m_GraphicsQueueFamilyIndex, m_PresentQueueFamilyIndex); - } - - vk::ShaderModule VulkanPlatform::loadShader(const vk::Device& logicalDevice, const std::filesystem::path& path) { - ShaderProgram* shader = ResourceManager::get().loadResource(path.string()); - - vk::ShaderModuleCreateInfo shaderModuleCreateInfo = vk::ShaderModuleCreateInfo() - .setCodeSize(shader->getBlobSize()) - .setPCode(shader->getBlob()); - - vk::ShaderModule shaderModule; - shaderModule = logicalDevice.createShaderModule(shaderModuleCreateInfo); - return shaderModule; - } - - uint32_t VulkanPlatform::identifyGraphicsQueueFamilyIndex(vk::PhysicalDevice& device, vk::QueueFlags flags) { - uint32_t graphicsQueueFamilyIndex = INVALID_VK_INDEX; - std::vector queueFamiliesProperties = device.getQueueFamilyProperties(); - for (uint32_t i = 0; i < queueFamiliesProperties.size(); i++) { - vk::QueueFamilyProperties props = queueFamiliesProperties[i]; - if (props.queueCount != 0 && props.queueFlags & flags) { - graphicsQueueFamilyIndex = i; - break; - } - } - return graphicsQueueFamilyIndex; - } - - uint32_t VulkanPlatform::identifyPresentQueueFamilyIndex(vk::PhysicalDevice& device, vk::SurfaceKHR& surface) { - uint32_t presentQueueFamilyIndex = INVALID_VK_INDEX; - std::vector queueFamiliesProperties = device.getQueueFamilyProperties(); - for (uint32_t i = 0; i < queueFamiliesProperties.size(); i++) { - if (device.getSurfaceSupportKHR(i, surface)) { - presentQueueFamilyIndex = i; - break; - } - } - return presentQueueFamilyIndex; - } - - uint32_t VulkanPlatform::getMemoryType(vk::PhysicalDevice physicalDevice, vk::MemoryPropertyFlags properties, uint32_t typeBits) { - vk::PhysicalDeviceMemoryProperties prop = physicalDevice.getMemoryProperties(); - for (uint32_t i = 0; i < prop.memoryTypeCount; i++) - if ((prop.memoryTypes[i].propertyFlags & properties) == properties && typeBits & (1 << i)) - return i; - return 0xFFFFFFFF; - } - - bool VulkanPlatform::validateExtensions(VkStringArray extensions) - { - std::vector supportedExtensions = vk::enumerateInstanceExtensionProperties(); - - for (VkString extension : extensions) { - auto it = std::find_if(supportedExtensions.begin(), supportedExtensions.end(), - [&](const vk::ExtensionProperties& supportedExtension) { - return strcmp(extension, supportedExtension.extensionName) == 0; - }); - - if (it != supportedExtensions.end()) { - Eternal::Logger::Debug("{} Extension Supported", extension); - } - else { - Eternal::Logger::Error("{} Extension Not Supported", extension); - return false; - } - } - - return true; - } - - bool VulkanPlatform::validateLayers(VkStringArray layers) { - std::vector supportedLayers = vk::enumerateInstanceLayerProperties(); - - for (VkString layer : layers) { - auto it = std::find_if(supportedLayers.begin(), supportedLayers.end(), - [&](const vk::LayerProperties& supportedLayer) { - return strcmp(layer, supportedLayer.layerName) == 0; - }); - - if (it != supportedLayers.end()) { - Eternal::Logger::Debug("{} Layer Supported", layer); - } - else { - Eternal::Logger::Error("{} Layer Not Supported", layer); - return false; - } - } - - return true; - } - - bool VulkanPlatform::checkDeviceExtensionSupport(const vk::PhysicalDevice& device, const VkStringArray requestedExtensions) { - std::set requiredExtesnions(requestedExtensions.begin(), requestedExtensions.end()); - - for (vk::ExtensionProperties& extensionProperty : device.enumerateDeviceExtensionProperties()) { - requiredExtesnions.erase(extensionProperty.extensionName); - } - - return requiredExtesnions.empty(); - } - - bool VulkanPlatform::checkDeviceIsSuitable(const vk::PhysicalDevice& device) { - VkStringArray requestedExtensions = { - VK_KHR_SWAPCHAIN_EXTENSION_NAME - }; - - bool isExtensionsSupported = checkDeviceExtensionSupport(device, requestedExtensions); - return isExtensionsSupported; - } - - void VulkanPlatform::logDeviceProps(const vk::PhysicalDevice& device) { - vk::PhysicalDeviceProperties properties = device.getProperties(); - - Eternal::Logger::Debug("Device Name : {}", properties.deviceName.data()); - - std::string deviceType = ""; - switch (properties.deviceType) { - - case (vk::PhysicalDeviceType::eCpu): - deviceType = "CPU"; - break; - - case (vk::PhysicalDeviceType::eDiscreteGpu): - deviceType = "Discrete GPU"; - break; - - case (vk::PhysicalDeviceType::eIntegratedGpu): - deviceType = "Integrated GPU"; - break; - - case (vk::PhysicalDeviceType::eVirtualGpu): - deviceType = "Virtual GPU"; - break; - - default: - deviceType = "Other"; - break; - } - Eternal::Logger::Debug("Device Type : {}", deviceType); - } - - vk::CommandPool VulkanPlatform::createCommandPool(vk::CommandPoolCreateFlags commandPoolCreateFlagBits) { - vk::CommandPoolCreateInfo commandPoolCreateInfo = vk::CommandPoolCreateInfo() - .setFlags(vk::CommandPoolCreateFlagBits::eResetCommandBuffer) - .setQueueFamilyIndex(m_GraphicsQueueIndex); - - return m_LogicalDevice.createCommandPool(commandPoolCreateInfo); - } - - std::vector VulkanPlatform::allocateCommandBuffers(vk::CommandPool commandPool, vk::CommandBufferLevel level, uint32_t count) { - vk::CommandBufferAllocateInfo commandBufferAllocateInfo = vk::CommandBufferAllocateInfo() - .setCommandPool(commandPool) - .setLevel(level) - .setCommandBufferCount(count); - - return m_LogicalDevice.allocateCommandBuffers(commandBufferAllocateInfo); - } - - vk::CommandBuffer VulkanPlatform::allocateCommandBuffer(vk::CommandPool commandPool, vk::CommandBufferLevel level) { - auto commandBuffer = allocateCommandBuffers(commandPool, level, 1); - return commandBuffer.front(); - } - - void VulkanPlatform::destroyCommandPool(vk::CommandPool commandPool) { - m_LogicalDevice.destroyCommandPool(commandPool); - } - - vk::CommandBuffer VulkanPlatform::beginSingleCommand(vk::CommandPool commandPool) { - vk::CommandBufferAllocateInfo commandBufferAllocateInfo = vk::CommandBufferAllocateInfo() - .setCommandPool(commandPool) - .setLevel(vk::CommandBufferLevel::ePrimary) - .setCommandBufferCount(1); - - vk::CommandBuffer commandBuffer = m_LogicalDevice.allocateCommandBuffers(commandBufferAllocateInfo)[0]; - - vk::CommandBufferBeginInfo beginInfo = vk::CommandBufferBeginInfo() - .setFlags(vk::CommandBufferUsageFlagBits::eOneTimeSubmit) - .setPInheritanceInfo(nullptr); - - commandBuffer.begin(beginInfo); - return commandBuffer; - } - - void VulkanPlatform::endSingleCommand(vk::CommandPool commandPool, vk::CommandBuffer commandBuffer, vk::Queue queue) { - commandBuffer.end(); - vk::SubmitInfo submitInfo = vk::SubmitInfo() - .setCommandBuffers(commandBuffer); + vk::PhysicalDevice VulkanPlatform::choosePhysicalDevice(const vk::Instance& instance) { + std::vector availableDevices = instance.enumeratePhysicalDevices(); - queue.submit(submitInfo, nullptr); - queue.waitIdle(); - m_LogicalDevice.freeCommandBuffers(commandPool, commandBuffer); - } - - void VulkanPlatform::executeOneCommand(vk::CommandPool commandPool, vk::Queue queue, const std::function& function) { - vk::CommandBuffer commandBuffer = beginSingleCommand(commandPool); - function(commandBuffer); - endSingleCommand(commandPool, commandBuffer, queue); - } + for (vk::PhysicalDevice& device: availableDevices) { + if (checkDeviceIsSuitable(device) && device.getProperties().deviceType == + vk::PhysicalDeviceType::eDiscreteGpu) { + Eternal::Logger::Info("************ Supported Device Properties ************"); + logDeviceProps(device); + return device; + } + } + + return nullptr; + } + + vk::Device VulkanPlatform::createLogicalDevice(vk::PhysicalDevice& device, uint32_t graphicsQueueFamilyIndex, + uint32_t presentQueueFamilyIndex) { + vk::Device logicalDevice; + float queuePriority = 1.0f; + + VkStringArray deviceExtensions = { + VK_KHR_SWAPCHAIN_EXTENSION_NAME + }; + + std::vector uniqueQueueFamilyIndices; + uniqueQueueFamilyIndices.push_back(graphicsQueueFamilyIndex); + if (graphicsQueueFamilyIndex != presentQueueFamilyIndex) { + uniqueQueueFamilyIndices.push_back(presentQueueFamilyIndex); + } + + std::vector queueCreateInfos; + for (uint32_t queueFamilyIndex: uniqueQueueFamilyIndices) { + vk::DeviceQueueCreateInfo queueCreateInfo = vk::DeviceQueueCreateInfo() + .setFlags(vk::DeviceQueueCreateFlags()) + .setQueueFamilyIndex(queueFamilyIndex) + .setQueueCount(1) + .setPQueuePriorities(&queuePriority); + + queueCreateInfos.push_back(queueCreateInfo); + } + + vk::PhysicalDeviceFeatures deviceFeature = vk::PhysicalDeviceFeatures(); + deviceFeature.setSamplerAnisotropy(true); + + vk::DeviceCreateInfo deviceCreateInfo = vk::DeviceCreateInfo() + .setFlags(vk::DeviceCreateFlags()) + .setPEnabledExtensionNames(deviceExtensions) + .setQueueCreateInfos(queueCreateInfos) + .setPEnabledFeatures(&deviceFeature); + + logicalDevice = device.createDevice(deviceCreateInfo); + + return logicalDevice; + } + + void VulkanPlatform::shutDown() { + if (m_Surface) { + m_VkInstance.destroySurfaceKHR(m_Surface); + } + + m_VkInstance.destroy(); + } + + SwapChain* VulkanPlatform::createSwapChain(Window* window) { + VulkanWindow* vkWindow = dynamic_cast(window); + + if (!vkWindow) { + Eternal::Logger::Debug("Returning Null SwapChain, expecting VulkanWindow in createSwapChain(..)"); + return nullptr; + } + + m_Surface = vkWindow->createWindowSurface(m_VkInstance); + + vk::Extent2D fallbackExtent = vkWindow->getExtent(); + + m_PresentQueueFamilyIndex = identifyPresentQueueFamilyIndex(m_PhysicalDevice, m_Surface); + ETERNAL_ASSERT(m_PresentQueueFamilyIndex != INVALID_VK_INDEX, "Present Queue Family Index is Invalid"); + + m_GraphicsQueueFamilyIndex = identifyGraphicsQueueFamilyIndex(m_PhysicalDevice, vk::QueueFlagBits::eGraphics); + ETERNAL_ASSERT(m_GraphicsQueueFamilyIndex != INVALID_VK_INDEX, "Graphics Queue Family Index is Invalid"); + + m_LogicalDevice = createLogicalDevice(m_PhysicalDevice, m_GraphicsQueueFamilyIndex, m_PresentQueueFamilyIndex); + + m_PresentQueue = m_LogicalDevice.getQueue(m_PresentQueueFamilyIndex, m_PresentQueueIndex); + + m_GraphicsQueue = m_LogicalDevice.getQueue(m_GraphicsQueueFamilyIndex, m_GraphicsQueueIndex); + + return Memory::Allocate(m_VkInstance, m_LogicalDevice, m_PhysicalDevice, m_PresentQueue, + m_Surface, fallbackExtent, m_GraphicsQueueFamilyIndex, + m_PresentQueueFamilyIndex); + } + + vk::ShaderModule VulkanPlatform::loadShader(const vk::Device& logicalDevice, const std::filesystem::path& path) { + ShaderProgram* shader = ResourceManager::get().loadResource(path.string()); + + vk::ShaderModuleCreateInfo shaderModuleCreateInfo = vk::ShaderModuleCreateInfo() + .setCodeSize(shader->getBlobSize()) + .setPCode(shader->getBlob()); + + vk::ShaderModule shaderModule = logicalDevice.createShaderModule(shaderModuleCreateInfo); + return shaderModule; + } + + uint32_t VulkanPlatform::identifyGraphicsQueueFamilyIndex(vk::PhysicalDevice& device, vk::QueueFlags flags) { + uint32_t graphicsQueueFamilyIndex = INVALID_VK_INDEX; + std::vector queueFamiliesProperties = device.getQueueFamilyProperties(); + for (uint32_t i = 0; i < queueFamiliesProperties.size(); i++) { + vk::QueueFamilyProperties props = queueFamiliesProperties[i]; + if (props.queueCount != 0 && props.queueFlags & flags) { + graphicsQueueFamilyIndex = i; + break; + } + } + return graphicsQueueFamilyIndex; + } + + uint32_t VulkanPlatform::identifyPresentQueueFamilyIndex(vk::PhysicalDevice& device, vk::SurfaceKHR& surface) { + uint32_t presentQueueFamilyIndex = INVALID_VK_INDEX; + std::vector queueFamiliesProperties = device.getQueueFamilyProperties(); + for (uint32_t i = 0; i < queueFamiliesProperties.size(); i++) { + if (device.getSurfaceSupportKHR(i, surface)) { + presentQueueFamilyIndex = i; + break; + } + } + return presentQueueFamilyIndex; + } + + uint32_t VulkanPlatform::getMemoryType(vk::PhysicalDevice physicalDevice, vk::MemoryPropertyFlags properties, + uint32_t typeBits) { + vk::PhysicalDeviceMemoryProperties prop = physicalDevice.getMemoryProperties(); + for (uint32_t i = 0; i < prop.memoryTypeCount; i++) + if ((prop.memoryTypes[i].propertyFlags & properties) == properties && typeBits & (1 << i)) + return i; + return 0xFFFFFFFF; + } + + bool VulkanPlatform::validateExtensions(VkStringArray extensions) { + std::vector supportedExtensions = vk::enumerateInstanceExtensionProperties(); + + for (VkString extension: extensions) { + auto it = std::find_if(supportedExtensions.begin(), supportedExtensions.end(), + [&](const vk::ExtensionProperties& supportedExtension) { + return strcmp(extension, supportedExtension.extensionName) == 0; + }); + + if (it != supportedExtensions.end()) { + Eternal::Logger::Debug("{} Extension Supported", extension); + } else { + Eternal::Logger::Error("{} Extension Not Supported", extension); + return false; + } + } + + return true; + } + + bool VulkanPlatform::validateLayers(VkStringArray layers) { + std::vector supportedLayers = vk::enumerateInstanceLayerProperties(); + + for (VkString layer: layers) { + auto it = std::find_if(supportedLayers.begin(), supportedLayers.end(), + [&](const vk::LayerProperties& supportedLayer) { + return strcmp(layer, supportedLayer.layerName) == 0; + }); + + if (it != supportedLayers.end()) { + Eternal::Logger::Debug("{} Layer Supported", layer); + } else { + Eternal::Logger::Error("{} Layer Not Supported", layer); + return false; + } + } + + return true; + } + + bool VulkanPlatform::checkDeviceExtensionSupport(const vk::PhysicalDevice& device, + const VkStringArray requestedExtensions) { + std::set requiredExtesnions(requestedExtensions.begin(), requestedExtensions.end()); + + for (vk::ExtensionProperties& extensionProperty: device.enumerateDeviceExtensionProperties()) { + requiredExtesnions.erase(extensionProperty.extensionName); + } + + return requiredExtesnions.empty(); + } + + bool VulkanPlatform::checkDeviceIsSuitable(const vk::PhysicalDevice& device) { + VkStringArray requestedExtensions = { + VK_KHR_SWAPCHAIN_EXTENSION_NAME + }; + + bool isExtensionsSupported = checkDeviceExtensionSupport(device, requestedExtensions); + return isExtensionsSupported; + } + + void VulkanPlatform::logDeviceProps(const vk::PhysicalDevice& device) { + vk::PhysicalDeviceProperties properties = device.getProperties(); + + Eternal::Logger::Debug("Device Name : {}", properties.deviceName.data()); + + std::string deviceType; + switch (properties.deviceType) { + case (vk::PhysicalDeviceType::eCpu): + deviceType = "CPU"; + break; + + case (vk::PhysicalDeviceType::eDiscreteGpu): + deviceType = "Discrete GPU"; + break; + + case (vk::PhysicalDeviceType::eIntegratedGpu): + deviceType = "Integrated GPU"; + break; + + case (vk::PhysicalDeviceType::eVirtualGpu): + deviceType = "Virtual GPU"; + break; + + default: + deviceType = "Other"; + break; + } + Eternal::Logger::Debug("Device Type : {}", deviceType); + } + + vk::CommandPool VulkanPlatform::createCommandPool(vk::CommandPoolCreateFlags commandPoolCreateFlagBits) { + vk::CommandPoolCreateInfo commandPoolCreateInfo = vk::CommandPoolCreateInfo() + .setFlags(vk::CommandPoolCreateFlagBits::eResetCommandBuffer) + .setQueueFamilyIndex(m_GraphicsQueueIndex); + + return m_LogicalDevice.createCommandPool(commandPoolCreateInfo); + } + + std::vector VulkanPlatform::allocateCommandBuffers( + vk::CommandPool commandPool, vk::CommandBufferLevel level, uint32_t count) { + vk::CommandBufferAllocateInfo commandBufferAllocateInfo = vk::CommandBufferAllocateInfo() + .setCommandPool(commandPool) + .setLevel(level) + .setCommandBufferCount(count); + + return m_LogicalDevice.allocateCommandBuffers(commandBufferAllocateInfo); + } + + vk::CommandBuffer VulkanPlatform::allocateCommandBuffer(vk::CommandPool commandPool, vk::CommandBufferLevel level) { + auto commandBuffer = allocateCommandBuffers(commandPool, level, 1); + return commandBuffer.front(); + } + + void VulkanPlatform::destroyCommandPool(vk::CommandPool commandPool) { + m_LogicalDevice.destroyCommandPool(commandPool); + } + + vk::CommandBuffer VulkanPlatform::beginSingleCommand(vk::CommandPool commandPool) { + vk::CommandBufferAllocateInfo commandBufferAllocateInfo = vk::CommandBufferAllocateInfo() + .setCommandPool(commandPool) + .setLevel(vk::CommandBufferLevel::ePrimary) + .setCommandBufferCount(1); + + vk::CommandBuffer commandBuffer = m_LogicalDevice.allocateCommandBuffers(commandBufferAllocateInfo)[0]; + + vk::CommandBufferBeginInfo beginInfo = vk::CommandBufferBeginInfo() + .setFlags(vk::CommandBufferUsageFlagBits::eOneTimeSubmit) + .setPInheritanceInfo(nullptr); + + commandBuffer.begin(beginInfo); + return commandBuffer; + } + + void VulkanPlatform::endSingleCommand(vk::CommandPool commandPool, vk::CommandBuffer commandBuffer, + vk::Queue queue) { + commandBuffer.end(); + vk::SubmitInfo submitInfo = vk::SubmitInfo() + .setCommandBuffers(commandBuffer); + + queue.submit(submitInfo, nullptr); + queue.waitIdle(); + m_LogicalDevice.freeCommandBuffers(commandPool, commandBuffer); + } + + void VulkanPlatform::executeOneCommand(vk::CommandPool commandPool, vk::Queue queue, + const std::function& function) { + vk::CommandBuffer commandBuffer = beginSingleCommand(commandPool); + function(commandBuffer); + endSingleCommand(commandPool, commandBuffer, queue); + } } diff --git a/Eternal/src/core/graphics/vulkan/VulkanPlatform.h b/Eternal/src/core/graphics/vulkan/VulkanPlatform.h index 7afc64d..3fa2d3e 100644 --- a/Eternal/src/core/graphics/vulkan/VulkanPlatform.h +++ b/Eternal/src/core/graphics/vulkan/VulkanPlatform.h @@ -2,66 +2,60 @@ #define GLM_ENABLE_EXPERIMENTAL -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include "utils/Base.h" +#include "core/graphics/vulkan/VulkanGraphicsContext.h" +#include "core/graphics/GraphicsPlatform.h" +#include "core/Camera.hpp" #include #include #include -#include -#include namespace Eternal { - - using VkStringArray = std::vector; - using VkString = const char*; - using VkStringArrayPtr = const char**; - - class VulkanPlatform : public GraphicsPlatform, public VulkanGraphicsContext { - public: - - struct PushConstants { - glm::mat4 transform{ 1.f }; - }; - - VulkanPlatform(const Builder& builder); - ~VulkanPlatform(); - void initialize() override; - void shutDown() override; - SwapChain* createSwapChain(Window* window) override; - vk::Instance createInstance(const std::string& applicationName); - vk::PhysicalDevice choosePhysicalDevice(vk::Instance& instance); - uint32_t identifyGraphicsQueueFamilyIndex(vk::PhysicalDevice& device, vk::QueueFlags flags); - uint32_t identifyPresentQueueFamilyIndex(vk::PhysicalDevice& device, vk::SurfaceKHR& surface); - vk::Device createLogicalDevice(vk::PhysicalDevice& device, uint32_t graphicsQueueFamilyIndex, uint32_t presentQueueFamilyIndex); - vk::ShaderModule loadShader(const vk::Device& logicalDevice, const std::filesystem::path& path); - bool validateExtensions(VkStringArray extensions); - bool validateLayers(VkStringArray layers); - bool checkDeviceExtensionSupport(const vk::PhysicalDevice& device, const VkStringArray requestedExtensions); - bool checkDeviceIsSuitable(const vk::PhysicalDevice& device); - void logDeviceProps(const vk::PhysicalDevice& device); - - vk::CommandPool createCommandPool(vk::CommandPoolCreateFlags commandPoolCreateFlagBits); - std::vector allocateCommandBuffers(vk::CommandPool commandPool, vk::CommandBufferLevel level, uint32_t count); - vk::CommandBuffer allocateCommandBuffer(vk::CommandPool commandPool, vk::CommandBufferLevel level); - void destroyCommandPool(vk::CommandPool commandPool); - - vk::CommandBuffer beginSingleCommand(vk::CommandPool commandPool); - void endSingleCommand(vk::CommandPool commandPool, vk::CommandBuffer commandBuffer, vk::Queue queue); - void executeOneCommand(vk::CommandPool commandPool, vk::Queue queue, const std::function& function); - - static uint32_t getMemoryType(vk::PhysicalDevice physicalDevice, vk::MemoryPropertyFlags properties, uint32_t typeBits); - - private: - std::string m_ApplicationName; - Timer timer; - }; -} \ No newline at end of file + using VkStringArray = std::vector; + using VkString = const char*; + using VkStringArrayPtr = const char**; + + class VulkanPlatform : public GraphicsPlatform, public VulkanGraphicsContext { + public: + struct PushConstants { + glm::mat4 transform{1.f}; + }; + + VulkanPlatform(const Builder& builder); + ~VulkanPlatform() override; + void initialize() override; + void shutDown() override; + SwapChain* createSwapChain(Window* window) override; + vk::Instance createInstance(const std::string& applicationName); + vk::PhysicalDevice choosePhysicalDevice(const vk::Instance& instance); + uint32_t identifyGraphicsQueueFamilyIndex(vk::PhysicalDevice& device, vk::QueueFlags flags); + uint32_t identifyPresentQueueFamilyIndex(vk::PhysicalDevice& device, vk::SurfaceKHR& surface); + vk::Device createLogicalDevice(vk::PhysicalDevice& device, uint32_t graphicsQueueFamilyIndex, + uint32_t presentQueueFamilyIndex); + vk::ShaderModule loadShader(const vk::Device& logicalDevice, const std::filesystem::path& path); + bool validateExtensions(VkStringArray extensions); + bool validateLayers(VkStringArray layers); + bool checkDeviceExtensionSupport(const vk::PhysicalDevice& device, const VkStringArray requestedExtensions); + bool checkDeviceIsSuitable(const vk::PhysicalDevice& device); + void logDeviceProps(const vk::PhysicalDevice& device); + + vk::CommandPool createCommandPool(vk::CommandPoolCreateFlags commandPoolCreateFlagBits); + std::vector allocateCommandBuffers(vk::CommandPool commandPool, vk::CommandBufferLevel level, + uint32_t count); + vk::CommandBuffer allocateCommandBuffer(vk::CommandPool commandPool, vk::CommandBufferLevel level); + void destroyCommandPool(vk::CommandPool commandPool); + + vk::CommandBuffer beginSingleCommand(vk::CommandPool commandPool); + void endSingleCommand(vk::CommandPool commandPool, vk::CommandBuffer commandBuffer, vk::Queue queue); + void executeOneCommand(vk::CommandPool commandPool, vk::Queue queue, + const std::function& function); + + static uint32_t getMemoryType(vk::PhysicalDevice physicalDevice, vk::MemoryPropertyFlags properties, + uint32_t typeBits); + + private: + std::string m_ApplicationName; + uint32_t m_Version = 0; + }; +} diff --git a/Eternal/src/core/graphics/vulkan/VulkanRenderer.cpp b/Eternal/src/core/graphics/vulkan/VulkanRenderer.cpp index 2530dce..9394387 100644 --- a/Eternal/src/core/graphics/vulkan/VulkanRenderer.cpp +++ b/Eternal/src/core/graphics/vulkan/VulkanRenderer.cpp @@ -1,13 +1,14 @@ -#include "VulkanRenderer.h" -#include "imgui/imgui.h" -#include "imgui/backends/imgui_impl_glfw.h" -#include "imgui/backends/imgui_impl_vulkan.h" - -#include -#include -#include -#include -#include +#include "core/graphics/vulkan/VulkanRenderer.h" + +#include "VulkanFrameInfo.h" +#include "core/graphics/vulkan/VulkanDescsriptorSetLayout.h" +#include "core/graphics/vulkan/VulkanDescriptorPool.h" +#include "core/graphics/vulkan/VulkanImGuiOverlay.h" +#include "core/graphics/vulkan/VulkanBufferManager.h" +#include "core/graphics/vulkan/VulkanPipelineCache.h" +#include "core/scene/Entity.h" +#include "core/scene/TransformComponent.h" +#include "core/scene/RenderComponent.h" namespace Eternal { VulkanRenderer::VulkanRenderer(const Builder& builder) { @@ -34,29 +35,36 @@ namespace Eternal { void VulkanRenderer::initialize() { bindScene(); - m_Camera = Memory::Allocate(); - float aspectRatio = m_Window->getAspectRatio(); - m_Camera->setPerspectiveProjection(glm::radians(50.f), aspectRatio, 0.1f, 1000.f); - auto swapchain = m_Platform->createSwapChain(m_Window); m_VulkanSwapChain = dynamic_cast(swapchain); + m_SwapChainDetails = m_VulkanSwapChain->getSwapChainDetails(); if (!m_VulkanSwapChain) { Eternal::Logger::Error("Failed to create Vulkan SwapChain"); return; } - m_RenderPass = m_VulkanSwapChain->getRenderPass(); - ETERNAL_ASSERT(m_RenderPass, "Render pass is null"); - m_LogicalDevice = m_Platform->getLogicalDevice(); m_PhysicalDevice = m_Platform->getPhysicalDevice(); - m_VulkanBufferManager = Memory::Allocate(m_LogicalDevice, m_PhysicalDevice, m_Scene); + m_VulkanBufferManager = Memory::Allocate(m_Platform, m_Scene); m_VulkanTextureManager = Memory::Allocate(m_Platform, m_Scene); - createPipeline(); + m_PipelineCache = Memory::Allocate(m_Platform); + + m_DescriptorPool = VulkanDescriptorPool::Builder(m_LogicalDevice) + .addPoolSize({vk::DescriptorType::eUniformBuffer, e_MaxEntities}) + .addPoolSize({vk::DescriptorType::eCombinedImageSampler, e_MaxEntities}) + .setMaxSets(e_MaxEntities) + .build(); + + m_PipelineLayoutCache = Memory::Allocate(m_DescriptorPool, m_Platform); + + createDepthImageView(); + createRenderPass(); + createFrameBuffers(); + initializeDescriptors(); createCommandPool(); createCommandBuffers(); createSemaphores(); @@ -80,10 +88,11 @@ namespace Eternal { m_Platform->destroyCommandPool(m_CommandPool); - Memory::Deallocate(m_VulkanPipeline); - - m_LogicalDevice.destroyPipelineLayout(m_PipelineLayout); - + Memory::Deallocate(m_PipelineLayoutCache); + Memory::Deallocate(m_PipelineCache); + destroyRenderPass(); + destroyDepthImageView(); + destroyFrameBuffers(); Memory::Deallocate(m_VulkanSwapChain); //m_UniformBuffers.clear(); @@ -91,9 +100,6 @@ namespace Eternal { m_UniformDescriptorSets.clear(); m_MaterialDescriptorSets.clear(); - Memory::Deallocate(m_UniformBufferDescriptorSetLayout); - Memory::Deallocate(m_MaterialDescriptorSetLayout); - Memory::Deallocate(m_DescriptorPool); Memory::Deallocate(m_VulkanTextureManager); @@ -101,91 +107,166 @@ namespace Eternal { Memory::Deallocate(m_VulkanBufferManager); m_LogicalDevice.destroy(); - - Memory::Deallocate(m_Platform); - - Memory::Deallocate(m_Camera); } void VulkanRenderer::bindScene() { m_Scene->onComponentAdded( - [this](Eternal::Entity entity, Eternal::RenderComponent& component) { + [this](Eternal::Entity& entity, Eternal::RenderComponent& component) { m_VulkanBufferManager->addBuffer(entity.getUUID(), component); }); m_Scene->onComponentAdded( - [this](Eternal::Entity entity, Eternal::TransformComponent& component) { + [this](Eternal::Entity& entity, Eternal::TransformComponent& component) { m_VulkanBufferManager->addUniformBuffer(entity.getUUID(), component); }); } - void VulkanRenderer::createPipeline() { - initializeDescriptors(); + void VulkanRenderer::updateUniformBuffers() { + } - vk::PushConstantRange pushConstantRange = vk::PushConstantRange() - .setOffset(0) - .setSize(sizeof(PushConstants)) - .setStageFlags(vk::ShaderStageFlagBits::eVertex | vk::ShaderStageFlagBits::eFragment); + void VulkanRenderer::destroyRenderPass() { + if (m_RenderPass) { + m_LogicalDevice.destroyRenderPass(m_RenderPass); + m_RenderPass = nullptr; + } + } - std::array setLayouts = { - m_UniformBufferDescriptorSetLayout->getDescriptorSetLayout(), - m_MaterialDescriptorSetLayout->getDescriptorSetLayout() - }; + void VulkanRenderer::destroyFrameBuffers() { + for (auto frameBuffer: m_FrameBuffers) { + m_LogicalDevice.destroyFramebuffer(frameBuffer); + } + m_FrameBuffers.clear(); + } - //vk::PipelineLayoutCreateInfo pipelineLayoutCreateInfo = vk::PipelineLayoutCreateInfo() - // .setSetLayoutCount(1) - // .setPSetLayouts(&(m_DescriptorSetLayout->getDescriptorSetLayout())) - // .setPushConstantRanges(pushConstantRange); + void VulkanRenderer::destroyDepthImageView() { + if (m_DepthImageView) { + m_LogicalDevice.destroyImageView(m_DepthImageView); + m_DepthImageView = nullptr; + } - vk::PipelineLayoutCreateInfo pipelineLayoutCreateInfo = vk::PipelineLayoutCreateInfo() - .setSetLayouts(setLayouts); + if (m_DepthImage) { + m_LogicalDevice.destroyImage(m_DepthImage); + m_DepthImage = nullptr; + } - m_PipelineLayout = m_LogicalDevice.createPipelineLayout(pipelineLayoutCreateInfo); + if (m_DepthImageMemory) { + m_LogicalDevice.freeMemory(m_DepthImageMemory); + m_DepthImageMemory = nullptr; + } + } - vk::ShaderModule vertexShaderModule = m_Platform->loadShader(m_LogicalDevice, "res/shader/bin/vert.spv"); - vk::ShaderModule fragmentShaderModule = m_Platform->loadShader(m_LogicalDevice, "res/shader/bin/frag.spv"); + void VulkanRenderer::createRenderPass() { + VulkanSwapChain::SwapChainDetails swapChainDetails = m_VulkanSwapChain->getSwapChainDetails(); + vk::AttachmentDescription colorAttachment = vk::AttachmentDescription() + .setFormat(swapChainDetails.surfaceFormat.format) + .setSamples(vk::SampleCountFlagBits::e1) + .setLoadOp(vk::AttachmentLoadOp::eClear) + .setStoreOp(vk::AttachmentStoreOp::eStore) + .setStencilLoadOp(vk::AttachmentLoadOp::eDontCare) + .setStencilStoreOp(vk::AttachmentStoreOp::eDontCare) + .setInitialLayout(vk::ImageLayout::eUndefined) + .setFinalLayout(vk::ImageLayout::ePresentSrcKHR); + + vk::AttachmentReference colorAttachmentReference = vk::AttachmentReference() + .setAttachment(0) + .setLayout(vk::ImageLayout::eColorAttachmentOptimal); + + vk::AttachmentDescription depthAttachment = vk::AttachmentDescription() + .setFormat(vk::Format::eD32Sfloat) + .setSamples(vk::SampleCountFlagBits::e1) + .setLoadOp(vk::AttachmentLoadOp::eClear) + .setStoreOp(vk::AttachmentStoreOp::eDontCare) + .setStencilLoadOp(vk::AttachmentLoadOp::eDontCare) + .setStencilStoreOp(vk::AttachmentStoreOp::eDontCare) + .setInitialLayout(vk::ImageLayout::eUndefined) + .setFinalLayout(vk::ImageLayout::eDepthStencilAttachmentOptimal); + + vk::AttachmentReference depthAttachmentReference = vk::AttachmentReference() + .setAttachment(1) + .setLayout(vk::ImageLayout::eDepthStencilAttachmentOptimal); + + vk::SubpassDescription subPass = vk::SubpassDescription() + .setColorAttachmentCount(1) + .setPColorAttachments(&colorAttachmentReference) + .setPDepthStencilAttachment(&depthAttachmentReference); + + std::array attachments = {colorAttachment, depthAttachment}; + + vk::RenderPassCreateInfo renderPassCreateInfo = vk::RenderPassCreateInfo() + .setAttachments(attachments) + .setSubpassCount(1) + .setPSubpasses(&subPass); + + m_RenderPass = m_LogicalDevice.createRenderPass(renderPassCreateInfo); + } - m_VulkanPipeline = Memory::Allocate(m_LogicalDevice); - m_VulkanPipeline->bindLayout(m_PipelineLayout); - m_VulkanPipeline->bindRenderPass(m_RenderPass); - m_VulkanPipeline->bindVertexShader(vertexShaderModule); - m_VulkanPipeline->bindFragmentShader(fragmentShaderModule); - m_VulkanPipeline->create(); + void VulkanRenderer::createDepthImageView() { + vk::ImageCreateInfo imageCreateInfo = vk::ImageCreateInfo() + .setImageType(vk::ImageType::e2D) + .setFormat(vk::Format::eD32Sfloat) + .setExtent({m_SwapChainDetails.extent.width, m_SwapChainDetails.extent.height, 1}) + .setMipLevels(1) + .setArrayLayers(1) + .setSamples(vk::SampleCountFlagBits::e1) + .setTiling(vk::ImageTiling::eOptimal) + .setUsage(vk::ImageUsageFlagBits::eDepthStencilAttachment); - m_LogicalDevice.destroyShaderModule(vertexShaderModule); - m_LogicalDevice.destroyShaderModule(fragmentShaderModule); - } + m_DepthImage = m_LogicalDevice.createImage(imageCreateInfo); - void VulkanRenderer::updateUniformBuffers() { - } + vk::MemoryRequirements memRequirements = m_LogicalDevice.getImageMemoryRequirements(m_DepthImage); + + uint32_t memoryTypeIndex = VulkanPlatform::getMemoryType( + m_PhysicalDevice, + vk::MemoryPropertyFlagBits::eDeviceLocal, + memRequirements.memoryTypeBits + ); + + ETERNAL_ASSERT(memoryTypeIndex != 0xFFFFFFFF, "Failed to find suitable memory type for depth image"); + + vk::MemoryAllocateInfo allocInfo = vk::MemoryAllocateInfo() + .setAllocationSize(memRequirements.size) + .setMemoryTypeIndex(memoryTypeIndex); + + m_DepthImageMemory = m_LogicalDevice.allocateMemory(allocInfo); + + m_LogicalDevice.bindImageMemory(m_DepthImage, m_DepthImageMemory, 0); - void VulkanRenderer::updateCamera() { - GLFWwindow* window = static_cast(m_Window->getNativeWindow()); - m_Camera->onUpdate(window); + vk::ImageViewCreateInfo imageViewCreateInfo = vk::ImageViewCreateInfo() + .setImage(m_DepthImage) + .setViewType(vk::ImageViewType::e2D) + .setFormat(vk::Format::eD32Sfloat) + .setSubresourceRange({vk::ImageAspectFlagBits::eDepth, 0, 1, 0, 1}); + + m_DepthImageView = m_LogicalDevice.createImageView(imageViewCreateInfo); } - void VulkanRenderer::initializeDescriptors() { - m_UniformBufferDescriptorSetLayout = VulkanDescriptorSetLayout::Builder(m_LogicalDevice) - .addBinding({0, vk::DescriptorType::eUniformBuffer, vk::ShaderStageFlagBits::eVertex}) - .build(); + void VulkanRenderer::createFrameBuffers() { + const std::vector& swapChainImages = m_VulkanSwapChain->getImageViews(); + m_FrameBuffers.resize(swapChainImages.size()); - m_MaterialDescriptorSetLayout = VulkanDescriptorSetLayout::Builder(m_LogicalDevice) - .addBinding({0, vk::DescriptorType::eCombinedImageSampler, vk::ShaderStageFlagBits::eFragment}) - .build(); + for (uint32_t i = 0; i < swapChainImages.size(); i++) { + vk::ImageView attachment[] = {swapChainImages[i], m_DepthImageView}; - m_DescriptorPool = VulkanDescriptorPool::Builder(m_LogicalDevice) - .addPoolSize({vk::DescriptorType::eUniformBuffer, e_MaxEntities}) - .addPoolSize({vk::DescriptorType::eCombinedImageSampler, e_MaxEntities}) - .setMaxSets(e_MaxEntities) - .build(); + vk::FramebufferCreateInfo frameBufferInfo = vk::FramebufferCreateInfo() + .setRenderPass(m_RenderPass) + .setAttachments(attachment) + .setWidth(m_SwapChainDetails.extent.width) + .setHeight(m_SwapChainDetails.extent.height) + .setLayers(1); + m_FrameBuffers[i] = m_LogicalDevice.createFramebuffer(frameBufferInfo); + } + } + + void VulkanRenderer::initializeDescriptors() { + auto uboDescriptorSetLayout = m_PipelineLayoutCache->getUboDescriptorSetLayout(); auto uniformBuffers = m_VulkanBufferManager->getUniformBuffers(); for (auto& [entityId, uniformBuffer]: uniformBuffers) { - vk::DescriptorSet descriptorSet = m_DescriptorPool->allocate(*m_UniformBufferDescriptorSetLayout); + vk::DescriptorSet descriptorSet = m_DescriptorPool->allocate(*uboDescriptorSetLayout); m_UniformDescriptorSets[entityId] = descriptorSet; vk::DescriptorBufferInfo bufferInfo = vk::DescriptorBufferInfo() - .setBuffer(*uniformBuffer->getBuffer()) + .setBuffer(*uniformBuffer->getVkBuffer()) .setOffset(0) .setRange(sizeof(VulkanBufferManager::UniformBuffer)); @@ -199,9 +280,10 @@ namespace Eternal { m_LogicalDevice.updateDescriptorSets(writeDescriptorSet, nullptr); } + auto materialDescriptorSetLayout = m_PipelineLayoutCache->getMaterialDescriptorSetLayout(); auto textures = m_VulkanTextureManager->getTextures(); for (auto& [entityId, texture]: textures) { - vk::DescriptorSet descriptorSet = m_DescriptorPool->allocate(*m_MaterialDescriptorSetLayout); + vk::DescriptorSet descriptorSet = m_DescriptorPool->allocate(*materialDescriptorSetLayout); m_MaterialDescriptorSets[entityId] = descriptorSet; vk::DescriptorImageInfo imageInfo = vk::DescriptorImageInfo() @@ -254,17 +336,19 @@ namespace Eternal { if (m_Window->isMinimized()) return; - m_Window->setWindowResized(false); m_VulkanSwapChain->setShouldRecreate(false); m_LogicalDevice.waitForFences(1, &m_InFlightFences[m_CurrentFrame], VK_TRUE, UINT16_MAX); m_LogicalDevice.resetFences(1, &m_InFlightFences[m_CurrentFrame]); m_VulkanSwapChain->recreate(); - m_RenderPass = m_VulkanSwapChain->getRenderPass(); - - float aspectRatio = m_Window->getAspectRatio(); - m_Camera->setPerspectiveProjection(glm::radians(50.f), aspectRatio, 0.1f, 1000.f); + m_SwapChainDetails = m_VulkanSwapChain->getSwapChainDetails(); + destroyRenderPass(); + destroyDepthImageView(); + destroyFrameBuffers(); + createDepthImageView(); + createRenderPass(); + createFrameBuffers(); } FrameInfo* VulkanRenderer::beginFrame() { @@ -273,7 +357,7 @@ namespace Eternal { m_VulkanSwapChain->acquire(m_ImageAvailableSemaphores[m_CurrentFrame], &m_CurrentImageIndex); - if (m_VulkanSwapChain->shouldRecreate() || m_Window->isResized()) { + if (m_VulkanSwapChain->shouldRecreate()) { handleWindowResize(); return nullptr; } @@ -285,72 +369,96 @@ namespace Eternal { m_CurrentCommandBuffer.reset(vk::CommandBufferResetFlagBits::eReleaseResources); beginRecording(m_CurrentCommandBuffer); - return Memory::Allocate(m_CurrentCommandBuffer, m_CurrentImageIndex); } - void VulkanRenderer::render() { - updateCamera(); + void VulkanRenderer::render(Eternal::Camera* camera) { + vk::CommandBuffer commandBuffer = m_CurrentCommandBuffer; VulkanSwapChain::SwapChainDetails swapChainDetails = m_VulkanSwapChain->getSwapChainDetails(); - for (auto [e, transform]: m_Scene->getAllEntityWith().each()) { + VulkanBufferManager::UniformBuffer sceneUbo; + sceneUbo.projection = camera->getProjection(); + sceneUbo.view = camera->getView(); + + vk::Viewport viewport = vk::Viewport() + .setX(0.0f) + .setY(0.0f) + .setWidth(static_cast(swapChainDetails.extent.width)) + .setHeight(static_cast(swapChainDetails.extent.height)) + .setMinDepth(0.0f) + .setMaxDepth(1.0f); + + commandBuffer.setViewport(0, 1, &viewport); + + vk::Rect2D scissor = vk::Rect2D() + .setOffset({0, 0}) + .setExtent(swapChainDetails.extent); + + commandBuffer.setScissor(0, 1, &scissor); + + for (const auto& [e, renderComponent]: m_Scene->getAllEntityWith().each()) { Eternal::Entity entity = Eternal::Entity(e, m_Scene); - VulkanBufferManager::UniformBuffer uniformBufferData; - uniformBufferData.projection = m_Camera->getProjection(); - uniformBufferData.view = m_Camera->getView(); - uniformBufferData.model = transform.mat4(); + auto transform = entity.getComponent(); + auto material = entity.tryGetComponent(); + sceneUbo.model = transform.mat4(); + + PipelineLayoutCacheKey pipelineLayoutKey = { + .pipelineLayoutMask = material != nullptr + ? material->getPipelineLayoutBitMask() + : eDefaultPipelineLayoutBitMask, + }; + + vk::PipelineLayout pipelineLayout; + pipelineLayout = m_PipelineLayoutCache->getOrCreatePipelineLayout(pipelineLayoutKey); + + PipelineKey pipelineKey = { + .pipelineLayoutMask = material != nullptr + ? material->getPipelineLayoutBitMask() + : eDefaultPipelineLayoutBitMask, + .pipelineLayout = pipelineLayout, + .renderPass = m_RenderPass, + .material = material, + }; + + vk::Pipeline pipeline = m_PipelineCache->getOrCreate(pipelineKey); + commandBuffer.bindPipeline(vk::PipelineBindPoint::eGraphics, pipeline); + std::shared_ptr uniformBuffer = m_VulkanBufferManager->getUniformBuffer(entity.getUUID()); if (uniformBuffer) { - uniformBuffer->write(&uniformBufferData); + uniformBuffer->write(&sceneUbo); } auto descriptorSet = m_UniformDescriptorSets[entity.getUUID()]; - m_CurrentCommandBuffer.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, m_PipelineLayout, 0, 1, - &descriptorSet, 0, nullptr); + commandBuffer.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, pipelineLayout, 0, 1, + &descriptorSet, 0, nullptr); - auto materialDescriptorSet = m_MaterialDescriptorSets[entity.getUUID()]; - m_CurrentCommandBuffer.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, m_PipelineLayout, 1, 1, - &materialDescriptorSet, 0, nullptr); - //m_CurrentCommandBuffer.pushConstants(m_PipelineLayout, vk::ShaderStageFlagBits::eVertex | vk::ShaderStageFlagBits::eFragment, 0, sizeof(PushConstants), &m_PushConstants); + if (material) { + auto materialDescriptorSet = m_MaterialDescriptorSets[entity.getUUID()]; + commandBuffer.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, pipelineLayout, 1, 1, + &materialDescriptorSet, 0, nullptr); + } std::shared_ptr vertexBuffer = m_VulkanBufferManager->getVertexBuffer(entity.getUUID()); if (vertexBuffer) { vk::DeviceSize offset = vk::DeviceSize(0); - m_CurrentCommandBuffer.bindVertexBuffers(0, 1, vertexBuffer->getBuffer(), &offset); + commandBuffer.bindVertexBuffers(0, 1, vertexBuffer->getVkBuffer(), &offset); } std::shared_ptr indexBuffer = m_VulkanBufferManager->getIndexBuffer(entity.getUUID()); if (indexBuffer) { - m_CurrentCommandBuffer.bindIndexBuffer(*(indexBuffer->getBuffer()), 0, vk::IndexType::eUint32); - } - - vk::Viewport viewport = vk::Viewport() - .setX(0.0f) - .setY(0.0f) - .setWidth((float) swapChainDetails.extent.width) - .setHeight((float) swapChainDetails.extent.height) - .setMinDepth(0.0f) - .setMaxDepth(1.0f); - - m_CurrentCommandBuffer.setViewport(0, 1, &viewport); - - vk::Rect2D scissor = vk::Rect2D() - .setOffset({0, 0}) - .setExtent(swapChainDetails.extent); - - m_CurrentCommandBuffer.setScissor(0, 1, &scissor); - - if (indexBuffer) { - m_CurrentCommandBuffer.drawIndexed(indexBuffer->getElementCount(), 1, 0, 0, 0); + commandBuffer.bindIndexBuffer(*(indexBuffer->getVkBuffer()), 0, vk::IndexType::eUint32); + commandBuffer.drawIndexed(indexBuffer->getElementCount(), 1, 0, 0, 0); } } } void VulkanRenderer::endFrame() { - endRecoding(m_CurrentCommandBuffer); + vk::CommandBuffer commandBuffer = m_CurrentCommandBuffer; + + endRecoding(commandBuffer); vk::PipelineStageFlags waitStages[] = {vk::PipelineStageFlagBits::eColorAttachmentOutput}; @@ -359,7 +467,7 @@ namespace Eternal { .setPWaitSemaphores(&m_ImageAvailableSemaphores[m_CurrentFrame]) .setPWaitDstStageMask(waitStages) .setCommandBufferCount(1) - .setPCommandBuffers(&m_CurrentCommandBuffer) + .setPCommandBuffers(&commandBuffer) .setSignalSemaphoreCount(1) .setPSignalSemaphores(&m_RenderFinishedSemaphores[m_CurrentFrame]); @@ -369,7 +477,7 @@ namespace Eternal { m_VulkanSwapChain->present(m_RenderFinishedSemaphores[m_CurrentFrame], m_CurrentImageIndex); - if (m_VulkanSwapChain->shouldRecreate() || m_Window->isResized()) { + if (m_VulkanSwapChain->shouldRecreate()) { handleWindowResize(); return; } @@ -396,13 +504,11 @@ namespace Eternal { vk::RenderPassBeginInfo renderPassBeginInfo = vk::RenderPassBeginInfo() .setRenderPass(m_RenderPass) - .setFramebuffer(m_VulkanSwapChain->getFrameBuffers()[m_CurrentImageIndex]) + .setFramebuffer(m_FrameBuffers[m_CurrentImageIndex]) .setRenderArea(renderArea) .setClearValues(clearValues); commandBuffer.beginRenderPass(renderPassBeginInfo, vk::SubpassContents::eInline); - - m_VulkanPipeline->bind(commandBuffer); } void VulkanRenderer::endRecoding(vk::CommandBuffer commandBuffer) { diff --git a/Eternal/src/core/graphics/vulkan/VulkanRenderer.h b/Eternal/src/core/graphics/vulkan/VulkanRenderer.h index fbbba9f..4c24e47 100644 --- a/Eternal/src/core/graphics/vulkan/VulkanRenderer.h +++ b/Eternal/src/core/graphics/vulkan/VulkanRenderer.h @@ -1,19 +1,18 @@ #pragma once -#include - -#include -#include - -#include "VulkanPlatform.h" -#include "VulkanFrameInfo.h" -#include "VulkanUtils.h" -#include "VulkanDescriptorPool.h" -#include "VulkanDescsriptorSetLayout.h" -#include "VulkanTextureManager.h" -#include "VulkanPipeline.h" +#include "utils/Base.h" +#include "core/graphics/Renderer.h" +#include "core/graphics/vulkan/VulkanBufferManager.h" +#include "core/graphics/vulkan/VulkanPlatform.h" +#include "core/graphics/vulkan/VulkanDescriptorPool.h" +#include "core/graphics/vulkan/VulkanTextureManager.h" +#include "core/graphics/vulkan/VulkanPipelineCache.h" +#include "core/graphics/vulkan/VulkanPipelineLayoutCache.h" +#include "core/scene/Scene.h" namespace Eternal { + class ImGuiOverlay; + constexpr uint32_t e_MaxEntities = 100; class VulkanRenderer : public Renderer { @@ -32,11 +31,13 @@ namespace Eternal { VulkanPlatform* getPlatform() const { return m_Platform; } - VulkanSwapChain* getSwapChain() const { return m_VulkanSwapChain; } + SwapChain* getSwapChain() const override { return m_VulkanSwapChain; } FrameInfo* beginFrame() override; - void render() override; + vk::RenderPass getRenderPass() const { return m_RenderPass; } + + void render(Eternal::Camera* camera) override; void endFrame() override; @@ -45,7 +46,11 @@ namespace Eternal { void bindScene(); - void createPipeline(); + void createRenderPass(); + + void createFrameBuffers(); + + void createDepthImageView(); void initializeDescriptors(); @@ -65,18 +70,30 @@ namespace Eternal { void updateUniformBuffers(); - void updateCamera(); + void destroyRenderPass(); + + void destroyFrameBuffers(); + + void destroyDepthImageView(); Scene* m_Scene = nullptr; VulkanPlatform* m_Platform = nullptr; VulkanSwapChain* m_VulkanSwapChain = nullptr; + VulkanSwapChain::SwapChainDetails m_SwapChainDetails = {}; vk::Viewport m_Viewport; vk::Rect2D m_Scissor; + vk::RenderPass m_RenderPass = nullptr; + + vk::Image m_DepthImage; + vk::DeviceMemory m_DepthImageMemory; + vk::ImageView m_DepthImageView; + + std::vector m_FrameBuffers; + Eternal::VulkanBufferManager* m_VulkanBufferManager = nullptr; Eternal::VulkanTextureManager* m_VulkanTextureManager = nullptr; - Eternal::Camera* m_Camera = nullptr; Eternal::Window* m_Window = nullptr; std::vector m_ImageAvailableSemaphores; @@ -94,16 +111,15 @@ namespace Eternal { vk::Device m_LogicalDevice = nullptr; vk::PhysicalDevice m_PhysicalDevice = nullptr; PushConstants m_PushConstants; - vk::PipelineLayout m_PipelineLayout = nullptr; - vk::RenderPass m_RenderPass = nullptr; - - VulkanPipeline* m_VulkanPipeline = nullptr; std::vector > m_UniformBuffers; VulkanDescriptorPool* m_DescriptorPool = nullptr; - VulkanDescriptorSetLayout* m_UniformBufferDescriptorSetLayout = nullptr; - VulkanDescriptorSetLayout* m_MaterialDescriptorSetLayout = nullptr; std::unordered_map m_UniformDescriptorSets; std::unordered_map m_MaterialDescriptorSets; + + Eternal::VulkanPipelineCache* m_PipelineCache = nullptr; + Eternal::VulkanPipelineLayoutCache* m_PipelineLayoutCache = nullptr; + vk::Pipeline* m_BoundPipeline = nullptr; + Eternal::Timer* m_Timer = nullptr; }; } diff --git a/Eternal/src/core/graphics/vulkan/VulkanSwapChain.cpp b/Eternal/src/core/graphics/vulkan/VulkanSwapChain.cpp index 5cba904..161931a 100644 --- a/Eternal/src/core/graphics/vulkan/VulkanSwapChain.cpp +++ b/Eternal/src/core/graphics/vulkan/VulkanSwapChain.cpp @@ -1,312 +1,211 @@ -#include "VulkanSwapChain.h" -#include +#include "core/graphics/vulkan/VulkanSwapChain.h" +#include "core/graphics/vulkan/VulkanPlatform.h" namespace Eternal { - VulkanSwapChain::VulkanSwapChain( - vk::Instance instance, - vk::Device logicalDevice, - vk::PhysicalDevice physicalDevice, - vk::Queue queue, - vk::SurfaceKHR surface, - vk::Extent2D extent, - uint32_t graphicsQueueFamilyIndex, - uint32_t presentQueueFamilyIndex - ) : m_VkInstance(instance), - m_LogicalDevice(logicalDevice), - m_PhysicalDevice(physicalDevice), - m_PresentQueue(queue), - m_Surface(surface), - m_FallBackExtent(extent), - m_GraphicsQueueFamilyIndex(graphicsQueueFamilyIndex), - m_PresentQueueFamilyIndex(presentQueueFamilyIndex) { - create(); - } - - VulkanSwapChain::~VulkanSwapChain() { - destroy(); - } - - vk::Result VulkanSwapChain::acquire(vk::Semaphore imageReadySemaphore, uint32_t* imageIndex) { - vk::Result result = m_LogicalDevice.acquireNextImageKHR(m_SwapChain, std::numeric_limits::max(), imageReadySemaphore, nullptr, imageIndex); - m_ShouldRecreate = result == vk::Result::eErrorOutOfDateKHR || result == vk::Result::eSuboptimalKHR; - return result; - } - - vk::Result VulkanSwapChain::present(vk::Semaphore renderFinishedSemaphore, uint32_t imageIndex) { - vk::PresentInfoKHR presentInfo = vk::PresentInfoKHR() - .setWaitSemaphoreCount(1) - .setPWaitSemaphores(&renderFinishedSemaphore) - .setSwapchainCount(1) - .setPSwapchains(&m_SwapChain) - .setPImageIndices(&imageIndex); - - vk::Result result = m_PresentQueue.presentKHR(&presentInfo); - m_ShouldRecreate = result == vk::Result::eErrorOutOfDateKHR || result == vk::Result::eSuboptimalKHR; - return result; - } - - void VulkanSwapChain::recreate() { - m_ShouldRecreate = false; - destroy(); - create(); - } - - void VulkanSwapChain::create() { - vk::SurfaceCapabilitiesKHR capabilities = m_PhysicalDevice.getSurfaceCapabilitiesKHR(m_Surface); - - vk::SurfaceFormatKHR format = selectSwapChainSurfaceFormat(); - - vk::PresentModeKHR presentMode = selectSwapChainPresentMode(); - Eternal::Logger::Debug("Selected Present Mode {}", vk::to_string(presentMode)); - - vk::Extent2D extent = selectSwapChainExtent(capabilities); - Eternal::Logger::Info("Selected Extent: {}x{}", extent.width, extent.height); - - m_SwapChainDetails.capabilities = capabilities; - m_SwapChainDetails.surfaceFormat = format; - m_SwapChainDetails.presentMode = presentMode; - m_SwapChainDetails.extent = extent; - - uint32_t swapChainImageCount = m_SwapChainDetails.capabilities.minImageCount; - if (m_SwapChainDetails.capabilities.maxImageCount > 0 && swapChainImageCount > m_SwapChainDetails.capabilities.maxImageCount) { - swapChainImageCount = m_SwapChainDetails.capabilities.maxImageCount; - } - - vk::SwapchainCreateInfoKHR swapChainCreateInfo = vk::SwapchainCreateInfoKHR() - .setSurface(m_Surface) - .setMinImageCount(swapChainImageCount) - .setImageFormat(m_SwapChainDetails.surfaceFormat.format) - .setImageColorSpace(m_SwapChainDetails.surfaceFormat.colorSpace) - .setImageExtent(m_SwapChainDetails.extent) - .setImageArrayLayers(1) - .setImageUsage(vk::ImageUsageFlagBits::eColorAttachment); - - std::vector queueFamilyIndices = { - m_GraphicsQueueFamilyIndex, - m_PresentQueueFamilyIndex - }; - - if (m_GraphicsQueueFamilyIndex != m_PresentQueueFamilyIndex) { - swapChainCreateInfo - .setImageSharingMode(vk::SharingMode::eConcurrent) - .setQueueFamilyIndexCount(2) - .setQueueFamilyIndices(queueFamilyIndices); - } - else { - swapChainCreateInfo - .setImageSharingMode(vk::SharingMode::eExclusive); - } - - swapChainCreateInfo - .setPreTransform(m_SwapChainDetails.capabilities.currentTransform) - .setCompositeAlpha(vk::CompositeAlphaFlagBitsKHR::eOpaque) - .setPresentMode(m_SwapChainDetails.presentMode) - .setClipped(VK_TRUE) - .setOldSwapchain(VK_NULL_HANDLE); - - m_SwapChain = m_LogicalDevice.createSwapchainKHR(swapChainCreateInfo); - - createImageViews(); - createDepthImageView(); - createRenderPass(); - createFrameBuffers(); - } - - void VulkanSwapChain::destroy() { - m_ShouldRecreate = false; - - m_LogicalDevice.waitIdle(); - - for (auto imageView : m_SwapChainImageViews) { - m_LogicalDevice.destroyImageView(imageView); - } - m_SwapChainImages.clear(); - - for (auto frameBuffer : m_SwapChainFrameBuffers) { - m_LogicalDevice.destroyFramebuffer(frameBuffer); - } - m_SwapChainFrameBuffers.clear(); - - if (m_DepthImageView) { - m_LogicalDevice.destroyImageView(m_DepthImageView); - m_DepthImageView = nullptr; - } - - if (m_DepthImage) { - m_LogicalDevice.destroyImage(m_DepthImage); - m_DepthImage = nullptr; - } - - if (m_DepthImageMemory) { - m_LogicalDevice.freeMemory(m_DepthImageMemory); - m_DepthImageMemory = nullptr; - } - - if (m_RenderPass) { - m_LogicalDevice.destroyRenderPass(m_RenderPass); - m_RenderPass = nullptr; - } - - if (m_SwapChain) { - m_LogicalDevice.destroySwapchainKHR(m_SwapChain); - m_SwapChain = nullptr; - } - } - - vk::SurfaceFormatKHR VulkanSwapChain::selectSwapChainSurfaceFormat() { - std::vector availableFormats = m_PhysicalDevice.getSurfaceFormatsKHR(m_Surface); - for (const vk::SurfaceFormatKHR& availableFormat : availableFormats) { - if (availableFormat.format == vk::Format::eB8G8R8A8Unorm && availableFormat.colorSpace == vk::ColorSpaceKHR::eSrgbNonlinear) { - return availableFormat; - } - } - - return availableFormats[0]; - } - - vk::PresentModeKHR VulkanSwapChain::selectSwapChainPresentMode() { - std::vector availablePresentModes = m_PhysicalDevice.getSurfacePresentModesKHR(m_Surface); - for (const auto& availablePresentMode : availablePresentModes) { - if (availablePresentMode == vk::PresentModeKHR::eMailbox) { - return availablePresentMode; - } - } - - return vk::PresentModeKHR::eFifo; - } - - vk::Extent2D VulkanSwapChain::selectSwapChainExtent(const vk::SurfaceCapabilitiesKHR& capabilities) { - if (capabilities.currentExtent.width != std::numeric_limits::max()) { - return capabilities.currentExtent; - } - else { - return m_FallBackExtent; - } - } - - void VulkanSwapChain::createImageViews() { - m_SwapChainImages = m_LogicalDevice.getSwapchainImagesKHR(m_SwapChain); - - m_SwapChainImageViews.resize(m_SwapChainImages.size()); - - for (uint32_t i = 0; i < m_SwapChainImages.size(); i++) { - vk::ImageSubresourceRange imageSubResourceRange = vk::ImageSubresourceRange() - .setAspectMask(vk::ImageAspectFlagBits::eColor) - .setBaseMipLevel(0) - .setLevelCount(1) - .setBaseArrayLayer(0) - .setLayerCount(1); - - vk::ImageViewCreateInfo imageViewCreateInfo = vk::ImageViewCreateInfo() - .setImage(m_SwapChainImages[i]) - .setViewType(vk::ImageViewType::e2D) - .setFormat(m_SwapChainDetails.surfaceFormat.format) - .setComponents(vk::ComponentMapping()) - .setSubresourceRange(imageSubResourceRange); - - m_SwapChainImageViews[i] = m_LogicalDevice.createImageView(imageViewCreateInfo); - } - } - - void VulkanSwapChain::createDepthImageView() { - vk::ImageCreateInfo imageCreateInfo = vk::ImageCreateInfo() - .setImageType(vk::ImageType::e2D) - .setFormat(vk::Format::eD32Sfloat) - .setExtent({ m_SwapChainDetails.extent.width, m_SwapChainDetails.extent.height, 1 }) - .setMipLevels(1) - .setArrayLayers(1) - .setSamples(vk::SampleCountFlagBits::e1) - .setTiling(vk::ImageTiling::eOptimal) - .setUsage(vk::ImageUsageFlagBits::eDepthStencilAttachment); - - m_DepthImage = m_LogicalDevice.createImage(imageCreateInfo); - - vk::MemoryRequirements memRequirements = m_LogicalDevice.getImageMemoryRequirements(m_DepthImage); - - uint32_t memoryTypeIndex = VulkanPlatform::getMemoryType( - m_PhysicalDevice, - vk::MemoryPropertyFlagBits::eDeviceLocal, - memRequirements.memoryTypeBits - ); - - ETERNAL_ASSERT(memoryTypeIndex != 0xFFFFFFFF, "Failed to find suitable memory type for depth image"); - - vk::MemoryAllocateInfo allocInfo = vk::MemoryAllocateInfo() - .setAllocationSize(memRequirements.size) - .setMemoryTypeIndex(memoryTypeIndex); - - m_DepthImageMemory = m_LogicalDevice.allocateMemory(allocInfo); - - m_LogicalDevice.bindImageMemory(m_DepthImage, m_DepthImageMemory, 0); - - vk::ImageViewCreateInfo imageViewCreateInfo = vk::ImageViewCreateInfo() - .setImage(m_DepthImage) - .setViewType(vk::ImageViewType::e2D) - .setFormat(vk::Format::eD32Sfloat) - .setSubresourceRange({ vk::ImageAspectFlagBits::eDepth,0, 1, 0, 1 }); - - m_DepthImageView = m_LogicalDevice.createImageView(imageViewCreateInfo); - } - - void VulkanSwapChain::createRenderPass() { - vk::AttachmentDescription colorAttachment = vk::AttachmentDescription() - .setFormat(m_SwapChainDetails.surfaceFormat.format) - .setSamples(vk::SampleCountFlagBits::e1) - .setLoadOp(vk::AttachmentLoadOp::eClear) - .setStoreOp(vk::AttachmentStoreOp::eStore) - .setStencilLoadOp(vk::AttachmentLoadOp::eDontCare) - .setStencilStoreOp(vk::AttachmentStoreOp::eDontCare) - .setInitialLayout(vk::ImageLayout::eUndefined) - .setFinalLayout(vk::ImageLayout::ePresentSrcKHR); - - vk::AttachmentReference colorAttachmentReference = vk::AttachmentReference() - .setAttachment(0) - .setLayout(vk::ImageLayout::eColorAttachmentOptimal); - - vk::AttachmentDescription depthAttachment = vk::AttachmentDescription() - .setFormat(vk::Format::eD32Sfloat) - .setSamples(vk::SampleCountFlagBits::e1) - .setLoadOp(vk::AttachmentLoadOp::eClear) - .setStoreOp(vk::AttachmentStoreOp::eDontCare) - .setStencilLoadOp(vk::AttachmentLoadOp::eDontCare) - .setStencilStoreOp(vk::AttachmentStoreOp::eDontCare) - .setInitialLayout(vk::ImageLayout::eUndefined) - .setFinalLayout(vk::ImageLayout::eDepthStencilAttachmentOptimal); - - vk::AttachmentReference depthAttachmentReference = vk::AttachmentReference() - .setAttachment(1) - .setLayout(vk::ImageLayout::eDepthStencilAttachmentOptimal); - - vk::SubpassDescription subPass = vk::SubpassDescription() - .setColorAttachmentCount(1) - .setPColorAttachments(&colorAttachmentReference) - .setPDepthStencilAttachment(&depthAttachmentReference); - - std::array attachments = { colorAttachment, depthAttachment }; - - vk::RenderPassCreateInfo renderPassCreateInfo = vk::RenderPassCreateInfo() - .setAttachments(attachments) - .setSubpassCount(1) - .setPSubpasses(&subPass); - - m_RenderPass = m_LogicalDevice.createRenderPass(renderPassCreateInfo); - } - - void VulkanSwapChain::createFrameBuffers() { - m_SwapChainFrameBuffers.resize(m_SwapChainImageViews.size()); - - for (uint32_t i = 0; i < m_SwapChainImageViews.size(); i++) - { - vk::ImageView attachment[] = { m_SwapChainImageViews[i] , m_DepthImageView }; - - vk::FramebufferCreateInfo frameBufferInfo = vk::FramebufferCreateInfo() - .setRenderPass(m_RenderPass) - .setAttachments(attachment) - .setWidth(m_SwapChainDetails.extent.width) - .setHeight(m_SwapChainDetails.extent.height) - .setLayers(1); - - m_SwapChainFrameBuffers[i] = m_LogicalDevice.createFramebuffer(frameBufferInfo); - } - } -} \ No newline at end of file + VulkanSwapChain::VulkanSwapChain( + vk::Instance instance, + vk::Device logicalDevice, + vk::PhysicalDevice physicalDevice, + vk::Queue queue, + vk::SurfaceKHR surface, + vk::Extent2D extent, + uint32_t graphicsQueueFamilyIndex, + uint32_t presentQueueFamilyIndex + ) : m_VkInstance(instance), + m_LogicalDevice(logicalDevice), + m_PhysicalDevice(physicalDevice), + m_PresentQueue(queue), + m_Surface(surface), + m_FallBackExtent(extent), + m_GraphicsQueueFamilyIndex(graphicsQueueFamilyIndex), + m_PresentQueueFamilyIndex(presentQueueFamilyIndex) { + create(); + } + + VulkanSwapChain::~VulkanSwapChain() { + destroy(); + } + + vk::Result VulkanSwapChain::acquire(vk::Semaphore imageReadySemaphore, uint32_t* imageIndex) { + vk::Result result = m_LogicalDevice.acquireNextImageKHR(m_SwapChain, std::numeric_limits::max(), + imageReadySemaphore, nullptr, imageIndex); + m_ShouldRecreate = result == vk::Result::eErrorOutOfDateKHR || result == vk::Result::eSuboptimalKHR; + return result; + } + + vk::Result VulkanSwapChain::present(vk::Semaphore renderFinishedSemaphore, uint32_t imageIndex) { + vk::PresentInfoKHR presentInfo = vk::PresentInfoKHR() + .setWaitSemaphoreCount(1) + .setPWaitSemaphores(&renderFinishedSemaphore) + .setSwapchainCount(1) + .setPSwapchains(&m_SwapChain) + .setPImageIndices(&imageIndex); + + vk::Result result = m_PresentQueue.presentKHR(&presentInfo); + m_ShouldRecreate = result == vk::Result::eErrorOutOfDateKHR || result == vk::Result::eSuboptimalKHR; + return result; + } + + void VulkanSwapChain::recreate() { + m_ShouldRecreate = false; + destroy(); + create(); + } + + void VulkanSwapChain::create() { + vk::SurfaceCapabilitiesKHR capabilities = m_PhysicalDevice.getSurfaceCapabilitiesKHR(m_Surface); + + vk::SurfaceFormatKHR format = selectSwapChainSurfaceFormat(); + + vk::PresentModeKHR presentMode = selectSwapChainPresentMode(); + Eternal::Logger::Debug("Selected Present Mode {}", vk::to_string(presentMode)); + + vk::Extent2D extent = selectSwapChainExtent(capabilities); + Eternal::Logger::Info("Selected Extent: {}x{}", extent.width, extent.height); + + m_SwapChainDetails.capabilities = capabilities; + m_SwapChainDetails.surfaceFormat = format; + m_SwapChainDetails.presentMode = presentMode; + m_SwapChainDetails.extent = extent; + + uint32_t swapChainImageCount = m_SwapChainDetails.capabilities.minImageCount; + if (m_SwapChainDetails.capabilities.maxImageCount > 0 && swapChainImageCount > m_SwapChainDetails.capabilities. + maxImageCount) { + swapChainImageCount = m_SwapChainDetails.capabilities.maxImageCount; + } + + vk::SwapchainCreateInfoKHR swapChainCreateInfo = vk::SwapchainCreateInfoKHR() + .setSurface(m_Surface) + .setMinImageCount(swapChainImageCount) + .setImageFormat(m_SwapChainDetails.surfaceFormat.format) + .setImageColorSpace(m_SwapChainDetails.surfaceFormat.colorSpace) + .setImageExtent(m_SwapChainDetails.extent) + .setImageArrayLayers(1) + .setImageUsage(vk::ImageUsageFlagBits::eColorAttachment); + + std::vector queueFamilyIndices = { + m_GraphicsQueueFamilyIndex, + m_PresentQueueFamilyIndex + }; + + if (m_GraphicsQueueFamilyIndex != m_PresentQueueFamilyIndex) { + swapChainCreateInfo + .setImageSharingMode(vk::SharingMode::eConcurrent) + .setQueueFamilyIndexCount(2) + .setQueueFamilyIndices(queueFamilyIndices); + } else { + swapChainCreateInfo + .setImageSharingMode(vk::SharingMode::eExclusive); + } + + swapChainCreateInfo + .setPreTransform(m_SwapChainDetails.capabilities.currentTransform) + .setCompositeAlpha(vk::CompositeAlphaFlagBitsKHR::eOpaque) + .setPresentMode(m_SwapChainDetails.presentMode) + .setClipped(VK_TRUE) + .setOldSwapchain(VK_NULL_HANDLE); + + m_SwapChain = m_LogicalDevice.createSwapchainKHR(swapChainCreateInfo); + + createImageViews(); + // createDepthImageView(); + // createRenderPass(); + // createFrameBuffers(); + } + + void VulkanSwapChain::destroy() { + m_ShouldRecreate = false; + + m_LogicalDevice.waitIdle(); + + for (auto imageView: m_SwapChainImageViews) { + m_LogicalDevice.destroyImageView(imageView); + } + m_SwapChainImages.clear(); + + // for (auto frameBuffer: m_SwapChainFrameBuffers) { + // m_LogicalDevice.destroyFramebuffer(frameBuffer); + // } + // m_SwapChainFrameBuffers.clear(); + // + // if (m_DepthImageView) { + // m_LogicalDevice.destroyImageView(m_DepthImageView); + // m_DepthImageView = nullptr; + // } + // + // if (m_DepthImage) { + // m_LogicalDevice.destroyImage(m_DepthImage); + // m_DepthImage = nullptr; + // } + // + // if (m_DepthImageMemory) { + // m_LogicalDevice.freeMemory(m_DepthImageMemory); + // m_DepthImageMemory = nullptr; + // } + // + // if (m_RenderPass) { + // m_LogicalDevice.destroyRenderPass(m_RenderPass); + // m_RenderPass = nullptr; + // } + + if (m_SwapChain) { + m_LogicalDevice.destroySwapchainKHR(m_SwapChain); + m_SwapChain = nullptr; + } + } + + vk::SurfaceFormatKHR VulkanSwapChain::selectSwapChainSurfaceFormat() { + std::vector availableFormats = m_PhysicalDevice.getSurfaceFormatsKHR(m_Surface); + for (const vk::SurfaceFormatKHR& availableFormat: availableFormats) { + if (availableFormat.format == vk::Format::eB8G8R8A8Unorm && availableFormat.colorSpace == + vk::ColorSpaceKHR::eSrgbNonlinear) { + return availableFormat; + } + } + + return availableFormats[0]; + } + + vk::PresentModeKHR VulkanSwapChain::selectSwapChainPresentMode() { + std::vector availablePresentModes = m_PhysicalDevice.getSurfacePresentModesKHR(m_Surface); + for (const auto& availablePresentMode: availablePresentModes) { + if (availablePresentMode == vk::PresentModeKHR::eMailbox) { + return availablePresentMode; + } + } + + return vk::PresentModeKHR::eFifo; + } + + vk::Extent2D VulkanSwapChain::selectSwapChainExtent(const vk::SurfaceCapabilitiesKHR& capabilities) { + if (capabilities.currentExtent.width != std::numeric_limits::max()) { + return capabilities.currentExtent; + } else { + return m_FallBackExtent; + } + } + + void VulkanSwapChain::createImageViews() { + m_SwapChainImages = m_LogicalDevice.getSwapchainImagesKHR(m_SwapChain); + + m_SwapChainImageViews.resize(m_SwapChainImages.size()); + + for (uint32_t i = 0; i < m_SwapChainImages.size(); i++) { + vk::ImageSubresourceRange imageSubResourceRange = vk::ImageSubresourceRange() + .setAspectMask(vk::ImageAspectFlagBits::eColor) + .setBaseMipLevel(0) + .setLevelCount(1) + .setBaseArrayLayer(0) + .setLayerCount(1); + + vk::ImageViewCreateInfo imageViewCreateInfo = vk::ImageViewCreateInfo() + .setImage(m_SwapChainImages[i]) + .setViewType(vk::ImageViewType::e2D) + .setFormat(m_SwapChainDetails.surfaceFormat.format) + .setComponents(vk::ComponentMapping()) + .setSubresourceRange(imageSubResourceRange); + + m_SwapChainImageViews[i] = m_LogicalDevice.createImageView(imageViewCreateInfo); + } + } +} diff --git a/Eternal/src/core/graphics/vulkan/VulkanSwapChain.h b/Eternal/src/core/graphics/vulkan/VulkanSwapChain.h index ccc9c1d..64e9d37 100644 --- a/Eternal/src/core/graphics/vulkan/VulkanSwapChain.h +++ b/Eternal/src/core/graphics/vulkan/VulkanSwapChain.h @@ -1,73 +1,65 @@ #pragma once -#include + +#include "utils/Base.h" +#include "core/graphics/SwapChain.h" + #include -#include namespace Eternal { + class VulkanSwapChain : public SwapChain { + public: + struct SwapChainDetails { + vk::SurfaceCapabilitiesKHR capabilities; + vk::SurfaceFormatKHR surfaceFormat; + vk::PresentModeKHR presentMode; + vk::Extent2D extent; + }; - class VulkanSwapChain : public SwapChain { - public: - struct SwapChainDetails { - vk::SurfaceCapabilitiesKHR capabilities; - vk::SurfaceFormatKHR surfaceFormat; - vk::PresentModeKHR presentMode; - vk::Extent2D extent; - }; + VulkanSwapChain( + vk::Instance instance, + vk::Device logicalDevice, + vk::PhysicalDevice physicalDevice, + vk::Queue queue, + vk::SurfaceKHR surface, + vk::Extent2D extent, + uint32_t graphicsQueueFamilyIndex, + uint32_t presentQueueFamilyIndex + ); - VulkanSwapChain( - vk::Instance instance, - vk::Device logicalDevice, - vk::PhysicalDevice physicalDevice, - vk::Queue queue, - vk::SurfaceKHR surface, - vk::Extent2D extent, - uint32_t graphicsQueueFamilyIndex, - uint32_t presentQueueFamilyIndex - ); + ~VulkanSwapChain(); - ~VulkanSwapChain(); + vk::Result acquire(vk::Semaphore imageReadySemaphore, uint32_t* imageIndex); + vk::Result present(vk::Semaphore renderFinishedSemaphore, uint32_t imageIndex); + void recreate(); + const SwapChainDetails& getSwapChainDetails() { return m_SwapChainDetails; } + const std::vector& getImageViews() { return m_SwapChainImageViews; } + const std::vector& getImages() { return m_SwapChainImages; } + vk::SwapchainKHR getSwapChain() { return m_SwapChain; } + vk::SurfaceKHR getSurface() { return m_Surface; } + bool shouldRecreate() const { return m_ShouldRecreate; } + void setShouldRecreate(bool shouldRecreate) { m_ShouldRecreate = shouldRecreate; } + void destroy(); - vk::Result acquire(vk::Semaphore imageReadySemaphore, uint32_t* imageIndex); - vk::Result present(vk::Semaphore renderFinishedSemaphore, uint32_t imageIndex); - void recreate(); - const SwapChainDetails& getSwapChainDetails() { return m_SwapChainDetails; } - const std::vector& getImageViews() { return m_SwapChainImageViews; } - const std::vector& getFrameBuffers() { return m_SwapChainFrameBuffers; } - const std::vector& getImages() { return m_SwapChainImages; } - vk::SwapchainKHR getSwapChain() { return m_SwapChain; } - vk::RenderPass getRenderPass() { return m_RenderPass; } - vk::SurfaceKHR getSurface() { return m_Surface; } - bool shouldRecreate() const { return m_ShouldRecreate; } - void setShouldRecreate(bool shouldRecreate) { m_ShouldRecreate = shouldRecreate; } - void destroy(); + private: + void create(); + vk::SurfaceFormatKHR selectSwapChainSurfaceFormat(); + vk::PresentModeKHR selectSwapChainPresentMode(); + vk::Extent2D selectSwapChainExtent(const vk::SurfaceCapabilitiesKHR& capabilities); + void createImageViews(); - private: - void create(); - vk::SurfaceFormatKHR selectSwapChainSurfaceFormat(); - vk::PresentModeKHR selectSwapChainPresentMode(); - vk::Extent2D selectSwapChainExtent(const vk::SurfaceCapabilitiesKHR& capabilities); - void createImageViews(); - void createDepthImageView(); - void createRenderPass(); - void createFrameBuffers(); + bool m_ShouldRecreate = false; + vk::Instance m_VkInstance = nullptr; + vk::Device m_LogicalDevice = nullptr; + vk::PhysicalDevice m_PhysicalDevice = nullptr; + vk::Queue m_PresentQueue = nullptr; + uint32_t m_GraphicsQueueFamilyIndex = INVALID_VK_INDEX; + uint32_t m_PresentQueueFamilyIndex = INVALID_VK_INDEX; + vk::SurfaceKHR m_Surface = nullptr; + vk::Extent2D m_FallBackExtent; + std::vector m_SwapChainImages; + std::vector m_SwapChainImageViews; - bool m_ShouldRecreate = false; - vk::Instance m_VkInstance = nullptr; - vk::Device m_LogicalDevice = nullptr; - vk::PhysicalDevice m_PhysicalDevice = nullptr; - vk::Queue m_PresentQueue = nullptr; - uint32_t m_GraphicsQueueFamilyIndex = INVALID_VK_INDEX; - uint32_t m_PresentQueueFamilyIndex = INVALID_VK_INDEX; - vk::SurfaceKHR m_Surface = nullptr; - vk::Extent2D m_FallBackExtent; - vk::RenderPass m_RenderPass = nullptr; - std::vector m_SwapChainFrameBuffers; - std::vector m_SwapChainImages; - std::vector m_SwapChainImageViews; - vk::Image m_DepthImage; - vk::DeviceMemory m_DepthImageMemory; - vk::ImageView m_DepthImageView; - vk::SwapchainKHR m_SwapChain = nullptr; - SwapChainDetails m_SwapChainDetails = {}; - }; -} \ No newline at end of file + vk::SwapchainKHR m_SwapChain = nullptr; + SwapChainDetails m_SwapChainDetails = {}; + }; +} diff --git a/Eternal/src/core/graphics/vulkan/VulkanTexture.cpp b/Eternal/src/core/graphics/vulkan/VulkanTexture.cpp index 1ef4138..903ebac 100644 --- a/Eternal/src/core/graphics/vulkan/VulkanTexture.cpp +++ b/Eternal/src/core/graphics/vulkan/VulkanTexture.cpp @@ -1,195 +1,195 @@ -#include "VulkanTexture.h" -#include "VulkanPlatform.h" +#include "core/graphics/vulkan/VulkanTexture.h" +#include "core/graphics/vulkan/VulkanPlatform.h" namespace Eternal { - - VulkanTexture::VulkanTexture(vk::Device device, vk::PhysicalDevice physicalDevice, const Eternal::Image* imageResource) { - m_ImageResource = imageResource; - m_Device = device; - m_PhysicalDevice = physicalDevice; - - m_Width = imageResource->getWidth(); - m_Height = imageResource->getHeight(); - - create(); - } - - VulkanTexture::~VulkanTexture() { - if (m_ImageView) { - m_Device.destroyImageView(m_ImageView); - } - if (m_Image) { - m_Device.destroyImage(m_Image); - } - if (m_Memory) { - m_Device.freeMemory(m_Memory); - } - if (m_Sampler) { - m_Device.destroySampler(m_Sampler); - } - } - - vk::BufferImageCopy VulkanTexture::getRegionForCopy() { - vk::ImageSubresourceLayers subresourceRange = vk::ImageSubresourceLayers() - .setAspectMask(vk::ImageAspectFlagBits::eColor) - .setMipLevel(0) - .setBaseArrayLayer(0) - .setLayerCount(1); - - vk::BufferImageCopy region = vk::BufferImageCopy() - .setBufferOffset(0) - .setBufferRowLength(0) - .setBufferImageHeight(0) - .setImageSubresource(subresourceRange) - .setImageOffset({ 0,0,0 }) - .setImageExtent({ (uint32_t)m_Width , (uint32_t)m_Height , 1 }); - - return region; - } - - void VulkanTexture::prepareStagingBuffer() { - int pixelCount = m_ImageResource->getPixelCount(); - int channel = m_ImageResource->getChannels(); - - m_StagingBuffer = std::make_shared(m_Device, m_PhysicalDevice); - m_StagingBuffer->create(pixelCount, channel, vk::BufferUsageFlagBits::eTransferSrc); - m_StagingBuffer->allocate(m_BufferProperties); - m_StagingBuffer->map(); - m_StagingBuffer->write(m_ImageResource->getData()); - m_StagingBuffer->unMap(); - } - - void VulkanTexture::createImage() { - vk::ImageCreateInfo imageCreateInfo; - imageCreateInfo.imageType = vk::ImageType::e2D; - imageCreateInfo.extent.width = m_Width; - imageCreateInfo.extent.height = m_Height; - imageCreateInfo.extent.depth = 1; - imageCreateInfo.mipLevels = 1; - imageCreateInfo.arrayLayers = 1; - imageCreateInfo.format = vk::Format::eR8G8B8A8Srgb; - imageCreateInfo.tiling = vk::ImageTiling::eOptimal; - imageCreateInfo.initialLayout = vk::ImageLayout::eUndefined; - imageCreateInfo.usage = vk::ImageUsageFlagBits::eTransferDst | vk::ImageUsageFlagBits::eSampled; - imageCreateInfo.samples = vk::SampleCountFlagBits::e1; - imageCreateInfo.sharingMode = vk::SharingMode::eExclusive; - - m_Image = m_Device.createImage(imageCreateInfo); - } - - void VulkanTexture::allocateMemory() { - vk::MemoryRequirements memoryRequirements = m_Device.getImageMemoryRequirements(m_Image); - - vk::MemoryAllocateInfo memoryAllocateInfo; - memoryAllocateInfo.allocationSize = memoryRequirements.size; - memoryAllocateInfo.memoryTypeIndex = VulkanPlatform::getMemoryType(m_PhysicalDevice, vk::MemoryPropertyFlagBits::eDeviceLocal, memoryRequirements.memoryTypeBits); - - m_Memory = m_Device.allocateMemory(memoryAllocateInfo); - m_Device.bindImageMemory(m_Image, m_Memory, 0); - } - - void VulkanTexture::createImageView() { - vk::ImageSubresourceRange imageSubResourceRange = vk::ImageSubresourceRange() - .setAspectMask(vk::ImageAspectFlagBits::eColor) - .setBaseMipLevel(0) - .setLevelCount(1) - .setBaseArrayLayer(0) - .setLayerCount(1); - - vk::ImageViewCreateInfo imageViewCreateInfo = vk::ImageViewCreateInfo() - .setImage(m_Image) - .setViewType(vk::ImageViewType::e2D) - .setFormat(m_Format) - .setComponents(vk::ComponentMapping()) - .setSubresourceRange(imageSubResourceRange); - - m_ImageView = m_Device.createImageView(imageViewCreateInfo); - } - - void VulkanTexture::createSampler() { - vk::PhysicalDeviceProperties props = m_PhysicalDevice.getProperties(); - vk::SamplerCreateInfo samplerInfo = vk::SamplerCreateInfo() - .setMagFilter(vk::Filter::eLinear) - .setMinFilter(vk::Filter::eLinear) - .setAddressModeU(vk::SamplerAddressMode::eRepeat) - .setAddressModeV(vk::SamplerAddressMode::eRepeat) - .setAddressModeW(vk::SamplerAddressMode::eRepeat) - .setAnisotropyEnable(VK_TRUE) - .setMaxAnisotropy(props.limits.maxSamplerAnisotropy) - .setBorderColor(vk::BorderColor::eIntOpaqueBlack) - .setUnnormalizedCoordinates(VK_FALSE) - .setCompareEnable(VK_FALSE) - .setCompareOp(vk::CompareOp::eAlways) - .setMipmapMode(vk::SamplerMipmapMode::eLinear); - - m_Sampler = m_Device.createSampler(samplerInfo); - } - - void VulkanTexture::create() { - prepareStagingBuffer(); - createImage(); - allocateMemory(); - createImageView(); - createSampler(); - } - - void VulkanTexture::recordUploadCommand(vk::CommandBuffer commandBuffer) { - { - VulkanTexture::LayoutTransitionInfo layoutTransitionInfo = - getLayoutTransitionInfo(m_Format, vk::ImageLayout::eUndefined, vk::ImageLayout::eTransferDstOptimal); - commandBuffer.pipelineBarrier(layoutTransitionInfo.sourceStage, layoutTransitionInfo.destinationStage, {}, {}, {}, { layoutTransitionInfo.imageMemoryBarrier }); - } - - { - vk::BufferImageCopy region = getRegionForCopy(); - auto stagingBuffer = m_StagingBuffer->getBuffer(); - commandBuffer.copyBufferToImage(*stagingBuffer, m_Image, vk::ImageLayout::eTransferDstOptimal, region); - } - - { - VulkanTexture::LayoutTransitionInfo layoutTransitionInfo = - getLayoutTransitionInfo(m_Format, vk::ImageLayout::eTransferDstOptimal, vk::ImageLayout::eShaderReadOnlyOptimal); - commandBuffer.pipelineBarrier(layoutTransitionInfo.sourceStage, layoutTransitionInfo.destinationStage, {}, {}, {}, { layoutTransitionInfo.imageMemoryBarrier }); - } - } - - VulkanTexture::LayoutTransitionInfo VulkanTexture::getLayoutTransitionInfo(vk::Format format, vk::ImageLayout oldLayout, vk::ImageLayout newLayout) { - vk::ImageSubresourceRange subresourceRange = vk::ImageSubresourceRange() - .setAspectMask(vk::ImageAspectFlagBits::eColor) - .setBaseMipLevel(0) - .setLevelCount(1) - .setBaseArrayLayer(0) - .setLayerCount(1); - - vk::ImageMemoryBarrier barrier = vk::ImageMemoryBarrier() - .setOldLayout(oldLayout) - .setNewLayout(newLayout) - .setSrcQueueFamilyIndex(VK_QUEUE_FAMILY_IGNORED) - .setDstQueueFamilyIndex(VK_QUEUE_FAMILY_IGNORED) - .setImage(m_Image) - .setSubresourceRange(subresourceRange); - - vk::PipelineStageFlags sourceStage; - vk::PipelineStageFlags destinationStage; - - if (oldLayout == vk::ImageLayout::eUndefined && newLayout == vk::ImageLayout::eTransferDstOptimal) { - barrier.setSrcAccessMask(vk::AccessFlagBits::eNone) - .setDstAccessMask(vk::AccessFlagBits::eTransferWrite); - - sourceStage = vk::PipelineStageFlagBits::eTopOfPipe; - destinationStage = vk::PipelineStageFlagBits::eTransfer; - } - else if (oldLayout == vk::ImageLayout::eTransferDstOptimal && newLayout == vk::ImageLayout::eShaderReadOnlyOptimal) { - barrier.setSrcAccessMask(vk::AccessFlagBits::eTransferWrite) - .setDstAccessMask(vk::AccessFlagBits::eShaderRead); - - sourceStage = vk::PipelineStageFlagBits::eTransfer; - destinationStage = vk::PipelineStageFlagBits::eFragmentShader; - } - else { - ETERNAL_ASSERT(false, "We do not support more layout transitions"); - } - - return { barrier , sourceStage , destinationStage }; - } -} \ No newline at end of file + VulkanTexture::VulkanTexture(Eternal::VulkanPlatform* vulkanPlatform, const Eternal::Image* imageResource) { + m_VulkanPlatform = vulkanPlatform; + m_ImageResource = imageResource; + m_Device = vulkanPlatform->getLogicalDevice(); + m_PhysicalDevice = vulkanPlatform->getPhysicalDevice(); + + m_Width = imageResource->getWidth(); + m_Height = imageResource->getHeight(); + + create(); + } + + VulkanTexture::~VulkanTexture() { + if (m_ImageView) { + m_Device.destroyImageView(m_ImageView); + } + if (m_Image) { + m_Device.destroyImage(m_Image); + } + if (m_Memory) { + m_Device.freeMemory(m_Memory); + } + if (m_Sampler) { + m_Device.destroySampler(m_Sampler); + } + } + + vk::BufferImageCopy VulkanTexture::getRegionForCopy() const { + vk::ImageSubresourceLayers subresourceRange = vk::ImageSubresourceLayers() + .setAspectMask(vk::ImageAspectFlagBits::eColor) + .setMipLevel(0) + .setBaseArrayLayer(0) + .setLayerCount(1); + + vk::BufferImageCopy region = vk::BufferImageCopy() + .setBufferOffset(0) + .setBufferRowLength(0) + .setBufferImageHeight(0) + .setImageSubresource(subresourceRange) + .setImageOffset({0, 0, 0}) + .setImageExtent({(uint32_t) m_Width, (uint32_t) m_Height, 1}); + + return region; + } + + void VulkanTexture::prepareStagingBuffer() { + int pixelCount = m_ImageResource->getPixelCount(); + int channel = m_ImageResource->getChannels(); + + m_StagingBuffer = std::make_shared(m_VulkanPlatform); + m_StagingBuffer->create(pixelCount, channel, vk::BufferUsageFlagBits::eTransferSrc); + m_StagingBuffer->allocate(m_BufferProperties); + m_StagingBuffer->map(); + m_StagingBuffer->write(m_ImageResource->getData()); + m_StagingBuffer->unMap(); + } + + void VulkanTexture::createImage() { + vk::ImageCreateInfo imageCreateInfo; + imageCreateInfo.imageType = vk::ImageType::e2D; + imageCreateInfo.extent.width = m_Width; + imageCreateInfo.extent.height = m_Height; + imageCreateInfo.extent.depth = 1; + imageCreateInfo.mipLevels = 1; + imageCreateInfo.arrayLayers = 1; + imageCreateInfo.format = vk::Format::eR8G8B8A8Srgb; + imageCreateInfo.tiling = vk::ImageTiling::eOptimal; + imageCreateInfo.initialLayout = vk::ImageLayout::eUndefined; + imageCreateInfo.usage = vk::ImageUsageFlagBits::eTransferDst | vk::ImageUsageFlagBits::eSampled; + imageCreateInfo.samples = vk::SampleCountFlagBits::e1; + imageCreateInfo.sharingMode = vk::SharingMode::eExclusive; + + m_Image = m_Device.createImage(imageCreateInfo); + } + + void VulkanTexture::allocateMemory() { + vk::MemoryRequirements memoryRequirements = m_Device.getImageMemoryRequirements(m_Image); + + vk::MemoryAllocateInfo memoryAllocateInfo; + memoryAllocateInfo.allocationSize = memoryRequirements.size; + memoryAllocateInfo.memoryTypeIndex = VulkanPlatform::getMemoryType( + m_PhysicalDevice, vk::MemoryPropertyFlagBits::eDeviceLocal, memoryRequirements.memoryTypeBits); + + m_Memory = m_Device.allocateMemory(memoryAllocateInfo); + m_Device.bindImageMemory(m_Image, m_Memory, 0); + } + + void VulkanTexture::createImageView() { + vk::ImageSubresourceRange imageSubResourceRange = vk::ImageSubresourceRange() + .setAspectMask(vk::ImageAspectFlagBits::eColor) + .setBaseMipLevel(0) + .setLevelCount(1) + .setBaseArrayLayer(0) + .setLayerCount(1); + + vk::ImageViewCreateInfo imageViewCreateInfo = vk::ImageViewCreateInfo() + .setImage(m_Image) + .setViewType(vk::ImageViewType::e2D) + .setFormat(m_Format) + .setComponents(vk::ComponentMapping()) + .setSubresourceRange(imageSubResourceRange); + + m_ImageView = m_Device.createImageView(imageViewCreateInfo); + } + + void VulkanTexture::createSampler() { + vk::PhysicalDeviceProperties props = m_PhysicalDevice.getProperties(); + vk::SamplerCreateInfo samplerInfo = vk::SamplerCreateInfo() + .setMagFilter(vk::Filter::eLinear) + .setMinFilter(vk::Filter::eLinear) + .setAddressModeU(vk::SamplerAddressMode::eRepeat) + .setAddressModeV(vk::SamplerAddressMode::eRepeat) + .setAddressModeW(vk::SamplerAddressMode::eRepeat) + .setAnisotropyEnable(VK_TRUE) + .setMaxAnisotropy(props.limits.maxSamplerAnisotropy) + .setBorderColor(vk::BorderColor::eIntOpaqueBlack) + .setUnnormalizedCoordinates(VK_FALSE) + .setCompareEnable(VK_FALSE) + .setCompareOp(vk::CompareOp::eAlways) + .setMipmapMode(vk::SamplerMipmapMode::eLinear); + + m_Sampler = m_Device.createSampler(samplerInfo); + } + + void VulkanTexture::create() { + prepareStagingBuffer(); + createImage(); + allocateMemory(); + createImageView(); + createSampler(); + } + + void VulkanTexture::recordUploadCommand(vk::CommandBuffer commandBuffer) const { { + VulkanTexture::LayoutTransitionInfo layoutTransitionInfo = + getLayoutTransitionInfo(m_Format, vk::ImageLayout::eUndefined, + vk::ImageLayout::eTransferDstOptimal); + commandBuffer.pipelineBarrier(layoutTransitionInfo.sourceStage, layoutTransitionInfo.destinationStage, {}, + {}, {}, {layoutTransitionInfo.imageMemoryBarrier}); + } { + vk::BufferImageCopy region = getRegionForCopy(); + auto stagingBuffer = m_StagingBuffer->getVkBuffer(); + commandBuffer.copyBufferToImage(*stagingBuffer, m_Image, vk::ImageLayout::eTransferDstOptimal, region); + } { + VulkanTexture::LayoutTransitionInfo layoutTransitionInfo = + getLayoutTransitionInfo(m_Format, vk::ImageLayout::eTransferDstOptimal, + vk::ImageLayout::eShaderReadOnlyOptimal); + commandBuffer.pipelineBarrier(layoutTransitionInfo.sourceStage, layoutTransitionInfo.destinationStage, {}, + {}, {}, {layoutTransitionInfo.imageMemoryBarrier}); + } + } + + VulkanTexture::LayoutTransitionInfo VulkanTexture::getLayoutTransitionInfo( + vk::Format format, vk::ImageLayout oldLayout, vk::ImageLayout newLayout) const { + vk::ImageSubresourceRange subresourceRange = vk::ImageSubresourceRange() + .setAspectMask(vk::ImageAspectFlagBits::eColor) + .setBaseMipLevel(0) + .setLevelCount(1) + .setBaseArrayLayer(0) + .setLayerCount(1); + + vk::ImageMemoryBarrier barrier = vk::ImageMemoryBarrier() + .setOldLayout(oldLayout) + .setNewLayout(newLayout) + .setSrcQueueFamilyIndex(VK_QUEUE_FAMILY_IGNORED) + .setDstQueueFamilyIndex(VK_QUEUE_FAMILY_IGNORED) + .setImage(m_Image) + .setSubresourceRange(subresourceRange); + + vk::PipelineStageFlags sourceStage; + vk::PipelineStageFlags destinationStage; + + if (oldLayout == vk::ImageLayout::eUndefined && newLayout == vk::ImageLayout::eTransferDstOptimal) { + barrier.setSrcAccessMask(vk::AccessFlagBits::eNone) + .setDstAccessMask(vk::AccessFlagBits::eTransferWrite); + + sourceStage = vk::PipelineStageFlagBits::eTopOfPipe; + destinationStage = vk::PipelineStageFlagBits::eTransfer; + } else if (oldLayout == vk::ImageLayout::eTransferDstOptimal && newLayout == + vk::ImageLayout::eShaderReadOnlyOptimal) { + barrier.setSrcAccessMask(vk::AccessFlagBits::eTransferWrite) + .setDstAccessMask(vk::AccessFlagBits::eShaderRead); + + sourceStage = vk::PipelineStageFlagBits::eTransfer; + destinationStage = vk::PipelineStageFlagBits::eFragmentShader; + } else { + ETERNAL_ASSERT(false, "We do not support more layout transitions"); + } + + return {barrier, sourceStage, destinationStage}; + } +} diff --git a/Eternal/src/core/graphics/vulkan/VulkanTexture.h b/Eternal/src/core/graphics/vulkan/VulkanTexture.h index 0bd53a5..63570fa 100644 --- a/Eternal/src/core/graphics/vulkan/VulkanTexture.h +++ b/Eternal/src/core/graphics/vulkan/VulkanTexture.h @@ -1,61 +1,64 @@ #pragma once -#include -#include - -#include "VulkanBuffer.h" +#include "utils/Base.h" +#include "core/graphics/vulkan/VulkanBuffer.h" +#include "core/resource/Image.h" namespace Eternal { - class VulkanTexture { - public: - struct LayoutTransitionInfo { - vk::ImageMemoryBarrier imageMemoryBarrier; - vk::PipelineStageFlags sourceStage; - vk::PipelineStageFlags destinationStage; - }; - - VulkanTexture(vk::Device device, vk::PhysicalDevice physicalDevice, const Eternal::Image* imageResource); - ~VulkanTexture(); - - std::shared_ptr getStagingBuffer() { return m_StagingBuffer; } - vk::Format getFormat() { return m_Format; } - const vk::Image& getImage() { return m_Image; } - int getWidth() { return m_Width; } - int getHeight() { return m_Height; } - vk::BufferImageCopy getRegionForCopy(); - vk::ImageView getImageView() { return m_ImageView; } - vk::Sampler getSampler() { return m_Sampler; } - - void create(); - void recordUploadCommand(vk::CommandBuffer commandBuffer); - LayoutTransitionInfo getLayoutTransitionInfo(vk::Format format, vk::ImageLayout oldLayout, vk::ImageLayout newLayout); - - private: - const Eternal::Image* m_ImageResource; - std::shared_ptr m_StagingBuffer; - - vk::MemoryPropertyFlags m_BufferProperties = vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent; - - void prepareStagingBuffer(); - void createImage(); - void allocateMemory(); - void createImageView(); - void createSampler(); - - vk::Device m_Device; - vk::PhysicalDevice m_PhysicalDevice; - - vk::Image m_Image; - vk::DeviceSize m_ImageSize = 0; - vk::DeviceMemory m_Memory; - vk::ImageView m_ImageView; - vk::Sampler m_Sampler; - vk::DescriptorImageInfo m_DescriptorInfo; - - int m_Width = 0; - int m_Height = 0; - vk::Format m_Format = vk::Format::eR8G8B8A8Srgb; - - std::string m_DebugName = "test_texture_name"; - }; -} \ No newline at end of file + class VulkanTexture { + public: + struct LayoutTransitionInfo { + vk::ImageMemoryBarrier imageMemoryBarrier; + vk::PipelineStageFlags sourceStage; + vk::PipelineStageFlags destinationStage; + }; + + VulkanTexture(Eternal::VulkanPlatform* vulkanPlatform, const Eternal::Image* imageResource); + ~VulkanTexture(); + + std::shared_ptr getStagingBuffer() { return m_StagingBuffer; } + vk::Format getFormat() const { return m_Format; } + const vk::Image& getImage() const { return m_Image; } + int getWidth() const { return m_Width; } + int getHeight() const { return m_Height; } + vk::BufferImageCopy getRegionForCopy() const; + vk::ImageView getImageView() const { return m_ImageView; } + vk::Sampler getSampler() const { return m_Sampler; } + + void create(); + void recordUploadCommand(vk::CommandBuffer commandBuffer) const; + LayoutTransitionInfo getLayoutTransitionInfo(vk::Format format, vk::ImageLayout oldLayout, + vk::ImageLayout newLayout) const; + + private: + const Eternal::Image* m_ImageResource; + std::shared_ptr m_StagingBuffer; + + vk::MemoryPropertyFlags m_BufferProperties = + vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent; + + void prepareStagingBuffer(); + void createImage(); + void allocateMemory(); + void createImageView(); + void createSampler(); + + vk::Device m_Device; + vk::PhysicalDevice m_PhysicalDevice; + + Eternal::VulkanPlatform* m_VulkanPlatform; + + vk::Image m_Image; + vk::DeviceSize m_ImageSize = 0; + vk::DeviceMemory m_Memory; + vk::ImageView m_ImageView; + vk::Sampler m_Sampler; + vk::DescriptorImageInfo m_DescriptorInfo; + + int m_Width = 0; + int m_Height = 0; + vk::Format m_Format = vk::Format::eR8G8B8A8Srgb; + + std::string m_DebugName = "test_texture_name"; + }; +} diff --git a/Eternal/src/core/graphics/vulkan/VulkanTextureManager.cpp b/Eternal/src/core/graphics/vulkan/VulkanTextureManager.cpp index d4bce4b..d1aee47 100644 --- a/Eternal/src/core/graphics/vulkan/VulkanTextureManager.cpp +++ b/Eternal/src/core/graphics/vulkan/VulkanTextureManager.cpp @@ -1,55 +1,56 @@ -#include "VulkanTextureManager.h" - -#include +#include "core/graphics/vulkan/VulkanTextureManager.h" +#include "core/scene/RenderComponent.h" +#include "core/scene/Entity.h" namespace Eternal { - - VulkanTextureManager::VulkanTextureManager(Eternal::VulkanPlatform* vulkanPlatform, Scene* scene) - : m_VulkanPlatform(vulkanPlatform), m_Scene(scene) { - m_Device = m_VulkanPlatform->getLogicalDevice(); - m_PhysicalDevice = m_VulkanPlatform->getPhysicalDevice(); - createCommandPool(); - initialize(); - } - - void VulkanTextureManager::initialize() { - for (auto& e : m_Scene->getAllEntityWith()) { - Eternal::Entity entity = Eternal::Entity(e, m_Scene); - EntityId entityUUID = entity.getUUID(); - - if (m_Textures.count(entityUUID) >= 1) - continue; - - auto& component = entity.getComponent(); - addTexture(entityUUID, component); - } - } - - VulkanTextureManager::~VulkanTextureManager() { - m_VulkanPlatform->destroyCommandPool(m_CommandPool); - } - - void VulkanTextureManager::addTexture(EntityId entityId, const MaterialComponent& materialComponent) { - const Eternal::Image* albedoTextureImage = materialComponent.getAlbedoTexture(); - std::shared_ptr vulkanTexture = - std::make_shared(m_Device, m_PhysicalDevice, albedoTextureImage); - - initializeTexture(vulkanTexture); - - m_Textures[entityId] = vulkanTexture; - } - - void VulkanTextureManager::initializeTexture(std::shared_ptr vulkanTexture) { - vk::Queue graphicsQueue = m_VulkanPlatform->getGraphicsQueue(); - m_VulkanPlatform->executeOneCommand(m_CommandPool, graphicsQueue, - [&](vk::CommandBuffer commandBuffer) { - vulkanTexture->recordUploadCommand(commandBuffer); - }); - } - - void VulkanTextureManager::createCommandPool() { - m_CommandPool = m_VulkanPlatform->createCommandPool(vk::CommandPoolCreateFlagBits::eTransient); - } + VulkanTextureManager::VulkanTextureManager(Eternal::VulkanPlatform* vulkanPlatform, Scene* scene) + : m_VulkanPlatform(vulkanPlatform), m_Scene(scene) { + createCommandPool(); + initialize(); + } + + void VulkanTextureManager::initialize() { + for (auto& e: m_Scene->getAllEntityWith()) { + Eternal::Entity entity = Eternal::Entity(e, m_Scene); + EntityId entityUUID = entity.getUUID(); + + if (m_Textures.contains(entityUUID) && m_Textures[entityUUID] != nullptr) + continue; + + if (auto component = entity.tryGetComponent()) { + addTexture(entityUUID, *component); + } + } + } + + VulkanTextureManager::~VulkanTextureManager() { + m_VulkanPlatform->destroyCommandPool(m_CommandPool); + } + + void VulkanTextureManager::addTexture(EntityId entityId, const MaterialComponent& materialComponent) { + const Eternal::Image* albedoTextureImage = materialComponent.getAlbedoTexture(); + if (albedoTextureImage == nullptr) { + m_Textures[entityId] = nullptr; + return; + } + + std::shared_ptr vulkanTexture = + std::make_shared(m_VulkanPlatform, albedoTextureImage); + + initializeTexture(vulkanTexture); + + m_Textures[entityId] = vulkanTexture; + } + + void VulkanTextureManager::initializeTexture(std::shared_ptr vulkanTexture) const { + vk::Queue graphicsQueue = m_VulkanPlatform->getGraphicsQueue(); + m_VulkanPlatform->executeOneCommand(m_CommandPool, graphicsQueue, + [&](vk::CommandBuffer commandBuffer) { + vulkanTexture->recordUploadCommand(commandBuffer); + }); + } + + void VulkanTextureManager::createCommandPool() { + m_CommandPool = m_VulkanPlatform->createCommandPool(vk::CommandPoolCreateFlagBits::eTransient); + } } - - diff --git a/Eternal/src/core/graphics/vulkan/VulkanTextureManager.h b/Eternal/src/core/graphics/vulkan/VulkanTextureManager.h index f29356c..26920eb 100644 --- a/Eternal/src/core/graphics/vulkan/VulkanTextureManager.h +++ b/Eternal/src/core/graphics/vulkan/VulkanTextureManager.h @@ -1,14 +1,13 @@ #pragma once -#include -#include -#include - -#include "VulkanTexture.h" -#include "VulkanUtils.h" -#include "VulkanPlatform.h" +#include "utils/Base.h" +#include "core/graphics/vulkan/VulkanTexture.h" +#include "core/graphics/vulkan/VulkanPlatform.h" +#include "core/scene/Scene.h" +#include "core/scene/MaterialComponent.h" namespace Eternal { + class VulkanTextureManager { public: using EntityId = uint32_t; @@ -20,8 +19,7 @@ namespace Eternal { void addTexture(EntityId entityId, const MaterialComponent& materialComponent); std::shared_ptr getTexture(EntityId entityId) const { - auto it = m_Textures.find(entityId); - if (it != m_Textures.end()) { + if (auto it = m_Textures.find(entityId); it != m_Textures.end()) { return it->second; } return nullptr; @@ -31,16 +29,13 @@ namespace Eternal { private: void initialize(); - void initializeTexture(std::shared_ptr vulkanTexture); + void initializeTexture(std::shared_ptr vulkanTexture) const; void createCommandPool(); vk::CommandPool m_CommandPool; Eternal::VulkanPlatform* m_VulkanPlatform = nullptr; Scene* m_Scene = nullptr; - vk::Device m_Device = nullptr; - vk::PhysicalDevice m_PhysicalDevice = nullptr; VulkanTextureContainer m_Textures; - }; } \ No newline at end of file diff --git a/Eternal/src/core/graphics/vulkan/VulkanUtils.h b/Eternal/src/core/graphics/vulkan/VulkanUtils.h index 7268c5d..bdfa98b 100644 --- a/Eternal/src/core/graphics/vulkan/VulkanUtils.h +++ b/Eternal/src/core/graphics/vulkan/VulkanUtils.h @@ -1,8 +1,10 @@ #pragma once -#include -#include +#include "utils/Base.h" +#include "core/log/Logger.h" +#define GLFW_INCLUDE_VULKAN +#define VK_USE_PLATFORM_WIN32_KHR #include -constexpr uint32_t const MAX_FRAMES_IN_FLIGHT = 2; \ No newline at end of file +constexpr uint32_t const MAX_FRAMES_IN_FLIGHT = 2; diff --git a/Eternal/src/core/graphics/vulkan/VulkanVertexBuffer.cpp b/Eternal/src/core/graphics/vulkan/VulkanVertexBuffer.cpp new file mode 100644 index 0000000..ea6a65d --- /dev/null +++ b/Eternal/src/core/graphics/vulkan/VulkanVertexBuffer.cpp @@ -0,0 +1,24 @@ +#include "core/graphics/vulkan/VulkanVertexBuffer.h" + +namespace Eternal { + VulkanVertexBuffer::VulkanVertexBuffer(VulkanPlatform* vulkanPlatform, + const std::vector& vertices) + : m_VulkanPlatform(vulkanPlatform) { + m_Buffer = std::make_unique(m_VulkanPlatform); + m_Buffer->create(vertices.size(), sizeof(Eternal::Vertex), + vk::BufferUsageFlagBits::eVertexBuffer); + m_Buffer->allocate(m_BufferProperties); + m_Buffer->map(); + m_Buffer->write((void*) (vertices.data())); + } + + VulkanVertexBuffer::~VulkanVertexBuffer() { + + } + + void VulkanVertexBuffer::bind() { + } + + void VulkanVertexBuffer::unBind() { + } +} diff --git a/Eternal/src/core/graphics/vulkan/VulkanVertexBuffer.h b/Eternal/src/core/graphics/vulkan/VulkanVertexBuffer.h new file mode 100644 index 0000000..cc8ccbb --- /dev/null +++ b/Eternal/src/core/graphics/vulkan/VulkanVertexBuffer.h @@ -0,0 +1,23 @@ +#pragma once +#include "core/graphics/vulkan/VulkanBuffer.h" +#include "core/graphics/Vertex.h" +#include "core/graphics/VertexBuffer.h" +#include "core/graphics/vulkan/VulkanPlatform.h" + +namespace Eternal { + class VulkanVertexBuffer : public VertexBuffer { + public: + VulkanVertexBuffer(VulkanPlatform* vulkanPlatform, const std::vector& vertices); + ~VulkanVertexBuffer() override; + void bind() override; + void unBind() override; + uint32_t getCount() override { return m_Buffer->getBufferSize(); }; + vk::Buffer* getVkBuffer() const { return m_Buffer->getVkBuffer(); } + + private : + std::unique_ptr m_Buffer; + vk::MemoryPropertyFlags m_BufferProperties = + vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent; + VulkanPlatform* m_VulkanPlatform; + }; +} diff --git a/Eternal/src/core/graphics/vulkan/VulkanWindow.h b/Eternal/src/core/graphics/vulkan/VulkanWindow.h index 2d25b16..1f5b2a1 100644 --- a/Eternal/src/core/graphics/vulkan/VulkanWindow.h +++ b/Eternal/src/core/graphics/vulkan/VulkanWindow.h @@ -1,15 +1,14 @@ #pragma once -#include +#include "core/window/Window.h" -#include #include namespace Eternal { - class VulkanWindow : public Window { - public: - virtual ~VulkanWindow() = default; - virtual vk::SurfaceKHR createWindowSurface(vk::Instance instance) const = 0; - virtual vk::Extent2D getExtent() const = 0; - }; -} \ No newline at end of file + class VulkanWindow : public Window { + public: + virtual ~VulkanWindow() = default; + virtual vk::SurfaceKHR createWindowSurface(vk::Instance instance) const = 0; + virtual vk::Extent2D getExtent() const = 0; + }; +} diff --git a/Eternal/src/core/imgui/ImGuiOverlay.cpp b/Eternal/src/core/imgui/ImGuiOverlay.cpp new file mode 100644 index 0000000..135d684 --- /dev/null +++ b/Eternal/src/core/imgui/ImGuiOverlay.cpp @@ -0,0 +1,45 @@ +#include "core/imgui/ImGuiOverlay.h" +#include "core/graphics/vulkan/VulkanImGuiOverlay.h" + +namespace Eternal { + std::unique_ptr ImGuiOverlay::create(const Builder& builder) { + ETERNAL_ASSERT(builder->backend == Backend::Vulkan, "Currently Only supported Backend is Vulkan"); + return std::make_unique(builder); + } + + ImGuiOverlay::Builder::Builder() noexcept = default; + + ImGuiOverlay::Builder::Builder(Builder const& rhs) noexcept = default; + + ImGuiOverlay::Builder::Builder(Builder&& rhs) noexcept = default; + + ImGuiOverlay::Builder::~Builder() noexcept = default; + + ImGuiOverlay::Builder& ImGuiOverlay::Builder::operator=(Builder const& rhs) noexcept = default; + + ImGuiOverlay::Builder& ImGuiOverlay::Builder::operator=(Builder&& rhs) noexcept = default; + + ImGuiOverlay::Builder& ImGuiOverlay::Builder::backend(const Backend backend) noexcept { + mImpl->backend = backend; + return *this; + } + + ImGuiOverlay::Builder& ImGuiOverlay::Builder::platform(GraphicsPlatform* platform) noexcept { + mImpl->platform = platform; + return *this; + } + + ImGuiOverlay::Builder& ImGuiOverlay::Builder::window(Window* window) noexcept { + mImpl->window = window; + return *this; + } + + ImGuiOverlay::Builder& ImGuiOverlay::Builder::renderer(Renderer* renderer) noexcept { + mImpl->renderer = renderer; + return *this; + } + + std::unique_ptr ImGuiOverlay::Builder::build() const noexcept { + return create(*this); + } +} diff --git a/Eternal/src/core/imgui/ImGuiOverlay.h b/Eternal/src/core/imgui/ImGuiOverlay.h new file mode 100644 index 0000000..30a0111 --- /dev/null +++ b/Eternal/src/core/imgui/ImGuiOverlay.h @@ -0,0 +1,56 @@ +#pragma once + +#include "core/graphics/FrameInfo.h" +#include "core/graphics/Backend.h" +#include "core/graphics/GraphicsPlatform.h" +#include "core/graphics/Renderer.h" +#include "core/window/Window.h" + +namespace Eternal { + class ImGuiOverlay { + public: + virtual void beginFrame() = 0; + + virtual void render(FrameInfo* frameInfo) = 0; + + virtual ~ImGuiOverlay() = default; + + struct BuilderDetails { + Backend backend = Vulkan; + GraphicsPlatform* platform = nullptr; + Window* window = nullptr; + Renderer* renderer = nullptr; + }; + + + class Builder : public utils::PrivateImplementation { + friend class ImGuiOverlay; + friend class VulkanImGuiOverlay; + + public: + Builder() noexcept; + + Builder(Builder const& rhs) noexcept; + + Builder(Builder&& rhs) noexcept; + + ~Builder() noexcept; + + Builder& operator=(Builder const& rhs) noexcept; + + Builder& operator=(Builder&& rhs) noexcept; + + Builder& backend(Backend backend) noexcept; + + Builder& platform(GraphicsPlatform* platform) noexcept; + + Builder& window(Window* window) noexcept; + + Builder& renderer(Renderer* renderer) noexcept; + + std::unique_ptr build() const noexcept; + }; + + static std::unique_ptr create(const Builder& builder); + }; +} diff --git a/Eternal/src/core/input/InputDispatcher.cpp b/Eternal/src/core/input/InputDispatcher.cpp new file mode 100644 index 0000000..3e9fd3f --- /dev/null +++ b/Eternal/src/core/input/InputDispatcher.cpp @@ -0,0 +1,10 @@ +#include "core/input/InputDispatcher.h" + +namespace Eternal { + InputDispatcher::InputDispatcher(Eternal::Window* window) : m_Window(window) { + } + + bool InputDispatcher::isKeyPressed(Eternal::KeyCode keycode) const { + return m_Window->isKeyPressed(keycode); + } +} diff --git a/Eternal/src/core/input/InputDispatcher.h b/Eternal/src/core/input/InputDispatcher.h new file mode 100644 index 0000000..1745eb9 --- /dev/null +++ b/Eternal/src/core/input/InputDispatcher.h @@ -0,0 +1,17 @@ +#pragma once + +#include "core/window/Window.h" + +namespace Eternal { + class InputDispatcher { + public: + InputDispatcher() = default; + InputDispatcher(Eternal::Window* window); + ~InputDispatcher() = default; + + bool isKeyPressed(Eternal::KeyCode keycode) const; + + private : + Eternal::Window* m_Window = nullptr; + }; +} diff --git a/Eternal/src/core/input/KeyCodes.h b/Eternal/src/core/input/KeyCodes.h new file mode 100644 index 0000000..77d4445 --- /dev/null +++ b/Eternal/src/core/input/KeyCodes.h @@ -0,0 +1,143 @@ +#pragma once + +#include "utils/Base.h" + +namespace Eternal { + using KeyCode = uint16_t; + + namespace Key { + enum : KeyCode { + // From glfw3.h + Space = 32, + Apostrophe = 39, /* ' */ + Comma = 44, /* , */ + Minus = 45, /* - */ + Period = 46, /* . */ + Slash = 47, /* / */ + + D0 = 48, /* 0 */ + D1 = 49, /* 1 */ + D2 = 50, /* 2 */ + D3 = 51, /* 3 */ + D4 = 52, /* 4 */ + D5 = 53, /* 5 */ + D6 = 54, /* 6 */ + D7 = 55, /* 7 */ + D8 = 56, /* 8 */ + D9 = 57, /* 9 */ + + Semicolon = 59, /* ; */ + Equal = 61, /* = */ + + A = 65, + B = 66, + C = 67, + D = 68, + E = 69, + F = 70, + G = 71, + H = 72, + I = 73, + J = 74, + K = 75, + L = 76, + M = 77, + N = 78, + O = 79, + P = 80, + Q = 81, + R = 82, + S = 83, + T = 84, + U = 85, + V = 86, + W = 87, + X = 88, + Y = 89, + Z = 90, + + LeftBracket = 91, /* [ */ + Backslash = 92, /* \ */ + RightBracket = 93, /* ] */ + GraveAccent = 96, /* ` */ + + World1 = 161, /* non-US #1 */ + World2 = 162, /* non-US #2 */ + + /* Function keys */ + Escape = 256, + Enter = 257, + Tab = 258, + Backspace = 259, + Insert = 260, + Delete = 261, + Right = 262, + Left = 263, + Down = 264, + Up = 265, + PageUp = 266, + PageDown = 267, + Home = 268, + End = 269, + CapsLock = 280, + ScrollLock = 281, + NumLock = 282, + PrintScreen = 283, + Pause = 284, + F1 = 290, + F2 = 291, + F3 = 292, + F4 = 293, + F5 = 294, + F6 = 295, + F7 = 296, + F8 = 297, + F9 = 298, + F10 = 299, + F11 = 300, + F12 = 301, + F13 = 302, + F14 = 303, + F15 = 304, + F16 = 305, + F17 = 306, + F18 = 307, + F19 = 308, + F20 = 309, + F21 = 310, + F22 = 311, + F23 = 312, + F24 = 313, + F25 = 314, + + /* Keypad */ + KP0 = 320, + KP1 = 321, + KP2 = 322, + KP3 = 323, + KP4 = 324, + KP5 = 325, + KP6 = 326, + KP7 = 327, + KP8 = 328, + KP9 = 329, + KPDecimal = 330, + KPDivide = 331, + KPMultiply = 332, + KPSubtract = 333, + KPAdd = 334, + KPEnter = 335, + KPEqual = 336, + + LeftShift = 340, + LeftControl = 341, + LeftAlt = 342, + LeftSuper = 343, + RightShift = 344, + RightControl = 345, + RightAlt = 346, + RightSuper = 347, + Menu = 348 + }; + } +} diff --git a/Eternal/src/core/log/Logger.cpp b/Eternal/src/core/log/Logger.cpp new file mode 100644 index 0000000..ec4bbf3 --- /dev/null +++ b/Eternal/src/core/log/Logger.cpp @@ -0,0 +1,19 @@ +#include "core/log/Logger.h" + +#include + +namespace Eternal { + std::shared_ptr Logger::m_InternalLogger = nullptr; + + void Logger::Init() { + std::vector logSinks; + logSinks.emplace_back(std::make_shared()); + + logSinks[0]->set_pattern("%^Eternal::%l [%T] %v%$"); + + m_InternalLogger = std::make_shared("Eternal", begin(logSinks), end(logSinks)); + spdlog::register_logger(m_InternalLogger); + m_InternalLogger->set_level(spdlog::level::trace); + m_InternalLogger->flush_on(spdlog::level::trace); + } +} diff --git a/Eternal/src/core/log/Logger.h b/Eternal/src/core/log/Logger.h new file mode 100644 index 0000000..5c01e37 --- /dev/null +++ b/Eternal/src/core/log/Logger.h @@ -0,0 +1,43 @@ +#pragma once + +#define FMT_UNICODE 0 +#include +#include + +namespace Eternal { + class Logger { + public: + static void Init(); + + template + static void Warn(fmt::format_string format, Args&&... args) { + if (m_InternalLogger != nullptr) { + m_InternalLogger->warn(fmt::runtime(format), std::forward(args)...); + } + } + + template + static void Debug(fmt::format_string format, Args&&... args) { + if (m_InternalLogger != nullptr) { + m_InternalLogger->debug(fmt::runtime(format), std::forward(args)...); + } + } + + template + static void Info(fmt::format_string format, Args&&... args) { + if (m_InternalLogger != nullptr) { + m_InternalLogger->info(fmt::runtime(format), std::forward(args)...); + } + } + + template + static void Error(fmt::format_string format, Args&&... args) { + if (m_InternalLogger != nullptr) { + m_InternalLogger->error(fmt::runtime(format), std::forward(args)...); + } + } + + private: + static std::shared_ptr m_InternalLogger; + }; +} diff --git a/Eternal/src/core/resource/Image.cpp b/Eternal/src/core/resource/Image.cpp index 7a76e33..5a25d99 100644 --- a/Eternal/src/core/resource/Image.cpp +++ b/Eternal/src/core/resource/Image.cpp @@ -1,4 +1,4 @@ -#include "Image.h" +#include "core/resource/Image.h" #define STB_IMAGE_IMPLEMENTATION #include diff --git a/Eternal/src/core/resource/Image.h b/Eternal/src/core/resource/Image.h index 3609400..55a6364 100644 --- a/Eternal/src/core/resource/Image.h +++ b/Eternal/src/core/resource/Image.h @@ -1,6 +1,7 @@ #pragma once #include "core/resource/Resource.h" + #include namespace Eternal { diff --git a/Eternal/src/core/resource/Mesh.cpp b/Eternal/src/core/resource/Mesh.cpp index ba06b0a..80a60ad 100644 --- a/Eternal/src/core/resource/Mesh.cpp +++ b/Eternal/src/core/resource/Mesh.cpp @@ -1,92 +1,89 @@ #include "Mesh.h" #define TINYOBJLOADER_IMPLEMENTATION -#include +#include "utils/TinyObjLoader.h" namespace std { - template <> - struct hash - { - size_t operator()(Eternal::Vertex const& vertex) const - { - size_t seed = 0; - Eternal::hashCombine(seed, - vertex.position.x, vertex.position.y, vertex.position.z, - vertex.color.x, vertex.color.y, vertex.color.z, - vertex.normal.x, vertex.normal.y, vertex.normal.z, - vertex.uv.x, vertex.uv.y); - return seed; - } - }; + template<> + struct hash { + size_t operator()(Eternal::Vertex const& vertex) const noexcept { + size_t seed = 0; + Eternal::hashCombine(seed, + vertex.position.x, vertex.position.y, vertex.position.z, + vertex.color.x, vertex.color.y, vertex.color.z, + vertex.normal.x, vertex.normal.y, vertex.normal.z, + vertex.uv.x, vertex.uv.y); + return seed; + } + }; } namespace Eternal { + Mesh::Mesh() { + } - Mesh::Mesh() {} + bool Mesh::load(const std::string& path) { + tinyobj::attrib_t attrib; + std::vector shapes; + std::vector materials; + std::string warn, err; - bool Mesh::load(const std::string& path) { - tinyobj::attrib_t attrib; - std::vector shapes; - std::vector materials; - std::string warn, err; + if (!tinyobj::LoadObj(&attrib, &shapes, &materials, &warn, &err, path.c_str())) { + ETERNAL_ASSERT_LOG(true, warn + err); + return false; + } - if (!tinyobj::LoadObj(&attrib, &shapes, &materials, &warn, &err, path.c_str())) { - ETERNAL_ASSERT_LOG(true, warn + err); - return false; - } + std::unordered_map uniqueVertices{}; + for (const auto& shape: shapes) { + for (const auto& index: shape.mesh.indices) { + Vertex vertex{}; - std::unordered_map uniqueVertices{}; - for (const auto& shape : shapes) { - for (const auto& index : shape.mesh.indices) { - Vertex vertex{}; + if (index.vertex_index >= 0) { + vertex.position = { + attrib.vertices[3 * index.vertex_index + 0], + attrib.vertices[3 * index.vertex_index + 1], + attrib.vertices[3 * index.vertex_index + 2], + }; - if (index.vertex_index >= 0) { - vertex.position = { - attrib.vertices[3 * index.vertex_index + 0], - attrib.vertices[3 * index.vertex_index + 1], - attrib.vertices[3 * index.vertex_index + 2], - }; + if (attrib.colors.empty()) { + vertex.color = {1.0f, 1.0f, 1.0f}; + } else { + vertex.color = { + attrib.colors[3 * index.vertex_index + 0], + attrib.colors[3 * index.vertex_index + 1], + attrib.colors[3 * index.vertex_index + 2], + }; + } + } - if (attrib.colors.empty()) { - vertex.color = { 1.0f, 1.0f, 1.0f }; - } - else { - vertex.color = { - attrib.colors[3 * index.vertex_index + 0], - attrib.colors[3 * index.vertex_index + 1], - attrib.colors[3 * index.vertex_index + 2], - }; - } - } + if (index.normal_index >= 0) { + vertex.normal = { + attrib.normals[3 * index.normal_index + 0], + attrib.normals[3 * index.normal_index + 1], + attrib.normals[3 * index.normal_index + 2], + }; + } - if (index.normal_index >= 0) { - vertex.normal = { - attrib.normals[3 * index.normal_index + 0], - attrib.normals[3 * index.normal_index + 1], - attrib.normals[3 * index.normal_index + 2], - }; - } + if (index.texcoord_index >= 0) { + vertex.uv = { + attrib.texcoords[2 * index.texcoord_index + 0], + attrib.texcoords[2 * index.texcoord_index + 1], + }; + } - if (index.texcoord_index >= 0) { - vertex.uv = { - attrib.texcoords[2 * index.texcoord_index + 0], - attrib.texcoords[2 * index.texcoord_index + 1], - }; - } + if (uniqueVertices.count(vertex) == 0) { + uniqueVertices[vertex] = static_cast(m_Vertices.size()); + m_Vertices.push_back(vertex); + } + m_Indices.push_back(uniqueVertices[vertex]); + } + } - if (uniqueVertices.count(vertex) == 0) { - uniqueVertices[vertex] = static_cast(m_Vertices.size()); - m_Vertices.push_back(vertex); - } - m_Indices.push_back(uniqueVertices[vertex]); - } - } + return true; + } - return true; - } - - Mesh::~Mesh() { - m_Vertices.clear(); - m_Indices.clear(); - } + Mesh::~Mesh() { + m_Vertices.clear(); + m_Indices.clear(); + } } diff --git a/Eternal/src/core/resource/Mesh.h b/Eternal/src/core/resource/Mesh.h index b40cd30..da8a7b2 100644 --- a/Eternal/src/core/resource/Mesh.h +++ b/Eternal/src/core/resource/Mesh.h @@ -1,25 +1,21 @@ #pragma once -#include -#include -#include +#include "core/resource/Resource.h" +#include "core/graphics/Vertex.h" -namespace Eternal -{ - class Mesh : public Resource { - public: - Mesh(); - Mesh(const Mesh& other) = delete; - Mesh& operator=(const Mesh&) = delete; - bool load(const std::string& path) override; - const std::vector& getVertices() const { return m_Vertices; } - const std::vector& getIndices() const { return m_Indices; } - virtual ~Mesh(); +namespace Eternal { + class Mesh : public Resource { + public: + Mesh(); + Mesh(const Mesh& other) = delete; + Mesh& operator=(const Mesh&) = delete; + bool load(const std::string& path) override; + const std::vector& getVertices() const { return m_Vertices; } + const std::vector& getIndices() const { return m_Indices; } + virtual ~Mesh(); - private: - std::vector m_Vertices; - std::vector m_Indices; - - }; - -} \ No newline at end of file + private: + std::vector m_Vertices; + std::vector m_Indices; + }; +} diff --git a/Eternal/src/core/resource/Resource.h b/Eternal/src/core/resource/Resource.h index fca9937..e92bda0 100644 --- a/Eternal/src/core/resource/Resource.h +++ b/Eternal/src/core/resource/Resource.h @@ -1,21 +1,20 @@ #pragma once -#include -#include +#include "utils/Base.h" namespace Eternal { - class Resource { - public: - Resource() = default; - Resource(const Resource&) = delete; - Resource& operator=(const Resource&) = delete; - const std::string& getName() const { return m_Name; } - const std::string& getPath() const { return m_Path; } - void setPath(const std::string& path) { m_Path = path; } - virtual bool load(const std::string& path) = 0; - virtual ~Resource() = default; + class Resource { + public: + Resource() = default; + Resource(const Resource&) = delete; + Resource& operator=(const Resource&) = delete; + const std::string& getName() const { return m_Name; } + const std::string& getPath() const { return m_Path; } + void setPath(const std::string& path) { m_Path = path; } + virtual bool load(const std::string& path) = 0; + virtual ~Resource() = default; - protected: - std::string m_Name; - std::string m_Path; - }; -} \ No newline at end of file + protected: + std::string m_Name; + std::string m_Path; + }; +} diff --git a/Eternal/src/core/resource/ResourceManager.h b/Eternal/src/core/resource/ResourceManager.h index 1b328f4..61e47c0 100644 --- a/Eternal/src/core/resource/ResourceManager.h +++ b/Eternal/src/core/resource/ResourceManager.h @@ -1,69 +1,69 @@ #pragma once -#include -#include "Resource.h" +#include "utils/Base.h" +#include "core/resource/Resource.h" namespace Eternal { - class ResourceManager { - public: - ResourceManager(const ResourceManager&) = delete; - ResourceManager& operator=(const ResourceManager&) = delete; + class ResourceManager { + public: + ResourceManager(const ResourceManager&) = delete; + ResourceManager& operator=(const ResourceManager&) = delete; - static ResourceManager& get() { - static ResourceManager instance; - return instance; - } + static ResourceManager& get() { + static ResourceManager instance; + return instance; + } - ~ResourceManager() { - for (auto& [path, resourcePtr] : m_Resources) { - delete resourcePtr; - } - m_Resources.clear(); - } + ~ResourceManager() { + for (auto& [path, resourcePtr]: m_Resources) { + delete resourcePtr; + } + m_Resources.clear(); + } - public: - template::value, int>::type = 0> - ResourceType* loadResource(const std::string& path) { - auto it = m_Resources.find(path); - if (it != m_Resources.end()) { - return dynamic_cast(it->second); - } + public: + template, int> = 0> + ResourceType* loadResource(const std::string& path) { + auto it = m_Resources.find(path); + if (it != m_Resources.end()) { + return dynamic_cast(it->second); + } - ResourceType* resource = Memory::Allocate(); - if (!resource->load(path)) { - delete resource; - return nullptr; - } + ResourceType* resource = Memory::Allocate(); + if (!resource->load(path)) { + delete resource; + return nullptr; + } - resource->setPath(path); - m_Resources[path] = resource; - return resource; - } + resource->setPath(path); + m_Resources[path] = resource; + return resource; + } - template::value, int>::type = 0> - std::future loadResourceAsync(const std::string& path) { - return std::async(std::launch::async, - [this, path]() -> ResourceType* { - std::lock_guard lock(m_Mutex); - return this->loadResource(path); - } - ); - } + template, int> = 0> + std::future loadResourceAsync(const std::string& path) { + return std::async(std::launch::async, + [this, path]() -> ResourceType* { + std::lock_guard lock(m_Mutex); + return this->loadResource(path); + } + ); + } - void unloadResource(Resource* resource) { - if (resource) { - auto it = m_Resources.find(resource->getPath()); - if (it != m_Resources.end()) { - delete it->second; - m_Resources.erase(it); - } - } - } + void unloadResource(Resource* resource) { + if (resource) { + auto it = m_Resources.find(resource->getPath()); + if (it != m_Resources.end()) { + delete it->second; + m_Resources.erase(it); + } + } + } - private: - ResourceManager() = default; + private: + ResourceManager() = default; - std::unordered_map m_Resources; - std::mutex m_Mutex; - }; -} \ No newline at end of file + std::unordered_map m_Resources; + std::mutex m_Mutex; + }; +} diff --git a/Eternal/src/core/resource/ShaderProgram.cpp b/Eternal/src/core/resource/ShaderProgram.cpp index d1371af..2cd275d 100644 --- a/Eternal/src/core/resource/ShaderProgram.cpp +++ b/Eternal/src/core/resource/ShaderProgram.cpp @@ -1,4 +1,4 @@ -#include "ShaderProgram.h" +#include "core/resource/ShaderProgram.h" namespace Eternal { ShaderProgram::ShaderProgram() {} diff --git a/Eternal/src/core/resource/ShaderProgram.h b/Eternal/src/core/resource/ShaderProgram.h index 4bfbc22..6156c50 100644 --- a/Eternal/src/core/resource/ShaderProgram.h +++ b/Eternal/src/core/resource/ShaderProgram.h @@ -1,24 +1,23 @@ #pragma once -#include -#include -#include -#include "Resource.h" +#include "utils/Base.h" +#include "core/resource/Resource.h" namespace Eternal { - // This is basic Shader file resource class that can be loaded from a file. - class ShaderProgram : public Resource { - using Blob = std::vector; - public: - ShaderProgram(); - ShaderProgram(const ShaderProgram&) = delete; - ShaderProgram& operator=(const ShaderProgram&) = delete; - bool load(const std::string& path) override; - const uint32_t* getBlob() { return reinterpret_cast(m_Blob.data()); } - size_t getBlobSize() const { return m_Blob.size(); } - virtual ~ShaderProgram(); + // This is basic Shader file resource class that can be loaded from a file. + class ShaderProgram : public Resource { + using Blob = std::vector; - private: - Blob m_Blob; - }; + public: + ShaderProgram(); + ShaderProgram(const ShaderProgram&) = delete; + ShaderProgram& operator=(const ShaderProgram&) = delete; + bool load(const std::string& path) override; + const uint32_t* getBlob() { return reinterpret_cast(m_Blob.data()); } + size_t getBlobSize() const { return m_Blob.size(); } + virtual ~ShaderProgram(); + + private: + Blob m_Blob; + }; } diff --git a/Eternal/src/core/scene/Entity.h b/Eternal/src/core/scene/Entity.h index f955527..fb41e8a 100644 --- a/Eternal/src/core/scene/Entity.h +++ b/Eternal/src/core/scene/Entity.h @@ -1,63 +1,61 @@ #pragma once -#include -#include -#include "Scene.h" -#include "IdComponent.h" -#include "NameComponent.h" -#include +#include "utils/Base.h" +#include "utils/UUID.h" +#include "core/scene/Scene.h" +#include "core/scene/IdComponent.h" +#include "core/scene/NameComponent.h" namespace Eternal { - class Entity { - public: - Entity() = default; - - explicit Entity(entt::entity entityHandle, Eternal::Scene* scene) - : m_EntityHandle(entityHandle), m_Scene(scene) { - } - - template - T& addComponent(Args&&... args) { - T& component = m_Scene->m_Registry.emplace(m_EntityHandle, std::forward(args)...); - m_Scene->notifyObservers(*this, component); - return component; - } - - template - T& addOrReplaceComponent(Args&&... args) { - T& component = m_Scene->m_Registry.emplace_or_replace(m_EntityHandle, std::forward(args)...); - m_Scene->notifyObservers(*this, component); - return component; - } - - template - T& getComponent() { - return m_Scene->m_Registry.get(m_EntityHandle); - } - - template - T* tryGetComponent() { - return m_Scene->m_Registry.try_get(m_EntityHandle); - } - - template - void removeComponent() { - m_Scene->m_Registry.remove(m_EntityHandle); - } - - UUID getUUID() { - auto& idComponent = m_Scene->m_Registry.get(m_EntityHandle); - return idComponent.getId(); - } - - std::string getName() { - auto& nameComponent = m_Scene->m_Registry.get(m_EntityHandle); - return nameComponent.getName(); - } - - private: - - entt::entity m_EntityHandle; - Eternal::Scene* m_Scene = nullptr; - }; -} \ No newline at end of file + class Entity { + public: + Entity() = default; + + explicit Entity(entt::entity entityHandle, Eternal::Scene* scene) + : m_EntityHandle(entityHandle), m_Scene(scene) { + } + + template + T& addComponent(Args&&... args) { + T& component = m_Scene->m_Registry.emplace(m_EntityHandle, std::forward(args)...); + m_Scene->notifyObservers(*this, component); + return component; + } + + template + T& addOrReplaceComponent(Args&&... args) { + T& component = m_Scene->m_Registry.emplace_or_replace(m_EntityHandle, std::forward(args)...); + m_Scene->notifyObservers(*this, component); + return component; + } + + template + T& getComponent() { + return m_Scene->m_Registry.get(m_EntityHandle); + } + + template + T* tryGetComponent() { + return m_Scene->m_Registry.try_get(m_EntityHandle); + } + + template + void removeComponent() { + m_Scene->m_Registry.remove(m_EntityHandle); + } + + UUID getUUID() { + auto& idComponent = m_Scene->m_Registry.get(m_EntityHandle); + return idComponent.getId(); + } + + std::string getName() { + auto& nameComponent = m_Scene->m_Registry.get(m_EntityHandle); + return nameComponent.getName(); + } + + private: + entt::entity m_EntityHandle; + Eternal::Scene* m_Scene = nullptr; + }; +} diff --git a/Eternal/src/core/scene/IdComponent.h b/Eternal/src/core/scene/IdComponent.h index 556db20..05dc917 100644 --- a/Eternal/src/core/scene/IdComponent.h +++ b/Eternal/src/core/scene/IdComponent.h @@ -1,16 +1,20 @@ #pragma once -#include -#include + +#include "utils/UUID.h" namespace Eternal { - struct IdComponent { - public: - IdComponent() : m_Id(UUID()) {} - IdComponent(const UUID& id) : m_Id(id) {} - IdComponent(const IdComponent&) = default; - UUID getId() { return m_Id; } + struct IdComponent { + public: + IdComponent() : m_Id(UUID()) { + } + + IdComponent(const UUID& id) : m_Id(id) { + } + + IdComponent(const IdComponent&) = default; + UUID getId() { return m_Id; } - private: - UUID m_Id; - }; -} \ No newline at end of file + private: + UUID m_Id; + }; +} diff --git a/Eternal/src/core/scene/MaterialComponent.h b/Eternal/src/core/scene/MaterialComponent.h index 90273af..d072cf6 100644 --- a/Eternal/src/core/scene/MaterialComponent.h +++ b/Eternal/src/core/scene/MaterialComponent.h @@ -1,21 +1,35 @@ #pragma once -#include -#include +#include "utils/Base.h" +#include "core/resource/Image.h" namespace Eternal { - struct MaterialComponent { - public: - MaterialComponent() = default; - ~MaterialComponent() = default; + enum PipelineParams { + NONE = BIT(0), + UBO = BIT(1), + SAMPLER = BIT(3), + }; - MaterialComponent(Image* albedoTexture) { - m_AlbedoTexture = albedoTexture; - } + constexpr uint32_t eDefaultPipelineLayoutBitMask = PipelineParams::UBO; - const Image* getAlbedoTexture() const { return m_AlbedoTexture; } + struct MaterialComponent { + public: + MaterialComponent() = default; + ~MaterialComponent() = default; - private: - Image* m_AlbedoTexture = nullptr; - }; -} \ No newline at end of file + MaterialComponent(Image* albedoTexture = nullptr) { + m_AlbedoTexture = albedoTexture; + if (m_AlbedoTexture) { + m_PipelineLayoutBitMask = m_PipelineLayoutBitMask |= PipelineParams::SAMPLER; + } + } + + uint32_t getPipelineLayoutBitMask() const { return m_PipelineLayoutBitMask; } + + const Image* getAlbedoTexture() const { return m_AlbedoTexture; } + + private: + Image* m_AlbedoTexture = nullptr; + uint32_t m_PipelineLayoutBitMask = PipelineParams::UBO | PipelineParams::SAMPLER; + }; +} diff --git a/Eternal/src/core/scene/NameComponent.h b/Eternal/src/core/scene/NameComponent.h index 57e3cae..2134be9 100644 --- a/Eternal/src/core/scene/NameComponent.h +++ b/Eternal/src/core/scene/NameComponent.h @@ -1,6 +1,6 @@ #pragma once -#include +#include "utils/Base.h" namespace Eternal { struct NameComponent { diff --git a/Eternal/src/core/scene/RenderComponent.h b/Eternal/src/core/scene/RenderComponent.h index bd3a9c2..de6f81e 100644 --- a/Eternal/src/core/scene/RenderComponent.h +++ b/Eternal/src/core/scene/RenderComponent.h @@ -1,22 +1,24 @@ #pragma once -#include -#include +#include "utils/Base.h" +#include "core/graphics/Vertex.h" namespace Eternal { - struct RenderComponent { - public: - RenderComponent() = default; - RenderComponent(std::vector vertices, std::vector indices) - : m_Vertices(vertices), m_Indices(indices) { } - ~RenderComponent() = default; + struct RenderComponent { + public: + RenderComponent() = default; - const std::vector& getVertices() const { return m_Vertices; } - const std::vector& getIndices() const { return m_Indices; } + RenderComponent(std::vector vertices, std::vector indices) + : m_Vertices(vertices), m_Indices(indices) { + } - private: - std::vector m_Vertices; - std::vector m_Indices; + ~RenderComponent() = default; - }; -} \ No newline at end of file + const std::vector& getVertices() const { return m_Vertices; } + const std::vector& getIndices() const { return m_Indices; } + + private: + std::vector m_Vertices; + std::vector m_Indices; + }; +} diff --git a/Eternal/src/core/scene/Scene.cpp b/Eternal/src/core/scene/Scene.cpp index db3d7be..0b9a0b1 100644 --- a/Eternal/src/core/scene/Scene.cpp +++ b/Eternal/src/core/scene/Scene.cpp @@ -1,12 +1,42 @@ -#include "Scene.h" -#include "Entity.h" +#include "core/scene/Scene.h" +#include "core/scene/Entity.h" +#include "core/scene/MaterialComponent.h" +#include "core/scene/RenderComponent.h" +#include "core/resource/Image.h" +#include "core/resource/Mesh.h" +#include "core/resource/ResourceManager.h" namespace Eternal { - Entity Eternal::Scene::createEntity(std::string name) { - auto entityHandle = m_Registry.create(); - Entity entity(entityHandle, this); - entity.addComponent(); - entity.addComponent(name); - return entity; - } + Entity Eternal::Scene::createEntity(std::string name) { + auto entityHandle = m_Registry.create(); + Entity entity(entityHandle, this); + entity.addComponent(); + entity.addComponent(name); + return entity; + } + + void Eternal::Scene::addEntity(TestEntityDetails entity) { + const Mesh* mesh = ResourceManager::get().loadResource(entity.filePath); + if (!mesh) { + Eternal::Logger::Error("Failed to load mesh from path: {}", entity.filePath); + return; + } + + Eternal::Logger::Info("Obj Vertices: {}", mesh->getVertices().size()); + + Eternal::Entity model = createEntity(entity.name); + model.addComponent(mesh->getVertices(), mesh->getIndices()); + model.addComponent(entity.initialPosition); + + if (entity.texturePath.empty()) return; + Image* texture = ResourceManager::get().loadResource(entity.texturePath); + + if (!texture) { + Eternal::Logger::Error("Failed to load texture from path: {}", entity.texturePath); + model.addComponent(texture); + return; + } + + model.addComponent(texture); + } } diff --git a/Eternal/src/core/scene/Scene.h b/Eternal/src/core/scene/Scene.h index 339abb9..1d434ef 100644 --- a/Eternal/src/core/scene/Scene.h +++ b/Eternal/src/core/scene/Scene.h @@ -1,11 +1,20 @@ #pragma once -#include "entt/entt.hpp" + #include "utils/Base.h" -#include "TransformComponent.h" +#include "core/scene/TransformComponent.h" + +#include namespace Eternal { class Entity; + struct TestEntityDetails { + std::string name = "test_entity"; + std::string filePath = "res/models/cube.obj"; + std::string texturePath = ""; + glm::vec3 initialPosition = glm::vec3(0.0f, 0.0f, 0.0f); + }; + class Scene { public: Scene() = default; @@ -14,16 +23,18 @@ namespace Eternal { Entity createEntity(std::string name); + void addEntity(TestEntityDetails testEntity); + template auto getAllEntityWith() { return m_Registry.view(); } template - void onComponentAdded(std::function callback) { + void onComponentAdded(std::function callback) { auto typeIndex = std::type_index(typeid(T)); - auto callbackFunction = [callback](Entity entity, void* component) { + auto callbackFunction = [callback](Entity& entity, void* component) { callback(entity, *static_cast(component)); }; @@ -32,7 +43,7 @@ namespace Eternal { private: template - void notifyObservers(Entity entity, T& component) { + void notifyObservers(Entity& entity, T& component) { auto it = m_ComponentAddedObservers.find(std::type_index(typeid(T))); if (it != m_ComponentAddedObservers.end()) { for (const auto& observer: it->second) { @@ -43,7 +54,7 @@ namespace Eternal { entt::registry m_Registry; - using ObserverFunction = std::function; + using ObserverFunction = std::function; std::unordered_map > m_ComponentAddedObservers; friend class Entity; diff --git a/Eternal/src/core/window/Window.cpp b/Eternal/src/core/window/Window.cpp new file mode 100644 index 0000000..c8f2b96 --- /dev/null +++ b/Eternal/src/core/window/Window.cpp @@ -0,0 +1,44 @@ +#include "core/window/Window.h" +#include +#include + +namespace Eternal { + std::unique_ptr Window::create(const Builder& builder) { + System system = Eternal::detectSystem(); + + switch (system) { + case System::WINDOWS: + return std::make_unique(builder); + break; + default: + return nullptr; + break; + } + } + + Window::Builder::Builder() noexcept = default; + Window::Builder::Builder(Builder const& rhs) noexcept = default; + Window::Builder::Builder(Builder&& rhs) noexcept = default; + Window::Builder::~Builder() noexcept = default; + Window::Builder& Window::Builder::operator=(Builder const& rhs) noexcept = default; + Window::Builder& Window::Builder::operator=(Builder&& rhs) noexcept = default; + + Window::Builder& Window::Builder::title(const std::string& title) noexcept { + mImpl->title = title; + return *this; + } + + Window::Builder& Window::Builder::height(uint32_t height) noexcept { + mImpl->height = height; + return *this; + } + + Window::Builder& Window::Builder::width(uint32_t width) noexcept { + mImpl->width = width; + return *this; + } + + std::unique_ptr Window::Builder::build() const noexcept { + return Window::create(*this); + } +} diff --git a/Eternal/src/core/window/Window.h b/Eternal/src/core/window/Window.h new file mode 100644 index 0000000..ab8c919 --- /dev/null +++ b/Eternal/src/core/window/Window.h @@ -0,0 +1,60 @@ +#pragma once + +#include "utils/Base.h" +#include "core/event/Event.h" +#include "core/input/KeyCodes.h" + +#include + +namespace Eternal { + enum CursorInputMode { + LOCKED, + NORMAL + }; + + class Window { + public: + using EventCallback = std::function; + + virtual ~Window() = default; + virtual void onUpdate() = 0; + virtual uint32_t getHeight() const = 0; + virtual uint32_t getWidth() const = 0; + virtual float getAspectRatio() const = 0; + virtual void* getNativeWindow() const = 0; + virtual void setCursorInputMode(CursorInputMode inputMode) = 0; + virtual bool shouldClose() const = 0; + virtual void shutDown() const = 0; + virtual bool isMinimized() const = 0; + virtual void setEventCallBack(const EventCallback& callback) = 0; + virtual bool isKeyPressed(Eternal::KeyCode keycode) const = 0; + + struct BuilderDetails { + std::string title = ""; + uint32_t height = 0; + uint32_t width = 0; + }; + + class Builder : public utils::PrivateImplementation { + friend class Window; + friend class WindowsWindow; + + public: + Builder() noexcept; + Builder(Builder const& rhs) noexcept; + Builder(Builder&& rhs) noexcept; + ~Builder() noexcept; + Builder& operator=(Builder const& rhs) noexcept; + Builder& operator=(Builder&& rhs) noexcept; + Builder& title(const std::string& title) noexcept; + Builder& width(uint32_t witdth) noexcept; + Builder& height(uint32_t height) noexcept; + std::unique_ptr build() const noexcept; + }; + + static std::unique_ptr create(const Builder& builder); + + protected: + bool m_IsWindowResized = false; + }; +} diff --git a/Eternal/src/core/window/WindowsWindow.cpp b/Eternal/src/core/window/WindowsWindow.cpp new file mode 100644 index 0000000..f36761d --- /dev/null +++ b/Eternal/src/core/window/WindowsWindow.cpp @@ -0,0 +1,136 @@ +#include "core/window/WindowsWindow.h" +#include "core/event/KeyEvents.h" +#include "core/event/MouseEvents.h" +#include "core/event/WindowEvent.h" +#include "core/resource/ResourceManager.h" +#include "core/resource/Image.h" + +namespace Eternal { + WindowsWindow::WindowsWindow(const Builder& builder) { + m_Data.title = builder->title; + m_Data.height = builder->height; + m_Data.width = builder->width; + + glfwInit(); + + glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); + + glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE); + + + m_Window = glfwCreateWindow(m_Data.width, m_Data.height, m_Data.title.c_str(), nullptr, nullptr); + ETERNAL_ASSERT(m_Window != nullptr, "Failed to create GLFW window"); + + glfwSetWindowUserPointer(m_Window, &m_Data); + + // glfwSetInputMode(m_Window, GLFW_CURSOR, GLFW_CURSOR_DISABLED); + + glfwSetFramebufferSizeCallback(m_Window, [](GLFWwindow* window, int width, int height) { + const WindowData& windowData = *(static_cast(glfwGetWindowUserPointer(window)));\ + WindowResizeEvent event(width, height); + windowData.eventCallback(event); + }); + + glfwSetKeyCallback(m_Window, [](GLFWwindow* window, int key, int scancode, int action, int mods) { + const WindowData& windowData = *(static_cast(glfwGetWindowUserPointer(window))); + switch (action) { + case GLFW_PRESS: { + KeyPressedEvent event(key, 0); + windowData.eventCallback(event); + break; + } + case GLFW_RELEASE: { + KeyReleasedEvent event(key); + windowData.eventCallback(event); + break; + } + case GLFW_REPEAT: { + KeyPressedEvent event(key, true); + windowData.eventCallback(event); + break; + } + default: break; + } + }); + + glfwSetCursorPosCallback(m_Window, [](GLFWwindow* window, double xpos, double ypos) { + WindowData& windowData = *(static_cast(glfwGetWindowUserPointer(window))); + MouseMovedEvent event(xpos, ypos); + windowData.eventCallback(event); + }); + + Logger::Info("Current Working Path {} , Accessing Window Icon", std::filesystem::current_path().string()); + setWindowIcon(WINDOW_ICON_PATH, m_Window); + + Eternal::Logger::Info("Window Created"); + } + + void WindowsWindow::onUpdate() { + glfwPollEvents(); + } + + void WindowsWindow::setCursorInputMode(CursorInputMode inputMode) { + int cursorInputMode; + if (inputMode == CursorInputMode::LOCKED) { + cursorInputMode = GLFW_CURSOR_DISABLED; + } else { + cursorInputMode = GLFW_CURSOR_NORMAL; + } + glfwSetInputMode(m_Window, GLFW_CURSOR, cursorInputMode); + } + + bool WindowsWindow::shouldClose() const { + return glfwWindowShouldClose(m_Window); + } + + void WindowsWindow::shutDown() const { + if (m_Window != nullptr) { + glfwDestroyWindow(m_Window); + } else { + Eternal::Logger::Error("mWindow Pointer is null"); + } + + glfwTerminate(); + + Eternal::Logger::Info("Window Destroyed"); + } + + vk::SurfaceKHR WindowsWindow::createWindowSurface(vk::Instance instance) const { + ETERNAL_ASSERT(m_Window != nullptr, "Window is null"); + + vk::SurfaceKHR surface = nullptr; + if (glfwCreateWindowSurface(instance, m_Window, nullptr, reinterpret_cast(&surface)) != + VK_SUCCESS) { + Eternal::Logger::Error("Failed to create window surface"); + return nullptr; + } + return surface; + } + + vk::Extent2D WindowsWindow::getExtent() const { + ETERNAL_ASSERT(m_Window != nullptr, "Window is null"); + int width = 0, height = 0; + glfwGetFramebufferSize(m_Window, &width, &height); + return {static_cast(width), static_cast(height)}; + } + + void WindowsWindow::setWindowIcon(const std::filesystem::path& path, GLFWwindow* window) { + if (window == nullptr) { + Eternal::Logger::Error("Trying to set icon on null window (GLFW)"); + return; + } + + Image* image = ResourceManager::get().loadResource(path.string()); + GLFWimage icon = image->getGLFWImage(); + glfwSetWindowIcon(window, 1, &icon); + } + + bool WindowsWindow::isKeyPressed(Eternal::KeyCode keycode) const { + auto state = glfwGetKey(m_Window, keycode); + return state == GLFW_PRESS; + } + + WindowsWindow::~WindowsWindow() { + WindowsWindow::shutDown(); + } +} diff --git a/Eternal/src/core/window/WindowsWindow.h b/Eternal/src/core/window/WindowsWindow.h new file mode 100644 index 0000000..2242a1d --- /dev/null +++ b/Eternal/src/core/window/WindowsWindow.h @@ -0,0 +1,64 @@ +#pragma once + +#include "core/graphics/vulkan/VulkanWindow.h" + +#include +#include + + +namespace Eternal { + constexpr const char* WINDOW_ICON_PATH = "res/PNGs/eternal_logo.png"; + + class WindowsWindow : public VulkanWindow { + public: + WindowsWindow(const Builder& builder); + + ~WindowsWindow() override; + + void onUpdate() override; + + virtual uint32_t getHeight() const override { return m_Data.height; } + + virtual uint32_t getWidth() const override { return m_Data.width; } + + virtual void* getNativeWindow() const override { return m_Window; } + + virtual void setCursorInputMode(CursorInputMode inputMode) override; + + virtual bool shouldClose() const override; + + virtual void shutDown() const override; + + bool isMinimized() const override { return m_Data.height == 0 || m_Data.width == 0; } + + virtual float getAspectRatio() const override { + return static_cast(m_Data.width) / static_cast(m_Data.height); + } + + virtual void setEventCallBack(const EventCallback& callback) override { + m_Data.eventCallback = callback; + } + + virtual vk::SurfaceKHR createWindowSurface(vk::Instance instance) const override; + + virtual vk::Extent2D getExtent() const override; + + void setWindowIcon(const std::filesystem::path& path, GLFWwindow* window); + + virtual bool isKeyPressed(Eternal::KeyCode keycode) const override; + + private: + GLFWwindow* m_Window = nullptr; + + struct WindowData { + std::string title; + uint32_t height = 0; + uint32_t width = 0; + bool VSync; + + EventCallback eventCallback; + }; + + WindowData m_Data; + }; +} diff --git a/Eternal/src/utils/Base.h b/Eternal/src/utils/Base.h index c290f10..ba25aec 100644 --- a/Eternal/src/utils/Base.h +++ b/Eternal/src/utils/Base.h @@ -1,23 +1,25 @@ #pragma once +#include "core/log/Logger.h" +#include "utils/PrivateImplementationImpl.h" + #include #include #include +#include #include #include #include #include #include #include +#include +#include #include #include #include #include -#include -#include - -#define ENABLE_LOGS 1 #define ETERNAL_FLAG_ENABLED(flags) ((flags & 1) == 1) #define ETERNAL_ASSERT(condition, message) \ @@ -35,28 +37,29 @@ } \ } while (0) +#define ETERNAL_BIND_EVENT_FN(fn) [this](auto&&... args) -> decltype(auto) { return this->fn(std::forward(args)...); } + +#define BIT(x) (1 << x) +#define IS_BIT_SET(value, bit) (((value) & (bit)) == (bit)) + namespace Eternal { - constexpr uint32_t const INVALID_VK_INDEX = 0xFFFFFFFF; - - template - void hashCombine(std::size_t& seed, const T& v, const Rest&... rest) { - seed ^= std::hash{}(v)+0x9e3779b9 + (seed << 6) + (seed >> 2); - (hashCombine(seed, rest), ...); - }; - - namespace Memory { - template - inline T* Allocate(Args&&... args) { - return new T(std::forward(args)...); - } - - template - inline void Deallocate(T* ptr) { - if (ptr) { - delete ptr; - } - } - } -} + constexpr uint32_t const INVALID_VK_INDEX = 0xFFFFFFFF; + + template + void hashCombine(std::size_t& seed, const T& v, const Rest&... rest) { + seed ^= std::hash{}(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2); + (hashCombine(seed, rest), ...); + }; + namespace Memory { + template + inline T* Allocate(Args&&... args) { + return new T(std::forward(args)...); + } + template + inline void Deallocate(T* ptr) { + delete ptr; + } + } +} diff --git a/Eternal/src/utils/PrivateImplementation.h b/Eternal/src/utils/PrivateImplementation.h index c0a9d48..6629904 100644 --- a/Eternal/src/utils/PrivateImplementation.h +++ b/Eternal/src/utils/PrivateImplementation.h @@ -1,6 +1,5 @@ #pragma once - namespace utils { template class PrivateImplementation { diff --git a/Eternal/src/utils/PrivateImplementationImpl.h b/Eternal/src/utils/PrivateImplementationImpl.h index 54675e3..ee6a372 100644 --- a/Eternal/src/utils/PrivateImplementationImpl.h +++ b/Eternal/src/utils/PrivateImplementationImpl.h @@ -1,6 +1,6 @@ #pragma once -#include "PrivateImplementation.h" +#include "utils/PrivateImplementation.h" #include diff --git a/Eternal/src/utils/UUID.cpp b/Eternal/src/utils/UUID.cpp index 8c53cde..ccf41a4 100644 --- a/Eternal/src/utils/UUID.cpp +++ b/Eternal/src/utils/UUID.cpp @@ -1,13 +1,15 @@ -#include "UUID.h" +#include "utils/UUID.h" + #include namespace Eternal { + static std::random_device s_RandomDevice; + static std::mt19937_64 s_Engine(s_RandomDevice()); + static std::uniform_int_distribution s_UniformDistribution; - static std::random_device s_RandomDevice; - static std::mt19937_64 s_Engine(s_RandomDevice()); - static std::uniform_int_distribution s_UniformDistribution; - - UUID::UUID() : m_UUID(s_UniformDistribution(s_Engine)) {} + UUID::UUID() : m_UUID(s_UniformDistribution(s_Engine)) { + } - UUID::UUID(uint64_t uuid) : m_UUID(uuid) {} + UUID::UUID(uint64_t uuid) : m_UUID(uuid) { + } } diff --git a/Eternal/src/utils/UUID.h b/Eternal/src/utils/UUID.h index 40f77fb..f9f71c7 100644 --- a/Eternal/src/utils/UUID.h +++ b/Eternal/src/utils/UUID.h @@ -1,28 +1,29 @@ #pragma once -#include "Base.h" + +#include "utils/Base.h" namespace Eternal { - class UUID { - public: - UUID(); - UUID(uint64_t uuid); - UUID(const UUID&) = default; + class UUID { + public: + UUID(); + UUID(uint64_t uuid); + UUID(const UUID&) = default; + + operator uint64_t() const { return m_UUID; } - operator uint64_t() const { return m_UUID; } - private: - uint64_t m_UUID; - }; + private: + uint64_t m_UUID; + }; } namespace std { - template struct hash; + template + struct hash; - template<> - struct hash - { - std::size_t operator()(const Eternal::UUID& uuid) const - { - return (uint64_t)uuid; - } - }; -} \ No newline at end of file + template<> + struct hash { + std::size_t operator()(const Eternal::UUID& uuid) const noexcept { + return uuid; + } + }; +} diff --git a/SandBox/CMakeLists.txt b/SandBox/CMakeLists.txt index bbaf4a1..bf154be 100644 --- a/SandBox/CMakeLists.txt +++ b/SandBox/CMakeLists.txt @@ -1,15 +1,15 @@ file(GLOB_RECURSE SANDBOX_SOURCE src/*.cpp src/*.h) -add_executable(EternalEditor ${SANDBOX_SOURCE}) +add_executable(EternalApp ${SANDBOX_SOURCE}) -target_link_libraries(EternalEditor PRIVATE EternalCore) -target_include_directories(EternalEditor PRIVATE +target_link_libraries(EternalApp PRIVATE EternalCore) +target_include_directories(EternalApp PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src ${CMAKE_CURRENT_SOURCE_DIR}/../Vendor/include ${CMAKE_CURRENT_SOURCE_DIR}/../Vendor ) -add_custom_command(TARGET EternalEditor POST_BUILD +add_custom_command(TARGET EternalApp POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_SOURCE_DIR}/res ${CMAKE_CURRENT_BINARY_DIR}/res @@ -28,10 +28,11 @@ set(SHADER_OUTPUT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/res/shader/bin) file(MAKE_DIRECTORY ${SHADER_OUTPUT_DIR}) add_custom_target(Shaders ALL - COMMAND ${GLSLC_EXECUTABLE} -fshader-stage=vertex ${SHADER_DIR}/vert.glsl -o ${SHADER_OUTPUT_DIR}/vert.spv - COMMAND ${GLSLC_EXECUTABLE} -fshader-stage=fragment ${SHADER_DIR}/frag.glsl -o ${SHADER_OUTPUT_DIR}/frag.spv + COMMAND ${GLSLC_EXECUTABLE} -fshader-stage=vertex ${SHADER_DIR}/common_vertex.glsl -o ${SHADER_OUTPUT_DIR}/common_vertex.spv + COMMAND ${GLSLC_EXECUTABLE} -fshader-stage=fragment ${SHADER_DIR}/common_fragment.glsl -o ${SHADER_OUTPUT_DIR}/common_fragment.spv + COMMAND ${GLSLC_EXECUTABLE} -fshader-stage=fragment ${SHADER_DIR}/frag_texture_mapping.glsl -o ${SHADER_OUTPUT_DIR}/frag_texture_mapping.spv WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} COMMENT "Building SPIR-V shaders" ) -add_dependencies(EternalEditor Shaders) \ No newline at end of file +add_dependencies(EternalApp Shaders) \ No newline at end of file diff --git a/SandBox/res/shader/common_fragment.glsl b/SandBox/res/shader/common_fragment.glsl new file mode 100644 index 0000000..3fcea96 --- /dev/null +++ b/SandBox/res/shader/common_fragment.glsl @@ -0,0 +1,9 @@ +#version 450 + +layout(location = 0) in vec3 fragInColor; + +layout (location = 0) out vec4 outColor; + +void main() { + outColor = vec4(fragInColor, 1.0); +} diff --git a/SandBox/res/shader/vert.glsl b/SandBox/res/shader/common_vertex.glsl similarity index 78% rename from SandBox/res/shader/vert.glsl rename to SandBox/res/shader/common_vertex.glsl index 823f47b..816b851 100644 --- a/SandBox/res/shader/vert.glsl +++ b/SandBox/res/shader/common_vertex.glsl @@ -5,7 +5,8 @@ layout(location = 1) in vec3 color; layout(location = 2) in vec3 normal; layout(location = 3) in vec2 uv; -layout(location = 0) out vec2 fragUv; +layout(location = 0) out vec3 fragInColor; +layout(location = 1) out vec2 fragUv; layout(set = 0 , binding = 0) uniform Uniform { mat4 projection; @@ -13,10 +14,8 @@ layout(set = 0 , binding = 0) uniform Uniform { mat4 model; } uniformBuffer; -const vec3 LIGHT_POS = vec3(0.0, 0.0, -7.0); -const float AMBIENT = 0.2; - void main() { fragUv = uv; + fragInColor = color; gl_Position = uniformBuffer.projection * uniformBuffer.view * uniformBuffer.model * vec4(position, 1.0); } diff --git a/SandBox/res/shader/frag.glsl b/SandBox/res/shader/frag.glsl deleted file mode 100644 index 4ab78b1..0000000 --- a/SandBox/res/shader/frag.glsl +++ /dev/null @@ -1,13 +0,0 @@ -#version 450 - -layout(set = 1, binding = 0) uniform sampler2D texSampler; - - -layout (location = 0) in vec2 fragUv; - -layout (location = 0) out vec4 outColor; - -void main() { - vec2 texCoord = vec2(fragUv.x , 1.0 - fragUv.y); - outColor = texture(texSampler, texCoord); -} diff --git a/SandBox/res/shader/frag_texture_mapping.glsl b/SandBox/res/shader/frag_texture_mapping.glsl new file mode 100644 index 0000000..e79c4e0 --- /dev/null +++ b/SandBox/res/shader/frag_texture_mapping.glsl @@ -0,0 +1,13 @@ +#version 450 + +layout(set = 1, binding = 0) uniform sampler2D texSampler; + +layout(location = 0) in vec3 fragInColor; +layout (location = 1) in vec2 fragUv; + +layout (location = 0) out vec4 outColor; + +void main() { + vec2 texCoord = vec2(fragUv.x, 1.0 - fragUv.y); + outColor = texture(texSampler, texCoord); +} diff --git a/SandBox/src/ImGuiApplication.h b/SandBox/src/Application.h similarity index 59% rename from SandBox/src/ImGuiApplication.h rename to SandBox/src/Application.h index ad446e1..1199327 100644 --- a/SandBox/src/ImGuiApplication.h +++ b/SandBox/src/Application.h @@ -1,13 +1,12 @@ #pragma once namespace Eternal { - class ImGuiApplication + class Application { public: - virtual ~ImGuiApplication() = default; + virtual ~Application() = default; virtual void run() = 0; virtual void shutdown() = 0; - virtual void onImGuiRender() = 0; protected: bool m_IsRunning = false; diff --git a/SandBox/src/Editor.cpp b/SandBox/src/Editor.cpp deleted file mode 100644 index 9f49e38..0000000 --- a/SandBox/src/Editor.cpp +++ /dev/null @@ -1,189 +0,0 @@ -#include "Editor.h" -#include "imgui/imgui.h" -#include "imgui/backends/imgui_impl_glfw.h" -#include "imgui/backends/imgui_impl_vulkan.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -void SetEngineRootDirectory() { - std::filesystem::path path = std::filesystem::current_path() / "../Eternal"; - std::filesystem::current_path(path); -} - -namespace Eternal { - Editor::Editor() { - Eternal::Logger::Init(); - - m_Window = Eternal::Window::Builder() - .title(std::string("Eternal Application")) - .height(800) - .width(1200) - .build(); - - m_Engine = Eternal::Engine::Builder() - .applicationName("Eternal Application") - .build(); - - m_Scene = Memory::Allocate(); - - TestEntityDetails testEntity1 = { - "watch_tower_1", - "res/models/wooden_watch_tower.obj", - "res/models/textures/Wood_Tower_Col.jpg", - glm::vec3(0.0f, 0.0f, 0.0f) - }; - - addEntity(testEntity1); - - //TestEntityDetails testEntity2 = { - // "cube", - // "res/models/cube.obj", - // "res/models/textures/Wood_Tower_Col.jpg" , - // glm::vec3(0.0f, 0.0f, -10.0f) - //}; - - //addEntity(testEntity2); - - m_Renderer = m_Engine->createRenderer(m_Window, m_Scene); - - m_EditorCamera = Memory::Allocate(); - - m_IsRunning = true; - } - - void Editor::addEntity(TestEntityDetails entity) { - Mesh* mesh = ResourceManager::get().loadResource(entity.filePath); - if (!mesh) { - Eternal::Logger::Error("Failed to load mesh from path: {}", entity.filePath); - return; - } - - Eternal::Logger::Info("Obj Vertices: {}", mesh->getVertices().size()); - - Eternal::Entity model = m_Scene->createEntity(entity.name); - model.addComponent(mesh->getVertices(), mesh->getIndices()); - model.addComponent(entity.initialPosition); - - if (entity.texturePath != "") { - Image* texture = ResourceManager::get().loadResource(entity.texturePath); - if (!texture) { - Eternal::Logger::Error("Failed to load texture from path: {}", entity.texturePath); - return; - } - model.addComponent(texture); - } - } - - void Editor::addTriangle() { - Eternal::Entity entity = m_Scene->createEntity("Triangle"); - - std::vector vertices = { - {0.0f, 0.5f, 0.0f}, - {-0.5f, -0.5f, 0.0f}, - {0.5f, -0.5f, 0.0f} - }; - - std::vector indices = {1, 0, 2}; - - entity.addComponent(vertices, indices); - } - - void Editor::addCube() { - std::vector cubeVertices = { - {glm::vec3(-0.5f, -0.5f, 0.5f), glm::vec3(1.0f, 0.0f, 0.0f)}, // red - {glm::vec3(-0.5f, 0.5f, 0.5f), glm::vec3(1.0f, 0.5f, 0.0f)}, // orange - {glm::vec3(0.5f, 0.5f, 0.5f), glm::vec3(1.0f, 1.0f, 0.0f)}, // yellow - {glm::vec3(0.5f, -0.5f, 0.5f), glm::vec3(0.0f, 1.0f, 0.0f)}, // green - - {glm::vec3(0.5f, -0.5f, -0.5f), glm::vec3(0.0f, 1.0f, 1.0f)}, // cyan - {glm::vec3(0.5f, 0.5f, -0.5f), glm::vec3(0.0f, 0.0f, 1.0f)}, // blue - {glm::vec3(-0.5f, 0.5f, -0.5f), glm::vec3(1.0f, 0.0f, 1.0f)}, // magenta - {glm::vec3(-0.5f, -0.5f, -0.5f), glm::vec3(0.5f, 0.0f, 0.5f)} // purple - }; - - std::vector cubeIndices = { - 0, 1, 2, 2, 3, 0, // Front - 3, 2, 5, 5, 4, 3, // Right - 4, 5, 6, 6, 7, 4, // Back - 7, 6, 1, 1, 0, 7, // Side - 1, 6, 5, 5, 2, 1, // Top - 7, 0, 3, 3, 4, 7, // Bottom - }; - - Eternal::Entity cube = m_Scene->createEntity("Cube"); - cube.addComponent(cubeVertices, cubeIndices); - cube.addComponent(glm::vec3(0.0f, 0.0f, -10.0f)); - } - - Editor::~Editor() { - Editor::shutdown(); - } - - void Editor::run() { - auto vkRenderer = dynamic_cast(m_Renderer); - - m_ImGuiLayer = Memory::Allocate(vkRenderer, m_Window); - - while (m_IsRunning) { - m_Window->onUpdate(); - - if (FrameInfo* frameInfo = m_Renderer->beginFrame()) { - m_ImGuiLayer->beginFrame(); - onImGuiRender(); - m_Renderer->render(); - m_ImGuiLayer->render(frameInfo); - m_Renderer->endFrame(); - Memory::Deallocate(frameInfo); - } - - m_IsRunning = !m_Window->shouldClose(); - } - } - - Editor* Editor::create() { - return Memory::Allocate(); - } - - void Editor::onImGuiRender() { - ImGui::Begin("Debug Info"); - ImGui::Text("FPS: %.1f", ImGui::GetIO().Framerate); - for (auto e: m_Scene->getAllEntityWith()) { - Eternal::Entity entity = Eternal::Entity(e, m_Scene); - - auto& nameComponent = entity.getComponent(); - ImGui::Text("Entity Name: %s", nameComponent.getName()); - - auto& component = entity.getComponent(); - glm::vec3 translation = component.getTranslation(); - std::string posLabel = "Position " + std::string(nameComponent.getName()); - if (ImGui::DragFloat3(posLabel.c_str(), &translation.x, 0.01f)) { - component.setTranslation(translation); - } - - glm::vec3 rotationDegrees = glm::degrees(component.getRotation()); - std::string rotationLabel = "Rotation " + std::string(nameComponent.getName()); - if (ImGui::SliderFloat3(rotationLabel.c_str(), &rotationDegrees.x, 0.0f, 180.0f, "%.1f")) { - rotationDegrees = glm::clamp(rotationDegrees, 0.0f, 180.0f); - component.setRotation(glm::radians(rotationDegrees)); - } - } - ImGui::End(); - } - - void Editor::shutdown() { - Memory::Deallocate(m_ImGuiLayer); - Memory::Deallocate(m_Engine); - Memory::Deallocate(m_Window); - } -} diff --git a/SandBox/src/Editor.h b/SandBox/src/Editor.h deleted file mode 100644 index c69926c..0000000 --- a/SandBox/src/Editor.h +++ /dev/null @@ -1,43 +0,0 @@ -#include -#include -#include -#include - -#include "ImGuiApplication.h" -#include "core/graphics/Camera.hpp" - -namespace Eternal { - - struct TestEntityDetails { - std::string name = "test_entity"; - std::string filePath = "res/models/cube.obj"; - std::string texturePath = ""; - glm::vec3 initialPosition = glm::vec3(0.0f, 0.0f, 0.0f); - }; - - class Editor : public ImGuiApplication { - public: - Editor(); - ~Editor(); - - static Editor* create(); - - void onImGuiRender() override; - void run() override; - void shutdown() override; - - private: - void addEntity(TestEntityDetails testEntity); - void addTriangle(); - void addCube(); - - Engine* m_Engine = nullptr; - Eternal::Scene* m_Scene = nullptr; - Eternal::Renderer* m_Renderer = nullptr; - Eternal::Camera* m_EditorCamera = nullptr; - Window* m_Window = nullptr; - SwapChain* m_SwapChain = nullptr; - ImGuiLayer* m_ImGuiLayer = nullptr; - - }; -} diff --git a/SandBox/src/EntryPoint.cpp b/SandBox/src/EntryPoint.cpp index ec1c96d..7baa486 100644 --- a/SandBox/src/EntryPoint.cpp +++ b/SandBox/src/EntryPoint.cpp @@ -1,9 +1,7 @@ -#include "Editor.h" +#include "Viewer.h" int main() { - Eternal::Editor* app = Eternal::Editor::create(); - app->run(); - delete app; - - return 0; -} \ No newline at end of file + const auto app = Eternal::Viewer::create(); + app->run(); + return 0; +} diff --git a/SandBox/src/Viewer.cpp b/SandBox/src/Viewer.cpp new file mode 100644 index 0000000..6300822 --- /dev/null +++ b/SandBox/src/Viewer.cpp @@ -0,0 +1,192 @@ +#include "Viewer.h" + +#include "utils/Base.h" + +#include "core/scene/Entity.h" +#include "core/scene/TransformComponent.h" +#include "core/scene/RenderComponent.h" +#include "core/event/EventDispatcher.h" +#include "core/graphics/Vertex.h" + +#include + + +void SetEngineRootDirectory() { + std::filesystem::path path = std::filesystem::current_path() / "../Eternal"; + std::filesystem::current_path(path); +} + +namespace Eternal { + Viewer::Viewer() { + Eternal::Logger::Init(); + + m_Window = Eternal::Window::Builder() + .title(std::string("Eternal Application")) + .height(800) + .width(1200) + .build(); + + m_InputDispatcher = std::make_unique(m_Window.get()); + + m_GraphicsPlatform = Eternal::GraphicsPlatform::Builder() + .applicationName("Eternal Application") + .backend(m_Backend) + .build(); + + m_Scene = std::make_unique(); + setupScene(); + + m_Renderer = Eternal::Renderer::Builder() + .backend(m_Backend) + .platform(m_GraphicsPlatform.get()) + .window(m_Window.get()) + .scene(m_Scene.get()) + .build(); + + m_ImGuiOverlay = Eternal::ImGuiOverlay::Builder() + .backend(m_Backend) + .platform(m_GraphicsPlatform.get()) + .window(m_Window.get()) + .renderer(m_Renderer.get()) + .build(); + + m_Timer = std::make_unique(); + + m_Camera = std::make_unique(m_InputDispatcher.get()); + float aspectRatio = m_Window->getAspectRatio(); + m_Camera->setPerspectiveProjection(glm::radians(50.f), aspectRatio, 0.1f, 1000.f); + + m_IsRunning = true; + } + + bool Viewer::onEvent(Event& event) { + EventDispatcher dispatcher(event); + dispatcher.dispatch(ETERNAL_BIND_EVENT_FN(Viewer::onKeyPressed)); + if (m_InputCapture.captured) { + m_Camera->onEvent(event); + } + return true; + } + + bool Viewer::onKeyPressed(KeyPressedEvent& event) { + switch (event.getKeyCode()) { + case Key::Escape: + m_InputCapture.release(); + return true; + case Key::P: + m_InputCapture.capture(); + return true; + default: + return false; + } + } + + void Viewer::handleInputCaptureState() { + if (!m_InputCapture.changed()) { + return; + } + + if (m_InputCapture.captured) { + m_Window->setCursorInputMode(CursorInputMode::LOCKED); + } else { + m_Window->setCursorInputMode(CursorInputMode::NORMAL); + } + + m_Camera->resetMouseTracking(); + m_InputCapture.acknowledge(); + } + + void Viewer::onImGuiRender(Eternal::Timestep& ts) const { + ImGui::Begin("Debug Info"); + ImGui::Text("Time: %.6f", ts); + ImGui::Text("FPS: %.1f", ImGui::GetIO().Framerate); + for (auto e: m_Scene->getAllEntityWith()) { + Eternal::Entity entity = Eternal::Entity(e, m_Scene.get()); + + auto& nameComponent = entity.getComponent(); + ImGui::Text("Entity Name: %s", nameComponent.getName()); + + auto& component = entity.getComponent(); + glm::vec3 translation = component.getTranslation(); + std::string posLabel = "Position " + std::string(nameComponent.getName()); + if (ImGui::DragFloat3(posLabel.c_str(), &translation.x, 0.01f)) { + component.setTranslation(translation); + } + + glm::vec3 rotationDegrees = glm::degrees(component.getRotation()); + std::string rotationLabel = "Rotation " + std::string(nameComponent.getName()); + if (ImGui::SliderFloat3(rotationLabel.c_str(), &rotationDegrees.x, 0.0f, 180.0f, "%.1f")) { + rotationDegrees = glm::clamp(rotationDegrees, 0.0f, 180.0f); + component.setRotation(glm::radians(rotationDegrees)); + } + } + + ImGui::Text("Press Esc to exit Capture Mode. Press P to enter Play/Capture Mode."); + ImGui::End(); + } + + void Viewer::setupScene() const { + TestEntityDetails testEntity1 = { + "watch_tower_1", + "res/models/wooden_watch_tower.obj", + "res/models/textures/Wood_Tower_Col.jpg", + glm::vec3(0.0f, 0.0f, 0.0f) + }; + + m_Scene->addEntity(testEntity1); + + TestEntityDetails testEntity2 = { + "watch_tower_2", + "res/models/wooden_watch_tower.obj", + "res/models/textures/Wood_Tower_Col.jpg", + glm::vec3(0.0f, 0.0f, 10.0f) + }; + + m_Scene->addEntity(testEntity2); + + std::vector triVertices = { + {{0.0f, 0.5f, 0.0f}, {1.0f, 0.0f, 0.0f}}, // 0: top (red) + {{-0.5f, -0.5f, 0.0f}, {0.0f, 1.0f, 0.0f}}, // 1: bottom-left (green) + {{0.5f, -0.5f, 0.0f}, {0.0f, 0.0f, 1.0f}}, // 2: bottom-right (blue) + }; + + std::vector triIndices = {0, 1, 2}; + + Eternal::Entity model = m_Scene->createEntity("triangle"); + model.addComponent(triVertices, triIndices); + model.addComponent(glm::vec3(0.0f, 10.0f, 0.0f)); + } + + void Viewer::run() { + m_Window->setEventCallBack(ETERNAL_BIND_EVENT_FN(Viewer::onEvent)); + m_Timer->start(); + while (m_IsRunning) { + auto timeStep = m_Timer->tick(); + m_Window->onUpdate(); + handleInputCaptureState(); + m_Camera->onUpdate(timeStep); + + if (FrameInfo* frameInfo = m_Renderer->beginFrame()) { + m_ImGuiOverlay->beginFrame(); + onImGuiRender(timeStep); + m_Renderer->render(m_Camera.get()); + m_ImGuiOverlay->render(frameInfo); + m_Renderer->endFrame(); + Memory::Deallocate(frameInfo); + } + + m_IsRunning = !m_Window->shouldClose(); + } + } + + std::unique_ptr Viewer::create() { + return std::make_unique(); + } + + Viewer::~Viewer() { + Viewer::shutdown(); + } + + void Viewer::shutdown() { + } +} diff --git a/SandBox/src/Viewer.h b/SandBox/src/Viewer.h new file mode 100644 index 0000000..b57190f --- /dev/null +++ b/SandBox/src/Viewer.h @@ -0,0 +1,54 @@ +#pragma once + +#include "Application.h" + +#include "core/imgui/ImGuiOverlay.h" +#include "core/window/Window.h" +#include "core/scene/Scene.h" +#include "core/event/KeyEvents.h" +#include "core/Camera.hpp" +#include "core/graphics/Renderer.h" +#include "core/graphics/Timer.h" + +namespace Eternal { + class Viewer : public Application { + public: + Viewer(); + ~Viewer() override; + + static std::unique_ptr create(); + + void run() override; + void shutdown() override; + + private: + void onImGuiRender(Eternal::Timestep& ts) const; + void setupScene() const; + bool onEvent(Event& event); + bool onKeyPressed(KeyPressedEvent& event); + void handleInputCaptureState(); + + private : + struct InputCaptureState { + bool captured = false; + bool lastApplied = false; + void capture() { captured = true; } + void release() { captured = false; } + bool changed() const { return captured != lastApplied; } + void acknowledge() { lastApplied = captured; } + }; + + std::unique_ptr m_GraphicsPlatform; + std::unique_ptr m_Renderer; + std::unique_ptr m_Window; + std::unique_ptr m_InputDispatcher; + std::unique_ptr m_Scene; + std::unique_ptr m_SwapChain; + std::unique_ptr m_ImGuiOverlay; + std::unique_ptr m_Camera; + std::unique_ptr m_Timer; + + InputCaptureState m_InputCapture; + Backend m_Backend = Backend::Vulkan; + }; +}