BioShock Shader Model 2.0 Hack

Arne Olav Hallingstad
27th August 2007
Updated 17th August 2008

BioShock requires a shader model 3.0 card, but I couldn't help myself to try to install it and see what happened on my A64 3200+ with an ATI Mobility X700. It did run, no warnings about graphics card requirements during startup, but there were some major graphical corruptions seen once I started a new game that ruins the immersion a lot. Not unexpected as the graphics card is a SM 2.0b card.

There are a lot of people with shader model 2.0 cards that want to run BioShock and it was on one of the BioShock forums I found that it is possible to modify the shaders.

HLSL Shaders

BioShock shaders can be found in plain text in the shaders.spk (shader pak?), and the precompiled shaders for DX9 and DX10 can be found in the files with the pcs (precompiled shaders?) and pcs10 extensions respectively. The precompiled shaders are only used for reducing the map load time and can be ignored while hacking the shaders.

SPK Format

Reverse engineering the SPK format there seems to be a file header of 8 bytes:

01 00 00 00  28 00 00 00
typedef struct {
	int version; // (???)
	int numShaderFiles;
} pksHeader_t;

Each plain text HLSL entry seems to be preceded by a file entry header:

0x0008: AmbientDistortion.hlsl:	01 00 00 00 7d a9 8d 46 16 00 00 00 [filename 22 shorts] 39 12 00 00
0x127d: Base.hlsl:              01 00 00 00 85 30 97 46 09 00 00 00 [filename 9 shorts]  A8 0c 00 00
0x1f47: Canvas.hlsl:            01 00 00 00 9a f5 8a 46 0b 00 00 00 ...
0x2399: Common.hlsl:            01 00 00 00 2b c1 8c 46 0b 00 00 00 ...
0x2e40: DepthShadows.hlsl:      01 00 00 00 28 95 8c 46 11 00 00 00 ...

With a little thinking it is quite easy to figure out the file entry structure:

typedef struct {
	int type;                       // always 1 (entry type???)
	int unknown;                    // might be a timestamp or some reference for use in a shader tool?
	int fileNameLength;
	short fileName[fileNameLength]; // size of short * fileNameLength
	int fileSize;                   // size of the HLSL text directly after
} fileEntry_t;

Where fileName is the wide string file name of the file entry. After having read the file size, create and write the next fileSize bytes to the new file. Do so numShaderFiles times and you've extracted all the HLSL files. Here's a few of them:

I spent some time making sure the HLSL files compiled without problems on a SM 2.x target. Having to remove some graphical effects because of the register and texture sample limits. It's quite clear that some of the most complex shaders are the different variations of the water shaders. I had to cut away quite a few of the graphical effects from them to make it compile without errors on my graphics card.

The SM 2.0 Hack

The changes in Version 4 were fixing the black effects, there are no shaders that do not compile that I am aware of. In version 4: Distorion effects may now be toggled on/off (most notably water/flames now distort the view) as well as all the other graphical options (toggling high detail shaders and distortion has a great effect on the visuals).


Performance was quite bad for me, especially post processing effects killed the FPS so I tend to turn all the graphical settings down.

Particle Effects

Some particle effects like the bubbles by the briefcases coming down outside the windows in the first map are all dark and very difficult to look through.

This problem might lie somewhere in Particle.hlsl since that's the shader for the particle effects (there are several types of them). It is interesting to note that the particle effects are dark even with the original shaders, ie. the shader compiles fine, but it is still looking wrong. You would often assume that the shader would not to compile at all if there was a problem. Still the fix in version 4 basically removes all dynamic lighting from particles which might not be the optimal solution.

After changing the particle shader to output color codes for the different types of particles it is easy to see what type of particles are the problem:

The color codes are:

Any Vertex/pixel lighted particle was completely black.


Update: Thought I'd put up the latest AOH release on this site. ReverendTed: "This is an unofficial minor update to AOH Version 4, adding in Flint's colored particles (which are slightly more "stable" than mine) and the Lightbeams which are present in the Flint and Phazz fixes for SM2.0 cards. AOH was not consulted on this release."

Download the new shaders.spk (Version 4.5):

Put this in the same folder for improved loading times, courtesy of Phazz: ShaderCache_aoh45.rar

Extract the contents of the zip file into your BioShock/Builds/Release folder, overwriting the file already there. Delete the ShaderCache.pcs if the game still looks wrong after updating.

If you have a SM 2.0 and not a SM 2.0b card then you will probably still see some defaulted shaders for water, etc. in the maps. Map loading times will increase by ~5 minutes since it has to compile the HLSL files.

Binary for extracting/merging HLSL files from shaders.spk: link

Source code for extracting/merging HLSL files from shaders.spk: link

The now obsolete version 4:

The now obsolete version 3:

The now obsolete version 2:
The now obsolete version 1: shaders.spk

Screenshots has been updated for version 4.

Shader Model 2.x card after version 4 hack:

Older screenshots


Creative Commons License
This work is licensed under a Creative Commons Attribution 3.0 Unported License.