Search Unity

Question Direct3D 12 Memory Allocation Crash

Discussion in 'Editor & General Support' started by FC_Alessandro, Apr 15, 2021.

  1. FC_Alessandro

    FC_Alessandro

    Joined:
    Dec 9, 2016
    Posts:
    2
    Hello everyone,
    I'm really stumped on this sporadic crash that happens in my app and I'm running out of ideas. I keep getting a memory access violation error, my stack trace has a couple of variations but always ends up with D3D12DescriptorCache::Allocate.

    In short my app is passing 2 textures as native array pointers to a custom c++ dll that then writes in them before I call Texture2D.Apply in unity. This was something I ended up doing cause I needed to handle multiple devices at a high framerate that was not possible with unity's standard LoadData function. here is my code:

    Here is a snippet of my unity code:
    Code (CSharp):
    1. void UpdateFrame()
    2. {
    3.     try
    4.     {
    5.         int newFrameResult = 0;
    6.  
    7.         if(!isDisabled)
    8.         {
    9.             texDataColor = colTex.GetRawTextureData<Color32>();
    10.             texDataDepth = depthTex.GetRawTextureData<Color32>();
    11.  
    12.             unsafe
    13.             {
    14.                 IntPtr colorPtr = (IntPtr)NativeArrayUnsafeUtility.GetUnsafePtr(texDataColor);
    15.                 IntPtr depthPtr = (IntPtr)NativeArrayUnsafeUtility.GetUnsafePtr(texDataDepth);
    16.  
    17.                 if(colorPtr != IntPtr.Zero && depthPtr != IntPtr.Zero)
    18.                 {
    19.                     newFrameResult = GetLatestLiveFrames(colorPtr, depthPtr, kinectIndex, resolution.x, resolution.y, offset, limitIR, maxDepthMM);
    20.                 }
    21.                 else
    22.                 {
    23.                     newFrameResult = 4;
    24.                 }
    25.             }
    26.  
    27.             if(newFrameResult == 1)
    28.             {
    29.                 colTex.Apply();
    30.                 depthTex.Apply();
    31.  
    32.                 cShader.SetInt("w", resolution.x);
    33.                 cShader.SetInt("h", resolution.y);
    34.                 cShader.SetBool("flipX", flipX);
    35.                 cShader.SetBool("flipY", flipY);
    36.                 cShader.SetFloat("maxDepth", maxDepth);
    37.  
    38.                 cShader.Dispatch(0, resolution.x / 8, resolution.y / 8, 1);
    39.                 cShader.Dispatch(1, resolution.x / 8, resolution.y / 8, 1);
    40.             }
    41.         }
    42.         else
    43.         {
    44.             RenderTexture.active = colRT;
    45.             GL.Clear(true, true, Color.black);
    46.             RenderTexture.active = depthRT;
    47.             GL.Clear(true, true, Color.black);
    48.             RenderTexture.active = null;
    49.  
    50.             newFrameResult = 1;
    51.         }
    52.  
    53.         if(texDataColor.IsCreated)
    54.         {
    55.             texDataColor.Dispose();
    56.         }
    57.  
    58.         if(texDataDepth.IsCreated)
    59.         {
    60.             texDataDepth.Dispose();
    61.         }
    62.  
    63.         if(newFrameResult == 1)
    64.         {
    65.             threeSlicePipeline.SendTexture(areaID, colRT, depthRT, this, !isDisabled);
    66.         }
    67.         else
    68.         {
    69.             switch(newFrameResult)
    70.             {
    71.                 case 0:
    72.                     Debug.LogWarning($"{gameObject.name}: DLL Error Maybe null pointer! Skipping frame!");
    73.                 break;
    74.                 case 2:
    75.                     if(useRecording)
    76.                     {
    77.                         Debug.LogWarning($"{gameObject.name}: DLL Error EOF! Skipping frame!");
    78.                     }
    79.                     else
    80.                     {
    81.                         Debug.LogWarning($"{gameObject.name}: DLL Error Timeout! Skipping frame!");
    82.                     }
    83.                 break;
    84.                 case 3:
    85.                     Debug.LogWarning($"{gameObject.name}: DLL Error Failed to pull capture! Skipping frame!");
    86.                 break;
    87.                 case 4:
    88.                     Debug.LogWarning($"{gameObject.name}: Unity Error NULL pointer found! Skipping frame!");
    89.                 break;
    90.             }
    91.  
    92.             ReadyForNextFrame();
    93.         }
    94.     }
    95.     catch
    96.     {
    97.         Debug.LogWarning($"{gameObject.name}: Error caught while pulling frame, skipping!");
    98.  
    99.         if(texDataColor.IsCreated)
    100.         {
    101.             texDataColor.Dispose();
    102.         }
    103.  
    104.         if(texDataDepth.IsCreated)
    105.         {
    106.             texDataDepth.Dispose();
    107.         }
    108.  
    109.         ReadyForNextFrame();
    110.     }
    111. }
    Here is a snippet of my DLL code:
    Code (C++):
    1. void MemCopyImage(uint8_t* _buffer, uint8_t* _dst, int _dstW, int _dstH, int _srcXOffset, size_t _stride, int _pixelSizeInBytes)
    2. {
    3.     uint8_t* ptr = _dst;
    4.     uint8_t* sourcePtr = _buffer;
    5.  
    6.     int chunkHeight = _dstH / 12; //denominator MUST cleanly divide the height
    7.  
    8.     sourcePtr += _srcXOffset * _pixelSizeInBytes;
    9.  
    10.     if (sourcePtr == NULL || *sourcePtr == NULL) {
    11.         OutputDebugString(L"Bad source pointer");
    12.         return;
    13.     }
    14.  
    15.     if (ptr == NULL || *ptr == NULL) {
    16.         OutputDebugString(L"Bad destination pointer");
    17.         return;
    18.     }
    19.  
    20.     std::vector<std::thread> threads;
    21.  
    22.     std::mutex mtx;
    23.  
    24.     for (int i = 0; i < 12; i++) {
    25.         threads.push_back(std::thread(CopyImageInThread, sourcePtr, ptr, _dstW, _dstH, _stride, _pixelSizeInBytes, i, chunkHeight, std::ref(mtx)));
    26.     }
    27.  
    28.     for (auto& th : threads) {
    29.         th.join();
    30.     }
    31. }
    32.  
    33. void CopyImageInThread(uint8_t* _sourceStart, uint8_t* _dstStart, int _dstW, int _dstH, size_t _stride, int _pixelSizeInBytes, int _index, int _chunkHeight, std::mutex& _mtx)
    34. {
    35.     //image 0,0 position
    36.     uint8_t* sourcePtr = _sourceStart;
    37.     uint8_t* dstPtr = _dstStart;
    38.  
    39.     //strides
    40.     size_t destinationStride = _dstW * _pixelSizeInBytes;
    41.     size_t srcStride = _stride;
    42.  
    43.     //starting position for this chunk
    44.     sourcePtr += srcStride * _index * _chunkHeight;
    45.     dstPtr += destinationStride * _index * _chunkHeight;
    46.  
    47.     if (sourcePtr == NULL || *sourcePtr == NULL) {
    48.         OutputDebugString(L"Bad source pointer");
    49.         return;
    50.     }
    51.  
    52.     if (dstPtr == NULL || *dstPtr == NULL) {
    53.         OutputDebugString(L"Bad destination pointer");
    54.         return;
    55.     }
    56.  
    57.     if (IsBadHugeReadPtr(sourcePtr, destinationStride)) {
    58.         OutputDebugString(L"Cant Read source pointer");
    59.         return;
    60.     }
    61.  
    62.     if (IsBadHugeWritePtr(dstPtr, destinationStride)) {
    63.         OutputDebugString(L"Cant Read destination pointer");
    64.         return;
    65.     }
    66.  
    67.     _mtx.lock();
    68.     for (int j = 0; j < _chunkHeight; j++)
    69.     {
    70.         try {
    71.             memcpy(dstPtr, sourcePtr, destinationStride);
    72.         }
    73.         catch (...) {
    74.             OutputDebugString(L"Problem writing line");
    75.         }
    76.  
    77.         //move for the next copy
    78.         sourcePtr += srcStride; //move by 1 row
    79.         dstPtr += destinationStride;
    80.     }
    81.     _mtx.unlock();
    82. }
    I attached the last couple of crash logs I got. As you can see on the code I have added plenty of null pointer checks and I designed the code so that there should never be any type of memory overlaps. The C# function only runs once the DLL is completely done with the previous cycle.

    Any help on this issue would be much appreciated!
     

    Attached Files:

    domportera likes this.
  2. domportera

    domportera

    Joined:
    Sep 12, 2013
    Posts:
    23
    I'm getting a similar issue and not sure why. Might be worth posting to Unity Answers if no one replies here?
     
  3. FC_Alessandro

    FC_Alessandro

    Joined:
    Dec 9, 2016
    Posts:
    2