简体   繁体   中英

DirectX 12 doesn't draw triangle

I'm learning DirectX 12. I would like to draw a triangle, but DirectX 12 doesn't draw it. I wonder if there's something I forgot.

This is Init() part.

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;
}

After Init, This code will be executed.

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();
}

Result is like this: enter image description here

There's no error. I compared my code with DirectX sample code "Hello Triangle", but I wrote most of DirectX code to render such as OMSetRenderTargets , ResourceBarrier , etc.

Windows 10, GTX 750ti, support DirectX 12.

I cought the reason myself. It is because I got wrong with initialization of pipeline states.

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

this was my code where create graphics pipeline state. When I wrote this code, I had an error.

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

I wanted to write like above. But it makes compile error, which is "C++ expression must be an lvalue or a function designator", because mGraphicsPSO->GetPipelineState() 's return is rvalue.

So, I thought that it might work if I wrote like the original code(the first code). UNFORTUNATELY it doesn't make compile error. It "works".

The problem of the first code is that the pipeline state pointer in class of GraphicsPSO is still nullptr because ThrowIfFailed(device->CreateGraphicsPipelineState(&desc, IID_PPV_ARGS(&pipelineState))); this code will create graphics pipeline state to "pipelineState" which is not a member of class of GraphicsPSO.

And I wrote this question to StackOverflow.

Anyway, I suspected the first code and wrote test code:

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

I moved mPipelineState from protected to public and wrote code like above. It works well.

enter image description here

This is result.

I found the fundamental reason of the error but it doesn't mean that it is finished. I need to think how to fix my first code.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM