Rendering optimisation with AddOn 28/238028/12
authoradam.b <adam.b@samsung.com>
Tue, 21 Jul 2020 10:34:15 +0000 (11:34 +0100)
committeradam.b <adam.b@samsung.com>
Fri, 24 Jul 2020 11:29:36 +0000 (12:29 +0100)
To enable, the external addon is required.

Change-Id: I932f0fedd157ac00cd6b564ebf7fdb08bd22cc5a

16 files changed:
automated-tests/src/CMakeLists.txt
automated-tests/src/dali-toolkit-internal/CMakeLists.txt
automated-tests/src/dali-toolkit-internal/addons/rendering.cmake [new file with mode: 0644]
automated-tests/src/dali-toolkit-internal/addons/sample.cmake [new file with mode: 0644]
automated-tests/src/dali-toolkit-internal/addons/test-rendering-addon.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit-internal/addons/test-sample-addon.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit-internal/dali-toolkit-test-utils/test-addon-manager.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit-internal/dali-toolkit-test-utils/test-addon-manager.h [new file with mode: 0644]
automated-tests/src/dali-toolkit-internal/utc-Dali-AddOns.cpp [new file with mode: 0644]
dali-toolkit/internal/visuals/image/image-visual.cpp
dali-toolkit/internal/visuals/npatch-loader.cpp
dali-toolkit/internal/visuals/npatch-loader.h
dali-toolkit/internal/visuals/npatch/npatch-visual.cpp
dali-toolkit/internal/visuals/rendering-addon.h [new file with mode: 0644]
dali-toolkit/internal/visuals/texture-manager-impl.cpp
dali-toolkit/internal/visuals/texture-manager-impl.h [changed mode: 0755->0644]

index e4f0a2b..4d59c62 100644 (file)
@@ -1,3 +1,4 @@
+# prebuild test addons
 IF( DEFINED MODULE )
     MESSAGE(STATUS "Building: ${CMAKE_CURRENT_SOURCE_DIR}/${MODULE}")
     ADD_SUBDIRECTORY(${MODULE})
