From f796d664079b3ee59f0a3de8a277e0f73e96648f Mon Sep 17 00:00:00 2001 From: Jack Andersen Date: Sat, 31 Oct 2015 14:06:56 -1000 Subject: [PATCH] All kinds of fixes and updates --- CMakeLists.txt | 3 +- include/boo/IApplication.hpp | 40 +-- include/boo/graphicsdev/GL.hpp | 9 +- .../boo/graphicsdev/IGraphicsDataFactory.hpp | 5 +- lib/graphicsdev/GL.cpp | 48 ++- lib/graphicsdev/glew.c | 6 +- lib/inputdev/HIDListenerIOKit.cpp | 2 +- lib/mac/ApplicationCocoa.mm | 280 ++++++++++-------- lib/mac/WindowCocoa.mm | 209 +++++++++---- test/main.cpp | 26 +- 10 files changed, 385 insertions(+), 243 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 732e947..e28f40c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -34,7 +34,8 @@ elseif(APPLE) find_library(APPKIT_LIBRARY AppKit) find_library(IOKIT_LIBRARY IOKit) find_library(OPENGL_LIBRARY OpenGL) - list(APPEND _BOO_SYS_LIBS ${APPKIT_LIBRARY} ${IOKIT_LIBRARY} ${OPENGL_LIBRARY}) + find_library(COREVIDEO_LIBRARY CoreVideo) + list(APPEND _BOO_SYS_LIBS ${APPKIT_LIBRARY} ${IOKIT_LIBRARY} ${OPENGL_LIBRARY} ${COREVIDEO_LIBRARY}) else() list(APPEND PLAT_SRCS lib/x11/ApplicationUnix.cpp diff --git a/include/boo/IApplication.hpp b/include/boo/IApplication.hpp index 574bf04..924789a 100644 --- a/include/boo/IApplication.hpp +++ b/include/boo/IApplication.hpp @@ -14,8 +14,8 @@ class IApplication; struct IApplicationCallback { - virtual int appMain(IApplication*) {return 0;} - virtual void appQuitting(IApplication*) {} + virtual int appMain(IApplication*)=0; + virtual void appQuitting(IApplication*)=0; virtual void appFilesOpen(IApplication*, const std::vector&) {} }; @@ -51,34 +51,34 @@ public: virtual const std::vector& getArgs() const=0; /* Constructors/initializers for sub-objects */ - virtual std::unique_ptr newWindow(const SystemString& title)=0; + virtual IWindow* newWindow(const SystemString& title)=0; }; -std::unique_ptr -ApplicationBootstrap(IApplication::EPlatformType platform, - IApplicationCallback& cb, - const SystemString& uniqueName, - const SystemString& friendlyName, - const SystemString& pname, - const std::vector& args, - bool singleInstance=true); +int +ApplicationRun(IApplication::EPlatformType platform, + IApplicationCallback& cb, + const SystemString& uniqueName, + const SystemString& friendlyName, + const SystemString& pname, + const std::vector& args, + bool singleInstance=true); extern IApplication* APP; -static inline std::unique_ptr -ApplicationBootstrap(IApplication::EPlatformType platform, - IApplicationCallback& cb, - const SystemString& uniqueName, - const SystemString& friendlyName, - int argc, const SystemChar** argv, - bool singleInstance=true) +static inline int +ApplicationRun(IApplication::EPlatformType platform, + IApplicationCallback& cb, + const SystemString& uniqueName, + const SystemString& friendlyName, + int argc, const SystemChar** argv, + bool singleInstance=true) { if (APP) - return std::unique_ptr(); + return 1; std::vector args; for (int i=1 ; i +#include namespace boo { @@ -13,9 +14,11 @@ namespace boo class GLES3DataFactory : public IGraphicsDataFactory { IGraphicsContext* m_parent; - std::unique_ptr m_deferredData; + IGraphicsData* m_deferredData = nullptr; + std::unordered_set m_committedData; public: GLES3DataFactory(IGraphicsContext* parent); + ~GLES3DataFactory() {} Platform platform() const {return PlatformOGLES3;} const char* platformName() const {return "OpenGL ES 3.0";} @@ -42,7 +45,9 @@ public: size_t texCount, const ITexture** texs); void reset(); - std::unique_ptr commit(); + IGraphicsData* commit(); + void destroyData(IGraphicsData*); + void destroyAllData(); }; } diff --git a/include/boo/graphicsdev/IGraphicsDataFactory.hpp b/include/boo/graphicsdev/IGraphicsDataFactory.hpp index 83c7c0e..52c89fc 100644 --- a/include/boo/graphicsdev/IGraphicsDataFactory.hpp +++ b/include/boo/graphicsdev/IGraphicsDataFactory.hpp @@ -115,7 +115,6 @@ struct IShaderDataBinding {}; * resource batch. */ struct IGraphicsData { - virtual ~IGraphicsData() {} }; /** Used by platform shader pipeline constructors */ @@ -173,7 +172,9 @@ struct IGraphicsDataFactory size_t texCount, const ITexture** texs)=0; virtual void reset()=0; - virtual std::unique_ptr commit()=0; + virtual IGraphicsData* commit()=0; + virtual void destroyData(IGraphicsData*)=0; + virtual void destroyAllData()=0; }; } diff --git a/lib/graphicsdev/GL.cpp b/lib/graphicsdev/GL.cpp index a7ca0e9..6208991 100644 --- a/lib/graphicsdev/GL.cpp +++ b/lib/graphicsdev/GL.cpp @@ -85,7 +85,7 @@ const IGraphicsBufferS* GLES3DataFactory::newStaticBuffer(BufferUse use, const void* data, size_t sz) { GLES3GraphicsBufferS* retval = new GLES3GraphicsBufferS(use, data, sz); - static_cast(m_deferredData.get())->m_SBufs.emplace_back(retval); + static_cast(m_deferredData)->m_SBufs.emplace_back(retval); return retval; } @@ -99,6 +99,11 @@ class GLES3TextureS : ITextureS const uint8_t* dataIt = static_cast(data); glGenTextures(1, &m_tex); glBindTexture(GL_TEXTURE_2D, m_tex); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + if (mips > 1) + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); + else + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); if (fmt == TextureFormatRGBA8) { for (size_t i=0 ; i(m_deferredData.get())->m_STexs.emplace_back(retval); + static_cast(m_deferredData)->m_STexs.emplace_back(retval); return retval; } @@ -337,10 +342,12 @@ const IShaderPipeline* GLES3DataFactory::newShaderPipeline GLint loc; if ((loc = glGetUniformLocation(shader.m_prog, texNames[i])) >= 0) glUniform1i(loc, i); + else + Log.report(LogVisor::FatalError, "unable to find sampler variable '%s'", texNames[i]); } GLES3ShaderPipeline* retval = new GLES3ShaderPipeline(std::move(shader)); - static_cast(m_deferredData.get())->m_SPs.emplace_back(retval); + static_cast(m_deferredData)->m_SPs.emplace_back(retval); return retval; } @@ -403,7 +410,7 @@ GLES3DataFactory::newShaderDataBinding(const IShaderPipeline* pipeline, { GLES3ShaderDataBinding* retval = new GLES3ShaderDataBinding(pipeline, vtxFormat, ubufCount, ubufs, texCount, texs); - static_cast(m_deferredData.get())->m_SBinds.emplace_back(retval); + static_cast(m_deferredData)->m_SBinds.emplace_back(retval); return retval; } @@ -412,15 +419,31 @@ GLES3DataFactory::GLES3DataFactory(IGraphicsContext* parent) void GLES3DataFactory::reset() { - m_deferredData.reset(new struct GLES3Data()); + delete static_cast(m_deferredData); + m_deferredData = new struct GLES3Data(); } -std::unique_ptr GLES3DataFactory::commit() +IGraphicsData* GLES3DataFactory::commit() { - std::unique_ptr retval(new struct GLES3Data()); - m_deferredData.swap(retval); + IGraphicsData* retval = m_deferredData; + m_deferredData = new struct GLES3Data(); + m_committedData.insert(retval); return retval; } + +void GLES3DataFactory::destroyData(IGraphicsData* d) +{ + GLES3Data* data = static_cast(d); + m_committedData.erase(data); + delete data; +} + +void GLES3DataFactory::destroyAllData() +{ + for (IGraphicsData* data : m_committedData) + delete static_cast(data); + m_committedData.clear(); +} static const GLint SEMANTIC_COUNT_TABLE[] = { @@ -533,6 +556,7 @@ struct GLES3CommandQueue : IGraphicsCommandQueue lastEBO = desc->indexBuffer; lastEBO->bindIndex(); } + glEnableVertexAttribArray(i); glVertexAttribPointer(i, SEMANTIC_COUNT_TABLE[desc->semantic], SEMANTIC_TYPE_TABLE[desc->semantic], GL_TRUE, stride, (void*)offset); offset += SEMANTIC_SIZE_TABLE[desc->semantic]; @@ -726,7 +750,7 @@ struct GLES3CommandQueue : IGraphicsCommandQueue std::vector& cmds = m_cmdBufs[m_fillBuf]; cmds.emplace_back(Command::OpPresent); } - + void addVertexFormat(GLES3VertexFormat* fmt) { std::unique_lock lk(m_mt); @@ -800,7 +824,7 @@ GLES3DataFactory::newDynamicBuffer(BufferUse use) { GLES3CommandQueue* q = static_cast(m_parent->getCommandQueue()); GLES3GraphicsBufferD* retval = new GLES3GraphicsBufferD(q, use); - static_cast(m_deferredData.get())->m_DBufs.emplace_back(retval); + static_cast(m_deferredData)->m_DBufs.emplace_back(retval); return retval; } @@ -823,7 +847,7 @@ GLES3DataFactory::newDynamicTexture(size_t width, size_t height, TextureFormat f { GLES3CommandQueue* q = static_cast(m_parent->getCommandQueue()); GLES3TextureD* retval = new GLES3TextureD(q, width, height, fmt); - static_cast(m_deferredData.get())->m_DTexs.emplace_back(retval); + static_cast(m_deferredData)->m_DTexs.emplace_back(retval); return retval; } @@ -844,7 +868,7 @@ const IVertexFormat* GLES3DataFactory::newVertexFormat { GLES3CommandQueue* q = static_cast(m_parent->getCommandQueue()); GLES3VertexFormat* retval = new struct GLES3VertexFormat(q, elementCount, elements); - static_cast(m_deferredData.get())->m_VFmts.emplace_back(retval); + static_cast(m_deferredData)->m_VFmts.emplace_back(retval); return retval; } diff --git a/lib/graphicsdev/glew.c b/lib/graphicsdev/glew.c index 31c8a22..3ea70f8 100644 --- a/lib/graphicsdev/glew.c +++ b/lib/graphicsdev/glew.c @@ -30,12 +30,12 @@ ** THE POSSIBILITY OF SUCH DAMAGE. */ -#include +#include #if defined(_WIN32) -# include +# include #elif !defined(__ANDROID__) && !defined(__native_client__) && !defined(__HAIKU__) && (!defined(__APPLE__) || defined(GLEW_APPLE_GLX)) -# include +# include #endif #include /* For size_t */ diff --git a/lib/inputdev/HIDListenerIOKit.cpp b/lib/inputdev/HIDListenerIOKit.cpp index 9160b3b..0e01dc9 100644 --- a/lib/inputdev/HIDListenerIOKit.cpp +++ b/lib/inputdev/HIDListenerIOKit.cpp @@ -182,7 +182,7 @@ public: ~HIDListenerIOKit() { - CFRunLoopRemoveSource(m_listenerRunLoop, IONotificationPortGetRunLoopSource(m_llPort), kCFRunLoopDefaultMode); + //CFRunLoopRemoveSource(m_listenerRunLoop, IONotificationPortGetRunLoopSource(m_llPort), kCFRunLoopDefaultMode); IOObjectRelease(m_llAddNotif); IOObjectRelease(m_llRemoveNotif); IONotificationPortDestroy(m_llPort); diff --git a/lib/mac/ApplicationCocoa.mm b/lib/mac/ApplicationCocoa.mm index 940a22f..406cc25 100644 --- a/lib/mac/ApplicationCocoa.mm +++ b/lib/mac/ApplicationCocoa.mm @@ -1,82 +1,29 @@ #include +#include #include "boo/IApplication.hpp" +namespace boo {class ApplicationCocoa;} @interface AppDelegate : NSObject { - boo::IApplicationCallback* callback; + boo::ApplicationCocoa* m_app; @public NSPanel* aboutPanel; } -- (id)initWithCallback:(boo::IApplicationCallback*)cb; -@end - -@implementation AppDelegate -- (id)initWithCallback:(boo::IApplicationCallback*)cb -{ - self = [super init]; - callback = cb; - return self; -} -- (void)applicationDidFinishLaunching:(NSNotification*)notification -{ - (void)notification; - callback->appMain(boo::APP); -} -- (void)applicationWillTerminate:(NSNotification*)notification -{ - (void)notification; - callback->appQuitting(boo::APP); -} -- (BOOL)application:(NSApplication*)sender openFile:(NSString*)filename -{ - std::vector strVec; - strVec.push_back(boo::SystemString([filename UTF8String])); - callback->appFilesOpen(boo::APP, strVec); - return true; -} -- (void)application:(NSApplication*)sender openFiles:(NSArray*)filenames -{ - std::vector strVec; - strVec.reserve([filenames count]); - for (NSString* str in filenames) - strVec.push_back(boo::SystemString([str UTF8String])); - callback->appFilesOpen(boo::APP, strVec); -} -- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication*)sender { - (void)sender; - return YES; -} -- (IBAction)aboutApp:(id)sender -{ - (void)sender; - NSRect screenFrame = [[aboutPanel screen] frame]; - CGFloat xPos = NSWidth(screenFrame)/2 - 300/2; - CGFloat yPos = NSHeight(screenFrame)/2 - 220/2; - NSRect aboutCr = NSMakeRect(xPos, yPos, 300, 220); - [aboutPanel setFrame:aboutCr display:NO]; - [aboutPanel makeKeyAndOrderFront:self]; -} -- (IBAction)toggleFs:(id)sender -{ - (void)sender; - [[NSApp keyWindow] toggleFullScreen:nil]; -} -- (IBAction)quitApp:(id)sender -{ - (void)sender; - [NSApp terminate:nil]; -} +- (id)initWithApp:(boo::ApplicationCocoa*)app; @end namespace boo { -IWindow* _WindowCocoaNew(const SystemString& title); +IWindow* _WindowCocoaNew(const SystemString& title, NSOpenGLContext* lastGLCtx); class ApplicationCocoa : public IApplication { +public: + NSApplication* m_app = nullptr; IApplicationCallback& m_callback; +private: const SystemString m_uniqueName; const SystemString m_friendlyName; const SystemString m_pname; @@ -84,9 +31,12 @@ class ApplicationCocoa : public IApplication NSPanel* aboutPanel; + /* All windows */ + std::unordered_map m_windows; + void _deletedWindow(IWindow* window) { - (void)window; + m_windows.erase((NSWindow*)window->getPlatformHandle()); } public: @@ -101,49 +51,44 @@ public: m_pname(pname), m_args(args) { - @autoreleasepool - { - NSApplication* app = [NSApplication sharedApplication]; - [app setActivationPolicy:NSApplicationActivationPolicyRegular]; - - /* Delegate (OS X callbacks) */ - AppDelegate* appDelegate = [[AppDelegate alloc] initWithCallback:&m_callback]; - [app setDelegate:appDelegate]; - - /* App menu */ - NSMenu* appMenu = [[NSMenu alloc] initWithTitle:@"main"]; - NSMenu* rwkMenu = [[NSMenu alloc] initWithTitle:[[NSString stringWithUTF8String:m_friendlyName.c_str()] autorelease]]; - [rwkMenu addItemWithTitle:[[NSString stringWithFormat:@"About %s", m_friendlyName.c_str()] autorelease] - action:@selector(aboutApp:) - keyEquivalent:@""]; - NSMenuItem* fsItem = [rwkMenu addItemWithTitle:@"Toggle Full Screen" - action:@selector(toggleFs:) - keyEquivalent:@"f"]; - [fsItem setKeyEquivalentModifierMask:NSCommandKeyMask]; - [rwkMenu addItem:[NSMenuItem separatorItem]]; - NSMenuItem* quit_item = [rwkMenu addItemWithTitle:[[NSString stringWithFormat:@"Quit %s", m_friendlyName.c_str()] autorelease] - action:@selector(quitApp:) - keyEquivalent:@"q"]; - [quit_item setKeyEquivalentModifierMask:NSCommandKeyMask]; - [[appMenu addItemWithTitle:[[NSString stringWithUTF8String:m_friendlyName.c_str()] autorelease] - action:nil keyEquivalent:@""] setSubmenu:rwkMenu]; - [[NSApplication sharedApplication] setMainMenu:appMenu]; - - /* About panel */ - NSRect aboutCr = NSMakeRect(0, 0, 300, 220); - aboutPanel = [[NSPanel alloc] initWithContentRect:aboutCr - styleMask:NSUtilityWindowMask|NSTitledWindowMask|NSClosableWindowMask - backing:NSBackingStoreBuffered defer:YES]; - [aboutPanel setTitle:[[NSString stringWithFormat:@"About %s", m_friendlyName.c_str()] autorelease]]; - NSText* aboutText = [[NSText alloc] initWithFrame:aboutCr]; - [aboutText setEditable:NO]; - [aboutText setAlignment:NSCenterTextAlignment]; - [aboutText setString:@"\nRWK Authors\n\nJackoalan\nAntidote\n"]; - [aboutPanel setContentView:aboutText]; - appDelegate->aboutPanel = aboutPanel; - - [app run]; - } + m_app = [NSApplication sharedApplication]; + [m_app setActivationPolicy:NSApplicationActivationPolicyRegular]; + + /* Delegate (OS X callbacks) */ + AppDelegate* appDelegate = [[AppDelegate alloc] initWithApp:this]; + [m_app setDelegate:appDelegate]; + + /* App menu */ + NSMenu* appMenu = [[NSMenu alloc] initWithTitle:@"main"]; + NSMenu* rwkMenu = [[NSMenu alloc] initWithTitle:[[NSString stringWithUTF8String:m_friendlyName.c_str()] autorelease]]; + [rwkMenu addItemWithTitle:[[NSString stringWithFormat:@"About %s", m_friendlyName.c_str()] autorelease] + action:@selector(aboutApp:) + keyEquivalent:@""]; + NSMenuItem* fsItem = [rwkMenu addItemWithTitle:@"Toggle Full Screen" + action:@selector(toggleFs:) + keyEquivalent:@"f"]; + [fsItem setKeyEquivalentModifierMask:NSCommandKeyMask]; + [rwkMenu addItem:[NSMenuItem separatorItem]]; + NSMenuItem* quit_item = [rwkMenu addItemWithTitle:[[NSString stringWithFormat:@"Quit %s", m_friendlyName.c_str()] autorelease] + action:@selector(quitApp:) + keyEquivalent:@"q"]; + [quit_item setKeyEquivalentModifierMask:NSCommandKeyMask]; + [[appMenu addItemWithTitle:[[NSString stringWithUTF8String:m_friendlyName.c_str()] autorelease] + action:nil keyEquivalent:@""] setSubmenu:rwkMenu]; + [[NSApplication sharedApplication] setMainMenu:appMenu]; + + /* About panel */ + NSRect aboutCr = NSMakeRect(0, 0, 300, 220); + aboutPanel = [[NSPanel alloc] initWithContentRect:aboutCr + styleMask:NSUtilityWindowMask|NSTitledWindowMask|NSClosableWindowMask + backing:NSBackingStoreBuffered defer:YES]; + [aboutPanel setTitle:[[NSString stringWithFormat:@"About %s", m_friendlyName.c_str()] autorelease]]; + NSText* aboutText = [[NSText alloc] initWithFrame:aboutCr]; + [aboutText setEditable:NO]; + [aboutText setAlignment:NSCenterTextAlignment]; + [aboutText setString:@"\nRWK Authors\n\nJackoalan\nAntidote\n"]; + [aboutPanel setContentView:aboutText]; + appDelegate->aboutPanel = aboutPanel; } EPlatformType getPlatformType() const @@ -151,9 +96,23 @@ public: return PLAT_COCOA; } - void pump() + std::thread m_clientThread; + int m_clientReturn = 0; + int run() { - + /* Spawn client thread */ + m_clientThread = std::thread([&]() + { + /* Run app */ + m_clientReturn = m_callback.appMain(this); + + /* Cleanup here */ + for (auto& window : m_windows) + delete window.second; + }); + + /* Already in Cocoa's event loop; return now */ + return 0; } void quit() @@ -183,27 +142,102 @@ public: IWindow* newWindow(const std::string& title) { - return _WindowCocoaNew(title); + IWindow* newWindow = _WindowCocoaNew(title, m_lastGLCtx); + m_windows[(NSWindow*)newWindow->getPlatformHandle()] = newWindow; + return newWindow; } + + /* Last GL context */ + NSOpenGLContext* m_lastGLCtx = nullptr; }; - -IApplication* APP = NULL; -std::unique_ptr ApplicationBootstrap(IApplication::EPlatformType platform, - IApplicationCallback& cb, - const SystemString& uniqueName, - const SystemString& friendlyName, - const SystemString& pname, - const std::vector& args, - bool singleInstance) + +void _CocoaUpdateLastGLCtx(NSOpenGLContext* lastGLCtx) { - if (!APP) + static_cast(APP)->m_lastGLCtx = lastGLCtx; +} + +IApplication* APP = nullptr; +int ApplicationRun(IApplication::EPlatformType platform, + IApplicationCallback& cb, + const SystemString& uniqueName, + const SystemString& friendlyName, + const SystemString& pname, + const std::vector& args, + bool singleInstance) +{ + @autoreleasepool { - if (platform != IApplication::PLAT_COCOA && - platform != IApplication::PLAT_AUTO) - return NULL; - APP = new ApplicationCocoa(cb, uniqueName, friendlyName, pname, args); + if (!APP) + { + if (platform != IApplication::PLAT_COCOA && + platform != IApplication::PLAT_AUTO) + return 1; + APP = new ApplicationCocoa(cb, uniqueName, friendlyName, pname, args); + } + [static_cast(APP)->m_app run]; + return static_cast(APP)->m_clientReturn; } - return std::unique_ptr(APP); } } + +@implementation AppDelegate +- (id)initWithApp:(boo::ApplicationCocoa*)app +{ + self = [super init]; + m_app = app; + return self; +} +- (void)applicationDidFinishLaunching:(NSNotification*)notification +{ + (void)notification; + m_app->run(); +} +- (void)applicationWillTerminate:(NSNotification*)notification +{ + (void)notification; + m_app->m_callback.appQuitting(m_app); + m_app->m_clientThread.join(); +} +- (BOOL)application:(NSApplication*)sender openFile:(NSString*)filename +{ + std::vector strVec; + strVec.push_back(boo::SystemString([filename UTF8String])); + m_app->m_callback.appFilesOpen(boo::APP, strVec); + return true; +} +- (void)application:(NSApplication*)sender openFiles:(NSArray*)filenames +{ + std::vector strVec; + strVec.reserve([filenames count]); + for (NSString* str in filenames) + strVec.push_back(boo::SystemString([str UTF8String])); + m_app->m_callback.appFilesOpen(boo::APP, strVec); +} +- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication*)sender +{ + (void)sender; + return YES; +} +- (IBAction)aboutApp:(id)sender +{ + (void)sender; + NSRect screenFrame = [[aboutPanel screen] frame]; + CGFloat xPos = NSWidth(screenFrame)/2 - 300/2; + CGFloat yPos = NSHeight(screenFrame)/2 - 220/2; + NSRect aboutCr = NSMakeRect(xPos, yPos, 300, 220); + [aboutPanel setFrame:aboutCr display:NO]; + [aboutPanel makeKeyAndOrderFront:self]; +} +- (IBAction)toggleFs:(id)sender +{ + (void)sender; + [[NSApp keyWindow] toggleFullScreen:nil]; +} +- (IBAction)quitApp:(id)sender +{ + (void)sender; + [NSApp terminate:nil]; +} +@end + diff --git a/lib/mac/WindowCocoa.mm b/lib/mac/WindowCocoa.mm index 896c516..9f62b34 100644 --- a/lib/mac/WindowCocoa.mm +++ b/lib/mac/WindowCocoa.mm @@ -1,10 +1,12 @@ +#include "boo/graphicsdev/GL.hpp" #import -#include -#include +#import #include "boo/IApplication.hpp" #include "boo/IWindow.hpp" #include "boo/IGraphicsContext.hpp" +#include + namespace boo {class WindowCocoa;} @interface WindowCocoaInternal : NSWindow { @@ -81,32 +83,42 @@ namespace boo {class GraphicsContextCocoa;} namespace boo { - +static LogVisor::LogModule Log("boo::WindowCocoa"); +IGraphicsCommandQueue* _NewGLES3CommandQueue(IGraphicsContext* parent); +void _CocoaUpdateLastGLCtx(NSOpenGLContext* lastGLCtx); + class GraphicsContextCocoa : public IGraphicsContext { EGraphicsAPI m_api; EPixelFormat m_pf; IWindow* m_parentWindow; - GraphicsContextCocoaInternal* m_nsContext; - NSOpenGLContext* m_nsShareContext; + GraphicsContextCocoaInternal* m_nsContext = nullptr; + + IGraphicsCommandQueue* m_commandQueue = nullptr; + IGraphicsDataFactory* m_dataFactory = nullptr; + NSOpenGLContext* m_loadCtx = nullptr; + CVDisplayLinkRef m_dispLink = nullptr; public: - IWindowCallback* m_callback; + NSOpenGLContext* m_lastCtx = nullptr; + IWindowCallback* m_callback = nullptr; - GraphicsContextCocoa(EGraphicsAPI api, IWindow* parentWindow) + GraphicsContextCocoa(EGraphicsAPI api, IWindow* parentWindow, NSOpenGLContext* lastGLCtx) : m_api(api), m_pf(PF_RGBA8), m_parentWindow(parentWindow), - m_nsContext(NULL), - m_nsShareContext(NULL), - m_callback(NULL) + m_lastCtx(lastGLCtx) {} ~GraphicsContextCocoa() { + delete m_dataFactory; + delete m_commandQueue; [m_nsContext release]; - [m_nsShareContext release]; + [m_loadCtx release]; + CVDisplayLinkStop(m_dispLink); + CVDisplayLinkRelease(m_dispLink); } void _setCallback(IWindowCallback* cb) @@ -131,58 +143,83 @@ public: m_pf = pf; } - void initializeContext() + std::mutex m_dlmt; + std::condition_variable m_dlcv; + + static CVReturn DLCallback(CVDisplayLinkRef CV_NONNULL displayLink, + const CVTimeStamp * CV_NONNULL inNow, + const CVTimeStamp * CV_NONNULL inOutputTime, + CVOptionFlags flagsIn, + CVOptionFlags * CV_NONNULL flagsOut, + GraphicsContextCocoa* CV_NULLABLE ctx) { - if (m_nsShareContext) - return; - m_nsContext = [[GraphicsContextCocoaInternal alloc] initWithBooContext:this]; - [(NSWindow*)m_parentWindow->getPlatformHandle() setContentView:m_nsContext]; + ctx->m_dlcv.notify_one(); + return kCVReturnSuccess; } - IGraphicsContext* makeShareContext() const + void waitForRetrace() { - NSOpenGLContext* nsctx; - if (m_nsContext) - { - nsctx = [[NSOpenGLContext alloc] initWithFormat:[m_nsContext pixelFormat] - shareContext:[m_nsContext openGLContext]]; - } - else if (m_nsShareContext) - { - nsctx = [[NSOpenGLContext alloc] initWithFormat:[m_nsShareContext pixelFormat] - shareContext:m_nsShareContext]; - } - else - return NULL; - if (!nsctx) - return NULL; - GraphicsContextCocoa* newCtx = new GraphicsContextCocoa(m_api, NULL); - newCtx->m_nsShareContext = nsctx; - return newCtx; + std::unique_lock lk(m_dlmt); + m_dlcv.wait(lk); + } + + void initializeContext() + { + m_nsContext = [[GraphicsContextCocoaInternal alloc] initWithBooContext:this]; + if (!m_nsContext) + Log.report(LogVisor::FatalError, "unable to make new NSOpenGLView"); + [(NSWindow*)m_parentWindow->getPlatformHandle() setContentView:m_nsContext]; + CVDisplayLinkCreateWithActiveCGDisplays(&m_dispLink); + CVDisplayLinkSetOutputCallback(m_dispLink, (CVDisplayLinkOutputCallback)DLCallback, this); + CVDisplayLinkStart(m_dispLink); } void makeCurrent() { - if (m_nsContext) - [[m_nsContext openGLContext] makeCurrentContext]; - else if (m_nsShareContext) - [m_nsShareContext makeCurrentContext]; + [[m_nsContext openGLContext] makeCurrentContext]; } - void clearCurrent() + void postInit() { - [NSOpenGLContext clearCurrentContext]; } - void swapBuffer() + IGraphicsCommandQueue* getCommandQueue() + { + if (!m_commandQueue) + m_commandQueue = _NewGLES3CommandQueue(this); + return m_commandQueue; + } + + IGraphicsDataFactory* getDataFactory() + { + if (!m_dataFactory) + m_dataFactory = new GLES3DataFactory(this); + return m_dataFactory; + } + + IGraphicsDataFactory* getLoadContextDataFactory() + { + if (!m_loadCtx) + { + NSOpenGLPixelFormat* nspf = [[NSOpenGLPixelFormat alloc] initWithAttributes:PF_TABLE[m_pf]]; + m_loadCtx = [[NSOpenGLContext alloc] initWithFormat:nspf shareContext:[m_nsContext openGLContext]]; + [nspf release]; + if (!m_loadCtx) + Log.report(LogVisor::FatalError, "unable to make load NSOpenGLContext"); + [m_loadCtx makeCurrentContext]; + } + return getDataFactory(); + } + + void present() { [[m_nsContext openGLContext] flushBuffer]; } }; -IGraphicsContext* _CGraphicsContextCocoaNew(IGraphicsContext::EGraphicsAPI api, - IWindow* parentWindow) +IGraphicsContext* _GraphicsContextCocoaNew(IGraphicsContext::EGraphicsAPI api, + IWindow* parentWindow, NSOpenGLContext* lastGLCtx) { if (api != IGraphicsContext::API_OPENGL_3_3 && api != IGraphicsContext::API_OPENGL_4_2) return NULL; @@ -215,7 +252,7 @@ IGraphicsContext* _CGraphicsContextCocoaNew(IGraphicsContext::EGraphicsAPI api, if (api == IGraphicsContext::API_OPENGL_4_2) return NULL; - return new GraphicsContextCocoa(api, parentWindow); + return new GraphicsContextCocoa(api, parentWindow, lastGLCtx); } } @@ -228,6 +265,12 @@ IGraphicsContext* _CGraphicsContextCocoaNew(IGraphicsContext::EGraphicsAPI api, boo::IGraphicsContext::EPixelFormat pf = bctx->getPixelFormat(); NSOpenGLPixelFormat* nspf = [[NSOpenGLPixelFormat alloc] initWithAttributes:PF_TABLE[pf]]; self = [self initWithFrame:NSMakeRect(0, 0, 100, 100) pixelFormat:nspf]; + if (bctx->m_lastCtx) + { + NSOpenGLContext* sharedCtx = [[NSOpenGLContext alloc] initWithFormat:nspf shareContext:bctx->m_lastCtx]; + [self setOpenGLContext:sharedCtx]; + [sharedCtx setView:self]; + } [nspf release]; return self; } @@ -660,23 +703,26 @@ class WindowCocoa : public IWindow public: - WindowCocoa(const std::string& title) + WindowCocoa(const std::string& title, NSOpenGLContext* lastGLCtx) { - m_nsWindow = [[WindowCocoaInternal alloc] initWithBooWindow:this title:title]; - m_gfxCtx = _CGraphicsContextCocoaNew(IGraphicsContext::API_OPENGL_3_3, this); - m_gfxCtx->initializeContext(); + dispatch_sync(dispatch_get_main_queue(), + ^{ + m_nsWindow = [[WindowCocoaInternal alloc] initWithBooWindow:this title:title]; + m_gfxCtx = _GraphicsContextCocoaNew(IGraphicsContext::API_OPENGL_3_3, this, lastGLCtx); + m_gfxCtx->initializeContext(); + }); } void _clearWindow() { - m_nsWindow = NULL; + m_nsWindow = nullptr; } ~WindowCocoa() { [m_nsWindow orderOut:nil]; - [m_nsWindow release]; delete m_gfxCtx; + [m_nsWindow release]; APP->_deletedWindow(this); } @@ -687,12 +733,18 @@ public: void showWindow() { - [m_nsWindow makeKeyAndOrderFront:nil]; + dispatch_sync(dispatch_get_main_queue(), + ^{ + [m_nsWindow makeKeyAndOrderFront:nil]; + }); } void hideWindow() { - [m_nsWindow orderOut:nil]; + dispatch_sync(dispatch_get_main_queue(), + ^{ + [m_nsWindow orderOut:nil]; + }); } std::string getTitle() @@ -702,16 +754,22 @@ public: void setTitle(const std::string& title) { - [m_nsWindow setTitle:[[NSString stringWithUTF8String:title.c_str()] autorelease]]; + dispatch_sync(dispatch_get_main_queue(), + ^{ + [m_nsWindow setTitle:[[NSString stringWithUTF8String:title.c_str()] autorelease]]; + }); } void setWindowFrameDefault() { - NSScreen* mainScreen = [NSScreen mainScreen]; - NSRect scrFrame = mainScreen.frame; - float x_off = scrFrame.size.width / 3.0; - float y_off = scrFrame.size.height / 3.0; - [m_nsWindow setFrame:NSMakeRect(x_off, y_off, x_off * 2.0, y_off * 2.0) display:NO]; + dispatch_sync(dispatch_get_main_queue(), + ^{ + NSScreen* mainScreen = [NSScreen mainScreen]; + NSRect scrFrame = mainScreen.frame; + float x_off = scrFrame.size.width / 3.0; + float y_off = scrFrame.size.height / 3.0; + [m_nsWindow setFrame:NSMakeRect(x_off, y_off, x_off * 2.0, y_off * 2.0) display:NO]; + }); } void getWindowFrame(float& xOut, float& yOut, float& wOut, float& hOut) const @@ -725,8 +783,11 @@ public: void setWindowFrame(float x, float y, float w, float h) { - NSRect wFrame = NSMakeRect(x, y, w, h); - [m_nsWindow setFrame:wFrame display:NO]; + dispatch_sync(dispatch_get_main_queue(), + ^{ + NSRect wFrame = NSMakeRect(x, y, w, h); + [m_nsWindow setFrame:wFrame display:NO]; + }); } float getVirtualPixelFactor() const @@ -742,7 +803,10 @@ public: void setFullscreen(bool fs) { if ((fs && !isFullscreen()) || (!fs && isFullscreen())) - [m_nsWindow toggleFullScreen:nil]; + dispatch_sync(dispatch_get_main_queue(), + ^{ + [m_nsWindow toggleFullScreen:nil]; + }); } ETouchType getTouchType() const @@ -752,7 +816,7 @@ public: void waitForRetrace() { - + static_cast(m_gfxCtx)->waitForRetrace(); } uintptr_t getPlatformHandle() const @@ -760,11 +824,26 @@ public: return (uintptr_t)m_nsWindow; } + IGraphicsCommandQueue* getCommandQueue() + { + return m_gfxCtx->getCommandQueue(); + } + + IGraphicsDataFactory* getDataFactory() + { + return m_gfxCtx->getDataFactory(); + } + + IGraphicsDataFactory* getLoadContextDataFactory() + { + return m_gfxCtx->getLoadContextDataFactory(); + } + }; -IWindow* _WindowCocoaNew(const SystemString& title) +IWindow* _WindowCocoaNew(const SystemString& title, NSOpenGLContext* lastGLCtx) { - return new WindowCocoa(title); + return new WindowCocoa(title, lastGLCtx); } } diff --git a/test/main.cpp b/test/main.cpp index 3c04331..6ac9416 100644 --- a/test/main.cpp +++ b/test/main.cpp @@ -174,7 +174,7 @@ struct CTestWindowCallback : IWindowCallback struct TestApplicationCallback : IApplicationCallback { - std::unique_ptr mainWindow; + IWindow* mainWindow; boo::TestDeviceFinder devFinder; CTestWindowCallback windowCallback; bool running = true; @@ -196,10 +196,10 @@ struct TestApplicationCallback : IApplicationCallback }; static const Vert quad[4] = { - {{1.0,1.0},{1.0,1.0}}, - {{-1.0,1.0},{0.0,1.0}}, - {{1.0,-1.0},{1.0,0.0}}, - {{-1.0,-1.0},{0.0,0.0}} + {{0.5,0.5},{1.0,1.0}}, + {{-0.5,0.5},{0.0,1.0}}, + {{0.5,-0.5},{1.0,0.0}}, + {{-0.5,-0.5},{0.0,0.0}} }; const IGraphicsBuffer* vbo = factory->newStaticBuffer(BufferUseVertex, quad, sizeof(quad)); @@ -241,15 +241,15 @@ struct TestApplicationCallback : IApplicationCallback static const char* FS = "#version 330\n" "precision highp float;\n" - "uniform sampler2D tex;\n" + "uniform sampler2D smplr;\n" "layout(location=0) out vec4 out_frag;\n" "in vec2 out_uv;\n" "void main()\n" "{\n" - " out_frag = texture(tex, out_uv);\n" + " out_frag = texture(smplr, out_uv);\n" "}\n"; - static const char* TexNames[] = {"tex"}; + static const char* TexNames[] = {"smplr"}; const IShaderPipeline* pipeline = factory->newShaderPipeline(VS, FS, 1, TexNames, BlendFactorOne, BlendFactorZero, true, true, false); @@ -259,7 +259,7 @@ struct TestApplicationCallback : IApplicationCallback factory->newShaderDataBinding(pipeline, vfmt, vbo, nullptr, 0, nullptr, 1, &texture); /* Commit objects */ - std::unique_ptr data = factory->commit(); + IGraphicsData* data = factory->commit(); /* Wait for exit */ while (self->running) @@ -301,7 +301,7 @@ struct TestApplicationCallback : IApplicationCallback gfxQ->present(); gfxQ->execute(); - //fprintf(stderr, "%zu\n", frameIdx++); + fprintf(stderr, "%zu\n", frameIdx); ++frameIdx; if ((frameIdx - lastCheck) > 100) @@ -344,10 +344,8 @@ int main(int argc, const char** argv) { LogVisor::RegisterConsoleLogger(); boo::TestApplicationCallback appCb; - std::unique_ptr app = - ApplicationBootstrap(boo::IApplication::PLAT_AUTO, - appCb, _S("rwk"), _S("RWK"), argc, argv); - int ret = app->run(); + int ret = ApplicationRun(boo::IApplication::PLAT_AUTO, + appCb, _S("rwk"), _S("RWK"), argc, argv); printf("IM DYING!!\n"); return ret; }