Political Science

May 6th, 2008

Hey, would some folks mind not standing up for me on the MAMEWorld forums?  I don’t need a caped crusader swooping in to the rescue, least of all someone who has more than enough enemies himself.  I can read the boards just fine:

In fact, the only thing keeping me from registering on the MAMEWorld forums and informing all and sundry exactly how I feel is… well, I just don’t feel like it.  The MAMEWorld boards have been intentionally castrated ever since the majority of MAME Testers was moved off there.  Nowadays the only real attractions are the bi-weekly trolling tournaments to see who can whip Haze into the most livid froth and the tinfoil-hat Eurotrash liberal circle-jerk going on in the Loony Bin.  Crusades against Big Oil?  Moon Landing conspiracies?  9/11 conspiracies?  Check, check, aaaaaaand check.  Why the hell would I want to have anything to do with it?

Putting aside the fact that the boards have pretty much no redeeming qualities anymore anyway, who would want to participate in a forum that’s run by such a weeping bleeding-heart that even the most mongoloid posts need to be met with tea, cupcakes, sunshine, roses, and shitting rainbows from one’s ass?  Twisty is the teacher who, after the class retard shits in his hand and starts wiping it on the walls, scolds you for reeling in utter disgust at the human atrocity before you, admonishing you, “Now, now, you have no right to be upset, Mongo is trying his best - he deserves our respect and love!  He’s letting his inner artist run wild, good job, Mongo, good job!”

In short, fuck MAMEWorld, I have no particular desired to be in that festering backwater shithole of the Internet anyway.

Cover Charge

May 3rd, 2008

One of the few(?) remaining issues with MESS’s RDP implementation, at least in my local source tree, is a lack of coverage emulation. Tonight I made the first of several steps to supporting it by adding a partial implementation to the PIN64 Viewer. The downside is that if I ever submit this to MESS (and by association, MAME), the Aleck 64 games in MAME and the N64 driver in MESS will easily become the slowest drivers in their respective emulators.

The problem with proper coverage emulation is that in its current implementation the worst case is that video rendering is approximately 32 times slower than without coverage, the best case is approximately 16 times slower. The reason for this is that in order to calculate coverage, the N64 driver has to render internally at 4 times the original X resolution and 4 times the original Y resolution. Coverage is calculated by applying a 4×4 50% dither mask over the sub-pixels comprising a single pixel like so:

If one of the gray pixels in the above mask is occupied by the primitive that is being drawn, it adds 1 to the current coverage value, for an effective range of 1 to 8 (though it is stored as 0 to 7 in order to fit into three bits). The coverage functionality can additionally be modified by the Set Other Modes RDP command, which has four modes:

  1. Clamp coverage to 8
  2. Wrap coverage value with each successive primitive overdraw
  3. Force coverage value to 8 for each partially-covered pixel
  4. Don’t modify coverage at all

As such, MESS needs to render with quarter-pixel accuracy, first of all. Second of all, it is possible for the Blender to use the pixel’s coverage as the alpha value when blending the pixel. I cannot think of a decent alternative means of accomplishing this other than by rendering each pixel twice, first to accumulate the coverage value, then to actually blend the pixels themselves.

Now for the metric you readers are interested in: Frame rate.

While I haven’t hooked this into MESS itself yet, I can tell you that it is SLOW. Rendering a scene from Super Mario 64 with Mario standing outside Princess Peach’s castle now takes between two and three seconds in the PIN64 Viewer. For the sake of being able to debug the rest of the N64 driver, if and when I submit this to MESS I’m probably going to make it a compile-time switch so that it’s possible to turn on the less accurate, non-coverage implementation.

Yikes.

Grand Theft Chrono

April 29th, 2008

Thanks to a friend of mine buying me a copy of Grand Theft Auto IV, my time over the coming month or two is going to be a bit short when it comes to emulation-related hobbies.

In addition, I’ve wholly disabled registration (and therefore commenting) on this blog thanks to the dickless sons of bitches who think it’s a fantastic idea to advertise their shitty fly-by-night online casinos in the comments of my fucking blog. Fuck spammers, fuck their mothers, fuck the shitty governments of the third world countries that they live in that allow this sort of bullshit to thrive, and fuck the patently ignorant retirees, soccer moms, ditzy teens, and generally gullible jackasses who willfully infect their machines with trojans and thus add them to the ever-growing botnets used by these spammers because they lack the pair of brain cells to rub together to realize that perhaps they really shouldn’t be opening the attachments provided with emails advertising “free/ cia1iis v|agggra make your d1ck bigger rk209k20ko92dk9pw;sf”.

