Shader libraries cached in MVKPipelineCache instead of MVKShaderModule.

This commit is contained in:
Bill Hollings 2018-03-22 23:52:12 -04:00
parent fd7521dc7b
commit c45b47183e
10 changed files with 242 additions and 111 deletions

View File

@ -105,9 +105,11 @@ typedef struct {
/** MoltenVK performance of shader compilation events for a VkDevice. */ /** MoltenVK performance of shader compilation events for a VkDevice. */
typedef struct { typedef struct {
MVKShaderCompilationEventPerformance hashShaderCode; /** Create a hash from the incoming shader code. */
MVKShaderCompilationEventPerformance spirvToMSL; /** Convert SPIR-V to MSL source code. */ MVKShaderCompilationEventPerformance spirvToMSL; /** Convert SPIR-V to MSL source code. */
MVKShaderCompilationEventPerformance mslCompile; /** Compile MSL source code into a MTLLibrary. */ MVKShaderCompilationEventPerformance mslCompile; /** Compile MSL source code into a MTLLibrary. */
MVKShaderCompilationEventPerformance mslLoad; /** Load pre-compiled MSL code into a MTLLibrary. */ MVKShaderCompilationEventPerformance mslLoad; /** Load pre-compiled MSL code into a MTLLibrary. */
MVKShaderCompilationEventPerformance shaderLibraryFromCache; /** Retrieve a shader library from the cache, lazily creating it if needed. */
MVKShaderCompilationEventPerformance functionRetrieval; /** Retrieve a MTLFunction from a MTLLibrary. */ MVKShaderCompilationEventPerformance functionRetrieval; /** Retrieve a MTLFunction from a MTLLibrary. */
MVKShaderCompilationEventPerformance functionSpecialization; /** Specialize a retrieved MTLFunction. */ MVKShaderCompilationEventPerformance functionSpecialization; /** Specialize a retrieved MTLFunction. */
MVKShaderCompilationEventPerformance pipelineCompile; /** Compile MTLFunctions into a pipeline. */ MVKShaderCompilationEventPerformance pipelineCompile; /** Compile MTLFunctions into a pipeline. */

View File

@ -29,7 +29,6 @@
#include "MVKCmdQueries.h" #include "MVKCmdQueries.h"
#include "MVKMTLBufferAllocation.h" #include "MVKMTLBufferAllocation.h"
#include <unordered_set> #include <unordered_set>
#include <unordered_map>
#include <list> #include <list>
#include <mutex> #include <mutex>

View File

@ -221,7 +221,7 @@ public:
return (MVKPhysicalDevice*)getDispatchableObject(vkPhysicalDevice); return (MVKPhysicalDevice*)getDispatchableObject(vkPhysicalDevice);
} }
private: protected:
friend class MVKDevice; friend class MVKDevice;
MTLFeatureSet getMaximalMTLFeatureSet(); MTLFeatureSet getMaximalMTLFeatureSet();

View File

@ -1325,22 +1325,24 @@ void MVKDevice::addShaderCompilationEventPerformanceImpl(MVKShaderCompilationEve
double currInterval = mvkGetElapsedMilliseconds(startTime, endTime); double currInterval = mvkGetElapsedMilliseconds(startTime, endTime);
shaderCompilationEvent.minimumDuration = min(currInterval, shaderCompilationEvent.minimumDuration); shaderCompilationEvent.minimumDuration = min(currInterval, shaderCompilationEvent.minimumDuration);
shaderCompilationEvent.maximumDuration = max(currInterval, shaderCompilationEvent.maximumDuration); shaderCompilationEvent.maximumDuration = max(currInterval, shaderCompilationEvent.maximumDuration);
double totalInverval = (shaderCompilationEvent.averageDuration * shaderCompilationEvent.count++) + currInterval; double totalInterval = (shaderCompilationEvent.averageDuration * shaderCompilationEvent.count++) + currInterval;
shaderCompilationEvent.averageDuration = totalInverval / shaderCompilationEvent.count; shaderCompilationEvent.averageDuration = totalInterval / shaderCompilationEvent.count;
MVKLogInfo("%s performance curr: %.3f ms, avg: %.3f ms, min: %.3f ms, max: %.3f ms, count: %d", MVKLogDebug("%s performance curr: %.3f ms, avg: %.3f ms, min: %.3f ms, max: %.3f ms, count: %d",
getShaderCompilationEventName(shaderCompilationEvent), getShaderCompilationEventName(shaderCompilationEvent),
currInterval, currInterval,
shaderCompilationEvent.averageDuration, shaderCompilationEvent.averageDuration,
shaderCompilationEvent.minimumDuration, shaderCompilationEvent.minimumDuration,
shaderCompilationEvent.maximumDuration, shaderCompilationEvent.maximumDuration,
shaderCompilationEvent.count); shaderCompilationEvent.count);
} }
const char* MVKDevice::getShaderCompilationEventName(MVKShaderCompilationEventPerformance& shaderCompilationEvent) { 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.spirvToMSL) { return "Convert SPIR-V to MSL source code"; }
if (&shaderCompilationEvent == &_shaderCompilationPerformance.mslCompile) { return "Compile MSL source code into a MTLLibrary"; } 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.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.functionRetrieval) { return "Retrieve a MTLFunction from a MTLLibrary"; }
if (&shaderCompilationEvent == &_shaderCompilationPerformance.functionSpecialization) { return "Specialize a retrieved MTLFunction"; } if (&shaderCompilationEvent == &_shaderCompilationPerformance.functionSpecialization) { return "Specialize a retrieved MTLFunction"; }
if (&shaderCompilationEvent == &_shaderCompilationPerformance.pipelineCompile) { return "Compile MTLFunctions into a pipeline"; } if (&shaderCompilationEvent == &_shaderCompilationPerformance.pipelineCompile) { return "Compile MTLFunctions into a pipeline"; }
@ -1464,9 +1466,11 @@ void MVKDevice::initPerformanceTracking() {
initPerf.minimumDuration = numeric_limits<double>::max(); initPerf.minimumDuration = numeric_limits<double>::max();
initPerf.maximumDuration = 0.0; initPerf.maximumDuration = 0.0;
_shaderCompilationPerformance.hashShaderCode = initPerf;
_shaderCompilationPerformance.spirvToMSL = initPerf; _shaderCompilationPerformance.spirvToMSL = initPerf;
_shaderCompilationPerformance.mslCompile = initPerf; _shaderCompilationPerformance.mslCompile = initPerf;
_shaderCompilationPerformance.mslLoad = initPerf; _shaderCompilationPerformance.mslLoad = initPerf;
_shaderCompilationPerformance.shaderLibraryFromCache = initPerf;
_shaderCompilationPerformance.functionRetrieval = initPerf; _shaderCompilationPerformance.functionRetrieval = initPerf;
_shaderCompilationPerformance.functionSpecialization = initPerf; _shaderCompilationPerformance.functionSpecialization = initPerf;
_shaderCompilationPerformance.pipelineCompile = initPerf; _shaderCompilationPerformance.pipelineCompile = initPerf;

View File

@ -71,7 +71,12 @@ public:
virtual void encode(MVKCommandEncoder* cmdEncoder) = 0; virtual void encode(MVKCommandEncoder* cmdEncoder) = 0;
/** Constructs an instance for the device. layout, and parent (which may be NULL). */ /** Constructs an instance for the device. layout, and parent (which may be NULL). */
MVKPipeline(MVKDevice* device, MVKPipelineCache* pipelineCache, MVKPipeline* parent) : MVKBaseDeviceObject(device) {} MVKPipeline(MVKDevice* device, MVKPipelineCache* pipelineCache, MVKPipeline* parent) : MVKBaseDeviceObject(device),
_pipelineCache(pipelineCache) {}
protected:
MVKPipelineCache* _pipelineCache;
}; };
@ -168,6 +173,9 @@ public:
return VK_SUCCESS; return VK_SUCCESS;
} }
/** 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. */ /** 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; } inline VkResult mergePipelineCaches(uint32_t srcCacheCount, const VkPipelineCache* pSrcCaches) { return VK_SUCCESS; }
@ -176,4 +184,10 @@ public:
/** Constructs an instance for the specified device. */ /** Constructs an instance for the specified device. */
MVKPipelineCache(MVKDevice* device, const VkPipelineCacheCreateInfo* pCreateInfo) : MVKBaseDeviceObject(device) {} MVKPipelineCache(MVKDevice* device, const VkPipelineCacheCreateInfo* pCreateInfo) : MVKBaseDeviceObject(device) {}
~MVKPipelineCache() override;
protected:
std::unordered_map<std::size_t, MVKShaderLibraryCache*> _shaderCacheByModuleHash;
std::mutex _shaderCacheLock;
}; };

