Weirdness when double-buffering

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Post Reply
User avatar
justinian
Posts: 19
Joined: Mon Apr 23, 2018 6:25 pm
Location: San Francisco

Weirdness when double-buffering

Post by justinian »

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:
Image

When I double-buffer, it looks like this:
Image

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;
}
Any ideas? Please tell me I did something simple and obvious..
Gigasoft
Member
Member
Posts: 856
Joined: Sat Nov 21, 2009 5:11 pm

Re: Weirdness when double-buffering

Post by Gigasoft »

Looks like something is wrong with malloc, where some of the memory being allocated overlaps with video memory.
User avatar
justinian
Posts: 19
Joined: Mon Apr 23, 2018 6:25 pm
Location: San Francisco

Re: Weirdness when double-buffering

Post by justinian »

Gigasoft wrote:Looks like something is wrong with malloc, where some of the memory being allocated overlaps with video memory.
Yeah, it sure does look like it's getting written over by something.. but if I follow the mappings, the lfb is at 0x90000000 (identity mapped) and the back buffer is at 0x1c0000000 (ends up mapped to somewhere around 0x1fc4f000). Though, that's what it starts at.. maybe there's some stack corruption and something is overwriting the pointer or something. I'll go look for that.
Developing: jsix - UEFI-booted x64 kernel
Gigasoft
Member
Member
Posts: 856
Joined: Sat Nov 21, 2009 5:11 pm

Re: Weirdness when double-buffering

Post by Gigasoft »

The asm statement is also wrong. It should be:

Code: Select all

uint64_t unused1, unused2;
asm volatile ( "rep stosl" : "=c"(unused1), "=D"(unused2) :
      "a"(color), "0"(len), "1"(m_back));
User avatar
justinian
Posts: 19
Joined: Mon Apr 23, 2018 6:25 pm
Location: San Francisco

Re: Weirdness when double-buffering

Post by justinian »

Gigasoft wrote:The asm statement is also wrong. It should be:

Code: Select all

uint64_t unused1, unused2;
asm volatile ( "rep stosl" : "=c"(unused1), "=D"(unused2) :
      "a"(color), "0"(len), "1"(m_back));
Interesting, why? It seems like this is just adding them to the output constraints list as well as the input constraints list, but then not using the output. The main difference in generated asm is storing them back in the local stack frame right before returning, which is pretty much what I'd expect.
Developing: jsix - UEFI-booted x64 kernel
Gigasoft
Member
Member
Posts: 856
Joined: Sat Nov 21, 2009 5:11 pm

Re: Weirdness when double-buffering

Post by Gigasoft »

GCC assumes that input-only registers remain unchanged. However, if you are compiling with optimizations off, it doesn't matter.
Post Reply