Browse Source

Merge branch 'master' into fixes/1185-stackpanel-gap-property-last-child

pull/1186/head
danwalmsley 8 years ago
committed by GitHub
parent
commit
2c7124d5cf
  1. 9
      src/Avalonia.Base/Platform/IRuntimePlatform.cs
  2. 3
      src/Avalonia.DotNetCoreRuntime/Avalonia.DotNetCoreRuntime.csproj
  3. 20
      src/Gtk/Avalonia.Gtk3/ImageSurfaceFramebuffer.cs
  4. 38
      src/Gtk/Avalonia.Gtk3/Interop/ManagedCairoSurface.cs
  5. 4
      src/Gtk/Avalonia.Gtk3/Interop/Native.cs
  6. 132
      src/Shared/PlatformSupport/StandardRuntimePlatform.cs
  7. 13
      src/Skia/Avalonia.Skia/BitmapImpl.cs

9
src/Avalonia.Base/Platform/IRuntimePlatform.cs

@ -14,6 +14,15 @@ namespace Avalonia.Platform
IDisposable StartSystemTimer(TimeSpan interval, Action tick);
string GetStackTrace();
RuntimePlatformInfo GetRuntimeInfo();
IUnmanagedBlob AllocBlob(int size);
}
public interface IUnmanagedBlob : IDisposable
{
IntPtr Address { get; }
int Size { get; }
bool IsDisposed { get; }
}
public struct RuntimePlatformInfo

3
src/Avalonia.DotNetCoreRuntime/Avalonia.DotNetCoreRuntime.csproj

@ -2,6 +2,7 @@
<PropertyGroup>
<TargetFramework>netcoreapp2.0</TargetFramework>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<DefineConstants>$(DefineConstants);DOTNETCORE</DefineConstants>
</PropertyGroup>
<PropertyGroup>
<DocumentationFile>bin\$(Configuration)\Avalonia.DotNetCoreRuntime.XML</DocumentationFile>
@ -21,5 +22,5 @@
<ProjectReference Include="..\Windows\Avalonia.Win32.NetStandard\Avalonia.Win32.NetStandard.csproj" />
</ItemGroup>
<Import Project="..\..\build\NetCore.props" />
<Import Project="..\Shared\PlatformSupport\PlatformSupport.projitems" Label="Shared" />
<Import Project="..\Shared\PlatformSupport\PlatformSupport.projitems" />
</Project>

20
src/Gtk/Avalonia.Gtk3/ImageSurfaceFramebuffer.cs

