From 555898a89aaf66835d0bc4d3820a35de59eba43c Mon Sep 17 00:00:00 2001 From: Pavel Rojtberg Date: Mon, 9 Sep 2019 01:33:53 +0200 Subject: [PATCH] GL3+: support loading SPIRV shaders --- .../Bites/src/OgreApplicationContextBase.cpp | 5 + .../GL3Plus/include/OgreGL3PlusRenderSystem.h | 1 + .../GL3Plus/include/OgreSPIRVShaderFactory.h | 66 ++++++++++ .../GL3Plus/src/GLSL/include/OgreGLSLShader.h | 2 +- .../GL3Plus/src/OgreGL3PlusRenderSystem.cpp | 27 +++- .../GL3Plus/src/OgreSPIRVShaderFactory.cpp | 122 ++++++++++++++++++ .../materials/programs/SPIRV/GrayScale.frag | 12 ++ .../Media/materials/programs/SPIRV/README.md | 12 ++ .../programs/SPIRV/StdQuad_Tex2a_vp.vert | 16 +++ .../Media/materials/programs/SPIRV/compile.sh | 3 + 10 files changed, 258 insertions(+), 8 deletions(-) create mode 100644 RenderSystems/GL3Plus/include/OgreSPIRVShaderFactory.h create mode 100644 RenderSystems/GL3Plus/src/OgreSPIRVShaderFactory.cpp create mode 100644 Samples/Media/materials/programs/SPIRV/GrayScale.frag create mode 100644 Samples/Media/materials/programs/SPIRV/README.md create mode 100644 Samples/Media/materials/programs/SPIRV/StdQuad_Tex2a_vp.vert create mode 100755 Samples/Media/materials/programs/SPIRV/compile.sh diff --git a/Components/Bites/src/OgreApplicationContextBase.cpp b/Components/Bites/src/OgreApplicationContextBase.cpp index f51b063e3a8..df1023ecefe 100644 --- a/Components/Bites/src/OgreApplicationContextBase.cpp +++ b/Components/Bites/src/OgreApplicationContextBase.cpp @@ -461,6 +461,11 @@ void ApplicationContextBase::locateResources() rgm.addResourceLocation(arch + "/materials/programs/HLSL", type, sec); } + if (Ogre::GpuProgramManager::getSingleton().isSyntaxSupported("spirv")) + { + rgm.addResourceLocation(arch + "/materials/programs/SPIRV", type, sec); + } + if(hasCgPlugin) rgm.addResourceLocation(arch + "/materials/programs/Cg", type, sec); if (use_HLSL_Cg_shared) diff --git a/RenderSystems/GL3Plus/include/OgreGL3PlusRenderSystem.h b/RenderSystems/GL3Plus/include/OgreGL3PlusRenderSystem.h index 7ee6ec63a7b..1feada94cd7 100644 --- a/RenderSystems/GL3Plus/include/OgreGL3PlusRenderSystem.h +++ b/RenderSystems/GL3Plus/include/OgreGL3PlusRenderSystem.h @@ -95,6 +95,7 @@ namespace Ogre { GpuProgramManager *mShaderManager; GLSLShaderFactory* mGLSLShaderFactory; + HighLevelGpuProgramFactory* mSPIRVShaderFactory; HardwareBufferManager* mHardwareBufferManager; /** These variables are used for caching RenderSystem state. diff --git a/RenderSystems/GL3Plus/include/OgreSPIRVShaderFactory.h b/RenderSystems/GL3Plus/include/OgreSPIRVShaderFactory.h new file mode 100644 index 00000000000..1b3f65eaceb --- /dev/null +++ b/RenderSystems/GL3Plus/include/OgreSPIRVShaderFactory.h @@ -0,0 +1,66 @@ +/* +----------------------------------------------------------------------------- +This source file is part of OGRE +(Object-oriented Graphics Rendering Engine) +For the latest info, see http://www.ogre3d.org/ + +Copyright (c) 2000-2014 Torus Knot Software Ltd + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +----------------------------------------------------------------------------- +*/ + +#ifndef __SPIRVGpuProgramManager_H__ +#define __SPIRVGpuProgramManager_H__ + +#include "OgreGL3PlusPrerequisites.h" +#include "OgreHighLevelGpuProgramManager.h" +#include "OgreGLSLShader.h" + +namespace Ogre { + +class _OgreGL3PlusExport SPIRVShader : public GLSLShader +{ +public: + SPIRVShader(ResourceManager* creator, const String& name, ResourceHandle handle, const String& group, bool isManual, + ManualResourceLoader* loader); + virtual ~SPIRVShader(); + + const String& getLanguage(void) const; +protected: + void loadFromSource(); +}; + +class _OgreGL3PlusExport SPIRVShaderFactory: public HighLevelGpuProgramFactory +{ +public: + SPIRVShaderFactory(); + ~SPIRVShaderFactory(); + /// Get the name of the language this factory creates shaders for. + const String& getLanguage(void) const; + /// Create an instance of GLSLProgram. + HighLevelGpuProgram* create(ResourceManager* creator, + const String& name, ResourceHandle handle, + const String& group, bool isManual, ManualResourceLoader* loader); + void destroy(HighLevelGpuProgram* prog); +}; + +} //namespace Ogre + +#endif //__GLGpuProgramManager_H__ diff --git a/RenderSystems/GL3Plus/src/GLSL/include/OgreGLSLShader.h b/RenderSystems/GL3Plus/src/GLSL/include/OgreGLSLShader.h index 444f314873f..49313cc8b79 100644 --- a/RenderSystems/GL3Plus/src/GLSL/include/OgreGLSLShader.h +++ b/RenderSystems/GL3Plus/src/GLSL/include/OgreGLSLShader.h @@ -107,7 +107,7 @@ namespace Ogre { // /// @copydoc Resource::loadImpl // void loadImpl(void) {} - private: + protected: /// GL handle for shader object. GLuint mGLShaderHandle; /// GL handle for program object the shader is bound to. diff --git a/RenderSystems/GL3Plus/src/OgreGL3PlusRenderSystem.cpp b/RenderSystems/GL3Plus/src/OgreGL3PlusRenderSystem.cpp index db42b9a91fb..fbc758f7f22 100644 --- a/RenderSystems/GL3Plus/src/OgreGL3PlusRenderSystem.cpp +++ b/RenderSystems/GL3Plus/src/OgreGL3PlusRenderSystem.cpp @@ -61,6 +61,8 @@ Copyright (c) 2000-2014 Torus Knot Software Ltd #include "OgreGL3PlusStateCacheManager.h" #include "OgreGLSLProgramCommon.h" #include "OgreGL3PlusFBOMultiRenderTarget.h" +#include "OgreSPIRVShaderFactory.h" + #if OGRE_PLATFORM == OGRE_PLATFORM_APPLE extern "C" void glFlushRenderAPPLE(); @@ -135,6 +137,7 @@ namespace Ogre { mStateCacheManager(0), mShaderManager(0), mGLSLShaderFactory(0), + mSPIRVShaderFactory(0), mHardwareBufferManager(0), mActiveTextureUnit(0) { @@ -345,6 +348,8 @@ namespace Ogre { if (getNativeShadingLanguageVersion() >= 130 && !limitedOSXCoreProfile) rsc->addShaderProfile("glsl130"); + if(checkExtension("GL_ARB_gl_spirv")) rsc->addShaderProfile("spirv"); + if (hasMinGLVersion(4, 1) || checkExtension("GL_ARB_separate_shader_objects")) { // this relaxes shader matching rules and requires slightly different GLSL declaration // however our usage pattern does not benefit from this and driver support is quite poor @@ -489,6 +494,8 @@ namespace Ogre { // Create GLSL shader factory mGLSLShaderFactory = new GLSLShaderFactory(this); HighLevelGpuProgramManager::getSingleton().addFactory(mGLSLShaderFactory); + mSPIRVShaderFactory = new SPIRVShaderFactory(); + HighLevelGpuProgramManager::getSingleton().addFactory(mSPIRVShaderFactory); // Use VBO's by default mHardwareBufferManager = new GL3PlusHardwareBufferManager(); @@ -515,16 +522,22 @@ namespace Ogre { { RenderSystem::shutdown(); - // Deleting the GLSL program factory - if (mGLSLShaderFactory) + // Remove from manager safely + if (auto progMgr = HighLevelGpuProgramManager::getSingletonPtr()) { - // Remove from manager safely - if (HighLevelGpuProgramManager::getSingletonPtr()) - HighLevelGpuProgramManager::getSingleton().removeFactory(mGLSLShaderFactory); - OGRE_DELETE mGLSLShaderFactory; - mGLSLShaderFactory = 0; + if(mGLSLShaderFactory) + progMgr->removeFactory(mGLSLShaderFactory); + + if(mSPIRVShaderFactory) + progMgr->removeFactory(mSPIRVShaderFactory); } + OGRE_DELETE mGLSLShaderFactory; + mGLSLShaderFactory = 0; + + OGRE_DELETE mSPIRVShaderFactory; + mSPIRVShaderFactory = 0; + // Deleting the GPU program manager and hardware buffer manager. Has to be done before the mGLSupport->stop(). if(mShaderManager) { diff --git a/RenderSystems/GL3Plus/src/OgreSPIRVShaderFactory.cpp b/RenderSystems/GL3Plus/src/OgreSPIRVShaderFactory.cpp new file mode 100644 index 00000000000..b73129b1c92 --- /dev/null +++ b/RenderSystems/GL3Plus/src/OgreSPIRVShaderFactory.cpp @@ -0,0 +1,122 @@ +/* +----------------------------------------------------------------------------- +This source file is part of OGRE +(Object-oriented Graphics Rendering Engine) +For the latest info, see http://www.ogre3d.org/ + +Copyright (c) 2000-2014 Torus Knot Software Ltd + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +----------------------------------------------------------------------------- +*/ + +#include "OgreSPIRVShaderFactory.h" +#include "OgreLogManager.h" +#include "OgreGLSLExtSupport.h" + + +namespace Ogre { + +static GLenum getGLShaderType(GpuProgramType programType) +{ + switch (programType) + { + case GPT_VERTEX_PROGRAM: + return GL_VERTEX_SHADER; + case GPT_HULL_PROGRAM: + return GL_TESS_CONTROL_SHADER; + case GPT_DOMAIN_PROGRAM: + return GL_TESS_EVALUATION_SHADER; + case GPT_GEOMETRY_PROGRAM: + return GL_GEOMETRY_SHADER; + case GPT_FRAGMENT_PROGRAM: + return GL_FRAGMENT_SHADER; + case GPT_COMPUTE_PROGRAM: + return GL_COMPUTE_SHADER; + } + + return 0; +} + +SPIRVShader::SPIRVShader(ResourceManager* creator, const String& name, ResourceHandle handle, const String& group, + bool isManual, ManualResourceLoader* loader) + : GLSLShader(creator, name, handle, group, isManual, loader) +{ + if (createParamDictionary("SPIRVGpuProgram")) + { + setupBaseParamDictionary(); + } +} + +SPIRVShader::~SPIRVShader() +{ + // have to call this here reather than in Resource destructor + // since calling virtual methods in base destructors causes crash + unloadHighLevel(); +} + +const String& SPIRVShader::getLanguage(void) const +{ + static String language = "spirv"; + return language; +} + +void SPIRVShader::loadFromSource(void) +{ + OGRE_CHECK_GL_ERROR(mGLShaderHandle = glCreateShader(getGLShaderType(mType))); + + OGRE_CHECK_GL_ERROR(glShaderBinary(1, &mGLShaderHandle, GL_SHADER_BINARY_FORMAT_SPIR_V, mSource.data(), mSource.size())); + + OGRE_CHECK_GL_ERROR(glSpecializeShader(mGLShaderHandle, "main", 0, NULL, NULL)); + + // Check for compile errors + int compiled = 0; + OGRE_CHECK_GL_ERROR(glGetShaderiv(mGLShaderHandle, GL_COMPILE_STATUS, &compiled)); + + if (compiled) return; + + String compileInfo = getObjectInfo(mGLShaderHandle); + + OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, compileInfo); +} + +SPIRVShaderFactory::SPIRVShaderFactory() +{ + +} + +SPIRVShaderFactory::~SPIRVShaderFactory() +{ + +} + +const String& SPIRVShaderFactory::getLanguage(void) const +{ + static String language = "spirv"; + return language; +} + +HighLevelGpuProgram* SPIRVShaderFactory::create(ResourceManager* creator, const String& name, ResourceHandle handle, + const String& group, bool isManual, ManualResourceLoader* loader) +{ + return OGRE_NEW SPIRVShader(creator, name, handle, group, isManual, loader); +} + +void SPIRVShaderFactory::destroy(HighLevelGpuProgram* prog) { delete prog; } +} diff --git a/Samples/Media/materials/programs/SPIRV/GrayScale.frag b/Samples/Media/materials/programs/SPIRV/GrayScale.frag new file mode 100644 index 00000000000..4826354298e --- /dev/null +++ b/Samples/Media/materials/programs/SPIRV/GrayScale.frag @@ -0,0 +1,12 @@ +#version 430 + +layout(location = 0) uniform sampler2D RT; +layout(location = 0) in vec2 oUv0; + +layout(location = 0) out vec4 fragColor; + +void main() +{ + vec3 greyscale = vec3(dot(texture(RT, oUv0).rgb, vec3(0.3, 0.59, 0.11))); + fragColor = vec4(greyscale, 1.0); +} diff --git a/Samples/Media/materials/programs/SPIRV/README.md b/Samples/Media/materials/programs/SPIRV/README.md new file mode 100644 index 00000000000..e37b3d70b26 --- /dev/null +++ b/Samples/Media/materials/programs/SPIRV/README.md @@ -0,0 +1,12 @@ +To compile these shaders install `glslangValidator` and run `compile.sh `. + +Then reference them in `BlackAndWhite.material` and `StdQuad_vp.program` by e.g. modifying the GLSL declaration as + +``` +fragment_program Ogre/Compositor/B&W_GLSL_FP spirv +{ + source GrayScale.frag.spv +} +``` + +to mix SPIRV and GLSL shaders, `RSC_GLSL_SSO_REDECLARE` must be enabled. \ No newline at end of file diff --git a/Samples/Media/materials/programs/SPIRV/StdQuad_Tex2a_vp.vert b/Samples/Media/materials/programs/SPIRV/StdQuad_Tex2a_vp.vert new file mode 100644 index 00000000000..cb44e7bbeab --- /dev/null +++ b/Samples/Media/materials/programs/SPIRV/StdQuad_Tex2a_vp.vert @@ -0,0 +1,16 @@ +#version 430 + +layout(location = 1) uniform mat4 worldViewProj; + +layout(location = 0) in vec4 vertex; +layout(location = 8) in vec2 uv0; + +layout(location = 0) out vec2 oUv0; + +void main() +{ + // uniforms are not yet passed correctly + // however here worldViewProj would be identity anyway + gl_Position = /*worldViewProj */ vertex; + oUv0 = uv0; +} diff --git a/Samples/Media/materials/programs/SPIRV/compile.sh b/Samples/Media/materials/programs/SPIRV/compile.sh new file mode 100755 index 00000000000..10f3d4ea269 --- /dev/null +++ b/Samples/Media/materials/programs/SPIRV/compile.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +glslangValidator --client opengl100 $1 -o $1.spv \ No newline at end of file