If you really need to get into contact with me, my contact info is on the parent page of this site.

Green Grass & High Tides

April 28th, 2008

ZZT32 seems to be doing… something… with homebrew as of late, and he sent a test case my way. Sure enough, it uncovered an issue with MESS’s implementation of 32-bit framebuffer mode.

Here’s what I first saw when plugging in the test case:

Thanks to a kindly-provided screenshot off of real hardware, it was easy to figure out that it’s actually supposed to look like this:

As it turns out, the now-WoW-addicted fellow who contributed the original N64 driver didn’t know that the N64 stores its 32-bit pixels in RGBA format, not ARGB format. A quick tweak to the VIDEO_UPDATE, BLENDER1_32, BLENDER2_32 and texture_rectangle_32bit functions, and everything’s fine!

Thanks again to ZZT32 for the helpful test case.

Going Mad(den)

April 26th, 2008

One issue that’s bugged me for a while now has been the fact that the majority of in-game graphics in Madden 64 are broken, displaying entirely in white.

As it turns out, Tiburon were saved from a broken game by the Nintendo 64 managing to do some modicum of error correction on the texture information that is uploaded to it. Madden 64 specifies most of its player and stadium textures as being in a format of either 4-bit RGBA or 8-bit RGBA. This is an invalid mode; RGBA textures must be either 16-bit or 32-bit.

After some digging, I found that the N64 silently treats such textures as 4-bit Color Indexed (palettized) or 8-bit Color Indexed. In addition, the current RDP implementation in MESS fails to emulate the fact that a 4-bit CI texture can select which of 16 different palettes to use; it’s hard-coded to index 0. After fixing this functionality, the game went from this:

To this:

I’m not sure what’s causing the purple corruption on the field, it looks fine in the PIN64 Viewer.

In addition, it fixes the field in Madden 2001 as well:

Simple fixes, big results.

I Am At Fucking Work, And I Am Usually Right

April 25th, 2008

During the hours of 8AM to 5PM EST, Monday through Friday, I am at fucking work. I know I’m on AIM, my coworkers use AIM to communicate, it isn’t an open invitation to start asking me questions about emulating the Nintendo 64. If you start asking me questions regarding the Nintendo 64, its hardware, peripherals for it, emulating it, developing for it, or whatever between those hours on those days, expect me to be a bit short with you, because I am at fucking work. If it’s a quick question, I will probably answer it, but if you start to argue with me, expect me to tell you to fuck off. Because I am at fucking work.

As a somewhat related topic, keep this in mind: When it comes to the Nintendo 64, I am usually right. I have evaluated the number of times that I have corrected someone else’s Nintendo 64-related code versus the number of times someone has corrected mine, and I have also evaluated the number of times I have lost debates regarding the abilities or disabilities of the Nintendo 64’s hardware, and I am right far more than 50% of the time - ergo, usually. If you disagree with information that I give you, then the onus is on you to attempt to prove me wrong. If you attempt to prove me wrong and I in turn come up with a weightier burden of proof that I am right, then I am not being “anal retentive”, nor am I being “a nutjob”. I’m being right.

Bicycle

April 20th, 2008

Two-cycle texture lookups are completely wrong in MESS. Big shock, right?

The whole principle behind two-cycle texturing is that you can look up texels from independent textures in order to do clever things like masking, or not having to upload textures quite as often (upload two textures one time, then just change the combiner mode to switch textures). With the current implementation, we just copy the value of texel0 into texel1. Yeah, that’s kind of wrong. I fixed it.

This gets us from the current jumbled mish-mash for menu backgrounds in Paper Mario (see my previous blog post) to this:

The menu backgrounds aren’t supposed to be black, certainly, but it’s a start.

I’m stumped as to exactly why the menu backgrounds are black. More accurately, I know why they’re black, but I don’t yet know how to fix them. The problem is that the blender set-up never directly carries in the result from the color combiner, it uses the C_BLEND input. As best I can tell, that input is supposed to be what’s set by the Set Blend Color command. In this case, it’s set to black.

The only thing I can come up with is that the “Force Blend” bit in the Set Other Modes command has some sort of effect on the Blend Color register’s contents. It’s something I’ll have to verify on real hardware.

Edit 8:17PM -

Oh, hey, my theory paid off. Apparently Force Blend forces the Blend Color register to carry in the Color Combiner output. I’m not really quite sure why, but it seems to fix Paper Mario without horrendously breaking anything else:

