// Copyright 2016 The SwiftShader Authors. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include "SwiftConfig.hpp" #include "Config.hpp" #include "System/Configurator.hpp" #include "Vulkan/VkDebug.hpp" #include "Vulkan/Version.h" #include #include #include #include #include #include namespace sw { extern Profiler profiler; std::string itoa(int number) { std::stringstream ss; ss << number; return ss.str(); } std::string ftoa(double number) { std::stringstream ss; ss << number; return ss.str(); } SwiftConfig::SwiftConfig(bool disableServerOverride) : listenSocket(0) { readConfiguration(disableServerOverride); if(!disableServerOverride) { writeConfiguration(); } receiveBuffer = 0; if(!config.disableServer) { createServer(); } } SwiftConfig::~SwiftConfig() { destroyServer(); } void SwiftConfig::createServer() { bufferLength = 16 * 1024; receiveBuffer = new char[bufferLength]; Socket::startup(); listenSocket = new Socket("localhost", "8080"); listenSocket->listen(); terminate = false; serverThread = new Thread(serverRoutine, this); } void SwiftConfig::destroyServer() { if(receiveBuffer) { terminate = true; serverThread->join(); delete serverThread; delete listenSocket; listenSocket = 0; Socket::cleanup(); delete[] receiveBuffer; receiveBuffer = 0; } } bool SwiftConfig::hasNewConfiguration(bool reset) { bool value = newConfig; if(reset) { newConfig = false; } return value; } void SwiftConfig::getConfiguration(Configuration &configuration) { criticalSection.lock(); configuration = config; criticalSection.unlock(); } void SwiftConfig::serverRoutine(void *parameters) { SwiftConfig *swiftConfig = (SwiftConfig*)parameters; swiftConfig->serverLoop(); } void SwiftConfig::serverLoop() { readConfiguration(); while(!terminate) { if(listenSocket->select(100000)) { Socket *clientSocket = listenSocket->accept(); int bytesReceived = 1; while(bytesReceived > 0 && !terminate) { if(clientSocket->select(10)) { bytesReceived = clientSocket->receive(receiveBuffer, bufferLength); if(bytesReceived > 0) { receiveBuffer[bytesReceived] = 0; respond(clientSocket, receiveBuffer); } } } delete clientSocket; } } } bool match(const char **url, const char *string) { size_t length = strlen(string); if(strncmp(*url, string, length) == 0) { *url += length; return true; } return false; } void SwiftConfig::respond(Socket *clientSocket, const char *request) { if(match(&request, "GET /")) { if(match(&request, "swiftshader") || match(&request, "swiftconfig")) { if(match(&request, " ") || match(&request, "/ ")) { return send(clientSocket, OK, page()); } } } else if(match(&request, "POST /")) { if(match(&request, "swiftshader") || match(&request, "swiftconfig")) { if(match(&request, " ") || match(&request, "/ ")) { criticalSection.lock(); const char *postData = strstr(request, "\r\n\r\n"); postData = postData ? postData + 4 : 0; if(postData && strlen(postData) > 0) { parsePost(postData); } else // POST data in next packet { int bytesReceived = clientSocket->receive(receiveBuffer, bufferLength); if(bytesReceived > 0) { receiveBuffer[bytesReceived] = 0; parsePost(receiveBuffer); } } writeConfiguration(); newConfig = true; if(config.disableServer) { destroyServer(); } criticalSection.unlock(); return send(clientSocket, OK, page()); } else if(match(&request, "/profile ")) { return send(clientSocket, OK, profile()); } } } return send(clientSocket, NotFound); } std::string SwiftConfig::page() { std::string html; const std::string selected = "selected='selected'"; const std::string checked = "checked='checked'"; const std::string empty = ""; html += "\n"; html += "\n"; html += "\n"; html += "\n"; html += "SwiftShader Configuration Panel\n"; html += "\n"; html += "\n"; html += "\n"; html += "
\n"; html += "

SwiftShader Configuration Panel

\n"; html += "
" + profile() + "
\n"; html += "

\n"; html += "\n"; // html += "\n"; html += "


\n"; html += "

Device capabilities

\n"; html += "\n"; html += "\n"; html += "\n"; html += "\n"; html += "\n"; html += "\n"; html += "
Build revision:" REVISION_STRING "
Pixel shader model:
Vertex shader model:
Texture memory:
Device identifier:
\n"; html += "

Cache sizes

\n"; html += "\n"; html += "\n"; html += "\n"; html += "\n"; html += "\n"; html += "\n"; html += "\n"; html += "\n"; html += "\n"; html += "
Vertex routine cache size:
Pixel routine cache size:
Setup routine cache size:
Vertex cache size:
\n"; html += "

Quality

\n"; html += "\n"; html += "\n"; html += "\n"; html += "\n"; html += "\n"; html += "\n"; html += "\n"; html += "\n"; html += "\n"; html += "\n"; html += "
Maximum texture sampling quality:
Maximum mipmapping quality:
Perspective correction:
Transcendental function precision:
Transparency anti-aliasing:
\n"; html += "

Processor settings

\n"; html += "\n"; html += "\n"; html += ""; html += ""; html += ""; html += ""; html += ""; html += "
Number of threads:
Enable SSE:
Enable SSE2:
Enable SSE3:
Enable SSSE3:
Enable SSE4.1:
\n"; html += "

Compiler optimizations

\n"; html += "\n"; for(int pass = 0; pass < 10; pass++) { html += "\n"; } html += "
Optimization pass " + itoa(pass + 1) + ":
\n"; html += "

Testing & Experimental

\n"; html += "\n"; html += ""; html += ""; html += ""; html += ""; html += ""; html += ""; html += ""; html += "\n"; html += ""; html += "\n"; html += ""; html += "
Disable SwiftConfig server:
Force windowed mode:
Complementary depth buffer:
Post alpha blend sRGB conversion:
Exact color rounding:
Disable alpha display formats:
Disable 10-bit display formats:
Frame-buffer API:
DLL precaching:
Shadow mapping extensions:
Force clearing registers that have no default value:
\n"; #ifndef NDEBUG html += "

Debugging

\n"; html += "\n"; html += "\n"; html += "\n"; html += "
Minimum primitives:
Maximum primitives:
\n"; #endif html += "

\n"; html += "Hover the mouse pointer over a control to get additional information.
\n"; html += "Some settings can be applied interactively, some need a restart of the application.
\n"; html += "Removing the SwiftShader.ini file results in resetting the options to their default.

\n"; html += "
\n"; html += "\n"; html += "\n"; profiler.reset(); return html; } std::string SwiftConfig::profile() { std::string html; html += "

FPS: " + ftoa(profiler.FPS) + "

\n"; html += "

Frame: " + itoa(profiler.framesTotal) + "

\n"; #if PERF_PROFILE int texTime = (int)(1000 * profiler.cycles[PERF_TEX] / profiler.cycles[PERF_PIXEL] + 0.5); int shaderTime = (int)(1000 * profiler.cycles[PERF_SHADER] / profiler.cycles[PERF_PIXEL] + 0.5); int pipeTime = (int)(1000 * profiler.cycles[PERF_PIPE] / profiler.cycles[PERF_PIXEL] + 0.5); int ropTime = (int)(1000 * profiler.cycles[PERF_ROP] / profiler.cycles[PERF_PIXEL] + 0.5); int interpTime = (int)(1000 * profiler.cycles[PERF_INTERP] / profiler.cycles[PERF_PIXEL] + 0.5); int rastTime = 1000 - pipeTime; pipeTime -= shaderTime + ropTime + interpTime; shaderTime -= texTime; double texTimeF = (double)texTime / 10; double shaderTimeF = (double)shaderTime / 10; double pipeTimeF = (double)pipeTime / 10; double ropTimeF = (double)ropTime / 10; double interpTimeF = (double)interpTime / 10; double rastTimeF = (double)rastTime / 10; double averageRopOperations = profiler.ropOperationsTotal / std::max(profiler.framesTotal, 1) / 1.0e6f; double averageCompressedTex = profiler.compressedTexTotal / std::max(profiler.framesTotal, 1) / 1.0e6f; double averageTexOperations = profiler.texOperationsTotal / std::max(profiler.framesTotal, 1) / 1.0e6f; html += "

Raster operations (million): " + ftoa(profiler.ropOperationsFrame / 1.0e6f) + " (current), " + ftoa(averageRopOperations) + " (average)

\n"; html += "

Texture operations (million): " + ftoa(profiler.texOperationsFrame / 1.0e6f) + " (current), " + ftoa(averageTexOperations) + " (average)

\n"; html += "

Compressed texture operations (million): " + ftoa(profiler.compressedTexFrame / 1.0e6f) + " (current), " + ftoa(averageCompressedTex) + " (average)

\n"; html += "
"; html += "
"; html += "
" + ftoa(rastTimeF) + "% rast
\n"; html += "
" + ftoa(pipeTimeF) + "% pipe
\n"; html += "
" + ftoa(interpTimeF) + "% interp
\n"; html += "
" + ftoa(shaderTimeF) + "% shader
\n"; html += "
" + ftoa(texTimeF) + "% tex
\n"; html += "
" + ftoa(ropTimeF) + "% rop
\n"; html += "
\n"; for(int i = 0; i < PERF_TIMERS; i++) { profiler.cycles[i] = 0; } #endif return html; } void SwiftConfig::send(Socket *clientSocket, Status code, std::string body) { std::string status; char header[1024]; switch(code) { case OK: status += "HTTP/1.1 200 OK\r\n"; break; case NotFound: status += "HTTP/1.1 404 Not Found\r\n"; break; } sprintf(header, "Content-Type: text/html; charset=UTF-8\r\n" "Content-Length: %zd\r\n" "Host: localhost\r\n" "\r\n", body.size()); std::string message = status + header + body; clientSocket->send(message.c_str(), (int)message.length()); } void SwiftConfig::parsePost(const char *post) { // Only enabled checkboxes appear in the POST config.enableSSE = true; config.enableSSE2 = false; config.enableSSE3 = false; config.enableSSSE3 = false; config.enableSSE4_1 = false; config.disableServer = false; config.forceWindowed = false; config.complementaryDepthBuffer = false; config.postBlendSRGB = false; config.exactColorRounding = false; config.disableAlphaMode = false; config.disable10BitMode = false; config.precache = false; config.forceClearRegisters = false; while(*post != 0) { int integer; int index; if(sscanf(post, "pixelShaderVersion=%d", &integer)) { config.pixelShaderVersion = integer; } else if(sscanf(post, "vertexShaderVersion=%d", &integer)) { config.vertexShaderVersion = integer; } else if(sscanf(post, "textureMemory=%d", &integer)) { config.textureMemory = integer; } else if(sscanf(post, "identifier=%d", &integer)) { config.identifier = integer; } else if(sscanf(post, "vertexRoutineCacheSize=%d", &integer)) { config.vertexRoutineCacheSize = integer; } else if(sscanf(post, "pixelRoutineCacheSize=%d", &integer)) { config.pixelRoutineCacheSize = integer; } else if(sscanf(post, "setupRoutineCacheSize=%d", &integer)) { config.setupRoutineCacheSize = integer; } else if(sscanf(post, "vertexCacheSize=%d", &integer)) { config.vertexCacheSize = integer; } else if(sscanf(post, "textureSampleQuality=%d", &integer)) { config.textureSampleQuality = integer; } else if(sscanf(post, "mipmapQuality=%d", &integer)) { config.mipmapQuality = integer; } else if(sscanf(post, "perspectiveCorrection=%d", &integer)) { config.perspectiveCorrection = integer != 0; } else if(sscanf(post, "transcendentalPrecision=%d", &integer)) { config.transcendentalPrecision = integer; } else if(sscanf(post, "transparencyAntialiasing=%d", &integer)) { config.transparencyAntialiasing = integer; } else if(sscanf(post, "threadCount=%d", &integer)) { config.threadCount = integer; } else if(sscanf(post, "frameBufferAPI=%d", &integer)) { config.frameBufferAPI = integer; } else if(sscanf(post, "shadowMapping=%d", &integer)) { config.shadowMapping = integer; } else if(strstr(post, "enableSSE=on")) { config.enableSSE = true; } else if(strstr(post, "enableSSE2=on")) { if(config.enableSSE) { config.enableSSE2 = true; } } else if(strstr(post, "enableSSE3=on")) { if(config.enableSSE2) { config.enableSSE3 = true; } } else if(strstr(post, "enableSSSE3=on")) { if(config.enableSSE3) { config.enableSSSE3 = true; } } else if(strstr(post, "enableSSE4_1=on")) { if(config.enableSSSE3) { config.enableSSE4_1 = true; } } else if(sscanf(post, "optimization%d=%d", &index, &integer)) { config.optimization[index - 1] = (rr::Optimization)integer; } else if(strstr(post, "disableServer=on")) { config.disableServer = true; } else if(strstr(post, "forceWindowed=on")) { config.forceWindowed = true; } else if(strstr(post, "complementaryDepthBuffer=on")) { config.complementaryDepthBuffer = true; } else if(strstr(post, "postBlendSRGB=on")) { config.postBlendSRGB = true; } else if(strstr(post, "exactColorRounding=on")) { config.exactColorRounding = true; } else if(strstr(post, "disableAlphaMode=on")) { config.disableAlphaMode = true; } else if(strstr(post, "disable10BitMode=on")) { config.disable10BitMode = true; } else if(strstr(post, "precache=on")) { config.precache = true; } else if(strstr(post, "forceClearRegisters=on")) { config.forceClearRegisters = true; } #ifndef NDEBUG else if(sscanf(post, "minPrimitives=%d", &integer)) { config.minPrimitives = integer; } else if(sscanf(post, "maxPrimitives=%d", &integer)) { config.maxPrimitives = integer; } #endif else { ASSERT(false); } do { post++; } while(post[-1] != '&' && *post != 0); } } void SwiftConfig::readConfiguration(bool disableServerOverride) { Configurator ini("SwiftShader.ini"); config.pixelShaderVersion = ini.getInteger("Capabilities", "PixelShaderVersion", 30); config.vertexShaderVersion = ini.getInteger("Capabilities", "VertexShaderVersion", 30); config.textureMemory = ini.getInteger("Capabilities", "TextureMemory", 256); config.identifier = ini.getInteger("Capabilities", "Identifier", 0); config.vertexRoutineCacheSize = ini.getInteger("Caches", "VertexRoutineCacheSize", 1024); config.pixelRoutineCacheSize = ini.getInteger("Caches", "PixelRoutineCacheSize", 1024); config.setupRoutineCacheSize = ini.getInteger("Caches", "SetupRoutineCacheSize", 1024); config.vertexCacheSize = ini.getInteger("Caches", "VertexCacheSize", 64); config.textureSampleQuality = ini.getInteger("Quality", "TextureSampleQuality", 2); config.mipmapQuality = ini.getInteger("Quality", "MipmapQuality", 1); config.perspectiveCorrection = ini.getBoolean("Quality", "PerspectiveCorrection", true); config.transcendentalPrecision = ini.getInteger("Quality", "TranscendentalPrecision", 2); config.transparencyAntialiasing = ini.getInteger("Quality", "TransparencyAntialiasing", 0); config.threadCount = ini.getInteger("Processor", "ThreadCount", DEFAULT_THREAD_COUNT); config.enableSSE = ini.getBoolean("Processor", "EnableSSE", true); config.enableSSE2 = ini.getBoolean("Processor", "EnableSSE2", true); config.enableSSE3 = ini.getBoolean("Processor", "EnableSSE3", true); config.enableSSSE3 = ini.getBoolean("Processor", "EnableSSSE3", true); config.enableSSE4_1 = ini.getBoolean("Processor", "EnableSSE4_1", true); for(int pass = 0; pass < 10; pass++) { config.optimization[pass] = (rr::Optimization)ini.getInteger("Optimization", "OptimizationPass" + itoa(pass + 1), pass == 0 ? rr::InstructionCombining : rr::Disabled); } config.disableServer = ini.getBoolean("Testing", "DisableServer", false); config.forceWindowed = ini.getBoolean("Testing", "ForceWindowed", false); config.complementaryDepthBuffer = ini.getBoolean("Testing", "ComplementaryDepthBuffer", false); config.postBlendSRGB = ini.getBoolean("Testing", "PostBlendSRGB", false); config.exactColorRounding = ini.getBoolean("Testing", "ExactColorRounding", true); config.disableAlphaMode = ini.getBoolean("Testing", "DisableAlphaMode", false); config.disable10BitMode = ini.getBoolean("Testing", "Disable10BitMode", false); config.frameBufferAPI = ini.getInteger("Testing", "FrameBufferAPI", 0); config.precache = ini.getBoolean("Testing", "Precache", false); config.shadowMapping = ini.getInteger("Testing", "ShadowMapping", 3); config.forceClearRegisters = ini.getBoolean("Testing", "ForceClearRegisters", false); #ifndef NDEBUG config.minPrimitives = 1; config.maxPrimitives = 1 << 21; #endif struct stat status; int lastModified = ini.getInteger("LastModified", "Time", 0); bool noConfig = stat("SwiftShader.ini", &status) != 0; newConfig = !noConfig && abs((int)status.st_mtime - lastModified) > 1; if(disableServerOverride) { config.disableServer = true; } } void SwiftConfig::writeConfiguration() { Configurator ini("SwiftShader.ini"); ini.addValue("Capabilities", "PixelShaderVersion", itoa(config.pixelShaderVersion)); ini.addValue("Capabilities", "VertexShaderVersion", itoa(config.vertexShaderVersion)); ini.addValue("Capabilities", "TextureMemory", itoa(config.textureMemory)); ini.addValue("Capabilities", "Identifier", itoa(config.identifier)); ini.addValue("Caches", "VertexRoutineCacheSize", itoa(config.vertexRoutineCacheSize)); ini.addValue("Caches", "PixelRoutineCacheSize", itoa(config.pixelRoutineCacheSize)); ini.addValue("Caches", "SetupRoutineCacheSize", itoa(config.setupRoutineCacheSize)); ini.addValue("Caches", "VertexCacheSize", itoa(config.vertexCacheSize)); ini.addValue("Quality", "TextureSampleQuality", itoa(config.textureSampleQuality)); ini.addValue("Quality", "MipmapQuality", itoa(config.mipmapQuality)); ini.addValue("Quality", "PerspectiveCorrection", itoa(config.perspectiveCorrection)); ini.addValue("Quality", "TranscendentalPrecision", itoa(config.transcendentalPrecision)); ini.addValue("Quality", "TransparencyAntialiasing", itoa(config.transparencyAntialiasing)); ini.addValue("Processor", "ThreadCount", itoa(config.threadCount)); // ini.addValue("Processor", "EnableSSE", itoa(config.enableSSE)); ini.addValue("Processor", "EnableSSE2", itoa(config.enableSSE2)); ini.addValue("Processor", "EnableSSE3", itoa(config.enableSSE3)); ini.addValue("Processor", "EnableSSSE3", itoa(config.enableSSSE3)); ini.addValue("Processor", "EnableSSE4_1", itoa(config.enableSSE4_1)); for(int pass = 0; pass < 10; pass++) { ini.addValue("Optimization", "OptimizationPass" + itoa(pass + 1), itoa(config.optimization[pass])); } ini.addValue("Testing", "DisableServer", itoa(config.disableServer)); ini.addValue("Testing", "ForceWindowed", itoa(config.forceWindowed)); ini.addValue("Testing", "ComplementaryDepthBuffer", itoa(config.complementaryDepthBuffer)); ini.addValue("Testing", "PostBlendSRGB", itoa(config.postBlendSRGB)); ini.addValue("Testing", "ExactColorRounding", itoa(config.exactColorRounding)); ini.addValue("Testing", "DisableAlphaMode", itoa(config.disableAlphaMode)); ini.addValue("Testing", "Disable10BitMode", itoa(config.disable10BitMode)); ini.addValue("Testing", "FrameBufferAPI", itoa(config.frameBufferAPI)); ini.addValue("Testing", "Precache", itoa(config.precache)); ini.addValue("Testing", "ShadowMapping", itoa(config.shadowMapping)); ini.addValue("Testing", "ForceClearRegisters", itoa(config.forceClearRegisters)); ini.addValue("LastModified", "Time", itoa((int)time(0))); ini.writeFile("SwiftShader Configuration File\n" ";\n" "; To get an overview of the valid settings and their meaning,\n" "; run the application in windowed mode and open the\n" "; SwiftConfig application or go to http://localhost:8080/swiftconfig."); } }