diff --git a/MoltenVK/MoltenVK/API/vk_mvk_moltenvk.h b/MoltenVK/MoltenVK/API/vk_mvk_moltenvk.h index 79696a4b..4eedd438 100644 --- a/MoltenVK/MoltenVK/API/vk_mvk_moltenvk.h +++ b/MoltenVK/MoltenVK/API/vk_mvk_moltenvk.h @@ -105,9 +105,11 @@ typedef struct { /** MoltenVK performance of shader compilation events for a VkDevice. */ typedef struct { + MVKShaderCompilationEventPerformance hashShaderCode; /** Create a hash from the incoming shader code. */ MVKShaderCompilationEventPerformance spirvToMSL; /** Convert SPIR-V to MSL source code. */ MVKShaderCompilationEventPerformance mslCompile; /** Compile MSL source 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 functionSpecialization; /** Specialize a retrieved MTLFunction. */ MVKShaderCompilationEventPerformance pipelineCompile; /** Compile MTLFunctions into a pipeline. */ diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandPool.h b/MoltenVK/MoltenVK/Commands/MVKCommandPool.h index aefe6992..845ae2ca 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCommandPool.h +++ b/MoltenVK/MoltenVK/Commands/MVKCommandPool.h @@ -29,7 +29,6 @@ #include "MVKCmdQueries.h" #include "MVKMTLBufferAllocation.h" #include -#include #include #include diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h index 8fbdd599..ca50732c 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h +++ b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h @@ -221,7 +221,7 @@ public: return (MVKPhysicalDevice*)getDispatchableObject(vkPhysicalDevice); } -private: +protected: friend class MVKDevice; MTLFeatureSet getMaximalMTLFeatureSet(); diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm index 7f0c6b70..9c89fb69 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm @@ -1325,22 +1325,24 @@ void MVKDevice::addShaderCompilationEventPerformanceImpl(MVKShaderCompilationEve double currInterval = mvkGetElapsedMilliseconds(startTime, endTime); shaderCompilationEvent.minimumDuration = min(currInterval, shaderCompilationEvent.minimumDuration); shaderCompilationEvent.maximumDuration = max(currInterval, shaderCompilationEvent.maximumDuration); - double totalInverval = (shaderCompilationEvent.averageDuration * shaderCompilationEvent.count++) + currInterval; - shaderCompilationEvent.averageDuration = totalInverval / shaderCompilationEvent.count; + double totalInterval = (shaderCompilationEvent.averageDuration * shaderCompilationEvent.count++) + currInterval; + shaderCompilationEvent.averageDuration = totalInterval / shaderCompilationEvent.count; - MVKLogInfo("%s performance curr: %.3f ms, avg: %.3f ms, min: %.3f ms, max: %.3f ms, count: %d", - getShaderCompilationEventName(shaderCompilationEvent), - currInterval, - shaderCompilationEvent.averageDuration, - shaderCompilationEvent.minimumDuration, - shaderCompilationEvent.maximumDuration, - shaderCompilationEvent.count); + MVKLogDebug("%s performance curr: %.3f ms, avg: %.3f ms, min: %.3f ms, max: %.3f ms, count: %d", + getShaderCompilationEventName(shaderCompilationEvent), + currInterval, + shaderCompilationEvent.averageDuration, + shaderCompilationEvent.minimumDuration, + shaderCompilationEvent.maximumDuration, + shaderCompilationEvent.count); } 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"; } @@ -1464,9 +1466,11 @@ void MVKDevice::initPerformanceTracking() { initPerf.minimumDuration = numeric_limits::max(); initPerf.maximumDuration = 0.0; + _shaderCompilationPerformance.hashShaderCode = initPerf; _shaderCompilationPerformance.spirvToMSL = initPerf; _shaderCompilationPerformance.mslCompile = initPerf; _shaderCompilationPerformance.mslLoad = initPerf; + _shaderCompilationPerformance.shaderLibraryFromCache = initPerf; _shaderCompilationPerformance.functionRetrieval = initPerf; _shaderCompilationPerformance.functionSpecialization = initPerf; _shaderCompilationPerformance.pipelineCompile = initPerf; diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.h b/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.h index 84dd34e3..d7a105a1 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.h +++ b/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.h @@ -71,7 +71,12 @@ public: virtual void encode(MVKCommandEncoder* cmdEncoder) = 0; /** 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 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; } @@ -176,4 +184,10 @@ public: /** Constructs an instance for the specified device. */ MVKPipelineCache(MVKDevice* device, const VkPipelineCacheCreateInfo* pCreateInfo) : MVKBaseDeviceObject(device) {} + ~MVKPipelineCache() override; + +protected: + std::unordered_map _shaderCacheByModuleHash; + std::mutex _shaderCacheLock; + }; diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm b/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm index 7382652e..d9682213 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm @@ -271,13 +271,13 @@ MTLRenderPipelineDescriptor* MVKGraphicsPipeline::getMTLRenderPipelineDescriptor // Vertex shader if (mvkAreFlagsEnabled(pSS->stage, VK_SHADER_STAGE_VERTEX_BIT)) { shaderContext.options.entryPointStage = spv::ExecutionModelVertex; - plDesc.vertexFunction = mvkShdrMod->getMTLFunction(&shaderContext, pSS->pSpecializationInfo).mtlFunction; + plDesc.vertexFunction = mvkShdrMod->getMTLFunction(&shaderContext, pSS->pSpecializationInfo, _pipelineCache).mtlFunction; } // Fragment shader if (mvkAreFlagsEnabled(pSS->stage, VK_SHADER_STAGE_FRAGMENT_BIT)) { 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); MVKShaderModule* mvkShdrMod = (MVKShaderModule*)pSS->module; - return mvkShdrMod->getMTLFunction(&shaderContext, pSS->pSpecializationInfo); + return mvkShdrMod->getMTLFunction(&shaderContext, pSS->pSpecializationInfo, _pipelineCache); } MVKComputePipeline::~MVKComputePipeline() { [_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 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(); +} + + diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKShaderModule.h b/MoltenVK/MoltenVK/GPUObjects/MVKShaderModule.h index a697a275..2ab4e5f7 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKShaderModule.h +++ b/MoltenVK/MoltenVK/GPUObjects/MVKShaderModule.h @@ -25,6 +25,8 @@ #import +class MVKPipelineCache; + using namespace mvk; @@ -47,8 +49,8 @@ public: /** Returns the Metal shader function, possibly specialized. */ MVKMTLFunction getMTLFunction(const VkSpecializationInfo* pSpecializationInfo); - /** Constructs an instance from the MSL source code in the specified SPIRVToMSLConverter. */ - MVKShaderLibrary(MVKDevice* device, SPIRVToMSLConverter& mslConverter); + /** Constructs an instance from the specified MSL source code. */ + MVKShaderLibrary(MVKDevice* device, const char* mslSourceCode, const SPIRVEntryPoint& entryPoint); /** Constructs an instance from the specified compiled MSL code data. */ 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> _shaderLibraries; +}; + + #pragma mark - #pragma mark MVKShaderModule @@ -75,19 +104,32 @@ class MVKShaderModule : public MVKBaseDeviceObject { public: /** Returns the Metal shader function, possibly specialized. */ 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() override; protected: - MVKShaderLibrary* getShaderLibrary(SPIRVToMSLConverterContext* pContext); - MVKShaderLibrary* findShaderLibrary(SPIRVToMSLConverterContext* pContext); - MVKShaderLibrary* addShaderLibrary(SPIRVToMSLConverterContext* pContext); - + MVKShaderLibraryCache _shaderLibraryCache; SPIRVToMSLConverter _converter; MVKShaderLibrary* _defaultLibrary; - std::vector> _shaderLibraries; + std::size_t _key; std::mutex _accessLock; }; diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKShaderModule.mm b/MoltenVK/MoltenVK/GPUObjects/MVKShaderModule.mm index ce9d059d..d36389e2 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKShaderModule.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKShaderModule.mm @@ -17,6 +17,7 @@ */ #include "MVKShaderModule.h" +#include "MVKPipeline.h" #include "MVKFoundation.h" #include "vk_mvk_moltenvk.h" #include @@ -119,19 +120,19 @@ MTLFunctionConstant* MVKShaderLibrary::getFunctionConstant(NSArraygetPerformanceTimestamp(); - @autoreleasepool { - MTLCompileOptions* options = [[MTLCompileOptions new] autorelease]; // TODO: what compile options apply? - NSError* err = nil; - _mtlLibrary = [getMTLDevice() newLibraryWithSource: @(mslConverter.getMSL().data()) - options: options - error: &err]; // retained - handleCompilationError(err, "Shader module compilation"); - } - _device->addShaderCompilationEventPerformance(_device->_shaderCompilationPerformance.mslCompile, startTime); +MVKShaderLibrary::MVKShaderLibrary(MVKDevice* device, const char* 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) + options: options + error: &err]; // retained + handleCompilationError(err, "Shader module compilation"); + } + _device->addShaderCompilationEventPerformance(_device->_shaderCompilationPerformance.mslCompile, startTime); - _entryPoint = mslConverter.getEntryPoint(); + _entryPoint = entryPoint; } MVKShaderLibrary::MVKShaderLibrary(MVKDevice* device, @@ -174,97 +175,150 @@ MVKShaderLibrary::~MVKShaderLibrary() { #pragma mark - -#pragma mark MVKShaderModule - -MVKMTLFunction MVKShaderModule::getMTLFunction(SPIRVToMSLConverterContext* pContext, - const VkSpecializationInfo* pSpecializationInfo) { - lock_guard lock(_accessLock); - MVKShaderLibrary* mvkLib = getShaderLibrary(pContext); - return mvkLib ? mvkLib->getMTLFunction(pSpecializationInfo) : MVKMTLFunctionNull; -} - -MVKShaderLibrary* MVKShaderModule::getShaderLibrary(SPIRVToMSLConverterContext* pContext) { - if (_defaultLibrary) { return _defaultLibrary; } +#pragma mark MVKShaderLibraryCache +MVKShaderLibrary* MVKShaderLibraryCache::getShaderLibrary(SPIRVToMSLConverterContext* pContext, + MVKShaderModule* shaderModule) { MVKShaderLibrary* shLib = findShaderLibrary(pContext); - if ( !shLib ) { shLib = addShaderLibrary(pContext); } -// else { MVKLogDebug("Shader Module %p reusing library.", this); } + if ( !shLib ) { + if (shaderModule->convert(pContext)) { + shLib = addShaderLibrary(pContext, shaderModule->getMSL().c_str(), shaderModule->getEntryPoint()); + } + } return shLib; } // 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. -MVKShaderLibrary* MVKShaderModule::findShaderLibrary(SPIRVToMSLConverterContext* pContext) { - for (auto& slPair : _shaderLibraries) { - if (slPair.first.matches(*pContext)) { - pContext->alignUsageWith(slPair.first); - return slPair.second; - } - } - return NULL; +MVKShaderLibrary* MVKShaderLibraryCache::findShaderLibrary(SPIRVToMSLConverterContext* pContext) { + for (auto& slPair : _shaderLibraries) { + if (slPair.first.matches(*pContext)) { + pContext->alignUsageWith(slPair.first); + return slPair.second; + } + } + return NULL; } /** 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(*pContext, shLib)); + return shLib; +} - MVKShaderLibrary* shLib = nullptr; - bool shouldLogCode = _device->_mvkConfig.debugMode; +MVKShaderLibraryCache::~MVKShaderLibraryCache() { + 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) { - if (shouldLogCode) { MVKLogInfo("%s", _converter.getResultLog().data()); } - shLib = new MVKShaderLibrary(_device, _converter); - _shaderLibraries.push_back(pair(*pContext, shLib)); -// MVKLogDebug("Shader Module %p compiled %d libraries.", this, _shaderLibraries.size()); - } else { - mvkNotifyErrorWithText(VK_ERROR_FORMAT_NOT_SUPPORTED, "Unable to convert SPIR-V to MSL:\n%s", _converter.getResultLog().data()); - } - return shLib; +#pragma mark - +#pragma mark MVKShaderModule + +MVKMTLFunction MVKShaderModule::getMTLFunction(SPIRVToMSLConverterContext* pContext, + const VkSpecializationInfo* pSpecializationInfo, + MVKPipelineCache* pipelineCache) { + lock_guard lock(_accessLock); + MVKShaderLibrary* mvkLib = _defaultLibrary; + 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 MVKShaderModule::MVKShaderModule(MVKDevice* device, - const VkShaderModuleCreateInfo* pCreateInfo) : MVKBaseDeviceObject(device) { + const VkShaderModuleCreateInfo* pCreateInfo) : MVKBaseDeviceObject(device), + _shaderLibraryCache(device) { _defaultLibrary = nullptr; - // Ensure something is there. - if ( (pCreateInfo->pCode != VK_NULL_HANDLE) && (pCreateInfo->codeSize >= 4) ) { + size_t codeSize = pCreateInfo->codeSize; - // 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 - _converter.setSPIRV(pCreateInfo->pCode, spvCount); - break; - } - case kMVKMagicNumberMSLSourceCode: { // MSL source code - uintptr_t pMSLCode = uintptr_t(pCreateInfo->pCode) + sizeof(MVKMSLSPIRVHeader); - _converter.setMSL((char*)pMSLCode, nullptr); - _defaultLibrary = new MVKShaderLibrary(_device, _converter); - break; - } - case kMVKMagicNumberMSLCompiledCode: { // MSL compiled binary code - uintptr_t pMSLCode = uintptr_t(pCreateInfo->pCode) + sizeof(MVKMSLSPIRVHeader); - _defaultLibrary = new MVKShaderLibrary(_device, (void*)(pMSLCode), (pCreateInfo->codeSize - sizeof(MVKMSLSPIRVHeader))); - break; - } - default: - setConfigurationResult(mvkNotifyErrorWithText(VK_ERROR_FORMAT_NOT_SUPPORTED, "SPIR-V contains invalid magic number %x.", magicNum)); - break; - } - } else { - setConfigurationResult(mvkNotifyErrorWithText(VK_INCOMPLETE, "Shader module contains no SPIR-V code.")); - } + // Ensure something is there. + if ( (pCreateInfo->pCode == VK_NULL_HANDLE) || (codeSize < 4) ) { + setConfigurationResult(mvkNotifyErrorWithText(VK_INCOMPLETE, "Shader module contains no SPIR-V code.")); + return; + } + + _key = mvkHash(&pCreateInfo->codeSize, 1); + + // 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 + + uint64_t startTime = _device->getPerformanceTimestamp(); + _key = mvkHash(pCreateInfo->pCode, spvCount, _key); + _device->addShaderCompilationEventPerformance(_device->_shaderCompilationPerformance.hashShaderCode, startTime); + + _converter.setSPIRV(pCreateInfo->pCode, spvCount); + + break; + } + case kMVKMagicNumberMSLSourceCode: { // MSL source 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); + + _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() { if (_defaultLibrary) { delete _defaultLibrary; } - for (auto& slPair : _shaderLibraries) { delete slPair.second; } } diff --git a/MoltenVK/MoltenVK/Utility/MVKOSExtensions.mm b/MoltenVK/MoltenVK/Utility/MVKOSExtensions.mm index 32be385d..5dc981f5 100644 --- a/MoltenVK/MoltenVK/Utility/MVKOSExtensions.mm +++ b/MoltenVK/MoltenVK/Utility/MVKOSExtensions.mm @@ -21,10 +21,8 @@ #include "MVKFoundation.h" #include -#include #include #include -#include #if MVK_MACOS #import diff --git a/MoltenVKShaderConverter/MoltenVKSPIRVToMSLConverter/SPIRVToMSLConverter.h b/MoltenVKShaderConverter/MoltenVKSPIRVToMSLConverter/SPIRVToMSLConverter.h index 3a5118e5..b5c9c67d 100644 --- a/MoltenVKShaderConverter/MoltenVKSPIRVToMSLConverter/SPIRVToMSLConverter.h +++ b/MoltenVKShaderConverter/MoltenVKSPIRVToMSLConverter/SPIRVToMSLConverter.h @@ -207,9 +207,6 @@ namespace mvk { /** Returns information about the shader entry point. */ 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. * @@ -228,10 +225,6 @@ namespace mvk { _msl = msl; if (pEntryPoint) { _entryPoint = *pEntryPoint; } } -// void setMSL(const std::string& msl, const SPIRVEntryPointsByName& entryPoints) { -// _msl = msl; -// _entryPoints = entryPoints; -// } protected: void logMsg(const char* logMsg); @@ -245,7 +238,6 @@ namespace mvk { std::string _msl; std::string _resultLog; SPIRVEntryPoint _entryPoint; -// SPIRVEntryPointsByName _entryPoints; bool _wasConverted = false; };