Hi. I need to draw text into a D3D11 texture, but I have encountered very poor performance and don't know how to fix it. I use DirectWrite and D2D1 to render text. It suits me very well because it allows me to create the effects I need and can work with unicode characters (emoticons, etc.).
I do the following:
- Create a D3D11 texture (ID3D11Device::CreateTexture2D)
- Create a DXGI render target via D2D1 (ID2D1Factory7::CreateDxgiSurfaceRenderTarget)
- Render text inside ID2D1RenderTarget::BeginDraw and ID2D1RenderTarget::EndDraw
And so. Several textures with text can be created per frame in the game (2-5). After creating a texture (or taking it from the pool), the following code is executed:
ID2D1RenderTarget::BeginDraw();
// render text, etc...
ID2D1RenderTarget::EndDraw();
But the game started to freeze a lot. I measured the code execution time, and noticed that the EndDraw call takes a very long time. From 1 to 5 ms (I have a good hardware and this is VERY much for it). I commented out the text rendering code and left ONLY the ID2D1RenderTarget::BeginDraw
and ID2D1RenderTarget::EndDraw
calls. I got exactly the same results.
It's not about DirectWrite, etc. It's just that calling BeginDraw
and EndDraw
for a DXGI surface takes a very long time. But what other way can I get D2D1 to draw what I need into a D3D11 texture in runtime?
Microsoft writes here https://learn.microsoft.com/en-us/windows/win32/direct2d/improving-direct2d-performance it:
When rendering to a DXGI surface, Direct2D saves the state of the Direct3D devices while rendering and restores it when rendering is completed. Every time that a batch of Direct2D rendering is completed, the cost of this save and restore and the cost of flushing all the 2D operations are paid, and yet, the Direct3D device is not flushed. Therefore, to increase performance, limit the number of rendering switches between Direct2D and Direct3D.
But LOL, even if I combine everything into one texture and call BeginDraw
and EndDraw
once per frame - ~5 ms is a LOT.
For clarity: