No Description
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

UnityAppController+Rendering.mm 6.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  1. #include "UnityAppController+Rendering.h"
  2. #include "UnityAppController+ViewHandling.h"
  3. #include "Unity/InternalProfiler.h"
  4. #include "Unity/DisplayManager.h"
  5. #include "UI/UnityView.h"
  6. #include <dlfcn.h>
  7. #import <Metal/Metal.h>
  8. extern bool _skipPresent;
  9. extern bool _didResignActive;
  10. static int _renderingAPI = 0;
  11. static void SelectRenderingAPIImpl();
  12. @implementation UnityAppController (Rendering)
  13. - (void)createDisplayLink
  14. {
  15. _displayLink = [CADisplayLink displayLinkWithTarget: self selector: @selector(repaintDisplayLink)];
  16. [self callbackFramerateChange: -1];
  17. [_displayLink addToRunLoop: [NSRunLoop currentRunLoop] forMode: NSRunLoopCommonModes];
  18. }
  19. - (void)destroyDisplayLink
  20. {
  21. [_displayLink invalidate];
  22. _displayLink = nil;
  23. }
  24. - (void)repaintDisplayLink
  25. {
  26. if (!_didResignActive)
  27. {
  28. UnityDisplayLinkCallback(_displayLink.timestamp);
  29. [self repaint];
  30. }
  31. }
  32. - (void)repaint
  33. {
  34. if (_unityView.skipRendering)
  35. return;
  36. #if UNITY_SUPPORT_ROTATION
  37. [self checkOrientationRequest];
  38. #endif
  39. [_unityView recreateRenderingSurfaceIfNeeded];
  40. [_unityView processKeyboard];
  41. UnityDeliverUIEvents();
  42. if (!UnityIsPaused())
  43. UnityRepaint();
  44. }
  45. - (void)callbackGfxInited
  46. {
  47. assert(self.engineLoadState < kUnityEngineLoadStateRenderingInitialized && "Graphics should not have been initialized at this point");
  48. InitRendering();
  49. [self advanceEngineLoadState: kUnityEngineLoadStateRenderingInitialized];
  50. [self shouldAttachRenderDelegate];
  51. [_unityView recreateRenderingSurface];
  52. [_renderDelegate mainDisplayInited: _mainDisplay.surface];
  53. _mainDisplay.surface->allowScreenshot = 1;
  54. }
  55. - (void)callbackPresent:(const UnityFrameStats*)frameStats
  56. {
  57. if (_skipPresent)
  58. return;
  59. // metal needs special processing, because in case of airplay we need extra command buffers to present non-main screen drawables
  60. if (UnitySelectedRenderingAPI() == apiMetal)
  61. {
  62. [[DisplayManager Instance].mainDisplay present];
  63. #if !PLATFORM_VISIONOS
  64. [[DisplayManager Instance] enumerateNonMainDisplaysWithBlock:^(DisplayConnection* conn) {
  65. PreparePresentNonMainScreenMTL((UnityDisplaySurfaceMTL*)conn.surface);
  66. }];
  67. #endif
  68. }
  69. else
  70. {
  71. [[DisplayManager Instance] present];
  72. }
  73. Profiler_FramePresent(frameStats);
  74. }
  75. - (void)callbackFramerateChange:(int)targetFPS
  76. {
  77. if (targetFPS <= 0)
  78. targetFPS = UnityGetTargetFPS();
  79. // on tvos it is possible to start application without a screen attached
  80. // alas, mainScreen is set in this case, but the values provided are bogus
  81. // and in the case of maxFPS = 0 we will end up in endless recursion
  82. #if !PLATFORM_VISIONOS
  83. const int maxFPS = (int)[UIScreen mainScreen].maximumFramesPerSecond;
  84. #else
  85. // no UIScreen on VisionOS
  86. const int maxFPS = 90;
  87. #endif
  88. if (maxFPS > 0 && targetFPS > maxFPS)
  89. {
  90. targetFPS = maxFPS;
  91. // note that this changes FPS, resulting in UnityFramerateChangeCallback call, calling this method recursively recursively
  92. UnitySetTargetFPS(targetFPS);
  93. return;
  94. }
  95. if (@available(iOS 15.0, tvOS 15.0, *))
  96. _displayLink.preferredFrameRateRange = CAFrameRateRangeMake(targetFPS, targetFPS, targetFPS);
  97. else
  98. _displayLink.preferredFramesPerSecond = targetFPS;
  99. }
  100. - (void)selectRenderingAPI
  101. {
  102. NSAssert(_renderingAPI == 0, @"[UnityAppController selectRenderingApi] called twice");
  103. SelectRenderingAPIImpl();
  104. }
  105. - (UnityRenderingAPI)renderingAPI
  106. {
  107. NSAssert(_renderingAPI != 0, @"[UnityAppController renderingAPI] called before [UnityAppController selectRenderingApi]");
  108. return (UnityRenderingAPI)_renderingAPI;
  109. }
  110. @end
  111. extern "C" void UnityGfxInitedCallback()
  112. {
  113. [GetAppController() callbackGfxInited];
  114. }
  115. extern "C" void UnityPresentContextCallback(struct UnityFrameStats const* unityFrameStats)
  116. {
  117. [GetAppController() callbackPresent: unityFrameStats];
  118. }
  119. extern "C" void UnityFramerateChangeCallback(int targetFPS)
  120. {
  121. [GetAppController() callbackFramerateChange: targetFPS];
  122. }
  123. static NSBundle* _MetalBundle = nil;
  124. static id<MTLDevice> _MetalDevice = nil;
  125. static id<MTLCommandQueue> _MetalCommandQueue = nil;
  126. static void SelectRenderingAPIImpl()
  127. {
  128. assert(_renderingAPI == 0 && "Rendering API selection was done twice");
  129. _renderingAPI = UnityGetRenderingAPI();
  130. if (_renderingAPI == apiMetal)
  131. {
  132. _MetalBundle = [NSBundle bundleWithPath: @"/System/Library/Frameworks/Metal.framework"];
  133. _MetalDevice = MTLCreateSystemDefaultDevice();
  134. _MetalCommandQueue = [_MetalDevice newCommandQueueWithMaxCommandBufferCount: UnityCommandQueueMaxCommandBufferCountMTL()];
  135. assert(_MetalDevice != nil && _MetalCommandQueue != nil && "Could not initialize Metal.");
  136. }
  137. }
  138. extern "C" NSBundle* UnityGetMetalBundle() { return _MetalBundle; }
  139. extern "C" MTLDeviceRef UnityGetMetalDevice() { return _MetalDevice; }
  140. extern "C" MTLCommandQueueRef UnityGetMetalCommandQueue() { return _MetalCommandQueue; }
  141. extern "C" int UnitySelectedRenderingAPI() { return _renderingAPI; }
  142. extern "C" void UnitySelectRenderingAPI() { SelectRenderingAPIImpl(); }
  143. // deprecated and no longer used by unity itself (will soon be removed)
  144. extern "C" MTLCommandQueueRef UnityGetMetalDrawableCommandQueue() { return UnityGetMetalCommandQueue(); }
  145. extern "C" UnityRenderBufferHandle UnityBackbufferColor() { return GetMainDisplaySurface()->unityColorBuffer; }
  146. extern "C" UnityRenderBufferHandle UnityBackbufferDepth() { return GetMainDisplaySurface()->unityDepthBuffer; }
  147. extern "C" void DisplayManagerEndFrameRendering() { [[DisplayManager Instance] endFrameRendering]; }
  148. extern "C" void UnityPrepareScreenshot() { UnitySetRenderTarget(GetMainDisplaySurface()->unityColorBuffer, GetMainDisplaySurface()->unityDepthBuffer); }
  149. extern "C" void UnityRepaint()
  150. {
  151. @autoreleasepool
  152. {
  153. Profiler_FrameStart();
  154. if (UnityIsBatchmode())
  155. UnityBatchPlayerLoop();
  156. else
  157. UnityPlayerLoop();
  158. Profiler_FrameEnd();
  159. }
  160. }