WPF 창에서 DirectX12 애플리케이션을 호스팅하는 방법이 있습니까?

FinnTheHuman

나는이 질문의 용어가 모두 틀 렸음에 틀림 없다는 것을 압니다. 그러나 제 평신도의 관점에서 사물을 보려고 노력하십시오. (저는 컴퓨터 기술에 대한 형성이없고, 독학적인 열광 자입니다. 프로그래밍 언어에 대한 공식 교육은 우리 학교의 로봇 공학 클럽입니다).

내가 원하는 것은 게임 루프와 모든 것을 포함하여 관리되는 DirectX 12를 내 응용 프로그램의 "배경"으로 사용할 수있는 것입니다. 그리고 가능하다면 리본이나 도구 상자 또는 실제 directX 게임 주변의 메뉴와 같은 WPF 컨트롤을 가질 수 있습니다. 저는 인터넷을 통해 찾아 봤는데 Windows와 DirectX 9.0을위한 아주 오래된 것뿐입니다. 요즘 뭔가 새로운 것이 있기를 바라고 있습니다.

기본적으로 다음과 같은 Windows Form 접근 방식을 시도했습니다.

using System;
using System.Windows;
using System.Windows.Interop;
using Microsoft.DirectX.Direct3D;
using DColor = System.Drawing.Color;

public partial class MainWindow : Window
{
    Device device;
    public MainWindow()
    {
        InitializeComponent();
        initDevice();
    }

    private void initDevice()
    {
        try
        {
            PresentParameters parameters = new PresentParameters();
            parameters.Windowed = true;
            parameters.SwapEffect = SwapEffect.Discard;
            IntPtr windowHandle = new WindowInteropHelper(this).Handle;

            device = new Device(0, DeviceType.Hardware, windowHandle, CreateFlags.HardwareVertexProcessing, parameters);
        }
        catch(Exception e)
        {
            MessageBox.Show("initDevice threw an Exception\n" + e.Message, "ERROR", MessageBoxButton.OK, MessageBoxImage.Error);
        }
    }

    private void render()
    {
        device.Clear(ClearFlags.Target, DColor.LightGreen, 0f, 1);
        device.Present();
    }
}

예외가 발생하지 않으며 창은 전혀 렌더링되지 않습니다. 응용 프로그램이 실행되지만 창이 표시되지 않습니다. 게임 루프 render가없고 어디에서나 호출되지 않기 때문에 이것이 작동하지 않을 것이라고 생각 했지만 창이 표시되지 않을 것이라고는 예상하지 못했습니다. initDevice ()를 호출하는 줄을 주석 처리하면 WPF의 빈 창이 정상적으로 표시됩니다.

그런 다음 CompositionTarget.Rendering이벤트가 매 프레임 (또는 틱?)마다 한 번씩 호출 된다는 사실을 발견 했으므로이 이벤트에 대한 처리기를 게임 루프로 사용해야합니다.

그래서 나는 이것을 시도했습니다.

using System;
using System.Drawing;
using System.IO;
using System.Windows;
using System.Windows.Media;
using System.Windows.Forms.Integration;
using Microsoft.DirectX.Direct3D;
using DColor = System.Drawing.Color;
using System.Windows.Forms;

public partial class MainWindow : Window
{
    Device device = null;
    MemoryStream stream;
    PictureBox display;
    WindowsFormsHost host;

    public MainWindow()
    {
        InitializeComponent();
        initDevice();
        CompositionTarget.Rendering += CompositionTarget_Rendering;
    }

    private void CompositionTarget_Rendering(object sender, EventArgs e)
    {
        render();
    }

    private void initDevice()
    {
        try
        {
            PresentParameters parameters = new PresentParameters();
            parameters.Windowed = true;
            parameters.SwapEffect = SwapEffect.Discard;

            device = new Device(0, DeviceType.Hardware, display, CreateFlags.HardwareVertexProcessing, parameters);
            stream = new MemoryStream();
            device.SetRenderTarget(0, new Surface(device, stream, Pool.Managed));
        }
        catch(Exception e)
        {
            System.Windows.MessageBox.Show("initDevice threw an Exception\n" + e.Message, "ERROR", MessageBoxButton.OK, MessageBoxImage.Error);
        }
    }

    private void render()
    {
        device.Clear(ClearFlags.Target, DColor.LightGreen, 0f, 1);
        device.Present();
        display.Image = Image.FromStream(stream);
    }

