Add MoltenVK support

SDL_Vulkan_LoadLibrary is used for macOS to keep 10.9 compatibility
This commit is contained in:
Benau 2021-06-10 13:21:11 +08:00
parent d5c848c4c2
commit 17d26338f8
12 changed files with 154 additions and 5 deletions

View File

@ -140,6 +140,8 @@ jobs:
lipo -create ./macosx-x86_64/supertuxkart.app/Contents/MacOS/supertuxkart ./macosx-arm64/supertuxkart.app/Contents/MacOS/supertuxkart -output ./macosx-arm64/supertuxkart.app/Contents/MacOS/supertuxkart
chmod 755 ./macosx-arm64/supertuxkart.app/Contents/MacOS/supertuxkart
dylibbundler -od -b -x ./macosx-arm64/supertuxkart.app/Contents/MacOS/supertuxkart -d ./macosx-arm64/supertuxkart.app/Contents/libs/ -p @executable_path/../libs/ -s dependencies-macosx/lib
# We use SDL_Vulkan_LoadLibrary for 10.9 compatibility, so otool -L supertuxkart has no libMoltenVK.dylib
cp ./dependencies-macosx/lib/libMoltenVK.dylib ./macosx-arm64/supertuxkart.app/Contents/libs/
cd ./macosx-arm64/supertuxkart.app/Contents/Resources/data
wget https://github.com/supertuxkart/stk-assets-mobile/releases/download/git/stk-assets-full.zip
unzip stk-assets-full.zip

View File

@ -26,7 +26,7 @@ if(NINTENDO_SWITCH)
endif()
if(WIN32)
option(USE_DIRECTX "Build DirectX 9 driver (requires DirectX SDK)" OFF)
option(USE_DIRECTX "Build DirectX 9 driver (requires DirectX SDK)" OFF)
endif()
option(SERVER_ONLY "Create a server only (i.e. no graphics or sound)" OFF)
@ -38,6 +38,11 @@ CMAKE_DEPENDENT_OPTION(USE_IPV6 "Allow create or connect to game server with IPv
option(USE_SYSTEM_WIIUSE "Use system WiiUse instead of the built-in version, when available." OFF)
option(USE_SQLITE3 "Use sqlite to manage server stats and ban list." ON)
if(APPLE)
CMAKE_DEPENDENT_OPTION(DLOPEN_MOLTENVK "Use dlopen to load MoltenVK for Apple." ON
"NOT IOS;NOT SERVER_ONLY" OFF)
endif()
CMAKE_DEPENDENT_OPTION(USE_CRYPTO_OPENSSL "Use OpenSSL instead of MbedTLS for cryptography in STK." ON
"NOT USE_SWITCH;NOT WIN32" OFF)
CMAKE_DEPENDENT_OPTION(BUILD_RECORDER "Build opengl recorder" ON
@ -49,6 +54,10 @@ CMAKE_DEPENDENT_OPTION(USE_WIIUSE "Support for wiimote input devices" ON
CMAKE_DEPENDENT_OPTION(USE_DNS_C "Build bundled dns resolver" OFF "NOT CYGWIN;NOT USE_SWITCH" ON)
CMAKE_DEPENDENT_OPTION(USE_MOJOAL "Use bundled MojoAL instead of system OpenAL" OFF "NOT APPLE" ON)
if (DLOPEN_MOLTENVK)
ADD_DEFINITIONS(-DDLOPEN_MOLTENVK)
endif()
if((UNIX AND NOT APPLE) OR NINTENDO_SWITCH)
include(FindPkgConfig)
endif()
@ -674,6 +683,10 @@ else()
endif()
if(NOT SERVER_ONLY)
if (APPLE AND NOT DLOPEN_MOLTENVK)
find_library(MOLTENVK_LIBRARY NAMES MoltenVK libMoltenVK REQUIRED)
target_link_libraries(supertuxkart "-framework Metal -weak_framework IOSurface -framework QuartzCore ${MOLTENVK_LIBRARY}")
endif()
if (IOS)
target_link_libraries(supertuxkart "-weak_framework CoreHaptics -framework QuartzCore -framework CoreGraphics -framework AVFoundation -framework AudioToolbox -framework Metal -framework GameController -framework OpenGLES -framework UIKit -framework CoreAudio -framework Foundation -framework GLKit")
# tvOS doesn't have CoreMotion framwork

View File

@ -7,7 +7,7 @@
# You can also use -DCMAKE_XCODE_ATTRIBUTE_DEVELOPMENT_TEAM=xxxxxxxxxx to specify team
# Increase every upload to App store
SET(IOS_BUILD_VERSION 23)
SET(IOS_BUILD_VERSION 24)
# Get SDK path
execute_process(COMMAND xcodebuild -version -sdk iphoneos Path
@ -57,6 +57,8 @@ set(SDL2_LIBRARY ${PROJECT_SOURCE_DIR}/dependencies\${EFFECTIVE_PLATFORM_NAME}/l
set(SDL2_INCLUDEDIR ${PROJECT_SOURCE_DIR}/dependencies-iphoneos/include/SDL2 CACHE STRING "")
set(LIBSAMPLERATE_LIBRARY ${PROJECT_SOURCE_DIR}/dependencies\${EFFECTIVE_PLATFORM_NAME}/lib/libsamplerate.a CACHE STRING "")
set(LIBSAMPLERATE_INCLUDEDIR ${PROJECT_SOURCE_DIR}/dependencies-iphoneos/include CACHE STRING "")
set(MOLTENVK_LIBRARY ${PROJECT_SOURCE_DIR}/dependencies\${EFFECTIVE_PLATFORM_NAME}/lib/libMoltenVK.a CACHE STRING "")
set(VULKAN_INCLUDEDIR ${PROJECT_SOURCE_DIR}/dependencies-iphoneos/include CACHE STRING "")
# For universal iOS and simulator
set(LIBRESOLV_LIBRARY -lresolv CACHE STRING "")

View File

@ -7,15 +7,30 @@ else()
include_directories("${SDL2_INCLUDEDIR}")
endif()
if(APPLE AND NOT DLOPEN_MOLTENVK)
find_path(VULKAN_INCLUDEDIR NAMES vulkan/vulkan.h PATHS)
if (NOT VULKAN_INCLUDEDIR)
message(FATAL_ERROR "Vulkan not found.")
else()
include_directories("${VULKAN_INCLUDEDIR}")
endif()
endif()
if(UNIX OR MINGW)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++0x")
endif()
add_library(graphics_engine STATIC
set(GE_SOURCES
src/gl.c
src/vulkan.c
src/ge_main.cpp
src/ge_texture.cpp
src/ge_dx9_texture.cpp
src/ge_vulkan_driver.cpp
src/ge_gl_texture.cpp
)
if(NOT APPLE OR DLOPEN_MOLTENVK)
set(GE_SOURCES ${GE_SOURCES} src/vulkan.c)
endif()
add_library(graphics_engine STATIC ${GE_SOURCES})

View File

@ -5,7 +5,7 @@
#ifdef _IRR_COMPILE_WITH_VULKAN_
#include "glad/vulkan.h"
#include "vulkan_wrapper.h"
#include "SDL_video.h"
#include "../source/Irrlicht/CNullDriver.h"

View File

@ -0,0 +1,10 @@
#ifndef HEADER_VULKAN_WRAPPER_HPP
#define HEADER_VULKAN_WRAPPER_HPP
#if !defined(__APPLE__) || defined(DLOPEN_MOLTENVK)
#include <glad/vulkan.h>
#else
#include <vulkan/vulkan.h>
#endif
#endif

View File

@ -8,6 +8,7 @@
#include "../source/Irrlicht/os.h"
#if !defined(__APPLE__) || defined(DLOPEN_MOLTENVK)
struct GE_VK_UserPointer
{
VkInstance instance;
@ -430,6 +431,7 @@ extern "C" PFN_vkVoidFunction loader(void* user_ptr, const char* name)
return NULL;
return get_instance_proc_addr(instance, name);
} // loader
#endif
namespace GE
{
@ -446,6 +448,7 @@ GEVulkanDriver::GEVulkanDriver(const SIrrlichtCreationParameters& params,
createInstance(window);
#if !defined(__APPLE__) || defined(DLOPEN_MOLTENVK)
GE_VK_UserPointer user_ptr = {};
user_ptr.instance = m_vk.instance;
if (gladLoadVulkanUserPtr(NULL,
@ -454,12 +457,15 @@ GEVulkanDriver::GEVulkanDriver(const SIrrlichtCreationParameters& params,
throw std::runtime_error("gladLoadVulkanUserPtr failed "
"with non-NULL instance");
}
#endif
if (SDL_Vulkan_CreateSurface(window, m_vk.instance, &m_vk.surface) == SDL_FALSE)
throw std::runtime_error("SDL_Vulkan_CreateSurface failed");
m_device_extensions.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
findPhysicalDevice();
createDevice();
#if !defined(__APPLE__) || defined(DLOPEN_MOLTENVK)
user_ptr.device = m_vk.device;
if (gladLoadVulkanUserPtr(m_physical_device,
(GLADuserptrloadfunc)loader, &user_ptr) == 0)
@ -467,6 +473,7 @@ GEVulkanDriver::GEVulkanDriver(const SIrrlichtCreationParameters& params,
throw std::runtime_error("gladLoadVulkanUserPtr failed with "
"non-NULL instance and non-NULL m_physical_device");
}
#endif
vkGetPhysicalDeviceProperties(m_physical_device, &m_properties);
os::Printer::log("Vulkan version", getVulkanVersionString().c_str());
@ -485,10 +492,13 @@ GEVulkanDriver::~GEVulkanDriver()
// ----------------------------------------------------------------------------
void GEVulkanDriver::createInstance(SDL_Window* window)
{
#if !defined(__APPLE__) || defined(DLOPEN_MOLTENVK)
if (gladLoadVulkanUserPtr(NULL, (GLADuserptrloadfunc)loader, NULL) == 0)
{
throw std::runtime_error("gladLoadVulkanUserPtr failed 1st time");
}
#endif
unsigned int count = 0;
if (!SDL_Vulkan_GetInstanceExtensions(window, &count, NULL))
throw std::runtime_error("SDL_Vulkan_GetInstanceExtensions failed with NULL extensions");

View File

@ -531,6 +531,15 @@ include/vector2d.h
include/vector3d.h
)
if(DLOPEN_MOLTENVK)
set(IRRLICHT_SOURCES
${IRRLICHT_SOURCES}
source/Irrlicht/MoltenVK.mm
source/Irrlicht/MoltenVK.h)
set_source_files_properties(source/Irrlicht/MoltenVK.mm PROPERTIES COMPILE_FLAGS "-x objective-c++ -O3 -fno-rtti")
set_source_files_properties(source/Irrlicht/MoltenVK.mm PROPERTIES LANGUAGE C)
endif()
if(IOS)
set(IRRLICHT_SOURCES
${IRRLICHT_SOURCES}

View File

@ -21,6 +21,7 @@
#include "guiengine/engine.hpp"
#include "glad/gl.h"
#include "MoltenVK.h"
extern bool GLContextDebugBit;
@ -71,6 +72,10 @@ CIrrDeviceSDL::CIrrDeviceSDL(const SIrrlichtCreationParameters& param)
setDebugName("CIrrDeviceSDL");
#endif
#ifdef DLOPEN_MOLTENVK
m_moltenvk = NULL;
#endif
Operator = 0;
// Initialize SDL... Timer for sleep, video for the obvious, and
// noparachute prevents SDL from catching fatal errors.
@ -194,6 +199,9 @@ CIrrDeviceSDL::~CIrrDeviceSDL()
VideoDriver->drop();
VideoDriver = NULL;
}
#ifdef DLOPEN_MOLTENVK
delete m_moltenvk;
#endif
if (Context)
SDL_GL_DeleteContext(Context);
if (Window)
@ -359,7 +367,17 @@ bool CIrrDeviceSDL::createWindow()
CreationParams.DriverType == video::EDT_OGLES2)
flags |= SDL_WINDOW_OPENGL;
else if (CreationParams.DriverType == video::EDT_VULKAN)
{
#ifdef DLOPEN_MOLTENVK
m_moltenvk = new MoltenVK();
if (!m_moltenvk->loaded())
{
os::Printer::log("Current MacOSX version doesn't support Vulkan or MoltenVK failed to load", ELL_WARNING);
return false;
}
#endif
flags |= SDL_WINDOW_VULKAN;
}
#ifdef MOBILE_STK
flags |= SDL_WINDOW_BORDERLESS | SDL_WINDOW_MAXIMIZED;

View File

@ -23,6 +23,7 @@
namespace irr
{
class MoltenVK;
class CIrrDeviceSDL : public CIrrDeviceStub, video::IImagePresenter
{
@ -323,6 +324,9 @@ namespace irr
std::map<SDL_Scancode, irr::EKEY_CODE> ScanCodeMap;
SDL_SysWMinfo Info;
void tryCreateOpenGLContext(u32 flags);
#ifdef DLOPEN_MOLTENVK
MoltenVK* m_moltenvk;
#endif
};
} // end namespace irr

View File

@ -0,0 +1,23 @@
#ifndef HEADER_MAC_VULKAN_HPP
#define HEADER_MAC_VULKAN_HPP
#ifdef DLOPEN_MOLTENVK
namespace irr
{
class MoltenVK
{
private:
bool m_loaded;
public:
// ------------------------------------------------------------------------
MoltenVK();
// ------------------------------------------------------------------------
~MoltenVK();
// ------------------------------------------------------------------------
bool loaded() const { return m_loaded; }
};
}
#endif
#endif

View File

@ -0,0 +1,43 @@
#include "MoltenVK.h"
#include "SDL_vulkan.h"
#import <AppKit/NSApplication.h>
#ifdef DLOPEN_MOLTENVK
namespace irr
{
// ----------------------------------------------------------------------------
MoltenVK::MoltenVK()
{
m_loaded = false;
// MacOSX 10.11 or later supports Metal (MoltenVK)
if (floor(NSAppKitVersionNumber) <= NSAppKitVersionNumber10_10_Max)
return;
const char* paths[3] =
{
// STK release binary path after dylibbundler
"@executable_path/../libs/libMoltenVK.dylib",
// bin/supertuxkart.app/Contents/MacOS/supertuxkart
"@executable_path/../../../../../dependencies-macosx/lib/libMoltenVK.dylib",
"NULL"
};
for (int i = 0; i < 3; i++)
{
if (SDL_Vulkan_LoadLibrary(paths[i]) == 0)
{
m_loaded = true;
break;
}
}
} // MoltenVK
// ----------------------------------------------------------------------------
MoltenVK::~MoltenVK()
{
if (m_loaded)
SDL_Vulkan_UnloadLibrary();
} // ~MoltenVK
#endif
}