1 // Copyright 2018 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/gfx/android/android_surface_control_compat.h"
6 
7 #include <android/data_space.h>
8 #include <dlfcn.h>
9 
10 #include "base/android/build_info.h"
11 #include "base/atomic_sequence_num.h"
12 #include "base/bind.h"
13 #include "base/debug/crash_logging.h"
14 #include "base/logging.h"
15 #include "base/memory/ptr_util.h"
16 #include "base/no_destructor.h"
17 #include "base/strings/string_number_conversions.h"
18 #include "base/system/sys_info.h"
19 #include "base/trace_event/trace_event.h"
20 #include "ui/gfx/color_space.h"
21 
22 extern "C" {
23 typedef struct ASurfaceTransactionStats ASurfaceTransactionStats;
24 typedef void (*ASurfaceTransaction_OnComplete)(void* context,
25                                                ASurfaceTransactionStats* stats);
26 
27 // ASurface
28 using pASurfaceControl_createFromWindow =
29     ASurfaceControl* (*)(ANativeWindow* parent, const char* name);
30 using pASurfaceControl_create = ASurfaceControl* (*)(ASurfaceControl* parent,
31                                                      const char* name);
32 using pASurfaceControl_release = void (*)(ASurfaceControl*);
33 
34 // ASurfaceTransaction enums
35 enum {
36   ASURFACE_TRANSACTION_TRANSPARENCY_TRANSPARENT = 0,
37   ASURFACE_TRANSACTION_TRANSPARENCY_TRANSLUCENT = 1,
38   ASURFACE_TRANSACTION_TRANSPARENCY_OPAQUE = 2,
39 };
40 
41 // ANativeWindow_FrameRateCompatibility enums
42 enum {
43   ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT = 0,
44   ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_FIXED_SOURCE = 1
45 };
46 
47 // ASurfaceTransaction
48 using pASurfaceTransaction_create = ASurfaceTransaction* (*)(void);
49 using pASurfaceTransaction_delete = void (*)(ASurfaceTransaction*);
50 using pASurfaceTransaction_apply = int64_t (*)(ASurfaceTransaction*);
51 using pASurfaceTransaction_setOnComplete =
52     void (*)(ASurfaceTransaction*, void* ctx, ASurfaceTransaction_OnComplete);
53 using pASurfaceTransaction_setVisibility = void (*)(ASurfaceTransaction*,
54                                                     ASurfaceControl*,
55                                                     int8_t visibility);
56 using pASurfaceTransaction_setZOrder =
57     void (*)(ASurfaceTransaction* transaction, ASurfaceControl*, int32_t z);
58 using pASurfaceTransaction_setBuffer =
59     void (*)(ASurfaceTransaction* transaction,
60              ASurfaceControl*,
61              AHardwareBuffer*,
62              int32_t fence_fd);
63 using pASurfaceTransaction_setGeometry =
64     void (*)(ASurfaceTransaction* transaction,
65              ASurfaceControl* surface,
66              const ARect& src,
67              const ARect& dst,
68              int32_t transform);
69 using pASurfaceTransaction_setBufferTransparency =
70     void (*)(ASurfaceTransaction* transaction,
71              ASurfaceControl* surface,
72              int8_t transparency);
73 using pASurfaceTransaction_setDamageRegion =
74     void (*)(ASurfaceTransaction* transaction,
75              ASurfaceControl* surface,
76              const ARect rects[],
77              uint32_t count);
78 using pASurfaceTransaction_setBufferDataSpace =
79     void (*)(ASurfaceTransaction* transaction,
80              ASurfaceControl* surface,
81              uint64_t data_space);
82 using pASurfaceTransaction_setFrameRate =
83     void (*)(ASurfaceTransaction* transaction,
84              ASurfaceControl* surface_control,
85              float frameRate,
86              int8_t compatibility);
87 
88 // ASurfaceTransactionStats
89 using pASurfaceTransactionStats_getPresentFenceFd =
90     int (*)(ASurfaceTransactionStats* stats);
91 using pASurfaceTransactionStats_getLatchTime =
92     int64_t (*)(ASurfaceTransactionStats* stats);
93 using pASurfaceTransactionStats_getASurfaceControls =
94     void (*)(ASurfaceTransactionStats* stats,
95              ASurfaceControl*** surface_controls,
96              size_t* size);
97 using pASurfaceTransactionStats_releaseASurfaceControls =
98     void (*)(ASurfaceControl** surface_controls);
99 using pASurfaceTransactionStats_getPreviousReleaseFenceFd =
100     int (*)(ASurfaceTransactionStats* stats, ASurfaceControl* surface_control);
101 }
102 
103 namespace gfx {
104 namespace {
105 
106 base::AtomicSequenceNumber g_next_transaction_id;
107 
108 uint64_t g_agb_required_usage_bits = AHARDWAREBUFFER_USAGE_COMPOSER_OVERLAY;
109 
110 #define LOAD_FUNCTION(lib, func)                             \
111   do {                                                       \
112     func##Fn = reinterpret_cast<p##func>(dlsym(lib, #func)); \
113     if (!func##Fn) {                                         \
114       supported = false;                                     \
115       LOG(ERROR) << "Unable to load function " << #func;     \
116     }                                                        \
117   } while (0)
118 
119 #define LOAD_FUNCTION_MAYBE(lib, func)                       \
120   do {                                                       \
121     func##Fn = reinterpret_cast<p##func>(dlsym(lib, #func)); \
122   } while (0)
123 
124 struct SurfaceControlMethods {
125  public:
Getgfx::__anon7b31ec160311::SurfaceControlMethods126   static const SurfaceControlMethods& Get() {
127     static const base::NoDestructor<SurfaceControlMethods> instance;
128     return *instance;
129   }
130 
SurfaceControlMethodsgfx::__anon7b31ec160311::SurfaceControlMethods131   SurfaceControlMethods() {
132     void* main_dl_handle = dlopen("libandroid.so", RTLD_NOW);
133     if (!main_dl_handle) {
134       LOG(ERROR) << "Couldnt load android so";
135       supported = false;
136       return;
137     }
138 
139     LOAD_FUNCTION(main_dl_handle, ASurfaceControl_createFromWindow);
140     LOAD_FUNCTION(main_dl_handle, ASurfaceControl_create);
141     LOAD_FUNCTION(main_dl_handle, ASurfaceControl_release);
142 
143     LOAD_FUNCTION(main_dl_handle, ASurfaceTransaction_create);
144     LOAD_FUNCTION(main_dl_handle, ASurfaceTransaction_delete);
145     LOAD_FUNCTION(main_dl_handle, ASurfaceTransaction_apply);
146     LOAD_FUNCTION(main_dl_handle, ASurfaceTransaction_setOnComplete);
147     LOAD_FUNCTION(main_dl_handle, ASurfaceTransaction_setVisibility);
148     LOAD_FUNCTION(main_dl_handle, ASurfaceTransaction_setZOrder);
149     LOAD_FUNCTION(main_dl_handle, ASurfaceTransaction_setBuffer);
150     LOAD_FUNCTION(main_dl_handle, ASurfaceTransaction_setGeometry);
151     LOAD_FUNCTION(main_dl_handle, ASurfaceTransaction_setBufferTransparency);
152     LOAD_FUNCTION(main_dl_handle, ASurfaceTransaction_setDamageRegion);
153     LOAD_FUNCTION(main_dl_handle, ASurfaceTransaction_setBufferDataSpace);
154     LOAD_FUNCTION_MAYBE(main_dl_handle, ASurfaceTransaction_setFrameRate);
155 
156     LOAD_FUNCTION(main_dl_handle, ASurfaceTransactionStats_getPresentFenceFd);
157     LOAD_FUNCTION(main_dl_handle, ASurfaceTransactionStats_getLatchTime);
158     LOAD_FUNCTION(main_dl_handle, ASurfaceTransactionStats_getASurfaceControls);
159     LOAD_FUNCTION(main_dl_handle,
160                   ASurfaceTransactionStats_releaseASurfaceControls);
161     LOAD_FUNCTION(main_dl_handle,
162                   ASurfaceTransactionStats_getPreviousReleaseFenceFd);
163   }
164 
165   ~SurfaceControlMethods() = default;
166 
167   bool supported = true;
168   // Surface methods.
169   pASurfaceControl_createFromWindow ASurfaceControl_createFromWindowFn;
170   pASurfaceControl_create ASurfaceControl_createFn;
171   pASurfaceControl_release ASurfaceControl_releaseFn;
172 
173   // Transaction methods.
174   pASurfaceTransaction_create ASurfaceTransaction_createFn;
175   pASurfaceTransaction_delete ASurfaceTransaction_deleteFn;
176   pASurfaceTransaction_apply ASurfaceTransaction_applyFn;
177   pASurfaceTransaction_setOnComplete ASurfaceTransaction_setOnCompleteFn;
178   pASurfaceTransaction_setVisibility ASurfaceTransaction_setVisibilityFn;
179   pASurfaceTransaction_setZOrder ASurfaceTransaction_setZOrderFn;
180   pASurfaceTransaction_setBuffer ASurfaceTransaction_setBufferFn;
181   pASurfaceTransaction_setGeometry ASurfaceTransaction_setGeometryFn;
182   pASurfaceTransaction_setBufferTransparency
183       ASurfaceTransaction_setBufferTransparencyFn;
184   pASurfaceTransaction_setDamageRegion ASurfaceTransaction_setDamageRegionFn;
185   pASurfaceTransaction_setBufferDataSpace
186       ASurfaceTransaction_setBufferDataSpaceFn;
187   pASurfaceTransaction_setFrameRate ASurfaceTransaction_setFrameRateFn;
188 
189   // TransactionStats methods.
190   pASurfaceTransactionStats_getPresentFenceFd
191       ASurfaceTransactionStats_getPresentFenceFdFn;
192   pASurfaceTransactionStats_getLatchTime
193       ASurfaceTransactionStats_getLatchTimeFn;
194   pASurfaceTransactionStats_getASurfaceControls
195       ASurfaceTransactionStats_getASurfaceControlsFn;
196   pASurfaceTransactionStats_releaseASurfaceControls
197       ASurfaceTransactionStats_releaseASurfaceControlsFn;
198   pASurfaceTransactionStats_getPreviousReleaseFenceFd
199       ASurfaceTransactionStats_getPreviousReleaseFenceFdFn;
200 };
201 
RectToARect(const gfx::Rect & rect)202 ARect RectToARect(const gfx::Rect& rect) {
203   return ARect{rect.x(), rect.y(), rect.right(), rect.bottom()};
204 }
205 
OverlayTransformToWindowTransform(gfx::OverlayTransform transform)206 int32_t OverlayTransformToWindowTransform(gfx::OverlayTransform transform) {
207   // Note that the gfx::OverlayTransform expresses rotations in anticlockwise
208   // direction while the ANativeWindow rotations are in clockwise direction.
209   switch (transform) {
210     case gfx::OVERLAY_TRANSFORM_INVALID:
211       DCHECK(false) << "Invalid Transform";
212       return ANATIVEWINDOW_TRANSFORM_IDENTITY;
213     case gfx::OVERLAY_TRANSFORM_NONE:
214       return ANATIVEWINDOW_TRANSFORM_IDENTITY;
215     case gfx::OVERLAY_TRANSFORM_FLIP_HORIZONTAL:
216       return ANATIVEWINDOW_TRANSFORM_MIRROR_HORIZONTAL;
217     case gfx::OVERLAY_TRANSFORM_FLIP_VERTICAL:
218       return ANATIVEWINDOW_TRANSFORM_MIRROR_VERTICAL;
219     case gfx::OVERLAY_TRANSFORM_ROTATE_90:
220       return ANATIVEWINDOW_TRANSFORM_ROTATE_270;
221     case gfx::OVERLAY_TRANSFORM_ROTATE_180:
222       return ANATIVEWINDOW_TRANSFORM_ROTATE_180;
223     case gfx::OVERLAY_TRANSFORM_ROTATE_270:
224       return ANATIVEWINDOW_TRANSFORM_ROTATE_90;
225   };
226   NOTREACHED();
227   return ANATIVEWINDOW_TRANSFORM_IDENTITY;
228 }
229 
ColorSpaceToADataSpace(const gfx::ColorSpace & color_space)230 uint64_t ColorSpaceToADataSpace(const gfx::ColorSpace& color_space) {
231   if (!color_space.IsValid() || color_space == gfx::ColorSpace::CreateSRGB())
232     return ADATASPACE_SRGB;
233 
234   if (color_space == gfx::ColorSpace::CreateSCRGBLinear())
235     return ADATASPACE_SCRGB_LINEAR;
236 
237   if (color_space == gfx::ColorSpace::CreateDisplayP3D65())
238     return ADATASPACE_DISPLAY_P3;
239 
240   // TODO(khushalsagar): Check if we can support BT2020 using
241   // ADATASPACE_BT2020_PQ.
242   return ADATASPACE_UNKNOWN;
243 }
244 
ToTransactionStats(ASurfaceTransactionStats * stats)245 SurfaceControl::TransactionStats ToTransactionStats(
246     ASurfaceTransactionStats* stats) {
247   SurfaceControl::TransactionStats transaction_stats;
248   transaction_stats.present_fence = base::ScopedFD(
249       SurfaceControlMethods::Get().ASurfaceTransactionStats_getPresentFenceFdFn(
250           stats));
251   transaction_stats.latch_time =
252       base::TimeTicks() +
253       base::TimeDelta::FromNanoseconds(
254           SurfaceControlMethods::Get().ASurfaceTransactionStats_getLatchTimeFn(
255               stats));
256   if (transaction_stats.latch_time == base::TimeTicks())
257     transaction_stats.latch_time = base::TimeTicks::Now();
258 
259   ASurfaceControl** surface_controls = nullptr;
260   size_t size = 0u;
261   SurfaceControlMethods::Get().ASurfaceTransactionStats_getASurfaceControlsFn(
262       stats, &surface_controls, &size);
263   transaction_stats.surface_stats.resize(size);
264   for (size_t i = 0u; i < size; ++i) {
265     transaction_stats.surface_stats[i].surface = surface_controls[i];
266     int fence_fd = SurfaceControlMethods::Get()
267                        .ASurfaceTransactionStats_getPreviousReleaseFenceFdFn(
268                            stats, surface_controls[i]);
269     if (fence_fd != -1) {
270       transaction_stats.surface_stats[i].fence = base::ScopedFD(fence_fd);
271     }
272   }
273   SurfaceControlMethods::Get()
274       .ASurfaceTransactionStats_releaseASurfaceControlsFn(surface_controls);
275 
276   return transaction_stats;
277 }
278 
279 struct TransactionAckCtx {
280   int id = 0;
281   scoped_refptr<base::SingleThreadTaskRunner> task_runner;
282   SurfaceControl::Transaction::OnCompleteCb callback;
283 };
284 
285 // Note that the framework API states that this callback can be dispatched on
286 // any thread (in practice it should be the binder thread).
OnTransactionCompletedOnAnyThread(void * context,ASurfaceTransactionStats * stats)287 void OnTransactionCompletedOnAnyThread(void* context,
288                                        ASurfaceTransactionStats* stats) {
289   auto* ack_ctx = static_cast<TransactionAckCtx*>(context);
290   auto transaction_stats = ToTransactionStats(stats);
291   TRACE_EVENT_NESTABLE_ASYNC_END0("gpu,benchmark", "SurfaceControlTransaction",
292                                   ack_ctx->id);
293 
294   if (ack_ctx->task_runner) {
295     ack_ctx->task_runner->PostTask(
296         FROM_HERE, base::BindOnce(std::move(ack_ctx->callback),
297                                   std::move(transaction_stats)));
298   } else {
299     std::move(ack_ctx->callback).Run(std::move(transaction_stats));
300   }
301 
302   delete ack_ctx;
303 }
304 }  // namespace
305 
306 // static
IsSupported()307 bool SurfaceControl::IsSupported() {
308   if (!base::android::BuildInfo::GetInstance()->is_at_least_q())
309     return false;
310 
311   CHECK(SurfaceControlMethods::Get().supported);
312   return true;
313 }
314 
SupportsColorSpace(const gfx::ColorSpace & color_space)315 bool SurfaceControl::SupportsColorSpace(const gfx::ColorSpace& color_space) {
316   return ColorSpaceToADataSpace(color_space) != ADATASPACE_UNKNOWN;
317 }
318 
RequiredUsage()319 uint64_t SurfaceControl::RequiredUsage() {
320   if (!IsSupported())
321     return 0u;
322   return g_agb_required_usage_bits;
323 }
324 
EnableQualcommUBWC()325 void SurfaceControl::EnableQualcommUBWC() {
326   g_agb_required_usage_bits |= AHARDWAREBUFFER_USAGE_VENDOR_0;
327 }
328 
SupportsSetFrameRate()329 bool SurfaceControl::SupportsSetFrameRate() {
330   // TODO(khushalsagar): Assert that this function is always available on R.
331   return IsSupported() &&
332          SurfaceControlMethods::Get().ASurfaceTransaction_setFrameRateFn !=
333              nullptr;
334 }
335 
336 SurfaceControl::Surface::Surface() = default;
337 
Surface(const Surface & parent,const char * name)338 SurfaceControl::Surface::Surface(const Surface& parent, const char* name) {
339   surface_ = SurfaceControlMethods::Get().ASurfaceControl_createFn(
340       parent.surface(), name);
341   if (!surface_)
342     LOG(ERROR) << "Failed to create ASurfaceControl : " << name;
343 }
344 
Surface(ANativeWindow * parent,const char * name)345 SurfaceControl::Surface::Surface(ANativeWindow* parent, const char* name) {
346   surface_ = SurfaceControlMethods::Get().ASurfaceControl_createFromWindowFn(
347       parent, name);
348   if (!surface_)
349     LOG(ERROR) << "Failed to create ASurfaceControl : " << name;
350 }
351 
~Surface()352 SurfaceControl::Surface::~Surface() {
353   if (surface_)
354     SurfaceControlMethods::Get().ASurfaceControl_releaseFn(surface_);
355 }
356 
357 SurfaceControl::SurfaceStats::SurfaceStats() = default;
358 SurfaceControl::SurfaceStats::~SurfaceStats() = default;
359 
360 SurfaceControl::SurfaceStats::SurfaceStats(SurfaceStats&& other) = default;
361 SurfaceControl::SurfaceStats& SurfaceControl::SurfaceStats::operator=(
362     SurfaceStats&& other) = default;
363 
364 SurfaceControl::TransactionStats::TransactionStats() = default;
365 SurfaceControl::TransactionStats::~TransactionStats() = default;
366 
367 SurfaceControl::TransactionStats::TransactionStats(TransactionStats&& other) =
368     default;
369 SurfaceControl::TransactionStats& SurfaceControl::TransactionStats::operator=(
370     TransactionStats&& other) = default;
371 
Transaction()372 SurfaceControl::Transaction::Transaction()
373     : id_(g_next_transaction_id.GetNext()) {
374   transaction_ = SurfaceControlMethods::Get().ASurfaceTransaction_createFn();
375   DCHECK(transaction_);
376 }
377 
~Transaction()378 SurfaceControl::Transaction::~Transaction() {
379   if (transaction_)
380     SurfaceControlMethods::Get().ASurfaceTransaction_deleteFn(transaction_);
381 }
382 
Transaction(Transaction && other)383 SurfaceControl::Transaction::Transaction(Transaction&& other)
384     : id_(other.id_), transaction_(other.transaction_) {
385   other.transaction_ = nullptr;
386   other.id_ = 0;
387 }
388 
operator =(Transaction && other)389 SurfaceControl::Transaction& SurfaceControl::Transaction::operator=(
390     Transaction&& other) {
391   if (transaction_)
392     SurfaceControlMethods::Get().ASurfaceTransaction_deleteFn(transaction_);
393 
394   transaction_ = other.transaction_;
395   id_ = other.id_;
396 
397   other.transaction_ = nullptr;
398   other.id_ = 0;
399   return *this;
400 }
401 
SetVisibility(const Surface & surface,bool show)402 void SurfaceControl::Transaction::SetVisibility(const Surface& surface,
403                                                 bool show) {
404   SurfaceControlMethods::Get().ASurfaceTransaction_setVisibilityFn(
405       transaction_, surface.surface(), show);
406 }
407 
SetZOrder(const Surface & surface,int32_t z)408 void SurfaceControl::Transaction::SetZOrder(const Surface& surface, int32_t z) {
409   SurfaceControlMethods::Get().ASurfaceTransaction_setZOrderFn(
410       transaction_, surface.surface(), z);
411 }
412 
SetBuffer(const Surface & surface,AHardwareBuffer * buffer,base::ScopedFD fence_fd)413 void SurfaceControl::Transaction::SetBuffer(const Surface& surface,
414                                             AHardwareBuffer* buffer,
415                                             base::ScopedFD fence_fd) {
416   SurfaceControlMethods::Get().ASurfaceTransaction_setBufferFn(
417       transaction_, surface.surface(), buffer,
418       fence_fd.is_valid() ? fence_fd.release() : -1);
419 }
420 
SetGeometry(const Surface & surface,const gfx::Rect & src,const gfx::Rect & dst,gfx::OverlayTransform transform)421 void SurfaceControl::Transaction::SetGeometry(const Surface& surface,
422                                               const gfx::Rect& src,
423                                               const gfx::Rect& dst,
424                                               gfx::OverlayTransform transform) {
425   SurfaceControlMethods::Get().ASurfaceTransaction_setGeometryFn(
426       transaction_, surface.surface(), RectToARect(src), RectToARect(dst),
427       OverlayTransformToWindowTransform(transform));
428 }
429 
SetOpaque(const Surface & surface,bool opaque)430 void SurfaceControl::Transaction::SetOpaque(const Surface& surface,
431                                             bool opaque) {
432   int8_t transparency = opaque ? ASURFACE_TRANSACTION_TRANSPARENCY_OPAQUE
433                                : ASURFACE_TRANSACTION_TRANSPARENCY_TRANSLUCENT;
434   SurfaceControlMethods::Get().ASurfaceTransaction_setBufferTransparencyFn(
435       transaction_, surface.surface(), transparency);
436 }
437 
SetDamageRect(const Surface & surface,const gfx::Rect & rect)438 void SurfaceControl::Transaction::SetDamageRect(const Surface& surface,
439                                                 const gfx::Rect& rect) {
440   auto a_rect = RectToARect(rect);
441   SurfaceControlMethods::Get().ASurfaceTransaction_setDamageRegionFn(
442       transaction_, surface.surface(), &a_rect, 1u);
443 }
444 
SetColorSpace(const Surface & surface,const gfx::ColorSpace & color_space)445 void SurfaceControl::Transaction::SetColorSpace(
446     const Surface& surface,
447     const gfx::ColorSpace& color_space) {
448   auto data_space = ColorSpaceToADataSpace(color_space);
449 
450   // Log the data space in crash keys for debugging crbug.com/997592.
451   static auto* kCrashKey = base::debug::AllocateCrashKeyString(
452       "data_space_for_buffer", base::debug::CrashKeySize::Size256);
453   auto crash_key_value = base::NumberToString(data_space);
454   base::debug::ScopedCrashKeyString scoped_crash_key(kCrashKey,
455                                                      crash_key_value);
456 
457   SurfaceControlMethods::Get().ASurfaceTransaction_setBufferDataSpaceFn(
458       transaction_, surface.surface(), data_space);
459 }
460 
SetFrameRate(const Surface & surface,float frame_rate)461 void SurfaceControl::Transaction::SetFrameRate(const Surface& surface,
462                                                float frame_rate) {
463   DCHECK(SupportsSetFrameRate());
464 
465   // We always used fixed source here since a non-default value is only used for
466   // videos which have a fixed playback rate.
467   SurfaceControlMethods::Get().ASurfaceTransaction_setFrameRateFn(
468       transaction_, surface.surface(), frame_rate,
469       ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_FIXED_SOURCE);
470 }
471 
SetOnCompleteCb(OnCompleteCb cb,scoped_refptr<base::SingleThreadTaskRunner> task_runner)472 void SurfaceControl::Transaction::SetOnCompleteCb(
473     OnCompleteCb cb,
474     scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
475   TransactionAckCtx* ack_ctx = new TransactionAckCtx;
476   ack_ctx->callback = std::move(cb);
477   ack_ctx->task_runner = std::move(task_runner);
478   ack_ctx->id = id_;
479 
480   SurfaceControlMethods::Get().ASurfaceTransaction_setOnCompleteFn(
481       transaction_, ack_ctx, &OnTransactionCompletedOnAnyThread);
482 }
483 
Apply()484 void SurfaceControl::Transaction::Apply() {
485   TRACE_EVENT_NESTABLE_ASYNC_BEGIN0("gpu,benchmark",
486                                     "SurfaceControlTransaction", id_);
487   SurfaceControlMethods::Get().ASurfaceTransaction_applyFn(transaction_);
488 }
489 
490 }  // namespace gfx
491