Jump to content

Pixel Functions and Speed


 Share

Recommended Posts

Is it possible that adding an "hDC" option to the pixel functions would help speed Pixel Functions up?

If a scripter calls GetDC() at the beginning of a script and holds that DC, then multiple calls by the AutoIt engine to GetDC() are not necessary... right? that should speed up the functionality of Pixel functions... maybe... on Vista?

Lar.

f_mrcleansmalm_77ce002.jpgAutoIt has helped make me wealthy

Link to comment
Share on other sites

Yes... re-writing all together is one way to go. I am just hoping that we implement something so that Pixel functions do not become obsolete with up and comping Vista and beyond. The prescribed method for getting screen info is still GetDC(null).

Perhaps a directive that sets a flag that the AutoIt engine knows that the script uses Pixel functions and should load GetDC(null) on initialization and use that hDC instead of making subsequent calls to GetDC.

any of this resonate?

Lar.

f_mrcleansmalm_77ce002.jpgAutoIt has helped make me wealthy

Link to comment
Share on other sites

The functions already take an HWND parameter. As far as I know calling GetDC() just looks up and returns a handle value found in a structure so I don't think you're going to get a noticeable performance increase by caching the DC instead of the HWND.

Link to comment
Share on other sites

The functions already take an HWND parameter. As far as I know calling GetDC() just looks up and returns a handle value found in a structure so I don't think you're going to get a noticeable performance increase by caching the DC instead of the HWND.

Yes... It's all theory for me now. I was reading about GetDC(null) and Vista and how messed up it is with Vista's window manager and new way of doing GDI. I know that in a script I can reuse the hDC called one time when my script starts... eliminating subsequent calls to getDC... so I was thinking maybe the same is possible in the engine.

I will try to test to get statistics for my theory... but usually a statement like this from me means... I am too lazy to find out... but, I will try.

Lar.

f_mrcleansmalm_77ce002.jpgAutoIt has helped make me wealthy

Link to comment
Share on other sites

  • Administrators

The functions already take an HWND parameter. As far as I know calling GetDC() just looks up and returns a handle value found in a structure so I don't think you're going to get a noticeable performance increase by caching the DC instead of the HWND.

GetDC(Null) is the performance killer when Aero is enabled. It literally takes forever. Something about it having to copy a screen somewhere because of the transparency.
Link to comment
Share on other sites

