VOGONS


QEMU 3Dfx Glide Pass-Through

Topic actions

Reply 120 of 242, by kjliew

User metadata
Rank Oldbie
Rank
Oldbie

Those errors were fixed. They are caused by `make clean`. There isn't any different for strip between host and cross toolchain when both were from GCC, but not when host was Clang. GNU and BSD findutils couldn't have agreed with each other on the syntax, damn!

I supposed Win2K/XP should work for HVF and that was already a huge advantage of running old games, though not in pristine condition. It is much easier to patch Win9x games to work in Win2K/XP. Windows 10 WHPX can only work when Win2k/XP was setup with ACPI Standard PC kernel. You can see if it is also true for HVF. Usually, it would just BSOD right during Win2k/XP installation in the very beginning with acceleration. So one has got to be patient to complete the OS installation in QEMU TCG, first boot into desktop and install all the drivers (if any) and finally switch the OS kernel to ACPI standard PC. Otherwise, setup the Win2k/XP VM in beefy Linux box with QEMU KVM, it will have everything done in less than 20mins. The QEMU qcow2 format supports sparse image so transferring the image after a fresh Win2k/XP VM setup is not going to take a long time over wired/WiFi network.

That's how one loves playing with VMs and have all of them handy, Win98SE, WinME, Win2K and WinXP rather than having 4 retro PCs for each of them. 😉

Reply 121 of 242, by Bruninho

User metadata
Rank Oldbie
Rank
Oldbie
kjliew wrote on 2021-07-16, 02:39:

Those errors were fixed. They are caused by `make clean`. There isn't any different for strip between host and cross toolchain when both were from GCC, but not when host was Clang. GNU and BSD findutils couldn't have agreed with each other on the syntax, damn!

These are some of the moments where I could agree. macOS being based on BSD and a (very) distant cousin of Ubuntu (a unix-like linux distro), is sometimes a problem... exactly when things like these happens. In an ideal world, if macOS were closer to linux than BSD, it could be a great thing for developers, but I think it doesn't fit Apple's business model. However, they (I mean, stakeholders) seem not to care about whatever is under the hood on macOS, as long as their market share grows and users pay for it.

I am not a hardcore apple fanboy and neither a purist; I give Apple credit where its due, and I criticize them when I think something is wrong. Sometimes Ubuntu is great. Sometimes macOS is great. Recently, the linux kernel was updated to support the M1. However, it is still very recent and I have no idea if a dual boot is possible, or if we are forced to choose one or another, but a dual boot would be the ideal scenario. Anyway, the M1 can run Ubuntu natively, I saw it on youtube.

kjliew wrote on 2021-07-16, 02:39:

I supposed Win2K/XP should work for HVF and that was already a huge advantage of running old games, though not in pristine condition. It is much easier to patch Win9x games to work in Win2K/XP. Windows 10 WHPX can only work when Win2k/XP was setup with ACPI Standard PC kernel. You can see if it is also true for HVF. Usually, it would just BSOD right during Win2k/XP installation in the very beginning with acceleration. So one has got to be patient to complete the OS installation in QEMU TCG, first boot into desktop and install all the drivers (if any) and finally switch the OS kernel to ACPI standard PC. Otherwise, setup the Win2k/XP VM in beefy Linux box with QEMU KVM, it will have everything done in less than 20mins. The QEMU qcow2 format supports sparse image so transferring the image after a fresh Win2k/XP VM setup is not going to take a long time over wired/WiFi network.

That's how one loves playing with VMs and have all of them handy, Win98SE, WinME, Win2K and WinXP rather than having 4 retro PCs for each of them. 😉

I Have a VMware Windows XP VM fully updated and ready, same games installed there. I think that I could transfer that VM to QEMU. Probably a matter of uninstalling the drivers from Device Manager before shutdown to let it detect everything on QEMU boot? That VMware XP VM is already heavily customized (theme) to look like 9x thanks to Inexperience Patcher. So it looks like a fantasy Windows 2002 Professional rather than XP (well, actually XP Pro is "2002 Professional", if we think about a bit).

"Design isn't just what it looks like and feels like. Design is how it works."
JOBS, Steve.
List of ALL Android vulnerabilities
Right to Repair sucks and is illegal!

Reply 122 of 242, by Bruninho

