Weirdness when double-buffering
Posted: Fri Feb 05, 2021 12:00 am
So I've been banging my head on this issue and can't figure it out. I'm wondering if any of you might have some insight. I've got a framebuffer (from GOP, on both real hardware and QEMU) and a userspace program that gets that framebuffer mapped into its address space. If I write directly to the framebuffer in this program, everything looks right. But if I malloc a back buffer and do double-buffering, things start looking skewed and over-drawn.
When I draw directly to the framebuffer, it looks like this:

When I double-buffer, it looks like this:

You can see the branch with my WIP code trying to figure this out in my GitHub repo, where the only difference is uncommenting the line here. So I'm still mallocing the back buffer, still drawing the same way, still even copying the frame (though then it's just copying the framebuffer to itself). I must just be forgetting something stupid here, but I can't for the life of me figure it out.
For ease of looking at, here's the most relevant code:
Any ideas? Please tell me I did something simple and obvious..
When I draw directly to the framebuffer, it looks like this:

When I double-buffer, it looks like this:

You can see the branch with my WIP code trying to figure this out in my GitHub repo, where the only difference is uncommenting the line here. So I'm still mallocing the back buffer, still drawing the same way, still even copying the frame (though then it's just copying the framebuffer to itself). I must just be forgetting something stupid here, but I can't for the life of me figure it out.
For ease of looking at, here's the most relevant code:
Code: Select all
screen::screen(volatile void *addr, unsigned hres, unsigned vres, unsigned scanline, pixel_order order) :
m_fb(static_cast<volatile pixel_t *>(addr)),
m_order(order),
m_scanline(scanline),
m_resx(hres),
m_resy(vres)
{
m_back = reinterpret_cast<pixel_t*>(malloc(scanline*vres*sizeof(pixel_t)));
//m_back = const_cast<pixel_t*>(m_fb); // <==== Uncommenting this to use the FB directly
}
void
screen::fill(pixel_t color)
{
const size_t len = m_scanline * m_resy;
asm volatile ( "rep stosl" : :
"a"(color), "c"(len), "D"(m_back) );
}
void
screen::update()
{
const size_t len = m_scanline * m_resy;
for (size_t i = 0; i < len; ++i) {
m_fb[i] = m_back[i];
}
}
// this function is defined inline in the header
inline void draw_pixel(unsigned x, unsigned y, pixel_t color) {
const size_t index = x + y * m_scanline;
if (x > m_resx || y > m_resy)
return;
m_back[index] = color;
}