UnityAppController+Rendering.mm 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274
  1. #include "UnityAppController+Rendering.h"
  2. #include "UnityAppController+ViewHandling.h"
  3. #include "Unity/InternalProfiler.h"
  4. #include "Unity/UnityMetalSupport.h"
  5. #include "Unity/DisplayManager.h"
  6. #include "UI/UnityView.h"
  7. #include <dlfcn.h>
  8. // _glesContextCreated was renamed to _renderingInited
  9. extern bool _renderingInited;
  10. extern bool _unityAppReady;
  11. extern bool _skipPresent;
  12. extern bool _didResignActive;
  13. static int _renderingAPI = 0;
  14. static int SelectRenderingAPIImpl();
  15. static bool _enableRunLoopAcceptInput = false;
  16. cp_layer_renderer_t _LayerRenderer = nil;
  17. static cp_layer_renderer_state _LayerRendererState = cp_layer_renderer_state_running;
  18. static bool _ShouldDispatchRepaint = false;
  19. @implementation UnityAppController (Rendering)
  20. - (void)createDisplayLink
  21. {
  22. _displayLink = [CADisplayLink displayLinkWithTarget: self selector: @selector(repaintDisplayLink)];
  23. [self callbackFramerateChange: -1];
  24. [_displayLink addToRunLoop: [NSRunLoop currentRunLoop] forMode: NSRunLoopCommonModes];
  25. }
  26. - (void)destroyDisplayLink
  27. {
  28. [_displayLink invalidate];
  29. _displayLink = nil;
  30. }
  31. - (void)repaintDisplayLink
  32. {
  33. if (_LayerRenderer == nil)
  34. {
  35. if (!_didResignActive) {
  36. UnityDisplayLinkCallback(_displayLink.timestamp);
  37. [self repaint];
  38. }
  39. }
  40. else
  41. {
  42. if (_LayerRendererState == cp_layer_renderer_state_running)
  43. {
  44. if (UnityIsPaused())
  45. {
  46. UnityWillResume();
  47. UnityPause(0);
  48. }
  49. UnityDisplayLinkCallback(0.0);
  50. [self repaint];
  51. }
  52. else
  53. {
  54. if (!UnityIsPaused())
  55. UnityPause(1);
  56. _LayerRendererState = cp_layer_renderer_get_state(_LayerRenderer);
  57. }
  58. if (_ShouldDispatchRepaint)
  59. dispatch_async(dispatch_get_main_queue(), ^{ [self repaintDisplayLink]; });
  60. }
  61. }
  62. - (void)repaint
  63. {
  64. #if UNITY_SUPPORT_ROTATION
  65. [self checkOrientationRequest];
  66. #endif
  67. [_unityView recreateRenderingSurfaceIfNeeded];
  68. [_unityView processKeyboard];
  69. UnityDeliverUIEvents();
  70. if (!UnityIsPaused())
  71. UnityRepaint();
  72. }
  73. - (void)callbackGfxInited
  74. {
  75. InitRendering();
  76. _renderingInited = true;
  77. [self shouldAttachRenderDelegate];
  78. [_unityView recreateRenderingSurface];
  79. [_renderDelegate mainDisplayInited: _mainDisplay.surface];
  80. _mainDisplay.surface->allowScreenshot = 1;
  81. }
  82. - (void)callbackPresent:(const UnityFrameStats*)frameStats
  83. {
  84. if (_skipPresent)
  85. return;
  86. // metal needs special processing, because in case of airplay we need extra command buffers to present non-main screen drawables
  87. if (UnitySelectedRenderingAPI() == apiMetal)
  88. {
  89. [[DisplayManager Instance].mainDisplay present];
  90. #if !PLATFORM_VISIONOS
  91. [[DisplayManager Instance] enumerateNonMainDisplaysWithBlock:^(DisplayConnection* conn) {
  92. PreparePresentNonMainScreenMTL((UnityDisplaySurfaceMTL*)conn.surface);
  93. }];
  94. #endif
  95. }
  96. else
  97. {
  98. [[DisplayManager Instance] present];
  99. }
  100. Profiler_FramePresent(frameStats);
  101. }
  102. - (void)callbackFramerateChange:(int)targetFPS
  103. {
  104. #if !PLATFORM_VISIONOS
  105. int maxFPS = (int)[UIScreen mainScreen].maximumFramesPerSecond;
  106. #else
  107. // hardcode for visionOS?
  108. int maxFPS = 90;
  109. #endif
  110. if (targetFPS <= 0)
  111. targetFPS = UnityGetTargetFPS();
  112. if (targetFPS > maxFPS)
  113. {
  114. targetFPS = maxFPS;
  115. UnitySetTargetFPS(targetFPS);
  116. return;
  117. }
  118. _enableRunLoopAcceptInput = (targetFPS == maxFPS && UnityDeviceCPUCount() > 1);
  119. if (@available(iOS 15.0, tvOS 15.0, *))
  120. _displayLink.preferredFrameRateRange = CAFrameRateRangeMake(targetFPS, targetFPS, targetFPS);
  121. else
  122. _displayLink.preferredFramesPerSecond = targetFPS;
  123. }
  124. - (void)selectRenderingAPI
  125. {
  126. NSAssert(_renderingAPI == 0, @"[UnityAppController selectRenderingApi] called twice");
  127. _renderingAPI = SelectRenderingAPIImpl();
  128. }
  129. - (UnityRenderingAPI)renderingAPI
  130. {
  131. NSAssert(_renderingAPI != 0, @"[UnityAppController renderingAPI] called before [UnityAppController selectRenderingApi]");
  132. return (UnityRenderingAPI)_renderingAPI;
  133. }
  134. @end
  135. @interface UnityVisionOSCompositorBridge : NSObject
  136. + (void)setLayerRenderer:(cp_layer_renderer_t)layerRenderer;
  137. + (void)setLayerRendererState:(NSNumber*)layerRendererState;
  138. @end
  139. @implementation UnityVisionOSCompositorBridge
  140. + (void)setLayerRenderer:(cp_layer_renderer_t)layerRenderer
  141. {
  142. _LayerRenderer = layerRenderer;
  143. if (layerRenderer == nil)
  144. {
  145. _ShouldDispatchRepaint = false;
  146. [_UnityAppController createDisplayLink];
  147. }
  148. else
  149. {
  150. _ShouldDispatchRepaint = true;
  151. [_UnityAppController destroyDisplayLink];
  152. // Manually call repaintDisplayLink to kick off dispatched repaint loop
  153. [_UnityAppController repaintDisplayLink];
  154. }
  155. }
  156. + (void)setLayerRendererState:(NSNumber*) layerRendererStateObject
  157. {
  158. _LayerRendererState = (cp_layer_renderer_state)layerRendererStateObject.intValue;
  159. }
  160. @end
  161. extern "C" void UnityGfxInitedCallback()
  162. {
  163. [GetAppController() callbackGfxInited];
  164. }
  165. extern "C" void UnityPresentContextCallback(struct UnityFrameStats const* unityFrameStats)
  166. {
  167. [GetAppController() callbackPresent: unityFrameStats];
  168. }
  169. extern "C" void UnityFramerateChangeCallback(int targetFPS)
  170. {
  171. [GetAppController() callbackFramerateChange: targetFPS];
  172. }
  173. static NSBundle* _MetalBundle = nil;
  174. static id<MTLDevice> _MetalDevice = nil;
  175. static bool IsMetalSupported(int /*api*/)
  176. {
  177. _MetalBundle = [NSBundle bundleWithPath: @"/System/Library/Frameworks/Metal.framework"];
  178. if (_MetalBundle)
  179. {
  180. [_MetalBundle load];
  181. _MetalDevice = ((MTLCreateSystemDefaultDeviceFunc)::dlsym(dlopen(0, RTLD_LOCAL | RTLD_LAZY), "MTLCreateSystemDefaultDevice"))();
  182. if (_MetalDevice)
  183. return true;
  184. }
  185. [_MetalBundle unload];
  186. return false;
  187. }
  188. static int SelectRenderingAPIImpl()
  189. {
  190. const int api = UnityGetRenderingAPI();
  191. if (api == apiMetal && IsMetalSupported(0))
  192. return api;
  193. #if TARGET_IPHONE_SIMULATOR || TARGET_TVOS_SIMULATOR
  194. printf_console("On Simulator, Metal is supported only from iOS 13, and it requires at least macOS 10.15 and Xcode 11. Setting no graphics device.\n");
  195. #endif
  196. return apiNoGraphics;
  197. }
  198. extern "C" NSBundle* UnityGetMetalBundle()
  199. {
  200. return _MetalBundle;
  201. }
  202. extern "C" MTLDeviceRef UnityGetMetalDevice() { return _MetalDevice; }
  203. extern "C" MTLCommandQueueRef UnityGetMetalCommandQueue() { return ((UnityDisplaySurfaceMTL*)GetMainDisplaySurface())->commandQueue; }
  204. extern "C" int UnitySelectedRenderingAPI() { return _renderingAPI; }
  205. // deprecated and no longer used by unity itself (will soon be removed)
  206. extern "C" MTLCommandQueueRef UnityGetMetalDrawableCommandQueue() { return UnityGetMetalCommandQueue(); }
  207. extern "C" UnityRenderBufferHandle UnityBackbufferColor() { return GetMainDisplaySurface()->unityColorBuffer; }
  208. extern "C" UnityRenderBufferHandle UnityBackbufferDepth() { return GetMainDisplaySurface()->unityDepthBuffer; }
  209. extern "C" void DisplayManagerEndFrameRendering() { [[DisplayManager Instance] endFrameRendering]; }
  210. extern "C" void UnityPrepareScreenshot() { UnitySetRenderTarget(GetMainDisplaySurface()->unityColorBuffer, GetMainDisplaySurface()->unityDepthBuffer); }
  211. extern "C" void UnityRepaint()
  212. {
  213. @autoreleasepool
  214. {
  215. Profiler_FrameStart();
  216. if (UnityIsBatchmode())
  217. UnityBatchPlayerLoop();
  218. else
  219. UnityPlayerLoop();
  220. Profiler_FrameEnd();
  221. }
  222. }