通用帧缓冲区的当前方法?
Current methods for generic frame buffer?
作为 OS 的一部分,我一直在研究通用帧缓冲区实现。明确地说,我是说没有 Linux 内核或 Windows 内核或设备驱动程序可用。
我的帧缓冲区运行良好(更新下面的代码),但我希望对其进行改进,而不是沿着为每个制造商创建单独的驱动程序的路线走下去。
TL;DR
我目前正在使用 SSE2 和 XMM 寄存器来更新视频内存。我开始沿着 DMA 路径冒险,但后来意识到我是基于我 30 年前的知识。今天使用 DMA 感觉不对;更好地优化此更新过程的下一步是什么?
const uint32_t h_res = gop->Mode->Info->HorizontalResolution;
const uint32_t v_res = gop->Mode->Info->VerticalResolution;
EFI_GRAPHICS_OUTPUT_BLT_PIXEL *framebuffer = (void *)(gop->Mode->FrameBufferBase);
volatile unsigned int ops = (h_res * v_res)/16;
__asm__ __volatile__(
"1:"
"PREFETCHNTA 128(%%rax);"
"MOVDQA (%%rax), %%xmm0;"
"MOVDQA 16(%%rax), %%xmm1;"
"MOVDQA 32(%%rax), %%xmm2;"
"MOVDQA 48(%%rax), %%xmm3;"
"MOVDQA 64(%%rax), %%xmm4;"
"MOVDQA 80(%%rax), %%xmm5;"
"MOVDQA 96(%%rax), %%xmm6;"
"MOVDQA 112(%%rax), %%xmm7;"
"MOVNTDQ %%xmm0, (%%rbx);"
"MOVNTDQ %%xmm1, 16(%%rbx);"
"MOVNTDQ %%xmm2, 32(%%rbx);"
"MOVNTDQ %%xmm3, 48(%%rbx);"
"MOVNTDQ %%xmm4, 64(%%rbx);"
"MOVNTDQ %%xmm5, 80(%%rbx);"
"MOVNTDQ %%xmm6, 96(%%rbx);"
"MOVNTDQ %%xmm7, 112(%%rbx);"
"ADDQ 8, %%rax;"
"ADDQ 8, %%rbx;"
"DEC %%rcx;"
"JNZ 1b;"
: "+a"(canvas), "+b"(framebuffer)
: "c"(ops)
: "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7", "memory"
);
关于复制的字节数错误(来自评论)。
我建议以 block-size 不可知的方式编写代码:
const uint32_t h_res = gop->Mode->Info->HorizontalResolution;
const uint32_t v_res = gop->Mode->Info->VerticalResolution;
EFI_GRAPHICS_OUTPUT_BLT_PIXEL *framebuffer = (void *)(gop->Mode->FrameBufferBase);
EFI_GRAPHICS_OUTPUT_BLT_PIXEL *end_of_frame = framebuffer + (h_res * v_res);
// "ops" removed
或者如果你不想自己计算,也有这个FrameBufferSize
提供:
UINT8* end_of_frame = ((UINT8*)framebuffer) + gop->Mode->FrameBufferSize;
... 在 asm 中,用 end_of_frame
加载 rcx
而 ...
...
"ADDQ 8, %%rbx;"
"ADDQ 8, %%rax;"
"CMP %%rcx, %%rbx;"
"JB 1b;"
...
(我不习惯内联和gas语法,所以在使用前仔细检查)
有了这个,您以后可以随意更改块代码(如果您将进一步试验),终止比较不再依赖于块大小。即使总帧长度不能被块大小整除,它实际上仍然存在,因此它会在最后一个块被写入(超过帧的边界)后终止。
作为 OS 的一部分,我一直在研究通用帧缓冲区实现。明确地说,我是说没有 Linux 内核或 Windows 内核或设备驱动程序可用。
我的帧缓冲区运行良好(更新下面的代码),但我希望对其进行改进,而不是沿着为每个制造商创建单独的驱动程序的路线走下去。
TL;DR
我目前正在使用 SSE2 和 XMM 寄存器来更新视频内存。我开始沿着 DMA 路径冒险,但后来意识到我是基于我 30 年前的知识。今天使用 DMA 感觉不对;更好地优化此更新过程的下一步是什么?
const uint32_t h_res = gop->Mode->Info->HorizontalResolution;
const uint32_t v_res = gop->Mode->Info->VerticalResolution;
EFI_GRAPHICS_OUTPUT_BLT_PIXEL *framebuffer = (void *)(gop->Mode->FrameBufferBase);
volatile unsigned int ops = (h_res * v_res)/16;
__asm__ __volatile__(
"1:"
"PREFETCHNTA 128(%%rax);"
"MOVDQA (%%rax), %%xmm0;"
"MOVDQA 16(%%rax), %%xmm1;"
"MOVDQA 32(%%rax), %%xmm2;"
"MOVDQA 48(%%rax), %%xmm3;"
"MOVDQA 64(%%rax), %%xmm4;"
"MOVDQA 80(%%rax), %%xmm5;"
"MOVDQA 96(%%rax), %%xmm6;"
"MOVDQA 112(%%rax), %%xmm7;"
"MOVNTDQ %%xmm0, (%%rbx);"
"MOVNTDQ %%xmm1, 16(%%rbx);"
"MOVNTDQ %%xmm2, 32(%%rbx);"
"MOVNTDQ %%xmm3, 48(%%rbx);"
"MOVNTDQ %%xmm4, 64(%%rbx);"
"MOVNTDQ %%xmm5, 80(%%rbx);"
"MOVNTDQ %%xmm6, 96(%%rbx);"
"MOVNTDQ %%xmm7, 112(%%rbx);"
"ADDQ 8, %%rax;"
"ADDQ 8, %%rbx;"
"DEC %%rcx;"
"JNZ 1b;"
: "+a"(canvas), "+b"(framebuffer)
: "c"(ops)
: "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7", "memory"
);
关于复制的字节数错误(来自评论)。
我建议以 block-size 不可知的方式编写代码:
const uint32_t h_res = gop->Mode->Info->HorizontalResolution;
const uint32_t v_res = gop->Mode->Info->VerticalResolution;
EFI_GRAPHICS_OUTPUT_BLT_PIXEL *framebuffer = (void *)(gop->Mode->FrameBufferBase);
EFI_GRAPHICS_OUTPUT_BLT_PIXEL *end_of_frame = framebuffer + (h_res * v_res);
// "ops" removed
或者如果你不想自己计算,也有这个FrameBufferSize
提供:
UINT8* end_of_frame = ((UINT8*)framebuffer) + gop->Mode->FrameBufferSize;
... 在 asm 中,用 end_of_frame
加载 rcx
而 ...
...
"ADDQ 8, %%rbx;"
"ADDQ 8, %%rax;"
"CMP %%rcx, %%rbx;"
"JB 1b;"
...
(我不习惯内联和gas语法,所以在使用前仔细检查)
有了这个,您以后可以随意更改块代码(如果您将进一步试验),终止比较不再依赖于块大小。即使总帧长度不能被块大小整除,它实际上仍然存在,因此它会在最后一个块被写入(超过帧的边界)后终止。