feat: expose query sets and render bundle encoders - #337
Conversation
Add public Device.CreateQuerySet and CreateRenderBundleEncoder wrappers, including descriptors, resource types, lifecycle handling.
kolkov
left a comment
There was a problem hiding this comment.
Thanks for the PR! Good structural foundation — build tags, lifecycle pattern (atomic.Bool + idempotent Release), and HAL delegation are all correct.
A few issues to address before merge:
1. QueryType duplication
QueryType is already defined in hal/descriptor.go:547-555 with identical values. The PR adds a second independent definition in types.go, then casts between them in toHAL() via hal.QueryType(d.Type).
In Rust wgpu, QueryType lives in wgpu-types (the shared types crate) — single source of truth (wgpu-types/src/lib.rs:450). Our equivalent is gputypes, but for now a type alias works:
type QueryType = hal.QueryType
const (
QueryTypeOcclusion = hal.QueryTypeOcclusion
QueryTypeTimestamp = hal.QueryTypeTimestamp
)This eliminates the duplication and the fragile cast.
2. Incomplete API — QuerySet is unusable without companion methods
Creating a QuerySet is only half the story. The W3C WebGPU spec (index.bs:11239-11295) requires companion methods to actually use queries:
| Method | Spec | Our HAL | Public API |
|---|---|---|---|
CommandEncoder.resolveQuerySet() |
Required | ✅ hal/command.go:62-68 |
❌ Missing |
RenderPassDescriptor.timestampWrites |
Required | ✅ hal/descriptor.go:481-482 |
❌ Missing |
RenderPassDescriptor.occlusionQuerySet |
Required | ❌ Not in HAL | ❌ Missing |
RenderPass.beginOcclusionQuery() |
Required | ❌ Not in HAL | ❌ Missing |
RenderPass.endOcclusionQuery() |
Required | ❌ Not in HAL | ❌ Missing |
Without at least resolveQuerySet, a user creates a QuerySet but can never read results from it.
Suggestion: either add CommandEncoder.ResolveQuerySet() in this PR (the HAL implementation is ready on all backends), or add a doc comment stating "Phase 1 — companion methods in follow-up PR" with a link to #330.
3. Incomplete API — RenderBundle is unusable without ExecuteBundles
Same pattern: RenderBundleEncoder.Finish() produces a RenderBundle, but there's no way to execute it. The spec requires RenderPass.executeBundles() (index.bs:13935-13948), and our HAL already implements it (hal/command.go:149-151, all 6 backends).
Suggestion: add RenderPassEncoder.ExecuteBundles(bundles ...*RenderBundle) to the public API in this PR.
4. Finish() should accept a descriptor
Both the W3C spec and Rust wgpu pass a descriptor to finish:
- Spec:
GPURenderBundle finish(optional GPURenderBundleDescriptor descriptor = {})(index.bs:14075) - Rust:
pub fn finish(self, desc: &RenderBundleDescriptor) -> RenderBundle(render_bundle_encoder.rs:76)
The descriptor contains at minimum a label for the resulting bundle. Suggestion:
func (e *RenderBundleEncoder) Finish(desc *RenderBundleDescriptor) (*RenderBundle, error)Returning (*RenderBundle, error) is more Go-idiomatic than returning nil on double-finish.
5. Encoder methods need guard after Finish()
The W3C spec defines an encoder state machine (index.bs:10455-10491): commands on an "ended" encoder must generate a validation error. Currently only Finish() checks e.finished — the 6 draw/state methods (SetPipeline, SetBindGroup, SetVertexBuffer, SetIndexBuffer, Draw, DrawIndexed) pass straight through to HAL after finish.
Go doesn't have Rust's ownership semantics that prevent this at compile time, so a runtime check is needed:
func (e *RenderBundleEncoder) SetPipeline(pipeline *RenderPipeline) {
if e.finished.Load() {
return // or log warning
}
e.hal.SetPipeline(pipeline.hal)
}Overall the code quality is good — you clearly understand the wgpu architecture. These changes will make the API complete and usable. Happy to help if you have questions!
|
Hi! Thanks for the review! This is my first open-source contribution, so I really appreciate your feedback. I’ll update the MR according to your comments soon.
Hi! Thanks for the review! This is my first open-source contribution, so I really appreciate the feedback. I’ll address the comments and update the MR soon. |
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
- alias QueryType to the shared HAL definition - expose CommandEncoder.ResolveQuerySet - add render pass timestamp writes - expose RenderPassEncoder.ExecuteBundles - accept RenderBundleDescriptor in Finish - return errors from repeated Finish calls - guard render bundle encoder methods after Finish - add lifecycle and delegation tests
|
Hi! I've made the requested changes. Could you please take another look when you have time? Thanks! |
This comment was marked as outdated.
This comment was marked as outdated.
|
Hi @gusevgrishaem1 — thanks again for the patience 🙏 #347 is now merged into Really appreciate the work you already put in — especially completing the companion methods and RenderBundle surface after the first review round. Once this is synced with Goal after update
Step-by-step1) Sync your fork branch with upstream
|
|
Thanks for the feedback! I’ve updated MR according to the "Step-by-step". Could you please take another look? |
|
Hi @gusevgrishaem1 — thanks for following the step-by-step after #347 🙏 Sync looks good:
One blocking issue before merge: TimestampWrites never reach the HAL via
|
Summary
This PR adds public query set types and render bundle encoders.
Related to #330