1 // Copyright 2019 Google LLC.
2 // Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.
4 // This is an example of a minimal iOS application that uses Skia to draw to
7 // Much of this code is copied from the default application created by XCode.
9 #include "tools/skottie_ios_app/SkMetalViewBridge.h"
11 #include "include/core/SkCanvas.h"
12 #include "include/core/SkColor.h"
13 #include "include/core/SkColorSpace.h"
14 #include "include/core/SkPaint.h"
15 #include "include/core/SkSurface.h"
16 #include "include/core/SkTime.h"
17 #include "include/effects/SkGradientShader.h"
18 #include "include/gpu/GrBackendSurface.h"
19 #include "include/gpu/GrDirectContext.h"
20 #include "include/gpu/mtl/GrMtlTypes.h"
22 #import <Metal/Metal.h>
23 #import <MetalKit/MetalKit.h>
24 #import <UIKit/UIKit.h>
26 ////////////////////////////////////////////////////////////////////////////////
28 static void config_paint(SkPaint* paint) {
29 if (!paint->getShader()) {
30 const SkColor4f colors[2] = {SkColors::kBlack, SkColors::kWhite};
31 const SkPoint points[2] = {{0, -1024}, {0, 1024}};
32 paint->setShader(SkGradientShader::MakeLinear(points, colors, nullptr, nullptr, 2,
33 SkTileMode::kClamp, 0, nullptr));
37 static void draw_example(SkSurface* surface, const SkPaint& paint, double rotation) {
38 SkCanvas* canvas = surface->getCanvas();
39 canvas->translate(surface->width() * 0.5f, surface->height() * 0.5f);
40 canvas->rotate(rotation);
41 canvas->drawPaint(paint);
44 ////////////////////////////////////////////////////////////////////////////////
46 @interface AppViewDelegate : NSObject <MTKViewDelegate>
47 @property (assign, nonatomic) GrDirectContext* grContext; // non-owning pointer.
48 @property (assign, nonatomic) id<MTLCommandQueue> metalQueue;
51 @implementation AppViewDelegate {
55 - (void)drawInMTKView:(nonnull MTKView *)view {
56 if (![self grContext] || !view) {
59 // Do as much as possible before creating surface.
60 config_paint(&fPaint);
61 float rotation = (float)(180 * 1e-9 * SkTime::GetNSecs());
64 sk_sp<SkSurface> surface = SkMtkViewToSurface(view, [self grContext]);
66 NSLog(@"error: no sksurface");
70 draw_example(surface.get(), fPaint, rotation);
72 // Must flush *and* present for this to work!
73 surface->flushAndSubmit();
76 id<MTLCommandBuffer> commandBuffer = [[self metalQueue] commandBuffer];
77 [commandBuffer presentDrawable:[view currentDrawable]];
78 [commandBuffer commit];
81 - (void)mtkView:(nonnull MTKView *)view drawableSizeWillChange:(CGSize)size {
82 // change anything on size change?
86 ////////////////////////////////////////////////////////////////////////////////
88 @interface AppViewController : UIViewController
89 @property (strong, nonatomic) id<MTLDevice> metalDevice;
90 @property (strong, nonatomic) id<MTLCommandQueue> metalQueue;
93 @implementation AppViewController {
94 GrContextHolder fGrContext;
98 [self setView:[[MTKView alloc] initWithFrame:[[UIScreen mainScreen] bounds] device:nil]];
101 - (void)viewDidLoad {
104 [self setMetalDevice:MTLCreateSystemDefaultDevice()];
105 [self setMetalQueue:[[self metalDevice] newCommandQueue]];
106 fGrContext = SkMetalDeviceToGrContext([self metalDevice], [self metalQueue]);
108 if (![self view] || ![self metalDevice]) {
109 NSLog(@"Metal is not supported on this device");
110 self.view = [[UIView alloc] initWithFrame:self.view.frame];
113 MTKView* mtkView = (MTKView*)[self view];
114 [mtkView setDevice:[self metalDevice]];
115 [mtkView setBackgroundColor:[UIColor blackColor]];
116 SkMtkViewConfigForSkia(mtkView);
117 AppViewDelegate* viewDelegate = [[AppViewDelegate alloc] init];
118 [viewDelegate setGrContext:fGrContext.get()];
119 [viewDelegate setMetalQueue:[self metalQueue]];
120 [viewDelegate mtkView:mtkView drawableSizeWillChange:[mtkView bounds].size];
121 [mtkView setDelegate:viewDelegate];
125 ////////////////////////////////////////////////////////////////////////////////
127 @interface AppDelegate : UIResponder <UIApplicationDelegate>
128 @property (strong, nonatomic) UIWindow *window;
131 @implementation AppDelegate
132 - (BOOL)application:(UIApplication *)app didFinishLaunchingWithOptions:(NSDictionary*)opts {
133 // Override point for customization after application launch.
134 [self setWindow:[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]];
135 [[self window] setFrame:[[UIScreen mainScreen] bounds]];
136 [[self window] setRootViewController:[[AppViewController alloc] init]];
137 [[self window] makeKeyAndVisible];
142 ////////////////////////////////////////////////////////////////////////////////
144 int main(int argc, char* argv[]) {
146 return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));