972 lines
30 KiB
C++
972 lines
30 KiB
C++
#include <fstream>
|
|
#include <string>
|
|
#include <atlconv.h>
|
|
#include <atlbase.h>
|
|
#include <atlstr.h>
|
|
#include <sstream>
|
|
#include <assert.h>
|
|
#include "DXShaderManager.h"
|
|
//#include "Util.h"
|
|
|
|
ShaderManager g_shaderManager;
|
|
|
|
using namespace Microsoft::WRL;
|
|
|
|
template <> HRESULT CreateShader<ID3D11VertexShader>(ID3D11Device* pd3dDevice, ID3D11VertexShader** shader, ID3DBlob* pBlob)
|
|
{
|
|
HRESULT hr;
|
|
ID3D11VertexShader* vs = NULL;
|
|
V(pd3dDevice->CreateVertexShader( pBlob->GetBufferPointer(),pBlob->GetBufferSize(), NULL, &vs ) );
|
|
|
|
if(FAILED(hr)) {
|
|
SAFE_RELEASE(vs);
|
|
}
|
|
else
|
|
{
|
|
SAFE_RELEASE(*shader);
|
|
*shader = vs;
|
|
}
|
|
|
|
return hr;
|
|
};
|
|
|
|
template <> HRESULT CreateShader<ID3D11DomainShader>(ID3D11Device* pd3dDevice,ID3D11DomainShader** shader, ID3DBlob* pBlob)
|
|
{
|
|
HRESULT hr;
|
|
ID3D11DomainShader* ds = NULL;
|
|
V( pd3dDevice->CreateDomainShader( pBlob->GetBufferPointer(),pBlob->GetBufferSize(), NULL, &ds ) );
|
|
|
|
if(FAILED(hr))
|
|
{
|
|
SAFE_RELEASE(ds);
|
|
}
|
|
else
|
|
{
|
|
SAFE_RELEASE(*shader);
|
|
*shader = ds;
|
|
}
|
|
|
|
return hr;
|
|
};
|
|
|
|
template <> HRESULT CreateShader<ID3D11HullShader>(ID3D11Device* pd3dDevice, ID3D11HullShader** shader, ID3DBlob* pBlob)
|
|
{
|
|
HRESULT hr;
|
|
ID3D11HullShader* vs = NULL;
|
|
V( pd3dDevice->CreateHullShader( pBlob->GetBufferPointer(),pBlob->GetBufferSize(), NULL, &vs ) );
|
|
|
|
|
|
if(FAILED(hr))
|
|
{
|
|
SAFE_RELEASE(vs);
|
|
}
|
|
else
|
|
{
|
|
SAFE_RELEASE(*shader);
|
|
*shader = vs;
|
|
}
|
|
|
|
return hr;
|
|
};
|
|
|
|
template <> HRESULT CreateShader<ID3D11GeometryShader>(ID3D11Device* pd3dDevice, ID3D11GeometryShader** shader, ID3DBlob* pBlob)
|
|
{
|
|
HRESULT hr;
|
|
ID3D11GeometryShader* vs = NULL;
|
|
|
|
V( pd3dDevice->CreateGeometryShader( pBlob->GetBufferPointer(),pBlob->GetBufferSize(), NULL, &vs ) );
|
|
|
|
if(FAILED(hr))
|
|
{
|
|
SAFE_RELEASE(vs);
|
|
}
|
|
else
|
|
{
|
|
SAFE_RELEASE(*shader);
|
|
*shader = vs;
|
|
}
|
|
|
|
return hr;
|
|
};
|
|
|
|
template <> HRESULT CreateShader<ID3D11PixelShader>(ID3D11Device* pd3dDevice,ID3D11PixelShader** shader, ID3DBlob* pBlob)
|
|
{
|
|
HRESULT hr;
|
|
ID3D11PixelShader* ps = NULL;
|
|
V( pd3dDevice->CreatePixelShader( pBlob->GetBufferPointer(),pBlob->GetBufferSize(), NULL, &ps ) );
|
|
|
|
if(FAILED(hr))
|
|
{
|
|
SAFE_RELEASE(ps);
|
|
}
|
|
else
|
|
{
|
|
SAFE_RELEASE(*shader);
|
|
*shader = ps;
|
|
}
|
|
|
|
return hr;
|
|
};
|
|
|
|
template <> HRESULT CreateShader<ID3D11ComputeShader>(ID3D11Device* pd3dDevice,ID3D11ComputeShader** shader, ID3DBlob* pBlob)
|
|
{
|
|
HRESULT hr;
|
|
ID3D11ComputeShader* vs = NULL;
|
|
V( pd3dDevice->CreateComputeShader( pBlob->GetBufferPointer(),pBlob->GetBufferSize(), NULL, &vs ) );
|
|
|
|
if(FAILED(hr))
|
|
{
|
|
SAFE_RELEASE(vs);
|
|
}
|
|
else
|
|
{
|
|
SAFE_RELEASE(*shader);
|
|
*shader = vs;
|
|
}
|
|
|
|
return hr;
|
|
};
|
|
|
|
template <>
|
|
HRESULT CreateShaderStreamOutput<ID3D11VertexShader>(ID3D11Device* pd3dDevice, ID3D11VertexShader** shader, ID3DBlob* pBlob, D3D11_SO_DECLARATION_ENTRY *pSODeclaration, UINT numSOEntries, UINT* pSOStrides, UINT numSOStrides, UINT rasterizerStream )
|
|
{
|
|
return S_FALSE;
|
|
};
|
|
|
|
|
|
template <>
|
|
HRESULT CreateShaderStreamOutput<ID3D11HullShader>(ID3D11Device* pd3dDevice, ID3D11HullShader** shader, ID3DBlob* pBlob, D3D11_SO_DECLARATION_ENTRY *pSODeclaration, UINT numSOEntries, UINT* pSOStrides, UINT numSOStrides, UINT rasterizerStream )
|
|
{
|
|
return S_FALSE;
|
|
};
|
|
|
|
|
|
template <>
|
|
HRESULT CreateShaderStreamOutput<ID3D11DomainShader>(ID3D11Device* pd3dDevice, ID3D11DomainShader** shader, ID3DBlob* pBlob, D3D11_SO_DECLARATION_ENTRY *pSODeclaration, UINT numSOEntries, UINT* pSOStrides, UINT numSOStrides, UINT rasterizerStream )
|
|
{
|
|
return S_FALSE;
|
|
};
|
|
|
|
|
|
template <>
|
|
HRESULT CreateShaderStreamOutput<ID3D11GeometryShader>(ID3D11Device* pd3dDevice, ID3D11GeometryShader** shader, ID3DBlob* pBlob, D3D11_SO_DECLARATION_ENTRY *pSODeclaration, UINT numSOEntries, UINT* pSOStrides, UINT numSOStrides, UINT rasterizerStream )
|
|
{
|
|
HRESULT hr;
|
|
ID3D11GeometryShader* vs = NULL;
|
|
|
|
V( pd3dDevice->CreateGeometryShaderWithStreamOutput( pBlob->GetBufferPointer(), pBlob->GetBufferSize(),pSODeclaration, numSOEntries, pSOStrides, numSOStrides, rasterizerStream, NULL, &vs) );
|
|
|
|
if(FAILED(hr))
|
|
{
|
|
SAFE_RELEASE(vs);
|
|
}
|
|
else
|
|
{
|
|
SAFE_RELEASE(*shader);
|
|
*shader = vs;
|
|
}
|
|
|
|
return hr;
|
|
|
|
};
|
|
|
|
|
|
template <>
|
|
HRESULT CreateShaderStreamOutput<ID3D11PixelShader>(ID3D11Device* pd3dDevice, ID3D11PixelShader** shader, ID3DBlob* pBlob, D3D11_SO_DECLARATION_ENTRY *pSODeclaration, UINT numSOEntries, UINT* pSOStrides, UINT numSOStrides, UINT rasterizerStream )
|
|
{
|
|
return S_FALSE;
|
|
};
|
|
|
|
|
|
template <>
|
|
HRESULT CreateShaderStreamOutput<ID3D11ComputeShader>(ID3D11Device* pd3dDevice, ID3D11ComputeShader** shader, ID3DBlob* pBlob, D3D11_SO_DECLARATION_ENTRY *pSODeclaration, UINT numSOEntries, UINT* pSOStrides, UINT numSOStrides, UINT rasterizerStream )
|
|
{
|
|
return S_FALSE;
|
|
};
|
|
|
|
#include <d3dcompiler.h>
|
|
template <typename T>
|
|
HRESULT Shader<T>::CompileShader(ID3D11Device* pd3dDevice, ID3DBlob** ppBlobOut )
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
bool srcChanged = false;
|
|
const auto& globIncludes = g_shaderManager.GetIncludes();
|
|
|
|
|
|
if(m_compiledInvalid)
|
|
{
|
|
srcChanged = true;
|
|
}
|
|
else
|
|
{
|
|
WatchedFile* shaderSrcFileWatch = globIncludes.find(m_fileNameSrcString)->second;
|
|
srcChanged = CompareFileTime(&shaderSrcFileWatch->getLastWrite().ftLastWriteTime, &m_lastChangeCompiled.ftLastWriteTime) > 0;
|
|
}
|
|
|
|
if(srcChanged == false)
|
|
{
|
|
// check include
|
|
|
|
if(m_firstLoad) // first run
|
|
{
|
|
ID3DBlob* srcBlob;
|
|
D3DReadFileToBlob(m_fileNameSrc, &srcBlob);
|
|
|
|
ID3DBlob* codeBlob;
|
|
ID3DBlob* errBlob;
|
|
|
|
// preparse
|
|
CShaderInclude includeObj(m_fileNameSrcString.c_str());
|
|
|
|
D3DPreprocess(srcBlob->GetBufferPointer(),srcBlob->GetBufferSize(),NULL, m_pDefines, &includeObj, &codeBlob, &errBlob);
|
|
const std::set<std::string>& includes = includeObj.GetIncludes();
|
|
for(auto inclFileName : includes)
|
|
{
|
|
m_includes.insert(inclFileName);
|
|
WatchedFile* currInclude = g_shaderManager.AddIncludeFile(inclFileName);
|
|
//std::cout << inclFileName << std::endl;
|
|
//exit(0);
|
|
}
|
|
|
|
SAFE_RELEASE(srcBlob);
|
|
SAFE_RELEASE(codeBlob);
|
|
SAFE_RELEASE(errBlob);
|
|
|
|
}
|
|
|
|
// check if includes are newer
|
|
for(const auto it : m_includes)
|
|
{
|
|
WatchedFile* incFile = globIncludes.find(it)->second;
|
|
if(CompareFileTime(&incFile->getLastWrite().ftLastWriteTime, &m_lastChangeCompiled.ftLastWriteTime ) > 0)
|
|
{
|
|
srcChanged = true;
|
|
std::cout << "src changed" << std::endl;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if(m_firstLoad == false && srcChanged == false)
|
|
return S_OK;
|
|
|
|
#ifndef _DEBUG
|
|
// for nsight shader debugging: compile shaders on first load, then only modified
|
|
if(!g_shaderManager.UsePrecompiledShaders())
|
|
{
|
|
if(m_firstLoad) srcChanged = true;
|
|
}
|
|
#endif
|
|
|
|
if(srcChanged)
|
|
{
|
|
std::cout << "." ;
|
|
// make sure sub directories exist
|
|
CreateDirectory(ExtractPath(m_fileNameCompiled).c_str(), NULL);
|
|
CShaderInclude includeObj(m_fileNameSrcString.c_str());
|
|
|
|
DWORD dwShaderFlags = D3DCOMPILE_ENABLE_STRICTNESS;
|
|
|
|
if(!g_shaderManager.UsePrecompiledShaders())
|
|
{
|
|
// dwShaderFlags |= D3DCOMPILE_WARNINGS_ARE_ERRORS;
|
|
}
|
|
|
|
#if defined( DEBUG ) || defined( _DEBUG )
|
|
// Set the D3DCOMPILE_DEBUG flag to embed debug information in the shaders.
|
|
// Setting this flag improves the shader debugging experience, but still allows
|
|
// the shaders to be optimized and to run exactly the way they will run in
|
|
// the release configuration of this program.
|
|
dwShaderFlags |= D3DCOMPILE_DEBUG;
|
|
//dwShaderFlags |= D3DCOMPILE_IEEE_STRICTNESS;
|
|
#endif
|
|
//dwShaderFlags |= D3DCOMPILE_DEBUG;
|
|
dwShaderFlags |= m_compilerFlags;
|
|
|
|
|
|
ID3DBlob* pErrorBlob= NULL;
|
|
std::wcout << "Compile: " << m_fileNameSrc << " Entrypoint: " << m_entryPoint << std::endl;
|
|
hr = D3DCompileFromFile(m_fileNameSrc, m_pDefines, &includeObj, m_entryPoint, m_shaderModel, dwShaderFlags, 0, ppBlobOut, &pErrorBlob);
|
|
|
|
if(pErrorBlob != NULL && pErrorBlob->GetBufferPointer() != NULL && pErrorBlob->GetBufferSize() > 0) {
|
|
OutputDebugStringA( (char*)pErrorBlob->GetBufferPointer() );
|
|
std::cerr << (char*)pErrorBlob->GetBufferPointer() << std::endl;
|
|
SAFE_RELEASE( pErrorBlob );
|
|
}
|
|
|
|
if( FAILED(hr) )
|
|
{
|
|
|
|
OutputDebugStringA(m_fileNameCompiled.c_str());
|
|
OutputDebugStringA("\n");
|
|
OutputDebugStringA("-------------------------------------------------------------------------------\n");
|
|
std::cout << "filename " << m_fileNameCompiled << std::endl;
|
|
std::cout << "-------------------------------------------------------------------------------" << std::endl;
|
|
std::cout << " shader macros: " << std::endl;
|
|
if(m_pDefines)
|
|
{
|
|
for(int numDefs = 0; m_pDefines[numDefs].Name != NULL; ++numDefs)
|
|
{
|
|
//std::cout << numDefs << ": " << m_pDefines[numDefs].Name << " " << m_pDefines[numDefs].Definition << std::endl;
|
|
std::cout << m_pDefines[numDefs].Name << "=" << m_pDefines[numDefs].Definition << std::endl;
|
|
}
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
// regenerate include file list
|
|
//m_includes.clear();
|
|
const std::set<std::string>& includes = includeObj.GetIncludes();
|
|
|
|
for(auto inclFileName : includes)
|
|
{
|
|
m_includes.insert(inclFileName);
|
|
WatchedFile* currInclude = g_shaderManager.AddIncludeFile(inclFileName);
|
|
}
|
|
|
|
// write compiled shader to disk
|
|
//std::wcout << m_fileNameCompiled << std::endl;
|
|
V(D3DWriteBlobToFile(*ppBlobOut, std::wstring(m_fileNameCompiled.begin(), m_fileNameCompiled.end()).c_str(), true));
|
|
if(hr!= S_OK)
|
|
{
|
|
std::cout << "filename " << m_fileNameCompiled << "to long, aborting" << std::endl;
|
|
V_RETURN(hr);
|
|
exit(1);
|
|
}
|
|
|
|
std::ofstream compiledFile(m_fileNameCompiled.c_str(), std::ios::out | std::ios::binary);
|
|
compiledFile.write((char*)(*ppBlobOut)->GetBufferPointer(), (*ppBlobOut)->GetBufferSize());
|
|
compiledFile.close();
|
|
|
|
// unref old shader if one is bound
|
|
SAFE_RELEASE(m_shader);
|
|
|
|
if(m_SONumEntries>0)
|
|
{
|
|
V(CreateShaderStreamOutput<T>(pd3dDevice, &m_shader, *ppBlobOut, m_SODeclarationArray, m_SONumEntries, m_SOStridesArray, m_SONumStrides, m_rasterizerStream));
|
|
}
|
|
else
|
|
V(CreateShader<T>(pd3dDevice, &m_shader, *ppBlobOut));
|
|
|
|
HANDLE hFindCompiled = FindFirstFile(m_fileNameCompiled.c_str(), &m_lastChangeCompiled);
|
|
if(hFindCompiled != INVALID_HANDLE_VALUE)
|
|
m_compiledInvalid = false;
|
|
|
|
}
|
|
else // load pre-compiled shader
|
|
{
|
|
std::cout << "." ;
|
|
std::ifstream compiledFile(m_fileNameCompiled.c_str(), std::ios::in | std::ios::binary);
|
|
assert(compiledFile.is_open());
|
|
unsigned int size_data = m_lastChangeCompiled.nFileSizeLow;
|
|
|
|
V(D3DReadFileToBlob(std::wstring(m_fileNameCompiled.begin(), m_fileNameCompiled.end()).c_str(), ppBlobOut));
|
|
if(hr!= S_OK)
|
|
{
|
|
std::cout << "filename " << m_fileNameCompiled << " path to long, aborting" << std::endl;
|
|
V_RETURN(hr);
|
|
exit(1);
|
|
}
|
|
//V(D3DCreateBlob(size_data,ppBlobOut));
|
|
//compiledFile.read((char*)(*ppBlobOut)->GetBufferPointer(), size_data);
|
|
//compiledFile.close();
|
|
|
|
// unref old shader if one is bound
|
|
SAFE_RELEASE(m_shader);
|
|
|
|
if(m_SONumEntries>0)
|
|
{
|
|
V(CreateShaderStreamOutput<T>(pd3dDevice, &m_shader, *ppBlobOut, m_SODeclarationArray, m_SONumEntries, m_SOStridesArray, m_SONumStrides, m_rasterizerStream));
|
|
}
|
|
else
|
|
{
|
|
V(CreateShader<T>(pd3dDevice, &m_shader, *ppBlobOut));
|
|
}
|
|
m_compiledInvalid = false;
|
|
}
|
|
m_firstLoad = false;
|
|
|
|
return hr;
|
|
|
|
}
|
|
|
|
ShaderManager::ShaderManager()
|
|
{
|
|
m_compiledShaderDirectory = COMPILED_SHADER_DIR;
|
|
CreateDirectory(m_compiledShaderDirectory.c_str(), NULL);
|
|
m_precompiledShadersEnabled = true;
|
|
}
|
|
|
|
ShaderManager::~ShaderManager()
|
|
{
|
|
Destroy();
|
|
}
|
|
|
|
Shader<ID3D11VertexShader>* ShaderManager::AddVertexShader( ID3D11Device* pd3dDevice, const char* szFileName, LPCSTR szEntryPoint, LPCSTR szShaderModel, ID3DBlob** ppBlobOut, D3D_SHADER_MACRO* pDefines /*= NULL*/, DWORD compilerFlags, const std::vector<int>& configHashes, ID3D11ClassLinkage* pClassLinkage /*= NULL */ )
|
|
{
|
|
std::string compiledFileName = CreateCompiledFileName( szFileName, szEntryPoint, szShaderModel, pDefines, compilerFlags, configHashes);
|
|
|
|
// check if shader is cached
|
|
auto it = m_vertexShaders.find(compiledFileName);
|
|
if(it != m_vertexShaders.end())
|
|
{
|
|
return it->second;
|
|
}
|
|
|
|
// otherwise load the shader
|
|
Shader<ID3D11VertexShader>* shader = new Shader<ID3D11VertexShader>(pd3dDevice, szFileName, szEntryPoint, szShaderModel, VERTEX_SHADER, ppBlobOut, compiledFileName, pDefines, compilerFlags, pClassLinkage);
|
|
|
|
m_vertexShaders[compiledFileName] = shader;
|
|
|
|
return shader;
|
|
|
|
}
|
|
|
|
Shader<ID3D11HullShader>* ShaderManager::AddHullShader( ID3D11Device* pd3dDevice, const char* szFileName, LPCSTR szEntryPoint, LPCSTR szShaderModel, ID3DBlob** ppBlobOut, D3D_SHADER_MACRO* pDefines /*= NULL*/, DWORD compilerFlags, const std::vector<int>& configHashes, ID3D11ClassLinkage* pClassLinkage /*= NULL */ )
|
|
{
|
|
std::string compiledFileName = CreateCompiledFileName( szFileName, szEntryPoint, szShaderModel, pDefines, compilerFlags, configHashes);
|
|
|
|
// check if shader is cached
|
|
auto it = m_hullShaders.find(compiledFileName);
|
|
if(it != m_hullShaders.end())
|
|
return it->second;
|
|
|
|
// otherwise load the shader
|
|
Shader<ID3D11HullShader>* shader = new Shader<ID3D11HullShader>(pd3dDevice, szFileName, szEntryPoint, szShaderModel, HULL_SHADER, ppBlobOut, compiledFileName, pDefines, compilerFlags, pClassLinkage);
|
|
m_hullShaders[compiledFileName] = shader;
|
|
return shader;
|
|
}
|
|
|
|
|
|
Shader<ID3D11DomainShader>* ShaderManager::AddDomainShader( ID3D11Device* pd3dDevice, const char* szFileName, LPCSTR szEntryPoint, LPCSTR szShaderModel, ID3DBlob** ppBlobOut, D3D_SHADER_MACRO* pDefines /*= NULL*/, DWORD compilerFlags, const std::vector<int>& configHashes, ID3D11ClassLinkage* pClassLinkage /*= NULL */ )
|
|
{
|
|
std::string compiledFileName = CreateCompiledFileName( szFileName, szEntryPoint, szShaderModel, pDefines, compilerFlags, configHashes);
|
|
|
|
// check if shader is cached
|
|
auto it = m_domainShaders.find(compiledFileName);
|
|
if(it != m_domainShaders.end())
|
|
return it->second;
|
|
|
|
// otherwise load the shader
|
|
Shader<ID3D11DomainShader>* shader = new Shader<ID3D11DomainShader>(pd3dDevice, szFileName, szEntryPoint, szShaderModel, DOMAIN_SHADER, ppBlobOut, compiledFileName, pDefines, compilerFlags, pClassLinkage);
|
|
if(shader->Get() != NULL)
|
|
{
|
|
m_domainShaders[compiledFileName] = shader;
|
|
return shader;
|
|
}
|
|
else return NULL;
|
|
}
|
|
|
|
Shader<ID3D11GeometryShader>* ShaderManager::AddGeometryShader( ID3D11Device* pd3dDevice, const char* szFileName, LPCSTR szEntryPoint, LPCSTR szShaderModel, ID3DBlob** ppBlobOut, D3D_SHADER_MACRO* pDefines /*= NULL*/, DWORD compilerFlags, const std::vector<int>& configHashes, ID3D11ClassLinkage* pClassLinkage /*= NULL */ )
|
|
{
|
|
std::string compiledFileName = CreateCompiledFileName( szFileName, szEntryPoint, szShaderModel, pDefines, compilerFlags, configHashes);
|
|
|
|
// check if shader is cached
|
|
auto it = m_geometryShaders.find(compiledFileName);
|
|
if(it != m_geometryShaders.end())
|
|
return it->second;
|
|
|
|
// otherwise load the shader
|
|
Shader<ID3D11GeometryShader>* shader = new Shader<ID3D11GeometryShader>(pd3dDevice, szFileName, szEntryPoint, szShaderModel, GEOMETRY_SHADER, ppBlobOut, compiledFileName, pDefines, compilerFlags, pClassLinkage);
|
|
m_geometryShaders[compiledFileName] = shader;
|
|
return shader;
|
|
}
|
|
|
|
Shader<ID3D11GeometryShader>* ShaderManager::AddGeometryShaderSO( ID3D11Device* pd3dDevice, const char* szFileName, LPCSTR szEntryPoint, LPCSTR szShaderModel, ID3DBlob** ppBlobOut, D3D_SHADER_MACRO* pDefines /*= NULL*/, DWORD compilerFlags /*= 0*/, D3D11_SO_DECLARATION_ENTRY *pSODeclaration /*= NULL*/, UINT numSOEntries /*= 0*/, UINT* pSOStrides /*= NULL*/, UINT numSOStrides /*= 0*/, UINT rasterizerStream /*= D3D11_SO_NO_RASTERIZED_STREAM*/, ID3D11ClassLinkage* pClassLinkage /*= NULL*/ )
|
|
{
|
|
std::string compiledFileName = CreateCompiledFileName( szFileName, szEntryPoint, szShaderModel, pDefines, compilerFlags);
|
|
|
|
// check if shader is cached
|
|
auto it = m_geometryShaders.find(compiledFileName);
|
|
if(it != m_geometryShaders.end())
|
|
return it->second;
|
|
|
|
// otherwise load the shader
|
|
Shader<ID3D11GeometryShader>* shader = new Shader<ID3D11GeometryShader>(pd3dDevice, szFileName, szEntryPoint, szShaderModel, GEOMETRY_SHADER, ppBlobOut, compiledFileName, pDefines, compilerFlags,
|
|
pSODeclaration, numSOEntries, pSOStrides, numSOStrides, rasterizerStream,
|
|
pClassLinkage);
|
|
m_geometryShaders[compiledFileName] = shader;
|
|
return shader;
|
|
}
|
|
|
|
Shader<ID3D11PixelShader>* ShaderManager::AddPixelShader( ID3D11Device* pd3dDevice, const char* szFileName, LPCSTR szEntryPoint, LPCSTR szShaderModel, ID3DBlob** ppBlobOut, D3D_SHADER_MACRO* pDefines /*= NULL*/, DWORD compilerFlags, const std::vector<int>& configHashes, ID3D11ClassLinkage* pClassLinkage /*= NULL */ )
|
|
{
|
|
std::string compiledFileName = CreateCompiledFileName( szFileName, szEntryPoint, szShaderModel, pDefines, compilerFlags, configHashes);
|
|
|
|
// check if shader is cached
|
|
auto it = m_pixelShaders.find(compiledFileName);
|
|
if(it != m_pixelShaders.end())
|
|
return it->second;
|
|
|
|
// otherwise load the shader
|
|
Shader<ID3D11PixelShader>* shader = new Shader<ID3D11PixelShader>(pd3dDevice, szFileName, szEntryPoint, szShaderModel, PIXEL_SHADER, ppBlobOut, compiledFileName, pDefines, compilerFlags, pClassLinkage);
|
|
m_pixelShaders[compiledFileName] = shader;
|
|
return shader;
|
|
}
|
|
|
|
Shader<ID3D11ComputeShader>* ShaderManager::AddComputeShader( ID3D11Device* pd3dDevice, const char* szFileName, LPCSTR szEntryPoint, LPCSTR szShaderModel, ID3DBlob** ppBlobOut, D3D_SHADER_MACRO* pDefines /*= NULL*/, DWORD compilerFlags, const std::vector<int>& configHashes, ID3D11ClassLinkage* pClassLinkage /*= NULL */ )
|
|
{
|
|
std::string compiledFileName = CreateCompiledFileName( szFileName, szEntryPoint, szShaderModel, pDefines, compilerFlags, configHashes);
|
|
|
|
// check if shader is cached
|
|
auto it = m_computeShaders.find(compiledFileName);
|
|
if(it != m_computeShaders.end())
|
|
return it->second;
|
|
|
|
// otherwise load the shader
|
|
Shader<ID3D11ComputeShader>* shader = new Shader<ID3D11ComputeShader>(pd3dDevice, szFileName, szEntryPoint, szShaderModel, COMPUTE_SHADER, ppBlobOut, compiledFileName, pDefines, compilerFlags, pClassLinkage);
|
|
m_computeShaders[compiledFileName] = shader;
|
|
return shader;
|
|
}
|
|
|
|
HRESULT ShaderManager::CheckAndReload(ID3D11Device* pd3dDevice)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
for(auto& inc : m_includeFiles )
|
|
{
|
|
inc.second->CheckIsModified();
|
|
}
|
|
|
|
for( const auto& shader : m_vertexShaders) { hr = shader.second->CheckAndReload(pd3dDevice); if(FAILED(hr)) return hr;}
|
|
for( const auto& shader : m_hullShaders) { hr = shader.second->CheckAndReload(pd3dDevice); if(FAILED(hr)) return hr;}
|
|
for( const auto& shader : m_domainShaders) { hr = shader.second->CheckAndReload(pd3dDevice); if(FAILED(hr)) return hr;}
|
|
for( const auto& shader : m_geometryShaders){ hr = shader.second->CheckAndReload(pd3dDevice); if(FAILED(hr)) return hr;}
|
|
for( const auto& shader : m_pixelShaders) { hr = shader.second->CheckAndReload(pd3dDevice); if(FAILED(hr)) return hr;}
|
|
for( const auto& shader : m_computeShaders) { hr = shader.second->CheckAndReload(pd3dDevice); if(FAILED(hr)) return hr;}
|
|
|
|
return hr;
|
|
}
|
|
|
|
void ShaderManager::Destroy()
|
|
{
|
|
for(auto& inc : m_includeFiles)
|
|
{
|
|
SAFE_DELETE(inc.second);
|
|
}
|
|
m_includeFiles.clear();
|
|
for(auto &shader : m_vertexShaders) delete shader.second;
|
|
for(auto &shader : m_domainShaders) delete shader.second;
|
|
for(auto &shader : m_hullShaders) delete shader.second;
|
|
for(auto &shader : m_geometryShaders) delete shader.second;
|
|
for(auto &shader : m_pixelShaders) delete shader.second;
|
|
for(auto &shader : m_computeShaders) delete shader.second;
|
|
|
|
m_vertexShaders.clear();
|
|
m_hullShaders.clear();
|
|
m_domainShaders.clear();
|
|
m_geometryShaders.clear();
|
|
m_pixelShaders.clear();
|
|
m_computeShaders.clear();
|
|
|
|
}
|
|
|
|
//const char* gSystemDir = "..\\Shader";
|
|
|
|
|
|
std::string ShaderManager::CreateCompiledFileName( const char* szFileName, LPCSTR szEntryPoint, LPCSTR szShaderModel, D3D_SHADER_MACRO* pDefines /*= NULL*/, DWORD compilerFlags /*= 0*/, const std::vector<int>& config_hashes )
|
|
{
|
|
std::string compiledFileName = m_compiledShaderDirectory;
|
|
compiledFileName.append(szFileName);
|
|
compiledFileName.append("-");
|
|
compiledFileName.append( szEntryPoint );
|
|
|
|
|
|
if(!config_hashes.empty())
|
|
{
|
|
for(auto hash : config_hashes)
|
|
{
|
|
std::stringstream ws;
|
|
ws << (int)hash;
|
|
compiledFileName.append("_");
|
|
compiledFileName.append(ws.str().c_str());
|
|
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(pDefines)
|
|
{
|
|
compiledFileName.append("-");
|
|
for(UINT i = 0; pDefines[i].Name != NULL; ++i)
|
|
{
|
|
std::string name = pDefines[i].Name;
|
|
if(name[0] == L'\"') name[0] = L'x';
|
|
if(name[name.length() -1 ] == '\"') name[name.length()-1] = L'x';
|
|
|
|
std::string def = pDefines[i].Definition;
|
|
if(def[0] == L'\"') def[0] = L'x';
|
|
if(def[def.length() -1 ] == L'\"') def[def.length()-1] = 'x';
|
|
|
|
compiledFileName.append(name);
|
|
compiledFileName.append("_");
|
|
compiledFileName.append(def);
|
|
|
|
if(pDefines[i+1].Name != NULL)
|
|
compiledFileName.append("-");
|
|
}
|
|
}
|
|
}
|
|
|
|
if(compilerFlags)
|
|
{
|
|
compiledFileName.append("-");
|
|
std::stringstream ss;
|
|
ss << compilerFlags;
|
|
compiledFileName.append(ss.str());
|
|
}
|
|
|
|
compiledFileName.append(".p");
|
|
|
|
//std::wcout << compiledFileName.c_str()<< std::endl;
|
|
return compiledFileName;
|
|
}
|
|
|
|
WatchedFile* ShaderManager::AddIncludeFile( std::string includeFileName )
|
|
{
|
|
const auto& it = m_includeFiles.find(includeFileName);
|
|
if(it == m_includeFiles.end())
|
|
{
|
|
WatchedFile* inc = new WatchedFile(includeFileName);
|
|
m_includeFiles[includeFileName] = inc;
|
|
return inc;
|
|
}
|
|
else
|
|
return it->second;
|
|
}
|
|
|
|
CShaderInclude::CShaderInclude( const char* shaderDir, const char* systemDir )
|
|
{
|
|
m_ShaderDir = ExtractPath(shaderDir);
|
|
|
|
m_SystemDir = ExtractPath(systemDir);
|
|
}
|
|
|
|
HRESULT __stdcall CShaderInclude::Open(D3D_INCLUDE_TYPE IncludeType, LPCSTR pFileName, LPCVOID pParentData, LPCVOID *ppData, UINT *pBytes) {
|
|
try {
|
|
std::string finalPath;
|
|
switch(IncludeType) {
|
|
case D3D_INCLUDE_LOCAL:
|
|
if (m_ShaderDir != std::string(""))
|
|
finalPath = m_ShaderDir + "\\" + pFileName;
|
|
else
|
|
finalPath = pFileName;
|
|
break;
|
|
case D3D_INCLUDE_SYSTEM:
|
|
if (m_SystemDir != std::string(""))
|
|
finalPath = m_SystemDir + "\\" + pFileName;
|
|
else
|
|
finalPath = pFileName;
|
|
break;
|
|
default:
|
|
assert(0);
|
|
}
|
|
m_includeFiles.insert(finalPath);
|
|
//std::cout << finalPath << std::endl;
|
|
std::ifstream includeFile(finalPath.c_str(), std::ios::in|std::ios::binary|std::ios::ate);
|
|
|
|
if (includeFile.is_open()) {
|
|
long long fileSize = includeFile.tellg();
|
|
char* buf = new char[(unsigned int)fileSize];
|
|
includeFile.seekg (0, std::ios::beg);
|
|
includeFile.read (buf, fileSize);
|
|
includeFile.close();
|
|
*ppData = buf;
|
|
*pBytes = (unsigned int)fileSize;
|
|
} else {
|
|
return E_FAIL;
|
|
}
|
|
|
|
|
|
return S_OK;
|
|
}
|
|
catch(std::exception) {
|
|
return E_FAIL;
|
|
}
|
|
}
|
|
|
|
HRESULT __stdcall CShaderInclude::Close(LPCVOID pData) {
|
|
char* buf = (char*)pData;
|
|
delete[] buf;
|
|
return S_OK;
|
|
}
|
|
|
|
WatchedFile::WatchedFile( const std::string& includeFileName )
|
|
{
|
|
m_fileName = includeFileName;
|
|
HANDLE hFind = FindFirstFile(m_fileName.c_str(), &m_lastWrite);
|
|
}
|
|
|
|
WatchedFile::~WatchedFile()
|
|
{
|
|
|
|
}
|
|
|
|
bool WatchedFile::CheckIsModified()
|
|
{
|
|
auto lastWrite = m_lastWrite.ftLastWriteTime;
|
|
|
|
HANDLE hFind = FindFirstFile(m_fileName.c_str(), &m_lastWrite);
|
|
return CompareFileTime(&m_lastWrite.ftLastWriteTime,&lastWrite) > 0;
|
|
}
|
|
|
|
DrawSourceConfig::~DrawSourceConfig()
|
|
{
|
|
for(auto e: commonShader.defines)
|
|
{
|
|
e.first.clear();
|
|
e.second.clear();
|
|
}
|
|
|
|
for(auto e: vertexShader.defines)
|
|
{
|
|
e.first.clear();
|
|
e.second.clear();
|
|
}
|
|
|
|
for(auto e: hullShader.defines)
|
|
{
|
|
e.first.clear();
|
|
e.second.clear();
|
|
}
|
|
|
|
for(auto e: domainShader.defines)
|
|
{
|
|
e.first.clear();
|
|
e.second.clear();
|
|
}
|
|
|
|
for(auto e: geometryShader.defines)
|
|
{
|
|
e.first.clear();
|
|
e.second.clear();
|
|
}
|
|
|
|
for(auto e: pixelShader.defines)
|
|
{
|
|
e.first.clear();
|
|
e.second.clear();
|
|
}
|
|
|
|
for(auto e: commonShader.defines)
|
|
{
|
|
e.first.clear();
|
|
e.second.clear();
|
|
}
|
|
|
|
commonShader.defines.clear();
|
|
computeShader.defines.clear();
|
|
vertexShader.defines.clear();
|
|
hullShader.defines.clear();
|
|
domainShader.defines.clear();
|
|
geometryShader.defines.clear();
|
|
pixelShader.defines.clear();
|
|
}
|
|
|
|
DrawSourceConfig * DrawRegistryBase::_CreateDrawSourceConfig( DescType const & desc, ID3D11Device * pd3dDevice ) const
|
|
{
|
|
DrawSourceConfig * sconfig = _NewDrawSourceConfig();
|
|
|
|
sconfig->vertexShader.target = "vs_5_0";
|
|
sconfig->hullShader.target = "hs_5_0";
|
|
sconfig->domainShader.target = "ds_5_0";
|
|
sconfig->geometryShader.target = "gs_5_0";
|
|
sconfig->pixelShader.target = "ps_5_0";
|
|
sconfig->computeShader.target = "cs_5_0";
|
|
|
|
sconfig->vertexShader.sourceFile.clear();
|
|
sconfig->hullShader.sourceFile.clear();
|
|
sconfig->domainShader.sourceFile.clear();
|
|
sconfig->geometryShader.sourceFile.clear();
|
|
sconfig->pixelShader.sourceFile.clear();
|
|
sconfig->computeShader.sourceFile.clear();
|
|
|
|
return sconfig;
|
|
}
|
|
|
|
void createDefineMacro(const std::vector< const ShaderDefineVector* >& defvec, std::vector<D3D_SHADER_MACRO>& outDefs)
|
|
{
|
|
|
|
for (int i=0; i<(int)defvec.size(); ++i) {
|
|
for(const auto& defI : *defvec[i])
|
|
{
|
|
const D3D_SHADER_MACRO def = {
|
|
defI.first.c_str(),
|
|
defI.second.c_str(),
|
|
};
|
|
outDefs.push_back(def);
|
|
}
|
|
}
|
|
|
|
const D3D_SHADER_MACRO zerodef = { 0, 0 };
|
|
outDefs.push_back(zerodef);
|
|
|
|
}
|
|
|
|
|
|
DrawConfig* DrawRegistryBase::_CreateDrawConfig( DescType const & desc, SourceConfigType const * sconfig, ID3D11Device * pd3dDevice, ID3D11InputLayout ** ppInputLayout, D3D11_INPUT_ELEMENT_DESC const * pInputElementDescs, int numInputElements ) const
|
|
{
|
|
assert(sconfig);
|
|
|
|
bool debug_shader_build = false;
|
|
|
|
DWORD dwShaderFlags = D3DCOMPILE_ENABLE_STRICTNESS;
|
|
|
|
#ifdef _DEBUG
|
|
dwShaderFlags |= D3DCOMPILE_DEBUG;
|
|
debug_shader_build = true;
|
|
#else
|
|
//dwShaderFlags |= D3DCOMPILE_OPTIMIZATION_LEVEL3;
|
|
#endif
|
|
|
|
ID3DBlob * pBlob = NULL;
|
|
|
|
Shader<ID3D11VertexShader> *vertexShader = NULL;
|
|
if (! sconfig->vertexShader.sourceFile.empty())
|
|
{
|
|
std::vector<int> config_hashes;
|
|
config_hashes.push_back(sconfig->value);
|
|
if(debug_shader_build) config_hashes.push_back(1337);
|
|
|
|
std::vector<const ShaderDefineVector *> fullDefs;
|
|
fullDefs.push_back(&sconfig->commonShader.defines);
|
|
fullDefs.push_back(&sconfig->vertexShader.defines);
|
|
|
|
std::vector<D3D_SHADER_MACRO> defs;
|
|
createDefineMacro(fullDefs,defs);
|
|
vertexShader = g_shaderManager.AddVertexShader(pd3dDevice, sconfig->vertexShader.sourceFile.c_str(), sconfig->vertexShader.entry.c_str(), sconfig->vertexShader.target.c_str(), &pBlob, &defs[0], dwShaderFlags, config_hashes);
|
|
fullDefs.clear();
|
|
assert(vertexShader->Get());
|
|
|
|
if (ppInputLayout && !*ppInputLayout) {
|
|
pd3dDevice->CreateInputLayout(pInputElementDescs, numInputElements,
|
|
pBlob->GetBufferPointer(),
|
|
pBlob->GetBufferSize(), ppInputLayout);
|
|
assert(ppInputLayout);
|
|
}
|
|
|
|
|
|
SAFE_RELEASE(pBlob);
|
|
}
|
|
|
|
Shader<ID3D11HullShader> *hullShader = NULL;
|
|
if (! sconfig->hullShader.sourceFile.empty())
|
|
{
|
|
std::vector<int> config_hashes;
|
|
config_hashes.push_back(sconfig->value);
|
|
if(debug_shader_build) config_hashes.push_back(1337);
|
|
|
|
std::vector<const ShaderDefineVector *> fullDefs;
|
|
fullDefs.push_back(&sconfig->commonShader.defines);
|
|
fullDefs.push_back(&sconfig->hullShader.defines);
|
|
|
|
std::vector<D3D_SHADER_MACRO> defs;
|
|
createDefineMacro(fullDefs,defs);
|
|
|
|
hullShader = g_shaderManager.AddHullShader(pd3dDevice, sconfig->hullShader.sourceFile.c_str(), sconfig->hullShader.entry.c_str(), sconfig->hullShader.target.c_str(),
|
|
&pBlob, &defs[0], dwShaderFlags, config_hashes);
|
|
|
|
assert(hullShader->Get());
|
|
SAFE_RELEASE(pBlob);
|
|
|
|
}
|
|
|
|
Shader<ID3D11DomainShader> *domainShader = NULL;
|
|
if (! sconfig->domainShader.sourceFile.empty())
|
|
{
|
|
std::vector<int> config_hashes;
|
|
config_hashes.push_back(sconfig->value);
|
|
if(debug_shader_build) config_hashes.push_back(1337);
|
|
|
|
std::vector<const ShaderDefineVector *> fullDefs;
|
|
fullDefs.push_back(&sconfig->commonShader.defines);
|
|
fullDefs.push_back(&sconfig->domainShader.defines);
|
|
|
|
std::vector<D3D_SHADER_MACRO> defs;
|
|
createDefineMacro(fullDefs, defs);
|
|
|
|
domainShader = g_shaderManager.AddDomainShader(pd3dDevice, sconfig->domainShader.sourceFile.c_str(), sconfig->domainShader.entry.c_str(), sconfig->domainShader.target.c_str(),
|
|
&pBlob, &defs[0], dwShaderFlags, config_hashes);
|
|
|
|
assert(domainShader->Get());
|
|
SAFE_RELEASE(pBlob);
|
|
|
|
}
|
|
|
|
Shader<ID3D11GeometryShader> *geometryShader = NULL;
|
|
if (! sconfig->geometryShader.sourceFile.empty())
|
|
{
|
|
std::vector<int> config_hashes;
|
|
config_hashes.push_back(sconfig->value);
|
|
if(debug_shader_build) config_hashes.push_back(1337);
|
|
|
|
std::vector<const ShaderDefineVector *> fullDefs;
|
|
fullDefs.push_back(&sconfig->commonShader.defines);
|
|
fullDefs.push_back(&sconfig->geometryShader.defines);
|
|
std::vector<D3D_SHADER_MACRO> defs;
|
|
createDefineMacro(fullDefs,defs);
|
|
|
|
|
|
geometryShader = g_shaderManager.AddGeometryShader(pd3dDevice, sconfig->geometryShader.sourceFile.c_str(), sconfig->geometryShader.entry.c_str(), sconfig->geometryShader.target.c_str(),
|
|
&pBlob, &defs[0], dwShaderFlags, config_hashes);
|
|
|
|
assert(geometryShader->Get());
|
|
SAFE_RELEASE(pBlob);
|
|
}
|
|
|
|
Shader<ID3D11PixelShader> *pixelShader = NULL;
|
|
if (! sconfig->pixelShader.sourceFile.empty())
|
|
{
|
|
std::vector<int> config_hashes;
|
|
config_hashes.push_back(sconfig->value);
|
|
if(debug_shader_build) config_hashes.push_back(1337);
|
|
|
|
|
|
std::vector<const ShaderDefineVector *> fullDefs;
|
|
fullDefs.push_back(&sconfig->commonShader.defines);
|
|
fullDefs.push_back(&sconfig->pixelShader.defines);
|
|
std::vector<D3D_SHADER_MACRO> defs;
|
|
createDefineMacro(fullDefs,defs);
|
|
|
|
pixelShader = g_shaderManager.AddPixelShader(pd3dDevice, sconfig->pixelShader.sourceFile.c_str(), sconfig->pixelShader.entry.c_str(), sconfig->pixelShader.target.c_str(),
|
|
&pBlob, &defs[0], dwShaderFlags, config_hashes);
|
|
|
|
assert(pixelShader);
|
|
SAFE_RELEASE(pBlob);
|
|
}
|
|
|
|
Shader<ID3D11ComputeShader> *computeShader = NULL;
|
|
if (! sconfig->computeShader.sourceFile.empty())
|
|
{
|
|
std::vector<int> config_hashes;
|
|
config_hashes.push_back(sconfig->value);
|
|
if(debug_shader_build) config_hashes.push_back(1337);
|
|
|
|
|
|
std::vector<const ShaderDefineVector *> fullDefs;
|
|
fullDefs.push_back(&sconfig->commonShader.defines);
|
|
fullDefs.push_back(&sconfig->computeShader.defines);
|
|
std::vector<D3D_SHADER_MACRO> defs;
|
|
createDefineMacro(fullDefs,defs);
|
|
|
|
computeShader = g_shaderManager.AddComputeShader(pd3dDevice, sconfig->computeShader.sourceFile.c_str(), sconfig->computeShader.entry.c_str(), sconfig->computeShader.target.c_str(),
|
|
&pBlob, &defs[0], dwShaderFlags, config_hashes);
|
|
|
|
assert(computeShader);
|
|
SAFE_RELEASE(pBlob);
|
|
}
|
|
|
|
DrawConfig * config = _NewDrawConfig();
|
|
config->srcConfig = const_cast<DrawSourceConfig*>(sconfig);
|
|
config->vertexShader = vertexShader;
|
|
config->hullShader = hullShader;
|
|
config->domainShader = domainShader;
|
|
config->geometryShader = geometryShader;
|
|
config->pixelShader = pixelShader;
|
|
config->computeShader = computeShader;
|
|
|
|
return config;
|
|
|
|
}
|