forked from mitsuba-renderer/nanogui
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathdarwin.mm
194 lines (157 loc) · 6.59 KB
/
darwin.mm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
#include <nanogui/nanogui.h>
#import <Cocoa/Cocoa.h>
#if defined(NANOGUI_USE_METAL)
# import <Metal/Metal.h>
# import <QuartzCore/CAMetalLayer.h>
# import <QuartzCore/CATransaction.h>
#endif
#if !defined(MAC_OS_X_VERSION_10_15) || \
MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_15
@interface NSScreen (ForwardDeclare)
@property(readonly)
CGFloat maximumPotentialExtendedDynamicRangeColorComponentValue;
@end
#endif
NAMESPACE_BEGIN(nanogui)
std::vector<std::string>
file_dialog(const std::vector<std::pair<std::string, std::string>> &filetypes,
bool save, bool multiple) {
if (save && multiple)
throw std::invalid_argument("file_dialog(): 'save' and 'multiple' must not both be true.");
std::vector<std::string> result;
if (save) {
NSSavePanel *saveDlg = [NSSavePanel savePanel];
NSMutableArray *types = [NSMutableArray new];
for (size_t idx = 0; idx < filetypes.size(); ++idx)
[types addObject: [NSString stringWithUTF8String: filetypes[idx].first.c_str()]];
[saveDlg setAllowedFileTypes: types];
if ([saveDlg runModal] == NSModalResponseOK)
result.emplace_back([[[saveDlg URL] path] UTF8String]);
} else {
NSOpenPanel *openDlg = [NSOpenPanel openPanel];
[openDlg setCanChooseFiles:YES];
[openDlg setCanChooseDirectories:NO];
[openDlg setAllowsMultipleSelection:multiple];
NSMutableArray *types = [NSMutableArray new];
for (size_t idx = 0; idx < filetypes.size(); ++idx)
[types addObject: [NSString stringWithUTF8String: filetypes[idx].first.c_str()]];
[openDlg setAllowedFileTypes: types];
if ([openDlg runModal] == NSModalResponseOK) {
for (NSURL* url in [openDlg URLs]) {
result.emplace_back((char*) [[url path] UTF8String]);
}
}
}
return result;
}
void chdir_to_bundle_parent() {
NSString *path = [[[NSBundle mainBundle] bundlePath] stringByDeletingLastPathComponent];
chdir([path fileSystemRepresentation]);
}
void disable_saved_application_state_osx() {
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"NSQuitAlwaysKeepsWindows"];
}
#if defined(NANOGUI_USE_METAL)
static void *s_metal_device = nullptr;
static void *s_metal_command_queue = nullptr;
void metal_init() {
if (s_metal_device || s_metal_command_queue)
throw std::runtime_error("init_metal(): already initialized!");
id<MTLDevice> device = MTLCreateSystemDefaultDevice();
if (!device)
throw std::runtime_error("init_metal(): unable to create system default device.");
id<MTLCommandQueue> command_queue = [device newCommandQueue];
if (!command_queue)
throw std::runtime_error("init_metal(): unable to create command queue.");
s_metal_device = (__bridge_retained void *) device;
s_metal_command_queue = (__bridge_retained void *) command_queue;
}
void metal_shutdown() {
(void) (__bridge_transfer id<MTLDevice>) s_metal_command_queue;
(void) (__bridge_transfer id<MTLCommandQueue>) s_metal_device;
}
void* metal_device() { return s_metal_device; }
void* metal_command_queue() { return s_metal_command_queue; }
void metal_window_init(void *nswin_, bool float_buffer) {
CAMetalLayer *layer = [CAMetalLayer layer];
if (!layer)
throw std::runtime_error("init_metal(): unable to create layer.");
NSWindow *nswin = (__bridge NSWindow *) nswin_;
nswin.contentView.layer = layer;
nswin.contentView.wantsLayer = YES;
nswin.contentView.layerContentsPlacement = NSViewLayerContentsPlacementTopLeft;
layer.device = (__bridge id<MTLDevice>) s_metal_device;
layer.contentsScale = nswin.backingScaleFactor;
if (float_buffer) {
layer.wantsExtendedDynamicRangeContent = YES;
layer.pixelFormat = MTLPixelFormatRGBA16Float;
layer.colorspace = CGColorSpaceCreateWithName(kCGColorSpaceExtendedSRGB);
} else {
layer.wantsExtendedDynamicRangeContent = NO;
layer.pixelFormat = MTLPixelFormatBGRA8Unorm;
layer.colorspace = CGColorSpaceCreateWithName(kCGColorSpaceSRGB);
}
layer.displaySyncEnabled = NO;
layer.allowsNextDrawableTimeout = NO;
layer.framebufferOnly = NO;
}
std::pair<bool, bool> metal_10bit_edr_support() {
NSArray<NSScreen *> * screens = [NSScreen screens];
bool buffer_10bit = false,
buffer_ext = false;
for (NSScreen * screen in screens) {
if ([screen canRepresentDisplayGamut: NSDisplayGamutP3]) {
buffer_10bit = true; // on macOS, P3 gamut is equivalent to 10 bit color depth
}
if ([screen respondsToSelector:@selector
(maximumPotentialExtendedDynamicRangeColorComponentValue)]) {
if ([screen maximumPotentialExtendedDynamicRangeColorComponentValue] >= 2.f) {
buffer_10bit = true;
buffer_ext = true;
}
}
}
return { buffer_10bit, buffer_ext };
}
void* metal_layer(void *nswin_) {
NSWindow *nswin = (__bridge NSWindow *) nswin_;
CAMetalLayer *layer = (CAMetalLayer *) nswin.contentView.layer;
return (__bridge void *) layer;
}
void metal_window_set_size(void *nswin_, const Vector2i &size) {
NSWindow *nswin = (__bridge NSWindow *) nswin_;
CAMetalLayer *layer = (CAMetalLayer *) nswin.contentView.layer;
layer.drawableSize = CGSizeMake(size.x(), size.y());
}
void metal_window_set_content_scale(void *nswin_, float scale) {
NSWindow *nswin = (__bridge NSWindow *) nswin_;
CAMetalLayer *layer = (CAMetalLayer *) nswin.contentView.layer;
float old_scale = layer.contentsScale;
if (old_scale != scale) {
[CATransaction begin];
[CATransaction setValue:(id)kCFBooleanTrue
forKey:kCATransactionDisableActions];
layer.contentsScale = scale;
[CATransaction commit];
}
}
void* metal_window_layer(void *nswin_) {
NSWindow *nswin = (__bridge NSWindow *) nswin_;
return (__bridge void *) nswin.contentView.layer;
}
void* metal_window_next_drawable(void *nswin_) {
NSWindow *nswin = (__bridge NSWindow *) nswin_;
CAMetalLayer *layer = (CAMetalLayer *) nswin.contentView.layer;
id<MTLDrawable> drawable = layer.nextDrawable;
return (__bridge_retained void *) drawable;
}
void *metal_drawable_texture(void *drawable_) {
id<CAMetalDrawable> drawable = (__bridge id<CAMetalDrawable>) drawable_;
return (__bridge void *) drawable.texture;
}
void metal_present_and_release_drawable(void *drawable_) {
id<CAMetalDrawable> drawable = (__bridge_transfer id<CAMetalDrawable>) drawable_;
[drawable present];
}
#endif
NAMESPACE_END(nanogui)