aboutsummaryrefslogtreecommitdiff
path: root/demo/d3d12/NvCoDx12CounterFence.h
blob: 9add39b25151d69ade6d8566ec020da9633cd628 (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
/* Copyright (c) 2016, NVIDIA CORPORATION.  All rights reserved.
* NVIDIA CORPORATION and its licensors retain all intellectual property
* and proprietary rights in and to this software, related documentation
* and any modifications thereto.  Any use, reproduction, disclosure or
* distribution of this software and related documentation without an express
* license agreement from NVIDIA CORPORATION is strictly prohibited. */

#ifndef NV_CO_DX12_COUNTER_FENCE_H
#define NV_CO_DX12_COUNTER_FENCE_H

#include <NvResult.h>

#define NOMINMAX
#include <d3d12.h>
#include <stdint.h>
#include <stdio.h>
#include <assert.h>
#include <wrl.h>

using namespace Microsoft::WRL;

/** \addtogroup common
@{
*/

namespace nvidia {
namespace Common { 

/*! \brief A class to simplify using Dx12 fences. 

A fence is a mechanism to track GPU work. This is achieved by having a counter that the CPU holds 
called the current value. Calling nextSignal will increase the CPU counter, and add a fence 
with that value to the commandQueue. When the GPU has completed all the work before the fence it will 
update the completed value. This is typically used when 
the CPU needs to know the GPU has finished some piece of work has completed. To do this the CPU
can check the completed value, and when it is greater or equal to the value returned by nextSignal the 
CPU will know that all the work prior to when the nextSignal was added to the queue will have completed. 

NOTE! This cannot be used across threads, as for amongst other reasons SetEventOnCompletion 
only works with a single value.

Signal on the CommandQueue updates the fence on the GPU side. Signal on the fence object changes 
the value on the CPU side (not used here).

Useful article describing how Dx12 synchronization works:
https://msdn.microsoft.com/en-us/library/windows/desktop/dn899217%28v=vs.85%29.aspx
*/
class Dx12CounterFence
{
	//NV_CO_DECLARE_CLASS_BASE(Dx12CounterFence);
public:
		/// Must be called before used
	int init(ID3D12Device* device, uint64_t initialValue = 0);
		/// Increases the counter, signals the queue and waits for the signal to be hit
	void nextSignalAndWait(ID3D12CommandQueue* queue);
		/// Signals with next counter value. Returns the value the signal was called on
	uint64_t nextSignal(ID3D12CommandQueue* commandQueue);
		/// Get the current value
	inline uint64_t getCurrentValue() const { return m_currentValue; }
		/// Get the completed value
	inline uint64_t getCompletedValue() const { return m_fence->GetCompletedValue(); }

		/// Waits for the the specified value 
	void waitUntilCompleted(uint64_t completedValue);

		/// Ctor
	Dx12CounterFence():m_event(nullptr), m_currentValue(0) {}
		/// Dtor
	~Dx12CounterFence();

	protected:
	HANDLE m_event;
	ComPtr<ID3D12Fence> m_fence;
	uint64_t m_currentValue;
};

} // namespace Common
} // namespace nvidia

/** @} */

#endif // NV_CO_DX12_COUNTER_FENCE_H