如何修复我的双缓冲区不绘制到屏幕



我在一个小型操作系统上工作,遇到了一些屏幕撕裂的问题,所以我正在使用双缓冲来解决这个问题。我刚刚遇到一个问题,在修改了渲染方法后,现在没有任何东西可以打印到屏幕上。列出了一些可能会成为问题的事情,尽管我真的不确定:

为了使void dstsrcmemcpy函数中的u8 ds兼容,我做了很多粗略的工作
  • 我实现了(或者应该说是从外部源复制的(双缓冲位,可能有一些东西我忘记了转换到新的、更好的系统
  • 打字错误(不太可能(
  • 这是我的C++代码:

    typedef unsigned char uint8_t;
    typedef unsigned char u8;
    typedef unsigned short uint16_t;
    typedef unsigned int u32;
    typedef u32 size_t;
    #define SCREEN_WIDTH 320
    #define SCREEN_HEIGHT 200
    #define SCREEN_SIZE (SCREEN_WIDTH * SCREEN_HEIGHT)
    #define FPS 30
    #define PIT_HERTZ 1193131.666
    #define CLOCK_HIT (int)(PIT_HERTZ/FPS)
    static uint8_t *BUFFER = (uint8_t *) 0xA0000;
    // double buffers
    uint8_t _sbuffers[2][SCREEN_SIZE];
    uint8_t _sback = 0;
    #define CURRENT (_sbuffers[_sback])
    #define SWAP() (_sback = 1 - _sback)
    #define screen_buffer() (_sbuffers[_sback])
    #define screen_set(_p, _x, _y)
    (_sbuffers[_sback][((_y) * SCREEN_WIDTH + (_x))]=(_p))
    const unsigned char font[128-32][8] = {
    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},   // U+0020 (space)
    *deleted to help with length and readability of code...*
    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}    // U+007F
    };
    static inline void *memcpy(void *dst, const void *src, size_t n) {
    u8 *d = (u8*)(&dst);
    const u8 *s = (u8*)(&src);
    while (n-- > 0) {
    *d++ = *s++;
    }
    return d;
    }
    void screen_swap() {
    memcpy(BUFFER, &CURRENT, SCREEN_SIZE);
    SWAP();
    }
    static inline void outb(uint16_t port, uint8_t val)
    {
    asm volatile ( "outb %0, %1" : : "a"(val), "Nd"(port) );
    }
    static inline uint8_t inb(uint16_t port)
    {
    uint8_t ret;
    asm volatile ( "inb %1, %0"
    : "=a"(ret)
    : "Nd"(port) );
    return ret;
    }
    unsigned read_pit(void) {
    unsigned count = 0;
    
    // al = channel in bits 6 and 7, remaining bits clear
    outb(0x43,0b0000000);
    
    count = inb(0x40);          // Low byte
    count |= inb(0x40)<<8;      // High byte
    
    return count;
    }
    
    void draw_char(char c, int x, int y, unsigned char color)
    {
    const unsigned char *glyph = font[(int)c-32];
    
    for(int cy=0;cy<8;cy++){
    for(int cx=0;cx<8;cx++){
    if(((int)glyph[cy]&(1<<cx))==(1<<cx)){
    screen_set(color,x+cx,y+cy);
    }
    } 
    }
    }
    void draw_string(const char * s, int x, int y, unsigned char color) {
    int i = 0;
    while(s[i] != false) {
    draw_char(s[i],x+(i*8),y,color);
    i++;
    }
    }
    void draw_rect(int pos_x, int pos_y, int w, int h, unsigned char color) {
    for(int y = 0; y<h; y++) {
    for(int x = 0; x<w; x++) {
    screen_set(color,x+pos_x,y+pos_y);
    }
    }
    }
    static void render() {
    //draw_rect(0,0,SCREEN_WIDTH,SCREEN_HEIGHT,0);
    draw_string("Hello, reader. This is written text.", 10, 18, 15);
    draw_string("If this is displayed, my code works.", 10, 10, 15);
    }
    extern "C" void main(){
    int clock = 0;
    while(true) {
    clock++;
    if(read_pit()!= 0 && clock == CLOCK_HIT) {
    clock = 0;
    render();
    screen_swap();
    }
    }
    return;
    }
    

    我做了很多粗略的事情来让void dst和src与memcpy函数中的u8 d和s兼容

    是的。这通常表明你做错了什么。让我们看看:

    static inline void *memcpy(void *dst, const void *src, size_t n) {
    u8 *d = (u8*)(&dst);
    const u8 *s = (const u8*)(&src);
    while (n-- > 0) {
    *d++ = *s++;
    }
    return d;
    }
    

    在这里,您获取指针变量的地址(而不是指针值本身(。这是一个void**,然后将其转换为u8*。当您取消引用它时,您将查看保存该指针的内存的各个字节。这显然是不正确的。

    另一件奇怪的事情是,您的函数返回d+n的值。这不是标准memcpy函数的工作方式。它将始终返回dst。所以,如果你真的想拥有一个具有标准行为的函数,可以考虑这样做。

    这是你应该做的:

    static inline void *memcpy(void *dst, const void *src, size_t n)
    {
    u8 *d = (u8*)dst;
    const u8 *s = (const u8*)src;
    while (n-- > 0) {
    *d++ = *s++;
    }
    return dst;
    }
    

    你也在奇怪地调用它:

    memcpy(BUFFER, &CURRENT, SCREEN_SIZE);
    

    现在,从技术上讲,&CURRENT可以正常工作,因为CURRENT宏指向一个数组。但是,应该避免获取数组的地址。让编译器将数组转换为指针:

    memcpy(BUFFER, CURRENT, SCREEN_SIZE);
    

    这里有一个替代实现,可以避免每次循环递减n

    static inline void *memcpy(void *dst, const void *src, size_t n)
    {
    u8 *d = (u8*)dst;
    const u8 *s = (const u8*)src;
    const u8 *s_end = s + n;
    while (s != s_end) {
    *d++ = *s++;
    }
    return dst;
    }
    

    如果您使用的是C编译器,也可以考虑添加restrict关键字,因为srcdst不重叠。

    最新更新