From ae47a9b2b841f6f6bbb226b9a98070c25588b53b Mon Sep 17 00:00:00 2001 From: Damien Picard Date: Thu, 23 Feb 2023 19:06:18 +0100 Subject: [PATCH 1/4] Fix #93953: Translation double displayed in panel header After ed870f87b9, panels headers displayed inside panels had their label duplicated when translations were enabled. This is because a string comparison was made against the original message, instead of the translated message. Pull Request: https://projects.blender.org/blender/blender/pulls/105151 --- source/blender/editors/interface/interface_layout.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) 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; } } From d31083583c403ce3246dbbc84cc2429dafd9cca8 Mon Sep 17 00:00:00 2001 From: Jason Fielder Date: Tue, 7 Mar 2023 16:00:23 +0100 Subject: [PATCH 2/4] Fix 105449: Resolve selection in Metal backend MTLFramebuffer's viewport was not correctly updated when updating attachments. Behaviour modified to be consistent with OpenGL. Authored by Apple: Michael Parkin-White Ref #96261 Pull Request: https://projects.blender.org/blender/blender/pulls/105529 --- .../metal/kernels/compute_texture_read.msl | 19 ++++++++-- source/blender/gpu/metal/mtl_framebuffer.mm | 36 ++++++++----------- 2 files changed, 30 insertions(+), 25 deletions(-) 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; } From 8f1136e018cf44cecb9a440ce7a0e83febb2b721 Mon Sep 17 00:00:00 2001 From: Michael Jones Date: Tue, 7 Mar 2023 17:08:30 +0100 Subject: [PATCH 3/4] Cycles: Use async Metal PSO compilation to avoid std::terminate on exit When running unit tests or other fast completing renders, forced crashes can occur if there are any slow, outstanding PSO compilation requests (due to the `std::terminate` fall-back case in `~ShaderCache`). This patch eliminates the need for this shutdown hack by using of the async version of `newComputePipelineStateWithDescriptor` when creating a PSO for the first time. In doing so, we are able to explicitly respond to app shutdown instead of waiting for the pipeline to finish compiling (..and then timing out and force-crashing). We still use the blocking version of `newComputePipelineStateWithDescriptor` when loading from an archive, as this can handle loading from a corrupted archive gracefully. Finally, we move `addComputePipelineFunctionsWithDescriptor` to *after* the PSO is built (as this will trigger a full blocking compile if the PSO has not yet been built, which would bring back the original issue). Pull Request: https://projects.blender.org/blender/blender/pulls/105506 --- intern/cycles/device/metal/kernel.mm | 140 +++++++++++++++++---------- 1 file changed, 90 insertions(+), 50 deletions(-) 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 { From 68e7004e5ec7e490dadb65a472168b651ad82552 Mon Sep 17 00:00:00 2001 From: Sebastian Parborg Date: Tue, 7 Mar 2023 17:33:08 +0100 Subject: [PATCH 4/4] Fix ffmpeg warnings due to missing header include --- intern/ffmpeg/ffmpeg_compat.h | 1 + 1 file changed, 1 insertion(+) diff --git a/intern/ffmpeg/ffmpeg_compat.h b/intern/ffmpeg/ffmpeg_compat.h index f121b400f07..045a3a72cba 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.