13 # pragma clang diagnostic ignored "-Wdeprecated-declarations"
18 #include <Cocoa/Cocoa.h>
19 #include <Metal/Metal.h>
20 #include <QuartzCore/QuartzCore.h>
30 NSString *message = [NSString stringWithFormat:
@"Error opening window:\n%s", msg];
32 NSAlert *alert = [[NSAlert alloc]
init];
33 [alert addButtonWithTitle:
@"Quit"];
34 [alert setMessageText:
@"Blender"];
35 [alert setInformativeText:message];
36 [alert setAlertStyle:NSAlertStyleCritical];
43 NSOpenGLContext *GHOST_ContextCGL::s_sharedOpenGLContext = nil;
44 int GHOST_ContextCGL::s_sharedCount = 0;
48 CAMetalLayer *metalLayer,
49 NSOpenGLView *openGLView)
51 m_metalView(metalView),
52 m_metalLayer(metalLayer),
54 m_metalRenderPipeline(nil),
55 m_openGLView(openGLView),
57 m_defaultFramebuffer(0),
58 m_defaultFramebufferMetalTexture(nil),
61 #if defined(WITH_GL_PROFILE_CORE)
64 m_coreProfile =
false;
76 if (m_openGLContext != nil) {
77 if (m_openGLContext == [NSOpenGLContext currentContext]) {
78 [NSOpenGLContext clearCurrentContext];
81 [m_openGLView clearGLContext];
85 if (m_openGLContext != s_sharedOpenGLContext || s_sharedCount == 1) {
86 assert(s_sharedCount > 0);
90 if (s_sharedCount == 0)
91 s_sharedOpenGLContext = nil;
93 [m_openGLContext release];
100 if (m_openGLContext != nil) {
104 else if (m_openGLView) {
105 NSAutoreleasePool *
pool = [[NSAutoreleasePool alloc]
init];
106 [m_openGLContext flushBuffer];
118 if (m_openGLContext != nil) {
119 NSAutoreleasePool *
pool = [[NSAutoreleasePool alloc]
init];
120 [m_openGLContext setValues:&interval forParameter:NSOpenGLCPSwapInterval];
131 if (m_openGLContext != nil) {
134 NSAutoreleasePool *
pool = [[NSAutoreleasePool alloc]
init];
136 [m_openGLContext getValues:&interval forParameter:NSOpenGLCPSwapInterval];
140 intervalOut =
static_cast<int>(interval);
151 if (m_openGLContext != nil) {
152 NSAutoreleasePool *
pool = [[NSAutoreleasePool alloc]
init];
153 [m_openGLContext makeCurrentContext];
164 if (m_openGLContext != nil) {
165 NSAutoreleasePool *
pool = [[NSAutoreleasePool alloc]
init];
166 [NSOpenGLContext clearCurrentContext];
177 return m_defaultFramebuffer;
182 if (m_openGLContext != nil) {
184 metalUpdateFramebuffer();
186 else if (m_openGLView) {
187 NSAutoreleasePool *
pool = [[NSAutoreleasePool alloc]
init];
204 bool increasedSamplerLimit)
208 attribs.push_back(NSOpenGLPFAOpenGLProfile);
209 attribs.push_back(coreProfile ? NSOpenGLProfileVersion3_2Core : NSOpenGLProfileVersionLegacy);
212 attribs.push_back(NSOpenGLPFADoubleBuffer);
215 attribs.push_back(NSOpenGLPFARendererID);
216 attribs.push_back(kCGLRendererGenericFloatID);
219 attribs.push_back(NSOpenGLPFAAccelerated);
220 attribs.push_back(NSOpenGLPFANoRecovery);
224 if (increasedSamplerLimit) {
225 attribs.push_back((NSOpenGLPixelFormatAttribute)400);
230 attribs.push_back(NSOpenGLPFAStereo);
233 attribs.push_back(NSOpenGLPFAAlphaSize);
234 attribs.push_back((NSOpenGLPixelFormatAttribute)8);
237 attribs.push_back((NSOpenGLPixelFormatAttribute)0);
244 #ifdef GHOST_OPENGL_ALPHA
245 static const bool needAlpha =
true;
247 static const bool needAlpha =
false;
251 static bool softwareGL = getenv(
"BLENDER_SOFTWAREGL");
253 NSOpenGLPixelFormat *pixelFormat = nil;
254 std::vector<NSOpenGLPixelFormatAttribute> attribs;
255 bool increasedSamplerLimit =
false;
263 if (@available(macos 11.0, *)) {
264 increasedSamplerLimit =
true;
267 const int max_ctx_attempts = increasedSamplerLimit ? 2 : 1;
268 for (
int ctx_create_attempt = 0; ctx_create_attempt < max_ctx_attempts; ctx_create_attempt++) {
273 attribs, m_coreProfile,
m_stereoVisual, needAlpha, softwareGL, increasedSamplerLimit);
275 pixelFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:&attribs[0]];
276 if (pixelFormat == nil) {
279 if (increasedSamplerLimit) {
280 increasedSamplerLimit =
false;
287 m_openGLContext = [[NSOpenGLContext alloc] initWithFormat:pixelFormat
288 shareContext:s_sharedOpenGLContext];
289 [pixelFormat release];
291 if (m_openGLContext == nil) {
294 if (increasedSamplerLimit) {
295 increasedSamplerLimit =
false;
304 [m_openGLContext makeCurrentContext];
307 if (increasedSamplerLimit) {
308 const char *vendor = (
const char *)glGetString(GL_VENDOR);
309 const char *renderer = (
const char *)glGetString(GL_RENDERER);
313 if (strstr(vendor,
"Intel") || strstr(renderer,
"Software")) {
314 [m_openGLContext release];
315 m_openGLContext = nil;
316 increasedSamplerLimit =
false;
323 GLint major = 0, minor = 0;
324 glGetIntegerv(GL_MAJOR_VERSION, &major);
325 glGetIntegerv(GL_MINOR_VERSION, &minor);
326 fprintf(stderr,
"OpenGL version %d.%d%s\n", major, minor, softwareGL ?
" (software)" :
"");
327 fprintf(stderr,
"Renderer: %s\n", glGetString(GL_RENDERER));
330 #ifdef GHOST_WAIT_FOR_VSYNC
334 [m_openGLContext setValues:&swapInt forParameter:NSOpenGLCPSwapInterval];
341 if (m_defaultFramebuffer == 0) {
343 [m_openGLContext makeCurrentContext];
344 metalInitFramebuffer();
348 else if (m_openGLView) {
349 [m_openGLView setOpenGLContext:m_openGLContext];
350 [m_openGLContext setView:m_openGLView];
354 [m_openGLContext flushBuffer];
356 if (s_sharedCount == 0)
357 s_sharedOpenGLContext = m_openGLContext;
366 m_openGLContext = nil;
380 void GHOST_ContextCGL::metalInit()
385 id<MTLDevice> device = m_metalLayer.device;
388 m_metalCmdQueue = (MTLCommandQueue *)[device newCommandQueue];
389 [m_metalCmdQueue retain];
392 NSString *source = @R
"msl(
393 using namespace metal;
396 float4 position [[position]];
397 float2 texCoord [[attribute(0)]];
400 vertex Vertex vertex_shader(uint v_id [[vertex_id]]) {
403 vtx.position.x = float(v_id & 1) * 4.0 - 1.0;
404 vtx.position.y = float(v_id >> 1) * 4.0 - 1.0;
405 vtx.position.z = 0.0;
406 vtx.position.w = 1.0;
408 vtx.texCoord = vtx.position.xy * 0.5 + 0.5;
413 constexpr sampler s {};
415 fragment float4 fragment_shader(Vertex v [[stage_in]],
416 texture2d<float> t [[texture(0)]]) {
417 return t.sample(s, v.texCoord);
422 MTLCompileOptions *options = [[[MTLCompileOptions alloc] init] autorelease];
423 options.languageVersion = MTLLanguageVersion1_1;
425 NSError *error = nil;
429 "GHOST_ContextCGL::metalInit: newLibraryWithSource:options:error: failed!");
433 MTLRenderPipelineDescriptor *desc = [[[MTLRenderPipelineDescriptor alloc]
init] autorelease];
435 desc.fragmentFunction = [
library newFunctionWithName:
@"fragment_shader"];
436 desc.vertexFunction = [
library newFunctionWithName:
@"vertex_shader"];
440 m_metalRenderPipeline = (MTLRenderPipelineState *)[device
441 newRenderPipelineStateWithDescriptor:desc
445 "GHOST_ContextCGL::metalInit: newRenderPipelineStateWithDescriptor:error: failed!");
450 void GHOST_ContextCGL::metalFree()
452 if (m_metalCmdQueue) {
453 [m_metalCmdQueue release];
455 if (m_metalRenderPipeline) {
456 [m_metalRenderPipeline release];
458 if (m_defaultFramebufferMetalTexture) {
459 [m_defaultFramebufferMetalTexture release];
463 void GHOST_ContextCGL::metalInitFramebuffer()
465 glGenFramebuffers(1, &m_defaultFramebuffer);
467 glBindFramebuffer(GL_FRAMEBUFFER, m_defaultFramebuffer);
470 void GHOST_ContextCGL::metalUpdateFramebuffer()
472 assert(m_defaultFramebuffer != 0);
475 NSSize backingSize = [m_metalView convertSizeToBacking:
bounds.size];
476 size_t width = (size_t)backingSize.width;
477 size_t height = (
size_t)backingSize.height;
481 id<MTLTexture>
tex = (id<MTLTexture>)m_defaultFramebufferMetalTexture;
489 NSDictionary *cvPixelBufferProps = @{
490 (__bridge NSString *)kCVPixelBufferOpenGLCompatibilityKey : @YES,
491 (__bridge NSString *)kCVPixelBufferMetalCompatibilityKey : @YES,
493 CVPixelBufferRef cvPixelBuffer = nil;
494 CVReturn cvret = CVPixelBufferCreate(kCFAllocatorDefault,
498 (__bridge CFDictionaryRef)cvPixelBufferProps,
500 if (cvret != kCVReturnSuccess) {
502 "GHOST_ContextCGL::metalUpdateFramebuffer: CVPixelBufferCreate failed!");
506 CVOpenGLTextureCacheRef cvGLTexCache = nil;
507 cvret = CVOpenGLTextureCacheCreate(kCFAllocatorDefault,
509 m_openGLContext.CGLContextObj,
510 m_openGLContext.pixelFormat.CGLPixelFormatObj,
513 if (cvret != kCVReturnSuccess) {
515 "GHOST_ContextCGL::metalUpdateFramebuffer: CVOpenGLTextureCacheCreate failed!");
518 CVOpenGLTextureRef cvGLTex = nil;
519 cvret = CVOpenGLTextureCacheCreateTextureFromImage(
520 kCFAllocatorDefault, cvGLTexCache, cvPixelBuffer, nil, &cvGLTex);
521 if (cvret != kCVReturnSuccess) {
523 "GHOST_ContextCGL::metalUpdateFramebuffer: "
524 "CVOpenGLTextureCacheCreateTextureFromImage failed!");
528 glTex = CVOpenGLTextureGetName(cvGLTex);
531 CVMetalTextureCacheRef cvMetalTexCache = nil;
532 cvret = CVMetalTextureCacheCreate(
533 kCFAllocatorDefault, nil, m_metalLayer.device, nil, &cvMetalTexCache);
534 if (cvret != kCVReturnSuccess) {
536 "GHOST_ContextCGL::metalUpdateFramebuffer: CVMetalTextureCacheCreate failed!");
539 CVMetalTextureRef cvMetalTex = nil;
540 cvret = CVMetalTextureCacheCreateTextureFromImage(kCFAllocatorDefault,
549 if (cvret != kCVReturnSuccess) {
551 "GHOST_ContextCGL::metalUpdateFramebuffer: "
552 "CVMetalTextureCacheCreateTextureFromImage failed!");
555 MTLTexture *
tex = (MTLTexture *)CVMetalTextureGetTexture(cvMetalTex);
559 "GHOST_ContextCGL::metalUpdateFramebuffer: CVMetalTextureGetTexture failed!");
562 [m_defaultFramebufferMetalTexture release];
563 m_defaultFramebufferMetalTexture = [
tex retain];
565 glBindFramebuffer(GL_FRAMEBUFFER, m_defaultFramebuffer);
566 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_RECTANGLE, glTex, 0);
568 [m_metalLayer setDrawableSize:CGSizeMake((CGFloat)
width, (CGFloat)
height)];
570 CVPixelBufferRelease(cvPixelBuffer);
571 CVOpenGLTextureCacheRelease(cvGLTexCache);
572 CVOpenGLTextureRelease(cvGLTex);
573 CFRelease(cvMetalTexCache);
574 CFRelease(cvMetalTex);
577 void GHOST_ContextCGL::metalSwapBuffers()
585 assert(m_defaultFramebufferMetalTexture != 0);
587 id<CAMetalDrawable> drawable = [m_metalLayer nextDrawable];
592 id<MTLCommandBuffer> cmdBuffer = [m_metalCmdQueue commandBuffer];
594 MTLRenderPassDescriptor *passDescriptor = [MTLRenderPassDescriptor renderPassDescriptor];
596 auto attachment = [passDescriptor.colorAttachments objectAtIndexedSubscript:0];
597 attachment.texture = drawable.texture;
598 attachment.loadAction = MTLLoadActionDontCare;
599 attachment.storeAction = MTLStoreActionStore;
602 id<MTLTexture> srcTexture = (id<MTLTexture>)m_defaultFramebufferMetalTexture;
605 id<MTLRenderCommandEncoder> enc = [cmdBuffer
606 renderCommandEncoderWithDescriptor:passDescriptor];
608 [enc setRenderPipelineState:(id<MTLRenderPipelineState>)m_metalRenderPipeline];
609 [enc setFragmentTexture:srcTexture atIndex:0];
610 [enc drawPrimitives:MTLPrimitiveTypeTriangle vertexStart:0 vertexCount:3];
615 [cmdBuffer presentDrawable:drawable];
static void ghost_fatal_error_dialog(const char *msg)
static const OSType METAL_CORE_VIDEO_PIXEL_FORMAT
static void makeAttribList(std::vector< NSOpenGLPixelFormatAttribute > &attribs, bool coreProfile, bool stereoVisual, bool needAlpha, bool softwareGL, bool increasedSamplerLimit)
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 height
_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
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 void error(const char *str)
static void update(bNodeTree *ntree)
static FT_Library library