Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/intern
diff options
context:
space:
mode:
Diffstat (limited to 'intern')
-rw-r--r--intern/ghost/intern/GHOST_ContextCGL.h35
-rw-r--r--intern/ghost/intern/GHOST_ContextCGL.mm327
-rw-r--r--intern/ghost/intern/GHOST_SystemCocoa.mm2
-rw-r--r--intern/ghost/intern/GHOST_WindowCocoa.h10
-rw-r--r--intern/ghost/intern/GHOST_WindowCocoa.mm78
-rw-r--r--intern/ghost/intern/GHOST_WindowViewCocoa.h11
6 files changed, 429 insertions, 34 deletions
diff --git a/intern/ghost/intern/GHOST_ContextCGL.h b/intern/ghost/intern/GHOST_ContextCGL.h
index b808effc795..37c1ac34299 100644
--- a/intern/ghost/intern/GHOST_ContextCGL.h
+++ b/intern/ghost/intern/GHOST_ContextCGL.h
@@ -26,15 +26,23 @@
#include "GHOST_Context.h"
-@class NSOpenGLView;
+@class CAMetalLayer;
+@class MTLCommandQueue;
+@class MTLRenderPipelineState;
+@class MTLTexture;
@class NSOpenGLContext;
+@class NSOpenGLView;
+@class NSView;
class GHOST_ContextCGL : public GHOST_Context {
public:
/**
* Constructor.
*/
- GHOST_ContextCGL(bool stereoVisual, NSOpenGLView *openGLView);
+ GHOST_ContextCGL(bool stereoVisual,
+ NSView *metalView,
+ CAMetalLayer *metalLayer,
+ NSOpenGLView *openglView);
/**
* Destructor.
@@ -59,6 +67,8 @@ class GHOST_ContextCGL : public GHOST_Context {
*/
GHOST_TSuccess releaseDrawingContext();
+ unsigned int getDefaultFramebuffer();
+
/**
* Call immediately after new to initialize. If this fails then immediately delete the object.
* \return Indication as to whether initialization has succeeded.
@@ -94,12 +104,24 @@ class GHOST_ContextCGL : public GHOST_Context {
GHOST_TSuccess updateDrawingContext();
private:
- /** The openGL view */
+ /** Metal state */
+ NSView *m_metalView;
+ CAMetalLayer *m_metalLayer;
+ MTLCommandQueue *m_metalCmdQueue;
+ MTLRenderPipelineState *m_metalRenderPipeline;
+
+ /** OpenGL state, for GPUs that don't support Metal */
NSOpenGLView *m_openGLView;
/** The OpenGL drawing context */
NSOpenGLContext *m_openGLContext;
+ /** The virtualized default framebuffer */
+ unsigned int m_defaultFramebuffer;
+
+ /** The virtualized default framebuffer's texture */
+ MTLTexture *m_defaultFramebufferMetalTexture;
+
bool m_coreProfile;
const bool m_debug;
@@ -107,6 +129,13 @@ class GHOST_ContextCGL : public GHOST_Context {
/** The first created OpenGL context (for sharing display lists) */
static NSOpenGLContext *s_sharedOpenGLContext;
static int s_sharedCount;
+
+ /* Metal functions */
+ void metalInit();
+ void metalFree();
+ void metalInitFramebuffer();
+ void metalUpdateFramebuffer();
+ void metalSwapBuffers();
};
#endif // __GHOST_CONTEXTCGL_H__
diff --git a/intern/ghost/intern/GHOST_ContextCGL.mm b/intern/ghost/intern/GHOST_ContextCGL.mm
index 5fe40cb04a0..12c340ffe97 100644
--- a/intern/ghost/intern/GHOST_ContextCGL.mm
+++ b/intern/ghost/intern/GHOST_ContextCGL.mm
@@ -26,25 +26,61 @@
#include "GHOST_ContextCGL.h"
#include <Cocoa/Cocoa.h>
+#include <QuartzCore/QuartzCore.h>
+#include <Metal/Metal.h>
#include <vector>
#include <cassert>
+static void ghost_fatal_error_dialog(const char *msg)
+{
+ @autoreleasepool {
+ NSString *message = [NSString stringWithFormat:@"Error opening window:\n%s", msg];
+
+ NSAlert *alert = [[NSAlert alloc] init];
+ [alert addButtonWithTitle:@"Quit"];
+ [alert setMessageText:@"Blender"];
+ [alert setInformativeText:message];
+ [alert setAlertStyle:NSAlertStyleCritical];
+ [alert runModal];
+ }
+
+ exit(1);
+}
+
NSOpenGLContext *GHOST_ContextCGL::s_sharedOpenGLContext = nil;
int GHOST_ContextCGL::s_sharedCount = 0;
-GHOST_ContextCGL::GHOST_ContextCGL(bool stereoVisual, NSOpenGLView *openGLView)
- : GHOST_Context(stereoVisual), m_openGLView(openGLView), m_openGLContext(nil), m_debug(false)
+GHOST_ContextCGL::GHOST_ContextCGL(bool stereoVisual,
+ NSView *metalView,
+ CAMetalLayer *metalLayer,
+ NSOpenGLView *openGLView)
+ : GHOST_Context(stereoVisual),
+ m_metalView(metalView),
+ m_metalLayer(metalLayer),
+ m_metalCmdQueue(nil),
+ m_metalRenderPipeline(nil),
+ m_openGLView(openGLView),
+ m_openGLContext(nil),
+ m_defaultFramebuffer(0),
+ m_defaultFramebufferMetalTexture(nil),
+ m_debug(false)
{
#if defined(WITH_GL_PROFILE_CORE)
m_coreProfile = true;
#else
m_coreProfile = false;
#endif
+
+ if (m_metalView) {
+ metalInit();
+ }
}
GHOST_ContextCGL::~GHOST_ContextCGL()
{
+ metalFree();
+
if (m_openGLContext != nil) {
if (m_openGLContext == [NSOpenGLContext currentContext]) {
[NSOpenGLContext clearCurrentContext];
@@ -70,9 +106,14 @@ GHOST_ContextCGL::~GHOST_ContextCGL()
GHOST_TSuccess GHOST_ContextCGL::swapBuffers()
{
if (m_openGLContext != nil) {
- NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
- [m_openGLContext flushBuffer];
- [pool drain];
+ if (m_metalView) {
+ metalSwapBuffers();
+ }
+ else if (m_openGLView) {
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+ [m_openGLContext flushBuffer];
+ [pool drain];
+ }
return GHOST_kSuccess;
}
else {
@@ -139,12 +180,23 @@ GHOST_TSuccess GHOST_ContextCGL::releaseDrawingContext()
}
}
+unsigned int GHOST_ContextCGL::getDefaultFramebuffer()
+{
+ return m_defaultFramebuffer;
+}
+
GHOST_TSuccess GHOST_ContextCGL::updateDrawingContext()
{
if (m_openGLContext != nil) {
- NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
- [m_openGLContext update];
- [pool drain];
+ if (m_metalView) {
+ metalUpdateFramebuffer();
+ }
+ else if (m_openGLView) {
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+ [m_openGLContext update];
+ [pool drain];
+ }
+
return GHOST_kSuccess;
}
else {
@@ -233,7 +285,15 @@ GHOST_TSuccess GHOST_ContextCGL::initializeDrawingContext()
initContextGLEW();
- if (m_openGLView) {
+ if (m_metalView) {
+ if (m_defaultFramebuffer == 0) {
+ // Create a virtual framebuffer
+ [m_openGLContext makeCurrentContext];
+ metalInitFramebuffer();
+ initClearGL();
+ }
+ }
+ else if (m_openGLView) {
[m_openGLView setOpenGLContext:m_openGLContext];
[m_openGLContext setView:m_openGLView];
initClearGL();
@@ -261,8 +321,253 @@ error:
GHOST_TSuccess GHOST_ContextCGL::releaseNativeHandles()
{
- m_openGLContext = NULL;
- m_openGLView = NULL;
+ m_openGLContext = nil;
+ m_openGLView = nil;
+ m_metalView = nil;
return GHOST_kSuccess;
}
+
+/* OpenGL on Metal
+ *
+ * Use Metal layer to avoid Viewport lagging on macOS, see T60043. */
+
+static const MTLPixelFormat METAL_FRAMEBUFFERPIXEL_FORMAT = MTLPixelFormatBGRA8Unorm;
+static const OSType METAL_CORE_VIDEO_PIXEL_FORMAT = kCVPixelFormatType_32BGRA;
+
+void GHOST_ContextCGL::metalInit()
+{
+ @autoreleasepool {
+ id<MTLDevice> device = m_metalLayer.device;
+
+ // Create a command queue for blit/present operation
+ m_metalCmdQueue = (MTLCommandQueue *)[device newCommandQueue];
+ [m_metalCmdQueue retain];
+
+ // Create shaders for blit operation
+ NSString *source = @R"msl(
+ using namespace metal;
+
+ struct Vertex {
+ float4 position [[position]];
+ float2 texCoord [[attribute(0)]];
+ };
+
+ vertex Vertex vertex_shader(uint v_id [[vertex_id]]) {
+ Vertex vtx;
+
+ vtx.position.x = float(v_id & 1) * 4.0 - 1.0;
+ vtx.position.y = float(v_id >> 1) * 4.0 - 1.0;
+ vtx.position.z = 0.0;
+ vtx.position.w = 1.0;
+
+ vtx.texCoord = vtx.position.xy * 0.5 + 0.5;
+
+ return vtx;
+ }
+
+ constexpr sampler s {};
+
+ fragment float4 fragment_shader(Vertex v [[stage_in]],
+ texture2d<float> t [[texture(0)]]) {
+ return t.sample(s, v.texCoord);
+ }
+
+ )msl";
+
+ MTLCompileOptions *options = [[[MTLCompileOptions alloc] init] autorelease];
+ options.languageVersion = MTLLanguageVersion1_1;
+
+ NSError *error = nil;
+ id<MTLLibrary> library = [device newLibraryWithSource:source options:options error:&error];
+ if (error) {
+ ghost_fatal_error_dialog(
+ "GHOST_ContextCGL::metalInit: newLibraryWithSource:options:error: failed!");
+ }
+
+ // Create a render pipeline for blit operation
+ MTLRenderPipelineDescriptor *desc = [[[MTLRenderPipelineDescriptor alloc] init] autorelease];
+
+ desc.fragmentFunction = [library newFunctionWithName:@"fragment_shader"];
+ desc.vertexFunction = [library newFunctionWithName:@"vertex_shader"];
+
+ [desc.colorAttachments objectAtIndexedSubscript:0].pixelFormat = METAL_FRAMEBUFFERPIXEL_FORMAT;
+
+ m_metalRenderPipeline = (MTLRenderPipelineState *)[device
+ newRenderPipelineStateWithDescriptor:desc
+ error:&error];
+ if (error) {
+ ghost_fatal_error_dialog(
+ "GHOST_ContextCGL::metalInit: newRenderPipelineStateWithDescriptor:error: failed!");
+ }
+ }
+}
+
+void GHOST_ContextCGL::metalFree()
+{
+ if (m_metalCmdQueue) {
+ [m_metalCmdQueue release];
+ }
+ if (m_metalRenderPipeline) {
+ [m_metalRenderPipeline release];
+ }
+ if (m_defaultFramebufferMetalTexture) {
+ [m_defaultFramebufferMetalTexture release];
+ }
+}
+
+void GHOST_ContextCGL::metalInitFramebuffer()
+{
+ glGenFramebuffers(1, &m_defaultFramebuffer);
+ updateDrawingContext();
+ glBindFramebuffer(GL_FRAMEBUFFER, m_defaultFramebuffer);
+}
+
+void GHOST_ContextCGL::metalUpdateFramebuffer()
+{
+ assert(m_defaultFramebuffer != 0);
+
+ NSRect bounds = [m_metalView bounds];
+ NSSize backingSize = [m_metalView convertSizeToBacking:bounds.size];
+ size_t width = (size_t)backingSize.width;
+ size_t height = (size_t)backingSize.height;
+
+ {
+ /* Test if there is anything to update */
+ id<MTLTexture> tex = (id<MTLTexture>)m_defaultFramebufferMetalTexture;
+ if (tex && tex.width == width && tex.height == height) {
+ return;
+ }
+ }
+
+ activateDrawingContext();
+
+ NSDictionary *cvPixelBufferProps = @{
+ (__bridge NSString *)kCVPixelBufferOpenGLCompatibilityKey : @YES,
+ (__bridge NSString *)kCVPixelBufferMetalCompatibilityKey : @YES,
+ };
+ CVPixelBufferRef cvPixelBuffer = nil;
+ CVReturn cvret = CVPixelBufferCreate(kCFAllocatorDefault,
+ width,
+ height,
+ METAL_CORE_VIDEO_PIXEL_FORMAT,
+ (__bridge CFDictionaryRef)cvPixelBufferProps,
+ &cvPixelBuffer);
+ if (cvret != kCVReturnSuccess) {
+ ghost_fatal_error_dialog(
+ "GHOST_ContextCGL::metalUpdateFramebuffer: CVPixelBufferCreate failed!");
+ }
+
+ // Create an OpenGL texture
+ CVOpenGLTextureCacheRef cvGLTexCache = nil;
+ cvret = CVOpenGLTextureCacheCreate(kCFAllocatorDefault,
+ nil,
+ m_openGLContext.CGLContextObj,
+ m_openGLContext.pixelFormat.CGLPixelFormatObj,
+ nil,
+ &cvGLTexCache);
+ if (cvret != kCVReturnSuccess) {
+ ghost_fatal_error_dialog(
+ "GHOST_ContextCGL::metalUpdateFramebuffer: CVOpenGLTextureCacheCreate failed!");
+ }
+
+ CVOpenGLTextureRef cvGLTex = nil;
+ cvret = CVOpenGLTextureCacheCreateTextureFromImage(
+ kCFAllocatorDefault, cvGLTexCache, cvPixelBuffer, nil, &cvGLTex);
+ if (cvret != kCVReturnSuccess) {
+ ghost_fatal_error_dialog(
+ "GHOST_ContextCGL::metalUpdateFramebuffer: "
+ "CVOpenGLTextureCacheCreateTextureFromImage failed!");
+ }
+
+ unsigned int glTex;
+ glTex = CVOpenGLTextureGetName(cvGLTex);
+
+ // Create a Metal texture
+ CVMetalTextureCacheRef cvMetalTexCache = nil;
+ cvret = CVMetalTextureCacheCreate(
+ kCFAllocatorDefault, nil, m_metalLayer.device, nil, &cvMetalTexCache);
+ if (cvret != kCVReturnSuccess) {
+ ghost_fatal_error_dialog(
+ "GHOST_ContextCGL::metalUpdateFramebuffer: CVMetalTextureCacheCreate failed!");
+ }
+
+ CVMetalTextureRef cvMetalTex = nil;
+ cvret = CVMetalTextureCacheCreateTextureFromImage(kCFAllocatorDefault,
+ cvMetalTexCache,
+ cvPixelBuffer,
+ nil,
+ METAL_FRAMEBUFFERPIXEL_FORMAT,
+ width,
+ height,
+ 0,
+ &cvMetalTex);
+ if (cvret != kCVReturnSuccess) {
+ ghost_fatal_error_dialog(
+ "GHOST_ContextCGL::metalUpdateFramebuffer: "
+ "CVMetalTextureCacheCreateTextureFromImage failed!");
+ }
+
+ MTLTexture *tex = (MTLTexture *)CVMetalTextureGetTexture(cvMetalTex);
+
+ if (!tex) {
+ ghost_fatal_error_dialog(
+ "GHOST_ContextCGL::metalUpdateFramebuffer: CVMetalTextureGetTexture failed!");
+ }
+
+ [m_defaultFramebufferMetalTexture release];
+ m_defaultFramebufferMetalTexture = [tex retain];
+
+ glBindFramebuffer(GL_FRAMEBUFFER, m_defaultFramebuffer);
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_RECTANGLE, glTex, 0);
+
+ [m_metalLayer setDrawableSize:CGSizeMake((CGFloat)width, (CGFloat)height)];
+
+ CVPixelBufferRelease(cvPixelBuffer);
+ CVOpenGLTextureCacheRelease(cvGLTexCache);
+ CVOpenGLTextureRelease(cvGLTex);
+ CFRelease(cvMetalTexCache);
+ CFRelease(cvMetalTex);
+}
+
+void GHOST_ContextCGL::metalSwapBuffers()
+{
+ @autoreleasepool {
+ updateDrawingContext();
+ glFlush();
+
+ assert(m_defaultFramebufferMetalTexture != 0);
+
+ id<CAMetalDrawable> drawable = [m_metalLayer nextDrawable];
+ if (!drawable) {
+ return;
+ }
+
+ id<MTLCommandBuffer> cmdBuffer = [m_metalCmdQueue commandBuffer];
+
+ MTLRenderPassDescriptor *passDescriptor = [MTLRenderPassDescriptor renderPassDescriptor];
+ {
+ auto attachment = [passDescriptor.colorAttachments objectAtIndexedSubscript:0];
+ attachment.texture = drawable.texture;
+ attachment.loadAction = MTLLoadActionDontCare;
+ attachment.storeAction = MTLStoreActionStore;
+ }
+
+ id<MTLTexture> srcTexture = (id<MTLTexture>)m_defaultFramebufferMetalTexture;
+
+ {
+ id<MTLRenderCommandEncoder> enc = [cmdBuffer
+ renderCommandEncoderWithDescriptor:passDescriptor];
+
+ [enc setRenderPipelineState:(id<MTLRenderPipelineState>)m_metalRenderPipeline];
+ [enc setFragmentTexture:srcTexture atIndex:0];
+ [enc drawPrimitives:MTLPrimitiveTypeTriangle vertexStart:0 vertexCount:3];
+
+ [enc endEncoding];
+ }
+
+ [cmdBuffer presentDrawable:drawable];
+
+ [cmdBuffer commit];
+ }
+}
diff --git a/intern/ghost/intern/GHOST_SystemCocoa.mm b/intern/ghost/intern/GHOST_SystemCocoa.mm
index c80424b279b..376ebfa2a21 100644
--- a/intern/ghost/intern/GHOST_SystemCocoa.mm
+++ b/intern/ghost/intern/GHOST_SystemCocoa.mm
@@ -762,7 +762,7 @@ GHOST_IWindow *GHOST_SystemCocoa::createWindow(const STR_String &title,
*/
GHOST_IContext *GHOST_SystemCocoa::createOffscreenContext()
{
- GHOST_Context *context = new GHOST_ContextCGL(false, NULL);
+ GHOST_Context *context = new GHOST_ContextCGL(false, NULL, NULL, NULL);
if (context->initializeDrawingContext())
return context;
else
diff --git a/intern/ghost/intern/GHOST_WindowCocoa.h b/intern/ghost/intern/GHOST_WindowCocoa.h
index 41e7191701e..5300b07523c 100644
--- a/intern/ghost/intern/GHOST_WindowCocoa.h
+++ b/intern/ghost/intern/GHOST_WindowCocoa.h
@@ -32,8 +32,10 @@
#include "GHOST_Window.h"
#include "STR_String.h"
-@class CocoaWindow;
+@class CAMetalLayer;
+@class CocoaMetalView;
@class CocoaOpenGLView;
+@class CocoaWindow;
@class NSCursor;
@class NSScreen;
@@ -313,11 +315,13 @@ class GHOST_WindowCocoa : public GHOST_Window {
int hotX,
int hotY);
- /** The window containing the OpenGL view */
+ /** The window containing the view */
CocoaWindow *m_window;
- /** The openGL view */
+ /** The view, either Metal or OpenGL */
CocoaOpenGLView *m_openGLView;
+ CocoaMetalView *m_metalView;
+ CAMetalLayer *m_metalLayer;
/** The mother SystemCocoa class to send events */
GHOST_SystemCocoa *m_systemCocoa;
diff --git a/intern/ghost/intern/GHOST_WindowCocoa.mm b/intern/ghost/intern/GHOST_WindowCocoa.mm
index 33d9921cdec..45ea3c85005 100644
--- a/intern/ghost/intern/GHOST_WindowCocoa.mm
+++ b/intern/ghost/intern/GHOST_WindowCocoa.mm
@@ -29,6 +29,8 @@
#endif
#include <Cocoa/Cocoa.h>
+#include <QuartzCore/QuartzCore.h>
+#include <Metal/Metal.h>
#include <sys/sysctl.h>
@@ -263,7 +265,17 @@
@end
/* NSView for handling input and drawing. */
+#define COCOA_VIEW_CLASS CocoaOpenGLView
+#define COCOA_VIEW_BASE_CLASS NSOpenGLView
#include "GHOST_WindowViewCocoa.h"
+#undef COCOA_VIEW_CLASS
+#undef COCOA_VIEW_BASE_CLASS
+
+#define COCOA_VIEW_CLASS CocoaMetalView
+#define COCOA_VIEW_BASE_CLASS NSView
+#include "GHOST_WindowViewCocoa.h"
+#undef COCOA_VIEW_CLASS
+#undef COCOA_VIEW_BASE_CLASS
#pragma mark initialization / finalization
@@ -281,6 +293,8 @@ GHOST_WindowCocoa::GHOST_WindowCocoa(GHOST_SystemCocoa *systemCocoa,
bool is_debug)
: GHOST_Window(width, height, state, stereoVisual, false),
m_openGLView(nil),
+ m_metalView(nil),
+ m_metalLayer(nil),
m_systemCocoa(systemCocoa),
m_customCursor(0),
m_immediateDraw(false),
@@ -318,21 +332,44 @@ GHOST_WindowCocoa::GHOST_WindowCocoa(GHOST_SystemCocoa *systemCocoa,
minSize.height = 240;
[m_window setContentMinSize:minSize];
- // Creates the OpenGL View inside the window
- m_openGLView = [[CocoaOpenGLView alloc] initWithFrame:rect];
+ // Create NSView inside the window
+ id<MTLDevice> metalDevice = MTLCreateSystemDefaultDevice();
+ NSView *view;
+
+ if (metalDevice) {
+ // Create metal layer and view if supported
+ m_metalLayer = [[CAMetalLayer alloc] init];
+ [m_metalLayer setEdgeAntialiasingMask:0];
+ [m_metalLayer setMasksToBounds:NO];
+ [m_metalLayer setOpaque:YES];
+ [m_metalLayer setFramebufferOnly:YES];
+ [m_metalLayer setPresentsWithTransaction:NO];
+ [m_metalLayer removeAllAnimations];
+ [m_metalLayer setDevice:metalDevice];
+
+ m_metalView = [[CocoaMetalView alloc] initWithFrame:rect];
+ [m_metalView setWantsLayer:YES];
+ [m_metalView setLayer:m_metalLayer];
+ [m_metalView setSystemAndWindowCocoa:systemCocoa windowCocoa:this];
+ view = m_metalView;
+ }
+ else {
+ // Fallback to OpenGL view if there is no Metal support
+ m_openGLView = [[CocoaOpenGLView alloc] initWithFrame:rect];
+ [m_openGLView setSystemAndWindowCocoa:systemCocoa windowCocoa:this];
+ view = m_openGLView;
+ }
if (m_systemCocoa->m_nativePixel) {
// Needs to happen early when building with the 10.14 SDK, otherwise
// has no effect until resizeing the window.
- if ([m_openGLView respondsToSelector:@selector(setWantsBestResolutionOpenGLSurface:)]) {
- [m_openGLView setWantsBestResolutionOpenGLSurface:YES];
+ if ([view respondsToSelector:@selector(setWantsBestResolutionOpenGLSurface:)]) {
+ [view setWantsBestResolutionOpenGLSurface:YES];
}
}
- [m_openGLView setSystemAndWindowCocoa:systemCocoa windowCocoa:this];
-
- [m_window setContentView:m_openGLView];
- [m_window setInitialFirstResponder:m_openGLView];
+ [m_window setContentView:view];
+ [m_window setInitialFirstResponder:view];
[m_window makeKeyAndOrderFront:nil];
@@ -381,7 +418,18 @@ GHOST_WindowCocoa::~GHOST_WindowCocoa()
releaseNativeHandles();
- [m_openGLView release];
+ if (m_openGLView) {
+ [m_openGLView release];
+ m_openGLView = nil;
+ }
+ if (m_metalView) {
+ [m_metalView release];
+ m_metalView = nil;
+ }
+ if (m_metalLayer) {
+ [m_metalLayer release];
+ m_metalLayer = nil;
+ }
if (m_window) {
[m_window close];
@@ -405,7 +453,8 @@ GHOST_WindowCocoa::~GHOST_WindowCocoa()
bool GHOST_WindowCocoa::getValid() const
{
- return GHOST_Window::getValid() && m_window != NULL && m_openGLView != NULL;
+ NSView *view = (m_openGLView) ? m_openGLView : m_metalView;
+ return GHOST_Window::getValid() && m_window != NULL && view != NULL;
}
void *GHOST_WindowCocoa::getOSWindow() const
@@ -669,7 +718,8 @@ NSScreen *GHOST_WindowCocoa::getScreen()
/* called for event, when window leaves monitor to another */
void GHOST_WindowCocoa::setNativePixelSize(void)
{
- NSRect backingBounds = [m_openGLView convertRectToBacking:[m_openGLView bounds]];
+ NSView *view = (m_openGLView) ? m_openGLView : m_metalView;
+ NSRect backingBounds = [view convertRectToBacking:[view bounds]];
GHOST_Rect rect;
getClientBounds(rect);
@@ -763,7 +813,8 @@ GHOST_Context *GHOST_WindowCocoa::newDrawingContext(GHOST_TDrawingContextType ty
{
if (type == GHOST_kDrawingContextTypeOpenGL) {
- GHOST_Context *context = new GHOST_ContextCGL(m_wantStereoVisual, m_openGLView);
+ GHOST_Context *context = new GHOST_ContextCGL(
+ m_wantStereoVisual, m_metalView, m_metalLayer, m_openGLView);
if (context->initializeDrawingContext())
return context;
@@ -780,7 +831,8 @@ GHOST_TSuccess GHOST_WindowCocoa::invalidate()
{
GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::invalidate(): window invalid");
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
- [m_openGLView setNeedsDisplay:YES];
+ NSView *view = (m_openGLView) ? m_openGLView : m_metalView;
+ [view setNeedsDisplay:YES];
[pool drain];
return GHOST_kSuccess;
}
diff --git a/intern/ghost/intern/GHOST_WindowViewCocoa.h b/intern/ghost/intern/GHOST_WindowViewCocoa.h
index 601c5fbdead..9ed339c9992 100644
--- a/intern/ghost/intern/GHOST_WindowViewCocoa.h
+++ b/intern/ghost/intern/GHOST_WindowViewCocoa.h
@@ -17,10 +17,15 @@
* All rights reserved.
*/
-/* NSView subclass for drawing and handling input. */
+/* NSView subclass for drawing and handling input.
+ *
+ * COCOA_VIEW_BASE_CLASS will be either NSView or NSOpenGLView depending if
+ * we use a Metal or OpenGL layer for drawing in the view. We use macros
+ * to defined classes for each case, so we don't have to duplicate code as
+ * Objective-C does not have multiple inheritance. */
// We need to subclass it in order to give Cocoa the feeling key events are trapped
-@interface CocoaOpenGLView : NSOpenGLView <NSTextInput>
+@interface COCOA_VIEW_CLASS : COCOA_VIEW_BASE_CLASS <NSTextInput>
{
GHOST_SystemCocoa *systemCocoa;
GHOST_WindowCocoa *associatedWindow;
@@ -34,7 +39,7 @@
windowCocoa:(GHOST_WindowCocoa *)winCocoa;
@end
-@implementation CocoaOpenGLView
+@implementation COCOA_VIEW_CLASS
- (void)setSystemAndWindowCocoa:(GHOST_SystemCocoa *)sysCocoa
windowCocoa:(GHOST_WindowCocoa *)winCocoa