2017-05-10 38 views
8

Z jakiegoś dziwnego powodu wywołanie funkcji ExtTextOutW w WinAPI w celu narysowania przyciętego tekstu w bitmapie o wysokiej rozdzielczości (2560x1440/3840x2160) skutkuje uzyskaniem wydajności ~ x50 po aktualizacji systemu Windows 10 z aktualizacją edycji Creators. Z dzienników testowania i debugowania mojego użytkownika wynika, że ​​niewielka różnica w bitmapach lub rozmiar czcionki może spowodować wzrost wydajności.Zmniejszenie wydajności ExtTextOutW x50 na ekranach QHD/4K po aktualizacji edycji Windows Creators

Oto dziennik debugowania pokazujący spadek wydajności:

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 

Jak widać z dziennika, pojedyncze wywołanie ExtTextgOutW trwa ~ 9.5ms podczas gdy ta sama rozmowa wziął również pod 1ms przed twórcami aktualizacja.

Oto rzeczywisty kod, który można porównać do wyjścia debugowania powyżej:

{$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} 

Kod ten ma bardzo prosty efekt drop-cień pełniąc ten sam tekst dwukrotnie nieznacznej różnicy w Y- Przesunięcie i kolor.

Oto pełna dyskusja z moich użytkowników forum, na którym staramy się debugować problem na szerokiej gamie sprzętu (dodatkowe dzienników debugowania są zawarte w poście): http://forum.inmatrix.com/index.php?showtopic=14995&page=2

Przetestowaliśmy z DPI ustawione na 100 %, aby upewnić się, że wyzwalacz nie jest powiązany ze zmianami DPI wprowadzonymi w edycji Creators.

Czy ktoś wie, co to powoduje? i czy istnieje obejście?

***** Aktualizacja 1 *****

Przynajmniej w początkowym testowaniu „DrawTextExW” również wydaje się mieć wpływ na utratę wydajności. Czcionka używana podczas testowania to Arial, a problemy z wydajnością wydają się być związane z rozmiarem czcionki, ponieważ użytkownik zgłosił, że dodanie do ekranu mniejszych linii (więcej tekstu jest renderowane w niższej rozdzielczości) znacznie poprawia wydajność.

***** Aktualizacja 2 *****

napisałem małe narzędzie do profilu tego problemu, które można znaleźć w repozytorium GitHub: https://github.com/bLightZP/WindowsTextRenderingProfiler

Wydaje się, że kwestia zależy rozmiar czcionki, na przykład, na ekranie 2560x1440, renderowanie linii tekstu czcionki "Arial" o rozmiarze "35" 21 ms w celu renderowania w rozmiarze "34" zajęło 2 ms.

Jest to renderowane do HDC mapy TBit Delphi w formacie 32-bitowym, a wyłączenie przycinania ma jedynie niewielki wpływ na wydajność.

***** Aktualizacja 3 *****

odpowiedź

Sebastiana Z. poniżej powoduje przywrócenie wstępnie twórcom poziom wydania wydajności i I zostały zaktualizowane przykładowy kod na GitHub, aby odzwierciedlić jego odpowiedź, ale mam ponieważ udało się odtworzyć problem w systemie Windows 7 64bit i na ekranie 1920x1080, więc nie jest ograniczony do edycji programów dla twórców systemu Windows 10 lub wyświetlaczy o wysokiej rozdzielczości, po prostu próg wyzwalacza jest wyższy, gdy jakość czcionki jest ustawiona na ANTYZONOWANĄ. W moim teście pod Windows 7, używając czcionki Arial, punktem wyzwalania był rozmiar czcionki "109" (szybki) a rozmiar czcionki "110" (x 10 wolniej lub gorzej). Ten sam próg wyzwalania istnieje w systemie Windows 10 po użyciu odpowiedzi Sebastiana Z w celu wyłączenia funkcji cleartype.

+4

Czy spadek wydajności po usunięciu flagi ETO_CLIPPED jest taki sam? Jaką głębią koloru jest bitmapa (np. 24bpp lub 32bpp)? Czy to DIB czy DDB? Najlepiej, jeśli dodasz [mcve], aby użytkownicy SO mogli próbować odtworzyć. – zett42

+0

Zaktualizowałem oryginalny post z linkiem do projektu GitHub, który zawiera kod źródłowy i plik wykonywalny, którego można użyć do przetestowania tego. Aktualizacja zawiera inne szczegóły. – bLight

Odpowiedz

4

Delphi tworzy czcionkę przy pomocy lfQuality := DEFAULT_QUALITY;. Jakość domyślna miała jakość antyaliasingową. Ale ponieważ Windows 10 Creators aktualizuje to teraz domyślnie jest cleartype. A to jest dość powolne. Rozwiązaniem jest ręczne wymuszanie jakości antyaliasingu.

Jeśli używasz aktualnej wersji Delphi następnie można po prostu ustawić właściwość Font.Quality:

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; 

W starszych wersjach Delphi jest nieco bardziej skomplikowana:

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; 

ten to całkiem sporo w aktualizacji Windows Creators Update, ponieważ tekst ClearType nie zawsze jest odpowiedni i może skutkować nieoczekiwanymi rezultatami.

+0

Twoja odpowiedź działa i przywraca poziomy wydajności pre-twórców, ale przy głębszych testach wydaje się, że problem nadal istnieje już w systemie Windows 7, ale z wyższym progiem poziomu, patrz aktualizacja 3 (około 5 minut) – bLight