Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit b0310da

Browse files
author
Jonah Williams
authored
[Impeller] null check drawable. (#47488)
Speculative fix for the first crash noted in flutter/flutter#136628 (comment) nextDrawble can return null if the method times out. Fixes flutter/flutter#136525
1 parent 117d47a commit b0310da

File tree

6 files changed

+112
-1
lines changed

6 files changed

+112
-1
lines changed

BUILD.gn

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,7 @@ group("unittests") {
196196
if (is_mac) {
197197
public_deps += [
198198
"//flutter/impeller/golden_tests:impeller_golden_tests",
199+
"//flutter/shell/gpu:gpu_surface_metal_unittests",
199200
"//flutter/shell/platform/darwin/common:framework_common_unittests",
200201
"//flutter/third_party/spring_animation:spring_animation_unittests",
201202
]

ci/licenses_golden/excluded_files

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,7 @@
256256
../../../flutter/shell/common/switches_unittests.cc
257257
../../../flutter/shell/common/variable_refresh_rate_display_unittests.cc
258258
../../../flutter/shell/common/vsync_waiter_unittests.cc
259+
../../../flutter/shell/gpu/gpu_surface_metal_impeller_unittests.mm
259260
../../../flutter/shell/platform/android/.gitignore
260261
../../../flutter/shell/platform/android/android_context_gl_impeller_unittests.cc
261262
../../../flutter/shell/platform/android/android_context_gl_unittests.cc

shell/gpu/BUILD.gn

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,3 +88,27 @@ source_set("gpu_surface_metal") {
8888
public_deps += [ "//flutter/impeller" ]
8989
}
9090
}
91+
92+
if (is_mac) {
93+
impeller_component("gpu_surface_metal_unittests") {
94+
testonly = true
95+
target_type = "executable"
96+
sources = [ "gpu_surface_metal_impeller_unittests.mm" ]
97+
98+
frameworks = [
99+
"AppKit.framework",
100+
"QuartzCore.framework",
101+
]
102+
103+
deps = [
104+
"//flutter/testing",
105+
":gpu_surface_metal",
106+
"//flutter/impeller/fixtures",
107+
"//flutter/fml",
108+
"//flutter/fml/dart",
109+
"//flutter/runtime",
110+
"//flutter/runtime:libdart",
111+
"//flutter/testing",
112+
] + gpu_common_deps
113+
}
114+
}

shell/gpu/gpu_surface_metal_impeller.mm

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@
5151

5252
// |Surface|
5353
bool GPUSurfaceMetalImpeller::IsValid() {
54-
return !!aiks_context_;
54+
return !!aiks_context_ && aiks_context_->IsValid();
5555
}
5656

5757
// |Surface|
@@ -99,6 +99,9 @@
9999

100100
auto drawable = impeller::SurfaceMTL::GetMetalDrawableAndValidate(
101101
impeller_renderer_->GetContext(), mtl_layer);
102+
if (!drawable) {
103+
return nullptr;
104+
}
102105
if (Settings::kSurfaceDataAccessible) {
103106
last_texture_.reset([drawable.texture retain]);
104107
}
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
// Copyright 2013 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
#include <Foundation/Foundation.h>
6+
#include <QuartzCore/QuartzCore.h>
7+
8+
#include "flutter/shell/gpu/gpu_surface_metal_impeller.h"
9+
#include "gtest/gtest.h"
10+
#include "impeller/entity/mtl/entity_shaders.h"
11+
#include "impeller/entity/mtl/framebuffer_blend_shaders.h"
12+
#include "impeller/entity/mtl/modern_shaders.h"
13+
#include "impeller/renderer/backend/metal/context_mtl.h"
14+
15+
namespace flutter {
16+
namespace testing {
17+
18+
class TestGPUSurfaceMetalDelegate : public GPUSurfaceMetalDelegate {
19+
public:
20+
TestGPUSurfaceMetalDelegate() : GPUSurfaceMetalDelegate(MTLRenderTargetType::kCAMetalLayer) {
21+
layer_ = [[CAMetalLayer alloc] init];
22+
}
23+
24+
~TestGPUSurfaceMetalDelegate() = default;
25+
26+
GPUCAMetalLayerHandle GetCAMetalLayer(const SkISize& frame_info) const override {
27+
return (__bridge GPUCAMetalLayerHandle)(layer_);
28+
}
29+
30+
bool PresentDrawable(GrMTLHandle drawable) const override { return true; }
31+
32+
GPUMTLTextureInfo GetMTLTexture(const SkISize& frame_info) const override { return {}; }
33+
34+
bool PresentTexture(GPUMTLTextureInfo texture) const override { return true; }
35+
36+
bool AllowsDrawingWhenGpuDisabled() const override { return true; }
37+
38+
private:
39+
CAMetalLayer* layer_ = nil;
40+
};
41+
42+
static std::shared_ptr<impeller::ContextMTL> CreateImpellerContext() {
43+
std::vector<std::shared_ptr<fml::Mapping>> shader_mappings = {
44+
std::make_shared<fml::NonOwnedMapping>(impeller_entity_shaders_data,
45+
impeller_entity_shaders_length),
46+
std::make_shared<fml::NonOwnedMapping>(impeller_modern_shaders_data,
47+
impeller_modern_shaders_length),
48+
std::make_shared<fml::NonOwnedMapping>(impeller_framebuffer_blend_shaders_data,
49+
impeller_framebuffer_blend_shaders_length),
50+
};
51+
auto sync_switch = std::make_shared<fml::SyncSwitch>(false);
52+
return impeller::ContextMTL::Create(shader_mappings, sync_switch, "Impeller Library");
53+
}
54+
55+
TEST(GPUSurfaceMetalImpeller, InvalidImpellerContextCreatesCausesSurfaceToBeInvalid) {
56+
auto delegate = std::make_shared<TestGPUSurfaceMetalDelegate>();
57+
auto surface = std::make_shared<GPUSurfaceMetalImpeller>(delegate.get(), nullptr);
58+
59+
ASSERT_FALSE(surface->IsValid());
60+
}
61+
62+
TEST(GPUSurfaceMetalImpeller, CanCreateValidSurface) {
63+
auto delegate = std::make_shared<TestGPUSurfaceMetalDelegate>();
64+
auto surface = std::make_shared<GPUSurfaceMetalImpeller>(delegate.get(), CreateImpellerContext());
65+
66+
ASSERT_TRUE(surface->IsValid());
67+
}
68+
69+
TEST(GPUSurfaceMetalImpeller, AcquireFrameFromCAMetalLayerNullChecksDrawable) {
70+
auto delegate = std::make_shared<TestGPUSurfaceMetalDelegate>();
71+
std::shared_ptr<Surface> surface =
72+
std::make_shared<GPUSurfaceMetalImpeller>(delegate.get(), CreateImpellerContext());
73+
74+
ASSERT_TRUE(surface->IsValid());
75+
76+
auto frame = surface->AcquireFrame(SkISize::Make(100, 100));
77+
ASSERT_EQ(frame, nullptr);
78+
}
79+
80+
} // namespace testing
81+
} // namespace flutter

testing/run_tests.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -437,6 +437,7 @@ def make_test(name, flags=None, extra_env=None):
437437
make_test('accessibility_unittests'),
438438
make_test('framework_common_unittests'),
439439
make_test('spring_animation_unittests'),
440+
make_test('gpu_surface_metal_unittests'),
440441
]
441442

442443
if is_linux():

0 commit comments

Comments
 (0)