Initial integration of Metal API

This commit is contained in:
Jack Andersen 2015-11-08 16:24:45 -10:00
parent 606e3676b1
commit 2be32d6ca4
7 changed files with 516 additions and 943 deletions

View File

@ -40,6 +40,7 @@ elseif(APPLE)
list(APPEND PLAT_SRCS list(APPEND PLAT_SRCS
lib/mac/ApplicationCocoa.mm lib/mac/ApplicationCocoa.mm
lib/mac/WindowCocoa.mm lib/mac/WindowCocoa.mm
lib/mac/CocoaCommon.hpp
lib/inputdev/HIDListenerIOKit.cpp lib/inputdev/HIDListenerIOKit.cpp
lib/inputdev/HIDDeviceIOKit.cpp lib/inputdev/HIDDeviceIOKit.cpp
lib/graphicsdev/Metal.mm) lib/graphicsdev/Metal.mm)
@ -50,8 +51,11 @@ elseif(APPLE)
find_library(APPKIT_LIBRARY AppKit) find_library(APPKIT_LIBRARY AppKit)
find_library(IOKIT_LIBRARY IOKit) find_library(IOKIT_LIBRARY IOKit)
find_library(OPENGL_LIBRARY OpenGL) find_library(OPENGL_LIBRARY OpenGL)
find_library(METAL_LIBRARY Metal)
find_library(QUARTZCORE_LIBRARY QuartzCore)
find_library(COREVIDEO_LIBRARY CoreVideo) find_library(COREVIDEO_LIBRARY CoreVideo)
list(APPEND _BOO_SYS_LIBS ${APPKIT_LIBRARY} ${IOKIT_LIBRARY} ${OPENGL_LIBRARY} ${COREVIDEO_LIBRARY}) list(APPEND _BOO_SYS_LIBS ${APPKIT_LIBRARY} ${IOKIT_LIBRARY} ${OPENGL_LIBRARY} ${METAL_LIBRARY}
${QUARTZCORE_LIBRARY} ${COREVIDEO_LIBRARY})
else(NOT GEKKO) else(NOT GEKKO)
list(APPEND PLAT_SRCS list(APPEND PLAT_SRCS
lib/x11/ApplicationUnix.cpp lib/x11/ApplicationUnix.cpp

View File

@ -6,17 +6,20 @@
#include "boo/IGraphicsContext.hpp" #include "boo/IGraphicsContext.hpp"
#include <vector> #include <vector>
#include <unordered_set> #include <unordered_set>
#include <unordered_map>
namespace boo namespace boo
{ {
struct MetalContext;
class MetalDataFactory : public IGraphicsDataFactory class MetalDataFactory : public IGraphicsDataFactory
{ {
IGraphicsContext* m_parent; IGraphicsContext* m_parent;
IGraphicsData* m_deferredData = nullptr; IGraphicsData* m_deferredData = nullptr;
std::unordered_set<IGraphicsData*> m_committedData; std::unordered_set<IGraphicsData*> m_committedData;
struct MetalContext* m_ctx;
public: public:
MetalDataFactory(IGraphicsContext* parent); MetalDataFactory(IGraphicsContext* parent, MetalContext* ctx);
~MetalDataFactory() {} ~MetalDataFactory() {}
Platform platform() const {return PlatformMetal;} Platform platform() const {return PlatformMetal;}
@ -36,7 +39,7 @@ public:
IVertexFormat* newVertexFormat(size_t elementCount, const VertexElementDescriptor* elements); IVertexFormat* newVertexFormat(size_t elementCount, const VertexElementDescriptor* elements);
IShaderPipeline* newShaderPipeline(const char* vertSource, const char* fragSource, IShaderPipeline* newShaderPipeline(const char* vertSource, const char* fragSource,
size_t texCount, const char** texNames, IVertexFormat* vtxFmt, ITextureR* target,
BlendFactor srcFac, BlendFactor dstFac, BlendFactor srcFac, BlendFactor dstFac,
bool depthTest, bool depthWrite, bool backfaceCulling); bool depthTest, bool depthWrite, bool backfaceCulling);
@ -53,14 +56,6 @@ public:
void destroyAllData(); void destroyAllData();
}; };
struct MetalContext
{
struct Window
{
};
};
} }
#endif // GDEV_METAL_HPP #endif // GDEV_METAL_HPP

File diff suppressed because it is too large Load Diff

View File

@ -3,6 +3,7 @@
#include "boo/IApplication.hpp" #include "boo/IApplication.hpp"
#include "boo/graphicsdev/Metal.hpp" #include "boo/graphicsdev/Metal.hpp"
#include "CocoaCommon.hpp"
namespace boo {class ApplicationCocoa;} namespace boo {class ApplicationCocoa;}
@interface AppDelegate : NSObject <NSApplicationDelegate> @interface AppDelegate : NSObject <NSApplicationDelegate>
@ -92,6 +93,15 @@ public:
[aboutText setString:@"\nBoo Authors\n\nJackoalan\nAntidote\n"]; [aboutText setString:@"\nBoo Authors\n\nJackoalan\nAntidote\n"];
[aboutPanel setContentView:aboutText]; [aboutPanel setContentView:aboutText];
appDelegate->aboutPanel = aboutPanel; appDelegate->aboutPanel = aboutPanel;
/* Determine which graphics API to use */
for (const SystemString& arg : args)
if (!arg.compare("--metal"))
{
m_metalCtx.m_dev = MTLCreateSystemDefaultDevice();
m_metalCtx.m_q = [m_metalCtx.m_dev.get() newCommandQueue];
break;
}
} }
EPlatformType getPlatformType() const EPlatformType getPlatformType() const

