MathewSachin / Captura

Capture Screen, Audio, Cursor, Mouse Clicks and Keystrokes
https://mathewsachin.github.io/Captura/
MIT License
9.51k stars 1.79k forks source link

SharpDX.SharpDXException: HRESULT: [0x8899000C], Module: [SharpDX.Direct2D1], ApiCode: [D2DERR_RECREATE_TARGET/RecreateTarget], Message: There has been a presentation error that may be recoverable. The caller needs to recreate, rerender the entire frame, and reattempt present. #567

Open alantan opened 4 years ago

alantan commented 4 years ago

SharpDX.SharpDXException: HRESULT: [0x8899000C], Module: [SharpDX.Direct2D1], ApiCode: [D2DERR_RECREATE_TARGET/RecreateTarget], Message: There has been a presentation error that may be recoverable. The caller needs to recreate, rerender the entire frame, and reattempt present.

at SharpDX.Result.CheckError() at DesktopDuplication.Direct2DEditorSession.EndDraw() at DesktopDuplication.Direct2DEditor.GenerateFrame() at Screna.Recorder.<>c__DisplayClass14_0.b2() at System.Threading.Tasks.Task`1.InnerInvoke() at System.Threading.Tasks.Task.Execute() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Screna.Recorder.d14.MoveNext()

Originally posted by @warichnict in https://github.com/MathewSachin/Captura/issues/454#issuecomment-550574112

alantan commented 4 years ago

I found a workaround solution to this problem that appears to work well in another project, but I do not trust my testing enough to suggest a commit yet.

The following appears to work for me:

  1. Putting this in EndDraw():
            try
            {
                RenderTarget.EndDraw();
            }
            catch (SharpDXException ex) when ((uint)ex.HResult == 0x8899000C)
            {
                throw new RenderTargetCorruptedException(ex);
            }
  1. Putting this in the Recorder.cs FrameWriter:
            try
            {
                frame = editableFrame.GenerateFrame(Timestamp);
            }
            catch (RenderTargetCorruptedException)
            {
                editableFrame.Dispose();
                // Retry
                return FrameWriter(Timestamp);
            }
MathewSachin commented 4 years ago

I think this is not safe to do. If it keeps on failing, we can get a StackOverflowException.

alantan commented 4 years ago

That's a very good point. Perhaps a limit on the number of retries? It is fairly rare, but when it happens it causes the entire recording to get corrupted. I realize this kind of solution is pretty ugly.