나는이 질문의 용어가 모두 틀 렸음에 틀림 없다는 것을 압니다. 그러나 제 평신도의 관점에서 사물을 보려고 노력하십시오. (저는 컴퓨터 기술에 대한 형성이없고, 독학적인 열광 자입니다. 프로그래밍 언어에 대한 공식 교육은 우리 학교의 로봇 공학 클럽입니다).
내가 원하는 것은 게임 루프와 모든 것을 포함하여 관리되는 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를 호출했습니다 . 동일한 결과 : 창이 없습니다.
누구든지 올바른 방향으로 나를 가리킬 수 있습니까?
나는 그것이 오래된 게시물이라는 것을 알고 있지만 해결책을 찾는 사람들을 위해 내가 찾은 것이 있습니다. 솔루션은 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] 삭제
몇 마디 만하겠습니다