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 代码来呈现,例如 OMSetRenderTargets
、ResourceBarrier
等
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
这是结果。
我找到了错误的根本原因,但并不意味着它就结束了。我需要考虑如何修复我的第一个代码。
我正在学习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 代码来呈现,例如 OMSetRenderTargets
、ResourceBarrier
等
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
这是结果。
我找到了错误的根本原因,但并不意味着它就结束了。我需要考虑如何修复我的第一个代码。