28 #include <Cocoa/Cocoa.h>
29 #include <Metal/Metal.h>
30 #include <QuartzCore/QuartzCore.h>
40 NSString *message = [NSString stringWithFormat:
@"Error opening window:\n%s", msg];
42 NSAlert *alert = [[NSAlert alloc]
init];
43 [alert addButtonWithTitle:
@"Quit"];
44 [alert setMessageText:
@"Blender"];
45 [alert setInformativeText:message];
46 [alert setAlertStyle:NSAlertStyleCritical];
53 NSOpenGLContext *GHOST_ContextCGL::s_sharedOpenGLContext = nil;
54 int GHOST_ContextCGL::s_sharedCount = 0;
58 CAMetalLayer *metalLayer,
59 NSOpenGLView *openGLView)
61 m_metalView(metalView),
62 m_metalLayer(metalLayer),
64 m_metalRenderPipeline(nil),
65 m_openGLView(openGLView),
67 m_defaultFramebuffer(0),
68 m_defaultFramebufferMetalTexture(nil),
71 #if defined(WITH_GL_PROFILE_CORE)
74 m_coreProfile =
false;
86 if (m_openGLContext != nil) {
87 if (m_openGLContext == [NSOpenGLContext currentContext]) {
88 [NSOpenGLContext clearCurrentContext];
91 [m_openGLView clearGLContext];
95 if (m_openGLContext != s_sharedOpenGLContext || s_sharedCount == 1) {
96 assert(s_sharedCount > 0);
100 if (s_sharedCount == 0)
101 s_sharedOpenGLContext = nil;
103 [m_openGLContext release];
110 if (m_openGLContext != nil) {
114 else if (m_openGLView) {
115 NSAutoreleasePool *
pool = [[NSAutoreleasePool alloc]
init];
116 [m_openGLContext flushBuffer];
128 if (m_openGLContext != nil) {
129 NSAutoreleasePool *
pool = [[NSAutoreleasePool alloc]
init];
130 [m_openGLContext setValues:&interval forParameter:NSOpenGLCPSwapInterval];
141 if (m_openGLContext != nil) {
144 NSAutoreleasePool *
pool = [[NSAutoreleasePool alloc]
init];
146 [m_openGLContext getValues:&interval forParameter:NSOpenGLCPSwapInterval];
150 intervalOut =
static_cast<int>(interval);
161 if (m_openGLContext != nil) {
162 NSAutoreleasePool *
pool = [[NSAutoreleasePool alloc]
init];
163 [m_openGLContext makeCurrentContext];
174 if (m_openGLContext != nil) {
175 NSAutoreleasePool *
pool = [[NSAutoreleasePool alloc]
init];
176 [NSOpenGLContext clearCurrentContext];
187 return m_defaultFramebuffer;
192 if (m_openGLContext != nil) {
194 metalUpdateFramebuffer();
196 else if (m_openGLView) {
197 NSAutoreleasePool *
pool = [[NSAutoreleasePool alloc]
init];
217 attribs.push_back(NSOpenGLPFAOpenGLProfile);
218 attribs.push_back(coreProfile ? NSOpenGLProfileVersion3_2Core : NSOpenGLProfileVersionLegacy);
221 attribs.push_back(NSOpenGLPFADoubleBuffer);
224 attribs.push_back(NSOpenGLPFARendererID);
225 attribs.push_back(kCGLRendererGenericFloatID);
228 attribs.push_back(NSOpenGLPFAAccelerated);
229 attribs.push_back(NSOpenGLPFANoRecovery);
233 attribs.push_back(NSOpenGLPFAStereo);
236 attribs.push_back(NSOpenGLPFAAlphaSize);
237 attribs.push_back((NSOpenGLPixelFormatAttribute)8);
240 attribs.push_back((NSOpenGLPixelFormatAttribute)0);
245 NSAutoreleasePool *
pool = [[NSAutoreleasePool alloc]
init];
247 #ifdef GHOST_OPENGL_ALPHA
248 static const bool needAlpha =
true;
250 static const bool needAlpha =
false;
253 static bool softwareGL = getenv(
"BLENDER_SOFTWAREGL");
255 std::vector<NSOpenGLPixelFormatAttribute> attribs;
259 NSOpenGLPixelFormat *pixelFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:&attribs[0]];
260 if (pixelFormat == nil) {
264 m_openGLContext = [[NSOpenGLContext alloc] initWithFormat:pixelFormat
265 shareContext:s_sharedOpenGLContext];
266 [pixelFormat release];
268 [m_openGLContext makeCurrentContext];
271 GLint major = 0, minor = 0;
272 glGetIntegerv(GL_MAJOR_VERSION, &major);
273 glGetIntegerv(GL_MINOR_VERSION, &minor);
274 fprintf(stderr,
"OpenGL version %d.%d%s\n", major, minor, softwareGL ?
" (software)" :
"");
275 fprintf(stderr,
"Renderer: %s\n", glGetString(GL_RENDERER));
278 #ifdef GHOST_WAIT_FOR_VSYNC
282 [m_openGLContext setValues:&swapInt forParameter:NSOpenGLCPSwapInterval];
289 if (m_defaultFramebuffer == 0) {
291 [m_openGLContext makeCurrentContext];
292 metalInitFramebuffer();
296 else if (m_openGLView) {
297 [m_openGLView setOpenGLContext:m_openGLContext];
298 [m_openGLContext setView:m_openGLView];
302 [m_openGLContext flushBuffer];
304 if (s_sharedCount == 0)
305 s_sharedOpenGLContext = m_openGLContext;
315 [pixelFormat release];
324 m_openGLContext = nil;
338 void GHOST_ContextCGL::metalInit()
343 id<MTLDevice> device = m_metalLayer.device;
346 m_metalCmdQueue = (MTLCommandQueue *)[device newCommandQueue];
347 [m_metalCmdQueue retain];
350 NSString *source = @R
"msl(
351 using namespace metal;
354 float4 position [[position]];
355 float2 texCoord [[attribute(0)]];
358 vertex Vertex vertex_shader(uint v_id [[vertex_id]]) {
361 vtx.position.x = float(v_id & 1) * 4.0 - 1.0;
362 vtx.position.y = float(v_id >> 1) * 4.0 - 1.0;
363 vtx.position.z = 0.0;
364 vtx.position.w = 1.0;
366 vtx.texCoord = vtx.position.xy * 0.5 + 0.5;
371 constexpr sampler s {};
373 fragment float4 fragment_shader(Vertex v [[stage_in]],
374 texture2d<float> t [[texture(0)]]) {
375 return t.sample(s, v.texCoord);
380 MTLCompileOptions *options = [[[MTLCompileOptions alloc] init] autorelease];
381 options.languageVersion = MTLLanguageVersion1_1;
383 NSError *error = nil;
387 "GHOST_ContextCGL::metalInit: newLibraryWithSource:options:error: failed!");
391 MTLRenderPipelineDescriptor *desc = [[[MTLRenderPipelineDescriptor alloc]
init] autorelease];
393 desc.fragmentFunction = [
library newFunctionWithName:
@"fragment_shader"];
394 desc.vertexFunction = [
library newFunctionWithName:
@"vertex_shader"];
398 m_metalRenderPipeline = (MTLRenderPipelineState *)[device
399 newRenderPipelineStateWithDescriptor:desc
403 "GHOST_ContextCGL::metalInit: newRenderPipelineStateWithDescriptor:error: failed!");
408 void GHOST_ContextCGL::metalFree()
410 if (m_metalCmdQueue) {
411 [m_metalCmdQueue release];
413 if (m_metalRenderPipeline) {
414 [m_metalRenderPipeline release];
416 if (m_defaultFramebufferMetalTexture) {
417 [m_defaultFramebufferMetalTexture release];
421 void GHOST_ContextCGL::metalInitFramebuffer()
423 glGenFramebuffers(1, &m_defaultFramebuffer);
425 glBindFramebuffer(GL_FRAMEBUFFER, m_defaultFramebuffer);
428 void GHOST_ContextCGL::metalUpdateFramebuffer()
430 assert(m_defaultFramebuffer != 0);
433 NSSize backingSize = [m_metalView convertSizeToBacking:
bounds.size];
434 size_t width = (size_t)backingSize.width;
435 size_t height = (
size_t)backingSize.height;
439 id<MTLTexture>
tex = (id<MTLTexture>)m_defaultFramebufferMetalTexture;
447 NSDictionary *cvPixelBufferProps = @{
448 (__bridge NSString *)kCVPixelBufferOpenGLCompatibilityKey : @YES,
449 (__bridge NSString *)kCVPixelBufferMetalCompatibilityKey : @YES,
451 CVPixelBufferRef cvPixelBuffer = nil;
452 CVReturn cvret = CVPixelBufferCreate(kCFAllocatorDefault,
456 (__bridge CFDictionaryRef)cvPixelBufferProps,
458 if (cvret != kCVReturnSuccess) {
460 "GHOST_ContextCGL::metalUpdateFramebuffer: CVPixelBufferCreate failed!");
464 CVOpenGLTextureCacheRef cvGLTexCache = nil;
465 cvret = CVOpenGLTextureCacheCreate(kCFAllocatorDefault,
467 m_openGLContext.CGLContextObj,
468 m_openGLContext.pixelFormat.CGLPixelFormatObj,
471 if (cvret != kCVReturnSuccess) {
473 "GHOST_ContextCGL::metalUpdateFramebuffer: CVOpenGLTextureCacheCreate failed!");
476 CVOpenGLTextureRef cvGLTex = nil;
477 cvret = CVOpenGLTextureCacheCreateTextureFromImage(
478 kCFAllocatorDefault, cvGLTexCache, cvPixelBuffer, nil, &cvGLTex);
479 if (cvret != kCVReturnSuccess) {
481 "GHOST_ContextCGL::metalUpdateFramebuffer: "
482 "CVOpenGLTextureCacheCreateTextureFromImage failed!");
486 glTex = CVOpenGLTextureGetName(cvGLTex);
489 CVMetalTextureCacheRef cvMetalTexCache = nil;
490 cvret = CVMetalTextureCacheCreate(
491 kCFAllocatorDefault, nil, m_metalLayer.device, nil, &cvMetalTexCache);
492 if (cvret != kCVReturnSuccess) {
494 "GHOST_ContextCGL::metalUpdateFramebuffer: CVMetalTextureCacheCreate failed!");
497 CVMetalTextureRef cvMetalTex = nil;
498 cvret = CVMetalTextureCacheCreateTextureFromImage(kCFAllocatorDefault,
507 if (cvret != kCVReturnSuccess) {
509 "GHOST_ContextCGL::metalUpdateFramebuffer: "
510 "CVMetalTextureCacheCreateTextureFromImage failed!");
513 MTLTexture *
tex = (MTLTexture *)CVMetalTextureGetTexture(cvMetalTex);
517 "GHOST_ContextCGL::metalUpdateFramebuffer: CVMetalTextureGetTexture failed!");
520 [m_defaultFramebufferMetalTexture release];
521 m_defaultFramebufferMetalTexture = [
tex retain];
523 glBindFramebuffer(GL_FRAMEBUFFER, m_defaultFramebuffer);
524 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_RECTANGLE, glTex, 0);
526 [m_metalLayer setDrawableSize:CGSizeMake((CGFloat)
width, (CGFloat)
height)];
528 CVPixelBufferRelease(cvPixelBuffer);
529 CVOpenGLTextureCacheRelease(cvGLTexCache);
530 CVOpenGLTextureRelease(cvGLTex);
531 CFRelease(cvMetalTexCache);
532 CFRelease(cvMetalTex);
535 void GHOST_ContextCGL::metalSwapBuffers()
543 assert(m_defaultFramebufferMetalTexture != 0);
545 id<CAMetalDrawable> drawable = [m_metalLayer nextDrawable];
550 id<MTLCommandBuffer> cmdBuffer = [m_metalCmdQueue commandBuffer];
552 MTLRenderPassDescriptor *passDescriptor = [MTLRenderPassDescriptor renderPassDescriptor];
554 auto attachment = [passDescriptor.colorAttachments objectAtIndexedSubscript:0];
555 attachment.texture = drawable.texture;
556 attachment.loadAction = MTLLoadActionDontCare;
557 attachment.storeAction = MTLStoreActionStore;
560 id<MTLTexture> srcTexture = (id<MTLTexture>)m_defaultFramebufferMetalTexture;
563 id<MTLRenderCommandEncoder> enc = [cmdBuffer
564 renderCommandEncoderWithDescriptor:passDescriptor];
566 [enc setRenderPipelineState:(id<MTLRenderPipelineState>)m_metalRenderPipeline];
567 [enc setFragmentTexture:srcTexture atIndex:0];
568 [enc drawPrimitives:MTLPrimitiveTypeTriangle vertexStart:0 vertexCount:3];
573 [cmdBuffer presentDrawable:drawable];
static void makeAttribList(std::vector< NSOpenGLPixelFormatAttribute > &attribs, bool coreProfile, bool stereoVisual, bool needAlpha, bool softwareGL)
static void ghost_fatal_error_dialog(const char *msg)
static const OSType METAL_CORE_VIDEO_PIXEL_FORMAT
static const MTLPixelFormat METAL_FRAMEBUFFERPIXEL_FORMAT
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei width
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei height
static btDbvtVolume bounds(btDbvtNode **leaves, int count)
GHOST_TSuccess setSwapInterval(int interval)
unsigned int getDefaultFramebuffer()
GHOST_TSuccess swapBuffers()
GHOST_TSuccess initializeDrawingContext()
GHOST_ContextCGL(bool stereoVisual, NSView *metalView, CAMetalLayer *metalLayer, NSOpenGLView *openglView)
GHOST_TSuccess releaseDrawingContext()
GHOST_TSuccess activateDrawingContext()
GHOST_TSuccess releaseNativeHandles()
GHOST_TSuccess getSwapInterval(int &)
GHOST_TSuccess updateDrawingContext()
static void initClearGL()
CCL_NAMESPACE_BEGIN struct Options options
static FT_Library library
static void error(const char *str)
static void update(bNodeTree *ntree)