I just logged into the forum for the first time in years and saw I had a message about this - I'm really struggling to recall the details of how this thread went down the rabbit hole of MTRR configuration, and if memory serves the final answer is that it all had very little to do with this - I could have sworn I wrote a post about it but can't find it now.
What I can say, the final performance results were valid, I was able to run software rendering bare-metal 20% faster than I could on Windows using OpenGL and a texture, or going via GDI and just copying a memory buffer. At the end of the day, regardless of approach a buffer of 1920x1080x32bit's has to be transferred to the GPU, whether that's a frame buffer or texture data.
The mileage on this may vary these days, as a lot of integrated GPUs are now bridged with things like Nvidia Optimus which makes the out-of-the box setup on the GOP / GPU worse it appears.
I landed up trying things on a range of machines, and I believe the final analysis was this:
1. You start with UEFI and GOP (1920x1080x32). This buffer is possibly marked as uncached via MTRR.
2. At this point, on pretty much every machine the GOP LFB is slow as mud .. 5fps is about the limit.
3. On a machine I had where the GPU was integrated and there was no other discrete one, the LFB was UC. I mapped it as write combining and there was a huge jump in performance across the board (I actually tried this right now on a new laptop with nvidia optimus + igpu) where I only get about 30fps, an older dell that has only an nvidia gpu gets about 1000fps, if you're only doing a rep movsq from a WB (regular mem) buffer to the LFB (WC).
4. The next step I took was looking at GPU specific PCIe config - and what I found was this, if you check your GPU running under Windows and doing something, you'll find the link speed is running at 8 GT/s, if you read the link speed info from pci space whilst in a UEFI shell for example you'll see the GPU boots up / defaults to 2.5 GT/s. Through a lot digging into what info I could find on Nvidia register maps, I was eventually able to find the configuraiton register in one of the BARs that lets you control this (it's not settable from PCIe config space, you can only read the link speed). That was the final piece of the puzzle - for discrete GPUs or any that are wired over PCIe, getting the link speed up was the key, for an igpu it seemed to depend on how it was wired up, if it ran of edram the link speed didn't come into play.
Code: Select all
;NVidia PCIe max speed - By default Nvidia GPUs run at 2.5Gt/s when they're capable of 8.0Gt/s
xor r12,r12
mov rdi,(PCIDevice PTR [rsi]).base
mov r12d,(PCIHeader0 PTR [rdi]).BAR0
and r12d,0xfffffff0
mov eax,[r12+0x8c1c0]
and eax,0x300000
mov eax,[r12+0x8c040]
and eax,0xfff3ffff
or eax,0
mov [r12+0x8c040],eax
mov eax,[r12+0x8c040]
and eax,0xfffffffe
or eax,1
mov [r12+0x8c040],eax
- PS: I have no idea why I left an OR eax, 0 in
this is the Nvidia specific link speed configuration - we'd need to replicate this for AMD and Discrete Intel GPUs too - but with this engaged, you can outperform mainstream OS software rendering performance.