Fixed osx multiple window create/destroy

This commit is contained in:
Attila Kocsis 2019-03-07 19:54:03 +01:00
parent 0c2b720f8e
commit 8196612195
3 changed files with 201 additions and 163 deletions

View File

@ -30,7 +30,6 @@
@interface Window : NSObject<NSWindowDelegate>
{
uint32_t windowCount;
}
+ (Window*)sharedDelegate;
@ -93,8 +92,7 @@ namespace entry
struct Context
{
Context()
: m_windowsCreated(0)
, m_scrollf(0.0f)
: m_scrollf(0.0f)
, m_mx(0)
, m_my(0)
, m_scroll(0)
@ -151,6 +149,11 @@ namespace entry
s_translateKey[uint8_t(ch)] =
s_translateKey[uint8_t(ch - ' ')] = Key::KeyA + (ch - 'a');
}
for(int ii=0; ii<ENTRY_CONFIG_MAX_WINDOWS; ++ii)
{
m_window[ii] = NULL;
}
}
NSEvent* waitEvent()
@ -258,8 +261,18 @@ namespace entry
{
NSEventType eventType = [event type];
NSWindow *window = [NSApp keyWindow];
WindowHandle handle = handleFromWindow(window);
NSWindow *window = [event window];
WindowHandle handle = {UINT16_MAX};
if (nil != window)
{
handle = findHandle(window);
}
if (!isValid(handle))
{
[NSApp sendEvent:event];
[NSApp updateWindows];
return true;
}
switch (eventType)
{
@ -367,7 +380,7 @@ namespace entry
void windowDidResize(NSWindow *window)
{
WindowHandle handle = handleFromWindow(window);
WindowHandle handle = findHandle(window);
NSRect originalFrame = [window frame];
NSRect rect = [window contentRectForFrameRect: originalFrame];
uint32_t width = uint32_t(rect.size.width);
@ -381,14 +394,14 @@ namespace entry
void windowDidBecomeKey(NSWindow *window)
{
WindowHandle handle = handleFromWindow(window);
WindowHandle handle = findHandle(window);
m_eventQueue.postSuspendEvent(handle, Suspend::WillResume);
m_eventQueue.postSuspendEvent(handle, Suspend::DidResume);
}
void windowDidResignKey(NSWindow *window)
{
WindowHandle handle = handleFromWindow(window);
WindowHandle handle = findHandle(window);
m_eventQueue.postSuspendEvent(handle, Suspend::WillSuspend);
m_eventQueue.postSuspendEvent(handle, Suspend::DidSuspend);
}
@ -477,31 +490,28 @@ namespace entry
return 0;
}
bool isValid(WindowHandle _handle)
WindowHandle findHandle(NSWindow *_window)
{
return m_windowAlloc.isValid(_handle.idx);
}
WindowHandle handleFromWindow(NSWindow *window)
{
uint16_t windowIdx = 0;
for (uint16_t i = 0; i < m_windowsCreated; i++)
bx::MutexScope scope(m_lock);
for (uint16_t ii = 0, num = m_windowAlloc.getNumHandles(); ii < num; ++ii)
{
if (window == m_window[i])
uint16_t idx = m_windowAlloc.getHandleAt(ii);
if (_window == m_window[idx])
{
windowIdx = i;
break;
WindowHandle handle = { idx };
return handle;
}
}
WindowHandle handle = { windowIdx };
return handle;
WindowHandle invalid = { UINT16_MAX };
return invalid;
}
EventQueue m_eventQueue;
bx::Mutex m_lock;
bx::HandleAllocT<ENTRY_CONFIG_MAX_WINDOWS> m_windowAlloc;
NSWindow* m_window[ENTRY_CONFIG_MAX_WINDOWS];
SInt32 m_windowsCreated;
NSRect m_windowFrame;
float m_scrollf;
@ -533,105 +543,111 @@ namespace entry
WindowHandle createWindow(int32_t _x, int32_t _y, uint32_t _width, uint32_t _height, uint32_t _flags, const char* _title)
{
BX_UNUSED(_flags);
bx::MutexScope scope(s_ctx.m_lock);
WindowHandle handle = { s_ctx.m_windowAlloc.alloc() };
uint16_t handleIdx = IncrementAtomic(&s_ctx.m_windowsCreated);
if (handleIdx >= ENTRY_CONFIG_MAX_WINDOWS)
if (UINT16_MAX != handle.idx)
{
return { UINT16_MAX };
}
WindowHandle handle = { handleIdx };
void (^createWindowBlock)(void) = ^(void) {
s_ctx.m_windowAlloc.alloc();
NSRect rect = NSMakeRect(_x, _y, _width, _height);
NSWindow* window = [[NSWindow alloc]
initWithContentRect:rect
styleMask:s_ctx.m_style
backing:NSBackingStoreBuffered defer:NO
];
NSString* appName = [NSString stringWithUTF8String:_title];
[window setTitle:appName];
[window makeKeyAndOrderFront:window];
[window setAcceptsMouseMovedEvents:YES];
[window setBackgroundColor:[NSColor blackColor]];
[[Window sharedDelegate] windowCreated:window];
s_ctx.m_window[handleIdx] = window;
if(s_ctx.m_windowsCreated > 1)
{
void (^createWindowBlock)(void) = ^(void) {
NSRect rect = NSMakeRect(_x, _y, _width, _height);
NSWindow* window = [[NSWindow alloc]
initWithContentRect:rect
styleMask:s_ctx.m_style
backing:NSBackingStoreBuffered defer:NO
];
NSString* appName = [NSString stringWithUTF8String:_title];
[window setTitle:appName];
[window makeKeyAndOrderFront:window];
[window setAcceptsMouseMovedEvents:YES];
[window setBackgroundColor:[NSColor blackColor]];
[[Window sharedDelegate] windowCreated:window];
s_ctx.m_window[handle.idx] = window;
s_ctx.m_eventQueue.postSizeEvent(handle, _width, _height);
s_ctx.m_eventQueue.postWindowEvent(handle, window);
}
};
};
if ([NSThread isMainThread])
{
createWindowBlock();
}
else
{
dispatch_async(dispatch_get_main_queue(), createWindowBlock);
if ([NSThread isMainThread])
{
createWindowBlock();
}
else
{
dispatch_async(dispatch_get_main_queue(), createWindowBlock);
}
}
return handle;
}
void destroyWindow(WindowHandle _handle, bool _closeWindow)
{
if (isValid(_handle))
{
dispatch_async(dispatch_get_main_queue(), ^(void)
{
NSWindow *window = s_ctx.m_window[_handle.idx];
if ( NULL != window)
{
s_ctx.m_eventQueue.postWindowEvent(_handle);
s_ctx.m_window[_handle.idx] = NULL;
if ( _closeWindow )
{
[window close];
}
if (0 == _handle.idx)
{
[NSApp terminate:nil];
}
}
});
bx::MutexScope scope(s_ctx.m_lock);
s_ctx.m_windowAlloc.free(_handle.idx);
}
}
void destroyWindow(WindowHandle _handle)
{
if (s_ctx.isValid(_handle) )
{
dispatch_async(dispatch_get_main_queue()
, ^{
[s_ctx.m_window[_handle.idx] performClose: nil];
});
}
destroyWindow(_handle, true);
}
void setWindowPos(WindowHandle _handle, int32_t _x, int32_t _y)
{
if (s_ctx.isValid(_handle) )
{
NSWindow* window = s_ctx.m_window[_handle.idx];
NSScreen* screen = [window screen];
NSRect screenRect = [screen frame];
CGFloat menuBarHeight = [[[NSApplication sharedApplication] mainMenu] menuBarHeight];
NSPoint position = { float(_x), screenRect.size.height - menuBarHeight - float(_y) };
dispatch_async(dispatch_get_main_queue()
, ^{
[window setFrameTopLeftPoint: position];
});
}
dispatch_async(dispatch_get_main_queue()
, ^{
NSWindow* window = s_ctx.m_window[_handle.idx];
NSScreen* screen = [window screen];
NSRect screenRect = [screen frame];
CGFloat menuBarHeight = [[[NSApplication sharedApplication] mainMenu] menuBarHeight];
NSPoint position = { float(_x), screenRect.size.height - menuBarHeight - float(_y) };
[window setFrameTopLeftPoint: position];
});
}
void setWindowSize(WindowHandle _handle, uint32_t _width, uint32_t _height)
{
if (s_ctx.isValid(_handle) )
{
NSSize size = { float(_width), float(_height) };
dispatch_async(dispatch_get_main_queue()
, ^{
[s_ctx.m_window[_handle.idx] setContentSize: size];
});
}
NSSize size = { float(_width), float(_height) };
dispatch_async(dispatch_get_main_queue()
, ^{
[s_ctx.m_window[_handle.idx] setContentSize: size];
});
}
void setWindowTitle(WindowHandle _handle, const char* _title)
{
if (s_ctx.isValid(_handle) )
{
NSString* title = [[NSString alloc] initWithCString:_title encoding:1];
dispatch_async(dispatch_get_main_queue()
, ^{
[s_ctx.m_window[_handle.idx] setTitle: title];
});
[title release];
}
NSString* title = [[NSString alloc] initWithCString:_title encoding:1];
dispatch_async(dispatch_get_main_queue()
, ^{
[s_ctx.m_window[_handle.idx] setTitle: title];
[title release];
});
}
void setWindowFlags(WindowHandle _handle, uint32_t _flags, bool _enabled)
@ -641,37 +657,32 @@ namespace entry
void toggleFullscreen(WindowHandle _handle)
{
if (s_ctx.isValid(_handle) )
{
NSWindow* window = s_ctx.m_window[_handle.idx];
NSScreen* screen = [window screen];
NSRect screenRect = [screen frame];
if (!s_ctx.m_fullscreen)
{
s_ctx.m_style &= ~NSWindowStyleMaskTitled;
dispatch_async(dispatch_get_main_queue()
, ^{
[NSMenu setMenuBarVisible: false];
[window setStyleMask: s_ctx.m_style];
[window setFrame:screenRect display:YES];
});
s_ctx.m_fullscreen = true;
}
else
{
s_ctx.m_style |= NSWindowStyleMaskTitled;
dispatch_async(dispatch_get_main_queue()
, ^{
[NSMenu setMenuBarVisible: true];
[window setStyleMask: s_ctx.m_style];
[window setFrame:s_ctx.m_windowFrame display:YES];
});
s_ctx.m_fullscreen = false;
}
}
dispatch_async(dispatch_get_main_queue()
, ^{
NSWindow* window = s_ctx.m_window[_handle.idx];
NSScreen* screen = [window screen];
NSRect screenRect = [screen frame];
if (!s_ctx.m_fullscreen)
{
s_ctx.m_style &= ~NSWindowStyleMaskTitled;
s_ctx.m_fullscreen = true;
[NSMenu setMenuBarVisible: false];
[window setStyleMask: s_ctx.m_style];
[window setFrame:screenRect display:YES];
}
else
{
s_ctx.m_style |= NSWindowStyleMaskTitled;
s_ctx.m_fullscreen = false;
[NSMenu setMenuBarVisible: true];
[window setStyleMask: s_ctx.m_style];
[window setFrame:s_ctx.m_windowFrame display:YES];
}
});
}
void setMouseLock(WindowHandle _handle, bool _lock)
@ -732,7 +743,6 @@ namespace entry
return nil;
}
self->windowCount = 0;
return self;
}
@ -741,31 +751,21 @@ namespace entry
assert(window);
[window setDelegate:self];
assert(self->windowCount < ~0u);
self->windowCount += 1;
}
- (void)windowWillClose:(NSNotification*)notification
{
BX_UNUSED(notification);
NSWindow *window = [notification object];
[window setDelegate:nil];
destroyWindow(entry::s_ctx.findHandle(window), false);
}
- (BOOL)windowShouldClose:(NSWindow*)window
{
assert(window);
[window setDelegate:nil];
assert(self->windowCount);
self->windowCount -= 1;
if (self->windowCount == 0)
{
[NSApp terminate:self];
return false;
}
return true;
}

