Added ShaderProgram::LoadFromBinary

Former-commit-id: fdc6b06173954bb9c382ed73e7cd9bb0c5fd01a5
This commit is contained in:
Lynix 2013-08-03 17:14:10 +02:00
parent ae53b01ca1
commit 059ea21b41
5 changed files with 165 additions and 72 deletions

View File

@ -58,6 +58,8 @@ class NAZARA_API NzShaderProgram : public NzResource, NzNonCopyable
bool IsLoaded(nzShaderType type) const;
bool IsValid() const;
bool LoadFromBinary(const void* buffer, unsigned int size);
bool LoadFromBinary(const NzByteArray& byteArray);
bool LoadShader(nzShaderType type, const NzString& source);
bool LoadShaderFromFile(nzShaderType type, const NzString& source);

View File

@ -35,6 +35,7 @@ class NzAbstractShaderProgram
virtual bool IsBinaryRetrievable() const = 0;
virtual bool IsLoaded(nzShaderType type) const = 0;
virtual bool LoadFromBinary(const void* buffer, unsigned int size) = 0;
virtual bool LoadShader(nzShaderType type, const NzString& source) = 0;
virtual bool SendBoolean(int location, bool value) = 0;

View File

@ -48,72 +48,11 @@ bool NzGLSLProgram::Compile()
{
NzContext::EnsureContext();
m_idCache.clear();
m_textures.clear();
if (NzOpenGL::IsSupported(nzOpenGLExtension_GetProgramBinary))
glProgramParameteri(m_program, GL_PROGRAM_BINARY_RETRIEVABLE_HINT, GL_TRUE);
PreLinkage();
glLinkProgram(m_program);
GLint success;
glGetProgramiv(m_program, GL_LINK_STATUS, &success);
if (success == GL_TRUE)
{
static NzString successStr("Linkage successful");
m_log = successStr;
// Pour éviter de se tromper entre le nom et la constante
#define CacheUniform(name) m_uniformLocations[nzShaderUniform_##name] = GetUniformLocation(#name)
CacheUniform(CameraPosition);
CacheUniform(InvTargetSize);
CacheUniform(MaterialAlphaMap);
CacheUniform(MaterialAlphaThreshold);
CacheUniform(MaterialAmbient);
CacheUniform(MaterialDiffuse);
CacheUniform(MaterialDiffuseMap);
CacheUniform(MaterialEmissiveMap);
CacheUniform(MaterialHeightMap);
CacheUniform(MaterialNormalMap);
CacheUniform(MaterialShininess);
CacheUniform(MaterialSpecular);
CacheUniform(MaterialSpecularMap);
CacheUniform(ProjMatrix);
CacheUniform(SceneAmbient);
CacheUniform(TargetSize);
CacheUniform(ViewMatrix);
CacheUniform(ViewProjMatrix);
CacheUniform(WorldMatrix);
CacheUniform(WorldViewMatrix);
CacheUniform(WorldViewProjMatrix);
#undef CacheUniform
return true;
}
else
{
// On remplit le log avec l'erreur de compilation
GLint length = 0;
glGetProgramiv(m_program, GL_INFO_LOG_LENGTH, &length);
if (length > 1)
{
m_log.Clear(true);
m_log.Reserve(length+15-2); // La taille retournée est celle du buffer (Avec caractère de fin)
m_log.Prepend("Linkage error: ");
m_log.Resize(length+15-2); // Extension du buffer d'écriture pour ajouter le log
glGetProgramInfoLog(m_program, length-1, nullptr, &m_log[19]);
}
else
m_log = "Linkage failed but no info log found";
NazaraError(m_log);
return false;
}
return PostLinkage();
}
bool NzGLSLProgram::Create()
@ -160,6 +99,9 @@ bool NzGLSLProgram::Create()
for (int i = 0; i <= nzShaderType_Max; ++i)
m_shaders[i] = 0;
if (NzOpenGL::IsSupported(nzOpenGLExtension_GetProgramBinary))
glProgramParameteri(m_program, GL_PROGRAM_BINARY_RETRIEVABLE_HINT, GL_TRUE);
return true;
}
@ -179,21 +121,20 @@ NzByteArray NzGLSLProgram::GetBinary() const
NzContext::EnsureContext();
GLint binaryLength;
GLint binaryLength = 0;
glGetProgramiv(m_program, GL_PROGRAM_BINARY_LENGTH, &binaryLength);
if (binaryLength > 0)
{
byteArray.Resize(sizeof(nzUInt64) + binaryLength);
nzUInt8* ptr = byteArray.GetBuffer();
nzUInt8* buffer = byteArray.GetBuffer();
GLenum binaryFormat;
glGetProgramBinary(m_program, binaryLength, nullptr, &binaryFormat, &ptr[sizeof(nzUInt64)]);
glGetProgramBinary(m_program, binaryLength, nullptr, &binaryFormat, &buffer[sizeof(nzUInt64)]);
// On stocke le format au début du binaire
nzUInt64* format = reinterpret_cast<nzUInt64*>(&ptr[0]);
*format = binaryFormat;
*reinterpret_cast<nzUInt64*>(&buffer[0]) = binaryFormat;
}
return byteArray;
@ -211,11 +152,11 @@ nzShaderLanguage NzGLSLProgram::GetLanguage() const
NzString NzGLSLProgram::GetSourceCode(nzShaderType type) const
{
NzString source;
NzContext::EnsureContext();
GLint length;
NzString source;
GLint length = 0;
glGetShaderiv(m_shaders[type], GL_SHADER_SOURCE_LENGTH, &length);
if (length > 1)
{
@ -258,6 +199,32 @@ bool NzGLSLProgram::IsLoaded(nzShaderType type) const
return m_shaders[type] != 0;
}
bool NzGLSLProgram::LoadFromBinary(const void* buffer, unsigned int size)
{
#if NAZARA_RENDERER_SAFE
if (!glProgramBinary)
{
NazaraError("GL_ARB_get_program_binary not supported");
return false;
}
#endif
NzContext::EnsureContext();
const nzUInt8* ptr = reinterpret_cast<const nzUInt8*>(buffer);
// On récupère le format au début du binaire
///TODO: ByteStream ?
GLenum binaryFormat = static_cast<GLenum>(*reinterpret_cast<const nzUInt64*>(&ptr[0]));
ptr += sizeof(nzUInt64);
PreLinkage();
glProgramBinary(m_program, binaryFormat, ptr, size-sizeof(nzUInt64));
return PostLinkage();
}
bool NzGLSLProgram::LoadShader(nzShaderType type, const NzString& source)
{
NzContext::EnsureContext();
@ -615,3 +582,72 @@ void NzGLSLProgram::OnResourceReleased(const NzResource* resource, int index)
resource->RemoveResourceListener(this);
}
void NzGLSLProgram::PreLinkage()
{
m_idCache.clear();
m_textures.clear();
}
bool NzGLSLProgram::PostLinkage()
{
// On suppose qu'un contexte OpenGL est actif à l'appel de cette fonction
GLint success;
glGetProgramiv(m_program, GL_LINK_STATUS, &success);
if (success == GL_TRUE)
{
static NzString successStr("Linkage successful");
m_log = successStr;
// Pour éviter de se tromper entre le nom et la constante
#define CacheUniform(name) m_uniformLocations[nzShaderUniform_##name] = GetUniformLocation(#name)
CacheUniform(CameraPosition);
CacheUniform(InvTargetSize);
CacheUniform(MaterialAlphaMap);
CacheUniform(MaterialAlphaThreshold);
CacheUniform(MaterialAmbient);
CacheUniform(MaterialDiffuse);
CacheUniform(MaterialDiffuseMap);
CacheUniform(MaterialEmissiveMap);
CacheUniform(MaterialHeightMap);
CacheUniform(MaterialNormalMap);
CacheUniform(MaterialShininess);
CacheUniform(MaterialSpecular);
CacheUniform(MaterialSpecularMap);
CacheUniform(ProjMatrix);
CacheUniform(SceneAmbient);
CacheUniform(TargetSize);
CacheUniform(ViewMatrix);
CacheUniform(ViewProjMatrix);
CacheUniform(WorldMatrix);
CacheUniform(WorldViewMatrix);
CacheUniform(WorldViewProjMatrix);
#undef CacheUniform
return true;
}
else
{
// On remplit le log avec l'erreur de compilation
GLint length = 0;
glGetProgramiv(m_program, GL_INFO_LOG_LENGTH, &length);
if (length > 1)
{
m_log.Clear(true);
m_log.Reserve(length+15-2); // La taille retournée est celle du buffer (Avec caractère de fin)
m_log.Prepend("Linkage error: ");
m_log.Resize(length+15-2); // Extension du buffer d'écriture pour ajouter le log
glGetProgramInfoLog(m_program, length-1, nullptr, &m_log[19]);
}
else
m_log = "Linkage failed but no info log found";
NazaraError(m_log);
return false;
}
}

View File

@ -41,6 +41,7 @@ class NzGLSLProgram : public NzAbstractShaderProgram, NzResourceListener
bool IsBinaryRetrievable() const;
bool IsLoaded(nzShaderType type) const;
bool LoadFromBinary(const void* buffer, unsigned int size);
bool LoadShader(nzShaderType type, const NzString& source);
bool SendBoolean(int location, bool value);
@ -62,6 +63,8 @@ class NzGLSLProgram : public NzAbstractShaderProgram, NzResourceListener
void OnResourceCreated(const NzResource* resource, int index) override;
void OnResourceDestroy(const NzResource* resource, int index) override;
void OnResourceReleased(const NzResource* resource, int index) override;
void PreLinkage();
bool PostLinkage();
struct TextureSlot
{

View File

@ -96,6 +96,8 @@ bool NzShaderProgram::Compile()
void NzShaderProgram::Destroy()
{
m_compiled = false;
if (m_impl)
{
NotifyDestroy();
@ -128,7 +130,19 @@ NzByteArray NzShaderProgram::GetBinary() const
}
#endif
return m_impl->GetBinary();
NzByteArray binary(m_impl->GetBinary());
if (binary.IsEmpty())
return NzByteArray();
NzByteArray byteArray;
///TODO: ByteStream
nzUInt32 language = static_cast<nzUInt32>(m_impl->GetLanguage());
byteArray.Append(&language, sizeof(nzUInt32));
byteArray.Append(binary);
return byteArray;
}
nzUInt32 NzShaderProgram::GetFlags() const
@ -286,6 +300,43 @@ bool NzShaderProgram::IsValid() const
return m_impl != nullptr;
}
bool NzShaderProgram::LoadFromBinary(const void* buffer, unsigned int size)
{
#if NAZARA_RENDERER_SAFE
if (size <= sizeof(nzUInt32))
{
NazaraError("Invalid binary");
return false;
}
#endif
///TODO: ByteStream
const nzUInt8* ptr = static_cast<const nzUInt8*>(buffer);
nzShaderLanguage language = static_cast<nzShaderLanguage>(*reinterpret_cast<const nzUInt32*>(&ptr[0]));
ptr += sizeof(nzUInt32);
if (!Create(language))
{
NazaraError("Failed to create shader");
return false;
}
if (m_impl->LoadFromBinary(ptr, size-sizeof(nzUInt32)))
{
m_compiled = true;
return true;
}
else
return false;
}
bool NzShaderProgram::LoadFromBinary(const NzByteArray& byteArray)
{
return LoadFromBinary(byteArray.GetConstBuffer(), byteArray.GetSize());
}
bool NzShaderProgram::LoadShader(nzShaderType type, const NzString& source)
{
#if NAZARA_RENDERER_SAFE