index 4513301..6a94a6f 100755 (executable)
@@ -7,6 +7,7 @@ SET(CAPI_LIB "dali-toolkit-internal")
 
 # List of test case sources (Only these get parsed for test cases)
 SET(TC_SOURCES
+ utc-Dali-AddOns.cpp
  utc-Dali-BidirectionalSupport.cpp
  utc-Dali-ColorConversion.cpp
  utc-Dali-Control-internal.cpp
@@ -73,19 +74,20 @@ LIST(APPEND TC_SOURCES
    ../dali-toolkit/dali-toolkit-test-utils/test-native-image.cpp
    dali-toolkit-test-utils/toolkit-text-utils.cpp
    dali-toolkit-test-utils/dummy-visual.cpp
+   dali-toolkit-test-utils/test-addon-manager.cpp
 )
 
-
 PKG_CHECK_MODULES(${CAPI_LIB} REQUIRED
     dali2-core
     dali2-adaptor
     dali2-toolkit
 )
 
-ADD_COMPILE_OPTIONS( -O0 -ggdb --coverage -Wall -Werror -DDEBUG_ENABLED )
+ADD_COMPILE_OPTIONS( -O0 -ggdb --coverage -Wall -Werror -DDEBUG_ENABLED -fPIC )
 ADD_COMPILE_OPTIONS( ${${CAPI_LIB}_CFLAGS_OTHER} )
 
 ADD_DEFINITIONS(-DTEST_RESOURCE_DIR=\"${CMAKE_CURRENT_SOURCE_DIR}/../../resources\" )
+ADD_DEFINITIONS(-DDALI_ADDONS_PATH=\"${CMAKE_CURRENT_BINARY_DIR}\")
 
 FOREACH(directory ${${CAPI_LIB}_LIBRARY_DIRS})
     SET(CMAKE_CXX_LINK_FLAGS "${CMAKE_CXX_LINK_FLAGS} -L${directory}")
@@ -101,9 +103,42 @@ INCLUDE_DIRECTORIES(
 ADD_EXECUTABLE(${EXEC_NAME} ${EXEC_NAME}.cpp ${TC_SOURCES})
 TARGET_LINK_LIBRARIES(${EXEC_NAME}
     ${${CAPI_LIB}_LIBRARIES}
-    -lpthread --coverage
+    -lpthread --coverage -ldl
 )
 
 INSTALL(PROGRAMS ${EXEC_NAME}
     DESTINATION ${BIN_DIR}/${EXEC_NAME}
 )
+
+# build addons
+MESSAGE( STATUS "BINDIR: ${CMAKE_CURRENT_BINARY_DIR}")
+
+FILE( GLOB FILES ${CMAKE_CURRENT_SOURCE_DIR}/addons/*.cmake )
+
+FOREACH( INFILE IN ITEMS ${FILES} )
+
+    INCLUDE( ${INFILE} )
+    MESSAGE( STATUS "Building ${INFILE}" )
+
+    ADD_LIBRARY( ${ADDON_NAME} SHARED ${ADDON_SOURCES} )
+
+    TARGET_INCLUDE_DIRECTORIES( ${ADDON_NAME} PUBLIC
+            ../../../
+            ${${CAPI_LIB}_INCLUDE_DIRS}
+            ../dali-toolkit/dali-toolkit-test-utils
+            dali-toolkit-test-utils)
+
+    TARGET_LINK_LIBRARIES(${ADDON_NAME}
+            ${CMAKE_CXX_LINK_FLAGS}
+            ${${CAPI_LIB}_LIBRARIES}
+            -lpthread -ldl --coverage
+            )
+
+    INSTALL( TARGETS ${ADDON_NAME} DESTINATION ${BIN_DIR} )
+
+    SET( ADDON_LIST "lib${ADDON_NAME}.so
+${ADDON_LIST}")
+ENDFOREACH()
+
+# store AddOns list
+FILE( WRITE ${CMAKE_CURRENT_BINARY_DIR}/addons.txt "${ADDON_LIST}" )
\ No newline at end of file
diff --git a/automated-tests/src/dali-toolkit-internal/addons/rendering.cmake b/automated-tests/src/dali-toolkit-internal/addons/rendering.cmake
new file mode 100644 (file)
index 0000000..f9e66e1
--- /dev/null
@@ -0,0 +1,2 @@
+SET(ADDON_NAME rendering )
+SET(ADDON_SOURCES ./addons/test-rendering-addon.cpp)
diff --git a/automated-tests/src/dali-toolkit-internal/addons/sample.cmake b/automated-tests/src/dali-toolkit-internal/addons/sample.cmake
new file mode 100644 (file)
index 0000000..1c5d781
--- /dev/null
@@ -0,0 +1,2 @@
+SET(ADDON_NAME sample )
+SET(ADDON_SOURCES ./addons/test-sample-addon.cpp)
\ No newline at end of file
diff --git a/automated-tests/src/dali-toolkit-internal/addons/test-rendering-addon.cpp b/automated-tests/src/dali-toolkit-internal/addons/test-rendering-addon.cpp
new file mode 100644 (file)
index 0000000..6756093
--- /dev/null
@@ -0,0 +1,180 @@
+/*
+ * Copyright (c) 2020 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 HEADERS
+#include <dali/devel-api/addons/addon-base.h>
+#include <dali/devel-api/adaptor-framework/pixel-buffer.h>
+#include <dali/public-api/rendering/geometry.h>
+#include <dali/public-api/rendering/renderer.h>
+
+// INTERNAL HEADERS
+// Needed to access the private class members
+#define private public
+#include <dali-toolkit/internal/visuals/npatch/npatch-visual.h>
+#include <dali-toolkit/internal/visuals/npatch-loader.h>
+#undef private
+
+
+using Dali::Toolkit::Internal::TextureManager;
+
+namespace Dali
+{
+namespace AddOns
+{
+
+struct DummyTiler
+{
+};
+
+void* CreateInstance( TextureManager* textureManager )
+{
+  fprintf(stderr, "AddOn::CreateInstance( %p )\n", textureManager);
+  return new DummyTiler;
+}
+
+namespace GeometryTiler
+{
+std::vector<std::string> gCallStack;
+
+static Geometry GetGeometryInternal(TextureManager::TextureId textureId, uint32_t& o0, uint32_t& o1 )
+{
+  gCallStack.emplace_back( "GetGeometry" );
+  o0 = 10;
+  o1 = 5;
+  fprintf(stderr, "AddOn::GetGeometryInternal()\n");
+  return Dali::Geometry::New();
+}
+
+static Geometry CreateGeometryInternal(TextureManager::TextureId textureId, const Devel::PixelBuffer& pixelBuffer )
+{
+  gCallStack.emplace_back( "CreateGeometry" );
+  fprintf(stderr, "AddOn::CreateGeometryInternal()\n");
+  return Dali::Geometry::New();
+}
+
+static Geometry CreateGeometryMapInternal(const void* opacityMap,
+                                          const Uint16Pair& gridSize,
+                                          uint32_t *outElements)
+{
+  gCallStack.emplace_back( "CreateGeometryGrid" );
+  outElements[0] = 2;
+  outElements[1] = 3;
+  return Dali::Geometry::New();
+}
+
+static void* NPatchBuildInternal(const Devel::PixelBuffer& pixelBuffer, Toolkit::Internal::NPatchLoader::Data* data )
+{
+  gCallStack.emplace_back( "BuildNPatch" );
+  fprintf(stderr, "AddOn::NPatchBuild()\n");
+  static char dummyData;
+  return &dummyData;
+}
+
+static void NPatchDestroyInternal(void* object )
+{
+  gCallStack.emplace_back( "DestroyNPatch" );
+  fprintf(stderr, "AddOn::NPatchDestroy()\n");
+}
+
+static void SubmitInternal(Renderer& renderer, const void* object  )
+{
+  gCallStack.emplace_back( "SubmitRenderTask" );
+  fprintf(stderr, "AddOn::SubmitInternal()\n");
+}
+
+static std::vector<std::string> GetCallStack( bool clear )
+{
+  auto retval = gCallStack;
+  if(clear)
+  {
+    gCallStack.clear();
+  }
+  return retval;
+}
+
+
+}
+}
+}
+
+/**
+ * OverdrawingAddOn implementation
+ */
+class TestRenderingAddOn : public Dali::AddOns::AddOnBase
+{
+public:
+
+  void GetAddOnInfo( Dali::AddOnInfo& info ) override
+  {
+    info.type = Dali::AddOnType::GENERIC;
+    info.name = "oo-rendering";
+    info.version = Dali::DALI_ADDON_VERSION( 1, 0, 0 );
+    info.next = nullptr;
+  }
+
+  /**
+   * Dispatch table for global functions
+   * @return
+   */
+  Dali::AddOns::DispatchTable* GetGlobalDispatchTable() override
+  {
+    static Dali::AddOns::DispatchTable dispatchTable{};
+    if( dispatchTable.Empty() )
+    {
+      dispatchTable["Initialize"]         = Dali::AddOns::CreateInstance;
+      dispatchTable["CreateGeometry"]     = Dali::AddOns::GeometryTiler::CreateGeometryInternal;
+      dispatchTable["GetGeometry"]        = Dali::AddOns::GeometryTiler::GetGeometryInternal;
+      dispatchTable["CreateGeometryGrid"] = Dali::AddOns::GeometryTiler::CreateGeometryMapInternal;
+      dispatchTable["BuildNPatch"]        = Dali::AddOns::GeometryTiler::NPatchBuildInternal;
+      dispatchTable["DestroyNPatch"]      = Dali::AddOns::GeometryTiler::NPatchDestroyInternal;
+      dispatchTable["SubmitRenderTask"]   = Dali::AddOns::GeometryTiler::SubmitInternal;
+      dispatchTable["GetCallStack"]       = Dali::AddOns::GeometryTiler::GetCallStack;
+    }
+    return &dispatchTable;
+  }
+
+  /**
+   * Lifecycle
+   */
+
+  void OnStart() override
+  {
+  }
+
+  void OnStop() override
+  {
+  }
+
+  void OnPause() override
+  {
+  }
+
+  void OnResume() override
+  {
+  }
+
+  /**
+   * Dispatch table for instance functions
+   * @return
+   */
+  Dali::AddOns::DispatchTable* GetInstanceDispatchTable() override
+  {
+    return nullptr;
+  }
+};
+
+REGISTER_ADDON_CLASS( TestRenderingAddOn );
diff --git a/automated-tests/src/dali-toolkit-internal/addons/test-sample-addon.cpp b/automated-tests/src/dali-toolkit-internal/addons/test-sample-addon.cpp
new file mode 100644 (file)
index 0000000..d6f019d
--- /dev/null
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) 2020 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 <cstring>
+#include <dali/devel-api/addons/addon-base.h>
+#include <dali-test-suite-utils.h>
+
+namespace
+{
+bool gIsPaused = false;
+const auto ANSWER_TO_EVERYTHING = 42;
+}
+
+int StringLen( const char* str )
+{
+  return strlen( str );
+}
+
+int DoSum( int a, int b )
+{
+  return a+b;
+}
+
+bool GetLifecycleStatus()
+{
+  return gIsPaused;
+}
+
+struct AddOnDataInstance
+{
+  int GetValue()
+  {
+    return ANSWER_TO_EVERYTHING;
+  }
+
+  static int GetValueWithInstance( AddOnDataInstance* instance )
+  {
+    return instance->GetValue();
+  }
+};
+
+AddOnDataInstance* CreateInstance()
+{
+  return new AddOnDataInstance();
+}
+
+class TestDummyAddOn : public Dali::AddOns::AddOnBase
+{
+public:
+
+  void GetAddOnInfo( Dali::AddOnInfo& info ) override
+  {
+    info.type = Dali::AddOnType::GENERIC;
+    info.name = "SampleAddOn";
+    info.version = Dali::DALI_ADDON_VERSION( 1, 0, 0 );
+    info.next = nullptr;
+    tet_printf( "SampleAddOn: GetAddOnInfo() : name = %s\n", info.name.c_str());
+  }
+
+  /**
+   * Dispatch table for global functions
+   * @return
+   */
+  Dali::AddOns::DispatchTable* GetGlobalDispatchTable() override
+  {
+    static Dali::AddOns::DispatchTable dispatchTable{};
+    if( dispatchTable.Empty() )
+    {
+      dispatchTable["DoSum"]                     = DoSum;
+      dispatchTable["StringLen"]                 = StringLen;
+      dispatchTable["GetLifecycleStatus"]        = GetLifecycleStatus;
+      dispatchTable["CreateInstance"]            = CreateInstance;
+
+    }
+    return &dispatchTable;
+  }
+
+  /**
+   * Lifecycle
+   */
+  void OnStart() override
+  {
+    gIsPaused = false;
+  }
+
+  void OnStop() override
+  {
+    gIsPaused = true;
+  }
+
+  void OnPause() override
+  {
+    gIsPaused = true;
+  }
+
+  void OnResume() override
+  {
+    gIsPaused = false;
+  }
+
+  /**
+   * Dispatch table for instance functions
+   */
+  Dali::AddOns::DispatchTable* GetInstanceDispatchTable() override
+  {
+    static Dali::AddOns::DispatchTable dispatchTable{};
+    if( dispatchTable.Empty() )
+    {
+      dispatchTable["InstanceCall"] = AddOnDataInstance::GetValueWithInstance;
+    }
+    return &dispatchTable;
+  }
+};
+
+REGISTER_ADDON_CLASS( TestDummyAddOn );
diff --git a/automated-tests/src/dali-toolkit-internal/dali-toolkit-test-utils/test-addon-manager.cpp b/automated-tests/src/dali-toolkit-internal/dali-toolkit-test-utils/test-addon-manager.cpp
new file mode 100644 (file)
index 0000000..6bd9682
--- /dev/null
@@ -0,0 +1,222 @@
+/*
+ * Copyright (c) 2020 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 "test-addon-manager.h"
+#include <dali-test-suite-utils.h>
+#include <cstring>
+#include <dlfcn.h>
+
+#ifndef DALI_ADDONS_PATH
+#define DALI_ADDONS_PATH ""
+#endif
+
+namespace Dali
+{
+namespace Test
+{
+
+std::vector<std::string> AddOnManager::EnumerateAddOns()
+{
+  std::string listFileName(DALI_ADDONS_PATH);
+  listFileName += "/addons.txt";
+
+  // Read list of available test addons
+  tet_printf("Enumerating addons, file: %s\n", listFileName.c_str());
+  std::vector<std::string> addons{};
+  auto* fin = fopen( listFileName.c_str(), "r" );
+  char* lineBuf = new char[256];
+  memset( lineBuf, 0, 256 );
+  size_t n = 256;
+  while( getline( &lineBuf, &n, fin ) > 0 )
+  {
+    char* c = lineBuf;
+    while( *c )
+    {
+      if( *c == '\n' || *c == '\r' )
+      {
+        *c = 0;
+        break;
+      }
+      ++c;
+    }
+    tet_printf("Adding %s\n", lineBuf);
+    addons.emplace_back( lineBuf );
+    memset( lineBuf, 0, 256 );
+  }
+  fclose(fin);
+  delete [] lineBuf;
+  std::vector<std::string> retval{};
+  // Open addons
+  for( auto& name : addons )
+  {
+    std::string path(DALI_ADDONS_PATH);
+    path += "/";
+    path += name;
+
+    mAddOnCache.emplace_back();
+    mAddOnCache.back().handle = dlopen( path.c_str(), RTLD_DEEPBIND|RTLD_LAZY );
+    if( !mAddOnCache.back().handle )
+    {
+      mAddOnCache.back().valid = false;
+      tet_printf( "Can't open addon lib: %s, error: '%s'\n", path.c_str(), dlerror());
+      continue;
+    }
+    // Here addon must self register
+    if( !mAddOnCache.back().valid )
+    {
+      puts("Addon invalid!");
+    }
+    else
+    {
+      tet_printf( "Valid AddOn: %s\n", mAddOnCache.back().name.c_str() );
+      retval.emplace_back( mAddOnCache.back().name );
+    }
+  }
+
+  return retval;
+
+  /**
+   * Check for self-registering addons
+   */
+}
+
+void AddOnManager::RegisterAddOnDispatchTable( const AddOnDispatchTable* dispatchTable )
+{
+  // Register the dispatch table
+  auto& entry = mAddOnCache.back();
+  entry.name = dispatchTable->name;
+  tet_printf( "Registering AddOn: %s\n", entry.name.c_str());
+  entry.GetGlobalProc = dispatchTable->GetGlobalProc;
+  entry.GetInstanceProc = dispatchTable->GetInstanceProc;
+  entry.GetAddOnInfo = dispatchTable->GetAddOnInfo;
+  entry.OnStart = dispatchTable->OnStart;
+  entry.OnStop = dispatchTable->OnStop;
+  entry.OnPause = dispatchTable->OnPause;
+  entry.OnResume = dispatchTable->OnResume;
+  entry.valid = true;
+}
+
+bool AddOnManager::GetAddOnInfo(const std::string& name, AddOnInfo& info )
+{
+  auto retval = false;
+  std::find_if( mAddOnCache.begin(), mAddOnCache.end(),
+    [&retval, name, &info]( AddOnCacheEntry& entry )
+  {
+    if(entry.name == name)
+    {
+      entry.GetAddOnInfo( info );
+      retval = true;
+      return true;
+    }
+    return false;
+  });
+  return retval;
+}
+
+std::vector<AddOnLibrary> AddOnManager::LoadAddOns( const std::vector<std::string>& addonNames )
+{
+  if(mAddOnCache.empty())
+  {
+    EnumerateAddOns();
+  }
+
+  std::vector<AddOnLibrary> retval{};
+  for( auto& name : addonNames)
+  {
+    size_t index = 0;
+    auto iter = std::find_if( mAddOnCache.begin(), mAddOnCache.end(),
+      [&retval, name, &index]( AddOnCacheEntry& entry )
+      {
+        index++;
+        if(entry.name == name)
+        {
+          return true;
+        }
+        return false;
+      });
+    if( iter != mAddOnCache.end() )
+    {
+      retval.emplace_back( *reinterpret_cast<void**>( &index ) );
+    }
+    else
+    {
+      retval.emplace_back( nullptr );
+    }
+  }
+
+  return retval;
+}
+
+void* AddOnManager::GetGlobalProc( const Dali::AddOnLibrary& addOnLibrary, const char* procName )
+{
+  auto index = *reinterpret_cast<const size_t*>( &addOnLibrary );
+  return mAddOnCache[index-1].GetGlobalProc( procName );
+}
+
+void* AddOnManager::GetInstanceProc( const Dali::AddOnLibrary& addOnLibrary, const char* procName )
+{
+  auto index = *reinterpret_cast<const size_t*>( &addOnLibrary );
+  return mAddOnCache[index-1].GetInstanceProc( procName );
+}
+
+void AddOnManager::Start()
+{
+  for( auto& entry : mAddOnCache )
+  {
+    if(entry.OnStart)
+    {
+      entry.OnStart();
+    }
+  }
+}
+
+void AddOnManager::Resume()
+{
+  for( auto& entry : mAddOnCache )
+  {
+    if(entry.OnResume)
+    {
+      entry.OnResume();
+    }
+  }
+}
+
+void AddOnManager::Stop()
+{
+  for( auto& entry : mAddOnCache )
+  {
+    if(entry.OnStop)
+    {
+      entry.OnStop();
+    }
+  }
+}
+
+void AddOnManager::Pause()
+{
+  for( auto& entry : mAddOnCache )
+  {
+    if(entry.OnPause)
+    {
+      entry.OnPause();
+    }
+  }
+}
+
+}
+}
+
diff --git a/automated-tests/src/dali-toolkit-internal/dali-toolkit-test-utils/test-addon-manager.h b/automated-tests/src/dali-toolkit-internal/dali-toolkit-test-utils/test-addon-manager.h
new file mode 100644 (file)
index 0000000..e924876
--- /dev/null
@@ -0,0 +1,89 @@
+#ifndef TEST_ADDON_MANAGER_H
+#define TEST_ADDON_MANAGER_H
+
+/*
+ * Copyright (c) 2020 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/integration-api/addon-manager.h>
+#include <dali/public-api/common/vector-wrapper.h>
+#include <string>
+
+namespace Dali
+{
+namespace Test
+{
+class AddOnManager : public Dali::Integration::AddOnManager
+{
+public:
+
+  /**
+   * @brief Constructor, initialised by the Adaptor
+   */
+  AddOnManager() = default;
+
+  /**
+   * @brief Destructor
+   */
+  virtual ~AddOnManager() = default;
+
+  std::vector<std::string> EnumerateAddOns() override;
+
+  bool GetAddOnInfo(const std::string& name, AddOnInfo& info ) override;
+
+  std::vector<AddOnLibrary> LoadAddOns( const std::vector<std::string>& addonNames ) override;
+
+  void* GetGlobalProc( const Dali::AddOnLibrary& addOnLibrary, const char* procName ) override;
+
+  void* GetInstanceProc( const Dali::AddOnLibrary& addOnLibrary, const char* procName ) override;
+
+  void RegisterAddOnDispatchTable( const AddOnDispatchTable* dispatchTable ) override;
+
+  void Start() override;
+
+  void Resume() override;
+
+  void Stop() override;
+
+  void Pause() override;
+
+  struct AddOnCacheEntry
+  {
+    std::string name{};
+    AddOnInfo info{};
+
+    // library handle
+    void* handle {nullptr};
+
+    // main function pointers
+    void(*GetAddOnInfo)(AddOnInfo& ) = nullptr; ///< Returns AddOnInfo structure
+    void*(*GetInstanceProc)( const char* ) = nullptr; ///< Returns pointer of instance function (member funtion)
+    void*(*GetGlobalProc)( const char* ) = nullptr; ///< Returns pointer of global function (non-member function)
+
+    void(*OnStart)() = nullptr;
+    void(*OnResume)() = nullptr;
+    void(*OnPause)() = nullptr;
+    void(*OnStop)() = nullptr;
+
+    bool valid = false;
+  };
+
+  std::vector<AddOnCacheEntry> mAddOnCache;
+};
+} // Namespace Test
+} // namespace Dali
+
+#endif // TEST_ADDON_MANAGER_H
diff --git a/automated-tests/src/dali-toolkit-internal/utc-Dali-AddOns.cpp b/automated-tests/src/dali-toolkit-internal/utc-Dali-AddOns.cpp
new file mode 100644 (file)
index 0000000..195656d
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2020 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 <iostream>
+#include <stdlib.h>
+
+#include <dali-toolkit-test-suite-utils.h>
+#include <dali-toolkit/dali-toolkit.h>
+#include "dali-toolkit-test-utils/test-addon-manager.h"
+#include <toolkit-event-thread-callback.h>
+
+using namespace Dali::Toolkit::Internal;
+
+namespace
+{
+
+const char* TEST_IMAGE_FILE_NAME =  TEST_RESOURCE_DIR "/application-icon-20.png";
+const char* TEST_IMAGE_FILE_NAME_9 =  TEST_RESOURCE_DIR "/heartsframe.9.png";
+
+int CountFunctionCalls( const std::vector<std::string>& callstack, const std::string& function )
+{
+  int counter = 0;
+  std::find_if( callstack.begin(), callstack.end(), [&counter, &function]( const std::string& item )
+  {
+    if( item == function )
+    {
+      counter++;
+    }
+    return false;
+  });
+
+  return counter;
+}
+
+}
+
+int UtcRenderingAddOnTestP(void)
+{
+  Dali::Integration::AddOnManager* addOnManager = new Dali::Test::AddOnManager();
+
+  bool valid = addOnManager->Get() != nullptr;
+  DALI_TEST_EQUALS( valid, true, TEST_LOCATION );
+  auto addon = addOnManager->GetAddOn( "oo-rendering" );
+  auto GetCallStack = addOnManager->GetGlobalProc<std::vector<std::string>(bool)>( addon, "GetCallStack" );
+
+  ToolkitTestApplication application;
+  tet_infoline( "UtcRenderingAddOnTestP" );
+
+  // Load regular image view
+  auto imageView = Dali::Toolkit::ImageView::New( TEST_IMAGE_FILE_NAME );
+  imageView.SetProperty( Actor::Property::SIZE, Vector2( 400.f, 60.f ) );
+  imageView.SetProperty( Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_LEFT );
+  imageView.SetProperty( Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT );
+
+  // Load npatch image view
+  auto imageView2 = Dali::Toolkit::ImageView::New( TEST_IMAGE_FILE_NAME_9 );
+  imageView2.SetProperty( Actor::Property::SIZE, Vector2( 400.f, 60.f ) );
+  imageView2.SetProperty( Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_LEFT );
+  imageView2.SetProperty( Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT );
+
+  application.GetScene().Add( imageView );
+  application.GetScene().Add( imageView2 );
+
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( ::Test::WaitForEventThreadTrigger( 2 ), true, TEST_LOCATION );
+
+  application.SendNotification();
+  application.Render();
+
+  auto callstack = GetCallStack(true);
+
+  DALI_TEST_EQUALS( CountFunctionCalls( callstack, "GetGeometry" ), 2, TEST_LOCATION);
+  DALI_TEST_EQUALS( CountFunctionCalls( callstack, "CreateGeometry" ), 1, TEST_LOCATION);
+  DALI_TEST_EQUALS( CountFunctionCalls( callstack, "CreateGeometryGrid" ), 1, TEST_LOCATION);
+  DALI_TEST_EQUALS( CountFunctionCalls( callstack, "BuildNPatch" ), 1, TEST_LOCATION);
+
+  delete addOnManager;
+
+  END_TEST;
+}
index 23a4793..059e9c8 100644 (file)
@@ -40,6 +40,7 @@
 #include <dali-toolkit/internal/visuals/visual-base-data-impl.h>
 #include <dali-toolkit/internal/visuals/visual-url.h>
 #include <dali-toolkit/internal/visuals/image-visual-shader-factory.h>
