Wire up Metal shader precompilation from offline training runs. (flutter/engine#25644)

This commit is contained in:
Chinmay Garde
2021-04-19 16:24:02 -07:00
committed by GitHub
parent a7b67eb678
commit a0a8fb04d8
18 changed files with 476 additions and 50 deletions

View File

@@ -681,6 +681,8 @@ FILE: ../../../flutter/shell/common/shell_test_platform_view.cc
FILE: ../../../flutter/shell/common/shell_test_platform_view.h
FILE: ../../../flutter/shell/common/shell_test_platform_view_gl.cc
FILE: ../../../flutter/shell/common/shell_test_platform_view_gl.h
FILE: ../../../flutter/shell/common/shell_test_platform_view_metal.h
FILE: ../../../flutter/shell/common/shell_test_platform_view_metal.mm
FILE: ../../../flutter/shell/common/shell_test_platform_view_vulkan.cc
FILE: ../../../flutter/shell/common/shell_test_platform_view_vulkan.h
FILE: ../../../flutter/shell/common/shell_unittests.cc

View File

@@ -18,6 +18,7 @@
#include "flutter/fml/trace_event.h"
#include "flutter/shell/version/version.h"
#include "rapidjson/document.h"
#include "third_party/skia/include/gpu/GrDirectContext.h"
#include "third_party/skia/include/utils/SkBase64.h"
namespace flutter {
@@ -191,7 +192,31 @@ sk_sp<SkData> ParseBase64(const std::string& input) {
return data;
}
std::vector<PersistentCache::SkSLCache> PersistentCache::LoadSkSLs() {
size_t PersistentCache::PrecompileKnownSkSLs(GrDirectContext* context) const {
auto known_sksls = LoadSkSLs();
// A trace must be present even if no precompilations have been completed.
FML_TRACE_EVENT("flutter", "PersistentCache::PrecompileKnownSkSLs", "count",
known_sksls.size());
if (context == nullptr) {
return 0;
}
size_t precompiled_count = 0;
for (const auto& sksl : known_sksls) {
TRACE_EVENT0("flutter", "PrecompilingSkSL");
if (context->precompileShader(*sksl.first, *sksl.second)) {
precompiled_count++;
}
}
FML_TRACE_COUNTER("flutter", "PersistentCache::PrecompiledSkSLs",
reinterpret_cast<int64_t>(this), // Trace Counter ID
"Successful", precompiled_count);
return precompiled_count;
}
std::vector<PersistentCache::SkSLCache> PersistentCache::LoadSkSLs() const {
TRACE_EVENT0("flutter", "PersistentCache::LoadSkSLs");
std::vector<PersistentCache::SkSLCache> result;
fml::FileVisitor visitor = [&result](const fml::UniqueFD& directory,

View File

@@ -72,7 +72,22 @@ class PersistentCache : public GrContextOptions::PersistentCache {
using SkSLCache = std::pair<sk_sp<SkData>, sk_sp<SkData>>;
/// Load all the SkSL shader caches in the right directory.
std::vector<SkSLCache> LoadSkSLs();
std::vector<SkSLCache> LoadSkSLs() const;
//----------------------------------------------------------------------------
/// @brief Precompile SkSLs packaged with the application and gathered
/// during previous runs in the given context.
///
/// @warning The context must be the rendering context. This context may be
/// destroyed during application suspension and subsequently
/// recreated. The SkSLs must be precompiled again in the new
/// context.
///
/// @param context The rendering context to precompile shaders in.
///
/// @return The number of SkSLs precompiled.
///
size_t PrecompileKnownSkSLs(GrDirectContext* context) const;
// Return mappings for all skp's accessible through the AssetManager
std::vector<std::unique_ptr<fml::Mapping>> GetSkpsFromAssetManager() const;
@@ -82,7 +97,9 @@ class PersistentCache : public GrContextOptions::PersistentCache {
static void SetAssetManager(std::shared_ptr<AssetManager> value);
static bool cache_sksl() { return cache_sksl_; }
static void SetCacheSkSL(bool value);
static void MarkStrategySet() { strategy_set_ = true; }
static constexpr char kSkSLSubdirName[] = "sksl";

View File

@@ -232,6 +232,15 @@ if (enable_unittests) {
public_deps += [ "//flutter/vulkan" ]
}
if (test_enable_metal) {
sources += [
"shell_test_platform_view_metal.h",
"shell_test_platform_view_metal.mm",
]
public_deps += [ "//flutter/shell/platform/darwin/graphics" ]
}
}
shell_host_executable("shell_unittests") {

View File

@@ -24,6 +24,8 @@
namespace flutter {
namespace testing {
using PersistentCacheTest = ShellTest;
static void WaitForIO(Shell* shell) {
std::promise<bool> io_task_finished;
shell->GetTaskRunners().GetIOTaskRunner()->PostTask(
@@ -31,7 +33,14 @@ static void WaitForIO(Shell* shell) {
io_task_finished.get_future().wait();
}
TEST_F(ShellTest, CacheSkSLWorks) {
static void WaitForRaster(Shell* shell) {
std::promise<bool> raster_task_finished;
shell->GetTaskRunners().GetRasterTaskRunner()->PostTask(
[&raster_task_finished]() { raster_task_finished.set_value(true); });
raster_task_finished.get_future().wait();
}
TEST_F(PersistentCacheTest, CacheSkSLWorks) {
// Create a temp dir to store the persistent cache
fml::ScopedTemporaryDirectory dir;
PersistentCache::SetCacheDirectoryPath(dir.path());
@@ -41,9 +50,11 @@ TEST_F(ShellTest, CacheSkSLWorks) {
settings.cache_sksl = true;
settings.dump_skp_on_shader_compilation = true;
fml::AutoResetWaitableEvent firstFrameLatch;
fml::AutoResetWaitableEvent first_frame_latch;
settings.frame_rasterized_callback =
[&firstFrameLatch](const FrameTiming& t) { firstFrameLatch.Signal(); };
[&first_frame_latch](const FrameTiming& t) {
first_frame_latch.Signal();
};
auto sksl_config = RunConfiguration::InferFromSettings(settings);
sksl_config.SetEntrypoint("emptyMain");
@@ -64,7 +75,7 @@ TEST_F(ShellTest, CacheSkSLWorks) {
root->Add(physical_shape_layer);
};
PumpOneFrame(shell.get(), 100, 100, builder);
firstFrameLatch.Wait();
first_frame_latch.Wait();
WaitForIO(shell.get());
// Some skp should be dumped due to shader compilations.
@@ -95,14 +106,14 @@ TEST_F(ShellTest, CacheSkSLWorks) {
shell = CreateShell(settings);
PlatformViewNotifyCreated(shell.get());
RunEngine(shell.get(), std::move(normal_config));
firstFrameLatch.Reset();
first_frame_latch.Reset();
PumpOneFrame(shell.get(), 100, 100, builder);
firstFrameLatch.Wait();
first_frame_latch.Wait();
WaitForIO(shell.get());
// Shader precompilation from SKSL is not implemented on the Skia Vulkan
// Shader precompilation from SkSL is not implemented on the Skia Vulkan
// backend so don't run the second half of this test on Vulkan. This can get
// removed if SKSL precompilation is implemented in the Skia Vulkan backend.
// removed if SkSL precompilation is implemented in the Skia Vulkan backend.
#if !defined(SHELL_ENABLE_VULKAN)
// To check that all shaders are precompiled, verify that no new skp is dumped
// due to shader compilations.
@@ -113,22 +124,66 @@ TEST_F(ShellTest, CacheSkSLWorks) {
#endif // !defined(SHELL_ENABLE_VULKAN)
// Remove all files generated
fml::FileVisitor remove_visitor = [&remove_visitor](
const fml::UniqueFD& directory,
const std::string& filename) {
if (fml::IsDirectory(directory, filename.c_str())) {
{ // To trigger fml::~UniqueFD before fml::UnlinkDirectory
fml::UniqueFD sub_dir =
fml::OpenDirectoryReadOnly(directory, filename.c_str());
fml::VisitFiles(sub_dir, remove_visitor);
}
fml::UnlinkDirectory(directory, filename.c_str());
} else {
fml::UnlinkFile(directory, filename.c_str());
}
return true;
fml::RemoveFilesInDirectory(dir.fd());
DestroyShell(std::move(shell));
}
TEST_F(PersistentCacheTest, CanPrecompileMetalShaders) {
#if !SHELL_ENABLE_METAL
GTEST_SKIP();
#endif // !SHELL_ENABLE_METAL
fml::ScopedTemporaryDirectory dir;
PersistentCache::SetCacheDirectoryPath(dir.path());
PersistentCache::ResetCacheForProcess();
auto settings = CreateSettingsForFixture();
settings.cache_sksl = true;
settings.dump_skp_on_shader_compilation = true;
fml::AutoResetWaitableEvent first_frame_latch;
settings.frame_rasterized_callback =
[&first_frame_latch](const FrameTiming& t) {
first_frame_latch.Signal();
};
auto sksl_config = RunConfiguration::InferFromSettings(settings);
sksl_config.SetEntrypoint("emptyMain");
std::unique_ptr<Shell> shell =
CreateShell(settings, //
GetTaskRunnersForFixture(), //
false, //
nullptr, //
false, //
ShellTestPlatformView::BackendType::kMetalBackend //
);
PlatformViewNotifyCreated(shell.get());
RunEngine(shell.get(), std::move(sksl_config));
// Initially, we should have no SkSL cache
{
auto empty_cache = PersistentCache::GetCacheForProcess()->LoadSkSLs();
ASSERT_EQ(empty_cache.size(), 0u);
}
// Draw something to trigger shader compilations.
LayerTreeBuilder builder = [](std::shared_ptr<ContainerLayer> root) {
SkPath path;
path.addCircle(50, 50, 20);
auto physical_shape_layer = std::make_shared<PhysicalShapeLayer>(
SK_ColorRED, SK_ColorBLUE, 1.0f, path, Clip::antiAlias);
root->Add(physical_shape_layer);
};
fml::VisitFiles(dir.fd(), remove_visitor);
PumpOneFrame(shell.get(), 100, 100, builder);
first_frame_latch.Wait();
WaitForRaster(shell.get());
WaitForIO(shell.get());
// Assert that SkSLs have been generated.
auto filled_cache = PersistentCache::GetCacheForProcess()->LoadSkSLs();
ASSERT_GT(filled_cache.size(), 0u);
// Remove all files generated.
fml::RemoveFilesInDirectory(dir.fd());
DestroyShell(std::move(shell));
}
@@ -148,7 +203,7 @@ static void CheckTwoSkSLsAreLoaded() {
ASSERT_EQ(shaders.size(), 2u);
}
TEST_F(ShellTest, CanLoadSkSLsFromAsset) {
TEST_F(PersistentCacheTest, CanLoadSkSLsFromAsset) {
// Avoid polluting unit tests output by hiding INFO level logging.
fml::LogSettings warning_only = {fml::LOG_WARNING};
fml::ScopedSetLogSettings scoped_set_log_settings(warning_only);
@@ -212,7 +267,7 @@ TEST_F(ShellTest, CanLoadSkSLsFromAsset) {
fml::UnlinkFile(asset_dir.fd(), PersistentCache::kAssetFileName);
}
TEST_F(ShellTest, CanRemoveOldPersistentCache) {
TEST_F(PersistentCacheTest, CanRemoveOldPersistentCache) {
fml::ScopedTemporaryDirectory base_dir;
ASSERT_TRUE(base_dir.fd().is_valid());
@@ -242,7 +297,7 @@ TEST_F(ShellTest, CanRemoveOldPersistentCache) {
fml::RemoveFilesInDirectory(base_dir.fd());
}
TEST_F(ShellTest, CanPurgePersistentCache) {
TEST_F(PersistentCacheTest, CanPurgePersistentCache) {
fml::ScopedTemporaryDirectory base_dir;
ASSERT_TRUE(base_dir.fd().is_valid());
auto cache_dir = fml::CreateDirectory(
@@ -274,7 +329,7 @@ TEST_F(ShellTest, CanPurgePersistentCache) {
DestroyShell(std::move(shell));
}
TEST_F(ShellTest, PurgeAllowsFutureSkSLCache) {
TEST_F(PersistentCacheTest, PurgeAllowsFutureSkSLCache) {
sk_sp<SkData> shader_key = SkData::MakeWithCString("key");
sk_sp<SkData> shader_value = SkData::MakeWithCString("value");
std::string shader_filename = PersistentCache::SkKeyToFilePath(*shader_key);

View File

@@ -315,8 +315,10 @@ std::unique_ptr<Shell> ShellTest::CreateShell(
bool simulate_vsync,
std::shared_ptr<ShellTestExternalViewEmbedder>
shell_test_external_view_embedder,
bool is_gpu_disabled) {
bool is_gpu_disabled,
ShellTestPlatformView::BackendType rendering_backend) {
const auto vsync_clock = std::make_shared<ShellTestVsyncClock>();
CreateVsyncWaiter create_vsync_waiter = [&]() {
if (simulate_vsync) {
return static_cast<std::unique_ptr<VsyncWaiter>>(
@@ -326,19 +328,35 @@ std::unique_ptr<Shell> ShellTest::CreateShell(
std::make_unique<VsyncWaiterFallback>(task_runners));
}
};
return Shell::Create(
flutter::PlatformData(), task_runners, settings,
[vsync_clock, &create_vsync_waiter,
shell_test_external_view_embedder](Shell& shell) {
Shell::CreateCallback<PlatformView> platfrom_view_create_callback =
[vsync_clock, //
&create_vsync_waiter, //
shell_test_external_view_embedder, //
rendering_backend //
](Shell& shell) {
return ShellTestPlatformView::Create(
shell, shell.GetTaskRunners(), vsync_clock,
std::move(create_vsync_waiter),
ShellTestPlatformView::BackendType::kDefaultBackend,
shell_test_external_view_embedder);
},
[](Shell& shell) { return std::make_unique<Rasterizer>(shell); },
is_gpu_disabled);
shell, //
shell.GetTaskRunners(), //
vsync_clock, //
std::move(create_vsync_waiter), //
rendering_backend, //
shell_test_external_view_embedder //
);
};
Shell::CreateCallback<Rasterizer> rasterizer_create_callback =
[](Shell& shell) { return std::make_unique<Rasterizer>(shell); };
return Shell::Create(flutter::PlatformData(), //
task_runners, //
settings, //
platfrom_view_create_callback, //
rasterizer_create_callback, //
is_gpu_disabled //
);
}
void ShellTest::DestroyShell(std::unique_ptr<Shell> shell) {
DestroyShell(std::move(shell), GetTaskRunnersForFixture());
}

View File

@@ -18,6 +18,7 @@
#include "flutter/lib/ui/window/platform_message.h"
#include "flutter/shell/common/run_configuration.h"
#include "flutter/shell/common/shell_test_external_view_embedder.h"
#include "flutter/shell/common/shell_test_platform_view.h"
#include "flutter/shell/common/thread_host.h"
#include "flutter/shell/common/vsync_waiters_test.h"
#include "flutter/testing/elf_loader.h"
@@ -40,7 +41,9 @@ class ShellTest : public FixtureTest {
bool simulate_vsync = false,
std::shared_ptr<ShellTestExternalViewEmbedder>
shell_test_external_view_embedder = nullptr,
bool is_gpu_disabled = false);
bool is_gpu_disabled = false,
ShellTestPlatformView::BackendType rendering_backend =
ShellTestPlatformView::BackendType::kDefaultBackend);
void DestroyShell(std::unique_ptr<Shell> shell);
void DestroyShell(std::unique_ptr<Shell> shell, TaskRunners task_runners);
TaskRunners GetTaskRunnersForFixture();

View File

@@ -10,6 +10,9 @@
#ifdef SHELL_ENABLE_VULKAN
#include "flutter/shell/common/shell_test_platform_view_vulkan.h"
#endif // SHELL_ENABLE_VULKAN
#ifdef SHELL_ENABLE_METAL
#include "flutter/shell/common/shell_test_platform_view_metal.h"
#endif // SHELL_ENABLE_METAL
namespace flutter {
namespace testing {
@@ -38,6 +41,13 @@ std::unique_ptr<ShellTestPlatformView> ShellTestPlatformView::Create(
delegate, task_runners, vsync_clock, create_vsync_waiter,
shell_test_external_view_embedder);
#endif // SHELL_ENABLE_VULKAN
#ifdef SHELL_ENABLE_METAL
case BackendType::kMetalBackend:
return std::make_unique<ShellTestPlatformViewMetal>(
delegate, task_runners, vsync_clock, create_vsync_waiter,
shell_test_external_view_embedder);
#endif // SHELL_ENABLE_METAL
default:
FML_LOG(FATAL) << "No backends supported for ShellTestPlatformView";
return nullptr;

View File

@@ -17,6 +17,7 @@ class ShellTestPlatformView : public PlatformView {
enum class BackendType {
kGLBackend,
kVulkanBackend,
kMetalBackend,
kDefaultBackend,
};

View File

@@ -28,6 +28,7 @@ std::unique_ptr<VsyncWaiter> ShellTestPlatformViewGL::CreateVSyncWaiter() {
return create_vsync_waiter_();
}
// |ShellTestPlatformView|
void ShellTestPlatformViewGL::SimulateVSync() {
vsync_clock_->SimulateVSync();
}

View File

@@ -23,8 +23,10 @@ class ShellTestPlatformViewGL : public ShellTestPlatformView,
std::shared_ptr<ShellTestExternalViewEmbedder>
shell_test_external_view_embedder);
// |ShellTestPlatformView|
virtual ~ShellTestPlatformViewGL() override;
// |ShellTestPlatformView|
virtual void SimulateVSync() override;
private:

View File

@@ -0,0 +1,71 @@
// 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.
#ifndef FLUTTER_SHELL_COMMON_SHELL_TEST_PLATFORM_VIEW_METAL_H_
#define FLUTTER_SHELL_COMMON_SHELL_TEST_PLATFORM_VIEW_METAL_H_
#include "flutter/fml/macros.h"
#include "flutter/shell/common/shell_test_platform_view.h"
#include "flutter/shell/gpu/gpu_surface_metal_delegate.h"
namespace flutter {
namespace testing {
class DarwinContextMetal;
class ShellTestPlatformViewMetal final : public ShellTestPlatformView,
public GPUSurfaceMetalDelegate {
public:
ShellTestPlatformViewMetal(PlatformView::Delegate& delegate,
TaskRunners task_runners,
std::shared_ptr<ShellTestVsyncClock> vsync_clock,
CreateVsyncWaiter create_vsync_waiter,
std::shared_ptr<ShellTestExternalViewEmbedder>
shell_test_external_view_embedder);
// |ShellTestPlatformView|
virtual ~ShellTestPlatformViewMetal() override;
private:
const std::unique_ptr<DarwinContextMetal> metal_context_;
const CreateVsyncWaiter create_vsync_waiter_;
const std::shared_ptr<ShellTestVsyncClock> vsync_clock_;
const std::shared_ptr<ShellTestExternalViewEmbedder>
shell_test_external_view_embedder_;
// |ShellTestPlatformView|
virtual void SimulateVSync() override;
// |PlatformView|
std::unique_ptr<VsyncWaiter> CreateVSyncWaiter() override;
// |PlatformView|
std::shared_ptr<ExternalViewEmbedder> CreateExternalViewEmbedder() override;
// |PlatformView|
PointerDataDispatcherMaker GetDispatcherMaker() override;
// |PlatformView|
std::unique_ptr<Surface> CreateRenderingSurface() override;
// |GPUSurfaceMetalDelegate|
GPUCAMetalLayerHandle GetCAMetalLayer(
const SkISize& frame_info) const override;
// |GPUSurfaceMetalDelegate|
bool PresentDrawable(GrMTLHandle drawable) const override;
// |GPUSurfaceMetalDelegate|
GPUMTLTextureInfo GetMTLTexture(const SkISize& frame_info) const override;
// |GPUSurfaceMetalDelegate|
bool PresentTexture(GPUMTLTextureInfo texture) const override;
FML_DISALLOW_COPY_AND_ASSIGN(ShellTestPlatformViewMetal);
};
} // namespace testing
} // namespace flutter
#endif // FLUTTER_SHELL_COMMON_SHELL_TEST_PLATFORM_VIEW_METAL_H_

View File

@@ -0,0 +1,123 @@
// 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 "flutter/shell/common/shell_test_platform_view_metal.h"
#import <Metal/Metal.h>
#include "flutter/fml/platform/darwin/scoped_nsobject.h"
#include "flutter/shell/gpu/gpu_surface_metal.h"
#include "flutter/shell/platform/darwin/graphics/FlutterDarwinContextMetal.h"
namespace flutter {
namespace testing {
static fml::scoped_nsprotocol<id<MTLTexture>> CreateOffscreenTexture(id<MTLDevice> device) {
auto descriptor =
[MTLTextureDescriptor texture2DDescriptorWithPixelFormat:MTLPixelFormatBGRA8Unorm
width:800
height:600
mipmapped:NO];
descriptor.usage = MTLTextureUsageRenderTarget | MTLTextureUsageShaderRead;
return fml::scoped_nsprotocol<id<MTLTexture>>{[device newTextureWithDescriptor:descriptor]};
}
// This is out of the header so that shell_test_platform_view_metal.h can be included in
// non-Objective-C TUs.
class DarwinContextMetal {
public:
DarwinContextMetal()
: context_([[FlutterDarwinContextMetal alloc] initWithDefaultMTLDevice]),
offscreen_texture_(CreateOffscreenTexture([context_.get() device])) {}
~DarwinContextMetal() = default;
fml::scoped_nsobject<FlutterDarwinContextMetal> context() const { return context_; }
fml::scoped_nsprotocol<id<MTLTexture>> offscreen_texture() const { return offscreen_texture_; }
GPUMTLTextureInfo offscreen_texture_info() const {
GPUMTLTextureInfo info = {};
info.texture_id = 0;
info.texture = reinterpret_cast<GPUMTLTextureHandle>(offscreen_texture_.get());
return info;
}
private:
const fml::scoped_nsobject<FlutterDarwinContextMetal> context_;
const fml::scoped_nsprotocol<id<MTLTexture>> offscreen_texture_;
FML_DISALLOW_COPY_AND_ASSIGN(DarwinContextMetal);
};
ShellTestPlatformViewMetal::ShellTestPlatformViewMetal(
PlatformView::Delegate& delegate,
TaskRunners task_runners,
std::shared_ptr<ShellTestVsyncClock> vsync_clock,
CreateVsyncWaiter create_vsync_waiter,
std::shared_ptr<ShellTestExternalViewEmbedder> shell_test_external_view_embedder)
: ShellTestPlatformView(delegate, std::move(task_runners)),
GPUSurfaceMetalDelegate(MTLRenderTargetType::kMTLTexture),
metal_context_(std::make_unique<DarwinContextMetal>()),
create_vsync_waiter_(std::move(create_vsync_waiter)),
vsync_clock_(vsync_clock),
shell_test_external_view_embedder_(shell_test_external_view_embedder) {
FML_CHECK([metal_context_->context() mainContext] != nil);
}
ShellTestPlatformViewMetal::~ShellTestPlatformViewMetal() = default;
std::unique_ptr<VsyncWaiter> ShellTestPlatformViewMetal::CreateVSyncWaiter() {
return create_vsync_waiter_();
}
// |ShellTestPlatformView|
void ShellTestPlatformViewMetal::SimulateVSync() {
vsync_clock_->SimulateVSync();
}
// |PlatformView|
std::shared_ptr<ExternalViewEmbedder> ShellTestPlatformViewMetal::CreateExternalViewEmbedder() {
return shell_test_external_view_embedder_;
}
// |PlatformView|
PointerDataDispatcherMaker ShellTestPlatformViewMetal::GetDispatcherMaker() {
return [](DefaultPointerDataDispatcher::Delegate& delegate) {
return std::make_unique<SmoothPointerDataDispatcher>(delegate);
};
}
// |PlatformView|
std::unique_ptr<Surface> ShellTestPlatformViewMetal::CreateRenderingSurface() {
return std::make_unique<GPUSurfaceMetal>(this, [metal_context_->context() mainContext]);
}
// |GPUSurfaceMetalDelegate|
GPUCAMetalLayerHandle ShellTestPlatformViewMetal::GetCAMetalLayer(const SkISize& frame_info) const {
FML_CHECK(false) << "A Metal Delegate configured with MTLRenderTargetType::kMTLTexture was asked "
"to acquire a layer.";
return nullptr;
}
// |GPUSurfaceMetalDelegate|
bool ShellTestPlatformViewMetal::PresentDrawable(GrMTLHandle drawable) const {
FML_CHECK(false) << "A Metal Delegate configured with MTLRenderTargetType::kMTLTexture was asked "
"to present a layer drawable.";
return true;
}
// |GPUSurfaceMetalDelegate|
GPUMTLTextureInfo ShellTestPlatformViewMetal::GetMTLTexture(const SkISize& frame_info) const {
return metal_context_->offscreen_texture_info();
}
// |GPUSurfaceMetalDelegate|
bool ShellTestPlatformViewMetal::PresentTexture(GPUMTLTextureInfo texture) const {
// The texture resides offscreen. There is nothing to render to.
return true;
}
} // namespace testing
} // namespace flutter

View File

@@ -2765,5 +2765,78 @@ TEST_F(ShellTest, UpdateAssetResolverByTypeDoesNotReplaceMismatchType) {
ASSERT_FALSE(DartVMRef::IsInstanceRunning());
}
TEST_F(ShellTest, CanCreateShellsWithGLBackend) {
#if !SHELL_ENABLE_GL
// GL emulation does not exist on Fuchsia.
GTEST_SKIP();
#endif // !SHELL_ENABLE_GL
auto settings = CreateSettingsForFixture();
std::unique_ptr<Shell> shell =
CreateShell(settings, //
GetTaskRunnersForFixture(), //
false, //
nullptr, //
false, //
ShellTestPlatformView::BackendType::kGLBackend //
);
ASSERT_NE(shell, nullptr);
ASSERT_TRUE(shell->IsSetup());
PlatformViewNotifyCreated(shell.get());
auto configuration = RunConfiguration::InferFromSettings(settings);
configuration.SetEntrypoint("emptyMain");
RunEngine(shell.get(), std::move(configuration));
PumpOneFrame(shell.get());
PlatformViewNotifyDestroyed(shell.get());
DestroyShell(std::move(shell));
}
TEST_F(ShellTest, CanCreateShellsWithVulkanBackend) {
#if !SHELL_ENABLE_VULKAN
GTEST_SKIP();
#endif // !SHELL_ENABLE_VULKAN
auto settings = CreateSettingsForFixture();
std::unique_ptr<Shell> shell =
CreateShell(settings, //
GetTaskRunnersForFixture(), //
false, //
nullptr, //
false, //
ShellTestPlatformView::BackendType::kVulkanBackend //
);
ASSERT_NE(shell, nullptr);
ASSERT_TRUE(shell->IsSetup());
PlatformViewNotifyCreated(shell.get());
auto configuration = RunConfiguration::InferFromSettings(settings);
configuration.SetEntrypoint("emptyMain");
RunEngine(shell.get(), std::move(configuration));
PumpOneFrame(shell.get());
PlatformViewNotifyDestroyed(shell.get());
DestroyShell(std::move(shell));
}
TEST_F(ShellTest, CanCreateShellsWithMetalBackend) {
#if !SHELL_ENABLE_METAL
GTEST_SKIP();
#endif // !SHELL_ENABLE_METAL
auto settings = CreateSettingsForFixture();
std::unique_ptr<Shell> shell =
CreateShell(settings, //
GetTaskRunnersForFixture(), //
false, //
nullptr, //
false, //
ShellTestPlatformView::BackendType::kMetalBackend //
);
ASSERT_NE(shell, nullptr);
ASSERT_TRUE(shell->IsSetup());
PlatformViewNotifyCreated(shell.get());
auto configuration = RunConfiguration::InferFromSettings(settings);
configuration.SetEntrypoint("emptyMain");
RunEngine(shell.get(), std::move(configuration));
PumpOneFrame(shell.get());
PlatformViewNotifyDestroyed(shell.get());
DestroyShell(std::move(shell));
}
} // namespace testing
} // namespace flutter

View File

@@ -70,14 +70,7 @@ sk_sp<GrDirectContext> GPUSurfaceGL::MakeGLContext(
context->setResourceCacheLimits(kGrCacheMaxCount, kGrCacheMaxByteSize);
std::vector<PersistentCache::SkSLCache> caches =
PersistentCache::GetCacheForProcess()->LoadSkSLs();
int compiled_count = 0;
for (const auto& cache : caches) {
compiled_count += context->precompileShader(*cache.first, *cache.second);
}
FML_LOG(INFO) << "Found " << caches.size() << " SkSL shaders; precompiled "
<< compiled_count;
PersistentCache::GetCacheForProcess()->PrecompileKnownSkSLs(context.get());
return context;
}

View File

@@ -29,6 +29,7 @@ class SK_API_AVAILABLE_CA_METAL_LAYER GPUSurfaceMetal : public Surface {
const MTLRenderTargetType render_target_type_;
GrMTLHandle next_drawable_ = nullptr;
sk_sp<GrDirectContext> context_;
GrDirectContext* precompiled_sksl_context_ = nullptr;
// |Surface|
std::unique_ptr<SurfaceFrame> AcquireFrame(const SkISize& size) override;
@@ -50,6 +51,8 @@ class SK_API_AVAILABLE_CA_METAL_LAYER GPUSurfaceMetal : public Surface {
void ReleaseUnusedDrawableIfNecessary();
void PrecompileKnownSkSLsIfNecessary();
FML_DISALLOW_COPY_AND_ASSIGN(GPUSurfaceMetal);
};

View File

@@ -6,6 +6,7 @@
#import <Metal/Metal.h>
#include "flutter/common/graphics/persistent_cache.h"
#include "flutter/fml/make_copyable.h"
#include "flutter/fml/platform/darwin/cf_utils.h"
#include "flutter/fml/trace_event.h"
@@ -32,6 +33,16 @@ bool GPUSurfaceMetal::IsValid() {
return context_ != nullptr;
}
void GPUSurfaceMetal::PrecompileKnownSkSLsIfNecessary() {
auto* current_context = GetContext();
if (current_context == precompiled_sksl_context_) {
// Known SkSLs have already been prepared in this context.
return;
}
precompiled_sksl_context_ = current_context;
flutter::PersistentCache::GetCacheForProcess()->PrecompileKnownSkSLs(precompiled_sksl_context_);
}
// |Surface|
std::unique_ptr<SurfaceFrame> GPUSurfaceMetal::AcquireFrame(const SkISize& frame_size) {
if (!IsValid()) {
@@ -44,6 +55,8 @@ std::unique_ptr<SurfaceFrame> GPUSurfaceMetal::AcquireFrame(const SkISize& frame
return nullptr;
}
PrecompileKnownSkSLsIfNecessary();
switch (render_target_type_) {
case MTLRenderTargetType::kCAMetalLayer:
return AcquireFrameFromCAMetalLayer(frame_size);
@@ -155,6 +168,10 @@ GrDirectContext* GPUSurfaceMetal::GetContext() {
// |Surface|
std::unique_ptr<GLContextResult> GPUSurfaceMetal::MakeRenderContextCurrent() {
// A context may either be necessary to render to the surface or to snapshot an offscreen
// surface. Either way, SkSL precompilation must be attempted.
PrecompileKnownSkSLsIfNecessary();
// This backend has no such concept.
return std::make_unique<GLContextDefaultResult>(true);
}

View File

@@ -59,6 +59,9 @@ static GrContextOptions CreateMetalGrContextOptions() {
return nil;
}
// The devices are in the same "sharegroup" because they share the same device and command
// queues for now. When the resource context gets its own transfer queue, this will have to be
// refactored.
_mainContext = [self createGrContext];
_resourceContext = [self createGrContext];