diff --git a/src/freedreno/vulkan/tu_drm.c b/src/freedreno/vulkan/tu_drm.c index c3b18e5a8b6..93307300a3c 100644 --- a/src/freedreno/vulkan/tu_drm.c +++ b/src/freedreno/vulkan/tu_drm.c @@ -120,6 +120,13 @@ tu_device_get_gpu_timestamp(struct tu_device *dev, uint64_t *ts) return tu_drm_get_param(dev->physical_device, MSM_PARAM_TIMESTAMP, ts); } +int +tu_device_get_suspend_count(struct tu_device *dev, uint64_t *suspend_count) +{ + int ret = tu_drm_get_param(dev->physical_device, MSM_PARAM_SUSPENDS, suspend_count); + return ret; +} + int tu_drm_submitqueue_new(const struct tu_device *dev, int priority, diff --git a/src/freedreno/vulkan/tu_kgsl.c b/src/freedreno/vulkan/tu_kgsl.c index e198947aa3e..e93e04d8a6a 100644 --- a/src/freedreno/vulkan/tu_kgsl.c +++ b/src/freedreno/vulkan/tu_kgsl.c @@ -663,6 +663,14 @@ tu_device_get_gpu_timestamp(struct tu_device *dev, uint64_t *ts) return 0; } +int +tu_device_get_suspend_count(struct tu_device *dev, uint64_t *suspend_count) +{ + /* kgsl doesn't have a way to get it */ + *suspend_count = 0; + return 0; +} + #ifdef ANDROID VKAPI_ATTR VkResult VKAPI_CALL tu_QueueSignalReleaseImageANDROID(VkQueue _queue, diff --git a/src/freedreno/vulkan/tu_perfetto.cc b/src/freedreno/vulkan/tu_perfetto.cc index 7e72bc999af..9973e6300ef 100644 --- a/src/freedreno/vulkan/tu_perfetto.cc +++ b/src/freedreno/vulkan/tu_perfetto.cc @@ -43,6 +43,11 @@ static uint64_t next_clock_sync_ns; /* cpu time of next clk sync */ */ static uint64_t sync_gpu_ts; +static uint64_t last_suspend_count; + +static uint64_t gpu_max_timestamp; +static uint64_t gpu_timestamp_offset; + struct TuRenderpassIncrementalState { bool was_cleared = true; }; @@ -73,6 +78,10 @@ public: */ gpu_clock_id = _mesa_hash_string("org.freedesktop.mesa.freedreno") | 0x80000000; + + gpu_timestamp_offset = 0; + gpu_max_timestamp = 0; + last_suspend_count = 0; } void OnStop(const StopArgs &) override @@ -156,7 +165,9 @@ stage_end(struct tu_device *dev, uint64_t ts_ns, enum tu_stage_id stage, auto packet = tctx.NewTracePacket(); - packet->set_timestamp(p->start_ts[stage]); + gpu_max_timestamp = MAX2(gpu_max_timestamp, ts_ns + gpu_timestamp_offset); + + packet->set_timestamp(p->start_ts[stage] + gpu_timestamp_offset); packet->set_timestamp_clock_id(gpu_clock_id); auto event = packet->set_gpu_render_stage_event(); @@ -201,9 +212,39 @@ sync_timestamp(struct tu_device *dev) return; } + uint64_t current_suspend_count = 0; + /* If we fail to get it we will use a fallback */ + tu_device_get_suspend_count(dev, ¤t_suspend_count); + /* convert GPU ts into ns: */ gpu_ts = tu_device_ticks_to_ns(dev, gpu_ts); + /* GPU timestamp is being reset after suspend-resume cycle. + * Perfetto requires clock snapshots to be monotonic, + * so we have to fix-up the time. + */ + if (current_suspend_count != last_suspend_count) { + gpu_timestamp_offset = gpu_max_timestamp; + last_suspend_count = current_suspend_count; + } + + gpu_ts += gpu_timestamp_offset; + + /* Fallback check, detect non-monotonic cases which would happen + * if we cannot retrieve suspend count. + */ + if (sync_gpu_ts > gpu_ts) { + gpu_ts += (gpu_max_timestamp - gpu_timestamp_offset); + gpu_timestamp_offset = gpu_max_timestamp; + } + + if (sync_gpu_ts > gpu_ts) { + PERFETTO_ELOG("Non-monotonic gpu timestamp detected, bailing out"); + return; + } + + gpu_max_timestamp = gpu_ts; + TuRenderpassDataSource::Trace([=](TuRenderpassDataSource::TraceContext tctx) { auto packet = tctx.NewTracePacket(); diff --git a/src/freedreno/vulkan/tu_perfetto.h b/src/freedreno/vulkan/tu_perfetto.h index a78dd7b7d44..3fa3ab63f72 100644 --- a/src/freedreno/vulkan/tu_perfetto.h +++ b/src/freedreno/vulkan/tu_perfetto.h @@ -100,6 +100,10 @@ int tu_device_get_gpu_timestamp(struct tu_device *dev, uint64_t *ts); +int +tu_device_get_suspend_count(struct tu_device *dev, + uint64_t *suspend_count); + uint64_t tu_device_ticks_to_ns(struct tu_device *dev, uint64_t ts); diff --git a/src/freedreno/vulkan/tu_private.h b/src/freedreno/vulkan/tu_private.h index 9a6d86ec144..eddcffda0c1 100644 --- a/src/freedreno/vulkan/tu_private.h +++ b/src/freedreno/vulkan/tu_private.h @@ -1731,6 +1731,10 @@ int tu_device_get_gpu_timestamp(struct tu_device *dev, uint64_t *ts); +int +tu_device_get_suspend_count(struct tu_device *dev, + uint64_t *suspend_count); + int tu_drm_submitqueue_new(const struct tu_device *dev, int priority,