Pages

Monday, March 19, 2012

Tutorial - Dosbox Linear Scaler 4x and Greater

Hey Everyone,

I was just checking up on the status of a program called Dosbox to see how the development is going and started reading the forum, I noticed someone asking if additional linear scales could be added to the rendering context configuration. I actually did this myself when I needed the game to fit nicely on a 2560x1600 screen in window mode by modifying and recompiling the source code. So since I've done it before I decided I should write a nice "quickish" tutorial on how to do this for those who are curious or even have the same problem like I once had. Please note that this is only going to add additional ScaleNormal's; 2x, 3x, etc which doesn't include TV, RGB, Scan, HQ, Sai, Super, Advanced Mame or Interp. Also for those who are more familiar with programming and are comfortable with working out dependencies in your favourite IDE etc feel free to skip the steps and head straight to the code change section :)

Additionally someone has recently compiled a patch using this tutorial to add support for 4x, 5x and 6x which you can find at the DosBox Development Forum here: link :)

Please note that at the point of which I wrote this tutorial, Dosbox v0.74 was the latest revision so I can't promise this tutorial will still be accurate with additional future Dosbox updates and changes to the VGA scaler code. If this is the case then I will take a look at the changes and if possible, I'll make a new tutorial in the future :)

The first step is to obtain the source code, you can either download the latest stable build from here or you could download a subversion aggregation program to obtain the latest up to date version of the code, the one I use is called Tortoise SVN which you can download from here. Once you have that you can download the latest SVN repository of Dosbox by copying and pasting this link into your subversion's checkout process:

https://dosbox.svn.sourceforge.net/svnroot/dosbox/dosbox/trunk

The second step once you've downloaded the source code into your desired directory you'll need an editor for modifying the source code, I believe Dosbox supports a few including make files. Since I use the Windows operating system I like to edit code using Microsoft's visual studio which you can download the express version for free from here, the source code is written in C++ so I've linked the 2010 C++ Express edition.

The third step is to load the project into your editor, for those using visual studio they have provided an .sln project file that you can open in the editor, you can find this in "SVNFolder\dosbox\trunk\visualc_net". You may need to convert the project file to 2010 due to the project being built from an older visual studio version but the code will still work fine in 2010 after you convert it; Visual Studio will provide a window that will take you through the conversion process while also giving the option to backup the code in case the conversion fails.

The fourth step will be getting the code to compile without build errors; for the purposes of the tutorial and to make things easier I'll be omitting the screenshot ability as well as the debugging system of Dosbox so the code will compile with less hassle. First things first, create a folder for placing everything in; well need to download some dependencies for the Dosbox rendering context and networking subsystem. First you'll need to download SDL from here, at the bottom of the page where it says development libraries click on the appropriate file for your IDE and download it to your new folder. Second you'll need to download SDL_Net from here where it says binaries; download the appropriate developer package for your operating system, they'll contain "devel" in their names and download it to your new folder as well.

Extract both packages to their own folder and then decide where you'd like your global dependencies to exist for future projects like "C:\API Dependencies" or something like that so you have a nice place to put everything. Create two folders inside; one called SDL and the other SDL_Net, once you've done that open the SDL folder you extracted and drag and drop the include and lib folders to your new SDL API Dependencies folder. Then do the same for SDL_Net from your extraction folder to the dependencies SDL_Net folder.

Ok time to modify the Dosbox project settings so it knows where these files are and allow it to compile happily. Make sure you have the project open in Visual Studio 2010, you can optionally set the project to either debug mode or release mode; release being more efficient and result in a smaller exe file but remember that all these settings you are about to change will have to be done again for debug. Please note that release mode will take longer to compile due to additional code optimizations but the program will run a lot smoother as a result, after choosing that you can either hit Alt+F7 or go up to the top menu under "Project" and click on "Dosbox Properties" which will open the project settings dialogue. Click on "VC++ Directories", then click on "Include Directories" and an arrow will appear to the right side of the text area, click that and then click edit (I have no idea why the interface is like this so bare with it). After you do that you'll see a small window open up called "Include Directories", go back to your API Dependencies folder and locate the include folder for SDL and copy the directories path and then go back to the "Include Directories" window, double click on the white space or click the new path button and paste your SDL directory into it. Do the same for SDL_Net and then hit ok to close the window.

