Flutter Engine
test_metal_surface_impl.mm
Go to the documentation of this file.
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 "flutter/testing/test_metal_surface_impl.h"
6 
7 #include <Metal/Metal.h>
8 
9 #include "flutter/fml/logging.h"
10 #include "flutter/fml/platform/darwin/scoped_nsobject.h"
11 #include "third_party/skia/include/core/SkSurface.h"
12 
13 namespace flutter {
14 
16  if (surface_size.isEmpty()) {
17  FML_LOG(ERROR) << "Size of test Metal surface was empty.";
18  return;
19  }
20 
21  auto device = fml::scoped_nsobject{[MTLCreateSystemDefaultDevice() retain]};
22  if (!device) {
23  FML_LOG(ERROR) << "Could not acquire Metal device.";
24  return;
25  }
26 
27  auto command_queue = fml::scoped_nsobject{[device.get() newCommandQueue]};
28  if (!command_queue) {
29  FML_LOG(ERROR) << "Could not create the default command queue.";
30  return;
31  }
32 
33  auto texture_descriptor = fml::scoped_nsobject{
34  [[MTLTextureDescriptor texture2DDescriptorWithPixelFormat:MTLPixelFormatBGRA8Unorm
35  width:surface_size.width()
36  height:surface_size.height()
37  mipmapped:NO] retain]};
38 
39  // The most pessimistic option and disables all optimizations but allows tests
40  // the most flexible access to the surface. They may read and write to the
41  // surface from shaders or use as a pixel view.
42  texture_descriptor.get().usage = MTLTextureUsageUnknown;
43 
44  if (!texture_descriptor) {
45  FML_LOG(ERROR) << "Invalid texture descriptor.";
46  return;
47  }
48 
49  auto texture =
50  fml::scoped_nsobject{[device.get() newTextureWithDescriptor:texture_descriptor.get()]};
51 
52  if (!texture) {
53  FML_LOG(ERROR) << "Could not create texture from texture descriptor.";
54  return;
55  }
56 
57  auto skia_context = GrDirectContext::MakeMetal(device.get(), command_queue.get());
58 
59  if (skia_context) {
60  // Skia wants ownership of the device and queue. If a context was created,
61  // we now no longer own the argument. Release the arguments only on
62  // successful creation of the context.
63  FML_ALLOW_UNUSED_LOCAL(device.release());
64  FML_ALLOW_UNUSED_LOCAL(command_queue.release());
65  } else {
66  FML_LOG(ERROR) << "Could not create the GrDirectContext from the Metal Device "
67  "and command queue.";
68  return;
69  }
70 
71  GrMtlTextureInfo skia_texture_info;
72  skia_texture_info.fTexture = sk_cf_obj<const void*>{[texture.get() retain]};
73 
74  auto backend_render_target = GrBackendRenderTarget{
75  surface_size.width(), // width
76  surface_size.height(), // height
77  1, // sample count
78  skia_texture_info // texture info
79  };
80 
81  auto surface = SkSurface::MakeFromBackendRenderTarget(
82  skia_context.get(), // context
83  backend_render_target, // backend render target
84  kTopLeft_GrSurfaceOrigin, // surface origin
85  kBGRA_8888_SkColorType, // color type
86  nullptr, // color space
87  nullptr, // surface properties
88  nullptr, // release proc (texture is already ref counted in sk_cf_obj)
89  nullptr // release context
90  );
91 
92  if (!surface) {
93  FML_LOG(ERROR) << "Could not create Skia surface from a Metal texture.";
94  return;
95  }
96 
97  surface_ = std::move(surface);
98  context_ = std::move(skia_context);
99 
100  is_valid_ = true;
101 }
102 
103 // |TestMetalSurface|
105 
106 // |TestMetalSurface|
107 bool TestMetalSurfaceImpl::IsValid() const {
108  return is_valid_;
109 }
110 // |TestMetalSurface|
111 sk_sp<GrDirectContext> TestMetalSurfaceImpl::GetGrContext() const {
112  return IsValid() ? context_ : nullptr;
113 }
114 // |TestMetalSurface|
115 sk_sp<SkSurface> TestMetalSurfaceImpl::GetSurface() const {
116  return IsValid() ? surface_ : nullptr;
117 }
118 
119 } // namespace flutter
#define FML_ALLOW_UNUSED_LOCAL(x)
#define FML_LOG(severity)
Definition: logging.h:65
int32_t height
int32_t width
TestMetalSurfaceImpl(SkISize surface_size)