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.
This commit is contained in:
Mike Popoloski 2015-04-11 15:40:31 -04:00
parent 68044893ab
commit 2819f93f26
3 changed files with 88 additions and 43 deletions

View file

@ -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");

View file

@ -61,6 +61,45 @@ extern bool g_verbose;
#include <bx/hash.h>
#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

View file

@ -7,6 +7,7 @@
#if SHADERC_CONFIG_HLSL
#include <sstream>
#include <d3dcompiler.h>
#include <d3d11shader.h>
@ -143,6 +144,8 @@ static uint32_t s_optimizationLevelDx11[4] =
D3DCOMPILE_OPTIMIZATION_LEVEL3,
};
typedef std::vector<std::string> 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();