parent
dcdabb9b12
commit
ad6e36023f
5 changed files with 338 additions and 32 deletions
6
BUILD.md
6
BUILD.md
|
|
@ -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/)
|
||||
|
||||
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"
|
||||
```
|
||||
|
|
@ -26,6 +26,10 @@ if (NOT CMAKE_VERSION VERSION_LESS 3.7.0)
|
|||
find_package(Vulkan)
|
||||
endif()
|
||||
|
||||
IF(UNIX AND NOT APPLE)
|
||||
set(LINUX TRUE)
|
||||
ENDIF()
|
||||
|
||||
IF(WIN32)
|
||||
IF (NOT Vulkan_FOUND)
|
||||
find_library(Vulkan_LIBRARY NAMES vulkan-1 vulkan PATHS ${CMAKE_SOURCE_DIR}/libs/vulkan)
|
||||
|
|
@ -35,7 +39,7 @@ IF(WIN32)
|
|||
ENDIF()
|
||||
ENDIF()
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DVK_USE_PLATFORM_WIN32_KHR")
|
||||
ELSE(WIN32)
|
||||
ELSEIF(LINUX)
|
||||
IF (NOT Vulkan_FOUND)
|
||||
find_library(Vulkan_LIBRARY NAMES vulkan HINTS "$ENV{VULKAN_SDK}/lib" "${CMAKE_SOURCE_DIR}/libs/vulkan" REQUIRED)
|
||||
IF (Vulkan_LIBRARY)
|
||||
|
|
@ -44,10 +48,10 @@ ELSE(WIN32)
|
|||
ENDIF()
|
||||
ENDIF()
|
||||
find_package(Threads REQUIRED)
|
||||
IF(USE_D2D_WSI)
|
||||
IF(USE_D2D_WSI)
|
||||
MESSAGE("Using direct to display extension...")
|
||||
add_definitions(-D_DIRECT2DISPLAY)
|
||||
ELSEIF(USE_WAYLAND_WSI)
|
||||
ELSEIF(USE_WAYLAND_WSI)
|
||||
find_program(PKG_CONFIG pkg-config)
|
||||
if (NOT PKG_CONFIG)
|
||||
message(FATAL_ERROR "pkg-config binary not found")
|
||||
|
|
@ -70,10 +74,12 @@ ELSEIF(USE_WAYLAND_WSI)
|
|||
execute_process(COMMAND ${WAYLAND_SCANNER} client-header ${protocol_dir}/stable/xdg-shell/xdg-shell.xml ${CMAKE_BINARY_DIR}/xdg-shell-client-protocol.h
|
||||
COMMAND ${WAYLAND_SCANNER} private-code ${protocol_dir}/stable/xdg-shell/xdg-shell.xml ${CMAKE_BINARY_DIR}/xdg-shell-protocol.c)
|
||||
include_directories(${CMAKE_BINARY_DIR})
|
||||
ELSE(USE_D2D_WSI)
|
||||
ELSE(USE_D2D_WSI)
|
||||
find_package(XCB REQUIRED)
|
||||
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?
|
||||
ENDIF(WIN32)
|
||||
|
||||
|
|
@ -115,10 +121,14 @@ endif()
|
|||
# Compiler specific stuff
|
||||
IF(MSVC)
|
||||
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /EHsc")
|
||||
ELSEIF(APPLE)
|
||||
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fobjc-arc -xobjective-c++")
|
||||
ENDIF(MSVC)
|
||||
|
||||
IF(WIN32)
|
||||
# Nothing here (yet)
|
||||
ELSEIF(APPLE)
|
||||
link_libraries(${Vulkan_LIBRARY} "-framework AppKit" "-framework QuartzCore")
|
||||
ELSE(WIN32)
|
||||
link_libraries(${XCB_LIBRARIES} ${Vulkan_LIBRARY} ${Vulkan_LIBRARY} ${WAYLAND_CLIENT_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT})
|
||||
ENDIF(WIN32)
|
||||
|
|
|
|||
|
|
@ -8,6 +8,13 @@
|
|||
|
||||
#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;
|
||||
|
||||
VkResult VulkanExampleBase::createInstance(bool enableValidation)
|
||||
|
|
@ -532,6 +539,8 @@ void VulkanExampleBase::renderLoop()
|
|||
}
|
||||
updateOverlay();
|
||||
}
|
||||
#elif (defined(VK_USE_PLATFORM_MACOS_MVK) && defined(VK_EXAMPLE_XCODE_GENERATED))
|
||||
[NSApp run];
|
||||
#endif
|
||||
// Flush device to make sure all resources can be freed
|
||||
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))
|
||||
#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)
|
||||
{
|
||||
#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;
|
||||
#endif
|
||||
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(VK_USE_PLATFORM_WAYLAND_KHR)
|
||||
/*static*/void VulkanExampleBase::registryGlobalCb(void *data,
|
||||
|
|
|
|||
|
|
@ -269,6 +269,10 @@ public:
|
|||
static void handleAppCommand(android_app* app, int32_t cmd);
|
||||
#elif (defined(VK_USE_PLATFORM_IOS_MVK) || defined(VK_USE_PLATFORM_MACOS_MVK))
|
||||
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)
|
||||
struct xdg_surface *setupWindow();
|
||||
void initWaylandConnection();
|
||||
|
|
@ -457,5 +461,24 @@ int main(const int argc, const char *argv[]) \
|
|||
return 0; \
|
||||
}
|
||||
#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()
|
||||
#endif
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -1186,4 +1186,20 @@ int main(const int argc, const char *argv[])
|
|||
delete(vulkanExample);
|
||||
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
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue