summaryrefslogtreecommitdiff
path: root/utils/remoteshadercompile/remoteshadercompile.cpp
diff options
context:
space:
mode:
authorFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
committerFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
commit3bf9df6b2785fa6d951086978a3e66f49427166a (patch)
tree2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /utils/remoteshadercompile/remoteshadercompile.cpp
downloadarchived-source-engine-2018-hl2-src-3bf9df6b2785fa6d951086978a3e66f49427166a.tar.xz
archived-source-engine-2018-hl2-src-3bf9df6b2785fa6d951086978a3e66f49427166a.zip
Diffstat (limited to 'utils/remoteshadercompile/remoteshadercompile.cpp')
-rw-r--r--utils/remoteshadercompile/remoteshadercompile.cpp316
1 files changed, 316 insertions, 0 deletions
diff --git a/utils/remoteshadercompile/remoteshadercompile.cpp b/utils/remoteshadercompile/remoteshadercompile.cpp
new file mode 100644
index 0000000..81438a1
--- /dev/null
+++ b/utils/remoteshadercompile/remoteshadercompile.cpp
@@ -0,0 +1,316 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Defines the entry point for the console application
+//
+//===============================================================================
+
+//#include <sys/stat.h>
+//#include <time.h>
+#include <winsock2.h>
+#include <ws2tcpip.h>
+#include <conio.h >
+#include "tier1/utlvector.h"
+#include "tier0/icommandline.h"
+#include "tier2/tier2.h"
+#include "tier2/fileutils.h"
+#include "../../dx9sdk/include/d3d9.h"
+#include "../../dx9sdk/include/d3dx9.h"
+
+#define DEFAULT_PORT "20000"
+#define DEFAULT_SEND_BUF_LEN 40000
+#define DEFAULT_RECV_BUF_LEN 40000
+
+char g_pPathBase[MAX_PATH];
+bool g_bPrintDisassembly;
+
+// This guy just spins and compiles when a command comes in from the game
+void ServerThread( void * )
+{
+ WSADATA wsaData;
+ if( WSAStartup( 0x101, &wsaData ) != 0 )
+ return;
+
+ struct addrinfo *result = NULL, hints;
+
+ ZeroMemory( &hints, sizeof(hints) );
+ hints.ai_family = AF_INET;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_protocol = IPPROTO_TCP;
+ hints.ai_flags = AI_PASSIVE;
+
+ // Resolve the server address and port
+ int nResult = getaddrinfo( NULL, DEFAULT_PORT, &hints, &result );
+ if ( nResult != 0 )
+ {
+ printf( "getaddrinfo failed: %d\n", nResult );
+ WSACleanup();
+ return;
+ }
+
+ // Create a SOCKET for connecting to server
+ SOCKET ListenSocket = socket( result->ai_family, result->ai_socktype, result->ai_protocol );
+ if (ListenSocket == INVALID_SOCKET) {
+ printf("socket failed: %ld\n", WSAGetLastError());
+ freeaddrinfo(result);
+ WSACleanup();
+ return;
+ }
+
+ // Setup the TCP listening socket
+ nResult = bind( ListenSocket, result->ai_addr, (int)result->ai_addrlen );
+ if (nResult == SOCKET_ERROR)
+ {
+ printf("bind failed: %d\n", WSAGetLastError());
+ freeaddrinfo(result);
+ closesocket(ListenSocket);
+ WSACleanup();
+ return;
+ }
+
+ freeaddrinfo(result);
+
+
+ nResult = listen( ListenSocket, SOMAXCONN );
+ if ( nResult == SOCKET_ERROR )
+ {
+ printf( "listen failed: %d\n", WSAGetLastError() );
+ closesocket( ListenSocket );
+ WSACleanup();
+ return;
+ }
+
+ printf( "Waiting for initial connection...\n" );
+
+ // Accept a client socket
+ SOCKET ClientSocket = accept( ListenSocket, NULL, NULL );
+ if ( ClientSocket == INVALID_SOCKET )
+ {
+ printf( "accept failed: %d\n", WSAGetLastError() );
+ closesocket( ListenSocket );
+ WSACleanup();
+ return;
+ }
+
+ // First connection
+ printf( "Game connected\n" );
+
+ char pRecbuf[DEFAULT_RECV_BUF_LEN]; // Text in command file from game
+ uint32 pSendbuf[DEFAULT_SEND_BUF_LEN]; // Error string or binary shader blob in reply
+
+ while ( true )
+ {
+ nResult = recv( ClientSocket, pRecbuf, DEFAULT_RECV_BUF_LEN, 0 );
+
+ if ( nResult > 0 )
+ {
+ char *pShaderFilename = strtok ( pRecbuf, "\n");
+ char pFullFilename[MAX_PATH];
+
+ // If we took in a path on the commandline, we concatenate the incoming filenames with it
+ if ( V_strlen( g_pPathBase ) > 0 )
+ {
+ V_strncpy( pFullFilename, g_pPathBase, MAX_PATH ); // base path
+ V_strncat( pFullFilename, pShaderFilename, MAX_PATH );
+ pShaderFilename = pFullFilename;
+ }
+ char *pShaderModel = strtok ( NULL, "\n");
+ int nSendBufLen = 0;
+
+ // Only try to compile if we have a recognized profile
+ if ( !stricmp( pShaderModel, "vs_2_0" ) || !stricmp( pShaderModel, "ps_2_0" ) || !stricmp( pShaderModel, "ps_2_b" ) )
+ {
+ char *pNumMacros = strtok ( NULL, "\n");
+ int nNumMacros = atoi( pNumMacros );
+
+ // Read macros from the command file
+ CUtlVector<D3DXMACRO> macros;
+ D3DXMACRO macro;
+ for ( int i=0; i<nNumMacros-1; i++ ) // The last one is the (null) one, so don't bother reading it
+ {
+ // Allocate and populate strings
+ macro.Name = strtok( NULL, "\n");
+ macro.Definition = strtok( NULL, "\n");
+ macros.AddToTail( macro );
+ }
+
+ // Null macro at the end
+ macro.Name = NULL;
+ macro.Definition = NULL;
+ macros.AddToTail( macro );
+
+ LPD3DXBUFFER pShader, pErrorMessages;
+
+ // This is the shader compiler we use for pre-ps30 shaders.
+ // This utility needs to change if we want to do ps30 shaders (see logic in vertexshaderdx8.cpp)
+ HRESULT hr = D3DXCompileShaderFromFile( pShaderFilename, macros.Base(), NULL /* LPD3DXINCLUDE */, "main",
+ pShaderModel, 0, &pShader, &pErrorMessages,
+ NULL /* LPD3DXCONSTANTTABLE *ppConstantTable */ );
+ if ( hr != D3D_OK )
+ {
+ pSendbuf[0] = 0;
+
+ printf( "Compilation error in %s\n", pShaderFilename );
+
+ if ( pErrorMessages )
+ {
+ memcpy( pSendbuf+1, pErrorMessages->GetBufferPointer(), pErrorMessages->GetBufferSize() ); // Null-terminated string
+ printf("%s\n", (const char*)(pSendbuf + 1 ));
+ nSendBufLen = pErrorMessages->GetBufferSize() + 4; // account for uint32 at front of the buffer
+ }
+ else
+ {
+ ((uint8*)(pSendbuf+1))[0] = '?';
+ ((uint8*)(pSendbuf+1))[1] = '\0';
+ nSendBufLen = 2 + 4; // account for uint32 at front of the buffer
+ }
+
+
+ }
+ else // Success!
+ {
+// printf( "Compiled %s\n", pShaderFilename );
+ pSendbuf[0] = pShader->GetBufferSize();
+ memcpy( pSendbuf+1, pShader->GetBufferPointer(), pShader->GetBufferSize() );
+ nSendBufLen = pShader->GetBufferSize() + 4; // account for uint32 at front of the buffer
+
+ if ( g_bPrintDisassembly )
+ {
+ printf( "Filename: %s\n", pShaderFilename );
+ printf( "Shader model: %s\n", pShaderModel );
+ printf( "Macros: " );
+ for ( int i = 0; i < nNumMacros - 1; i++ )
+ printf( " %s\n", macros[i].Name );
+ LPD3DXBUFFER pDisassembly = NULL;
+ D3DXDisassembleShader( (const DWORD*)pShader->GetBufferPointer(), FALSE, "", &pDisassembly );
+ if ( pDisassembly )
+ {
+ printf( "Disassembled shader:\n");
+ puts( (const char*)pDisassembly->GetBufferPointer() );
+ printf("\n");
+
+ pDisassembly->Release();
+ }
+ }
+ }
+
+ if (pErrorMessages)
+ {
+ pErrorMessages->Release();
+ }
+
+ if (pShader)
+ {
+ pShader->Release();
+ }
+
+ // Purge the macro buffer
+ macros.RemoveMultipleFromTail( nNumMacros );
+ }
+ else // Not a supported shader profile
+ {
+ pSendbuf[0] = 0;
+ char *pCharSendbuff = (char *) (pSendbuf+1);
+ V_snprintf( pCharSendbuff, DEFAULT_SEND_BUF_LEN, "Unsupported shader profile: %s\n", pShaderModel );
+ nSendBufLen = strlen( pCharSendbuff ) + 4; // account for uint32 at front of the buffer
+ }
+
+ // Send the compiled shader back to the game
+ int nSendResult = send( ClientSocket, (const char *)pSendbuf, nSendBufLen, 0 );
+ if ( nSendResult == SOCKET_ERROR )
+ {
+ printf( "send failed: %d\n", WSAGetLastError() );
+ closesocket( ClientSocket );
+ WSACleanup();
+ return;
+ }
+ }
+ else // We had a game talking to us but it went away
+ {
+ printf( "Game went away, waiting for new connection...\n" );
+
+ // Block again waiting to accept a connection
+ ClientSocket = accept( ListenSocket, NULL, NULL );
+
+ printf( "Game connected\n" );
+
+ if ( ClientSocket == INVALID_SOCKET )
+ {
+ printf( "accept failed: %d\n", WSAGetLastError() );
+ Assert( 0 );
+ closesocket( ListenSocket );
+ WSACleanup();
+ return;
+ }
+ }
+ }
+
+ nResult = shutdown( ClientSocket, SD_SEND );
+ if ( nResult == SOCKET_ERROR )
+ {
+ printf("shutdown failed: %d\n", WSAGetLastError());
+ closesocket( ClientSocket );
+ WSACleanup();
+ return;
+ }
+
+ // cleanup
+ closesocket( ClientSocket );
+ WSACleanup();
+}
+
+
+void CheckPath( char *pPath )
+{
+ int len = V_strlen( pPath );
+
+ // If we don't have a path separator at the end of the path, put one there
+ if ( ( pPath[len-1] != '\\' ) && ( pPath[len-1] != '/' ) )
+ {
+ V_strncat( pPath, CORRECT_PATH_SEPARATOR_S, MAX_PATH );
+ }
+}
+
+
+int main(int argc, char* argv[])
+{
+ if ( argc < 2 )
+ {
+ printf( "============================================================\n" );
+ printf( " Please provide full path to shader directory. For example:\n" );
+ printf( " U:\\piston\\staging\\src\\materialsystem\\stdshaders\\ \n");
+ printf( "============================================================\n" );
+ printf( " remoteshadercompiler will now exit!!! \n" );
+ printf( "============================================================\n" );
+ return 0;
+ }
+
+ printf( "========================================================\n");
+ printf( "Remote shader compiler is running. Press ESCAPE to exit\n" );
+ printf( "========================================================\n");
+
+ // If we have a path specified on the commandline, we expect
+ // that the remote machine is going to send base filenames only
+ // and that we'll want to strcat this path onto the filename from the worker.
+ //
+ // For example, if you have your shader source on your Windows machine, you can use something like this:
+ //
+ // U:\piston\staging\src\materialsystem\stdshaders\
+ //
+ strcpy( g_pPathBase, argv[1] );
+
+ if ( argc == 3 )
+ {
+ g_bPrintDisassembly = true;
+ }
+
+ CheckPath( g_pPathBase );
+
+ // Kick off compile server thread
+ _beginthread( ServerThread, 0, NULL );
+
+ // Spin until escape
+ while( _getch() != 27 )
+ ;
+
+ return 0;
+}