Mirror, Mirror on the Wall

April 20th, 2008

Just a quick fix this morning for texture masking and mirroring. Fixes some shadows and some other miscellaneous stuff. The fix this time around is that if the bit specified by the S or T mask value plus one is 1 and mirroring is enabled for S or T, then that bit and all lower bits are inverted.

In plain English, with an S mask bit of 3, the following sequence of texture coordinates:

0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15

…would become:

0, 1, 2, 3, 4, 5, 6, 7, 7, 6, 5, 4, 3, 2, 1, 0

Simple! Among other things, I’m sure, this fixes things like shadows (depending on how a game rendered its shadows), some visual effects, some car textures, and such. Before:

Castlevania - Legacy of Darkness VFX (click for big)

Paper Mario - Curtains

California Speed - Car Textures

Army Men - Sarge’s Heroes 2 - Shadow tiling

Aaaaand after:

Good stuff! My next goal is to fix the rest of Paper Mario’s menu system.

Satisfaction

April 17th, 2008
“Ray, if someone asks if you are a God, you say YES!

As it turns out, the RDP will clamp to either 0 or 255 depending on the result of (A - B) * C in cases where (A - B) results in a negative number.

If the resulting value is negative and in the range -1 to -128, the value is clamped to 0. If the value is negative and in the range -129 or greater, the resulting value will be clamped to 255.

As an additional fix, the current Blender functionality in two-cycle mode in MESS is broken; the Pixel Color mux should take in the result from cycle 2 of the color combiner, not cycle 1. If you think about it, it makes sense - for the second Bldner cycle, the Pixel Color mux is replaced by the result from the first Blender cycle, ergo, BLENDER2_16 and BLENDER2_32 in MESS accomplishes nothing when it puts the cycle 2 result from the Color Combiner into the Pixel Color mux just before executing the second blend cycle, as it can’t be used in the second blend cycle anyway.

Combination

April 16th, 2008
“Ray, pretend for a moment that I don’t know anything about metallurgy, or engineering, or physics, and just tell me what the hell is going on.”

Right now I’m trying to figure out why The Legend of Zelda: Ocarina of Time’s boot screen has a frankly wrong color scheme, looking like this:

The problem, as far as I can tell, is that this boot screen uses one of the most complex Color Combiner setups that anything that boots in MESS attempts to use. Essentially, the N is supposed to have each face tinted to be the usual red / green / blue / yellow color scheme of the Nintendo 64 ‘N’ logo, with an environment-mapped texture blended onto the face with its own per-face tint as well.

The Color Combiner (CC) setup used in this scene is as follows:

Cycle 0 Color: ( C_TEX0 - C_PRIM ) * A_ENV + C_TEX0

Cycle 0 Alpha: 0 (simplified)

Cycle 1 Color: ( C_PRIM - C_ENV ) * C_COMBINED + C_ENV

Cycle 1 Alpha: 1 (simplified)

In plain (well, as plain as it can get) English, the Color Combiner implements the following equation for all four channels of a given pixel (R, G, B and A):

( A - B ) * C + D

For colors, A and B can be one of nine inputs (technically sixteen, but the last eight are the same):

  1. The combined color from the previous CC stage (C_COMBINED)
  2. The texel color from texture 0 (C_TEX0)
  3. The texel color from texture 1 (C_TEX1)
  4. The color stored in the Primitive Color register (C_PRIM)
  5. The triangle’s gouraud-shaded color for the current pixel (C_SHADE) (replaced by C_PRIM for non-triangle draw commands)
  6. The color stored in the Environment Color register (C_ENV)
  7. 1.0 (C_ONE)
  8. Randomized noise (C_NOISE, useful for static effects)
  9. 0.0 (C_ZERO, duplicated in selections 10-16)