User metadata
Rank Oldbie
Rank
Oldbie
kjliew wrote on 2021-07-16, 02:39:

Those errors were fixed. They are caused by `make clean`. There isn't any different for strip between host and cross toolchain when both were from GCC, but not when host was Clang. GNU and BSD findutils couldn't have agreed with each other on the syntax, damn!

Only one error this time, but let's see if it works now... meanwhile, for mesa, opengl32.dll was compiled without errors.

MacBruno-Pro:build Bruninho$ make && make clean
CC fxhook.o fxlib9x.o fxlibnt.o
CC gl211dll.o
CFLAGS -I../../../qemu-0/hw/3dfx -I../../fxlib -D__REV__="0cce1fa-" -Wall -Werror -msse2 -O3 -flto -fomit-frame-pointer
LDFLAGS -static-libgcc -Wl,--disable-auto-image-base -Wl,--dynamicbase -Wl,--nxcompat
RC glide_res.o
LD glide.dll
CC glidedll.o
CFLAGS -I../../../qemu-0/hw/3dfx -I../../fxlib -D__REV__="0cce1fa-" -Wall -Werror -msse2 -O3 -flto -fomit-frame-pointer
LDFLAGS -static-libgcc -Wl,--disable-auto-image-base -Wl,--dynamicbase -Wl,--nxcompat
RC glide2x_res.o
LD glide2x.dll
CC gl301dll.o
CFLAGS -I../../../qemu-0/hw/3dfx -I../../fxlib -D__REV__="0cce1fa-" -Wall -Werror -msse2 -O3 -flto -fomit-frame-pointer
LDFLAGS -static-libgcc -Wl,--disable-auto-image-base -Wl,--dynamicbase -Wl,--nxcompat
RC glide3x_res.o
LD glide3x.dll
make[1]: *** No rule to make target `QEMU'. Stop.
make: *** [fxdrv] Error 2

I can't tell if it is working because there is no log on terminal telling me if Glide is active or not, like it happens when I tested on Ubuntu VM. But the machine is helluva slow as Rubens "The Turtle" Barrichello. I have even enabled HVF and bumped the CPU from Pentium3 to Celeron to be able to use HVF. As it is now, I would be better off playing these games in software mode or on VMware.

"Design isn't just what it looks like and feels like. Design is how it works."
JOBS, Steve.
List of ALL Android vulnerabilities
Right to Repair sucks and is illegal!

Reply 123 of 242, by kjliew

User metadata
Rank Oldbie
Rank
Oldbie
Bruninho wrote on 2021-07-16, 04:02:
[…]
Show full quote
make[1]: *** No rule to make target `QEMU'.  Stop.
make: *** [fxdrv] Error 2

This does not make sense. Start from a clean state and repeat Step #3.

Bruninho wrote on 2021-07-16, 04:02:

I can't tell if it is working because there is no log on terminal telling me if Glide is active or not, like it happens when I tested on Ubuntu VM.

Try something simple. If there was no "DLL loaded" in the console logs, then the fresh built QEMU just couldn't find the dylib to load, either it was the Host OpenGL or the OpenGlide you just built. Or, the dylib couldn't load due to other dylib that it depends on. Go back and read how typical console logs should look like.

Do a "--version" to make sure the right QEMU was called in the run script since you also have vanilla QEMU installed somewhere.

Or, you forgot to `sign_commit` and rebuilt QEMU after re-sync'ed GitHub at new commit with the wrappers at new commit id.

Sigh ... this project is really evil ... 😉 Full of minefield to blow away one's precious time & sleep ... 🤣

Last edited by kjliew on 2021-07-16, 07:59. Edited 1 time in total.

Reply 124 of 242, by Bruninho

User metadata
Rank Oldbie
Rank
Oldbie

Wrappers compiled without errors, this time they seem OK. I have even rebuilt QEMU from scratch as well, and I ran the 'sign_commit' command as well. No changes. Must be OpenGlide the problem now. I'll try to rebuild OpenGlide.

I know how the log should look like because I see them on terminal when I used the Ubuntu VM yesterday. But when I look at the terminal on macOS, nothing happens.

*scratches head*

"Design isn't just what it looks like and feels like. Design is how it works."
JOBS, Steve.
List of ALL Android vulnerabilities
Right to Repair sucks and is illegal!