41
lib/mac/CocoaCommon.hpp Normal file
View File

@ -0,0 +1,41 @@
#ifndef BOO_COCOACOMMON_HPP
#define BOO_COCOACOMMON_HPP
#if __APPLE__
#include <Metal/Metal.h>
#include <QuartzCore/CAMetalLayer.h>
template <class T>
class NSPtr
{
T m_ptr = 0;
public:
NSPtr() = default;
~NSPtr() {[m_ptr release];}
NSPtr(T&& recv) : m_ptr(recv) {}
NSPtr& operator=(T&& recv) {[m_ptr release]; m_ptr = recv; return *this;}
NSPtr(const NSPtr& other) = delete;
NSPtr(NSPtr&& other) = default;
NSPtr& operator=(const NSPtr& other) = delete;
NSPtr& operator=(NSPtr&& other) = default;
operator bool() const {return m_ptr != 0;}
T get() const {return m_ptr;}
void reset() {[m_ptr release]; m_ptr = 0;}
};
namespace boo
{
struct MetalContext
{
NSPtr<id<MTLDevice>> m_dev;
NSPtr<id<MTLCommandQueue>> m_q;
struct Window
{
CAMetalLayer* m_metalLayer = nullptr;
};
std::unordered_map<IWindow*, Window> m_windows;
};
}
#endif // __APPLE__
#endif // BOO_COCOACOMMON_HPP

View File

