From c3aaf976aed0c0061061aba7c19a0ec67f1674d8 Mon Sep 17 00:00:00 2001 From: Bill Hollings Date: Fri, 10 May 2019 12:21:03 -0400 Subject: [PATCH] Add support for the VK_NV_glsl_shader extension. Support runtime shader compilation from GLSL. Return VK_ERROR_INVALID_SHADER_NV on shader and pipeline compilation errors. Add MVKShaderCompilationPerformance::glslToSPRIV to track GLSL conversion performance. Rename MoltenVKGLSLToSPIRVConverter MVKShaderStage enum to MVKGLSLConversionShaderStage to avoid naming conflicts with MoltenVK MVKShaderStage enum. Hologram demo load SPIR-V directly instead of using GLSL through either MoltenVKGLSLToSPIRVConverter or VK_NV_glsl_shader extension. Update to latest version of VulkanSamples that supports MVKGLSLConversionShaderStage. --- .../Hologram.xcodeproj/project.pbxproj | 48 ++--------- Demos/README.md | 6 -- Docs/MoltenVK_Runtime_UserGuide.md | 1 + Docs/Whats_New.md | 1 + ExternalRevisions/VulkanSamples_repo_revision | 2 +- MoltenVK/MoltenVK.xcodeproj/project.pbxproj | 30 ++++++- MoltenVK/MoltenVK/API/vk_mvk_moltenvk.h | 1 + MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm | 32 ++++---- .../MoltenVK/GPUObjects/MVKShaderModule.h | 14 ++-- .../MoltenVK/GPUObjects/MVKShaderModule.mm | 79 +++++++++++++++---- MoltenVK/MoltenVK/Layers/MVKExtensions.def | 3 +- .../GLSLConversion.h | 20 ++--- .../GLSLConversion.mm | 4 +- .../GLSLToSPIRVConverter.cpp | 32 +++----- .../GLSLToSPIRVConverter.h | 27 ++++--- .../SPIRVToMSLConverter.cpp | 4 - .../SPIRVToMSLConverter.h | 21 ++--- .../MoltenVKShaderConverterTool.cpp | 26 +++--- .../MoltenVKShaderConverterTool.h | 6 +- 19 files changed, 197 insertions(+), 160 deletions(-) diff --git a/Demos/LunarG-VulkanSamples/Hologram/Hologram.xcodeproj/project.pbxproj b/Demos/LunarG-VulkanSamples/Hologram/Hologram.xcodeproj/project.pbxproj index 950535ef..027b362f 100644 --- a/Demos/LunarG-VulkanSamples/Hologram/Hologram.xcodeproj/project.pbxproj +++ b/Demos/LunarG-VulkanSamples/Hologram/Hologram.xcodeproj/project.pbxproj @@ -9,12 +9,6 @@ /* Begin PBXBuildFile section */ A99789AF1CD3D4E2005E7DAC /* Hologram.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A99789831CD3D4E2005E7DAC /* Hologram.cpp */; }; A99789B01CD3D4E2005E7DAC /* Hologram.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A99789831CD3D4E2005E7DAC /* Hologram.cpp */; }; - A99789B11CD3D4E2005E7DAC /* Hologram.frag in Resources */ = {isa = PBXBuildFile; fileRef = A99789841CD3D4E2005E7DAC /* Hologram.frag */; }; - A99789B21CD3D4E2005E7DAC /* Hologram.frag in Resources */ = {isa = PBXBuildFile; fileRef = A99789841CD3D4E2005E7DAC /* Hologram.frag */; }; - A99789B31CD3D4E2005E7DAC /* Hologram.push_constant.vert in Resources */ = {isa = PBXBuildFile; fileRef = A99789861CD3D4E2005E7DAC /* Hologram.push_constant.vert */; }; - A99789B41CD3D4E2005E7DAC /* Hologram.push_constant.vert in Resources */ = {isa = PBXBuildFile; fileRef = A99789861CD3D4E2005E7DAC /* Hologram.push_constant.vert */; }; - A99789B51CD3D4E2005E7DAC /* Hologram.vert in Resources */ = {isa = PBXBuildFile; fileRef = A99789871CD3D4E2005E7DAC /* Hologram.vert */; }; - A99789B61CD3D4E2005E7DAC /* Hologram.vert in Resources */ = {isa = PBXBuildFile; fileRef = A99789871CD3D4E2005E7DAC /* Hologram.vert */; }; A99789B71CD3D4E2005E7DAC /* Main.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A99789881CD3D4E2005E7DAC /* Main.cpp */; }; A99789B81CD3D4E2005E7DAC /* Main.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A99789881CD3D4E2005E7DAC /* Main.cpp */; }; A99789B91CD3D4E2005E7DAC /* Meshes.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A99789891CD3D4E2005E7DAC /* Meshes.cpp */; }; @@ -38,8 +32,6 @@ A9B67B901C3AAEA200373FFD /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = A9B67B8A1C3AAEA200373FFD /* Main.storyboard */; }; A9B67B911C3AAEA200373FFD /* macOS.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = A9B67B8B1C3AAEA200373FFD /* macOS.xcassets */; }; A9C2AB99218503A400DDBC03 /* libMoltenVK.a in Frameworks */ = {isa = PBXBuildFile; fileRef = A9C2AB97218503A400DDBC03 /* libMoltenVK.a */; }; - A9C2AB9A218503A400DDBC03 /* MoltenVKGLSLToSPIRVConverter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A9C2AB98218503A400DDBC03 /* MoltenVKGLSLToSPIRVConverter.framework */; }; - A9C2AB9D218503BA00DDBC03 /* MoltenVKGLSLToSPIRVConverter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A9C2AB9B218503BA00DDBC03 /* MoltenVKGLSLToSPIRVConverter.framework */; }; A9C2AB9E218503BA00DDBC03 /* libMoltenVK.a in Frameworks */ = {isa = PBXBuildFile; fileRef = A9C2AB9C218503BA00DDBC03 /* libMoltenVK.a */; }; A9D516F81CD575E300097D96 /* HelpersDispatchTable.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9D516F61CD575E300097D96 /* HelpersDispatchTable.cpp */; }; A9D516F91CD575E300097D96 /* HelpersDispatchTable.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9D516F61CD575E300097D96 /* HelpersDispatchTable.cpp */; }; @@ -47,16 +39,16 @@ /* Begin PBXFileReference section */ 1D6058910D05DD3D006BFB54 /* Hologram.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Hologram.app; sourceTree = BUILT_PRODUCTS_DIR; }; + A93374642284CD260059D36E /* Hologram.vert.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Hologram.vert.h; path = android/src/main/jni/Hologram.vert.h; sourceTree = ""; }; + A93374652284CD260059D36E /* Hologram.push_constant.vert.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Hologram.push_constant.vert.h; path = android/src/main/jni/Hologram.push_constant.vert.h; sourceTree = ""; }; + A93374662284CD260059D36E /* Hologram.frag.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Hologram.frag.h; path = android/src/main/jni/Hologram.frag.h; sourceTree = ""; }; A93CC3701CD56B8F00EB8A56 /* generate-dispatch-table */ = {isa = PBXFileReference; explicitFileType = text.script.python; path = "generate-dispatch-table"; sourceTree = ""; }; A93CC3711CD56FD600EB8A56 /* CMakeLists.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = CMakeLists.txt; sourceTree = ""; }; A977BCFE1B66BB010067E5BF /* Hologram.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Hologram.app; sourceTree = BUILT_PRODUCTS_DIR; }; A997897F1CD3D4E2005E7DAC /* Game.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Game.h; sourceTree = ""; }; A99789821CD3D4E2005E7DAC /* Helpers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Helpers.h; sourceTree = ""; }; A99789831CD3D4E2005E7DAC /* Hologram.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Hologram.cpp; sourceTree = ""; }; - A99789841CD3D4E2005E7DAC /* Hologram.frag */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.glsl; path = Hologram.frag; sourceTree = ""; }; A99789851CD3D4E2005E7DAC /* Hologram.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Hologram.h; sourceTree = ""; }; - A99789861CD3D4E2005E7DAC /* Hologram.push_constant.vert */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.glsl; path = Hologram.push_constant.vert; sourceTree = ""; }; - A99789871CD3D4E2005E7DAC /* Hologram.vert */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.glsl; path = Hologram.vert; sourceTree = ""; }; A99789881CD3D4E2005E7DAC /* Main.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Main.cpp; sourceTree = ""; }; A99789891CD3D4E2005E7DAC /* Meshes.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Meshes.cpp; sourceTree = ""; }; A997898A1CD3D4E2005E7DAC /* Meshes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Meshes.h; sourceTree = ""; }; @@ -88,8 +80,6 @@ A9B67B8A1C3AAEA200373FFD /* Main.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = Main.storyboard; sourceTree = ""; }; A9B67B8B1C3AAEA200373FFD /* macOS.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = macOS.xcassets; sourceTree = ""; }; A9C2AB97218503A400DDBC03 /* libMoltenVK.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libMoltenVK.a; path = ../../../MoltenVK/iOS/static/libMoltenVK.a; sourceTree = ""; }; - A9C2AB98218503A400DDBC03 /* MoltenVKGLSLToSPIRVConverter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MoltenVKGLSLToSPIRVConverter.framework; path = ../../../MoltenVKShaderConverter/MoltenVKGLSLToSPIRVConverter/iOS/framework/MoltenVKGLSLToSPIRVConverter.framework; sourceTree = ""; }; - A9C2AB9B218503BA00DDBC03 /* MoltenVKGLSLToSPIRVConverter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MoltenVKGLSLToSPIRVConverter.framework; path = ../../../MoltenVKShaderConverter/MoltenVKGLSLToSPIRVConverter/macOS/framework/MoltenVKGLSLToSPIRVConverter.framework; sourceTree = ""; }; A9C2AB9C218503BA00DDBC03 /* libMoltenVK.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libMoltenVK.a; path = ../../../MoltenVK/macOS/static/libMoltenVK.a; sourceTree = ""; }; A9D516F61CD575E300097D96 /* HelpersDispatchTable.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = HelpersDispatchTable.cpp; sourceTree = ""; }; A9D516F71CD575E300097D96 /* HelpersDispatchTable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HelpersDispatchTable.h; sourceTree = ""; }; @@ -101,7 +91,6 @@ buildActionMask = 2147483647; files = ( A9C2AB99218503A400DDBC03 /* libMoltenVK.a in Frameworks */, - A9C2AB9A218503A400DDBC03 /* MoltenVKGLSLToSPIRVConverter.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -110,7 +99,6 @@ buildActionMask = 2147483647; files = ( A9C2AB9E218503BA00DDBC03 /* libMoltenVK.a in Frameworks */, - A9C2AB9D218503BA00DDBC03 /* MoltenVKGLSLToSPIRVConverter.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -147,10 +135,10 @@ A997897F1CD3D4E2005E7DAC /* Game.h */, A99789821CD3D4E2005E7DAC /* Helpers.h */, A99789831CD3D4E2005E7DAC /* Hologram.cpp */, - A99789841CD3D4E2005E7DAC /* Hologram.frag */, A99789851CD3D4E2005E7DAC /* Hologram.h */, - A99789861CD3D4E2005E7DAC /* Hologram.push_constant.vert */, - A99789871CD3D4E2005E7DAC /* Hologram.vert */, + A93374662284CD260059D36E /* Hologram.frag.h */, + A93374652284CD260059D36E /* Hologram.push_constant.vert.h */, + A93374642284CD260059D36E /* Hologram.vert.h */, A99789881CD3D4E2005E7DAC /* Main.cpp */, A99789891CD3D4E2005E7DAC /* Meshes.cpp */, A997898A1CD3D4E2005E7DAC /* Meshes.h */, @@ -220,9 +208,7 @@ isa = PBXGroup; children = ( A9C2AB9C218503BA00DDBC03 /* libMoltenVK.a */, - A9C2AB9B218503BA00DDBC03 /* MoltenVKGLSLToSPIRVConverter.framework */, A9C2AB97218503A400DDBC03 /* libMoltenVK.a */, - A9C2AB98218503A400DDBC03 /* MoltenVKGLSLToSPIRVConverter.framework */, ); name = Frameworks; sourceTree = ""; @@ -312,12 +298,9 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( - A99789B51CD3D4E2005E7DAC /* Hologram.vert in Resources */, A9B67B7F1C3AAE9800373FFD /* Icon.png in Resources */, - A99789B31CD3D4E2005E7DAC /* Hologram.push_constant.vert in Resources */, A9B67B801C3AAE9800373FFD /* Main.storyboard in Resources */, A9B67B7E1C3AAE9800373FFD /* Default~ipad.png in Resources */, - A99789B11CD3D4E2005E7DAC /* Hologram.frag in Resources */, A9B67B7D1C3AAE9800373FFD /* Default-568h@2x.png in Resources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -327,10 +310,7 @@ buildActionMask = 2147483647; files = ( A9B67B911C3AAEA200373FFD /* macOS.xcassets in Resources */, - A99789B21CD3D4E2005E7DAC /* Hologram.frag in Resources */, A9B67B901C3AAEA200373FFD /* Main.storyboard in Resources */, - A99789B41CD3D4E2005E7DAC /* Hologram.push_constant.vert in Resources */, - A99789B61CD3D4E2005E7DAC /* Hologram.vert in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -379,9 +359,7 @@ buildSettings = { CODE_SIGN_IDENTITY = "iPhone Developer"; DEVELOPMENT_TEAM = ""; - FRAMEWORK_SEARCH_PATHS = "\"$(SRCROOT)/../../../MoltenVKShaderConverter/MoltenVKGLSLToSPIRVConverter/iOS/framework\""; GCC_PREFIX_HEADER = "$(SRCROOT)/iOS/Prefix.pch"; - GCC_PREPROCESSOR_DEFINITIONS = "$(inherited)"; INFOPLIST_FILE = "$(SRCROOT)/iOS/Info.plist"; IPHONEOS_DEPLOYMENT_TARGET = 9.0; LIBRARY_SEARCH_PATHS = "\"$(SRCROOT)/../../../MoltenVK/iOS/static\""; @@ -396,9 +374,7 @@ buildSettings = { CODE_SIGN_IDENTITY = "iPhone Developer"; DEVELOPMENT_TEAM = ""; - FRAMEWORK_SEARCH_PATHS = "\"$(SRCROOT)/../../../MoltenVKShaderConverter/MoltenVKGLSLToSPIRVConverter/iOS/framework\""; GCC_PREFIX_HEADER = "$(SRCROOT)/iOS/Prefix.pch"; - GCC_PREPROCESSOR_DEFINITIONS = "$(inherited)"; INFOPLIST_FILE = "$(SRCROOT)/iOS/Info.plist"; IPHONEOS_DEPLOYMENT_TARGET = 9.0; LIBRARY_SEARCH_PATHS = "\"$(SRCROOT)/../../../MoltenVK/iOS/static\""; @@ -413,9 +389,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; COMBINE_HIDPI_IMAGES = YES; - FRAMEWORK_SEARCH_PATHS = "\"$(SRCROOT)/../../../MoltenVKShaderConverter/MoltenVKGLSLToSPIRVConverter/macOS/framework\""; GCC_PREFIX_HEADER = "$(SRCROOT)/macOS/Prefix.pch"; - GCC_PREPROCESSOR_DEFINITIONS = "$(inherited)"; INFOPLIST_FILE = "$(SRCROOT)/macOS/Info.plist"; LIBRARY_SEARCH_PATHS = "\"$(SRCROOT)/../../../MoltenVK/macOS/static\""; MACOSX_DEPLOYMENT_TARGET = 10.11; @@ -432,9 +406,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; COMBINE_HIDPI_IMAGES = YES; - FRAMEWORK_SEARCH_PATHS = "\"$(SRCROOT)/../../../MoltenVKShaderConverter/MoltenVKGLSLToSPIRVConverter/macOS/framework\""; GCC_PREFIX_HEADER = "$(SRCROOT)/macOS/Prefix.pch"; - GCC_PREPROCESSOR_DEFINITIONS = "$(inherited)"; INFOPLIST_FILE = "$(SRCROOT)/macOS/Info.plist"; LIBRARY_SEARCH_PATHS = "\"$(SRCROOT)/../../../MoltenVK/macOS/static\""; MACOSX_DEPLOYMENT_TARGET = 10.11; @@ -463,7 +435,6 @@ "DEBUG=1", _DEBUG, GLM_FORCE_RADIANS, - MVK_USE_MOLTENVK_SHADER_CONVERTER, ); GCC_SYMBOLS_PRIVATE_EXTERN = NO; GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO; @@ -471,7 +442,6 @@ HEADER_SEARCH_PATHS = ( "\"$(SRCROOT)/../../../MoltenVK/include\"", "\"$(SRCROOT)/../VulkanSamples/API-Samples/utils\"", - "\"$(SRCROOT)/../../../MoltenVKShaderConverter/include\"", ); ONLY_ACTIVE_ARCH = YES; OTHER_LDFLAGS = "-ObjC"; @@ -490,17 +460,13 @@ ENABLE_BITCODE = NO; GCC_C_LANGUAGE_STANDARD = c99; GCC_PRECOMPILE_PREFIX_HEADER = YES; - GCC_PREPROCESSOR_DEFINITIONS = ( - GLM_FORCE_RADIANS, - MVK_USE_MOLTENVK_SHADER_CONVERTER, - ); + GCC_PREPROCESSOR_DEFINITIONS = GLM_FORCE_RADIANS; GCC_SYMBOLS_PRIVATE_EXTERN = NO; GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO; GCC_WARN_ABOUT_RETURN_TYPE = YES; HEADER_SEARCH_PATHS = ( "\"$(SRCROOT)/../../../MoltenVK/include\"", "\"$(SRCROOT)/../VulkanSamples/API-Samples/utils\"", - "\"$(SRCROOT)/../../../MoltenVKShaderConverter/include\"", ); OTHER_LDFLAGS = "-ObjC"; PRODUCT_BUNDLE_IDENTIFIER = "com.moltenvk.${PRODUCT_NAME:identifier}"; diff --git a/Demos/README.md b/Demos/README.md index 6f1e8206..e689634b 100644 --- a/Demos/README.md +++ b/Demos/README.md @@ -109,12 +109,6 @@ The demo allows some customization, by modifying the arguments passed to the dem To customize, modify the arguments created in the `DemoViewController viewDidLoad` method found in the `iOS/DemoViewController.mm` or `macOS/DemoViewController.mm` file. -This demo illustrates the use of the **MoltenVK** API `vkGetMoltenVKDeviceConfigurationMVK()` -and `vkSetMoltenVKDeviceConfigurationMVK()` functions to enable **MoltenVK** debugging, including -logging the conversion of shaders from *SPIR-V* to *Metal Shading Language*. See the use of these -functions in the `Hologram/Hologram.cpp` file. To see the effect, modify the `Hologram-iOS` or -`Hologram-macOS` *Scheme* from within *Xcode* to use the **Debug** *Build Configuration* setting. - The `Hologram` demo is a simple example of installing **MoltenVK** as a *static library*. diff --git a/Docs/MoltenVK_Runtime_UserGuide.md b/Docs/MoltenVK_Runtime_UserGuide.md index 24274e21..8310e03a 100644 --- a/Docs/MoltenVK_Runtime_UserGuide.md +++ b/Docs/MoltenVK_Runtime_UserGuide.md @@ -260,6 +260,7 @@ In addition to the core *Vulkan* API, **MoltenVK** also supports the following - `VK_AMD_gpu_shader_half_float` - `VK_AMD_negative_viewport_height` - `VK_IMG_format_pvrtc` (iOS) +- `VK_NV_glsl_shader` In order to visibly display your content on *iOS* or *macOS*, you must enable the `VK_MVK_ios_surface` or `VK_MVK_macos_surface` extension, respectively, and use the functions defined for that extension diff --git a/Docs/Whats_New.md b/Docs/Whats_New.md index b510ad0f..9bc03edd 100644 --- a/Docs/Whats_New.md +++ b/Docs/Whats_New.md @@ -19,6 +19,7 @@ MoltenVK 1.0.35 Released TBD - Support the `VK_EXT_debug_report` extension. +- Support the `VK_NV_glsl_shader` extension. - Change log indication of error in logs from `[***MoltenVK ERROR***]` to `[mvk-error]`, for consistency with other log level indications. - Tessellation fixes: diff --git a/ExternalRevisions/VulkanSamples_repo_revision b/ExternalRevisions/VulkanSamples_repo_revision index 2ea88219..8c62934b 100644 --- a/ExternalRevisions/VulkanSamples_repo_revision +++ b/ExternalRevisions/VulkanSamples_repo_revision @@ -1 +1 @@ -07b1ccd82ff6b7e6369a0d8d6a5e5e4f7ba0b7d6 +37e808988e758ec4f6f689012fb425bab1398ecf diff --git a/MoltenVK/MoltenVK.xcodeproj/project.pbxproj b/MoltenVK/MoltenVK.xcodeproj/project.pbxproj index b41d81b1..74f1b38d 100644 --- a/MoltenVK/MoltenVK.xcodeproj/project.pbxproj +++ b/MoltenVK/MoltenVK.xcodeproj/project.pbxproj @@ -222,6 +222,20 @@ /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ + A96B8156227BF6FD008A772B /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = A9C86CB61C55B8350096CAF2 /* MoltenVKShaderConverter.xcodeproj */; + proxyType = 1; + remoteGlobalIDString = A937472B1A9A8B2900F29B34; + remoteInfo = "MoltenVKGLSLToSPIRVConverter-iOS"; + }; + A96B8158227BF715008A772B /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = A9C86CB61C55B8350096CAF2 /* MoltenVKShaderConverter.xcodeproj */; + proxyType = 1; + remoteGlobalIDString = A93747701A9A98D000F29B34; + remoteInfo = "MoltenVKGLSLToSPIRVConverter-macOS"; + }; A981497B1FB6B566005F00B4 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = A9C86CB61C55B8350096CAF2 /* MoltenVKShaderConverter.xcodeproj */; @@ -763,6 +777,7 @@ ); dependencies = ( A981499B1FB6B9CF005F00B4 /* PBXTargetDependency */, + A96B8157227BF6FD008A772B /* PBXTargetDependency */, ); name = "MoltenVK-iOS"; productName = MoltenVK; @@ -782,6 +797,7 @@ ); dependencies = ( A98149A41FB6B9EB005F00B4 /* PBXTargetDependency */, + A96B8159227BF715008A772B /* PBXTargetDependency */, ); name = "MoltenVK-macOS"; productName = MoltenVK; @@ -1048,6 +1064,16 @@ /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ + A96B8157227BF6FD008A772B /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = "MoltenVKGLSLToSPIRVConverter-iOS"; + targetProxy = A96B8156227BF6FD008A772B /* PBXContainerItemProxy */; + }; + A96B8159227BF715008A772B /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = "MoltenVKGLSLToSPIRVConverter-macOS"; + targetProxy = A96B8158227BF715008A772B /* PBXContainerItemProxy */; + }; A981499B1FB6B9CF005F00B4 /* PBXTargetDependency */ = { isa = PBXTargetDependency; name = "MVKSPIRVToMSLConverter-iOS"; @@ -1157,7 +1183,7 @@ MACH_O_TYPE = staticlib; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; - PRELINK_LIBS = "${CONFIGURATION_BUILD_DIR}/libMoltenVKSPIRVToMSLConverter.a"; + PRELINK_LIBS = "${CONFIGURATION_BUILD_DIR}/libMoltenVKSPIRVToMSLConverter.a ${CONFIGURATION_BUILD_DIR}/libMoltenVKGLSLToSPIRVConverter.a"; PRODUCT_NAME = MoltenVK; SKIP_INSTALL = YES; }; @@ -1214,7 +1240,7 @@ ); MACH_O_TYPE = staticlib; MTL_ENABLE_DEBUG_INFO = NO; - PRELINK_LIBS = "${CONFIGURATION_BUILD_DIR}/libMoltenVKSPIRVToMSLConverter.a"; + PRELINK_LIBS = "${CONFIGURATION_BUILD_DIR}/libMoltenVKSPIRVToMSLConverter.a ${CONFIGURATION_BUILD_DIR}/libMoltenVKGLSLToSPIRVConverter.a"; PRODUCT_NAME = MoltenVK; SKIP_INSTALL = YES; VALIDATE_PRODUCT = YES; diff --git a/MoltenVK/MoltenVK/API/vk_mvk_moltenvk.h b/MoltenVK/MoltenVK/API/vk_mvk_moltenvk.h index 381fd4eb..d695a7ae 100644 --- a/MoltenVK/MoltenVK/API/vk_mvk_moltenvk.h +++ b/MoltenVK/MoltenVK/API/vk_mvk_moltenvk.h @@ -566,6 +566,7 @@ typedef struct { MVKPerformanceTracker functionRetrieval; /** Retrieve a MTLFunction from a MTLLibrary. */ MVKPerformanceTracker functionSpecialization; /** Specialize a retrieved MTLFunction. */ MVKPerformanceTracker pipelineCompile; /** Compile MTLFunctions into a pipeline. */ + MVKPerformanceTracker glslToSPRIV; /** Convert GLSL to SPIR-V code. */ } MVKShaderCompilationPerformance; diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm b/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm index 6f307b16..90e71760 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm @@ -703,7 +703,7 @@ bool MVKGraphicsPipeline::addVertexShaderToPipeline(MTLRenderPipelineDescriptor* addVertexInputToShaderConverterContext(shaderContext, pCreateInfo); id mtlFunction = ((MVKShaderModule*)_pVertexSS->module)->getMTLFunction(&shaderContext, _pVertexSS->pSpecializationInfo, _pipelineCache).mtlFunction; if ( !mtlFunction ) { - setConfigurationResult(reportError(VK_ERROR_INITIALIZATION_FAILED, "Vertex shader function could not be compiled into pipeline. See previous logged error.")); + setConfigurationResult(reportError(VK_ERROR_INVALID_SHADER_NV, "Vertex shader function could not be compiled into pipeline. See previous logged error.")); return false; } plDesc.vertexFunction = mtlFunction; @@ -712,16 +712,16 @@ bool MVKGraphicsPipeline::addVertexShaderToPipeline(MTLRenderPipelineDescriptor* _needsVertexOutputBuffer = shaderContext.options.needsOutputBuffer; // If we need the auxiliary buffer and there's no place to put it, we're in serious trouble. if (_needsVertexAuxBuffer && _auxBufferIndex.stages[kMVKShaderStageVertex] >= _device->_pMetalFeatures->maxPerStageBufferCount - vbCnt) { - setConfigurationResult(reportError(VK_ERROR_INITIALIZATION_FAILED, "Vertex shader requires auxiliary buffer, but there is no free slot to pass it.")); + setConfigurationResult(reportError(VK_ERROR_INVALID_SHADER_NV, "Vertex shader requires auxiliary buffer, but there is no free slot to pass it.")); return false; } // Ditto captured output buffer. if (_needsVertexOutputBuffer && _outputBufferIndex.stages[kMVKShaderStageVertex] >= _device->_pMetalFeatures->maxPerStageBufferCount - vbCnt) { - setConfigurationResult(reportError(VK_ERROR_INITIALIZATION_FAILED, "Vertex shader requires output buffer, but there is no free slot to pass it.")); + setConfigurationResult(reportError(VK_ERROR_INVALID_SHADER_NV, "Vertex shader requires output buffer, but there is no free slot to pass it.")); return false; } if (_needsVertexOutputBuffer && _indirectParamsIndex.stages[kMVKShaderStageVertex] >= _device->_pMetalFeatures->maxPerStageBufferCount - vbCnt) { - setConfigurationResult(reportError(VK_ERROR_INITIALIZATION_FAILED, "Vertex shader requires indirect parameters buffer, but there is no free slot to pass it.")); + setConfigurationResult(reportError(VK_ERROR_INVALID_SHADER_NV, "Vertex shader requires indirect parameters buffer, but there is no free slot to pass it.")); return false; } return true; @@ -739,7 +739,7 @@ bool MVKGraphicsPipeline::addTessCtlShaderToPipeline(MTLComputePipelineDescripto addPrevStageOutputToShaderConverterContext(shaderContext, vtxOutputs); id mtlFunction = ((MVKShaderModule*)_pTessCtlSS->module)->getMTLFunction(&shaderContext, _pTessCtlSS->pSpecializationInfo, _pipelineCache).mtlFunction; if ( !mtlFunction ) { - setConfigurationResult(reportError(VK_ERROR_INITIALIZATION_FAILED, "Tessellation control shader function could not be compiled into pipeline. See previous logged error.")); + setConfigurationResult(reportError(VK_ERROR_INVALID_SHADER_NV, "Tessellation control shader function could not be compiled into pipeline. See previous logged error.")); return false; } plDesc.computeFunction = mtlFunction; @@ -748,23 +748,23 @@ bool MVKGraphicsPipeline::addTessCtlShaderToPipeline(MTLComputePipelineDescripto _needsTessCtlPatchOutputBuffer = shaderContext.options.needsPatchOutputBuffer; _needsTessCtlInput = shaderContext.options.needsInputThreadgroupMem; if (_needsTessCtlAuxBuffer && _auxBufferIndex.stages[kMVKShaderStageTessCtl] >= _device->_pMetalFeatures->maxPerStageBufferCount - kMVKTessCtlNumReservedBuffers) { - setConfigurationResult(reportError(VK_ERROR_INITIALIZATION_FAILED, "Tessellation control shader requires auxiliary buffer, but there is no free slot to pass it.")); + setConfigurationResult(reportError(VK_ERROR_INVALID_SHADER_NV, "Tessellation control shader requires auxiliary buffer, but there is no free slot to pass it.")); return false; } if (_indirectParamsIndex.stages[kMVKShaderStageTessCtl] >= _device->_pMetalFeatures->maxPerStageBufferCount - kMVKTessCtlNumReservedBuffers) { - setConfigurationResult(reportError(VK_ERROR_INITIALIZATION_FAILED, "Tessellation control shader requires indirect parameters buffer, but there is no free slot to pass it.")); + setConfigurationResult(reportError(VK_ERROR_INVALID_SHADER_NV, "Tessellation control shader requires indirect parameters buffer, but there is no free slot to pass it.")); return false; } if (_needsTessCtlOutputBuffer && _outputBufferIndex.stages[kMVKShaderStageTessCtl] >= _device->_pMetalFeatures->maxPerStageBufferCount - kMVKTessCtlNumReservedBuffers) { - setConfigurationResult(reportError(VK_ERROR_INITIALIZATION_FAILED, "Tessellation control shader requires per-vertex output buffer, but there is no free slot to pass it.")); + setConfigurationResult(reportError(VK_ERROR_INVALID_SHADER_NV, "Tessellation control shader requires per-vertex output buffer, but there is no free slot to pass it.")); return false; } if (_needsTessCtlPatchOutputBuffer && _tessCtlPatchOutputBufferIndex >= _device->_pMetalFeatures->maxPerStageBufferCount - kMVKTessCtlNumReservedBuffers) { - setConfigurationResult(reportError(VK_ERROR_INITIALIZATION_FAILED, "Tessellation control shader requires per-patch output buffer, but there is no free slot to pass it.")); + setConfigurationResult(reportError(VK_ERROR_INVALID_SHADER_NV, "Tessellation control shader requires per-patch output buffer, but there is no free slot to pass it.")); return false; } if (_tessCtlLevelBufferIndex >= _device->_pMetalFeatures->maxPerStageBufferCount - kMVKTessCtlNumReservedBuffers) { - setConfigurationResult(reportError(VK_ERROR_INITIALIZATION_FAILED, "Tessellation control shader requires tessellation level output buffer, but there is no free slot to pass it.")); + setConfigurationResult(reportError(VK_ERROR_INVALID_SHADER_NV, "Tessellation control shader requires tessellation level output buffer, but there is no free slot to pass it.")); return false; } return true; @@ -779,7 +779,7 @@ bool MVKGraphicsPipeline::addTessEvalShaderToPipeline(MTLRenderPipelineDescripto addPrevStageOutputToShaderConverterContext(shaderContext, tcOutputs); id mtlFunction = ((MVKShaderModule*)_pTessEvalSS->module)->getMTLFunction(&shaderContext, _pTessEvalSS->pSpecializationInfo, _pipelineCache).mtlFunction; if ( !mtlFunction ) { - setConfigurationResult(reportError(VK_ERROR_INITIALIZATION_FAILED, "Tessellation evaluation shader function could not be compiled into pipeline. See previous logged error.")); + setConfigurationResult(reportError(VK_ERROR_INVALID_SHADER_NV, "Tessellation evaluation shader function could not be compiled into pipeline. See previous logged error.")); return false; } // Yeah, you read that right. Tess. eval functions are a kind of vertex function in Metal. @@ -788,7 +788,7 @@ bool MVKGraphicsPipeline::addTessEvalShaderToPipeline(MTLRenderPipelineDescripto _needsTessEvalAuxBuffer = shaderContext.options.needsAuxBuffer; // If we need the auxiliary buffer and there's no place to put it, we're in serious trouble. if (_needsTessEvalAuxBuffer && _auxBufferIndex.stages[kMVKShaderStageTessEval] >= _device->_pMetalFeatures->maxPerStageBufferCount - kMVKTessEvalNumReservedBuffers) { - setConfigurationResult(reportError(VK_ERROR_INITIALIZATION_FAILED, "Tessellation evaluation shader requires auxiliary buffer, but there is no free slot to pass it.")); + setConfigurationResult(reportError(VK_ERROR_INVALID_SHADER_NV, "Tessellation evaluation shader requires auxiliary buffer, but there is no free slot to pass it.")); return false; } return true; @@ -802,13 +802,13 @@ bool MVKGraphicsPipeline::addFragmentShaderToPipeline(MTLRenderPipelineDescripto shaderContext.options.shouldCaptureOutput = false; id mtlFunction = ((MVKShaderModule*)_pFragmentSS->module)->getMTLFunction(&shaderContext, _pFragmentSS->pSpecializationInfo, _pipelineCache).mtlFunction; if ( !mtlFunction ) { - setConfigurationResult(reportError(VK_ERROR_INITIALIZATION_FAILED, "Fragment shader function could not be compiled into pipeline. See previous logged error.")); + setConfigurationResult(reportError(VK_ERROR_INVALID_SHADER_NV, "Fragment shader function could not be compiled into pipeline. See previous logged error.")); return false; } plDesc.fragmentFunction = mtlFunction; _needsFragmentAuxBuffer = shaderContext.options.needsAuxBuffer; if (_needsFragmentAuxBuffer && _auxBufferIndex.stages[kMVKShaderStageFragment] >= _device->_pMetalFeatures->maxPerStageBufferCount) { - setConfigurationResult(reportError(VK_ERROR_INITIALIZATION_FAILED, "Fragment shader requires auxiliary buffer, but there is no free slot to pass it.")); + setConfigurationResult(reportError(VK_ERROR_INVALID_SHADER_NV, "Fragment shader requires auxiliary buffer, but there is no free slot to pass it.")); return false; } } @@ -1170,11 +1170,11 @@ MVKComputePipeline::MVKComputePipeline(MVKDevice* device, _mtlPipelineState = plc->newMTLComputePipelineState(shaderFunc.mtlFunction); // retained plc->destroy(); } else { - setConfigurationResult(reportError(VK_ERROR_INITIALIZATION_FAILED, "Compute shader function could not be compiled into pipeline. See previous logged error.")); + setConfigurationResult(reportError(VK_ERROR_INVALID_SHADER_NV, "Compute shader function could not be compiled into pipeline. See previous logged error.")); } if (_needsAuxBuffer && _auxBufferIndex.stages[kMVKShaderStageCompute] > _device->_pMetalFeatures->maxPerStageBufferCount) { - setConfigurationResult(reportError(VK_ERROR_INITIALIZATION_FAILED, "Compute shader requires auxiliary buffer, but there is no free slot to pass it.")); + setConfigurationResult(reportError(VK_ERROR_INVALID_SHADER_NV, "Compute shader requires auxiliary buffer, but there is no free slot to pass it.")); } } diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKShaderModule.h b/MoltenVK/MoltenVK/GPUObjects/MVKShaderModule.h index 4a0ff70f..573cf306 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKShaderModule.h +++ b/MoltenVK/MoltenVK/GPUObjects/MVKShaderModule.h @@ -21,6 +21,7 @@ #include "MVKDevice.h" #include "MVKSync.h" #include +#include #include #include @@ -167,22 +168,22 @@ public: bool convert(SPIRVToMSLConverterContext* pContext); /** Returns the original SPIR-V code that was specified when this object was created. */ - inline const std::vector& getSPIRV() { return _converter.getSPIRV(); } + const std::vector& getSPIRV() { return _spvConverter.getSPIRV(); } /** * Returns the Metal Shading Language source code as converted by the most recent * call to convert() function, or set directly using the setMSL() function. */ - inline const std::string& getMSL() { return _converter.getMSL(); } + const std::string& getMSL() { return _spvConverter.getMSL(); } /** * Returns information about the shader entry point as converted by the most recent * call to convert() function, or set directly using the setMSL() function. */ - inline const SPIRVEntryPoint& getEntryPoint() { return _converter.getEntryPoint(); } + const SPIRVEntryPoint& getEntryPoint() { return _spvConverter.getEntryPoint(); } /** Returns a key as a means of identifying this shader module in a pipeline cache. */ - inline MVKShaderModuleKey getKey() { return _key; } + MVKShaderModuleKey getKey() { return _key; } MVKShaderModule(MVKDevice* device, const VkShaderModuleCreateInfo* pCreateInfo); @@ -191,8 +192,11 @@ public: protected: friend MVKShaderCacheIterator; + MVKGLSLConversionShaderStage getMVKGLSLConversionShaderStage(SPIRVToMSLConverterContext* pContext); + MVKShaderLibraryCache _shaderLibraryCache; - SPIRVToMSLConverter _converter; + SPIRVToMSLConverter _spvConverter; + GLSLToSPIRVConverter _glslConverter; MVKShaderLibrary* _defaultLibrary; MVKShaderModuleKey _key; std::mutex _accessLock; diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKShaderModule.mm b/MoltenVK/MoltenVK/GPUObjects/MVKShaderModule.mm index 199c0bac..6c30480e 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKShaderModule.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKShaderModule.mm @@ -92,7 +92,7 @@ MVKMTLFunction MVKShaderLibrary::getMTLFunction(const VkSpecializationInfo* pSpe } } } else { - reportError(VK_ERROR_INITIALIZATION_FAILED, "Shader module does not contain an entry point named '%s'.", mtlFuncName.UTF8String); + reportError(VK_ERROR_INVALID_SHADER_NV, "Shader module does not contain an entry point named '%s'.", mtlFuncName.UTF8String); } return { mtlFunc, MTLSizeMake(getWorkgroupDimensionSize(_entryPoint.workgroupSize.width, pSpecializationInfo), @@ -150,7 +150,7 @@ void MVKShaderLibrary::handleCompilationError(NSError* err, const char* opDesc) if (_mtlLibrary) { MVKLogInfo("%s succeeded with warnings (Error code %li):\n%s", opDesc, (long)err.code, err.localizedDescription.UTF8String); } else { - _owner->setConfigurationResult(reportError(VK_ERROR_INITIALIZATION_FAILED, + _owner->setConfigurationResult(reportError(VK_ERROR_INVALID_SHADER_NV, "%s failed (Error code %li):\n%s", opDesc, (long)err.code, err.localizedDescription.UTF8String)); @@ -244,19 +244,53 @@ MVKMTLFunction MVKShaderModule::getMTLFunction(SPIRVToMSLConverterContext* pCont bool MVKShaderModule::convert(SPIRVToMSLConverterContext* pContext) { bool shouldLogCode = _device->_pMVKConfig->debugMode; + bool shouldLogEstimatedGLSL = shouldLogCode; + + // If the SPIR-V converter does not have any code, but the GLSL converter does, + // convert the GLSL code to SPIR-V and set it into the SPIR-V conveter. + if ( !_spvConverter.hasSPIRV() && _glslConverter.hasGLSL() ) { + + uint64_t startTime = _device->getPerformanceTimestamp(); + bool wasConverted = _glslConverter.convert(getMVKGLSLConversionShaderStage(pContext), shouldLogCode, false); + _device->addActivityPerformance(_device->_performanceStatistics.shaderCompilation.glslToSPRIV, startTime); + + if (wasConverted) { + if (shouldLogCode) { MVKLogInfo("%s", _glslConverter.getResultLog().c_str()); } + _spvConverter.setSPIRV(_glslConverter.getSPIRV()); + } else { + reportError(VK_ERROR_INVALID_SHADER_NV, "Unable to convert GLSL to SPIR-V:\n%s", _glslConverter.getResultLog().c_str()); + } + shouldLogEstimatedGLSL = false; + } uint64_t startTime = _device->getPerformanceTimestamp(); - bool wasConverted = _converter.convert(*pContext, shouldLogCode, shouldLogCode, shouldLogCode); + bool wasConverted = _spvConverter.convert(*pContext, shouldLogCode, shouldLogCode, shouldLogEstimatedGLSL); _device->addActivityPerformance(_device->_performanceStatistics.shaderCompilation.spirvToMSL, startTime); if (wasConverted) { - if (shouldLogCode) { MVKLogInfo("%s", _converter.getResultLog().data()); } + if (shouldLogCode) { MVKLogInfo("%s", _spvConverter.getResultLog().c_str()); } } else { - reportError(VK_ERROR_FORMAT_NOT_SUPPORTED, "Unable to convert SPIR-V to MSL:\n%s", _converter.getResultLog().data()); + reportError(VK_ERROR_INVALID_SHADER_NV, "Unable to convert SPIR-V to MSL:\n%s", _spvConverter.getResultLog().c_str()); } return wasConverted; } +// Returns the MVKGLSLConversionShaderStage corresponding to the shader stage in the SPIR-V converter context. +MVKGLSLConversionShaderStage MVKShaderModule::getMVKGLSLConversionShaderStage(SPIRVToMSLConverterContext* pContext) { + switch (pContext->options.entryPointStage) { + case spv::ExecutionModelVertex: return kMVKGLSLConversionShaderStageVertex; + case spv::ExecutionModelTessellationControl: return kMVKGLSLConversionShaderStageTessControl; + case spv::ExecutionModelTessellationEvaluation: return kMVKGLSLConversionShaderStageTessEval; + case spv::ExecutionModelGeometry: return kMVKGLSLConversionShaderStageGeometry; + case spv::ExecutionModelFragment: return kMVKGLSLConversionShaderStageFragment; + case spv::ExecutionModelGLCompute: return kMVKGLSLConversionShaderStageCompute; + case spv::ExecutionModelKernel: return kMVKGLSLConversionShaderStageCompute; + + default: + MVKAssert(false, "Bad shader stage provided for GLSL to SPIR-V conversion."); + return kMVKGLSLConversionShaderStageAuto; + } +} #pragma mark Construction @@ -270,7 +304,7 @@ MVKShaderModule::MVKShaderModule(MVKDevice* device, // Ensure something is there. if ( (pCreateInfo->pCode == VK_NULL_HANDLE) || (codeSize < 4) ) { - setConfigurationResult(reportError(VK_INCOMPLETE, "Shader module contains no SPIR-V code.")); + setConfigurationResult(reportError(VK_ERROR_INVALID_SHADER_NV, "vkCreateShaderModule(): Shader module contains no shader code.")); return; } @@ -279,36 +313,36 @@ MVKShaderModule::MVKShaderModule(MVKDevice* device, // Retrieve the magic number to determine what type of shader code has been loaded. uint32_t magicNum = *pCreateInfo->pCode; switch (magicNum) { - case kMVKMagicNumberSPIRVCode: { // SPIR-V code - size_t spvCount = (pCreateInfo->codeSize + 3) >> 2; // Round up if byte length not exactly on uint32_t boundary + case kMVKMagicNumberSPIRVCode: { // SPIR-V code + size_t spvCount = (codeSize + 3) >> 2; // Round up if byte length not exactly on uint32_t boundary uint64_t startTime = _device->getPerformanceTimestamp(); codeHash = mvkHash(pCreateInfo->pCode, spvCount); _device->addActivityPerformance(_device->_performanceStatistics.shaderCompilation.hashShaderCode, startTime); - _converter.setSPIRV(pCreateInfo->pCode, spvCount); + _spvConverter.setSPIRV(pCreateInfo->pCode, spvCount); break; } - case kMVKMagicNumberMSLSourceCode: { // MSL source code + case kMVKMagicNumberMSLSourceCode: { // MSL source code size_t hdrSize = sizeof(MVKMSLSPIRVHeader); char* pMSLCode = (char*)(uintptr_t(pCreateInfo->pCode) + hdrSize); - size_t mslCodeLen = pCreateInfo->codeSize - hdrSize; + size_t mslCodeLen = codeSize - hdrSize; uint64_t startTime = _device->getPerformanceTimestamp(); codeHash = mvkHash(&magicNum); codeHash = mvkHash(pMSLCode, mslCodeLen, codeHash); _device->addActivityPerformance(_device->_performanceStatistics.shaderCompilation.hashShaderCode, startTime); - _converter.setMSL(pMSLCode, nullptr); - _defaultLibrary = new MVKShaderLibrary(this, _converter.getMSL().c_str(), _converter.getEntryPoint()); + _spvConverter.setMSL(pMSLCode, nullptr); + _defaultLibrary = new MVKShaderLibrary(this, _spvConverter.getMSL().c_str(), _spvConverter.getEntryPoint()); break; } - case kMVKMagicNumberMSLCompiledCode: { // MSL compiled binary code + case kMVKMagicNumberMSLCompiledCode: { // MSL compiled binary code size_t hdrSize = sizeof(MVKMSLSPIRVHeader); char* pMSLCode = (char*)(uintptr_t(pCreateInfo->pCode) + hdrSize); - size_t mslCodeLen = pCreateInfo->codeSize - hdrSize; + size_t mslCodeLen = codeSize - hdrSize; uint64_t startTime = _device->getPerformanceTimestamp(); codeHash = mvkHash(&magicNum); @@ -319,8 +353,19 @@ MVKShaderModule::MVKShaderModule(MVKDevice* device, break; } - default: - setConfigurationResult(reportError(VK_ERROR_FORMAT_NOT_SUPPORTED, "SPIR-V contains invalid magic number %x.", magicNum)); + default: // Could be GLSL source code + if (_device->_enabledExtensions.vk_NV_glsl_shader.enabled) { + const char* pGLSL = (char*)pCreateInfo->pCode; + size_t glslLen = codeSize - 1; + + uint64_t startTime = _device->getPerformanceTimestamp(); + codeHash = mvkHash(pGLSL, codeSize); + _device->addActivityPerformance(_device->_performanceStatistics.shaderCompilation.hashShaderCode, startTime); + + _glslConverter.setGLSL(pGLSL, glslLen); + } else { + setConfigurationResult(reportError(VK_ERROR_INVALID_SHADER_NV, "vkCreateShaderModule(): The SPIR-V contains an invalid magic number %x.", magicNum)); + } break; } diff --git a/MoltenVK/MoltenVK/Layers/MVKExtensions.def b/MoltenVK/MoltenVK/Layers/MVKExtensions.def index 764db988..7c5fd145 100644 --- a/MoltenVK/MoltenVK/Layers/MVKExtensions.def +++ b/MoltenVK/MoltenVK/Layers/MVKExtensions.def @@ -63,7 +63,8 @@ MVK_EXTENSION(MVK_macos_surface, MVK_MACOS_SURFACE) MVK_EXTENSION(MVK_moltenvk, MVK_MOLTENVK) MVK_EXTENSION(AMD_gpu_shader_half_float, AMD_GPU_SHADER_HALF_FLOAT) MVK_EXTENSION(AMD_negative_viewport_height, AMD_NEGATIVE_VIEWPORT_HEIGHT) -MVK_EXTENSION_LAST(IMG_format_pvrtc, IMG_FORMAT_PVRTC) +MVK_EXTENSION(IMG_format_pvrtc, IMG_FORMAT_PVRTC) +MVK_EXTENSION_LAST(NV_glsl_shader, NV_GLSL_SHADER) #undef MVK_EXTENSION #undef MVK_EXTENSION_LAST diff --git a/MoltenVKShaderConverter/MoltenVKGLSLToSPIRVConverter/GLSLConversion.h b/MoltenVKShaderConverter/MoltenVKGLSLToSPIRVConverter/GLSLConversion.h index 0ad5c67a..fe12106b 100644 --- a/MoltenVKShaderConverter/MoltenVKGLSLToSPIRVConverter/GLSLConversion.h +++ b/MoltenVKShaderConverter/MoltenVKGLSLToSPIRVConverter/GLSLConversion.h @@ -32,14 +32,14 @@ extern "C" { /** Enumeration of the pipeline stages for which a shader can be compiled. */ typedef enum { - kMVKShaderStageAuto, - kMVKShaderStageVertex, - kMVKShaderStageTessControl, - kMVKShaderStageTessEval, - kMVKShaderStageGeometry, - kMVKShaderStageFragment, - kMVKShaderStageCompute, -} MVKShaderStage; + kMVKGLSLConversionShaderStageAuto, + kMVKGLSLConversionShaderStageVertex, + kMVKGLSLConversionShaderStageTessControl, + kMVKGLSLConversionShaderStageTessEval, + kMVKGLSLConversionShaderStageGeometry, + kMVKGLSLConversionShaderStageFragment, + kMVKGLSLConversionShaderStageCompute, +} MVKGLSLConversionShaderStage; /** @@ -63,7 +63,7 @@ typedef enum { * should be logged to the converter results log. This can be useful during shader debugging. */ bool mvkConvertGLSLToSPIRV(const char* glslSource, - MVKShaderStage shaderStage, + MVKGLSLConversionShaderStage shaderStage, uint32_t** pSPIRVCode, size_t *pSPIRVLength, char** pResultLog, @@ -90,7 +90,7 @@ bool mvkConvertGLSLToSPIRV(const char* glslSource, * should be logged to the converter results log. This can be useful during shader debugging. */ bool mvkConvertGLSLFileToSPIRV(const char* glslFilepath, - MVKShaderStage shaderStage, + MVKGLSLConversionShaderStage shaderStage, uint32_t** pSPIRVCode, size_t *pSPIRVLength, char** pResultLog, diff --git a/MoltenVKShaderConverter/MoltenVKGLSLToSPIRVConverter/GLSLConversion.mm b/MoltenVKShaderConverter/MoltenVKGLSLToSPIRVConverter/GLSLConversion.mm index 8cfb49b7..909abf8b 100644 --- a/MoltenVKShaderConverter/MoltenVKGLSLToSPIRVConverter/GLSLConversion.mm +++ b/MoltenVKShaderConverter/MoltenVKGLSLToSPIRVConverter/GLSLConversion.mm @@ -26,7 +26,7 @@ using namespace mvk; MVK_PUBLIC_SYMBOL bool mvkConvertGLSLToSPIRV(const char* glslSource, - MVKShaderStage shaderStage, + MVKGLSLConversionShaderStage shaderStage, uint32_t** pSPIRVCode, size_t *pSPIRVLength, char** pResultLog, @@ -59,7 +59,7 @@ MVK_PUBLIC_SYMBOL bool mvkConvertGLSLToSPIRV(const char* glslSource, } MVK_PUBLIC_SYMBOL bool mvkConvertGLSLFileToSPIRV(const char* glslFilepath, - MVKShaderStage shaderStage, + MVKGLSLConversionShaderStage shaderStage, uint32_t** pSPIRVCode, size_t *pSPIRVLength, char** pResultLog, diff --git a/MoltenVKShaderConverter/MoltenVKGLSLToSPIRVConverter/GLSLToSPIRVConverter.cpp b/MoltenVKShaderConverter/MoltenVKGLSLToSPIRVConverter/GLSLToSPIRVConverter.cpp index b9b45d57..8f19dda3 100644 --- a/MoltenVKShaderConverter/MoltenVKGLSLToSPIRVConverter/GLSLToSPIRVConverter.cpp +++ b/MoltenVKShaderConverter/MoltenVKGLSLToSPIRVConverter/GLSLToSPIRVConverter.cpp @@ -37,13 +37,9 @@ using namespace mvk; void configureGLSLCompilerResources(TBuiltInResource* glslCompilerResources); /** Returns the GLSL compiler language type corresponding to the specified MoltenVK shader stage. */ -EShLanguage eshLanguageFromMVKShaderStage(const MVKShaderStage mvkShaderStage); +EShLanguage eshLanguageFromMVKGLSLConversionShaderStage(const MVKGLSLConversionShaderStage mvkShaderStage); -MVK_PUBLIC_SYMBOL void GLSLToSPIRVConverter::setGLSL(const string& glslSrc) { _glsl = glslSrc; } - -MVK_PUBLIC_SYMBOL const string& GLSLToSPIRVConverter::getGLSL() { return _glsl; } - -MVK_PUBLIC_SYMBOL bool GLSLToSPIRVConverter::convert(MVKShaderStage shaderStage, +MVK_PUBLIC_SYMBOL bool GLSLToSPIRVConverter::convert(MVKGLSLConversionShaderStage shaderStage, bool shouldLogGLSL, bool shouldLogSPIRV) { _wasConverted = true; @@ -54,7 +50,7 @@ MVK_PUBLIC_SYMBOL bool GLSLToSPIRVConverter::convert(MVKShaderStage shaderStage, EShMessages messages = (EShMessages)(EShMsgDefault | EShMsgSpvRules | EShMsgVulkanRules); - EShLanguage stage = eshLanguageFromMVKShaderStage(shaderStage); + EShLanguage stage = eshLanguageFromMVKGLSLConversionShaderStage(shaderStage); TBuiltInResource glslCompilerResources; configureGLSLCompilerResources(&glslCompilerResources); const char *glslStrings[1]; @@ -91,12 +87,6 @@ MVK_PUBLIC_SYMBOL bool GLSLToSPIRVConverter::convert(MVKShaderStage shaderStage, return _wasConverted; } -MVK_PUBLIC_SYMBOL const vector& GLSLToSPIRVConverter::getSPIRV() { return _spirv; } - -MVK_PUBLIC_SYMBOL bool GLSLToSPIRVConverter::getWasConverted() { return _wasConverted; } - -MVK_PUBLIC_SYMBOL const string& GLSLToSPIRVConverter::getResultLog() { return _resultLog; } - /** Appends the message text to the result log. */ void GLSLToSPIRVConverter::logMsg(const char* logMsg) { string trimMsg = trim(logMsg); @@ -240,15 +230,15 @@ void configureGLSLCompilerResources(TBuiltInResource* glslCompilerResources) { glslCompilerResources->limits.generalConstantMatrixVectorIndexing = 1; } -EShLanguage eshLanguageFromMVKShaderStage(const MVKShaderStage mvkShaderStage) { +EShLanguage eshLanguageFromMVKGLSLConversionShaderStage(const MVKGLSLConversionShaderStage mvkShaderStage) { switch (mvkShaderStage) { - case kMVKShaderStageVertex: return EShLangVertex; - case kMVKShaderStageTessControl: return EShLangTessControl; - case kMVKShaderStageTessEval: return EShLangTessEvaluation; - case kMVKShaderStageGeometry: return EShLangGeometry; - case kMVKShaderStageFragment: return EShLangFragment; - case kMVKShaderStageCompute: return EShLangCompute; - default: return EShLangVertex; + case kMVKGLSLConversionShaderStageVertex: return EShLangVertex; + case kMVKGLSLConversionShaderStageTessControl: return EShLangTessControl; + case kMVKGLSLConversionShaderStageTessEval: return EShLangTessEvaluation; + case kMVKGLSLConversionShaderStageGeometry: return EShLangGeometry; + case kMVKGLSLConversionShaderStageFragment: return EShLangFragment; + case kMVKGLSLConversionShaderStageCompute: return EShLangCompute; + default: return EShLangVertex; } } diff --git a/MoltenVKShaderConverter/MoltenVKGLSLToSPIRVConverter/GLSLToSPIRVConverter.h b/MoltenVKShaderConverter/MoltenVKGLSLToSPIRVConverter/GLSLToSPIRVConverter.h index 48f2ef1f..2bc433fb 100644 --- a/MoltenVKShaderConverter/MoltenVKGLSLToSPIRVConverter/GLSLToSPIRVConverter.h +++ b/MoltenVKShaderConverter/MoltenVKGLSLToSPIRVConverter/GLSLToSPIRVConverter.h @@ -35,11 +35,20 @@ namespace mvk { public: - /** Sets the GLSL source code that is to be converted to the specified null-terminated string. */ - void setGLSL(const std::string& glslSrc); + /** Sets the GLSL source code that is to be converted to the specified string. */ + void setGLSL(const std::string& glslSrc) { _glsl = glslSrc; } + + /** + * Sets the GLSL source code that is to be converted from the first length characters + * of the buffer, and ensuring the resulting string is null-terminated. + */ + void setGLSL(const char* glslSrc, size_t length) { _glsl.assign(glslSrc, length); } /** Returns the GLSL source code that was set using the setGLSL() function. */ - const std::string& getGLSL(); + const std::string& getGLSL() { return _glsl; } + + /** Returns whether the SPIR-V code has been set. */ + bool hasGLSL() { return !_glsl.empty(); } /** * Converts GLSL code, set with setGLSL(), to SPIR-V code, which can be retrieved using getSPIRV(). @@ -47,23 +56,23 @@ namespace mvk { * The boolean flags indicate whether the original GLSL code and resulting SPIR-V code should * be logged to the result log of this converter. This can be useful during shader debugging. */ - bool convert(MVKShaderStage shaderStage, bool shouldLogGLSL, bool shouldLogSPIRV); - - /** Returns the SPIRV code most recently converted by the convert() function. */ - const std::vector& getSPIRV(); + bool convert(MVKGLSLConversionShaderStage shaderStage, bool shouldLogGLSL, bool shouldLogSPIRV); /** * Returns whether the most recent conversion was successful. * * The initial value of this property is NO. It is set to YES upon successful conversion. */ - bool getWasConverted(); + bool wasConverted() { return _wasConverted; } + + /** Returns the SPIRV code most recently converted by the convert() function. */ + const std::vector& getSPIRV() { return _spirv; } /** * Returns a human-readable log of the most recent conversion activity. * This may be empty if the conversion was successful. */ - const std::string& getResultLog(); + const std::string& getResultLog() { return _resultLog; } protected: void logMsg(const char* logMsg); diff --git a/MoltenVKShaderConverter/MoltenVKSPIRVToMSLConverter/SPIRVToMSLConverter.cpp b/MoltenVKShaderConverter/MoltenVKSPIRVToMSLConverter/SPIRVToMSLConverter.cpp index a593c252..4caa021e 100644 --- a/MoltenVKShaderConverter/MoltenVKSPIRVToMSLConverter/SPIRVToMSLConverter.cpp +++ b/MoltenVKShaderConverter/MoltenVKSPIRVToMSLConverter/SPIRVToMSLConverter.cpp @@ -197,8 +197,6 @@ SPIRV_CROSS_NAMESPACE::CompilerMSL::Options::Platform getCompilerMSLPlatform(SPI // Populates the entry point with info extracted from the SPRI-V compiler. void populateEntryPoint(SPIRVEntryPoint& entryPoint, SPIRV_CROSS_NAMESPACE::Compiler* pCompiler, SPIRVToMSLConverterOptions& options); -MVK_PUBLIC_SYMBOL void SPIRVToMSLConverter::setSPIRV(const vector& spirv) { _spirv = spirv; } - MVK_PUBLIC_SYMBOL void SPIRVToMSLConverter::setSPIRV(const uint32_t* spirvCode, size_t length) { _spirv.clear(); // Clear for reuse _spirv.reserve(length); @@ -207,8 +205,6 @@ MVK_PUBLIC_SYMBOL void SPIRVToMSLConverter::setSPIRV(const uint32_t* spirvCode, } } -MVK_PUBLIC_SYMBOL const vector& SPIRVToMSLConverter::getSPIRV() { return _spirv; } - MVK_PUBLIC_SYMBOL bool SPIRVToMSLConverter::convert(SPIRVToMSLConverterContext& context, bool shouldLogSPIRV, bool shouldLogMSL, diff --git a/MoltenVKShaderConverter/MoltenVKSPIRVToMSLConverter/SPIRVToMSLConverter.h b/MoltenVKShaderConverter/MoltenVKSPIRVToMSLConverter/SPIRVToMSLConverter.h index 83e93396..feac98a4 100644 --- a/MoltenVKShaderConverter/MoltenVKSPIRVToMSLConverter/SPIRVToMSLConverter.h +++ b/MoltenVKShaderConverter/MoltenVKSPIRVToMSLConverter/SPIRVToMSLConverter.h @@ -225,7 +225,7 @@ namespace mvk { public: /** Sets the SPIRV code. */ - void setSPIRV(const std::vector& spirv); + void setSPIRV(const std::vector& spirv) { _spirv = spirv; } /** * Sets the SPIRV code from the specified array of values. @@ -234,7 +234,10 @@ namespace mvk { void setSPIRV(const uint32_t* spirvCode, size_t length); /** Returns a reference to the SPIRV code, set by one of the setSPIRV() functions. */ - const std::vector& getSPIRV(); + const std::vector& getSPIRV() { return _spirv; } + + /** Returns whether the SPIR-V code has been set. */ + bool hasSPIRV() { return !_spirv.empty(); } /** * Converts SPIR-V code, set using setSPIRV() to MSL code, which can be retrieved using getMSL(). @@ -248,6 +251,13 @@ namespace mvk { bool shouldLogMSL = false, bool shouldLogGLSL = false); + /** + * Returns whether the most recent conversion was successful. + * + * The initial value of this property is NO. It is set to YES upon successful conversion. + */ + bool wasConverted() { return _wasConverted; } + /** * Returns the Metal Shading Language source code most recently converted * by the convert() function, or set directly using the setMSL() function. @@ -257,13 +267,6 @@ namespace mvk { /** Returns information about the shader entry point. */ const SPIRVEntryPoint& getEntryPoint() { return _entryPoint; } - /** - * Returns whether the most recent conversion was successful. - * - * The initial value of this property is NO. It is set to YES upon successful conversion. - */ - bool getWasConverted() { return _wasConverted; } - /** * Returns a human-readable log of the most recent conversion activity. * This may be empty if the conversion was successful. diff --git a/MoltenVKShaderConverter/MoltenVKShaderConverterTool/MoltenVKShaderConverterTool.cpp b/MoltenVKShaderConverter/MoltenVKShaderConverterTool/MoltenVKShaderConverterTool.cpp index a193e814..cf441bc3 100644 --- a/MoltenVKShaderConverter/MoltenVKShaderConverterTool/MoltenVKShaderConverterTool.cpp +++ b/MoltenVKShaderConverter/MoltenVKShaderConverterTool/MoltenVKShaderConverterTool.cpp @@ -84,7 +84,7 @@ bool MoltenVKShaderConverterTool::processFile(string filePath) { string pathExtn = pathExtension(absPath); if (_shouldReadGLSL && isGLSLFileExtension(pathExtn)) { - return convertGLSL(absPath, emptyPath, emptyPath, kMVKShaderStageAuto); + return convertGLSL(absPath, emptyPath, emptyPath, kMVKGLSLConversionShaderStageAuto); } else if (_shouldReadSPIRV && isSPIRVFileExtension(pathExtn)) { return convertSPIRV(absPath, emptyPath); } @@ -97,7 +97,7 @@ bool MoltenVKShaderConverterTool::processFile(string filePath) { bool MoltenVKShaderConverterTool::convertGLSL(string& glslInFile, string& spvOutFile, string& mslOutFile, - MVKShaderStage shaderStage) { + MVKGLSLConversionShaderStage shaderStage) { string path; vector fileContents; string glslCode; @@ -120,11 +120,11 @@ bool MoltenVKShaderConverterTool::convertGLSL(string& glslInFile, } glslCode.append(fileContents.begin(), fileContents.end()); - if (shaderStage == kMVKShaderStageAuto) { + if (shaderStage == kMVKGLSLConversionShaderStageAuto) { string pathExtn = pathExtension(glslInFile); shaderStage = shaderStageFromFileExtension(pathExtn); } - if (shaderStage == kMVKShaderStageAuto) { + if (shaderStage == kMVKGLSLConversionShaderStageAuto) { errMsg = "Could not determine shader type from GLSL file: " + absolutePath(path); log(errMsg.data()); return false; @@ -254,11 +254,11 @@ bool MoltenVKShaderConverterTool::convertSPIRV(const vector& spv, } } -MVKShaderStage MoltenVKShaderConverterTool::shaderStageFromFileExtension(string& pathExtension) { - for (auto& fx : _glslVtxFileExtns) { if (fx == pathExtension) { return kMVKShaderStageVertex; } } - for (auto& fx : _glslFragFileExtns) { if (fx == pathExtension) { return kMVKShaderStageFragment; } } - for (auto& fx : _glslCompFileExtns) { if (fx == pathExtension) { return kMVKShaderStageCompute; } } - return kMVKShaderStageAuto; +MVKGLSLConversionShaderStage MoltenVKShaderConverterTool::shaderStageFromFileExtension(string& pathExtension) { + for (auto& fx : _glslVtxFileExtns) { if (fx == pathExtension) { return kMVKGLSLConversionShaderStageVertex; } } + for (auto& fx : _glslFragFileExtns) { if (fx == pathExtension) { return kMVKGLSLConversionShaderStageFragment; } } + for (auto& fx : _glslCompFileExtns) { if (fx == pathExtension) { return kMVKGLSLConversionShaderStageCompute; } } + return kMVKGLSLConversionShaderStageAuto; } bool MoltenVKShaderConverterTool::isGLSLFileExtension(string& pathExtension) { @@ -372,7 +372,7 @@ MoltenVKShaderConverterTool::MoltenVKShaderConverterTool(int argc, const char* a extractTokens(_defaultCompShaderExtns, _glslCompFileExtns); extractTokens(_defaultSPIRVShaderExtns, _spvFileExtns); _origPathExtnSep = "_"; - _shaderStage = kMVKShaderStageAuto; + _shaderStage = kMVKGLSLConversionShaderStageAuto; _shouldUseDirectoryRecursion = false; _shouldReadGLSL = false; _shouldReadSPIRV = false; @@ -482,13 +482,13 @@ bool MoltenVKShaderConverterTool::parseArgs(int argc, const char* argv[]) { switch (shdrTypeStr.front()) { case 'v': - _shaderStage = kMVKShaderStageVertex; + _shaderStage = kMVKGLSLConversionShaderStageVertex; break; case 'f': - _shaderStage = kMVKShaderStageFragment; + _shaderStage = kMVKGLSLConversionShaderStageFragment; break; case 'c': - _shaderStage = kMVKShaderStageCompute; + _shaderStage = kMVKGLSLConversionShaderStageCompute; break; default: return false; diff --git a/MoltenVKShaderConverter/MoltenVKShaderConverterTool/MoltenVKShaderConverterTool.h b/MoltenVKShaderConverter/MoltenVKShaderConverterTool/MoltenVKShaderConverterTool.h index 18504337..b4baa617 100644 --- a/MoltenVKShaderConverter/MoltenVKShaderConverterTool/MoltenVKShaderConverterTool.h +++ b/MoltenVKShaderConverter/MoltenVKShaderConverterTool/MoltenVKShaderConverterTool.h @@ -64,13 +64,13 @@ namespace mvk { MoltenVKShaderConverterTool(int argc, const char* argv[]); protected: - MVKShaderStage shaderStageFromFileExtension(std::string& pathExtension); + MVKGLSLConversionShaderStage shaderStageFromFileExtension(std::string& pathExtension); bool isGLSLFileExtension(std::string& pathExtension); bool isSPIRVFileExtension(std::string& pathExtension); bool convertGLSL(std::string& glslInFile, std::string& spvOutFile, std::string& mslOutFile, - MVKShaderStage shaderStage); + MVKGLSLConversionShaderStage shaderStage); bool convertSPIRV(std::string& spvInFile, std::string& mslOutFile); bool convertSPIRV(const std::vector& spv, @@ -100,7 +100,7 @@ namespace mvk { std::vector _glslFragFileExtns; std::vector _glslCompFileExtns; std::vector _spvFileExtns; - MVKShaderStage _shaderStage; + MVKGLSLConversionShaderStage _shaderStage; MVKPerformanceTracker _glslConversionPerformance; MVKPerformanceTracker _spvConversionPerformance; uint32_t _mslVersionMajor;