bochs-emu / Bochs

Bochs - Cross Platform x86 Emulator Project
https://bochs.sourceforge.io/
GNU Lesser General Public License v2.1
891 stars 107 forks source link

Corrupted image in Windows 3.11 with CL-GD5446 driver #350

Closed Vort closed 1 month ago

Vort commented 1 month ago

After I change Windows 3.11 resolution with utility, which comes with CL-GD5446 driver v1.31 (source), image becomes corrupted in different ways depending on which options I choose.

For example, 640x480x4 with VGA driver -> 800x600x8 with CL-GD5446 driver: image image

640x480x4 with CL-GD5446 driver: image

800x600x24 with CL-GD5446 driver: image

Version: f5e3dd9

vruppert commented 1 month ago

I have driver version 1.12 here and I can confirm the behavior at 4 bpp and 24 bpp. There are no errors in the log, so I have to add some BX_INFOs to find out what's going on.

vruppert commented 1 month ago

I have now fixed issues with missing / unreadable text in 8 bpp and 16 bpp modes. The driver uses unimplemented the byte swapping apertures for cpu-to-video bitblt operations. I have now done it in the mem_write_handler(). The 4 bpp and 24 bpp issues are different and not affected by these changes.

vruppert commented 1 month ago

While testing 24 bpp modes, I found out that 640x480 and 1024x768 modes are okay, but 800x600 mode only works correctly with original Cirrus VGABIOS.

vruppert commented 1 month ago

I have now modified the LGPL VGABIOS to make the Cirrus mode 800x600x24 work with Windows 3.11 driver.

Vort commented 1 month ago

I have now modified the LGPL VGABIOS to make the Cirrus mode 800x600x24 work with Windows 3.11 driver.

Please check other modes as well with default Windows 3.11 SVGA driver. This is how 640x480x8 looks like with VGABIOS-lgpl-latest-cirrus: image

640x480x8 with cl-gd5446_pci_vga_bios_version_1.31.u2: image

Window movements with SVGA driver bring chaos, but that's another question.

vruppert commented 1 month ago

I have now fixed the issue found with the Super VGA driver in the VGABIOS. The function clearing VRAM enables 16k bank granularity, but it didn't disable it at the end. To avoid breaking vbetest, I had to clear VRAM before setting 16k granularity. There is no real progress with the 4 bpp issue reported above. In addition to the display issue, I found out that the hardware cursor is turned on, but since the VGA core code doesn't know about it, you cannot see it. So I wrote some test code to make it visible. For now it's only a white square, since I don't know why the driver doesn't write the cursor pattern at memory top.

Vort commented 1 month ago

With commit ec469aa62607e19e5dc1bcf335cd0af829aa44e7, less information is displayed. Also log is flooded with [CIRRUS] current guest pixel format is unsupported on indexed colour host displays, svga_dispbpp=4. Looks like problem specific to Windows host. bochs_4bpp

vruppert commented 1 month ago

