First Apple platform support for Vulkan demos

Uses Metal-CPP-Extensions code to create window and the event loop.
Does not include support for Nuklear
This commit is contained in:
Jake Turner
2022-07-06 10:26:30 +01:00
committed by Baldur Karlsson
parent 4e13b1ad38
commit c83851e884
9 changed files with 470 additions and 8 deletions
+33 -3
View File
@@ -1,5 +1,11 @@
cmake_minimum_required(VERSION 2.8.12)
if(APPLE)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/../bin")
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}")
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}")
endif()
set(PROJECT demos)
set(VULKAN_SRC
@@ -127,7 +133,17 @@ if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${warning_flags}")
endif()
if(NOT APPLE AND UNIX)
if(APPLE)
list(APPEND SRC
apple/official/metal-cpp.cpp
apple/official/metal-cpp.h
apple/apple_platform.cpp
apple/apple_platform.h
apple/apple_window.cpp
apple/apple_window.h)
add_executable(demos ${SRC} ${VULKAN_SRC})
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17")
elseif(UNIX)
list(APPEND OPENGL_SRC
3rdparty/glad/glad_glx.c
gl/gl_test_linux.cpp)
@@ -161,7 +177,21 @@ find_package(Threads REQUIRED)
target_include_directories(demos
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/vk/official
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
target_compile_definitions(demos PRIVATE -DVK_USE_PLATFORM_XCB_KHR=1)
target_link_libraries(demos PRIVATE -lX11 -lxcb -lX11-xcb ${CMAKE_THREAD_LIBS_INIT} ${CMAKE_DL_LIBS})
if(APPLE)
target_include_directories(demos
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/apple/official)
find_library(COCOA_LIBRARY Cocoa)
find_library(QUARTZCORE_LIBRARY QuartzCore)
find_library(METAL_LIBRARY Metal)
target_compile_definitions(demos PRIVATE
-DVK_USE_PLATFORM_MACOS_MVK=1)
set(LIBS ${COCOA_LIBRARY} ${QUARTZCORE_LIBRARY} ${METAL_LIBRARY})
elseif(UNIX)
target_compile_definitions(demos PRIVATE -DVK_USE_PLATFORM_XCB_KHR=1)
set(LIBS -lX11 -lxcb -lX11-xcb)
endif()
target_link_libraries(demos PRIVATE ${LIBS} ${CMAKE_THREAD_LIBS_INIT} ${CMAKE_DL_LIBS})
set_target_properties(demos PROPERTIES OUTPUT_NAME demos_${BIN_SUFFIX})
+97
View File
@@ -0,0 +1,97 @@
/******************************************************************************
* The MIT License (MIT)
*
* Copyright (c) 2022 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.
******************************************************************************/
#include <mach-o/dyld.h>
#include <mach/mach.h>
#include "test_common.h"
uint64_t GetMemoryUsage()
{
mach_task_basic_info taskInfo;
mach_msg_type_number_t infoCount = MACH_TASK_BASIC_INFO_COUNT;
int ret = task_info(mach_task_self(), MACH_TASK_BASIC_INFO, (task_info_t)&taskInfo, &infoCount);
if(ret != KERN_SUCCESS)
return 0;
return taskInfo.resident_size;
}
std::string GetCWD()
{
char cwd[MAX_PATH + 1] = {0};
getcwd(cwd, MAX_PATH);
std::string cwdstr = cwd;
for(size_t i = 0; i < cwdstr.size(); i++)
if(cwdstr[i] == '\\')
cwdstr[i] = '/';
while(cwdstr.back() == '/' || cwdstr.back() == '\\')
cwdstr.pop_back();
return cwdstr;
}
std::string GetEnvVar(const char *var)
{
const char *data = getenv(var);
if(data)
return data;
return "";
}
std::string GetExecutableName()
{
char path[512] = {0};
std::string selfName;
uint32_t pathSize = (uint32_t)sizeof(path);
if(_NSGetExecutablePath(path, &pathSize) == 0)
{
selfName = path;
}
else
{
pathSize++;
if(_NSGetExecutablePath(path, &pathSize) == 0)
{
selfName = path;
}
else
{
return "/unknown/unknown";
}
}
memset(path, 0, sizeof(path));
readlink(selfName.c_str(), path, 511);
if(path[0] != 0)
selfName = path;
return selfName;
}
+44
View File
@@ -0,0 +1,44 @@
/******************************************************************************
* The MIT License (MIT)
*
* Copyright (c) 2022 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.
******************************************************************************/
#pragma once
#include <dlfcn.h>
#include <signal.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <string>
#define DEBUG_BREAK() raise(SIGTRAP)
#define MAX_PATH 256
#define msleep(time) usleep((time)*1000)
#define EXECUTABLE_SUFFIX ""
#define MakeDir(dir) mkdir(dir, 0755)
std::string GetExecutableName();
+192
View File
@@ -0,0 +1,192 @@
/******************************************************************************
* The MIT License (MIT)
*
* Copyright (c) 2022 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.
******************************************************************************/
#include "apple_window.h"
#include "official/metal-cpp.h"
static NS::Application *pSharedApplication = NULL;
MyAppDelegate *AppleWindow::pAppDelegate = NULL;
class MyAppDelegate : public NS::ApplicationDelegate
{
public:
~MyAppDelegate();
NS::Menu *createMenuBar();
virtual void applicationWillFinishLaunching(NS::Notification *pNotification) override;
virtual void applicationDidFinishLaunching(NS::Notification *pNotification) override;
virtual bool applicationShouldTerminateAfterLastWindowClosed(NS::Application *pSender) override;
void CreateWindow(int width, int height, const char *title);
NS::View *GetContentView();
NS::Window *GetWindow();
private:
NS::Window *_pWindow;
};
MyAppDelegate::~MyAppDelegate()
{
_pWindow->release();
}
NS::Menu *MyAppDelegate::createMenuBar()
{
using NS::StringEncoding::UTF8StringEncoding;
NS::Menu *pMainMenu = NS::Menu::alloc()->init();
NS::MenuItem *pAppMenuItem = NS::MenuItem::alloc()->init();
NS::Menu *pAppMenu = NS::Menu::alloc()->init(NS::String::string("Appname", UTF8StringEncoding));
NS::String *appName = NS::RunningApplication::currentApplication()->localizedName();
NS::String *quitItemName =
NS::String::string("Quit ", UTF8StringEncoding)->stringByAppendingString(appName);
SEL quitCb =
NS::MenuItem::registerActionCallback("appQuit", [](void *, SEL, const NS::Object *pSender) {
NS::Application *pApp = NS::Application::sharedApplication();
pApp->terminate(pSender);
});
NS::MenuItem *pAppQuitItem =
pAppMenu->addItem(quitItemName, quitCb, NS::String::string("q", UTF8StringEncoding));
pAppQuitItem->setKeyEquivalentModifierMask(NS::EventModifierFlagCommand);
pAppMenuItem->setSubmenu(pAppMenu);
NS::MenuItem *pWindowMenuItem = NS::MenuItem::alloc()->init();
NS::Menu *pWindowMenu = NS::Menu::alloc()->init(NS::String::string("Window", UTF8StringEncoding));
SEL closeWindowCb =
NS::MenuItem::registerActionCallback("windowClose", [](void *, SEL, const NS::Object *) {
NS::Application *pApp = NS::Application::sharedApplication();
pApp->windows()->object<NS::Window>(0)->close();
});
NS::MenuItem *pCloseWindowItem =
pWindowMenu->addItem(NS::String::string("Close Window", UTF8StringEncoding), closeWindowCb,
NS::String::string("w", UTF8StringEncoding));
pCloseWindowItem->setKeyEquivalentModifierMask(NS::EventModifierFlagCommand);
pWindowMenuItem->setSubmenu(pWindowMenu);
pMainMenu->addItem(pAppMenuItem);
pMainMenu->addItem(pWindowMenuItem);
pAppMenuItem->release();
pWindowMenuItem->release();
pAppMenu->release();
pWindowMenu->release();
return pMainMenu->autorelease();
}
void MyAppDelegate::applicationWillFinishLaunching(NS::Notification *pNotification)
{
NS::Menu *pMenu = createMenuBar();
NS::Application *pApp = (NS::Application *)pNotification->object();
pApp->setMainMenu(pMenu);
pApp->setActivationPolicy(NS::ActivationPolicy::ActivationPolicyRegular);
}
void MyAppDelegate::applicationDidFinishLaunching(NS::Notification *pNotification)
{
NS::Application *pApp = (NS::Application *)pNotification->object();
pApp->activateIgnoringOtherApps(true);
}
bool MyAppDelegate::applicationShouldTerminateAfterLastWindowClosed(NS::Application *pSender)
{
return true;
}
void MyAppDelegate::CreateWindow(int width, int height, const char *title)
{
CGRect frame = CGRectMake(100.0f, 100.0f, width, height);
_pWindow = NS::Window::alloc()->init(frame, NS::WindowStyleMaskClosable | NS::WindowStyleMaskTitled,
NS::BackingStoreBuffered, false);
NS::View *view = _pWindow->contentView();
view->setWantsLayer(true);
view->setLayer(CA::MetalLayer::layer());
_pWindow->setTitle(NS::String::string(title, NS::StringEncoding::UTF8StringEncoding));
_pWindow->makeKeyAndOrderFront(nullptr);
}
NS::View *MyAppDelegate::GetContentView()
{
return _pWindow->contentView();
}
NS::Window *MyAppDelegate::GetWindow()
{
return _pWindow;
}
AppleWindow::~AppleWindow()
{
pAppDelegate = nullptr;
}
AppleWindow::AppleWindow(int width, int height, const char *title) : GraphicsWindow(title)
{
pAppDelegate->CreateWindow(width, height, title);
view = pAppDelegate->GetContentView();
}
bool AppleWindow::Init()
{
pSharedApplication = NS::Application::sharedApplication();
pAppDelegate = new MyAppDelegate();
pSharedApplication->setDelegate(pAppDelegate);
if(!NS::RunningApplication::currentApplication()->finishedLaunching())
pSharedApplication->finishLaunching();
return true;
}
void AppleWindow::Resize(int width, int height)
{
TEST_ERROR("Resize is not implemented");
}
extern "C" void *const NSDefaultRunLoopMode;
bool AppleWindow::Update()
{
NS::AutoreleasePool *pAutoreleasePool = NS::AutoreleasePool::alloc()->init();
while(true)
{
NS::Event *event = pSharedApplication->nextEventMatchingMask(
(int)NS::EventMaskAny, NS::Date::distantPast(), (NS::String *)NSDefaultRunLoopMode, true);
if(event == NULL)
break;
pSharedApplication->sendEvent(event);
}
pAutoreleasePool->release();
return pAppDelegate->GetWindow()->visible();
}
+43
View File
@@ -0,0 +1,43 @@
/******************************************************************************
* The MIT License (MIT)
*
* Copyright (c) 2022 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.
******************************************************************************/
#pragma once
#include "../test_common.h"
class MyAppDelegate;
struct AppleWindow : GraphicsWindow
{
AppleWindow(int width, int height, const char *title);
~AppleWindow();
static bool Init();
void Resize(int width, int height);
bool Update();
static MyAppDelegate *pAppDelegate;
void *view;
};
+24
View File
@@ -214,6 +214,30 @@ void NuklearShutdown()
XCloseDisplay(dpy);
}
#elif defined(__APPLE__)
nk_context *NuklearInit(int width, int height, const char *title)
{
TEST_ERROR("NuklearInit: Not Implemented");
return NULL;
}
bool NuklearTick(nk_context *ctx)
{
TEST_ERROR("NuklearTick: Not Implemented");
return false;
}
void NuklearRender()
{
TEST_ERROR("NuklearRender: Not Implemented");
}
void NuklearShutdown()
{
TEST_ERROR("NuklearShutdown: Not Implemented");
}
#else
#error UNKNOWN PLATFORM
+7 -1
View File
@@ -569,10 +569,16 @@ bool GraphicsTest::Init()
HMODULE mod = GetModuleHandleA("renderdoc.dll");
if(mod)
RENDERDOC_GetAPI = (pRENDERDOC_GetAPI)GetProcAddress(mod, "RENDERDOC_GetAPI");
#else
#elif defined(__linux__)
void *mod = dlopen("librenderdoc.so", RTLD_NOW | RTLD_NOLOAD);
if(mod)
RENDERDOC_GetAPI = (pRENDERDOC_GetAPI)dlsym(mod, "RENDERDOC_GetAPI");
#elif defined(__APPLE__)
void *mod = dlopen("librenderdoc.dylib", RTLD_NOW | RTLD_NOLOAD);
if(mod)
RENDERDOC_GetAPI = (pRENDERDOC_GetAPI)dlsym(mod, "RENDERDOC_GetAPI");
#else
#error UNKNOWN PLATFORM
#endif
if(RENDERDOC_GetAPI)
+2
View File
@@ -28,6 +28,8 @@
#include "win32/win32_platform.h"
#elif defined(__linux__)
#include "linux/linux_platform.h"
#elif defined(__APPLE__)
#include "apple/apple_platform.h"
#else
#error UNKNOWN PLATFORM
#endif
+28 -4
View File
@@ -102,8 +102,12 @@ void main()
#if defined(WIN32)
#include "../win32/win32_window.h"
#else
#elif defined(__linux__)
#include "../linux/linux_window.h"
#elif defined(__APPLE__)
#include "../apple/apple_window.h"
#else
#error UNKNOWN PLATFORM
#endif
static VkBool32 VKAPI_PTR vulkanCallback(VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
@@ -157,10 +161,16 @@ void VulkanGraphicsTest::Prepare(int argc, char **argv)
#if defined(WIN32)
enabledInstExts.push_back(VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
#else
#elif defined(__linux__)
enabledInstExts.push_back(VK_KHR_XCB_SURFACE_EXTENSION_NAME);
X11Window::Init();
#elif defined(__APPLE__)
enabledInstExts.push_back(VK_MVK_MACOS_SURFACE_EXTENSION_NAME);
AppleWindow::Init();
#else
#error UNKNOWN PLATFORM
#endif
std::vector<const char *> optInstExts;
@@ -706,8 +716,12 @@ VulkanWindow *VulkanGraphicsTest::MakeWindow(int width, int height, const char *
{
#if defined(WIN32)
GraphicsWindow *platWin = new Win32Window(width, height, title);
#else
#elif defined(__linux__)
GraphicsWindow *platWin = new X11Window(width, height, 0, title);
#elif defined(__APPLE__)
GraphicsWindow *platWin = new AppleWindow(width, height, title);
#else
#error UNKNOWN PLATFORM
#endif
return new VulkanWindow(this, platWin);
@@ -1269,7 +1283,7 @@ VulkanWindow::VulkanWindow(VulkanGraphicsTest *test, GraphicsWindow *win)
createInfo.hinstance = GetModuleHandleA(NULL);
vkCreateWin32SurfaceKHR(m_Test->instance, &createInfo, NULL, &surface);
#else
#elif defined(__linux__)
VkXcbSurfaceCreateInfoKHR createInfo;
createInfo.sType = VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR;
@@ -1279,6 +1293,16 @@ VulkanWindow::VulkanWindow(VulkanGraphicsTest *test, GraphicsWindow *win)
createInfo.window = ((X11Window *)win)->xcb.window;
vkCreateXcbSurfaceKHR(m_Test->instance, &createInfo, NULL, &surface);
#elif defined(__APPLE__)
VkMacOSSurfaceCreateInfoMVK createInfo;
createInfo.sType = VK_STRUCTURE_TYPE_MACOS_SURFACE_CREATE_INFO_MVK;
createInfo.pNext = NULL;
createInfo.flags = 0;
createInfo.pView = ((AppleWindow *)win)->view;
vkCreateMacOSSurfaceMVK(m_Test->instance, &createInfo, NULL, &surface);
#else
#error UNKNOWN PLATFORM
#endif
}