diff --git a/intern/cycles/device/metal/kernel.mm b/intern/cycles/device/metal/kernel.mm index fea25172f21..12a2bfe1bb8 100644 --- a/intern/cycles/device/metal/kernel.mm +++ b/intern/cycles/device/metal/kernel.mm @@ -161,25 +161,12 @@ ShaderCache::~ShaderCache() running = false; cond_var.notify_all(); - int num_incomplete = int(incomplete_requests); - if (num_incomplete) { - /* Shutting down the app with incomplete shader compilation requests. Give 1 second's grace for - * clean shutdown. */ - metal_printf("ShaderCache busy (incomplete_requests = %d)...\n", num_incomplete); - std::this_thread::sleep_for(std::chrono::seconds(1)); - num_incomplete = int(incomplete_requests); - } - - if (num_incomplete && !MetalDeviceKernels::is_benchmark_warmup()) { - metal_printf("ShaderCache still busy (incomplete_requests = %d). Terminating...\n", - num_incomplete); - std::terminate(); - } - - metal_printf("ShaderCache idle. Shutting down.\n"); + metal_printf("Waiting for ShaderCache threads... (incomplete_requests = %d)\n", + int(incomplete_requests)); for (auto &thread : compile_threads) { thread.join(); } + metal_printf("ShaderCache shut down.\n"); } void ShaderCache::wait_for_all() @@ -675,7 +662,9 @@ void MetalKernelPipeline::compile() } } - __block bool creating_new_archive = false; + bool creating_new_archive = false; + bool recreate_archive = false; + if (@available(macOS 11.0, *)) { if (use_binary_archive) { if (!archive) { @@ -684,51 +673,101 @@ void MetalKernelPipeline::compile() archive = [mtlDevice newBinaryArchiveWithDescriptor:archiveDesc error:nil]; creating_new_archive = true; } - computePipelineStateDescriptor.binaryArchives = [NSArray arrayWithObjects:archive, nil]; - pipelineOptions = MTLPipelineOptionFailOnBinaryArchiveMiss; + else { + pipelineOptions = MTLPipelineOptionFailOnBinaryArchiveMiss; + computePipelineStateDescriptor.binaryArchives = [NSArray arrayWithObjects:archive, nil]; + } } } + /* Lambda to do the actual pipeline compilation. */ + auto do_compilation = [&]() { + __block bool compilation_finished = false; + __block string error_str; + + if (archive && path_exists(metalbin_path)) { + /* Use the blocking variant of newComputePipelineStateWithDescriptor if an archive exists on + * disk. It should load almost instantaneously, and will fail gracefully when loading a + * corrupt archive (unlike the async variant). */ + NSError *error = nil; + pipeline = [mtlDevice newComputePipelineStateWithDescriptor:computePipelineStateDescriptor + options:pipelineOptions + reflection:nullptr + error:&error]; + const char *err = error ? [[error localizedDescription] UTF8String] : nullptr; + error_str = err ? err : "nil"; + } + else { + /* Use the async variant of newComputePipelineStateWithDescriptor if no archive exists on + * disk. This allows us responds to app shutdown. */ + [mtlDevice + newComputePipelineStateWithDescriptor:computePipelineStateDescriptor + options:pipelineOptions + completionHandler:^(id computePipelineState, + MTLComputePipelineReflection *reflection, + NSError *error) { + pipeline = computePipelineState; + + /* Retain the pipeline so we can use it safely past the completion + * handler. */ + if (pipeline) { + [pipeline retain]; + } + const char *err = error ? + [[error localizedDescription] UTF8String] : + nullptr; + error_str = err ? err : "nil"; + + compilation_finished = true; + }]; + + /* Immediately wait for either the compilation to finish or for app shutdown. */ + while (ShaderCache::running && !compilation_finished) { + std::this_thread::sleep_for(std::chrono::milliseconds(5)); + } + } + + if (creating_new_archive && pipeline && ShaderCache::running) { + /* 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( + "newComputePipelineStateWithDescriptor failed for \"%s\"%s. " + "Error:\n%s\n", + device_kernel_as_string((DeviceKernel)device_kernel), + (archive && !recreate_archive) ? " Archive may be incomplete or corrupt - attempting " + "recreation.." : + "", + error_str.c_str()); + } + }; + double starttime = time_dt(); - /* Block on load to ensure we continue with a valid kernel function */ - if (creating_new_archive) { - starttime = time_dt(); - 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"); - } - } + do_compilation(); - pipeline = [mtlDevice newComputePipelineStateWithDescriptor:computePipelineStateDescriptor - options:pipelineOptions - reflection:nullptr - error:&error]; - - bool recreate_archive = false; + /* An archive might have a corrupt entry and fail to materialize the pipeline. This shouldn't + * happen, but if it does we recreate it. */ if (pipeline == nil && archive) { - NSString *errStr = [error localizedDescription]; - metal_printf( - "Failed to create compute pipeline state \"%s\" from archive - attempting recreation... " - "(error: %s)\n", - device_kernel_as_string((DeviceKernel)device_kernel), - errStr ? [errStr UTF8String] : "nil"); - pipeline = [mtlDevice newComputePipelineStateWithDescriptor:computePipelineStateDescriptor - options:MTLPipelineOptionNone - reflection:nullptr - error:&error]; recreate_archive = true; + pipelineOptions = MTLPipelineOptionNone; + path_remove(metalbin_path); + + do_compilation(); } double duration = time_dt() - starttime; if (pipeline == nil) { - NSString *errStr = [error localizedDescription]; - error_str = string_printf("Failed to create compute pipeline state \"%s\", error: \n", - device_kernel_as_string((DeviceKernel)device_kernel)); - error_str += (errStr ? [errStr UTF8String] : "nil"); metal_printf("%16s | %2d | %-55s | %7.2fs | FAILED!\n", kernel_type_as_string(pso_type), device_kernel, @@ -748,7 +787,8 @@ void MetalKernelPipeline::compile() if (creating_new_archive || recreate_archive) { if (![archive serializeToURL:[NSURL fileURLWithPath:@(metalbin_path.c_str())] error:&error]) { - metal_printf("Failed to save binary archive, error:\n%s\n", + metal_printf("Failed to save binary archive to %s, error:\n%s\n", + metalbin_path.c_str(), [[error localizedDescription] UTF8String]); } else { diff --git a/intern/ffmpeg/ffmpeg_compat.h b/intern/ffmpeg/ffmpeg_compat.h index d32cc5bb015..a8254a99032 100644 --- a/intern/ffmpeg/ffmpeg_compat.h +++ b/intern/ffmpeg/ffmpeg_compat.h @@ -13,6 +13,7 @@ #ifndef __FFMPEG_COMPAT_H__ #define __FFMPEG_COMPAT_H__ +#include #include /* Check if our ffmpeg is new enough, avoids user complaints. diff --git a/source/blender/editors/interface/interface_layout.cc b/source/blender/editors/interface/interface_layout.cc index c2a78686608..a377c896465 100644 --- a/source/blender/editors/interface/interface_layout.cc +++ b/source/blender/editors/interface/interface_layout.cc @@ -5912,7 +5912,8 @@ static bool ui_layout_has_panel_label(const uiLayout *layout, const PanelType *p LISTBASE_FOREACH (uiItem *, subitem, &layout->items) { if (subitem->type == ITEM_BUTTON) { uiButtonItem *bitem = (uiButtonItem *)subitem; - if (!(bitem->but->flag & UI_HIDDEN) && STREQ(bitem->but->str, pt->label)) { + if (!(bitem->but->flag & UI_HIDDEN) && + STREQ(bitem->but->str, CTX_IFACE_(pt->translation_context, pt->label))) { return true; } } diff --git a/source/blender/gpu/metal/kernels/compute_texture_read.msl b/source/blender/gpu/metal/kernels/compute_texture_read.msl index 41d7b312dbd..6c099024f7a 100644 --- a/source/blender/gpu/metal/kernels/compute_texture_read.msl +++ b/source/blender/gpu/metal/kernels/compute_texture_read.msl @@ -62,11 +62,24 @@ template<> uint denormalize(float val) return uint(float(DEPTH_SCALE_FACTOR) * val); } +/* Float to other type case. */ template T convert_type(float type) { return T(type); } +/* Uint to other types. */ +template T convert_type(uint type) +{ + return T(type); +} + +/* Int to other types. */ +template T convert_type(int type) +{ + return T(type); +} + template<> uchar convert_type(float val) { return uchar(val * float(0xFF)); @@ -141,8 +154,8 @@ kernel void compute_texture_read(constant TextureReadParams ¶ms [[buffer(0)] uint xx = position[0]; uint yy = position[1]; uint zz = position[2]; - int index = (zz * (params.extent[0] * params.extent[1]) + yy * params.extnt[0] + xx) * - COMPONENT_COUNT_INPUT; + int index = (zz * (params.extent[0] * params.extent[1]) + yy * params.extent[0] + xx) * + COMPONENT_COUNT_OUTPUT; read_colour = read_tex.read(uint3(params.offset[0], params.offset[1], params.offset[2]) + uint3(xx, yy, zz)); @@ -163,7 +176,7 @@ kernel void compute_texture_read(constant TextureReadParams ¶ms [[buffer(0)] uint yy = position[1]; uint layer = position[2]; int index = (layer * (params.extent[0] * params.extent[1]) + yy * params.extent[0] + xx) * - COMPONENT_COUNT_INPUT; + COMPONENT_COUNT_OUTPUT; /* Read data */ # if IS_DEPTH_FORMAT == 1 diff --git a/source/blender/gpu/metal/mtl_framebuffer.mm b/source/blender/gpu/metal/mtl_framebuffer.mm index 5e3a4136d88..86b7601a3cc 100644 --- a/source/blender/gpu/metal/mtl_framebuffer.mm +++ b/source/blender/gpu/metal/mtl_framebuffer.mm @@ -606,17 +606,6 @@ void MTLFrameBuffer::update_attachments(bool update_viewport) if (!dirty_attachments_) { return; } - - /* Cache viewport and scissor (If we have existing attachments). */ - int t_viewport[4], t_scissor[4]; - update_viewport = update_viewport && - (this->get_attachment_count() > 0 && this->has_depth_attachment() && - this->has_stencil_attachment()); - if (update_viewport) { - this->viewport_get(t_viewport); - this->scissor_get(t_scissor); - } - /* Clear current attachments state. */ this->remove_all_attachments(); @@ -738,22 +727,25 @@ void MTLFrameBuffer::update_attachments(bool update_viewport) } } - /* Check whether the first attachment is SRGB. */ + /* Extract attachment size and determine if framebuffer is SRGB. */ if (first_attachment != GPU_FB_MAX_ATTACHMENT) { - srgb_ = (first_attachment_mtl.texture->format_get() == GPU_SRGB8_A8); - } - - /* Reset viewport and Scissor (If viewport is smaller or equal to the framebuffer size). */ - if (update_viewport && t_viewport[2] <= width_ && t_viewport[3] <= height_) { - - this->viewport_set(t_viewport); - this->scissor_set(t_viewport); + /* Ensure size is correctly assigned. */ + GPUAttachment &attach = attachments_[first_attachment]; + int size[3]; + GPU_texture_get_mipmap_size(attach.tex, attach.mip, size); + this->size_set(size[0], size[1]); + srgb_ = (GPU_texture_format(attach.tex) == GPU_SRGB8_A8); } else { - this->viewport_reset(); - this->scissor_reset(); + /* Empty frame-buffer. */ + width_ = 0; + height_ = 0; } + /* Reset viewport and Scissor. */ + this->viewport_reset(); + this->scissor_reset(); + /* We have now updated our internal structures. */ dirty_attachments_ = false; }