Skip to content

Commit

Permalink
AHardwareBuffer-based GpuMemoryBuffer implementation
Browse files Browse the repository at this point in the history
AHardwareBuffer support is included on Android O and up. The NDK
functions are included as of platform level 26, but Chromium currently
doesn't use this as the target level, so we have to use dynamic
loading to get the symbols at runtime.

This is encapsulated in gfx::AndroidHardwareBufferCompat which makes
it a bit easier to work with them across Android versions.

The implementation adds a new ANDROID_HARDWARE_BUFFER subtype to the
SharedMemoryHandle Android implementation in addition to the pre-existing
ashmem support, including IPC transport via a SocketPair. It uses one end
to write the native object using a NDK call, and the other end is a file
descriptor sendable via usual IPC methods from which the receiver can fetch
the object.

BUG=761432

Cq-Include-Trybots: master.tryserver.chromium.android:android_optional_gpu_tests_rel;master.tryserver.chromium.linux:linux_optional_gpu_tests_rel;master.tryserver.chromium.mac:mac_optional_gpu_tests_rel;master.tryserver.chromium.win:win_optional_gpu_tests_rel
Change-Id: I9edfa733ffccea21dd58a3940aa96cb6955c8f09
Reviewed-on: https://chromium-review.googlesource.com/680100
Commit-Queue: Klaus Weidner <klausw@chromium.org>
Reviewed-by: Daniel Cheng <dcheng@chromium.org>
Reviewed-by: Mark Mentovai <mark@chromium.org>
Reviewed-by: Ken Rockot <rockot@chromium.org>
Reviewed-by: Kenneth Russell <kbr@chromium.org>
Reviewed-by: David Reveman <reveman@chromium.org>
Cr-Commit-Position: refs/heads/master@{#513710}
  • Loading branch information
klausw authored and Commit Bot committed Nov 3, 2017
1 parent d86db31 commit 3824a88
Show file tree
Hide file tree
Showing 31 changed files with 1,272 additions and 42 deletions.
8 changes: 7 additions & 1 deletion base/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,9 @@ jumbo_component("base") {
"allocator/allocator_shim.h",
"allocator/malloc_zone_functions_mac.cc",
"allocator/malloc_zone_functions_mac.h",
"android/android_hardware_buffer_abi.h",
"android/android_hardware_buffer_compat.cc",
"android/android_hardware_buffer_compat.h",
"android/animation_frame_time_histogram.cc",
"android/apk_assets.cc",
"android/apk_assets.h",
Expand Down Expand Up @@ -509,6 +512,7 @@ jumbo_component("base") {
"memory/shared_memory_android.cc",
"memory/shared_memory_handle.cc",
"memory/shared_memory_handle.h",
"memory/shared_memory_handle_android.cc",
"memory/shared_memory_handle_mac.cc",
"memory/shared_memory_handle_win.cc",
"memory/shared_memory_helper.cc",
Expand Down Expand Up @@ -1118,7 +1122,9 @@ jumbo_component("base") {
}
}

if (!is_mac && is_posix) {
# MacOS and Android have their own custom shared memory implementations due
# to supporting both POSIX and native handles.
if (is_posix && !is_mac && !is_android) {
sources += [ "memory/shared_memory_handle_posix.cc" ]
}

Expand Down
90 changes: 90 additions & 0 deletions base/android/android_hardware_buffer_abi.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
// Copyright 2017 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.

#ifndef BASE_ANDROID_ANDROID_HARDWARE_BUFFER_ABI_H_
#define BASE_ANDROID_ANDROID_HARDWARE_BUFFER_ABI_H_

// Minimal binary interface definitions for AHardwareBuffer based on
// include/android/hardware_buffer.h from the Android NDK for platform level
// 26+. This is only intended for use from the AndroidHardwareBufferCompat
// wrapper for building without NDK platform level support, it is not a
// general-use header and is not complete.
//
// TODO(crbug.com/771171): Delete this file when third_party/android_tools/ndk/
// is updated to a version that contains the android/hardware_buffer.h file.
//
// Please refer to the API documentation for details:
// https://developer.android.com/ndk/reference/hardware__buffer_8h.html

#include <stdint.h>

// Use "C" linkage to match the original header file. This isn't strictly
// required since the file is not declaring global functions, but the types
// should remain in the global namespace for compatibility, and it's a reminder
// that forward declarations elsewhere should use "extern "C" to avoid
// namespace issues.
extern "C" {

typedef struct AHardwareBuffer AHardwareBuffer;
typedef struct ARect ARect;

enum {
AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM = 1,
AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM = 2,
AHARDWAREBUFFER_FORMAT_R8G8B8_UNORM = 3,
AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM = 4,
AHARDWAREBUFFER_FORMAT_R16G16B16A16_FLOAT = 0x16,
AHARDWAREBUFFER_FORMAT_R10G10B10A2_UNORM = 0x2b,
AHARDWAREBUFFER_FORMAT_BLOB = 0x21,
};

enum {
AHARDWAREBUFFER_USAGE_CPU_READ_NEVER = 0UL,
AHARDWAREBUFFER_USAGE_CPU_READ_RARELY = 2UL,
AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN = 3UL,
AHARDWAREBUFFER_USAGE_CPU_READ_MASK = 0xFUL,
AHARDWAREBUFFER_USAGE_CPU_WRITE_NEVER = 0UL << 4,
AHARDWAREBUFFER_USAGE_CPU_WRITE_RARELY = 2UL << 4,
AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN = 3UL << 4,
AHARDWAREBUFFER_USAGE_CPU_WRITE_MASK = 0xFUL << 4,
AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE = 1UL << 8,
AHARDWAREBUFFER_USAGE_GPU_COLOR_OUTPUT = 1UL << 9,
AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT = 1UL << 14,
AHARDWAREBUFFER_USAGE_VIDEO_ENCODE = 1UL << 16,
AHARDWAREBUFFER_USAGE_SENSOR_DIRECT_DATA = 1UL << 23,
AHARDWAREBUFFER_USAGE_GPU_DATA_BUFFER = 1UL << 24,
};

typedef struct AHardwareBuffer_Desc {
uint32_t width;
uint32_t height;
uint32_t layers;
uint32_t format;
uint64_t usage;
uint32_t stride;
uint32_t rfu0;
uint64_t rfu1;
} AHardwareBuffer_Desc;

using PFAHardwareBuffer_allocate = void (*)(const AHardwareBuffer_Desc* desc,
AHardwareBuffer** outBuffer);
using PFAHardwareBuffer_acquire = void (*)(AHardwareBuffer* buffer);
using PFAHardwareBuffer_describe = void (*)(const AHardwareBuffer* buffer,
AHardwareBuffer_Desc* outDesc);
using PFAHardwareBuffer_lock = int (*)(AHardwareBuffer* buffer,
uint64_t usage,
int32_t fence,
const ARect* rect,
void** outVirtualAddress);
using PFAHardwareBuffer_recvHandleFromUnixSocket =
int (*)(int socketFd, AHardwareBuffer** outBuffer);
using PFAHardwareBuffer_release = void (*)(AHardwareBuffer* buffer);
using PFAHardwareBuffer_sendHandleToUnixSocket =
int (*)(const AHardwareBuffer* buffer, int socketFd);
using PFAHardwareBuffer_unlock = int (*)(AHardwareBuffer* buffer,
int32_t* fence);

} // extern "C"

#endif // BASE_ANDROID_ANDROID_HARDWARE_BUFFER_ABI_H_
129 changes: 129 additions & 0 deletions base/android/android_hardware_buffer_compat.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
// Copyright 2017 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 "base/android/android_hardware_buffer_compat.h"

#include "base/android/build_info.h"
#include "base/lazy_instance.h"
#include "base/logging.h"

#include <dlfcn.h>

namespace base {

namespace {

static base::LazyInstance<AndroidHardwareBufferCompat>::Leaky g_compat =
LAZY_INSTANCE_INITIALIZER;

} // namespace

AndroidHardwareBufferCompat::AndroidHardwareBufferCompat() {
DCHECK(IsSupportAvailable());

// TODO(klausw): If the Chromium build requires __ANDROID_API__ >= 26 at some
// point in the future, we could directly use the global functions instead of
// dynamic loading. However, since this would be incompatible with pre-Oreo
// devices, this is unlikely to happen in the foreseeable future, so just
// unconditionally use dynamic loading.

// cf. base/android/linker/modern_linker_jni.cc
void* main_dl_handle = dlopen(nullptr, RTLD_NOW);

*reinterpret_cast<void**>(&allocate_) =
dlsym(main_dl_handle, "AHardwareBuffer_allocate");
DCHECK(allocate_);

*reinterpret_cast<void**>(&acquire_) =
dlsym(main_dl_handle, "AHardwareBuffer_acquire");
DCHECK(acquire_);

*reinterpret_cast<void**>(&describe_) =
dlsym(main_dl_handle, "AHardwareBuffer_describe");
DCHECK(describe_);

*reinterpret_cast<void**>(&lock_) =
dlsym(main_dl_handle, "AHardwareBuffer_lock");
DCHECK(lock_);

*reinterpret_cast<void**>(&recv_handle_) =
dlsym(main_dl_handle, "AHardwareBuffer_recvHandleFromUnixSocket");
DCHECK(recv_handle_);

*reinterpret_cast<void**>(&release_) =
dlsym(main_dl_handle, "AHardwareBuffer_release");
DCHECK(release_);

*reinterpret_cast<void**>(&send_handle_) =
dlsym(main_dl_handle, "AHardwareBuffer_sendHandleToUnixSocket");
DCHECK(send_handle_);

*reinterpret_cast<void**>(&unlock_) =
dlsym(main_dl_handle, "AHardwareBuffer_unlock");
DCHECK(unlock_);
}

// static
bool AndroidHardwareBufferCompat::IsSupportAvailable() {
return base::android::BuildInfo::GetInstance()->sdk_int() >=
base::android::SDK_VERSION_OREO;
}

// static
AndroidHardwareBufferCompat AndroidHardwareBufferCompat::GetInstance() {
return g_compat.Get();
}

void AndroidHardwareBufferCompat::Allocate(const AHardwareBuffer_Desc* desc,
AHardwareBuffer** out_buffer) {
DCHECK(IsSupportAvailable());
allocate_(desc, out_buffer);
}

void AndroidHardwareBufferCompat::Acquire(AHardwareBuffer* buffer) {
DCHECK(IsSupportAvailable());
acquire_(buffer);
}

void AndroidHardwareBufferCompat::Describe(const AHardwareBuffer* buffer,
AHardwareBuffer_Desc* out_desc) {
DCHECK(IsSupportAvailable());
describe_(buffer, out_desc);
}

int AndroidHardwareBufferCompat::Lock(AHardwareBuffer* buffer,
uint64_t usage,
int32_t fence,
const ARect* rect,
void** out_virtual_address) {
DCHECK(IsSupportAvailable());
return lock_(buffer, usage, fence, rect, out_virtual_address);
}

int AndroidHardwareBufferCompat::RecvHandleFromUnixSocket(
int socket_fd,
AHardwareBuffer** out_buffer) {
DCHECK(IsSupportAvailable());
return recv_handle_(socket_fd, out_buffer);
}

void AndroidHardwareBufferCompat::Release(AHardwareBuffer* buffer) {
DCHECK(IsSupportAvailable());
release_(buffer);
}

int AndroidHardwareBufferCompat::SendHandleToUnixSocket(
const AHardwareBuffer* buffer,
int socket_fd) {
DCHECK(IsSupportAvailable());
return send_handle_(buffer, socket_fd);
}

int AndroidHardwareBufferCompat::Unlock(AHardwareBuffer* buffer,
int32_t* fence) {
DCHECK(IsSupportAvailable());
return unlock_(buffer, fence);
}

} // namespace base
51 changes: 51 additions & 0 deletions base/android/android_hardware_buffer_compat.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// Copyright 2017 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.

#ifndef BASE_ANDROID_ANDROID_HARDWARE_BUFFER_COMPAT_H_
#define BASE_ANDROID_ANDROID_HARDWARE_BUFFER_COMPAT_H_

#include "base/android/android_hardware_buffer_abi.h"
#include "base/base_export.h"
#include "base/lazy_instance.h"

namespace base {

// This class provides runtime support for working with AHardwareBuffer objects
// on Android O systems without requiring building for the Android O NDK level.
// Don't call GetInstance() unless IsSupportAvailable() returns true.
class BASE_EXPORT AndroidHardwareBufferCompat {
public:
static bool IsSupportAvailable();
static AndroidHardwareBufferCompat GetInstance();

void Allocate(const AHardwareBuffer_Desc* desc, AHardwareBuffer** outBuffer);
void Acquire(AHardwareBuffer* buffer);
void Describe(const AHardwareBuffer* buffer, AHardwareBuffer_Desc* outDesc);
int Lock(AHardwareBuffer* buffer,
uint64_t usage,
int32_t fence,
const ARect* rect,
void** out_virtual_address);
int RecvHandleFromUnixSocket(int socketFd, AHardwareBuffer** outBuffer);
void Release(AHardwareBuffer* buffer);
int SendHandleToUnixSocket(const AHardwareBuffer* buffer, int socketFd);
int Unlock(AHardwareBuffer* buffer, int32_t* fence);

private:
friend struct base::LazyInstanceTraitsBase<AndroidHardwareBufferCompat>;
AndroidHardwareBufferCompat();

PFAHardwareBuffer_allocate allocate_;
PFAHardwareBuffer_acquire acquire_;
PFAHardwareBuffer_describe describe_;
PFAHardwareBuffer_lock lock_;
PFAHardwareBuffer_recvHandleFromUnixSocket recv_handle_;
PFAHardwareBuffer_release release_;
PFAHardwareBuffer_sendHandleToUnixSocket send_handle_;
PFAHardwareBuffer_unlock unlock_;
};

} // namespace base

#endif // BASE_ANDROID_ANDROID_HARDWARE_BUFFER_COMPAT_H_
3 changes: 2 additions & 1 deletion base/android/build_info.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ enum SdkVersion {
SDK_VERSION_LOLLIPOP_MR1 = 22,
SDK_VERSION_MARSHMALLOW = 23,
SDK_VERSION_NOUGAT = 24,
SDK_VERSION_NOUGAT_MR1 = 25
SDK_VERSION_NOUGAT_MR1 = 25,
SDK_VERSION_OREO = 26,
};

// BuildInfo is a singleton class that stores android build and device
Expand Down
Loading

0 comments on commit 3824a88

Please sign in to comment.