VincentWei / MiniGUI

A modern and mature cross-platform window system for embedded systems and smart IoT devices.
http://www.minigui.com
GNU General Public License v3.0
694 stars 157 forks source link

MiniGUI3.2.3-double buffer running on ucos-ii multi-thread mode #73

Closed KevinShuuichi closed 3 years ago

KevinShuuichi commented 3 years ago

Hi, Dear VincentWei : I'm trying to use MiniGUI3.2.3 Dbuff to optimize the issue of flickers. Limited by the basic frequency of the CPU(up to 200M), everytime I tried to show a MainWindow (such as a soft-keyboard, which contains dozens of button controls), it took times. I followed the steps introduced by MINIGUI-PROG-GUIDE-V3.0, here is my code

static HDC exposureWndSecDC;
void CreateSettingsWindow(void)
{
    MAINWINCREATE CreateInfo;
    int leftX;
    int wndWidth;
    int wndInterval;
    MSG msg;
    RECT rect;
    memset(&CreateInfo, 0, sizeof(MAINWINCREATE));
    leftX = 40*SCREEN_RATIO_X;
    wndWidth =  400*SCREEN_RATIO_X;
    wndInterval = 15*SCREEN_RATIO_Y;

    CreateInfo.dwStyle = WS_NONE;
    CreateInfo.dwExStyle = WS_EX_NOCLOSEBOX | WS_EX_TROUNDCNS | WS_EX_BROUNDCNS | WS_EX_AUTOSECONDARYDC;
    CreateInfo.spCaption = "";
    CreateInfo.hCursor = GetSystemCursor(0);
    CreateInfo.iBkColor = SETTING_WINDOW_BKGCOLOR;
    CreateInfo.hHosting = mainWindow;
    CreateInfo.MainWindowProc = exposureWindowProc;
    CreateInfo.lx = leftX;
    CreateInfo.ty = 240*SCREEN_RATIO_Y;
    CreateInfo.rx = CreateInfo.lx+wndWidth;
    CreateInfo.by = CreateInfo.ty+160*SCREEN_RATIO_Y;
    s_settingsInfo.exposureWnd = CreateMainWindow(&CreateInfo);

    exposureWndSecDC = GetSecondaryDC(s_settingsInfo.exposureWnd);
    SetSecondaryDC(s_settingsInfo.exposureWnd, exposureWndSecDC, ON_UPDSECDC_DONOTHING);
    ShowWindow(s_settingsInfo.exposureWnd, SW_SHOWNORMAL);
}