@ -16,7 +16,7 @@ namespace Avalonia.Gtk3
{
private readonly WindowBaseImpl _impl;
private readonly GtkWidget _widget;
private CairoSurface _surface;
private ManagedCairoSurface _surface;
private int _factor;
private object _lock = new object();
public ImageSurfaceFramebuffer(WindowBaseImpl impl, int width, int height, int factor)
@ -26,13 +26,13 @@ namespace Avalonia.Gtk3
_factor = factor;
width *= _factor;
height *= _factor;
_surface = Native.CairoImageSurfaceCreate(1, width, height);
_surface = new ManagedCairoSurface(width, height);
Width = width;
Height = height;
Address = Native.CairoImageSurfaceGetData(_surface);
RowBytes = Native.CairoImageSurfaceGetStride(_surface);
Native.CairoSurfaceFlush(_surface);
Address = _surface.Buffer;
RowBytes = _surface.Stride;
Native.CairoSurfaceFlush(_surface.Surface);
}
static void Draw(IntPtr context, CairoSurface surface, double factor)
@ -83,12 +83,12 @@ namespace Avalonia.Gtk3
class RenderOp : IDeferredRenderOperation
{
private readonly GtkWidget _widget;
private CairoSurface _surface;
private ManagedCairoSurface _surface;
private readonly double _factor;
private readonly int _width;
private readonly int _height;
public RenderOp(GtkWidget widget, CairoSurface _surface, double factor, int width, int height)
public RenderOp(GtkWidget widget, ManagedCairoSurface _surface, double factor, int width, int height)
{
_widget = widget;
this._surface = _surface;
@ -105,7 +105,7 @@ namespace Avalonia.Gtk3
public void RenderNow()
{
DrawToWidget(_widget, _surface, _width, _height, _factor);
DrawToWidget(_widget, _surface.Surface, _width, _height, _factor);
}
}
@ -116,9 +116,9 @@ namespace Avalonia.Gtk3
if (Dispatcher.UIThread.CheckAccess())
{
if (_impl.CurrentCairoContext != IntPtr.Zero)
Draw(_impl.CurrentCairoContext, _surface, _factor);
Draw(_impl.CurrentCairoContext, _surface.Surface, _factor);
else
DrawToWidget(_widget, _surface, Width, Height, _factor);
DrawToWidget(_widget, _surface.Surface, Width, Height, _factor);
_surface.Dispose();
}
else

38
src/Gtk/Avalonia.Gtk3/Interop/ManagedCairoSurface.cs

@ -0,0 +1,38 @@
using System;
using System.Runtime.InteropServices;
using Avalonia.Platform;
namespace Avalonia.Gtk3.Interop
{
class ManagedCairoSurface : IDisposable
{
public IntPtr Buffer { get; private set; }
public CairoSurface Surface { get; private set; }
public int Stride { get; private set; }
private int _size;
private IRuntimePlatform _plat;
private IUnmanagedBlob _blob;
public ManagedCairoSurface(int width, int height)
{
_plat = AvaloniaLocator.Current.GetService<IRuntimePlatform>();
Stride = width * 4;
_size = height * Stride;
_blob = _plat.AllocBlob(_size * 2);
Buffer = _blob.Address;
Surface = Native.CairoImageSurfaceCreateForData(Buffer, 1, width, height, Stride);
}
public void Dispose()
{
if (Buffer != IntPtr.Zero)
{
Surface.Dispose();
_blob.Dispose();
Buffer = IntPtr.Zero;
}
}
}
}

4
src/Gtk/Avalonia.Gtk3/Interop/Native.cs

@ -160,6 +160,9 @@ namespace Avalonia.Gtk3.Interop
[UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Cairo)]
public delegate CairoSurface cairo_image_surface_create(int format, int width, int height);
[UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Cairo)]
public delegate CairoSurface cairo_image_surface_create_for_data(IntPtr data, int format, int width, int height, int stride);
[UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Cairo)]
public delegate IntPtr cairo_image_surface_get_data(CairoSurface surface);
@ -459,6 +462,7 @@ namespace Avalonia.Gtk3.Interop
public static D.gdk_cairo_create GdkCairoCreate;
public static D.cairo_image_surface_create CairoImageSurfaceCreate;
public static D.cairo_image_surface_create_for_data CairoImageSurfaceCreateForData;
public static D.cairo_image_surface_get_data CairoImageSurfaceGetData;
public static D.cairo_image_surface_get_stride CairoImageSurfaceGetStride;
public static D.cairo_surface_mark_dirty CairoSurfaceMarkDirty;

132
src/Shared/PlatformSupport/StandardRuntimePlatform.cs

