Browse Source

Fixed osx multiple window create/destroy

Attila Kocsis 6 years ago
parent
commit
8196612195
3 changed files with 200 additions and 162 deletions
  1. 143 143
      examples/common/entry/entry_osx.mm
  2. 3 1
      src/renderer_mtl.h
  3. 54 18
      src/renderer_mtl.mm

+ 143 - 143
examples/common/entry/entry_osx.mm

@@ -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)
+	void destroyWindow(WindowHandle _handle, bool _closeWindow)
 	{
-		if (s_ctx.isValid(_handle) )
+		if (isValid(_handle))
 		{
-			dispatch_async(dispatch_get_main_queue()
-			, ^{
-				[s_ctx.m_window[_handle.idx] performClose: nil];
-			});
+			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)
+	{
+		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;
 }
 

+ 3 - 1
src/renderer_mtl.h

@@ -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;

+ 54 - 18
src/renderer_mtl.mm

@@ -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);