|
|
|
@ -26,8 +26,8 @@ namespace Avalonia.Web.Blazor |
|
|
|
private InputHelperInterop _canvasHelper = null!; |
|
|
|
private ElementReference _htmlCanvas; |
|
|
|
private ElementReference _inputElement; |
|
|
|
private double _dpi; |
|
|
|
private SKSize _canvasSize; |
|
|
|
private double _dpi = 1; |
|
|
|
private SKSize _canvasSize = new (100, 100); |
|
|
|
|
|
|
|
private GRContext? _context; |
|
|
|
private GRGlInterface? _glInterface; |
|
|
|
@ -249,71 +249,55 @@ namespace Avalonia.Web.Blazor |
|
|
|
[Parameter(CaptureUnmatchedValues = true)] |
|
|
|
public IReadOnlyDictionary<string, object>? AdditionalAttributes { get; set; } |
|
|
|
|
|
|
|
protected override void OnAfterRender(bool firstRender) |
|
|
|
protected override async Task OnAfterRenderAsync(bool firstRender) |
|
|
|
{ |
|
|
|
if (firstRender) |
|
|
|
{ |
|
|
|
Threading.Dispatcher.UIThread.Post(async () => |
|
|
|
_inputHelper = await InputHelperInterop.ImportAsync(Js, _inputElement); |
|
|
|
_canvasHelper = await InputHelperInterop.ImportAsync(Js, _htmlCanvas); |
|
|
|
|
|
|
|
_inputHelper.Hide(); |
|
|
|
_canvasHelper.SetCursor("default"); |
|
|
|
_topLevelImpl.SetCssCursor = x => |
|
|
|
{ |
|
|
|
_inputHelper.SetCursor(x); //macOS
|
|
|
|
_canvasHelper.SetCursor(x); //windows
|
|
|
|
}; |
|
|
|
|
|
|
|
Console.WriteLine("starting html canvas setup"); |
|
|
|
_interop = await SKHtmlCanvasInterop.ImportAsync(Js, _htmlCanvas, OnRenderFrame); |
|
|
|
|
|
|
|
Console.WriteLine("Interop created"); |
|
|
|
_jsGlInfo = _interop.InitGL(); |
|
|
|
|
|
|
|
Console.WriteLine("jsglinfo created - init gl"); |
|
|
|
|
|
|
|
// create the SkiaSharp context
|
|
|
|
if (_context == null) |
|
|
|
{ |
|
|
|
_inputHelper = await InputHelperInterop.ImportAsync(Js, _inputElement); |
|
|
|
_canvasHelper = await InputHelperInterop.ImportAsync(Js, _htmlCanvas); |
|
|
|
|
|
|
|
_inputHelper.Hide(); |
|
|
|
_canvasHelper.SetCursor("default"); |
|
|
|
_topLevelImpl.SetCssCursor = x => |
|
|
|
{ |
|
|
|
_inputHelper.SetCursor(x);//macOS
|
|
|
|
_canvasHelper.SetCursor(x);//windows
|
|
|
|
}; |
|
|
|
|
|
|
|
Console.WriteLine("starting html canvas setup"); |
|
|
|
_interop = await SKHtmlCanvasInterop.ImportAsync(Js, _htmlCanvas, OnRenderFrame); |
|
|
|
|
|
|
|
Console.WriteLine("Interop created"); |
|
|
|
_jsGlInfo = _interop.InitGL(); |
|
|
|
|
|
|
|
Console.WriteLine("jsglinfo created - init gl"); |
|
|
|
|
|
|
|
_sizeWatcher = await SizeWatcherInterop.ImportAsync(Js, _htmlCanvas, OnSizeChanged); |
|
|
|
_dpiWatcher = await DpiWatcherInterop.ImportAsync(Js, OnDpiChanged); |
|
|
|
|
|
|
|
Console.WriteLine("watchers created."); |
|
|
|
|
|
|
|
// create the SkiaSharp context
|
|
|
|
if (_context == null) |
|
|
|
{ |
|
|
|
Console.WriteLine("create glcontext"); |
|
|
|
_glInterface = GRGlInterface.Create(); |
|
|
|
_context = GRContext.CreateGl(_glInterface); |
|
|
|
|
|
|
|
var options = AvaloniaLocator.Current.GetService<SkiaOptions>(); |
|
|
|
// bump the default resource cache limit
|
|
|
|
_context.SetResourceCacheLimit(options?.MaxGpuResourceSizeBytes ?? 32 * 1024 * 1024); |
|
|
|
Console.WriteLine("glcontext created and resource limit set"); |
|
|
|
} |
|
|
|
|
|
|
|
_topLevelImpl.SetSurface(_context, _jsGlInfo, ColorType, |
|
|
|
new PixelSize((int)_canvasSize.Width, (int)_canvasSize.Height), _dpi); |
|
|
|
|
|
|
|
_initialised = true; |
|
|
|
|
|
|
|
_topLevel.Prepare(); |
|
|
|
|
|
|
|
_topLevel.Renderer.Start(); |
|
|
|
|
|
|
|
// Note: this is technically a hack, but it's a kinda unique use case when
|
|
|
|
// we want to blit the previous frame
|
|
|
|
// renderer doesn't have much control over the render target
|
|
|
|
// we render on the UI thread
|
|
|
|
// We also don't want to have it as a meaningful public API.
|
|
|
|
// Therefore we have InternalsVisibleTo hack here.
|
|
|
|
if (_topLevel.Renderer is DeferredRenderer dr) |
|
|
|
{ |
|
|
|
dr.Render(true); |
|
|
|
} |
|
|
|
|
|
|
|
Invalidate(); |
|
|
|
}); |
|
|
|
Console.WriteLine("create glcontext"); |
|
|
|
_glInterface = GRGlInterface.Create(); |
|
|
|
_context = GRContext.CreateGl(_glInterface); |
|
|
|
|
|
|
|
var options = AvaloniaLocator.Current.GetService<SkiaOptions>(); |
|
|
|
// bump the default resource cache limit
|
|
|
|
_context.SetResourceCacheLimit(options?.MaxGpuResourceSizeBytes ?? 32 * 1024 * 1024); |
|
|
|
Console.WriteLine("glcontext created and resource limit set"); |
|
|
|
} |
|
|
|
|
|
|
|
_topLevelImpl.SetSurface(_context, _jsGlInfo, ColorType, |
|
|
|
new PixelSize((int)_canvasSize.Width, (int)_canvasSize.Height), _dpi); |
|
|
|
|
|
|
|
_initialised = true; |
|
|
|
|
|
|
|
_topLevel.Prepare(); |
|
|
|
|
|
|
|
_topLevel.Renderer.Start(); |
|
|
|
|
|
|
|
Invalidate(); |
|
|
|
|
|
|
|
_sizeWatcher = await SizeWatcherInterop.ImportAsync(Js, _htmlCanvas, OnSizeChanged); |
|
|
|
_dpiWatcher = await DpiWatcherInterop.ImportAsync(Js, OnDpiChanged); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
@ -335,16 +319,28 @@ namespace Avalonia.Web.Blazor |
|
|
|
_interop.Dispose(); |
|
|
|
} |
|
|
|
|
|
|
|
private void OnDpiChanged(double newDpi) |
|
|
|
private void ForceBlit() |
|
|
|
{ |
|
|
|
_dpi = newDpi; |
|
|
|
// Note: this is technically a hack, but it's a kinda unique use case when
|
|
|
|
// we want to blit the previous frame
|
|
|
|
// renderer doesn't have much control over the render target
|
|
|
|
// we render on the UI thread
|
|
|
|
// We also don't want to have it as a meaningful public API.
|
|
|
|
// Therefore we have InternalsVisibleTo hack here.
|
|
|
|
|
|
|
|
_topLevelImpl.SetClientSize(_canvasSize, _dpi); |
|
|
|
|
|
|
|
if (_topLevel.Renderer is DeferredRenderer dr) |
|
|
|
{ |
|
|
|
dr.Render(true); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
private void OnDpiChanged(double newDpi) |
|
|
|
{ |
|
|
|
_dpi = newDpi; |
|
|
|
|
|
|
|
_topLevelImpl.SetClientSize(_canvasSize, _dpi); |
|
|
|
|
|
|
|
ForceBlit(); |
|
|
|
|
|
|
|
Invalidate(); |
|
|
|
} |
|
|
|
@ -357,17 +353,14 @@ namespace Avalonia.Web.Blazor |
|
|
|
|
|
|
|
_topLevelImpl.SetClientSize(_canvasSize, _dpi); |
|
|
|
|
|
|
|
if (_topLevel.Renderer is DeferredRenderer dr) |
|
|
|
{ |
|
|
|
dr.Render(true); |
|
|
|
} |
|
|
|
ForceBlit(); |
|
|
|
|
|
|
|
Invalidate(); |
|
|
|
} |
|
|
|
|
|
|
|
public void Invalidate() |
|
|
|
{ |
|
|
|
if (!_initialised || _canvasSize.Width <= 0 || _canvasSize.Height <= 0 || _dpi <= 0 || _jsGlInfo == null) |
|
|
|
if (!_initialised || _jsGlInfo == null) |
|
|
|
{ |
|
|
|
Console.WriteLine("invalidate ignored"); |
|
|
|
return; |
|
|
|
|