That makes no sense (I'm not saying you're wrong, just saying it doesn't make sense). The description of the function says exactly what I expect:

The GetDC function retrieves a handle to a display device context (DC) for the client area of a specified window or for the entire screen.
The function should be returning a handle. It shouldn't have to copy anything or do anything fancy, it should just return a handle to existing data. I can't imagine how Microsoft could cock that up so that a function for returning a handle can take so long in certain cases.
Link to comment
Share on other sites

This thread is relevant to my interests. At work we're having a performance problem with a piece of software that uses GDI and DirectX extensively. I've never realised or heard anything about GetDC being so much slower on Vista. We've been wanting to switch the box to XP, although drivers then become a problem. The software has been developed on XP, where it had no performance issues. We've been looking into other areas to determine the performance drop on Vista, but not into the actual GDI yet.

That makes no sense (I'm not saying you're wrong, just saying it doesn't make sense). The description of the function says exactly what I expect:

The GetDC function retrieves a handle to a display device context (DC) for the client area of a specified window or for the entire screen.
The function should be returning a handle. It shouldn't have to copy anything or do anything fancy, it should just return a handle to existing data. I can't imagine how Microsoft could cock that up so that a function for returning a handle can take so long in certain cases.
I believe a common DC can only be used by one thread at a time. It must be released by the previous thread using ReleaseDC, before your application can use it. Aero probably uses the same common DC. Edited by Manadar
Link to comment
Share on other sites

That makes no sense (I'm not saying you're wrong, just saying it doesn't make sense). The description of the function says exactly what I expect:

The GetDC function retrieves a handle to a display device context (DC) for the client area of a specified window or for the entire screen.
The function should be returning a handle. It shouldn't have to copy anything or do anything fancy, it should just return a handle to existing data. I can't imagine how Microsoft could cock that up so that a function for returning a handle can take so long in certain cases.
I read an article that says something about windows (in Vista) being rendered "off screen" and some other magical business that contributes to the GetDC(null) trouble.

Lar.

f_mrcleansmalm_77ce002.jpgAutoIt has helped make me wealthy

Link to comment
Share on other sites

Read this

Drawing To and Reading From the Screen -- Baaaad!

Lastly, since we're on the redirection topic, one particularly dangerous practice is writing to the screen, either through the use of GetDC(NULL) and writing to that, or attempting to do XOR rubber-band lines, etc. There are two big reasons that writing to the screen is bad:

1. It's expensive... writing to the screen itself isn't expensive, but it is almost always accompanied by reading from the screen because one typically does read-modify-write operations like XOR when writing to the screen. Reading from the video memory surface is very expensive, requires synchronization with the DWM, and stalls the entire GPU pipe, as well as the DWM application pipe.

2. It's unpredictable... if you somehow manage to get to the actual primary and write to it, there can be no predictability as to how long what you wrote to the primary will remain on screen. Since the UCE doesn't know about it, it may get cleared in the next frame refresh, or it may persist for a very long time, depending on what else needs to be updated on the screen. (We really don't allow direct writing to the primary anyhow, for that very reason... if you try to access the DirectDraw primary, for instance, the DWM will turn off until the accessing application exits)

from here...

http://blogs.msdn.com/greg_schechter/archi.../02/588934.aspx

Lar.

Edited by LarryDalooza

f_mrcleansmalm_77ce002.jpgAutoIt has helped make me wealthy

Link to comment
Share on other sites

Here's the source to a simple program to measure the time it takes to create a DC and the time it takes to read a pixel from a DC. Run this on Vista with Aero enabled and report the results.

// GetDCTest.cpp : Defines the entry point for the application.
//

#include <vector>
#include <sstream>
#include <algorithm>
#include <windows.h>
#include <tchar.h>

// Global Variables:
HINSTANCE hInst;                                // current instance
__int64 g_i64Create = 0, g_i64Read = 0;

// Forward declarations of functions included in this code module:
ATOM                MyRegisterClass(HINSTANCE hInstance);
BOOL                InitInstance(HINSTANCE, int);
LRESULT CALLBACK    WndProc(HWND, UINT, WPARAM, LPARAM);

class CTimer
{
public:
    CTimer()
    {
        QueryPerformanceCounter(&m_li);
    }
    __int64 Elapsed()
    {
        LARGE_INTEGER li;
        QueryPerformanceCounter(&li);
        return li.QuadPart - m_li.QuadPart;
    }
private:
    LARGE_INTEGER m_li;
};

class CReleaseDC
{
public:
    void operator()(HDC &hDC)
    {
        ReleaseDC(NULL, hDC);
    }
};

void GetDCTest()
{
    const unsigned int iCount = 1000;

    // First let's measure the time it takes to create a DC.
    {
        std::vector<HDC> vHDC;

        CTimer c;
        for (unsigned int i = 0; i < iCount; ++i)
            vHDC.push_back(GetDC(NULL));
        g_i64Create = c.Elapsed() / iCount;
        std::for_each(vHDC.begin(), vHDC.end(), CReleaseDC());
    }

    // Now let's measure how long it takes to read from a DC.
    {
        HDC hDC = GetDC(NULL);

        CTimer c;
        for (unsigned int i = 0; i < iCount; ++i)
            COLORREF cr = GetPixel(hDC, 0, 0);
        g_i64Read = c.Elapsed() / iCount;
        ReleaseDC(NULL, hDC);
    }
}

int APIENTRY _tWinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPTSTR lpCmdLine,
                     int       nCmdShow)
{
    UNREFERENCED_PARAMETER(hPrevInstance);
    UNREFERENCED_PARAMETER(lpCmdLine);

    // Run our test.
    GetDCTest();

    MSG msg;

    // Initialize global strings
    MyRegisterClass(hInstance);

    // Perform application initialization:
    if (!InitInstance (hInstance, nCmdShow))
    {
        return FALSE;
    }


    // Main message loop:
    while (GetMessage(&msg, NULL, 0, 0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    return (int) msg.wParam;
}



//
//  FUNCTION: MyRegisterClass()
//
//  PURPOSE: Registers the window class.
//
//  COMMENTS:
//
//  This function and its usage are only necessary if you want this code
//  to be compatible with Win32 systems prior to the 'RegisterClassEx'
//  function that was added to Windows 95. It is important to call this function
//  so that the application will get 'well formed' small icons associated
//  with it.
//
ATOM MyRegisterClass(HINSTANCE hInstance)
{
    WNDCLASSEX wcex;

    wcex.cbSize = sizeof(WNDCLASSEX);

    wcex.style          = CS_HREDRAW | CS_VREDRAW;
    wcex.lpfnWndProc    = WndProc;
    wcex.cbClsExtra     = 0;
    wcex.cbWndExtra     = 0;
    wcex.hInstance      = hInstance;
    wcex.hIcon          = NULL;
    wcex.hCursor        = LoadCursor(NULL, IDC_ARROW);
    wcex.hbrBackground  = (HBRUSH)(COLOR_WINDOW+1);
    wcex.lpszMenuName   = NULL;
    wcex.lpszClassName  = _T("GetDCTest");
    wcex.hIconSm        = NULL;

    return RegisterClassEx(&wcex);
}

//
//   FUNCTION: InitInstance(HINSTANCE, int)
//
//   PURPOSE: Saves instance handle and creates main window
//
//   COMMENTS:
//
//      In this function, we save the instance handle in a global variable and
//      create and display the main program window.
//
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
   HWND hWnd;

   hInst = hInstance; // Store instance handle in our global variable

   hWnd = CreateWindow(_T("GetDCTest"), _T("GetDCTest"), WS_OVERLAPPEDWINDOW,
      CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);

   if (!hWnd)
   {
      return FALSE;
   }

   ShowWindow(hWnd, nCmdShow);
   UpdateWindow(hWnd);

   return TRUE;
}

//
//  FUNCTION: WndProc(HWND, UINT, WPARAM, LPARAM)
//
//  PURPOSE:  Processes messages for the main window.
//
//  WM_COMMAND  - process the application menu
//  WM_PAINT    - Paint the main window
//  WM_DESTROY  - post a quit message and return
//
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    PAINTSTRUCT ps;
    HDC hdc;

    switch (message)
    {
    case WM_PAINT:
        {
            hdc = BeginPaint(hWnd, &ps);
            RECT rc;
            GetClientRect(hWnd, &rc);
            rc.top = rc.bottom / 2;
            
            // Draw to the screen.
            std::stringstream ss;
            ss<<"Time to create DC: "<<g_i64Create<<" ms per call.\nTime to read DC: "<<g_i64Read<<" ms per call.";
            DrawTextA(hdc, ss.str().c_str(), -1, &rc, DT_CENTER);

            EndPaint(hWnd, &ps);
        }
        break;
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    default:
        return DefWindowProc(hWnd, message, wParam, lParam);
    }
    return 0;
}
Link to comment
Share on other sites

  • Administrators

Aero:

Create: 565ms

Read: 475637ms (?)

Vista basic:

Create: 553ms

Read: 30ms

Also, I have a 1900x1200 resolution which won't be helping if the pixel functions are indeed making copies offscreen.

MS want everyone to use WPF instead of GDI...

Link to comment
Share on other sites

Umm, yeah. So caching the DC doesn't do shit, then. Okay, sure you save a couple hundred ms per call which is nothing to sneeze at. But like I suspected, it's not going to go from slow to usable since it's not really GetDC() that's slow but rather reading from the DC.

I don't know, is it worth it to add DC support when we already have HWND support?

Link to comment
Share on other sites

Umm, yeah. So caching the DC doesn't do shit, then. Okay, sure you save a couple hundred ms per call which is nothing to sneeze at. But like I suspected, it's not going to go from slow to usable since it's not really GetDC() that's slow but rather reading from the DC.

I don't know, is it worth it to add DC support when we already have HWND support?

No. I don't think so. I am going to have to get used to using the hWnd when doing Pixel functions. Just need sharpen my mouse position and hWndUnderMouse skills.

Thanks Jon and Valik, you two have saved me a lot of time.

Lar.

f_mrcleansmalm_77ce002.jpgAutoIt has helped make me wealthy

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...