我似乎偶然发现了有关DirectX 12.0编程的问题,到目前为止还没有研究能够深入了解这个问题.因此,除了似乎还没有一个切实可行的解决方案之外,我一直在寻找问题.
要告诉你,我现在用C(不是C++)和编程,因为很明显,提供了DirectX 12头文件做支持C,沿着C++,虽然我已经遇到的问题是奇怪的,因为它似乎是设计不良的C,可能由于没有多少人用这种语言编写复杂的(特别是面向对象的)应用程序.
这是我的问题:我在D3D12设备初始化过程中有以下代码块:
/* Get a handle to the memory location in the render target
view heap to identify where the render target views will be
located for the two back buffers */
hRTV = pThis->pRTVHeap->lpVtbl->GetCPUDescriptorHandleForHeapStart(pThis->pRTVHeap);
Run Code Online (Sandbox Code Playgroud)
凡HRTV代表" 处理,以渲染目标视图 "(D3D12_CPU_DESCRIPTOR_HANDLE)和pRTVHeap代表" 指针到渲染目标视图堆 "(ID3D12DescriptorHeap).
这是C++的等价物 - 这很好用:
/* Get a handle to the memory location in the render target
view heap to identify where the render target views will be
located …Run Code Online (Sandbox Code Playgroud) 假设一个单线程应用程序。如果您调用ExecuteCommandLists两次(A和B)。在启动B的任何命令之前, A是否能保证在 GPU 上执行其所有命令?我在文档中可以找到的最接近的内容是这个,但它似乎并不能真正保证A在B开始之前完成:
应用程序可以从多个线程向任何命令队列提交命令列表。运行时将执行按提交顺序序列化这些请求的工作。
作为比较,我知道Vulkan 中显然无法保证这一点:
vkQueueSubmit 是一个队列提交命令,每个批次由 pSubmits 的一个元素定义为 VkSubmitInfo 结构的实例。批次按照它们在 pSubmits 中出现的顺序开始执行,但可能会乱序完成。
不过,我不确定 DX12 是否也能以同样的方式工作。
弗兰克卢纳的书说:
命令列表从第一个数组元素开始按顺序执行
然而,在这种情况下,他谈论的是使用ExecuteCommandLists两个命令列表(C和D)调用一次。这些操作与两个单独的呼叫相同吗?我的同事认为这仍然只能保证它们按顺序启动,而不能保证C在D开始之前完成。
我缺少的地方有更清晰的文档吗?
我设置了一个 DX12 应用程序,它只清除每帧的后缓冲区。
它确实是准系统:没有 PSO,没有根...唯一的特殊性是它在启动新帧( msdn waitable swap chain )之前等待交换链上的 Present() 完成(我将帧延迟设置为 1 ,如下所示)以及只有 2 个缓冲区)。
第一帧运行良好,但它立即开始绘制第二帧,当然,命令分配器抱怨它正在重置,而命令仍在 GPU 上执行。
我当然可以设置一个栅栏来等待 GPU 在移动到新框架之前完成,但我认为这是可等待交换链对象的工作。
这是渲染例程:
if (m_command_allocator->Reset() == E_FAIL) { throw; }
HRESULT res = S_OK;
res = m_command_list->Reset(m_command_allocator.Get(), nullptr);
if (res == E_FAIL || res == E_OUTOFMEMORY) { throw; }
m_command_list->ResourceBarrier(1,
&CD3DX12_RESOURCE_BARRIER::Transition(m_render_targets[m_frame_index].Get(),
D3D12_RESOURCE_STATE_PRESENT, D3D12_RESOURCE_STATE_RENDER_TARGET));
m_command_list->RSSetViewports(1, &m_screen_viewport);
m_command_list->RSSetScissorRects(1, &m_scissor_rect);
m_command_list->ClearRenderTargetView(get_rtv_handle(),
DirectX::Colors::BlueViolet, 0, nullptr);
m_command_list->OMSetRenderTargets(1, &get_rtv_handle(), true, nullptr);
m_command_list->ResourceBarrier(1,
&CD3DX12_RESOURCE_BARRIER::Transition(m_render_targets[m_frame_index].Get(),
D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_PRESENT));
tools::throw_if_failed(m_command_list->Close());
ID3D12CommandList* ppCommandLists[] = { m_command_list.Get() };
m_command_queue->ExecuteCommandLists(_countof(ppCommandLists),
ppCommandLists);
if (m_swap_chain->Present(1, …Run Code Online (Sandbox Code Playgroud) 我在微软的示例中发现:
void D3D12HelloTriangle::OnRender()
{
// Record all the commands we need to render the scene into the command list.
PopulateCommandList();
// Execute the command list.
ID3D12CommandList* ppCommandLists[] = { m_commandList.Get() };
m_commandQueue->ExecuteCommandLists(_countof(ppCommandLists), ppCommandLists);
// Present the frame.
ThrowIfFailed(m_swapChain->Present(1, 0));
WaitForPreviousFrame();
}
Run Code Online (Sandbox Code Playgroud)
实际上是如何运作的?ExecuteCommandLists 是一个异步函数调用,因此这意味着代码将继续执行并命中 Present 函数。
当前通话后会发生什么?比方说,GPU 仍在绘图、工作并存在被调用。Present是同步调用吗?当 GPU 仍在绘图时,它无法呈现缓冲区。那是对的吗 ?有人可以解释一下这里发生了什么吗?
假设 DX12 被挂钩以进行叠加渲染的场景,看起来最好的挂钩函数是 IDXGISwapChain::Present,与 DX11 的做法相同。将此函数挂钩后,交换链就可用,并且可以从中检索设备以创建资源。有了这些资源,它也可以记录渲染命令。当我们尝试执行渲染命令时,就会出现问题,因为没有选项可以从交换链中检索关联的命令队列,因此不会出现这样的情况:
\n\nCComPtr<ID3D12Device> pD3D12Device;\nif (pSwapChain->GetDevice(__uuidof(ID3D12Device), (void**)(&pD3D12Device)) == S_OK)\n{\n pD3D12Device->GetCommandQueueForSwapChain( swapChain )->ExecuteCommandLists(\xe2\x80\xa6);\n}\nRun Code Online (Sandbox Code Playgroud)\n\n另一个选项是创建一个新的命令队列来执行,如下所示:
\n\nCComPtr<ID3D12Device> pD3D12Device;\nif (pSwapChain->GetDevice(__uuidof(ID3D12Device), (void**)(&pD3D12Device)) == S_OK)\n{\n D3D12_COMMAND_QUEUE_DESC queue_desc = {};\n queue_desc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE;\n queue_desc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT;\n HRESULT commandQueueRes = _device->CreateCommandQueue( &queue_desc, IID_PPV_ARGS( &_commandQueue ) );\n\n _commandQueue->ExecuteCommandLists( ... );\n}\nRun Code Online (Sandbox Code Playgroud)\n\n这会导致错误并导致随后的设备删除。请参阅下面的错误消息。
\n\n\n\n\nD3D12 错误:ID3D12CommandQueue::ExecuteCommandLists:写入交换链后台缓冲区的命令列表只能在与该缓冲区关联的命令队列上执行。[状态设置错误#907:执行命令列表_WRONGSWAPCHAINBUFFERREFERENCE]
\n
即使 ID3D12CommandQueue::ExecuteCommandLists 也被挂钩,问题也没有解决,因为也无法从命令队列中检索关联的交换链。
\n\n所以我的问题是,在交换链创建发生在挂钩可能发生之前的情况下,处理此问题的推荐方法是什么?
\n我知道这个问题的术语一定是错的,但请耐心等待,并尝试从我的外行角度看待事物(我没有计算机技术方面的知识,我是自学爱好者。我得到的最接近的编程语言方面的正规教育是我学校的机器人俱乐部)。
我想要的是能够使用托管 DirectX 12 作为我的应用程序的“背景”,以及游戏循环和所有内容。并且,如果可能的话,能够在实际的 DirectX 游戏周围拥有 WPF 控件,如功能区或工具箱或菜单。我一直在寻找互联网上的所有内容,我发现的都是适用于 Windows 和 DirectX 9.0 的旧东西;我希望这些天有新的东西。
我尝试了 Windows 窗体方法,基本上是这样的:
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 …Run Code Online (Sandbox Code Playgroud) 我记得当我看到DirectX 12的最初谈话时,我认为它消除了对纹理图谱的需求.然而,现在看起来并不是一个明显的结论,我正在阅读文档.
我见过的一个可以替代它的功能是HLSL中资源数组的动态非均匀索引:
Texture2D<float4> textures[128];
SamplerState sampler;
textures[NonUniformResourceIndex(textureIndex)].Sample(sampler, uv);
Run Code Online (Sandbox Code Playgroud)
另一个潜在的特性是ExecuteIndirect,它编码仍然是一堆单独的绘图和资源更改调用缓冲区,并在单个CPU调用中立即将其提交给GPU.
这两个都将解决纹理图集的局限性(无法在atlas区域使用边界模式,有问题的mipmapping),但我想知道性能特征或预期是否与纹理图谱相似或者该技术是否仍然合理.
我也很想知道答案是否适用于Mantle,Vulkan和Metal.
我对ID3D12GraphicsCommandList::SetGraphicsRootSignature方法的存在有点困惑。从我对这个 MSDN 页面的理解来看,它的唯一有效用法似乎是始终在 之后调用它SetPipelineState,并为其提供与创建管道状态对象时提供的相同的根签名。如果是这样,那么不隐含有什么好处?还有其他方法可以使用这种方法吗?
ID3D12Device::SetStablePowerState函数调用仅在系统中打开开发人员模式时可用.如果没有,它会触发设备删除.
是否有一个API来检测开发人员模式是否打开,到目前为止我没有在msdn上发现允许应用程序查询它的任何内容.
我正在尝试创建两个应用程序。一个应用程序将在屏幕外渲染纹理,第二个应用程序将从图形内存中读取它并在窗口上渲染/呈现它。
我的疑问是是否可以在 directx 12 中共享图形内存。
我的命名共享内存方法导致 comptr addref 错误...
我正在使用 comptr 来ID3D12Resource获取纹理数据......
那么我们如何继续这种方法......
directx-12 ×10
c++ ×2
direct3d12 ×2
directx ×2
c ×1
c# ×1
com ×1
dxgi ×1
interop ×1
windows-10 ×1
wpf ×1