Compare commits

...

3 Commits

Author SHA1 Message Date
Camilla Berglund
70297aeb49 Metal example code cleanup 2016-12-19 13:50:57 +01:00
Camilla Berglund
8eb2345347 Add Metal guide 2016-12-19 13:49:57 +01:00
Keith Bauer
97b652c584 Initial Metal example 2016-12-19 13:49:57 +01:00
5 changed files with 180 additions and 0 deletions

View File

@ -14,6 +14,7 @@ set(glfw_DOCS_SOURCES
"${GLFW_SOURCE_DIR}/docs/window.dox"
"${GLFW_SOURCE_DIR}/docs/input.dox"
"${GLFW_SOURCE_DIR}/docs/vulkan.dox"
"${GLFW_SOURCE_DIR}/docs/metal.dox"
"${GLFW_SOURCE_DIR}/docs/compat.dox")
if (GLFW_DOCUMENT_INTERNALS)

View File

@ -34,6 +34,8 @@ use the new API.
There is a section on @ref guarantees_limitations for pointer lifetimes,
reentrancy, thread safety, event order and backward and forward compatibility.
The @ref metal shows how to use Metal with GLFW on OS X.
The [FAQ](http://www.glfw.org/faq.html) answers many common questions about the
design, implementation and use of GLFW.

7
docs/metal.dox Normal file
View File

@ -0,0 +1,7 @@
/*!
@page metal Metal guide
@tableofcontents
*/

View File

@ -41,6 +41,13 @@ add_executable(wave WIN32 MACOSX_BUNDLE wave.c ${ICON} ${GLAD})
target_link_libraries(particles "${CMAKE_THREAD_LIBS_INIT}" "${RT_LIBRARY}")
if (APPLE)
add_executable(metal MACOSX_BUNDLE metal.m ${ICON})
target_compile_options(metal PUBLIC "-fobjc-arc")
target_link_libraries(metal "-framework Metal" "-framework QuartzCore")
set_target_properties(metal PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "Metal")
endif()
set(WINDOWS_BINARIES boing gears heightmap particles simple splitview wave)
set(CONSOLE_BINARIES offscreen)
@ -57,6 +64,7 @@ if (APPLE)
set_target_properties(boing PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "Boing")
set_target_properties(gears PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "Gears")
set_target_properties(heightmap PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "Heightmap")
set_target_properties(metal PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "Metal")
set_target_properties(particles PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "Particles")
set_target_properties(simple PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "Simple")
set_target_properties(splitview PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "SplitView")

162
examples/metal.m Normal file
View File

@ -0,0 +1,162 @@
//========================================================================
// 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]
#define GLFW_INCLUDE_NONE
#import <GLFW/glfw3.h>
#define GLFW_EXPOSE_NATIVE_COCOA
#import <GLFW/glfw3native.h>
#import <Metal/Metal.h>
#import <QuartzCore/QuartzCore.h>
#import <simd/simd.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);
glfwSetErrorCallback(error_callback);
if (!glfwInit())
exit(EXIT_FAILURE);
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
GLFWwindow* 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;
nswin.contentView.layer = layer;
nswin.contentView.wantsLayer = YES;
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]