Esempio n. 1
0
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;
        }
    }
}
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;
        }
    }
}