From d8a8948186b99734854111e6da4b8893bf1b2a1e Mon Sep 17 00:00:00 2001 From: Jerome Laban Date: Wed, 12 Oct 2022 08:35:55 -0400 Subject: [PATCH 1/9] feat(wasm): Add mt and mt+simd for emsdk 3.1.12 --- scripts/azure-templates-stages.yml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/scripts/azure-templates-stages.yml b/scripts/azure-templates-stages.yml index 277b4ad164..42937cd261 100644 --- a/scripts/azure-templates-stages.yml +++ b/scripts/azure-templates-stages.yml @@ -388,6 +388,14 @@ stages: displayName: '3.1.12_SIMD' version: 3.1.12 features: simd + - 3.1.12: + displayName: '3.1.12_Threading' + version: 3.1.12 + features: mt + - 3.1.12: + displayName: '3.1.12_Threading_SIMD' + version: 3.1.12 + features: mt,simd - ${{ if ne(parameters.buildPipelineType, 'tests') }}: - stage: managed From f17f50aa33c7d15d7217f920a1735194a2927da2 Mon Sep 17 00:00:00 2001 From: Jerome Laban Date: Wed, 12 Oct 2022 09:03:22 -0400 Subject: [PATCH 2/9] chore: Adjust build flags for pthread, fix harfbuzz generation --- native/wasm/build.cake | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/native/wasm/build.cake b/native/wasm/build.cake index 2c54effcc5..91e0082a2f 100644 --- a/native/wasm/build.cake +++ b/native/wasm/build.cake @@ -24,6 +24,7 @@ Task("libSkiaSharp") .Does(() => { bool hasSimdEnabled = EMSCRIPTEN_FEATURES.Contains("simd"); + bool hasThreadingEnabled = EMSCRIPTEN_FEATURES.Contains("mt"); GnNinja($"wasm", "SkiaSharp", $"target_os='linux' " + @@ -62,7 +63,7 @@ Task("libSkiaSharp") $" '-s', 'WARN_UNALIGNED=1' " + // '-s', 'USE_WEBGL2=1' (experimental) $"] " + // SIMD support is based on https://github.com/google/skia/blob/1f193df9b393d50da39570dab77a0bb5d28ec8ef/modules/canvaskit/compile.sh#L57 - $"extra_cflags_cc=[ '-frtti' { (hasSimdEnabled ? ", '-msimd128'" : "") } ] " + + $"extra_cflags_cc=[ '-frtti' { (hasSimdEnabled ? ", '-msimd128'" : "") { (hasThreadingEnabled ? ", '-pthread'" : "") } } ] " + COMPILERS + ADDITIONAL_GN_ARGS); @@ -111,12 +112,15 @@ Task("libHarfBuzzSharp") $"target_cpu='wasm' " + $"is_static_skiasharp=true " + $"visibility_hidden=false " + + $"extra_cflags_cc=[ '-frtti' { (hasSimdEnabled ? ", '-msimd128'" : "") { (hasThreadingEnabled ? ", '-pthread'" : "") } } ] " + COMPILERS + ADDITIONAL_GN_ARGS); var outDir = OUTPUT_PATH.Combine($"wasm"); if (!string.IsNullOrEmpty(EMSCRIPTEN_VERSION)) outDir = outDir.Combine("libHarfBuzzSharp.a").Combine(EMSCRIPTEN_VERSION); + if (EMSCRIPTEN_FEATURES.Length != 0) + outDir = outDir.Combine(string.Join(",", EMSCRIPTEN_FEATURES)); EnsureDirectoryExists(outDir); var so = SKIA_PATH.CombineWithFilePath($"out/wasm/libHarfBuzzSharp.a"); CopyFileToDirectory(so, outDir); From 8784f17bfad06fcc717e393fe818d730cc1453b7 Mon Sep 17 00:00:00 2001 From: Jerome Laban Date: Wed, 12 Oct 2022 09:30:02 -0400 Subject: [PATCH 3/9] chore: missing variables --- native/wasm/build.cake | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/native/wasm/build.cake b/native/wasm/build.cake index 91e0082a2f..cfa51de6de 100644 --- a/native/wasm/build.cake +++ b/native/wasm/build.cake @@ -63,7 +63,7 @@ Task("libSkiaSharp") $" '-s', 'WARN_UNALIGNED=1' " + // '-s', 'USE_WEBGL2=1' (experimental) $"] " + // SIMD support is based on https://github.com/google/skia/blob/1f193df9b393d50da39570dab77a0bb5d28ec8ef/modules/canvaskit/compile.sh#L57 - $"extra_cflags_cc=[ '-frtti' { (hasSimdEnabled ? ", '-msimd128'" : "") { (hasThreadingEnabled ? ", '-pthread'" : "") } } ] " + + $"extra_cflags_cc=[ '-frtti' { (hasSimdEnabled ? ", '-msimd128'" : "") } { (hasThreadingEnabled ? ", '-pthread'" : "") } ] " + COMPILERS + ADDITIONAL_GN_ARGS); @@ -107,12 +107,15 @@ Task("libHarfBuzzSharp") .WithCriteria(IsRunningOnLinux()) .Does(() => { + bool hasSimdEnabled = EMSCRIPTEN_FEATURES.Contains("simd"); + bool hasThreadingEnabled = EMSCRIPTEN_FEATURES.Contains("mt"); + GnNinja($"wasm", "HarfBuzzSharp", $"target_os='linux' " + $"target_cpu='wasm' " + $"is_static_skiasharp=true " + $"visibility_hidden=false " + - $"extra_cflags_cc=[ '-frtti' { (hasSimdEnabled ? ", '-msimd128'" : "") { (hasThreadingEnabled ? ", '-pthread'" : "") } } ] " + + $"extra_cflags_cc=[ '-frtti' { (hasSimdEnabled ? ", '-msimd128'" : "") } { (hasThreadingEnabled ? ", '-pthread'" : "") } ] " + COMPILERS + ADDITIONAL_GN_ARGS); From cfc5073306b8bed31d132b749cf52a5d5284f52d Mon Sep 17 00:00:00 2001 From: Jerome Laban Date: Wed, 12 Oct 2022 11:11:31 -0400 Subject: [PATCH 4/9] chore: Adjust globbing for harbuzz wasm --- binding/HarfBuzzSharp/nuget/build/wasm/HarfBuzzSharp.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/binding/HarfBuzzSharp/nuget/build/wasm/HarfBuzzSharp.props b/binding/HarfBuzzSharp/nuget/build/wasm/HarfBuzzSharp.props index 013ef410d2..7f90974e52 100644 --- a/binding/HarfBuzzSharp/nuget/build/wasm/HarfBuzzSharp.props +++ b/binding/HarfBuzzSharp/nuget/build/wasm/HarfBuzzSharp.props @@ -12,7 +12,7 @@ - + \ No newline at end of file From 7d7e47510ce35e853f5148b03d8aeb763fead55e Mon Sep 17 00:00:00 2001 From: Jerome Laban Date: Wed, 12 Oct 2022 13:19:17 -0400 Subject: [PATCH 5/9] chore: Adjust flags for C compiler --- native/wasm/build.cake | 3 +++ 1 file changed, 3 insertions(+) diff --git a/native/wasm/build.cake b/native/wasm/build.cake index cfa51de6de..e480f9a19a 100644 --- a/native/wasm/build.cake +++ b/native/wasm/build.cake @@ -61,6 +61,8 @@ Task("libSkiaSharp") $" '-DSKIA_C_DLL', '-DXML_POOR_ENTROPY', " + $" {(!hasSimdEnabled ? "'-DSKNX_NO_SIMD', " : "")} '-DSK_DISABLE_AAA', '-DGR_GL_CHECK_ALLOC_WITH_GET_ERROR=0', " + $" '-s', 'WARN_UNALIGNED=1' " + // '-s', 'USE_WEBGL2=1' (experimental) + $" { (hasSimdEnabled ? ", '-msimd128'" : "") } " + + $" { (hasThreadingEnabled ? ", '-pthread'" : "") } " + $"] " + // SIMD support is based on https://github.com/google/skia/blob/1f193df9b393d50da39570dab77a0bb5d28ec8ef/modules/canvaskit/compile.sh#L57 $"extra_cflags_cc=[ '-frtti' { (hasSimdEnabled ? ", '-msimd128'" : "") } { (hasThreadingEnabled ? ", '-pthread'" : "") } ] " + @@ -115,6 +117,7 @@ Task("libHarfBuzzSharp") $"target_cpu='wasm' " + $"is_static_skiasharp=true " + $"visibility_hidden=false " + + $"extra_cflags=[ { (hasSimdEnabled ? "'-msimd128', " : "") } { (hasThreadingEnabled ? "'-pthread'" : "") } ] " + $"extra_cflags_cc=[ '-frtti' { (hasSimdEnabled ? ", '-msimd128'" : "") } { (hasThreadingEnabled ? ", '-pthread'" : "") } ] " + COMPILERS + ADDITIONAL_GN_ARGS); From 4540e06cf91edfa09be900eaf79f9173b9d71e34 Mon Sep 17 00:00:00 2001 From: Jerome Laban Date: Wed, 12 Oct 2022 15:52:54 -0400 Subject: [PATCH 6/9] fix(SKSwapChainPanel): Invalid namespace for UWP target for Uno support --- .../SkiaSharp.Views.Uno.Wasm/SKSwapChainPanel.Wasm.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/SkiaSharp.Views.Uno/SkiaSharp.Views.Uno.Wasm/SKSwapChainPanel.Wasm.cs b/source/SkiaSharp.Views.Uno/SkiaSharp.Views.Uno.Wasm/SKSwapChainPanel.Wasm.cs index a454f0962c..ea5fda39ca 100644 --- a/source/SkiaSharp.Views.Uno/SkiaSharp.Views.Uno.Wasm/SKSwapChainPanel.Wasm.cs +++ b/source/SkiaSharp.Views.Uno/SkiaSharp.Views.Uno.Wasm/SKSwapChainPanel.Wasm.cs @@ -21,7 +21,7 @@ public partial class SKSwapChainPanel : FrameworkElement #if HAS_UNO_WINUI const string SKSwapChainPanelTypeFullName = "SkiaSharp.Views.Windows." + nameof(SKSwapChainPanel); #else - const string SKSwapChainPanelTypeFullName = "SkiaSharp.Views.UWP" + nameof(SKSwapChainPanel); + const string SKSwapChainPanelTypeFullName = "SkiaSharp.Views.UWP." + nameof(SKSwapChainPanel); #endif private const int ResourceCacheBytes = 256 * 1024 * 1024; // 256 MB From 1243a6621e99016103aa937e9f3a3a48f3bf660b Mon Sep 17 00:00:00 2001 From: Jerome Laban Date: Wed, 12 Oct 2022 16:05:21 -0400 Subject: [PATCH 7/9] fix(threading): Adjust support for software rendering using secure context --- .../SKXamlCanvas.Wasm.cs | 2 ++ .../WasmScripts/SkiaSharp.Views.Uno.Wasm.js | 33 +++++++++++++++++-- 2 files changed, 32 insertions(+), 3 deletions(-) diff --git a/source/SkiaSharp.Views.Uno/SkiaSharp.Views.Uno.Wasm/SKXamlCanvas.Wasm.cs b/source/SkiaSharp.Views.Uno/SkiaSharp.Views.Uno.Wasm/SKXamlCanvas.Wasm.cs index 7d596cf199..1141534c52 100644 --- a/source/SkiaSharp.Views.Uno/SkiaSharp.Views.Uno.Wasm/SKXamlCanvas.Wasm.cs +++ b/source/SkiaSharp.Views.Uno/SkiaSharp.Views.Uno.Wasm/SKXamlCanvas.Wasm.cs @@ -90,6 +90,8 @@ private SKImageInfo CreateBitmap(out SKSizeI unscaledSize, out float dpi) private void FreeBitmap() { + WebAssemblyRuntime.InvokeJS(SKXamlCanvasFullTypeName + $".clearCanvas(\"{this.GetHtmlId()}\");"); + if (pixels != null) { pixelsHandle.Free(); diff --git a/source/SkiaSharp.Views.Uno/SkiaSharp.Views.Uno.Wasm/WasmScripts/SkiaSharp.Views.Uno.Wasm.js b/source/SkiaSharp.Views.Uno/SkiaSharp.Views.Uno.Wasm/WasmScripts/SkiaSharp.Views.Uno.Wasm.js index de4ad9f683..1d10765f91 100644 --- a/source/SkiaSharp.Views.Uno/SkiaSharp.Views.Uno.Wasm/WasmScripts/SkiaSharp.Views.Uno.Wasm.js +++ b/source/SkiaSharp.Views.Uno/SkiaSharp.Views.Uno.Wasm/WasmScripts/SkiaSharp.Views.Uno.Wasm.js @@ -6,6 +6,8 @@ (function (UWP) { class SKXamlCanvas { + static buffers = []; + static invalidateCanvas(pData, canvasId, width, height) { var htmlCanvas = document.getElementById(canvasId); htmlCanvas.width = width; @@ -15,12 +17,37 @@ if (!ctx) return false; - var buffer = new Uint8ClampedArray(Module.HEAPU8.buffer, pData, width * height * 4); - var imageData = new ImageData(buffer, width, height); - ctx.putImageData(imageData, 0, 0); + var byteLength = width * height * 4; + + if (isSecureContext) { + // In a secure context (e.g. with threading enabled), creating a view + // from Module.HEAPU8.buffer is not supported, so we're making an + // explicit copy of the wasm memory. + var buffer = SKXamlCanvas.buffers[canvasId]; + + if (!buffer || buffer.length != byteLength) { + SKXamlCanvas.buffers[canvasId] = buffer = new Uint8ClampedArray(new ArrayBuffer(byteLength)); + } + + var slice = Module.HEAPU8.buffer.slice(pData, pData + byteLength); + buffer.set(new Uint8ClampedArray(slice), 0); + var imageData = new ImageData(buffer, width, height); + ctx.putImageData(imageData, 0, 0); + } + else { + var buffer = new Uint8ClampedArray(Module.HEAPU8.buffer, byteLength); + var imageData = new ImageData(buffer, width, height); + ctx.putImageData(imageData, 0, 0); + } return true; } + + static clearCanvas(canvasId) { + if (isSecureContext) { + delete SKXamlCanvas.buffers[canvasId]; + } + } } class SKSwapChainPanel { From deb67540d8719bdb18328ad2cac3e1b1d4df3242 Mon Sep 17 00:00:00 2001 From: Jerome Laban Date: Wed, 12 Oct 2022 22:17:11 -0400 Subject: [PATCH 8/9] ci: Bump dotnet version --- scripts/azure-pipelines-variables.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/azure-pipelines-variables.yml b/scripts/azure-pipelines-variables.yml index e9a92cc5ba..5f25da6d4c 100644 --- a/scripts/azure-pipelines-variables.yml +++ b/scripts/azure-pipelines-variables.yml @@ -15,7 +15,7 @@ variables: MONO_VERSION_LINUX: 'stable-focal/snapshots/6.12.0.182' XCODE_VERSION: 13.2.1 VISUAL_STUDIO_VERSION: '17/pre' - DOTNET_VERSION_PREVIEW: '6.0.401' + DOTNET_VERSION_PREVIEW: '6.0.402' DOTNET_WORKLOAD_SOURCE: 'https://maui.blob.core.windows.net/metadata/rollbacks/6.0.540.json' CONFIGURATION: 'Release' DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true From 5ace490f5449fb48aee1c0d9779476c764e4d01c Mon Sep 17 00:00:00 2001 From: Jerome Laban Date: Thu, 13 Oct 2022 09:08:04 -0400 Subject: [PATCH 9/9] fix: ensures GL and GLctx are available, and GLctx for threading. --- .../nuget/build/wasm/SkiaSharp.targets | 17 +++++++++++++++-- .../WasmScripts/SkiaSharp.Views.Uno.Wasm.js | 16 ++++++++++++---- 2 files changed, 27 insertions(+), 6 deletions(-) diff --git a/binding/SkiaSharp/nuget/build/wasm/SkiaSharp.targets b/binding/SkiaSharp/nuget/build/wasm/SkiaSharp.targets index b471538965..4583939e16 100644 --- a/binding/SkiaSharp/nuget/build/wasm/SkiaSharp.targets +++ b/binding/SkiaSharp/nuget/build/wasm/SkiaSharp.targets @@ -1,8 +1,21 @@ - + + + + - + + + + + + + + + + + \ No newline at end of file diff --git a/source/SkiaSharp.Views.Uno/SkiaSharp.Views.Uno.Wasm/WasmScripts/SkiaSharp.Views.Uno.Wasm.js b/source/SkiaSharp.Views.Uno/SkiaSharp.Views.Uno.Wasm/WasmScripts/SkiaSharp.Views.Uno.Wasm.js index 1d10765f91..cdf2c016a9 100644 --- a/source/SkiaSharp.Views.Uno/SkiaSharp.Views.Uno.Wasm/WasmScripts/SkiaSharp.Views.Uno.Wasm.js +++ b/source/SkiaSharp.Views.Uno/SkiaSharp.Views.Uno.Wasm/WasmScripts/SkiaSharp.Views.Uno.Wasm.js @@ -140,14 +140,22 @@ // make current GL.makeContextCurrent(ctx); + // Starting from .NET 7 the GLctx is defined in an inaccessible scope + // when the current GL context changes. We need to pick it up from the + // GL.currentContext instead. + let currentGLctx = GL.currentContext && GL.currentContext.GLctx; + + if (!currentGLctx) + throw `Failed to get current WebGL context`; + // read values this.canvas = canvas; var info = { ctx: ctx, - fbo: GLctx.getParameter(GLctx.FRAMEBUFFER_BINDING), - stencil: GLctx.getParameter(GLctx.STENCIL_BITS), - sample: 0, // TODO: GLctx.getParameter(GLctx.SAMPLES) - depth: GLctx.getParameter(GLctx.DEPTH_BITS), + fbo: currentGLctx.getParameter(currentGLctx.FRAMEBUFFER_BINDING), + stencil: currentGLctx.getParameter(currentGLctx.STENCIL_BITS), + sample: 0, // TODO: currentGLctx.getParameter(GLctx.SAMPLES) + depth: currentGLctx.getParameter(currentGLctx.DEPTH_BITS), }; // format as array for nicer parsing