Bug 41413 - Xamarin.Forms.AnimationExtensions/ViewExtensions-based animation often fails when the View is on the same Page as an OpenGLView that HasRenderLoop
Summary: Xamarin.Forms.AnimationExtensions/ViewExtensions-based animation often fails ...
Status: RESOLVED FIXED
Alias: None
Product: Forms
Classification: Xamarin
Component: Forms ()
Version: 2.2.0
Hardware: Macintosh Mac OS
: --- critical
Target Milestone: ---
Assignee: Bugzilla
URL:
Depends on:
Blocks:
 
Reported: 2016-05-31 22:46 UTC by Stuart Fischer
Modified: 2017-05-23 18:06 UTC (History)
8 users (show)

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


Attachments
Sample solution showing the issue of OpenGLView having RenderLoop interfering with ViewExtensions.FadeTo(double) (16.11 KB, application/zip)
2016-05-31 22:58 UTC, Stuart Fischer
Details


Notice (2018-05-24): bugzilla.xamarin.com is now in read-only mode.

Please join us on Visual Studio Developer Community and in the Xamarin and Mono organizations on GitHub to continue tracking issues. Bugzilla will remain available for reference in read-only mode. We will continue to work on open Bugzilla bugs, copy them to the new locations as needed for follow-up, and add the new items under Related Links.

Our sincere thanks to everyone who has contributed on this bug tracker over the years. Thanks also for your understanding as we make these adjustments and improvements for the future.


Please create a new report on Developer Community or GitHub with your current version information, steps to reproduce, and relevant error messages or log files if you are hitting an issue that looks similar to this resolved bug and you do not yet see a matching new report.

Related Links:
Status:
RESOLVED FIXED

Description Stuart Fischer 2016-05-31 22:46:37 UTC
# Steps to reproduce
1) A Xamarin.Forms.OpenGLView is layed-out in a Xamarin.Forms ContentPage. A Render method is defined for the OpenGLView, and its HasRenderLoop property is set to true.
2) Another Xamarin.Forms.View (ie: AbsoluteLayout or Label) "nonOpenGLView" is layed-out above
(in-front of) the OpenGlView (eg: centered on the same Xamarin.Forms Page).
3) Upon pressing a Button on the same page, in the Button's event handler, animate fade-out/fade-in nonOpenGLView:
  await nonOpenGLView.FadeTo(0.0);
    or, if already faded-out, fade in:
  await nonOpenGLView.FadeTo(1.0);
4) Visually observe that there are times when the nonOpenGLView fails to start or complete fading-in or fading-out.

# Expected behaviour
The nonOpenGLView should fade-in or fade-out based on the description of the ViewExtensions.FadeOut() method, regardless of the existence/render-status of the OpenGLView appearing on the same ContentPage.

# Actual behavior
After pressing the fade-in/fade-out Button a few times, the nonOpenGLView fails to animate (ie: stays opaque instead of fading-out). If the HasRenderLoop property of the OpenGLView is subsequently set to false, the animations (fade-in/fade-out) of the nonOpenGLView again succeed without issue.

# Supplemental info (logs, images, videos)
I have a simple sample to demonstrate the issue as described above occurring with Xamarin.Forms 2.2.0.45, but not with 1.4.3.6376. Will attach this sample. Aside from ViewExtensions.FadeTo() failing to complete when OpenGlView is present, we also observe the same issue using AnimationExtensions Animate() method.

Issue does not occur with the iOS simulator or Android platform, only on iOS devices (real hardware).
We did not observe these issues with older versions of Xamarin.Forms (eg. 1.4.3.6376).
I think this issue has existed in many Xamarin.Forms 2+ releases: it is not a brand new issue but at least several months old.

# Test environment (full version information)
iOS 8.4.1, iPad mini 2
(probably occurs with iOS 9, probably occurs with other iOS hardware)
Xamarin.Forms 2.2.0.45

Xamarin Studio Business
Version 5.10.3 (build 51)
Installation UUID: 27ddf78f-5af9-402d-b2fc-e28fdbe94f16
Runtime:
	Mono 4.2.4 (explicit/71b88f3)
	GTK+ 2.24.23 (Raleigh theme)

	Package version: 402040004

