| // 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 <Foundation/Foundation.h> | 
 | #include <QuartzCore/QuartzCore.h> | 
 |  | 
 | #include "flutter/shell/gpu/gpu_surface_metal_impeller.h" | 
 | #include "gtest/gtest.h" | 
 | #include "impeller/entity/mtl/entity_shaders.h" | 
 | #include "impeller/entity/mtl/framebuffer_blend_shaders.h" | 
 | #include "impeller/entity/mtl/modern_shaders.h" | 
 | #include "impeller/renderer/backend/metal/context_mtl.h" | 
 |  | 
 | namespace flutter { | 
 | namespace testing { | 
 |  | 
 | class TestGPUSurfaceMetalDelegate : public GPUSurfaceMetalDelegate { | 
 |  public: | 
 |   TestGPUSurfaceMetalDelegate() : GPUSurfaceMetalDelegate(MTLRenderTargetType::kCAMetalLayer) { | 
 |     layer_ = [[CAMetalLayer alloc] init]; | 
 |   } | 
 |  | 
 |   ~TestGPUSurfaceMetalDelegate() = default; | 
 |  | 
 |   GPUCAMetalLayerHandle GetCAMetalLayer(const SkISize& frame_info) const override { | 
 |     layer_.drawableSize = CGSizeMake(frame_info.width(), frame_info.height()); | 
 |     return (__bridge GPUCAMetalLayerHandle)(layer_); | 
 |   } | 
 |  | 
 |   bool PresentDrawable(GrMTLHandle drawable) const override { return true; } | 
 |  | 
 |   GPUMTLTextureInfo GetMTLTexture(const SkISize& frame_info) const override { return {}; } | 
 |  | 
 |   bool PresentTexture(GPUMTLTextureInfo texture) const override { return true; } | 
 |  | 
 |   bool AllowsDrawingWhenGpuDisabled() const override { return true; } | 
 |  | 
 |   void SetDevice() { layer_.device = ::MTLCreateSystemDefaultDevice(); } | 
 |  | 
 |  private: | 
 |   CAMetalLayer* layer_ = nil; | 
 | }; | 
 |  | 
 | static std::shared_ptr<impeller::ContextMTL> CreateImpellerContext() { | 
 |   std::vector<std::shared_ptr<fml::Mapping>> shader_mappings = { | 
 |       std::make_shared<fml::NonOwnedMapping>(impeller_entity_shaders_data, | 
 |                                              impeller_entity_shaders_length), | 
 |       std::make_shared<fml::NonOwnedMapping>(impeller_modern_shaders_data, | 
 |                                              impeller_modern_shaders_length), | 
 |       std::make_shared<fml::NonOwnedMapping>(impeller_framebuffer_blend_shaders_data, | 
 |                                              impeller_framebuffer_blend_shaders_length), | 
 |   }; | 
 |   auto sync_switch = std::make_shared<fml::SyncSwitch>(false); | 
 |   return impeller::ContextMTL::Create(shader_mappings, sync_switch, "Impeller Library"); | 
 | } | 
 |  | 
 | TEST(GPUSurfaceMetalImpeller, InvalidImpellerContextCreatesCausesSurfaceToBeInvalid) { | 
 |   auto delegate = std::make_shared<TestGPUSurfaceMetalDelegate>(); | 
 |   auto surface = std::make_shared<GPUSurfaceMetalImpeller>(delegate.get(), nullptr); | 
 |  | 
 |   ASSERT_FALSE(surface->IsValid()); | 
 | } | 
 |  | 
 | TEST(GPUSurfaceMetalImpeller, CanCreateValidSurface) { | 
 |   auto delegate = std::make_shared<TestGPUSurfaceMetalDelegate>(); | 
 |   auto surface = std::make_shared<GPUSurfaceMetalImpeller>(delegate.get(), CreateImpellerContext()); | 
 |  | 
 |   ASSERT_TRUE(surface->IsValid()); | 
 | } | 
 |  | 
 | TEST(GPUSurfaceMetalImpeller, AcquireFrameFromCAMetalLayerNullChecksDrawable) { | 
 |   auto delegate = std::make_shared<TestGPUSurfaceMetalDelegate>(); | 
 |   std::shared_ptr<Surface> surface = | 
 |       std::make_shared<GPUSurfaceMetalImpeller>(delegate.get(), CreateImpellerContext()); | 
 |  | 
 |   ASSERT_TRUE(surface->IsValid()); | 
 |  | 
 |   auto frame = surface->AcquireFrame(SkISize::Make(100, 100)); | 
 |   ASSERT_EQ(frame, nullptr); | 
 | } | 
 |  | 
 | TEST(GPUSurfaceMetalImpeller, AcquireFrameFromCAMetalLayerDoesNotRetainThis) { | 
 |   auto delegate = std::make_shared<TestGPUSurfaceMetalDelegate>(); | 
 |   delegate->SetDevice(); | 
 |   std::unique_ptr<Surface> surface = | 
 |       std::make_unique<GPUSurfaceMetalImpeller>(delegate.get(), CreateImpellerContext()); | 
 |  | 
 |   ASSERT_TRUE(surface->IsValid()); | 
 |  | 
 |   auto frame = surface->AcquireFrame(SkISize::Make(100, 100)); | 
 |   ASSERT_TRUE(frame); | 
 |  | 
 |   // Simulate a rasterizer teardown, e.g. due to going to the background. | 
 |   surface.reset(); | 
 |  | 
 |   ASSERT_TRUE(frame->Submit()); | 
 | } | 
 |  | 
 | }  // namespace testing | 
 | }  // namespace flutter |