finarfin wrote:Ok so technically is 24bit used.
Well yes, but it's unfortunate to call it like this, because there's also a 24 bit mode (don't use that). Let's call it 32 bit (where only 24 bits are used, and 8 is there for padding only). When you start to handle window buffers, you'll need an alpha channel for transparent windows. Then you'll realize how benefitial it is that the framebuffer has an extra byte so that you don't have to make strange offset calculations and word+byte or byte+word copies, instead a simple repne movsd will do which is also a lot faster.
finarfin wrote:So since i can't foresee it at compile time, i need to have kind of putpixel wrapper that based on the configuration is going to use the right function, or something like during kernel setup, initialize just a pointer to a function with the correct putpixel function (i'm writing my kernel in C) and use it everytime i need to draw something? Something like that? Sounds reasonable?
That's one way to do it. But if you think about it, if one pixel would be 32 bits, then you'll use the same code no matter what.
Here's a code example (just for demonstration purposes only, I haven't tested it):
Code: Select all
unsigned int rgb_to_pixel(int r,int g,int b)
{
if (red_shift >= 0) r <<= red_shift; else r >>= -red_shift;
if (green_shift >= 0) g <<= green_shift; else g >>= -green_shift;
if (blue_shift >= 0) b <<= blue_shift; else b >>= -blue_shift;
r &= red_mask;
g &= green_mask;
b &= blue_mask;
return r | g | b;
}
void drawline(int x0, int y0, int x1, int x2, unsigned int fg) { ... }
void drawbox(int x, int y, int w, int h, unsigned int fg) { ... }
And then all the other functions (drawline, drawbox, etc.) just use the unsigned int pixel returned by this function in "fg", they don't have to know nor care about the actual channel order.
You can also use special double buffering: there window has a fixed pixel format, and the visual has another pixel format (same or could be different). The window can handle its own pixels with the same code (like say 32 bit RGBA), and there's a special blitting function that copies to the visual (the framebuffer) converting between pixel formats. The advantage is, you'll only need one blitter per visual pixel format (that's 2 functions for 32 bit, and 6/7 functions if you also want to support hicolor). You can optimize that blitter to the extreme, and you only need to select the blitter function once in run-time during initialization (again, for demonstration only, not tested code):
Code: Select all
void (*blitter_t)(int x, int y, int w, int h);
blitter_t *blitter;
void init_fb() {
switch(fb->format) {
/* speed optimized versions */
case PIXEL_RGB_15: blitter = blit_rgba32_to_rgb555; break;
case PIXEL_BGR_15: blitter = blit_rgba32_to_bgr555; break;
case PIXEL_RGB_16: blitter = blit_rgba32_to_rgb565; break;
case PIXEL_BGR_16: blitter = blit_rgba32_to_bgr565; break;
case PIXEL_RGB_32: blitter = blit_rgba32_to_rgb888; break;
case PIXEL_BGR_32: blitter = blit_rgba32_to_bgr888; break;
/* fallback using shifts and masks, slow, but but can handle any format */
default: blitter = blit_rgba32_to_somethingdefinedbybitmasks; break;
}
}
void window_flush()
{
/* copy from window buffer to framebuffer */
(*blitter)(0, 0, fb->width, fb->height);
}
With this, your code won't need to know the pixel format in compilation time, all your drawing primitives can simply use RGBA 32 bit. (And if you limit the query to 32 bit modes only, then you'll only need 2 blitters: rgba and bgra). This is quite different to setting up a putpixel function dynamically, because that would disallow compiler optimizations in the drawing primitive functions, while this does not interfere with the compiler's opts. With multiple windows, you'll have to copy the window buffers to the screen eventually (called compositing), so that's not a drawback.
finarfin wrote:So you say i need to query it (i suppose you mean using the vbe modeinfo)
Yes, exactly. It also returns the channel shifts and masks I talked about above. It's the same for GOP, but there it's a bit more trickier because there are more formats (to describe the pixel format). For example, in
this tutorial 800x600 was reported with PixelBlueGreenRedReserved8BitPerColor format, while 1024x768 reported in PixelBitMask format. Despite of the different description, both are describing the same BGRA 32 bit as the packed pixel format (see the calculated bitmasks on the screenshot).
finarfin wrote:and then you also say that pitch and scanline are the same things, so since multiboot is returning me the pitch, i can use the value from multiboot correct? and wherever i found scanline replace it with pitch right? (i just found the definition of ptich)
Well technically yes. However reading through lots and lots of specs and docs I've noticed that if the size of the row is given in pixels, it's more likely called scanline, and if it's given in bytes, then it's more likely called pitch. But this isn't a rule, just my observation, I know about libraries that use byte based scanline and pixel based pitch. The point is, the size of one row is just as important argument like the screen's width or height for example.
(
Ralf Brown's calls it scan line, but VBE actually reports it in bytes and not pixels for example)
Korona wrote:Technically, VESA is not the standard itself but the committee designing the VBE standard.
I stand corrected, that's right. Regardless it is the BIOS VBE that you're interfacing with.
Cheers,
bzt