    private void Window_Loaded(object sender, RoutedEventArgs e)
    {
        host = new WindowsFormsHost();
        display = new PictureBox();
        host.Child = display;
        mainGrid.Children.Add(host);
    }
}

응용 프로그램이 실행 중이고 충돌하지 않는 경우에도 여전히 창이 표시되지 않습니다.

마지막으로 동일한 작업을 시도했지만 처리하지 않고 CompositionTarget.Rendering대신 DispatcherTimer를 사용하고 Tick이벤트 처리기 내부에서 render를 호출했습니다 . 동일한 결과 : 창이 없습니다.

누구든지 올바른 방향으로 나를 가리킬 수 있습니까?

신체 상해 50

나는 그것이 오래된 게시물이라는 것을 알고 있지만 해결책을 찾는 사람들을 위해 내가 찾은 것이 있습니다. 솔루션은 Chuck이 언급 한 프로젝트의 D3D11Image를 기반으로합니다.

1. Window_Loaded_Event에서 :

    private void Window_Loaded(object sender, RoutedEventArgs e) {
        InitDx12();
        CreateDx11Stuff();

        DxImage.SetPixelSize(1280, 720);
        DxImage.WindowOwner = (new System.Windows.Interop.WindowInteropHelper(this)).Handle;
        DxImage.OnRender += Render;
        CompositionTarget.Rendering += CompositionTarget_Rendering;
    }

2. Dx11 물건 만들기 :

private void CreateDx11Stuff() {
        D3D11Device = SharpDX.Direct3D11.Device.CreateFromDirect3D12(D3D12Device, SharpDX.Direct3D11.DeviceCreationFlags.BgraSupport | SharpDX.Direct3D11.DeviceCreationFlags.Debug, new[] { SharpDX.Direct3D.FeatureLevel.Level_12_1 }, Adatper, CommandQueue);

        D3D11On12 = ComObject.QueryInterfaceOrNull<SharpDX.Direct3D11.Device11On12>(D3D11Device.NativePointer);                       

        for(int idx = 0; idx < BackBufferCount; idx++) {
            D3D11On12.CreateWrappedResource(BackBuffers[idx], new D3D11ResourceFlags { BindFlags = (int)BindFlags.RenderTarget, CPUAccessFlags = 0, MiscFlags = (int)0x2L, StructureByteStride = 0 }, (int)ResourceStates.RenderTarget, (int)ResourceStates.Present, typeof(Texture2D).GUID, out D3D11BackBuffers[idx]);
        }
    }

3. CompositionTarget Rendering : 매우 간단합니다.

private void CompositionTarget_Rendering(object sender, EventArgs e) {
        DxImage.RequestRender();
    }

4. 렌더링 기능 :

private void Render(IntPtr surface, bool newSurface) {
        DoDx12Rendering();

        var unk = new ComObject(surface);
        var dxgiRes = unk.QueryInterface<SharpDX.DXGI.Resource>();

        var tempRes = D3D11Device.OpenSharedResource<SharpDX.Direct3D11.Resource>(dxgiRes.SharedHandle);
        var backBuffer = tempRes.QueryInterface<Texture2D>();
        var d3d11BackBuffer = D3D11BackBuffers[CurrentFrame];

        D3D11On12.AcquireWrappedResources(new[] { d3d11BackBuffer }, 1);
        D3D11Device.ImmediateContext.CopyResource(d3d11BackBuffer, backBuffer);
        D3D11Device.ImmediateContext.Flush();
        D3D11On12.ReleaseWrappedResources(new[] { d3d11BackBuffer }, 1);
    }

보너스

컴포지션 대상 이벤트없이 렌더링 할 수도 있습니다. 이를 위해 Render 콜백-> void Render (IntPtr surface, bool newSurface)에서 표면의 핸들을 저장합니다.

이를 위해 DxImage.RequestRender ()를 호출하십시오.

렌더링 루프에서 렌더링하고 끝에 D3D11on12를 D3D11 사본에 추가합니까?

노트

크기 조정 이벤트를 처리하는 경우 DxImage.SetPixelSize를 사용하여 DxImage의 크기를 조정 한 다음 래핑 된 리소스를 다시 만듭니다.

더 많은 설명

다음과 같이 장치를 만듭니다.

