Skip to content

glDrawElements draws nothing when ELEMENT_ARRAY_BUFFER is bound, but ARRAY_BUFFER is not. #26460

@paradust7

Description

@paradust7

Version of emscripten/emsdk:
emcc (Emscripten gcc/clang-like replacement + linker emulating GNU ld) 5.0.3 (285c424)
clang version 23.0.0git (https:/github.com/llvm/llvm-project e5927fecf8a6ce89e1a4eac5b828e7d42676452a)
Target: wasm32-unknown-emscripten
Thread model: posix

Minimal example to demonstrate the problem visually

https://gist.github.com/paradust7/cd6610b76939b9756b6ee561a929164d

Compile with:

emcc -g -O0 -s USE_SDL=2 -s FULL_ES2=1 -s WASM=1 -s ALLOW_MEMORY_GROWTH=1 -o index.html minimal.c

And then serve with python3 -m http.server 8080 (or other).

Explanation

The problem originates from here:

emscripten/src/lib/libwebgl.js

Lines 3853 to 3908 in cb060ca

glDrawElements: (mode, count, type, indices) => {
#if FULL_ES2
var buf;
var vertexes = 0;
if (!GLctx.currentElementArrayBufferBinding) {
var size = GL.calcBufLength(1, type, 0, count);
buf = GL.getTempIndexBuffer(size);
GLctx.bindBuffer(0x8893 /*GL_ELEMENT_ARRAY_BUFFER*/, buf);
GLctx.bufferSubData(0x8893 /*GL_ELEMENT_ARRAY_BUFFER*/,
0,
HEAPU8.subarray(indices, indices + size));
// Calculating vertex count if shader's attribute data is on client side
if (count > 0) {
for (var i = 0; i < GL.currentContext.maxVertexAttribs; ++i) {
var cb = GL.currentContext.clientBuffers[i];
if (cb.clientside && cb.enabled) {
let arrayClass;
switch(type) {
case 0x1401 /* GL_UNSIGNED_BYTE */: arrayClass = Uint8Array; break;
case 0x1403 /* GL_UNSIGNED_SHORT */: arrayClass = Uint16Array; break;
#if FULL_ES3
case 0x1405 /* GL_UNSIGNED_INT */: arrayClass = Uint32Array; break;
#endif
default:
GL.recordError(0x502 /* GL_INVALID_OPERATION */);
#if GL_ASSERTIONS
err('type is not supported in glDrawElements');
#endif
return;
}
vertexes = new arrayClass(HEAPU8.buffer, indices, count).reduce((max, current) => Math.max(max, current)) + 1;
break;
}
}
}
// the index is now 0
indices = 0;
}
// bind any client-side buffers
GL.preDrawHandleClientVertexAttribBindings(vertexes);
#endif
GLctx.drawElements(mode, count, type, indices);
#if FULL_ES2
GL.postDrawHandleClientVertexAttribBindings(count);
if (!GLctx.currentElementArrayBufferBinding) {
GLctx.bindBuffer(0x8893 /*GL_ELEMENT_ARRAY_BUFFER*/, null);
}
#endif
},

When !currentElementArrayBufferBinding, "vertexes" (the maximum vertex count) is calculated using the indices data. Otherwise, vertexes is never calculated and remains 0, so vertex data is never copied.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions