Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 80523e2e authored by Jesse Hall's avatar Jesse Hall
Browse files

vulkan: Implement layer and extension enumeration

Change-Id: I485ebbe3e57da396d361f772793e1e89850c334c
(cherry picked from commit 4bee2c3f2fdff04f1eb437f24a7bcf841364d5b3)
parent c1ab303f
Loading
Loading
Loading
Loading
+4 −2
Original line number Diff line number Diff line
@@ -19,11 +19,12 @@ LOCAL_CLANG := true
LOCAL_CFLAGS := -std=c99 -fvisibility=hidden -fstrict-aliasing
LOCAL_CFLAGS += -DLOG_TAG=\"vulkan\"
LOCAL_CFLAGS += -Weverything -Werror -Wno-padded -Wno-undef
LOCAL_CPPFLAGS := -std=c++1y \
LOCAL_CPPFLAGS := -std=c++14 \
	-Wno-c++98-compat-pedantic \
	-Wno-exit-time-destructors \
	-Wno-c99-extensions \
	-Wno-zero-length-array
	-Wno-zero-length-array \
	-Wno-global-constructors

LOCAL_C_INCLUDES := \
	frameworks/native/vulkan/include \
@@ -31,6 +32,7 @@ LOCAL_C_INCLUDES := \

LOCAL_SRC_FILES := \
	dispatch_gen.cpp \
	layers_extensions.cpp \
	loader.cpp \
	swapchain.cpp \
	vulkan_loader_data.cpp
+268 −0
Original line number Diff line number Diff line
/*
 * Copyright 2016 The Android Open Source Project
 *
 * 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.
 */

#define LOG_NDEBUG 0

#include "loader.h"
#include <alloca.h>
#include <dirent.h>
#include <dlfcn.h>
#include <mutex>
#include <sys/prctl.h>
#include <string>
#include <string.h>
#include <vector>
#include <log/log.h>
#include <vulkan/vulkan_loader_data.h>

using namespace vulkan;

namespace vulkan {
struct Layer {
    VkLayerProperties properties;
    size_t library_idx;
    std::vector<VkExtensionProperties> extensions;
};
}  // namespace vulkan

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_layers;

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;
    }

    PFN_vkEnumerateInstanceLayerProperties enumerate_layer_properties =
        reinterpret_cast<PFN_vkEnumerateInstanceLayerProperties>(
            dlsym(dlhandle, "vkEnumerateInstanceLayerProperties"));
    if (!enumerate_layer_properties) {
        ALOGW(
            "failed to find vkEnumerateInstanceLayerProperties in library "
            "'%s': %s",
            path.c_str(), dlerror());
        dlclose(dlhandle);
        return;
    }
    PFN_vkEnumerateInstanceExtensionProperties enumerate_extension_properties =
        reinterpret_cast<PFN_vkEnumerateInstanceExtensionProperties>(
            dlsym(dlhandle, "vkEnumerateInstanceExtensionProperties"));
    if (!enumerate_extension_properties) {
        ALOGW(
            "failed to find vkEnumerateInstanceExtensionProperties in library "
            "'%s': %s",
            path.c_str(), dlerror());
        dlclose(dlhandle);
        return;
    }

    uint32_t layer_count;
    VkResult result = enumerate_layer_properties(&layer_count, nullptr);
    if (result != VK_SUCCESS) {
        ALOGW("vkEnumerateInstanceLayerProperties failed for library '%s': %d",
              path.c_str(), result);
        dlclose(dlhandle);
        return;
    }
    VkLayerProperties* properties = static_cast<VkLayerProperties*>(
        alloca(layer_count * sizeof(VkLayerProperties)));
    result = enumerate_layer_properties(&layer_count, properties);
    if (result != VK_SUCCESS) {
        ALOGW("vkEnumerateInstanceLayerProperties failed for library '%s': %d",
              path.c_str(), result);
        dlclose(dlhandle);
        return;
    }

    size_t library_idx = g_layer_libraries.size();
    g_layers.reserve(g_layers.size() + layer_count);
    for (size_t i = 0; i < layer_count; i++) {
        Layer layer;
        layer.properties = properties[i];
        layer.library_idx = library_idx;

        uint32_t count;
        result = enumerate_extension_properties(properties[i].layerName, &count,
                                                nullptr);
        if (result != VK_SUCCESS) {
            ALOGW(
                "vkEnumerateInstanceExtensionProperties(%s) failed for library "
                "'%s': %d",
                properties[i].layerName, path.c_str(), result);
            g_layers.resize(g_layers.size() - (i + 1));
            dlclose(dlhandle);
            return;
        }
        layer.extensions.resize(count);
        result = enumerate_extension_properties(properties[i].layerName, &count,
                                                layer.extensions.data());
        if (result != VK_SUCCESS) {
            ALOGW(
                "vkEnumerateInstanceExtensionProperties(%s) failed for library "
                "'%s': %d",
                properties[i].layerName, path.c_str(), result);
            g_layers.resize(g_layers.size() - (i + 1));
            dlclose(dlhandle);
            return;
        }

        g_layers.push_back(layer);
        ALOGV("found layer '%s'", properties[i].layerName);
    }

    dlclose(dlhandle);

    g_layer_libraries.push_back(LayerLibrary{path, nullptr, 0});
}