View File

@ -271,13 +271,13 @@ MTLRenderPipelineDescriptor* MVKGraphicsPipeline::getMTLRenderPipelineDescriptor
// Vertex shader // Vertex shader
if (mvkAreFlagsEnabled(pSS->stage, VK_SHADER_STAGE_VERTEX_BIT)) { if (mvkAreFlagsEnabled(pSS->stage, VK_SHADER_STAGE_VERTEX_BIT)) {
shaderContext.options.entryPointStage = spv::ExecutionModelVertex; shaderContext.options.entryPointStage = spv::ExecutionModelVertex;
plDesc.vertexFunction = mvkShdrMod->getMTLFunction(&shaderContext, pSS->pSpecializationInfo).mtlFunction; plDesc.vertexFunction = mvkShdrMod->getMTLFunction(&shaderContext, pSS->pSpecializationInfo, _pipelineCache).mtlFunction;
} }
// Fragment shader // Fragment shader
if (mvkAreFlagsEnabled(pSS->stage, VK_SHADER_STAGE_FRAGMENT_BIT)) { if (mvkAreFlagsEnabled(pSS->stage, VK_SHADER_STAGE_FRAGMENT_BIT)) {
shaderContext.options.entryPointStage = spv::ExecutionModelFragment; shaderContext.options.entryPointStage = spv::ExecutionModelFragment;
plDesc.fragmentFunction = mvkShdrMod->getMTLFunction(&shaderContext, pSS->pSpecializationInfo).mtlFunction; plDesc.fragmentFunction = mvkShdrMod->getMTLFunction(&shaderContext, pSS->pSpecializationInfo, _pipelineCache).mtlFunction;
} }
} }
@ -437,10 +437,36 @@ MVKMTLFunction MVKComputePipeline::getMTLFunction(const VkComputePipelineCreateI
layout->populateShaderConverterContext(shaderContext); layout->populateShaderConverterContext(shaderContext);
MVKShaderModule* mvkShdrMod = (MVKShaderModule*)pSS->module; MVKShaderModule* mvkShdrMod = (MVKShaderModule*)pSS->module;
return mvkShdrMod->getMTLFunction(&shaderContext, pSS->pSpecializationInfo); return mvkShdrMod->getMTLFunction(&shaderContext, pSS->pSpecializationInfo, _pipelineCache);
} }
MVKComputePipeline::~MVKComputePipeline() { MVKComputePipeline::~MVKComputePipeline() {
[_mtlPipelineState release]; [_mtlPipelineState release];
} }
#pragma mark -
#pragma mark MVKPipelineCache
/** Return a shader library from the specified shader context sourced from the specified shader module. */
MVKShaderLibrary* MVKPipelineCache::getShaderLibrary(SPIRVToMSLConverterContext* pContext, MVKShaderModule* shaderModule) {
lock_guard<mutex> lock(_shaderCacheLock);
size_t smKey = shaderModule->getKey();
MVKShaderLibraryCache* slCache = _shaderCacheByModuleHash[smKey];
if ( !slCache ) {
slCache = new MVKShaderLibraryCache(_device);
_shaderCacheByModuleHash[smKey] = slCache;
}
return slCache->getShaderLibrary(pContext, shaderModule);
}
MVKPipelineCache::~MVKPipelineCache() {
for (auto& pair : _shaderCacheByModuleHash) { delete pair.second; }
_shaderCacheByModuleHash.clear();
}

