Add option to dump shaders

This commit is contained in:
Evan Tang 2023-04-24 13:23:23 -05:00
parent d0f066a8fb
commit b420d58b59
6 changed files with 87 additions and 1 deletions

View File

@ -676,3 +676,14 @@ features that are difficult to support otherwise.
Unlike `MVK_USE_METAL_PRIVATE_API`, this setting may be overridden at run time.
This option is not available unless MoltenVK were built with `MVK_USE_METAL_PRIVATE_API` set to `1`.
---------------------------------------
#### MVK_CONFIG_SHADER_DUMP_DIR
##### Type: String
##### Default: `""`
_(The default value is an empty string)._
If not empty, MoltenVK will dump all SPIRV shaders, compiled MSL shaders, and pipeline shader lists to the given directory.
The directory will be non-recursively created if it doesn't already exist.

View File

@ -244,6 +244,7 @@ typedef struct {
VkBool32 shouldMaximizeConcurrentCompilation; /**< MVK_CONFIG_SHOULD_MAXIMIZE_CONCURRENT_COMPILATION */
float timestampPeriodLowPassAlpha; /**< MVK_CONFIG_TIMESTAMP_PERIOD_LOWPASS_ALPHA */
VkBool32 useMetalPrivateAPI; /**< MVK_CONFIG_USE_METAL_PRIVATE_API */
const char* shaderDumpDir; /**< MVK_CONFIG_SHADER_DUMP_DIR */
} MVKConfiguration;
// Legacy support for renamed struct elements.

View File