void DiscoverLayersInDirectory(const std::string& dir_path) {
    ALOGV("looking for layers in '%s'", dir_path.c_str());

    DIR* directory = opendir(dir_path.c_str());
    if (!directory) {
        int err = errno;
        ALOGV_IF(err != ENOENT, "failed to open layer directory '%s': %s (%d)",
                 dir_path.c_str(), strerror(err), err);
        return;
    }

    std::string path;
    path.reserve(dir_path.size() + 20);
    path.append(dir_path);
    path.append("/");

    struct dirent* entry;
    while ((entry = readdir(directory))) {
        size_t libname_len = strlen(entry->d_name);
        if (strncmp(entry->d_name, "libVKLayer", 10) != 0 ||
            strncmp(entry->d_name + libname_len - 3, ".so", 3) != 0)
            continue;
        path.append(entry->d_name);
        AddLayerLibrary(path);
        path.resize(dir_path.size() + 1);
    }

    closedir(directory);
}

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(2u, 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;
}

}  // anonymous namespace

namespace vulkan {

void DiscoverLayers() {
    if (prctl(PR_GET_DUMPABLE, 0, 0, 0, 0))
        DiscoverLayersInDirectory("/data/local/debug/vulkan");
    if (!LoaderData::GetInstance().layer_path.empty())
        DiscoverLayersInDirectory(LoaderData::GetInstance().layer_path.c_str());
}

uint32_t EnumerateLayers(uint32_t count, VkLayerProperties* properties) {
    uint32_t n = std::min(count, g_layers.size());
    for (uint32_t i = 0; i < n; i++) {
        properties[i] = g_layers[i].properties;
    }
    return g_layers.size();
}

void GetLayerExtensions(const char* name,
                        const VkExtensionProperties** properties,
                        uint32_t* count) {
    for (const auto& layer : g_layers) {
        if (strcmp(name, layer.properties.layerName) != 0)
            continue;
        *properties = layer.extensions.data();
        *count = layer.extensions.size();
    }
}

LayerRef GetLayerRef(const char* name) {
    for (uint32_t id = 0; id < g_layers.size(); id++) {
        if (strcmp(name, g_layers[id].properties.layerName) != 0) {
            LayerLibrary& library = g_layer_libraries[g_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);
                if (!library.dlhandle) {
                    ALOGE("failed to load layer library '%s': %s",
                          library.path.c_str(), dlerror());
                    library.refcount = 0;
                    return LayerRef(nullptr);
                }
            }
            return LayerRef(&g_layers[id]);
        }
    }
    return LayerRef(nullptr);
}

LayerRef::LayerRef(Layer* layer) : layer_(layer) {}

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) {
            dlclose(library.dlhandle);
            library.dlhandle = nullptr;
        }
    }
}

LayerRef::LayerRef(LayerRef&& other) : layer_(std::move(other.layer_)) {}

PFN_vkGetInstanceProcAddr LayerRef::GetGetInstanceProcAddr() const {
    return layer_ ? reinterpret_cast<PFN_vkGetInstanceProcAddr>(
                        GetLayerGetProcAddr(*layer_, "GetInstanceProcAddr", 19))
                  : nullptr;
}

PFN_vkGetDeviceProcAddr LayerRef::GetGetDeviceProcAddr() const {
    return layer_ ? reinterpret_cast<PFN_vkGetDeviceProcAddr>(
                        GetLayerGetProcAddr(*layer_, "GetDeviceProcAddr", 17))
                  : nullptr;
}

}  // namespace vulkan
+90 −226

File changed.

Preview size limit exceeded, changes collapsed.

+29 −0
Original line number Diff line number Diff line
@@ -117,6 +117,35 @@ VKAPI_ATTR VkResult AcquireNextImageKHR_Bottom(VkDevice device, VkSwapchainKHR s
VKAPI_ATTR VkResult QueuePresentKHR_Bottom(VkQueue queue, const VkPresentInfoKHR* present_info);
// clang-format on

// -----------------------------------------------------------------------------
// layers_extensions.cpp

struct Layer;
class LayerRef {
   public:
    LayerRef(Layer* layer);
    LayerRef(LayerRef&& other);
    ~LayerRef();
    LayerRef(const LayerRef&) = delete;
    LayerRef& operator=(const LayerRef&) = delete;

    // provides bool-like behavior
    operator const Layer*() const { return layer_; }

    PFN_vkGetInstanceProcAddr GetGetInstanceProcAddr() const;
    PFN_vkGetDeviceProcAddr GetGetDeviceProcAddr() const;

   private:
    Layer* layer_;
};

void DiscoverLayers();
uint32_t EnumerateLayers(uint32_t count, VkLayerProperties* properties);
void GetLayerExtensions(const char* name,
                        const VkExtensionProperties** properties,
                        uint32_t* count);
LayerRef GetLayerRef(const char* name);

}  // namespace vulkan

#endif  // LIBVULKAN_LOADER_H