660 lines
19 KiB
C++
660 lines
19 KiB
C++
// Copyright (C) 2013 Jérôme Leclercq
|
|
// This file is part of the "Nazara Engine - Renderer module"
|
|
// For conditions of distribution and use, see copyright notice in Config.hpp
|
|
|
|
#include <Nazara/Core/Log.hpp>
|
|
#include <Nazara/Core/Clock.hpp>
|
|
#include <Nazara/Core/Directory.hpp>
|
|
#include <Nazara/Core/File.hpp>
|
|
#include <Nazara/Renderer/OpenGL.hpp>
|
|
#include <Nazara/Renderer/ShaderProgramManager.hpp>
|
|
#include <cstring>
|
|
#include <memory>
|
|
#include <unordered_map>
|
|
#include <Nazara/Graphics/Debug.hpp>
|
|
|
|
namespace
|
|
{
|
|
struct ParamsHash
|
|
{
|
|
std::size_t operator()(const NzShaderProgramManagerParams& params) const
|
|
{
|
|
static_assert(nzShaderTarget_Max < 0x4, "Maximum shader target takes more than 2 bits");
|
|
|
|
std::size_t h = (params.target << 0) | // 2 bits
|
|
(params.flags << 2); // 8 bits
|
|
|
|
switch (params.target)
|
|
{
|
|
case nzShaderTarget_FullscreenQuad:
|
|
h |= (params.fullscreenQuad.alphaMapping << 10) | // 1 bit
|
|
(params.fullscreenQuad.alphaTest << 11) | // 1 bit
|
|
(params.fullscreenQuad.diffuseMapping << 12); // 1 bit
|
|
break;
|
|
|
|
case nzShaderTarget_Model:
|
|
h |= (params.model.alphaMapping << 10) | // 1 bit
|
|
(params.model.alphaTest << 11) | // 1 bit
|
|
(params.model.diffuseMapping << 12) | // 1 bit
|
|
(params.model.emissiveMapping << 13) | // 1 bit
|
|
(params.model.lighting << 14) | // 1 bit
|
|
(params.model.normalMapping << 15) | // 1 bit
|
|
(params.model.parallaxMapping << 16) | // 1 bit
|
|
(params.model.specularMapping << 17); // 1 bit
|
|
break;
|
|
|
|
case nzShaderTarget_None:
|
|
break;
|
|
|
|
case nzShaderTarget_Sprite:
|
|
h |= (params.sprite.alphaMapping << 10) | // 1 bit
|
|
(params.sprite.alphaTest << 11) | // 1 bit
|
|
(params.sprite.diffuseMapping << 12); // 1 bit
|
|
break;
|
|
}
|
|
|
|
return h;
|
|
}
|
|
};
|
|
|
|
struct ParamsEquality
|
|
{
|
|
bool operator()(const NzShaderProgramManagerParams& first, const NzShaderProgramManagerParams& second) const
|
|
{
|
|
if (first.target != second.target || first.flags != second.flags)
|
|
return false;
|
|
|
|
switch (first.target)
|
|
{
|
|
case nzShaderTarget_FullscreenQuad:
|
|
return std::memcmp(&first.fullscreenQuad, &second.fullscreenQuad, sizeof(NzShaderProgramManagerParams::FullscreenQuad)) == 0;
|
|
|
|
case nzShaderTarget_Model:
|
|
return std::memcmp(&first.model, &second.model, sizeof(NzShaderProgramManagerParams::Model)) == 0;
|
|
|
|
case nzShaderTarget_None:
|
|
return true;
|
|
|
|
case nzShaderTarget_Sprite:
|
|
return std::memcmp(&first.sprite, &second.sprite, sizeof(NzShaderProgramManagerParams::Sprite)) == 0;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
};
|
|
|
|
std::unordered_map<NzShaderProgramManagerParams, NzShaderProgramRef, ParamsHash, ParamsEquality> s_programs;
|
|
NzString s_cacheDirectory("shaderCache");
|
|
bool s_cacheEnabled = false;
|
|
bool s_earlyFragmentTest;
|
|
bool s_glsl140;
|
|
//bool s_loadCachedPrograms = true;
|
|
unsigned int s_glslVersion;
|
|
}
|
|
|
|
const NzShaderProgram* NzShaderProgramManager::Get(const NzShaderProgramManagerParams& params)
|
|
{
|
|
auto it = s_programs.find(params);
|
|
if (it == s_programs.end())
|
|
{
|
|
// Alors nous générons le programme
|
|
std::unique_ptr<NzShaderProgram> program;
|
|
|
|
if (s_cacheEnabled)
|
|
{
|
|
NzString programFileName = NzNumberToString(ParamsHash()(params), 36) + ".nsb"; // Nazara Shader Binary, très original, je sais
|
|
NazaraDebug("Checking cache for program file \"" + programFileName + "\"...");
|
|
|
|
NzFile shaderFile(s_cacheDirectory + NAZARA_DIRECTORY_SEPARATOR + programFileName);
|
|
if (shaderFile.Open(NzFile::ReadOnly))
|
|
{
|
|
NazaraDebug("File found");
|
|
|
|
unsigned int size = shaderFile.GetSize();
|
|
|
|
NzByteArray binary;
|
|
binary.Resize(size);
|
|
|
|
if (shaderFile.Read(&binary[0], size) != size)
|
|
{
|
|
NazaraError("Failed to read program binary");
|
|
return false;
|
|
}
|
|
|
|
shaderFile.Close();
|
|
|
|
program.reset(new NzShaderProgram);
|
|
if (!program->LoadFromBinary(binary))
|
|
{
|
|
NazaraWarning("Program \"" + programFileName + "\" loading failed, this is mostly due to a driver/video card "
|
|
"update or a file corruption, regenerating program...");
|
|
|
|
program.reset(GenerateProgram(params));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (shaderFile.Exists())
|
|
NazaraWarning("Program file exists but couldn't be opened");
|
|
|
|
program.reset(GenerateProgram(params));
|
|
if (program)
|
|
{
|
|
if (program->IsBinaryRetrievable())
|
|
{
|
|
NazaraDebug("Program \"" + programFileName + "\" (re)generated, saving it into program cache directory...");
|
|
|
|
NzByteArray programBinary = program->GetBinary();
|
|
if (!programBinary.IsEmpty())
|
|
{
|
|
if (!shaderFile.Open(NzFile::Truncate | NzFile::WriteOnly) || !shaderFile.Write(programBinary))
|
|
NazaraWarning("Failed to save program binary to file \"" + programFileName + "\": " + NzGetLastSystemError());
|
|
}
|
|
else
|
|
NazaraWarning("Failed to retrieve shader program binary");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
program.reset(GenerateProgram(params));
|
|
|
|
if (program)
|
|
s_programs[params] = program.get();
|
|
else
|
|
{
|
|
NazaraWarning("Failed to build program, using default one...");
|
|
|
|
NzShaderProgramManagerParams defaultParams;
|
|
defaultParams.flags = params.flags;
|
|
defaultParams.target = nzShaderTarget_None;
|
|
|
|
program.reset(s_programs[defaultParams]); // Shader par défaut
|
|
}
|
|
|
|
return program.release();
|
|
}
|
|
else
|
|
return it->second;
|
|
}
|
|
|
|
NzString NzShaderProgramManager::BuildFragmentCode(const NzShaderProgramManagerParams& params)
|
|
{
|
|
#ifdef NAZARA_DEBUG
|
|
if (params.target > nzShaderTarget_Max)
|
|
{
|
|
NazaraError("Shader target out of enum");
|
|
return NzString();
|
|
}
|
|
#endif
|
|
|
|
NzString source;
|
|
|
|
/********************Header********************/
|
|
source.Reserve(14 + 24 + 24 + 26 + 1);
|
|
source += "#version ";
|
|
source += NzString::Number(s_glslVersion);
|
|
source += "\n\n";
|
|
|
|
source += "#define FLAG_DEFERRED ";
|
|
source += (params.flags & nzShaderFlags_Deferred) ? '1' : '0';
|
|
source += '\n';
|
|
|
|
source += "#define FLAG_FLIP_UVS ";
|
|
source += (params.flags & nzShaderFlags_FlipUVs) ? '1' : '0';
|
|
source += '\n';
|
|
|
|
source += "#define FLAG_INSTANCING ";
|
|
source += (params.flags & nzShaderFlags_Instancing) ? '1' : '0';
|
|
source += '\n';
|
|
|
|
source += '\n';
|
|
|
|
switch (params.target)
|
|
{
|
|
case nzShaderTarget_FullscreenQuad:
|
|
{
|
|
char coreFragmentShader[] = {
|
|
#include <Nazara/Renderer/Shaders/FullscreenQuad/core.frag.h>
|
|
};
|
|
|
|
char compatibilityFragmentShader[] = {
|
|
#include <Nazara/Renderer/Shaders/FullscreenQuad/compatibility.frag.h>
|
|
};
|
|
|
|
const char* shaderSource = (s_glsl140) ? coreFragmentShader : compatibilityFragmentShader;
|
|
unsigned int shaderSourceSize = (s_glsl140) ? sizeof(coreFragmentShader) : sizeof(compatibilityFragmentShader);
|
|
|
|
|
|
source.Reserve(source.GetCapacity() + 34 + 24 + 21 + 26 + 1 + shaderSourceSize);
|
|
|
|
// "discard" ne s'entend pas bien avec les early fragment tests
|
|
if (s_earlyFragmentTest && !params.fullscreenQuad.alphaMapping)
|
|
source += "layout(early_fragment_tests) in;\n\n";
|
|
|
|
source += "#define ALPHA_MAPPING ";
|
|
source += (params.fullscreenQuad.alphaMapping) ? '1' : '0';
|
|
source += '\n';
|
|
|
|
source += "#define ALPHA_TEST ";
|
|
source += (params.fullscreenQuad.alphaTest) ? '1' : '0';
|
|
source += '\n';
|
|
|
|
source += "#define DIFFUSE_MAPPING ";
|
|
source += (params.fullscreenQuad.diffuseMapping) ? '1' : '0';
|
|
source += '\n';
|
|
|
|
source += '\n';
|
|
|
|
source.Append(shaderSource, shaderSourceSize);
|
|
break;
|
|
}
|
|
|
|
case nzShaderTarget_Model:
|
|
{
|
|
char coreFragmentShader[] = {
|
|
#include <Nazara/Renderer/Shaders/Model/core.frag.h>
|
|
};
|
|
|
|
char compatibilityFragmentShader[] = {
|
|
#include <Nazara/Renderer/Shaders/Model/compatibility.frag.h>
|
|
};
|
|
|
|
const char* shaderSource = (s_glsl140) ? coreFragmentShader : compatibilityFragmentShader;
|
|
unsigned int shaderSourceSize = (s_glsl140) ? sizeof(coreFragmentShader) : sizeof(compatibilityFragmentShader);
|
|
|
|
source.Reserve(source.GetCapacity() + 34 + 24 + 21 + 26 + 27 + 19 + 25 + 27 + 27 + 1 + shaderSourceSize);
|
|
|
|
if (s_earlyFragmentTest && !params.model.alphaMapping)
|
|
source += "layout(early_fragment_tests) in;\n\n";
|
|
|
|
source += "#define ALPHA_MAPPING ";
|
|
source += (params.model.alphaMapping) ? '1' : '0';
|
|
source += '\n';
|
|
|
|
source += "#define ALPHA_TEST ";
|
|
source += (params.model.alphaTest) ? '1' : '0';
|
|
source += '\n';
|
|
|
|
source += "#define DIFFUSE_MAPPING ";
|
|
source += (params.model.diffuseMapping) ? '1' : '0';
|
|
source += '\n';
|
|
|
|
source += "#define EMISSIVE_MAPPING ";
|
|
source += (params.model.emissiveMapping) ? '1' : '0';
|
|
source += '\n';
|
|
|
|
source += "#define LIGHTING ";
|
|
source += (params.model.lighting) ? '1' : '0';
|
|
source += '\n';
|
|
|
|
source += "#define NORMAL_MAPPING ";
|
|
source += (params.model.normalMapping) ? '1' : '0';
|
|
source += '\n';
|
|
|
|
source += "#define PARALLAX_MAPPING ";
|
|
source += (params.model.parallaxMapping) ? '1' : '0';
|
|
source += '\n';
|
|
|
|
source += "#define SPECULAR_MAPPING ";
|
|
source += (params.model.specularMapping) ? '1' : '0';
|
|
source += '\n';
|
|
|
|
source += '\n';
|
|
|
|
source.Append(shaderSource, shaderSourceSize);
|
|
break;
|
|
}
|
|
|
|
case nzShaderTarget_None:
|
|
{
|
|
char coreFragmentShader[] = {
|
|
#include <Nazara/Renderer/Shaders/None/core.frag.h>
|
|
};
|
|
|
|
char compatibilityFragmentShader[] = {
|
|
#include <Nazara/Renderer/Shaders/None/compatibility.frag.h>
|
|
};
|
|
|
|
const char* shaderSource = (s_glsl140) ? coreFragmentShader : compatibilityFragmentShader;
|
|
unsigned int shaderSourceSize = (s_glsl140) ? sizeof(coreFragmentShader) : sizeof(compatibilityFragmentShader);
|
|
|
|
source.Reserve(source.GetCapacity() + 34 + shaderSourceSize);
|
|
|
|
if (s_earlyFragmentTest)
|
|
source += "layout(early_fragment_tests) in;\n\n";
|
|
|
|
source.Append(shaderSource, shaderSourceSize);
|
|
break;
|
|
}
|
|
|
|
case nzShaderTarget_Sprite:
|
|
{
|
|
char coreFragmentShader[] = {
|
|
#include <Nazara/Renderer/Shaders/Sprite/core.frag.h>
|
|
};
|
|
|
|
char compatibilityFragmentShader[] = {
|
|
#include <Nazara/Renderer/Shaders/Sprite/compatibility.frag.h>
|
|
};
|
|
|
|
const char* shaderSource = (s_glsl140) ? coreFragmentShader : compatibilityFragmentShader;
|
|
unsigned int shaderSourceSize = (s_glsl140) ? sizeof(coreFragmentShader) : sizeof(compatibilityFragmentShader);
|
|
|
|
source.Reserve(source.GetCapacity() + 34 + 24 + 21 + 26 + 1 + shaderSourceSize);
|
|
|
|
// "discard" ne s'entend pas bien avec les early fragment tests
|
|
if (s_earlyFragmentTest && !params.sprite.alphaMapping)
|
|
source += "layout(early_fragment_tests) in;\n\n";
|
|
|
|
source += "#define ALPHA_MAPPING ";
|
|
source += (params.sprite.alphaMapping) ? '1' : '0';
|
|
source += '\n';
|
|
|
|
source += "#define ALPHA_TEST ";
|
|
source += (params.sprite.alphaTest) ? '1' : '0';
|
|
source += '\n';
|
|
|
|
source += "#define DIFFUSE_MAPPING ";
|
|
source += (params.sprite.diffuseMapping) ? '1' : '0';
|
|
source += '\n';
|
|
|
|
source += '\n';
|
|
|
|
source.Append(shaderSource, shaderSourceSize);
|
|
break;
|
|
}
|
|
}
|
|
|
|
return source;
|
|
}
|
|
|
|
NzString NzShaderProgramManager::BuildVertexCode(const NzShaderProgramManagerParams& params)
|
|
{
|
|
#ifdef NAZARA_DEBUG
|
|
if (params.target > nzShaderTarget_Max)
|
|
{
|
|
NazaraError("Shader target out of enum");
|
|
return NzString();
|
|
}
|
|
#endif
|
|
|
|
NzString source;
|
|
|
|
/********************Header********************/
|
|
source.Reserve(14 + 24 + 24 + 26 + 1);
|
|
source += "#version ";
|
|
source += NzString::Number(s_glslVersion);
|
|
source += "\n\n";
|
|
|
|
source += "#define FLAG_DEFERRED ";
|
|
source += (params.flags & nzShaderFlags_Deferred) ? '1' : '0';
|
|
source += '\n';
|
|
|
|
source += "#define FLAG_FLIP_UVS ";
|
|
source += (params.flags & nzShaderFlags_FlipUVs) ? '1' : '0';
|
|
source += '\n';
|
|
|
|
source += "#define FLAG_INSTANCING ";
|
|
source += (params.flags & nzShaderFlags_Instancing) ? '1' : '0';
|
|
source += '\n';
|
|
|
|
source += '\n';
|
|
|
|
switch (params.target)
|
|
{
|
|
case nzShaderTarget_FullscreenQuad:
|
|
{
|
|
char coreVertexShader[] = {
|
|
#include <Nazara/Renderer/Shaders/FullscreenQuad/core.vert.h>
|
|
};
|
|
|
|
char compatibilityVertexShader[] = {
|
|
#include <Nazara/Renderer/Shaders/FullscreenQuad/compatibility.vert.h>
|
|
};
|
|
|
|
const char* shaderSource = (s_glsl140) ? coreVertexShader : compatibilityVertexShader;
|
|
unsigned int shaderSourceSize = (s_glsl140) ? sizeof(coreVertexShader) : sizeof(compatibilityVertexShader);
|
|
|
|
source.Reserve(source.GetCapacity() + 24 + 21 + 26 + 1 + shaderSourceSize);
|
|
|
|
source += "#define ALPHA_MAPPING ";
|
|
source += (params.fullscreenQuad.alphaMapping) ? '1' : '0';
|
|
source += '\n';
|
|
|
|
source += "#define ALPHA_TEST ";
|
|
source += (params.fullscreenQuad.alphaTest) ? '1' : '0';
|
|
source += '\n';
|
|
|
|
source += "#define DIFFUSE_MAPPING ";
|
|
source += (params.fullscreenQuad.diffuseMapping) ? '1' : '0';
|
|
source += '\n';
|
|
|
|
source += '\n';
|
|
|
|
source.Append(shaderSource, shaderSourceSize);
|
|
break;
|
|
}
|
|
|
|
case nzShaderTarget_Model:
|
|
{
|
|
char coreVertexShader[] = {
|
|
#include <Nazara/Renderer/Shaders/Model/core.vert.h>
|
|
};
|
|
|
|
char compatibilityVertexShader[] = {
|
|
#include <Nazara/Renderer/Shaders/Model/compatibility.vert.h>
|
|
};
|
|
|
|
const char* shaderSource = (s_glsl140) ? coreVertexShader : compatibilityVertexShader;
|
|
unsigned int shaderSourceSize = (s_glsl140) ? sizeof(coreVertexShader) : sizeof(compatibilityVertexShader);
|
|
|
|
source.Reserve(source.GetCapacity() + 24 + 21 + 26 + 27 + 19 + 25 + 27 + 27 + 1 + shaderSourceSize);
|
|
|
|
source += "#define ALPHA_MAPPING ";
|
|
source += (params.model.alphaMapping) ? '1' : '0';
|
|
source += '\n';
|
|
|
|
source += "#define ALPHA_TEST ";
|
|
source += (params.model.alphaTest) ? '1' : '0';
|
|
source += '\n';
|
|
|
|
source += "#define DIFFUSE_MAPPING ";
|
|
source += (params.model.diffuseMapping) ? '1' : '0';
|
|
source += '\n';
|
|
|
|
source += "#define EMISSIVE_MAPPING ";
|
|
source += (params.model.emissiveMapping) ? '1' : '0';
|
|
source += '\n';
|
|
|
|
source += "#define LIGHTING ";
|
|
source += (params.model.lighting) ? '1' : '0';
|
|
source += '\n';
|
|
|
|
source += "#define NORMAL_MAPPING ";
|
|
source += (params.model.normalMapping) ? '1' : '0';
|
|
source += '\n';
|
|
|
|
source += "#define PARALLAX_MAPPING ";
|
|
source += (params.model.parallaxMapping) ? '1' : '0';
|
|
source += '\n';
|
|
|
|
source += "#define SPECULAR_MAPPING ";
|
|
source += (params.model.specularMapping) ? '1' : '0';
|
|
source += '\n';
|
|
|
|
source += '\n';
|
|
|
|
source.Append(shaderSource, shaderSourceSize);
|
|
break;
|
|
}
|
|
|
|
case nzShaderTarget_None:
|
|
{
|
|
char coreVertexShader[] = {
|
|
#include <Nazara/Renderer/Shaders/None/core.vert.h>
|
|
};
|
|
|
|
char compatibilityVertexShader[] = {
|
|
#include <Nazara/Renderer/Shaders/None/compatibility.vert.h>
|
|
};
|
|
|
|
const char* shaderSource = (s_glsl140) ? coreVertexShader : compatibilityVertexShader;
|
|
unsigned int shaderSourceSize = (s_glsl140) ? sizeof(coreVertexShader) : sizeof(compatibilityVertexShader);
|
|
|
|
source.Append(shaderSource, shaderSourceSize);
|
|
break;
|
|
}
|
|
|
|
case nzShaderTarget_Sprite:
|
|
{
|
|
char coreVertexShader[] = {
|
|
#include <Nazara/Renderer/Shaders/Sprite/core.vert.h>
|
|
};
|
|
|
|
char compatibilityVertexShader[] = {
|
|
#include <Nazara/Renderer/Shaders/Sprite/compatibility.vert.h>
|
|
};
|
|
|
|
const char* shaderSource = (s_glsl140) ? coreVertexShader : compatibilityVertexShader;
|
|
unsigned int shaderSourceSize = (s_glsl140) ? sizeof(coreVertexShader) : sizeof(compatibilityVertexShader);
|
|
|
|
source.Reserve(source.GetCapacity() + 24 + 21 + 26 + 1 + shaderSourceSize);
|
|
|
|
source += "#define ALPHA_MAPPING ";
|
|
source += (params.fullscreenQuad.alphaMapping) ? '1' : '0';
|
|
source += '\n';
|
|
|
|
source += "#define ALPHA_TEST ";
|
|
source += (params.fullscreenQuad.alphaTest) ? '1' : '0';
|
|
source += '\n';
|
|
|
|
source += "#define DIFFUSE_MAPPING ";
|
|
source += (params.fullscreenQuad.diffuseMapping) ? '1' : '0';
|
|
source += '\n';
|
|
|
|
source += '\n';
|
|
|
|
source.Append(shaderSource, shaderSourceSize);
|
|
break;
|
|
}
|
|
}
|
|
|
|
return source;
|
|
}
|
|
|
|
NzShaderProgram* NzShaderProgramManager::GenerateProgram(const NzShaderProgramManagerParams& params)
|
|
{
|
|
std::unique_ptr<NzShaderProgram> program(new NzShaderProgram);
|
|
program->SetPersistent(false);
|
|
|
|
if (!program->Create(nzShaderLanguage_GLSL))
|
|
{
|
|
NazaraError("Failed to create program");
|
|
return nullptr;
|
|
}
|
|
|
|
NzString fragmentSource = BuildFragmentCode(params);
|
|
if (!program->LoadShader(nzShaderType_Fragment, fragmentSource))
|
|
{
|
|
NazaraError("Failed to load fragment shader: " + program->GetLog());
|
|
NazaraNotice("Source:\n" + fragmentSource);
|
|
return nullptr;
|
|
}
|
|
|
|
NzString vertexSource = BuildVertexCode(params);
|
|
if (!program->LoadShader(nzShaderType_Vertex, vertexSource))
|
|
{
|
|
NazaraError("Failed to load vertex shader: " + program->GetLog());
|
|
NazaraNotice("Source:\n" + vertexSource);
|
|
return nullptr;
|
|
}
|
|
|
|
if (!program->Compile())
|
|
{
|
|
NazaraError("Failed to compile program: " + program->GetLog());
|
|
return nullptr;
|
|
}
|
|
|
|
return program.release();
|
|
}
|
|
|
|
bool NzShaderProgramManager::Initialize()
|
|
{
|
|
s_glslVersion = NzOpenGL::GetGLSLVersion();
|
|
s_earlyFragmentTest = (s_glslVersion >= 420 || NzOpenGL::IsSupported(nzOpenGLExtension_Shader_ImageLoadStore));
|
|
s_glsl140 = (s_glslVersion >= 140);
|
|
|
|
NzShaderProgramManagerParams params;
|
|
params.target = nzShaderTarget_None;
|
|
for (unsigned int i = 0; i <= nzShaderFlags_Max; ++i)
|
|
{
|
|
params.flags = i;
|
|
|
|
NzShaderProgram* program = GenerateProgram(params);
|
|
if (!program)
|
|
{
|
|
NazaraError("Failed to generate default program (flags: 0x" + NzString::Number(i, 16) + ')');
|
|
Uninitialize();
|
|
return false;
|
|
}
|
|
|
|
s_programs[params] = program;
|
|
}
|
|
|
|
/*if (s_loadCachedPrograms)
|
|
{
|
|
NzDirectory cacheDirectory(s_cacheDirectory);
|
|
cacheDirectory.SetPattern("*.nsb");
|
|
|
|
if (cacheDirectory.Open())
|
|
{
|
|
while (cacheDirectory.NextResult(true))
|
|
{
|
|
long long hash;
|
|
if (cacheDirectory.GetResultName().SubStringTo(".nsb", -1, true, false).ToInteger(&hash, 32))
|
|
{
|
|
std::size_t hashCode = static_cast<std::size_t>(hash);
|
|
|
|
if (s_programs.find(hashCode) == s_programs.end())
|
|
{
|
|
NzFile shaderFile(cacheDirectory.GetResultPath());
|
|
if (shaderFile.Open(NzFile::ReadOnly))
|
|
{
|
|
unsigned int size = cacheDirectory.GetResultSize();
|
|
|
|
NzByteArray binary;
|
|
binary.Resize(size);
|
|
|
|
if (shaderFile.Read(&binary[0], size) != size)
|
|
{
|
|
NazaraError("Failed to read program binary");
|
|
return false;
|
|
}
|
|
|
|
shaderFile.Close();
|
|
|
|
std::unique_ptr<NzShaderProgram> program(new NzShaderProgram);
|
|
if (program->LoadFromBinary(binary))
|
|
s_programs[hashCode] = binary.release();
|
|
else
|
|
NazaraWarning("Program binary \"" + cacheDirectory.GetResultName() + "\" loading failed, this is mostly due to a driver/video card "
|
|
"update or a file corruption, regenerating program..."); }
|
|
}
|
|
}
|
|
else
|
|
NazaraWarning("Failed to parse program file name (" + cacheDirectory.GetResultName() + ')');
|
|
}
|
|
}
|
|
else if (cacheDirectory.Exists())
|
|
NazaraWarning("Failed to open shader cache directory");
|
|
}*/
|
|
|
|
return true;
|
|
}
|
|
|
|
void NzShaderProgramManager::Uninitialize()
|
|
{
|
|
s_programs.clear();
|
|
}
|