diff --git a/renderdoccmd/CMakeLists.txt b/renderdoccmd/CMakeLists.txt index 768a6bbd6..52454435d 100644 --- a/renderdoccmd/CMakeLists.txt +++ b/renderdoccmd/CMakeLists.txt @@ -9,7 +9,14 @@ else() endif() if(APPLE) - list(APPEND sources renderdoccmd_apple.cpp) + list(APPEND sources renderdoccmd_apple.cpp apple/cocoa_window.mm) + + find_library(COCOA_LIBRARY Cocoa) + list(APPEND libraries PRIVATE ${COCOA_LIBRARY}) + + find_library(QUARTZCORE_LIBRARY QuartzCore) + list(APPEND libraries PRIVATE ${QUARTZCORE_LIBRARY}) + elseif(ANDROID) string(REPLACE "\\" "/" GLUE_SOURCE "${ANDROID_NDK_ROOT_PATH}/sources/android/native_app_glue/android_native_app_glue.c") list(APPEND sources renderdoccmd_android.cpp "${GLUE_SOURCE}") diff --git a/renderdoccmd/apple/cocoa_window.mm b/renderdoccmd/apple/cocoa_window.mm new file mode 100644 index 000000000..33e9e8e4f --- /dev/null +++ b/renderdoccmd/apple/cocoa_window.mm @@ -0,0 +1,178 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2019-2021 Baldur Karlsson + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + +#import +#import + +struct cocoa_Window +{ + NSWindow *nsWindow; + NSView *nsView; + bool shouldClose; +}; + +@interface cocoa_WindowApplicationDelegate : NSObject +@end + +@implementation cocoa_WindowApplicationDelegate + +- (void)applicationDidFinishLaunching:(NSNotification *)notification +{ + @autoreleasepool + { + NSEvent *event = [NSEvent otherEventWithType:NSEventTypeApplicationDefined + location:NSMakePoint(0, 0) + modifierFlags:0 + timestamp:0 + windowNumber:0 + context:nil + subtype:0 + data1:0 + data2:0]; + [NSApp postEvent:event atStart:YES]; + [NSApp stop:nil]; + } +} + +@end + +@interface cocoa_WindowDelegate : NSObject +{ + cocoa_Window *window; +} + +- (instancetype)initWithCocoaWindow:(cocoa_Window *)initWindow; + +@end + +@implementation cocoa_WindowDelegate + +- (instancetype)initWithCocoaWindow:(cocoa_Window *)initWindow +{ + self = [super init]; + assert(self); + window = initWindow; + return self; +} + +- (BOOL)windowShouldClose:(id)sender +{ + window->shouldClose = true; + return NO; +} +@end + +void *cocoa_windowCreate(int width, int height, const char *title) +{ + cocoa_Window *window = (cocoa_Window *)calloc(1, sizeof(cocoa_Window)); + + @autoreleasepool + { + [NSApplication sharedApplication]; + [NSApp setActivationPolicy:NSApplicationActivationPolicyRegular]; + [NSApp activateIgnoringOtherApps:YES]; + + id appDelegate = [[cocoa_WindowApplicationDelegate alloc] init]; + [NSApp setDelegate:appDelegate]; + + if(![[NSRunningApplication currentApplication] isFinishedLaunching]) + [NSApp run]; + } + + NSRect contentRect; + contentRect = NSMakeRect(0, 0, width, height); + + window->nsWindow = + [[NSWindow alloc] initWithContentRect:contentRect + styleMask:NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | + NSWindowStyleMaskMiniaturizable + backing:NSBackingStoreBuffered + defer:NO]; + assert(window->nsWindow); + + window->nsView = [[NSView alloc] initWithFrame:contentRect]; + assert(window->nsView); + [window->nsView setLayer:[CAMetalLayer layer]]; + [window->nsView setWantsLayer:YES]; + + id windowDelegate = [[cocoa_WindowDelegate alloc] initWithCocoaWindow:window]; + assert(windowDelegate); + + [window->nsWindow center]; + [window->nsWindow setContentView:window->nsView]; + [window->nsWindow makeFirstResponder:window->nsView]; + [window->nsWindow setTitle:@(title)]; + [window->nsWindow setDelegate:windowDelegate]; + + [window->nsWindow orderFront:nil]; + [window->nsWindow makeKeyAndOrderFront:nil]; + return (void *)window; +} + +void *cocoa_windowGetView(void *cocoaWindow) +{ + cocoa_Window *window = (cocoa_Window *)cocoaWindow; + assert(window); + return (void *)(window->nsView); +} + +void *cocoa_windowGetLayer(void *cocoaWindow) +{ + cocoa_Window *window = (cocoa_Window *)cocoaWindow; + assert(window); + return (void *)(window->nsView.layer); +} + +bool cocoa_windowShouldClose(void *cocoaWindow) +{ + cocoa_Window *window = (cocoa_Window *)cocoaWindow; + assert(window); + return window->shouldClose; +} + +bool cocoa_windowPoll(unsigned short &appleKeyCode) +{ + bool keyUp = false; + @autoreleasepool + { + for(;;) + { + NSEvent *event = [NSApp nextEventMatchingMask:NSEventMaskAny + untilDate:[NSDate distantPast] + inMode:NSDefaultRunLoopMode + dequeue:YES]; + if(event == nil) + break; + + if([event type] == NSEventTypeKeyUp) + { + appleKeyCode = [event keyCode]; + keyUp = true; + } + + [NSApp sendEvent:event]; + } + } + return keyUp; +} diff --git a/renderdoccmd/renderdoccmd_apple.cpp b/renderdoccmd/renderdoccmd_apple.cpp index d1369efa3..44a80fa57 100644 --- a/renderdoccmd/renderdoccmd_apple.cpp +++ b/renderdoccmd/renderdoccmd_apple.cpp @@ -28,6 +28,13 @@ #include #include +// helpers defined in cocoa_window.mm +extern void *cocoa_windowCreate(int width, int height, const char *title); +extern void *cocoa_windowGetView(void *cocoaWindow); +extern void *cocoa_windowGetLayer(void *cocoaWindow); +extern bool cocoa_windowShouldClose(void *cocoaWindow); +extern bool cocoa_windowPoll(unsigned short &appleKeyCode); + void Daemonise() { } @@ -41,6 +48,44 @@ WindowingData DisplayRemoteServerPreview(bool active, const rdcarrayCreateOutput(CreateMacOSWindowingData(view, layer), ReplayOutputType::Texture); + + out->SetTextureDisplay(displayCfg); + + uint32_t loopCount = 0; + + bool done = false; + while(!done) + { + if(cocoa_windowShouldClose(cocoaWindow)) + { + break; + } + + unsigned short appleKeyCode; + if(cocoa_windowPoll(appleKeyCode)) + { + // kVK_Escape + if(appleKeyCode == 0x35) + { + break; + } + } + + renderer->SetFrameEvent(10000000, true); + out->Display(); + + usleep(100000); + + loopCount++; + + if(numLoops > 0 && loopCount == numLoops) + break; + } } int main(int argc, char *argv[]) @@ -53,5 +98,35 @@ int main(int argc, char *argv[]) GlobalEnvironment env; + // add compiled-in support to version line + { + std::string support = "APIs supported at compile-time: "; + int count = 0; + +#if defined(RENDERDOC_SUPPORT_VULKAN) + support += "Vulkan, "; + count++; +#endif + +#if defined(RENDERDOC_SUPPORT_GL) + support += "GL, "; + count++; +#endif + + if(count == 0) + { + support += "None."; + } + else + { + // remove trailing ', ' + support.pop_back(); + support.pop_back(); + support += "."; + } + + add_version_line(support); + } + return renderdoccmd(env, argc, argv); }