Оптимизированный способ отображения Unity RenderTexture в WPF с использованием SharpDX - PullRequest
0 голосов
/ 10 апреля 2020

Я пишу плагин Unity, который использует WPF для пользовательского интерфейса, плагин работает в том же процессе Unity и имеет прямой доступ к памяти Unity.

Код Unity:

    render_rt_desc = new RenderTextureDescriptor(300, 300, RenderTextureFormat.BGRA32);
    render_rt = new RenderTexture(render_rt_desc);
    rendering_camera.targetTexture = render_rt;
    rendering_camera.Render();
    render_pointer = t2d_format.GetNativeTexturePtr();

    if (WPFWindow.IsWindowValid)
        {
            WPFWindow.UpdateImagePointer(render_pointer);
        }

Теперь в моем приложении wpf я получаю указатель текстуры и свойства правильные, он имеет формат B8G8R8A8_Typeless с ShaderResource и RenderTarget , привязывают флаги и я запишите его в файл, и это нормально.

Чтобы показать его в WPF, мне нужна эта текстура OptionFlags.Shared Поэтому я попытался скопировать ее следующим образом (используя https://github.com/Marlamin/SharpDX.WPF):

    Device wpfdevice = new Device(SharpDX.Direct3D.DriverType.Hardware,DeviceCreationFlags.BgraSupport);

    Texture2D dx11t2D = CppObject.FromPointer<Texture2D>(Dx11Textureptr); /// pointer from unity

    Texture2DDescription texture2DDescription = dx11t2D.Description;
    texture2DDescription.OptionFlags = ResourceOptionFlags.Shared;
    texture2DDescription.BindFlags = BindFlags.ShaderResource | BindFlags.RenderTarget;
    texture2DDescription.Format = SharpDX.DXGI.Format.B8G8R8A8_UNorm;

    Texture2D sharedt2d = new Texture2D(wpfdevice, texture2DDescription); 

    Device d3d11device = dx11t2D.QueryInterface<DeviceChild>().Device;
    d3d11device.ImmediateContext.CopyResource(dx11t2D, sharedt2d);

    DXImageSource dXImageSource = new DXImageSource();
                dXImageSource.Lock();
                dx_output.Source = dXImageSource;
                dXImageSource.SetBackBuffer(sharedt2d);
                dXImageSource.Unlock();

Результат черный, но он не выдает ошибку с помощью SharpDX.WPF.

Я нашел новый wpf directx 11 D3DImage от Microsoft, который можно найти здесь: https://github.com/microsoft/WPFDXInterop

Глобальные объекты WPF:

        IntPtr _resourcePointer;
        SharpDX.Direct3D11.Device _device;
        SwapChain _swapChain;
        RenderTargetView _renderTargetView;

Код запуска WPF:

                var _swapChainDescription = new SwapChainDescription();
                _swapChainDescription.OutputHandle = new WindowInteropHelper(this).Handle;
                _swapChainDescription.BufferCount = 1;
                _swapChainDescription.Flags = SwapChainFlags.AllowModeSwitch;
                _swapChainDescription.IsWindowed = true;
                _swapChainDescription.ModeDescription = new ModeDescription(0, 0, new Rational(60, 1), Format.B8G8R8A8_UNorm);
                _swapChainDescription.SampleDescription = new SampleDescription(1, 0);
                _swapChainDescription.SwapEffect = SwapEffect.Discard;
                _swapChainDescription.Usage = Usage.RenderTargetOutput | Usage.Shared;

                var flags = DeviceCreationFlags.BgraSupport;
                Device.CreateWithSwapChain(SharpDX.Direct3D.DriverType.Hardware,
                    flags, _swapChainDescription, out _device, out _swapChain);

                InteropImage.SetPixelSize(300, 300);

                InteropImage.WindowOwner = new WindowInteropHelper(this).Handle;
                InteropImage.OnRender = this.xRENDER;
                InteropImage.RequestRender();

                dx_output.Source = InteropImage;

DoRender Код функции:

 void DoRender(IntPtr resourcePointer)
        {
            if (_resourcePointer != resourcePointer)
            {
                if (_resourcePointer != IntPtr.Zero)
                {
                    _renderTargetView.Dispose();
                    _renderTargetView = null;
                }

                _resourcePointer = resourcePointer;
            }
            else
            {
                var texture = _renderTargetView.ResourceAs<SharpDX.Direct3D11.Texture2D>();
                if (texture.Description.Width != (int)this.ActualWidth || texture.Description.Height != (int)this.ActualHeight)
                {
                    _renderTargetView.Dispose();
                    _renderTargetView = null;
                }
            }

            if (_renderTargetView == null)
            {
                SharpDX.DXGI.Resource dxgiResource;
                using (var r = new SharpDX.ComObject(resourcePointer))
                {
                    dxgiResource = r.QueryInterface<SharpDX.DXGI.Resource>();
                }

                var directx11Texture = _device.OpenSharedResource<Texture2D>(dxgiResource.SharedHandle);
                _renderTargetView = new RenderTargetView(_device, directx11Texture);
            }

            _device.ImmediateContext.Rasterizer.SetViewport(0, 0, (float)this.ActualWidth, (float)this.ActualHeight, 0.0f, 1.0f);
            _device.ImmediateContext.OutputMerger.SetRenderTargets(_renderTargetView);
            _device.ImmediateContext.ClearRenderTargetView(_renderTargetView, new SharpDX.Color4(0.7f, 0.5f, 0.2f, 1.0f));
            _device.ImmediateContext.Flush();
        }

Этот код работает нормально но я понятия не имею, как я могу использовать мою текстуру рендеринга для размещения в функции DoRender без копирования или дополнительных шагов.

* 10 41 * Производительность очень важна для меня, я не хочу оставлять лишние блоки памяти или следы.
...