renderengine: use std::unordered_map in ProgramCache

Replace DefaultKeyedVector by std::unordered_map for
ProgramCache::mCache.  Dump cache size in dumpsys.

Bug: 115738279
Test: boots
Change-Id: I28428e32866e6d4e78df4b569e476b33be31c091
diff --git a/services/surfaceflinger/RenderEngine/gl/GLES20RenderEngine.cpp b/services/surfaceflinger/RenderEngine/gl/GLES20RenderEngine.cpp
index 1b0a539..b94cdca 100644
--- a/services/surfaceflinger/RenderEngine/gl/GLES20RenderEngine.cpp
+++ b/services/surfaceflinger/RenderEngine/gl/GLES20RenderEngine.cpp
@@ -35,6 +35,7 @@
 #include <ui/DebugUtils.h>
 #include <ui/Rect.h>
 #include <ui/Region.h>
+#include <utils/KeyedVector.h>
 #include <utils/String8.h>
 #include <utils/Trace.h>
 #include "GLExtensions.h"
@@ -883,6 +884,10 @@
     result.appendFormat("GLES: %s, %s, %s\n", extensions.getVendor(), extensions.getRenderer(),
                         extensions.getVersion());
     result.appendFormat("%s\n", extensions.getExtensions());
+
+    result.appendFormat("RenderEngine program cache size: %zu\n",
+                        ProgramCache::getInstance().getSize());
+
     result.appendFormat("RenderEngine last dataspace conversion: (%s) to (%s)\n",
                         dataspaceDetails(static_cast<android_dataspace>(mDataSpace)).c_str(),
                         dataspaceDetails(static_cast<android_dataspace>(mOutputDataSpace)).c_str());
diff --git a/services/surfaceflinger/RenderEngine/gl/ProgramCache.cpp b/services/surfaceflinger/RenderEngine/gl/ProgramCache.cpp
index c118248..1e7e93c 100644
--- a/services/surfaceflinger/RenderEngine/gl/ProgramCache.cpp
+++ b/services/surfaceflinger/RenderEngine/gl/ProgramCache.cpp
@@ -20,6 +20,7 @@
 
 #include <GLES2/gl2.h>
 #include <GLES2/gl2ext.h>
+#include <log/log.h>
 #include <renderengine/private/Description.h>
 #include <utils/String8.h>
 #include <utils/Trace.h>
@@ -94,10 +95,8 @@
         if (tex != Key::TEXTURE_OFF && tex != Key::TEXTURE_EXT && tex != Key::TEXTURE_2D) {
             continue;
         }
-        Program* program = mCache.valueFor(shaderKey);
-        if (program == nullptr) {
-            program = generateProgram(shaderKey);
-            mCache.add(shaderKey, program);
+        if (mCache.count(shaderKey) == 0) {
+            mCache.emplace(shaderKey, generateProgram(shaderKey));
             shaderCount++;
         }
     }
@@ -113,10 +112,8 @@
             shaderKey.set(Key::OPACITY_MASK,
                           (i & 1) ? Key::OPACITY_OPAQUE : Key::OPACITY_TRANSLUCENT);
             shaderKey.set(Key::ALPHA_MASK, (i & 2) ? Key::ALPHA_LT_ONE : Key::ALPHA_EQ_ONE);
-            Program* program = mCache.valueFor(shaderKey);
-            if (program == nullptr) {
-                program = generateProgram(shaderKey);
-                mCache.add(shaderKey, program);
+            if (mCache.count(shaderKey) == 0) {
+                mCache.emplace(shaderKey, generateProgram(shaderKey));
                 shaderCount++;
             }
         }
@@ -667,19 +664,19 @@
     Key needs(computeKey(description));
 
     // look-up the program in the cache
-    Program* program = mCache.valueFor(needs);
-    if (program == nullptr) {
+    auto it = mCache.find(needs);
+    if (it == mCache.end()) {
         // we didn't find our program, so generate one...
-        nsecs_t time = -systemTime();
-        program = generateProgram(needs);
-        mCache.add(needs, program);
-        time += systemTime();
+        nsecs_t time = systemTime();
+        it = mCache.emplace(needs, generateProgram(needs)).first;
+        time = systemTime() - time;
 
         ALOGV(">>> generated new program: needs=%08X, time=%u ms (%zu programs)", needs.mKey,
               uint32_t(ns2ms(time)), mCache.size());
     }
 
     // here we have a suitable program for this description
+    Program* program = it->second;
     if (program->isValid()) {
         program->use();
         program->setUniforms(description);
diff --git a/services/surfaceflinger/RenderEngine/gl/ProgramCache.h b/services/surfaceflinger/RenderEngine/gl/ProgramCache.h
index 47963eb..bf5e434 100644
--- a/services/surfaceflinger/RenderEngine/gl/ProgramCache.h
+++ b/services/surfaceflinger/RenderEngine/gl/ProgramCache.h
@@ -17,9 +17,10 @@
 #ifndef SF_RENDER_ENGINE_PROGRAMCACHE_H
 #define SF_RENDER_ENGINE_PROGRAMCACHE_H
 
+#include <unordered_map>
+
 #include <GLES2/gl2.h>
 #include <renderengine/private/Description.h>
-#include <utils/KeyedVector.h>
 #include <utils/Singleton.h>
 #include <utils/TypeHelpers.h>
 
@@ -155,10 +156,17 @@
         }
         inline bool isY410BT2020() const { return (mKey & Y410_BT2020_MASK) == Y410_BT2020_ON; }
 
-        // this is the definition of a friend function -- not a method of class Needs
-        friend inline int strictly_order_type(const Key& lhs, const Key& rhs) {
-            return (lhs.mKey < rhs.mKey) ? 1 : 0;
+        // for use by std::unordered_map
+
+        bool operator==(const Key& other) const {
+            return mKey == other.mKey;
         }
+
+        struct Hash {
+            size_t operator()(const Key& key) const {
+                return static_cast<size_t>(key.mKey);
+            }
+        };
     };
 
     ProgramCache();
@@ -167,6 +175,8 @@
     // Generate shaders to populate the cache
     void primeCache(bool useColorManagement);
 
+    size_t getSize() const { return mCache.size(); }
+
     // useProgram lookup a suitable program in the cache or generates one
     // if none can be found.
     void useProgram(const Description& description);
@@ -191,7 +201,7 @@
 
     // Key/Value map used for caching Programs. Currently the cache
     // is never shrunk.
-    DefaultKeyedVector<Key, Program*> mCache;
+    std::unordered_map<Key, Program*, Key::Hash> mCache;
 };
 
 }  // namespace gl