Reply 125 of 242, by kjliew

User metadata
Rank Oldbie
Rank
Oldbie

Try to install into /usr/local/lib.
Here's mine.

MacBook-Air: /usr/local/lib
$ ls -la
total 1408
drwxr-xr-x 7 root wheel 224B May 17 22:21 ./
drwxr-xr-x 3 root wheel 96B May 24 18:57 ../
-rwxr-xr-x 1 root wheel 348K Jun 11 00:47 libglide2x.0.dylib*
lrwxr-xr-x 1 root wheel 33B May 15 04:34 libglide2x.dylib@ -> /usr/local/lib/libglide2x.0.dylib
-rwxr-xr-x 1 root wheel 348K Jun 11 00:47 libglide3x.0.dylib*
lrwxr-xr-x 1 root wheel 33B May 15 13:34 libglide3x.dylib@ -> /usr/local/lib/libglide3x.0.dylib

This is my way that works for me. There are many ways for dealing with dynamic loading dylib on macOS. I am a newbie in macOS. Perhaps other more pro-Mac users can chime in their ideas how this should be done properly.

Reply 126 of 242, by Bruninho

User metadata
Rank Oldbie
Rank
Oldbie

They are in the same directory structure as yours. It’s the standard since Catalina, bin and lib as well as includes go under /usr/local/lib, /usr/local/bin and /usr/local/include. Because /usr/bin and others are system protected and cannot be modified.

I think the problem is SDL. I cheated before using a custom brew formulae with the parameters supposed to build and install with X11 support. Which version of SDL are you using? OpenGlide log complains about no availabile SDL video device

I have to sleep, 5AM now and I need to be up 9:30AM for remote team call. I’ll share the brew formulae later to see if something is wrong.

Cya

"Design isn't just what it looks like and feels like. Design is how it works."
JOBS, Steve.
List of ALL Android vulnerabilities
Right to Repair sucks and is illegal!

Reply 127 of 242, by kjliew

User metadata
Rank Oldbie
Rank
Oldbie

No SDL is required for OpenGlide. Go back & read Step #1 one more time.

$ OTool -L /usr/local/lib/libglide2x.dylib 
/usr/local/lib/libglide2x.dylib:
/usr/local/lib/libglide2x.0.dylib (compatibility version 1.0.0, current version 1.0.0)
/opt/X11/lib/libSM.6.dylib (compatibility version 7.0.0, current version 7.1.0)
/opt/X11/lib/libICE.6.dylib (compatibility version 10.0.0, current version 10.0.0)
/opt/X11/lib/libX11.6.dylib (compatibility version 11.0.0, current version 11.0.0)
/opt/X11/lib/libXxf86vm.1.dylib (compatibility version 2.0.0, current version 2.0.0)
/opt/X11/lib/libGL.1.dylib (compatibility version 4.0.0, current version 4.0.0)
/opt/X11/lib/libGLU.1.dylib (compatibility version 5.0.0, current version 5.1.0)
/System/Library/Frameworks/OpenGL.framework/Versions/A/OpenGL (compatibility version 1.0.0, current version 1.0.0)
/usr/lib/libc++.1.dylib (compatibility version 1.0.0, current version 905.6.0)
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1292.100.5)

Reply 129 of 242, by Bruninho

User metadata
Rank Oldbie
Rank
Oldbie
kjliew wrote on 2021-07-16, 08:20:
No SDL is required for OpenGlide. Go back & read Step #1 one more time. […]
Show full quote

No SDL is required for OpenGlide. Go back & read Step #1 one more time.

$ OTool -L /usr/local/lib/libglide2x.dylib 
/usr/local/lib/libglide2x.dylib:
/usr/local/lib/libglide2x.0.dylib (compatibility version 1.0.0, current version 1.0.0)
/opt/X11/lib/libSM.6.dylib (compatibility version 7.0.0, current version 7.1.0)
/opt/X11/lib/libICE.6.dylib (compatibility version 10.0.0, current version 10.0.0)
/opt/X11/lib/libX11.6.dylib (compatibility version 11.0.0, current version 11.0.0)
/opt/X11/lib/libXxf86vm.1.dylib (compatibility version 2.0.0, current version 2.0.0)
/opt/X11/lib/libGL.1.dylib (compatibility version 4.0.0, current version 4.0.0)
/opt/X11/lib/libGLU.1.dylib (compatibility version 5.0.0, current version 5.1.0)
/System/Library/Frameworks/OpenGL.framework/Versions/A/OpenGL (compatibility version 1.0.0, current version 1.0.0)
/usr/lib/libc++.1.dylib (compatibility version 1.0.0, current version 905.6.0)
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1292.100.5)

