Add support for caching converted MSL shader code offline from pipeline cache

via vkGetPipelineCacheData(), vkCreatePipelineCache() & vkMergePipelineCaches().

Add the cereal serialization framework as a dependency.
Update documentation. Update project settings to Xcode 9.3.
This commit is contained in:
Bill Hollings 2018-03-30 12:13:50 -04:00
parent c45b47183e
commit 20c98e5e46
35 changed files with 535 additions and 128 deletions

1
.gitignore vendored
View File

@ -21,6 +21,7 @@ External/SPIRV-Tools
External/SPIRV-Headers
External/SPIRV-Cross
External/VulkanSamples
External/cereal
# Other source repository archive directories (protects when importing)
.hg

View File

@ -20,6 +20,7 @@
#define __MVKStrings_h_ 1
#include <string>
#include <streambuf>
namespace mvk {
@ -44,6 +45,26 @@ namespace mvk {
return ( (startPos != std::string::npos) && (endPos != std::string::npos) ) ? s.substr(startPos, endPos + 1) : "";
}
/** A memory-based stream buffer. */
class membuf : public std::streambuf {
public:
membuf(char* p, size_t n) {
setg(p, p, p + n);
setp(p, p + n);
}
};
/** A character counting stream buffer. */
class countbuf : public std::streambuf {
public:
size_t buffSize = 0;
private:
std::streamsize xsputn (const char* /* s */, std::streamsize n) override {
buffSize += n;
return n;
}
};
}
#endif

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>

View File

