diff --git a/examples/android/android-simple/.gitignore b/examples/android/android-simple/.gitignore index 60b71a8b5..f23ff3a66 100644 --- a/examples/android/android-simple/.gitignore +++ b/examples/android/android-simple/.gitignore @@ -9,4 +9,3 @@ local.properties .cxx .cdep cdep.sha256 - diff --git a/examples/android/android-simple/README.md b/examples/android/android-simple/README.md index b58262930..1f5d12d07 100644 --- a/examples/android/android-simple/README.md +++ b/examples/android/android-simple/README.md @@ -1,5 +1,14 @@ -Vulkan Kompute Android Example +Tutorial 02 - use validation layers - 1 =========== -Loading Vulkan to Andriod Application using Vulkan Kompute. +1. Add validation layers into gradle and pack them into apk +1. Enable all validation layers/extensions found on the system +1. Use vulkan wrappers in common/vulkan_wrapper directory + +Verification +============ +Planted error: this sample sets `VkDeviceQueueCreateInfo::pQueuePriorities` to nullptr, +which will trigger validation layers to notify us from registered callback function +`vkDebugReportCallbackEX_impl();` putting a breakpoint with Android Studo, observe +the breakpoint being triggered. diff --git a/examples/android/android-simple/app/build.gradle b/examples/android/android-simple/app/build.gradle index ea5436e88..82cd7a09e 100644 --- a/examples/android/android-simple/app/build.gradle +++ b/examples/android/android-simple/app/build.gradle @@ -1,18 +1,23 @@ apply plugin: 'com.android.application' +Properties properties = new Properties() +properties.load(project.rootProject.file('local.properties').newDataInputStream()) +def ndkDir = properties.getProperty('ndk.dir') +def valLayerBinDir = "${ndkDir}/sources/third_party/vulkan/src/build-android/jniLibs" + android { compileSdkVersion 24 defaultConfig { - applicationId "com.kompute.examples.android" + applicationId "com.ethicalml.kompute.examples.android" minSdkVersion 24 targetSdkVersion 24 - versionCode 1 - versionName "0.0.1" + versionCode = 1 + versionName = "0.0.1" externalNativeBuild { cmake { abiFilters "armeabi-v7a", 'arm64-v8a', 'x86', 'x86_64' - arguments '-DANDROID_TOOLCHAIN=clang', '-DANDROID_STL=c++_static' + arguments '-DANDROID_TOOLCHAIN=clang', '-DANDROID_STL=c++_static', '-DKOMPUTE_OPT_ANDOID_BUILD=1', '-DKOMPUTE_OPT_INSTALL=0' } } } @@ -21,13 +26,22 @@ android { path 'src/main/jni/CMakeLists.txt' } } - buildTypes { - release { - minifyEnabled = false - proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + + sourceSets { + main { + jniLibs { + // Must have ndk-r12 or better which including layer binaries + srcDirs = ["${valLayerBinDir}"] + } } } - ndkVersion '21.3.6528147' + + buildTypes { + release { + minifyEnabled = false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } } dependencies { diff --git a/examples/android/android-simple/app/proguard-rules.pro b/examples/android/android-simple/app/proguard-rules.pro index c8505fb8e..b41fe70c7 100644 --- a/examples/android/android-simple/app/proguard-rules.pro +++ b/examples/android/android-simple/app/proguard-rules.pro @@ -1,6 +1,6 @@ # Add project specific ProGuard rules here. # By default, the flags in this file are appended to flags specified -# in {ANDROID_SDK}/tools/proguard/proguard-android.txt +# in ${ANDROID_SDK}/tools/proguard/proguard-android.txt # You can edit the include path and order by changing the proguardFiles # directive in build.gradle. # diff --git a/examples/android/android-simple/app/src/main/AndroidManifest.xml b/examples/android/android-simple/app/src/main/AndroidManifest.xml index 3f36ad490..c15080377 100755 --- a/examples/android/android-simple/app/src/main/AndroidManifest.xml +++ b/examples/android/android-simple/app/src/main/AndroidManifest.xml @@ -1,7 +1,7 @@ @@ -15,7 +15,7 @@ android:configChanges="orientation|keyboardHidden"> + android:value="kompute_android" /> diff --git a/examples/android/android-simple/app/src/main/jni/CMakeLists.txt b/examples/android/android-simple/app/src/main/jni/CMakeLists.txt index 0ecb4e451..7d9e7b19a 100644 --- a/examples/android/android-simple/app/src/main/jni/CMakeLists.txt +++ b/examples/android/android-simple/app/src/main/jni/CMakeLists.txt @@ -1,16 +1,38 @@ cmake_minimum_required(VERSION 3.4.1) +add_subdirectory(../../../../../../../ ${CMAKE_CURRENT_BINARY_DIR}/kompute_build) + +set(ANDROID_APP_GLUE_DIR ${ANDROID_NDK}/sources/android/native_app_glue) +set(VK_ANDROID_COMMON_DIR ${ANDROID_NDK}/sources/third_party/vulkan/src/common) +set(VK_ANDROID_INCLUDE_DIR ${ANDROID_NDK}/sources/third_party/vulkan/src/include) + # build native_app_glue as a static lib -set(APP_GLUE_DIR ${ANDROID_NDK}/sources/android/native_app_glue) -include_directories(${APP_GLUE_DIR}) -add_library( app-glue STATIC ${APP_GLUE_DIR}/android_native_app_glue.c) +include_directories(${ANDROID_APP_GLUE_DIR}) +add_library(app-glue STATIC + ${ANDROID_APP_GLUE_DIR}/android_native_app_glue.c) -add_library(vktuts SHARED +# build vulkan app +add_library(kompute_android SHARED + TutorialValLayer.cpp main.cpp - vulkan_wrapper.cpp) + ${VK_ANDROID_COMMON_DIR}/vulkan_wrapper.cpp) -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror -std=c++11 \ - -DVK_USE_PLATFORM_ANDROID_KHR") -set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -u ANativeActivity_onCreate") +include_directories( + ${VK_ANDROID_COMMON_DIR} + ${VK_ANDROID_INCLUDE_DIR}) -target_link_libraries(vktuts app-glue log android) \ No newline at end of file +# TODO: Explore: +# * -DVK_NO_PROTOTYPES +# * -DUSE_DEBUG_EXTENTIONS +# * -Wno-unused-variable +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14 -Werror \ + -DVK_USE_PLATFORM_ANDROID_KHR -DVK_NO_PROTOTYPES") + +set(CMAKE_SHARED_LINKER_FLAGS + "${CMAKE_SHARED_LINKER_FLAGS} -u ANativeActivity_onCreate") + +target_link_libraries(kompute_android + kompute + app-glue + log + android) \ No newline at end of file diff --git a/examples/android/android-simple/app/src/main/jni/TutorialValLayer.cpp b/examples/android/android-simple/app/src/main/jni/TutorialValLayer.cpp new file mode 100644 index 000000000..35902b0fc --- /dev/null +++ b/examples/android/android-simple/app/src/main/jni/TutorialValLayer.cpp @@ -0,0 +1,361 @@ +// Copyright 2016 Google Inc. All Rights Reserved. +// +// 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. +#include "TutorialValLayer.hpp" +#include +#include + +// Android log function wrappers +static const char* kTAG = "Vulkan-Tutorial02"; +#define LOGI(...) \ + ((void)__android_log_print(ANDROID_LOG_INFO, kTAG, __VA_ARGS__)) +#define LOGW(...) \ + ((void)__android_log_print(ANDROID_LOG_WARN, kTAG, __VA_ARGS__)) +#define LOGE(...) \ + ((void)__android_log_print(ANDROID_LOG_ERROR, kTAG, __VA_ARGS__)) + +// Vulkan call wrapper +#define CALL_VK(func) \ + if (VK_SUCCESS != (func)) { \ + __android_log_print(ANDROID_LOG_ERROR, "Tutorial ", \ + "Vulkan error. File[%s], line[%d]", __FILE__, \ + __LINE__); \ + assert(false); \ + } + +/* + * Validation Layer names at this time (info purpose) + static const char* kValLayerNames[] = { + "VK_LAYER_GOOGLE_threading", + "VK_LAYER_LUNARG_device_limits", + "VK_LAYER_LUNARG_core_validation", + "VK_LAYER_LUNARG_image", + "VK_LAYER_LUNARG_object_tracker", + "VK_LAYER_LUNARG_parameter_validation", + "VK_LAYER_LUNARG_swapchain", + "VK_LAYER_GOOGLE_unique_objects", + }; +*/ +static const char* kUniqueObjectLayer = "VK_LAYER_GOOGLE_unique_objects"; +static const char* kGoogleThreadingLayer = "VK_LAYER_GOOGLE_threading"; + +// Debug Extension names in use. +// assumed usage: +// 1) app calls GetDbgExtName() +// 2) app calls IsExtSupported() to make sure it is supported +// 3) app tucks dbg extension name into InstanceCreateInfo to create instance +// 4) app calls CreateDbgExtCallback() to hook up debug print message +static const char* kDbgExtName = "VK_EXT_debug_report"; + +// Simple Dbg Callback function to be used by Vk engine +static VkBool32 VKAPI_PTR vkDebugReportCallbackEX_impl( + VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT objectType, + uint64_t object, size_t location, int32_t messageCode, + const char* pLayerPrefix, const char* pMessage, void* pUserData) { + if (flags & VK_DEBUG_REPORT_INFORMATION_BIT_EXT) { + __android_log_print(ANDROID_LOG_INFO, "Vulkan-Debug-Message: ", "%s -- %s", + pLayerPrefix, pMessage); + } + if (flags & VK_DEBUG_REPORT_WARNING_BIT_EXT) { + __android_log_print(ANDROID_LOG_WARN, "Vulkan-Debug-Message: ", "%s -- %s", + pLayerPrefix, pMessage); + } + if (flags & VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT) { + __android_log_print(ANDROID_LOG_WARN, "Vulkan-Debug-Message-(Perf): ", + "%s -- %s", pLayerPrefix, pMessage); + } + if (flags & VK_DEBUG_REPORT_ERROR_BIT_EXT) { + __android_log_print(ANDROID_LOG_ERROR, "Vulkan-Debug-Message: ", "%s -- %s", + pLayerPrefix, pMessage); + } + if (flags & VK_DEBUG_REPORT_DEBUG_BIT_EXT) { + __android_log_print(ANDROID_LOG_DEBUG, "Vulkan-Debug-Message: ", "%s -- %s", + pLayerPrefix, pMessage); + } + + return VK_FALSE; +} +// Reinforce the layer name sequence to meet load sequence +// requirement if there is any +void LayerAndExtensions::CheckLayerLoadingSequence( + std::vector* layerPtr) { + // VK_LAYER_GOOGLE_unique_objects need to be after + // VK_LAYER_LUNARG_core_validation + // VK_GOOGLE_THREADING_LAYER better to be the very first one + std::vector& layers = *layerPtr; + uint32_t uniqueObjIdx = -1; + uint32_t threadingIdx = -1; + uint32_t size = layers.size(); + for (uint32_t idx = 0; idx < size; ++idx) { + if (!strcmp(layers[idx], kUniqueObjectLayer)) uniqueObjIdx = idx; + if (!strcmp(layers[idx], kGoogleThreadingLayer)) threadingIdx = idx; + } + if (uniqueObjIdx != -1) { + char* tmp = layers[uniqueObjIdx]; + layers[uniqueObjIdx] = layers[size - 1]; + layers[size - 1] = tmp; + } + + if (threadingIdx != -1) { + char* tmp = layers[threadingIdx]; + layers[threadingIdx] = layers[0]; + layers[0] = tmp; + } +} + +bool LayerAndExtensions::InitExtNames(const std::vector& prop, + std::vector* names) { + names->clear(); + for (auto& ext : prop) { + for (uint32_t i = 0; i < ext.count; ++i) { + // skip the one already inside + bool duplicate = false; + for (uint32_t j = 0; j < names->size(); ++j) { + if (!strcmp(ext.prop[i].extensionName, (*names)[j])) { + duplicate = true; + break; + } + } + if (duplicate) continue; + // save this unique one + names->push_back(ext.prop[i].extensionName); + LOGI("Ext name: %s", ext.prop[i].extensionName); + } + } + return true; +} + +bool LayerAndExtensions::InitInstExts(void) { + ExtInfo extInfo{0, nullptr}; + CALL_VK( + vkEnumerateInstanceExtensionProperties(nullptr, &extInfo.count, nullptr)); + if (extInfo.count) { + extInfo.prop = new VkExtensionProperties[extInfo.count]; + assert(extInfo.prop); + CALL_VK(vkEnumerateInstanceExtensionProperties(nullptr, &extInfo.count, + extInfo.prop)); + instExtProp_.push_back(extInfo); + } + + for (int i = 0; i < instLayerCount_; i++) { + extInfo.count = 0; + CALL_VK(vkEnumerateInstanceExtensionProperties(instLayerProp_[i].layerName, + &extInfo.count, nullptr)); + if (extInfo.count == 0) continue; + extInfo.prop = new VkExtensionProperties[extInfo.count]; + CALL_VK(vkEnumerateInstanceExtensionProperties( + instLayerProp_[i].layerName, &extInfo.count, extInfo.prop)); + instExtProp_.push_back(extInfo); + } + return InitExtNames(instExtProp_, &instExts_); +} + +char** LayerAndExtensions::InstLayerNames(void) { + if (instLayers_.size()) { + return static_cast(instLayers_.data()); + } + return nullptr; +} +uint32_t LayerAndExtensions::InstLayerCount(void) { + LOGI("InstLayerCount = %d", static_cast(instLayers_.size())); + return static_cast(instLayers_.size()); +} +char** LayerAndExtensions::InstExtNames(void) { + if (instExts_.size()) { + return static_cast(instExts_.data()); + } + return nullptr; +} +uint32_t LayerAndExtensions::InstExtCount(void) { + LOGI("InstExtCount: %d", static_cast(instExts_.size())); + return static_cast(instExts_.size()); +} + +bool LayerAndExtensions::IsInstExtSupported(const char* extName) { + for (auto name : instExts_) { + if (!strcmp(name, extName)) { + return true; + } + } + return false; +} + +bool LayerAndExtensions::AddInstanceExt(const char* extName) { + if (!extName) return false; + + // enable all available extensions, plus the one asked + if (!IsInstExtSupported(extName)) { +#ifdef ENABLE_NON_ENUMERATED_EXT + instExts.push_back(static_cast(extName)); + instExtCount++; + return true; +#else + return false; +#endif + } + return true; +} +bool LayerAndExtensions::IsInstLayerSupported(const char* layerName) { + InstLayerNames(); + for (auto name : instLayers_) { + if (!strcmp(name, layerName)) return true; + } + return false; +} + +LayerAndExtensions::LayerAndExtensions(void) { + instance_ = VK_NULL_HANDLE; + vkCallbackHandle_ = VK_NULL_HANDLE; + CALL_VK(vkEnumerateInstanceLayerProperties(&instLayerCount_, nullptr)); + if (instLayerCount_) { + instLayerProp_ = new VkLayerProperties[instLayerCount_]; + assert(instLayerProp_); + CALL_VK( + vkEnumerateInstanceLayerProperties(&instLayerCount_, instLayerProp_)); + } + for (uint32_t i = 0; i < instLayerCount_; i++) { + instLayers_.push_back(instLayerProp_[i].layerName); + LOGI("InstLayer name: %s", instLayerProp_[i].layerName); + } + CheckLayerLoadingSequence(&instLayers_); + + InitInstExts(); +} + +LayerAndExtensions::~LayerAndExtensions() { + if (instLayerProp_) { + delete[] instLayerProp_; + } + for (auto ext : instExtProp_) { + delete[] ext.prop; + } + if (vkCallbackHandle_) { + vkDestroyDebugReportCallbackEXT(instance_, vkCallbackHandle_, nullptr); + } +} + +void LayerAndExtensions::InitDevLayersAndExt(VkPhysicalDevice physicalDevice) { + physicalDev_ = physicalDevice; + if (physicalDev_ == VK_NULL_HANDLE) return; + + // get all supported layers props + devLayerCount_ = 0; + CALL_VK( + vkEnumerateDeviceLayerProperties(physicalDev_, &devLayerCount_, nullptr)); + if (devLayerCount_) { + devLayerProp_ = new VkLayerProperties[devLayerCount_]; + assert(devLayerProp_); + CALL_VK(vkEnumerateDeviceLayerProperties(physicalDev_, &devLayerCount_, + devLayerProp_)); + } + +#ifdef LOADER_DEVICE_LAYER_REPORT_BUG_WA + // validation layer for device only report out for one layer, + // but it seems we could ask for all layers that asked for instance + // so we just add them all in brutally + // assume all device layers are also implemented for device layers + if (devLayerCount_ == 1) { + LOGI("Only Reported One layer for device"); + if (devLayerProp_) delete[] devLayerProp_; + devLayerProp_ = + (instLayerCount_ ? (new VkLayerProperties[instLayerCount_]) : nullptr); + memcpy(devLayerProp_, instLayerProp_, + instLayerCount_ * sizeof(VkLayerProperties)); + devLayerCount_ = instLayerCount_; + } +#endif + + for (int i = 0; i < devLayerCount_; i++) { + LOGI("deviceLayerName: %s", devLayerProp_[i].layerName); + devLayers_.push_back(devLayerProp_[i].layerName); + } + CheckLayerLoadingSequence(&devLayers_); + + // get all supported ext props + ExtInfo ext{0, nullptr}; + CALL_VK(vkEnumerateDeviceExtensionProperties(physicalDev_, nullptr, + &ext.count, nullptr)); + if (ext.count) { + ext.prop = new VkExtensionProperties[ext.count]; + assert(ext.prop); + CALL_VK(vkEnumerateDeviceExtensionProperties(physicalDev_, nullptr, + &ext.count, ext.prop)); + devExtProp_.push_back(ext); + } + for (int i = 0; i < devLayerCount_; i++) { + ext.count = 0; + CALL_VK(vkEnumerateDeviceExtensionProperties( + physicalDev_, devLayerProp_[i].layerName, &ext.count, nullptr)); + if (ext.count) { + ext.prop = new VkExtensionProperties[ext.count]; + assert(ext.prop); + CALL_VK(vkEnumerateDeviceExtensionProperties( + physicalDev_, devLayerProp_[i].layerName, &ext.count, ext.prop)); + devExtProp_.push_back(ext); + } + } + + InitExtNames(devExtProp_, &devExts_); +} + +char** LayerAndExtensions::DevLayerNames(void) { + assert(physicalDev_ != VK_NULL_HANDLE); + if (devLayers_.size()) return devLayers_.data(); + + return nullptr; +} +uint32_t LayerAndExtensions::DevLayerCount(void) { + assert(physicalDev_ != VK_NULL_HANDLE); + return devLayers_.size(); +} +char** LayerAndExtensions::DevExtNames(void) { + assert(physicalDev_ != VK_NULL_HANDLE); + if (devExts_.size()) return devExts_.data(); + return nullptr; +} +uint32_t LayerAndExtensions::DevExtCount(void) { + assert(physicalDev_ != VK_NULL_HANDLE); + return devExts_.size(); +} + +const char* LayerAndExtensions::GetDbgExtName(void) { return kDbgExtName; } +bool LayerAndExtensions::HookDbgReportExt(VkInstance instance) { + instance_ = instance; + if (!IsInstExtSupported(GetDbgExtName())) { + return false; + } + if (!vkCreateDebugReportCallbackEXT) { + vkCreateDebugReportCallbackEXT = + (PFN_vkCreateDebugReportCallbackEXT)vkGetInstanceProcAddr( + instance, "vkCreateDebugReportCallbackEXT"); + vkDestroyDebugReportCallbackEXT = + (PFN_vkDestroyDebugReportCallbackEXT)vkGetInstanceProcAddr( + instance, "vkDestroyDebugReportCallbackEXT"); + vkDebugReportMessageEXT = + (PFN_vkDebugReportMessageEXT)vkGetInstanceProcAddr( + instance, "vkDebugReportMessageEXT"); + } + + VkDebugReportCallbackCreateInfoEXT dbgInfo = { + .sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT, + .pNext = nullptr, + .flags = VK_DEBUG_REPORT_WARNING_BIT_EXT | + VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT | + VK_DEBUG_REPORT_ERROR_BIT_EXT, + .pfnCallback = vkDebugReportCallbackEX_impl, + .pUserData = this, // we provide the debug object as context + }; + CALL_VK(vkCreateDebugReportCallbackEXT(instance, &dbgInfo, nullptr, + &vkCallbackHandle_)); + return true; +} diff --git a/examples/android/android-simple/app/src/main/jni/TutorialValLayer.hpp b/examples/android/android-simple/app/src/main/jni/TutorialValLayer.hpp new file mode 100644 index 000000000..997ed2844 --- /dev/null +++ b/examples/android/android-simple/app/src/main/jni/TutorialValLayer.hpp @@ -0,0 +1,93 @@ +// Copyright 2016 Google Inc. All Rights Reserved. +// +// 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 __VALLAYER_HPP__ +#define __VALLAYER_HPP__ +#include +#include +#include +#include + +// Some loader only report one layer for device layers, enable this to +// workaround it: it will copy all instance layers into device layers +// and NOT enumerating device layers +//#define LOADER_DEVICE_LAYER_REPORT_BUG_WA + +// If extension is not enumerated, it should not be enabled in general; +// If you know an extension is on the device, but loader does not report it, +// it could be forced in by enabling +// the following compile flag and call AddInstanceExt(). +// #define ENABLE_NON_ENUMERATED_EXT 1 + +// A Helper class to manage validation layers and extensions +// Supposed usage: +// 1) validation layers: app should enable them with +// InstanceLayerCount() +// InstanceLayerNames() +// 2) Extension layers: app should check for supportability +// and then enable in app code ( not in this class ) +// 3) DbgExtension: once instance is created, just call +// HookDbgReportExt +class LayerAndExtensions { + public: + LayerAndExtensions(void); + ~LayerAndExtensions(); + + uint32_t InstLayerCount(void); + char** InstLayerNames(void); + uint32_t InstExtCount(void); + char** InstExtNames(void); + bool IsInstExtSupported(const char* extName); + bool IsInstLayerSupported(const char* layerName); + + const char* GetDbgExtName(void); + bool AddInstanceExt(const char* extName); + bool HookDbgReportExt(VkInstance instance); + + void InitDevLayersAndExt(VkPhysicalDevice physicalDevice); + char** DevLayerNames(void); + uint32_t DevLayerCount(void); + char** DevExtNames(void); + uint32_t DevExtCount(void); + + private: + // internal helper data structure + struct ExtInfo { + uint32_t count; + VkExtensionProperties* prop; + }; + + VkInstance instance_; + VkDebugReportCallbackEXT vkCallbackHandle_; + VkPhysicalDevice physicalDev_; + + std::vector instLayers_; + std::vector instExts_; + std::vector devLayers_; + std::vector devExts_; + + VkLayerProperties* instLayerProp_{nullptr}; + uint32_t instLayerCount_{0}; + std::vector instExtProp_; + + VkLayerProperties* devLayerProp_{nullptr}; + uint32_t devLayerCount_{0}; + std::vector devExtProp_; + + bool InitInstExts(void); + bool InitExtNames(const std::vector& props, + std::vector* names); + void CheckLayerLoadingSequence(std::vector* layers); +}; + +#endif // __VALLAYER_HPP__ diff --git a/examples/android/android-simple/app/src/main/jni/main.cpp b/examples/android/android-simple/app/src/main/jni/main.cpp index 991455979..20ac5b0b2 100644 --- a/examples/android/android-simple/app/src/main/jni/main.cpp +++ b/examples/android/android-simple/app/src/main/jni/main.cpp @@ -16,10 +16,11 @@ #include #include #include +#include "TutorialValLayer.hpp" #include "vulkan_wrapper.h" // Android log function wrappers -static const char* kTAG = "Vulkan-Tutorial01"; +static const char* kTAG = "Vulkan-Tutorial02"; #define LOGI(...) \ ((void)__android_log_print(ANDROID_LOG_INFO, kTAG, __VA_ARGS__)) #define LOGW(...) \ @@ -79,36 +80,31 @@ bool initialize(android_app* app) { .apiVersion = VK_MAKE_VERSION(1, 0, 0), .applicationVersion = VK_MAKE_VERSION(1, 0, 0), .engineVersion = VK_MAKE_VERSION(1, 0, 0), - .pApplicationName = "tutorial01_load_vulkan", + .pApplicationName = "tutorial02_prebuilt_layers", .pEngineName = "tutorial", }; - // prepare necessary extensions: Vulkan on Android need these to function - std::vector instanceExt, deviceExt; - instanceExt.push_back("VK_KHR_surface"); - instanceExt.push_back("VK_KHR_android_surface"); - deviceExt.push_back("VK_KHR_swapchain"); + // prepare debug and layer objects + LayerAndExtensions layerAndExt; + layerAndExt.AddInstanceExt(layerAndExt.GetDbgExtName()); - // Create the Vulkan instance + // Create Vulkan instance, requesting all enabled layers / extensions + // available on the system VkInstanceCreateInfo instanceCreateInfo{ .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, .pNext = nullptr, .pApplicationInfo = &appInfo, - .enabledExtensionCount = static_cast(instanceExt.size()), - .ppEnabledExtensionNames = instanceExt.data(), - .enabledLayerCount = 0, - .ppEnabledLayerNames = nullptr, + .enabledExtensionCount = layerAndExt.InstExtCount(), + .ppEnabledExtensionNames = + static_cast(layerAndExt.InstExtNames()), + .enabledLayerCount = layerAndExt.InstLayerCount(), + .ppEnabledLayerNames = + static_cast(layerAndExt.InstLayerNames()), }; CALL_VK(vkCreateInstance(&instanceCreateInfo, nullptr, &tutorialInstance)); - // if we create a surface, we need the surface extension - VkAndroidSurfaceCreateInfoKHR createInfo{ - .sType = VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR, - .pNext = nullptr, - .flags = 0, - .window = app->window}; - CALL_VK(vkCreateAndroidSurfaceKHR(tutorialInstance, &createInfo, nullptr, - &tutorialSurface)); + // Create debug callback obj and connect to vulkan instance + layerAndExt.HookDbgReportExt(tutorialInstance); // Find one GPU to use: // On Android, every GPU device is equal -- supporting @@ -120,6 +116,9 @@ bool initialize(android_app* app) { CALL_VK(vkEnumeratePhysicalDevices(tutorialInstance, &gpuCount, tmpGpus)); tutorialGpu = tmpGpus[0]; // Pick up the first GPU Device + // Enumerate available device validation layers & extensions + layerAndExt.InitDevLayersAndExt(tutorialGpu); + // check for vulkan info on this GPU device VkPhysicalDeviceProperties gpuProperties; vkGetPhysicalDeviceProperties(tutorialGpu, &gpuProperties); @@ -131,6 +130,14 @@ bool initialize(android_app* app) { VK_VERSION_MINOR(gpuProperties.apiVersion), VK_VERSION_PATCH(gpuProperties.apiVersion)); + VkAndroidSurfaceCreateInfoKHR createInfo{ + .sType = VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR, + .pNext = nullptr, + .flags = 0, + .window = app->window}; + CALL_VK(vkCreateAndroidSurfaceKHR(tutorialInstance, &createInfo, nullptr, + &tutorialSurface)); + VkSurfaceCapabilitiesKHR surfaceCapabilities; vkGetPhysicalDeviceSurfaceCapabilitiesKHR(tutorialGpu, tutorialSurface, &surfaceCapabilities); @@ -178,7 +185,9 @@ bool initialize(android_app* app) { .flags = 0, .queueCount = 1, .queueFamilyIndex = queueFamilyIndex, - .pQueuePriorities = priorities, + // Send nullptr for queue priority so debug extension could + // catch the bug and call back app's debug function + .pQueuePriorities = nullptr, // priorities, }; VkDeviceCreateInfo deviceCreateInfo{ @@ -186,17 +195,19 @@ bool initialize(android_app* app) { .pNext = nullptr, .queueCreateInfoCount = 1, .pQueueCreateInfos = &queueCreateInfo, - .enabledLayerCount = 0, - .ppEnabledLayerNames = nullptr, - .enabledExtensionCount = static_cast(deviceExt.size()), - .ppEnabledExtensionNames = deviceExt.data(), + .enabledLayerCount = layerAndExt.DevLayerCount(), + .ppEnabledLayerNames = + static_cast(layerAndExt.DevLayerNames()), + .enabledExtensionCount = layerAndExt.DevExtCount(), + .ppEnabledExtensionNames = + static_cast(layerAndExt.DevExtNames()), .pEnabledFeatures = nullptr, }; CALL_VK( vkCreateDevice(tutorialGpu, &deviceCreateInfo, nullptr, &tutorialDevice)); initialized_ = true; - return 0; + return true; } void terminate(void) { diff --git a/examples/android/android-simple/app/src/main/res/values/strings.xml b/examples/android/android-simple/app/src/main/res/values/strings.xml index f4df1ad46..c899fe132 100755 --- a/examples/android/android-simple/app/src/main/res/values/strings.xml +++ b/examples/android/android-simple/app/src/main/res/values/strings.xml @@ -1,4 +1,4 @@ - Tutorial 01 + Kompute Android Example diff --git a/examples/android/android-simple/build.gradle b/examples/android/android-simple/build.gradle index 97047034f..123abac4a 100644 --- a/examples/android/android-simple/build.gradle +++ b/examples/android/android-simple/build.gradle @@ -6,7 +6,7 @@ buildscript { jcenter() } dependencies { - classpath 'com.android.tools.build:gradle:4.0.1' + classpath 'com.android.tools.build:gradle:3.5.2' // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files } diff --git a/examples/android/android-simple/gradle/wrapper/gradle-wrapper.properties b/examples/android/android-simple/gradle/wrapper/gradle-wrapper.properties old mode 100755 new mode 100644 index cf89bf4f5..14819fe99 --- a/examples/android/android-simple/gradle/wrapper/gradle-wrapper.properties +++ b/examples/android/android-simple/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Tue Sep 29 20:22:44 BST 2020 -distributionBase=GRADLE_USER_HOME -distributionPath=wrapper/dists -zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.1.1-all.zip +#Mon Jan 13 14:51:34 PST 2020 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-all.zip diff --git a/examples/android/android-simple/gradlew b/examples/android/android-simple/gradlew index cccdd3d51..9d82f7891 100755 --- a/examples/android/android-simple/gradlew +++ b/examples/android/android-simple/gradlew @@ -1,4 +1,4 @@ -#!/usr/bin/env sh +#!/usr/bin/env bash ############################################################################## ## @@ -6,6 +6,42 @@ ## ############################################################################## +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn ( ) { + echo "$*" +} + +die ( ) { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; +esac + # Attempt to set APP_HOME # Resolve links: $0 may be a link PRG="$0" @@ -24,46 +60,6 @@ cd "`dirname \"$PRG\"`/" >/dev/null APP_HOME="`pwd -P`" cd "$SAVED" >/dev/null -APP_NAME="Gradle" -APP_BASE_NAME=`basename "$0"` - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS="" - -# Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD="maximum" - -warn () { - echo "$*" -} - -die () { - echo - echo "$*" - echo - exit 1 -} - -# OS specific support (must be 'true' or 'false'). -cygwin=false -msys=false -darwin=false -nonstop=false -case "`uname`" in - CYGWIN* ) - cygwin=true - ;; - Darwin* ) - darwin=true - ;; - MINGW* ) - msys=true - ;; - NONSTOP* ) - nonstop=true - ;; -esac - CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. @@ -89,7 +85,7 @@ location of your Java installation." fi # Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then +if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then MAX_FD_LIMIT=`ulimit -H -n` if [ $? -eq 0 ] ; then if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then @@ -154,19 +150,11 @@ if $cygwin ; then esac fi -# Escape application args -save () { - for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done - echo " " +# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules +function splitJvmOpts() { + JVM_OPTS=("$@") } -APP_ARGS=$(save "$@") +eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS +JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" -# Collect all arguments for the java command, following the shell quoting and substitution rules -eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" - -# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong -if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then - cd "$(dirname "$0")" -fi - -exec "$JAVACMD" "$@" +exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" diff --git a/examples/android/android-simple/gradlew.bat b/examples/android/android-simple/gradlew.bat index e95643d6a..aec99730b 100644 --- a/examples/android/android-simple/gradlew.bat +++ b/examples/android/android-simple/gradlew.bat @@ -8,14 +8,14 @@ @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + set DIRNAME=%~dp0 if "%DIRNAME%" == "" set DIRNAME=. set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS= - @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome @@ -46,9 +46,10 @@ echo location of your Java installation. goto fail :init -@rem Get command-line arguments, handling Windows variants +@rem Get command-line arguments, handling Windowz variants if not "%OS%" == "Windows_NT" goto win9xME_args +if "%@eval[2+2]" == "4" goto 4NT_args :win9xME_args @rem Slurp the command line arguments. @@ -59,6 +60,11 @@ set _SKIP=2 if "x%~1" == "x" goto execute set CMD_LINE_ARGS=%* +goto execute + +:4NT_args +@rem Get arguments from the 4NT Shell from JP Software +set CMD_LINE_ARGS=%$ :execute @rem Setup the command line diff --git a/examples/android/android-simple/settings.gradle b/examples/android/android-simple/settings.gradle index e7b4def49..573abcb32 100644 --- a/examples/android/android-simple/settings.gradle +++ b/examples/android/android-simple/settings.gradle @@ -1 +1,2 @@ include ':app' +