зеркало из https://github.com/mono/SkiaSharp.git
Expose SKBlender (#2830)
This commit is contained in:
Родитель
a0f3767c96
Коммит
aa4f2ffedb
|
@ -18,6 +18,7 @@ using gr_vk_extensions_t = System.IntPtr;
|
|||
using gr_vk_memory_allocator_t = System.IntPtr;
|
||||
using gr_vkinterface_t = System.IntPtr;
|
||||
using sk_bitmap_t = System.IntPtr;
|
||||
using sk_blender_t = System.IntPtr;
|
||||
using sk_canvas_t = System.IntPtr;
|
||||
using sk_codec_t = System.IntPtr;
|
||||
using sk_colorfilter_t = System.IntPtr;
|
||||
|
|
|
@ -18,6 +18,7 @@ using gr_vk_extensions_t = System.IntPtr;
|
|||
using gr_vk_memory_allocator_t = System.IntPtr;
|
||||
using gr_vkinterface_t = System.IntPtr;
|
||||
using sk_bitmap_t = System.IntPtr;
|
||||
using sk_blender_t = System.IntPtr;
|
||||
using sk_canvas_t = System.IntPtr;
|
||||
using sk_codec_t = System.IntPtr;
|
||||
using sk_colorfilter_t = System.IntPtr;
|
||||
|
|
|
@ -18,6 +18,7 @@ using gr_vk_extensions_t = System.IntPtr;
|
|||
using gr_vk_memory_allocator_t = System.IntPtr;
|
||||
using gr_vkinterface_t = System.IntPtr;
|
||||
using sk_bitmap_t = System.IntPtr;
|
||||
using sk_blender_t = System.IntPtr;
|
||||
using sk_canvas_t = System.IntPtr;
|
||||
using sk_codec_t = System.IntPtr;
|
||||
using sk_colorfilter_t = System.IntPtr;
|
||||
|
|
|
@ -0,0 +1,63 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace SkiaSharp;
|
||||
|
||||
public unsafe class SKBlender : SKObject, ISKReferenceCounted
|
||||
{
|
||||
private static readonly Dictionary<SKBlendMode, SKBlender> blendModeBlenders;
|
||||
|
||||
static SKBlender ()
|
||||
{
|
||||
// TODO: This is not the best way to do this as it will create a lot of objects that
|
||||
// might not be needed, but it is the only way to ensure that the static
|
||||
// instances are created before any access is made to them.
|
||||
// See more info: SKObject.EnsureStaticInstanceAreInitialized()
|
||||
|
||||
var modes = Enum.GetValues (typeof (SKBlendMode));
|
||||
blendModeBlenders = new Dictionary<SKBlendMode, SKBlender> (modes.Length);
|
||||
foreach (SKBlendMode mode in modes)
|
||||
{
|
||||
blendModeBlenders [mode] = new SKBlenderStatic (SkiaApi.sk_blender_new_mode (mode));
|
||||
}
|
||||
}
|
||||
|
||||
internal static void EnsureStaticInstanceAreInitialized ()
|
||||
{
|
||||
// IMPORTANT: do not remove to ensure that the static instances
|
||||
// are initialized before any access is made to them
|
||||
}
|
||||
|
||||
internal SKBlender(IntPtr handle, bool owns)
|
||||
: base (handle, owns)
|
||||
{
|
||||
}
|
||||
|
||||
protected override void Dispose (bool disposing) =>
|
||||
base.Dispose (disposing);
|
||||
|
||||
public static SKBlender CreateBlendMode (SKBlendMode mode)
|
||||
{
|
||||
if (!blendModeBlenders.TryGetValue (mode, out var value))
|
||||
throw new ArgumentOutOfRangeException (nameof (mode));
|
||||
return value;
|
||||
}
|
||||
|
||||
public static SKBlender CreateArithmetic (float k1, float k2, float k3, float k4, bool enforcePMColor) =>
|
||||
GetObject (SkiaApi.sk_blender_new_arithmetic (k1, k2, k3, k4, enforcePMColor));
|
||||
|
||||
internal static SKBlender GetObject (IntPtr handle) =>
|
||||
GetOrAddObject (handle, (h, o) => new SKBlender (h, o));
|
||||
|
||||
//
|
||||
|
||||
private sealed class SKBlenderStatic : SKBlender
|
||||
{
|
||||
internal SKBlenderStatic (IntPtr x)
|
||||
: base (x, false)
|
||||
{
|
||||
}
|
||||
|
||||
protected override void Dispose (bool disposing) { }
|
||||
}
|
||||
}
|
|
@ -12,6 +12,11 @@ namespace SkiaSharp
|
|||
|
||||
static SKColorSpace ()
|
||||
{
|
||||
// TODO: This is not the best way to do this as it will create a lot of objects that
|
||||
// might not be needed, but it is the only way to ensure that the static
|
||||
// instances are created before any access is made to them.
|
||||
// See more info: SKObject.EnsureStaticInstanceAreInitialized()
|
||||
|
||||
srgb = new SKColorSpaceStatic (SkiaApi.sk_colorspace_new_srgb ());
|
||||
srgbLinear = new SKColorSpaceStatic (SkiaApi.sk_colorspace_new_srgb_linear ());
|
||||
}
|
||||
|
|
|
@ -19,6 +19,11 @@ namespace SkiaSharp
|
|||
|
||||
static SKData ()
|
||||
{
|
||||
// TODO: This is not the best way to do this as it will create a lot of objects that
|
||||
// might not be needed, but it is the only way to ensure that the static
|
||||
// instances are created before any access is made to them.
|
||||
// See more info: SKObject.EnsureStaticInstanceAreInitialized()
|
||||
|
||||
empty = new SKDataStatic (SkiaApi.sk_data_new_empty ());
|
||||
}
|
||||
|
||||
|
|
|
@ -14,6 +14,11 @@ namespace SkiaSharp
|
|||
|
||||
static SKFontManager ()
|
||||
{
|
||||
// TODO: This is not the best way to do this as it will create a lot of objects that
|
||||
// might not be needed, but it is the only way to ensure that the static
|
||||
// instances are created before any access is made to them.
|
||||
// See more info: SKObject.EnsureStaticInstanceAreInitialized()
|
||||
|
||||
defaultManager = new SKFontManagerStatic (SkiaApi.sk_fontmgr_ref_default ());
|
||||
}
|
||||
|
||||
|
|
|
@ -341,6 +341,23 @@ namespace SkiaSharp
|
|||
private static SKImageFilter CreateBlendMode (SKBlendMode mode, SKImageFilter? background, SKImageFilter? foreground, SKRect* cropRect) =>
|
||||
GetObject (SkiaApi.sk_imagefilter_new_blend (mode, background?.Handle ?? IntPtr.Zero, foreground?.Handle ?? IntPtr.Zero, cropRect));
|
||||
|
||||
// CreateBlendMode (Blender)
|
||||
|
||||
public static SKImageFilter CreateBlendMode (SKBlender blender, SKImageFilter? background) =>
|
||||
CreateBlendMode (blender, background, null, null);
|
||||
|
||||
public static SKImageFilter CreateBlendMode (SKBlender blender, SKImageFilter? background, SKImageFilter? foreground) =>
|
||||
CreateBlendMode (blender, background, foreground, null);
|
||||
|
||||
public static SKImageFilter CreateBlendMode (SKBlender blender, SKImageFilter? background, SKImageFilter? foreground, SKRect cropRect) =>
|
||||
CreateBlendMode (blender, background, foreground, &cropRect);
|
||||
|
||||
private static SKImageFilter CreateBlendMode (SKBlender blender, SKImageFilter? background, SKImageFilter? foreground, SKRect* cropRect)
|
||||
{
|
||||
_ = blender ?? throw new ArgumentNullException (nameof (blender));
|
||||
return GetObject (SkiaApi.sk_imagefilter_new_blender (blender.Handle, background?.Handle ?? IntPtr.Zero, foreground?.Handle ?? IntPtr.Zero, cropRect));
|
||||
}
|
||||
|
||||
// CreateArithmetic
|
||||
|
||||
public static SKImageFilter CreateArithmetic (float k1, float k2, float k3, float k4, bool enforcePMColor, SKImageFilter? background) =>
|
||||
|
|
|
@ -44,6 +44,7 @@ namespace SkiaSharp
|
|||
SKData.EnsureStaticInstanceAreInitialized ();
|
||||
SKFontManager.EnsureStaticInstanceAreInitialized ();
|
||||
SKTypeface.EnsureStaticInstanceAreInitialized ();
|
||||
SKBlender.EnsureStaticInstanceAreInitialized ();
|
||||
}
|
||||
|
||||
internal SKObject (IntPtr handle, bool owns)
|
||||
|
|
|
@ -203,6 +203,11 @@ namespace SkiaSharp
|
|||
set => SkiaApi.sk_paint_set_blendmode (Handle, value);
|
||||
}
|
||||
|
||||
public SKBlender Blender {
|
||||
get => SKBlender.GetObject (SkiaApi.sk_paint_get_blender (Handle));
|
||||
set => SkiaApi.sk_paint_set_blender (Handle, value == null ? IntPtr.Zero : value.Handle);
|
||||
}
|
||||
|
||||
[Obsolete ($"Use {nameof (SKSamplingOptions)} instead.")]
|
||||
public SKFilterQuality FilterQuality {
|
||||
get => (SKFilterQuality)SkiaApi.sk_compatpaint_get_filter_quality (Handle);
|
||||
|
|
|
@ -41,6 +41,17 @@ namespace SkiaSharp
|
|||
return effect;
|
||||
}
|
||||
|
||||
public static SKRuntimeEffect CreateBlender (string sksl, out string errors)
|
||||
{
|
||||
using var s = new SKString (sksl);
|
||||
using var errorString = new SKString ();
|
||||
var effect = GetObject (SkiaApi.sk_runtimeeffect_make_for_blender (s.Handle, errorString.Handle));
|
||||
errors = errorString?.ToString ();
|
||||
if (errors?.Length == 0)
|
||||
errors = null;
|
||||
return effect;
|
||||
}
|
||||
|
||||
// Build*
|
||||
|
||||
public static SKRuntimeShaderBuilder BuildShader (string sksl)
|
||||
|
@ -57,6 +68,13 @@ namespace SkiaSharp
|
|||
return new SKRuntimeColorFilterBuilder (effect);
|
||||
}
|
||||
|
||||
public static SKRuntimeBlenderBuilder BuildBlender (string sksl)
|
||||
{
|
||||
var effect = CreateBlender (sksl, out var errors);
|
||||
ValidateResult (effect, errors);
|
||||
return new SKRuntimeBlenderBuilder (effect);
|
||||
}
|
||||
|
||||
private static void ValidateResult (SKRuntimeEffect effect, string errors)
|
||||
{
|
||||
if (effect is null) {
|
||||
|
@ -148,6 +166,30 @@ namespace SkiaSharp
|
|||
}
|
||||
}
|
||||
|
||||
// ToBlender
|
||||
|
||||
public SKBlender ToBlender () =>
|
||||
ToBlender ((SKData)null, null);
|
||||
|
||||
public SKBlender ToBlender (SKRuntimeEffectUniforms uniforms) =>
|
||||
ToBlender (uniforms.ToData (), null);
|
||||
|
||||
private SKBlender ToBlender (SKData uniforms) =>
|
||||
ToBlender (uniforms, null);
|
||||
|
||||
public SKBlender ToBlender (SKRuntimeEffectUniforms uniforms, SKRuntimeEffectChildren children) =>
|
||||
ToBlender (uniforms.ToData (), children.ToArray ());
|
||||
|
||||
private SKBlender ToBlender (SKData uniforms, SKObject[] children)
|
||||
{
|
||||
var uniformsHandle = uniforms?.Handle ?? IntPtr.Zero;
|
||||
using var childrenHandles = Utils.RentHandlesArray (children, true);
|
||||
|
||||
fixed (IntPtr* ch = childrenHandles) {
|
||||
return SKBlender.GetObject (SkiaApi.sk_runtimeeffect_make_blender (Handle, uniformsHandle, ch, (IntPtr)childrenHandles.Length));
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
internal static SKRuntimeEffect GetObject (IntPtr handle) =>
|
||||
|
@ -560,15 +602,24 @@ namespace SkiaSharp
|
|||
value = colorFilter;
|
||||
}
|
||||
|
||||
public SKRuntimeEffectChild (SKBlender blender)
|
||||
{
|
||||
value = blender;
|
||||
}
|
||||
|
||||
public SKObject Value => value;
|
||||
|
||||
public SKShader Shader => value as SKShader;
|
||||
|
||||
public SKColorFilter ColorFilter => value as SKColorFilter;
|
||||
|
||||
public SKBlender Blender => value as SKBlender;
|
||||
|
||||
public static implicit operator SKRuntimeEffectChild (SKShader shader) => new (shader);
|
||||
|
||||
public static implicit operator SKRuntimeEffectChild (SKColorFilter colorFilter) => new (colorFilter);
|
||||
|
||||
public static implicit operator SKRuntimeEffectChild (SKBlender blender) => new (blender);
|
||||
}
|
||||
|
||||
public class SKRuntimeEffectBuilderException : ApplicationException
|
||||
|
@ -627,4 +678,15 @@ namespace SkiaSharp
|
|||
public SKColorFilter Build () =>
|
||||
Effect.ToColorFilter (Uniforms, Children);
|
||||
}
|
||||
|
||||
public class SKRuntimeBlenderBuilder : SKRuntimeEffectBuilder
|
||||
{
|
||||
public SKRuntimeBlenderBuilder (SKRuntimeEffect effect)
|
||||
: base (effect)
|
||||
{
|
||||
}
|
||||
|
||||
public SKBlender Build () =>
|
||||
Effect.ToBlender (Uniforms, Children);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -408,6 +408,23 @@ namespace SkiaSharp
|
|||
return GetObject (SkiaApi.sk_shader_new_blend (mode, shaderA.Handle, shaderB.Handle));
|
||||
}
|
||||
|
||||
// CreateBlend
|
||||
|
||||
public static SKShader CreateBlend (SKBlendMode mode, SKShader shaderA, SKShader shaderB)
|
||||
{
|
||||
_ = shaderA ?? throw new ArgumentNullException (nameof (shaderA));
|
||||
_ = shaderB ?? throw new ArgumentNullException (nameof (shaderB));
|
||||
return GetObject (SkiaApi.sk_shader_new_blend (mode, shaderA.Handle, shaderB.Handle));
|
||||
}
|
||||
|
||||
public static SKShader CreateBlend (SKBlender blender, SKShader shaderA, SKShader shaderB)
|
||||
{
|
||||
_ = shaderA ?? throw new ArgumentNullException (nameof (shaderA));
|
||||
_ = shaderB ?? throw new ArgumentNullException (nameof (shaderB));
|
||||
_ = blender ?? throw new ArgumentNullException (nameof (blender));
|
||||
return GetObject (SkiaApi.sk_shader_new_blender (blender.Handle, shaderA.Handle, shaderB.Handle));
|
||||
}
|
||||
|
||||
// CreateColorFilter
|
||||
|
||||
public static SKShader CreateColorFilter (SKShader shader, SKColorFilter filter)
|
||||
|
|
|
@ -14,6 +14,11 @@ namespace SkiaSharp
|
|||
|
||||
static SKTypeface ()
|
||||
{
|
||||
// TODO: This is not the best way to do this as it will create a lot of objects that
|
||||
// might not be needed, but it is the only way to ensure that the static
|
||||
// instances are created before any access is made to them.
|
||||
// See more info: SKObject.EnsureStaticInstanceAreInitialized()
|
||||
|
||||
defaultTypeface = new SKTypefaceStatic (SkiaApi.sk_typeface_ref_default ());
|
||||
}
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@ using gr_vk_extensions_t = System.IntPtr;
|
|||
using gr_vk_memory_allocator_t = System.IntPtr;
|
||||
using gr_vkinterface_t = System.IntPtr;
|
||||
using sk_bitmap_t = System.IntPtr;
|
||||
using sk_blender_t = System.IntPtr;
|
||||
using sk_canvas_t = System.IntPtr;
|
||||
using sk_codec_t = System.IntPtr;
|
||||
using sk_colorfilter_t = System.IntPtr;
|
||||
|
@ -1414,6 +1415,66 @@ namespace SkiaSharp
|
|||
|
||||
#endregion
|
||||
|
||||
#region sk_blender.h
|
||||
|
||||
// sk_blender_t* sk_blender_new_arithmetic(float k1, float k2, float k3, float k4, bool enforcePremul)
|
||||
#if !USE_DELEGATES
|
||||
[DllImport (SKIA, CallingConvention = CallingConvention.Cdecl)]
|
||||
internal static extern sk_blender_t sk_blender_new_arithmetic (Single k1, Single k2, Single k3, Single k4, [MarshalAs (UnmanagedType.I1)] bool enforcePremul);
|
||||
#else
|
||||
private partial class Delegates {
|
||||
[UnmanagedFunctionPointer (CallingConvention.Cdecl)]
|
||||
internal delegate sk_blender_t sk_blender_new_arithmetic (Single k1, Single k2, Single k3, Single k4, [MarshalAs (UnmanagedType.I1)] bool enforcePremul);
|
||||
}
|
||||
private static Delegates.sk_blender_new_arithmetic sk_blender_new_arithmetic_delegate;
|
||||
internal static sk_blender_t sk_blender_new_arithmetic (Single k1, Single k2, Single k3, Single k4, [MarshalAs (UnmanagedType.I1)] bool enforcePremul) =>
|
||||
(sk_blender_new_arithmetic_delegate ??= GetSymbol<Delegates.sk_blender_new_arithmetic> ("sk_blender_new_arithmetic")).Invoke (k1, k2, k3, k4, enforcePremul);
|
||||
#endif
|
||||
|
||||
// sk_blender_t* sk_blender_new_mode(sk_blendmode_t mode)
|
||||
#if !USE_DELEGATES
|
||||
[DllImport (SKIA, CallingConvention = CallingConvention.Cdecl)]
|
||||
internal static extern sk_blender_t sk_blender_new_mode (SKBlendMode mode);
|
||||
#else
|
||||
private partial class Delegates {
|
||||
[UnmanagedFunctionPointer (CallingConvention.Cdecl)]
|
||||
internal delegate sk_blender_t sk_blender_new_mode (SKBlendMode mode);
|
||||
}
|
||||
private static Delegates.sk_blender_new_mode sk_blender_new_mode_delegate;
|
||||
internal static sk_blender_t sk_blender_new_mode (SKBlendMode mode) =>
|
||||
(sk_blender_new_mode_delegate ??= GetSymbol<Delegates.sk_blender_new_mode> ("sk_blender_new_mode")).Invoke (mode);
|
||||
#endif
|
||||
|
||||
// void sk_blender_ref(sk_blender_t* blender)
|
||||
#if !USE_DELEGATES
|
||||
[DllImport (SKIA, CallingConvention = CallingConvention.Cdecl)]
|
||||
internal static extern void sk_blender_ref (sk_blender_t blender);
|
||||
#else
|
||||
private partial class Delegates {
|
||||
[UnmanagedFunctionPointer (CallingConvention.Cdecl)]
|
||||
internal delegate void sk_blender_ref (sk_blender_t blender);
|
||||
}
|
||||
private static Delegates.sk_blender_ref sk_blender_ref_delegate;
|
||||
internal static void sk_blender_ref (sk_blender_t blender) =>
|
||||
(sk_blender_ref_delegate ??= GetSymbol<Delegates.sk_blender_ref> ("sk_blender_ref")).Invoke (blender);
|
||||
#endif
|
||||
|
||||
// void sk_blender_unref(sk_blender_t* blender)
|
||||
#if !USE_DELEGATES
|
||||
[DllImport (SKIA, CallingConvention = CallingConvention.Cdecl)]
|
||||
internal static extern void sk_blender_unref (sk_blender_t blender);
|
||||
#else
|
||||
private partial class Delegates {
|
||||
[UnmanagedFunctionPointer (CallingConvention.Cdecl)]
|
||||
internal delegate void sk_blender_unref (sk_blender_t blender);
|
||||
}
|
||||
private static Delegates.sk_blender_unref sk_blender_unref_delegate;
|
||||
internal static void sk_blender_unref (sk_blender_t blender) =>
|
||||
(sk_blender_unref_delegate ??= GetSymbol<Delegates.sk_blender_unref> ("sk_blender_unref")).Invoke (blender);
|
||||
#endif
|
||||
|
||||
#endregion
|
||||
|
||||
#region sk_canvas.h
|
||||
|
||||
// void sk_canvas_clear(sk_canvas_t* ccanvas, sk_color_t color)
|
||||
|
@ -5326,6 +5387,20 @@ namespace SkiaSharp
|
|||
(sk_imagefilter_new_blend_delegate ??= GetSymbol<Delegates.sk_imagefilter_new_blend> ("sk_imagefilter_new_blend")).Invoke (mode, background, foreground, cropRect);
|
||||
#endif
|
||||
|
||||
// sk_imagefilter_t* sk_imagefilter_new_blender(sk_blender_t* blender, const sk_imagefilter_t* background, const sk_imagefilter_t* foreground, const sk_rect_t* cropRect)
|
||||
#if !USE_DELEGATES
|
||||
[DllImport (SKIA, CallingConvention = CallingConvention.Cdecl)]
|
||||
internal static extern sk_imagefilter_t sk_imagefilter_new_blender (sk_blender_t blender, sk_imagefilter_t background, sk_imagefilter_t foreground, SKRect* cropRect);
|
||||
#else
|
||||
private partial class Delegates {
|
||||
[UnmanagedFunctionPointer (CallingConvention.Cdecl)]
|
||||
internal delegate sk_imagefilter_t sk_imagefilter_new_blender (sk_blender_t blender, sk_imagefilter_t background, sk_imagefilter_t foreground, SKRect* cropRect);
|
||||
}
|
||||
private static Delegates.sk_imagefilter_new_blender sk_imagefilter_new_blender_delegate;
|
||||
internal static sk_imagefilter_t sk_imagefilter_new_blender (sk_blender_t blender, sk_imagefilter_t background, sk_imagefilter_t foreground, SKRect* cropRect) =>
|
||||
(sk_imagefilter_new_blender_delegate ??= GetSymbol<Delegates.sk_imagefilter_new_blender> ("sk_imagefilter_new_blender")).Invoke (blender, background, foreground, cropRect);
|
||||
#endif
|
||||
|
||||
// sk_imagefilter_t* sk_imagefilter_new_blur(float sigmaX, float sigmaY, sk_shader_tilemode_t tileMode, const sk_imagefilter_t* input, const sk_rect_t* cropRect)
|
||||
#if !USE_DELEGATES
|
||||
[DllImport (SKIA, CallingConvention = CallingConvention.Cdecl)]
|
||||
|
@ -5706,6 +5781,24 @@ namespace SkiaSharp
|
|||
|
||||
#endregion
|
||||
|
||||
#region sk_linker.h
|
||||
|
||||
// void sk_linker_keep_alive()
|
||||
#if !USE_DELEGATES
|
||||
[DllImport (SKIA, CallingConvention = CallingConvention.Cdecl)]
|
||||
internal static extern void sk_linker_keep_alive ();
|
||||
#else
|
||||
private partial class Delegates {
|
||||
[UnmanagedFunctionPointer (CallingConvention.Cdecl)]
|
||||
internal delegate void sk_linker_keep_alive ();
|
||||
}
|
||||
private static Delegates.sk_linker_keep_alive sk_linker_keep_alive_delegate;
|
||||
internal static void sk_linker_keep_alive () =>
|
||||
(sk_linker_keep_alive_delegate ??= GetSymbol<Delegates.sk_linker_keep_alive> ("sk_linker_keep_alive")).Invoke ();
|
||||
#endif
|
||||
|
||||
#endregion
|
||||
|
||||
#region sk_maskfilter.h
|
||||
|
||||
// sk_maskfilter_t* sk_maskfilter_new_blur(sk_blurstyle_t, float sigma)
|
||||
|
@ -5998,6 +6091,20 @@ namespace SkiaSharp
|
|||
(sk_paint_delete_delegate ??= GetSymbol<Delegates.sk_paint_delete> ("sk_paint_delete")).Invoke (param0);
|
||||
#endif
|
||||
|
||||
// sk_blender_t* sk_paint_get_blender(sk_paint_t* cpaint)
|
||||
#if !USE_DELEGATES
|
||||
[DllImport (SKIA, CallingConvention = CallingConvention.Cdecl)]
|
||||
internal static extern sk_blender_t sk_paint_get_blender (sk_paint_t cpaint);
|
||||
#else
|
||||
private partial class Delegates {
|
||||
[UnmanagedFunctionPointer (CallingConvention.Cdecl)]
|
||||
internal delegate sk_blender_t sk_paint_get_blender (sk_paint_t cpaint);
|
||||
}
|
||||
private static Delegates.sk_paint_get_blender sk_paint_get_blender_delegate;
|
||||
internal static sk_blender_t sk_paint_get_blender (sk_paint_t cpaint) =>
|
||||
(sk_paint_get_blender_delegate ??= GetSymbol<Delegates.sk_paint_get_blender> ("sk_paint_get_blender")).Invoke (cpaint);
|
||||
#endif
|
||||
|
||||
// sk_blendmode_t sk_paint_get_blendmode(sk_paint_t*)
|
||||
#if !USE_DELEGATES
|
||||
[DllImport (SKIA, CallingConvention = CallingConvention.Cdecl)]
|
||||
|
@ -6270,6 +6377,20 @@ namespace SkiaSharp
|
|||
(sk_paint_set_antialias_delegate ??= GetSymbol<Delegates.sk_paint_set_antialias> ("sk_paint_set_antialias")).Invoke (param0, param1);
|
||||
#endif
|
||||
|
||||
// void sk_paint_set_blender(sk_paint_t* paint, sk_blender_t* blender)
|
||||
#if !USE_DELEGATES
|
||||
[DllImport (SKIA, CallingConvention = CallingConvention.Cdecl)]
|
||||
internal static extern void sk_paint_set_blender (sk_paint_t paint, sk_blender_t blender);
|
||||
#else
|
||||
private partial class Delegates {
|
||||
[UnmanagedFunctionPointer (CallingConvention.Cdecl)]
|
||||
internal delegate void sk_paint_set_blender (sk_paint_t paint, sk_blender_t blender);
|
||||
}
|
||||
private static Delegates.sk_paint_set_blender sk_paint_set_blender_delegate;
|
||||
internal static void sk_paint_set_blender (sk_paint_t paint, sk_blender_t blender) =>
|
||||
(sk_paint_set_blender_delegate ??= GetSymbol<Delegates.sk_paint_set_blender> ("sk_paint_set_blender")).Invoke (paint, blender);
|
||||
#endif
|
||||
|
||||
// void sk_paint_set_blendmode(sk_paint_t*, sk_blendmode_t)
|
||||
#if !USE_DELEGATES
|
||||
[DllImport (SKIA, CallingConvention = CallingConvention.Cdecl)]
|
||||
|
@ -9456,6 +9577,20 @@ namespace SkiaSharp
|
|||
(sk_runtimeeffect_get_uniforms_size_delegate ??= GetSymbol<Delegates.sk_runtimeeffect_get_uniforms_size> ("sk_runtimeeffect_get_uniforms_size")).Invoke (effect);
|
||||
#endif
|
||||
|
||||
// sk_blender_t* sk_runtimeeffect_make_blender(sk_runtimeeffect_t* effect, sk_data_t* uniforms, sk_flattenable_t** children, size_t childCount)
|
||||
#if !USE_DELEGATES
|
||||
[DllImport (SKIA, CallingConvention = CallingConvention.Cdecl)]
|
||||
internal static extern sk_blender_t sk_runtimeeffect_make_blender (sk_runtimeeffect_t effect, sk_data_t uniforms, sk_flattenable_t* children, /* size_t */ IntPtr childCount);
|
||||
#else
|
||||
private partial class Delegates {
|
||||
[UnmanagedFunctionPointer (CallingConvention.Cdecl)]
|
||||
internal delegate sk_blender_t sk_runtimeeffect_make_blender (sk_runtimeeffect_t effect, sk_data_t uniforms, sk_flattenable_t* children, /* size_t */ IntPtr childCount);
|
||||
}
|
||||
private static Delegates.sk_runtimeeffect_make_blender sk_runtimeeffect_make_blender_delegate;
|
||||
internal static sk_blender_t sk_runtimeeffect_make_blender (sk_runtimeeffect_t effect, sk_data_t uniforms, sk_flattenable_t* children, /* size_t */ IntPtr childCount) =>
|
||||
(sk_runtimeeffect_make_blender_delegate ??= GetSymbol<Delegates.sk_runtimeeffect_make_blender> ("sk_runtimeeffect_make_blender")).Invoke (effect, uniforms, children, childCount);
|
||||
#endif
|
||||
|
||||
// sk_colorfilter_t* sk_runtimeeffect_make_color_filter(sk_runtimeeffect_t* effect, sk_data_t* uniforms, sk_flattenable_t** children, size_t childCount)
|
||||
#if !USE_DELEGATES
|
||||
[DllImport (SKIA, CallingConvention = CallingConvention.Cdecl)]
|
||||
|
@ -9470,6 +9605,20 @@ namespace SkiaSharp
|
|||
(sk_runtimeeffect_make_color_filter_delegate ??= GetSymbol<Delegates.sk_runtimeeffect_make_color_filter> ("sk_runtimeeffect_make_color_filter")).Invoke (effect, uniforms, children, childCount);
|
||||
#endif
|
||||
|
||||
// sk_runtimeeffect_t* sk_runtimeeffect_make_for_blender(sk_string_t* sksl, sk_string_t* error)
|
||||
#if !USE_DELEGATES
|
||||
[DllImport (SKIA, CallingConvention = CallingConvention.Cdecl)]
|
||||
internal static extern sk_runtimeeffect_t sk_runtimeeffect_make_for_blender (sk_string_t sksl, sk_string_t error);
|
||||
#else
|
||||
private partial class Delegates {
|
||||
[UnmanagedFunctionPointer (CallingConvention.Cdecl)]
|
||||
internal delegate sk_runtimeeffect_t sk_runtimeeffect_make_for_blender (sk_string_t sksl, sk_string_t error);
|
||||
}
|
||||
private static Delegates.sk_runtimeeffect_make_for_blender sk_runtimeeffect_make_for_blender_delegate;
|
||||
internal static sk_runtimeeffect_t sk_runtimeeffect_make_for_blender (sk_string_t sksl, sk_string_t error) =>
|
||||
(sk_runtimeeffect_make_for_blender_delegate ??= GetSymbol<Delegates.sk_runtimeeffect_make_for_blender> ("sk_runtimeeffect_make_for_blender")).Invoke (sksl, error);
|
||||
#endif
|
||||
|
||||
// sk_runtimeeffect_t* sk_runtimeeffect_make_for_color_filter(sk_string_t* sksl, sk_string_t* error)
|
||||
#if !USE_DELEGATES
|
||||
[DllImport (SKIA, CallingConvention = CallingConvention.Cdecl)]
|
||||
|
@ -9544,6 +9693,20 @@ namespace SkiaSharp
|
|||
(sk_shader_new_blend_delegate ??= GetSymbol<Delegates.sk_shader_new_blend> ("sk_shader_new_blend")).Invoke (mode, dst, src);
|
||||
#endif
|
||||
|
||||
// sk_shader_t* sk_shader_new_blender(sk_blender_t* blender, const sk_shader_t* dst, const sk_shader_t* src)
|
||||
#if !USE_DELEGATES
|
||||
[DllImport (SKIA, CallingConvention = CallingConvention.Cdecl)]
|
||||
internal static extern sk_shader_t sk_shader_new_blender (sk_blender_t blender, sk_shader_t dst, sk_shader_t src);
|
||||
#else
|
||||
private partial class Delegates {
|
||||
[UnmanagedFunctionPointer (CallingConvention.Cdecl)]
|
||||
internal delegate sk_shader_t sk_shader_new_blender (sk_blender_t blender, sk_shader_t dst, sk_shader_t src);
|
||||
}
|
||||
private static Delegates.sk_shader_new_blender sk_shader_new_blender_delegate;
|
||||
internal static sk_shader_t sk_shader_new_blender (sk_blender_t blender, sk_shader_t dst, sk_shader_t src) =>
|
||||
(sk_shader_new_blender_delegate ??= GetSymbol<Delegates.sk_shader_new_blender> ("sk_shader_new_blender")).Invoke (blender, dst, src);
|
||||
#endif
|
||||
|
||||
// sk_shader_t* sk_shader_new_color(sk_color_t color)
|
||||
#if !USE_DELEGATES
|
||||
[DllImport (SKIA, CallingConvention = CallingConvention.Cdecl)]
|
||||
|
|
|
@ -32,7 +32,7 @@ There are some small improvements in the initial release of 3.x, and many more w
|
|||
* `SKPoint3` is now implicitly compatible with `System.Numerics.Vector3` in both directions.
|
||||
* `SKPointI` is now implicitly cast to `System.Numerics.Vector3`.
|
||||
* `SKRuntimeEffect` now works on both CPU and GPU:
|
||||
* GPU is accelerated and support more targets: `SKColorFilter` and `SKShader` (there is also a new `SKBlender` that is not yet exposed in SkiaSharp).
|
||||
* GPU is accelerated and support more targets: `SKColorFilter`, `SKShader` and the new `SKBlender`.
|
||||
* CPU is NOT accelerated and may be very slow.
|
||||
* `SKMatrix44` is now a high-performance struct that can be used on any `SKCanvas`.
|
||||
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit 8684edb4e68d2bbf0d56a600633f5d4c44a16a36
|
||||
Subproject commit f1c2f7b4246141c6037820dc75d89496ac4aa8b3
|
|
@ -16,6 +16,7 @@ namespace SkiaSharp.Tests
|
|||
"SkiaSharp.SKFontStyle+SKFontStyleStatic",
|
||||
"SkiaSharp.SKTypeface+SKTypefaceStatic",
|
||||
"SkiaSharp.SKColorSpace+SKColorSpaceStatic",
|
||||
"SkiaSharp.SKBlender+SKBlenderStatic",
|
||||
};
|
||||
|
||||
public GarbageCleanupFixture()
|
||||
|
|
|
@ -0,0 +1,213 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Xunit;
|
||||
|
||||
namespace SkiaSharp.Tests;
|
||||
|
||||
public class SKBlenderTest
|
||||
{
|
||||
[SkippableFact]
|
||||
public void SameBlendModeReturnsSameBlenderInstance()
|
||||
{
|
||||
var blender1 = SKBlender.CreateBlendMode(SKBlendMode.Src);
|
||||
var blender2 = SKBlender.CreateBlendMode(SKBlendMode.Src);
|
||||
|
||||
Assert.Same(blender1, blender2);
|
||||
}
|
||||
|
||||
[SkippableFact]
|
||||
public void BlendModeBlenderIsNotDisposed()
|
||||
{
|
||||
var blender = SKBlender.CreateBlendMode(SKBlendMode.Src);
|
||||
Assert.True(SKObject.GetInstance<SKBlender>(blender.Handle, out _));
|
||||
|
||||
blender.Dispose();
|
||||
Assert.True(SKObject.GetInstance<SKBlender>(blender.Handle, out _));
|
||||
}
|
||||
|
||||
[SkippableFact]
|
||||
public void ArithmeticBlendModeBlenderIsBlendModeBlender()
|
||||
{
|
||||
var blendmode = SKBlender.CreateBlendMode(SKBlendMode.Src);
|
||||
|
||||
var arithmetic = SKBlender.CreateArithmetic(0, 1, 0, 0, false);
|
||||
|
||||
Assert.Same(blendmode, arithmetic);
|
||||
}
|
||||
|
||||
[SkippableFact]
|
||||
public void InvalidBlendModeThrowsArgumentException()
|
||||
{
|
||||
Assert.Throws<ArgumentOutOfRangeException>(() => SKBlender.CreateBlendMode((SKBlendMode)100));
|
||||
}
|
||||
|
||||
public abstract class SurfaceTestBase : SKTest
|
||||
{
|
||||
protected SKSurface Surface { get; set; }
|
||||
|
||||
protected SKImageInfo Info { get; set; }
|
||||
|
||||
protected abstract void CreateSurface(int width, int height);
|
||||
|
||||
[SkippableTheory]
|
||||
[MemberData(nameof(GetAllBlendModes))]
|
||||
public void BlenderMatchesBlendModeWhenUsingOpaqueColor(SKBlendMode mode)
|
||||
{
|
||||
var blendModeColor = GetColor(p => ApplyColor(p, false), p => ApplyBlendMode(p, mode));
|
||||
var blenderColor = GetColor(p => ApplyColor(p, false), p => ApplyBlender(p, mode));
|
||||
Assert.Equal(blendModeColor, blenderColor);
|
||||
}
|
||||
|
||||
[SkippableTheory]
|
||||
[MemberData(nameof(GetAllBlendModes))]
|
||||
public void BlenderMatchesBlendModeWhenUsingransparentColor(SKBlendMode mode)
|
||||
{
|
||||
var blendModeColor = GetColor(p => ApplyColor(p, true), p => ApplyBlendMode(p, mode));
|
||||
var blenderColor = GetColor(p => ApplyColor(p, true), p => ApplyBlender(p, mode));
|
||||
Assert.Equal(blendModeColor, blenderColor);
|
||||
}
|
||||
|
||||
[SkippableTheory]
|
||||
[MemberData(nameof(GetAllBlendModes))]
|
||||
public void BlenderMatchesBlendModeWhenUsingOpaqueShader(SKBlendMode mode)
|
||||
{
|
||||
var blendModeColor = GetColor(p => ApplyColorShader(p, false), p => ApplyBlendMode(p, mode));
|
||||
var blenderColor = GetColor(p => ApplyColorShader(p, false), p => ApplyBlender(p, mode));
|
||||
Assert.Equal(blendModeColor, blenderColor);
|
||||
}
|
||||
|
||||
[SkippableTheory]
|
||||
[MemberData(nameof(GetAllBlendModes))]
|
||||
public void BlenderMatchesBlendModeWhenUsingransparentShader(SKBlendMode mode)
|
||||
{
|
||||
var blendModeColor = GetColor(p => ApplyColorShader(p, true), p => ApplyBlendMode(p, mode));
|
||||
var blenderColor = GetColor(p => ApplyColorShader(p, true), p => ApplyBlender(p, mode));
|
||||
Assert.Equal(blendModeColor, blenderColor);
|
||||
}
|
||||
|
||||
private SKColor GetColor(Action<SKPaint> applyColor, Action<SKPaint> applyBlend)
|
||||
{
|
||||
// Draw a solid red pixel.
|
||||
using var paint = new SKPaint
|
||||
{
|
||||
Shader = null,
|
||||
Color = SKColors.Red,
|
||||
Blender = null,
|
||||
BlendMode = SKBlendMode.Src,
|
||||
};
|
||||
Surface.Canvas.DrawRect(SKRect.Create(1, 1), paint);
|
||||
|
||||
// Draw a blue pixel on top of it, using the passed-in blend mode.
|
||||
applyColor(paint);
|
||||
applyBlend(paint);
|
||||
Surface.Canvas.DrawRect(SKRect.Create(1, 1), paint);
|
||||
|
||||
// Read the pixels out of the surface and into the bitmap.
|
||||
using var bmp = new SKBitmap(new SKImageInfo(1, 1));
|
||||
Surface.ReadPixels(bmp.Info, bmp.GetPixels(), bmp.RowBytes, 0, 0);
|
||||
|
||||
// Get the pixel color.
|
||||
return bmp.GetPixel(0, 0);
|
||||
}
|
||||
|
||||
private static void ApplyBlendMode(SKPaint paint, SKBlendMode mode) =>
|
||||
paint.BlendMode = mode;
|
||||
|
||||
private static void ApplyBlender(SKPaint paint, SKBlendMode mode) =>
|
||||
paint.Blender = GetRuntimeBlenderForBlendMode(mode);
|
||||
|
||||
private static void ApplyColor(SKPaint paint, bool useTransparent)
|
||||
{
|
||||
var alpha = GetAlpha(useTransparent);
|
||||
paint.Color = new SKColor(0x00, 0x00, 0xFF, alpha);
|
||||
}
|
||||
|
||||
private static void ApplyColorShader(SKPaint paint, bool useTransparent)
|
||||
{
|
||||
// Install a different color in the paint, to ensure we're using the shader
|
||||
paint.Color = SKColors.Green;
|
||||
|
||||
var alpha = GetAlpha(useTransparent);
|
||||
paint.Shader = SKShader.CreateColor(new SKColor(0x00, 0x00, 0xFF, alpha));
|
||||
}
|
||||
|
||||
private static byte GetAlpha(bool useTransparent) =>
|
||||
useTransparent ? (byte)0x80 : (byte)0xFF;
|
||||
|
||||
public static IEnumerable<object[]> GetAllBlendModes()
|
||||
{
|
||||
foreach (SKBlendMode mode in Enum.GetValues(typeof(SKBlendMode)))
|
||||
yield return new object[] { mode };
|
||||
}
|
||||
|
||||
private static SKBlender GetRuntimeBlenderForBlendMode(SKBlendMode mode)
|
||||
{
|
||||
using var builder = SKRuntimeEffect.BuildBlender(
|
||||
"""
|
||||
uniform blender b;
|
||||
half4 main(half4 src, half4 dst) {
|
||||
return b.eval(src, dst);
|
||||
}
|
||||
""");
|
||||
|
||||
Assert.NotNull(builder.Effect);
|
||||
|
||||
builder.Children["b"] = SKBlender.CreateBlendMode(mode);
|
||||
|
||||
return builder.Build();
|
||||
}
|
||||
}
|
||||
|
||||
[Trait(Traits.Category.Key, Traits.Category.Values.Gpu)]
|
||||
public unsafe class Gpu : SurfaceTestBase, IDisposable
|
||||
{
|
||||
GlContext glContext;
|
||||
GRContext grContext;
|
||||
|
||||
public Gpu()
|
||||
{
|
||||
glContext = CreateGlContext();
|
||||
glContext.MakeCurrent();
|
||||
|
||||
grContext = GRContext.CreateGl();
|
||||
|
||||
CreateSurface(1, 1);
|
||||
}
|
||||
|
||||
protected override void CreateSurface(int width, int height)
|
||||
{
|
||||
Surface?.Dispose();
|
||||
|
||||
Info = new SKImageInfo(width, height, SKColorType.Rgba8888);
|
||||
Surface = SKSurface.Create(grContext, false, Info);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Surface.Dispose();
|
||||
grContext.Dispose();
|
||||
glContext.Destroy();
|
||||
}
|
||||
}
|
||||
|
||||
public unsafe class Raster : SurfaceTestBase, IDisposable
|
||||
{
|
||||
public Raster()
|
||||
{
|
||||
CreateSurface(1, 1);
|
||||
}
|
||||
|
||||
protected override void CreateSurface(int width, int height)
|
||||
{
|
||||
Surface?.Dispose();
|
||||
|
||||
Info = new SKImageInfo(width, height, SKColorType.Rgba8888);
|
||||
Surface = SKSurface.Create(Info);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Surface.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
Загрузка…
Ссылка в новой задаче