For colors, C can be one of 17 inputs, (technically 32, but the last 16 are the same):

  1. The combined color from the previous CC stage (C_COMBINED)
  2. The texel color from texture 0 (C_TEX0)
  3. The texel color from texture 1 (C_TEX1)
  4. The color stored in the Primitive Color register (C_PRIM)
  5. The triangle’s gouraud-shaded color for the current pixel (C_SHADE) (replaced by C_PRIM for non-triangle draw commands)
  6. The color stored in the Environment Color register (C_ENV)
  7. The scaling value set by the Set Color Key command (color keying does not work on production N64 units)
  8. The combined alpha from the previous CC stage (A_COMBINED)
  9. The texel alpha from texture 0 (A_TEX0)
  10. The texel alpha from texture 1 (A_TEX1)
  11. The alpha value stored in the Primitive Color register (A_PRIM)
  12. The triangle’s gouraud-shaded alpha for the current pixel (A_SHADE) (replaced by A_PRIM for non-triangle draw commands)
  13. The alpha value stored in the Environment Color register (A_ENV)
  14. The fractional LOD value stepped from the triangle itself (LOD_FRAC, useful for blending between mipmaps of a texture)
  15. The fractional LOD value set by the most recent Set Primitive Color command (PRIM_LOD_FRAC, useful for blending between mipmaps of a texture)
  16. The K5 factor set by the most recent Set Convert command (CONV_K5, useful for hardware YUV conversion)
  17. 0.0 (duplicated in selections 18-32)

For colors, D can be one of eight inputs:

  1. The combined color from the previous CC stage (C_COMBINED)
  2. The texel color from texture 0 (C_TEX0)
  3. The texel color from texture 1 (C_TEX1)
  4. The color stored in the Primitive Color register (C_PRIM)
  5. The triangle’s gouraud-shaded color for the current pixel (C_SHADE) (replaced by C_PRIM for non-triangle draw commands)
  6. The color stored in the Environment Color register (C_ENV)
  7. 1.0 (C_ONE)
  8. 0.0 (C_ZERO)

For alpha values, A and B can be one of eight inputs:

  1. The combined alpha from the previous CC stage (A_COMBINED)
  2. The texel alpha from texture 0 (C_TEX0)
  3. The texel alpha from texture 1 (C_TEX1)
  4. The alpha value stored in the Primitive Color register (A_PRIM)
  5. The triangle’s gouraud-shaded alpha for the current pixel (A_SHADE) (replaced by A_PRIM for non-triangle draw commands)
  6. The alpha value stored in the Environment Color register (A_ENV)
  7. 1.0 (A_ONE)
  8. 0.0 (A_ZERO)

For alpha values, C can be one of eight inputs:

  1. The fractional LOD value stepped from the triangle itself (LOD_FRAC, useful for blending between mipmaps of a texture)
  2. The texel alpha from texture 0 (C_TEX0)
  3. The texel alpha from texture 1 (C_TEX1)
  4. The alpha value stored in the Primitive Color register (A_PRIM)
  5. The triangle’s gouraud-shaded alpha for the current pixel (A_SHADE) (replaced by A_PRIM for non-triangle draw commands)
  6. The alpha value stored in the Environment Color register (A_ENV)
  7. The non-fractional LOD value set by the most recent Set Primitive Color command (PRIM_LOD, useful for blending between mipmaps of a texture)
  8. 0.0 (A_ZERO)

For alpha values, D can be one of eight inputs. For the sake of brevity I’ll simply say that they’re the alpha equivalents of D’s inputs in the color equation.

All of this is pretty well-known already. That isn’t really the problem. The problem is figuring out how to handle overflow and underflow in the CC equation. I feel like I’m hitting my head against a brick wall, because none of the sensible answers that I’ve come up with so far seem to correspond to what actually happens on real hardware.

To simplify things a little, let’s concentrate on the left side of the N.

When the triangles in that face are drawn, the state of the Primitive Color register is 0xffaaffff (A255, R170, G255, B255) and the state of the Environment Color register is 0×80003296 (A128, R0, G50, B150).

To simplify things further, let’s kick the N64 into single-cycle mode and change the Cycle 0 Color equation to:

( C_ENV - C_PRIM ) * A_PRIM + C_ZERO

Since A_PRIM is 255 in this case, we can assume the equation simplifies further to just:

C_ENV - C_PRIM

With that in mind, filling the numbers in, we get:

  • R: 0 - 170 = -170
  • G: 50 - 255 = -205
  • B: 150 - 255 = -105

On real hardware, we get:

As it stands, I’m at a loss as to how this manages to reduce down to yellow:

  • If underflowing values are saturated to zero, then the color should be black.
  • If the low 8 bits of the result are masked off prior to multiplication, then we get 0×00563397 (R:86, G:51, B:151), which doesn’t look anything like bright yellow.
  • If the low 8 bits of the result are used after the multiplication, then we get 0×00AACD69 (R:170, G:205, B:105), which is a yellow-green color. Your first reaction may be to say that we’re getting closer, but none of the other faces are even close using that method, and it breaks Color Combiner functionality in pretty much all other cases as well.

I can’t think of any other ways this could work.

Can you? Post in the comments section if you think you have it sussed.