diff --git a/examples/common/entry/entry_osx.mm b/examples/common/entry/entry_osx.mm index 49a0a05c9..c3d6e3282 100644 --- a/examples/common/entry/entry_osx.mm +++ b/examples/common/entry/entry_osx.mm @@ -30,7 +30,6 @@ @interface Window : NSObject { - 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 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; } diff --git a/src/renderer_mtl.h b/src/renderer_mtl.h index c0109fbde..eb1589c66 100644 --- a/src/renderer_mtl.h +++ b/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 currentDrawable(); + id currentDrawableTexture(); CAMetalLayer* m_metalLayer; id m_drawable; + id m_drawableTexture; Texture m_backBufferColorMsaa; Texture m_backBufferDepth; Texture m_backBufferStencil; diff --git a/src/renderer_mtl.mm b/src/renderer_mtl.mm index 83aeb7960..66ef8c5e4 100644 --- a/src/renderer_mtl.mm +++ b/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 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 SwapChainMtl::currentDrawable() + + id 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);