1
\$\begingroup\$

I'm writing a Unity plugin which uses WPF for UI , Plugin runs in same process of Unity and has direct access to unity's memory.

Unity Code :

    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);
        }

Now in my wpf app I get the texture pointer and properties are right, it has B8G8R8A8_Typeless format with ShaderResource and RenderTarget bind flags and I write it to file and it's fine.

To show it in WPF I need this texture be OptionFlags.Shared So i tried to copy it like this (using 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();

Result is black but it throws no error using SharpDX.WPF.

I found new wpf directx 11 D3DImage from Microsoft can be find here : https://github.com/microsoft/WPFDXInterop

WPF Global Objects :

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

WPF Startup Code :

                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 Function Code :

 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();
        }

This code works fine but I have no idea how can I use my unity render texture to place in DoRender function without any copying or extra steps.

Performance is very important to me, I don't want to leave extra memory blocks or footprints.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.