Shader binary synchronous simplified IO 87/42487/14
authorAndrew Cox <andrew.cox@partner.samsung.com>
Fri, 12 Jun 2015 19:23:55 +0000 (20:23 +0100)
committerAndrew Cox <andrew.cox@partner.samsung.com>
Mon, 13 Jul 2015 11:21:28 +0000 (12:21 +0100)
Loading shader binaries synchronously on event thread.
Saving shader binaries from ShaderFactory on event thread.
Deleted old resource sytem based shader binary loading.

Change-Id: I38a79a7b4e9eb33d9a5059f1c43d9e8c892b0867
Signed-off-by: Andrew Cox <andrew.cox@partner.samsung.com>
33 files changed:
automated-tests/src/dali-internal/utc-Dali-Internal-ResourceClient.cpp
automated-tests/src/dali/dali-test-suite-utils/test-platform-abstraction.cpp
automated-tests/src/dali/dali-test-suite-utils/test-platform-abstraction.h
dali/integration-api/file.list
dali/integration-api/platform-abstraction.h
dali/integration-api/resource-types.h
dali/integration-api/shader-data.cpp [new file with mode: 0644]
dali/integration-api/shader-data.h
dali/internal/common/core-impl.cpp
dali/internal/common/shader-saver.h [new file with mode: 0644]
dali/internal/event/effects/shader-effect-impl.cpp
dali/internal/event/effects/shader-effect-impl.h
dali/internal/event/effects/shader-factory.cpp
dali/internal/event/effects/shader-factory.h
dali/internal/event/images/image-factory.h
dali/internal/event/rendering/shader-impl.cpp
dali/internal/event/rendering/shader-impl.h
dali/internal/event/resources/resource-client.cpp
dali/internal/event/resources/resource-client.h
dali/internal/event/resources/resource-type-path-id-map.h [deleted file]
dali/internal/event/resources/resource-type-path.cpp
dali/internal/render/common/render-manager.cpp
dali/internal/render/common/render-manager.h
dali/internal/render/gl-resources/bitmap-texture.cpp
dali/internal/render/shaders/program-controller.cpp
dali/internal/render/shaders/program-controller.h
dali/internal/render/shaders/program.cpp
dali/internal/render/shaders/scene-graph-shader.cpp
dali/internal/render/shaders/scene-graph-shader.h
dali/internal/update/manager/update-manager.cpp
dali/internal/update/manager/update-manager.h
dali/internal/update/resources/resource-manager.cpp
dali/internal/update/resources/resource-manager.h

index a0aecc6..3ea4b7f 100644 (file)
@@ -801,57 +801,6 @@ int UtcDaliInternalRequestResourceTicket02(void)
   END_TEST;
 }
 