View File

@ -25,6 +25,8 @@
#import <Metal/Metal.h> #import <Metal/Metal.h>
class MVKPipelineCache;
using namespace mvk; using namespace mvk;
@ -47,8 +49,8 @@ public:
/** Returns the Metal shader function, possibly specialized. */ /** Returns the Metal shader function, possibly specialized. */
MVKMTLFunction getMTLFunction(const VkSpecializationInfo* pSpecializationInfo); MVKMTLFunction getMTLFunction(const VkSpecializationInfo* pSpecializationInfo);
/** Constructs an instance from the MSL source code in the specified SPIRVToMSLConverter. */ /** Constructs an instance from the specified MSL source code. */
MVKShaderLibrary(MVKDevice* device, SPIRVToMSLConverter& mslConverter); MVKShaderLibrary(MVKDevice* device, const char* mslSourceCode, const SPIRVEntryPoint& entryPoint);
/** Constructs an instance from the specified compiled MSL code data. */ /** Constructs an instance from the specified compiled MSL code data. */
MVKShaderLibrary(MVKDevice* device, MVKShaderLibrary(MVKDevice* device,
@ -66,6 +68,33 @@ protected:
}; };
#pragma mark -
#pragma mark MVKShaderLibraryCache
/** Represents a cache of shader libraries for one shader module. */
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);
MVKShaderLibraryCache(MVKDevice* device) : MVKBaseDeviceObject(device) {};
~MVKShaderLibraryCache() override;
protected:
MVKShaderLibrary* findShaderLibrary(SPIRVToMSLConverterContext* pContext);
MVKShaderLibrary* addShaderLibrary(SPIRVToMSLConverterContext* pContext,
const char* mslSourceCode,
const SPIRVEntryPoint& entryPoint);
std::mutex _accessLock;
std::size_t _shaderModuleHash;
std::vector<std::pair<SPIRVToMSLConverterContext, MVKShaderLibrary*>> _shaderLibraries;
};
#pragma mark - #pragma mark -
#pragma mark MVKShaderModule #pragma mark MVKShaderModule
@ -75,19 +104,32 @@ class MVKShaderModule : public MVKBaseDeviceObject {
public: public:
/** Returns the Metal shader function, possibly specialized. */ /** Returns the Metal shader function, possibly specialized. */
MVKMTLFunction getMTLFunction(SPIRVToMSLConverterContext* pContext, MVKMTLFunction getMTLFunction(SPIRVToMSLConverterContext* pContext,
const VkSpecializationInfo* pSpecializationInfo); const VkSpecializationInfo* pSpecializationInfo,
MVKPipelineCache* pipelineCache);
/** Convert the SPIR-V to MSL, using the specified shader conversion context. */
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.
*/
inline const std::string& getMSL() { return _converter.getMSL(); }
/** Returns information about the shader entry point. */
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; }
MVKShaderModule(MVKDevice* device, const VkShaderModuleCreateInfo* pCreateInfo); MVKShaderModule(MVKDevice* device, const VkShaderModuleCreateInfo* pCreateInfo);
~MVKShaderModule() override; ~MVKShaderModule() override;
protected: protected:
MVKShaderLibrary* getShaderLibrary(SPIRVToMSLConverterContext* pContext); MVKShaderLibraryCache _shaderLibraryCache;
MVKShaderLibrary* findShaderLibrary(SPIRVToMSLConverterContext* pContext);
MVKShaderLibrary* addShaderLibrary(SPIRVToMSLConverterContext* pContext);
SPIRVToMSLConverter _converter; SPIRVToMSLConverter _converter;
MVKShaderLibrary* _defaultLibrary; MVKShaderLibrary* _defaultLibrary;
std::vector<std::pair<SPIRVToMSLConverterContext, MVKShaderLibrary*>> _shaderLibraries; std::size_t _key;
std::mutex _accessLock; std::mutex _accessLock;
}; };

