Added recycling of Graphics resources. 89/290289/5
authorAdam Bialogonski <adam.b@samsung.com>
Wed, 22 Mar 2023 15:26:42 +0000 (15:26 +0000)
committerAdam Bialogonski <adam.b@samsung.com>
Tue, 9 May 2023 11:06:45 +0000 (12:06 +0100)
When any Controller::Create...(...) function is being called, the last arguments takes a pointer to the old object. Originally, the implementation was supposed to use that object in order to recycle it (when possible). That code has never been implemented. This patch adds TryRecycle() method to the Graphics::Resource<> class and calls TryRecycle() if a valid pointer is being passed to the NewObject(). If TryRecycle() returns false (object couldn't be recycled) then original path is taken and new object is created (old is discarded). Otherwise, the object implementation should handle recycling.

The GLES graphics buffer is recycled when:
- The new spec (create info) matches old spec
- There is valid GPU/CPU storage already allocated

For a GPU-allocated buffer, the orphaning takes place. For CPU-allocated buffer, nothing changes.

Change-Id: I5969161c1004b2f0728b5dc9323e6caa88fab84b

automated-tests/src/dali-graphics/CMakeLists.txt
automated-tests/src/dali-graphics/utc-Dali-GraphicsBuffer.cpp [new file with mode: 0644]
dali/internal/graphics/gles-impl/egl-graphics-controller.cpp
dali/internal/graphics/gles-impl/egl-graphics-controller.h
dali/internal/graphics/gles-impl/gles-graphics-buffer.cpp
dali/internal/graphics/gles-impl/gles-graphics-buffer.h
dali/internal/graphics/gles-impl/gles-graphics-resource.h

index 329f8d4..262c656 100644 (file)
@@ -7,6 +7,7 @@ SET(CAPI_LIB "dali-graphics")
 SET(TC_SOURCES
     utc-Dali-GlImplementation.cpp
     utc-Dali-GlesImplementation.cpp
+    utc-Dali-GraphicsBuffer.cpp
     utc-Dali-GraphicsFramebuffer.cpp
     utc-Dali-GraphicsGeometry.cpp
     utc-Dali-GraphicsNativeImage.cpp
diff --git a/automated-tests/src/dali-graphics/utc-Dali-GraphicsBuffer.cpp b/automated-tests/src/dali-graphics/utc-Dali-GraphicsBuffer.cpp
new file mode 100644 (file)
index 0000000..bc7042b
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2023 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.
+ */
+
+#include <dali-test-suite-utils.h>
+#include <dali/dali.h>
+
+#include <dali/internal/graphics/gles-impl/egl-graphics-controller.h>
+#include <test-actor-utils.h>
+#include <test-graphics-application.h>
+#include <test-graphics-framebuffer.h>
+
+using namespace Dali;
+
+namespace
+{
+} // namespace
+
+int UtcDaliBufferReuseTest(void)
+{
+  TestGraphicsApplication app;
+  tet_infoline("UtcDaliBufferReuseTest: Tests whether GLES buffer can be reused (orphaning content)");
+
+  auto& controller = app.GetGraphicsController();
+
+  Graphics::BufferCreateInfo info;
+  info.size            = 1024;
+  info.usage           = 0u | Graphics::BufferUsage::VERTEX_BUFFER;
+  info.propertiesFlags = 0u;
+
+  auto buffer = controller.CreateBuffer(info, nullptr);
+  controller.WaitIdle();
+
+  DALI_TEST_NOT_EQUALS((void*)buffer.get(), (void*)nullptr, 0, TEST_LOCATION);
+
+  // New buffer with different spec, should create new object
+  Graphics::BufferCreateInfo info2;
+  info.size            = 2024;
+  info.usage           = 0u | Graphics::BufferUsage::VERTEX_BUFFER;
+  info.propertiesFlags = 0u;
+
+  auto buffer2 = controller.CreateBuffer(info2, std::move(buffer));
+  controller.WaitIdle();
+
+  DALI_TEST_NOT_EQUALS(buffer.get(), buffer2.get(), 0, TEST_LOCATION);
+
+  auto ptr = buffer2.get(); // store pointer for testing, the uptr will be emptied
+  // Create new buffer using the same spec
+  auto buffer3 = controller.CreateBuffer(info2, std::move(buffer2));
+  controller.WaitIdle();
+
+  DALI_TEST_EQUALS(ptr, buffer3.get(), TEST_LOCATION);
+
+  END_TEST;
+}
index fa90dba..4c02256 100644 (file)
@@ -97,6 +97,24 @@ auto NewObject(const GfxCreateInfo& info, EglGraphicsController& controller, T&&
   }
   else // Use standard allocator
   {
+    // We are given all object for recycling
+    if(oldObject)
+    {
+      auto reusedObject = oldObject.release();
+      // If succeeded, attach the object to the unique_ptr and return it back
+      if(static_cast<GLESType*>(reusedObject)->TryRecycle(info, controller))
+      {
+        return UPtr(reusedObject, GLESDeleter<GLESType>());
+      }
+      else
+      {
+        // can't reuse so kill object by giving it back to original
+        // unique pointer.
+        oldObject.reset(reusedObject);
+      }
+    }
+
+    // Create brand new object
     return UPtr(new GLESType(info, controller), GLESDeleter<GLESType>());
   }
 }
@@ -170,6 +188,11 @@ void EglGraphicsController::SubmitCommandBuffers(const SubmitInfo& submitInfo)
   }
 }
 
