software-mansion / software-mansion/TypeGPU

GPUBuffer, binding sub-regions, drawIndexed with baseVertex and firstInstance

Open
#2,236 1 comment 2 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
TypeScript
Stars
3.2k
Forks
122
Avg merge
3d 5h
Merged PRs (30d)
34

Description

In project I'm working on I ran into a case that TypeGPU api doesn't natively support. I'm mostly sharing this out of curiosity and in case it's useful, the unwrap escape hatch is great and everything works.

1. GPUBuffer

I need to use a raw GPUBuffer as a vertex source to get sub-buffer writes at specified byte offsets, like this:

device.queue.writeBuffer(page, alloc.offset, someVertexData);

if I understand correctly, TypeGPU write() replaces the entire buffer, and for my case it would possibly have support something like
buffer.writeAt(offset,data). Alternatively, a way to use or wrap GPUBuffer so it can be accessed directly without unwrapping

2. Binding sub region of a buffer - draw indexed with baseVertex and firstInstance

My buffers hold many objects' geometry packed together, but I need each draw call to read only one objects vertices and indices - not the whole buffer.

setIndexBuffer has built-in offset and size params:

pass.setIndexBuffer(
        fullBuffer,
        "uint16",
        indexOffset,
        indexSize,
      );

For vertex buffer I have to set the entire buffer in the pass:

pass.setVertexBuffer(0, fullBuffer);

but then I can use drawIndexed like this:

pass.drawIndexed(
  draw.indexCount,   // 36 indices for a cube
  1,                 // 1 instance
  0,                 // firstIndex
  draw.baseVertex,   // added to every index before vertex fetch acts as an offset
  draw.modelSlot,    // firstInstance - becomes instance_index in shader
);

Now when the GPU processes index 0, it actually fetches vertex 0 + 24 = 24. Index 1 fetches vertex 25. And so on. The indices stay [0,..,23] but they're shifted to read from the right region of the buffer.

This is the other half of why I have to unwrap. TypeGPU's draw abstractions don't expose baseVertex or firstInstance.

My draw code currently looks like this:

const encoder = device.createCommandEncoder();
  const pass = encoder.beginRenderPass({
    colorAttachments: [
      {
        view: context.getCurrentTexture().createView(),
        clearValue: [0.04, 0.04, 0.07, 1],
        loadOp: "clear" as const,
        storeOp: "store" as const,
      },
    ],
    depthStencilAttachment: {
      view: depthTexture.createView(),
      depthClearValue: 1,
      depthLoadOp: "clear" as const,
      depthStoreOp: "store" as const,
    },
  });
  const rawPipeline = root.unwrap(renderPipeline);
  pass.setPipeline(rawPipeline);
  pass.setBindGroup(0, rawCameraBindGroup);
  pass.setBindGroup(1, rawModelsBindGroup);

  for (const [vertPage, draws] of drawsByPage) {
    pass.setVertexBuffer(0, vertexPool.getBuffer(vertPage));
    for (const draw of draws) {
      pass.setIndexBuffer(
        indexPool.getBuffer(draw.idxPage),
        "uint16",
        draw.idxOffset,
        draw.idxSize,
      );
      pass.drawIndexed(draw.indexCount, 1, 0, draw.baseVertex, draw.modelSlot);
    }
  }

  pass.end();
  device.queue.submit([encoder.finish()]);

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with TypeGPU's buffer write API and draw abstractions, comparing them with the raw GPUBuffer, setVertexBuffer, setIndexBuffer, and drawIndexed calls shown here. Done means supporting sub-buffer writes and exposing the needed vertex-region, baseVertex, and firstInstance behavior without requiring unwrap.

Written by the indexing model from the issue text.

Assessment

Tech stack
typescript
Domain
api, computer-graphics
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.