@ -27,6 +27,7 @@
#include "MTLRenderPipelineColorAttachmentDescriptor+MoltenVK.h"
#endif
#include "mvk_datatypes.hpp"
#include <sys/stat.h>
#ifndef MVK_USE_CEREAL
#define MVK_USE_CEREAL (1)
@ -685,6 +686,34 @@ void MVKGraphicsPipeline::initMTLRenderPipelineState(const VkGraphicsPipelineCre
if (isUsingMetalArgumentBuffers()) { _descriptorBindingUse.resize(_descriptorSetCount); }
if (isUsingPipelineStageMetalArgumentBuffers()) { _mtlArgumentEncoders.resize(_descriptorSetCount); }
const char* dumpDir = getMVKConfig().shaderDumpDir;
if (dumpDir && *dumpDir) {
char filename[PATH_MAX];
char text[1024];
char* ptext = text;
size_t full_hash = 0;
const char* type = pTessCtlSS && pTessEvalSS ? "-tess" : "";
auto addShader = [&](const char* type, const VkPipelineShaderStageCreateInfo* ss) {
if (!ss) {
return;
}
size_t hash = reinterpret_cast<MVKShaderModule*>(ss->module)->getKey().codeHash;
full_hash = full_hash * 33 ^ hash;
ptext = std::min(ptext + snprintf(ptext, std::end(text) - ptext, "%s: %016zx\n", type, hash), std::end(text) - 1);
};
addShader(" VS", pVertexSS);
addShader("TCS", pTessCtlSS);
addShader("TES", pTessEvalSS);
addShader(" FS", pFragmentSS);
mkdir(dumpDir, 0755);
snprintf(filename, sizeof(filename), "%s/pipeline%s-%016zx.txt", dumpDir, type, full_hash);
FILE* file = fopen(filename, "w");
if (file) {
fwrite(text, 1, ptext - text, file);
fclose(file);
}
}
if (!isTessellationPipeline()) {
MTLRenderPipelineDescriptor* plDesc = newMTLRenderPipelineDescriptor(pCreateInfo, reflectData, pVertexSS, pVertexFB, pFragmentSS, pFragmentFB); // temp retain
if (plDesc) {

View File

@ -19,6 +19,7 @@
#include "MVKShaderModule.h"
#include "MVKPipeline.h"
#include "MVKFoundation.h"
#include <sys/stat.h>
using namespace std;
@ -379,6 +380,42 @@ bool MVKShaderModule::convert(SPIRVToMSLConversionConfiguration* pShaderConfig,
bool wasConverted = _spvConverter.convert(*pShaderConfig, conversionResult, shouldLogCode, shouldLogCode, shouldLogEstimatedGLSL);
_device->addPerformanceInterval(_device->_performanceStatistics.shaderCompilation.spirvToMSL, startTime);
const char* dumpDir = getMVKConfig().shaderDumpDir;
if (dumpDir && *dumpDir) {
char path[PATH_MAX];
const char* type;
switch (pShaderConfig->options.entryPointStage) {
case spv::ExecutionModelVertex: type = "-vs"; break;
case spv::ExecutionModelTessellationControl: type = "-tcs"; break;
case spv::ExecutionModelTessellationEvaluation: type = "-tes"; break;
case spv::ExecutionModelFragment: type = "-fs"; break;
case spv::ExecutionModelGeometry: type = "-gs"; break;
case spv::ExecutionModelTaskNV: type = "-ts"; break;
case spv::ExecutionModelMeshNV: type = "-ms"; break;
case spv::ExecutionModelGLCompute: type = "-cs"; break;
default: type = ""; break;
}
mkdir(dumpDir, 0755);
snprintf(path, sizeof(path), "%s/shader%s-%016zx.spv", dumpDir, type, _key.codeHash);
FILE* file = fopen(path, "wb");
if (file) {
fwrite(_spvConverter.getSPIRV().data(), sizeof(uint32_t), _spvConverter.getSPIRV().size(), file);
fclose(file);
}
snprintf(path, sizeof(path), "%s/shader%s-%016zx.metal", dumpDir, type, _key.codeHash);
file = fopen(path, "wb");
if (file) {
if (wasConverted) {
fwrite(conversionResult.msl.data(), 1, conversionResult.msl.size(), file);
fclose(file);
} else {
fputs("Failed to convert:\n", file);
fwrite(conversionResult.resultLog.data(), 1, conversionResult.resultLog.size(), file);
fclose(file);
}
}
}
if (wasConverted) {
if (shouldLogCode) { MVKLogInfo("%s", conversionResult.resultLog.c_str()); }
} else {

View File

@ -83,6 +83,7 @@ MVK_CONFIG_MEMBER(shaderSourceCompressionAlgorithm, MVKConfigCompressionAl
MVK_CONFIG_MEMBER(shouldMaximizeConcurrentCompilation, VkBool32, SHOULD_MAXIMIZE_CONCURRENT_COMPILATION)
MVK_CONFIG_MEMBER(timestampPeriodLowPassAlpha, float, TIMESTAMP_PERIOD_LOWPASS_ALPHA)
MVK_CONFIG_MEMBER(useMetalPrivateAPI, VkBool32, USE_METAL_PRIVATE_API)
MVK_CONFIG_MEMBER_STRING(shaderDumpDir, char*, SHADER_DUMP_DIR)
#undef MVK_CONFIG_MEMBER
#undef MVK_CONFIG_MEMBER_STRING

View File

@ -86,7 +86,7 @@
#ifdef __cplusplus
/** The number of members of MVKConfiguration that are strings. */
static constexpr uint32_t kMVKConfigurationStringCount = 1;
static constexpr uint32_t kMVKConfigurationStringCount = 2;
/** Global function to access MoltenVK configuration info. */
const MVKConfiguration& getGlobalMVKConfig();
@ -357,5 +357,12 @@ void mvkSetConfig(MVKConfiguration& dstMVKConfig, const MVKConfiguration& srcMVK
# define MVK_CONFIG_USE_METAL_PRIVATE_API MVK_USE_METAL_PRIVATE_API
#endif
/**
* If set, MVK will dump spirv input, translated msl, and pipelines into the given directory.
*/
#ifndef MVK_CONFIG_SHADER_DUMP_DIR
# define MVK_CONFIG_SHADER_DUMP_DIR ""
#endif
#undef MVK_CONFIG__UNUSED_STRUCT_PADDING
#define MVK_CONFIG__UNUSED_STRUCT_PADDING 0