I might as well try again, yes. I can generate a log for each configure & make just so we can have a look and see if something is missing or wrong. Can you just tell me how to generate them?

I'll post an otool like yours for it, in a moment after the 2nd team call of the day (happening right now).

"Design isn't just what it looks like and feels like. Design is how it works."
JOBS, Steve.
List of ALL Android vulnerabilities
Right to Repair sucks and is illegal!

Reply 130 of 242, by Bruninho

User metadata
Rank Oldbie
Rank
Oldbie
kjliew wrote on 2021-07-16, 08:20:
No SDL is required for OpenGlide. Go back & read Step #1 one more time. […]
Show full quote

No SDL is required for OpenGlide. Go back & read Step #1 one more time.

$ OTool -L /usr/local/lib/libglide2x.dylib 
/usr/local/lib/libglide2x.dylib:
/usr/local/lib/libglide2x.0.dylib (compatibility version 1.0.0, current version 1.0.0)
/opt/X11/lib/libSM.6.dylib (compatibility version 7.0.0, current version 7.1.0)
/opt/X11/lib/libICE.6.dylib (compatibility version 10.0.0, current version 10.0.0)
/opt/X11/lib/libX11.6.dylib (compatibility version 11.0.0, current version 11.0.0)
/opt/X11/lib/libXxf86vm.1.dylib (compatibility version 2.0.0, current version 2.0.0)
/opt/X11/lib/libGL.1.dylib (compatibility version 4.0.0, current version 4.0.0)
/opt/X11/lib/libGLU.1.dylib (compatibility version 5.0.0, current version 5.1.0)
/System/Library/Frameworks/OpenGL.framework/Versions/A/OpenGL (compatibility version 1.0.0, current version 1.0.0)
/usr/lib/libc++.1.dylib (compatibility version 1.0.0, current version 905.6.0)
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1292.100.5)
MacBruno-Pro:~ Bruninho$ otool -L /usr/local/lib/libglide2x.dylib
/usr/local/lib/libglide2x.dylib:
/usr/local/lib/libglide2x.0.dylib (compatibility version 1.0.0, current version 1.0.0)
/opt/X11/lib/libX11.6.dylib (compatibility version 11.0.0, current version 11.0.0)
/opt/X11/lib/libXxf86vm.1.dylib (compatibility version 2.0.0, current version 2.0.0)
/opt/X11/lib/libGL.1.dylib (compatibility version 4.0.0, current version 4.0.0)
/opt/X11/lib/libGLU.1.dylib (compatibility version 5.0.0, current version 5.1.0)
/System/Library/Frameworks/OpenGL.framework/Versions/A/OpenGL (compatibility version 1.0.0, current version 1.0.0)
/usr/lib/libc++.1.dylib (compatibility version 1.0.0, current version 905.6.0)
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1292.100.5)

OK, looks like I am missing these two?
/opt/X11/lib/libSM.6.dylib (compatibility version 7.0.0, current version 7.1.0)
/opt/X11/lib/libICE.6.dylib (compatibility version 10.0.0, current version 10.0.0)

"Design isn't just what it looks like and feels like. Design is how it works."
JOBS, Steve.
List of ALL Android vulnerabilities
Right to Repair sucks and is illegal!

Reply 132 of 242, by Bruninho

User metadata
Rank Oldbie
Rank
Oldbie
kjliew wrote on 2021-07-16, 21:54:

Show me your `qemu --version`. I will provide TEST04 with DOS OVL signed with the same commit id for simple test, since you can't build DOS32 OVL yourself.

My Win98.sh bash shell script that calls the whole command line for QEMU is calling the right qemu version: 5.2.0. This method works fine for all other QEMU VMs.

