Genesis / Mega Drive Emulator

Hello all,

i’ve been working on a little Emulator for some time now, and anyone interested can see/try it here:
http://www.workingdesign.de/projects/index.php

I am quite happy so far about the emulation part, which is already pretty accurate, but the sound needs definitely more work.
There are some issues though, since i switched to LWJGL for the rendering part. While it works for me in Windows/Linux and also for most others i talked to,
some ppl experience blank screens or crashes (just with the LWJGL renderer). I am using the AWTGLCanvas for the windowed mode and Display for fullscreen.
The problematic part lies within the initialization of the AWTGLCanvas, specially under Linux, as far as i can see - i cant reproduce the error here.

So… any feedback (except negative one ;D ) is welcome. I would also be interested if someone using a Mac can try it.

Ah and for some reason it refuses to work with any 1.6beta VM for me.

Thats awsome! Really nice…

I have the 1.6 betas on Linux and it works flawlessly with the ROM it came with…

Keep up the good work, i can enjoy Sonic now! wahay!

DP

Thanks, its good to hear something like good feedback for once :slight_smile:

You might not be able to enjoy Sonic though. The thing is, its not completely right that it doesnt work with the 1.6betas for me, just that there is some strange behaviour and i didnt find the reason yet.
Some games get to the Intro Screen using the 1.6beta, others dont do anything. From the integrated debugger i can see, that it is like it was using an early version of the cpu core, with the PC going out of bounds and illegal instructions being executed. The parts that could be responsible for that were changed a lot during the development of my emu, the effect is the same for all versions with the 1.6beta though.
I didnt test it with the new VM on Linux yet, so maybe it works there. I dont really now what is causing this.

Ummm, well for me the questionable honour to give some negative feedback then:
In windowed mode, I just see a white screen, and when I switch to full screen it barfs out the following stack trace:


Exception in thread "Thread-5" org.lwjgl.opengl.OpenGLException: Invalid value (1281)
        at org.lwjgl.opengl.Util.checkGLError(Util.java:56)
        at org.lwjgl.opengl.Display.update(Display.java:569)
        at jenesis.video.a.int(Unknown Source)
        at jenesis.a.a(Unknown Source)
        at jenesis.a.run(Unknown Source)
        at java.lang.Thread.run(Unknown Source)

In windowed mode, I hear sound, but it sounds like it suffers from buffer underruns.

Running winXP SP2, GF2, JRE 1.5.0_06

Tried it in window mode and the provided ROM showed only a blank screen with playing music. I tried to go into full screen mode and it freezed while switching the video mode. I was forced to kill the app to return to normal.

I’m running Win XP SP2 with a Xeon 2.8 GHz, 1 GB of RAM. The video card is nVidia Quadro NVS 64 MB. I was running Java 5_06.

Nice. Works fine here on WinXP, JDK 6.
Would you mind sharing the source for that 7z archive handler? Decoding a simple lzma stream can easily be done with the sdk, but I assume a 7z archive has some clever format and needs additional code.

hey runs great here, can play sonic 3 :slight_smile: but still slow atm, guess with more optimisation you can get it much faster speeds, currently i get only 15fps, however great work, always wanted to a nice mega drive emulator written in java :), keep up the good work!

Thanks all for testing.

I guess there is some kind of thread issue with LWJGL. Initially i just wanted to see how much faster it would be using it for the rendering part and for that i ‘raped’ my code to make it fit in there. I’ll rewrite those parts and properly implement it to hopefully resolve those problems.

About optimizing it, i dont think, much can be done. Of course there is always room for improvement, but i am also aiming for accuracy. The parts that need the most cpu time are already pretty much optimized and i dont think much more than 10% can be done. On my 1.8GHz athlon xp it runs at up to 120fps (depending on the game) without throtteling and i think anything faster than a 1.5GHz Athlon is needed for fullspeed. I will however include an option to switch between accurate and fast emulation, because a lot of things that slow it down a LOT are just needed by less than 5% of all games.

Yes, i spent a nice time, trying to figure that format out by the available documentation. I wanted to release that part publicly, although the code is horrible and it surely doesnt work with all .7z archives, but i am not completely sure about the licence part of it yet. I used the java_lzma which is LGPL as a base for my 7ZipInputStream class and asked the author about it, too. They were discussing it in the 7Zip forums, but i still really didnt get any answer. I dont know all too much about licences. I mentioned the use of the java_lzma in the readme and also provided links to the source, thinking that would be fine. If it is not, i will take that whole part out.
Anyone knows more about that?

I think LGPL means you can use the code in any project but if you modify the code itself you have to release the modified source. So, as long as you don’t change anything in the actual llzma sdk, I guess you don’t need to worry about it.

just tried on windows xp on another computer and i get the above error, for the system that i’m using now i know that it has problems with VBO’s, probably due to crappy graphics card or drivers, just wonder are you using VBO’s? could be the cause of the problems.

VBA’s kappa? You either mean VBO’s (Vertex Buffer Objects) or VA’s (Vertex Arrays) :stuck_out_tongue:

whoops sorry did mean VBO (Vertex Buffer Object), got mixed up since this is an emulator and there is an emulator called vba ;D