-int UtcDaliInternalLoadShaderRequest01(void)
-{
-  TestApplication application;
-  tet_infoline("Testing LoadShader() success");
-  testTicketObserver.Reset();
-
-  // Clear through all of the outstanding shader load requests from the default shader effect
-  std::vector< unsigned char > buffer;
-  for( int i=0; i<10; i++ )
-  {
-    buffer.push_back((unsigned char)i);
-  }
-  application.GetPlatform().SetLoadFileResult( true, buffer );
-  application.GetGlAbstraction().SetLinkStatus(1);
-  application.SendNotification(); // Flush update messages
-  application.Render();           // Process load shader request (immediately)
-  application.SendNotification();
-  application.Render();
-  application.SendNotification();
-  application.Render();
-  application.SendNotification();
-
-  Internal::ResourceClient& resourceClient = Internal::ThreadLocalStorage::Get().GetResourceClient();
-
-  Integration::ShaderResourceType shaderRequest(123, "vertex src", "frag src");
-  std::string shaderBinaryFile("shader.bin");
-  Internal::ResourceTicketPtr ticket = resourceClient.LoadShader(shaderRequest, shaderBinaryFile);
-  DALI_TEST_CHECK( ticket );
-
-  application.GetPlatform().SetLoadFileResult( true, buffer );
-  application.GetGlAbstraction().EnableShaderCallTrace( true );
-  application.GetGlAbstraction().SetLinkStatus(1);
-
-  application.SendNotification(); // Flush update messages
-  application.Render();           // Process load shader request (immediately)
-
-  application.SendNotification();
-  application.Render();
-
-  application.SendNotification();
-  application.Render();
-
-  // If shader program loads OK, we shouldn't see any calls to CompileShader or SaveResource
-  TraceCallStack& shaderTrace = application.GetGlAbstraction().GetShaderTrace();
-  DALI_TEST_CHECK( ! shaderTrace.FindMethod("CompileShader") );
-
-  // Ensure no request sent to platform abstraction
-  DALI_TEST_CHECK( ! application.GetPlatform().WasCalled(TestPlatformAbstraction::SaveResourceFunc ) );
-  END_TEST;
-}
-
 int UtcDaliInternalAllocateBitmapImage01(void)
 {
   TestApplication application;
index 51edfdd..fb31688 100644 (file)
@@ -208,7 +208,7 @@ void TestPlatformAbstraction::SetDpi (unsigned int dpiHorizontal, unsigned int d
 /**
  * @copydoc PlatformAbstraction::LoadFile()
  */
-bool TestPlatformAbstraction::LoadFile( const std::string& filename, std::vector< unsigned char >& buffer ) const
+bool TestPlatformAbstraction::LoadFile( const std::string& filename, Dali::Vector< unsigned char >& buffer ) const
 {
   mTrace.PushCall("LoadFile", "");
   if( mLoadFileResult.loadResult )
@@ -220,11 +220,11 @@ bool TestPlatformAbstraction::LoadFile( const std::string& filename, std::vector
 }
 
 /**
- * @copydoc PlatformAbstraction::LoadShaderBinFile()
+ * @copydoc PlatformAbstraction::LoadShaderBinaryFile()
  */
-bool TestPlatformAbstraction::LoadShaderBinFile( const std::string& filename, std::vector< unsigned char >& buffer ) const
+bool TestPlatformAbstraction::LoadShaderBinaryFile( const std::string& filename, Dali::Vector< unsigned char >& buffer ) const
 {
-  mTrace.PushCall("LoadShaderBinFile", "");
+  mTrace.PushCall("LoadShaderBinaryFile", "");
   if( mLoadFileResult.loadResult )
   {
     buffer = mLoadFileResult.buffer;
@@ -236,7 +236,7 @@ bool TestPlatformAbstraction::LoadShaderBinFile( const std::string& filename, st
 /**
  * @copydoc PlatformAbstraction::SaveFile()
  */
-bool TestPlatformAbstraction::SaveFile(const std::string& filename, std::vector< unsigned char >& buffer) const
+bool TestPlatformAbstraction::SaveFile(const std::string& filename, const unsigned char * buffer, unsigned int numBytes ) const
 {
   mTrace.PushCall("SaveFile", "");
   return false;
@@ -359,7 +359,7 @@ void TestPlatformAbstraction::SetClosestImageSize(const Vector2& size)
   mClosestSize = size;
 }
 
-void TestPlatformAbstraction::SetLoadFileResult( bool result, std::vector< unsigned char >& buffer )
+void TestPlatformAbstraction::SetLoadFileResult( bool result, Dali::Vector< unsigned char >& buffer )
 {
   mLoadFileResult.loadResult = result;
   if( result )
index 6c525fc..fc66701 100644 (file)
@@ -68,7 +68,7 @@ public:
     }
 
     bool loadResult;
-    std::vector< unsigned char> buffer;
+    Dali::Vector< unsigned char> buffer;
   };
 
   /**
@@ -153,17 +153,22 @@ public:
   /**
    * @copydoc PlatformAbstraction::LoadFile()
    */
-  virtual bool LoadFile( const std::string& filename, std::vector< unsigned char >& buffer ) const;
+  virtual bool LoadFile( const std::string& filename, Dali::Vector< unsigned char >& buffer ) const;
 
   /**
-   * @copydoc PlatformAbstraction::LoadShaderBinFile()
+   * @copydoc PlatformAbstraction::LoadShaderBinaryFile()
    */
-  virtual bool LoadShaderBinFile( const std::string& filename, std::vector< unsigned char >& buffer ) const;
+  virtual bool LoadShaderBinaryFile( const std::string& filename, Dali::Vector< unsigned char >& buffer ) const;
 
   /**
    * @copydoc PlatformAbstraction::SaveFile()
    */
-  virtual bool SaveFile(const std::string& filename, std::vector< unsigned char >& buffer) const;
+  virtual bool SaveFile(const std::string& filename, const unsigned char * buffer, unsigned int numBytes ) const;
+
+ /**
+  * @copydoc PlatformAbstraction::SaveShaderBinaryFile()
+  */
+  virtual bool SaveShaderBinaryFile( const std::string& filename, const unsigned char * buffer, unsigned int numBytes ) const { return false; }
 
   virtual void JoinLoaderThreads();
 
@@ -222,7 +227,7 @@ public: // TEST FUNCTIONS
 
   void SetClosestImageSize(const Vector2& size);
 
-  void SetLoadFileResult( bool result, std::vector< unsigned char >& buffer );
+  void SetLoadFileResult( bool result, Dali::Vector< unsigned char >& buffer );
 
   void SetSaveFileResult( bool result );
 
index 8158523..5c03098 100644 (file)
@@ -7,6 +7,7 @@ platform_abstraction_src_files = \
    $(platform_abstraction_src_dir)/debug.cpp \
    $(platform_abstraction_src_dir)/profiling.cpp \
    $(platform_abstraction_src_dir)/input-options.cpp \
+   $(platform_abstraction_src_dir)/shader-data.cpp \
    $(platform_abstraction_src_dir)/system-overlay.cpp \
    $(platform_abstraction_src_dir)/lockless-buffer.cpp \
    $(platform_abstraction_src_dir)/events/event.cpp \
index f2875c5..59a5cbb 100644 (file)
@@ -23,6 +23,7 @@
 #include <dali/integration-api/resource-cache.h>
 #include <dali/integration-api/bitmap.h> ///@todo Remove this include (a bunch of stuff needs to include it though)
 #include <dali/public-api/images/image-operations.h>
+#include <dali/public-api/common/dali-vector.h>
 
 namespace Dali
 {
@@ -212,16 +213,16 @@ public:
    * @param[out] buffer  A buffer to receive the file.
    * @result             true if the file is loaded.
    */
-  virtual bool LoadFile( const std::string& filename, std::vector< unsigned char >& buffer ) const = 0;
+  virtual bool LoadFile( const std::string& filename, Dali::Vector< unsigned char >& buffer ) const = 0;
 
   /**
    * Load a file into a buffer
    * @param[in] filename The filename to save
    * @param[out] buffer  A buffer containing some data
-   *                     The buffer is implemeneted with a std::vector. The size() member specifies the buffer length.
+   *                     The buffer is implemeneted with a Dali::Vector. The size() member specifies the buffer length.
    * @result             true if the file is saved.
    */
-  virtual bool SaveFile(const std::string& filename, std::vector< unsigned char >& buffer) const = 0;
+  virtual bool SaveFile( const std::string& filename, const unsigned char * buffer, unsigned int numBytes ) const = 0;
 
   /**
    * Load a shader binary file into a buffer
@@ -229,7 +230,16 @@ public:
    * @param[out] buffer  A buffer to receive the file.
    * @result             true if the file is loaded.
    */
-  virtual bool LoadShaderBinFile( const std::string& filename, std::vector< unsigned char >& buffer ) const = 0;
+  virtual bool LoadShaderBinaryFile( const std::string& filename, Dali::Vector< unsigned char >& buffer ) const = 0;
+
+  /**
+   * Save a shader binary file to the resource file system.
+   * @param[in] filename The shader binary filename to save to.
+   * @param[in] buffer  A buffer to write the file from.
+   * @param[in] numbytes Size of the buffer.
+   * @result             true if the file is saved, else false.
+   */
+  virtual bool SaveShaderBinaryFile( const std::string& filename, const unsigned char * buffer, unsigned int numBytes ) const = 0;
 
 }; // class PlatformAbstraction
 
index 911da94..1d5182e 100644 (file)
@@ -47,8 +47,7 @@ enum ResourceTypeId
 {
   ResourceBitmap,
   ResourceNativeImage,
-  ResourceTargetImage,
-  ResourceShader
+  ResourceTargetImage
 };
 
 /**
@@ -233,52 +232,6 @@ private:
   RenderTargetResourceType& operator=(const RenderTargetResourceType& rhs);
 };
 
-/**
- * ShaderResourceType describes a shader program resource, which can be requested
- * from PlatformAbstraction::LoadResource()
- */
-struct ShaderResourceType : public ResourceType
-{
-  /**
-   * Constructor.
-   */
-  ShaderResourceType(size_t shaderHash, const std::string& vertexSource, const std::string& fragmentSource)
-  : ResourceType(ResourceShader),
-    hash(shaderHash),
-    vertexShader(vertexSource),
-    fragmentShader(fragmentSource)
-  {
-  }
-
-  /**
-   * Destructor.
-   */
-  virtual ~ShaderResourceType()
-  {
-  }
-
-  /**
-   * @copydoc ResourceType::Clone
-   */
-  virtual ResourceType* Clone() const
-  {
-    return new ShaderResourceType(hash, vertexShader, fragmentShader);
-  }
-
-public: // Attributes
-  size_t            hash;              ///< Hash of the vertex/fragment sources
-  const std::string vertexShader;      ///< source code for vertex program
-  const std::string fragmentShader;    ///< source code for fragment program
-
-private:
-
-  // Undefined copy constructor.
-  ShaderResourceType(const ShaderResourceType& typePath);
-
-  // Undefined assignment operator.
-  ShaderResourceType& operator=(const ShaderResourceType& rhs);
-};
-
 } // namespace Integration
 
 } // namespace Dali
diff --git a/dali/integration-api/shader-data.cpp b/dali/integration-api/shader-data.cpp
new file mode 100644 (file)
index 0000000..6bab886
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/integration-api/shader-data.h>
+
+namespace Dali
+{
+
+namespace Integration
+{
+
+const size_t ShaderData::UNINITIALISED_HASH_VALUE = size_t(0) - 1;
+
+}
+}
index 1775204..b047650 100644 (file)
@@ -2,7 +2,7 @@
 #define __DALI_INTEGRATION_SHADER_DATA_H__
 
 /*
- * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2015 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.
@@ -23,7 +23,7 @@
 
 // INTERNAL INCLUDES
 #include <dali/public-api/object/ref-object.h>
-#include <dali/public-api/common/vector-wrapper.h>
+#include <dali/public-api/common/dali-vector.h>
 #include <dali/integration-api/resource-declarations.h>
 
 namespace Dali
@@ -38,21 +38,23 @@ typedef IntrusivePtr<ShaderData> ShaderDataPtr;
 
 /**
  * ShaderData class.
- * A container for shader source code and compiled binary byte code
+ * A container for shader source code and compiled binary byte code.
  */
 class ShaderData : public Dali::RefObject
 {
 public:
+
+  static const size_t UNINITIALISED_HASH_VALUE;
+
   /**
    * Constructor
    * @param[in] vertexSource   Source code for vertex program
    * @param[in] fragmentSource Source code for fragment program
    */
   ShaderData(const std::string& vertexSource, const std::string& fragmentSource)
-  : mShaderHash( 0 ),
+  : mShaderHash( UNINITIALISED_HASH_VALUE ),
     mVertexShader(vertexSource),
-    mFragmentShader(fragmentSource),
-    mResourceId( 0 )
+    mFragmentShader(fragmentSource)
   { }
 
 protected:
@@ -73,6 +75,7 @@ public: // API
    */
   void SetHashValue(size_t shaderHash)
   {
+    DALI_ASSERT_DEBUG( shaderHash != 0 );
     mShaderHash = shaderHash;
   }
 
@@ -80,15 +83,16 @@ public: // API
    * Get hash value which is created with vertex and fragment shader code
    * @return shaderHash  hash key created with vertex and fragment shader code
    */
-  size_t GetHashValue()
+  size_t GetHashValue() const
   {
+    DALI_ASSERT_DEBUG( mShaderHash != UNINITIALISED_HASH_VALUE );
     return mShaderHash;
   }
 
   /**
    * @return the vertex shader
    */
-  const char* GetVertexShader()
+  const char* GetVertexShader() const
   {
     return mVertexShader.c_str();
   }
@@ -96,7 +100,7 @@ public: // API
   /**
    * @return the vertex shader
    */
-  const char* GetFragmentShader()
+  const char* GetFragmentShader() const
   {
     return mFragmentShader.c_str();
   }
@@ -107,7 +111,7 @@ public: // API
    */
   bool HasBinary() const
   {
-    return 0 != mBuffer.size();
+    return 0 != mBuffer.Size();
   }
 
   /**
@@ -116,19 +120,16 @@ public: // API
    */
   void AllocateBuffer( size_t size )
   {
-    if( size > mBuffer.size() )
-    {
-      mBuffer.resize( size );
-    }
+    mBuffer.Resize( size );
   }
 
   /**
    * Get the program buffer
    * @return reference to the buffer
    */
-  size_t GetBufferSize()
+  size_t GetBufferSize() const
   {
-    return mBuffer.size();
+    return mBuffer.Size();
   }
 
   /**
@@ -137,38 +138,19 @@ public: // API
    */
   unsigned char* GetBufferData()
   {
-    DALI_ASSERT_DEBUG( mBuffer.size() > 0 );
+    DALI_ASSERT_DEBUG( mBuffer.Size() > 0 );
     return &mBuffer[0];
   }
 
   /**
    * Get the data that the buffer points to
-   * @TODO TO BE REMOVED WHEN PLATFORM ABSTRACTION FOR SHADER LOAD/STORE IS FIXED
    * @return raw pointer to the buffer data
    */
-  std::vector<unsigned char>& GetBuffer()
+  Dali::Vector<unsigned char>& GetBuffer()
   {
     return mBuffer;
   }
 
-  /**
-   * Set the resource id
-   * @param resourceId
-   */
-  void SetResourceId( ResourceId resourceId )
-  {
-    mResourceId = resourceId;
-  }
-
-  /**
-   * Get the resource id
-   * @return resourceId
-   */
-  ResourceId GetResourceId()
-  {
-    return mResourceId;
-  }
-
 private: // Not implemented
 
   ShaderData(const ShaderData& other);            ///< no copying of this object
@@ -179,9 +161,7 @@ private: // Data
   size_t                      mShaderHash;     ///< hash key created with vertex and fragment shader code
   std::string                 mVertexShader;   ///< source code for vertex program
   std::string                 mFragmentShader; ///< source code for fragment program
-  std::vector<unsigned char>  mBuffer;         ///< buffer containing compiled binary bytecode
-  ResourceId                  mResourceId;     ///< resource id
-
+  Dali::Vector<unsigned char> mBuffer;         ///< buffer containing compiled binary bytecode
 };
 
 } // namespace Integration
index 5d11734..1e9f06c 100644 (file)
@@ -148,6 +148,8 @@ Core::Core( RenderController& renderController, PlatformAbstraction& platform,
                                        textureCache,
                                       *mTouchResampler );
 
+  mRenderManager->SetShaderSaver( *mUpdateManager );
+
   mStage = IntrusivePtr<Stage>( Stage::New( *mAnimationPlaylist, *mPropertyNotificationManager, *mUpdateManager, *mNotificationManager ) );
 
   // This must be called after stage is created but before stage initialization
@@ -161,7 +163,8 @@ Core::Core( RenderController& renderController, PlatformAbstraction& platform,
   mEventProcessor = new EventProcessor(*mStage, *mNotificationManager, *mGestureEventProcessor);
 
   mImageFactory = new ImageFactory( *mResourceClient );
-  mShaderFactory = new ShaderFactory(*mResourceClient);
+  mShaderFactory = new ShaderFactory();
+  mUpdateManager->SetShaderSaver( *mShaderFactory );
   mShaderFactory->LoadDefaultShaders();
 
   GetImplementation(Dali::TypeRegistry::Get()).CallInitFunctions();
diff --git a/dali/internal/common/shader-saver.h b/dali/internal/common/shader-saver.h
new file mode 100644 (file)
index 0000000..1083282
--- /dev/null
@@ -0,0 +1,64 @@
+#ifndef __DALI_INTERNAL_SHADER_DISPATCHER_H__
+#define __DALI_INTERNAL_SHADER_DISPATCHER_H__
+
+/*
+ * Copyright (c) 2015 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.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali/public-api/common/intrusive-ptr.h>
+
+// EXTERNAL INCLUDES
+
+
+namespace Dali
+{
+
+namespace Integration
+{
+class ShaderData;
+typedef IntrusivePtr<ShaderData> ShaderDataPtr;
+}
+
+namespace Internal
+{
+
+/**
+ * Abstract interface for passing a ShaderData object towards being saved.
+ */
+class ShaderSaver
+{
+public:
+
+  /**
+   * A function saving the binary from a ShaderDataPtr or passing it on to where it can be saved.
+   * @param[in] shaderData A smart pointer to a ShaderData for which the program binary should be saved.
+   */
+  virtual void SaveBinary( Integration::ShaderDataPtr shaderData ) = 0;
+
+protected:
+  /**
+   * Destructor. Protected as no derived class should ever be deleted
+   * through a reference to this pure abstract interface.
+   */
+  virtual ~ShaderSaver(){}
+};
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // __DALI_INTERNAL_SHADER_DISPATCHER_H__
index 0d4dae5..688196b 100644 (file)
@@ -292,14 +292,11 @@ void ShaderEffect::SendProgramMessage( const string& vertexSource, const string&
   ShaderFactory& shaderFactory = tls.GetShaderFactory();
   size_t shaderHash;
 
-  ResourceTicketPtr ticket( shaderFactory.Load(vertexSource, fragmentSource, shaderHash) );
-
-  DALI_LOG_INFO( Debug::Filter::gShader, Debug::General, "ShaderEffect: SetProgram(ticket.id:%d)\n", ticket->GetId() );
+  Integration::ShaderDataPtr shaderData = shaderFactory.Load( vertexSource, fragmentSource, shaderHash );
+  DALI_ASSERT_DEBUG( shaderHash != 0U );
 
   // Add shader program to scene-object using a message to the UpdateManager
-  SetShaderProgramMessage( mEventThreadServices.GetUpdateManager(), *mSceneObject, ticket->GetId(), shaderHash, modifiesGeometry );
-
-  mTickets.push_back(ticket);       // add ticket to collection to keep it alive.
+  SetShaderProgramMessage( mEventThreadServices.GetUpdateManager(), *mSceneObject, shaderData, false );
 }
 
 void ShaderEffect::Connect()
index 9f80091..2ccc768 100644 (file)
@@ -207,7 +207,6 @@ private: // Data
   EventThreadServices& mEventThreadServices; ///< Event thread services, for sending messages
   SceneGraph::Shader* mSceneObject;         ///< pointer to the scene shader, should not be changed on this thread
   Dali::Image mImage;                       ///< Client-side handle for the effect image
-  std::vector<ResourceTicketPtr>  mTickets; ///< Collection of shader program tickets
   unsigned int  mConnectionCount;           ///< number of on-stage ImageActors using this shader effect
   Dali::ShaderEffect::GeometryHints  mGeometryHints; ///< shader geometry hints for building the geometry
   Dali::Vector< UniformCoordinateType > mCoordinateTypes; ///< cached to avoid sending tons of unnecessary messages
index f276ef6..88ef6ed 100644 (file)
@@ -26,6 +26,8 @@
 #include <dali/public-api/common/dali-common.h>
 #include <dali/devel-api/common/hash.h>
 #include <dali/integration-api/debug.h>
+#include <dali/integration-api/platform-abstraction.h>
+#include <dali/internal/event/common/thread-local-storage.h>
 #include <dali/internal/event/resources/resource-client.h>
 #include <dali/internal/event/effects/shader-effect-impl.h>
 #include <dali/internal/event/effects/shader-declarations.h>
@@ -52,66 +54,104 @@ namespace Dali
 namespace Internal
 {
 
-ShaderFactory::ShaderFactory(ResourceClient& resourceClient)
-: mResourceClient(resourceClient)
+namespace
 {
+
+/**
+ * @brief Generates a filename for a shader binary based on the hash value passed in.
+ * @param[in] shaderHash A hash over shader sources.
+ * @param[out] filename A string to overwrite with the filename.
+ */
+void shaderBinaryFilename( size_t shaderHash, std::string& filename )
+{
+  std::stringstream binaryShaderFilenameBuilder( std::ios_base::out );
+  binaryShaderFilenameBuilder << CORE_MAJOR_VERSION << VERSION_SEPARATOR << CORE_MINOR_VERSION << VERSION_SEPARATOR << CORE_MICRO_VERSION << VERSION_SEPARATOR
+                              << shaderHash
+                              << SHADER_SUFFIX;
+  filename = binaryShaderFilenameBuilder.str();
 }
 
-ShaderFactory::~ShaderFactory()
+}
+
+ShaderFactory::ShaderFactory()
 {
 }
 
-ResourceTicketPtr ShaderFactory::Load(const std::string& vertexSource, const std::string& fragmentSource, size_t& shaderHash)
+ShaderFactory::~ShaderFactory()
 {
-  ResourceTicketPtr ticket;
-
-  shaderHash = CalculateHash(vertexSource, fragmentSource);
-  std::stringstream stringHash;
-  stringHash << CORE_MAJOR_VERSION << VERSION_SEPARATOR << CORE_MINOR_VERSION << VERSION_SEPARATOR << CORE_MICRO_VERSION << VERSION_SEPARATOR;
-  stringHash << shaderHash;
-  std::string filename;
-  filename.append( stringHash.str() );
-  filename.append( SHADER_SUFFIX );
-
-  ShaderResourceType resourceType(shaderHash, vertexSource, fragmentSource);
-  ResourceTypePath typePath(resourceType, filename);
-
-  // Search for a matching resource
-  ResourceTypePathIdIter iter = mResourceTypePathIdMap.end();
-  if ( !mResourceTypePathIdMap.empty() )
+  // Let all the cached objects destroy themselves:
+  for( int i = 0, cacheSize = mShaderBinaryCache.Size(); i < cacheSize; ++i )
   {
-    iter = mResourceTypePathIdMap.find( typePath );
+    if( mShaderBinaryCache[i] )
+    {
+      mShaderBinaryCache[i]->Unreference();
+    }
   }
+}
 
-  if ( mResourceTypePathIdMap.end() != iter )
-  {
-    // The resource was previously requested
-    unsigned int resourceId = iter->second;
+ShaderDataPtr ShaderFactory::Load( const std::string& vertexSource, const std::string& fragmentSource, size_t& shaderHash )
+{
+  // Work out the filename for the binary that the glsl source will be compiled and linked to:
+  shaderHash = CalculateHash( vertexSource.c_str(), fragmentSource.c_str() );
+  std::string binaryShaderFilename;
+  shaderBinaryFilename( shaderHash, binaryShaderFilename );
 
-    // The ticket may still be alive, request another copy
-    ticket = mResourceClient.RequestResourceTicket( resourceId );
+  ShaderDataPtr shaderData;
 
-    // Clean-up the map of resource IDs, if the ticket has been discarded
-    if ( !ticket )
-    {
-      mResourceTypePathIdMap.erase( iter );
-    }
-    else
+  /// Check a cache of previously loaded shaders:
+  for( int i = 0, cacheSize = mShaderBinaryCache.Size(); i < cacheSize; ++i )
+  {
+    if( mShaderBinaryCache[i]->GetHashValue() == shaderHash )
     {
-      DALI_LOG_INFO(Debug::Filter::gShader, Debug::General, "ShaderFactory::Load filename= %s already requested to Load\n", filename.c_str());
+      shaderData = mShaderBinaryCache[i];
+
+      DALI_LOG_INFO( Debug::Filter::gShader, Debug::General, "Mem cache hit on path: \"%s\"\n", binaryShaderFilename.c_str() );
+      break;
     }
   }
 
-  if ( !ticket )
+  // If memory cache failed check the file system for a binary or return a source-only ShaderData:
+  if( shaderData.Get() == NULL )
   {
-    // Load the shader (loaded synchronously in Update thread so its ready by the time the set shader message is processed)
-    ticket = mResourceClient.LoadShader(resourceType, filename);
-    DALI_LOG_INFO(Debug::Filter::gShader, Debug::General, "ShaderFactory::Load Ticket ID:%d, path: \"%s\"\n", ticket->GetId(), filename.c_str());
+    // Allocate the structure that returns the loaded shader:
+    shaderData = new ShaderData( vertexSource, fragmentSource );
+    shaderData->SetHashValue( shaderHash );
+    shaderData->GetBuffer().Clear();
 
-    mResourceTypePathIdMap.insert( ResourceTypePathIdPair( typePath, ticket->GetId() ) );
+    // Try to load the binary (this will fail if the shader source has never been compiled before):
+    ThreadLocalStorage& tls = ThreadLocalStorage::Get();
+    Integration::PlatformAbstraction& platformAbstraction = tls.GetPlatformAbstraction();
+    const bool loaded = platformAbstraction.LoadShaderBinaryFile( binaryShaderFilename, shaderData->GetBuffer() );
+
+    if( loaded )
+    {
+      MemoryCacheInsert( *shaderData );
+    }
+
+    DALI_LOG_INFO(Debug::Filter::gShader, Debug::General, loaded ?
+        "loaded on path: \"%s\"\n" :
+        "failed to load on path: \"%s\"\n",
+        binaryShaderFilename.c_str());
   }
 
-  return ticket;
+  return shaderData;
+}
+
+void ShaderFactory::SaveBinary( Integration::ShaderDataPtr shaderData )
+{
+  // Save the binary to the file system:
+  std::string binaryShaderFilename;
+  shaderBinaryFilename( shaderData->GetHashValue(), binaryShaderFilename );
+
+  ThreadLocalStorage& tls = ThreadLocalStorage::Get();
+  Integration::PlatformAbstraction& platformAbstraction = tls.GetPlatformAbstraction();
+  const bool saved = platformAbstraction.SaveShaderBinaryFile( binaryShaderFilename, &shaderData->GetBuffer()[0], shaderData->GetBufferSize() );
+
+  // Save the binary into to memory cache:
+  MemoryCacheInsert( *shaderData );
+
+  DALI_LOG_INFO( Debug::Filter::gShader, Debug::General, saved ? "Saved to file: %s\n" : "Save to file failed: %s\n", binaryShaderFilename.c_str() );
+  if( saved ) {} // Avoid unused variable warning in release builds
 }
 
 void ShaderFactory::LoadDefaultShaders()
@@ -121,6 +161,20 @@ void ShaderFactory::LoadDefaultShaders()
   mDefaultShader->SendProgramMessage( ImageVertex, ImageFragment, false );
 }
 
+void ShaderFactory::MemoryCacheInsert( ShaderData& shaderData )
+{
+  DALI_ASSERT_DEBUG( shaderData.GetBufferSize() > 0 );
+
+  // Save the binary into to memory cache:
+  if( shaderData.GetBufferSize() > 0 )
+  {
+    mShaderBinaryCache.Reserve( mShaderBinaryCache.Size() + 1 ); // Make sure the push won't throw after we inc the ref count.
+    shaderData.Reference();
+    mShaderBinaryCache.PushBack( &shaderData );
+    DALI_LOG_INFO( Debug::Filter::gShader, Debug::General, "CACHED BINARY FOR HASH: %u\n", shaderData.GetHashValue() );
+  }
+}
+
 } // namespace Internal
 
 } // namespace Dali
index fd5a07f..29fd221 100644 (file)
  */
 
 // INTERNAL INCLUDES
+#include <dali/public-api/common/dali-vector.h>
 #include <dali/internal/event/resources/resource-ticket.h>
-#include <dali/internal/event/resources/resource-type-path-id-map.h>
 #include <dali/internal/event/effects/shader-declarations.h>
+#include <dali/internal/common/message.h>
+#include <dali/internal/common/shader-saver.h>
 
 namespace Dali
 {
+namespace Integration
+{
+
+class ShaderData;
+typedef IntrusivePtr<ShaderData> ShaderDataPtr;
+
+}
 
 namespace Internal
 {
@@ -33,35 +42,49 @@ class ResourceClient;
 class MessageController;
 
 /**
- * ShaderFactory is an object that manages shader binary resource load requests,
+ * ShaderFactory is an object which manages shader binary resource load requests,
  * It triggers the load requests during core initialization and sends a message to the
- * render manager with information about all the requested shader binaries and their
- * request Id.
+ * render manager with information about all the requested shader binaries.
  */
-class ShaderFactory
+class ShaderFactory : public ShaderSaver
 {
 public:
 
   /**
    * Default constructor
    */
-  ShaderFactory(ResourceClient& resourceClient);
+  ShaderFactory();
 
   /**
    * Destructor
    */
-  ~ShaderFactory();
+  virtual ~ShaderFactory();
 
   /**
-   * Issues a request to load a binary version of a shader program, and returns a resource ticket
-   * If a request for an identical shader has already been made, the ticket for the older request
-   * is shared.
+   * @brief Looks for precompiled binary version of shader program in memory and file caches.
+   *
+   * Tries to load a binary version of a shader program identified by a hash over the two source
+   * files, checking an in-memory cache first.
+   * If the cache hits or the load succeeds, the buffer member of the returned ShaderData will
+   * contain a precompiled shader binary program which can be uploaded directly to GLES.
+   *
    * @param [in] vertexSource   The vertex shader source code
    * @param [in] fragmentSource The fragment shader source code
-   * @param [out] shaderHash  hash key created with vertex and fragment shader code
-   * @return                    A ticket for the resource
+   * @param [out] shaderHash    Hash key created from vertex and fragment shader code
+   * @return                    ShaderData containing the source and hash value, and additionally,
+   *                            a compiled shader program binary if one could be found, else an
+   *                            empty binary buffer cleared to size zero.
    */
-  ResourceTicketPtr Load( const std::string& vertexSource, const std::string& fragmentSource, size_t& shaderHash );
+  Integration::ShaderDataPtr Load( const std::string& vertexSource, const std::string& fragmentSource, size_t& shaderHash );
+
+  /**
+   * @brief Saves shader to memory cache and filesystem.
+   * This is called when a shader binary is ready to be saved to the memory cache file system.
+   * Shaders that pass through here become available to subsequent invocations of Load.
+   * @param[in] shader The data to be saved.
+   * @sa Load
+   */
+  virtual void SaveBinary( Integration::ShaderDataPtr shader );
 
   /**
    * Called during Core initialization to load the default shader.
@@ -70,6 +93,8 @@ public:
 
 private:
 
+  void MemoryCacheInsert( Integration::ShaderData& shaderData );
+
   // Undefined
   ShaderFactory( const ShaderFactory& );
 
@@ -77,12 +102,18 @@ private:
   ShaderFactory& operator=( const ShaderFactory& rhs );
 
 private:
-  ResourceClient&       mResourceClient;
-  ResourceTypePathIdMap mResourceTypePathIdMap; ///< A map of resource IDs sorted by ResourceTypePath
-  ShaderEffectPtr       mDefaultShader;
+  ShaderEffectPtr                           mDefaultShader;
+  Dali::Vector< Integration::ShaderData* > mShaderBinaryCache; ///< Cache of pre-compiled shaders.
 
 }; // class ShaderFactory
 
+inline MessageBase* ShaderCompiledMessage( ShaderSaver& factory, Integration::ShaderDataPtr shaderData )
+{
+  return new MessageValue1< ShaderSaver, Integration::ShaderDataPtr >( &factory,
+                                                            &ShaderSaver::SaveBinary,
+                                                            shaderData );
+}
+
 } // namespace Internal
 
 } // namespace Dali
index a72016f..4f235ed 100644 (file)
@@ -20,7 +20,6 @@
 
 // INTERNAL INCLUDES
 #include <dali/public-api/common/dali-vector.h>
-#include <dali/internal/event/resources/resource-type-path-id-map.h>
 #include <dali/internal/event/resources/resource-ticket.h>
 #include <dali/internal/event/images/context-recovery-interface.h>
 #include <dali/internal/event/images/image-factory-cache.h>
index 4760d5f..d9398bd 100644 (file)
@@ -272,20 +272,19 @@ void Shader::Initialize(
   }
   Dali::ShaderEffect::GeometryHints shaderEffectHint = static_cast<Dali::ShaderEffect::GeometryHints>( effectHint );
 
-  mSceneObject = new SceneGraph::Shader(shaderEffectHint);
+  mSceneObject = new SceneGraph::Shader( shaderEffectHint );
 
   // Add to update manager
   AddShaderMessage( updateManager, *mSceneObject );
 
+  // Try to load a precompiled shader binary for the source pair:
   ThreadLocalStorage& tls = ThreadLocalStorage::Get();
   ShaderFactory& shaderFactory = tls.GetShaderFactory();
   size_t shaderHash;
-
-  mTicket = ResourceTicketPtr( shaderFactory.Load(vertexSource, fragmentSource, shaderHash) );
+  Integration::ShaderDataPtr shaderData = shaderFactory.Load( vertexSource, fragmentSource, shaderHash );
 
   // Add shader program to scene-object using a message to the UpdateManager
-  SetShaderProgramMessage( updateManager, *mSceneObject, mTicket->GetId(), shaderHash, false );
-
+  SetShaderProgramMessage( updateManager, *mSceneObject, shaderData, false );
   eventThreadServices.RegisterObject( this );
 }
 
index d70992f..f71289d 100644 (file)
@@ -179,7 +179,6 @@ private: // unimplemented methods
 
 private:
   SceneGraph::Shader* mSceneObject;
-  ResourceTicketPtr mTicket;
   bool mOnStage;
 };
 
index 31c8f9f..c5ec4da 100644 (file)
@@ -119,7 +119,6 @@ ResourceTicketPtr ResourceClient::RequestResource(
       break;
     }
     case ResourceTargetImage:
-    case ResourceShader:
     {
       newTicket = new ResourceTicket(*this, newId, typePath);
       break;
@@ -165,7 +164,6 @@ ResourceTicketPtr ResourceClient::DecodeResource(
       // FALLTHROUGH:
       case ResourceNativeImage:
       case ResourceTargetImage:
-      case ResourceShader:
       {
         DALI_LOG_ERROR( "Unsupported resource type passed for decoding from a memory buffer." );
       }
@@ -182,24 +180,6 @@ ResourceTicketPtr ResourceClient::DecodeResource(
   return newTicket;
 }
 
-ResourceTicketPtr ResourceClient::LoadShader( ShaderResourceType& type,
-                                              const std::string& path )
-{
-  ResourceTicketPtr newTicket;
-
-  const ResourceId newId = ++(mImpl->mNextId);
-
-  ResourceTypePath typePath(type, path);
-  newTicket = new ResourceTicket(*this, newId, typePath);
-
-  mImpl->mTickets.insert(TicketPair(newId, newTicket.Get()));
-
-  DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: LoadShader(path:%s) newId:%u\n", path.c_str(), newId);
-
-  RequestLoadShaderMessage( mEventThreadServices, mResourceManager, newId, typePath );
-  return newTicket;
-}
-
 bool ResourceClient::ReloadResource( ResourceId id, bool resetFinishedStatus, LoadResourcePriority priority )
 {
   DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: ReloadResource(Id: %u)\n", id);
index 303fa44..c4b7123 100644 (file)
@@ -121,14 +121,6 @@ public:
                                     Integration::LoadResourcePriority priority = Integration::LoadPriorityNormal );
 
   /**
-   * Load a shader program from a file
-   * @param[in] type     A ResourceType specialization describing a shader program resource
-   * @param[in] filename The file's full path/file name
-   * @return             A ref-counted request object. Keep a copy until the resource is no longer required.
-   */
-  ResourceTicketPtr LoadShader(Integration::ShaderResourceType& type, const std::string& filename);
-
-  /**
    * Request reloading a resource from the native filesystem.
    * If the resource is still loading, this request is ignored.
    * The ticket observer will be notified of completion with ResourceLoadingSucceeded() or
@@ -143,7 +135,7 @@ public:
 
   /**
    * Save a resource to the given url.
-   * If the resource type is saveable (model or shader), then the ticket observer will get
+   * If the resource type is saveable (model), then the ticket observer will get
    * notified with ResourceSavingSucceeded() or ResourceSavingFailed(), otherwise there
    * will be no response.
    * @param[in] ticket The ticket of the resource to save
diff --git a/dali/internal/event/resources/resource-type-path-id-map.h b/dali/internal/event/resources/resource-type-path-id-map.h
deleted file mode 100644 (file)
index 8c8bab3..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-#ifndef __DALI_INTERNAL_RESOURCE_TYPE_PATH_ID_MAP_H__
-#define __DALI_INTERNAL_RESOURCE_TYPE_PATH_ID_MAP_H__
-
-/*
- * Copyright (c) 2014 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.
- *
- */
-
-// INTERNAL INCLUDES
-#include <dali/devel-api/common/map-wrapper.h>
-#include <dali/internal/event/resources/resource-type-path.h>
-
-namespace Dali
-{
-
-namespace Internal
-{
-
-///< A map of resource IDs sorted by ResourceTypePath
-typedef std::map<ResourceTypePath, unsigned int>  ResourceTypePathIdMap;
-typedef ResourceTypePathIdMap::iterator           ResourceTypePathIdIter;
-typedef ResourceTypePathIdMap::size_type          ResourceTypePathIdSize;
-typedef std::pair<ResourceTypePath, unsigned int> ResourceTypePathIdPair;
-
-} // namespace Internal
-
-} // namespace Dali
-
-#endif // __DALI_INTERNAL_RESOURCE_TYPE_PATH_ID_MAP_H__
index e856895..1204e81 100644 (file)
@@ -116,23 +116,6 @@ int ResourceTypeCompare(const ResourceType& lhs, const ResourceType& rhs)
         // else result = 0
         break;
       }
-
-      case ResourceShader:
-      {
-        // compare shader source hashes
-        const ShaderResourceType& lhsShader = static_cast<const ShaderResourceType&>(lhs);
-        const ShaderResourceType& rhsShader = static_cast<const ShaderResourceType&>(rhs);
-
-        if (lhsShader.hash != rhsShader.hash)
-        {
-          result = lhsShader.hash < rhsShader.hash ? -1 : 1;
-        }
-        // else result = 0
-        break;
-      }
-
-
-
     }
   }
   return result;
index 8d6446d..35954a9 100644 (file)
@@ -102,7 +102,7 @@ struct RenderManager::Impl
     renderersAdded( false ),
     firstRenderCompleted( false ),
     defaultShader( NULL ),
-    programController( postProcessDispatcher, glAbstraction )
+    programController( glAbstraction )
   {
   }
 
@@ -232,6 +232,11 @@ void RenderManager::DispatchPostProcessRequest(ResourcePostProcessRequest& reque
   mImpl->resourcePostProcessQueue[ mImpl->renderBufferIndex ].push_back( request );
 }
 
+void RenderManager::SetShaderSaver( ShaderSaver& upstream )
+{
+  mImpl->programController.SetShaderSaver( upstream );
+}
+
 RenderInstructionContainer& RenderManager::GetRenderInstructionContainer()
 {
   return mImpl->instructions;
index 5ec8b0d..d716d43 100644 (file)
@@ -20,6 +20,7 @@
 
 // INTERNAL INCLUDES
 #include <dali/public-api/math/rect.h>
+#include <dali/internal/common/shader-saver.h>
 #include <dali/internal/render/common/post-process-resource-dispatcher.h>
 #include <dali/internal/update/resources/resource-manager-declarations.h>
 #include <dali/internal/render/gl-resources/gpu-buffer.h>
@@ -39,6 +40,7 @@ namespace Internal
 {
 class Context;
 class ProgramCache;
+class ShaderSaver;
 
 namespace SceneGraph
 {
@@ -99,7 +101,15 @@ public:
    * Dispatch requests onto the postProcessResourcesQueue
    * @param[in] request The request to dispatch
    */
-  virtual void DispatchPostProcessRequest(ResourcePostProcessRequest& request);
+  virtual void DispatchPostProcessRequest( ResourcePostProcessRequest& request );
+
+  /**
+   * Set the upstream interface for compiled shader binaries to be sent back to for eventual
+   * caching and saving.
+   * @param[in] upstream The abstract interface to send any received ShaderDatas onwards to..
+   * @note This should be called during core initialisation if shader binaries are to be used.
+   */
+  void SetShaderSaver( ShaderSaver& upstream );
 
   /**
    * Retrieve the render instructions; these should be set during each "update" traversal.
index cd17e17..cbabab6 100644 (file)
@@ -169,7 +169,10 @@ void BitmapTexture::AssignBitmap( bool generateTexture, const unsigned char* pix
   mContext.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
   mContext.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
 
-  INCREASE_BY( PerformanceMonitor::TEXTURE_DATA_UPLOADED, GetBytesPerPixel(mPixelFormat) * mWidth * mHeight );
+  if( pixels != NULL )
+  {
+    INCREASE_BY( PerformanceMonitor::TEXTURE_DATA_UPLOADED, GetBytesPerPixel(mPixelFormat) * mWidth * mHeight );
+  }
 }
 
 void BitmapTexture::Update( Integration::Bitmap* bitmap )
@@ -322,11 +325,11 @@ bool BitmapTexture::CreateGlTexture()
   else
   {
     const unsigned char* pixels = NULL;
-    std::vector<unsigned char> pixelData;
-    if( ( NULL == pixels ) && ( true == mClearPixels ) )
+    Dali::Vector<unsigned char> pixelData; // Okay to create outside branch as empty vector has no heap allocation.
+    if( true == mClearPixels )
     {
-      unsigned int size = mWidth * mHeight * Pixel::GetBytesPerPixel(mPixelFormat);
-      pixelData.resize(size, 0);
+      unsigned int size = mWidth * mHeight * Pixel::GetBytesPerPixel( mPixelFormat );
+      pixelData.Resize( size, 0 );
       pixels = &pixelData[0];
     }
     AssignBitmap( true, pixels );
index 949e2d4..e4163db 100644 (file)
@@ -20,6 +20,7 @@
 
 // INTERNAL INCLUDES
 #include <dali/integration-api/gl-defines.h>
+#include <dali/internal/common/shader-saver.h>
 #include <dali/internal/update/resources/resource-manager-declarations.h>
 #include <dali/internal/render/shaders/program.h>
 #include <dali/internal/render/common/post-process-resource-dispatcher.h>
@@ -31,8 +32,8 @@ namespace Dali
 namespace Internal
 {
 
-ProgramController::ProgramController( SceneGraph::PostProcessResourceDispatcher& postProcessDispatcher, Integration::GlAbstraction& glAbstraction )
-: mPostProcessDispatcher( postProcessDispatcher ),
+ProgramController::ProgramController( Integration::GlAbstraction& glAbstraction )
+: mShaderSaver( 0 ),
   mGlAbstraction( glAbstraction ),
   mCurrentProgram( NULL ),
   mProgramBinaryFormat( 0 ),
@@ -142,8 +143,19 @@ unsigned int ProgramController::ProgramBinaryFormat()
 
 void ProgramController::StoreBinary( Integration::ShaderDataPtr programData )
 {
-  ResourcePostProcessRequest request( programData->GetResourceId(), ResourcePostProcessRequest::SAVE );
-  mPostProcessDispatcher.DispatchPostProcessRequest( request );
+  DALI_ASSERT_DEBUG( programData->GetBufferSize() > 0 );
+  DALI_ASSERT_DEBUG( programData->GetHashValue() != 0 );
+  DALI_ASSERT_DEBUG( mShaderSaver && "SetShaderSaver() should have been called during startup." );
+
+  if( mShaderSaver != NULL )
+  {
+    mShaderSaver->SaveBinary( programData );
+  }
+}
+
+void ProgramController::SetShaderSaver( ShaderSaver& shaderSaver )
+{
+  mShaderSaver = &shaderSaver;
 }
 
 } // namespace Internal
index 6ce57f9..8dedd95 100644 (file)
@@ -29,10 +29,7 @@ namespace Dali
 namespace Internal
 {
 
-namespace SceneGraph
-{
-class PostProcessResourceDispatcher;
-}
+class ShaderSaver;
 
 /**
  * This class is the owner of GL shader programs
@@ -96,7 +93,7 @@ public:
    * Constructor
    * @param postProcessDispatcher to send save binary message back to update
    */
-  ProgramController( SceneGraph::PostProcessResourceDispatcher& postProcessDispatcher, Integration::GlAbstraction& glAbstraction );
+  ProgramController( Integration::GlAbstraction& glAbstraction );
 
   /**
    * Destructor, non virtual as not a base class
@@ -120,6 +117,12 @@ public: // API
    */
   void GlContextDestroyed();
 
+  /**
+   * Set the destination for compiler shader binaries so they can be saved.
+   * @note Must be called during initialisation.
+   */
+  void SetShaderSaver( ShaderSaver& shaderSaver );
+
 private: // From ProgramCache
 
   /**
@@ -169,7 +172,7 @@ private: // not implemented as non-copyable
 
 private: // Data
 
-  SceneGraph::PostProcessResourceDispatcher& mPostProcessDispatcher;
+  ShaderSaver* mShaderSaver;
   Integration::GlAbstraction& mGlAbstraction;
   Program* mCurrentProgram;
 
index dbfc298..6957698 100644 (file)
@@ -486,6 +486,7 @@ Program::~Program()
 void Program::Load()
 {
   DALI_ASSERT_ALWAYS( NULL != mProgramData.Get() && "Program data is not initialized" );
+  DALI_ASSERT_DEBUG( mProgramId == 0 && "mProgramId != 0, so about to leak a GL resource by overwriting it." );
 
   LOG_GL( "CreateProgram()\n" );
   mProgramId = CHECK_GL( mGlAbstraction, mGlAbstraction.CreateProgram() );
@@ -527,6 +528,7 @@ void Program::Load()
     else
     {
       mLinked = true;
+      DALI_LOG_INFO( Debug::Filter::gShader, Debug::General, "Reused binary.\n" );
     }
   }
 
@@ -544,6 +546,7 @@ void Program::Load()
         {
           GLint  binaryLength = 0;
           GLenum binaryFormat;
+          DALI_LOG_INFO( Debug::Filter::gShader, Debug::General, "Compiled and linked.\n\nVS:\n%s\nFS:\n%s\n", mProgramData->GetVertexShader(), mProgramData->GetFragmentShader() );
 
           CHECK_GL( mGlAbstraction, mGlAbstraction.GetProgramiv(mProgramId, GL_PROGRAM_BINARY_LENGTH_OES, &binaryLength) );
           DALI_LOG_INFO(Debug::Filter::gShader, Debug::General, "Program::Load() - GL_PROGRAM_BINARY_LENGTH_OES: %d\n", binaryLength);
@@ -554,6 +557,7 @@ void Program::Load()
             // Copy the bytecode to ShaderData
             CHECK_GL( mGlAbstraction, mGlAbstraction.GetProgramBinary(mProgramId, binaryLength, NULL, &binaryFormat, mProgramData->GetBufferData()) );
             mCache.StoreBinary( mProgramData );
+            DALI_LOG_INFO( Debug::Filter::gShader, Debug::General, "Saved binary.\n" );
           }
         }
       }
index 74f78a4..e9b5c14 100644 (file)
@@ -214,6 +214,16 @@ void Shader::SetProgram( Integration::ResourceId resourceId,
   // The program cache owns the Program object so we don't need to worry here.
 }
 
+void Shader::SetProgram( Integration::ShaderDataPtr shaderData,
+                         ProgramCache* programCache,
+                         bool modifiesGeometry )
+{
+  DALI_LOG_TRACE_METHOD_FMT( Debug::Filter::gShader, "%d\n", shaderData->GetHashValue() );
+
+  mProgram = Program::New( *programCache, shaderData, modifiesGeometry );
+  // The program cache owns the Program object so we don't need to worry about this raw allocation here.
+}
+
 Program* Shader::GetProgram()
 {
   return mProgram;
index 83a65b0..7a21a71 100644 (file)
@@ -48,7 +48,6 @@ typedef unsigned int ResourceId;
 namespace Internal
 {
 
-class ProgramController;
 class Program;
 
 namespace SceneGraph
@@ -238,10 +237,10 @@ public:
   void SetCoordinateTypeInRender( unsigned int index, Dali::ShaderEffect::UniformCoordinateType type );
 
   /**
-   * @brief Set the program for a geometry type.
+   * @brief Set the program for this shader.
    * @param[in] resourceId        The resource ID for the program.
-   * @param[in] shaderData        The program's vertex/fragment source and optionally compiled bytecode
-   * @param[in] programCache      Owner of the Programs
+   * @param[in] shaderData        The program's vertex/fragment source and optionally precompiled shader binary.
+   * @param[in] programCache      Owner of the Programs.
    * @param[in] modifiesGeometry  True if the vertex shader changes the positions of vertexes such that
    * they might exceed the bounding box of vertexes passing through the default transformation.
    */
@@ -251,6 +250,17 @@ public:
                    bool modifiesGeometry );
 
   /**
+   * @brief Set the program for this shader.
+   * @param[in] shaderData        The program's vertex/fragment source and optionally precompiled shader binary.
+   * @param[in] programCache      Owner of the Programs.
+   * @param[in] modifiesGeometry  True if the vertex shader changes the positions of vertexes such that
+   * they might exceed the bounding box of vertexes passing through the default transformation.
+   */
+  void SetProgram( Integration::ShaderDataPtr shaderData,
+                   ProgramCache* programCache,
+                   bool modifiesGeometry );
+
+  /**
    * Get the program built for this shader
    * @return The program built from the shader sources.
    */
index 866f4bc..bdae788 100644 (file)
@@ -34,6 +34,7 @@
 #include <dali/internal/event/common/notification-manager.h>
 #include <dali/internal/event/common/property-notification-impl.h>
 #include <dali/internal/event/common/property-notifier.h>
+#include <dali/internal/event/effects/shader-factory.h>
 
 #include <dali/internal/update/animation/scene-graph-animator.h>
 #include <dali/internal/update/animation/scene-graph-animation.h>
@@ -130,6 +131,9 @@ typedef OwnerContainer< Shader* >              ShaderContainer;
 typedef ShaderContainer::Iterator              ShaderIter;
 typedef ShaderContainer::ConstIterator         ShaderConstIter;
 
+typedef std::vector<Integration::ShaderDataPtr> ShaderDataBatchedQueue;
+typedef ShaderDataBatchedQueue::iterator        ShaderDataBatchedQueueIterator;
+
 typedef OwnerContainer<PanGesture*>            GestureContainer;
 typedef GestureContainer::Iterator             GestureIter;
 typedef GestureContainer::ConstIterator        GestureConstIter;
@@ -157,6 +161,7 @@ struct UpdateManager::Impl
     notificationManager( notificationManager ),
     animationFinishedNotifier( animationFinishedNotifier ),
     propertyNotifier( propertyNotifier ),
+    shaderSaver( NULL ),
     resourceManager( resourceManager ),
     discardQueue( discardQueue ),
     renderController( renderController ),
@@ -238,6 +243,7 @@ struct UpdateManager::Impl
   NotificationManager&                notificationManager;           ///< Queues notification messages for the event-thread.
   CompleteNotificationInterface&      animationFinishedNotifier;     ///< Provides notification to applications when animations are finished.
   PropertyNotifier&                   propertyNotifier;              ///< Provides notification to applications when properties are modified.
+  ShaderSaver*                        shaderSaver;                   ///< Saves shader binaries.
   ResourceManager&                    resourceManager;               ///< resource manager
   DiscardQueue&                       discardQueue;                  ///< Nodes are added here when disconnected from the scene-graph.
   RenderController&                   renderController;              ///< render controller
@@ -275,6 +281,7 @@ struct UpdateManager::Impl
   ShaderContainer                     shaders;                       ///< A container of owned shaders
 
   MessageQueue                        messageQueue;                  ///< The messages queued from the event-thread
+  ShaderDataBatchedQueue              compiledShaders[2];            ///< Shaders compiled on Render thread are inserted here for update thread to pass on to event thread.
 
   float                               keepRenderingSeconds;          ///< Set via Dali::Stage::KeepRendering
   bool                                animationFinishedDuringUpdate; ///< Flag whether any animations finished during the Update()
@@ -603,28 +610,28 @@ void UpdateManager::RemoveShader( Shader* shader )
 }
 
 void UpdateManager::SetShaderProgram( Shader* shader,
-                                      ResourceId resourceId, size_t shaderHash, bool modifiesGeometry )
+                                      Integration::ShaderDataPtr shaderData, bool modifiesGeometry )
 {
-  DALI_LOG_TRACE_METHOD_FMT(Debug::Filter::gShader, " - (id:%d hash:%d)\n", resourceId, shaderHash);
-
-  DALI_ASSERT_ALWAYS( NULL != shader && "shader is uninitialized" );
-
-  Integration::ShaderDataPtr shaderData( mImpl->resourceManager.GetShaderData(resourceId) );
   if( shaderData )
   {
-    shaderData->SetHashValue( shaderHash );
-    shaderData->SetResourceId( resourceId );
 
-    typedef MessageValue4< Shader, Integration::ResourceId, Integration::ShaderDataPtr, ProgramCache*, bool> DerivedType;
+    typedef MessageValue3< Shader, Integration::ShaderDataPtr, ProgramCache*, bool> DerivedType;
 
     // Reserve some memory inside the render queue
     unsigned int* slot = mImpl->renderQueue.ReserveMessageSlot( mSceneGraphBuffers.GetUpdateBufferIndex(), sizeof( DerivedType ) );
 
     // Construct message in the render queue memory; note that delete should not be called on the return value
-    new (slot) DerivedType( shader, &Shader::SetProgram, resourceId, shaderData, mImpl->renderManager.GetProgramCache(), modifiesGeometry );
+    new (slot) DerivedType( shader, &Shader::SetProgram, shaderData, mImpl->renderManager.GetProgramCache(), modifiesGeometry );
   }
 }
 
+void UpdateManager::SaveBinary( Integration::ShaderDataPtr shaderData )
+{
+  DALI_ASSERT_DEBUG( shaderData && "No NULL shader data pointers please." );
+  DALI_ASSERT_DEBUG( shaderData->GetBufferSize() > 0 && "Shader binary empty so nothing to save." );
+  mImpl->compiledShaders[mSceneGraphBuffers.GetUpdateBufferIndex() > 0 ? 0 : 1].push_back( shaderData );
+}
+
 RenderTaskList* UpdateManager::GetRenderTaskList( bool systemLevel )
 {
   if ( !systemLevel )
@@ -907,6 +914,25 @@ void UpdateManager::ProcessPropertyNotifications()
   }
 }
 
+void UpdateManager::ForwardCompiledShadersToEventThread()
+{
+  DALI_ASSERT_DEBUG( (mImpl->shaderSaver != 0) && "shaderSaver should be wired-up during startup." );
+  if( mImpl->shaderSaver )
+  {
+    ShaderDataBatchedQueue& compiledShaders = mImpl->compiledShaders[mSceneGraphBuffers.GetUpdateBufferIndex()];
+    if( compiledShaders.size() > 0 )
+    {
+      ShaderSaver& factory = *mImpl->shaderSaver;
+      ShaderDataBatchedQueueIterator i   = compiledShaders.begin();
+      ShaderDataBatchedQueueIterator end = compiledShaders.end();
+      for( ; i != end; ++i )
+      {
+        mImpl->notificationManager.QueueMessage( ShaderCompiledMessage( factory, *i ) );
+      }
+    }
+  }
+}
+
 void UpdateManager::UpdateNodes()
 {
   mImpl->nodeDirtyFlags = NothingFlag;
@@ -983,6 +1009,9 @@ unsigned int UpdateManager::Update( float elapsedSeconds,
   // 6) Post Process Ids of resources updated by renderer
   mImpl->resourceManager.PostProcessResources( bufferIndex );
 
+  // 6.1) Forward a batch of compiled shader programs to event thread for saving
+  ForwardCompiledShadersToEventThread();
+
   // Although the scene-graph may not require an update, we still need to synchronize double-buffered
   // renderer lists if the scene was updated in the previous frame.
   // We should not start skipping update steps or reusing lists until there has been two frames where nothing changes
@@ -1174,6 +1203,11 @@ void UpdateManager::SetLayerDepths( const SortedLayerPointers& layers, bool syst
   }
 }
 
+void UpdateManager::SetShaderSaver( ShaderSaver& upstream )
+{
+  mImpl->shaderSaver = &upstream;
+}
+
 } // namespace SceneGraph
 
 } // namespace Internal