+void EglGraphicsController::WaitIdle()
+{
+  Flush();
+}
+
 void EglGraphicsController::PresentRenderTarget(RenderTarget* renderTarget)
 {
   GLES::CommandBuffer* presentCommandBuffer{nullptr};
index 33918b5..a8edd34 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_EGL_GRAPHICS_CONTROLLER_H
 
 /*
- * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2023 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.
@@ -113,9 +113,7 @@ public:
   /**
    * @copydoc Dali::Graphics::WaitIdle()
    */
-  void WaitIdle() override
-  {
-  }
+  void WaitIdle() override;
 
   /**
    * @copydoc Dali::Graphics::Pause()
index ed72c22..f41ca6c 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2023 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.
@@ -50,6 +50,35 @@ Buffer::Buffer(const Graphics::BufferCreateInfo& createInfo, Graphics::EglGraphi
   controller.AddBuffer(*this);
 }
 
+bool Buffer::TryRecycle(const Graphics::BufferCreateInfo& createInfo, Graphics::EglGraphicsController& controller)
+{
+  // Compare whether specs are same and the buffer is allocated
+  mSetForGLRecycling = false;
+
+  // if different buffer spec, we need new buffer
+  if(!(createInfo.size == mCreateInfo.size
+     && createInfo.allocationCallbacks == mCreateInfo.allocationCallbacks
+     && createInfo.propertiesFlags == mCreateInfo.propertiesFlags
+     && createInfo.usage == mCreateInfo.usage
+     && createInfo.nextExtension == mCreateInfo.nextExtension ))
+  {
+    return false;
+  }
+
+  // GL resource hasn't been allocated yet, we need new buffer
+  if(mBufferId == 0)
+  {
+    return false;
+  }
+
+  // Make sure the buffer will be reinitialized
+  controller.AddBuffer(*this);
+
+  mSetForGLRecycling = true;
+
+  return true;
+}
+
 bool Buffer::InitializeResource()
 {
   // CPU allocated uniform buffer is a special "compatibility" mode
@@ -63,6 +92,8 @@ bool Buffer::InitializeResource()
     InitializeGPUBuffer();
   }
 
+  // make sure recycling mode is disabled after (re)initializing resource
+  mSetForGLRecycling = false;
   return true;
 }
 
@@ -71,6 +102,13 @@ void Buffer::InitializeCPUBuffer()
   // Just allocate memory
   // @TODO put better CPU memory management in place
   const auto allocators = GetCreateInfo().allocationCallbacks;
+
+  // Early out if we recycle the buffer
+  if(mBufferPtr && mSetForGLRecycling)
+  {
+    return;
+  }
+
   if(allocators)
   {
     mBufferPtr = allocators->allocCallback(mCreateInfo.size, 0, allocators->userData);
@@ -90,7 +128,11 @@ void Buffer::InitializeGPUBuffer()
     return;
   }
 
-  gl->GenBuffers(1, &mBufferId);
+  // If mBufferId is already set and we recycling the buffer (orphaning)
+  if(!mSetForGLRecycling && !mBufferId)
+  {
+    gl->GenBuffers(1, &mBufferId);
+  }
   context->BindBuffer(GL_ARRAY_BUFFER, mBufferId);
   gl->BufferData(GL_ARRAY_BUFFER, GLsizeiptr(mCreateInfo.size), nullptr, GL_STATIC_DRAW);
 }
index 2e1f96b..3ac11cf 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_GRAPHICS_GLES_BUFFER_H
 
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2023 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.
@@ -56,6 +56,8 @@ public:
 
   void Bind(Graphics::BufferUsage bindingTarget) const;
 
+  bool TryRecycle(const Graphics::BufferCreateInfo& createInfo, Graphics::EglGraphicsController& controller) override;
+
   [[nodiscard]] uint32_t GetGLBuffer() const
   {
     return mBufferId;
@@ -86,6 +88,8 @@ private:
   void*    mBufferPtr{nullptr}; // CPU allocated memory
   bool     mCpuAllocated{false};
   bool     mTransient{false};
+
+  bool     mSetForGLRecycling{false}; ///< If flag set true the buffer will recycle
 };
 } // namespace GLES
 } // namespace Dali::Graphics
index ed0e297..ce4ce04 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_GRAPHICS_GLES_RESOURCE_H
 
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2023 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.
@@ -43,6 +43,22 @@ public:
   }
 
   /**
+   * @brief Tries to recycle Graphics resource
+   *
+   * If False returned, the object must be initialized with use of constructor
+   *
+   * By default, all graphics resources are non-recyclable
+   *
+   * @param[in] createInfo CreateInfo structure of new object
+   * @param[in] controller Reference to the controller
+   * @return True on success, False otherwise
+   */
+  virtual bool TryRecycle(const CreateInfo& createInfo, Graphics::EglGraphicsController& controller)
+  {
+    return false;
+  }
+
+  /**
    * @brief Destructor
    */
   ~Resource() override = default;