5

We're maintaining an old video game that uses a full-screen 256-color graphics mode with DirectDraw. The problem is, some applications running in the background sometimes try to change the system palette while the game is running, which results in corrupted graphics.

We can (sometimes) detect when this happens by processing the WM_PALETTECHANGED message. A few update versions ago we added logging (just log the window title/class/process name), which helped users identify offending applications and close them. MSN Live Messenger was a common culprit.

The problem got worse when we found out that Windows Vista (and 7) does it "by itself". The WM_PALETTECHANGED parameters point towards CSRSS and the desktop window. In Vista, a workaround that often worked was to open any folder (Computer, Documents, etc.) and leave it open while running the game. Sounds ridiculous, but it worked - in most cases. In Windows 7, not even this workaround worked any more. Users found that stopping some services (Windows Update and the indexing service) also resolved the problem on some configurations.

Some time ago I just started trying random things in hope of finding a solution. I found that setting the GDI palette (using Create/SelectPalette) before setting the DirectDraw palette (using IDirectDrawPalette::SetEntries) would restore the palette after it became corrupted (WM_PALETTECHANGED handler). SetSystemPaletteUse and calling SetPalette on the primary surface helped some more. However, there is still perceivable flickering when an application tries to steal the palette, which is especially prominent during fades.

Question: is there a way to get a "real" exclusive palette, which completely disallows other applications changing the Windows palette as long as our game retains focus?

Vladimir Panteleev
  • 24,651
  • 6
  • 70
  • 114

5 Answers5

3

What you can do is a 'simple' workaround. Since your game is an old game it is probably no match to current hardware, which is why this trick will work:

  • Blit everything to an offscreen buffer (memory)
  • convert the 8bit buffer to 16 bit(or 32 bit) using the current palette (so also done in memory)
  • copy the contents of the 16 bit(or 32bit) buffer to the backbuffer of the screen
  • flip the screenbuffer.

This will require minimal changes to your game, and will get rid of palette issues completely, though your game can still use all it's palette trickery

R

Toad
  • 15,593
  • 16
  • 82
  • 128
  • There's someone doing that for the first two Command & Conquer games (C&C1 and Red Alert 1), by making a ddraw.dll override. Worked pretty nicely, and added windowed mode too (after some hacks to adapt the mouse offset functions, to compensate for the now-variable 0,0 offset). Project info at http://hifi.iki.fi/cnc-ddraw/ – Nyerguds Nov 13 '10 at 13:37
  • This is what we ULTIMATELY went through with, but it didn't come cheap. Some users reported *triple* CPU usage because of the software palette transformation. – Vladimir Panteleev Sep 20 '12 at 10:19
  • @CyberShadow Then you might be doing it wrong. The transformation can be done using a really tight loop using just lookups. If you want I could check your code. – Toad Sep 21 '12 at 14:16
  • I'm quite sure the code is OK - here's the loop: `for ( int i=0; i < iSize; i++ ) *(pDst++) = pPalette[ *(pSrc++) ];` The problem is doing this at 60 FPS on HD resolutions and not-so-modern PCs. – Vladimir Panteleev Sep 22 '12 at 01:20
  • @CyberShadow That code looks fine indeed. I was afraid you were perhaps using multiplications or even 'getpixel/putpixel' in a loop. BTW Never looked at it, but on a GPU this routine should be trivial to implement... – Toad Sep 23 '12 at 12:35
  • 2
    Not-so-modern PCs have no business using HD resolutions :p – Nyerguds Oct 05 '12 at 11:26
1

Someone actually found a registry entry fix for this, here:

http://answers.ea.com/t5/Command-Conquer-The-Ultimate/Common-Problems-Read-This-Before-Posting/m-p/222052

Look for "scrambled colours" on that page and you'll get to the part with the fix you need.


Since online resources are fleeting, though, here's the full explanation:

Make a new key under "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\DirectDraw\Compatibility\" for the program.

If the program you're applying the compatibility for is a 32-bit program, and you're on a 64-bit system (either applying it manually or through a 64-bit program), don't forget to add the "Wow6432Node" between "Software" and "DirectDraw" to compensate for that.

In that key, set these values:

  • "Flags" (REG_BINARY) : [00,08,00,00]
  • "Name" (REG_SW) : File name of your program. No path, just the executable file name.
  • "ID" (REG_BINARY) : DirectDraw ID of the application.

To get the required DirectDraw ID, run the program and then check this registry key:

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\DirectDraw\MostRecentApplication

Again, if you're on a 64 bit system and the program you're doing this for is a 32-bit one, add the "Wow6432Node" after "Software".

The ID in that key is four bytes. Reverse their order to get the bytes to put in the ID value. 32dd83d5 becomes d5,83,dd,32.

Nyerguds
  • 5,360
  • 1
  • 31
  • 63
0

Apparently "an application should not call SetSystemPaletteUse, unless it has a maximized window and the input focus". Perhaps some other program is misbehaving. That description makes it sound very much like Microsoft hope all programs will cooperate and offer no way to compel them to do so. It's like being back on Windows 3.1. :)

Random suggestion: have you tried SetSystemPaletteUse with the SYSPAL_NOSTATIC256 parameter?

You could also see if your palette contains the 20 Windows reserved colours; if so, it means that any other palettised program that just uses Windows colours will not need to change the palette in order to render itself, as I understand it.

Kylotan
  • 18,290
  • 7
  • 46
  • 74
  • When the palette would get stolen, it would usually be the entire (or most of the visible) palette, so it probably wasn't an application setting SetSystemPaletteUse. We added a SetSystemPaletteUse(dc,SYSPAL_NOSTATIC256) call, and it helped in some situations, but hasn't resolved the main problem. Palette space is tight as it is, so we'd rather stay with our occasional flickering than repalletise game or user content. – Vladimir Panteleev Jul 01 '09 at 01:50
0

All you have to do is set your PC to 16 bit colours in Control Panel and the game comes right, works on Original Command and Conquer for me :D

Diosney
  • 10,520
  • 15
  • 66
  • 111
OcTiC
  • 1
  • 1
    This isn't a solution that can be applied by a video game. Also, this will not work for Windows versions starting with Windows 8, which no longer support color modes lower than True Color. – Vladimir Panteleev Jul 19 '13 at 22:06
  • 1
    Also you cannot set the displays color depth to 16-bit in Windows 8 and later. – Ray Jul 27 '13 at 10:04
  • Just FYI, there's [a ddraw override](http://hifi.iki.fi/cnc-ddraw/) created specifically for Command & Conquer that does the trick on all OSes. I'd advise just downloading [the full unofficial patch for the game](http://nyerguds.arsaneus-design.com/cnc95upd/cc95p106/), though; CnC-DDraw was optimized for it anyway :p – Nyerguds Dec 19 '13 at 09:27
0

I don't know DirectX at all, but I'd suggest trying to do your rendering off-screen then converting to the display depth... I imagine you can get Direct2D to do all that for you...

Spudd86
  • 2,986
  • 22
  • 20