Commit
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,167 @@ | ||
//======================================================================== | ||
// Simple GLFW+Metal example | ||
// Copyright (c) Camilla Berglund <elmindreda@elmindreda.org> | ||
// | ||
// This software is provided 'as-is', without any express or implied | ||
// warranty. In no event will the authors be held liable for any damages | ||
// arising from the use of this software. | ||
// | ||
// Permission is granted to anyone to use this software for any purpose, | ||
// including commercial applications, and to alter it and redistribute it | ||
// freely, subject to the following restrictions: | ||
// | ||
// 1. The origin of this software must not be misrepresented; you must not | ||
// claim that you wrote the original software. If you use this software | ||
// in a product, an acknowledgment in the product documentation would | ||
// be appreciated but is not required. | ||
// | ||
// 2. Altered source versions must be plainly marked as such, and must not | ||
// be misrepresented as being the original software. | ||
// | ||
// 3. This notice may not be removed or altered from any source | ||
// distribution. | ||
// | ||
//======================================================================== | ||
//! [code] | ||
|
||
#import <Metal/Metal.h> | ||
#import <QuartzCore/QuartzCore.h> | ||
#import <simd/simd.h> | ||
|
||
#define GLFW_INCLUDE_NONE | ||
#import <GLFW/glfw3.h> | ||
#define GLFW_EXPOSE_NATIVE_COCOA | ||
#define GLFW_EXPOSE_NATIVE_NSGL | ||
#import <GLFW/glfw3native.h> | ||
|
||
#include <assert.h> | ||
#include <stdlib.h> | ||
#include <stdio.h> | ||
|
||
static void error_callback(int error, const char* description) | ||
{ | ||
fputs(description, stderr); | ||
} | ||
|
||
static void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods) | ||
{ | ||
if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS) | ||
glfwSetWindowShouldClose(window, GLFW_TRUE); | ||
} | ||
|
||
int main(void) | ||
{ | ||
id<MTLDevice> device = MTLCreateSystemDefaultDevice(); | ||
if (!device) | ||
{ | ||
exit(EXIT_FAILURE); | ||
} | ||
|
||
GLFWwindow* window; | ||
|
||
glfwSetErrorCallback(error_callback); | ||
|
||
if (!glfwInit()) | ||
exit(EXIT_FAILURE); | ||
|
||
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); | ||
window = glfwCreateWindow(640, 480, "Metal Example", NULL, NULL); | ||
if (!window) | ||
{ | ||
glfwTerminate(); | ||
exit(EXIT_FAILURE); | ||
} | ||
|
||
NSWindow *nswin = glfwGetCocoaWindow(window); | ||
CAMetalLayer *layer = [CAMetalLayer layer]; | ||
layer.device = device; | ||
layer.pixelFormat = MTLPixelFormatBGRA8Unorm; | ||
This comment has been minimized.
Sorry, something went wrong. |
||
nswin.contentView.layer = layer; | ||
nswin.contentView.wantsLayer = YES; | ||
This comment has been minimized.
Sorry, something went wrong.
dmitshur
Collaborator
|
||
|
||
MTLCompileOptions *compileOptions = [MTLCompileOptions new]; | ||
compileOptions.languageVersion = MTLLanguageVersion1_1; | ||
NSError *compileError; | ||
id<MTLLibrary> lib = [device newLibraryWithSource: | ||
@"#include <metal_stdlib>\n" | ||
"using namespace metal;\n" | ||
"vertex float4 v_simple(\n" | ||
" constant float4 *in [[buffer(0)]],\n" | ||
" uint vid [[vertex_id]])\n" | ||
"{\n" | ||
" return in[vid];\n" | ||
"}\n" | ||
"fragment float4 f_simple(\n" | ||
" float4 in [[stage_in]])\n" | ||
"{\n" | ||
" return float4(1, 0, 0, 1);\n" | ||
"}\n" | ||
options:compileOptions error:&compileError]; | ||
if (!lib) | ||
{ | ||
NSLog(@"can't create library: %@", compileError); | ||
glfwTerminate(); | ||
exit(EXIT_FAILURE); | ||
} | ||
|
||
id<MTLFunction> vs = [lib newFunctionWithName:@"v_simple"]; | ||
assert(vs); | ||
id<MTLFunction> fs = [lib newFunctionWithName:@"f_simple"]; | ||
assert(fs); | ||
|
||
id<MTLCommandQueue> cq = [device newCommandQueue]; | ||
assert(cq); | ||
|
||
MTLRenderPipelineDescriptor *rpd = [MTLRenderPipelineDescriptor new]; | ||
rpd.vertexFunction = vs; | ||
rpd.fragmentFunction = fs; | ||
rpd.colorAttachments[0].pixelFormat = layer.pixelFormat; | ||
id<MTLRenderPipelineState> rps = [device newRenderPipelineStateWithDescriptor:rpd error:NULL]; | ||
assert(rps); | ||
|
||
glfwSetKeyCallback(window, key_callback); | ||
|
||
while (!glfwWindowShouldClose(window)) | ||
{ | ||
float ratio; | ||
int width, height; | ||
|
||
glfwGetFramebufferSize(window, &width, &height); | ||
ratio = width / (float) height; | ||
|
||
layer.drawableSize = CGSizeMake(width, height); | ||
id<CAMetalDrawable> drawable = [layer nextDrawable]; | ||
assert(drawable); | ||
|
||
id<MTLCommandBuffer> cb = [cq commandBuffer]; | ||
|
||
MTLRenderPassDescriptor *rpd = [MTLRenderPassDescriptor new]; | ||
MTLRenderPassColorAttachmentDescriptor *cd = rpd.colorAttachments[0]; | ||
cd.texture = drawable.texture; | ||
cd.loadAction = MTLLoadActionClear; | ||
cd.clearColor = MTLClearColorMake(1.0, 1.0, 1.0, 1.0); | ||
cd.storeAction = MTLStoreActionStore; | ||
id<MTLRenderCommandEncoder> rce = [cb renderCommandEncoderWithDescriptor:rpd]; | ||
|
||
[rce setRenderPipelineState:rps]; | ||
[rce setVertexBytes:(vector_float4[]){ | ||
{ 0, 0, 0, 1 }, | ||
{ -1, 1, 0, 1 }, | ||
{ 1, 1, 0, 1 }, | ||
} length:3 * sizeof(vector_float4) atIndex:0]; | ||
[rce drawPrimitives:MTLPrimitiveTypeTriangle vertexStart:0 vertexCount:3]; | ||
|
||
[rce endEncoding]; | ||
[cb presentDrawable:drawable]; | ||
[cb commit]; | ||
|
||
glfwPollEvents(); | ||
} | ||
|
||
glfwDestroyWindow(window); | ||
|
||
glfwTerminate(); | ||
exit(EXIT_SUCCESS); | ||
} | ||
|
||
//! [code] |
FWIW, according to https://developer.apple.com/documentation/quartzcore/cametallayer/1478155-pixelformat:
So this line is a no-op.