1 /*
2  * Copyright 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17 
18 #define LOG_TAG "RootlessGpuDebug"
19 
20 #include <EGL/egl.h>
21 #include <GLES3/gl3.h>
22 #include <android/log.h>
23 #include <android/native_window.h>
24 #include <jni.h>
25 #include <vulkan/vulkan.h>
26 
27 #include <sstream>
28 #include <string>
29 #include <vector>
30 
31 #define ALOGI(msg, ...) \
32     __android_log_print(ANDROID_LOG_INFO, LOG_TAG, (msg), __VA_ARGS__)
33 #define ALOGE(msg, ...) \
34     __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, (msg), __VA_ARGS__)
35 #define ALOGD(msg, ...) \
36     __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, (msg), __VA_ARGS__)
37 
38 namespace {
39 
40 typedef __eglMustCastToProperFunctionPointerType EGLFuncPointer;
41 
initVulkan()42 std::string initVulkan() {
43     std::stringstream result;
44 
45     {
46       uint32_t count = 0;
47       vkEnumerateInstanceExtensionProperties(nullptr, &count, nullptr);
48       if (count > 0) {
49         std::vector<VkExtensionProperties> properties(count);
50         vkEnumerateInstanceExtensionProperties(nullptr, &count,
51                                                properties.data());
52         for (uint32_t i = 0; i < count; ++i) {
53           if (!strcmp("VK_EXT_debug_utils", properties[i].extensionName)) {
54             ALOGI("VK_EXT_debug_utils: %u", properties[i].specVersion);
55             break;
56           }
57         }
58       }
59     }
60 
61     const VkApplicationInfo app_info = {
62         VK_STRUCTURE_TYPE_APPLICATION_INFO,
63         nullptr,             // pNext
64         "RootlessGpuDebug",  // app name
65         0,                   // app version
66         nullptr,             // engine name
67         0,                   // engine version
68         VK_API_VERSION_1_0,
69     };
70     const VkInstanceCreateInfo instance_info = {
71         VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
72         nullptr,  // pNext
73         0,        // flags
74         &app_info,
75         0,        // layer count
76         nullptr,  // layers
77         0,        // extension count
78         nullptr,  // extensions
79     };
80     VkInstance instance;
81     VkResult vkResult = vkCreateInstance(&instance_info, nullptr, &instance);
82     if (vkResult == VK_SUCCESS) {
83         result << "vkCreateInstance succeeded.";
84     } else {
85         result << "vkCreateInstance failed with VkResult: " << vkResult;
86     }
87 
88     return result.str();
89 }
90 
initGLES()91 std::string initGLES() {
92     std::string result = "";
93 
94     const EGLint attribs[] = {EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
95                               EGL_BLUE_SIZE,    8,
96                               EGL_GREEN_SIZE,   8,
97                               EGL_RED_SIZE,     8,
98                               EGL_NONE};
99 
100     // Create an EGL context
101     EGLDisplay display;
102     EGLConfig config;
103     EGLint numConfigs;
104     EGLint format;
105 
106     // Check for the EGL_ANDROID_GLES_layers
107     std::string display_extensions = eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS);
108     if (display_extensions.find("EGL_ANDROID_GLES_layers") == std::string::npos)
109     {
110         result = "Did not find EGL_ANDROID_GLES_layers extension";
111         return result;
112     }
113 
114     if ((display = eglGetDisplay(EGL_DEFAULT_DISPLAY)) == EGL_NO_DISPLAY) {
115         result = "eglGetDisplay() returned error " + std::to_string(eglGetError());
116         return result;
117     }
118 
119     if (!eglInitialize(display, 0, 0)) {
120         result = "eglInitialize() returned error " + std::to_string(eglGetError());
121         return result;
122     }
123 
124     if (!eglChooseConfig(display, attribs, &config, 1, &numConfigs)) {
125         result =
126             "eglChooseConfig() returned error " + std::to_string(eglGetError());
127         return result;
128     }
129 
130     if (!eglGetConfigAttrib(display, config, EGL_NATIVE_VISUAL_ID, &format)) {
131         result =
132             "eglGetConfigAttrib() returned error " + std::to_string(eglGetError());
133         return result;
134     }
135 
136     eglTerminate(display);
137 
138     return result;
139 }
140 
android_gputools_cts_RootlessGpuDebug_nativeInitVulkan(JNIEnv * env,jclass)141 jstring android_gputools_cts_RootlessGpuDebug_nativeInitVulkan(
142         JNIEnv* env, jclass /*clazz*/) {
143     std::string result;
144 
145     result = initVulkan();
146 
147     return env->NewStringUTF(result.c_str());
148 }
149 
android_gputools_cts_RootlessGpuDebug_nativeInitGLES(JNIEnv * env,jclass)150 jstring android_gputools_cts_RootlessGpuDebug_nativeInitGLES(JNIEnv* env,
151                                                              jclass /*clazz*/) {
152     std::string result;
153 
154     result = initGLES();
155 
156     return env->NewStringUTF(result.c_str());
157 }
158 
159 static JNINativeMethod gMethods[] = {
160     {"nativeInitVulkan", "()Ljava/lang/String;",
161      (void*)android_gputools_cts_RootlessGpuDebug_nativeInitVulkan},
162     {"nativeInitGLES", "()Ljava/lang/String;",
163      (void*)android_gputools_cts_RootlessGpuDebug_nativeInitGLES}};
164 }  // anonymous namespace
165 
register_android_gputools_cts_RootlessGpuDebug(JNIEnv * env)166 int register_android_gputools_cts_RootlessGpuDebug(JNIEnv* env) {
167     jclass clazz = env->FindClass("android/rootlessgpudebug/app/RootlessGpuDebugService");
168     return env->RegisterNatives(clazz, gMethods,
169                                 sizeof(gMethods) / sizeof(JNINativeMethod));
170 }
171