vsg 1.1.3
VulkanSceneGraph library
Loading...
Searching...
No Matches
TracyInstrumentation.h
1#pragma once
2
3/* <editor-fold desc="MIT License">
4
5Copyright(c) 2023 Robert Osfield
6
7Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
8
9The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
10
11THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
12
13</editor-fold> */
14
15#include <tracy/Tracy.hpp>
16#include <tracy/TracyVulkan.hpp>
17
18#include <vsg/utils/Instrumentation.h>
19
20using namespace tracy;
21
22namespace vsg
23{
24
25 class TracySettings : public Inherit<Object, TracySettings>
26 {
27 public:
28 uint32_t cpu_instrumentation_level = 3;
29 uint32_t gpu_instrumentation_level = 3;
30 };
31 VSG_type_name(vsg::TracySettings);
32
33#ifdef TRACY_ENABLE
35 class TracyContexts : public Inherit<Object, TracyContexts>
36 {
37 public:
38 VkCtx* getOrCreateContext(CommandBuffer& commandBuffer) const
39 {
40 std::scoped_lock<std::mutex> lock(mutex);
41
42 ref_ptr<Device> device(commandBuffer.getDevice());
43 auto& [ctx, requiresCollection] = ctxMap[device];
44 if (!ctx)
45 {
46 auto queue = device->getQueue(commandBuffer.getCommandPool()->queueFamilyIndex, 0);
47 auto commandPool = CommandPool::create(device, queue->queueFamilyIndex(), VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT);
48 auto temporaryCommandBuffer = commandPool->allocate();
49 auto extensions = device->getInstance()->getExtensions();
50
51 if (device->supportsDeviceExtension("VK_EXT_calibrated_timestamps"))
52 {
53 ctx = TracyVkContextCalibrated(device->getPhysicalDevice()->vk(), device->vk(), queue->vk(), temporaryCommandBuffer->vk(),
54 extensions->vkGetPhysicalDeviceCalibrateableTimeDomainsEXT, extensions->vkGetCalibratedTimestampsEXT);
55 }
56 else
57 {
58 ctx = TracyVkContext(device->getPhysicalDevice()->vk(), device->vk(), queue->vk(), temporaryCommandBuffer->vk());
59 }
60 requiresCollection = false;
61 }
62
63 if (ctx && requiresCollection)
64 {
65 TracyVkCollect(ctx, commandBuffer.vk());
66 requiresCollection = false;
67 }
68
69 return ctx;
70 }
71
72 void frameComplete()
73 {
74 std::scoped_lock<std::mutex> lock(mutex);
75 for (auto itr = ctxMap.begin(); itr != ctxMap.end(); ++itr)
76 {
77 itr->second.second = true;
78 }
79 }
80
81 mutable std::mutex mutex;
82 mutable std::map<ref_ptr<Device>, std::pair<VkCtx*, bool>> ctxMap;
83
84 protected:
85 ~TracyContexts()
86 {
87 for (auto itr = ctxMap.begin(); itr != ctxMap.end(); ++itr)
88 {
89 TracyVkDestroy(itr->second.first);
90 }
91 }
92 };
93 VSG_type_name(vsg::TracyContexts);
94
96 class TracyInstrumentation : public Inherit<Instrumentation, TracyInstrumentation>
97 {
98 public:
99 TracyInstrumentation() :
100 settings(TracySettings::create()),
101 contexts(TracyContexts::create())
102 {
103 }
104
105 TracyInstrumentation(TracyInstrumentation& parent) :
106 settings(parent.settings),
107 contexts(parent.contexts)
108 {
109 }
110
111 ref_ptr<TracySettings> settings;
112 ref_ptr<TracyContexts> contexts;
113 mutable VkCtx* ctx = nullptr;
114 bool requiresCollection = false;
115
116 ref_ptr<Instrumentation> shareOrDuplicateForThreadSafety() override
117 {
118 return TracyInstrumentation::create(*this);
119 }
120
121 void setThreadName(const std::string& name) const override
122 {
123 tracy::SetThreadName(name.c_str());
124 }
125
126 void enterFrame(const SourceLocation*, uint64_t&, FrameStamp&) const override {}
127
128 void leaveFrame(const SourceLocation*, uint64_t&, FrameStamp&) const override
129 {
130 contexts->frameComplete();
131
132 FrameMark;
133 }
134
135 void enter(const SourceLocation* slcloc, uint64_t& reference, const Object*) const override
136 {
137# ifdef TRACY_ON_DEMAND
138 if (!GetProfiler().IsConnected() || (slcloc->level > settings->cpu_instrumentation_level))
139# else
140 if (slcloc->level > settings->cpu_instrumentation_level)
141# endif
142 {
143 reference = 0;
144 return;
145 }
146
147# ifdef TRACY_ON_DEMAND
148 reference = GetProfiler().ConnectionId();
149# else
150 reference = 1;
151# endif
152
153 TracyQueuePrepare(QueueType::ZoneBegin);
154 MemWrite(&item->zoneBegin.time, tracy::Profiler::GetTime());
155 MemWrite(&item->zoneBegin.srcloc, (uint64_t)slcloc);
156 TracyQueueCommit(zoneBeginThread);
157 }
158
159 void leave(const SourceLocation*, uint64_t& reference, const Object*) const override
160 {
161# ifdef TRACY_ON_DEMAND
162 if (reference == 0 || GetProfiler().ConnectionId() != reference) return;
163# else
164 if (reference == 0) return;
165# endif
166
167 TracyQueuePrepare(QueueType::ZoneEnd);
168 MemWrite(&item->zoneEnd.time, tracy::Profiler::GetTime());
169 TracyQueueCommit(zoneEndThread);
170 }
171
172 void enterCommandBuffer(const SourceLocation* slcloc, uint64_t& reference, CommandBuffer& commandBuffer) const override
173 {
174 if (ctx = contexts->getOrCreateContext(commandBuffer))
175 {
176 enter(slcloc, reference, commandBuffer, nullptr);
177 }
178 }
179
180 void leaveCommandBuffer(const SourceLocation* slcloc, uint64_t& reference, CommandBuffer& commandBuffer) const override
181 {
182 if (ctx)
183 {
184 leave(slcloc, reference, commandBuffer, nullptr);
185 }
186
187 ctx = nullptr;
188 }
189
190 void enter(const SourceLocation* slcloc, uint64_t& reference, CommandBuffer& cmdbuf, const Object*) const override
191 {
192# ifdef TRACY_ON_DEMAND
193 if (!ctx || !GetProfiler().IsConnected() || (slcloc->level > settings->gpu_instrumentation_level))
194# else
195 if (!ctx || slcloc->level > settings->gpu_instrumentation_level)
196# endif
197 {
198 reference = 0;
199 return;
200 }
201
202# ifdef TRACY_ON_DEMAND
203 reference = GetProfiler().ConnectionId();
204# else
205 reference = 1;
206# endif
207
208 const auto queryId = ctx->NextQueryId();
209 CONTEXT_VK_FUNCTION_WRAPPER(vkCmdWriteTimestamp(cmdbuf, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, ctx->GetQueryPool(), queryId));
210
211 auto item = tracy::Profiler::QueueSerial();
212 MemWrite(&item->hdr.type, QueueType::GpuZoneBeginSerial);
213 MemWrite(&item->gpuZoneBegin.cpuTime, tracy::Profiler::GetTime());
214 MemWrite(&item->gpuZoneBegin.srcloc, (uint64_t)slcloc);
215 MemWrite(&item->gpuZoneBegin.thread, GetThreadHandle());
216 MemWrite(&item->gpuZoneBegin.queryId, uint16_t(queryId));
217 MemWrite(&item->gpuZoneBegin.context, ctx->GetId());
218 tracy::Profiler::QueueSerialFinish();
219 }
220
221 void leave(const SourceLocation*, uint64_t& reference, CommandBuffer& cmdbuf, const Object*) const override
222 {
223# ifdef TRACY_ON_DEMAND
224 if (reference == 0 || GetProfiler().ConnectionId() != reference) return;
225# else
226 if (reference == 0) return;
227# endif
228
229 const auto queryId = ctx->NextQueryId();
230 CONTEXT_VK_FUNCTION_WRAPPER(vkCmdWriteTimestamp(cmdbuf, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, ctx->GetQueryPool(), queryId));
231
232 auto item = tracy::Profiler::QueueSerial();
233 MemWrite(&item->hdr.type, QueueType::GpuZoneEndSerial);
234 MemWrite(&item->gpuZoneEnd.cpuTime, tracy::Profiler::GetTime());
235 MemWrite(&item->gpuZoneEnd.thread, GetThreadHandle());
236 MemWrite(&item->gpuZoneEnd.queryId, uint16_t(queryId));
237 MemWrite(&item->gpuZoneEnd.context, ctx->GetId());
238 tracy::Profiler::QueueSerialFinish();
239 }
240 };
241 VSG_type_name(vsg::TracyInstrumentation);
242#else
243 class TracyInstrumentation : public Inherit<Instrumentation, TracyInstrumentation>
244 {
245 public:
247 {
248 vsg::info("TracyInstrumentation not supported and the tracy's TRACY_ENABLE is set to OFF.");
249 }
250
251 ref_ptr<TracySettings> settings;
252 };
253 VSG_type_name(vsg::TracyInstrumentation);
254#endif
255} // namespace vsg
CommandBuffer encapsulates VkCommandBuffer.
Definition CommandBuffer.h:27
Definition Inherit.h:28
Definition TracyInstrumentation.h:244
Definition TracyInstrumentation.h:26
Definition ref_ptr.h:22