Page 1 of 2

Getting performant VESA video output

Posted: Wed Oct 07, 2015 1:16 am
by max
Hey :)

I've implemented a windowing system that works itself quite performant and well. Still, it doesn't feel as smooth as I'd want it to, because theres a huge bottleneck: the video output.

My rather primitive approach to write the pixels to the output looks like this. It only works for LFBs and 24 or 32 bit modes. So the thing is, it works, but in VirtualBox it takes about 10ms to blit stuff. I only blit the area of the screen that is actually "dirty" (like where the mouse cursor moves or a button is clicked).

"invalid" is the rectangle to be written out, "sourceSize" is the size of the internal buffer, "source" is the internal argb buffer.

Code: Select all

void vbe_video_output_t::blit(g_rectangle invalid, g_rectangle sourceSize, g_color_argb* source) {

	uint16_t bpp = video_mode_information.bpp;
	uint8_t* position = ((uint8_t*) video_mode_information.lfb) + (invalid.y * video_mode_information.bpsl);

	uint32_t right = invalid.x + invalid.width;
	uint32_t bottom = invalid.y + invalid.height;

	if (bpp == 32) {
		for (int y = invalid.y; y < bottom; y++) {
			uint32_t* position4 = (uint32_t*) position;
			for (int x = invalid.x; x < right; x++) {
				position4[x] = source[y * sourceSize.width + x];
			}
			position += video_mode_information.bpsl;
		}

	} else if (bpp == 24) {
		for (int y = invalid.y; y < bottom; y++) {
			for (int x = invalid.x; x < right; x++) {
				g_color_argb color = source[y * sourceSize.width + x];
				position[x * 3] = color & 0xFF;
				position[x * 3 + 1] = (color >> 8) & 0xFF;
				position[x * 3 + 2] = (color >> 16) & 0xFF;
			}
			position += video_mode_information.bpsl;
		}
	}
}
So my question is, how can you get a more performant video output? Or is that as good as it gets? VirtualBox is okay, but it just feels very slow in QEMU. Any help is greatly appreciated. :)

Greets,
Max

Oh, by the way, I've updated the Ghost website, you can leave comments now: http://ghostkernel.org/ :P

Re: Getting performant VESA video output

Posted: Wed Oct 07, 2015 1:32 am
by madanra
How does the performance compare between 24bpp and 32bpp?

In general, you want to be doing large, aligned reads & writes for performance.

Re: Getting performant VESA video output

Posted: Wed Oct 07, 2015 2:43 am
by max
madanra wrote:How does the performance compare between 24bpp and 32bpp?

In general, you want to be doing large, aligned reads & writes for performance.
Hi,

thanks for your response. Well for 24bpp its about 12-13ms per blit, for 32bpp it's about 9-10ms. The actual writing to the VESA memory is what's so slow. I'm looking for ways to accelerate that process.

Greets

Re: Getting performant VESA video output

Posted: Wed Oct 07, 2015 2:49 am
by Brendan
Hi,
max wrote:My rather primitive approach to write the pixels to the output looks like this. It only works for LFBs and 24 or 32 bit modes. So the thing is, it works, but in VirtualBox it takes about 10ms to blit stuff. I only blit the area of the screen that is actually "dirty" (like where the mouse cursor moves or a button is clicked).
In VirtualBox, with hardware acceleration used/enabled, if it takes 10ms to blit a small area when the mouse cursor moves or a button is clicked then something is extremely wrong.

In VirtualBox, without hardware acceleration, if it takes 10ms to blit a large area (or the entire screen) then the code is just slower than it could/should be.

In either case, post a disassembly so it's possible to determine what the code actually asks the CPU to do (which can be, and hopefully is, completely different to what the C++ source looks like it asks the CPU to do).

Also note that madanra is right. For example, for 24-bpp you want to load 4 pixels of data into registers, do bit shifting, then write 3 aligned dwords. For 32-bpp you'd want to be using "rep movsd" to do entire horizontal rows.


