main sync #3

Merged
Patrick Busch merged 318 commits from blender/blender:main into main 2023-03-17 15:52:21 +01:00
Showing only changes of commit a60626ab0b - Show all commits

View File

@ -621,6 +621,8 @@ void MetalKernelPipeline::compile()
MTLPipelineOption pipelineOptions = MTLPipelineOptionNone; MTLPipelineOption pipelineOptions = MTLPipelineOptionNone;
bool use_binary_archive = should_use_binary_archive(); bool use_binary_archive = should_use_binary_archive();
bool loading_existing_archive = false;
bool creating_new_archive = false;
id<MTLBinaryArchive> archive = nil; id<MTLBinaryArchive> archive = nil;
string metalbin_path; string metalbin_path;
@ -650,42 +652,39 @@ void MetalKernelPipeline::compile()
metalbin_path = path_cache_get(path_join("kernels", metalbin_name)); metalbin_path = path_cache_get(path_join("kernels", metalbin_name));
path_create_directories(metalbin_path); path_create_directories(metalbin_path);
/* Retrieve shader binary from disk, and update the file timestamp for LRU purging to work as /* Check if shader binary exists on disk, and if so, update the file timestamp for LRU purging
* intended. */ * to work as intended. */
if (use_binary_archive && path_cache_kernel_exists_and_mark_used(metalbin_path)) { loading_existing_archive = path_cache_kernel_exists_and_mark_used(metalbin_path);
creating_new_archive = !loading_existing_archive;
if (@available(macOS 11.0, *)) { if (@available(macOS 11.0, *)) {
MTLBinaryArchiveDescriptor *archiveDesc = [[MTLBinaryArchiveDescriptor alloc] init]; MTLBinaryArchiveDescriptor *archiveDesc = [[MTLBinaryArchiveDescriptor alloc] init];
if (loading_existing_archive) {
archiveDesc.url = [NSURL fileURLWithPath:@(metalbin_path.c_str())]; archiveDesc.url = [NSURL fileURLWithPath:@(metalbin_path.c_str())];
archive = [mtlDevice newBinaryArchiveWithDescriptor:archiveDesc error:nil];
[archiveDesc release];
} }
} NSError *error = nil;
} archive = [mtlDevice newBinaryArchiveWithDescriptor:archiveDesc error:&error];
bool creating_new_archive = false;
bool recreate_archive = false;
if (@available(macOS 11.0, *)) {
if (use_binary_archive) {
if (!archive) { if (!archive) {
MTLBinaryArchiveDescriptor *archiveDesc = [[MTLBinaryArchiveDescriptor alloc] init]; const char *err = error ? [[error localizedDescription] UTF8String] : nullptr;
archiveDesc.url = nil; metal_printf("newBinaryArchiveWithDescriptor failed: %s\n", err ? err : "nil");
archive = [mtlDevice newBinaryArchiveWithDescriptor:archiveDesc error:nil];
creating_new_archive = true;
} }
else { [archiveDesc release];
if (loading_existing_archive) {
pipelineOptions = MTLPipelineOptionFailOnBinaryArchiveMiss; pipelineOptions = MTLPipelineOptionFailOnBinaryArchiveMiss;
computePipelineStateDescriptor.binaryArchives = [NSArray arrayWithObjects:archive, nil]; computePipelineStateDescriptor.binaryArchives = [NSArray arrayWithObjects:archive, nil];
} }
} }
} }
bool recreate_archive = false;
/* Lambda to do the actual pipeline compilation. */ /* Lambda to do the actual pipeline compilation. */
auto do_compilation = [&]() { auto do_compilation = [&]() {
__block bool compilation_finished = false; __block bool compilation_finished = false;
__block string error_str; __block string error_str;
if (archive && path_exists(metalbin_path)) { if (loading_existing_archive) {
/* Use the blocking variant of newComputePipelineStateWithDescriptor if an archive exists on /* Use the blocking variant of newComputePipelineStateWithDescriptor if an archive exists on
* disk. It should load almost instantaneously, and will fail gracefully when loading a * disk. It should load almost instantaneously, and will fail gracefully when loading a
* corrupt archive (unlike the async variant). */ * corrupt archive (unlike the async variant). */
@ -698,8 +697,30 @@ void MetalKernelPipeline::compile()
error_str = err ? err : "nil"; error_str = err ? err : "nil";
} }
else { else {
/* TODO / MetalRT workaround:
* Workaround for a crash when addComputePipelineFunctionsWithDescriptor is called *after*
* newComputePipelineStateWithDescriptor with linked functions (i.e. with MetalRT enabled).
* Ideally we would like to call newComputePipelineStateWithDescriptor (async) first so we
* can bail out if needed, but we can stop the crash by flipping the order when there are
* linked functions. However when addComputePipelineFunctionsWithDescriptor is called first
* it will block while it builds the pipeline, offering no way of bailing out. */
auto addComputePipelineFunctionsWithDescriptor = [&]() {
if (creating_new_archive && ShaderCache::running) {
NSError *error;
if (![archive addComputePipelineFunctionsWithDescriptor:computePipelineStateDescriptor
error:&error]) {
NSString *errStr = [error localizedDescription];
metal_printf("Failed to add PSO to archive:\n%s\n",
errStr ? [errStr UTF8String] : "nil");
}
}
};
if (computePipelineStateDescriptor.linkedFunctions) {
addComputePipelineFunctionsWithDescriptor();
}
/* Use the async variant of newComputePipelineStateWithDescriptor if no archive exists on /* Use the async variant of newComputePipelineStateWithDescriptor if no archive exists on
* disk. This allows us responds to app shutdown. */ * disk. This allows us to respond to app shutdown. */
[mtlDevice [mtlDevice
newComputePipelineStateWithDescriptor:computePipelineStateDescriptor newComputePipelineStateWithDescriptor:computePipelineStateDescriptor
options:pipelineOptions options:pipelineOptions
@ -725,21 +746,14 @@ void MetalKernelPipeline::compile()
while (ShaderCache::running && !compilation_finished) { while (ShaderCache::running && !compilation_finished) {
std::this_thread::sleep_for(std::chrono::milliseconds(5)); std::this_thread::sleep_for(std::chrono::milliseconds(5));
} }
/* Add pipeline into the new archive (unless we did it earlier). */
if (pipeline && !computePipelineStateDescriptor.linkedFunctions) {
addComputePipelineFunctionsWithDescriptor();
}
} }
if (creating_new_archive && pipeline && ShaderCache::running) { if (!pipeline) {
/* Add pipeline into the new archive. It should be instantaneous following
* newComputePipelineStateWithDescriptor. */
NSError *error;
computePipelineStateDescriptor.binaryArchives = [NSArray arrayWithObjects:archive, nil];
if (![archive addComputePipelineFunctionsWithDescriptor:computePipelineStateDescriptor
error:&error]) {
NSString *errStr = [error localizedDescription];
metal_printf("Failed to add PSO to archive:\n%s\n", errStr ? [errStr UTF8String] : "nil");
}
}
else if (!pipeline) {
metal_printf( metal_printf(
"newComputePipelineStateWithDescriptor failed for \"%s\"%s. " "newComputePipelineStateWithDescriptor failed for \"%s\"%s. "
"Error:\n%s\n", "Error:\n%s\n",