Make PixelData flag that we release buffer after texture upload 15/303915/2
authorEunki, Hong <eunkiki.hong@samsung.com>
Mon, 8 Jan 2024 01:21:12 +0000 (10:21 +0900)
committerEunki, Hong <eunkiki.hong@samsung.com>
Mon, 8 Jan 2024 14:06:22 +0000 (23:06 +0900)
Let we support to release pixel data memory automatically after upload finished.
And also, let we make new PixelBuffer::Convert API with this flag.

Change-Id: I9537da4d10a59bdb4c6cd12ea3d62463455399a3
Signed-off-by: Eunki, Hong <eunkiki.hong@samsung.com>
automated-tests/src/dali-adaptor/dali-test-suite-utils/test-graphics-texture.cpp
automated-tests/src/dali-adaptor/utc-Dali-PixelBuffer.cpp
dali/devel-api/adaptor-framework/pixel-buffer.cpp
dali/devel-api/adaptor-framework/pixel-buffer.h
dali/internal/graphics/gles-impl/egl-graphics-controller.cpp
dali/internal/imaging/common/pixel-buffer-impl.cpp
dali/internal/imaging/common/pixel-buffer-impl.h

index 30a759d..4950bbd 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2023 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2024 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.
@@ -15,6 +15,7 @@
  */
 
 #include "test-graphics-texture.h"
+#include <dali/integration-api/pixel-data-integ.h>
 #include <iostream>
 #include <sstream>
 
@@ -935,26 +936,74 @@ void TestGraphicsTexture::Update(Graphics::TextureUpdateInfo updateInfo, Graphic
                         updateInfo.srcExtent2D.width != (mCreateInfo.size.width / (1 << updateInfo.level)) ||
                         updateInfo.srcExtent2D.height != (mCreateInfo.size.height / (1 << updateInfo.level)));
 
+  uint8_t* pixels        = nullptr;
+  bool     releasePixels = false;
+
+  switch(source.sourceType)
+  {
+    case Graphics::TextureUpdateSourceInfo::Type::PIXEL_DATA:
+    {
+      auto pixelDataBuffer = Dali::Integration::GetPixelDataBuffer(source.pixelDataSource.pixelData);
+
+      pixels        = pixelDataBuffer.buffer;
+      releasePixels = Dali::Integration::IsPixelDataReleaseAfterUpload(source.pixelDataSource.pixelData) && updateInfo.srcOffset == 0u;
+      break;
+    }
+    case Graphics::TextureUpdateSourceInfo::Type::MEMORY:
+    {
+      pixels        = reinterpret_cast<uint8_t*>(source.memorySource.memory);
+      releasePixels = true;
+      break;
+    }
+    default:
+    {
+      // TODO : Implement here
+      break;
+    }
+  }
+
   if(!isSubImage)
   {
     if(!mIsCompressed)
     {
-      mGlAbstraction.TexImage2D(target, updateInfo.level, mGlInternalFormat, updateInfo.srcExtent2D.width, updateInfo.srcExtent2D.height, 0, mGlFormat, mPixelDataType, source.memorySource.memory);
+      mGlAbstraction.TexImage2D(target, updateInfo.level, mGlInternalFormat, updateInfo.srcExtent2D.width, updateInfo.srcExtent2D.height, 0, mGlFormat, mPixelDataType, pixels);
     }
     else
     {
-      mGlAbstraction.CompressedTexImage2D(target, updateInfo.level, mGlInternalFormat, updateInfo.srcExtent2D.width, updateInfo.srcExtent2D.height, 0, updateInfo.srcSize, source.memorySource.memory);
+      mGlAbstraction.CompressedTexImage2D(target, updateInfo.level, mGlInternalFormat, updateInfo.srcExtent2D.width, updateInfo.srcExtent2D.height, 0, updateInfo.srcSize, pixels);
     }
   }
   else
   {
     if(!mIsCompressed)
     {
-      mGlAbstraction.TexSubImage2D(target, updateInfo.level, updateInfo.dstOffset2D.x, updateInfo.dstOffset2D.y, updateInfo.srcExtent2D.width, updateInfo.srcExtent2D.height, mGlFormat, mPixelDataType, source.memorySource.memory);
+      mGlAbstraction.TexSubImage2D(target, updateInfo.level, updateInfo.dstOffset2D.x, updateInfo.dstOffset2D.y, updateInfo.srcExtent2D.width, updateInfo.srcExtent2D.height, mGlFormat, mPixelDataType, pixels);
     }
     else
     {
-      mGlAbstraction.CompressedTexSubImage2D(target, updateInfo.level, updateInfo.dstOffset2D.x, updateInfo.dstOffset2D.y, updateInfo.srcExtent2D.width, updateInfo.srcExtent2D.height, mGlFormat, updateInfo.srcSize, source.memorySource.memory);
+      mGlAbstraction.CompressedTexSubImage2D(target, updateInfo.level, updateInfo.dstOffset2D.x, updateInfo.dstOffset2D.y, updateInfo.srcExtent2D.width, updateInfo.srcExtent2D.height, mGlFormat, updateInfo.srcSize, pixels);
+    }
+  }
+
+  if(releasePixels && pixels != nullptr)
+  {
+    switch(source.sourceType)
+    {
+      case Graphics::TextureUpdateSourceInfo::Type::PIXEL_DATA:
+      {
+        Dali::Integration::ReleasePixelDataBuffer(source.pixelDataSource.pixelData);
+        break;
+      }
+      case Graphics::TextureUpdateSourceInfo::Type::MEMORY:
+      {
+        free(reinterpret_cast<void*>(pixels));
+        break;
+      }
+      default:
+      {
+        // TODO : Implement here
+        break;
+      }
     }
   }
 }