@ -1,6 +1,7 @@
#include "boo/graphicsdev/GL.hpp" #include "boo/graphicsdev/GL.hpp"
#include "boo/graphicsdev/glew.h" #include "boo/graphicsdev/glew.h"
#include "boo/graphicsdev/Metal.hpp" #include "boo/graphicsdev/Metal.hpp"
#include "CocoaCommon.hpp"
#import <AppKit/AppKit.h> #import <AppKit/AppKit.h>
#import <CoreVideo/CVDisplayLink.h> #import <CoreVideo/CVDisplayLink.h>
#include "boo/IApplication.hpp" #include "boo/IApplication.hpp"
@ -142,6 +143,7 @@ class GraphicsContextCocoaMetal;
@interface GraphicsContextCocoaMetalInternal : NSView @interface GraphicsContextCocoaMetalInternal : NSView
{ {
BooCocoaResponder* resp; BooCocoaResponder* resp;
boo::MetalContext* m_ctx;
} }
- (id)initWithBooContext:(boo::GraphicsContextCocoaMetal*)bctx; - (id)initWithBooContext:(boo::GraphicsContextCocoaMetal*)bctx;
@end @end
@ -150,7 +152,7 @@ namespace boo
{ {
static LogVisor::LogModule Log("boo::WindowCocoa"); static LogVisor::LogModule Log("boo::WindowCocoa");
IGraphicsCommandQueue* _NewGLCommandQueue(IGraphicsContext* parent); IGraphicsCommandQueue* _NewGLCommandQueue(IGraphicsContext* parent);
IGraphicsCommandQueue* _NewMetalCommandQueue(MetalContext* ctx, MetalContext::Window* windowCtx, IGraphicsCommandQueue* _NewMetalCommandQueue(MetalContext* ctx, IWindow* parentWindow,
IGraphicsContext* parent); IGraphicsContext* parent);
void _CocoaUpdateLastGLCtx(NSOpenGLContext* lastGLCtx); void _CocoaUpdateLastGLCtx(NSOpenGLContext* lastGLCtx);
@ -297,17 +299,16 @@ class GraphicsContextCocoaMetal : public GraphicsContextCocoa
IGraphicsCommandQueue* m_commandQueue = nullptr; IGraphicsCommandQueue* m_commandQueue = nullptr;
IGraphicsDataFactory* m_dataFactory = nullptr; IGraphicsDataFactory* m_dataFactory = nullptr;
MetalContext* m_metalCtx;
MetalContext::Window* m_metalWindowCtx;
public: public:
MetalContext* m_metalCtx;
GraphicsContextCocoaMetal(EGraphicsAPI api, IWindow* parentWindow, GraphicsContextCocoaMetal(EGraphicsAPI api, IWindow* parentWindow,
MetalContext* metalCtx, MetalContext::Window* metalWindowCtx) MetalContext* metalCtx)
: GraphicsContextCocoa(api, PF_RGBA8, parentWindow), : GraphicsContextCocoa(api, PF_RGBA8, parentWindow),
m_metalCtx(metalCtx), m_metalWindowCtx(metalWindowCtx) m_metalCtx(metalCtx)
{ {
m_dataFactory = new MetalDataFactory(this); m_dataFactory = new MetalDataFactory(this, metalCtx);
} }
~GraphicsContextCocoaMetal() ~GraphicsContextCocoaMetal()
@ -315,6 +316,7 @@ public:
delete m_dataFactory; delete m_dataFactory;
delete m_commandQueue; delete m_commandQueue;
[m_nsContext release]; [m_nsContext release];
m_metalCtx->m_windows.erase(m_parentWindow);
} }
void _setCallback(IWindowCallback* cb) void _setCallback(IWindowCallback* cb)
@ -341,14 +343,16 @@ public:
void initializeContext() void initializeContext()
{ {
MetalContext::Window& w = m_metalCtx->m_windows[m_parentWindow];
m_nsContext = [[GraphicsContextCocoaMetalInternal alloc] initWithBooContext:this]; m_nsContext = [[GraphicsContextCocoaMetalInternal alloc] initWithBooContext:this];
if (!m_nsContext) if (!m_nsContext)
Log.report(LogVisor::FatalError, "unable to make new NSView for Metal"); Log.report(LogVisor::FatalError, "unable to make new NSView for Metal");
w.m_metalLayer = (CAMetalLayer*)m_nsContext.layer;
[(NSWindow*)m_parentWindow->getPlatformHandle() setContentView:m_nsContext]; [(NSWindow*)m_parentWindow->getPlatformHandle() setContentView:m_nsContext];
CVDisplayLinkCreateWithActiveCGDisplays(&m_dispLink); CVDisplayLinkCreateWithActiveCGDisplays(&m_dispLink);
CVDisplayLinkSetOutputCallback(m_dispLink, (CVDisplayLinkOutputCallback)DLCallback, this); CVDisplayLinkSetOutputCallback(m_dispLink, (CVDisplayLinkOutputCallback)DLCallback, this);
CVDisplayLinkStart(m_dispLink); CVDisplayLinkStart(m_dispLink);
m_commandQueue = _NewMetalCommandQueue(m_metalCtx, m_metalWindowCtx, this); m_commandQueue = _NewMetalCommandQueue(m_metalCtx, m_parentWindow, this);
} }
void makeCurrent() void makeCurrent()
@ -382,12 +386,11 @@ public:
IGraphicsContext* _GraphicsContextCocoaMetalNew(IGraphicsContext::EGraphicsAPI api, IGraphicsContext* _GraphicsContextCocoaMetalNew(IGraphicsContext::EGraphicsAPI api,
IWindow* parentWindow, IWindow* parentWindow,
MetalContext* metalCtx, MetalContext* metalCtx)
MetalContext::Window* metalWindowCtx)
{ {
if (api != IGraphicsContext::API_METAL) if (api != IGraphicsContext::API_METAL)
return nullptr; return nullptr;
return new GraphicsContextCocoaMetal(api, parentWindow, metalCtx, metalWindowCtx); return new GraphicsContextCocoaMetal(api, parentWindow, metalCtx);
} }
} }
@ -881,6 +884,8 @@ static boo::ESpecialKey translateKeycode(short code)
@implementation GraphicsContextCocoaMetalInternal @implementation GraphicsContextCocoaMetalInternal
- (id)initWithBooContext:(boo::GraphicsContextCocoaMetal*)bctx - (id)initWithBooContext:(boo::GraphicsContextCocoaMetal*)bctx
{ {
self = [self initWithFrame:NSMakeRect(0, 0, 100, 100)];
m_ctx = bctx->m_metalCtx;
resp = [[BooCocoaResponder alloc] initWithBooContext:bctx View:self]; resp = [[BooCocoaResponder alloc] initWithBooContext:bctx View:self];
return self; return self;
} }
@ -891,6 +896,20 @@ static boo::ESpecialKey translateKeycode(short code)
[super dealloc]; [super dealloc];
} }
- (BOOL)wantsLayer
{
return YES;
}
- (CALayer*)makeBackingLayer
{
CAMetalLayer* layer = [CAMetalLayer new];
layer.device = m_ctx->m_dev.get();
layer.pixelFormat = MTLPixelFormatBGRA8Unorm;
layer.framebufferOnly = NO;
return layer;
}
- (BOOL)acceptsTouchEvents - (BOOL)acceptsTouchEvents
{ {
return YES; return YES;
@ -924,7 +943,10 @@ public:
dispatch_sync(dispatch_get_main_queue(), dispatch_sync(dispatch_get_main_queue(),
^{ ^{
m_nsWindow = [[WindowCocoaInternal alloc] initWithBooWindow:this title:title]; m_nsWindow = [[WindowCocoaInternal alloc] initWithBooWindow:this title:title];
m_gfxCtx = _GraphicsContextCocoaGLNew(IGraphicsContext::API_OPENGL_3_3, this, lastGLCtx); if (metalCtx->m_dev)
m_gfxCtx = _GraphicsContextCocoaMetalNew(IGraphicsContext::API_METAL, this, metalCtx);
else
m_gfxCtx = _GraphicsContextCocoaGLNew(IGraphicsContext::API_OPENGL_3_3, this, lastGLCtx);
m_gfxCtx->initializeContext(); m_gfxCtx->initializeContext();
}); });
} }

