Draw loading cover image during rendering

Joined
Jan 22, 2020
Messages
10
Programming Experience
10+
Hi,
I have simple single borderless fullscreen Form (now with enabled double buffering) application because of Forms applet that I want. The problem is simple, a mentioned applet reqiure full lazy redrawing, so it causes screen flickering. That I make fullscreen cover image for hide loading state of that applet. Funny is, that my cover image flickering too! :) Problem is combination Forms nad hard image size. Can it be easy to the fast draw cover image for avoiding background flickering? (Some screen drawing probably with some Windows lib or Nuget package.) I want result with no external requirements, just small lib if must it be. Also remember, that I want transitions in/out this cover image for really smooth loading...
 

Skydiver

Staff member
Joined
Apr 6, 2019
Messages
4,029
Location
Chesapeake, VA
Programming Experience
10+
A simple splash screen should not be flickering. Show us your code.
 

NoUserHere

Well-known member
Joined
Sep 5, 2018
Messages
2,138
Programming Experience
10+
mentioned applet reqiure full lazy redrawing
What applet? From where did you get it?
Problem is combination Forms nad hard image size
You seem to know the issue, so why can't you propose a fix for this "hard image size"?
If you are drawing over another image, (which it appears to be as you've described), do you not think its normal for flicker to occur?
Double buffering isn't going to help you a great deal if you have a foreground item being drawn over one behind the one being drawn.

Given the fact that windows are forcing Windows 7 users to upgrade to windows 10, it sounds like a pointless question, but what OS are you targeting with your application?
I ask because if you are targeting an older OS, you could use WS_EX_COMPOSITED; might i add requires AERO to be disabled, and this would drastically help with reduced flickering. Using this API does require disabling DWM, however, the most logical thing to do would be to design your application in WPF to avoid all of these necessaries, especially if your app is in anyway graphic processing dependent.
 
Joined
Jan 22, 2020
Messages
10
Programming Experience
10+
So again. I have FULLSCREEN (borderless maximized) Form (for now with enabled DoubleBuffering) and docked (filled) Control. I want cover Form Handle rendering in background. It is all. Problem of Fomrs rendeing is well known - Controls in Form cannot render if not visible - at background. I try two solutions - draw on Control Handle and draw on Screen handle. Drawing on Control Handle is bad solution, because applet rendering in fast FPS and it causes flickering. But drawing on Screen (zero PTR) really working and cover Control rendering. Only problem of Screen rendering is slow speed of drawing. So I only want draw cover image over Form/Control in lower code, that is possible I know, I used a lot rendering frameworks etc. - only I am looking for some simple solution. All I need is let my Form render in background smoothly and draw fullscreen cover in front... (And bring Form in front without refreshing loaded Control, just paint rendered.) I am targeting Windows 10 without special libs or etc. - basic system as it is possible. There must be easy solution, because really I know, that it is possible. I can prepare for it, I can run some background app, that have DirectX access or etc. - really just I want paint cover image over form and smoothly bring form in front...

For example what I tried and it works good:
I can draw cover at ZeroPtr Handle and grab Control snapshot, that I also draw in Desktop Handle, but rendering was so extremly slow - I know, that it is bad idea to draw on Desktop Handle. But it awoid flickering.
I draw in timer cover at Control Handle, that make fast rendering and really Cower Control rendering, but it make one fast flicker at end. So I really looking for some smoothly transition...
 
Last edited:

Skydiver

Staff member
Joined
Apr 6, 2019
Messages
4,029
Location
Chesapeake, VA
Programming Experience
10+
Please show us your code. I suspect that something you are doing is causing your screen flicker.

Consider the code that I presented in this other thread. It does a full screen Matrix screen saver effect without any flickering. (Granted, I've only tested on machines with regular 80-96 DPI monitors at 2560x1080, 1920x1080, and smaller. I don't own any 4K monitors.) All I've done there is just use the built in double buffering and do normal painting in the paint event. I had not even pull out all the other tricks for making drawing faster like skipping the background painting, skipping frames only that are faster that the screen refresh rate, only updating the parts of the screen that actually changed, or implemented my own double buffering by drawing to an offscreen graphics surface.
 
Joined
Jan 22, 2020
Messages
10
Programming Experience
10+
I have no code for that applet. I have LIB of applet, that have CUSTOM rendering system outside Forms and it is hosted in Forms application. I know exactly why it flickering. I describe it in my first post. Only problem is, that this applet require dispose of previous screen, so it draw blank screen and become render. And this I mean as flickering. Empty page before applet become rendering. And also I must watch to item positionig during rendering. So I JUST want cover this rendering under image that I have. Really nothing special. I am requested for draw other sceen, so I show cover image and send new screen into applet. Applet redraw screen with blank page and become rendering. After redered I am bring applet Control into front. That is all I want. Just I want some low code fullscreen rendering, that can easy cower Forms rendering. This is my question. Really I have just Form {Maimized, Borderless}, inside this Form docked Control and I want to cover it. Nothing more. I have only this two simple items.

Problem is also, that this applet have custom rendering, so it not cause Forms Paint event. I have no control about applet rendering. And I do not need it. I just want let this applet render and cover it under my image. And I want hide image when job done. Just without blank screen before or after. So in lower code, not stupid Forms... (Simulated fade in/out.)

Just I saw info about applet and it shoud use SKIA endine for rendering.
 
Last edited:

Skydiver

Staff member
Joined
Apr 6, 2019
Messages
4,029
Location
Chesapeake, VA
Programming Experience
10+
Is it an applet, or a WinForms control or an ActiveX control that you are hosting in your fullscreen borderless Form?

Can you move your Form off screen (e.g. Form.Location = Screen.PrimaryScreen.Bounds.Location - Screen.PrimaryScreen.Bounds.Size;, and then when it is done drawing move it back on screen Form.Location = new Point(0,0);) ?
 
Joined
Jan 22, 2020
Messages
10
Programming Experience
10+
But what will be on current screen? As I mentioned, it should be SKIA applet - so something as WebGL. It not render outside of Form Handle, but also it not cause normal Forms events... As I wrote, when I draw image on zero Handle, it cover form under it and it working for me. Only this rendering was so slow, so I just want render via some DirectX library, or something on screen buffer. When I move or resize main Form, it still make flicker - I mean, some color rectange drawn before action done... So I am looking for really cover rendering, that not require Form Handle...
 

NoUserHere

Well-known member
Joined
Sep 5, 2018
Messages
2,138
Programming Experience
10+
So again. I have FULLSCREEN (borderless maximized) Form (for now with enabled DoubleBuffering)
There is an awful echo on this thread.
You seem to know the issue, so why can't you propose a fix for this "hard image size"?
If you are drawing over another image, (which it appears to be as you've described), do you not think its normal for flicker to occur?
Double buffering isn't going to help you a great deal if you have a foreground item being drawn over one behind the one being drawn.
I would have thought with your 10 years experience, that this would be relatively simple for you to understand what I am saying instead of trying to dismiss my post as some useless dribble. Maybe if you took some time to read the replies you are receiving, you would find that your method is not achievable. On post 4, you come across rather rude as though the code monkey's who replied to you didn't understand your question and it appears to have gone over our heads, which it hasn't.

You're talking about drawing on handles. LOL You don't draw on handles, and you seriously don't seem to understand what a handle is or how one is used. This does partially explain that though as a off topic link to your original question. What is a "handle"?

Also, if you have 10 years experience. You should know what you are using. Is it an applet, and active X control, a usercontrol, a custom plugin?

Just reading your replies, I can tell you don't have ten years experience, and you certainly don't have a good understanding of what you're doing or if it is even possible. I will spare you the heartache and tell you this isn't going to work, especially in Winforms. Also, if you are using some kind of Applet, its going to effect everything in-front of it when it redraws regardless what buffering you have applied. Winforms wasn't built for this type of processing. Good luck with it though.
 
Joined
Jan 22, 2020
Messages
10
Programming Experience
10+
I really not have 10 years experiences with Windows Forms. I am Linux programmer on BSD at begin. MVC ASP/PHP for last 5 years. I am using "IntPtr GetDC(IntPtr hwnd);" for drawing on Control. (Via Handle.) I used direct buffer drawing before 7 years about. So I know, that is really easy to redraw screen buffer, just I forgot solution. I am not Desktop Forms developer at all. But I am pretty sure about what I need and how to do it. Because I was Mono/Xamarin developer for 4 years and I spend some part in Forms rendering. I ony want do hide Form rendering via some lower rendering... I have got idea just hour ago, so after about 40 minutes I will try it. As I wrote, I am not well Desktop developer, but this really must have easy solution - to hide Control painting...
 

Skydiver

Staff member
Joined
Apr 6, 2019
Messages
4,029
Location
Chesapeake, VA
Programming Experience
10+
I am using "IntPtr GetDC(IntPtr hwnd);" for drawing on Control. (Via Handle.)
And there lies part of your performance problems. When you are using P/Invoke calls, parameters need to be marshalled from the managed side of the world into the unmanaged side, perform the actual call, and then marshal any responses from the unmanaged side back to the managed side. So Win32 GDI code that takes a few milliseconds with unmanaged code will go up into several hundreds of milliseconds. Make sure to minimize these managed/unmanaged transitions.

Why are you not simply painting on your own control that you are using to cover the other form with the "applet" hosted in it?
 
Joined
Jan 22, 2020
Messages
10
Programming Experience
10+
Where can I draw? It is all my question. I have cover image. But where to draw... When I try to draw in Control, its rendering win... (And flicker over.) So I need some new layer that can I bring in front... This is what I want. Just let Control fully rendered and cover it. It not cause normal Paint event, so I cannot use normal paiting... As I mentioned, I can prepare some background app for example. It is SKIA, WebGL like plugin as I wrote before. I can prepare second Form in background, but I really not know, how bring it in front without flickering... And no, my P/Invoke call is not slow at all. Because I am doing it BEFORE I trigger Control refresh. This is what I am try to tell you from begin. It is me, who cause Control rendering, so I can prepare for it. I take snapshot before, I draw snapshot before and I let Control refresh after. And I hide cover after Control rendered. I can manage every step of this. Just I not have access to lower rendering, that can fast redraw image over Form... You still try to tell me, that my rendering flickering, but not, it is really not the problem, because I not call Control redraw until I am ready to let it.. I can prepare for it, I can run other app in background, I can do everything. Just I not know what can smoothly cover Form and let Form bring in front without reloading Control again... And only one small thing cause flicker in this case. Only stupidity of applet rendering, that CLEAR sceen before render it. So it make few seconds background color on screen, before it become render. And it cause flicker... I just want cover it before I let Control refresh... And yes, all this time I am looking how to enable double-buffer for this applet in this applet forum, but I not have answer for it. So, I just want hide it, because I am sure, that is easy and fast solution...
 

Skydiver

Staff member
Joined
Apr 6, 2019
Messages
4,029
Location
Chesapeake, VA
Programming Experience
10+
Again, without seeing your code it is very hard to talk about what you are doing and how to make things better.

If your "applet" is using WebGL and it is using any kind of GPU acceleration, Direct Draw, or if it actually drawing an overlay over the window it is using (ala some nVidia and ATI/AMD video playback acceleration), then the WinForms double buffering is not going to do you any good because the double buffering is happening at the GDI level, while your "applet" is actually drawing to the screen and bypassing GDI.
 
Joined
Jan 22, 2020
Messages
10
Programming Experience
10+
I not have applet code. I really have only Form and Control. Everything else is written just for applet content. I really know, that double buffering of Windows API cannot be solution, this is why I everytime wrote it in round brackets. Yes, it have GPU acceleration. I wrote it really before 4 posts, that you ignore it...

"Just I saw info about applet and it shoud use SKIA endine for rendering."

I also can turn acceleration off, but I am unsure to do it just for this solution. (It must be turn off before app run and cannot be used anytime after.) How many times must I wrote, that I not want resolve it with Forms render, I not want resolve it with Forms double buffering! I know, that it cannot be solution. Whole time, from first post, I want use some DirectX lib in lower code, but you still ignore it and still thinging about Forms. But Form layer really cannot resolve it. That I know and this is why I am here. I want access lower into Screen buffer... I really not know how to wrote it better. I have Form , run Form with docked Control. Take snapshot from Control, draw image in Control DC, call refresh (applet screen reload) and let last paint of Control flicker over my image. From this time I am really thinking to turn off GPU acceleration, I am still unsure, if can I use it. But you really cannot blame me, I wrote you from first post, that I am looking for low layer rendering... I know situation, I know, that rendering of Forms is noob... Really I am talking about 2 Form controls and refreshing one of them. Nothing more. I really not expect that problem. Just I want to cover applet refresh before it is done...
 

Skydiver

Staff member
Joined
Apr 6, 2019
Messages
4,029
Location
Chesapeake, VA
Programming Experience
10+
Can you create a minimal WinForms application that demonstrates the problem? It'll have:
- some minimal version of your Form that is hosting the "applet"
- some minimal version of your Form hosting your "docked Control"
- some minimal version of your Control
- some minimal version of your code that takes the snapshot, draws the image in the Control DC, call refresh or he applet, and paints your control.
 

Skydiver

Staff member
Joined
Apr 6, 2019
Messages
4,029
Location
Chesapeake, VA
Programming Experience
10+

Skydiver

Staff member
Joined
Apr 6, 2019
Messages
4,029
Location
Chesapeake, VA
Programming Experience
10+
That I know and this is why I am here. I want access lower into Screen buffer...
"here" happens to be the WinForms forum. WinForms doesn't have that kind of lower level access. Note the word "forms" in "WinForms".

In your first post you said:
(Some screen drawing probably with some Windows lib or Nuget package.) I want result with no external requirements, just small lib if must it be.
If you don't want external requirements, then using DirectX or DirectDraw is going to be eliminated because those are external dependencies. Even though it maybe installed on Windows, you'll still have to jump outside of WinForms to get to them. As it is, your current P/Invoke call to GetDC() is also technically an external dependency/requirement since again, you are jumping outside of WinForms. Granted that WinForms is built on WinUser and WinGDI, consider what happens when you run your code on .NET Core 3.0 on Linux where you may not have a real Windows DC to play with.
 

Skydiver

Staff member
Joined
Apr 6, 2019
Messages
4,029
Location
Chesapeake, VA
Programming Experience
10+
Since you are so reticent to provide some code that tries to demonstrate the problem, here is some code that tries to reproduce it.

To emulate your form that hosts your SKIA based "applet", I have a fullscreen MainForm which has a SKGLControl. Inside the control, a bouncing ball and the current time is rendered at a target frame rate.

Unfortunately, I can't reproduce the flickering while drawing on SKIA control that is hardware accelerated. The closest I could get was for some horizontal tearing to happen on my old desktop computer with an 8 year ATI/AMD graphics card. (I couldn't get the same tearing to happen on my laptop that has a relatively modern dedicated ATI/AMD graphics chip.) I got the tearing to show by using higher values for PixelsPerSecond in the Ball class (line 142).

Anyway with the tearing appearing, I then show the covering DesktopForm on top of the MainForm by pressing the Escape key (see lines 91-101). All this form does is render an upside down screenshot of the desktop. I deliberately render the screen upside down because I was confusing myself as to when I had my real desktop vs. a static screenshot of it. If you don't want it upside down, comment out the transform lines. Any which way, I'm just using normal painting. I really don't understand why you would need to P/Invoke GetDC().

Anyway, I'm not seeing any flicker or tearing on this new form that is covering the hosting form. I can't reproduce your problem where you said that the covering form flickers as it covers the hosting form.

If you are not convinced that the hosting form is actually continuing to render, try uncommenting line 26 which sets the opacity of the cover form to 50%. You will be able to see the ball continuing to move around under the covering form.

Dismissing the covering form by clicking on it or pressing a key, the hosting form gets shown without any issues. I'm not seeing any blinking or flickering as the original form draws when the cover goes away.

SkiaWinForms:
using SkiaSharp;
using SkiaSharp.Views.Desktop;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Imaging;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace SkiaWinForms
{
    [DesignerCategory("Code")]
    class DesktopForm : Form
    {
        readonly Bitmap _bitmap;

        public DesktopForm(Bitmap bitmap)
        {
            _bitmap = bitmap;

            Bounds = Screen.PrimaryScreen.Bounds;
            FormBorderStyle = FormBorderStyle.None;
            DoubleBuffered = true;
            // Opacity = 0.50;

            Click += (o, e) => Close();
            KeyPress += (o, e) => Close();
            Paint += (o, e) =>
            {
                e.Graphics.TranslateTransform(_bitmap.Width, bitmap.Height);
                e.Graphics.ScaleTransform(-1, -1);
                e.Graphics.DrawImage(_bitmap, Point.Empty);
            };
        }
    }

    [DesignerCategory("Code")]
    class MainForm : Form
    {
        readonly Bitmap _screenshot;
        readonly Ball _ball;

        MainForm(Bitmap screenshot, Ball ball, int framesPerSecond)
        {
            _screenshot = screenshot;
            _ball = ball;

            Bounds = Screen.PrimaryScreen.Bounds;
            FormBorderStyle = FormBorderStyle.None;
            DoubleBuffered = true;

            var skcontrol = new SKGLControl() { Dock = DockStyle.Fill };
            skcontrol.PaintSurface += Skcontrol_PaintSurface;
            skcontrol.Click += (o, e) => Close();
            skcontrol.KeyPress += (o, e) => Close();

            var timer = new Timer() { Interval = (int)Math.Round(1000.0 / framesPerSecond) };
            timer.Tick += (o, e) => { _ball.Update(); skcontrol.Invalidate(); };
            timer.Start();

            Controls.Add(skcontrol);
        }

        private void Skcontrol_PaintSurface(object sender, SKPaintGLSurfaceEventArgs e)
        {
            var surface = e.Surface;
            var canvas = surface.Canvas;

            canvas.Clear(SKColors.White);

            canvas.DrawCircle(_ball.Position, _ball.Radius, new SKPaint()
            {
                IsAntialias = true,
                Color = SKColors.Green,
                Style = SKPaintStyle.Fill
            });

            canvas.DrawText($"{DateTime.Now}", 100, 100, new SKPaint()
            {
                TextSize = 64.0f,
                IsAntialias = true,
                Color = SKColors.Red,
                Style = SKPaintStyle.Fill
            });

            canvas.Flush();
        }

        protected override bool ProcessDialogKey(Keys keyData)
        {
            if (keyData.HasFlag(Keys.Escape))
            {
                using (var desktop = new DesktopForm(_screenshot))
                    desktop.ShowDialog();
                return true;
            }

            return base.ProcessDialogKey(keyData);
        }

        static Bitmap CreateScreenshot()
        {
            var rect = Screen.PrimaryScreen.Bounds;
            var bitmap = new Bitmap(rect.Width, rect.Height, PixelFormat.Format32bppArgb);
            using (var g = Graphics.FromImage(bitmap))
            {
                g.CopyFromScreen(rect.Location, Point.Empty, rect.Size);
            }
            return bitmap;
        }

        [STAThread]
        static void Main()
        {
            const int FramesPerSecond = 24;

            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new MainForm(CreateScreenshot(),
                            new Ball(Screen.PrimaryScreen.Bounds, FramesPerSecond),
                            FramesPerSecond));
        }
    }

    class Ball
    {
        readonly Rectangle _bounds;
        SKPoint _vector;
        SKPoint _position;

        public SKPoint Position => _position;
        public float Radius => 200.0f;

        public Ball(Rectangle bounds, int framesPerSecond)
        {
            _bounds = bounds;
            _position.X = _bounds.Width / 2;
            _position.Y = _bounds.Height / 2;

            const int PixelsPerSecond = 150;
            var pixelsPerFrame = (float) PixelsPerSecond / framesPerSecond;
            _vector = new SKPoint(pixelsPerFrame, pixelsPerFrame);
        }

        public void Update()
        {
            (_position.X, _vector.X) = CheckBounds(_position.X, _vector.X, _bounds.Left, _bounds.Right);
            (_position.Y, _vector.Y) = CheckBounds(_position.Y, _vector.Y, _bounds.Top, _bounds.Bottom);

            (float newValue, float newVector) CheckBounds(float value, float vector, float min, float max)
            {
                value += vector;
                if (value + Radius > max)
                {
                    value = max - Radius;
                    vector *= -1;
                }
                else if (value - Radius < min)
                {
                    value = min + Radius;
                    vector *= -1;
                }
                return (value, vector);
            }
        }
    }
}

