iAmNewbe Posted July 19, 2020 Posted July 19, 2020 (edited) While using the screen capture feature of AutoIT I am having problems with CPU spiking each time it runs. I created sample code below. I am creating several tools that use screen capture from the mouse pointer position and in one of the applications I am using two separate screen captures of the same area one would overlay over the other for a zoom effect for example. The below code uses two screen captures which run in a tight loop for the live effect. I am not saving any files to a drive because it is not needed in the use case I am doing this in. I read somewhere else with examples in the forum of using "double buffering" but I do not understand this or how to use it in the code below. Not sure if it would work or be useful in this example. I have seen and have freeware color pickers that use screen capture, maybe done differently and they do not spike the CPU at all. Why is this code example doing it? Changing the sleep time in the loop doesn't stop the CPU spikes just happens less frequent though it does happen every time the capture() function runs. Is there another way to do the below that I can understand? Took me awhile to figure out how to do this code. Press 'ESC' to close the application Thanks for any help. expandcollapse popup#AutoIt3Wrapper_AU3Check_Parameters=-q -d -w 1 -w 2 -w 3 -w- 4 -w 5 -w 6 -w- 7 #include <WindowsConstants.au3> #include <GUIConstantsEx.au3> #include <ScreenCapture.au3> #include <GDIPlus.au3> HotKeySet("{ESC}","close") Global $gui = GUICreate('Test', 350, 200, -1, -1, $WS_BORDER + $WS_POPUP) GUISetState(@SW_SHOW) Func capture() Local $getMPos = MouseGetPos() _GDIPlus_Startup() Local $hScrn1 = _ScreenCapture_Capture("", $getMPos[0] - 10, $getMPos[1] - 10, $getMPos[0] + 10, $getMPos[1] + 10, False) Local $hScrn2 = _ScreenCapture_Capture("", $getMPos[0] - 80, $getMPos[1] - 80, $getMPos[0] + 80, $getMPos[1] + 80, False) Local $cap1 = _GDIPlus_BitmapCreateFromHBITMAP($hScrn1) Local $cap2 = _GDIPlus_BitmapCreateFromHBITMAP($hScrn2) _WinAPI_DeleteObject($hScrn1) _WinAPI_DeleteObject($hScrn2) Local $gObj = _GDIPlus_GraphicsCreateFromHWND($gui) _GDIPlus_GraphicsDrawImage($gObj, $cap1, 10, 20) _GDIPlus_GraphicsDrawImage($gObj, $cap2, 180, 20) _GDIPlus_GraphicsDispose($gObj) _GDIPlus_BitmapDispose($cap1) _GDIPlus_BitmapDispose($cap2) _GDIPlus_Shutdown() EndFunc While 1 capture() Sleep(50) WEnd Func close() GUIDelete($gui) Exit EndFunc Edited July 19, 2020 by iAmNewbe Adjusted Code to use separate off sets
Dan_555 Posted July 19, 2020 Posted July 19, 2020 (edited) Hmm, in your exampe, you can skip one screen capture, as it is using the same data which is under the mouse. Local $hScrn1 = _ScreenCapture_Capture("", $getMPos[0] - 80, $getMPos[1] - 80, $getMPos[0] + 80, $getMPos[1] + 80, False) ;Local $hScrn2 = _ScreenCapture_Capture("", $getMPos[0] - 80, $getMPos[1] - 80, $getMPos[0] + 80, $getMPos[1] + 80, False) Local $cap1 = _GDIPlus_BitmapCreateFromHBITMAP($hScrn1) Local $cap2 = _GDIPlus_BitmapCreateFromHBITMAP($hScrn1) ;<---- hScrn1 _WinAPI_DeleteObject($hScrn1) ;_WinAPI_DeleteObject($hScrn2) Unless you want to offset the hScrn2 to something else, i would do it in this way. About double buffering: It is used to make drawing on the screen smooth and to avoid flickerings. You (basically) have 2 drawing buffers, which are displayed one after other. While the one is being shown, the other receives the drawing operations. At the loop end, the buffers are switched, so that the buffer, which received the drawing, shows its contents, and the other buffer becomes the receiver. It is, technically a flipbook animation technique, just that the computer uses only 2 papers for drawing, because it can switch and draw on them on the fly. Edited July 19, 2020 by Dan_555 Some of my script sourcecode
iAmNewbe Posted July 19, 2020 Author Posted July 19, 2020 Yes in my actual code I have different offsets for the two screen captures. I adjusted the code in the OP to reflect this instead of just saying that i did this in the explanation. How do you implement the buffering? The CPU still spikes whether it is one or two screen captures. Why and how to fix this?
iAmNewbe Posted July 19, 2020 Author Posted July 19, 2020 (edited) In my code example there is no flickering so I don't need to use double buffering in my use case? I am looking for way to reduce the CPU spiking. Edited July 19, 2020 by iAmNewbe
iAmNewbe Posted July 19, 2020 Author Posted July 19, 2020 (edited) Local $hScrn1 = _ScreenCapture_Capture("", $getMPos[0] - 80, $getMPos[1] - 80, $getMPos[0] + 80, $getMPos[1] + 80, False) Local $cap1 = _GDIPlus_BitmapCreateFromHBITMAP($hScrn1) _GDIPlus_GraphicsDrawImage($gObj, $cap1, 180, 20) _GDIPlus_GraphicsDrawImage($gObj, $cap1, 180, 20) In this example... Is this double buffering? You said one gets drawn to then the other received the finished drawing. But the above is just drawing over the other simultaneously. I thought that the "Buffer" was stored in memory and used like a temporary cache. I am not understanding this yet. Edited July 19, 2020 by iAmNewbe corrected typos
Dan_555 Posted July 19, 2020 Posted July 19, 2020 (edited) You can look at some examples in here: Double buffering is used mainly for games. A screenshot is a kind of buffer, but it doesn't need double buffering, because you are not modifying it on the fly. Edited July 19, 2020 by Dan_555 Some of my script sourcecode
iAmNewbe Posted July 19, 2020 Author Posted July 19, 2020 Will look at the links, thank you. The Screenshot example above does update on the fly via a loop and capturing around the mouse pointer so maybe it does need it? I don't know.
iAmNewbe Posted July 19, 2020 Author Posted July 19, 2020 Still not sure about the CPU Spiking though.. Has to do with the GDI+ ???
Dan_555 Posted July 19, 2020 Posted July 19, 2020 (edited) Here the spike is almost not noticeable. Well, at the Start, the fan could be heard (i guess ~20% of rotation speed), but then, after about 5~10 seconds it becomes silent again (~10%). I'm not an expert in GDI(+) but i guess it can be done like this too: expandcollapse popup#AutoIt3Wrapper_AU3Check_Parameters=-q -d -w 1 -w 2 -w 3 -w- 4 -w 5 -w 6 -w- 7 #include <WindowsConstants.au3> #include <GUIConstantsEx.au3> #include <ScreenCapture.au3> #include <GDIPlus.au3> HotKeySet("{ESC}","close") Global $gui = GUICreate('Test', 350, 200, -1, -1, $WS_BORDER + $WS_POPUP) GUISetState(@SW_SHOW) Global $gObj Func capture() Local $getMPos = MouseGetPos() Local $hScrn1 = _ScreenCapture_Capture("", $getMPos[0] - 80, $getMPos[1] - 80, $getMPos[0] + 80, $getMPos[1] + 80, False) Local $hScrn2 = _ScreenCapture_Capture("", $getMPos[0] - 180, $getMPos[1] - 180, $getMPos[0] + 180, $getMPos[1] + 180, False) Local $cap1 = _GDIPlus_BitmapCreateFromHBITMAP($hScrn1) Local $cap2 = _GDIPlus_BitmapCreateFromHBITMAP($hScrn2) ;<---- hScrn1 _WinAPI_DeleteObject($hScrn1) _WinAPI_DeleteObject($hScrn2) _GDIPlus_GraphicsDrawImage($gObj, $cap1, 10, 20) _GDIPlus_GraphicsDrawImage($gObj, $cap2, 180, 20) _GDIPlus_BitmapDispose($cap1) _GDIPlus_BitmapDispose($cap2) EndFunc _GDIPlus_Startup() $gObj = _GDIPlus_GraphicsCreateFromHWND($gui) While 1 capture() ;Sleep(40) WEnd Func close() _GDIPlus_GraphicsDispose($gObj) _GDIPlus_Shutdown() GUIDelete($gui) Exit EndFunc Edited July 19, 2020 by Dan_555 Placed GDI_Shutdown into the close function ! Some of my script sourcecode
iAmNewbe Posted July 20, 2020 Author Posted July 20, 2020 (edited) I opened Task Manager and looked at the Processes tab. Comparing your version to the original I don't see any change in the CPU column or how often it jumps to 01 for the process. I compiled it out to EXE and watched that. Also switching to the Performance Tab you see the increase activity everytime the capture() function runs. I don't know. Maybe it is not fixable in this use case? I can survive it, where I will be using this won't be active for very long so it won't be a long term stress, just when needing to see what is directly under the cursor. Like a Color, or for absolute positioning an element say on a web page, or setting points between locations on a screen for comparing distance or whatever. Thanks for your help. Edited July 20, 2020 by iAmNewbe
iAmNewbe Posted July 20, 2020 Author Posted July 20, 2020 I created a Toggle switch to turn on and off the screen capture via the space bar. Doesn't solve the problem but allows for opting to not run or "pause" the screen capture. Global $toggle = 0 HotKeySet("{SPACE}","toggleScreenCap") While 1 If $toggle = 0 Then capture() ;Sleep(40) WEnd Func toggleScreenCap() If $toggle = 1 Then $toggle = 0 ElseIf $toggle = 0 Then $toggle = 1 EndIf EndFunc
Recommended Posts
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 accountSign in
Already have an account? Sign in here.
Sign In Now