Autor Thema: VESA Informationen zum Grafikmodus abfragen  (Gelesen 15616 mal)

üäpöol

  • Beiträge: 110
    • Profil anzeigen
Gespeichert
« am: 04. June 2012, 18:17 »
Hallo,
ich habe mir dieses großartige Tutorial (http://www.lowlevel.eu/wiki/VESA_BIOS_Extensions) angeschaut und wollte als erstes testen, ob LFB bei verschiedenen Grafikmodi vorhanden ist.
Hier der Code:
mov ax, 0x4F01
mov di, 0x0
mov bx, 0x8000
mov es, bx
mov cx, 0x0118
int 0x10
mov al, byte [0x8000]
and al, 10000000b
cmp al, 0
jne LFB
je no_lFB
LFB:
mov al, 'j'
mov ah, 0x0E
int 0x10
no_lFB:
mov al, 'n'
mov ah, 0x0E
int 0x10
jmp $
Ich habe leider keine Ahnung, warum n ausgegeben wird.

Jidder

  • Administrator
  • Beiträge: 1 625
    • Profil anzeigen
Gespeichert
« Antwort #1 am: 04. June 2012, 20:17 »
Du hast Segment und Offset verdreht. Du sagst dem BIOS, dass es nach 8000:0000 (es:di) schreiben soll, aber du liest von irgendwas:8000.
Dieser Text wird unter jedem Beitrag angezeigt.

üäpöol

  • Beiträge: 110
    • Profil anzeigen
Gespeichert
« Antwort #2 am: 04. June 2012, 20:26 »
OK. Danke schonmal. Aber wie kann ich dann von 0x8000:0000 lesen?
EDIT:
Hat sich erledigt.
mov bx, 0x8000
mov es, bx
mov si, 0x0
mov al, [es:si]
« Letzte Änderung: 04. June 2012, 20:43 von üäpöol »

üäpöol

  • Beiträge: 110
    • Profil anzeigen
Gespeichert
« Antwort #3 am: 04. June 2012, 21:32 »
Ich habe noch ein kleines Problem. Ich möchte die Startadresse des LFB auslesen. Dazu habe ich folgende Assemblerfunktion geschrieben:

[GLOBAL GetGraficModeInfo]
GetGraficModeInfo:
push ebp
mov ebp, esp
mov si, [ebp+8]
mov bx, 0x8000
mov es, bx
mov eax, [es:si]
mov esp, ebp
pop ebp
ret
Jetzt sieht meine DrawPixel so aus:
void DrawPixel(int x, int y, long color){
       *(int *)(GetGraficModeInfo(40) + y * GetGraficModeInfo(50) + x * 4) = color;
}
Leider wird nicht gezeichnet.

EDIT:
QEMU gibt aus: "General Protection Fault". Da scheint etwas gewaltig schief zu gehen.
« Letzte Änderung: 04. June 2012, 21:36 von üäpöol »

Jidder

  • Administrator
  • Beiträge: 1 625
    • Profil anzeigen
Gespeichert
« Antwort #4 am: 04. June 2012, 22:41 »
Wenn du im Protected Mode bist, darfst du nicht einfach so die Segmentregister mit Real Mode Segmenten laden. (Der GPF versucht dir zu sagen, dass 0x8000 kein gültiger Selektor ist.) Du solltest mit linearen Adressen arbeiten.

int GetGraficModeInfo(int offset)
{
    return *(int *)(0x80000 + offset);
}

Der Wert ist jetzt 0x80000 weil segment * 16 + offset = 0x8000 * 16 + offset = 0x80000 + offset.

Übrigens solltest du für die bytes per scan line nur ein Word lesen, kein DWord.

void DrawPixel(int x, int y, long color){
       *(int *)(GetGraficModeInfo(40) + y * (GetGraficModeInfo(50) & 0xffff) + x * 4) = color;
}

Wenn du über den Prototypenstatus hinaus bist, kannst du zum Beispiel ein struct anlegen, dass dem Format der Modusinformationen entspricht. Dann umgehst du Probleme mit den Datentypen. Zum Beispiel wie hier: http://wiki.osdev.org/Getting_VBE_Mode_Info
« Letzte Änderung: 04. June 2012, 22:46 von Jidder »
Dieser Text wird unter jedem Beitrag angezeigt.

üäpöol

  • Beiträge: 110
    • Profil anzeigen
Gespeichert
« Antwort #5 am: 04. June 2012, 23:54 »
Wow, es funktioniert perfekt! Viele vielen Dank! :) Ich muss mich zwar noch mit den Farben auseinandersetzen, das ist aber glaube ich auch irgendwo beschrieben. :)

üäpöol

  • Beiträge: 110
    • Profil anzeigen
Gespeichert
« Antwort #6 am: 05. June 2012, 01:35 »
Es gibt doch noch ein Problem. Es geht um die Funktion DrawCircle.
void DrawCircle(int centerX, int centerY, int radius, short R, short G, short B){
for(int actPoint = 0; actPoint <= radius; actPoint++){
DrawPixel(centerX+actPoint, centerY+sqrt(radius*radius-actPoint*actPoint), R, G, B);
DrawPixel(centerX+sqrt(radius*radius-actPoint*actPoint), centerY+actPoint, R, G, B);

DrawPixel(centerX+actPoint, centerY-sqrt(radius*radius-actPoint*actPoint), R, G, B);
DrawPixel(centerX+sqrt(radius*radius-actPoint*actPoint), centerY-actPoint, R, G, B);

// ZWEITER TEIL, FUNKTIONIERT NICHT RICHTIG
DrawPixel(centerX-actPoint, centerY+sqrt(radius*radius-actPoint*actPoint), R, G, B);
DrawPixel(centerX-sqrt(radius*radius-actPoint*actPoint), centerY+actPoint, R, G, B);

DrawPixel(centerX-actPoint, centerY-sqrt(radius*radius-actPoint*actPoint), R, G, B);
DrawPixel(centerX-sqrt(radius*radius-actPoint*actPoint), centerY-actPoint, R, G, B);
}
}
Der zweite Teil des Kreises sieht dann aber nicht so aus wie erste und recht.
Ein Bild ist angehängt. Ich kann's mir nicht erklären, weil auf der linken Seite dieselben Y-Werte sein sollte wie auf der Rechten.

Jidder

  • Administrator
  • Beiträge: 1 625
    • Profil anzeigen
Gespeichert
« Antwort #7 am: 05. June 2012, 02:18 »
Also ich weiß auch nicht was da verkehrt ist, aber du solltest dir mal den Bresenham-Algorithmus für Kreise angucken.
Dieser Text wird unter jedem Beitrag angezeigt.

üäpöol

  • Beiträge: 110
    • Profil anzeigen
Gespeichert
« Antwort #8 am: 05. June 2012, 02:33 »
Das ist jetzt hochinteressant. Ich bekomme ein sehr ähnliches Ergebnis mit dem Algorithmus. Es liegt also nicht am Code, sondern an sonst irgendetwas. Woran kann das liegen?

üäpöol

  • Beiträge: 110
    • Profil anzeigen
Gespeichert
« Antwort #9 am: 05. June 2012, 16:51 »
Ich habe das Problem jetzt gelöst.
// LINKE SEITE
for(int actPoint = 0; actPoint <= radius; actPoint++){
DrawPixel(centerX-actPoint, centerY+sqrt(radius*radius-actPoint*actPoint), R, G, B, A);
DrawPixel(centerX-sqrt(radius*radius-actPoint*actPoint), centerY+actPoint, R, G, B, A);

DrawPixel(centerX-actPoint, centerY-sqrt(radius*radius-actPoint*actPoint), R, G, B, A);
DrawPixel(centerX-sqrt(radius*radius-actPoint*actPoint), centerY-actPoint, R, G, B, A);
}
for(int actPoint = -radius; actPoint <= 0; actPoint++){
DrawPixel(centerX+actPoint, centerY+sqrt(radius*radius-actPoint*actPoint), R, G, B, A);
DrawPixel(centerX+sqrt(radius*radius-actPoint*actPoint), centerY+actPoint, R, G, B, A);

DrawPixel(centerX+actPoint, centerY-sqrt(radius*radius-actPoint*actPoint), R, G, B, A);
DrawPixel(centerX+sqrt(radius*radius-actPoint*actPoint), centerY-actPoint, R, G, B, A);
}
Vielleicht hat ja noch jemand eine Erklärung für mich. :)

