Open wjiali6 opened 5 years ago
Use a thread instead of a timer.
dw = new nana::drawing(form);
dw->draw([this](nana::paint::graphics &g){ ball.paste(g,{ballPosition.x,ballPosition.y}); });
std::thread thr([this]{
while(true)
{
_calculate_ball_pos();
nana::API::refresh_window(form);
std::this_thread::sleep_for(std::chrono::milliseconds(10));
}
});
Using another thread solves the flickering problem but I noticed It's very bad in efficiency, sleep 10 milli Sec between every refresh window call ,uses up 10% to 17% of my old i5-3230 @2.6GHz laptop,I'll try again on my i7-6700 home when I'm off duty.
same program compiled from one source runs perfectly (cpu usage 1 to 0)on i7 6700 windows 7 ,but consumes about 12% to 15% on i5 3230 windows 10. it might nothing to do with nana
After a quick profiling with visual studio ,now I have this data nana::API::refresh_window(*plygrd); --consumes 61% percent of cpu time and in that call nana::detail::window_layout::maproot takes 36.4% nana::detail::drawer::refresh takes 24.4%
and along with this test I found that nana pastes the whole scene every time, this causes cpu consumption grows significantly as the scene gets larger
Thanks for your feedback!
In the past, I used nana library to write graphical application that runs on Windows platform. I could achieve smooth drawing by directly modifying pixels that nana library manages. This might be kind of dirty hack though. I'm not sure if current nana library still supports this way.
void draw_foo(paint::graphics& g, ....)
{
auto sz = g.size();
paint::pixel_buffer pbuffer;
rectangle r;
r.x = 0;
r.y = 0;
r.width = sz.width;
r.height = sz.height;
pbuffer.attach(g.handle(), r);
pixel_color_t* line = pbuffer.raw_ptr(0);
size_t lineBytes = pbuffer.bytes_per_line();
memset(line, 0xFF, lineBytes * r.height);
}
void show_form()
{
appearance ap;
ap.minimize = false;
form fm(parent, size(1400, 800), ap);
....
drawing dw{fm};
paint::graphics g;
dw.draw([&](paint::graphics& graph){
graph.bitblt(0, get_controls_bottom(), g);
});
// call this on event
auto& draw = [&]() {
if (!is_ok_to_draw) {
return;
}
UTILITY_SCOPE_EXIT([&](){
dw.update();
});
draw_foo(
g,
......
);
};
.....
}
An another idea solution is to use Vulkan.
https://github.com/tim37021/NANA_VULKAN
In the past, I used nana library to write graphical application that runs on Windows platform. I could achieve smooth drawing by directly modifying pixels that nana library manages. This might be kind of dirty hack though. I'm not sure if current nana library still supports this way.
void draw_foo(paint::graphics& g, ....) { auto sz = g.size(); paint::pixel_buffer pbuffer; rectangle r; r.x = 0; r.y = 0; r.width = sz.width; r.height = sz.height; pbuffer.attach(g.handle(), r); pixel_color_t* line = pbuffer.raw_ptr(0); size_t lineBytes = pbuffer.bytes_per_line(); memset(line, 0xFF, lineBytes * r.height); } void show_form() { appearance ap; ap.minimize = false; form fm(parent, size(1400, 800), ap); .... drawing dw{fm}; paint::graphics g; dw.draw([&](paint::graphics& graph){ graph.bitblt(0, get_controls_bottom(), g); }); // call this on event auto& draw = [&]() { if (!is_ok_to_draw) { return; } UTILITY_SCOPE_EXIT([&](){ dw.update(); }); draw_foo( g, ...... ); }; ..... }
An another ~idea~ solution is to use Vulkan. https://github.com/tim37021/NANA_VULKAN I'll try your sollution and feed back by the end of the week,thank you
In the past, I used nana library to write graphical application that runs on Windows platform. I could achieve smooth drawing by directly modifying pixels that nana library manages. This might be kind of dirty hack though. I'm not sure if current nana library still supports this way.
void draw_foo(paint::graphics& g, ....) { auto sz = g.size(); paint::pixel_buffer pbuffer; rectangle r; r.x = 0; r.y = 0; r.width = sz.width; r.height = sz.height; pbuffer.attach(g.handle(), r); pixel_color_t* line = pbuffer.raw_ptr(0); size_t lineBytes = pbuffer.bytes_per_line(); memset(line, 0xFF, lineBytes * r.height); } void show_form() { appearance ap; ap.minimize = false; form fm(parent, size(1400, 800), ap); .... drawing dw{fm}; paint::graphics g; dw.draw([&](paint::graphics& graph){ graph.bitblt(0, get_controls_bottom(), g); }); // call this on event auto& draw = [&]() { if (!is_ok_to_draw) { return; } UTILITY_SCOPE_EXIT([&](){ dw.update(); }); draw_foo( g, ...... ); }; ..... }
An another ~idea~ solution is to use Vulkan. https://github.com/tim37021/NANA_VULKAN I'll try your sollution and feed back by the end of the week,thank you
following your solution ,I did something like
size_t lineBytes = pbuffer_of_img.bytes_per_line(); for(auto n = 0; n < height_of_img ; n++ ) { memcpy(x+y + pbuffer_of_form,pbuffer_of_img,pbuffer_of_img.bytes_per_line();) }
still having a jumping effect.
I wander if it something to do with amount of pixels for every call for _calculate_ball_pos, then I change _calculate_ball_pos as
``
_calculate_ball_pos()
{
static auto lastTimechecked = std::chrono::steady_clock::now();
if(this->ballPos->y >plgrd->size().height)
{
this->ballPos->y = 0;
}else
{
auto now = std::chrono::steady_clock::now();
auto delta = (now - lastTimechecked).count();
this->ballPos->y += delta/10000000 + 0.5;
lastTimechecked = now;
}
}
`` but still have flickering
I have a code which draws a png image on frame graphics ,But I found that no matter how often I call the refresh window I still get some flickering (it seems nana produces drawing calls with vsync),this is how I do my drawing
nana::timer t1; dw = new nana::drawing(form); dw->draw([this](nana::paint::graphics &g){ ball.paste(g,{ballPosition.x,ballPosition.y}); }); t1.interval(10); t1.elapse([this](){ this->_calculate_ball_pos(); nana::API::refresh_window(form); }); t1.start();
_calculate_ball_pos() looks like this ` _calculate_ball_pos() { static bool down = true; const int delta = 2; auto ballsize = ball.size(); auto playgroundsize = plygrd->size(); if(down) { if(ballPosition.y + ballsize.height/2 == playgroundsize.height) { down = false; ballPosition.y -= delta; return; } if(ballPosition.y + ballsize.height/2 + delta >= playgroundsize.height) { ballPosition.y = playgroundsize.height - ballsize.height/2; down = false; return; } ballPosition.y += delta; } else { if(ballPosition.y == 0) { down = true; ballPosition.y +=delta; return; } if(ballPosition.y - delta <= 0) { ballPosition.y = 0; down = true; return; } ballPosition.y -= delta; } }`