Support MultiSampling FrameBuffer 14/284214/18
authorEunki, Hong <eunkiki.hong@samsung.com>
Fri, 11 Nov 2022 13:51:29 +0000 (22:51 +0900)
committerEunki, Hong <eunkiki.hong@samsung.com>
Thu, 1 Dec 2022 09:46:04 +0000 (18:46 +0900)
Let we check Multisampled Framebuffer system supported.
If then + If user setup specific sampling size, render to texture multisampled.

TODO : Ubuntu profile make some crash even it support this feature.
Other profiles are all works well. Until find the reason of this crash,
Just block Multisampled FBO feature in Ubuntu case.

Change-Id: I329a97e47b65479756d9e7d2c8a57660fc569fcb
Signed-off-by: Eunki, Hong <eunkiki.hong@samsung.com>
19 files changed:
automated-tests/src/dali-adaptor/dali-test-suite-utils/test-gl-abstraction.cpp
automated-tests/src/dali-adaptor/dali-test-suite-utils/test-gl-abstraction.h
automated-tests/src/dali-adaptor/dali-test-suite-utils/test-graphics-application.h
dali/internal/graphics/common/graphics-interface.h
dali/internal/graphics/file.list
dali/internal/graphics/gles-impl/gles-graphics-framebuffer.cpp
dali/internal/graphics/gles-impl/gles-graphics-framebuffer.h
dali/internal/graphics/gles/egl-graphics.cpp
dali/internal/graphics/gles/egl-graphics.h
dali/internal/graphics/gles/gl-extensions-support.cpp [new file with mode: 0644]
dali/internal/graphics/gles/gl-extensions-support.h [new file with mode: 0644]
dali/internal/graphics/gles/gl-extensions.cpp
dali/internal/graphics/gles/gl-extensions.h
dali/internal/graphics/gles/gl-implementation.h
dali/internal/graphics/gles/gles-abstraction.h
dali/internal/graphics/gles/gles2-implementation.h
dali/internal/graphics/gles/gles3-implementation.h
dali/internal/system/common/configuration-manager.cpp
dali/internal/system/common/configuration-manager.h

index 7a31046..6021026 100644 (file)
@@ -166,6 +166,11 @@ bool TestGlAbstraction::IsAdvancedBlendEquationSupported()
   return true;
 }
 
+bool TestGlAbstraction::IsMultisampledRenderToTextureSupported()
+{
+  return true;
+}
+
 bool TestGlAbstraction::IsBlendEquationSupported(DevelBlendEquation::Type blendEquation)
 {
   return true;
index f6878ae..5e5fde3 100644 (file)
@@ -72,6 +72,8 @@ public:
 
   bool IsAdvancedBlendEquationSupported() override;
 
+  bool IsMultisampledRenderToTextureSupported() override;
+
   bool IsBlendEquationSupported(DevelBlendEquation::Type blendEquation) override;
 
   std::string GetShaderVersionPrefix();
@@ -1702,6 +1704,12 @@ public:
   {
   }
 
+  inline void FramebufferTexture2DMultisample(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLsizei samples) override
+  {
+    // TODO : Check it if need
+    FramebufferTexture2D(target, attachment, textarget, texture, level);
+  }
+
   inline void FramebufferTextureLayer(GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer) override
   {
   }
index 3705eee..a1f8a2e 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_TEST_GRAPHICS_APPLICATION_H
 
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -148,6 +148,14 @@ public:
   }
 
   /**
+   * @return true if multisampled render to texture is supported
+   */
+  bool IsMultisampledRenderToTextureSupported() override
+  {
+    return true;
+  }
+
+  /**
    * @return true if graphics subsystem is initialized
    */
   bool IsInitialized() override
@@ -172,6 +180,14 @@ public:
   }
 
   /**
+   * @return the maximum texture samples when we use multisampled texture
+   */
+  uint8_t GetMaxTextureSamples() override
+  {
+    return 8u;
+  }
+
+  /**
    * @return the version number of the shader language
    */
   uint32_t GetShaderLanguageVersion() override
index 6575a0c..08cc77d 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_INTERNAL_BASE_GRAPHICS_INTERFACE_H
 
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -147,6 +147,11 @@ public:
   virtual bool IsAdvancedBlendEquationSupported() = 0;
 
   /**
+   * @return true if multisampled render to texture is supported
+   */
+  virtual bool IsMultisampledRenderToTextureSupported() = 0;
+
+  /**
    * @return true if graphics subsystem is initialized
    */
   virtual bool IsInitialized() = 0;
@@ -162,6 +167,11 @@ public:
   virtual uint32_t GetMaxTextureSize() = 0;
 
   /**
+   * @return the maximum texture samples when we use multisampled texture
+   */
+  virtual uint8_t GetMaxTextureSamples() = 0;
+
+  /**
    * @return the version number of the shader language
    */
   virtual uint32_t GetShaderLanguageVersion() = 0;
index 1aaa12f..e40507a 100644 (file)
@@ -6,6 +6,7 @@ SET( adaptor_graphics_gles_src_files
     ${adaptor_graphics_dir}/gles/egl-sync-implementation.cpp
     ${adaptor_graphics_dir}/gles/egl-context-helper-implementation.cpp
     ${adaptor_graphics_dir}/gles/gl-extensions.cpp
+    ${adaptor_graphics_dir}/gles/gl-extensions-support.cpp
     ${adaptor_graphics_dir}/gles/gl-proxy-implementation.cpp
     ${adaptor_graphics_dir}/gles/egl-graphics-factory.cpp
     ${adaptor_graphics_dir}/gles/egl-graphics.cpp
index f5f750b..6695fbf 100644 (file)
@@ -84,6 +84,12 @@ struct DEPTH_STENCIL_ATTACHMENT_TYPE
 Framebuffer::Framebuffer(const Graphics::FramebufferCreateInfo& createInfo, Graphics::EglGraphicsController& controller)
 : FramebufferResource(createInfo, controller)
 {
+  // Check whether we need to consider multisampling
+  if(createInfo.multiSamplingLevel > 1u && controller.GetGraphicsInterface()->IsMultisampledRenderToTextureSupported())
+  {
+    mMultisamples = std::min(createInfo.multiSamplingLevel, controller.GetGraphicsInterface()->GetMaxTextureSamples());
+  }
+
   // Add framebuffer to the Resource queue
   mController.AddFramebuffer(*this);
 }
@@ -137,30 +143,32 @@ bool Framebuffer::InitializeResource()
 
       AttachTexture(depthTexture, attachmentId, 0, mCreateInfo.depthStencilAttachment.depthLevel);
     }
