Write a Direct3D12 application (3)

Direct3D12 takes the form of buffering drawing commands in a command list and executing them together. A simple description of the process to be executed every frame is as follows.

{
    // Start of command list
    commandAllocator->Reset();
    commandList->Reset(commandAllocator.Get(), pipelineState.Get());

    // Execute various drawing commands to create a command list
    ...

    // Execute buffered command list
    commandList->Close();
    ID3D12CommandList* commandLists[] = { commandList.Get() };
    commandQueue->ExecuteCommandLists(_countof(commandLists), commandLists);

    // View swap chain
    swapChain->Present(1, 0);
}

Whether the GPU starts drawing at ExecuteCommandLists or buffers one frame and then starts drawing all together at Present depends on the GPU architecture and driver implementation policy, This depends on the GPU architecture and driver implementation policy. For example, in the case of tile-based rendering, For example, in the case of tile-based rendering, the GPU must buffer one frame and then start drawing.

Next, let’s look at present. This API is abstract and difficult to understand, but it is an important API.

Internally, what is being processed is as follows.

  • Waiting for the previous frame to complete drawing(WaitDrawDone)
  • Swaps the frame buffer that has completed drawing with the front buffer at the timing of the next VSync.(SwapBuffer)
  • Wait for VSync for the number of times specified by the first argument.(WaitVSync)

This is also basically driver-dependent processing, so it may not be processed in Present.

Note that some arguments can be set to not wait for VSync, but in order to draw correctly without tearing, The following two settings are the only options.

  • Wait for VSync on a double buffer
  • Do not wait for VSync on triple buffers

In other words, drawing with two buffers requires waiting for VSync, and not waiting for VSync requires three buffers.

VSync is a lengthy process to explain precisely, so I will omit it, but simply put, the display finishes showing the specified frame buffer, The VSync timing is the point in time when the display finishes displaying the specified frame buffer and before it starts displaying the next frame buffer. When a request is made to the display to switch frame buffers, VSync timing is when the display actually switches the framebuffer.

In Windows, there are two modes: windowed mode and full screen mode. in windowed mode, it does not seem to work correctly because the entire screen is waiting for VSync even if it is set to “no wait for VSync”. In full-screen mode, the drawing loop can be changed to 60 fps or higher by setting it to not wait for VSync.

I am still in the process of explaining this, but I would like to implement the debugging display function next, as I am getting to the point where I want it.