From 25e3a1ec90cbc08acbb1d33668ad71e6ca241e05 Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Sun, 27 Aug 2017 22:15:57 -0400 Subject: [PATCH] vulkan: Initial Vulkan support! This work was done by Jacob Lifshay and Mark Callow; I'm just merging it into revision control. --- CMakeLists.txt | 36 + Makefile.in | 1 + VisualC/SDL/SDL_VS2008.vcproj | 44 +- VisualC/SDL_VS2008.sln | 11 + .../tests/testvulkan/testvulkan_VS2008.vcproj | 355 +++++ Xcode-iOS/SDL/SDL.xcodeproj/project.pbxproj | 37 + Xcode/SDL/SDL.xcodeproj/project.pbxproj | 106 +- cmake/sdlchecks.cmake | 19 + configure | 107 +- configure.in | 66 + debian/control | 1 + docs/README-ios.md | 13 +- docs/README-linux.md | 4 +- docs/README-macosx.md | 14 +- docs/README-windows.md | 86 +- include/SDL.h | 1 + include/SDL_config.h.cmake | 3 + include/SDL_config.h.in | 3 + include/SDL_config_android.h | 8 + include/SDL_config_iphoneos.h | 7 + include/SDL_config_macosx.h | 8 + include/SDL_config_windows.h | 1 + include/SDL_video.h | 28 +- include/SDL_vulkan.h | 251 ++++ src/test/SDL_test_common.c | 2 +- src/video/SDL_sysvideo.h | 22 + src/video/SDL_video.c | 160 ++- src/video/SDL_vulkan_internal.h | 80 ++ src/video/SDL_vulkan_utils.c | 191 +++ src/video/android/SDL_androidvideo.c | 8 + src/video/android/SDL_androidvulkan.c | 174 +++ src/video/android/SDL_androidvulkan.h | 52 + src/video/cocoa/SDL_cocoametalview.h | 61 + src/video/cocoa/SDL_cocoametalview.m | 124 ++ src/video/cocoa/SDL_cocoavideo.m | 9 + src/video/cocoa/SDL_cocoavulkan.h | 55 + src/video/cocoa/SDL_cocoavulkan.m | 217 +++ src/video/mir/SDL_mirvideo.c | 8 + src/video/mir/SDL_mirvideo.h | 1 + src/video/mir/SDL_mirvulkan.c | 175 +++ src/video/mir/SDL_mirvulkan.h | 52 + src/video/uikit/SDL_uikitmetalview.h | 53 + src/video/uikit/SDL_uikitmetalview.m | 146 ++ src/video/uikit/SDL_uikitvideo.m | 10 + src/video/uikit/SDL_uikitvulkan.h | 54 + src/video/uikit/SDL_uikitvulkan.m | 221 +++ src/video/wayland/SDL_waylandvideo.c | 8 + src/video/wayland/SDL_waylandvulkan.c | 175 +++ src/video/wayland/SDL_waylandvulkan.h | 52 + src/video/windows/SDL_windowsvideo.c | 8 + src/video/windows/SDL_windowsvulkan.c | 176 +++ src/video/windows/SDL_windowsvulkan.h | 52 + src/video/x11/SDL_x11video.c | 12 + src/video/x11/SDL_x11video.h | 7 + src/video/x11/SDL_x11vulkan.c | 239 ++++ src/video/x11/SDL_x11vulkan.h | 48 + test/Makefile.in | 4 + test/configure | 456 ++++++- test/configure.in | 19 + test/testvulkan.c | 1195 +++++++++++++++++ 60 files changed, 5456 insertions(+), 80 deletions(-) create mode 100644 VisualC/tests/testvulkan/testvulkan_VS2008.vcproj create mode 100644 include/SDL_vulkan.h create mode 100644 src/video/SDL_vulkan_internal.h create mode 100644 src/video/SDL_vulkan_utils.c create mode 100644 src/video/android/SDL_androidvulkan.c create mode 100644 src/video/android/SDL_androidvulkan.h create mode 100644 src/video/cocoa/SDL_cocoametalview.h create mode 100644 src/video/cocoa/SDL_cocoametalview.m create mode 100644 src/video/cocoa/SDL_cocoavulkan.h create mode 100644 src/video/cocoa/SDL_cocoavulkan.m create mode 100644 src/video/mir/SDL_mirvulkan.c create mode 100644 src/video/mir/SDL_mirvulkan.h create mode 100644 src/video/uikit/SDL_uikitmetalview.h create mode 100644 src/video/uikit/SDL_uikitmetalview.m create mode 100644 src/video/uikit/SDL_uikitvulkan.h create mode 100644 src/video/uikit/SDL_uikitvulkan.m create mode 100644 src/video/wayland/SDL_waylandvulkan.c create mode 100644 src/video/wayland/SDL_waylandvulkan.h create mode 100644 src/video/windows/SDL_windowsvulkan.c create mode 100644 src/video/windows/SDL_windowsvulkan.h create mode 100644 src/video/x11/SDL_x11vulkan.c create mode 100644 src/video/x11/SDL_x11vulkan.h create mode 100644 test/testvulkan.c diff --git a/CMakeLists.txt b/CMakeLists.txt index ad86399ed02f6..f725d5984aef1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -20,6 +20,7 @@ include(CheckLibraryExists) include(CheckIncludeFiles) include(CheckIncludeFile) include(CheckSymbolExists) +include(CheckCSourceCompiles) include(CheckCSourceRuns) include(CheckCCompilerFlag) include(CheckTypeSize) @@ -324,9 +325,14 @@ set_option(VIDEO_COCOA "Use Cocoa video driver" ${APPLE}) set_option(DIRECTX "Use DirectX for Windows audio/video" ${WINDOWS}) set_option(RENDER_D3D "Enable the Direct3D render driver" ${WINDOWS}) set_option(VIDEO_VIVANTE "Use Vivante EGL video driver" ${UNIX_SYS}) +dep_option(VIDEO_VULKAN "Enable Vulkan surface creation" ON "ANDROID OR APPLE OR LINUX OR WINDOWS" OFF) set_option(VIDEO_KMSDRM "Use KMS DRM video driver" ${UNIX_SYS}) dep_option(KMSDRM_SHARED "Dynamically load KMS DRM support" ON "VIDEO_KMSDRM" OFF) +if(VIDEO_VULKAN) + set(VULKAN_SDK $ENV{VULKAN_SDK} CACHE PATH "Location of Vulkan headers' grandparent, e.g. /foo when headers are in /foo/include/vulkan.") +endif() + # TODO: We should (should we?) respect cmake's ${BUILD_SHARED_LIBS} flag here # The options below are for compatibility to configure's default behaviour. set(SDL_SHARED ${SDL_SHARED_ENABLED_BY_DEFAULT} CACHE BOOL "Build a shared version of the library") @@ -855,6 +861,22 @@ if(ANDROID) find_library(OpenGLES2_LIBRARY GLESv2) list(APPEND EXTRA_LIBS ${OpenGLES1_LIBRARY} ${OpenGLES2_LIBRARY}) endif() + + CHECK_C_SOURCE_COMPILES(" + #if defined(__ANDROID__) && defined(__ARM_EABI__) && !defined(__ARM_ARCH_7A__) + #error Vulkan doesn't work on this configuration + #endif + int main() + { + return 0; + } + " VULKAN_PASSED_ANDROID_CHECKS) + if(NOT VULKAN_PASSED_ANDROID_CHECKS) + set(VIDEO_VULKAN OFF) + message(STATUS "Vulkan doesn't work on this configuration") + else() + CheckVulkanHeaders() + endif() endif() CheckPTHREAD() @@ -1020,6 +1042,7 @@ elseif(UNIX AND NOT APPLE AND NOT ANDROID) check_include_file("fcitx/frontend.h" HAVE_FCITX_FRONTEND_H) + CheckVulkanHeaders() endif() if(INPUT_TSLIB) @@ -1278,6 +1301,8 @@ elseif(WINDOWS) set(SDL_VIDEO_RENDER_OGL_ES2 1) set(HAVE_VIDEO_OPENGLES TRUE) endif() + + CheckVulkanHeaders() endif() if(SDL_JOYSTICK) @@ -1419,6 +1444,13 @@ elseif(APPLE) endif() # Actually load the frameworks at the end so we don't duplicate include. + if (VIDEO_VULKAN) + CheckVulkanHeaders() + if(HAVE_VULKAN_H) + find_library(QUARTZCORE QuartzCore) + list(APPEND EXTRA_LIBS ${QUARTZCORE}) + endif() + endif() if(SDL_FRAMEWORK_COREVIDEO) find_library(COREVIDEO CoreVideo) list(APPEND EXTRA_LIBS ${COREVIDEO}) @@ -1498,6 +1530,10 @@ elseif(HAIKU) CheckPTHREAD() endif() +if(VIDEO_VULKAN AND HAVE_VULKAN_H AND (NOT APPLE OR QUARTZCORE)) + set(SDL_VIDEO_VULKAN_SURFACE 1) +endif() + # Dummies # configure.in does it differently: # if not have X diff --git a/Makefile.in b/Makefile.in index f6d12cdf9cb46..fe566523de9ab 100644 --- a/Makefile.in +++ b/Makefile.in @@ -112,6 +112,7 @@ HDRS = \ SDL_types.h \ SDL_version.h \ SDL_video.h \ + SDL_vulkan.h \ begin_code.h \ close_code.h diff --git a/VisualC/SDL/SDL_VS2008.vcproj b/VisualC/SDL/SDL_VS2008.vcproj index fd90b8145a4c1..a5ea1d0c514d4 100644 --- a/VisualC/SDL/SDL_VS2008.vcproj +++ b/VisualC/SDL/SDL_VS2008.vcproj @@ -52,7 +52,7 @@ Name="VCCLCompilerTool" Optimization="0" InlineFunctionExpansion="1" - AdditionalIncludeDirectories="$(SolutionDir)/../include" + AdditionalIncludeDirectories=""$(SolutionDir)/../include";"$(VULKAN_SDK)/include"" AdditionalUsingDirectories="" PreprocessorDefinitions="_DEBUG;_WINDOWS" RuntimeLibrary="2" @@ -135,7 +135,7 @@ Name="VCCLCompilerTool" Optimization="0" InlineFunctionExpansion="1" - AdditionalIncludeDirectories="$(SolutionDir)/../include" + AdditionalIncludeDirectories=""$(SolutionDir)/../include";"$(VULKAN_SDK)/include"" AdditionalUsingDirectories="" PreprocessorDefinitions="_DEBUG;_WINDOWS" RuntimeLibrary="2" @@ -216,7 +216,7 @@ + + + + + + @@ -1313,6 +1325,22 @@ RelativePath="..\..\src\audio\wasapi\SDL_wasapi.h" > + + + + + + + + @@ -1437,6 +1465,14 @@ RelativePath="..\..\src\video\windows\SDL_windowsvideo.h" > + + + + diff --git a/VisualC/SDL_VS2008.sln b/VisualC/SDL_VS2008.sln index 5398bfb2290e6..83c3ccf779892 100644 --- a/VisualC/SDL_VS2008.sln +++ b/VisualC/SDL_VS2008.sln @@ -48,6 +48,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "controllermap", "tests\cont EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{D69D5741-611F-4E14-8541-1FEE94F50B5A}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testvulkan", "tests\testvulkan\testvulkan_VS2008.vcproj", "{0D604DFD-AAB6-442C-9368-F91A344146AB}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 @@ -240,6 +242,14 @@ Global {55812185-D13C-4022-9C81-32E0F4A08306}.Release|Win32.Build.0 = Release|Win32 {55812185-D13C-4022-9C81-32E0F4A08306}.Release|x64.ActiveCfg = Release|x64 {55812185-D13C-4022-9C81-32E0F4A08306}.Release|x64.Build.0 = Release|x64 + {0D604DFD-AAB6-442C-9368-F91A344146AB}.Debug|Win32.ActiveCfg = Debug|Win32 + {0D604DFD-AAB6-442C-9368-F91A344146AB}.Debug|Win32.Build.0 = Debug|Win32 + {0D604DFD-AAB6-442C-9368-F91A344146AB}.Debug|x64.ActiveCfg = Debug|x64 + {0D604DFD-AAB6-442C-9368-F91A344146AB}.Debug|x64.Build.0 = Debug|x64 + {0D604DFD-AAB6-442C-9368-F91A344146AB}.Release|Win32.ActiveCfg = Release|Win32 + {0D604DFD-AAB6-442C-9368-F91A344146AB}.Release|Win32.Build.0 = Release|Win32 + {0D604DFD-AAB6-442C-9368-F91A344146AB}.Release|x64.ActiveCfg = Release|x64 + {0D604DFD-AAB6-442C-9368-F91A344146AB}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -265,5 +275,6 @@ Global {E9558DFE-1961-4DD4-B09B-DD0EEFD5C315} = {D69D5741-611F-4E14-8541-1FEE94F50B5A} {55812185-D13C-4022-9C81-32E0F4A08306} = {D69D5741-611F-4E14-8541-1FEE94F50B5A} {26828762-C95D-4637-9CB1-7F0979523813} = {D69D5741-611F-4E14-8541-1FEE94F50B5A} + {0D604DFD-AAB6-442C-9368-F91A344146AB} = {D69D5741-611F-4E14-8541-1FEE94F50B5A} EndGlobalSection EndGlobal diff --git a/VisualC/tests/testvulkan/testvulkan_VS2008.vcproj b/VisualC/tests/testvulkan/testvulkan_VS2008.vcproj new file mode 100644 index 0000000000000..f8da23fa3a276 --- /dev/null +++ b/VisualC/tests/testvulkan/testvulkan_VS2008.vcproj @@ -0,0 +1,355 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Xcode-iOS/SDL/SDL.xcodeproj/project.pbxproj b/Xcode-iOS/SDL/SDL.xcodeproj/project.pbxproj index d1bacc1f84754..19c472794adf4 100755 --- a/Xcode-iOS/SDL/SDL.xcodeproj/project.pbxproj +++ b/Xcode-iOS/SDL/SDL.xcodeproj/project.pbxproj @@ -67,6 +67,13 @@ 04F7808512FB753F00FC43C0 /* SDL_nullframebuffer.c in Sources */ = {isa = PBXBuildFile; fileRef = 04F7808312FB753F00FC43C0 /* SDL_nullframebuffer.c */; }; 04FFAB8B12E23B8D00BA343D /* SDL_atomic.c in Sources */ = {isa = PBXBuildFile; fileRef = 04FFAB8912E23B8D00BA343D /* SDL_atomic.c */; }; 04FFAB8C12E23B8D00BA343D /* SDL_spinlock.c in Sources */ = {isa = PBXBuildFile; fileRef = 04FFAB8A12E23B8D00BA343D /* SDL_spinlock.c */; }; + 4D7516FB1EE1C28A00820EEA /* SDL_uikitmetalview.m in Sources */ = {isa = PBXBuildFile; fileRef = 4D7516F81EE1C28A00820EEA /* SDL_uikitmetalview.m */; }; + 4D7516FC1EE1C28A00820EEA /* SDL_uikitvulkan.h in Headers */ = {isa = PBXBuildFile; fileRef = 4D7516F91EE1C28A00820EEA /* SDL_uikitvulkan.h */; }; + 4D7516FD1EE1C28A00820EEA /* SDL_uikitvulkan.m in Sources */ = {isa = PBXBuildFile; fileRef = 4D7516FA1EE1C28A00820EEA /* SDL_uikitvulkan.m */; }; + 4D7516FF1EE1C5B400820EEA /* SDL_vulkan.h in Headers */ = {isa = PBXBuildFile; fileRef = 4D7516FE1EE1C5B400820EEA /* SDL_vulkan.h */; }; + 4D75171A1EE1D32200820EEA /* SDL_uikitmetalview.h in Headers */ = {isa = PBXBuildFile; fileRef = 4D7517191EE1D32200820EEA /* SDL_uikitmetalview.h */; }; + 4D75171F1EE1D98200820EEA /* SDL_vulkan_internal.h in Headers */ = {isa = PBXBuildFile; fileRef = 4D75171D1EE1D98200820EEA /* SDL_vulkan_internal.h */; }; + 4D7517201EE1D98200820EEA /* SDL_vulkan_utils.c in Sources */ = {isa = PBXBuildFile; fileRef = 4D75171E1EE1D98200820EEA /* SDL_vulkan_utils.c */; }; 566726451DF72CF5001DD3DB /* SDL_dataqueue.c in Sources */ = {isa = PBXBuildFile; fileRef = 566726431DF72CF5001DD3DB /* SDL_dataqueue.c */; }; 566726461DF72CF5001DD3DB /* SDL_dataqueue.h in Headers */ = {isa = PBXBuildFile; fileRef = 566726441DF72CF5001DD3DB /* SDL_dataqueue.h */; }; 56A6702E18565E450007D20F /* SDL_internal.h in Headers */ = {isa = PBXBuildFile; fileRef = 56A6702D18565E450007D20F /* SDL_internal.h */; }; @@ -364,6 +371,13 @@ 04F7808312FB753F00FC43C0 /* SDL_nullframebuffer.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SDL_nullframebuffer.c; sourceTree = ""; }; 04FFAB8912E23B8D00BA343D /* SDL_atomic.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SDL_atomic.c; sourceTree = ""; }; 04FFAB8A12E23B8D00BA343D /* SDL_spinlock.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SDL_spinlock.c; sourceTree = ""; }; + 4D7516F81EE1C28A00820EEA /* SDL_uikitmetalview.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDL_uikitmetalview.m; sourceTree = ""; }; + 4D7516F91EE1C28A00820EEA /* SDL_uikitvulkan.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDL_uikitvulkan.h; sourceTree = ""; }; + 4D7516FA1EE1C28A00820EEA /* SDL_uikitvulkan.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDL_uikitvulkan.m; sourceTree = ""; }; + 4D7516FE1EE1C5B400820EEA /* SDL_vulkan.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDL_vulkan.h; sourceTree = ""; }; + 4D7517191EE1D32200820EEA /* SDL_uikitmetalview.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDL_uikitmetalview.h; sourceTree = ""; }; + 4D75171D1EE1D98200820EEA /* SDL_vulkan_internal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDL_vulkan_internal.h; sourceTree = ""; }; + 4D75171E1EE1D98200820EEA /* SDL_vulkan_utils.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SDL_vulkan_utils.c; sourceTree = ""; }; 566726431DF72CF5001DD3DB /* SDL_dataqueue.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = SDL_dataqueue.c; path = ../../src/SDL_dataqueue.c; sourceTree = ""; }; 566726441DF72CF5001DD3DB /* SDL_dataqueue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SDL_dataqueue.h; path = ../../src/SDL_dataqueue.h; sourceTree = ""; }; 56A6702D18565E450007D20F /* SDL_internal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SDL_internal.h; path = ../../src/SDL_internal.h; sourceTree = ""; }; @@ -759,6 +773,8 @@ FD689F0D0E26E5D900F90B21 /* SDL_uikitevents.m */, AABCC3921640643D00AB8930 /* SDL_uikitmessagebox.h */, AABCC3931640643D00AB8930 /* SDL_uikitmessagebox.m */, + 4D7517191EE1D32200820EEA /* SDL_uikitmetalview.h */, + 4D7516F81EE1C28A00820EEA /* SDL_uikitmetalview.m */, AA126AD21617C5E6005ABC8F /* SDL_uikitmodes.h */, AA126AD31617C5E6005ABC8F /* SDL_uikitmodes.m */, FD689F0E0E26E5D900F90B21 /* SDL_uikitopengles.h */, @@ -771,6 +787,8 @@ FD689F130E26E5D900F90B21 /* SDL_uikitview.m */, 93CB792213FC5E5200BD3E05 /* SDL_uikitviewcontroller.h */, 93CB792513FC5F5300BD3E05 /* SDL_uikitviewcontroller.m */, + 4D7516F91EE1C28A00820EEA /* SDL_uikitvulkan.h */, + 4D7516FA1EE1C28A00820EEA /* SDL_uikitvulkan.m */, FD689F140E26E5D900F90B21 /* SDL_uikitwindow.h */, FD689F150E26E5D900F90B21 /* SDL_uikitwindow.m */, ); @@ -852,6 +870,7 @@ AA7558941595D55500BBD41B /* SDL_types.h */, AA7558951595D55500BBD41B /* SDL_version.h */, AA7558961595D55500BBD41B /* SDL_video.h */, + 4D7516FE1EE1C5B400820EEA /* SDL_vulkan.h */, ); name = "Public Headers"; path = ../../include; @@ -1041,6 +1060,8 @@ FDA683190DF2374E00F98A1A /* SDL_surface.c */, FDA6831A0DF2374E00F98A1A /* SDL_sysvideo.h */, FDA6831B0DF2374E00F98A1A /* SDL_video.c */, + 4D75171D1EE1D98200820EEA /* SDL_vulkan_internal.h */, + 4D75171E1EE1D98200820EEA /* SDL_vulkan_utils.c */, ); name = video; path = ../../src/video; @@ -1067,6 +1088,8 @@ buildActionMask = 2147483647; files = ( FDA6844E0DF2374E00F98A1A /* SDL_blit.h in Headers */, + 4D75171A1EE1D32200820EEA /* SDL_uikitmetalview.h in Headers */, + 4D75171F1EE1D98200820EEA /* SDL_vulkan_internal.h in Headers */, FDA684530DF2374E00F98A1A /* SDL_blit_auto.h in Headers */, FDA684550DF2374E00F98A1A /* SDL_blit_copy.h in Headers */, FDA6845D0DF2374E00F98A1A /* SDL_pixels_c.h in Headers */, @@ -1159,8 +1182,10 @@ AA7558C61595D55500BBD41B /* SDL_touch.h in Headers */, AA7558C71595D55500BBD41B /* SDL_types.h in Headers */, AA7558C81595D55500BBD41B /* SDL_version.h in Headers */, + 4D7516FF1EE1C5B400820EEA /* SDL_vulkan.h in Headers */, AA7558C91595D55500BBD41B /* SDL_video.h in Headers */, AA7558CA1595D55500BBD41B /* SDL.h in Headers */, + 4D7516FC1EE1C28A00820EEA /* SDL_uikitvulkan.h in Headers */, AA126AD41617C5E7005ABC8F /* SDL_uikitmodes.h in Headers */, AA704DD6162AA90A0076D1C1 /* SDL_dropevents_c.h in Headers */, AA9FF9511637C6E5000DF050 /* SDL_messagebox.h in Headers */, @@ -1213,8 +1238,15 @@ attributes = { LastUpgradeCheck = 0800; TargetAttributes = { + 00B4F48B12F6A69C0084EC00 = { + DevelopmentTeam = UZ5V327NE3; + }; FAB598131BB5C1B100BE72C5 = { CreatedOnToolsVersion = 7.1; + DevelopmentTeam = UZ5V327NE3; + }; + FD6526620DE8FCCB002AD96B = { + DevelopmentTeam = UZ5V327NE3; }; }; }; @@ -1373,6 +1405,7 @@ FD65266A0DE8FCDD002AD96B /* SDL_audiotypecvt.c in Sources */, FD65266B0DE8FCDD002AD96B /* SDL_mixer.c in Sources */, FD65266F0DE8FCDD002AD96B /* SDL_wave.c in Sources */, + 4D7516FD1EE1C28A00820EEA /* SDL_uikitvulkan.m in Sources */, FA1DC2731C62BE65008F99A0 /* SDL_uikitclipboard.m in Sources */, FD6526700DE8FCDD002AD96B /* SDL_cpuinfo.c in Sources */, FD6526710DE8FCDD002AD96B /* SDL_events.c in Sources */, @@ -1381,7 +1414,9 @@ FD6526730DE8FCDD002AD96B /* SDL_mouse.c in Sources */, FD6526740DE8FCDD002AD96B /* SDL_quit.c in Sources */, FD6526750DE8FCDD002AD96B /* SDL_windowevents.c in Sources */, + 4D7516FB1EE1C28A00820EEA /* SDL_uikitmetalview.m in Sources */, FD6526760DE8FCDD002AD96B /* SDL_rwops.c in Sources */, + 4D7517201EE1D98200820EEA /* SDL_vulkan_utils.c in Sources */, FD6526780DE8FCDD002AD96B /* SDL_error.c in Sources */, FD65267A0DE8FCDD002AD96B /* SDL.c in Sources */, FD65267B0DE8FCDD002AD96B /* SDL_syscond.c in Sources */, @@ -1613,6 +1648,7 @@ GCC_WARN_MULTIPLE_DEFINITION_TYPES_FOR_SELECTOR = YES; GCC_WARN_STRICT_SELECTOR_MATCH = YES; GCC_WARN_UNDECLARED_SELECTOR = YES; + HEADER_SEARCH_PATHS = "$(VULKAN_SDK)/include"; PRODUCT_NAME = SDL2; SKIP_INSTALL = YES; }; @@ -1628,6 +1664,7 @@ GCC_WARN_MULTIPLE_DEFINITION_TYPES_FOR_SELECTOR = YES; GCC_WARN_STRICT_SELECTOR_MATCH = YES; GCC_WARN_UNDECLARED_SELECTOR = YES; + HEADER_SEARCH_PATHS = "$(VULKAN_SDK)/include"; PRODUCT_NAME = SDL2; SKIP_INSTALL = YES; }; diff --git a/Xcode/SDL/SDL.xcodeproj/project.pbxproj b/Xcode/SDL/SDL.xcodeproj/project.pbxproj index 1a63d02a4f27b..e075e15c36216 100755 --- a/Xcode/SDL/SDL.xcodeproj/project.pbxproj +++ b/Xcode/SDL/SDL.xcodeproj/project.pbxproj @@ -377,6 +377,25 @@ 04F7805D12FB74A200FC43C0 /* SDL_drawline.h in Headers */ = {isa = PBXBuildFile; fileRef = 04F7804512FB74A200FC43C0 /* SDL_drawline.h */; }; 04F7805E12FB74A200FC43C0 /* SDL_drawpoint.c in Sources */ = {isa = PBXBuildFile; fileRef = 04F7804612FB74A200FC43C0 /* SDL_drawpoint.c */; }; 04F7805F12FB74A200FC43C0 /* SDL_drawpoint.h in Headers */ = {isa = PBXBuildFile; fileRef = 04F7804712FB74A200FC43C0 /* SDL_drawpoint.h */; }; + 4D16644B1EDD5FE8003DE88E /* SDL_vulkan.h in Headers */ = {isa = PBXBuildFile; fileRef = 4D16644A1EDD5FE8003DE88E /* SDL_vulkan.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 4D16644E1EDD6023003DE88E /* SDL_vulkan_internal.h in Headers */ = {isa = PBXBuildFile; fileRef = 4D16644C1EDD6023003DE88E /* SDL_vulkan_internal.h */; }; + 4D16644F1EDD6023003DE88E /* SDL_vulkan_utils.c in Sources */ = {isa = PBXBuildFile; fileRef = 4D16644D1EDD6023003DE88E /* SDL_vulkan_utils.c */; }; + 4D1664531EDD60AD003DE88E /* SDL_cocoametalview.m in Sources */ = {isa = PBXBuildFile; fileRef = 4D1664501EDD60AD003DE88E /* SDL_cocoametalview.m */; }; + 4D1664541EDD60AD003DE88E /* SDL_cocoavulkan.h in Headers */ = {isa = PBXBuildFile; fileRef = 4D1664511EDD60AD003DE88E /* SDL_cocoavulkan.h */; }; + 4D1664551EDD60AD003DE88E /* SDL_cocoavulkan.m in Sources */ = {isa = PBXBuildFile; fileRef = 4D1664521EDD60AD003DE88E /* SDL_cocoavulkan.m */; }; + 4D1664561EDD61DA003DE88E /* SDL_vulkan_utils.c in Sources */ = {isa = PBXBuildFile; fileRef = 4D16644D1EDD6023003DE88E /* SDL_vulkan_utils.c */; }; + 4D1664571EDD61F0003DE88E /* SDL_cocoametalview.m in Sources */ = {isa = PBXBuildFile; fileRef = 4D1664501EDD60AD003DE88E /* SDL_cocoametalview.m */; }; + 4D1664581EDD61F0003DE88E /* SDL_cocoavulkan.m in Sources */ = {isa = PBXBuildFile; fileRef = 4D1664521EDD60AD003DE88E /* SDL_cocoavulkan.m */; }; + 4D1664591EDD621B003DE88E /* SDL_vulkan_utils.c in Sources */ = {isa = PBXBuildFile; fileRef = 4D16644D1EDD6023003DE88E /* SDL_vulkan_utils.c */; }; + 4D16645A1EDD6235003DE88E /* SDL_cocoametalview.m in Sources */ = {isa = PBXBuildFile; fileRef = 4D1664501EDD60AD003DE88E /* SDL_cocoametalview.m */; }; + 4D16645B1EDD6235003DE88E /* SDL_cocoavulkan.m in Sources */ = {isa = PBXBuildFile; fileRef = 4D1664521EDD60AD003DE88E /* SDL_cocoavulkan.m */; }; + 4D16645E1EDD73E0003DE88E /* Metal.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4D16645D1EDD73E0003DE88E /* Metal.framework */; }; + 4D16645F1EDD73FE003DE88E /* Metal.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4D16645D1EDD73E0003DE88E /* Metal.framework */; }; + 4D1664601EDD741F003DE88E /* Metal.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4D16645D1EDD73E0003DE88E /* Metal.framework */; }; + 4D1664641EDD7528003DE88E /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4D1664611EDD74A9003DE88E /* QuartzCore.framework */; }; + 4D1664651EDD7727003DE88E /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4D1664611EDD74A9003DE88E /* QuartzCore.framework */; }; + 4D1664661EDD776A003DE88E /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4D1664611EDD74A9003DE88E /* QuartzCore.framework */; }; + 4D7517291EE2562B00820EEA /* SDL_cocoametalview.h in Headers */ = {isa = PBXBuildFile; fileRef = 4D7517281EE2562B00820EEA /* SDL_cocoametalview.h */; }; 56115BBB1DF72C6D00F47E1E /* SDL_dataqueue.c in Sources */ = {isa = PBXBuildFile; fileRef = 56115BB91DF72C6D00F47E1E /* SDL_dataqueue.c */; }; 56115BBC1DF72C6D00F47E1E /* SDL_dataqueue.h in Headers */ = {isa = PBXBuildFile; fileRef = 56115BBA1DF72C6D00F47E1E /* SDL_dataqueue.h */; }; 562C4AE91D8F496200AF9EBE /* AudioToolbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A7381E931D8B69C300B177DD /* AudioToolbox.framework */; }; @@ -1015,6 +1034,16 @@ 04F7804512FB74A200FC43C0 /* SDL_drawline.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDL_drawline.h; sourceTree = ""; }; 04F7804612FB74A200FC43C0 /* SDL_drawpoint.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SDL_drawpoint.c; sourceTree = ""; }; 04F7804712FB74A200FC43C0 /* SDL_drawpoint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDL_drawpoint.h; sourceTree = ""; }; + 4D16644A1EDD5FE8003DE88E /* SDL_vulkan.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDL_vulkan.h; sourceTree = ""; }; + 4D16644C1EDD6023003DE88E /* SDL_vulkan_internal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDL_vulkan_internal.h; sourceTree = ""; }; + 4D16644D1EDD6023003DE88E /* SDL_vulkan_utils.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SDL_vulkan_utils.c; sourceTree = ""; }; + 4D1664501EDD60AD003DE88E /* SDL_cocoametalview.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDL_cocoametalview.m; sourceTree = ""; }; + 4D1664511EDD60AD003DE88E /* SDL_cocoavulkan.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDL_cocoavulkan.h; sourceTree = ""; }; + 4D1664521EDD60AD003DE88E /* SDL_cocoavulkan.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDL_cocoavulkan.m; sourceTree = ""; }; + 4D16645D1EDD73E0003DE88E /* Metal.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Metal.framework; path = System/Library/Frameworks/Metal.framework; sourceTree = SDKROOT; }; + 4D1664611EDD74A9003DE88E /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; }; + 4D4820431F0F10B400EDC31C /* SDL_vulkan.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SDL_vulkan.h; path = ../../include/SDL_vulkan.h; sourceTree = ""; }; + 4D7517281EE2562B00820EEA /* SDL_cocoametalview.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDL_cocoametalview.h; sourceTree = ""; }; 56115BB91DF72C6D00F47E1E /* SDL_dataqueue.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = SDL_dataqueue.c; path = ../../src/SDL_dataqueue.c; sourceTree = ""; }; 56115BBA1DF72C6D00F47E1E /* SDL_dataqueue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SDL_dataqueue.h; path = ../../src/SDL_dataqueue.h; sourceTree = ""; }; 566CDE8D148F0AC200C5A9BB /* SDL_dropevents_c.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDL_dropevents_c.h; sourceTree = ""; }; @@ -1123,6 +1152,8 @@ 00D0D08410675DD9004B05EF /* CoreFoundation.framework in Frameworks */, 00D0D0D810675E46004B05EF /* Carbon.framework in Frameworks */, 00CFA89D106B4BA100758660 /* ForceFeedback.framework in Frameworks */, + 4D16645E1EDD73E0003DE88E /* Metal.framework in Frameworks */, + 4D1664651EDD7727003DE88E /* QuartzCore.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1138,6 +1169,8 @@ 007317C30858E15000B2BC32 /* Carbon.framework in Frameworks */, DB31408B17554D37006C0E22 /* ForceFeedback.framework in Frameworks */, 562C4AE91D8F496200AF9EBE /* AudioToolbox.framework in Frameworks */, + 4D16645F1EDD73FE003DE88E /* Metal.framework in Frameworks */, + 4D1664661EDD776A003DE88E /* QuartzCore.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1153,6 +1186,8 @@ DB31407217554B71006C0E22 /* Carbon.framework in Frameworks */, DB31408D17554D3C006C0E22 /* ForceFeedback.framework in Frameworks */, 562C4AEA1D8F496300AF9EBE /* AudioToolbox.framework in Frameworks */, + 4D1664601EDD741F003DE88E /* Metal.framework in Frameworks */, + 4D1664641EDD7528003DE88E /* QuartzCore.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1221,6 +1256,7 @@ AA7557F61595D4D800BBD41B /* SDL_types.h */, AA7557F71595D4D800BBD41B /* SDL_version.h */, AA7557F81595D4D800BBD41B /* SDL_video.h */, + 4D16644A1EDD5FE8003DE88E /* SDL_vulkan.h */, ); name = "Public Headers"; path = ../../include; @@ -1573,6 +1609,8 @@ 04BDFF7412E6671800899322 /* SDL_surface.c */, 04BDFF7512E6671800899322 /* SDL_sysvideo.h */, 04BDFF7612E6671800899322 /* SDL_video.c */, + 4D16644C1EDD6023003DE88E /* SDL_vulkan_internal.h */, + 4D16644D1EDD6023003DE88E /* SDL_vulkan_utils.c */, ); name = video; path = ../../src/video; @@ -1589,6 +1627,8 @@ 04BDFEC712E6671800899322 /* SDL_cocoakeyboard.m */, AABCC38B164063D200AB8930 /* SDL_cocoamessagebox.h */, AABCC38C164063D200AB8930 /* SDL_cocoamessagebox.m */, + 4D7517281EE2562B00820EEA /* SDL_cocoametalview.h */, + 4D1664501EDD60AD003DE88E /* SDL_cocoametalview.m */, 04BDFEC812E6671800899322 /* SDL_cocoamodes.h */, 04BDFEC912E6671800899322 /* SDL_cocoamodes.m */, 04BDFECA12E6671800899322 /* SDL_cocoamouse.h */, @@ -1601,6 +1641,8 @@ 04BDFECF12E6671800899322 /* SDL_cocoashape.m */, 04BDFED012E6671800899322 /* SDL_cocoavideo.h */, 04BDFED112E6671800899322 /* SDL_cocoavideo.m */, + 4D1664511EDD60AD003DE88E /* SDL_cocoavulkan.h */, + 4D1664521EDD60AD003DE88E /* SDL_cocoavulkan.m */, 04BDFED212E6671800899322 /* SDL_cocoawindow.h */, 04BDFED312E6671800899322 /* SDL_cocoawindow.m */, ); @@ -1662,6 +1704,7 @@ 0867D691FE84028FC02AAC07 /* SDLFramework */ = { isa = PBXGroup; children = ( + 4D4820431F0F10B400EDC31C /* SDL_vulkan.h */, F5A2EF3900C6A39A01000001 /* BUGS.txt */, F59C70FC00D5CB5801000001 /* pkg-support */, 0153844A006D81B07F000001 /* Public Headers */, @@ -1669,6 +1712,7 @@ 034768DDFF38A45A11DB9C8B /* Products */, BECDF66B0761BA81005FE872 /* Info-Framework.plist */, BEC562FE0761C0E800A33029 /* Linked Frameworks */, + 4D16645C1EDD73E0003DE88E /* Frameworks */, ); comments = "To build Universal Binaries, we have experimented with a variety of different options.\nThe complication is that we must retain compatibility with at least 10.2. \nThe Universal Binary defaults only work for > 10.3.9\n\nSo far, we have found:\ngcc 4.0.0 with Xcode 2.1 always links against libgcc_s. gcc 4.0.1 from Xcode 2.2 fixes this problem.\n\nBut gcc 4.0 will not work with < 10.3.9 because we continue to get an undefined symbol to _fprintf$LDBL128.\nSo we must use gcc 3.3 on PPC to accomplish 10.2 support. (But 4.0 is required for i386.)\n\nSetting the deployment target to 10.4 will disable prebinding, so for PPC, we set it less than 10.4 to preserve prebinding for legacy support.\n\nSetting the PPC SDKROOT to /Developers/SDKs/MacOSX10.2.8.sdk will link to 63.0.0 libSystem.B.dylib. Leaving it at current or 10.4u links to 88.1.2. However, as long as we are using gcc 3.3, it doesn't seem to matter as testing has demonstrated both will run. We have decided not to invoke the 10.2.8 SDK because it is not a default installed component with Xcode which will probably cause most people problems. However, rather than deleting the SDKROOT_ppc entry entirely, we have mapped it to 10.4u in case we decide we need to change this setting.\n\nTo use Altivec or SSE, we needed architecture specific flags:\nOTHER_CFLAGS_ppc\nOTHER_CFLAGS_i386\nOTHER_CFLAGS=$(OTHER_CFLAGS_($CURRENT_ARCH))\n\nThe general OTHER_CFLAGS needed to be manually mapped to architecture specific options because Xcode didn't do this automatically for us.\n\n\n"; indentWidth = 4; @@ -1717,6 +1761,15 @@ name = "Library Source"; sourceTree = ""; }; + 4D16645C1EDD73E0003DE88E /* Frameworks */ = { + isa = PBXGroup; + children = ( + 4D1664611EDD74A9003DE88E /* QuartzCore.framework */, + 4D16645D1EDD73E0003DE88E /* Metal.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; 567E2F1F17C44BBB005F1892 /* filesystem */ = { isa = PBXGroup; children = ( @@ -1834,8 +1887,10 @@ AA7558541595D4D800BBD41B /* SDL_timer.h in Headers */, AA7558561595D4D800BBD41B /* SDL_touch.h in Headers */, AA7558581595D4D800BBD41B /* SDL_types.h in Headers */, - AA75585A1595D4D800BBD41B /* SDL_version.h in Headers */, AA75585C1595D4D800BBD41B /* SDL_video.h in Headers */, + AA75585A1595D4D800BBD41B /* SDL_version.h in Headers */, + 4D16644B1EDD5FE8003DE88E /* SDL_vulkan.h in Headers */, + 4D7517291EE2562B00820EEA /* SDL_cocoametalview.h in Headers */, 04BD000912E6671800899322 /* SDL_diskaudio.h in Headers */, 04BD001112E6671800899322 /* SDL_dummyaudio.h in Headers */, 04BD001912E6671800899322 /* SDL_coreaudio.h in Headers */, @@ -1871,6 +1926,7 @@ 04BD00CB12E6671800899322 /* SDL_thread_c.h in Headers */, 04BD00D812E6671800899322 /* SDL_timer_c.h in Headers */, 04BD00F312E6671800899322 /* SDL_cocoaclipboard.h in Headers */, + 4D1664541EDD60AD003DE88E /* SDL_cocoavulkan.h in Headers */, 04BD00F512E6671800899322 /* SDL_cocoaevents.h in Headers */, 04BD00F712E6671800899322 /* SDL_cocoakeyboard.h in Headers */, 04BD00F912E6671800899322 /* SDL_cocoamodes.h in Headers */, @@ -1891,6 +1947,7 @@ 04BD019912E6671800899322 /* SDL_shape_internals.h in Headers */, 04BD019C12E6671800899322 /* SDL_sysvideo.h in Headers */, 04BD01DC12E6671800899322 /* imKStoUCS.h in Headers */, + 4D16644E1EDD6023003DE88E /* SDL_vulkan_internal.h in Headers */, 04BD01DE12E6671800899322 /* SDL_x11clipboard.h in Headers */, 04BD01E012E6671800899322 /* SDL_x11dyn.h in Headers */, 04BD01E212E6671800899322 /* SDL_x11events.h in Headers */, @@ -2325,14 +2382,6 @@ isa = PBXProject; attributes = { LastUpgradeCheck = 0730; - TargetAttributes = { - BECDF5FE0761BA81005FE872 = { - DevelopmentTeam = EH385AYQ6F; - }; - BECDF6BB0761BA81005FE872 = { - DevelopmentTeam = EH385AYQ6F; - }; - }; }; buildConfigurationList = 0073178E0858DB0500B2BC32 /* Build configuration list for PBXProject "SDL" */; compatibilityVersion = "Xcode 3.2"; @@ -2425,12 +2474,14 @@ 04BD005A12E6671800899322 /* SDL_rwops.c in Sources */, 04BD005B12E6671800899322 /* SDL_syshaptic.c in Sources */, 04BD005F12E6671800899322 /* SDL_haptic.c in Sources */, + 4D1664551EDD60AD003DE88E /* SDL_cocoavulkan.m in Sources */, 04BD006612E6671800899322 /* SDL_sysjoystick.c in Sources */, 04BD007012E6671800899322 /* SDL_joystick.c in Sources */, 04BD008812E6671800899322 /* SDL_sysloadso.c in Sources */, 04BD009412E6671800899322 /* SDL_syspower.c in Sources */, 04BD009612E6671800899322 /* SDL_power.c in Sources */, 04BD009C12E6671800899322 /* SDL_assert.c in Sources */, + 4D1664531EDD60AD003DE88E /* SDL_cocoametalview.m in Sources */, 04BD009F12E6671800899322 /* SDL_error.c in Sources */, 04BD00A212E6671800899322 /* SDL.c in Sources */, 04BD00A312E6671800899322 /* SDL_getenv.c in Sources */, @@ -2451,6 +2502,7 @@ 04BD00F612E6671800899322 /* SDL_cocoaevents.m in Sources */, 04BD00F812E6671800899322 /* SDL_cocoakeyboard.m in Sources */, 04BD00FA12E6671800899322 /* SDL_cocoamodes.m in Sources */, + 4D16644F1EDD6023003DE88E /* SDL_vulkan_utils.c in Sources */, 04BD00FC12E6671800899322 /* SDL_cocoamouse.m in Sources */, 04BD00FE12E6671800899322 /* SDL_cocoaopengl.m in Sources */, 04BD010012E6671800899322 /* SDL_cocoashape.m in Sources */, @@ -2521,6 +2573,9 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 4D1664571EDD61F0003DE88E /* SDL_cocoametalview.m in Sources */, + 4D1664581EDD61F0003DE88E /* SDL_cocoavulkan.m in Sources */, + 4D1664561EDD61DA003DE88E /* SDL_vulkan_utils.c in Sources */, 04BD021712E6671800899322 /* SDL_atomic.c in Sources */, 04BD021812E6671800899322 /* SDL_spinlock.c in Sources */, 56F9D55C1DF73B6B00C15B5D /* SDL_dataqueue.c in Sources */, @@ -2641,6 +2696,9 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 4D16645A1EDD6235003DE88E /* SDL_cocoametalview.m in Sources */, + 4D16645B1EDD6235003DE88E /* SDL_cocoavulkan.m in Sources */, + 4D1664591EDD621B003DE88E /* SDL_vulkan_utils.c in Sources */, DB313FFE17554B71006C0E22 /* SDL_atomic.c in Sources */, DB313FFF17554B71006C0E22 /* SDL_spinlock.c in Sources */, 56F9D55D1DF73B6C00C15B5D /* SDL_dataqueue.c in Sources */, @@ -2810,7 +2868,10 @@ DYLIB_COMPATIBILITY_VERSION = 1.0.0; DYLIB_CURRENT_VERSION = 7.0.0; FRAMEWORK_VERSION = A; - HEADER_SEARCH_PATHS = /usr/X11R6/include; + HEADER_SEARCH_PATHS = ( + /usr/X11R6/include, + "$(VULKAN_SDK)/include", + ); INFOPLIST_FILE = "Info-Framework.plist"; INSTALL_PATH = "@rpath"; OTHER_LDFLAGS = "-liconv"; @@ -2833,7 +2894,10 @@ "$(GCC_PREPROCESSOR_DEFINITIONS_QUOTED_4)", ); GCC_SYMBOLS_PRIVATE_EXTERN = YES; - HEADER_SEARCH_PATHS = /usr/X11R6/include; + HEADER_SEARCH_PATHS = ( + /usr/X11R6/include, + "$(VULKAN_SDK)/include", + ); PRODUCT_NAME = SDL2; SKIP_INSTALL = YES; }; @@ -2889,7 +2953,10 @@ DYLIB_COMPATIBILITY_VERSION = 1.0.0; DYLIB_CURRENT_VERSION = 7.0.0; FRAMEWORK_VERSION = A; - HEADER_SEARCH_PATHS = /usr/X11R6/include; + HEADER_SEARCH_PATHS = ( + /usr/X11R6/include, + "$(VULKAN_SDK)/include", + ); INFOPLIST_FILE = "Info-Framework.plist"; INSTALL_PATH = "@rpath"; OTHER_LDFLAGS = "-liconv"; @@ -2912,7 +2979,10 @@ "$(GCC_PREPROCESSOR_DEFINITIONS_QUOTED_4)", ); GCC_SYMBOLS_PRIVATE_EXTERN = YES; - HEADER_SEARCH_PATHS = /usr/X11R6/include; + HEADER_SEARCH_PATHS = ( + /usr/X11R6/include, + "$(VULKAN_SDK)/include", + ); PRODUCT_NAME = SDL2; SKIP_INSTALL = YES; }; @@ -2939,7 +3009,10 @@ "$(GCC_PREPROCESSOR_DEFINITIONS_QUOTED_4)", ); GCC_SYMBOLS_PRIVATE_EXTERN = YES; - HEADER_SEARCH_PATHS = /usr/X11R6/include; + HEADER_SEARCH_PATHS = ( + /usr/X11R6/include, + "$(VULKAN_SDK)/include", + ); INSTALL_PATH = "@rpath"; PRODUCT_NAME = SDL2; SKIP_INSTALL = YES; @@ -2959,7 +3032,10 @@ "$(GCC_PREPROCESSOR_DEFINITIONS_QUOTED_4)", ); GCC_SYMBOLS_PRIVATE_EXTERN = YES; - HEADER_SEARCH_PATHS = /usr/X11R6/include; + HEADER_SEARCH_PATHS = ( + /usr/X11R6/include, + "$(VULKAN_SDK)/include", + ); INSTALL_PATH = "@rpath"; PRODUCT_NAME = SDL2; SKIP_INSTALL = YES; diff --git a/cmake/sdlchecks.cmake b/cmake/sdlchecks.cmake index e2e89a279c0d6..661fd67377711 100644 --- a/cmake/sdlchecks.cmake +++ b/cmake/sdlchecks.cmake @@ -1153,6 +1153,25 @@ macro(CheckRPI) endif(VIDEO_RPI) endmacro(CheckRPI) +macro(CheckVulkanHeaders) + if(VIDEO_VULKAN) + # ${VULKAN_SDK} could be unset during the first configure run with + # cmake-gui resulting in vulkan.h not being found. If it's been + # subsequently changed, unset is necessary to ensure check is run again. + unset(HAVE_VULKAN_H CACHE) + # Prefer ${VULKAN_SDK} header + set(CMAKE_REQUIRED_INCLUDES "${VULKAN_SDK}/include") + check_include_file("vulkan/vulkan.h" HAVE_VULKAN_H) + if(HAVE_VULKAN_H) + list(APPEND EXTRA_CFLAGS "-I${VULKAN_SDK}/include") + else() + # Check system includes. + unset(HAVE_VULKAN_H CACHE) + check_include_file("vulkan/vulkan.h" HAVE_VULKAN_H) + endif() + endif() +endmacro(CheckVulkanHeaders) + # Requires: # - EGL # - PkgCheckModules diff --git a/configure b/configure index 6be48e5839f66..f5c07633f54f9 100755 --- a/configure +++ b/configure @@ -745,6 +745,7 @@ infodir docdir oldincludedir includedir +runstatedir localstatedir sharedstatedir sysconfdir @@ -854,6 +855,7 @@ enable_video_opengl enable_video_opengles enable_video_opengles1 enable_video_opengles2 +enable_video_vulkan enable_libudev enable_dbus enable_ime @@ -920,6 +922,7 @@ datadir='${datarootdir}' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' +runstatedir='${localstatedir}/run' includedir='${prefix}/include' oldincludedir='/usr/include' docdir='${datarootdir}/doc/${PACKAGE}' @@ -1172,6 +1175,15 @@ do | -silent | --silent | --silen | --sile | --sil) silent=yes ;; + -runstatedir | --runstatedir | --runstatedi | --runstated \ + | --runstate | --runstat | --runsta | --runst | --runs \ + | --run | --ru | --r) + ac_prev=runstatedir ;; + -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \ + | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \ + | --run=* | --ru=* | --r=*) + runstatedir=$ac_optarg ;; + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ @@ -1309,7 +1321,7 @@ fi for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ datadir sysconfdir sharedstatedir localstatedir includedir \ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ - libdir localedir mandir + libdir localedir mandir runstatedir do eval ac_val=\$$ac_var # Remove trailing slashes. @@ -1462,6 +1474,7 @@ Fine tuning of the installation directories: --sysconfdir=DIR read-only single-machine data [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] --localstatedir=DIR modifiable single-machine data [PREFIX/var] + --runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run] --libdir=DIR object code libraries [EPREFIX/lib] --includedir=DIR C header files [PREFIX/include] --oldincludedir=DIR C header files for non-gcc [/usr/include] @@ -1603,6 +1616,7 @@ Optional Features: include OpenGL ES 1.1 support [[default=yes]] --enable-video-opengles2 include OpenGL ES 2.0 support [[default=yes]] + --enable-video-vulkan include Vulkan surface support [[default=yes]] --enable-libudev enable libudev support [[default=yes]] --enable-dbus enable D-Bus support [[default=yes]] --enable-ime enable IME support [[default=yes]] @@ -21891,6 +21905,87 @@ $as_echo "#define SDL_VIDEO_RENDER_OGL_ES2 1" >>confdefs.h fi } +# Check whether --enable-video-vulkan was given. +if test "${enable_video_vulkan+set}" = set; then : + enableval=$enable_video_vulkan; +else + enable_video_vulkan=yes +fi + + +CheckVulkan() +{ + have_vulkan_hdr=no + if test x$enable_video = xyes -a x$enable_video_vulkan = xyes; then + case "$host" in + *-*-androideabi*) + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + #if defined(__ANDROID__) && defined(__ARM_EABI__) && !defined(__ARM_ARCH_7A__) + #error Vulkan doesn't work on this configuration + #endif + int main() + { + return 0; + } + +int +main () +{ + + enable_video_vulkan=no + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ;; + *) + ;; + esac + if test x$enable_video_vulkan = xno; then + # For reasons I am totally unable to see, I get an undefined macro error if + # I put this in the AC_TRY_COMPILE. + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Sorry, Vulkan does not work on this configuration." >&5 +$as_echo "$as_me: WARNING: Sorry, Vulkan does not work on this configuration." >&2;} + fi + if test x$enable_video_vulkan = xyes; then + vsdk_include_dir="${VULKAN_SDK}/include" + vulkan_header="vulkan/vulkan.h" + save_CPPFLAGS="$CPPFLAGS" + CPPFLAGS="${save_CPPFLAGS} -I$vsdk_include_dir" + as_ac_Header=`$as_echo "ac_cv_header_$vulkan_header" | $as_tr_sh` +ac_fn_c_check_header_mongrel "$LINENO" "$vulkan_header" "$as_ac_Header" "$ac_includes_default" +if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : + have_vulkan_hdr=yes +else + have_vulkan_hdr=no +fi + + + CPPFLAGS="$save_CPPFLAGS" + fi + fi + if test x$have_vulkan_hdr = xyes; then + # vulkan.h has been found in either $VULKAN_SDK/include or along the + # the standard include path. Unfortunately there seems no easy + # way to find out which, so... + if test -n "$VULKAN_SDK" -a -f "$vsdk_include_dir/$vulkan_header"; then + EXTRA_CFLAGS="$EXTRA_CFLAGS -I$vsdk_include_dir" + fi + +$as_echo "#define SDL_VIDEO_VULKAN_SURFACE 1" >>confdefs.h + + SUMMARY_video="${SUMMARY_video} vulkan" + fi +} + CheckInputEvents() { { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Linux 2.4 unified input interface" >&5 @@ -23637,6 +23732,7 @@ case "$host" in CheckKMSDRM CheckOpenGLX11 CheckOpenGLESX11 + CheckVulkan CheckMir CheckWayland CheckLibUDev @@ -23806,6 +23902,7 @@ $as_echo "#define SDL_TIMER_UNIX 1" >>confdefs.h CheckWINDOWS CheckWINDOWSGL CheckWINDOWSGLES + CheckVulkan CheckDIRECTX # Set up the core platform files @@ -24092,6 +24189,7 @@ fi CheckDummyAudio CheckDLOPEN CheckPTHREAD + CheckVulkan # Set up files for the audio library if test x$enable_audio = xyes; then @@ -24174,6 +24272,9 @@ $as_echo "#define SDL_VIDEO_RENDER_OGL_ES2 1" >>confdefs.h EXTRA_LDFLAGS="$EXTRA_LDFLAGS -Wl,-framework,OpenGLES" EXTRA_LDFLAGS="$EXTRA_LDFLAGS -Wl,-framework,QuartzCore" EXTRA_LDFLAGS="$EXTRA_LDFLAGS -Wl,-framework,UIKit" + if test x$ac_cv_header_vulkan_vulkan_h = xyes; then + EXTRA_LDFLAGS="$EXTRA_LDFLAGS -Wl,-framework,QuartzCore" + fi ;; *-*-darwin* ) # This could be either full "Mac OS X", or plain "Darwin" which is @@ -24195,6 +24296,7 @@ $as_echo "#define SDL_VIDEO_RENDER_OGL_ES2 1" >>confdefs.h CheckX11 CheckMacGL CheckOpenGLX11 + CheckVulkan CheckPTHREAD # Set up files for the audio library @@ -24260,6 +24362,9 @@ $as_echo "#define SDL_TIMER_UNIX 1" >>confdefs.h EXTRA_LDFLAGS="$EXTRA_LDFLAGS -Wl,-framework,Cocoa" EXTRA_LDFLAGS="$EXTRA_LDFLAGS -Wl,-framework,Carbon" EXTRA_LDFLAGS="$EXTRA_LDFLAGS -Wl,-framework,IOKit" + if test x$ac_cv_header_vulkan_vulkan_h = xyes; then + EXTRA_LDFLAGS="$EXTRA_LDFLAGS -Wl,-framework,QuartzCore" + fi ;; *-nacl|*-pnacl) ARCH=nacl diff --git a/configure.in b/configure.in index 64a484018265d..f4ccc274aedb5 100644 --- a/configure.in +++ b/configure.in @@ -2401,6 +2401,62 @@ CheckEmscriptenGLES() fi } +dnl Check to see if Vulkan surface support is desired +AC_ARG_ENABLE(video-vulkan, +AC_HELP_STRING([--enable-video-vulkan], [include Vulkan surface support [[default=yes]]]), + , enable_video_vulkan=yes) + +dnl Find Vulkan Header +CheckVulkan() +{ + have_vulkan_hdr=no + if test x$enable_video = xyes -a x$enable_video_vulkan = xyes; then + case "$host" in + *-*-androideabi*) + AC_TRY_COMPILE([ + #if defined(__ANDROID__) && defined(__ARM_EABI__) && !defined(__ARM_ARCH_7A__) + #error Vulkan doesn't work on this configuration + #endif + int main() + { + return 0; + } + ],[ + enable_video_vulkan=no + ],[ + ]) + ;; + *) + ;; + esac + if test x$enable_video_vulkan = xno; then + # For reasons I am totally unable to see, I get an undefined macro error if + # I put this in the AC_TRY_COMPILE. + AC_MSG_WARN([Sorry, Vulkan does not work on this configuration.]) + fi + if test x$enable_video_vulkan = xyes; then + vsdk_include_dir="${VULKAN_SDK}/include" + vulkan_header="vulkan/vulkan.h" + save_CPPFLAGS="$CPPFLAGS" + CPPFLAGS="${save_CPPFLAGS} -I$vsdk_include_dir" + AC_CHECK_HEADER($vulkan_header, + have_vulkan_hdr=yes, + have_vulkan_hdr=no) + CPPFLAGS="$save_CPPFLAGS" + fi + fi + if test x$have_vulkan_hdr = xyes; then + # vulkan.h has been found in either $VULKAN_SDK/include or along the + # the standard include path. Unfortunately there seems no easy + # way to find out which, so... + if test -n "$VULKAN_SDK" -a -f "$vsdk_include_dir/$vulkan_header"; then + EXTRA_CFLAGS="$EXTRA_CFLAGS -I$vsdk_include_dir" + fi + AC_DEFINE(SDL_VIDEO_VULKAN_SURFACE, 1, [ ]) + SUMMARY_video="${SUMMARY_video} vulkan" + fi +} + dnl See if we can use the new unified event interface in Linux 2.4 CheckInputEvents() { @@ -3230,6 +3286,7 @@ case "$host" in CheckKMSDRM CheckOpenGLX11 CheckOpenGLESX11 + CheckVulkan CheckMir CheckWayland CheckLibUDev @@ -3375,6 +3432,7 @@ case "$host" in CheckWINDOWS CheckWINDOWSGL CheckWINDOWSGLES + CheckVulkan CheckDIRECTX # Set up the core platform files @@ -3559,6 +3617,7 @@ AC_HELP_STRING([--enable-render-d3d], [enable the Direct3D render driver [[defau CheckDummyAudio CheckDLOPEN CheckPTHREAD + CheckVulkan # Set up files for the audio library if test x$enable_audio = xyes; then @@ -3621,6 +3680,9 @@ AC_HELP_STRING([--enable-render-d3d], [enable the Direct3D render driver [[defau EXTRA_LDFLAGS="$EXTRA_LDFLAGS -Wl,-framework,OpenGLES" EXTRA_LDFLAGS="$EXTRA_LDFLAGS -Wl,-framework,QuartzCore" EXTRA_LDFLAGS="$EXTRA_LDFLAGS -Wl,-framework,UIKit" + if test x$ac_cv_header_vulkan_vulkan_h = xyes; then + EXTRA_LDFLAGS="$EXTRA_LDFLAGS -Wl,-framework,QuartzCore" + fi ;; *-*-darwin* ) # This could be either full "Mac OS X", or plain "Darwin" which is @@ -3642,6 +3704,7 @@ AC_HELP_STRING([--enable-render-d3d], [enable the Direct3D render driver [[defau CheckX11 CheckMacGL CheckOpenGLX11 + CheckVulkan CheckPTHREAD # Set up files for the audio library @@ -3695,6 +3758,9 @@ AC_HELP_STRING([--enable-render-d3d], [enable the Direct3D render driver [[defau EXTRA_LDFLAGS="$EXTRA_LDFLAGS -Wl,-framework,Cocoa" EXTRA_LDFLAGS="$EXTRA_LDFLAGS -Wl,-framework,Carbon" EXTRA_LDFLAGS="$EXTRA_LDFLAGS -Wl,-framework,IOKit" + if test x$ac_cv_header_vulkan_vulkan_h = xyes; then + EXTRA_LDFLAGS="$EXTRA_LDFLAGS -Wl,-framework,QuartzCore" + fi ;; *-nacl|*-pnacl) ARCH=nacl diff --git a/debian/control b/debian/control index a3411335ae786..020884bd4b691 100644 --- a/debian/control +++ b/debian/control @@ -20,6 +20,7 @@ Build-Depends: debhelper (>= 9), libibus-1.0-dev[linux-any], libusb2-dev [kfreebsd-any], libusbhid-dev [kfreebsd-any], + libvulkan-dev, libx11-dev, libxcursor-dev, libxext-dev, diff --git a/docs/README-ios.md b/docs/README-ios.md index 29f4170483573..746b4fba78f27 100644 --- a/docs/README-ios.md +++ b/docs/README-ios.md @@ -7,9 +7,12 @@ Building the Simple DirectMedia Layer for iOS 5.1+ Requirements: Mac OS X 10.8 or later and the iOS 7+ SDK. -Instructions: -1. Open SDL.xcodeproj (located in Xcode-iOS/SDL) in Xcode. -2. Select your desired target, and hit build. +Instructions: + +1. Either download [Molten](https://moltengl.com/free-trial/) and unzip it or download the Vulkan headers from Khronos's [Vulkan-Docs](https://github.com/KhronosGroup/Vulkan-Docs/tree/1.0/src/vulkan) repo and put them in a directory hierarchy `include/vulkan`. +2. Open SDL.xcodeproj (located in Xcode-iOS/SDL) in Xcode. +3. Set a `VULKAN_SDK` custom path in the Xcode preferences. Select *Custom Paths* on the *Locations* tab. The value should be either the `MoltenVK` directory within the unzipped Molten package or the parent of the `include/vulkan` hierarchy. +4. Select your desired target, and hit build. There are three build targets: - libSDL.a: @@ -24,7 +27,9 @@ There are three build targets: Build SDL for iOS from the command line ============================================================================== -1. cd (PATH WHERE THE SDL CODE IS)/build-scripts +1. Follow step 1 above. +2. Either create and export a `VULKAN_SDK` environment variable with the value described in step 3 above or open Xcode, set the custom path described in step 3 above and close Xcode. +3. cd (PATH WHERE THE SDL CODE IS)/build-scripts 2. ./iosbuild.sh If everything goes fine, you should see a build/ios directory, inside there's diff --git a/docs/README-linux.md b/docs/README-linux.md index 1fe6a24d8d95f..9ed2276d05532 100644 --- a/docs/README-linux.md +++ b/docs/README-linux.md @@ -22,8 +22,8 @@ libxss-dev libgl1-mesa-dev libesd0-dev libdbus-1-dev libudev-dev \ libgles1-mesa-dev libgles2-mesa-dev libegl1-mesa-dev libibus-1.0-dev \ fcitx-libs-dev libsamplerate0-dev libsndio-dev -Ubuntu 16.04 can also add "libwayland-dev libxkbcommon-dev wayland-protocols" -to that command line for Wayland support. +Ubuntu 16.04+ can also add "libwayland-dev libxkbcommon-dev wayland-protocols" +to that command line for Wayland support and "libvulkan-dev" for Vulkan surface support. Ubuntu 16.10 can also add "libmirclient-dev libxkbcommon-dev" to that command line for Mir support. diff --git a/docs/README-macosx.md b/docs/README-macosx.md index 869de2e52b941..5263cef23f753 100644 --- a/docs/README-macosx.md +++ b/docs/README-macosx.md @@ -6,7 +6,19 @@ These instructions are for people using Apple's Mac OS X (pronounced From the developer's point of view, OS X is a sort of hybrid Mac and Unix system, and you have the option of using either traditional -command line tools or Apple's IDE Xcode. +command line tools or Apple's IDE Xcode. + +Preparation +=========== + +1. Either download [Molten](https://moltengl.com/free-trial/) and unzip it or download the Vulkan headers from Khronos's [Vulkan-Docs](https://github.com/KhronosGroup/Vulkan-Docs/tree/1.0/src/vulkan) repo and put them in a directory hierarchy `include/vulkan`. +2. Set a `VULKAN_SDK` variable in one of the ways described below. Its value should be either the `MoltenVK` directory within the unzipped Molten package or the parent of the `include/vulkan` hierarchy. + - If you are going to use the command line, set and export a `VULKAN_SDK` environment variable in your shell's start-up file, e.g. `~/.bash_profile`. + - If you are going to use CMake, either set and export a `VULKAN_SDK` environment variable before running `cmake` or set the `VULKAN_SDK` variable in `cmake-gui` and press *Configure*. + - If you are going to use the provided Xcode projects, set a `VULKAN_SDK` custom path in Xcode's preferences. Select *Custom Paths* on the *Locations* tab of preferences. + +Command Line Build +================== To build SDL using the command line, use the standard configure and make process: diff --git a/docs/README-windows.md b/docs/README-windows.md index de6e606bce97e..d133537f5edff 100644 --- a/docs/README-windows.md +++ b/docs/README-windows.md @@ -1,41 +1,45 @@ -Windows -================================================================================ - -================================================================================ -OpenGL ES 2.x support -================================================================================ - -SDL has support for OpenGL ES 2.x under Windows via two alternative -implementations. -The most straightforward method consists in running your app in a system with -a graphic card paired with a relatively recent (as of November of 2013) driver -which supports the WGL_EXT_create_context_es2_profile extension. Vendors known -to ship said extension on Windows currently include nVidia and Intel. - -The other method involves using the ANGLE library (https://code.google.com/p/angleproject/) -If an OpenGL ES 2.x context is requested and no WGL_EXT_create_context_es2_profile -extension is found, SDL will try to load the libEGL.dll library provided by -ANGLE. -To obtain the ANGLE binaries, you can either compile from source from -https://chromium.googlesource.com/angle/angle or copy the relevant binaries from -a recent Chrome/Chromium install for Windows. The files you need are: - - * libEGL.dll - * libGLESv2.dll - * d3dcompiler_46.dll (supports Windows Vista or later, better shader compiler) - or... - * d3dcompiler_43.dll (supports Windows XP or later) - -If you compile ANGLE from source, you can configure it so it does not need the -d3dcompiler_* DLL at all (for details on this, see their documentation). -However, by default SDL will try to preload the d3dcompiler_46.dll to -comply with ANGLE's requirements. If you wish SDL to preload d3dcompiler_43.dll (to -support Windows XP) or to skip this step at all, you can use the -SDL_HINT_VIDEO_WIN_D3DCOMPILER hint (see SDL_hints.h for more details). - -Known Bugs: - - * SDL_GL_SetSwapInterval is currently a no op when using ANGLE. It appears - that there's a bug in the library which prevents the window contents from - refreshing if this is set to anything other than the default value. - +Windows +================================================================================ + +================================================================================ +OpenGL ES 2.x support +================================================================================ + +SDL has support for OpenGL ES 2.x under Windows via two alternative +implementations. +The most straightforward method consists in running your app in a system with +a graphic card paired with a relatively recent (as of November of 2013) driver +which supports the WGL_EXT_create_context_es2_profile extension. Vendors known +to ship said extension on Windows currently include nVidia and Intel. + +The other method involves using the ANGLE library (https://code.google.com/p/angleproject/) +If an OpenGL ES 2.x context is requested and no WGL_EXT_create_context_es2_profile +extension is found, SDL will try to load the libEGL.dll library provided by +ANGLE. +To obtain the ANGLE binaries, you can either compile from source from +https://chromium.googlesource.com/angle/angle or copy the relevant binaries from +a recent Chrome/Chromium install for Windows. The files you need are: + + * libEGL.dll + * libGLESv2.dll + * d3dcompiler_46.dll (supports Windows Vista or later, better shader compiler) + or... + * d3dcompiler_43.dll (supports Windows XP or later) + +If you compile ANGLE from source, you can configure it so it does not need the +d3dcompiler_* DLL at all (for details on this, see their documentation). +However, by default SDL will try to preload the d3dcompiler_46.dll to +comply with ANGLE's requirements. If you wish SDL to preload d3dcompiler_43.dll (to +support Windows XP) or to skip this step at all, you can use the +SDL_HINT_VIDEO_WIN_D3DCOMPILER hint (see SDL_hints.h for more details). + +Known Bugs: + + * SDL_GL_SetSwapInterval is currently a no op when using ANGLE. It appears + that there's a bug in the library which prevents the window contents from + refreshing if this is set to anything other than the default value. + +Vulkan Surface Support +============== + +Support for creating Vulkan surfaces is configured on by default. To disable it change the value of `SDL_VIDEO_VULKAN_SURFACE` to 0 in `SDL_config_windows`. When it is on you must install a [Vulkan SDK](https://www.lunarg.com/vulkan-sdk/) in order to build libSDL. diff --git a/include/SDL.h b/include/SDL.h index 4a6b45350bc5a..4cd6108cd031f 100644 --- a/include/SDL.h +++ b/include/SDL.h @@ -56,6 +56,7 @@ #include "SDL_timer.h" #include "SDL_version.h" #include "SDL_video.h" +#include "SDL_vulkan.h" #include "begin_code.h" /* Set up for C function definitions, even when using C++ */ diff --git a/include/SDL_config.h.cmake b/include/SDL_config.h.cmake index 8f6d844024b0a..4998581a5a94f 100644 --- a/include/SDL_config.h.cmake +++ b/include/SDL_config.h.cmake @@ -354,6 +354,9 @@ #cmakedefine SDL_VIDEO_OPENGL_OSMESA @SDL_VIDEO_OPENGL_OSMESA@ #cmakedefine SDL_VIDEO_OPENGL_OSMESA_DYNAMIC @SDL_VIDEO_OPENGL_OSMESA_DYNAMIC@ +/* Enable Vulkan surface support */ +#cmakedefine SDL_VIDEO_VULKAN_SURFACE @SDL_VIDEO_VULKAN_SURFACE@ + /* Enable system power support */ #cmakedefine SDL_POWER_ANDROID @SDL_POWER_ANDROID@ #cmakedefine SDL_POWER_LINUX @SDL_POWER_LINUX@ diff --git a/include/SDL_config.h.in b/include/SDL_config.h.in index 6e929fdb4d27a..779543efe55ad 100644 --- a/include/SDL_config.h.in +++ b/include/SDL_config.h.in @@ -351,6 +351,9 @@ #undef SDL_VIDEO_OPENGL_OSMESA #undef SDL_VIDEO_OPENGL_OSMESA_DYNAMIC +/* Enable Vulkan surface support */ +#undef SDL_VIDEO_VULKAN_SURFACE + /* Enable system power support */ #undef SDL_POWER_LINUX #undef SDL_POWER_WINDOWS diff --git a/include/SDL_config_android.h b/include/SDL_config_android.h index 0bdff66c6cbb9..edc394451465c 100644 --- a/include/SDL_config_android.h +++ b/include/SDL_config_android.h @@ -140,6 +140,14 @@ #define SDL_VIDEO_RENDER_OGL_ES 1 #define SDL_VIDEO_RENDER_OGL_ES2 1 +/* Enable Vulkan surface support */ +/* Android does not support Vulkan in native code using the "armeabi" ABI. */ +#if !defined(__ARM_EABI__) || defined(__ARM_ARCH_7A__) +#define SDL_VIDEO_VULKAN_SURFACE 1 +#else +#define SDL_VIDEO_VULKAN_SURFACE 0 +#endif + /* Enable system power support */ #define SDL_POWER_ANDROID 1 diff --git a/include/SDL_config_iphoneos.h b/include/SDL_config_iphoneos.h index 7d5af2c66cacb..51bb0448fc03a 100644 --- a/include/SDL_config_iphoneos.h +++ b/include/SDL_config_iphoneos.h @@ -139,6 +139,13 @@ #define SDL_VIDEO_RENDER_OGL_ES 1 #define SDL_VIDEO_RENDER_OGL_ES2 1 +/* Enable Vulkan surface support */ +#if !TARGET_OS_SIMULATOR && !TARGET_CPU_ARM // Only 64-bit devices have Metal +#define SDL_VIDEO_VULKAN_SURFACE 1 +#else +#define SDL_VIDEO_VULKAN_SURFACE 0 +#endif + /* Enable system power support */ #define SDL_POWER_UIKIT 1 diff --git a/include/SDL_config_macosx.h b/include/SDL_config_macosx.h index 4b29f62c01134..7fdd9f81b479d 100644 --- a/include/SDL_config_macosx.h +++ b/include/SDL_config_macosx.h @@ -174,6 +174,14 @@ #define SDL_VIDEO_OPENGL_GLX 1 #endif +/* enable Vulkan surface support */ +#if TARGET_CPU_X86_64 +/* Metal/MoltenVK/Vulkan not supported on 32-bit architectures. */ +#define SDL_VIDEO_VULKAN_SURFACE 1 +#else +#define SDL_VIDEO_VULKAN_SURFACE 0 +#endif + /* Enable system power support */ #define SDL_POWER_MACOSX 1 diff --git a/include/SDL_config_windows.h b/include/SDL_config_windows.h index e29a2efb58901..23cdd5d1cd968 100644 --- a/include/SDL_config_windows.h +++ b/include/SDL_config_windows.h @@ -208,6 +208,7 @@ typedef unsigned int uintptr_t; #define SDL_VIDEO_OPENGL_EGL 1 #endif +#define SDL_VIDEO_VULKAN_SURFACE 1 /* Enable system power support */ #define SDL_POWER_WINDOWS 1 diff --git a/include/SDL_video.h b/include/SDL_video.h index 97b3aef86ab39..3eafb6a9952b0 100644 --- a/include/SDL_video.h +++ b/include/SDL_video.h @@ -233,7 +233,6 @@ typedef enum SDL_GL_CONTEXT_RESET_LOSE_CONTEXT = 0x0001 } SDL_GLContextResetNotification; - /* Function prototypes */ /** @@ -457,17 +456,32 @@ extern DECLSPEC Uint32 SDLCALL SDL_GetWindowPixelFormat(SDL_Window * window); * ::SDL_WINDOW_HIDDEN, ::SDL_WINDOW_BORDERLESS, * ::SDL_WINDOW_RESIZABLE, ::SDL_WINDOW_MAXIMIZED, * ::SDL_WINDOW_MINIMIZED, ::SDL_WINDOW_INPUT_GRABBED, - * ::SDL_WINDOW_ALLOW_HIGHDPI. + * ::SDL_WINDOW_ALLOW_HIGHDPI, ::SDL_WINDOW_VULKAN. * * \return The created window, or NULL if window creation failed. * * If the window is created with the SDL_WINDOW_ALLOW_HIGHDPI flag, its size * in pixels may differ from its size in screen coordinates on platforms with * high-DPI support (e.g. iOS and Mac OS X). Use SDL_GetWindowSize() to query - * the client area's size in screen coordinates, and SDL_GL_GetDrawableSize() - * or SDL_GetRendererOutputSize() to query the drawable size in pixels. + * the client area's size in screen coordinates, and SDL_GL_GetDrawableSize(), + * SDL_Vulkan_GetDrawableSize(), or SDL_GetRendererOutputSize() to query the + * drawable size in pixels. + * + * If the window is created with any of the SDL_WINDOW_OPENGL or + * SDL_WINDOW_VULKAN flags, then the corresponding LoadLibrary function + * (SDL_GL_LoadLibrary or SDL_Vulkan_LoadLibrary) is called and the + * corrensponding UnloadLibrary function is called by SDL_DestroyWindow(). + * + * If SDL_WINDOW_VULKAN is specified and there isn't a working Vulkan driver, + * SDL_CreateWindow() will fail because SDL_Vulkan_LoadLibrary() will fail. + * + * \note On non-Apple devices, SDL requires you to either not link to the + * Vulkan loader or link to a dynamic library version. This limitation + * may be removed in a future version of SDL. * * \sa SDL_DestroyWindow() + * \sa SDL_GL_LoadLibrary() + * \sa SDL_Vulkan_LoadLibrary() */ extern DECLSPEC SDL_Window * SDLCALL SDL_CreateWindow(const char *title, int x, int y, int w, @@ -879,7 +893,7 @@ extern DECLSPEC float SDLCALL SDL_GetWindowBrightness(SDL_Window * window); * \param window The window which will be made transparent or opaque * \param opacity Opacity (0.0f - transparent, 1.0f - opaque) This will be * clamped internally between 0.0f and 1.0f. - * + * * \return 0 on success, or -1 if setting the opacity isn't supported. * * \sa SDL_GetWindowOpacity() @@ -906,7 +920,7 @@ extern DECLSPEC int SDLCALL SDL_GetWindowOpacity(SDL_Window * window, float * ou * * \param modal_window The window that should be modal * \param parent_window The parent window - * + * * \return 0 on success, or -1 otherwise. */ extern DECLSPEC int SDLCALL SDL_SetWindowModalFor(SDL_Window * modal_window, SDL_Window * parent_window); @@ -919,7 +933,7 @@ extern DECLSPEC int SDLCALL SDL_SetWindowModalFor(SDL_Window * modal_window, SDL * obscured by other windows. * * \param window The window that should get the input focus - * + * * \return 0 on success, or -1 otherwise. * \sa SDL_RaiseWindow() */ diff --git a/include/SDL_vulkan.h b/include/SDL_vulkan.h new file mode 100644 index 0000000000000..f7b51915b66aa --- /dev/null +++ b/include/SDL_vulkan.h @@ -0,0 +1,251 @@ +/* + Simple DirectMedia Layer + Copyright (C) 2017, Mark Callow. + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + */ + +/** + * \file SDL_vulkan.h + * + * Header file for functions to creating Vulkan surfaces on SDL windows. + */ + +#ifndef SDL_vulkan_h_ +#define SDL_vulkan_h_ + +#include "SDL_video.h" + +#include "begin_code.h" +/* Set up for C function definitions, even when using C++ */ +#ifdef __cplusplus +extern "C" { +#endif + +/* Avoid including vulkan.h */ +#define VK_DEFINE_HANDLE(object) typedef struct object##_T* object; + +#if defined(__LP64__) || defined(_WIN64) || defined(__x86_64__) || defined(_M_X64) || defined(__ia64) || defined (_M_IA64) || defined(__aarch64__) || defined(__powerpc64__) +#define VK_DEFINE_NON_DISPATCHABLE_HANDLE(object) typedef struct object##_T *object; +#else +#define VK_DEFINE_NON_DISPATCHABLE_HANDLE(object) typedef uint64_t object; +#endif + +VK_DEFINE_HANDLE(VkInstance) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkSurfaceKHR) + +typedef VkInstance SDL_vulkanInstance; +typedef VkSurfaceKHR SDL_vulkanSurface; /* for compatibility with Tizen */ + +/** + * \name Vulkan support functions + * + * \note SDL_Vulkan_GetInstanceExtensions & SDL_Vulkan_CreateSurface API + * is compatable with Tizen's implementation of Vulkan in SDL. + */ +/* @{ */ + +/** + * \brief Dynamically load a Vulkan loader library. + * + * \param [in] path The platform dependent Vulkan loader library name, or + * \c NULL to open the default Vulkan loader library. + * + * \return \c 0 on success, or \c -1 if the library couldn't be loaded. + * + * This should be done after initializing the video driver, but before + * creating any Vulkan windows. If no Vulkan loader library is loaded, the + * default library will be loaded upon creation of the first Vulkan window. + * + * \note If you specify a non-NULL \a path, you should retrieve all of the + * Vulkan functions used in your program from the dynamic library using + * \c SDL_Vulkan_GetVkGetInstanceProcAddr() unless you can guarantee + * \a path points to the same vulkan loader library that you linked to. + * + * \note On Apple devices, if \a path is NULL, SDL will attempt to find + * the vkGetInstanceProcAddr address within all the mach-o images of + * the current process. This is because the currently (v0.17.0) + * recommended MoltenVK (Vulkan on Metal) usage is as a static library. + * If it is not found then SDL will attempt to load \c libMoltenVK.dylib. + * Applications using the dylib alternative therefore do not need to do + * anything special when calling SDL. + * + * \note On non-Apple devices, SDL requires you to either not link to the + * Vulkan loader or link to a dynamic library version. This limitation + * may be removed in a future version of SDL. + * + * \note This function will fail if there are no working Vulkan drivers + * installed. + * + * \sa SDL_Vulkan_GetVkGetInstanceProcAddr() + * \sa SDL_Vulkan_UnloadLibrary() + */ +extern DECLSPEC int SDLCALL SDL_Vulkan_LoadLibrary(const char *path); + +/** + * \brief Get the address of the \c vkGetInstanceProcAddr function. + * + * \note This should be called after either calling SDL_Vulkan_LoadLibrary + * or creating an SDL_Window with the SDL_WINDOW_VULKAN flag. + */ +extern DECLSPEC void *SDLCALL SDL_Vulkan_GetVkGetInstanceProcAddr(void); + +/** + * \brief Unload the Vulkan loader library previously loaded by + * \c SDL_Vulkan_LoadLibrary(). + * + * \sa SDL_Vulkan_LoadLibrary() + */ +extern DECLSPEC void SDLCALL SDL_Vulkan_UnloadLibrary(void); + +/** + * \brief Get the names of the Vulkan instance extensions needed to create + * a surface with \c SDL_Vulkan_CreateSurface(). + * + * \param [in] window Window for which the required Vulkan instance + * extensions should be retrieved + * \param [in,out] count pointer to an \c unsigned related to the number of + * required Vulkan instance extensions + * \param [out] names \c NULL or a pointer to an array to be filled with the + * required Vulkan instance extensions + * + * \return \c SDL_TRUE on success, \c SDL_FALSE on error. + * + * If \a pNames is \c NULL, then the number of required Vulkan instance + * extensions is returned in pCount. Otherwise, \a pCount must point to a + * variable set to the number of elements in the \a pNames array, and on + * return the variable is overwritten with the number of names actually + * written to \a pNames. If \a pCount is less than the number of required + * extensions, at most \a pCount structures will be written. If \a pCount + * is smaller than the number of required extensions, \c SDL_FALSE will be + * returned instead of \c SDL_TRUE, to indicate that not all the required + * extensions were returned. + * + * \note The returned list of extensions will contain \c VK_KHR_surface + * and zero or more platform specific extensions + * + * \note The extension names queried here must be enabled when calling + * VkCreateInstance, otherwise surface creation will fail. + * + * \note \c window should have been created with the \c SDL_WINDOW_VULKAN flag. + * + * \code + * unsigned count; + * // get count of required extensions + * if(!SDL_Vulkan_GetInstanceExtensions(window, &count, NULL)) + * handle_error(); + * + * static const char *const additionalExtensions[] = + * { + * VK_EXT_DEBUG_REPORT_EXTENSION_NAME, // example additional extension + * }; + * size_t additionalExtensionsCount = sizeof(additionalExtensions) / sizeof(additionalExtensions[0]); + * size_t extensionCount = count + additionalExtensionsCount; + * const char **names = malloc(sizeof(const char *) * extensionCount); + * if(!names) + * handle_error(); + * + * // get names of required extensions + * if(!SDL_Vulkan_GetInstanceExtensions(window, &count, names)) + * handle_error(); + * + * // copy additional extensions after required extensions + * for(size_t i = 0; i < additionalExtensionsCount; i++) + * names[i + count] = additionalExtensions[i]; + * + * VkInstanceCreateInfo instanceCreateInfo = {}; + * instanceCreateInfo.enabledExtensionCount = extensionCount; + * instanceCreateInfo.ppEnabledExtensionNames = names; + * // fill in rest of instanceCreateInfo + * + * VkInstance instance; + * // create the Vulkan instance + * VkResult result = vkCreateInstance(&instanceCreateInfo, NULL, &instance); + * free(names); + * \endcode + * + * \sa SDL_Vulkan_CreateSurface() + */ +extern DECLSPEC SDL_bool SDLCALL SDL_Vulkan_GetInstanceExtensions( + SDL_Window *window, + unsigned *pCount, + const char **pNames); + +/** + * \brief Create a Vulkan rendering surface for a window. + * + * \param [in] window SDL_Window to which to attach the rendering surface. + * \param [in] instance handle to the Vulkan instance to use. + * \param [out] surface pointer to a VkSurfaceKHR handle to receive the + * handle of the newly created surface. + * + * \return \c SDL_TRUE on success, \c SDL_FALSE on error. + * + * \code + * VkInstance instance; + * SDL_Window *window; + * + * // create instance and window + * + * // create the Vulkan surface + * VkSurfaceKHR surface; + * if(!SDL_Vulkan_CreateSurface(window, instance, &surface)) + * handle_error(); + * \endcode + * + * \note \a window should have been created with the \c SDL_WINDOW_VULKAN flag. + * + * \note \a instance should have been created with the extensions returned + * by \c SDL_Vulkan_CreateSurface() enabled. + * + * \sa SDL_Vulkan_GetInstanceExtensions() + */ +extern DECLSPEC SDL_bool SDLCALL SDL_Vulkan_CreateSurface( + SDL_Window *window, + VkInstance instance, + VkSurfaceKHR* surface); + +/** + * \brief Get the size of a window's underlying drawable in pixels (for use + * with setting viewport, scissor & etc). + * + * \param window SDL_Window from which the drawable size should be queried + * \param w Pointer to variable for storing the width in pixels, + * may be NULL + * \param h Pointer to variable for storing the height in pixels, + * may be NULL + * + * This may differ from SDL_GetWindowSize() if we're rendering to a high-DPI + * drawable, i.e. the window was created with SDL_WINDOW_ALLOW_HIGHDPI on a + * platform with high-DPI support (Apple calls this "Retina"), and not disabled + * by the \c SDL_HINT_VIDEO_HIGHDPI_DISABLED hint. + * + * \sa SDL_GetWindowSize() + * \sa SDL_CreateWindow() + */ +extern DECLSPEC void SDLCALL SDL_Vulkan_GetDrawableSize(SDL_Window * window, + int *w, int *h); + +/* @} *//* Vulkan support functions */ + +/* Ends C function definitions when using C++ */ +#ifdef __cplusplus +} +#endif +#include "close_code.h" + +#endif /* SDL_vulkan_h_ */ diff --git a/src/test/SDL_test_common.c b/src/test/SDL_test_common.c index 184a09732063b..c9bcbaf060dd5 100644 --- a/src/test/SDL_test_common.c +++ b/src/test/SDL_test_common.c @@ -886,7 +886,7 @@ SDLTest_CommonInit(SDLTest_CommonState * state) if (!state->skip_renderer && (state->renderdriver - || !(state->window_flags & SDL_WINDOW_OPENGL))) { + || !(state->window_flags & (SDL_WINDOW_OPENGL | SDL_WINDOW_VULKAN)))) { m = -1; if (state->renderdriver) { SDL_RendererInfo info; diff --git a/src/video/SDL_sysvideo.h b/src/video/SDL_sysvideo.h index c3ca82df221df..5b2bea5b45bf9 100644 --- a/src/video/SDL_sysvideo.h +++ b/src/video/SDL_sysvideo.h @@ -26,6 +26,7 @@ #include "SDL_messagebox.h" #include "SDL_shape.h" #include "SDL_thread.h" +#include "SDL_vulkan.h" /* The SDL video driver */ @@ -260,6 +261,16 @@ struct SDL_VideoDevice int (*GL_SwapWindow) (_THIS, SDL_Window * window); void (*GL_DeleteContext) (_THIS, SDL_GLContext context); + /* * * */ + /* + * Vulkan support + */ + int (*Vulkan_LoadLibrary) (_THIS, const char *path); + void (*Vulkan_UnloadLibrary) (_THIS); + SDL_bool (*Vulkan_GetInstanceExtensions) (_THIS, SDL_Window *window, unsigned *count, const char **names); + SDL_bool (*Vulkan_CreateSurface) (_THIS, SDL_Window *window, VkInstance instance, VkSurfaceKHR *surface); + void (*Vulkan_GetDrawableSize) (_THIS, SDL_Window * window, int *w, int *h); + /* * * */ /* * Event manager functions @@ -348,6 +359,17 @@ struct SDL_VideoDevice SDL_TLSID current_glwin_tls; SDL_TLSID current_glctx_tls; + /* * * */ + /* Data used by the Vulkan drivers */ + struct + { + void *vkGetInstanceProcAddr; + void *vkEnumerateInstanceExtensionProperties; + int loader_loaded; + char loader_path[256]; + void *loader_handle; + } vulkan_config; + /* * * */ /* Data private to this driver */ void *driverdata; diff --git a/src/video/SDL_video.c b/src/video/SDL_video.c index 4c6b45c4edc07..ae9d3a11077a9 100644 --- a/src/video/SDL_video.c +++ b/src/video/SDL_video.c @@ -1329,7 +1329,7 @@ SDL_UpdateFullscreenMode(SDL_Window * window, SDL_bool fullscreen) } #define CREATE_FLAGS \ - (SDL_WINDOW_OPENGL | SDL_WINDOW_BORDERLESS | SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI | SDL_WINDOW_ALWAYS_ON_TOP | SDL_WINDOW_SKIP_TASKBAR | SDL_WINDOW_POPUP_MENU | SDL_WINDOW_UTILITY | SDL_WINDOW_TOOLTIP | SDL_WINDOW_VULKAN ) + (SDL_WINDOW_OPENGL | SDL_WINDOW_BORDERLESS | SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI | SDL_WINDOW_ALWAYS_ON_TOP | SDL_WINDOW_SKIP_TASKBAR | SDL_WINDOW_POPUP_MENU | SDL_WINDOW_UTILITY | SDL_WINDOW_TOOLTIP | SDL_WINDOW_VULKAN) static void SDL_FinishWindowCreation(SDL_Window *window, Uint32 flags) @@ -1384,7 +1384,7 @@ SDL_CreateWindow(const char *title, int x, int y, int w, int h, Uint32 flags) /* Some platforms have OpenGL enabled by default */ #if (SDL_VIDEO_OPENGL && __MACOSX__) || __IPHONEOS__ || __ANDROID__ || __NACL__ - if (!_this->is_dummy) { + if (!_this->is_dummy && !(flags & SDL_WINDOW_VULKAN)) { flags |= SDL_WINDOW_OPENGL; } #endif @@ -1398,6 +1398,25 @@ SDL_CreateWindow(const char *title, int x, int y, int w, int h, Uint32 flags) } } + if(flags & SDL_WINDOW_VULKAN) + { + if(!_this->Vulkan_CreateSurface) + { + SDL_SetError("Vulkan support is either not configured in SDL " + "or not available in video driver"); + return NULL; + } + if(flags & SDL_WINDOW_OPENGL) + { + SDL_SetError("Vulkan and OpenGL not supported on same window"); + return NULL; + } + if(SDL_Vulkan_LoadLibrary(NULL) < 0) + { + return NULL; + } + } + /* Unless the user has specified the high-DPI disabling hint, respect the * SDL_WINDOW_ALLOW_HIGHDPI flag. */ @@ -1573,6 +1592,16 @@ SDL_RecreateWindow(SDL_Window * window, Uint32 flags) } } + if ((window->flags & SDL_WINDOW_VULKAN) != (flags & SDL_WINDOW_VULKAN)) { + SDL_SetError("Can't change SDL_WINDOW_VULKAN window flag"); + return -1; + } + + if ((window->flags & SDL_WINDOW_VULKAN) && (flags & SDL_WINDOW_OPENGL)) { + SDL_SetError("Vulkan and OpenGL not supported on same window"); + return -1; + } + window->flags = ((flags & CREATE_FLAGS) | SDL_WINDOW_HIDDEN); window->last_fullscreen_flags = window->flags; window->is_destroying = SDL_FALSE; @@ -2632,6 +2661,9 @@ SDL_DestroyWindow(SDL_Window * window) if (window->flags & SDL_WINDOW_OPENGL) { SDL_GL_UnloadLibrary(); } + if (window->flags & SDL_WINDOW_VULKAN) { + SDL_Vulkan_UnloadLibrary(); + } display = SDL_GetDisplayForWindow(window); if (display->fullscreen_window == window) { @@ -3946,4 +3978,128 @@ void SDL_OnApplicationDidBecomeActive(void) } } +#define NOT_A_VULKAN_WINDOW "The specified window isn't a Vulkan window." + +int SDL_Vulkan_LoadLibrary(const char *path) +{ + int retval; + if(!_this) + { + SDL_UninitializedVideo(); + return -1; + } + if(_this->vulkan_config.loader_loaded) + { + if(path && SDL_strcmp(path, _this->vulkan_config.loader_path) != 0) + { + return SDL_SetError("Vulkan loader library already loaded"); + } + retval = 0; + } + else + { + if(!_this->Vulkan_LoadLibrary) + { + return SDL_SetError("No Vulkan support in video driver"); + } + retval = _this->Vulkan_LoadLibrary(_this, path); + } + if(retval == 0) + { + _this->vulkan_config.loader_loaded++; + } + return retval; +} + +void *SDL_Vulkan_GetVkGetInstanceProcAddr(void) +{ + if(!_this) + { + SDL_UninitializedVideo(); + return NULL; + } + if(!_this->vulkan_config.loader_loaded) + { + SDL_SetError("No Vulkan loader has been loaded"); + } + return _this->vulkan_config.vkGetInstanceProcAddr; +} + +void SDL_Vulkan_UnloadLibrary(void) +{ + if(!_this) + { + SDL_UninitializedVideo(); + return; + } + if(_this->vulkan_config.loader_loaded > 0) + { + if(--_this->vulkan_config.loader_loaded > 0) + { + return; + } + if(_this->Vulkan_UnloadLibrary) + { + _this->Vulkan_UnloadLibrary(_this); + } + } +} + +SDL_bool SDL_Vulkan_GetInstanceExtensions(SDL_Window *window, unsigned *count, const char **names) +{ + CHECK_WINDOW_MAGIC(window, SDL_FALSE); + + if(!(window->flags & SDL_WINDOW_VULKAN)) + { + SDL_SetError(NOT_A_VULKAN_WINDOW); + return SDL_FALSE; + } + + if(!count) + { + SDL_SetError("invalid count"); + return SDL_FALSE; + } + + return _this->Vulkan_GetInstanceExtensions(_this, window, count, names); +} + +SDL_bool SDL_Vulkan_CreateSurface(SDL_Window *window, + VkInstance instance, + VkSurfaceKHR *surface) +{ + CHECK_WINDOW_MAGIC(window, SDL_FALSE); + + if(!(window->flags & SDL_WINDOW_VULKAN)) + { + SDL_SetError(NOT_A_VULKAN_WINDOW); + return SDL_FALSE; + } + + if(!instance) + { + SDL_SetError("invalid instance"); + return SDL_FALSE; + } + + if(!surface) + { + SDL_SetError("invalid surface"); + return SDL_FALSE; + } + + return _this->Vulkan_CreateSurface(_this, window, instance, surface); +} + +void SDL_Vulkan_GetDrawableSize(SDL_Window * window, int *w, int *h) +{ + CHECK_WINDOW_MAGIC(window,); + + if (_this->Vulkan_GetDrawableSize) { + _this->Vulkan_GetDrawableSize(_this, window, w, h); + } else { + SDL_GetWindowSize(window, w, h); + } +} + /* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/video/SDL_vulkan_internal.h b/src/video/SDL_vulkan_internal.h new file mode 100644 index 0000000000000..ab68ea96b5050 --- /dev/null +++ b/src/video/SDL_vulkan_internal.h @@ -0,0 +1,80 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2016 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ +#ifndef _SDL_vulkan_internal_h +#define _SDL_vulkan_internal_h + +#include "../SDL_internal.h" + +#include "SDL_stdinc.h" + +#if defined(SDL_LOADSO_DISABLED) +#undef SDL_VIDEO_VULKAN_SURFACE +#define SDL_VIDEO_VULKAN_SURFACE 0 +#endif + +#if SDL_VIDEO_DRIVER_ANDROID +#define VK_USE_PLATFORM_ANDROID_KHR +#endif +#if SDL_VIDEO_DRIVER_COCOA +#define VK_USE_PLATFORM_MACOS_MVK +#endif +#if SDL_VIDEO_DRIVER_MIR +#define VK_USE_PLATFORM_MIR_KHR +#endif +#if SDL_VIDEO_DRIVER_UIKIT +#define VK_USE_PLATFORM_IOS_MVK +#endif +#if SDL_VIDEO_DRIVER_WAYLAND +#define VK_USE_PLATFORM_WAYLAND_KHR +#endif +#if SDL_VIDEO_DRIVER_WINDOWS +#define VK_USE_PLATFORM_WIN32_KHR +#endif +#if SDL_VIDEO_DRIVER_X11 +#define VK_USE_PLATFORM_XLIB_KHR +#define VK_USE_PLATFORM_XCB_KHR +#endif + +#if SDL_VIDEO_VULKAN_SURFACE + +/* Need vulkan.h for the following declarations. Must ensure the first + * inclusion of vulkan has the appropriate USE_PLATFORM defined, hence + * the above. */ +#define VK_NO_PROTOTYPES +#include "vulkan/vulkan.h" + +extern const char *SDL_Vulkan_GetResultString(VkResult result); + +extern VkExtensionProperties *SDL_Vulkan_CreateInstanceExtensionsList( + PFN_vkEnumerateInstanceExtensionProperties vkEnumerateInstanceExtensionProperties, + Uint32 *extensionCount); /* free returned list with SDL_free */ + +/* Implements functionality of SDL_Vulkan_GetInstanceExtensions for a list of + * names passed in nameCount and names. */ +extern SDL_bool SDL_Vulkan_GetInstanceExtensions_Helper(unsigned *userCount, + const char **userNames, + unsigned nameCount, + const char *const *names); + +#endif + +#endif +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/video/SDL_vulkan_utils.c b/src/video/SDL_vulkan_utils.c new file mode 100644 index 0000000000000..d5714094284bf --- /dev/null +++ b/src/video/SDL_vulkan_utils.c @@ -0,0 +1,191 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2016 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ +#include "../SDL_internal.h" + +#include "SDL_vulkan_internal.h" +#include "SDL_error.h" + +#if SDL_VIDEO_VULKAN_SURFACE + +/* Based on the headers found in + * https://github.com/KhronosGroup/Vulkan-LoaderAndValidationLayers + */ +#if VK_HEADER_VERSION < 22 +enum +{ + VK_ERROR_FRAGMENTED_POOL = -12, +}; +#endif +#if VK_HEADER_VERSION < 38 +enum { + VK_ERROR_OUT_OF_POOL_MEMORY_KHR = -1000069000 +}; +#endif + +const char *SDL_Vulkan_GetResultString(VkResult result) +{ + switch((int)result) + { + case VK_SUCCESS: + return "VK_SUCCESS"; + case VK_NOT_READY: + return "VK_NOT_READY"; + case VK_TIMEOUT: + return "VK_TIMEOUT"; + case VK_EVENT_SET: + return "VK_EVENT_SET"; + case VK_EVENT_RESET: + return "VK_EVENT_RESET"; + case VK_INCOMPLETE: + return "VK_INCOMPLETE"; + case VK_ERROR_OUT_OF_HOST_MEMORY: + return "VK_ERROR_OUT_OF_HOST_MEMORY"; + case VK_ERROR_OUT_OF_DEVICE_MEMORY: + return "VK_ERROR_OUT_OF_DEVICE_MEMORY"; + case VK_ERROR_INITIALIZATION_FAILED: + return "VK_ERROR_INITIALIZATION_FAILED"; + case VK_ERROR_DEVICE_LOST: + return "VK_ERROR_DEVICE_LOST"; + case VK_ERROR_MEMORY_MAP_FAILED: + return "VK_ERROR_MEMORY_MAP_FAILED"; + case VK_ERROR_LAYER_NOT_PRESENT: + return "VK_ERROR_LAYER_NOT_PRESENT"; + case VK_ERROR_EXTENSION_NOT_PRESENT: + return "VK_ERROR_EXTENSION_NOT_PRESENT"; + case VK_ERROR_FEATURE_NOT_PRESENT: + return "VK_ERROR_FEATURE_NOT_PRESENT"; + case VK_ERROR_INCOMPATIBLE_DRIVER: + return "VK_ERROR_INCOMPATIBLE_DRIVER"; + case VK_ERROR_TOO_MANY_OBJECTS: + return "VK_ERROR_TOO_MANY_OBJECTS"; + case VK_ERROR_FORMAT_NOT_SUPPORTED: + return "VK_ERROR_FORMAT_NOT_SUPPORTED"; + case VK_ERROR_FRAGMENTED_POOL: + return "VK_ERROR_FRAGMENTED_POOL"; + case VK_ERROR_SURFACE_LOST_KHR: + return "VK_ERROR_SURFACE_LOST_KHR"; + case VK_ERROR_NATIVE_WINDOW_IN_USE_KHR: + return "VK_ERROR_NATIVE_WINDOW_IN_USE_KHR"; + case VK_SUBOPTIMAL_KHR: + return "VK_SUBOPTIMAL_KHR"; + case VK_ERROR_OUT_OF_DATE_KHR: + return "VK_ERROR_OUT_OF_DATE_KHR"; + case VK_ERROR_INCOMPATIBLE_DISPLAY_KHR: + return "VK_ERROR_INCOMPATIBLE_DISPLAY_KHR"; + case VK_ERROR_VALIDATION_FAILED_EXT: + return "VK_ERROR_VALIDATION_FAILED_EXT"; + case VK_ERROR_OUT_OF_POOL_MEMORY_KHR: + return "VK_ERROR_OUT_OF_POOL_MEMORY_KHR"; + case VK_ERROR_INVALID_SHADER_NV: + return "VK_ERROR_INVALID_SHADER_NV"; + case VK_RESULT_MAX_ENUM: + case VK_RESULT_RANGE_SIZE: + break; + } + if(result < 0) + return "VK_ERROR_"; + return "VK_"; +} + +VkExtensionProperties *SDL_Vulkan_CreateInstanceExtensionsList( + PFN_vkEnumerateInstanceExtensionProperties vkEnumerateInstanceExtensionProperties, + Uint32 *extensionCount) +{ + Uint32 count = 0; + VkResult result = vkEnumerateInstanceExtensionProperties(NULL, &count, NULL); + VkExtensionProperties *retval; + if(result == VK_ERROR_INCOMPATIBLE_DRIVER) + { + SDL_SetError( + "You probably don't have a working Vulkan driver installed: getting Vulkan " + "extensions failed: vkEnumerateInstanceExtensionProperties returned %s(%d)", + SDL_Vulkan_GetResultString(result), + (int)result); + return NULL; + } + else if(result != VK_SUCCESS) + { + SDL_SetError( + "Getting Vulkan extensions failed: vkEnumerateInstanceExtensionProperties returned " + "%s(%d)", + SDL_Vulkan_GetResultString(result), + (int)result); + return NULL; + } + if(count == 0) + { + retval = SDL_calloc(1, sizeof(VkExtensionProperties)); // so we can return non-null + if(!retval) + { + SDL_OutOfMemory(); + return NULL; + } + *extensionCount = 0; + } + retval = SDL_calloc(count, sizeof(VkExtensionProperties)); + if(!retval) + { + SDL_OutOfMemory(); + return NULL; + } + result = vkEnumerateInstanceExtensionProperties(NULL, &count, retval); + if(result != VK_SUCCESS) + { + SDL_SetError( + "Getting Vulkan extensions failed: vkEnumerateInstanceExtensionProperties returned " + "%s(%d)", + SDL_Vulkan_GetResultString(result), + (int)result); + SDL_free(retval); + return NULL; + } + *extensionCount = count; + return retval; +} + +SDL_bool SDL_Vulkan_GetInstanceExtensions_Helper(unsigned *userCount, + const char **userNames, + unsigned nameCount, + const char *const *names) +{ + if(userNames) + { + unsigned int i; + + if(*userCount != nameCount) + { + SDL_SetError( + "Count doesn't match count from previous call of SDL_Vulkan_GetInstanceExtensions"); + return SDL_FALSE; + } + for(i = 0; i < nameCount; i++) + { + userNames[i] = names[i]; + } + } + else + { + *userCount = nameCount; + } + return SDL_TRUE; +} + +#endif diff --git a/src/video/android/SDL_androidvideo.c b/src/video/android/SDL_androidvideo.c index e5e70f9bf75c5..d9887018779c3 100644 --- a/src/video/android/SDL_androidvideo.c +++ b/src/video/android/SDL_androidvideo.c @@ -40,6 +40,7 @@ #include "SDL_androidmouse.h" #include "SDL_androidtouch.h" #include "SDL_androidwindow.h" +#include "SDL_androidvulkan.h" #define ANDROID_VID_DRIVER_NAME "Android" @@ -132,6 +133,13 @@ Android_CreateDevice(int devindex) device->GL_SwapWindow = Android_GLES_SwapWindow; device->GL_DeleteContext = Android_GLES_DeleteContext; +#if SDL_VIDEO_VULKAN_SURFACE + device->Vulkan_LoadLibrary = Android_Vulkan_LoadLibrary; + device->Vulkan_UnloadLibrary = Android_Vulkan_UnloadLibrary; + device->Vulkan_GetInstanceExtensions = Android_Vulkan_GetInstanceExtensions; + device->Vulkan_CreateSurface = Android_Vulkan_CreateSurface; +#endif + /* Screensaver */ device->SuspendScreenSaver = Android_SuspendScreenSaver; diff --git a/src/video/android/SDL_androidvulkan.c b/src/video/android/SDL_androidvulkan.c new file mode 100644 index 0000000000000..c8e4c8858afdd --- /dev/null +++ b/src/video/android/SDL_androidvulkan.c @@ -0,0 +1,174 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2016 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ + +/* + * @author Mark Callow, www.edgewise-consulting.com. Based on Jacob Lifshay's + * SDL_x11vulkan.c. + */ + +#include "../../SDL_internal.h" + +#if SDL_VIDEO_VULKAN_SURFACE && SDL_VIDEO_DRIVER_ANDROID + +#include "SDL_androidvideo.h" +#include "SDL_androidwindow.h" +#include "SDL_assert.h" + +#include "SDL_loadso.h" +#include "SDL_androidvulkan.h" +#include "SDL_syswm.h" + +int Android_Vulkan_LoadLibrary(_THIS, const char *path) +{ + VkExtensionProperties *extensions = NULL; + Uint32 extensionCount = 0; + SDL_bool hasSurfaceExtension = SDL_FALSE; + SDL_bool hasAndroidSurfaceExtension = SDL_FALSE; + PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr = NULL; + if(_this->vulkan_config.loader_handle) + return SDL_SetError("Vulkan already loaded"); + + /* Load the Vulkan loader library */ + if(!path) + path = SDL_getenv("SDL_VULKAN_LIBRARY"); + if(!path) + path = "libvulkan.so.1"; + _this->vulkan_config.loader_handle = SDL_LoadObject(path); + if(!_this->vulkan_config.loader_handle) + return -1; + SDL_strlcpy(_this->vulkan_config.loader_path, path, + SDL_arraysize(_this->vulkan_config.loader_path)); + vkGetInstanceProcAddr = (PFN_vkGetInstanceProcAddr)SDL_LoadFunction( + _this->vulkan_config.loader_handle, "vkGetInstanceProcAddr"); + if(!vkGetInstanceProcAddr) + goto fail; + _this->vulkan_config.vkGetInstanceProcAddr = (void *)vkGetInstanceProcAddr; + _this->vulkan_config.vkEnumerateInstanceExtensionProperties = + (void *)((PFN_vkGetInstanceProcAddr)_this->vulkan_config.vkGetInstanceProcAddr)( + VK_NULL_HANDLE, "vkEnumerateInstanceExtensionProperties"); + if(!_this->vulkan_config.vkEnumerateInstanceExtensionProperties) + goto fail; + extensions = SDL_Vulkan_CreateInstanceExtensionsList( + (PFN_vkEnumerateInstanceExtensionProperties) + _this->vulkan_config.vkEnumerateInstanceExtensionProperties, + &extensionCount); + if(!extensions) + goto fail; + for(Uint32 i = 0; i < extensionCount; i++) + { + if(SDL_strcmp(VK_KHR_SURFACE_EXTENSION_NAME, extensions[i].extensionName) == 0) + hasSurfaceExtension = SDL_TRUE; + else if(SDL_strcmp(VK_KHR_ANDROID_SURFACE_EXTENSION_NAME, extensions[i].extensionName) == 0) + hasAndroidSurfaceExtension = SDL_TRUE; + } + SDL_free(extensions); + if(!hasSurfaceExtension) + { + SDL_SetError("Installed Vulkan doesn't implement the " + VK_KHR_SURFACE_EXTENSION_NAME " extension"); + goto fail; + } + else if(!hasAndroidSurfaceExtension) + { + SDL_SetError("Installed Vulkan doesn't implement the " + VK_KHR_ANDROID_SURFACE_EXTENSION_NAME "extension"); + goto fail; + } + return 0; + +fail: + SDL_UnloadObject(_this->vulkan_config.loader_handle); + _this->vulkan_config.loader_handle = NULL; + return -1; +} + +void Android_Vulkan_UnloadLibrary(_THIS) +{ + if(_this->vulkan_config.loader_handle) + { + SDL_UnloadObject(_this->vulkan_config.loader_handle); + _this->vulkan_config.loader_handle = NULL; + } +} + +SDL_bool Android_Vulkan_GetInstanceExtensions(_THIS, + SDL_Window *window, + unsigned *count, + const char **names) +{ + static const char *const extensionsForAndroid[] = { + VK_KHR_SURFACE_EXTENSION_NAME, VK_KHR_ANDROID_SURFACE_EXTENSION_NAME + }; + if(!_this->vulkan_config.loader_handle) + { + SDL_SetError("Vulkan is not loaded"); + return SDL_FALSE; + } + return SDL_Vulkan_GetInstanceExtensions_Helper( + count, names, SDL_arraysize(extensionsForMir), + extensionsForAndroid); +} + +SDL_bool Android_Vulkan_CreateSurface(_THIS, + SDL_Window *window, + VkInstance instance, + VkSurfaceKHR *surface) +{ + SDL_WindowData *windowData = (SDL_WindowData *)window->driverdata; + PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr = + (PFN_vkGetInstanceProcAddr)_this->vulkan_config.vkGetInstanceProcAddr; + PFN_vkCreateAndroidSurfaceKHR vkCreateAndroidSurfaceKHR = + (PFN_vkCreateAndroidSurfaceKHR)vkGetInstanceProcAddr( + (VkInstance)instance, + "vkCreateAndroidSurfaceKHR"); + VkAndroidSurfaceCreateInfoKHR createInfo = {}; + VkResult result; + + if(!_this->vulkan_config.loader_handle) + { + SDL_SetError("Vulkan is not loaded"); + return SDL_FALSE; + } + + if(!vkCreateAndroidSurfaceKHR) + { + SDL_SetError(VK_KHR_Android_SURFACE_EXTENSION_NAME + " extension is not enabled in the Vulkan instance."); + return SDL_FALSE; + } + createInfo.sType = VK_STRUCTURE_TYPE_Android_SURFACE_CREATE_INFO_KHR; + createInfo.pNext = NULL; + createInfo.flags = 0; + createInfo.window = windowData->native_window; + result = vkCreateAndroidSurfaceKHR(instance, &createInfo, + NULL, surface); + if(result != VK_SUCCESS) + { + SDL_SetError("vkCreateAndroidSurfaceKHR failed: %s", + SDL_Vulkan_GetResultString(result)); + return SDL_FALSE; + } + return SDL_TRUE; +} + +#endif + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/video/android/SDL_androidvulkan.h b/src/video/android/SDL_androidvulkan.h new file mode 100644 index 0000000000000..d7d372cd9f2bc --- /dev/null +++ b/src/video/android/SDL_androidvulkan.h @@ -0,0 +1,52 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2016 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ + +/* + * @author Mark Callow, www.edgewise-consulting.com. Based on Jacob Lifshay's + * SDL_x11vulkan.h. + */ + +#include "../../SDL_internal.h" + +#ifndef _SDL_androidvulkan_h +#define _SDL_androidvulkan_h + +#include "../SDL_vulkan_internal.h" +#include "../SDL_sysvideo.h" + +#if SDL_VIDEO_VULKAN_SURFACE && SDL_VIDEO_DRIVER_ANDROID + +int Android_Vulkan_LoadLibrary(_THIS, const char *path); +void Android_Vulkan_UnloadLibrary(_THIS); +SDL_bool Android_Vulkan_GetInstanceExtensions(_THIS, + SDL_Window *window, + unsigned *count, + const char **names); +SDL_bool Android_Vulkan_CreateSurface(_THIS, + SDL_Window *window, + VkInstance instance, + VkSurfaceKHR *surface); + +#endif + +#endif /* _SDL_androidvulkan_h */ + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/video/cocoa/SDL_cocoametalview.h b/src/video/cocoa/SDL_cocoametalview.h new file mode 100644 index 0000000000000..be96b2b4f46f2 --- /dev/null +++ b/src/video/cocoa/SDL_cocoametalview.h @@ -0,0 +1,61 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2017 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + */ + +/* + * @author Mark Callow, www.edgewise-consulting.com. + * + * Thanks to Alex Szpakowski, @slime73 on GitHub, for his gist showing + * how to add a CAMetalLayer backed view. + */ + +#ifndef _SDL_cocoametalview_h +#define _SDL_cocoametalview_h + +#import "../SDL_sysvideo.h" +#import "SDL_cocoawindow.h" + +#import +#import +#import + +#define METALVIEW_TAG 255 + +@interface SDL_cocoametalview : NSView { + NSInteger _tag; + bool _useHighDPI; +} + +- (instancetype)initWithFrame:(NSRect)frame + useHighDPI:(bool)useHighDPI; + +/* Override superclass tag so this class can set it. */ +@property (assign, readonly) NSInteger tag; + +@end + +SDL_cocoametalview* Cocoa_Mtl_AddMetalView(SDL_Window* window); + +void Cocoa_Mtl_GetDrawableSize(SDL_Window * window, int * w, int * h); + +#endif /* _SDL_cocoametalview_h */ + +/* vi: set ts=4 sw=4 expandtab: */ + diff --git a/src/video/cocoa/SDL_cocoametalview.m b/src/video/cocoa/SDL_cocoametalview.m new file mode 100644 index 0000000000000..64ad40728f397 --- /dev/null +++ b/src/video/cocoa/SDL_cocoametalview.m @@ -0,0 +1,124 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2017 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + */ + +/* + * @author Mark Callow, www.edgewise-consulting.com. + * + * Thanks to Alex Szpakowski, @slime73 on GitHub, for his gist showing + * how to add a CAMetalLayer backed view. + */ + +/* this is (currently) only used with Vulkan. Remove this #if when that changes! */ +#if SDL_VIDEO_VULKAN_SURFACE && SDL_VIDEO_DRIVER_COCOA + +#import "SDL_cocoametalview.h" + +#include "SDL_assert.h" +#include "SDL_loadso.h" +#include + +@implementation SDL_cocoametalview + +/* The synthesized getter should be called by super's viewWithTag. */ +@synthesize tag = _tag; + +/* Return a Metal-compatible layer. */ ++ (Class)layerClass +{ + return [CAMetalLayer class]; +} + +/* Indicate the view wants to draw using a backing layer instead of drawRect. */ +-(BOOL) wantsUpdateLayer { return YES; } + +/* When the wantsLayer property is set to YES, this method will be invoked to + * return a layer instance. + */ +-(CALayer*) makeBackingLayer { return [self.class.layerClass layer]; } + +- (instancetype)initWithFrame:(NSRect)frame + useHighDPI:(bool)useHighDPI +{ + if ((self = [super initWithFrame:frame])) { + + /* Allow resize. */ + self.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable; + _tag = METALVIEW_TAG; + + _useHighDPI = useHighDPI; + [self updateDrawableSize]; + } + + return self; +} + +/* Set the size of the metal drawables when the view is resized. */ +- (void)resizeSubviewsWithOldSize:(NSSize)oldSize { + [super resizeSubviewsWithOldSize:oldSize]; + [self updateDrawableSize]; +} + +- (void)updateDrawableSize +{ + if (_useHighDPI) { + NSSize size = [self convertRectToBacking:[self bounds]].size; + /* Isn't there a better way to convert from NSSize to CGSize? */ + CGSize cgsize = *(CGSize*)&size; + ((CAMetalLayer *) self.layer).drawableSize = cgsize; + } +} + +@end + +SDL_cocoametalview* +Cocoa_Mtl_AddMetalView(SDL_Window* window) +{ + SDL_WindowData *data = (SDL_WindowData *)window->driverdata; + NSView *view = data->nswindow.contentView; + + SDL_cocoametalview *metalview + = [[SDL_cocoametalview alloc] initWithFrame:view.frame + useHighDPI:(window->flags & SDL_WINDOW_ALLOW_HIGHDPI)]; + [view addSubview:metalview]; + + return metalview; +} + +void +Cocoa_Mtl_GetDrawableSize(SDL_Window * window, int * w, int * h) +{ + SDL_WindowData *data = (__bridge SDL_WindowData *)window->driverdata; + NSView *view = data->nswindow.contentView; + SDL_cocoametalview* metalview = [view viewWithTag:METALVIEW_TAG]; + if (metalview) { + CAMetalLayer *layer = (CAMetalLayer*)metalview.layer; + assert(layer != NULL); + if (w) + *w = layer.drawableSize.width; + if (h) + *h = layer.drawableSize.height; + } +} + +#endif + +/* vi: set ts=4 sw=4 expandtab: */ + diff --git a/src/video/cocoa/SDL_cocoavideo.m b/src/video/cocoa/SDL_cocoavideo.m index cc41863ddb3bf..9504a772acc96 100644 --- a/src/video/cocoa/SDL_cocoavideo.m +++ b/src/video/cocoa/SDL_cocoavideo.m @@ -26,6 +26,7 @@ #include "SDL_endian.h" #include "SDL_cocoavideo.h" #include "SDL_cocoashape.h" +#include "SDL_cocoavulkan.h" #include "SDL_assert.h" /* Initialization/Query functions */ @@ -122,6 +123,14 @@ device->GL_DeleteContext = Cocoa_GL_DeleteContext; #endif +#if SDL_VIDEO_VULKAN_SURFACE + device->Vulkan_LoadLibrary = Cocoa_Vulkan_LoadLibrary; + device->Vulkan_UnloadLibrary = Cocoa_Vulkan_UnloadLibrary; + device->Vulkan_GetInstanceExtensions = Cocoa_Vulkan_GetInstanceExtensions; + device->Vulkan_CreateSurface = Cocoa_Vulkan_CreateSurface; + device->Vulkan_GetDrawableSize = Cocoa_Vulkan_GetDrawableSize; +#endif + device->StartTextInput = Cocoa_StartTextInput; device->StopTextInput = Cocoa_StopTextInput; device->SetTextInputRect = Cocoa_SetTextInputRect; diff --git a/src/video/cocoa/SDL_cocoavulkan.h b/src/video/cocoa/SDL_cocoavulkan.h new file mode 100644 index 0000000000000..b97163506b207 --- /dev/null +++ b/src/video/cocoa/SDL_cocoavulkan.h @@ -0,0 +1,55 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2016 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ + +/* + * @author Mark Callow, www.edgewise-consulting.com. Based on Jacob Lifshay's + * SDL_x11vulkan.h. + */ + + +#include "../../SDL_internal.h" + +#ifndef _SDL_cocoavulkan_h +#define _SDL_cocoavulkan_h + +#include "../SDL_vulkan_internal.h" +#include "../SDL_sysvideo.h" + +#if SDL_VIDEO_VULKAN_SURFACE && SDL_VIDEO_DRIVER_COCOA + +int Cocoa_Vulkan_LoadLibrary(_THIS, const char *path); +void Cocoa_Vulkan_UnloadLibrary(_THIS); +SDL_bool Cocoa_Vulkan_GetInstanceExtensions(_THIS, + SDL_Window *window, + unsigned *count, + const char **names); +SDL_bool Cocoa_Vulkan_CreateSurface(_THIS, + SDL_Window *window, + VkInstance instance, + VkSurfaceKHR *surface); + +void Cocoa_Vulkan_GetDrawableSize(_THIS, SDL_Window *window, int *w, int *h); + +#endif + +#endif /* _SDL_cocoavulkan_h */ + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/video/cocoa/SDL_cocoavulkan.m b/src/video/cocoa/SDL_cocoavulkan.m new file mode 100644 index 0000000000000..0f6cbd126a4ae --- /dev/null +++ b/src/video/cocoa/SDL_cocoavulkan.m @@ -0,0 +1,217 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2016 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ + +/* + * @author Mark Callow, www.edgewise-consulting.com. Based on Jacob Lifshay's + * SDL_x11vulkan.c. + */ + +#include "../../SDL_internal.h" + +#if SDL_VIDEO_VULKAN_SURFACE && SDL_VIDEO_DRIVER_COCOA + +#include "SDL_cocoavideo.h" +#include "SDL_cocoawindow.h" +#include "SDL_assert.h" + +#include "SDL_loadso.h" +#include "SDL_cocoametalview.h" +#include "SDL_cocoavulkan.h" +#include "SDL_syswm.h" + +#include + +#define DEFAULT_MOLTENVK "libMoltenVK.dylib" +/* Since libSDL is most likely a .dylib, need RTLD_DEFAULT not RTLD_SELF. */ +#define DEFAULT_HANDLE RTLD_DEFAULT + +int Cocoa_Vulkan_LoadLibrary(_THIS, const char *path) +{ + VkExtensionProperties *extensions = NULL; + Uint32 extensionCount = 0; + SDL_bool hasSurfaceExtension = SDL_FALSE; + SDL_bool hasMacOSSurfaceExtension = SDL_FALSE; + PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr = NULL; + if(_this->vulkan_config.loader_handle) + { + SDL_SetError("MoltenVK/Vulkan already loaded"); + return -1; + } + + /* Load the Vulkan loader library */ + if(!path) + path = SDL_getenv("SDL_VULKAN_LIBRARY"); + if(!path) + { + /* MoltenVK framework, currently, v0.17.0, has a static library and is + * the recommended way to use the package. There is likely no object to + * load. */ + vkGetInstanceProcAddr = + (PFN_vkGetInstanceProcAddr)dlsym(DEFAULT_HANDLE, + "vkGetInstanceProcAddr"); + } + + if(vkGetInstanceProcAddr) + { + _this->vulkan_config.loader_handle = DEFAULT_HANDLE; + } + else + { + if (!path) + { + /* Look for the .dylib packaged with the application instead. */ + path = DEFAULT_MOLTENVK; + } + + _this->vulkan_config.loader_handle = SDL_LoadObject(path); + if(!_this->vulkan_config.loader_handle) + return -1; + SDL_strlcpy(_this->vulkan_config.loader_path, path, + SDL_arraysize(_this->vulkan_config.loader_path)); + vkGetInstanceProcAddr = (PFN_vkGetInstanceProcAddr)SDL_LoadFunction( + _this->vulkan_config.loader_handle, "vkGetInstanceProcAddr"); + } + if(!vkGetInstanceProcAddr) + { + SDL_SetError("Failed to find %s in either executable or %s: %s", + "vkGetInstanceProcAddr", + DEFAULT_MOLTENVK, + (const char *) dlerror()); + goto fail; + } + + _this->vulkan_config.vkGetInstanceProcAddr = (void *)vkGetInstanceProcAddr; + _this->vulkan_config.vkEnumerateInstanceExtensionProperties = + (void *)((PFN_vkGetInstanceProcAddr)_this->vulkan_config.vkGetInstanceProcAddr)( + VK_NULL_HANDLE, "vkEnumerateInstanceExtensionProperties"); + if(!_this->vulkan_config.vkEnumerateInstanceExtensionProperties) + goto fail; + extensions = SDL_Vulkan_CreateInstanceExtensionsList( + (PFN_vkEnumerateInstanceExtensionProperties) + _this->vulkan_config.vkEnumerateInstanceExtensionProperties, + &extensionCount); + if(!extensions) + goto fail; + for(Uint32 i = 0; i < extensionCount; i++) + { + if(SDL_strcmp(VK_KHR_SURFACE_EXTENSION_NAME, extensions[i].extensionName) == 0) + hasSurfaceExtension = SDL_TRUE; + else if(SDL_strcmp(VK_MVK_MACOS_SURFACE_EXTENSION_NAME, extensions[i].extensionName) == 0) + hasMacOSSurfaceExtension = SDL_TRUE; + } + SDL_free(extensions); + if(!hasSurfaceExtension) + { + SDL_SetError("Installed MoltenVK/Vulkan doesn't implement the " + VK_KHR_SURFACE_EXTENSION_NAME " extension"); + goto fail; + } + else if(!hasMacOSSurfaceExtension) + { + SDL_SetError("Installed MoltenVK/Vulkan doesn't implement the " + VK_MVK_MACOS_SURFACE_EXTENSION_NAME "extension"); + goto fail; + } + return 0; + +fail: + SDL_UnloadObject(_this->vulkan_config.loader_handle); + _this->vulkan_config.loader_handle = NULL; + return -1; +} + +void Cocoa_Vulkan_UnloadLibrary(_THIS) +{ + if(_this->vulkan_config.loader_handle) + { + if (_this->vulkan_config.loader_handle != DEFAULT_HANDLE) + SDL_UnloadObject(_this->vulkan_config.loader_handle); + _this->vulkan_config.loader_handle = NULL; + } +} + +SDL_bool Cocoa_Vulkan_GetInstanceExtensions(_THIS, + SDL_Window *window, + unsigned *count, + const char **names) +{ + static const char *const extensionsForCocoa[] = { + VK_KHR_SURFACE_EXTENSION_NAME, VK_MVK_MACOS_SURFACE_EXTENSION_NAME + }; + if(!_this->vulkan_config.loader_handle) + { + SDL_SetError("Vulkan is not loaded"); + return SDL_FALSE; + } + return SDL_Vulkan_GetInstanceExtensions_Helper( + count, names, SDL_arraysize(extensionsForCocoa), + extensionsForCocoa); +} + +SDL_bool Cocoa_Vulkan_CreateSurface(_THIS, + SDL_Window *window, + VkInstance instance, + VkSurfaceKHR *surface) +{ + PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr = + (PFN_vkGetInstanceProcAddr)_this->vulkan_config.vkGetInstanceProcAddr; + PFN_vkCreateMacOSSurfaceMVK vkCreateMacOSSurfaceMVK = + (PFN_vkCreateMacOSSurfaceMVK)vkGetInstanceProcAddr( + (VkInstance)instance, + "vkCreateMacOSSurfaceMVK"); + VkMacOSSurfaceCreateInfoMVK createInfo = {}; + VkResult result; + + if(!_this->vulkan_config.loader_handle) + { + SDL_SetError("Vulkan is not loaded"); + return SDL_FALSE; + } + + if(!vkCreateMacOSSurfaceMVK) + { + SDL_SetError(VK_MVK_MACOS_SURFACE_EXTENSION_NAME + " extension is not enabled in the Vulkan instance."); + return SDL_FALSE; + } + createInfo.sType = VK_STRUCTURE_TYPE_MACOS_SURFACE_CREATE_INFO_MVK; + createInfo.pNext = NULL; + createInfo.flags = 0; + createInfo.pView = Cocoa_Mtl_AddMetalView(window); + result = vkCreateMacOSSurfaceMVK(instance, &createInfo, + NULL, surface); + if(result != VK_SUCCESS) + { + SDL_SetError("vkCreateMacOSSurfaceMVK failed: %s", + SDL_Vulkan_GetResultString(result)); + return SDL_FALSE; + } + return SDL_TRUE; +} + +void Cocoa_Vulkan_GetDrawableSize(_THIS, SDL_Window *window, int *w, int *h) +{ + Cocoa_Mtl_GetDrawableSize(window, w, h); +} + +#endif + +/* vim: set ts=4 sw=4 expandtab: */ diff --git a/src/video/mir/SDL_mirvideo.c b/src/video/mir/SDL_mirvideo.c index c1f2d40109fd5..767ada3781eda 100644 --- a/src/video/mir/SDL_mirvideo.c +++ b/src/video/mir/SDL_mirvideo.c @@ -36,6 +36,7 @@ #include "SDL_mirmouse.h" #include "SDL_miropengl.h" #include "SDL_mirvideo.h" +#include "SDL_mirvulkan.h" #include "SDL_mirdyn.h" @@ -232,6 +233,13 @@ MIR_CreateDevice(int device_index) device->ShowMessageBox = NULL; +#if SDL_VIDEO_VULKAN_SURFACE + device->Vulkan_LoadLibrary = MIR_Vulkan_LoadLibrary; + device->Vulkan_UnloadLibrary = MIR_Vulkan_UnloadLibrary; + device->Vulkan_GetInstanceExtensions = MIR_Vulkan_GetInstanceExtensions; + device->Vulkan_CreateSurface = MIR_Vulkan_CreateSurface; +#endif + return device; } diff --git a/src/video/mir/SDL_mirvideo.h b/src/video/mir/SDL_mirvideo.h index bd1b0f8548d5f..a0657250edfd3 100644 --- a/src/video/mir/SDL_mirvideo.h +++ b/src/video/mir/SDL_mirvideo.h @@ -28,6 +28,7 @@ #include #include +#include "SDL_stdinc.h" typedef struct MIR_Window MIR_Window; diff --git a/src/video/mir/SDL_mirvulkan.c b/src/video/mir/SDL_mirvulkan.c new file mode 100644 index 0000000000000..e81cb09aedfa5 --- /dev/null +++ b/src/video/mir/SDL_mirvulkan.c @@ -0,0 +1,175 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2016 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ + +/* + * @author Mark Callow, www.edgewise-consulting.com. Based on Jacob Lifshay's + * SDL_x11vulkan.c. + */ + +#include "../../SDL_internal.h" + +#if SDL_VIDEO_VULKAN_SURFACE && SDL_VIDEO_DRIVER_MIR + +#include "SDL_mirvideo.h" +#include "SDL_mirwindow.h" +#include "SDL_assert.h" + +#include "SDL_loadso.h" +#include "SDL_mirvulkan.h" +#include "SDL_syswm.h" + +int MIR_Vulkan_LoadLibrary(_THIS, const char *path) +{ + VkExtensionProperties *extensions = NULL; + Uint32 extensionCount = 0; + SDL_bool hasSurfaceExtension = SDL_FALSE; + SDL_bool hasMIRSurfaceExtension = SDL_FALSE; + PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr = NULL; + if(_this->vulkan_config.loader_handle) + return SDL_SetError("Vulkan already loaded"); + + /* Load the Vulkan loader library */ + if(!path) + path = SDL_getenv("SDL_VULKAN_LIBRARY"); + if(!path) + path = "libvulkan.so.1"; + _this->vulkan_config.loader_handle = SDL_LoadObject(path); + if(!_this->vulkan_config.loader_handle) + return -1; + SDL_strlcpy(_this->vulkan_config.loader_path, path, + SDL_arraysize(_this->vulkan_config.loader_path)); + vkGetInstanceProcAddr = (PFN_vkGetInstanceProcAddr)SDL_LoadFunction( + _this->vulkan_config.loader_handle, "vkGetInstanceProcAddr"); + if(!vkGetInstanceProcAddr) + goto fail; + _this->vulkan_config.vkGetInstanceProcAddr = (void *)vkGetInstanceProcAddr; + _this->vulkan_config.vkEnumerateInstanceExtensionProperties = + (void *)((PFN_vkGetInstanceProcAddr)_this->vulkan_config.vkGetInstanceProcAddr)( + VK_NULL_HANDLE, "vkEnumerateInstanceExtensionProperties"); + if(!_this->vulkan_config.vkEnumerateInstanceExtensionProperties) + goto fail; + extensions = SDL_Vulkan_CreateInstanceExtensionsList( + (PFN_vkEnumerateInstanceExtensionProperties) + _this->vulkan_config.vkEnumerateInstanceExtensionProperties, + &extensionCount); + if(!extensions) + goto fail; + for(Uint32 i = 0; i < extensionCount; i++) + { + if(SDL_strcmp(VK_KHR_SURFACE_EXTENSION_NAME, extensions[i].extensionName) == 0) + hasSurfaceExtension = SDL_TRUE; + else if(SDL_strcmp(VK_KHR_MIR_SURFACE_EXTENSION_NAME, extensions[i].extensionName) == 0) + hasMIRSurfaceExtension = SDL_TRUE; + } + SDL_free(extensions); + if(!hasSurfaceExtension) + { + SDL_SetError("Installed Vulkan doesn't implement the " + VK_KHR_SURFACE_EXTENSION_NAME " extension"); + goto fail; + } + else if(!hasMIRSurfaceExtension) + { + SDL_SetError("Installed Vulkan doesn't implement the " + VK_KHR_MIR_SURFACE_EXTENSION_NAME "extension"); + goto fail; + } + return 0; + +fail: + SDL_UnloadObject(_this->vulkan_config.loader_handle); + _this->vulkan_config.loader_handle = NULL; + return -1; +} + +void MIR_Vulkan_UnloadLibrary(_THIS) +{ + if(_this->vulkan_config.loader_handle) + { + SDL_UnloadObject(_this->vulkan_config.loader_handle); + _this->vulkan_config.loader_handle = NULL; + } +} + +SDL_bool MIR_Vulkan_GetInstanceExtensions(_THIS, + SDL_Window *window, + unsigned *count, + const char **names) +{ + static const char *const extensionsForMir[] = { + VK_KHR_SURFACE_EXTENSION_NAME, VK_KHR_MIR_SURFACE_EXTENSION_NAME + }; + if(!_this->vulkan_config.loader_handle) + { + SDL_SetError("Vulkan is not loaded"); + return SDL_FALSE; + } + return SDL_Vulkan_GetInstanceExtensions_Helper( + count, names, SDL_arraysize(extensionsForMir), + extensionsForMir); +} + +SDL_bool MIR_Vulkan_CreateSurface(_THIS, + SDL_Window *window, + VkInstance instance, + VkSurfaceKHR *surface) +{ + MIR_Window *windowData = (MIR_Window *)window->driverdata; + PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr = + (PFN_vkGetInstanceProcAddr)_this->vulkan_config.vkGetInstanceProcAddr; + PFN_vkCreateMirSurfaceKHR vkCreateMirSurfaceKHR = + (PFN_vkCreateMirSurfaceKHR)vkGetInstanceProcAddr( + (VkInstance)instance, + "vkCreateMirSurfaceKHR"); + VkMirSurfaceCreateInfoKHR createInfo = {}; + VkResult result; + + if(!_this->vulkan_config.loader_handle) + { + SDL_SetError("Vulkan is not loaded"); + return SDL_FALSE; + } + + if(!vkCreateMirSurfaceKHR) + { + SDL_SetError(VK_KHR_MIR_SURFACE_EXTENSION_NAME + " extension is not enabled in the Vulkan instance."); + return SDL_FALSE; + } + createInfo.sType = VK_STRUCTURE_TYPE_MIR_SURFACE_CREATE_INFO_KHR; + createInfo.pNext = NULL; + createInfo.flags = 0; + createInfo.connection = windowData->mir_data->connection; + createInfo.mirSurface = windowData->window; + result = vkCreateMirSurfaceKHR(instance, &createInfo, + NULL, surface); + if(result != VK_SUCCESS) + { + SDL_SetError("vkCreateMirSurfaceKHR failed: %s", + SDL_Vulkan_GetResultString(result)); + return SDL_FALSE; + } + return SDL_TRUE; +} + +#endif + +/* vim: set ts=4 sw=4 expandtab: */ diff --git a/src/video/mir/SDL_mirvulkan.h b/src/video/mir/SDL_mirvulkan.h new file mode 100644 index 0000000000000..42ad7ccc7a8e3 --- /dev/null +++ b/src/video/mir/SDL_mirvulkan.h @@ -0,0 +1,52 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2016 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ + +/* + * @author Mark Callow, www.edgewise-consulting.com. Based on Jacob Lifshay's + * SDL_x11vulkan.h. + */ + +#include "../../SDL_internal.h" + +#ifndef _SDL_mirvulkan_h +#define _SDL_mirvulkan_h + +#include "../SDL_vulkan_internal.h" +#include "../SDL_sysvideo.h" + +#if SDL_VIDEO_VULKAN_SURFACE && SDL_VIDEO_DRIVER_MIR + +int MIR_Vulkan_LoadLibrary(_THIS, const char *path); +void MIR_Vulkan_UnloadLibrary(_THIS); +SDL_bool MIR_Vulkan_GetInstanceExtensions(_THIS, + SDL_Window *window, + unsigned *count, + const char **names); +SDL_bool MIR_Vulkan_CreateSurface(_THIS, + SDL_Window *window, + VkInstance instance, + VkSurfaceKHR *surface); + +#endif + +#endif /* _SDL_mirvulkan_h */ + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/video/uikit/SDL_uikitmetalview.h b/src/video/uikit/SDL_uikitmetalview.h new file mode 100644 index 0000000000000..0099f58a958a9 --- /dev/null +++ b/src/video/uikit/SDL_uikitmetalview.h @@ -0,0 +1,53 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2017 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + */ + +/* + * @author Mark Callow, www.edgewise-consulting.com. + * + * Thanks to Alex Szpakowski, @slime73 on GitHub, for his gist showing + * how to add a CAMetalLayer backed view. + */ + +#ifndef _SDL_uikitmetalview_h +#define _SDL_uikitmetalview_h + +#import "../SDL_sysvideo.h" +#import "SDL_uikitwindow.h" + +#import +#import +#import + +#define METALVIEW_TAG 255 + +@interface SDL_uikitmetalview : UIView + +- (instancetype)initWithFrame:(CGRect)frame + scale:(CGFloat)scale + tag:(int)tag; + +@end + +SDL_uikitmetalview* UIKit_Mtl_AddMetalView(SDL_Window* window); + +void UIKit_Mtl_GetDrawableSize(SDL_Window * window, int * w, int * h); + +#endif /* _SDL_uikitmetalview_h */ diff --git a/src/video/uikit/SDL_uikitmetalview.m b/src/video/uikit/SDL_uikitmetalview.m new file mode 100644 index 0000000000000..a9d7875eb3abc --- /dev/null +++ b/src/video/uikit/SDL_uikitmetalview.m @@ -0,0 +1,146 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2017 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + */ + +/* + * @author Mark Callow, www.edgewise-consulting.com. + * + * Thanks to Alex Szpakowski, @slime73 on GitHub, for his gist showing + * how to add a CAMetalLayer backed view. + */ + +#include "../../SDL_internal.h" + +#if SDL_VIDEO_VULKAN_SURFACE && SDL_VIDEO_DRIVER_UIKIT + +#import "../SDL_sysvideo.h" +#import "SDL_uikitwindow.h" +#import "SDL_uikitmetalview.h" + +#include "SDL_assert.h" +#include "SDL_loadso.h" +#include + +static void* loader_handle; + +@implementation SDL_uikitmetalview + +/* Returns a Metal-compatible layer. */ ++ (Class)layerClass +{ + return [CAMetalLayer class]; +} + +- (instancetype)initWithFrame:(CGRect)frame + scale:(CGFloat)scale + tag:(int)tag +{ + if ((self = [super initWithFrame:frame])) { + /* Resize properly when rotated. */ + self.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; + + /* Set the appropriate scale (for retina display support) */ + self.contentScaleFactor = scale; + self.tag = tag; + + [self updateDrawableSize]; + } + + return self; +} + +/* Set the size of the metal drawables when the view is resized. */ +- (void)layoutSubviews +{ + [super layoutSubviews]; + [self updateDrawableSize]; +} + +- (void)updateDrawableSize +{ + CGSize size = self.bounds.size; + size.width *= self.contentScaleFactor; + size.height *= self.contentScaleFactor; + + ((CAMetalLayer *) self.layer).drawableSize = size; +} + +@end + +SDL_uikitmetalview* +UIKit_Mtl_AddMetalView(SDL_Window* window) +{ + SDL_WindowData *data = (__bridge SDL_WindowData *)window->driverdata; + SDL_uikitview *view = (SDL_uikitview*)data.uiwindow.rootViewController.view; + CGFloat scale = 1.0; + + if (window->flags & SDL_WINDOW_ALLOW_HIGHDPI) { + /* Set the scale to the natural scale factor of the screen - the + * backing dimensions of the Metal view will match the pixel + * dimensions of the screen rather than the dimensions in points. + */ +#ifdef __IPHONE_8_0 + if ([data.uiwindow.screen respondsToSelector:@selector(nativeScale)]) { + scale = data.uiwindow.screen.nativeScale; + } else +#endif + { + scale = data.uiwindow.screen.scale; + } + } + SDL_uikitmetalview *metalview + = [[SDL_uikitmetalview alloc] initWithFrame:view.frame + scale:scale + tag:METALVIEW_TAG]; +#if 1 + [view addSubview:metalview]; +#else + /* Sets this view as the controller's view, and adds the view to + * the window hierarchy. + * + * Left here for information. Not used because I suspect that for correct + * operation it will be necesary to copy everything from the window's + * current SDL_uikitview instance to the SDL_uikitview portion of the + * SDL_metalview. The latter would be derived from SDL_uikitview rather + * than UIView. */ + [metalview setSDLWindow:window]; +#endif + + return metalview; +} + +void +UIKit_Mtl_GetDrawableSize(SDL_Window * window, int * w, int * h) +{ + SDL_WindowData *data = (__bridge SDL_WindowData *)window->driverdata; + SDL_uikitview *view = (SDL_uikitview*)data.uiwindow.rootViewController.view; + SDL_uikitmetalview* metalview = [view viewWithTag:METALVIEW_TAG]; + if (metalview) { + CAMetalLayer *layer = (CAMetalLayer*)metalview.layer; + assert(layer != NULL); + if (w) + *w = layer.drawableSize.width; + if (h) + *h = layer.drawableSize.height; + } else + SDL_GetWindowSize(window, w, h); +} + +#endif diff --git a/src/video/uikit/SDL_uikitvideo.m b/src/video/uikit/SDL_uikitvideo.m index 617ce093b3078..39969db7831c3 100644 --- a/src/video/uikit/SDL_uikitvideo.m +++ b/src/video/uikit/SDL_uikitvideo.m @@ -37,6 +37,7 @@ #include "SDL_uikitwindow.h" #include "SDL_uikitopengles.h" #include "SDL_uikitclipboard.h" +#include "SDL_uikitvulkan.h" #define UIKITVID_DRIVER_NAME "uikit" @@ -123,6 +124,15 @@ static void UIKit_DeleteDevice(SDL_VideoDevice * device) device->GL_LoadLibrary = UIKit_GL_LoadLibrary; device->free = UIKit_DeleteDevice; + #if SDL_VIDEO_VULKAN_SURFACE + device->Vulkan_LoadLibrary = UIKit_Vulkan_LoadLibrary; + device->Vulkan_UnloadLibrary = UIKit_Vulkan_UnloadLibrary; + device->Vulkan_GetInstanceExtensions + = UIKit_Vulkan_GetInstanceExtensions; + device->Vulkan_CreateSurface = UIKit_Vulkan_CreateSurface; + device->Vulkan_GetDrawableSize = UIKit_Vulkan_GetDrawableSize; + #endif + device->gl_config.accelerated = 1; return device; diff --git a/src/video/uikit/SDL_uikitvulkan.h b/src/video/uikit/SDL_uikitvulkan.h new file mode 100644 index 0000000000000..55eeacf27c25a --- /dev/null +++ b/src/video/uikit/SDL_uikitvulkan.h @@ -0,0 +1,54 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2016 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ + +/* + * @author Mark Callow, www.edgewise-consulting.com. Based on Jacob Lifshay's + * SDL_x11vulkan.h. + */ + +#include "../../SDL_internal.h" + +#ifndef _SDL_uikitvulkan_h +#define _SDL_uikitvulkan_h + +#include "../SDL_vulkan_internal.h" +#include "../SDL_sysvideo.h" + +#if SDL_VIDEO_VULKAN_SURFACE && SDL_VIDEO_DRIVER_UIKIT + +int UIKit_Vulkan_LoadLibrary(_THIS, const char *path); +void UIKit_Vulkan_UnloadLibrary(_THIS); +SDL_bool UIKit_Vulkan_GetInstanceExtensions(_THIS, + SDL_Window *window, + unsigned *count, + const char **names); +SDL_bool UIKit_Vulkan_CreateSurface(_THIS, + SDL_Window *window, + VkInstance instance, + VkSurfaceKHR *surface); + +void UIKit_Vulkan_GetDrawableSize(_THIS, SDL_Window *window, int *w, int *h); + +#endif + +#endif /* _SDL_uikitvulkan_h */ + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/video/uikit/SDL_uikitvulkan.m b/src/video/uikit/SDL_uikitvulkan.m new file mode 100644 index 0000000000000..2e951f8ddf579 --- /dev/null +++ b/src/video/uikit/SDL_uikitvulkan.m @@ -0,0 +1,221 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2016 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ + +/* + * @author Mark Callow, www.edgewise-consulting.com. Based on Jacob Lifshay's + * SDL_x11vulkan.c. + */ + +#include "../../SDL_internal.h" + +#if SDL_VIDEO_VULKAN_SURFACE && SDL_VIDEO_DRIVER_UIKIT + +#include "SDL_uikitvideo.h" +#include "SDL_uikitwindow.h" +#include "SDL_assert.h" + +#include "SDL_loadso.h" +#include "SDL_uikitvulkan.h" +#include "SDL_uikitmetalview.h" +#include "SDL_syswm.h" + +#include + +#define DEFAULT_MOLTENVK "libMoltenVK.dylib" +/* Since libSDL is static, could use RTLD_SELF. Using RTLD_DEFAULT is future + * proofing. */ +#define DEFAULT_HANDLE RTLD_DEFAULT + +int UIKit_Vulkan_LoadLibrary(_THIS, const char *path) +{ + VkExtensionProperties *extensions = NULL; + Uint32 extensionCount = 0; + SDL_bool hasSurfaceExtension = SDL_FALSE; + SDL_bool hasIOSSurfaceExtension = SDL_FALSE; + PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr = NULL; + + if(_this->vulkan_config.loader_handle) + return SDL_SetError("MoltenVK/Vulkan already loaded"); + + /* Load the Vulkan loader library */ + if(!path) + path = SDL_getenv("SDL_VULKAN_LIBRARY"); + if(!path) + { + /* MoltenVK framework, currently, v0.17.0, has a static library and is + * the recommended way to use the package. There is likely no object to + * load. */ + vkGetInstanceProcAddr = + (PFN_vkGetInstanceProcAddr)dlsym(DEFAULT_HANDLE, + "vkGetInstanceProcAddr"); + } + + if(vkGetInstanceProcAddr) + { + _this->vulkan_config.loader_handle = DEFAULT_HANDLE; + } + else + { + if (!path) + { + /* Look for the .dylib packaged with the application instead. */ + path = DEFAULT_MOLTENVK; + } + + _this->vulkan_config.loader_handle = SDL_LoadObject(path); + if(!_this->vulkan_config.loader_handle) + return -1; + SDL_strlcpy(_this->vulkan_config.loader_path, path, + SDL_arraysize(_this->vulkan_config.loader_path)); + vkGetInstanceProcAddr = + (PFN_vkGetInstanceProcAddr)SDL_LoadFunction( + _this->vulkan_config.loader_handle, + "vkGetInstanceProcAddr"); + } + if(!vkGetInstanceProcAddr) + { + SDL_SetError("Failed to find %s in either executable or %s: %s", + "vkGetInstanceProcAddr", + DEFAULT_MOLTENVK, + (const char *) dlerror()); + goto fail; + } + + _this->vulkan_config.vkGetInstanceProcAddr = (void *)vkGetInstanceProcAddr; + _this->vulkan_config.vkEnumerateInstanceExtensionProperties = + (void *)((PFN_vkGetInstanceProcAddr)_this->vulkan_config.vkGetInstanceProcAddr)( + VK_NULL_HANDLE, "vkEnumerateInstanceExtensionProperties"); + if(!_this->vulkan_config.vkEnumerateInstanceExtensionProperties) + { + SDL_SetError("No vkEnumerateInstanceExtensionProperties found."); + goto fail; + } + extensions = SDL_Vulkan_CreateInstanceExtensionsList( + (PFN_vkEnumerateInstanceExtensionProperties) + _this->vulkan_config.vkEnumerateInstanceExtensionProperties, + &extensionCount); + if(!extensions) + goto fail; + for(Uint32 i = 0; i < extensionCount; i++) + { + if(SDL_strcmp(VK_KHR_SURFACE_EXTENSION_NAME, extensions[i].extensionName) == 0) + hasSurfaceExtension = SDL_TRUE; + else if(SDL_strcmp(VK_MVK_IOS_SURFACE_EXTENSION_NAME, extensions[i].extensionName) == 0) + hasIOSSurfaceExtension = SDL_TRUE; + } + SDL_free(extensions); + if(!hasSurfaceExtension) + { + SDL_SetError("Installed MoltenVK/Vulkan doesn't implement the " + VK_KHR_SURFACE_EXTENSION_NAME " extension"); + goto fail; + } + else if(!hasIOSSurfaceExtension) + { + SDL_SetError("Installed MoltenVK/Vulkan doesn't implement the " + VK_MVK_IOS_SURFACE_EXTENSION_NAME "extension"); + goto fail; + } + + return 0; + +fail: + _this->vulkan_config.loader_handle = NULL; + return -1; +} + +void UIKit_Vulkan_UnloadLibrary(_THIS) +{ + if(_this->vulkan_config.loader_handle) + { + if (_this->vulkan_config.loader_handle != DEFAULT_HANDLE) + SDL_UnloadObject(_this->vulkan_config.loader_handle); + _this->vulkan_config.loader_handle = NULL; + } +} + +SDL_bool UIKit_Vulkan_GetInstanceExtensions(_THIS, + SDL_Window *window, + unsigned *count, + const char **names) +{ + static const char *const extensionsForUIKit[] = { + VK_KHR_SURFACE_EXTENSION_NAME, VK_MVK_IOS_SURFACE_EXTENSION_NAME + }; + if(!_this->vulkan_config.loader_handle) + { + SDL_SetError("Vulkan is not loaded"); + return SDL_FALSE; + } + return SDL_Vulkan_GetInstanceExtensions_Helper( + count, names, SDL_arraysize(extensionsForUIKit), + extensionsForUIKit); +} + +SDL_bool UIKit_Vulkan_CreateSurface(_THIS, + SDL_Window *window, + VkInstance instance, + VkSurfaceKHR *surface) +{ + PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr = + (PFN_vkGetInstanceProcAddr)_this->vulkan_config.vkGetInstanceProcAddr; + PFN_vkCreateIOSSurfaceMVK vkCreateIOSSurfaceMVK = + (PFN_vkCreateIOSSurfaceMVK)vkGetInstanceProcAddr( + (VkInstance)instance, + "vkCreateIOSSurfaceMVK"); + VkIOSSurfaceCreateInfoMVK createInfo = {}; + VkResult result; + + if(!_this->vulkan_config.loader_handle) + { + SDL_SetError("Vulkan is not loaded"); + return SDL_FALSE; + } + + if(!vkCreateIOSSurfaceMVK) + { + SDL_SetError(VK_MVK_IOS_SURFACE_EXTENSION_NAME + " extension is not enabled in the Vulkan instance."); + return SDL_FALSE; + } + createInfo.sType = VK_STRUCTURE_TYPE_IOS_SURFACE_CREATE_INFO_MVK; + createInfo.pNext = NULL; + createInfo.flags = 0; + createInfo.pView = (__bridge void *)UIKit_Mtl_AddMetalView(window); + result = vkCreateIOSSurfaceMVK(instance, &createInfo, + NULL, surface); + if(result != VK_SUCCESS) + { + SDL_SetError("vkCreateIOSSurfaceMVK failed: %s", + SDL_Vulkan_GetResultString(result)); + return SDL_FALSE; + } + return SDL_TRUE; +} + +void UIKit_Vulkan_GetDrawableSize(_THIS, SDL_Window *window, int *w, int *h) +{ + UIKit_Mtl_GetDrawableSize(window, w, h); +} + +#endif + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/video/wayland/SDL_waylandvideo.c b/src/video/wayland/SDL_waylandvideo.c index 0539cf6bcefe5..7c936a74d6833 100644 --- a/src/video/wayland/SDL_waylandvideo.c +++ b/src/video/wayland/SDL_waylandvideo.c @@ -35,6 +35,7 @@ #include "SDL_waylandmouse.h" #include "SDL_waylandtouch.h" #include "SDL_waylandclipboard.h" +#include "SDL_waylandvulkan.h" #include #include @@ -181,6 +182,13 @@ Wayland_CreateDevice(int devindex) device->GetClipboardText = Wayland_GetClipboardText; device->HasClipboardText = Wayland_HasClipboardText; +#if SDL_VIDEO_VULKAN_SURFACE + device->Vulkan_LoadLibrary = Wayland_Vulkan_LoadLibrary; + device->Vulkan_UnloadLibrary = Wayland_Vulkan_UnloadLibrary; + device->Vulkan_GetInstanceExtensions = Wayland_Vulkan_GetInstanceExtensions; + device->Vulkan_CreateSurface = Wayland_Vulkan_CreateSurface; +#endif + device->free = Wayland_DeleteDevice; return device; diff --git a/src/video/wayland/SDL_waylandvulkan.c b/src/video/wayland/SDL_waylandvulkan.c new file mode 100644 index 0000000000000..f5a9a3a78342d --- /dev/null +++ b/src/video/wayland/SDL_waylandvulkan.c @@ -0,0 +1,175 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2016 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ + +/* + * @author Mark Callow, www.edgewise-consulting.com. Based on Jacob Lifshay's + * SDL_x11vulkan.c. + */ + +#include "../../SDL_internal.h" + +#if SDL_VIDEO_VULKAN_SURFACE && SDL_VIDEO_DRIVER_WAYLAND + +#include "SDL_waylandvideo.h" +#include "SDL_waylandwindow.h" +#include "SDL_assert.h" + +#include "SDL_loadso.h" +#include "SDL_waylandvulkan.h" +#include "SDL_syswm.h" + +int Wayland_Vulkan_LoadLibrary(_THIS, const char *path) +{ + VkExtensionProperties *extensions = NULL; + Uint32 extensionCount = 0; + SDL_bool hasSurfaceExtension = SDL_FALSE; + SDL_bool hasWaylandSurfaceExtension = SDL_FALSE; + PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr = NULL; + if(_this->vulkan_config.loader_handle) + return SDL_SetError("Vulkan already loaded"); + + /* Load the Vulkan loader library */ + if(!path) + path = SDL_getenv("SDL_VULKAN_LIBRARY"); + if(!path) + path = "libvulkan.so.1"; + _this->vulkan_config.loader_handle = SDL_LoadObject(path); + if(!_this->vulkan_config.loader_handle) + return -1; + SDL_strlcpy(_this->vulkan_config.loader_path, path, + SDL_arraysize(_this->vulkan_config.loader_path)); + vkGetInstanceProcAddr = (PFN_vkGetInstanceProcAddr)SDL_LoadFunction( + _this->vulkan_config.loader_handle, "vkGetInstanceProcAddr"); + if(!vkGetInstanceProcAddr) + goto fail; + _this->vulkan_config.vkGetInstanceProcAddr = (void *)vkGetInstanceProcAddr; + _this->vulkan_config.vkEnumerateInstanceExtensionProperties = + (void *)((PFN_vkGetInstanceProcAddr)_this->vulkan_config.vkGetInstanceProcAddr)( + VK_NULL_HANDLE, "vkEnumerateInstanceExtensionProperties"); + if(!_this->vulkan_config.vkEnumerateInstanceExtensionProperties) + goto fail; + extensions = SDL_Vulkan_CreateInstanceExtensionsList( + (PFN_vkEnumerateInstanceExtensionProperties) + _this->vulkan_config.vkEnumerateInstanceExtensionProperties, + &extensionCount); + if(!extensions) + goto fail; + for(Uint32 i = 0; i < extensionCount; i++) + { + if(SDL_strcmp(VK_KHR_SURFACE_EXTENSION_NAME, extensions[i].extensionName) == 0) + hasSurfaceExtension = SDL_TRUE; + else if(SDL_strcmp(VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME, extensions[i].extensionName) == 0) + hasWaylandSurfaceExtension = SDL_TRUE; + } + SDL_free(extensions); + if(!hasSurfaceExtension) + { + SDL_SetError("Installed Vulkan doesn't implement the " + VK_KHR_SURFACE_EXTENSION_NAME " extension"); + goto fail; + } + else if(!hasWaylandSurfaceExtension) + { + SDL_SetError("Installed Vulkan doesn't implement the " + VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME "extension"); + goto fail; + } + return 0; + +fail: + SDL_UnloadObject(_this->vulkan_config.loader_handle); + _this->vulkan_config.loader_handle = NULL; + return -1; +} + +void Wayland_Vulkan_UnloadLibrary(_THIS) +{ + if(_this->vulkan_config.loader_handle) + { + SDL_UnloadObject(_this->vulkan_config.loader_handle); + _this->vulkan_config.loader_handle = NULL; + } +} + +SDL_bool Wayland_Vulkan_GetInstanceExtensions(_THIS, + SDL_Window *window, + unsigned *count, + const char **names) +{ + static const char *const extensionsForWayland[] = { + VK_KHR_SURFACE_EXTENSION_NAME, VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME + }; + if(!_this->vulkan_config.loader_handle) + { + SDL_SetError("Vulkan is not loaded"); + return SDL_FALSE; + } + return SDL_Vulkan_GetInstanceExtensions_Helper( + count, names, SDL_arraysize(extensionsForWayland), + extensionsForWayland); +} + +SDL_bool Wayland_Vulkan_CreateSurface(_THIS, + SDL_Window *window, + VkInstance instance, + VkSurfaceKHR *surface) +{ + SDL_WindowData *windowData = (SDL_WindowData *)window->driverdata; + PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr = + (PFN_vkGetInstanceProcAddr)_this->vulkan_config.vkGetInstanceProcAddr; + PFN_vkCreateWaylandSurfaceKHR vkCreateWaylandSurfaceKHR = + (PFN_vkCreateWaylandSurfaceKHR)vkGetInstanceProcAddr( + (VkInstance)instance, + "vkCreateWaylandSurfaceKHR"); + VkWaylandSurfaceCreateInfoKHR createInfo = {}; + VkResult result; + + if(!_this->vulkan_config.loader_handle) + { + SDL_SetError("Vulkan is not loaded"); + return SDL_FALSE; + } + + if(!vkCreateWaylandSurfaceKHR) + { + SDL_SetError(VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME + " extension is not enabled in the Vulkan instance."); + return SDL_FALSE; + } + createInfo.sType = VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR; + createInfo.pNext = NULL; + createInfo.flags = 0; + createInfo.display = windowData->waylandData->display; + createInfo.surface = windowData->surface; + result = vkCreateWaylandSurfaceKHR(instance, &createInfo, + NULL, surface); + if(result != VK_SUCCESS) + { + SDL_SetError("vkCreateWaylandSurfaceKHR failed: %s", + SDL_Vulkan_GetResultString(result)); + return SDL_FALSE; + } + return SDL_TRUE; +} + +#endif + +/* vim: set ts=4 sw=4 expandtab: */ diff --git a/src/video/wayland/SDL_waylandvulkan.h b/src/video/wayland/SDL_waylandvulkan.h new file mode 100644 index 0000000000000..51c12c2ef0fae --- /dev/null +++ b/src/video/wayland/SDL_waylandvulkan.h @@ -0,0 +1,52 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2016 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ + +/* + * @author Mark Callow, www.edgewise-consulting.com. Based on Jacob Lifshay's + * SDL_x11vulkan.h. + */ + +#include "../../SDL_internal.h" + +#ifndef _SDL_waylandvulkan_h +#define _SDL_waylandvulkan_h + +#include "../SDL_vulkan_internal.h" +#include "../SDL_sysvideo.h" + +#if SDL_VIDEO_VULKAN_SURFACE && SDL_VIDEO_DRIVER_WAYLAND + +int Wayland_Vulkan_LoadLibrary(_THIS, const char *path); +void Wayland_Vulkan_UnloadLibrary(_THIS); +SDL_bool Wayland_Vulkan_GetInstanceExtensions(_THIS, + SDL_Window *window, + unsigned *count, + const char **names); +SDL_bool Wayland_Vulkan_CreateSurface(_THIS, + SDL_Window *window, + VkInstance instance, + VkSurfaceKHR *surface); + +#endif + +#endif /* _SDL_waylandvulkan_h */ + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/video/windows/SDL_windowsvideo.c b/src/video/windows/SDL_windowsvideo.c index f03ebb061b786..bff2f4f41e59a 100644 --- a/src/video/windows/SDL_windowsvideo.c +++ b/src/video/windows/SDL_windowsvideo.c @@ -33,6 +33,7 @@ #include "SDL_windowsvideo.h" #include "SDL_windowsframebuffer.h" #include "SDL_windowsshape.h" +#include "SDL_windowsvulkan.h" /* Initialization/Query functions */ static int WIN_VideoInit(_THIS); @@ -190,6 +191,13 @@ WIN_CreateDevice(int devindex) device->GL_SwapWindow = WIN_GLES_SwapWindow; device->GL_DeleteContext = WIN_GLES_DeleteContext; #endif +#if SDL_VIDEO_VULKAN_SURFACE + device->Vulkan_LoadLibrary = WIN_Vulkan_LoadLibrary; + device->Vulkan_UnloadLibrary = WIN_Vulkan_UnloadLibrary; + device->Vulkan_GetInstanceExtensions = WIN_Vulkan_GetInstanceExtensions; + device->Vulkan_CreateSurface = WIN_Vulkan_CreateSurface; +#endif + device->StartTextInput = WIN_StartTextInput; device->StopTextInput = WIN_StopTextInput; device->SetTextInputRect = WIN_SetTextInputRect; diff --git a/src/video/windows/SDL_windowsvulkan.c b/src/video/windows/SDL_windowsvulkan.c new file mode 100644 index 0000000000000..2bd4b66b4c7b3 --- /dev/null +++ b/src/video/windows/SDL_windowsvulkan.c @@ -0,0 +1,176 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2016 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ + +/* + * @author Mark Callow, www.edgewise-consulting.com. Based on Jacob Lifshay's + * SDL_x11vulkan.c. + */ + +#include "../../SDL_internal.h" + +#if SDL_VIDEO_VULKAN_SURFACE && SDL_VIDEO_DRIVER_WINDOWS + +#include "SDL_windowsvideo.h" +#include "SDL_windowswindow.h" +#include "SDL_assert.h" + +#include "SDL_loadso.h" +#include "SDL_windowsvulkan.h" +#include "SDL_syswm.h" + +int WIN_Vulkan_LoadLibrary(_THIS, const char *path) +{ + VkExtensionProperties *extensions = NULL; + Uint32 extensionCount = 0; + Uint32 i; + SDL_bool hasSurfaceExtension = SDL_FALSE; + SDL_bool hasWin32SurfaceExtension = SDL_FALSE; + PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr = NULL; + if(_this->vulkan_config.loader_handle) + return SDL_SetError("Vulkan already loaded"); + + /* Load the Vulkan loader library */ + if(!path) + path = SDL_getenv("SDL_VULKAN_LIBRARY"); + if(!path) + path = "vulkan-1.dll"; + _this->vulkan_config.loader_handle = SDL_LoadObject(path); + if(!_this->vulkan_config.loader_handle) + return -1; + SDL_strlcpy(_this->vulkan_config.loader_path, path, + SDL_arraysize(_this->vulkan_config.loader_path)); + vkGetInstanceProcAddr = (PFN_vkGetInstanceProcAddr)SDL_LoadFunction( + _this->vulkan_config.loader_handle, "vkGetInstanceProcAddr"); + if(!vkGetInstanceProcAddr) + goto fail; + _this->vulkan_config.vkGetInstanceProcAddr = (void *)vkGetInstanceProcAddr; + _this->vulkan_config.vkEnumerateInstanceExtensionProperties = + (void *)((PFN_vkGetInstanceProcAddr)_this->vulkan_config.vkGetInstanceProcAddr)( + VK_NULL_HANDLE, "vkEnumerateInstanceExtensionProperties"); + if(!_this->vulkan_config.vkEnumerateInstanceExtensionProperties) + goto fail; + extensions = SDL_Vulkan_CreateInstanceExtensionsList( + (PFN_vkEnumerateInstanceExtensionProperties) + _this->vulkan_config.vkEnumerateInstanceExtensionProperties, + &extensionCount); + if(!extensions) + goto fail; + for(i = 0; i < extensionCount; i++) + { + if(SDL_strcmp(VK_KHR_SURFACE_EXTENSION_NAME, extensions[i].extensionName) == 0) + hasSurfaceExtension = SDL_TRUE; + else if(SDL_strcmp(VK_KHR_WIN32_SURFACE_EXTENSION_NAME, extensions[i].extensionName) == 0) + hasWin32SurfaceExtension = SDL_TRUE; + } + SDL_free(extensions); + if(!hasSurfaceExtension) + { + SDL_SetError("Installed Vulkan doesn't implement the " + VK_KHR_SURFACE_EXTENSION_NAME " extension"); + goto fail; + } + else if(!hasWin32SurfaceExtension) + { + SDL_SetError("Installed Vulkan doesn't implement the " + VK_KHR_WIN32_SURFACE_EXTENSION_NAME "extension"); + goto fail; + } + return 0; + +fail: + SDL_UnloadObject(_this->vulkan_config.loader_handle); + _this->vulkan_config.loader_handle = NULL; + return -1; +} + +void WIN_Vulkan_UnloadLibrary(_THIS) +{ + if(_this->vulkan_config.loader_handle) + { + SDL_UnloadObject(_this->vulkan_config.loader_handle); + _this->vulkan_config.loader_handle = NULL; + } +} + +SDL_bool WIN_Vulkan_GetInstanceExtensions(_THIS, + SDL_Window *window, + unsigned *count, + const char **names) +{ + static const char *const extensionsForWin32[] = { + VK_KHR_SURFACE_EXTENSION_NAME, VK_KHR_WIN32_SURFACE_EXTENSION_NAME + }; + if(!_this->vulkan_config.loader_handle) + { + SDL_SetError("Vulkan is not loaded"); + return SDL_FALSE; + } + return SDL_Vulkan_GetInstanceExtensions_Helper( + count, names, SDL_arraysize(extensionsForWin32), + extensionsForWin32); +} + +SDL_bool WIN_Vulkan_CreateSurface(_THIS, + SDL_Window *window, + VkInstance instance, + VkSurfaceKHR *surface) +{ + SDL_WindowData *windowData = (SDL_WindowData *)window->driverdata; + PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr = + (PFN_vkGetInstanceProcAddr)_this->vulkan_config.vkGetInstanceProcAddr; + PFN_vkCreateWin32SurfaceKHR vkCreateWin32SurfaceKHR = + (PFN_vkCreateWin32SurfaceKHR)vkGetInstanceProcAddr( + (VkInstance)instance, + "vkCreateWin32SurfaceKHR"); + VkWin32SurfaceCreateInfoKHR createInfo; + VkResult result; + + if(!_this->vulkan_config.loader_handle) + { + SDL_SetError("Vulkan is not loaded"); + return SDL_FALSE; + } + + if(!vkCreateWin32SurfaceKHR) + { + SDL_SetError(VK_KHR_WIN32_SURFACE_EXTENSION_NAME + " extension is not enabled in the Vulkan instance."); + return SDL_FALSE; + } + createInfo.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR; + createInfo.pNext = NULL; + createInfo.flags = 0; + createInfo.hinstance = windowData->hinstance; + createInfo.hwnd = windowData->hwnd; + result = vkCreateWin32SurfaceKHR(instance, &createInfo, + NULL, surface); + if(result != VK_SUCCESS) + { + SDL_SetError("vkCreateWin32SurfaceKHR failed: %s", + SDL_Vulkan_GetResultString(result)); + return SDL_FALSE; + } + return SDL_TRUE; +} + +#endif + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/video/windows/SDL_windowsvulkan.h b/src/video/windows/SDL_windowsvulkan.h new file mode 100644 index 0000000000000..82284b14fad5f --- /dev/null +++ b/src/video/windows/SDL_windowsvulkan.h @@ -0,0 +1,52 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2016 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ + +/* + * @author Mark Callow, www.edgewise-consulting.com. Based on Jacob Lifshay's + * SDL_x11vulkan.h. + */ + +#include "../../SDL_internal.h" + +#ifndef _SDL_windowsvulkan_h +#define _SDL_windowsvulkan_h + +#include "../SDL_vulkan_internal.h" +#include "../SDL_sysvideo.h" + +#if SDL_VIDEO_VULKAN_SURFACE && SDL_VIDEO_DRIVER_WINDOWS + +int WIN_Vulkan_LoadLibrary(_THIS, const char *path); +void WIN_Vulkan_UnloadLibrary(_THIS); +SDL_bool WIN_Vulkan_GetInstanceExtensions(_THIS, + SDL_Window *window, + unsigned *count, + const char **names); +SDL_bool WIN_Vulkan_CreateSurface(_THIS, + SDL_Window *window, + VkInstance instance, + VkSurfaceKHR *surface); + +#endif + +#endif /* _SDL_windowsvulkan_h */ + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/video/x11/SDL_x11video.c b/src/video/x11/SDL_x11video.c index 0a73e29c9204a..a84dbdeb765f2 100644 --- a/src/video/x11/SDL_x11video.c +++ b/src/video/x11/SDL_x11video.c @@ -40,6 +40,8 @@ #include "SDL_x11opengles.h" #endif +#include "SDL_x11vulkan.h" + /* Initialization/Query functions */ static int X11_VideoInit(_THIS); static void X11_VideoQuit(_THIS); @@ -107,6 +109,9 @@ static void X11_DeleteDevice(SDL_VideoDevice * device) { SDL_VideoData *data = (SDL_VideoData *) device->driverdata; + if (device->vulkan_config.loader_handle) { + device->Vulkan_UnloadLibrary(device); + } if (data->display) { X11_XCloseDisplay(data->display); } @@ -291,6 +296,13 @@ X11_CreateDevice(int devindex) device->free = X11_DeleteDevice; +#if SDL_VIDEO_VULKAN_SURFACE + device->Vulkan_LoadLibrary = X11_Vulkan_LoadLibrary; + device->Vulkan_UnloadLibrary = X11_Vulkan_UnloadLibrary; + device->Vulkan_GetInstanceExtensions = X11_Vulkan_GetInstanceExtensions; + device->Vulkan_CreateSurface = X11_Vulkan_CreateSurface; +#endif + return device; } diff --git a/src/video/x11/SDL_x11video.h b/src/video/x11/SDL_x11video.h index 7df549e01d4ec..1b11aeb87f320 100644 --- a/src/video/x11/SDL_x11video.h +++ b/src/video/x11/SDL_x11video.h @@ -68,6 +68,7 @@ #include "SDL_x11mouse.h" #include "SDL_x11opengl.h" #include "SDL_x11window.h" +#include "SDL_x11vulkan.h" /* Private display data */ @@ -140,6 +141,12 @@ typedef struct SDL_VideoData KeyCode filter_code; Time filter_time; +#if SDL_VIDEO_VULKAN_SURFACE + /* Vulkan variables only valid if _this->vulkan_config.loader_handle is not NULL */ + void *vulkan_xlib_xcb_library; + PFN_XGetXCBConnection vulkan_XGetXCBConnection; +#endif + } SDL_VideoData; extern SDL_bool X11_UseDirectColorVisuals(void); diff --git a/src/video/x11/SDL_x11vulkan.c b/src/video/x11/SDL_x11vulkan.c new file mode 100644 index 0000000000000..3cba3001e28e5 --- /dev/null +++ b/src/video/x11/SDL_x11vulkan.c @@ -0,0 +1,239 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2016 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ +#include "../../SDL_internal.h" + +#if SDL_VIDEO_VULKAN_SURFACE && SDL_VIDEO_DRIVER_X11 + +#include "SDL_x11video.h" +#include "SDL_assert.h" + +#include "SDL_loadso.h" +#include "SDL_x11vulkan.h" + +#include +//#include +typedef uint32_t xcb_window_t; +typedef uint32_t xcb_visualid_t; + +int X11_Vulkan_LoadLibrary(_THIS, const char *path) +{ + SDL_VideoData *videoData = (SDL_VideoData *)_this->driverdata; + VkExtensionProperties *extensions = NULL; + Uint32 extensionCount = 0; + SDL_bool hasSurfaceExtension = SDL_FALSE; + SDL_bool hasXlibSurfaceExtension = SDL_FALSE; + SDL_bool hasXCBSurfaceExtension = SDL_FALSE; + PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr = NULL; + Uint32 i; + if(_this->vulkan_config.loader_handle) + return SDL_SetError("Vulkan already loaded"); + + /* Load the Vulkan loader library */ + if(!path) + path = SDL_getenv("SDL_VULKAN_LIBRARY"); + if(!path) + path = "libvulkan.so.1"; + _this->vulkan_config.loader_handle = SDL_LoadObject(path); + if(!_this->vulkan_config.loader_handle) + return -1; + SDL_strlcpy(_this->vulkan_config.loader_path, path, SDL_arraysize(_this->vulkan_config.loader_path)); + vkGetInstanceProcAddr = (PFN_vkGetInstanceProcAddr)SDL_LoadFunction( + _this->vulkan_config.loader_handle, "vkGetInstanceProcAddr"); + if(!vkGetInstanceProcAddr) + goto fail; + _this->vulkan_config.vkGetInstanceProcAddr = (void *)vkGetInstanceProcAddr; + _this->vulkan_config.vkEnumerateInstanceExtensionProperties = + (void *)((PFN_vkGetInstanceProcAddr)_this->vulkan_config.vkGetInstanceProcAddr)( + VK_NULL_HANDLE, "vkEnumerateInstanceExtensionProperties"); + if(!_this->vulkan_config.vkEnumerateInstanceExtensionProperties) + goto fail; + extensions = SDL_Vulkan_CreateInstanceExtensionsList( + (PFN_vkEnumerateInstanceExtensionProperties) + _this->vulkan_config.vkEnumerateInstanceExtensionProperties, + &extensionCount); + if(!extensions) + goto fail; + for(i = 0; i < extensionCount; i++) + { + if(SDL_strcmp(VK_KHR_SURFACE_EXTENSION_NAME, extensions[i].extensionName) == 0) + hasSurfaceExtension = SDL_TRUE; + else if(SDL_strcmp(VK_KHR_XCB_SURFACE_EXTENSION_NAME, extensions[i].extensionName) == 0) + hasXCBSurfaceExtension = SDL_TRUE; + else if(SDL_strcmp(VK_KHR_XLIB_SURFACE_EXTENSION_NAME, extensions[i].extensionName) == 0) + hasXlibSurfaceExtension = SDL_TRUE; + } + SDL_free(extensions); + if(!hasSurfaceExtension) + { + SDL_SetError("Installed Vulkan doesn't implement the " + VK_KHR_SURFACE_EXTENSION_NAME " extension"); + goto fail; + } + if(hasXlibSurfaceExtension) + { + videoData->vulkan_xlib_xcb_library = NULL; + } + else if(!hasXCBSurfaceExtension) + { + SDL_SetError("Installed Vulkan doesn't implement either the " + VK_KHR_XCB_SURFACE_EXTENSION_NAME "extension or the " + VK_KHR_XLIB_SURFACE_EXTENSION_NAME " extension"); + goto fail; + } + else + { + const char *libX11XCBLibraryName = SDL_getenv("SDL_X11_XCB_LIBRARY"); + if(!libX11XCBLibraryName) + libX11XCBLibraryName = "libX11-xcb.so"; + videoData->vulkan_xlib_xcb_library = SDL_LoadObject(libX11XCBLibraryName); + if(!videoData->vulkan_xlib_xcb_library) + goto fail; + videoData->vulkan_XGetXCBConnection = + SDL_LoadFunction(videoData->vulkan_xlib_xcb_library, "XGetXCBConnection"); + if(!videoData->vulkan_XGetXCBConnection) + { + SDL_UnloadObject(videoData->vulkan_xlib_xcb_library); + goto fail; + } + } + return 0; + +fail: + SDL_UnloadObject(_this->vulkan_config.loader_handle); + _this->vulkan_config.loader_handle = NULL; + return -1; +} + +void X11_Vulkan_UnloadLibrary(_THIS) +{ + SDL_VideoData *videoData = (SDL_VideoData *)_this->driverdata; + if(_this->vulkan_config.loader_handle) + { + if(videoData->vulkan_xlib_xcb_library) + SDL_UnloadObject(videoData->vulkan_xlib_xcb_library); + SDL_UnloadObject(_this->vulkan_config.loader_handle); + _this->vulkan_config.loader_handle = NULL; + } +} + +SDL_bool X11_Vulkan_GetInstanceExtensions(_THIS, + SDL_Window *window, + unsigned *count, + const char **names) +{ + SDL_VideoData *videoData = (SDL_VideoData *)_this->driverdata; + if(!_this->vulkan_config.loader_handle) + { + SDL_SetError("Vulkan is not loaded"); + return SDL_FALSE; + } + if(videoData->vulkan_xlib_xcb_library) + { + static const char *const extensionsForXCB[] = { + VK_KHR_SURFACE_EXTENSION_NAME, VK_KHR_XCB_SURFACE_EXTENSION_NAME, + }; + return SDL_Vulkan_GetInstanceExtensions_Helper( + count, names, SDL_arraysize(extensionsForXCB), extensionsForXCB); + } + else + { + static const char *const extensionsForXlib[] = { + VK_KHR_SURFACE_EXTENSION_NAME, VK_KHR_XLIB_SURFACE_EXTENSION_NAME, + }; + return SDL_Vulkan_GetInstanceExtensions_Helper( + count, names, SDL_arraysize(extensionsForXlib), extensionsForXlib); + } +} + +SDL_bool X11_Vulkan_CreateSurface(_THIS, + SDL_Window *window, + VkInstance instance, + VkSurfaceKHR *surface) +{ + SDL_VideoData *videoData = (SDL_VideoData *)_this->driverdata; + SDL_WindowData *windowData = (SDL_WindowData *)window->driverdata; + PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr; + if(!_this->vulkan_config.loader_handle) + { + SDL_SetError("Vulkan is not loaded"); + return SDL_FALSE; + } + vkGetInstanceProcAddr = (PFN_vkGetInstanceProcAddr)_this->vulkan_config.vkGetInstanceProcAddr; + if(videoData->vulkan_xlib_xcb_library) + { + PFN_vkCreateXcbSurfaceKHR vkCreateXcbSurfaceKHR = + (PFN_vkCreateXcbSurfaceKHR)vkGetInstanceProcAddr((VkInstance)instance, + "vkCreateXcbSurfaceKHR"); + VkXcbSurfaceCreateInfoKHR createInfo = {}; + VkResult result; + if(!vkCreateXcbSurfaceKHR) + { + SDL_SetError(VK_KHR_XCB_SURFACE_EXTENSION_NAME + " extension is not enabled in the Vulkan instance."); + return SDL_FALSE; + } + createInfo.sType = VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR; + createInfo.connection = videoData->vulkan_XGetXCBConnection(videoData->display); + if(!createInfo.connection) + { + SDL_SetError("XGetXCBConnection failed"); + return SDL_FALSE; + } + createInfo.window = (xcb_window_t)windowData->xwindow; + result = vkCreateXcbSurfaceKHR(instance, &createInfo, + NULL, surface); + if(result != VK_SUCCESS) + { + SDL_SetError("vkCreateXcbSurfaceKHR failed: %s", SDL_Vulkan_GetResultString(result)); + return SDL_FALSE; + } + return SDL_TRUE; + } + else + { + PFN_vkCreateXlibSurfaceKHR vkCreateXlibSurfaceKHR = + (PFN_vkCreateXlibSurfaceKHR)vkGetInstanceProcAddr((VkInstance)instance, + "vkCreateXlibSurfaceKHR"); + VkXlibSurfaceCreateInfoKHR createInfo = {}; + VkResult result; + if(!vkCreateXlibSurfaceKHR) + { + SDL_SetError(VK_KHR_XLIB_SURFACE_EXTENSION_NAME + " extension is not enabled in the Vulkan instance."); + return SDL_FALSE; + } + createInfo.sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR; + createInfo.dpy = videoData->display; + createInfo.window = (xcb_window_t)windowData->xwindow; + result = vkCreateXlibSurfaceKHR(instance, &createInfo, + NULL, surface); + if(result != VK_SUCCESS) + { + SDL_SetError("vkCreateXlibSurfaceKHR failed: %s", SDL_Vulkan_GetResultString(result)); + return SDL_FALSE; + } + return SDL_TRUE; + } +} + +#endif + +/* vim: set ts=4 sw=4 expandtab: */ diff --git a/src/video/x11/SDL_x11vulkan.h b/src/video/x11/SDL_x11vulkan.h new file mode 100644 index 0000000000000..d028473f80e64 --- /dev/null +++ b/src/video/x11/SDL_x11vulkan.h @@ -0,0 +1,48 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2016 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ +#include "../../SDL_internal.h" + +#ifndef _SDL_x11vulkan_h +#define _SDL_x11vulkan_h + +#include "../SDL_vulkan_internal.h" + +#if SDL_VIDEO_VULKAN_SURFACE && SDL_VIDEO_DRIVER_X11 + +typedef struct xcb_connection_t xcb_connection_t; +typedef xcb_connection_t *(*PFN_XGetXCBConnection)(Display *dpy); + +int X11_Vulkan_LoadLibrary(_THIS, const char *path); +void X11_Vulkan_UnloadLibrary(_THIS); +SDL_bool X11_Vulkan_GetInstanceExtensions(_THIS, + SDL_Window *window, + unsigned *count, + const char **names); +SDL_bool X11_Vulkan_CreateSurface(_THIS, + SDL_Window *window, + VkInstance instance, + VkSurfaceKHR *surface); + +#endif + +#endif /* _SDL_x11vulkan_h */ + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/test/Makefile.in b/test/Makefile.in index 53c2d3477afca..0ac70e923be68 100644 --- a/test/Makefile.in +++ b/test/Makefile.in @@ -66,6 +66,7 @@ TARGETS = \ testdisplayinfo$(EXE) \ testqsort$(EXE) \ controllermap$(EXE) \ + testvulkan$(EXE) \ all: Makefile $(TARGETS) copydatafiles @@ -289,6 +290,9 @@ testcustomcursor$(EXE): $(srcdir)/testcustomcursor.c controllermap$(EXE): $(srcdir)/controllermap.c $(CC) -o $@ $^ $(CFLAGS) $(LIBS) +testvulkan$(EXE): $(srcdir)/testvulkan.c + $(CC) -o $@ $^ $(CFLAGS) $(LIBS) + clean: rm -f $(TARGETS) diff --git a/test/configure b/test/configure index 61c32fba1bec6..79ba9ce762879 100755 --- a/test/configure +++ b/test/configure @@ -195,7 +195,8 @@ test -x / || exit 1" as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && - test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1" + test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1 +test \$(( 1 + 1 )) = 2 || exit 1" if (eval "$as_required") 2>/dev/null; then : as_have_required=yes else @@ -582,9 +583,47 @@ PACKAGE_BUGREPORT= PACKAGE_URL= ac_unique_file="README" +# Factoring default headers for most tests. +ac_includes_default="\ +#include +#ifdef HAVE_SYS_TYPES_H +# include +#endif +#ifdef HAVE_SYS_STAT_H +# include +#endif +#ifdef STDC_HEADERS +# include +# include +#else +# ifdef HAVE_STDLIB_H +# include +# endif +#endif +#ifdef HAVE_STRING_H +# if !defined STDC_HEADERS && defined HAVE_MEMORY_H +# include +# endif +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif +#ifdef HAVE_INTTYPES_H +# include +#endif +#ifdef HAVE_STDINT_H +# include +#endif +#ifdef HAVE_UNISTD_H +# include +#endif" + ac_subst_vars='LTLIBOBJS LIBOBJS SDL_TTF_LIB +EGREP +GREP XLIB GLES2LIB GLESLIB @@ -637,6 +676,7 @@ infodir docdir oldincludedir includedir +runstatedir localstatedir sharedstatedir sysconfdir @@ -717,6 +757,7 @@ datadir='${datarootdir}' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' +runstatedir='${localstatedir}/run' includedir='${prefix}/include' oldincludedir='/usr/include' docdir='${datarootdir}/doc/${PACKAGE}' @@ -969,6 +1010,15 @@ do | -silent | --silent | --silen | --sile | --sil) silent=yes ;; + -runstatedir | --runstatedir | --runstatedi | --runstated \ + | --runstate | --runstat | --runsta | --runst | --runs \ + | --run | --ru | --r) + ac_prev=runstatedir ;; + -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \ + | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \ + | --run=* | --ru=* | --r=*) + runstatedir=$ac_optarg ;; + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ @@ -1106,7 +1156,7 @@ fi for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ datadir sysconfdir sharedstatedir localstatedir includedir \ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ - libdir localedir mandir + libdir localedir mandir runstatedir do eval ac_val=\$$ac_var # Remove trailing slashes. @@ -1259,6 +1309,7 @@ Fine tuning of the installation directories: --sysconfdir=DIR read-only single-machine data [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] --localstatedir=DIR modifiable single-machine data [PREFIX/var] + --runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run] --libdir=DIR object code libraries [EPREFIX/lib] --includedir=DIR C header files [PREFIX/include] --oldincludedir=DIR C header files for non-gcc [/usr/include] @@ -1563,6 +1614,124 @@ fi as_fn_set_status $ac_retval } # ac_fn_c_try_cpp + +# ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES +# ------------------------------------------------------- +# Tests whether HEADER exists, giving a warning if it cannot be compiled using +# the include files in INCLUDES and setting the cache variable VAR +# accordingly. +ac_fn_c_check_header_mongrel () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if eval \${$3+:} false; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } +else + # Is the header compilable? +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5 +$as_echo_n "checking $2 usability... " >&6; } +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +#include <$2> +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_header_compiler=yes +else + ac_header_compiler=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5 +$as_echo "$ac_header_compiler" >&6; } + +# Is the header present? +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5 +$as_echo_n "checking $2 presence... " >&6; } +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <$2> +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + ac_header_preproc=yes +else + ac_header_preproc=no +fi +rm -f conftest.err conftest.i conftest.$ac_ext +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5 +$as_echo "$ac_header_preproc" >&6; } + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in #(( + yes:no: ) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5 +$as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 +$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} + ;; + no:yes:* ) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5 +$as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: check for missing prerequisite headers?" >&5 +$as_echo "$as_me: WARNING: $2: check for missing prerequisite headers?" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5 +$as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&5 +$as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 +$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} + ;; +esac + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +else + eval "$3=\$ac_header_compiler" +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } +fi + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_c_check_header_mongrel + +# ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES +# ------------------------------------------------------- +# Tests whether HEADER exists and can be compiled using the include files in +# INCLUDES, setting the cache variable VAR accordingly. +ac_fn_c_check_header_compile () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +#include <$2> +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + eval "$3=yes" +else + eval "$3=no" +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_c_check_header_compile cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. @@ -3919,6 +4088,289 @@ fi +have_vulkan_hdr=no +vsdk_include_dir="${VULKAN_SDK}/include" +vulkan_header="vulkan/vulkan.h" +save_CPPFLAGS="$CPPFLAGS" +CPPFLAGS="${save_CPPFLAGS} -I$vsdk_include_dir" +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 +$as_echo_n "checking for grep that handles long lines and -e... " >&6; } +if ${ac_cv_path_GREP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -z "$GREP"; then + ac_path_GREP_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in grep ggrep; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" + as_fn_executable_p "$ac_path_GREP" || continue +# Check for GNU ac_path_GREP and select it if it is found. + # Check for GNU $ac_path_GREP +case `"$ac_path_GREP" --version 2>&1` in +*GNU*) + ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; +*) + ac_count=0 + $as_echo_n 0123456789 >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + $as_echo 'GREP' >> "conftest.nl" + "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + as_fn_arith $ac_count + 1 && ac_count=$as_val + if test $ac_count -gt ${ac_path_GREP_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_GREP="$ac_path_GREP" + ac_path_GREP_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + $ac_path_GREP_found && break 3 + done + done + done +IFS=$as_save_IFS + if test -z "$ac_cv_path_GREP"; then + as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 + fi +else + ac_cv_path_GREP=$GREP +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 +$as_echo "$ac_cv_path_GREP" >&6; } + GREP="$ac_cv_path_GREP" + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 +$as_echo_n "checking for egrep... " >&6; } +if ${ac_cv_path_EGREP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 + then ac_cv_path_EGREP="$GREP -E" + else + if test -z "$EGREP"; then + ac_path_EGREP_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in egrep; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" + as_fn_executable_p "$ac_path_EGREP" || continue +# Check for GNU ac_path_EGREP and select it if it is found. + # Check for GNU $ac_path_EGREP +case `"$ac_path_EGREP" --version 2>&1` in +*GNU*) + ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; +*) + ac_count=0 + $as_echo_n 0123456789 >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + $as_echo 'EGREP' >> "conftest.nl" + "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + as_fn_arith $ac_count + 1 && ac_count=$as_val + if test $ac_count -gt ${ac_path_EGREP_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_EGREP="$ac_path_EGREP" + ac_path_EGREP_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + $ac_path_EGREP_found && break 3 + done + done + done +IFS=$as_save_IFS + if test -z "$ac_cv_path_EGREP"; then + as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 + fi +else + ac_cv_path_EGREP=$EGREP +fi + + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 +$as_echo "$ac_cv_path_EGREP" >&6; } + EGREP="$ac_cv_path_EGREP" + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 +$as_echo_n "checking for ANSI C header files... " >&6; } +if ${ac_cv_header_stdc+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +#include +#include + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_header_stdc=yes +else + ac_cv_header_stdc=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +if test $ac_cv_header_stdc = yes; then + # SunOS 4.x string.h does not declare mem*, contrary to ANSI. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "memchr" >/dev/null 2>&1; then : + +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "free" >/dev/null 2>&1; then : + +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. + if test "$cross_compiling" = yes; then : + : +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +#if ((' ' & 0x0FF) == 0x020) +# define ISLOWER(c) ('a' <= (c) && (c) <= 'z') +# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) +#else +# define ISLOWER(c) \ + (('a' <= (c) && (c) <= 'i') \ + || ('j' <= (c) && (c) <= 'r') \ + || ('s' <= (c) && (c) <= 'z')) +# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) +#endif + +#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) +int +main () +{ + int i; + for (i = 0; i < 256; i++) + if (XOR (islower (i), ISLOWER (i)) + || toupper (i) != TOUPPER (i)) + return 2; + return 0; +} +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + +else + ac_cv_header_stdc=no +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + +fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5 +$as_echo "$ac_cv_header_stdc" >&6; } +if test $ac_cv_header_stdc = yes; then + +$as_echo "#define STDC_HEADERS 1" >>confdefs.h + +fi + +# On IRIX 5.3, sys/types and inttypes.h are conflicting. +for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ + inttypes.h stdint.h unistd.h +do : + as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` +ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default +" +if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + +as_ac_Header=`$as_echo "ac_cv_header_$vulkan_header" | $as_tr_sh` +ac_fn_c_check_header_mongrel "$LINENO" "$vulkan_header" "$as_ac_Header" "$ac_includes_default" +if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : + have_vulkan_hdr=yes +else + have_vulkan_hdr=no +fi + + +CPPFLAGS="$save_CPPFLAGS" +if test x$have_vulkan_hdr = xyes; then + # vulkan.h has been found in either $VULKAN_SDK/include or along the + # the standard include path. Unfortunately there seems no easy + # way to find out which, so... + if test -n "$VULKAN_SDK" -a -f "$vsdk_include_dir/$vulkan_header"; then + CFLAGS="$CFLAGS -I$vsdk_include_dir" + fi +fi + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for TTF_Init in -lSDL2_ttf" >&5 $as_echo_n "checking for TTF_Init in -lSDL2_ttf... " >&6; } if ${ac_cv_lib_SDL2_ttf_TTF_Init+:} false; then : diff --git a/test/configure.in b/test/configure.in index fd3f3022bc2e5..6c5574b7f7063 100644 --- a/test/configure.in +++ b/test/configure.in @@ -179,6 +179,25 @@ AC_SUBST(GLESLIB) AC_SUBST(GLES2LIB) AC_SUBST(XLIB) +dnl Check for Vulkan Header +have_vulkan_hdr=no +vsdk_include_dir="${VULKAN_SDK}/include" +vulkan_header="vulkan/vulkan.h" +save_CPPFLAGS="$CPPFLAGS" +CPPFLAGS="${save_CPPFLAGS} -I$vsdk_include_dir" +AC_CHECK_HEADER($vulkan_header, + have_vulkan_hdr=yes, + have_vulkan_hdr=no) +CPPFLAGS="$save_CPPFLAGS" +if test x$have_vulkan_hdr = xyes; then + # vulkan.h has been found in either $VULKAN_SDK/include or along the + # the standard include path. Unfortunately there seems no easy + # way to find out which, so... + if test -n "$VULKAN_SDK" -a -f "$vsdk_include_dir/$vulkan_header"; then + CFLAGS="$CFLAGS -I$vsdk_include_dir" + fi +fi + dnl Check for SDL_ttf AC_CHECK_LIB(SDL2_ttf, TTF_Init, have_SDL_ttf=yes) if test x$have_SDL_ttf = xyes; then diff --git a/test/testvulkan.c b/test/testvulkan.c new file mode 100644 index 0000000000000..7eeec7b4013bd --- /dev/null +++ b/test/testvulkan.c @@ -0,0 +1,1195 @@ +/* + Copyright (C) 1997-2016 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely. +*/ +#include +#include +#include +#include + +#ifndef UINT64_MAX /* VS2008 */ +#define UINT64_MAX 18446744073709551615 +#endif + +#include "SDL_test_common.h" + +#if defined(__ANDROID__) && defined(__ARM_EABI__) && !defined(__ARM_ARCH_7A__) + +int main(int argc, char *argv[]) +{ + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "No Vulkan support on this system\n"); + return 1; +} + +#else + +#define VK_NO_PROTOTYPES +#include "vulkan/vulkan.h" + +#define VULKAN_FUNCTIONS() \ + VULKAN_DEVICE_FUNCTION(vkAcquireNextImageKHR) \ + VULKAN_DEVICE_FUNCTION(vkAllocateCommandBuffers) \ + VULKAN_DEVICE_FUNCTION(vkBeginCommandBuffer) \ + VULKAN_DEVICE_FUNCTION(vkCmdClearColorImage) \ + VULKAN_DEVICE_FUNCTION(vkCmdPipelineBarrier) \ + VULKAN_DEVICE_FUNCTION(vkCreateCommandPool) \ + VULKAN_DEVICE_FUNCTION(vkCreateFence) \ + VULKAN_DEVICE_FUNCTION(vkCreateImageView) \ + VULKAN_DEVICE_FUNCTION(vkCreateSemaphore) \ + VULKAN_DEVICE_FUNCTION(vkCreateSwapchainKHR) \ + VULKAN_DEVICE_FUNCTION(vkDestroyCommandPool) \ + VULKAN_DEVICE_FUNCTION(vkDestroyDevice) \ + VULKAN_DEVICE_FUNCTION(vkDestroyFence) \ + VULKAN_DEVICE_FUNCTION(vkDestroyImageView) \ + VULKAN_DEVICE_FUNCTION(vkDestroySemaphore) \ + VULKAN_DEVICE_FUNCTION(vkDestroySwapchainKHR) \ + VULKAN_DEVICE_FUNCTION(vkDeviceWaitIdle) \ + VULKAN_DEVICE_FUNCTION(vkEndCommandBuffer) \ + VULKAN_DEVICE_FUNCTION(vkFreeCommandBuffers) \ + VULKAN_DEVICE_FUNCTION(vkGetDeviceQueue) \ + VULKAN_DEVICE_FUNCTION(vkGetFenceStatus) \ + VULKAN_DEVICE_FUNCTION(vkGetSwapchainImagesKHR) \ + VULKAN_DEVICE_FUNCTION(vkQueuePresentKHR) \ + VULKAN_DEVICE_FUNCTION(vkQueueSubmit) \ + VULKAN_DEVICE_FUNCTION(vkResetCommandBuffer) \ + VULKAN_DEVICE_FUNCTION(vkResetFences) \ + VULKAN_DEVICE_FUNCTION(vkWaitForFences) \ + VULKAN_GLOBAL_FUNCTION(vkCreateInstance) \ + VULKAN_GLOBAL_FUNCTION(vkEnumerateInstanceExtensionProperties) \ + VULKAN_GLOBAL_FUNCTION(vkEnumerateInstanceLayerProperties) \ + VULKAN_INSTANCE_FUNCTION(vkCreateDevice) \ + VULKAN_INSTANCE_FUNCTION(vkDestroyInstance) \ + VULKAN_INSTANCE_FUNCTION(vkDestroySurfaceKHR) \ + VULKAN_INSTANCE_FUNCTION(vkEnumerateDeviceExtensionProperties) \ + VULKAN_INSTANCE_FUNCTION(vkEnumeratePhysicalDevices) \ + VULKAN_INSTANCE_FUNCTION(vkGetDeviceProcAddr) \ + VULKAN_INSTANCE_FUNCTION(vkGetPhysicalDeviceFeatures) \ + VULKAN_INSTANCE_FUNCTION(vkGetPhysicalDeviceProperties) \ + VULKAN_INSTANCE_FUNCTION(vkGetPhysicalDeviceQueueFamilyProperties) \ + VULKAN_INSTANCE_FUNCTION(vkGetPhysicalDeviceSurfaceCapabilitiesKHR) \ + VULKAN_INSTANCE_FUNCTION(vkGetPhysicalDeviceSurfaceFormatsKHR) \ + VULKAN_INSTANCE_FUNCTION(vkGetPhysicalDeviceSurfacePresentModesKHR) \ + VULKAN_INSTANCE_FUNCTION(vkGetPhysicalDeviceSurfaceSupportKHR) + +#define VULKAN_DEVICE_FUNCTION(name) static PFN_##name name = NULL; +#define VULKAN_GLOBAL_FUNCTION(name) static PFN_##name name = NULL; +#define VULKAN_INSTANCE_FUNCTION(name) static PFN_##name name = NULL; +VULKAN_FUNCTIONS() +#undef VULKAN_DEVICE_FUNCTION +#undef VULKAN_GLOBAL_FUNCTION +#undef VULKAN_INSTANCE_FUNCTION +static PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr = NULL; + +/* Based on the headers found in + * https://github.com/KhronosGroup/Vulkan-LoaderAndValidationLayers + */ +#if VK_HEADER_VERSION < 22 +enum +{ + VK_ERROR_FRAGMENTED_POOL = -12, +}; +#endif +#if VK_HEADER_VERSION < 38 +enum { + VK_ERROR_OUT_OF_POOL_MEMORY_KHR = -1000069000 +}; +#endif + +static const char *getVulkanResultString(VkResult result) +{ + switch((int)result) + { + case VK_SUCCESS: + return "VK_SUCCESS"; + case VK_NOT_READY: + return "VK_NOT_READY"; + case VK_TIMEOUT: + return "VK_TIMEOUT"; + case VK_EVENT_SET: + return "VK_EVENT_SET"; + case VK_EVENT_RESET: + return "VK_EVENT_RESET"; + case VK_INCOMPLETE: + return "VK_INCOMPLETE"; + case VK_ERROR_OUT_OF_HOST_MEMORY: + return "VK_ERROR_OUT_OF_HOST_MEMORY"; + case VK_ERROR_OUT_OF_DEVICE_MEMORY: + return "VK_ERROR_OUT_OF_DEVICE_MEMORY"; + case VK_ERROR_INITIALIZATION_FAILED: + return "VK_ERROR_INITIALIZATION_FAILED"; + case VK_ERROR_DEVICE_LOST: + return "VK_ERROR_DEVICE_LOST"; + case VK_ERROR_MEMORY_MAP_FAILED: + return "VK_ERROR_MEMORY_MAP_FAILED"; + case VK_ERROR_LAYER_NOT_PRESENT: + return "VK_ERROR_LAYER_NOT_PRESENT"; + case VK_ERROR_EXTENSION_NOT_PRESENT: + return "VK_ERROR_EXTENSION_NOT_PRESENT"; + case VK_ERROR_FEATURE_NOT_PRESENT: + return "VK_ERROR_FEATURE_NOT_PRESENT"; + case VK_ERROR_INCOMPATIBLE_DRIVER: + return "VK_ERROR_INCOMPATIBLE_DRIVER"; + case VK_ERROR_TOO_MANY_OBJECTS: + return "VK_ERROR_TOO_MANY_OBJECTS"; + case VK_ERROR_FORMAT_NOT_SUPPORTED: + return "VK_ERROR_FORMAT_NOT_SUPPORTED"; + case VK_ERROR_FRAGMENTED_POOL: + return "VK_ERROR_FRAGMENTED_POOL"; + case VK_ERROR_SURFACE_LOST_KHR: + return "VK_ERROR_SURFACE_LOST_KHR"; + case VK_ERROR_NATIVE_WINDOW_IN_USE_KHR: + return "VK_ERROR_NATIVE_WINDOW_IN_USE_KHR"; + case VK_SUBOPTIMAL_KHR: + return "VK_SUBOPTIMAL_KHR"; + case VK_ERROR_OUT_OF_DATE_KHR: + return "VK_ERROR_OUT_OF_DATE_KHR"; + case VK_ERROR_INCOMPATIBLE_DISPLAY_KHR: + return "VK_ERROR_INCOMPATIBLE_DISPLAY_KHR"; + case VK_ERROR_VALIDATION_FAILED_EXT: + return "VK_ERROR_VALIDATION_FAILED_EXT"; + case VK_ERROR_OUT_OF_POOL_MEMORY_KHR: + return "VK_ERROR_OUT_OF_POOL_MEMORY_KHR"; + case VK_ERROR_INVALID_SHADER_NV: + return "VK_ERROR_INVALID_SHADER_NV"; + case VK_RESULT_MAX_ENUM: + case VK_RESULT_RANGE_SIZE: + break; + } + if(result < 0) + return "VK_ERROR_"; + return "VK_"; +} + +typedef struct VulkanContext +{ + VkInstance instance; + VkDevice device; + VkSurfaceKHR surface; + VkSwapchainKHR swapchain; + VkPhysicalDeviceProperties physicalDeviceProperties; + VkPhysicalDeviceFeatures physicalDeviceFeatures; + uint32_t graphicsQueueFamilyIndex; + uint32_t presentQueueFamilyIndex; + VkPhysicalDevice physicalDevice; + VkQueue graphicsQueue; + VkQueue presentQueue; + VkSemaphore imageAvailableSemaphore; + VkSemaphore renderingFinishedSemaphore; + VkSurfaceCapabilitiesKHR surfaceCapabilities; + VkSurfaceFormatKHR *surfaceFormats; + uint32_t surfaceFormatsAllocatedCount; + uint32_t surfaceFormatsCount; + uint32_t swapchainDesiredImageCount; + VkSurfaceFormatKHR surfaceFormat; + VkExtent2D swapchainSize; + VkCommandPool commandPool; + uint32_t swapchainImageCount; + VkImage *swapchainImages; + VkCommandBuffer *commandBuffers; + VkFence *fences; +} VulkanContext; + +static SDLTest_CommonState *state; +static VulkanContext vulkanContext = {0}; + +static void shutdownVulkan(void); + +/* Call this instead of exit(), so we can clean up SDL: atexit() is evil. */ +static void quit(int rc) +{ + shutdownVulkan(); + SDLTest_CommonQuit(state); + exit(rc); +} + +static void loadGlobalFunctions(void) +{ + vkGetInstanceProcAddr = SDL_Vulkan_GetVkGetInstanceProcAddr(); + if(!vkGetInstanceProcAddr) + { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, + "SDL_Vulkan_GetVkGetInstanceProcAddr(): %s\n", + SDL_GetError()); + quit(2); + } + +#define VULKAN_DEVICE_FUNCTION(name) +#define VULKAN_GLOBAL_FUNCTION(name) \ + name = (PFN_##name)vkGetInstanceProcAddr(VK_NULL_HANDLE, #name); \ + if(!name) \ + { \ + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, \ + "vkGetInstanceProcAddr(VK_NULL_HANDLE, \"" #name "\") failed\n"); \ + quit(2); \ + } +#define VULKAN_INSTANCE_FUNCTION(name) + VULKAN_FUNCTIONS() +#undef VULKAN_DEVICE_FUNCTION +#undef VULKAN_GLOBAL_FUNCTION +#undef VULKAN_INSTANCE_FUNCTION +} + +static void createInstance(void) +{ + VkApplicationInfo appInfo = {0}; + VkInstanceCreateInfo instanceCreateInfo = {0}; + const char **extensions = NULL; + unsigned extensionCount = 0; + VkResult result; + + + appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; + appInfo.apiVersion = VK_API_VERSION_1_0; + instanceCreateInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; + instanceCreateInfo.pApplicationInfo = &appInfo; + if(!SDL_Vulkan_GetInstanceExtensions(state->windows[0], &extensionCount, NULL)) + { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, + "SDL_Vulkan_GetInstanceExtensions(): %s\n", + SDL_GetError()); + quit(2); + } + extensions = SDL_malloc(sizeof(const char *) * extensionCount); + if(!extensions) + { + SDL_OutOfMemory(); + quit(2); + } + if(!SDL_Vulkan_GetInstanceExtensions(state->windows[0], &extensionCount, extensions)) + { + SDL_free((void*)extensions); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, + "SDL_Vulkan_GetInstanceExtensions(): %s\n", + SDL_GetError()); + quit(2); + } + instanceCreateInfo.enabledExtensionCount = extensionCount; + instanceCreateInfo.ppEnabledExtensionNames = extensions; + result = vkCreateInstance(&instanceCreateInfo, NULL, &vulkanContext.instance); + SDL_free((void*)extensions); + if(result != VK_SUCCESS) + { + vulkanContext.instance = VK_NULL_HANDLE; + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, + "vkCreateInstance(): %s\n", + getVulkanResultString(result)); + quit(2); + } +} + +static void loadInstanceFunctions(void) +{ +#define VULKAN_DEVICE_FUNCTION(name) +#define VULKAN_GLOBAL_FUNCTION(name) +#define VULKAN_INSTANCE_FUNCTION(name) \ + name = (PFN_##name)vkGetInstanceProcAddr(vulkanContext.instance, #name); \ + if(!name) \ + { \ + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, \ + "vkGetInstanceProcAddr(instance, \"" #name "\") failed\n"); \ + quit(2); \ + } + VULKAN_FUNCTIONS() +#undef VULKAN_DEVICE_FUNCTION +#undef VULKAN_GLOBAL_FUNCTION +#undef VULKAN_INSTANCE_FUNCTION +} + +static void createSurface(void) +{ + if(!SDL_Vulkan_CreateSurface(state->windows[0], + vulkanContext.instance, + &vulkanContext.surface)) + { + vulkanContext.surface = VK_NULL_HANDLE; + SDL_LogError( + SDL_LOG_CATEGORY_APPLICATION, "SDL_Vulkan_CreateSurface(): %s\n", SDL_GetError()); + quit(2); + } +} + +static void findPhysicalDevice(void) +{ + uint32_t physicalDeviceCount = 0; + VkPhysicalDevice *physicalDevices; + VkQueueFamilyProperties *queueFamiliesProperties = NULL; + uint32_t queueFamiliesPropertiesAllocatedSize = 0; + VkExtensionProperties *deviceExtensions = NULL; + uint32_t deviceExtensionsAllocatedSize = 0; + uint32_t physicalDeviceIndex; + + VkResult result = + vkEnumeratePhysicalDevices(vulkanContext.instance, &physicalDeviceCount, NULL); + if(result != VK_SUCCESS) + { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, + "vkEnumeratePhysicalDevices(): %s\n", + getVulkanResultString(result)); + quit(2); + } + if(physicalDeviceCount == 0) + { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, + "vkEnumeratePhysicalDevices(): no physical devices\n"); + quit(2); + } + physicalDevices = SDL_malloc(sizeof(VkPhysicalDevice) * physicalDeviceCount); + if(!physicalDevices) + { + SDL_OutOfMemory(); + quit(2); + } + result = + vkEnumeratePhysicalDevices(vulkanContext.instance, &physicalDeviceCount, physicalDevices); + if(result != VK_SUCCESS) + { + SDL_free(physicalDevices); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, + "vkEnumeratePhysicalDevices(): %s\n", + getVulkanResultString(result)); + quit(2); + } + vulkanContext.physicalDevice = NULL; + for(physicalDeviceIndex = 0; physicalDeviceIndex < physicalDeviceCount; + physicalDeviceIndex++) + { + uint32_t queueFamiliesCount = 0; + uint32_t queueFamilyIndex; + uint32_t deviceExtensionCount = 0; + SDL_bool hasSwapchainExtension = SDL_FALSE; + uint32_t i; + + + VkPhysicalDevice physicalDevice = physicalDevices[physicalDeviceIndex]; + vkGetPhysicalDeviceProperties(physicalDevice, &vulkanContext.physicalDeviceProperties); + if(VK_VERSION_MAJOR(vulkanContext.physicalDeviceProperties.apiVersion) < 1) + continue; + vkGetPhysicalDeviceFeatures(physicalDevice, &vulkanContext.physicalDeviceFeatures); + vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &queueFamiliesCount, NULL); + if(queueFamiliesCount == 0) + continue; + if(queueFamiliesPropertiesAllocatedSize < queueFamiliesCount) + { + SDL_free(queueFamiliesProperties); + queueFamiliesPropertiesAllocatedSize = queueFamiliesCount; + queueFamiliesProperties = + SDL_malloc(sizeof(VkQueueFamilyProperties) * queueFamiliesPropertiesAllocatedSize); + if(!queueFamiliesProperties) + { + SDL_free(physicalDevices); + SDL_free(deviceExtensions); + SDL_OutOfMemory(); + quit(2); + } + } + vkGetPhysicalDeviceQueueFamilyProperties( + physicalDevice, &queueFamiliesCount, queueFamiliesProperties); + vulkanContext.graphicsQueueFamilyIndex = queueFamiliesCount; + vulkanContext.presentQueueFamilyIndex = queueFamiliesCount; + for(queueFamilyIndex = 0; queueFamilyIndex < queueFamiliesCount; + queueFamilyIndex++) + { + VkBool32 supported = 0; + + if(queueFamiliesProperties[queueFamilyIndex].queueCount == 0) + continue; + if(queueFamiliesProperties[queueFamilyIndex].queueFlags & VK_QUEUE_GRAPHICS_BIT) + vulkanContext.graphicsQueueFamilyIndex = queueFamilyIndex; + result = vkGetPhysicalDeviceSurfaceSupportKHR( + physicalDevice, queueFamilyIndex, vulkanContext.surface, &supported); + if(result != VK_SUCCESS) + { + SDL_free(physicalDevices); + SDL_free(queueFamiliesProperties); + SDL_free(deviceExtensions); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, + "vkGetPhysicalDeviceSurfaceSupportKHR(): %s\n", + getVulkanResultString(result)); + quit(2); + } + if(supported) + { + vulkanContext.presentQueueFamilyIndex = queueFamilyIndex; + if(queueFamiliesProperties[queueFamilyIndex].queueFlags & VK_QUEUE_GRAPHICS_BIT) + break; // use this queue because it can present and do graphics + } + } + if(vulkanContext.graphicsQueueFamilyIndex == queueFamiliesCount) // no good queues found + continue; + if(vulkanContext.presentQueueFamilyIndex == queueFamiliesCount) // no good queues found + continue; + result = + vkEnumerateDeviceExtensionProperties(physicalDevice, NULL, &deviceExtensionCount, NULL); + if(result != VK_SUCCESS) + { + SDL_free(physicalDevices); + SDL_free(queueFamiliesProperties); + SDL_free(deviceExtensions); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, + "vkEnumerateDeviceExtensionProperties(): %s\n", + getVulkanResultString(result)); + quit(2); + } + if(deviceExtensionCount == 0) + continue; + if(deviceExtensionsAllocatedSize < deviceExtensionCount) + { + SDL_free(deviceExtensions); + deviceExtensionsAllocatedSize = deviceExtensionCount; + deviceExtensions = + SDL_malloc(sizeof(VkExtensionProperties) * deviceExtensionsAllocatedSize); + if(!deviceExtensions) + { + SDL_free(physicalDevices); + SDL_free(queueFamiliesProperties); + SDL_OutOfMemory(); + quit(2); + } + } + result = vkEnumerateDeviceExtensionProperties( + physicalDevice, NULL, &deviceExtensionCount, deviceExtensions); + if(result != VK_SUCCESS) + { + SDL_free(physicalDevices); + SDL_free(queueFamiliesProperties); + SDL_free(deviceExtensions); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, + "vkEnumerateDeviceExtensionProperties(): %s\n", + getVulkanResultString(result)); + quit(2); + } + for(i = 0; i < deviceExtensionCount; i++) + { + if(0 == SDL_strcmp(deviceExtensions[i].extensionName, VK_KHR_SWAPCHAIN_EXTENSION_NAME)) + { + hasSwapchainExtension = SDL_TRUE; + break; + } + } + if(!hasSwapchainExtension) + continue; + vulkanContext.physicalDevice = physicalDevice; + break; + } + SDL_free(physicalDevices); + SDL_free(queueFamiliesProperties); + SDL_free(deviceExtensions); + if(!vulkanContext.physicalDevice) + { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Vulkan: no viable physical devices found"); + quit(2); + } +} + +static void createDevice(void) +{ + VkDeviceQueueCreateInfo deviceQueueCreateInfo[1] = {0}; + static const float queuePriority[] = {1.0f}; + VkDeviceCreateInfo deviceCreateInfo = {0}; + static const char *const deviceExtensionNames[] = { + VK_KHR_SWAPCHAIN_EXTENSION_NAME, + }; + VkResult result; + + deviceQueueCreateInfo->sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; + deviceQueueCreateInfo->queueFamilyIndex = vulkanContext.graphicsQueueFamilyIndex; + deviceQueueCreateInfo->queueCount = 1; + deviceQueueCreateInfo->pQueuePriorities = &queuePriority[0]; + + deviceCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; + deviceCreateInfo.queueCreateInfoCount = 1; + deviceCreateInfo.pQueueCreateInfos = deviceQueueCreateInfo; + deviceCreateInfo.pEnabledFeatures = NULL; + deviceCreateInfo.enabledExtensionCount = SDL_arraysize(deviceExtensionNames); + deviceCreateInfo.ppEnabledExtensionNames = deviceExtensionNames; + result = vkCreateDevice( + vulkanContext.physicalDevice, &deviceCreateInfo, NULL, &vulkanContext.device); + if(result != VK_SUCCESS) + { + vulkanContext.device = VK_NULL_HANDLE; + SDL_LogError( + SDL_LOG_CATEGORY_APPLICATION, "vkCreateDevice(): %s\n", getVulkanResultString(result)); + quit(2); + } +} + +static void loadDeviceFunctions(void) +{ +#define VULKAN_DEVICE_FUNCTION(name) \ + name = (PFN_##name)vkGetDeviceProcAddr(vulkanContext.device, #name); \ + if(!name) \ + { \ + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, \ + "vkGetDeviceProcAddr(device, \"" #name "\") failed\n"); \ + quit(2); \ + } +#define VULKAN_GLOBAL_FUNCTION(name) +#define VULKAN_INSTANCE_FUNCTION(name) + VULKAN_FUNCTIONS() +#undef VULKAN_DEVICE_FUNCTION +#undef VULKAN_GLOBAL_FUNCTION +#undef VULKAN_INSTANCE_FUNCTION +} + +#undef VULKAN_FUNCTIONS + +static void getQueues(void) +{ + vkGetDeviceQueue(vulkanContext.device, + vulkanContext.graphicsQueueFamilyIndex, + 0, + &vulkanContext.graphicsQueue); + if(vulkanContext.graphicsQueueFamilyIndex != vulkanContext.presentQueueFamilyIndex) + vkGetDeviceQueue(vulkanContext.device, + vulkanContext.presentQueueFamilyIndex, + 0, + &vulkanContext.presentQueue); + else + vulkanContext.presentQueue = vulkanContext.graphicsQueue; +} + +static void createSemaphore(VkSemaphore *semaphore) +{ + VkResult result; + + VkSemaphoreCreateInfo createInfo = {0}; + createInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; + result = vkCreateSemaphore(vulkanContext.device, &createInfo, NULL, semaphore); + if(result != VK_SUCCESS) + { + *semaphore = VK_NULL_HANDLE; + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, + "vkCreateSemaphore(): %s\n", + getVulkanResultString(result)); + quit(2); + } +} + +static void createSemaphores(void) +{ + createSemaphore(&vulkanContext.imageAvailableSemaphore); + createSemaphore(&vulkanContext.renderingFinishedSemaphore); +} + +static void getSurfaceCaps(void) +{ + VkResult result = vkGetPhysicalDeviceSurfaceCapabilitiesKHR( + vulkanContext.physicalDevice, vulkanContext.surface, &vulkanContext.surfaceCapabilities); + if(result != VK_SUCCESS) + { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, + "vkGetPhysicalDeviceSurfaceCapabilitiesKHR(): %s\n", + getVulkanResultString(result)); + quit(2); + } + + // check surface usage + if(!(vulkanContext.surfaceCapabilities.supportedUsageFlags & VK_IMAGE_USAGE_TRANSFER_DST_BIT)) + { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, + "Vulkan surface doesn't support VK_IMAGE_USAGE_TRANSFER_DST_BIT\n"); + quit(2); + } +} + +static void getSurfaceFormats(void) +{ + VkResult result = vkGetPhysicalDeviceSurfaceFormatsKHR(vulkanContext.physicalDevice, + vulkanContext.surface, + &vulkanContext.surfaceFormatsCount, + NULL); + if(result != VK_SUCCESS) + { + vulkanContext.surfaceFormatsCount = 0; + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, + "vkGetPhysicalDeviceSurfaceFormatsKHR(): %s\n", + getVulkanResultString(result)); + quit(2); + } + if(vulkanContext.surfaceFormatsCount > vulkanContext.surfaceFormatsAllocatedCount) + { + vulkanContext.surfaceFormatsAllocatedCount = vulkanContext.surfaceFormatsCount; + SDL_free(vulkanContext.surfaceFormats); + vulkanContext.surfaceFormats = + SDL_malloc(sizeof(VkSurfaceFormatKHR) * vulkanContext.surfaceFormatsAllocatedCount); + if(!vulkanContext.surfaceFormats) + { + vulkanContext.surfaceFormatsCount = 0; + SDL_OutOfMemory(); + quit(2); + } + } + result = vkGetPhysicalDeviceSurfaceFormatsKHR(vulkanContext.physicalDevice, + vulkanContext.surface, + &vulkanContext.surfaceFormatsCount, + vulkanContext.surfaceFormats); + if(result != VK_SUCCESS) + { + vulkanContext.surfaceFormatsCount = 0; + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, + "vkGetPhysicalDeviceSurfaceFormatsKHR(): %s\n", + getVulkanResultString(result)); + quit(2); + } +} + +static void getSwapchainImages(void) +{ + VkResult result; + + SDL_free(vulkanContext.swapchainImages); + vulkanContext.swapchainImages = NULL; + result = vkGetSwapchainImagesKHR( + vulkanContext.device, vulkanContext.swapchain, &vulkanContext.swapchainImageCount, NULL); + if(result != VK_SUCCESS) + { + vulkanContext.swapchainImageCount = 0; + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, + "vkGetSwapchainImagesKHR(): %s\n", + getVulkanResultString(result)); + quit(2); + } + vulkanContext.swapchainImages = SDL_malloc(sizeof(VkImage) * vulkanContext.swapchainImageCount); + if(!vulkanContext.swapchainImages) + { + SDL_OutOfMemory(); + quit(2); + } + result = vkGetSwapchainImagesKHR(vulkanContext.device, + vulkanContext.swapchain, + &vulkanContext.swapchainImageCount, + vulkanContext.swapchainImages); + if(result != VK_SUCCESS) + { + SDL_free(vulkanContext.swapchainImages); + vulkanContext.swapchainImages = NULL; + vulkanContext.swapchainImageCount = 0; + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, + "vkGetSwapchainImagesKHR(): %s\n", + getVulkanResultString(result)); + quit(2); + } +} + +static SDL_bool createSwapchain(void) +{ + uint32_t i; + int w, h; + VkSwapchainCreateInfoKHR createInfo = {0}; + VkResult result; + + // pick an image count + vulkanContext.swapchainDesiredImageCount = vulkanContext.surfaceCapabilities.minImageCount + 1; + if(vulkanContext.swapchainDesiredImageCount > vulkanContext.surfaceCapabilities.maxImageCount + && vulkanContext.surfaceCapabilities.maxImageCount > 0) + vulkanContext.swapchainDesiredImageCount = vulkanContext.surfaceCapabilities.maxImageCount; + + // pick a format + if(vulkanContext.surfaceFormatsCount == 1 + && vulkanContext.surfaceFormats[0].format == VK_FORMAT_UNDEFINED) + { + // aren't any preferred formats, so we pick + vulkanContext.surfaceFormat.colorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR; + vulkanContext.surfaceFormat.format = VK_FORMAT_R8G8B8A8_UNORM; + } + else + { + vulkanContext.surfaceFormat = vulkanContext.surfaceFormats[0]; + for(i = 0; i < vulkanContext.surfaceFormatsCount; i++) + { + if(vulkanContext.surfaceFormats[i].format == VK_FORMAT_R8G8B8A8_UNORM) + { + vulkanContext.surfaceFormat = vulkanContext.surfaceFormats[i]; + break; + } + } + } + + // get size + SDL_GL_GetDrawableSize(state->windows[0], &w, &h); + vulkanContext.swapchainSize.width = w; + vulkanContext.swapchainSize.height = h; + if(w == 0 || h == 0) + return SDL_FALSE; + + createInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; + createInfo.surface = vulkanContext.surface; + createInfo.minImageCount = vulkanContext.swapchainDesiredImageCount; + createInfo.imageFormat = vulkanContext.surfaceFormat.format; + createInfo.imageColorSpace = vulkanContext.surfaceFormat.colorSpace; + createInfo.imageExtent = vulkanContext.swapchainSize; + createInfo.imageArrayLayers = 1; + createInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT; + createInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; + createInfo.preTransform = vulkanContext.surfaceCapabilities.currentTransform; + createInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; + createInfo.presentMode = VK_PRESENT_MODE_FIFO_KHR; + createInfo.clipped = VK_TRUE; + createInfo.oldSwapchain = vulkanContext.swapchain; + result = + vkCreateSwapchainKHR(vulkanContext.device, &createInfo, NULL, &vulkanContext.swapchain); + if(createInfo.oldSwapchain) + vkDestroySwapchainKHR(vulkanContext.device, createInfo.oldSwapchain, NULL); + if(result != VK_SUCCESS) + { + vulkanContext.swapchain = VK_NULL_HANDLE; + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, + "vkCreateSwapchainKHR(): %s\n", + getVulkanResultString(result)); + quit(2); + } + getSwapchainImages(); + return SDL_TRUE; +} + +static void destroySwapchain(void) +{ + if(vulkanContext.swapchain) + vkDestroySwapchainKHR(vulkanContext.device, vulkanContext.swapchain, NULL); + vulkanContext.swapchain = VK_NULL_HANDLE; + SDL_free(vulkanContext.swapchainImages); + vulkanContext.swapchainImages = NULL; +} + +static void destroyCommandBuffers(void) +{ + if(vulkanContext.commandBuffers) + vkFreeCommandBuffers(vulkanContext.device, + vulkanContext.commandPool, + vulkanContext.swapchainImageCount, + vulkanContext.commandBuffers); + SDL_free(vulkanContext.commandBuffers); + vulkanContext.commandBuffers = NULL; +} + +static void destroyCommandPool(void) +{ + if(vulkanContext.commandPool) + vkDestroyCommandPool(vulkanContext.device, vulkanContext.commandPool, NULL); + vulkanContext.commandPool = VK_NULL_HANDLE; +} + +static void createCommandPool(void) +{ + VkResult result; + + VkCommandPoolCreateInfo createInfo = {0}; + createInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; + createInfo.flags = + VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT | VK_COMMAND_POOL_CREATE_TRANSIENT_BIT; + createInfo.queueFamilyIndex = vulkanContext.graphicsQueueFamilyIndex; + result = + vkCreateCommandPool(vulkanContext.device, &createInfo, NULL, &vulkanContext.commandPool); + if(result != VK_SUCCESS) + { + vulkanContext.commandPool = VK_NULL_HANDLE; + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, + "vkCreateCommandPool(): %s\n", + getVulkanResultString(result)); + quit(2); + } +} + +static void createCommandBuffers(void) +{ + VkResult result; + + VkCommandBufferAllocateInfo allocateInfo = {0}; + allocateInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; + allocateInfo.commandPool = vulkanContext.commandPool; + allocateInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; + allocateInfo.commandBufferCount = vulkanContext.swapchainImageCount; + vulkanContext.commandBuffers = + SDL_malloc(sizeof(VkCommandBuffer) * vulkanContext.swapchainImageCount); + result = + vkAllocateCommandBuffers(vulkanContext.device, &allocateInfo, vulkanContext.commandBuffers); + if(result != VK_SUCCESS) + { + SDL_free(vulkanContext.commandBuffers); + vulkanContext.commandBuffers = NULL; + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, + "vkAllocateCommandBuffers(): %s\n", + getVulkanResultString(result)); + quit(2); + } +} + +static void createFences(void) +{ + uint32_t i; + + vulkanContext.fences = SDL_malloc(sizeof(VkFence) * vulkanContext.swapchainImageCount); + if(!vulkanContext.fences) + { + SDL_OutOfMemory(); + quit(2); + } + for(i = 0; i < vulkanContext.swapchainImageCount; i++) + { + VkResult result; + + VkFenceCreateInfo createInfo = {0}; + createInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; + createInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT; + result = + vkCreateFence(vulkanContext.device, &createInfo, NULL, &vulkanContext.fences[i]); + if(result != VK_SUCCESS) + { + for(; i > 0; i--) + { + vkDestroyFence(vulkanContext.device, vulkanContext.fences[i - 1], NULL); + } + SDL_free(vulkanContext.fences); + vulkanContext.fences = NULL; + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, + "vkCreateFence(): %s\n", + getVulkanResultString(result)); + quit(2); + } + } +} + +static void destroyFences(void) +{ + uint32_t i; + + if(!vulkanContext.fences) + return; + for(i = 0; i < vulkanContext.swapchainImageCount; i++) + { + vkDestroyFence(vulkanContext.device, vulkanContext.fences[i], NULL); + } + SDL_free(vulkanContext.fences); + vulkanContext.fences = NULL; +} + +static void recordPipelineImageBarrier(VkCommandBuffer commandBuffer, + VkAccessFlags sourceAccessMask, + VkAccessFlags destAccessMask, + VkImageLayout sourceLayout, + VkImageLayout destLayout, + VkImage image) +{ + VkImageMemoryBarrier barrier = {0}; + barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + barrier.srcAccessMask = sourceAccessMask; + barrier.dstAccessMask = destAccessMask; + barrier.oldLayout = sourceLayout; + barrier.newLayout = destLayout; + barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + barrier.image = image; + barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + barrier.subresourceRange.baseMipLevel = 0; + barrier.subresourceRange.levelCount = 1; + barrier.subresourceRange.baseArrayLayer = 0; + barrier.subresourceRange.layerCount = 1; + vkCmdPipelineBarrier(commandBuffer, + VK_PIPELINE_STAGE_TRANSFER_BIT, + VK_PIPELINE_STAGE_TRANSFER_BIT, + 0, + 0, + NULL, + 0, + NULL, + 1, + &barrier); +} + +static void rerecordCommandBuffer(uint32_t frameIndex, const VkClearColorValue *clearColor) +{ + VkCommandBuffer commandBuffer = vulkanContext.commandBuffers[frameIndex]; + VkImage image = vulkanContext.swapchainImages[frameIndex]; + VkCommandBufferBeginInfo beginInfo = {0}; + VkImageSubresourceRange clearRange = {0}; + + VkResult result = vkResetCommandBuffer(commandBuffer, 0); + if(result != VK_SUCCESS) + { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, + "vkResetCommandBuffer(): %s\n", + getVulkanResultString(result)); + quit(2); + } + beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + beginInfo.flags = VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT; + result = vkBeginCommandBuffer(commandBuffer, &beginInfo); + if(result != VK_SUCCESS) + { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, + "vkBeginCommandBuffer(): %s\n", + getVulkanResultString(result)); + quit(2); + } + recordPipelineImageBarrier(commandBuffer, + 0, + VK_ACCESS_TRANSFER_WRITE_BIT, + VK_IMAGE_LAYOUT_UNDEFINED, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + image); + clearRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + clearRange.baseMipLevel = 0; + clearRange.levelCount = 1; + clearRange.baseArrayLayer = 0; + clearRange.layerCount = 1; + vkCmdClearColorImage( + commandBuffer, image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, clearColor, 1, &clearRange); + recordPipelineImageBarrier(commandBuffer, + VK_ACCESS_TRANSFER_WRITE_BIT, + VK_ACCESS_MEMORY_READ_BIT, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, + image); + result = vkEndCommandBuffer(commandBuffer); + if(result != VK_SUCCESS) + { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, + "vkEndCommandBuffer(): %s\n", + getVulkanResultString(result)); + quit(2); + } +} + +static void destroySwapchainAndSwapchainSpecificStuff(SDL_bool doDestroySwapchain) +{ + destroyFences(); + destroyCommandBuffers(); + destroyCommandPool(); + if(doDestroySwapchain) + destroySwapchain(); +} + +static SDL_bool createNewSwapchainAndSwapchainSpecificStuff(void) +{ + destroySwapchainAndSwapchainSpecificStuff(SDL_FALSE); + getSurfaceCaps(); + getSurfaceFormats(); + if(!createSwapchain()) + return SDL_FALSE; + createCommandPool(); + createCommandBuffers(); + createFences(); + return SDL_TRUE; +} + +static void initVulkan(void) +{ + SDL_Vulkan_LoadLibrary(NULL); + SDL_memset(&vulkanContext, 0, sizeof(VulkanContext)); + loadGlobalFunctions(); + createInstance(); + loadInstanceFunctions(); + createSurface(); + findPhysicalDevice(); + createDevice(); + loadDeviceFunctions(); + getQueues(); + createSemaphores(); + createNewSwapchainAndSwapchainSpecificStuff(); +} + +static void shutdownVulkan(void) +{ + if(vulkanContext.device && vkDeviceWaitIdle) + vkDeviceWaitIdle(vulkanContext.device); + destroySwapchainAndSwapchainSpecificStuff(SDL_TRUE); + if(vulkanContext.imageAvailableSemaphore && vkDestroySemaphore) + vkDestroySemaphore(vulkanContext.device, vulkanContext.imageAvailableSemaphore, NULL); + if(vulkanContext.renderingFinishedSemaphore && vkDestroySemaphore) + vkDestroySemaphore(vulkanContext.device, vulkanContext.renderingFinishedSemaphore, NULL); + if(vulkanContext.device && vkDestroyDevice) + vkDestroyDevice(vulkanContext.device, NULL); + if(vulkanContext.surface && vkDestroySurfaceKHR) + vkDestroySurfaceKHR(vulkanContext.instance, vulkanContext.surface, NULL); + if(vulkanContext.instance && vkDestroyInstance) + vkDestroyInstance(vulkanContext.instance, NULL); + SDL_free(vulkanContext.surfaceFormats); + SDL_Vulkan_UnloadLibrary(); +} + +static SDL_bool render(void) +{ + uint32_t frameIndex; + VkResult result; + double currentTime; + VkClearColorValue clearColor = {0}; + VkPipelineStageFlags waitDestStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT; + VkSubmitInfo submitInfo = {0}; + VkPresentInfoKHR presentInfo = {0}; + int w, h; + + if(!vulkanContext.swapchain) + { + SDL_bool retval = createNewSwapchainAndSwapchainSpecificStuff(); + if(!retval) + SDL_Delay(100); + return retval; + } + result = vkAcquireNextImageKHR(vulkanContext.device, + vulkanContext.swapchain, + UINT64_MAX, + vulkanContext.imageAvailableSemaphore, + VK_NULL_HANDLE, + &frameIndex); + if(result == VK_ERROR_OUT_OF_DATE_KHR) + return createNewSwapchainAndSwapchainSpecificStuff(); + if(result != VK_SUBOPTIMAL_KHR && result != VK_SUCCESS) + { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, + "vkAcquireNextImageKHR(): %s\n", + getVulkanResultString(result)); + quit(2); + } + result = vkWaitForFences( + vulkanContext.device, 1, &vulkanContext.fences[frameIndex], VK_FALSE, UINT64_MAX); + if(result != VK_SUCCESS) + { + SDL_LogError( + SDL_LOG_CATEGORY_APPLICATION, "vkWaitForFences(): %s\n", getVulkanResultString(result)); + quit(2); + } + result = vkResetFences(vulkanContext.device, 1, &vulkanContext.fences[frameIndex]); + if(result != VK_SUCCESS) + { + SDL_LogError( + SDL_LOG_CATEGORY_APPLICATION, "vkResetFences(): %s\n", getVulkanResultString(result)); + quit(2); + } + currentTime = (double)SDL_GetPerformanceCounter() / SDL_GetPerformanceFrequency(); + clearColor.float32[0] = (float)(0.5 + 0.5 * SDL_sin(currentTime)); + clearColor.float32[1] = (float)(0.5 + 0.5 * SDL_sin(currentTime + M_PI * 2 / 3)); + clearColor.float32[2] = (float)(0.5 + 0.5 * SDL_sin(currentTime + M_PI * 4 / 3)); + clearColor.float32[3] = 1; + rerecordCommandBuffer(frameIndex, &clearColor); + submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + submitInfo.waitSemaphoreCount = 1; + submitInfo.pWaitSemaphores = &vulkanContext.imageAvailableSemaphore; + submitInfo.pWaitDstStageMask = &waitDestStageMask; + submitInfo.commandBufferCount = 1; + submitInfo.pCommandBuffers = &vulkanContext.commandBuffers[frameIndex]; + submitInfo.signalSemaphoreCount = 1; + submitInfo.pSignalSemaphores = &vulkanContext.renderingFinishedSemaphore; + result = vkQueueSubmit( + vulkanContext.graphicsQueue, 1, &submitInfo, vulkanContext.fences[frameIndex]); + if(result != VK_SUCCESS) + { + SDL_LogError( + SDL_LOG_CATEGORY_APPLICATION, "vkQueueSubmit(): %s\n", getVulkanResultString(result)); + quit(2); + } + presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR; + presentInfo.waitSemaphoreCount = 1; + presentInfo.pWaitSemaphores = &vulkanContext.renderingFinishedSemaphore; + presentInfo.swapchainCount = 1; + presentInfo.pSwapchains = &vulkanContext.swapchain; + presentInfo.pImageIndices = &frameIndex; + result = vkQueuePresentKHR(vulkanContext.presentQueue, &presentInfo); + if(result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR) + { + return createNewSwapchainAndSwapchainSpecificStuff(); + } + if(result != VK_SUCCESS) + { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, + "vkQueuePresentKHR(): %s\n", + getVulkanResultString(result)); + quit(2); + } + SDL_GL_GetDrawableSize(state->windows[0], &w, &h); + if(w != (int)vulkanContext.swapchainSize.width || h != (int)vulkanContext.swapchainSize.height) + { + return createNewSwapchainAndSwapchainSpecificStuff(); + } + return SDL_TRUE; +} + +int main(int argc, char *argv[]) +{ + int fsaa, accel; + int i, done; + SDL_DisplayMode mode; + SDL_Event event; + Uint32 then, now, frames; + int dw, dh; + + /* Enable standard application logging */ + SDL_LogSetPriority(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO); + + /* Initialize parameters */ + fsaa = 0; + accel = -1; + + /* Initialize test framework */ + state = SDLTest_CommonCreateState(argv, SDL_INIT_VIDEO); + if(!state) + { + return 1; + } + for(i = 1; i < argc;) + { + int consumed; + + consumed = SDLTest_CommonArg(state, i); + if(consumed < 0) + { + SDL_Log("Usage: %s %s\n", argv[0], SDLTest_CommonUsage(state)); + quit(1); + } + i += consumed; + } + + /* Set Vulkan parameters */ + state->window_flags |= SDL_WINDOW_VULKAN; + state->num_windows = 1; + state->skip_renderer = 1; + + if(!SDLTest_CommonInit(state)) + { + quit(2); + } + + SDL_GetCurrentDisplayMode(0, &mode); + SDL_Log("Screen BPP : %d\n", SDL_BITSPERPIXEL(mode.format)); + SDL_GetWindowSize(state->windows[0], &dw, &dh); + SDL_Log("Window Size : %d,%d\n", dw, dh); + SDL_GL_GetDrawableSize(state->windows[0], &dw, &dh); + SDL_Log("Draw Size : %d,%d\n", dw, dh); + SDL_Log("\n"); + + initVulkan(); + + /* Main render loop */ + frames = 0; + then = SDL_GetTicks(); + done = 0; + while(!done) + { + /* Check for events */ + ++frames; + while(SDL_PollEvent(&event)) + { + SDLTest_CommonEvent(state, &event, &done); + } + + if(!done) + render(); + } + + /* Print out some timing information */ + now = SDL_GetTicks(); + if(now > then) + { + SDL_Log("%2.2f frames per second\n", ((double)frames * 1000) / (now - then)); + } + quit(0); + return 0; +} + +#endif