OSDev.org
https://forum.osdev.org/

Double Buffering problems
https://forum.osdev.org/viewtopic.php?f=1&t=31385
Page 1 of 1

Author:  ComputerFido [ Fri Feb 24, 2017 4:37 am ]
Post subject:  Double Buffering problems

I have been running into some really weird problems when i tried implementing Double Buffering in my graphics driver in my operating system. When i don't use the double buffering my functions work fine. When i do however, if I use malloc to allocate space nothing happens and the screen is black but when i don't it's really weird and it draws my first yellow 200x200 rectangle, but it wont draw anything else and there is an exception (VirtualBox won't tell me much else).
Here is my graphics code:
Code:
namespace graphics{
   vesa_mode_info_t *modeInfo;
   uint32_t vram = 0;

   unsigned char* dblBuffer;
   unsigned char* screen;
   bool initialized = false;

   vesa_mode_info_t * initGfx(){
      if(!initialized){
         modeInfo = EnterGraphicsMode();
         vram = modeInfo->physbase;
         //if(vram == 0)
         //   panic("ERR_GFX_MODE_FAILED", "Error whilst setting graphics mode.",false);

         screen = (unsigned char*)vram;
         //dblBuffer = (unsigned char*)malloc(modeInfo->width*modeInfo->height*modeInfo->bpp/8);

         UpdateScreen();

         initialized = true;
      }

      return modeInfo;
   }

   void putpixel(int x,int y, uint8_t r, uint8_t g, uint8_t b) {
      putpixel(x,y,(r << 16) + (g << 8) + b);
   }

   /* Using Double Buffer
       void putpixel(int x,int y, uint32_t colour) {
      unsigned where = y * modeInfo->pitch + (x * (modeInfo->bpp/8));
      dblBuffer[where] = colour & 255;              // BLUE
      dblBuffer[where + 1] = (colour >> 8) & 255;   // GREEN
      dblBuffer[where + 2] = (colour >> 16) & 255;  // RED
   }

   void fillrect(int x, int y, int w, int h, uint32_t colour) {
      int bpp = modeInfo->bpp;
      int pitch = modeInfo->pitch;
      uint32_t where = 0;
      for(int i=0;i<h;i++){
         for(int j=0;j<w;j++){
            where = (y+i) * pitch + ((x+j) * (bpp/8));
            dblBuffer[where] = colour & 255;             // BLUE
            dblBuffer[where + 1] = (colour >> 8) & 255;  // GREEN
            dblBuffer[where + 2] = (colour >> 16) & 255; // RED
         }
      }
   }*/

        /* Without Double Buffer*/
   void putpixel(int x,int y, uint32_t colour) {
      unsigned where = y * modeInfo->pitch + (x * (modeInfo->bpp/8));
      screen[where] = colour & 255;              // BLUE
      screen[where + 1] = (colour >> 8) & 255;   // GREEN
      screen[where + 2] = (colour >> 16) & 255;  // RED
   }

   void fillrect(int x, int y, int w, int h, uint32_t colour) {
      int bpp = modeInfo->bpp;
      int pitch = modeInfo->pitch;
      uint32_t where = 0;
      for(int i=0;i<h;i++){
         for(int j=0;j<w;j++){
            where = (y+i) * pitch + ((x+j) * (bpp/8));
            screen[where] = colour & 255;             // BLUE
            screen[where + 1] = (colour >> 8) & 255;  // GREEN
            screen[where + 2] = (colour >> 16) & 255; // RED
         }
      }
   }

   void fillrect(int x, int y, int w, int h, unsigned char r, unsigned char g, unsigned char b){
      fillrect(x,y,w,h,(r << 16) + (g << 8) + b);
   }

        // Copy back buffer to video memory
   void UpdateScreen(){
      memcpy(screen,dblBuffer,modeInfo->width*modeInfo->height*(modeInfo->bpp/8));
   }
}

Author:  iansjack [ Fri Feb 24, 2017 5:37 am ]
Post subject:  Re: Double Buffering problems

If you don't allocate memory for the buffer you are bound to have problems. So the question you need to answer is why things don't work when you malloc() the buffer; time for a little debugging.

Author:  ComputerFido [ Fri Feb 24, 2017 7:47 pm ]
Post subject:  Re: Double Buffering problems

iansjack wrote:
If you don't allocate memory for the buffer you are bound to have problems. So the question you need to answer is why things don't work when you malloc() the buffer; time for a little debugging.

Ok thanks i will try to find out the problem with malloc()

Author:  ComputerFido [ Sat Mar 11, 2017 1:44 am ]
Post subject:  Re: Double Buffering problems

iansjack wrote:
If you don't allocate memory for the buffer you are bound to have problems. So the question you need to answer is why things don't work when you malloc() the buffer; time for a little debugging.
Malloc is working but i am still having problems, i tried drawing a rectangle to fill the screen and it only filled about 50 pixels at the top of the screen.

Author:  Brendan [ Sat Mar 11, 2017 2:43 am ]
Post subject:  Re: Double Buffering problems

Hi,

ComputerFido wrote:
iansjack wrote:
If you don't allocate memory for the buffer you are bound to have problems. So the question you need to answer is why things don't work when you malloc() the buffer; time for a little debugging.
Malloc is working but i am still having problems, i tried drawing a rectangle to fill the screen and it only filled about 50 pixels at the top of the screen.


Try to figure out if it's a problem with the code that draws stuff in the double buffer, and/or if it's a problem with the code that copies the double buffer to display memory.

Looking at your old (and likely no longer relevant) code; I'd be tempted to expect multiple problems (e.g. that "fillrect()" is buggy and that "UpdateScreen()" is buggy too), but it's hard to say without seeing any of the new/relevant code.


