Hello!
I'm working with my own DirectX11.1 engine. Text rendering was previously done via Direct2D and DirectWrite. Rendering text this way is quite slow, so I buffered the result into a small canvas and only updated it if the string changed.
To improve performance, render the glyphs into an atlas (using the same old D2D and DirectWrite approach), then use the IDWriteTextLayout layout and call its Draw function in your custom renderer (IDWriteTextRenderer). It iterates through DWRITE_GLYPH_RUN and adds instances to the instantiated object. Glyph quad renderer.
This works well and is much faster than the previous attempt. However, rendering breaks strangely for some strings. I noticed this for the first time in the player debug his panel.
It seems to break after a small f, but only sometimes. If I replace f with any other character, it works fine.
I checked glyphAdvances in the DrawGlyphRun callback. After those nasty fs they're all over the place (not what they should be on regular strings). Then I realized that the last character of the messed up string was missing. In fact, you can see that glyphRun->glyphCount is 1 lower than it should be.
Analyzed IDWriteTextLayout using GetClusterMetrics.
hr = pDWriteFactory_->CreateTextLayout(wszText_, cTextLength_, text->font->textFormat, text->width, text->height, &text->pDWriteTextLayout);
if (FAILED(hr)) ...
DWRITE_CLUSTER_METRICS clusterMetrics[64];
UINT32 actualClusterCount = 0;
text->pDWriteTextLayout->GetClusterMetrics(clusterMetrics, 64, &actualClusterCount);
kuOutPrintf("\n pDWriteTextLayout(%S): cTextLength_(%d) actualClusterCount(%d)", wszText_, (int)cTextLength_, (int)actualClusterCount);
if (ID == 117 || ID == 118) breakpoint
this showed me that
pDWriteTextLayout(tlick: state(0) progress(0.0)): cTextLength_(29) actualClusterCount(29)
pDWriteTextLayout(flick: state(0) progress(0.0)): cTextLength_(29) actualClusterCount(28)
Here the actualClusterCount is already low and the problem is not with the rendering itself. When I checked clusterMetrics, I noticed that the length member of the first clusterMetrics entry in the offending “flick” string had a length of 2, instead of 1 like all the other members. Next, I specified the string as a fixed literal (I forget what it's called in case I'm wrong) as L”flick: state(0) progress(0.0)” to prevent string formatting issues and just to be sure. We checked the code points of the string for (102 (f ), 108 (l), etc.).
I checked all the members (get the function from the interface) and made sure that the settings for IDWriteTextFormat text->font->textFormat are the same in both calls. I replaced the font Josefin Sans with Arial and the problem was resolved. I thought the font might be the problem in the end. So I downloaded Noto Sans and had the same issue and the same placement mistake (clusterMetrics length 2).
It seems a bit difficult to use IDWriteTextAnalyzer. I tried it a little earlier and thought I saw something.
Does anyone know what I can do? In my opinion, the problem lies in CreateTextLayout (see code above). Is it a bug in DirectWrite?
thank you.
Edit: I also adjusted Text → Width and Text → Height to make sure it wasn't a size-based formatting issue.