|  | // Copyright 2018 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 "ui/gfx/android/android_surface_control_compat.h" | 
|  |  | 
|  | #include <android/data_space.h> | 
|  | #include <android/hdr_metadata.h> | 
|  | #include <dlfcn.h> | 
|  |  | 
|  | #include "base/android/build_info.h" | 
|  | #include "base/atomic_sequence_num.h" | 
|  | #include "base/bind.h" | 
|  | #include "base/debug/crash_logging.h" | 
|  | #include "base/hash/md5_constexpr.h" | 
|  | #include "base/logging.h" | 
|  | #include "base/memory/ptr_util.h" | 
|  | #include "base/strings/string_number_conversions.h" | 
|  | #include "base/system/sys_info.h" | 
|  | #include "base/task/bind_post_task.h" | 
|  | #include "base/trace_event/trace_event.h" | 
|  | #include "ui/gfx/color_space.h" | 
|  |  | 
|  | extern "C" { | 
|  | typedef struct ASurfaceTransactionStats ASurfaceTransactionStats; | 
|  | typedef void (*ASurfaceTransaction_OnComplete)(void* context, | 
|  | ASurfaceTransactionStats* stats); | 
|  | typedef void (*ASurfaceTransaction_OnCommit)(void* context, | 
|  | ASurfaceTransactionStats* stats); | 
|  |  | 
|  | // ASurface | 
|  | using pASurfaceControl_createFromWindow = | 
|  | ASurfaceControl* (*)(ANativeWindow* parent, const char* name); | 
|  | using pASurfaceControl_create = ASurfaceControl* (*)(ASurfaceControl* parent, | 
|  | const char* name); | 
|  | using pASurfaceControl_release = void (*)(ASurfaceControl*); | 
|  |  | 
|  | // ASurfaceTransaction enums | 
|  | enum { | 
|  | ASURFACE_TRANSACTION_TRANSPARENCY_TRANSPARENT = 0, | 
|  | ASURFACE_TRANSACTION_TRANSPARENCY_TRANSLUCENT = 1, | 
|  | ASURFACE_TRANSACTION_TRANSPARENCY_OPAQUE = 2, | 
|  | }; | 
|  |  | 
|  | // ASurfaceTransaction | 
|  | using pASurfaceTransaction_create = ASurfaceTransaction* (*)(void); | 
|  | using pASurfaceTransaction_delete = void (*)(ASurfaceTransaction*); | 
|  | using pASurfaceTransaction_apply = int64_t (*)(ASurfaceTransaction*); | 
|  | using pASurfaceTransaction_setOnComplete = | 
|  | void (*)(ASurfaceTransaction*, void* ctx, ASurfaceTransaction_OnComplete); | 
|  | using pASurfaceTransaction_setOnCommit = void (*)(ASurfaceTransaction*, | 
|  | void* ctx, | 
|  | ASurfaceTransaction_OnCommit); | 
|  | using pASurfaceTransaction_setVisibility = void (*)(ASurfaceTransaction*, | 
|  | ASurfaceControl*, | 
|  | int8_t visibility); | 
|  | using pASurfaceTransaction_setZOrder = | 
|  | void (*)(ASurfaceTransaction* transaction, ASurfaceControl*, int32_t z); | 
|  | using pASurfaceTransaction_setBuffer = | 
|  | void (*)(ASurfaceTransaction* transaction, | 
|  | ASurfaceControl*, | 
|  | AHardwareBuffer*, | 
|  | int32_t fence_fd); | 
|  | using pASurfaceTransaction_setGeometry = | 
|  | void (*)(ASurfaceTransaction* transaction, | 
|  | ASurfaceControl* surface, | 
|  | const ARect& src, | 
|  | const ARect& dst, | 
|  | int32_t transform); | 
|  | using pASurfaceTransaction_setPosition = | 
|  | void (*)(ASurfaceTransaction* transaction, | 
|  | ASurfaceControl* surface, | 
|  | int32_t x, | 
|  | int32_t y); | 
|  | using pASurfaceTransaction_setScale = void (*)(ASurfaceTransaction* transaction, | 
|  | ASurfaceControl* surface, | 
|  | float x_scale, | 
|  | float y_scale); | 
|  | using pASurfaceTransaction_setCrop = void (*)(ASurfaceTransaction* transaction, | 
|  | ASurfaceControl* surface, | 
|  | const ARect& src); | 
|  | using pASurfaceTransaction_setBufferTransparency = | 
|  | void (*)(ASurfaceTransaction* transaction, | 
|  | ASurfaceControl* surface, | 
|  | int8_t transparency); | 
|  | using pASurfaceTransaction_setDamageRegion = | 
|  | void (*)(ASurfaceTransaction* transaction, | 
|  | ASurfaceControl* surface, | 
|  | const ARect rects[], | 
|  | uint32_t count); | 
|  | using pASurfaceTransaction_setBufferDataSpace = | 
|  | void (*)(ASurfaceTransaction* transaction, | 
|  | ASurfaceControl* surface, | 
|  | uint64_t data_space); | 
|  | using pASurfaceTransaction_setHdrMetadata_cta861_3 = | 
|  | void (*)(ASurfaceTransaction* transaction, | 
|  | ASurfaceControl* surface, | 
|  | struct AHdrMetadata_cta861_3* metadata); | 
|  | using pASurfaceTransaction_setHdrMetadata_smpte2086 = | 
|  | void (*)(ASurfaceTransaction* transaction, | 
|  | ASurfaceControl* surface, | 
|  | struct AHdrMetadata_smpte2086* metadata); | 
|  | using pASurfaceTransaction_setFrameRate = | 
|  | void (*)(ASurfaceTransaction* transaction, | 
|  | ASurfaceControl* surface_control, | 
|  | float frameRate, | 
|  | int8_t compatibility); | 
|  | using pASurfaceTransaction_setFrameTimeline = | 
|  | void (*)(ASurfaceTransaction* transaction, int64_t vsync_id); | 
|  | using pASurfaceTransaction_reparent = void (*)(ASurfaceTransaction*, | 
|  | ASurfaceControl* surface_control, | 
|  | ASurfaceControl* new_parent); | 
|  | // ASurfaceTransactionStats | 
|  | using pASurfaceTransactionStats_getPresentFenceFd = | 
|  | int (*)(ASurfaceTransactionStats* stats); | 
|  | using pASurfaceTransactionStats_getLatchTime = | 
|  | int64_t (*)(ASurfaceTransactionStats* stats); | 
|  | using pASurfaceTransactionStats_getASurfaceControls = | 
|  | void (*)(ASurfaceTransactionStats* stats, | 
|  | ASurfaceControl*** surface_controls, | 
|  | size_t* size); | 
|  | using pASurfaceTransactionStats_releaseASurfaceControls = | 
|  | void (*)(ASurfaceControl** surface_controls); | 
|  | using pASurfaceTransactionStats_getPreviousReleaseFenceFd = | 
|  | int (*)(ASurfaceTransactionStats* stats, ASurfaceControl* surface_control); | 
|  | } | 
|  |  | 
|  | namespace gfx { | 
|  | namespace { | 
|  |  | 
|  | base::AtomicSequenceNumber g_next_transaction_id; | 
|  |  | 
|  | uint64_t g_agb_required_usage_bits = AHARDWAREBUFFER_USAGE_COMPOSER_OVERLAY; | 
|  |  | 
|  | #define LOAD_FUNCTION(lib, func)                             \ | 
|  | do {                                                       \ | 
|  | func##Fn = reinterpret_cast<p##func>(dlsym(lib, #func)); \ | 
|  | if (!func##Fn) {                                         \ | 
|  | supported = false;                                     \ | 
|  | LOG(ERROR) << "Unable to load function " << #func;     \ | 
|  | }                                                        \ | 
|  | } while (0) | 
|  |  | 
|  | #define LOAD_FUNCTION_MAYBE(lib, func)                       \ | 
|  | do {                                                       \ | 
|  | func##Fn = reinterpret_cast<p##func>(dlsym(lib, #func)); \ | 
|  | } while (0) | 
|  |  | 
|  | struct SurfaceControlMethods { | 
|  | public: | 
|  | static SurfaceControlMethods& GetImpl(bool load_functions) { | 
|  | static SurfaceControlMethods instance(load_functions); | 
|  | return instance; | 
|  | } | 
|  |  | 
|  | static const SurfaceControlMethods& Get() { | 
|  | return GetImpl(/*load_functions=*/true); | 
|  | } | 
|  |  | 
|  | void InitWithStubs() { | 
|  | struct TransactionStub { | 
|  | ASurfaceTransaction_OnComplete on_complete = nullptr; | 
|  | void* on_complete_ctx = nullptr; | 
|  | ASurfaceTransaction_OnCommit on_commit = nullptr; | 
|  | void* on_commit_ctx = nullptr; | 
|  | }; | 
|  |  | 
|  | ASurfaceTransaction_createFn = []() { | 
|  | return reinterpret_cast<ASurfaceTransaction*>(new TransactionStub); | 
|  | }; | 
|  | ASurfaceTransaction_deleteFn = [](ASurfaceTransaction* transaction) { | 
|  | delete reinterpret_cast<TransactionStub*>(transaction); | 
|  | }; | 
|  | ASurfaceTransaction_applyFn = [](ASurfaceTransaction* transaction) { | 
|  | auto* stub = reinterpret_cast<TransactionStub*>(transaction); | 
|  |  | 
|  | if (stub->on_commit) | 
|  | stub->on_commit(stub->on_commit_ctx, nullptr); | 
|  | stub->on_commit = nullptr; | 
|  | stub->on_commit_ctx = nullptr; | 
|  |  | 
|  | if (stub->on_complete) | 
|  | stub->on_complete(stub->on_complete_ctx, nullptr); | 
|  | stub->on_complete = nullptr; | 
|  | stub->on_complete_ctx = nullptr; | 
|  |  | 
|  | return static_cast<int64_t>(0); | 
|  | }; | 
|  |  | 
|  | ASurfaceTransaction_setOnCompleteFn = | 
|  | [](ASurfaceTransaction* transaction, void* ctx, | 
|  | ASurfaceTransaction_OnComplete callback) { | 
|  | auto* stub = reinterpret_cast<TransactionStub*>(transaction); | 
|  | stub->on_complete = callback; | 
|  | stub->on_complete_ctx = ctx; | 
|  | }; | 
|  |  | 
|  | ASurfaceTransaction_setOnCommitFn = | 
|  | [](ASurfaceTransaction* transaction, void* ctx, | 
|  | ASurfaceTransaction_OnCommit callback) { | 
|  | auto* stub = reinterpret_cast<TransactionStub*>(transaction); | 
|  | stub->on_commit = callback; | 
|  | stub->on_commit_ctx = ctx; | 
|  | }; | 
|  | } | 
|  |  | 
|  | SurfaceControlMethods(bool load_functions) { | 
|  | if (!load_functions) | 
|  | return; | 
|  |  | 
|  | void* main_dl_handle = dlopen("libandroid.so", RTLD_NOW); | 
|  | if (!main_dl_handle) { | 
|  | LOG(ERROR) << "Couldnt load android so"; | 
|  | supported = false; | 
|  | return; | 
|  | } | 
|  |  | 
|  | LOAD_FUNCTION(main_dl_handle, ASurfaceControl_createFromWindow); | 
|  | LOAD_FUNCTION(main_dl_handle, ASurfaceControl_create); | 
|  | LOAD_FUNCTION(main_dl_handle, ASurfaceControl_release); | 
|  |  | 
|  | LOAD_FUNCTION(main_dl_handle, ASurfaceTransaction_create); | 
|  | LOAD_FUNCTION(main_dl_handle, ASurfaceTransaction_delete); | 
|  | LOAD_FUNCTION(main_dl_handle, ASurfaceTransaction_apply); | 
|  | LOAD_FUNCTION(main_dl_handle, ASurfaceTransaction_setOnComplete); | 
|  | LOAD_FUNCTION_MAYBE(main_dl_handle, ASurfaceTransaction_setOnCommit); | 
|  | LOAD_FUNCTION(main_dl_handle, ASurfaceTransaction_reparent); | 
|  | LOAD_FUNCTION(main_dl_handle, ASurfaceTransaction_setVisibility); | 
|  | LOAD_FUNCTION(main_dl_handle, ASurfaceTransaction_setZOrder); | 
|  | LOAD_FUNCTION(main_dl_handle, ASurfaceTransaction_setBuffer); | 
|  | LOAD_FUNCTION(main_dl_handle, ASurfaceTransaction_setGeometry); | 
|  | LOAD_FUNCTION_MAYBE(main_dl_handle, ASurfaceTransaction_setPosition); | 
|  | LOAD_FUNCTION_MAYBE(main_dl_handle, ASurfaceTransaction_setScale); | 
|  | LOAD_FUNCTION_MAYBE(main_dl_handle, ASurfaceTransaction_setCrop); | 
|  | LOAD_FUNCTION(main_dl_handle, ASurfaceTransaction_setBufferTransparency); | 
|  | LOAD_FUNCTION(main_dl_handle, ASurfaceTransaction_setDamageRegion); | 
|  | LOAD_FUNCTION(main_dl_handle, ASurfaceTransaction_setBufferDataSpace); | 
|  | LOAD_FUNCTION(main_dl_handle, ASurfaceTransaction_setHdrMetadata_cta861_3); | 
|  | LOAD_FUNCTION(main_dl_handle, ASurfaceTransaction_setHdrMetadata_smpte2086); | 
|  | LOAD_FUNCTION_MAYBE(main_dl_handle, ASurfaceTransaction_setFrameRate); | 
|  | LOAD_FUNCTION_MAYBE(main_dl_handle, ASurfaceTransaction_setFrameTimeline); | 
|  |  | 
|  | LOAD_FUNCTION(main_dl_handle, ASurfaceTransactionStats_getPresentFenceFd); | 
|  | LOAD_FUNCTION(main_dl_handle, ASurfaceTransactionStats_getLatchTime); | 
|  | LOAD_FUNCTION(main_dl_handle, ASurfaceTransactionStats_getASurfaceControls); | 
|  | LOAD_FUNCTION(main_dl_handle, | 
|  | ASurfaceTransactionStats_releaseASurfaceControls); | 
|  | LOAD_FUNCTION(main_dl_handle, | 
|  | ASurfaceTransactionStats_getPreviousReleaseFenceFd); | 
|  | } | 
|  |  | 
|  | ~SurfaceControlMethods() = default; | 
|  |  | 
|  | bool supported = true; | 
|  | // Surface methods. | 
|  | pASurfaceControl_createFromWindow ASurfaceControl_createFromWindowFn; | 
|  | pASurfaceControl_create ASurfaceControl_createFn; | 
|  | pASurfaceControl_release ASurfaceControl_releaseFn; | 
|  |  | 
|  | // Transaction methods. | 
|  | pASurfaceTransaction_create ASurfaceTransaction_createFn; | 
|  | pASurfaceTransaction_delete ASurfaceTransaction_deleteFn; | 
|  | pASurfaceTransaction_apply ASurfaceTransaction_applyFn; | 
|  | pASurfaceTransaction_setOnComplete ASurfaceTransaction_setOnCompleteFn; | 
|  | pASurfaceTransaction_setOnCommit ASurfaceTransaction_setOnCommitFn; | 
|  | pASurfaceTransaction_reparent ASurfaceTransaction_reparentFn; | 
|  | pASurfaceTransaction_setVisibility ASurfaceTransaction_setVisibilityFn; | 
|  | pASurfaceTransaction_setZOrder ASurfaceTransaction_setZOrderFn; | 
|  | pASurfaceTransaction_setBuffer ASurfaceTransaction_setBufferFn; | 
|  | pASurfaceTransaction_setGeometry ASurfaceTransaction_setGeometryFn; | 
|  | pASurfaceTransaction_setPosition ASurfaceTransaction_setPositionFn; | 
|  | pASurfaceTransaction_setScale ASurfaceTransaction_setScaleFn; | 
|  | pASurfaceTransaction_setCrop ASurfaceTransaction_setCropFn; | 
|  | pASurfaceTransaction_setBufferTransparency | 
|  | ASurfaceTransaction_setBufferTransparencyFn; | 
|  | pASurfaceTransaction_setDamageRegion ASurfaceTransaction_setDamageRegionFn; | 
|  | pASurfaceTransaction_setBufferDataSpace | 
|  | ASurfaceTransaction_setBufferDataSpaceFn; | 
|  | pASurfaceTransaction_setHdrMetadata_cta861_3 | 
|  | ASurfaceTransaction_setHdrMetadata_cta861_3Fn; | 
|  | pASurfaceTransaction_setHdrMetadata_smpte2086 | 
|  | ASurfaceTransaction_setHdrMetadata_smpte2086Fn; | 
|  | pASurfaceTransaction_setFrameRate ASurfaceTransaction_setFrameRateFn; | 
|  | pASurfaceTransaction_setFrameTimeline ASurfaceTransaction_setFrameTimelineFn; | 
|  |  | 
|  | // TransactionStats methods. | 
|  | pASurfaceTransactionStats_getPresentFenceFd | 
|  | ASurfaceTransactionStats_getPresentFenceFdFn; | 
|  | pASurfaceTransactionStats_getLatchTime | 
|  | ASurfaceTransactionStats_getLatchTimeFn; | 
|  | pASurfaceTransactionStats_getASurfaceControls | 
|  | ASurfaceTransactionStats_getASurfaceControlsFn; | 
|  | pASurfaceTransactionStats_releaseASurfaceControls | 
|  | ASurfaceTransactionStats_releaseASurfaceControlsFn; | 
|  | pASurfaceTransactionStats_getPreviousReleaseFenceFd | 
|  | ASurfaceTransactionStats_getPreviousReleaseFenceFdFn; | 
|  | }; | 
|  |  | 
|  | ARect RectToARect(const gfx::Rect& rect) { | 
|  | return ARect{rect.x(), rect.y(), rect.right(), rect.bottom()}; | 
|  | } | 
|  |  | 
|  | int32_t OverlayTransformToWindowTransform(gfx::OverlayTransform transform) { | 
|  | // Note that the gfx::OverlayTransform expresses rotations in anticlockwise | 
|  | // direction while the ANativeWindow rotations are in clockwise direction. | 
|  | switch (transform) { | 
|  | case gfx::OVERLAY_TRANSFORM_INVALID: | 
|  | DCHECK(false) << "Invalid Transform"; | 
|  | return ANATIVEWINDOW_TRANSFORM_IDENTITY; | 
|  | case gfx::OVERLAY_TRANSFORM_NONE: | 
|  | return ANATIVEWINDOW_TRANSFORM_IDENTITY; | 
|  | case gfx::OVERLAY_TRANSFORM_FLIP_HORIZONTAL: | 
|  | return ANATIVEWINDOW_TRANSFORM_MIRROR_HORIZONTAL; | 
|  | case gfx::OVERLAY_TRANSFORM_FLIP_VERTICAL: | 
|  | return ANATIVEWINDOW_TRANSFORM_MIRROR_VERTICAL; | 
|  | case gfx::OVERLAY_TRANSFORM_ROTATE_90: | 
|  | return ANATIVEWINDOW_TRANSFORM_ROTATE_270; | 
|  | case gfx::OVERLAY_TRANSFORM_ROTATE_180: | 
|  | return ANATIVEWINDOW_TRANSFORM_ROTATE_180; | 
|  | case gfx::OVERLAY_TRANSFORM_ROTATE_270: | 
|  | return ANATIVEWINDOW_TRANSFORM_ROTATE_90; | 
|  | }; | 
|  | NOTREACHED(); | 
|  | return ANATIVEWINDOW_TRANSFORM_IDENTITY; | 
|  | } | 
|  |  | 
|  | // Remove this and use ADataSpace when SDK will roll. Note, this doesn't define | 
|  | // any new data spaces, just defines a primary(standard)/transfer/range | 
|  | // separately. | 
|  | enum DataSpace : uint64_t { | 
|  | // Primaries | 
|  | STANDARD_BT709 = 1 << 16, | 
|  | STANDARD_BT601_625 = 2 << 16, | 
|  | STANDARD_BT601_525 = 4 << 16, | 
|  | STANDARD_BT2020 = 6 << 16, | 
|  | // Transfer functions | 
|  | TRANSFER_LINEAR = 1 << 22, | 
|  | TRANSFER_SRGB = 2 << 22, | 
|  | TRANSFER_SMPTE_170M = 3 << 22, | 
|  | TRANSFER_ST2084 = 7 << 22, | 
|  | TRANSFER_HLG = 8 << 22, | 
|  | // Ranges; | 
|  | RANGE_FULL = 1 << 27, | 
|  | RANGE_LIMITED = 2 << 27, | 
|  |  | 
|  | ADATASPACE_DCI_P3 = 155844608 | 
|  | }; | 
|  |  | 
|  | absl::optional<uint64_t> GetDataSpaceStandard( | 
|  | const gfx::ColorSpace& color_space) { | 
|  | switch (color_space.GetPrimaryID()) { | 
|  | case gfx::ColorSpace::PrimaryID::BT709: | 
|  | return DataSpace::STANDARD_BT709; | 
|  | case gfx::ColorSpace::PrimaryID::BT470BG: | 
|  | return DataSpace::STANDARD_BT601_625; | 
|  | case gfx::ColorSpace::PrimaryID::SMPTE170M: | 
|  | return DataSpace::STANDARD_BT601_525; | 
|  | case gfx::ColorSpace::PrimaryID::BT2020: | 
|  | return DataSpace::STANDARD_BT2020; | 
|  | default: | 
|  | return absl::nullopt; | 
|  | } | 
|  | } | 
|  |  | 
|  | absl::optional<uint64_t> GetDataSpaceTransfer( | 
|  | const gfx::ColorSpace& color_space) { | 
|  | switch (color_space.GetTransferID()) { | 
|  | case gfx::ColorSpace::TransferID::SMPTE170M: | 
|  | return DataSpace::TRANSFER_SMPTE_170M; | 
|  | case gfx::ColorSpace::TransferID::LINEAR_HDR: | 
|  | return DataSpace::TRANSFER_LINEAR; | 
|  | case gfx::ColorSpace::TransferID::PQ: | 
|  | return DataSpace::TRANSFER_ST2084; | 
|  | case gfx::ColorSpace::TransferID::HLG: | 
|  | return DataSpace::TRANSFER_HLG; | 
|  | // We use SRGB for BT709. See |ColorSpace::GetTransferFunction()| for | 
|  | // details. | 
|  | case gfx::ColorSpace::TransferID::BT709: | 
|  | return DataSpace::TRANSFER_SRGB; | 
|  | default: | 
|  | return absl::nullopt; | 
|  | } | 
|  | } | 
|  |  | 
|  | absl::optional<uint64_t> GetDataSpaceRange(const gfx::ColorSpace& color_space) { | 
|  | switch (color_space.GetRangeID()) { | 
|  | case gfx::ColorSpace::RangeID::FULL: | 
|  | return DataSpace::RANGE_FULL; | 
|  | case gfx::ColorSpace::RangeID::LIMITED: | 
|  | return DataSpace::RANGE_LIMITED; | 
|  | default: | 
|  | return absl::nullopt; | 
|  | }; | 
|  | } | 
|  |  | 
|  | uint64_t ColorSpaceToADataSpace(const gfx::ColorSpace& color_space) { | 
|  | if (!color_space.IsValid() || color_space == gfx::ColorSpace::CreateSRGB()) | 
|  | return ADATASPACE_SRGB; | 
|  |  | 
|  | if (color_space == gfx::ColorSpace::CreateSRGBLinear()) | 
|  | return ADATASPACE_SCRGB_LINEAR; | 
|  |  | 
|  | if (color_space == gfx::ColorSpace::CreateDisplayP3D65()) | 
|  | return ADATASPACE_DISPLAY_P3; | 
|  |  | 
|  | if (base::android::BuildInfo::GetInstance()->sdk_int() >= | 
|  | base::android::SDK_VERSION_S) { | 
|  | auto standard = GetDataSpaceStandard(color_space); | 
|  | auto transfer = GetDataSpaceTransfer(color_space); | 
|  | auto range = GetDataSpaceRange(color_space); | 
|  |  | 
|  | // Data space is set of the flags, so check if all components are valid. | 
|  | if (standard && transfer && range) | 
|  | return standard.value() | transfer.value() | range.value(); | 
|  | } | 
|  |  | 
|  | return ADATASPACE_UNKNOWN; | 
|  | } | 
|  |  | 
|  | SurfaceControl::TransactionStats ToTransactionStats( | 
|  | ASurfaceTransactionStats* stats) { | 
|  | SurfaceControl::TransactionStats transaction_stats; | 
|  |  | 
|  | // In unit tests we don't have stats. | 
|  | if (!stats) | 
|  | return transaction_stats; | 
|  |  | 
|  | transaction_stats.present_fence = base::ScopedFD( | 
|  | SurfaceControlMethods::Get().ASurfaceTransactionStats_getPresentFenceFdFn( | 
|  | stats)); | 
|  | transaction_stats.latch_time = | 
|  | base::TimeTicks() + | 
|  | base::Nanoseconds( | 
|  | SurfaceControlMethods::Get().ASurfaceTransactionStats_getLatchTimeFn( | 
|  | stats)); | 
|  | if (transaction_stats.latch_time == base::TimeTicks()) | 
|  | transaction_stats.latch_time = base::TimeTicks::Now(); | 
|  |  | 
|  | ASurfaceControl** surface_controls = nullptr; | 
|  | size_t size = 0u; | 
|  | SurfaceControlMethods::Get().ASurfaceTransactionStats_getASurfaceControlsFn( | 
|  | stats, &surface_controls, &size); | 
|  | transaction_stats.surface_stats.resize(size); | 
|  | for (size_t i = 0u; i < size; ++i) { | 
|  | transaction_stats.surface_stats[i].surface = surface_controls[i]; | 
|  | int fence_fd = SurfaceControlMethods::Get() | 
|  | .ASurfaceTransactionStats_getPreviousReleaseFenceFdFn( | 
|  | stats, surface_controls[i]); | 
|  | if (fence_fd != -1) { | 
|  | transaction_stats.surface_stats[i].fence = base::ScopedFD(fence_fd); | 
|  | } | 
|  | } | 
|  | SurfaceControlMethods::Get() | 
|  | .ASurfaceTransactionStats_releaseASurfaceControlsFn(surface_controls); | 
|  |  | 
|  | return transaction_stats; | 
|  | } | 
|  |  | 
|  | struct TransactionAckCtx { | 
|  | int id = 0; | 
|  | SurfaceControl::Transaction::OnCompleteCb callback; | 
|  | SurfaceControl::Transaction::OnCommitCb latch_callback; | 
|  | }; | 
|  |  | 
|  | uint64_t GetTraceIdForTransaction(int transaction_id) { | 
|  | constexpr uint64_t kMask = | 
|  | base::MD5Hash64Constexpr("SurfaceControl::Transaction"); | 
|  | return kMask ^ transaction_id; | 
|  | } | 
|  |  | 
|  | // Note that the framework API states that this callback can be dispatched on | 
|  | // any thread (in practice it should be a binder thread). | 
|  | void OnTransactionCompletedOnAnyThread(void* context, | 
|  | ASurfaceTransactionStats* stats) { | 
|  | auto* ack_ctx = static_cast<TransactionAckCtx*>(context); | 
|  | auto transaction_stats = ToTransactionStats(stats); | 
|  | TRACE_EVENT_NESTABLE_ASYNC_END0("gpu,benchmark", "SurfaceControlTransaction", | 
|  | ack_ctx->id); | 
|  | TRACE_EVENT_WITH_FLOW0( | 
|  | "toplevel.flow", "gfx::SurfaceControlTransaction completed", | 
|  | GetTraceIdForTransaction(ack_ctx->id), TRACE_EVENT_FLAG_FLOW_IN); | 
|  |  | 
|  | std::move(ack_ctx->callback).Run(std::move(transaction_stats)); | 
|  | delete ack_ctx; | 
|  | } | 
|  |  | 
|  | // Note that the framework API states that this callback can be dispatched on | 
|  | // any thread (in practice it should be a binder thread). | 
|  | void OnTransactiOnCommittedOnAnyThread(void* context, | 
|  | ASurfaceTransactionStats* stats) { | 
|  | auto* ack_ctx = static_cast<TransactionAckCtx*>(context); | 
|  | TRACE_EVENT_INSTANT0("gpu,benchmark", "SurfaceControlTransaction committed", | 
|  | TRACE_EVENT_SCOPE_THREAD); | 
|  |  | 
|  | std::move(ack_ctx->latch_callback).Run(); | 
|  | delete ack_ctx; | 
|  | } | 
|  |  | 
|  | }  // namespace | 
|  |  | 
|  | // static | 
|  | bool SurfaceControl::IsSupported() { | 
|  | const auto* build_info = base::android::BuildInfo::GetInstance(); | 
|  |  | 
|  | // Disabled on Samsung devices due to a platform bug fixed in R. | 
|  | int min_sdk_version = base::android::SDK_VERSION_Q; | 
|  | if (base::EqualsCaseInsensitiveASCII(build_info->manufacturer(), "samsung")) | 
|  | min_sdk_version = base::android::SDK_VERSION_R; | 
|  |  | 
|  | if (build_info->sdk_int() < min_sdk_version) | 
|  | return false; | 
|  |  | 
|  | CHECK(SurfaceControlMethods::Get().supported); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool SurfaceControl::SupportsColorSpace(const gfx::ColorSpace& color_space) { | 
|  | return ColorSpaceToADataSpace(color_space) != ADATASPACE_UNKNOWN; | 
|  | } | 
|  |  | 
|  | uint64_t SurfaceControl::RequiredUsage() { | 
|  | if (!IsSupported()) | 
|  | return 0u; | 
|  | return g_agb_required_usage_bits; | 
|  | } | 
|  |  | 
|  | void SurfaceControl::EnableQualcommUBWC() { | 
|  | g_agb_required_usage_bits |= AHARDWAREBUFFER_USAGE_VENDOR_0; | 
|  | } | 
|  |  | 
|  | bool SurfaceControl::SupportsSetFrameRate() { | 
|  | // TODO(khushalsagar): Assert that this function is always available on R. | 
|  | return IsSupported() && | 
|  | SurfaceControlMethods::Get().ASurfaceTransaction_setFrameRateFn != | 
|  | nullptr; | 
|  | } | 
|  |  | 
|  | bool SurfaceControl::SupportsOnCommit() { | 
|  | return IsSupported() && | 
|  | SurfaceControlMethods::Get().ASurfaceTransaction_setOnCommitFn != | 
|  | nullptr; | 
|  | } | 
|  |  | 
|  | bool SurfaceControl::SupportsSetFrameTimeline() { | 
|  | return IsSupported() && | 
|  | SurfaceControlMethods::Get().ASurfaceTransaction_setFrameTimelineFn != | 
|  | nullptr; | 
|  | } | 
|  |  | 
|  | void SurfaceControl::SetStubImplementationForTesting() { | 
|  | SurfaceControlMethods::GetImpl(/*load_functions=*/false).InitWithStubs(); | 
|  | } | 
|  |  | 
|  | void SurfaceControl::ApplyTransaction(ASurfaceTransaction* transaction) { | 
|  | SurfaceControlMethods::Get().ASurfaceTransaction_applyFn(transaction); | 
|  | } | 
|  |  | 
|  | scoped_refptr<SurfaceControl::Surface> SurfaceControl::Surface::WrapUnowned( | 
|  | ASurfaceControl* surface) { | 
|  | scoped_refptr<SurfaceControl::Surface> result = | 
|  | base::MakeRefCounted<SurfaceControl::Surface>(); | 
|  | result->surface_ = surface; | 
|  | return result; | 
|  | } | 
|  |  | 
|  | SurfaceControl::Surface::Surface() = default; | 
|  |  | 
|  | SurfaceControl::Surface::Surface(const Surface& parent, const char* name) { | 
|  | owned_surface_ = SurfaceControlMethods::Get().ASurfaceControl_createFn( | 
|  | parent.surface(), name); | 
|  | if (!owned_surface_) | 
|  | LOG(ERROR) << "Failed to create ASurfaceControl : " << name; | 
|  | surface_ = owned_surface_; | 
|  | } | 
|  |  | 
|  | SurfaceControl::Surface::Surface(ANativeWindow* parent, const char* name) { | 
|  | owned_surface_ = | 
|  | SurfaceControlMethods::Get().ASurfaceControl_createFromWindowFn(parent, | 
|  | name); | 
|  | if (!owned_surface_) | 
|  | LOG(ERROR) << "Failed to create ASurfaceControl : " << name; | 
|  | surface_ = owned_surface_; | 
|  | } | 
|  |  | 
|  | SurfaceControl::Surface::~Surface() { | 
|  | if (owned_surface_) | 
|  | SurfaceControlMethods::Get().ASurfaceControl_releaseFn(owned_surface_); | 
|  | } | 
|  |  | 
|  | SurfaceControl::SurfaceStats::SurfaceStats() = default; | 
|  | SurfaceControl::SurfaceStats::~SurfaceStats() = default; | 
|  |  | 
|  | SurfaceControl::SurfaceStats::SurfaceStats(SurfaceStats&& other) = default; | 
|  | SurfaceControl::SurfaceStats& SurfaceControl::SurfaceStats::operator=( | 
|  | SurfaceStats&& other) = default; | 
|  |  | 
|  | SurfaceControl::TransactionStats::TransactionStats() = default; | 
|  | SurfaceControl::TransactionStats::~TransactionStats() = default; | 
|  |  | 
|  | SurfaceControl::TransactionStats::TransactionStats(TransactionStats&& other) = | 
|  | default; | 
|  | SurfaceControl::TransactionStats& SurfaceControl::TransactionStats::operator=( | 
|  | TransactionStats&& other) = default; | 
|  |  | 
|  | SurfaceControl::Transaction::Transaction() | 
|  | : id_(g_next_transaction_id.GetNext()) { | 
|  | transaction_ = SurfaceControlMethods::Get().ASurfaceTransaction_createFn(); | 
|  | DCHECK(transaction_); | 
|  | } | 
|  |  | 
|  | SurfaceControl::Transaction::~Transaction() { | 
|  | if (transaction_) | 
|  | SurfaceControlMethods::Get().ASurfaceTransaction_deleteFn(transaction_); | 
|  | } | 
|  |  | 
|  | SurfaceControl::Transaction::Transaction(Transaction&& other) | 
|  | : id_(other.id_), | 
|  | transaction_(other.transaction_), | 
|  | on_commit_cb_(std::move(other.on_commit_cb_)), | 
|  | on_complete_cb_(std::move(other.on_complete_cb_)) { | 
|  | other.transaction_ = nullptr; | 
|  | other.id_ = 0; | 
|  | } | 
|  |  | 
|  | SurfaceControl::Transaction& SurfaceControl::Transaction::operator=( | 
|  | Transaction&& other) { | 
|  | if (transaction_) | 
|  | SurfaceControlMethods::Get().ASurfaceTransaction_deleteFn(transaction_); | 
|  |  | 
|  | transaction_ = other.transaction_; | 
|  | id_ = other.id_; | 
|  | on_commit_cb_ = std::move(other.on_commit_cb_); | 
|  | on_complete_cb_ = std::move(other.on_complete_cb_); | 
|  |  | 
|  | other.transaction_ = nullptr; | 
|  | other.id_ = 0; | 
|  | return *this; | 
|  | } | 
|  |  | 
|  | void SurfaceControl::Transaction::SetVisibility(const Surface& surface, | 
|  | bool show) { | 
|  | SurfaceControlMethods::Get().ASurfaceTransaction_setVisibilityFn( | 
|  | transaction_, surface.surface(), show); | 
|  | } | 
|  |  | 
|  | void SurfaceControl::Transaction::SetZOrder(const Surface& surface, int32_t z) { | 
|  | SurfaceControlMethods::Get().ASurfaceTransaction_setZOrderFn( | 
|  | transaction_, surface.surface(), z); | 
|  | } | 
|  |  | 
|  | void SurfaceControl::Transaction::SetBuffer(const Surface& surface, | 
|  | AHardwareBuffer* buffer, | 
|  | base::ScopedFD fence_fd) { | 
|  | SurfaceControlMethods::Get().ASurfaceTransaction_setBufferFn( | 
|  | transaction_, surface.surface(), buffer, | 
|  | fence_fd.is_valid() ? fence_fd.release() : -1); | 
|  | } | 
|  |  | 
|  | void SurfaceControl::Transaction::SetGeometry(const Surface& surface, | 
|  | const gfx::Rect& src, | 
|  | const gfx::Rect& dst, | 
|  | gfx::OverlayTransform transform) { | 
|  | SurfaceControlMethods::Get().ASurfaceTransaction_setGeometryFn( | 
|  | transaction_, surface.surface(), RectToARect(src), RectToARect(dst), | 
|  | OverlayTransformToWindowTransform(transform)); | 
|  | } | 
|  |  | 
|  | void SurfaceControl::Transaction::SetPosition(const Surface& surface, | 
|  | const gfx::Point& position) { | 
|  | CHECK(SurfaceControlMethods::Get().ASurfaceTransaction_setPositionFn); | 
|  | SurfaceControlMethods::Get().ASurfaceTransaction_setPositionFn( | 
|  | transaction_, surface.surface(), position.x(), position.y()); | 
|  | } | 
|  |  | 
|  | void SurfaceControl::Transaction::SetScale(const Surface& surface, | 
|  | const float sx, | 
|  | float sy) { | 
|  | CHECK(SurfaceControlMethods::Get().ASurfaceTransaction_setScaleFn); | 
|  | SurfaceControlMethods::Get().ASurfaceTransaction_setScaleFn( | 
|  | transaction_, surface.surface(), sx, sy); | 
|  | } | 
|  |  | 
|  | void SurfaceControl::Transaction::SetCrop(const Surface& surface, | 
|  | const gfx::Rect& rect) { | 
|  | CHECK(SurfaceControlMethods::Get().ASurfaceTransaction_setCropFn); | 
|  | SurfaceControlMethods::Get().ASurfaceTransaction_setCropFn( | 
|  | transaction_, surface.surface(), RectToARect(rect)); | 
|  | } | 
|  |  | 
|  | void SurfaceControl::Transaction::SetFrameTimelineId(int64_t vsync_id) { | 
|  | CHECK(SurfaceControlMethods::Get().ASurfaceTransaction_setFrameTimelineFn); | 
|  | SurfaceControlMethods::Get().ASurfaceTransaction_setFrameTimelineFn( | 
|  | transaction_, vsync_id); | 
|  | } | 
|  |  | 
|  | void SurfaceControl::Transaction::SetOpaque(const Surface& surface, | 
|  | bool opaque) { | 
|  | int8_t transparency = opaque ? ASURFACE_TRANSACTION_TRANSPARENCY_OPAQUE | 
|  | : ASURFACE_TRANSACTION_TRANSPARENCY_TRANSLUCENT; | 
|  | SurfaceControlMethods::Get().ASurfaceTransaction_setBufferTransparencyFn( | 
|  | transaction_, surface.surface(), transparency); | 
|  | } | 
|  |  | 
|  | void SurfaceControl::Transaction::SetDamageRect(const Surface& surface, | 
|  | const gfx::Rect& rect) { | 
|  | auto a_rect = RectToARect(rect); | 
|  | SurfaceControlMethods::Get().ASurfaceTransaction_setDamageRegionFn( | 
|  | transaction_, surface.surface(), &a_rect, 1u); | 
|  | } | 
|  |  | 
|  | void SurfaceControl::Transaction::SetColorSpace( | 
|  | const Surface& surface, | 
|  | const gfx::ColorSpace& color_space) { | 
|  | auto data_space = ColorSpaceToADataSpace(color_space); | 
|  |  | 
|  | // Log the data space in crash keys for debugging crbug.com/997592. | 
|  | static auto* kCrashKey = base::debug::AllocateCrashKeyString( | 
|  | "data_space_for_buffer", base::debug::CrashKeySize::Size256); | 
|  | auto crash_key_value = base::NumberToString(data_space); | 
|  | base::debug::ScopedCrashKeyString scoped_crash_key(kCrashKey, | 
|  | crash_key_value); | 
|  |  | 
|  | SurfaceControlMethods::Get().ASurfaceTransaction_setBufferDataSpaceFn( | 
|  | transaction_, surface.surface(), data_space); | 
|  | } | 
|  |  | 
|  | void SurfaceControl::Transaction::SetHDRMetadata( | 
|  |  | 
|  | const Surface& surface, | 
|  | const absl::optional<HDRMetadata>& metadata) { | 
|  | if (metadata) { | 
|  | AHdrMetadata_cta861_3 cta861_3 = { | 
|  | .maxContentLightLevel = | 
|  | static_cast<float>(metadata->max_content_light_level), | 
|  | .maxFrameAverageLightLevel = | 
|  | static_cast<float>(metadata->max_frame_average_light_level)}; | 
|  |  | 
|  | AHdrMetadata_smpte2086 smpte2086 = { | 
|  | .displayPrimaryRed = | 
|  | {.x = metadata->color_volume_metadata.primary_r.x(), | 
|  | .y = metadata->color_volume_metadata.primary_r.y()}, | 
|  | .displayPrimaryGreen = | 
|  | {.x = metadata->color_volume_metadata.primary_g.x(), | 
|  | .y = metadata->color_volume_metadata.primary_g.y()}, | 
|  | .displayPrimaryBlue = | 
|  | {.x = metadata->color_volume_metadata.primary_b.x(), | 
|  | .y = metadata->color_volume_metadata.primary_b.y()}, | 
|  | .whitePoint = {.x = metadata->color_volume_metadata.white_point.x(), | 
|  | .y = metadata->color_volume_metadata.white_point.y()}, | 
|  | .maxLuminance = metadata->color_volume_metadata.luminance_max, | 
|  | .minLuminance = metadata->color_volume_metadata.luminance_min}; | 
|  |  | 
|  | SurfaceControlMethods::Get().ASurfaceTransaction_setHdrMetadata_cta861_3Fn( | 
|  | transaction_, surface.surface(), &cta861_3); | 
|  | SurfaceControlMethods::Get().ASurfaceTransaction_setHdrMetadata_smpte2086Fn( | 
|  | transaction_, surface.surface(), &smpte2086); | 
|  | } else { | 
|  | SurfaceControlMethods::Get().ASurfaceTransaction_setHdrMetadata_cta861_3Fn( | 
|  | transaction_, surface.surface(), nullptr); | 
|  | SurfaceControlMethods::Get().ASurfaceTransaction_setHdrMetadata_smpte2086Fn( | 
|  | transaction_, surface.surface(), nullptr); | 
|  | } | 
|  | } | 
|  |  | 
|  | void SurfaceControl::Transaction::SetFrameRate(const Surface& surface, | 
|  | float frame_rate) { | 
|  | DCHECK(SupportsSetFrameRate()); | 
|  |  | 
|  | // We always used fixed source here since a non-default value is only used for | 
|  | // videos which have a fixed playback rate. | 
|  | SurfaceControlMethods::Get().ASurfaceTransaction_setFrameRateFn( | 
|  | transaction_, surface.surface(), frame_rate, | 
|  | ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_FIXED_SOURCE); | 
|  | } | 
|  |  | 
|  | void SurfaceControl::Transaction::SetParent(const Surface& surface, | 
|  | Surface* new_parent) { | 
|  | SurfaceControlMethods::Get().ASurfaceTransaction_reparentFn( | 
|  | transaction_, surface.surface(), | 
|  | new_parent ? new_parent->surface() : nullptr); | 
|  | } | 
|  |  | 
|  | void SurfaceControl::Transaction::SetOnCompleteCb( | 
|  | OnCompleteCb cb, | 
|  | scoped_refptr<base::SingleThreadTaskRunner> task_runner) { | 
|  | TRACE_EVENT_WITH_FLOW0( | 
|  | "toplevel.flow", "gfx::SurfaceControl::Transaction::SetOnCompleteCb", | 
|  | GetTraceIdForTransaction(id_), TRACE_EVENT_FLAG_FLOW_OUT); | 
|  |  | 
|  | DCHECK(!on_complete_cb_); | 
|  | on_complete_cb_ = base::BindPostTask(std::move(task_runner), std::move(cb)); | 
|  | } | 
|  |  | 
|  | void SurfaceControl::Transaction::SetOnCommitCb( | 
|  | OnCommitCb cb, | 
|  | scoped_refptr<base::SingleThreadTaskRunner> task_runner) { | 
|  | DCHECK(!on_commit_cb_); | 
|  | on_commit_cb_ = base::BindPostTask(std::move(task_runner), std::move(cb)); | 
|  | } | 
|  |  | 
|  | void SurfaceControl::Transaction::Apply() { | 
|  | TRACE_EVENT_NESTABLE_ASYNC_BEGIN0("gpu,benchmark", | 
|  | "SurfaceControlTransaction", id_); | 
|  |  | 
|  | PrepareCallbacks(); | 
|  | SurfaceControlMethods::Get().ASurfaceTransaction_applyFn(transaction_); | 
|  | } | 
|  |  | 
|  | ASurfaceTransaction* SurfaceControl::Transaction::GetTransaction() { | 
|  | PrepareCallbacks(); | 
|  | return transaction_; | 
|  | } | 
|  |  | 
|  | void SurfaceControl::Transaction::PrepareCallbacks() { | 
|  | if (on_commit_cb_) { | 
|  | TransactionAckCtx* ack_ctx = new TransactionAckCtx; | 
|  | ack_ctx->latch_callback = std::move(on_commit_cb_); | 
|  | ack_ctx->id = id_; | 
|  |  | 
|  | SurfaceControlMethods::Get().ASurfaceTransaction_setOnCommitFn( | 
|  | transaction_, ack_ctx, &OnTransactiOnCommittedOnAnyThread); | 
|  | } | 
|  |  | 
|  | if (on_complete_cb_) { | 
|  | TransactionAckCtx* ack_ctx = new TransactionAckCtx; | 
|  | ack_ctx->callback = std::move(on_complete_cb_); | 
|  | ack_ctx->id = id_; | 
|  |  | 
|  | SurfaceControlMethods::Get().ASurfaceTransaction_setOnCompleteFn( | 
|  | transaction_, ack_ctx, &OnTransactionCompletedOnAnyThread); | 
|  | } | 
|  | } | 
|  |  | 
|  | }  // namespace gfx |