7 changed files with 169 additions and 1 deletions
@ -0,0 +1,84 @@ |
|||
#include "common.h" |
|||
|
|||
class PlatformRenderTimer : public ComSingleObject<IAvnPlatformRenderTimer, &IID_IAvnPlatformRenderTimer> |
|||
{ |
|||
private: |
|||
ComPtr<IAvnActionCallback> _callback; |
|||
CVDisplayLinkRef _displayLink; |
|||
|
|||
public: |
|||
FORWARD_IUNKNOWN() |
|||
virtual HRESULT RegisterTick ( |
|||
IAvnActionCallback* callback) override |
|||
{ |
|||
START_COM_CALL; |
|||
|
|||
@autoreleasepool |
|||
{ |
|||
if (_displayLink != nil) |
|||
{ |
|||
return E_UNEXPECTED; |
|||
} |
|||
|
|||
_callback = callback; |
|||
auto result = CVDisplayLinkCreateWithActiveCGDisplays(&_displayLink); |
|||
if (result != 0) |
|||
{ |
|||
return E_FAIL; |
|||
} |
|||
|
|||
result = CVDisplayLinkSetOutputCallback(_displayLink, OnTick, this); |
|||
if (result != 0) |
|||
{ |
|||
return E_FAIL; |
|||
} |
|||
} |
|||
return S_OK; |
|||
} |
|||
|
|||
virtual void Start () override |
|||
{ |
|||
START_COM_CALL; |
|||
|
|||
@autoreleasepool |
|||
{ |
|||
if (CVDisplayLinkIsRunning(_displayLink) == false) { |
|||
CVDisplayLinkStart(_displayLink); |
|||
} |
|||
} |
|||
} |
|||
|
|||
virtual void Stop () override |
|||
{ |
|||
START_COM_CALL; |
|||
|
|||
@autoreleasepool |
|||
{ |
|||
if (CVDisplayLinkIsRunning(_displayLink) == true) { |
|||
CVDisplayLinkStop(_displayLink); |
|||
} |
|||
} |
|||
} |
|||
|
|||
virtual bool RunsInBackground () override |
|||
{ |
|||
START_COM_CALL; |
|||
|
|||
@autoreleasepool |
|||
{ |
|||
return true; |
|||
} |
|||
} |
|||
|
|||
static CVReturn OnTick(CVDisplayLinkRef displayLink, const CVTimeStamp *inNow, const CVTimeStamp *inOutputTime, CVOptionFlags flagsIn, CVOptionFlags *flagsOut, void *displayLinkContext) |
|||
{ |
|||
PlatformRenderTimer *object = (PlatformRenderTimer *)displayLinkContext; |
|||
object->_callback->Run(); |
|||
return kCVReturnSuccess; |
|||
} |
|||
}; |
|||
|
|||
extern IAvnPlatformRenderTimer* CreatePlatformRenderTimer() |
|||
{ |
|||
return new PlatformRenderTimer(); |
|||
} |
|||
@ -0,0 +1,58 @@ |
|||
using System; |
|||
using System.Diagnostics; |
|||
using Avalonia.Native.Interop; |
|||
using Avalonia.Rendering; |
|||
#nullable enable |
|||
|
|||
namespace Avalonia.Native; |
|||
|
|||
internal sealed class AvaloniaNativeRenderTimer : NativeCallbackBase, IRenderTimer, IAvnActionCallback |
|||
{ |
|||
private readonly IAvnPlatformRenderTimer _platformRenderTimer; |
|||
private readonly Stopwatch _stopwatch; |
|||
private Action<TimeSpan>? _tick; |
|||
private int _subscriberCount; |
|||
private bool registered; |
|||
|
|||
public AvaloniaNativeRenderTimer(IAvnPlatformRenderTimer platformRenderTimer) |
|||
{ |
|||
_platformRenderTimer = platformRenderTimer; |
|||
_stopwatch = Stopwatch.StartNew(); |
|||
} |
|||
|
|||
public event Action<TimeSpan> Tick |
|||
{ |
|||
add |
|||
{ |
|||
_tick += value; |
|||
|
|||
if (!registered) |
|||
{ |
|||
registered = true; |
|||
_platformRenderTimer.RegisterTick(this); |
|||
} |
|||
|
|||
if (_subscriberCount++ == 0) |
|||
{ |
|||
_platformRenderTimer.Start(); |
|||
} |
|||
} |
|||
|
|||
remove |
|||
{ |
|||
if (--_subscriberCount == 0) |
|||
{ |
|||
_platformRenderTimer.Stop(); |
|||
} |
|||
|
|||
_tick -= value; |
|||
} |
|||
} |
|||
|
|||
public bool RunsInBackground => _platformRenderTimer.RunsInBackground().FromComBool(); |
|||
|
|||
public void Run() |
|||
{ |
|||
_tick?.Invoke(_stopwatch.Elapsed); |
|||
} |
|||
} |
|||
Loading…
Reference in new issue