blob: a92788e7240f67ac970e023b9de796db0bdb55ee [file] [log] [blame]
// 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 <dlfcn.h>
#include "base/android/build_info.h"
#include "base/atomic_sequence_num.h"
#include "base/bind.h"
#include "base/bind_post_task.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/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,
};
// ANativeWindow_FrameRateCompatibility enums
enum {
ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT = 0,
ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_FIXED_SOURCE = 1
};
// 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_setFrameRate =
void (*)(ASurfaceTransaction* transaction,
ASurfaceControl* surface_control,
float frameRate,
int8_t compatibility);
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_MAYBE(main_dl_handle, ASurfaceTransaction_setFrameRate);
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_setFrameRate ASurfaceTransaction_setFrameRateFn;
// 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;
}
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::CreateSCRGBLinear())
return ADATASPACE_SCRGB_LINEAR;
if (color_space == gfx::ColorSpace::CreateDisplayP3D65())
return ADATASPACE_DISPLAY_P3;
// TODO(khushalsagar): Check if we can support BT2020 using
// ADATASPACE_BT2020_PQ.
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;
}
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::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::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