wxPanel on another panel, repaint using a lot CPU
-
- Ultimate wxWidgets Guru
- Posts: 539
- Joined: Fri May 22, 2009 8:52 am
- Location: Bremen, Germany
wxPanel on another panel, repaint using a lot CPU
I have a custom wxPanel to show infos about whatever is under the cursor (the orange panel)
Is there a better way that uses less CPU?
this is a wxPanel and I copy all the underlying bitmaps every time the mouse moves and the panel with it. This uses a lot of CPU, but when I do not copy the bitmaps while the mouse is moving, the panel leaves a trace (old versions of it).Is there a better way that uses less CPU?
Re: wxPanel on another panel, repaint using a lot CPU
There must be drawing issue somewhere.
Also, are you sure you cannot use a wx(Rich)ToolTip instead of the custom panel?
Also, are you sure you cannot use a wx(Rich)ToolTip instead of the custom panel?
-
- Ultimate wxWidgets Guru
- Posts: 539
- Joined: Fri May 22, 2009 8:52 am
- Location: Bremen, Germany
Re: wxPanel on another panel, repaint using a lot CPU
Can I make drawing faster (less CPU hungry) by somehow not having to draw the whole background on every little mouse movement? Maybe using https://docs.wxwidgets.org/3.1.2/classw ... ipper.html?
I looked into it, it is not customizable enough, too big and ugly on MSW.
Re: wxPanel on another panel, repaint using a lot CPU
Are you drawing individual circles? If yes, try rendering into a background bitmap instead that's only updated when the content changes. Additionally, you can update only the "dirty" rectangles. Check the code snippet using GetUpdateRegion() from here: https://docs.wxwidgets.org/trunk/classw ... event.htmlCan I make drawing faster (less CPU hungry) by somehow not having to draw the whole background on every little mouse movement?
I think you could also just use a borderless wxFrame for the tooltip. To avoid Z-order issues, i'd show it only when the main frame is active.
Use the source, Luke!
-
- Ultimate wxWidgets Guru
- Posts: 539
- Joined: Fri May 22, 2009 8:52 am
- Location: Bremen, Germany
Re: wxPanel on another panel, repaint using a lot CPU
The biggest part of cpu usage comes from wxDc::DrawBitmap on a wxBufferedPaintDC. The circles are already painted on a wxBitmap earlier.
That is nice! A simpledoublemax wrote: ↑Sun Apr 19, 2020 11:45 amAdditionally, you can update only the "dirty" rectangles. Check the code snippet using GetUpdateRegion() from here: https://docs.wxwidgets.org/trunk/classw ... event.html
Code: Select all
wxBufferedPaintDC bpdc(this);
bpdc.SetDeviceClippingRegion(GetUpdateRegion());
I don't understand what you mean by "borderless"? At the moment, it is a
Code: Select all
wxPanel(par, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxBORDER_SIMPLE)
Re: wxPanel on another panel, repaint using a lot CPU
I meant a real, complete wxFrame, an independent toplevel window for the tooltip, that you position at the correct coordinates.I don't understand what you mean by "borderless"?
Use the source, Luke!
-
- Ultimate wxWidgets Guru
- Posts: 539
- Joined: Fri May 22, 2009 8:52 am
- Location: Bremen, Germany
Re: wxPanel on another panel, repaint using a lot CPU
Cool idea, tried it, but it leads to ~20% higher cpu load than wxPanel. Only with wxFrame it is not the wxPaintEvent of the underlying panel but SetPosition and SetSizeHints that cost more. But I am pretty happy with it now, it uses about half of the cpu compared to before. So if there is not much else one can try, then maybe this is as good as it gets.
Re: wxPanel on another panel, repaint using a lot CPU
Of course you still get paint events in the underlying window when you move the frame accross.
In fact, nothing i see on your screenshot should take any significant CPU load on modern hardware.
Here you should definitely use the wxBufferedPaintDC overload that takes a wxBitmap &buffer as paramter. This buffer bitmap should be static and only get (re-) created when the client size changes. This should save some time.
I find it hard to believe that these cause so much CPU load.Only with wxFrame it is not the wxPaintEvent of the underlying panel but SetPosition and SetSizeHints that cost more.
In fact, nothing i see on your screenshot should take any significant CPU load on modern hardware.
Code: Select all
wxBufferedPaintDC bpdc(this);
bpdc.SetDeviceClippingRegion(GetUpdateRegion());
Use the source, Luke!
-
- Ultimate wxWidgets Guru
- Posts: 539
- Joined: Fri May 22, 2009 8:52 am
- Location: Bremen, Germany
Re: wxPanel on another panel, repaint using a lot CPU
I wrote this little test program and cannot see any difference in cpu usage when moving the mouse quickly on the maximized window with a bitmap showing. I used the bitmap from my first post.doublemax wrote: ↑Mon Apr 20, 2020 10:29 amHere you should definitely use the wxBufferedPaintDC overload that takes a wxBitmap &buffer as paramter. This buffer bitmap should be static and only get (re-) created when the client size changes. This should save some time.Code: Select all
wxBufferedPaintDC bpdc(this); bpdc.SetDeviceClippingRegion(GetUpdateRegion());
Code: Select all
#pragma once
#include <wx/frame.h>
#include <wx/app.h>
#include <wx/filename.h>
#include <wx/stdpaths.h>
#include <wx/dcbuffer.h>
class CursorPanel : public wxPanel {
public:
CursorPanel(wxWindow* par) : wxPanel(par){
SetOwnBackgroundColour(wxColour(255, 126, 40));
SetFont(wxFont(9, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD));
wxBoxSizer* outerBox = new wxBoxSizer(wxVERTICAL);
SetSizer(outerBox);
coordsText = new wxStaticText(this, wxID_ANY, wxT("5/10"));
wxString label = coordsText->GetLabel();
coordsText->SetForegroundColour(*wxBLACK);
GetSizer()->Add(coordsText, 1, wxALIGN_CENTER_HORIZONTAL | wxALL, 5);
}
wxPoint getCursorCoords() {
wxPoint ret;
wxString label = coordsText->GetLabel();
ret.x = wxAtoi(label.BeforeFirst('/'));
ret.y = wxAtoi(label.AfterFirst('/'));
return ret;
}
void setCursorCoords(wxPoint newCoords) {
if (newCoords == getCursorCoords())
return;
coordsText->SetLabel(wxString::Format(wxT("%i/%i"), newCoords.x, newCoords.y));
GetSizer()->SetSizeHints(this);
}
private:
wxStaticText* coordsText = nullptr;
};
class MyFrame1 : public wxFrame
{
public:
MyFrame1( wxWindow* parent = NULL,
wxWindowID id = wxID_ANY,
const wxString& title = wxEmptyString,
const wxPoint& pos = wxDefaultPosition,
const wxSize& size = wxSize( 500,300 ),
long style = wxDEFAULT_FRAME_STYLE | wxTAB_TRAVERSAL) :
wxFrame(parent, id, title, pos, size, style)
{
wxInitAllImageHandlers();
wxFileName f(wxStandardPaths::Get().GetExecutablePath());
wxString appPath(f.GetPath());
loadedBtmp = wxBitmap(appPath + wxT("\\panelOnBtmp.jpg"), wxBITMAP_TYPE_JPEG);
bool btmpOk = loadedBtmp.IsOk();
bufferBtmp = wxBitmap(GetClientSize());
SetSizer(new wxBoxSizer(wxVERTICAL));
curPan = new CursorPanel(this);
Bind(wxEVT_MOTION, &MyFrame1::onMouseMotion, this);
Bind(wxEVT_PAINT, &MyFrame1::onPaint, this);
Bind(wxEVT_SIZE, &MyFrame1::onResize, this);
this->SetSizeHints(wxDefaultSize, wxDefaultSize);
this->Centre(wxBOTH);
}
~MyFrame1() {}
void onMouseMotion(const wxMouseEvent& evt) {
this;
wxPoint cursorSize(15, 15);
wxPoint evtPos = evt.GetPosition();
curPan->SetPosition(evtPos + cursorSize);
curPan->setCursorCoords(evt.GetPosition());
}
void onPaint(const wxPaintEvent& evt) {
wxBufferedPaintDC bpdc(this/*, bufferBtmp*/);
bpdc.SetDeviceClippingRegion(GetUpdateRegion());
bpdc.DrawBitmap(loadedBtmp, wxPoint(0, 0));
}
void onResize(const wxSizeEvent& evt) {
bufferBtmp = wxBitmap(GetClientSize());
}
CursorPanel* curPan = nullptr;
wxBitmap loadedBtmp, bufferBtmp;
private:
};
class MyApp : public wxApp {
virtual bool OnInit();
};
Re: wxPanel on another panel, repaint using a lot CPU
Hmm, the CPU load on my system is around 1-2%, no matter how fast i move the mouse. From your posts i would have expected something much worse
Use the source, Luke!
-
- Ultimate wxWidgets Guru
- Posts: 539
- Joined: Fri May 22, 2009 8:52 am
- Location: Bremen, Germany
Re: wxPanel on another panel, repaint using a lot CPU
Hmmmmmmm, when I maximize the frame on a full hd display and move the mouse around it goes up to 8-9% on my i7 3.5GHz 16GB ram system. At least when not using
Code: Select all
bpdc.SetDeviceClippingRegion(GetUpdateRegion());
Re: wxPanel on another panel, repaint using a lot CPU
Yes, i'm under Windows.
If i make the window fullscreen, i can get it up to 4%. But, i get 4% even if i leave the paint event handler empty. I made a few variants of the code, but i never got it below these 4%.
There is one approach i haven't tried, because it was a little too much effort, but if you really want to optimize it more, maybe you can try:
Get rid of CursorPanel, instead draw its content yourself. And - although i always preach not to use it - here the use of wxClientDC might make sense. Instead of forcing a refresh when the cursor moves, draw into the wxClientDC of the frame, and only the parts that have changed. I can't think of any faster way to do it.
If i make the window fullscreen, i can get it up to 4%. But, i get 4% even if i leave the paint event handler empty. I made a few variants of the code, but i never got it below these 4%.
There is one approach i haven't tried, because it was a little too much effort, but if you really want to optimize it more, maybe you can try:
Get rid of CursorPanel, instead draw its content yourself. And - although i always preach not to use it - here the use of wxClientDC might make sense. Instead of forcing a refresh when the cursor moves, draw into the wxClientDC of the frame, and only the parts that have changed. I can't think of any faster way to do it.
Use the source, Luke!
Re: wxPanel on another panel, repaint using a lot CPU
Regarding the CPU utilization: I believe that on modern CPUs just the percentage can be deceiving, as the CPU underclocks when not fully utilized. For example, my desktop AMD CPU underclocks to < 2 GHz from its default 3.4. The current speed can be seen on the Performance tab of the Task Manager.
Does running your application make your CPU go to its full speed?
Does running your application make your CPU go to its full speed?
-
- Ultimate wxWidgets Guru
- Posts: 539
- Joined: Fri May 22, 2009 8:52 am
- Location: Bremen, Germany
Re: wxPanel on another panel, repaint using a lot CPU
That is really interesting. In my posts I used the cpu values straight from the process tab of the task manager, but the ressource monitor for this process shows lower values. I guess these are more adequate.PB wrote: ↑Tue Apr 21, 2020 8:33 am Regarding the CPU utilization: I believe that on modern CPUs just the percentage can be deceiving, as the CPU underclocks when not fully utilized. For example, my desktop AMD CPU underclocks to < 2 GHz from its default 3.4. The current speed can be seen on the Performance tab of the Task Manager.
When doublemax's tips worked, I noticed around 40% of cpu usage came from a ProcessIdle function. I trace these with the visual studio cpu diagnostic tool.
I noticed it went to a max value in the cpu usage chart. I show a real time signal on screen and additionally moving the mouse with this CursorPanel over a wxBitmap made the signal stutter on a machine less powerful than mine. It is way better now.
I am happy now and only try this if I should need more optimization in the future. Thank you for you valuable input, I learned a lot from it!doublemax wrote: ↑Tue Apr 21, 2020 8:06 amThere is one approach i haven't tried, because it was a little too much effort, but if you really want to optimize it more, maybe you can try:
Get rid of CursorPanel, instead draw its content yourself. And - although i always preach not to use it - here the use of wxClientDC might make sense. Instead of forcing a refresh when the cursor moves, draw into the wxClientDC of the frame, and only the parts that have changed. I can't think of any faster way to do it.