Skip to content

Commit dce82cc

Browse files
committed
Added an example to showcase the metal backend
1 parent e56a34c commit dce82cc

File tree

17 files changed

+334
-6
lines changed

17 files changed

+334
-6
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
# Project
22
build/
3+
build_*/
34
tmp/
45

56
# Compiled Object files

CMakeLists.txt

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,10 @@ if(NOT CMAKE_BUILD_TYPE)
99
set(CMAKE_BUILD_TYPE Release)
1010
endif()
1111

12-
option(BACKEND_METAL "Build the Metal backend" ON)
13-
option(BACKEND_OPENGL "Build the OpenGL backend" OFF)
12+
option(BACKEND_METAL "Build the Metal backend" ON)
13+
option(BACKEND_OPENGL "Build the OpenGL backend" OFF)
14+
15+
option(BUILD_EXAMPLES "Build the example projects" ON)
1416

1517
# TARGET
1618

@@ -31,6 +33,11 @@ if(BACKEND_METAL)
3133
"-fobjc-arc"
3234
)
3335

36+
target_compile_definitions(graphics
37+
PUBLIC
38+
GRAPHICS_USE_METAL=1
39+
)
40+
3441
target_sources(graphics
3542
PRIVATE
3643
src/graphics/metal/context.mm
@@ -44,8 +51,21 @@ if(BACKEND_METAL)
4451
endif()
4552

4653
if(BACKEND_OPENGL)
54+
target_compile_definitions(graphics
55+
PUBLIC
56+
GRAPHICS_USE_OPENGL=1
57+
)
58+
4759
target_sources(graphics
4860
PRIVATE
4961
# src/graphics/opengl/*
5062
)
5163
endif()
64+
65+
# EXAMPLES
66+
67+
if(BUILD_EXAMPLES)
68+
if(BACKEND_METAL)
69+
add_subdirectory(examples/hello_metal)
70+
endif()
71+
endif()

examples/hello_metal/AppDelegate.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
#import <Cocoa/Cocoa.h>
2+
3+
@interface AppDelegate : NSObject <NSApplicationDelegate, NSWindowDelegate>
4+
5+
@end

examples/hello_metal/AppDelegate.mm

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
#import "./AppDelegate.h"
2+
#import "./Renderer.h"
3+
4+
@implementation AppDelegate {
5+
NSString * _appName;
6+
NSWindow * _window;
7+
Renderer * _renderer;
8+
}
9+
10+
- (nonnull instancetype) init {
11+
if ((self = [super init])) {
12+
_appName = [[NSProcessInfo processInfo] processName];
13+
14+
NSApplication * application = [NSApplication sharedApplication];
15+
[application setMainMenu:[self createMenu]];
16+
_window = [self createWindow];
17+
}
18+
19+
return self;
20+
}
21+
22+
- (void) applicationWillFinishLaunching:(NSNotification *)notification {
23+
[_window setTitle:_appName];
24+
[_window cascadeTopLeftFromPoint:NSMakePoint(20, 20)];
25+
[_window makeKeyAndOrderFront:self];
26+
}
27+
28+
- (BOOL) applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)sender {
29+
return TRUE;
30+
}
31+
32+
- (NSMenu *) createMenu {
33+
NSMenuItem * quit = [[NSMenuItem alloc] initWithTitle:[@"Quit " stringByAppendingString:_appName] action:@selector(terminate:) keyEquivalent:@"q"];
34+
NSMenuItem * item = [[NSMenuItem alloc] init];
35+
item.submenu = [[NSMenu alloc] init];
36+
[item.submenu addItem:quit];
37+
38+
NSMenu * mainMenu = [[NSMenu alloc] init];
39+
[mainMenu addItem:item];
40+
41+
return mainMenu;
42+
}
43+
44+
- (NSWindow *) createWindow {
45+
NSWindow * window = [[NSWindow alloc] initWithContentRect:NSMakeRect(0, 0, 640, 480)
46+
styleMask:NSWindowStyleMaskTitled | NSWindowStyleMaskClosable
47+
backing:NSBackingStoreBuffered
48+
defer:NO];
49+
50+
MTKView * mtlView = [[MTKView alloc] initWithFrame:window.contentView.frame device:MTLCreateSystemDefaultDevice()];
51+
[window.contentView addSubview:mtlView];
52+
53+
_renderer = [[Renderer alloc] initWithMetalKitView:mtlView];
54+
[_renderer mtkView:mtlView drawableSizeWillChange:mtlView.drawableSize];
55+
mtlView.delegate = _renderer;
56+
57+
return window;
58+
}
59+
60+
@end

examples/hello_metal/CMakeLists.txt

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
cmake_minimum_required(VERSION 3.10)
2+
3+
if(NOT XCODE)
4+
message(
5+
WARNING
6+
"Cannot create `hello_metal` example: The generator must be `Xcode` in order to compile metal shader files"
7+
)
8+
else()
9+
project(hello_metal)
10+
set(CMAKE_CXX_STANDARD 17)
11+
12+
add_executable(hello_metal)
13+
14+
target_compile_options(hello_metal
15+
PUBLIC
16+
"-fobjc-arc"
17+
)
18+
19+
set(SHADERS
20+
shader.metal
21+
)
22+
23+
set_source_files_properties(
24+
${SHADERS}
25+
PROPERTIES
26+
LANGUAGE METAL
27+
)
28+
29+
target_sources(hello_metal
30+
PRIVATE
31+
main.mm
32+
AppDelegate.mm
33+
Renderer.mm
34+
${SHADERS}
35+
)
36+
37+
target_link_libraries(hello_metal
38+
PRIVATE
39+
graphics
40+
"-framework Cocoa"
41+
"-framework Metal"
42+
"-framework MetalKit"
43+
)
44+
endif()

examples/hello_metal/Renderer.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
#import <MetalKit/MetalKit.h>
2+
3+
@interface Renderer : NSObject <MTKViewDelegate>
4+
5+
- (nonnull instancetype) initWithMetalKitView:(nonnull MTKView *)view;
6+
7+
@end

examples/hello_metal/Renderer.mm

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
#import "./Renderer.h"
2+
3+
#include <simd/simd.h>
4+
#include <graphics/graphics.hpp>
5+
6+
#define SIZEOF_ARRAY(array) (sizeof(array) / sizeof(*array))
7+
8+
// Declare the graphics data used for initialization
9+
#include "../shared/decl.inc"
10+
11+
@implementation Renderer {
12+
graphics::Context * _context;
13+
graphics::State * _state;
14+
graphics::DynamicBuffer * _uniformsBuffer;
15+
graphics::StaticBuffer * _verticesBuffer;
16+
}
17+
18+
- (nonnull instancetype) initWithMetalKitView:(nonnull MTKView *)view {
19+
if ((self = [super init])) {
20+
_context = new graphics::Context(view);
21+
22+
// Initialize the graphics objects
23+
#include "../shared/init.inc"
24+
}
25+
26+
return self;
27+
}
28+
29+
- (void) drawInMTKView:(nonnull MTKView *)view {
30+
// Render the frame
31+
#include "../shared/update.inc"
32+
33+
// Render the frame
34+
#include "../shared/render.inc"
35+
}
36+
37+
- (void) mtkView:(nonnull MTKView *)view drawableSizeWillChange:(CGSize)size {
38+
// Respond to drawable size or orientation changes here
39+
}
40+
41+
@end

examples/hello_metal/main.mm

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
#import <Cocoa/Cocoa.h>
2+
3+
#import "./AppDelegate.h"
4+
5+
int main() {
6+
@autoreleasepool {
7+
NSApplication * application = [NSApplication sharedApplication];
8+
[application setActivationPolicy:NSApplicationActivationPolicyRegular];
9+
10+
AppDelegate * appDelegate = [[AppDelegate alloc] init];
11+
[application setDelegate:appDelegate];
12+
[application activateIgnoringOtherApps:YES];
13+
[application run];
14+
}
15+
16+
return EXIT_SUCCESS;
17+
}

examples/hello_metal/shader.metal

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
#include <metal_stdlib>
2+
using namespace metal;
3+
4+
struct Vertex {
5+
float4 position [[ attribute(0) ]];
6+
float4 color [[ attribute(1) ]];
7+
};
8+
9+
struct Uniforms {
10+
float4x4 matrix;
11+
};
12+
13+
struct InOut {
14+
float4 position [[ position ]];
15+
half4 color;
16+
};
17+
18+
vertex InOut default_vertex(Vertex in [[ stage_in ]], constant Uniforms & uniforms [[ buffer(1) ]]) {
19+
InOut out;
20+
out.position = uniforms.matrix * in.position;
21+
out.color = half4(in.color);
22+
return out;
23+
}
24+
25+
fragment half4 default_fragment(InOut in [[ stage_in ]]) {
26+
return in.color;
27+
}

