Skip to content

Instantly share code, notes, and snippets.

@sortofsleepy
Last active December 12, 2022 13:07
Show Gist options
  • Save sortofsleepy/2f6b6fd9c818fd7697b942ff8bfa31cb to your computer and use it in GitHub Desktop.
Save sortofsleepy/2f6b6fd9c818fd7697b942ff8bfa31cb to your computer and use it in GitHub Desktop.
Basic setup of getting a Metal context up and running.
//
// ViewController.h
// metal.test
//
// Created by josephchow on 12/10/19.
// Copyright © 2019 josephchow. All rights reserved.
//
#import <UIKit/UIKit.h>
#import <Metal/Metal.h>
#import <MetalKit/MetalKit.h>
#import <vector>
#import <memory>
/**
Quick abstracted sample of how to draw a triangle with Metal. Follows Ray Wenderlich tutorial.
https://www.raywenderlich.com/7475-metal-tutorial-getting-started
*/
typedef std::shared_ptr<class Vbo> VboRef;
class Vbo {
public:
Vbo(id<MTLDevice> device){
this->device = device;
}
//! Add data
template<typename T>
void bufferData(std::vector<T> &data){
buffer = [device newBufferWithBytes:data.data() length:sizeof(T) * data.size() options:MTLResourceCPUCacheModeDefaultCache];
}
//! Returns the buffer.
id<MTLBuffer> getBuffer() { return buffer; }
protected:
id <MTLDevice> device;
id <MTLBuffer> buffer;
};
@interface ViewController : UIViewController{
// device referencing the GPU
id <MTLDevice> device;
id <MTLBuffer> buffer;
// used to render something to screen
id <MTLRenderPipelineState> pipeline;
// timer synced to display refresh rate.
CADisplayLink * timer;
// object used to render something to screen.
CAMetalLayer * layer;
id <MTLCommandQueue> commandQueue;
Vbo * vbo;
};
- (void) draw;
@end
//
// ViewController.m
// metal.test
//
// Created by josephchow on 12/10/19.
// Copyright © 2019 josephchow. All rights reserved.
//
#import "ViewController.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
// ======= LOAD DEVICE ======== //
device = MTLCreateSystemDefaultDevice();
if(device == nil){
NSLog(@"Deivce nil");
}
// ========= BUILD LAYER ======== //
layer = [[CAMetalLayer alloc] init];
layer.device = device;
layer.pixelFormat = MTLPixelFormatBGRA8Unorm;
layer.framebufferOnly = true;
layer.frame = self.view.layer.frame;
[self.view.layer addSublayer:layer];
// ====== LOAD DATA =========== //
std::vector<float> data = {
0.0, 1.0, 0.0,
-1.0, -1.0, 0.0,
1.0, -1.0, 0.0
};
vbo = new Vbo(device);
vbo->bufferData(data);
// ========= LOAD SHADER ======== //
// looks for all .metal source files set in compiled sources.
id <MTLLibrary> defaultLibrary = [device newDefaultLibrary];
id <MTLFunction> vertex_func = [defaultLibrary newFunctionWithName:@"basic_vertex"];
id <MTLFunction> fragment_func = [defaultLibrary newFunctionWithName:@"basic_fragment"];
// ======== BUILD PIPELINE DESCRIPTOR AND PIPELINE STATE ========= //
MTLRenderPipelineDescriptor * descrip = [[MTLRenderPipelineDescriptor alloc] init];
descrip.label = @"MyCapturedImagePipeline";
descrip.vertexFunction = vertex_func;
descrip.fragmentFunction =fragment_func;
descrip.colorAttachments[0].pixelFormat = MTLPixelFormatBGRA8Unorm;
NSError * err = nil;
pipeline = [device newRenderPipelineStateWithDescriptor:descrip error:&err];
if (err != nil) {
NSLog(@"Error creating render pipeline state: %@",[err localizedFailureReason]);
}
// ======== BUILD COMMAND QUEUE =========== //
commandQueue = [device newCommandQueue];
// ======= SETUP DISPLAY LINKE ========= //
timer = [CADisplayLink displayLinkWithTarget:self selector:@selector(draw)];
[timer addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
}
-(void) draw {
//===== BUILD RENDER PASS DESCRIPTOR ======= //
auto drawable = layer.nextDrawable;
if(drawable != nil){
MTLClearColor color = MTLClearColor();
color.red = 0.0f;
color.green = 104.0 / 255.0;
color.blue = 55.0 / 255.0;
color.alpha = 1.0;
MTLRenderPassDescriptor * renderPassDescriptor = [[MTLRenderPassDescriptor alloc] init];
renderPassDescriptor.colorAttachments[0].texture = drawable.texture;
renderPassDescriptor.colorAttachments[0].loadAction = MTLLoadActionClear;
renderPassDescriptor.colorAttachments[0].clearColor = color;
id<MTLCommandBuffer> commandBuffer = [commandQueue commandBuffer];
id<MTLRenderCommandEncoder> renderEncoder = [commandBuffer renderCommandEncoderWithDescriptor:renderPassDescriptor];
[renderEncoder setRenderPipelineState:pipeline];
//[renderEncoder setVertexBuffer:buffer offset:0 atIndex:0];
[renderEncoder setVertexBuffer:vbo->getBuffer() offset:0 atIndex:0];
[renderEncoder drawPrimitives:MTLPrimitiveTypeTriangle vertexStart:0 vertexCount:3 instanceCount:1];
[renderEncoder endEncoding];
[commandBuffer presentDrawable:drawable];
[commandBuffer commit];
}
}
@end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment