I'm new to DirectX12. I've read document about DirectX12 for some days and now I just want to use it to draw a triangle. But it's not work! I used PIX to debug the program and I found that my pixel shader has no output!. I don't know if there's something wrong with my Pipeline State Object settings.
this is the function that create the PSO
/** vs and ps are indices of shader resource which have been compiled with dxc.exe in sm6 and stored in a map called shaders */
void Renderer::CreatePSO(uint32_t vs, uint32_t ps)
{
D3D12_INPUT_LAYOUT_DESC inputDesc;
D3D12_INPUT_ELEMENT_DESC pos;
pos.SemanticName = "POSITION";
pos.SemanticIndex = 0;
pos.Format = DXGI_FORMAT_R32G32B32_FLOAT;
pos.InputSlot = 0;
pos.InputSlotClass = D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA;
pos.AlignedByteOffset = D3D12_APPEND_ALIGNED_ELEMENT;
pos.InstanceDataStepRate = 0;
inputDesc.NumElements = 1;
inputDesc.pInputElementDescs = &pos;
D3D12_RASTERIZER_DESC rasterDesc = {}; /**< use default value */
rasterDesc.FillMode = D3D12_FILL_MODE_SOLID;
rasterDesc.CullMode = D3D12_CULL_MODE_NONE; /**< disable cull */
rasterDesc.DepthClipEnable = false;
D3D12_GRAPHICS_PIPELINE_STATE_DESC desc = {};
desc.pRootSignature = mRootSignature.Get();
ID3DBlob* const vsb = shaders[vs].Get();
ID3DBlob* const psb = shaders[ps].Get();
desc.VS.BytecodeLength = vsb->GetBufferSize();
desc.VS.pShaderBytecode = vsb->GetBufferPointer();
desc.PS.BytecodeLength = psb->GetBufferSize();
desc.PS.pShaderBytecode = psb->GetBufferPointer();
desc.StreamOutput = {};
desc.BlendState = {};
desc.InputLayout = inputDesc;
desc.SampleMask = 0;
desc.RasterizerState = rasterDesc;
desc.DepthStencilState = {}; /**< use the default value */
desc.DepthStencilState.DepthEnable = false; /**< disable depth testing */
desc.DepthStencilState.StencilEnable = false; /**< disable stencil testing */
desc.IBStripCutValue = D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_DISABLED;
desc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
desc.NumRenderTargets = 1;
desc.RTVFormats[0] = DXGI_FORMAT_R8G8B8A8_UNORM;
desc.DSVFormat = DXGI_FORMAT_UNKNOWN; /**< since there is no depth stencil buffer */
desc.SampleDesc.Count = 1;
desc.SampleDesc.Quality = 0;
desc.NodeMask = 0;
desc.CachedPSO = {};
desc.Flags = D3D12_PIPELINE_STATE_FLAG_NONE;
if (FAILED(mDevice->CreateGraphicsPipelineState(&desc, IID_PPV_ARGS(&mPSO))))
throw("create pipeline state failed");
}
And this is the function that setting command list for each frame
void Renderer::Run()
{
WindowBase::MainLoop = [this](float) {
/** Command List setting for each frame */
mCmdList->Reset(mCmdAloc.Get(), nullptr);
mCmdList->SetPipelineState(mPSO.Get()); /**< Which is created throgh Function CreatePSO */
/** A constant buffer in the heap that I never use within my shaders */
D3D12_GPU_DESCRIPTOR_HANDLE gpuHandle = mBufDescHeap->GetGPUDescriptorHandleForHeapStart();
ID3D12DescriptorHeap* heaps[] = { mBufDescHeap.Get() };
mCmdList->SetDescriptorHeaps(1, heaps);
mCmdList->SetGraphicsRootSignature(mRootSignature.Get());
mCmdList->SetGraphicsRootDescriptorTable(0, gpuHandle);
/** Vertex And Index Buffers setting */
mCmdList->IASetVertexBuffers(0, 1, &mVtxBufView);
mCmdList->IASetIndexBuffer(&mIdxBufView);
mCmdList->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
/** Viewport and Scissor Rect settings. mWidth = 300 and mHeight = 300. */
D3D12_VIEWPORT viewport = {};
viewport.Height = mHeight; viewport.Width = mWidth;
viewport.MaxDepth = 1.0f; viewport.MinDepth = 0.0f;
viewport.TopLeftX = 0; viewport.TopLeftY = 0;
mCmdList->RSSetViewports(1, &viewport);
D3D12_RECT scissorRect;
scissorRect.bottom = mHeight;
scissorRect.right = mWidth;
scissorRect.top = scissorRect.left = 0;
mCmdList->RSSetScissorRects(1, &scissorRect);
D3D12_RESOURCE_BARRIER barrier;
barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
barrier.Transition.pResource = mRtvs[mSwapChain->GetCurrentBackBufferIndex()].Get();
barrier.Transition.Subresource = 0;
barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_PRESENT;
barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_RENDER_TARGET;
mCmdList->ResourceBarrier(1, &barrier);
D3D12_CPU_DESCRIPTOR_HANDLE rtvHandle = mRtvDescHeap->GetCPUDescriptorHandleForHeapStart();
rtvHandle.ptr += mRtvDescHeapSize * mSwapChain->GetCurrentBackBufferIndex();
static float clearColor[] = { 0.2f, 0.4f, 0.6f, 1.0f };
mCmdList->ClearRenderTargetView(rtvHandle, clearColor, 0, nullptr);
/** no depth stencil buffer here, since i don't want to use depth testing */
mCmdList->OMSetRenderTargets(1, &rtvHandle, false, nullptr);
mCmdList->DrawIndexedInstanced(3, 1, 0, 0, 0);
barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_RENDER_TARGET;
barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_PRESENT;
mCmdList->ResourceBarrier(1, &barrier);
mCmdList->Close();
ID3D12CommandList* list[] = { mCmdList.Get() };
mCmdQue->ExecuteCommandLists(1, list);
mSwapChain->Present(1, 0);
/** Waiting until above commands were executed */
synchronizationCPU(mCmdQue.Get(), mFence.Get(), mNextFenceValue, mFenceEventHandle);
};
win->Run(); /** start window's main loop */
}
And here is my simplest vertex shader and pixel shader(I used dxc.exe to compile it in Shader Model 6_0)
/////////////////////////////////
// VERTEX SHADER
/////////////////////////////////
float4 main( float3 pos : POSITION ) : SV_POSITION
{
return float4(pos, 1.0f);
}
/////////////////////////////////
// PIXEL SHADER
/////////////////////////////////
float4 main() : SV_TARGET
{
return float4(1.0f, 1.0f, 1.0f, 1.0f);
}
Vertex buffer and Index buffer are also very simple
std::array<float, 9> VtxData = {
-.5f, 0.0f, 0.0f,
0.0f, .5f, 0.0f,
.5f, 0.0f, 0.0f
};
std::array<uint32_t, 3> IdxData = {
0, 1, 2
};
By the way, I have used the debug layer and there is no error or warning message. When I try to use PIX to debug the pixel that should be inside the triangle, it warn me that "Shader Debugging returned no invocation records. Check that your selected pixel, vertex, or thread exists and was executed on this draw call".
My Vertex Shader has the correct output which should not be culled anymore
Hope anybody can give me some suggestions to do more test. Thanks!!! (Seriously, DirectX12 is really harder than DirectX11...)