View File

@ -9,6 +9,8 @@
#if _WIN32 #if _WIN32
#include <boo/graphicsdev/D3D.hpp> #include <boo/graphicsdev/D3D.hpp>
#elif __APPLE__
#include <boo/graphicsdev/Metal.hpp>
#endif #endif
namespace boo namespace boo
@ -336,6 +338,33 @@ struct TestApplicationCallback : IApplicationCallback
pipeline = d3dF->newShaderPipeline(VS, PS, vsCompile, psCompile, vfmt, pipeline = d3dF->newShaderPipeline(VS, PS, vsCompile, psCompile, vfmt,
BlendFactorOne, BlendFactorZero, true, true, false); BlendFactorOne, BlendFactorZero, true, true, false);
} }
#elif __APPLE__
else if (factory->platform() == IGraphicsDataFactory::PlatformMetal)
{
MetalDataFactory* metalF = dynamic_cast<MetalDataFactory*>(factory);
static const char* VS =
"struct VertData {float3 in_pos [[ attribute(0) ]]; float2 in_uv [[ attribute(1) ]];};\n"
"struct VertToFrag {float4 out_pos [[ position ]]; float2 out_uv;};\n"
"vertex VertToFrag main(VertData v [[ stage_in ]])\n"
"{\n"
" VertToFrag retval;\n"
" retval.out_pos = float4(v.in_pos, 1.0);\n"
" retval.out_uv = v.in_uv;\n"
" return retval;\n"
"}\n";
static const char* FS =
"constexpr sampler samp(address::repeat);\n"
"struct VertToFrag {float4 out_pos [[ position ]]; float2 out_uv;};\n"
"fragment float4 main(VertToFrag d [[ stage_in ]], texture2d<float> tex [[ texture(0) ]])\n"
"{\n"
" return tex.sample(samp, d.out_uv);\n"
"}\n";
pipeline = metalF->newShaderPipeline(VS, FS, vfmt, self->m_renderTarget,
BlendFactorOne, BlendFactorZero, true, true, false);
}
#endif #endif