bochs-emu / Bochs

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

The screen is not displayed correctly when the display mode is QVGA (@320×240) in Microsoft Windows. #230

Closed Githubmaniak closed 6 months ago

Githubmaniak commented 7 months ago

Some games or applications running full screen will not display correctly when the display mode is changed to QVGA or similar resolution (e.g. 320×200).

Below are screenshots of when it is displayed correctly and when it is not displayed.

lBochs PC Emulator20240120041301 lBochs PC Emulator20240120042202 lBochs PC Emulator20240120041946 lBochs PC Emulator20240120042531

I couldn't check the log because I was using Bochs PC Emulator, an Android port.

stlintel commented 7 months ago

Many of these issues just were fixed in github. You will have to update the Android port for yourself to latest Github code and see what if it is still problem. or re-test it somehow on Windows or Linux.

Vort commented 7 months ago

MegaMan X4 looks fine on Windows 98 with Cirrus card: image It shows black screen with Voodoo 3, but this effect is different from what is on your screenshot.

Githubmaniak commented 7 months ago

@Vort For the Megaman X4, it displays properly in 640×480 mode, but not in 320×240 mode. lBochs PC Emulator20240120225258 In addition to Megaman X4, neither GTA1 nor Heven7 demo scenes display properly in 320×240 (or 200) mode. lBochs PC Emulator20240120230457 lBochs PC Emulator20240120230613

Vort commented 7 months ago

For the Megaman X4, it displays properly in 640×480 mode, but not in 320×240 mode.

How to switch it to different mode? I did not found such option.


I made issue about problems with Voodoo 3 by the way: #231.

Githubmaniak commented 7 months ago

@Vort You can change the display mode with the F5 key and the color depth with the F6 key. Changes up to 800×600 24bit color.

Vort commented 7 months ago

Ok, thanks. This is how Cirrus glitches.

image

This issue is similar to #202, but for Cirrus instead of Voodoo 3.

Please provide more details about your configuration next time.

Here is test program for reproduction (modeset.zip):

#define WIN32_LEAN_AND_MEAN
#include <windows.h>

int ChangeResolution(int width, int height, int bpp)
{
    DEVMODE dm;
    memset(&dm, 0, sizeof(dm));
    dm.dmSize = sizeof(dm);
    dm.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
    dm.dmPelsWidth = width;
    dm.dmPelsHeight = height;
    dm.dmBitsPerPel = bpp;
    return ChangeDisplaySettings(&dm, 0);
}

int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
{
    ChangeResolution(320, 200, 16);
    Sleep(5000);
    ChangeResolution(800, 600, 16);
    return 0;
}
vruppert commented 7 months ago

I have now applied a fix for the double scan mode. Doubling the screen width similar to Voodoo3 is not done yet.

Vort commented 7 months ago

Doubling the screen width similar to Voodoo3 is not done yet.

This is how game looks now: image

Not sure what mode it is however, because I can't cycle them all: next press of F5 results in hang: image

Vort commented 7 months ago

@vruppert looks like doubling happens twice now. Pixels are 2x4 in size.

vruppert commented 7 months ago

This is a feature of the win32 gui. If the width is < 400 the screen is automatically doubled in both directions to avoid having an unusable small window. When I add support for doubling the width in the Cirrus code, the aspect ratio should look correct again.

vruppert commented 7 months ago

Update: I have now added double width support for Cirrus. The program / driver doesn't enable the hardware cursor, so I don't know whether or not this part is correct. The cursor visibility is not correct, but in this case it's created by software.

Vort commented 7 months ago

Not only cursor, but also desktop is displayed incorrectly: image

vruppert commented 7 months ago

I have now added double scan and double width support for banked memory writes to makes it look better, but the cursor is still not okay.

Vort commented 7 months ago

I see almost no differences: image

There are slightly higher chances of correct rendering for Windows 95. But for Windows 98 updates are still happen only 1/4 of the time and no Start menu appears. Also cursor not only glitchy, but also located offscreen initially when mode is switched.

Vort commented 7 months ago

update: absence of Start menu and offscreen cursor are just properties of Windows 98. I didn't knew about it before, sorry. So only checkerboard tile updates need to be solved.

Vort commented 7 months ago

@vruppert your change was almost right. However, after integer division is done, it is not possible to recover lost bits with multiplication. Something like this should be done instead (multiplication first, division afterwards):

