From 059ea21b41d82191976405e5f27e2fe71c465cc2 Mon Sep 17 00:00:00 2001 From: Lynix Date: Sat, 3 Aug 2013 17:14:10 +0200 Subject: [PATCH] Added ShaderProgram::LoadFromBinary Former-commit-id: fdc6b06173954bb9c382ed73e7cd9bb0c5fd01a5 --- include/Nazara/Renderer/ShaderProgram.hpp | 2 + src/Nazara/Renderer/AbstractShaderProgram.hpp | 1 + src/Nazara/Renderer/GLSLProgram.cpp | 178 +++++++++++------- src/Nazara/Renderer/GLSLProgram.hpp | 3 + src/Nazara/Renderer/ShaderProgram.cpp | 53 +++++- 5 files changed, 165 insertions(+), 72 deletions(-) diff --git a/include/Nazara/Renderer/ShaderProgram.hpp b/include/Nazara/Renderer/ShaderProgram.hpp index 828d4d4ea..49d99ab18 100644 --- a/include/Nazara/Renderer/ShaderProgram.hpp +++ b/include/Nazara/Renderer/ShaderProgram.hpp @@ -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); diff --git a/src/Nazara/Renderer/AbstractShaderProgram.hpp b/src/Nazara/Renderer/AbstractShaderProgram.hpp index af9008381..ae2135cbb 100644 --- a/src/Nazara/Renderer/AbstractShaderProgram.hpp +++ b/src/Nazara/Renderer/AbstractShaderProgram.hpp @@ -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; diff --git a/src/Nazara/Renderer/GLSLProgram.cpp b/src/Nazara/Renderer/GLSLProgram.cpp index 7990f8956..401489cb4 100644 --- a/src/Nazara/Renderer/GLSLProgram.cpp +++ b/src/Nazara/Renderer/GLSLProgram.cpp @@ -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(&ptr[0]); - *format = binaryFormat; + *reinterpret_cast(&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(buffer); + + // On récupère le format au début du binaire + ///TODO: ByteStream ? + GLenum binaryFormat = static_cast(*reinterpret_cast(&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; + } +} diff --git a/src/Nazara/Renderer/GLSLProgram.hpp b/src/Nazara/Renderer/GLSLProgram.hpp index 5de7dcf31..cc1c89040 100644 --- a/src/Nazara/Renderer/GLSLProgram.hpp +++ b/src/Nazara/Renderer/GLSLProgram.hpp @@ -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 { diff --git a/src/Nazara/Renderer/ShaderProgram.cpp b/src/Nazara/Renderer/ShaderProgram.cpp index 38e87c5f2..ba244a2f8 100644 --- a/src/Nazara/Renderer/ShaderProgram.cpp +++ b/src/Nazara/Renderer/ShaderProgram.cpp @@ -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(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(buffer); + + nzShaderLanguage language = static_cast(*reinterpret_cast(&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