OSDN Git Service

Merge "Fix query management in GpuProfiler" into oc-dev
authorSteven Thomas <steventhomas@google.com>
Tue, 18 Apr 2017 22:43:22 +0000 (22:43 +0000)
committerandroid-build-merger <android-build-merger@google.com>
Tue, 18 Apr 2017 22:43:22 +0000 (22:43 +0000)
am: 511544f212

Change-Id: I854ef8bf9424a06b36e98315237868d4263f0ce2

libs/vr/libdvrgraphics/gpu_profiler.cpp
libs/vr/libdvrgraphics/include/private/dvr/graphics/gpu_profiler.h
libs/vr/libvrflinger/compositor.cpp

index 49c515f..c8c978d 100644 (file)
@@ -7,6 +7,12 @@
 namespace android {
 namespace dvr {
 
+namespace {
+
+constexpr int kMaxPendingQueries = 32;
+
+}  // anonynmous namespace
+
 static int64_t AdjustTimerQueryToNs(int64_t gpu_time) { return gpu_time; }
 
 void GpuProfiler::TimerData::reset() {
@@ -21,6 +27,7 @@ void GpuProfiler::TimerData::print(const char* name) const {
 
 // Enter a scope, records the timestamp for later matching with leave.
 void GpuProfiler::TimerData::enter(int64_t timestamp_ns) {
+  entered = true;
   enter_timestamp_ns = timestamp_ns;
 }
 
@@ -28,6 +35,15 @@ void GpuProfiler::TimerData::enter(int64_t timestamp_ns) {
 void GpuProfiler::TimerData::leave(int64_t timestamp_ns, const char* name,
                                    std::weak_ptr<int64_t> duration_ns,
                                    int print_period) {
+  if (!entered) {
+    // We got the leave event but are missing the enter. This can happen if
+    // OnPendingQueryOverflow() is called, or if the calls to enter()/leave()
+    // aren't properly balanced. Ignore the call but print a warning.
+    ALOGW("Ignoring GpuProfiler::TimerData::leave event with no enter event");
+    return;
+  }
+  entered = false;
+
   int64_t elapsed = timestamp_ns - enter_timestamp_ns;
   if (elapsed > 1000 * 1000 * 1000) {
     // More than one second, drop it as invalid data.
@@ -50,12 +66,12 @@ GpuProfiler* GpuProfiler::Get() {
 
 GpuProfiler::GpuProfiler()
     : enable_gpu_tracing_(true),
+      has_gl_context_(false),
       sync_with_cpu_time_(false),
       gl_timer_offset_ns_(0) {
-  SyncGlTimebase();
 }
 
-GpuProfiler::~GpuProfiler() {}
+GpuProfiler::~GpuProfiler() { Clear(); }
 
 bool GpuProfiler::IsGpuProfilingSupported() const {
   // TODO(jbates) check for GL_EXT_disjoint_timer_query
@@ -63,6 +79,9 @@ bool GpuProfiler::IsGpuProfilingSupported() const {
 }
 
 GLuint GpuProfiler::TryAllocateGlQueryId() {
+  if (pending_gpu_queries_.size() >= kMaxPendingQueries)
+    OnPendingQueryOverflow();
+
   GLuint query_id = 0;
   if (gl_timer_query_id_pool_.empty()) {
     glGenQueries(1, &query_id);
@@ -95,6 +114,35 @@ void GpuProfiler::LeaveGlScope(const char* scope_name,
   }
 }
 
+void GpuProfiler::OnGlContextCreated() {
+  has_gl_context_ = true;
+  gl_timer_offset_ns_ = 0;
+  SyncGlTimebase();
+}
+
+void GpuProfiler::OnGlContextDestroyed() {
+  has_gl_context_ = false;
+  Clear();
+}
+
+void GpuProfiler::Clear() {
+  events_.clear();
+  for (auto& query : pending_gpu_queries_)
+    glDeleteQueries(1, &query.query_id);
+  pending_gpu_queries_.clear();
+  while (!gl_timer_query_id_pool_.empty()) {
+    GLuint id = gl_timer_query_id_pool_.top();
+    gl_timer_query_id_pool_.pop();
+    glDeleteQueries(1, &id);
+  }
+}
+
+void GpuProfiler::OnPendingQueryOverflow() {
+  ALOGW("Reached limit of %d pending queries in GpuProfiler."
+        " Clearing all queries.", kMaxPendingQueries);
+  Clear();
+}
+
 void GpuProfiler::SyncGlTimebase() {
   if (!sync_with_cpu_time_) {
     return;
index 2905d00..c6e752b 100644 (file)
@@ -38,7 +38,7 @@ class GpuProfiler {
   // one of the TRACE_GPU* macros defined below.
   void SetEnableGpuTracing(bool enabled) { enable_gpu_tracing_ = enabled; }
 
-  bool enabled() const { return enable_gpu_tracing_; }
+  bool enabled() const { return enable_gpu_tracing_ && has_gl_context_; }
 
   // Attempt to keep the GPU times in sync with CPU times.
   void SetEnableSyncCpuTime(bool enabled) { sync_with_cpu_time_ = enabled; }
@@ -62,6 +62,14 @@ class GpuProfiler {
   void LeaveGlScope(const char* scope_name, std::weak_ptr<int64_t> duration_ns,
                     int print_period);
 
+  // Must be called when the GL context is created. The GpuProfiler will be
+  // inactive until this is called.
+  void OnGlContextCreated();
+
+  // Must be called before the GL context is destroyed. The GpuProfiler will be
+  // inactive until a call to OnGlContextCreated().
+  void OnGlContextDestroyed();
+
  private:
   // Data to queue the pending GPU timer queries that need to be polled
   // for completion.
@@ -105,11 +113,20 @@ class GpuProfiler {
     void leave(int64_t timestamp_ns, const char* name,
                std::weak_ptr<int64_t> duration_ns, int print_period);
 
+    bool entered = false;
     int64_t total_elapsed_ns = 0;
     int64_t enter_timestamp_ns = 0;
     int num_events = 0;
   };
 
+  // Clear out events and free GL resources.
+  void Clear();
+
+  // Called when we detect that we've overflowed the pending query queue. This
+  // shouldn't occur in practice, and probably indicates some internal
+  // mismanagement of the gl query objects.
+  void OnPendingQueryOverflow();
+
   // Synchronises the GL timebase with the CallTraceManager timebase.
   void SyncGlTimebase();
 
@@ -119,6 +136,10 @@ class GpuProfiler {
   // Setting for enabling GPU tracing.
   bool enable_gpu_tracing_;
 
+  // True if we have a GL context, false otherwise. When the GpuProfiler is
+  // first created we assume no GL context.
+  bool has_gl_context_;
+
   // Setting for synchronizing GPU timestamps with CPU time.
   bool sync_with_cpu_time_;
 
index aa01f22..07e4a8b 100644 (file)
@@ -403,6 +403,7 @@ bool Compositor::InitializeEGL() {
   }
 
   load_gl_extensions();
+  GpuProfiler::Get()->OnGlContextCreated();
 
   glEnable(BINNING_CONTROL_HINT_QCOM);
   glHint(BINNING_CONTROL_HINT_QCOM, RENDER_DIRECT_TO_FRAMEBUFFER_QCOM);
@@ -438,6 +439,7 @@ void Compositor::Shutdown() {
   eds_renderer_.reset();
 
   if (context_) {
+    GpuProfiler::Get()->OnGlContextDestroyed();
     eglDestroyContext(display_, context_);
     context_ = 0;
   }