From cd414c352ede91ea72546f26578b6dc251388474 Mon Sep 17 00:00:00 2001 From: Georg Hagen Date: Wed, 5 Jun 2024 14:17:29 +0200 Subject: [PATCH] Start refactoring of OpenVulkanoView implementation (#1) --- openVulkanoCpp/Host/iOS/MetalViewWindow.h | 88 ++++++++++ openVulkanoCpp/Host/iOS/MetalViewWindow.mm | 53 ++++++ openVulkanoCpp/Host/iOS/OpenVulkanoView.h | 7 + openVulkanoCpp/Host/iOS/OpenVulkanoView.mm | 115 ++++++++++++- .../Host/iOS/OpenVulkanoViewController.h | 7 + .../Host/iOS/OpenVulkanoViewController.mm | 162 +++--------------- 6 files changed, 292 insertions(+), 140 deletions(-) create mode 100644 openVulkanoCpp/Host/iOS/MetalViewWindow.h create mode 100644 openVulkanoCpp/Host/iOS/MetalViewWindow.mm diff --git a/openVulkanoCpp/Host/iOS/MetalViewWindow.h b/openVulkanoCpp/Host/iOS/MetalViewWindow.h new file mode 100644 index 0000000..94c1613 --- /dev/null +++ b/openVulkanoCpp/Host/iOS/MetalViewWindow.h @@ -0,0 +1,88 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +#pragma once + +#include "Base/UI/IVulkanWindow.hpp" + +namespace OpenVulkano +{ + class MetalViewWindow final : public IVulkanWindow + { + WindowConfiguration windowConf; + IWindowHandler* handler = nullptr; + void* caMetalLayer = nullptr; + bool tickHandler = true; + + public: + void Init(RenderAPI::RenderApi renderApi) override {} + + void Init(void* metalLayer, Math::Vector2ui size) + { + caMetalLayer = metalLayer; + windowConf.size = size; + } + + void SetMetalLayer(void* metalLayer) { caMetalLayer = metalLayer; } + + bool HasTitle() override { return false; } + + const std::string& GetTitle() override { return windowConf.title; } + + void SetTitle(const std::string& title) override {} + + WindowMode GetWindowMode() override { return FULLSCREEN; } + + void SetWindowMode(WindowMode) override {} + + const WindowConfiguration& GetWindowConfiguration() override { return windowConf; } + + void SetSize(uint32_t width, uint32_t height) override { windowConf.size = { width, height }; } + + void SetSizeLimits(int minWidth, int minHeight, int maxWidth, int maxHeight) override {} + + Math::Vector2i GetPosition() override { return { 0, 0 }; } + + void SetPosition(int posX, int posY) override {} + + void Show() override {} + + void Hide() override {} + + void Show(bool show) override {} + + IWindowHandler* GetWindowHandler() override { return handler; } + + void SetWindowHandler(IWindowHandler* handler) override { this->handler = handler; } + + uint32_t GetWindowId() const override { return 0; } + + IOpenGlWindow* GetOpenGlWindow() override { return nullptr; } + + IVulkanWindow* GetVulkanWindow() override { return this; } + + bool WindowHasBeenDestroyed() const override { return false; } + + void SetWindowHasBeenDestroyed() override + { + //TODO + } + + void* GetNativeWindowHandle() override { return caMetalLayer; } + + vk::SurfaceKHR CreateSurface(const vk::Instance& instance, const vk::AllocationCallbacks* pAllocator = nullptr) override; + + std::vector GetRequiredInstanceExtensions() override; + + Math::Vector2ui GetSize() override { return windowConf.size; } + + void Close() override {} + + void OnResize(uint32_t width, uint32_t height); + + void TickHandler(); + }; +} diff --git a/openVulkanoCpp/Host/iOS/MetalViewWindow.mm b/openVulkanoCpp/Host/iOS/MetalViewWindow.mm new file mode 100644 index 0000000..1a791a3 --- /dev/null +++ b/openVulkanoCpp/Host/iOS/MetalViewWindow.mm @@ -0,0 +1,53 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +// Makre usre the Molten include is first! +#include + +#include "MetalViewWindow.h" +#include "Base/Logger.hpp" +#include "Host/GraphicsAppManager.hpp" + +#import + +namespace OpenVulkano +{ + vk::SurfaceKHR MetalViewWindow::CreateSurface(const vk::Instance& instance, const vk::AllocationCallbacks* pAllocator) + { + VkMetalSurfaceCreateInfoEXT surfaceCreateInfo; + surfaceCreateInfo.sType = VK_STRUCTURE_TYPE_METAL_SURFACE_CREATE_INFO_EXT; + surfaceCreateInfo.pNext = NULL; + surfaceCreateInfo.flags = 0; + surfaceCreateInfo.pLayer = (CAMetalLayer*) caMetalLayer; + + VkSurfaceKHR surface; + auto err = vkCreateMetalSurfaceEXT(static_cast(instance), &surfaceCreateInfo, NULL, &surface); + return {surface}; + } + + std::vector MetalViewWindow::GetRequiredInstanceExtensions() + { + return {}; //TODO + } + + void MetalViewWindow::OnResize(uint32_t newWidth, uint32_t newHeight) + { + Logger::WINDOW->debug("Window (id: {0}) resized (width: {1}, height: {2})", GetWindowId(), newWidth, newHeight); + if (handler) + handler->OnWindowResize(this, newWidth, newHeight); + } + + void MetalViewWindow::TickHandler() + { + if (tickHandler) + { + if (auto graphApp = dynamic_cast(handler)) + { + graphApp->LoopTick(); + } + } + } +} diff --git a/openVulkanoCpp/Host/iOS/OpenVulkanoView.h b/openVulkanoCpp/Host/iOS/OpenVulkanoView.h index e432261..0783328 100644 --- a/openVulkanoCpp/Host/iOS/OpenVulkanoView.h +++ b/openVulkanoCpp/Host/iOS/OpenVulkanoView.h @@ -14,4 +14,11 @@ //@interface OpenVulkanoView : UIView @interface OpenVulkanoView : MTKView +-(void*)GetWindow; + +-(void)WillAppear; +-(void)DidAppear; +-(void)WillDisappear; +-(void)DidDisappear; +-(void)DidUnload; @end diff --git a/openVulkanoCpp/Host/iOS/OpenVulkanoView.mm b/openVulkanoCpp/Host/iOS/OpenVulkanoView.mm index ba38f94..c5f99e9 100644 --- a/openVulkanoCpp/Host/iOS/OpenVulkanoView.mm +++ b/openVulkanoCpp/Host/iOS/OpenVulkanoView.mm @@ -8,21 +8,57 @@ #include "Input/Touch/InputDeviceTouch.hpp" #include "Input/InputManager.hpp" +#include "MetalViewWindow.h" #include +#import + +using namespace OpenVulkano; + +#pragma mark MetalViewDelegate +@interface MetalViewDelegate : NSObject +- (void) mtkView:(MTKView *) view drawableSizeWillChange:(CGSize) size; +- (void) drawInMTKView:(MTKView *) view; +@end + +@implementation MetalViewDelegate +{ + MetalViewWindow* window; +} + +- (id)initWithWindow:(MetalViewWindow*)win +{ + window = win; + return self; +} + +- (void) mtkView:(MTKView *) view drawableSizeWillChange:(CGSize) size +{ + window->OnResize(size.width, size.height); +} + +- (void) drawInMTKView:(MTKView *) view +{ + @autoreleasepool { + window->TickHandler(); + } +} +@end + #pragma mark - #pragma mark OpenVulkanoView -using namespace OpenVulkano; - @interface OpenVulkanoView() { - CADisplayLink * m_displayLink; + CADisplayLink* m_displayLink; + MetalViewDelegate* m_mtdelegate; std::map m_touchToIdMap; Input::InputDeviceTouch m_touchDevice; + MetalViewWindow m_window; } @end +#pragma mark OpenVulkanoView Implementation @implementation OpenVulkanoView /** Returns a Metal-compatible layer. */ +(Class) layerClass { return [CAMetalLayer class]; } @@ -45,8 +81,28 @@ using namespace OpenVulkano; - (void)commonInit { [self setMultipleTouchEnabled:YES]; + + self.contentScaleFactor = UIScreen.mainScreen.nativeScale / 1.5f; + + auto size = self.bounds.size; + auto sizeX = size.width * self.contentScaleFactor; + auto sizeY = size.height * self.contentScaleFactor; + m_window.Init(self.layer, {sizeX, sizeY}); + m_touchDevice.Init(); //TODO link window Input::InputManager::GetInstance()->RegisterInputDevice(&m_touchDevice); + + if ([self isKindOfClass:[MTKView class]]) { + MTKView* mtkView = (MTKView*)(self); + m_mtdelegate = [[MetalViewDelegate alloc] initWithWindow:&m_window]; + [mtkView setDelegate:m_mtdelegate]; + mtkView.preferredFramesPerSecond = 60; + } else { + m_displayLink = [CADisplayLink displayLinkWithTarget: self selector: @selector(renderLoop)]; + [m_displayLink setPreferredFramesPerSecond: 60]; + [m_displayLink addToRunLoop: NSRunLoop.currentRunLoop forMode: NSDefaultRunLoopMode]; + m_displayLink.paused = YES; + } } - (void)dealloc { @@ -55,9 +111,23 @@ using namespace OpenVulkano; } Input::InputManager::GetInstance()->UnregisterInputDevice(&m_touchDevice); m_touchDevice.Close(); + [m_displayLink release]; + [m_mtdelegate release]; [super dealloc]; } +- (void)layoutSubviews { + [super layoutSubviews]; + + if (m_displayLink) + { // Only use this update method if we use display link instead of metal delegate + auto size = self.bounds.size; + auto sizeX = size.width * self.contentScaleFactor; + auto sizeY = size.height * self.contentScaleFactor; + m_window.OnResize(sizeX, sizeY); + } +} + - (Math::Vector2f)getTouchPosition:(UITouch*)touch { CGPoint uitouchLocation = [touch locationInView:touch.view]; @@ -121,5 +191,44 @@ using namespace OpenVulkano; } } +-(void*)GetWindow +{ + return &m_window; +} + +-(void) renderLoop +{ + m_window.TickHandler(); +} + +-(void)WillAppear +{ + if (m_displayLink) m_displayLink.paused = NO; +} + +-(void)DidAppear +{ + if (m_displayLink) m_displayLink.paused = NO; +} + +-(void)WillDisappear +{ + if (m_displayLink) m_displayLink.paused = YES; +} + +-(void)DidDisappear +{ + if (m_displayLink) m_displayLink.paused = YES; +} + +-(void)DidUnload +{ + if (m_displayLink) + { + [m_displayLink invalidate]; + [m_displayLink release]; + m_displayLink = nil; + } +} @end diff --git a/openVulkanoCpp/Host/iOS/OpenVulkanoViewController.h b/openVulkanoCpp/Host/iOS/OpenVulkanoViewController.h index db0223f..0935db7 100644 --- a/openVulkanoCpp/Host/iOS/OpenVulkanoViewController.h +++ b/openVulkanoCpp/Host/iOS/OpenVulkanoViewController.h @@ -4,12 +4,19 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ +#pragma once + +#import "OpenVulkanoView.h" #import #pragma mark - #pragma mark OpenVulkanoViewController @interface OpenVulkanoViewController : UIViewController +{ + @public OpenVulkanoView* openVulkanoView; + @public BOOL fixOpenVulkanoViewOrientation; +} -(void*) makeGraphicsApp; @end diff --git a/openVulkanoCpp/Host/iOS/OpenVulkanoViewController.mm b/openVulkanoCpp/Host/iOS/OpenVulkanoViewController.mm index 20f6237..20ebc71 100644 --- a/openVulkanoCpp/Host/iOS/OpenVulkanoViewController.mm +++ b/openVulkanoCpp/Host/iOS/OpenVulkanoViewController.mm @@ -11,128 +11,32 @@ #include "Base/UI/IVulkanWindow.hpp" #import +#import "OpenVulkanoView.h" #pragma mark - #pragma mark OpenVulkanoViewController using namespace OpenVulkano; -class ViewWindow final : public IVulkanWindow -{ - WindowConfiguration windowConf; - IWindowHandler* handler = nullptr; - void* caMetalLayer = nullptr; - -public: - void Init(RenderAPI::RenderApi renderApi) override {} - void Init(void* metalLayer, Math::Vector2ui size) - { - caMetalLayer = metalLayer; - windowConf.size = size; - } - - void SetMetalLayer(void* metalLayer) { caMetalLayer = metalLayer; } - - bool HasTitle() override { return false; } - const std::string& GetTitle() override { return windowConf.title; } - void SetTitle(const std::string& title) override {} - - WindowMode GetWindowMode() override { return FULLSCREEN; } - void SetWindowMode(WindowMode) override {} - - const WindowConfiguration & GetWindowConfiguration() override { return windowConf; } - void SetSize(uint32_t width, uint32_t height) override { windowConf.size = { width, height }; } - void SetSizeLimits(int minWidth, int minHeight, int maxWidth, int maxHeight) override {} - - Math::Vector2i GetPosition() override { return { 0,0 }; } - void SetPosition(int posX, int posY) override {} - - void Show() override {} - void Hide() override {} - void Show(bool show) override {} - - IWindowHandler * GetWindowHandler() override { return handler; } - void SetWindowHandler(IWindowHandler *handler) override { this->handler = handler; } - uint32_t GetWindowId() const override { return 0; } - - IOpenGlWindow * GetOpenGlWindow() override { return nullptr; } - IVulkanWindow * GetVulkanWindow() override { return this; } - - bool WindowHasBeenDestroyed() const override { return false; } - void SetWindowHasBeenDestroyed() override {} - - void* GetNativeWindowHandle() override { return caMetalLayer; } - - vk::SurfaceKHR CreateSurface(const vk::Instance &instance, const vk::AllocationCallbacks *pAllocator = nullptr) override - { - VkMetalSurfaceCreateInfoEXT surfaceCreateInfo; - surfaceCreateInfo.sType = VK_STRUCTURE_TYPE_METAL_SURFACE_CREATE_INFO_EXT; - surfaceCreateInfo.pNext = NULL; - surfaceCreateInfo.flags = 0; - surfaceCreateInfo.pLayer = (CAMetalLayer*)caMetalLayer; - - VkSurfaceKHR surface; - auto err = vkCreateMetalSurfaceEXT(static_cast(instance), &surfaceCreateInfo, NULL, &surface); - return { surface }; - } - - std::vector GetRequiredInstanceExtensions() override - { - return {}; - } - - Math::Vector2ui GetSize() override { return windowConf.size;} - - void Close() override {} -}; - -@interface MetalViewDelegate : NSObject -- (id)initWithGAM:(GraphicsAppManager*)gam; -- (void) mtkView:(MTKView *) view drawableSizeWillChange:(CGSize) size; -- (void) drawInMTKView:(MTKView *) view; -@end - -@implementation MetalViewDelegate -{ - GraphicsAppManager* manager; - IWindow* window; -} - -- (id)initWithGAM:(GraphicsAppManager*)gam win:(IWindow*)win -{ - manager = gam; - window = win; - return self; -} - -- (void) mtkView:(MTKView *) view drawableSizeWillChange:(CGSize) size -{ - manager->OnWindowResize(window, size.width, size.height); -} - -- (void) drawInMTKView:(MTKView *) view -{ - @autoreleasepool { - manager->LoopTick(); - } -} -@end @implementation OpenVulkanoViewController { - CADisplayLink* _displayLink; GraphicsAppManager* manager; - ViewWindow window; std::unique_ptr app; - MetalViewDelegate* mtdelegate; } -(void*) makeGraphicsApp { return nullptr; } +-(id)init { + [super init]; + openVulkanoView = nil; + fixOpenVulkanoViewOrientation = false; + return self; +} + -(void) dealloc { manager->ShutDown(); - [_displayLink release]; [super dealloc]; } @@ -140,61 +44,45 @@ public: -(void) viewDidLoad { [super viewDidLoad]; - self.view.contentScaleFactor = UIScreen.mainScreen.nativeScale / 1.5f; - - auto size = self.view.bounds.size; - auto sizeX = size.width * self.view.contentScaleFactor; - auto sizeY = size.height * self.view.contentScaleFactor; - window.Init(self.view.layer, {sizeX, sizeY}); + if (openVulkanoView == nil && [self.view isKindOfClass:[OpenVulkanoView class]]) { + openVulkanoView = (OpenVulkanoView*)self.view; + } + //TODO check if type is correct IGraphicsApp* appPtr = static_cast(self.makeGraphicsApp); if (!appPtr) throw std::runtime_error("Failed to create graphics app"); app = std::unique_ptr(appPtr); - manager = new GraphicsAppManager(app.get(), &window); + manager = new GraphicsAppManager(app.get(), (IVulkanWindow*)[openVulkanoView GetWindow]); manager->StartUp(); - - if ([self.view isKindOfClass:[MTKView class]]) { - MTKView* mtkView = (MTKView*)(self.view); - mtdelegate = [[MetalViewDelegate alloc] initWithGAM:manager win:&window]; - [mtkView setDelegate:mtdelegate]; - mtkView.preferredFramesPerSecond = 60; - } else { - _displayLink = [CADisplayLink displayLinkWithTarget: self selector: @selector(renderLoop)]; - [_displayLink setPreferredFramesPerSecond: 60]; - [_displayLink addToRunLoop: NSRunLoop.currentRunLoop forMode: NSDefaultRunLoopMode]; - } } -(void) viewWillAppear:(BOOL)animated { + if (openVulkanoView != nil) { [openVulkanoView willAppear]; } [super viewWillAppear:animated]; - self.view.contentScaleFactor = UIScreen.mainScreen.nativeScale / 1.5f; +} - auto size = self.view.bounds.size; - auto sizeX = size.width * self.view.contentScaleFactor; - auto sizeY = size.height * self.view.contentScaleFactor; - manager->OnWindowResize(&window, sizeX, sizeY); +-(void) viewDidAppear:(BOOL)animated { + if (openVulkanoView != nil) { [openVulkanoView DidAppear]; } + [super viewDidAppear:animated]; +} + +-(void) viewWillDisappear:(BOOL)animated { + if (openVulkanoView != nil) { [openVulkanoView WillDisappear]; } + [super viewWillDisappear:animated]; } -(void) viewDidDisappear:(BOOL)animated { - [_displayLink release]; - _displayLink = nil; + if (openVulkanoView != nil) { [openVulkanoView DidDisappear]; } [super viewDidDisappear:animated]; } -(void) viewDidUnload { - [_displayLink release]; - _displayLink = nil; + if (openVulkanoView != nil) { [openVulkanoView DidUnload]; } [super viewDidUnload]; } --(void) renderLoop { - manager->LoopTick(); -} - -// Allow device rotation to resize the swapchain -(void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id)coordinator { [super viewWillTransitionToSize:size withTransitionCoordinator:coordinator]; - manager->OnWindowResize(&window, size.width, size.height); } - (BOOL)prefersHomeIndicatorAutoHidden {