Created
May 25, 2022 21:52
-
-
Save warrenm/50bb40e80d6bb57f9fbd09048bd12891 to your computer and use it in GitHub Desktop.
A one-file example of rendering into a UIView with Metal and CADisplayLink
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#import <UIKit/UIKit.h> | |
#import <QuartzCore/CAMetalLayer.h> | |
#import <Metal/Metal.h> | |
@class MetalView; | |
@protocol MetalViewDelegate | |
- (void)drawInView:(MetalView *)view; | |
@end | |
@interface MetalView : UIView | |
@property (nonatomic, strong) id<MTLDevice> device; | |
@property (nonatomic, weak) id<MetalViewDelegate> delegate; | |
@property (nonatomic, nullable, strong) CADisplayLink *displayLink; | |
@end | |
@implementation MetalView | |
+ (Class)layerClass { | |
return [CAMetalLayer class]; | |
} | |
- (id<MTLDevice>)device { | |
return ((CAMetalLayer *)self.layer).device; | |
} | |
- (void)setDevice:(id<MTLDevice>)device { | |
((CAMetalLayer *)self.layer).device = device; | |
} | |
- (id<CAMetalDrawable>)currentDrawable { | |
return [((CAMetalLayer *)self.layer) nextDrawable]; | |
} | |
- (void)didMoveToWindow { | |
if (self.window == nil) { | |
[self deactivateDisplayLink]; | |
} else { | |
[self activateDisplayLink]; | |
} | |
} | |
- (void)activateDisplayLink { | |
self.displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(displayLinkDidFire:)]; | |
[self.displayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes]; | |
} | |
- (void)deactivateDisplayLink { | |
[self.displayLink invalidate]; | |
self.displayLink = nil; | |
} | |
- (void)displayLinkDidFire:(CADisplayLink *)displayLink { | |
[self drawRect:self.bounds]; | |
} | |
- (void)drawRect:(CGRect)rect { | |
[self.delegate drawInView:self]; | |
} | |
@end | |
@interface ViewController : UIViewController <MetalViewDelegate> | |
@property (nonatomic, strong) UIWindow *window; | |
@property (nonatomic, strong) id<MTLDevice> device; | |
@property (nonatomic, strong) id<MTLCommandQueue> commandQueue; | |
@end | |
@implementation ViewController | |
- (instancetype)init { | |
if (self = [super init]) { | |
_device = MTLCreateSystemDefaultDevice(); | |
_commandQueue = [_device newCommandQueue]; | |
} | |
return self; | |
} | |
- (void)loadView { | |
CGRect bounds = UIScreen.mainScreen.bounds; | |
MetalView *view = [[MetalView alloc] initWithFrame:bounds]; | |
view.delegate = self; | |
self.view = view; | |
} | |
- (void)drawInView:(MetalView *)view { | |
id<CAMetalDrawable> drawable = [view currentDrawable]; | |
if (drawable == nil) { | |
return; | |
} | |
MTLRenderPassDescriptor *passDescriptor = [MTLRenderPassDescriptor new]; | |
passDescriptor.colorAttachments[0].texture = drawable.texture; | |
passDescriptor.colorAttachments[0].clearColor = MTLClearColorMake(0, 0.5, 1, 1); | |
passDescriptor.colorAttachments[0].loadAction = MTLLoadActionClear; | |
passDescriptor.colorAttachments[0].storeAction = MTLStoreActionStore; | |
id<MTLCommandBuffer> commandBuffer = [self.commandQueue commandBuffer]; | |
id<MTLRenderCommandEncoder> renderCommandEncoder = [commandBuffer renderCommandEncoderWithDescriptor:passDescriptor]; | |
[renderCommandEncoder endEncoding]; | |
[commandBuffer presentDrawable:drawable]; | |
[commandBuffer commit]; | |
} | |
@end | |
@interface AppDelegate : UIResponder <UIApplicationDelegate> | |
@property (nonatomic, strong) UIWindow *window; | |
@end | |
@implementation AppDelegate | |
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { | |
ViewController *vc = [[ViewController alloc] init]; | |
self.window = [[UIWindow alloc] initWithFrame:vc.view.bounds]; | |
self.window.rootViewController = vc; | |
[self.window makeKeyAndVisible]; | |
return YES; | |
} | |
@end | |
int main(int argc, char * argv[]) { | |
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment