AsynchronousVk.h#

Parent directory (Vulkan)

Contains a futures system for asynchronous loading of resources into Vulkan.

Includes#

  • PVRCore/Threading.h

  • PVRCore/texture/Texture.h

  • PVRCore/texture/TextureLoadAsync.h

  • PVRUtils/Vulkan/HelperVk.h

  • PVRVk/ImageVk.h

Included By#

Namespaces#

Classes#

Functions#

Typedefs#

Source Code#

#pragma once
#include "PVRCore/Threading.h"
#include "PVRCore/texture/Texture.h"
#include "PVRCore/texture/TextureLoadAsync.h"
#include "PVRVk/ImageVk.h"
#include "PVRUtils/Vulkan/HelperVk.h"
namespace pvr {
namespace utils {

typedef std::shared_ptr<Texture> TexturePtr;

typedef std::shared_ptr<async::IFrameworkAsyncResult<TexturePtr>> AsyncTexture;

typedef std::shared_ptr<async::IFrameworkAsyncResult<pvrvk::ImageView>> AsyncApiTexture;

struct ImageUploadFuture_ : public async::IFrameworkAsyncResult<pvrvk::ImageView>, public std::enable_shared_from_this<ImageUploadFuture_>
{
public:
    typedef IFrameworkAsyncResult<pvrvk::ImageView>::Callback CallbackType;

    ImageUploadFuture_() {}

    pvrvk::Queue _queue;

    pvrvk::Device _device;

    AsyncTexture _texture;

    pvrvk::CommandPool _cmdPool;

    async::Mutex* _cmdQueueMutex;

    bool _allowDecompress;

    mutable async::SemaphorePtr _resultSemaphore;

    bool _callbackBeforeSignal = false;

    void setCallBack(CallbackType callback) { setTheCallback(callback); }

    void loadNow()
    {
        _result = customUploadImage();

        _successful = _result != nullptr;
        if (_callbackBeforeSignal)
        {
            callBack();
            _resultSemaphore->signal();
        }
        else
        {
            _resultSemaphore->signal();
            callBack();
        }
    }

    const pvrvk::ImageView& getResult() { return _result; }

private:
    pvrvk::ImageView customUploadImage()
    {
        Texture& assetTexture = *_texture->get();
        pvrvk::CommandBuffer cmdBuffer = _cmdPool->allocateCommandBuffer();
        cmdBuffer->begin();
        pvrvk::ImageView results = uploadImageAndView(_device, assetTexture, _allowDecompress, cmdBuffer);
        cmdBuffer->end();

        pvrvk::SubmitInfo submitInfo;
        submitInfo.commandBuffers = &cmdBuffer;
        submitInfo.numCommandBuffers = 1;
        pvrvk::Fence fence = _device->createFence();
        if (_cmdQueueMutex != nullptr)
        {
            std::lock_guard<pvr::async::Mutex> lock(*_cmdQueueMutex);
            _queue->submit(&submitInfo, 1, fence);
        }
        else
        {
            _queue->submit(&submitInfo, 1, fence);
        }
        fence->wait();

        return results;
    }

    void callBack() { executeCallBack(shared_from_this()); }
    pvrvk::ImageView _result;
    pvrvk::ImageView get_() const
    {
        if (!_inCallback)
        {
            _resultSemaphore->wait();
            _resultSemaphore->signal();
        }
        return _result;
    }

    pvrvk::ImageView getNoWait() const { return _result; }

    bool isComplete_() const
    {
        if (_resultSemaphore->tryWait())
        {
            _resultSemaphore->signal();
            return true;
        }
        return false;
    }
    void cleanup_() {}
    void destroyObject() {}
};

typedef std::shared_ptr<ImageUploadFuture_> ImageUploadFuture;

inline void imageUploadAsyncWorker(ImageUploadFuture uploadFuture) { uploadFuture->loadNow(); }

class ImageApiAsyncUploader : public async::AsyncScheduler<pvrvk::ImageView, ImageUploadFuture, imageUploadAsyncWorker>
{
private:
    pvrvk::Device _device;
    pvrvk::Queue _queueVk;
    pvrvk::CommandPool _cmdPool;
    async::Mutex* _cmdQueueMutex;

public:
    ImageApiAsyncUploader() : _cmdQueueMutex(nullptr) { _myInfo = "ImageApiAsyncUploader"; }
    typedef async::IFrameworkAsyncResult<pvrvk::ImageView>::Callback CallbackType;

    void init(pvrvk::Device& device, pvrvk::Queue& queue, async::Mutex* queueSemaphore = nullptr)
    {
        _device = device;
        _queueVk = queue;
        _cmdPool = device->createCommandPool(pvrvk::CommandPoolCreateInfo(queue->getFamilyIndex(), pvrvk::CommandPoolCreateFlags::e_RESET_COMMAND_BUFFER_BIT));
        _cmdQueueMutex = queueSemaphore;
    }

    AsyncApiTexture uploadTextureAsync(const AsyncTexture& texture, bool allowDecompress = true, CallbackType callback = nullptr, bool callbackBeforeSignal = false)
    {
        assertion(_queueVk != nullptr, "Queue has not been initialized");
        auto future = std::make_shared<ImageUploadFuture_>();
        auto& params = *future;
        params._allowDecompress = allowDecompress;
        params._queue = _queueVk;
        params._device = _device;
        params._texture = texture;
        params._resultSemaphore = std::make_shared<async::Semaphore>();
        params._cmdPool = _cmdPool;
        params.setCallBack(callback);
        params._callbackBeforeSignal = callbackBeforeSignal;
        params._cmdQueueMutex = _cmdQueueMutex;
        _queueSemaphore.wait();
        _queue.emplace_back(future);
        _queueSemaphore.signal();
        _workSemaphore.signal();
        return future;
    }
};
} // namespace utils
} // namespace pvr