Cheers,

Brendan

Re: Getting performant VESA video output

Posted: Wed Oct 07, 2015 2:54 am
by gerryg400
Max, as you have discovered writing to video men is extremely slow. Reading will be even slower.

There are 2 steps to helping fix this.

1. Agregate blit buffers. In other words collect multiple sets of changes that might overlap to ensure that no pixel is written and re-written. Only think about writing to the screen when you have a complete transaction.

2. Have a buffer that is an identical copy of the screen. Begin by clearing them both. When doing an blit, compare the copy of the screen with the pixel you want to blit and only write to the actual screen if they are different. In other words if the pixels match do nothing. If the pixels differ write to the copy and to the screen. It takes a little bit of thought about how to do this but the results will be well worth it.

Re: Getting performant VESA video output

Posted: Wed Oct 07, 2015 3:21 am
by max
Hey guys,

what I've measured is actually only the time to execute that function.
@Brendan, yes madanra is right, as I said it's currently about 3ms faster with the dword-access, due to less memory writes.

I compiled it twice for simplicity, when writing to 32bits its:

Code: Select all

080597ea <vbe_video_output_t::blit(g_rectangle, g_rectangle, unsigned int*)>:
 80597ea:	55                   	push   %ebp
 80597eb:	89 e5                	mov    %esp,%ebp
 80597ed:	83 ec 20             	sub    $0x20,%esp
 80597f0:	8b 45 0c             	mov    0xc(%ebp),%eax
 80597f3:	8b 50 04             	mov    0x4(%eax),%edx
 80597f6:	8b 45 08             	mov    0x8(%ebp),%eax
 80597f9:	0f b7 40 0a          	movzwl 0xa(%eax),%eax
 80597fd:	0f b7 c0             	movzwl %ax,%eax
 8059800:	0f af c2             	imul   %edx,%eax
 8059803:	89 c2                	mov    %eax,%edx
 8059805:	8b 45 08             	mov    0x8(%ebp),%eax
 8059808:	8b 40 0c             	mov    0xc(%eax),%eax
 805980b:	01 d0                	add    %edx,%eax
 805980d:	89 45 fc             	mov    %eax,-0x4(%ebp)
 8059810:	8b 45 0c             	mov    0xc(%ebp),%eax
 8059813:	8b 10                	mov    (%eax),%edx
 8059815:	8b 45 0c             	mov    0xc(%ebp),%eax
 8059818:	8b 40 08             	mov    0x8(%eax),%eax
 805981b:	01 d0                	add    %edx,%eax
 805981d:	89 45 f0             	mov    %eax,-0x10(%ebp)
 8059820:	8b 45 0c             	mov    0xc(%ebp),%eax
 8059823:	8b 50 04             	mov    0x4(%eax),%edx
 8059826:	8b 45 0c             	mov    0xc(%ebp),%eax
 8059829:	8b 40 0c             	mov    0xc(%eax),%eax
 805982c:	01 d0                	add    %edx,%eax
 805982e:	89 45 ec             	mov    %eax,-0x14(%ebp)
 8059831:	8b 45 0c             	mov    0xc(%ebp),%eax
 8059834:	8b 40 04             	mov    0x4(%eax),%eax
 8059837:	89 45 f8             	mov    %eax,-0x8(%ebp)
 805983a:	eb 5d                	jmp    8059899 <vbe_video_output_t::blit(g_rectangle, g_rectangle, unsigned int*)+0xaf>
 805983c:	8b 45 fc             	mov    -0x4(%ebp),%eax
 805983f:	89 45 e8             	mov    %eax,-0x18(%ebp)
 8059842:	8b 45 0c             	mov    0xc(%ebp),%eax
 8059845:	8b 00                	mov    (%eax),%eax
 8059847:	89 45 f4             	mov    %eax,-0xc(%ebp)
 805984a:	eb 34                	jmp    8059880 <vbe_video_output_t::blit(g_rectangle, g_rectangle, unsigned int*)+0x96>
 805984c:	8b 45 f4             	mov    -0xc(%ebp),%eax
 805984f:	8d 14 85 00 00 00 00 	lea    0x0(,%eax,4),%edx
 8059856:	8b 45 e8             	mov    -0x18(%ebp),%eax
 8059859:	01 c2                	add    %eax,%edx
 805985b:	8b 45 10             	mov    0x10(%ebp),%eax
 805985e:	8b 40 08             	mov    0x8(%eax),%eax
 8059861:	0f af 45 f8          	imul   -0x8(%ebp),%eax
 8059865:	89 c1                	mov    %eax,%ecx
 8059867:	8b 45 f4             	mov    -0xc(%ebp),%eax
 805986a:	01 c8                	add    %ecx,%eax
 805986c:	8d 0c 85 00 00 00 00 	lea    0x0(,%eax,4),%ecx
 8059873:	8b 45 14             	mov    0x14(%ebp),%eax
 8059876:	01 c8                	add    %ecx,%eax
 8059878:	8b 00                	mov    (%eax),%eax
 805987a:	89 02                	mov    %eax,(%edx)
 805987c:	83 45 f4 01          	addl   $0x1,-0xc(%ebp)
 8059880:	8b 45 f4             	mov    -0xc(%ebp),%eax
 8059883:	3b 45 f0             	cmp    -0x10(%ebp),%eax
 8059886:	72 c4                	jb     805984c <vbe_video_output_t::blit(g_rectangle, g_rectangle, unsigned int*)+0x62>
 8059888:	8b 45 08             	mov    0x8(%ebp),%eax
 805988b:	0f b7 40 0a          	movzwl 0xa(%eax),%eax
 805988f:	0f b7 c0             	movzwl %ax,%eax
 8059892:	01 45 fc             	add    %eax,-0x4(%ebp)
 8059895:	83 45 f8 01          	addl   $0x1,-0x8(%ebp)
 8059899:	8b 45 f8             	mov    -0x8(%ebp),%eax
 805989c:	3b 45 ec             	cmp    -0x14(%ebp),%eax
 805989f:	72 9b                	jb     805983c <vbe_video_output_t::blit(g_rectangle, g_rectangle, unsigned int*)+0x52>
 80598a1:	c9                   	leave  
 80598a2:	c3                   	ret    
 80598a3:	90                   	nop
