Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice
  3. Join us on November 16th, 2023, between 1 pm and 9 pm CET for Ask the Experts Online on Discord and on Unity Discussions.
    Dismiss Notice

[RESOLVED] ReadPixels crash on HTC One M7, iPad Air, and probably many other mobile platforms

Discussion in 'Android' started by Johny_G, Nov 19, 2015.

  1. Johny_G

    Johny_G

    Joined:
    Mar 28, 2014
    Posts:
    20
    Hi there!

    For last 2 days I've been wrestling with strange crash in native code of our mobile builds. The crash goes like this on HTC One M7 (Unity Pro 5.2.2f1), but the "EndWrite" part with Bad Access also applies to iPad Air in Xcode, so I suppose the reason is the same:

    Code (CSharp):
    1. 11-19 11:04:41.976: I/DEBUG(274): *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
    2. 11-19 11:04:41.976: I/DEBUG(274): Build fingerprint: 'htc/htc_europe/m7:5.0.2/LRX22G/482424.22:user/release-keys'
    3. 11-19 11:04:41.976: I/DEBUG(274): Revision: '3'
    4. 11-19 11:04:41.976: I/DEBUG(274): ABI: 'arm'
    5. 11-19 11:04:41.976: I/DEBUG(274): pid: 14801, tid: 14845, name: UnityGfxDeviceW  >>> com.napoleongames.sevenmages <<<
    6. 11-19 11:04:41.976: I/DEBUG(274): signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0xc
    7. 11-19 11:04:42.026: I/DEBUG(274):     r0 a1f55a2c  r1 fffff23c  r2 deaddead  r3 a1436c98
    8. 11-19 11:04:42.026: I/DEBUG(274):     r4 bc54d380  r5 b93fc290  r6 b93fc670  r7 00000000
    9. 11-19 11:04:42.026: I/DEBUG(274):     r8 00005568  r9 ffffef58  sl 002f1e28  fp b8635ca0
    10. 11-19 11:04:42.026: I/DEBUG(274):     ip a1f55a84  sp 9ed8b8d0  lr a1436ca8  pc a1436cfc  cpsr 20020010
    11. 11-19 11:04:42.026: I/DEBUG(274): backtrace:
    12. 11-19 11:04:42.026: I/DEBUG(274):     #00 pc 00499cfc  /data/app/com.napoleongames.sevenmages-1/lib/arm/libunity.so (DrawBufferGLES<IndexBuffer, IndexBufferUsageMapperGLES>::EndWrite(unsigned int)+80)
    13. 11-19 11:04:42.036: I/DEBUG(274):     #01 pc 00499ca4  /data/app/com.napoleongames.sevenmages-1/lib/arm/libunity.so (GfxDeviceGLES::EndWriteIndices(IndexBuffer*, unsigned int)+12)
    14. 11-19 11:04:42.036: I/DEBUG(274):     #02 pc 002a9f18  /data/app/com.napoleongames.sevenmages-1/lib/arm/libunity.so (GeometryJobTasks::PutGeometryJobFence(GfxDevice&, unsigned int)+164)
    15. 11-19 11:04:42.036: I/DEBUG(274):     #03 pc 002a9e04  /data/app/com.napoleongames.sevenmages-1/lib/arm/libunity.so (GeometryJobTasks::EndGeometryJobFrame(GfxDevice&)+68)
    16. 11-19 11:04:42.036: I/DEBUG(274):     #04 pc 00481c38  /data/app/com.napoleongames.sevenmages-1/lib/arm/libunity.so (GfxDeviceWorker::RunCommand(ThreadedStreamBuffer&)+4052)
    17. 11-19 11:04:42.036: I/DEBUG(274):     #05 pc 004866a0  /data/app/com.napoleongames.sevenmages-1/lib/arm/libunity.so (GfxDeviceWorker::Run()+20)
    18. 11-19 11:04:42.036: I/DEBUG(274):     #06 pc 00480c4c  /data/app/com.napoleongames.sevenmages-1/lib/arm/libunity.so (GfxDeviceWorker::RunGfxDeviceWorker(void*)+80)
    19. 11-19 11:04:42.036: I/DEBUG(274):     #07 pc 00402ac0  /data/app/com.napoleongames.sevenmages-1/lib/arm/libunity.so (Thread::RunThreadWrapper(void*)+84)
    20. 11-19 11:04:42.036: I/DEBUG(274):     #08 pc 00012f83  /system/lib/libc.so (__pthread_start(void*)+30)
    21. 11-19 11:04:42.036: I/DEBUG(274):     #09 pc 00011047  /system/lib/libc.so (__start_thread+6)
    I was able to trace (using the strange code below) that this happens on this line of my code:
    Code (CSharp):
    1. _screenshotTexture.ReadPixels(new Rect(0, 0, targetWidth, targetHeight), 0, 0, false);
    My class has those fields:
    Code (CSharp):
    1. private RenderTexture _renderTexture;
    2. private Texture2D _screenshotTexture;
    The code goes as follows (please note that the code was originally much less verbose and without the WaitForEndOfFrame and GC.Collect, and File.Delete, but this seemed like the most secure way to minimize the crash and find the problematic line, and I don't want to clean it for this post just in case that I miss something important - but the same thing happens for clean code):

    Code (CSharp):
    1. public IEnumerator SaveScreenshot(string filePath, bool allCameras, int quality, Vector2 targetSize)
    2.     {
    3.         var targetWidth = Mathf.RoundToInt(targetSize.x);
    4.         var targetHeight = Mathf.RoundToInt(targetSize.y);
    5.  
    6.         if (_renderTexture == null)
    7.         {
    8.             _renderTexture = new RenderTexture(targetWidth, targetHeight, 16); // 24 is the same
    9.         }
    10.  
    11.         if (_screenshotTexture == null)
    12.         {
    13.             _screenshotTexture = new Texture2D(targetWidth, targetHeight, TextureFormat.RGB24, false);
    14.         }
    15.  
    16.         try
    17.         {
    18.             Debug.Log("Rendering to texture"); // Debug only
    19.  
    20.             GC.Collect(); // Debug only
    21.  
    22.             if (allCameras)
    23.             {
    24.                 foreach (Camera cam in Camera.allCameras)
    25.                 {
    26.                     cam.targetTexture = _renderTexture;
    27.                     cam.Render();
    28.                     cam.targetTexture = null;
    29.                 }
    30.             }
    31.             else
    32.             {
    33.                 GroupControls.PerspectiveCamera.targetTexture = _renderTexture;
    34.                 GroupControls.PerspectiveCamera.Render();
    35.                 GroupControls.PerspectiveCamera.targetTexture = null;
    36.             }
    37.         }
    38.         catch (Exception e)
    39.         {
    40.             Debug.Log(e.ToString());
    41.         }
    42.  
    43.         yield return new WaitForEndOfFrame(); // Debug only
    44.  
    45.         try
    46.         {
    47.             Debug.Log("Reading pixels"); // Debug only
    48.  
    49.             GC.Collect(); // Debug only
    50.  
    51.             Debug.Log("RenderTexture.active = renderTexture");  // Debug only
    52.             RenderTexture.active = _renderTexture;
    53.  
    54.             Debug.Log("_screenshotTexture.ReadPixels(new Rect(0, 0, " + targetWidth + ", " + targetHeight + "), 0, 0, false)"); // Debug only
    55.             _screenshotTexture.ReadPixels(new Rect(0, 0, targetWidth, targetHeight), 0, 0, false);
    56.  
    57.             Debug.Log("Camera.main.targetTexture = null"); // Debug only
    58.             Camera.main.targetTexture = null;
    59.  
    60.             Debug.Log("RenderTexture.active = null"); // Debug only
    61.             RenderTexture.active = null;
    62.  
    63.             Debug.Log("Destroy(renderTexture)"); // Debug only
    64.             Destroy(_renderTexture);
    65.         }
    66.         catch (Exception e)
    67.         {
    68.             Debug.Log(e.ToString());
    69.         }
    70.  
    71.         yield return new WaitForEndOfFrame(); // Debug only
    72.  
    73.         try
    74.         {
    75.             Debug.Log("Saving screenshot"); // Debug only
    76.  
    77.             GC.Collect(); // Debug only
    78.  
    79.             byte[] bytes = _screenshotTexture.EncodeToJPG(quality);
    80.  
    81.             if (File.Exists(filePath))
    82.             {
    83.                 File.Delete(filePath); // Debug only
    84.             }
    85.  
    86.             File.WriteAllBytes(filePath, bytes);
    87.         }
    88.         catch (Exception e)
    89.         {
    90.             Debug.Log(e.ToString());
    91.         }
    92.     }
    The code usually works fine (on PC, Nexus 5, most of the time iPad Air), it's basically 100% reliable for autosave (where I grab the screenshot), but as soon as I try to do it from the Save screen, where the main camera is obscured by GUI's rich graphics (maybe it's a memory issue?), the crash will trigger in about 30 % of attempts on iPad Air and about 90 % on HTC One M7.

    Does anybody have an idea? Thanks a lot!
     
  2. Johny_G

    Johny_G

    Joined:
    Mar 28, 2014
    Posts:
    20
    Finally got it!

    You can easily avoid the crash by delaying the rendering to the end of the frame by adding this as a first line:
    Code (CSharp):
    1. yield return new WaitForEndOfFrame();
    Now you can be sure that you don't interrupt regular rendering of the camera. Implemented it on friday and had no crash since.
     
    DrKucho likes this.