Merge "Implemenet fenceWait and createReleaseFence in VulkanManager."

This commit is contained in:
Greg Daniel
2018-09-25 13:16:08 +00:00
committed by Android (Google) Code Review
2 changed files with 191 additions and 7 deletions

View File

@@ -16,6 +16,8 @@
#include "VulkanManager.h"
#include <private/gui/SyncFeatures.h>
#include "Properties.h"
#include "RenderThread.h"
#include "renderstate/RenderState.h"
@@ -41,6 +43,10 @@ VulkanManager::VulkanManager(RenderThread& thread) : mRenderThread(thread) {}
void VulkanManager::destroy() {
mRenderThread.setGrContext(nullptr);
// We don't need to explicitly free the command buffer since it automatically gets freed when we
// delete the VkCommandPool below.
mDummyCB = VK_NULL_HANDLE;
if (VK_NULL_HANDLE != mCommandPool) {
mDestroyCommandPool(mDevice, mCommandPool, nullptr);
mCommandPool = VK_NULL_HANDLE;
@@ -226,6 +232,11 @@ bool VulkanManager::setupDevice(GrVkExtensions& grExtensions, VkPhysicalDeviceFe
grExtensions.init(getProc, mInstance, mPhysicalDevice, instanceExtensions.size(),
instanceExtensions.data(), deviceExtensions.size(), deviceExtensions.data());
if (!grExtensions.hasExtension(VK_KHR_EXTERNAL_SEMAPHORE_FD_EXTENSION_NAME, 1)) {
this->destroy();
return false;
}
memset(&features, 0, sizeof(VkPhysicalDeviceFeatures2));
features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
features.pNext = nullptr;
@@ -313,6 +324,8 @@ bool VulkanManager::setupDevice(GrVkExtensions& grExtensions, VkPhysicalDeviceFe
GET_DEV_PROC(DeviceWaitIdle);
GET_DEV_PROC(CreateSemaphore);
GET_DEV_PROC(DestroySemaphore);
GET_DEV_PROC(ImportSemaphoreFdKHR);
GET_DEV_PROC(GetSemaphoreFdKHR);
GET_DEV_PROC(CreateFence);
GET_DEV_PROC(DestroyFence);
GET_DEV_PROC(WaitForFences);
@@ -384,6 +397,14 @@ void VulkanManager::initialize() {
&mCommandPool);
SkASSERT(VK_SUCCESS == res);
}
LOG_ALWAYS_FATAL_IF(mCommandPool == VK_NULL_HANDLE);
if (!setupDummyCommandBuffer()) {
this->destroy();
return;
}
LOG_ALWAYS_FATAL_IF(mDummyCB == VK_NULL_HANDLE);
mGetDeviceQueue(mDevice, mPresentQueueIndex, 0, &mPresentQueue);
@@ -976,19 +997,176 @@ int VulkanManager::getAge(VulkanSurface* surface) {
return surface->mCurrentTime - lastUsed;
}
bool VulkanManager::setupDummyCommandBuffer() {
if (mDummyCB != VK_NULL_HANDLE) {
return true;
}
VkCommandBufferAllocateInfo commandBuffersInfo;
memset(&commandBuffersInfo, 0, sizeof(VkCommandBufferAllocateInfo));
commandBuffersInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
commandBuffersInfo.pNext = nullptr;
commandBuffersInfo.commandPool = mCommandPool;
commandBuffersInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
commandBuffersInfo.commandBufferCount = 1;
VkResult err = mAllocateCommandBuffers(mDevice, &commandBuffersInfo, &mDummyCB);
if (err != VK_SUCCESS) {
// It is probably unnecessary to set this back to VK_NULL_HANDLE, but we set it anyways to
// make sure the driver didn't set a value and then return a failure.
mDummyCB = VK_NULL_HANDLE;
return false;
}
VkCommandBufferBeginInfo beginInfo;
memset(&beginInfo, 0, sizeof(VkCommandBufferBeginInfo));
beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
beginInfo.flags = VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT;
mBeginCommandBuffer(mDummyCB, &beginInfo);
mEndCommandBuffer(mDummyCB);
return true;
}
status_t VulkanManager::fenceWait(sp<Fence>& fence) {
//TODO: Insert a wait on fence command into the Vulkan command buffer.
// Block CPU on the fence.
status_t err = fence->waitForever("VulkanManager::fenceWait");
if (err != NO_ERROR) {
ALOGE("VulkanManager::fenceWait: error waiting for fence: %d", err);
return err;
if (!hasVkContext()) {
ALOGE("VulkanManager::fenceWait: VkDevice not initialized");
return INVALID_OPERATION;
}
if (SyncFeatures::getInstance().useWaitSync() &&
SyncFeatures::getInstance().useNativeFenceSync()) {
// Block GPU on the fence.
int fenceFd = fence->dup();
if (fenceFd == -1) {
ALOGE("VulkanManager::fenceWait: error dup'ing fence fd: %d", errno);
return -errno;
}
VkSemaphoreCreateInfo semaphoreInfo;
semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
semaphoreInfo.pNext = nullptr;
semaphoreInfo.flags = 0;
VkSemaphore semaphore;
VkResult err = mCreateSemaphore(mDevice, &semaphoreInfo, nullptr, &semaphore);
if (VK_SUCCESS != err) {
ALOGE("Failed to create import semaphore, err: %d", err);
return UNKNOWN_ERROR;
}
VkImportSemaphoreFdInfoKHR importInfo;
importInfo.sType = VK_STRUCTURE_TYPE_IMPORT_SEMAPHORE_FD_INFO_KHR;
importInfo.pNext = nullptr;
importInfo.semaphore = semaphore;
importInfo.flags = VK_SEMAPHORE_IMPORT_TEMPORARY_BIT;
importInfo.handleType = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT;
importInfo.fd = fenceFd;
err = mImportSemaphoreFdKHR(mDevice, &importInfo);
if (VK_SUCCESS != err) {
ALOGE("Failed to import semaphore, err: %d", err);
return UNKNOWN_ERROR;
}
LOG_ALWAYS_FATAL_IF(mDummyCB == VK_NULL_HANDLE);
VkPipelineStageFlags waitDstStageFlags = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
VkSubmitInfo submitInfo;
memset(&submitInfo, 0, sizeof(VkSubmitInfo));
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
submitInfo.waitSemaphoreCount = 1;
// Wait to make sure aquire semaphore set above has signaled.
submitInfo.pWaitSemaphores = &semaphore;
submitInfo.pWaitDstStageMask = &waitDstStageFlags;
submitInfo.commandBufferCount = 1;
submitInfo.pCommandBuffers = &mDummyCB;
submitInfo.signalSemaphoreCount = 0;
mQueueSubmit(mGraphicsQueue, 1, &submitInfo, VK_NULL_HANDLE);
// On Android when we import a semaphore, it is imported using temporary permanence. That
// means as soon as we queue the semaphore for a wait it reverts to its previous permanent
// state before importing. This means it will now be in an idle state with no pending
// signal or wait operations, so it is safe to immediately delete it.
mDestroySemaphore(mDevice, semaphore, nullptr);
} else {
// Block CPU on the fence.
status_t err = fence->waitForever("VulkanManager::fenceWait");
if (err != NO_ERROR) {
ALOGE("VulkanManager::fenceWait: error waiting for fence: %d", err);
return err;
}
}
return OK;
}
status_t VulkanManager::createReleaseFence(sp<Fence>& nativeFence) {
//TODO: Create a fence that is signaled, when all the pending Vulkan commands are flushed.
if (!hasVkContext()) {
ALOGE("VulkanManager::createReleaseFence: VkDevice not initialized");
return INVALID_OPERATION;
}
if (SyncFeatures::getInstance().useFenceSync()) {
ALOGE("VulkanManager::createReleaseFence: Vk backend doesn't support non-native fences");
return INVALID_OPERATION;
}
if (!SyncFeatures::getInstance().useNativeFenceSync()) {
return OK;
}
VkExportSemaphoreCreateInfo exportInfo;
exportInfo.sType = VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_CREATE_INFO;
exportInfo.pNext = nullptr;
exportInfo.handleTypes = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT;
VkSemaphoreCreateInfo semaphoreInfo;
semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
semaphoreInfo.pNext = &exportInfo;
semaphoreInfo.flags = 0;
VkSemaphore semaphore;
VkResult err = mCreateSemaphore(mDevice, &semaphoreInfo, nullptr, &semaphore);
if (VK_SUCCESS != err) {
ALOGE("VulkanManager::createReleaseFence: Failed to create semaphore");
return INVALID_OPERATION;
}
LOG_ALWAYS_FATAL_IF(mDummyCB == VK_NULL_HANDLE);
VkSubmitInfo submitInfo;
memset(&submitInfo, 0, sizeof(VkSubmitInfo));
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
submitInfo.waitSemaphoreCount = 0;
submitInfo.pWaitSemaphores = nullptr;
submitInfo.pWaitDstStageMask = nullptr;
submitInfo.commandBufferCount = 1;
submitInfo.pCommandBuffers = &mDummyCB;
submitInfo.signalSemaphoreCount = 1;
submitInfo.pSignalSemaphores = &semaphore;
mQueueSubmit(mGraphicsQueue, 1, &submitInfo, VK_NULL_HANDLE);
VkSemaphoreGetFdInfoKHR getFdInfo;
getFdInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_GET_FD_INFO_KHR;
getFdInfo.pNext = nullptr;
getFdInfo.semaphore = semaphore;
getFdInfo.handleType = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT;
int fenceFd = 0;
err = mGetSemaphoreFdKHR(mDevice, &getFdInfo, &fenceFd);
if (VK_SUCCESS != err) {
ALOGE("VulkanManager::createReleaseFence: Failed to get semaphore Fd");
return INVALID_OPERATION;
}
nativeFence = new Fence(fenceFd);
// Exporting a semaphore with copy transference via vkGetSemahporeFdKHR, has the same effect of
// destroying the semaphore and creating a new one with the same handle, and the payloads
// ownership is move to the Fd we created. Thus the semahpore is in a state that we can delete
// it and we don't need to wait on the command buffer we submitted to finish.
mDestroySemaphore(mDevice, semaphore, nullptr);
return OK;
}

View File

@@ -139,6 +139,8 @@ private:
VulkanSurface::BackbufferInfo* getAvailableBackbuffer(VulkanSurface* surface);
bool setupDummyCommandBuffer();
// simple wrapper class that exists only to initialize a pointer to NULL
template <typename FNPTR_TYPE>
class VkPtr {
@@ -199,6 +201,8 @@ private:
VkPtr<PFN_vkCreateSemaphore> mCreateSemaphore;
VkPtr<PFN_vkDestroySemaphore> mDestroySemaphore;
VkPtr<PFN_vkImportSemaphoreFdKHR> mImportSemaphoreFdKHR;
VkPtr<PFN_vkGetSemaphoreFdKHR> mGetSemaphoreFdKHR;
VkPtr<PFN_vkCreateFence> mCreateFence;
VkPtr<PFN_vkDestroyFence> mDestroyFence;
VkPtr<PFN_vkWaitForFences> mWaitForFences;
@@ -216,6 +220,8 @@ private:
VkQueue mPresentQueue = VK_NULL_HANDLE;
VkCommandPool mCommandPool = VK_NULL_HANDLE;
VkCommandBuffer mDummyCB = VK_NULL_HANDLE;
enum class SwapBehavior {
Discard,
BufferAge,