VR-Vantage 2.8 API Documentation
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
TracyVulkan.hpp
Go to the documentation of this file.
1 #ifndef __TRACYVULKAN_HPP__
2 #define __TRACYVULKAN_HPP__
3 
4 #if !defined TRACY_ENABLE
5 
6 #define TracyVkContext(x,y,z,w) nullptr
7 #define TracyVkContextCalibrated(x,y,z,w,a,b) nullptr
8 #define TracyVkDestroy(x)
9 #define TracyVkNamedZone(c,x,y,z,w)
10 #define TracyVkNamedZoneC(c,x,y,z,w,a)
11 #define TracyVkZone(c,x,y)
12 #define TracyVkZoneC(c,x,y,z)
13 #define TracyVkCollect(c,x)
14 
15 #define TracyVkNamedZoneS(c,x,y,z,w,a)
16 #define TracyVkNamedZoneCS(c,x,y,z,w,v,a)
17 #define TracyVkZoneS(c,x,y,z)
18 #define TracyVkZoneCS(c,x,y,z,w)
19 
20 namespace tracy
21 {
22 class VkCtxScope {};
23 }
24 
25 using TracyVkCtx = void*;
26 
27 #else
28 
29 #include <assert.h>
30 #include <stdlib.h>
31 #include <vulkan/vulkan.h>
32 #include "Tracy.hpp"
33 #include "client/TracyProfiler.hpp"
35 
36 namespace tracy
37 {
38 
39 class VkCtx
40 {
41  friend class VkCtxScope;
42 
43  enum { QueryCount = 64 * 1024 };
44 
45 public:
46  VkCtx( VkPhysicalDevice physdev, VkDevice device, VkQueue queue, VkCommandBuffer cmdbuf, PFN_vkGetPhysicalDeviceCalibrateableTimeDomainsEXT _vkGetPhysicalDeviceCalibrateableTimeDomainsEXT, PFN_vkGetCalibratedTimestampsEXT _vkGetCalibratedTimestampsEXT )
47  : m_device( device )
48  , m_timeDomain( VK_TIME_DOMAIN_DEVICE_EXT )
49  , m_context( GetGpuCtxCounter().fetch_add( 1, std::memory_order_relaxed ) )
50  , m_head( 0 )
51  , m_tail( 0 )
52  , m_oldCnt( 0 )
53  , m_queryCount( QueryCount )
54  , m_vkGetCalibratedTimestampsEXT( _vkGetCalibratedTimestampsEXT )
55  {
56  assert( m_context != 255 );
57 
58  if( _vkGetPhysicalDeviceCalibrateableTimeDomainsEXT && _vkGetCalibratedTimestampsEXT )
59  {
60  uint32_t num;
61  _vkGetPhysicalDeviceCalibrateableTimeDomainsEXT( physdev, &num, nullptr );
62  if( num > 4 ) num = 4;
63  VkTimeDomainEXT data[4];
64  _vkGetPhysicalDeviceCalibrateableTimeDomainsEXT( physdev, &num, data );
65  for( uint32_t i=0; i<num; i++ )
66  {
67  // TODO VK_TIME_DOMAIN_CLOCK_MONOTONIC_RAW_EXT
68  if( data[i] == VK_TIME_DOMAIN_QUERY_PERFORMANCE_COUNTER_EXT )
69  {
70  m_timeDomain = data[i];
71  break;
72  }
73  }
74  }
75 
76  VkPhysicalDeviceProperties prop;
77  vkGetPhysicalDeviceProperties( physdev, &prop );
78  const float period = prop.limits.timestampPeriod;
79 
80  VkQueryPoolCreateInfo poolInfo = {};
81  poolInfo.sType = VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO;
82  poolInfo.queryCount = m_queryCount;
83  poolInfo.queryType = VK_QUERY_TYPE_TIMESTAMP;
84  while( vkCreateQueryPool( device, &poolInfo, nullptr, &m_query ) != VK_SUCCESS )
85  {
86  m_queryCount /= 2;
87  poolInfo.queryCount = m_queryCount;
88  }
89 
90  VkCommandBufferBeginInfo beginInfo = {};
91  beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
92  beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
93 
94  VkSubmitInfo submitInfo = {};
95  submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
96  submitInfo.commandBufferCount = 1;
97  submitInfo.pCommandBuffers = &cmdbuf;
98 
99  vkBeginCommandBuffer( cmdbuf, &beginInfo );
100  vkCmdResetQueryPool( cmdbuf, m_query, 0, m_queryCount );
101  vkEndCommandBuffer( cmdbuf );
102  vkQueueSubmit( queue, 1, &submitInfo, VK_NULL_HANDLE );
103  vkQueueWaitIdle( queue );
104 
105  int64_t tcpu, tgpu;
106  if( m_timeDomain == VK_TIME_DOMAIN_DEVICE_EXT )
107  {
108  vkBeginCommandBuffer( cmdbuf, &beginInfo );
109  vkCmdWriteTimestamp( cmdbuf, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, m_query, 0 );
110  vkEndCommandBuffer( cmdbuf );
111  vkQueueSubmit( queue, 1, &submitInfo, VK_NULL_HANDLE );
112  vkQueueWaitIdle( queue );
113 
114  tcpu = Profiler::GetTime();
115  vkGetQueryPoolResults( device, m_query, 0, 1, sizeof( tgpu ), &tgpu, sizeof( tgpu ), VK_QUERY_RESULT_64_BIT | VK_QUERY_RESULT_WAIT_BIT );
116 
117  vkBeginCommandBuffer( cmdbuf, &beginInfo );
118  vkCmdResetQueryPool( cmdbuf, m_query, 0, 1 );
119  vkEndCommandBuffer( cmdbuf );
120  vkQueueSubmit( queue, 1, &submitInfo, VK_NULL_HANDLE );
121  vkQueueWaitIdle( queue );
122  }
123  else
124  {
125  enum { NumProbes = 32 };
126 
127  VkCalibratedTimestampInfoEXT spec[2] = {
128  { VK_STRUCTURE_TYPE_CALIBRATED_TIMESTAMP_INFO_EXT, nullptr, VK_TIME_DOMAIN_DEVICE_EXT },
129  { VK_STRUCTURE_TYPE_CALIBRATED_TIMESTAMP_INFO_EXT, nullptr, m_timeDomain },
130  };
131  uint64_t ts[2];
132  uint64_t deviation[NumProbes];
133  for( int i=0; i<NumProbes; i++ )
134  {
135  _vkGetCalibratedTimestampsEXT( device, 2, spec, ts, deviation+i );
136  }
137  uint64_t minDeviation = deviation[0];
138  for( int i=1; i<NumProbes; i++ )
139  {
140  if( minDeviation > deviation[i] )
141  {
142  minDeviation = deviation[i];
143  }
144  }
145  m_deviation = minDeviation * 3 / 2;
146 
147  m_qpcToNs = int64_t( 1000000000. / GetFrequencyQpc() );
148 
149  Calibrate( device, m_prevCalibration, tgpu );
150  tcpu = Profiler::GetTime();
151  }
152 
153  uint8_t flags = 0;
154  if( m_timeDomain != VK_TIME_DOMAIN_DEVICE_EXT ) flags |= GpuContextCalibration;
155 
156  auto item = Profiler::QueueSerial();
157  MemWrite( &item->hdr.type, QueueType::GpuNewContext );
158  MemWrite( &item->gpuNewContext.cpuTime, tcpu );
159  MemWrite( &item->gpuNewContext.gpuTime, tgpu );
160  memset( &item->gpuNewContext.thread, 0, sizeof( item->gpuNewContext.thread ) );
161  MemWrite( &item->gpuNewContext.period, period );
162  MemWrite( &item->gpuNewContext.context, m_context );
163  MemWrite( &item->gpuNewContext.flags, flags );
164  MemWrite( &item->gpuNewContext.type, GpuContextType::Vulkan );
165 
166 #ifdef TRACY_ON_DEMAND
167  GetProfiler().DeferItem( *item );
168 #endif
170 
171  m_res = (int64_t*)tracy_malloc( sizeof( int64_t ) * m_queryCount );
172  }
173 
174  ~VkCtx()
175  {
176  tracy_free( m_res );
177  vkDestroyQueryPool( m_device, m_query, nullptr );
178  }
179 
180  void Collect( VkCommandBuffer cmdbuf )
181  {
183 
184  if( m_tail == m_head ) return;
185 
186 #ifdef TRACY_ON_DEMAND
187  if( !GetProfiler().IsConnected() )
188  {
189  vkCmdResetQueryPool( cmdbuf, m_query, 0, m_queryCount );
190  m_head = m_tail = 0;
191  int64_t tgpu;
192  if( m_timeDomain != VK_TIME_DOMAIN_DEVICE_EXT ) Calibrate( m_device, m_prevCalibration, tgpu );
193  return;
194  }
195 #endif
196 
197  unsigned int cnt;
198  if( m_oldCnt != 0 )
199  {
200  cnt = m_oldCnt;
201  m_oldCnt = 0;
202  }
203  else
204  {
205  cnt = m_head < m_tail ? m_queryCount - m_tail : m_head - m_tail;
206  }
207 
208  if( vkGetQueryPoolResults( m_device, m_query, m_tail, cnt, sizeof( int64_t ) * m_queryCount, m_res, sizeof( int64_t ), VK_QUERY_RESULT_64_BIT ) == VK_NOT_READY )
209  {
210  m_oldCnt = cnt;
211  return;
212  }
213 
214  for( unsigned int idx=0; idx<cnt; idx++ )
215  {
216  auto item = Profiler::QueueSerial();
217  MemWrite( &item->hdr.type, QueueType::GpuTime );
218  MemWrite( &item->gpuTime.gpuTime, m_res[idx] );
219  MemWrite( &item->gpuTime.queryId, uint16_t( m_tail + idx ) );
220  MemWrite( &item->gpuTime.context, m_context );
222  }
223 
224  if( m_timeDomain != VK_TIME_DOMAIN_DEVICE_EXT )
225  {
226  int64_t tgpu, tcpu;
227  Calibrate( m_device, tcpu, tgpu );
228  const auto refCpu = Profiler::GetTime();
229  const auto delta = tcpu - m_prevCalibration;
230  if( delta > 0 )
231  {
232  m_prevCalibration = tcpu;
233  auto item = Profiler::QueueSerial();
234  MemWrite( &item->hdr.type, QueueType::GpuCalibration );
235  MemWrite( &item->gpuCalibration.gpuTime, tgpu );
236  MemWrite( &item->gpuCalibration.cpuTime, refCpu );
237  MemWrite( &item->gpuCalibration.cpuDelta, delta );
238  MemWrite( &item->gpuCalibration.context, m_context );
240  }
241  }
242 
243  vkCmdResetQueryPool( cmdbuf, m_query, m_tail, cnt );
244 
245  m_tail += cnt;
246  if( m_tail == m_queryCount ) m_tail = 0;
247  }
248 
249 private:
250  tracy_force_inline unsigned int NextQueryId()
251  {
252  const auto id = m_head;
253  m_head = ( m_head + 1 ) % m_queryCount;
254  assert( m_head != m_tail );
255  return id;
256  }
257 
258  tracy_force_inline uint8_t GetId() const
259  {
260  return m_context;
261  }
262 
263  tracy_force_inline void Calibrate( VkDevice device, int64_t& tCpu, int64_t& tGpu )
264  {
265  assert( m_timeDomain != VK_TIME_DOMAIN_DEVICE_EXT );
266  VkCalibratedTimestampInfoEXT spec[2] = {
267  { VK_STRUCTURE_TYPE_CALIBRATED_TIMESTAMP_INFO_EXT, nullptr, VK_TIME_DOMAIN_DEVICE_EXT },
268  { VK_STRUCTURE_TYPE_CALIBRATED_TIMESTAMP_INFO_EXT, nullptr, m_timeDomain },
269  };
270  uint64_t ts[2];
271  uint64_t deviation;
272  do
273  {
274  m_vkGetCalibratedTimestampsEXT( device, 2, spec, ts, &deviation );
275  }
276  while( deviation > m_deviation );
277 
278 #if defined _WIN32 || defined __CYGWIN__
279  tGpu = ts[0];
280  tCpu = ts[1] * m_qpcToNs;
281 #else
282  assert( false );
283 #endif
284  }
285 
286  VkDevice m_device;
287  VkQueryPool m_query;
288  VkTimeDomainEXT m_timeDomain;
289  uint64_t m_deviation;
290  int64_t m_qpcToNs;
291  int64_t m_prevCalibration;
292  uint8_t m_context;
293 
294  unsigned int m_head;
295  unsigned int m_tail;
296  unsigned int m_oldCnt;
297  unsigned int m_queryCount;
298 
299  int64_t* m_res;
300 
301  PFN_vkGetCalibratedTimestampsEXT m_vkGetCalibratedTimestampsEXT;
302 };
303 
304 class VkCtxScope
305 {
306 public:
307  tracy_force_inline VkCtxScope( VkCtx* ctx, const SourceLocationData* srcloc, VkCommandBuffer cmdbuf, bool is_active )
308 #ifdef TRACY_ON_DEMAND
309  : m_active( is_active && GetProfiler().IsConnected() )
310 #else
311  : m_active( is_active )
312 #endif
313  {
314  if( !m_active ) return;
315  m_cmdbuf = cmdbuf;
316  m_ctx = ctx;
317 
318  const auto queryId = ctx->NextQueryId();
319  vkCmdWriteTimestamp( cmdbuf, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, ctx->m_query, queryId );
320 
321  auto item = Profiler::QueueSerial();
322  MemWrite( &item->hdr.type, QueueType::GpuZoneBeginSerial );
323  MemWrite( &item->gpuZoneBegin.cpuTime, Profiler::GetTime() );
324  MemWrite( &item->gpuZoneBegin.srcloc, (uint64_t)srcloc );
325  MemWrite( &item->gpuZoneBegin.thread, GetThreadHandle() );
326  MemWrite( &item->gpuZoneBegin.queryId, uint16_t( queryId ) );
327  MemWrite( &item->gpuZoneBegin.context, ctx->GetId() );
329  }
330 
331  tracy_force_inline VkCtxScope( VkCtx* ctx, const SourceLocationData* srcloc, VkCommandBuffer cmdbuf, int depth, bool is_active )
332 #ifdef TRACY_ON_DEMAND
333  : m_active( is_active && GetProfiler().IsConnected() )
334 #else
335  : m_active( is_active )
336 #endif
337  {
338  if( !m_active ) return;
339  m_cmdbuf = cmdbuf;
340  m_ctx = ctx;
341 
342  const auto queryId = ctx->NextQueryId();
343  vkCmdWriteTimestamp( cmdbuf, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, ctx->m_query, queryId );
344 
345  auto item = Profiler::QueueSerial();
346  MemWrite( &item->hdr.type, QueueType::GpuZoneBeginCallstackSerial );
347  MemWrite( &item->gpuZoneBegin.cpuTime, Profiler::GetTime() );
348  MemWrite( &item->gpuZoneBegin.srcloc, (uint64_t)srcloc );
349  MemWrite( &item->gpuZoneBegin.thread, GetThreadHandle() );
350  MemWrite( &item->gpuZoneBegin.queryId, uint16_t( queryId ) );
351  MemWrite( &item->gpuZoneBegin.context, ctx->GetId() );
353 
354  GetProfiler().SendCallstack( depth );
355  }
356 
357  tracy_force_inline ~VkCtxScope()
358  {
359  if( !m_active ) return;
360 
361  const auto queryId = m_ctx->NextQueryId();
362  vkCmdWriteTimestamp( m_cmdbuf, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, m_ctx->m_query, queryId );
363 
364  auto item = Profiler::QueueSerial();
365  MemWrite( &item->hdr.type, QueueType::GpuZoneEndSerial );
366  MemWrite( &item->gpuZoneEnd.cpuTime, Profiler::GetTime() );
367  MemWrite( &item->gpuZoneEnd.thread, GetThreadHandle() );
368  MemWrite( &item->gpuZoneEnd.queryId, uint16_t( queryId ) );
369  MemWrite( &item->gpuZoneEnd.context, m_ctx->GetId() );
371  }
372 
373 private:
374  const bool m_active;
375 
376  VkCommandBuffer m_cmdbuf;
377  VkCtx* m_ctx;
378 };
379 
380 static inline VkCtx* CreateVkContext( VkPhysicalDevice physdev, VkDevice device, VkQueue queue, VkCommandBuffer cmdbuf, PFN_vkGetPhysicalDeviceCalibrateableTimeDomainsEXT gpdctd, PFN_vkGetCalibratedTimestampsEXT gct )
381 {
383  auto ctx = (VkCtx*)tracy_malloc( sizeof( VkCtx ) );
384  new(ctx) VkCtx( physdev, device, queue, cmdbuf, gpdctd, gct );
385  return ctx;
386 }
387 
388 static inline void DestroyVkContext( VkCtx* ctx )
389 {
390  ctx->~VkCtx();
391  tracy_free( ctx );
392 }
393 
394 }
395 
396 using TracyVkCtx = tracy::VkCtx*;
397 
398 #define TracyVkContext( physdev, device, queue, cmdbuf ) tracy::CreateVkContext( physdev, device, queue, cmdbuf, nullptr, nullptr );
399 #define TracyVkContextCalibrated( physdev, device, queue, cmdbuf, gpdctd, gct ) tracy::CreateVkContext( physdev, device, queue, cmdbuf, gpdctd, gct );
400 #define TracyVkDestroy( ctx ) tracy::DestroyVkContext( ctx );
401 #if defined TRACY_HAS_CALLSTACK && defined TRACY_CALLSTACK
402 # define TracyVkNamedZone( ctx, varname, cmdbuf, name, active ) static constexpr tracy::SourceLocationData TracyConcat(__tracy_gpu_source_location,__LINE__) { name, __FUNCTION__, __FILE__, (uint32_t)__LINE__, 0 }; tracy::VkCtxScope varname( ctx, &TracyConcat(__tracy_gpu_source_location,__LINE__), cmdbuf, TRACY_CALLSTACK, active );
403 # define TracyVkNamedZoneC( ctx, varname, cmdbuf, name, color, active ) static constexpr tracy::SourceLocationData TracyConcat(__tracy_gpu_source_location,__LINE__) { name, __FUNCTION__, __FILE__, (uint32_t)__LINE__, color }; tracy::VkCtxScope varname( ctx, &TracyConcat(__tracy_gpu_source_location,__LINE__), cmdbuf, TRACY_CALLSTACK, active );
404 # define TracyVkZone( ctx, cmdbuf, name ) TracyVkNamedZoneS( ctx, ___tracy_gpu_zone, cmdbuf, name, TRACY_CALLSTACK, true )
405 # define TracyVkZoneC( ctx, cmdbuf, name, color ) TracyVkNamedZoneCS( ctx, ___tracy_gpu_zone, cmdbuf, name, color, TRACY_CALLSTACK, true )
406 #else
407 # define TracyVkNamedZone( ctx, varname, cmdbuf, name, active ) static constexpr tracy::SourceLocationData TracyConcat(__tracy_gpu_source_location,__LINE__) { name, __FUNCTION__, __FILE__, (uint32_t)__LINE__, 0 }; tracy::VkCtxScope varname( ctx, &TracyConcat(__tracy_gpu_source_location,__LINE__), cmdbuf, active );
408 # define TracyVkNamedZoneC( ctx, varname, cmdbuf, name, color, active ) static constexpr tracy::SourceLocationData TracyConcat(__tracy_gpu_source_location,__LINE__) { name, __FUNCTION__, __FILE__, (uint32_t)__LINE__, color }; tracy::VkCtxScope varname( ctx, &TracyConcat(__tracy_gpu_source_location,__LINE__), cmdbuf, active );
409 # define TracyVkZone( ctx, cmdbuf, name ) TracyVkNamedZone( ctx, ___tracy_gpu_zone, cmdbuf, name, true )
410 # define TracyVkZoneC( ctx, cmdbuf, name, color ) TracyVkNamedZoneC( ctx, ___tracy_gpu_zone, cmdbuf, name, color, true )
411 #endif
412 #define TracyVkCollect( ctx, cmdbuf ) ctx->Collect( cmdbuf );
413 
414 #ifdef TRACY_HAS_CALLSTACK
415 # define TracyVkNamedZoneS( ctx, varname, cmdbuf, name, depth, active ) static constexpr tracy::SourceLocationData TracyConcat(__tracy_gpu_source_location,__LINE__) { name, __FUNCTION__, __FILE__, (uint32_t)__LINE__, 0 }; tracy::VkCtxScope varname( ctx, &TracyConcat(__tracy_gpu_source_location,__LINE__), cmdbuf, depth, active );
416 # define TracyVkNamedZoneCS( ctx, varname, cmdbuf, name, color, depth, active ) static constexpr tracy::SourceLocationData TracyConcat(__tracy_gpu_source_location,__LINE__) { name, __FUNCTION__, __FILE__, (uint32_t)__LINE__, color }; tracy::VkCtxScope varname( ctx, &TracyConcat(__tracy_gpu_source_location,__LINE__), cmdbuf, depth, active );
417 # define TracyVkZoneS( ctx, cmdbuf, name, depth ) TracyVkNamedZoneS( ctx, ___tracy_gpu_zone, cmdbuf, name, depth, true )
418 # define TracyVkZoneCS( ctx, cmdbuf, name, color, depth ) TracyVkNamedZoneCS( ctx, ___tracy_gpu_zone, cmdbuf, name, color, depth, true )
419 #else
420 # define TracyVkNamedZoneS( ctx, varname, cmdbuf, name, depth, active ) TracyVkNamedZone( ctx, varname, cmdbuf, name, active )
421 # define TracyVkNamedZoneCS( ctx, varname, cmdbuf, name, color, depth, active ) TracyVkNamedZoneC( ctx, varname, cmdbuf, name, color, active )
422 # define TracyVkZoneS( ctx, cmdbuf, name, depth ) TracyVkZone( ctx, cmdbuf, name )
423 # define TracyVkZoneCS( ctx, cmdbuf, name, color, depth ) TracyVkZoneC( ctx, cmdbuf, name, color )
424 #endif
425 
426 #endif
427 
428 #endif


Copyright © 2005-2021 MAK Technologies. All Rights Reserved (www.mak.com)