NO_GUI
NO_GUI

Reputation: 464

How To Speed Up Printing Unicode?

I'm using windows.h "TextOutW" function to print text to a bitmap. Printing regular ascii is really fast, but the printing in the unicode range seems to cause a huge slowdown. Here's my code to print a unicode square & test the duration:

wchar_t b = 0x25A0;
LPCWSTR s = &b;
TextOutW(hMyDC, x, y, s, wcslen(s));

Are there any ways of speeding this up?

EDIT: I ran my loop with a timer to test speed:

    using std::chrono::high_resolution_clock;
    using std::chrono::duration_cast;
    using std::chrono::duration;
    using std::chrono::milliseconds;



auto t1 = high_resolution_clock::now();

for(int i = 0; i<1000; i++){
    TextOutW(hMyDC, 25, 25, s, 1);
}
  
auto t2 = high_resolution_clock::now();

  //  auto ms_int = duration_cast<milliseconds>(t2 - t1);
duration<double, std::milli> ms_double = t2 - t1;
    cout << ms_double.count() << "ms\n";

Printing 'H' a 1000 times took around 5ms and printing 0x25A0 1000 times took around 50ms

Upvotes: 0

Views: 236

Answers (3)

Daniel Sęk
Daniel Sęk

Reputation: 2769

You are hitting Uniscribe. ExtTextOutW and TextOutW check if text should be threaded through Uniscribe or passed directly to GDI.

To avoid Uniscribe overhead (NOT RECOMMENDED) you can pass ETO_IGNORELANGUAGE to ExtTextOutW, but you will miss some more advanced scripts (CJK aka Chinese+Japan+Korean, right to left writing, characters changing shape depending on where they are placed etc.) or get no text at all.

For 0x25A0 character I get slowdown about 8×

For 0x6F22 slowdown increases to 17×

On my system, when ETO_IGNORELANGUAGE is specified there is no slowdown. 0x25A0 displays correctly, 0x6F22 is replaced by default box.

Upvotes: 1

Vlad Feinstein
Vlad Feinstein

Reputation: 11321

This is not an answer. I just want to post the code to confirm the timing from this question.

I am getting 7-8 ms for the commented out characters, and ~50 ms for that 0x25A0.

I use Times New Roman because this page claims that it has that UNICODE symbol.

#include <iostream>
#include <chrono>
#include <windows.h>

int main()
{
    wchar_t b = 0x25A0;
    //wchar_t b = 0x0416;
    //wchar_t b = L'H';

    LPCWSTR s = &b;
    HDC hDC = ::GetWindowDC(::GetDesktopWindow());
    HFONT hFont = CreateFontW(36, 20, 0, 0, FW_DONTCARE, FALSE, TRUE, FALSE, DEFAULT_CHARSET, OUT_OUTLINE_PRECIS,
        CLIP_DEFAULT_PRECIS, CLEARTYPE_QUALITY, VARIABLE_PITCH, L"Times New Roman");
    HGDIOBJ hOld = ::SelectObject(hDC, hFont);
    auto t1 = std::chrono::steady_clock::now();
    for (int i = 0; i < 1000; i++) {
        TextOutW(hDC, 25, 25, s, 1);
    }
    auto t2 = std::chrono::steady_clock::now();

    std::cout << std::chrono::duration_cast<std::chrono::milliseconds>(t2 - t1).count() << " msec" << std::endl;
    return 0;
}

Upvotes: 1

Mark Ransom
Mark Ransom

Reputation: 308452

The problem is that you're pointing to a single character, not a string. The wcslen is exhibiting undefined behavior and probably returning a very large number. Replace it with 1 and things should speed up greatly.

Upvotes: 6

Related Questions