Core GPU programming
Outcome
Core gives you explicit control of GPU work without tying the application to raw WebGPU or WebGL 2 objects. After reading this guide, you should be able to answer five questions for any rendering or compute task:
- Which backend and capabilities does the task require?
- Which resources must live on the GPU, and who owns them?
- How does shader code see those resources?
- Which commands produce the result, and when are they submitted?
- When can resources be reused, read back, resized, or destroyed?
If you would rather have geometry, shader inputs, pipeline reuse, and redraw tracking managed for you, start with the Engine guide. Core is the right layer when those details are part of the problem you need to solve.
Mental model
A Core application has two kinds of state:
- Durable GPU state includes buffers, textures, samplers, shaders, pipelines, and presentation contexts. Create these deliberately, reuse them across frames, and destroy the resources your application owns.
- Recorded work includes copies, render passes, compute passes, and command buffers. An encoder records an ordered unit of work; submitting it makes that work eligible to execute.
The Device connects the two. It reports capabilities, creates resources and pipelines, starts
passes, and submits finished commands. It does not decide what your frame loop should render or
when your application should redraw.
adapter → device → resources → layouts and bindings → pipeline
↓
CPU update → command encoder → render/compute pass → submit → present or read back
The important conclusion is that resources describe what exists; commands describe what happens to it. Keeping those lifetimes separate makes performance and ownership much easier to reason about.
Complete workflow
1. Choose and create a device
Import the adapters your application can use, request webgpu, webgl, or
best-available, then inspect features and limits before selecting an implementation path.
See GPU initialization.
2. Create owned resources
Create buffers for linear data and textures for sampled or renderable images. Declare every usage a resource will need; backends use that information for validation and allocation. Keep ownership explicit so teardown does not destroy borrowed resources. See GPU resources and GPU memory.
3. Describe the shader interface
Layouts define how bytes become shader values. Bindings connect buffers, textures, samplers, and uniform blocks to that interface. Vertex attributes are one specialized input path; storage buffers are the general WebGPU data path. See bindings, memory layouts, and tabular data in WGSL.
4. Build reusable pipeline state
Compile shaders and fixed rendering or compute state into pipelines. Parameters such as depth, blending, and culling belong to the pipeline or pass according to how frequently they change. See rendering and GPU parameters.
5. Encode and submit work
Record uploads, copies, render passes, and compute passes in dependency order. Use immediate helpers for isolated updates; use an explicit command encoder when ordering several operations matters. Finish the command buffer and submit it once. See issuing GPU commands.
6. Present, read back, and reuse
Present rendered output through a canvas context, or request an asynchronous readback when the CPU genuinely needs a result. Reuse resources and pipelines between frames; recreate only what changed. Avoid using readback as an ordinary connection between GPU stages.
7. Destroy what you own
Stop producers first, then destroy application-owned models, pipelines, buffers, textures, and the device. Borrowed resources remain the responsibility of their owner.
Choose the next page
| If you need to… | Continue with… | Conclusion you should reach |
|---|---|---|
| Open a portable backend | GPU initialization | Select by required capabilities, not by browser name. |
| Understand allocation and transfer cost | GPU memory | Keep intermediate data GPU-resident when possible. |
| Upload or copy linear data | GPU buffers | Choose an operation from access pattern and synchronization cost. |
| Sample or render images | GPU textures | Format, usage, layout, and sampling must agree. |
| Expose data to shaders | GPU bindings | A stable ownership convention keeps interfaces composable. |
| Render into a canvas or texture | GPU rendering | Reuse resources and pipelines; encode only the work for this frame. |
| Start from a small task | Core GPU cookbook | Copy one complete lifecycle, then expand it. |
Decisions and tradeoffs
- Core or Engine? Use Core when resource, binding, pass, or submission behavior is central. Use Engine when the task is naturally one or more reusable models.
- WebGPU or portable? Provide both WGSL and GLSL paths when WebGL 2 is a requirement. Do not assume that a WebGPU-only storage or compute feature has a transparent fallback.
- Immediate helper or encoder? Prefer a helper for one independent update. Prefer explicit encoding when copies, compute, and rendering must form one ordered submission.
- Readback or another GPU stage? Keep data on the GPU unless JavaScript must consume the result. Readbacks introduce latency and may force synchronization.
Common mistakes
- Creating pipelines, large buffers, or textures on every frame instead of reusing them.
- Omitting a required resource usage and discovering the mismatch only when encoding work.
- Treating byte layout, shader value type, and binding location as the same concept.
- Reading GPU results back merely to decide the next draw or dispatch.
- Destroying borrowed resources, or forgetting to destroy application-owned resources.
- Assuming Core schedules a frame loop or redraw policy; those remain application decisions.
Next steps
- Use the Core GPU cookbook for short, copyable workflows.
- Use the Core API overview to map concepts to exact classes.
- Move up to Engine when a managed
Modelis a better unit of work. - Add GPU scheduling when several GPU operations need dependency scheduling, transient reuse, indirect work, or bounded multi-frame execution.