examples/shared/decl.inc

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
struct Vertex {
2+
simd::float4 position;
3+
simd::float4 color;
4+
};
5+
6+
struct Uniforms {
7+
simd::float4x4 matrix;
8+
};
9+
10+
const Vertex VERTICES[] = {
11+
Vertex{ simd::float4{-0.5f, -0.5f, 0.0f, 1.0f}, simd::float4{1.0f, 0.0f, 0.0f, 1.0f} },
12+
Vertex{ simd::float4{+0.5f, -0.5f, 0.0f, 1.0f}, simd::float4{1.0f, 1.0f, 0.0f, 1.0f} },
13+
Vertex{ simd::float4{-0.5f, +0.5f, 0.0f, 1.0f}, simd::float4{0.0f, 0.0f, 1.0f, 1.0f} },
14+
Vertex{ simd::float4{+0.5f, +0.5f, 0.0f, 1.0f}, simd::float4{0.0f, 1.0f, 0.0f, 1.0f} },
15+
};
16+
17+
const graphics::VertexAttribute VERTEX_ATTRIBS[] = {
18+
graphics::VertexAttribute{
19+
.id = 0,
20+
.format = graphics::VertexFormat::Float4,
21+
.offset = offsetof(Vertex, position),
22+
.bufferIndex = 0,
23+
},
24+
graphics::VertexAttribute{
25+
.id = 1,
26+
.format = graphics::VertexFormat::Float4,
27+
.offset = offsetof(Vertex, color),
28+
.bufferIndex = 0,
29+
},
30+
};
31+
32+
const graphics::BufferLayout VERTEX_LAYOUTS[] = {
33+
graphics::BufferLayout{
34+
.bufferIndex = 0,
35+
.stride = sizeof(Vertex),
36+
.stepFunction = graphics::StepFunction::PerVertex,
37+
},
38+
};
39+
40+
const graphics::VertexDesc VERTEX_DESC{
41+
.attributeCount = SIZEOF_ARRAY(VERTEX_ATTRIBS),
42+
.layoutCount = SIZEOF_ARRAY(VERTEX_LAYOUTS),
43+
.attributes = VERTEX_ATTRIBS,
44+
.layouts = VERTEX_LAYOUTS,
45+
};
46+
47+
const graphics::StateDesc stateDesc{
48+
.vertexShader = "default_vertex",
49+
.fragmentShader = "default_fragment",
50+
.targetDesc = nullptr, //< Use screen
51+
.vertexDesc = &VERTEX_DESC,
52+
.cullMode = graphics::CullMode::Back,
53+
.winding = graphics::Winding::CounterClockwise,
54+
.depthCompareFunction = graphics::CompareFunction::Always,
55+
.depthWriteEnabled = true,
56+
};

examples/shared/init.inc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
_state = _context->createState(stateDesc);
2+
3+
_uniformsBuffer = _context->createDynamicBuffer<Uniforms>(1);
4+
_verticesBuffer = _context->createStaticBuffer(SIZEOF_ARRAY(VERTICES), VERTICES);

examples/shared/render.inc

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
_context->startFrame();
2+
3+
// Render to the screen
4+
_context->setRenderTarget(nullptr);
5+
6+
// Set the graphics state
7+
// This includes the shaders, depth and blend settings
8+
_context->setState(_state);
9+
10+
// Set the buffers to use to render
11+
_context->setBuffer(0, _verticesBuffer);
12+
_context->setBuffer(1, _uniformsBuffer);
13+
14+
// Finally draw the triangles
15+
_context->drawTriangleStrip(SIZEOF_ARRAY(VERTICES));
16+
17+
_context->commitFrame();

examples/shared/update.inc

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
static float angle = 0.0f;
2+
angle += 0.5f * M_PI / 60.0f;
3+
4+
const uint32_t frame = _context->getFrame();
5+
6+
float c = cosf(angle);
7+
float s = sinf(angle);
8+
9+
Uniforms * uniforms = (Uniforms *) _uniformsBuffer->getData(frame);
10+
uniforms->matrix = simd::float4x4{
11+
simd::float4{ c, s, 0.0f, 0.0f },
12+
simd::float4{ -s, c, 0.0f, 0.0f },
13+
simd::float4{ 0.0f, 0.0f, 1.0f, 0.0f },
14+
simd::float4{ 0.0f, 0.0f, 0.0f, 1.0f },
15+
};
16+
17+
_uniformsBuffer->update(frame);

include/graphics/descriptors.hpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,6 @@ namespace graphics {
7171
struct BufferLayout {
7272
uint32_t bufferIndex;
7373
uint32_t stride;
74-
uint32_t stepRate;
7574
StepFunction stepFunction;
7675
};
7776

include/graphics/graphics.hpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,16 @@
1414

1515
#if GRAPHICS_USE_METAL
1616
#include "graphics/metal/context.hpp"
17-
namespace graphics = graphics::metal;
17+
namespace graphics {
18+
using namespace metal;
19+
}
1820
#endif
1921

2022
#if GRAPHICS_USE_OPENGL
2123
#include "graphics/opengl/graphics.hpp"
22-
namespace graphics = graphics::opengl;
24+
namespace graphics {
25+
using namespace opengl;
26+
}
2327
#endif
2428

2529
#endif /* graphics_graphics_hpp */

0 commit comments

Comments
 (0)