In 2012, Peter "Durante" Thoman wrote the popular mod DSfix for Dark Souls: Prepare to Die on PC, fixing its locked 1024x720 resolution and other issues. In 2013, he released a similar fix for Deadly Premonition . We asked Durante to analyze the PC port of Dark Souls 2 in a series of articles. He also modded the game. The image above is an in-game texture, not a Photoshop.
My first two articles about Dark Souls 2 investigated the PC port's features and how generic PC tweaking tools like SweetFX can be used to further improve its graphics . Now it's time to look at the full extent of what can be achieved by modifying Dark Souls 2 on a deeper level. First, I'll provide a short overview of the general avenues available for PC game modding and how each applies to Dark Souls 2. Then I'll detail the modifications I have implemented so far with a new tool I'm calling GeDoSaTo, which enables texture modding, arbitrary downsampling, and more. Consider it the successor to DSfix and DPfix—except its final goal is to work with any 3D game, not just Dark Souls 2.
While there are many ways to modify a game, they can generally be assigned to one of three categories based on their underlying approach:
These are ordered by increasing “invasiveness” of the procedure. The more invasive the mod, the more difficult it is. We'll now look at each approach and how it can be applied to Dark Souls 2.
If you just want to get to GeDoSaTo and how it enables modding in Dark Souls 2, click here to jump to page two.
Data file alteration
This is a simple method in principle, and can be used with many games to alter their assets—textures, sound files, even models and levels. Imagine a basic game, which ships with a folder full of images used directly as textures. By changing one of these images, you perform modding via data file alteration. For example, the popular rhythm game Audiosurf has all of its files fully accessible in this way.
In most modern games—at least those not built for modding—the situation is not this convenient. Data files are often gathered in undocumented custom archive formats with unknown forms of compression. While this is of course an obstacle, resourceful modders may reverse-engineer such archives and provide tools to rebuild them with different data. Dark Souls 2, as discussed in the initial article , stores the vast majority of its data in “*.bdt” files, such as “GameDataEbl.bdt”.
Above, you see a tiny excerpt of the contents of Dark Souls 2's main game data file. As you can see on the right, this part appears to contain some names of a few individual files stored in this archive. Before this section, a set of numbers is stored which might well contain offsets into the archive which designate the location of each individual file. With enough time and effort, it should be feasible to fully understand this file format and write tools for handling it. That could take anywhere from weeks to years, and even such a heroic attempt might still not suffice to enable Data File Alteration in Dark Souls 2.
What you see above are the contents of the “GameDataKeyCode.pem” file shipped with Dark Souls. It is a RSA public key file , and there is one such file associated with each game data archive. The most obvious interpretation of this is that the game checks the signature of each data file upon load, in order to ascertain that no modifications have been made. Note that this is not a certainty—it's an educated guess. If I'm correct, then data file alteration for Dark Souls 2 will additionally require breaking its encryption and/or direct binary modification in order to disable it. Luckily, there are alternative approaches.
Library call interception
Library call interception works by replacing a library (a collection of program functions) that a given game depends on with a customized alternative. A very common tool based on this principle is SweetFX.
In the image above, you see a schematic illustration of the “normal” execution of a program. At various points in time, the game makes a call to a library function (for example in the Direct3D9 library d3d9.dll), which cause some procedure to be executed and a value reported back to the program. Library calls in the program are illustrated by blue arrows, and return values by green arrows.
An interceptor, as the name suggests, intercepts the program's library calls, altering them before they reach the library. It then reports its return values—or entirely different ones—to the program. As an example, think of Dark Souls 1 and DSFix. In simplified terms, DS1 asked Direct3D for a 1024x720 surface to render the game to. DSfix took this request, changed the resolution to whatever the user desired, and gave the subsequently generated surface back to Dark Souls. That alone would generally just break rendering—you also need to adjust rendering viewports, projection matrices, scissor rectangles and potentially shader parameters to make it work—but this is the basic idea.
The largest challenge when writing an interceptor (beyond the mechanics of interception) is understanding the original program's behavior and determining how to alter it in order to achieve the desired effect. Crucially, a library call or sequence of calls has to be determined which uniquely identifies what a program is doing at that given point in time. This difficulty is the reason why SweetFX works well with a great number of games: it simply changes the output image at the very end before it is presented on the monitor, and this point is easy to generically identify.
Direct binary modification
Modifying the code of a running program directly in memory is the most powerful, but also most complex, form of modification. In this process, some binary instructions in the original program are replaced with different ones, resulting in an altered behavior. It can—in theory—be used to accomplish anything, but in practice this is often not feasible for large modern games due to the reverse engineering effort necessary to understand their code base to the degree required for meaningful alterations. Nwks achieved the Dark Souls 1 frame rate unlocking using this process, and something similar might be possible for Dark Souls 2.
For now, we're going with the interception method. On page two, we mod Dark Souls 2.
Dark Souls 2 is a good PC port, and the tweaks we discussed before are nice, but they have some significant shortcomings. HBAO+, while of terrific quality, is currently buggy and can only be used by NVIDIA users. SGSSAA improves image quality tremendously, but has an equally tremendous performance impact. Downsampling is limited to monitor hardware. SweetFX allows for a much more dynamic visual experience, but also negatively affects the HUD and UI screens.
We can do better than that.
Given the options outlined above, the properties of Dark Souls 2, and my previous experience, I chose the library interception approach to modding. I have been working (in secret, until now) on a new, generic tool for just that purpose since the beginning of 2014— it is called GeDoSaTo . In short, it allows for game downsampling without any hardware limitations, and texture modification in any game which uses the default texture loading mechanisms provided by DirectX. It works “out of the box” with Dark Souls 2, allowing for the ridiculous resolution you have seen earlier, without any hardware or driver dependency—beyond performance of course:
As of today, you can download an early build of GeDoSaTo. It isn't finished—I'll continue to work on new features and stamp out bugs—but you can download it today and use it in Dark Souls 2. Downsampling and texture modification should also work in many other DirectX 9 games, but no guarantees for that.
Now here's what it can do in addition to downsampling.
The texture dumping and modding facilities in GeDoSaTo function similarly to the ones included in DSfix, and an initial test has shown that everything works as expected in Dark Souls 2:
I'm looking forward to some talented artists trying their hand at texture modifications! However, they generally shouldn't be as impactful as they were in Dark Souls 1, given the much higher average texture resolution in the PC version of its sequel.
One interesting thing I found out while texture dumping is that some of the game's armor textures sport a massive 2048x4096 resolution, easily on par with everything I've seen in any PC title before. Certainly not a texture you would create for a game primarily targeted at running in 1280x720. Another fact I learned during the development of this mod is that high quality shadows use a 4096x4096 render target. Pretty good!
While downsampling and texture modding are basic GeDoSaTo features applicable to every game, I've used the generic basis provided by GeDoSaTo to implement further effects, which are specific to Dark Souls 2. These modifications are more stable than in any other mod I have created so far. When we discussed library call interception I noted that the largest challenge lies in finding the right time to act.
DSfix used a complex and error prone mechanism based on per-frame counters and cryptic event sequences . Conversely, the tentatively titled “GeDoSaTo: DS2 edition” uses new tools I developed to reliably recognize the shaders used by game, and simply applies its effects instead of the original Dark Souls 2 AA pass. Which, by the way, I can now beyond any reasonable doubt confirm to be FXAA, looking at the shader code.
An additional advantage other than quality of performing these effects in a mod is configurability: all the shader files and parameters are available in plain text files, and can be tweaked to everyone's individual preferences. Note that for the screenshots in the following sections, I have chosen extremely strong versions of each, in order to better show off the effects. Rest assured that less extreme versions are just a small configuration change away.
As shown in the earlier tweaking guide, the in-game ambient occlusion effect is very blurry, temporally unstable, and generally low quality. A more in-depth examination of the game's rendering has uncovered why this is the case: it is rendered at 1/16th (!) of the display resolution, then upscaled to ¼, blurred twice and finally added to the shadow map. This means that ambient occlusion for e.g. a 1080p target resolution is rendered at 480x270. Such a drastic performance-saving measure may be required on 7-year-old consoles, but most modern gaming PCs can deal with a higher quality effect.
The animated comparison above (full-size screenshots: No AO , VSSAO2 ) and here shows the VSSAO2 method of ambient occlusion I ported from DSfix (with minor improvements). It is no HBAO+ in quality, but it is higher resolution, more temporally stable, and less “2D drop shadow” like than the default effect included in the game, and it works on all GPUs. And of course, it does not suffer from the UI rendering issue currently affecting HBAO+ in DS2.
Further effects may be implemented and tweaked by simply modifying the shader effect—the original VSSAO2 was in fact contributed to Dark Souls 1 by Asmodean, a third party modder! Note that the performance impact of VSSAO2 is moderate, though of course larger than the in-game ambient occlusion. It amounts to around 11 percentage points of additional GPU usage on my system—a Geforce 770 rendering at 2560x1440.
SweetFX post-processing can greatly enhance the mood and contrast in many areas in Dark Souls 2, but it also negatively affects the UI. To solve this issue, I have implemented the subset of SweetFX filters used in my Dark Souls 2 profile in GeDoSaTo, where they can be applied before the UI is rendered. Furthermore, to replace the in-game anti-aliasing with a relatively low-cost—but superior—alternative, I have included SMAA. At “Ultra” settings the latter consumes about 10 percentage points of GPU performance on my system, while the full image post-processing requires 9.
Dark Souls 2's integrated depth of field effect, while quite high quality, is also far more subtle than the DoF in the first Dark Souls. Some have speculated that this is part of the reason why graphical level design issues, such as low-quality geometry in the far distance or endlessly repeating textures, are more noticeable in DS2 than its predecessor. To alleviate this issue—and, honestly, because I think Bokeh effects look incredibly neat—I've integrated an extremely high-quality Circular Bokeh DoF filter adapted from OBGE .
The image above shows the effect, configured to be far stronger than you'd probably want to use for gaming (it also uses VSSAO2, SMAA and my post-processing). Another reason not to use it are its ridiculous performance requirements, which sit around 30 (!) percentage points on my configuration, or roughly as much as all other effects and AA combined. I do plan to add another DoF implementation which is slightly less amazing in quality, but also much less ridiculous performance-wise, in the future. For now, think of it more as a special treat for Bokeh aficionados.
For your amusement, I'd like to share three images generated during the development of GeDoSaTo: DS2 Edition.
Using a library call interceptor approach, it is possible to provide arbitrary downsampling, a facility for future texture modding, and higher-quality highly configurable alternatives to some of the in-game effects. Additionally, post-processing can be performed without affecting the UI rendering, and other convenience features, such as taking HUDless screenshots even when a HUD is present in the game, might be possible in the future. You can do all of the above with GeDoSaTo and Dark Souls 2.
I hope you enjoyed this series of articles, and if you want to read more technical stuff from time to time feel free to follow my (sporadically updated) blog . As for me, I'm looking forward to truly diving into Dark Souls 2's gameplay for a while, instead of focusing on analyzing, tweaking and modifying its technical aspects.