首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >ExtTextOutW创建者版本更新后QHD/4K屏幕上的x50性能下降

ExtTextOutW创建者版本更新后QHD/4K屏幕上的x50性能下降
EN

Stack Overflow用户
提问于 2017-05-10 14:29:43
回答 1查看 440关注 0票数 9

由于一些奇怪的原因,调用WinAPI的ExtTextOutW函数在高分辨率位图(2560x1440/3840x2160)上绘制剪裁文本,在用Creator版本更新更新Windows 10之后,会导致~x50性能下降。从我的用户的测试和调试日志来看,位图或字体大小的细微差别可能会触发性能下降。

下面是一个显示性能命中的调试日志:

代码语言:javascript
复制
10/05/2017 15:51:50 [   63227,186] : Calculate Rect
10/05/2017 15:51:50 [   63227,190] : Rect : Left=263, Top=504, Right=3561, Bottom=2155
10/05/2017 15:51:50 [   63227,193] : Set Shadow Color
10/05/2017 15:51:50 [   63227,198] : Render Text Shadow
10/05/2017 15:51:50 [   63236,650] : Set Text Color
10/05/2017 15:51:50 [   63236,661] : Render Text "Kingdom come Deliverance"
10/05/2017 15:51:50 [   63246,062] : Rendering complete

从日志中可以看到,对ExtTextgOutW的单个调用需要9.5ms,而这个调用在creators更新之前花费了不到1ms的时间。

下面是实际代码,可以与上面的调试输出进行比较:

代码语言:javascript
复制
  {$IFDEF TEXTRENDERTRACE}DebugMsgFT('c:\log\.TextRender.txt','Calculate Rect');{$ENDIF}
  cRect    := Rect(X,Y,Width+X,MainForm.Monitor.Height-(1+(MainForm.Monitor.Height div 540)));
  {$IFDEF TEXTRENDERTRACE}DebugMsgFT('c:\log\.TextRender.txt','Rect : Left='+IntToStr(cRect.Left)+', Top='+IntToStr(cRect.Top)+', Right='+IntToStr(cRect.Right)+', Bottom='+IntToStr(cRect.Bottom));{$ENDIF}
  {$IFDEF TEXTRENDERTRACE}DebugMsgFT('c:\log\.TextRender.txt','Set Shadow Color');{$ENDIF}
  srcColor := txtCanvas.Font.Color;
  txtCanvas.Font.Color := OutLineColor;
  {$IFDEF TEXTRENDERTRACE}DebugMsgFT('c:\log\.TextRender.txt','Render Text Shadow');{$ENDIF}
  Windows.ExtTextOutW(txtCanvas.Handle,X  ,Y+(MainForm.Monitor.Height div 540),ETO_CLIPPED,@cRect,@S[1],I,nil);
  {$IFDEF TEXTRENDERTRACE}DebugMsgFT('c:\log\.TextRender.txt','Set Text Color');{$ENDIF}
  txtCanvas.Font.Color := srcColor;
  {$IFDEF TEXTRENDERTRACE}DebugMsgFT('c:\log\.TextRender.txt','Render Text "'+S+'"');{$ENDIF}
  Windows.ExtTextOutW(txtCanvas.Handle,X  ,Y  ,ETO_CLIPPED,@cRect,@S[1],I,nil);
  {$IFDEF TEXTRENDERTRACE}DebugMsgFT('c:\log\.TextRender.txt','Rendering complete'+CRLF);{$ENDIF}

这个代码做了一个非常简单的阴影效果,通过渲染相同的文本两次,在Y偏移量和颜色上略有不同。

下面是与我的论坛用户的完整讨论,在那里我们尝试在各种各样的硬件上调试这个问题(附加的调试日志包含在文章中):http://forum.inmatrix.com/index.php?showtopic=14995&page=2

我们将DPI设置为100%进行测试,以确保触发器与Creators中引入的DPI更改无关。

有人知道是什么引起的吗?有解决办法吗?

更新1*

至少在最初的测试中,"DrawTextExW“似乎也受到性能损失的影响。在测试期间使用的字体是Arial,性能问题似乎与字体的大小有关,因为用户报告说,在屏幕上添加更多较小的行(更多的文本以较低的分辨率呈现)大大提高了性能。

更新2*

我编写了一个小工具来分析这个问题,您可以在这个GitHub存储库中找到这个工具:https://github.com/bLightZP/WindowsTextRenderingProfiler

问题似乎取决于字体大小,例如,在2560x1440屏幕上,呈现一行"Arial“字体文本,大小为"35”21 2ms,而大小为"34“则需要2ms。

这将呈现给具有32位像素格式的Delphi TBitmap的HDC,并且禁用裁剪只对性能有很小的影响。

*更新3*

塞巴斯蒂安Z的答案确实恢复了预创建者版本的性能水平,我已经更新了GitHub上的示例代码以反映他的答案,但我已经能够在Windows764bit和1920x1080屏幕上重现这个问题,因此它不限于Windows 10创建者版本或高分辨率显示器,只是当字体质量设置为ANTIALIASED时触发阈值更高。在我在Windows 7下的测试中,使用字体Arial,触发点是字体大小为"109“(快速)和字体大小为"110”(x10慢或性能差)。在使用Sebastian Z的答案禁用cleartype之后,Windows 10中也存在相同的触发阈值。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2017-05-15 14:19:16

Delphi用lfQuality := DEFAULT_QUALITY;创建字体。默认质量过去是反别名质量。但是,由于Windows 10的创建者更新了这一点,现在默认为cleartype。这是相当慢的。因此,解决办法是手动强制抗锯齿质量。

如果使用的是当前的Delphi版本,那么只需设置Font.Quality属性:

代码语言:javascript
复制
Procedure RenderText(oBitmap : TBitmap; X,Y : Integer; cRect : TRect; S : WideString; testFunction : Integer; TxtEffect : Integer; EffectColor : TColor; Clipping : Boolean);
// [...]
begin
  obitmap.Canvas.Font.Quality := fqClearType;

在较早的Delphi版本中,它稍微复杂一些:

代码语言:javascript
复制
var
  lf: TLogFont;
begin
  if GetObject(oBitmap.Canvas.Font.Handle, SizeOf(TLogFont), @lf) = sizeof(TLogFont) then
  begin
    lf.lfQuality := ANTIALIASED_QUALITY;
    oBitmap.Canvas.Font.Handle := CreateFontIndirect(lf);
  end;

在Windows10CreatorUpdate中,这是一个非常棘手的问题,因为ClearType文本并不总是合适的,并且可能导致意外的结果。

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/43895435

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档