зеркало из https://github.com/mono/SkiaSharp.git
Add the GPU views for Uno Platform (#1429)
* Add the GPU views for the platforms * Add the render loop for the platforms * Fix the samples for infinite recursion * Added the GL views to the gallery
This commit is contained in:
Родитель
1fa3daddcc
Коммит
b3f5975cd8
|
@ -50,7 +50,7 @@ namespace SkiaSharpSample.Samples
|
||||||
|
|
||||||
private void GenerateDocument()
|
private void GenerateDocument()
|
||||||
{
|
{
|
||||||
if (isSupported && File.Exists(path))
|
if (!isSupported || (isSupported && File.Exists(path)))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var metadata = new SKDocumentPdfMetadata
|
var metadata = new SKDocumentPdfMetadata
|
||||||
|
@ -70,7 +70,6 @@ namespace SkiaSharpSample.Samples
|
||||||
if (document == null)
|
if (document == null)
|
||||||
{
|
{
|
||||||
isSupported = false;
|
isSupported = false;
|
||||||
Refresh();
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -52,7 +52,7 @@ namespace SkiaSharpSample.Samples
|
||||||
|
|
||||||
private void GenerateDocument()
|
private void GenerateDocument()
|
||||||
{
|
{
|
||||||
if (isSupported && File.Exists(path))
|
if (!isSupported || (isSupported && File.Exists(path)))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
using var document = SKDocument.CreateXps(path);
|
using var document = SKDocument.CreateXps(path);
|
||||||
|
@ -60,7 +60,6 @@ namespace SkiaSharpSample.Samples
|
||||||
if (document == null)
|
if (document == null)
|
||||||
{
|
{
|
||||||
isSupported = false;
|
isSupported = false;
|
||||||
Refresh();
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionName="1.0" package="com.companyname.skiasharpsample" android:versionCode="1">
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionName="1.0" package="com.companyname.skiasharpsample" android:versionCode="1">
|
||||||
<uses-sdk android:minSdkVersion="21" android:targetSdkVersion="29" />
|
<uses-sdk android:minSdkVersion="21" android:targetSdkVersion="29" />
|
||||||
<application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:roundIcon="@mipmap/ic_launcher_round" android:label="@string/app_name" android:theme="@style/Theme.AppCompat" android:hardwareAccelerated="true"></application>
|
<application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:roundIcon="@mipmap/ic_launcher_round" android:label="@string/app_name" android:theme="@style/AppTheme" android:hardwareAccelerated="true"></application>
|
||||||
</manifest>
|
</manifest>
|
|
@ -0,0 +1,12 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8" ?>
|
||||||
|
<resources>
|
||||||
|
<style name="AppTheme" parent="Theme.AppCompat.Light">
|
||||||
|
|
||||||
|
<!-- This removes the ActionBar -->
|
||||||
|
<item name="windowActionBar">false</item>
|
||||||
|
<item name="android:windowActionBar">false</item>
|
||||||
|
<item name="windowNoTitle">true</item>
|
||||||
|
<item name="android:windowNoTitle">true</item>
|
||||||
|
|
||||||
|
</style>
|
||||||
|
</resources>
|
|
@ -44,6 +44,7 @@
|
||||||
<!-- the samples canvas -->
|
<!-- the samples canvas -->
|
||||||
<Grid Tapped="OnSampleTapped" Background="White">
|
<Grid Tapped="OnSampleTapped" Background="White">
|
||||||
<views:SKXamlCanvas x:Name="canvas" Grid.Row="1" PaintSurface="OnPaintCanvas" />
|
<views:SKXamlCanvas x:Name="canvas" Grid.Row="1" PaintSurface="OnPaintCanvas" />
|
||||||
|
<views:SKSwapChainPanel x:Name="glview" Grid.Row="1" PaintSurface="OnPaintGL" Visibility="Collapsed" />
|
||||||
</Grid>
|
</Grid>
|
||||||
</SplitView.Content>
|
</SplitView.Content>
|
||||||
</SplitView>
|
</SplitView>
|
||||||
|
@ -54,6 +55,14 @@
|
||||||
OverflowButtonVisibility="Collapsed"
|
OverflowButtonVisibility="Collapsed"
|
||||||
Foreground="White">
|
Foreground="White">
|
||||||
<!-- the toolbar items -->
|
<!-- the toolbar items -->
|
||||||
|
<AppBarButton Icon="Repair" Label="Backend" IsCompact="True" Foreground="White">
|
||||||
|
<Button.Flyout>
|
||||||
|
<MenuFlyout>
|
||||||
|
<MenuFlyoutItem Text="Memory" Tag="Memory" Click="OnBackendSelected" />
|
||||||
|
<MenuFlyoutItem Text="OpenGL" Tag="OpenGL" Click="OnBackendSelected" />
|
||||||
|
</MenuFlyout>
|
||||||
|
</Button.Flyout>
|
||||||
|
</AppBarButton>
|
||||||
<AppBarButton
|
<AppBarButton
|
||||||
Click="OnToggleSlideshow"
|
Click="OnToggleSlideshow"
|
||||||
Foreground="White"
|
Foreground="White"
|
||||||
|
|
|
@ -58,6 +58,26 @@ namespace SkiaSharpSample
|
||||||
splitView.IsPaneOpen = menuButton.IsChecked == true;
|
splitView.IsPaneOpen = menuButton.IsChecked == true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void OnBackendSelected(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
var menu = sender as MenuFlyoutItem;
|
||||||
|
|
||||||
|
var backend = (SampleBackends)Enum.Parse(typeof(SampleBackends), menu.Tag.ToString());
|
||||||
|
switch (backend)
|
||||||
|
{
|
||||||
|
case SampleBackends.Memory:
|
||||||
|
glview.Visibility = Visibility.Collapsed;
|
||||||
|
canvas.Visibility = Visibility.Visible;
|
||||||
|
canvas.Invalidate();
|
||||||
|
break;
|
||||||
|
case SampleBackends.OpenGL:
|
||||||
|
glview.Visibility = Visibility.Visible;
|
||||||
|
canvas.Visibility = Visibility.Collapsed;
|
||||||
|
glview.Invalidate();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void OnToggleSlideshow(object sender, RoutedEventArgs e)
|
private void OnToggleSlideshow(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
if (cancellations != null)
|
if (cancellations != null)
|
||||||
|
@ -107,6 +127,11 @@ namespace SkiaSharpSample
|
||||||
OnPaintSurface(e.Surface.Canvas, e.Info.Width, e.Info.Height);
|
OnPaintSurface(e.Surface.Canvas, e.Info.Width, e.Info.Height);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void OnPaintGL(object sender, SKPaintGLSurfaceEventArgs e)
|
||||||
|
{
|
||||||
|
OnPaintSurface(e.Surface.Canvas, e.BackendRenderTarget.Width, e.BackendRenderTarget.Height);
|
||||||
|
}
|
||||||
|
|
||||||
private void SetSample(SampleBase newSample)
|
private void SetSample(SampleBase newSample)
|
||||||
{
|
{
|
||||||
// clean up the old sample
|
// clean up the old sample
|
||||||
|
@ -145,7 +170,10 @@ namespace SkiaSharpSample
|
||||||
|
|
||||||
private void OnRefreshRequested(object sender, EventArgs e)
|
private void OnRefreshRequested(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
canvas.Invalidate();
|
if (canvas.Visibility == Visibility.Visible)
|
||||||
|
canvas.Invalidate();
|
||||||
|
if (glview.Visibility == Visibility.Visible)
|
||||||
|
glview.Invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnPaintSurface(SKCanvas canvas, int width, int height)
|
private void OnPaintSurface(SKCanvas canvas, int width, int height)
|
||||||
|
|
|
@ -737,6 +737,7 @@ stages:
|
||||||
- task: TSAUpload@1
|
- task: TSAUpload@1
|
||||||
displayName: Publish TSA logs
|
displayName: Publish TSA logs
|
||||||
condition: always()
|
condition: always()
|
||||||
|
continueOnError: true
|
||||||
inputs:
|
inputs:
|
||||||
tsaVersion: 'TsaV2'
|
tsaVersion: 'TsaV2'
|
||||||
codebase: 'NewOrUpdate'
|
codebase: 'NewOrUpdate'
|
||||||
|
|
|
@ -0,0 +1,57 @@
|
||||||
|
using Android.Opengl;
|
||||||
|
using Windows.UI.Xaml;
|
||||||
|
using Windows.UI.Xaml.Controls;
|
||||||
|
|
||||||
|
namespace SkiaSharp.Views.UWP
|
||||||
|
{
|
||||||
|
public partial class SKSwapChainPanel : FrameworkElement
|
||||||
|
{
|
||||||
|
private SKGLTextureView glTextureView;
|
||||||
|
|
||||||
|
public SKSwapChainPanel()
|
||||||
|
{
|
||||||
|
Initialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
private SKSize GetCanvasSize() =>
|
||||||
|
glTextureView?.CanvasSize ?? SKSize.Empty;
|
||||||
|
|
||||||
|
private GRContext GetGRContext() =>
|
||||||
|
glTextureView?.GRContext;
|
||||||
|
|
||||||
|
partial void DoLoaded()
|
||||||
|
{
|
||||||
|
glTextureView = new SKGLTextureView(Context);
|
||||||
|
DoEnableRenderLoop(EnableRenderLoop);
|
||||||
|
glTextureView.PaintSurface += OnPaintSurface;
|
||||||
|
AddView(glTextureView);
|
||||||
|
}
|
||||||
|
|
||||||
|
partial void DoUnloaded()
|
||||||
|
{
|
||||||
|
if (glTextureView == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
RemoveView(glTextureView);
|
||||||
|
glTextureView.PaintSurface -= OnPaintSurface;
|
||||||
|
glTextureView.Dispose();
|
||||||
|
glTextureView = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
partial void DoEnableRenderLoop(bool enable)
|
||||||
|
{
|
||||||
|
if (glTextureView == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
glTextureView.RenderMode = enable
|
||||||
|
? Rendermode.Continuously
|
||||||
|
: Rendermode.WhenDirty;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DoInvalidate() =>
|
||||||
|
glTextureView?.RequestRender();
|
||||||
|
|
||||||
|
private void OnPaintSurface(object sender, SKPaintGLSurfaceEventArgs e) =>
|
||||||
|
OnPaintSurface(e);
|
||||||
|
}
|
||||||
|
}
|
|
@ -15,6 +15,9 @@
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Include="..\..\SkiaSharp.Views\SkiaSharp.Views.Shared\**\*.cs" Link="%(RecursiveDir)%(Filename)%(Extension)" />
|
<Compile Include="..\..\SkiaSharp.Views\SkiaSharp.Views.Shared\**\*.cs" Link="%(RecursiveDir)%(Filename)%(Extension)" />
|
||||||
|
<Compile Include="..\..\SkiaSharp.Views\SkiaSharp.Views.Android\GLTextureView.cs" />
|
||||||
|
<Compile Include="..\..\SkiaSharp.Views\SkiaSharp.Views.Android\SKGLTextureView.cs" />
|
||||||
|
<Compile Include="..\..\SkiaSharp.Views\SkiaSharp.Views.Android\SKGLTextureViewRenderer.cs" />
|
||||||
<Compile Include="..\..\SkiaSharp.Views\SkiaSharp.Views.UWP\UWPExtensions.cs" />
|
<Compile Include="..\..\SkiaSharp.Views\SkiaSharp.Views.UWP\UWPExtensions.cs" />
|
||||||
<Compile Include="..\SkiaSharp.Views.Uno\**\*.cs" Link="%(RecursiveDir)%(Filename)%(Extension)" />
|
<Compile Include="..\SkiaSharp.Views.Uno\**\*.cs" Link="%(RecursiveDir)%(Filename)%(Extension)" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
|
@ -0,0 +1,83 @@
|
||||||
|
using CoreVideo;
|
||||||
|
using Windows.UI.Xaml;
|
||||||
|
using Windows.UI.Xaml.Controls;
|
||||||
|
|
||||||
|
namespace SkiaSharp.Views.UWP
|
||||||
|
{
|
||||||
|
public partial class SKSwapChainPanel : FrameworkElement
|
||||||
|
{
|
||||||
|
private SKGLView glView;
|
||||||
|
private CVDisplayLink displayLink;
|
||||||
|
|
||||||
|
public SKSwapChainPanel()
|
||||||
|
{
|
||||||
|
Initialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
private SKSize GetCanvasSize() =>
|
||||||
|
glView?.CanvasSize ?? SKSize.Empty;
|
||||||
|
|
||||||
|
private GRContext GetGRContext() =>
|
||||||
|
glView?.GRContext;
|
||||||
|
|
||||||
|
partial void DoLoaded()
|
||||||
|
{
|
||||||
|
glView = new SKGLView(Bounds);
|
||||||
|
glView.PaintSurface += OnPaintSurface;
|
||||||
|
AddSubview(glView);
|
||||||
|
}
|
||||||
|
|
||||||
|
partial void DoUnloaded()
|
||||||
|
{
|
||||||
|
DoEnableRenderLoop(false);
|
||||||
|
|
||||||
|
if (glView != null)
|
||||||
|
{
|
||||||
|
glView.RemoveFromSuperview();
|
||||||
|
glView.PaintSurface -= OnPaintSurface;
|
||||||
|
glView.Dispose();
|
||||||
|
glView = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DoInvalidate() =>
|
||||||
|
DoEnableRenderLoop(true);
|
||||||
|
|
||||||
|
private void OnPaintSurface(object sender, SKPaintGLSurfaceEventArgs e) =>
|
||||||
|
OnPaintSurface(e);
|
||||||
|
|
||||||
|
partial void DoEnableRenderLoop(bool enable)
|
||||||
|
{
|
||||||
|
// stop the render loop
|
||||||
|
if (!enable)
|
||||||
|
{
|
||||||
|
if (displayLink != null)
|
||||||
|
{
|
||||||
|
displayLink.Stop();
|
||||||
|
displayLink.Dispose();
|
||||||
|
displayLink = null;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// only start if we haven't already
|
||||||
|
if (displayLink != null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// create the loop
|
||||||
|
displayLink = new CVDisplayLink();
|
||||||
|
displayLink.SetOutputCallback(delegate
|
||||||
|
{
|
||||||
|
// redraw the view
|
||||||
|
glView?.BeginInvokeOnMainThread(() => glView?.Display());
|
||||||
|
|
||||||
|
// stop the render loop if it has been disabled or the views are disposed
|
||||||
|
if (glView == null || !EnableRenderLoop)
|
||||||
|
DoEnableRenderLoop(false);
|
||||||
|
|
||||||
|
return CVReturn.Success;
|
||||||
|
});
|
||||||
|
displayLink.Start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -16,6 +16,7 @@
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Include="..\..\SkiaSharp.Views\SkiaSharp.Views.Shared\**\*.cs" Link="%(RecursiveDir)%(Filename)%(Extension)" />
|
<Compile Include="..\..\SkiaSharp.Views\SkiaSharp.Views.Shared\**\*.cs" Link="%(RecursiveDir)%(Filename)%(Extension)" />
|
||||||
<Compile Include="..\..\SkiaSharp.Views\SkiaSharp.Views.Apple\SKCGSurfaceFactory.cs" />
|
<Compile Include="..\..\SkiaSharp.Views\SkiaSharp.Views.Apple\SKCGSurfaceFactory.cs" />
|
||||||
|
<Compile Include="..\..\SkiaSharp.Views\SkiaSharp.Views.Mac\SKGLView.cs" />
|
||||||
<Compile Include="..\..\SkiaSharp.Views\SkiaSharp.Views.UWP\UWPExtensions.cs" />
|
<Compile Include="..\..\SkiaSharp.Views\SkiaSharp.Views.UWP\UWPExtensions.cs" />
|
||||||
<Compile Include="..\SkiaSharp.Views.Uno\**\*.cs" Link="%(RecursiveDir)%(Filename)%(Extension)" />
|
<Compile Include="..\SkiaSharp.Views.Uno\**\*.cs" Link="%(RecursiveDir)%(Filename)%(Extension)" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
|
@ -0,0 +1,210 @@
|
||||||
|
using System;
|
||||||
|
using System.Threading;
|
||||||
|
using Uno.Foundation;
|
||||||
|
using Uno.Foundation.Interop;
|
||||||
|
using Windows.UI.Xaml;
|
||||||
|
|
||||||
|
namespace SkiaSharp.Views.UWP
|
||||||
|
{
|
||||||
|
public partial class SKSwapChainPanel : FrameworkElement
|
||||||
|
{
|
||||||
|
private const int ResourceCacheBytes = 256 * 1024 * 1024; // 256 MB
|
||||||
|
private const SKColorType colorType = SKColorType.Rgba8888;
|
||||||
|
private const GRSurfaceOrigin surfaceOrigin = GRSurfaceOrigin.BottomLeft;
|
||||||
|
|
||||||
|
private readonly SKSwapChainPanelJsInterop jsInterop;
|
||||||
|
|
||||||
|
private GRGlInterface glInterface;
|
||||||
|
private GRContext context;
|
||||||
|
private JsInfo jsInfo;
|
||||||
|
private GRGlFramebufferInfo glInfo;
|
||||||
|
private GRBackendRenderTarget renderTarget;
|
||||||
|
private SKSurface surface;
|
||||||
|
private SKCanvas canvas;
|
||||||
|
|
||||||
|
private SKSizeI lastSize;
|
||||||
|
|
||||||
|
public SKSwapChainPanel()
|
||||||
|
: base("canvas")
|
||||||
|
{
|
||||||
|
jsInterop = new SKSwapChainPanelJsInterop(this);
|
||||||
|
Initialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
private SKSize GetCanvasSize() => lastSize;
|
||||||
|
|
||||||
|
private GRContext GetGRContext() => context;
|
||||||
|
|
||||||
|
partial void DoLoaded()
|
||||||
|
{
|
||||||
|
jsInfo = jsInterop.CreateContext();
|
||||||
|
|
||||||
|
Invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
partial void DoEnableRenderLoop(bool enable) =>
|
||||||
|
jsInterop.SetEnableRenderLoop(enable);
|
||||||
|
|
||||||
|
//partial void DoUpdateBounds() =>
|
||||||
|
// jsInterop.ResizeCanvas();
|
||||||
|
|
||||||
|
private void DoInvalidate()
|
||||||
|
{
|
||||||
|
if (designMode)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!isVisible)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if ((int)ActualWidth <= 0 || (int)ActualHeight <= 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
jsInterop.RequestAnimationFrame(EnableRenderLoop);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void RenderFrame()
|
||||||
|
{
|
||||||
|
if (!jsInfo.IsValid)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// create the SkiaSharp context
|
||||||
|
if (context == null)
|
||||||
|
{
|
||||||
|
glInterface = GRGlInterface.Create();
|
||||||
|
context = GRContext.CreateGl(glInterface);
|
||||||
|
|
||||||
|
// bump the default resource cache limit
|
||||||
|
context.SetResourceCacheLimit(ResourceCacheBytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
// get the new surface size
|
||||||
|
var newSize = new SKSizeI((int)(ActualWidth * ContentsScale), (int)(ActualHeight * ContentsScale));
|
||||||
|
|
||||||
|
// manage the drawing surface
|
||||||
|
if (renderTarget == null || lastSize != newSize || !renderTarget.IsValid)
|
||||||
|
{
|
||||||
|
// create or update the dimensions
|
||||||
|
lastSize = newSize;
|
||||||
|
|
||||||
|
glInfo = new GRGlFramebufferInfo(jsInfo.FboId, colorType.ToGlSizedFormat());
|
||||||
|
|
||||||
|
// destroy the old surface
|
||||||
|
surface?.Dispose();
|
||||||
|
surface = null;
|
||||||
|
canvas = null;
|
||||||
|
|
||||||
|
// re-create the render target
|
||||||
|
renderTarget?.Dispose();
|
||||||
|
renderTarget = new GRBackendRenderTarget(newSize.Width, newSize.Height, jsInfo.Samples, jsInfo.Stencil, glInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
// create the surface
|
||||||
|
if (surface == null)
|
||||||
|
{
|
||||||
|
surface = SKSurface.Create(context, renderTarget, surfaceOrigin, colorType);
|
||||||
|
canvas = surface.Canvas;
|
||||||
|
}
|
||||||
|
|
||||||
|
using (new SKAutoCanvasRestore(canvas, true))
|
||||||
|
{
|
||||||
|
// start drawing
|
||||||
|
OnPaintSurface(new SKPaintGLSurfaceEventArgs(surface, renderTarget, surfaceOrigin, colorType, glInfo));
|
||||||
|
}
|
||||||
|
|
||||||
|
// update the control
|
||||||
|
canvas.Flush();
|
||||||
|
context.Flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
private struct JsInfo
|
||||||
|
{
|
||||||
|
public bool IsValid { get; set; }
|
||||||
|
|
||||||
|
public int ContextId { get; set; }
|
||||||
|
|
||||||
|
public uint FboId { get; set; }
|
||||||
|
|
||||||
|
public int Stencil { get; set; }
|
||||||
|
|
||||||
|
public int Samples { get; set; }
|
||||||
|
|
||||||
|
public int Depth { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
private class SKSwapChainPanelJsInterop : IJSObject, IJSObjectMetadata
|
||||||
|
{
|
||||||
|
private static long handleCounter = 0L;
|
||||||
|
|
||||||
|
private readonly long jsHandle;
|
||||||
|
|
||||||
|
public SKSwapChainPanelJsInterop(SKSwapChainPanel panel)
|
||||||
|
{
|
||||||
|
Panel = panel ?? throw new ArgumentNullException(nameof(panel));
|
||||||
|
|
||||||
|
jsHandle = Interlocked.Increment(ref handleCounter);
|
||||||
|
Handle = JSObjectHandle.Create(this, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public SKSwapChainPanel Panel { get; }
|
||||||
|
|
||||||
|
public JSObjectHandle Handle { get; }
|
||||||
|
|
||||||
|
public void RenderFrame() =>
|
||||||
|
Panel.RenderFrame();
|
||||||
|
|
||||||
|
public void RequestAnimationFrame(bool renderLoop) =>
|
||||||
|
WebAssemblyRuntime.InvokeJSWithInterop($"{this}.requestAnimationFrame({(renderLoop ? "true" : "false")});");
|
||||||
|
|
||||||
|
public void SetEnableRenderLoop(bool enable) =>
|
||||||
|
WebAssemblyRuntime.InvokeJSWithInterop($"{this}.setEnableRenderLoop({(enable ? "true" : "false")});");
|
||||||
|
|
||||||
|
public void ResizeCanvas() =>
|
||||||
|
WebAssemblyRuntime.InvokeJSWithInterop($"{this}.resizeCanvas();");
|
||||||
|
|
||||||
|
public JsInfo CreateContext()
|
||||||
|
{
|
||||||
|
var resultString = WebAssemblyRuntime.InvokeJSWithInterop($"return {this}.createContext('{Panel.HtmlId}');");
|
||||||
|
var result = resultString?.Split(',');
|
||||||
|
if (result?.Length != 5)
|
||||||
|
return default;
|
||||||
|
|
||||||
|
return new JsInfo
|
||||||
|
{
|
||||||
|
IsValid = true,
|
||||||
|
ContextId = int.Parse(result[0]),
|
||||||
|
FboId = uint.Parse(result[1]),
|
||||||
|
Stencil = int.Parse(result[2]),
|
||||||
|
Samples = int.Parse(result[3]),
|
||||||
|
Depth = int.Parse(result[4]),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
long IJSObjectMetadata.CreateNativeInstance(IntPtr managedHandle)
|
||||||
|
{
|
||||||
|
WebAssemblyRuntime.InvokeJS($"SkiaSharp.Views.UWP.SKSwapChainPanel.createInstance('{managedHandle}', '{jsHandle}')");
|
||||||
|
return jsHandle;
|
||||||
|
}
|
||||||
|
|
||||||
|
string IJSObjectMetadata.GetNativeInstance(IntPtr managedHandle, long jsHandle) =>
|
||||||
|
$"SkiaSharp.Views.UWP.SKSwapChainPanel.getInstance('{jsHandle}')";
|
||||||
|
|
||||||
|
void IJSObjectMetadata.DestroyNativeInstance(IntPtr managedHandle, long jsHandle) =>
|
||||||
|
WebAssemblyRuntime.InvokeJS($"SkiaSharp.Views.UWP.SKSwapChainPanel.destroyInstance('{jsHandle}')");
|
||||||
|
|
||||||
|
object IJSObjectMetadata.InvokeManaged(object instance, string method, string parameters)
|
||||||
|
{
|
||||||
|
switch (method)
|
||||||
|
{
|
||||||
|
case nameof(RenderFrame):
|
||||||
|
RenderFrame();
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new ArgumentException($"Unable to execute method: {method}", nameof(method));
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -22,7 +22,149 @@
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class SKSwapChainPanel {
|
||||||
|
static activeInstances = {};
|
||||||
|
|
||||||
|
constructor(managedHandle) {
|
||||||
|
this.managedHandle = managedHandle;
|
||||||
|
this.canvas = undefined;
|
||||||
|
this.jsInfo = undefined;
|
||||||
|
this.renderLoop = false;
|
||||||
|
this.currentRequest = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// JSObject
|
||||||
|
static createInstance(managedHandle, jsHandle) {
|
||||||
|
SKSwapChainPanel.activeInstances[jsHandle] = new SKSwapChainPanel(managedHandle);
|
||||||
|
}
|
||||||
|
static getInstance(jsHandle) {
|
||||||
|
return SKSwapChainPanel.activeInstances[jsHandle];
|
||||||
|
}
|
||||||
|
static destroyInstance(jsHandle) {
|
||||||
|
delete SKSwapChainPanel.activeInstances[jsHandle];
|
||||||
|
}
|
||||||
|
|
||||||
|
requestAnimationFrame(renderLoop) {
|
||||||
|
// optionally update the render loop
|
||||||
|
if (renderLoop !== undefined && this.renderLoop !== renderLoop)
|
||||||
|
this.setEnableRenderLoop(renderLoop);
|
||||||
|
|
||||||
|
// skip because we have a render loop
|
||||||
|
if (this.currentRequest !== 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// make sure the canvas is scaled correctly for the drawing
|
||||||
|
this.resizeCanvas();
|
||||||
|
|
||||||
|
// add the draw to the next frame
|
||||||
|
this.currentRequest = window.requestAnimationFrame(() => {
|
||||||
|
Uno.Foundation.Interop.ManagedObject.dispatch(this.managedHandle, 'RenderFrame', null);
|
||||||
|
|
||||||
|
this.currentRequest = 0;
|
||||||
|
|
||||||
|
// we may want to draw the next frame
|
||||||
|
if (this.renderLoop)
|
||||||
|
this.requestAnimationFrame();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
resizeCanvas() {
|
||||||
|
if (!this.canvas)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var scale = window.devicePixelRatio || 1;
|
||||||
|
var w = this.canvas.clientWidth * scale
|
||||||
|
var h = this.canvas.clientHeight * scale;
|
||||||
|
|
||||||
|
if (this.canvas.width !== w)
|
||||||
|
this.canvas.width = w;
|
||||||
|
if (this.canvas.height !== h)
|
||||||
|
this.canvas.height = h;
|
||||||
|
}
|
||||||
|
|
||||||
|
setEnableRenderLoop(enable) {
|
||||||
|
this.renderLoop = enable;
|
||||||
|
|
||||||
|
// either start the new frame or cancel the existing one
|
||||||
|
if (enable) {
|
||||||
|
this.requestAnimationFrame();
|
||||||
|
} else if (this.currentRequest !== 0) {
|
||||||
|
window.cancelAnimationFrame(this.currentRequest);
|
||||||
|
this.currentRequest = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
createContext(canvasOrCanvasId) {
|
||||||
|
if (!canvasOrCanvasId)
|
||||||
|
throw 'No <canvas> element or ID was provided';
|
||||||
|
|
||||||
|
var canvas = canvasOrCanvasId;
|
||||||
|
if (canvas.tagName !== 'CANVAS') {
|
||||||
|
canvas = document.getElementById(canvasOrCanvasId);
|
||||||
|
if (!canvas)
|
||||||
|
throw `No <canvas> with id ${canvasOrCanvasId} was found`;
|
||||||
|
}
|
||||||
|
|
||||||
|
var ctx = SKSwapChainPanel.createWebGLContext(canvas);
|
||||||
|
if (!ctx || ctx < 0)
|
||||||
|
throw `Failed to create WebGL context: err ${ctx}`;
|
||||||
|
|
||||||
|
// make current
|
||||||
|
GL.makeContextCurrent(ctx);
|
||||||
|
|
||||||
|
// 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),
|
||||||
|
};
|
||||||
|
|
||||||
|
// format as array for nicer parsing
|
||||||
|
this.jsInfo = [
|
||||||
|
info.ctx,
|
||||||
|
info.fbo ? info.fbo.id : 0,
|
||||||
|
info.stencil,
|
||||||
|
info.sample,
|
||||||
|
info.depth,
|
||||||
|
];
|
||||||
|
return this.jsInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
static createWebGLContext(canvas) {
|
||||||
|
var contextAttributes = {
|
||||||
|
alpha: 1,
|
||||||
|
depth: 1,
|
||||||
|
stencil: 8,
|
||||||
|
antialias: 1,
|
||||||
|
premultipliedAlpha: 1,
|
||||||
|
preserveDrawingBuffer: 0,
|
||||||
|
preferLowPowerToHighPerformance: 0,
|
||||||
|
failIfMajorPerformanceCaveat: 0,
|
||||||
|
majorVersion: 2,
|
||||||
|
minorVersion: 0,
|
||||||
|
enableExtensionsByDefault: 1,
|
||||||
|
explicitSwapControl: 0,
|
||||||
|
renderViaOffscreenBackBuffer: 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
var ctx = GL.createContext(canvas, contextAttributes);
|
||||||
|
if (!ctx && contextAttributes.majorVersion > 1) {
|
||||||
|
console.warn('Falling back to WebGL 1.0');
|
||||||
|
contextAttributes.majorVersion = 1;
|
||||||
|
contextAttributes.minorVersion = 0;
|
||||||
|
ctx = GL.createContext(canvas, contextAttributes);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ctx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
UWP.SKXamlCanvas = SKXamlCanvas;
|
UWP.SKXamlCanvas = SKXamlCanvas;
|
||||||
|
UWP.SKSwapChainPanel = SKSwapChainPanel;
|
||||||
|
|
||||||
})(UWP = Views.UWP || (Views.UWP = {}));
|
})(UWP = Views.UWP || (Views.UWP = {}));
|
||||||
})(Views = SkiaSharp.Views || (SkiaSharp.Views = {}));
|
})(Views = SkiaSharp.Views || (SkiaSharp.Views = {}));
|
||||||
|
|
|
@ -0,0 +1,81 @@
|
||||||
|
using CoreAnimation;
|
||||||
|
using Foundation;
|
||||||
|
using Windows.UI.Xaml;
|
||||||
|
using Windows.UI.Xaml.Controls;
|
||||||
|
|
||||||
|
namespace SkiaSharp.Views.UWP
|
||||||
|
{
|
||||||
|
public partial class SKSwapChainPanel : FrameworkElement
|
||||||
|
{
|
||||||
|
private SKGLView glView;
|
||||||
|
private CADisplayLink displayLink;
|
||||||
|
|
||||||
|
public SKSwapChainPanel()
|
||||||
|
{
|
||||||
|
Initialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
private SKSize GetCanvasSize() =>
|
||||||
|
glView?.CanvasSize ?? SKSize.Empty;
|
||||||
|
|
||||||
|
private GRContext GetGRContext() =>
|
||||||
|
glView?.GRContext;
|
||||||
|
|
||||||
|
partial void DoLoaded()
|
||||||
|
{
|
||||||
|
glView = new SKGLView(Bounds);
|
||||||
|
glView.PaintSurface += OnPaintSurface;
|
||||||
|
AddSubview(glView);
|
||||||
|
}
|
||||||
|
|
||||||
|
partial void DoUnloaded()
|
||||||
|
{
|
||||||
|
DoEnableRenderLoop(false);
|
||||||
|
|
||||||
|
if (glView != null)
|
||||||
|
{
|
||||||
|
glView.RemoveFromSuperview();
|
||||||
|
glView.PaintSurface -= OnPaintSurface;
|
||||||
|
glView.Dispose();
|
||||||
|
glView = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DoInvalidate() =>
|
||||||
|
DoEnableRenderLoop(true);
|
||||||
|
|
||||||
|
private void OnPaintSurface(object sender, SKPaintGLSurfaceEventArgs e) =>
|
||||||
|
OnPaintSurface(e);
|
||||||
|
|
||||||
|
partial void DoEnableRenderLoop(bool enable)
|
||||||
|
{
|
||||||
|
// stop the render loop
|
||||||
|
if (!enable)
|
||||||
|
{
|
||||||
|
if (displayLink != null)
|
||||||
|
{
|
||||||
|
displayLink.Invalidate();
|
||||||
|
displayLink.Dispose();
|
||||||
|
displayLink = null;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// only start if we haven't already
|
||||||
|
if (displayLink != null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// create the loop
|
||||||
|
displayLink = CADisplayLink.Create(delegate
|
||||||
|
{
|
||||||
|
// redraw the view
|
||||||
|
glView?.BeginInvokeOnMainThread(() => glView?.Display());
|
||||||
|
|
||||||
|
// stop the render loop if it has been disabled or the views are disposed
|
||||||
|
if (glView == null || !EnableRenderLoop)
|
||||||
|
DoEnableRenderLoop(false);
|
||||||
|
});
|
||||||
|
displayLink.AddToRunLoop(NSRunLoop.Current, NSRunLoop.NSDefaultRunLoopMode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -15,6 +15,7 @@
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Include="..\..\SkiaSharp.Views\SkiaSharp.Views.Shared\**\*.cs" Link="%(RecursiveDir)%(Filename)%(Extension)" />
|
<Compile Include="..\..\SkiaSharp.Views\SkiaSharp.Views.Shared\**\*.cs" Link="%(RecursiveDir)%(Filename)%(Extension)" />
|
||||||
<Compile Include="..\..\SkiaSharp.Views\SkiaSharp.Views.Apple\SKCGSurfaceFactory.cs" />
|
<Compile Include="..\..\SkiaSharp.Views\SkiaSharp.Views.Apple\SKCGSurfaceFactory.cs" />
|
||||||
|
<Compile Include="..\..\SkiaSharp.Views\SkiaSharp.Views.AppleiOS\SKGLView.cs" />
|
||||||
<Compile Include="..\..\SkiaSharp.Views\SkiaSharp.Views.UWP\UWPExtensions.cs" />
|
<Compile Include="..\..\SkiaSharp.Views\SkiaSharp.Views.UWP\UWPExtensions.cs" />
|
||||||
<Compile Include="..\SkiaSharp.Views.Uno\**\*.cs" Link="%(RecursiveDir)%(Filename)%(Extension)" />
|
<Compile Include="..\SkiaSharp.Views.Uno\**\*.cs" Link="%(RecursiveDir)%(Filename)%(Extension)" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
|
@ -0,0 +1,144 @@
|
||||||
|
using System;
|
||||||
|
using Uno;
|
||||||
|
using Windows.ApplicationModel;
|
||||||
|
using Windows.Graphics.Display;
|
||||||
|
using Windows.UI.Core;
|
||||||
|
using Windows.UI.Xaml;
|
||||||
|
using Windows.UI.Xaml.Data;
|
||||||
|
|
||||||
|
namespace SkiaSharp.Views.UWP
|
||||||
|
{
|
||||||
|
public partial class SKSwapChainPanel : FrameworkElement
|
||||||
|
{
|
||||||
|
private static readonly DependencyProperty ProxyVisibilityProperty =
|
||||||
|
DependencyProperty.Register(
|
||||||
|
"ProxyVisibility",
|
||||||
|
typeof(Visibility),
|
||||||
|
typeof(SKSwapChainPanel),
|
||||||
|
new PropertyMetadata(Visibility.Visible, OnVisibilityChanged));
|
||||||
|
|
||||||
|
private static bool designMode = DesignMode.DesignModeEnabled;
|
||||||
|
|
||||||
|
private bool isVisible = true;
|
||||||
|
private bool enableRenderLoop = false;
|
||||||
|
|
||||||
|
// workaround for https://github.com/mono/SkiaSharp/issues/1118
|
||||||
|
private int loadUnloadCounter = 0;
|
||||||
|
|
||||||
|
private void Initialize()
|
||||||
|
{
|
||||||
|
if (designMode)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var display = DisplayInformation.GetForCurrentView();
|
||||||
|
OnDpiChanged(display);
|
||||||
|
|
||||||
|
Loaded += OnLoaded;
|
||||||
|
Unloaded += OnUnloaded;
|
||||||
|
SizeChanged += OnSizeChanged;
|
||||||
|
|
||||||
|
var binding = new Binding
|
||||||
|
{
|
||||||
|
Path = new PropertyPath(nameof(Visibility)),
|
||||||
|
Source = this
|
||||||
|
};
|
||||||
|
SetBinding(ProxyVisibilityProperty, binding);
|
||||||
|
}
|
||||||
|
|
||||||
|
public SKSize CanvasSize => GetCanvasSize();
|
||||||
|
|
||||||
|
public GRContext GRContext => GetGRContext();
|
||||||
|
|
||||||
|
public double ContentsScale { get; private set; }
|
||||||
|
|
||||||
|
[NotImplemented]
|
||||||
|
public bool DrawInBackground
|
||||||
|
{
|
||||||
|
get => throw new NotImplementedException();
|
||||||
|
set => throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool EnableRenderLoop
|
||||||
|
{
|
||||||
|
get => enableRenderLoop;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (enableRenderLoop != value)
|
||||||
|
{
|
||||||
|
enableRenderLoop = value;
|
||||||
|
DoEnableRenderLoop(enableRenderLoop);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public new void Invalidate()
|
||||||
|
{
|
||||||
|
_ = Dispatcher.RunAsync(CoreDispatcherPriority.Normal, DoInvalidate);
|
||||||
|
}
|
||||||
|
|
||||||
|
public event EventHandler<SKPaintGLSurfaceEventArgs> PaintSurface;
|
||||||
|
|
||||||
|
protected virtual void OnPaintSurface(SKPaintGLSurfaceEventArgs e)
|
||||||
|
{
|
||||||
|
// invoke the event
|
||||||
|
PaintSurface?.Invoke(this, e);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void OnVisibilityChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||||
|
{
|
||||||
|
if (d is SKSwapChainPanel canvas && e.NewValue is Visibility visibility)
|
||||||
|
{
|
||||||
|
canvas.isVisible = visibility == Visibility.Visible;
|
||||||
|
canvas.DoUpdateBounds();
|
||||||
|
canvas.Invalidate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnDpiChanged(DisplayInformation sender, object args = null)
|
||||||
|
{
|
||||||
|
ContentsScale = sender.LogicalDpi / 96.0f;
|
||||||
|
DoUpdateBounds();
|
||||||
|
Invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnSizeChanged(object sender, SizeChangedEventArgs e)
|
||||||
|
{
|
||||||
|
DoUpdateBounds();
|
||||||
|
Invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnLoaded(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
loadUnloadCounter++;
|
||||||
|
if (loadUnloadCounter != 1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
DoLoaded();
|
||||||
|
|
||||||
|
var display = DisplayInformation.GetForCurrentView();
|
||||||
|
display.DpiChanged += OnDpiChanged;
|
||||||
|
|
||||||
|
OnDpiChanged(display);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnUnloaded(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
loadUnloadCounter--;
|
||||||
|
if (loadUnloadCounter != 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
DoUnloaded();
|
||||||
|
|
||||||
|
var display = DisplayInformation.GetForCurrentView();
|
||||||
|
display.DpiChanged -= OnDpiChanged;
|
||||||
|
}
|
||||||
|
|
||||||
|
partial void DoLoaded();
|
||||||
|
|
||||||
|
partial void DoUnloaded();
|
||||||
|
|
||||||
|
partial void DoUpdateBounds();
|
||||||
|
|
||||||
|
partial void DoEnableRenderLoop(bool enable);
|
||||||
|
}
|
||||||
|
}
|
|
@ -18,9 +18,18 @@ using EGLContext = Javax.Microedition.Khronos.Egl.EGLContext;
|
||||||
using EGLDisplay = Javax.Microedition.Khronos.Egl.EGLDisplay;
|
using EGLDisplay = Javax.Microedition.Khronos.Egl.EGLDisplay;
|
||||||
using EGLSurface = Javax.Microedition.Khronos.Egl.EGLSurface;
|
using EGLSurface = Javax.Microedition.Khronos.Egl.EGLSurface;
|
||||||
|
|
||||||
|
#if HAS_UNO
|
||||||
|
namespace SkiaSharp.Views.UWP
|
||||||
|
#else
|
||||||
namespace SkiaSharp.Views.Android
|
namespace SkiaSharp.Views.Android
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
public class GLTextureView : TextureView, TextureView.ISurfaceTextureListener, View.IOnLayoutChangeListener
|
#if HAS_UNO
|
||||||
|
internal
|
||||||
|
#else
|
||||||
|
public
|
||||||
|
#endif
|
||||||
|
partial class GLTextureView : TextureView, TextureView.ISurfaceTextureListener, View.IOnLayoutChangeListener
|
||||||
{
|
{
|
||||||
private const bool EnableLogging = false;
|
private const bool EnableLogging = false;
|
||||||
|
|
||||||
|
|
|
@ -4,9 +4,18 @@ using Android.Content;
|
||||||
using Android.Opengl;
|
using Android.Opengl;
|
||||||
using Android.Util;
|
using Android.Util;
|
||||||
|
|
||||||
|
#if HAS_UNO
|
||||||
|
namespace SkiaSharp.Views.UWP
|
||||||
|
#else
|
||||||
namespace SkiaSharp.Views.Android
|
namespace SkiaSharp.Views.Android
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
public class SKGLTextureView : GLTextureView
|
#if HAS_UNO
|
||||||
|
internal
|
||||||
|
#else
|
||||||
|
public
|
||||||
|
#endif
|
||||||
|
partial class SKGLTextureView : GLTextureView
|
||||||
{
|
{
|
||||||
private SKGLTextureViewRenderer renderer;
|
private SKGLTextureViewRenderer renderer;
|
||||||
|
|
||||||
|
|
|
@ -5,9 +5,18 @@ using Javax.Microedition.Khronos.Opengles;
|
||||||
|
|
||||||
using EGLConfig = Javax.Microedition.Khronos.Egl.EGLConfig;
|
using EGLConfig = Javax.Microedition.Khronos.Egl.EGLConfig;
|
||||||
|
|
||||||
|
#if HAS_UNO
|
||||||
|
namespace SkiaSharp.Views.UWP
|
||||||
|
#else
|
||||||
namespace SkiaSharp.Views.Android
|
namespace SkiaSharp.Views.Android
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
public abstract class SKGLTextureViewRenderer : Java.Lang.Object, GLTextureView.IRenderer
|
#if HAS_UNO
|
||||||
|
internal
|
||||||
|
#else
|
||||||
|
public
|
||||||
|
#endif
|
||||||
|
abstract partial class SKGLTextureViewRenderer : Java.Lang.Object, GLTextureView.IRenderer
|
||||||
{
|
{
|
||||||
private const SKColorType colorType = SKColorType.Rgba8888;
|
private const SKColorType colorType = SKColorType.Rgba8888;
|
||||||
private const GRSurfaceOrigin surfaceOrigin = GRSurfaceOrigin.BottomLeft;
|
private const GRSurfaceOrigin surfaceOrigin = GRSurfaceOrigin.BottomLeft;
|
||||||
|
|
|
@ -8,7 +8,9 @@ using GLKit;
|
||||||
using OpenGLES;
|
using OpenGLES;
|
||||||
using SkiaSharp.Views.GlesInterop;
|
using SkiaSharp.Views.GlesInterop;
|
||||||
|
|
||||||
#if __TVOS__
|
#if HAS_UNO
|
||||||
|
namespace SkiaSharp.Views.UWP
|
||||||
|
#elif __TVOS__
|
||||||
namespace SkiaSharp.Views.tvOS
|
namespace SkiaSharp.Views.tvOS
|
||||||
#elif __IOS__
|
#elif __IOS__
|
||||||
namespace SkiaSharp.Views.iOS
|
namespace SkiaSharp.Views.iOS
|
||||||
|
@ -16,7 +18,12 @@ namespace SkiaSharp.Views.iOS
|
||||||
{
|
{
|
||||||
[Register(nameof(SKGLView))]
|
[Register(nameof(SKGLView))]
|
||||||
[DesignTimeVisible(true)]
|
[DesignTimeVisible(true)]
|
||||||
public class SKGLView : GLKView, IGLKViewDelegate, IComponent
|
#if HAS_UNO
|
||||||
|
internal
|
||||||
|
#else
|
||||||
|
public
|
||||||
|
#endif
|
||||||
|
class SKGLView : GLKView, IGLKViewDelegate, IComponent
|
||||||
{
|
{
|
||||||
private const SKColorType colorType = SKColorType.Rgba8888;
|
private const SKColorType colorType = SKColorType.Rgba8888;
|
||||||
private const GRSurfaceOrigin surfaceOrigin = GRSurfaceOrigin.BottomLeft;
|
private const GRSurfaceOrigin surfaceOrigin = GRSurfaceOrigin.BottomLeft;
|
||||||
|
|
|
@ -5,11 +5,20 @@ using CoreGraphics;
|
||||||
using Foundation;
|
using Foundation;
|
||||||
using SkiaSharp.Views.GlesInterop;
|
using SkiaSharp.Views.GlesInterop;
|
||||||
|
|
||||||
|
#if HAS_UNO
|
||||||
|
namespace SkiaSharp.Views.UWP
|
||||||
|
#else
|
||||||
namespace SkiaSharp.Views.Mac
|
namespace SkiaSharp.Views.Mac
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
[Register(nameof(SKGLView))]
|
[Register(nameof(SKGLView))]
|
||||||
[DesignTimeVisible(true)]
|
[DesignTimeVisible(true)]
|
||||||
public class SKGLView : NSOpenGLView
|
#if HAS_UNO
|
||||||
|
internal
|
||||||
|
#else
|
||||||
|
public
|
||||||
|
#endif
|
||||||
|
partial class SKGLView : NSOpenGLView
|
||||||
{
|
{
|
||||||
private const SKColorType colorType = SKColorType.Rgba8888;
|
private const SKColorType colorType = SKColorType.Rgba8888;
|
||||||
private const GRSurfaceOrigin surfaceOrigin = GRSurfaceOrigin.BottomLeft;
|
private const GRSurfaceOrigin surfaceOrigin = GRSurfaceOrigin.BottomLeft;
|
||||||
|
@ -88,7 +97,8 @@ namespace SkiaSharp.Views.Mac
|
||||||
base.Reshape();
|
base.Reshape();
|
||||||
|
|
||||||
// get the new surface size
|
// get the new surface size
|
||||||
newSize = ConvertSizeToBacking(Bounds.Size).ToSKSize().ToSizeI();
|
var size = ConvertSizeToBacking(Bounds.Size);
|
||||||
|
newSize = new SKSizeI((int)size.Width, (int)size.Height);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void DrawRect(CGRect dirtyRect)
|
public override void DrawRect(CGRect dirtyRect)
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
#if !__WATCHOS__ && !HAS_UNO
|
#if !__WATCHOS__ && !__WASM__
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
namespace SkiaSharp.Views.GlesInterop
|
namespace SkiaSharp.Views.GlesInterop
|
||||||
|
|
Загрузка…
Ссылка в новой задаче