Skip to content

Commit

Permalink
Simplified NativeHandle structure for Mac: Use single NSResponder field.
Browse files Browse the repository at this point in the history
  • Loading branch information
LukasBanana committed Sep 4, 2023
1 parent 820ed6f commit 5ee8cc3
Show file tree
Hide file tree
Showing 6 changed files with 92 additions and 86 deletions.
13 changes: 8 additions & 5 deletions include/LLGL/Platform/MacOS/MacOSNativeHandle.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,14 @@ namespace LLGL
*/
struct NativeHandle
{
//! NSWindow object for top level windows.
NSWindow* window;

//! NSView object for borderless windows that have a parent window.
NSView* view;
/**
\brief Generic \c NSResponder object that must be either of type \c NSWindow or \c NSView.
\remarks When a SwapChain is created, the responder is interpreted as:
- \b Top-level window if it points to an \c NSWindow, in which case the respective \c MTKView (Metal) or \c GLKView (OpenGL) will \e replace its content view.
- \b Subview if it points to an \c NSView, in which case the respective \c MTKView (Metal) or \c GLKView (OpenGL) will be \e added as a subview.
\see WindowDescriptor::windowContext
*/
NSResponder* responder;
};


Expand Down
9 changes: 5 additions & 4 deletions sources/Platform/MacOS/MacOSSubviewWindow.mm
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,7 @@
if (nativeHandle != nullptr && nativeHandleSize == sizeof(NativeHandle))
{
NativeHandle* handle = reinterpret_cast<NativeHandle*>(nativeHandle);
handle->window = nullptr;
handle->view = view_;
handle->responder = view_;
return true;
}
return false;
Expand Down Expand Up @@ -160,14 +159,16 @@ static void SetRelativeNSViewPosition(NSView* view, const Offset2D& position, NS
{
/* Add to parent window if specified */
const NativeHandle* parentHandle = reinterpret_cast<const NativeHandle*>(desc.windowContext);
if (NSWindow* parentWindow = parentHandle->window)
if ([parentHandle->responder isKindOfClass:[NSWindow class]])
{
NSWindow* parentWindow = (NSWindow*)parentHandle->responder;
[[parentWindow contentView] addSubview:view];
if (!isCentered)
SetRelativeNSViewPosition(view, desc.position, [parentWindow contentView]);
}
else if (NSView* parentView = parentHandle->view)
else if ([parentHandle->responder isKindOfClass:[NSView class]])
{
NSView* parentView = (NSView*)parentHandle->responder;
[parentView addSubview:view];
if (!isCentered)
SetRelativeNSViewPosition(view, desc.position, parentView);
Expand Down
26 changes: 6 additions & 20 deletions sources/Platform/MacOS/MacOSWindow.mm
Original file line number Diff line number Diff line change
Expand Up @@ -113,8 +113,7 @@ static NSUInteger GetNSWindowStyleMask(const WindowDescriptor& desc)
if (nativeHandle != nullptr && nativeHandleSize == sizeof(NativeHandle))
{
NativeHandle* handle = reinterpret_cast<NativeHandle*>(nativeHandle);
handle->window = wnd_;
handle->view = nullptr;
handle->responder = wnd_;
return true;
}
return false;
Expand Down Expand Up @@ -321,25 +320,12 @@ static void SetRelativeNSWindowPosition(NSWindow* wnd, const Offset2D& position,

const bool isCentered = ((desc.flags & WindowFlags::Centered) != 0);

if (desc.windowContext != nullptr && desc.windowContextSize == sizeof(NativeHandle))
{
/* Add to parent window if specified */
if (NSWindow* parentWnd = reinterpret_cast<const NativeHandle*>(desc.windowContext)->window)
{
[parentWnd addChildWindow:wnd ordered:NSWindowAbove];
if (!isCentered)
SetRelativeNSWindowPosition(wnd, desc.position, parentWnd);
}
}
/* Move this window to the front of the screen list and center if requested */
[wnd makeKeyAndOrderFront:nil];
if (isCentered)
[wnd center];
else
{
/* Move this window to the front of the screen list and center if requested */
[wnd makeKeyAndOrderFront:nil];
if (isCentered)
[wnd center];
else
SetRelativeNSWindowPosition(wnd, desc.position);
}
SetRelativeNSWindowPosition(wnd, desc.position);

/* Show window */
if ((desc.flags & WindowFlags::Visible) != 0)
Expand Down
3 changes: 3 additions & 0 deletions sources/Renderer/Metal/MTSwapChain.h
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,9 @@ class MTSwapChain final : public SwapChain

private:

// Allocates the MetalKit view and initializes it with the specified surface.
MTKView* AllocMTKViewAndInitWithSurface(id<MTLDevice> device, Surface& surface);

bool ResizeBuffersPrimary(const Extent2D& resolution) override;

private:
Expand Down
117 changes: 65 additions & 52 deletions sources/Renderer/Metal/MTSwapChain.mm
Original file line number Diff line number Diff line change
Expand Up @@ -55,62 +55,14 @@ - (void)mtkView:(nonnull MTKView *)view drawableSizeWillChange:(CGSize)size
SwapChain { desc },
renderPass_ { device, desc }
{
/* Create surface */
/* Initialize surface for MetalKit view */
SetOrCreateSurface(surface, desc.resolution, desc.fullscreen, nullptr);

NativeHandle nativeHandle = {};
GetSurface().GetNativeHandle(&nativeHandle, sizeof(nativeHandle));

/* Create MetalKit view */
#ifdef LLGL_OS_IOS

LLGL_ASSERT_PTR(nativeHandle.view);
UIView* canvasView = nativeHandle.view;

/* Allocate MetalKit view */
view_ = [[MTKView alloc] initWithFrame:canvasView.frame device:device];

/* Allocate view delegate to handle re-draw events */
viewDelegate_ = [[MTSwapChainViewDelegate alloc] initWithCanvas:CastTo<Canvas>(GetSurface())];
[viewDelegate_ mtkView:view_ drawableSizeWillChange:view_.bounds.size];
[view_ setDelegate:viewDelegate_];

/* Register rotate/resize layout constraints */
view_.translatesAutoresizingMaskIntoConstraints = NO;
NSDictionary* viewsDictionary = @{@"mtkView":view_};
[canvasView addSubview:view_];
[canvasView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"|[mtkView]|" options:0 metrics:nil views:viewsDictionary]];
[canvasView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[mtkView]|" options:0 metrics:nil views:viewsDictionary]];

#else // LLGL_OS_IOS

if (NSWindow* contentWindow = nativeHandle.window)
{
/* Allocate MetalKit view */
CGRect contentViewRect = [[contentWindow contentView] frame];
view_ = [[MTKView alloc] initWithFrame:contentViewRect device:device];

/* Replace content view of input window with MTKView */
[contentWindow setContentView:view_];
[contentWindow.contentViewController setView:view_];
}
else if (NSView* contentView = nativeHandle.view)
{
/* Allocate MetalKit view */
CGRect contentViewRect = [contentView frame];
view_ = [[MTKView alloc] initWithFrame:contentViewRect device:device];

/* Add MTKView as subview to the input view */
[contentView addSubview:view_];
}
else
LLGL_TRAP("neither NSWindow nor NSView is specified for MTKView");

#endif // /LLGL_OS_IOS

view_.framebufferOnly = NO; //TODO: make this optional with create/bind flag
/* Allocate and initialize MetalKit view */
view_ = AllocMTKViewAndInitWithSurface(device, GetSurface());

/* Initialize color and depth buffer */
view_.framebufferOnly = NO; //TODO: make this optional with create/bind flag
view_.colorPixelFormat = renderPass_.GetColorAttachments()[0].pixelFormat;
view_.depthStencilPixelFormat = renderPass_.GetDepthStencilFormat();
view_.sampleCount = renderPass_.GetSampleCount();
Expand Down Expand Up @@ -191,6 +143,67 @@ - (void)mtkView:(nonnull MTKView *)view drawableSizeWillChange:(CGSize)size
* ======= Private: =======
*/

MTKView* MTSwapChain::AllocMTKViewAndInitWithSurface(id<MTLDevice> device, Surface& surface)
{
MTKView* mtkView = nullptr;

NativeHandle nativeHandle = {};
GetSurface().GetNativeHandle(&nativeHandle, sizeof(nativeHandle));

/* Create MetalKit view */
#ifdef LLGL_OS_IOS

LLGL_ASSERT_PTR(nativeHandle.view);
UIView* canvasView = nativeHandle.view;

/* Allocate MetalKit view */
mtkView = [[MTKView alloc] initWithFrame:canvasView.frame device:device];

/* Allocate view delegate to handle re-draw events */
viewDelegate_ = [[MTSwapChainViewDelegate alloc] initWithCanvas:CastTo<Canvas>(GetSurface())];
[viewDelegate_ mtkView:mtkView drawableSizeWillChange:mtkView.bounds.size];
[mtkView setDelegate:viewDelegate_];

/* Register rotate/resize layout constraints */
mtkView.translatesAutoresizingMaskIntoConstraints = NO;
NSDictionary* viewsDictionary = @{@"mtkView":mtkView};
[canvasView addSubview:mtkView];
[canvasView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"|[mtkView]|" options:0 metrics:nil views:viewsDictionary]];
[canvasView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[mtkView]|" options:0 metrics:nil views:viewsDictionary]];

#else // LLGL_OS_IOS

if ([nativeHandle.responder isKindOfClass:[NSWindow class]])
{
NSWindow* contentWindow = (NSWindow*)nativeHandle.responder;

/* Allocate MetalKit view */
CGRect contentViewRect = [[contentWindow contentView] frame];
mtkView = [[MTKView alloc] initWithFrame:contentViewRect device:device];

/* Replace content view of input window with MTKView */
[contentWindow setContentView:mtkView];
[contentWindow.contentViewController setView:mtkView];
}
else if ([nativeHandle.responder isKindOfClass:[NSView class]])
{
NSView* contentView = (NSView*)nativeHandle.responder;

/* Allocate MetalKit view */
CGRect contentViewRect = [contentView frame];
mtkView = [[MTKView alloc] initWithFrame:contentViewRect device:device];

/* Add MTKView as subview to the input view */
[contentView addSubview:mtkView];
}
else
LLGL_TRAP("NativeHandle::responder is neither of type NSWindow nor NSView for MTKView");

#endif // /LLGL_OS_IOS

return mtkView;
}

bool MTSwapChain::ResizeBuffersPrimary(const Extent2D& /*resolution*/)
{
return true; // do nothing
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,12 @@
/* Get native window handle */
NativeHandle nativeHandle = {};
surface.GetNativeHandle(&nativeHandle, sizeof(nativeHandle));
if (NSWindow* contentWindow = nativeHandle.window)
view_ = [contentWindow contentView];
else if (NSView* contentView = nativeHandle.view)
view_ = contentView;
if ([nativeHandle.responder isKindOfClass:[NSWindow class]])
view_ = [(NSWindow*)nativeHandle.responder contentView];
else if ([nativeHandle.responder isKindOfClass:[NSView class]])
view_ = (NSView*)nativeHandle.responder;
else
LLGL_TRAP("neither NSWindow nor NSView is specified for GLKView");
LLGL_TRAP("NativeHandle::responder is neither of type NSWindow nor NSView for GLKView");
}

bool MacOSGLSwapChainContext::SwapBuffers()
Expand Down

0 comments on commit 5ee8cc3

Please sign in to comment.