With 24 bits, its:

Code: Select all

080597ea <vbe_video_output_t::blit(g_rectangle, g_rectangle, unsigned int*)>:
 80597ea:	55                   	push   %ebp
 80597eb:	89 e5                	mov    %esp,%ebp
 80597ed:	83 ec 20             	sub    $0x20,%esp
 80597f0:	8b 45 0c             	mov    0xc(%ebp),%eax
 80597f3:	8b 50 04             	mov    0x4(%eax),%edx
 80597f6:	8b 45 08             	mov    0x8(%ebp),%eax
 80597f9:	0f b7 40 0a          	movzwl 0xa(%eax),%eax
 80597fd:	0f b7 c0             	movzwl %ax,%eax
 8059800:	0f af c2             	imul   %edx,%eax
 8059803:	89 c2                	mov    %eax,%edx
 8059805:	8b 45 08             	mov    0x8(%ebp),%eax
 8059808:	8b 40 0c             	mov    0xc(%eax),%eax
 805980b:	01 d0                	add    %edx,%eax
 805980d:	89 45 fc             	mov    %eax,-0x4(%ebp)
 8059810:	8b 45 0c             	mov    0xc(%ebp),%eax
 8059813:	8b 10                	mov    (%eax),%edx
 8059815:	8b 45 0c             	mov    0xc(%ebp),%eax
 8059818:	8b 40 08             	mov    0x8(%eax),%eax
 805981b:	01 d0                	add    %edx,%eax
 805981d:	89 45 f0             	mov    %eax,-0x10(%ebp)
 8059820:	8b 45 0c             	mov    0xc(%ebp),%eax
 8059823:	8b 50 04             	mov    0x4(%eax),%edx
 8059826:	8b 45 0c             	mov    0xc(%ebp),%eax
 8059829:	8b 40 0c             	mov    0xc(%eax),%eax
 805982c:	01 d0                	add    %edx,%eax
 805982e:	89 45 ec             	mov    %eax,-0x14(%ebp)
 8059831:	8b 45 0c             	mov    0xc(%ebp),%eax
 8059834:	8b 40 04             	mov    0x4(%eax),%eax
 8059837:	89 45 f8             	mov    %eax,-0x8(%ebp)
 805983a:	e9 90 00 00 00       	jmp    80598cf <vbe_video_output_t::blit(g_rectangle, g_rectangle, unsigned int*)+0xe5>
 805983f:	8b 45 0c             	mov    0xc(%ebp),%eax
 8059842:	8b 00                	mov    (%eax),%eax
 8059844:	89 45 f4             	mov    %eax,-0xc(%ebp)
 8059847:	eb 6d                	jmp    80598b6 <vbe_video_output_t::blit(g_rectangle, g_rectangle, unsigned int*)+0xcc>
 8059849:	8b 45 10             	mov    0x10(%ebp),%eax
 805984c:	8b 40 08             	mov    0x8(%eax),%eax
 805984f:	0f af 45 f8          	imul   -0x8(%ebp),%eax
 8059853:	89 c2                	mov    %eax,%edx
 8059855:	8b 45 f4             	mov    -0xc(%ebp),%eax
 8059858:	01 d0                	add    %edx,%eax
 805985a:	8d 14 85 00 00 00 00 	lea    0x0(,%eax,4),%edx
 8059861:	8b 45 14             	mov    0x14(%ebp),%eax
 8059864:	01 d0                	add    %edx,%eax
 8059866:	8b 00                	mov    (%eax),%eax
 8059868:	89 45 e8             	mov    %eax,-0x18(%ebp)
 805986b:	8b 55 f4             	mov    -0xc(%ebp),%edx
 805986e:	89 d0                	mov    %edx,%eax
 8059870:	01 c0                	add    %eax,%eax
 8059872:	01 d0                	add    %edx,%eax
 8059874:	89 c2                	mov    %eax,%edx
 8059876:	8b 45 fc             	mov    -0x4(%ebp),%eax
 8059879:	01 d0                	add    %edx,%eax
 805987b:	8b 55 e8             	mov    -0x18(%ebp),%edx
 805987e:	88 10                	mov    %dl,(%eax)
 8059880:	8b 55 f4             	mov    -0xc(%ebp),%edx
 8059883:	89 d0                	mov    %edx,%eax
 8059885:	01 c0                	add    %eax,%eax
 8059887:	01 d0                	add    %edx,%eax
 8059889:	8d 50 01             	lea    0x1(%eax),%edx
 805988c:	8b 45 fc             	mov    -0x4(%ebp),%eax
 805988f:	01 d0                	add    %edx,%eax
 8059891:	8b 55 e8             	mov    -0x18(%ebp),%edx
 8059894:	c1 ea 08             	shr    $0x8,%edx
 8059897:	88 10                	mov    %dl,(%eax)
 8059899:	8b 55 f4             	mov    -0xc(%ebp),%edx
 805989c:	89 d0                	mov    %edx,%eax
 805989e:	01 c0                	add    %eax,%eax
 80598a0:	01 d0                	add    %edx,%eax
 80598a2:	8d 50 02             	lea    0x2(%eax),%edx
 80598a5:	8b 45 fc             	mov    -0x4(%ebp),%eax
 80598a8:	01 d0                	add    %edx,%eax
 80598aa:	8b 55 e8             	mov    -0x18(%ebp),%edx
 80598ad:	c1 ea 10             	shr    $0x10,%edx
 80598b0:	88 10                	mov    %dl,(%eax)
 80598b2:	83 45 f4 01          	addl   $0x1,-0xc(%ebp)
 80598b6:	8b 45 f4             	mov    -0xc(%ebp),%eax
 80598b9:	3b 45 f0             	cmp    -0x10(%ebp),%eax
 80598bc:	72 8b                	jb     8059849 <vbe_video_output_t::blit(g_rectangle, g_rectangle, unsigned int*)+0x5f>
 80598be:	8b 45 08             	mov    0x8(%ebp),%eax
 80598c1:	0f b7 40 0a          	movzwl 0xa(%eax),%eax
 80598c5:	0f b7 c0             	movzwl %ax,%eax
 80598c8:	01 45 fc             	add    %eax,-0x4(%ebp)
 80598cb:	83 45 f8 01          	addl   $0x1,-0x8(%ebp)
 80598cf:	8b 45 f8             	mov    -0x8(%ebp),%eax
 80598d2:	3b 45 ec             	cmp    -0x14(%ebp),%eax
 80598d5:	0f 82 64 ff ff ff    	jb     805983f <vbe_video_output_t::blit(g_rectangle, g_rectangle, unsigned int*)+0x55>
 80598db:	c9                   	leave  
 80598dc:	c3                   	ret    
 80598dd:	90                   	nop
