我正在尝试在 Visual Studio 中设置 SwapChain,我创建了一个 SwapChainPanel UI 元素,我希望交换链绘制到该元素。
当前,当我运行此代码时,在呈现交换链时出现空引用异常。我认为问题出在选角上?我对 DirectX 不太熟悉,但非常感谢任何帮助!
var swapChainPanel = this._swapChainPanel;
var swapChainPanelNative = ComObject.As<SharpDX.DXGI.ISwapChainPanelNative>(swapChainPanel);
swapChainPanelNative.SwapChain = swapChain;
成员变量和构造函数
private SwapChainPanel _swapChainPanel;
private SharpDX.Direct3D11.Device device;
private SharpDX.Direct3D11.DeviceContext deviceContext;
private SwapChain swapChain;
private IDirect3DSurface surface;
private RenderTargetView renderTargetView;
private Texture2D renderTargetTexture;
private Texture2D backBuffer;
// Media player members
private MediaPlayer mediaPlayer;
private MediaPlaybackItem mediaPlaybackItem;
private FFmpegMediaSource ffmpegMediaSource;
private SoftwareBitmap frameServerDest = new SoftwareBitmap(BitmapPixelFormat.Rgba8, 512, 512, BitmapAlphaMode.Premultiplied);
private IDirect3DSurface direct3DSurface;
public StreamService(SwapChainPanel swapChainPanel)
{
_swapChainPanel = swapChainPanel;
swapChainPanel.Loaded += (sender, args) =>
{
// Only create the swap chain after the SwapChainPanel is loaded
InitializeSwapChain();
InitializeMediaPlayer();
};
}
交换链初始化
private void InitializeSwapChain()
{
// Create Direct3D device and context
var creationFlags = DeviceCreationFlags.BgraSupport;
creationFlags |= DeviceCreationFlags.Debug;
device = new Device(SharpDX.Direct3D.DriverType.Hardware, creationFlags);
// Descriptions
SwapChainDescription1 swapChainDesc = new SwapChainDescription1()
{
Width = (int)_swapChainPanel.ActualWidth,
Height = (int)_swapChainPanel.ActualHeight,
Format = Format.B8G8R8A8_UNorm,
Stereo = false,
SampleDescription = new SampleDescription(1, 0),
Usage = Usage.BackBuffer | Usage.RenderTargetOutput,
BufferCount = 2,
SwapEffect = SwapEffect.FlipDiscard,
Scaling = Scaling.Stretch,
AlphaMode = AlphaMode.Premultiplied,
Flags = SwapChainFlags.AllowModeSwitch | SwapChainFlags.AllowTearing
};
var textureDesc = new Texture2DDescription
{
Width = width,
Height = height,
MipLevels = 1,
ArraySize = 1,
Format = Format.B8G8R8A8_UNorm,
SampleDescription = new SampleDescription(1, 0),
Usage = ResourceUsage.Default,
BindFlags = BindFlags.RenderTarget | BindFlags.ShaderResource,
CpuAccessFlags = CpuAccessFlags.None,
OptionFlags = ResourceOptionFlags.None,
};
using (var dxgiDevice = device.QueryInterface<SharpDX.DXGI.Device>())
{
using (var adapter = dxgiDevice.Adapter)
{
using (var factory = adapter.GetParent<Factory2>())
{
using (swapChain = new SwapChain1(factory, dxgiDevice, ref swapChainDesc))
{
var swapChainPanel = this._swapChainPanel;
var swapChainPanelNative = ComObject.As<SharpDX.DXGI.ISwapChainPanelNative>(swapChainPanel);
swapChainPanelNative.SwapChain = swapChain;
// Set render view
backBuffer = swapChain.GetBackBuffer<Texture2D>(0);
renderTargetView = new RenderTargetView(device, backBuffer);
device.ImmediateContext.OutputMerger.SetRenderTargets(renderTargetView);
// Set render target texture
renderTargetTexture = new Texture2D(device, textureDesc);
direct3DSurface = Direct3D11Helper.CreateDirect3DSurfaceFromSharpDXTexture(renderTargetTexture);
backBuffer.Dispose();
}
}
}
}
}
展示交换链
public void RenderFrame()
{
// Clear the render target
device.ImmediateContext.ClearRenderTargetView(renderTargetView, new RawColor4(1, 1, 1, 1));
// Set the render target
device.ImmediateContext.OutputMerger.SetRenderTargets(renderTargetView);
// Bind the texture that was updated by MediaPlayer to the pixel shader
using (var shaderResourceView = new ShaderResourceView(device, renderTargetTexture))
{
device.ImmediateContext.PixelShader.SetShaderResource(0, shaderResourceView);
// Render quad
device.ImmediateContext.Draw(6, 0);
}
// Present the frame
swapChain.Present(1, PresentFlags.None);
System.Diagnostics.Debug.WriteLine("Frame presented successfully.");
}
在您的代码中,您可以像这样创建交换链:
using swapChain = new SwapChain1(factory, dxgiDevice, ref swapChainDesc);
{
// do something
}
这意味着一旦您超出范围,它就会被处理掉。当您调用
RenderFrame
时,swapChain
对象本身不为 null,因为它是本机事物的 .NET 包装器,但它是底层的 NativePointer
,并且您在 SharpDX 代码“下面”中得到一个 NullReferenceException
。
只需保持您需要的 DirectX 对象处于活动状态,例如:
swapChain = new SwapChain1(factory, dxgiDevice, ref swapChainDesc);
并且您应该将大多数这些“活动”对象(设备、交换链、后台缓冲区)存储在成员变量中(仅在关闭服务代码时处置它们)。但是,您通常可以在使用完中间对象(例如工厂)后立即释放它们。