-    else if(mCreateInfo.depthStencilAttachment.depthUsage == Graphics::DepthStencilAttachment::Usage::WRITE &&
-            mCreateInfo.depthStencilAttachment.stencilUsage == Graphics::DepthStencilAttachment::Usage::WRITE)
-    {
-      // Create depth+stencil renderbuffer
-      gl->GenRenderbuffers(1, &mStencilBufferId);
-      gl->BindRenderbuffer(GL_RENDERBUFFER, mStencilBufferId);
-      gl->RenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, mCreateInfo.size.width, mCreateInfo.size.height);
-      gl->FramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, mStencilBufferId);
-    }
-    else if(mCreateInfo.depthStencilAttachment.depthUsage == Graphics::DepthStencilAttachment::Usage::WRITE)
-    {
-      // Create depth renderbuffer
-      gl->GenRenderbuffers(1, &mDepthBufferId);
-      gl->BindRenderbuffer(GL_RENDERBUFFER, mDepthBufferId);
-      gl->RenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, mCreateInfo.size.width, mCreateInfo.size.height);
-      gl->FramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, mDepthBufferId);
-    }
-    else if(mCreateInfo.depthStencilAttachment.stencilUsage == Graphics::DepthStencilAttachment::Usage::WRITE)
+    else
     {
-      // Create stencil renderbuffer
-      gl->GenRenderbuffers(1, &mStencilBufferId);
-      gl->BindRenderbuffer(GL_RENDERBUFFER, mStencilBufferId);
-      gl->RenderbufferStorage(GL_RENDERBUFFER, GL_STENCIL_INDEX8, mCreateInfo.size.width, mCreateInfo.size.height);
-      gl->FramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, mStencilBufferId);
+      const bool depthWrite   = mCreateInfo.depthStencilAttachment.depthUsage == Graphics::DepthStencilAttachment::Usage::WRITE;
+      const bool stencilWrite = mCreateInfo.depthStencilAttachment.stencilUsage == Graphics::DepthStencilAttachment::Usage::WRITE;
+
+      // Check whether we need to use RenderBuffer
+      if(depthWrite || stencilWrite)
+      {
+        // if stencil is write, use renderbuffer as mStencilBufferId.
+        uint32_t&  bufferId       = stencilWrite ? mStencilBufferId : mDepthBufferId;
+        const auto internalFormat = depthWrite ? (stencilWrite ? GL_DEPTH24_STENCIL8 : GL_DEPTH_COMPONENT16) : GL_STENCIL_INDEX8;
+        const auto attachment     = depthWrite ? (stencilWrite ? GL_DEPTH_STENCIL_ATTACHMENT : GL_DEPTH_ATTACHMENT) : GL_STENCIL_ATTACHMENT;
+
+        gl->GenRenderbuffers(1, &bufferId);
+        gl->BindRenderbuffer(GL_RENDERBUFFER, bufferId);
+
+        if(mMultisamples <= 1u)
+        {
+          gl->RenderbufferStorage(GL_RENDERBUFFER, internalFormat, mCreateInfo.size.width, mCreateInfo.size.height);
+        }
+        else
+        {
+          gl->RenderbufferStorageMultisample(GL_RENDERBUFFER, mMultisamples, internalFormat, mCreateInfo.size.width, mCreateInfo.size.height);
+        }
+        gl->FramebufferRenderbuffer(GL_FRAMEBUFFER, attachment, GL_RENDERBUFFER, bufferId);
+      }
     }
 
     context->BindFrameBuffer(GL_FRAMEBUFFER, 0);
@@ -213,13 +221,14 @@ void Framebuffer::AttachTexture(const Graphics::Texture* texture, uint32_t attac
   if(gl)
   {
     auto graphicsTexture = static_cast<const GLES::Texture*>(texture);
-    if(graphicsTexture->GetCreateInfo().textureType == Graphics::TextureType::TEXTURE_2D)
+    auto textarget       = (graphicsTexture->GetCreateInfo().textureType == Graphics::TextureType::TEXTURE_2D) ? graphicsTexture->GetGlTarget() : GL_TEXTURE_CUBE_MAP_POSITIVE_X + layerId;
+    if(mMultisamples <= 1u)
     {
-      gl->FramebufferTexture2D(GL_FRAMEBUFFER, attachmentId, graphicsTexture->GetGlTarget(), graphicsTexture->GetGLTexture(), levelId);
+      gl->FramebufferTexture2D(GL_FRAMEBUFFER, attachmentId, textarget, graphicsTexture->GetGLTexture(), levelId);
     }
     else
     {
-      gl->FramebufferTexture2D(GL_FRAMEBUFFER, attachmentId, GL_TEXTURE_CUBE_MAP_POSITIVE_X + layerId, graphicsTexture->GetGLTexture(), levelId);
+      gl->FramebufferTexture2DMultisample(GL_FRAMEBUFFER, attachmentId, textarget, graphicsTexture->GetGLTexture(), levelId, mMultisamples);
     }
   }
 }
index b48af2c..430b395 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_GRAPHICS_GLES_FRAMEBUFFER_H
 
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -86,6 +86,7 @@ private:
   uint32_t mFramebufferId{0u};
   uint32_t mDepthBufferId{0u};
   uint32_t mStencilBufferId{0u};
