UnityView.mm 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  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. #if UNITY_CAN_USE_METAL
  24. if (UnitySelectedRenderingAPI() == apiMetal)
  25. ((CAMetalLayer*)self.layer).drawableSize = systemRenderSize;
  26. #endif
  27. }
  28. - (void)initImpl:(CGRect)frame scaleFactor:(CGFloat)scale
  29. {
  30. #if !PLATFORM_TVOS
  31. self.multipleTouchEnabled = YES;
  32. self.exclusiveTouch = YES;
  33. #endif
  34. self.contentScaleFactor = scale;
  35. self.isAccessibilityElement = TRUE;
  36. self.accessibilityTraits = UIAccessibilityTraitAllowsDirectInteraction;
  37. #if UNITY_TVOS
  38. _curOrientation = UNITY_TVOS_ORIENTATION;
  39. #endif
  40. [self onUpdateSurfaceSize: frame.size];
  41. #if UNITY_CAN_USE_METAL
  42. if (UnitySelectedRenderingAPI() == apiMetal)
  43. ((CAMetalLayer*)self.layer).framebufferOnly = NO;
  44. #endif
  45. }
  46. - (id)initWithFrame:(CGRect)frame scaleFactor:(CGFloat)scale;
  47. {
  48. if ((self = [super initWithFrame: frame]))
  49. [self initImpl: frame scaleFactor: scale];
  50. return self;
  51. }
  52. - (id)initWithFrame:(CGRect)frame
  53. {
  54. if ((self = [super initWithFrame: frame]))
  55. [self initImpl: frame scaleFactor: 1.0f];
  56. return self;
  57. }
  58. - (id)initFromMainScreen
  59. {
  60. CGRect frame = [UIScreen mainScreen].bounds;
  61. CGFloat scale = UnityScreenScaleFactor([UIScreen mainScreen]);
  62. if ((self = [super initWithFrame: frame]))
  63. [self initImpl: frame scaleFactor: scale];
  64. return self;
  65. }
  66. - (void)layoutSubviews
  67. {
  68. if (_surfaceSize.width != self.bounds.size.width || _surfaceSize.height != self.bounds.size.height)
  69. _shouldRecreateView = YES;
  70. [self onUpdateSurfaceSize: self.bounds.size];
  71. for (UIView* subView in self.subviews)
  72. {
  73. if ([subView respondsToSelector: @selector(onUnityUpdateViewLayout)])
  74. [subView performSelector: @selector(onUnityUpdateViewLayout)];
  75. }
  76. [super layoutSubviews];
  77. }
  78. - (void)safeAreaInsetsDidChange
  79. {
  80. ReportSafeAreaChangeForView(self);
  81. }
  82. - (void)recreateRenderingSurfaceIfNeeded
  83. {
  84. unsigned requestedW, requestedH; UnityGetRenderingResolution(&requestedW, &requestedH);
  85. int requestedMSAA = UnityGetDesiredMSAASampleCount(MSAA_DEFAULT_SAMPLE_COUNT);
  86. int requestedSRGB = UnityGetSRGBRequested();
  87. int requestedWideColor = UnityGetWideColorRequested();
  88. UnityDisplaySurfaceBase* surf = GetMainDisplaySurface();
  89. if (_shouldRecreateView == YES
  90. || surf->targetW != requestedW || surf->targetH != requestedH
  91. || surf->disableDepthAndStencil != UnityDisableDepthAndStencilBuffers()
  92. || (_supportsMSAA && surf->msaaSamples != requestedMSAA)
  93. || surf->srgb != requestedSRGB
  94. || surf->wideColor != requestedWideColor
  95. )
  96. {
  97. [self recreateRenderingSurface];
  98. }
  99. }
  100. - (void)recreateRenderingSurface
  101. {
  102. if (_renderingInited)
  103. {
  104. unsigned requestedW, requestedH;
  105. UnityGetRenderingResolution(&requestedW, &requestedH);
  106. RenderingSurfaceParams params =
  107. {
  108. UnityGetDesiredMSAASampleCount(MSAA_DEFAULT_SAMPLE_COUNT),
  109. (int)requestedW, (int)requestedH,
  110. UnityGetSRGBRequested(),
  111. UnityGetWideColorRequested(),
  112. UnityMetalFramebufferOnly(),
  113. UnityDisableDepthAndStencilBuffers(), 0
  114. };
  115. APP_CONTROLLER_RENDER_PLUGIN_METHOD_ARG(onBeforeMainDisplaySurfaceRecreate, &params);
  116. [GetMainDisplay() recreateSurface: params];
  117. // actually poke unity about updated back buffer and notify that extents were changed
  118. UnityReportBackbufferChange(GetMainDisplaySurface()->unityColorBuffer, GetMainDisplaySurface()->unityDepthBuffer);
  119. APP_CONTROLLER_RENDER_PLUGIN_METHOD(onAfterMainDisplaySurfaceRecreate);
  120. if (_unityAppReady)
  121. {
  122. // seems like ios sometimes got confused about abrupt swap chain destroy
  123. // draw 2 times to fill both buffers
  124. // present only once to make sure correct image goes to CA
  125. // if we are calling this from inside repaint, second draw and present will be done automatically
  126. _skipPresent = true;
  127. if (!UnityIsPaused())
  128. UnityRepaint();
  129. _skipPresent = false;
  130. }
  131. }
  132. _shouldRecreateView = NO;
  133. }
  134. @end
  135. @implementation UnityView (Deprecated)
  136. - (void)recreateGLESSurfaceIfNeeded { [self recreateRenderingSurfaceIfNeeded]; }
  137. - (void)recreateGLESSurface { [self recreateRenderingSurface]; }
  138. @end
  139. static Class UnityRenderingView_LayerClassGLES(id self_, SEL _cmd)
  140. {
  141. return [CAEAGLLayer class];
  142. }
  143. static Class UnityRenderingView_LayerClassMTL(id self_, SEL _cmd)
  144. {
  145. return [[NSBundle bundleWithPath: @"/System/Library/Frameworks/QuartzCore.framework"] classNamed: @"CAMetalLayer"];
  146. }
  147. @implementation UnityRenderingView
  148. + (Class)layerClass
  149. {
  150. return nil;
  151. }
  152. + (void)InitializeForAPI:(UnityRenderingAPI)api
  153. {
  154. IMP layerClassImpl = 0;
  155. if (api == apiOpenGLES2 || api == apiOpenGLES3)
  156. layerClassImpl = (IMP)UnityRenderingView_LayerClassGLES;
  157. else if (api == apiMetal)
  158. layerClassImpl = (IMP)UnityRenderingView_LayerClassMTL;
  159. class_replaceMethod(object_getClass([UnityRenderingView class]), @selector(layerClass), layerClassImpl, UIView_LayerClass_Enc);
  160. }
  161. @end
  162. void ReportSafeAreaChangeForView(UIView* view)
  163. {
  164. CGRect safeArea = ComputeSafeArea(view);
  165. UnityReportSafeAreaChange(safeArea.origin.x, safeArea.origin.y,
  166. safeArea.size.width, safeArea.size.height);
  167. }
  168. CGRect ComputeSafeArea(UIView* view)
  169. {
  170. CGSize screenSize = view.bounds.size;
  171. CGRect screenRect = CGRectMake(0, 0, screenSize.width, screenSize.height);
  172. UIEdgeInsets insets = UIEdgeInsetsMake(0, 0, 0, 0);
  173. #if UNITY_HAS_IOSSDK_11_0 || UNITY_HAS_TVOSSDK_11_0
  174. if (@available(iOS 11.0, tvOS 11.0, *))
  175. insets = [view safeAreaInsets];
  176. #endif
  177. screenRect.origin.x += insets.left;
  178. screenRect.origin.y += insets.bottom; // Unity uses bottom left as the origin
  179. screenRect.size.width -= insets.left + insets.right;
  180. screenRect.size.height -= insets.top + insets.bottom;
  181. float scale = view.contentScaleFactor;
  182. // Truncate safe area size because in some cases (for example when Display zoom is turned on)
  183. // it might become larger than Screen.widht/height which are returned as ints.
  184. screenRect.origin.x = (unsigned)(screenRect.origin.x * scale);
  185. screenRect.origin.y = (unsigned)(screenRect.origin.y * scale);
  186. screenRect.size.width = (unsigned)(screenRect.size.width * scale);
  187. screenRect.size.height = (unsigned)(screenRect.size.height * scale);
  188. return screenRect;
  189. }