From 2819f93f26afc84a22c61ac301aa8ff228571dce Mon Sep 17 00:00:00 2001 From: Mike Popoloski Date: Sat, 11 Apr 2015 15:40:31 -0400 Subject: [PATCH] shaderc dx11 now removes unused constants The D3D11 shader compiler doesn't remove unused constants because it would change the size of buffers uploaded by the application. This means that all of the default unused bgfx uniforms take up a huge amount of space that forces the app to waste a ton of time uploading zeroes. This change is a bit of a hack but removes the unused constants and improves performance a great deal. --- tools/shaderc/shaderc.cpp | 39 -------------------------- tools/shaderc/shaderc.h | 41 ++++++++++++++++++++++++++- tools/shaderc/shaderc_hlsl.cpp | 51 ++++++++++++++++++++++++++++++++-- 3 files changed, 88 insertions(+), 43 deletions(-) diff --git a/tools/shaderc/shaderc.cpp b/tools/shaderc/shaderc.cpp index cc060001..1388385f 100644 --- a/tools/shaderc/shaderc.cpp +++ b/tools/shaderc/shaderc.cpp @@ -313,45 +313,6 @@ void strreplace(char* _str, const char* _find, const char* _replace) } } -class LineReader -{ -public: - LineReader(const char* _str) - : m_str(_str) - , m_pos(0) - , m_size( (uint32_t)strlen(_str) ) - { - } - - std::string getLine() - { - const char* str = &m_str[m_pos]; - skipLine(); - - const char* eol = &m_str[m_pos]; - - std::string tmp; - tmp.assign(str, eol-str); - return tmp; - } - - bool isEof() const - { - return m_str[m_pos] == '\0'; - } - - void skipLine() - { - const char* str = &m_str[m_pos]; - const char* nl = bx::strnl(str); - m_pos += (uint32_t)(nl - str); - } - - const char* m_str; - uint32_t m_pos; - uint32_t m_size; -}; - void printCode(const char* _code, int32_t _line, int32_t _start, int32_t _end) { fprintf(stderr, "Code:\n---\n"); diff --git a/tools/shaderc/shaderc.h b/tools/shaderc/shaderc.h index e728cee3..38735c6b 100644 --- a/tools/shaderc/shaderc.h +++ b/tools/shaderc/shaderc.h @@ -61,6 +61,45 @@ extern bool g_verbose; #include #include "../../src/vertexdecl.h" +class LineReader +{ +public: + LineReader(const char* _str) + : m_str(_str) + , m_pos(0) + , m_size((uint32_t)strlen(_str)) + { + } + + std::string getLine() + { + const char* str = &m_str[m_pos]; + skipLine(); + + const char* eol = &m_str[m_pos]; + + std::string tmp; + tmp.assign(str, eol - str); + return tmp; + } + + bool isEof() const + { + return m_str[m_pos] == '\0'; + } + + void skipLine() + { + const char* str = &m_str[m_pos]; + const char* nl = bx::strnl(str); + m_pos += (uint32_t)(nl - str); + } + + const char* m_str; + uint32_t m_pos; + uint32_t m_size; +}; + struct UniformType { enum Enum @@ -102,7 +141,7 @@ void strreplace(char* _str, const char* _find, const char* _replace); int32_t writef(bx::WriterI* _writer, const char* _format, ...); void writeFile(const char* _filePath, const void* _data, int32_t _size); -bool compileHLSLShader(bx::CommandLine& _cmdLine, uint32_t _d3d, const std::string& _code, bx::WriterI* _writer); +bool compileHLSLShader(bx::CommandLine& _cmdLine, uint32_t _d3d, const std::string& _code, bx::WriterI* _writer, bool firstPass = true); bool compileGLSLShader(bx::CommandLine& _cmdLine, uint32_t _gles, const std::string& _code, bx::WriterI* _writer); #endif // SHADERC_H_HEADER_GUARD diff --git a/tools/shaderc/shaderc_hlsl.cpp b/tools/shaderc/shaderc_hlsl.cpp index b5f6a04e..55ebaa26 100644 --- a/tools/shaderc/shaderc_hlsl.cpp +++ b/tools/shaderc/shaderc_hlsl.cpp @@ -7,6 +7,7 @@ #if SHADERC_CONFIG_HLSL +#include #include #include @@ -143,6 +144,8 @@ static uint32_t s_optimizationLevelDx11[4] = D3DCOMPILE_OPTIMIZATION_LEVEL3, }; +typedef std::vector UniformNameList; + bool getReflectionDataDx9(ID3DBlob* _code, UniformArray& _uniforms) { // see reference for magic values: https://msdn.microsoft.com/en-us/library/ff552891(VS.85).aspx @@ -243,7 +246,7 @@ bool getReflectionDataDx9(ID3DBlob* _code, UniformArray& _uniforms) return true; } -bool getReflectionDataDx11(ID3DBlob* _code, bool _vshader, UniformArray& _uniforms, uint8_t& _numAttrs, uint16_t* _attrs, uint16_t& _size) +bool getReflectionDataDx11(ID3DBlob* _code, bool _vshader, UniformArray& _uniforms, uint8_t& _numAttrs, uint16_t* _attrs, uint16_t& _size, UniformNameList& unusedUniforms) { ID3D11ShaderReflection* reflect = NULL; HRESULT hr = D3DReflect(_code->GetBufferPointer() @@ -355,6 +358,9 @@ bool getReflectionDataDx11(ID3DBlob* _code, bool _vshader, UniformArray& _unifor } else { + if (0 == (varDesc.uFlags & D3D_SVF_USED)) + unusedUniforms.push_back(varDesc.Name); + BX_TRACE("\t%s, unknown type", varDesc.Name); } } @@ -391,7 +397,7 @@ bool getReflectionDataDx11(ID3DBlob* _code, bool _vshader, UniformArray& _unifor return true; } -bool compileHLSLShader(bx::CommandLine& _cmdLine, uint32_t _d3d, const std::string& _code, bx::WriterI* _writer) +bool compileHLSLShader(bx::CommandLine& _cmdLine, uint32_t _d3d, const std::string& _code, bx::WriterI* _writer, bool firstPass) { BX_TRACE("DX11"); @@ -495,8 +501,47 @@ bool compileHLSLShader(bx::CommandLine& _cmdLine, uint32_t _d3d, const std::stri } else { - if (!getReflectionDataDx11(code, profile[0] == 'v', uniforms, numAttrs, attrs, size) ) + UniformNameList unusedUniforms; + if (!getReflectionDataDx11(code, profile[0] == 'v', uniforms, numAttrs, attrs, size, unusedUniforms) ) return false; + + if (firstPass && unusedUniforms.size() > 0) + { + // first time through, we just find unused uniforms and get rid of them + std::stringstream output; + LineReader reader(_code.c_str()); + while (!reader.isEof() ) + { + std::string line = reader.getLine(); + for (UniformNameList::const_iterator it = unusedUniforms.begin(); it != unusedUniforms.end(); ++it) + { + size_t index = line.find("uniform "); + if (index == std::string::npos) + continue; + + size_t index2 = line.find_first_not_of(' ', index); + if (index2 == std::string::npos) + continue; + + // matching lines like: uniform u_name; + // we want to replace "uniform" with "static" so that it's no longer + // included in the uniform blob that the application must upload + // we can't just remove them, because unused functions might still reference + // them and cause a compile error when they're gone + if (line.find(*it, index2) == index2) + { + line = line.replace(index, 7, "static"); + unusedUniforms.erase(it); + break; + } + } + + output << line << std::endl; + } + + // recompile with the unused uniforms converted to statics + return compileHLSLShader(_cmdLine, _d3d, output.str(), _writer, false); + } } uint16_t count = (uint16_t)uniforms.size();