Michael Langbein
Michael Langbein

Reputation: 23

TransformFeedback with instanced drawing

How does WebGL write data to a transform-feedback output when doing instanced drawing? Particularly, how does it decide on what index of the transform-feedback-buffer to write to when using instanced drawing?

Consider the following example:

Setup

Here's some pseudo-code (full code available here):

Vertex shader:

#version 300 es
in vec2 rectVertex;
in vec2 offset;
out vec2 newOffset;
void main() {
  gl_Position = vec4(rectVertex + offset, 0, 1);
  newOffset = offset + vec2(0.02);
}

Fragment shader:

#version 300 es
precision mediump float;
out vec4 fragColor;
void main() {
  fragColor = vec4(1, 0, 0, 1);
}

JS:


  const program = createProgram(vertexShader, fragmentShader, ['newOffset']);
  const rectBuffer = createBuffer(rectData.flat()); // 6*2 entries
  const offsetBuffer1 = createBuffer(offsetData.flat()); // 100*2 entries
  const offsetBuffer2 = createBuffer(offsetData.flat()); // 100*2 entries

  const vao1 = createVao(
    {
      rectVertex: { buffer: rectBuffer, nrInstances: 0 },
      offset: { buffer: offsetBuffer1, nrInstances: 1 },
    },
    program
  );
  const tf1 = createTf({
    newOffset: offsetBuffer2,
  });

  const vao2 = createVao(
    {
      rectVertex: { buffer: rectBuffer, nrInstances: 0 },
      offset: { buffer: offsetBuffer2, nrInstances: 1 },
    },
    program
  );
  const tf2 = createTf({
    newOffset: offsetBuffer1,
  });

  drawInstanced({ program, vao: vao1, tf: tf1, nrInstances });

  drawInstanced({ program, vao: vao2, tf: tf2, nrInstances });


Observation

Chrome gives me a helpful error:

[.WebGL-0x11c00521400] GL_INVALID_OPERATION: Not enough space in bound transform feedback buffers.

Why does that error occur?

I'm not quite sure... but here's my best guess, written in python pseudo-code:

import numpy as np

nrInstances = 5
nrVertices = 3

positionBuffer = {
    "data": np.array([[0,1], [2,3], [4,5], [5,6], [6,7]], dtype=np.float32),
    "nrInstances": 1
}

# transform feedback output
positionNewBuffer = {
    "data": np.array([[0, 0]] * nrInstances * nrVertices, dtype=np.float32),
}


# my understanding of how webgl fetches data from instanced
# and non-instanced attributes:
def getDataIn(i, v, buffer):
    index = 0
    if "nrInstances" in buffer:
        # https://registry.khronos.org/OpenGL/specs/es/3.0/es_spec_3.0.pdf#nameddest=subsection.2.9
        # If an enabled vertex attribute array is instanced (it has a non-zero 
        # divisor), the element that is transferred to the GL, for
        # all vertices, is given by:
        # floor(instance / divisor)
        index = int(i / buffer["nrInstances"])   # independent of v!

    # non-instanced: same vertices used for all instances
    else:
        index = v                                # independent of i!

    data = buffer["data"][index]
    return data


# my understanding of how webgl places data in a transform-feedback buffer:
def setDataOut(value, i, v, buffer):
    # https://registry.khronos.org/OpenGL/specs/es/3.0/es_spec_3.0.pdf#nameddest=subsection.2.15.2
    # not sure how this is implemented when doing instanced drawing,
    # but here's my guess:
    indexOut = i * nrVertices + v
    buffer["data"][indexOut] = value


# draw call:
for i in range(nrInstances):
    for v in range(nrVertices):
        valPos = getDataIn(i, v, positionBuffer)
        newVal = valPos + 0.02
        setDataOut(newVal, i, v, positionNewBuffer)

The problem here is this: While webgl expects the input-attribute position to have a buffer with nrInstances * 2 elements, it requires the output-transform-feedback buffer to have nrInstances * nrVertices * 2 elements.

Question

Is my suspicion correct? Is there a way to configure transform feedback in such a way that I can still combine transform feedback with instanced drawing?

Upvotes: 0

Views: 84

Answers (0)

Related Questions