├── .gitignore ├── HLSL.cpp ├── IntelGPUCompiler.h ├── IntelShaderAnalyzer.cpp ├── IntelShaderAnalyzer.h ├── IntelShaderAnalyzer.sln ├── IntelShaderAnalyzer.vcxproj ├── IntelShaderAnalyzer.vcxproj.filters ├── LICENSE.txt ├── README.md └── tests ├── cases ├── command_line.txt ├── data │ ├── ps50.dxbc │ ├── ps50_with_rs.dxbc │ ├── ps60.dxbc │ ├── ps60_with_rs.dxbc │ ├── rootsig_readme_2 │ └── testrootsig ├── dxbc.txt ├── fxc_11.txt ├── fxc_12.txt ├── fxc_define.txt ├── readme_1.txt └── readme_2.txt └── run_tests.py /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Compiled Object files 5 | *.slo 6 | *.lo 7 | *.o 8 | *.obj 9 | 10 | # Precompiled Headers 11 | *.gch 12 | *.pch 13 | 14 | # Compiled Dynamic libraries 15 | *.so 16 | *.dylib 17 | *.dll 18 | 19 | # Fortran module files 20 | *.mod 21 | *.smod 22 | 23 | # Compiled Static libraries 24 | *.lai 25 | *.la 26 | *.a 27 | *.lib 28 | 29 | # Executables 30 | *.exe 31 | *.out 32 | *.app 33 | *.dll 34 | 35 | .vs/* 36 | *.user 37 | x64/* 38 | -------------------------------------------------------------------------------- /HLSL.cpp: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 2 | // Copyright (c) 2019, Intel Corporation 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 4 | // documentation files (the "Software"), to deal in the Software without restriction, including without limitation 5 | // the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to 6 | // permit persons to whom the Software is furnished to do so, subject to the following conditions: 7 | // The above copyright notice and this permission notice shall be included in all copies or substantial portions of 8 | // the Software. 9 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO 10 | // THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 11 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 12 | // TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 13 | // SOFTWARE. 14 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 15 | 16 | #include "IntelShaderAnalyzer.h" 17 | #include 18 | #include 19 | #include 20 | 21 | typedef HRESULT( WINAPI *D3DCOMPILE_FUNC )( 22 | LPCVOID pSrcData, 23 | SIZE_T SrcDataSize, 24 | LPCSTR pSourceName, 25 | const D3D_SHADER_MACRO *pDefines, 26 | ID3DInclude *pInclude, 27 | LPCSTR pEntrypoint, 28 | LPCSTR pTarget, 29 | UINT Flags1, 30 | UINT Flags2, 31 | ID3DBlob **ppCode, 32 | ID3DBlob **ppErrorMsgs); 33 | 34 | typedef HRESULT( WINAPI *D3DGETBLOBPART_FUNC )( 35 | LPCVOID pShaderBytecode, 36 | SIZE_T BytecodeLength, 37 | UINT uBlobPartEnum, 38 | UINT uFlags, 39 | ID3DBlob **ppBlob 40 | ); 41 | 42 | bool GetRootSignatureFromDXBC( FrontendOptions& frontend_opts, ToolInputs& inputs ) 43 | { 44 | HINSTANCE hCompiler = LoadLibraryA( frontend_opts.dx_location ); 45 | if(!hCompiler) 46 | { 47 | printf( "Failed to load D3D compiler dll from: %s\n", frontend_opts.dx_location ); 48 | return false; 49 | } 50 | 51 | D3DGETBLOBPART_FUNC pfnD3DGetBlobPart = (D3DGETBLOBPART_FUNC) GetProcAddress( hCompiler, "D3DGetBlobPart" ); 52 | if(!pfnD3DGetBlobPart) 53 | { 54 | printf( "GetProcAddress failed for D3DGetBlobPart\n" ); 55 | return false; 56 | } 57 | 58 | CComPtr pEmbeddedRS; 59 | HRESULT hr = pfnD3DGetBlobPart( inputs.bytecode.data(), inputs.bytecode.size(), D3D_BLOB_ROOT_SIGNATURE, 0, &pEmbeddedRS ); 60 | if(SUCCEEDED( hr )) 61 | { 62 | inputs.rootsig.resize( pEmbeddedRS->GetBufferSize() ); 63 | memcpy( inputs.rootsig.data(), pEmbeddedRS->GetBufferPointer(), pEmbeddedRS->GetBufferSize() ); 64 | } 65 | 66 | return true; 67 | } 68 | 69 | 70 | bool CompileHLSL( FrontendOptions& frontend_opts,ToolInputs& inputs ) 71 | { 72 | HINSTANCE hCompiler = LoadLibraryA( frontend_opts.dx_location ); 73 | if ( !hCompiler ) 74 | { 75 | printf( "Failed to load D3D compiler dll from: %s\n",frontend_opts.dx_location ); 76 | return false; 77 | } 78 | 79 | D3DCOMPILE_FUNC pfnD3DCompile = (D3DCOMPILE_FUNC)GetProcAddress( hCompiler,"D3DCompile" ); 80 | if ( !pfnD3DCompile ) 81 | { 82 | printf( "GetProcAddress failed for D3DCompile\n" ); 83 | return false; 84 | } 85 | D3DGETBLOBPART_FUNC pfnD3DGetBlobPart = (D3DGETBLOBPART_FUNC)GetProcAddress( hCompiler,"D3DGetBlobPart" ); 86 | if ( !pfnD3DGetBlobPart ) 87 | { 88 | printf( "GetProcAddress failed for D3DGetBlobPart\n" ); 89 | return false; 90 | } 91 | 92 | std::vector macros; 93 | for ( auto it : frontend_opts.defines ) 94 | { 95 | D3D_SHADER_MACRO m; 96 | m.Definition = it.second; 97 | m.Name = it.first; 98 | macros.push_back( m ); 99 | } 100 | 101 | macros.push_back( D3D_SHADER_MACRO{ nullptr,nullptr } ); 102 | 103 | CComPtr pCode; 104 | CComPtr pMessages; 105 | HRESULT hr = pfnD3DCompile( frontend_opts.input_text.c_str(), 106 | frontend_opts.input_text.size(), 107 | frontend_opts.input_file,macros.data(), 108 | D3D_COMPILE_STANDARD_FILE_INCLUDE, 109 | frontend_opts.entry, 110 | frontend_opts.profile, 111 | frontend_opts.dx_flags, 112 | 0, 113 | &pCode, 114 | &pMessages ); 115 | 116 | if ( pMessages ) 117 | printf( "%s\n",(char*)pMessages->GetBufferPointer() ); 118 | 119 | if ( FAILED( hr ) ) 120 | return false; 121 | 122 | if ( pCode ) 123 | { 124 | inputs.bytecode.resize( pCode->GetBufferSize() ); 125 | memcpy( inputs.bytecode.data(),pCode->GetBufferPointer(),pCode->GetBufferSize() ); 126 | 127 | // try to extract root signature if one is embedded 128 | CComPtr pEmbeddedRS; 129 | hr = pfnD3DGetBlobPart( pCode->GetBufferPointer(), pCode->GetBufferSize(),D3D_BLOB_ROOT_SIGNATURE,0, &pEmbeddedRS ); 130 | if ( SUCCEEDED( hr ) ) 131 | { 132 | inputs.rootsig.resize( pEmbeddedRS->GetBufferSize() ); 133 | memcpy( inputs.rootsig.data(), pEmbeddedRS->GetBufferPointer(), pEmbeddedRS->GetBufferSize() ); 134 | } 135 | else if( frontend_opts.rs_macro && frontend_opts.rs_profile ) 136 | { 137 | // try and compile a root signature using user-specified macro name 138 | CComPtr pRS; 139 | CComPtr pRSMessages; 140 | hr = pfnD3DCompile( frontend_opts.input_text.c_str(), 141 | frontend_opts.input_text.size(), 142 | frontend_opts.input_file,macros.data(), 143 | D3D_COMPILE_STANDARD_FILE_INCLUDE, 144 | frontend_opts.rs_macro, 145 | frontend_opts.rs_profile, 146 | frontend_opts.dx_flags, 147 | 0, 148 | &pRS, 149 | &pRSMessages ); 150 | 151 | if ( pRSMessages ) 152 | printf( "%s\n",(char*)pRSMessages->GetBufferPointer() ); 153 | 154 | if ( SUCCEEDED( hr ) ) 155 | { 156 | inputs.rootsig.resize( pRS->GetBufferSize() ); 157 | memcpy( inputs.rootsig.data(),pRS->GetBufferPointer(),pRS->GetBufferSize() ); 158 | } 159 | } 160 | } 161 | 162 | return true; 163 | } 164 | -------------------------------------------------------------------------------- /IntelGPUCompiler.h: -------------------------------------------------------------------------------- 1 | /*===================== begin_copyright_notice ================================== 2 | 3 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 4 | // Copyright (c) 2019, Intel Corporation 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 6 | // documentation files (the "Software"), to deal in the Software without restriction, including without limitation 7 | // the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to 8 | // permit persons to whom the Software is furnished to do so, subject to the following conditions: 9 | // The above copyright notice and this permission notice shall be included in all copies or substantial portions of 10 | // the Software. 11 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO 12 | // THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 13 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 14 | // TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 15 | // SOFTWARE. 16 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 17 | 18 | ======================= end_copyright_notice ==================================*/ 19 | /************************************************************************/ 20 | // This header provide an interface to call into Intel shader compiler for shaders in DXBC format 21 | /************************************************************************/ 22 | #pragma once 23 | namespace IntelGPUCompiler 24 | { 25 | typedef void* OpaqueCompiler; 26 | typedef void* OpaqueShader; 27 | 28 | // Platform supported by the library may be queried with pfnEnumPlatforms callback 29 | enum class Platform { 30 | SKL, //Skylake 31 | KBL, //Kabylake 32 | ICLLP, //Icelake LP 33 | }; 34 | 35 | struct PlatformInfo 36 | { 37 | Platform Identifier; 38 | const char* platformName; 39 | }; 40 | 41 | // Max version support in the header 42 | static const unsigned int g_HeaderVersion = 1; 43 | 44 | struct ShaderInput_DX11_V1 45 | { 46 | const void* DXBCBin = nullptr; 47 | }; 48 | 49 | struct ShaderInput_DX12_V1 50 | { 51 | const void* DXBCBin = nullptr; 52 | const void* rootSignature = nullptr; 53 | size_t rootSignatureSize = 0; 54 | }; 55 | 56 | // DX11 callbacks 57 | typedef bool(__stdcall* PFNCREATESHADERCOMPILER_DX11_V1)(Platform, OpaqueCompiler&); 58 | typedef void(__stdcall* PFNDELETESHADERCOMPILER_DX11)(OpaqueCompiler&); 59 | typedef bool(__stdcall* PFNCREATESHADER_DX11_V1)(OpaqueCompiler, const ShaderInput_DX11_V1& input, OpaqueShader& output); 60 | typedef void(__stdcall* PFNDELETESHADER_DX11)(OpaqueShader& shader); 61 | 62 | // DX12 callbacks 63 | typedef bool(__stdcall* PFNCREATESHADERCOMPILER_DX12_V1)(Platform, OpaqueCompiler&); 64 | typedef void(__stdcall* PFNDELETESHADERCOMPILER_DX12)(OpaqueCompiler&); 65 | typedef bool(__stdcall* PFNCREATESHADER_DX12_V1)(OpaqueCompiler, const ShaderInput_DX12_V1& input, OpaqueShader& output); 66 | typedef void(__stdcall* PFNDELETESHADER_DX12)(OpaqueShader& shader); 67 | 68 | 69 | // common callbacks 70 | typedef char*(__stdcall* PFNGETISATEXT)(OpaqueShader, size_t& textSize); 71 | typedef void*(__stdcall* PFNGETISABINARY)(OpaqueShader, size_t& shaderSize); 72 | typedef const char*(__stdcall* PFNGETLASTERROR)(); 73 | typedef size_t(__stdcall* PFNENUMPLATFORMS)(PlatformInfo* pPlatforms, size_t nMaxPlatforms); 74 | 75 | 76 | struct SFunctionTable_V1 77 | { 78 | struct DX11Functions 79 | { 80 | // DX11 callbacks 81 | PFNCREATESHADERCOMPILER_DX11_V1 pfnCreateCompiler; 82 | PFNDELETESHADERCOMPILER_DX11 pfnDeleteShaderCompiler; 83 | PFNCREATESHADER_DX11_V1 pfnCreateShader; 84 | PFNDELETESHADER_DX11 pfnDeleteShader; 85 | } pfnDX11; 86 | struct DX12Functions 87 | { 88 | // DX12 callbacks 89 | PFNCREATESHADERCOMPILER_DX12_V1 pfnCreateCompiler; 90 | PFNDELETESHADERCOMPILER_DX12 pfnDeleteShaderCompiler; 91 | PFNCREATESHADER_DX12_V1 pfnCreateShader; 92 | PFNDELETESHADER_DX12 pfnDeleteShader; 93 | } pfnDX12; 94 | 95 | PFNENUMPLATFORMS pfnEnumPlatforms; 96 | PFNGETISATEXT pfnGetIsaText; 97 | PFNGETISABINARY pfnGetIsaBinary; 98 | PFNGETLASTERROR pfnGetLastError; 99 | }; 100 | 101 | struct SFunctionTable 102 | { 103 | union 104 | { 105 | SFunctionTable_V1 interface1; 106 | }; 107 | }; 108 | 109 | struct SOpenCompiler 110 | { 111 | unsigned int InterfaceVersion = g_HeaderVersion; 112 | SFunctionTable* pCompilerFuncs; 113 | }; 114 | 115 | /* 116 | The way to use this library is to call OpenCompiler with the interface version 117 | 118 | /// Load library 119 | HINSTANCE compilerInstance = (HINSTANCE)LoadLibrary("IntelGpuCompiler64.dll"); 120 | PFNOPENCOMPILER pfnOpenCompiler = (PFNOPENCOMPILER)GetProcAddress(compilerInstance, g_cOpenCompilerFnName); 121 | SFunctionTable functionTable; 122 | SOpenCompiler desc; 123 | desc.pCompilerFuncs = &functionTable; 124 | 125 | /// get the right set of callbacks 126 | if(pfnOpenCompiler(desc)) 127 | { 128 | /// create compiler context 129 | OpaqueCompiler pCompiler; 130 | functionTable.interface1.pfnDX11.pfnCreateCompiler(Platform::KBL, pCompiler); 131 | 132 | /// CreateShader 133 | ShaderInput_DX11_V1 input; 134 | input.DXBCBin = pShader; 135 | OpaqueShader output; 136 | functionTable.interface1.pfnDX11.pfnCreateShader(pCompiler, input, output); 137 | const char* isaText = functionTable.interface1.pfnGetIsaText(output); 138 | printf("%s", isaText); 139 | /// free up memory 140 | functionTable.interface1.pfnDX11.pfnDeleteShader(output); 141 | functionTable.interface1.pfnDX11.pfnDeleteShaderCompiler(pCompiler); 142 | } 143 | 144 | */ 145 | 146 | static const char* g_cOpenCompilerFnName = "OpenCompiler"; 147 | 148 | // auto pfnOpenCompiler = (PFNOPENCOMPILER)GetProcAddress( igcLib, g_cOpenCompilerFnName ); 149 | typedef bool(__stdcall* PFNOPENCOMPILER)(SOpenCompiler&); 150 | 151 | } 152 | -------------------------------------------------------------------------------- /IntelShaderAnalyzer.cpp: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 2 | // Copyright (c) 2019, Intel Corporation 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 4 | // documentation files (the "Software"), to deal in the Software without restriction, including without limitation 5 | // the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to 6 | // permit persons to whom the Software is furnished to do so, subject to the following conditions: 7 | // The above copyright notice and this permission notice shall be included in all copies or substantial portions of 8 | // the Software. 9 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO 10 | // THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 11 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 12 | // TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 13 | // SOFTWARE. 14 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 15 | 16 | #define _CRT_SECURE_NO_WARNINGS 17 | 18 | #include "IntelShaderAnalyzer.h" 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | #include 26 | 27 | #ifdef _WIN64 28 | #define DLL_NAME "IntelGpuCompiler64.dll" 29 | #else 30 | #define DLL_NAME "IntelGpuCompiler32.dll" 31 | #endif 32 | 33 | using namespace IntelGPUCompiler; 34 | 35 | 36 | 37 | int sizeOfFile(const char* filename) { 38 | struct stat st; 39 | if (stat(filename, &st) == -1) 40 | return -1; 41 | return st.st_size; 42 | } 43 | 44 | bool readAllBytes( std::vector& bytes, const char * filename ) 45 | { 46 | size_t length = sizeOfFile( filename ); 47 | if ( length == -1 ) 48 | return false; 49 | 50 | std::ifstream is(filename, std::ifstream::binary); 51 | 52 | bytes.resize( length ); 53 | is.read((char*)bytes.data(), length); 54 | 55 | return true; 56 | } 57 | 58 | bool readAllText( std::string& text,const char * filename ) 59 | { 60 | std::ifstream file( filename ); 61 | if ( !file.good() ) 62 | return false; 63 | 64 | std::stringstream buffer; 65 | buffer << file.rdbuf(); 66 | text = std::move( buffer.str() ); 67 | return true; 68 | } 69 | 70 | 71 | class API 72 | { 73 | public: 74 | virtual bool CanRun( ToolInputs& opts ) = 0; 75 | virtual bool CreateCompiler( Platform platformID,SFunctionTable& functionTable,OpaqueCompiler& compiler ) = 0; 76 | virtual bool CreateShader( SFunctionTable& functionTable,OpaqueCompiler& compiler,OpaqueShader& output,ToolInputs& opts ) = 0; 77 | virtual void DeleteShader( SFunctionTable& functionTable,OpaqueShader& shader ) = 0; 78 | virtual void DeleteCompiler( SFunctionTable& functionTable,OpaqueCompiler& compiler ) = 0; 79 | }; 80 | 81 | class API_DX11 : public API 82 | { 83 | public: 84 | virtual bool CanRun( ToolInputs& opts ) override 85 | { 86 | if ( opts.bytecode.empty() ) 87 | { 88 | printf( "Missing shader bytecode\n" ); 89 | return false; 90 | } 91 | return true; 92 | } 93 | 94 | virtual bool CreateCompiler( Platform platformID, SFunctionTable& functionTable,OpaqueCompiler& compiler ) override 95 | { 96 | return functionTable.interface1.pfnDX11.pfnCreateCompiler( platformID,compiler ); 97 | } 98 | 99 | virtual bool CreateShader( SFunctionTable& functionTable, OpaqueCompiler& compiler, OpaqueShader& output,ToolInputs& opts ) override 100 | { 101 | ShaderInput_DX11_V1 input; 102 | input.DXBCBin = (void*)opts.bytecode.data(); 103 | return functionTable.interface1.pfnDX11.pfnCreateShader( compiler,input,output ); 104 | } 105 | 106 | virtual void DeleteCompiler( SFunctionTable& functionTable, OpaqueCompiler& compiler ) override 107 | { 108 | functionTable.interface1.pfnDX11.pfnDeleteShaderCompiler( compiler ); 109 | } 110 | 111 | virtual void DeleteShader( SFunctionTable& functionTable,OpaqueShader& shader ) override 112 | { 113 | functionTable.interface1.pfnDX11.pfnDeleteShader( shader ); 114 | } 115 | }; 116 | 117 | class API_DX12 : public API 118 | { 119 | public: 120 | virtual bool CanRun( ToolInputs& opts ) override 121 | { 122 | if ( opts.bytecode.empty() ) 123 | { 124 | printf( "Missing shader bytecode\n" ); 125 | return false; 126 | } 127 | if ( opts.rootsig.empty() ) 128 | { 129 | printf( "Missing root signature\n" ); 130 | return false; 131 | } 132 | return true; 133 | } 134 | 135 | virtual bool CreateCompiler( Platform platformID,SFunctionTable& functionTable,OpaqueCompiler& compiler ) override 136 | { 137 | return functionTable.interface1.pfnDX12.pfnCreateCompiler( platformID,compiler ); 138 | } 139 | 140 | virtual bool CreateShader( SFunctionTable& functionTable,OpaqueCompiler& compiler,OpaqueShader& output,ToolInputs& opts ) override 141 | { 142 | ShaderInput_DX12_V1 input; 143 | input.DXBCBin = (void*)opts.bytecode.data(); 144 | input.rootSignature = (void*)opts.rootsig.data(); 145 | input.rootSignatureSize = opts.rootsig.size(); 146 | return functionTable.interface1.pfnDX12.pfnCreateShader( compiler,input,output ); 147 | } 148 | 149 | virtual void DeleteCompiler( SFunctionTable& functionTable,OpaqueCompiler& compiler ) override 150 | { 151 | functionTable.interface1.pfnDX12.pfnDeleteShaderCompiler( compiler ); 152 | } 153 | 154 | virtual void DeleteShader( SFunctionTable& functionTable,OpaqueShader& shader ) override 155 | { 156 | functionTable.interface1.pfnDX12.pfnDeleteShader( shader ); 157 | } 158 | }; 159 | 160 | 161 | 162 | 163 | bool RunTool( SFunctionTable& functionTable, ToolInputs& opts, API& api ) 164 | { 165 | if ( !api.CanRun( opts ) ) 166 | return false; 167 | 168 | for ( PlatformInfo& platform : opts.asics ) 169 | { 170 | /// create compiler context 171 | OpaqueCompiler pCompiler; 172 | if ( !api.CreateCompiler( platform.Identifier,functionTable,pCompiler ) ) 173 | { 174 | printf( "ERROR: %s\n",functionTable.interface1.pfnGetLastError( ) ); 175 | return false; 176 | } 177 | 178 | OpaqueShader output; 179 | if( api.CreateShader( functionTable, pCompiler, output, opts ) ) 180 | { 181 | size_t isaSize = 0; 182 | const char* isaText = functionTable.interface1.pfnGetIsaText( output,isaSize ); 183 | if ( isaText ) 184 | { 185 | std::stringstream isaFile; 186 | if ( opts.isa_prefix ) 187 | isaFile << opts.isa_prefix; 188 | 189 | isaFile << platform.platformName << ".asm"; 190 | 191 | std::string isaFileName = isaFile.str(); 192 | 193 | FILE* fp = fopen( isaFileName.c_str(), "w" ); 194 | if ( fp ) 195 | { 196 | fprintf( fp,"%s",isaText ); 197 | fclose( fp ); 198 | } 199 | else 200 | { 201 | printf( "Failed to open output file: %s\n",isaFileName.c_str() ); 202 | return false; 203 | } 204 | } 205 | else 206 | { 207 | printf( "ERROR: %s\n", functionTable.interface1.pfnGetLastError( ) ); 208 | return false; 209 | } 210 | 211 | /// free up memory 212 | api.DeleteShader( functionTable,output ); 213 | } 214 | else 215 | { 216 | printf( "ERROR: %s\n", functionTable.interface1.pfnGetLastError( ) ); 217 | return false; 218 | } 219 | 220 | api.DeleteCompiler( functionTable,pCompiler ); 221 | } 222 | 223 | return true; 224 | } 225 | 226 | void GetAsicList( SFunctionTable& functionTable, std::vector< IntelGPUCompiler::PlatformInfo >& asics ) 227 | { 228 | size_t nPlatforms = functionTable.interface1.pfnEnumPlatforms( nullptr,0 ); 229 | asics.resize( nPlatforms ); 230 | functionTable.interface1.pfnEnumPlatforms( asics.data(),nPlatforms ); 231 | } 232 | 233 | bool ListAsics() 234 | { 235 | HINSTANCE compilerInstance = (HINSTANCE)LoadLibraryA( DLL_NAME ); 236 | if ( !compilerInstance ) 237 | { 238 | printf( "Failed to load: %s\n",DLL_NAME ); 239 | return false; 240 | } 241 | 242 | PFNOPENCOMPILER pfnOpenCompiler = (PFNOPENCOMPILER)GetProcAddress( compilerInstance,g_cOpenCompilerFnName ); 243 | if ( !pfnOpenCompiler ) 244 | { 245 | printf( "GetProcAddress failed for: %s\n",g_cOpenCompilerFnName ); 246 | return false; 247 | } 248 | 249 | SFunctionTable functionTable; 250 | SOpenCompiler desc; 251 | desc.InterfaceVersion = 1; 252 | desc.pCompilerFuncs = &functionTable; 253 | 254 | /// get the right set of callbacks 255 | if ( !pfnOpenCompiler( desc ) ) 256 | { 257 | printf( "OpenCompiler failed\n" ); 258 | return false; 259 | } 260 | 261 | std::vector< IntelGPUCompiler::PlatformInfo > asics; 262 | GetAsicList( functionTable,asics ); 263 | 264 | for ( size_t i=0; i -f \n" ); 272 | printf( "To compile dxbc use: -s dxbc \n" ); 273 | printf( "For details, read the readme\n" ); 274 | } 275 | 276 | 277 | 278 | 279 | int main(int argc, char *argv[]) 280 | { 281 | std::vector asicNames; 282 | 283 | const char* api = "dx11"; 284 | const char* rootsig_file = nullptr; 285 | const char* source_lang = "dxbc"; 286 | 287 | ToolInputs opts; 288 | FrontendOptions frontend_opts; 289 | 290 | // parse the command line. Where possible we have tried to match the syntax of AMD's RGA 291 | int i=1; 292 | while( i < argc ) 293 | { 294 | if ( _stricmp( argv[i], "-l" ) == 0 || 295 | _stricmp( argv[i], "--list-asics" ) == 0 ) 296 | { 297 | if ( ListAsics() ) 298 | return 0; 299 | else 300 | return 1; 301 | } 302 | else if ( _stricmp( argv[i], "-h" ) == 0 || 303 | _stricmp( argv[i], "--help" ) == 0 ) 304 | { 305 | ShowHelp(); 306 | return 0; 307 | } 308 | else if ( _stricmp( argv[i], "-c" ) == 0 || 309 | _stricmp( argv[i], "--asic" ) == 0 ) 310 | { 311 | if ( i == argc-1 ) 312 | { 313 | printf( "Missing argument for --asic\n" ); 314 | return 1; 315 | } 316 | asicNames.push_back( argv[++i] ); 317 | } 318 | else if ( _stricmp( argv[i],"--api" ) == 0 ) 319 | { 320 | if ( i == argc-1 ) 321 | { 322 | printf( "Missing argument for --api\n" ); 323 | return 1; 324 | } 325 | api = argv[++i]; 326 | } 327 | else if ( _stricmp( argv[i],"--rootsig_file" ) == 0 ) 328 | { 329 | if ( i == argc-1 ) 330 | { 331 | printf( "Missing argument for --rootsig_file\n" ); 332 | return 1; 333 | } 334 | rootsig_file = argv[++i]; 335 | } 336 | else if ( _stricmp( argv[i],"--rootsig_profile" ) == 0 ) 337 | { 338 | if ( i == argc-1 ) 339 | { 340 | printf( "Missing argument for %s\n", argv[i] ); 341 | return 1; 342 | } 343 | frontend_opts.rs_profile = argv[++i]; 344 | } 345 | else if ( _stricmp( argv[i],"--rootsig_macro" ) == 0 ) 346 | { 347 | if ( i == argc-1 ) 348 | { 349 | printf( "Missing argument for %s\n",argv[i] ); 350 | return 1; 351 | } 352 | frontend_opts.rs_macro = argv[++i]; 353 | } 354 | else if ( _stricmp( argv[i],"--isa" ) == 0 ) 355 | { 356 | if ( i == argc-1 ) 357 | { 358 | printf( "Missing argument for --isa\n" ); 359 | return 1; 360 | } 361 | opts.isa_prefix = argv[++i]; 362 | } 363 | else if ( strcmp( argv[i],"-s" ) == 0 ) 364 | { 365 | if ( i == argc-1 ) 366 | { 367 | printf( "Missing argument for -s\n" ); 368 | return 1; 369 | } 370 | source_lang = argv[++i]; 371 | } 372 | else if ( strcmp( argv[i],"-D" ) == 0 ) 373 | { 374 | if ( i == argc-1 ) 375 | { 376 | printf( "Missing argument for %s\n", argv[i] ); 377 | return 1; 378 | } 379 | 380 | char* def = argv[++i]; 381 | char* value = def; 382 | while ( *value ) 383 | { 384 | if ( *(value++) == '=' ) 385 | { 386 | value[-1] = '\0'; // replace '=' with null and stop scanning 387 | break; 388 | } 389 | } 390 | 391 | frontend_opts.defines.push_back( std::pair( def,value ) ); 392 | } 393 | else if ( _stricmp( argv[i],"--profile" ) == 0 || 394 | _stricmp( argv[i], "-p" ) == 0 ) 395 | { 396 | if ( i == argc-1 ) 397 | { 398 | printf( "Missing argument for %s\n",argv[i] ); 399 | return 1; 400 | } 401 | 402 | frontend_opts.profile = argv[++i]; 403 | } 404 | else if ( _stricmp( argv[i],"--function" ) == 0 || 405 | _stricmp( argv[i],"-f" ) == 0 ) 406 | { 407 | if ( i == argc-1 ) 408 | { 409 | printf( "Missing argument for %s\n",argv[i] ); 410 | return 1; 411 | } 412 | 413 | frontend_opts.entry = argv[++i]; 414 | } 415 | else if ( _stricmp( argv[i], "--DXFlags" ) == 0 ) 416 | { 417 | if ( i == argc-1 ) 418 | { 419 | printf( "Missing argument for %s\n",argv[i] ); 420 | return 1; 421 | } 422 | 423 | frontend_opts.dx_flags = strtoul( argv[++i], nullptr, 0 ); 424 | 425 | } 426 | else if ( _stricmp( argv[i],"--DXLocation" ) == 0 ) 427 | { 428 | if ( i == argc-1 ) 429 | { 430 | printf( "Missing argument for %s\n",argv[i] ); 431 | return 1; 432 | } 433 | frontend_opts.dx_location = argv[++i]; 434 | } 435 | else if ( argv[i][0] == '-' ) 436 | { 437 | printf( "Don't understand what: '%s' means\n",argv[i] ); 438 | ShowHelp(); 439 | return 1; 440 | } 441 | else 442 | { 443 | frontend_opts.input_file = argv[i]; 444 | } 445 | 446 | ++i; 447 | } 448 | 449 | if ( frontend_opts.input_file == nullptr ) 450 | { 451 | printf( "No input filename\n" ); 452 | return 1; 453 | } 454 | 455 | 456 | if ( _stricmp( source_lang,"hlsl" ) == 0 ) 457 | { 458 | if ( !readAllText( frontend_opts.input_text,frontend_opts.input_file ) ) 459 | { 460 | printf( "Failed to read source from: %s\n",frontend_opts.input_file ); 461 | return 1; 462 | } 463 | 464 | if ( frontend_opts.profile == nullptr ) 465 | { 466 | printf( "Missing --profile\n" ); 467 | return 1; 468 | } 469 | 470 | if ( !CompileHLSL( frontend_opts, opts ) ) 471 | return 1; 472 | } 473 | else if ( _stricmp( source_lang,"dxbc" ) == 0 ) 474 | { 475 | // load bytecode 476 | if ( frontend_opts.input_file != nullptr ) 477 | { 478 | if ( !readAllBytes( opts.bytecode, frontend_opts.input_file ) ) 479 | { 480 | printf( "Unable to load bytecode from: %s\n", frontend_opts.input_file ); 481 | return 1; 482 | } 483 | } 484 | 485 | // try to extract a root signature 486 | if( opts.rootsig.empty() ) 487 | { 488 | if( !GetRootSignatureFromDXBC( frontend_opts, opts ) ) 489 | { 490 | // failure here indicates DX compiler DLL problems 491 | // diagnostics will happen elsewhere 492 | // Simply not having a root signature is considered success here... 493 | return 1; 494 | } 495 | } 496 | } 497 | else 498 | { 499 | printf( "Source language: '%s' not recognized\n",source_lang ); 500 | return 1; 501 | } 502 | 503 | // load root signature if we're missing one 504 | if ( opts.rootsig.empty() ) 505 | { 506 | if ( rootsig_file != nullptr ) 507 | { 508 | if ( !readAllBytes( opts.rootsig, rootsig_file ) ) 509 | { 510 | printf( "Unable to load root signature from: %s\n",rootsig_file ); 511 | return 1; 512 | } 513 | } 514 | } 515 | 516 | // Load compiler DLL 517 | HINSTANCE compilerInstance = (HINSTANCE)LoadLibraryA( DLL_NAME ); 518 | if ( !compilerInstance ) 519 | { 520 | printf( "Failed to load: %s\n",DLL_NAME ); 521 | return 1; 522 | } 523 | 524 | PFNOPENCOMPILER pfnOpenCompiler = (PFNOPENCOMPILER)GetProcAddress( compilerInstance,g_cOpenCompilerFnName ); 525 | if ( !pfnOpenCompiler ) 526 | { 527 | printf( "GetProcAddress failed for: %s\n",g_cOpenCompilerFnName ); 528 | return 1; 529 | } 530 | 531 | 532 | SFunctionTable functionTable; 533 | SOpenCompiler desc; 534 | desc.InterfaceVersion = 1; 535 | desc.pCompilerFuncs = &functionTable; 536 | 537 | // get the right set of callbacks 538 | if ( !pfnOpenCompiler( desc ) ) 539 | { 540 | printf( "OpenCompiler failed\n" ); 541 | return 1; 542 | } 543 | 544 | // get list of supported asics 545 | GetAsicList( functionTable,opts.asics ); 546 | 547 | // filter asic list down to the ones we've been asked to use. By default use all of them 548 | if ( !asicNames.empty() ) 549 | { 550 | size_t nAsicsToKeep=0; 551 | for ( size_t i=0; i 21 | #include "IntelGPUCompiler.h" 22 | 23 | struct FrontendOptions 24 | { 25 | std::vector< std::pair > defines; 26 | std::string input_text; 27 | 28 | const char* profile = nullptr; 29 | const char* entry = "main"; 30 | unsigned int dx_flags = 0; 31 | const char* dx_location = "d3dcompiler_47.dll"; 32 | const char* input_file = nullptr; 33 | const char* rs_macro = nullptr; 34 | const char* rs_profile = "rootsig_1_0"; 35 | }; 36 | 37 | struct ToolInputs 38 | { 39 | std::vector bytecode; 40 | std::vector rootsig; 41 | const char* isa_prefix = "./isa_"; 42 | std::vector< IntelGPUCompiler::PlatformInfo > asics; 43 | }; 44 | 45 | bool CompileHLSL( FrontendOptions& opts, ToolInputs& inputs ); 46 | bool GetRootSignatureFromDXBC( FrontendOptions& frontend_opts, ToolInputs& inputs ); 47 | 48 | #endif -------------------------------------------------------------------------------- /IntelShaderAnalyzer.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.27428.2037 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "IntelShaderAnalyzer", "IntelShaderAnalyzer.vcxproj", "{7A538657-DB64-494A-A5D4-CBDB552231E7}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|x64 = Debug|x64 11 | Release|x64 = Release|x64 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {7A538657-DB64-494A-A5D4-CBDB552231E7}.Debug|x64.ActiveCfg = Debug|x64 15 | {7A538657-DB64-494A-A5D4-CBDB552231E7}.Debug|x64.Build.0 = Debug|x64 16 | {7A538657-DB64-494A-A5D4-CBDB552231E7}.Release|x64.ActiveCfg = Release|x64 17 | {7A538657-DB64-494A-A5D4-CBDB552231E7}.Release|x64.Build.0 = Release|x64 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | GlobalSection(ExtensibilityGlobals) = postSolution 23 | SolutionGuid = {70D60463-4154-488F-94AD-77DE57EEEE6B} 24 | EndGlobalSection 25 | EndGlobal 26 | -------------------------------------------------------------------------------- /IntelShaderAnalyzer.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | x64 7 | 8 | 9 | Release 10 | x64 11 | 12 | 13 | 14 | 15.0 15 | {7A538657-DB64-494A-A5D4-CBDB552231E7} 16 | Win32Proj 17 | IntelShaderAnalyzer 18 | 10.0.16299.0 19 | 20 | 21 | 22 | Application 23 | true 24 | v141 25 | Unicode 26 | 27 | 28 | Application 29 | false 30 | v141 31 | true 32 | Unicode 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | true 48 | 49 | 50 | false 51 | 52 | 53 | 54 | NotUsing 55 | Level3 56 | Disabled 57 | true 58 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions) 59 | true 60 | 61 | 62 | Console 63 | true 64 | 65 | 66 | 67 | 68 | NotUsing 69 | Level3 70 | MaxSpeed 71 | true 72 | true 73 | true 74 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 75 | true 76 | 77 | 78 | Console 79 | true 80 | true 81 | true 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | -------------------------------------------------------------------------------- /IntelShaderAnalyzer.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;hm;inl;inc;ipp;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | {32bc0925-8116-4b69-be1b-94e8591b1630} 18 | 19 | 20 | {c43ce26e-f85b-4cd9-9e52-05a7beb7af3a} 21 | 22 | 23 | 24 | 25 | Source Files 26 | 27 | 28 | Header Files 29 | 30 | 31 | 32 | 33 | Source Files 34 | 35 | 36 | Source Files 37 | 38 | 39 | 40 | 41 | 42 | Test 43 | 44 | 45 | 46 | 47 | Test\Cases 48 | 49 | 50 | Test\Cases 51 | 52 | 53 | Test\Cases 54 | 55 | 56 | Test\Cases 57 | 58 | 59 | Test\Cases 60 | 61 | 62 | Test\Cases 63 | 64 | 65 | Test\Cases 66 | 67 | 68 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2017 Intel 2 | Permission is hereby granted, free of charge, to any person obtaining a copy 3 | of this software and associated documentation files (the "Software"), to deal 4 | in the Software without restriction, including without limitation the rights 5 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 6 | copies of the Software, and to permit persons to whom the Software is 7 | furnished to do so, subject to the following conditions: 8 | The above copyright notice and this permission notice shall be included in all 9 | copies or substantial portions of the Software. 10 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 11 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 12 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 13 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 14 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 15 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 16 | SOFTWARE. 17 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # DISCONTINUATION OF PROJECT # 2 | This project will no longer be maintained by Intel. 3 | Intel has ceased development and contributions including, but not limited to, maintenance, bug fixes, new releases, or updates, to this project. 4 | Intel no longer accepts patches to this project. 5 | 6 | ## Intel Shader Analyzer 7 | Intel Shader Analyzer is a tool for offline static analysis of shaders for Intel GPU Architectures. It allows a user to compile dxbc or HLSL code and inspect the generated GPU ISA for either DX11 and DX12. 8 | 9 | Intel Shader Analyzer uses a dedicated driver API to compile and disassemble shaders, and may be run on any Windows 10 machine. It depends on the following graphics driver components: 10 | * For 32-bit: 11 | * igc32.dll 12 | * iga32.dll 13 | * IntelGPUCompiler32.dll 14 | * For 64-bit: 15 | * igc64.dll 16 | * iga64.dll 17 | * IntelGPUCompiler64.dll 18 | 19 | 20 | In the initial release, these driver components are bundled with the release executable. Future driver releases will also allow Intel GPU users to run with in-situ drivers. 21 | 22 | Besides being a functional tool, Intel Shader Analyzer is also intended to serve as a working refrence for the use of the driver compilation API, so that others may incorporate into their own tool chains as appropriate. 23 | 24 | ## Related Links 25 | 26 | The following third-party tools integrate IntelShaderAnalyzer and provide GUIs: 27 | * [Pyramid](https://github.com/jbarczak/pyramid) 28 | * [Shader Playground](http://shader-playground.timjones.io/) 29 | 30 | Below are some overviews and articles which introduce the ISA and architecture: 31 | * [Intel Graphics ISA (micro 2016)](https://software.intel.com/sites/default/files/managed/89/92/micro-2016-ISA-tutorial.pdf) 32 | * [Introduction to Gen Assembly](https://software.intel.com/en-us/articles/introduction-to-gen-assembly) 33 | * [Gen11 Architecture Whitepaper](https://software.intel.com/sites/default/files/managed/db/88/The-Architecture-of-Intel-Processor-Graphics-Gen11_R1new.pdf) 34 | 35 | Detailed ISA documentation can be found in the PRMs: 36 | * [Skylake](https://01.org/sites/default/files/documentation/intel-gfx-prm-osrc-skl-vol07-3d_media_gpgpu.pdf) 37 | * [KabyLake](https://01.org/sites/default/files/documentation/intel-gfx-prm-osrc-kbl-vol07-3d_media_gpgpu.pdf) 38 | 39 | 40 | ## Usage 41 | 42 | Intel Shader Analyzer can consume HLSL input or DX bytecode, and pass them for compilation to either the DX11 or DX12 compilers. Currently, HLSL is only supported for shader model 5 shaders. 43 | 44 | A simple HLSL command line is shown below: 45 | 46 | IntelShaderAnalyzer.exe -s hlsl -f MyVS -p vs_5_0 shader.hlsl 47 | 48 | By default, DX11 will be used. DX12 may be specified by using the `--api` command line switch. For example: 49 | 50 | IntelShaderAnalyzer.exe -s hlsl --api dx12 -f MyVS -p vs_5_0 shader.hlsl 51 | 52 | The `dxbc` source language may be used to feed dx bytecode directly to the tool. For example: 53 | 54 | IntelShaderAnalyzer.exe -s dxbc --api dx11 shader.bin 55 | 56 | The `dxbc` option also supports passing DXIL shaders to the DX12 backend. For example: 57 | 58 | IntelShaderAnalyzer.exe -s dxbc --api dx12 --rootsig_file rootsig.bin shader.bin 59 | 60 | ### Root Signatures 61 | 62 | DX12 compilation requires a root signature, so that the compiler may determine how samplers, descriptors, and constants are to be provided to the shader. Different root signatures will result in slightly different generation. Intel Shader Analyzer can obtain a root signature in several differnet ways. If more than one of them is attempted, they are applied in the order described here. 63 | 64 | #### HLSL Attributes 65 | 66 | The first option is to use HLSL attributes to embed a root signature in the resulting shader blob, as shown in the example below. If a root signature is found embedded in the compiled shader, it will always be used first. 67 | 68 | ``` 69 | #define MyRS1 "DescriptorTable(SRV(t0))," \ 70 | "StaticSampler(s0, addressU = TEXTURE_ADDRESS_CLAMP, " \ 71 | "filter = FILTER_MIN_MAG_MIP_LINEAR )" 72 | 73 | Texture2D tx : register(t0); 74 | sampler SS : register(s0); 75 | 76 | [RootSignature(MyRS1)] 77 | float4 main( float4 uv : uv ) : SV_Target 78 | { 79 | return tx.Sample( SS, uv ); 80 | } 81 | 82 | 83 | ``` 84 | 85 | #### Two-Pass Compilation 86 | 87 | For HLSL shaders, a second option is to use the `--rootsig_macro` command line switch to compile a root signature out of the same source. Here is the same shader, without the `rootsignature` attribute: 88 | 89 | ``` 90 | #define MyRS1 "DescriptorTable(SRV(t0))," \ 91 | "StaticSampler(s0, addressU = TEXTURE_ADDRESS_CLAMP, " \ 92 | "filter = FILTER_MIN_MAG_MIP_LINEAR )" 93 | 94 | Texture2D tx : register(t0); 95 | sampler SS : register(s0); 96 | 97 | float4 main( float4 uv : uv ) : SV_Target 98 | { 99 | return tx.Sample( SS, uv ); 100 | } 101 | ``` 102 | 103 | If the following command line is used, Intel Shader Analyzer will attempt to compile the input file a second time to obtain the root signature: 104 | 105 | IntelShaderAnalyzer.exe -s HLSL --rootsig_macro MyRS1 --api dx12 --profile ps_5_0 filename.hlsl 106 | 107 | 108 | #### Precompiled Root Signatures 109 | 110 | The final option is to supply a pre-compiled, serialized root signature in a separate file, using the following command line: 111 | 112 | IntelShaderAnalyzer.exe -s HLSL --rootsig_file rootsig.bin --api dx12 --profile ps_5_0 filename.hlsl 113 | 114 | This option may also be used with dxbc input: 115 | 116 | IntelShaderAnalyzer.exe -s dxbc --rootsig_file rootsig.bin --api dx12 filename.dxbc 117 | 118 | ## Command Line 119 | 120 | 121 | ### General-Purpose Options 122 | 123 | -l 124 | --list-asics 125 | 126 | Print a list of supported device families. 127 | 128 | 129 | -c 130 | --asic 131 | 132 | Add the specified device to the list of compile targets. The device name must be one of the ones returned by --list-asics. By default, all supported asics are compiled. 133 | 134 | --api dx11 135 | --api dx12 136 | 137 | Set the target API. Default is 'dx11'. Code generation may differ between the dx11 and dx12 drivers. Supported APIs are 'dx11' and 'dx12' Compilation for DX12 requires a root signature. 138 | 139 | --isa 140 | 141 | Set the directory name for output ISA files. For each target device the compiler will emit a file named .asm 142 | 143 | For example: 144 | --isa ./output --asic Skylake 145 | 146 | will produce a file named: ./outputSkylake.asm 147 | 148 | The default is "./isa_". 149 | 150 | -s [hlsl | dxbc] 151 | 152 | Set the source language. Valid values are `hlsl` or `dxbc`. The `dxbc`source language may be used for both legacy DX11 bytecode and DXIL. Default is `dxbc` 153 | 154 | --rootsig_file 155 | 156 | Load a serialized DX root signature from the specified path. 157 | 158 | 159 | ### HLSL Options 160 | 161 | --rootsig_profile 162 | 163 | Set the compilation profile for root signature compilation. Default is: `rootsig_1_0`. 164 | 165 | --rootsig_macro 166 | 167 | Sets the macro name for root signature compilation. If this option is specified, and no root signature is provided. The tool will attempt to re-compile the input HLSL source to extract the root signature. 168 | 169 | --DXLocation 170 | 171 | Set the location of the D3D compiler DLL. The default is `d3dcompiler_47.dll` 172 | 173 | --DXFlags 174 | 175 | Set the flags for the HLSL compiler. Argument is a bitwise combination of D3DCOMPILE_ flags. See the [MSDN documentation](https://docs.microsoft.com/en-us/windows/desktop/direct3dhlsl/d3dcompile-constants) 176 | 177 | -D = 178 | -D 179 | 180 | Add a preprocessor define 181 | 182 | --profile 183 | -p 184 | 185 | Set the shader profile for HLSL compilation. Required. 186 | 187 | --function 188 | -f 189 | 190 | Set the entrypoint for HLSL compilation. Optional. Default is `main`. 191 | 192 | 193 | ## Running Tests 194 | 195 | The tests use a very simple-minded python script. 196 | 197 | To run the tests, cd to the 'tests' directory, copy the executable into it (and the driver DLLs, as required). Then run `python run_tests.py` 198 | The script will automatically check exit codes, but it is necessary to manually inspect the output to ensure that the tool is behaving as expected. 199 | 200 | The tests need to be run from a bash shell, or a windows shell with GNU 'rm' utilities in the path. 201 | -------------------------------------------------------------------------------- /tests/cases/command_line.txt: -------------------------------------------------------------------------------- 1 | /* 2 | @DO $EXE$ -h 3 | @DO_FAIL $EXE$ 4 | @DO_FAIL $EXE$ --bogus_option 5 | @DO_FAIL $EXE$ -bogus_option 6 | @DO $EXE$ -l 7 | @DO $EXE$ --list-asics 8 | @DO_FAIL $EXE$ -s bogus_lang --api dx11 $PATH$ 9 | @DO_FAIL $EXE$ -s dxbc --api bogus_api $PATH$ 10 | @DO_FAIL $EXE$ -s 11 | @DO_FAIL $EXE$ --api 12 | @DO_FAIL $EXE$ -p 13 | @DO_FAIL $EXE$ -c 14 | @DO_FAIL $EXE$ --rootsig_profile 15 | @DO_FAIL $EXE$ --rootsig_macro 16 | @DO_FAIL $EXE$ -s dxbc--api dx12 -D 17 | @DO_FAIL $EXE$ -s dxbc --api dx11 bad_filename 18 | @DO_FAIL $EXE$ -s hlsl --api dx11 bad_filename 19 | @DO_FAIL $EXE$ -s dxbc --api dx12 bad_filename 20 | @DO_FAIL $EXE$ -s dxbc --api dx12 bad_filename 21 | @DO_FAIL $EXE$ -s hlsl --api dx11 $PATH$ 22 | @DO_FAIL $EXE$ -s dxbc --api dx11 $PATH$ 23 | 24 | 25 | @DO $EXE$ -s hlsl --api dx11 -p cs_5_0 -c Skylake --isa myext_ $PATH$ 26 | @DO cat myext_Skylake.asm 27 | @DO rm myext_Skylake.asm 28 | 29 | @END 30 | 31 | */ 32 | 33 | [numthreads(64,1,1)] 34 | void main() 35 | { 36 | } 37 | -------------------------------------------------------------------------------- /tests/cases/data/ps50.dxbc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GameTechDev/IntelShaderAnalyzer/c0fbef5094dcc3e20f9c4c9fa6b97f73a1700905/tests/cases/data/ps50.dxbc -------------------------------------------------------------------------------- /tests/cases/data/ps50_with_rs.dxbc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GameTechDev/IntelShaderAnalyzer/c0fbef5094dcc3e20f9c4c9fa6b97f73a1700905/tests/cases/data/ps50_with_rs.dxbc -------------------------------------------------------------------------------- /tests/cases/data/ps60.dxbc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GameTechDev/IntelShaderAnalyzer/c0fbef5094dcc3e20f9c4c9fa6b97f73a1700905/tests/cases/data/ps60.dxbc -------------------------------------------------------------------------------- /tests/cases/data/ps60_with_rs.dxbc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GameTechDev/IntelShaderAnalyzer/c0fbef5094dcc3e20f9c4c9fa6b97f73a1700905/tests/cases/data/ps60_with_rs.dxbc -------------------------------------------------------------------------------- /tests/cases/data/rootsig_readme_2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GameTechDev/IntelShaderAnalyzer/c0fbef5094dcc3e20f9c4c9fa6b97f73a1700905/tests/cases/data/rootsig_readme_2 -------------------------------------------------------------------------------- /tests/cases/data/testrootsig: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GameTechDev/IntelShaderAnalyzer/c0fbef5094dcc3e20f9c4c9fa6b97f73a1700905/tests/cases/data/testrootsig -------------------------------------------------------------------------------- /tests/cases/dxbc.txt: -------------------------------------------------------------------------------- 1 | 2 | # DX11 3 | @DO $EXE$ -s dxbc --api dx11 $DIR$/data/ps50.dxbc 4 | 5 | ############## 6 | # DX12-dxbc 7 | ############## 8 | 9 | @DO $EXE$ -s dxbc --api dx12 $DIR$/data/ps50.dxbc --rootsig_file $DIR$/data/testrootsig 10 | @DO $EXE$ -s dxbc --api dx12 $DIR$/data/ps50_with_rs.dxbc 11 | 12 | # missing root-sig 13 | @DO_FAIL $EXE$ -s dxbc --api dx12 $DIR$/data/ps50.dxbc 14 | 15 | ############## 16 | # DX12-dxil 17 | ############## 18 | @DO $EXE$ -s dxbc --api dx12 $DIR$/data/ps60.dxbc --rootsig_file $DIR$/data/testrootsig 19 | @DO $EXE$ -s dxbc --api dx12 $DIR$/data/ps60_with_rs.dxbc 20 | 21 | # missing root-sig 22 | @DO_FAIL $EXE$ -s dxbc --api dx12 $DIR$/data/ps60.dxbc 23 | 24 | @DO rm -rf *.asm -------------------------------------------------------------------------------- /tests/cases/fxc_11.txt: -------------------------------------------------------------------------------- 1 | /* 2 | @DO $EXE$ -s hlsl --api dx11 -f Foo -p ps_5_0 $PATH$ 3 | @DO_FAIL $EXE$ -s hlsl --api dx11 -f Bar -p ps_5_0 $PATH$ 4 | @DO_FAIL $EXE$ -s hlsl --api dx12 -f Foo -p ps_5_0 $PATH$ 5 | @DO_FAIL $EXE$ -s hlsl --api dx11 -p ps_5_0 -c Skylake --isa ISA_ --DXLocation foo.dll $PATH$ 6 | @DO rm -rf *.asm 7 | @END 8 | */ 9 | 10 | float4 Foo( ) : SV_Target 11 | { 12 | return 0; 13 | } 14 | -------------------------------------------------------------------------------- /tests/cases/fxc_12.txt: -------------------------------------------------------------------------------- 1 | /* 2 | # no root signature 3 | @DO_FAIL $EXE$ -s hlsl --api dx12 -f NoRootSig -p ps_5_0 $PATH$ 4 | 5 | # root-sig file missing 6 | @DO_FAIL $EXE$ -s hlsl --api dx12 -f NoRootSig -p ps_5_0 $PATH$ --rootsig_file $DIR$/data/testrootsig_missing 7 | 8 | # root-sig from file 9 | @DO $EXE$ -s hlsl --api dx12 -f NoRootSig -p ps_5_0 $PATH$ --rootsig_file $DIR$/data/testrootsig 10 | 11 | # root-sig from HLSL attribute 12 | @DO $EXE$ -s hlsl --api dx12 -f HasRootSig -p ps_5_0 $PATH$ 13 | 14 | ######################################## 15 | # two-pass compilation 16 | ######################################## 17 | 18 | # bad macro name 19 | @DO_FAIL $EXE$ -s hlsl --api dx12 -f NoRootSig -p ps_5_0 $PATH$ --rootsig_macro bogus_macro 20 | 21 | # missing macro name 22 | @DO_FAIL $EXE$ -s hlsl --api dx12 -f NoRootSig -p ps_5_0 $PATH$ --rootsig_profile rootsig_1_0 23 | 24 | # bad profile 25 | @DO_FAIL $EXE$ -s hlsl --api dx12 -f NoRootSig -p ps_5_0 $PATH$ --rootsig_profile bad 26 | 27 | # success case 28 | @DO $EXE$ -s hlsl --api dx12 -f NoRootSig -p ps_5_0 $PATH$ --rootsig_macro MyRS 29 | 30 | @DO rm -rf *.asm 31 | 32 | @END 33 | */ 34 | 35 | #define MyRS "SRV(t0)" 36 | 37 | [RootSignature(MyRS)] 38 | float4 HasRootSig() : SV_Target 39 | { 40 | return 0; 41 | } 42 | 43 | float4 NoRootSig( ) : SV_Target 44 | { 45 | return 0; 46 | } 47 | -------------------------------------------------------------------------------- /tests/cases/fxc_define.txt: -------------------------------------------------------------------------------- 1 | /* 2 | @DO_FAIL $EXE$ -s hlsl -p cs_5_0 $PATH$ 3 | @DO_FAIL $EXE$ -s hlsl -p cs_5_0 -D FOO=baz $PATH$ 4 | @DO_FAIL $EXE$ -s hlsl -p cs_5_0 -D FOO=bar $PATH$ 5 | @DO $EXE$ -s hlsl -p cs_5_0 -D FOO=bar -D BAR=42 $PATH$ 6 | @DO rm -rf *.asm 7 | */ 8 | 9 | #ifndef FOO 10 | #error "Missing foo" 11 | #endif 12 | 13 | RWByteAddressBuffer buff; 14 | 15 | [numthreads(64,1,1)] 16 | void main() 17 | { 18 | int bar = 0; 19 | buff.Store(0, FOO + BAR + 5 ); 20 | } -------------------------------------------------------------------------------- /tests/cases/readme_1.txt: -------------------------------------------------------------------------------- 1 | /* 2 | @DO $EXE$ -s hlsl -f main -p ps_5_0 --api dx12 $PATH$ 3 | @DO rm -rf *.asm 4 | @END 5 | */ 6 | 7 | #define MyRS1 "DescriptorTable(SRV(t0))," \ 8 | "StaticSampler(s0, addressU = TEXTURE_ADDRESS_CLAMP, " \ 9 | "filter = FILTER_MIN_MAG_MIP_LINEAR )" 10 | 11 | Texture2D tx : register(t0); 12 | sampler SS : register(s0); 13 | 14 | [RootSignature(MyRS1)] 15 | float4 main( float4 uv : uv ) : SV_Target 16 | { 17 | return tx.Sample( SS, uv ); 18 | } 19 | -------------------------------------------------------------------------------- /tests/cases/readme_2.txt: -------------------------------------------------------------------------------- 1 | /* 2 | @DO $EXE$ -s HLSL --rootsig_macro MyRS1 --api dx12 --profile ps_5_0 $PATH$ 3 | @DO $EXE$ -s HLSL --rootsig_file $DIR$/data/rootsig_readme_2 --api dx12 --profile ps_5_0 $PATH$ 4 | @DO rm -rf *.asm 5 | @END 6 | */ 7 | 8 | #define MyRS1 "DescriptorTable(SRV(t0))," \ 9 | "StaticSampler(s0, addressU = TEXTURE_ADDRESS_CLAMP, " \ 10 | "filter = FILTER_MIN_MAG_MIP_LINEAR )" 11 | 12 | Texture2D tx : register(t0); 13 | sampler SS : register(s0); 14 | 15 | float4 main( float4 uv : uv ) : SV_Target 16 | { 17 | return tx.Sample( SS, uv ); 18 | } -------------------------------------------------------------------------------- /tests/run_tests.py: -------------------------------------------------------------------------------- 1 | # 2 | # This script scanes a directory full of test cases. For each file, it opens the file 3 | # and parses a set of commands. There are two types of commands: 4 | # @ DO which runs a command that should succeed, and and @DO_FAIL, which runs a command that should fail. 5 | # If the exit code is deviates from what is expected, the test will indicate failure 6 | # 7 | # Some simple text substitution is done on the command line for maintainability 8 | # $PATH$ is replaced with the path to the current file 9 | # $FILE$ is replaced with the current file name 10 | # $DIR$ is replaced with the path to the test directory 11 | # $EXE$ is the path to the test executable 12 | # 13 | 14 | import os; 15 | import sys; 16 | import subprocess; 17 | 18 | test_path = './cases' 19 | binary_path = 'IntelShaderAnalyzer.exe' 20 | 21 | for file in os.listdir(test_path): 22 | 23 | fullpath = os.path.join(test_path, file); 24 | 25 | if os.path.isfile(fullpath): 26 | print (fullpath); 27 | 28 | f = open(fullpath,'r') 29 | lines = f.readlines(); 30 | f.close(); 31 | 32 | # extract commands 33 | commands = []; 34 | expect_fail = []; 35 | for line in lines : 36 | 37 | tokens = line.split(); 38 | 39 | if len(tokens) == 0: 40 | continue; 41 | 42 | # $END$ signals end of test script 43 | if tokens[0] == "@END": 44 | break; 45 | 46 | if tokens[0] == "@DO": 47 | expect_fail.append(False); 48 | elif tokens[0] == "@DO_FAIL": 49 | expect_fail.append(True); 50 | else: 51 | continue; 52 | 53 | tokens = tokens[1:]; 54 | 55 | # do substitution 56 | command = ''; 57 | for tok in tokens : 58 | tok = tok.replace( "$FILE$", file ) 59 | tok = tok.replace( "$PATH$", fullpath ) 60 | tok = tok.replace( "$DIR$", test_path ) 61 | tok = tok.replace( "$EXE$", binary_path ) 62 | command = command + tok + ' '; 63 | 64 | commands.append(command); 65 | 66 | # run the commands 67 | for i in range(0, len(commands)): 68 | command = commands[i]; 69 | 70 | print(' COMMAND: ' + command); 71 | sys.stdout.flush(); 72 | 73 | result = os.system( command ); 74 | fail = (result != 0); 75 | 76 | if( result != 0 and result != 1 ): 77 | print( ' UNEXPECTED RETURN CODE: ' + str(result) + ' TEST FAILED!' ); 78 | sys.exit(); 79 | 80 | if (result == 0 and expect_fail[i]) or (result == 1 and not expect_fail[i]): 81 | print( 'WRONG RETURN CODE: TEST FAILED!!!!!!!' ) 82 | sys.exit(); 83 | 84 | 85 | print( 'TEST PASSED') 86 | --------------------------------------------------------------------------------