index 1f6e632..10bbfcf 100644 (file)
@@ -26,6 +26,7 @@
 
 #include <dali/internal/common/message.h>
 #include <dali/internal/common/type-abstraction-enums.h>
+#include <dali/internal/common/shader-saver.h>
 #include <dali/internal/event/common/event-thread-services.h>
 #include <dali/internal/update/animation/scene-graph-animation.h>
 #include <dali/internal/update/common/scene-graph-buffers.h>
@@ -84,7 +85,7 @@ class RendererAttachment;
  * It also maintains the lifecycle of nodes and other property owners that are
  * disconnected from the scene graph.
  */
-class UpdateManager
+class UpdateManager : public ShaderSaver
 {
 public:
 
@@ -115,9 +116,9 @@ public:
                  TouchResampler& touchResampler );
 
   /**
-   * Destructor. Not virtual as this is not a base class
+   * Destructor.
    */
-  ~UpdateManager();
+  virtual ~UpdateManager();
 
   // Node connection methods
 
@@ -305,11 +306,25 @@ public:
   /**
    * Set the shader program for a Shader object
    * @param[in] shader        The shader to modify
-   * @param[in] resourceId    A ResourceManager ticket ID for the program data (source and compiled binary)
-   * @param[in] shaderHash    hash key created with vertex and fragment shader code
+   * @param[in] shaderData    Source code, hash over source, and optional compiled binary for the shader program
    * @param[in] modifiesGeometry True if the vertex shader modifies geometry
    */