EDIT:
Ich habe leider noch ein Problem mit der Farbtiefe.
short BitsPerPixel = GetGraficModeInfo(25);
switch(BitsPerPixel){
case 24:
x *= 3;
*(int*)(LFB_Start+y*(LinBytesPerScanLine & 0xFFFF)+x) = B;
*(int*)(LFB_Start+y*(LinBytesPerScanLine & 0xFFFF)+x+1) = G;
*(int*)(LFB_Start+y*(LinBytesPerScanLine & 0xFFFF)+x+2) = R;
break;
case 32:
x *= 4;
*(int*)(LFB_Start+y*(LinBytesPerScanLine & 0xFFFF)+x) = A;
*(int*)(LFB_Start+y*(LinBytesPerScanLine & 0xFFFF)+x+1) = B;
*(int*)(LFB_Start+y*(LinBytesPerScanLine & 0xFFFF)+x+2) = G;
*(int*)(LFB_Start+y*(LinBytesPerScanLine & 0xFFFF)+x+3) = R;
break;
default:
break;
};
Ich bin immer noch im Modus 0x11B, aber es wird nichts gezeichnet.
« Letzte Änderung: 05. June 2012, 17:09 von üäpöol »

üäpöol

  • Beiträge: 110
    • Profil anzeigen
Gespeichert
« Antwort #10 am: 06. June 2012, 00:31 »
Es gibt gleich noch ein Problem. Ich möchte eine Funktion schreiben, die den besten Grafikmodus auswählt. Dazu habe ich eine Funktion geschrieben, die die Informationen zum aktuellen Grafikmodus in 0x8000 schreiben soll. Leider ist cx nie 0xFFFF. Hier der Code:
mov dword [VBEInfoBlock-start], "VBE2"
mov ax, 0x4F00
mov bx, VBEInfoBlock-start
mov es, bx
mov di, 0
int 0x10
; ...
Get_Info_Of_Grafic_Mode:
mov bx, VBEInfoBlock-start
mov es, bx
mov di, 14
mov cx, [es:di]
mov es, cx
mov al, byte [Grafic_Mode_number-start]
mov ah, 0
mov cx, 2
mul cx
mov di, ax
mov cx, [es:di]
mov bx, 0x8000
mov es, bx
mov di, 0
mov ax, 0x4F01
int 0x10
ret
VBE2 funktioniert. Die Funktion Get_Info_Of_Grafic_Mode soll zuerst die Adresse der Liste auslesen und dann den Modusnamen aus der Liste auslesen. Danke im Voraus.

EDIT:
OK, das kann natürlich nicht funktionieren. Ich habe die Funktion jetzt so verändert, dass es imho funktionieren müsste:
mov bx, 0x7E00
mov es, bx
mov di, 0
mov [es:di], dword "VBE2"
mov ax, 0x4F00
int 0x10
; ...
Choose_Best_Grafic_Mode:
call Get_Grafic_Mode_Info
cmp ax, 0x118
je Set_Grafic_Mode
Get_Grafic_Mode_Info:
mov bx, 0x7E00
mov es, bx
mov di, 14
mov es, [es:di]
mov di, word [Grafic_Mode_number-start]
mov bx, 0x8000
mov es, bx
mov di, 0
mov cx, [es:di]
mov ax, 0x4F01
int 0x10
mov ax, cx
ret
Set_Grafic_Mode:
mov ax, 0x4F02
mov bx, 0x11B
int 0x10
jmp GraficModeSet
Das sollte doch eigentlich funktionieren, weil 0x118 normalerweise unterstürzt wird. Sobald der Grafikmodus gefunden wird soll er gesetzt werden. Das ist natürlich nur ein einfacher Test, aber ich weiß nicht mal, warum das nicht funktioniert.
« Letzte Änderung: 06. June 2012, 15:57 von üäpöol »

üäpöol

  • Beiträge: 110
    • Profil anzeigen
Gespeichert
« Antwort #11 am: 06. June 2012, 23:58 »
OK. Das hat sich erledigt. Aber eine Frage habe ich noch. Wie setzt man "Packed pixel" GraficModeInfo+27 == 0x04?

üäpöol

  • Beiträge: 110
    • Profil anzeigen