+#include <dali/devel-api/rendering/renderer-devel.h>
 
 namespace Dali
 {
@@ -515,7 +516,15 @@ void ImageVisual::CreateRenderer( TextureSet& textureSet )
 
   if( !mImpl->mCustomShader )
   {
-    geometry = CreateGeometry( mFactoryCache, ImageDimensions( 1, 1 ) );
+    TextureManager& textureManager = mFactoryCache.GetTextureManager();
+
+    uint32_t opaqueElementsCount {0u};
+    uint32_t transparentElementsCount {0u};
+    geometry = textureManager.GetRenderGeometry(mTextureId, opaqueElementsCount, transparentElementsCount);
+    if(!opaqueElementsCount && !transparentElementsCount)
+    {
+      geometry = CreateGeometry( mFactoryCache, ImageDimensions( 1, 1 ) );
+    }
 
     shader = mImageVisualShaderFactory.GetShader( mFactoryCache,
                              mImpl->mFlags & Impl::IS_ATLASING_APPLIED,
@@ -850,6 +859,37 @@ void ImageVisual::UploadComplete( bool loadingSuccess, int32_t textureId, Textur
   {
     resourceStatus = Toolkit::Visual::ResourceStatus::FAILED;
   }
+
+  // use geometry if needed
+  if( loadingSuccess )
+  {
+    uint32_t opaqueElements{0u};
+    uint32_t transparentElements{0u};
+    auto geometry = mFactoryCache.GetTextureManager().GetRenderGeometry(mTextureId, opaqueElements, transparentElements);
+    if (mImpl->mRenderer && geometry)
+    {
+      mImpl->mRenderer.SetGeometry(geometry);
+      Dali::DevelRenderer::DrawCommand drawCommand{};
+      drawCommand.drawType = DevelRenderer::DrawType::INDEXED;
+
+      if (opaqueElements)
+      {
+        drawCommand.firstIndex = 0;
+        drawCommand.elementCount = opaqueElements;
+        drawCommand.queue = 0;
+        DevelRenderer::AddDrawCommand(mImpl->mRenderer, drawCommand);
+      }
+
+      if (transparentElements)
+      {
+        drawCommand.firstIndex = opaqueElements;
+        drawCommand.elementCount = transparentElements;
+        drawCommand.queue = 1;
+        DevelRenderer::AddDrawCommand(mImpl->mRenderer, drawCommand);
+      }
+    }
+  }
+
   // Signal to observers ( control ) that resources are ready. Must be all resources.
   ResourceReady( resourceStatus );
   mLoading = false;
index d4a1f0e..2e216f3 100644 (file)
 // CLASS HEADER
 #include <dali-toolkit/internal/visuals/npatch-loader.h>
 
-// EXTERNAL INCLUDES
+// INTERNAL HEADERS
+#include <dali-toolkit/internal/visuals/rendering-addon.h>
+
+// EXTERNAL HEADERS
 #include <dali/devel-api/common/hash.h>
 #include <dali/integration-api/debug.h>
 
@@ -52,6 +55,9 @@ void SetLoadedNPatchData( NPatchLoader::Data* data, Devel::PixelBuffer& pixelBuf
   data->croppedWidth = pixelBuffer.GetWidth();
   data->croppedHeight = pixelBuffer.GetHeight();
 
+  // Create opacity map
+  data->renderingMap = RenderingAddOn::Get().IsValid() ? RenderingAddOn::Get().BuildNPatch(pixelBuffer, data ) : nullptr;
+
   PixelData pixels = Devel::PixelBuffer::Convert( pixelBuffer ); // takes ownership of buffer
 
   Texture texture = Texture::New( TextureType::TEXTURE_2D, pixels.GetPixelFormat(), pixels.GetWidth(), pixels.GetHeight() );
@@ -65,6 +71,15 @@ void SetLoadedNPatchData( NPatchLoader::Data* data, Devel::PixelBuffer& pixelBuf
 
 } // namespace NPatchBuffer
 
+NPatchLoader::Data::~Data()
+{
+  // If there is an opacity map, it has to be destroyed using addon call
+  if( renderingMap )
+  {
+    RenderingAddOn::Get().DestroyNPatch( renderingMap );
+  }
+}
+
 NPatchLoader::NPatchLoader()
 {
 }
index 58bd73f..2c0e852 100644 (file)
@@ -63,18 +63,22 @@ public:
       croppedWidth( 0 ),
       croppedHeight( 0 ),
       border( 0, 0, 0, 0 ),
-      loadCompleted( false )
+      loadCompleted( false ),
+      renderingMap{ nullptr }
     {}
 
-    std::string url;                              ///< Url of the N-Patch
-    TextureSet textureSet;                        ///< Texture containing the cropped image
-    NPatchUtility::StretchRanges stretchPixelsX;  ///< X stretch pixels
-    NPatchUtility::StretchRanges stretchPixelsY;  ///< Y stretch pixels
-    std::size_t hash;                             ///< Hash code for the Url
-    uint32_t croppedWidth;                        ///< Width of the cropped middle part of N-patch
-    uint32_t croppedHeight;                       ///< Height of the cropped middle part of N-patch
-    Rect< int > border;                           ///< The size of the border
-    bool loadCompleted;                           ///< True if the data loading is completed
+    ~Data();
+
+    std::string url;                               ///< Url of the N-Patch
+    TextureSet textureSet;                         ///< Texture containing the cropped image
+    NPatchUtility::StretchRanges stretchPixelsX;   ///< X stretch pixels
+    NPatchUtility::StretchRanges stretchPixelsY;   ///< Y stretch pixels
+    std::size_t hash;                              ///< Hash code for the Url
+    uint32_t croppedWidth;                         ///< Width of the cropped middle part of N-patch
+    uint32_t croppedHeight;                        ///< Height of the cropped middle part of N-patch
+    Rect< int > border;                            ///< The size of the border
+    bool loadCompleted;                            ///< True if the data loading is completed
+    void* renderingMap;                            ///< NPatch rendering data
   };
 
 public:
index 147f88c..ea72d4f 100644 (file)
@@ -20,6 +20,7 @@
 
 // EXTERNAL INCLUDES
 #include <dali/devel-api/object/handle-devel.h>
+#include <dali/devel-api/rendering/renderer-devel.h>
 #include <dali/devel-api/adaptor-framework/image-loading.h>
 #include <dali/integration-api/debug.h>
 
@@ -33,6 +34,7 @@
 #include <dali-toolkit/internal/visuals/visual-string-constants.h>
 #include <dali-toolkit/internal/visuals/visual-base-impl.h>
 #include <dali-toolkit/internal/visuals/visual-base-data-impl.h>
+#include <dali-toolkit/internal/visuals/rendering-addon.h>
 
 namespace Dali
 {
@@ -403,6 +405,11 @@ void NPatchVisual::DoSetOnStage( Actor& actor )
     mPlacementActor = actor;
     if( data->loadCompleted )
     {
+      if( RenderingAddOn::Get().IsValid() )
+      {
+        RenderingAddOn::Get().SubmitRenderTask( mImpl->mRenderer, data->renderingMap );
+      }
+
       ApplyTextureAndUniforms();
       actor.AddRenderer( mImpl->mRenderer );
       mPlacementActor.Reset();
@@ -486,13 +493,30 @@ Geometry NPatchVisual::CreateGeometry()
       }
       else
       {
-        geometry = GetNinePatchGeometry( VisualFactoryCache::NINE_PATCH_GEOMETRY );
+        if( data->renderingMap )
+        {
+          uint32_t elementCount[2];
+          geometry = RenderingAddOn::Get().CreateGeometryGrid(data->renderingMap, Uint16Pair(3, 3), elementCount );
+        }
+        else
+        {
+          geometry = GetNinePatchGeometry( VisualFactoryCache::NINE_PATCH_GEOMETRY );
+        }
       }
     }
     else if( data->stretchPixelsX.Size() > 0 || data->stretchPixelsY.Size() > 0)
     {
       Uint16Pair gridSize( 2 * data->stretchPixelsX.Size() + 1,  2 * data->stretchPixelsY.Size() + 1 );
-      geometry = !mBorderOnly ? CreateGridGeometry( gridSize ) : CreateBorderGeometry( gridSize );
+      if( !data->renderingMap )
+      {
+        geometry = !mBorderOnly ? CreateGridGeometry( gridSize ) : CreateBorderGeometry( gridSize );
+      }
+      else
+      {
+        uint32_t elementCount[2];
+        geometry = !mBorderOnly ?
+                   RenderingAddOn::Get().CreateGeometryGrid(data->renderingMap, gridSize, elementCount ) : CreateBorderGeometry(gridSize );
+      }
     }
   }
   else
diff --git a/dali-toolkit/internal/visuals/rendering-addon.h b/dali-toolkit/internal/visuals/rendering-addon.h
new file mode 100644 (file)
index 0000000..5d39f97
--- /dev/null
@@ -0,0 +1,93 @@
+#ifndef DALI_CMAKE_RENDERING_ADDON_H
+#define DALI_CMAKE_RENDERING_ADDON_H
+
+/*
+* Copyright (c) 2020 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/devel-api/common/addon-binder.h>
+#include <dali-toolkit/internal/visuals/npatch/npatch-visual.h>
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Internal
+{
+
+/**
+ * Interface of Overdrawing AddOn
+ */
+class RenderingAddOn : public Dali::AddOn::AddOnBinder
+{
+  using TextureManager = Dali::Toolkit::Internal::TextureManager;
+public:
+  RenderingAddOn() : Dali::AddOn::AddOnBinder( "oo-rendering", 0u )
+  {}
+
+  // Bind AddOn functions
+  ADDON_BIND_FUNCTION(
+    GetGeometry,
+    Dali::Geometry(TextureManager::TextureId, uint32_t&, uint32_t& ) );
+
+  ADDON_BIND_FUNCTION(
+    CreateGeometry,
+    Dali::Geometry( TextureManager::TextureId, const Dali::Devel::PixelBuffer& pixelBuffer ) );
+
+  ADDON_BIND_FUNCTION(
+    Initialize,
+    void*() );
+
+  ADDON_BIND_FUNCTION(
+    CreateGeometryGrid,
+    Dali::Geometry( const void*, const Uint16Pair&, uint32_t*) );
+
+  ADDON_BIND_FUNCTION(
+    SubmitRenderTask,
+    void( Renderer&, const void* ) );
+
+  ADDON_BIND_FUNCTION(
+    BuildNPatch,
+    void*( const Devel::PixelBuffer&, void*) );
+
+  ADDON_BIND_FUNCTION(
+    DestroyNPatch,
+    void( void* ) );
+
+  /**
+   * Single instance of the addon
+   * @return
+   */
+  static RenderingAddOn& Get()
+  {
+    static RenderingAddOn* addon = nullptr;
+    if( !addon )
+    {
+      addon = new RenderingAddOn();
+      if(addon->IsValid())
+      {
+        addon->Initialize();
+      }
+    }
+    return *addon;
+  }
+};
+
+} // Internal
+} // Toolkit
+} // Dali
+
+#endif //DALI_CMAKE_RENDERING_ADDON_H
index e23290b..64bbb5b 100644 (file)
 #include <dali/devel-api/common/hash.h>
 #include <dali/devel-api/adaptor-framework/pixel-buffer.h>
 #include <dali/integration-api/debug.h>
