Master the fundamental concepts of modern graphics apis (low level) through this focused micro-challenge.
You have read the whole brief, and the concepts above stay free on every task. Writing and running the code needs a plan.
Three hints are available for this task, revealed one at a time inside the code workspace so you can struggle productively before seeing them.
Every task includes starter code, theory, and hidden tests so you can implement and verify locally in the browser.
How it worksIn Vulkan and D3D12, the CPU records commands into command buffers and submits them for GPU execution later. This decoupling lets the CPU prepare multiple frames ahead while the GPU works on previously submitted buffers.
A typical command sequence:
Command buffers come from command pools tied to queue families (graphics, compute, transfer). Secondary command buffers record independently and execute from a primary buffer, enabling multi-threaded recording. Unreal's Vulkan RHI uses this to parallelize CPU-side rendering.
cLoading…
For example, a frame might record once and resubmit every frame if the scene is static, amortizing CPU overhead. Semaphores synchronize queue submissions (image available -> render -> present). Fences signal CPU-GPU completion. Pipeline barriers enforce memory visibility within a buffer.
You will simulate a command buffer as an array of typed commands and demonstrate record-then-submit ordering. This task asks you to append commands and print the sequence. Command buffer reuse is why Vulkan renderers issue far more draw calls per frame than OpenGL could manage.
Model the Vulkan command buffer lifecycle and a slice of the validation layer. A command buffer is:
vkBeginCommandBuffer and vkEndCommandBuffer (RECORDING → EXECUTABLE);Destroying a resource it recorded also makes it INVALID. Commands have rules too: draws need a render pass, a pipeline and a vertex buffer, and transfers and plain barriers are forbidden inside a render pass.
# starts a comment.
cLoading…
CB: OLD -> NEW. States: INITIAL, RECORDING, EXECUTABLE, PENDING, INVALID.CB is already recording) or PENDING (CB is pending execution and cannot be begun). From EXECUTABLE or INVALID it first prints CB: implicit reset. Beginning clears the recorded state.CB ends inside a render pass).CB is pending execution and cannot be reset). It goes to INITIAL.CB is not recording (STATE)); commands that pass their checks are counted:
beginRenderPass inside one: render pass already active in CB;endRenderPass outside one: no active render pass in CB;draw: draw outside a render pass, draw without a bound pipeline, draw without a bound vertex buffer (checked in that order);copyBuffer inside a render pass: copyBuffer is not allowed inside a render pass;pipelineBarrier inside a render pass: pipelineBarrier inside a render pass needs a subpass self-dependency;buffer B has been destroyed;bindVertexBuffer/copyBuffer are remembered as used by the CB.CB is already pending (not simultaneous-use) or CB is STATE, not executable. At most 8 submissions can be in flight.
submitted CB: N command(s), D draw(s), fence F, then move to PENDING (if not already).one-time. If nothing matched: wait F: no pending work on this fence.buffer B is in use by a pending command buffer). Otherwise print buffer B destroyed, and every RECORDING or EXECUTABLE CB that used it becomes INVALID.CB: STATE, N command(s) recorded[, one-time submit].Validation failures print validation error: MESSAGE and change nothing.
cLoading…
Other errors:
alloc: CB [simultaneous], alloc X: name in use or pool full (8 max)begin: CB [one-time], submit: CB FENCE, wait: FENCE, destroy: BUFFERcmd: CB COMMAND [ARG], cmd: bindPipeline NAME, cmd: bindVertexBuffer BUFFER (or copyBuffer), cmd: unknown command XOP: unknown command buffer X, unknown operation XInput:
cLoading…
Output:
cLoading…
Hidden tests cover draw-state errors in order, render-pass nesting, transfers and barriers inside a render pass, a simultaneous-use buffer submitted twice, a one-time buffer becoming invalid, destruction blocked while pending, invalidation by destruction, an implicit reset, and unknown names.