DirectX 11 渲染 BGRA32 帧
DirectX 11 render BGRA32 Frame
第一次尝试渲染某些东西时遇到了很大的麻烦...我正在使用 KlearTouch.MediaPlayer 中的 DirectN library and SwapChainSurface class。我正在尝试使用 D3D11Device 渲染 BGRA32 帧。
为此我稍微修改了 OnNewSurfaceAvailable:
public void OnNewSurfaceAvailable2(Action<ID3D11Device, ID3D11DeviceContext> updateSurface)
{
if (rendering)
{
return;
}
try
{
if (this.swapChain is null || swapChainComObject is null)
{
return;
}
swapChainComObject.GetDesc(out var swapChainDesc).ThrowOnError();
if (swapChainDesc.BufferDesc.Width != PanelWidth || swapChainDesc.BufferDesc.Height != PanelHeight)
{
swapChainComObject.ResizeBuffers(2, PanelWidth, PanelHeight, DXGI_FORMAT.DXGI_FORMAT_UNKNOWN, 0).ThrowOnError();
}
var device = swapChain.Object.GetDevice1().Object.As<ID3D11Device>();
device.GetImmediateContext(out var context);
// context.ClearRenderTargetView(renderTargetView.Object, new []{0f, 1f, 1f, 1f});
updateSurface(device, context);
swapChainComObject.Present(1, 0).ThrowOnError();
}
catch (ObjectDisposedException)
{
Reinitialize();
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine("\nException: " + ex, nameof(SwapChainSurface) + '.' + nameof(OnNewSurfaceAvailable));
}
rendering = false;
}
OnSurfaceAvailable2 调用自:
void VideoFrameArrived(Bgra32VideoFrame frame)
{
DispatcherQueue.TryEnqueue(() =>
{
previewSurface.OnNewSurfaceAvailable2((device, context) =>
{
var size = frame.m_height * frame.m_height * 4;
D3D11_TEXTURE2D_DESC td;
td.ArraySize = 1;
td.BindFlags = (uint) D3D11_BIND_FLAG.D3D11_BIND_SHADER_RESOURCE;
td.Usage = D3D11_USAGE.D3D11_USAGE_DYNAMIC;
td.CPUAccessFlags = (uint) D3D11_CPU_ACCESS_FLAG.D3D11_CPU_ACCESS_WRITE;
td.Format = DXGI_FORMAT.DXGI_FORMAT_B8G8R8A8_UNORM;
td.Height = (uint) frame.m_height;
td.Width = (uint) frame.m_width;
td.MipLevels = 1;
td.MiscFlags = 0;
td.SampleDesc.Count = 1;
td.SampleDesc.Quality = 0;
D3D11_SUBRESOURCE_DATA srd;
srd.pSysMem = frame.m_pixelBuffer;
srd.SysMemPitch = (uint) frame.m_height;
srd.SysMemSlicePitch = 0;
var texture = device.CreateTexture2D<ID3D11Texture2D>(td, new []{srd});
var mappedResource = context.Map(texture.Object, 0, D3D11_MAP.D3D11_MAP_WRITE_DISCARD);
var mappedData = mappedResource.pData;
unsafe
{
Buffer.MemoryCopy(frame.m_pixelBuffer.ToPointer(), mappedData.ToPointer(), size, size);
}
// Just for debug
var pixelsInFrame = new byte[size];
var pixelsInResource = new byte[size];
Marshal.Copy(frame.m_pixelBuffer, pixelsInFrame, 0, size);
Marshal.Copy(mappedResource.pData, pixelsInResource, 0, size);
context.Unmap(texture.Object, 0);
});
});
}
问题是我看不到任何渲染的东西并且表面保持黑色,我认为它不应该是。
更新:Project repository
更新 2:
我解决了我的问题。我对 DX11 的了解太少,所以我不得不更多地研究那里的工作原理。有了这些知识,我更新了可以显示黑魔法设计卡预览的存储库。这只是许多问题的示例,因此请小心并随时在那里寻找或启发。
这里有各种各样的问题。
第一帧到达,你有
var texture = device.CreateTexture2D<ID3D11Texture2D>(td, new []{srd});
所以你创建了一个纹理,但你没有在任何地方使用它,它需要被 blit 到交换链(可以在设备上下文上做一个 CopyResource 或绘制一个全屏 triangle/quad)。
请注意,只有当您的交换链与传入纹理的大小相同时,CopyResource 才会起作用,这是不太可能的,因此您很可能必须使用着色器绘制 blit。
而且你实际上复制了两次纹理中的数据:
var texture = device.CreateTexture2D<ID3D11Texture2D>(td, new []{srd});
由于您提供了初始数据,因此内容已经存在。
此外,音调不正确:
srd.SysMemPitch = (uint) frame.m_height;
pitch 是一行的长度(以字节为单位),所以它应该是:
srd.SysMemPitch = frame.GetRowBytes();
另请注意,如果是未转换的 Decklink 框架,
GetRowBytes 可以与 width*4 不同(它们可以将行大小对齐为 16/32 的倍数或其他值)。
接下来,在资源映射的情况下,以下也是不正确的:
unsafe
{
Buffer.MemoryCopy(frame.m_pixelBuffer.ToPointer(), mappedData.ToPointer(), size, size);
}
您没有检查纹理的 pitch/stride 要求(也可能不同),
所以你需要做:
if (mappedResource.RowPitch == frame.GetRowBytes())
{
//here you can use a direct copy as above
}
else
{
//here you need to copy data line per line
}
第一次尝试渲染某些东西时遇到了很大的麻烦...我正在使用 KlearTouch.MediaPlayer 中的 DirectN library and SwapChainSurface class。我正在尝试使用 D3D11Device 渲染 BGRA32 帧。
为此我稍微修改了 OnNewSurfaceAvailable:
public void OnNewSurfaceAvailable2(Action<ID3D11Device, ID3D11DeviceContext> updateSurface)
{
if (rendering)
{
return;
}
try
{
if (this.swapChain is null || swapChainComObject is null)
{
return;
}
swapChainComObject.GetDesc(out var swapChainDesc).ThrowOnError();
if (swapChainDesc.BufferDesc.Width != PanelWidth || swapChainDesc.BufferDesc.Height != PanelHeight)
{
swapChainComObject.ResizeBuffers(2, PanelWidth, PanelHeight, DXGI_FORMAT.DXGI_FORMAT_UNKNOWN, 0).ThrowOnError();
}
var device = swapChain.Object.GetDevice1().Object.As<ID3D11Device>();
device.GetImmediateContext(out var context);
// context.ClearRenderTargetView(renderTargetView.Object, new []{0f, 1f, 1f, 1f});
updateSurface(device, context);
swapChainComObject.Present(1, 0).ThrowOnError();
}
catch (ObjectDisposedException)
{
Reinitialize();
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine("\nException: " + ex, nameof(SwapChainSurface) + '.' + nameof(OnNewSurfaceAvailable));
}
rendering = false;
}
OnSurfaceAvailable2 调用自:
void VideoFrameArrived(Bgra32VideoFrame frame)
{
DispatcherQueue.TryEnqueue(() =>
{
previewSurface.OnNewSurfaceAvailable2((device, context) =>
{
var size = frame.m_height * frame.m_height * 4;
D3D11_TEXTURE2D_DESC td;
td.ArraySize = 1;
td.BindFlags = (uint) D3D11_BIND_FLAG.D3D11_BIND_SHADER_RESOURCE;
td.Usage = D3D11_USAGE.D3D11_USAGE_DYNAMIC;
td.CPUAccessFlags = (uint) D3D11_CPU_ACCESS_FLAG.D3D11_CPU_ACCESS_WRITE;
td.Format = DXGI_FORMAT.DXGI_FORMAT_B8G8R8A8_UNORM;
td.Height = (uint) frame.m_height;
td.Width = (uint) frame.m_width;
td.MipLevels = 1;
td.MiscFlags = 0;
td.SampleDesc.Count = 1;
td.SampleDesc.Quality = 0;
D3D11_SUBRESOURCE_DATA srd;
srd.pSysMem = frame.m_pixelBuffer;
srd.SysMemPitch = (uint) frame.m_height;
srd.SysMemSlicePitch = 0;
var texture = device.CreateTexture2D<ID3D11Texture2D>(td, new []{srd});
var mappedResource = context.Map(texture.Object, 0, D3D11_MAP.D3D11_MAP_WRITE_DISCARD);
var mappedData = mappedResource.pData;
unsafe
{
Buffer.MemoryCopy(frame.m_pixelBuffer.ToPointer(), mappedData.ToPointer(), size, size);
}
// Just for debug
var pixelsInFrame = new byte[size];
var pixelsInResource = new byte[size];
Marshal.Copy(frame.m_pixelBuffer, pixelsInFrame, 0, size);
Marshal.Copy(mappedResource.pData, pixelsInResource, 0, size);
context.Unmap(texture.Object, 0);
});
});
}
问题是我看不到任何渲染的东西并且表面保持黑色,我认为它不应该是。
更新:Project repository
更新 2:
我解决了我的问题。我对 DX11 的了解太少,所以我不得不更多地研究那里的工作原理。有了这些知识,我更新了可以显示黑魔法设计卡预览的存储库。这只是许多问题的示例,因此请小心并随时在那里寻找或启发。
这里有各种各样的问题。
第一帧到达,你有
var texture = device.CreateTexture2D<ID3D11Texture2D>(td, new []{srd});
所以你创建了一个纹理,但你没有在任何地方使用它,它需要被 blit 到交换链(可以在设备上下文上做一个 CopyResource 或绘制一个全屏 triangle/quad)。
请注意,只有当您的交换链与传入纹理的大小相同时,CopyResource 才会起作用,这是不太可能的,因此您很可能必须使用着色器绘制 blit。
而且你实际上复制了两次纹理中的数据:
var texture = device.CreateTexture2D<ID3D11Texture2D>(td, new []{srd});
由于您提供了初始数据,因此内容已经存在。
此外,音调不正确: srd.SysMemPitch = (uint) frame.m_height;
pitch 是一行的长度(以字节为单位),所以它应该是:
srd.SysMemPitch = frame.GetRowBytes();
另请注意,如果是未转换的 Decklink 框架, GetRowBytes 可以与 width*4 不同(它们可以将行大小对齐为 16/32 的倍数或其他值)。
接下来,在资源映射的情况下,以下也是不正确的:
unsafe
{
Buffer.MemoryCopy(frame.m_pixelBuffer.ToPointer(), mappedData.ToPointer(), size, size);
}
您没有检查纹理的 pitch/stride 要求(也可能不同),
所以你需要做:
if (mappedResource.RowPitch == frame.GetRowBytes())
{
//here you can use a direct copy as above
}
else
{
//here you need to copy data line per line
}