summaryrefslogtreecommitdiffstats
path: root/src/video_core/renderer_vulkan/vk_resource_manager.h
blob: 5345ba46e90faccbd3190f72d7453193f1632ec5 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
// Copyright 2018 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.

#pragma once

#include <vector>
#include "video_core/renderer_vulkan/declarations.h"

namespace Vulkan {

class VKDevice;
class VKFence;
class VKResourceManager;

/// Interface for a Vulkan resource
class VKResource {
public:
    explicit VKResource();
    virtual ~VKResource();

    /**
     * Signals the object that an owning fence has been signaled.
     * @param signaling_fence Fence that signals its usage end.
     */
    virtual void OnFenceRemoval(VKFence* signaling_fence) = 0;
};

/**
 * Fences take ownership of objects, protecting them from GPU-side or driver-side concurrent access.
 * They must be commited from the resource manager. Their usage flow is: commit the fence from the
 * resource manager, protect resources with it and use them, send the fence to an execution queue
 * and Wait for it if needed and then call Release. Used resources will automatically be signaled
 * when they are free to be reused.
 * @brief Protects resources for concurrent usage and signals its release.
 */
class VKFence {
    friend class VKResourceManager;

public:
    explicit VKFence(const VKDevice& device, UniqueFence handle);
    ~VKFence();

    /**
     * Waits for the fence to be signaled.
     * @warning You must have ownership of the fence and it has to be previously sent to a queue to
     * call this function.
     */
    void Wait();

    /**
     * Releases ownership of the fence. Pass after it has been sent to an execution queue.
     * Unmanaged usage of the fence after the call will result in undefined behavior because it may
     * be being used for something else.
     */
    void Release();

    /// Protects a resource with this fence.
    void Protect(VKResource* resource);

    /// Removes protection for a resource.
    void Unprotect(const VKResource* resource);

    /// Retreives the fence.
    operator vk::Fence() const {
        return *handle;
    }

private:
    /// Take ownership of the fence.
    void Commit();

    /**
     * Updates the fence status.
     * @warning Waiting for the owner might soft lock the execution.
     * @param gpu_wait Wait for the fence to be signaled by the driver.
     * @param owner_wait Wait for the owner to signal its freedom.
     * @returns True if the fence is free. Waiting for gpu and owner will always return true.
     */
    bool Tick(bool gpu_wait, bool owner_wait);

    const VKDevice& device;                       ///< Device handler
    UniqueFence handle;                           ///< Vulkan fence
    std::vector<VKResource*> protected_resources; ///< List of resources protected by this fence
    bool is_owned = false; ///< The fence has been commited but not released yet.
    bool is_used = false;  ///< The fence has been commited but it has not been checked to be free.
};

/**
 * A fence watch is used to keep track of the usage of a fence and protect a resource or set of
 * resources without having to inherit VKResource from their handlers.
 */
class VKFenceWatch final : public VKResource {
public:
    explicit VKFenceWatch();
    ~VKFenceWatch();

    /// Waits for the fence to be released.
    void Wait();

    /**
     * Waits for a previous fence and watches a new one.
     * @param new_fence New fence to wait to.
     */
    void Watch(VKFence& new_fence);

    /**
     * Checks if it's currently being watched and starts watching it if it's available.
     * @returns True if a watch has started, false if it's being watched.
     */
    bool TryWatch(VKFence& new_fence);

    void OnFenceRemoval(VKFence* signaling_fence) override;

private:
    VKFence* fence{}; ///< Fence watching this resource. nullptr when the watch is free.
};

} // namespace Vulkan