From 4ce1db591511b2d4d261208c4b636686e8d5cd6e Mon Sep 17 00:00:00 2001 From: jonahwilliams Date: Fri, 17 Nov 2023 14:25:40 -0800 Subject: [PATCH 01/14] [Impeller] dont blit onto wide gamut surface. --- impeller/entity/entity_pass.cc | 16 +++++-- impeller/renderer/BUILD.gn | 1 + impeller/renderer/blit_pass.cc | 11 +++++ impeller/renderer/blit_pass_unittests.cc | 61 ++++++++++++++++++++++++ 4 files changed, 85 insertions(+), 4 deletions(-) create mode 100644 impeller/renderer/blit_pass_unittests.cc diff --git a/impeller/entity/entity_pass.cc b/impeller/entity/entity_pass.cc index f938f560e55de..aabcfd1b91238 100644 --- a/impeller/entity/entity_pass.cc +++ b/impeller/entity/entity_pass.cc @@ -360,12 +360,20 @@ bool EntityPass::Render(ContentContext& renderer, auto command_buffer = renderer.GetContext()->CreateCommandBuffer(); command_buffer->SetLabel("EntityPass Root Command Buffer"); - // If the context supports blitting, blit the offscreen texture to the - // onscreen texture. Otherwise, draw it to the parent texture using a - // pipeline (slower). + // If the context supports blitting and the pixel formats are identical, + // blit the offscreen texture to the onscreen texture. Otherwise, draw it to + // the parent texture using a pipeline (slower). + auto src_format = offscreen_target.GetRenderTarget() + .GetRenderTargetTexture() + ->GetTextureDescriptor() + .format; + auto dst_format = root_render_target.GetRenderTargetTexture() + ->GetTextureDescriptor() + .format; if (renderer.GetContext() ->GetCapabilities() - ->SupportsTextureToTextureBlits()) { + ->SupportsTextureToTextureBlits() && + src_format == dst_format) { auto blit_pass = command_buffer->CreateBlitPass(); blit_pass->AddCopy( offscreen_target.GetRenderTarget().GetRenderTargetTexture(), diff --git a/impeller/renderer/BUILD.gn b/impeller/renderer/BUILD.gn index 22a42063ac196..a04ecd5e7ab0e 100644 --- a/impeller/renderer/BUILD.gn +++ b/impeller/renderer/BUILD.gn @@ -122,6 +122,7 @@ impeller_component("renderer_unittests") { testonly = true sources = [ + "blit_pass_unittests.cc", "capabilities_unittests.cc", "device_buffer_unittests.cc", "host_buffer_unittests.cc", diff --git a/impeller/renderer/blit_pass.cc b/impeller/renderer/blit_pass.cc index b8644d1dcc788..d9441f6b85127 100644 --- a/impeller/renderer/blit_pass.cc +++ b/impeller/renderer/blit_pass.cc @@ -8,6 +8,7 @@ #include "impeller/base/strings.h" #include "impeller/base/validation.h" +#include "impeller/core/formats.h" #include "impeller/core/host_buffer.h" #include "impeller/renderer/blit_command.h" @@ -52,6 +53,16 @@ bool BlitPass::AddCopy(std::shared_ptr source, static_cast(destination->GetTextureDescriptor().sample_count)); return false; } + if (source->GetTextureDescriptor().format != + destination->GetTextureDescriptor().format) { + VALIDATION_LOG << SPrintF( + "The source pixel format (%s) must match the destination pixel format " + "(%s) " + "for blits.", + PixelFormatToString(source->GetTextureDescriptor().format), + PixelFormatToString(destination->GetTextureDescriptor().format)); + return false; + } if (!source_region.has_value()) { source_region = IRect::MakeSize(source->GetSize()); diff --git a/impeller/renderer/blit_pass_unittests.cc b/impeller/renderer/blit_pass_unittests.cc new file mode 100644 index 0000000000000..4ff5906e2cca4 --- /dev/null +++ b/impeller/renderer/blit_pass_unittests.cc @@ -0,0 +1,61 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "gtest/gtest.h" +#include "impeller/base/validation.h" +#include "impeller/core/formats.h" +#include "impeller/core/texture_descriptor.h" +#include "impeller/playground/playground_test.h" +#include "impeller/renderer/command_buffer.h" + +// TODO(zanderso): https://github.com/flutter/flutter/issues/127701 +// NOLINTBEGIN(bugprone-unchecked-optional-access) + +namespace impeller { +namespace testing { + +using BlitPassTest = PlaygroundTest; +INSTANTIATE_PLAYGROUND_SUITE(BlitPassTest); + +TEST_P(BlitPassTest, BlitAcrossDifferentPixelFormatsFails) { + ScopedValidationDisable scope; // avoid noise in output. + auto context = GetContext(); + auto cmd_buffer = context->CreateCommandBuffer(); + auto blit_pass = cmd_buffer->CreateBlitPass(); + + TextureDescriptor src_desc; + src_desc.format = PixelFormat::kA8UNormInt; + src_desc.size = {100, 100}; + auto src = context->GetResourceAllocator()->CreateTexture(src_desc); + + TextureDescriptor dst_format; + dst_format.format = PixelFormat::kR8G8B8A8UNormInt; + dst_format.size = {100, 100}; + auto dst = context->GetResourceAllocator()->CreateTexture(dst_format); + + EXPECT_FALSE(blit_pass->AddCopy(src, dst)); +} + +TEST_P(BlitPassTest, BlitAcrossDifferentSampleCountsFails) { + ScopedValidationDisable scope; // avoid noise in output. + auto context = GetContext(); + auto cmd_buffer = context->CreateCommandBuffer(); + auto blit_pass = cmd_buffer->CreateBlitPass(); + + TextureDescriptor src_desc; + src_desc.format = PixelFormat::kR8G8B8A8UNormInt; + src_desc.sample_count = SampleCount::kCount4; + src_desc.size = {100, 100}; + auto src = context->GetResourceAllocator()->CreateTexture(src_desc); + + TextureDescriptor dst_format; + dst_format.format = PixelFormat::kR8G8B8A8UNormInt; + dst_format.size = {100, 100}; + auto dst = context->GetResourceAllocator()->CreateTexture(dst_format); + + EXPECT_FALSE(blit_pass->AddCopy(src, dst)); +} + +} // namespace testing +} // namespace impeller From 55272b42d55349891347cb42587bbfc28c79da72 Mon Sep 17 00:00:00 2001 From: jonahwilliams Date: Fri, 17 Nov 2023 14:56:43 -0800 Subject: [PATCH 02/14] add excluded file. --- ci/licenses_golden/excluded_files | 1 + 1 file changed, 1 insertion(+) diff --git a/ci/licenses_golden/excluded_files b/ci/licenses_golden/excluded_files index 3970d9479b543..a0ffd30fbe3bf 100644 --- a/ci/licenses_golden/excluded_files +++ b/ci/licenses_golden/excluded_files @@ -176,6 +176,7 @@ ../../../flutter/impeller/renderer/backend/vulkan/pass_bindings_cache_unittests.cc ../../../flutter/impeller/renderer/backend/vulkan/resource_manager_vk_unittests.cc ../../../flutter/impeller/renderer/backend/vulkan/test +../../../flutter/impeller/renderer/blit_pass_unittests.cc ../../../flutter/impeller/renderer/capabilities_unittests.cc ../../../flutter/impeller/renderer/compute_subgroup_unittests.cc ../../../flutter/impeller/renderer/compute_unittests.cc From 5beac1ed2c483f3eb8e37d17f3f371941f0737af Mon Sep 17 00:00:00 2001 From: jonahwilliams Date: Fri, 17 Nov 2023 18:12:51 -0800 Subject: [PATCH 03/14] overlay views should have same pixel format as original view. --- impeller/entity/entity_pass.cc | 16 ++------ impeller/renderer/backend/metal/context_mtl.h | 2 +- .../renderer/backend/metal/context_mtl.mm | 1 + .../ios/framework/Source/FlutterOverlayView.h | 5 ++- .../framework/Source/FlutterOverlayView.mm | 26 ++++++++++-- .../framework/Source/FlutterPlatformViews.mm | 40 ++++++++++++------- .../Source/FlutterPlatformViews_Internal.h | 7 +++- .../darwin/ios/framework/Source/FlutterView.h | 2 + .../ios/framework/Source/FlutterView.mm | 14 ++++++- 9 files changed, 77 insertions(+), 36 deletions(-) diff --git a/impeller/entity/entity_pass.cc b/impeller/entity/entity_pass.cc index aabcfd1b91238..f938f560e55de 100644 --- a/impeller/entity/entity_pass.cc +++ b/impeller/entity/entity_pass.cc @@ -360,20 +360,12 @@ bool EntityPass::Render(ContentContext& renderer, auto command_buffer = renderer.GetContext()->CreateCommandBuffer(); command_buffer->SetLabel("EntityPass Root Command Buffer"); - // If the context supports blitting and the pixel formats are identical, - // blit the offscreen texture to the onscreen texture. Otherwise, draw it to - // the parent texture using a pipeline (slower). - auto src_format = offscreen_target.GetRenderTarget() - .GetRenderTargetTexture() - ->GetTextureDescriptor() - .format; - auto dst_format = root_render_target.GetRenderTargetTexture() - ->GetTextureDescriptor() - .format; + // If the context supports blitting, blit the offscreen texture to the + // onscreen texture. Otherwise, draw it to the parent texture using a + // pipeline (slower). if (renderer.GetContext() ->GetCapabilities() - ->SupportsTextureToTextureBlits() && - src_format == dst_format) { + ->SupportsTextureToTextureBlits()) { auto blit_pass = command_buffer->CreateBlitPass(); blit_pass->AddCopy( offscreen_target.GetRenderTarget().GetRenderTargetTexture(), diff --git a/impeller/renderer/backend/metal/context_mtl.h b/impeller/renderer/backend/metal/context_mtl.h index 02997d6670b00..aa22ff491d14b 100644 --- a/impeller/renderer/backend/metal/context_mtl.h +++ b/impeller/renderer/backend/metal/context_mtl.h @@ -104,7 +104,7 @@ class ContextMTL final : public Context, private: class SyncSwitchObserver : public fml::SyncSwitch::Observer { public: - SyncSwitchObserver(ContextMTL& parent); + explicit SyncSwitchObserver(ContextMTL& parent); virtual ~SyncSwitchObserver() = default; void OnSyncSwitchUpdate(bool new_value) override; diff --git a/impeller/renderer/backend/metal/context_mtl.mm b/impeller/renderer/backend/metal/context_mtl.mm index 9373d3e3a7b35..2e5244b3acb96 100644 --- a/impeller/renderer/backend/metal/context_mtl.mm +++ b/impeller/renderer/backend/metal/context_mtl.mm @@ -12,6 +12,7 @@ #include "flutter/fml/logging.h" #include "flutter/fml/paths.h" #include "flutter/fml/synchronization/sync_switch.h" +#include "impeller/core/formats.h" #include "impeller/core/sampler_descriptor.h" #include "impeller/renderer/backend/metal/gpu_tracer_mtl.h" #include "impeller/renderer/backend/metal/sampler_library_mtl.h" diff --git a/shell/platform/darwin/ios/framework/Source/FlutterOverlayView.h b/shell/platform/darwin/ios/framework/Source/FlutterOverlayView.h index e21d5635dc82e..fa1e9cb9a8d7b 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterOverlayView.h +++ b/shell/platform/darwin/ios/framework/Source/FlutterOverlayView.h @@ -5,6 +5,7 @@ #ifndef SHELL_PLATFORM_IOS_FRAMEWORK_SOURCE_FLUTTER_OVERLAY_VIEW_H_ #define SHELL_PLATFORM_IOS_FRAMEWORK_SOURCE_FLUTTER_OVERLAY_VIEW_H_ +#include #include #include @@ -31,8 +32,8 @@ - (instancetype)initWithFrame:(CGRect)frame NS_UNAVAILABLE; - (instancetype)initWithCoder:(NSCoder*)aDecoder NS_UNAVAILABLE; -- (instancetype)init NS_DESIGNATED_INITIALIZER; -- (instancetype)initWithContentsScale:(CGFloat)contentsScale; +- (instancetype)init:(MTLPixelFormat)pixelFormat NS_DESIGNATED_INITIALIZER; +- (instancetype)initWithContentsScale:(CGFloat)contentsScale pixelFormat:(MTLPixelFormat)pixelFormat; @end diff --git a/shell/platform/darwin/ios/framework/Source/FlutterOverlayView.mm b/shell/platform/darwin/ios/framework/Source/FlutterOverlayView.mm index 490efaf5162a1..b5ed05b853868 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterOverlayView.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterOverlayView.mm @@ -3,6 +3,7 @@ // found in the LICENSE file. #import "flutter/shell/platform/darwin/ios/framework/Source/FlutterOverlayView.h" +#include #include "flutter/common/settings.h" #include "flutter/common/task_runners.h" @@ -30,25 +31,44 @@ - (instancetype)initWithCoder:(NSCoder*)aDecoder { return nil; } -- (instancetype)init { +- (instancetype)init:(MTLPixelFormat)pixelFormat { self = [super initWithFrame:CGRectZero]; if (self) { self.layer.opaque = NO; self.userInteractionEnabled = NO; self.autoresizingMask = (UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight); +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunguarded-availability-new" + CAMetalLayer* layer = (CAMetalLayer*)self.layer; +#pragma clang diagnostic pop + layer.pixelFormat = pixelFormat; + if (pixelFormat == MTLPixelFormatRGBA16Float) { + CGColorSpaceRef srgb = CGColorSpaceCreateWithName(kCGColorSpaceExtendedSRGB); + layer.colorspace = srgb; + } } return self; } -- (instancetype)initWithContentsScale:(CGFloat)contentsScale { - self = [self init]; +- (instancetype)initWithContentsScale:(CGFloat)contentsScale + pixelFormat:(MTLPixelFormat)pixelFormat { + self = [self init:pixelFormat]; if ([self.layer isKindOfClass:NSClassFromString(@"CAMetalLayer")]) { self.layer.allowsGroupOpacity = NO; self.layer.contentsScale = contentsScale; self.layer.rasterizationScale = contentsScale; +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunguarded-availability-new" + CAMetalLayer* layer = (CAMetalLayer*)self.layer; +#pragma clang diagnostic pop + layer.pixelFormat = pixelFormat; + if (pixelFormat == MTLPixelFormatRGBA16Float) { + CGColorSpaceRef srgb = CGColorSpaceCreateWithName(kCGColorSpaceExtendedSRGB); + layer.colorspace = srgb; + } } return self; diff --git a/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews.mm b/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews.mm index da76b2e107eaa..79e3d4312155f 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews.mm @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include #import #include @@ -14,6 +15,7 @@ #import "flutter/shell/platform/darwin/common/framework/Headers/FlutterChannels.h" #import "flutter/shell/platform/darwin/ios/framework/Source/FlutterOverlayView.h" #import "flutter/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.h" +#import "flutter/shell/platform/darwin/ios/framework/Source/FlutterView.h" #import "flutter/shell/platform/darwin/ios/framework/Source/FlutterViewController_Internal.h" #import "flutter/shell/platform/darwin/ios/ios_surface.h" @@ -85,15 +87,19 @@ static bool ClipRRectContainsPlatformViewBoundingRect(const SkRRect& clip_rrect, std::shared_ptr FlutterPlatformViewLayerPool::GetLayer( GrDirectContext* gr_context, - const std::shared_ptr& ios_context) { + const std::shared_ptr& ios_context, + MTLPixelFormat pixel_format) { if (available_layer_index_ >= layers_.size()) { std::shared_ptr layer; fml::scoped_nsobject overlay_view; fml::scoped_nsobject overlay_view_wrapper; if (!gr_context) { - overlay_view.reset([[FlutterOverlayView alloc] init]); - overlay_view_wrapper.reset([[FlutterOverlayView alloc] init]); + CGFloat screenScale = [UIScreen mainScreen].scale; + overlay_view.reset([[FlutterOverlayView alloc] initWithContentsScale:screenScale + pixelFormat:pixel_format]); + overlay_view_wrapper.reset([[FlutterOverlayView alloc] initWithContentsScale:screenScale + pixelFormat:pixel_format]); auto ca_layer = fml::scoped_nsobject{[[overlay_view.get() layer] retain]}; std::unique_ptr ios_surface = IOSSurface::Create(ios_context, ca_layer); @@ -104,8 +110,10 @@ static bool ClipRRectContainsPlatformViewBoundingRect(const SkRRect& clip_rrect, std::move(surface)); } else { CGFloat screenScale = [UIScreen mainScreen].scale; - overlay_view.reset([[FlutterOverlayView alloc] initWithContentsScale:screenScale]); - overlay_view_wrapper.reset([[FlutterOverlayView alloc] initWithContentsScale:screenScale]); + overlay_view.reset([[FlutterOverlayView alloc] initWithContentsScale:screenScale + pixelFormat:pixel_format]); + overlay_view_wrapper.reset([[FlutterOverlayView alloc] initWithContentsScale:screenScale + pixelFormat:pixel_format]); auto ca_layer = fml::scoped_nsobject{[[overlay_view.get() layer] retain]}; std::unique_ptr ios_surface = IOSSurface::Create(ios_context, ca_layer); @@ -735,13 +743,15 @@ static bool ClipRRectContainsPlatformViewBoundingRect(const SkRRect& clip_rrect, // on the overlay layer. background_canvas->ClipRect(joined_rect, DlCanvas::ClipOp::kDifference); // Get a new host layer. - std::shared_ptr layer = GetLayer(gr_context, // - ios_context, // - slice, // - joined_rect, // - current_platform_view_id, // - overlay_id // - ); + std::shared_ptr layer = + GetLayer(gr_context, // + ios_context, // + slice, // + joined_rect, // + current_platform_view_id, // + overlay_id, // + ((FlutterView*)flutter_view_.get()).pixelFormat // + ); did_submit &= layer->did_submit_last_frame; platform_view_layers[current_platform_view_id].push_back(layer); overlay_id++; @@ -811,9 +821,11 @@ static bool ClipRRectContainsPlatformViewBoundingRect(const SkRRect& clip_rrect, EmbedderViewSlice* slice, SkRect rect, int64_t view_id, - int64_t overlay_id) { + int64_t overlay_id, + MTLPixelFormat pixel_format) { FML_DCHECK(flutter_view_); - std::shared_ptr layer = layer_pool_->GetLayer(gr_context, ios_context); + std::shared_ptr layer = + layer_pool_->GetLayer(gr_context, ios_context, pixel_format); UIView* overlay_view_wrapper = layer->overlay_view_wrapper.get(); auto screenScale = [UIScreen mainScreen].scale; diff --git a/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.h b/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.h index e18569868115f..5e30f57eff151 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.h +++ b/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.h @@ -5,6 +5,7 @@ #ifndef FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_SOURCE_FLUTTERPLATFORMVIEWS_INTERNAL_H_ #define FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_SOURCE_FLUTTERPLATFORMVIEWS_INTERNAL_H_ +#include #include "flutter/flow/embedded_views.h" #include "flutter/fml/platform/darwin/scoped_nsobject.h" #include "flutter/shell/common/shell.h" @@ -169,7 +170,8 @@ class FlutterPlatformViewLayerPool { // Finally, it marks the layer as used. That is, it increments `available_layer_index_`. std::shared_ptr GetLayer( GrDirectContext* gr_context, - const std::shared_ptr& ios_context); + const std::shared_ptr& ios_context, + MTLPixelFormat pixel_format); // Gets the layers in the pool that aren't currently used. // This method doesn't mark the layers as unused. @@ -320,7 +322,8 @@ class FlutterPlatformViewsController { EmbedderViewSlice* slice, SkRect rect, int64_t view_id, - int64_t overlay_id); + int64_t overlay_id, + MTLPixelFormat pixel_format); // Removes overlay views and platform views that aren't needed in the current frame. // Must run on the platform thread. void RemoveUnusedLayers(); diff --git a/shell/platform/darwin/ios/framework/Source/FlutterView.h b/shell/platform/darwin/ios/framework/Source/FlutterView.h index daebc0df5314c..6337580c6887f 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterView.h +++ b/shell/platform/darwin/ios/framework/Source/FlutterView.h @@ -5,6 +5,7 @@ #ifndef SHELL_PLATFORM_IOS_FRAMEWORK_SOURCE_FLUTTER_VIEW_H_ #define SHELL_PLATFORM_IOS_FRAMEWORK_SOURCE_FLUTTER_VIEW_H_ +#include #import #include @@ -47,6 +48,7 @@ enableWideGamut:(BOOL)isWideGamutEnabled NS_DESIGNATED_INITIALIZER; - (UIScreen*)screen; +- (MTLPixelFormat)pixelFormat; // Set by FlutterEngine or FlutterViewController to override software rendering. @property(class, nonatomic) BOOL forceSoftwareRendering; diff --git a/shell/platform/darwin/ios/framework/Source/FlutterView.mm b/shell/platform/darwin/ios/framework/Source/FlutterView.mm index dfb25224e0e2a..cb6f18fd33218 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterView.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterView.mm @@ -3,6 +3,7 @@ // found in the LICENSE file. #import "flutter/shell/platform/darwin/ios/framework/Source/FlutterView.h" +#include #include "flutter/common/settings.h" #include "flutter/common/task_runners.h" @@ -19,6 +20,7 @@ @implementation FlutterView { id _delegate; BOOL _isWideGamutEnabled; + MTLPixelFormat _pixelFormat; } - (instancetype)init { @@ -43,6 +45,10 @@ - (UIScreen*)screen { return UIScreen.mainScreen; } +- (MTLPixelFormat)pixelFormat { + return _pixelFormat; +} + - (BOOL)isWideGamutSupported { if (![_delegate isUsingImpeller]) { return NO; @@ -115,8 +121,12 @@ - (void)layoutSubviews { // F16 was chosen over BGRA10_XR since Skia does not support decoding // BGRA10_XR. layer.pixelFormat = MTLPixelFormatRGBA16Float; - } else if (_isWideGamutEnabled && !isWideGamutSupported) { - PrintWideGamutWarningOnce(); + _pixelFormat = MTLPixelFormatRGBA16Float; + } else { + if (_isWideGamutEnabled && !isWideGamutSupported) { + PrintWideGamutWarningOnce(); + } + _pixelFormat = layer.pixelFormat; } } From 4d2a2093a293ce21fc3358b6f959db4343ececb5 Mon Sep 17 00:00:00 2001 From: jonahwilliams Date: Fri, 17 Nov 2023 18:14:26 -0800 Subject: [PATCH 04/14] ++ --- .../darwin/ios/framework/Source/FlutterOverlayView.h | 3 ++- .../ios/framework/Source/FlutterPlatformViews_Internal.h | 7 +++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/shell/platform/darwin/ios/framework/Source/FlutterOverlayView.h b/shell/platform/darwin/ios/framework/Source/FlutterOverlayView.h index fa1e9cb9a8d7b..2d5926c36f675 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterOverlayView.h +++ b/shell/platform/darwin/ios/framework/Source/FlutterOverlayView.h @@ -33,7 +33,8 @@ - (instancetype)initWithCoder:(NSCoder*)aDecoder NS_UNAVAILABLE; - (instancetype)init:(MTLPixelFormat)pixelFormat NS_DESIGNATED_INITIALIZER; -- (instancetype)initWithContentsScale:(CGFloat)contentsScale pixelFormat:(MTLPixelFormat)pixelFormat; +- (instancetype)initWithContentsScale:(CGFloat)contentsScale + pixelFormat:(MTLPixelFormat)pixelFormat; @end diff --git a/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.h b/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.h index 5e30f57eff151..45145cbc38a31 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.h +++ b/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.h @@ -168,10 +168,9 @@ class FlutterPlatformViewLayerPool { // Gets a layer from the pool if available, or allocates a new one. // Finally, it marks the layer as used. That is, it increments `available_layer_index_`. - std::shared_ptr GetLayer( - GrDirectContext* gr_context, - const std::shared_ptr& ios_context, - MTLPixelFormat pixel_format); + std::shared_ptr GetLayer(GrDirectContext* gr_context, + const std::shared_ptr& ios_context, + MTLPixelFormat pixel_format); // Gets the layers in the pool that aren't currently used. // This method doesn't mark the layers as unused. From 98c7c7ec75bbb60f8f5a92b4ced6bb73cb532feb Mon Sep 17 00:00:00 2001 From: jonahwilliams Date: Sat, 18 Nov 2023 08:54:57 -0800 Subject: [PATCH 05/14] ++ --- .../darwin/ios/framework/Source/FlutterPlatformViews.mm | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews.mm b/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews.mm index 79e3d4312155f..705bd5d6b9c5f 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews.mm @@ -96,10 +96,8 @@ static bool ClipRRectContainsPlatformViewBoundingRect(const SkRRect& clip_rrect, if (!gr_context) { CGFloat screenScale = [UIScreen mainScreen].scale; - overlay_view.reset([[FlutterOverlayView alloc] initWithContentsScale:screenScale - pixelFormat:pixel_format]); - overlay_view_wrapper.reset([[FlutterOverlayView alloc] initWithContentsScale:screenScale - pixelFormat:pixel_format]); + overlay_view.reset([[FlutterOverlayView alloc] init pixelFormat:pixel_format]); + overlay_view_wrapper.reset([[FlutterOverlayView alloc] init pixelFormat:pixel_format]); auto ca_layer = fml::scoped_nsobject{[[overlay_view.get() layer] retain]}; std::unique_ptr ios_surface = IOSSurface::Create(ios_context, ca_layer); From f63e4d5fbfd729ee40f2b317d00ecaa854b2ef6b Mon Sep 17 00:00:00 2001 From: Jonah Williams Date: Sat, 18 Nov 2023 09:05:08 -0800 Subject: [PATCH 06/14] Update FlutterPlatformViews.mm --- .../darwin/ios/framework/Source/FlutterPlatformViews.mm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews.mm b/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews.mm index 705bd5d6b9c5f..fa7831696e84d 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews.mm @@ -96,8 +96,8 @@ static bool ClipRRectContainsPlatformViewBoundingRect(const SkRRect& clip_rrect, if (!gr_context) { CGFloat screenScale = [UIScreen mainScreen].scale; - overlay_view.reset([[FlutterOverlayView alloc] init pixelFormat:pixel_format]); - overlay_view_wrapper.reset([[FlutterOverlayView alloc] init pixelFormat:pixel_format]); + overlay_view.reset([[FlutterOverlayView alloc] init:pixel_format]); + overlay_view_wrapper.reset([[FlutterOverlayView alloc] init:pixel_format]); auto ca_layer = fml::scoped_nsobject{[[overlay_view.get() layer] retain]}; std::unique_ptr ios_surface = IOSSurface::Create(ios_context, ca_layer); From 801034978b6e159eb002796685e44a8dde2d9728 Mon Sep 17 00:00:00 2001 From: Jonah Williams Date: Sat, 18 Nov 2023 09:25:30 -0800 Subject: [PATCH 07/14] Update FlutterPlatformViews.mm --- .../platform/darwin/ios/framework/Source/FlutterPlatformViews.mm | 1 - 1 file changed, 1 deletion(-) diff --git a/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews.mm b/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews.mm index fa7831696e84d..3b8c7c87a1280 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews.mm @@ -95,7 +95,6 @@ static bool ClipRRectContainsPlatformViewBoundingRect(const SkRRect& clip_rrect, fml::scoped_nsobject overlay_view_wrapper; if (!gr_context) { - CGFloat screenScale = [UIScreen mainScreen].scale; overlay_view.reset([[FlutterOverlayView alloc] init:pixel_format]); overlay_view_wrapper.reset([[FlutterOverlayView alloc] init:pixel_format]); From 075e579591defd950ca9de8544a3dd799379f627 Mon Sep 17 00:00:00 2001 From: Jonah Williams Date: Sat, 18 Nov 2023 10:56:29 -0800 Subject: [PATCH 08/14] Update FlutterOverlayView.mm --- .../darwin/ios/framework/Source/FlutterOverlayView.mm | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/shell/platform/darwin/ios/framework/Source/FlutterOverlayView.mm b/shell/platform/darwin/ios/framework/Source/FlutterOverlayView.mm index b5ed05b853868..133e7d5172fa5 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterOverlayView.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterOverlayView.mm @@ -60,17 +60,7 @@ - (instancetype)initWithContentsScale:(CGFloat)contentsScale self.layer.allowsGroupOpacity = NO; self.layer.contentsScale = contentsScale; self.layer.rasterizationScale = contentsScale; -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wunguarded-availability-new" - CAMetalLayer* layer = (CAMetalLayer*)self.layer; -#pragma clang diagnostic pop - layer.pixelFormat = pixelFormat; - if (pixelFormat == MTLPixelFormatRGBA16Float) { - CGColorSpaceRef srgb = CGColorSpaceCreateWithName(kCGColorSpaceExtendedSRGB); - layer.colorspace = srgb; - } } - return self; } From a9a7a9ce09e41cba33f3c2920ac2a358c7220169 Mon Sep 17 00:00:00 2001 From: jonahwilliams Date: Sat, 18 Nov 2023 16:24:31 -0800 Subject: [PATCH 09/14] ++ --- .../ios/framework/Source/FlutterOverlayView.h | 2 +- .../framework/Source/FlutterOverlayView.mm | 22 +++++++++---------- .../framework/Source/FlutterPlatformViews.mm | 7 +++--- 3 files changed, 16 insertions(+), 15 deletions(-) diff --git a/shell/platform/darwin/ios/framework/Source/FlutterOverlayView.h b/shell/platform/darwin/ios/framework/Source/FlutterOverlayView.h index 2d5926c36f675..59f85195e8d34 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterOverlayView.h +++ b/shell/platform/darwin/ios/framework/Source/FlutterOverlayView.h @@ -32,7 +32,7 @@ - (instancetype)initWithFrame:(CGRect)frame NS_UNAVAILABLE; - (instancetype)initWithCoder:(NSCoder*)aDecoder NS_UNAVAILABLE; -- (instancetype)init:(MTLPixelFormat)pixelFormat NS_DESIGNATED_INITIALIZER; +- (instancetype)init NS_DESIGNATED_INITIALIZER; - (instancetype)initWithContentsScale:(CGFloat)contentsScale pixelFormat:(MTLPixelFormat)pixelFormat; diff --git a/shell/platform/darwin/ios/framework/Source/FlutterOverlayView.mm b/shell/platform/darwin/ios/framework/Source/FlutterOverlayView.mm index 133e7d5172fa5..6a8e079f9a9a9 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterOverlayView.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterOverlayView.mm @@ -31,22 +31,13 @@ - (instancetype)initWithCoder:(NSCoder*)aDecoder { return nil; } -- (instancetype)init:(MTLPixelFormat)pixelFormat { +- (instancetype)init { self = [super initWithFrame:CGRectZero]; if (self) { self.layer.opaque = NO; self.userInteractionEnabled = NO; self.autoresizingMask = (UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight); -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wunguarded-availability-new" - CAMetalLayer* layer = (CAMetalLayer*)self.layer; -#pragma clang diagnostic pop - layer.pixelFormat = pixelFormat; - if (pixelFormat == MTLPixelFormatRGBA16Float) { - CGColorSpaceRef srgb = CGColorSpaceCreateWithName(kCGColorSpaceExtendedSRGB); - layer.colorspace = srgb; - } } return self; @@ -54,12 +45,21 @@ - (instancetype)init:(MTLPixelFormat)pixelFormat { - (instancetype)initWithContentsScale:(CGFloat)contentsScale pixelFormat:(MTLPixelFormat)pixelFormat { - self = [self init:pixelFormat]; + self = [self init]; if ([self.layer isKindOfClass:NSClassFromString(@"CAMetalLayer")]) { self.layer.allowsGroupOpacity = NO; self.layer.contentsScale = contentsScale; self.layer.rasterizationScale = contentsScale; +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunguarded-availability-new" + CAMetalLayer* layer = (CAMetalLayer*)self.layer; +#pragma clang diagnostic pop + layer.pixelFormat = pixelFormat; + if (pixelFormat == MTLPixelFormatRGBA16Float) { + CGColorSpaceRef srgb = CGColorSpaceCreateWithName(kCGColorSpaceExtendedSRGB); + layer.colorspace = srgb; + } } return self; } diff --git a/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews.mm b/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews.mm index 3b8c7c87a1280..7979430ff3700 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews.mm @@ -94,9 +94,10 @@ static bool ClipRRectContainsPlatformViewBoundingRect(const SkRRect& clip_rrect, fml::scoped_nsobject overlay_view; fml::scoped_nsobject overlay_view_wrapper; - if (!gr_context) { - overlay_view.reset([[FlutterOverlayView alloc] init:pixel_format]); - overlay_view_wrapper.reset([[FlutterOverlayView alloc] init:pixel_format]); + bool impeller_enabled = !!ios_context->GetImpellerContext(); + if (!gr_context && !impeller_enabled) { + overlay_view.reset([[FlutterOverlayView alloc] init]); + overlay_view_wrapper.reset([[FlutterOverlayView alloc] init]); auto ca_layer = fml::scoped_nsobject{[[overlay_view.get() layer] retain]}; std::unique_ptr ios_surface = IOSSurface::Create(ios_context, ca_layer); From 6dd77e6d8483ba0020cb2cf7a70e29def9ea1c38 Mon Sep 17 00:00:00 2001 From: jonahwilliams Date: Sat, 18 Nov 2023 18:00:57 -0800 Subject: [PATCH 10/14] no temp --- .../platform/darwin/ios/framework/Source/FlutterOverlayView.mm | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/shell/platform/darwin/ios/framework/Source/FlutterOverlayView.mm b/shell/platform/darwin/ios/framework/Source/FlutterOverlayView.mm index 6a8e079f9a9a9..1e199b1e263bb 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterOverlayView.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterOverlayView.mm @@ -57,8 +57,7 @@ - (instancetype)initWithContentsScale:(CGFloat)contentsScale #pragma clang diagnostic pop layer.pixelFormat = pixelFormat; if (pixelFormat == MTLPixelFormatRGBA16Float) { - CGColorSpaceRef srgb = CGColorSpaceCreateWithName(kCGColorSpaceExtendedSRGB); - layer.colorspace = srgb; + layer.colorspace = CGColorSpaceCreateWithName(kCGColorSpaceExtendedSRGB); } } return self; From 17b4c298559c6809742d11e41f8dcf0ae953b1a3 Mon Sep 17 00:00:00 2001 From: jonahwilliams Date: Mon, 20 Nov 2023 09:23:02 -0800 Subject: [PATCH 11/14] release --- .../darwin/ios/framework/Source/FlutterOverlayView.mm | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/shell/platform/darwin/ios/framework/Source/FlutterOverlayView.mm b/shell/platform/darwin/ios/framework/Source/FlutterOverlayView.mm index 1e199b1e263bb..3382a055f4c23 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterOverlayView.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterOverlayView.mm @@ -3,6 +3,7 @@ // found in the LICENSE file. #import "flutter/shell/platform/darwin/ios/framework/Source/FlutterOverlayView.h" +#include #include #include "flutter/common/settings.h" @@ -57,7 +58,9 @@ - (instancetype)initWithContentsScale:(CGFloat)contentsScale #pragma clang diagnostic pop layer.pixelFormat = pixelFormat; if (pixelFormat == MTLPixelFormatRGBA16Float) { - layer.colorspace = CGColorSpaceCreateWithName(kCGColorSpaceExtendedSRGB); + auto srgb = CGColorSpaceCreateWithName(kCGColorSpaceExtendedSRGB); + layer.colorspace = srgb; + CGColorSpaceRelease(srgb); } } return self; From 98b553fa1e4a26fbe89f7e8b782fa95e021a7c67 Mon Sep 17 00:00:00 2001 From: jonahwilliams Date: Mon, 20 Nov 2023 11:51:35 -0800 Subject: [PATCH 12/14] ++ --- .../darwin/ios/framework/Source/FlutterOverlayView.h | 6 ++++-- .../darwin/ios/framework/Source/FlutterOverlayView.mm | 5 ++--- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/shell/platform/darwin/ios/framework/Source/FlutterOverlayView.h b/shell/platform/darwin/ios/framework/Source/FlutterOverlayView.h index 59f85195e8d34..db3b8e94c990d 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterOverlayView.h +++ b/shell/platform/darwin/ios/framework/Source/FlutterOverlayView.h @@ -13,6 +13,7 @@ #include "flutter/fml/memory/weak_ptr.h" #include "flutter/shell/common/shell.h" #import "flutter/shell/platform/darwin/ios/ios_surface.h" +#include "fml/platform/darwin/cf_utils.h" #import "flutter/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.h" @@ -27,8 +28,9 @@ /// FlutterOverlay view contains the backing stores for the rest. The overlay /// views also handle touch propagation and the like for touches that occurs /// either on overlays or otherwise may be intercepted by the platform views. -@interface FlutterOverlayView : UIView - +@interface FlutterOverlayView : UIView { + fml::CFRef colorSpaceRef; +} - (instancetype)initWithFrame:(CGRect)frame NS_UNAVAILABLE; - (instancetype)initWithCoder:(NSCoder*)aDecoder NS_UNAVAILABLE; diff --git a/shell/platform/darwin/ios/framework/Source/FlutterOverlayView.mm b/shell/platform/darwin/ios/framework/Source/FlutterOverlayView.mm index 3382a055f4c23..48d198c767451 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterOverlayView.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterOverlayView.mm @@ -58,9 +58,8 @@ - (instancetype)initWithContentsScale:(CGFloat)contentsScale #pragma clang diagnostic pop layer.pixelFormat = pixelFormat; if (pixelFormat == MTLPixelFormatRGBA16Float) { - auto srgb = CGColorSpaceCreateWithName(kCGColorSpaceExtendedSRGB); - layer.colorspace = srgb; - CGColorSpaceRelease(srgb); + self->colorSpaceRef = fml::CFRef(CGColorSpaceCreateWithName(kCGColorSpaceExtendedSRGB)); + layer.colorspace = self->colorSpaceRef; } } return self; From d98696a85f2aa3503bc1b281b63a3c699541fed3 Mon Sep 17 00:00:00 2001 From: jonahwilliams Date: Tue, 21 Nov 2023 10:45:50 -0800 Subject: [PATCH 13/14] review. --- impeller/renderer/blit_pass_unittests.cc | 22 ++++++++++++++++--- .../ios/framework/Source/FlutterOverlayView.h | 4 +--- .../framework/Source/FlutterOverlayView.mm | 8 ++++--- 3 files changed, 25 insertions(+), 9 deletions(-) diff --git a/impeller/renderer/blit_pass_unittests.cc b/impeller/renderer/blit_pass_unittests.cc index 4ff5906e2cca4..bffa3babdf974 100644 --- a/impeller/renderer/blit_pass_unittests.cc +++ b/impeller/renderer/blit_pass_unittests.cc @@ -9,9 +9,6 @@ #include "impeller/playground/playground_test.h" #include "impeller/renderer/command_buffer.h" -// TODO(zanderso): https://github.com/flutter/flutter/issues/127701 -// NOLINTBEGIN(bugprone-unchecked-optional-access) - namespace impeller { namespace testing { @@ -57,5 +54,24 @@ TEST_P(BlitPassTest, BlitAcrossDifferentSampleCountsFails) { EXPECT_FALSE(blit_pass->AddCopy(src, dst)); } +TEST_P(BlitPassTest, BlitPassesForMatchingFormats) { + ScopedValidationDisable scope; // avoid noise in output. + auto context = GetContext(); + auto cmd_buffer = context->CreateCommandBuffer(); + auto blit_pass = cmd_buffer->CreateBlitPass(); + + TextureDescriptor src_desc; + src_desc.format = PixelFormat::kR8G8B8A8UNormInt; + src_desc.size = {100, 100}; + auto src = context->GetResourceAllocator()->CreateTexture(src_desc); + + TextureDescriptor dst_format; + dst_format.format = PixelFormat::kR8G8B8A8UNormInt; + dst_format.size = {100, 100}; + auto dst = context->GetResourceAllocator()->CreateTexture(dst_format); + + EXPECT_TRUE(blit_pass->AddCopy(src, dst)); +} + } // namespace testing } // namespace impeller diff --git a/shell/platform/darwin/ios/framework/Source/FlutterOverlayView.h b/shell/platform/darwin/ios/framework/Source/FlutterOverlayView.h index db3b8e94c990d..4f9ddd6bbbdf1 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterOverlayView.h +++ b/shell/platform/darwin/ios/framework/Source/FlutterOverlayView.h @@ -28,9 +28,7 @@ /// FlutterOverlay view contains the backing stores for the rest. The overlay /// views also handle touch propagation and the like for touches that occurs /// either on overlays or otherwise may be intercepted by the platform views. -@interface FlutterOverlayView : UIView { - fml::CFRef colorSpaceRef; -} +@interface FlutterOverlayView : UIView - (instancetype)initWithFrame:(CGRect)frame NS_UNAVAILABLE; - (instancetype)initWithCoder:(NSCoder*)aDecoder NS_UNAVAILABLE; diff --git a/shell/platform/darwin/ios/framework/Source/FlutterOverlayView.mm b/shell/platform/darwin/ios/framework/Source/FlutterOverlayView.mm index 48d198c767451..db1d13d8d37f8 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterOverlayView.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterOverlayView.mm @@ -20,7 +20,9 @@ // This is mostly a duplication of FlutterView. // TODO(amirh): once GL support is in evaluate if we can merge this with FlutterView. -@implementation FlutterOverlayView +@implementation FlutterOverlayView { + fml::CFRef _colorSpaceRef; +} - (instancetype)initWithFrame:(CGRect)frame { NSAssert(NO, @"FlutterOverlayView must init or initWithContentsScale"); @@ -58,8 +60,8 @@ - (instancetype)initWithContentsScale:(CGFloat)contentsScale #pragma clang diagnostic pop layer.pixelFormat = pixelFormat; if (pixelFormat == MTLPixelFormatRGBA16Float) { - self->colorSpaceRef = fml::CFRef(CGColorSpaceCreateWithName(kCGColorSpaceExtendedSRGB)); - layer.colorspace = self->colorSpaceRef; + self->_colorSpaceRef = fml::CFRef(CGColorSpaceCreateWithName(kCGColorSpaceExtendedSRGB)); + layer.colorspace = self->_colorSpaceRef; } } return self; From 6d89959a4c5faf507960a157d3cda0f84439a2c9 Mon Sep 17 00:00:00 2001 From: jonahwilliams Date: Tue, 21 Nov 2023 11:09:59 -0800 Subject: [PATCH 14/14] remove extra ivar --- .../ios/framework/Source/FlutterView.mm | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/shell/platform/darwin/ios/framework/Source/FlutterView.mm b/shell/platform/darwin/ios/framework/Source/FlutterView.mm index cb6f18fd33218..d1af6ebf5beb1 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterView.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterView.mm @@ -20,7 +20,6 @@ @implementation FlutterView { id _delegate; BOOL _isWideGamutEnabled; - MTLPixelFormat _pixelFormat; } - (instancetype)init { @@ -46,9 +45,16 @@ - (UIScreen*)screen { } - (MTLPixelFormat)pixelFormat { - return _pixelFormat; + if ([self.layer isKindOfClass:NSClassFromString(@"CAMetalLayer")]) { +// It is a known Apple bug that CAMetalLayer incorrectly reports its supported +// SDKs. It is, in fact, available since iOS 8. +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunguarded-availability-new" + CAMetalLayer* layer = (CAMetalLayer*)self.layer; + return layer.pixelFormat; + } + return MTLPixelFormatBGRA8Unorm; } - - (BOOL)isWideGamutSupported { if (![_delegate isUsingImpeller]) { return NO; @@ -121,12 +127,8 @@ - (void)layoutSubviews { // F16 was chosen over BGRA10_XR since Skia does not support decoding // BGRA10_XR. layer.pixelFormat = MTLPixelFormatRGBA16Float; - _pixelFormat = MTLPixelFormatRGBA16Float; - } else { - if (_isWideGamutEnabled && !isWideGamutSupported) { - PrintWideGamutWarningOnce(); - } - _pixelFormat = layer.pixelFormat; + } else if (_isWideGamutEnabled && !isWideGamutSupported) { + PrintWideGamutWarningOnce(); } }