@gerryg400 nice ideas. For the first point, I already blit everything to a "screen buffer", of which only the portions that changed are blitted out to the video output. I'll implement point two and see how it impacts performance, I think that could make a big difference.

Thanks for your suggestions! :)

Greets

Re: Getting performant VESA video output

Posted: Wed Oct 07, 2015 4:16 am
by Brendan
Hi,
max wrote:I compiled it twice for simplicity, when writing to 32bits its:
Did you enable optimisations when this was compiled (e.g. "-O2" or "-O3")?


Cheers,

Brendan

Re: Getting performant VESA video output

Posted: Wed Oct 07, 2015 4:45 am
by max
Brendan wrote:Did you enable optimisations when this was compiled (e.g. "-O2" or "-O3")?
I didn't do so, explicitly :oops: with optimizations it's slightly faster, maybe a half ms.

Re: Getting performant VESA video output

Posted: Wed Oct 07, 2015 10:25 am
by Ready4Dis
Why are you blitting like that to video memory? You should only blit to a back buffer, then copy the entire image at once (or the section that changed at one time). You should be doing a memcpy of sorts instead of copying one at a time like you are. The whole point of a LFB was so you can write everything at once instead of little sections.

That being said, you are only going to get so fast with an emulator/vm and non hardware accelerated drawing.