index 2c74145..e435ed7 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2024 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.
@@ -244,7 +244,7 @@ int UtcDaliPixelBufferNew01N(void)
   END_TEST;
 }
 
-int UtcDaliPixelBufferConvert(void)
+int UtcDaliPixelBufferConvert01(void)
 {
   TestApplication    application;
   TestGlAbstraction& gl           = application.GetGlAbstraction();
@@ -294,6 +294,56 @@ int UtcDaliPixelBufferConvert(void)
   END_TEST;
 }
 
+int UtcDaliPixelBufferConvert02(void)
+{
+  TestApplication    application;
+  TestGlAbstraction& gl           = application.GetGlAbstraction();
+  TraceCallStack&    textureTrace = gl.GetTextureTrace();
+  textureTrace.Enable(true);
+
+  Devel::PixelBuffer pixbuf = Devel::PixelBuffer::New(10, 10, Pixel::RGB565);
+  FillCheckerboard(pixbuf);
+
+  {
+    Devel::PixelBuffer pixbufPrime = pixbuf; // store a second handle to the data
+
+    Dali::PixelData pixelData = Devel::PixelBuffer::Convert(pixbuf, true);
+    DALI_TEST_CHECK(!pixbuf);
+
+    // check the buffer in the second handle is empty
+    DALI_TEST_CHECK(pixbufPrime.GetBuffer() == NULL);
+
+    DALI_TEST_CHECK(pixelData);
+    DALI_TEST_EQUALS(pixelData.GetWidth(), 10, TEST_LOCATION);
+    DALI_TEST_EQUALS(pixelData.GetHeight(), 10, TEST_LOCATION);
+    DALI_TEST_EQUALS(pixelData.GetStride(), 10, TEST_LOCATION);
+    DALI_TEST_EQUALS(pixelData.GetPixelFormat(), Pixel::RGB565, TEST_LOCATION);
+
+    // Try drawing it
+    Texture t = Texture::New(TextureType::TEXTURE_2D, Pixel::RGB565, 10, 10);
+    t.Upload(pixelData);
+    TextureSet ts = TextureSet::New();
+    ts.SetTexture(0, t);
+    Geometry g = CreateQuadGeometry();
+    Shader   s = Shader::New("v", "f");
+    Renderer r = Renderer::New(g, s);
+    r.SetTextures(ts);
+    Actor a = Actor::New();
+    a.AddRenderer(r);
+    a.SetProperty(Actor::Property::SIZE, Vector2(10, 10));
+    a.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
+    application.GetScene().Add(a);
+
+    application.SendNotification();
+    application.Render();
+    DALI_TEST_EQUALS(textureTrace.FindMethod("BindTexture"), true, TEST_LOCATION);
+
+    // Let secondary scope destroy pixbufPrime
+  }
+
+  END_TEST;
+}
+
 int UtcDaliPixelBufferGetWidth(void)
 {
   TestApplication    application;
index e391463..4000b4f 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2024 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.
@@ -39,8 +39,12 @@ PixelBuffer PixelBuffer::New(uint32_t            width,
 
 Dali::PixelData PixelBuffer::Convert(PixelBuffer& pixelBuffer)
 {
-  Dali::PixelData pixelData =
-    Internal::Adaptor::PixelBuffer::Convert(GetImplementation(pixelBuffer));
+  return Convert(pixelBuffer, false);
+}
+
+Dali::PixelData PixelBuffer::Convert(PixelBuffer& pixelBuffer, bool releaseAfterUpload)
+{
+  Dali::PixelData pixelData = Internal::Adaptor::PixelBuffer::Convert(GetImplementation(pixelBuffer), releaseAfterUpload);
   pixelBuffer.Reset();
   return pixelData;
 }
index 40f3eae..2d768c0 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_PIXEL_BUFFER_H
 
 /*
- * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2024 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.
@@ -128,6 +128,20 @@ public:
   static PixelData Convert(PixelBuffer& pixelBuffer);
 
   /**
+   * Convert to a pixel data and release the pixelBuffer's object.
+   * This handle is left empty.
+   *
+   * @warning Any other handles that keep a reference to this object
+   * will be left with no buffer, trying to access it will return NULL.
+   *
+   * @SINCE_2_3.6
+   * @param[in,out] pixelBuffer
+   * @param[in] releaseAfterUpload Whether converted PixelData released after upload or not.
+   * @return a new PixelData which takes ownership of the PixelBuffer's buffer.
+   */
+  static PixelData Convert(PixelBuffer& pixelBuffer, bool releaseAfterUpload);
+
+  /**
    * Copy the data from this object into a new PixelData object, which could be
    * used for uploading to a texture.
    * @return a new PixelData object containing a copy of this pixel buffer's data.
index b211897..fef6d60 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2023 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2024 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.
@@ -748,17 +748,19 @@ void EglGraphicsController::ProcessTextureUpdateQueue()
                               info.srcExtent2D.width != (createInfo.size.width / (1 << info.level)) ||
                               info.srcExtent2D.height != (createInfo.size.height / (1 << info.level)));
 
-        uint8_t* sourceBuffer;
+        uint8_t* sourceBuffer                = nullptr;
+        bool     sourceBufferReleaseRequired = false;
         if(source.sourceType == Graphics::TextureUpdateSourceInfo::Type::MEMORY)
         {
-          sourceBuffer = reinterpret_cast<uint8_t*>(source.memorySource.memory);
+          sourceBuffer                = reinterpret_cast<uint8_t*>(source.memorySource.memory);
+          sourceBufferReleaseRequired = true;
         }
         else
         {
-          // Get buffer of PixelData
           Dali::Integration::PixelDataBuffer pixelBufferData = Dali::Integration::GetPixelDataBuffer(source.pixelDataSource.pixelData);
 
-          sourceBuffer = pixelBufferData.buffer + info.srcOffset;
+          sourceBuffer                = pixelBufferData.buffer + info.srcOffset;
+          sourceBufferReleaseRequired = Dali::Integration::IsPixelDataReleaseAfterUpload(source.pixelDataSource.pixelData) && info.srcOffset == 0u;
         }
 
         auto                 sourceStride = info.srcStride;
@@ -847,10 +849,16 @@ void EglGraphicsController::ProcessTextureUpdateQueue()
           }
         }
 
-        if(source.sourceType == Graphics::TextureUpdateSourceInfo::Type::MEMORY)
+        if(sourceBufferReleaseRequired && sourceBuffer != nullptr)
         {
-          // free staging memory
-          free(source.memorySource.memory);
+          if(source.sourceType == Graphics::TextureUpdateSourceInfo::Type::MEMORY)
+          {
+            free(reinterpret_cast<void*>(sourceBuffer));
+          }
+          else
+          {
+            Dali::Integration::ReleasePixelDataBuffer(source.pixelDataSource.pixelData);
+          }
         }
         break;
       }
index 31b7f0f..3afdce5 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2023 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2024 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.
@@ -19,6 +19,7 @@
 #include <dali/internal/imaging/common/pixel-buffer-impl.h>
 
 // EXTERNAL INCLUDES
+#include <dali/integration-api/pixel-data-integ.h>
 #include <stdlib.h>
 #include <cstring>
 
@@ -102,23 +103,37 @@ PixelBufferPtr PixelBuffer::New(uint8_t*            buffer,
   return new PixelBuffer(buffer, bufferSize, width, height, stride, pixelFormat);
 }
 
-Dali::PixelData PixelBuffer::Convert(PixelBuffer& pixelBuffer)
+Dali::PixelData PixelBuffer::Convert(PixelBuffer& pixelBuffer, bool releaseAfterUpload)
 {
 #if defined(DEBUG_ENABLED)
   gPixelBufferAllocationTotal -= pixelBuffer.mBufferSize;
 #endif
-  Dali::PixelData pixelData = Dali::PixelData::New(pixelBuffer.mBuffer,
-                                                   pixelBuffer.mBufferSize,
-                                                   pixelBuffer.mWidth,
-                                                   pixelBuffer.mHeight,
-                                                   pixelBuffer.mStride,
-                                                   pixelBuffer.mPixelFormat,
-                                                   Dali::PixelData::FREE);
-  pixelBuffer.mBuffer       = NULL;
-  pixelBuffer.mWidth        = 0;
-  pixelBuffer.mHeight       = 0;
-  pixelBuffer.mBufferSize   = 0;
-  pixelBuffer.mStride       = 0;
+  Dali::PixelData pixelData;
+  if(releaseAfterUpload)
+  {
+    pixelData = Dali::Integration::NewPixelDataWithReleaseAfterUpload(pixelBuffer.mBuffer,
+                                                                      pixelBuffer.mBufferSize,
+                                                                      pixelBuffer.mWidth,
+                                                                      pixelBuffer.mHeight,
+                                                                      pixelBuffer.mStride,
+                                                                      pixelBuffer.mPixelFormat,
+                                                                      Dali::PixelData::FREE);
+  }
+  else
+  {
+    pixelData = Dali::PixelData::New(pixelBuffer.mBuffer,
+                                     pixelBuffer.mBufferSize,
+                                     pixelBuffer.mWidth,
+                                     pixelBuffer.mHeight,
+                                     pixelBuffer.mStride,
+                                     pixelBuffer.mPixelFormat,
+                                     Dali::PixelData::FREE);
+  }
+  pixelBuffer.mBuffer     = NULL;
+  pixelBuffer.mWidth      = 0;
+  pixelBuffer.mHeight     = 0;
+  pixelBuffer.mBufferSize = 0;
+  pixelBuffer.mStride     = 0;
 
   return pixelData;
 }
@@ -240,6 +255,7 @@ void PixelBuffer::ReleaseBuffer()
     gPixelBufferAllocationTotal -= mBufferSize;
 #endif
     free(mBuffer);
+    mBuffer = nullptr;
   }
 }
 
@@ -325,6 +341,10 @@ bool PixelBuffer::Rotate(Degree angle)
     pixelsOut   = nullptr;
     mBufferSize = mWidth * mHeight * pixelSize;
     mStride     = mWidth; // The buffer is tightly packed.
+
+#if defined(DEBUG_ENABLED)
+    gPixelBufferAllocationTotal += mBufferSize;
+#endif
   }
 
   return success;
index 45ff5dd..d9898bf 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_INTERNAL_ADAPTOR_PIXEL_BUFFER_H
 
 /*
- * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2024 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,10 @@ public:
    * The new object takes ownership of the buffer data, and the
    * mBuffer pointer is reset to NULL.
    * @param[in] pixelBuffer The buffer to convert
+   * @param[in] releaseAfterUpload Whether converted PixelData released after upload or not.
    * @return the pixelData
    */
-  static Dali::PixelData Convert(PixelBuffer& pixelBuffer);
+  static Dali::PixelData Convert(PixelBuffer& pixelBuffer, bool releaseAfterUpload);
 
   /**
    * @brief Constructor.