@ -2,8 +2,11 @@
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Resources;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Threading;
using Avalonia.Platform;
@ -18,8 +21,135 @@ namespace Avalonia.Shared.PlatformSupport
return new Timer(_ => tick(), null, interval, interval);
}
public string GetStackTrace() => Environment.StackTrace;
public IUnmanagedBlob AllocBlob(int size) => new UnmanagedBlob(this, size);
class UnmanagedBlob : IUnmanagedBlob
{
private readonly StandardRuntimePlatform _plat;
#if DEBUG
private static readonly List<string> Backtraces = new List<string>();
private static Thread GCThread;
private readonly string _backtrace;
public string GetStackTrace() => Environment.StackTrace;
class GCThreadDetector
{
~GCThreadDetector()
{
GCThread = Thread.CurrentThread;
}
}
[MethodImpl(MethodImplOptions.NoInlining)]
static void Spawn() => new GCThreadDetector();
static UnmanagedBlob()
{
Spawn();
GC.WaitForPendingFinalizers();
}
#endif
public UnmanagedBlob(StandardRuntimePlatform plat, int size)
{
_plat = plat;
Address = plat.Alloc(size);
GC.AddMemoryPressure(size);
Size = size;
#if DEBUG
_backtrace = Environment.StackTrace;
Backtraces.Add(_backtrace);
#endif
}
void DoDispose()
{
if (!IsDisposed)
{
Backtraces.Remove(_backtrace);
_plat.Free(Address, Size);
GC.RemoveMemoryPressure(Size);
IsDisposed = true;
Address = IntPtr.Zero;
}
}
public void Dispose()
{
#if DEBUG
if (Thread.CurrentThread.ManagedThreadId == GCThread?.ManagedThreadId)
{
Console.Error.WriteLine("Native blob disposal from finalizer thread\nBacktrace: "
+ Environment.StackTrace
+ "\n\nBlob created by " + _backtrace);
}
#endif
DoDispose();
GC.SuppressFinalize(this);
}
~UnmanagedBlob()
{
#if DEBUG
Console.Error.WriteLine("Undisposed native blob created by " + _backtrace);
#endif
DoDispose();
}
public IntPtr Address { get; private set; }
public int Size { get; private set; }
public bool IsDisposed { get; private set; }
}
#if FULLDOTNET || DOTNETCORE
[DllImport("libc", SetLastError = true)]
private static extern IntPtr mmap(IntPtr addr, IntPtr length, int prot, int flags, int fd, IntPtr offset);
[DllImport("libc", SetLastError = true)]
private static extern int munmap(IntPtr addr, IntPtr length);
[DllImport("libc", SetLastError = true)]
private static extern long sysconf(int name);
private bool? _useMmap;
private bool UseMmap
=> _useMmap ?? ((_useMmap = GetRuntimeInfo().OperatingSystem == OperatingSystemType.Linux)).Value;
IntPtr Alloc(int size)
{
if (UseMmap)
{
var rv = mmap(IntPtr.Zero, new IntPtr(size), 3, 0x22, -1, IntPtr.Zero);
if (rv.ToInt64() == -1 || (ulong) rv.ToInt64() == 0xffffffff)
{
var errno = Marshal.GetLastWin32Error();
throw new Exception("Unable to allocate memory: " + errno);
}
return rv;
}
else
return Marshal.AllocHGlobal(size);
}
void Free(IntPtr ptr, int len)
{
if (UseMmap)
{
if (munmap(ptr, new IntPtr(len)) == -1)
{
var errno = Marshal.GetLastWin32Error();
throw new Exception("Unable to free memory: " + errno);
}
}
else
Marshal.FreeHGlobal(ptr);
}
#else
IntPtr Alloc(int size) => Marshal.AllocHGlobal(size);
void Free(IntPtr ptr, int len) => Marshal.FreeHGlobal(ptr);
#endif
}
}

13
src/Skia/Avalonia.Skia/BitmapImpl.cs

@ -20,6 +20,13 @@ namespace Avalonia.Skia
_dpi = new Vector(96, 96);
}
static void ReleaseProc(IntPtr address, object ctx)
{
((IUnmanagedBlob) ctx).Dispose();
}
private static readonly SKBitmapReleaseDelegate ReleaseDelegate = ReleaseProc;
public BitmapImpl(int width, int height, Vector dpi, PixelFormat? fmt = null)
{
PixelHeight = height;
@ -29,6 +36,12 @@ namespace Avalonia.Skia
var runtime = AvaloniaLocator.Current?.GetService<IRuntimePlatform>()?.GetRuntimeInfo();
if (runtime?.IsDesktop == true && runtime?.OperatingSystem == OperatingSystemType.Linux)
colorType = SKColorType.Bgra8888;
Bitmap = new SKBitmap();
var nfo = new SKImageInfo(width, height, colorType, SKAlphaType.Premul);
var plat = AvaloniaLocator.Current.GetService<IRuntimePlatform>();
var blob = plat.AllocBlob(nfo.BytesSize);
Bitmap.InstallPixels(nfo, blob.Address, nfo.RowBytes, null, ReleaseDelegate, blob);
Bitmap = new SKBitmap(width, height, colorType, SKAlphaType.Premul);
Bitmap.Erase(SKColor.Empty);
}

Loading…
Cancel
Save