-  void SetShaderProgram( Shader* shader, Integration::ResourceId resourceId, size_t shaderHash, bool modifiesGeometry );
+  void SetShaderProgram( Shader* shader, Integration::ShaderDataPtr shaderData, bool modifiesGeometry );
+
+  /**
+   * @brief Accept compiled shaders passed back on render thread for saving.
+   * @param[in] shaderData Source code, hash over source, and corresponding compiled binary to be saved.
+   */
+  virtual void SaveBinary( Integration::ShaderDataPtr shaderData );
+
+  /**
+   * @brief Set the destination for compiled shader binaries to be passed on to.
+   * The dispatcher passed in will be called from the update thread.
+   * @param[in] upstream A sink for ShaderDatas to be passed into.
+   */
+  void SetShaderSaver( ShaderSaver& upstream );
+
+  // Gestures
 
   /**
    * Add a newly created gesture.
@@ -461,6 +476,11 @@ private:
   void ProcessPropertyNotifications();
 
   /**
+   * Pass shader binaries queued here on to event thread.
+   */
+  void ForwardCompiledShadersToEventThread();
+
+  /**
    * Update the default camera.
    * This must be altered to match the root Node for 2D layouting.
    * @param[in] updateBuffer The buffer to read the root node size from.
@@ -678,8 +698,6 @@ inline void PropertyNotificationSetNotifyModeMessage( UpdateManager& manager,
   new (slot) LocalType( &manager, &UpdateManager::PropertyNotificationSetNotify, propertyNotification, notifyMode );
 }
 
-
-
 // The render thread can safely change the Shader
 inline void AddShaderMessage( UpdateManager& manager, Shader& shader )
 {
@@ -706,17 +724,16 @@ inline void RemoveShaderMessage( UpdateManager& manager, Shader& shader )
 
 inline void SetShaderProgramMessage( UpdateManager& manager,
                                      Shader& shader,
-                                     Integration::ResourceId resourceId,
-                                     size_t shaderHash,
+                                     Integration::ShaderDataPtr shaderData,
                                      bool modifiesGeometry )
 {
-  typedef MessageValue4< UpdateManager, Shader*, Integration::ResourceId, size_t, bool > LocalType;
+  typedef MessageValue3< UpdateManager, Shader*, Integration::ShaderDataPtr, bool > LocalType;
 
   // Reserve some memory inside the message queue
   unsigned int* slot = manager.ReserveMessageSlot( sizeof( LocalType ) );
 
   // Construct message in the message queue memory; note that delete should not be called on the return value
-  new (slot) LocalType( &manager, &UpdateManager::SetShaderProgram, &shader, resourceId, shaderHash, modifiesGeometry );
+  new (slot) LocalType( &manager, &UpdateManager::SetShaderProgram, &shader, shaderData, modifiesGeometry );
 }
 
 inline void SetBackgroundColorMessage( UpdateManager& manager, const Vector4& color )
index acbb558..5c558de 100644 (file)
@@ -69,10 +69,6 @@ typedef std::map<ResourceId, BitmapMetadata>     BitmapMetadataCache;
 typedef BitmapMetadataCache::iterator            BitmapMetadataIter;
 typedef std::pair<ResourceId, BitmapMetadata>    BitmapMetadataPair;
 
-typedef std::map<ResourceId, ShaderDataPtr>      ShaderCache;
-typedef ShaderCache::iterator                    ShaderCacheIter;
-typedef ShaderCache::size_type                   ShaderCacheSize;
-typedef std::pair<ResourceId, ShaderDataPtr>     ShaderDataPair;
 
 static inline bool RemoveId( LiveRequestContainer& container, ResourceId id )
 {
@@ -141,7 +137,6 @@ struct ResourceManager::ResourceManagerImpl
    * This is the resource cache. It's filled/emptied from within Core::Update()
    */
   BitmapMetadataCache mBitmapMetadata;
