Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 26e0dca4 authored by Greg Daniel's avatar Greg Daniel
Browse files

Implemenet fenceWait and createReleaseFence in VulkanManager.

Test: Manual building and testing on walleye device.
Change-Id: I9f5fa259d6457805b546d2b6b11ce4b0800621eb
parent 7b198b32
Loading
Loading
Loading
Loading
+185 −7
Original line number Diff line number Diff line
@@ -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.
    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;
}

+6 −0
Original line number Diff line number Diff line
@@ -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,