Jump to content

Advanced Hook Management


klepto2
 Share

Recommended Posts

 

while developing the PBR Texture generator I have found some flaw with the current hook system. It is somewhat inflexible. Soi tried to add my own Hook Manager:

enum class HookState
{
    IDLE,
    PENDING,
    RUNNING,
    FINISHED,
};
class HookManager;

class Hook : public Object
{
    friend class HookManager;

private:
    void* _function;
    shared_ptr<Object> _extra;
    HookState _currentState;
    bool _stopping = false;
    bool _repeating = false;
    shared_ptr<HookManager> _manager;
public:
    
    Hook(shared_ptr<HookManager> manager, void callback(const UltraEngine::Render::VkRenderer&, shared_ptr<Object>), shared_ptr<Object> extra, bool repeat = false)
    {
        _function = callback;
        _extra = extra;
        _currentState = HookState::IDLE;
        _repeating = repeat;
        _manager = manager;
    }

    void Start()
    {
        _currentState = HookState::PENDING;
    }

    void Stop()
    {
        _stopping = true;
    }

    HookState GetState() { return _currentState; }

    void SetExtra(shared_ptr<Object> extra)
    {
        _extra = extra;
    }
};

class HookManager : public Object
{
    friend class Hook;

private:
    static void UpdateDispatch(const UltraEngine::Render::VkRenderer& renderer, shared_ptr<Object> extra)
    {
        auto hookManager = extra->As<HookManager>();
        if (hookManager != NULL)
        {
            for (auto hook : hookManager->_hooks)
            {
                if (hook->_stopping)
                {
                    hook->_currentState = HookState::IDLE;
                    hook->_stopping = false;
                }

                if (hook->GetState() != HookState::FINISHED)
                {
                    if (hook->GetState() == HookState::PENDING)
                    {
                        hook->_currentState = HookState::RUNNING;
                        auto f = (void(*)(const UltraEngine::Render::VkRenderer&, shared_ptr<Object>))hook->_function;
                        f(renderer, hook->_extra);
                    }
                    else if (hook->GetState() == HookState::RUNNING)
                    {
                        if (!hook->_repeating)
                        {
                            hook->_currentState = HookState::FINISHED;
                        }
                        else
                        {
                            hook->_currentState = HookState::PENDING;
                        }
                    }
                }
            }
        }
    }

    inline static map<HookID,map<shared_ptr<World>, shared_ptr<HookManager>>> _mapWorldHookManager;

    vector<shared_ptr<Hook>> _hooks;
    shared_ptr<World> _world;
    HookID _hookId;

public:
    static shared_ptr<HookManager> Get(shared_ptr<World> world, HookID hookId)
    {
        if (_mapWorldHookManager.size() == 0)
        {
            _mapWorldHookManager[HOOKID_RENDER] = {};
            _mapWorldHookManager[HOOKID_TRANSFER] = {};
        }

        if (HookManager::_mapWorldHookManager[hookId][world] == NULL)
        {
            auto mgr = std::make_shared<HookManager>(world, hookId);
            mgr->StartDispatching();
            HookManager::_mapWorldHookManager[hookId][world] = mgr;
        }

        return HookManager::_mapWorldHookManager[hookId][world];
    }

    void StartDispatching()
    {
        _world->AddHook(HookID::HOOKID_TRANSFER, HookManager::UpdateDispatch, Self(), true);
    }

    void Start(shared_ptr<Hook> hook)
    {
        auto position = std::find(_hooks.begin(), _hooks.end(), hook);
        if (position != _hooks.end())
        {
            hook->Start();
        }
    }

    void Stop(shared_ptr<Hook> hook)
    {
        auto position = std::find(_hooks.begin(), _hooks.end(), hook);
        if (position != _hooks.end())
        {
            hook->Stop();
        }
    }

    HookManager(shared_ptr<World> world, HookID hookId)
    {
        _world = world;
        _hookId = hookId;
    }

    shared_ptr<Hook> AddHook(void callback(const UltraEngine::Render::VkRenderer&, shared_ptr<Object>), shared_ptr<Object> extra , bool repeat = false)
    {
        auto hook = std::make_shared<Hook>(Self()->As<HookManager>(), callback, extra, repeat);
        _hooks.push_back(hook);
        return hook;
    }

    void RemoveHook(shared_ptr<Hook> hook)
    {
        auto position = std::find(_hooks.begin(), _hooks.end(), hook);
        if (position != _hooks.end())
            _hooks.erase(position);
    }
};

 It allows to dispatch, Start/Stop hooks like a thread and also adds the ability check the state of a hook. 

static void checkCallback(const UltraEngine::Render::VkRenderer&, shared_ptr<Object>)
{
}
  
auto hookManager = HookManager::Get(_world, HOOKID_TRANSFER);
auto checkHook = _hookManager->AddHook(checkCallback, _world, false);
hookManager->Start(checkHook);
  
while(checkHook->GetState() != HookState::Finished)
{
  world->Update();
  world->Render();
}  
 
  

This makes it a bit easier to watch the Hook execution.

I use it in my PBRTextureGen and in my current state of Computeshader Implementation. It makes it much easier to manage the hooks. It might stll have a few bugs in it as i haven't fully tested every usecase, but for the basics it works :)

 

 

  • Windows 10 Pro 64-Bit-Version
  • NVIDIA Geforce 1080 TI
Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

 Share

×
×
  • Create New...