diff --git a/Docs/src/high-level-programs.md b/Docs/src/high-level-programs.md index af5f048e77a..01a2f6b4291 100644 --- a/Docs/src/high-level-programs.md +++ b/Docs/src/high-level-programs.md @@ -196,6 +196,18 @@ param_named skewMatrix float4 0.5 0 -0.5 1.0 This means that `mat[0]` is the first column in GLSL, but the first row in HLSL and %Ogre. %Ogre takes care of transposing square matrices before uploading them with GLSL, so matrix-vector multiplication `M*v` just works and `mat[0]` will return the same data. However, with non-square matrices transposing would change their GLSL type from e.g. `mat2x4` (two columns, four rows) to `mat4x2` (two rows, four columns) and consequently what `mat[0]` would return. Therefore %Ogre just passes such matrices unchanged and you have to handle this case (notably in skinning) yourself by either transposing the matrix in the shader or column-wise access. +## Uniform Buffers {#Uniform-Buffers} + +If supported by the RenderSystem, you can opt-in to use uniform buffers for parameter storage. +This is done by declaring the parameters in a uniform block named @c OgreUniforms + +```cpp +layout(std140, row_major) uniform OgreUniforms +{ + mat4 worldTransform; +} +``` + ## Transform Feedback Varyings {#Transform-Feedback-Varyings} Similarly to vertex attributes, the transform feedback varyings are bound by name. diff --git a/RenderSystems/GL3Plus/include/OgreGL3PlusRenderSystem.h b/RenderSystems/GL3Plus/include/OgreGL3PlusRenderSystem.h index d2957747acf..7e146bcc67c 100644 --- a/RenderSystems/GL3Plus/include/OgreGL3PlusRenderSystem.h +++ b/RenderSystems/GL3Plus/include/OgreGL3PlusRenderSystem.h @@ -102,6 +102,8 @@ namespace Ogre { std::array mCurrentShader; + HardwareBufferPtr mUniformBuffer[GPT_COUNT]; + GLenum getBlendMode(SceneBlendFactor ogreBlend) const; void bindVertexElementToGpu(const VertexElement& elem, diff --git a/RenderSystems/GL3Plus/src/GLSL/include/OgreGLSLShader.h b/RenderSystems/GL3Plus/src/GLSL/include/OgreGLSLShader.h index 993b7ee7a75..dcb8bb7acc5 100644 --- a/RenderSystems/GL3Plus/src/GLSL/include/OgreGLSLShader.h +++ b/RenderSystems/GL3Plus/src/GLSL/include/OgreGLSLShader.h @@ -52,8 +52,6 @@ namespace Ogre { void setSamplerBinding(bool enable) { mHasSamplerBinding = enable; } bool getSamplerBinding() const { return mHasSamplerBinding; } - const HardwareBufferPtr& getDefaultBuffer() const { return mDefaultBuffer; } - /// Overridden from GpuProgram const String& getLanguage(void) const override; protected: @@ -68,9 +66,8 @@ namespace Ogre { /// @param block uniform block to consider. -1 for non-UBO uniforms void extractUniforms(int block = -1) const; - void extractBufferBlocks(GLenum type) const; + void extractBufferBlocks(GLenum type); - mutable HardwareBufferPtr mDefaultBuffer; bool mHasSamplerBinding; }; diff --git a/RenderSystems/GL3Plus/src/GLSL/src/OgreGLSLSeparableProgram.cpp b/RenderSystems/GL3Plus/src/GLSL/src/OgreGLSLSeparableProgram.cpp index 1d712c2f6fe..fe2578eb334 100644 --- a/RenderSystems/GL3Plus/src/GLSL/src/OgreGLSLSeparableProgram.cpp +++ b/RenderSystems/GL3Plus/src/GLSL/src/OgreGLSLSeparableProgram.cpp @@ -120,14 +120,7 @@ namespace Ogre GLuint progID = mShaders[fromProgType]->getGLProgramHandle(); GLUniformCache* uniformCache = mShaders[fromProgType]->getUniformCache(); - bool usesUBO = false; - if(const auto& ubo = static_cast(mShaders[fromProgType])->getDefaultBuffer()) - { - // we ignore ma - ubo->writeData(0, ubo->getSizeInBytes(), params->getConstantList().data(), true); - static_cast(ubo.get())->bind(); - usesUBO = true; - } + bool usesUBO = !params->hasLogicalIndexedParameters(); // Iterate through uniform reference list and update uniform values for (const auto& it : params->getConstantDefinitions().map) diff --git a/RenderSystems/GL3Plus/src/GLSL/src/OgreGLSLShader.cpp b/RenderSystems/GL3Plus/src/GLSL/src/OgreGLSLShader.cpp index 88ea9e2a2c5..2046c11377b 100644 --- a/RenderSystems/GL3Plus/src/GLSL/src/OgreGLSLShader.cpp +++ b/RenderSystems/GL3Plus/src/GLSL/src/OgreGLSLShader.cpp @@ -566,7 +566,7 @@ namespace Ogre { } } - void GLSLShader::extractBufferBlocks(GLenum type) const + void GLSLShader::extractBufferBlocks(GLenum type) { GLint numBlocks = 0; OGRE_CHECK_GL_ERROR(glGetProgramInterfaceiv(mGLProgramHandle, type, GL_ACTIVE_RESOURCES, &numBlocks)); @@ -589,15 +589,14 @@ namespace Ogre { if (name == "OgreUniforms") // default buffer { extractUniforms(blockIdx); - int binding = mType == GPT_COMPUTE_PROGRAM ? 0 : int(mType); + int binding = mType == GPT_COMPUTE_PROGRAM ? 0 : (int(mType) % GPT_PIPELINE_COUNT); if (binding > 1) LogManager::getSingleton().logWarning( getResourceLogName() + " - using 'OgreUniforms' in this shader type does alias with shared_params"); - mDefaultBuffer = hbm.createUniformBuffer(values[2]); - static_cast(mDefaultBuffer.get())->setGLBufferBinding(binding); OGRE_CHECK_GL_ERROR(glUniformBlockBinding(mGLProgramHandle, blockIdx, binding)); + mLogicalToPhysical.reset(); continue; } diff --git a/RenderSystems/GL3Plus/src/OgreGL3PlusRenderSystem.cpp b/RenderSystems/GL3Plus/src/OgreGL3PlusRenderSystem.cpp index 83e25029fae..393280d6821 100644 --- a/RenderSystems/GL3Plus/src/OgreGL3PlusRenderSystem.cpp +++ b/RenderSystems/GL3Plus/src/OgreGL3PlusRenderSystem.cpp @@ -1648,6 +1648,22 @@ namespace Ogre { params->_updateSharedParams(); } + auto paramsSize = params->getConstantList().size(); + if (paramsSize && getCapabilities()->hasCapability(RSC_SEPARATE_SHADER_OBJECTS) && + !params->hasLogicalIndexedParameters()) + { + auto& ubo = mUniformBuffer[gptype]; + if(!ubo || ubo->getSizeInBytes() < paramsSize) + { + ubo = mHardwareBufferManager->createUniformBuffer(paramsSize); + } + + ubo->writeData(0, ubo->getSizeInBytes(), params->getConstantList().data(), true); + + int binding = gptype == GPT_COMPUTE_PROGRAM ? 0 : (int(gptype) % GPT_PIPELINE_COUNT); + static_cast(ubo.get())->setGLBufferBinding(binding); + } + // Pass on parameters from params to program object uniforms. program->updateUniforms(params, mask, gptype); }