public override void OnApplyTemplate()
        {
            var window = Window.GetWindow(this);

            _windowHandle = window is null ? IntPtr.Zero : new WindowInteropHelper(window).Handle;
            _hwnd         = new HwndSource(0, 0, 0, 0, 0, "Offscreen Window", _windowHandle);
            _windowInfo   = Utilities.CreateWindowsWindowInfo(_hwnd.Handle);

            _wpfImage = new Image()
            {
                RenderTransformOrigin = new Point(0.5, 0.5),
                RenderTransform       = new ScaleTransform(1, -1)
            };

            var grid = new Grid();

            _framesTextBlock = new TextBlock()
            {
                HorizontalAlignment = HorizontalAlignment.Left,
                VerticalAlignment   = VerticalAlignment.Top,
                Margin     = new Thickness(5),
                Foreground = new SolidColorBrush(Colors.Blue),
                FontWeight = FontWeights.Bold
            };
            Panel.SetZIndex(_framesTextBlock, 1);

            grid.Children.Add(_framesTextBlock);
            grid.Children.Add(_wpfImage);
            AddChild(grid);

            switch (UpdateStrategy)
            {
            case UpdateStrategy.WriteableBitmapImage:
                _updateStrategy = new UpdateStrategyWriteableBitmap();
                break;

            case UpdateStrategy.D3DSurface:
                _updateStrategy = new UpdateStrategyD3D();
                break;
            }

            if (UseSeperateRenderThread)
            {
                _cts          = new CancellationTokenSource();
                _renderThread = new Thread((object boxedToken) =>
                {
                    InitOpenGLContext();
                    while (!_cts.IsCancellationRequested)
                    {
                        UpdateFramerate();
                        if (_wasResized)
                        {
                            _wasResized = false;
                            _updateStrategy.Resize((int)Math.Round(ActualWidth), (int)Math.Round(ActualHeight));
                            Dispatcher.Invoke(() => _wpfImage.Source = _updateStrategy.CreateImageSource());
                        }

                        GLRender?.Invoke(this, EventArgs.Empty);
                        _updateStrategy?.Draw();
                        Dispatcher.Invoke(() => _updateStrategy.InvalidateImageSource());
                    }

                    _renderThread.Join();
                })
                {
                    IsBackground = true, Priority = ThreadPriority.Highest
                };
                _renderThread.Start(_cts);
                _stopwatch.Start();
            }
            else
            {
                _dt = new DispatcherTimer(DispatcherPriority.Send)
                {
                    Interval = TimeSpan.FromMilliseconds(1)
                };
                InitOpenGLContext();
                _dt.Tick += (o, e) =>
                {
                    UpdateFramerate();
                    if (_wasResized)
                    {
                        _wasResized = false;
                        _updateStrategy.Resize((int)Math.Round(ActualWidth), (int)Math.Round(ActualHeight));
                        _wpfImage.Source = _updateStrategy.CreateImageSource();
                    }

                    GLRender?.Invoke(this, EventArgs.Empty);
                    _updateStrategy.Draw();
                    _updateStrategy.InvalidateImageSource();
                };
                _dt.Start();
                _stopwatch.Start();
            }

            base.OnApplyTemplate();
        }
        private void OnLoaded(object sender, RoutedEventArgs e)
        {
            if (!DesignerProperties.GetIsInDesignMode(new DependencyObject()))
            {
                Window.GetWindow(this).Closing += (ss, ee) => { mCts?.Cancel(); }
            }
            ;

            var ptr = DXInterop.Direct3DCreate9(DXInterop.D3D_SDK_VERSION);



            var window = Window.GetWindow(this);

            mWndHandle       = window is null ? IntPtr.Zero : new WindowInteropHelper(window).Handle;
            mHwnd            = new HwndSource(0, 0, 0, 0, 0, "Offscreen Window", mWndHandle);
            mWindowInfo      = Utilities.CreateWindowsWindowInfo(mHwnd.Handle);
            mTargetFramerate = FramerateLimit > 0 ? TimeSpan.FromMilliseconds(1000.0d / FramerateLimit) : TimeSpan.Zero;

            switch (UpdateStrategy)
            {
            case UpdateStrategy.WriteableBitmapImage:
                mUpdateStrategy = new UpdateStrategyWriteableBitmap();
                break;

            case UpdateStrategy.D3DImage:
                mUpdateStrategy = new UpdateStrategyD3D();
                break;
            }

            mRenderTread = new Thread((object boxedToken) =>
            {
                InitOpenGLContext();
                while (!mCts.IsCancellationRequested)
                {
                    ++mFrames;
                    if (mWasResized)
                    {
                        mWasResized = false;
                        mUpdateStrategy.Resize((int)Math.Round(ActualWidth), (int)Math.Round(ActualHeight));
                        Dispatcher.Invoke(() => mRenderedImg = mUpdateStrategy.CreateImageSource());
                    }

                    var rt    = Render();
                    var sleep = mTargetFramerate - rt;

                    mAccumulatedDt += rt;

                    if (FramerateLimit > 0)
                    {
                        mAccumulatedDt += sleep;
                    }

                    if (mAccumulatedDt >= TimeSpan.FromSeconds(1))
                    {
                        mLastFrames    = mFrames;
                        mFrames        = 0;
                        mAccumulatedDt = TimeSpan.Zero;
                    }

                    if (FramerateLimit > 0)
                    {
                        Thread.Sleep(sleep > TimeSpan.Zero ? sleep : TimeSpan.Zero);
                    }

                    Dispatcher.Invoke(() => InvalidateVisual());
                }

                mRenderTread.Join();
            })
            {
                IsBackground = true
            };
            mRenderTread.Start(mCts);
        }