Bug 18003 - [OpenTK] iPhoneOSGameView causes errors on iOS 7 when the parent view controller is transitioned off screen by a UINavigationController
Summary: [OpenTK] iPhoneOSGameView causes errors on iOS 7 when the parent view control...
Status: CONFIRMED
Alias: None
Product: iOS
Classification: Xamarin
Component: Xamarin.iOS.dll (show other bugs)
Version: 7.0.7
Hardware: PC Mac OS
: Normal normal
Target Milestone: Untriaged
Assignee: Radek Doulik
URL:
Depends on:
Blocks:
 
Reported: 2014-02-25 16:15 UTC by Brendan Zagaeski (Xamarin Support)
Modified: 2014-05-08 07:04 UTC (History)
4 users (show)

See Also:
Tags:
Is this bug a regression?: ---
Last known good build:


Attachments
Test case (11.04 KB, application/zip)
2014-02-25 16:15 UTC, Brendan Zagaeski (Xamarin Support)
Details

Description Brendan Zagaeski (Xamarin Support) 2014-02-25 16:15:32 UTC
Created attachment 6149 [details]
Test case

`iPhoneOSGameView.WillMoveToWindow()` leads to "Operation requires a GraphicsContext" and "Can't change RenderingApi after GraphicsContext is constructed" errors on iOS 7 when the parent view controller is transitioned off screen with animation by a UINavigationController.


## Steps to reproduce
1. Run the attached project on iOS 6 or iOS 7 (either simulator or device is fine). This is a slightly modified version of the "OpenGL Application" template that places the `OpenGLViewController` within a `UINavigationController`.

2. Wait 5 seconds so that the bouncing square gets transitioned off screen by the navigation controller.

3. Push the "Back" navigation button.


## Results

### On iOS 6 simulator: SUCCEEDS

Console output:
> Called OpenGLViewController.ViewWillAppear()
> Called WillMoveToWindow() with window: <UIWindow: 0xd083a00; frame = (0 0; 320 480); layer = <UIWindowLayer: 0xd083650>>
> Called OpenGLViewController.ViewWillDisappear()
> Called WillMoveToWindow() with window: 
> Called OpenGLViewController.ViewWillAppear()
> Called WillMoveToWindow() with window: <UIWindow: 0xd083a00; frame = (0 0; 320 480); layer = <UIWindowLayer: 0xd083650>>

### On iOS 7 simulator: FAILS

Console output:
> Called OpenGLViewController.ViewWillAppear()
> Called WillMoveToWindow() with window: <UIWindow: 0x10264f30; frame = (0 0; 320 480); gestureRecognizers = <NSArray: 0x10265690>; layer = <UIWindowLayer: 0x102633a0>>
> Called OpenGLViewController.ViewWillDisappear()
> Called WillMoveToWindow() with window: 
> Called WillMoveToWindow() with window: <UIWindow: 0x10264f30; frame = (0 0; 320 480); gestureRecognizers = <NSArray: 0x10265690>; layer = <UIWindowLayer: 0x102633a0>>
> Error in DestroyFrameBuffer: System.InvalidOperationException: Operation requires a GraphicsContext, which hasn't been created yet.
>   at OpenTK.Platform.iPhoneOS.iPhoneOSGameView.AssertContext () [0x00011] in /Developer/MonoTouch/Source/monotouch/src/OpenGLES/OpenTK_1.0/Platform/iPhoneOS/iPhoneOSGameView.cs:246 
>   at OpenTK.Platform.iPhoneOS.iPhoneOSGameView.DestroyFrameBuffer () [0x00008] in /Developer/MonoTouch/Source/monotouch/src/OpenGLES/OpenTK_1.0/Platform/iPhoneOS/iPhoneOSGameView.cs:546 
>   at OpenGLTest2.EAGLView.DestroyFrameBuffer () [0x00003] in /Volumes/Cases/iOS_DestroyedOpenGL_View_RFicker_2014_02_24/OpenGLTest2/EAGLView.cs:63 
> Called WillMoveToWindow() with window: 
> Called OpenGLViewController.ViewWillAppear()
> 
> Unhandled Exception:
> System.NotSupportedException: Can't change RenderingApi after GraphicsContext is constructed.
>   at OpenTK.Platform.iPhoneOS.iPhoneOSGameView.set_ContextRenderingApi (EAGLRenderingAPI value)
(remainder of stack trace omitted for brevity)


