Merge changes I97efd6c9,I6460f8f0,Ic67e4290,I16214514,Ieaa4e463, ... into nyc-dev

* changes:
  vulkan: remove g_device_layers
  vulkan: ignore device-only layers
  vulkan: ignore layer libraries without instance layers
  vulkan: add FindLayer helper
  vulkan: constify LayerRef members
  vulkan: make g_library_mutex per-LayerLibrary
  vulkan: make LayerLibrary a class
  vulkan: refactor GetLayerGetProcAddr
  vulkan: refactor AddLayerLibrary
  vulkan: refactor LayerRef::~LayerRef
  vulkan: refactor GetLayerRef
  vulkan: add a constructor for LayerLibrary
diff --git a/vulkan/libvulkan/layers_extensions.cpp b/vulkan/libvulkan/layers_extensions.cpp
index 6b53a9a..4cf1c2a 100644
--- a/vulkan/libvulkan/layers_extensions.cpp
+++ b/vulkan/libvulkan/layers_extensions.cpp
@@ -43,75 +43,118 @@
 // probably want to intern strings, etc., and will need some custom/manual data
 // structures.
 
-// TODO(jessehall): Currently we have separate lists for instance and device
-// layers. Most layers are both; we should use one entry for each layer name,
-// with a mask saying what kind(s) it is.
-
 namespace vulkan {
 namespace api {
 
 struct Layer {
     VkLayerProperties properties;
     size_t library_idx;
-    std::vector<VkExtensionProperties> extensions;
+
+    bool is_global;
+
+    std::vector<VkExtensionProperties> instance_extensions;
+    std::vector<VkExtensionProperties> device_extensions;
 };
 
 namespace {
 
-std::mutex g_library_mutex;
-struct LayerLibrary {
-    std::string path;
-    void* dlhandle;
-    size_t refcount;
-};
-std::vector<LayerLibrary> g_layer_libraries;
-std::vector<Layer> g_instance_layers;
-std::vector<Layer> g_device_layers;
+class LayerLibrary {
+   public:
+    LayerLibrary(const std::string& path)
+        : path_(path), dlhandle_(nullptr), refcount_(0) {}
 
-void AddLayerLibrary(const std::string& path) {
-    ALOGV("examining layer library '%s'", path.c_str());
-
-    void* dlhandle = dlopen(path.c_str(), RTLD_NOW | RTLD_LOCAL);
-    if (!dlhandle) {
-        ALOGW("failed to load layer library '%s': %s", path.c_str(), dlerror());
-        return;
+    LayerLibrary(LayerLibrary&& other)
+        : path_(std::move(other.path_)),
+          dlhandle_(other.dlhandle_),
+          refcount_(other.refcount_) {
+        other.dlhandle_ = nullptr;
+        other.refcount_ = 0;
     }
 
+    LayerLibrary(const LayerLibrary&) = delete;
+    LayerLibrary& operator=(const LayerLibrary&) = delete;
+
+    // these are thread-safe
+    bool Open();
+    void Close();
+
+    bool EnumerateLayers(size_t library_idx,
+                         std::vector<Layer>& instance_layers) const;
+
+    void* GetGPA(const Layer& layer,
+                 const char* gpa_name,
+                 size_t gpa_name_len) const;
+
+   private:
+    const std::string path_;
+
+    std::mutex mutex_;
+    void* dlhandle_;
+    size_t refcount_;
+};
+
+bool LayerLibrary::Open() {
+    std::lock_guard<std::mutex> lock(mutex_);
+
+    if (refcount_++ == 0) {
+        dlhandle_ = dlopen(path_.c_str(), RTLD_NOW | RTLD_LOCAL);
+        ALOGV("Opening library %s", path_.c_str());
+        if (!dlhandle_) {
+            ALOGE("failed to load layer library '%s': %s", path_.c_str(),
+                  dlerror());
+            refcount_ = 0;
+            return false;
+        }
+    }
+    ALOGV("Refcount on activate is %zu", refcount_);
+    return true;
+}
+
+void LayerLibrary::Close() {
+    std::lock_guard<std::mutex> lock(mutex_);
+
+    if (--refcount_ == 0) {
+        ALOGV("Closing library %s", path_.c_str());
+        dlclose(dlhandle_);
+        dlhandle_ = nullptr;
+    }
+    ALOGV("Refcount on destruction is %zu", refcount_);
+}
+
+bool LayerLibrary::EnumerateLayers(size_t library_idx,
+                                   std::vector<Layer>& instance_layers) const {
     PFN_vkEnumerateInstanceLayerProperties enumerate_instance_layers =
         reinterpret_cast<PFN_vkEnumerateInstanceLayerProperties>(
-            dlsym(dlhandle, "vkEnumerateInstanceLayerProperties"));
+            dlsym(dlhandle_, "vkEnumerateInstanceLayerProperties"));
     PFN_vkEnumerateInstanceExtensionProperties enumerate_instance_extensions =
         reinterpret_cast<PFN_vkEnumerateInstanceExtensionProperties>(
-            dlsym(dlhandle, "vkEnumerateInstanceExtensionProperties"));
-    PFN_vkEnumerateDeviceLayerProperties enumerate_device_layers =
-        reinterpret_cast<PFN_vkEnumerateDeviceLayerProperties>(
-            dlsym(dlhandle, "vkEnumerateDeviceLayerProperties"));
-    PFN_vkEnumerateDeviceExtensionProperties enumerate_device_extensions =
-        reinterpret_cast<PFN_vkEnumerateDeviceExtensionProperties>(
-            dlsym(dlhandle, "vkEnumerateDeviceExtensionProperties"));
-    if (!((enumerate_instance_layers && enumerate_instance_extensions) ||
-          (enumerate_device_layers && enumerate_device_extensions))) {
-        ALOGV(
-            "layer library '%s' has neither instance nor device enumeraion "
-            "functions",
-            path.c_str());
-        dlclose(dlhandle);
-        return;
+            dlsym(dlhandle_, "vkEnumerateInstanceExtensionProperties"));
+    if (!enumerate_instance_layers || !enumerate_instance_extensions) {
+        ALOGV("layer library '%s' misses some instance enumeraion functions",
+              path_.c_str());
+        return false;
     }
 
-    VkResult result;
+    // device functions are optional
+    PFN_vkEnumerateDeviceLayerProperties enumerate_device_layers =
+        reinterpret_cast<PFN_vkEnumerateDeviceLayerProperties>(
+            dlsym(dlhandle_, "vkEnumerateDeviceLayerProperties"));
+    PFN_vkEnumerateDeviceExtensionProperties enumerate_device_extensions =
+        reinterpret_cast<PFN_vkEnumerateDeviceExtensionProperties>(
+            dlsym(dlhandle_, "vkEnumerateDeviceExtensionProperties"));
+
+    // get layer counts
     uint32_t num_instance_layers = 0;
     uint32_t num_device_layers = 0;
-    if (enumerate_instance_layers) {
-        result = enumerate_instance_layers(&num_instance_layers, nullptr);
+    VkResult result = enumerate_instance_layers(&num_instance_layers, nullptr);
+    if (result != VK_SUCCESS || !num_instance_layers) {
         if (result != VK_SUCCESS) {
             ALOGW(
                 "vkEnumerateInstanceLayerProperties failed for library '%s': "
                 "%d",
-                path.c_str(), result);
-            dlclose(dlhandle);
-            return;
+                path_.c_str(), result);
         }
+        return false;
     }
     if (enumerate_device_layers) {
         result = enumerate_device_layers(VK_NULL_HANDLE, &num_device_layers,
@@ -119,23 +162,19 @@
         if (result != VK_SUCCESS) {
             ALOGW(
                 "vkEnumerateDeviceLayerProperties failed for library '%s': %d",
-                path.c_str(), result);
-            dlclose(dlhandle);
-            return;
+                path_.c_str(), result);
+            return false;
         }
     }
+
+    // get layer properties
     VkLayerProperties* properties = static_cast<VkLayerProperties*>(alloca(
         (num_instance_layers + num_device_layers) * sizeof(VkLayerProperties)));
-    if (num_instance_layers > 0) {
-        result = enumerate_instance_layers(&num_instance_layers, properties);
-        if (result != VK_SUCCESS) {
-            ALOGW(
-                "vkEnumerateInstanceLayerProperties failed for library '%s': "
-                "%d",
-                path.c_str(), result);
-            dlclose(dlhandle);
-            return;
-        }
+    result = enumerate_instance_layers(&num_instance_layers, properties);
+    if (result != VK_SUCCESS) {
+        ALOGW("vkEnumerateInstanceLayerProperties failed for library '%s': %d",
+              path_.c_str(), result);
+        return false;
     }
     if (num_device_layers > 0) {
         result = enumerate_device_layers(VK_NULL_HANDLE, &num_device_layers,
@@ -143,102 +182,121 @@
         if (result != VK_SUCCESS) {
             ALOGW(
                 "vkEnumerateDeviceLayerProperties failed for library '%s': %d",
-                path.c_str(), result);
-            dlclose(dlhandle);
-            return;
+                path_.c_str(), result);
+            return false;
         }
     }
 
-    size_t library_idx = g_layer_libraries.size();
-    size_t prev_num_instance_layers = g_instance_layers.size();
-    size_t prev_num_device_layers = g_device_layers.size();
-    g_instance_layers.reserve(prev_num_instance_layers + num_instance_layers);
-    g_device_layers.reserve(prev_num_device_layers + num_device_layers);
+    // append layers to instance_layers
+    size_t prev_num_instance_layers = instance_layers.size();
+    instance_layers.reserve(prev_num_instance_layers + num_instance_layers);
     for (size_t i = 0; i < num_instance_layers; i++) {
         const VkLayerProperties& props = properties[i];
 
         Layer layer;
         layer.properties = props;
         layer.library_idx = library_idx;
+        layer.is_global = false;
 
-        if (enumerate_instance_extensions) {
-            uint32_t count = 0;
-            result =
-                enumerate_instance_extensions(props.layerName, &count, nullptr);
-            if (result != VK_SUCCESS) {
-                ALOGW(
-                    "vkEnumerateInstanceExtensionProperties(%s) failed for "
-                    "library "
-                    "'%s': %d",
-                    props.layerName, path.c_str(), result);
-                g_instance_layers.resize(prev_num_instance_layers);
-                dlclose(dlhandle);
-                return;
-            }
-            layer.extensions.resize(count);
-            result = enumerate_instance_extensions(props.layerName, &count,
-                                                   layer.extensions.data());
-            if (result != VK_SUCCESS) {
-                ALOGW(
-                    "vkEnumerateInstanceExtensionProperties(%s) failed for "
-                    "library "
-                    "'%s': %d",
-                    props.layerName, path.c_str(), result);
-                g_instance_layers.resize(prev_num_instance_layers);
-                dlclose(dlhandle);
-                return;
+        uint32_t count = 0;
+        result =
+            enumerate_instance_extensions(props.layerName, &count, nullptr);
+        if (result != VK_SUCCESS) {
+            ALOGW(
+                "vkEnumerateInstanceExtensionProperties(%s) failed for library "
+                "'%s': %d",
+                props.layerName, path_.c_str(), result);
+            instance_layers.resize(prev_num_instance_layers);
+            return false;
+        }
+        layer.instance_extensions.resize(count);
+        result = enumerate_instance_extensions(
+            props.layerName, &count, layer.instance_extensions.data());
+        if (result != VK_SUCCESS) {
+            ALOGW(
+                "vkEnumerateInstanceExtensionProperties(%s) failed for library "
+                "'%s': %d",
+                props.layerName, path_.c_str(), result);
+            instance_layers.resize(prev_num_instance_layers);
+            return false;
+        }
+
+        for (size_t j = 0; j < num_device_layers; j++) {
+            const auto& dev_props = properties[num_instance_layers + j];
+            if (memcmp(&props, &dev_props, sizeof(props)) == 0) {
+                layer.is_global = true;
+                break;
             }
         }
 
-        g_instance_layers.push_back(layer);
-        ALOGV("  added instance layer '%s'", props.layerName);
-    }
-    for (size_t i = 0; i < num_device_layers; i++) {
-        const VkLayerProperties& props = properties[num_instance_layers + i];
-
-        Layer layer;
-        layer.properties = props;
-        layer.library_idx = library_idx;
-
-        if (enumerate_device_extensions) {
-            uint32_t count;
+        if (layer.is_global && enumerate_device_extensions) {
             result = enumerate_device_extensions(
                 VK_NULL_HANDLE, props.layerName, &count, nullptr);
             if (result != VK_SUCCESS) {
                 ALOGW(
                     "vkEnumerateDeviceExtensionProperties(%s) failed for "
-                    "library "
-                    "'%s': %d",
-                    props.layerName, path.c_str(), result);
-                g_instance_layers.resize(prev_num_instance_layers);
-                g_device_layers.resize(prev_num_device_layers);
-                dlclose(dlhandle);
-                return;
+                    "library '%s': %d",
+                    props.layerName, path_.c_str(), result);
+                instance_layers.resize(prev_num_instance_layers);
+                return false;
             }
-            layer.extensions.resize(count);
-            result =
-                enumerate_device_extensions(VK_NULL_HANDLE, props.layerName,
-                                            &count, layer.extensions.data());
+            layer.device_extensions.resize(count);
+            result = enumerate_device_extensions(
+                VK_NULL_HANDLE, props.layerName, &count,
+                layer.device_extensions.data());
             if (result != VK_SUCCESS) {
                 ALOGW(
                     "vkEnumerateDeviceExtensionProperties(%s) failed for "
-                    "library "
-                    "'%s': %d",
-                    props.layerName, path.c_str(), result);
-                g_instance_layers.resize(prev_num_instance_layers);
-                g_device_layers.resize(prev_num_device_layers);
-                dlclose(dlhandle);
-                return;
+                    "library '%s': %d",
+                    props.layerName, path_.c_str(), result);
+                instance_layers.resize(prev_num_instance_layers);
+                return false;
             }
         }
 
-        g_device_layers.push_back(layer);
-        ALOGV("  added device layer '%s'", props.layerName);
+        instance_layers.push_back(layer);
+        ALOGV("  added %s layer '%s'",
+              (layer.is_global) ? "global" : "instance", props.layerName);
     }
 
-    dlclose(dlhandle);
+    return true;
+}
 
-    g_layer_libraries.push_back(LayerLibrary{path, nullptr, 0});
+void* LayerLibrary::GetGPA(const Layer& layer,
+                           const char* gpa_name,
+                           size_t gpa_name_len) const {
+    void* gpa;
+    size_t layer_name_len =
+        std::max(size_t{2}, strlen(layer.properties.layerName));
+    char* name = static_cast<char*>(alloca(layer_name_len + gpa_name_len + 1));
+    strcpy(name, layer.properties.layerName);
+    strcpy(name + layer_name_len, gpa_name);
+    if (!(gpa = dlsym(dlhandle_, name))) {
+        strcpy(name, "vk");
+        strcpy(name + 2, gpa_name);
+        gpa = dlsym(dlhandle_, name);
+    }
+    return gpa;
+}
+
+std::vector<LayerLibrary> g_layer_libraries;
+std::vector<Layer> g_instance_layers;
+
+void AddLayerLibrary(const std::string& path) {
+    ALOGV("examining layer library '%s'", path.c_str());
+
+    LayerLibrary library(path);
+    if (!library.Open())
+        return;
+
+    if (!library.EnumerateLayers(g_layer_libraries.size(), g_instance_layers)) {
+        library.Close();
+        return;
+    }
+
+    library.Close();
+
+    g_layer_libraries.emplace_back(std::move(library));
 }
 
 void DiscoverLayersInDirectory(const std::string& dir_path) {
@@ -271,71 +329,25 @@
     closedir(directory);
 }
 
+const Layer* FindInstanceLayer(const char* name) {
+    auto layer =
+        std::find_if(g_instance_layers.cbegin(), g_instance_layers.cend(),
+                     [=](const Layer& entry) {
+                         return strcmp(entry.properties.layerName, name) == 0;
+                     });
+    return (layer != g_instance_layers.cend()) ? &*layer : nullptr;
+}
+
+const Layer* FindDeviceLayer(const char* name) {
+    const Layer* layer = FindInstanceLayer(name);
+    return (layer && layer->is_global) ? layer : nullptr;
+}
+
 void* GetLayerGetProcAddr(const Layer& layer,
                           const char* gpa_name,
                           size_t gpa_name_len) {
     const LayerLibrary& library = g_layer_libraries[layer.library_idx];
-    void* gpa;
-    size_t layer_name_len = std::max(size_t{2}, strlen(layer.properties.layerName));
-    char* name = static_cast<char*>(alloca(layer_name_len + gpa_name_len + 1));
-    strcpy(name, layer.properties.layerName);
-    strcpy(name + layer_name_len, gpa_name);
-    if (!(gpa = dlsym(library.dlhandle, name))) {
-        strcpy(name, "vk");
-        strcpy(name + 2, gpa_name);
-        gpa = dlsym(library.dlhandle, name);
-    }
-    return gpa;
-}
-
-uint32_t EnumerateLayers(const std::vector<Layer>& layers,
-                         uint32_t count,
-                         VkLayerProperties* properties) {
-    uint32_t n = std::min(count, static_cast<uint32_t>(layers.size()));
-    for (uint32_t i = 0; i < n; i++) {
-        properties[i] = layers[i].properties;
-    }
-    return static_cast<uint32_t>(layers.size());
-}
-
-void GetLayerExtensions(const std::vector<Layer>& layers,
-                        const char* name,
-                        const VkExtensionProperties** properties,
-                        uint32_t* count) {
-    auto layer =
-        std::find_if(layers.cbegin(), layers.cend(), [=](const Layer& entry) {
-            return strcmp(entry.properties.layerName, name) == 0;
-        });
-    if (layer == layers.cend()) {
-        *properties = nullptr;
-        *count = 0;
-    } else {
-        *properties = layer->extensions.data();
-        *count = static_cast<uint32_t>(layer->extensions.size());
-    }
-}
-
-LayerRef GetLayerRef(std::vector<Layer>& layers, const char* name) {
-    for (uint32_t id = 0; id < layers.size(); id++) {
-        if (strcmp(name, layers[id].properties.layerName) == 0) {
-            LayerLibrary& library = g_layer_libraries[layers[id].library_idx];
-            std::lock_guard<std::mutex> lock(g_library_mutex);
-            if (library.refcount++ == 0) {
-                library.dlhandle =
-                    dlopen(library.path.c_str(), RTLD_NOW | RTLD_LOCAL);
-                ALOGV("Opening library %s", library.path.c_str());
-                if (!library.dlhandle) {
-                    ALOGE("failed to load layer library '%s': %s",
-                          library.path.c_str(), dlerror());
-                    library.refcount = 0;
-                    return LayerRef(nullptr);
-                }
-            }
-            ALOGV("Refcount on activate is %zu", library.refcount);
-            return LayerRef(&layers[id]);
-        }
-    }
-    return LayerRef(nullptr);
+    return library.GetGPA(layer, gpa_name, gpa_name_len);
 }
 
 }  // anonymous namespace
@@ -349,45 +361,84 @@
 
 uint32_t EnumerateInstanceLayers(uint32_t count,
                                  VkLayerProperties* properties) {
-    return EnumerateLayers(g_instance_layers, count, properties);
+    uint32_t n =
+        std::min(count, static_cast<uint32_t>(g_instance_layers.size()));
+    for (uint32_t i = 0; i < n; i++)
+        properties[i] = g_instance_layers[i].properties;
+
+    return static_cast<uint32_t>(g_instance_layers.size());
 }
 
 uint32_t EnumerateDeviceLayers(uint32_t count, VkLayerProperties* properties) {
-    return EnumerateLayers(g_device_layers, count, properties);
+    uint32_t n = 0;
+    for (const auto& layer : g_instance_layers) {
+        // ignore non-global layers
+        if (!layer.is_global)
+            continue;
+
+        if (n < count)
+            properties[n] = layer.properties;
+        n++;
+    }
+
+    return n;
 }
 
 void GetInstanceLayerExtensions(const char* name,
                                 const VkExtensionProperties** properties,
                                 uint32_t* count) {
-    GetLayerExtensions(g_instance_layers, name, properties, count);
+    const Layer* layer = FindInstanceLayer(name);
+    if (layer) {
+        *properties = layer->instance_extensions.data();
+        *count = static_cast<uint32_t>(layer->instance_extensions.size());
+    } else {
+        *properties = nullptr;
+        *count = 0;
+    }
 }
 
 void GetDeviceLayerExtensions(const char* name,
                               const VkExtensionProperties** properties,
                               uint32_t* count) {
-    GetLayerExtensions(g_device_layers, name, properties, count);
+    const Layer* layer = FindDeviceLayer(name);
+    if (layer) {
+        *properties = layer->device_extensions.data();
+        *count = static_cast<uint32_t>(layer->device_extensions.size());
+    } else {
+        *properties = nullptr;
+        *count = 0;
+    }
 }
 
 LayerRef GetInstanceLayerRef(const char* name) {
-    return GetLayerRef(g_instance_layers, name);
+    const Layer* layer = FindInstanceLayer(name);
+    if (layer) {
+        LayerLibrary& library = g_layer_libraries[layer->library_idx];
+        if (!library.Open())
+            layer = nullptr;
+    }
+
+    return LayerRef(layer, true);
 }
 
 LayerRef GetDeviceLayerRef(const char* name) {
-    return GetLayerRef(g_device_layers, name);
+    const Layer* layer = FindDeviceLayer(name);
+    if (layer) {
+        LayerLibrary& library = g_layer_libraries[layer->library_idx];
+        if (!library.Open())
+            layer = nullptr;
+    }
+
+    return LayerRef(layer, false);
 }
 
-LayerRef::LayerRef(Layer* layer) : layer_(layer) {}
+LayerRef::LayerRef(const Layer* layer, bool is_instance)
+    : layer_(layer), is_instance_(is_instance) {}
 
 LayerRef::~LayerRef() {
     if (layer_) {
         LayerLibrary& library = g_layer_libraries[layer_->library_idx];
-        std::lock_guard<std::mutex> lock(g_library_mutex);
-        if (--library.refcount == 0) {
-            ALOGV("Closing library %s", library.path.c_str());
-            dlclose(library.dlhandle);
-            library.dlhandle = nullptr;
-        }
-        ALOGV("Refcount on destruction is %zu", library.refcount);
+        library.Close();
     }
 }
 
@@ -395,11 +446,12 @@
     return layer_->properties.layerName;
 }
 
-uint32_t LayerRef::GetSpecVersion() {
+uint32_t LayerRef::GetSpecVersion() const {
     return layer_->properties.specVersion;
 }
 
-LayerRef::LayerRef(LayerRef&& other) : layer_(std::move(other.layer_)) {
+LayerRef::LayerRef(LayerRef&& other)
+    : layer_(other.layer_), is_instance_(other.is_instance_) {
     other.layer_ = nullptr;
 }
 
@@ -416,10 +468,12 @@
 }
 
 bool LayerRef::SupportsExtension(const char* name) const {
-    return std::find_if(layer_->extensions.cbegin(), layer_->extensions.cend(),
+    const auto& extensions = (is_instance_) ? layer_->instance_extensions
+                                            : layer_->device_extensions;
+    return std::find_if(extensions.cbegin(), extensions.cend(),
                         [=](const VkExtensionProperties& ext) {
                             return strcmp(ext.extensionName, name) == 0;
-                        }) != layer_->extensions.cend();
+                        }) != extensions.cend();
 }
 
 }  // namespace api
diff --git a/vulkan/libvulkan/layers_extensions.h b/vulkan/libvulkan/layers_extensions.h
index 7e7bfd3..e2eb32b 100644
--- a/vulkan/libvulkan/layers_extensions.h
+++ b/vulkan/libvulkan/layers_extensions.h
@@ -25,14 +25,14 @@
 struct Layer;
 class LayerRef {
    public:
-    LayerRef(Layer* layer);
+    LayerRef(const Layer* layer, bool is_instance);
     LayerRef(LayerRef&& other);
     ~LayerRef();
     LayerRef(const LayerRef&) = delete;
     LayerRef& operator=(const LayerRef&) = delete;
 
     const char* GetName() const;
-    uint32_t GetSpecVersion();
+    uint32_t GetSpecVersion() const;
 
     // provides bool-like behavior
     operator const Layer*() const { return layer_; }
@@ -43,7 +43,8 @@
     bool SupportsExtension(const char* name) const;
 
    private:
-    Layer* layer_;
+    const Layer* layer_;
+    bool is_instance_;
 };
 
 void DiscoverLayers();