+#include <dali/public-api/rendering/geometry.h>
 
 // INTERNAL HEADERS
 #include <dali-toolkit/internal/image-loader/image-atlas-impl.h>
 #include <dali-toolkit/public-api/image-loader/sync-image-loader.h>
 #include <dali-toolkit/internal/visuals/image-atlas-manager.h>
+#include <dali-toolkit/internal/visuals/rendering-addon.h>
 
 namespace
 {
@@ -133,6 +135,8 @@ TextureManager::TextureManager()
   mCurrentTextureId( 0 ),
   mQueueLoadFlag(false)
 {
+  // Initialize the AddOn
+  RenderingAddOn::Get();
 }
 
 TextureManager::~TextureManager()
@@ -1048,6 +1052,12 @@ void TextureManager::UploadTexture( Devel::PixelBuffer& pixelBuffer, TextureInfo
     // Check if this pixelBuffer is premultiplied
     textureInfo.preMultiplied = pixelBuffer.IsAlphaPreMultiplied();
 
+    auto& renderingAddOn = RenderingAddOn::Get();
+    if( renderingAddOn.IsValid() )
+    {
+      renderingAddOn.CreateGeometry( textureInfo.textureId, pixelBuffer );
+    }
+
     Texture texture = Texture::New( Dali::TextureType::TEXTURE_2D, pixelBuffer.GetPixelFormat(),
                                     pixelBuffer.GetWidth(), pixelBuffer.GetHeight() );
 
@@ -1373,6 +1383,13 @@ void TextureManager::SetBrokenImageUrl(const std::string& brokenImageUrl)
   mBrokenImageUrl = brokenImageUrl;
 }
 
+Geometry TextureManager::GetRenderGeometry(TextureId textureId, uint32_t& frontElements, uint32_t& backElements )
+{
+  return RenderingAddOn::Get().IsValid() ?
+         RenderingAddOn::Get().GetGeometry( textureId, frontElements, backElements) :
+         Geometry();
+}
+
 } // namespace Internal
 
 } // namespace Toolkit