The problem is roughly that `WillMoveToWindow()` is called 3 times instead of just once between `OpenGLViewController.ViewWillDisappear()` and `OpenGLViewController.ViewWillAppear()`. It is called once with a `null` window, then once with a non-null window (causing an error), then again with a `null` window.


## Workarounds

### Workaround 1: don't animate the UINavigationController transition

In `AppDelegate.cs`, change:
> _nav.PushViewController(new UIViewController(), true)

... to:
> _nav.PushViewController(new UIViewController(), false)

Apparently iOS 7 does something different with how it calls `WillMoveToWindow()` when performing an animated navigation controller transition compared to a non-animated transition.


### Workaround 2: add some logic to ensure that the base `iPhoneOSGameView.WillMoveToWindow()` method is only called once for each call of `OpenGLViewController.ViewWillAppear()` or `OpenGLViewController.ViewWillAppear()`.

For example, in EAGLView.cs add:
> public bool HasMovedToWindow { get; set; }
> 
> public override void WillMoveToWindow(UIWindow window)
> {
>     Console.WriteLine ("Called WillMoveToWindow() with window: {0}", window);
>     if (!HasMovedToWindow) {
>         HasMovedToWindow = true;
>         base.WillMoveToWindow(window);
>     }
> }


Then in both `OpenGLViewController.ViewWillAppear()` and `OpenGLViewController.ViewWillAppear()` add:
> _eaglView.HasMovedToWindow = false;


## Version information
Tested on Xamarin.iOS 7.0.6.168 and 7.0.7.2
Comment 2 Sadik Ali 2014-02-26 05:32:45 UTC
I have checked this is issue on below environments:

Mac
XS 4.2.2 (build 2)
X iOS: 7.0.6.168

I debug application on iOS 6 and iOS 7, noticed that application is working is working on iOS 6 and for iOS 7 getting exception same as mentioned in bug description.

For exception refer screen cast: https://gist.github.com/anonymous/fdbd08b42873ff0d6650
Comment 3 Johannes Rudolph 2014-05-08 07:04:03 UTC
I can confirm this bug still exists with the current Xamarin Stable version, and in addition (depending on the state of the view) I get a slightly different exception:

`
System.InvalidOperationException: Operation requires a GraphicsContext, which hasn't been created yet.
  at OpenTK.Platform.iPhoneOS.iPhoneOSGameView.AssertContext () [0x00011] in /Developer/MonoTouch/Source/monotouch/src/OpenGLES/OpenTK_1.0/Platform/iPhoneOS/iPhoneOSGameView.cs:246 
  at OpenTK.Platform.iPhoneOS.iPhoneOSGameView.DestroyFrameBuffer () [0x00008] in /Developer/MonoTouch/Source/monotouch/src/OpenGLES/OpenTK_1.0/Platform/iPhoneOS/iPhoneOSGameView.cs:546 
  at OpenTK.Platform.iPhoneOS.iPhoneOSGameView.WillMoveToWindow (MonoTouch.UIKit.UIWindow window) [0x00078] in /Developer/MonoTouch/Source/monotouch/src/OpenGLES/OpenTK_1.0/Platform/iPhoneOS/iPhoneOSGameView.cs:802 
  at RowingInMotion.Mobile.BoatApp.iOS.EAGLView.WillMoveToWindow (MonoTouch.UIKit.UIWindow window) [0x00003] in /Users/jr/dev/rowinginmotion-cross/RowingInMotion.Mobile.BoatApp.iOS/Views/EAGLView.cs:80 
  at (wrapper managed-to-native) MonoTouch.UIKit.UIApplication:UIApplicationMain (int,string[],intptr,intptr)
  at MonoTouch.UIKit.UIApplication.Main (System.String[] args, System.String principalClassName, System.String delegateClassName) [0x0004c] in /Developer/MonoTouch/Source/monotouch/src/UIKit/.pmcs-compat.UIApplication.cs:38 
  at RowingInMotion.Mobile.BoatApp.iOS.Application.Main (System.String[] args) [0x00008] in /Users/jr/dev/rowinginmotion-cross/RowingInMotion.Mobile.BoatApp.iOS/Setup/Main.cs:17 
`


Xamarin.iOS
Version: 7.2.2.2 (Business Edition)
Hash: db4427f
Branch: 
Build date: 2014-04-22 12:49:14-0400

Trying to see whether there's an easy workaround/patch.

Note You need to log in before you can comment on or make changes to this bug.