DisplayManager.mm 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806
  1. #include "DisplayManager.h"
  2. #include "UI/UnityView.h"
  3. #include "UnityAppController.h"
  4. #include "UI/UnityAppController+ViewHandling.h"
  5. #import <QuartzCore/QuartzCore.h>
  6. #import <CoreGraphics/CoreGraphics.h>
  7. #include "UnityMetalSupport.h"
  8. static DisplayManager* _DisplayManager = nil;
  9. @interface DisplayConnection ()
  10. @property (readonly, nonatomic) UnityDisplaySurfaceMTL* surfaceMTL;
  11. @end
  12. @implementation DisplayConnection
  13. {
  14. BOOL _needRecreateSurface;
  15. CGSize _requestedRenderingSize;
  16. #if !PLATFORM_VISIONOS
  17. UIScreen* _screen;
  18. #endif
  19. UIWindow* _window;
  20. UIView* _view;
  21. CGSize _screenSize;
  22. UnityDisplaySurfaceBase* _surface;
  23. }
  24. #if !PLATFORM_VISIONOS
  25. @synthesize screen = _screen;
  26. #endif
  27. @synthesize window = _window;
  28. @synthesize view = _view;
  29. @synthesize screenSize = _screenSize;
  30. @synthesize surface = _surface;
  31. @synthesize surfaceMTL;
  32. - (UnityDisplaySurfaceMTL*)surfaceMTL
  33. {
  34. assert(_surface->api == apiMetal);
  35. return (UnityDisplaySurfaceMTL*)_surface;
  36. }
  37. #if !PLATFORM_VISIONOS
  38. - (id)init:(UIScreen*)targetScreen
  39. {
  40. if ((self = [super init]))
  41. {
  42. self->_screen = targetScreen;
  43. #if !PLATFORM_TVOS
  44. targetScreen.currentMode = targetScreen.preferredMode;
  45. #endif
  46. // UIScreenOverscanCompensationNone == UIScreenOverscanCompensationInsetApplicationFrame so it will work with pre-ios9 just fine
  47. targetScreen.overscanCompensation = UIScreenOverscanCompensationNone;
  48. self->_screenSize = targetScreen.currentMode.size;
  49. self->_needRecreateSurface = NO;
  50. self->_requestedRenderingSize = CGSizeMake(-1, -1);
  51. }
  52. return self;
  53. }
  54. #else
  55. - (id)init
  56. {
  57. if ((self = [super init]))
  58. {
  59. self->_screenSize = CGSizeMake(1920, 1080);
  60. self->_needRecreateSurface = NO;
  61. self->_requestedRenderingSize = CGSizeMake(-1, -1);
  62. }
  63. return self;
  64. }
  65. #endif
  66. - (void)createWithWindow:(UIWindow*)window andView:(UIView*)view
  67. {
  68. _window = window;
  69. _view = view;
  70. CGSize layerSize = _view.layer.bounds.size;
  71. _screenSize = CGSizeMake(roundf(layerSize.width) * _view.contentScaleFactor, roundf(layerSize.height) * _view.contentScaleFactor);
  72. }
  73. - (void)createView:(BOOL)useForRendering
  74. {
  75. [self createView: useForRendering showRightAway: YES];
  76. }
  77. - (void)createView:(BOOL)useForRendering showRightAway:(BOOL)showRightAway;
  78. {
  79. #if !PLATFORM_VISIONOS
  80. NSAssert(_screen != [UIScreen mainScreen], @"DisplayConnection for mainScreen should be created with createWithWindow:andView:");
  81. #endif
  82. if (_view == nil)
  83. {
  84. #if !PLATFORM_VISIONOS
  85. UIWindow* window = [[UIWindow alloc] initWithFrame: _screen.bounds];
  86. window.screen = _screen;
  87. UIView* view = [(useForRendering ? [UnityRenderingView alloc] : [UIView alloc]) initWithFrame: _screen.bounds];
  88. view.contentScaleFactor = UnityScreenScaleFactor(_screen);
  89. #else
  90. UIWindow* window = [[UIWindow alloc] init];
  91. UIView* view = [(useForRendering ? [UnityRenderingView alloc] : [UIView alloc]) init];
  92. #endif
  93. [self createWithWindow: window andView: view];
  94. if (showRightAway)
  95. {
  96. [window addSubview: view];
  97. window.hidden = NO;
  98. }
  99. }
  100. }
  101. - (void)shouldShowWindow:(BOOL)show
  102. {
  103. _window.hidden = show ? NO : YES;
  104. #if !PLATFORM_VISIONOS
  105. _window.screen = show ? _screen : nil;
  106. #endif
  107. }
  108. - (UnityDisplaySurfaceBase*)initRendering
  109. {
  110. if (_surface)
  111. return _surface;
  112. UnityDisplaySurfaceBase* ret = NULL;
  113. const int api = UnitySelectedRenderingAPI();
  114. if (api == apiMetal)
  115. {
  116. UnityDisplaySurfaceMTL* surf = new UnityDisplaySurfaceMTL();
  117. surf->layer = (CAMetalLayer*)_view.layer;
  118. surf->device = UnityGetMetalDevice();
  119. surf->commandQueue = [surf->device newCommandQueueWithMaxCommandBufferCount: UnityCommandQueueMaxCommandBufferCountMTL()];
  120. ret = surf;
  121. }
  122. else
  123. ret = new UnityDisplaySurfaceBase();
  124. ret->api = api;
  125. return ret;
  126. }
  127. - (void)recreateSurface:(RenderingSurfaceParams)params
  128. {
  129. UnityDisplaySurfaceBase* surface = [self initRendering];
  130. // On metal we depend on hardware screen compositor to handle upscaling this way avoiding additional blit
  131. CGSize layerSize = _view.layer.bounds.size;
  132. float scale = _view.contentScaleFactor;
  133. CGSize screenSize = CGSizeMake(layerSize.width * scale, layerSize.height * scale);
  134. // if we did request custom resolution we apply it here.
  135. // for metal we use hardware scaler which will be triggered exactly because our window is not of "native" size
  136. // but we also want to enforce native resolution as maximum, otherwise we might run out of memory vert fast
  137. // TODO: how about supersampling screenshots? maybe there are reasonable usecases
  138. if (UnitySelectedRenderingAPI() == apiMetal && params.renderW > 0 && params.renderH > 0)
  139. _screenSize = CGSizeMake(fminf(screenSize.width, params.renderW), fminf(screenSize.height, params.renderH));
  140. else
  141. _screenSize = screenSize;
  142. bool systemSizeChanged = surface->systemW != _screenSize.width || surface->systemH != _screenSize.height;
  143. bool msaaChanged = surface->msaaSamples != params.msaaSampleCount;
  144. bool depthFmtChanged = surface->disableDepthAndStencil != params.disableDepthAndStencil;
  145. bool cvCacheChanged = surface->useCVTextureCache != params.useCVTextureCache;
  146. bool memorylessChanged = surface->memorylessDepth != params.metalMemorylessDepth;
  147. bool renderSizeChanged = false;
  148. if ((params.renderW > 0 && surface->targetW != params.renderW) // changed resolution
  149. || (params.renderH > 0 && surface->targetH != params.renderH) // changed resolution
  150. || (params.renderW <= 0 && surface->targetW != surface->systemW) // no longer need intermediate fb
  151. || (params.renderH <= 0 && surface->targetH != surface->systemH) // no longer need intermediate fb
  152. )
  153. {
  154. renderSizeChanged = true;
  155. }
  156. bool recreateSystemSurface = systemSizeChanged;
  157. bool recreateRenderingSurface = systemSizeChanged || renderSizeChanged || msaaChanged || cvCacheChanged;
  158. bool recreateDepthbuffer = systemSizeChanged || renderSizeChanged || msaaChanged || depthFmtChanged || memorylessChanged;
  159. surface->disableDepthAndStencil = params.disableDepthAndStencil;
  160. surface->systemW = (unsigned)_screenSize.width;
  161. surface->systemH = (unsigned)_screenSize.height;
  162. surface->targetW = params.renderW > 0 ? params.renderW : surface->systemW;
  163. surface->targetH = params.renderH > 0 ? params.renderH : surface->systemH;
  164. surface->msaaSamples = params.msaaSampleCount;
  165. surface->srgb = params.srgb;
  166. surface->wideColor = params.wideColor;
  167. surface->hdr = params.hdr;
  168. surface->useCVTextureCache = params.useCVTextureCache;
  169. surface->memorylessDepth = params.metalMemorylessDepth;
  170. const int api = UnitySelectedRenderingAPI();
  171. if (api == apiMetal)
  172. {
  173. UnityDisplaySurfaceMTL* mtlSurf = (UnityDisplaySurfaceMTL*)surface;
  174. recreateSystemSurface = recreateSystemSurface || mtlSurf->systemColorRB == 0;
  175. mtlSurf->framebufferOnly = params.metalFramebufferOnly;
  176. }
  177. if (recreateSystemSurface)
  178. CreateSystemRenderingSurface(surface);
  179. if (recreateRenderingSurface)
  180. CreateRenderingSurface(surface);
  181. if (recreateDepthbuffer)
  182. CreateSharedDepthbuffer(surface);
  183. if (recreateSystemSurface || recreateRenderingSurface || recreateDepthbuffer)
  184. CreateUnityRenderBuffers(surface);
  185. _surface = surface;
  186. #if !PLATFORM_VISIONOS
  187. UnityInvalidateDisplayDataCache((__bridge void*)_screen);
  188. #endif
  189. }
  190. - (void)destroySurface
  191. {
  192. if (_surface)
  193. {
  194. DestroySystemRenderingSurface(_surface);
  195. DestroyRenderingSurface(_surface);
  196. DestroySharedDepthbuffer(_surface);
  197. DestroyUnityRenderBuffers(_surface);
  198. const int api = UnitySelectedRenderingAPI();
  199. if (api == apiMetal)
  200. {
  201. self.surfaceMTL->device = nil;
  202. self.surfaceMTL->layer = nil;
  203. }
  204. }
  205. delete _surface;
  206. _surface = 0;
  207. }
  208. - (void)dealloc
  209. {
  210. NSAssert(_surface == 0, @"At this point surface should be already destroyed!");
  211. _view = nil;
  212. _window = nil;
  213. }
  214. - (void)present
  215. {
  216. PreparePresent(self.surface);
  217. Present(self.surface);
  218. if (_needRecreateSurface)
  219. {
  220. RenderingSurfaceParams params =
  221. {
  222. .msaaSampleCount = _surface->msaaSamples,
  223. .renderW = (int)_requestedRenderingSize.width,
  224. .renderH = (int)_requestedRenderingSize.height,
  225. .srgb = _surface->srgb,
  226. .wideColor = _surface->wideColor,
  227. .hdr = _surface->hdr,
  228. .metalFramebufferOnly = 0,
  229. .metalMemorylessDepth = 0,
  230. .disableDepthAndStencil = _surface->disableDepthAndStencil,
  231. .useCVTextureCache = self.surface->cvTextureCache != 0,
  232. };
  233. [self recreateSurface: params];
  234. _needRecreateSurface = NO;
  235. _requestedRenderingSize = CGSizeMake(_surface->targetW, _surface->targetH);
  236. }
  237. }
  238. - (void)requestRenderingResolution:(CGSize)res
  239. {
  240. _requestedRenderingSize = res;
  241. _needRecreateSurface = YES;
  242. }
  243. @end
  244. #if !PLATFORM_VISIONOS
  245. @implementation DisplayManager
  246. {
  247. NSMapTable* _displayConnection;
  248. DisplayConnection* _mainDisplay;
  249. }
  250. @synthesize mainDisplay = _mainDisplay;
  251. @synthesize displayCount;
  252. - (NSUInteger)displayCount { return _displayConnection.count; }
  253. - (void)registerScreen:(UIScreen*)screen
  254. {
  255. [_displayConnection setObject: [[DisplayConnection alloc] init: screen] forKey: screen];
  256. }
  257. - (id)init
  258. {
  259. if ((self = [super init]))
  260. {
  261. [[NSNotificationCenter defaultCenter] addObserver: self
  262. selector: @selector(screenDidConnect:)
  263. name: UIScreenDidConnectNotification
  264. object: nil
  265. ];
  266. [[NSNotificationCenter defaultCenter] addObserver: self
  267. selector: @selector(screenDidDisconnect:)
  268. name: UIScreenDidDisconnectNotification
  269. object: nil
  270. ];
  271. _displayConnection = [NSMapTable
  272. mapTableWithKeyOptions: NSPointerFunctionsStrongMemory | NSPointerFunctionsObjectPointerPersonality
  273. valueOptions: NSPointerFunctionsStrongMemory | NSPointerFunctionsObjectPointerPersonality
  274. ];
  275. for (UIScreen* screen in [UIScreen screens])
  276. [self registerScreen: screen];
  277. _mainDisplay = self[[UIScreen mainScreen]];
  278. }
  279. return self;
  280. }
  281. - (void)dealloc
  282. {
  283. [[NSNotificationCenter defaultCenter] removeObserver: self];
  284. }
  285. - (BOOL)displayAvailable:(UIScreen*)targetScreen;
  286. {
  287. return self[targetScreen] != nil;
  288. }
  289. - (DisplayConnection*)display:(UIScreen*)targetScreen
  290. {
  291. return self[targetScreen];
  292. }
  293. - (id)objectForKeyedSubscript:(id)key
  294. {
  295. NSAssert([key isKindOfClass: [UIScreen class]], @"DisplayManager allows only UIScreen as subscript");
  296. return [_displayConnection objectForKey: (UIScreen*)key];
  297. }
  298. - (void)updateDisplayListCacheInUnity
  299. {
  300. // [UIScreen screens] might be out of sync to what is indicated to the
  301. // application via UIScreenDidConnectNotification and UIScreenDidDisconnectNotification
  302. // notifications. For example, on disconnection [UIScreen screens] might still
  303. // have the screen that the display manager no longer knows about.
  304. const unsigned MAX_DISPLAYS_SUPPORTED = 8; // sync this to the value on Unity side
  305. void* screens[MAX_DISPLAYS_SUPPORTED];
  306. unsigned screenCount = 0;
  307. UIScreen* mainScreen = [UIScreen mainScreen];
  308. screens[screenCount++] = (__bridge void*)mainScreen;
  309. for (UIScreen* screen in _displayConnection)
  310. {
  311. if (screen == mainScreen)
  312. continue;
  313. screens[screenCount++] = (__bridge void*)screen;
  314. }
  315. UnityUpdateDisplayListCache(screens, screenCount);
  316. }
  317. - (void)enumerateDisplaysWithBlock:(void (^)(DisplayConnection* conn))block
  318. {
  319. for (UIScreen* screen in _displayConnection)
  320. {
  321. // if we want simple mirroring unity wont create rendering backing for display
  322. // in that case we dont want to touch Display
  323. DisplayConnection* conn = [_displayConnection objectForKey: screen];
  324. if (conn.surface != nil)
  325. block(conn);
  326. }
  327. }
  328. - (void)enumerateNonMainDisplaysWithBlock:(void (^)(DisplayConnection* conn))block
  329. {
  330. for (UIScreen* screen in _displayConnection)
  331. {
  332. DisplayConnection* conn = [_displayConnection objectForKey: screen];
  333. if (conn != _mainDisplay && conn.surface != nil)
  334. block(conn);
  335. }
  336. }
  337. - (void)startFrameRendering
  338. {
  339. [self enumerateDisplaysWithBlock:^(DisplayConnection* conn) {
  340. StartFrameRendering(conn.surface);
  341. }];
  342. }
  343. - (void)endFrameRendering
  344. {
  345. [self enumerateDisplaysWithBlock:^(DisplayConnection* conn) {
  346. EndFrameRendering(conn.surface);
  347. }];
  348. }
  349. - (void)present
  350. {
  351. [self enumerateDisplaysWithBlock:^(DisplayConnection* conn) {
  352. [conn present];
  353. }];
  354. }
  355. - (void)screenDidConnect:(NSNotification*)notification
  356. {
  357. [self registerScreen: (UIScreen*)[notification object]];
  358. [self updateDisplayListCacheInUnity];
  359. }
  360. - (void)screenDidDisconnect:(NSNotification*)notification
  361. {
  362. UIScreen* screen = (UIScreen*)[notification object];
  363. DisplayConnection* conn = (DisplayConnection*)self[screen];
  364. if (conn != nil && conn.surface != nil)
  365. UnityDisableRenderBuffers(conn.surface->unityColorBuffer, conn.surface->unityDepthBuffer);
  366. [conn destroySurface];
  367. conn = nil;
  368. [_displayConnection removeObjectForKey: screen];
  369. [self updateDisplayListCacheInUnity];
  370. }
  371. + (void)Initialize
  372. {
  373. NSAssert(_DisplayManager == nil, @"[DisplayManager Initialize] called after creating handler");
  374. if (!_DisplayManager)
  375. _DisplayManager = [[DisplayManager alloc] init];
  376. }
  377. + (DisplayManager*)Instance
  378. {
  379. if (!_DisplayManager)
  380. _DisplayManager = [[DisplayManager alloc] init];
  381. return _DisplayManager;
  382. }
  383. + (void)Destroy
  384. {
  385. _DisplayManager = nil;
  386. }
  387. @end
  388. #else
  389. // xros DisplayManager
  390. @implementation DisplayManager
  391. {
  392. DisplayConnection* _mainDisplay;
  393. }
  394. @synthesize mainDisplay = _mainDisplay;
  395. @synthesize displayCount;
  396. - (NSUInteger)displayCount { return 1; }
  397. - (id)init
  398. {
  399. if ((self = [super init]))
  400. {
  401. _mainDisplay = [[DisplayConnection alloc] init];
  402. // Unity needs a non-zero screen in order for renderloop to run
  403. const int screenCount = 1;
  404. void* screens[screenCount] = {(void*)0x1};
  405. UnityUpdateDisplayListCache(screens, screenCount);
  406. }
  407. return self;
  408. }
  409. - (void)dealloc
  410. {
  411. }
  412. - (void)startFrameRendering
  413. {
  414. StartFrameRendering(_mainDisplay.surface);
  415. }
  416. - (void)endFrameRendering
  417. {
  418. EndFrameRendering(_mainDisplay.surface);
  419. }
  420. - (void)present
  421. {
  422. [_mainDisplay present];
  423. }
  424. + (void)Initialize
  425. {
  426. NSAssert(_DisplayManager == nil, @"[DisplayManager Initialize] called after creating handler");
  427. if (!_DisplayManager)
  428. _DisplayManager = [[DisplayManager alloc] init];
  429. }
  430. + (DisplayManager*)Instance
  431. {
  432. if (!_DisplayManager)
  433. _DisplayManager = [[DisplayManager alloc] init];
  434. return _DisplayManager;
  435. }
  436. @end
  437. #endif
  438. //==============================================================================
  439. //
  440. // Unity Interface:
  441. static void EnsureDisplayIsInited(DisplayConnection* conn)
  442. {
  443. // main screen view will be created in AppController,
  444. // so we can assume that we need to init secondary display from script
  445. // meaning: gles + show right away
  446. if (conn.view == nil)
  447. [conn createView: YES];
  448. int api = UnitySelectedRenderingAPI();
  449. bool needRecreate = false;
  450. if (conn.surface == 0)
  451. needRecreate = true;
  452. else if (api == apiMetal)
  453. needRecreate = conn.surfaceMTL->layer == nil;
  454. if (needRecreate)
  455. {
  456. RenderingSurfaceParams params =
  457. {
  458. .msaaSampleCount = UnityGetDesiredMSAASampleCount(1),
  459. .renderW = -1, // native resolution at first (can be changed later)
  460. .renderH = -1, // native resolution at first (can be changed later)
  461. .srgb = UnityGetSRGBRequested(),
  462. .wideColor = 0, // i am not sure how to handle wide color here (and if it is even supported for airplay)
  463. .hdr = 0,
  464. .metalFramebufferOnly = UnityMetalFramebufferOnly(),
  465. .metalMemorylessDepth = UnityMetalMemorylessDepth(),
  466. .disableDepthAndStencil = UnityDisableDepthAndStencilBuffers(),
  467. .useCVTextureCache = 0,
  468. };
  469. [conn recreateSurface: params];
  470. {
  471. DisplayConnection* main = [DisplayManager Instance].mainDisplay;
  472. StartFrameRendering(main.surface);
  473. }
  474. }
  475. }
  476. #if !PLATFORM_TVOS
  477. extern "C" int UnityDisplayManager_DisplayCount()
  478. {
  479. return (int)[DisplayManager Instance].displayCount;
  480. }
  481. extern "C" bool UnityDisplayManager_DisplayAvailable(void* nativeDisplay)
  482. {
  483. #if !PLATFORM_VISIONOS
  484. if (nativeDisplay == NULL)
  485. return false;
  486. return [[DisplayManager Instance] displayAvailable: (__bridge UIScreen*)nativeDisplay];
  487. #else
  488. return false;
  489. #endif
  490. }
  491. extern "C" bool UnityDisplayManager_DisplayActive(void* nativeDisplay)
  492. {
  493. #if !PLATFORM_VISIONOS
  494. return UnityDisplayManager_DisplayAvailable(nativeDisplay);
  495. #else
  496. return true;
  497. #endif
  498. }
  499. extern "C" void UnityDisplayManager_DisplaySystemResolution(void* nativeDisplay, int* w, int* h)
  500. {
  501. #if !PLATFORM_VISIONOS
  502. if (nativeDisplay == NULL)
  503. return;
  504. DisplayConnection* conn = [DisplayManager Instance][(__bridge UIScreen*)nativeDisplay];
  505. EnsureDisplayIsInited(conn);
  506. // CODE ARCHEOLOGY: We were creating full-screen buffer for "system" RT, and (possibly) resized for "target" RT,
  507. // CODE ARCHEOLOGY: and if the resolution was changed we were blitting target to system to rescale the image.
  508. // CODE ARCHEOLOGY: Since then we have switched to using OS scaling mechanism, i.e. we are creating window
  509. // CODE ARCHEOLOGY: with rendering extents and let iOS do the upscale
  510. // CODE ARCHEOLOGY: We should revisit the rendering code to possibly get rid of the code needed for this setup
  511. // CODE ARCHEOLOGY: but for now we do the minimal change to unbreak native resolution query
  512. // note that we mimic size calculation that we use in other places, i.e. using screen bounds + content scale factor
  513. // we should also note that we tweak CAMetalLayer.drawableSize (well, that's the way to trigger native upscale)
  514. // so we have CAMetalLayer.drawableSize = rendering size
  515. // and CAMetalLayer.size = system (native) size
  516. const CGSize layerSize = conn.view.layer.bounds.size; const float scale = conn.view.contentScaleFactor;
  517. *w = (int)(layerSize.width * scale);
  518. *h = (int)(layerSize.height * scale);
  519. #endif
  520. }
  521. extern "C" void UnityDisplayManager_DisplayRenderingResolution(void* nativeDisplay, int* w, int* h)
  522. {
  523. if (nativeDisplay == NULL)
  524. return;
  525. #if !PLATFORM_VISIONOS
  526. DisplayConnection* conn = [DisplayManager Instance][(__bridge UIScreen*)nativeDisplay];
  527. #else
  528. DisplayConnection* conn = [DisplayManager Instance].mainDisplay;
  529. #endif
  530. EnsureDisplayIsInited(conn);
  531. *w = (int)conn.surface->targetW;
  532. *h = (int)conn.surface->targetH;
  533. }
  534. extern "C" void UnityDisplayManager_DisplayRenderingBuffers(void* nativeDisplay, void** colorBuffer, void** depthBuffer)
  535. {
  536. if (nativeDisplay == NULL)
  537. return;
  538. #if !PLATFORM_VISIONOS
  539. DisplayConnection* conn = [DisplayManager Instance][(__bridge UIScreen*)nativeDisplay];
  540. #else
  541. DisplayConnection* conn = [DisplayManager Instance].mainDisplay;
  542. #endif
  543. EnsureDisplayIsInited(conn);
  544. if (colorBuffer)
  545. *colorBuffer = conn.surface->unityColorBuffer;
  546. if (depthBuffer)
  547. *depthBuffer = conn.surface->unityDepthBuffer;
  548. }
  549. extern "C" void UnityDisplayManager_SetRenderingResolution(void* nativeDisplay, int w, int h)
  550. {
  551. #if !PLATFORM_VISIONOS
  552. if (nativeDisplay == NULL)
  553. return;
  554. UIScreen* screen = (__bridge UIScreen*)nativeDisplay;
  555. DisplayConnection* conn = [DisplayManager Instance][screen];
  556. EnsureDisplayIsInited(conn);
  557. if (screen == [UIScreen mainScreen])
  558. UnityRequestRenderingResolution(w, h);
  559. else
  560. [conn requestRenderingResolution: CGSizeMake(w, h)];
  561. #endif
  562. }
  563. extern "C" int UnityDisplayManager_PrimaryDisplayIndex()
  564. {
  565. return 0;
  566. }
  567. #endif
  568. extern "C" void UnityActivateScreenForRendering(void* nativeDisplay)
  569. {
  570. if (nativeDisplay == NULL)
  571. return;
  572. #if !PLATFORM_VISIONOS
  573. DisplayConnection* conn = [DisplayManager Instance][(__bridge UIScreen*)nativeDisplay];
  574. #else
  575. DisplayConnection* conn = [DisplayManager Instance].mainDisplay;
  576. #endif
  577. EnsureDisplayIsInited(conn);
  578. [conn shouldShowWindow: YES];
  579. }
  580. #if !PLATFORM_VISIONOS
  581. extern "C" float UnityScreenScaleFactor(UIScreen* screen)
  582. {
  583. // NOTE: All views handled by Unity have their contentScaleFactor initialized
  584. // to value returned by this function.
  585. // we should query nativeScale if available to get the true device resolution
  586. // this way we avoid unnecessarily large frame buffers and downscaling.
  587. // e.g. iPhone 6+ pretends to be a x3 device, while its physical screen is x2.6 something.
  588. // it is available on iOS 8.0+, tvOS 9.0+
  589. // for older ios versions we add this selector ourselves (AddNewAPIImplIfNeeded in UnityAppController.mm)
  590. // On AppleTV screen.nativeScale returns NaN when device is in sleep mode and starting from tvOS 10 (?) it returns 0.
  591. if (isnan(screen.nativeScale) || (screen.nativeScale == 0))
  592. return 1.0f;
  593. else
  594. {
  595. float scalingFactor = UnityCalculateScalingFactorFromTargetDPI(screen);
  596. if (scalingFactor > 0.0f)
  597. return scalingFactor;
  598. else
  599. return screen.nativeScale;
  600. }
  601. return screen.scale;
  602. }
  603. extern "C" int UnityMainScreenRefreshRate()
  604. {
  605. return (int)[UIScreen mainScreen].maximumFramesPerSecond;
  606. }
  607. extern "C" void UnityStartFrameRendering()
  608. {
  609. [[DisplayManager Instance] startFrameRendering];
  610. }
  611. extern "C" void UnityDestroyUnityRenderSurfaces()
  612. {
  613. [[DisplayManager Instance] enumerateDisplaysWithBlock:^(DisplayConnection* conn) {
  614. [conn destroySurface];
  615. }];
  616. }
  617. extern "C" void UnitySetBrightness(float brightness)
  618. {
  619. #if !PLATFORM_TVOS
  620. brightness = (brightness > 1.0 ? 1.0 : brightness) < 0 ? 0.0 : brightness;
  621. UIScreen* screen = [UIScreen mainScreen];
  622. screen.brightness = brightness;
  623. #endif
  624. }
  625. extern "C" float UnityGetBrightness()
  626. {
  627. #if !PLATFORM_TVOS
  628. UIScreen* screen = [UIScreen mainScreen];
  629. return screen.brightness;
  630. #else
  631. return 1.0f;
  632. #endif
  633. }
  634. extern "C" bool UnityIsFullscreen()
  635. {
  636. CGSize screenSize = [[[[DisplayManager Instance] mainDisplay] screen] bounds].size;
  637. CGSize viewSize = [[[[DisplayManager Instance] mainDisplay] view] bounds].size;
  638. return screenSize.width == viewSize.width && screenSize.height == viewSize.height;
  639. }
  640. #else
  641. extern "C" int UnityMainScreenRefreshRate()
  642. {
  643. return 90;
  644. }
  645. extern "C" void UnityStartFrameRendering()
  646. {
  647. [[DisplayManager Instance] startFrameRendering];
  648. }
  649. extern "C" void UnityDestroyUnityRenderSurfaces()
  650. {
  651. [[DisplayManager Instance].mainDisplay destroySurface];
  652. }
  653. extern "C" void UnitySetBrightness(float brightness)
  654. {
  655. }
  656. extern "C" float UnityGetBrightness()
  657. {
  658. return 1.0f;
  659. }
  660. extern "C" bool UnityIsFullscreen()
  661. {
  662. return false;
  663. }
  664. #endif