Further down the list you'll see another list called "Library Directories", this time you need to copy and paste the "Lib" folder directories of both SDL and SDL_Net into the libraries window then hit ok. So far so good, now on the right panel of your project settings you'll see something called "Linker", click this and then open up the "Additional Dependencies" list like you did with the include and library lists. Remove the references to "zlib.lib", "libpng.lib" and "curses.lib" then hit ok, this will remove the dependencies for the screenshot and debugging systems; you can add this back later if your willing to compile libpng and zlib yourself since Dosbox doesn't come with them, probably due to licensing or something and what's worse is some dependency developers don't even provide binaries or libraries so you can avoid compiling manually.

To finalise the removal of all external dependencies you'll need to open the "config.h" file located under "Source Files/visualc" and make sure both "C_DEBUG" and "C_SSHOT" are set to zero next to them. If you compile the code you should be left with one last error informing you that it can not find "afxres.h" which for some reason the express addition of visual studio doesn't come packaged with, to fix this last error double click on the error about the missing file and it will open the "winres.rc" file showing the include statement trying to find the missing header file, replace that line with this code section:

#include <Windows.h>

Ok with any luck you should have a compiled version of Dosbox, just make sure that when you place the exe outside of the IDE's compile folder to make sure you put both "SDL.dll" and "SDL_net.dll" which you can find inside the dependencies lib folder under x86 with it, otherwise it will crash. You should take note when you run the program that there's a reference to the config file that allows you to change Dosbox's settings written on the console that's unique for this SVN Build located at "C:\Users\Your Name\AppData\Local\DOSBox\dosbox-SVN.conf" for Windows 7 but write down where it says for your computer so you can change the settings later.

Code Change Section

Alrighty, now that we can run Dosbox from its source code we can begin to implement some upgrades for the VGA linear scaling system. First things first we must create a new definition for our new scaler type; under "Source Files/gui" you will find a header file called "render_scalers.h", open it and scroll down to the bottom. You should see this

extern ScalerSimpleBlock_t ScaleNormal2x;
extern ScalerSimpleBlock_t ScaleNormal3x;

Add this line just after them at whatever scale you desire:

extern ScalerSimpleBlock_t ScaleNormal4x;

In this case I'll be adding a 4x linear scaler. Now Open the file "render.cpp" under the gui folder and scroll down to line 291, you should see this:

if ( render.scale.size == 2 )
       simpleBlock = &ScaleNormal2x
else if ( render.scale.size == 3 )
       simpleBlock = &ScaleNormal3x;
else
       simpleBlock = &ScaleNormal1x;

Append your scaler as an additional else if line like this:

else if ( render.scale.size == 4 )
       simpleBlock = &ScaleNormal4x;

Scroll down to line 600 and add this:

else if (scaler == "normal4x") { render.scale.op = scalerOpNormal;render.scale.size = 4; }

Ok, now open up "render_templates.h" in the gui folder, then scroll down to line 241. Add this after the Normal3x's definition:

#define SCALERNAME        Normal4x
#define SCALERWIDTH        4
#define SCALERHEIGHT    4
#define SCALERFUNC                                \
    line0[0] = P;                                \
    line0[1] = P;                                \
    line0[2] = P;                                \
    line0[3] = P;                                \
    line1[0] = P;                                \
    line1[1] = P;                                \
    line1[2] = P;                                \
    line1[3] = P;                                \
    line2[0] = P;                                \
    line2[1] = P;                                \
    line2[2] = P;                                \
    line2[3] = P;                                \
    line3[0] = P;                                \
    line3[1] = P;                                \
    line3[2] = P;                                \
    line3[3] = P; 
#include "render_simple.h"
#undef SCALERNAME
#undef SCALERWIDTH
#undef SCALERHEIGHT
#undef SCALERFUNC

