Some of the colorspaces created are just references (#922)
* Some of the colorspaces created are just references - SRGB and SRGB Linear colorspaces are static and should never be disposed * Fix concurrent disposal and creation - In some cases, a new native object is created with the same memory location while the managed instances is still being disposed. In this case, we cannot remove the managed instance from the dictionary, since it is not the current object being disposed anymore. - SKColorSpace has some members that should not be disposed, since they are static on the native side. Just, there is no docs for this, so calling dispose will crash everything. - Added the logic to make sure that all static objects are created before anything, so we can get a handle on them and make sure they are static managed instances. * Make sure the objects are not collected when using spans
This commit is contained in:
Родитель
d5aa34a787
Коммит
c10c7394a2
|
@ -3,6 +3,7 @@
|
|||
|
||||
# Repository-specific files
|
||||
output/
|
||||
output-temp/
|
||||
tools/
|
||||
*.VC.db
|
||||
**/Resources/Resource.designer.cs
|
||||
|
|
|
@ -4,8 +4,8 @@ mdoc.targets release 5.7.4.9
|
|||
mdoc release 5.7.4.9
|
||||
harfbuzz release 2.5.3
|
||||
skia release m68
|
||||
xunit release 2.4.0
|
||||
xunit.runner.console release 2.4.0
|
||||
xunit release 2.4.1
|
||||
xunit.runner.console release 2.4.1
|
||||
Xamarin.Forms release 4.0.0.540366
|
||||
Tizen.NET release 4.0.0
|
||||
OpenTK release 3.0.1
|
||||
|
|
|
@ -392,7 +392,13 @@ namespace SkiaSharp
|
|||
// no-op due to unsupperted action
|
||||
}
|
||||
|
||||
public byte[] Bytes => GetPixelSpan ().ToArray ();
|
||||
public byte[] Bytes {
|
||||
get {
|
||||
var array = GetPixelSpan ().ToArray ();
|
||||
GC.KeepAlive (this);
|
||||
return array;
|
||||
}
|
||||
}
|
||||
|
||||
public SKColor[] Pixels {
|
||||
get {
|
||||
|
|
|
@ -178,6 +178,21 @@ namespace SkiaSharp
|
|||
|
||||
public class SKColorSpace : SKObject, ISKReferenceCounted
|
||||
{
|
||||
private static readonly SKColorSpace srgb;
|
||||
private static readonly SKColorSpace srgbLinear;
|
||||
|
||||
static SKColorSpace ()
|
||||
{
|
||||
srgb = new SKColorSpaceStatic (SkiaApi.sk_colorspace_new_srgb ());
|
||||
srgbLinear = new SKColorSpaceStatic (SkiaApi.sk_colorspace_new_srgb_linear ());
|
||||
}
|
||||
|
||||
internal static void EnsureStaticInstanceAreInitialized ()
|
||||
{
|
||||
// IMPORTANT: do not remove to ensure that the static instances
|
||||
// are initialized before any access is made to them
|
||||
}
|
||||
|
||||
[Preserve]
|
||||
internal SKColorSpace (IntPtr handle, bool owns)
|
||||
: base (handle, owns)
|
||||
|
@ -208,11 +223,9 @@ namespace SkiaSharp
|
|||
return SkiaApi.sk_colorspace_equals (left.Handle, right.Handle);
|
||||
}
|
||||
|
||||
public static SKColorSpace CreateSrgb () =>
|
||||
GetObject<SKColorSpace> (SkiaApi.sk_colorspace_new_srgb ());
|
||||
public static SKColorSpace CreateSrgb () => srgb;
|
||||
|
||||
public static SKColorSpace CreateSrgbLinear () =>
|
||||
GetObject<SKColorSpace> (SkiaApi.sk_colorspace_new_srgb_linear ());
|
||||
public static SKColorSpace CreateSrgbLinear () => srgbLinear;
|
||||
|
||||
public static SKColorSpace CreateIcc (IntPtr input, long length)
|
||||
{
|
||||
|
@ -299,5 +312,19 @@ namespace SkiaSharp
|
|||
|
||||
public SKMatrix44 FromXyzD50 () =>
|
||||
GetObject<SKMatrix44> (SkiaApi.sk_colorspace_as_from_xyzd50 (Handle), false);
|
||||
|
||||
private sealed class SKColorSpaceStatic : SKColorSpace
|
||||
{
|
||||
internal SKColorSpaceStatic (IntPtr x)
|
||||
: base (x, false)
|
||||
{
|
||||
IgnorePublicDispose = true;
|
||||
}
|
||||
|
||||
protected override void Dispose (bool disposing)
|
||||
{
|
||||
// do not dispose
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,8 +13,18 @@ namespace SkiaSharp
|
|||
// improvement in Copy performance.
|
||||
internal const int CopyBufferSize = 81920;
|
||||
|
||||
private static readonly Lazy<SKData> empty =
|
||||
new Lazy<SKData> (() => new SKDataStatic (SkiaApi.sk_data_new_empty ()));
|
||||
private static readonly Lazy<SKData> empty;
|
||||
|
||||
static SKData()
|
||||
{
|
||||
empty = new Lazy<SKData> (() => new SKDataStatic (SkiaApi.sk_data_new_empty ()));
|
||||
}
|
||||
|
||||
internal static void EnsureStaticInstanceAreInitialized ()
|
||||
{
|
||||
// IMPORTANT: do not remove to ensure that the static instances
|
||||
// are initialized before any access is made to them
|
||||
}
|
||||
|
||||
[Preserve]
|
||||
internal SKData (IntPtr x, bool owns)
|
||||
|
@ -174,7 +184,12 @@ namespace SkiaSharp
|
|||
return GetObject<SKData> (SkiaApi.sk_data_new_subset (Handle, (IntPtr) offset, (IntPtr) length));
|
||||
}
|
||||
|
||||
public byte[] ToArray () => AsSpan ().ToArray ();
|
||||
public byte[] ToArray ()
|
||||
{
|
||||
var array = AsSpan ().ToArray ();
|
||||
GC.KeepAlive (this);
|
||||
return array;
|
||||
}
|
||||
|
||||
public bool IsEmpty => Size == 0;
|
||||
|
||||
|
|
|
@ -7,8 +7,18 @@ namespace SkiaSharp
|
|||
{
|
||||
public class SKFontManager : SKObject, ISKReferenceCounted
|
||||
{
|
||||
private static readonly Lazy<SKFontManager> defaultManager =
|
||||
new Lazy<SKFontManager> (() => new SKFontManagerStatic (SkiaApi.sk_fontmgr_ref_default ()));
|
||||
private static readonly Lazy<SKFontManager> defaultManager;
|
||||
|
||||
static SKFontManager()
|
||||
{
|
||||
defaultManager = new Lazy<SKFontManager> (() => new SKFontManagerStatic (SkiaApi.sk_fontmgr_ref_default ()));
|
||||
}
|
||||
|
||||
internal static void EnsureStaticInstanceAreInitialized ()
|
||||
{
|
||||
// IMPORTANT: do not remove to ensure that the static instances
|
||||
// are initialized before any access is made to them
|
||||
}
|
||||
|
||||
[Preserve]
|
||||
internal SKFontManager (IntPtr handle, bool owns)
|
||||
|
|
|
@ -4,6 +4,7 @@ using System.Collections.Generic;
|
|||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading;
|
||||
|
||||
namespace SkiaSharp
|
||||
{
|
||||
|
@ -13,11 +14,22 @@ namespace SkiaSharp
|
|||
internal static readonly ConcurrentBag<Exception> exceptions = new ConcurrentBag<Exception> ();
|
||||
#endif
|
||||
|
||||
internal static readonly ConcurrentDictionary<Type, ConstructorInfo> constructors = new ConcurrentDictionary<Type, ConstructorInfo> ();
|
||||
internal static readonly ConcurrentDictionary<IntPtr, WeakReference> instances = new ConcurrentDictionary<IntPtr, WeakReference> ();
|
||||
internal static readonly ConcurrentDictionary<Type, ConstructorInfo> constructors;
|
||||
internal static readonly ConcurrentDictionary<IntPtr, WeakReference> instances;
|
||||
|
||||
internal readonly ConcurrentDictionary<IntPtr, SKObject> ownedObjects = new ConcurrentDictionary<IntPtr, SKObject> ();
|
||||
|
||||
static SKObject ()
|
||||
{
|
||||
constructors = new ConcurrentDictionary<Type, ConstructorInfo> ();
|
||||
instances = new ConcurrentDictionary<IntPtr, WeakReference> ();
|
||||
|
||||
SKColorSpace.EnsureStaticInstanceAreInitialized ();
|
||||
SKData.EnsureStaticInstanceAreInitialized ();
|
||||
SKFontManager.EnsureStaticInstanceAreInitialized ();
|
||||
SKTypeface.EnsureStaticInstanceAreInitialized ();
|
||||
}
|
||||
|
||||
[Preserve]
|
||||
internal SKObject (IntPtr handle, bool owns)
|
||||
: base (handle, owns)
|
||||
|
@ -108,7 +120,7 @@ namespace SkiaSharp
|
|||
|
||||
WeakReference Update (IntPtr key, WeakReference oldValue)
|
||||
{
|
||||
if (oldValue.Target is SKObject obj) {
|
||||
if (oldValue.Target is SKObject obj && !obj.IsDisposed) {
|
||||
#if THROW_OBJECT_EXCEPTIONS
|
||||
if (obj.OwnsHandle)
|
||||
throw new InvalidOperationException (
|
||||
|
@ -128,14 +140,28 @@ namespace SkiaSharp
|
|||
if (handle == IntPtr.Zero)
|
||||
return;
|
||||
|
||||
var removed = instances.TryRemove (handle, out _);
|
||||
var nonExistent = new WeakReference (null);
|
||||
var weak = instances.AddOrUpdate (handle, nonExistent, (ptr, old) => {
|
||||
if (old.Target is SKObject obj && !obj.IsDisposed)
|
||||
return old;
|
||||
return new WeakReference (null);
|
||||
});
|
||||
|
||||
#if THROW_OBJECT_EXCEPTIONS
|
||||
if (!removed) {
|
||||
var ex = new InvalidOperationException (
|
||||
InvalidOperationException ex = null;
|
||||
if (weak == nonExistent) {
|
||||
// the dummy instance was added instead of being removed
|
||||
ex = new InvalidOperationException (
|
||||
$"A managed object did not exist for the specified native object. " +
|
||||
$"H: {handle.ToString ("x")} Type: {instance.GetType ()}");
|
||||
ex.Data.Add ("Handle", handle);
|
||||
}
|
||||
if (weak.Target is SKObject o && o != instance && !instance.IsDisposed) {
|
||||
// there was a new living object there, but we are still alive
|
||||
ex = new InvalidOperationException (
|
||||
$"Trying to remove a different object with the same native handle. " +
|
||||
$"H: {handle.ToString ("x")} Type: ({o.GetType ()}, {instance.GetType ()})");
|
||||
}
|
||||
if (ex != null) {
|
||||
if (instance.fromFinalizer)
|
||||
exceptions.Add (ex);
|
||||
else
|
||||
|
@ -148,18 +174,26 @@ namespace SkiaSharp
|
|||
where TSkiaObject : SKObject
|
||||
{
|
||||
if (instances.TryGetValue (handle, out var weak)) {
|
||||
if (weak.Target is TSkiaObject match) {
|
||||
if (!match.IsDisposed) {
|
||||
instance = match;
|
||||
return true;
|
||||
}
|
||||
#if THROW_OBJECT_EXCEPTIONS
|
||||
if (weak.Target is object existing && !(weak.Target is TSkiaObject))
|
||||
} else if (weak.Target is SKObject obj) {
|
||||
if (!obj.IsDisposed) {
|
||||
throw new InvalidOperationException (
|
||||
$"A managed object exists for the handle, but is not the expected type. " +
|
||||
$"H: {handle.ToString ("x")} Type: ({obj.GetType ()}, {typeof (TSkiaObject)})");
|
||||
}
|
||||
} else if (weak.Target is object o) {
|
||||
throw new InvalidOperationException (
|
||||
$"A managed object exists for the handle, but is not the expected type. " +
|
||||
$"H: {handle.ToString ("x")} Type: ({existing.GetType ()}, {typeof (TSkiaObject)})");
|
||||
$"An unknown object exists for the handle when trying to fetch an instance. " +
|
||||
$"H: {handle.ToString ("x")} Type: ({o.GetType ()}, {typeof (TSkiaObject)})");
|
||||
#endif
|
||||
|
||||
if (weak.Target is TSkiaObject obj && obj.Handle != IntPtr.Zero) {
|
||||
instance = obj;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
instance = null;
|
||||
return false;
|
||||
}
|
||||
|
@ -225,7 +259,7 @@ namespace SkiaSharp
|
|||
internal bool fromFinalizer = false;
|
||||
#endif
|
||||
|
||||
private bool isDisposed = false;
|
||||
private int isDisposed = 0;
|
||||
|
||||
internal SKNativeObject (IntPtr handle)
|
||||
: this (handle, true)
|
||||
|
@ -253,6 +287,8 @@ namespace SkiaSharp
|
|||
|
||||
protected internal bool IgnorePublicDispose { get; protected set; }
|
||||
|
||||
protected internal bool IsDisposed => isDisposed == 1;
|
||||
|
||||
protected virtual void DisposeManaged ()
|
||||
{
|
||||
// dispose of any managed resources
|
||||
|
@ -265,9 +301,8 @@ namespace SkiaSharp
|
|||
|
||||
protected virtual void Dispose (bool disposing)
|
||||
{
|
||||
if (isDisposed)
|
||||
if (Interlocked.CompareExchange (ref isDisposed, 1, 0) != 0)
|
||||
return;
|
||||
isDisposed = true;
|
||||
|
||||
if (disposing) {
|
||||
DisposeManaged ();
|
||||
|
|
|
@ -15,8 +15,18 @@ namespace SkiaSharp
|
|||
|
||||
public class SKTypeface : SKObject, ISKReferenceCounted
|
||||
{
|
||||
private static readonly Lazy<SKTypeface> defaultTypeface =
|
||||
new Lazy<SKTypeface> (() => new SKTypefaceStatic (SkiaApi.sk_typeface_ref_default ()));
|
||||
private static readonly Lazy<SKTypeface> defaultTypeface;
|
||||
|
||||
static SKTypeface ()
|
||||
{
|
||||
defaultTypeface = new Lazy<SKTypeface> (() => new SKTypefaceStatic (SkiaApi.sk_typeface_ref_default ()));
|
||||
}
|
||||
|
||||
internal static void EnsureStaticInstanceAreInitialized ()
|
||||
{
|
||||
// IMPORTANT: do not remove to ensure that the static instances
|
||||
// are initialized before any access is made to them
|
||||
}
|
||||
|
||||
[Preserve]
|
||||
internal SKTypeface (IntPtr handle, bool owns)
|
||||
|
|
|
@ -69,9 +69,21 @@ namespace HarfBuzzSharp
|
|||
set => HarfBuzzApi.hb_buffer_set_unicode_funcs (Handle, value.Handle);
|
||||
}
|
||||
|
||||
public GlyphInfo[] GlyphInfos => GetGlyphInfoSpan ().ToArray ();
|
||||
public GlyphInfo[] GlyphInfos {
|
||||
get {
|
||||
var array = GetGlyphInfoSpan ().ToArray ();
|
||||
GC.KeepAlive (this);
|
||||
return array;
|
||||
}
|
||||
}
|
||||
|
||||
public GlyphPosition[] GlyphPositions => GetGlyphPositionSpan ().ToArray ();
|
||||
public GlyphPosition[] GlyphPositions {
|
||||
get {
|
||||
var array = GetGlyphPositionSpan ().ToArray ();
|
||||
GC.KeepAlive (this);
|
||||
return array;
|
||||
}
|
||||
}
|
||||
|
||||
public void Add (uint codepoint, uint cluster)
|
||||
{
|
||||
|
|
15
build.cake
15
build.cake
|
@ -6,7 +6,7 @@
|
|||
#addin nuget:?package=Xamarin.Nuget.Validator&version=1.1.1
|
||||
|
||||
#tool nuget:?package=mdoc&version=5.7.4.9
|
||||
#tool nuget:?package=xunit.runner.console&version=2.4.0
|
||||
#tool nuget:?package=xunit.runner.console&version=2.4.1
|
||||
#tool nuget:?package=vswhere&version=2.5.2
|
||||
|
||||
using System.Linq;
|
||||
|
@ -24,7 +24,7 @@ using NuGet.Versioning;
|
|||
#load "cake/Utils.cake"
|
||||
|
||||
var TARGET = Argument ("t", Argument ("target", Argument ("Target", "Default")));
|
||||
var VERBOSITY = (Verbosity) Enum.Parse (typeof(Verbosity), Argument ("v", Argument ("verbosity", Argument ("Verbosity", "Normal"))), true);
|
||||
var VERBOSITY = Argument ("v", Argument ("verbosity", Argument ("Verbosity", Verbosity.Normal)));
|
||||
var SKIP_EXTERNALS = Argument ("skipexternals", Argument ("SkipExternals", "")).ToLower ().Split (',');
|
||||
var PACK_ALL_PLATFORMS = Argument ("packall", Argument ("PackAll", Argument ("PackAllPlatforms", TARGET.ToLower() == "ci" || TARGET.ToLower() == "nuget-only")));
|
||||
var PRINT_ALL_ENV_VARS = Argument ("printAllEnvVars", false);
|
||||
|
@ -137,16 +137,6 @@ Task ("tests-only")
|
|||
.Does (() =>
|
||||
{
|
||||
var RunDesktopTest = new Action<string> (arch => {
|
||||
var platform = "";
|
||||
if (IsRunningOnWindows ()) {
|
||||
platform = "windows";
|
||||
} else if (IsRunningOnMac ()) {
|
||||
platform = "mac";
|
||||
} else if (IsRunningOnLinux ()) {
|
||||
platform = "linux";
|
||||
}
|
||||
|
||||
EnsureDirectoryExists ($"./output/tests/{platform}/{arch}");
|
||||
RunMSBuild ("./tests/SkiaSharp.Desktop.Tests/SkiaSharp.Desktop.Tests.sln", platform: arch == "AnyCPU" ? "Any CPU" : arch);
|
||||
RunTests ($"./tests/SkiaSharp.Desktop.Tests/bin/{arch}/{CONFIGURATION}/SkiaSharp.Tests.dll", arch == "x86");
|
||||
});
|
||||
|
@ -165,7 +155,6 @@ Task ("tests-only")
|
|||
}
|
||||
|
||||
// .NET Core
|
||||
EnsureDirectoryExists ("./output/tests/netcore");
|
||||
RunMSBuild ("./tests/SkiaSharp.NetCore.Tests/SkiaSharp.NetCore.Tests.sln");
|
||||
RunNetCoreTests ("./tests/SkiaSharp.NetCore.Tests/SkiaSharp.NetCore.Tests.csproj");
|
||||
});
|
||||
|
|
|
@ -71,6 +71,8 @@ void RunTests (FilePath testAssembly, bool is32)
|
|||
ReportName = "TestResults",
|
||||
XmlReport = true,
|
||||
UseX86 = is32,
|
||||
NoAppDomain = true,
|
||||
Parallelism = ParallelismOption.All,
|
||||
OutputDirectory = dir,
|
||||
WorkingDirectory = dir,
|
||||
ArgumentCustomization = args => args.Append ("-verbose"),
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"msbuild-sdks": {
|
||||
"MSBuild.Sdk.Extras": "1.6.65"
|
||||
"sdk": {
|
||||
"version": "2.2.108.1"
|
||||
}
|
||||
}
|
Двоичные данные
samples/AppStoreCertificates/SkiaSharpSample_TemporaryKey.pfx
Двоичные данные
samples/AppStoreCertificates/SkiaSharpSample_TemporaryKey.pfx
Двоичный файл не отображается.
|
@ -17,7 +17,7 @@
|
|||
<FileAlignment>512</FileAlignment>
|
||||
<ProjectTypeGuids>{A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
|
||||
<PackageCertificateKeyFile>..\..\..\AppStoreCertificates\SkiaSharpSample_TemporaryKey.pfx</PackageCertificateKeyFile>
|
||||
<PackageCertificateThumbprint>8DD3DBEC438E69AF67465BF733A17DBA8397D719</PackageCertificateThumbprint>
|
||||
<PackageCertificateThumbprint>D3578B78019FED6AEE572B23C1723D44951E0BF9</PackageCertificateThumbprint>
|
||||
<RestoreProjectStyle>PackageReference</RestoreProjectStyle>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
<FileAlignment>512</FileAlignment>
|
||||
<ProjectTypeGuids>{A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
|
||||
<PackageCertificateKeyFile>..\..\..\AppStoreCertificates\SkiaSharpSample_TemporaryKey.pfx</PackageCertificateKeyFile>
|
||||
<PackageCertificateThumbprint>8DD3DBEC438E69AF67465BF733A17DBA8397D719</PackageCertificateThumbprint>
|
||||
<PackageCertificateThumbprint>D3578B78019FED6AEE572B23C1723D44951E0BF9</PackageCertificateThumbprint>
|
||||
<RestoreProjectStyle>PackageReference</RestoreProjectStyle>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|ARM'">
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
<FileAlignment>512</FileAlignment>
|
||||
<ProjectTypeGuids>{A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
|
||||
<PackageCertificateKeyFile>..\..\..\AppStoreCertificates\SkiaSharpSample_TemporaryKey.pfx</PackageCertificateKeyFile>
|
||||
<PackageCertificateThumbprint>8DD3DBEC438E69AF67465BF733A17DBA8397D719</PackageCertificateThumbprint>
|
||||
<PackageCertificateThumbprint>D3578B78019FED6AEE572B23C1723D44951E0BF9</PackageCertificateThumbprint>
|
||||
<RestoreProjectStyle>PackageReference</RestoreProjectStyle>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
<FileAlignment>512</FileAlignment>
|
||||
<ProjectTypeGuids>{A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
|
||||
<PackageCertificateKeyFile>..\..\..\AppStoreCertificates\SkiaSharpSample_TemporaryKey.pfx</PackageCertificateKeyFile>
|
||||
<PackageCertificateThumbprint>8DD3DBEC438E69AF67465BF733A17DBA8397D719</PackageCertificateThumbprint>
|
||||
<PackageCertificateThumbprint>D3578B78019FED6AEE572B23C1723D44951E0BF9</PackageCertificateThumbprint>
|
||||
<RestoreProjectStyle>PackageReference</RestoreProjectStyle>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|ARM'">
|
||||
|
|
|
@ -2,6 +2,10 @@ trigger:
|
|||
- master
|
||||
- development
|
||||
|
||||
pr:
|
||||
- master
|
||||
- development
|
||||
|
||||
variables:
|
||||
FEATURE_NAME_PREFIX: 'feature/'
|
||||
VERBOSITY: normal
|
||||
|
@ -11,14 +15,20 @@ variables:
|
|||
FEATURE_NAME: ''
|
||||
PREVIEW_LABEL: 'rc'
|
||||
NATIVE_LINUX_PACKAGES: curl mono-complete msbuild python git libfontconfig1-dev clang-3.8 make
|
||||
TIZEN_LINUX_PACKAGES: libxcb-xfixes0 libxcb-render-util0 libwebkitgtk-1.0-0 libxcb-image0 acl libsdl1.2debian libv4l-0 libxcb-randr0 libxcb-shape0 libxcb-icccm4 libsm6 gettext rpm2cpio cpio bridge-utils openvpn
|
||||
MANAGED_LINUX_PACKAGES: ttf-ancient-fonts
|
||||
MONO_VERSION: 5_18_1
|
||||
XCODE_VERSION: 10.2.1
|
||||
# CONFIGURATION: 'Release'
|
||||
VM_IMAGE_WINDOWS: vs2017-win2016
|
||||
VM_IMAGE_MAC: macos-10.14
|
||||
VM_IMAGE_LINUX: ubuntu-16.04
|
||||
TIZEN_LINUX_PACKAGES: mono-complete msbuild libxcb-xfixes0 libxcb-render-util0 libwebkitgtk-1.0-0 libxcb-image0 acl libsdl1.2debian libv4l-0 libxcb-randr0 libxcb-shape0 libxcb-icccm4 libsm6 gettext rpm2cpio cpio bridge-utils openvpn
|
||||
MANAGED_LINUX_PACKAGES: mono-complete msbuild ttf-ancient-fonts
|
||||
MONO_VERSION_MACOS: 5_18_3
|
||||
MONO_VERSION_LINUX: stable-xenial/snapshots/5.20.1.34
|
||||
XCODE_VERSION: 10.3
|
||||
DOTNET_VERSION: 2.2.108
|
||||
CONFIGURATION: 'Release'
|
||||
VM_IMAGE_WINDOWS: Hosted VS2017
|
||||
VM_IMAGE_MAC: Hosted macOS
|
||||
VM_IMAGE_LINUX: Hosted Ubuntu 1604
|
||||
DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true
|
||||
|
||||
# # To speed up builds when debugging DevOps
|
||||
# DOWNLOAD_EXTERNALS: ''
|
||||
|
||||
resources:
|
||||
repositories:
|
||||
|
@ -38,12 +48,14 @@ stages:
|
|||
displayName: Build Native Android (Windows)
|
||||
vmImage: $(VM_IMAGE_WINDOWS)
|
||||
target: externals-android
|
||||
buildExternals: $(DOWNLOAD_EXTERNALS)
|
||||
- template: azure-templates-bootstrapper.yml # Build Native Tizen (Windows)
|
||||
parameters:
|
||||
name: native_tizen_windows
|
||||
displayName: Build Native Tizen (Windows)
|
||||
vmImage: $(VM_IMAGE_WINDOWS)
|
||||
target: externals-tizen
|
||||
buildExternals: $(DOWNLOAD_EXTERNALS)
|
||||
condition: false # TODO: TIZEN INSTALL BUGS
|
||||
- template: azure-templates-bootstrapper.yml # Build Native UWP (Windows)
|
||||
parameters:
|
||||
|
@ -51,12 +63,14 @@ stages:
|
|||
displayName: Build Native UWP (Windows)
|
||||
vmImage: $(VM_IMAGE_WINDOWS)
|
||||
target: externals-uwp
|
||||
buildExternals: $(DOWNLOAD_EXTERNALS)
|
||||
- template: azure-templates-bootstrapper.yml # Build Native Win32 (Windows)
|
||||
parameters:
|
||||
name: native_win32_windows
|
||||
displayName: Build Native Win32 (Windows)
|
||||
vmImage: $(VM_IMAGE_WINDOWS)
|
||||
target: externals-windows
|
||||
buildExternals: $(DOWNLOAD_EXTERNALS)
|
||||
# NATIVE JOBS - MAC
|
||||
- template: azure-templates-bootstrapper.yml # Build Native Android (macOS)
|
||||
parameters:
|
||||
|
@ -64,24 +78,28 @@ stages:
|
|||
displayName: Build Native Android (macOS)
|
||||
vmImage: $(VM_IMAGE_MAC)
|
||||
target: externals-android
|
||||
buildExternals: $(DOWNLOAD_EXTERNALS)
|
||||
- template: azure-templates-bootstrapper.yml # Build Native iOS (macOS)
|
||||
parameters:
|
||||
name: native_ios_macos
|
||||
displayName: Build Native iOS (macOS)
|
||||
vmImage: $(VM_IMAGE_MAC)
|
||||
target: externals-ios
|
||||
buildExternals: $(DOWNLOAD_EXTERNALS)
|
||||
- template: azure-templates-bootstrapper.yml # Build Native macOS (macOS)
|
||||
parameters:
|
||||
name: native_macos_macos
|
||||
displayName: Build Native macOS (macOS)
|
||||
vmImage: $(VM_IMAGE_MAC)
|
||||
target: externals-macos
|
||||
buildExternals: $(DOWNLOAD_EXTERNALS)
|
||||
- template: azure-templates-bootstrapper.yml # Build Native Tizen (macOS)
|
||||
parameters:
|
||||
name: native_tizen_macos
|
||||
displayName: Build Native Tizen (macOS)
|
||||
vmImage: $(VM_IMAGE_MAC)
|
||||
target: externals-tizen
|
||||
buildExternals: $(DOWNLOAD_EXTERNALS)
|
||||
condition: false # TODO: TIZEN INSTALL BUGS
|
||||
- template: azure-templates-bootstrapper.yml # Build Native tvOS (macOS)
|
||||
parameters:
|
||||
|
@ -89,25 +107,31 @@ stages:
|
|||
displayName: Build Native tvOS (macOS)
|
||||
vmImage: $(VM_IMAGE_MAC)
|
||||
target: externals-tvos
|
||||
buildExternals: $(DOWNLOAD_EXTERNALS)
|
||||
- template: azure-templates-bootstrapper.yml # Build Native watchOS (macOS)
|
||||
parameters:
|
||||
name: native_watchos_macos
|
||||
displayName: Build Native watchOS (macOS)
|
||||
vmImage: $(VM_IMAGE_MAC)
|
||||
target: externals-watchos
|
||||
buildExternals: $(DOWNLOAD_EXTERNALS)
|
||||
# NATIVE JOBS - LINUX
|
||||
- template: azure-templates-native-linux.yml # Build Native Linux (Linux)
|
||||
parameters:
|
||||
name: native_linux_linux
|
||||
displayName: Build Native Linux (Linux)
|
||||
vmImage: $(VM_IMAGE_LINUX)
|
||||
packages: $(NATIVE_LINUX_PACKAGES)
|
||||
target: externals-linux
|
||||
buildExternals: $(DOWNLOAD_EXTERNALS)
|
||||
- template: azure-templates-native-linux.yml # Build Native Linux [No Dependencies] (Linux)
|
||||
parameters:
|
||||
name: native_linux_nodependencies_linux
|
||||
displayName: Build Native Linux [No Dependencies] (Linux)
|
||||
vmImage: $(VM_IMAGE_LINUX)
|
||||
packages: $(NATIVE_LINUX_PACKAGES)
|
||||
target: externals-linux
|
||||
buildExternals: $(DOWNLOAD_EXTERNALS)
|
||||
additionalArgs: --additionalGnArgs="skia_use_fontconfig=false"
|
||||
- template: azure-templates-bootstrapper.yml # Build Native Tizen (Linux)
|
||||
parameters:
|
||||
|
@ -116,6 +140,7 @@ stages:
|
|||
vmImage: $(VM_IMAGE_LINUX)
|
||||
packages: $(TIZEN_LINUX_PACKAGES)
|
||||
target: externals-tizen
|
||||
buildExternals: $(DOWNLOAD_EXTERNALS)
|
||||
|
||||
- stage: managed
|
||||
displayName: Build Managed
|
||||
|
@ -238,7 +263,7 @@ stages:
|
|||
- package_nodependencies_windows
|
||||
- package_windows
|
||||
pool:
|
||||
vmImage: $(VM_IMAGE_LINUX)
|
||||
name: $(VM_IMAGE_LINUX)
|
||||
steps:
|
||||
- task: DownloadBuildArtifacts@0
|
||||
displayName: Download the nuget-nodependencies artifacts
|
||||
|
@ -270,23 +295,9 @@ stages:
|
|||
dependsOn: package
|
||||
condition: eq(variables['System.TeamProject'], 'devdiv')
|
||||
jobs:
|
||||
- job: signing # Sign NuGets
|
||||
displayName: Sign NuGets
|
||||
pool:
|
||||
name: VSEng-XamarinCustom
|
||||
demands:
|
||||
- corpnet
|
||||
condition: and(succeeded(), or(startsWith(variables['Build.SourceBranch'], 'refs/tags/'), eq(variables['Build.SourceBranch'], 'refs/heads/master')))
|
||||
steps:
|
||||
- checkout: none
|
||||
- template: sign-artifacts.yml@xamarin-templates
|
||||
parameters:
|
||||
targetFolder: '$(Build.ArtifactStagingDirectory)/signed'
|
||||
- task: PublishBuildArtifacts@1
|
||||
displayName: Publish the nuget-signed artifacts
|
||||
inputs:
|
||||
artifactName: nuget-signed
|
||||
pathToPublish: '$(Build.ArtifactStagingDirectory)/signed'
|
||||
- template: sign-artifacts/jobs/v1.yml@xamarin-templates
|
||||
parameters:
|
||||
additionalConditions: eq(variables['Build.SourceBranch'], 'refs/heads/master')
|
||||
|
||||
- stage: tests
|
||||
displayName: Run Tests
|
||||
|
@ -305,11 +316,19 @@ stages:
|
|||
- native_win32_windows
|
||||
postBuildSteps:
|
||||
- task: PublishTestResults@2
|
||||
displayName: Publish the test results
|
||||
displayName: Publish the .NET Framework test results
|
||||
condition: always()
|
||||
inputs:
|
||||
testResultsFormat: xUnit
|
||||
testResultsFiles: 'tests/**/TestResults.xml'
|
||||
testResultsFiles: 'tests/SkiaSharp.Desktop.Tests/**/TestResults.xml'
|
||||
testRunTitle: 'Windows .NET Framework Tests'
|
||||
- task: PublishTestResults@2
|
||||
displayName: Publish the .NET Core test results
|
||||
condition: always()
|
||||
inputs:
|
||||
testResultsFormat: xUnit
|
||||
testResultsFiles: 'tests/SkiaSharp.NetCore.Tests/**/TestResults.xml'
|
||||
testRunTitle: 'Windows .NET Core Tests'
|
||||
- template: azure-templates-bootstrapper.yml # Tests (macOS)
|
||||
parameters:
|
||||
name: tests_macos
|
||||
|
@ -323,11 +342,19 @@ stages:
|
|||
- native_macos_macos
|
||||
postBuildSteps:
|
||||
- task: PublishTestResults@2
|
||||
displayName: Publish the test results
|
||||
displayName: Publish the Mono test results
|
||||
condition: always()
|
||||
inputs:
|
||||
testResultsFormat: xUnit
|
||||
testResultsFiles: 'tests/**/TestResults.xml'
|
||||
testResultsFiles: 'tests/SkiaSharp.Desktop.Tests/**/TestResults.xml'
|
||||
testRunTitle: 'macOS Mono Tests'
|
||||
- task: PublishTestResults@2
|
||||
displayName: Publish the .NET Core test results
|
||||
condition: always()
|
||||
inputs:
|
||||
testResultsFormat: xUnit
|
||||
testResultsFiles: 'tests/SkiaSharp.NetCore.Tests/**/TestResults.xml'
|
||||
testRunTitle: 'macOS .NET Core Tests'
|
||||
- template: azure-templates-bootstrapper.yml # Tests (Linux)
|
||||
parameters:
|
||||
name: tests_linux
|
||||
|
@ -342,11 +369,19 @@ stages:
|
|||
- native_linux_linux
|
||||
postBuildSteps:
|
||||
- task: PublishTestResults@2
|
||||
displayName: Publish the test results
|
||||
displayName: Publish the Mono test results
|
||||
condition: always()
|
||||
inputs:
|
||||
testResultsFormat: xUnit
|
||||
testResultsFiles: 'tests/**/TestResults.xml'
|
||||
testResultsFiles: 'tests/SkiaSharp.Desktop.Tests/**/TestResults.xml'
|
||||
testRunTitle: 'Linux Mono Tests'
|
||||
- task: PublishTestResults@2
|
||||
displayName: Publish the .NET Core test results
|
||||
condition: always()
|
||||
inputs:
|
||||
testResultsFormat: xUnit
|
||||
testResultsFiles: 'tests/SkiaSharp.NetCore.Tests/**/TestResults.xml'
|
||||
testRunTitle: 'Linux .NET Core Tests'
|
||||
- template: azure-templates-bootstrapper.yml # Tests [No Dependencies] (Linux)
|
||||
parameters:
|
||||
name: tests_nodependencies_linux
|
||||
|
@ -361,11 +396,19 @@ stages:
|
|||
- native_linux_nodependencies_linux
|
||||
postBuildSteps:
|
||||
- task: PublishTestResults@2
|
||||
displayName: Publish the test results
|
||||
displayName: Publish the Mono test results
|
||||
condition: always()
|
||||
inputs:
|
||||
testResultsFormat: xUnit
|
||||
testResultsFiles: 'tests/**/TestResults.xml'
|
||||
testResultsFiles: 'tests/SkiaSharp.Desktop.Tests/**/TestResults.xml'
|
||||
testRunTitle: 'Linux [No Dependencies] Mono Tests'
|
||||
- task: PublishTestResults@2
|
||||
displayName: Publish the .NET Core test results
|
||||
condition: always()
|
||||
inputs:
|
||||
testResultsFormat: xUnit
|
||||
testResultsFiles: 'tests/SkiaSharp.NetCore.Tests/**/TestResults.xml'
|
||||
testRunTitle: 'Linux [No Dependencies] .NET Core Tests'
|
||||
|
||||
- stage: samples
|
||||
displayName: Build Samples
|
||||
|
|
|
@ -1,25 +1,38 @@
|
|||
parameters:
|
||||
name: '' # in the form type_platform_host
|
||||
displayName: '' # the human name
|
||||
vmImage: '' # the VM image
|
||||
packages: '' # any additional packages
|
||||
target: '' # the bootstrapper target
|
||||
dependsOn: [] # the dependiencies
|
||||
requiredArtifacts: [] # the artifacts that this build needs to download
|
||||
demands: [] # the demands
|
||||
preBuildSteps: [] # any steps to run before the build
|
||||
postBuildSteps: [] # any additional steps to run after the build
|
||||
additionalArgs: '' # any additional arguments to pass to the bootstrapper
|
||||
retryCount: 1 # the number of times to retry the bootstrapper
|
||||
condition: succeeded() # whether or not to run this template
|
||||
shouldPublish: true # whether or not to publish the artifacts
|
||||
name: '' # in the form type_platform_host
|
||||
displayName: '' # the human name
|
||||
vmImage: '' # the VM image
|
||||
packages: '' # any additional packages
|
||||
target: '' # the bootstrapper target
|
||||
dependsOn: [] # the dependiencies
|
||||
requiredArtifacts: [] # the artifacts that this build needs to download
|
||||
demands: [] # the demands
|
||||
preBuildSteps: [] # any steps to run before the build
|
||||
postBuildSteps: [] # any additional steps to run after the build
|
||||
additionalArgs: '' # any additional arguments to pass to the bootstrapper
|
||||
retryCount: 1 # the number of times to retry the bootstrapper
|
||||
condition: succeeded() # whether or not to run this template
|
||||
shouldPublish: true # whether or not to publish the artifacts
|
||||
configuration: '$(CONFIGURATION)' # the build configuration
|
||||
buildExternals: '$(DOWNLOAD_EXTERNALS)' # the build number to download externals from
|
||||
verbosity: '$(VERBOSITY)' # the level of verbosity to use when building
|
||||
|
||||
jobs:
|
||||
# - ${{ if and(parameters.buildExternals, startsWith(parameters.name, 'native_')) }}:
|
||||
# - template: azure-templates-download.yml
|
||||
# parameters:
|
||||
# name: ${{ parameters.name }}
|
||||
# displayName: ${{ parameters.displayName }}
|
||||
# vmImage: ${{ parameters.vmImage }}
|
||||
# condition: ${{ parameters.condition }}
|
||||
# buildExternals: ${{ parameters.buildExternals }}
|
||||
|
||||
# - ${{ if or(not(parameters.buildExternals), not(startsWith(parameters.name, 'native_'))) }}:
|
||||
- job: ${{ parameters.name }}
|
||||
displayName: ${{ parameters.displayName }}
|
||||
timeoutInMinutes: 120
|
||||
pool:
|
||||
vmImage: ${{ parameters.vmImage }}
|
||||
name: ${{ parameters.vmImage }}
|
||||
demands: ${{ parameters.demands }}
|
||||
dependsOn: ${{ parameters.dependsOn }}
|
||||
condition: ${{ parameters.condition }}
|
||||
|
@ -35,6 +48,11 @@ jobs:
|
|||
# install any packages on linux
|
||||
- ${{ if endsWith(parameters.name, '_linux') }}:
|
||||
- bash: |
|
||||
sudo apt remove -y mono-complete msbuild
|
||||
sudo apt autoremove -y
|
||||
sudo rm /etc/mono/config
|
||||
sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 3FA7E0328081BFF6A14DA29AA6A19B38D3D831EF
|
||||
echo "deb https://download.mono-project.com/repo/ubuntu $(MONO_VERSION_LINUX) main" | sudo tee /etc/apt/sources.list.d/mono-official-stable.list
|
||||
sudo apt update
|
||||
sudo apt install -y ${{ parameters.packages }}
|
||||
displayName: Install any package dependencies
|
||||
|
@ -56,9 +74,17 @@ jobs:
|
|||
- ${{ if contains(parameters.name, '_android_') }}:
|
||||
- powershell: .\scripts\install-android-ndk.ps1
|
||||
displayName: Install the Android NDK
|
||||
# install extra bits for the manged builds
|
||||
- ${{ if not(startsWith(parameters.name, 'native_')) }}:
|
||||
- task: UseDotNet@2
|
||||
inputs:
|
||||
packageType: 'sdk'
|
||||
version: $(DOTNET_VERSION)
|
||||
performMultiLevelLookup: true
|
||||
displayName: Install the correct version of .NET Core
|
||||
# switch to the correct mono version on mac
|
||||
- ${{ if endsWith(parameters.name, '_macos') }}:
|
||||
- bash: sudo $AGENT_HOMEDIRECTORY/scripts/select-xamarin-sdk.sh $(MONO_VERSION)
|
||||
- bash: sudo $(Agent.HomeDirectory)/scripts/select-xamarin-sdk.sh $(MONO_VERSION_MACOS)
|
||||
displayName: Switch to the latest Xamarin SDK
|
||||
- bash: echo '##vso[task.setvariable variable=MD_APPLE_SDK_ROOT;]'/Applications/Xcode_$(XCODE_VERSION).app;sudo xcode-select --switch /Applications/Xcode_$(XCODE_VERSION).app/Contents/Developer
|
||||
displayName: Switch to the latest Xcode
|
||||
|
@ -78,10 +104,14 @@ jobs:
|
|||
- ${{ parameters.preBuildSteps }}
|
||||
# build
|
||||
- ${{ if endsWith(parameters.name, '_windows') }}:
|
||||
- powershell: .\scripts\retry-command.ps1 -RetryCount ${{ parameters.retryCount }} { .\bootstrapper.ps1 -t ${{ parameters.target }} -v $env:VERBOSITY -c ${{ coalesce(variables.CONFIGURATION, 'Release') }} ${{ parameters.additionalArgs }} }
|
||||
- powershell: .\scripts\retry-command.ps1 -RetryCount ${{ parameters.retryCount }} { .\bootstrapper.ps1 -t ${{ parameters.target }} -v ${{ parameters.verbosity }} -c ${{ coalesce(parameters.configuration, 'Release') }} ${{ parameters.additionalArgs }} }
|
||||
env:
|
||||
JavaSdkDirectory: $(JAVA_HOME)
|
||||
displayName: Run the bootstrapper for ${{ parameters.target }}
|
||||
- ${{ if not(endsWith(parameters.name, '_windows')) }}:
|
||||
- bash: ./scripts/retry-command.sh ${{ parameters.retryCount }} ./bootstrapper.sh -t ${{ parameters.target }} -v $VERBOSITY -c ${{ coalesce(variables.CONFIGURATION, 'Release') }} ${{ parameters.additionalArgs }}
|
||||
- bash: ./scripts/retry-command.sh ${{ parameters.retryCount }} ./bootstrapper.sh -t ${{ parameters.target }} -v ${{ parameters.verbosity }} -c ${{ coalesce(parameters.configuration, 'Release') }} ${{ parameters.additionalArgs }}
|
||||
env:
|
||||
JavaSdkDirectory: $(JAVA_HOME)
|
||||
displayName: Run the bootstrapper for ${{ parameters.target }}
|
||||
# post-build steps
|
||||
- ${{ parameters.postBuildSteps }}
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
parameters:
|
||||
name: '' # in the form type_platform_host
|
||||
displayName: '' # the human name
|
||||
vmImage: '' # the VM image
|
||||
condition: succeeded() # whether or not to run this template
|
||||
buildExternals: '$(DOWNLOAD_EXTERNALS)' # the build number to download externals from
|
||||
|
||||
jobs:
|
||||
- job: ${{ parameters.name }}
|
||||
displayName: ${{ parameters.displayName }}
|
||||
pool:
|
||||
name: ${{ parameters.vmImage }}
|
||||
condition: ${{ parameters.condition }}
|
||||
steps:
|
||||
- checkout: none
|
||||
- task: DownloadBuildArtifacts@0
|
||||
displayName: Download the pre-built ${{ parameters.name }} artifacts
|
||||
inputs:
|
||||
buildType: 'specific'
|
||||
project: '$(System.TeamProjectId)'
|
||||
pipeline: '$(System.DefinitionId)'
|
||||
buildVersionToDownload: 'specific'
|
||||
buildId: '${{ parameters.buildExternals }}'
|
||||
downloadType: 'single'
|
||||
artifactName: ${{ parameters.name }}
|
||||
downloadPath: 'download-temp'
|
||||
- powershell: |
|
||||
New-Item '.\output\' -Type Directory -Force | Out-Null
|
||||
Get-ChildItem '.\download-temp\${{ parameters.name }}\' | Copy-Item -Destination '.\output\' -Recurse -Force
|
||||
Remove-Item '.\download-temp\${{ parameters.name }}\' -Recurse -Force
|
||||
displayName: Move the ${{ parameters.name }} artifacts to the output directory
|
||||
- task: PublishBuildArtifacts@1
|
||||
displayName: Publish the ${{ parameters.name }} artifacts
|
||||
inputs:
|
||||
artifactName: ${{ parameters.name }}
|
||||
pathToPublish: 'output'
|
|
@ -1,19 +1,32 @@
|
|||
parameters:
|
||||
name: '' # in the form type_platform_host
|
||||
displayName: '' # the human name
|
||||
packages: '' # any additional packages
|
||||
target: '' # the bootstrapper target
|
||||
preBuildSteps: [] # any steps to run before the build
|
||||
postBuildSteps: [] # any additional steps to run after the build
|
||||
additionalArgs: '' # any additional arguments to pass to the bootstrapper
|
||||
retryCount: 1 # the number of times to retry the bootstrapper
|
||||
name: '' # in the form type_platform_host
|
||||
displayName: '' # the human name
|
||||
vmImage: '' # the VM image
|
||||
packages: '' # any additional packages
|
||||
target: '' # the bootstrapper target
|
||||
preBuildSteps: [] # any steps to run before the build
|
||||
postBuildSteps: [] # any additional steps to run after the build
|
||||
additionalArgs: '' # any additional arguments to pass to the bootstrapper
|
||||
retryCount: 1 # the number of times to retry the bootstrapper
|
||||
configuration: '$(CONFIGURATION)' # the build configuration
|
||||
buildExternals: '$(DOWNLOAD_EXTERNALS)' # the build number to download externals from
|
||||
verbosity: '$(VERBOSITY)' # the level of verbosity to use when building
|
||||
|
||||
jobs:
|
||||
# - ${{ if and(parameters.buildExternals, startsWith(parameters.name, 'native_')) }}:
|
||||
# - template: azure-templates-download.yml
|
||||
# parameters:
|
||||
# name: ${{ parameters.name }}
|
||||
# displayName: ${{ parameters.displayName }}
|
||||
# vmImage: ${{ parameters.vmImage }}
|
||||
# buildExternals: ${{ parameters.buildExternals }}
|
||||
|
||||
# - ${{ if or(not(parameters.buildExternals), not(startsWith(parameters.name, 'native_'))) }}:
|
||||
- job: ${{ parameters.name }}
|
||||
displayName: ${{ parameters.displayName }}
|
||||
timeoutInMinutes: 120
|
||||
pool:
|
||||
vmImage: $(VM_IMAGE_LINUX)
|
||||
name: ${{ parameters.vmImage }}
|
||||
container: ubuntu:14.04
|
||||
steps:
|
||||
- checkout: self
|
||||
|
@ -30,7 +43,7 @@ jobs:
|
|||
# pre-build steps
|
||||
- ${{ parameters.preBuildSteps }}
|
||||
# build
|
||||
- bash: ./scripts/retry-command.sh ${{ parameters.retryCount }} ./bootstrapper.sh -t ${{ parameters.target }} -v $VERBOSITY -c ${{ coalesce(variables.CONFIGURATION, 'Release') }} ${{ parameters.additionalArgs }}
|
||||
- bash: ./scripts/retry-command.sh ${{ parameters.retryCount }} ./bootstrapper.sh -t ${{ parameters.target }} -v ${{ parameters.verbosity }} -c ${{ coalesce(parameters.configuration, 'Release') }} ${{ parameters.additionalArgs }}
|
||||
displayName: Run the bootstrapper for ${{ parameters.target }}
|
||||
env:
|
||||
CC: clang-3.8
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
param (
|
||||
[string] $BuildNumber,
|
||||
[string] $Artifact
|
||||
)
|
||||
|
||||
$ErrorActionPreference = 'Stop'
|
||||
|
||||
Add-Type -AssemblyName System.IO.Compression.FileSystem
|
||||
|
||||
$url = "https://dev.azure.com/xamarin/public/_apis/build/builds/$BuildNumber/artifacts?artifactName=$Artifact&api-version=5.1&%24format=zip"
|
||||
$outputTemp = "./output-temp"
|
||||
$dest = "$outputTemp/$Artifact.zip"
|
||||
$destTemp = "$outputTemp/$Artifact"
|
||||
$output = "./output"
|
||||
|
||||
# dowload the artifact
|
||||
New-Item -Type Directory -Path $outputTemp -Force | Out-Null
|
||||
Invoke-WebRequest -Uri $url -OutFile $dest
|
||||
|
||||
# extract it
|
||||
if (Test-Path -Path $destTemp) {
|
||||
Remove-Item -Path $destTemp/** -Force -Recurse
|
||||
}
|
||||
[System.IO.Compression.ZipFile]::ExtractToDirectory($dest, $outputTemp)
|
||||
|
||||
# create the output folder
|
||||
New-Item -Type Directory -Path $output -Force | Out-Null
|
||||
|
||||
# move the items into the output folder
|
||||
Get-ChildItem $destTemp | Copy-Item -Destination $output -Force -Recurse
|
|
@ -0,0 +1,44 @@
|
|||
|
||||
# This was modified from StackOverflow
|
||||
# https://stackoverflow.com/questions/45574479/powershell-determine-new-url-of-a-permanently-moved-redirected-resource
|
||||
|
||||
Param (
|
||||
[Parameter(Mandatory, ValueFromPipeline)] [Uri] $Uri,
|
||||
[string] $OutFile,
|
||||
[int] $MaxRedirections = 50 # Use same default as [System.Net.HttpWebRequest]
|
||||
)
|
||||
|
||||
process {
|
||||
$nextUri = $Uri
|
||||
$ultimateFound = $false
|
||||
foreach($i in 1..$($MaxRedirections+1)) {
|
||||
Write-Verbose "Examining: $nextUri"
|
||||
$request = [System.Net.HttpWebRequest]::Create($nextUri)
|
||||
$request.AllowAutoRedirect = $False
|
||||
try {
|
||||
$response = $request.GetResponse()
|
||||
$nextUriStr = $response.Headers['Location']
|
||||
$response.Close()
|
||||
if (-not $nextUriStr) {
|
||||
$ultimateFound = $true
|
||||
break
|
||||
}
|
||||
} catch [System.Net.WebException] {
|
||||
$nextUriStr = try { $_.Exception.Response.Headers['Location'] } catch {}
|
||||
if (-not $nextUriStr) { Throw }
|
||||
}
|
||||
Write-Verbose "Raw target: $nextUriStr"
|
||||
if ($nextUriStr -match '^https?:') {
|
||||
$nextUri = $prevUri = [Uri] $nextUriStr
|
||||
} else {
|
||||
$nextUri = $prevUri = [Uri] ($prevUri.Scheme + '://' + $prevUri.Authority + $nextUriStr)
|
||||
}
|
||||
if ($i -ge $MaxRedirections) {
|
||||
break
|
||||
}
|
||||
}
|
||||
if (-not $ultimateFound) {
|
||||
Throw "Enumeration of $Uri redirections ended before reaching the ultimate target."
|
||||
}
|
||||
Invoke-WebRequest -Uri $nextUri -OutFile $OutFile
|
||||
}
|
|
@ -20,7 +20,7 @@ $ndk = "$HOME/android-ndk"
|
|||
if ($InstallDestination) {
|
||||
$ndk = $InstallDestination
|
||||
}
|
||||
Write-Host "Install destination is '$ts'..."
|
||||
Write-Host "Install destination is '$ndk'..."
|
||||
|
||||
$ndkTemp = "$HOME/android-ndk-temp"
|
||||
$install = "$ndkTemp/android-ndk.zip"
|
||||
|
|
|
@ -16,7 +16,7 @@ $jdk = Join-Path "$HOME" "openjdk"
|
|||
if ($InstallDestination) {
|
||||
$jdk = $InstallDestination
|
||||
}
|
||||
Write-Host "Install destination is '$ts'..."
|
||||
Write-Host "Install destination is '$jdk'..."
|
||||
|
||||
$jdkTemp = Join-Path "$HOME" "openjdk-temp"
|
||||
$archive = Join-Path "$jdkTemp" "openjdk.tar.gz"
|
||||
|
|
|
@ -81,8 +81,8 @@
|
|||
<Reference Include="System.Xml.Linq" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="xunit" Version="2.4.0" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.0" />
|
||||
<PackageReference Include="xunit" Version="2.4.1" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.1" />
|
||||
<PackageReference Include="xunit.assemblyfixture" Version="2.0.3" />
|
||||
<PackageReference Include="xunit.skippablefact" Version="1.3.12" />
|
||||
</ItemGroup>
|
||||
|
|
|
@ -14,8 +14,8 @@
|
|||
<SkipCopyToOutputDirectory>true</SkipCopyToOutputDirectory>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="xunit" Version="2.4.0" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.0" />
|
||||
<PackageReference Include="xunit" Version="2.4.1" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.1" />
|
||||
<PackageReference Include="XunitXml.TestLogger" Version="2.1.26" />
|
||||
<PackageReference Include="xunit.assemblyfixture" Version="2.0.3" />
|
||||
<PackageReference Include="xunit.skippablefact" Version="1.3.12" />
|
||||
|
|
|
@ -7,20 +7,21 @@ namespace SkiaSharp.Tests
|
|||
{
|
||||
public class GarbageCleanupFixture : IDisposable
|
||||
{
|
||||
#if THROW_OBJECT_EXCEPTIONS
|
||||
internal static readonly ConcurrentBag<IntPtr> ignoredExceptions = new ConcurrentBag<IntPtr>();
|
||||
#endif
|
||||
|
||||
private static readonly string[] StaticTypes = new[] {
|
||||
"SkiaSharp.SKData+SKDataStatic",
|
||||
"SkiaSharp.SKFontManager+SKFontManagerStatic",
|
||||
"SkiaSharp.SKTypeface+SKTypefaceStatic",
|
||||
"SkiaSharp.SKColorSpace+SKColorSpaceStatic",
|
||||
};
|
||||
|
||||
public GarbageCleanupFixture()
|
||||
{
|
||||
Assert.Empty(SKObject.constructors);
|
||||
Assert.Empty(SKObject.instances);
|
||||
var aliveObjects = SKObject.instances.Values
|
||||
.Select(o => o.Target)
|
||||
.Where(IsExpectedToBeDead)
|
||||
.ToList();
|
||||
Assert.Empty(aliveObjects);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
|
@ -37,21 +38,9 @@ namespace SkiaSharp.Tests
|
|||
|
||||
#if THROW_OBJECT_EXCEPTIONS
|
||||
// make sure all the exceptions are accounted for
|
||||
var ignored = ignoredExceptions
|
||||
.ToList();
|
||||
var exceptions = SKObject.exceptions
|
||||
.ToList();
|
||||
var keep = exceptions
|
||||
.Where(ex => !ignored.Contains((IntPtr)ex.Data["Handle"]))
|
||||
.ToList();
|
||||
Assert.Empty(keep);
|
||||
foreach (var ignore in ignored)
|
||||
{
|
||||
var e = exceptions
|
||||
.Where(ex => ex.Data["Handle"] is IntPtr)
|
||||
.ToList();
|
||||
Assert.NotEmpty(e);
|
||||
}
|
||||
Assert.Empty(exceptions);
|
||||
|
||||
// make sure all the GCHandles are freed
|
||||
var gcHandles = GCHandleProxy.allocatedHandles.Values
|
||||
|
@ -63,6 +52,9 @@ namespace SkiaSharp.Tests
|
|||
|
||||
private bool IsExpectedToBeDead(object instance)
|
||||
{
|
||||
if (instance == null)
|
||||
return false;
|
||||
|
||||
var skobject = Assert.IsAssignableFrom<SKObject>(instance);
|
||||
|
||||
if (StaticTypes.Contains(skobject.GetType().FullName))
|
||||
|
|
|
@ -180,7 +180,7 @@ namespace SkiaSharp.Tests
|
|||
if (index > 0) {
|
||||
decodeInfo = info.WithAlphaType (frameInfos [index].AlphaType);
|
||||
}
|
||||
bm.TryAllocPixels (decodeInfo);
|
||||
Assert.True (bm.TryAllocPixels (decodeInfo));
|
||||
if (cachedIndex != -1) {
|
||||
Assert.True (cachedFrames [cachedIndex].CopyTo (bm));
|
||||
}
|
||||
|
@ -199,7 +199,9 @@ namespace SkiaSharp.Tests
|
|||
var uncachedFrame = new SKBitmap ();
|
||||
decode (uncachedFrame, frameInfos [i].RequiredFrame, i);
|
||||
|
||||
Assert.Equal (cachedFrame.Bytes, uncachedFrame.Bytes);
|
||||
var cachedBytes = cachedFrame.Bytes;
|
||||
var uncachedBytes = uncachedFrame.Bytes;
|
||||
Assert.Equal (cachedBytes, uncachedBytes);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,6 +16,21 @@ namespace SkiaSharp.Tests
|
|||
Assert.True(SKColorSpace.Equal(colorspace, colorspace));
|
||||
}
|
||||
|
||||
[SkippableFact]
|
||||
public void StaticSrgbIsReturnedAsTheStaticInstance()
|
||||
{
|
||||
var handle = SkiaApi.sk_colorspace_new_srgb();
|
||||
try
|
||||
{
|
||||
var cs = SKObject.GetObject<SKColorSpace>(handle, unrefExisting: false);
|
||||
Assert.Equal("SKColorSpaceStatic", cs.GetType().Name);
|
||||
}
|
||||
finally
|
||||
{
|
||||
SkiaApi.sk_refcnt_safe_unref(handle);
|
||||
}
|
||||
}
|
||||
|
||||
[SkippableFact]
|
||||
public void ImageInfoHasColorSpace()
|
||||
{
|
||||
|
@ -226,6 +241,58 @@ namespace SkiaSharp.Tests
|
|||
Assert.True(colorspace.GammaIsCloseToSrgb);
|
||||
}
|
||||
|
||||
[SkippableFact]
|
||||
public void ColorSpaceCorrectlyReferencesSrgbSingleton()
|
||||
{
|
||||
var handle1 = SkiaApi.sk_colorspace_new_srgb();
|
||||
|
||||
var colorspace1 = SKColorSpace.CreateSrgb();
|
||||
|
||||
Assert.Equal(colorspace1.Handle, handle1);
|
||||
|
||||
var colorspace2 = SKColorSpace.CreateSrgb();
|
||||
|
||||
Assert.Same(colorspace1, colorspace2);
|
||||
Assert.Equal(handle1, colorspace2.Handle);
|
||||
|
||||
colorspace2.Dispose();
|
||||
Assert.False(colorspace2.IsDisposed);
|
||||
Assert.False(colorspace1.IsDisposed);
|
||||
|
||||
SkiaApi.sk_refcnt_safe_unref(handle1);
|
||||
}
|
||||
|
||||
[SkippableFact]
|
||||
public void SameColorSpaceCreatedDifferentWaysAreTheSameObject()
|
||||
{
|
||||
var colorspace1 = SKColorSpace.CreateSrgbLinear();
|
||||
Assert.Equal("SkiaSharp.SKColorSpace+SKColorSpaceStatic", colorspace1.GetType().FullName);
|
||||
Assert.Equal(2, colorspace1.GetReferenceCount());
|
||||
|
||||
var colorspace2 = SKColorSpace.CreateRgb(SKNamedGamma.Linear, SKColorSpaceGamut.Srgb);
|
||||
Assert.Equal("SkiaSharp.SKColorSpace+SKColorSpaceStatic", colorspace2.GetType().FullName);
|
||||
Assert.Equal(2, colorspace2.GetReferenceCount());
|
||||
|
||||
Assert.Same(colorspace1, colorspace2);
|
||||
|
||||
var colorspace3 = SKColorSpace.CreateRgb(
|
||||
new SKColorSpaceTransferFn { A = 0.6f, B = 0.5f, C = 0.4f, D = 0.3f, E = 0.2f, F = 0.1f },
|
||||
SKMatrix44.CreateIdentity());
|
||||
Assert.NotSame(colorspace1, colorspace3);
|
||||
|
||||
colorspace3.Dispose();
|
||||
Assert.True(colorspace3.IsDisposed);
|
||||
Assert.Equal(2, colorspace1.GetReferenceCount());
|
||||
|
||||
colorspace2.Dispose();
|
||||
Assert.False(colorspace2.IsDisposed);
|
||||
Assert.Equal(2, colorspace1.GetReferenceCount());
|
||||
|
||||
colorspace1.Dispose();
|
||||
Assert.False(colorspace1.IsDisposed);
|
||||
Assert.Equal(2, colorspace1.GetReferenceCount());
|
||||
}
|
||||
|
||||
private static void AssertMatrix(float[] expected, SKMatrix44 actual)
|
||||
{
|
||||
var actualArray = actual
|
||||
|
|
|
@ -171,6 +171,8 @@ namespace SkiaSharp.Tests
|
|||
[SkippableFact]
|
||||
public void StreamIsNotCollectedPrematurely()
|
||||
{
|
||||
VerifyImmediateFinalizers();
|
||||
|
||||
DoWork(out var handle);
|
||||
|
||||
CollectGarbage();
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
using Xunit;
|
||||
|
||||
namespace SkiaSharp.Tests
|
||||
|
@ -131,9 +133,8 @@ namespace SkiaSharp.Tests
|
|||
var inst1 = new LifecycleObject(handle, true) { Value = 1 };
|
||||
|
||||
#if THROW_OBJECT_EXCEPTIONS
|
||||
Assert.Throws<InvalidOperationException>(() => new LifecycleObject(handle, true) { Value = 2 });
|
||||
|
||||
GarbageCleanupFixture.ignoredExceptions.Add(handle);
|
||||
var ex = Assert.Throws<InvalidOperationException>(() => new LifecycleObject(handle, true) { Value = 2 });
|
||||
Assert.Contains("H: " + handle.ToString("x") + " ", ex.Message);
|
||||
#else
|
||||
var inst2 = new LifecycleObject(handle, true) { Value = 2 };
|
||||
Assert.True(inst1.DestroyedNative);
|
||||
|
@ -230,5 +231,79 @@ namespace SkiaSharp.Tests
|
|||
throw new Exception("BREAK!");
|
||||
}
|
||||
}
|
||||
|
||||
[SkippableTheory]
|
||||
[InlineData(1)]
|
||||
[InlineData(1000)]
|
||||
public async Task EnsureMultithreadingDoesNotThrow(int iterations)
|
||||
{
|
||||
var imagePath = Path.Combine(PathToImages, "baboon.jpg");
|
||||
|
||||
var tasks = new Task[iterations];
|
||||
|
||||
for (var i = 0; i < iterations; i++)
|
||||
{
|
||||
var task = new Task(() =>
|
||||
{
|
||||
using (var stream = File.OpenRead(imagePath))
|
||||
using (var data = SKData.Create(stream))
|
||||
using (var codec = SKCodec.Create(data))
|
||||
{
|
||||
var info = new SKImageInfo(codec.Info.Width, codec.Info.Height);
|
||||
using (var image = SKBitmap.Decode(codec, info))
|
||||
{
|
||||
var img = new byte[image.Height, image.Width];
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
tasks[i] = task;
|
||||
task.Start();
|
||||
}
|
||||
|
||||
await Task.WhenAll(tasks);
|
||||
}
|
||||
|
||||
[SkippableFact]
|
||||
public void EnsureConcurrencyResultsInCorrectDeregistration()
|
||||
{
|
||||
var handle = (IntPtr)446;
|
||||
|
||||
var obj = new ImmediateRecreationObject(handle, true);
|
||||
Assert.Null(obj.NewInstance);
|
||||
Assert.Equal(obj, SKObject.instances[handle]?.Target);
|
||||
|
||||
obj.Dispose();
|
||||
Assert.True(SKObject.GetInstance<ImmediateRecreationObject>(handle, out _));
|
||||
|
||||
var newObj = obj.NewInstance;
|
||||
|
||||
Assert.NotEqual(obj, SKObject.instances[handle]?.Target);
|
||||
Assert.Equal(newObj, SKObject.instances[handle]?.Target);
|
||||
|
||||
newObj.Dispose();
|
||||
Assert.False(SKObject.GetInstance<ImmediateRecreationObject>(handle, out _));
|
||||
}
|
||||
|
||||
private class ImmediateRecreationObject : SKObject
|
||||
{
|
||||
public ImmediateRecreationObject(IntPtr handle, bool shouldRecreate)
|
||||
: base(handle, true)
|
||||
{
|
||||
ShouldRecreate = shouldRecreate;
|
||||
}
|
||||
|
||||
public bool ShouldRecreate { get; }
|
||||
|
||||
public ImmediateRecreationObject NewInstance { get; private set; }
|
||||
|
||||
protected override void DisposeNative()
|
||||
{
|
||||
base.DisposeNative();
|
||||
|
||||
if (ShouldRecreate)
|
||||
NewInstance = new ImmediateRecreationObject(Handle, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="Cake" version="0.33.0" />
|
||||
<package id="Cake" version="0.34.1" />
|
||||
</packages>
|
||||
|
|
Загрузка…
Ссылка в новой задаче