old mode 100755 (executable)
new mode 100644 (file)
index c3cd015..2ad0225
@@ -27,6 +27,7 @@
 #include <dali/public-api/rendering/texture-set.h>
 #include <dali/devel-api/common/owner-container.h>
 #include <dali/devel-api/adaptor-framework/pixel-buffer.h>
+#include <dali/public-api/rendering/geometry.h>
 
 // INTERNAL INCLUDES
 #include <dali-toolkit/devel-api/image-loader/async-image-loader-devel.h>
@@ -426,6 +427,15 @@ public:
    */
   void SetBrokenImageUrl(const std::string& brokenImageUrl);
 
+  /**
+   * @brief Returns the geometry associated with texture.
+   * @param[in] textureId Id of the texture
+   * @param[out] frontElements number of front elements
+   * @param[out] backElements number of back elements
+   * @return Returns valid geometry object
+   */
+  Geometry GetRenderGeometry(TextureId textureId, uint32_t& frontElements, uint32_t& backElements );
+
 private:
 
   /**
@@ -690,6 +700,14 @@ private:
   void UploadTexture( Devel::PixelBuffer& pixelBuffer, TextureInfo& textureInfo );
 
   /**
+   * Creates tiled geometry of for the texture which separates fully-opaque
+   * tiles from ones which use transparency.
+   * @param pixelBuffer
+   * @param textureInfo
+   */
+  bool CreateTiledGeometry( const Devel::PixelBuffer& pixelBuffer, TextureInfo& textureInfo );
+
+  /**
    * Mark the texture as complete, and inform observers
    * @param[in] textureInfo The struct associated with this Texture
    */