Search code examples
javascriptwebglwebgl2transform-feedback

Can't wait on a fence


I'm trying to get some data from TRANSFORM_FEEDBACK_BUFFER with the code below:

const transform_feedback = gl.createTransformFeedback();
gl.bindTransformFeedback(gl.TRANSFORM_FEEDBACK, transform_feedback);
gl.transformFeedbackVaryings(program, ['position'], gl.INTERLEAVED_ATTRIBS);
gl.linkProgram(program);
const feedback_buffer = gl.createBuffer();

const data_length = 2;
const output_data = new Float32Array(data_length);

gl.bindBuffer(gl.TRANSFORM_FEEDBACK_BUFFER, feedback_buffer);
gl.bufferData(gl.TRANSFORM_FEEDBACK_BUFFER, output_data, gl.STATIC_READ);
gl.bindBufferBase(gl.TRANSFORM_FEEDBACK_BUFFER, 0, feedback_buffer);

gl.beginTransformFeedback(gl.POINTS);
gl.drawArrays(gl.POINTS, 0, data_length);
gl.endTransformFeedback();

gl.getBufferSubData(gl.TRANSFORM_FEEDBACK_BUFFER, 0, output_data);

But if I do in this way, I get the following warning msg on getBufferSubData:

performance warning: READ-usage buffer was read back without waiting on a fence. This caused a graphics pipeline stall.

Then, I tried to add the below code just after gl.endTransformFeedback();:

const fence = gl.fenceSync(gl.SYNC_GPU_COMMANDS_COMPLETE, 0);
gl.flush();
wait_for_results = async () => {
    const status = gl.clientWaitSync(fence, 0, 0);
    if (status === gl.CONDITION_SATISFIED || status === gl.ALREADY_SIGNALED) {
        gl.deleteSync(fence);
        gl.getBufferSubData(gl.TRANSFORM_FEEDBACK_BUFFER, 0, output_data);
        return true;
    } else {
        return false;
    }
};

let result_is_ok = false;
while (!result_is_ok) {
    result_is_ok = await wait_for_results();
}

The problem I'm having here is that status is always returning gl.TIMEOUT_EXPIRED. Then I tried to set gl.MAX_CLIENT_WAIT_TIMEOUT_WEBGL as the timeout value in gl.clientWaitSync, then I got:

WebGL: INVALID_OPERATION: clientWaitSync: timeout > MAX_CLIENT_WAIT_TIMEOUT_WEBGL

This also happens if I set gl.MAX_CLIENT_WAIT_TIMEOUT_WEBGL - 1. Next, I tried setting gl.TIMEOUT_IGNORED as timeout value, with this set, status is getting gl.WAIT_FAILED.

What am I missing here in order to rid of that performance warning?


Solution

  • Thanks @gman for the help in github.

    What I did to get rid of that performance warning with the guidelines in the link above:

    ...
    gl.beginTransformFeedback(gl.POINTS);
    gl.drawArrays(gl.POINTS, 0, data_length);
    gl.endTransformFeedback();
    
    gl.bindTransformFeedback(gl.TRANSFORM_FEEDBACK, null);
    
    const fence = gl.fenceSync(gl.SYNC_GPU_COMMANDS_COMPLETE, 0);
    gl.flush();
    
    let aux_resolve;
    const aux_promise = new Promise(resolve => aux_resolve = resolve);
    checkSync = () => {
        const status = gl.clientWaitSync(fence, 0, 0);
        switch (status) {
            case gl.TIMEOUT_EXPIRED:
                return setTimeout(checkSync);
            case gl.WAIT_FAILED:
                throw new Error('Something went wrong...');
            default:
                gl.deleteSync(fence);
                gl.getBufferSubData(gl.TRANSFORM_FEEDBACK_BUFFER, 0, output_data);
                aux_resolve();
        }
    }
    setTimeout(checkSync);
    await aux_promise;
    
    console.log(output_data);