-  ShaderCache         mShaders;
 };
 
 ResourceManager::ResourceManager( PlatformAbstraction& platformAbstraction,
@@ -339,30 +334,6 @@ void ResourceManager::HandleAllocateTextureRequest( ResourceId id, unsigned int
   mImpl->mTextureCacheDispatcher.DispatchCreateTexture( id, width, height, pixelFormat, true /* true = clear the texture */ );
 }
 
-void ResourceManager::HandleLoadShaderRequest( ResourceId id, const ResourceTypePath& typePath )
-{
-  DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceManager: HandleLoadShaderRequest(id:%u, path:%s)\n", id, typePath.path.c_str());
-
-  const ShaderResourceType* shaderType = dynamic_cast<const ShaderResourceType*>(typePath.type);
-  DALI_ASSERT_DEBUG(shaderType);
-
-  if( shaderType )
-  {
-    ShaderDataPtr shaderData(new ShaderData(shaderType->vertexShader, shaderType->fragmentShader));
-
-    mImpl->mPlatformAbstraction.LoadShaderBinFile(typePath.path, shaderData->GetBuffer());
-
-    // Add the ID to the completed set
-    mImpl->newCompleteRequests.insert(id);
-
-    // Cache the resource
-    mImpl->mShaders.insert(ShaderDataPair(id, shaderData));
-
-    // Let NotificationManager know that the resource manager needs to do some processing
-    NotifyTickets();
-  }
-}
-
 void ResourceManager::HandleUpdateBitmapAreaRequest( ResourceId textureId, const RectArea& area )
 {
   if( textureId )
@@ -459,11 +430,6 @@ void ResourceManager::HandleSaveResourceRequest( ResourceId id, const ResourceTy
       {
         break;
       }
-      case ResourceShader:
-      {
-        resource = GetShaderData(id);
-        break;
-      }
 
     }
 
@@ -621,17 +587,6 @@ BitmapMetadata ResourceManager::GetBitmapMetadata(ResourceId id)
   return metadata;
 }
 
-ShaderDataPtr ResourceManager::GetShaderData(ResourceId id)
-{
-  ShaderDataPtr shaderData;
-  ShaderCacheIter iter = mImpl->mShaders.find(id);
-  if(iter != mImpl->mShaders.end())
-  {
-    shaderData = iter->second;
-  }
-  return shaderData;
-}
-
 /********************************************************************************
  ************************* ResourceCache Implementation  ************************
  ********************************************************************************/
@@ -710,13 +665,6 @@ void ResourceManager::LoadResponse( ResourceId id, ResourceTypeId type, Resource
       {
         break;
       }
-
-      case ResourceShader:
-      {
-        mImpl->mShaders.insert(ShaderDataPair(id, static_cast<ShaderData*>(resource.Get())));
-        break;
-      }
-
     }
 
     // Let ResourceClient know that the resource manager has loaded something that its clients might want to hear about:
@@ -865,15 +813,6 @@ void ResourceManager::DiscardDeadResources( BufferIndex updateBufferIndex )
       case ResourceNativeImage:
       case ResourceTargetImage:
         break;
-
-      case ResourceShader:
-      {
-        ShaderCacheIter shaderIter = mImpl->mShaders.find(iter->first);
-        DALI_ASSERT_DEBUG( mImpl->mShaders.end() != shaderIter );
-        // shader data is owned through intrusive pointers so no need for discard queue
-        mImpl->mShaders.erase( shaderIter );
-        break;
-      }
     }
 
     // Erase the item and increment the iterator