View File

@ -1004,6 +1004,7 @@ namespace bgfx { namespace mtl
SwapChainMtl()
: m_metalLayer(nil)
, m_drawable(nil)
, m_drawableTexture(nil)
, m_backBufferColorMsaa()
, m_backBufferDepth()
, m_backBufferStencil()
@ -1016,10 +1017,11 @@ namespace bgfx { namespace mtl
void init(void* _nwh);
void resize(FrameBufferMtl &_frameBuffer, uint32_t _width, uint32_t _height, uint32_t _flags);
id<CAMetalDrawable> currentDrawable();
id <MTLTexture> currentDrawableTexture();
CAMetalLayer* m_metalLayer;
id <CAMetalDrawable> m_drawable;
id <MTLTexture> m_drawableTexture;
Texture m_backBufferColorMsaa;
Texture m_backBufferDepth;
Texture m_backBufferStencil;

View File

@ -358,6 +358,7 @@ namespace bgfx { namespace mtl
, m_captureSize(0)
, m_saveScreenshot(false)
{
bx::memSet(&m_windows, 0xff, sizeof(m_windows) );
}
~RendererContextMtl()
@ -1186,10 +1187,15 @@ namespace bgfx { namespace mtl
{
FrameBufferMtl& frameBuffer = ii == 0 ? m_mainFrameBuffer : m_frameBuffers[m_windows[ii].idx];
if (NULL != frameBuffer.m_swapChain
&& frameBuffer.m_swapChain->m_drawable)
&& frameBuffer.m_swapChain->m_drawableTexture)
{
m_commandBuffer.presentDrawable(frameBuffer.m_swapChain->m_drawable);
MTL_RELEASE(frameBuffer.m_swapChain->m_drawable);
MTL_RELEASE(frameBuffer.m_swapChain->m_drawableTexture);
if ( NULL != frameBuffer.m_swapChain->m_drawable)
{
m_commandBuffer.presentDrawable(frameBuffer.m_swapChain->m_drawable);
MTL_RELEASE(frameBuffer.m_swapChain->m_drawable);
}
}
}
@ -1600,14 +1606,14 @@ namespace bgfx { namespace mtl
_renderPassDescriptor.colorAttachments[0].texture = swapChain->m_backBufferColorMsaa;
_renderPassDescriptor.colorAttachments[0].resolveTexture = NULL != m_screenshotTarget
? m_screenshotTarget.m_obj
: swapChain->currentDrawable().texture
: swapChain->currentDrawableTexture()
;
}
else
{
_renderPassDescriptor.colorAttachments[0].texture = NULL != m_screenshotTarget
? m_screenshotTarget.m_obj
: swapChain->currentDrawable().texture
: swapChain->currentDrawableTexture()
;
}
@ -1941,7 +1947,7 @@ namespace bgfx { namespace mtl
? swapChain->m_backBufferColorMsaa.sampleCount()
: 1
;
pd.colorAttachments[0].pixelFormat = swapChain->currentDrawable().texture.pixelFormat;
pd.colorAttachments[0].pixelFormat = swapChain->currentDrawableTexture().pixelFormat;
pd.depthAttachmentPixelFormat = swapChain->m_backBufferDepth.m_obj.pixelFormat;
pd.stencilAttachmentPixelFormat = swapChain->m_backBufferStencil.m_obj.pixelFormat;
}
@ -2308,7 +2314,6 @@ namespace bgfx { namespace mtl
SamplerDescriptor m_samplerDescriptor;
// currently active objects data
id <CAMetalDrawable> m_drawable;
bool m_saveScreenshot;
Texture m_screenshotTarget;
ShaderMtl m_screenshotBlitProgramVsh;
@ -2932,11 +2937,9 @@ namespace bgfx { namespace mtl
SwapChainMtl::~SwapChainMtl()
{
if (NULL != m_drawable)
{
release(m_drawable);
m_drawable = NULL;
}
MTL_RELEASE(m_metalLayer);
MTL_RELEASE(m_drawable);
MTL_RELEASE(m_drawableTexture);
MTL_RELEASE(m_backBufferDepth);
MTL_RELEASE(m_backBufferStencil);
@ -3010,6 +3013,8 @@ namespace bgfx { namespace mtl
m_metalLayer.device = s_renderMtl->m_device;
m_metalLayer.pixelFormat = MTLPixelFormatBGRA8Unorm;
m_metalLayer.magnificationFilter = kCAFilterNearest;
retain(m_metalLayer);
}
void SwapChainMtl::resize(FrameBufferMtl &_frameBuffer, uint32_t _width, uint32_t _height, uint32_t _flags)
@ -3097,16 +3102,47 @@ namespace bgfx { namespace mtl
murmur.add( (uint32_t)sampleCount);
_frameBuffer.m_pixelFormatHash = murmur.end();
}
id<CAMetalDrawable> SwapChainMtl::currentDrawable()
id <MTLTexture> SwapChainMtl::currentDrawableTexture()
{
if (NULL == m_drawable)
if (NULL == m_drawableTexture)
{
m_drawable = m_metalLayer.nextDrawable;
retain(m_drawable); // keep alive to be useable at 'flip'
if (m_drawable != NULL)
{
m_drawableTexture = m_drawable.texture;
retain(m_drawableTexture);
retain(m_drawable); // keep alive to be useable at 'flip'
}
else
{
TextureDescriptor desc = s_renderMtl->m_textureDescriptor;
desc.textureType = MTLTextureType2D;
desc.pixelFormat = m_metalLayer.pixelFormat;
desc.width = m_metalLayer.drawableSize.width;
desc.height = m_metalLayer.drawableSize.height;
desc.depth = 1;
desc.mipmapLevelCount = 1;
desc.sampleCount = 1;
desc.arrayLength = 1;
if (s_renderMtl->m_iOS9Runtime
|| s_renderMtl->m_macOS11Runtime)
{
desc.cpuCacheMode = MTLCPUCacheModeDefaultCache;
desc.storageMode = BX_ENABLED(BX_PLATFORM_IOS)
? (MTLStorageMode)0 // MTLStorageModeShared
: (MTLStorageMode)1 // MTLStorageModeManaged
;
desc.usage = MTLTextureUsageRenderTarget;
}
m_drawableTexture = s_renderMtl->m_device.newTextureWithDescriptor(desc);
}
}
return m_drawable;
return m_drawableTexture;
}
void FrameBufferMtl::create(uint8_t _num, const Attachment* _attachment)
@ -4570,7 +4606,7 @@ namespace bgfx { namespace mtl
if (m_screenshotTarget)
{
RenderPassDescriptor renderPassDescriptor = newRenderPassDescriptor();
renderPassDescriptor.colorAttachments[0].texture = m_mainFrameBuffer.m_swapChain->currentDrawable().texture;
renderPassDescriptor.colorAttachments[0].texture = m_mainFrameBuffer.m_swapChain->currentDrawableTexture();
renderPassDescriptor.colorAttachments[0].storeAction = MTLStoreActionStore;
rce = m_commandBuffer.renderCommandEncoderWithDescriptor(renderPassDescriptor);