Xamarin.Profiler
Version: 0.20.0.0
Location: /Applications/Xamarin Profiler.app/Contents/MacOS/Xamarin Profiler

Apple Developer Tools
Xcode 7.3.1 (10188.1)
Build 7D1014

Xamarin.Mac
Not Installed

Xamarin.Android
Version: 6.0.4.0 (Xamarin Business)
Android SDK: /data/home/sfischer/Library/Developer/Xamarin/android-sdk-macosx
	Supported Android versions:
		2.3    (API level 10)
		4.0.3  (API level 15)
		4.1    (API level 16)
		4.4    (API level 19)
		4.4.87 (API level 20)
		5.0    (API level 21)
		5.1    (API level 22)
		6.0    (API level 23)

SDK Tools Version: 25.1.3
SDK Platform Tools Version: 23.1
SDK Build Tools Version: 23.0.1

Java SDK: /usr
java version "1.8.0_71"
Java(TM) SE Runtime Environment (build 1.8.0_71-b15)
Java HotSpot(TM) 64-Bit Server VM (build 25.71-b15, mixed mode)

Android Designer EPL code available here:
https://github.com/xamarin/AndroidDesigner.EPL

Xamarin Android Player
Not Installed

Xamarin.iOS
Version: 9.6.2.4 (Xamarin Business)
Hash: d8bedd0
Branch: master
Build date: 2016-05-05 17:43:01-0400

Build Information
Release ID: 510030051
Git revision: f3c0d982165f785772d125f02668370d929014fb
Build date: 2016-03-24 18:51:31-04
Xamarin addins: ee5cfd3ecb6b20de47c1d25efb9a9abc101e8ce7
Build lane: monodevelop-lion-cycle6-c6sr3

Operating System
Mac OS X 10.11.4
Darwin Thalasa.local 15.4.0 Darwin Kernel Version 15.4.0
    Fri Feb 26 22:08:05 PST 2016
    root:xnu-3248.40.184~3/RELEASE_X86_64 x86_64
Comment 1 Stuart Fischer 2016-05-31 22:58:27 UTC
Created attachment 16147 [details]
Sample solution showing the issue of OpenGLView having RenderLoop interfering with ViewExtensions.FadeTo(double)

Start the sample on iOS hardware (does not occur in simulator, only device). Press the "Fade in/out Non-OpenGLView" button a number of times. Note that the grey "Non-OpenGLView" label stops fading-in/fading-out after a few button presses. 
+ Toggle the "OpenGLView HasRenderLoop" Switch below the OpenGLView. Note that subsequent presses on the Fade in/out button will result in successfully fading in/out the Non-OpenGLView Label.

Notes:

1) The problem occurs in the sample with extra sleep added to the OpenGLView's render-loop, originally to simulate longer rendering time for the OpenGLView. Below types of sleep seem to trigger the issue:
+ Task.Delay(10).Wait();
or
+ Thread.Sleep(10),
, but the problem does NOT occur with
+ await Task.Delay(100); // and make the Render-loop async()

2) Our released app "YVR Airport" experiences these issues extensively when interacting with its 3D Map screen after upgrading Xamarin.Forms to current version 2.2.0.45. The problem does not occur with older Xamarin.Forms version 1.4.3.6376. We do not have any intentional sleep() inserted in the production app, but a similar problem exists as described above. I am thinking (guessing) that although we do not have the intentional sleep() inserted in the "YVR Airport" app, there is a good chance this is the same issue shown in the sample.
Comment 2 Jon Goldberger [MSFT] 2016-05-31 23:21:51 UTC
I am not able to reproduce the described issue deploying sample app to an iPhone 6s running iOS 9.3.2. What device are you testing this on and what version of iOS does it have?
Comment 3 Stuart Fischer 2016-06-01 15:58:38 UTC
Hi Jon,

I repeated testing on several different hardware devices we have available now. As your test suggests, the problem happens on some devices/versions of iOS, not others. In particular, it is happening with the final iOS 8 version (8.4.1), but not with newer iOS 9.2/9.3. Seems to be an OS-version-specific issue, not related to iOS hardware type.

Problem occurs here with:

+ iPad mini 2 (Model A1489, (Retina/2nd Gen, Wi-Fi Only)), running iOS 8.4.1.
+ iPhone 5 (Model A1428), running iOS 8.4.1

