Home | History | Annotate | Download | only in Device
      1 // Copyright 2016 The SwiftShader Authors. All Rights Reserved.
      2 //
      3 // Licensed under the Apache License, Version 2.0 (the "License");
      4 // you may not use this file except in compliance with the License.
      5 // You may obtain a copy of the License at
      6 //
      7 //    http://www.apache.org/licenses/LICENSE-2.0
      8 //
      9 // Unless required by applicable law or agreed to in writing, software
     10 // distributed under the License is distributed on an "AS IS" BASIS,
     11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     12 // See the License for the specific language governing permissions and
     13 // limitations under the License.
     14 
     15 #include "SwiftConfig.hpp"
     16 
     17 #include "Config.hpp"
     18 #include "System/Configurator.hpp"
     19 #include "Vulkan/VkDebug.hpp"
     20 #include "Vulkan/Version.h"
     21 
     22 #include <sstream>
     23 #include <stdio.h>
     24 #include <time.h>
     25 #include <sys/stat.h>
     26 #include <string.h>
     27 #include <algorithm>
     28 
     29 namespace sw
     30 {
     31 	extern Profiler profiler;
     32 
     33 	std::string itoa(int number)
     34 	{
     35 		std::stringstream ss;
     36 		ss << number;
     37 		return ss.str();
     38 	}
     39 
     40 	std::string ftoa(double number)
     41 	{
     42 		std::stringstream ss;
     43 		ss << number;
     44 		return ss.str();
     45 	}
     46 
     47 	SwiftConfig::SwiftConfig(bool disableServerOverride) : listenSocket(0)
     48 	{
     49 		readConfiguration(disableServerOverride);
     50 
     51 		if(!disableServerOverride)
     52 		{
     53 			writeConfiguration();
     54 		}
     55 
     56 		receiveBuffer = 0;
     57 
     58 		if(!config.disableServer)
     59 		{
     60 			createServer();
     61 		}
     62 	}
     63 
     64 	SwiftConfig::~SwiftConfig()
     65 	{
     66 		destroyServer();
     67 	}
     68 
     69 	void SwiftConfig::createServer()
     70 	{
     71 		bufferLength = 16 * 1024;
     72 		receiveBuffer = new char[bufferLength];
     73 
     74 		Socket::startup();
     75 		listenSocket = new Socket("localhost", "8080");
     76 		listenSocket->listen();
     77 
     78 		terminate = false;
     79 		serverThread = new Thread(serverRoutine, this);
     80 	}
     81 
     82 	void SwiftConfig::destroyServer()
     83 	{
     84 		if(receiveBuffer)
     85 		{
     86 			terminate = true;
     87 			serverThread->join();
     88 			delete serverThread;
     89 
     90 			delete listenSocket;
     91 			listenSocket = 0;
     92 
     93 			Socket::cleanup();
     94 
     95 			delete[] receiveBuffer;
     96 			receiveBuffer = 0;
     97 		}
     98 	}
     99 
    100 	bool SwiftConfig::hasNewConfiguration(bool reset)
    101 	{
    102 		bool value = newConfig;
    103 
    104 		if(reset)
    105 		{
    106 			newConfig = false;
    107 		}
    108 
    109 		return value;
    110 	}
    111 
    112 	void SwiftConfig::getConfiguration(Configuration &configuration)
    113 	{
    114 		criticalSection.lock();
    115 		configuration = config;
    116 		criticalSection.unlock();
    117 	}
    118 
    119 	void SwiftConfig::serverRoutine(void *parameters)
    120 	{
    121 		SwiftConfig *swiftConfig = (SwiftConfig*)parameters;
    122 
    123 		swiftConfig->serverLoop();
    124 	}
    125 
    126 	void SwiftConfig::serverLoop()
    127 	{
    128 		readConfiguration();
    129 
    130 		while(!terminate)
    131 		{
    132 			if(listenSocket->select(100000))
    133 			{
    134 				Socket *clientSocket = listenSocket->accept();
    135 				int bytesReceived = 1;
    136 
    137 				while(bytesReceived > 0 && !terminate)
    138 				{
    139 					if(clientSocket->select(10))
    140 					{
    141 						bytesReceived = clientSocket->receive(receiveBuffer, bufferLength);
    142 
    143 						if(bytesReceived > 0)
    144 						{
    145 							receiveBuffer[bytesReceived] = 0;
    146 
    147 							respond(clientSocket, receiveBuffer);
    148 						}
    149 					}
    150 				}
    151 
    152 				delete clientSocket;
    153 			}
    154 		}
    155 	}
    156 
    157 	bool match(const char **url, const char *string)
    158 	{
    159 		size_t length = strlen(string);
    160 
    161 		if(strncmp(*url, string, length) == 0)
    162 		{
    163 			*url += length;
    164 
    165 			return true;
    166 		}
    167 
    168 		return false;
    169 	}
    170 
    171 	void SwiftConfig::respond(Socket *clientSocket, const char *request)
    172 	{
    173 		if(match(&request, "GET /"))
    174 		{
    175 			if(match(&request, "swiftshader") || match(&request, "swiftconfig"))
    176 			{
    177 				if(match(&request, " ") || match(&request, "/ "))
    178 				{
    179 					return send(clientSocket, OK, page());
    180 				}
    181 			}
    182 		}
    183 		else if(match(&request, "POST /"))
    184 		{
    185 			if(match(&request, "swiftshader") || match(&request, "swiftconfig"))
    186 			{
    187 				if(match(&request, " ") || match(&request, "/ "))
    188 				{
    189 					criticalSection.lock();
    190 
    191 					const char *postData = strstr(request, "\r\n\r\n");
    192 					postData = postData ? postData + 4 : 0;
    193 
    194 					if(postData && strlen(postData) > 0)
    195 					{
    196 						parsePost(postData);
    197 					}
    198 					else   // POST data in next packet
    199 					{
    200 						int bytesReceived = clientSocket->receive(receiveBuffer, bufferLength);
    201 
    202 						if(bytesReceived > 0)
    203 						{
    204 							receiveBuffer[bytesReceived] = 0;
    205 							parsePost(receiveBuffer);
    206 						}
    207 					}
    208 
    209 					writeConfiguration();
    210 					newConfig = true;
    211 
    212 					if(config.disableServer)
    213 					{
    214 						destroyServer();
    215 					}
    216 
    217 					criticalSection.unlock();
    218 
    219 					return send(clientSocket, OK, page());
    220 				}
    221 				else if(match(&request, "/profile "))
    222 				{
    223 					return send(clientSocket, OK, profile());
    224 				}
    225 			}
    226 		}
    227 
    228 		return send(clientSocket, NotFound);
    229 	}
    230 
    231 	std::string SwiftConfig::page()
    232 	{
    233 		std::string html;
    234 
    235 		const std::string selected = "selected='selected'";
    236 		const std::string checked = "checked='checked'";
    237 		const std::string empty = "";
    238 
    239 		html += "<!DOCTYPE HTML PUBLIC '-//W3C//DTD HTML 4.01//EN' 'http://www.w3.org/TR/html4/strict.dtd'>\n";
    240 		html += "<html>\n";
    241 		html += "<head>\n";
    242 		html += "<meta http-equiv='content-type' content='text/html; charset=UTF-8'>\n";
    243 		html += "<title>SwiftShader Configuration Panel</title>\n";
    244 		html += "</head>\n";
    245 		html += "<body>\n";
    246 		html += "<script type='text/javascript'>\n";
    247 		html += "request();\n";
    248 		html += "function request()\n";
    249 		html += "{\n";
    250 		html += "var xhr = new XMLHttpRequest();\n";
    251 		html += "xhr.open('POST', '/swiftshader/profile', true);\n";
    252 		html += "xhr.onreadystatechange = function()\n";
    253 		html += "{\n";
    254 		html += "if(xhr.readyState == 4 && xhr.status == 200)\n";
    255 		html += "{\n";
    256 		html += "document.getElementById('profile').innerHTML = xhr.responseText;\n";
    257 		html += "setTimeout('request()', 1000);\n";
    258 		html += "}\n";
    259 		html += "}\n";
    260 		html += "xhr.send();\n";
    261 		html += "}\n";
    262 		html += "</script>\n";
    263 		html += "<form method='POST' action=''>\n";
    264 		html += "<h1>SwiftShader Configuration Panel</h1>\n";
    265 		html += "<div id='profile'>" + profile() + "</div>\n";
    266 		html += "<hr><p>\n";
    267 		html += "<input type='submit' value='Apply changes' title='Click to apply all settings.'>\n";
    268 	//	html += "<input type='reset' value='Reset changes' title='Click to reset your changes to the previous value.'>\n";
    269 		html += "</p><hr>\n";
    270 		html += "<h2><em>Device capabilities</em></h2>\n";
    271 		html += "<table>\n";
    272 		html += "<tr><td>Build revision:</td><td>" REVISION_STRING "</td></tr>\n";
    273 		html += "<tr><td>Pixel shader model:</td><td><select name='pixelShaderVersion' title='The highest version of pixel shader supported by SwiftShader. Lower versions might be faster if supported by the application. Only effective after restarting the application.'>\n";
    274 		html += "<option value='0'"  + (config.pixelShaderVersion ==  0 ? selected : empty) + ">0.0</option>\n";
    275 		html += "<option value='11'" + (config.pixelShaderVersion == 11 ? selected : empty) + ">1.1</option>\n";
    276 		html += "<option value='12'" + (config.pixelShaderVersion == 12 ? selected : empty) + ">1.2</option>\n";
    277 		html += "<option value='13'" + (config.pixelShaderVersion == 13 ? selected : empty) + ">1.3</option>\n";
    278 		html += "<option value='14'" + (config.pixelShaderVersion == 14 ? selected : empty) + ">1.4</option>\n";
    279 		html += "<option value='20'" + (config.pixelShaderVersion == 20 ? selected : empty) + ">2.0</option>\n";
    280 		html += "<option value='21'" + (config.pixelShaderVersion == 21 ? selected : empty) + ">2.x</option>\n";
    281 		html += "<option value='30'" + (config.pixelShaderVersion == 30 ? selected : empty) + ">3.0 (default)</option>\n";
    282 		html += "</select></td></tr>\n";
    283 		html += "<tr><td>Vertex shader model:</td><td><select name='vertexShaderVersion' title='The highest version of vertex shader supported by SwiftShader. Lower versions might be faster if supported by the application. Only effective after restarting the application.'>\n";
    284 		html += "<option value='0'"  + (config.vertexShaderVersion ==  0 ? selected : empty) + ">0.0</option>\n";
    285 		html += "<option value='11'" + (config.vertexShaderVersion == 11 ? selected : empty) + ">1.1</option>\n";
    286 		html += "<option value='20'" + (config.vertexShaderVersion == 20 ? selected : empty) + ">2.0</option>\n";
    287 		html += "<option value='21'" + (config.vertexShaderVersion == 21 ? selected : empty) + ">2.x</option>\n";
    288 		html += "<option value='30'" + (config.vertexShaderVersion == 30 ? selected : empty) + ">3.0 (default)</option>\n";
    289 		html += "</select></td></tr>\n";
    290 		html += "<tr><td>Texture memory:</td><td><select name='textureMemory' title='The maximum amount of memory used for textures and other resources.'>\n";
    291 		html += "<option value='128'"  + (config.textureMemory == 128  ? selected : empty) + ">128 MB</option>\n";
    292 		html += "<option value='256'"  + (config.textureMemory == 256  ? selected : empty) + ">256 MB (default)</option>\n";
    293 		html += "<option value='512'"  + (config.textureMemory == 512  ? selected : empty) + ">512 MB</option>\n";
    294 		html += "<option value='1024'" + (config.textureMemory == 1024 ? selected : empty) + ">1024 MB</option>\n";
    295 		html += "<option value='2048'" + (config.textureMemory == 2048 ? selected : empty) + ">2048 MB</option>\n";
    296 		html += "</select></td></tr>\n";
    297 		html += "<tr><td>Device identifier:</td><td><select name='identifier' title='The information used by some applications to determine device capabilities.'>\n";
    298 		html += "<option value='0'" + (config.identifier == 0 ? selected : empty) + ">Google SwiftShader (default)</option>\n";
    299 		html += "<option value='1'" + (config.identifier == 1 ? selected : empty) + ">NVIDIA GeForce 7900 GS</option>\n";
    300 		html += "<option value='2'" + (config.identifier == 2 ? selected : empty) + ">ATI Mobility Radeon X1600</option>\n";
    301 		html += "<option value='3'" + (config.identifier == 3 ? selected : empty) + ">Intel GMA X3100</option>\n";
    302 		html += "<option value='4'" + (config.identifier == 4 ? selected : empty) + ">System device</option>\n";
    303 		html += "</select></td></tr>\n";
    304 		html += "</table>\n";
    305 		html += "<h2><em>Cache sizes</em></h2>\n";
    306 		html += "<table>\n";
    307 		html += "<tr><td>Vertex routine cache size:</td><td><select name='vertexRoutineCacheSize' title='The number of dynamically generated vertex processing routines being cached for reuse. Lower numbers save memory but require more routines to be regenerated.'>\n";
    308 		html += "<option value='64'"   + (config.vertexRoutineCacheSize == 64   ? selected : empty) + ">64</option>\n";
    309 		html += "<option value='128'"  + (config.vertexRoutineCacheSize == 128  ? selected : empty) + ">128</option>\n";
    310 		html += "<option value='256'"  + (config.vertexRoutineCacheSize == 256  ? selected : empty) + ">256</option>\n";
    311 		html += "<option value='512'"  + (config.vertexRoutineCacheSize == 512  ? selected : empty) + ">512</option>\n";
    312 		html += "<option value='1024'" + (config.vertexRoutineCacheSize == 1024 ? selected : empty) + ">1024 (default)</option>\n";
    313 		html += "<option value='2048'" + (config.vertexRoutineCacheSize == 2048 ? selected : empty) + ">2048</option>\n";
    314 		html += "<option value='4096'" + (config.vertexRoutineCacheSize == 4096 ? selected : empty) + ">4096</option>\n";
    315 		html += "</select></td>\n";
    316 		html += "</tr>\n";
    317 		html += "<tr><td>Pixel routine cache size:</td><td><select name='pixelRoutineCacheSize' title='The number of dynamically generated pixel processing routines being cached for reuse. Lower numbers save memory but require more routines to be regenerated.'>\n";
    318 		html += "<option value='64'"   + (config.pixelRoutineCacheSize == 64   ? selected : empty) + ">64</option>\n";
    319 		html += "<option value='128'"  + (config.pixelRoutineCacheSize == 128  ? selected : empty) + ">128</option>\n";
    320 		html += "<option value='256'"  + (config.pixelRoutineCacheSize == 256  ? selected : empty) + ">256</option>\n";
    321 		html += "<option value='512'"  + (config.pixelRoutineCacheSize == 512  ? selected : empty) + ">512</option>\n";
    322 		html += "<option value='1024'" + (config.pixelRoutineCacheSize == 1024 ? selected : empty) + ">1024 (default)</option>\n";
    323 		html += "<option value='2048'" + (config.pixelRoutineCacheSize == 2048 ? selected : empty) + ">2048</option>\n";
    324 		html += "<option value='4096'" + (config.pixelRoutineCacheSize == 4096 ? selected : empty) + ">4096</option>\n";
    325 		html += "</select></td>\n";
    326 		html += "</tr>\n";
    327 		html += "<tr><td>Setup routine cache size:</td><td><select name='setupRoutineCacheSize' title='The number of dynamically generated primitive setup routines being cached for reuse. Lower numbers save memory but require more routines to be regenerated.'>\n";
    328 		html += "<option value='64'"   + (config.setupRoutineCacheSize == 64   ? selected : empty) + ">64</option>\n";
    329 		html += "<option value='128'"  + (config.setupRoutineCacheSize == 128  ? selected : empty) + ">128</option>\n";
    330 		html += "<option value='256'"  + (config.setupRoutineCacheSize == 256  ? selected : empty) + ">256</option>\n";
    331 		html += "<option value='512'"  + (config.setupRoutineCacheSize == 512  ? selected : empty) + ">512</option>\n";
    332 		html += "<option value='1024'" + (config.setupRoutineCacheSize == 1024 ? selected : empty) + ">1024 (default)</option>\n";
    333 		html += "<option value='2048'" + (config.setupRoutineCacheSize == 2048 ? selected : empty) + ">2048</option>\n";
    334 		html += "<option value='4096'" + (config.setupRoutineCacheSize == 4096 ? selected : empty) + ">4096</option>\n";
    335 		html += "</select></td>\n";
    336 		html += "</tr>\n";
    337 		html += "<tr><td>Vertex cache size:</td><td><select name='vertexCacheSize' title='The number of processed vertices being cached for reuse. Lower numbers save memory but require more vertices to be reprocessed.'>\n";
    338 		html += "<option value='64'"   + (config.vertexCacheSize == 64   ? selected : empty) + ">64 (default)</option>\n";
    339 		html += "</select></td>\n";
    340 		html += "</tr>\n";
    341 		html += "</table>\n";
    342 		html += "<h2><em>Quality</em></h2>\n";
    343 		html += "<table>\n";
    344 		html += "<tr><td>Maximum texture sampling quality:</td><td><select name='textureSampleQuality' title='The maximum texture filtering quality. Lower settings can be faster but cause visual artifacts.'>\n";
    345 		html += "<option value='0'" + (config.textureSampleQuality == 0 ? selected : empty) + ">Point</option>\n";
    346 		html += "<option value='1'" + (config.textureSampleQuality == 1 ? selected : empty) + ">Linear</option>\n";
    347 		html += "<option value='2'" + (config.textureSampleQuality == 2 ? selected : empty) + ">Anisotropic (default)</option>\n";
    348 		html += "</select></td>\n";
    349 		html += "</tr>\n";
    350 		html += "<tr><td>Maximum mipmapping quality:</td><td><select name='mipmapQuality' title='The maximum mipmap filtering quality. Higher settings can be more visually appealing but are slower.'>\n";
    351 		html += "<option value='0'" + (config.mipmapQuality == 0 ? selected : empty) + ">Point</option>\n";
    352 		html += "<option value='1'" + (config.mipmapQuality == 1 ? selected : empty) + ">Linear (default)</option>\n";
    353 		html += "</select></td>\n";
    354 		html += "</tr>\n";
    355 		html += "<tr><td>Perspective correction:</td><td><select name='perspectiveCorrection' title='Enables or disables perspective correction. Disabling it is faster but can causes distortion. Recommended for 2D applications only.'>\n";
    356 		html += "<option value='0'" + (config.perspectiveCorrection == 0 ? selected : empty) + ">Off</option>\n";
    357 		html += "<option value='1'" + (config.perspectiveCorrection == 1 ? selected : empty) + ">On (default)</option>\n";
    358 		html += "</select></td>\n";
    359 		html += "</tr>\n";
    360 		html += "<tr><td>Transcendental function precision:</td><td><select name='transcendentalPrecision' title='The precision at which log/exp/pow/rcp/rsq/nrm shader instructions are computed. Lower settings can be faster but cause visual artifacts.'>\n";
    361 		html += "<option value='0'" + (config.transcendentalPrecision == 0 ? selected : empty) + ">Approximate</option>\n";
    362 		html += "<option value='1'" + (config.transcendentalPrecision == 1 ? selected : empty) + ">Partial</option>\n";
    363 		html += "<option value='2'" + (config.transcendentalPrecision == 2 ? selected : empty) + ">Accurate (default)</option>\n";
    364 		html += "<option value='3'" + (config.transcendentalPrecision == 3 ? selected : empty) + ">WHQL</option>\n";
    365 		html += "<option value='4'" + (config.transcendentalPrecision == 4 ? selected : empty) + ">IEEE</option>\n";
    366 		html += "</select></td>\n";
    367 		html += "</tr>\n";
    368 		html += "<tr><td>Transparency anti-aliasing:</td><td><select name='transparencyAntialiasing' title='The technique used to anti-alias alpha-tested transparent textures.'>\n";
    369 		html += "<option value='0'" + (config.transparencyAntialiasing == 0 ? selected : empty) + ">None (default)</option>\n";
    370 		html += "<option value='1'" + (config.transparencyAntialiasing == 1 ? selected : empty) + ">Alpha-to-Coverage</option>\n";
    371 		html += "</select></td>\n";
    372 		html += "</table>\n";
    373 		html += "<h2><em>Processor settings</em></h2>\n";
    374 		html += "<table>\n";
    375 		html += "<tr><td>Number of threads:</td><td><select name='threadCount' title='The number of rendering threads to be used.'>\n";
    376 		html += "<option value='-1'" + (config.threadCount == -1 ? selected : empty) + ">Core count</option>\n";
    377 		html += "<option value='0'"  + (config.threadCount == 0  ? selected : empty) + ">Process affinity (default)</option>\n";
    378 		html += "<option value='1'"  + (config.threadCount == 1  ? selected : empty) + ">1</option>\n";
    379 		html += "<option value='2'"  + (config.threadCount == 2  ? selected : empty) + ">2</option>\n";
    380 		html += "<option value='3'"  + (config.threadCount == 3  ? selected : empty) + ">3</option>\n";
    381 		html += "<option value='4'"  + (config.threadCount == 4  ? selected : empty) + ">4</option>\n";
    382 		html += "<option value='5'"  + (config.threadCount == 5  ? selected : empty) + ">5</option>\n";
    383 		html += "<option value='6'"  + (config.threadCount == 6  ? selected : empty) + ">6</option>\n";
    384 		html += "<option value='7'"  + (config.threadCount == 7  ? selected : empty) + ">7</option>\n";
    385 		html += "<option value='8'"  + (config.threadCount == 8  ? selected : empty) + ">8</option>\n";
    386 		html += "<option value='9'"  + (config.threadCount == 9  ? selected : empty) + ">9</option>\n";
    387 		html += "<option value='10'" + (config.threadCount == 10 ? selected : empty) + ">10</option>\n";
    388 		html += "<option value='11'" + (config.threadCount == 11 ? selected : empty) + ">11</option>\n";
    389 		html += "<option value='12'" + (config.threadCount == 12 ? selected : empty) + ">12</option>\n";
    390 		html += "<option value='13'" + (config.threadCount == 13 ? selected : empty) + ">13</option>\n";
    391 		html += "<option value='14'" + (config.threadCount == 14 ? selected : empty) + ">14</option>\n";
    392 		html += "<option value='15'" + (config.threadCount == 15 ? selected : empty) + ">15</option>\n";
    393 		html += "<option value='16'" + (config.threadCount == 16 ? selected : empty) + ">16</option>\n";
    394 		html += "</select></td></tr>\n";
    395 		html += "<tr><td>Enable SSE:</td><td><input name = 'enableSSE' type='checkbox'" + (config.enableSSE ? checked : empty) + " disabled='disabled' title='If checked enables the use of SSE instruction set extentions if supported by the CPU.'></td></tr>";
    396 		html += "<tr><td>Enable SSE2:</td><td><input name = 'enableSSE2' type='checkbox'" + (config.enableSSE2 ? checked : empty) + " title='If checked enables the use of SSE2 instruction set extentions if supported by the CPU.'></td></tr>";
    397 		html += "<tr><td>Enable SSE3:</td><td><input name = 'enableSSE3' type='checkbox'" + (config.enableSSE3 ? checked : empty) + " title='If checked enables the use of SSE3 instruction set extentions if supported by the CPU.'></td></tr>";
    398 		html += "<tr><td>Enable SSSE3:</td><td><input name = 'enableSSSE3' type='checkbox'" + (config.enableSSSE3 ? checked : empty) + " title='If checked enables the use of SSSE3 instruction set extentions if supported by the CPU.'></td></tr>";
    399 		html += "<tr><td>Enable SSE4.1:</td><td><input name = 'enableSSE4_1' type='checkbox'" + (config.enableSSE4_1 ? checked : empty) + " title='If checked enables the use of SSE4.1 instruction set extentions if supported by the CPU.'></td></tr>";
    400 		html += "</table>\n";
    401 		html += "<h2><em>Compiler optimizations</em></h2>\n";
    402 		html += "<table>\n";
    403 
    404 		for(int pass = 0; pass < 10; pass++)
    405 		{
    406 			html += "<tr><td>Optimization pass " + itoa(pass + 1) + ":</td><td><select name='optimization" + itoa(pass + 1) + "' title='An optimization pass for the shader compiler.'>\n";
    407 			html += "<option value='0'"  + (config.optimization[pass] == 0  ? selected : empty) + ">Disabled" + (pass > 0 ? " (default)" : "") + "</option>\n";
    408 			html += "<option value='1'"  + (config.optimization[pass] == 1  ? selected : empty) + ">Instruction Combining" + (pass == 0 ? " (default)" : "") + "</option>\n";
    409 			html += "<option value='2'"  + (config.optimization[pass] == 2  ? selected : empty) + ">Control Flow Simplification</option>\n";
    410 			html += "<option value='3'"  + (config.optimization[pass] == 3  ? selected : empty) + ">Loop Invariant Code Motion</option>\n";
    411 			html += "<option value='4'"  + (config.optimization[pass] == 4  ? selected : empty) + ">Aggressive Dead Code Elimination</option>\n";
    412 			html += "<option value='5'"  + (config.optimization[pass] == 5  ? selected : empty) + ">Global Value Numbering</option>\n";
    413 			html += "<option value='6'"  + (config.optimization[pass] == 6  ? selected : empty) + ">Commutative Expressions Reassociation</option>\n";
    414 			html += "<option value='7'"  + (config.optimization[pass] == 7  ? selected : empty) + ">Dead Store Elimination</option>\n";
    415 			html += "<option value='8'"  + (config.optimization[pass] == 8  ? selected : empty) + ">Sparse Conditional Copy Propagation</option>\n";
    416 			html += "<option value='9'"  + (config.optimization[pass] == 9  ? selected : empty) + ">Scalar Replacement of Aggregates</option>\n";
    417 			html += "</select></td></tr>\n";
    418 		}
    419 
    420 		html += "</table>\n";
    421 		html += "<h2><em>Testing & Experimental</em></h2>\n";
    422 		html += "<table>\n";
    423 		html += "<tr><td>Disable SwiftConfig server:</td><td><input name = 'disableServer' type='checkbox'" + (config.disableServer == true ? checked : empty) + " title='If checked disables the web browser based control panel.'></td></tr>";
    424 		html += "<tr><td>Force windowed mode:</td><td><input name = 'forceWindowed' type='checkbox'" + (config.forceWindowed == true ? checked : empty) + " title='If checked prevents the application from switching to full-screen mode.'></td></tr>";
    425 		html += "<tr><td>Complementary depth buffer:</td><td><input name = 'complementaryDepthBuffer' type='checkbox'" + (config.complementaryDepthBuffer == true ? checked : empty) + " title='If checked causes 1 - z to be stored in the depth buffer.'></td></tr>";
    426 		html += "<tr><td>Post alpha blend sRGB conversion:</td><td><input name = 'postBlendSRGB' type='checkbox'" + (config.postBlendSRGB == true ? checked : empty) + " title='If checked alpha blending is performed in linear color space.'></td></tr>";
    427 		html += "<tr><td>Exact color rounding:</td><td><input name = 'exactColorRounding' type='checkbox'" + (config.exactColorRounding == true ? checked : empty) + " title='If checked color rounding is done at high accuracy.'></td></tr>";
    428 		html += "<tr><td>Disable alpha display formats:</td><td><input name = 'disableAlphaMode' type='checkbox'" + (config.disableAlphaMode == true ? checked : empty) + " title='If checked the device does not advertise the A8R8G8B8 display mode.'></td></tr>";
    429 		html += "<tr><td>Disable 10-bit display formats:</td><td><input name = 'disable10BitMode' type='checkbox'" + (config.disable10BitMode == true ? checked : empty) + " title='If checked the device does not advertise the A2R10G10B10 display mode.'></td></tr>";
    430 		html += "<tr><td>Frame-buffer API:</td><td><select name='frameBufferAPI' title='The API used for displaying the rendered result on screen (requires restart).'>\n";
    431 		html += "<option value='0'" + (config.frameBufferAPI == 0 ? selected : empty) + ">DirectDraw (default)</option>\n";
    432 		html += "<option value='1'" + (config.frameBufferAPI == 1 ? selected : empty) + ">GDI</option>\n";
    433 		html += "</select></td>\n";
    434 		html += "<tr><td>DLL precaching:</td><td><input name = 'precache' type='checkbox'" + (config.precache == true ? checked : empty) + " title='If checked dynamically generated routines will be stored in a DLL for faster loading on application restart.'></td></tr>";
    435 		html += "<tr><td>Shadow mapping extensions:</td><td><select name='shadowMapping' title='Features that may accelerate or improve the quality of shadow mapping.'>\n";
    436 		html += "<option value='0'" + (config.shadowMapping == 0 ? selected : empty) + ">None</option>\n";
    437 		html += "<option value='1'" + (config.shadowMapping == 1 ? selected : empty) + ">Fetch4</option>\n";
    438 		html += "<option value='2'" + (config.shadowMapping == 2 ? selected : empty) + ">DST</option>\n";
    439 		html += "<option value='3'" + (config.shadowMapping == 3 ? selected : empty) + ">Fetch4 & DST (default)</option>\n";
    440 		html += "</select></td>\n";
    441 		html += "<tr><td>Force clearing registers that have no default value:</td><td><input name = 'forceClearRegisters' type='checkbox'" + (config.forceClearRegisters == true ? checked : empty) + " title='Initializes shader register values to 0 even if they have no default.'></td></tr>";
    442 		html += "</table>\n";
    443 	#ifndef NDEBUG
    444 		html += "<h2><em>Debugging</em></h2>\n";
    445 		html += "<table>\n";
    446 		html += "<tr><td>Minimum primitives:</td><td><input type='text' size='10' maxlength='10' name='minPrimitives' value='" + itoa(config.minPrimitives) + "'></td></tr>\n";
    447 		html += "<tr><td>Maximum primitives:</td><td><input type='text' size='10' maxlength='10' name='maxPrimitives' value='" + itoa(config.maxPrimitives) + "'></td></tr>\n";
    448 		html += "</table>\n";
    449 	#endif
    450 		html += "<hr><p>\n";
    451 		html += "<span style='font-size:10pt'>Hover the mouse pointer over a control to get additional information.</span><br>\n";
    452 		html += "<span style='font-size:10pt'>Some settings can be applied interactively, some need a restart of the application.</span><br>\n";
    453 		html += "<span style='font-size:10pt'>Removing the SwiftShader.ini file results in resetting the options to their default.</span></p>\n";
    454 		html += "</form>\n";
    455 		html += "</body>\n";
    456 		html += "</html>\n";
    457 
    458 		profiler.reset();
    459 
    460 		return html;
    461 	}
    462 
    463 	std::string SwiftConfig::profile()
    464 	{
    465 		std::string html;
    466 
    467 		html += "<p>FPS: " + ftoa(profiler.FPS) + "</p>\n";
    468 		html += "<p>Frame: " + itoa(profiler.framesTotal) + "</p>\n";
    469 
    470 		#if PERF_PROFILE
    471 			int texTime = (int)(1000 * profiler.cycles[PERF_TEX] / profiler.cycles[PERF_PIXEL] + 0.5);
    472 			int shaderTime = (int)(1000 * profiler.cycles[PERF_SHADER] / profiler.cycles[PERF_PIXEL] + 0.5);
    473 			int pipeTime = (int)(1000 * profiler.cycles[PERF_PIPE] / profiler.cycles[PERF_PIXEL] + 0.5);
    474 			int ropTime = (int)(1000 * profiler.cycles[PERF_ROP] / profiler.cycles[PERF_PIXEL] + 0.5);
    475 			int interpTime = (int)(1000 * profiler.cycles[PERF_INTERP] / profiler.cycles[PERF_PIXEL] + 0.5);
    476 			int rastTime = 1000 - pipeTime;
    477 
    478 			pipeTime -= shaderTime + ropTime + interpTime;
    479 			shaderTime -= texTime;
    480 
    481 			double texTimeF = (double)texTime / 10;
    482 			double shaderTimeF = (double)shaderTime / 10;
    483 			double pipeTimeF = (double)pipeTime / 10;
    484 			double ropTimeF = (double)ropTime / 10;
    485 			double interpTimeF = (double)interpTime / 10;
    486 			double rastTimeF = (double)rastTime / 10;
    487 
    488 			double averageRopOperations = profiler.ropOperationsTotal / std::max(profiler.framesTotal, 1) / 1.0e6f;
    489 			double averageCompressedTex = profiler.compressedTexTotal / std::max(profiler.framesTotal, 1) / 1.0e6f;
    490 			double averageTexOperations = profiler.texOperationsTotal / std::max(profiler.framesTotal, 1) / 1.0e6f;
    491 
    492 			html += "<p>Raster operations (million): " + ftoa(profiler.ropOperationsFrame / 1.0e6f) + " (current), " + ftoa(averageRopOperations) + " (average)</p>\n";
    493 			html += "<p>Texture operations (million): " + ftoa(profiler.texOperationsFrame / 1.0e6f) + " (current), " + ftoa(averageTexOperations) + " (average)</p>\n";
    494 			html += "<p>Compressed texture operations (million): " + ftoa(profiler.compressedTexFrame / 1.0e6f) + " (current), " + ftoa(averageCompressedTex) + " (average)</p>\n";
    495 			html += "<div id='profile' style='position:relative; width:1010px; height:50px; background-color:silver;'>";
    496 			html += "<div style='position:relative; width:1000px; height:40px; background-color:white; left:5px; top:5px;'>";
    497 			html += "<div style='position:relative; float:left; width:" + itoa(rastTime)   + "px; height:40px; border-style:none; text-align:center; line-height:40px; background-color:#FFFF7F; overflow:hidden;'>" + ftoa(rastTimeF)   + "% rast</div>\n";
    498 			html += "<div style='position:relative; float:left; width:" + itoa(pipeTime)   + "px; height:40px; border-style:none; text-align:center; line-height:40px; background-color:#FF7F7F; overflow:hidden;'>" + ftoa(pipeTimeF)   + "% pipe</div>\n";
    499 			html += "<div style='position:relative; float:left; width:" + itoa(interpTime) + "px; height:40px; border-style:none; text-align:center; line-height:40px; background-color:#7FFFFF; overflow:hidden;'>" + ftoa(interpTimeF) + "% interp</div>\n";
    500 			html += "<div style='position:relative; float:left; width:" + itoa(shaderTime) + "px; height:40px; border-style:none; text-align:center; line-height:40px; background-color:#7FFF7F; overflow:hidden;'>" + ftoa(shaderTimeF) + "% shader</div>\n";
    501 			html += "<div style='position:relative; float:left; width:" + itoa(texTime)    + "px; height:40px; border-style:none; text-align:center; line-height:40px; background-color:#FF7FFF; overflow:hidden;'>" + ftoa(texTimeF)    + "% tex</div>\n";
    502 			html += "<div style='position:relative; float:left; width:" + itoa(ropTime)    + "px; height:40px; border-style:none; text-align:center; line-height:40px; background-color:#7F7FFF; overflow:hidden;'>" + ftoa(ropTimeF)    + "% rop</div>\n";
    503 			html += "</div></div>\n";
    504 
    505 			for(int i = 0; i < PERF_TIMERS; i++)
    506 			{
    507 				profiler.cycles[i] = 0;
    508 			}
    509 		#endif
    510 
    511 		return html;
    512 	}
    513 
    514 	void SwiftConfig::send(Socket *clientSocket, Status code, std::string body)
    515 	{
    516 		std::string status;
    517 		char header[1024];
    518 
    519 		switch(code)
    520 		{
    521 		case OK:       status += "HTTP/1.1 200 OK\r\n";        break;
    522 		case NotFound: status += "HTTP/1.1 404 Not Found\r\n"; break;
    523 		}
    524 
    525 		sprintf(header, "Content-Type: text/html; charset=UTF-8\r\n"
    526 						"Content-Length: %zd\r\n"
    527 						"Host: localhost\r\n"
    528 						"\r\n", body.size());
    529 
    530 		std::string message = status + header + body;
    531 		clientSocket->send(message.c_str(), (int)message.length());
    532 	}
    533 
    534 	void SwiftConfig::parsePost(const char *post)
    535 	{
    536 		// Only enabled checkboxes appear in the POST
    537 		config.enableSSE = true;
    538 		config.enableSSE2 = false;
    539 		config.enableSSE3 = false;
    540 		config.enableSSSE3 = false;
    541 		config.enableSSE4_1 = false;
    542 		config.disableServer = false;
    543 		config.forceWindowed = false;
    544 		config.complementaryDepthBuffer = false;
    545 		config.postBlendSRGB = false;
    546 		config.exactColorRounding = false;
    547 		config.disableAlphaMode = false;
    548 		config.disable10BitMode = false;
    549 		config.precache = false;
    550 		config.forceClearRegisters = false;
    551 
    552 		while(*post != 0)
    553 		{
    554 			int integer;
    555 			int index;
    556 
    557 			if(sscanf(post, "pixelShaderVersion=%d", &integer))
    558 			{
    559 				config.pixelShaderVersion = integer;
    560 			}
    561 			else if(sscanf(post, "vertexShaderVersion=%d", &integer))
    562 			{
    563 				config.vertexShaderVersion = integer;
    564 			}
    565 			else if(sscanf(post, "textureMemory=%d", &integer))
    566 			{
    567 				config.textureMemory = integer;
    568 			}
    569 			else if(sscanf(post, "identifier=%d", &integer))
    570 			{
    571 				config.identifier = integer;
    572 			}
    573 			else if(sscanf(post, "vertexRoutineCacheSize=%d", &integer))
    574 			{
    575 				config.vertexRoutineCacheSize = integer;
    576 			}
    577 			else if(sscanf(post, "pixelRoutineCacheSize=%d", &integer))
    578 			{
    579 				config.pixelRoutineCacheSize = integer;
    580 			}
    581 			else if(sscanf(post, "setupRoutineCacheSize=%d", &integer))
    582 			{
    583 				config.setupRoutineCacheSize = integer;
    584 			}
    585 			else if(sscanf(post, "vertexCacheSize=%d", &integer))
    586 			{
    587 				config.vertexCacheSize = integer;
    588 			}
    589 			else if(sscanf(post, "textureSampleQuality=%d", &integer))
    590 			{
    591 				config.textureSampleQuality = integer;
    592 			}
    593 			else if(sscanf(post, "mipmapQuality=%d", &integer))
    594 			{
    595 				config.mipmapQuality = integer;
    596 			}
    597 			else if(sscanf(post, "perspectiveCorrection=%d", &integer))
    598 			{
    599 				config.perspectiveCorrection = integer != 0;
    600 			}
    601 			else if(sscanf(post, "transcendentalPrecision=%d", &integer))
    602 			{
    603 				config.transcendentalPrecision = integer;
    604 			}
    605 			else if(sscanf(post, "transparencyAntialiasing=%d", &integer))
    606 			{
    607 				config.transparencyAntialiasing = integer;
    608 			}
    609 			else if(sscanf(post, "threadCount=%d", &integer))
    610 			{
    611 				config.threadCount = integer;
    612 			}
    613 			else if(sscanf(post, "frameBufferAPI=%d", &integer))
    614 			{
    615 				config.frameBufferAPI = integer;
    616 			}
    617 			else if(sscanf(post, "shadowMapping=%d", &integer))
    618 			{
    619 				config.shadowMapping = integer;
    620 			}
    621 			else if(strstr(post, "enableSSE=on"))
    622 			{
    623 				config.enableSSE = true;
    624 			}
    625 			else if(strstr(post, "enableSSE2=on"))
    626 			{
    627 				if(config.enableSSE)
    628 				{
    629 					config.enableSSE2 = true;
    630 				}
    631 			}
    632 			else if(strstr(post, "enableSSE3=on"))
    633 			{
    634 				if(config.enableSSE2)
    635 				{
    636 					config.enableSSE3 = true;
    637 				}
    638 			}
    639 			else if(strstr(post, "enableSSSE3=on"))
    640 			{
    641 				if(config.enableSSE3)
    642 				{
    643 					config.enableSSSE3 = true;
    644 				}
    645 			}
    646 			else if(strstr(post, "enableSSE4_1=on"))
    647 			{
    648 				if(config.enableSSSE3)
    649 				{
    650 					config.enableSSE4_1 = true;
    651 				}
    652 			}
    653 			else if(sscanf(post, "optimization%d=%d", &index, &integer))
    654 			{
    655 				config.optimization[index - 1] = (rr::Optimization)integer;
    656 			}
    657 			else if(strstr(post, "disableServer=on"))
    658 			{
    659 				config.disableServer = true;
    660 			}
    661 			else if(strstr(post, "forceWindowed=on"))
    662 			{
    663 				config.forceWindowed = true;
    664 			}
    665 			else if(strstr(post, "complementaryDepthBuffer=on"))
    666 			{
    667 				config.complementaryDepthBuffer = true;
    668 			}
    669 			else if(strstr(post, "postBlendSRGB=on"))
    670 			{
    671 				config.postBlendSRGB = true;
    672 			}
    673 			else if(strstr(post, "exactColorRounding=on"))
    674 			{
    675 				config.exactColorRounding = true;
    676 			}
    677 			else if(strstr(post, "disableAlphaMode=on"))
    678 			{
    679 				config.disableAlphaMode = true;
    680 			}
    681 			else if(strstr(post, "disable10BitMode=on"))
    682 			{
    683 				config.disable10BitMode = true;
    684 			}
    685 			else if(strstr(post, "precache=on"))
    686 			{
    687 				config.precache = true;
    688 			}
    689 			else if(strstr(post, "forceClearRegisters=on"))
    690 			{
    691 				config.forceClearRegisters = true;
    692 			}
    693 		#ifndef NDEBUG
    694 			else if(sscanf(post, "minPrimitives=%d", &integer))
    695 			{
    696 				config.minPrimitives = integer;
    697 			}
    698 			else if(sscanf(post, "maxPrimitives=%d", &integer))
    699 			{
    700 				config.maxPrimitives = integer;
    701 			}
    702 		#endif
    703 			else
    704 			{
    705 				ASSERT(false);
    706 			}
    707 
    708 			do
    709 			{
    710 				post++;
    711 			}
    712 			while(post[-1] != '&' && *post != 0);
    713 		}
    714 	}
    715 
    716 	void SwiftConfig::readConfiguration(bool disableServerOverride)
    717 	{
    718 		Configurator ini("SwiftShader.ini");
    719 
    720 		config.pixelShaderVersion = ini.getInteger("Capabilities", "PixelShaderVersion", 30);
    721 		config.vertexShaderVersion = ini.getInteger("Capabilities", "VertexShaderVersion", 30);
    722 		config.textureMemory = ini.getInteger("Capabilities", "TextureMemory", 256);
    723 		config.identifier = ini.getInteger("Capabilities", "Identifier", 0);
    724 		config.vertexRoutineCacheSize = ini.getInteger("Caches", "VertexRoutineCacheSize", 1024);
    725 		config.pixelRoutineCacheSize = ini.getInteger("Caches", "PixelRoutineCacheSize", 1024);
    726 		config.setupRoutineCacheSize = ini.getInteger("Caches", "SetupRoutineCacheSize", 1024);
    727 		config.vertexCacheSize = ini.getInteger("Caches", "VertexCacheSize", 64);
    728 		config.textureSampleQuality = ini.getInteger("Quality", "TextureSampleQuality", 2);
    729 		config.mipmapQuality = ini.getInteger("Quality", "MipmapQuality", 1);
    730 		config.perspectiveCorrection = ini.getBoolean("Quality", "PerspectiveCorrection", true);
    731 		config.transcendentalPrecision = ini.getInteger("Quality", "TranscendentalPrecision", 2);
    732 		config.transparencyAntialiasing = ini.getInteger("Quality", "TransparencyAntialiasing", 0);
    733 		config.threadCount = ini.getInteger("Processor", "ThreadCount", DEFAULT_THREAD_COUNT);
    734 		config.enableSSE = ini.getBoolean("Processor", "EnableSSE", true);
    735 		config.enableSSE2 = ini.getBoolean("Processor", "EnableSSE2", true);
    736 		config.enableSSE3 = ini.getBoolean("Processor", "EnableSSE3", true);
    737 		config.enableSSSE3 = ini.getBoolean("Processor", "EnableSSSE3", true);
    738 		config.enableSSE4_1 = ini.getBoolean("Processor", "EnableSSE4_1", true);
    739 
    740 		for(int pass = 0; pass < 10; pass++)
    741 		{
    742 			config.optimization[pass] = (rr::Optimization)ini.getInteger("Optimization", "OptimizationPass" + itoa(pass + 1), pass == 0 ? rr::InstructionCombining : rr::Disabled);
    743 		}
    744 
    745 		config.disableServer = ini.getBoolean("Testing", "DisableServer", false);
    746 		config.forceWindowed = ini.getBoolean("Testing", "ForceWindowed", false);
    747 		config.complementaryDepthBuffer = ini.getBoolean("Testing", "ComplementaryDepthBuffer", false);
    748 		config.postBlendSRGB = ini.getBoolean("Testing", "PostBlendSRGB", false);
    749 		config.exactColorRounding = ini.getBoolean("Testing", "ExactColorRounding", true);
    750 		config.disableAlphaMode = ini.getBoolean("Testing", "DisableAlphaMode", false);
    751 		config.disable10BitMode = ini.getBoolean("Testing", "Disable10BitMode", false);
    752 		config.frameBufferAPI = ini.getInteger("Testing", "FrameBufferAPI", 0);
    753 		config.precache = ini.getBoolean("Testing", "Precache", false);
    754 		config.shadowMapping = ini.getInteger("Testing", "ShadowMapping", 3);
    755 		config.forceClearRegisters = ini.getBoolean("Testing", "ForceClearRegisters", false);
    756 
    757 	#ifndef NDEBUG
    758 		config.minPrimitives = 1;
    759 		config.maxPrimitives = 1 << 21;
    760 	#endif
    761 
    762 		struct stat status;
    763 		int lastModified = ini.getInteger("LastModified", "Time", 0);
    764 
    765 		bool noConfig = stat("SwiftShader.ini", &status) != 0;
    766 		newConfig = !noConfig && abs((int)status.st_mtime - lastModified) > 1;
    767 
    768 		if(disableServerOverride)
    769 		{
    770 			config.disableServer = true;
    771 		}
    772 	}
    773 
    774 	void SwiftConfig::writeConfiguration()
    775 	{
    776 		Configurator ini("SwiftShader.ini");
    777 
    778 		ini.addValue("Capabilities", "PixelShaderVersion", itoa(config.pixelShaderVersion));
    779 		ini.addValue("Capabilities", "VertexShaderVersion", itoa(config.vertexShaderVersion));
    780 		ini.addValue("Capabilities", "TextureMemory", itoa(config.textureMemory));
    781 		ini.addValue("Capabilities", "Identifier", itoa(config.identifier));
    782 		ini.addValue("Caches", "VertexRoutineCacheSize", itoa(config.vertexRoutineCacheSize));
    783 		ini.addValue("Caches", "PixelRoutineCacheSize", itoa(config.pixelRoutineCacheSize));
    784 		ini.addValue("Caches", "SetupRoutineCacheSize", itoa(config.setupRoutineCacheSize));
    785 		ini.addValue("Caches", "VertexCacheSize", itoa(config.vertexCacheSize));
    786 		ini.addValue("Quality", "TextureSampleQuality", itoa(config.textureSampleQuality));
    787 		ini.addValue("Quality", "MipmapQuality", itoa(config.mipmapQuality));
    788 		ini.addValue("Quality", "PerspectiveCorrection", itoa(config.perspectiveCorrection));
    789 		ini.addValue("Quality", "TranscendentalPrecision", itoa(config.transcendentalPrecision));
    790 		ini.addValue("Quality", "TransparencyAntialiasing", itoa(config.transparencyAntialiasing));
    791 		ini.addValue("Processor", "ThreadCount", itoa(config.threadCount));
    792 	//	ini.addValue("Processor", "EnableSSE", itoa(config.enableSSE));
    793 		ini.addValue("Processor", "EnableSSE2", itoa(config.enableSSE2));
    794 		ini.addValue("Processor", "EnableSSE3", itoa(config.enableSSE3));
    795 		ini.addValue("Processor", "EnableSSSE3", itoa(config.enableSSSE3));
    796 		ini.addValue("Processor", "EnableSSE4_1", itoa(config.enableSSE4_1));
    797 
    798 		for(int pass = 0; pass < 10; pass++)
    799 		{
    800 			ini.addValue("Optimization", "OptimizationPass" + itoa(pass + 1), itoa(config.optimization[pass]));
    801 		}
    802 
    803 		ini.addValue("Testing", "DisableServer", itoa(config.disableServer));
    804 		ini.addValue("Testing", "ForceWindowed", itoa(config.forceWindowed));
    805 		ini.addValue("Testing", "ComplementaryDepthBuffer", itoa(config.complementaryDepthBuffer));
    806 		ini.addValue("Testing", "PostBlendSRGB", itoa(config.postBlendSRGB));
    807 		ini.addValue("Testing", "ExactColorRounding", itoa(config.exactColorRounding));
    808 		ini.addValue("Testing", "DisableAlphaMode", itoa(config.disableAlphaMode));
    809 		ini.addValue("Testing", "Disable10BitMode", itoa(config.disable10BitMode));
    810 		ini.addValue("Testing", "FrameBufferAPI", itoa(config.frameBufferAPI));
    811 		ini.addValue("Testing", "Precache", itoa(config.precache));
    812 		ini.addValue("Testing", "ShadowMapping", itoa(config.shadowMapping));
    813 		ini.addValue("Testing", "ForceClearRegisters", itoa(config.forceClearRegisters));
    814 		ini.addValue("LastModified", "Time", itoa((int)time(0)));
    815 
    816 		ini.writeFile("SwiftShader Configuration File\n"
    817 		              ";\n"
    818 					  "; To get an overview of the valid settings and their meaning,\n"
    819 					  "; run the application in windowed mode and open the\n"
    820 					  "; SwiftConfig application or go to http://localhost:8080/swiftconfig.");
    821 	}
    822 }
    823