Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

316 lines
8.8 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Defines the entry point for the console application
  4. //
  5. //===============================================================================
  6. //#include <sys/stat.h>
  7. //#include <time.h>
  8. #include <winsock2.h>
  9. #include <ws2tcpip.h>
  10. #include <conio.h >
  11. #include "tier1/utlvector.h"
  12. #include "tier0/icommandline.h"
  13. #include "tier2/tier2.h"
  14. #include "tier2/fileutils.h"
  15. #include "../../dx9sdk/include/d3d9.h"
  16. #include "../../dx9sdk/include/d3dx9.h"
  17. #define DEFAULT_PORT "20000"
  18. #define DEFAULT_SEND_BUF_LEN 40000
  19. #define DEFAULT_RECV_BUF_LEN 40000
  20. char g_pPathBase[MAX_PATH];
  21. bool g_bPrintDisassembly;
  22. // This guy just spins and compiles when a command comes in from the game
  23. void ServerThread( void * )
  24. {
  25. WSADATA wsaData;
  26. if( WSAStartup( 0x101, &wsaData ) != 0 )
  27. return;
  28. struct addrinfo *result = NULL, hints;
  29. ZeroMemory( &hints, sizeof(hints) );
  30. hints.ai_family = AF_INET;
  31. hints.ai_socktype = SOCK_STREAM;
  32. hints.ai_protocol = IPPROTO_TCP;
  33. hints.ai_flags = AI_PASSIVE;
  34. // Resolve the server address and port
  35. int nResult = getaddrinfo( NULL, DEFAULT_PORT, &hints, &result );
  36. if ( nResult != 0 )
  37. {
  38. printf( "getaddrinfo failed: %d\n", nResult );
  39. WSACleanup();
  40. return;
  41. }
  42. // Create a SOCKET for connecting to server
  43. SOCKET ListenSocket = socket( result->ai_family, result->ai_socktype, result->ai_protocol );
  44. if (ListenSocket == INVALID_SOCKET) {
  45. printf("socket failed: %ld\n", WSAGetLastError());
  46. freeaddrinfo(result);
  47. WSACleanup();
  48. return;
  49. }
  50. // Setup the TCP listening socket
  51. nResult = bind( ListenSocket, result->ai_addr, (int)result->ai_addrlen );
  52. if (nResult == SOCKET_ERROR)
  53. {
  54. printf("bind failed: %d\n", WSAGetLastError());
  55. freeaddrinfo(result);
  56. closesocket(ListenSocket);
  57. WSACleanup();
  58. return;
  59. }
  60. freeaddrinfo(result);
  61. nResult = listen( ListenSocket, SOMAXCONN );
  62. if ( nResult == SOCKET_ERROR )
  63. {
  64. printf( "listen failed: %d\n", WSAGetLastError() );
  65. closesocket( ListenSocket );
  66. WSACleanup();
  67. return;
  68. }
  69. printf( "Waiting for initial connection...\n" );
  70. // Accept a client socket
  71. SOCKET ClientSocket = accept( ListenSocket, NULL, NULL );
  72. if ( ClientSocket == INVALID_SOCKET )
  73. {
  74. printf( "accept failed: %d\n", WSAGetLastError() );
  75. closesocket( ListenSocket );
  76. WSACleanup();
  77. return;
  78. }
  79. // First connection
  80. printf( "Game connected\n" );
  81. char pRecbuf[DEFAULT_RECV_BUF_LEN]; // Text in command file from game
  82. uint32 pSendbuf[DEFAULT_SEND_BUF_LEN]; // Error string or binary shader blob in reply
  83. while ( true )
  84. {
  85. nResult = recv( ClientSocket, pRecbuf, DEFAULT_RECV_BUF_LEN, 0 );
  86. if ( nResult > 0 )
  87. {
  88. char *pShaderFilename = strtok ( pRecbuf, "\n");
  89. char pFullFilename[MAX_PATH];
  90. // If we took in a path on the commandline, we concatenate the incoming filenames with it
  91. if ( V_strlen( g_pPathBase ) > 0 )
  92. {
  93. V_strncpy( pFullFilename, g_pPathBase, MAX_PATH ); // base path
  94. V_strncat( pFullFilename, pShaderFilename, MAX_PATH );
  95. pShaderFilename = pFullFilename;
  96. }
  97. char *pShaderModel = strtok ( NULL, "\n");
  98. int nSendBufLen = 0;
  99. // Only try to compile if we have a recognized profile
  100. if ( !stricmp( pShaderModel, "vs_2_0" ) || !stricmp( pShaderModel, "ps_2_0" ) || !stricmp( pShaderModel, "ps_2_b" ) )
  101. {
  102. char *pNumMacros = strtok ( NULL, "\n");
  103. int nNumMacros = atoi( pNumMacros );
  104. // Read macros from the command file
  105. CUtlVector<D3DXMACRO> macros;
  106. D3DXMACRO macro;
  107. for ( int i=0; i<nNumMacros-1; i++ ) // The last one is the (null) one, so don't bother reading it
  108. {
  109. // Allocate and populate strings
  110. macro.Name = strtok( NULL, "\n");
  111. macro.Definition = strtok( NULL, "\n");
  112. macros.AddToTail( macro );
  113. }
  114. // Null macro at the end
  115. macro.Name = NULL;
  116. macro.Definition = NULL;
  117. macros.AddToTail( macro );
  118. LPD3DXBUFFER pShader, pErrorMessages;
  119. // This is the shader compiler we use for pre-ps30 shaders.
  120. // This utility needs to change if we want to do ps30 shaders (see logic in vertexshaderdx8.cpp)
  121. HRESULT hr = D3DXCompileShaderFromFile( pShaderFilename, macros.Base(), NULL /* LPD3DXINCLUDE */, "main",
  122. pShaderModel, 0, &pShader, &pErrorMessages,
  123. NULL /* LPD3DXCONSTANTTABLE *ppConstantTable */ );
  124. if ( hr != D3D_OK )
  125. {
  126. pSendbuf[0] = 0;
  127. printf( "Compilation error in %s\n", pShaderFilename );
  128. if ( pErrorMessages )
  129. {
  130. memcpy( pSendbuf+1, pErrorMessages->GetBufferPointer(), pErrorMessages->GetBufferSize() ); // Null-terminated string
  131. printf("%s\n", (const char*)(pSendbuf + 1 ));
  132. nSendBufLen = pErrorMessages->GetBufferSize() + 4; // account for uint32 at front of the buffer
  133. }
  134. else
  135. {
  136. ((uint8*)(pSendbuf+1))[0] = '?';
  137. ((uint8*)(pSendbuf+1))[1] = '\0';
  138. nSendBufLen = 2 + 4; // account for uint32 at front of the buffer
  139. }
  140. }
  141. else // Success!
  142. {
  143. // printf( "Compiled %s\n", pShaderFilename );
  144. pSendbuf[0] = pShader->GetBufferSize();
  145. memcpy( pSendbuf+1, pShader->GetBufferPointer(), pShader->GetBufferSize() );
  146. nSendBufLen = pShader->GetBufferSize() + 4; // account for uint32 at front of the buffer
  147. if ( g_bPrintDisassembly )
  148. {
  149. printf( "Filename: %s\n", pShaderFilename );
  150. printf( "Shader model: %s\n", pShaderModel );
  151. printf( "Macros: " );
  152. for ( int i = 0; i < nNumMacros - 1; i++ )
  153. printf( " %s\n", macros[i].Name );
  154. LPD3DXBUFFER pDisassembly = NULL;
  155. D3DXDisassembleShader( (const DWORD*)pShader->GetBufferPointer(), FALSE, "", &pDisassembly );
  156. if ( pDisassembly )
  157. {
  158. printf( "Disassembled shader:\n");
  159. puts( (const char*)pDisassembly->GetBufferPointer() );
  160. printf("\n");
  161. pDisassembly->Release();
  162. }
  163. }
  164. }
  165. if (pErrorMessages)
  166. {
  167. pErrorMessages->Release();
  168. }
  169. if (pShader)
  170. {
  171. pShader->Release();
  172. }
  173. // Purge the macro buffer
  174. macros.RemoveMultipleFromTail( nNumMacros );
  175. }
  176. else // Not a supported shader profile
  177. {
  178. pSendbuf[0] = 0;
  179. char *pCharSendbuff = (char *) (pSendbuf+1);
  180. V_snprintf( pCharSendbuff, DEFAULT_SEND_BUF_LEN, "Unsupported shader profile: %s\n", pShaderModel );
  181. nSendBufLen = strlen( pCharSendbuff ) + 4; // account for uint32 at front of the buffer
  182. }
  183. // Send the compiled shader back to the game
  184. int nSendResult = send( ClientSocket, (const char *)pSendbuf, nSendBufLen, 0 );
  185. if ( nSendResult == SOCKET_ERROR )
  186. {
  187. printf( "send failed: %d\n", WSAGetLastError() );
  188. closesocket( ClientSocket );
  189. WSACleanup();
  190. return;
  191. }
  192. }
  193. else // We had a game talking to us but it went away
  194. {
  195. printf( "Game went away, waiting for new connection...\n" );
  196. // Block again waiting to accept a connection
  197. ClientSocket = accept( ListenSocket, NULL, NULL );
  198. printf( "Game connected\n" );
  199. if ( ClientSocket == INVALID_SOCKET )
  200. {
  201. printf( "accept failed: %d\n", WSAGetLastError() );
  202. Assert( 0 );
  203. closesocket( ListenSocket );
  204. WSACleanup();
  205. return;
  206. }
  207. }
  208. }
  209. nResult = shutdown( ClientSocket, SD_SEND );
  210. if ( nResult == SOCKET_ERROR )
  211. {
  212. printf("shutdown failed: %d\n", WSAGetLastError());
  213. closesocket( ClientSocket );
  214. WSACleanup();
  215. return;
  216. }
  217. // cleanup
  218. closesocket( ClientSocket );
  219. WSACleanup();
  220. }
  221. void CheckPath( char *pPath )
  222. {
  223. int len = V_strlen( pPath );
  224. // If we don't have a path separator at the end of the path, put one there
  225. if ( ( pPath[len-1] != '\\' ) && ( pPath[len-1] != '/' ) )
  226. {
  227. V_strncat( pPath, CORRECT_PATH_SEPARATOR_S, MAX_PATH );
  228. }
  229. }
  230. int main(int argc, char* argv[])
  231. {
  232. if ( argc < 2 )
  233. {
  234. printf( "============================================================\n" );
  235. printf( " Please provide full path to shader directory. For example:\n" );
  236. printf( " U:\\piston\\staging\\src\\materialsystem\\stdshaders\\ \n");
  237. printf( "============================================================\n" );
  238. printf( " remoteshadercompiler will now exit!!! \n" );
  239. printf( "============================================================\n" );
  240. return 0;
  241. }
  242. printf( "========================================================\n");
  243. printf( "Remote shader compiler is running. Press ESCAPE to exit\n" );
  244. printf( "========================================================\n");
  245. // If we have a path specified on the commandline, we expect
  246. // that the remote machine is going to send base filenames only
  247. // and that we'll want to strcat this path onto the filename from the worker.
  248. //
  249. // For example, if you have your shader source on your Windows machine, you can use something like this:
  250. //
  251. // U:\piston\staging\src\materialsystem\stdshaders\
  252. //
  253. strcpy( g_pPathBase, argv[1] );
  254. if ( argc == 3 )
  255. {
  256. g_bPrintDisassembly = true;
  257. }
  258. CheckPath( g_pPathBase );
  259. // Kick off compile server thread
  260. _beginthread( ServerThread, 0, NULL );
  261. // Spin until escape
  262. while( _getch() != 27 )
  263. ;
  264. return 0;
  265. }