Add destroy hooks for several GL objects.

These hooks allow the back-end renderer to free object resources
without having to store pointers to shared device handles for
each and every object. This will allow us to save memory on
back-ends that really care about memory overhead.

There is a downside in that there is more boilerplate in passing
gl::Context handles around everywhere.

BUG=angleproject:1684

Change-Id: I89463bba8d23f92920e8956650cb73c7fc6d66b7
Reviewed-on: https://chromium-review.googlesource.com/426401
Commit-Queue: Jamie Madill <jmadill@chromium.org>
Reviewed-by: Geoff Lang <geofflang@chromium.org>
diff --git a/src/libANGLE/ResourceManager.cpp b/src/libANGLE/ResourceManager.cpp
index c7defac..c60db2c 100644
--- a/src/libANGLE/ResourceManager.cpp
+++ b/src/libANGLE/ResourceManager.cpp
@@ -54,10 +54,11 @@
 }
 
 template <typename HandleAllocatorType>
-void ResourceManagerBase<HandleAllocatorType>::release()
+void ResourceManagerBase<HandleAllocatorType>::release(const Context *context)
 {
     if (--mRefCount == 0)
     {
+        reset(context);
         delete this;
     }
 }
@@ -65,14 +66,23 @@
 template <typename ResourceType, typename HandleAllocatorType, typename ImplT>
 TypedResourceManager<ResourceType, HandleAllocatorType, ImplT>::~TypedResourceManager()
 {
-    while (!mObjectMap.empty())
-    {
-        deleteObject(mObjectMap.begin()->first);
-    }
+    ASSERT(mObjectMap.empty());
 }
 
 template <typename ResourceType, typename HandleAllocatorType, typename ImplT>
-void TypedResourceManager<ResourceType, HandleAllocatorType, ImplT>::deleteObject(GLuint handle)
+void TypedResourceManager<ResourceType, HandleAllocatorType, ImplT>::reset(const Context *context)
+{
+    while (!mObjectMap.empty())
+    {
+        deleteObject(context, mObjectMap.begin()->first);
+    }
+    mObjectMap.clear();
+}
+
+template <typename ResourceType, typename HandleAllocatorType, typename ImplT>
+void TypedResourceManager<ResourceType, HandleAllocatorType, ImplT>::deleteObject(
+    const Context *context,
+    GLuint handle)
 {
     auto objectIter = mObjectMap.find(handle);
     if (objectIter == mObjectMap.end())
@@ -82,6 +92,7 @@
 
     if (objectIter->second != nullptr)
     {
+        objectIter->second->destroy(context);
         ImplT::DeleteObject(objectIter->second);
     }
 
@@ -181,14 +192,22 @@
 
 ShaderProgramManager::~ShaderProgramManager()
 {
+    ASSERT(mPrograms.empty());
+    ASSERT(mShaders.empty());
+}
+
+void ShaderProgramManager::reset(const Context *context)
+{
     while (!mPrograms.empty())
     {
-        deleteProgram(mPrograms.begin()->first);
+        deleteProgram(context, mPrograms.begin()->first);
     }
+    mPrograms.clear();
     while (!mShaders.empty())
     {
-        deleteShader(mShaders.begin()->first);
+        deleteShader(context, mShaders.begin()->first);
     }
+    mShaders.clear();
 }
 
 GLuint ShaderProgramManager::createShader(rx::GLImplFactory *factory,
@@ -201,9 +220,9 @@
     return handle;
 }
 
-void ShaderProgramManager::deleteShader(GLuint shader)
+void ShaderProgramManager::deleteShader(const Context *context, GLuint shader)
 {
-    deleteObject(&mShaders, shader);
+    deleteObject(context, &mShaders, shader);
 }
 
 Shader *ShaderProgramManager::getShader(GLuint handle) const
@@ -218,9 +237,9 @@
     return handle;
 }
 
-void ShaderProgramManager::deleteProgram(GLuint program)
+void ShaderProgramManager::deleteProgram(const gl::Context *context, GLuint program)
 {
-    deleteObject(&mPrograms, program);
+    deleteObject(context, &mPrograms, program);
 }
 
 Program *ShaderProgramManager::getProgram(GLuint handle) const
@@ -229,7 +248,9 @@
 }
 
 template <typename ObjectType>
-void ShaderProgramManager::deleteObject(ResourceMap<ObjectType> *objectMap, GLuint id)
+void ShaderProgramManager::deleteObject(const Context *context,
+                                        ResourceMap<ObjectType> *objectMap,
+                                        GLuint id)
 {
     auto iter = objectMap->find(id);
     if (iter == objectMap->end())
@@ -241,6 +262,7 @@
     if (object->getRefCount() == 0)
     {
         mHandleAllocator.release(id);
+        object->destroy(context);
         SafeDelete(object);
         objectMap->erase(iter);
     }
@@ -421,10 +443,16 @@
 
 PathManager::~PathManager()
 {
+    ASSERT(mPaths.empty());
+}
+
+void PathManager::reset(const Context *context)
+{
     for (auto path : mPaths)
     {
         SafeDelete(path.second);
     }
+    mPaths.clear();
 }
 
 // FramebufferManager Implementation.