通用帧缓冲器的当前方法?

时间:2017-01-19 12:18:41

标签: assembly graphics operating-system framebuffer

我一直致力于将通用帧缓冲器实现作为操作系统的一部分。为了清楚起见,我说没有可用的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 $128, %%rax;"
        "ADDQ $128, %%rbx;"
        "DEC %%rcx;"
        "JNZ 1b;"
        : "+a"(canvas), "+b"(framebuffer)
        : "c"(ops)
        : "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7", "memory"
    );

1 个答案:

答案 0 :(得分:1)

关于复制的错误字节数(来自评论)。

我建议以块大小不可知的方式编写代码:

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中,使用rcx加载end_of_frame而不是......

    ...
    "ADDQ $128, %%rbx;"
    "ADDQ $128, %%rax;"
    "CMP %%rcx, %%rbx;"
    "JB 1b;"
    ...

(我不习惯使用内联和气体语法,因此请在使用前仔细检查)

有了这个,您可以稍后以任何方式更改块代码(如果您将进一步试验),终止比较不再依赖于块大小。即使总帧长度不能被块大小整除,它也会存活下来,因此它会在写入最后一个块后(在帧的边界上)终止。