| // Copyright 2020 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "cc/raster/raster_query_queue.h" |
| |
| #include <utility> |
| |
| #include "base/strings/stringprintf.h" |
| #include "cc/base/histograms.h" |
| #include "components/viz/common/gpu/raster_context_provider.h" |
| #include "gpu/GLES2/gl2extchromium.h" |
| #include "gpu/command_buffer/client/raster_interface.h" |
| |
| namespace cc { |
| |
| RasterQuery::RasterQuery() = default; |
| |
| RasterQuery::~RasterQuery() = default; |
| |
| RasterQueryQueue::RasterQueryQueue( |
| viz::RasterContextProvider* const worker_context_provider, |
| bool oop_rasterization_enabled) |
| : worker_context_provider_(worker_context_provider), |
| oop_rasterization_enabled_(oop_rasterization_enabled) {} |
| |
| RasterQueryQueue::~RasterQueryQueue() = default; |
| |
| void RasterQueryQueue::Append(RasterQuery raster_query) { |
| // It is important for this method to not be called with the raster context |
| // lock to avoid a deadlock in CheckRasterFinishedQueries, which acquired |
| // the raster context lock while holding this lock. |
| base::AutoLock hold(pending_raster_queries_lock_); |
| pending_raster_queries_.push_back(std::move(raster_query)); |
| } |
| |
| #define UMA_HISTOGRAM_RASTER_TIME_CUSTOM_MICROSECONDS(name, total_time) \ |
| UMA_HISTOGRAM_CUSTOM_MICROSECONDS_TIMES( \ |
| name, total_time, base::Microseconds(1), base::Milliseconds(100), 100); |
| |
| bool RasterQueryQueue::CheckRasterFinishedQueries() { |
| base::AutoLock hold(pending_raster_queries_lock_); |
| if (pending_raster_queries_.empty()) |
| return false; |
| |
| viz::RasterContextProvider::ScopedRasterContextLock scoped_context( |
| worker_context_provider_); |
| auto* ri = scoped_context.RasterInterface(); |
| |
| auto it = pending_raster_queries_.begin(); |
| while (it != pending_raster_queries_.end()) { |
| GLuint complete = 0; |
| ri->GetQueryObjectuivEXT(it->raster_duration_query_id, |
| GL_QUERY_RESULT_AVAILABLE_NO_FLUSH_CHROMIUM_EXT, |
| &complete); |
| if (!complete) |
| break; |
| |
| #if DCHECK_IS_ON() |
| if (it->raster_start_query_id) { |
| // We issued the GL_COMMANDS_ISSUED_TIMESTAMP_CHROMIUM query prior to the |
| // GL_COMMANDS_ISSUED_CHROMIUM query. Therefore, if the result of the |
| // latter is available, the result of the former should be too. |
| complete = 0; |
| ri->GetQueryObjectuivEXT(it->raster_start_query_id, |
| GL_QUERY_RESULT_AVAILABLE_NO_FLUSH_CHROMIUM_EXT, |
| &complete); |
| DCHECK(complete); |
| } |
| #endif |
| |
| GLuint gpu_raster_duration = 0u; |
| ri->GetQueryObjectuivEXT(it->raster_duration_query_id, GL_QUERY_RESULT_EXT, |
| &gpu_raster_duration); |
| ri->DeleteQueriesEXT(1, &it->raster_duration_query_id); |
| |
| base::TimeDelta raster_duration = |
| it->worker_raster_duration + base::Microseconds(gpu_raster_duration); |
| |
| // It is safe to use the UMA macros here with runtime generated strings |
| // because the client name should be initialized once in the process, before |
| // recording any metrics here. |
| const char* client_name = GetClientNameForMetrics(); |
| |
| if (it->raster_start_query_id) { |
| GLuint64 gpu_raster_start_time = 0u; |
| ri->GetQueryObjectui64vEXT(it->raster_start_query_id, GL_QUERY_RESULT_EXT, |
| &gpu_raster_start_time); |
| ri->DeleteQueriesEXT(1, &it->raster_start_query_id); |
| |
| // The base::checked_cast<int64_t> should not crash as long as the GPU |
| // process was not compromised: that's because the result of the query |
| // should have been generated using base::TimeDelta::InMicroseconds() |
| // there, so the result should fit in an int64_t. |
| base::TimeDelta raster_scheduling_delay = |
| base::Microseconds( |
| base::checked_cast<int64_t>(gpu_raster_start_time)) - |
| it->raster_buffer_creation_time.since_origin(); |
| |
| // We expect the clock we're using to be monotonic, so we shouldn't get a |
| // negative scheduling delay. |
| DCHECK_GE(raster_scheduling_delay.InMicroseconds(), 0u); |
| UMA_HISTOGRAM_RASTER_TIME_CUSTOM_MICROSECONDS( |
| base::StringPrintf( |
| "Renderer4.%s.RasterTaskSchedulingDelayNoAtRasterDecodes.All", |
| client_name), |
| raster_scheduling_delay); |
| if (it->depends_on_hardware_accelerated_jpeg_candidates) { |
| UMA_HISTOGRAM_RASTER_TIME_CUSTOM_MICROSECONDS( |
| base::StringPrintf( |
| "Renderer4.%s.RasterTaskSchedulingDelayNoAtRasterDecodes." |
| "TilesWithJpegHwDecodeCandidates", |
| client_name), |
| raster_scheduling_delay); |
| } |
| if (it->depends_on_hardware_accelerated_webp_candidates) { |
| UMA_HISTOGRAM_RASTER_TIME_CUSTOM_MICROSECONDS( |
| base::StringPrintf( |
| "Renderer4.%s.RasterTaskSchedulingDelayNoAtRasterDecodes." |
| "TilesWithWebPHwDecodeCandidates", |
| client_name), |
| raster_scheduling_delay); |
| } |
| } |
| |
| if (oop_rasterization_enabled_) { |
| UMA_HISTOGRAM_RASTER_TIME_CUSTOM_MICROSECONDS( |
| base::StringPrintf("Renderer4.%s.RasterTaskTotalDuration.Oop", |
| client_name), |
| raster_duration); |
| } else { |
| UMA_HISTOGRAM_RASTER_TIME_CUSTOM_MICROSECONDS( |
| base::StringPrintf("Renderer4.%s.RasterTaskTotalDuration.Gpu", |
| client_name), |
| raster_duration); |
| } |
| |
| it = pending_raster_queries_.erase(it); |
| } |
| |
| return pending_raster_queries_.size() > 0u; |
| } |
| |
| } // namespace cc |