From 4f2fcf9c7848c58464e1b6f2fa55a585dd4986f9 Mon Sep 17 00:00:00 2001 From: gmurray81 Date: Tue, 23 Feb 2021 16:53:05 -0500 Subject: [PATCH 1/6] avoid issues with failure to create gl surface --- .../AngleSwapChainPanel.cs | 14 +++++ .../GlesInterop/GlesContext.cs | 61 +++++++++++++------ .../SkiaSharp.Views.UWP/SKSwapChainPanel.cs | 6 +- 3 files changed, 62 insertions(+), 19 deletions(-) diff --git a/source/SkiaSharp.Views/SkiaSharp.Views.UWP/AngleSwapChainPanel.cs b/source/SkiaSharp.Views/SkiaSharp.Views.UWP/AngleSwapChainPanel.cs index 1afe7485dc7..7ca7a58d90d 100644 --- a/source/SkiaSharp.Views/SkiaSharp.Views.UWP/AngleSwapChainPanel.cs +++ b/source/SkiaSharp.Views/SkiaSharp.Views.UWP/AngleSwapChainPanel.cs @@ -33,8 +33,14 @@ public class AngleSwapChainPanel : SwapChainPanel private bool enableRenderLoop; + private double lastCompositionScaleX = 0.0; + private double lastCompositionScaleY = 0.0; + public AngleSwapChainPanel() { + lastCompositionScaleX = CompositionScaleX; + lastCompositionScaleY = CompositionScaleY; + glesContext = null; renderLoopWorker = null; @@ -148,6 +154,14 @@ private static void OnVisibilityChanged(DependencyObject d, DependencyPropertyCh private void OnCompositionChanged(SwapChainPanel sender, object args) { + if (lastCompositionScaleX == CompositionScaleX && + lastCompositionScaleY == CompositionScaleY) + { + return; + } + + lastCompositionScaleX = CompositionScaleX; + lastCompositionScaleY = CompositionScaleY; ContentsScale = CompositionScaleX; DestroyRenderSurface(); diff --git a/source/SkiaSharp.Views/SkiaSharp.Views.UWP/GlesInterop/GlesContext.cs b/source/SkiaSharp.Views/SkiaSharp.Views.UWP/GlesInterop/GlesContext.cs index 0bbae5b30a2..fa7e0a8c572 100644 --- a/source/SkiaSharp.Views/SkiaSharp.Views.UWP/GlesInterop/GlesContext.cs +++ b/source/SkiaSharp.Views/SkiaSharp.Views.UWP/GlesInterop/GlesContext.cs @@ -2,6 +2,7 @@ using Windows.Foundation; using Windows.Foundation.Collections; using Windows.UI.Xaml.Controls; +using System.Collections.Generic; using SkiaSharp.Views.UWP.Interop; @@ -21,6 +22,9 @@ internal class GlesContext : IDisposable private EGLSurface eglSurface; private EGLConfig eglConfig; + private static readonly object displayLock = new object(); + private static readonly Dictionary displayReferenceCounts = new Dictionary(); + public GlesContext() { eglConfig = Egl.EGL_NO_CONFIG; @@ -210,26 +214,19 @@ private void Initialize() // using "warpDisplayAttributes". This corresponds to D3D11 Feature Level 11_0 on WARP, a D3D11 software rasterizer. // - // This tries to initialize EGL to D3D11 Feature Level 10_0+. See above comment for details. - eglDisplay = Egl.eglGetPlatformDisplayEXT(Egl.EGL_PLATFORM_ANGLE_ANGLE, Egl.EGL_DEFAULT_DISPLAY, defaultDisplayAttributes); - if (eglDisplay == Egl.EGL_NO_DISPLAY) + lock (displayLock) { - throw new Exception("Failed to get EGL display"); - } - - if (Egl.eglInitialize(eglDisplay, out int major, out int minor) == Egl.EGL_FALSE) - { - // This tries to initialize EGL to D3D11 Feature Level 9_3, if 10_0+ is unavailable (e.g. on some mobile devices). - eglDisplay = Egl.eglGetPlatformDisplayEXT(Egl.EGL_PLATFORM_ANGLE_ANGLE, Egl.EGL_DEFAULT_DISPLAY, fl9_3DisplayAttributes); + // This tries to initialize EGL to D3D11 Feature Level 10_0+. See above comment for details. + eglDisplay = Egl.eglGetPlatformDisplayEXT(Egl.EGL_PLATFORM_ANGLE_ANGLE, Egl.EGL_DEFAULT_DISPLAY, defaultDisplayAttributes); if (eglDisplay == Egl.EGL_NO_DISPLAY) { throw new Exception("Failed to get EGL display"); } - if (Egl.eglInitialize(eglDisplay, out major, out minor) == Egl.EGL_FALSE) + if (Egl.eglInitialize(eglDisplay, out int major, out int minor) == Egl.EGL_FALSE) { - // This initializes EGL to D3D11 Feature Level 11_0 on WARP, if 9_3+ is unavailable on the default GPU. - eglDisplay = Egl.eglGetPlatformDisplayEXT(Egl.EGL_PLATFORM_ANGLE_ANGLE, Egl.EGL_DEFAULT_DISPLAY, warpDisplayAttributes); + // This tries to initialize EGL to D3D11 Feature Level 9_3, if 10_0+ is unavailable (e.g. on some mobile devices). + eglDisplay = Egl.eglGetPlatformDisplayEXT(Egl.EGL_PLATFORM_ANGLE_ANGLE, Egl.EGL_DEFAULT_DISPLAY, fl9_3DisplayAttributes); if (eglDisplay == Egl.EGL_NO_DISPLAY) { throw new Exception("Failed to get EGL display"); @@ -237,10 +234,29 @@ private void Initialize() if (Egl.eglInitialize(eglDisplay, out major, out minor) == Egl.EGL_FALSE) { - // If all of the calls to eglInitialize returned EGL_FALSE then an error has occurred. - throw new Exception("Failed to initialize EGL"); + // This initializes EGL to D3D11 Feature Level 11_0 on WARP, if 9_3+ is unavailable on the default GPU. + eglDisplay = Egl.eglGetPlatformDisplayEXT(Egl.EGL_PLATFORM_ANGLE_ANGLE, Egl.EGL_DEFAULT_DISPLAY, warpDisplayAttributes); + if (eglDisplay == Egl.EGL_NO_DISPLAY) + { + throw new Exception("Failed to get EGL display"); + } + + if (Egl.eglInitialize(eglDisplay, out major, out minor) == Egl.EGL_FALSE) + { + + // If all of the calls to eglInitialize returned EGL_FALSE then an error has occurred. + throw new Exception("Failed to initialize EGL"); + } } } + + if (eglDisplay != Egl.EGL_NO_DISPLAY) + { + int refCount = 0; + displayReferenceCounts.TryGetValue(eglDisplay, out refCount); + refCount += 1; + displayReferenceCounts[eglDisplay] = refCount; + } } EGLDisplay[] configs = new EGLDisplay[1]; @@ -267,8 +283,19 @@ private void Cleanup() if (eglDisplay != Egl.EGL_NO_DISPLAY) { - Egl.eglTerminate(eglDisplay); - eglDisplay = Egl.EGL_NO_DISPLAY; + lock (displayReferenceCounts) + { + int refCount = 0; + displayReferenceCounts.TryGetValue(eglDisplay, out refCount); + refCount -= 1; + displayReferenceCounts[eglDisplay] = refCount; + + if (refCount == 0) + { + Egl.eglTerminate(eglDisplay); + eglDisplay = Egl.EGL_NO_DISPLAY; + } + } } } } diff --git a/source/SkiaSharp.Views/SkiaSharp.Views.UWP/SKSwapChainPanel.cs b/source/SkiaSharp.Views/SkiaSharp.Views.UWP/SKSwapChainPanel.cs index e4ad1e9d147..9c32af78833 100644 --- a/source/SkiaSharp.Views/SkiaSharp.Views.UWP/SKSwapChainPanel.cs +++ b/source/SkiaSharp.Views/SkiaSharp.Views.UWP/SKSwapChainPanel.cs @@ -110,8 +110,10 @@ protected override void OnDestroyingContext() glInfo = default; - context?.AbandonContext(true); - context?.Dispose(); + //this probably isn't valid to yank these lines? but the behavior is correct with these gone. + //skiasharp doesn't seem to be calling AbandonContext anywhere else? + //context?.AbandonContext(true); + //context?.Dispose(); context = null; glInterface?.Dispose(); From f2326ba13421e9392b2d2b85dbf1a71f106cfcba Mon Sep 17 00:00:00 2001 From: gmurray81 Date: Wed, 24 Feb 2021 09:23:51 -0500 Subject: [PATCH 2/6] safer cleanup for context? --- .../SkiaSharp.Views.UWP/SKSwapChainPanel.cs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/source/SkiaSharp.Views/SkiaSharp.Views.UWP/SKSwapChainPanel.cs b/source/SkiaSharp.Views/SkiaSharp.Views.UWP/SKSwapChainPanel.cs index 9c32af78833..943f51badbe 100644 --- a/source/SkiaSharp.Views/SkiaSharp.Views.UWP/SKSwapChainPanel.cs +++ b/source/SkiaSharp.Views/SkiaSharp.Views.UWP/SKSwapChainPanel.cs @@ -110,10 +110,11 @@ protected override void OnDestroyingContext() glInfo = default; - //this probably isn't valid to yank these lines? but the behavior is correct with these gone. - //skiasharp doesn't seem to be calling AbandonContext anywhere else? - //context?.AbandonContext(true); - //context?.Dispose(); + //This seems to be a safer fix for the issue? + //But I'm not sure about the difference in semantics between + //AbandonContext(true) and AbandonContext(false) on the Skia end. + context?.AbandonContext(false); + context?.Dispose(); context = null; glInterface?.Dispose(); From 0c445ae61cc82b6f839799120aaecbea2b03ba65 Mon Sep 17 00:00:00 2001 From: gmurray81 Date: Sun, 14 Mar 2021 17:01:41 -0400 Subject: [PATCH 3/6] change display to static, don't seem to need abandonContext(false) when display is stiatc. --- .../GlesInterop/GlesContext.cs | 32 ++----------------- .../SkiaSharp.Views.UWP/SKSwapChainPanel.cs | 5 +-- 2 files changed, 3 insertions(+), 34 deletions(-) diff --git a/source/SkiaSharp.Views/SkiaSharp.Views.UWP/GlesInterop/GlesContext.cs b/source/SkiaSharp.Views/SkiaSharp.Views.UWP/GlesInterop/GlesContext.cs index fa7e0a8c572..f72be060fd5 100644 --- a/source/SkiaSharp.Views/SkiaSharp.Views.UWP/GlesInterop/GlesContext.cs +++ b/source/SkiaSharp.Views/SkiaSharp.Views.UWP/GlesInterop/GlesContext.cs @@ -17,14 +17,11 @@ internal class GlesContext : IDisposable { private bool isDisposed = false; - private EGLDisplay eglDisplay; + private static EGLDisplay eglDisplay = Egl.EGL_NO_DISPLAY; private EGLContext eglContext; private EGLSurface eglSurface; private EGLConfig eglConfig; - private static readonly object displayLock = new object(); - private static readonly Dictionary displayReferenceCounts = new Dictionary(); - public GlesContext() { eglConfig = Egl.EGL_NO_CONFIG; @@ -214,7 +211,7 @@ private void Initialize() // using "warpDisplayAttributes". This corresponds to D3D11 Feature Level 11_0 on WARP, a D3D11 software rasterizer. // - lock (displayLock) + if (eglDisplay == Egl.EGL_NO_DISPLAY) { // This tries to initialize EGL to D3D11 Feature Level 10_0+. See above comment for details. eglDisplay = Egl.eglGetPlatformDisplayEXT(Egl.EGL_PLATFORM_ANGLE_ANGLE, Egl.EGL_DEFAULT_DISPLAY, defaultDisplayAttributes); @@ -249,14 +246,6 @@ private void Initialize() } } } - - if (eglDisplay != Egl.EGL_NO_DISPLAY) - { - int refCount = 0; - displayReferenceCounts.TryGetValue(eglDisplay, out refCount); - refCount += 1; - displayReferenceCounts[eglDisplay] = refCount; - } } EGLDisplay[] configs = new EGLDisplay[1]; @@ -280,23 +269,6 @@ private void Cleanup() Egl.eglDestroyContext(eglDisplay, eglContext); eglContext = Egl.EGL_NO_CONTEXT; } - - if (eglDisplay != Egl.EGL_NO_DISPLAY) - { - lock (displayReferenceCounts) - { - int refCount = 0; - displayReferenceCounts.TryGetValue(eglDisplay, out refCount); - refCount -= 1; - displayReferenceCounts[eglDisplay] = refCount; - - if (refCount == 0) - { - Egl.eglTerminate(eglDisplay); - eglDisplay = Egl.EGL_NO_DISPLAY; - } - } - } } } } diff --git a/source/SkiaSharp.Views/SkiaSharp.Views.UWP/SKSwapChainPanel.cs b/source/SkiaSharp.Views/SkiaSharp.Views.UWP/SKSwapChainPanel.cs index 943f51badbe..e4ad1e9d147 100644 --- a/source/SkiaSharp.Views/SkiaSharp.Views.UWP/SKSwapChainPanel.cs +++ b/source/SkiaSharp.Views/SkiaSharp.Views.UWP/SKSwapChainPanel.cs @@ -110,10 +110,7 @@ protected override void OnDestroyingContext() glInfo = default; - //This seems to be a safer fix for the issue? - //But I'm not sure about the difference in semantics between - //AbandonContext(true) and AbandonContext(false) on the Skia end. - context?.AbandonContext(false); + context?.AbandonContext(true); context?.Dispose(); context = null; From 4327d7132c9da9cf9650dfe3957efdf3ee1168e7 Mon Sep 17 00:00:00 2001 From: gmurray81 Date: Sun, 14 Mar 2021 19:08:26 -0400 Subject: [PATCH 4/6] still seeing issue with AbandonContext(true). Must be more too this. --- source/SkiaSharp.Views/SkiaSharp.Views.UWP/SKSwapChainPanel.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/SkiaSharp.Views/SkiaSharp.Views.UWP/SKSwapChainPanel.cs b/source/SkiaSharp.Views/SkiaSharp.Views.UWP/SKSwapChainPanel.cs index e4ad1e9d147..213a0220830 100644 --- a/source/SkiaSharp.Views/SkiaSharp.Views.UWP/SKSwapChainPanel.cs +++ b/source/SkiaSharp.Views/SkiaSharp.Views.UWP/SKSwapChainPanel.cs @@ -110,7 +110,7 @@ protected override void OnDestroyingContext() glInfo = default; - context?.AbandonContext(true); + context?.AbandonContext(false); context?.Dispose(); context = null; From f799997d4729213a1fc078b431e22782c951a938 Mon Sep 17 00:00:00 2001 From: Matthew Leibowitz Date: Tue, 30 Mar 2021 17:49:18 +0200 Subject: [PATCH 5/6] Split the Initialize method to avoid any confusion --- .../GlesInterop/GlesContext.cs | 78 ++++++++++--------- 1 file changed, 41 insertions(+), 37 deletions(-) diff --git a/source/SkiaSharp.Views/SkiaSharp.Views.UWP/GlesInterop/GlesContext.cs b/source/SkiaSharp.Views/SkiaSharp.Views.UWP/GlesInterop/GlesContext.cs index f72be060fd5..527c1de9688 100644 --- a/source/SkiaSharp.Views/SkiaSharp.Views.UWP/GlesInterop/GlesContext.cs +++ b/source/SkiaSharp.Views/SkiaSharp.Views.UWP/GlesInterop/GlesContext.cs @@ -15,9 +15,10 @@ namespace SkiaSharp.Views.GlesInterop { internal class GlesContext : IDisposable { + private static EGLDisplay eglDisplay = Egl.EGL_NO_DISPLAY; + private bool isDisposed = false; - private static EGLDisplay eglDisplay = Egl.EGL_NO_DISPLAY; private EGLContext eglContext; private EGLSurface eglSurface; private EGLConfig eglConfig; @@ -25,10 +26,10 @@ internal class GlesContext : IDisposable public GlesContext() { eglConfig = Egl.EGL_NO_CONFIG; - eglDisplay = Egl.EGL_NO_DISPLAY; eglContext = Egl.EGL_NO_CONTEXT; eglSurface = Egl.EGL_NO_SURFACE; + InitializeDisplay(); Initialize(); } @@ -140,24 +141,10 @@ public void Reset() Initialize(); } - private void Initialize() + private void InitializeDisplay() { - int[] configAttributes = new[] - { - Egl.EGL_RED_SIZE, 8, - Egl.EGL_GREEN_SIZE, 8, - Egl.EGL_BLUE_SIZE, 8, - Egl.EGL_ALPHA_SIZE, 8, - Egl.EGL_DEPTH_SIZE, 8, - Egl.EGL_STENCIL_SIZE, 8, - Egl.EGL_NONE - }; - - int[] contextAttributes = new[] - { - Egl.EGL_CONTEXT_CLIENT_VERSION, 2, - Egl.EGL_NONE - }; + if (eglDisplay != Egl.EGL_NO_DISPLAY) + return; int[] defaultDisplayAttributes = new[] { @@ -211,19 +198,26 @@ private void Initialize() // using "warpDisplayAttributes". This corresponds to D3D11 Feature Level 11_0 on WARP, a D3D11 software rasterizer. // + // This tries to initialize EGL to D3D11 Feature Level 10_0+. See above comment for details. + eglDisplay = Egl.eglGetPlatformDisplayEXT(Egl.EGL_PLATFORM_ANGLE_ANGLE, Egl.EGL_DEFAULT_DISPLAY, defaultDisplayAttributes); if (eglDisplay == Egl.EGL_NO_DISPLAY) { - // This tries to initialize EGL to D3D11 Feature Level 10_0+. See above comment for details. - eglDisplay = Egl.eglGetPlatformDisplayEXT(Egl.EGL_PLATFORM_ANGLE_ANGLE, Egl.EGL_DEFAULT_DISPLAY, defaultDisplayAttributes); + throw new Exception("Failed to get EGL display"); + } + + if (Egl.eglInitialize(eglDisplay, out int major, out int minor) == Egl.EGL_FALSE) + { + // This tries to initialize EGL to D3D11 Feature Level 9_3, if 10_0+ is unavailable (e.g. on some mobile devices). + eglDisplay = Egl.eglGetPlatformDisplayEXT(Egl.EGL_PLATFORM_ANGLE_ANGLE, Egl.EGL_DEFAULT_DISPLAY, fl9_3DisplayAttributes); if (eglDisplay == Egl.EGL_NO_DISPLAY) { throw new Exception("Failed to get EGL display"); } - if (Egl.eglInitialize(eglDisplay, out int major, out int minor) == Egl.EGL_FALSE) + if (Egl.eglInitialize(eglDisplay, out major, out minor) == Egl.EGL_FALSE) { - // This tries to initialize EGL to D3D11 Feature Level 9_3, if 10_0+ is unavailable (e.g. on some mobile devices). - eglDisplay = Egl.eglGetPlatformDisplayEXT(Egl.EGL_PLATFORM_ANGLE_ANGLE, Egl.EGL_DEFAULT_DISPLAY, fl9_3DisplayAttributes); + // This initializes EGL to D3D11 Feature Level 11_0 on WARP, if 9_3+ is unavailable on the default GPU. + eglDisplay = Egl.eglGetPlatformDisplayEXT(Egl.EGL_PLATFORM_ANGLE_ANGLE, Egl.EGL_DEFAULT_DISPLAY, warpDisplayAttributes); if (eglDisplay == Egl.EGL_NO_DISPLAY) { throw new Exception("Failed to get EGL display"); @@ -231,22 +225,32 @@ private void Initialize() if (Egl.eglInitialize(eglDisplay, out major, out minor) == Egl.EGL_FALSE) { - // This initializes EGL to D3D11 Feature Level 11_0 on WARP, if 9_3+ is unavailable on the default GPU. - eglDisplay = Egl.eglGetPlatformDisplayEXT(Egl.EGL_PLATFORM_ANGLE_ANGLE, Egl.EGL_DEFAULT_DISPLAY, warpDisplayAttributes); - if (eglDisplay == Egl.EGL_NO_DISPLAY) - { - throw new Exception("Failed to get EGL display"); - } - - if (Egl.eglInitialize(eglDisplay, out major, out minor) == Egl.EGL_FALSE) - { - - // If all of the calls to eglInitialize returned EGL_FALSE then an error has occurred. - throw new Exception("Failed to initialize EGL"); - } + + // If all of the calls to eglInitialize returned EGL_FALSE then an error has occurred. + throw new Exception("Failed to initialize EGL"); } } } + } + + public void Initialize() + { + int[] configAttributes = new[] + { + Egl.EGL_RED_SIZE, 8, + Egl.EGL_GREEN_SIZE, 8, + Egl.EGL_BLUE_SIZE, 8, + Egl.EGL_ALPHA_SIZE, 8, + Egl.EGL_DEPTH_SIZE, 8, + Egl.EGL_STENCIL_SIZE, 8, + Egl.EGL_NONE + }; + + int[] contextAttributes = new[] + { + Egl.EGL_CONTEXT_CLIENT_VERSION, 2, + Egl.EGL_NONE + }; EGLDisplay[] configs = new EGLDisplay[1]; if ((Egl.eglChooseConfig(eglDisplay, configAttributes, configs, configs.Length, out int numConfigs) == Egl.EGL_FALSE) || (numConfigs == 0)) From 4e9ef60adb49d8ffbfe0b6de82f3f5e3dc300f93 Mon Sep 17 00:00:00 2001 From: Matthew Leibowitz Date: Tue, 30 Mar 2021 17:49:52 +0200 Subject: [PATCH 6/6] ? --- .../SkiaSharp.Views.UWP/GlesInterop/GlesContext.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/source/SkiaSharp.Views/SkiaSharp.Views.UWP/GlesInterop/GlesContext.cs b/source/SkiaSharp.Views/SkiaSharp.Views.UWP/GlesInterop/GlesContext.cs index 527c1de9688..45fb664ba8a 100644 --- a/source/SkiaSharp.Views/SkiaSharp.Views.UWP/GlesInterop/GlesContext.cs +++ b/source/SkiaSharp.Views/SkiaSharp.Views.UWP/GlesInterop/GlesContext.cs @@ -225,7 +225,6 @@ private void InitializeDisplay() if (Egl.eglInitialize(eglDisplay, out major, out minor) == Egl.EGL_FALSE) { - // If all of the calls to eglInitialize returned EGL_FALSE then an error has occurred. throw new Exception("Failed to initialize EGL"); }