DirectX 12 不绘制三角形

DirectX 12 doesn't draw triangle

我正在学习DirectX 12。我想画一个三角形,但是DirectX 12 不画。不知是不是我忘记了什么。

这是 Init() 部分。

void Engine::Init() {
    mDevice = new Device();
    mCommandQueue = new CommandQueue();
    mSwapChain = new SwapChain();
    mDescriptorHeap = new DescriptorHeap();
    mRootSignature = new RootSignature();

    mDevice->Init();
    mCommandQueue->Init(mDevice->GetDevice());
    mSwapChain->Init(mDevice->GetDevice(), mDevice->GetFactory(), mCommandQueue->GetCommandQueue(), mWndInfo);
    mDescriptorHeap->Init(mDevice->GetDevice(), mSwapChain);
    mRootSignature->Init(mDevice->GetDevice());

    mesh = new Mesh();
    shader = new Shader(mRootSignature);

    D3D12_INPUT_ELEMENT_DESC desc[] = {
        {"POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0},
        {"COLOR", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 12, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0}
    };

    shader->Init(mDevice->GetDevice(), L"..\Resources\Shader\default.hlsli");
    shader->SetPipelineState(mDevice->GetDevice(), desc, _countof(desc));

    std::vector<Vertex> vec(3);
    vec[0].pos = Vec3(0.0f, 0.5f, 0.5f);
    vec[0].color = Vec4(1.0f, 0.0f, 0.0f, 1.0f);
    vec[1].pos = Vec3(0.5f, -0.5f, 0.5f);
    vec[1].color = Vec4(0.0f, 1.0f, 0.0f, 1.0f);
    vec[2].pos = Vec3(-0.5f, -0.5f, 0.5f);
    vec[2].color = Vec4(0.0f, 0.0f, 1.0f, 1.0f);
    mesh->Init(mDevice->GetDevice(), vec);

    mCommandQueue->WaitForPreviousFrame(mSwapChain);
}
void Mesh::Init(ID3D12Device* const device, const std::vector<Vertex>& vec) {
    mVertexCount = static_cast<uint32>(vec.size());
    const uint32 bufferSize = mVertexCount * sizeof(Vertex);
    
    D3D12_HEAP_PROPERTIES heapProperties = CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD);
    D3D12_RESOURCE_DESC resourceDesc = CD3DX12_RESOURCE_DESC::Buffer(bufferSize);

    ThrowIfFailed(device->CreateCommittedResource(
        &heapProperties,
        D3D12_HEAP_FLAG_NONE,
        &resourceDesc,
        D3D12_RESOURCE_STATE_GENERIC_READ,
        nullptr,
        IID_PPV_ARGS(&mVertexBuffer)));

    // Copy the triangle data to the vertex buffer.
    void* pVertexDataBuffer = nullptr;
    CD3DX12_RANGE readRange(0, 0);        // We do not intend to read from this resource on the CPU.
    ThrowIfFailed(mVertexBuffer->Map(0, &readRange, &pVertexDataBuffer));
    std::memcpy(pVertexDataBuffer, &vec[0], bufferSize);
    mVertexBuffer->Unmap(0, nullptr);

    // Initialize the vertex buffer view.
    mVertexBufferView.BufferLocation = mVertexBuffer->GetGPUVirtualAddress();
    mVertexBufferView.StrideInBytes = sizeof(Vertex);
    mVertexBufferView.SizeInBytes = bufferSize;
}

初始化后,将执行此代码。

void Engine::Render() {
    mCommandQueue->RenderBegin(mSwapChain, mDescriptorHeap, shader->GetGraphicsPSO(), &mViewport, &mScissorRect);
    
    mesh->Render(mCommandQueue->GetCommandList());

    mCommandQueue->RenderEnd(mSwapChain);
}
void CommandQueue::RenderBegin(SwapChain* swapChain, DescriptorHeap* descHeap, GraphicsPSO* graphicsPSO, const D3D12_VIEWPORT* viewPort, const D3D12_RECT* scissorRect) {
    ThrowIfFailed(mCommandAllocator->Reset());
    ThrowIfFailed(mCommandList->Reset(mCommandAllocator, graphicsPSO->GetPipelineState()));

    mCommandList->SetGraphicsRootSignature(graphicsPSO->GetRootSignatrue()->GetRootSignature());
    mCommandList->RSSetViewports(1, viewPort);
    mCommandList->RSSetScissorRects(1, scissorRect);


    // Indicate that the back buffer will be used as a render target.
    D3D12_RESOURCE_BARRIER resourceBarrierDesc = CD3DX12_RESOURCE_BARRIER::Transition(swapChain->GetBackRtvBuffer(),
        D3D12_RESOURCE_STATE_PRESENT,
        D3D12_RESOURCE_STATE_RENDER_TARGET); 
    mCommandList->ResourceBarrier(1, &resourceBarrierDesc);

    
    D3D12_CPU_DESCRIPTOR_HANDLE rtvHandle = descHeap->GetBackRtvHandle(); 
    const float clearColor[] = { 0.0f, 0.2f, 0.4f, 1.0f };
    mCommandList->OMSetRenderTargets(1, &rtvHandle, FALSE, nullptr);
    mCommandList->ClearRenderTargetView(rtvHandle, clearColor, 0, nullptr);
}
void Mesh::Render(ID3D12GraphicsCommandList* cmdList) {
    cmdList->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
    cmdList->IASetVertexBuffers(0, 1, &mVertexBufferView);
    cmdList->DrawInstanced(mVertexCount, 1, 0, 0);
}
void CommandQueue::RenderEnd(SwapChain* swapChain) {
    // Indicate that the back buffer will now be used to present.
    D3D12_RESOURCE_BARRIER resourceBarrierDesc = CD3DX12_RESOURCE_BARRIER::Transition(swapChain->GetBackRtvBuffer(),
                                                        D3D12_RESOURCE_STATE_RENDER_TARGET,
                                                        D3D12_RESOURCE_STATE_PRESENT);

    mCommandList->ResourceBarrier(1, &resourceBarrierDesc);
    ThrowIfFailed(mCommandList->Close());

    // Execute the command list.
    ID3D12CommandList* ppCommandLists[] = { mCommandList };
    mCommandQueue->ExecuteCommandLists(_countof(ppCommandLists), ppCommandLists);

    // Back buffer <-> Front buffer
    swapChain->Present();
    WaitForPreviousFrame(swapChain);
    swapChain->SwapIndex();
}

结果是这样的: enter image description here

没有错误。我将我的代码与 DirectX 示例代码“Hello Triangle”进行了比较,但我编写了大部分 DirectX 代码来呈现,例如 OMSetRenderTargetsResourceBarrier

Windows10、GTX 750ti,支持DirectX 12。

我自己咳了咳。这是因为我对管道状态的初始化有误

    ID3D12PipelineState* pipelineState = mGraphicsPSO->GetPipelineState();
    D3D12_GRAPHICS_PIPELINE_STATE_DESC desc = mGraphicsPSO->GetGraphicsPipelineStateDesc();
    ThrowIfFailed(device->CreateGraphicsPipelineState(&desc, IID_PPV_ARGS(&pipelineState)));

这是我创建图形管道状态的代码。我写这段代码的时候出错了

ThrowIfFailed(device->CreateGraphicsPipelineState(&desc, IID_PPV_ARGS(&mGraphicsPSO->GetPipelineState())));

我想像上面那样写。但它会导致编译错误,即“C++ 表达式必须是左值或函数指示符”,因为 mGraphicsPSO->GetPipelineState() 的 return 是右值。

所以,我想如果我像原来的代码(第一个代码)那样写,它可能会起作用。不幸的是,它不会产生编译错误。它“有效”。

第一个代码的问题是 GraphicsPSO class 中的管道状态指针仍然是 nullptr 因为 ThrowIfFailed(device->CreateGraphicsPipelineState(&desc, IID_PPV_ARGS(&pipelineState))); 这段代码将创建图形管道状态到“pipelineState”不是 GraphicsPSO class 的成员。

我把这个问题写给了 Whosebug。

反正我怀疑第一个代码写了测试代码:

    D3D12_GRAPHICS_PIPELINE_STATE_DESC desc = mGraphicsPSO->GetGraphicsPipelineStateDesc();
    ThrowIfFailed(device->CreateGraphicsPipelineState(&desc, IID_PPV_ARGS(&mGraphicsPSO->mPipelineState)));

我将 mPipelineState 从 protected 移动到 public 并编写了如上代码。效果很好。

enter image description here

这是结果。

我找到了错误的根本原因,但并不意味着它就结束了。我需要考虑如何修复我的第一个代码。