//Optimized 32-bit code

Code: Select all

void vbe_video_output_t::blit32(g_rectangle invalid, g_rectangle sourceSize, g_color_argb* source)
{
	//Precalculate everything
	uint8_t* position = ((uint8_t*) video_mode_information.lfb) + (invalid.y * video_mode_information.bpsl) + (invalid.x * 4);
	uint8_t* p_source = g_color_argb;
	uint32_t source_stride = sourceSize.width * 4;	//Source is always 4-bits per pixel??
	uint32_t invalid_stride = invalid.width * 4;	//4 bits per pixel

	//Now render each line, simple memcpy and two add's
	for (int y = 0; y < invalid.height; y++)
	{
		memcpy(position, p_source, invalid_stride);
		p_source += source_stride;
		position += video_mode_information.bpsl;
	}
}
Of course you can get into some better optimizations, but it's not to bad. for 24-bit to 32-bit, why are you converting like this? Why not store your sprite data in the format you need it? Convert during load instead of during each time you render. If you change the * 4's into * video_mode_information.bpp and use the same target and destination size, this works for any bit depth (8, 15, 16, 24, 32). I don't know why your data isn't in the right format before sending it to through the PCI bus to your VGA adapter! Sending data like this is slow even on real hardware.

Re: Getting performant VESA video output