Gespeichert
« Antwort #12 am: 09. June 2012, 12:33 »
Erstmal sorry für die vielen Posts! :oops: Es wird inzwischen immer der beste Grafikmodus ausgewählt. Allerdings gibt es noch ein Bochsproblem.
romimage: file=Bochs-2.5.1/BIOS-bochs-latest
vgaromimage: file=Bochs-2.5.1/VGABIOS-lgpl-latest
vga: extension=vbe, update_freq=10
Das führt im bochsscr schonmal dazu, dass der Grafikmodus ausgewählt wird. Leider werden keine Pixel gezeichnet. Es kann kaum am Code liegen, weil es in VirtualBox und am echten PC funktioniert. Was muss ich bei Bochs noch einstellen?

Dimension

  • Beiträge: 155
    • Profil anzeigen
Gespeichert
« Antwort #13 am: 09. June 2012, 23:07 »
Die Grafikroutinen erinnern mich an meine ersten Gehversuche in Assembler. Ich war davon begeistert, wie sehr man mit REP MOVSD/STOSD und verschachtelten LOOPs optimieren konnte. Ich bin bis heute kein  Fan von selfmodifying Code auf Maschinencode-Ebene, Farbverläufe mit Dithering... toll

Also Bochs bietet VBE, Vesa Bios Extension, google mal danach.

üäpöol

  • Beiträge: 110
    • Profil anzeigen
Gespeichert
« Antwort #14 am: 09. June 2012, 23:58 »
Ja... :D Ich bin leider immer noch Anfänger, was OSDev angeht. Was meinst du denn mit "selfmodifying Code auf Maschinencode-Ebene"? Dass Bochs VBE bietet, kann ich ja schon sehen, da in einen Grafikmodus geschaltet wird, aber Pixel kann ich trotzdem nicht zeichnen. Kann das überhaupt sein, oder kann doch etwas an meinem Code falsch sein? Ich könnte ihn mal posten...

üäpöol

  • Beiträge: 110
    • Profil anzeigen
Gespeichert
« Antwort #15 am: 10. June 2012, 15:01 »
Ich poste den Code einfach mal. Da es doch relativ viel ist, habe ich es mit Pastebin gemacht:
http://pastebin.com/AMBVz5xK
Ich habe den Code leider noch nicht kommentiert, aber er sollte nicht so schwer zu verstehen sein. Es werden einfach unterstützte Grafikmodi durchgegangen, von denen der beste gespeichert und irgendwann aufgerufen wird.

Svenska

  • Beiträge: 1 792
    • Profil anzeigen
Gespeichert
« Antwort #16 am: 10. June 2012, 19:34 »
Definiere mal "der beste Grafikmodus". Ist es der mit der höchsten Auflösung, höchsten Farbtiefe oder etwas ganz anderes?

VESA garantiert nicht, dass der Bildschirm die angegebene Auflösung auch darstellen kann. Es gibt neben dem VBE-Standard noch den VBE/DDC-Standard, der dir die EDID (Fähigkeiten) des Bildschirms mitteilen kann, sofern es unterstützt wird (VBE/DDC ist eine Extension). Im Emulator geht natürlich alles, was die virtuelle Grafikkarte kann.

Gruß,
Svenska

üäpöol

  • Beiträge: 110
    • Profil anzeigen
Gespeichert
« Antwort #17 am: 10. June 2012, 19:54 »
Rangfolge:
1. Beste X-Auflösung
2. Beste Y-Auflösung
3. Beste Farbtiefe

Verboten:
- Kein LFB
- Textmodus
- "Packed pixel"

VirtaulBox hat keine Probleme, aber Bochs. Aber Bochs müsste doch mindestens 0x115 unterstützen, oder? Es wird aber leider nie ein Pixel gezeichnet.

üäpöol

  • Beiträge: 110
    • Profil anzeigen
Gespeichert
« Antwort #18 am: 11. June 2012, 21:19 »
Ich hab's grad mal mit QEMU getestet. Da ist es exakt dasselbe ...

Svenska

  • Beiträge: 1 792
    • Profil anzeigen
Gespeichert
« Antwort #19 am: 11. June 2012, 23:12 »
Welcher Grafikmodus wird denn ausgewählt?
Vielleicht ist der ja einfach nur kaputt oder unerwartet. Gib einfach mal einen vor, z.B. 800x600x16. Die simulierte Cirrus Logic kann meines Wissens keine 32-Bit-Modi, sondern nur welche mit 24 Bit/Pixel.

 

Einloggen