index 131c45c..6c91394 100644 (file)
 #include <dali/integration-api/bitmap.h>
 #include <dali/integration-api/platform-abstraction.h>
 #include <dali/integration-api/resource-cache.h>
-#include <dali/integration-api/shader-data.h>
 
 #include <dali/internal/common/message.h>
 #include <dali/internal/event/common/event-thread-services.h>
 #include <dali/internal/event/common/thread-local-storage.h>
+#include <dali/internal/event/resources/resource-type-path.h>
 #include <dali/internal/event/resources/resource-client-declarations.h>
-#include <dali/internal/event/effects/shader-factory.h>
 #include <dali/internal/update/resources/resource-manager-declarations.h>
 #include <dali/internal/update/resources/bitmap-metadata.h>
 
@@ -239,14 +238,6 @@ public: // Used by ResourceClient
    */
   void HandleAllocateTextureRequest( ResourceId id, unsigned int width, unsigned int height, Pixel::Format pixelFormat );
 
-
-  /**
-   * Load a shader program from a file
-   * @param[in] id The resource id
-   * @param[in] typePath The type & path of the resource
-   */
-  void HandleLoadShaderRequest(ResourceId id, const ResourceTypePath& typePath );
-
   /**
    * Update bitmap area request
    * @param[in] textureId The resource ID of a bitmap-texture to remove.
@@ -323,14 +314,7 @@ public: // Used by ResourceClient
    */
   BitmapMetadata GetBitmapMetadata(ResourceId id);
 
