PipelineWarmer

construct-gpu-profiling-windows §WGP-A3.3 — a graphics pipeline's driver compile, done on a helper thread before the render thread creates it.

In the namespace rhi. Declared in src/libs/librhi/rhi/PipelineWarmer.hpp.

Detailed description

The cold cost of a QRhiGraphicsPipeline::create() is the driver turning the shader into GPU code: 1.8 s and 5.1 s for construct's two SDF pipelines on the RX 7800 XT (Direct3D 12), 35 s on Vulkan. It runs on the thread that renders, so the viewport stood still for all of it. The driver caches that work per device, not per QRhi: a pipeline created on a second QRhi that adopts the same ID3D12Device costs 0.6 ms after a 5.4 s cold create on the first (testGpuProfilingWindows::testDriverCacheIsSharedAcrossQRhisOnOneDevice).

A Template says everything the driver compile depends on, as plain values: the shader stages, the vertex input layout, the fixed-function state, the binding layout (slot, stages, type, count: all Qt's Direct3D 12 root signature reads) and the render targets' formats. warm() rebuilds the pipeline from it on the helper's own QRhi, with placeholder buffers, textures and targets, and creates it there. The caller's later create() of the same pipeline is then a cache hit.

Direct3D 12 only: for(native device) returns null for anything else, and the caller simply creates as before. Thread-safe; warm() blocks the calling thread (a build thread, never the render thread) until the helper is done.

On Vulkan a pipeline compiled on one device is a hit on another only through the driver's own disk cache, so a Vulkan warm-up carries the device's pipeline cache to the helper and back (construct::pathtrace::KernelPipelineForge, construct-owner-feedback row 8.16). That forge describes a pipeline with describe(), which reads the render targets of a Vulkan render pass descriptor too, and creates it on its helper device with createOn(), the body the warmer's helpers run.

In this section