Page 1 of 2
Graphics mode?
Posted: Sun Feb 25, 2007 1:50 am
by pcmattman
I've run into a problem when I try to implement my GUI - I can't set the graphics mode because I can't use BIOS interrupts from PMode. Is there any way of getting into the graphics mode from PMode? (I'm trying to do the tutorial for GUI development over at osdever.net).
Posted: Sun Feb 25, 2007 4:33 am
by Combuster
several options:
- use v8086 mode
- exit pmode, call the interrupt, then re-enter pmode
- write your own drivers
- build an emulator to execute bios code
Posted: Sun Feb 25, 2007 12:35 pm
by Dex
Here are some examples of the method Combuster suggested
This is a demo of go to and from real mode for mode switching (need vesa2)
http://www.dex4u.com/tuts/DemoVesa.zip
Here are examples of mode switching from pmode
http://bos.asmhackers.net/docs/vga_without_bios/
Posted: Sun Feb 25, 2007 3:31 pm
by pcmattman
Sounds good, thankyou for your quick reply!
Posted: Mon Feb 26, 2007 4:15 am
by digo_rp
to setup a v86 task is so easy,
you just set a protected mode task "32bits one" and you put 4 v86 registers like that:
process->kstack = (dword)&process->pl0_stacK+stack_size;
p = (dword)0x1fff8;
*--p = r->gs; /* v86_gs */
*--p = r->fs; /* v86_fs */
*--p = r->ds; /* v86_ds */
*--p = r->es; /* v86_es */
*--p = r->cs; /* v86_ss */
*--p = 0xfff8; /* v86_esp */
*--p = 0x20202L; /* eflags */
*--p = r->cs; /* v86_cs */
*--p = r->eip; /* v86_eip */
*--p = r->eax; /* eax */
*--p = r->ecx; /* ecx */
*--p = r->edx; /* edx */
*--p = r->ebx; /* ebx */
*--p = 0; /* nullesp*/
*--p = r->ebp; /* ebp */
*--p = r->esi; /* esi */
*--p = r->edi; /* edi */
*--p = 0x10; /* PMode_gs */
*--p = 0x10; /* PMode_fs */
*--p = 0x10; /* PMode_es */
*--p = 0x10; /* PMode_ds */
be carefull, remember that realmode access only 1MB from your memory.
so that v86 task should be below 1MB Mark.
I use the segment 0x1000
in case you want, I can send to you my sources, then you can take anything you want and change modify, or to learn.
I´ll be very glad to send to evebody.
Posted: Mon Feb 26, 2007 4:20 am
by pcmattman
Thanks, I can get into the video mode now...
The problem is, the following does not work:
Code: Select all
#include "mattise.h"
// gui code...
unsigned char* VGA = (unsigned char*) 0x000A0000;
unsigned char *dbl_buffer;
mBlock dbl_buffer_info;
typedef struct tagBITMAP /* the structure for a bitmap. */
{
unsigned int width;
unsigned int height;
unsigned char *data;
} BITMAP;
typedef struct tagRECT
{
long x1;
long y1;
long x2;
long y2;
} RECT;
void init_dbl_buffer(void)
{
dbl_buffer = (unsigned char *) malloc_count( &dbl_buffer_info, 64 );
// special - make it red if there aren't enough blocks
if( dbl_buffer_info.count < 64 )
{
int i;
for( i = 0; i < 64000; i++ )
*VGA++ = 0x1;
}
if( dbl_buffer == (unsigned char*) NULL )
{
int i;
for( i = 0; i < 64000; i++ )
*VGA++ = 0x4;
kputs("Not enough memory for double buffer.\n");
getch();
}
}
void update_screen(void)
{
#ifdef VERTICAL_RETRACE
while ((inportb(0x3DA) & 0x08));
while (!(inportb(0x3DA) & 0x08));
#endif
int i;
for( i = 0; i < (SCREEN_WIDTH * SCREEN_HEIGHT); i++ )
VGA[i] = dbl_buffer[i];
// memcpy( VGA, dbl_buffer, (unsigned int)(SCREEN_WIDTH * SCREEN_HEIGHT) );
}
void setpixel (BITMAP *bmp, int x, int y, unsigned char color)
{
bmp->data[ ( y * bmp->width ) + x ] = color;
}
/* Draws a filled in rectangle IN A BITMAP. To fill a full bitmap call as
drawrect (&bmp, 0, 0, bmp.width, bmp.height, color); */
void drawrect(BITMAP *bmp, unsigned short x, unsigned short y,
unsigned short x2, unsigned short y2,
unsigned char color)
{
unsigned short tx, ty;
for (ty = y; ty < y2; ty++)
for (tx = x; tx < x2; tx++)
setpixel( bmp, tx, ty, color );
}
void draw_bitmap_old(BITMAP *bmp, int x, int y)
{
int j;
unsigned int screen_offset = (y << 8) + (y << 6) + x;
unsigned int bitmap_offset = 0;
for(j = 0; j < bmp->height; j++)
{
memcpy( &dbl_buffer[screen_offset], &bmp->data[bitmap_offset], bmp->width );
bitmap_offset += bmp->width;
screen_offset += SCREEN_WIDTH;
}
}
void RunGUI()
{
init_dbl_buffer();
unsigned char key;
mBlock test_dat;
do
{
//key = 0;
//if (kbhit()) key = getch();
/* You must clear the double buffer every time to avoid evil messes
(go ahead and try without this, you will see) */
memset_c( dbl_buffer, 0x0, SCREEN_WIDTH * SCREEN_HEIGHT );
/* DRAW ALL BITMAPS AND DO GUI CODE HERE */
BITMAP test;
test.width = 100;
test.height = 100;
test.data = (unsigned char*) malloc( &test_dat );
drawrect( &test, 0, 0, test.width, test.height, 0x1 );
draw_bitmap_old( &test, 5, 5 );
/* Draws the double buffer */
update_screen();
// free memory here
free( test.data, test_dat );
sleep( 100 );
}
while ( true ); /* keep going */
}
The bitmap draws funny, just a whole lot of lines instead of the solid blue that it should be... any ideas?
Screenshot is attached.
Posted: Mon Feb 26, 2007 4:28 am
by Combuster
it seems like you're trying to blit something with the wrong size (blitting a 100x100 bitmap as if it were 320xsomething?)
Posted: Tue Feb 27, 2007 12:45 am
by pcmattman
No, it seems my offsets are wrong. I've tried to set pixels directly to the vga location like so:
Code: Select all
*(unsigned char*)( 0x000A0000 + ( x + ( y * SCREEN_WIDTH ) ) ) = color;
But this still draws with a gap between the two 'pixels'...
I'm confused, can anyone help?
Edit: what really confuses me is that the clearing of the screen works properly, it's just the offsets from the video memory that seem to be failing. I've only tried this in 320x200x8bpp, 256x200x8bpp, 256x256x8bpp... I doubt this is a problem with the mode, though.
Edit 2: Well, it appears the resolution is wrong - I'm apparently NOT running in 320x200, but 80x25 (tested by using SetPixel( 79, 0, 0x4 ); - red line appeared at top right corner, right on edge...). This leads me to assume that somewhere along the line the mode switch got seriously messed up! Any ideas?
Edit 3:
Shame on me, I realized that I forgot to enable chain4 for the resolution (ie. don't use plane switching)... now I've enabled it, everything is working really well. Sorry for wasting everyone's time
Posted: Sat Apr 07, 2007 5:30 am
by stevenup7002
You read that tutorial wron, change the top line to:
Code: Select all
unsigned char *VGA = (unsigned char *)0xA0000L;
And it should work in pmode.
Posted: Sat Apr 07, 2007 10:12 am
by Jeko
digo_rp wrote:in case you want, I can send to you my sources, then you can take anything you want and change modify, or to learn.
I´ll be very glad to send to evebody.
can you send me your sources?
[email protected]
Posted: Sun Apr 08, 2007 8:30 am
by Daedalus
I found the drivers used in TabOS to be incredibly helpful to learn from.
Their sources, whilst not formatted the way I would do it, are clean, use few external files/functions, and most of all - portable.
It was quite an easy task to port their ps2 mouse and vga driver to my OS and use them successfully.
I urge you to download the source to their OS and learn from their drivers!
Posted: Sun Apr 08, 2007 9:08 am
by mystran
stevenup7002 wrote:You read that tutorial wron, change the top line to:
Code: Select all
unsigned char *VGA = (unsigned char *)0xA0000L;
And it should work in pmode.
pcmattman wrote:
Code: Select all
*(unsigned char*)( 0x000A0000 + ( x + ( y * SCREEN_WIDTH ) ) ) = color;
No difference between these. Doesn't matter if the cast is done before or after adding offset, as sizeof(char) is almost certainly 1.
Posted: Sun Apr 08, 2007 11:26 am
by proxy
there is one difference, the second one is technically illegal (though many compilers will accept it)
it is ill formed to cast an l-value.
so thing like:
*((T *)p) = x;
are not legal :-/
proxy
Posted: Sun Apr 08, 2007 12:10 pm
by mystran
proxy wrote:there is one difference, the seocnd one is technically illegal (though many compilers will accept it)
it is ill formed to cast an l-value.
so thing like:
*((T *)p) = x;
are not legal :-/
proxy
Yeah technically. But system software that needs to access memory by address will have to do it anyway, and practically every compiler will allow it, as long as it makes sense on the architecture. It doesn't make any difference whether you use the first or the second method though, because if you first cast the address into a pointer, you're technically violating the rules already, because technically you can't cast an integer into a pointer, unless it's of type intptr_t (C99) and even then it's legal only if you obtained the value from a pointer originally.
The whole issue is ofcourse purely academical, and of interest mostly to language lawyers. We aren't writing portable code here after all, if we are dealing with a specific device, like the VGA.
Posted: Sun Apr 08, 2007 3:28 pm
by Candy
proxy wrote:there is one difference, the seocnd one is technically illegal (though many compilers will accept it)
it is ill formed to cast an l-value.
so thing like:
*((T *)p) = x;
are not legal :-/
proxy
I agree that (T *)p is an rvalue, but isn't *((T *)p) an lvalue in the same way that *p would be?