Code also available at: azureskydiver/SKIAWinForms
 
Joined
Jan 22, 2020
Messages
10
Programming Experience
10+
It was so stupidly easy. I want to avoid double form visible for user comfort, but it was only the problem. I just leave idea of one Form active and it resolve it. Just I open second Form, that it let previous Form rendering and after I can just Hide my cover Form when main Form rendered. Both Form DoubleBuffered and it make smooth loading at all. It was my question from begin - how to draw image to let Form render in background. And answer is, that I need second app just for managing cover. Now I just try to bind both Forms together in case, that user somehow change Window size, so my cover Form must have same position and size as covering Form... (I make some test before display cover, to make it well.) Also I am interested in, how can I hide dual Form icons of my app - to not making mess in taskbar etc... But really thank you for try to help...
 

Skydiver

Staff member
Joined
Apr 6, 2019
Messages
4,029
Location
Chesapeake, VA
Programming Experience
10+
Also I am interested in, how can I hide dual Form icons of my app - to not making mess in taskbar etc...
If you don't want a form to show in the taskbar, just set ShowInTaskbar to false. But if your main form is full screen as you said in post #1, then it'll be hiding the taskbar anyway, so I don't see the point. (More on fullscreen below.)

And answer is, that I need second app just for managing cover.
You don't need a second app. See how I managed with just a single application in post #18. The trick is to keep the message pump running. In post #18, I did that by using ShowDialog() to create a dialog. A modeless dialog will also work. (For details on modeless dialogs, see Modeless Dialogs in WinForms .)

What you essentially need is effectively a splash screen while your main form prepares to run. To do that, you simply show the cover form as a modeless dialog that is on top of your current form, and then when you are ready, you close the cover form.

Now I just try to bind both Forms together in case, that user somehow change Window size, so my cover Form must have same position and size as covering Form...
Assuming you are using a single app, whenever your main form gets a resize event, tell your cover form to also resize. If you had to 2 apps, then you'd create a custom WM_USER+n message and post that

I'm not seeing how your main form would resize in normal situations, though. In your post #1 you said:
I have simple single borderless fullscreen Form
That means that there won't be any resize handles if it is borderless.

The only time you'd get resizing is if you are running on a tablet and the user changes orientation, or if you on a PC or laptop and the user replaces the monitor. The probability of that happening is really low considering that you said that the flickering happens only when the main form is first shown. How long is that flickering period? Less than 1 second? Less than 3 seconds?
 

Similar threads

Top Bottom