-  /**
-   * Returns the shader resource corresponding to the Id
-   * @param[in] id - the id of a shader binary resource.
-   * @return the shader binary resource data or NULL if it has not been loaded.
-   */
-  Integration::ShaderDataPtr GetShaderData(ResourceId id);
-
-  /********************************************************************************
+    /********************************************************************************
    ************************* ResourceCache Implementation  ************************
    ********************************************************************************/
 public:
@@ -503,21 +487,6 @@ inline void RequestAllocateTextureMessage( EventThreadServices& eventThreadServi
   new (slot) LocalType( &manager, &ResourceManager::HandleAllocateTextureRequest, id, width, height, pixelFormat );
 }
 
-
-inline void RequestLoadShaderMessage( EventThreadServices& eventThreadServices,
-                                      ResourceManager& manager,
-                                      ResourceId id,
-                                      const ResourceTypePath& typePath )
-{
-  typedef MessageValue2< ResourceManager, ResourceId, ResourceTypePath > LocalType;
-
-  // Reserve some memory inside the message queue
-  unsigned int* slot = eventThreadServices.ReserveMessageSlot( sizeof( LocalType ) );
-
-  // Construct message in the message queue memory; note that delete should not be called on the return value
-  new (slot) LocalType( &manager, &ResourceManager::HandleLoadShaderRequest, id, typePath );
-}
-
 inline void RequestUpdateBitmapAreaMessage( EventThreadServices& eventThreadServices,
                                             ResourceManager& manager,
                                             ResourceId id,