Posted: Wed Oct 07, 2015 12:27 pm
by abcdef4bfd
max wrote:
madanra wrote:How does the performance compare between 24bpp and 32bpp?

In general, you want to be doing large, aligned reads & writes for performance.
Hi,

thanks for your response. Well for 24bpp its about 12-13ms per blit, for 32bpp it's about 9-10ms. The actual writing to the VESA memory is what's so slow. I'm looking for ways to accelerate that process.

Greets
Milliseconds... I need to wait about a sec to fully draw my OS GUI :( And this is on my newest computer, on my old notebook it takes 5-6 secs. All is because of VGA registers.

Re: Getting performant VESA video output

Posted: Wed Oct 07, 2015 5:23 pm
by Brendan
Hi,
max wrote:
Brendan wrote:Did you enable optimisations when this was compiled (e.g. "-O2" or "-O3")?
I didn't do so, explicitly :oops: with optimizations it's slightly faster, maybe a half ms.
Part of the performance problem may be that the compiler isn't optimising the code well (when optimisations are enabled); either due to "less than perfect" compiler, or because the compiler can't legally make those optimisations.

For example, I can almost guarantee that the compiler will use EBP for a mostly useless frame pointer, which prevents it from using EBP to cache a value that's used within a loop, which means using a slower memory access for that value within the loop instead.

The only way to check is to examine a disassembly of the compiler's output and identify things that its optimiser didn't optimise. This is why I asked for a disassembly; and why I'd need a disassembly of the compiler's output when optimisations have been enabled.


Cheers,

Brendan

Re: Getting performant VESA video output

Posted: Thu Oct 08, 2015 1:15 am
by max
Uh. Sorry for wasting your time guys. It turned out that I did my average measuring wrong... and didn't exclude the context switches in between. :mrgreen:

Let's keep this for discussing about UI in general, maybe help others.
Ready4Dis wrote:Why are you blitting like that to video memory? You should only blit to a back buffer, then copy the entire image at once (or the section that changed at one time). You should be doing a memcpy of sorts instead of copying one at a time like you are. The whole point of a LFB was so you can write everything at once instead of little sections.
I do, this is only the very last step of my rendering chain, where the section that changed in the back buffer is converted and blit to the output. I do it like this because the content in the buffer is ARGB and must be converted to be written to the video memory in specific configurations. I think there won't be much difference from memcpy in the 32bpp copying routine.
catnikita225 wrote:Milliseconds... I need to wait about a sec to fully draw my OS GUI :( And this is on my newest computer, on my old notebook it takes 5-6 secs. All is because of VGA registers.
Don't worry. Why because of VGA registers? How are you setting up your video and accessing it?
Brendan wrote:The only way to check is to examine a disassembly of the compiler's output and identify things that its optimiser didn't optimise. This is why I asked for a disassembly; and why I'd need a disassembly of the compiler's output when optimisations have been enabled.
Here's the optimized output:

Code: Select all

08057600 <vbe_video_output_t::blit(g_rectangle, g_rectangle, unsigned int*)>:
 8057600:	55                   	push   %ebp
 8057601:	57                   	push   %edi
 8057602:	56                   	push   %esi
 8057603:	53                   	push   %ebx
 8057604:	83 ec 08             	sub    $0x8,%esp
 8057607:	8b 44 24 1c          	mov    0x1c(%esp),%eax
 805760b:	8b 5c 24 20          	mov    0x20(%esp),%ebx
 805760f:	8b 54 24 20          	mov    0x20(%esp),%edx
 8057613:	8b 6c 24 24          	mov    0x24(%esp),%ebp
 8057617:	0f b7 70 0a          	movzwl 0xa(%eax),%esi
 805761b:	8b 4b 04             	mov    0x4(%ebx),%ecx
 805761e:	89 f3                	mov    %esi,%ebx
 8057620:	89 74 24 04          	mov    %esi,0x4(%esp)
 8057624:	8b 72 08             	mov    0x8(%edx),%esi
 8057627:	0f af d9             	imul   %ecx,%ebx
 805762a:	03 58 0c             	add    0xc(%eax),%ebx
 805762d:	8b 44 24 20          	mov    0x20(%esp),%eax
 8057631:	8b 52 0c             	mov    0xc(%edx),%edx
 8057634:	8b 00                	mov    (%eax),%eax
 8057636:	01 ca                	add    %ecx,%edx
 8057638:	89 14 24             	mov    %edx,(%esp)
 805763b:	01 c6                	add    %eax,%esi
 805763d:	39 ca                	cmp    %ecx,%edx
 805763f:	76 48                	jbe    8057689 <vbe_video_output_t::blit(g_rectangle, g_rectangle, unsigned int*)+0x89>
 8057641:	8b 7c 24 28          	mov    0x28(%esp),%edi
 8057645:	8d 74 26 00          	lea    0x0(%esi,%eiz,1),%esi
 8057649:	8d bc 27 00 00 00 00 	lea    0x0(%edi,%eiz,1),%edi
 8057650:	39 c6                	cmp    %eax,%esi
 8057652:	76 21                	jbe    8057675 <vbe_video_output_t::blit(g_rectangle, g_rectangle, unsigned int*)+0x75>
 8057654:	8d b6 00 00 00 00    	lea    0x0(%esi),%esi
 805765a:	8d bf 00 00 00 00    	lea    0x0(%edi),%edi
 8057660:	8b 55 08             	mov    0x8(%ebp),%edx
 8057663:	0f af d1             	imul   %ecx,%edx
 8057666:	01 c2                	add    %eax,%edx
 8057668:	8b 14 97             	mov    (%edi,%edx,4),%edx
 805766b:	89 14 83             	mov    %edx,(%ebx,%eax,4)
 805766e:	83 c0 01             	add    $0x1,%eax
 8057671:	39 f0                	cmp    %esi,%eax
 8057673:	75 eb                	jne    8057660 <vbe_video_output_t::blit(g_rectangle, g_rectangle, unsigned int*)+0x60>
 8057675:	03 5c 24 04          	add    0x4(%esp),%ebx
 8057679:	83 c1 01             	add    $0x1,%ecx
 805767c:	3b 0c 24             	cmp    (%esp),%ecx
 805767f:	74 08                	je     8057689 <vbe_video_output_t::blit(g_rectangle, g_rectangle, unsigned int*)+0x89>
 8057681:	8b 44 24 20          	mov    0x20(%esp),%eax
 8057685:	8b 00                	mov    (%eax),%eax
 8057687:	eb c7                	jmp    8057650 <vbe_video_output_t::blit(g_rectangle, g_rectangle, unsigned int*)+0x50>
 8057689:	83 c4 08             	add    $0x8,%esp
 805768c:	5b                   	pop    %ebx
 805768d:	5e                   	pop    %esi
 805768e:	5f                   	pop    %edi
 805768f:	5d                   	pop    %ebp
 8057690:	c3                   	ret    
 8057691:	90                   	nop
 8057692:	8d b4 26 00 00 00 00 	lea    0x0(%esi,%eiz,1),%esi
 8057699:	8d bc 27 00 00 00 00 	lea    0x0(%edi,%eiz,1),%edi

Re: Getting performant VESA video output

Posted: Thu Oct 08, 2015 2:02 am
by alexfru
catnikita255 wrote:Milliseconds... I need to wait about a sec to fully draw my OS GUI :( And this is on my newest computer, on my old notebook it takes 5-6 secs. All is because of VGA registers.
Nope. It's not VGA registers. You have inefficient code and you're running into a speed bump of VGA memory. If you just solid fill the entire screen in a VGA mode (I'm assuming we're talking about 640x480x16 colors) with only switching color planes 4 times per horizontal scanline or per frame, you'll not get more than ~30 FPS. I don't know exactly why, but the hardware limits the speed of writing in this mode (maybe in all legacy modes with color planes). The only workaround here is to rarely switch planes and never redraw anything and draw simple things in the first place, of course.

Re: Getting performant VESA video output

Posted: Thu Oct 08, 2015 3:53 am
by Brendan
Hi,
max wrote:
Brendan wrote:The only way to check is to examine a disassembly of the compiler's output and identify things that its optimiser didn't optimise. This is why I asked for a disassembly; and why I'd need a disassembly of the compiler's output when optimisations have been enabled.
Here's the optimized output:
Are you sure this has been optimised?

For a simple example, it's fairly common to transform something like this:

Code: Select all

         for (int x = invalid.x; x < right; x++) {
            position4[x] = source[y * sourceSize.width + x];
         }
Into something more like this:

Code: Select all

         temp1 = y * sourceSize.width;
         for (int x = invalid.x; x < right; x++) {
            position4[x] = source[temp1 + x];
         }
Which completely removes a (relatively expensive) multiplication from the inner loop.

The disassembly shows no real sign of any optimisations like this. For example, here is the inner loop:

Code: Select all

 8057660:	8b 55 08             	mov    0x8(%ebp),%edx
 8057663:	0f af d1             	imul   %ecx,%edx
 8057666:	01 c2                	add    %eax,%edx
 8057668:	8b 14 97             	mov    (%edi,%edx,4),%edx
 805766b:	89 14 83             	mov    %edx,(%ebx,%eax,4)
 805766e:	83 c0 01             	add    $0x1,%eax
 8057671:	39 f0                	cmp    %esi,%eax
 8057673:	75 eb                	jne    8057660 <vbe_video_output_t::blit(g_rectangle, g_rectangle, unsigned int*)+0x60>
And that "imul %ecx,%edx" is the multiplication that should not be in the inner loop at all.


Cheers,

Brendan

Re: Getting performant VESA video output

Posted: Thu Oct 08, 2015 4:08 am
by Ready4Dis
max wrote:I do, this is only the very last step of my rendering chain, where the section that changed in the back buffer is converted and blit to the output. I do it like this because the content in the buffer is ARGB and must be converted to be written to the video memory in specific configurations. I think there won't be much difference from memcpy in the 32bpp copying routine.
I promise you, copying a buffer across the PCI bus is MUCH faster when you do it in one go rather than copying a little bit at a time. It really needs to be a one of the STO commands (STOS/STOSB/STOSW/STOSD/STOSQ) in order to transfer anything near efficiently. I still don't understand why your final buffer bit depth doesn't match the screen bit depth and if you're really worried about performance start writing in assembly or find a better algorithm. My question though was, WHY is the content of the buffer ARGB? Are you actually using the alpha channel? If you are, you can still easily use a 24-bit color buffer with an 8-bit alpha buffer so you only have to copy the 24-bit buffer at the end. Why not convert your data to match the output format, especially if you're only using 24/32. 15/16-bit can get kind of interesting if you're trying to do some advanced rendering.

Did you try to benchmark your optimized version with the memcpy version? You say you think there won't be much difference, but how do you know? Drop the routine in and check it out, I bet it's faster than you think. Heck, it only has one loop instead of two! A lot less math going on (took the multiplications out of the inner loop completely) and reduced it to two additions plus the increment for the loop.

Even for a 32x32 texture update.

My loop is called 32 times with 64 additions and a memory copy.

Your loop is called 1024 times with a multiplication + addition in each iteration, not to mention an addition 32 times for the outter loop and a temporary variable being created (!??! why is this inside the loop?? Even if it's optimized away, it's bad programming habit for anything you are wanting to be fast). Now if your entire screen needs updating, it's a much different story. Even at 640x480... mine has 480 iterations with two additions, or 960 additions.
Your version would be 307200 multiplications + additions in the inner loop, and 480 additions for the outer loop. That plus the fact that your sending small chunks through the PCI bus makes a very large difference!