+# prebuild test addons
IF( DEFINED MODULE )
MESSAGE(STATUS "Building: ${CMAKE_CURRENT_SOURCE_DIR}/${MODULE}")
ADD_SUBDIRECTORY(${MODULE})
# 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
../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}")
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
--- /dev/null
+SET(ADDON_NAME rendering )
+SET(ADDON_SOURCES ./addons/test-rendering-addon.cpp)
--- /dev/null
+SET(ADDON_NAME sample )
+SET(ADDON_SOURCES ./addons/test-sample-addon.cpp)
\ No newline at end of file
--- /dev/null
+/*
+ * 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 );
--- /dev/null
+/*
+ * 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 );
--- /dev/null
+/*
+ * 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();
+ }
+ }
+}
+
+}
+}
+
--- /dev/null
+#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
--- /dev/null
+/*
+ * 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;
+}
#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
{
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,
{
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;
// 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>
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() );
} // 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()
{
}
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:
// 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>
#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
{
mPlacementActor = actor;
if( data->loadCompleted )
{
+ if( RenderingAddOn::Get().IsValid() )
+ {
+ RenderingAddOn::Get().SubmitRenderTask( mImpl->mRenderer, data->renderingMap );
+ }
+
ApplyTextureAndUniforms();
actor.AddRenderer( mImpl->mRenderer );
mPlacementActor.Reset();
}
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
--- /dev/null
+#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
#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
{
mCurrentTextureId( 0 ),
mQueueLoadFlag(false)
{
+ // Initialize the AddOn
+ RenderingAddOn::Get();
}
TextureManager::~TextureManager()
// 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() );
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
#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>
*/
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:
/**
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
*/