static ID3DBlobPtr CompileShader(const char* shaderCode, size_t shaderLength, const char* shaderProfile) { ID3DBlobPtr blob = nullptr; ID3DBlobPtr errors = nullptr; HRESULT hr = D3DCompile(shaderCode, shaderLength, nullptr, nullptr, nullptr, "Main", shaderProfile, 0, 0, &blob, &errors); if (FAILED(hr)) { if (errors) { OutputDebugStringA((char*)errors->GetBufferPointer()); errors->Release(); } return nullptr; } return blob; }
void CreateRootSignature(ID3D12RootSignature** rootSignature, const D3D12_ROOT_SIGNATURE_DESC1& desc) { D3D12_VERSIONED_ROOT_SIGNATURE_DESC versionedDesc = { }; versionedDesc.Version = D3D_ROOT_SIGNATURE_VERSION_1_1; versionedDesc.Desc_1_1 = desc; ID3DBlobPtr signature; ID3DBlobPtr error; HRESULT hr = D3D12SerializeVersionedRootSignature(&versionedDesc, &signature, &error); if(FAILED(hr)) { const char* errString = error ? reinterpret_cast<const char*>(error->GetBufferPointer()) : ""; #if UseAsserts_ AssertMsg_(false, "Failed to create root signature: %s", errString); #else throw DXException(hr, MakeString(L"Failed to create root signature: %s", errString).c_str()); #endif } DXCall(DX12::Device->CreateRootSignature(0, signature->GetBufferPointer(), signature->GetBufferSize(), IID_PPV_ARGS(rootSignature))); }
static ID3DBlob* CompileShader(const wchar* path, const char* functionName, const char* profile, const D3D_SHADER_MACRO* defines, bool forceOptimization, vector<wstring>& filePaths) { // Make a hash off the expanded shader code string shaderCode = GetExpandedShaderCode(path, filePaths); wstring cacheName = MakeShaderCacheName(shaderCode, functionName, profile, defines); if(FileExists(cacheName.c_str())) { File cacheFile(cacheName.c_str(), File::OpenRead); const uint64 shaderSize = cacheFile.Size(); vector<uint8> compressedShader; compressedShader.resize(shaderSize); cacheFile.Read(shaderSize, compressedShader.data()); ID3DBlob* decompressedShader[1] = { nullptr }; uint32 indices[1] = { 0 }; DXCall(D3DDecompressShaders(compressedShader.data(), shaderSize, 1, 0, indices, 0, decompressedShader, nullptr)); return decompressedShader[0]; } std::printf("Compiling shader %s %s %s\n", WStringToAnsi(GetFileName(path).c_str()).c_str(), profile, MakeDefinesString(defines).c_str()); // Loop until we succeed, or an exception is thrown while(true) { UINT flags = D3DCOMPILE_WARNINGS_ARE_ERRORS; #ifdef _DEBUG flags |= D3DCOMPILE_DEBUG; if(forceOptimization == false) flags |= D3DCOMPILE_SKIP_OPTIMIZATION; #endif ID3DBlob* compiledShader; ID3DBlobPtr errorMessages; HRESULT hr = D3DCompileFromFile(path, defines, D3D_COMPILE_STANDARD_FILE_INCLUDE, functionName, profile, flags, 0, &compiledShader, &errorMessages); if(FAILED(hr)) { if(errorMessages) { wchar message[1024] = { 0 }; char* blobdata = reinterpret_cast<char*>(errorMessages->GetBufferPointer()); MultiByteToWideChar(CP_ACP, 0, blobdata, static_cast<int>(errorMessages->GetBufferSize()), message, 1024); std::wstring fullMessage = L"Error compiling shader file \""; fullMessage += path; fullMessage += L"\" - "; fullMessage += message; // Pop up a message box allowing user to retry compilation int retVal = MessageBoxW(nullptr, fullMessage.c_str(), L"Shader Compilation Error", MB_RETRYCANCEL); if(retVal != IDRETRY) throw DXException(hr, fullMessage.c_str()); #if EnableShaderCaching_ shaderCode = GetExpandedShaderCode(path); cacheName = MakeShaderCacheName(shaderCode, functionName, profile, defines); #endif } else { _ASSERT(false); throw DXException(hr); } } else { // Compress the shader D3D_SHADER_DATA shaderData; shaderData.pBytecode = compiledShader->GetBufferPointer(); shaderData.BytecodeLength = compiledShader->GetBufferSize(); ID3DBlobPtr compressedShader; DXCall(D3DCompressShaders(1, &shaderData, D3D_COMPRESS_SHADER_KEEP_ALL_PARTS, &compressedShader)); // Create the cache directory if it doesn't exist if(DirectoryExists(baseCacheDir.c_str()) == false) Win32Call(CreateDirectory(baseCacheDir.c_str(), nullptr)); if(DirectoryExists(cacheDir.c_str()) == false) Win32Call(CreateDirectory(cacheDir.c_str(), nullptr)); File cacheFile(cacheName.c_str(), File::OpenWrite); // Write the compiled shader to disk uint64 shaderSize = compressedShader->GetBufferSize(); cacheFile.Write(shaderSize, compressedShader->GetBufferPointer()); return compiledShader; } } }
// code->bytecode bool CompileShader( ShaderType type, const std::string& code, D3DBlob& blob, const D3D_SHADER_MACRO* pDefines, const char* pEntry, bool throwerror) { #if defined(_DEBUG) || defined(DEBUGFAST) UINT flags = D3DCOMPILE_DEBUG | D3DCOMPILE_SKIP_OPTIMIZATION; #else UINT flags = D3DCOMPILE_SKIP_VALIDATION; if (type != DX11::D3D::ShaderType::Hull) { flags |= D3D10_SHADER_ENABLE_BACKWARDS_COMPATIBILITY | D3DCOMPILE_OPTIMIZATION_LEVEL3; } else { flags |= D3DCOMPILE_SKIP_OPTIMIZATION; } #endif char const *profile = nullptr; char const *sufix = nullptr; switch (type) { case DX11::D3D::ShaderType::Vertex: profile = D3D::VertexShaderVersionString(); sufix = "vs"; break; case DX11::D3D::ShaderType::Pixel: profile = D3D::PixelShaderVersionString(); sufix = "ps"; break; case DX11::D3D::ShaderType::Geometry: profile = D3D::GeometryShaderVersionString(); sufix = "gs"; break; case DX11::D3D::ShaderType::Hull: profile = D3D::HullShaderVersionString(); sufix = "hs"; break; case DX11::D3D::ShaderType::Domain: profile = D3D::DomainShaderVersionString(); sufix = "ds"; break; case DX11::D3D::ShaderType::Compute: profile = D3D::ComputeShaderVersionString(); sufix = "cs"; break; default: return false; break; } ID3DBlobPtr shaderBuffer; ID3DBlobPtr errorBuffer; HRESULT hr = HLSLCompiler::getInstance().CompileShader(code.c_str(), code.length(), nullptr, pDefines, nullptr, pEntry != nullptr ? pEntry : "main", profile, flags, 0, ToAddr(shaderBuffer), ToAddr(errorBuffer)); if (errorBuffer) { INFO_LOG(VIDEO, "Shader compiler messages:\n%s", (const char*)errorBuffer->GetBufferPointer()); } if (FAILED(hr)) { static int num_failures = 0; std::string filename = StringFromFormat("%sbad_%s_%04i.txt", File::GetUserPath(D_DUMP_IDX).c_str(), sufix, num_failures++); std::ofstream file; OpenFStream(file, filename, std::ios_base::out); file << code; file << "\n"; file << (const char*)errorBuffer->GetBufferPointer(); file.close(); if (throwerror) { PanicAlert("Failed to compile shader: %s\nDebug info (%s):\n%s", filename.c_str(), profile, (char*)errorBuffer->GetBufferPointer()); } blob = nullptr; } else { blob = std::move(shaderBuffer); } return SUCCEEDED(hr); }
static ID3DBlob* CompileShader(const wchar* path, const char* functionName, ShaderType type, ShaderProfile profile, const D3D_SHADER_MACRO* defines, bool forceOptimization, GrowableList<wstring>& filePaths) { if(FileExists(path) == false) { Assert_(false); throw Exception(L"Shader file " + std::wstring(path) + L" does not exist"); } uint64 profileIdx = uint64(profile) * uint64(ShaderType::NumTypes) + uint64(type); Assert_(profileIdx < TotalNumProfiles); const char* profileString = ProfileStrings[profileIdx]; // Make a hash off the expanded shader code string shaderCode = GetExpandedShaderCode(path, filePaths); wstring cacheName = MakeShaderCacheName(shaderCode, functionName, profileString, defines); if(FileExists(cacheName.c_str())) { File cacheFile(cacheName.c_str(), FileOpenMode::Read); const uint64 shaderSize = cacheFile.Size(); Array<uint8> compressedShader; compressedShader.Init(shaderSize); cacheFile.Read(shaderSize, compressedShader.Data()); ID3DBlob* decompressedShader[1] = { nullptr }; uint32 indices[1] = { 0 }; DXCall(D3DDecompressShaders(compressedShader.Data(), shaderSize, 1, 0, indices, 0, decompressedShader, nullptr)); return decompressedShader[0]; } WriteLog("Compiling %s shader %s_%s %s\n", TypeStrings[uint64(type)], WStringToAnsi(GetFileName(path).c_str()).c_str(), functionName, MakeDefinesString(defines).c_str()); // Loop until we succeed, or an exception is thrown while(true) { UINT flags = D3DCOMPILE_WARNINGS_ARE_ERRORS; #ifdef _DEBUG flags |= D3DCOMPILE_DEBUG; // This is causing some shader bugs /*if(forceOptimization == false) flags |= D3DCOMPILE_SKIP_OPTIMIZATION;*/ #endif ID3DBlob* compiledShader; ID3DBlobPtr errorMessages; FrameworkInclude include; HRESULT hr = D3DCompileFromFile(path, defines, &include, functionName, profileString, flags, 0, &compiledShader, &errorMessages); if(FAILED(hr)) { if(errorMessages) { wchar message[1024] = { 0 }; char* blobdata = reinterpret_cast<char*>(errorMessages->GetBufferPointer()); MultiByteToWideChar(CP_ACP, 0, blobdata, static_cast<int>(errorMessages->GetBufferSize()), message, 1024); std::wstring fullMessage = L"Error compiling shader file \""; fullMessage += path; fullMessage += L"\" - "; fullMessage += message; // Pop up a message box allowing user to retry compilation int retVal = MessageBoxW(nullptr, fullMessage.c_str(), L"Shader Compilation Error", MB_RETRYCANCEL); if(retVal != IDRETRY) throw DXException(hr, fullMessage.c_str()); } else { Assert_(false); throw DXException(hr); } } else { // Compress the shader D3D_SHADER_DATA shaderData; shaderData.pBytecode = compiledShader->GetBufferPointer(); shaderData.BytecodeLength = compiledShader->GetBufferSize(); ID3DBlobPtr compressedShader; DXCall(D3DCompressShaders(1, &shaderData, D3D_COMPRESS_SHADER_KEEP_ALL_PARTS, &compressedShader)); // Create the cache directory if it doesn't exist if(DirectoryExists(baseCacheDir.c_str()) == false) Win32Call(CreateDirectory(baseCacheDir.c_str(), nullptr)); if(DirectoryExists(cacheDir.c_str()) == false) Win32Call(CreateDirectory(cacheDir.c_str(), nullptr)); File cacheFile(cacheName.c_str(), FileOpenMode::Write); // Write the compiled shader to disk uint64 shaderSize = compressedShader->GetBufferSize(); cacheFile.Write(shaderSize, compressedShader->GetBufferPointer()); return compiledShader; } } }