diff --git a/bochs/iodev/display/svga_cirrus.cc b/bochs/iodev/display/svga_cirrus.cc
index 6301239e9..8f5d34380 100644
--- a/bochs/iodev/display/svga_cirrus.cc
+++ b/bochs/iodev/display/svga_cirrus.cc
@@ -667,8 +667,6 @@ void bx_svga_cirrus_c::mem_write(bx_phy_address addr, Bit8u value)
 {
 #if BX_SUPPORT_PCI
   if (BX_CIRRUS_THIS pci_enabled) {
-    unsigned xti, yti;
-
     if ((addr >= BX_CIRRUS_THIS pci_bar[0].addr) &&
         (addr < (BX_CIRRUS_THIS pci_bar[0].addr + CIRRUS_PNPMEM_SIZE))) {

@@ -710,15 +708,9 @@ void bx_svga_cirrus_c::mem_write(bx_phy_address addr, Bit8u value)
         }
       }
       BX_CIRRUS_THIS svga_needs_update_tile = 1;
-      xti = ((offset % BX_CIRRUS_THIS svga_pitch) / (BX_CIRRUS_THIS svga_bpp / 8)) / X_TILESIZE;
-      yti = (offset / BX_CIRRUS_THIS svga_pitch) / Y_TILESIZE;
-      if (BX_CIRRUS_THIS s.y_doublescan) {
-        yti <<= 1;
-      }
-      if (BX_CIRRUS_THIS svga_double_width) {
-        xti <<= 1;
-      }
-      SET_TILE_UPDATED(BX_CIRRUS_THIS, xti, yti, 1);
+      SET_TILE_UPDATED(BX_CIRRUS_THIS,
+        (BX_CIRRUS_THIS svga_double_width + 1) * ((offset % BX_CIRRUS_THIS svga_pitch) / (BX_CIRRUS_THIS svga_bpp / 8)) / X_TILESIZE,
+        (BX_CIRRUS_THIS s.y_doublescan + 1) * (offset / BX_CIRRUS_THIS svga_pitch) / Y_TILESIZE, 1);
       return;
     } else if ((addr >= BX_CIRRUS_THIS pci_bar[1].addr) &&
                (addr < (BX_CIRRUS_THIS pci_bar[1].addr + CIRRUS_PNPMMIO_SIZE))) {
@@ -743,7 +735,6 @@ void bx_svga_cirrus_c::mem_write(bx_phy_address addr, Bit8u value)
   if (addr >= 0xA0000 && addr <= 0xAFFFF) {
     Bit32u bank, offset;
     Bit8u mode;
-    unsigned xti, yti;

     // cpu-to-video BLT
     if (BX_CIRRUS_THIS bitblt.memsrc_needed > 0) {
@@ -776,15 +767,9 @@ void bx_svga_cirrus_c::mem_write(bx_phy_address addr, Bit8u value)
         }
       }
       BX_CIRRUS_THIS svga_needs_update_tile = 1;
-      xti = ((offset % BX_CIRRUS_THIS svga_pitch) / (BX_CIRRUS_THIS svga_bpp / 8)) / X_TILESIZE;
-      yti = (offset / BX_CIRRUS_THIS svga_pitch) / Y_TILESIZE;
-      if (BX_CIRRUS_THIS s.y_doublescan) {
-        yti <<= 1;
-      }
-      if (BX_CIRRUS_THIS svga_double_width) {
-        xti <<= 1;
-      }
-      SET_TILE_UPDATED(BX_CIRRUS_THIS, xti, yti, 1);
+      SET_TILE_UPDATED(BX_CIRRUS_THIS,
+        (BX_CIRRUS_THIS svga_double_width + 1) * ((offset % BX_CIRRUS_THIS svga_pitch) / (BX_CIRRUS_THIS svga_bpp / 8)) / X_TILESIZE,
+        (BX_CIRRUS_THIS s.y_doublescan + 1) * (offset / BX_CIRRUS_THIS svga_pitch) / Y_TILESIZE, 1);
     }
   } else if (addr >= 0xB8000 && addr < 0xB8100) {
     // memory-mapped I/O. 
vruppert commented 7 months ago

In the meantime I have also found a way for correctly marking the tiles. Doubling the x/y values is the right way to do this. Your code would also work, but I saw it after applying changes.

vruppert commented 7 months ago

Now we need to know whether or not the original issue is fixed.

Vort commented 7 months ago

For me low resolution support looks good now.