View File

@ -17,6 +17,7 @@
*/ */
#include "MVKShaderModule.h" #include "MVKShaderModule.h"
#include "MVKPipeline.h"
#include "MVKFoundation.h" #include "MVKFoundation.h"
#include "vk_mvk_moltenvk.h" #include "vk_mvk_moltenvk.h"
#include <string> #include <string>
@ -119,19 +120,19 @@ MTLFunctionConstant* MVKShaderLibrary::getFunctionConstant(NSArray<MTLFunctionCo
return nil; return nil;
} }
MVKShaderLibrary::MVKShaderLibrary(MVKDevice* device, SPIRVToMSLConverter& mslConverter) : MVKBaseDeviceObject(device) { MVKShaderLibrary::MVKShaderLibrary(MVKDevice* device, const char* mslSourceCode, const SPIRVEntryPoint& entryPoint) : MVKBaseDeviceObject(device) {
uint64_t startTime = _device->getPerformanceTimestamp(); uint64_t startTime = _device->getPerformanceTimestamp();
@autoreleasepool { @autoreleasepool {
MTLCompileOptions* options = [[MTLCompileOptions new] autorelease]; // TODO: what compile options apply? MTLCompileOptions* options = [[MTLCompileOptions new] autorelease]; // TODO: what compile options apply?
NSError* err = nil; NSError* err = nil;
_mtlLibrary = [getMTLDevice() newLibraryWithSource: @(mslConverter.getMSL().data()) _mtlLibrary = [getMTLDevice() newLibraryWithSource: @(mslSourceCode)
options: options options: options
error: &err]; // retained error: &err]; // retained
handleCompilationError(err, "Shader module compilation"); handleCompilationError(err, "Shader module compilation");
} }
_device->addShaderCompilationEventPerformance(_device->_shaderCompilationPerformance.mslCompile, startTime); _device->addShaderCompilationEventPerformance(_device->_shaderCompilationPerformance.mslCompile, startTime);
_entryPoint = mslConverter.getEntryPoint(); _entryPoint = entryPoint;
} }
MVKShaderLibrary::MVKShaderLibrary(MVKDevice* device, MVKShaderLibrary::MVKShaderLibrary(MVKDevice* device,
@ -174,97 +175,150 @@ MVKShaderLibrary::~MVKShaderLibrary() {
#pragma mark - #pragma mark -
#pragma mark MVKShaderModule #pragma mark MVKShaderLibraryCache
MVKMTLFunction MVKShaderModule::getMTLFunction(SPIRVToMSLConverterContext* pContext,
const VkSpecializationInfo* pSpecializationInfo) {
lock_guard<mutex> lock(_accessLock);
MVKShaderLibrary* mvkLib = getShaderLibrary(pContext);
return mvkLib ? mvkLib->getMTLFunction(pSpecializationInfo) : MVKMTLFunctionNull;
}
MVKShaderLibrary* MVKShaderModule::getShaderLibrary(SPIRVToMSLConverterContext* pContext) {
if (_defaultLibrary) { return _defaultLibrary; }
MVKShaderLibrary* MVKShaderLibraryCache::getShaderLibrary(SPIRVToMSLConverterContext* pContext,
MVKShaderModule* shaderModule) {
MVKShaderLibrary* shLib = findShaderLibrary(pContext); MVKShaderLibrary* shLib = findShaderLibrary(pContext);
if ( !shLib ) { shLib = addShaderLibrary(pContext); } if ( !shLib ) {
// else { MVKLogDebug("Shader Module %p reusing library.", this); } if (shaderModule->convert(pContext)) {
shLib = addShaderLibrary(pContext, shaderModule->getMSL().c_str(), shaderModule->getEntryPoint());
}
}
return shLib; return shLib;
} }
// Finds and returns a shader library matching the specified context, or returns nullptr if it doesn't exist. // Finds and returns a shader library matching the specified context, or returns nullptr if it doesn't exist.
// If a match is found, the usage of the specified context is aligned with the context of the matching library. // If a match is found, the usage of the specified context is aligned with the context of the matching library.
MVKShaderLibrary* MVKShaderModule::findShaderLibrary(SPIRVToMSLConverterContext* pContext) { MVKShaderLibrary* MVKShaderLibraryCache::findShaderLibrary(SPIRVToMSLConverterContext* pContext) {
for (auto& slPair : _shaderLibraries) { for (auto& slPair : _shaderLibraries) {
if (slPair.first.matches(*pContext)) { if (slPair.first.matches(*pContext)) {
pContext->alignUsageWith(slPair.first); pContext->alignUsageWith(slPair.first);
return slPair.second; return slPair.second;
} }
} }
return NULL; 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* MVKShaderModule::addShaderLibrary(SPIRVToMSLConverterContext* pContext) { MVKShaderLibrary* MVKShaderLibraryCache::addShaderLibrary(SPIRVToMSLConverterContext* pContext,
const char* mslSourceCode,
const SPIRVEntryPoint& entryPoint) {
MVKShaderLibrary* shLib = new MVKShaderLibrary(_device, mslSourceCode, entryPoint);
_shaderLibraries.push_back(pair<SPIRVToMSLConverterContext, MVKShaderLibrary*>(*pContext, shLib));
return shLib;
}
MVKShaderLibrary* shLib = nullptr; MVKShaderLibraryCache::~MVKShaderLibraryCache() {
bool shouldLogCode = _device->_mvkConfig.debugMode; for (auto& slPair : _shaderLibraries) { delete slPair.second; }
}
uint64_t startTime = _device->getPerformanceTimestamp();
bool wasConverted = _converter.convert(*pContext, shouldLogCode, shouldLogCode, shouldLogCode);
_device->addShaderCompilationEventPerformance(_device->_shaderCompilationPerformance.spirvToMSL, startTime);
if (wasConverted) { #pragma mark -
if (shouldLogCode) { MVKLogInfo("%s", _converter.getResultLog().data()); } #pragma mark MVKShaderModule
shLib = new MVKShaderLibrary(_device, _converter);
_shaderLibraries.push_back(pair<SPIRVToMSLConverterContext, MVKShaderLibrary*>(*pContext, shLib)); MVKMTLFunction MVKShaderModule::getMTLFunction(SPIRVToMSLConverterContext* pContext,
// MVKLogDebug("Shader Module %p compiled %d libraries.", this, _shaderLibraries.size()); const VkSpecializationInfo* pSpecializationInfo,
} else { MVKPipelineCache* pipelineCache) {
mvkNotifyErrorWithText(VK_ERROR_FORMAT_NOT_SUPPORTED, "Unable to convert SPIR-V to MSL:\n%s", _converter.getResultLog().data()); lock_guard<mutex> lock(_accessLock);
} MVKShaderLibrary* mvkLib = _defaultLibrary;
return shLib; 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);
}
return mvkLib ? mvkLib->getMTLFunction(pSpecializationInfo) : MVKMTLFunctionNull;
}
bool MVKShaderModule::convert(SPIRVToMSLConverterContext* pContext) {
bool shouldLogCode = _device->_mvkConfig.debugMode;
uint64_t startTime = _device->getPerformanceTimestamp();
bool wasConverted = _converter.convert(*pContext, shouldLogCode, shouldLogCode, shouldLogCode);
_device->addShaderCompilationEventPerformance(_device->_shaderCompilationPerformance.spirvToMSL, startTime);
if (wasConverted) {
if (shouldLogCode) { MVKLogInfo("%s", _converter.getResultLog().data()); }
} else {
mvkNotifyErrorWithText(VK_ERROR_FORMAT_NOT_SUPPORTED, "Unable to convert SPIR-V to MSL:\n%s", _converter.getResultLog().data());
}
return wasConverted;
} }
#pragma mark Construction #pragma mark Construction
MVKShaderModule::MVKShaderModule(MVKDevice* device, MVKShaderModule::MVKShaderModule(MVKDevice* device,
const VkShaderModuleCreateInfo* pCreateInfo) : MVKBaseDeviceObject(device) { const VkShaderModuleCreateInfo* pCreateInfo) : MVKBaseDeviceObject(device),
_shaderLibraryCache(device) {
_defaultLibrary = nullptr; _defaultLibrary = nullptr;
// Ensure something is there. size_t codeSize = pCreateInfo->codeSize;
if ( (pCreateInfo->pCode != VK_NULL_HANDLE) && (pCreateInfo->codeSize >= 4) ) {
// Retrieve the magic number to determine what type of shader code has been loaded. // Ensure something is there.
uint32_t magicNum = *pCreateInfo->pCode; if ( (pCreateInfo->pCode == VK_NULL_HANDLE) || (codeSize < 4) ) {
switch (magicNum) { setConfigurationResult(mvkNotifyErrorWithText(VK_INCOMPLETE, "Shader module contains no SPIR-V code."));
case kMVKMagicNumberSPIRVCode: { // SPIR-V code return;
size_t spvCount = (pCreateInfo->codeSize + 3) >> 2; // Round up if byte length not exactly on uint32_t boundary }
_converter.setSPIRV(pCreateInfo->pCode, spvCount);
break; _key = mvkHash(&pCreateInfo->codeSize, 1);
}
case kMVKMagicNumberMSLSourceCode: { // MSL source code // Retrieve the magic number to determine what type of shader code has been loaded.
uintptr_t pMSLCode = uintptr_t(pCreateInfo->pCode) + sizeof(MVKMSLSPIRVHeader); uint32_t magicNum = *pCreateInfo->pCode;
_converter.setMSL((char*)pMSLCode, nullptr); switch (magicNum) {
_defaultLibrary = new MVKShaderLibrary(_device, _converter); case kMVKMagicNumberSPIRVCode: { // SPIR-V code
break; size_t spvCount = (pCreateInfo->codeSize + 3) >> 2; // Round up if byte length not exactly on uint32_t boundary
}
case kMVKMagicNumberMSLCompiledCode: { // MSL compiled binary code uint64_t startTime = _device->getPerformanceTimestamp();
uintptr_t pMSLCode = uintptr_t(pCreateInfo->pCode) + sizeof(MVKMSLSPIRVHeader); _key = mvkHash(pCreateInfo->pCode, spvCount, _key);
_defaultLibrary = new MVKShaderLibrary(_device, (void*)(pMSLCode), (pCreateInfo->codeSize - sizeof(MVKMSLSPIRVHeader))); _device->addShaderCompilationEventPerformance(_device->_shaderCompilationPerformance.hashShaderCode, startTime);
break;
} _converter.setSPIRV(pCreateInfo->pCode, spvCount);
default:
setConfigurationResult(mvkNotifyErrorWithText(VK_ERROR_FORMAT_NOT_SUPPORTED, "SPIR-V contains invalid magic number %x.", magicNum)); break;
break; }
} case kMVKMagicNumberMSLSourceCode: { // MSL source code
} else { size_t hdrSize = sizeof(MVKMSLSPIRVHeader);
setConfigurationResult(mvkNotifyErrorWithText(VK_INCOMPLETE, "Shader module contains no SPIR-V code.")); char* pMSLCode = (char*)(uintptr_t(pCreateInfo->pCode) + hdrSize);
} size_t mslCodeLen = pCreateInfo->codeSize - hdrSize;
uint64_t startTime = _device->getPerformanceTimestamp();
_key = mvkHash(&magicNum, 1, _key);
_key = mvkHash(pMSLCode, mslCodeLen, _key);
_device->addShaderCompilationEventPerformance(_device->_shaderCompilationPerformance.hashShaderCode, startTime);
_converter.setMSL(pMSLCode, nullptr);
_defaultLibrary = new MVKShaderLibrary(_device, _converter.getMSL().c_str(), _converter.getEntryPoint());
break;
}
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;
uint64_t startTime = _device->getPerformanceTimestamp();
_key = mvkHash(&magicNum, 1, _key);
_key = mvkHash(pMSLCode, mslCodeLen, _key);
_device->addShaderCompilationEventPerformance(_device->_shaderCompilationPerformance.hashShaderCode, startTime);
_defaultLibrary = new MVKShaderLibrary(_device, (void*)(pMSLCode), mslCodeLen);
break;
}
default:
setConfigurationResult(mvkNotifyErrorWithText(VK_ERROR_FORMAT_NOT_SUPPORTED, "SPIR-V contains invalid magic number %x.", magicNum));
break;
}
} }
MVKShaderModule::~MVKShaderModule() { MVKShaderModule::~MVKShaderModule() {
if (_defaultLibrary) { delete _defaultLibrary; } if (_defaultLibrary) { delete _defaultLibrary; }
for (auto& slPair : _shaderLibraries) { delete slPair.second; }
} }

View File

@ -21,10 +21,8 @@
#include "MVKFoundation.h" #include "MVKFoundation.h"
#include <vector> #include <vector>
#include <mach/mach.h>
#include <mach/mach_host.h> #include <mach/mach_host.h>
#include <mach/mach_time.h> #include <mach/mach_time.h>
#include <uuid/uuid.h>
#if MVK_MACOS #if MVK_MACOS
#import <CoreFoundation/CFData.h> #import <CoreFoundation/CFData.h>

View File

@ -207,9 +207,6 @@ namespace mvk {
/** Returns information about the shader entry point. */ /** Returns information about the shader entry point. */
const SPIRVEntryPoint& getEntryPoint() { return _entryPoint; } const SPIRVEntryPoint& getEntryPoint() { return _entryPoint; }
/** Returns a mapping of entry point info, indexed by SPIR-V entry point name. */
// const SPIRVEntryPointsByName& getEntryPoints() { return _entryPoints; }
/** /**
* Returns whether the most recent conversion was successful. * Returns whether the most recent conversion was successful.
* *
@ -228,10 +225,6 @@ namespace mvk {
_msl = msl; _msl = msl;
if (pEntryPoint) { _entryPoint = *pEntryPoint; } if (pEntryPoint) { _entryPoint = *pEntryPoint; }
} }
// void setMSL(const std::string& msl, const SPIRVEntryPointsByName& entryPoints) {
// _msl = msl;
// _entryPoints = entryPoints;
// }
protected: protected:
void logMsg(const char* logMsg); void logMsg(const char* logMsg);
@ -245,7 +238,6 @@ namespace mvk {
std::string _msl; std::string _msl;
std::string _resultLog; std::string _resultLog;
SPIRVEntryPoint _entryPoint; SPIRVEntryPoint _entryPoint;
// SPIRVEntryPointsByName _entryPoints;
bool _wasConverted = false; bool _wasConverted = false;
}; };