I’ve noticed a weird edge case where glTexSubImage2D
stalls the CPU for 5 seconds, but only when:
- its internal format is 16-bit ushort
glTexStorage2D
is not called beforehand
The stall doesn’t happen with 8-bit byte or 32-bit float textures, even if glTexStorage2D
isn’t called
I’m able to reproduce it with the small demo code below. I understand texture uploads should run across multiple frames with fences, but I’ve merged it all into this one function for simplicity:
// This works great
// var pixelType = GL_UNSIGNED_BYTE;
// var sizedFormat = GL_RGB8;
// uint bytesPerPixel = 3;
// This also works great
// var pixelType = GL_FLOAT;
// var sizedFormat = GL_RGB32F;
// uint bytesPerPixel = 12;
// This format causes a stall on glTexSubImage2D
var pixelType = GL_UNSIGNED_SHORT;
var sizedFormat = GL_RGB16;
uint bytesPerPixel = 6;
uint textureSize = 4096;
uint textureSizeBytes = textureSize * textureSize * bytesPerPixel;
// Create a texture
var texHandle = glGenTexture();
glBindTexture(GL_TEXTURE_2D, texHandle);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, textureSize, textureSize, 0, GL_RGB, pixelType, NULL);
/* This call fixes the stall: */ glTexStorage2D(GL_TEXTURE_2D, 1, sizedFormat, textureSize, textureSize);
glTexParameter(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameter(GL_TEXTURE_2D, GL_TEXTURE_MAX_FILTER, GL_NEAREST);
glTexParameter(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameter(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glBindTexture(GL_TEXTURE_2D, 0);
// Create and map a PBO
var pboHandle = glGenBuffer();
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pboHandle);
glBufferStorage(GL_PIXEL_UNPACK_BUFFER, textureSizeBytes, null, GL_MAP_PERSISTENT_BIT | GL_MAP_WRITE_BIT);
var pboPtr = glMapBufferRange(GL_PIXEL_UNPACK_BUFFER, 0, textureSizeBytes, GL_MAP_PERSISTENT_BIT | GL_MAP_WRITE_BIT | GL_FLUSH_EXPLCIIT_BIT);
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
// Write to PBO
// ...
// Flush the PBO
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pboHandle);
glFlushMappedBufferRange(GL_PIXEL_UNPACK_BUFFER, 0, textureSizeBytes);
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
// Copy from PBO to texture
glBindTexture(GL_TEXTURE_2D, texHandle);
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pboHandle);
/* This function stalls */ glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, textureSize, textureSize, GL_RGB, pixelType, NULL);
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
glBindTexture(GL_TEXTURE_2D, 0);
I’m happy with the glTexStorage2D
fix, but I’m curious what’s going on under the covers to cause this stall.