pcoder 4 Posted December 2, 2023 Sometimes my draw in OnPaint (WM_Paint) is very slow (kind of UI freezing). Now I would prefer to exit the paint handler earlier (based on time measurement (getTickCount)) and continue the draw in subsequent OnPaint events (like progressive drawing). Is that possible under Windows? And how can I trigger the paint events? 1 Share this post Link to post
Remy Lebeau 1394 Posted December 2, 2023 (edited) 6 hours ago, pcoder said: Sometimes my draw in OnPaint (WM_Paint) is very slow (kind of UI freezing). Then you are likely doing too much work in your drawing code. Or you are doing other things besides just drawing. Painting should be a quick task. Draw only what can be seen for the current state of your existing data, nothing more. Do not manage your data/UI in any way other than drawing. If you need to manipulate your data/UI, that has to be done outside of a paint cycle. 6 hours ago, pcoder said: Now I would prefer to exit the paint handler earlier (based on time measurement (getTickCount)) and continue the draw in subsequent OnPaint events (like progressive drawing). That is not how UI painting works. You have to draw whatever your current state represents. After the painting is finished, if a state change occurs, then you can trigger a repaint to draw the updated state. 6 hours ago, pcoder said: Is that possible under Windows? No. Every paint cycle is a complete redraw from scratch. For each window/control that is being painted, you have to draw it entirely in a single cycle. And then again in the next cycle. And so on. 6 hours ago, pcoder said: And how can I trigger the paint events? You can Invalidate() an individual form/control to trigger a new paint cycle for it, but that requires you to redraw it entirely from scratch when that next cycle begins, Edited December 2, 2023 by Remy Lebeau 1 Share this post Link to post
Uwe Raabe 2057 Posted December 2, 2023 If the drawing code is too time consuming for being called in OnPaint, you might consider drawing to a bitmap when something changed and draw that bitmap in OnPaint. 4 Share this post Link to post
FPiette 383 Posted December 3, 2023 15 hours ago, pcoder said: Sometimes my draw in OnPaint (WM_Paint) is very slow (kind of UI freezing). Maybe you are doing computation in the OnPaint event. Decouple computation from presentation (the drawing). For the drawing itself, avoid drawing pixel by pixel on screen. Avoid having hundreds of components to draw. Avoid drawing invisible parts. Painting in a bitmap and then blasting the bitmap on screen could be faster than painting on screen directly. 2 Share this post Link to post
pcoder 4 Posted December 3, 2023 Thanks for all! I will use a bitmap and draw into it whenever I have a time slot. The main problem is a real slow color-font (text draw 100+ times slower than with other color-fonts). I will also try distribution over several WM_Paint (each displays whole (but possibly unfinished) bitmap)), will see... (should look better than freeze). As Remy said, the framework is not prepared for this, so I will extend the wmPaint method to trigger the next paint. Initial tests have shown that this works. procedure TmyControl.WMPaint(var Message: TWMPaint); begin wantMorePaintTime := false; inherited; if wantMorePaintTime then postMessage( handle, iwm_wantPaintTime, 0, 0); // handler calls self.invalidate; end; Share this post Link to post
Kas Ob. 121 Posted December 3, 2023 35 minutes ago, pcoder said: The main problem is a real slow color-font (text draw 100+ times slower than with other color-fonts). Of course they are dead slow. I would suggest to build your own class that handle drawing a a single text string on its own small BMP (sized according to the text and the font), so there texts strings will have their own BMP that will invalidate only when you change the text, and simple draw procedure needing canvas and coordinates ( and may be a rect for clipping if needed), this what i do and this will make things faster enough for drawing on your own BMP or directly on the needed canvas. Share this post Link to post
pcoder 4 Posted December 3, 2023 (edited) Each textline needs up to 2 seconds :), varies on whether DirectWrite has found a way to cache something. I also have found that DirectWrite textdraw to bitmap DC is slower than DirectWrite textdraw to window DC. But I'm still happy with the progressive display now. And users have the option to select a different font:) The challenge (I should have mentioned it earlier) was, the user clicks a button to generate a different image on display. Thus a waiting time between button click and resulting display is impossible to avoid, regardless of internal concept. Edited December 3, 2023 by pcoder Share this post Link to post
Lars Fosdal 1792 Posted December 3, 2023 Something that is often overlooked is to limit the redraw frequency. If you redraw the display on every update and there are many updates per second, you may save a lot of time on triggering the invalidate at a capped rate, i.e. not do a full redraw every time, but update once every fixed time interval. Unless you are doing video processing - a redraw at maximum twice per second should be more than sufficient? 2 Share this post Link to post
pcoder 4 Posted December 3, 2023 (edited) Yes, in most cases more than sufficient. Edited December 3, 2023 by pcoder Share this post Link to post
Pat Foley 51 Posted December 3, 2023 5 hours ago, Lars Fosdal said: Something that is often overlooked is to limit the redraw frequency. If you redraw the display on every update and there are many updates per second, you may save a lot of time on triggering the invalidate at a capped rate, i.e. not do a full redraw every time, but update once every fixed time interval. Unless you are doing video processing - a redraw at maximum twice per second should be more than sufficient? But overclocking is fun! Using paint; override; with say TShape a tGraphicalControl allows using inherited to draw existing shape and add text as needed. Not using inherited means drawing your own polygon. The sample simply draws over the TShape control Ok But the focus rect yielded some relics. In the past it was necessary to exit a timer event when busy or in debug mode. Even with example switches the following stacks up clicks events. I put a call to Button8click in the formPaint and it ran but slowly. Otherwise just invalidate the controls as needed. var Button8clickIsBusy: Integer = 0; var OneShot: Boolean = False; procedure TForm1.Button8Click(Sender: TObject); const Red = clRed; Green = clGreen; Colors: Array of Tcolor = [clGreen,clRed,clBlue,clYellow]; var sw: TStopwatch; sX: string; function RandomFontColor: Tcolor; begin var Clr := High(Colors); var R := Random(Clr); Result := Colors[R]; end; begin sw.Reset; sw.Start; If Oneshot then Exit; If Button8clickIsBusy > 0 then begin Canvas.TextOut(10,10,'Drawing on Canvas'); Caption := 'Busy ' + Button8clickIsBusy.ToString; Exit; end; //Canvas.Unlock; // may need Inc(Button8clickIsBusy); OneShot := True; const L = Shape1.Left + 5; const T = Shape1.Top + 5; var SP: Integer := 0; var X := -50; //Brush.Color := clmoneygreen; //Canvas.FillRect(BoundsRect); //hosed by style and not max windowstate Repeat sX := X.ToString; Canvas.Font.Color := RandomFontColor; Canvas.Font.Size := X; Canvas.TextOut(20, 20, sX); canvas.DrawFocusRect(Rect(22,22,X+X-3,(X-3)*2)); //on shape Canvas.Font.Color := RandomFontColor; Canvas.Font.Size := -X; Canvas.TextOut(L, T, sX); Sleep(20); Canvas.Font.Color := clWindowFrame; canvas.DrawFocusRect(Rect(22,22,X+X-3,(X-3)*2)); Inc(X); Until x > 50; Button8clickIsBusy := 0; sw.Stop; Canvas.TextOut( 10,100,'Done et='+ sw.ElapsedMilliseconds.ToString); Caption := 'Busy ' + Button8clickIsBusy.ToString; Oneshot := False; end; Share this post Link to post
Anders Melander 1782 Posted December 3, 2023 10 hours ago, Kas Ob. said: Of course they are dead slow. SVG color fonts are probably slow. All the other color font types (COLR, SBIX, CBDT) should perform more or less on par with regular OpenType fonts. Share this post Link to post
pcoder 4 Posted December 3, 2023 Most common fonts are acceptable, but even "Noto Color Emoji" (2.038) can be very slow on certain systems. The file description displays COLRv1, but I don't know if DirectWrite actually uses this format. Share this post Link to post
Anders Melander 1782 Posted December 4, 2023 3 hours ago, pcoder said: Most common fonts are acceptable, but even "Noto Color Emoji" (2.038) can be very slow on certain systems. Probably because of its size. Most Noto fonts are huuuge. Noto Color Emoji contains both COLR and SVG data. The COLR data is ~1Mb while the SVG data is ~18Mb... 3 hours ago, pcoder said: The file description displays COLRv1, but I don't know if DirectWrite actually uses this format. I'm not sure what you are saying here. Microsoft is the primary author of the COLR format and DirectWrite supports all the common color glyph formats: https://learn.microsoft.com/en-us/windows/win32/directwrite/color-fonts However, the client has to specify what format to use during Shaping and if the client asks for SVG glyphs then that is what it will use. https://learn.microsoft.com/en-us/windows/win32/api/dcommon/ne-dcommon-dwrite_glyph_image_formats You can try subsetting the font to exclude the SVG data and see if that makes a difference (apart from the 18 Mb data saved 🙂) 1 Share this post Link to post
pcoder 4 Posted December 4, 2023 COLRv1 was just an info shown in the file properties dialog. The glyph rendering looks vector based and has color gradients, so SVG or COLRv1. Format-selection is for lower-level handling, but I use only RenderTarget.drawTextLayout() with D2D1_DRAW_TEXT_OPTIONS_ENABLE_COLOR_FONT. It would be useful here (also for end-users) if DirectWrite would offer a parameter to specify a preferred format. If possible I try to avoid lower-level handling, even more code according to the preview Share this post Link to post
Anders Melander 1782 Posted December 4, 2023 1 hour ago, pcoder said: It would be useful here (also for end-users) if DirectWrite would offer a parameter to specify a preferred format. Yes, you probably need to use a custom renderer to get control over the formats used. https://github.com/microsoft/Windows-universal-samples/blob/main/Samples/DWriteColorGlyph/cpp/CustomTextRenderer.cpp Share this post Link to post