_D3D9Device = new DeviceEx(new Direct3DEx(), 0, DeviceType.Hardware, handle, CreateFlags.HardwareVertexProcessing | CreateFlags.Multithreaded | CreateFlags.FpuPreserve, new SharpDX.Direct3D9.PresentParameters(1, 1) {
            Windowed = true,
            SwapEffect = SharpDX.Direct3D9.SwapEffect.Discard,
            DeviceWindowHandle = handle,
            PresentationInterval = PresentInterval.Immediate
        });


_D3D11Device = SharpDX.Direct3D11.Device.CreateFromDirect3D12(Device, DeviceCreationFlags.BgraSupport, new[] { SharpDX.Direct3D.FeatureLevel.Level_12_0 }, null, RenderCommandQueue);

그리고 다음과 같이 Dx11 및 Dx9 FBO를 만듭니다.

private void CreateWPFInteropFBO()
    {
        var desc = new Texture2DDescription {
            ArraySize = 1,
            BindFlags = BindFlags.RenderTarget,
            Format = SharpDX.DXGI.Format.B8G8R8A8_UNorm,
            Height = RenderTargetSize.Height,
            Width = RenderTargetSize.Width,
            MipLevels = 1,
            OptionFlags = ResourceOptionFlags.Shared,
            SampleDescription = new SharpDX.DXGI.SampleDescription(1, 0),
            Usage = ResourceUsage.Default
        };

        Dx11Texture?.Dispose();

        Dx11Texture = new Texture2D(_D3D11Device, desc);

        var ptr = Dx11Texture.NativePointer;
        var comobj = new ComObject(ptr);
        using (var dxgiRes = comobj.QueryInterface<SharpDX.DXGI.Resource>()) {
            var sharedHandle = dxgiRes.SharedHandle;

            var texture = new Texture(_D3D9Device, desc.Width, desc.Height, 1, SharpDX.Direct3D9.Usage.RenderTarget, SharpDX.Direct3D9.Format.A8R8G8B8, Pool.Default, ref sharedHandle);

            Dx9Surface?.Dispose();
            Dx9Surface = texture.GetSurfaceLevel(0);
        }
    }

사실 그들은 동일합니다. 그런 다음 렌더링 후 Dx12 RenderTarget을 Dx11 RenderTarget에 복사합니다.

        var ptr = GetDx12ResourceFromHandle(Resources.Dx11Texture.NativePointer);
        commandList.CopyResource(ptr, Resources.RenderTarget);

내 RenderLoop에서 다음과 같이 BackBuffer를 업데이트합니다.

private async void UpdateDx9Image()
    {
        if (Application.Current == null) return;

        await Application.Current?.Dispatcher.BeginInvoke(DispatcherPriority.Render, new Action(() =>
        {
            if (DxImage.TryLock(new Duration(new TimeSpan(0, 0, 0, 0, 16))))
            {
                DxImage.SetBackBuffer(D3DResourceType.IDirect3DSurface9, _Renderer.Resources.Dx9Surface.NativePointer, false);
                DxImage.AddDirtyRect(new Int32Rect(0, 0, _Renderer.Resources.Dx9Surface.Description.Width, _Renderer.Resources.Dx9Surface.Description.Height));
            }

            DxImage.Unlock();
        }));
    }

이 기사는 인터넷에서 수집됩니다. 재 인쇄 할 때 출처를 알려주십시오.

침해가 발생한 경우 연락 주시기 바랍니다[email protected] 삭제

에서 수정
0

몇 마디 만하겠습니다

0리뷰
로그인참여 후 검토

관련 기사

DirectX12에서 어댑터 드라이버 버전을 얻는 방법은 무엇입니까?

Windows Forms 애플리케이션 내에서 모든 창에 초점을 맞추는 방법이 있습니까?

AWS에서 * CONSOLE * 애플리케이션을 호스팅 할 수 있습니까?

내 WPF 애플리케이션을 터치 스크린에서 실행할 수 있습니까?

MVVMLight 애플리케이션에 Modern UI WPF 스타일을 추가하는 방법은 무엇입니까?

Docker에서 각도 애플리케이션을 호스팅하는 방법은 무엇입니까?

Python Django에서 Angular 6 애플리케이션을 호스팅하는 방법은 무엇입니까?

AWS에서 Java 애플리케이션을 호스팅하는 방법은 무엇입니까?