static int exposureWindowProc(HWND hWnd, int message, WPARAM wParam, LPARAM lParam)
{
        HWND hCtrl;

        switch (message) {
        case MSG_CREATE: {
            hCtrl = CreateWindow(CTRL_STATIC,  "S",  WS_VISIBLE  |  WS_CHILD,  IDC_STATIC, 
                142*SCREEN_RATIO_X,  30*SCREEN_RATIO_Y,  20*SCREEN_RATIO_X,  20*SCREEN_RATIO_Y,  hWnd,  0);
            SetWindowBkColor(hCtrl,  SETTING_WINDOW_BKGCOLOR);

            hCtrl = CreateWindow(CTRL_STATIC,  "100MS",  WS_VISIBLE  |  WS_CHILD,  IDC_STATIC, 
                220*SCREEN_RATIO_X,  30*SCREEN_RATIO_Y,  50*SCREEN_RATIO_X,  20*SCREEN_RATIO_Y,  hWnd,  0);
            SetWindowBkColor(hCtrl,  SETTING_WINDOW_BKGCOLOR);

            hCtrl = CreateWindow(CTRL_STATIC,  "MS",  WS_VISIBLE  |  WS_CHILD,  IDC_STATIC, 
                327*SCREEN_RATIO_X,  30*SCREEN_RATIO_Y,  30*SCREEN_RATIO_X,  20*SCREEN_RATIO_Y,  hWnd,  0);
            SetWindowBkColor(hCtrl,  SETTING_WINDOW_BKGCOLOR);

            hCtrl = CreateWindow(CTRL_STATIC,  "Auto Exposure",  WS_VISIBLE  |  WS_CHILD,  IDC_STATIC, 
                10*SCREEN_RATIO_X,  55*SCREEN_RATIO_Y,  80*SCREEN_RATIO_X,  20*SCREEN_RATIO_Y,  hWnd,  0);
            SetWindowBkColor(hCtrl,  SETTING_WINDOW_BKGCOLOR);

            hCtrl = CreateWindow(CTRL_STATIC,  "Gain",  WS_VISIBLE  |  WS_CHILD,  IDC_STATIC, 
                10*SCREEN_RATIO_X,  90*SCREEN_RATIO_Y,  80*SCREEN_RATIO_X,  20*SCREEN_RATIO_Y,  hWnd,  0);
            SetWindowBkColor(hCtrl, SETTING_WINDOW_BKGCOLOR);

            hCtrl = CreateWindow(CTRL_STATIC,  "K",  WS_VISIBLE  |  WS_CHILD,  IDC_STATIC, 
                100*SCREEN_RATIO_X,  90*SCREEN_RATIO_Y,  20*SCREEN_RATIO_X,  20*SCREEN_RATIO_Y,  hWnd,  0);
            SetWindowBkColor(hCtrl, SETTING_WINDOW_BKGCOLOR);
                        break;
                }
               case MSG_COMMAND: {
                   ......
               }
}

When the code runs to BeginPaint of the Static control (almost the last one whose caption is "K"), I found the InvRgn pointer is pointing to somewhere wild. And the system went down. Is there any problems in my code ? I tracked the bug for days, looking forward to your reply, thanks.

VincentWei commented 3 years ago

I can't see what's wrong with your code.

You can check whether the system memory is sufficient.

KevinShuuichi commented 3 years ago

Thanks for reply. I checked my stack and malloc heap, I don't think there is any problem with it. I can use malloc anywhere correctly. I resized the main_stack to 32K ( 16K by default) at the file: minigui_startup.c, nothing changed. I called the CreateSettingsWindow at MiniGUIMain before it fall into the loop, something like this:

int MiniGUIMain(int argc, const char *argv[])
{
        ...
    SetDefaultWindowElementRenderer("skin");
    CreateMeasureSysFont();

    if (mainWindow = CreateMeasureMainWindow() < 0)
        exit(-1);

    CreateSettingsWindow();
    ......
    while (GetMessage(&Msg, mainWindow)) {
        printf("Msg = %#x.\n", Msg.message);
        DispatchMessage(&Msg);
    }
    return 0;

FAILED:
    DestroyMainWindow(mainWindow);
    MainWindowThreadCleanup(mainWindow);

    return -1;
}

I created mainWindow first, and set the settingWindow's hosting window as mainWindow (CreateInfo.hHosting = mainWindow), is it correct ? Or if I have other way to optimize the flickers ? maybe higher version or using privateDC ? By the way , I don't know what private DC actually does.

VincentWei commented 3 years ago

Some suggestions:

  1. The secondary DC will use an extra memory block as the surface of the main window. I guess that the memory allocation failed on your system.
  2. To eliminate the flickers, you can:
    • Try to use the shadow engine.
    • Write a your own GAL engine to use a shadow screen to eliminate the flickers; see fbcon engine in MiniGUI 5.0.
KevinShuuichi commented 3 years ago

I tried shadow engine with real engine = commlcd, it worked just fine. But it 's too slow to show a big window. (about 1.5s to show a window with size of 540*800) If I want to show a big window immediately, the best way I know is dbuff first and then using bitblt to show. I changed the way of creating the secondDC, it worked, and the system won't down again. First, I changed CreateInfo.dwExStyle = WS_EX_NOCLOSEBOX | WS_EX_TROUNDCNS | WS_EX_BROUNDCNS | WS_EX_AUTOSECONDARYDC; to: CreateInfo.dwExStyle = WS_EX_NOCLOSEBOX | WS_EX_TROUNDCNS | WS_EX_BROUNDCNS; then create the secondDC by myself,

exposureWndSecDC = CreateSecondaryDC(s_settingsInfo.exposureWnd);
SetSecondaryDC(s_settingsInfo.exposureWnd, exposureWndSecDC, ON_UPDSECDC_DONOTHING);
ShowWindow(s_settingsInfo.exposureWnd, SW_SHOWNORMAL);

when I want to show the window, I use bitblt like this:

GetWindowRect(s_settingsInfo.exposureWnd, &rect);
BitBlt(exposureWndSecDC, 0, 0, RECTW(rect), RECTH(rect), HDC_SCREEN, 40*SCREEN_RATIO_X, 240*SCREEN_RATIO_Y, 0);

But sometimes the result area is totally black or something like this : pict

any suggestions ?

VincentWei commented 3 years ago

Try to call the following functions after handle MSG_PAINT:

case MSG_PAINT:
    BeginPaint();
    ...
    EndPaint();

    GetWindowRect(s_settingsInfo.exposureWnd, &rect);
    BitBlt(exposureWndSecDC, 0, 0, RECTW(rect), RECTH(rect), HDC_SCREEN, 40*SCREEN_RATIO_X, 240*SCREEN_RATIO_Y, 0);
    return 0;
...
KevinShuuichi commented 3 years ago

It didn't work. Finally, I used the shadow engine, and I changed the shadow_refresh function to DMA instead of memcpy. now, the window shows soon enough. But I still don't understand why dbuff doesn't work. It takes time to track the source code. I'm just new to MiniGUI. Anyway, Thanks for your advice.

VincentWei commented 3 years ago

That's great!