2019-12-18 21:26:19 +00:00
|
|
|
// Copyright 2020 Google LLC.
|
|
|
|
// Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.
|
|
|
|
|
|
|
|
#include "tools/skottie_ios_app/SkiaContext.h"
|
|
|
|
|
|
|
|
#include "include/core/SkSurface.h"
|
2020-08-13 19:06:09 +00:00
|
|
|
#include "include/gpu/GrDirectContext.h"
|
2019-12-18 21:26:19 +00:00
|
|
|
#include "tools/skottie_ios_app/SkMetalViewBridge.h"
|
|
|
|
|
|
|
|
#import <Metal/Metal.h>
|
|
|
|
#import <MetalKit/MetalKit.h>
|
|
|
|
#import <UIKit/UIKit.h>
|
|
|
|
|
|
|
|
// A UIView that uses a Metal-backed SkSurface to draw.
|
|
|
|
@interface SkiaMtkView : MTKView
|
|
|
|
@property (strong) SkiaViewController* controller;
|
|
|
|
|
|
|
|
// Override of the MTKView interface. Uses Skia+Metal to draw.
|
|
|
|
- (void)drawRect:(CGRect)rect;
|
|
|
|
|
|
|
|
// Required initializer.
|
|
|
|
- (instancetype)initWithFrame:(CGRect)frameRect
|
|
|
|
device:(id<MTLDevice>)device
|
|
|
|
queue:(id<MTLCommandQueue>)queue
|
2020-08-13 19:06:09 +00:00
|
|
|
grDevice:(GrDirectContext*)dContext;
|
2019-12-18 21:26:19 +00:00
|
|
|
@end
|
|
|
|
|
|
|
|
@implementation SkiaMtkView {
|
|
|
|
id<MTLCommandQueue> fQueue;
|
2020-08-13 19:06:09 +00:00
|
|
|
GrDirectContext* fDContext;
|
2019-12-18 21:26:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (instancetype)initWithFrame:(CGRect)frameRect
|
|
|
|
device:(id<MTLDevice>)mtlDevice
|
|
|
|
queue:(id<MTLCommandQueue>)queue
|
2020-08-13 19:06:09 +00:00
|
|
|
grDevice:(GrDirectContext*)dContext {
|
2019-12-18 21:26:19 +00:00
|
|
|
self = [super initWithFrame:frameRect device:mtlDevice];
|
|
|
|
fQueue = queue;
|
2020-08-13 19:06:09 +00:00
|
|
|
fDContext = dContext;
|
2019-12-18 21:26:19 +00:00
|
|
|
SkMtkViewConfigForSkia(self);
|
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)drawRect:(CGRect)rect {
|
|
|
|
[super drawRect:rect];
|
|
|
|
// TODO(halcanary): Use the rect and the InvalidationController to speed up rendering.
|
|
|
|
SkiaViewController* viewController = [self controller];
|
2020-08-13 19:06:09 +00:00
|
|
|
if (!viewController || ![[self currentDrawable] texture] || !fDContext) {
|
2019-12-18 21:26:19 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
CGSize size = [self drawableSize];
|
2020-08-13 19:06:09 +00:00
|
|
|
sk_sp<SkSurface> surface = SkMtkViewToSurface(self, fDContext);
|
2019-12-18 21:26:19 +00:00
|
|
|
if (!surface) {
|
|
|
|
NSLog(@"error: no sksurface");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
[viewController draw:rect toCanvas:surface->getCanvas() atSize:size];
|
2020-05-19 22:06:26 +00:00
|
|
|
surface->flushAndSubmit();
|
2019-12-18 21:26:19 +00:00
|
|
|
surface = nullptr;
|
|
|
|
|
|
|
|
id<MTLCommandBuffer> commandBuffer = [fQueue commandBuffer];
|
|
|
|
[commandBuffer presentDrawable:[self currentDrawable]];
|
|
|
|
[commandBuffer commit];
|
|
|
|
|
|
|
|
bool paused = [viewController isPaused];
|
|
|
|
[self setEnableSetNeedsDisplay:paused];
|
|
|
|
[self setPaused:paused];
|
|
|
|
}
|
|
|
|
@end
|
|
|
|
|
|
|
|
@interface SkiaMetalContext : SkiaContext
|
|
|
|
@property (strong) id<MTLDevice> metalDevice;
|
|
|
|
@property (strong) id<MTLCommandQueue> metalQueue;
|
|
|
|
- (instancetype) init;
|
|
|
|
- (UIView*) makeViewWithController:(SkiaViewController*)vc withFrame:(CGRect)frame;
|
|
|
|
- (SkiaViewController*) getViewController:(UIView*)view;
|
|
|
|
@end
|
|
|
|
|
|
|
|
@implementation SkiaMetalContext {
|
2020-08-13 19:06:09 +00:00
|
|
|
sk_sp<GrDirectContext> fDContext;
|
2019-12-18 21:26:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (instancetype) init {
|
|
|
|
self = [super init];
|
|
|
|
[self setMetalDevice:MTLCreateSystemDefaultDevice()];
|
|
|
|
if(![self metalDevice]) {
|
|
|
|
NSLog(@"Metal is not supported on this device");
|
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
[self setMetalQueue:[[self metalDevice] newCommandQueue]];
|
2020-08-13 19:06:09 +00:00
|
|
|
fDContext = GrDirectContext::MakeMetal((__bridge void*)[self metalDevice],
|
|
|
|
(__bridge void*)[self metalQueue],
|
|
|
|
GrContextOptions());
|
2019-12-18 21:26:19 +00:00
|
|
|
|
2020-08-13 19:06:09 +00:00
|
|
|
if (!fDContext) {
|
|
|
|
NSLog(@"GrDirectContext::MakeMetal failed");
|
2019-12-18 21:26:19 +00:00
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (UIView*) makeViewWithController:(SkiaViewController*)vc withFrame:(CGRect)frame {
|
|
|
|
SkiaMtkView* skiaView = [[SkiaMtkView alloc] initWithFrame:frame
|
|
|
|
device:[self metalDevice]
|
|
|
|
queue:[self metalQueue]
|
2020-08-13 19:06:09 +00:00
|
|
|
grDevice:fDContext.get()];
|
2019-12-18 21:26:19 +00:00
|
|
|
[skiaView setPreferredFramesPerSecond:30];
|
|
|
|
[skiaView setController:vc];
|
|
|
|
return skiaView;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (SkiaViewController*) getViewController:(UIView*)view {
|
2020-01-14 19:19:48 +00:00
|
|
|
return [view isKindOfClass:[SkiaMtkView class]] ? [(SkiaMtkView*)view controller] : nil;
|
2019-12-18 21:26:19 +00:00
|
|
|
}
|
|
|
|
@end
|
|
|
|
|
|
|
|
SkiaContext* MakeSkiaMetalContext() { return [[SkiaMetalContext alloc] init]; }
|