UnityView.mm 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251
  1. #include "UnityView.h"
  2. #include "UnityAppController.h"
  3. #include "UnityAppController+Rendering.h"
  4. #include "OrientationSupport.h"
  5. #include "Unity/DisplayManager.h"
  6. #include "Unity/UnityMetalSupport.h"
  7. #include "Unity/ObjCRuntime.h"
  8. extern bool _renderingInited;
  9. extern bool _unityAppReady;
  10. extern bool _skipPresent;
  11. extern bool _supportsMSAA;
  12. @implementation UnityView
  13. {
  14. CGSize _surfaceSize;
  15. }
  16. @synthesize contentOrientation = _curOrientation;
  17. - (void)onUpdateSurfaceSize:(CGSize)size
  18. {
  19. _surfaceSize = size;
  20. CGSize systemRenderSize = CGSizeMake(size.width * self.contentScaleFactor, size.height * self.contentScaleFactor);
  21. _curOrientation = (ScreenOrientation)UnityReportResizeView(systemRenderSize.width, systemRenderSize.height, _curOrientation);
  22. ReportSafeAreaChangeForView(self);
  23. }
  24. - (void)initImpl:(CGRect)frame scaleFactor:(CGFloat)scale
  25. {
  26. #if !PLATFORM_TVOS
  27. self.multipleTouchEnabled = YES;
  28. self.exclusiveTouch = YES;
  29. #endif
  30. self.contentScaleFactor = scale;
  31. self.isAccessibilityElement = TRUE;
  32. self.accessibilityTraits = UIAccessibilityTraitAllowsDirectInteraction;
  33. #if UNITY_TVOS
  34. _curOrientation = UNITY_TVOS_ORIENTATION;
  35. #endif
  36. [self onUpdateSurfaceSize: frame.size];
  37. }
  38. - (id)initWithFrame:(CGRect)frame scaleFactor:(CGFloat)scale;
  39. {
  40. if ((self = [super initWithFrame: frame]))
  41. [self initImpl: frame scaleFactor: scale];
  42. return self;
  43. }
  44. - (id)initWithFrame:(CGRect)frame
  45. {
  46. if ((self = [super initWithFrame: frame]))
  47. [self initImpl: frame scaleFactor: 1.0f];
  48. return self;
  49. }
  50. - (id)initFromMainScreen
  51. {
  52. CGRect frame = [UIScreen mainScreen].bounds;
  53. CGFloat scale = UnityScreenScaleFactor([UIScreen mainScreen]);
  54. if ((self = [super initWithFrame: frame]))
  55. [self initImpl: frame scaleFactor: scale];
  56. return self;
  57. }
  58. - (void)layoutSubviews
  59. {
  60. if (_surfaceSize.width != self.bounds.size.width || _surfaceSize.height != self.bounds.size.height)
  61. _shouldRecreateView = YES;
  62. [self onUpdateSurfaceSize: self.bounds.size];
  63. for (UIView* subView in self.subviews)
  64. {
  65. if ([subView respondsToSelector: @selector(onUnityUpdateViewLayout)])
  66. [subView performSelector: @selector(onUnityUpdateViewLayout)];
  67. }
  68. [super layoutSubviews];
  69. }
  70. - (void)safeAreaInsetsDidChange
  71. {
  72. ReportSafeAreaChangeForView(self);
  73. }
  74. - (void)recreateRenderingSurfaceIfNeeded
  75. {
  76. unsigned requestedW, requestedH; UnityGetRenderingResolution(&requestedW, &requestedH);
  77. int requestedMSAA = UnityGetDesiredMSAASampleCount(MSAA_DEFAULT_SAMPLE_COUNT);
  78. int requestedSRGB = UnityGetSRGBRequested();
  79. int requestedWideColor = UnityGetWideColorRequested();
  80. int requestedMemorylessDepth = UnityMetalMemorylessDepth();
  81. UnityDisplaySurfaceBase* surf = GetMainDisplaySurface();
  82. if (_shouldRecreateView == YES
  83. || surf->targetW != requestedW || surf->targetH != requestedH
  84. || surf->disableDepthAndStencil != UnityDisableDepthAndStencilBuffers()
  85. || (_supportsMSAA && surf->msaaSamples != requestedMSAA)
  86. || surf->srgb != requestedSRGB
  87. || surf->wideColor != requestedWideColor
  88. || surf->memorylessDepth != requestedMemorylessDepth
  89. )
  90. {
  91. [self recreateRenderingSurface];
  92. }
  93. }
  94. - (void)recreateRenderingSurface
  95. {
  96. if (_renderingInited)
  97. {
  98. unsigned requestedW, requestedH;
  99. UnityGetRenderingResolution(&requestedW, &requestedH);
  100. RenderingSurfaceParams params =
  101. {
  102. .msaaSampleCount = UnityGetDesiredMSAASampleCount(MSAA_DEFAULT_SAMPLE_COUNT),
  103. .renderW = (int)requestedW,
  104. .renderH = (int)requestedH,
  105. .srgb = UnityGetSRGBRequested(),
  106. .wideColor = UnityGetWideColorRequested(),
  107. .metalFramebufferOnly = UnityMetalFramebufferOnly(),
  108. .metalMemorylessDepth = UnityMetalMemorylessDepth(),
  109. .disableDepthAndStencil = UnityDisableDepthAndStencilBuffers(),
  110. .useCVTextureCache = 0,
  111. };
  112. APP_CONTROLLER_RENDER_PLUGIN_METHOD_ARG(onBeforeMainDisplaySurfaceRecreate, &params);
  113. [GetMainDisplay() recreateSurface: params];
  114. // actually poke unity about updated back buffer and notify that extents were changed
  115. UnityReportBackbufferChange(GetMainDisplaySurface()->unityColorBuffer, GetMainDisplaySurface()->unityDepthBuffer);
  116. APP_CONTROLLER_RENDER_PLUGIN_METHOD(onAfterMainDisplaySurfaceRecreate);
  117. if (_unityAppReady)
  118. {
  119. // seems like ios sometimes got confused about abrupt swap chain destroy
  120. // draw 2 times to fill both buffers
  121. // present only once to make sure correct image goes to CA
  122. // if we are calling this from inside repaint, second draw and present will be done automatically
  123. _skipPresent = true;
  124. if (!UnityIsPaused())
  125. {
  126. UnityRepaint();
  127. // we are not inside repaint so we need to draw second time ourselves
  128. if (_viewIsRotating)
  129. UnityRepaint();
  130. }
  131. _skipPresent = false;
  132. }
  133. }
  134. _shouldRecreateView = NO;
  135. }
  136. @end
  137. @implementation UnityView (Deprecated)
  138. - (void)recreateGLESSurfaceIfNeeded { [self recreateRenderingSurfaceIfNeeded]; }
  139. - (void)recreateGLESSurface { [self recreateRenderingSurface]; }
  140. @end
  141. static Class UnityRenderingView_LayerClassGLES(id self_, SEL _cmd)
  142. {
  143. return [CAEAGLLayer class];
  144. }
  145. static Class UnityRenderingView_LayerClassMTL(id self_, SEL _cmd)
  146. {
  147. return [[NSBundle bundleWithPath: @"/System/Library/Frameworks/QuartzCore.framework"] classNamed: @"CAMetalLayer"];
  148. }
  149. @implementation UnityRenderingView
  150. + (Class)layerClass
  151. {
  152. return nil;
  153. }
  154. + (void)InitializeForAPI:(UnityRenderingAPI)api
  155. {
  156. IMP layerClassImpl = 0;
  157. if (api == apiOpenGLES2 || api == apiOpenGLES3)
  158. layerClassImpl = (IMP)UnityRenderingView_LayerClassGLES;
  159. else if (api == apiMetal)
  160. layerClassImpl = (IMP)UnityRenderingView_LayerClassMTL;
  161. class_replaceMethod(object_getClass([UnityRenderingView class]), @selector(layerClass), layerClassImpl, UIView_LayerClass_Enc);
  162. }
  163. @end
  164. void ReportSafeAreaChangeForView(UIView* view)
  165. {
  166. CGRect safeArea = ComputeSafeArea(view);
  167. UnityReportSafeAreaChange(safeArea.origin.x, safeArea.origin.y,
  168. safeArea.size.width, safeArea.size.height);
  169. switch (UnityDeviceGeneration())
  170. {
  171. case deviceiPhoneXR:
  172. {
  173. const float x = 184, y = 1726, w = 460, h = 66;
  174. UnityReportDisplayCutouts(&x, &y, &w, &h, 1);
  175. break;
  176. }
  177. case deviceiPhoneX:
  178. case deviceiPhoneXS:
  179. {
  180. const float x = 250, y = 2346, w = 625, h = 90;
  181. UnityReportDisplayCutouts(&x, &y, &w, &h, 1);
  182. break;
  183. }
  184. case deviceiPhoneXSMax:
  185. {
  186. const float x = 308, y = 2598, w = 626, h = 90;
  187. UnityReportDisplayCutouts(&x, &y, &w, &h, 1);
  188. break;
  189. }
  190. default:
  191. UnityReportDisplayCutouts(nullptr, nullptr, nullptr, nullptr, 0);
  192. }
  193. }
  194. CGRect ComputeSafeArea(UIView* view)
  195. {
  196. CGSize screenSize = view.bounds.size;
  197. CGRect screenRect = CGRectMake(0, 0, screenSize.width, screenSize.height);
  198. UIEdgeInsets insets = UIEdgeInsetsMake(0, 0, 0, 0);
  199. if (@available(iOS 11.0, tvOS 11.0, *))
  200. insets = [view safeAreaInsets];
  201. screenRect.origin.x += insets.left;
  202. screenRect.origin.y += insets.bottom; // Unity uses bottom left as the origin
  203. screenRect.size.width -= insets.left + insets.right;
  204. screenRect.size.height -= insets.top + insets.bottom;
  205. float scale = view.contentScaleFactor;
  206. // Truncate safe area size because in some cases (for example when Display zoom is turned on)
  207. // it might become larger than Screen.width/height which are returned as ints.
  208. screenRect.origin.x = (unsigned)(screenRect.origin.x * scale);
  209. screenRect.origin.y = (unsigned)(screenRect.origin.y * scale);
  210. screenRect.size.width = (unsigned)(screenRect.size.width * scale);
  211. screenRect.size.height = (unsigned)(screenRect.size.height * scale);
  212. return screenRect;
  213. }