From 3cb8e82909ef47f9688b6eecbfe96f76ff010fca Mon Sep 17 00:00:00 2001 From: Matej Knopp Date: Thu, 31 Aug 2023 08:02:29 +0200 Subject: [PATCH] [macOS] Implement unobstructed platform views (flutter/engine#42960) Fixes https://github.com/flutter/flutter/issues/129073 ## Changes to Embedder API Introduced `FlutterRegion` to represent arbitrary region: ```cpp typedef struct { /// The size of this struct. Must be sizeof(FlutterRegion). size_t struct_size; /// Number of rectangles in the region. size_t rects_count; /// The rectangles that make up the region. FlutterRect* rects; } FlutterRegion; ``` Note that this is identical to struct `FlutterDamage` with more generic naming. Maybe down the line we could deprecate `FlutterDamage` and use `FlutterRegion` instead. Introduced `FlutterBackingStorePresentInfo`: ```cpp typedef struct { size_t struct_size; /// The area of the backing store that contains Flutter contents. Pixels /// outside of this area are transparent and the embedder may choose not /// to render them. Coordinates are in physical pixels. FlutterRegion* paint_region; } FlutterBackingStorePresentInfo; ``` In future this struct may also contain more precise hit test region (when framework supports it) and/or information relevant to partial repaint (buffer damage, frame damage). Added a `backing_store_present_info` field to `FlutterLayer`: ```cpp typedef struct { ... /// Extra information for the backing store that the embedder may /// use during presentation. FlutterBackingStorePresentInfo* backing_store_present_info; } FlutterLayer; ``` ## Changes to the macOS embedder This PR adds support for `FLTEnableSurfaceDebugInfo` flag in main bundle `Info.plist` that enables visual indicators of overlay layers. ## Example of unobstructed platform views https://github.com/flutter/flutter/assets/96958/09a75eee-316b-4d53-a8b4-d6bb4e1e52f7 ## Pre-launch Checklist - [X] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [X] I read the [Tree Hygiene] wiki page, which explains my responsibilities. - [X] I read and followed the [Flutter Style Guide] and the [C++, Objective-C, Java style guides]. - [X] I listed at least one issue that this PR fixes in the description above. - [X] I added new tests to check the change I am making or feature I am adding, or Hixie said the PR is test-exempt. See [testing the engine] for instructions on writing and running engine tests. - [X] I updated/added relevant documentation (doc comments with `///`). - [X] I signed the [CLA]. - [X] All existing and new tests are passing. If you need help, consider asking for advice on the #hackers-new channel on [Discord]. [Contributor Guide]: https://github.com/flutter/flutter/wiki/Tree-hygiene#overview [Tree Hygiene]: https://github.com/flutter/flutter/wiki/Tree-hygiene [Flutter Style Guide]: https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo [C++, Objective-C, Java style guides]: https://github.com/flutter/engine/blob/main/CONTRIBUTING.md#style [testing the engine]: https://github.com/flutter/flutter/wiki/Testing-the-engine [CLA]: https://cla.developers.google.com/ [flutter/tests]: https://github.com/flutter/tests [breaking change policy]: https://github.com/flutter/flutter/wiki/Tree-hygiene#handling-breaking-changes [Discord]: https://github.com/flutter/flutter/wiki/Chat --- .../framework/Source/FlutterCompositor.mm | 7 + .../framework/Source/FlutterSurfaceManager.h | 3 + .../framework/Source/FlutterSurfaceManager.mm | 98 +++- .../Source/FlutterSurfaceManagerTest.mm | 73 ++- .../shell/platform/embedder/embedder.h | 25 + .../embedder/embedder_external_view.cc | 5 + .../embedder/embedder_external_view.h | 2 + .../embedder_external_view_embedder.cc | 11 +- .../platform/embedder/embedder_layers.cc | 31 +- .../shell/platform/embedder/embedder_layers.h | 7 +- .../embedder/tests/embedder_assertions.h | 20 +- .../embedder/tests/embedder_gl_unittests.cc | 435 ++++++++++++++++++ .../tests/embedder_metal_unittests.mm | 70 +++ .../embedder/tests/embedder_unittests.cc | 98 ++++ 14 files changed, 872 insertions(+), 13 deletions(-) diff --git a/engine/src/flutter/shell/platform/darwin/macos/framework/Source/FlutterCompositor.mm b/engine/src/flutter/shell/platform/darwin/macos/framework/Source/FlutterCompositor.mm index b40234c5b3b..307c6c9a939 100644 --- a/engine/src/flutter/shell/platform/darwin/macos/framework/Source/FlutterCompositor.mm +++ b/engine/src/flutter/shell/platform/darwin/macos/framework/Source/FlutterCompositor.mm @@ -57,6 +57,13 @@ bool FlutterCompositor::Present(FlutterViewId view_id, info.surface = surface; info.offset = CGPointMake(layer->offset.x, layer->offset.y); info.zIndex = i; + FlutterBackingStorePresentInfo* present_info = layer->backing_store_present_info; + if (present_info != nullptr && present_info->paint_region != nullptr) { + auto paint_region = present_info->paint_region; + // Safe because the size of FlutterRect is not expected to change. + info.paintRegion = std::vector( + paint_region->rects, paint_region->rects + paint_region->rects_count); + } [surfaces addObject:info]; } } diff --git a/engine/src/flutter/shell/platform/darwin/macos/framework/Source/FlutterSurfaceManager.h b/engine/src/flutter/shell/platform/darwin/macos/framework/Source/FlutterSurfaceManager.h index da1e2bcc9b9..46872df2ff0 100644 --- a/engine/src/flutter/shell/platform/darwin/macos/framework/Source/FlutterSurfaceManager.h +++ b/engine/src/flutter/shell/platform/darwin/macos/framework/Source/FlutterSurfaceManager.h @@ -5,6 +5,8 @@ #import #import +#include + #import "flutter/shell/platform/darwin/macos/framework/Source/FlutterSurface.h" /** @@ -15,6 +17,7 @@ @property(readwrite, strong, nonatomic, nonnull) FlutterSurface* surface; @property(readwrite, nonatomic) CGPoint offset; @property(readwrite, nonatomic) size_t zIndex; +@property(readwrite, nonatomic) std::vector paintRegion; @end diff --git a/engine/src/flutter/shell/platform/darwin/macos/framework/Source/FlutterSurfaceManager.mm b/engine/src/flutter/shell/platform/darwin/macos/framework/Source/FlutterSurfaceManager.mm index 8473d2b7395..ed41844529b 100644 --- a/engine/src/flutter/shell/platform/darwin/macos/framework/Source/FlutterSurfaceManager.mm +++ b/engine/src/flutter/shell/platform/darwin/macos/framework/Source/FlutterSurfaceManager.mm @@ -29,6 +29,11 @@ // Currently visible layers. NSMutableArray* _layers; + + // Whether to highlight borders of overlay surfaces. Determined by + // FLTEnableSurfaceDebugInfo value in main bundle Info.plist. + NSNumber* _enableSurfaceDebugInfo; + CATextLayer* _infoLayer; } /** @@ -38,6 +43,60 @@ @end +static NSColor* GetBorderColorForLayer(int layer) { + NSArray* colors = @[ + [NSColor yellowColor], + [NSColor cyanColor], + [NSColor magentaColor], + [NSColor greenColor], + [NSColor purpleColor], + [NSColor orangeColor], + [NSColor blueColor], + ]; + return colors[layer % colors.count]; +} + +/// Creates sublayers for given layer, each one displaying a portion of the +/// of the surface determined by a rectangle in the provided paint region. +static void UpdateContentSubLayers(CALayer* layer, + IOSurfaceRef surface, + CGFloat scale, + CGSize surfaceSize, + NSColor* borderColor, + const std::vector& paintRegion) { + // Adjust sublayer count to paintRegion count. + while (layer.sublayers.count > paintRegion.size()) { + [layer.sublayers.lastObject removeFromSuperlayer]; + } + + while (layer.sublayers.count < paintRegion.size()) { + CALayer* newLayer = [CALayer layer]; + [layer addSublayer:newLayer]; + } + + for (size_t i = 0; i < paintRegion.size(); i++) { + CALayer* subLayer = [layer.sublayers objectAtIndex:i]; + const auto& rect = paintRegion[i]; + subLayer.frame = CGRectMake(rect.left / scale, rect.top / scale, + (rect.right - rect.left) / scale, (rect.bottom - rect.top) / scale); + + double width = surfaceSize.width; + double height = surfaceSize.height; + + subLayer.contentsRect = + CGRectMake(rect.left / width, rect.top / height, (rect.right - rect.left) / width, + (rect.bottom - rect.top) / height); + + if (borderColor != nil) { + // Visualize sublayer + subLayer.borderColor = borderColor.CGColor; + subLayer.borderWidth = 1.0; + } + + subLayer.contents = (__bridge id)surface; + } +} + @implementation FlutterSurfaceManager - (instancetype)initWithDevice:(id)device @@ -77,6 +136,17 @@ return surface; } +- (BOOL)enableSurfaceDebugInfo { + if (_enableSurfaceDebugInfo == nil) { + _enableSurfaceDebugInfo = + [[NSBundle mainBundle] objectForInfoDictionaryKey:@"FLTEnableSurfaceDebugInfo"]; + if (_enableSurfaceDebugInfo == nil) { + _enableSurfaceDebugInfo = @NO; + } + } + return [_enableSurfaceDebugInfo boolValue]; +} + - (void)commit:(NSArray*)surfaces { FML_DCHECK([NSThread isMainThread]); @@ -100,16 +170,38 @@ [_layers addObject:layer]; } + bool enableSurfaceDebugInfo = self.enableSurfaceDebugInfo; + // Update contents of surfaces. for (size_t i = 0; i < surfaces.count; ++i) { FlutterSurfacePresentInfo* info = surfaces[i]; CALayer* layer = _layers[i]; CGFloat scale = _containingLayer.contentsScale; - layer.frame = CGRectMake(info.offset.x / scale, info.offset.y / scale, - info.surface.size.width / scale, info.surface.size.height / scale); - layer.contents = (__bridge id)info.surface.ioSurface; + if (i == 0) { + layer.frame = CGRectMake(info.offset.x / scale, info.offset.y / scale, + info.surface.size.width / scale, info.surface.size.height / scale); + layer.contents = (__bridge id)info.surface.ioSurface; + } else { + layer.frame = CGRectZero; + NSColor* borderColor = enableSurfaceDebugInfo ? GetBorderColorForLayer(i - 1) : nil; + UpdateContentSubLayers(layer, info.surface.ioSurface, scale, info.surface.size, borderColor, + info.paintRegion); + } layer.zPosition = info.zIndex; } + + if (enableSurfaceDebugInfo) { + if (_infoLayer == nil) { + _infoLayer = [[CATextLayer alloc] init]; + [_containingLayer addSublayer:_infoLayer]; + _infoLayer.fontSize = 15; + _infoLayer.foregroundColor = [NSColor yellowColor].CGColor; + _infoLayer.frame = CGRectMake(15, 15, 300, 100); + _infoLayer.contentsScale = _containingLayer.contentsScale; + _infoLayer.zPosition = 100000; + } + _infoLayer.string = [NSString stringWithFormat:@"Surface count: %li", _layers.count]; + } } static CGSize GetRequiredFrameSize(NSArray* surfaces) { diff --git a/engine/src/flutter/shell/platform/darwin/macos/framework/Source/FlutterSurfaceManagerTest.mm b/engine/src/flutter/shell/platform/darwin/macos/framework/Source/FlutterSurfaceManagerTest.mm index 058913ae2e6..8b5606834c0 100644 --- a/engine/src/flutter/shell/platform/darwin/macos/framework/Source/FlutterSurfaceManagerTest.mm +++ b/engine/src/flutter/shell/platform/darwin/macos/framework/Source/FlutterSurfaceManagerTest.mm @@ -25,6 +25,7 @@ self = [super initWithFrame:NSZeroRect]; if (self) { [self setWantsLayer:YES]; + self.layer.contentsScale = 2.0; } return self; } @@ -48,13 +49,16 @@ static FlutterSurfaceManager* CreateSurfaceManager(TestView* testView) { delegate:testView]; } -static FlutterSurfacePresentInfo* CreatePresentInfo(FlutterSurface* surface, - CGPoint offset = CGPointZero, - size_t index = 0) { +static FlutterSurfacePresentInfo* CreatePresentInfo( + FlutterSurface* surface, + CGPoint offset = CGPointZero, + size_t index = 0, + const std::vector& paintRegion = {}) { FlutterSurfacePresentInfo* res = [[FlutterSurfacePresentInfo alloc] init]; res.surface = surface; res.offset = offset; res.zIndex = index; + res.paintRegion = paintRegion; return res; } @@ -160,6 +164,10 @@ TEST(FlutterSurfaceManager, SurfacesAreRecycled) { EXPECT_EQ(surface3, surface1); } +inline bool operator==(const CGRect& lhs, const CGRect& rhs) { + return CGRectEqualToRect(lhs, rhs); +} + TEST(FlutterSurfaceManager, LayerManagement) { TestView* testView = [[TestView alloc] init]; FlutterSurfaceManager* surfaceManager = CreateSurfaceManager(testView); @@ -176,15 +184,68 @@ TEST(FlutterSurfaceManager, LayerManagement) { auto surface2_2 = [surfaceManager surfaceForSize:CGSizeMake(20, 20)]; [surfaceManager present:@[ CreatePresentInfo(surface2_1, CGPointMake(20, 10), 1), - CreatePresentInfo(surface2_2, CGPointMake(40, 50), 2) + CreatePresentInfo(surface2_2, CGPointMake(40, 50), 2, + { + FlutterRect{0, 0, 20, 20}, + FlutterRect{40, 0, 60, 20}, + }) ] notify:nil]; EXPECT_EQ(testView.layer.sublayers.count, 2ul); - EXPECT_EQ([testView.layer.sublayers objectAtIndex:0].zPosition, 1.0); - EXPECT_EQ([testView.layer.sublayers objectAtIndex:1].zPosition, 2.0); + EXPECT_EQ(testView.layer.sublayers[0].zPosition, 1.0); + EXPECT_EQ(testView.layer.sublayers[1].zPosition, 2.0); + CALayer* firstOverlaySublayer; + { + NSArray* sublayers = testView.layer.sublayers[1].sublayers; + EXPECT_EQ(sublayers.count, 2ul); + EXPECT_TRUE(CGRectEqualToRect(sublayers[0].frame, CGRectMake(0, 0, 10, 10))); + EXPECT_TRUE(CGRectEqualToRect(sublayers[1].frame, CGRectMake(20, 0, 10, 10))); + EXPECT_TRUE(CGRectEqualToRect(sublayers[0].contentsRect, CGRectMake(0, 0, 1, 1))); + EXPECT_TRUE(CGRectEqualToRect(sublayers[1].contentsRect, CGRectMake(2, 0, 1, 1))); + EXPECT_EQ(sublayers[0].contents, sublayers[1].contents); + firstOverlaySublayer = sublayers[0]; + } EXPECT_TRUE(CGSizeEqualToSize(testView.presentedFrameSize, CGSizeMake(70, 70))); + // Check second overlay sublayer is removed while first is reused and updated + [surfaceManager present:@[ + CreatePresentInfo(surface2_1, CGPointMake(20, 10), 1), + CreatePresentInfo(surface2_2, CGPointMake(40, 50), 2, + { + FlutterRect{0, 10, 20, 20}, + }) + ] + notify:nil]; + EXPECT_EQ(testView.layer.sublayers.count, 2ul); + { + NSArray* sublayers = testView.layer.sublayers[1].sublayers; + EXPECT_EQ(sublayers.count, 1ul); + EXPECT_EQ(sublayers[0], firstOverlaySublayer); + EXPECT_TRUE(CGRectEqualToRect(sublayers[0].frame, CGRectMake(0, 5, 10, 5))); + } + + // Check that second overlay sublayer is added back while first is reused and updated + [surfaceManager present:@[ + CreatePresentInfo(surface2_1, CGPointMake(20, 10), 1), + CreatePresentInfo(surface2_2, CGPointMake(40, 50), 2, + { + FlutterRect{0, 0, 20, 20}, + FlutterRect{40, 0, 60, 20}, + }) + ] + notify:nil]; + + EXPECT_EQ(testView.layer.sublayers.count, 2ul); + { + NSArray* sublayers = testView.layer.sublayers[1].sublayers; + EXPECT_EQ(sublayers.count, 2ul); + EXPECT_EQ(sublayers[0], firstOverlaySublayer); + EXPECT_TRUE(CGRectEqualToRect(sublayers[0].frame, CGRectMake(0, 0, 10, 10))); + EXPECT_TRUE(CGRectEqualToRect(sublayers[1].frame, CGRectMake(20, 0, 10, 10))); + EXPECT_EQ(sublayers[0].contents, sublayers[1].contents); + } + auto surface3_1 = [surfaceManager surfaceForSize:CGSizeMake(50, 30)]; [surfaceManager present:@[ CreatePresentInfo(surface3_1, CGPointMake(20, 10)) ] notify:nil]; diff --git a/engine/src/flutter/shell/platform/embedder/embedder.h b/engine/src/flutter/shell/platform/embedder/embedder.h index d2ffe33e5b6..dbbb346dd87 100644 --- a/engine/src/flutter/shell/platform/embedder/embedder.h +++ b/engine/src/flutter/shell/platform/embedder/embedder.h @@ -1663,6 +1663,27 @@ typedef enum { kFlutterLayerContentTypePlatformView, } FlutterLayerContentType; +/// A region represented by a collection of non-overlapping rectangles. +typedef struct { + /// The size of this struct. Must be sizeof(FlutterRegion). + size_t struct_size; + /// Number of rectangles in the region. + size_t rects_count; + /// The rectangles that make up the region. + FlutterRect* rects; +} FlutterRegion; + +/// Contains additional information about the backing store provided +/// during presentation to the embedder. +typedef struct { + size_t struct_size; + + /// The area of the backing store that contains Flutter contents. Pixels + /// outside of this area are transparent and the embedder may choose not + /// to render them. Coordinates are in physical pixels. + FlutterRegion* paint_region; +} FlutterBackingStorePresentInfo; + typedef struct { /// This size of this struct. Must be sizeof(FlutterLayer). size_t struct_size; @@ -1682,6 +1703,10 @@ typedef struct { FlutterPoint offset; /// The size of the layer (in physical pixels). FlutterSize size; + + /// Extra information for the backing store that the embedder may + /// use during presentation. + FlutterBackingStorePresentInfo* backing_store_present_info; } FlutterLayer; typedef bool (*FlutterBackingStoreCreateCallback)( diff --git a/engine/src/flutter/shell/platform/embedder/embedder_external_view.cc b/engine/src/flutter/shell/platform/embedder/embedder_external_view.cc index fcb436865a7..c28d2fce96f 100644 --- a/engine/src/flutter/shell/platform/embedder/embedder_external_view.cc +++ b/engine/src/flutter/shell/platform/embedder/embedder_external_view.cc @@ -73,6 +73,11 @@ bool EmbedderExternalView::HasPlatformView() const { return view_identifier_.platform_view_id.has_value(); } +std::list EmbedderExternalView::GetEngineRenderedContentsRegion( + const SkRect& query) const { + return slice_->searchNonOverlappingDrawnRects(query); +} + bool EmbedderExternalView::HasEngineRenderedContents() { if (has_engine_rendered_contents_.has_value()) { return has_engine_rendered_contents_.value(); diff --git a/engine/src/flutter/shell/platform/embedder/embedder_external_view.h b/engine/src/flutter/shell/platform/embedder/embedder_external_view.h index e4187b4edff..95f42a94b6c 100644 --- a/engine/src/flutter/shell/platform/embedder/embedder_external_view.h +++ b/engine/src/flutter/shell/platform/embedder/embedder_external_view.h @@ -111,6 +111,8 @@ class EmbedderExternalView { bool Render(const EmbedderRenderTarget& render_target); + std::list GetEngineRenderedContentsRegion(const SkRect& query) const; + private: // End the recording of the slice. // Noop if the slice's recording has already ended. diff --git a/engine/src/flutter/shell/platform/embedder/embedder_external_view_embedder.cc b/engine/src/flutter/shell/platform/embedder/embedder_external_view_embedder.cc index 1b328ff84fa..2f182877310 100644 --- a/engine/src/flutter/shell/platform/embedder/embedder_external_view_embedder.cc +++ b/engine/src/flutter/shell/platform/embedder/embedder_external_view_embedder.cc @@ -241,8 +241,17 @@ void EmbedderExternalViewEmbedder::SubmitFrame( // platform view. if (external_view->HasEngineRenderedContents()) { const auto& exteral_render_target = matched_render_targets.at(view_id); + const auto& external_view = pending_views_.at(view_id); + auto rect_list = + external_view->GetEngineRenderedContentsRegion(SkRect::MakeIWH( + pending_frame_size_.width(), pending_frame_size_.height())); + std::vector rects; + rects.reserve(rect_list.size()); + for (const auto& rect : rect_list) { + rects.push_back(rect.roundOut()); + } presented_layers.PushBackingStoreLayer( - exteral_render_target->GetBackingStore()); + exteral_render_target->GetBackingStore(), rects); } } diff --git a/engine/src/flutter/shell/platform/embedder/embedder_layers.cc b/engine/src/flutter/shell/platform/embedder/embedder_layers.cc index 6465293748f..2b103590855 100644 --- a/engine/src/flutter/shell/platform/embedder/embedder_layers.cc +++ b/engine/src/flutter/shell/platform/embedder/embedder_layers.cc @@ -17,7 +17,9 @@ EmbedderLayers::EmbedderLayers(SkISize frame_size, EmbedderLayers::~EmbedderLayers() = default; -void EmbedderLayers::PushBackingStoreLayer(const FlutterBackingStore* store) { +void EmbedderLayers::PushBackingStoreLayer( + const FlutterBackingStore* store, + const std::vector& paint_region_vec) { FlutterLayer layer = {}; layer.struct_size = sizeof(FlutterLayer); @@ -35,6 +37,33 @@ void EmbedderLayers::PushBackingStoreLayer(const FlutterBackingStore* store) { layer.size.width = transformed_layer_bounds.width(); layer.size.height = transformed_layer_bounds.height(); + auto paint_region_rects = std::make_unique>(); + paint_region_rects->reserve(paint_region_vec.size()); + + for (const auto& rect : paint_region_vec) { + auto transformed_rect = + root_surface_transformation_.mapRect(SkRect::Make(rect)); + paint_region_rects->push_back(FlutterRect{ + transformed_rect.x(), + transformed_rect.y(), + transformed_rect.right(), + transformed_rect.bottom(), + }); + } + + auto paint_region = std::make_unique(); + paint_region->struct_size = sizeof(FlutterRegion); + paint_region->rects = paint_region_rects->data(); + paint_region->rects_count = paint_region_rects->size(); + rects_referenced_.push_back(std::move(paint_region_rects)); + + auto present_info = std::make_unique(); + present_info->struct_size = sizeof(FlutterBackingStorePresentInfo); + present_info->paint_region = paint_region.get(); + regions_referenced_.push_back(std::move(paint_region)); + layer.backing_store_present_info = present_info.get(); + + present_info_referenced_.push_back(std::move(present_info)); presented_layers_.push_back(layer); } diff --git a/engine/src/flutter/shell/platform/embedder/embedder_layers.h b/engine/src/flutter/shell/platform/embedder/embedder_layers.h index c1cb2907588..b4054bde665 100644 --- a/engine/src/flutter/shell/platform/embedder/embedder_layers.h +++ b/engine/src/flutter/shell/platform/embedder/embedder_layers.h @@ -24,7 +24,8 @@ class EmbedderLayers { ~EmbedderLayers(); - void PushBackingStoreLayer(const FlutterBackingStore* store); + void PushBackingStoreLayer(const FlutterBackingStore* store, + const std::vector& drawn_region); void PushPlatformViewLayer(FlutterPlatformViewIdentifier identifier, const EmbeddedViewParams& params); @@ -42,6 +43,10 @@ class EmbedderLayers { mutations_referenced_; std::vector>> mutations_arrays_referenced_; + std::vector> + present_info_referenced_; + std::vector> regions_referenced_; + std::vector>> rects_referenced_; std::vector presented_layers_; FML_DISALLOW_COPY_AND_ASSIGN(EmbedderLayers); diff --git a/engine/src/flutter/shell/platform/embedder/tests/embedder_assertions.h b/engine/src/flutter/shell/platform/embedder/tests/embedder_assertions.h index 9f43aca20bb..dc639eba255 100644 --- a/engine/src/flutter/shell/platform/embedder/tests/embedder_assertions.h +++ b/engine/src/flutter/shell/platform/embedder/tests/embedder_assertions.h @@ -116,6 +116,23 @@ inline bool operator==(const FlutterSoftwareBackingStore2& a, a.pixel_format == b.pixel_format; } +inline bool operator==(const FlutterRegion& a, const FlutterRegion& b) { + if (a.struct_size != b.struct_size || a.rects_count != b.rects_count) { + return false; + } + for (size_t i = 0; i < a.rects_count; i++) { + if (!(a.rects[i] == b.rects[i])) { + return false; + } + } + return true; +} + +inline bool operator==(const FlutterBackingStorePresentInfo& a, + const FlutterBackingStorePresentInfo& b) { + return a.struct_size == b.struct_size && *a.paint_region == *b.paint_region; +} + inline bool operator==(const FlutterBackingStore& a, const FlutterBackingStore& b) { if (!(a.struct_size == b.struct_size && a.user_data == b.user_data && @@ -183,7 +200,8 @@ inline bool operator==(const FlutterLayer& a, const FlutterLayer& b) { switch (a.type) { case kFlutterLayerContentTypeBackingStore: - return *a.backing_store == *b.backing_store; + return *a.backing_store == *b.backing_store && + *a.backing_store_present_info == *b.backing_store_present_info; case kFlutterLayerContentTypePlatformView: return *a.platform_view == *b.platform_view; } diff --git a/engine/src/flutter/shell/platform/embedder/tests/embedder_gl_unittests.cc b/engine/src/flutter/shell/platform/embedder/tests/embedder_gl_unittests.cc index 41ed0381c16..d233f836d9a 100644 --- a/engine/src/flutter/shell/platform/embedder/tests/embedder_gl_unittests.cc +++ b/engine/src/flutter/shell/platform/embedder/tests/embedder_gl_unittests.cc @@ -103,12 +103,26 @@ TEST_F(EmbedderTest, CompositorMustBeAbleToRenderToOpenGLFramebuffer) { backing_store.did_update = true; backing_store.open_gl.type = kFlutterOpenGLTargetTypeFramebuffer; + FlutterRect paint_region_rects[] = { + FlutterRectMakeLTRB(0, 0, 800, 600), + }; + FlutterRegion paint_region = { + .struct_size = sizeof(FlutterRegion), + .rects_count = 1, + .rects = paint_region_rects, + }; + FlutterBackingStorePresentInfo present_info = { + .struct_size = sizeof(FlutterBackingStorePresentInfo), + .paint_region = &paint_region, + }; + FlutterLayer layer = {}; layer.struct_size = sizeof(layer); layer.type = kFlutterLayerContentTypeBackingStore; layer.backing_store = &backing_store; layer.size = FlutterSizeMake(800.0, 600.0); layer.offset = FlutterPointMake(0, 0); + layer.backing_store_present_info = &present_info; ASSERT_EQ(*layers[0], layer); } @@ -135,12 +149,26 @@ TEST_F(EmbedderTest, CompositorMustBeAbleToRenderToOpenGLFramebuffer) { backing_store.did_update = true; backing_store.open_gl.type = kFlutterOpenGLTargetTypeFramebuffer; + FlutterRect paint_region_rects[] = { + FlutterRectMakeLTRB(2, 3, 800, 600), + }; + FlutterRegion paint_region = { + .struct_size = sizeof(FlutterRegion), + .rects_count = 1, + .rects = paint_region_rects, + }; + FlutterBackingStorePresentInfo present_info = { + .struct_size = sizeof(FlutterBackingStorePresentInfo), + .paint_region = &paint_region, + }; + FlutterLayer layer = {}; layer.struct_size = sizeof(layer); layer.type = kFlutterLayerContentTypeBackingStore; layer.backing_store = &backing_store; layer.size = FlutterSizeMake(800.0, 600.0); layer.offset = FlutterPointMake(0.0, 0.0); + layer.backing_store_present_info = &present_info; ASSERT_EQ(*layers[2], layer); } @@ -196,12 +224,26 @@ TEST_F(EmbedderTest, RasterCacheDisabledWithPlatformViews) { backing_store.did_update = true; backing_store.open_gl.type = kFlutterOpenGLTargetTypeFramebuffer; + FlutterRect paint_region_rects[] = { + FlutterRectMakeLTRB(0, 0, 800, 600), + }; + FlutterRegion paint_region = { + .struct_size = sizeof(FlutterRegion), + .rects_count = 1, + .rects = paint_region_rects, + }; + FlutterBackingStorePresentInfo present_info = { + .struct_size = sizeof(FlutterBackingStorePresentInfo), + .paint_region = &paint_region, + }; + FlutterLayer layer = {}; layer.struct_size = sizeof(layer); layer.type = kFlutterLayerContentTypeBackingStore; layer.backing_store = &backing_store; layer.size = FlutterSizeMake(800.0, 600.0); layer.offset = FlutterPointMake(0, 0); + layer.backing_store_present_info = &present_info; ASSERT_EQ(*layers[0], layer); } @@ -228,12 +270,26 @@ TEST_F(EmbedderTest, RasterCacheDisabledWithPlatformViews) { backing_store.did_update = true; backing_store.open_gl.type = kFlutterOpenGLTargetTypeFramebuffer; + FlutterRect paint_region_rects[] = { + FlutterRectMakeLTRB(3, 3, 800, 600), + }; + FlutterRegion paint_region = { + .struct_size = sizeof(FlutterRegion), + .rects_count = 1, + .rects = paint_region_rects, + }; + FlutterBackingStorePresentInfo present_info = { + .struct_size = sizeof(FlutterBackingStorePresentInfo), + .paint_region = &paint_region, + }; + FlutterLayer layer = {}; layer.struct_size = sizeof(layer); layer.type = kFlutterLayerContentTypeBackingStore; layer.backing_store = &backing_store; layer.size = FlutterSizeMake(800.0, 600.0); layer.offset = FlutterPointMake(0.0, 0.0); + layer.backing_store_present_info = &present_info; ASSERT_EQ(*layers[2], layer); } @@ -300,12 +356,26 @@ TEST_F(EmbedderTest, RasterCacheEnabled) { backing_store.did_update = true; backing_store.open_gl.type = kFlutterOpenGLTargetTypeFramebuffer; + FlutterRect paint_region_rects[] = { + FlutterRectMakeLTRB(0, 0, 800, 600), + }; + FlutterRegion paint_region = { + .struct_size = sizeof(FlutterRegion), + .rects_count = 1, + .rects = paint_region_rects, + }; + FlutterBackingStorePresentInfo present_info = { + .struct_size = sizeof(FlutterBackingStorePresentInfo), + .paint_region = &paint_region, + }; + FlutterLayer layer = {}; layer.struct_size = sizeof(layer); layer.type = kFlutterLayerContentTypeBackingStore; layer.backing_store = &backing_store; layer.size = FlutterSizeMake(800.0, 600.0); layer.offset = FlutterPointMake(0, 0); + layer.backing_store_present_info = &present_info; ASSERT_EQ(*layers[0], layer); } @@ -369,12 +439,26 @@ TEST_F(EmbedderTest, CompositorMustBeAbleToRenderToOpenGLTexture) { backing_store.did_update = true; backing_store.open_gl.type = kFlutterOpenGLTargetTypeTexture; + FlutterRect paint_region_rects[] = { + FlutterRectMakeLTRB(0, 0, 800, 600), + }; + FlutterRegion paint_region = { + .struct_size = sizeof(FlutterRegion), + .rects_count = 1, + .rects = paint_region_rects, + }; + FlutterBackingStorePresentInfo present_info = { + .struct_size = sizeof(FlutterBackingStorePresentInfo), + .paint_region = &paint_region, + }; + FlutterLayer layer = {}; layer.struct_size = sizeof(layer); layer.type = kFlutterLayerContentTypeBackingStore; layer.backing_store = &backing_store; layer.size = FlutterSizeMake(800.0, 600.0); layer.offset = FlutterPointMake(0, 0); + layer.backing_store_present_info = &present_info; ASSERT_EQ(*layers[0], layer); } @@ -401,12 +485,26 @@ TEST_F(EmbedderTest, CompositorMustBeAbleToRenderToOpenGLTexture) { backing_store.did_update = true; backing_store.open_gl.type = kFlutterOpenGLTargetTypeTexture; + FlutterRect paint_region_rects[] = { + FlutterRectMakeLTRB(2, 3, 800, 600), + }; + FlutterRegion paint_region = { + .struct_size = sizeof(FlutterRegion), + .rects_count = 1, + .rects = paint_region_rects, + }; + FlutterBackingStorePresentInfo present_info = { + .struct_size = sizeof(FlutterBackingStorePresentInfo), + .paint_region = &paint_region, + }; + FlutterLayer layer = {}; layer.struct_size = sizeof(layer); layer.type = kFlutterLayerContentTypeBackingStore; layer.backing_store = &backing_store; layer.size = FlutterSizeMake(800.0, 600.0); layer.offset = FlutterPointMake(0.0, 0.0); + layer.backing_store_present_info = &present_info; ASSERT_EQ(*layers[2], layer); } @@ -463,12 +561,26 @@ TEST_F(EmbedderTest, CompositorMustBeAbleToRenderToSoftwareBuffer) { backing_store.software.row_bytes * backing_store.software.height, 800 * 4 * 600.0); + FlutterRect paint_region_rects[] = { + FlutterRectMakeLTRB(0, 0, 800, 600), + }; + FlutterRegion paint_region = { + .struct_size = sizeof(FlutterRegion), + .rects_count = 1, + .rects = paint_region_rects, + }; + FlutterBackingStorePresentInfo present_info = { + .struct_size = sizeof(FlutterBackingStorePresentInfo), + .paint_region = &paint_region, + }; + FlutterLayer layer = {}; layer.struct_size = sizeof(layer); layer.type = kFlutterLayerContentTypeBackingStore; layer.backing_store = &backing_store; layer.size = FlutterSizeMake(800.0, 600.0); layer.offset = FlutterPointMake(0, 0); + layer.backing_store_present_info = &present_info; ASSERT_EQ(*layers[0], layer); } @@ -493,12 +605,27 @@ TEST_F(EmbedderTest, CompositorMustBeAbleToRenderToSoftwareBuffer) { backing_store.struct_size = sizeof(backing_store); backing_store.type = kFlutterBackingStoreTypeSoftware; backing_store.did_update = true; + + FlutterRect paint_region_rects[] = { + FlutterRectMakeLTRB(2, 3, 800, 600), + }; + FlutterRegion paint_region = { + .struct_size = sizeof(FlutterRegion), + .rects_count = 1, + .rects = paint_region_rects, + }; + FlutterBackingStorePresentInfo present_info = { + .struct_size = sizeof(FlutterBackingStorePresentInfo), + .paint_region = &paint_region, + }; + FlutterLayer layer = {}; layer.struct_size = sizeof(layer); layer.type = kFlutterLayerContentTypeBackingStore; layer.backing_store = &backing_store; layer.size = FlutterSizeMake(800.0, 600.0); layer.offset = FlutterPointMake(0.0, 0.0); + layer.backing_store_present_info = &present_info; ASSERT_EQ(*layers[2], layer); } @@ -555,12 +682,26 @@ TEST_F(EmbedderTest, CompositorMustBeAbleToRenderKnownScene) { backing_store.did_update = true; backing_store.open_gl.type = kFlutterOpenGLTargetTypeTexture; + FlutterRect paint_region_rects[] = { + FlutterRectMakeLTRB(0, 0, 800, 600), + }; + FlutterRegion paint_region = { + .struct_size = sizeof(FlutterRegion), + .rects_count = 1, + .rects = paint_region_rects, + }; + FlutterBackingStorePresentInfo present_info = { + .struct_size = sizeof(FlutterBackingStorePresentInfo), + .paint_region = &paint_region, + }; + FlutterLayer layer = {}; layer.struct_size = sizeof(layer); layer.type = kFlutterLayerContentTypeBackingStore; layer.backing_store = &backing_store; layer.size = FlutterSizeMake(800.0, 600.0); layer.offset = FlutterPointMake(0.0, 0.0); + layer.backing_store_present_info = &present_info; ASSERT_EQ(*layers[0], layer); } @@ -588,12 +729,26 @@ TEST_F(EmbedderTest, CompositorMustBeAbleToRenderKnownScene) { backing_store.did_update = true; backing_store.open_gl.type = kFlutterOpenGLTargetTypeTexture; + FlutterRect paint_region_rects[] = { + FlutterRectMakeLTRB(30, 30, 80, 180), + }; + FlutterRegion paint_region = { + .struct_size = sizeof(FlutterRegion), + .rects_count = 1, + .rects = paint_region_rects, + }; + FlutterBackingStorePresentInfo present_info = { + .struct_size = sizeof(FlutterBackingStorePresentInfo), + .paint_region = &paint_region, + }; + FlutterLayer layer = {}; layer.struct_size = sizeof(layer); layer.type = kFlutterLayerContentTypeBackingStore; layer.backing_store = &backing_store; layer.size = FlutterSizeMake(800.0, 600.0); layer.offset = FlutterPointMake(0.0, 0.0); + layer.backing_store_present_info = &present_info; ASSERT_EQ(*layers[2], layer); } @@ -621,12 +776,26 @@ TEST_F(EmbedderTest, CompositorMustBeAbleToRenderKnownScene) { backing_store.did_update = true; backing_store.open_gl.type = kFlutterOpenGLTargetTypeTexture; + FlutterRect paint_region_rects[] = { + FlutterRectMakeLTRB(50, 50, 100, 200), + }; + FlutterRegion paint_region = { + .struct_size = sizeof(FlutterRegion), + .rects_count = 1, + .rects = paint_region_rects, + }; + FlutterBackingStorePresentInfo present_info = { + .struct_size = sizeof(FlutterBackingStorePresentInfo), + .paint_region = &paint_region, + }; + FlutterLayer layer = {}; layer.struct_size = sizeof(layer); layer.type = kFlutterLayerContentTypeBackingStore; layer.backing_store = &backing_store; layer.size = FlutterSizeMake(800.0, 600.0); layer.offset = FlutterPointMake(0.0, 0.0); + layer.backing_store_present_info = &present_info; ASSERT_EQ(*layers[4], layer); } @@ -738,12 +907,26 @@ TEST_F(EmbedderTest, CustomCompositorMustWorkWithCustomTaskRunner) { backing_store.did_update = true; backing_store.open_gl.type = kFlutterOpenGLTargetTypeTexture; + FlutterRect paint_region_rects[] = { + FlutterRectMakeLTRB(0, 0, 800, 600), + }; + FlutterRegion paint_region = { + .struct_size = sizeof(FlutterRegion), + .rects_count = 1, + .rects = paint_region_rects, + }; + FlutterBackingStorePresentInfo present_info = { + .struct_size = sizeof(FlutterBackingStorePresentInfo), + .paint_region = &paint_region, + }; + FlutterLayer layer = {}; layer.struct_size = sizeof(layer); layer.type = kFlutterLayerContentTypeBackingStore; layer.backing_store = &backing_store; layer.size = FlutterSizeMake(800.0, 600.0); layer.offset = FlutterPointMake(0, 0); + layer.backing_store_present_info = &present_info; ASSERT_EQ(*layers[0], layer); } @@ -753,12 +936,26 @@ TEST_F(EmbedderTest, CustomCompositorMustWorkWithCustomTaskRunner) { platform_view.struct_size = sizeof(platform_view); platform_view.identifier = 42; + FlutterRect paint_region_rects[] = { + FlutterRectMakeLTRB(2, 3, 800, 600), + }; + FlutterRegion paint_region = { + .struct_size = sizeof(FlutterRegion), + .rects_count = 1, + .rects = paint_region_rects, + }; + FlutterBackingStorePresentInfo present_info = { + .struct_size = sizeof(FlutterBackingStorePresentInfo), + .paint_region = &paint_region, + }; + FlutterLayer layer = {}; layer.struct_size = sizeof(layer); layer.type = kFlutterLayerContentTypePlatformView; layer.platform_view = &platform_view; layer.size = FlutterSizeMake(123.0, 456.0); layer.offset = FlutterPointMake(1.0, 2.0); + layer.backing_store_present_info = &present_info; ASSERT_EQ(*layers[1], layer); } @@ -770,12 +967,26 @@ TEST_F(EmbedderTest, CustomCompositorMustWorkWithCustomTaskRunner) { backing_store.did_update = true; backing_store.open_gl.type = kFlutterOpenGLTargetTypeTexture; + FlutterRect paint_region_rects[] = { + FlutterRectMakeLTRB(2, 3, 800, 600), + }; + FlutterRegion paint_region = { + .struct_size = sizeof(FlutterRegion), + .rects_count = 1, + .rects = paint_region_rects, + }; + FlutterBackingStorePresentInfo present_info = { + .struct_size = sizeof(FlutterBackingStorePresentInfo), + .paint_region = &paint_region, + }; + FlutterLayer layer = {}; layer.struct_size = sizeof(layer); layer.type = kFlutterLayerContentTypeBackingStore; layer.backing_store = &backing_store; layer.size = FlutterSizeMake(800.0, 600.0); layer.offset = FlutterPointMake(0.0, 0.0); + layer.backing_store_present_info = &present_info; ASSERT_EQ(*layers[2], layer); } @@ -852,12 +1063,26 @@ TEST_F(EmbedderTest, CompositorMustBeAbleToRenderWithRootLayerOnly) { backing_store.did_update = true; backing_store.open_gl.type = kFlutterOpenGLTargetTypeTexture; + FlutterRect paint_region_rects[] = { + FlutterRectMakeLTRB(0, 0, 800, 600), + }; + FlutterRegion paint_region = { + .struct_size = sizeof(FlutterRegion), + .rects_count = 1, + .rects = paint_region_rects, + }; + FlutterBackingStorePresentInfo present_info = { + .struct_size = sizeof(FlutterBackingStorePresentInfo), + .paint_region = &paint_region, + }; + FlutterLayer layer = {}; layer.struct_size = sizeof(layer); layer.type = kFlutterLayerContentTypeBackingStore; layer.backing_store = &backing_store; layer.size = FlutterSizeMake(800.0, 600.0); layer.offset = FlutterPointMake(0.0, 0.0); + layer.backing_store_present_info = &present_info; ASSERT_EQ(*layers[0], layer); } @@ -919,12 +1144,26 @@ TEST_F(EmbedderTest, CompositorMustBeAbleToRenderWithPlatformLayerOnBottom) { backing_store.did_update = true; backing_store.open_gl.type = kFlutterOpenGLTargetTypeTexture; + FlutterRect paint_region_rects[] = { + FlutterRectMakeLTRB(0, 0, 800, 600), + }; + FlutterRegion paint_region = { + .struct_size = sizeof(FlutterRegion), + .rects_count = 1, + .rects = paint_region_rects, + }; + FlutterBackingStorePresentInfo present_info = { + .struct_size = sizeof(FlutterBackingStorePresentInfo), + .paint_region = &paint_region, + }; + FlutterLayer layer = {}; layer.struct_size = sizeof(layer); layer.type = kFlutterLayerContentTypeBackingStore; layer.backing_store = &backing_store; layer.size = FlutterSizeMake(800.0, 600.0); layer.offset = FlutterPointMake(0.0, 0.0); + layer.backing_store_present_info = &present_info; ASSERT_EQ(*layers[0], layer); } @@ -1039,12 +1278,26 @@ TEST_F(EmbedderTest, backing_store.did_update = true; backing_store.open_gl.type = kFlutterOpenGLTargetTypeTexture; + FlutterRect paint_region_rects[] = { + FlutterRectMakeLTRB(0, 0, 600, 800), + }; + FlutterRegion paint_region = { + .struct_size = sizeof(FlutterRegion), + .rects_count = 1, + .rects = paint_region_rects, + }; + FlutterBackingStorePresentInfo present_info = { + .struct_size = sizeof(FlutterBackingStorePresentInfo), + .paint_region = &paint_region, + }; + FlutterLayer layer = {}; layer.struct_size = sizeof(layer); layer.type = kFlutterLayerContentTypeBackingStore; layer.backing_store = &backing_store; layer.size = FlutterSizeMake(600.0, 800.0); layer.offset = FlutterPointMake(0.0, 0.0); + layer.backing_store_present_info = &present_info; ASSERT_EQ(*layers[0], layer); } @@ -1072,12 +1325,26 @@ TEST_F(EmbedderTest, backing_store.did_update = true; backing_store.open_gl.type = kFlutterOpenGLTargetTypeTexture; + FlutterRect paint_region_rects[] = { + FlutterRectMakeLTRB(30, 720, 180, 770), + }; + FlutterRegion paint_region = { + .struct_size = sizeof(FlutterRegion), + .rects_count = 1, + .rects = paint_region_rects, + }; + FlutterBackingStorePresentInfo present_info = { + .struct_size = sizeof(FlutterBackingStorePresentInfo), + .paint_region = &paint_region, + }; + FlutterLayer layer = {}; layer.struct_size = sizeof(layer); layer.type = kFlutterLayerContentTypeBackingStore; layer.backing_store = &backing_store; layer.size = FlutterSizeMake(600.0, 800.0); layer.offset = FlutterPointMake(0.0, 0.0); + layer.backing_store_present_info = &present_info; ASSERT_EQ(*layers[2], layer); } @@ -1105,12 +1372,26 @@ TEST_F(EmbedderTest, backing_store.did_update = true; backing_store.open_gl.type = kFlutterOpenGLTargetTypeTexture; + FlutterRect paint_region_rects[] = { + FlutterRectMakeLTRB(50, 700, 200, 750), + }; + FlutterRegion paint_region = { + .struct_size = sizeof(FlutterRegion), + .rects_count = 1, + .rects = paint_region_rects, + }; + FlutterBackingStorePresentInfo present_info = { + .struct_size = sizeof(FlutterBackingStorePresentInfo), + .paint_region = &paint_region, + }; + FlutterLayer layer = {}; layer.struct_size = sizeof(layer); layer.type = kFlutterLayerContentTypeBackingStore; layer.backing_store = &backing_store; layer.size = FlutterSizeMake(600.0, 800.0); layer.offset = FlutterPointMake(0.0, 0.0); + layer.backing_store_present_info = &present_info; ASSERT_EQ(*layers[4], layer); } @@ -1386,12 +1667,26 @@ TEST_P(EmbedderTestMultiBackend, backing_store.did_update = true; ConfigureBackingStore(backing_store, backend, true); + FlutterRect paint_region_rects[] = { + FlutterRectMakeLTRB(0, 0, 800, 600), + }; + FlutterRegion paint_region = { + .struct_size = sizeof(FlutterRegion), + .rects_count = 1, + .rects = paint_region_rects, + }; + FlutterBackingStorePresentInfo present_info = { + .struct_size = sizeof(FlutterBackingStorePresentInfo), + .paint_region = &paint_region, + }; + FlutterLayer layer = {}; layer.struct_size = sizeof(layer); layer.type = kFlutterLayerContentTypeBackingStore; layer.backing_store = &backing_store; layer.size = FlutterSizeMake(800.0, 600.0); layer.offset = FlutterPointMake(0.0, 0.0); + layer.backing_store_present_info = &present_info; ASSERT_EQ(*layers[0], layer); } @@ -1418,12 +1713,26 @@ TEST_P(EmbedderTestMultiBackend, backing_store.did_update = true; ConfigureBackingStore(backing_store, backend, true); + FlutterRect paint_region_rects[] = { + FlutterRectMakeLTRB(0, 0, 800, 600), + }; + FlutterRegion paint_region = { + .struct_size = sizeof(FlutterRegion), + .rects_count = 1, + .rects = paint_region_rects, + }; + FlutterBackingStorePresentInfo present_info = { + .struct_size = sizeof(FlutterBackingStorePresentInfo), + .paint_region = &paint_region, + }; + FlutterLayer layer = {}; layer.struct_size = sizeof(layer); layer.type = kFlutterLayerContentTypeBackingStore; layer.backing_store = &backing_store; layer.size = FlutterSizeMake(800.0, 600.0); layer.offset = FlutterPointMake(0.0, 0.0); + layer.backing_store_present_info = &present_info; ASSERT_EQ(*layers[2], layer); } @@ -1499,12 +1808,26 @@ TEST_F(EmbedderTest, CanRenderGradientWithCompositorOnNonRootLayerWithXform) { backing_store.did_update = true; backing_store.open_gl.type = kFlutterOpenGLTargetTypeFramebuffer; + FlutterRect paint_region_rects[] = { + FlutterRectMakeLTRB(0, 0, 600, 800), + }; + FlutterRegion paint_region = { + .struct_size = sizeof(FlutterRegion), + .rects_count = 1, + .rects = paint_region_rects, + }; + FlutterBackingStorePresentInfo present_info = { + .struct_size = sizeof(FlutterBackingStorePresentInfo), + .paint_region = &paint_region, + }; + FlutterLayer layer = {}; layer.struct_size = sizeof(layer); layer.type = kFlutterLayerContentTypeBackingStore; layer.backing_store = &backing_store; layer.size = FlutterSizeMake(600.0, 800.0); layer.offset = FlutterPointMake(0.0, 0.0); + layer.backing_store_present_info = &present_info; ASSERT_EQ(*layers[0], layer); } @@ -1532,12 +1855,26 @@ TEST_F(EmbedderTest, CanRenderGradientWithCompositorOnNonRootLayerWithXform) { backing_store.did_update = true; backing_store.open_gl.type = kFlutterOpenGLTargetTypeFramebuffer; + FlutterRect paint_region_rects[] = { + FlutterRectMakeLTRB(0, 0, 600, 800), + }; + FlutterRegion paint_region = { + .struct_size = sizeof(FlutterRegion), + .rects_count = 1, + .rects = paint_region_rects, + }; + FlutterBackingStorePresentInfo present_info = { + .struct_size = sizeof(FlutterBackingStorePresentInfo), + .paint_region = &paint_region, + }; + FlutterLayer layer = {}; layer.struct_size = sizeof(layer); layer.type = kFlutterLayerContentTypeBackingStore; layer.backing_store = &backing_store; layer.size = FlutterSizeMake(600.0, 800.0); layer.offset = FlutterPointMake(0.0, 0.0); + layer.backing_store_present_info = &present_info; ASSERT_EQ(*layers[2], layer); } @@ -1842,12 +2179,26 @@ TEST_P(EmbedderTestMultiBackend, backing_store.did_update = true; ConfigureBackingStore(backing_store, backend, false); + FlutterRect paint_region_rects[] = { + FlutterRectMakeLTRB(0, 0, 800, 600), + }; + FlutterRegion paint_region = { + .struct_size = sizeof(FlutterRegion), + .rects_count = 1, + .rects = paint_region_rects, + }; + FlutterBackingStorePresentInfo present_info = { + .struct_size = sizeof(FlutterBackingStorePresentInfo), + .paint_region = &paint_region, + }; + FlutterLayer layer = {}; layer.struct_size = sizeof(layer); layer.type = kFlutterLayerContentTypeBackingStore; layer.backing_store = &backing_store; layer.size = FlutterSizeMake(800.0, 600.0); layer.offset = FlutterPointMake(0.0, 0.0); + layer.backing_store_present_info = &present_info; ASSERT_EQ(*layers[0], layer); } @@ -1874,12 +2225,26 @@ TEST_P(EmbedderTestMultiBackend, backing_store.did_update = true; ConfigureBackingStore(backing_store, backend, false); + FlutterRect paint_region_rects[] = { + FlutterRectMakeLTRB(0, 0, 800, 600), + }; + FlutterRegion paint_region = { + .struct_size = sizeof(FlutterRegion), + .rects_count = 1, + .rects = paint_region_rects, + }; + FlutterBackingStorePresentInfo present_info = { + .struct_size = sizeof(FlutterBackingStorePresentInfo), + .paint_region = &paint_region, + }; + FlutterLayer layer = {}; layer.struct_size = sizeof(layer); layer.type = kFlutterLayerContentTypeBackingStore; layer.backing_store = &backing_store; layer.size = FlutterSizeMake(800.0, 600.0); layer.offset = FlutterPointMake(0.0, 0.0); + layer.backing_store_present_info = &present_info; ASSERT_EQ(*layers[2], layer); } @@ -1937,12 +2302,26 @@ TEST_F( backing_store.did_update = true; backing_store.open_gl.type = kFlutterOpenGLTargetTypeTexture; + FlutterRect paint_region_rects[] = { + FlutterRectMakeLTRB(0, 0, 600, 800), + }; + FlutterRegion paint_region = { + .struct_size = sizeof(FlutterRegion), + .rects_count = 1, + .rects = paint_region_rects, + }; + FlutterBackingStorePresentInfo present_info = { + .struct_size = sizeof(FlutterBackingStorePresentInfo), + .paint_region = &paint_region, + }; + FlutterLayer layer = {}; layer.struct_size = sizeof(layer); layer.type = kFlutterLayerContentTypeBackingStore; layer.backing_store = &backing_store; layer.size = FlutterSizeMake(600.0, 800.0); layer.offset = FlutterPointMake(0.0, 0.0); + layer.backing_store_present_info = &present_info; ASSERT_EQ(*layers[0], layer); } @@ -1970,12 +2349,26 @@ TEST_F( backing_store.did_update = true; backing_store.open_gl.type = kFlutterOpenGLTargetTypeTexture; + FlutterRect paint_region_rects[] = { + FlutterRectMakeLTRB(0, 0, 600, 800), + }; + FlutterRegion paint_region = { + .struct_size = sizeof(FlutterRegion), + .rects_count = 1, + .rects = paint_region_rects, + }; + FlutterBackingStorePresentInfo present_info = { + .struct_size = sizeof(FlutterBackingStorePresentInfo), + .paint_region = &paint_region, + }; + FlutterLayer layer = {}; layer.struct_size = sizeof(layer); layer.type = kFlutterLayerContentTypeBackingStore; layer.backing_store = &backing_store; layer.size = FlutterSizeMake(600.0, 800.0); layer.offset = FlutterPointMake(0.0, 0.0); + layer.backing_store_present_info = &present_info; ASSERT_EQ(*layers[2], layer); } @@ -2106,12 +2499,26 @@ TEST_P(EmbedderTestMultiBackend, PlatformViewMutatorsAreValid) { backing_store.did_update = true; ConfigureBackingStore(backing_store, backend, false); + FlutterRect paint_region_rects[] = { + FlutterRectMakeLTRB(0, 0, 800, 600), + }; + FlutterRegion paint_region = { + .struct_size = sizeof(FlutterRegion), + .rects_count = 1, + .rects = paint_region_rects, + }; + FlutterBackingStorePresentInfo present_info = { + .struct_size = sizeof(FlutterBackingStorePresentInfo), + .paint_region = &paint_region, + }; + FlutterLayer layer = {}; layer.struct_size = sizeof(layer); layer.type = kFlutterLayerContentTypeBackingStore; layer.backing_store = &backing_store; layer.size = FlutterSizeMake(800.0, 600.0); layer.offset = FlutterPointMake(0.0, 0.0); + layer.backing_store_present_info = &present_info; ASSERT_EQ(*layers[0], layer); } @@ -2202,12 +2609,26 @@ TEST_F(EmbedderTest, PlatformViewMutatorsAreValidWithPixelRatio) { backing_store.did_update = true; backing_store.open_gl.type = kFlutterOpenGLTargetTypeTexture; + FlutterRect paint_region_rects[] = { + FlutterRectMakeLTRB(0, 0, 800, 600), + }; + FlutterRegion paint_region = { + .struct_size = sizeof(FlutterRegion), + .rects_count = 1, + .rects = paint_region_rects, + }; + FlutterBackingStorePresentInfo present_info = { + .struct_size = sizeof(FlutterBackingStorePresentInfo), + .paint_region = &paint_region, + }; + FlutterLayer layer = {}; layer.struct_size = sizeof(layer); layer.type = kFlutterLayerContentTypeBackingStore; layer.backing_store = &backing_store; layer.size = FlutterSizeMake(800.0, 600.0); layer.offset = FlutterPointMake(0.0, 0.0); + layer.backing_store_present_info = &present_info; ASSERT_EQ(*layers[0], layer); } @@ -2304,12 +2725,26 @@ TEST_F(EmbedderTest, backing_store.did_update = true; backing_store.open_gl.type = kFlutterOpenGLTargetTypeTexture; + FlutterRect paint_region_rects[] = { + FlutterRectMakeLTRB(0, 0, 600, 800), + }; + FlutterRegion paint_region = { + .struct_size = sizeof(FlutterRegion), + .rects_count = 1, + .rects = paint_region_rects, + }; + FlutterBackingStorePresentInfo present_info = { + .struct_size = sizeof(FlutterBackingStorePresentInfo), + .paint_region = &paint_region, + }; + FlutterLayer layer = {}; layer.struct_size = sizeof(layer); layer.type = kFlutterLayerContentTypeBackingStore; layer.backing_store = &backing_store; layer.size = FlutterSizeMake(600.0, 800.0); layer.offset = FlutterPointMake(0.0, 0.0); + layer.backing_store_present_info = &present_info; ASSERT_EQ(*layers[0], layer); } diff --git a/engine/src/flutter/shell/platform/embedder/tests/embedder_metal_unittests.mm b/engine/src/flutter/shell/platform/embedder/tests/embedder_metal_unittests.mm index 78f7b82ed2f..f3666d9fee4 100644 --- a/engine/src/flutter/shell/platform/embedder/tests/embedder_metal_unittests.mm +++ b/engine/src/flutter/shell/platform/embedder/tests/embedder_metal_unittests.mm @@ -146,12 +146,26 @@ TEST_F(EmbedderTest, MetalCompositorMustBeAbleToRenderPlatformViews) { backing_store.type = kFlutterBackingStoreTypeMetal; backing_store.did_update = true; + FlutterRect paint_region_rects[] = { + FlutterRectMakeLTRB(0, 0, 800, 600), + }; + FlutterRegion paint_region = { + .struct_size = sizeof(FlutterRegion), + .rects_count = 1, + .rects = paint_region_rects, + }; + FlutterBackingStorePresentInfo present_info = { + .struct_size = sizeof(FlutterBackingStorePresentInfo), + .paint_region = &paint_region, + }; + FlutterLayer layer = {}; layer.struct_size = sizeof(layer); layer.type = kFlutterLayerContentTypeBackingStore; layer.backing_store = &backing_store; layer.size = FlutterSizeMake(800.0, 600.0); layer.offset = FlutterPointMake(0, 0); + layer.backing_store_present_info = &present_info; ASSERT_EQ(*layers[0], layer); } @@ -177,12 +191,26 @@ TEST_F(EmbedderTest, MetalCompositorMustBeAbleToRenderPlatformViews) { backing_store.type = kFlutterBackingStoreTypeMetal; backing_store.did_update = true; + FlutterRect paint_region_rects[] = { + FlutterRectMakeLTRB(2, 3, 800, 600), + }; + FlutterRegion paint_region = { + .struct_size = sizeof(FlutterRegion), + .rects_count = 1, + .rects = paint_region_rects, + }; + FlutterBackingStorePresentInfo present_info = { + .struct_size = sizeof(FlutterBackingStorePresentInfo), + .paint_region = &paint_region, + }; + FlutterLayer layer = {}; layer.struct_size = sizeof(layer); layer.type = kFlutterLayerContentTypeBackingStore; layer.backing_store = &backing_store; layer.size = FlutterSizeMake(800.0, 600.0); layer.offset = FlutterPointMake(0.0, 0.0); + layer.backing_store_present_info = &present_info; ASSERT_EQ(*layers[2], layer); } @@ -306,12 +334,26 @@ TEST_F(EmbedderTest, CompositorMustBeAbleToRenderKnownSceneMetal) { backing_store.type = kFlutterBackingStoreTypeMetal; backing_store.did_update = true; + FlutterRect paint_region_rects[] = { + FlutterRectMakeLTRB(0, 0, 800, 600), + }; + FlutterRegion paint_region = { + .struct_size = sizeof(FlutterRegion), + .rects_count = 1, + .rects = paint_region_rects, + }; + FlutterBackingStorePresentInfo present_info = { + .struct_size = sizeof(FlutterBackingStorePresentInfo), + .paint_region = &paint_region, + }; + FlutterLayer layer = {}; layer.struct_size = sizeof(layer); layer.type = kFlutterLayerContentTypeBackingStore; layer.backing_store = &backing_store; layer.size = FlutterSizeMake(800.0, 600.0); layer.offset = FlutterPointMake(0.0, 0.0); + layer.backing_store_present_info = &present_info; ASSERT_EQ(*layers[0], layer); } @@ -338,12 +380,26 @@ TEST_F(EmbedderTest, CompositorMustBeAbleToRenderKnownSceneMetal) { backing_store.type = kFlutterBackingStoreTypeMetal; backing_store.did_update = true; + FlutterRect paint_region_rects[] = { + FlutterRectMakeLTRB(30, 30, 80, 180), + }; + FlutterRegion paint_region = { + .struct_size = sizeof(FlutterRegion), + .rects_count = 1, + .rects = paint_region_rects, + }; + FlutterBackingStorePresentInfo present_info = { + .struct_size = sizeof(FlutterBackingStorePresentInfo), + .paint_region = &paint_region, + }; + FlutterLayer layer = {}; layer.struct_size = sizeof(layer); layer.type = kFlutterLayerContentTypeBackingStore; layer.backing_store = &backing_store; layer.size = FlutterSizeMake(800.0, 600.0); layer.offset = FlutterPointMake(0.0, 0.0); + layer.backing_store_present_info = &present_info; ASSERT_EQ(*layers[2], layer); } @@ -370,12 +426,26 @@ TEST_F(EmbedderTest, CompositorMustBeAbleToRenderKnownSceneMetal) { backing_store.type = kFlutterBackingStoreTypeMetal; backing_store.did_update = true; + FlutterRect paint_region_rects[] = { + FlutterRectMakeLTRB(50, 50, 100, 200), + }; + FlutterRegion paint_region = { + .struct_size = sizeof(FlutterRegion), + .rects_count = 1, + .rects = paint_region_rects, + }; + FlutterBackingStorePresentInfo present_info = { + .struct_size = sizeof(FlutterBackingStorePresentInfo), + .paint_region = &paint_region, + }; + FlutterLayer layer = {}; layer.struct_size = sizeof(layer); layer.type = kFlutterLayerContentTypeBackingStore; layer.backing_store = &backing_store; layer.size = FlutterSizeMake(800.0, 600.0); layer.offset = FlutterPointMake(0.0, 0.0); + layer.backing_store_present_info = &present_info; ASSERT_EQ(*layers[4], layer); } diff --git a/engine/src/flutter/shell/platform/embedder/tests/embedder_unittests.cc b/engine/src/flutter/shell/platform/embedder/tests/embedder_unittests.cc index a2f403d8f0a..5a21214a06d 100644 --- a/engine/src/flutter/shell/platform/embedder/tests/embedder_unittests.cc +++ b/engine/src/flutter/shell/platform/embedder/tests/embedder_unittests.cc @@ -671,12 +671,26 @@ TEST_F(EmbedderTest, backing_store.did_update = true; backing_store.software.height = 600; + FlutterRect paint_region_rects[] = { + FlutterRectMakeLTRB(0, 0, 800, 600), + }; + FlutterRegion paint_region = { + .struct_size = sizeof(FlutterRegion), + .rects_count = 1, + .rects = paint_region_rects, + }; + FlutterBackingStorePresentInfo present_info = { + .struct_size = sizeof(FlutterBackingStorePresentInfo), + .paint_region = &paint_region, + }; + FlutterLayer layer = {}; layer.struct_size = sizeof(layer); layer.type = kFlutterLayerContentTypeBackingStore; layer.backing_store = &backing_store; layer.size = FlutterSizeMake(800.0, 600.0); layer.offset = FlutterPointMake(0.0, 0.0); + layer.backing_store_present_info = &present_info; ASSERT_EQ(*layers[0], layer); } @@ -704,12 +718,26 @@ TEST_F(EmbedderTest, backing_store.did_update = true; backing_store.software.height = 600; + FlutterRect paint_region_rects[] = { + FlutterRectMakeLTRB(30, 30, 80, 180), + }; + FlutterRegion paint_region = { + .struct_size = sizeof(FlutterRegion), + .rects_count = 1, + .rects = paint_region_rects, + }; + FlutterBackingStorePresentInfo present_info = { + .struct_size = sizeof(FlutterBackingStorePresentInfo), + .paint_region = &paint_region, + }; + FlutterLayer layer = {}; layer.struct_size = sizeof(layer); layer.type = kFlutterLayerContentTypeBackingStore; layer.backing_store = &backing_store; layer.size = FlutterSizeMake(800.0, 600.0); layer.offset = FlutterPointMake(0.0, 0.0); + layer.backing_store_present_info = &present_info; ASSERT_EQ(*layers[2], layer); } @@ -737,12 +765,26 @@ TEST_F(EmbedderTest, backing_store.did_update = true; backing_store.software.height = 600; + FlutterRect paint_region_rects[] = { + FlutterRectMakeLTRB(50, 50, 100, 200), + }; + FlutterRegion paint_region = { + .struct_size = sizeof(FlutterRegion), + .rects_count = 1, + .rects = paint_region_rects, + }; + FlutterBackingStorePresentInfo present_info = { + .struct_size = sizeof(FlutterBackingStorePresentInfo), + .paint_region = &paint_region, + }; + FlutterLayer layer = {}; layer.struct_size = sizeof(layer); layer.type = kFlutterLayerContentTypeBackingStore; layer.backing_store = &backing_store; layer.size = FlutterSizeMake(800.0, 600.0); layer.offset = FlutterPointMake(0.0, 0.0); + layer.backing_store_present_info = &present_info; ASSERT_EQ(*layers[4], layer); } @@ -847,12 +889,26 @@ TEST_F(EmbedderTest, NoLayerCreatedForTransparentOverlayOnTopOfPlatformLayer) { backing_store.did_update = true; backing_store.software.height = 600; + FlutterRect paint_region_rects[] = { + FlutterRectMakeLTRB(0, 0, 800, 600), + }; + FlutterRegion paint_region = { + .struct_size = sizeof(FlutterRegion), + .rects_count = 1, + .rects = paint_region_rects, + }; + FlutterBackingStorePresentInfo present_info = { + .struct_size = sizeof(FlutterBackingStorePresentInfo), + .paint_region = &paint_region, + }; + FlutterLayer layer = {}; layer.struct_size = sizeof(layer); layer.type = kFlutterLayerContentTypeBackingStore; layer.backing_store = &backing_store; layer.size = FlutterSizeMake(800.0, 600.0); layer.offset = FlutterPointMake(0.0, 0.0); + layer.backing_store_present_info = &present_info; ASSERT_EQ(*layers[0], layer); } @@ -969,12 +1025,26 @@ TEST_F(EmbedderTest, NoLayerCreatedForNoOverlayOnTopOfPlatformLayer) { backing_store.did_update = true; backing_store.software.height = 600; + FlutterRect paint_region_rects[] = { + FlutterRectMakeLTRB(0, 0, 800, 600), + }; + FlutterRegion paint_region = { + .struct_size = sizeof(FlutterRegion), + .rects_count = 1, + .rects = paint_region_rects, + }; + FlutterBackingStorePresentInfo present_info = { + .struct_size = sizeof(FlutterBackingStorePresentInfo), + .paint_region = &paint_region, + }; + FlutterLayer layer = {}; layer.struct_size = sizeof(layer); layer.type = kFlutterLayerContentTypeBackingStore; layer.backing_store = &backing_store; layer.size = FlutterSizeMake(800.0, 600.0); layer.offset = FlutterPointMake(0.0, 0.0); + layer.backing_store_present_info = &present_info; ASSERT_EQ(*layers[0], layer); } @@ -1235,12 +1305,26 @@ TEST_F(EmbedderTest, VerifyB143464703WithSoftwareBackend) { backing_store.type = kFlutterBackingStoreTypeSoftware; backing_store.did_update = true; + FlutterRect paint_region_rects[] = { + FlutterRectMakeLTRB(0, 0, 1024, 600), + }; + FlutterRegion paint_region = { + .struct_size = sizeof(FlutterRegion), + .rects_count = 1, + .rects = paint_region_rects, + }; + FlutterBackingStorePresentInfo present_info = { + .struct_size = sizeof(FlutterBackingStorePresentInfo), + .paint_region = &paint_region, + }; + FlutterLayer layer = {}; layer.struct_size = sizeof(layer); layer.type = kFlutterLayerContentTypeBackingStore; layer.backing_store = &backing_store; layer.size = FlutterSizeMake(1024.0, 600.0); layer.offset = FlutterPointMake(0.0, 0.0); + layer.backing_store_present_info = &present_info; ASSERT_EQ(*layers[0], layer); } @@ -1267,12 +1351,26 @@ TEST_F(EmbedderTest, VerifyB143464703WithSoftwareBackend) { backing_store.type = kFlutterBackingStoreTypeSoftware; backing_store.did_update = true; + FlutterRect paint_region_rects[] = { + FlutterRectMakeLTRB(135, 0, 1024, 60), + }; + FlutterRegion paint_region = { + .struct_size = sizeof(FlutterRegion), + .rects_count = 1, + .rects = paint_region_rects, + }; + FlutterBackingStorePresentInfo present_info = { + .struct_size = sizeof(FlutterBackingStorePresentInfo), + .paint_region = &paint_region, + }; + FlutterLayer layer = {}; layer.struct_size = sizeof(layer); layer.type = kFlutterLayerContentTypeBackingStore; layer.backing_store = &backing_store; layer.size = FlutterSizeMake(1024.0, 600.0); layer.offset = FlutterPointMake(0.0, 0.0); + layer.backing_store_present_info = &present_info; ASSERT_EQ(*layers[2], layer); }