bkaradzic / bgfx

Cross-platform, graphics API agnostic, "Bring Your Own Engine/Framework" style rendering library.
https://bkaradzic.github.io/bgfx/overview.html
BSD 2-Clause "Simplified" License
14.92k stars 1.93k forks source link

Hitching when uploading large textures #664

Open WangHoi opened 8 years ago

WangHoi commented 8 years ago

When using bgfx in our company's game. The texture upload flow is hard to make smooth.

Currently, the loading thread load image, preparing memory, the main thread create them. Event once per frame, when creatign large texture(2048x2048 uncompressed with mipmaps), render thread block in glTexImage2D, about 20ms, and the delay is noticeable.

We have modified bgfx code, expose a PBO pointer to the loading thread, then unmap and trigger texture upload in main thread.It works well. Added the follow funcs:

PIXEL_WRITE_BUFFER_HANDLE CreatePixelWriteBuffer(uint32 size);
std::future<void*> MapPixelWriteBuffer(PIXEL_WRITE_BUFFER_HANDLE handle);
void UnmapPixelWriteBuffer(PIXEL_WRITE_BUFFER_HANDLE handle);
void DestroyPixelWriteBuffer();
void UpdateTexture2D(TEXTURE_HANDLE handle, uint8 mip, uint16 x, uint16 y, uint16 width, uint16 height, PIXEL_WRITE_BUFFER_HANDLE pixel_buffer);

I think the ability to map/unmap buffer, will help texture/vertex data streaming when using bgfx.

bkaradzic commented 8 years ago

Can you create repro case in one of bgfx examples? And I'll fix internals instead of changing API.

For passing memory that's owned by systems outside bgfx, and avoiding copies you should use bgfx::makeRef: https://bkaradzic.github.io/bgfx/bgfx.html#_CPPv2N4bgfx7makeRefEPKv8uint32_t9ReleaseFnPv

WangHoi commented 8 years ago

To reproduce, modify example-08-update/update.cpp

  1. init with OpenGL renderer type.
  2. change 'm_texture2dSize' to 2048.
  3. around line 376, update that texture: image
  4. Noticed 6ms frame time increase while call 'updateTexture2D' every frame.

My box: i5-4590, gtx960, pretty descent machine.

WangHoi commented 8 years ago

Btw, I've an idea for a new texture-streaming example.

Draw an animated bunny mesh in foreground, progressively loading a very large texture in background. And the large texture is loaded with highest mipmap first, and progressively rendered from blurring to clarity.

bkaradzic commented 8 years ago

That should be up to app, bgfx doesn't deal with high level concepts like that. I'm gonna see just if I can remove hitching for texture upload requests.

jazzbre commented 8 years ago

Unity 5.3+ when using OpenGL ES 2 (which doesn't support gl contexts and so threaded rendering) solves this by uploading texture part by part.

WangHoi commented 8 years ago

Yeah, part by part is do-able, need to be careful when uploading part of compressed texture, and need to adjust the step size of uploaded part according to platform. With this method, doesn't need to change bgfx's api.

We expose a PBO pointer, and fill that buffer in another thread, then create/update texture from pbo in main thread. It also works in out game.

qimmer commented 5 years ago

Is this something that is going to be looked at, at some point? Having the same issue with Direct3D11. When creating a static large (4k) RGBA texture, it creates a momentary stall in the next frame rendered. As far as I know, it is pretty common practice to upload texture data on a separate thread on D3D11. Currently, loading textures (even a single large one) on-the-fly is not possible while still maintaining a consistent framerate.

kalmard0 commented 4 months ago

I'm running into the same issue. I'm not sure what workaround there is - simply throttling texture uploads is not viable when a single upload takes longer than 16ms. Perhaps textures could be uploaded in multiple parts over multiple frames, but that seems like a huge PITA.