No, i am not using anything like that. I think the problem only lies in the initialization.
I would appreciate it, if anyone with those issues could try this:
http://www.workingdesign.de/projects/jEnesis%200.0.5b.zip

and also if there are any problems without LWJGL (you can switch to the awt renderer by setting LWJGL=false in the jEnesis.cfg), so i can make sure the problem isnt elsewhere.

Thanks :slight_smile:

I’ve set LWJGL flag to false and it worked perfectly, apart some white noise in music. The same type of noise you would notice if you play an audio cassette.

I’ll try your new version later…

I tried the new version but I’m afraid it didn’t make a difference for me (still a white screen).
Disabling LWJGL made it work, but sound was still not right. Disabling the high precision timer made it better, but there was still some noise and buffer underruns.

Hm. Too bad, i hoped erasing that one line would help something ;D The sound is my next thing on the list, once i sort out this problem with LWJGL.

What strikes me though, is that the screen is white, not black. How is it exactly? Is it white when you start the emu, or gets white, when you load a game?

Maybe someone has an idea of what could go wrong here?
I am basically subclassing an AWTGLCanvas and adding it to the Frame.
When a game is loaded, the main emulation loop starts in its own thread and calls the refresh method of the AWTGLCanvas each frame:


    public final void refresh(){        
        repaint();
    }

    public final void paintGL(){
        synchronized(this){
            try{                
                
                makeCurrent();
                if(!glrender.isInitialized()){
                    glrender.init(w, h);
                    return;
                }

                 // some irrelevant stuff

                glrender.render();
                swapBuffers();
                
            }catch(Exception e){
                e.printStackTrace();
            }
        }
    }

And this are the called methods of the renderer:


    public final boolean init(int width, int height){
        try{                                
            GL11.glViewport(0, 0, width, height);
            GL11.glMatrixMode(GL11.GL_PROJECTION);
            GL11.glLoadIdentity();
            GLU.gluPerspective(45.0f, ((float) width) / ((float) height), 0.9f, 20.0f);

            GL11.glMatrixMode(GL11.GL_MODELVIEW);
            GL11.glLoadIdentity();

            GL11.glShadeModel(GL11.GL_SMOOTH);

            GL11.glDisable(GL11.GL_CULL_FACE);

            GL11.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);

            GL11.glHint(GL11.GL_PERSPECTIVE_CORRECTION_HINT, GL11.GL_NICEST);

            GL11.glClear(GL11.GL_COLOR_BUFFER_BIT);

            GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL11.GL_CLAMP);
            GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL11.GL_CLAMP);
            GL11.glBindTexture(GL11.GL_TEXTURE_2D, pointer.get(0));                
                
            GL11.glEnable(GL11.GL_TEXTURE_2D);

            GL11.glGenTextures(pointer);
            if (pointer.get(0) == 0) {
                System.out.println("ERROR");
            }

            GL11.glBindTexture(GL11.GL_TEXTURE_2D, pointer.get(0));

            // Linear Filtering
            GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_LINEAR);
            GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_LINEAR);

            GL11.glTexImage2D(GL11.GL_TEXTURE_2D, 0, GL11.GL_RGBA, 320, 240, 0, GL11.GL_RGBA, GL11.GL_UNSIGNED_BYTE, buffer);                
                        
            initialized = true;
                                    
        } catch(Exception e){
            e.printStackTrace();
            return false;
        }
        return true;
    }
    
    
    public final void render(){
        GL11.glClear(GL11.GL_DEPTH_BUFFER_BIT | GL11.GL_COLOR_BUFFER_BIT);
        
        buffer.put(pixelbuffer);
        buffer.flip();
        GL11.glTexSubImage2D(GL11.GL_TEXTURE_2D, 0, 0, 0, 320, 240, GL11.GL_RGBA, GL11.GL_UNSIGNED_BYTE, buffer);

        GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL11.GL_CLAMP);
        GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL11.GL_CLAMP);
        
        GL11.glBegin(GL11.GL_QUADS);
        GL11.glNormal3f(0, 0, -1);

        GL11.glTexCoord2f(1.0f, 1.0f);
        GL11.glVertex3f(+width, -height, -7.2f);

        GL11.glTexCoord2f(0, 1.0f);
        GL11.glVertex3f(-width, -height, -7.2f);

        GL11.glTexCoord2f(0, 0);
        GL11.glVertex3f(-width, +height, -7.2f);

        GL11.glTexCoord2f(1.0f, 0);
        GL11.glVertex3f(+width, +height, -7.2f);
        GL11.glEnd();
    }    

Just a little update :wink:
I posted some screens here: http://www.workingdesign.de/projects/index.php .

I was working on a Java SH2 core and now the 32X is basically emulated. Its still a bit slow, but i am trying to change that…
The 32X is just a pretty powerful machine to emulate, probably needs more recources than the PSX even, with its dual SH2s, the Motorola68000 and a Z80 (same setup as in the Saturn). So i hope dynamic recompilation can help …

Looks awesome! :slight_smile:
I always heard that 32X emulation is pretty hard, especially to get it both fast and compatible.