Optimized shader hash to not allocate memory or perform multiple passes of string... 83/28683/5
authorNick Holland <nick.holland@partner.samsung.com>
Tue, 14 Oct 2014 07:17:35 +0000 (08:17 +0100)
committerNick Holland <nick.holland@partner.samsung.com>
Wed, 15 Oct 2014 07:05:23 +0000 (08:05 +0100)
Applications like dali-demo end up hashing around 1MB of shader source on startup
due to multiple calls to ShaderFactory::Load ( 340 calls for dali-demo).

The previous code would:
 - Allocate a new string to hold both vertex/ fragment source code
 - Copy vertex / fragment source code in to the new string
 - Pass through the string removing white spaces
 - Pass through the string removing tabs
 - Pass through the string removing new line characters
 - Pass through the string to perform Hash calculation

So if a total of 1MB is passed to the hasher it would end
read/ writing around 5MB of data.

Hence OProfile flagged it up as being a bottleneck for some apps on startup.

New version does no memory allocation and does a single pass of the data.

Todo: Need to look at a better way of comparing shaders

Change-Id: I39c8b351c65c6e91f2c4b32e321f861d634ccca4

dali/internal/common/dali-hash.cpp
dali/internal/common/dali-hash.h
dali/internal/event/effects/shader-factory.cpp
dali/internal/event/effects/shader-factory.h
dali/internal/event/images/image-factory.cpp
dali/internal/event/text/font-factory.cpp

index e77839d..f154b14 100644 (file)
 namespace Dali
 {
 
+namespace //un-named namespace
+{
 /*
  * djb2 (http://www.cse.yorku.ca/~oz/hash.html)
  */
-unsigned long StringHash::operator()(const std::string& toHash)
-{
-  unsigned long hash = 5381;
+const unsigned long INITIAL_HASH_VALUE = 5381;
 
-  const char *str = toHash.c_str();
-
-  while( int c = *str++ )
+inline void HashShader( const char* string, unsigned long& hash )
+{
+  while( int c = *string++ )
   {
     hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
   }
+}
+} // un-named namespace
+
+unsigned long CalculateHash(const std::string& toHash)
+{
+  unsigned long hash = INITIAL_HASH_VALUE;
+
+  HashShader( toHash.c_str(), hash );
 
   return hash;
 }
 
+unsigned long CalculateHash(const std::string& string1, const std::string& string2)
+{
+  unsigned long hash = INITIAL_HASH_VALUE;
+
+  HashShader( string1.c_str(), hash);
+  HashShader( string2.c_str(), hash );
+  return hash;
+}
+
+
+
+
 } // namespace Dali
index 487efd3..a609762 100644 (file)
 namespace Dali
 {
 
-struct StringHash
-{
-  unsigned long operator()(const std::string& toHash);
-};
+
+/**
+ * @brief Create a hash code for the string
+ * @param toHash string to hash
+ * @return hash code
+ */
+unsigned long CalculateHash(const std::string& toHash);
+
+
+/**
+ * @brief Create a hash code for 2 strings combined
+ * @param string1 first string
+ * @param string2 second string
+ * @return hash code
+ */
+unsigned long CalculateHash(const std::string& string1, const std::string& string2);
+
+
+
 
 } // namespace Dali
 
index 6c488d3..5d7dc4c 100644 (file)
@@ -61,7 +61,7 @@ ResourceTicketPtr ShaderFactory::Load(const std::string& vertexSource, const std
 {
   ResourceTicketPtr ticket;
 
-  shaderHash = HashShaderSource(vertexSource, fragmentSource);
+  shaderHash = CalculateHash(vertexSource, fragmentSource);
   std::stringstream stringHash;
   stringHash << shaderHash;
   std::string filename = DALI_SHADERBIN_DIR;
@@ -211,19 +211,6 @@ void ShaderFactory::LoadTextSubtypeShaders(ShaderEffectPtr shaderEffect)
 }
 
 
-size_t ShaderFactory::HashShaderSource(const std::string& vertexSource, const std::string& fragmentSource) const
-{
-  std::string source = vertexSource + fragmentSource;
-
-  // remove all white spaces, tabs and new lines
-  source.erase(std::remove(source.begin(), source.end(), ' '), source.end());
-  source.erase(std::remove(source.begin(), source.end(), '\n'), source.end());
-  source.erase(std::remove(source.begin(), source.end(), '\t'), source.end());
-
-  StringHash hasher;
-  return hasher( source );
-}
-
 } // namespace Internal
 
 } // namespace Dali
index 6da5ca4..2314c48 100644 (file)
@@ -83,14 +83,6 @@ private:
   // Undefined
   ShaderFactory& operator=( const ShaderFactory& rhs );
 
-  /**
-   * Returns a hash of the shader strings
-   * @param[in] vertexShaderSrc   Source code for the vertex shader
-   * @param[in] fragmentShaderSrc Source code for the fragment shader
-   * @return Hashed value
-   */
-  size_t HashShaderSource( const std::string& vertexShaderSrc, const std::string& fragmentShaderSrc ) const;
-
 private:
   ResourceClient&       mResourceClient;
   ResourceTypePathIdMap mResourceTypePathIdMap; ///< A map of resource IDs sorted by ResourceTypePath
index c7e8f82..67e0895 100644 (file)
@@ -60,8 +60,7 @@ Request* ImageFactory::RegisterRequest( const std::string &filename, const Image
 {
   // check url cache
   // check if same request exists
-  StringHash stringHashFunc;
-  std::size_t urlHash = stringHashFunc( filename );
+  std::size_t urlHash = CalculateHash( filename );
 
   Request* foundReq( NULL );
   foundReq = FindRequest(filename, urlHash, attr);
index 9b8ff20..c088d0f 100644 (file)
@@ -25,8 +25,6 @@
 #include <dali/internal/event/text/atlas/glyph-atlas-manager.h>
 #include <dali/internal/common/dali-hash.h>
 
-// EXTERNAL INCLUDES
-#include <boost/functional/hash.hpp>
 
 using namespace Dali::Integration;
 
@@ -57,8 +55,7 @@ FontFactory::~FontFactory()
 FontMetricsIntrusivePtr FontFactory::GetFontMetrics( const std::string& fontFamily, const std::string& fontStyle )
 {
 
-  StringHash hasher;
-  std::size_t hashValue = hasher(fontFamily + fontStyle);
+  std::size_t hashValue = CalculateHash(fontFamily,fontStyle);
   FontMetricsIntrusivePtr metrics;
 
   FontMetricsIter iter = mMetricsCache.find( hashValue );
@@ -87,8 +84,7 @@ FontMetricsIntrusivePtr FontFactory::GetFontMetrics( const std::string& fontFami
 void FontFactory::RemoveFontMetrics(const std::string& fontFamily,
                                     const std::string& fontStyle)
 {
-  StringHash hasher;
-  std::size_t hashValue = hasher(fontFamily + fontStyle);
+  std::size_t hashValue = CalculateHash(fontFamily, fontStyle);
   FontMetricsIntrusivePtr metrics;
 
   FontMetricsIter iter = mMetricsCache.find( hashValue );