IBM에 Worklight 서버 / 애플리케이션을 호스팅하는 데 사용할 수있는 클라우드 호스팅 서비스가 있습니까?

Javascript 애플리케이션을 Java 애플리케이션과 유사하게 WebSphere에서 호스팅 할 수 있습니까?

WPF에서 애플리케이션 테마 이름을 저장하는 방법

DirectX12에서 전체 화면으로 이동할 수 없습니다.

WPF에서 Qt 애플리케이션 호스팅

서로 다른 가상 데스크톱 (또는 애플리케이션 창)을 서로 다른 모니터에 복제하는 방법이 있습니까?

오류가있는 WPF에서 애플리케이션보기

wpf 애플리케이션에서 json 응답을 사용하는 방법

WPF 애플리케이션에서 RESTful 웹 서비스를 제공하는 방법은 무엇입니까?

WinForms 애플리케이션 내 WPF 창에서 라이브 비주얼 트리를 사용하는 방법은 무엇입니까?

Tomcat API를 사용하여 애플리케이션 내부에서 웹 애플리케이션을 다시 시작하는 방법이 있습니까?

Java-스윙 애플리케이션에서 닫기 버튼을 숨기는 방법이 있습니까?

WPF 애플리케이션에서 메모리의 변수를 검색하는 방법은 무엇입니까?

xamarin iOS 애플리케이션에서 메일 애플리케이션 창을 여는 방법은 무엇입니까?

Google Colab에서 웹 애플리케이션을 실행하는 일반적인 방법이 있습니까?

C # WPF 또는 Windows Forms 애플리케이션에서 DirectX C ++ DLL 사용

앱 스토어 외부에 iOS 애플리케이션을 배포 할 수있는 방법이 있습니까?

Linux의 시스템 호스트 이름과 다른 애플리케이션에 특정 호스트 이름을 제공하는 방법이 있습니까?

앱에서 다른 애플리케이션의 창에 대한 참조를 얻을 수있는 방법이 있습니까?

WPF 애플리케이션에 ScrollViewer를 추가하는 방법

동일한 AppDomain에있는 여러 WPF 애플리케이션

TOP 리스트

  1. 1

    JNDI를 사용하여 Spring Boot에서 다중 데이터 소스 구성

  2. 2

    std :: regex의 일관성없는 동작

  3. 3

    JSoup javax.net.ssl.SSLHandshakeException : <url>과 일치하는 주체 대체 DNS 이름이 없습니다.

  4. 4

    PrematureCloseException : 연결이 너무 일찍 닫혔습니다.

  5. 5

    Xcode10 유효성 검사 : 이미지에 투명성이 없지만 여전히 수락되지 않습니까?

  6. 6

    정점 셰이더에서 카메라에서 개체까지의 XY 거리

  7. 7

    Ionic 2 로더가 적시에 표시되지 않음

  8. 8

    Seaborn에서 축 제목 숨기기

  9. 9

    C #에서 'System.DBNull'형식의 개체를 'System.String'형식으로 캐스팅 할 수 없습니다.

  10. 10

    복사 / 붙여 넣기 비활성화

  11. 11

    ArrayBufferLike의 typescript 정의의 깊은 의미

  12. 12

    Google Play Console에서 '예기치 않은 오류가 발생했습니다. 나중에 다시 시도해주세요. (7100000)'오류를 수정하는 방법은 무엇입니까?

  13. 13

    Kubernetes Horizontal Pod Autoscaler (HPA) 테스트

  14. 14

    jfreecharts에서 x 및 y 축 선을 조정하는 방법

  15. 15

    PRNG 기간보다 순열이 더 많은 목록을 무작위로 섞는 방법은 무엇입니까?

  16. 16

    C # HttpWebRequest 기본 연결이 닫혔습니다. 전송시 예기치 않은 오류가 발생했습니다.

  17. 17

    다음 컨트롤이 추가되었지만 사용할 수 없습니다.

  18. 18

    잘못된 구성 개체입니다. Webpack이 Angular의 API 스키마와 일치하지 않는 구성 개체를 사용하여 초기화되었습니다.

  19. 19

    Android Kotlin은 다른 활동에서 함수를 호출합니다.

  20. 20

    R의 마침표와 숫자 사이에 문자열 삽입

  21. 21

    Assets의 BitmapFactory.decodeStream이 Android 7에서 null을 반환합니다.

뜨겁다태그

보관