Problem does NOT occur here with:
+ iPhone 4S (Model A1387), running iOS 9.3.1
+ iPhone 6S (Model A1633), running iOS 9.2.1.
+ Apple iPad Air 2 (Model A1566 (Wi-Fi Only)), running iOS 9.3.1

Again, on the iOS version showing the problem now, if we revert the Xamarin.Forms package to an older version (eg. 1.4.3.6376), the animation failure issues are not observed: ie: something has been broken.
Comment 4 Stuart Fischer 2016-06-01 21:25:24 UTC
Hi,

I tried different versions of Xamarin.Forms packages to see when the problem started happening: first version with the issue is 1.4.4.6377-pre1, does not happen with 1.4.3.6376.

In Below "BAD" means the animation fail issue described by this bug occurs, "OK" means the animation fail issue does not occur. (tested using the sample attached to this issue):

2.2.0.45  : BAD
2.1.0.6529  : BAD
2.1.0.6521  : BAD
2.0.1.6505  : BAD
2.0.0.6490  : BAD
2.0.0.6482  : BAD
1.5.1.6471  : BAD
1.5.0.6447  : BAD
1.4.4.6449  : BAD
1.4.4.6387  : BAD
1.4.4.6378-pre2 : BAD
1.4.4.6377-pre1 : BAD
1.4.3.6376  : OK
Comment 5 Stuart Fischer 2016-06-01 21:31:17 UTC
From reading the list of bug fixes in release notes of 1.4.4.6377-pre1 at https://www.nuget.org/packages/Xamarin.Forms/1.4.4.6377-pre1, I guess changes for the below bug fix might be suspicious for causing this issue (just a guess):

Bug 26783 - [iOS] - Scrolling causes animations to pause
Comment 6 Jon Goldberger [MSFT] 2016-06-06 22:20:38 UTC
Setting status to confirmed as I was able to reproduce this on iOS 8.4.1 device on Test Cloud.
Comment 8 Stuart Fischer 2016-07-20 01:03:41 UTC
Seems like fix may changing on line 101 in OpenGLViewRenderer.cs:

from:

_displayLink.AddToRunLoop(NSRunLoop.Current, NSRunLoop.NSDefaultRunLoopMode);

to:

_displayLink.AddToRunLoop(NSRunLoop.Current, NSRunLoop.NSRunLoopCommonModes);

This fixes the issue in my sample, and is based on info at:

http://stackoverflow.com/questions/4876488/animation-in-opengl-es-view-freezes-when-uiscrollview-is-dragged-on-iphone

, and I assume (although cannot see the old changelist) this matches changes made for Bug 26783 (Based on the bug notes that was also probably a change to parameters passed to CADisplayLink::AddToRunLoop).
Comment 10 Stuart Fischer 2016-07-22 01:21:50 UTC
In testing my local fix for this issue (change from using NSRunLoop.NSDefaultRunLoopMode to NSRunLoop.NSRunLoopCommonModes on OpenGLViewRenderer.cs line 101), I observed a crash in OpenGLViewRenderer.cs on line 96, when multiple OpenGLViewRenderers exist in the same app (eg. different Sub-views).

A View (the map in our app) instantiates a Xamarin.Forms OpenGLView (using OpenGLViewRenderer), then another View (a match-3 game on an overlaying view) instantiates a second OpenGLView. At that point, there is a Null Reference Exception on line 96 ("_displayLink.Invalidate()") of OpenGLViewRenderer.cs.

It can happen because the Dispose() method of OpenGLViewRenderer.cs is setting _displayLink to null (on line 45), but the run-loop is thereafter accessing the now-null _displayLink on line 96. If one adds a guard for null _displayLink to the condition of line 94, the problem no longer occurs:

BEFORE (line 94):

 if (control == null || model == null || !model.HasRenderLoop)

AFTER, with null guard (line 94):

if ((control == null || model == null || !model.HasRenderLoop)&&(_displayLink!=null))

I think this null guard on line 94 is needed.

This solves a separate (crash) issue than that described by this Bug report, so I don't know if it OK to make the changes under this issue without filing another bug report, or if I should file another bug report in order to get the line 94 change into a build?
Comment 12 Rui Marinho 2017-05-23 18:06:55 UTC
Should be fixed on 2.3.6-pre1