+  uint32_t mMultisamples{1u};
   bool     mInitialized{false};
 };
 
index a963e28..15e17f1 100644 (file)
@@ -247,6 +247,7 @@ Graphics::Controller& EglGraphics::GetController()
 void EglGraphics::CacheConfigurations(ConfigurationManager& configurationManager)
 {
   mGLES->SetIsAdvancedBlendEquationSupported(configurationManager.IsAdvancedBlendEquationSupported());
+  mGLES->SetIsMultisampledRenderToTextureSupported(configurationManager.IsMultisampledRenderToTextureSupported());
   mGLES->SetShadingLanguageVersion(configurationManager.GetShadingLanguageVersion());
 }
 
index 399ff1a..48dd0b7 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_INTERNAL_BASE_GRAPHICS_IMPLEMENTATION_H
 
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -171,6 +171,11 @@ public:
     return mGLES->IsAdvancedBlendEquationSupported();
   }
 
+  bool IsMultisampledRenderToTextureSupported() override
+  {
+    return mGLES->IsMultisampledRenderToTextureSupported();
+  }
+
   /**
    * @return true if graphics subsystem is initialized
    */
@@ -189,6 +194,11 @@ public:
     return mGLES->GetMaxTextureSize();
   }
 
+  uint8_t GetMaxTextureSamples() override
+  {
+    return mGLES->GetMaxTextureSamples();
+  }
+
   uint32_t GetShaderLanguageVersion() override
   {
     return mGLES->GetShadingLanguageVersion();
diff --git a/dali/internal/graphics/gles/gl-extensions-support.cpp b/dali/internal/graphics/gles/gl-extensions-support.cpp
new file mode 100644 (file)
index 0000000..b5e04d4
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/graphics/gles/gl-extensions-support.h>
+
+// EXTERNAL HEADER
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+#include <GLES3/gl3.h>
+
+#include <algorithm> // for std::find_if
+#include <sstream>
+#include <string>
+#include <string_view>
+#include <utility> // for std::pair
+
+namespace Dali
+{
+namespace Internal
+{
+namespace Adaptor
+{
+namespace
+{
+static constexpr const char* KHR_BLEND_EQUATION_ADVANCED        = "GL_KHR_blend_equation_advanced";
+static constexpr const char* EXT_MULTISAMPLED_RENDER_TO_TEXTURE = "GL_EXT_multisampled_render_to_texture";
+
+} // namespace
+
+namespace GlExtensionCache
+{
+void GlExtensionSupportedCacheList::EnsureGlExtensionSupportedCheck()
+{
+  // Note that this function calls at most one time.
+  // But the number of GL_EXTENSIONS itmes are so vairous.
+  // We need to reduce extension checkup
+
+  const char* const  extensionStr = reinterpret_cast<const char*>(glGetString(GL_EXTENSIONS));
+  std::istringstream stream(extensionStr);
+  std::string        currentExtension;
+
+  // Create expected string-to-checkertype convertor.
+  using StringTypePair = std::pair<std::string_view, GlExtensionCheckerType>;
+  // clang-format off
+  std::vector<StringTypePair> extensionStringToTypeList
+  {
+    {KHR_BLEND_EQUATION_ADVANCED,        GlExtensionCheckerType::BLEND_EQUATION_ADVANCED       },
+
+#ifndef DALI_PROFILE_UBUNTU
+    // @todo : Current ubuntu profile's multisamples FBO make crash when eglDestroyContext.
+    // Invalidate multisampled render to texture feature hardly.
+    {EXT_MULTISAMPLED_RENDER_TO_TEXTURE, GlExtensionCheckerType::MULTISAMPLED_RENDER_TO_TEXTURE},
+#endif //DALI_PROFILE_UBUNTU
+
+    ///< Append additional extension checker type here.
+  };
+  // clang-format on
+
+  while(!extensionStringToTypeList.empty() && std::getline(stream, currentExtension, ' '))
+  {
+    auto findResult = std::find_if(extensionStringToTypeList.begin(),
+                                   extensionStringToTypeList.end(),
+                                   [&currentExtension](const StringTypePair& value) {
+                                     return value.first == currentExtension;
+                                   });
+    if(findResult != extensionStringToTypeList.end())
+    {
+      auto type = findResult->second;
+
+      // Mark as True.
+      MarkSupported(type, true);
+
+      // Remove from list. we don't need to check this extension.
+      extensionStringToTypeList.erase(findResult);
+    }
+  }
+
+  // Set supported as false if extension keyword not exist.
+  SetAllUncachedAsNotSupported();
+}
+} // namespace GlExtensionCache
+} // namespace Adaptor
+} // namespace Internal
+} // namespace Dali
diff --git a/dali/internal/graphics/gles/gl-extensions-support.h b/dali/internal/graphics/gles/gl-extensions-support.h
new file mode 100644 (file)
index 0000000..6caa497
--- /dev/null
@@ -0,0 +1,181 @@
+#ifndef DALI_INTERNAL_GL_EXTENSION_SUPPORT_H
+#define DALI_INTERNAL_GL_EXTENSION_SUPPORT_H
+
+/*
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/common/vector-wrapper.h>
+#include <cstdint>
+
+namespace Dali
+{
+namespace Internal
+{
+namespace Adaptor
+{
+/**
+ * Common extensions support checker type.
+ * Type value should be start with 0, and increase continuous.
+ */
+using ExtensionCheckerType = uint32_t;
+
+/**
+ * @brief Store the supported information cached or not.
+ */
+struct ExtensionSupportedCache
+{
+  ExtensionSupportedCache()
+  : isSupported{false},
+    cached{false}
+  {
+  }
+  bool isSupported : 1;
+  bool cached : 1;
+};
+
+/**
+ * @brief Extension Supported caching system interface.
+ *
+ * Create ExtensionSupportedCache list and Set/Get supported value.
+ * Use ExtensionCheckerType as index of container.
+ *
+ * It will help to check gl extension & egl extention support.
+ */
+struct ExtensionSupportedCacheListInterface
+{
+  ExtensionSupportedCacheListInterface(const uint32_t maxCount)
+  : mCachedItemCount(0u),
+    mMaxCount(maxCount),
+    mData{maxCount}
+  {
+  }
+
+  /**
+   * @brief Check whether we need to check some more extension types or not.
+   * @return True if some extension type to check remained. False if we checked all extension types.
+   */
+  inline bool NeedFullCheck() const
+  {
+    return mCachedItemCount < mMaxCount;
+  }
+
+  /**
+   * @brief Set extension is supported or not
+   * If we already cached the result before, just ignored.
+   *
+   * @param[in] type The index of extension type.
+   * @param[in] isSupported Whether this extension supported or not. Default as true.
+   */
+  inline void MarkSupported(ExtensionCheckerType type, bool isSupported = true)
+  {
+    auto& cache = mData[static_cast<uint32_t>(type)];
+    if(!cache.cached)
+    {
+      cache.cached      = true;
+      cache.isSupported = isSupported;
+      ++mCachedItemCount;
+    }
+  }
+
+  /**
+   * @brief Get extension is supported or not.
+   *
+   * @param[in] type The index of extension type.
+   * @return True if we cached extension as supported. False otherwise.
+   */
+  inline bool IsSupported(ExtensionCheckerType type) const
+  {
+    return mData[static_cast<uint32_t>(type)].isSupported;
+  }
+
+  /**
+   * @brief Get extension is cached or not.
+   *
+   * @param[in] type The index of extension type.
+   * @return True if we cached extension. False otherwise.
+   */
+  inline bool IsCached(ExtensionCheckerType type) const
+  {
+    return mData[static_cast<uint32_t>(type)].cached;
+  }
+
+  /**
+   * @brief Mark all uncached extension type as not supported.
+   * After this API called, we can assume that every extensions are cached.
+   */
+  void SetAllUncachedAsNotSupported()
+  {
+    if(NeedFullCheck())
+    {
+      for(auto&& iter : mData)
+      {
+        if(!iter.cached)
+        {
+          iter.isSupported = false;
+          iter.cached      = true;
+        }
+      }
+
+      // Mark all cached.
+      mCachedItemCount = mMaxCount;
+    }
+  }
+
+  uint32_t       mCachedItemCount;
+  const uint32_t mMaxCount;
+
+  std::vector<ExtensionSupportedCache> mData;
+};
+
+/**
+ * Gl extensions support checker system.
+ */
+namespace GlExtensionCache
+{
+enum GlExtensionCheckerType
+{
+  BLEND_EQUATION_ADVANCED = 0,
+  MULTISAMPLED_RENDER_TO_TEXTURE,
+  ///< Append additional extension checker type here.
+  EXTENSION_CHECKER_TYPE_MAX,
+};
+
+/**
+ * @brief Extension Supported caching system for gl.
+ */
+struct GlExtensionSupportedCacheList : public ExtensionSupportedCacheListInterface
+{
+  GlExtensionSupportedCacheList()
+  : ExtensionSupportedCacheListInterface(static_cast<uint32_t>(GlExtensionCheckerType::EXTENSION_CHECKER_TYPE_MAX))
+  {
+  }
+
+  /**
+   * Ensure that we check all gl extension features for this system.
+   */
+  void EnsureGlExtensionSupportedCheck();
+};
+} // namespace GlExtensionCache
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif /* DALI_INTERNAL_GL_EXTENSION_SUPPORT_H */
index 1790fe5..062af6b 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -42,6 +42,10 @@ GlExtensions::GlExtensions()
 #ifdef GL_KHR_blend_equation_advanced
   mBlendBarrierKHR(nullptr),
 #endif
+#ifdef GL_EXT_multisampled_render_to_texture
+  mGlRenderbufferStorageMultisampleEXT(nullptr),
+  mGlFramebufferTexture2DMultisampleEXT(nullptr),
+#endif
   mInitialized(false)
 {
 }
@@ -54,7 +58,7 @@ void GlExtensions::DiscardFrameBuffer(GLenum target, GLsizei numAttachments, con
 {
   // initialize extension on first use as on some hw platforms a context
   // has to be bound for the extensions to return correct pointer
-  if(!mInitialized)
+  if(DALI_UNLIKELY(!mInitialized))
   {
     Initialize();
   }
@@ -75,7 +79,7 @@ void GlExtensions::GetProgramBinaryOES(GLuint program, GLsizei bufSize, GLsizei*
 {
   // initialize extension on first use as on some hw platforms a context
   // has to be bound for the extensions to return correct pointer
-  if(!mInitialized)
+  if(DALI_UNLIKELY(!mInitialized))
   {
     Initialize();
   }
@@ -97,7 +101,7 @@ void GlExtensions::ProgramBinaryOES(GLuint program, GLenum binaryFormat, const G
 {
   // initialize extension on first use as on some hw platforms a context
   // has to be bound for the extensions to return correct pointer
-  if(!mInitialized)
+  if(DALI_UNLIKELY(!mInitialized))
   {
     Initialize();
   }
@@ -119,7 +123,7 @@ bool GlExtensions::BlendBarrierKHR()
 {
   // initialize extension on first use as on some hw platforms a context
   // has to be bound for the extensions to return correct pointer
-  if(!mInitialized)
+  if(DALI_UNLIKELY(!mInitialized))
   {
     Initialize();
   }
@@ -136,6 +140,50 @@ bool GlExtensions::BlendBarrierKHR()
   return false;
 }
 
+void GlExtensions::RenderbufferStorageMultisampleEXT(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height)
+{
+  // initialize extension on first use as on some hw platforms a context
+  // has to be bound for the extensions to return correct pointer
+  if(DALI_UNLIKELY(!mInitialized))
+  {
+    Initialize();
+  }
+
+#ifdef GL_EXT_multisampled_render_to_texture
+  if(mGlRenderbufferStorageMultisampleEXT)
+  {
+    mGlRenderbufferStorageMultisampleEXT(target, samples, internalformat, width, height);
+  }
+  else
+  {
+    DALI_LOG_ERROR("Error: glRenderbufferStorageMultisampleEXT extension is not available\n");
+    DALI_ASSERT_DEBUG(0);
+  }
+#endif
+}
+
+void GlExtensions::FramebufferTexture2DMultisampleEXT(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLsizei samples)
+{
+  // initialize extension on first use as on some hw platforms a context
+  // has to be bound for the extensions to return correct pointer
+  if(DALI_UNLIKELY(!mInitialized))
+  {
+    Initialize();
+  }
+
+#ifdef GL_EXT_multisampled_render_to_texture
+  if(mGlFramebufferTexture2DMultisampleEXT)
+  {
+    mGlFramebufferTexture2DMultisampleEXT(target, attachment, textarget, texture, level, samples);
+  }
+  else
+  {
+    DALI_LOG_ERROR("Error: glFramebufferTexture2DMultisampleEXT extension is not available\n");
+    DALI_ASSERT_DEBUG(0);
+  }
+#endif
+}
+
 void GlExtensions::Initialize()
 {
   mInitialized = true;
@@ -152,6 +200,11 @@ void GlExtensions::Initialize()
 #ifdef GL_KHR_blend_equation_advanced
   mBlendBarrierKHR = reinterpret_cast<PFNGLBLENDBARRIERKHRPROC>(eglGetProcAddress("glBlendBarrierKHR"));
 #endif
+
+#ifdef GL_EXT_multisampled_render_to_texture
+  mGlRenderbufferStorageMultisampleEXT  = reinterpret_cast<PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC>(eglGetProcAddress("glRenderbufferStorageMultisampleEXT"));
+  mGlFramebufferTexture2DMultisampleEXT = reinterpret_cast<PFNGLFRAMEBUFFERTEXTURE2DMULTISAMPLEEXTPROC>(eglGetProcAddress("glFramebufferTexture2DMultisampleEXT"));
+#endif
 }
 
 } // namespace Adaptor
index fe457e2..859f450 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_INTERNAL_GL_EXTENSION_H
 
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -87,6 +87,32 @@ public:
    */
   bool BlendBarrierKHR();
 
+  /**
+   * GLES extension
+   * Establish data storage, format, dimensions and sample count of a renderbuffer object's image
+   *
+   * @param[in] target Specifies a binding to which the target of the allocation and must be GL_RENDERBUFFER.
+   * @param[in] samples Specifies the number of samples to be used for the renderbuffer object's storage. Must not bigger than MAX_SAMPLES_EXT.
+   * @param[in] internalformat Specifies the internal format to use for the renderbuffer object's image.
+   * @param[in] width Specifies the width of the renderbuffer, in pixels.
+   * @param[in] height Specifies the height of the renderbuffer, in pixels.
+   */
+  void RenderbufferStorageMultisampleEXT(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
+
+  /**
+   * GLES extension
+   * Enables multisampled rendering into the images of a texture object.
+   * If samples as 0, same as FramebufferTexture2D
+   *
+   * @param[in] target Specifies the framebuffer target. The symbolic constant must be GL_FRAMEBUFFER.
+   * @param[in] attachment Specifies the attachment point to which an image from texture should be attached.
+   * @param[in] textarget Specifies the texture target.
+   * @param[in] texture Specifies the texture object whose image is to be attached.
+   * @param[in] level Specifies the mipmap level of the texture image to be attached, which must be 0.
+   * @param[in] samples The number of samples to the texture. Must not bigger than MAX_SAMPLES_EXT.
+   */
+  void FramebufferTexture2DMultisampleEXT(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLsizei samples);
+
 private:
   /**
    * Lazy Initialize extensions on first use
@@ -106,6 +132,11 @@ private:
   PFNGLBLENDBARRIERKHRPROC mBlendBarrierKHR;
 #endif
 
+#ifdef GL_EXT_multisampled_render_to_texture
+  PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC  mGlRenderbufferStorageMultisampleEXT;
+  PFNGLFRAMEBUFFERTEXTURE2DMULTISAMPLEEXTPROC mGlFramebufferTexture2DMultisampleEXT;
+#endif
+
   bool mInitialized;
 };
 
index b7551a4..61c2c08 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_INTERNAL_GL_IMPLEMENTATION_H
 
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
 #include <dali/devel-api/threading/conditional-wait.h>
 #include <dali/integration-api/gl-abstraction.h>
 #include <dali/internal/graphics/common/egl-include.h>
+#include <dali/public-api/common/vector-wrapper.h>
 #include <cstdlib>
 #include <cstring>
 #include <memory>
 
 // INTERNAL INCLUDES
+#include <dali/internal/graphics/gles/gl-extensions-support.h>
 #include <dali/internal/graphics/gles/gles-abstraction.h>
 #include <dali/internal/graphics/gles/gles2-implementation.h>
 #include <dali/internal/graphics/gles/gles3-implementation.h>
@@ -44,7 +46,6 @@ namespace
 static constexpr int32_t     INITIAL_GLES_VERSION                         = 30;
 static constexpr int32_t     GLES_VERSION_SUPPORT_BLEND_EQUATION_ADVANCED = 32;
 static constexpr const char* LEGACY_SHADING_LANGUAGE_VERSION              = "100";
-static constexpr const char* KHR_BLEND_EQUATION_ADVANCED                  = "GL_KHR_blend_equation_advanced";
 
 static constexpr const char* DEFAULT_SAMPLER_TYPE = "sampler2D";
 
@@ -63,6 +64,7 @@ static constexpr const char* FRAGMENT_SHADER_OUTPUT_COLOR_STRING =
 static constexpr const char* OES_EGL_IMAGE_EXTERNAL_STRING = "#extension GL_OES_EGL_image_external:require\n";
 
 static constexpr const char* OES_EGL_IMAGE_EXTERNAL_STRING_ESSL3 = "#extension GL_OES_EGL_image_external_essl3:require\n";
+
 } // namespace
 
 /**
@@ -74,15 +76,15 @@ class GlImplementation : public Dali::Integration::GlAbstraction
 {
 public:
   GlImplementation()
-  : mContextCreatedWaitCondition(),
+  : mGlExtensionSupportedCacheList(),
+    mContextCreatedWaitCondition(),
     mMaxTextureSize(0),
+    mMaxTextureSamples(0),
     mVertexShaderPrefix(""),
     mGlesVersion(INITIAL_GLES_VERSION),
     mShadingLanguageVersion(100),
     mShadingLanguageVersionCached(false),
     mIsSurfacelessContextSupported(false),
-    mIsAdvancedBlendEquationSupportedCached(false),
-    mIsAdvancedBlendEquationSupported(false),
     mIsContextCreated(false)
   {
     mImpl.reset(new Gles3Implementation());
@@ -117,25 +119,18 @@ public:
 
     if(mGlesVersion >= GLES_VERSION_SUPPORT_BLEND_EQUATION_ADVANCED)
     {
-      mIsAdvancedBlendEquationSupported = true;
+      SetIsAdvancedBlendEquationSupported(true);
     }
-    else
+
+    if(mGlExtensionSupportedCacheList.NeedFullCheck())
     {
-      // when mIsAdvancedBlendEquationSupported is cached, we don't need to check all the extensions.
-      if(!mIsAdvancedBlendEquationSupportedCached)
-      {
-        const char* const  extensionStr = reinterpret_cast<const char*>(glGetString(GL_EXTENSIONS));
-        std::istringstream stream(extensionStr);
-        std::string        currentExtension;
-        while(std::getline(stream, currentExtension, ' '))
-        {
-          if(currentExtension == KHR_BLEND_EQUATION_ADVANCED)
-          {
-            mIsAdvancedBlendEquationSupported = true;
-            break;
-          }
-        }
-      }
+      // fully check gl extensions if we miss some extension supported
+      mGlExtensionSupportedCacheList.EnsureGlExtensionSupportedCheck();
+    }
+
+    if(IsMultisampledRenderToTextureSupported())
+    {
+      glGetIntegerv(GL_MAX_SAMPLES_EXT, &mMaxTextureSamples);
     }
 
     if(!mShadingLanguageVersionCached)
@@ -193,18 +188,36 @@ public:
 
   void SetIsAdvancedBlendEquationSupported(const bool isSupported)
   {
-    mIsAdvancedBlendEquationSupported       = isSupported;
-    mIsAdvancedBlendEquationSupportedCached = true;
+    mGlExtensionSupportedCacheList.MarkSupported(GlExtensionCache::GlExtensionCheckerType::BLEND_EQUATION_ADVANCED, isSupported);
   }
 
   bool IsAdvancedBlendEquationSupported()
   {
     ConditionalWait::ScopedLock lock(mContextCreatedWaitCondition);
-    if(!mIsContextCreated && !mIsAdvancedBlendEquationSupportedCached)
+
+    const auto type = GlExtensionCache::GlExtensionCheckerType::BLEND_EQUATION_ADVANCED;
+    if(!mIsContextCreated && !mGlExtensionSupportedCacheList.IsCached(type))
+    {
+      mContextCreatedWaitCondition.Wait(lock);
+    }
+    return mGlExtensionSupportedCacheList.IsSupported(type);
+  }
+
+  void SetIsMultisampledRenderToTextureSupported(const bool isSupported)
+  {
+    mGlExtensionSupportedCacheList.MarkSupported(GlExtensionCache::GlExtensionCheckerType::MULTISAMPLED_RENDER_TO_TEXTURE, isSupported);
+  }
+
+  bool IsMultisampledRenderToTextureSupported()
+  {
+    ConditionalWait::ScopedLock lock(mContextCreatedWaitCondition);
+
+    const auto type = GlExtensionCache::GlExtensionCheckerType::MULTISAMPLED_RENDER_TO_TEXTURE;
+    if(!mIsContextCreated && !mGlExtensionSupportedCacheList.IsCached(type))
     {
       mContextCreatedWaitCondition.Wait(lock);
     }
-    return mIsAdvancedBlendEquationSupported;
+    return mGlExtensionSupportedCacheList.IsSupported(type);
   }
 
   bool IsBlendEquationSupported(DevelBlendEquation::Type blendEquation)
@@ -337,6 +350,16 @@ public:
     return mMaxTextureSize;
   }
 
+  int GetMaxTextureSamples()
+  {
+    ConditionalWait::ScopedLock lock(mContextCreatedWaitCondition);
+    if(!mIsContextCreated)
+    {
+      mContextCreatedWaitCondition.Wait(lock);
+    }
+    return mMaxTextureSamples;
+  }
+
   int GetGlesVersion()
   {
     ConditionalWait::ScopedLock lock(mContextCreatedWaitCondition);
@@ -371,7 +394,7 @@ public:
     if(versionPosition != std::string::npos)
     {
       std::string extensionString;
-      size_t shadingLanguageVersionPosition = shader.find_first_not_of(" \t", versionPosition + versionString.length());
+      size_t      shadingLanguageVersionPosition = shader.find_first_not_of(" \t", versionPosition + versionString.length());
       if(shadingLanguageVersionPosition != std::string::npos &&
          shader.substr(shadingLanguageVersionPosition, 3) == LEGACY_SHADING_LANGUAGE_VERSION)
       {
@@ -1250,6 +1273,11 @@ public:
     mImpl->RenderbufferStorageMultisample(target, samples, internalformat, width, height);
   }
 
+  void FramebufferTexture2DMultisample(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLsizei samples) override
+  {
+    mImpl->FramebufferTexture2DMultisample(target, attachment, textarget, texture, level, samples);
+  }
+
   void FramebufferTextureLayer(GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer) override
   {
     mImpl->FramebufferTextureLayer(target, attachment, texture, level, layer);
@@ -1647,7 +1675,7 @@ public:
 
   void BlendBarrier(void)
   {
-    if(mIsAdvancedBlendEquationSupported)
+    if(mGlExtensionSupportedCacheList.IsSupported(GlExtensionCache::GlExtensionCheckerType::BLEND_EQUATION_ADVANCED))
     {
       mImpl->BlendBarrier();
     }
@@ -1656,8 +1684,11 @@ public:
 private:
   std::unique_ptr<GlesAbstraction> mImpl;
 
+  GlExtensionCache::GlExtensionSupportedCacheList mGlExtensionSupportedCacheList;
+
   ConditionalWait mContextCreatedWaitCondition;
   GLint           mMaxTextureSize;
+  GLint           mMaxTextureSamples;
   std::string     mShaderVersionPrefix;
   std::string     mVertexShaderPrefix;
   std::string     mFragmentShaderPrefix;
@@ -1665,8 +1696,6 @@ private:
   int32_t         mShadingLanguageVersion;
   bool            mShadingLanguageVersionCached;
   bool            mIsSurfacelessContextSupported;
-  bool            mIsAdvancedBlendEquationSupportedCached;
-  bool            mIsAdvancedBlendEquationSupported;
   bool            mIsContextCreated;
 };
 
index 80e0c6e..f3cb780 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_INTERNAL_GLES_ABSTRACTION_H
 
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -82,6 +82,8 @@ public:
 
   virtual void RenderbufferStorageMultisample(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height) = 0;
 
+  virtual void FramebufferTexture2DMultisample(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLsizei samples) = 0;
+
   virtual void FramebufferTextureLayer(GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer) = 0;
 
   virtual GLvoid* MapBufferRange(GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access) = 0;
index 4ca86b3..527cebf 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_INTERNAL_GLES2_IMPLEMENTATION_H
 
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -166,7 +166,12 @@ public:
 
   void RenderbufferStorageMultisample(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height) override
   {
-    DALI_LOG_ERROR("glRenderbufferStorageMultisample is not supported in OpenGL es 2.0\n");
+    mGlExtensions.RenderbufferStorageMultisampleEXT(target, samples, internalformat, width, height);
+  }
+
+  void FramebufferTexture2DMultisample(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLsizei samples) override
+  {
+    mGlExtensions.FramebufferTexture2DMultisampleEXT(target, attachment, textarget, texture, level, samples);
   }
 
   void FramebufferTextureLayer(GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer) override
index dbdeddf..178443b 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_INTERNAL_GLES3_IMPLEMENTATION_H
 
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -164,7 +164,14 @@ public:
 
   void RenderbufferStorageMultisample(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height) override
   {
-    glRenderbufferStorageMultisample(target, samples, internalformat, width, height);
+    // @note even gles 3.0 support glRenderbufferStorageMultisample, We cannot use that API with FramebufferTexture2DMultisampleEXT cause vendor issue.
+    // Since dali only use RenderbufferStorageMultisample API for FBO MSAA, just keep to use extension API.
+    mGlExtensions.RenderbufferStorageMultisampleEXT(target, samples, internalformat, width, height);
+  }
+
+  void FramebufferTexture2DMultisample(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLsizei samples) override
+  {
+    mGlExtensions.FramebufferTexture2DMultisampleEXT(target, attachment, textarget, texture, level, samples);
   }
 
   void FramebufferTextureLayer(GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer) override
index 12c1c9a..0515b46 100644 (file)
@@ -37,10 +37,11 @@ namespace Adaptor
 {
 namespace
 {
-const std::string SYSTEM_CACHE_FILE                    = "gpu-environment.conf";
-const std::string DALI_ENV_MULTIPLE_WINDOW_SUPPORT     = "DALI_ENV_MULTIPLE_WINDOW_SUPPORT";
-const std::string DALI_BLEND_EQUATION_ADVANCED_SUPPORT = "DALI_BLEND_EQUATION_ADVANCED_SUPPORT";
-const std::string DALI_GLSL_VERSION                    = "DALI_GLSL_VERSION";
+const std::string SYSTEM_CACHE_FILE                           = "gpu-environment.conf";
+const std::string DALI_ENV_MULTIPLE_WINDOW_SUPPORT            = "DALI_ENV_MULTIPLE_WINDOW_SUPPORT";
+const std::string DALI_BLEND_EQUATION_ADVANCED_SUPPORT        = "DALI_BLEND_EQUATION_ADVANCED_SUPPORT";
+const std::string DALI_MULTISAMPLED_RENDER_TO_TEXTURE_SUPPORT = "DALI_MULTISAMPLED_RENDER_TO_TEXTURE_SUPPORT";
+const std::string DALI_GLSL_VERSION                           = "DALI_GLSL_VERSION";
 
 } // unnamed namespace
 
@@ -52,9 +53,11 @@ ConfigurationManager::ConfigurationManager(std::string systemCachePath, Graphics
   mShaderLanguageVersion(0u),
   mIsMultipleWindowSupported(true),
   mIsAdvancedBlendEquationSupported(true),
+  mIsMultisampledRenderToTextureSupported(true),
   mMaxTextureSizeCached(false),
   mIsMultipleWindowSupportedCached(false),
   mIsAdvancedBlendEquationSupportedCached(false),
+  mIsMultisampledRenderToTextureSupportedCached(false),
   mShaderLanguageVersionCached(false)
 {
 }
@@ -95,6 +98,12 @@ void ConfigurationManager::RetrieveKeysFromConfigFile(const std::string& configF
         mIsAdvancedBlendEquationSupported       = std::atoi(value.c_str());
         mIsAdvancedBlendEquationSupportedCached = true;
       }
+      else if(!mIsMultisampledRenderToTextureSupportedCached && name == DALI_MULTISAMPLED_RENDER_TO_TEXTURE_SUPPORT)
+      {
+        std::getline(subStream, value);
+        mIsMultisampledRenderToTextureSupported       = std::atoi(value.c_str());
+        mIsMultisampledRenderToTextureSupportedCached = true;
+      }
       else if(!mShaderLanguageVersionCached && name == DALI_GLSL_VERSION)
       {
         std::getline(subStream, value);
@@ -250,6 +259,41 @@ bool ConfigurationManager::IsAdvancedBlendEquationSupported()
   return mIsAdvancedBlendEquationSupported;
 }
 
+bool ConfigurationManager::IsMultisampledRenderToTextureSupported()
+{
+  if(!mIsMultisampledRenderToTextureSupportedCached)
+  {
+    RetrieveKeysFromConfigFile(mSystemCacheFilePath);
+
+    if(!mIsMultisampledRenderToTextureSupportedCached)
+    {
+      if(!mGraphics->IsInitialized())
+      {
+        // Wait until graphics subsystem is initialised, but this will happen once per factory reset.
+        // This method blocks until the render thread has initialised the graphics.
+        mThreadController->WaitForGraphicsInitialization();
+      }
+
+      // Query from Graphics Subsystem and save the cache
+      mIsMultisampledRenderToTextureSupported       = mGraphics->IsMultisampledRenderToTextureSupported();
+      mIsMultisampledRenderToTextureSupportedCached = true;
+
+      Dali::FileStream configFile(mSystemCacheFilePath, Dali::FileStream::READ | Dali::FileStream::APPEND | Dali::FileStream::TEXT);
+      std::fstream&    stream = dynamic_cast<std::fstream&>(configFile.GetStream());
+      if(stream.is_open())
+      {
+        stream << DALI_MULTISAMPLED_RENDER_TO_TEXTURE_SUPPORT << " " << mIsMultisampledRenderToTextureSupported << std::endl;
+      }
+      else
+      {
+        DALI_LOG_ERROR("Fail to open file : %s\n", mSystemCacheFilePath.c_str());
+      }
+    }
+  }
+
+  return mIsMultisampledRenderToTextureSupported;
+}
+
 } // namespace Adaptor
 
 } // namespace Internal
index 148b928..7fc767e 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_INTERNAL_ENVIRONMENT_CONFIGURATION_MANAGER_H
 
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -76,9 +76,14 @@ public:
 
   /**
    * @brief Check whether blend equation advanced (extension) is supported
-   * @return Whether blend equation advanced (extension is supported
+   * @return Whether blend equation advanced (extension) is supported
    */
   bool IsAdvancedBlendEquationSupported();
+  /**
+   * @brief Check whether multisampled render to texture (extension) is supported
+   * @return Whether multisampled render to texture (extension) is supported
+   */
+  bool IsMultisampledRenderToTextureSupported();
 
   // Deleted copy constructor.
   ConfigurationManager(const ConfigurationManager&) = delete;
@@ -92,18 +97,20 @@ public:
   // Deleted move assignment operator.
   ConfigurationManager& operator=(const ConfigurationManager&&) = delete;
 
-private:                                                          // Data
-  std::string        mSystemCacheFilePath;                        ///< The path of system cache file
-  GraphicsInterface* mGraphics;                                   ///< Graphics interface
-  ThreadController*  mThreadController;                           ///< The thread controller
-  unsigned int       mMaxTextureSize;                             ///< The largest texture that the GL can handle
-  unsigned int       mShaderLanguageVersion;                      ///< The shader language version that the system supports.
-  bool               mIsMultipleWindowSupported : 1;              ///< Whether multiple window is supported by the GLES
-  bool               mIsAdvancedBlendEquationSupported : 1;       ///< Whether blend equation advanced (extension) is supported by the GLES
-  bool               mMaxTextureSizeCached : 1;                   ///< Whether we have checked the maximum texture size
-  bool               mIsMultipleWindowSupportedCached : 1;        ///< Whether we have checked the support of multiple window
-  bool               mIsAdvancedBlendEquationSupportedCached : 1; ///< Whether we have checked the support of blend equation advanced (extension)
-  bool               mShaderLanguageVersionCached : 1;            ///< Whether we have checked the shader language version
+private:                                                                // Data
+  std::string        mSystemCacheFilePath;                              ///< The path of system cache file
+  GraphicsInterface* mGraphics;                                         ///< Graphics interface
+  ThreadController*  mThreadController;                                 ///< The thread controller
+  unsigned int       mMaxTextureSize;                                   ///< The largest texture that the GL can handle
+  unsigned int       mShaderLanguageVersion;                            ///< The shader language version that the system supports.
+  bool               mIsMultipleWindowSupported : 1;                    ///< Whether multiple window is supported by the GLES
+  bool               mIsAdvancedBlendEquationSupported : 1;             ///< Whether blend equation advanced (extension) is supported by the GLES
+  bool               mIsMultisampledRenderToTextureSupported : 1;       ///< Whether multisampled render to texture (extension) is supported by the GLES
+  bool               mMaxTextureSizeCached : 1;                         ///< Whether we have checked the maximum texture size
+  bool               mIsMultipleWindowSupportedCached : 1;              ///< Whether we have checked the support of multiple window
+  bool               mIsAdvancedBlendEquationSupportedCached : 1;       ///< Whether we have checked the support of blend equation advanced (extension)
+  bool               mIsMultisampledRenderToTextureSupportedCached : 1; ///< Whether we have checked the support of multisampled render to texture (extension)
+  bool               mShaderLanguageVersionCached : 1;                  ///< Whether we have checked the shader language version
 };
 
 } // namespace Adaptor