xemu-project / xemu

Original Xbox Emulator for Windows, macOS, and Linux (Active Development)
https://xemu.app
Other
2.75k stars 275 forks source link

Midtown Madness 3 - Artifacts when using screen scaling #1771

Open kPYKx7Ddw4n1aIKZ opened 3 weeks ago

kPYKx7Ddw4n1aIKZ commented 3 weeks ago

Title

https://xemu.app/titles/4d53002a/#Midtown-Madness-3

Bug Description

I really enjoyed the first parts of Midtown Madness, so it’s disappointing that they only released Midtown Madness 3 for Xbox. The work you've done on the Xbox emulator is outstanding.

However, while using the scaling feature in Midtown Madness 3, I noticed some weird artifacts and couldn’t help but look into it further.

Have a look at this picture (screen scale x2): xemu-2024-09-04-07-13-38

Original resolution (640x480): xemu-2024-09-04-07-12-56

I looked around a bit with RenderDoc (great tool btw) and found a texture causing this issue which is used in some postprocessing step (I think it darkens the sky). The following texture is used in the original screen resolution (640x480), but this texture has the resolution (1280x480) and the format GL_R16. depth_stencil

It looks kinda weird and at first I was surprised, that it doesnt cause any artifacts in original and wondered what this texture was. After some investigation, I found out that this is orginally the depth stencil buffer, which is downloaded from the GPU in the pgraph_download_surface_data_to_buffer() method in the pgraph.c file with the original format GL_DEPTH24_STENCIL8 and the original resolution (640x480). Even when scaling the screen, it gets scaled down to this size and is saved somewhere (ram?).

Then this memory block is interpreted again as the previously found GL_R16 texture (with the only call to generate_texture in pgraph.c).

Now follows a trick that probably the original game developers did.

Since the screen resolution has only half the width of this texture and the texture gets mapped to the screen in the postprocessing step, only every second texel column gets read resulting in this depth like texture (this is the weird, distorted looking texture, just with every second texel column):

depth_extracted

As clever as it was for the original developers, it now becomes a problem when scaling.

The texture that is downloaded from GPU and reuploaded, remains at the original resolution (1280x480) with the screen size being (1280x960) and this trick doesnt work anymore and every second row is also read causing the artifacts.

I can also confirm this, by using this hackish code around the generate_texture method call in pgraph.c:

            uint8_t * tex_theft_buf = texture_data;

            if(width == 1280 && height == 480 && color_format == NV097_SET_TEXTURE_FORMAT_COLOR_LU_IMAGE_Y16) {
                size_t size = height*width*f.bytes_per_pixel;

                tex_theft_buf = malloc(size);
                memcpy(tex_theft_buf, texture_data, size);
                for(size_t idx = 0; idx < size; idx+=4) {
                    tex_theft_buf[idx] = tex_theft_buf[idx+2];
                    tex_theft_buf[idx+1] = tex_theft_buf[idx+3];
                }
            }

            key_out->binding = generate_texture(state, tex_theft_buf, palette_data);
            key_out->binding->data_hash = tex_data_hash;
            key_out->binding->scale = 1;

            if(width == 1280 && height == 480 && color_format == NV097_SET_TEXTURE_FORMAT_COLOR_LU_IMAGE_Y16) {
                free(tex_theft_buf);
            }

About what this does: It simulates exactly this behaviour of only reading every second texel column, by replacing the first texel by the content of the second one (be careful, we are talking about 16 bit texels here). I was lucky here, that there is only one texture with the size and the NV097_SET_TEXTURE_FORMAT_COLOR_LU_IMAGE_Y16 format so this hack-code actually worked and did no damage elsewhere.

And it worked (2x display resolution scale): xemu-2024-09-04-07-19-15

Of course, this code isnt suitable for the emulator (or you would have to rename it MM3-emu 😊).

I basically see two possible resolutions:

I don't know that much about the xemu emulator or the xbox in general, so i think its up to you, which one is the preferred option (or maybe another one). In the meantime, I'll play this gem in 2x resolution 😊.

Expected Behavior

No artifacts (look at the bug description).

xemu Version

Version: 0.7.132 Branch: master Commit: 8707d2aa2626063cb67b5ea20382584a0848dce7

System Information

OS: Windows 11 (also tested on Debian) CPU: Intel(R) Core(TM) i5-14600 GPU: NVIDIA GeForce RTX 4060

Additional Context

No response

hogfilho commented 2 hours ago

Hello everyone,

I am sending my contribution of a patch for the Vulkan branch (feat/vulkan) based on the suggestion provided by kPYKx7Ddw4n1aIKZ. With this patch, I am now able to comfortably experience the game at 5x resolution with approximately 30 FPS.

For those interested in testing it, I have attached the patch for application to the feat/vulkan branch.

Additionally, if you wish for the hotfix to function with the OpenGL backend as well, please ensure that you apply the fix suggested by kPYKx7Ddw4n1aIKZ.

Thank you!

mm3_5x

mm3_dirtyfix_vulkan.patch.txt