1 // Copyright 2015 The Chromium 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 "ui/gl/angle_platform_impl.h"
6 
7 #include "base/base64.h"
8 #include "base/bind.h"
9 #include "base/callback.h"
10 #include "base/compiler_specific.h"
11 #include "base/lazy_instance.h"
12 #include "base/metrics/histogram.h"
13 #include "base/metrics/histogram_functions.h"
14 #include "base/task/post_task.h"
15 #include "base/task/thread_pool/thread_pool_instance.h"
16 #include "base/trace_event/trace_event.h"
17 #include "third_party/angle/include/platform/PlatformMethods.h"
18 #include "ui/gl/gl_bindings.h"
19 
20 namespace angle {
21 
22 namespace {
23 
24 ResetDisplayPlatformFunc g_angle_reset_platform = nullptr;
25 
ANGLEPlatformImpl_currentTime(PlatformMethods * platform)26 double ANGLEPlatformImpl_currentTime(PlatformMethods* platform) {
27   return base::Time::Now().ToDoubleT();
28 }
29 
ANGLEPlatformImpl_monotonicallyIncreasingTime(PlatformMethods * platform)30 double ANGLEPlatformImpl_monotonicallyIncreasingTime(
31     PlatformMethods* platform) {
32   return (base::TimeTicks::Now() - base::TimeTicks()).InSecondsF();
33 }
34 
ANGLEPlatformImpl_getTraceCategoryEnabledFlag(PlatformMethods * platform,const char * category_group)35 const unsigned char* ANGLEPlatformImpl_getTraceCategoryEnabledFlag(
36     PlatformMethods* platform,
37     const char* category_group) {
38   return TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED(category_group);
39 }
40 
ANGLEPlatformImpl_logError(PlatformMethods * platform,const char * errorMessage)41 void ANGLEPlatformImpl_logError(PlatformMethods* platform,
42                                 const char* errorMessage) {
43   LOG(ERROR) << errorMessage;
44 }
45 
ANGLEPlatformImpl_logWarning(PlatformMethods * platform,const char * warningMessage)46 void ANGLEPlatformImpl_logWarning(PlatformMethods* platform,
47                                   const char* warningMessage) {
48   LOG(WARNING) << warningMessage;
49 }
50 
ANGLEPlatformImpl_addTraceEvent(PlatformMethods * platform,char phase,const unsigned char * category_group_enabled,const char * name,unsigned long long id,double timestamp,int num_args,const char ** arg_names,const unsigned char * arg_types,const unsigned long long * arg_values,unsigned char flags)51 TraceEventHandle ANGLEPlatformImpl_addTraceEvent(
52     PlatformMethods* platform,
53     char phase,
54     const unsigned char* category_group_enabled,
55     const char* name,
56     unsigned long long id,
57     double timestamp,
58     int num_args,
59     const char** arg_names,
60     const unsigned char* arg_types,
61     const unsigned long long* arg_values,
62     unsigned char flags) {
63   base::TimeTicks timestamp_tt =
64       base::TimeTicks() + base::TimeDelta::FromSecondsD(timestamp);
65   base::trace_event::TraceArguments args(num_args, arg_names, arg_types,
66                                          arg_values);
67   base::trace_event::TraceEventHandle handle =
68       TRACE_EVENT_API_ADD_TRACE_EVENT_WITH_THREAD_ID_AND_TIMESTAMP(
69           phase, category_group_enabled, name,
70           trace_event_internal::kGlobalScope, id, trace_event_internal::kNoId,
71           base::PlatformThread::CurrentId(), timestamp_tt, &args, flags);
72   TraceEventHandle result;
73   memcpy(&result, &handle, sizeof(result));
74   return result;
75 }
76 
ANGLEPlatformImpl_updateTraceEventDuration(PlatformMethods * platform,const unsigned char * category_group_enabled,const char * name,TraceEventHandle handle)77 void ANGLEPlatformImpl_updateTraceEventDuration(
78     PlatformMethods* platform,
79     const unsigned char* category_group_enabled,
80     const char* name,
81     TraceEventHandle handle) {
82   base::trace_event::TraceEventHandle trace_event_handle;
83   memcpy(&trace_event_handle, &handle, sizeof(handle));
84   TRACE_EVENT_API_UPDATE_TRACE_EVENT_DURATION(category_group_enabled, name,
85                                               trace_event_handle);
86 }
87 
ANGLEPlatformImpl_histogramCustomCounts(PlatformMethods * platform,const char * name,int sample,int min,int max,int bucket_count)88 void ANGLEPlatformImpl_histogramCustomCounts(PlatformMethods* platform,
89                                              const char* name,
90                                              int sample,
91                                              int min,
92                                              int max,
93                                              int bucket_count) {
94   // Copied from histogram macro, but without the static variable caching
95   // the histogram because name is dynamic.
96   base::HistogramBase* counter = base::Histogram::FactoryGet(
97       name, min, max, bucket_count,
98       base::HistogramBase::kUmaTargetedHistogramFlag);
99   counter->Add(sample);
100 }
101 
ANGLEPlatformImpl_histogramEnumeration(PlatformMethods * platform,const char * name,int sample,int boundary_value)102 void ANGLEPlatformImpl_histogramEnumeration(PlatformMethods* platform,
103                                             const char* name,
104                                             int sample,
105                                             int boundary_value) {
106   // Copied from histogram macro, but without the static variable caching
107   // the histogram because name is dynamic.
108   base::HistogramBase* counter = base::LinearHistogram::FactoryGet(
109       name, 1, boundary_value, boundary_value + 1,
110       base::HistogramBase::kUmaTargetedHistogramFlag);
111   counter->Add(sample);
112 }
113 
ANGLEPlatformImpl_histogramSparse(PlatformMethods * platform,const char * name,int sample)114 void ANGLEPlatformImpl_histogramSparse(PlatformMethods* platform,
115                                        const char* name,
116                                        int sample) {
117   base::UmaHistogramSparse(name, sample);
118 }
119 
ANGLEPlatformImpl_histogramBoolean(PlatformMethods * platform,const char * name,bool sample)120 void ANGLEPlatformImpl_histogramBoolean(PlatformMethods* platform,
121                                         const char* name,
122                                         bool sample) {
123   ANGLEPlatformImpl_histogramEnumeration(platform, name, sample ? 1 : 0, 2);
124 }
125 
126 NO_SANITIZE("cfi-icall")
AnglePlatformImpl_runWorkerTask(PostWorkerTaskCallback callback,void * user_data)127 void AnglePlatformImpl_runWorkerTask(PostWorkerTaskCallback callback, void* user_data) {
128   TRACE_EVENT0("toplevel", "ANGLEPlatformImpl::RunWorkerTask");
129   callback(user_data);
130 }
131 
ANGLEPlatformImpl_postWorkerTask(PlatformMethods * platform,PostWorkerTaskCallback callback,void * user_data)132 void ANGLEPlatformImpl_postWorkerTask(PlatformMethods* platform,
133                                       PostWorkerTaskCallback callback,
134                                       void* user_data) {
135   base::ThreadPool::PostTask(
136       FROM_HERE, {base::TaskPriority::USER_VISIBLE},
137       base::BindOnce(&AnglePlatformImpl_runWorkerTask, callback, user_data));
138 }
139 
140 }  // anonymous namespace
141 
142 NO_SANITIZE("cfi-icall")
InitializePlatform(EGLDisplay display)143 bool InitializePlatform(EGLDisplay display) {
144   GetDisplayPlatformFunc angle_get_platform =
145       reinterpret_cast<GetDisplayPlatformFunc>(
146           eglGetProcAddress("ANGLEGetDisplayPlatform"));
147   if (!angle_get_platform)
148     return false;
149 
150   // Save the pointer to the destroy function here to avoid crash.
151   g_angle_reset_platform = reinterpret_cast<ResetDisplayPlatformFunc>(
152       eglGetProcAddress("ANGLEResetDisplayPlatform"));
153 
154   PlatformMethods* platformMethods = nullptr;
155   if (!angle_get_platform(static_cast<EGLDisplayType>(display),
156                           g_PlatformMethodNames, g_NumPlatformMethods, nullptr,
157                           &platformMethods))
158     platformMethods->currentTime = ANGLEPlatformImpl_currentTime;
159   platformMethods->addTraceEvent = ANGLEPlatformImpl_addTraceEvent;
160   platformMethods->currentTime = ANGLEPlatformImpl_currentTime;
161   platformMethods->getTraceCategoryEnabledFlag =
162       ANGLEPlatformImpl_getTraceCategoryEnabledFlag;
163   platformMethods->histogramBoolean = ANGLEPlatformImpl_histogramBoolean;
164   platformMethods->histogramCustomCounts =
165       ANGLEPlatformImpl_histogramCustomCounts;
166   platformMethods->histogramEnumeration =
167       ANGLEPlatformImpl_histogramEnumeration;
168   platformMethods->histogramSparse = ANGLEPlatformImpl_histogramSparse;
169   platformMethods->logError = ANGLEPlatformImpl_logError;
170   platformMethods->logWarning = ANGLEPlatformImpl_logWarning;
171   platformMethods->monotonicallyIncreasingTime =
172       ANGLEPlatformImpl_monotonicallyIncreasingTime;
173   platformMethods->updateTraceEventDuration =
174       ANGLEPlatformImpl_updateTraceEventDuration;
175 
176   // Initialize the delegate to allow posting tasks in the Chromium thread pool.
177   // The thread pool is not available in some unittests.
178   if (base::ThreadPoolInstance::Get())
179     platformMethods->postWorkerTask = ANGLEPlatformImpl_postWorkerTask;
180   return true;
181 }
182 
183 NO_SANITIZE("cfi-icall")
ResetPlatform(EGLDisplay display)184 void ResetPlatform(EGLDisplay display) {
185   if (!g_angle_reset_platform)
186     return;
187   g_angle_reset_platform(static_cast<EGLDisplayType>(display));
188 }
189 
190 }  // namespace angle
191