diff --git a/cmd/device-info/main.cpp b/cmd/device-info/main.cpp index ddd04cc532..29f871f98a 100644 --- a/cmd/device-info/main.cpp +++ b/cmd/device-info/main.cpp @@ -50,7 +50,7 @@ int main(int argc, char const *argv[]) { } } - device_instance instance = get_device_instance(nullptr); + device_instance instance = get_device_instance(); if (output_binary) { #if _WIN32 _setmode(_fileno(stdout), _O_BINARY); diff --git a/core/os/device/deviceinfo/cc/android/jni.cpp b/core/os/device/deviceinfo/cc/android/jni.cpp index a65d83e022..8ed220edb3 100644 --- a/core/os/device/deviceinfo/cc/android/jni.cpp +++ b/core/os/device/deviceinfo/cc/android/jni.cpp @@ -22,9 +22,7 @@ extern "C" { jbyteArray Java_com_google_android_gapid_DeviceInfoService_getDeviceInfo( JNIEnv* env) { - JavaVM* vm = nullptr; - env->GetJavaVM(&vm); - auto device_instance = get_device_instance(vm); + auto device_instance = get_device_instance(); auto out = env->NewByteArray(device_instance.size); auto data = reinterpret_cast(device_instance.data); env->SetByteArrayRegion(out, 0, device_instance.size, data); diff --git a/core/os/device/deviceinfo/cc/android/jni_helpers.h b/core/os/device/deviceinfo/cc/android/jni_helpers.h deleted file mode 100644 index ef1a7b5cb6..0000000000 --- a/core/os/device/deviceinfo/cc/android/jni_helpers.h +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Copyright (C) 2017 Google Inc. - * - * 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. - */ - -#ifndef DEVICEINFO_ANDROID_JNI_HELPERS_H -#define DEVICEINFO_ANDROID_JNI_HELPERS_H - -#include - -#include -#include - -// Class is a wrapper around a JNIEnv and class name and offers methods for -// getting fields. -class Class { - public: - inline Class(JNIEnv* env, const char* name) - : mEnv(env), mClass(env->FindClass(name)) {} - template - inline bool get_field(const char* name, T& out); - - private: - inline void convString(jstring str, std::string&); - - JNIEnv* mEnv; - jclass mClass; -}; - -template <> -inline bool Class::get_field(const char* name, std::string& out) { - if (mClass == nullptr) { - return false; - } - auto id = mEnv->GetStaticFieldID(mClass, name, "Ljava/lang/String;"); - jboolean flag = mEnv->ExceptionCheck(); - if (flag) { - mEnv->ExceptionClear(); - return false; - } - if (id == nullptr) { - return false; - } - auto str = reinterpret_cast(mEnv->GetStaticObjectField(mClass, id)); - convString(str, out); - return true; -} - -template <> -inline bool Class::get_field(const char* name, std::vector& out) { - if (mClass == nullptr) { - return false; - } - auto id = mEnv->GetStaticFieldID(mClass, name, "[Ljava/lang/String;"); - jboolean flag = mEnv->ExceptionCheck(); - if (flag) { - mEnv->ExceptionClear(); - return false; - } - if (id == nullptr) { - return false; - } - auto arr = - reinterpret_cast(mEnv->GetStaticObjectField(mClass, id)); - auto len = mEnv->GetArrayLength(arr); - out.resize(len); - for (int i = 0; i < len; i++) { - auto str = reinterpret_cast(mEnv->GetObjectArrayElement(arr, i)); - if (str == nullptr) { - return false; - } - convString(str, out[i]); - } - return true; -} - -template <> -inline bool Class::get_field(const char* name, int& out) { - if (mClass == nullptr) { - return false; - } - auto id = mEnv->GetStaticFieldID(mClass, name, "I"); - jboolean flag = mEnv->ExceptionCheck(); - if (flag) { - mEnv->ExceptionClear(); - return false; - } - if (id == nullptr) { - return false; - } - out = mEnv->GetStaticIntField(mClass, id); - return true; -} - -void Class::convString(jstring str, std::string& out) { - auto chars = mEnv->GetStringUTFChars(str, nullptr); - out = chars; - mEnv->ReleaseStringUTFChars(str, chars); -} - -#endif // DEVICEINFO_ANDROID_JNI_HELPERS_H diff --git a/core/os/device/deviceinfo/cc/android/query.cpp b/core/os/device/deviceinfo/cc/android/query.cpp index 7be02529c4..00fb862bad 100644 --- a/core/os/device/deviceinfo/cc/android/query.cpp +++ b/core/os/device/deviceinfo/cc/android/query.cpp @@ -15,7 +15,6 @@ */ #include "egl_lite.h" -#include "jni_helpers.h" #include "../query.h" @@ -24,9 +23,10 @@ #include "core/cc/log.h" #include +#include #include -#include +#include #define LOG_ERR(...) \ __android_log_print(ANDROID_LOG_ERROR, "GAPID", __VA_ARGS__); @@ -176,7 +176,7 @@ void destroyContext() { } } -bool createContext(void* platform_data) { +bool createContext() { if (gContextRefCount++ > 0) { return true; } @@ -186,12 +186,6 @@ bool createContext(void* platform_data) { gContext.mContext = nullptr; gContext.mNumCores = 0; - if (platform_data == nullptr) { - snprintf(gContext.mError, sizeof(gContext.mError), - "platform_data was nullptr"); - return false; - } - #define RESOLVE(name, pfun) \ auto name = reinterpret_cast(core::GetGlesProcAddress(#name)); \ GAPID_ASSERT(name != nullptr) @@ -271,48 +265,39 @@ bool createContext(void* platform_data) { #undef CHECK -#define CHECK(x) \ - if (!x) { \ - snprintf(gContext.mError, sizeof(gContext.mError), "JNI error:\n " #x); \ - destroyContext(); \ - return false; \ - } - - JavaVM* vm = reinterpret_cast(platform_data); - JNIEnv* env = nullptr; - auto res = vm->GetEnv(reinterpret_cast(&env), JNI_VERSION_1_6); - bool shouldDetach = false; - switch (res) { - case JNI_OK: - break; - case JNI_EDETACHED: - res = vm->AttachCurrentThread(&env, nullptr); - if (res != 0) { - snprintf(gContext.mError, sizeof(gContext.mError), - "Failed to attach thread to JavaVM. (%d)", res); - destroyContext(); - return false; - } - shouldDetach = true; - break; - default: - snprintf(gContext.mError, sizeof(gContext.mError), - "Failed to get Java env. (%d)", res); - destroyContext(); - return false; - } +#define GET_PROP(name, trans) \ + do { \ + char _v[PROP_VALUE_MAX] = {0}; \ + if (__system_property_get(name, _v) == 0) { \ + snprintf(gContext.mError, sizeof(gContext.mError), \ + "Failed reading property %s", name); \ + destroyContext(); \ + return false; \ + } \ + trans; \ + } while (0) + +#define GET_STRING_PROP(n, t) GET_PROP(n, t = _v) +#define GET_INT_PROP(n, t) GET_PROP(n, t = atoi(_v)) +#define GET_STRING_LIST_PROP(n, t) \ + do { \ + std::string _l, _t; \ + GET_STRING_PROP(n, _l); \ + std::istringstream _s(_l); \ + while (std::getline(_s, _t, ',')) { \ + t.push_back(_t); \ + } \ + } while (0) std::string manufacturer; std::string model; - Class build(env, "android/os/Build"); - CHECK(build.get_field("SUPPORTED_ABIS", gContext.mSupportedABIs)); - CHECK(build.get_field("HOST", gContext.mHost)); - CHECK(build.get_field("SERIAL", gContext.mSerial)); - CHECK(build.get_field("MANUFACTURER", manufacturer)); - CHECK(build.get_field("MODEL", model)); - CHECK(build.get_field("HARDWARE", gContext.mHardware)); - CHECK(build.get_field("DISPLAY", gContext.mOSBuild)); + GET_STRING_LIST_PROP("ro.product.cpu.abilist", gContext.mSupportedABIs); + GET_STRING_PROP("ro.build.host", gContext.mHost); + GET_STRING_PROP("ro.product.manufacturer", manufacturer); + GET_STRING_PROP("ro.product.model", model); + GET_STRING_PROP("ro.hardware", gContext.mHardware); + GET_STRING_PROP("ro.build.display.id", gContext.mOSBuild); if (model != "") { if (manufacturer != "") { @@ -322,15 +307,8 @@ bool createContext(void* platform_data) { } } - Class version(env, "android/os/Build$VERSION"); - CHECK(version.get_field("RELEASE", gContext.mOSName)); - CHECK(version.get_field("SDK_INT", gContext.mOSVersion)); - - if (shouldDetach) { - vm->DetachCurrentThread(); - } - -#undef CHECK + GET_STRING_PROP("ro.build.version.release", gContext.mOSName); + GET_INT_PROP("ro.build.version.sdk", gContext.mOSVersion); if (gContext.mSupportedABIs.size() > 0) { auto primaryABI = gContext.mSupportedABIs[0]; diff --git a/core/os/device/deviceinfo/cc/instance.cpp b/core/os/device/deviceinfo/cc/instance.cpp index 1ebd257231..d7aeb03996 100644 --- a/core/os/device/deviceinfo/cc/instance.cpp +++ b/core/os/device/deviceinfo/cc/instance.cpp @@ -19,13 +19,13 @@ extern "C" { -device_instance get_device_instance(void* platform_data) { +device_instance get_device_instance() { device_instance out = {}; query::Option query_opt; query_opt.vulkan.set_query_layers_and_extensions(true) .set_query_physical_devices(true); - auto instance = query::getDeviceInstance(query_opt, platform_data); + auto instance = query::getDeviceInstance(query_opt); if (!instance) { return out; } diff --git a/core/os/device/deviceinfo/cc/instance.h b/core/os/device/deviceinfo/cc/instance.h index 4ba013ac50..5e05914a97 100644 --- a/core/os/device/deviceinfo/cc/instance.h +++ b/core/os/device/deviceinfo/cc/instance.h @@ -29,7 +29,7 @@ typedef struct { size_t size; } device_instance; -device_instance get_device_instance(void* platform_data); +device_instance get_device_instance(); const char* get_device_instance_error(); void free_device_instance(device_instance); diff --git a/core/os/device/deviceinfo/cc/linux/query.cpp b/core/os/device/deviceinfo/cc/linux/query.cpp index fe7536e206..6d4bea5f05 100644 --- a/core/os/device/deviceinfo/cc/linux/query.cpp +++ b/core/os/device/deviceinfo/cc/linux/query.cpp @@ -225,7 +225,7 @@ void createGlContext() { gContext.mPbuffer, gContext.mGlCtx); } -bool createContext(void* platform_data) { +bool createContext() { if (gContextRefCount++ > 0) { return true; } diff --git a/core/os/device/deviceinfo/cc/osx/query.mm b/core/os/device/deviceinfo/cc/osx/query.mm index f291a79aee..83109ee04a 100644 --- a/core/os/device/deviceinfo/cc/osx/query.mm +++ b/core/os/device/deviceinfo/cc/osx/query.mm @@ -86,7 +86,7 @@ void createGlContext() { } } -bool createContext(void* platform_data) { +bool createContext() { if (gContextRefCount++ > 0) { return true; } diff --git a/core/os/device/deviceinfo/cc/query.cpp b/core/os/device/deviceinfo/cc/query.cpp index 50c12c78e7..7f749e2f97 100644 --- a/core/os/device/deviceinfo/cc/query.cpp +++ b/core/os/device/deviceinfo/cc/query.cpp @@ -71,12 +71,11 @@ void deviceInstanceID(device::Instance* instance) { delete[] proto_data; } -void buildDeviceInstance(const query::Option& opt, void* platform_data, - device::Instance** out) { +void buildDeviceInstance(const query::Option& opt, device::Instance** out) { using namespace device; using namespace google::protobuf::io; - if (!query::createContext(platform_data)) { + if (!query::createContext()) { return; } @@ -181,12 +180,12 @@ void buildDeviceInstance(const query::Option& opt, void* platform_data, namespace query { -device::Instance* getDeviceInstance(const Option& opt, void* platform_data) { +device::Instance* getDeviceInstance(const Option& opt) { device::Instance* instance = nullptr; // buildDeviceInstance on a separate thread to avoid EGL screwing with the // currently bound context. - std::thread thread(buildDeviceInstance, opt, platform_data, &instance); + std::thread thread(buildDeviceInstance, opt, &instance); thread.join(); return instance; } diff --git a/core/os/device/deviceinfo/cc/query.h b/core/os/device/deviceinfo/cc/query.h index c84296107b..49d6318475 100644 --- a/core/os/device/deviceinfo/cc/query.h +++ b/core/os/device/deviceinfo/cc/query.h @@ -64,7 +64,7 @@ struct Option { // getDeviceInstance returns the device::Instance proto message for the // current device. It must be freed with delete. -device::Instance* getDeviceInstance(const Option& opt, void* platform_data); +device::Instance* getDeviceInstance(const Option& opt); // updateVulkanPhysicalDevices modifies the given device::Instance by adding // device::VulkanPhysicalDevice to the device::Instance. If a @@ -76,10 +76,10 @@ device::Instance* getDeviceInstance(const Option& opt, void* platform_data); // ID re-hashed with the new content. Returns true if Vulkan physical device // info is fetched successfully and device::Instance updated, otherwise returns // false and keeps the device::Instance unchanged. Caution: When called with -// VkGraphicsSpy layer loaded i.e. during tracing, the function pointer to a -// layer under VkGraphicsSpy must be passed in. Resolving the Vulkan function -// addresses from loader will cause a infinite calling stack and may deadlock -// in the loader. +// GraphicsSpy layer loaded i.e. during tracing, the function pointer to a layer +// under GraphicsSpy must be passed in. Resolving the Vulkan function addresses +// from loader will cause a infinite calling stack and may deadlock in the +// loader. bool updateVulkanDriver( device::Instance* inst, size_t vk_inst_handle = 0, std::function get_inst_proc_addr = nullptr); @@ -112,7 +112,7 @@ bool hasGLorGLES(); // The functions below are used by getDeviceInstance(), and are implemented // in the target-dependent sub-directories. -bool createContext(void* platform_data); +bool createContext(); const char* contextError(); void destroyContext(); diff --git a/core/os/device/deviceinfo/cc/vk.cpp b/core/os/device/deviceinfo/cc/vk.cpp index 0246f7d9b7..9de9748604 100644 --- a/core/os/device/deviceinfo/cc/vk.cpp +++ b/core/os/device/deviceinfo/cc/vk.cpp @@ -78,7 +78,7 @@ bool vkLayersAndExtensions( auto& l = inst_layer_props[i]; uint32_t ext_count = 0; // Skip our layers. - if (!strcmp(l.layerName, "VkGraphicsSpy") || + if (!strcmp(l.layerName, "GraphicsSpy") || !strcmp(l.layerName, "VirtualSwapchain")) { continue; } diff --git a/core/os/device/deviceinfo/cc/windows/query.cpp b/core/os/device/deviceinfo/cc/windows/query.cpp index 9e0688ccc6..d17fcfae78 100644 --- a/core/os/device/deviceinfo/cc/windows/query.cpp +++ b/core/os/device/deviceinfo/cc/windows/query.cpp @@ -127,7 +127,7 @@ void createGlContext() { return; } -bool createContext(void* platform_data) { +bool createContext() { if (gContextRefCount++ > 0) { return true; } diff --git a/core/os/device/host/host_c.go b/core/os/device/host/host_c.go index f8359c2463..cf02839b0d 100644 --- a/core/os/device/host/host_c.go +++ b/core/os/device/host/host_c.go @@ -26,7 +26,7 @@ import ( ) func getHostDevice() device.Instance { - s := C.get_device_instance(nil) + s := C.get_device_instance() defer C.free_device_instance(s) if s.data == nil { panic(fmt.Errorf("Failed to get host machine information: %v", diff --git a/core/vulkan/loader/loader.go b/core/vulkan/loader/loader.go index 9dc44dacf1..1afe3d2c55 100644 --- a/core/vulkan/loader/loader.go +++ b/core/vulkan/loader/loader.go @@ -141,8 +141,8 @@ func SetupTrace(ctx context.Context, d bind.Device, abi *device.ABI, env *shell. c(ctx) } env.Set("LD_PRELOAD", lib). - AddPathStart("VK_INSTANCE_LAYERS", "VkGraphicsSpy"). - AddPathStart("VK_DEVICE_LAYERS", "VkGraphicsSpy"). + AddPathStart("VK_INSTANCE_LAYERS", "GraphicsSpy"). + AddPathStart("VK_DEVICE_LAYERS", "GraphicsSpy"). Set("GAPII_PORT_FILE", f) if abi.OS == device.Windows { // Adds the extra MSYS DLL dependencies onto the path. diff --git a/gapidapk/android/apk/BUILD.bazel b/gapidapk/android/apk/BUILD.bazel index 857ddf640e..972e8bd45b 100644 --- a/gapidapk/android/apk/BUILD.bazel +++ b/gapidapk/android/apk/BUILD.bazel @@ -19,7 +19,7 @@ _NATIVE_LIBRARIES = { "VkLayer_VirtualSwapchain": "//core/vulkan/vk_virtual_swapchain/apk", "gapii": "//gapii/apk", "interceptor": "//gapii/apk", - "VkLayerGraphicsSpy": "//gapii/apk", + "VkLayer_GraphicsSpy": "//gapii/apk", "gapir": "//cmd/gapir/apk", } diff --git a/gapii/apk/BUILD.bazel b/gapii/apk/BUILD.bazel index dc52b7f608..2068cbefe2 100644 --- a/gapii/apk/BUILD.bazel +++ b/gapii/apk/BUILD.bazel @@ -27,7 +27,7 @@ android_native( ) android_native( - name = "VkLayerGraphicsSpy", + name = "VkLayer_GraphicsSpy", visibility = ["//visibility:public"], - deps = ["//gapii/vulkan/vk_graphics_spy/cc:libVkLayerGraphicsSpy"], + deps = ["//gapii/vulkan/vk_graphics_spy/cc:libVkLayer_GraphicsSpy"], ) diff --git a/gapii/cc/spy.cpp b/gapii/cc/spy.cpp index 57b066b92a..2bb1d7bd4e 100644 --- a/gapii/cc/spy.cpp +++ b/gapii/cc/spy.cpp @@ -52,18 +52,12 @@ #include static std::unique_ptr gInstaller; -static JavaVM* gJavaVM = nullptr; extern "C" jint JNI_OnLoad(JavaVM* vm, void* reserved) { GAPID_INFO("JNI_OnLoad() was called. vm = %p", vm); - gJavaVM = vm; gapii::Spy::get(); // Construct the spy. return JNI_VERSION_1_6; } - -void* queryPlatformData() { return gJavaVM; } -#else // TARGET_OS == GAPID_OS_ANDROID -void* queryPlatformData() { return nullptr; } #endif // TARGET_OS == GAPID_OS_ANDROID using namespace gapii::GLenum; @@ -196,8 +190,7 @@ Spy::Spy() // deviceinfo queries want to call into EGL / GL commands which will be // patched. query::Option query_opt; - SpyBase::set_device_instance( - query::getDeviceInstance(query_opt, queryPlatformData())); + SpyBase::set_device_instance(query::getDeviceInstance(query_opt)); SpyBase::set_current_abi(query::currentABI()); if (!SpyBase::writeHeader()) { GAPID_ERROR("Failed at writing trace header."); diff --git a/gapii/cc/vulkan_extras.cpp b/gapii/cc/vulkan_extras.cpp index d182e38ec8..7c566826b5 100644 --- a/gapii/cc/vulkan_extras.cpp +++ b/gapii/cc/vulkan_extras.cpp @@ -716,7 +716,7 @@ uint32_t VulkanSpy::SpyOverride_vkEnumerateInstanceLayerProperties( } *pCount = 1; memset(pProperties, 0x00, sizeof(*pProperties)); - strcpy((char*)pProperties->mlayerName, "VkGraphicsSpy"); + strcpy((char*)pProperties->mlayerName, "GraphicsSpy"); pProperties->mspecVersion = VK_VERSION_MAJOR(1) | VK_VERSION_MINOR(0) | 5; pProperties->mimplementationVersion = 1; strcpy((char*)pProperties->mdescription, "vulkan_trace"); @@ -734,7 +734,7 @@ uint32_t VulkanSpy::SpyOverride_vkEnumerateDeviceLayerProperties( } *pCount = 1; memset(pProperties, 0x00, sizeof(*pProperties)); - strcpy((char*)pProperties->mlayerName, "VkGraphicsSpy"); + strcpy((char*)pProperties->mlayerName, "GraphicsSpy"); pProperties->mspecVersion = VK_VERSION_MAJOR(1) | VK_VERSION_MINOR(0) | 5; pProperties->mimplementationVersion = 1; strcpy((char*)pProperties->mdescription, "vulkan_trace"); diff --git a/gapii/client/adb.go b/gapii/client/adb.go index db7a4240b2..7f4d3e2ba9 100644 --- a/gapii/client/adb.go +++ b/gapii/client/adb.go @@ -203,10 +203,10 @@ func Connect(ctx context.Context, d adb.Device, abi *device.ABI, pipe string, o // reserveVulkanDevice reserves the given device for starting Vulkan trace and // set the implicit Vulkan layers property to let the Vulkan loader loads -// VkGraphicsSpy layer. It returns the mutex which reserves the device and error. +// GraphicsSpy layer. It returns the mutex which reserves the device and error. func reserveVulkanDevice(ctx context.Context, d adb.Device) (*flock.Mutex, error) { m := flock.Lock(d.Instance().GetSerial()) - if err := d.SetSystemProperty(ctx, vkImplicitLayersProp, "VkGraphicsSpy"); err != nil { + if err := d.SetSystemProperty(ctx, vkImplicitLayersProp, "GraphicsSpy"); err != nil { return nil, log.Err(ctx, err, "Setting up vulkan layer") } return m, nil diff --git a/gapii/vulkan/vk_graphics_spy/cc/BUILD.bazel b/gapii/vulkan/vk_graphics_spy/cc/BUILD.bazel index 0d2afffcd6..10d08fc7b2 100644 --- a/gapii/vulkan/vk_graphics_spy/cc/BUILD.bazel +++ b/gapii/vulkan/vk_graphics_spy/cc/BUILD.bazel @@ -29,16 +29,19 @@ cc_library( "//tools/build:darwin": [], "//tools/build:windows": [], # Android. - "//conditions:default": ["-ldl"], + "//conditions:default": [ + "-ldl", + "-llog", + ], }), visibility = ["//visibility:public"], deps = ["//core/vulkan/cc/include/vulkan"], ) android_dynamic_library( - name = "libVkLayerGraphicsSpy", + name = "libVkLayer_GraphicsSpy", visibility = ["//visibility:public"], - exports = "vk_graphics_spy.exports", + exports = "graphics_spy.exports", deps = [":cc"], ) diff --git a/gapii/vulkan/vk_graphics_spy/cc/GraphicsSpyLayer.json b/gapii/vulkan/vk_graphics_spy/cc/GraphicsSpyLayer.json index cce9343dc5..570473c079 100644 --- a/gapii/vulkan/vk_graphics_spy/cc/GraphicsSpyLayer.json +++ b/gapii/vulkan/vk_graphics_spy/cc/GraphicsSpyLayer.json @@ -1,7 +1,7 @@ { "file_format_version" : "1.0.0", "layer": { - "name": "VkGraphicsSpy", + "name": "GraphicsSpy", "type": "GLOBAL", "library_path": "", "api_version" : "1.0.5", @@ -25,4 +25,3 @@ ] } } - diff --git a/gapii/vulkan/vk_graphics_spy/cc/vk_graphics_spy.exports b/gapii/vulkan/vk_graphics_spy/cc/graphics_spy.exports similarity index 69% rename from gapii/vulkan/vk_graphics_spy/cc/vk_graphics_spy.exports rename to gapii/vulkan/vk_graphics_spy/cc/graphics_spy.exports index 6a265a468b..4cf775067a 100644 --- a/gapii/vulkan/vk_graphics_spy/cc/vk_graphics_spy.exports +++ b/gapii/vulkan/vk_graphics_spy/cc/graphics_spy.exports @@ -1,5 +1,5 @@ -VkGraphicsSpyGetDeviceProcAddr -VkGraphicsSpyGetInstanceProcAddr +GraphicsSpyGetDeviceProcAddr +GraphicsSpyGetInstanceProcAddr vkEnumerateInstanceLayerProperties vkEnumerateInstanceExtensionProperties vkEnumerateDeviceLayerProperties diff --git a/gapii/vulkan/vk_graphics_spy/cc/layer.cpp b/gapii/vulkan/vk_graphics_spy/cc/layer.cpp index 1abdec1d84..737040f60b 100644 --- a/gapii/vulkan/vk_graphics_spy/cc/layer.cpp +++ b/gapii/vulkan/vk_graphics_spy/cc/layer.cpp @@ -14,134 +14,129 @@ * limitations under the License. */ -#include "vulkan/vulkan.h" +#include +#include +#include +#include -#if defined(_WIN32) -#define VK_LAYER_EXPORT __declspec(dllexport) -#elif defined(__GNUC__) -#define VK_LAYER_EXPORT __attribute__((visibility("default"))) -#else -#define VK_LAYER_EXPORT -#endif +#include +#include "vulkan/vulkan.h" extern "C" { -typedef void *(*eglGetProcAddress)(char const *procname); - -#ifdef _WIN32 -#include -#include -// On windows we do not have linker namespaces, we also don't have a -// convenient way to have already loaded libgapii.dll. In this case -// we can just LoadModule(libgapii.dll) and get the pointers from there. -#define PROC(name) \ - static PFN_##name fn = (PFN_##name)getProcAddress(#name); \ - if (fn != nullptr) return fn - -HMODULE LoadGAPIIDLL() { - char path[MAX_PATH] = {'\0'}; - HMODULE this_module = GetModuleHandle("libVkLayer_GraphicsSpy.dll"); - const char libgapii[] = "libgapii.dll"; - if (this_module == NULL) { - fprintf(stderr, "Could not find libVkLayer_GraphicsSpy.dll\n"); - return 0; - } - SetLastError(0); - DWORD num_characters = GetModuleFileName(this_module, path, MAX_PATH); - if (GetLastError() != 0) { - fprintf(stderr, "Could not the path to libVkLayer_GraphicsSpy.dll\n"); - return 0; - } - for (DWORD i = num_characters - 1; i >= 0; --i) { - // Wipe out the file-name but keep the directory name if we can. - if (path[i] == '\\') { - path[i] = '\0'; - } - num_characters = i + 1; - } - - if (num_characters + strlen(libgapii) + 1 > MAX_PATH) { - fprintf(stderr, "Path too long\n"); - return 0; - } - // Append "libgapii.dll" to the full path of libVKLayer_GraphicsSpy - memcpy(path + num_characters, libgapii, strlen(libgapii) + 1); - return LoadLibrary(path); -} - -FARPROC getProcAddress(const char *name) { - static HMODULE libgapii = LoadGAPIIDLL(); - if (libgapii != NULL) { - return GetProcAddress(libgapii, name); - } - return NULL; -} - -#else +#define VK_LAYER_EXPORT __attribute__((visibility("default"))) +typedef void* (*eglGetProcAddress)(const char* procname); -#include +#define LOG_DEBUG(fmt, ...) \ + __android_log_print(ANDROID_LOG_DEBUG, "GAPID", fmt, ##__VA_ARGS__) -#define PROC(name) \ - static PFN_##name fn = (PFN_##name)(getProcAddress()("gapid_" #name)); \ +#define PROC(name) \ + static PFN_##name fn = (PFN_##name)(getProcAddress("gapid_" #name)); \ if (fn != nullptr) return fn -// On android due to linker namespaces we cannot open libgapii.so, -// but since we already have it loaded, and libEGL.so hooked, -// we can use eglGetProcAddress to find the functions. -eglGetProcAddress getProcAddress() { - static void *libegl = dlopen("libEGL.so", RTLD_NOW); +static void* getLibGapii(); + +// Up to and including Android P, libgapii, which contains the actual layer +// functions, is loaded via JDWP. Thus, use libEGL's eglGetProcAddress to find +// the functions. Starting with Q, libgapii will not be loaded via JDWP +// anymore, so we load it here if eglGetProcAddress can't find the symbol. +static void* getProcAddress(const char* name) { + static void* libegl = dlopen("libEGL.so", RTLD_NOW); static eglGetProcAddress pa = (eglGetProcAddress)dlsym(libegl, "eglGetProcAddress"); - return pa; + + LOG_DEBUG("Looking for function %s", name); + void* result = pa(name); + if (result == nullptr) { + result = dlsym(getLibGapii(), name); + } + return result; } -#endif VK_LAYER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL -VkGraphicsSpyGetDeviceProcAddr(VkDevice dev, const char *funcName) { +GraphicsSpyGetDeviceProcAddr(VkDevice dev, const char* funcName) { PROC(vkGetDeviceProcAddr)(dev, funcName); return nullptr; } VK_LAYER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL -VkGraphicsSpyGetInstanceProcAddr(VkInstance instance, const char *funcName) { +GraphicsSpyGetInstanceProcAddr(VkInstance instance, const char* funcName) { PROC(vkGetInstanceProcAddr)(instance, funcName); return nullptr; } -VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL -vkEnumerateInstanceLayerProperties(uint32_t *pCount, - VkLayerProperties *pProperties) { - PROC(vkEnumerateInstanceLayerProperties)(pCount, pProperties); - *pCount = 0; +// This should probably match the struct in vulkan_extras.cpp's +// SpyOverride_vkEnumerateInstanceLayerProperties. +static const VkLayerProperties global_layer_properties[] = {{ + "GraphicsSpy", + VK_VERSION_MAJOR(1) | VK_VERSION_MINOR(0) | 5, + 1, + "vulkan_trace", +}}; + +static VkResult get_layer_properties(uint32_t* pCount, + VkLayerProperties* pProperties) { + if (pProperties == NULL) { + *pCount = 1; + return VK_SUCCESS; + } + + if (pCount == 0) { + return VK_INCOMPLETE; + } + *pCount = 1; + memcpy(pProperties, global_layer_properties, sizeof(global_layer_properties)); return VK_SUCCESS; } +VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL +vkEnumerateInstanceLayerProperties(uint32_t* pCount, + VkLayerProperties* pProperties) { + return get_layer_properties(pCount, pProperties); +} + // On Android this must also be defined, even if we have 0 // layers to expose. VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL -vkEnumerateInstanceExtensionProperties(const char *pLayerName, uint32_t *pCount, - VkExtensionProperties *pProperties) { - PROC(vkEnumerateInstanceExtensionProperties)(pLayerName, pCount, pProperties); +vkEnumerateInstanceExtensionProperties(const char* pLayerName, uint32_t* pCount, + VkExtensionProperties* pProperties) { *pCount = 0; return VK_SUCCESS; } VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateDeviceLayerProperties( - VkPhysicalDevice device, uint32_t *pCount, VkLayerProperties *pProperties) { - PROC(vkEnumerateDeviceLayerProperties)(device, pCount, pProperties); - *pCount = 0; - return VK_SUCCESS; + VkPhysicalDevice device, uint32_t* pCount, VkLayerProperties* pProperties) { + return get_layer_properties(pCount, pProperties); } // On android this must also be defined, even if we have 0 // layers to expose. VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateDeviceExtensionProperties(VkPhysicalDevice device, - const char *pLayerName, uint32_t *pCount, - VkExtensionProperties *pProperties) { - PROC(vkEnumerateDeviceExtensionProperties) - (device, pLayerName, pCount, pProperties); + const char* pLayerName, uint32_t* pCount, + VkExtensionProperties* pProperties) { *pCount = 0; return VK_SUCCESS; } + +static void* getLibGapii() { + static void* libgapii = nullptr; + if (libgapii == nullptr) { + Dl_info me; + dladdr((void*)GraphicsSpyGetDeviceProcAddr, &me); + if (me.dli_fname != nullptr) { + const char* base = strrchr(me.dli_fname, '/'); + if (base != nullptr) { + int baseLen = base - me.dli_fname + 1; + char* name = static_cast(alloca(baseLen + 12 /*"libgapii.so"*/)); + memcpy(name, me.dli_fname, baseLen); + strncpy(name + baseLen, "libgapii.so", 12); + LOG_DEBUG("Loading gapii at %s", name); + libgapii = dlopen(name, RTLD_NOW); + } + } + } + return libgapii; +} + } // extern "C" diff --git a/gapis/api/templates/vulkan_gfx_api_extras.tmpl b/gapis/api/templates/vulkan_gfx_api_extras.tmpl index 3f16709d56..b836930ad2 100644 --- a/gapis/api/templates/vulkan_gfx_api_extras.tmpl +++ b/gapis/api/templates/vulkan_gfx_api_extras.tmpl @@ -54,7 +54,7 @@ namespace {« ¶ const char kVirtualSwapchainLayerName[] = "VirtualSwapchain"; - const char kVkGraphicsSpyLayerName[] = "VkGraphicsSpy"; + const char kGraphicsSpyLayerName[] = "GraphicsSpy"; const char kValidationMetaLayerName[] = "VK_LAYER_LUNARG_standard_validation"; const char* kValidationLayerNames[] = { "VK_LAYER_GOOGLE_threading", @@ -105,12 +105,12 @@ bool Vulkan::replayCreateVkInstanceImpl(Stack* stack, pCreateInfo->ppEnabledExtensionNames + pCreateInfo->enabledExtensionCount); extensions.reserve(pCreateInfo->enabledExtensionCount + 1); - // Drop the VkGraphicsSpy layer and validation layers if requested. + // Drop the GraphicsSpy layer and validation layers if requested. layers.erase( std::remove_if( layers.begin(), layers.end(), [dropValidationLayersAndDebugReport](const char* layer) -> bool { - if (strcmp(kVkGraphicsSpyLayerName, layer) == 0) { + if (strcmp(kGraphicsSpyLayerName, layer) == 0) { return true; } if (dropValidationLayersAndDebugReport) {