Alright, now we need to declare our scaler; open up "render_scalers.cpp" under gui and scroll down to line 242. Here you can see the definitions for the linear scalers, append this code after the definition of "ScaleNormal3x":

ScalerSimpleBlock_t ScaleNormal4x = {
    "Normal4x",
    GFX_CAN_8|GFX_CAN_15|GFX_CAN_16|GFX_CAN_32,
    4,4,{
{    Normal4x_8_8_L,        Normal4x_8_15_L ,    Normal4x_8_16_L ,    Normal4x_8_32_L },
{                 0,        Normal4x_15_15_L,    Normal4x_15_16_L,    Normal4x_15_32_L},
{                 0,        Normal4x_16_15_L,    Normal4x_16_16_L,    Normal4x_16_32_L},
{                 0,        Normal4x_32_15_L,    Normal4x_32_16_L,    Normal4x_32_32_L},
{    Normal4x_8_8_L,        Normal4x_9_15_L ,    Normal4x_9_16_L ,    Normal4x_9_32_L }
},{
{    Normal4x_8_8_R,        Normal4x_8_15_R ,    Normal4x_8_16_R ,    Normal4x_8_32_R },
{                 0,        Normal4x_15_15_R,    Normal4x_15_16_R,    Normal4x_15_32_R},
{                 0,        Normal4x_16_15_R,    Normal4x_16_16_R,    Normal4x_16_32_R},
{                 0,        Normal4x_32_15_R,    Normal4x_32_16_R,    Normal4x_32_32_R},
{    Normal4x_8_8_R,        Normal4x_9_15_R ,    Normal4x_9_16_R ,    Normal4x_9_32_R }
}};

Ok, now inside "render_simple.h" in the gui folder which in my case seems to be excluded for some reason. You can find it inside the SVN directory's gui folder manually, just drag and drop it into your IDE editor; feel free to add it to your "Source Files/gui" folder so you can always access it later. Now you can scroll down to line 68 and append this:

#if (SCALERHEIGHT > 3)
            PTYPE *line3 = WC[2];
#endif

This after line 79:

#if (SCALERHEIGHT > 3)
        PTYPE *line3 = (PTYPE *)(((Bit8u*)line0)+ render.scale.outPitch * 3);
#endif

This after line 97:

#if (SCALERHEIGHT > 3)
                line3 += SCALERWIDTH;
#endif

Finally this after line 109:

#if (SCALERHEIGHT > 3)
            BituMove(((Bit8u*)line0)-copyLen+render.scale.outPitch*3,WC[2], copyLen );
#endif

To use your new scaler as an available option, you can open up "dosbox.cpp" and go to line 389 where you can add this:

const char *scalers[] = {
        "none", "normal2x", "normal3x", "normal4x" 

Now compile the code and you'll be able to specify the "Normal4x" setting inside the Dosbox.conf file and your game should render larger than the 3x multiplier. If you would like the config file to show your scaler as an available option in the comments you'll need to delete the old config file first as this change will only effect the config when it's created by default; when one hasn't been found in the AppData directory.

And that's it! I hope this wasn't too much of a headache for people and that you enjoyed the tutorial. Feel free to explore what the changes do and see if you can work out how to add even more scalers to your code :)

Thanks for reading,
Ashton.

5 comments:

  1. Replies
    1. You're welcome, I'm glad the tutorial was helpful :)

      Delete
  2. Thanks for this post, I took it and extended the code to make working normal5x and normal6x modes.

    ReplyDelete
    Replies
    1. That's awesome :) I'm so glad that my post has been useful. I'm actually surprised they never bothered adding enhanced scalars since now days people have pretty large resolutions and the original scalars just don't cut it, computers are more than fast enough to support it.

      I found the page you posted the patch to through the analytic references so I'll leave a link for others to find it :)

      Delete
  3. Thanks for the post, Ashton. Would it be possible to implement the same in a more robust and scalable (sic) way — via a special ini-file parameter called Scale which would accept an arbitrary integer multiplier? The correct way to display a game in full-screen mode is to use the maximum integer scaler that keeps the image withing the display dimentions. Of course, this enhancement must be merged into the official DosBox release.

    ReplyDelete