cframebufferosdev

C (OSDev) - How could I shift the contents of a 32-bit framebuffer upwards efficiently?


I'm working on writing a hobby operating system. Currently a large struggle that I'm having is attempting to scroll the framebuffer upwards. It's simply a 32-bit linear framebuffer. I have access to a few tools that could be helpful:

speaking of which, my previous attempt:

for (uint64_t i = 0; i != atoi(numLines); i++) {
    for (uint64_t j = 0; j != bootboot.fb_width; j++) {
        for (uint64_t k = 1; k != bootboot.fb_size; k++) {
            ((uint32_t *)&fb)[k - 1] = ((uint32_t *)&fb)[k];
        }
    }
}

A few things to note about the above:

Any and all help would be appreciated.


Solution

  • If I read the code correctly, what's happening with the triple nested loops is:

    1. For every line to scroll,
    2. For every pixel that the framebuffer is wide,
    3. For every pixel in the entire framebuffer,
    4. Move that pixel backwards by one.

    Essentially you're moving each pixel one pixel distance at a time, so it's no wonder it takes so long to scroll the framebuffer. The total number of pixel moves is (numLines * fb_width * fb_size), so if your framebuffer is 1024x768, that's 5*1024*1024*768 moves, which is 4,026,531,840 moves. That's basically 5000 times the amount of work required.

    Instead, you'll want to loop over the framebuffer only once, calculate that pixel's start and its end pointer, and only do the move once. Or you can calculate the source, destination, and size of the move once and then use memmove. Here's my attempt at this (with excessive comments):

     // Convert string to integer
    uint32_t numLinesInt = atoi(numLines);
     // The destination of the move is just the top of the framebuffer
    uint32_t* destination = (uint32_t*)&fb;
     // Start the move from the top of the framebuffer plus however
     // many lines we want to scroll.
    uint32_t* source = (uint32_t*)&fb +
        (numLinesInt * bootboot.fb_width);
     // The total number of pixels to move is the size of the
     // framebuffer minus the amount of lines we want to scroll.
    uint32_t pixelSize = (bootboot.fb_height - numLinesInt)
        * bootboot.fb_width;
     // The total number of bytes is that times the size of one pixel.
    uint32_t byteSize = pixelSize * sizeof(uint32_t);
     // Do the move
    memmove(destination, source, byteSize);
    

    I haven't tested this, and I'm making a number of assumptions about how your framebuffer is laid out, so please make sure it works before using it. :)

    (P.S. Also, if you put atoi(numLines) inside the end condition of the for loop, atoi will be called every time through the loop, instead of once at the beginning like you intended.)