Next Generation Emulation banner

1 - 2 of 2 Posts

Premium Member
6,071 Posts
Discussion Starter · #1 · (Edited)
Okay, I know that this isn't exactly relevant or necessary, but this is my 3944th post here! I wanted to dedicate my 3911th post to something Xbox emulation related, but I forgot. Oh well, 3944 was an XDK version too (although only used in a dashboard update), so this will have to do :)

While I'm happy to see that actual GPU emulation is happening, I wanted to ask a few things.

1. Since you no longer need to emulate D3DDevice::CreateVertexBuffer, how are you storing vertex information? Via dynamic vertex buffer, or a growable heap array using DrawPrimitiveUP to render the vertices?

2. Are you still patching vertex shader creation functions or no?

3. Are you still patching D3DDevice::CreateIndexBuffer/SetIndices/DrawIndexedVertices[UP]?

The reason I'm asking is because I'm beginning to think that this type of emulation may be necessary to emulate Unreal Championship on Cxbx which crashes due to bogus vertex/index data and I can't figure out why :( If I can just fix this (and the gamepad problem) I can probably get the game playable. One reason I'm working on this game so much is because I'm interested in emulating Xbox system link and possibly emulate Xbox live (but don't get too excited about it though, I could fail). While getting Whacked playable itself was a major achievement considering that it's the first Xbox game with Xbox Live/System Link support to become playable on either Xbox emulator, I still would like to have more than one game to test that feature out on, if it does work.

Aside from that, I really like the idea of playing Unreal Championship on my PC over Unreal Tournament 2003 :)

Oh, and Patrick, expect a surprise soon in your email. Hopefully you can learn a thing or two from this. When you get it, feel free to share it with shadow too! :)

Shogun. :)

Premium Member
423 Posts
Ah, here come the real questions! Well, I'll send you my patch too, but I'll answer here for the public interest:

Since most D3D Create* API's do nothing scary, I can leave them all unpatched. They may allocate a resource record, populate it's fields, allocate a bit of contiguous memory - all fine by me. (The 2 exceptions to this are CreateStateBlock and CreateVertexShader, which I indeed keep patched just like before.)

Currently, I emulate via the Draw[Indexed]Vertices[UP] patches that are still in-place. In these, I gather all state (active textures, pixel shader, vertex & index buffers, render state, texture stage state) and convert & forward it all to native D3D8 (just the modified parts of course).

To gather this state, I currently still need the Setter/Getter patches, but I'm working on a way to read these directly from the g_pDevice structure (I'll probably use a mapping table to cater for version differences, much like how I already do for render states). So most state related Get*/Set* patches can be removed too then.

As for vertex buffers, I removed all patching related to QUADLIST/LINELOOP primitives. For quads, they are now emulated using either an indexed draw (drawing 2 triangles per quad) or using a repeated draw of 2 triangle's (1 call per quad). For line-loops, I just issue 2 calls : one to draw a LINELIST with the given vertices/indexes and one single line to close the loop.
So the only vertex-patching that remains, is the stream-patching for unsupported D3DVSDT cases (I just kept the old code for that).

What is different, is that I now let all Xbox resources have their own memory. This has the disadvantage that resource memory cost has doubled, but it gives two important advantages :
1) The data-conversion only takes place when copying to the native resource, cleanly separating the Xbox and native worlds.
2) It also makes it possible to check for resource data modifications (I haven't done this yet - I think I'll use an infrequently executed CRC check for this) and convert only when needed.

One of the things I had to do in order to allow D3DInit and CreateDevice to run unpatched, was to create 'make-pretend' GPU execution of the pushbuffer. For this, I added a thread that repeatedly sets the GPU's DMA 'Get' address to the current pushbuffers 'Put' address. This way, various busy-loops terminate quickly, allowing the rest of the code to run unmodified.
Now that I have that in-place, I have started to investigate how I can actually interpret the pushbuffer commands, so that I can emulate on that level (instead of patching the Draw methods). Once that starts to work, we could start thinking on migrating that to low-level emulation, by intercepting access violations on GPU memory (at a performance penalty no-doubt, but it would become even less dependant on patching).

The current state is, that I still cannot run the games we ran before, although many samples and homebrew now work better than ever! I hope some experienced people will help me out with the last few glitches, so that I can finally commit this patch, as it is really THE way forward in my view.

Thanks for reading, and don't hestitate to ask further.
1 - 2 of 2 Posts