It`s not specific to Windows hosts, but specific to 8 bpp host displays. I have now added some untested code for this case. If I did it correct, you should see the incorrect / incomplete VGA display plus a movable white square. I have to find out what the driver is doing and then try to fix up the code if possible.

Vort commented 1 month ago

I see black square with jumpy movement.

upd: jumps are probably because of cursor changing shape.

Vort commented 1 month ago

By the way, did you noticed corrupted image in WinMode program launched with regular VGA driver? May have sense to fix it first (because corruption is not massive).

Corruption is better visible if you open WinMode and then close it with Alt+F4: image

Sorry for clumping too much problems into single report. I'm doing it because I suspect they may be related to each other and fixing one problem may fix other problems as well.

Vort commented 1 month ago

I have to find out what the driver is doing and then try to fix up the code if possible.

If I replace BX_CIRRUS_THIS s.memsize in draw_hardware_cursor with 0x00040000, I can see black shadow of cursor: image

Vort commented 1 month ago

I suspect driver gets memory size from Return Installed Memory BIOS call (ah = 12h, bl = 85h).

upd. not so easy ^^ There are at least two drivers in this pack: 54X6.DRV (Windows Linear Display Driver), 156032 bytes and 16_1280.DRV (Cirrus Logic 16 color display driver), 142047 bytes. First driver (8 bpp and probably more) uses function 85h like I said before, second driver (4 bpp) have just hardcoded addresses and offsets, like so:

cseg01:39CB                 mov     word_1114D, 0FF40h
cseg01:39D1                 mov     word_1114F, 40h
cseg01:39D7                 mov     byte ptr unk_11151, 3Dh
cseg01:39DC                 mov     byte ptr unk_11152, 3Eh
Vort commented 1 month ago

Here are bunch of hacks allowing me to see hardware cursor in 4bpp mode. Most likely, requires refining.

diff --git a/bochs/iodev/display/svga_cirrus.cc b/bochs/iodev/display/svga_cirrus.cc
index 09d650703..ef51d1225 100644
--- a/bochs/iodev/display/svga_cirrus.cc
+++ b/bochs/iodev/display/svga_cirrus.cc
@@ -1086,8 +1086,9 @@ void bx_svga_cirrus_c::draw_hardware_cursor(unsigned xc, unsigned yc, bx_svga_ti
   Bit16u hwcx = BX_CIRRUS_THIS hw_cursor.x;
   Bit16u hwcy = BX_CIRRUS_THIS hw_cursor.y;
   Bit16u size = BX_CIRRUS_THIS hw_cursor.size;
+  bool bpp4 = BX_CIRRUS_THIS svga_dispbpp == 4;

-  if (BX_CIRRUS_THIS svga_double_width) {
+  if (BX_CIRRUS_THIS svga_double_width && !bpp4) {
     hwcx <<= 1; // FIXME: untested
   }
   if ((size > 0) &&
@@ -1112,7 +1113,7 @@ void bx_svga_cirrus_c::draw_hardware_cursor(unsigned xc, unsigned yc, bx_svga_ti
     if (info->bpp == 15) info->bpp = 16;
     tile_ptr = bx_gui->graphics_tile_get(xc, yc, &w, &h) +
                info->pitch * (cy0 - yc) + (info->bpp / 8) * (cx0 - xc);
-    plane0_ptr = BX_CIRRUS_THIS s.memory + BX_CIRRUS_THIS s.memsize - 16384;
+    plane0_ptr = BX_CIRRUS_THIS s.memory + (bpp4 ? 0x40000 : BX_CIRRUS_THIS s.memsize) - 16384;

     switch (size) {
       case 32:
@@ -1145,7 +1146,7 @@ void bx_svga_cirrus_c::draw_hardware_cursor(unsigned xc, unsigned yc, bx_svga_ti
     } else {
       // FIXME: this is a hack that works in Windows guests
       // TODO: compare hidden DAC entries with DAC entries to find nearest match
-      fgcol = 0xff;
+      fgcol = bpp4 ? 0x3f : 0xff;
       bgcol = 0x00;
     }

@@ -2033,7 +2034,7 @@ void bx_svga_cirrus_c::svga_write_sequencer(Bit32u address, unsigned index, Bit8
   }

   if (update_cursor) {
-    if (!BX_CIRRUS_THIS svga_double_width) {
+    if (!BX_CIRRUS_THIS svga_double_width || BX_CIRRUS_THIS svga_dispbpp == 4) {
       BX_CIRRUS_THIS vga_redraw_area(x, y, size, size);
       BX_CIRRUS_THIS vga_redraw_area(BX_CIRRUS_THIS hw_cursor.x, BX_CIRRUS_THIS hw_cursor.y, BX_CIRRUS_THIS hw_cursor.size, BX_CIRRUS_THIS hw_cursor.size);
     } else { 
vruppert commented 1 month ago

I can confirm that these hacks would work, but they are not correct. The driver enables the extended address wrap in VGA mode. This means that the cursor pattern must be in the last 16 k of 1 MB memory, but it's not copied there. I also noticed that it's impossible to switch to a higher resolution higher than 640x480 in 4 bpp mode. For now I want to continue with fixing / improving other parts of Bochs and return to this issue later.

Vort commented 1 month ago

but it's not copied there

It is copied to addresses like 0xAFF87, which corresponds to latest addressable bytes for VGA mode. I don't see how it will go to 1MB from there and why. However, my understanding is not good and I may be wrong.

I also noticed that it's impossible to switch to a higher resolution higher than 640x480 in 4 bpp mode

Driver may be designed that way. It is weird to have dedicated driver for single mode, but why not.

By the way, 800x600x4 mode is accessible with default SVGA driver. At least, this is what Windows says.

For now I want to continue with fixing / improving other parts of Bochs and return to this issue later.

Ok. Can you look at nearby issue #352? It should be easy fix, I just don't know how to properly implement big endian support.

vruppert commented 1 month ago

Now I know the reason for the corrupted image in 4 bpp mode. The functionality of graphics controller register 0x0b must be implemented for the VGA mode (extended write modes, x8 addressing, 8-byte data latches). I'll have a look whether or not I have to copy&paste the VGA mem_read() / mem_write() code in the Cirrus code to add these extensions.

vruppert commented 1 month ago

I have now applied a usable version of the graphics controller mode extensions for the VGA mode. I did a lot of copy&paste, but I don't know whether or not all of this code is really needed. On the other side I have only implemented extensions required by the driver. For the hardware cursor I have now modified the code based on your suggestion, since the specs don't say anything about this case.

Vort commented 1 month ago

Same mode, but with regular VGA driver, needs fixing as well.

Vort commented 1 month ago

Same mode, but with regular VGA driver, needs fixing as well.

I made separate issue about it: #359.

I also noticed that it's impossible to switch to a higher resolution higher than 640x480 in 4 bpp mode.

Driver may be designed that way.

Turned out, driver really should support 640x480x4, 800x600x4 and 1024x768x4. Switching works ok with original BIOS.

But it is better to make separate report for this problem (upd: Done: #360). This issue is filled enough with subtasks already so I'm closing it.