Run on MacOS (#762)

* Run on MacOS

* Update BUILD.md
This commit is contained in:
daemyung jang 2020-09-12 03:19:28 +09:00 committed by GitHub
parent dcdabb9b12
commit ad6e36023f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 338 additions and 32 deletions

View file

@ -37,3 +37,9 @@ If you want to build and install on a connected device or emulator image, run ``
## <img src="./images/applelogo.png" alt="" height="32px"> [iOS and macOS](xcode/) ## <img src="./images/applelogo.png" alt="" height="32px"> [iOS and macOS](xcode/)
Building for *iOS* and *macOS* is done using the [examples](xcode/examples.xcodeproj) *Xcode* project found in the [xcode](xcode) directory. These examples use the [**MoltenVK**](https://moltengl.com/moltenvk) Vulkan driver to provide Vulkan support on *iOS* and *macOS*, and require an *iOS* or *macOS* device that supports *Metal*. Please see the [MoltenVK Examples readme](xcode/README_MoltenVK_Examples.md) for more info on acquiring **MoltenVK** and building and deploying the examples on *iOS* and *macOS*. Building for *iOS* and *macOS* is done using the [examples](xcode/examples.xcodeproj) *Xcode* project found in the [xcode](xcode) directory. These examples use the [**MoltenVK**](https://moltengl.com/moltenvk) Vulkan driver to provide Vulkan support on *iOS* and *macOS*, and require an *iOS* or *macOS* device that supports *Metal*. Please see the [MoltenVK Examples readme](xcode/README_MoltenVK_Examples.md) for more info on acquiring **MoltenVK** and building and deploying the examples on *iOS* and *macOS*.
##### MacOS
Use the provided CMakeLists.txt with [CMake](https://cmake.org) to generate a build configuration for your favorite IDE or compiler, e.g.:
```
cmake -G "Xcode"
```

View file

@ -26,6 +26,10 @@ if (NOT CMAKE_VERSION VERSION_LESS 3.7.0)
find_package(Vulkan) find_package(Vulkan)
endif() endif()
IF(UNIX AND NOT APPLE)
set(LINUX TRUE)
ENDIF()
IF(WIN32) IF(WIN32)
IF (NOT Vulkan_FOUND) IF (NOT Vulkan_FOUND)
find_library(Vulkan_LIBRARY NAMES vulkan-1 vulkan PATHS ${CMAKE_SOURCE_DIR}/libs/vulkan) find_library(Vulkan_LIBRARY NAMES vulkan-1 vulkan PATHS ${CMAKE_SOURCE_DIR}/libs/vulkan)
@ -35,7 +39,7 @@ IF(WIN32)
ENDIF() ENDIF()
ENDIF() ENDIF()
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DVK_USE_PLATFORM_WIN32_KHR") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DVK_USE_PLATFORM_WIN32_KHR")
ELSE(WIN32) ELSEIF(LINUX)
IF (NOT Vulkan_FOUND) IF (NOT Vulkan_FOUND)
find_library(Vulkan_LIBRARY NAMES vulkan HINTS "$ENV{VULKAN_SDK}/lib" "${CMAKE_SOURCE_DIR}/libs/vulkan" REQUIRED) find_library(Vulkan_LIBRARY NAMES vulkan HINTS "$ENV{VULKAN_SDK}/lib" "${CMAKE_SOURCE_DIR}/libs/vulkan" REQUIRED)
IF (Vulkan_LIBRARY) IF (Vulkan_LIBRARY)
@ -74,6 +78,8 @@ ELSE(USE_D2D_WSI)
find_package(XCB REQUIRED) find_package(XCB REQUIRED)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DVK_USE_PLATFORM_XCB_KHR") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DVK_USE_PLATFORM_XCB_KHR")
ENDIF(USE_D2D_WSI) ENDIF(USE_D2D_WSI)
ELSEIF(APPLE)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DVK_USE_PLATFORM_MACOS_MVK -DVK_EXAMPLE_XCODE_GENERATED")
# Todo : android? # Todo : android?
ENDIF(WIN32) ENDIF(WIN32)
@ -115,10 +121,14 @@ endif()
# Compiler specific stuff # Compiler specific stuff
IF(MSVC) IF(MSVC)
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /EHsc") SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /EHsc")
ELSEIF(APPLE)
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fobjc-arc -xobjective-c++")
ENDIF(MSVC) ENDIF(MSVC)
IF(WIN32) IF(WIN32)
# Nothing here (yet) # Nothing here (yet)
ELSEIF(APPLE)
link_libraries(${Vulkan_LIBRARY} "-framework AppKit" "-framework QuartzCore")
ELSE(WIN32) ELSE(WIN32)
link_libraries(${XCB_LIBRARIES} ${Vulkan_LIBRARY} ${Vulkan_LIBRARY} ${WAYLAND_CLIENT_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT}) link_libraries(${XCB_LIBRARIES} ${Vulkan_LIBRARY} ${Vulkan_LIBRARY} ${WAYLAND_CLIENT_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT})
ENDIF(WIN32) ENDIF(WIN32)

