diff --git a/include/Nazara/Graphics/Systems/RenderSystem.hpp b/include/Nazara/Graphics/Systems/RenderSystem.hpp index 02da87897..b76943929 100644 --- a/include/Nazara/Graphics/Systems/RenderSystem.hpp +++ b/include/Nazara/Graphics/Systems/RenderSystem.hpp @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -27,7 +28,6 @@ namespace Nz class CommandBufferBuilder; class FramePipeline; class RenderFrame; - class RenderWindow; class UploadPool; class NAZARA_GRAPHICS_API RenderSystem @@ -41,7 +41,7 @@ namespace Nz RenderSystem(RenderSystem&&) = delete; ~RenderSystem(); - template T& CreateWindow(Args&&... args); + WindowSwapchain& CreateSwapchain(Window& window, const SwapchainParameters& parameters = SwapchainParameters{}); inline FramePipeline& GetFramePipeline(); inline const FramePipeline& GetFramePipeline() const; @@ -133,7 +133,7 @@ namespace Nz std::unordered_set m_newlyVisibleGfxEntities; std::unordered_set m_newlyHiddenLightEntities; std::unordered_set m_newlyVisibleLightEntities; - std::vector> m_renderWindows; + std::vector> m_windowSwapchains; ElementRendererRegistry m_elementRegistry; MemoryPool m_cameraEntityPool; MemoryPool m_graphicsEntityPool; diff --git a/include/Nazara/Graphics/Systems/RenderSystem.inl b/include/Nazara/Graphics/Systems/RenderSystem.inl index 23b7a6960..465f28822 100644 --- a/include/Nazara/Graphics/Systems/RenderSystem.inl +++ b/include/Nazara/Graphics/Systems/RenderSystem.inl @@ -8,19 +8,6 @@ namespace Nz { - template - T& RenderSystem::CreateWindow(Args&& ...args) - { - static_assert(std::is_base_of_v, "T must inherit RenderWindow"); - - auto windowPtr = std::make_unique(std::forward(args)...); - T& windowRef = *windowPtr; - - m_renderWindows.emplace_back(std::move(windowPtr)); - - return windowRef; - } - inline FramePipeline& RenderSystem::GetFramePipeline() { return *m_pipeline; diff --git a/include/Nazara/OpenGLRenderer.hpp b/include/Nazara/OpenGLRenderer.hpp index e4dadf2dd..530de613b 100644 --- a/include/Nazara/OpenGLRenderer.hpp +++ b/include/Nazara/OpenGLRenderer.hpp @@ -30,7 +30,6 @@ #define NAZARA_GLOBAL_OPENGLRENDERER_HPP #include -#include #include #include #include @@ -44,9 +43,9 @@ #include #include #include -#include #include #include +#include #include #include #include diff --git a/include/Nazara/OpenGLRenderer/DummySurface.hpp b/include/Nazara/OpenGLRenderer/DummySurface.hpp deleted file mode 100644 index 91bcf0b21..000000000 --- a/include/Nazara/OpenGLRenderer/DummySurface.hpp +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright (C) 2022 Jérôme "Lynix" Leclercq (lynix680@gmail.com) -// This file is part of the "Nazara Engine - OpenGL renderer" -// For conditions of distribution and use, see copyright notice in Config.hpp - -#pragma once - -#ifndef NAZARA_OPENGLRENDERER_DUMMYSURFACE_HPP -#define NAZARA_OPENGLRENDERER_DUMMYSURFACE_HPP - -#include -#include -#include - -namespace Nz -{ - class NAZARA_OPENGLRENDERER_API DummySurface : public RenderSurface - { - public: - DummySurface() = default; - ~DummySurface() = default; - - bool Create(WindowHandle handle) override; - void Destroy() override; - - inline WindowHandle GetWindowHandle() const; - - private: - WindowHandle m_handle; - }; -} - -#include - -#endif // NAZARA_OPENGLRENDERER_DUMMYSURFACE_HPP diff --git a/include/Nazara/OpenGLRenderer/DummySurface.inl b/include/Nazara/OpenGLRenderer/DummySurface.inl deleted file mode 100644 index 18005eb52..000000000 --- a/include/Nazara/OpenGLRenderer/DummySurface.inl +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright (C) 2022 Jérôme "Lynix" Leclercq (lynix680@gmail.com) -// This file is part of the "Nazara Engine - OpenGL renderer" -// For conditions of distribution and use, see copyright notice in Config.hpp - -#include -#include - -namespace Nz -{ - inline WindowHandle DummySurface::GetWindowHandle() const - { - return m_handle; - } -} - -#include diff --git a/include/Nazara/OpenGLRenderer/OpenGLDevice.hpp b/include/Nazara/OpenGLRenderer/OpenGLDevice.hpp index ff9983df3..9a8011245 100644 --- a/include/Nazara/OpenGLRenderer/OpenGLDevice.hpp +++ b/include/Nazara/OpenGLRenderer/OpenGLDevice.hpp @@ -45,6 +45,7 @@ namespace Nz std::shared_ptr InstantiateRenderPipelineLayout(RenderPipelineLayoutInfo pipelineLayoutInfo) override; std::shared_ptr InstantiateShaderModule(nzsl::ShaderStageTypeFlags shaderStages, const nzsl::Ast::Module& shaderModule, const nzsl::ShaderWriter::States& states) override; std::shared_ptr InstantiateShaderModule(nzsl::ShaderStageTypeFlags shaderStages, ShaderLanguage lang, const void* source, std::size_t sourceSize, const nzsl::ShaderWriter::States& states) override; + std::shared_ptr InstantiateSwapchain(WindowHandle windowHandle, const Vector2ui& windowSize, const SwapchainParameters& parameters) override; std::shared_ptr InstantiateTexture(const TextureInfo& params) override; std::shared_ptr InstantiateTextureSampler(const TextureSamplerInfo& params) override; diff --git a/include/Nazara/OpenGLRenderer/OpenGLRenderImage.hpp b/include/Nazara/OpenGLRenderer/OpenGLRenderImage.hpp index 29758f9ee..cc5dd0201 100644 --- a/include/Nazara/OpenGLRenderer/OpenGLRenderImage.hpp +++ b/include/Nazara/OpenGLRenderer/OpenGLRenderImage.hpp @@ -15,12 +15,12 @@ namespace Nz { class OpenGLCommandBuffer; - class OpenGLRenderWindow; + class OpenGLSwapchain; class NAZARA_OPENGLRENDERER_API OpenGLRenderImage : public RenderImage { public: - OpenGLRenderImage(OpenGLRenderWindow& owner); + OpenGLRenderImage(OpenGLSwapchain& owner); void Execute(const FunctionRef& callback, QueueTypeFlags queueTypeFlags) override; @@ -31,7 +31,7 @@ namespace Nz void SubmitCommandBuffer(CommandBuffer* commandBuffer, QueueTypeFlags queueTypeFlags) override; private: - OpenGLRenderWindow& m_owner; + OpenGLSwapchain& m_owner; OpenGLUploadPool m_uploadPool; }; } diff --git a/include/Nazara/OpenGLRenderer/OpenGLRenderer.hpp b/include/Nazara/OpenGLRenderer/OpenGLRenderer.hpp index 8360268d0..85c86369e 100644 --- a/include/Nazara/OpenGLRenderer/OpenGLRenderer.hpp +++ b/include/Nazara/OpenGLRenderer/OpenGLRenderer.hpp @@ -22,9 +22,6 @@ namespace Nz OpenGLRenderer() = default; ~OpenGLRenderer(); - std::unique_ptr CreateRenderSurfaceImpl() override; - std::unique_ptr CreateRenderWindowImpl(RenderWindow& owner) override; - std::shared_ptr InstanciateRenderDevice(std::size_t deviceIndex, const RenderDeviceFeatures& enabledFeatures) override; RenderAPI QueryAPI() const override; diff --git a/include/Nazara/OpenGLRenderer/OpenGLRenderWindow.hpp b/include/Nazara/OpenGLRenderer/OpenGLSwapchain.hpp similarity index 73% rename from include/Nazara/OpenGLRenderer/OpenGLRenderWindow.hpp rename to include/Nazara/OpenGLRenderer/OpenGLSwapchain.hpp index 849a06842..ef67afb41 100644 --- a/include/Nazara/OpenGLRenderer/OpenGLRenderWindow.hpp +++ b/include/Nazara/OpenGLRenderer/OpenGLSwapchain.hpp @@ -14,23 +14,21 @@ #include #include #include -#include +#include +#include #include #include namespace Nz { - class RenderWindow; - - class NAZARA_OPENGLRENDERER_API OpenGLRenderWindow final : public RenderWindowImpl + class NAZARA_OPENGLRENDERER_API OpenGLSwapchain final : public Swapchain { public: - OpenGLRenderWindow(RenderWindow& owner); - ~OpenGLRenderWindow() = default; + OpenGLSwapchain(OpenGLDevice& device, WindowHandle windowHandle, const Vector2ui& windowSize, const SwapchainParameters& parameters); + ~OpenGLSwapchain() = default; - RenderFrame Acquire() override; + RenderFrame AcquireFrame() override; - bool Create(RendererImpl* renderer, RenderSurface* surface, const RenderWindowParameters& parameters) override; std::shared_ptr CreateCommandPool(QueueType queueType) override; inline GL::Context& GetContext(); @@ -39,6 +37,8 @@ namespace Nz const OpenGLRenderPass& GetRenderPass() const override; const Vector2ui& GetSize() const override; + void NotifyResize(const Vector2ui& newSize) override; + void Present(); private: @@ -47,11 +47,11 @@ namespace Nz std::vector> m_renderImage; std::unique_ptr m_context; OpenGLWindowFramebuffer m_framebuffer; - RenderWindow& m_owner; Vector2ui m_size; + bool m_sizeInvalidated; }; } -#include +#include #endif // NAZARA_OPENGLRENDERER_OPENGLRENDERWINDOW_HPP diff --git a/include/Nazara/OpenGLRenderer/OpenGLRenderWindow.inl b/include/Nazara/OpenGLRenderer/OpenGLSwapchain.inl similarity index 77% rename from include/Nazara/OpenGLRenderer/OpenGLRenderWindow.inl rename to include/Nazara/OpenGLRenderer/OpenGLSwapchain.inl index ecaebe87a..2554c9ddb 100644 --- a/include/Nazara/OpenGLRenderer/OpenGLRenderWindow.inl +++ b/include/Nazara/OpenGLRenderer/OpenGLSwapchain.inl @@ -2,13 +2,13 @@ // This file is part of the "Nazara Engine - OpenGL renderer" // For conditions of distribution and use, see copyright notice in Config.hpp -#include +#include #include #include namespace Nz { - inline GL::Context& OpenGLRenderWindow::GetContext() + inline GL::Context& OpenGLSwapchain::GetContext() { assert(m_context); return *m_context; diff --git a/include/Nazara/OpenGLRenderer/OpenGLWindowFramebuffer.hpp b/include/Nazara/OpenGLRenderer/OpenGLWindowFramebuffer.hpp index a7f95f3fb..9e9654a2d 100644 --- a/include/Nazara/OpenGLRenderer/OpenGLWindowFramebuffer.hpp +++ b/include/Nazara/OpenGLRenderer/OpenGLWindowFramebuffer.hpp @@ -12,12 +12,12 @@ namespace Nz { - class OpenGLRenderWindow; + class OpenGLSwapchain; class NAZARA_OPENGLRENDERER_API OpenGLWindowFramebuffer : public OpenGLFramebuffer { public: - inline OpenGLWindowFramebuffer(OpenGLRenderWindow& renderWindow); + inline OpenGLWindowFramebuffer(OpenGLSwapchain& renderWindow); OpenGLWindowFramebuffer(const OpenGLWindowFramebuffer&) = delete; OpenGLWindowFramebuffer(OpenGLWindowFramebuffer&&) noexcept = default; ~OpenGLWindowFramebuffer() = default; @@ -34,7 +34,7 @@ namespace Nz OpenGLWindowFramebuffer& operator=(OpenGLWindowFramebuffer&&) = delete; private: - OpenGLRenderWindow& m_renderWindow; + OpenGLSwapchain& m_renderWindow; }; } diff --git a/include/Nazara/OpenGLRenderer/OpenGLWindowFramebuffer.inl b/include/Nazara/OpenGLRenderer/OpenGLWindowFramebuffer.inl index 29acac6fb..e5d9695f8 100644 --- a/include/Nazara/OpenGLRenderer/OpenGLWindowFramebuffer.inl +++ b/include/Nazara/OpenGLRenderer/OpenGLWindowFramebuffer.inl @@ -7,7 +7,7 @@ namespace Nz { - inline OpenGLWindowFramebuffer::OpenGLWindowFramebuffer(OpenGLRenderWindow& renderWindow) : + inline OpenGLWindowFramebuffer::OpenGLWindowFramebuffer(OpenGLSwapchain& renderWindow) : OpenGLFramebuffer(FramebufferType::Window), m_renderWindow(renderWindow) { diff --git a/include/Nazara/Platform.hpp b/include/Nazara/Platform.hpp index d1bc4f210..9a904e901 100644 --- a/include/Nazara/Platform.hpp +++ b/include/Nazara/Platform.hpp @@ -34,8 +34,8 @@ #include #include #include -#include -#include +#include +#include #include #include #include diff --git a/include/Nazara/Platform/Enums.hpp b/include/Nazara/Platform/Enums.hpp index ed8531ae1..f547e8a57 100644 --- a/include/Nazara/Platform/Enums.hpp +++ b/include/Nazara/Platform/Enums.hpp @@ -48,10 +48,13 @@ namespace Nz enum class WindowEventType { + Created, + Destruction, GainedFocus, LostFocus, KeyPressed, KeyReleased, + Minimized, MouseButtonPressed, MouseButtonReleased, MouseEntered, @@ -61,6 +64,7 @@ namespace Nz Moved, Quit, Resized, + Restored, TextEdited, TextEntered, diff --git a/include/Nazara/Platform/EventHandler.hpp b/include/Nazara/Platform/EventHandler.hpp deleted file mode 100644 index d508b5b9f..000000000 --- a/include/Nazara/Platform/EventHandler.hpp +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright (C) 2022 Jérôme "Lynix" Leclercq (lynix680@gmail.com) -// This file is part of the "Nazara Engine - Platform module" -// For conditions of distribution and use, see copyright notice in Config.hpp - -#pragma once - -#ifndef NAZARA_PLATFORM_EVENTHANDLER_HPP -#define NAZARA_PLATFORM_EVENTHANDLER_HPP - -#include -#include -#include -#include -#include -#include - -namespace Nz -{ - class EventHandler; - - using EventHandlerHandle = ObjectHandle; - - class EventHandler : public HandledObject - { - public: - EventHandler() = default; - explicit EventHandler(const EventHandler&); - EventHandler(EventHandler&&) noexcept = default; - ~EventHandler() = default; - - inline void Dispatch(const WindowEvent& event); - - EventHandler& operator=(const EventHandler&) = delete; - EventHandler& operator=(EventHandler&&) noexcept = default; - - NazaraSignal(OnEvent, const EventHandler* /*eventHandler*/, const WindowEvent& /*event*/); - NazaraSignal(OnGainedFocus, const EventHandler* /*eventHandler*/); - NazaraSignal(OnLostFocus, const EventHandler* /*eventHandler*/); - NazaraSignal(OnKeyPressed, const EventHandler* /*eventHandler*/, const WindowEvent::KeyEvent& /*event*/); - NazaraSignal(OnKeyReleased, const EventHandler* /*eventHandler*/, const WindowEvent::KeyEvent& /*event*/); - NazaraSignal(OnMouseButtonPressed, const EventHandler* /*eventHandler*/, const WindowEvent::MouseButtonEvent& /*event*/); - NazaraSignal(OnMouseButtonReleased, const EventHandler* /*eventHandler*/, const WindowEvent::MouseButtonEvent& /*event*/); - NazaraSignal(OnMouseEntered, const EventHandler* /*eventHandler*/); - NazaraSignal(OnMouseLeft, const EventHandler* /*eventHandler*/); - NazaraSignal(OnMouseMoved, const EventHandler* /*eventHandler*/, const WindowEvent::MouseMoveEvent& /*event*/); - NazaraSignal(OnMouseWheelMoved, const EventHandler* /*eventHandler*/, const WindowEvent::MouseWheelEvent& /*event*/); - NazaraSignal(OnMoved, const EventHandler* /*eventHandler*/, const WindowEvent::PositionEvent& /*event*/); - NazaraSignal(OnQuit, const EventHandler* /*eventHandler*/); - NazaraSignal(OnResized, const EventHandler* /*eventHandler*/, const WindowEvent::SizeEvent& /*event*/); - NazaraSignal(OnTextEntered, const EventHandler* /*eventHandler*/, const WindowEvent::TextEvent& /*event*/); - NazaraSignal(OnTextEdited, const EventHandler* /*eventHandler*/, const WindowEvent::EditEvent& /*event*/); - }; -} - -#include - -#endif // NAZARA_PLATFORM_EVENTHANDLER_HPP diff --git a/include/Nazara/Platform/Window.hpp b/include/Nazara/Platform/Window.hpp index 49ddcd4a2..568c9bb1a 100644 --- a/include/Nazara/Platform/Window.hpp +++ b/include/Nazara/Platform/Window.hpp @@ -15,7 +15,7 @@ #include #include #include -#include +#include #include #include #include @@ -38,35 +38,31 @@ namespace Nz public: Window(); inline Window(VideoMode mode, const std::string& title, WindowStyleFlags style = WindowStyle_Default); - inline explicit Window(void* handle); + inline explicit Window(WindowHandle handle); Window(const Window&) = delete; - Window(Window&& window); - virtual ~Window(); + Window(Window&& window) noexcept; + ~Window(); inline void Close(); bool Create(VideoMode mode, const std::string& title, WindowStyleFlags style = WindowStyle_Default); - bool Create(void* handle); + bool Create(WindowHandle handle); void Destroy(); inline void EnableCloseOnQuit(bool closeOnQuit); - NAZARA_DEPRECATED("Event pooling/waiting is deprecated, please use the EventHandler system") - inline void EnableEventPolling(bool enable); - - void EnableKeyRepeat(bool enable); - void EnableSmoothScrolling(bool enable); - inline const std::shared_ptr& GetCursor() const; inline CursorController& GetCursorController(); - inline EventHandler& GetEventHandler(); + inline WindowEventHandler& GetEventHandler(); + WindowHandle GetHandle() const; Vector2i GetPosition() const; Vector2ui GetSize() const; WindowStyleFlags GetStyle() const; - WindowHandle GetSystemHandle() const; std::string GetTitle() const; + void HandleEvent(const WindowEvent& event); + bool HasFocus() const; bool IsMinimized() const; @@ -75,16 +71,8 @@ namespace Nz inline bool IsValid() const; bool IsVisible() const; - NAZARA_DEPRECATED("Event pooling/waiting is deprecated, please use the EventHandler system") - bool PollEvent(WindowEvent* event); - - void PushEvent(const WindowEvent& event); - - void ProcessEvents(bool block = false); - void SetCursor(std::shared_ptr cursor); inline void SetCursor(SystemCursor systemCursor); - void SetEventListener(bool listener); void SetFocus(); void SetIcon(std::shared_ptr icon); void SetMaximumSize(const Vector2i& maxSize); @@ -99,20 +87,10 @@ namespace Nz void SetTitle(const std::string& title); void SetVisible(bool visible); - NAZARA_DEPRECATED("Event pooling/waiting is deprecated, please use the EventHandler system") - bool WaitEvent(WindowEvent* event); - Window& operator=(const Window&) = delete; - Window& operator=(Window&& window); + Window& operator=(Window&& window) noexcept; - protected: - void* GetHandle(); - - virtual bool OnWindowCreated(); - virtual void OnWindowDestroy(); - virtual void OnWindowResized(); - - MovablePtr m_impl; + static void ProcessEvents(); private: void ConnectSlots(); @@ -122,26 +100,21 @@ namespace Nz inline const WindowImpl* GetImpl() const; void IgnoreNextMouseEvent(int mouseX, int mouseY) const; - void HandleEvent(const WindowEvent& event); static bool Initialize(); static void Uninitialize(); NazaraSlot(CursorController, OnCursorUpdated, m_cursorUpdateSlot); - std::queue m_events; - std::vector m_pendingEvents; - std::condition_variable m_eventCondition; - CursorController m_cursorController; std::shared_ptr m_cursor; - EventHandler m_eventHandler; std::shared_ptr m_icon; - std::mutex m_eventMutex; - std::mutex m_eventConditionMutex; - bool m_asyncWindow; + std::unique_ptr m_impl; + CursorController m_cursorController; + Vector2i m_position; + Vector2ui m_size; + WindowEventHandler m_eventHandler; bool m_closed; bool m_closeOnQuit; - bool m_eventPolling; bool m_ownsWindow; bool m_waitForEvent; }; diff --git a/include/Nazara/Platform/Window.inl b/include/Nazara/Platform/Window.inl index dfd6d8b16..e13700260 100644 --- a/include/Nazara/Platform/Window.inl +++ b/include/Nazara/Platform/Window.inl @@ -19,7 +19,7 @@ namespace Nz Create(mode, title, style); } - inline Window::Window(void* handle) : + inline Window::Window(WindowHandle handle) : Window() { ErrorFlags flags(ErrorMode::ThrowException, true); @@ -36,16 +36,6 @@ namespace Nz m_closeOnQuit = closeOnQuit; } - inline void Window::EnableEventPolling(bool enable) - { - m_eventPolling = enable; - if (!m_eventPolling) - { - while (!m_events.empty()) - m_events.pop(); - } - } - inline const std::shared_ptr& Window::GetCursor() const { return m_cursor; @@ -56,7 +46,7 @@ namespace Nz return m_cursorController; } - inline EventHandler& Nz::Window::GetEventHandler() + inline WindowEventHandler& Nz::Window::GetEventHandler() { return m_eventHandler; } @@ -90,34 +80,14 @@ namespace Nz SetCursor(Cursor::Get(systemCursor)); } - inline void Window::PushEvent(const WindowEvent& event) - { - if (!m_asyncWindow) - HandleEvent(event); - else - { - { - std::lock_guard eventLock(m_eventMutex); - - m_pendingEvents.push_back(event); - } - - if (m_waitForEvent) - { - std::lock_guard lock(m_eventConditionMutex); - m_eventCondition.notify_all(); - } - } - } - inline WindowImpl* Window::GetImpl() { - return m_impl; + return m_impl.get(); } inline const WindowImpl* Window::GetImpl() const { - return m_impl; + return m_impl.get(); } } diff --git a/include/Nazara/Platform/Event.hpp b/include/Nazara/Platform/WindowEvent.hpp similarity index 99% rename from include/Nazara/Platform/Event.hpp rename to include/Nazara/Platform/WindowEvent.hpp index fc0ccd2df..40f468425 100644 --- a/include/Nazara/Platform/Event.hpp +++ b/include/Nazara/Platform/WindowEvent.hpp @@ -9,11 +9,10 @@ #ifndef NAZARA_PLATFORM_EVENT_HPP #define NAZARA_PLATFORM_EVENT_HPP -#include - #include #include #include +#include namespace Nz { diff --git a/include/Nazara/Platform/WindowEventHandler.hpp b/include/Nazara/Platform/WindowEventHandler.hpp new file mode 100644 index 000000000..48bf88444 --- /dev/null +++ b/include/Nazara/Platform/WindowEventHandler.hpp @@ -0,0 +1,61 @@ +// Copyright (C) 2022 Jérôme "Lynix" Leclercq (lynix680@gmail.com) +// This file is part of the "Nazara Engine - Platform module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_PLATFORM_EVENTHANDLER_HPP +#define NAZARA_PLATFORM_EVENTHANDLER_HPP + +#include +#include +#include +#include +#include +#include + +namespace Nz +{ + class WindowEventHandler; + + using EventHandlerHandle = ObjectHandle; + + class WindowEventHandler : public HandledObject + { + public: + WindowEventHandler() = default; + explicit WindowEventHandler(const WindowEventHandler&); + WindowEventHandler(WindowEventHandler&&) noexcept = default; + ~WindowEventHandler() = default; + + inline void Dispatch(const WindowEvent& event); + + WindowEventHandler& operator=(const WindowEventHandler&) = delete; + WindowEventHandler& operator=(WindowEventHandler&&) noexcept = default; + + NazaraSignal(OnCreated, const WindowEventHandler* /*eventHandler*/); + NazaraSignal(OnDestruction, const WindowEventHandler* /*eventHandler*/); + NazaraSignal(OnEvent, const WindowEventHandler* /*eventHandler*/, const WindowEvent& /*event*/); + NazaraSignal(OnGainedFocus, const WindowEventHandler* /*eventHandler*/); + NazaraSignal(OnLostFocus, const WindowEventHandler* /*eventHandler*/); + NazaraSignal(OnKeyPressed, const WindowEventHandler* /*eventHandler*/, const WindowEvent::KeyEvent& /*event*/); + NazaraSignal(OnKeyReleased, const WindowEventHandler* /*eventHandler*/, const WindowEvent::KeyEvent& /*event*/); + NazaraSignal(OnMinimized, const WindowEventHandler* /*eventHandler*/); + NazaraSignal(OnMouseButtonPressed, const WindowEventHandler* /*eventHandler*/, const WindowEvent::MouseButtonEvent& /*event*/); + NazaraSignal(OnMouseButtonReleased, const WindowEventHandler* /*eventHandler*/, const WindowEvent::MouseButtonEvent& /*event*/); + NazaraSignal(OnMouseEntered, const WindowEventHandler* /*eventHandler*/); + NazaraSignal(OnMouseLeft, const WindowEventHandler* /*eventHandler*/); + NazaraSignal(OnMouseMoved, const WindowEventHandler* /*eventHandler*/, const WindowEvent::MouseMoveEvent& /*event*/); + NazaraSignal(OnMouseWheelMoved, const WindowEventHandler* /*eventHandler*/, const WindowEvent::MouseWheelEvent& /*event*/); + NazaraSignal(OnMoved, const WindowEventHandler* /*eventHandler*/, const WindowEvent::PositionEvent& /*event*/); + NazaraSignal(OnQuit, const WindowEventHandler* /*eventHandler*/); + NazaraSignal(OnResized, const WindowEventHandler* /*eventHandler*/, const WindowEvent::SizeEvent& /*event*/); + NazaraSignal(OnRestored, const WindowEventHandler* /*eventHandler*/); + NazaraSignal(OnTextEntered, const WindowEventHandler* /*eventHandler*/, const WindowEvent::TextEvent& /*event*/); + NazaraSignal(OnTextEdited, const WindowEventHandler* /*eventHandler*/, const WindowEvent::EditEvent& /*event*/); + }; +} + +#include + +#endif // NAZARA_PLATFORM_EVENTHANDLER_HPP diff --git a/include/Nazara/Platform/EventHandler.inl b/include/Nazara/Platform/WindowEventHandler.inl similarity index 77% rename from include/Nazara/Platform/EventHandler.inl rename to include/Nazara/Platform/WindowEventHandler.inl index 4ee7e0a23..10f20acc1 100644 --- a/include/Nazara/Platform/EventHandler.inl +++ b/include/Nazara/Platform/WindowEventHandler.inl @@ -2,23 +2,31 @@ // This file is part of the "Nazara Engine - Platform module" // For conditions of distribution and use, see copyright notice in Config.hpp -#include +#include #include #include namespace Nz { - inline EventHandler::EventHandler(const EventHandler& other) : + inline WindowEventHandler::WindowEventHandler(const WindowEventHandler& other) : HandledObject(other) { } - inline void EventHandler::Dispatch(const WindowEvent& event) + inline void WindowEventHandler::Dispatch(const WindowEvent& event) { OnEvent(this, event); switch (event.type) { + case WindowEventType::Created: + OnCreated(this); + break; + + case WindowEventType::Destruction: + OnDestruction(this); + break; + case WindowEventType::GainedFocus: OnGainedFocus(this); break; @@ -35,6 +43,10 @@ namespace Nz OnLostFocus(this); break; + case WindowEventType::Minimized: + OnMinimized(this); + break; + case WindowEventType::MouseButtonPressed: OnMouseButtonPressed(this, event.mouseButton); break; @@ -71,6 +83,10 @@ namespace Nz OnResized(this, event.size); break; + case WindowEventType::Restored: + OnRestored(this); + break; + case WindowEventType::TextEntered: OnTextEntered(this, event.text); break; diff --git a/include/Nazara/Renderer.hpp b/include/Nazara/Renderer.hpp index 77af8b018..ef3ca49a0 100644 --- a/include/Nazara/Renderer.hpp +++ b/include/Nazara/Renderer.hpp @@ -51,15 +51,14 @@ #include #include #include -#include #include -#include -#include -#include #include #include +#include +#include #include #include #include +#include #endif // NAZARA_GLOBAL_RENDERER_HPP diff --git a/include/Nazara/Renderer/RenderDevice.hpp b/include/Nazara/Renderer/RenderDevice.hpp index 68772fe7d..19e103579 100644 --- a/include/Nazara/Renderer/RenderDevice.hpp +++ b/include/Nazara/Renderer/RenderDevice.hpp @@ -17,6 +17,8 @@ #include #include #include +#include +#include #include #include #include @@ -49,6 +51,7 @@ namespace Nz virtual std::shared_ptr InstantiateShaderModule(nzsl::ShaderStageTypeFlags shaderStages, const nzsl::Ast::Module& shaderModule, const nzsl::ShaderWriter::States& states) = 0; virtual std::shared_ptr InstantiateShaderModule(nzsl::ShaderStageTypeFlags shaderStages, ShaderLanguage lang, const void* source, std::size_t sourceSize, const nzsl::ShaderWriter::States& states) = 0; std::shared_ptr InstantiateShaderModule(nzsl::ShaderStageTypeFlags shaderStages, ShaderLanguage lang, const std::filesystem::path& sourcePath, const nzsl::ShaderWriter::States& states); + virtual std::shared_ptr InstantiateSwapchain(WindowHandle windowHandle, const Vector2ui& windowSize, const SwapchainParameters& parameters) = 0; virtual std::shared_ptr InstantiateTexture(const TextureInfo& params) = 0; virtual std::shared_ptr InstantiateTextureSampler(const TextureSamplerInfo& params) = 0; diff --git a/include/Nazara/Renderer/RenderSurface.hpp b/include/Nazara/Renderer/RenderSurface.hpp deleted file mode 100644 index 340cdbc83..000000000 --- a/include/Nazara/Renderer/RenderSurface.hpp +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright (C) 2022 Jérôme "Lynix" Leclercq (lynix680@gmail.com) -// This file is part of the "Nazara Engine - Renderer module" -// For conditions of distribution and use, see copyright notice in Config.hpp - -#pragma once - -#ifndef NAZARA_RENDERER_RENDERSURFACE_HPP -#define NAZARA_RENDERER_RENDERSURFACE_HPP - -#include -#include -#include - -namespace Nz -{ - ///TODO: Rename - class NAZARA_RENDERER_API RenderSurface - { - public: - RenderSurface() = default; - virtual ~RenderSurface(); - - virtual bool Create(WindowHandle handle) = 0; - virtual void Destroy() = 0; - }; -} - -#include - -#endif // NAZARA_RENDERER_RENDERSURFACE_HPP diff --git a/include/Nazara/Renderer/RenderSurface.inl b/include/Nazara/Renderer/RenderSurface.inl deleted file mode 100644 index 77e69170e..000000000 --- a/include/Nazara/Renderer/RenderSurface.inl +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright (C) 2022 Jérôme "Lynix" Leclercq (lynix680@gmail.com) -// This file is part of the "Nazara Engine - Renderer module" -// For conditions of distribution and use, see copyright notice in Config.hpp - -#include -#include - -namespace Nz -{ -} - -#include diff --git a/include/Nazara/Renderer/RenderWindow.hpp b/include/Nazara/Renderer/RenderWindow.hpp deleted file mode 100644 index 2042db450..000000000 --- a/include/Nazara/Renderer/RenderWindow.hpp +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright (C) 2022 Jérôme "Lynix" Leclercq (lynix680@gmail.com) -// This file is part of the "Nazara Engine - Renderer module" -// For conditions of distribution and use, see copyright notice in Config.hpp - -#pragma once - -#ifndef NAZARA_RENDERER_RENDERWINDOW_HPP -#define NAZARA_RENDERER_RENDERWINDOW_HPP - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace Nz -{ - class RenderDevice; - - class NAZARA_RENDERER_API RenderWindow : public Window - { - public: - inline RenderWindow(); - inline RenderWindow(std::shared_ptr renderDevice, VideoMode mode, const std::string& title, WindowStyleFlags style = WindowStyle_Default, const RenderWindowParameters& parameters = RenderWindowParameters()); - inline RenderWindow(std::shared_ptr renderDevice, void* handle, const RenderWindowParameters& parameters = RenderWindowParameters()); - inline ~RenderWindow(); - - RenderFrame AcquireFrame(); - - bool Create(std::shared_ptr renderDevice, VideoMode mode, const std::string& title, WindowStyleFlags style = WindowStyle_Default, const RenderWindowParameters& parameters = RenderWindowParameters()); - bool Create(std::shared_ptr renderDevice, void* handle, const RenderWindowParameters ¶meters = RenderWindowParameters()); - - void EnableVerticalSync(bool enabled); - - inline const std::shared_ptr& GetRenderDevice() const; - inline const RenderTarget* GetRenderTarget() const; - inline RenderSurface* GetSurface(); - - inline bool IsValid() const; - - inline void SetFramerateLimit(unsigned int limit); - - RenderWindow &operator=(const RenderWindow &) = delete; - RenderWindow &operator=(RenderWindow &&) = delete; ///TODO - - protected: - bool OnWindowCreated() override; - void OnWindowDestroy() override; - void OnWindowResized() override; - - private: - std::shared_ptr m_renderDevice; - std::unique_ptr m_surface; - std::unique_ptr m_impl; - MillisecondClock m_clock; - RenderWindowParameters m_parameters; - unsigned int m_framerateLimit; - }; -} // namespace Nz - -#include - -#endif // NAZARA_RENDERER_RENDERWINDOW_HPP diff --git a/include/Nazara/Renderer/RenderWindow.inl b/include/Nazara/Renderer/RenderWindow.inl deleted file mode 100644 index e8299106e..000000000 --- a/include/Nazara/Renderer/RenderWindow.inl +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright (C) 2022 Jérôme "Lynix" Leclercq (lynix680@gmail.com) -// This file is part of the "Nazara Engine - Renderer module" -// For conditions of distribution and use, see copyright notice in Config.hpp - -#include -#include -#include - -namespace Nz -{ - inline RenderWindow::RenderWindow() : - m_framerateLimit(0U) - { - } - - inline RenderWindow::RenderWindow(std::shared_ptr renderDevice, VideoMode mode, const std::string& title, WindowStyleFlags style, const RenderWindowParameters& parameters) : - RenderWindow() - { - ErrorFlags errFlags(ErrorMode::ThrowException, true); - - Create(std::move(renderDevice), mode, title, style, parameters); - } - - inline RenderWindow::RenderWindow(std::shared_ptr renderDevice, void* handle, const RenderWindowParameters& parameters) - { - ErrorFlags errFlags(ErrorMode::ThrowException, true); - - Create(std::move(renderDevice), handle, parameters); - } - - inline RenderWindow::~RenderWindow() - { - Destroy(); - } - - inline const std::shared_ptr& RenderWindow::GetRenderDevice() const - { - return m_renderDevice; - } - - inline const RenderTarget* RenderWindow::GetRenderTarget() const - { - return m_impl.get(); - } - - inline RenderSurface* RenderWindow::GetSurface() - { - return m_surface.get(); - } - - inline bool RenderWindow::IsValid() const - { - return m_impl != nullptr; - } - - inline void RenderWindow::SetFramerateLimit(unsigned int limit) - { - m_framerateLimit = limit; - } -} - -#include diff --git a/include/Nazara/Renderer/RendererImpl.hpp b/include/Nazara/Renderer/RendererImpl.hpp index a56066424..239e7d1a7 100644 --- a/include/Nazara/Renderer/RendererImpl.hpp +++ b/include/Nazara/Renderer/RendererImpl.hpp @@ -23,8 +23,8 @@ namespace Nz class RendererImpl; class RenderDevice; class RenderSurface; - class RenderWindow; - class RenderWindowImpl; + class WindowSwapchain; + class Swapchain; using CreateRendererImplFunc = RendererImpl*(*)(); @@ -34,9 +34,6 @@ namespace Nz RendererImpl() = default; virtual ~RendererImpl(); - virtual std::unique_ptr CreateRenderSurfaceImpl() = 0; - virtual std::unique_ptr CreateRenderWindowImpl(RenderWindow& owner) = 0; - virtual std::shared_ptr InstanciateRenderDevice(std::size_t deviceIndex, const RenderDeviceFeatures& enabledFeatures) = 0; virtual RenderAPI QueryAPI() const = 0; diff --git a/include/Nazara/Renderer/RenderWindowImpl.hpp b/include/Nazara/Renderer/Swapchain.hpp similarity index 63% rename from include/Nazara/Renderer/RenderWindowImpl.hpp rename to include/Nazara/Renderer/Swapchain.hpp index f7d72e5e1..dd68f3ae4 100644 --- a/include/Nazara/Renderer/RenderWindowImpl.hpp +++ b/include/Nazara/Renderer/Swapchain.hpp @@ -4,41 +4,38 @@ #pragma once -#ifndef NAZARA_RENDERER_RENDERWINDOWIMPL_HPP -#define NAZARA_RENDERER_RENDERWINDOWIMPL_HPP +#ifndef NAZARA_RENDERER_SWAPCHAIN_HPP +#define NAZARA_RENDERER_SWAPCHAIN_HPP #include #include #include #include -#include #include #include #include -#include #include namespace Nz { class CommandPool; - class RendererImpl; class RenderDevice; - class RenderSurface; - class NAZARA_RENDERER_API RenderWindowImpl : public RenderTarget + class NAZARA_RENDERER_API Swapchain : public RenderTarget { public: - RenderWindowImpl() = default; - virtual ~RenderWindowImpl(); + Swapchain() = default; + virtual ~Swapchain(); - virtual RenderFrame Acquire() = 0; + virtual RenderFrame AcquireFrame() = 0; - virtual bool Create(RendererImpl* renderer, RenderSurface* surface, const RenderWindowParameters& parameters) = 0; virtual std::shared_ptr CreateCommandPool(QueueType queueType) = 0; + virtual void NotifyResize(const Vector2ui& newSize) = 0; + protected: static void BuildRenderPass(PixelFormat colorFormat, PixelFormat depthFormat, std::vector& attachments, std::vector& subpassDescriptions, std::vector& subpassDependencies); }; } -#endif // NAZARA_RENDERER_RENDERWINDOWIMPL_HPP +#endif // NAZARA_RENDERER_SWAPCHAIN_HPP diff --git a/include/Nazara/Renderer/RenderWindowParameters.hpp b/include/Nazara/Renderer/SwapchainParameters.hpp similarity index 96% rename from include/Nazara/Renderer/RenderWindowParameters.hpp rename to include/Nazara/Renderer/SwapchainParameters.hpp index 25dc56bc4..97d3dfa6d 100644 --- a/include/Nazara/Renderer/RenderWindowParameters.hpp +++ b/include/Nazara/Renderer/SwapchainParameters.hpp @@ -13,7 +13,7 @@ namespace Nz { - struct RenderWindowParameters + struct SwapchainParameters { std::vector depthFormats = {Nz::PixelFormat::Depth24Stencil8, Nz::PixelFormat::Depth32FStencil8, Nz::PixelFormat::Depth16Stencil8, Nz::PixelFormat::Depth32F, Nz::PixelFormat::Depth24}; //< By order of preference bool verticalSync = false; diff --git a/include/Nazara/Renderer/WindowSwapchain.hpp b/include/Nazara/Renderer/WindowSwapchain.hpp new file mode 100644 index 000000000..302604e6a --- /dev/null +++ b/include/Nazara/Renderer/WindowSwapchain.hpp @@ -0,0 +1,65 @@ +// Copyright (C) 2022 Jérôme "Lynix" Leclercq (lynix680@gmail.com) +// This file is part of the "Nazara Engine - Renderer module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_RENDERER_RENDERWINDOW_HPP +#define NAZARA_RENDERER_RENDERWINDOW_HPP + +#include +#include +#include +#include +#include + +namespace Nz +{ + class RenderDevice; + class Window; + + class NAZARA_RENDERER_API WindowSwapchain + { + public: + WindowSwapchain(std::shared_ptr renderDevice, Window& window, SwapchainParameters parameters = SwapchainParameters()); + WindowSwapchain(const WindowSwapchain&) = delete; + inline WindowSwapchain(WindowSwapchain&& windowSwapchain) noexcept; + ~WindowSwapchain() = default; + + inline RenderFrame AcquireFrame(); + + inline bool DoesRenderOnlyIfFocused() const; + + inline void EnableRenderOnlyIfFocused(bool enable = true); + + inline Swapchain& GetSwapchain(); + inline const Swapchain& GetSwapchain() const; + + WindowSwapchain& operator=(const WindowSwapchain&) = default; + inline WindowSwapchain& operator=(WindowSwapchain&& windowSwapchain) noexcept; + + private: + void ConnectSignals(); + inline void DisconnectSignals(); + + NazaraSlot(WindowEventHandler, OnCreated, m_onCreated); + NazaraSlot(WindowEventHandler, OnDestruction, m_onDestruction); + NazaraSlot(WindowEventHandler, OnGainedFocus, m_onGainedFocus); + NazaraSlot(WindowEventHandler, OnLostFocus, m_onLostFocus); + NazaraSlot(WindowEventHandler, OnMinimized, m_onMinimized); + NazaraSlot(WindowEventHandler, OnResized, m_onResized); + NazaraSlot(WindowEventHandler, OnRestored, m_onRestored); + + std::shared_ptr m_renderDevice; + std::shared_ptr m_swapchain; + MovablePtr m_window; + SwapchainParameters m_parameters; + bool m_renderOnlyIfFocused; + bool m_hasFocus; + bool m_isMinimized; + }; +} + +#include + +#endif // NAZARA_RENDERER_RENDERWINDOW_HPP diff --git a/include/Nazara/Renderer/WindowSwapchain.inl b/include/Nazara/Renderer/WindowSwapchain.inl new file mode 100644 index 000000000..141d24e96 --- /dev/null +++ b/include/Nazara/Renderer/WindowSwapchain.inl @@ -0,0 +1,76 @@ +// Copyright (C) 2022 Jérôme "Lynix" Leclercq (lynix680@gmail.com) +// This file is part of the "Nazara Engine - Renderer module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include +#include + +namespace Nz +{ + inline WindowSwapchain::WindowSwapchain(WindowSwapchain&& windowSwapchain) noexcept : + m_renderDevice(std::move(windowSwapchain.m_renderDevice)), + m_swapchain(std::move(windowSwapchain.m_swapchain)), + m_window(std::move(windowSwapchain.m_window)), + m_renderOnlyIfFocused(windowSwapchain.m_renderOnlyIfFocused), + m_hasFocus(windowSwapchain.m_hasFocus), + m_isMinimized(windowSwapchain.m_isMinimized) + { + ConnectSignals(); + } + + inline RenderFrame WindowSwapchain::AcquireFrame() + { + if (m_isMinimized || (!m_hasFocus && m_renderOnlyIfFocused)) + return RenderFrame{}; + + return m_swapchain->AcquireFrame(); + } + + inline bool WindowSwapchain::DoesRenderOnlyIfFocused() const + { + return m_renderOnlyIfFocused; + } + + inline void WindowSwapchain::EnableRenderOnlyIfFocused(bool enable) + { + m_renderOnlyIfFocused = enable; + } + + inline Swapchain& WindowSwapchain::GetSwapchain() + { + return *m_swapchain; + } + + inline const Swapchain& WindowSwapchain::GetSwapchain() const + { + return *m_swapchain; + } + + inline WindowSwapchain& WindowSwapchain::operator=(WindowSwapchain&& windowSwapchain) noexcept + { + windowSwapchain.DisconnectSignals(); + + m_renderDevice = std::move(windowSwapchain.m_renderDevice); + m_swapchain = std::move(windowSwapchain.m_swapchain); + m_window = std::move(windowSwapchain.m_window); + m_renderOnlyIfFocused = windowSwapchain.m_renderOnlyIfFocused; + m_hasFocus = windowSwapchain.m_hasFocus; + m_isMinimized = windowSwapchain.m_isMinimized; + + ConnectSignals(); + + return *this; + } + + void WindowSwapchain::DisconnectSignals() + { + m_onGainedFocus.Disconnect(); + m_onLostFocus.Disconnect(); + m_onMinimized.Disconnect(); + m_onResized.Disconnect(); + m_onRestored.Disconnect(); + } +} + +#include diff --git a/include/Nazara/VulkanRenderer.hpp b/include/Nazara/VulkanRenderer.hpp index faf8cedc7..b19f39d0f 100644 --- a/include/Nazara/VulkanRenderer.hpp +++ b/include/Nazara/VulkanRenderer.hpp @@ -45,10 +45,9 @@ #include #include #include -#include #include #include -#include +#include #include #include #include diff --git a/include/Nazara/VulkanRenderer/VulkanDevice.hpp b/include/Nazara/VulkanRenderer/VulkanDevice.hpp index 0c6c76fa6..3f07e3af1 100644 --- a/include/Nazara/VulkanRenderer/VulkanDevice.hpp +++ b/include/Nazara/VulkanRenderer/VulkanDevice.hpp @@ -35,6 +35,7 @@ namespace Nz std::shared_ptr InstantiateRenderPipelineLayout(RenderPipelineLayoutInfo pipelineLayoutInfo) override; std::shared_ptr InstantiateShaderModule(nzsl::ShaderStageTypeFlags stages, const nzsl::Ast::Module& shaderModule, const nzsl::ShaderWriter::States& states) override; std::shared_ptr InstantiateShaderModule(nzsl::ShaderStageTypeFlags stages, ShaderLanguage lang, const void* source, std::size_t sourceSize, const nzsl::ShaderWriter::States& states) override; + std::shared_ptr InstantiateSwapchain(WindowHandle windowHandle, const Vector2ui& windowSize, const SwapchainParameters& parameters) override; std::shared_ptr InstantiateTexture(const TextureInfo& params) override; std::shared_ptr InstantiateTextureSampler(const TextureSamplerInfo& params) override; diff --git a/include/Nazara/VulkanRenderer/VulkanRenderImage.hpp b/include/Nazara/VulkanRenderer/VulkanRenderImage.hpp index 0aff4cb6c..44aabd4d1 100644 --- a/include/Nazara/VulkanRenderer/VulkanRenderImage.hpp +++ b/include/Nazara/VulkanRenderer/VulkanRenderImage.hpp @@ -18,12 +18,12 @@ namespace Nz { - class VulkanRenderWindow; + class VulkanSwapchain; class NAZARA_VULKANRENDERER_API VulkanRenderImage : public RenderImage { public: - VulkanRenderImage(VulkanRenderWindow& owner); + VulkanRenderImage(VulkanSwapchain& owner); VulkanRenderImage(const VulkanRenderImage&) = delete; VulkanRenderImage(VulkanRenderImage&&) = delete; ~VulkanRenderImage(); @@ -50,7 +50,7 @@ namespace Nz std::size_t m_currentCommandBuffer; std::vector m_inFlightCommandBuffers; std::vector m_graphicalCommandsBuffers; - VulkanRenderWindow& m_owner; + VulkanSwapchain& m_owner; Vk::CommandPool m_commandPool; Vk::Fence m_inFlightFence; Vk::Semaphore m_imageAvailableSemaphore; diff --git a/include/Nazara/VulkanRenderer/VulkanRenderer.hpp b/include/Nazara/VulkanRenderer/VulkanRenderer.hpp index 67f660bc2..5372e23aa 100644 --- a/include/Nazara/VulkanRenderer/VulkanRenderer.hpp +++ b/include/Nazara/VulkanRenderer/VulkanRenderer.hpp @@ -25,9 +25,6 @@ namespace Nz VulkanRenderer() = default; ~VulkanRenderer(); - std::unique_ptr CreateRenderSurfaceImpl() override; - std::unique_ptr CreateRenderWindowImpl(RenderWindow& owner) override; - std::shared_ptr InstanciateRenderDevice(std::size_t deviceIndex, const RenderDeviceFeatures& enabledFeatures) override; RenderAPI QueryAPI() const override; diff --git a/include/Nazara/VulkanRenderer/VulkanSurface.hpp b/include/Nazara/VulkanRenderer/VulkanSurface.hpp deleted file mode 100644 index ee84bb53c..000000000 --- a/include/Nazara/VulkanRenderer/VulkanSurface.hpp +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright (C) 2022 Jérôme "Lynix" Leclercq (lynix680@gmail.com) -// This file is part of the "Nazara Engine - Vulkan renderer" -// For conditions of distribution and use, see copyright notice in Config.hpp - -#pragma once - -#ifndef NAZARA_VULKANRENDERER_VULKANSURFACE_HPP -#define NAZARA_VULKANRENDERER_VULKANSURFACE_HPP - -#include -#include -#include -#include - -namespace Nz -{ - class NAZARA_VULKANRENDERER_API VulkanSurface : public RenderSurface - { - public: - VulkanSurface(); - VulkanSurface(const VulkanSurface&) = delete; - VulkanSurface(VulkanSurface&&) = delete; ///TODO - ~VulkanSurface() = default; - - bool Create(WindowHandle handle) override; - void Destroy() override; - - inline Vk::Surface& GetSurface(); - - VulkanSurface& operator=(const VulkanSurface&) = delete; - VulkanSurface& operator=(VulkanSurface&&) = delete; ///TODO - - private: - Vk::Surface m_surface; - }; -} - -#include - -#endif // NAZARA_VULKANRENDERER_VULKANSURFACE_HPP diff --git a/include/Nazara/VulkanRenderer/VulkanSurface.inl b/include/Nazara/VulkanRenderer/VulkanSurface.inl deleted file mode 100644 index 6417dd90c..000000000 --- a/include/Nazara/VulkanRenderer/VulkanSurface.inl +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright (C) 2022 Jérôme "Lynix" Leclercq (lynix680@gmail.com) -// This file is part of the "Nazara Engine - Vulkan renderer" -// For conditions of distribution and use, see copyright notice in Config.hpp - -#include -#include - -namespace Nz -{ - inline Vk::Surface& VulkanSurface::GetSurface() - { - return m_surface; - } -} - -#include diff --git a/include/Nazara/VulkanRenderer/VulkanRenderWindow.hpp b/include/Nazara/VulkanRenderer/VulkanSwapchain.hpp similarity index 72% rename from include/Nazara/VulkanRenderer/VulkanRenderWindow.hpp rename to include/Nazara/VulkanRenderer/VulkanSwapchain.hpp index e16b6db22..5c1c003d2 100644 --- a/include/Nazara/VulkanRenderer/VulkanRenderWindow.hpp +++ b/include/Nazara/VulkanRenderer/VulkanSwapchain.hpp @@ -12,8 +12,9 @@ #include #include #include -#include +#include #include +#include #include #include #include @@ -33,17 +34,15 @@ namespace Nz { - class NAZARA_VULKANRENDERER_API VulkanRenderWindow : public RenderWindowImpl + class NAZARA_VULKANRENDERER_API VulkanSwapchain : public Swapchain { public: - VulkanRenderWindow(RenderWindow& owner); - VulkanRenderWindow(const VulkanRenderWindow&) = delete; - VulkanRenderWindow(VulkanRenderWindow&&) = delete; ///TODO - ~VulkanRenderWindow(); + VulkanSwapchain(VulkanDevice& device, WindowHandle windowHandle, const Vector2ui& windowSize, const SwapchainParameters& parameters); + VulkanSwapchain(const VulkanSwapchain&) = delete; + VulkanSwapchain(VulkanSwapchain&&) = delete; + ~VulkanSwapchain(); - RenderFrame Acquire() override; - - bool Create(RendererImpl* renderer, RenderSurface* surface, const RenderWindowParameters& parameters) override; + RenderFrame AcquireFrame() override; std::shared_ptr CreateCommandPool(QueueType queueType) override; @@ -56,20 +55,22 @@ namespace Nz const Vector2ui& GetSize() const override; inline const Vk::Swapchain& GetSwapchain() const; + void NotifyResize(const Vector2ui& newSize) override; + void Present(UInt32 imageIndex, VkSemaphore waitSemaphore = VK_NULL_HANDLE); - VulkanRenderWindow& operator=(const VulkanRenderWindow&) = delete; - VulkanRenderWindow& operator=(VulkanRenderWindow&&) = delete; ///TODO + VulkanSwapchain& operator=(const VulkanSwapchain&) = delete; + VulkanSwapchain& operator=(VulkanSwapchain&&) = delete; private: - bool CreateSwapchain(Vk::Surface& surface, const Vector2ui& size); - bool SetupDepthBuffer(const Vector2ui& size); - bool SetupFrameBuffers(const Vector2ui& size); + bool CreateSwapchain(); + bool SetupDepthBuffer(); + bool SetupFrameBuffers(); bool SetupRenderPass(); - bool SetupSwapchain(const Vk::PhysicalDevice& deviceInfo, Vk::Surface& surface, const Vector2ui& size); + bool SetupSurface(WindowHandle windowHandle); + bool SetupSwapchain(const Vk::PhysicalDevice& deviceInfo); std::optional m_renderPass; - std::shared_ptr m_device; std::size_t m_currentFrame; std::vector m_framebuffers; std::vector m_inflightFences; @@ -80,15 +81,16 @@ namespace Nz Vk::QueueHandle m_graphicsQueue; Vk::QueueHandle m_presentQueue; Vk::QueueHandle m_transferQueue; + Vk::Surface m_surface; Vk::Swapchain m_swapchain; - RenderWindow& m_owner; Vector2ui m_swapchainSize; VkFormat m_depthStencilFormat; VkSurfaceFormatKHR m_surfaceFormat; + VulkanDevice& m_device; bool m_shouldRecreateSwapchain; }; } -#include +#include #endif // NAZARA_VULKANRENDERER_VULKANRENDERWINDOW_HPP diff --git a/include/Nazara/VulkanRenderer/VulkanRenderWindow.inl b/include/Nazara/VulkanRenderer/VulkanSwapchain.inl similarity index 52% rename from include/Nazara/VulkanRenderer/VulkanRenderWindow.inl rename to include/Nazara/VulkanRenderer/VulkanSwapchain.inl index 18b36b6a6..f7cd318d3 100644 --- a/include/Nazara/VulkanRenderer/VulkanRenderWindow.inl +++ b/include/Nazara/VulkanRenderer/VulkanSwapchain.inl @@ -2,27 +2,27 @@ // This file is part of the "Nazara Engine - Vulkan renderer" // For conditions of distribution and use, see copyright notice in Config.hpp -#include +#include #include namespace Nz { - inline VulkanDevice& VulkanRenderWindow::GetDevice() + inline VulkanDevice& VulkanSwapchain::GetDevice() { - return *m_device; + return m_device; } - inline const VulkanDevice& VulkanRenderWindow::GetDevice() const + inline const VulkanDevice& VulkanSwapchain::GetDevice() const { - return *m_device; + return m_device; } - inline Vk::QueueHandle& VulkanRenderWindow::GetGraphicsQueue() + inline Vk::QueueHandle& VulkanSwapchain::GetGraphicsQueue() { return m_graphicsQueue; } - inline const Vk::Swapchain& VulkanRenderWindow::GetSwapchain() const + inline const Vk::Swapchain& VulkanSwapchain::GetSwapchain() const { return m_swapchain; } diff --git a/include/Nazara/VulkanRenderer/Wrapper/Surface.hpp b/include/Nazara/VulkanRenderer/Wrapper/Surface.hpp index 95157b889..2aba7211d 100644 --- a/include/Nazara/VulkanRenderer/Wrapper/Surface.hpp +++ b/include/Nazara/VulkanRenderer/Wrapper/Surface.hpp @@ -17,78 +17,75 @@ #include #endif -namespace Nz +namespace Nz::Vk { - namespace Vk + class Surface { - class Surface - { - public: - inline Surface(Instance& instance); - Surface(const Surface&) = delete; - Surface(Surface&& surface); - inline ~Surface(); + public: + inline Surface(Instance& instance); + Surface(const Surface&) = delete; + Surface(Surface&& surface) noexcept; + inline ~Surface(); - #ifdef VK_USE_PLATFORM_ANDROID_KHR - // VK_KHR_android_surface - inline bool Create(const VkAndroidSurfaceCreateInfoKHR& createInfo, const VkAllocationCallbacks* allocator = nullptr); - inline bool Create(ANativeWindow* window, VkAndroidSurfaceCreateFlagsKHR flags = 0, const VkAllocationCallbacks* allocator = nullptr); - #endif + #ifdef VK_USE_PLATFORM_ANDROID_KHR + // VK_KHR_android_surface + inline bool Create(const VkAndroidSurfaceCreateInfoKHR& createInfo, const VkAllocationCallbacks* allocator = nullptr); + inline bool Create(ANativeWindow* window, VkAndroidSurfaceCreateFlagsKHR flags = 0, const VkAllocationCallbacks* allocator = nullptr); + #endif - #ifdef VK_USE_PLATFORM_XCB_KHR - // VK_KHR_xcb_surface - inline bool Create(const VkXcbSurfaceCreateInfoKHR& createInfo, const VkAllocationCallbacks* allocator = nullptr); - inline bool Create(xcb_connection_t* connection, xcb_window_t window, VkXcbSurfaceCreateFlagsKHR flags = 0, const VkAllocationCallbacks* allocator = nullptr); - #endif + #ifdef VK_USE_PLATFORM_XCB_KHR + // VK_KHR_xcb_surface + inline bool Create(const VkXcbSurfaceCreateInfoKHR& createInfo, const VkAllocationCallbacks* allocator = nullptr); + inline bool Create(xcb_connection_t* connection, xcb_window_t window, VkXcbSurfaceCreateFlagsKHR flags = 0, const VkAllocationCallbacks* allocator = nullptr); + #endif - #ifdef VK_USE_PLATFORM_XLIB_KHR - // VK_KHR_xlib_surface - inline bool Create(const VkXlibSurfaceCreateInfoKHR& createInfo, const VkAllocationCallbacks* allocator = nullptr); - inline bool Create(Display* display, Window window, VkXlibSurfaceCreateFlagsKHR flags = 0, const VkAllocationCallbacks* allocator = nullptr); - #endif + #ifdef VK_USE_PLATFORM_XLIB_KHR + // VK_KHR_xlib_surface + inline bool Create(const VkXlibSurfaceCreateInfoKHR& createInfo, const VkAllocationCallbacks* allocator = nullptr); + inline bool Create(Display* display, Window window, VkXlibSurfaceCreateFlagsKHR flags = 0, const VkAllocationCallbacks* allocator = nullptr); + #endif - #ifdef VK_USE_PLATFORM_WAYLAND_KHR - // VK_KHR_wayland_surface - inline bool Create(const VkWaylandSurfaceCreateInfoKHR& createInfo, const VkAllocationCallbacks* allocator = nullptr); - inline bool Create(wl_display* display, wl_surface* surface, VkWaylandSurfaceCreateFlagsKHR flags = 0, const VkAllocationCallbacks* allocator = nullptr); - #endif + #ifdef VK_USE_PLATFORM_WAYLAND_KHR + // VK_KHR_wayland_surface + inline bool Create(const VkWaylandSurfaceCreateInfoKHR& createInfo, const VkAllocationCallbacks* allocator = nullptr); + inline bool Create(wl_display* display, wl_surface* surface, VkWaylandSurfaceCreateFlagsKHR flags = 0, const VkAllocationCallbacks* allocator = nullptr); + #endif - #ifdef VK_USE_PLATFORM_WIN32_KHR - // VK_KHR_win32_surface - inline bool Create(const VkWin32SurfaceCreateInfoKHR& createInfo, const VkAllocationCallbacks* allocator = nullptr); - inline bool Create(HINSTANCE instance, HWND handle, VkWin32SurfaceCreateFlagsKHR flags = 0, const VkAllocationCallbacks* allocator = nullptr); - #endif + #ifdef VK_USE_PLATFORM_WIN32_KHR + // VK_KHR_win32_surface + inline bool Create(const VkWin32SurfaceCreateInfoKHR& createInfo, const VkAllocationCallbacks* allocator = nullptr); + inline bool Create(HINSTANCE instance, HWND handle, VkWin32SurfaceCreateFlagsKHR flags = 0, const VkAllocationCallbacks* allocator = nullptr); + #endif - #ifdef VK_USE_PLATFORM_METAL_EXT - inline bool Create(const VkMetalSurfaceCreateInfoEXT& createInfo, const VkAllocationCallbacks* allocator = nullptr); - inline bool Create(id layer, const VkAllocationCallbacks* allocator = nullptr); - #endif + #ifdef VK_USE_PLATFORM_METAL_EXT + inline bool Create(const VkMetalSurfaceCreateInfoEXT& createInfo, const VkAllocationCallbacks* allocator = nullptr); + inline bool Create(id layer, const VkAllocationCallbacks* allocator = nullptr); + #endif - inline void Destroy(); + inline void Destroy(); - bool GetCapabilities(VkPhysicalDevice physicalDevice, VkSurfaceCapabilitiesKHR* surfaceCapabilities) const; - bool GetFormats(VkPhysicalDevice physicalDevice, std::vector* surfaceFormats) const; - bool GetPresentModes(VkPhysicalDevice physicalDevice, std::vector* presentModes) const; - bool GetSupportPresentation(VkPhysicalDevice physicalDevice, UInt32 queueFamilyIndex, bool* supported) const; + bool GetCapabilities(VkPhysicalDevice physicalDevice, VkSurfaceCapabilitiesKHR* surfaceCapabilities) const; + bool GetFormats(VkPhysicalDevice physicalDevice, std::vector* surfaceFormats) const; + bool GetPresentModes(VkPhysicalDevice physicalDevice, std::vector* presentModes) const; + bool GetSupportPresentation(VkPhysicalDevice physicalDevice, UInt32 queueFamilyIndex, bool* supported) const; - inline VkResult GetLastErrorCode() const; + inline VkResult GetLastErrorCode() const; - Surface& operator=(const Surface&) = delete; - Surface& operator=(Surface&&) = delete; + Surface& operator=(const Surface&) = delete; + Surface& operator=(Surface&&) = delete; - inline operator VkSurfaceKHR() const; + inline operator VkSurfaceKHR() const; - static inline bool IsSupported(const Instance& instance); + static inline bool IsSupported(const Instance& instance); - private: - inline bool Create(const VkAllocationCallbacks* allocator); + private: + inline bool Create(const VkAllocationCallbacks* allocator); - Instance& m_instance; - VkAllocationCallbacks m_allocator; - VkSurfaceKHR m_surface; - mutable VkResult m_lastErrorCode; - }; - } + Instance& m_instance; + VkAllocationCallbacks m_allocator; + VkSurfaceKHR m_surface; + mutable VkResult m_lastErrorCode; + }; } #include diff --git a/include/Nazara/VulkanRenderer/Wrapper/Surface.inl b/include/Nazara/VulkanRenderer/Wrapper/Surface.inl index 5e6d6b4e8..86758ee4f 100644 --- a/include/Nazara/VulkanRenderer/Wrapper/Surface.inl +++ b/include/Nazara/VulkanRenderer/Wrapper/Surface.inl @@ -7,305 +7,302 @@ #include #include -namespace Nz +namespace Nz::Vk { - namespace Vk + inline Surface::Surface(Instance& instance) : + m_instance(instance), + m_surface(VK_NULL_HANDLE) { - inline Surface::Surface(Instance& instance) : - m_instance(instance), - m_surface(VK_NULL_HANDLE) + } + + inline Surface::Surface(Surface&& surface) noexcept : + m_instance(surface.m_instance), + m_allocator(surface.m_allocator), + m_surface(surface.m_surface), + m_lastErrorCode(surface.m_lastErrorCode) + { + surface.m_surface = VK_NULL_HANDLE; + } + + inline Surface::~Surface() + { + Destroy(); + } + + #ifdef VK_USE_PLATFORM_ANDROID_KHR + inline bool Surface::Create(const VkAndroidSurfaceCreateInfoKHR& createInfo, const VkAllocationCallbacks* allocator) + { + m_lastErrorCode = m_instance.vkCreateAndroidSurfaceKHR(m_instance, &createInfo, allocator, &m_surface); + return Create(allocator); + } + + inline bool Surface::Create(ANativeWindow* window, VkAndroidSurfaceCreateFlagsKHR flags, const VkAllocationCallbacks* allocator) + { + VkAndroidSurfaceCreateInfoKHR createInfo = { - } + VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR, + nullptr, + flags, + window + }; - inline Surface::Surface(Surface&& surface) : - m_instance(surface.m_instance), - m_allocator(surface.m_allocator), - m_surface(surface.m_surface), - m_lastErrorCode(surface.m_lastErrorCode) + return Create(createInfo, allocator); + } + #endif + + #ifdef VK_USE_PLATFORM_XCB_KHR + inline bool Surface::Create(const VkXcbSurfaceCreateInfoKHR& createInfo, const VkAllocationCallbacks* allocator) + { + m_lastErrorCode = m_instance.vkCreateXcbSurfaceKHR(m_instance, &createInfo, allocator, &m_surface); + return Create(allocator); + } + + inline bool Surface::Create(xcb_connection_t* connection, xcb_window_t window, VkXcbSurfaceCreateFlagsKHR flags, const VkAllocationCallbacks* allocator) + { + VkXcbSurfaceCreateInfoKHR createInfo = { - surface.m_surface = VK_NULL_HANDLE; - } + VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR, + nullptr, + flags, + connection, + window + }; - inline Surface::~Surface() + return Create(createInfo, allocator); + } + #endif + + #ifdef VK_USE_PLATFORM_XLIB_KHR + inline bool Surface::Create(const VkXlibSurfaceCreateInfoKHR& createInfo, const VkAllocationCallbacks* allocator) + { + m_lastErrorCode = m_instance.vkCreateXlibSurfaceKHR(m_instance, &createInfo, allocator, &m_surface); + return Create(allocator); + } + + inline bool Surface::Create(Display* display, Window window, VkXlibSurfaceCreateFlagsKHR flags, const VkAllocationCallbacks* allocator) + { + VkXlibSurfaceCreateInfoKHR createInfo = { - Destroy(); - } + VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR, + nullptr, + flags, + display, + window + }; - #ifdef VK_USE_PLATFORM_ANDROID_KHR - inline bool Surface::Create(const VkAndroidSurfaceCreateInfoKHR& createInfo, const VkAllocationCallbacks* allocator) + return Create(createInfo, allocator); + } + #endif + + #ifdef VK_USE_PLATFORM_WAYLAND_KHR + inline bool Surface::Create(const VkWaylandSurfaceCreateInfoKHR& createInfo, const VkAllocationCallbacks* allocator) + { + m_lastErrorCode = m_instance.vkCreateWaylandSurfaceKHR(m_instance, &createInfo, allocator, &m_surface); + return Create(allocator); + } + + inline bool Surface::Create(wl_display* display, wl_surface* surface, VkWaylandSurfaceCreateFlagsKHR flags, const VkAllocationCallbacks* allocator) + { + VkWaylandSurfaceCreateInfoKHR createInfo = { - m_lastErrorCode = m_instance.vkCreateAndroidSurfaceKHR(m_instance, &createInfo, allocator, &m_surface); - return Create(allocator); - } + VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR, + nullptr, + flags, + display, + surface + }; - inline bool Surface::Create(ANativeWindow* window, VkAndroidSurfaceCreateFlagsKHR flags, const VkAllocationCallbacks* allocator) + return Create(createInfo, allocator); + } + #endif + + #ifdef VK_USE_PLATFORM_WIN32_KHR + inline bool Surface::Create(const VkWin32SurfaceCreateInfoKHR& createInfo, const VkAllocationCallbacks* allocator) + { + m_lastErrorCode = m_instance.vkCreateWin32SurfaceKHR(m_instance, &createInfo, allocator, &m_surface); + return Create(allocator); + } + + inline bool Surface::Create(HINSTANCE instance, HWND handle, VkWin32SurfaceCreateFlagsKHR flags, const VkAllocationCallbacks* allocator) + { + VkWin32SurfaceCreateInfoKHR createInfo = { - VkAndroidSurfaceCreateInfoKHR createInfo = - { - VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR, - nullptr, - flags, - window - }; + VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR, + nullptr, + flags, + instance, + handle + }; - return Create(createInfo, allocator); - } - #endif + return Create(createInfo, allocator); + } + #endif - #ifdef VK_USE_PLATFORM_XCB_KHR - inline bool Surface::Create(const VkXcbSurfaceCreateInfoKHR& createInfo, const VkAllocationCallbacks* allocator) + #ifdef VK_USE_PLATFORM_METAL_EXT + inline bool Surface::Create(const VkMetalSurfaceCreateInfoEXT& createInfo, const VkAllocationCallbacks* allocator) + { + m_lastErrorCode = m_instance.vkCreateMetalSurfaceEXT(m_instance, &createInfo, allocator, &m_surface); + return Create(allocator); + } + + inline bool Surface::Create(id layer, const VkAllocationCallbacks* allocator) + { + VkMetalSurfaceCreateInfoEXT createInfo = { - m_lastErrorCode = m_instance.vkCreateXcbSurfaceKHR(m_instance, &createInfo, allocator, &m_surface); - return Create(allocator); - } + VK_STRUCTURE_TYPE_METAL_SURFACE_CREATE_INFO_EXT, + nullptr, + 0, + layer + }; - inline bool Surface::Create(xcb_connection_t* connection, xcb_window_t window, VkXcbSurfaceCreateFlagsKHR flags, const VkAllocationCallbacks* allocator) + return Create(createInfo, allocator); + } + #endif + + inline void Surface::Destroy() + { + if (m_surface != VK_NULL_HANDLE) { - VkXcbSurfaceCreateInfoKHR createInfo = - { - VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR, - nullptr, - flags, - connection, - window - }; - - return Create(createInfo, allocator); - } - #endif - - #ifdef VK_USE_PLATFORM_XLIB_KHR - inline bool Surface::Create(const VkXlibSurfaceCreateInfoKHR& createInfo, const VkAllocationCallbacks* allocator) - { - m_lastErrorCode = m_instance.vkCreateXlibSurfaceKHR(m_instance, &createInfo, allocator, &m_surface); - return Create(allocator); - } - - inline bool Surface::Create(Display* display, Window window, VkXlibSurfaceCreateFlagsKHR flags, const VkAllocationCallbacks* allocator) - { - VkXlibSurfaceCreateInfoKHR createInfo = - { - VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR, - nullptr, - flags, - display, - window - }; - - return Create(createInfo, allocator); - } - #endif - - #ifdef VK_USE_PLATFORM_WAYLAND_KHR - inline bool Surface::Create(const VkWaylandSurfaceCreateInfoKHR& createInfo, const VkAllocationCallbacks* allocator) - { - m_lastErrorCode = m_instance.vkCreateWaylandSurfaceKHR(m_instance, &createInfo, allocator, &m_surface); - return Create(allocator); - } - - inline bool Surface::Create(wl_display* display, wl_surface* surface, VkWaylandSurfaceCreateFlagsKHR flags, const VkAllocationCallbacks* allocator) - { - VkWaylandSurfaceCreateInfoKHR createInfo = - { - VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR, - nullptr, - flags, - display, - surface - }; - - return Create(createInfo, allocator); - } - #endif - - #ifdef VK_USE_PLATFORM_WIN32_KHR - inline bool Surface::Create(const VkWin32SurfaceCreateInfoKHR& createInfo, const VkAllocationCallbacks* allocator) - { - m_lastErrorCode = m_instance.vkCreateWin32SurfaceKHR(m_instance, &createInfo, allocator, &m_surface); - return Create(allocator); - } - - inline bool Surface::Create(HINSTANCE instance, HWND handle, VkWin32SurfaceCreateFlagsKHR flags, const VkAllocationCallbacks* allocator) - { - VkWin32SurfaceCreateInfoKHR createInfo = - { - VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR, - nullptr, - flags, - instance, - handle - }; - - return Create(createInfo, allocator); - } - #endif - - #ifdef VK_USE_PLATFORM_METAL_EXT - inline bool Surface::Create(const VkMetalSurfaceCreateInfoEXT& createInfo, const VkAllocationCallbacks* allocator) - { - m_lastErrorCode = m_instance.vkCreateMetalSurfaceEXT(m_instance, &createInfo, allocator, &m_surface); - return Create(allocator); - } - - inline bool Surface::Create(id layer, const VkAllocationCallbacks* allocator) - { - VkMetalSurfaceCreateInfoEXT createInfo = - { - VK_STRUCTURE_TYPE_METAL_SURFACE_CREATE_INFO_EXT, - nullptr, - 0, - layer - }; - - return Create(createInfo, allocator); - } - #endif - - inline void Surface::Destroy() - { - if (m_surface != VK_NULL_HANDLE) - { - m_instance.vkDestroySurfaceKHR(m_instance, m_surface, (m_allocator.pfnAllocation) ? &m_allocator : nullptr); - m_surface = VK_NULL_HANDLE; - } + m_instance.vkDestroySurfaceKHR(m_instance, m_surface, (m_allocator.pfnAllocation) ? &m_allocator : nullptr); + m_surface = VK_NULL_HANDLE; } + } - inline VkResult Surface::GetLastErrorCode() const + inline VkResult Surface::GetLastErrorCode() const + { + return m_lastErrorCode; + } + + inline bool Surface::GetCapabilities(VkPhysicalDevice physicalDevice, VkSurfaceCapabilitiesKHR* surfaceCapabilities) const + { + m_lastErrorCode = m_instance.vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physicalDevice, m_surface, surfaceCapabilities); + if (m_lastErrorCode != VkResult::VK_SUCCESS) { - return m_lastErrorCode; - } - - inline bool Surface::GetCapabilities(VkPhysicalDevice physicalDevice, VkSurfaceCapabilitiesKHR* surfaceCapabilities) const - { - m_lastErrorCode = m_instance.vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physicalDevice, m_surface, surfaceCapabilities); - if (m_lastErrorCode != VkResult::VK_SUCCESS) - { - NazaraError("Failed to query surface capabilities: " + TranslateVulkanError(m_lastErrorCode)); - return false; - } - - return true; - } - - inline bool Surface::GetFormats(VkPhysicalDevice physicalDevice, std::vector* surfaceFormats) const - { - // First, query format count - UInt32 surfaceCount = 0; // Remember, Nz::UInt32 is a typedef on uint32_t - m_lastErrorCode = m_instance.vkGetPhysicalDeviceSurfaceFormatsKHR(physicalDevice, m_surface, &surfaceCount, nullptr); - if (m_lastErrorCode != VkResult::VK_SUCCESS || surfaceCount == 0) - { - NazaraError("Failed to query format count: " + TranslateVulkanError(m_lastErrorCode)); - return false; - } - - // Now we can get the list of the available physical device - surfaceFormats->resize(surfaceCount); - m_lastErrorCode = m_instance.vkGetPhysicalDeviceSurfaceFormatsKHR(physicalDevice, m_surface, &surfaceCount, surfaceFormats->data()); - if (m_lastErrorCode != VkResult::VK_SUCCESS) - { - NazaraError("Failed to query formats: " + TranslateVulkanError(m_lastErrorCode)); - return false; - } - - return true; - } - - inline bool Surface::GetPresentModes(VkPhysicalDevice physicalDevice, std::vector* presentModes) const - { - // First, query present modes count - UInt32 presentModeCount = 0; // Remember, Nz::UInt32 is a typedef on uint32_t - m_lastErrorCode = m_instance.vkGetPhysicalDeviceSurfacePresentModesKHR(physicalDevice, m_surface, &presentModeCount, nullptr); - if (m_lastErrorCode != VkResult::VK_SUCCESS || presentModeCount == 0) - { - NazaraError("Failed to query present mode count"); - return false; - } - - // Now we can get the list of the available physical device - presentModes->resize(presentModeCount); - m_lastErrorCode = m_instance.vkGetPhysicalDeviceSurfacePresentModesKHR(physicalDevice, m_surface, &presentModeCount, presentModes->data()); - if (m_lastErrorCode != VkResult::VK_SUCCESS) - { - NazaraError("Failed to query present modes: " + TranslateVulkanError(m_lastErrorCode)); - return false; - } - - return true; - } - - inline bool Surface::GetSupportPresentation(VkPhysicalDevice physicalDevice, UInt32 queueFamilyIndex, bool* supported) const - { - VkBool32 presentationSupported = VK_FALSE; - m_lastErrorCode = m_instance.vkGetPhysicalDeviceSurfaceSupportKHR(physicalDevice, queueFamilyIndex, m_surface, &presentationSupported); - if (m_lastErrorCode != VkResult::VK_SUCCESS) - { - NazaraError("Failed to query surface capabilities: " + TranslateVulkanError(m_lastErrorCode)); - return false; - } - - *supported = (presentationSupported == VK_TRUE); - - return true; - } - - inline Surface::operator VkSurfaceKHR() const - { - return m_surface; - } - - inline bool Surface::IsSupported(const Instance& instance) - { - if (!instance.IsExtensionLoaded(VK_KHR_SURFACE_EXTENSION_NAME)) - return false; - -#ifdef VK_USE_PLATFORM_ANDROID_KHR - if (instance.IsExtensionLoaded(VK_KHR_ANDROID_SURFACE_EXTENSION_NAME)) - return true; -#endif - -#ifdef VK_USE_PLATFORM_XCB_KHR - if (instance.IsExtensionLoaded(VK_KHR_XCB_SURFACE_EXTENSION_NAME)) - return true; -#endif - -#ifdef VK_USE_PLATFORM_XLIB_KHR - if (instance.IsExtensionLoaded(VK_KHR_XLIB_SURFACE_EXTENSION_NAME)) - return true; -#endif - -#ifdef VK_USE_PLATFORM_WAYLAND_KHR - if (instance.IsExtensionLoaded(VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME)) - return true; -#endif - -#ifdef VK_USE_PLATFORM_WIN32_KHR - if (instance.IsExtensionLoaded(VK_KHR_WIN32_SURFACE_EXTENSION_NAME)) - return true; -#endif - -#ifdef VK_USE_PLATFORM_METAL_EXT - if (instance.IsExtensionLoaded(VK_EXT_METAL_SURFACE_EXTENSION_NAME)) - return true; -#endif + NazaraError("Failed to query surface capabilities: " + TranslateVulkanError(m_lastErrorCode)); return false; } - inline bool Surface::Create(const VkAllocationCallbacks* allocator) + return true; + } + + inline bool Surface::GetFormats(VkPhysicalDevice physicalDevice, std::vector* surfaceFormats) const + { + // First, query format count + UInt32 surfaceCount = 0; // Remember, Nz::UInt32 is a typedef on uint32_t + m_lastErrorCode = m_instance.vkGetPhysicalDeviceSurfaceFormatsKHR(physicalDevice, m_surface, &surfaceCount, nullptr); + if (m_lastErrorCode != VkResult::VK_SUCCESS || surfaceCount == 0) { - if (m_lastErrorCode != VkResult::VK_SUCCESS) - { - NazaraError("Failed to create Vulkan surface: " + TranslateVulkanError(m_lastErrorCode)); - return false; - } - - // Store the allocator to access them when needed - if (allocator) - m_allocator = *allocator; - else - m_allocator.pfnAllocation = nullptr; - - return true; + NazaraError("Failed to query format count: " + TranslateVulkanError(m_lastErrorCode)); + return false; } + + // Now we can get the list of the available physical device + surfaceFormats->resize(surfaceCount); + m_lastErrorCode = m_instance.vkGetPhysicalDeviceSurfaceFormatsKHR(physicalDevice, m_surface, &surfaceCount, surfaceFormats->data()); + if (m_lastErrorCode != VkResult::VK_SUCCESS) + { + NazaraError("Failed to query formats: " + TranslateVulkanError(m_lastErrorCode)); + return false; + } + + return true; + } + + inline bool Surface::GetPresentModes(VkPhysicalDevice physicalDevice, std::vector* presentModes) const + { + // First, query present modes count + UInt32 presentModeCount = 0; // Remember, Nz::UInt32 is a typedef on uint32_t + m_lastErrorCode = m_instance.vkGetPhysicalDeviceSurfacePresentModesKHR(physicalDevice, m_surface, &presentModeCount, nullptr); + if (m_lastErrorCode != VkResult::VK_SUCCESS || presentModeCount == 0) + { + NazaraError("Failed to query present mode count"); + return false; + } + + // Now we can get the list of the available physical device + presentModes->resize(presentModeCount); + m_lastErrorCode = m_instance.vkGetPhysicalDeviceSurfacePresentModesKHR(physicalDevice, m_surface, &presentModeCount, presentModes->data()); + if (m_lastErrorCode != VkResult::VK_SUCCESS) + { + NazaraError("Failed to query present modes: " + TranslateVulkanError(m_lastErrorCode)); + return false; + } + + return true; + } + + inline bool Surface::GetSupportPresentation(VkPhysicalDevice physicalDevice, UInt32 queueFamilyIndex, bool* supported) const + { + VkBool32 presentationSupported = VK_FALSE; + m_lastErrorCode = m_instance.vkGetPhysicalDeviceSurfaceSupportKHR(physicalDevice, queueFamilyIndex, m_surface, &presentationSupported); + if (m_lastErrorCode != VkResult::VK_SUCCESS) + { + NazaraError("Failed to query surface capabilities: " + TranslateVulkanError(m_lastErrorCode)); + return false; + } + + *supported = (presentationSupported == VK_TRUE); + + return true; + } + + inline Surface::operator VkSurfaceKHR() const + { + return m_surface; + } + + inline bool Surface::IsSupported(const Instance& instance) + { + if (!instance.IsExtensionLoaded(VK_KHR_SURFACE_EXTENSION_NAME)) + return false; + +#ifdef VK_USE_PLATFORM_ANDROID_KHR + if (instance.IsExtensionLoaded(VK_KHR_ANDROID_SURFACE_EXTENSION_NAME)) + return true; +#endif + +#ifdef VK_USE_PLATFORM_XCB_KHR + if (instance.IsExtensionLoaded(VK_KHR_XCB_SURFACE_EXTENSION_NAME)) + return true; +#endif + +#ifdef VK_USE_PLATFORM_XLIB_KHR + if (instance.IsExtensionLoaded(VK_KHR_XLIB_SURFACE_EXTENSION_NAME)) + return true; +#endif + +#ifdef VK_USE_PLATFORM_WAYLAND_KHR + if (instance.IsExtensionLoaded(VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME)) + return true; +#endif + +#ifdef VK_USE_PLATFORM_WIN32_KHR + if (instance.IsExtensionLoaded(VK_KHR_WIN32_SURFACE_EXTENSION_NAME)) + return true; +#endif + +#ifdef VK_USE_PLATFORM_METAL_EXT + if (instance.IsExtensionLoaded(VK_EXT_METAL_SURFACE_EXTENSION_NAME)) + return true; +#endif + return false; + } + + inline bool Surface::Create(const VkAllocationCallbacks* allocator) + { + if (m_lastErrorCode != VkResult::VK_SUCCESS) + { + NazaraError("Failed to create Vulkan surface: " + TranslateVulkanError(m_lastErrorCode)); + return false; + } + + // Store the allocator to access them when needed + if (allocator) + m_allocator = *allocator; + else + m_allocator.pfnAllocation = nullptr; + + return true; } } diff --git a/include/Nazara/Widgets/BaseWidget.hpp b/include/Nazara/Widgets/BaseWidget.hpp index 320b312ed..a69003510 100644 --- a/include/Nazara/Widgets/BaseWidget.hpp +++ b/include/Nazara/Widgets/BaseWidget.hpp @@ -8,7 +8,7 @@ #define NAZARA_WIDGETS_BASEWIDGET_HPP #include -#include +#include #include #include #include diff --git a/include/Nazara/Widgets/Canvas.hpp b/include/Nazara/Widgets/Canvas.hpp index 95909b076..bff50e952 100644 --- a/include/Nazara/Widgets/Canvas.hpp +++ b/include/Nazara/Widgets/Canvas.hpp @@ -8,7 +8,7 @@ #define NAZARA_WIDGETS_CANVAS_HPP #include -#include +#include #include #include #include @@ -20,7 +20,7 @@ namespace Nz friend BaseWidget; public: - Canvas(entt::registry& registry, EventHandler& eventHandler, CursorControllerHandle cursorController, UInt32 renderMask, int initialRenderLayer = 0); + Canvas(entt::registry& registry, WindowEventHandler& eventHandler, CursorControllerHandle cursorController, UInt32 renderMask, int initialRenderLayer = 0); Canvas(const Canvas&) = delete; Canvas(Canvas&&) = delete; inline ~Canvas(); @@ -32,8 +32,8 @@ namespace Nz Canvas& operator=(const Canvas&) = delete; Canvas& operator=(Canvas&&) = delete; - NazaraSignal(OnUnhandledKeyPressed, const EventHandler* /*eventHandler*/, const WindowEvent::KeyEvent& /*event*/); - NazaraSignal(OnUnhandledKeyReleased, const EventHandler* /*eventHandler*/, const WindowEvent::KeyEvent& /*event*/); + NazaraSignal(OnUnhandledKeyPressed, const WindowEventHandler* /*eventHandler*/, const WindowEvent::KeyEvent& /*event*/); + NazaraSignal(OnUnhandledKeyReleased, const WindowEventHandler* /*eventHandler*/, const WindowEvent::KeyEvent& /*event*/); protected: inline void ClearKeyboardOwner(std::size_t canvasIndex); @@ -57,17 +57,17 @@ namespace Nz private: template void DispatchEvent(std::size_t widgetIndex, F&& functor); - void OnEventMouseButtonPressed(const EventHandler* eventHandler, const WindowEvent::MouseButtonEvent& event); - void OnEventMouseButtonRelease(const EventHandler* eventHandler, const WindowEvent::MouseButtonEvent& event); - void OnEventMouseEntered(const EventHandler* eventHandler); - void OnEventMouseLeft(const EventHandler* eventHandler); - void OnEventMouseMoved(const EventHandler* eventHandler, const WindowEvent::MouseMoveEvent& event); + void OnEventMouseButtonPressed(const WindowEventHandler* eventHandler, const WindowEvent::MouseButtonEvent& event); + void OnEventMouseButtonRelease(const WindowEventHandler* eventHandler, const WindowEvent::MouseButtonEvent& event); + void OnEventMouseEntered(const WindowEventHandler* eventHandler); + void OnEventMouseLeft(const WindowEventHandler* eventHandler); + void OnEventMouseMoved(const WindowEventHandler* eventHandler, const WindowEvent::MouseMoveEvent& event); - void OnEventMouseWheelMoved(const EventHandler* eventHandler, const WindowEvent::MouseWheelEvent& event); - void OnEventKeyPressed(const EventHandler* eventHandler, const WindowEvent::KeyEvent& event); - void OnEventKeyReleased(const EventHandler* eventHandler, const WindowEvent::KeyEvent& event); - void OnEventTextEntered(const EventHandler* eventHandler, const WindowEvent::TextEvent& event); - void OnEventTextEdited(const EventHandler* eventHandler, const WindowEvent::EditEvent& event); + void OnEventMouseWheelMoved(const WindowEventHandler* eventHandler, const WindowEvent::MouseWheelEvent& event); + void OnEventKeyPressed(const WindowEventHandler* eventHandler, const WindowEvent::KeyEvent& event); + void OnEventKeyReleased(const WindowEventHandler* eventHandler, const WindowEvent::KeyEvent& event); + void OnEventTextEntered(const WindowEventHandler* eventHandler, const WindowEvent::TextEvent& event); + void OnEventTextEdited(const WindowEventHandler* eventHandler, const WindowEvent::EditEvent& event); void UpdateHoveredWidget(int x, int y); @@ -78,16 +78,16 @@ namespace Nz SystemCursor cursor; }; - NazaraSlot(EventHandler, OnKeyPressed, m_keyPressedSlot); - NazaraSlot(EventHandler, OnKeyReleased, m_keyReleasedSlot); - NazaraSlot(EventHandler, OnMouseButtonPressed, m_mouseButtonPressedSlot); - NazaraSlot(EventHandler, OnMouseButtonReleased, m_mouseButtonReleasedSlot); - NazaraSlot(EventHandler, OnMouseEntered, m_mouseEnteredSlot); - NazaraSlot(EventHandler, OnMouseLeft, m_mouseLeftSlot); - NazaraSlot(EventHandler, OnMouseMoved, m_mouseMovedSlot); - NazaraSlot(EventHandler, OnMouseWheelMoved, m_mouseWheelMovedSlot); - NazaraSlot(EventHandler, OnTextEntered, m_textEnteredSlot); - NazaraSlot(EventHandler, OnTextEdited, m_textEditedSlot); + NazaraSlot(WindowEventHandler, OnKeyPressed, m_keyPressedSlot); + NazaraSlot(WindowEventHandler, OnKeyReleased, m_keyReleasedSlot); + NazaraSlot(WindowEventHandler, OnMouseButtonPressed, m_mouseButtonPressedSlot); + NazaraSlot(WindowEventHandler, OnMouseButtonReleased, m_mouseButtonReleasedSlot); + NazaraSlot(WindowEventHandler, OnMouseEntered, m_mouseEnteredSlot); + NazaraSlot(WindowEventHandler, OnMouseLeft, m_mouseLeftSlot); + NazaraSlot(WindowEventHandler, OnMouseMoved, m_mouseMovedSlot); + NazaraSlot(WindowEventHandler, OnMouseWheelMoved, m_mouseWheelMovedSlot); + NazaraSlot(WindowEventHandler, OnTextEntered, m_textEnteredSlot); + NazaraSlot(WindowEventHandler, OnTextEdited, m_textEditedSlot); CursorControllerHandle m_cursorController; UInt32 m_renderMask; diff --git a/src/Nazara/Graphics/Systems/RenderSystem.cpp b/src/Nazara/Graphics/Systems/RenderSystem.cpp index b5db54d32..ac31f9d7a 100644 --- a/src/Nazara/Graphics/Systems/RenderSystem.cpp +++ b/src/Nazara/Graphics/Systems/RenderSystem.cpp @@ -10,7 +10,7 @@ #include #include #include -#include +#include #include #include #include @@ -48,13 +48,18 @@ namespace Nz m_pipeline.reset(); } + WindowSwapchain& RenderSystem::CreateSwapchain(Window& window, const SwapchainParameters& parameters) + { + return *m_windowSwapchains.emplace_back(std::make_unique(Graphics::Instance()->GetRenderDevice(), window, parameters)); + } + void RenderSystem::Update(Time /*elapsedTime*/) { UpdateObservers(); UpdateVisibility(); UpdateInstances(); - for (auto& windowPtr : m_renderWindows) + for (auto& windowPtr : m_windowSwapchains) { RenderFrame frame = windowPtr->AcquireFrame(); if (!frame) diff --git a/src/Nazara/OpenGLRenderer/DummySurface.cpp b/src/Nazara/OpenGLRenderer/DummySurface.cpp deleted file mode 100644 index a480ae1fb..000000000 --- a/src/Nazara/OpenGLRenderer/DummySurface.cpp +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright (C) 2022 Jérôme "Lynix" Leclercq (lynix680@gmail.com) -// This file is part of the "Nazara Engine - OpenGL renderer" -// For conditions of distribution and use, see copyright notice in Config.hpp - -#include -#include - -namespace Nz -{ - bool DummySurface::Create(WindowHandle handle) - { - m_handle = handle; - return true; - } - - void DummySurface::Destroy() - { - m_handle = WindowHandle{}; - } -} diff --git a/src/Nazara/OpenGLRenderer/OpenGLDevice.cpp b/src/Nazara/OpenGLRenderer/OpenGLDevice.cpp index 70854a40f..f07b96913 100644 --- a/src/Nazara/OpenGLRenderer/OpenGLDevice.cpp +++ b/src/Nazara/OpenGLRenderer/OpenGLDevice.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -200,6 +201,11 @@ namespace Nz return std::make_shared(*this, shaderStages, lang, source, sourceSize, states); } + std::shared_ptr OpenGLDevice::InstantiateSwapchain(WindowHandle windowHandle, const Vector2ui& windowSize, const SwapchainParameters& parameters) + { + return std::make_shared(*this, windowHandle, windowSize, parameters); + } + std::shared_ptr OpenGLDevice::InstantiateTexture(const TextureInfo& params) { return std::make_shared(*this, params); diff --git a/src/Nazara/OpenGLRenderer/OpenGLRenderImage.cpp b/src/Nazara/OpenGLRenderer/OpenGLRenderImage.cpp index 24a3e7e92..1fdb3681e 100644 --- a/src/Nazara/OpenGLRenderer/OpenGLRenderImage.cpp +++ b/src/Nazara/OpenGLRenderer/OpenGLRenderImage.cpp @@ -5,13 +5,13 @@ #include #include #include -#include +#include #include #include namespace Nz { - OpenGLRenderImage::OpenGLRenderImage(OpenGLRenderWindow& owner) : + OpenGLRenderImage::OpenGLRenderImage(OpenGLSwapchain& owner) : m_owner(owner), m_uploadPool(2 * 1024 * 1024) { diff --git a/src/Nazara/OpenGLRenderer/OpenGLRenderer.cpp b/src/Nazara/OpenGLRenderer/OpenGLRenderer.cpp index 8c1afc1d3..38df7658a 100644 --- a/src/Nazara/OpenGLRenderer/OpenGLRenderer.cpp +++ b/src/Nazara/OpenGLRenderer/OpenGLRenderer.cpp @@ -4,11 +4,9 @@ #include #include -#include -#include +#include #include -#include -#include +#include #include #include @@ -30,17 +28,7 @@ namespace Nz m_device.reset(); } - std::unique_ptr OpenGLRenderer::CreateRenderSurfaceImpl() - { - return std::make_unique(); - } - - std::unique_ptr OpenGLRenderer::CreateRenderWindowImpl(RenderWindow& owner) - { - return std::make_unique(owner); - } - - std::shared_ptr OpenGLRenderer::InstanciateRenderDevice(std::size_t deviceIndex, const RenderDeviceFeatures& enabledFeatures) + std::shared_ptr OpenGLRenderer::InstanciateRenderDevice([[maybe_unused]] std::size_t deviceIndex, const RenderDeviceFeatures& enabledFeatures) { assert(deviceIndex == 0); diff --git a/src/Nazara/OpenGLRenderer/OpenGLRenderWindow.cpp b/src/Nazara/OpenGLRenderer/OpenGLSwapchain.cpp similarity index 59% rename from src/Nazara/OpenGLRenderer/OpenGLRenderWindow.cpp rename to src/Nazara/OpenGLRenderer/OpenGLSwapchain.cpp index f9a817f28..1fbc9476c 100644 --- a/src/Nazara/OpenGLRenderer/OpenGLRenderWindow.cpp +++ b/src/Nazara/OpenGLRenderer/OpenGLSwapchain.cpp @@ -2,64 +2,36 @@ // This file is part of the "Nazara Engine - OpenGL renderer" // For conditions of distribution and use, see copyright notice in Config.hpp -#include -#include +#include #include #include #include -#include +#include #include namespace Nz { - OpenGLRenderWindow::OpenGLRenderWindow(RenderWindow& owner) : + OpenGLSwapchain::OpenGLSwapchain(OpenGLDevice& device, WindowHandle windowHandle, const Vector2ui& windowSize, const SwapchainParameters& parameters) : m_currentFrame(0), m_framebuffer(*this), - m_owner(owner) + m_size(windowSize), + m_sizeInvalidated(false) { - } - - RenderFrame OpenGLRenderWindow::Acquire() - { - if (m_owner.IsMinimized()) - return RenderFrame(); - - bool invalidateFramebuffer = false; - Vector2ui size = m_owner.GetSize(); - if (m_size != size) - { - invalidateFramebuffer = true; - - OnRenderTargetSizeChange(this, size); - m_size = size; - } - - return RenderFrame(m_renderImage[m_currentFrame].get(), invalidateFramebuffer, m_size, 0); - } - - bool OpenGLRenderWindow::Create(RendererImpl* /*renderer*/, RenderSurface* surface, const RenderWindowParameters& parameters) - { - DummySurface* dummySurface = static_cast(surface); - - OpenGLDevice& device = static_cast(*m_owner.GetRenderDevice()); - GL::ContextParams contextParams; #ifdef NAZARA_OPENGLRENDERER_DEBUG contextParams.wrapErrorHandling = true; #endif - //TODO: Pass render window parameters to context + //TODO: Pass swapchain parameters to context - m_context = device.CreateContext(contextParams, dummySurface->GetWindowHandle()); + m_context = device.CreateContext(contextParams, windowHandle); if (!m_context) - return false; - - m_size = m_owner.GetSize(); + throw std::runtime_error("failed to create swapchain context"); // TODO: extract the exact window pixel format PixelFormat colorFormat; switch (contextParams.bitsPerPixel) { - case 8: colorFormat = PixelFormat::R8; break; + case 8: colorFormat = PixelFormat::R8; break; case 16: colorFormat = PixelFormat::RG8; break; case 24: colorFormat = PixelFormat::RGB8; break; @@ -94,38 +66,52 @@ namespace Nz m_renderImage.reserve(RenderImageCount); for (std::size_t i = 0; i < RenderImageCount; ++i) m_renderImage.emplace_back(std::make_unique(*this)); - - return true; } - std::shared_ptr OpenGLRenderWindow::CreateCommandPool(QueueType /*queueType*/) + RenderFrame OpenGLSwapchain::AcquireFrame() + { + bool sizeInvalidated = m_sizeInvalidated; + m_sizeInvalidated = false; + + return RenderFrame(m_renderImage[m_currentFrame].get(), sizeInvalidated, m_size, 0); + } + + std::shared_ptr OpenGLSwapchain::CreateCommandPool(QueueType /*queueType*/) { return std::make_unique(); } - const OpenGLFramebuffer& OpenGLRenderWindow::GetFramebuffer(std::size_t i) const + const OpenGLFramebuffer& OpenGLSwapchain::GetFramebuffer(std::size_t i) const { assert(i == 0); NazaraUnused(i); return m_framebuffer; } - std::size_t OpenGLRenderWindow::GetFramebufferCount() const + std::size_t OpenGLSwapchain::GetFramebufferCount() const { return 1; } - const OpenGLRenderPass& OpenGLRenderWindow::GetRenderPass() const + const OpenGLRenderPass& OpenGLSwapchain::GetRenderPass() const { return *m_renderPass; } - const Vector2ui& OpenGLRenderWindow::GetSize() const + const Vector2ui& OpenGLSwapchain::GetSize() const { return m_size; } - void OpenGLRenderWindow::Present() + void OpenGLSwapchain::NotifyResize(const Vector2ui& newSize) + { + OnRenderTargetSizeChange(this, newSize); + + m_size = newSize; + m_sizeInvalidated = true; + } + + void OpenGLSwapchain::Present() { m_context->SwapBuffers(); m_currentFrame = (m_currentFrame + 1) % m_renderImage.size(); diff --git a/src/Nazara/OpenGLRenderer/OpenGLWindowFramebuffer.cpp b/src/Nazara/OpenGLRenderer/OpenGLWindowFramebuffer.cpp index 63e9b8961..b02f7a89c 100644 --- a/src/Nazara/OpenGLRenderer/OpenGLWindowFramebuffer.cpp +++ b/src/Nazara/OpenGLRenderer/OpenGLWindowFramebuffer.cpp @@ -3,7 +3,7 @@ // For conditions of distribution and use, see copyright notice in Config.hpp #include -#include +#include #include #include diff --git a/src/Nazara/Platform/AppWindowingComponent.cpp b/src/Nazara/Platform/AppWindowingComponent.cpp index 621808ca9..c82234eaf 100644 --- a/src/Nazara/Platform/AppWindowingComponent.cpp +++ b/src/Nazara/Platform/AppWindowingComponent.cpp @@ -3,12 +3,25 @@ // For conditions of distribution and use, see copyright notice in Config.hpp #include +#include #include namespace Nz { void AppWindowingComponent::Update(Time elapsedTime) { - // SDL_PollEvent + Window::ProcessEvents(); + + for (auto it = m_windows.begin(); it != m_windows.end();) + { + Window& window = **it; + if (!window.IsOpen(true)) + it = m_windows.erase(it); + else + ++it; + } + + if (m_quitOnLastWindowClosed && m_windows.empty()) + GetApp().Quit(); } } diff --git a/src/Nazara/Platform/SDL2/WindowImpl.cpp b/src/Nazara/Platform/SDL2/WindowImpl.cpp index 0ee55185c..1e3df5b8a 100644 --- a/src/Nazara/Platform/SDL2/WindowImpl.cpp +++ b/src/Nazara/Platform/SDL2/WindowImpl.cpp @@ -34,16 +34,11 @@ namespace Nz { switch (sdlButton) { - case SDL_BUTTON_LEFT: - return Mouse::Left; - case SDL_BUTTON_MIDDLE: - return Mouse::Middle; - case SDL_BUTTON_RIGHT: - return Mouse::Right; - case SDL_BUTTON_X1: - return Mouse::XButton1; - case SDL_BUTTON_X2: - return Mouse::XButton2; + case SDL_BUTTON_LEFT: return Mouse::Left; + case SDL_BUTTON_MIDDLE: return Mouse::Middle; + case SDL_BUTTON_RIGHT: return Mouse::Right; + case SDL_BUTTON_X1: return Mouse::XButton1; + case SDL_BUTTON_X2: return Mouse::XButton2; default: NazaraAssert(false, "Unkown mouse button"); return Mouse::Left; @@ -54,30 +49,16 @@ namespace Nz WindowImpl::WindowImpl(Window* parent) : m_cursor(nullptr), m_handle(nullptr), - //m_callback(0), - m_style(0), - m_maxSize(-1), - m_minSize(-1), m_parent(parent), - m_keyRepeat(true), - m_mouseInside(false), - m_smoothScrolling(false), - m_scrolling(0) + m_eventListener(false), + m_ignoreNextMouseMove(false), + m_lastEditEventLength(0) { m_cursor = SDL_GetDefaultCursor(); } bool WindowImpl::Create(const VideoMode& mode, const std::string& title, WindowStyleFlags style) { - bool async = (style & WindowStyle::Threaded) != 0; - if (async) - { - NazaraError("SDL2 backend doesn't support asyn window for now"); - - return false; - } - - bool fullscreen = (style & WindowStyle::Fullscreen) != 0; Uint32 winStyle = 0; @@ -88,7 +69,6 @@ namespace Nz if (fullscreen) winStyle |= SDL_WINDOW_FULLSCREEN; - // Testé une seconde fois car sa valeur peut changer if (fullscreen) { x = 0; @@ -105,72 +85,106 @@ namespace Nz if (style & WindowStyle::Resizable) winStyle |= SDL_WINDOW_RESIZABLE; - if (style & WindowStyle::Max) - winStyle |= SDL_WINDOW_MAXIMIZED; - m_eventListener = true; m_ownsWindow = true; - m_sizemove = false; - m_style = style; m_handle = SDL_CreateWindow(title.c_str(), x, y, width, height, winStyle); - if (!m_handle) { NazaraError("Failed to create window: " + Error::GetLastSystemError()); return false; } - PrepareWindow(fullscreen); - - SDL_AddEventWatch(HandleEvent, this); - + m_windowId = SDL_GetWindowID(m_handle); + SetEventListener(true); return true; } - bool WindowImpl::Create(void* handle) + bool WindowImpl::Create(WindowHandle handle) { - m_handle = SDL_CreateWindowFrom(handle); + void* systemHandle = nullptr; + switch (handle.type) + { + case WindowBackend::Invalid: + { + NazaraError("unsupported creation from a Wayland handle"); + return false; + } + + case WindowBackend::Wayland: + { + NazaraError("unsupported creation from a Wayland handle"); + return false; + } + + case WindowBackend::Cocoa: systemHandle = handle.cocoa.window; break; + case WindowBackend::X11: systemHandle = (void*) handle.x11.window; break; + case WindowBackend::Windows: systemHandle = handle.windows.window; break; + } + + m_ownsWindow = false; + + m_handle = SDL_CreateWindowFrom(systemHandle); if (!m_handle) { NazaraError("Invalid handle"); return false; } - m_eventListener = false; - m_ownsWindow = false; - m_sizemove = false; - - SDL_GetWindowPosition(m_handle, &m_position.x, &m_position.y); - - int width; - int height; - SDL_GetWindowSize(m_handle, &width, &height); - - m_size.Set(width, height); - + m_windowId = SDL_GetWindowID(m_handle); + SetEventListener(true); return true; } void WindowImpl::Destroy() { - if (m_ownsWindow && m_handle) + SetEventListener(false); + + if (m_handle) { - SDL_DelEventWatch(HandleEvent, this); - SDL_DestroyWindow(m_handle); + if (m_ownsWindow) + SDL_DestroyWindow(m_handle); + + m_handle = nullptr; } - else - SetEventListener(false); } - void WindowImpl::EnableKeyRepeat(bool enable) + Vector2i WindowImpl::FetchPosition() const { - m_keyRepeat = enable; + int x, y; + SDL_GetWindowPosition(m_handle, &x, &y); + + return { x, y }; } - void WindowImpl::EnableSmoothScrolling(bool enable) + Vector2ui WindowImpl::FetchSize() const { - m_smoothScrolling = enable; + int width, height; + SDL_GetWindowSize(m_handle, &width, &height); + + return { SafeCast(width), SafeCast(height) }; + } + + WindowStyleFlags WindowImpl::FetchStyle() const + { + UInt32 windowFlags = SDL_GetWindowFlags(m_handle); + + WindowStyleFlags styleFlags; + if (windowFlags & SDL_WINDOW_RESIZABLE) + styleFlags |= WindowStyle::Resizable; + + if ((windowFlags & SDL_WINDOW_BORDERLESS) == 0) + styleFlags |= WindowStyle::Titlebar | WindowStyle::Closable; + + if (windowFlags & SDL_WINDOW_FULLSCREEN) + styleFlags |= WindowStyle::Fullscreen; + + return styleFlags; + } + + std::string WindowImpl::FetchTitle() const + { + return SDL_GetWindowTitle(m_handle); } SDL_Window* WindowImpl::GetHandle() const @@ -178,21 +192,6 @@ namespace Nz return m_handle; } - Vector2i WindowImpl::GetPosition() const - { - return m_position; - } - - Vector2ui WindowImpl::GetSize() const - { - return m_size; - } - - WindowStyleFlags WindowImpl::GetStyle() const - { - return m_style; - } - WindowHandle WindowImpl::GetSystemHandle() const { SDL_SysWMinfo wmInfo; @@ -253,22 +252,14 @@ namespace Nz return handle; } - std::string WindowImpl::GetTitle() const - { - return SDL_GetWindowTitle(m_handle); - } - bool WindowImpl::HasFocus() const { return (SDL_GetWindowFlags(m_handle) & SDL_WINDOW_INPUT_FOCUS) != 0; } - void WindowImpl::IgnoreNextMouseEvent(int mouseX, int mouseY) + void WindowImpl::IgnoreNextMouseEvent(int /*mouseX*/, int /*mouseY*/) { m_ignoreNextMouseMove = true; - // Petite astuce ... probablement foireuse dans certains cas :ahde: - m_mousePos.x = mouseX; - m_mousePos.y = mouseY; } bool WindowImpl::IsMinimized() const @@ -297,27 +288,7 @@ namespace Nz } } - void WindowImpl::ProcessEvents(bool block) - { - if (m_ownsWindow) - SDL_PumpEvents(); - - - /*if (m_ownsWindow) - { - if (block) - WaitMessage(); - - MSG message; - while (PeekMessageW(&message, nullptr, 0, 0, PM_REMOVE)) - { - TranslateMessage(&message); - DispatchMessageW(&message); - } - }*/ - } - - int WindowImpl::HandleEvent(void *userdata, SDL_Event* event) + int WindowImpl::HandleEvent(void* userdata, SDL_Event* event) { try { @@ -327,7 +298,7 @@ namespace Nz { case SDL_WINDOWEVENT: { - if (SDL_GetWindowID(window->m_handle) != event->window.windowID) + if (window->m_windowId != event->window.windowID) return 0; WindowEvent windowEvent; @@ -337,20 +308,16 @@ namespace Nz windowEvent.type = WindowEventType::Quit; break; - case SDL_WINDOWEVENT_RESIZED: + case SDL_WINDOWEVENT_SIZE_CHANGED: windowEvent.type = WindowEventType::Resized; windowEvent.size.width = static_cast(std::max(0, event->window.data1)); windowEvent.size.height = static_cast(std::max(0, event->window.data2)); - - window->m_size.Set(windowEvent.size.width, windowEvent.size.height); break; case SDL_WINDOWEVENT_MOVED: windowEvent.type = WindowEventType::Moved; windowEvent.position.x = event->window.data1; windowEvent.position.y = event->window.data2; - - window->m_position.Set(event->window.data1, event->window.data2); break; case SDL_WINDOWEVENT_FOCUS_GAINED: @@ -364,23 +331,35 @@ namespace Nz case SDL_WINDOWEVENT_ENTER: windowEvent.type = WindowEventType::MouseEntered; + window->RefreshCursor(); break; case SDL_WINDOWEVENT_LEAVE: windowEvent.type = WindowEventType::MouseLeft; break; + + case SDL_WINDOWEVENT_MINIMIZED: + windowEvent.type = WindowEventType::Minimized; + break; + + case SDL_WINDOWEVENT_RESTORED: + windowEvent.type = WindowEventType::Restored; + break; + + default: + return 0; } - window->m_parent->PushEvent(windowEvent); + window->m_parent->HandleEvent(windowEvent); break; } case SDL_MOUSEMOTION: { - if (SDL_GetWindowID(window->m_handle) != event->motion.windowID) + if (window->m_windowId != event->motion.windowID) return 0; - if (window->m_ignoreNextMouseMove /*&& event->motion.x == window->m_mousePos.x && event->motion.y == window->m_mousePos.y*/) + if (window->m_ignoreNextMouseMove) { window->m_ignoreNextMouseMove = false; return 0; @@ -393,13 +372,13 @@ namespace Nz windowEvent.mouseMove.deltaX = event->motion.xrel; windowEvent.mouseMove.deltaY = event->motion.yrel; - window->m_parent->PushEvent(windowEvent); + window->m_parent->HandleEvent(windowEvent); break; } case SDL_MOUSEBUTTONDOWN: { - if (SDL_GetWindowID(window->m_handle) != event->button.windowID) + if (window->m_windowId != event->button.windowID) return 0; WindowEvent windowEvent; @@ -409,13 +388,13 @@ namespace Nz windowEvent.mouseButton.y = event->button.y; windowEvent.mouseButton.clickCount = event->button.clicks; - window->m_parent->PushEvent(windowEvent); + window->m_parent->HandleEvent(windowEvent); break; } case SDL_MOUSEBUTTONUP: { - if (SDL_GetWindowID(window->m_handle) != event->button.windowID) + if (window->m_windowId != event->button.windowID) return 0; WindowEvent windowEvent; @@ -424,25 +403,28 @@ namespace Nz windowEvent.mouseButton.x = event->button.x; windowEvent.mouseButton.y = event->button.y; - window->m_parent->PushEvent(windowEvent); + window->m_parent->HandleEvent(windowEvent); break; } case SDL_MOUSEWHEEL: { - if (SDL_GetWindowID(window->m_handle) != event->wheel.windowID) + if (window->m_windowId != event->wheel.windowID) return 0; WindowEvent windowEvent; windowEvent.type = WindowEventType::MouseWheelMoved; - windowEvent.mouseWheel.delta = event->wheel.y; + windowEvent.mouseWheel.delta = event->wheel.preciseY; + windowEvent.mouseWheel.x = event->wheel.mouseX; + windowEvent.mouseWheel.y = event->wheel.mouseY; - window->m_parent->PushEvent(windowEvent); + window->m_parent->HandleEvent(windowEvent); break; } case SDL_KEYDOWN: - if (SDL_GetWindowID(window->m_handle) != event->key.windowID) + { + if (window->m_windowId != event->key.windowID) return 0; WindowEvent windowEvent; @@ -455,7 +437,7 @@ namespace Nz windowEvent.key.system = (event->key.keysym.mod & KMOD_GUI) != 0; windowEvent.key.virtualKey = SDLHelper::FromSDL(event->key.keysym.sym); - window->m_parent->PushEvent(windowEvent); + window->m_parent->HandleEvent(windowEvent); // implements X11/Win32 APIs behavior for Enter and Backspace switch (windowEvent.key.virtualKey) @@ -470,7 +452,7 @@ namespace Nz windowEvent.text.character = U'\n'; windowEvent.text.repeated = event->key.repeat != 0; - window->m_parent->PushEvent(windowEvent); + window->m_parent->HandleEvent(windowEvent); break; } @@ -479,7 +461,7 @@ namespace Nz windowEvent.text.character = U'\b'; windowEvent.text.repeated = event->key.repeat != 0; - window->m_parent->PushEvent(windowEvent); + window->m_parent->HandleEvent(windowEvent); break; default: @@ -487,12 +469,14 @@ namespace Nz } break; + } case SDL_KEYUP: { - if (SDL_GetWindowID(window->m_handle) != event->key.windowID) + if (window->m_windowId != event->key.windowID) return 0; + WindowEvent windowEvent; windowEvent.type = WindowEventType::KeyReleased; windowEvent.key.alt = (event->key.keysym.mod & KMOD_ALT) != 0; windowEvent.key.control = (event->key.keysym.mod & KMOD_CTRL) != 0; @@ -502,15 +486,16 @@ namespace Nz windowEvent.key.system = (event->key.keysym.mod & KMOD_GUI) != 0; windowEvent.key.virtualKey = SDLHelper::FromSDL(event->key.keysym.sym); - window->m_parent->PushEvent(windowEvent); + window->m_parent->HandleEvent(windowEvent); break; } case SDL_TEXTINPUT: { - if (SDL_GetWindowID(window->m_handle) != event->text.windowID) + if (window->m_windowId != event->text.windowID) return 0; + WindowEvent windowEvent; windowEvent.type = WindowEventType::TextEntered; windowEvent.text.repeated = false; @@ -519,7 +504,7 @@ namespace Nz { windowEvent.text.character = *it; - window->m_parent->PushEvent(windowEvent); + window->m_parent->HandleEvent(windowEvent); } while (*it++); @@ -528,9 +513,10 @@ namespace Nz case SDL_TEXTEDITING: { - if (SDL_GetWindowID(window->m_handle) != event->edit.windowID) + if (window->m_windowId != event->edit.windowID) return 0; + WindowEvent windowEvent; windowEvent.type = WindowEventType::TextEdited; windowEvent.edit.length = event->edit.length; window->m_lastEditEventLength = windowEvent.edit.length; @@ -540,7 +526,7 @@ namespace Nz windowEvent.edit.text[i] = event->edit.text[i]; } - window->m_parent->PushEvent(windowEvent); + window->m_parent->HandleEvent(windowEvent); break; } } @@ -557,7 +543,7 @@ namespace Nz return 0; } - void WindowImpl::SetCursor(const Cursor& cursor) + void WindowImpl::UpdateCursor(const Cursor& cursor) { m_cursor = cursor.m_impl->GetCursor(); @@ -565,73 +551,57 @@ namespace Nz RefreshCursor(); } - void WindowImpl::SetEventListener(bool listener) - { - if (m_ownsWindow) - return; - - if (listener) - SDL_AddEventWatch(HandleEvent, this); - else - SDL_DelEventWatch(HandleEvent, this); - } - - void WindowImpl::SetFocus() + void WindowImpl::RaiseFocus() { SDL_RaiseWindow(m_handle); } - void WindowImpl::SetIcon(const Icon& icon) + void WindowImpl::UpdateIcon(const Icon& icon) { SDL_SetWindowIcon(m_handle, icon.m_impl->GetIcon()); } - void WindowImpl::SetMaximumSize(int width, int height) + void WindowImpl::UpdateMaximumSize(int width, int height) { SDL_SetWindowMaximumSize(m_handle, width, height); } - void WindowImpl::SetMinimumSize(int width, int height) + void WindowImpl::UpdateMinimumSize(int width, int height) { SDL_SetWindowMinimumSize(m_handle, width, height); } - void WindowImpl::SetPosition(int x, int y) + void WindowImpl::UpdatePosition(int x, int y) { SDL_SetWindowPosition(m_handle, x, y); } - void WindowImpl::SetSize(unsigned int width, unsigned int height) + void WindowImpl::UpdateSize(unsigned int width, unsigned int height) { - m_size.Set(width, height); SDL_SetWindowSize(m_handle, width, height); } - void WindowImpl::SetStayOnTop(bool stayOnTop) + void WindowImpl::UpdateStayOnTop(bool stayOnTop) { - NazaraDebug("Stay on top isn't supported by SDL2 backend for now"); + SDL_SetWindowAlwaysOnTop(m_handle, (stayOnTop) ? SDL_TRUE : SDL_FALSE); } - void WindowImpl::SetTitle(const std::string& title) + void WindowImpl::UpdateTitle(const std::string& title) { SDL_SetWindowTitle(m_handle, title.c_str()); } - void WindowImpl::SetVisible(bool visible) + void WindowImpl::Show(bool visible) { - visible ? SDL_ShowWindow(m_handle) : SDL_HideWindow(m_handle); + if (visible) + SDL_ShowWindow(m_handle); + else + SDL_HideWindow(m_handle); } - void WindowImpl::PrepareWindow(bool fullscreen) + void WindowImpl::ProcessEvents() { - (void)fullscreen; // ignore param warning - - SDL_GetWindowPosition(m_handle, &m_position.x, &m_position.y); - - int width, height; - SDL_GetWindowSize(m_handle, &width, &height); - - m_size.Set(width, height); + SDL_PumpEvents(); } bool WindowImpl::Initialize() @@ -650,27 +620,18 @@ namespace Nz SDL_Quit(); } - // not implemented for now, wait for mainloop friendly input - //void WindowImpl::WindowThread(SDL_Window* handle, /*DWORD styleEx,*/ const String& title, /*DWORD style,*/ bool fullscreen, const Rectui& dimensions, WindowImpl* window, Mutex* mutex, ConditionVariable* condition) - //{ - // SDL_Window& winHandle = *handle; - /*winHandle = CreateWindowExW(styleEx, className, title.GetWideString().data(), style, dimensions.x, dimensions.y, dimensions.width, dimensions.height, nullptr, nullptr, GetModuleHandle(nullptr), window); + void WindowImpl::SetEventListener(bool listener) + { + if (m_eventListener == listener) + return; - if (winHandle) - window->PrepareWindow(fullscreen); + if (listener) + SDL_AddEventWatch(HandleEvent, this); + else + SDL_DelEventWatch(HandleEvent, this); - mutex->Lock(); - condition->Signal(); - mutex->Unlock(); // mutex and condition may be destroyed after this line - - if (!winHandle) - return; - - while (window->m_threadActive) - window->ProcessEvents(true); - - DestroyWindow(winHandle);*/ - //} + m_eventListener = listener; + } } #if defined(NAZARA_PLATFORM_WINDOWS) diff --git a/src/Nazara/Platform/SDL2/WindowImpl.hpp b/src/Nazara/Platform/SDL2/WindowImpl.hpp index 4037a51a7..185cf0bef 100644 --- a/src/Nazara/Platform/SDL2/WindowImpl.hpp +++ b/src/Nazara/Platform/SDL2/WindowImpl.hpp @@ -35,19 +35,17 @@ namespace Nz ~WindowImpl() = default; bool Create(const VideoMode& mode, const std::string& title, WindowStyleFlags style); - bool Create(void* handle); + bool Create(WindowHandle handle); void Destroy(); - void EnableKeyRepeat(bool enable); - void EnableSmoothScrolling(bool enable); + Vector2i FetchPosition() const; + Vector2ui FetchSize() const; + WindowStyleFlags FetchStyle() const; + std::string FetchTitle() const; SDL_Window* GetHandle() const; - Vector2i GetPosition() const; - Vector2ui GetSize() const; - WindowStyleFlags GetStyle() const; WindowHandle GetSystemHandle() const; - std::string GetTitle() const; bool HasFocus() const; @@ -56,52 +54,40 @@ namespace Nz bool IsMinimized() const; bool IsVisible() const; + void RaiseFocus(); void RefreshCursor(); - void ProcessEvents(bool block); + void UpdateCursor(const Cursor& cursor); + void UpdateIcon(const Icon& icon); + void UpdateMaximumSize(int width, int height); + void UpdateMinimumSize(int width, int height); + void UpdatePosition(int x, int y); + void UpdateSize(unsigned int width, unsigned int height); + void UpdateStayOnTop(bool stayOnTop); + void UpdateTitle(const std::string& title); - void SetCursor(const Cursor& cursor); - void SetEventListener(bool listener); - void SetFocus(); - void SetIcon(const Icon& icon); - void SetMaximumSize(int width, int height); - void SetMinimumSize(int width, int height); - void SetPosition(int x, int y); - void SetSize(unsigned int width, unsigned int height); - void SetStayOnTop(bool stayOnTop); - void SetTitle(const std::string& title); - void SetVisible(bool visible); + void Show(bool visible); WindowImpl& operator=(const WindowImpl&) = delete; WindowImpl& operator=(WindowImpl&&) = delete; ///TODO? + static void ProcessEvents(); static bool Initialize(); static void Uninitialize(); private: + void SetEventListener(bool listener); + static int SDLCALL HandleEvent(void* userdata, SDL_Event* event); - void PrepareWindow(bool fullscreen); - - int m_lastEditEventLength = 0; + UInt32 m_windowId; SDL_Cursor* m_cursor; SDL_Window* m_handle; - WindowStyleFlags m_style; - Vector2i m_maxSize; - Vector2i m_minSize; - Vector2i m_mousePos; - Vector2i m_position; - Vector2ui m_size; Window* m_parent; bool m_eventListener; - bool m_ignoreNextMouseMove = false; - bool m_keyRepeat; - bool m_mouseInside; + bool m_ignoreNextMouseMove; bool m_ownsWindow; - bool m_sizemove; - bool m_smoothScrolling; - bool m_threadActive; - short m_scrolling; + int m_lastEditEventLength; }; } diff --git a/src/Nazara/Platform/Window.cpp b/src/Nazara/Platform/Window.cpp index d1c99abbd..733440cac 100644 --- a/src/Nazara/Platform/Window.cpp +++ b/src/Nazara/Platform/Window.cpp @@ -12,33 +12,22 @@ namespace Nz { - namespace NAZARA_ANONYMOUS_NAMESPACE - { - Window* s_fullscreenWindow = nullptr; - } - Window::Window() : m_impl(nullptr), - m_asyncWindow(false), m_closeOnQuit(true), - m_eventPolling(false), m_waitForEvent(false) { ConnectSlots(); } - Window::Window(Window&& window) : - m_events(std::move(window.m_events)), - m_pendingEvents(std::move(window.m_pendingEvents)), + Window::Window(Window&& window) noexcept : m_cursorController(std::move(window.m_cursorController)), m_cursor(std::move(window.m_cursor)), m_eventHandler(std::move(window.m_eventHandler)), m_icon(std::move(window.m_icon)), - m_asyncWindow(window.m_asyncWindow), - m_closed(window.m_asyncWindow), + m_closed(window.m_closed), m_closeOnQuit(window.m_closeOnQuit), - m_eventPolling(window.m_eventPolling), - m_ownsWindow(window.m_asyncWindow), + m_ownsWindow(window.m_ownsWindow), m_waitForEvent(window.m_waitForEvent) { window.DisconnectSlots(); @@ -52,214 +41,136 @@ namespace Nz bool Window::Create(VideoMode mode, const std::string& title, WindowStyleFlags style) { - NAZARA_USE_ANONYMOUS_NAMESPACE - // If the window is already open, we keep its position bool opened = IsOpen(); Vector2i position; if (opened) - position = m_impl->GetPosition(); + position = m_position; Destroy(); - // Inspired by the code of the SFML by Laurent Gomila (and its team) - if (style & WindowStyle::Fullscreen) - { - if (s_fullscreenWindow) - { - NazaraError("Window " + PointerToString(s_fullscreenWindow) + " already in fullscreen mode"); - style &= ~WindowStyle::Fullscreen; - } - else - { - if (!mode.IsFullscreenValid()) - { - NazaraWarning("Video mode is not fullscreen valid"); - mode = VideoMode::GetFullscreenModes()[0]; - } - - s_fullscreenWindow = this; - } - } - else if (style & WindowStyle::Closable || style & WindowStyle::Resizable) + if (style & WindowStyle::Closable || style & WindowStyle::Resizable) style |= WindowStyle::Titlebar; - m_asyncWindow = (style & WindowStyle::Threaded) != 0; - - std::unique_ptr impl = std::make_unique(this); - if (!impl->Create(mode, title, style)) + m_impl = std::make_unique(this); + if (!m_impl->Create(mode, title, style)) { NazaraError("Failed to create window implementation"); return false; } - m_impl = impl.release(); CallOnExit destroyOnFailure([this] () { Destroy(); }); m_closed = false; m_ownsWindow = true; - if (!OnWindowCreated()) - { - NazaraError("Failed to initialize window extension"); - return false; - } + m_position = m_impl->FetchPosition(); + m_size = m_impl->FetchSize(); // Default parameters - m_impl->EnableKeyRepeat(true); - m_impl->EnableSmoothScrolling(false); - m_impl->SetMaximumSize(-1, -1); - m_impl->SetMinimumSize(-1, -1); - m_impl->SetVisible(true); + m_impl->UpdateMaximumSize(-1, -1); + m_impl->UpdateMinimumSize(-1, -1); + m_impl->Show(true); if (opened) - m_impl->SetPosition(position.x, position.y); - - OnWindowResized(); + m_impl->UpdatePosition(position.x, position.y); destroyOnFailure.Reset(); + m_eventHandler.Dispatch({ WindowEventType::Created }); + return true; } - bool Window::Create(void* handle) + bool Window::Create(WindowHandle handle) { Destroy(); - m_asyncWindow = false; - m_impl = new WindowImpl(this); + m_impl = std::make_unique(this); if (!m_impl->Create(handle)) { NazaraError("Unable to create window implementation"); - delete m_impl; - m_impl = nullptr; - + m_impl.reset(); return false; } + m_position = m_impl->FetchPosition(); + m_size = m_impl->FetchSize(); + m_closed = false; m_ownsWindow = false; - if (!OnWindowCreated()) - { - NazaraError("Failed to initialize window's derivate"); - delete m_impl; - m_impl = nullptr; - - return false; - } + m_eventHandler.Dispatch({ WindowEventType::Created }); return true; } void Window::Destroy() { - NAZARA_USE_ANONYMOUS_NAMESPACE - - m_cursor.reset(); - if (m_impl) { - OnWindowDestroy(); + m_eventHandler.Dispatch({ WindowEventType::Destruction }); m_impl->Destroy(); - delete m_impl; - m_impl = nullptr; - - if (s_fullscreenWindow == this) - s_fullscreenWindow = nullptr; + m_impl.reset(); } - } - void Window::EnableKeyRepeat(bool enable) - { - #if NAZARA_PLATFORM_SAFE - if (!m_impl) - { - NazaraError("Window not created"); - return; - } - #endif - - m_impl->EnableKeyRepeat(enable); - } - - void Window::EnableSmoothScrolling(bool enable) - { - #if NAZARA_PLATFORM_SAFE - if (!m_impl) - { - NazaraError("Window not created"); - return; - } - #endif - - m_impl->EnableSmoothScrolling(enable); + m_cursor.reset(); } Vector2i Window::GetPosition() const { - #if NAZARA_PLATFORM_SAFE - if (!m_impl) - { - NazaraError("Window not created"); - return Vector2i::Zero(); - } - #endif - - return m_impl->GetPosition(); + NazaraAssert(m_impl, "Window not created"); + return m_position; } Vector2ui Window::GetSize() const { - #if NAZARA_PLATFORM_SAFE - if (!m_impl) - { - NazaraError("Window not created"); - return Vector2ui::Zero(); - } - #endif - - return m_impl->GetSize(); + NazaraAssert(m_impl, "Window not created"); + return m_size; } WindowStyleFlags Window::GetStyle() const { - #if NAZARA_PLATFORM_SAFE - if (!m_impl) - { - NazaraError("Window not created"); - return 0; - } - #endif - - return m_impl->GetStyle(); - } - - WindowHandle Window::GetSystemHandle() const - { -#if NAZARA_PLATFORM_SAFE - if (!m_impl) - { - NazaraError("Window not created"); - return {}; - } -#endif - - return m_impl->GetSystemHandle(); + NazaraAssert(m_impl, "Window not created"); + return m_impl->FetchStyle(); } std::string Window::GetTitle() const { - #if NAZARA_PLATFORM_SAFE - if (!m_impl) - { - NazaraError("Window not created"); - return {}; - } - #endif + NazaraAssert(m_impl, "Window not created"); + return m_impl->FetchTitle(); + } - return m_impl->GetTitle(); + void Window::HandleEvent(const WindowEvent& event) + { + m_eventHandler.Dispatch(event); + + switch (event.type) + { + case WindowEventType::Moved: + { + m_position = { event.position.x, event.position.y }; + break; + } + + case WindowEventType::Quit: + { + if (m_closeOnQuit) + Close(); + + break; + } + + case WindowEventType::Resized: + { + m_size = { event.size.width, event.size.height }; + break; + } + + default: + break; + } } bool Window::HasFocus() const @@ -301,76 +212,13 @@ namespace Nz return m_impl->IsVisible(); } - bool Window::PollEvent(WindowEvent* event) - { - #if NAZARA_PLATFORM_SAFE - if (!m_impl) - { - NazaraError("Window not created"); - return false; - } - #endif - - if (!m_asyncWindow) - m_impl->ProcessEvents(false); - - if (!m_events.empty()) - { - if (event) - *event = m_events.front(); - - m_events.pop(); - - return true; - } - - return false; - } - - void Window::ProcessEvents(bool block) - { - NazaraAssert(m_impl, "Window not created"); - NazaraUnused(block); - - if (!m_asyncWindow) - m_impl->ProcessEvents(block); - else - { - std::lock_guard eventLock(m_eventMutex); - - for (const WindowEvent& event : m_pendingEvents) - HandleEvent(event); - - m_pendingEvents.clear(); - } - } - void Window::SetCursor(std::shared_ptr cursor) { NazaraAssert(m_impl, "Window not created"); NazaraAssert(cursor && cursor->IsValid(), "Invalid cursor"); m_cursor = std::move(cursor); - m_impl->SetCursor(*m_cursor); - } - - void Window::SetEventListener(bool listener) - { - #if NAZARA_PLATFORM_SAFE - if (!m_impl) - { - NazaraError("Window not created"); - return; - } - #endif - - m_impl->SetEventListener(listener); - if (!listener) - { - // Empty the event queue - while (!m_events.empty()) - m_events.pop(); - } + m_impl->UpdateCursor(*m_cursor); } void Window::SetFocus() @@ -383,7 +231,7 @@ namespace Nz } #endif - m_impl->SetFocus(); + m_impl->RaiseFocus(); } void Window::SetIcon(std::shared_ptr icon) @@ -392,7 +240,7 @@ namespace Nz NazaraAssert(icon, "Invalid icon"); m_icon = std::move(icon); - m_impl->SetIcon(*m_icon); + m_impl->UpdateIcon(*m_icon); } void Window::SetMaximumSize(const Vector2i& maxSize) @@ -405,7 +253,7 @@ namespace Nz } #endif - m_impl->SetMaximumSize(maxSize.x, maxSize.y); + m_impl->UpdateMaximumSize(maxSize.x, maxSize.y); } void Window::SetMaximumSize(int width, int height) @@ -418,7 +266,7 @@ namespace Nz } #endif - m_impl->SetMaximumSize(width, height); + m_impl->UpdateMaximumSize(width, height); } void Window::SetMinimumSize(const Vector2i& minSize) @@ -431,7 +279,7 @@ namespace Nz } #endif - m_impl->SetMinimumSize(minSize.x, minSize.y); + m_impl->UpdateMinimumSize(minSize.x, minSize.y); } void Window::SetMinimumSize(int width, int height) @@ -444,7 +292,7 @@ namespace Nz } #endif - m_impl->SetMinimumSize(width, height); + m_impl->UpdateMinimumSize(width, height); } void Window::SetPosition(const Vector2i& position) @@ -457,7 +305,7 @@ namespace Nz } #endif - m_impl->SetPosition(position.x, position.y); + m_impl->UpdatePosition(position.x, position.y); } void Window::SetPosition(int x, int y) @@ -470,7 +318,7 @@ namespace Nz } #endif - m_impl->SetPosition(x, y); + m_impl->UpdatePosition(x, y); } void Window::SetSize(const Vector2i& size) @@ -483,7 +331,7 @@ namespace Nz } #endif - m_impl->SetSize(size.x, size.y); + m_impl->UpdateSize(size.x, size.y); } void Window::SetSize(unsigned int width, unsigned int height) @@ -496,7 +344,7 @@ namespace Nz } #endif - m_impl->SetSize(width, height); + m_impl->UpdateSize(width, height); } void Window::SetStayOnTop(bool stayOnTop) @@ -509,7 +357,7 @@ namespace Nz } #endif - m_impl->SetStayOnTop(stayOnTop); + m_impl->UpdateStayOnTop(stayOnTop); } void Window::SetTitle(const std::string& title) @@ -522,7 +370,7 @@ namespace Nz } #endif - m_impl->SetTitle(title); + m_impl->UpdateTitle(title); } void Window::SetVisible(bool visible) @@ -535,76 +383,18 @@ namespace Nz } #endif - m_impl->SetVisible(visible); + m_impl->Show(visible); } - bool Window::WaitEvent(WindowEvent* event) + Window& Window::operator=(Window&& window) noexcept { - #if NAZARA_PLATFORM_SAFE - if (!m_impl) - { - NazaraError("Window not created"); - return false; - } - #endif - - if (!m_asyncWindow) - { - while (m_events.empty()) - m_impl->ProcessEvents(true); - - if (event) - *event = m_events.front(); - - m_events.pop(); - - return true; - } - else - { - std::lock_guard lock(m_eventMutex); - - if (m_events.empty()) - { - m_waitForEvent = true; - { - m_eventMutex.unlock(); - - std::unique_lock eventConditionLock(m_eventConditionMutex); - m_eventCondition.wait(eventConditionLock); - - m_eventMutex.lock(); - } - m_waitForEvent = false; - } - - if (!m_events.empty()) - { - if (event) - *event = m_events.front(); - - m_events.pop(); - - return true; - } - - return false; - } - } - - Window& Window::operator=(Window&& window) - { - m_events = std::move(window.m_events); - m_pendingEvents = std::move(window.m_pendingEvents); m_cursorController = std::move(window.m_cursorController); m_cursor = std::move(window.m_cursor); m_eventHandler = std::move(window.m_eventHandler); m_icon = std::move(window.m_icon); - m_asyncWindow = window.m_asyncWindow; - m_closed = window.m_asyncWindow; + m_closed = window.m_closed; m_closeOnQuit = window.m_closeOnQuit; - m_eventPolling = window.m_eventPolling; - m_ownsWindow = window.m_asyncWindow; + m_ownsWindow = window.m_ownsWindow; m_waitForEvent = window.m_waitForEvent; window.DisconnectSlots(); @@ -613,22 +403,14 @@ namespace Nz return *this; } - void* Window::GetHandle() + void Window::ProcessEvents() { - return (m_impl) ? m_impl->GetHandle() : nullptr; + WindowImpl::ProcessEvents(); } - bool Window::OnWindowCreated() - { - return true; - } - - void Window::OnWindowDestroy() - { - } - - void Window::OnWindowResized() + WindowHandle Window::GetHandle() const { + return (m_impl) ? m_impl->GetSystemHandle() : WindowHandle{}; } void Window::ConnectSlots() @@ -658,34 +440,6 @@ namespace Nz m_impl->IgnoreNextMouseEvent(mouseX, mouseY); } - void Window::HandleEvent(const WindowEvent& event) - { - if (m_eventPolling) - m_events.push(event); - - m_eventHandler.Dispatch(event); - - switch (event.type) - { - case WindowEventType::MouseEntered: - m_impl->RefreshCursor(); - break; - - case WindowEventType::Resized: - OnWindowResized(); - break; - - case WindowEventType::Quit: - if (m_closeOnQuit) - Close(); - - break; - - default: - break; - } - } - bool Window::Initialize() { return WindowImpl::Initialize(); diff --git a/src/Nazara/Renderer/RenderSurface.cpp b/src/Nazara/Renderer/RenderSurface.cpp deleted file mode 100644 index 3afb871e3..000000000 --- a/src/Nazara/Renderer/RenderSurface.cpp +++ /dev/null @@ -1,11 +0,0 @@ -// Copyright (C) 2022 Jérôme "Lynix" Leclercq (lynix680@gmail.com) -// This file is part of the "Nazara Engine - Renderer module" -// For conditions of distribution and use, see copyright notice in Config.hpp - -#include -#include - -namespace Nz -{ - RenderSurface::~RenderSurface() = default; -} diff --git a/src/Nazara/Renderer/RenderWindow.cpp b/src/Nazara/Renderer/RenderWindow.cpp deleted file mode 100644 index eb1649275..000000000 --- a/src/Nazara/Renderer/RenderWindow.cpp +++ /dev/null @@ -1,91 +0,0 @@ -// Copyright (C) 2022 Jérôme "Lynix" Leclercq (lynix680@gmail.com) -// This file is part of the "Nazara Engine - Renderer module" -// For conditions of distribution and use, see copyright notice in Config.hpp - -#include -#include -#include -#include -#include -#include -#include - -namespace Nz -{ - RenderFrame RenderWindow::AcquireFrame() - { - if (!m_impl) - { - NazaraError("window is not created"); - return RenderFrame{}; - } - - if (m_framerateLimit > 0) - { - int remainingTime = 1000 / static_cast(m_framerateLimit) - static_cast(m_clock.GetElapsedTime().AsMilliseconds()); - if (remainingTime > 0) - std::this_thread::sleep_for(std::chrono::milliseconds(remainingTime)); - - m_clock.Restart(); - } - - return m_impl->Acquire(); - } - - bool RenderWindow::Create(std::shared_ptr renderDevice, VideoMode mode, const std::string& title, WindowStyleFlags style, const RenderWindowParameters& parameters) - { - m_parameters = parameters; - m_renderDevice = std::move(renderDevice); - - return Window::Create(mode, title, style); - } - - bool RenderWindow::Create(std::shared_ptr renderDevice, void* handle, const RenderWindowParameters& parameters) - { - m_parameters = parameters; - m_renderDevice = std::move(renderDevice); - - return Window::Create(handle); - } - - void RenderWindow::EnableVerticalSync(bool enabled) - { - ///TODO - } - - bool RenderWindow::OnWindowCreated() - { - RendererImpl* rendererImpl = Renderer::Instance()->GetRendererImpl(); - auto surface = rendererImpl->CreateRenderSurfaceImpl(); - if (!surface->Create(GetSystemHandle())) - { - NazaraError("Failed to create render surface: " + Error::GetLastError()); - return false; - } - - auto impl = rendererImpl->CreateRenderWindowImpl(*this); - if (!impl->Create(rendererImpl, surface.get(), m_parameters)) - { - NazaraError("Failed to create render window implementation: " + Error::GetLastError()); - return false; - } - - m_impl = std::move(impl); - m_surface = std::move(surface); - - m_clock.Restart(); - - return true; - } - - void RenderWindow::OnWindowDestroy() - { - m_impl.reset(); - m_renderDevice.reset(); - m_surface.reset(); - } - - void RenderWindow::OnWindowResized() - { - } -} diff --git a/src/Nazara/Renderer/RenderWindowImpl.cpp b/src/Nazara/Renderer/Swapchain.cpp similarity index 81% rename from src/Nazara/Renderer/RenderWindowImpl.cpp rename to src/Nazara/Renderer/Swapchain.cpp index 2effc6189..453d3c0b2 100644 --- a/src/Nazara/Renderer/RenderWindowImpl.cpp +++ b/src/Nazara/Renderer/Swapchain.cpp @@ -2,14 +2,14 @@ // This file is part of the "Nazara Engine - Renderer module" // For conditions of distribution and use, see copyright notice in Config.hpp -#include +#include #include namespace Nz { - RenderWindowImpl::~RenderWindowImpl() = default; + Swapchain::~Swapchain() = default; - void RenderWindowImpl::BuildRenderPass(PixelFormat colorFormat, PixelFormat depthFormat, std::vector& attachments, std::vector& subpassDescriptions, std::vector& subpassDependencies) + void Swapchain::BuildRenderPass(PixelFormat colorFormat, PixelFormat depthFormat, std::vector& attachments, std::vector& subpassDescriptions, std::vector& subpassDependencies) { assert(colorFormat != PixelFormat::Undefined); diff --git a/src/Nazara/Renderer/WindowSwapchain.cpp b/src/Nazara/Renderer/WindowSwapchain.cpp new file mode 100644 index 000000000..884dede23 --- /dev/null +++ b/src/Nazara/Renderer/WindowSwapchain.cpp @@ -0,0 +1,72 @@ +// Copyright (C) 2022 Jérôme "Lynix" Leclercq (lynix680@gmail.com) +// This file is part of the "Nazara Engine - Renderer module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include +#include +#include + +namespace Nz +{ + WindowSwapchain::WindowSwapchain(std::shared_ptr renderDevice, Window& window, SwapchainParameters parameters) : + m_renderDevice(std::move(renderDevice)), + m_window(&window), + m_parameters(std::move(parameters)), + m_renderOnlyIfFocused(false) + { + NazaraAssert(m_renderDevice, "invalid render device"); + + if (m_window->IsValid()) + { + m_swapchain = m_renderDevice->InstantiateSwapchain(window.GetHandle(), window.GetSize(), m_parameters); + m_isMinimized = window.IsMinimized(); + } + else + m_isMinimized = true; //< consider it minimized so AcquireFrame returns no frame + + ConnectSignals(); + } + + void WindowSwapchain::ConnectSignals() + { + WindowEventHandler& windowEvents = m_window->GetEventHandler(); + m_onCreated.Connect(windowEvents.OnCreated, [this](const WindowEventHandler* /*eventHandler*/) + { + // Recreate swapchain + m_swapchain = m_renderDevice->InstantiateSwapchain(m_window->GetHandle(), m_window->GetSize(), m_parameters); + m_isMinimized = m_window->IsMinimized(); + }); + + m_onDestruction.Connect(windowEvents.OnDestruction, [this](const WindowEventHandler* /*eventHandler*/) + { + m_swapchain.reset(); + m_isMinimized = true; + }); + + m_onGainedFocus.Connect(windowEvents.OnGainedFocus, [this](const WindowEventHandler* /*eventHandler*/) + { + m_hasFocus = true; + }); + + m_onLostFocus.Connect(windowEvents.OnLostFocus, [this](const WindowEventHandler* /*eventHandler*/) + { + m_hasFocus = false; + }); + + m_onMinimized.Connect(windowEvents.OnMinimized, [this](const WindowEventHandler* /*eventHandler*/) + { + m_isMinimized = true; + }); + + m_onResized.Connect(windowEvents.OnResized, [this](const WindowEventHandler* /*eventHandler*/, const WindowEvent::SizeEvent& event) + { + m_swapchain->NotifyResize({ event.width, event.height }); + }); + + m_onRestored.Connect(windowEvents.OnRestored, [this](const WindowEventHandler* /*eventHandler*/) + { + m_isMinimized = false; + }); + } +} diff --git a/src/Nazara/VulkanRenderer/VulkanDevice.cpp b/src/Nazara/VulkanRenderer/VulkanDevice.cpp index b70b582fd..a5268feec 100644 --- a/src/Nazara/VulkanRenderer/VulkanDevice.cpp +++ b/src/Nazara/VulkanRenderer/VulkanDevice.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -85,6 +86,11 @@ namespace Nz return stage; } + std::shared_ptr VulkanDevice::InstantiateSwapchain(WindowHandle windowHandle, const Vector2ui& windowSize, const SwapchainParameters& parameters) + { + return std::make_shared(*this, windowHandle, windowSize, parameters); + } + std::shared_ptr VulkanDevice::InstantiateTexture(const TextureInfo& params) { return std::make_shared(*this, params); diff --git a/src/Nazara/VulkanRenderer/VulkanRenderImage.cpp b/src/Nazara/VulkanRenderer/VulkanRenderImage.cpp index 0c87a8464..c2394edd5 100644 --- a/src/Nazara/VulkanRenderer/VulkanRenderImage.cpp +++ b/src/Nazara/VulkanRenderer/VulkanRenderImage.cpp @@ -5,13 +5,13 @@ #include #include #include -#include +#include #include #include namespace Nz { - VulkanRenderImage::VulkanRenderImage(VulkanRenderWindow& owner) : + VulkanRenderImage::VulkanRenderImage(VulkanSwapchain& owner) : m_owner(owner), m_uploadPool(m_owner.GetDevice(), 2 * 1024 * 1024) { diff --git a/src/Nazara/VulkanRenderer/VulkanRenderer.cpp b/src/Nazara/VulkanRenderer/VulkanRenderer.cpp index 0cca1dfc6..1463da436 100644 --- a/src/Nazara/VulkanRenderer/VulkanRenderer.cpp +++ b/src/Nazara/VulkanRenderer/VulkanRenderer.cpp @@ -6,8 +6,7 @@ #include #include #include -#include -#include +#include #include #include #include @@ -20,16 +19,6 @@ namespace Nz Vulkan::Uninitialize(); } - std::unique_ptr VulkanRenderer::CreateRenderSurfaceImpl() - { - return std::make_unique(); - } - - std::unique_ptr VulkanRenderer::CreateRenderWindowImpl(RenderWindow& owner) - { - return std::make_unique(owner); - } - std::shared_ptr VulkanRenderer::InstanciateRenderDevice(std::size_t deviceIndex, const RenderDeviceFeatures& enabledFeatures) { const auto& physDevices = Vulkan::GetPhysicalDevices(); diff --git a/src/Nazara/VulkanRenderer/VulkanSurface.cpp b/src/Nazara/VulkanRenderer/VulkanSurface.cpp deleted file mode 100644 index 3663e3c17..000000000 --- a/src/Nazara/VulkanRenderer/VulkanSurface.cpp +++ /dev/null @@ -1,98 +0,0 @@ -// Copyright (C) 2022 Jérôme "Lynix" Leclercq (lynix680@gmail.com) -// This file is part of the "Nazara Engine - Vulkan renderer" -// For conditions of distribution and use, see copyright notice in Config.hpp - -#include -#include -#include -#include - -#ifdef VK_USE_PLATFORM_METAL_EXT -#include -#include -#endif - -namespace Nz -{ - #ifdef VK_USE_PLATFORM_METAL_EXT - id CreateAndAttachMetalLayer(void* window); - #endif - - VulkanSurface::VulkanSurface() : - m_surface(Vulkan::GetInstance()) - { - } - - bool VulkanSurface::Create(WindowHandle handle) - { - bool success = false; - #if defined(NAZARA_PLATFORM_WINDOWS) - { - NazaraAssert(handle.type == WindowBackend::Windows, "expected Windows window"); - - HWND winHandle = reinterpret_cast(handle.windows.window); - HINSTANCE instance = reinterpret_cast(GetWindowLongPtrW(winHandle, GWLP_HINSTANCE)); - - success = m_surface.Create(instance, winHandle); - } - #elif defined(NAZARA_PLATFORM_LINUX) - { - switch (handle.type) - { -#ifdef VK_USE_PLATFORM_WAYLAND_KHR - case WindowBackend::Wayland: - { - wl_display* display = static_cast(handle.wayland.display); - wl_surface* surface = static_cast(handle.wayland.surface); - - success = m_surface.Create(display, surface); - break; - } -#endif - -#ifdef VK_USE_PLATFORM_XLIB_KHR - case WindowBackend::X11: - { - Display* display = static_cast(handle.x11.display); - ::Window window = static_cast<::Window>(handle.x11.window); - - success = m_surface.Create(display, window); - break; - } -#endif - - default: - { - NazaraError("unhandled window type"); - return false; - } - } - } - #elif defined(NAZARA_PLATFORM_MACOS) - { - NazaraAssert(handle.type == WindowBackend::Cocoa, "expected cocoa window"); - id layer = CreateAndAttachMetalLayer(handle.cocoa.window); - success = m_surface.Create(layer); - } - #else - #error This OS is not supported by Vulkan - #endif - - if (!success) - { - NazaraError("Failed to create Vulkan surface: " + TranslateVulkanError(m_surface.GetLastErrorCode())); - return false; - } - - return true; - } - - void VulkanSurface::Destroy() - { - m_surface.Destroy(); - } -} - -#if defined(NAZARA_PLATFORM_WINDOWS) -#include -#endif diff --git a/src/Nazara/VulkanRenderer/VulkanSurfaceMetal.mm b/src/Nazara/VulkanRenderer/VulkanSurfaceMetal.mm index 3ea392a61..18e70b066 100644 --- a/src/Nazara/VulkanRenderer/VulkanSurfaceMetal.mm +++ b/src/Nazara/VulkanRenderer/VulkanSurfaceMetal.mm @@ -4,13 +4,17 @@ namespace Nz { - id CreateAndAttachMetalLayer(void* window) { - NSWindow* obj = (__bridge NSWindow*)window; + id CreateAndAttachMetalLayer(void* window) + { + NSWindow* obj = (__bridge NSWindow*) window; + NSView* view = [[NSView alloc] initWithFrame:obj.frame]; [view setLayer:[CAMetalLayer layer]]; [view setWantsLayer:YES]; view.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable; + [obj.contentView addSubview:view]; + return view.layer; } } diff --git a/src/Nazara/VulkanRenderer/VulkanRenderWindow.cpp b/src/Nazara/VulkanRenderer/VulkanSwapchain.cpp similarity index 65% rename from src/Nazara/VulkanRenderer/VulkanRenderWindow.cpp rename to src/Nazara/VulkanRenderer/VulkanSwapchain.cpp index b4668adff..a53ed0f1b 100644 --- a/src/Nazara/VulkanRenderer/VulkanRenderWindow.cpp +++ b/src/Nazara/VulkanRenderer/VulkanSwapchain.cpp @@ -2,34 +2,160 @@ // This file is part of the "Nazara Engine - Vulkan renderer" // For conditions of distribution and use, see copyright notice in Config.hpp -#include +#include #include #include #include -#include +#include #include #include #include #include -#include #include #include #include + +#ifdef VK_USE_PLATFORM_METAL_EXT +#include +#include +#endif + #include namespace Nz { - VulkanRenderWindow::VulkanRenderWindow(RenderWindow& owner) : +#ifdef VK_USE_PLATFORM_METAL_EXT + id CreateAndAttachMetalLayer(void* window); +#endif + + VulkanSwapchain::VulkanSwapchain(VulkanDevice& device, WindowHandle windowHandle, const Vector2ui& windowSize, const SwapchainParameters& parameters) : m_currentFrame(0), - m_owner(owner), + m_surface(device.GetInstance()), + m_swapchainSize(windowSize), + m_device(device), m_shouldRecreateSwapchain(false) { + if (!SetupSurface(windowHandle)) + throw std::runtime_error("failed to create surface"); + + const auto& physDeviceInfo = m_device.GetPhysicalDeviceInfo(); + + const std::vector& queueFamilyInfo = m_device.GetEnabledQueues(); + UInt32 graphicsFamilyQueueIndex = UINT32_MAX; + UInt32 presentableFamilyQueueIndex = UINT32_MAX; + + for (const Vk::Device::QueueFamilyInfo& queueInfo : queueFamilyInfo) + { + bool supported = false; + if (m_surface.GetSupportPresentation(physDeviceInfo.physDevice, queueInfo.familyIndex, &supported) && supported) + { + if (presentableFamilyQueueIndex == UINT32_MAX || queueInfo.flags & VK_QUEUE_GRAPHICS_BIT) + { + presentableFamilyQueueIndex = queueInfo.familyIndex; + if (queueInfo.flags & VK_QUEUE_GRAPHICS_BIT) + { + graphicsFamilyQueueIndex = queueInfo.familyIndex; + break; + } + } + } + } + + if (presentableFamilyQueueIndex == UINT32_MAX) + throw std::runtime_error("device doesn't support presenting to this surface"); + + if (graphicsFamilyQueueIndex == UINT32_MAX) + { + for (const Vk::Device::QueueFamilyInfo& queueInfo : queueFamilyInfo) + { + if (queueInfo.flags & VK_QUEUE_GRAPHICS_BIT) + { + graphicsFamilyQueueIndex = queueInfo.familyIndex; + break; + } + } + } + + if (graphicsFamilyQueueIndex == UINT32_MAX) + throw std::runtime_error("device doesn't support graphics operation"); + + UInt32 transferFamilyQueueIndex = UINT32_MAX; + // Search for a transfer queue (first one being different to the graphics one) + for (const Vk::Device::QueueFamilyInfo& queueInfo : queueFamilyInfo) + { + // Transfer bit is not mandatory if compute and graphics bits are set (as they implicitly support transfer) + if (queueInfo.flags & (VK_QUEUE_COMPUTE_BIT | VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_TRANSFER_BIT)) + { + transferFamilyQueueIndex = queueInfo.familyIndex; + if (transferFamilyQueueIndex != graphicsFamilyQueueIndex) + break; + } + } + + assert(transferFamilyQueueIndex != UINT32_MAX); + + m_graphicsQueue = m_device.GetQueue(graphicsFamilyQueueIndex, 0); + m_presentQueue = m_device.GetQueue(presentableFamilyQueueIndex, 0); + m_transferQueue = m_device.GetQueue(transferFamilyQueueIndex, 0); + + std::vector surfaceFormats; + if (!m_surface.GetFormats(physDeviceInfo.physDevice, &surfaceFormats)) + throw std::runtime_error("failed to query supported surface formats"); + + m_surfaceFormat = [&]() -> VkSurfaceFormatKHR + { + if (surfaceFormats.size() == 1 && surfaceFormats.front().format == VK_FORMAT_UNDEFINED) + { + // If the list contains one undefined format, it means any format can be used + return { VK_FORMAT_R8G8B8A8_UNORM, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR }; + } + else + { + // Search for RGBA8 and default to first format + for (const VkSurfaceFormatKHR& surfaceFormat : surfaceFormats) + { + if (surfaceFormat.format == VK_FORMAT_R8G8B8A8_UNORM) + return surfaceFormat; + } + + return surfaceFormats.front(); + } + }(); + + m_depthStencilFormat = VK_FORMAT_UNDEFINED; + if (!parameters.depthFormats.empty()) + { + for (PixelFormat format : parameters.depthFormats) + { + PixelFormatContent formatContent = PixelFormatInfo::GetContent(format); + if (formatContent != PixelFormatContent::DepthStencil && formatContent != PixelFormatContent::Stencil) + NazaraWarning("Invalid format " + PixelFormatInfo::GetName(format) + " for depth-stencil attachment"); + + m_depthStencilFormat = ToVulkan(format); + if (m_depthStencilFormat == VK_FORMAT_UNDEFINED) + continue; + + VkFormatProperties formatProperties = m_device.GetInstance().GetPhysicalDeviceFormatProperties(physDeviceInfo.physDevice, m_depthStencilFormat); + if (formatProperties.optimalTilingFeatures & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT) + break; //< Found it + + m_depthStencilFormat = VK_FORMAT_UNDEFINED; + } + + if (m_depthStencilFormat == VK_FORMAT_UNDEFINED) + throw std::runtime_error("failed to find a support depth-stencil format"); + } + + if (!SetupRenderPass()) + throw std::runtime_error("failed to create renderpass"); + + if (!CreateSwapchain()) + throw std::runtime_error("failed to create swapchain"); } - VulkanRenderWindow::~VulkanRenderWindow() + VulkanSwapchain::~VulkanSwapchain() { - if (m_device) - m_device->WaitForIdle(); + m_device.WaitForIdle(); m_concurrentImageData.clear(); m_renderPass.reset(); @@ -37,22 +163,13 @@ namespace Nz m_swapchain.Destroy(); } - RenderFrame VulkanRenderWindow::Acquire() + RenderFrame VulkanSwapchain::AcquireFrame() { bool invalidateFramebuffer = false; - Vector2ui size = m_owner.GetSize(); - // Special case: window is minimized - if (size == Nz::Vector2ui::Zero() || m_owner.IsMinimized()) - return RenderFrame(); - - if (m_shouldRecreateSwapchain || size != m_swapchainSize) + if (m_shouldRecreateSwapchain) { - Vk::Surface& vulkanSurface = static_cast(m_owner.GetSurface())->GetSurface(); - - OnRenderTargetSizeChange(this, size); - - if (!CreateSwapchain(vulkanSurface, size)) + if (!CreateSwapchain()) throw std::runtime_error("failed to recreate swapchain"); m_shouldRecreateSwapchain = false; @@ -79,7 +196,7 @@ namespace Nz case VK_ERROR_OUT_OF_DATE_KHR: m_shouldRecreateSwapchain = true; - return Acquire(); + return AcquireFrame(); // Not expected (since timeout is infinite) case VK_TIMEOUT: @@ -102,191 +219,16 @@ namespace Nz currentFrame.Reset(imageIndex); - return RenderFrame(¤tFrame, invalidateFramebuffer, size, imageIndex); + return RenderFrame(¤tFrame, invalidateFramebuffer, m_swapchainSize, imageIndex); } - bool VulkanRenderWindow::Create(RendererImpl* /*renderer*/, RenderSurface* surface, const RenderWindowParameters& parameters) - { - std::shared_ptr device = std::static_pointer_cast(m_owner.GetRenderDevice()); - - const auto& physDeviceInfo = device->GetPhysicalDeviceInfo(); - - Vk::Surface& vulkanSurface = static_cast(surface)->GetSurface(); - - const std::vector& queueFamilyInfo = device->GetEnabledQueues(); - UInt32 graphicsFamilyQueueIndex = UINT32_MAX; - UInt32 presentableFamilyQueueIndex = UINT32_MAX; - - for (const Vk::Device::QueueFamilyInfo& queueInfo : queueFamilyInfo) - { - bool supported = false; - if (vulkanSurface.GetSupportPresentation(physDeviceInfo.physDevice, queueInfo.familyIndex, &supported) && supported) - { - if (presentableFamilyQueueIndex == UINT32_MAX || queueInfo.flags & VK_QUEUE_GRAPHICS_BIT) - { - presentableFamilyQueueIndex = queueInfo.familyIndex; - if (queueInfo.flags & VK_QUEUE_GRAPHICS_BIT) - { - graphicsFamilyQueueIndex = queueInfo.familyIndex; - break; - } - } - } - } - - if (presentableFamilyQueueIndex == UINT32_MAX) - { - NazaraError("device doesn't support presenting to this surface"); - return false; - } - - if (graphicsFamilyQueueIndex == UINT32_MAX) - { - for (const Vk::Device::QueueFamilyInfo& queueInfo : queueFamilyInfo) - { - if (queueInfo.flags & VK_QUEUE_GRAPHICS_BIT) - { - graphicsFamilyQueueIndex = queueInfo.familyIndex; - break; - } - } - } - - if (graphicsFamilyQueueIndex == UINT32_MAX) - { - NazaraError("device doesn't support graphics operations"); - return false; - } - - UInt32 transferFamilyQueueIndex = UINT32_MAX; - // Search for a transfer queue (first one being different to the graphics one) - for (const Vk::Device::QueueFamilyInfo& queueInfo : queueFamilyInfo) - { - // Transfer bit is not mandatory if compute and graphics bits are set (as they implicitly support transfer) - if (queueInfo.flags & (VK_QUEUE_COMPUTE_BIT | VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_TRANSFER_BIT)) - { - transferFamilyQueueIndex = queueInfo.familyIndex; - if (transferFamilyQueueIndex != graphicsFamilyQueueIndex) - break; - } - } - - assert(transferFamilyQueueIndex != UINT32_MAX); - - m_device = std::move(device); - - m_graphicsQueue = m_device->GetQueue(graphicsFamilyQueueIndex, 0); - m_presentQueue = m_device->GetQueue(presentableFamilyQueueIndex, 0); - m_transferQueue = m_device->GetQueue(transferFamilyQueueIndex, 0); - - std::vector surfaceFormats; - if (!vulkanSurface.GetFormats(physDeviceInfo.physDevice, &surfaceFormats)) - { - NazaraError("Failed to query supported surface formats"); - return false; - } - - m_surfaceFormat = [&] () -> VkSurfaceFormatKHR - { - if (surfaceFormats.size() == 1 && surfaceFormats.front().format == VK_FORMAT_UNDEFINED) - { - // If the list contains one undefined format, it means any format can be used - return { VK_FORMAT_R8G8B8A8_UNORM, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR }; - } - else - { - // Search for RGBA8 and default to first format - for (const VkSurfaceFormatKHR& surfaceFormat : surfaceFormats) - { - if (surfaceFormat.format == VK_FORMAT_R8G8B8A8_UNORM) - return surfaceFormat; - } - - return surfaceFormats.front(); - } - }(); - - m_depthStencilFormat = VK_FORMAT_MAX_ENUM; - if (!parameters.depthFormats.empty()) - { - for (PixelFormat format : parameters.depthFormats) - { - switch (format) - { - case PixelFormat::Depth16: - m_depthStencilFormat = VK_FORMAT_D16_UNORM; - break; - - case PixelFormat::Depth16Stencil8: - m_depthStencilFormat = VK_FORMAT_D16_UNORM_S8_UINT; - break; - - case PixelFormat::Depth24: - case PixelFormat::Depth24Stencil8: - m_depthStencilFormat = VK_FORMAT_D24_UNORM_S8_UINT; - break; - - case PixelFormat::Depth32F: - m_depthStencilFormat = VK_FORMAT_D32_SFLOAT; - break; - - case PixelFormat::Depth32FStencil8: - m_depthStencilFormat = VK_FORMAT_D32_SFLOAT_S8_UINT; - break; - - case PixelFormat::Stencil1: - case PixelFormat::Stencil4: - case PixelFormat::Stencil8: - m_depthStencilFormat = VK_FORMAT_S8_UINT; - break; - - case PixelFormat::Stencil16: - continue; - - default: - { - PixelFormatContent formatContent = PixelFormatInfo::GetContent(format); - if (formatContent != PixelFormatContent::DepthStencil && formatContent != PixelFormatContent::Stencil) - NazaraWarning("Invalid format " + PixelFormatInfo::GetName(format) + " for depth-stencil attachment"); - - m_depthStencilFormat = VK_FORMAT_MAX_ENUM; - break; - } - } - - if (m_depthStencilFormat != VK_FORMAT_MAX_ENUM) - { - VkFormatProperties formatProperties = m_device->GetInstance().GetPhysicalDeviceFormatProperties(physDeviceInfo.physDevice, m_depthStencilFormat); - if (formatProperties.optimalTilingFeatures & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT) - break; //< Found it - - m_depthStencilFormat = VK_FORMAT_MAX_ENUM; - } - } - } - - if (!SetupRenderPass()) - { - NazaraError("Failed to create render pass"); - return false; - } - - if (!CreateSwapchain(vulkanSurface, m_owner.GetSize())) - { - NazaraError("failed to create swapchain"); - return false; - } - - return true; - } - - std::shared_ptr VulkanRenderWindow::CreateCommandPool(QueueType queueType) + std::shared_ptr VulkanSwapchain::CreateCommandPool(QueueType queueType) { UInt32 queueFamilyIndex = [&] { switch (queueType) { case QueueType::Compute: - return m_device->GetDefaultFamilyIndex(QueueType::Compute); + return m_device.GetDefaultFamilyIndex(QueueType::Compute); case QueueType::Graphics: return m_graphicsQueue.GetQueueFamilyIndex(); @@ -298,31 +240,62 @@ namespace Nz throw std::runtime_error("invalid queue type " + std::to_string(UnderlyingCast(queueType))); }(); - return std::make_shared(*m_device, queueFamilyIndex); + return std::make_shared(m_device, queueFamilyIndex); } - const VulkanWindowFramebuffer& VulkanRenderWindow::GetFramebuffer(std::size_t i) const + bool VulkanSwapchain::CreateSwapchain() + { + if (!SetupSwapchain(m_device.GetPhysicalDeviceInfo())) + { + NazaraError("Failed to create swapchain"); + return false; + } + + if (m_depthStencilFormat != VK_FORMAT_MAX_ENUM && !SetupDepthBuffer()) + { + NazaraError("Failed to create depth buffer"); + return false; + } + + if (!SetupFrameBuffers()) + { + NazaraError("failed to create framebuffers"); + return false; + } + + return true; + } + + const VulkanWindowFramebuffer& VulkanSwapchain::GetFramebuffer(std::size_t i) const { assert(i < m_framebuffers.size()); return m_framebuffers[i]; } - std::size_t VulkanRenderWindow::GetFramebufferCount() const + std::size_t VulkanSwapchain::GetFramebufferCount() const { return m_framebuffers.size(); } - const VulkanRenderPass& VulkanRenderWindow::GetRenderPass() const + const VulkanRenderPass& VulkanSwapchain::GetRenderPass() const { return *m_renderPass; } - const Vector2ui& VulkanRenderWindow::GetSize() const + const Vector2ui& VulkanSwapchain::GetSize() const { return m_swapchainSize; } - void VulkanRenderWindow::Present(UInt32 imageIndex, VkSemaphore waitSemaphore) + void VulkanSwapchain::NotifyResize(const Vector2ui& newSize) + { + OnRenderTargetSizeChange(this, newSize); + + m_swapchainSize = newSize; + m_shouldRecreateSwapchain = true; + } + + void VulkanSwapchain::Present(UInt32 imageIndex, VkSemaphore waitSemaphore) { NazaraAssert(imageIndex < m_inflightFences.size(), "Invalid image index"); @@ -354,31 +327,7 @@ namespace Nz } } - bool VulkanRenderWindow::CreateSwapchain(Vk::Surface& surface, const Vector2ui& size) - { - assert(m_device); - if (!SetupSwapchain(m_device->GetPhysicalDeviceInfo(), surface, size)) - { - NazaraError("Failed to create swapchain"); - return false; - } - - if (m_depthStencilFormat != VK_FORMAT_MAX_ENUM && !SetupDepthBuffer(size)) - { - NazaraError("Failed to create depth buffer"); - return false; - } - - if (!SetupFrameBuffers(size)) - { - NazaraError("failed to create framebuffers"); - return false; - } - - return true; - } - - bool VulkanRenderWindow::SetupDepthBuffer(const Vector2ui& size) + bool VulkanSwapchain::SetupDepthBuffer() { VkImageCreateInfo imageCreateInfo = { VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType; @@ -386,7 +335,7 @@ namespace Nz 0U, // VkImageCreateFlags flags; VK_IMAGE_TYPE_2D, // VkImageType imageType; m_depthStencilFormat, // VkFormat format; - {size.x, size.y, 1U}, // VkExtent3D extent; + { m_swapchainSize.x, m_swapchainSize.y, 1U }, // VkExtent3D extent; 1U, // uint32_t mipLevels; 1U, // uint32_t arrayLayers; VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples; @@ -398,14 +347,14 @@ namespace Nz VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout; }; - if (!m_depthBuffer.Create(*m_device, imageCreateInfo)) + if (!m_depthBuffer.Create(m_device, imageCreateInfo)) { NazaraError("Failed to create depth buffer"); return false; } VkMemoryRequirements memoryReq = m_depthBuffer.GetMemoryRequirements(); - if (!m_depthBufferMemory.Create(*m_device, memoryReq.size, memoryReq.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)) + if (!m_depthBufferMemory.Create(m_device, memoryReq.size, memoryReq.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)) { NazaraError("Failed to allocate depth buffer memory"); return false; @@ -433,21 +382,21 @@ namespace Nz VK_IMAGE_VIEW_TYPE_2D, // VkImageViewType viewType; m_depthStencilFormat, // VkFormat format; { // VkComponentMapping components; - VK_COMPONENT_SWIZZLE_R, // VkComponentSwizzle .r; - VK_COMPONENT_SWIZZLE_G, // VkComponentSwizzle .g; - VK_COMPONENT_SWIZZLE_B, // VkComponentSwizzle .b; - VK_COMPONENT_SWIZZLE_A // VkComponentSwizzle .a; + VK_COMPONENT_SWIZZLE_R, // VkComponentSwizzle .r; + VK_COMPONENT_SWIZZLE_G, // VkComponentSwizzle .g; + VK_COMPONENT_SWIZZLE_B, // VkComponentSwizzle .b; + VK_COMPONENT_SWIZZLE_A // VkComponentSwizzle .a; }, { // VkImageSubresourceRange subresourceRange; - aspectMask, // VkImageAspectFlags .aspectMask; - 0, // uint32_t .baseMipLevel; - 1, // uint32_t .levelCount; - 0, // uint32_t .baseArrayLayer; - 1 // uint32_t .layerCount; + aspectMask, // VkImageAspectFlags .aspectMask; + 0, // uint32_t .baseMipLevel; + 1, // uint32_t .levelCount; + 0, // uint32_t .baseArrayLayer; + 1 // uint32_t .layerCount; } }; - if (!m_depthBufferView.Create(*m_device, imageViewCreateInfo)) + if (!m_depthBufferView.Create(m_device, imageViewCreateInfo)) { NazaraError("Failed to create depth buffer view"); return false; @@ -456,7 +405,7 @@ namespace Nz return true; } - bool VulkanRenderWindow::SetupFrameBuffers(const Vector2ui& size) + bool VulkanSwapchain::SetupFrameBuffers() { UInt32 imageCount = m_swapchain.GetImageCount(); @@ -473,14 +422,14 @@ namespace Nz m_renderPass->GetRenderPass(), (attachments[1] != VK_NULL_HANDLE) ? 2U : 1U, attachments.data(), - size.x, - size.y, + m_swapchainSize.x, + m_swapchainSize.y, 1U }; Vk::Framebuffer framebuffer; - if (!framebuffer.Create(*m_device, frameBufferCreate)) + if (!framebuffer.Create(*m_swapchain.GetDevice(), frameBufferCreate)) { NazaraError("Failed to create framebuffer for image #" + NumberToString(i) + ": " + TranslateVulkanError(framebuffer.GetLastErrorCode())); return false; @@ -492,7 +441,7 @@ namespace Nz return true; } - bool VulkanRenderWindow::SetupRenderPass() + bool VulkanSwapchain::SetupRenderPass() { std::optional colorFormat = FromVulkan(m_surfaceFormat.format); if (!colorFormat) @@ -517,34 +466,98 @@ namespace Nz std::vector subpassDependencies; BuildRenderPass(*colorFormat, depthStencilFormat.value_or(PixelFormat::Undefined), attachments, subpassDescriptions, subpassDependencies); - m_renderPass.emplace(*m_device, std::move(attachments), std::move(subpassDescriptions), std::move(subpassDependencies)); + m_renderPass.emplace(m_device, std::move(attachments), std::move(subpassDescriptions), std::move(subpassDependencies)); return true; } - bool VulkanRenderWindow::SetupSwapchain(const Vk::PhysicalDevice& deviceInfo, Vk::Surface& surface, const Vector2ui& size) + bool VulkanSwapchain::SetupSurface(WindowHandle windowHandle) + { + bool success = false; +#if defined(NAZARA_PLATFORM_WINDOWS) + { + NazaraAssert(windowHandle.type == WindowBackend::Windows, "expected Windows window"); + + HWND winHandle = reinterpret_cast(windowHandle.windows.window); + HINSTANCE instance = reinterpret_cast(GetWindowLongPtrW(winHandle, GWLP_HINSTANCE)); + + success = m_surface.Create(instance, winHandle); + } +#elif defined(NAZARA_PLATFORM_LINUX) + { + switch (windowHandle.type) + { +#ifdef VK_USE_PLATFORM_WAYLAND_KHR + case WindowBackend::Wayland: + { + wl_display* display = static_cast(windowHandle.wayland.display); + wl_surface* surface = static_cast(windowHandle.wayland.surface); + + success = m_surface.Create(display, surface); + break; + } +#endif + +#ifdef VK_USE_PLATFORM_XLIB_KHR + case WindowBackend::X11: + { + Display* display = static_cast(windowHandle.x11.display); + ::Window window = static_cast<::Window>(windowHandle.x11.window); + + success = m_surface.Create(display, window); + break; + } +#endif + + default: + { + NazaraError("unhandled window type"); + return false; + } + } + } +#elif defined(NAZARA_PLATFORM_MACOS) + { + NazaraAssert(windowHandle.type == WindowBackend::Cocoa, "expected cocoa window"); + id layer = CreateAndAttachMetalLayer(windowHandle.cocoa.window); + success = m_surface.Create(layer); + } +#else +#error This OS is not supported by Vulkan +#endif + + if (!success) + { + NazaraError("Failed to create Vulkan surface: " + TranslateVulkanError(m_surface.GetLastErrorCode())); + return false; + } + + return true; + } + + bool VulkanSwapchain::SetupSwapchain(const Vk::PhysicalDevice& deviceInfo) { VkSurfaceCapabilitiesKHR surfaceCapabilities; - if (!surface.GetCapabilities(deviceInfo.physDevice, &surfaceCapabilities)) + if (!m_surface.GetCapabilities(deviceInfo.physDevice, &surfaceCapabilities)) { NazaraError("Failed to query surface capabilities"); return false; } - Nz::UInt32 imageCount = surfaceCapabilities.minImageCount + 1; + UInt32 imageCount = surfaceCapabilities.minImageCount + 1; if (surfaceCapabilities.maxImageCount > 0 && imageCount > surfaceCapabilities.maxImageCount) imageCount = surfaceCapabilities.maxImageCount; VkExtent2D extent; if (surfaceCapabilities.currentExtent.width == 0xFFFFFFFF) { - extent.width = Nz::Clamp(size.x, surfaceCapabilities.minImageExtent.width, surfaceCapabilities.maxImageExtent.width); - extent.height = Nz::Clamp(size.y, surfaceCapabilities.minImageExtent.height, surfaceCapabilities.maxImageExtent.height); + extent.width = std::clamp(m_swapchainSize.x, surfaceCapabilities.minImageExtent.width, surfaceCapabilities.maxImageExtent.width); + extent.height = std::clamp(m_swapchainSize.y, surfaceCapabilities.minImageExtent.height, surfaceCapabilities.maxImageExtent.height); } else extent = surfaceCapabilities.currentExtent; std::vector presentModes; - if (!surface.GetPresentModes(deviceInfo.physDevice, &presentModes)) + if (!m_surface.GetPresentModes(deviceInfo.physDevice, &presentModes)) { NazaraError("Failed to query supported present modes"); return false; @@ -564,13 +577,13 @@ namespace Nz } // Ensure all operations on the device have been finished before recreating the swapchain (this can be avoided but is more complicated) - m_device->WaitForIdle(); + m_device.WaitForIdle(); VkSwapchainCreateInfoKHR swapchainInfo = { VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR, nullptr, 0, - surface, + m_surface, imageCount, m_surfaceFormat.format, m_surfaceFormat.colorSpace, @@ -587,14 +600,13 @@ namespace Nz }; Vk::Swapchain newSwapchain; - if (!newSwapchain.Create(*m_device, swapchainInfo)) + if (!newSwapchain.Create(m_device, swapchainInfo)) { NazaraError("failed to create swapchain: " + TranslateVulkanError(newSwapchain.GetLastErrorCode())); return false; } m_swapchain = std::move(newSwapchain); - m_swapchainSize = size; // Framebuffers imageCount = m_swapchain.GetImageCount(); diff --git a/src/Nazara/Widgets/Canvas.cpp b/src/Nazara/Widgets/Canvas.cpp index a89bf84f1..36d99eef9 100644 --- a/src/Nazara/Widgets/Canvas.cpp +++ b/src/Nazara/Widgets/Canvas.cpp @@ -9,7 +9,7 @@ namespace Nz { - Canvas::Canvas(entt::registry& registry, Nz::EventHandler& eventHandler, Nz::CursorControllerHandle cursorController, UInt32 renderMask, int initialRenderLayer) : + Canvas::Canvas(entt::registry& registry, Nz::WindowEventHandler& eventHandler, Nz::CursorControllerHandle cursorController, UInt32 renderMask, int initialRenderLayer) : BaseWidget(std::make_shared()), m_cursorController(cursorController), m_renderMask(renderMask), @@ -106,7 +106,7 @@ namespace Nz } } - void Canvas::OnEventMouseButtonPressed(const EventHandler* /*eventHandler*/, const WindowEvent::MouseButtonEvent& event) + void Canvas::OnEventMouseButtonPressed(const WindowEventHandler* /*eventHandler*/, const WindowEvent::MouseButtonEvent& event) { UpdateHoveredWidget(event.x, event.y); @@ -130,7 +130,7 @@ namespace Nz m_mouseOwnerButtons[event.button] = true; } - void Canvas::OnEventMouseButtonRelease(const EventHandler* /*eventHandler*/, const WindowEvent::MouseButtonEvent& event) + void Canvas::OnEventMouseButtonRelease(const WindowEventHandler* /*eventHandler*/, const WindowEvent::MouseButtonEvent& event) { if (std::size_t targetWidgetIndex = GetMouseEventTarget(); targetWidgetIndex != InvalidCanvasIndex) { @@ -150,7 +150,7 @@ namespace Nz UpdateHoveredWidget(event.x, event.y); } - void Canvas::OnEventMouseEntered(const EventHandler* /*eventHandler*/) + void Canvas::OnEventMouseEntered(const WindowEventHandler* /*eventHandler*/) { // Keep previous mouse states but not new ones if (m_mouseOwner != InvalidCanvasIndex) @@ -176,7 +176,7 @@ namespace Nz m_mouseOwnerButtons.reset(); } - void Canvas::OnEventMouseLeft(const EventHandler* /*eventHandler*/) + void Canvas::OnEventMouseLeft(const WindowEventHandler* /*eventHandler*/) { if (std::size_t targetWidgetIndex = GetMouseEventTarget(); targetWidgetIndex != InvalidCanvasIndex) { @@ -185,7 +185,7 @@ namespace Nz } } - void Canvas::OnEventMouseMoved(const EventHandler* /*eventHandler*/, const WindowEvent::MouseMoveEvent& event) + void Canvas::OnEventMouseMoved(const WindowEventHandler* /*eventHandler*/, const WindowEvent::MouseMoveEvent& event) { // Don't update hovered widget while the user doesn't release its mouse UpdateHoveredWidget(event.x, event.y); @@ -201,7 +201,7 @@ namespace Nz } } - void Canvas::OnEventMouseWheelMoved(const EventHandler* /*eventHandler*/, const WindowEvent::MouseWheelEvent& event) + void Canvas::OnEventMouseWheelMoved(const WindowEventHandler* /*eventHandler*/, const WindowEvent::MouseWheelEvent& event) { if (std::size_t targetWidgetIndex = GetMouseEventTarget(); targetWidgetIndex != InvalidCanvasIndex) { @@ -215,7 +215,7 @@ namespace Nz } } - void Canvas::OnEventKeyPressed(const EventHandler* eventHandler, const WindowEvent::KeyEvent& event) + void Canvas::OnEventKeyPressed(const WindowEventHandler* eventHandler, const WindowEvent::KeyEvent& event) { if (m_keyboardOwner != InvalidCanvasIndex) { @@ -273,7 +273,7 @@ namespace Nz OnUnhandledKeyPressed(eventHandler, event); } - void Canvas::OnEventKeyReleased(const EventHandler* eventHandler, const WindowEvent::KeyEvent& event) + void Canvas::OnEventKeyReleased(const WindowEventHandler* eventHandler, const WindowEvent::KeyEvent& event) { if (m_keyboardOwner != InvalidCanvasIndex) m_widgetEntries[m_keyboardOwner].widget->OnKeyReleased(event); @@ -281,13 +281,13 @@ namespace Nz OnUnhandledKeyReleased(eventHandler, event); } - void Canvas::OnEventTextEntered(const EventHandler* /*eventHandler*/, const WindowEvent::TextEvent& event) + void Canvas::OnEventTextEntered(const WindowEventHandler* /*eventHandler*/, const WindowEvent::TextEvent& event) { if (m_keyboardOwner != InvalidCanvasIndex) m_widgetEntries[m_keyboardOwner].widget->OnTextEntered(event.character, event.repeated); } - void Canvas::OnEventTextEdited(const EventHandler* /*eventHandler*/, const WindowEvent::EditEvent& event) + void Canvas::OnEventTextEdited(const WindowEventHandler* /*eventHandler*/, const WindowEvent::EditEvent& event) { if (m_keyboardOwner != InvalidCanvasIndex) m_widgetEntries[m_keyboardOwner].widget->OnTextEdited(event.text, event.length); diff --git a/tests/RenderTest/main.cpp b/tests/RenderTest/main.cpp index ba7fde2af..6195b6848 100644 --- a/tests/RenderTest/main.cpp +++ b/tests/RenderTest/main.cpp @@ -2,7 +2,6 @@ #include #include #include -#include #include #include #include @@ -12,6 +11,7 @@ #include #include #include +#include NAZARA_REQUEST_DEDICATED_GPU() @@ -101,10 +101,11 @@ int main() std::shared_ptr device = Nz::Renderer::Instance()->InstanciateRenderDevice(0); - Nz::RenderWindow window; + Nz::Window window; + Nz::WindowSwapchain windowSwapchain(device, window); std::string windowTitle = "Render Test"; - if (!window.Create(device, Nz::VideoMode(800, 600, 32), windowTitle)) + if (!window.Create(Nz::VideoMode(1280, 720), windowTitle)) { std::cout << "Failed to create Window" << std::endl; return __LINE__; @@ -153,15 +154,13 @@ int main() std::cout << "Vertex count: " << meshVB->GetVertexCount() << std::endl; // Create renderbuffers (GPU buffers) - const std::shared_ptr& renderDevice = window.GetRenderDevice(); - assert(meshIB->GetBuffer()->GetStorage() == Nz::DataStorage::Software); assert(meshVB->GetBuffer()->GetStorage() == Nz::DataStorage::Software); const Nz::SoftwareBuffer* indexBufferContent = static_cast(meshIB->GetBuffer().get()); const Nz::SoftwareBuffer* vertexBufferContent = static_cast(meshVB->GetBuffer().get()); - std::shared_ptr renderBufferIB = renderDevice->InstantiateBuffer(Nz::BufferType::Index, indexBufferContent->GetSize(), Nz::BufferUsage::DeviceLocal, indexBufferContent->GetData()); - std::shared_ptr renderBufferVB = renderDevice->InstantiateBuffer(Nz::BufferType::Vertex, vertexBufferContent->GetSize(), Nz::BufferUsage::DeviceLocal, vertexBufferContent->GetData()); + std::shared_ptr renderBufferIB = device->InstantiateBuffer(Nz::BufferType::Index, indexBufferContent->GetSize(), Nz::BufferUsage::DeviceLocal, indexBufferContent->GetData()); + std::shared_ptr renderBufferVB = device->InstantiateBuffer(Nz::BufferType::Vertex, vertexBufferContent->GetSize(), Nz::BufferUsage::DeviceLocal, vertexBufferContent->GetData()); // Texture Nz::TextureParams texParams; @@ -244,15 +243,13 @@ int main() std::shared_ptr pipeline = device->InstantiateRenderPipeline(pipelineInfo); - std::shared_ptr commandPool = renderDevice->InstantiateCommandPool(Nz::QueueType::Graphics); + std::shared_ptr commandPool = device->InstantiateCommandPool(Nz::QueueType::Graphics); Nz::Vector3f viewerPos = Nz::Vector3f::Zero(); Nz::EulerAnglesf camAngles(0.f, 0.f, 0.f); Nz::Quaternionf camQuat(camAngles); - window.EnableEventPolling(true); - Nz::MillisecondClock updateClock; Nz::MillisecondClock secondClock; unsigned int fps = 0; @@ -260,49 +257,42 @@ int main() Nz::Mouse::SetRelativeMouseMode(true); - Nz::DebugDrawer debugDrawer(*renderDevice); + Nz::DebugDrawer debugDrawer(*device); + + Nz::WindowEventHandler& windowEvents = window.GetEventHandler(); + windowEvents.OnKeyPressed.Connect([&](const Nz::WindowEventHandler*, const Nz::WindowEvent::KeyEvent& key) + { + if (key.virtualKey == Nz::Keyboard::VKey::F1) + window.Create(Nz::VideoMode(1920, 1080), windowTitle); + }); + + windowEvents.OnMouseMoved.Connect([&](const Nz::WindowEventHandler*, const Nz::WindowEvent::MouseMoveEvent& mouseMove) + { + // Gestion de la caméra free-fly (Rotation) + float sensitivity = 0.3f; // Sensibilité de la souris + + // On modifie l'angle de la caméra grâce au déplacement relatif sur X de la souris + camAngles.yaw = camAngles.yaw - mouseMove.deltaX * sensitivity; + camAngles.yaw.Normalize(); + + // Idem, mais pour éviter les problèmes de calcul de la matrice de vue, on restreint les angles + camAngles.pitch = Nz::Clamp(camAngles.pitch - mouseMove.deltaY * sensitivity, -89.f, 89.f); + + camQuat = camAngles; + + uboUpdate = true; + }); + + windowEvents.OnResized.Connect([&](const Nz::WindowEventHandler*, const Nz::WindowEvent::SizeEvent& sizeEvent) + { + windowSize = { sizeEvent.width, sizeEvent.height }; + ubo.projectionMatrix = Nz::Matrix4f::Perspective(Nz::DegreeAnglef(70.f), float(windowSize.x) / windowSize.y, 0.1f, 1000.f); + uboUpdate = true; + }); while (window.IsOpen()) { - Nz::WindowEvent event; - while (window.PollEvent(&event)) - { - switch (event.type) - { - case Nz::WindowEventType::Quit: - window.Close(); - break; - - case Nz::WindowEventType::MouseMoved: // La souris a bougé - { - // Gestion de la caméra free-fly (Rotation) - float sensitivity = 0.3f; // Sensibilité de la souris - - // On modifie l'angle de la caméra grâce au déplacement relatif sur X de la souris - camAngles.yaw = camAngles.yaw - event.mouseMove.deltaX * sensitivity; - camAngles.yaw.Normalize(); - - // Idem, mais pour éviter les problèmes de calcul de la matrice de vue, on restreint les angles - camAngles.pitch = Nz::Clamp(camAngles.pitch - event.mouseMove.deltaY*sensitivity, -89.f, 89.f); - - camQuat = camAngles; - - uboUpdate = true; - break; - } - - case Nz::WindowEventType::Resized: - { - windowSize = window.GetSize(); - ubo.projectionMatrix = Nz::Matrix4f::Perspective(Nz::DegreeAnglef(70.f), float(windowSize.x) / windowSize.y, 0.1f, 1000.f); - uboUpdate = true; - break; - } - - default: - break; - } - } + Nz::Window::ProcessEvents(); if (std::optional deltaTime = updateClock.RestartIfOver(Nz::Time::TickDuration(60))) { @@ -334,7 +324,7 @@ int main() uboUpdate = true; } - Nz::RenderFrame frame = window.AcquireFrame(); + Nz::RenderFrame frame = windowSwapchain.AcquireFrame(); if (!frame) { std::this_thread::sleep_for(std::chrono::milliseconds(1)); @@ -373,10 +363,11 @@ int main() debugDrawer.Prepare(frame); - const Nz::RenderTarget* windowRT = window.GetRenderTarget(); + const Nz::RenderTarget& windowRT = windowSwapchain.GetSwapchain(); frame.Execute([&](Nz::CommandBufferBuilder& builder) { - Nz::Recti renderRect(0, 0, window.GetSize().x, window.GetSize().y); + windowSize = window.GetSize(); + Nz::Recti renderRect(0, 0, windowSize.x, windowSize.y); Nz::CommandBufferBuilder::ClearValues clearValues[2]; clearValues[0].color = Nz::Color::Black(); @@ -385,7 +376,7 @@ int main() builder.BeginDebugRegion("Main window rendering", Nz::Color::Green()); { - builder.BeginRenderPass(windowRT->GetFramebuffer(frame.GetFramebufferIndex()), windowRT->GetRenderPass(), renderRect, { clearValues[0], clearValues[1] }); + builder.BeginRenderPass(windowRT.GetFramebuffer(frame.GetFramebufferIndex()), windowRT.GetRenderPass(), renderRect, { clearValues[0], clearValues[1] }); { builder.BindIndexBuffer(*renderBufferIB, Nz::IndexType::U16); builder.BindRenderPipeline(*pipeline);