The vanilla QEMU when called "qemu-system-i386 --version" returns v6.0.0.
Our compiled version when called from "/Volumes/Bruninho HD/QEMU/bin/qemu-system-i386 --version" returns 5.2.0, also with the message saying it's patched for qemu-3dfx.

I am going to do two checks on my Win98.sh, one to see if I am correctly calling for SDL_VIDEODRIVER=x11, and one to see of I am calling the correct QEMU version; I am sure it is calling the right version, considering that I gave the whole full path to that version.

Then if it persists, let's try your TEST04 stuff... Gimme a couple of minutes.

EDIT: Also, FYI, you might want to try the following to see if ctrl + alt +g can lock/unlock the mouse under this whole X11 method, saw it on another forum:

Also, you might want to enable "Option keys send Alt_L and Alt_R" in the X11.app preferences. You won't be able to unlock the mouse otherwise.

"Design isn't just what it looks like and feels like. Design is how it works."
JOBS, Steve.
List of ALL Android vulnerabilities
Right to Repair sucks and is illegal!

Reply 133 of 242, by Bruninho

User metadata
Rank Oldbie
Rank
Oldbie

Results of most recent run, running the qemu, openglide and wrappers I had compiled last night. This happens when I attempt to run FIFA 98 RTWC:

MacBruno-Pro:QEMU Bruninho$ ./Win98X11.sh
WARNING: Image format was not specified for 'Disks/Win98X11.img' and probing guessed raw.
Automatically detecting the format is dangerous for raw images, write operations on block 0 will be restricted.
Specify the 'raw' format explicitly to remove the restrictions.
glidept: DLL loaded - glide2x.dll
trace: _grSstQueryBoards@4 called
trace: _grGlideInit@0 called
glidept: 0cce1fa-03:00:40 Jul 16 2021 build WRAPFX32
wr2x_trace: _grSstQueryHardware@4
wr2x_trace: _grGlideGetVersion@4
glidept: grGlideGetVersion Glide 2.45 - OpenGLide 0.09rc9
wr2x_trace: _grGlideShutdown@0
glidept: grGlideShutdown called, fifo 0x0000 data 0x0000 shm 0x0040000 lfb 0xfb000000
glidept: GrState 0 VtxLayout 0
glidept: DLL unloaded
glidept: DLL loaded - glide2x.dll
trace: _grGlideInit@0 called
glidept: 0cce1fa-03:00:40 Jul 16 2021 build WRAPFX32
wr2x_trace: _grSstQueryHardware@4
wr2x_trace: _grSstSelect@4
glidept: grSstWinOpen called, fmt 0 org 0 buf 2 aux 1 gLfb 0xde6fb000
FBConfig id 0x08f visual 0x0f6 swapUndef
Xlib: extension "XFree86-VidModeExtension" missing on display "/private/tmp/com.apple.launchd.ydpgILV85Y/org.xquartz:0".
Xlib: extension "XFree86-VidModeExtension" missing on display "/private/tmp/com.apple.launchd.ydpgILV85Y/org.xquartz:0".
error: xp_attach_gl_context returned: 2
X Error of failed request: GLXBadContext
Major opcode of failed request: 149 (GLX)
Minor opcode of failed request: 26 (X_GLXMakeContextCurrent)
Serial number of failed request: 20
Current serial number in output stream: 20
MacBruno-Pro:QEMU Bruninho$

"Design isn't just what it looks like and feels like. Design is how it works."
JOBS, Steve.
List of ALL Android vulnerabilities
Right to Repair sucks and is illegal!

Reply 134 of 242, by kjliew

User metadata
Rank Oldbie
Rank
Oldbie

Alright, you got everything right in place this time, kudos! 👍

Sadly, we are now into the territory of crappy Intel OpenGL implementation. Now, you have everything right, can you try other games such as NFS2SEA or simple 3Dfx SDK TEST04?

Attach a log of `glxinfo` would also be helpful.

Reply 135 of 242, by Bruninho

User metadata
Rank Oldbie
Rank
Oldbie

FIFA 98 and FIFA 99 are both crashing. I am yet to try out NFS 2 SE.

Alright, NFS2SEA.EXE also crashes for the same reason.

As for 3dfx SDK TEST04, how?

Issuing a $ glxinfo | grep OpenGL on terminal return this:

