Browse Source

Use multimedia timer on Win32 for render loop.

pull/773/head
Steven Kirk 10 years ago
parent
commit
e190cb4e8c
  1. 7
      src/Avalonia.SceneGraph/Rendering/DefaultRenderLoop.cs
  2. 12
      src/Avalonia.SceneGraph/Rendering/Renderer.cs
  3. 1
      src/Windows/Avalonia.Win32/Avalonia.Win32.csproj
  4. 10
      src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs
  5. 35
      src/Windows/Avalonia.Win32/RenderLoop.cs
  6. 2
      src/Windows/Avalonia.Win32/Win32Platform.cs

7
src/Avalonia.SceneGraph/Rendering/DefaultRenderLoop.cs

@ -65,24 +65,25 @@ namespace Avalonia.Rendering
/// </summary>
protected void Start()
{
_subscription = StartCore();
_subscription = StartCore(InternalTick);
}
/// <summary>
/// Provides the implementation of starting the timer.
/// </summary>
/// <param name="tick">The method to call on each tick.</param>
/// <remarks>
/// This can be overridden by platform implementations to use a specialized timer
/// implementation.
/// </remarks>
protected virtual IDisposable StartCore()
protected virtual IDisposable StartCore(Action tick)
{
if (_threading == null)
{
_threading = AvaloniaLocator.Current.GetService<IPlatformThreadingInterface>();
}
return _threading.StartTimer(TimeSpan.FromSeconds(1.0 / FramesPerSecond), InternalTick);
return _threading.StartTimer(TimeSpan.FromSeconds(1.0 / FramesPerSecond), tick);
}
/// <summary>

12
src/Avalonia.SceneGraph/Rendering/Renderer.cs

@ -13,6 +13,7 @@ namespace Avalonia.Rendering
private IRenderRoot _root;
private IRenderTarget _renderTarget;
private bool _dirty;
private bool _rendering;
public void Attach(IRenderRoot root, IRenderLoop renderLoop)
{
@ -35,6 +36,11 @@ namespace Avalonia.Rendering
public void Render(Rect rect)
{
if (_rendering)
{
return;
}
if (_renderTarget == null)
{
_renderTarget = _root.CreateRenderTarget();
@ -42,6 +48,7 @@ namespace Avalonia.Rendering
try
{
_rendering = true;
_renderTarget.Render(_root);
}
catch (RenderTargetCorruptedException ex)
@ -50,6 +57,11 @@ namespace Avalonia.Rendering
_renderTarget.Dispose();
_renderTarget = null;
}
finally
{
_rendering = false;
_dirty = false;
}
}
private void OnRenderLoopTick(object sender, EventArgs e)

1
src/Windows/Avalonia.Win32/Avalonia.Win32.csproj

@ -70,6 +70,7 @@
</Compile>
<Compile Include="Embedding\WpfAvaloniaControlHost.cs" />
<Compile Include="IconImpl.cs" />
<Compile Include="RenderLoop.cs" />
<Compile Include="SystemDialogImpl.cs" />
<Compile Include="CursorFactory.cs" />
<Compile Include="Input\KeyInterop.cs" />

10
src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs

@ -23,6 +23,8 @@ namespace Avalonia.Win32.Interop
public delegate void TimerProc(IntPtr hWnd, uint uMsg, IntPtr nIDEvent, uint dwTime);
public delegate void TimeCallback(uint uTimerID, uint uMsg, UIntPtr dwUser, UIntPtr dw1, UIntPtr dw2);
public delegate IntPtr WndProc(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam);
public enum Cursor
@ -705,8 +707,6 @@ namespace Avalonia.Win32.Interop
[DllImport("user32.dll")]
public static extern IntPtr LoadCursor(IntPtr hInstance, IntPtr lpCursorName);
[DllImport("user32.dll")]
public static extern bool PeekMessage(out MSG lpMsg, IntPtr hWnd, uint wMsgFilterMin, uint wMsgFilterMax, uint wRemoveMsg);
@ -738,6 +738,12 @@ namespace Avalonia.Win32.Interop
[DllImport("user32.dll")]
public static extern bool ShowWindow(IntPtr hWnd, ShowWindowCommand nCmdShow);
[DllImport("Winmm.dll")]
public static extern uint timeKillEvent(uint uTimerID);
[DllImport("Winmm.dll")]
public static extern uint timeSetEvent(uint uDelay, uint uResolution, TimeCallback lpTimeProc, UIntPtr dwUser, uint fuEvent);
[DllImport("user32.dll")]
public static extern int ToUnicode(
uint virtualKeyCode,

35
src/Windows/Avalonia.Win32/RenderLoop.cs

@ -0,0 +1,35 @@
using System;
using System.Reactive.Disposables;
using Avalonia.Rendering;
using Avalonia.Win32.Interop;
namespace Avalonia.Win32
{
internal class RenderLoop : DefaultRenderLoop
{
private UnmanagedMethods.TimeCallback timerDelegate;
public RenderLoop(int framesPerSecond)
: base(framesPerSecond)
{
}
protected override IDisposable StartCore(Action tick)
{
timerDelegate = (id, uMsg, user, dw1, dw2) => tick();
var handle = UnmanagedMethods.timeSetEvent(
(uint)(1000 / FramesPerSecond),
0,
timerDelegate,
UIntPtr.Zero,
1);
return Disposable.Create(() =>
{
timerDelegate = null;
UnmanagedMethods.timeKillEvent(handle);
});
}
}
}

2
src/Windows/Avalonia.Win32/Win32Platform.cs

@ -66,7 +66,7 @@ namespace Avalonia.Win32
.Bind<IMouseDevice>().ToConstant(WindowsMouseDevice.Instance)
.Bind<IPlatformSettings>().ToConstant(s_instance)
.Bind<IPlatformThreadingInterface>().ToConstant(s_instance)
.Bind<IRenderLoop>().ToConstant(new DefaultRenderLoop(60))
.Bind<IRenderLoop>().ToConstant(new RenderLoop(60))
.Bind<ISystemDialogImpl>().ToSingleton<SystemDialogImpl>()
.Bind<IWindowingPlatform>().ToConstant(s_instance)
.Bind<IPlatformIconLoader>().ToConstant(s_instance);

Loading…
Cancel
Save