|
| 1 | +// Copyright 2013 The Flutter Authors. All rights reserved. |
| 2 | +// Use of this source code is governed by a BSD-style license that can be |
| 3 | +// found in the LICENSE file. |
| 4 | + |
| 5 | +#include "impeller/renderer/backend/gles/gpu_tracer_gles.h" |
| 6 | +#include <thread> |
| 7 | +#include "fml/trace_event.h" |
| 8 | + |
| 9 | +namespace impeller { |
| 10 | + |
| 11 | +GPUTracerGLES::GPUTracerGLES(const ProcTableGLES& gl, bool enable_tracing) { |
| 12 | +#ifdef IMPELLER_DEBUG |
| 13 | + auto desc = gl.GetDescription(); |
| 14 | + enabled_ = |
| 15 | + enable_tracing && desc->HasExtension("GL_EXT_disjoint_timer_query"); |
| 16 | +#endif // IMPELLER_DEBUG |
| 17 | +} |
| 18 | + |
| 19 | +void GPUTracerGLES::MarkFrameStart(const ProcTableGLES& gl) { |
| 20 | + if (!enabled_ || active_frame_.has_value() || |
| 21 | + std::this_thread::get_id() != raster_thread_) { |
| 22 | + return; |
| 23 | + } |
| 24 | + |
| 25 | + // At the beginning of a frame, check the status of all pending |
| 26 | + // previous queries. |
| 27 | + ProcessQueries(gl); |
| 28 | + |
| 29 | + uint32_t query = 0; |
| 30 | + gl.GenQueriesEXT(1, &query); |
| 31 | + if (query == 0) { |
| 32 | + return; |
| 33 | + } |
| 34 | + |
| 35 | + active_frame_ = query; |
| 36 | + gl.BeginQueryEXT(GL_TIME_ELAPSED_EXT, query); |
| 37 | +} |
| 38 | + |
| 39 | +void GPUTracerGLES::RecordRasterThread() { |
| 40 | + raster_thread_ = std::this_thread::get_id(); |
| 41 | +} |
| 42 | + |
| 43 | +void GPUTracerGLES::ProcessQueries(const ProcTableGLES& gl) { |
| 44 | + // For reasons unknown to me, querying the state of more than |
| 45 | + // one query object per frame causes crashes on a Pixel 6 pro. |
| 46 | + // It does not crash on an S10. |
| 47 | + while (!pending_traces_.empty()) { |
| 48 | + auto query = pending_traces_.front(); |
| 49 | + |
| 50 | + // First check if the query is complete without blocking |
| 51 | + // on the result. Incomplete results are left in the pending |
| 52 | + // trace vector and will not be checked again for another |
| 53 | + // frame. |
| 54 | + GLuint available = GL_FALSE; |
| 55 | + gl.GetQueryObjectuivEXT(query, GL_QUERY_RESULT_AVAILABLE_EXT, &available); |
| 56 | + |
| 57 | + if (available != GL_TRUE) { |
| 58 | + // If a query is not available, then all subsequent queries will be |
| 59 | + // unavailable. |
| 60 | + return; |
| 61 | + } |
| 62 | + // Return the timer resolution in nanoseconds. |
| 63 | + uint64_t duration = 0; |
| 64 | + gl.GetQueryObjectui64vEXT(query, GL_QUERY_RESULT_EXT, &duration); |
| 65 | + auto gpu_ms = duration / 1000000.0; |
| 66 | + |
| 67 | + FML_TRACE_COUNTER("flutter", "GPUTracer", |
| 68 | + reinterpret_cast<int64_t>(this), // Trace Counter ID |
| 69 | + "FrameTimeMS", gpu_ms); |
| 70 | + gl.DeleteQueriesEXT(1, &query); |
| 71 | + pending_traces_.pop_front(); |
| 72 | + } |
| 73 | +} |
| 74 | + |
| 75 | +void GPUTracerGLES::MarkFrameEnd(const ProcTableGLES& gl) { |
| 76 | + if (!enabled_ || std::this_thread::get_id() != raster_thread_ || |
| 77 | + !active_frame_.has_value()) { |
| 78 | + return; |
| 79 | + } |
| 80 | + |
| 81 | + auto query = active_frame_.value(); |
| 82 | + gl.EndQueryEXT(GL_TIME_ELAPSED_EXT); |
| 83 | + |
| 84 | + pending_traces_.push_back(query); |
| 85 | + active_frame_ = std::nullopt; |
| 86 | +} |
| 87 | + |
| 88 | +} // namespace impeller |
0 commit comments