14# pragma clang diagnostic ignored "-Wdeprecated-declarations"
19#import <Cocoa/Cocoa.h>
20#import <Metal/Metal.h>
21#import <QuartzCore/QuartzCore.h>
31 NSString *message = [NSString stringWithFormat:
@"Error opening window:\n%s", msg];
33 NSAlert *alert = [[NSAlert alloc]
init];
35 alert.messageText =
@"Blender";
36 alert.informativeText = message;
37 alert.alertStyle = NSAlertStyleCritical;
39 [alert addButtonWithTitle:
@"Quit"];
46MTLCommandQueue *GHOST_ContextCGL::s_sharedMetalCommandQueue = nil;
47int GHOST_ContextCGL::s_sharedCount = 0;
51 CAMetalLayer *metalLayer,
54 m_metalView(metalView),
55 m_metalLayer(metalLayer),
56 m_metalRenderPipeline(nil),
61 current_swapchain_index = 0;
62 for (
int i = 0;
i < METAL_SWAPCHAIN_SIZE;
i++) {
63 m_defaultFramebufferMetalTexture[
i].texture = nil;
64 m_defaultFramebufferMetalTexture[
i].index =
i;
68 m_ownsMetalDevice =
false;
73 id<MTLDevice>
metalDevice = MTLCreateSystemDefaultDevice();
79 m_ownsMetalDevice =
true;
81 m_metalLayer = [[CAMetalLayer alloc]
init];
82 m_metalLayer.edgeAntialiasingMask = 0;
83 m_metalLayer.masksToBounds = NO;
84 m_metalLayer.opaque = YES;
85 m_metalLayer.framebufferOnly = YES;
86 m_metalLayer.presentsWithTransaction = NO;
87 [m_metalLayer removeAllAnimations];
89 m_metalLayer.allowsNextDrawableTimeout = NO;
97 m_metalLayer.wantsExtendedDynamicRangeContent = YES;
99 const CFStringRef name = kCGColorSpaceExtendedSRGB;
100 CGColorSpaceRef colorspace = CGColorSpaceCreateWithName(name);
101 m_metalLayer.colorspace = colorspace;
102 CGColorSpaceRelease(colorspace);
108 "[ERROR] Failed to create Metal device for offscreen GHOST Context.\n");
113 mtl_SwapInterval = 60;
121 if (m_ownsMetalDevice) {
123 [m_metalLayer release];
130 [s_sharedMetalCommandQueue release];
131 if (s_sharedCount == 0) {
132 s_sharedMetalCommandQueue = nil;
146 mtl_SwapInterval = interval;
152 intervalOut = mtl_SwapInterval;
177 metalUpdateFramebuffer();
186 current_swapchain_index = (current_swapchain_index + 1) % METAL_SWAPCHAIN_SIZE;
192 return m_defaultFramebufferMetalTexture[current_swapchain_index].texture;
197 return s_sharedMetalCommandQueue;
201 id<MTLDevice> device = m_metalLayer.device;
202 return (MTLDevice *)device;
206 MTLRenderPassDescriptor *, id<MTLRenderPipelineState>, id<MTLTexture>, id<CAMetalDrawable>))
208 this->contextPresentCallback = callback;
215 metalInitFramebuffer();
229void GHOST_ContextCGL::metalInit()
232 id<MTLDevice> device = m_metalLayer.device;
237 if (s_sharedMetalCommandQueue == nil) {
238 s_sharedMetalCommandQueue = (MTLCommandQueue *)[device
242 [s_sharedMetalCommandQueue retain];
246 NSString *source = @R
"msl(
247 using namespace metal;
250 float4 position [[position]];
251 float2 texCoord [[attribute(0)]];
254 vertex Vertex vertex_shader(uint v_id [[vertex_id]]) {
257 vtx.position.x = float(v_id & 1) * 4.0 - 1.0;
258 vtx.position.y = float(v_id >> 1) * 4.0 - 1.0;
259 vtx.position.z = 0.0;
260 vtx.position.w = 1.0;
262 vtx.texCoord = vtx.position.xy * 0.5 + 0.5;
267 constexpr sampler s {};
269 fragment float4 fragment_shader(Vertex v [[stage_in]],
270 texture2d<float> t [[texture(0)]]) {
272 /* Final blit should ensure alpha is 1.0. This resolves
273 * rendering artifacts for blitting of final back-buffer. */
274 float4 out_tex = t.sample(s, v.texCoord);
280 MTLCompileOptions *options = [[[MTLCompileOptions alloc] init] autorelease];
281 options.languageVersion = MTLLanguageVersion1_1;
283 NSError *error = nil;
287 "GHOST_ContextCGL::metalInit: newLibraryWithSource:options:error: failed!");
291 MTLRenderPipelineDescriptor *desc = [[[MTLRenderPipelineDescriptor alloc]
init] autorelease];
293 desc.fragmentFunction = [library newFunctionWithName:
@"fragment_shader"];
294 desc.vertexFunction = [library newFunctionWithName:
@"vertex_shader"];
295 [desc.colorAttachments objectAtIndexedSubscript:0].pixelFormat =
299 [library autorelease];
301 m_metalRenderPipeline = (MTLRenderPipelineState *)[device
302 newRenderPipelineStateWithDescriptor:desc
306 "GHOST_ContextCGL::metalInit: newRenderPipelineStateWithDescriptor:error: failed!");
312 desc.label =
@"Metal Overlay";
313 desc.colorAttachments[0].blendingEnabled = YES;
314 desc.colorAttachments[0].sourceRGBBlendFactor = MTLBlendFactorSourceAlpha;
315 desc.colorAttachments[0].destinationRGBBlendFactor = MTLBlendFactorOneMinusSourceAlpha;
319 "GHOST_ContextCGL::metalInit: newRenderPipelineStateWithDescriptor:error: failed (when "
320 "creating the Metal overlay pipeline)!");
323 [desc.fragmentFunction release];
324 [desc.vertexFunction release];
328void GHOST_ContextCGL::metalFree()
330 if (m_metalRenderPipeline) {
331 [m_metalRenderPipeline release];
332 m_metalRenderPipeline = nil;
335 for (
int i = 0;
i < METAL_SWAPCHAIN_SIZE;
i++) {
336 if (m_defaultFramebufferMetalTexture[
i].
texture) {
337 [m_defaultFramebufferMetalTexture[
i].texture release];
338 m_defaultFramebufferMetalTexture[
i].texture = nil;
343void GHOST_ContextCGL::metalInitFramebuffer()
348void GHOST_ContextCGL::metalUpdateFramebuffer()
352 const NSSize backingSize = [m_metalView convertSizeToBacking:
bounds.size];
353 const size_t width = size_t(backingSize.width);
354 const size_t height = size_t(backingSize.height);
356 if (m_defaultFramebufferMetalTexture[current_swapchain_index].
texture &&
357 m_defaultFramebufferMetalTexture[current_swapchain_index].
texture.width == width &&
358 m_defaultFramebufferMetalTexture[current_swapchain_index].texture.height == height)
364 [m_defaultFramebufferMetalTexture[current_swapchain_index].texture release];
366 id<MTLDevice> device = m_metalLayer.device;
367 MTLTextureDescriptor *overlayDesc = [MTLTextureDescriptor
372 overlayDesc.storageMode = MTLStorageModePrivate;
373 overlayDesc.usage = MTLTextureUsageRenderTarget | MTLTextureUsageShaderRead;
375 id<MTLTexture> overlayTex = [device newTextureWithDescriptor:overlayDesc];
378 "GHOST_ContextCGL::metalUpdateFramebuffer: failed to create Metal overlay texture!");
381 overlayTex.label = [NSString
382 stringWithFormat:
@"Metal Overlay for GHOST Context %p",
this];
385 m_defaultFramebufferMetalTexture[current_swapchain_index].texture = overlayTex;
388 id<MTLCommandBuffer> cmdBuffer = [s_sharedMetalCommandQueue commandBuffer];
389 MTLRenderPassDescriptor *passDescriptor = [MTLRenderPassDescriptor renderPassDescriptor];
391 auto attachment = [passDescriptor.colorAttachments objectAtIndexedSubscript:0];
392 attachment.texture = m_defaultFramebufferMetalTexture[current_swapchain_index].texture;
393 attachment.loadAction = MTLLoadActionClear;
394 attachment.clearColor = MTLClearColorMake(0.294, 0.294, 0.294, 1.000);
395 attachment.storeAction = MTLStoreActionStore;
398 id<MTLRenderCommandEncoder> enc = [cmdBuffer
399 renderCommandEncoderWithDescriptor:passDescriptor];
404 m_metalLayer.drawableSize = CGSizeMake(CGFloat(width), CGFloat(height));
408void GHOST_ContextCGL::metalSwapBuffers()
413 id<CAMetalDrawable> drawable = [m_metalLayer nextDrawable];
418 MTLRenderPassDescriptor *passDescriptor = [MTLRenderPassDescriptor renderPassDescriptor];
420 auto attachment = [passDescriptor.colorAttachments objectAtIndexedSubscript:0];
421 attachment.texture = drawable.texture;
422 attachment.loadAction = MTLLoadActionClear;
423 attachment.clearColor = MTLClearColorMake(1.0, 0.294, 0.294, 1.000);
424 attachment.storeAction = MTLStoreActionStore;
427 assert(contextPresentCallback);
428 assert(m_defaultFramebufferMetalTexture[current_swapchain_index].
texture != nil);
429 (*contextPresentCallback)(passDescriptor,
430 (id<MTLRenderPipelineState>)m_metalRenderPipeline,
431 m_defaultFramebufferMetalTexture[current_swapchain_index].texture,
static const MTLPixelFormat METAL_FRAMEBUFFERPIXEL_FORMAT_EDR
static void ghost_fatal_error_dialog(const char *msg)
static btDbvtVolume bounds(btDbvtNode **leaves, int count)
void metalRegisterPresentCallback(void(*callback)(MTLRenderPassDescriptor *, id< MTLRenderPipelineState >, id< MTLTexture >, id< CAMetalDrawable >))
GHOST_TSuccess updateDrawingContext() override
id< MTLTexture > metalOverlayTexture()
GHOST_TSuccess swapBuffers() override
GHOST_TSuccess activateDrawingContext() override
GHOST_TSuccess getSwapInterval(int &intervalOut) override
MTLDevice * metalDevice()
GHOST_ContextCGL(bool stereoVisual, NSView *metalView, CAMetalLayer *metalLayer, int debug)
GHOST_TSuccess releaseDrawingContext() override
static const int max_command_buffer_count
GHOST_TSuccess initializeDrawingContext() override
unsigned int getDefaultFramebuffer() override
MTLCommandQueue * metalCommandQueue()
GHOST_TSuccess releaseNativeHandles() override
GHOST_TSuccess setSwapInterval(int interval) override
~GHOST_ContextCGL() override
static GHOST_Context * active_context_
GHOST_Context(bool stereoVisual)
CCL_NAMESPACE_BEGIN struct Options options
TEX_TEMPLATE DataVec texture(T, FltCoord, float=0.0f) RET
#define assert(assertion)
static void error(const char *str)
static void init(bNodeTree *, bNode *node)