Turn on vk unit tests
* Degrade error when changing the rendering backend from Properties to
no longer be fatal.
* Support using a single graphics queue for the Vulkan backend. Cloud
devices only support a single queue and some Vulkan implementations such
as Swiftshader expose only one queue for simplying their implementation,
so we'll need to support one.
Bug: 175618060
Bug: 162628999
Test: hwui_unit_tests
Test: experiment on Pixel 4 enforcing a single queue (settings app,
maps, sysui)
Change-Id: I495fcabc3c89bd62bbb833998eab4944c6660f6f
diff --git a/libs/hwui/Properties.cpp b/libs/hwui/Properties.cpp
index ba44d05..65f4e8c 100644
--- a/libs/hwui/Properties.cpp
+++ b/libs/hwui/Properties.cpp
@@ -15,7 +15,9 @@
*/
#include "Properties.h"
+
#include "Debug.h"
+#include "log/log_main.h"
#ifdef __ANDROID__
#include "HWUIProperties.sysprop.h"
#endif
@@ -190,15 +192,12 @@
return sRenderPipelineType;
}
-void Properties::overrideRenderPipelineType(RenderPipelineType type) {
+void Properties::overrideRenderPipelineType(RenderPipelineType type, bool inUnitTest) {
// If we're doing actual rendering then we can't change the renderer after it's been set.
- // Unit tests can freely change this as often as it wants, though, as there's no actual
- // GL rendering happening
- if (sRenderPipelineType != RenderPipelineType::NotInitialized) {
- LOG_ALWAYS_FATAL_IF(sRenderPipelineType != type,
- "Trying to change pipeline but it's already set");
- return;
- }
+ // Unit tests can freely change this as often as it wants.
+ LOG_ALWAYS_FATAL_IF(sRenderPipelineType != RenderPipelineType::NotInitialized &&
+ sRenderPipelineType != type && !inUnitTest,
+ "Trying to change pipeline but it's already set.");
sRenderPipelineType = type;
}
diff --git a/libs/hwui/Properties.h b/libs/hwui/Properties.h
index 85a0f4a..1639143 100644
--- a/libs/hwui/Properties.h
+++ b/libs/hwui/Properties.h
@@ -238,7 +238,7 @@
static bool enableRTAnimations;
// Used for testing only to change the render pipeline.
- static void overrideRenderPipelineType(RenderPipelineType);
+ static void overrideRenderPipelineType(RenderPipelineType, bool inUnitTest = false);
static bool runningInEmulator;
diff --git a/libs/hwui/renderthread/VulkanManager.cpp b/libs/hwui/renderthread/VulkanManager.cpp
index 1333b92..3e7ce36 100644
--- a/libs/hwui/renderthread/VulkanManager.cpp
+++ b/libs/hwui/renderthread/VulkanManager.cpp
@@ -27,6 +27,8 @@
#include <vk/GrVkExtensions.h>
#include <vk/GrVkTypes.h>
+#include <cstring>
+
#include "Properties.h"
#include "RenderThread.h"
#include "renderstate/RenderState.h"
@@ -53,6 +55,19 @@
}
}
+GrVkGetProc VulkanManager::sSkiaGetProp = [](const char* proc_name, VkInstance instance,
+ VkDevice device) {
+ if (device != VK_NULL_HANDLE) {
+ if (strcmp("vkQueueSubmit", proc_name) == 0) {
+ return (PFN_vkVoidFunction)VulkanManager::interceptedVkQueueSubmit;
+ } else if (strcmp("vkQueueWaitIdle", proc_name) == 0) {
+ return (PFN_vkVoidFunction)VulkanManager::interceptedVkQueueWaitIdle;
+ }
+ return vkGetDeviceProcAddr(device, proc_name);
+ }
+ return vkGetInstanceProcAddr(instance, proc_name);
+};
+
#define GET_PROC(F) m##F = (PFN_vk##F)vkGetInstanceProcAddr(VK_NULL_HANDLE, "vk" #F)
#define GET_INST_PROC(F) m##F = (PFN_vk##F)vkGetInstanceProcAddr(mInstance, "vk" #F)
#define GET_DEV_PROC(F) m##F = (PFN_vk##F)vkGetDeviceProcAddr(mDevice, "vk" #F)
@@ -83,7 +98,6 @@
}
mGraphicsQueue = VK_NULL_HANDLE;
- mAHBUploadQueue = VK_NULL_HANDLE;
mDevice = VK_NULL_HANDLE;
mPhysicalDevice = VK_NULL_HANDLE;
mInstance = VK_NULL_HANDLE;
@@ -185,7 +199,6 @@
for (uint32_t i = 0; i < queueCount; i++) {
if (queueProps[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) {
mGraphicsQueueIndex = i;
- LOG_ALWAYS_FATAL_IF(queueProps[i].queueCount < 2);
break;
}
}
@@ -210,14 +223,7 @@
LOG_ALWAYS_FATAL_IF(!hasKHRSwapchainExtension);
}
- auto getProc = [](const char* proc_name, VkInstance instance, VkDevice device) {
- if (device != VK_NULL_HANDLE) {
- return vkGetDeviceProcAddr(device, proc_name);
- }
- return vkGetInstanceProcAddr(instance, proc_name);
- };
-
- grExtensions.init(getProc, mInstance, mPhysicalDevice, mInstanceExtensions.size(),
+ grExtensions.init(sSkiaGetProp, mInstance, mPhysicalDevice, mInstanceExtensions.size(),
mInstanceExtensions.data(), mDeviceExtensions.size(),
mDeviceExtensions.data());
@@ -289,7 +295,7 @@
queueNextPtr, // pNext
0, // VkDeviceQueueCreateFlags
mGraphicsQueueIndex, // queueFamilyIndex
- 2, // queueCount
+ 1, // queueCount
queuePriorities, // pQueuePriorities
};
@@ -344,7 +350,6 @@
this->setupDevice(mExtensions, mPhysicalDeviceFeatures2);
mGetDeviceQueue(mDevice, mGraphicsQueueIndex, 0, &mGraphicsQueue);
- mGetDeviceQueue(mDevice, mGraphicsQueueIndex, 1, &mAHBUploadQueue);
if (Properties::enablePartialUpdates && Properties::useBufferAge) {
mSwapBehavior = SwapBehavior::BufferAge;
@@ -353,24 +358,17 @@
sk_sp<GrDirectContext> VulkanManager::createContext(const GrContextOptions& options,
ContextType contextType) {
- auto getProc = [](const char* proc_name, VkInstance instance, VkDevice device) {
- if (device != VK_NULL_HANDLE) {
- return vkGetDeviceProcAddr(device, proc_name);
- }
- return vkGetInstanceProcAddr(instance, proc_name);
- };
GrVkBackendContext backendContext;
backendContext.fInstance = mInstance;
backendContext.fPhysicalDevice = mPhysicalDevice;
backendContext.fDevice = mDevice;
- backendContext.fQueue = (contextType == ContextType::kRenderThread) ? mGraphicsQueue
- : mAHBUploadQueue;
+ backendContext.fQueue = mGraphicsQueue;
backendContext.fGraphicsQueueIndex = mGraphicsQueueIndex;
backendContext.fMaxAPIVersion = mAPIVersion;
backendContext.fVkExtensions = &mExtensions;
backendContext.fDeviceFeatures2 = &mPhysicalDeviceFeatures2;
- backendContext.fGetProc = std::move(getProc);
+ backendContext.fGetProc = sSkiaGetProp;
return GrDirectContext::MakeVulkan(backendContext, options);
}
@@ -530,6 +528,8 @@
ALOGE_IF(VK_SUCCESS != err, "VulkanManager::swapBuffers(): Failed to get semaphore Fd");
} else {
ALOGE("VulkanManager::swapBuffers(): Semaphore submission failed");
+
+ std::lock_guard<std::mutex> lock(mGraphicsQueueMutex);
mQueueWaitIdle(mGraphicsQueue);
}
destroy_semaphore(destroyInfo);
@@ -540,6 +540,7 @@
void VulkanManager::destroySurface(VulkanSurface* surface) {
// Make sure all submit commands have finished before starting to destroy objects.
if (VK_NULL_HANDLE != mGraphicsQueue) {
+ std::lock_guard<std::mutex> lock(mGraphicsQueueMutex);
mQueueWaitIdle(mGraphicsQueue);
}
mDeviceWaitIdle(mDevice);
diff --git a/libs/hwui/renderthread/VulkanManager.h b/libs/hwui/renderthread/VulkanManager.h
index 7a77466..121afc9 100644
--- a/libs/hwui/renderthread/VulkanManager.h
+++ b/libs/hwui/renderthread/VulkanManager.h
@@ -17,6 +17,10 @@
#ifndef VULKANMANAGER_H
#define VULKANMANAGER_H
+#include <functional>
+#include <mutex>
+
+#include "vulkan/vulkan_core.h"
#if !defined(VK_USE_PLATFORM_ANDROID_KHR)
#define VK_USE_PLATFORM_ANDROID_KHR
#endif
@@ -161,8 +165,25 @@
VkDevice mDevice = VK_NULL_HANDLE;
uint32_t mGraphicsQueueIndex;
+
+ std::mutex mGraphicsQueueMutex;
VkQueue mGraphicsQueue = VK_NULL_HANDLE;
- VkQueue mAHBUploadQueue = VK_NULL_HANDLE;
+
+ static VKAPI_ATTR VkResult interceptedVkQueueSubmit(VkQueue queue, uint32_t submitCount,
+ const VkSubmitInfo* pSubmits,
+ VkFence fence) {
+ sp<VulkanManager> manager = VulkanManager::getInstance();
+ std::lock_guard<std::mutex> lock(manager->mGraphicsQueueMutex);
+ return manager->mQueueSubmit(queue, submitCount, pSubmits, fence);
+ }
+
+ static VKAPI_ATTR VkResult interceptedVkQueueWaitIdle(VkQueue queue) {
+ sp<VulkanManager> manager = VulkanManager::getInstance();
+ std::lock_guard<std::mutex> lock(manager->mGraphicsQueueMutex);
+ return manager->mQueueWaitIdle(queue);
+ }
+
+ static GrVkGetProc sSkiaGetProp;
// Variables saved to populate VkFunctorInitParams.
static const uint32_t mAPIVersion = VK_MAKE_VERSION(1, 1, 0);
diff --git a/libs/hwui/tests/common/TestUtils.h b/libs/hwui/tests/common/TestUtils.h
index c1d8b76..771c345 100644
--- a/libs/hwui/tests/common/TestUtils.h
+++ b/libs/hwui/tests/common/TestUtils.h
@@ -50,12 +50,12 @@
ADD_FAILURE() << "ClipState not a rect"; \
}
-#define INNER_PIPELINE_TEST(test_case_name, test_name, pipeline, functionCall) \
- TEST(test_case_name, test_name##_##pipeline) { \
- RenderPipelineType oldType = Properties::getRenderPipelineType(); \
- Properties::overrideRenderPipelineType(RenderPipelineType::pipeline); \
- functionCall; \
- Properties::overrideRenderPipelineType(oldType); \
+#define INNER_PIPELINE_TEST(test_case_name, test_name, pipeline, functionCall) \
+ TEST(test_case_name, test_name##_##pipeline) { \
+ RenderPipelineType oldType = Properties::getRenderPipelineType(); \
+ Properties::overrideRenderPipelineType(RenderPipelineType::pipeline, true); \
+ functionCall; \
+ Properties::overrideRenderPipelineType(oldType, true); \
};
#define INNER_PIPELINE_RENDERTHREAD_TEST(test_case_name, test_name, pipeline) \
@@ -67,29 +67,27 @@
* Like gtest's TEST, but runs on the RenderThread, and 'renderThread' is passed, in top level scope
* (for e.g. accessing its RenderState)
*/
-#define RENDERTHREAD_TEST(test_case_name, test_name) \
- class test_case_name##_##test_name##_RenderThreadTest { \
- public: \
- static void doTheThing(renderthread::RenderThread& renderThread); \
- }; \
- INNER_PIPELINE_RENDERTHREAD_TEST(test_case_name, test_name, SkiaGL); \
- /* Temporarily disabling Vulkan until we can figure out a way to stub out the driver */ \
- /* INNER_PIPELINE_RENDERTHREAD_TEST(test_case_name, test_name, SkiaVulkan); */ \
- void test_case_name##_##test_name##_RenderThreadTest::doTheThing( \
+#define RENDERTHREAD_TEST(test_case_name, test_name) \
+ class test_case_name##_##test_name##_RenderThreadTest { \
+ public: \
+ static void doTheThing(renderthread::RenderThread& renderThread); \
+ }; \
+ INNER_PIPELINE_RENDERTHREAD_TEST(test_case_name, test_name, SkiaGL); \
+ INNER_PIPELINE_RENDERTHREAD_TEST(test_case_name, test_name, SkiaVulkan); \
+ void test_case_name##_##test_name##_RenderThreadTest::doTheThing( \
renderthread::RenderThread& renderThread)
/**
* Like RENDERTHREAD_TEST, but only runs with the Skia RenderPipelineTypes
*/
-#define RENDERTHREAD_SKIA_PIPELINE_TEST(test_case_name, test_name) \
- class test_case_name##_##test_name##_RenderThreadTest { \
- public: \
- static void doTheThing(renderthread::RenderThread& renderThread); \
- }; \
- INNER_PIPELINE_RENDERTHREAD_TEST(test_case_name, test_name, SkiaGL); \
- /* Temporarily disabling Vulkan until we can figure out a way to stub out the driver */ \
- /* INNER_PIPELINE_RENDERTHREAD_TEST(test_case_name, test_name, SkiaVulkan); */ \
- void test_case_name##_##test_name##_RenderThreadTest::doTheThing( \
+#define RENDERTHREAD_SKIA_PIPELINE_TEST(test_case_name, test_name) \
+ class test_case_name##_##test_name##_RenderThreadTest { \
+ public: \
+ static void doTheThing(renderthread::RenderThread& renderThread); \
+ }; \
+ INNER_PIPELINE_RENDERTHREAD_TEST(test_case_name, test_name, SkiaGL); \
+ INNER_PIPELINE_RENDERTHREAD_TEST(test_case_name, test_name, SkiaVulkan); \
+ void test_case_name##_##test_name##_RenderThreadTest::doTheThing( \
renderthread::RenderThread& renderThread)
/**