View file

@ -8,6 +8,13 @@
#include "vulkanexamplebase.h" #include "vulkanexamplebase.h"
#if (defined(VK_USE_PLATFORM_MACOS_MVK) && defined(VK_EXAMPLE_XCODE_GENERATED))
#include <Cocoa/Cocoa.h>
#include <Carbon/Carbon.h>
#include <QuartzCore/CAMetalLayer.h>
#include <CoreVideo/CVDisplayLink.h>
#endif
std::vector<const char*> VulkanExampleBase::args; std::vector<const char*> VulkanExampleBase::args;
VkResult VulkanExampleBase::createInstance(bool enableValidation) VkResult VulkanExampleBase::createInstance(bool enableValidation)
@ -532,6 +539,8 @@ void VulkanExampleBase::renderLoop()
} }
updateOverlay(); updateOverlay();
} }
#elif (defined(VK_USE_PLATFORM_MACOS_MVK) && defined(VK_EXAMPLE_XCODE_GENERATED))
[NSApp run];
#endif #endif
// Flush device to make sure all resources can be freed // Flush device to make sure all resources can be freed
if (device != VK_NULL_HANDLE) { if (device != VK_NULL_HANDLE) {
@ -1427,11 +1436,253 @@ void VulkanExampleBase::handleAppCommand(android_app * app, int32_t cmd)
} }
} }
#elif (defined(VK_USE_PLATFORM_IOS_MVK) || defined(VK_USE_PLATFORM_MACOS_MVK)) #elif (defined(VK_USE_PLATFORM_IOS_MVK) || defined(VK_USE_PLATFORM_MACOS_MVK))
#if defined(VK_EXAMPLE_XCODE_GENERATED)
@interface AppDelegate : NSObject<NSApplicationDelegate>
{
}
@end
@implementation AppDelegate
{
}
- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)sender
{
return YES;
}
@end
static CVReturn displayLinkOutputCallback(CVDisplayLinkRef displayLink, const CVTimeStamp *inNow,
const CVTimeStamp *inOutputTime, CVOptionFlags flagsIn, CVOptionFlags *flagsOut,
void *displayLinkContext)
{
@autoreleasepool
{
auto vulkanExample = static_cast<VulkanExampleBase*>(displayLinkContext);
vulkanExample->displayLinkOutputCb();
}
return kCVReturnSuccess;
}
@interface View : NSView<NSWindowDelegate>
{
@public
VulkanExampleBase *vulkanExample;
}
@end
@implementation View
{
CVDisplayLinkRef displayLink;
}
- (instancetype)initWithFrame:(NSRect)frameRect
{
self = [super initWithFrame:(frameRect)];
if (self)
{
self.wantsLayer = YES;
self.layer = [CAMetalLayer layer];
}
return self;
}
- (void)viewDidMoveToWindow
{
CVDisplayLinkCreateWithActiveCGDisplays(&displayLink);
CVDisplayLinkSetOutputCallback(displayLink, &displayLinkOutputCallback, vulkanExample);
CVDisplayLinkStart(displayLink);
}
- (BOOL)acceptsFirstResponder
{
return YES;
}
- (void)keyDown:(NSEvent*)event
{
switch (event.keyCode)
{
case kVK_ANSI_P:
vulkanExample->paused = !vulkanExample->paused;
break;
case kVK_Escape:
[NSApp terminate:nil];
break;
case kVK_ANSI_W:
vulkanExample->camera.keys.up = true;
break;
case kVK_ANSI_S:
vulkanExample->camera.keys.down = true;
break;
case kVK_ANSI_A:
vulkanExample->camera.keys.left = true;
break;
case kVK_ANSI_D:
vulkanExample->camera.keys.right = true;
break;
default:
break;
}
}
- (void)keyUp:(NSEvent*)event
{
switch (event.keyCode)
{
case kVK_ANSI_W:
vulkanExample->camera.keys.up = false;
break;
case kVK_ANSI_S:
vulkanExample->camera.keys.down = false;
break;
case kVK_ANSI_A:
vulkanExample->camera.keys.left = false;
break;
case kVK_ANSI_D:
vulkanExample->camera.keys.right = false;
break;
default:
break;
}
}
- (NSPoint)getMouseLocalPoint:(NSEvent*)event
{
NSPoint location = [event locationInWindow];
NSPoint point = [self convertPoint:location fromView:nil];
point.y = self.frame.size.height - point.y;
return point;
}
- (void)mouseDown:(NSEvent *)event
{
auto point = [self getMouseLocalPoint:event];
vulkanExample->mousePos = glm::vec2(point.x, point.y);
vulkanExample->mouseButtons.left = true;
}
- (void)mouseUp:(NSEvent *)event
{
auto point = [self getMouseLocalPoint:event];
vulkanExample->mousePos = glm::vec2(point.x, point.y);
vulkanExample->mouseButtons.left = false;
}
- (void)otherMouseDown:(NSEvent *)event
{
vulkanExample->mouseButtons.right = true;
}
- (void)otherMouseUp:(NSEvent *)event
{
vulkanExample->mouseButtons.right = false;
}
- (void)mouseDragged:(NSEvent *)event
{
auto point = [self getMouseLocalPoint:event];
vulkanExample->mouseDragged(point.x, point.y);
}
- (void)mouseMoved:(NSEvent *)event
{
auto point = [self getMouseLocalPoint:event];
vulkanExample->mouseDragged(point.x, point.y);
}
- (void)scrollWheel:(NSEvent *)event
{
short wheelDelta = [event deltaY];
vulkanExample->camera.translate(glm::vec3(0.0f, 0.0f,
-(float)wheelDelta * 0.05f * vulkanExample->camera.movementSpeed));
}
- (NSSize)windowWillResize:(NSWindow *)sender toSize:(NSSize)frameSize
{
CVDisplayLinkStop(displayLink);
vulkanExample->windowWillResize(frameSize.width, frameSize.height);
return frameSize;
}
- (void)windowDidResize:(NSNotification *)notification
{
vulkanExample->windowDidResize();
CVDisplayLinkStart(displayLink);
}
- (BOOL)windowShouldClose:(NSWindow *)sender
{
return TRUE;
}
- (void)windowWillClose:(NSNotification *)notification
{
CVDisplayLinkStop(displayLink);
}
@end
#endif
void* VulkanExampleBase::setupWindow(void* view) void* VulkanExampleBase::setupWindow(void* view)
{ {
#if defined(VK_EXAMPLE_XCODE_GENERATED)
NSApp = [NSApplication sharedApplication];
[NSApp setActivationPolicy:NSApplicationActivationPolicyRegular];
[NSApp setDelegate:[AppDelegate new]];
const auto kContentRect = NSMakeRect(0.0f, 0.0f, width, height);
const auto kWindowStyle = NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | NSWindowStyleMaskResizable;
auto window = [[NSWindow alloc] initWithContentRect:kContentRect
styleMask:kWindowStyle
backing:NSBackingStoreBuffered
defer:NO];
[window setTitle:@(title.c_str())];
[window setAcceptsMouseMovedEvents:YES];
[window center];
[window makeKeyAndOrderFront:nil];
auto nsView = [[View alloc] initWithFrame:kContentRect];
nsView->vulkanExample = this;
[window setDelegate:nsView];
[window setContentView:nsView];
this->view = (__bridge void*)nsView;
#else
this->view = view; this->view = view;
#endif
return view; return view;
} }
void VulkanExampleBase::displayLinkOutputCb()
{
if (prepared)
nextFrame();
}
void VulkanExampleBase::mouseDragged(float x, float y)
{
handleMouseMove(static_cast<uint32_t>(x), static_cast<uint32_t>(y));
}
void VulkanExampleBase::windowWillResize(float x, float y)
{
resizing = true;
if (prepared)
{
destWidth = x;
destHeight = y;
windowResize();
}
}
void VulkanExampleBase::windowDidResize()
{
resizing = false;
}
#elif defined(_DIRECT2DISPLAY) #elif defined(_DIRECT2DISPLAY)
#elif defined(VK_USE_PLATFORM_WAYLAND_KHR) #elif defined(VK_USE_PLATFORM_WAYLAND_KHR)
/*static*/void VulkanExampleBase::registryGlobalCb(void *data, /*static*/void VulkanExampleBase::registryGlobalCb(void *data,

View file

@ -269,6 +269,10 @@ public:
static void handleAppCommand(android_app* app, int32_t cmd); static void handleAppCommand(android_app* app, int32_t cmd);
#elif (defined(VK_USE_PLATFORM_IOS_MVK) || defined(VK_USE_PLATFORM_MACOS_MVK)) #elif (defined(VK_USE_PLATFORM_IOS_MVK) || defined(VK_USE_PLATFORM_MACOS_MVK))
void* setupWindow(void* view); void* setupWindow(void* view);
void displayLinkOutputCb();
void mouseDragged(float x, float y);
void windowWillResize(float x, float y);
void windowDidResize();
#elif defined(VK_USE_PLATFORM_WAYLAND_KHR) #elif defined(VK_USE_PLATFORM_WAYLAND_KHR)
struct xdg_surface *setupWindow(); struct xdg_surface *setupWindow();
void initWaylandConnection(); void initWaylandConnection();
@ -457,5 +461,24 @@ int main(const int argc, const char *argv[]) \
return 0; \ return 0; \
} }
#elif (defined(VK_USE_PLATFORM_IOS_MVK) || defined(VK_USE_PLATFORM_MACOS_MVK)) #elif (defined(VK_USE_PLATFORM_IOS_MVK) || defined(VK_USE_PLATFORM_MACOS_MVK))
#if defined(VK_EXAMPLE_XCODE_GENERATED)
#define VULKAN_EXAMPLE_MAIN() \
VulkanExample *vulkanExample; \
int main(const int argc, const char *argv[]) \
{ \
@autoreleasepool \
{ \
for (size_t i = 0; i < argc; i++) { VulkanExample::args.push_back(argv[i]); }; \
vulkanExample = new VulkanExample(); \
vulkanExample->initVulkan(); \
vulkanExample->setupWindow(nullptr); \
vulkanExample->prepare(); \
vulkanExample->renderLoop(); \
delete(vulkanExample); \
} \
return 0; \
}
#else
#define VULKAN_EXAMPLE_MAIN() #define VULKAN_EXAMPLE_MAIN()
#endif #endif
#endif

View file

@ -1186,4 +1186,20 @@ int main(const int argc, const char *argv[])
delete(vulkanExample); delete(vulkanExample);
return 0; return 0;
} }
#elif (defined(VK_USE_PLATFORM_MACOS_MVK) && defined(VK_EXAMPLE_XCODE_GENERATED))
VulkanExample *vulkanExample;
int main(const int argc, const char *argv[])
{
@autoreleasepool
{
for (size_t i = 0; i < argc; i++) { VulkanExample::args.push_back(argv[i]); };
vulkanExample = new VulkanExample();
vulkanExample->initVulkan();
vulkanExample->setupWindow(nullptr);
vulkanExample->prepare();
vulkanExample->renderLoop();
delete(vulkanExample);
}
return 0;
}
#endif #endif