OpenGL vendor string: Intel Inc.
OpenGL renderer string: Intel Iris OpenGL Engine
OpenGL version string: 2.1 INTEL-16.4.5
OpenGL shading language version string: 1.20
OpenGL extensions:

"Design isn't just what it looks like and feels like. Design is how it works."
JOBS, Steve.
List of ALL Android vulnerabilities
Right to Repair sucks and is illegal!

Reply 136 of 242, by kjliew

User metadata
Rank Oldbie
Rank
Oldbie
Bruninho wrote on 2021-07-16, 22:58:

As for 3dfx SDK TEST04, how?

VOGONS is your friend 😉

That kind of `glxinfo` does not help at all. Please attach the full log. Use `glxinfo | tee intelglx.log` and attach it.

Last edited by kjliew on 2021-07-16, 23:10. Edited 1 time in total.

Reply 137 of 242, by Bruninho

User metadata
Rank Oldbie
Rank
Oldbie
kjliew wrote on 2021-07-16, 23:06:

That kind of `glxinfo` does not help at all. Please attach the full log. Use `glxinfo | tee intelglx.log` and attach it.

OK, there you go:

Attachments

"Design isn't just what it looks like and feels like. Design is how it works."
JOBS, Steve.
List of ALL Android vulnerabilities
Right to Repair sucks and is illegal!

Reply 138 of 242, by kjliew

User metadata
Rank Oldbie
Rank
Oldbie

This is the problem. Without an Intel Mac at my side, I think you will be mostly on your own. Or, you will have to bear the grunts of C/C++ refresher course with me. 😉
Google is still your best friend, a few keywords suggestion for search, "GLX OpenGL", "OpenGL context GLX", "glX* functions".

error: xp_attach_gl_context returned: 2

Here's the unproven theory of the error. OpenGlide was trying to steal a GLX context which was already attached to the native window. I am not an expert in OpenGL and below are just my assumption of the behavior of OpenGL implementation. When the implementation forbids or doesn't like GL context reattachment, it should simply return the Visuals or FBConfigs that was already in used regardless of the attributes defined by the calls or do some magics in the data being returned for the software to end up choosing the same as current. And so the next call to make the GL context current could simply be handled as NOP and everyone was happy. NVIDIA OpenGL implementation is particularly good at this. When the software insisted the required GL context attributes, the implementation was left with 2 options, go ahead & do as the software demanded, likely resulted in unoptimized behaviors. Or, the implementation simply did as "What Mr. Torvalds had shown to NVIDIA" and called it quit. There is always an ideology wrestles on how to handle such scenarios especially OpenGL had been inevitably vague in GL context creation.

So let's hope Intel OpenGL would still honor GL context reattachment as long as the same attributes were requested. These are the experiments that lead to the search. You will have to recompile OpenGlide multiple times.

Case #1, the big hammer. Fall back to old glXChooseVisual by always-false the if(0).

In openglide/platform/linux/window.cpp: line 129:
if (0 && fbc && elements)

Here's the code for defining GL context attributes.

In openglide/platform/linux/window.cpp: line 112:
static const int attrib[] =
{
GLX_X_RENDERABLE , True,
GLX_DRAWABLE_TYPE , GLX_WINDOW_BIT,
GLX_RENDER_TYPE , GLX_RGBA_BIT,
GLX_X_VISUAL_TYPE , GLX_TRUE_COLOR,
GLX_RED_SIZE , 8,
GLX_GREEN_SIZE , 8,
GLX_BLUE_SIZE , 8,
GLX_DEPTH_SIZE , 24,
GLX_STENCIL_SIZE , 8,
GLX_DOUBLEBUFFER , True,
None
};

Case #2, completely remove line GLX_STENCIL_SIZE and try different GLX_DEPTH_SIZE. The 24 already failed, so try 32 and 16 decimal.
Case #3, completely remove both lines GLX_STENCIL_SIZE and GLX_DEPTH_SIZE. Hopefully, they will come back the same as current.

glidept: grSstWinOpen called, fmt 0 org 0 buf 2 aux 1 gLfb 0xde6fb000
FBConfig id 0x08f visual 0x0f6 swapUndef

If you will, I am interested to know the line for each experiments in #2 and #3.

Good Luck! 😎

Last edited by kjliew on 2021-07-17, 05:35. Edited 1 time in total.