Cheers,

Brendan

Author:  ComputerFido [ Sat Mar 11, 2017 5:14 am ]
Post subject:  Re: Double Buffering problems

Brendan wrote:
Hi,

ComputerFido wrote:
iansjack wrote:
If you don't allocate memory for the buffer you are bound to have problems. So the question you need to answer is why things don't work when you malloc() the buffer; time for a little debugging.
Malloc is working but i am still having problems, i tried drawing a rectangle to fill the screen and it only filled about 50 pixels at the top of the screen.


Try to figure out if it's a problem with the code that draws stuff in the double buffer, and/or if it's a problem with the code that copies the double buffer to display memory.

Looking at your old (and likely no longer relevant) code; I'd be tempted to expect multiple problems (e.g. that "fillrect()" is buggy and that "UpdateScreen()" is buggy too), but it's hard to say without seeing any of the new/relevant code.


Cheers,

Brendan


I have not changed my fillrect code (as it worked without the doublebuffer and i got the same problem when i used memset) i also tried using a loop instead of memcpy and i still got the same problem.

Author:  Brendan [ Sun Mar 12, 2017 12:39 am ]
Post subject:  Re: Double Buffering problems

Hi,

ComputerFido wrote:
Looking at your old (and likely no longer relevant) code; I'd be tempted to expect multiple problems (e.g. that "fillrect()" is buggy and that "UpdateScreen()" is buggy too), but it's hard to say without seeing any of the new/relevant code.


I have not changed my fillrect code (as it worked without the doublebuffer and i got the same problem when i used memset) i also tried using a loop instead of memcpy and i still got the same problem.[/quote]

The first problem is your handling of "pitch".

Think of the video card's display memory as rows, where each row consists of pixel data followed by none or more unused bytes (for padding). For example, for "800*600 with 32-bpp" each row might be 800*4 bytes (3200 bytes) of pixel data followed by 896 bytes of padding, that adds up to a total of 4096 bytes per row (and so "modeInfo->pitch" would be 4096).

Of course your double buffer has no padding.

Your "UpdateScreen()" assumes that there is no padding for the double buffer (correct) and that there's no padding for display memory (incorrect). This can cause pixels in the double buffer to be written to unused padding and be invisible.

Your "fillrect()" code assumes that there is padding when it draws into the double buffer (that has no padding). This is a potential "index out of range" bug where data in memory after the buffer get trashed. For example, for "800*600 with 32-bpp" with "modeInfo->pitch" is 4096, you allocate 800*600*4 bytes (or 1920000 bytes), and for the bottom left pixel you would write to "where = 799*4096+599*4 = 3275100" , which is 1355100 bytes past the end of the memory you allocated.


Cheers,

Brendan

Author:  ComputerFido [ Fri Mar 17, 2017 5:56 pm ]
Post subject:  Re: Double Buffering problems

Brendan wrote:
The first problem is your handling of "pitch".

Think of the video card's display memory as rows, where each row consists of pixel data followed by none or more unused bytes (for padding). For example, for "800*600 with 32-bpp" each row might be 800*4 bytes (3200 bytes) of pixel data followed by 896 bytes of padding, that adds up to a total of 4096 bytes per row (and so "modeInfo->pitch" would be 4096).

Of course your double buffer has no padding.

Your "UpdateScreen()" assumes that there is no padding for the double buffer (correct) and that there's no padding for display memory (incorrect). This can cause pixels in the double buffer to be written to unused padding and be invisible.


Okay i have tried many different things to try and fix UpdateScreen() this being among them.
Code:
void UpdateScreen(){
      for(int i=0;i<modeInfo->height;i++){
         for(int j=0;j<modeInfo->width;j++)
            screen[i*modeInfo->width*modeInfo->pitch+j] = dblBuffer[i*modeInfo->width+j];
      }
   }

But it still isn't working and i have no idea why. It's probably just something obvious i am missing but i am not sure. It would be really helpful if you could point me in right direction with the really annoying equation to copy the buffer :?

Author:  Brendan [ Fri Mar 17, 2017 6:19 pm ]
Post subject:  Re: Double Buffering problems

Hi,

ComputerFido wrote:
Okay i have tried many different things to try and fix UpdateScreen() this being among them.
Code:
void UpdateScreen(){
      for(int i=0;i<modeInfo->height;i++){
         for(int j=0;j<modeInfo->width;j++)
            screen[i*modeInfo->width*modeInfo->pitch+j] = dblBuffer[i*modeInfo->width+j];
      }
   }

But it still isn't working and i have no idea why. It's probably just something obvious i am missing but i am not sure. It would be really helpful if you could point me in right direction with the really annoying equation to copy the buffer :?


That's not right either. The "modeInfo->pitch" is the number of bytes in a horizontal line and should not be multiplied by the horizontal resolution ("modeInfo->width").

It also won't work "as is" for arrays in C - you'd have to use something like "modeInfo->pitch/sizeof(screen[0])" instead. A better alternative is something like:


Code:
void UpdateScreen(){
      unsigned int visibleBytesPerLine = modeInfo->width * modeInfo->bpp / 8;
      uint8_t *dest = screen;
      uint8_t *src = dblBuffer;

      for(int y = 0; y < modeInfo->height; y++) {
         memcpy(dest, src, visibleBytesPerLine);
         dest += modeInfo->pitch;
         src += visibleBytesPerLine;
      }
   }


Cheers,

Brendan

Page 1 of 1 All times are UTC - 6 hours
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group
http://www.phpbb.com/