18 KiB
DRP2 Lifetimes And State
This document defines the authoritative lifetime, scope, and recorder-state rules for the active
DRP2 2.0 command surface.
If command prose in COMMANDS.md and this document appear to disagree, treat
COMMANDS.md as the field-level source of truth and this document as the source of state and
lifetime invariants.
Scope
This document applies only to the active DRP2 2.0 commands:
- session and diagnostics,
- buffer and texture lifecycle,
- sampler lifecycle,
- shader-module lifecycle,
- bind-group lifecycle,
- pipeline lifecycle,
- command encoder lifecycle,
- render and compute pass lifecycle,
- render and compute recording commands,
- copy commands,
- queue submission.
Deferred commands listed in schema/DEFERRED.md are not covered by these invariants and must not be
assumed to inherit them unchanged.
Object Identity
General id rules:
- ids are chosen by the client,
- ids are typed by the command that creates or defines their scope,
- a live id must refer to exactly one object kind,
- referencing an unknown id is invalid,
- referencing a destroyed id is invalid,
- reusing an id after destruction is invalid in DRP2
2.0, - reusing an id for a different object kind is invalid even if the earlier object is no longer live.
Validation consequences:
- unknown ids should fail with
DRP2_ERR_INVALID_ID, - duplicate or reused ids should fail with
DRP2_ERR_DUPLICATE_ID, - correct id existence with wrong object kind should fail with
DRP2_ERR_WRONG_OBJECT_TYPE.
Persistent Versus Scoped Objects
Persistent objects remain live until explicit destruction:
- buffer
- texture
- sampler
- shader module
- bind-group layout
- bind group
- pipeline
- command buffer
Scoped objects exist only between their begin and end commands:
- command encoder
- render pass
- compute pass
Diagnostic messages are not persistent objects:
HelloRendererandRendererHelloReplynegotiate session compatibility,Errorreports a failure but does not create a reusable object.
Session State
Session states:
unnegotiatedreadyfailed
Rules:
- a fresh connection starts in
unnegotiated, HelloRendereris valid only inunnegotiated,- a successful
RendererHelloReplytransitions the session toready, - a failed handshake transitions the session to
failed, HelloRendererandRendererHelloReplyare single-use for a stream and may not be repeated after negotiation has started,Erroris valid afterHelloRendererregardless of whether the session is still pending, ready, or already failed,- active resource and recording commands are valid only in
ready, - once the session is
failed, the stream is not required to recover within the same connection.
Active fixture-runner note:
- the executable fixture runner requires
HelloRendereras the first command of every stream, RendererHelloReplymust complete before any active resource or recording command is valid,- a failed handshake leaves the session in
failedfor the remainder of that stream, Erroris treated as diagnostic output and does not by itself change the session state.
Buffer Lifetime
Rules:
CreateBuffermakesidlive as a buffer immediately after semantic validation succeeds,WriteBufferrequires a live buffer id,DestroyBufferends the buffer lifetime immediately after semantic validation succeeds,- no later command may reference the destroyed buffer,
- a buffer may be referenced by copy commands only while live,
- a buffer may be referenced by
QueueSubmitonly indirectly through previously finished command buffers.
Texture Lifetime
Rules:
CreateTexturemakesidlive as a texture immediately after semantic validation succeeds,WriteTexturerequires a live texture id,DestroyTextureends the texture lifetime immediately after semantic validation succeeds,- no later command may reference the destroyed texture,
- a texture may be referenced by copy commands only while live,
- texture subresources do not have independent protocol lifetimes in the active
2.0surface, - render-pass attachments in active
2.0reference textures directly rather than separate texture-view objects.
Sampler Lifetime
Rules:
CreateSamplermakesidlive as a sampler immediately after semantic validation succeeds,DestroySamplerends the sampler lifetime immediately after semantic validation succeeds,- no later command may reference the destroyed sampler,
- a sampler may be referenced by bind groups as a
samplerbinding resource, - a bind group that references a sampler must be destroyed before that sampler may be destroyed.
Bind-Group Lifetime
Rules:
CreateBindGroupLayoutmakesidlive as a bind-group layout immediately after semantic validation succeeds,DestroyBindGroupLayoutends the bind-group-layout lifetime immediately after semantic validation succeeds,- no later command may reference the destroyed bind-group layout,
CreateBindGroupmakesidlive as a bind group immediately after semantic validation succeeds,DestroyBindGroupends the bind-group lifetime immediately after semantic validation succeeds,- no later command may reference the destroyed bind group,
- a bind group may reference existing buffers, textures, and samplers, but it does not create independent subresource lifetimes for them,
- a bind-group layout may be referenced by bind groups and pipelines,
- a bind group may be referenced by
QueueSubmitonly indirectly through previously finished command buffers.
Validation consequences:
- a bind-group entry whose
binding_typeis incompatible withresource_kindshould fail during schema validation before semantic code selection is considered, - a bind-group entry whose referenced resource lacks the usage bits implied by
binding_typeshould fail withDRP2_ERR_USAGE, - a bind group whose entries do not exactly match its declared bind-group layout should fail with
DRP2_ERR_INVALID_ARGUMENTbecause the create-time command shape is malformed against the chosen layout, - a dynamic buffer binding created without an explicit
offsetandsizeshould fail withDRP2_ERR_INVALID_ARGUMENT.
Shader-Module Lifetime
Rules:
CreateShaderModulemakesidlive as a shader module immediately after semantic validation succeeds,DestroyShaderModuleends the shader-module lifetime immediately after semantic validation succeeds,- no later command may reference the destroyed shader module,
- a shader module may be referenced by live pipelines,
- a shader module may be referenced by
QueueSubmitonly indirectly through previously finished command buffers that capture pipelines using it.
Pipeline Lifetime
Rules:
CreateRenderPipelinemakesidlive as a render pipeline immediately after semantic validation succeeds,CreateComputePipelinemakesidlive as a compute pipeline immediately after semantic validation succeeds,DestroyRenderPipelineends the lifetime of the referenced render pipeline immediately after semantic validation succeeds,DestroyComputePipelineends the lifetime of the referenced compute pipeline immediately after semantic validation succeeds,- no later command may reference a destroyed pipeline,
- a pipeline may be referenced by
QueueSubmitonly indirectly through previously finished command buffers, - a live pipeline keeps its referenced shader modules live for as long as the pipeline itself is live,
- creating a pipeline with shader modules whose stages do not match the pipeline slot is invalid.
Command Buffer Lifetime
Rules:
FinishCommandEncodercreates a new command buffer object identified bycommand_buffer_id,- a command buffer becomes live only if its parent encoder finishes successfully,
QueueSubmitrequires every referenced command buffer to be live and finished,- command buffers are immutable once created,
- a command buffer may be submitted at most once in active DRP2
2.0, - a single
QueueSubmitmay not list the same command buffer id more than once, - DRP2
2.0has no explicitDestroyCommandBuffer, - runtimes may reclaim backend-native command-buffer resources after submission or stream teardown, but that is not a protocol-visible state change.
Command Encoder State Machine
Encoder states:
openfinished
Rules:
BeginCommandEncodercreates an encoder inopen,- copy commands are valid only while the target encoder is
open, BeginRenderPassandBeginComputePassare valid only while the target encoder isopen,FinishCommandEncoderis valid only while the target encoder isopen,FinishCommandEncodertransitions the encoder tofinished,- no later command may target a
finishedencoder, - an encoder with an open child pass cannot be finished,
- an encoder cannot contain more than one open child pass at a time.
Pass State Machine
Render-pass states:
openended
Compute-pass states:
openended
Rules:
BeginRenderPasscreates a render pass inopen,BeginComputePasscreates a compute pass inopen,EndRenderPasstransitions the referenced render pass toended,EndComputePasstransitions the referenced compute pass toended,- no later command may target an ended pass,
- a pass must belong to exactly one encoder,
- a second pass may not begin in an encoder while the first is still open,
- a pass must be the currently open pass of its encoder when it is ended.
Command Validity By Scope
Commands valid without encoder or pass scope:
HelloRendererRendererHelloReplyErrorCreateBufferDestroyBufferWriteBufferCreateTextureDestroyTextureWriteTextureCreateSamplerDestroySamplerCreateBindGroupDestroyBindGroupCreateBindGroupLayoutDestroyBindGroupLayoutCreateShaderModuleDestroyShaderModuleCreateRenderPipelineDestroyRenderPipelineCreateComputePipelineDestroyComputePipelineBeginCommandEncoderQueueSubmit
Commands valid in an open encoder but outside any pass:
BeginRenderPassBeginComputePassFinishCommandEncoderCopyBufferToBufferCopyBufferToTextureCopyTextureToBufferCopyTextureToTexture
Commands valid only in an open render pass:
SetPipelinewith a render pipelineSetVertexBufferSetIndexBufferSetBindGroupSetViewportSetScissorSetBlendConstantSetStencilReferenceDrawDrawIndexedEndRenderPass
Commands valid only in an open compute pass:
SetPipelinewith a compute pipelineSetBindGroupDispatchWorkgroupsEndComputePass
Additional rules:
- draw commands are invalid outside an open render pass,
- dispatch commands are invalid outside an open compute pass,
- copy commands are invalid inside any pass,
SetViewport,SetScissor,SetBlendConstant, andSetStencilReferenceare invalid in compute passes,EndRenderPassis invalid for a compute pass id,EndComputePassis invalid for a render pass id.
Pipeline And Pass Compatibility
Rules:
SetPipelinerequires a live pipeline id,- the bound pipeline kind must match the target pass kind,
- a draw command requires a render pipeline to have been bound earlier in the same open render pass,
- a dispatch command requires a compute pipeline to have been bound earlier in the same open compute pass,
SetVertexBufferrequires a live buffer id whose usage includesVERTEX,SetIndexBufferrequires a live buffer id whose usage includesINDEX,DrawandDrawIndexedrequire every vertex-buffer slot required by the bound render pipeline to have been bound earlier in the same open render pass,DrawIndexedadditionally requires index-buffer state to have been bound earlier in the same open render pass,- rebinding a pipeline replaces the previously bound pipeline for subsequent commands in the same pass,
SetBindGrouprequires a live bind-group id,CreateBindGrouprequires a live bind-group layout id,SetBindGroupis interpreted against the currently bound pipeline layout,- if the bound pipeline declares a bind-group layout for the requested slot, the bound bind group must have been created from that exact layout,
- if a bind-group layout marks buffer bindings as dynamic,
SetBindGroupmust provide exactly one dynamic offset for each such binding in layout entry order, - each dynamic offset is applied to the corresponding bind-group entry's base offset before buffer range validation,
- after a pipeline rebind, later draw/dispatch commands validate against the newly bound pipeline's requirements rather than any earlier pipeline,
- validation may reject
SetBindGroupimmediately if no pipeline is currently bound and the runtime cannot validate the slot against a known layout.
Active runner note:
- the active fixture runner models pipeline objects, pass-local pipeline binding, pass-local vertex-buffer binding, pass-local index-buffer binding, and bind-group object binding as first-class semantic state.
Submission And Destruction Safety
The active 2.0 contract distinguishes between recording-time references and already-submitted work.
Rules:
- an object referenced by an open encoder or open pass cannot be destroyed,
- a command buffer referenced by a
QueueSubmitis consumed as immutable recorded work, - a command buffer that has already been submitted cannot be submitted again in active DRP2
2.0, - destroying a resource that is referenced by a finished but not yet submitted command buffer is invalid,
- destroying a resource that is referenced by already submitted work is invalid unless the runtime
explicitly defines completion tracking beyond the active
2.0contract, - because active
2.0has no fence or completion primitive, clients should conservatively treat submitted work as still using its referenced resources for the remainder of the stream, - destroying an already-destroyed object is invalid,
- destroying an object of the wrong kind is invalid.
Validation consequences:
- state violations should usually fail with
DRP2_ERR_INVALID_STATE, - active-use destruction should usually fail with
DRP2_ERR_USAGEorDRP2_ERR_INVALID_STATE, - pass-kind mismatches should fail with
DRP2_ERR_PASS_MISMATCH.
Readback Lifetime
Rules:
- every buffer referenced in a
QueueSubmit.readbacksentry must be live at the timeQueueSubmitis processed, - every such buffer must have
MAP_READin its declared usage, - the readback range
offset + sizemust fit within the buffer's declared size, submission_idmust be present onQueueSubmitwheneverreadbacksis non-empty,- the runtime must send exactly one
QueueSubmitReplyfor eachQueueSubmitwhosereadbackslist is non-empty, - replies must arrive in the same order as the corresponding submissions,
QueueSubmitReplymust reference asubmission_idthat matches a priorQueueSubmitwith a non-empty readbacks list; referencing an unknown or already-replied submission id is invalid,- the
readbackslist inQueueSubmitReplymust mirror the request exactly: same buffer ids, offsets, and sizes, in the same order, - each
datafield in the reply must contain exactlysizebytes encoded as base64.
Validation consequences:
- a buffer in readbacks lacking
MAP_READusage should fail withDRP2_ERR_USAGE, - a readback range that exceeds the buffer should fail with
DRP2_ERR_OUT_OF_RANGE, - a
QueueSubmitReplywith no matching pending submission should fail withDRP2_ERR_INVALID_STATE, - a
QueueSubmitReplywhose readbacks list does not match the request should fail withDRP2_ERR_INVALID_ARGUMENT.
Range And Layout Invariants
These rules supplement the per-command field semantics in COMMANDS.md.
WriteBufferrequiresoffset + sizeto fit inside the target buffer,CopyBufferToBufferrequires both source and destination ranges to fit inside their buffers,CopyBufferToTexturerequires the destination box to fit inside the selected texture subresource,CopyTextureToBufferrequires the source box to fit inside the selected texture subresource,WriteTexturerequires the written box to fit inside the selected texture subresource,bytes_per_rowandrows_per_imagedescribe payload layout and do not change object lifetime or resource shape,- texture transfer commands require
mip_levelor*_mip_levelto select an allocated mip subresource, - texture transfer commands require layout metadata to describe at least one full texel row and, for multi-image transfers, enough rows per image slice,
- these layout and mip-selection rules apply symmetrically to
WriteTexture,CopyBufferToTexture, andCopyTextureToBuffer, - schema-valid commands may still fail semantic validation if ids, ranges, usage, pass state, or layout metadata are wrong.
Invalid Sequence Examples
The following sequences are invalid in active DRP2 2.0.
Draw Outside A Render Pass
BeginCommandEncoderDraw
Reason:
Draw requires an open render pass.
Finish Encoder With Open Pass
BeginCommandEncoderBeginRenderPassFinishCommandEncoder
Reason:
an encoder cannot finish while a child pass is still open.
Copy Inside A Pass
BeginCommandEncoderBeginComputePassCopyBufferToBuffer
Reason:
copy commands are valid only at encoder scope, not inside a render or compute pass.
Destroy Resource Still Referenced By Recorded Work
CreateBufferBeginCommandEncoderCopyBufferToBufferFinishCommandEncoderDestroyBuffer
Reason:
the finished command buffer still refers to the buffer, so destruction is invalid before that work is considered no longer in use by the protocol.
Validation Consequences
Lifetime and state violations should fail during semantic validation whenever possible.
They should not be deferred to backend execution unless the violation depends on backend-only facts that are not visible at the DRP2 contract layer.