@ -623,7 +623,7 @@
29B97313FDCFA39411CA2CEA /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 0920;
LastUpgradeCheck = 0930;
TargetAttributes = {
A977BCBD1B66BB010067E5BF = {
DevelopmentTeam = VU3TCKU48B;

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0920"
LastUpgradeVersion = "0930"
version = "2.0">
<BuildAction
parallelizeBuildables = "YES"
@ -26,7 +26,6 @@
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
language = ""
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
@ -46,7 +45,6 @@
buildConfiguration = "Release"
selectedDebuggerIdentifier = ""
selectedLauncherIdentifier = "Xcode.IDEFoundation.Launcher.PosixSpawn"
language = ""
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0920"
LastUpgradeVersion = "0930"
version = "2.0">
<BuildAction
parallelizeBuildables = "YES"
@ -26,7 +26,6 @@
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
language = ""
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
@ -46,7 +45,6 @@
buildConfiguration = "Release"
selectedDebuggerIdentifier = ""
selectedLauncherIdentifier = "Xcode.IDEFoundation.Launcher.PosixSpawn"
language = ""
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"

View File

@ -266,7 +266,7 @@
29B97313FDCFA39411CA2CEA /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 0920;
LastUpgradeCheck = 0930;
TargetAttributes = {
A9B53B0F1C3AC0BE00ABC6F6 = {
DevelopmentTeam = VU3TCKU48B;

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0920"
LastUpgradeVersion = "0930"
version = "2.0">
<BuildAction
parallelizeBuildables = "YES"
@ -26,7 +26,6 @@
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
language = ""
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
@ -46,7 +45,6 @@
buildConfiguration = "Release"
selectedDebuggerIdentifier = ""
selectedLauncherIdentifier = "Xcode.IDEFoundation.Launcher.PosixSpawn"
language = ""
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0920"
LastUpgradeVersion = "0930"
version = "2.0">
<BuildAction
parallelizeBuildables = "YES"
@ -26,7 +26,6 @@
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
language = ""
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
@ -46,7 +45,6 @@
buildConfiguration = "Release"
selectedDebuggerIdentifier = ""
selectedLauncherIdentifier = "Xcode.IDEFoundation.Launcher.PosixSpawn"
language = ""
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"

View File

@ -355,7 +355,7 @@
29B97313FDCFA39411CA2CEA /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 0920;
LastUpgradeCheck = 0930;
TargetAttributes = {
A977BCBD1B66BB010067E5BF = {
DevelopmentTeam = VU3TCKU48B;

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0920"
LastUpgradeVersion = "0930"
version = "2.0">
<BuildAction
parallelizeBuildables = "YES"
@ -26,7 +26,6 @@
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
language = ""
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
@ -46,7 +45,6 @@
buildConfiguration = "Release"
selectedDebuggerIdentifier = ""
selectedLauncherIdentifier = "Xcode.IDEFoundation.Launcher.PosixSpawn"
language = ""
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0920"
LastUpgradeVersion = "0930"
version = "2.0">
<BuildAction
parallelizeBuildables = "YES"
@ -26,7 +26,6 @@
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
language = ""
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
@ -46,7 +45,6 @@
buildConfiguration = "Release"
selectedDebuggerIdentifier = ""
selectedLauncherIdentifier = "Xcode.IDEFoundation.Launcher.PosixSpawn"
language = ""
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"

View File

@ -388,11 +388,33 @@ This section discusses various options for improving performance when using **Mo
<a name="shader_load_time"></a>
### Shader Loading Time
*Metal* supports pre-compiled shaders, which can improve shader loading and set-up performance,
allowing you to reduce your scene loading time. See the [*Metal Shading Language* Shaders](#shaders)
and [MoltenVKShaderConverter Shader Converter Tool](#shader_converter_tool) sections above for
more information about how to use the `MoltenVKShaderConverter` tool to create and load pre-compiled
*Metal* shaders into **MoltenVK**.
A number of steps is require to load and compile *SPIR-V* shaders into a form that *Metal* can use.
Although the overall process is fast, the slowest step involves converting shaders from *SPIR-V* to
*MSL* source code format.
If you have a lot of shaders, you can dramatically improve shader loading time by using the standard
*Vulkan pipeline cache* feature, to serialize shaders and store them in *MSL* form offline.
Loading *MSL* shaders via the pipeline cache serializing mechanism can be significantly faster than
converting from *SPIR-V* to *MSL* each time.
In *Vulkan*, pipeline cache serialization for offline storage is available through the
`vkGetPipelineCacheData()` and `vkCreatePipelineCache()` functions. Loading the pipeline cache
from offline storage at app start-up time can dramatically improve both shader loading performance,
and performance glitches and hiccups during runtime code if shader loading is performed then.
When using pipeline caching, nothing changes about how you load *SPIR-V* shader code. **MoltenVK**
automatically detects that the *SPIR-V* was previously converted to *MSL*, and stored offline via
the *Vulkan* pipeline cache serialization mechanism, and does not invoke the relatively expensive
step of converting the *SPIR-V* to *MSL* again.
As a second shader loading performance option, *Metal* also supports pre-compiled shaders, which
can improve shader loading and set-up performance, allowing you to reduce your scene loading time.
See the [*Metal Shading Language* Shaders](#shaders) and
[MoltenVKShaderConverter Shader Converter Tool](#shader_converter_tool) sections above for more
information about how to use the `MoltenVKShaderConverter` tool to create and load pre-compiled
*Metal* shaders into **MoltenVK**. This behaviour is not standard *Vulkan* behaviour, and does not
improve performance significantly. Your first choice should be to use offline storage of pipeline
cache contents as described in the previous paragraphs.
<a name="xcode_config"></a>

39
External/README.md vendored
View File

@ -20,6 +20,7 @@ Table of Contents
- [Adding the *SPIRV-Cross* Library to the *MoltenVKShaderConverter Xcode* Project](#add_spirv-cross)
- [Adding the *SPIRV-Tools* Library to the *MoltenVKShaderConverter Xcode* Project](#add_spirv-tools)
- [Adding the *glslang* Library to the *MoltenVKShaderConverter Xcode* Project](#add_glslang)
- [Adding the *cereal* Library to the *MoltenVK Xcode* Project](#add_cereal)
@ -35,6 +36,7 @@ Fetching External Libraries
- [*SPIRV-Tools*](https://github.com/KhronosGroup/SPIRV-Tools)
- [*SPIRV-Headers*](https://github.com/KhronosGroup/SPIRV-Headers)
- [*VulkanSamples*](https://github.com/brenwill/VulkanSamples)
- [*cereal*](https://github.com/USCiLab/cereal)
These external open-source libraries are maintained in the `External` directory.
To retrieve these libraries from their sources, run the `fetchDependencies`
@ -75,9 +77,12 @@ determined as follows:
- **_SPIRV-Headers_**: automatically retrieved by the *glslang* repository.
You can update which version of the *SPIRV-Cross*, *VulkanSamples*, and
*Vulkan-LoaderAndValidationLayers* libraries are retrieved, by changing the
value held in the corresponding `*_repo_revision` file listed above.
- **_cereal_**: a GitHub repository commit identifier found in the
`External/cereal_repo_revision` file.
You can update which versions of the *SPIRV-Cross*, *VulkanSamples*,
*Vulkan-LoaderAndValidationLayers*, or *cereal* libraries are retrieved,
by changing the value held in the corresponding `*_repo_revision` file listed above.
The version of the *glslang*, *SPIRV-Tools*, and *SPIRV-Headers* libraries is
automatically determined by the version of the *Vulkan-LoaderAndValidationLayers*
@ -97,7 +102,7 @@ Adding the *SPIRV-Cross* Library to the *MoltenVKShaderConverter Xcode* Project
The `MoltenVKShaderConverter` *Xcode* project is already configured to use the *SPIRV-Cross*
library. However, after updating the version of *SPIRV-Cross*, as described [above](#updating),
if you encounter any linking errors, may need to re-add the *SPIRV-Cross* library to the
if you encounter any building errors, you may need to re-add the *SPIRV-Cross* library to the
`MoltenVKShaderConverter` *Xcode* project as follows:
1. In the *Project Navigator*, remove all of the files under the *Group* named
@ -158,7 +163,7 @@ Adding the *SPIRV-Tools* Library to the *MoltenVKShaderConverter Xcode* Project
The `MoltenVKShaderConverter` *Xcode* project is already configured to use the *SPIRV-Tools*
library. However, after updating the version of *SPIRV-Tools*, as described [above](#updating),
if you encounter any linking errors, may need to re-add the *SPIRV-Tools* library to the
if you encounter any building errors, you may need to re-add the *SPIRV-Tools* library to the
`MoltenVKShaderConverter` *Xcode* project as follows:
1. In the *Project Navigator*, remove the *Group* named `source` from under the *Group* named
@ -169,15 +174,17 @@ if you encounter any linking errors, may need to re-add the *SPIRV-Tools* librar
_**Create groups**_ option, add the files to *both* the `MoltenVKSPIRVToMSLConverter-iOS`
and `MoltenVKSPIRVToMSLConverter-macOS` targets, and click the ***Finish*** button.
3. In the *Project Navigator* panel, select your application's target, and open the
*Build Settings* tab. Locate the build setting entry **Header Search Paths**
(`HEADER_SEARCH_PATHS`) and add the following paths:
3. In the *Project Navigator* panel, select the `MoltenVKShaderConverter` *Xcode* project, then select the
`MoltenVKSPIRVToMSLConverter-macOS` target, and open the *Build Settings* tab. Locate the build setting
entry **Header Search Paths** (`HEADER_SEARCH_PATHS`) and add the following paths:
"$(SRCROOT)/../External/glslang/External/spirv-tools/include"
"$(SRCROOT)/../External/glslang/External/spirv-tools/source"
"$(SRCROOT)/../External/glslang/External/spirv-tools/external/spirv-headers/include"
"$(SRCROOT)/../External/glslang/build/External/spirv-tools"
4. Repeat *Step 3* for the `MoltenVKSPIRVToMSLConverter-iOS` target within the `MoltenVKShaderConverter` *Xcode* project
5. ***(Optional)*** To simplify the paths used within *Xcode* to reference the added files,
perform the following steps:
@ -196,7 +203,7 @@ Adding the *glslang* Library to the *MoltenVKShaderConverter Xcode* Project
The `MoltenVKShaderConverter` *Xcode* project is already configured to use the *glslang*
library. However, after updating the version of *glslang*, as described [above](#updating),
if you encounter any linking errors, may need to re-add the *glslang* library to the
if you encounter any building errors, you may need to re-add the *glslang* library to the
`MoltenVKShaderConverter` *Xcode* project as follows:
1. In the *Project Navigator*, remove all *Groups* from under the *Group* named
@ -229,3 +236,17 @@ if you encounter any linking errors, may need to re-add the *glslang* library to
`glslang`, `OGLCompilersDLL`, and `SPIRV` directories added above.
<a name="add_cereal"></a>
Adding the *cereal* Library to the *MoltenVK Xcode* Project
-----------------------------------------------------------
The `MoltenVK` *Xcode* project is already configured to use the *cereal* library. However, after
updating the version of *cereal*, as described [above](#updating), if you encounter any building
errors, you may need to re-add the *cereal* library to the `MoltenVK` *Xcode* project as follows:
1. In the *Project Navigator* panel, select the `MoltenVK` *Xcode* project, then the `MoltenVK`
project target, and open the *Build Settings* tab. Locate the build setting entry
**Header Search Paths** (`HEADER_SEARCH_PATHS`) and add the following paths:
"$(SRCROOT)/../External/cereal/include"

1
External/cereal_repo_revision vendored Normal file
View File

@ -0,0 +1 @@
51cbda5f30e56c801c07fe3d3aba5d7fb9e6cca4

View File

@ -48,6 +48,16 @@ echo
V_LVL_NAME=Vulkan-LoaderAndValidationLayers
GLSLANG_NAME=glslang
# ----------------- Cereal -------------------
REPO_NAME=cereal
REPO_URL="https://github.com/USCiLab/${REPO_NAME}.git"
REPO_REV=$(cat "./${REPO_NAME}_repo_revision")
clone_repo ${REPO_NAME} ${REPO_URL} ${REPO_REV}
# ----------------- SPIRV-Cross -------------------
REPO_NAME=SPIRV-Cross

View File

@ -679,7 +679,7 @@
A9F55D25198BE6A7004EC31B /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 0920;
LastUpgradeCheck = 0930;
ORGANIZATIONNAME = "The Brenwill Workshop Ltd.";
TargetAttributes = {
A9B8EE091A98D796009C5A02 = {
@ -969,6 +969,7 @@
HEADER_SEARCH_PATHS = (
"\"$(SRCROOT)/include\"",
"\"$(SRCROOT)/../MoltenVKShaderConverter\"",
"\"$(SRCROOT)/../External/cereal/include\"",
);
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
MACH_O_TYPE = staticlib;
@ -1026,6 +1027,7 @@
HEADER_SEARCH_PATHS = (
"\"$(SRCROOT)/include\"",
"\"$(SRCROOT)/../MoltenVKShaderConverter\"",
"\"$(SRCROOT)/../External/cereal/include\"",
);
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
MACH_O_TYPE = staticlib;

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0920"
LastUpgradeVersion = "0930"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
@ -26,7 +26,6 @@
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
language = ""
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
@ -37,7 +36,6 @@
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
language = ""
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0920"
LastUpgradeVersion = "0930"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
@ -26,7 +26,6 @@
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
language = ""
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
@ -37,7 +36,6 @@
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
language = ""
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"

View File

@ -113,6 +113,9 @@ typedef struct {
MVKShaderCompilationEventPerformance functionRetrieval; /** Retrieve a MTLFunction from a MTLLibrary. */
MVKShaderCompilationEventPerformance functionSpecialization; /** Specialize a retrieved MTLFunction. */
MVKShaderCompilationEventPerformance pipelineCompile; /** Compile MTLFunctions into a pipeline. */
MVKShaderCompilationEventPerformance sizePipelineCache; /** Calculate the size of cache data required to write MSL to pipeline cache data stream. */
MVKShaderCompilationEventPerformance writePipelineCache; /** Write MSL to pipeline cache data stream. */
MVKShaderCompilationEventPerformance readPipelineCache; /** Read MSL from pipeline cache data stream. */
} MVKShaderCompilationPerformance;

View File

@ -1328,7 +1328,7 @@ void MVKDevice::addShaderCompilationEventPerformanceImpl(MVKShaderCompilationEve
double totalInterval = (shaderCompilationEvent.averageDuration * shaderCompilationEvent.count++) + currInterval;
shaderCompilationEvent.averageDuration = totalInterval / shaderCompilationEvent.count;
MVKLogDebug("%s performance curr: %.3f ms, avg: %.3f ms, min: %.3f ms, max: %.3f ms, count: %d",
MVKLogDebug("Shader building performance to %s curr: %.3f ms, avg: %.3f ms, min: %.3f ms, max: %.3f ms, count: %d",
getShaderCompilationEventName(shaderCompilationEvent),
currInterval,
shaderCompilationEvent.averageDuration,
@ -1338,14 +1338,17 @@ void MVKDevice::addShaderCompilationEventPerformanceImpl(MVKShaderCompilationEve
}
const char* MVKDevice::getShaderCompilationEventName(MVKShaderCompilationEventPerformance& shaderCompilationEvent) {
if (&shaderCompilationEvent == &_shaderCompilationPerformance.hashShaderCode) { return "Hash shader code"; }
if (&shaderCompilationEvent == &_shaderCompilationPerformance.spirvToMSL) { return "Convert SPIR-V to MSL source code"; }
if (&shaderCompilationEvent == &_shaderCompilationPerformance.mslCompile) { return "Compile MSL source code into a MTLLibrary"; }
if (&shaderCompilationEvent == &_shaderCompilationPerformance.mslLoad) { return "Load pre-compiled MSL code into a MTLLibrary"; }
if (&shaderCompilationEvent == &_shaderCompilationPerformance.shaderLibraryFromCache) { return "Retrieve shader library from the cache."; }
if (&shaderCompilationEvent == &_shaderCompilationPerformance.functionRetrieval) { return "Retrieve a MTLFunction from a MTLLibrary"; }
if (&shaderCompilationEvent == &_shaderCompilationPerformance.functionSpecialization) { return "Specialize a retrieved MTLFunction"; }
if (&shaderCompilationEvent == &_shaderCompilationPerformance.pipelineCompile) { return "Compile MTLFunctions into a pipeline"; }
if (&shaderCompilationEvent == &_shaderCompilationPerformance.hashShaderCode) { return "hash shader code"; }
if (&shaderCompilationEvent == &_shaderCompilationPerformance.spirvToMSL) { return "convert SPIR-V to MSL source code"; }
if (&shaderCompilationEvent == &_shaderCompilationPerformance.mslCompile) { return "compile MSL source code into a MTLLibrary"; }
if (&shaderCompilationEvent == &_shaderCompilationPerformance.mslLoad) { return "load pre-compiled MSL code into a MTLLibrary"; }
if (&shaderCompilationEvent == &_shaderCompilationPerformance.shaderLibraryFromCache) { return "retrieve shader library from the cache."; }
if (&shaderCompilationEvent == &_shaderCompilationPerformance.functionRetrieval) { return "retrieve a MTLFunction from a MTLLibrary"; }
if (&shaderCompilationEvent == &_shaderCompilationPerformance.functionSpecialization) { return "specialize a retrieved MTLFunction"; }
if (&shaderCompilationEvent == &_shaderCompilationPerformance.pipelineCompile) { return "compile MTLFunctions into a pipeline"; }
if (&shaderCompilationEvent == &_shaderCompilationPerformance.sizePipelineCache) { return "calculate cache size required to write MSL to pipeline cache"; }
if (&shaderCompilationEvent == &_shaderCompilationPerformance.writePipelineCache) { return "write MSL to pipeline cache"; }
if (&shaderCompilationEvent == &_shaderCompilationPerformance.readPipelineCache) { return "read MSL from pipeline cache"; }
return "Unknown shader compile event";
}
@ -1406,6 +1409,8 @@ uint32_t MVKDevice::expandVisibilityResultMTLBuffer(uint32_t queryCount) {
MVKDevice::MVKDevice(MVKPhysicalDevice* physicalDevice, const VkDeviceCreateInfo* pCreateInfo) : _mvkConfig() {
// MVKLogDebug("Creating MVKDevice. Elapsed time: %.6f ms.", mvkGetElapsedMilliseconds());
initPerformanceTracking();
_physicalDevice = physicalDevice;
_pFeatures = &_physicalDevice->_features;
_pMetalFeatures = &_physicalDevice->_metalFeatures;
@ -1454,8 +1459,6 @@ MVKDevice::MVKDevice(MVKPhysicalDevice* physicalDevice, const VkDeviceCreateInfo
}
}
initPerformanceTracking();
MVKLogInfo("Created VkDevice to run on GPU %s", _pProperties->deviceName);
}
@ -1474,6 +1477,9 @@ void MVKDevice::initPerformanceTracking() {
_shaderCompilationPerformance.functionRetrieval = initPerf;
_shaderCompilationPerformance.functionSpecialization = initPerf;
_shaderCompilationPerformance.pipelineCompile = initPerf;
_shaderCompilationPerformance.sizePipelineCache = initPerf;
_shaderCompilationPerformance.writePipelineCache = initPerf;
_shaderCompilationPerformance.readPipelineCache = initPerf;
}
MVKDevice::~MVKDevice() {

View File

@ -24,6 +24,7 @@
#include <MoltenVKSPIRVToMSLConverter/SPIRVToMSLConverter.h>
#include <unordered_set>
#include <vector>
#include <ostream>
#import <Metal/Metal.h>
@ -164,30 +165,32 @@ class MVKPipelineCache : public MVKBaseDeviceObject {
public:
/**
* If pData is not null, serializes at most pDataSize bytes of the contents of the cache
* into that memory location, and returns the number of bytes serialized in pDataSize.
* If pData is null, returns the number of bytes required to serialize the contents of
* If pData is not null, serializes at most pDataSize bytes of the contents of the cache into that
* memory location, and returns the number of bytes serialized in pDataSize. If pData is null,
* returns the number of bytes required to serialize the contents of this pipeline cache.
*/
inline VkResult getData(size_t* pDataSize, void* pData) {
*pDataSize = 0;
return VK_SUCCESS;
}
VkResult writeData(size_t* pDataSize, void* pData);
/** Return a shader library from the specified shader context sourced from the specified shader module. */
MVKShaderLibrary* getShaderLibrary(SPIRVToMSLConverterContext* pContext, MVKShaderModule* shaderModule);
/** Merges the contents of the specified number of pipeline caches into this cache. */
inline VkResult mergePipelineCaches(uint32_t srcCacheCount, const VkPipelineCache* pSrcCaches) { return VK_SUCCESS; }
VkResult mergePipelineCaches(uint32_t srcCacheCount, const VkPipelineCache* pSrcCaches);
#pragma mark Construction
/** Constructs an instance for the specified device. */
MVKPipelineCache(MVKDevice* device, const VkPipelineCacheCreateInfo* pCreateInfo) : MVKBaseDeviceObject(device) {}
MVKPipelineCache(MVKDevice* device, const VkPipelineCacheCreateInfo* pCreateInfo);
~MVKPipelineCache() override;
protected:
std::unordered_map<std::size_t, MVKShaderLibraryCache*> _shaderCacheByModuleHash;
std::mutex _shaderCacheLock;
MVKShaderLibraryCache* getShaderLibraryCache(MVKShaderModuleKey smKey);
void readData(const VkPipelineCacheCreateInfo* pCreateInfo);
void writeData(std::ostream& outstream, bool isCounting = false);
void markDirty();
std::unordered_map<MVKShaderModuleKey, MVKShaderLibraryCache*> _shaderCache;
size_t _dataSize = 0;
std::mutex _shaderCacheLock;
};

View File

@ -17,11 +17,18 @@
*/
#include "MVKPipeline.h"
#include <MoltenVKSPIRVToMSLConverter/SPIRVToMSLConverter.h>
#include "MVKRenderPass.h"
#include "MVKCommandBuffer.h"
#include "MVKFoundation.h"
#include "MVKOSExtensions.h"
#include "MVKStrings.h"
#include "mvk_datatypes.h"
#include <cereal/archives/binary.hpp>
#include <cereal/types/string.hpp>
#include <cereal/types/vector.hpp>
using namespace std;
@ -453,20 +460,288 @@ MVKComputePipeline::~MVKComputePipeline() {
MVKShaderLibrary* MVKPipelineCache::getShaderLibrary(SPIRVToMSLConverterContext* pContext, MVKShaderModule* shaderModule) {
lock_guard<mutex> lock(_shaderCacheLock);
size_t smKey = shaderModule->getKey();
MVKShaderLibraryCache* slCache = _shaderCacheByModuleHash[smKey];
bool wasAdded = false;
MVKShaderLibraryCache* slCache = getShaderLibraryCache(shaderModule->getKey());
MVKShaderLibrary* shLib = slCache->getShaderLibrary(pContext, shaderModule, &wasAdded);
if (wasAdded) { markDirty(); }
return shLib;
}
// Returns a shader library cache for the specified shader module key, creating it if necessary.
MVKShaderLibraryCache* MVKPipelineCache::getShaderLibraryCache(MVKShaderModuleKey smKey) {
MVKShaderLibraryCache* slCache = _shaderCache[smKey];
if ( !slCache ) {
slCache = new MVKShaderLibraryCache(_device);
_shaderCacheByModuleHash[smKey] = slCache;
_shaderCache[smKey] = slCache;
}
return slCache;
}
return slCache->getShaderLibrary(pContext, shaderModule);
#pragma mark Streaming pipeline cache to and from offline memory
static uint32_t kDataHeaderSize = (sizeof(uint32_t) * 4) + VK_UUID_SIZE;
// Entry type markers to be inserted into data stream
typedef enum {
MVKPipelineCacheEntryTypeEOF = 0,
MVKPipelineCacheEntryTypeShaderLibrary = 1,
} MVKPipelineCacheEntryType;
// Ceral archive definitions
namespace mvk {
template<class Archive>
void serialize(Archive & archive, SPIRVEntryPoint& ep) {
archive(ep.mtlFunctionName,
ep.workgroupSize.width,
ep.workgroupSize.height,
ep.workgroupSize.depth,
ep.workgroupSizeId.width,
ep.workgroupSizeId.height,
ep.workgroupSizeId.depth,
ep.workgroupSizeId.constant);
}
template<class Archive>
void serialize(Archive & archive, SPIRVToMSLConverterOptions& opt) {
archive(opt.entryPointName,
opt.entryPointStage,
opt.mslVersion,
opt.shouldFlipVertexY,
opt.isRenderingPoints);
}
template<class Archive>
void serialize(Archive & archive, MSLVertexAttribute& va) {
archive(va.location,
va.mslBuffer,
va.mslOffset,
va.mslStride,
va.isPerInstance,
va.isUsedByShader);
}
template<class Archive>
void serialize(Archive & archive, MSLResourceBinding& rb) {
archive(rb.stage,
rb.descriptorSet,
rb.binding,
rb.mslBuffer,
rb.mslTexture,
rb.mslSampler,
rb.isUsedByShader);
}
template<class Archive>
void serialize(Archive & archive, SPIRVToMSLConverterContext& ctx) {
archive(ctx.options, ctx.vertexAttributes, ctx.resourceBindings);
}
}
template<class Archive>
void serialize(Archive & archive, MVKShaderModuleKey& k) {
archive(k.codeSize, k.codeHash);
}
// Helper class to iterate through the shader libraries in a shader library cache in order to serialize them.
// Needs to support input of null shader library cache.
class MVKShaderCacheIterator : MVKBaseObject {
protected:
friend MVKPipelineCache;
bool next() { return (++_index < (_pSLCache ? _pSLCache->_shaderLibraries.size() : 0)); }
SPIRVToMSLConverterContext& getShaderContext() { return _pSLCache->_shaderLibraries[_index].first; }
std::string& getMSL() { return _pSLCache->_shaderLibraries[_index].second->_msl; }
SPIRVEntryPoint& getEntryPoint() { return _pSLCache->_shaderLibraries[_index].second->_entryPoint; }
MVKShaderCacheIterator(MVKShaderLibraryCache* pSLCache) : _pSLCache(pSLCache) {}
MVKShaderLibraryCache* _pSLCache;
size_t _count = 0;
int32_t _index = -1;
};
// If pData is not null, serializes at most pDataSize bytes of the contents of the cache into that
// memory location, and returns the number of bytes serialized in pDataSize. If pData is null,
// returns the number of bytes required to serialize the contents of this pipeline cache.
// This is the compliment of the readData() function. The two must be kept aligned.
VkResult MVKPipelineCache::writeData(size_t* pDataSize, void* pData) {
lock_guard<mutex> lock(_shaderCacheLock);
try {
if ( !pDataSize ) { return VK_SUCCESS; }
if (pData) {
if (*pDataSize >= _dataSize) {
mvk::membuf mb((char*)pData, _dataSize);
ostream outStream(&mb);
writeData(outStream);
*pDataSize = _dataSize;
return VK_SUCCESS;
} else {
*pDataSize = 0;
return VK_INCOMPLETE;
}
} else {
if (_dataSize == 0) {
mvk::countbuf cb;
ostream outStream(&cb);
writeData(outStream, true);
_dataSize = cb.buffSize;
}
*pDataSize = _dataSize;
return VK_SUCCESS;
}
} catch (cereal::Exception& ex) {
*pDataSize = 0;
return mvkNotifyErrorWithText(VK_INCOMPLETE, "Error writing pipeline cache data: %s", ex.what());
}
}
// Serializes the data in this cache to a stream
void MVKPipelineCache::writeData(ostream& outstream, bool isCounting) {
MVKShaderCompilationEventPerformance& shaderCompilationEvent = isCounting
? _device->_shaderCompilationPerformance.sizePipelineCache
: _device->_shaderCompilationPerformance.writePipelineCache;
uint32_t cacheEntryType;
cereal::BinaryOutputArchive writer(outstream);
// Write the data header...after ensuring correct byte-order.
const VkPhysicalDeviceProperties* pDevProps = _device->_pProperties;
writer(NSSwapHostIntToLittle(kDataHeaderSize));
writer(NSSwapHostIntToLittle(VK_PIPELINE_CACHE_HEADER_VERSION_ONE));
writer(NSSwapHostIntToLittle(pDevProps->vendorID));
writer(NSSwapHostIntToLittle(pDevProps->deviceID));
writer(pDevProps->pipelineCacheUUID);
// Shader libraries
// Output a cache entry for each shader library, including the shader module key in each entry.
cacheEntryType = MVKPipelineCacheEntryTypeShaderLibrary;
for (auto& scPair : _shaderCache) {
MVKShaderModuleKey smKey = scPair.first;
MVKShaderCacheIterator cacheIter(scPair.second);
while (cacheIter.next()) {
uint64_t startTime = _device->getPerformanceTimestamp();
writer(cacheEntryType);
writer(smKey);
writer(cacheIter.getShaderContext());
writer(cacheIter.getEntryPoint());
writer(cacheIter.getMSL());
_device->addShaderCompilationEventPerformance(shaderCompilationEvent, startTime);
}
}
// Mark the end of the archive
cacheEntryType = MVKPipelineCacheEntryTypeEOF;
writer(cacheEntryType);
}
// Loads any data indicated by the creation info.
// This is the compliment of the writeData() function. The two must be kept aligned.
void MVKPipelineCache::readData(const VkPipelineCacheCreateInfo* pCreateInfo) {
try {
size_t byteCount = pCreateInfo->initialDataSize;
uint32_t cacheEntryType;
// Must be able to read the header and at least one cache entry type.
if (byteCount < kDataHeaderSize + sizeof(cacheEntryType)) { return; }
mvk::membuf mb((char*)pCreateInfo->pInitialData, byteCount);
istream inStream(&mb);
cereal::BinaryInputArchive reader(inStream);
// Read the data header...and ensure correct byte-order.
uint32_t hdrComponent;
uint8_t pcUUID[VK_UUID_SIZE];
const VkPhysicalDeviceProperties* pDevProps = _device->_pProperties;
reader(hdrComponent); // Header size
if (NSSwapLittleIntToHost(hdrComponent) != kDataHeaderSize) { return; }
reader(hdrComponent); // Header version
if (NSSwapLittleIntToHost(hdrComponent) != VK_PIPELINE_CACHE_HEADER_VERSION_ONE) { return; }
reader(hdrComponent); // Vendor ID
if (NSSwapLittleIntToHost(hdrComponent) != pDevProps->vendorID) { return; }
reader(hdrComponent); // Device ID
if (NSSwapLittleIntToHost(hdrComponent) != pDevProps->deviceID) { return; }
reader(pcUUID); // Pipeline cache UUID
if (memcmp(pcUUID, pDevProps->pipelineCacheUUID, VK_UUID_SIZE) != 0) { return; }
bool done = false;
while ( !done ) {
reader(cacheEntryType);
switch (cacheEntryType) {
case MVKPipelineCacheEntryTypeShaderLibrary: {
uint64_t startTime = _device->getPerformanceTimestamp();
MVKShaderModuleKey smKey;
reader(smKey);
SPIRVToMSLConverterContext shaderContext;
reader(shaderContext);
SPIRVEntryPoint entryPoint;
reader(entryPoint);
string msl;
reader(msl);
// Add the shader library to the staging cache.
MVKShaderLibraryCache* slCache = getShaderLibraryCache(smKey);
_device->addShaderCompilationEventPerformance(_device->_shaderCompilationPerformance.readPipelineCache, startTime);
slCache->addShaderLibrary(&shaderContext, msl, entryPoint);
break;
}
default: {
done = true;
break;
}
}
}
} catch (cereal::Exception& ex) {
setConfigurationResult(mvkNotifyErrorWithText(VK_SUCCESS, "Error reading pipeline cache data: %s", ex.what()));
}
}
// Mark the cache as dirty, so that existing streaming info is released
void MVKPipelineCache::markDirty() {
_dataSize = 0;
}
VkResult MVKPipelineCache::mergePipelineCaches(uint32_t srcCacheCount, const VkPipelineCache* pSrcCaches) {
for (uint32_t srcIdx = 0; srcIdx < srcCacheCount; srcIdx++) {
MVKPipelineCache* srcPLC = (MVKPipelineCache*)pSrcCaches[srcIdx];
for (auto& srcPair : srcPLC->_shaderCache) {
getShaderLibraryCache(srcPair.first)->merge(srcPair.second);
}
}
markDirty();
return VK_SUCCESS;
}
#pragma mark Construction
MVKPipelineCache::MVKPipelineCache(MVKDevice* device, const VkPipelineCacheCreateInfo* pCreateInfo) : MVKBaseDeviceObject(device) {
readData(pCreateInfo);
}
MVKPipelineCache::~MVKPipelineCache() {
for (auto& pair : _shaderCacheByModuleHash) { delete pair.second; }
_shaderCacheByModuleHash.clear();
for (auto& pair : _shaderCache) { delete pair.second; }
_shaderCache.clear();
}

View File

@ -26,6 +26,7 @@
#import <Metal/Metal.h>
class MVKPipelineCache;
class MVKShaderCacheIterator;
using namespace mvk;
@ -50,7 +51,7 @@ public:
MVKMTLFunction getMTLFunction(const VkSpecializationInfo* pSpecializationInfo);
/** Constructs an instance from the specified MSL source code. */
MVKShaderLibrary(MVKDevice* device, const char* mslSourceCode, const SPIRVEntryPoint& entryPoint);
MVKShaderLibrary(MVKDevice* device, const std::string& mslSourceCode, const SPIRVEntryPoint& entryPoint);
/** Constructs an instance from the specified compiled MSL code data. */
MVKShaderLibrary(MVKDevice* device,
@ -60,11 +61,14 @@ public:
~MVKShaderLibrary() override;
protected:
friend MVKShaderCacheIterator;
void handleCompilationError(NSError* err, const char* opDesc);
MTLFunctionConstant* getFunctionConstant(NSArray<MTLFunctionConstant*>* mtlFCs, NSUInteger mtlFCID);
id<MTLLibrary> _mtlLibrary;
SPIRVEntryPoint _entryPoint;
std::string _msl;
};
@ -76,21 +80,32 @@ class MVKShaderLibraryCache : public MVKBaseDeviceObject {
public:
/** Return a shader library from the specified shader context sourced from the specified shader module. */
MVKShaderLibrary* getShaderLibrary(SPIRVToMSLConverterContext* pContext, MVKShaderModule* shaderModule);
/**
* Returns a shader library from the specified shader context sourced from the specified shader module,
* lazily creating the shader library from source code in the shader module, if needed.
*
* If pWasAdded is not nil, this function will set it to true if a new shader library was created,
* and to false if an existing shader library was found and returned.
*/
MVKShaderLibrary* getShaderLibrary(SPIRVToMSLConverterContext* pContext,
MVKShaderModule* shaderModule,
bool* pWasAdded = nullptr);
MVKShaderLibraryCache(MVKDevice* device) : MVKBaseDeviceObject(device) {};
~MVKShaderLibraryCache() override;
protected:
friend MVKShaderCacheIterator;
friend MVKPipelineCache;
MVKShaderLibrary* findShaderLibrary(SPIRVToMSLConverterContext* pContext);
MVKShaderLibrary* addShaderLibrary(SPIRVToMSLConverterContext* pContext,
const char* mslSourceCode,
const std::string& mslSourceCode,
const SPIRVEntryPoint& entryPoint);
void merge(MVKShaderLibraryCache* other);
std::mutex _accessLock;
std::size_t _shaderModuleHash;
std::vector<std::pair<SPIRVToMSLConverterContext, MVKShaderLibrary*>> _shaderLibraries;
};
@ -98,6 +113,30 @@ protected:
#pragma mark -
#pragma mark MVKShaderModule
typedef struct MVKShaderModuleKey_t {
std::size_t codeSize;
std::size_t codeHash;
bool operator==(const MVKShaderModuleKey_t& rhs) const {
return ((codeSize == rhs.codeSize) && (codeHash == rhs.codeHash));
}
MVKShaderModuleKey_t(std::size_t codeSize, std::size_t codeHash) : codeSize(codeSize), codeHash(codeHash) {}
MVKShaderModuleKey_t() : MVKShaderModuleKey_t(0, 0) {}
} MVKShaderModuleKey;
/**
* Hash structure implementation for MVKShaderModuleKey in std namespace,
* so MVKShaderModuleKey can be used as a key in a std::map and std::unordered_map.
*/
namespace std {
template <>
struct hash<MVKShaderModuleKey> {
std::size_t operator()(const MVKShaderModuleKey& k) const {
return k.codeHash;
}
};
}
/** Represents a Vulkan shader module. */
class MVKShaderModule : public MVKBaseDeviceObject {
@ -111,25 +150,30 @@ public:
bool convert(SPIRVToMSLConverterContext* pContext);
/**
* Returns the Metal Shading Language source code most recently converted
* by the convert() function, or set directly using the setMSL() function.
* 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(); }
/** Returns information about the shader entry point. */
/**
* 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(); }
/** Returns a key as a means of identifying this shader module in a pipeline cache. */
inline std::size_t getKey() { return _key; }
inline MVKShaderModuleKey getKey() { return _key; }
MVKShaderModule(MVKDevice* device, const VkShaderModuleCreateInfo* pCreateInfo);
~MVKShaderModule() override;
protected:
friend MVKShaderCacheIterator;
MVKShaderLibraryCache _shaderLibraryCache;
SPIRVToMSLConverter _converter;
MVKShaderLibrary* _defaultLibrary;
std::size_t _key;
MVKShaderModuleKey _key;
std::mutex _accessLock;
};

View File

@ -120,12 +120,12 @@ MTLFunctionConstant* MVKShaderLibrary::getFunctionConstant(NSArray<MTLFunctionCo
return nil;
}
MVKShaderLibrary::MVKShaderLibrary(MVKDevice* device, const char* mslSourceCode, const SPIRVEntryPoint& entryPoint) : MVKBaseDeviceObject(device) {
MVKShaderLibrary::MVKShaderLibrary(MVKDevice* device, const string& mslSourceCode, const SPIRVEntryPoint& entryPoint) : MVKBaseDeviceObject(device) {
uint64_t startTime = _device->getPerformanceTimestamp();
@autoreleasepool {
MTLCompileOptions* options = [[MTLCompileOptions new] autorelease]; // TODO: what compile options apply?
NSError* err = nil;
_mtlLibrary = [getMTLDevice() newLibraryWithSource: @(mslSourceCode)
_mtlLibrary = [getMTLDevice() newLibraryWithSource: @(mslSourceCode.c_str())
options: options
error: &err]; // retained
handleCompilationError(err, "Shader module compilation");
@ -133,6 +133,7 @@ MVKShaderLibrary::MVKShaderLibrary(MVKDevice* device, const char* mslSourceCode,
_device->addShaderCompilationEventPerformance(_device->_shaderCompilationPerformance.mslCompile, startTime);
_entryPoint = entryPoint;
_msl = mslSourceCode;
}
MVKShaderLibrary::MVKShaderLibrary(MVKDevice* device,
@ -178,13 +179,19 @@ MVKShaderLibrary::~MVKShaderLibrary() {
#pragma mark MVKShaderLibraryCache
MVKShaderLibrary* MVKShaderLibraryCache::getShaderLibrary(SPIRVToMSLConverterContext* pContext,
MVKShaderModule* shaderModule) {
MVKShaderModule* shaderModule,
bool* pWasAdded) {
bool wasAdded = false;
MVKShaderLibrary* shLib = findShaderLibrary(pContext);
if ( !shLib ) {
if (shaderModule->convert(pContext)) {
shLib = addShaderLibrary(pContext, shaderModule->getMSL().c_str(), shaderModule->getEntryPoint());
shLib = addShaderLibrary(pContext, shaderModule->getMSL(), shaderModule->getEntryPoint());
wasAdded = true;
}
}
if (pWasAdded) { *pWasAdded = wasAdded; }
return shLib;
}
@ -200,15 +207,25 @@ MVKShaderLibrary* MVKShaderLibraryCache::findShaderLibrary(SPIRVToMSLConverterCo
return NULL;
}
/** Adds and returns a new shader library configured from the specified context. */
// Adds and returns a new shader library configured from the specified context.
MVKShaderLibrary* MVKShaderLibraryCache::addShaderLibrary(SPIRVToMSLConverterContext* pContext,
const char* mslSourceCode,
const string& mslSourceCode,
const SPIRVEntryPoint& entryPoint) {
MVKShaderLibrary* shLib = new MVKShaderLibrary(_device, mslSourceCode, entryPoint);
_shaderLibraries.push_back(pair<SPIRVToMSLConverterContext, MVKShaderLibrary*>(*pContext, shLib));
return shLib;
}
// Merge another shader library cache with this one. Handle null input.
void MVKShaderLibraryCache::merge(MVKShaderLibraryCache* other) {
if ( !other ) { return; }
for (auto& otherPair : other->_shaderLibraries) {
if ( !findShaderLibrary(&otherPair.first) ) {
_shaderLibraries.push_back(otherPair);
}
}
}
MVKShaderLibraryCache::~MVKShaderLibraryCache() {
for (auto& slPair : _shaderLibraries) { delete slPair.second; }
}
@ -225,10 +242,8 @@ MVKMTLFunction MVKShaderModule::getMTLFunction(SPIRVToMSLConverterContext* pCont
if ( !mvkLib ) {
uint64_t startTime = _device->getPerformanceTimestamp();
if (pipelineCache) {
MVKLogDebug("Retrieving shader from pipeline cache.");
mvkLib = pipelineCache->getShaderLibrary(pContext, this);
} else {
MVKLogDebug("Retrieving shader from shader module.");
mvkLib = _shaderLibraryCache.getShaderLibrary(pContext, this);
}
_device->addShaderCompilationEventPerformance(_device->_shaderCompilationPerformance.shaderLibraryFromCache, startTime);
@ -255,10 +270,11 @@ bool MVKShaderModule::convert(SPIRVToMSLConverterContext* pContext) {
#pragma mark Construction
MVKShaderModule::MVKShaderModule(MVKDevice* device,
const VkShaderModuleCreateInfo* pCreateInfo) : MVKBaseDeviceObject(device),
_shaderLibraryCache(device) {
const VkShaderModuleCreateInfo* pCreateInfo) : MVKBaseDeviceObject(device), _shaderLibraryCache(device) {
_defaultLibrary = nullptr;
size_t codeSize = pCreateInfo->codeSize;
// Ensure something is there.
@ -267,7 +283,7 @@ MVKShaderModule::MVKShaderModule(MVKDevice* device,
return;
}
_key = mvkHash(&pCreateInfo->codeSize, 1);
size_t codeHash = 0;
// Retrieve the magic number to determine what type of shader code has been loaded.
uint32_t magicNum = *pCreateInfo->pCode;
@ -276,7 +292,7 @@ MVKShaderModule::MVKShaderModule(MVKDevice* device,
size_t spvCount = (pCreateInfo->codeSize + 3) >> 2; // Round up if byte length not exactly on uint32_t boundary
uint64_t startTime = _device->getPerformanceTimestamp();
_key = mvkHash(pCreateInfo->pCode, spvCount, _key);
codeHash = mvkHash(pCreateInfo->pCode, spvCount);
_device->addShaderCompilationEventPerformance(_device->_shaderCompilationPerformance.hashShaderCode, startTime);
_converter.setSPIRV(pCreateInfo->pCode, spvCount);
@ -289,8 +305,8 @@ MVKShaderModule::MVKShaderModule(MVKDevice* device,
size_t mslCodeLen = pCreateInfo->codeSize - hdrSize;
uint64_t startTime = _device->getPerformanceTimestamp();
_key = mvkHash(&magicNum, 1, _key);
_key = mvkHash(pMSLCode, mslCodeLen, _key);
codeHash = mvkHash(&magicNum, 1);
codeHash = mvkHash(pMSLCode, mslCodeLen, codeHash);
_device->addShaderCompilationEventPerformance(_device->_shaderCompilationPerformance.hashShaderCode, startTime);
_converter.setMSL(pMSLCode, nullptr);
@ -304,8 +320,8 @@ MVKShaderModule::MVKShaderModule(MVKDevice* device,
size_t mslCodeLen = pCreateInfo->codeSize - hdrSize;
uint64_t startTime = _device->getPerformanceTimestamp();
_key = mvkHash(&magicNum, 1, _key);
_key = mvkHash(pMSLCode, mslCodeLen, _key);
codeHash = mvkHash(&magicNum, 1);
codeHash = mvkHash(pMSLCode, mslCodeLen, codeHash);
_device->addShaderCompilationEventPerformance(_device->_shaderCompilationPerformance.hashShaderCode, startTime);
_defaultLibrary = new MVKShaderLibrary(_device, (void*)(pMSLCode), mslCodeLen);
@ -316,6 +332,8 @@ MVKShaderModule::MVKShaderModule(MVKDevice* device,
setConfigurationResult(mvkNotifyErrorWithText(VK_ERROR_FORMAT_NOT_SUPPORTED, "SPIR-V contains invalid magic number %x.", magicNum));
break;
}
_key = MVKShaderModuleKey(codeSize, codeHash);
}
MVKShaderModule::~MVKShaderModule() {

View File

@ -674,7 +674,7 @@ MVK_PUBLIC_SYMBOL VkResult vkGetPipelineCacheData(
void* pData) {
MVKPipelineCache* mvkPLC = (MVKPipelineCache*)pipelineCache;
return mvkPLC->getData(pDataSize, pData);
return mvkPLC->writeData(pDataSize, pData);
}
MVK_PUBLIC_SYMBOL VkResult vkMergePipelineCaches(

View File

@ -143,6 +143,7 @@
A9AD67D22054E2D700ED3C08 /* Vulkan-LoaderAndValidationLayers_repo_revision */ = {isa = PBXFileReference; lastKnownFileType = text; path = "Vulkan-LoaderAndValidationLayers_repo_revision"; sourceTree = "<group>"; };
A9AD67D32054E2D700ED3C08 /* SPIRV-Cross_repo_revision */ = {isa = PBXFileReference; lastKnownFileType = text; path = "SPIRV-Cross_repo_revision"; sourceTree = "<group>"; };
A9AD67E92055D8A600ED3C08 /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = "<group>"; };
A9EE46412065766C00193200 /* cereal_repo_revision */ = {isa = PBXFileReference; lastKnownFileType = text; path = cereal_repo_revision; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXGroup section */
@ -181,6 +182,7 @@
children = (
A9AD67E92055D8A600ED3C08 /* README.md */,
A943100220546CDD00F5CF87 /* fetchDependencies */,
A9EE46412065766C00193200 /* cereal_repo_revision */,
A9AD67D32054E2D700ED3C08 /* SPIRV-Cross_repo_revision */,
A9AD67D22054E2D700ED3C08 /* Vulkan-LoaderAndValidationLayers_repo_revision */,
A9AD67D12054E2D700ED3C08 /* VulkanSamples_repo_revision */,
@ -206,7 +208,7 @@
A90B2B1D1A9B6170008EE819 /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 0920;
LastUpgradeCheck = 0930;
TargetAttributes = {
A9FEADBC1F3517480010240E = {
DevelopmentTeam = VU3TCKU48B;

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0920"
LastUpgradeVersion = "0930"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
@ -26,7 +26,6 @@
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
language = ""
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
@ -38,7 +37,6 @@
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
disableMainThreadChecker = "YES"
language = ""
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0920"
LastUpgradeVersion = "0930"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
@ -26,7 +26,6 @@
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
language = ""
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
@ -38,7 +37,6 @@
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
disableMainThreadChecker = "YES"
language = ""
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"

View File

@ -2209,7 +2209,7 @@
A9F55D25198BE6A7004EC31B /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 0920;
LastUpgradeCheck = 0930;
ORGANIZATIONNAME = "The Brenwill Workshop Ltd.";
TargetAttributes = {
A9092A8C1A81717B00051823 = {

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0920"
LastUpgradeVersion = "0930"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
@ -26,7 +26,6 @@
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
language = ""
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
@ -37,7 +36,6 @@
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
language = ""
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0920"
LastUpgradeVersion = "0930"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
@ -26,7 +26,6 @@
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
language = ""
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
@ -37,7 +36,6 @@
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
language = ""
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0920"
LastUpgradeVersion = "0930"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
@ -26,7 +26,6 @@
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
language = ""
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
@ -37,7 +36,6 @@
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
language = ""
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0920"
LastUpgradeVersion = "0930"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
@ -26,7 +26,6 @@
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
language = ""
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
@ -37,7 +36,6 @@
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
language = ""
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0920"
LastUpgradeVersion = "0930"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
@ -26,7 +26,6 @@
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
language = ""
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
@ -46,7 +45,6 @@
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
language = ""
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
@ -74,19 +72,19 @@
</CommandLineArgument>
<CommandLineArgument
argument = "-gi"
isEnabled = "YES">
isEnabled = "NO">
</CommandLineArgument>
<CommandLineArgument
argument = "/Users/bill/Documents/Dev/iOSProjects/Molten/MoltenVK-bh/External/SPIRV-Cross/shaders-msl/comp/struct-nested.comp"
isEnabled = "YES">
argument = "/Users/bill/Documents/Dev/iOSProjects/Molten/Support/2018/MVK_Issue_112/bad_attrs.vert"
isEnabled = "NO">
</CommandLineArgument>
<CommandLineArgument
argument = "-si"
isEnabled = "NO">
isEnabled = "YES">
</CommandLineArgument>
<CommandLineArgument
argument = "/Users/bill/Documents/Dev/iOSProjects/Molten/Support/Valve/Dota2/shader-issues/sample_mask/sample_mask.spv"
isEnabled = "NO">
argument = "/Users/bill/Documents/Dev/iOSProjects/Molten/Support/2018/MVK_Issue_112/second/vert_bin.spv"
isEnabled = "YES">
</CommandLineArgument>
<CommandLineArgument
argument = "-mo"