From 3824a888dd6ed3014445573d0944508f10318b9a Mon Sep 17 00:00:00 2001 From: Klaus Weidner Date: Fri, 3 Nov 2017 06:24:57 +0000 Subject: [PATCH] AHardwareBuffer-based GpuMemoryBuffer implementation 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 Reviewed-by: Daniel Cheng Reviewed-by: Mark Mentovai Reviewed-by: Ken Rockot Reviewed-by: Kenneth Russell Reviewed-by: David Reveman Cr-Commit-Position: refs/heads/master@{#513710} --- base/BUILD.gn | 8 +- base/android/android_hardware_buffer_abi.h | 90 +++++++++ .../android/android_hardware_buffer_compat.cc | 129 ++++++++++++ base/android/android_hardware_buffer_compat.h | 51 +++++ base/android/build_info.h | 3 +- base/memory/shared_memory_handle.h | 91 ++++++--- base/memory/shared_memory_handle_android.cc | 187 ++++++++++++++++++ gpu/BUILD.gn | 4 + gpu/ipc/client/BUILD.gn | 6 + gpu/ipc/client/gpu_memory_buffer_impl.cc | 9 + ...ory_buffer_impl_android_hardware_buffer.cc | 156 +++++++++++++++ ...mory_buffer_impl_android_hardware_buffer.h | 66 +++++++ ...r_impl_android_hardware_buffer_unittest.cc | 20 ++ gpu/ipc/common/gpu_memory_buffer_support.cc | 24 +++ gpu/ipc/host/gpu_memory_buffer_support.cc | 7 +- gpu/ipc/service/BUILD.gn | 2 + gpu/ipc/service/gpu_memory_buffer_factory.cc | 6 + ..._buffer_factory_android_hardware_buffer.cc | 82 ++++++++ ...y_buffer_factory_android_hardware_buffer.h | 58 ++++++ ipc/ipc_message_utils.cc | 49 ++++- ipc/ipc_message_utils.h | 14 +- ui/gfx/gpu_memory_buffer.cc | 7 + ui/gfx/gpu_memory_buffer.h | 3 +- ui/gfx/mojo/buffer_types.mojom | 2 +- ui/gfx/mojo/buffer_types_struct_traits.cc | 6 +- ui/gfx/mojo/buffer_types_struct_traits.h | 7 +- ui/gl/BUILD.gn | 11 ++ ui/gl/gl_image_ahardwarebuffer.cc | 46 +++++ ui/gl/gl_image_ahardwarebuffer.h | 44 +++++ ui/gl/gl_image_ahardwarebuffer_unittest.cc | 125 ++++++++++++ ui/gl/gl_image_egl.h | 1 + 31 files changed, 1272 insertions(+), 42 deletions(-) create mode 100644 base/android/android_hardware_buffer_abi.h create mode 100644 base/android/android_hardware_buffer_compat.cc create mode 100644 base/android/android_hardware_buffer_compat.h create mode 100644 base/memory/shared_memory_handle_android.cc create mode 100644 gpu/ipc/client/gpu_memory_buffer_impl_android_hardware_buffer.cc create mode 100644 gpu/ipc/client/gpu_memory_buffer_impl_android_hardware_buffer.h create mode 100644 gpu/ipc/client/gpu_memory_buffer_impl_android_hardware_buffer_unittest.cc create mode 100644 gpu/ipc/service/gpu_memory_buffer_factory_android_hardware_buffer.cc create mode 100644 gpu/ipc/service/gpu_memory_buffer_factory_android_hardware_buffer.h create mode 100644 ui/gl/gl_image_ahardwarebuffer.cc create mode 100644 ui/gl/gl_image_ahardwarebuffer.h create mode 100644 ui/gl/gl_image_ahardwarebuffer_unittest.cc diff --git a/base/BUILD.gn b/base/BUILD.gn index 164d39f2f68602..1f94988635c5dc 100644 --- a/base/BUILD.gn +++ b/base/BUILD.gn @@ -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", @@ -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", @@ -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" ] } diff --git a/base/android/android_hardware_buffer_abi.h b/base/android/android_hardware_buffer_abi.h new file mode 100644 index 00000000000000..c44ea9eba87395 --- /dev/null +++ b/base/android/android_hardware_buffer_abi.h @@ -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 + +// 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_ diff --git a/base/android/android_hardware_buffer_compat.cc b/base/android/android_hardware_buffer_compat.cc new file mode 100644 index 00000000000000..70f058947bf13d --- /dev/null +++ b/base/android/android_hardware_buffer_compat.cc @@ -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 + +namespace base { + +namespace { + +static base::LazyInstance::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(&allocate_) = + dlsym(main_dl_handle, "AHardwareBuffer_allocate"); + DCHECK(allocate_); + + *reinterpret_cast(&acquire_) = + dlsym(main_dl_handle, "AHardwareBuffer_acquire"); + DCHECK(acquire_); + + *reinterpret_cast(&describe_) = + dlsym(main_dl_handle, "AHardwareBuffer_describe"); + DCHECK(describe_); + + *reinterpret_cast(&lock_) = + dlsym(main_dl_handle, "AHardwareBuffer_lock"); + DCHECK(lock_); + + *reinterpret_cast(&recv_handle_) = + dlsym(main_dl_handle, "AHardwareBuffer_recvHandleFromUnixSocket"); + DCHECK(recv_handle_); + + *reinterpret_cast(&release_) = + dlsym(main_dl_handle, "AHardwareBuffer_release"); + DCHECK(release_); + + *reinterpret_cast(&send_handle_) = + dlsym(main_dl_handle, "AHardwareBuffer_sendHandleToUnixSocket"); + DCHECK(send_handle_); + + *reinterpret_cast(&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 diff --git a/base/android/android_hardware_buffer_compat.h b/base/android/android_hardware_buffer_compat.h new file mode 100644 index 00000000000000..14be3d5b9c8aa7 --- /dev/null +++ b/base/android/android_hardware_buffer_compat.h @@ -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(); + + 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_ diff --git a/base/android/build_info.h b/base/android/build_info.h index 163f70eb5aafc2..52aec78fee4246 100644 --- a/base/android/build_info.h +++ b/base/android/build_info.h @@ -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 diff --git a/base/memory/shared_memory_handle.h b/base/memory/shared_memory_handle.h index f719aeb9b245dd..c4e140e612636a 100644 --- a/base/memory/shared_memory_handle.h +++ b/base/memory/shared_memory_handle.h @@ -24,6 +24,10 @@ #include "base/file_descriptor_posix.h" #endif +#if defined(OS_ANDROID) +extern "C" typedef struct AHardwareBuffer AHardwareBuffer; +#endif + namespace base { // SharedMemoryHandle is the smallest possible IPC-transportable "reference" to @@ -82,26 +86,6 @@ class BASE_EXPORT SharedMemoryHandle { MACH, }; - // Constructs a SharedMemoryHandle backed by the components of a - // FileDescriptor. The newly created instance has the same ownership semantics - // as base::FileDescriptor. This typically means that the SharedMemoryHandle - // takes ownership of the |fd| if |auto_close| is true. Unfortunately, it's - // common for existing code to make shallow copies of SharedMemoryHandle, and - // the one that is finally passed into a base::SharedMemory is the one that - // "consumes" the fd. - // |guid| uniquely identifies the shared memory region pointed to by the - // underlying OS resource. If |file_descriptor| is associated with another - // SharedMemoryHandle, the caller must pass the |guid| of that - // SharedMemoryHandle. Otherwise, the caller should generate a new - // UnguessableToken. - // |size| refers to the size of the memory region pointed to by - // file_descriptor.fd. Passing the wrong |size| has no immediate consequence, - // but may cause errors when trying to map the SharedMemoryHandle at a later - // point in time. - SharedMemoryHandle(const base::FileDescriptor& file_descriptor, - size_t size, - const base::UnguessableToken& guid); - // Makes a Mach-based SharedMemoryHandle of the given size. On error, // subsequent calls to IsValid() return false. // Passing the wrong |size| has no immediate consequence, but may cause errors @@ -150,17 +134,6 @@ class BASE_EXPORT SharedMemoryHandle { SharedMemoryHandle(HANDLE h, size_t size, const base::UnguessableToken& guid); HANDLE GetHandle() const; #else - // |guid| uniquely identifies the shared memory region pointed to by the - // underlying OS resource. If |file_descriptor| is associated with another - // SharedMemoryHandle, the caller must pass the |guid| of that - // SharedMemoryHandle. Otherwise, the caller should generate a new - // UnguessableToken. - // Passing the wrong |size| has no immediate consequence, but may cause errors - // when trying to map the SharedMemoryHandle at a later point in time. - SharedMemoryHandle(const base::FileDescriptor& file_descriptor, - size_t size, - const base::UnguessableToken& guid); - // Creates a SharedMemoryHandle from an |fd| supplied from an external // service. // Passing the wrong |size| has no immediate consequence, but may cause errors @@ -175,6 +148,54 @@ class BASE_EXPORT SharedMemoryHandle { int Release(); #endif +#if defined(OS_ANDROID) + enum class Type { + // The SharedMemoryHandle is not backed by a handle. This is used for + // a default-constructed SharedMemoryHandle() or for a failed duplicate. + // The other types are assumed to be valid. + INVALID, + // The SharedMemoryHandle is backed by a valid fd for ashmem. + ASHMEM, + // The SharedMemoryHandle is backed by a valid AHardwareBuffer object. + ANDROID_HARDWARE_BUFFER, + + LAST = ANDROID_HARDWARE_BUFFER + }; + Type GetType() const { return type_; } + SharedMemoryHandle(AHardwareBuffer* buffer, + size_t size, + const base::UnguessableToken& guid); + // Constructs a handle from file descriptor and type. Both ASHMEM and + // AHardwareBuffer types are transported via file descriptor for IPC, so the + // type field is needed to distinguish them. The generic file descriptor + // constructor below assumes type ASHMEM. + SharedMemoryHandle(Type type, + const base::FileDescriptor& file_descriptor, + size_t size, + const base::UnguessableToken& guid); + AHardwareBuffer* GetMemoryObject() const; +#endif + +#if defined(OS_POSIX) && !defined(OS_FUCHSIA) + // Constructs a SharedMemoryHandle backed by a FileDescriptor. The newly + // created instance has the same ownership semantics as base::FileDescriptor. + // This typically means that the SharedMemoryHandle takes ownership of the + // |fd| if |auto_close| is true. Unfortunately, it's common for existing code + // to make shallow copies of SharedMemoryHandle, and the one that is finally + // passed into a base::SharedMemory is the one that "consumes" the fd. + // + // |guid| uniquely identifies the shared memory region pointed to by the + // underlying OS resource. If |file_descriptor| is associated with another + // SharedMemoryHandle, the caller must pass the |guid| of that + // SharedMemoryHandle. Otherwise, the caller should generate a new + // UnguessableToken. + // Passing the wrong |size| has no immediate consequence, but may cause errors + // when trying to map the SharedMemoryHandle at a later point in time. + SharedMemoryHandle(const base::FileDescriptor& file_descriptor, + size_t size, + const base::UnguessableToken& guid); +#endif + private: #if defined(OS_MACOSX) && !defined(OS_IOS) friend class SharedMemory; @@ -196,6 +217,14 @@ class BASE_EXPORT SharedMemoryHandle { bool ownership_passes_to_ipc_ = false; }; }; +#elif defined(OS_ANDROID) + // Each instance of a SharedMemoryHandle is either INVALID, or backed by an + // ashmem fd, or backed by an AHardwareBuffer. |type_| determines the backing + // member. + Type type_ = Type::INVALID; + FileDescriptor file_descriptor_; + AHardwareBuffer* memory_object_ = nullptr; + bool ownership_passes_to_ipc_ = false; #elif defined(OS_FUCHSIA) zx_handle_t handle_ = ZX_HANDLE_INVALID; bool ownership_passes_to_ipc_ = false; diff --git a/base/memory/shared_memory_handle_android.cc b/base/memory/shared_memory_handle_android.cc new file mode 100644 index 00000000000000..e38d50e4132890 --- /dev/null +++ b/base/memory/shared_memory_handle_android.cc @@ -0,0 +1,187 @@ +// 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/memory/shared_memory_handle.h" + +#include + +#include "base/android/android_hardware_buffer_compat.h" +#include "base/logging.h" +#include "base/posix/eintr_wrapper.h" +#include "base/posix/unix_domain_socket.h" +#include "base/unguessable_token.h" + +namespace base { + +SharedMemoryHandle::SharedMemoryHandle() {} + +SharedMemoryHandle::SharedMemoryHandle( + const base::FileDescriptor& file_descriptor, + size_t size, + const base::UnguessableToken& guid) + : SharedMemoryHandle(Type::ASHMEM, file_descriptor, size, guid) {} + +SharedMemoryHandle::SharedMemoryHandle( + Type type, + const base::FileDescriptor& file_descriptor, + size_t size, + const base::UnguessableToken& guid) + : type_(type), guid_(guid), size_(size) { + switch (type) { + case Type::INVALID: + NOTREACHED() << "Can't create a Type::INVALID from a file descriptor"; + break; + case Type::ASHMEM: + DCHECK_GE(file_descriptor.fd, 0); + file_descriptor_ = file_descriptor; + break; + case Type::ANDROID_HARDWARE_BUFFER: + // This may be the first use of AHardwareBuffers in this process, so we + // need to load symbols. This should not fail since we're supposedly + // receiving one from IPC, but better to be paranoid. + if (!AndroidHardwareBufferCompat::IsSupportAvailable()) { + NOTREACHED() << "AHardwareBuffer support not available"; + type_ = Type::INVALID; + return; + } + + AHardwareBuffer* ahb = nullptr; + // A successful receive increments refcount, we don't need to do so + // separately. + int ret = + AndroidHardwareBufferCompat::GetInstance().RecvHandleFromUnixSocket( + file_descriptor.fd, &ahb); + + if (ret < 0) { + PLOG(ERROR) << "recv"; + type_ = Type::INVALID; + return; + } + + memory_object_ = ahb; + } +} + +SharedMemoryHandle::SharedMemoryHandle(AHardwareBuffer* buffer, + size_t size, + const base::UnguessableToken& guid) + : type_(Type::ANDROID_HARDWARE_BUFFER), + memory_object_(buffer), + ownership_passes_to_ipc_(false), + guid_(guid), + size_(size) {} + +// static +SharedMemoryHandle SharedMemoryHandle::ImportHandle(int fd, size_t size) { + SharedMemoryHandle handle; + handle.type_ = Type::ASHMEM; + handle.file_descriptor_.fd = fd; + handle.file_descriptor_.auto_close = false; + handle.guid_ = UnguessableToken::Create(); + handle.size_ = size; + return handle; +} + +int SharedMemoryHandle::GetHandle() const { + switch (type_) { + case Type::INVALID: + return -1; + case Type::ASHMEM: + DCHECK(IsValid()); + return file_descriptor_.fd; + case Type::ANDROID_HARDWARE_BUFFER: + DCHECK(IsValid()); + ScopedFD read_fd, write_fd; + CreateSocketPair(&read_fd, &write_fd); + + int ret = + AndroidHardwareBufferCompat::GetInstance().SendHandleToUnixSocket( + memory_object_, write_fd.get()); + + if (ret < 0) { + PLOG(ERROR) << "send"; + return -1; + } + + // Close write end now to avoid timeouts in case the receiver goes away. + write_fd.reset(); + + return read_fd.release(); + } +} + +bool SharedMemoryHandle::IsValid() const { + return type_ != Type::INVALID; +} + +void SharedMemoryHandle::Close() const { + switch (type_) { + case Type::INVALID: + return; + case Type::ASHMEM: + DCHECK(IsValid()); + if (IGNORE_EINTR(close(file_descriptor_.fd)) < 0) + PLOG(ERROR) << "close"; + break; + case Type::ANDROID_HARDWARE_BUFFER: + DCHECK(IsValid()); + AndroidHardwareBufferCompat::GetInstance().Release(memory_object_); + } +} + +int SharedMemoryHandle::Release() { + DCHECK_EQ(type_, Type::ASHMEM); + int old_fd = file_descriptor_.fd; + file_descriptor_.fd = -1; + return old_fd; +} + +SharedMemoryHandle SharedMemoryHandle::Duplicate() const { + switch (type_) { + case Type::INVALID: + return SharedMemoryHandle(); + case Type::ASHMEM: { + DCHECK(IsValid()); + int duped_handle = HANDLE_EINTR(dup(file_descriptor_.fd)); + if (duped_handle < 0) + return SharedMemoryHandle(); + return SharedMemoryHandle(FileDescriptor(duped_handle, true), GetSize(), + GetGUID()); + } + case Type::ANDROID_HARDWARE_BUFFER: + DCHECK(IsValid()); + AndroidHardwareBufferCompat::GetInstance().Acquire(memory_object_); + SharedMemoryHandle handle(*this); + handle.SetOwnershipPassesToIPC(true); + return handle; + } +} + +AHardwareBuffer* SharedMemoryHandle::GetMemoryObject() const { + DCHECK_EQ(type_, Type::ANDROID_HARDWARE_BUFFER); + return memory_object_; +} + +void SharedMemoryHandle::SetOwnershipPassesToIPC(bool ownership_passes) { + switch (type_) { + case Type::ASHMEM: + file_descriptor_.auto_close = ownership_passes; + break; + case Type::INVALID: + case Type::ANDROID_HARDWARE_BUFFER: + ownership_passes_to_ipc_ = ownership_passes; + } +} + +bool SharedMemoryHandle::OwnershipPassesToIPC() const { + switch (type_) { + case Type::ASHMEM: + return file_descriptor_.auto_close; + case Type::INVALID: + case Type::ANDROID_HARDWARE_BUFFER: + return ownership_passes_to_ipc_; + } +} + +} // namespace base diff --git a/gpu/BUILD.gn b/gpu/BUILD.gn index c3f8843d222b8b..b67f718c98e7a3 100644 --- a/gpu/BUILD.gn +++ b/gpu/BUILD.gn @@ -352,6 +352,10 @@ test("gpu_unittests") { sources += [ "ipc/client/gpu_memory_buffer_impl_dxgi_unittest.cc" ] } + if (is_android) { + sources += [ "ipc/client/gpu_memory_buffer_impl_android_hardware_buffer_unittest.cc" ] + } + # TODO(geofflang): Run passthrough command decoder unittests on more platforms # once initialization of ANGLE's NULL context is supported if ((is_win || (is_linux && !use_ozone)) && !is_asan) { diff --git a/gpu/ipc/client/BUILD.gn b/gpu/ipc/client/BUILD.gn index ed85892e052398..1af50dfe5906f1 100644 --- a/gpu/ipc/client/BUILD.gn +++ b/gpu/ipc/client/BUILD.gn @@ -47,6 +47,12 @@ source_set("ipc_client_sources") { "gpu_memory_buffer_impl_native_pixmap.h", ] } + if (is_android) { + sources += [ + "gpu_memory_buffer_impl_android_hardware_buffer.cc", + "gpu_memory_buffer_impl_android_hardware_buffer.h", + ] + } configs += [ "//build/config/compiler:no_size_t_to_int_warning", "//gpu:gpu_implementation", diff --git a/gpu/ipc/client/gpu_memory_buffer_impl.cc b/gpu/ipc/client/gpu_memory_buffer_impl.cc index 73b18996eb7b75..c649c1fe9d8d05 100644 --- a/gpu/ipc/client/gpu_memory_buffer_impl.cc +++ b/gpu/ipc/client/gpu_memory_buffer_impl.cc @@ -20,6 +20,10 @@ #include "gpu/ipc/client/gpu_memory_buffer_impl_dxgi.h" #endif +#if defined(OS_ANDROID) +#include "gpu/ipc/client/gpu_memory_buffer_impl_android_hardware_buffer.h" +#endif + namespace gpu { GpuMemoryBufferImpl::GpuMemoryBufferImpl(gfx::GpuMemoryBufferId id, @@ -63,6 +67,11 @@ std::unique_ptr GpuMemoryBufferImpl::CreateFromHandle( case gfx::DXGI_SHARED_HANDLE: return GpuMemoryBufferImplDXGI::CreateFromHandle(handle, size, format, usage, callback); +#endif +#if defined(OS_ANDROID) + case gfx::ANDROID_HARDWARE_BUFFER: + return GpuMemoryBufferImplAndroidHardwareBuffer::CreateFromHandle( + handle, size, format, usage, callback); #endif default: NOTREACHED(); diff --git a/gpu/ipc/client/gpu_memory_buffer_impl_android_hardware_buffer.cc b/gpu/ipc/client/gpu_memory_buffer_impl_android_hardware_buffer.cc new file mode 100644 index 00000000000000..d85a90bf4a66a8 --- /dev/null +++ b/gpu/ipc/client/gpu_memory_buffer_impl_android_hardware_buffer.cc @@ -0,0 +1,156 @@ +// 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 "gpu/ipc/client/gpu_memory_buffer_impl_android_hardware_buffer.h" + +#include + +#include "base/android/android_hardware_buffer_compat.h" +#include "base/bind.h" +#include "base/logging.h" +#include "base/memory/ptr_util.h" +#include "base/memory/shared_memory_handle.h" +#include "gpu/ipc/client/gpu_memory_buffer_impl_android_hardware_buffer.h" +#include "gpu/ipc/common/gpu_memory_buffer_support.h" +#include "ui/gfx/geometry/size.h" + +namespace gpu { + +namespace { + +AHardwareBuffer_Desc GetBufferDescription(const gfx::Size& size, + gfx::BufferFormat format, + gfx::BufferUsage usage) { + // On create, all elements must be initialized, including setting the + // "reserved for future use" (rfu) fields to zero. + AHardwareBuffer_Desc desc = {}; + desc.width = size.width(); + desc.height = size.height(); + desc.layers = 1; // number of images + + switch (format) { + case gfx::BufferFormat::RGBA_8888: + desc.format = AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM; + break; + case gfx::BufferFormat::RGBX_8888: + desc.format = AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM; + break; + default: + NOTREACHED(); + } + + switch (usage) { + case gfx::BufferUsage::GPU_READ: + case gfx::BufferUsage::SCANOUT: + desc.usage = AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE | + AHARDWAREBUFFER_USAGE_GPU_COLOR_OUTPUT; + break; + default: + NOTREACHED(); + } + return desc; +} + +} // namespace + +GpuMemoryBufferImplAndroidHardwareBuffer:: + GpuMemoryBufferImplAndroidHardwareBuffer( + gfx::GpuMemoryBufferId id, + const gfx::Size& size, + gfx::BufferFormat format, + const DestructionCallback& callback, + const base::SharedMemoryHandle& handle) + : GpuMemoryBufferImpl(id, size, format, callback), + shared_memory_(handle, false) {} + +GpuMemoryBufferImplAndroidHardwareBuffer:: + ~GpuMemoryBufferImplAndroidHardwareBuffer() {} + +// static +std::unique_ptr +GpuMemoryBufferImplAndroidHardwareBuffer::Create( + gfx::GpuMemoryBufferId id, + const gfx::Size& size, + gfx::BufferFormat format, + gfx::BufferUsage usage, + const DestructionCallback& callback) { + DCHECK(base::AndroidHardwareBufferCompat::IsSupportAvailable()); + + AHardwareBuffer* buffer = nullptr; + AHardwareBuffer_Desc desc = GetBufferDescription(size, format, usage); + base::AndroidHardwareBufferCompat::GetInstance().Allocate(&desc, &buffer); + if (!buffer) { + LOG(ERROR) << "Failed to allocate AHardwareBuffer"; + return nullptr; + } + + return base::WrapUnique(new GpuMemoryBufferImplAndroidHardwareBuffer( + id, size, format, callback, + base::SharedMemoryHandle(buffer, 0, base::UnguessableToken::Create()))); +} + +// static +std::unique_ptr +GpuMemoryBufferImplAndroidHardwareBuffer::CreateFromHandle( + const gfx::GpuMemoryBufferHandle& handle, + const gfx::Size& size, + gfx::BufferFormat format, + gfx::BufferUsage usage, + const DestructionCallback& callback) { + DCHECK(base::SharedMemory::IsHandleValid(handle.handle)); + return base::WrapUnique(new GpuMemoryBufferImplAndroidHardwareBuffer( + handle.id, size, format, callback, handle.handle)); +} + +// static +bool GpuMemoryBufferImplAndroidHardwareBuffer::IsConfigurationSupported( + gfx::BufferFormat format, + gfx::BufferUsage usage) { + return gpu::IsNativeGpuMemoryBufferConfigurationSupported(format, usage); +} + +bool GpuMemoryBufferImplAndroidHardwareBuffer::Map() { + return false; +} + +void* GpuMemoryBufferImplAndroidHardwareBuffer::memory(size_t plane) { + return nullptr; +} + +void GpuMemoryBufferImplAndroidHardwareBuffer::Unmap() {} + +int GpuMemoryBufferImplAndroidHardwareBuffer::stride(size_t plane) const { + return 0; +} + +gfx::GpuMemoryBufferHandle GpuMemoryBufferImplAndroidHardwareBuffer::GetHandle() + const { + gfx::GpuMemoryBufferHandle handle; + handle.type = gfx::ANDROID_HARDWARE_BUFFER; + handle.id = id_; + handle.handle = shared_memory_.handle(); + + return handle; +} + +// static +base::Closure GpuMemoryBufferImplAndroidHardwareBuffer::AllocateForTesting( + const gfx::Size& size, + gfx::BufferFormat format, + gfx::BufferUsage usage, + gfx::GpuMemoryBufferHandle* handle) { + DCHECK(IsConfigurationSupported(format, usage)); + gfx::GpuMemoryBufferId kBufferId(1); + handle->type = gfx::ANDROID_HARDWARE_BUFFER; + handle->id = kBufferId; + AHardwareBuffer* buffer = nullptr; + AHardwareBuffer_Desc desc = GetBufferDescription(size, format, usage); + base::AndroidHardwareBufferCompat::GetInstance().Allocate(&desc, &buffer); + DCHECK(buffer); + handle->handle = + base::SharedMemoryHandle(buffer, 0, base::UnguessableToken::Create()); + return base::Bind(&base::DoNothing); +} + +} // namespace gpu diff --git a/gpu/ipc/client/gpu_memory_buffer_impl_android_hardware_buffer.h b/gpu/ipc/client/gpu_memory_buffer_impl_android_hardware_buffer.h new file mode 100644 index 00000000000000..a0204293a75a44 --- /dev/null +++ b/gpu/ipc/client/gpu_memory_buffer_impl_android_hardware_buffer.h @@ -0,0 +1,66 @@ +// 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 GPU_IPC_CLIENT_GPU_MEMORY_BUFFER_IMPL_ANDROID_HARDWARE_BUFFER_H_ +#define GPU_IPC_CLIENT_GPU_MEMORY_BUFFER_IMPL_ANDROID_HARDWARE_BUFFER_H_ + +#include "base/memory/shared_memory.h" +#include "gpu/gpu_export.h" +#include "gpu/ipc/client/gpu_memory_buffer_impl.h" + +extern "C" typedef struct AHardwareBuffer AHardwareBuffer; + +namespace gpu { + +// Implementation of GPU memory buffer based on AHardwareBuffer. +class GPU_EXPORT GpuMemoryBufferImplAndroidHardwareBuffer + : public GpuMemoryBufferImpl { + public: + ~GpuMemoryBufferImplAndroidHardwareBuffer() override; + + static std::unique_ptr Create( + gfx::GpuMemoryBufferId id, + const gfx::Size& size, + gfx::BufferFormat format, + gfx::BufferUsage usage, + const DestructionCallback& callback); + + static std::unique_ptr + CreateFromHandle(const gfx::GpuMemoryBufferHandle& handle, + const gfx::Size& size, + gfx::BufferFormat format, + gfx::BufferUsage usage, + const DestructionCallback& callback); + + static bool IsConfigurationSupported(gfx::BufferFormat format, + gfx::BufferUsage usage); + + static base::Closure AllocateForTesting(const gfx::Size& size, + gfx::BufferFormat format, + gfx::BufferUsage usage, + gfx::GpuMemoryBufferHandle* handle); + + // Overridden from gfx::GpuMemoryBuffer: + bool Map() override; + void* memory(size_t plane) override; + void Unmap() override; + int stride(size_t plane) const override; + gfx::GpuMemoryBufferHandle GetHandle() const override; + + private: + GpuMemoryBufferImplAndroidHardwareBuffer( + gfx::GpuMemoryBufferId id, + const gfx::Size& size, + gfx::BufferFormat format, + const DestructionCallback& callback, + const base::SharedMemoryHandle& handle); + + base::SharedMemory shared_memory_; + + DISALLOW_COPY_AND_ASSIGN(GpuMemoryBufferImplAndroidHardwareBuffer); +}; + +} // namespace gpu + +#endif // GPU_IPC_CLIENT_GPU_MEMORY_BUFFER_IMPL_ANDROID_HARDWARE_BUFFER_H_ diff --git a/gpu/ipc/client/gpu_memory_buffer_impl_android_hardware_buffer_unittest.cc b/gpu/ipc/client/gpu_memory_buffer_impl_android_hardware_buffer_unittest.cc new file mode 100644 index 00000000000000..cb5cea7f01c26b --- /dev/null +++ b/gpu/ipc/client/gpu_memory_buffer_impl_android_hardware_buffer_unittest.cc @@ -0,0 +1,20 @@ +// 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 "gpu/ipc/client/gpu_memory_buffer_impl_android_hardware_buffer.h" +#include "gpu/ipc/client/gpu_memory_buffer_impl_test_template.h" + +namespace gpu { +namespace { + +INSTANTIATE_TYPED_TEST_CASE_P(GpuMemoryBufferImplAndroidHardwareBuffer, + GpuMemoryBufferImplTest, + GpuMemoryBufferImplAndroidHardwareBuffer); + +INSTANTIATE_TYPED_TEST_CASE_P(GpuMemoryBufferImplAndroidHardwareBuffer, + GpuMemoryBufferImplCreateTest, + GpuMemoryBufferImplAndroidHardwareBuffer); + +} // namespace +} // namespace gpu diff --git a/gpu/ipc/common/gpu_memory_buffer_support.cc b/gpu/ipc/common/gpu_memory_buffer_support.cc index 7a3f3456078d73..8747c099224fc6 100644 --- a/gpu/ipc/common/gpu_memory_buffer_support.cc +++ b/gpu/ipc/common/gpu_memory_buffer_support.cc @@ -11,11 +11,17 @@ #include "ui/gfx/client_native_pixmap_factory.h" #endif +#if defined(OS_ANDROID) +#include "base/android/android_hardware_buffer_compat.h" +#endif + namespace gpu { gfx::GpuMemoryBufferType GetNativeGpuMemoryBufferType() { #if defined(OS_MACOSX) return gfx::IO_SURFACE_BUFFER; +#elif defined(OS_ANDROID) + return gfx::ANDROID_HARDWARE_BUFFER; #elif defined(OS_LINUX) return gfx::NATIVE_PIXMAP; #elif defined(OS_WIN) @@ -57,6 +63,24 @@ bool IsNativeGpuMemoryBufferConfigurationSupported(gfx::BufferFormat format, } NOTREACHED(); return false; +#elif defined(OS_ANDROID) + if (!base::AndroidHardwareBufferCompat::IsSupportAvailable()) { + return false; + } + switch (usage) { + case gfx::BufferUsage::GPU_READ: + case gfx::BufferUsage::SCANOUT: + return format == gfx::BufferFormat::RGBA_8888 || + format == gfx::BufferFormat::RGBX_8888; + case gfx::BufferUsage::SCANOUT_CPU_READ_WRITE: + case gfx::BufferUsage::GPU_READ_CPU_READ_WRITE: + case gfx::BufferUsage::GPU_READ_CPU_READ_WRITE_PERSISTENT: + case gfx::BufferUsage::SCANOUT_VDA_WRITE: + case gfx::BufferUsage::SCANOUT_CAMERA_READ_WRITE: + return false; + } + NOTREACHED(); + return false; #elif defined(OS_LINUX) if (!gfx::ClientNativePixmapFactory::GetInstance()) { // unittests don't have to set ClientNativePixmapFactory. diff --git a/gpu/ipc/host/gpu_memory_buffer_support.cc b/gpu/ipc/host/gpu_memory_buffer_support.cc index 0a4e0c170db403..44cb946718c1d8 100644 --- a/gpu/ipc/host/gpu_memory_buffer_support.cc +++ b/gpu/ipc/host/gpu_memory_buffer_support.cc @@ -35,7 +35,8 @@ bool AreNativeGpuMemoryBuffersEnabled() { GpuMemoryBufferConfigurationSet GetNativeGpuMemoryBufferConfigurations() { GpuMemoryBufferConfigurationSet configurations; -#if defined(USE_OZONE) || defined(OS_MACOSX) || defined(OS_WIN) +#if defined(USE_OZONE) || defined(OS_MACOSX) || defined(OS_WIN) || \ + defined(OS_ANDROID) if (AreNativeGpuMemoryBuffersEnabled()) { const gfx::BufferFormat kNativeFormats[] = { gfx::BufferFormat::R_8, gfx::BufferFormat::RG_88, @@ -86,7 +87,8 @@ GpuMemoryBufferConfigurationSet GetNativeGpuMemoryBufferConfigurations() { uint32_t GetImageTextureTarget(gfx::BufferFormat format, gfx::BufferUsage usage) { -#if defined(USE_OZONE) || defined(OS_MACOSX) || defined(OS_WIN) +#if defined(USE_OZONE) || defined(OS_MACOSX) || defined(OS_WIN) || \ + defined(OS_ANDROID) GpuMemoryBufferConfigurationSet native_configurations = GetNativeGpuMemoryBufferConfigurations(); if (native_configurations.find(std::make_pair(format, usage)) == @@ -96,6 +98,7 @@ uint32_t GetImageTextureTarget(gfx::BufferFormat format, switch (GetNativeGpuMemoryBufferType()) { case gfx::NATIVE_PIXMAP: + case gfx::ANDROID_HARDWARE_BUFFER: // GPU memory buffers that are shared with the GL using EGLImages // require TEXTURE_EXTERNAL_OES. return GL_TEXTURE_EXTERNAL_OES; diff --git a/gpu/ipc/service/BUILD.gn b/gpu/ipc/service/BUILD.gn index ffb0dee79d1719..b0e787866b1946 100644 --- a/gpu/ipc/service/BUILD.gn +++ b/gpu/ipc/service/BUILD.gn @@ -114,6 +114,8 @@ target(link_target_type, "ipc_service_sources") { } if (is_android) { sources += [ + "gpu_memory_buffer_factory_android_hardware_buffer.cc", + "gpu_memory_buffer_factory_android_hardware_buffer.h", "image_transport_surface_android.cc", "stream_texture_android.cc", "stream_texture_android.h", diff --git a/gpu/ipc/service/gpu_memory_buffer_factory.cc b/gpu/ipc/service/gpu_memory_buffer_factory.cc index 5adc710c235a8c..5a70a0221a5bac 100644 --- a/gpu/ipc/service/gpu_memory_buffer_factory.cc +++ b/gpu/ipc/service/gpu_memory_buffer_factory.cc @@ -20,6 +20,10 @@ #include "gpu/ipc/service/gpu_memory_buffer_factory_dxgi.h" #endif +#if defined(OS_ANDROID) +#include "gpu/ipc/service/gpu_memory_buffer_factory_android_hardware_buffer.h" +#endif + namespace gpu { // static @@ -27,6 +31,8 @@ std::unique_ptr GpuMemoryBufferFactory::CreateNativeType() { #if defined(OS_MACOSX) return base::WrapUnique(new GpuMemoryBufferFactoryIOSurface); +#elif defined(OS_ANDROID) + return base::WrapUnique(new GpuMemoryBufferFactoryAndroidHardwareBuffer); #elif defined(OS_LINUX) return base::WrapUnique(new GpuMemoryBufferFactoryNativePixmap); #elif defined(OS_WIN) diff --git a/gpu/ipc/service/gpu_memory_buffer_factory_android_hardware_buffer.cc b/gpu/ipc/service/gpu_memory_buffer_factory_android_hardware_buffer.cc new file mode 100644 index 00000000000000..838a46daa5c726 --- /dev/null +++ b/gpu/ipc/service/gpu_memory_buffer_factory_android_hardware_buffer.cc @@ -0,0 +1,82 @@ +// 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 "gpu/ipc/service/gpu_memory_buffer_factory_android_hardware_buffer.h" + +#include "base/logging.h" +#include "base/memory/shared_memory_handle.h" +#include "build/build_config.h" +#include "ui/gl/gl_image_ahardwarebuffer.h" + +namespace gpu { + +GpuMemoryBufferFactoryAndroidHardwareBuffer:: + GpuMemoryBufferFactoryAndroidHardwareBuffer() {} + +GpuMemoryBufferFactoryAndroidHardwareBuffer:: + ~GpuMemoryBufferFactoryAndroidHardwareBuffer() {} + +gfx::GpuMemoryBufferHandle +GpuMemoryBufferFactoryAndroidHardwareBuffer::CreateGpuMemoryBuffer( + gfx::GpuMemoryBufferId id, + const gfx::Size& size, + gfx::BufferFormat format, + gfx::BufferUsage usage, + int client_id, + SurfaceHandle surface_handle) { + NOTIMPLEMENTED(); + return gfx::GpuMemoryBufferHandle(); +} + +void GpuMemoryBufferFactoryAndroidHardwareBuffer::DestroyGpuMemoryBuffer( + gfx::GpuMemoryBufferId id, + int client_id) {} + +ImageFactory* GpuMemoryBufferFactoryAndroidHardwareBuffer::AsImageFactory() { + return this; +} + +scoped_refptr +GpuMemoryBufferFactoryAndroidHardwareBuffer::CreateImageForGpuMemoryBuffer( + const gfx::GpuMemoryBufferHandle& handle, + const gfx::Size& size, + gfx::BufferFormat format, + unsigned internalformat, + int client_id, + SurfaceHandle surface_handle) { + // We should only end up in this code path if the memory buffer has a valid + // AHardwareBuffer. + DCHECK_EQ(handle.type, gfx::ANDROID_HARDWARE_BUFFER); + DCHECK_EQ(handle.handle.GetType(), + base::SharedMemoryHandle::Type::ANDROID_HARDWARE_BUFFER); + + AHardwareBuffer* buffer = handle.handle.GetMemoryObject(); + DCHECK(buffer); + + EGLint attribs[] = {EGL_IMAGE_PRESERVED_KHR, EGL_FALSE, EGL_NONE}; + + scoped_refptr image(new gl::GLImageAHardwareBuffer(size)); + EGLClientBuffer client_buffer = eglGetNativeClientBufferANDROID(buffer); + if (!image->Initialize(EGL_NATIVE_BUFFER_ANDROID, client_buffer, attribs)) { + DLOG(ERROR) << "Failed to create GLImage " << size.ToString(); + return nullptr; + } + return image; +} + +scoped_refptr +GpuMemoryBufferFactoryAndroidHardwareBuffer::CreateAnonymousImage( + const gfx::Size& size, + gfx::BufferFormat format, + gfx::BufferUsage usage, + unsigned internalformat) { + NOTIMPLEMENTED(); + return nullptr; +} + +unsigned GpuMemoryBufferFactoryAndroidHardwareBuffer::RequiredTextureType() { + return GL_TEXTURE_EXTERNAL_OES; +} + +} // namespace gpu diff --git a/gpu/ipc/service/gpu_memory_buffer_factory_android_hardware_buffer.h b/gpu/ipc/service/gpu_memory_buffer_factory_android_hardware_buffer.h new file mode 100644 index 00000000000000..7cd7b614f96085 --- /dev/null +++ b/gpu/ipc/service/gpu_memory_buffer_factory_android_hardware_buffer.h @@ -0,0 +1,58 @@ +// 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 GPU_IPC_SERVICE_GPU_MEMORY_BUFFER_FACTORY_ANDROID_HARDWARE_BUFFER_H_ +#define GPU_IPC_SERVICE_GPU_MEMORY_BUFFER_FACTORY_ANDROID_HARDWARE_BUFFER_H_ + +#include "gpu/command_buffer/service/image_factory.h" +#include "gpu/gpu_export.h" +#include "gpu/ipc/service/gpu_memory_buffer_factory.h" + +namespace gl { +class GLImage; +} + +namespace gpu { + +class GPU_EXPORT GpuMemoryBufferFactoryAndroidHardwareBuffer + : public GpuMemoryBufferFactory, + public ImageFactory { + public: + GpuMemoryBufferFactoryAndroidHardwareBuffer(); + ~GpuMemoryBufferFactoryAndroidHardwareBuffer() override; + + // Overridden from GpuMemoryBufferFactory: + gfx::GpuMemoryBufferHandle CreateGpuMemoryBuffer( + gfx::GpuMemoryBufferId id, + const gfx::Size& size, + gfx::BufferFormat format, + gfx::BufferUsage usage, + int client_id, + SurfaceHandle surface_handle) override; + void DestroyGpuMemoryBuffer(gfx::GpuMemoryBufferId id, + int client_id) override; + ImageFactory* AsImageFactory() override; + + // Overridden from ImageFactory: + scoped_refptr CreateImageForGpuMemoryBuffer( + const gfx::GpuMemoryBufferHandle& handle, + const gfx::Size& size, + gfx::BufferFormat format, + unsigned internalformat, + int client_id, + SurfaceHandle surface_handle) override; + scoped_refptr CreateAnonymousImage( + const gfx::Size& size, + gfx::BufferFormat format, + gfx::BufferUsage usage, + unsigned internalformat) override; + unsigned RequiredTextureType() override; + + private: + DISALLOW_COPY_AND_ASSIGN(GpuMemoryBufferFactoryAndroidHardwareBuffer); +}; + +} // namespace gpu + +#endif // GPU_IPC_SERVICE_GPU_MEMORY_BUFFER_FACTORY_ANDROID_HARDWARE_BUFFER_H_ diff --git a/ipc/ipc_message_utils.cc b/ipc/ipc_message_utils.cc index 6ea3e902dcfd34..8d7319da9271ec 100644 --- a/ipc/ipc_message_utils.cc +++ b/ipc/ipc_message_utils.cc @@ -10,7 +10,6 @@ #include "base/files/file_path.h" #include "base/json/json_writer.h" #include "base/memory/ptr_util.h" -#include "base/memory/shared_memory_handle.h" #include "base/strings/nullable_string16.h" #include "base/strings/string_number_conversions.h" #include "base/strings/utf_string_conversions.h" @@ -568,6 +567,33 @@ void ParamTraits::Log(const param_type& p, } #endif // defined(OS_POSIX) +#if defined(OS_ANDROID) +void ParamTraits::Write(base::Pickle* m, + const param_type& p) { + DCHECK(static_cast(p) >= 0 && p <= base::SharedMemoryHandle::Type::LAST); + m->WriteInt(static_cast(p)); +} + +bool ParamTraits::Read( + const base::Pickle* m, + base::PickleIterator* iter, + param_type* r) { + int value; + if (!iter->ReadInt(&value)) + return false; + if (value < 0 || + value > static_cast(base::SharedMemoryHandle::Type::LAST)) + return false; + *r = static_cast(value); + return true; +} + +void ParamTraits::Log(const param_type& p, + std::string* l) { + l->append(base::IntToString(static_cast(p))); +} +#endif + void ParamTraits::Write(base::Pickle* m, const param_type& p) { // This serialization must be kept in sync with @@ -588,6 +614,12 @@ void ParamTraits::Write(base::Pickle* m, HandleFuchsia handle_fuchsia(p.GetHandle()); WriteParam(m, handle_fuchsia); #else +#if defined(OS_ANDROID) + // Android transfers both ashmem and AHardwareBuffer SharedMemoryHandle + // subtypes, both are transferred via file descriptor but need to be handled + // differently by the receiver. Write the type to distinguish. + WriteParam(m, p.GetType()); +#endif if (p.OwnershipPassesToIPC()) { if (!m->WriteAttachment(new internal::PlatformFileAttachment( base::ScopedFD(p.GetHandle())))) @@ -635,6 +667,13 @@ bool ParamTraits::Read(const base::Pickle* m, if (!ReadParam(m, iter, &handle_fuchsia)) return false; #else +#if defined(OS_ANDROID) + // Android uses both ashmen and AHardwareBuffer subtypes, get the actual type + // for use as a constructor argument alongside the file descriptor. + base::SharedMemoryHandle::Type android_subtype; + if (!ReadParam(m, iter, &android_subtype)) + return false; +#endif scoped_refptr attachment; if (!m->ReadAttachment(iter, &attachment)) return false; @@ -660,6 +699,14 @@ bool ParamTraits::Read(const base::Pickle* m, #elif defined(OS_FUCHSIA) *r = base::SharedMemoryHandle(handle_fuchsia.get_handle(), static_cast(size), guid); +#elif defined(OS_ANDROID) + *r = base::SharedMemoryHandle( + android_subtype, + base::FileDescriptor( + static_cast(attachment.get()) + ->TakePlatformFile(), + true), + static_cast(size), guid); #else *r = base::SharedMemoryHandle( base::FileDescriptor( diff --git a/ipc/ipc_message_utils.h b/ipc/ipc_message_utils.h index 3d1b736e9977e1..54fee405190b5c 100644 --- a/ipc/ipc_message_utils.h +++ b/ipc/ipc_message_utils.h @@ -23,6 +23,7 @@ #include "base/containers/stack_container.h" #include "base/files/file.h" #include "base/format_macros.h" +#include "base/memory/shared_memory_handle.h" #include "base/numerics/safe_conversions.h" #include "base/optional.h" #include "base/strings/string16.h" @@ -39,7 +40,6 @@ class DictionaryValue; class FilePath; class ListValue; class NullableString16; -class SharedMemoryHandle; class Time; class TimeDelta; class TimeTicks; @@ -556,6 +556,18 @@ struct IPC_EXPORT ParamTraits { static void Log(const param_type& p, std::string* l); }; +#if defined(OS_ANDROID) +template <> +struct IPC_EXPORT ParamTraits { + typedef base::SharedMemoryHandle::Type param_type; + static void Write(base::Pickle* m, const param_type& p); + static bool Read(const base::Pickle* m, + base::PickleIterator* iter, + param_type* r); + static void Log(const param_type& p, std::string* l); +}; +#endif + #if defined(OS_WIN) template <> struct IPC_EXPORT ParamTraits { diff --git a/ui/gfx/gpu_memory_buffer.cc b/ui/gfx/gpu_memory_buffer.cc index 5c050207f0773a..813141df8ca639 100644 --- a/ui/gfx/gpu_memory_buffer.cc +++ b/ui/gfx/gpu_memory_buffer.cc @@ -42,6 +42,13 @@ GpuMemoryBufferHandle CloneHandleForIPC( #endif return handle; } + case gfx::ANDROID_HARDWARE_BUFFER: { + gfx::GpuMemoryBufferHandle handle; + handle.type = gfx::ANDROID_HARDWARE_BUFFER; + handle.id = source_handle.id; + handle.handle = base::SharedMemory::DuplicateHandle(source_handle.handle); + return handle; + } case gfx::IO_SURFACE_BUFFER: return source_handle; case gfx::DXGI_SHARED_HANDLE: diff --git a/ui/gfx/gpu_memory_buffer.h b/ui/gfx/gpu_memory_buffer.h index 87ebea26b98c40..241dc78205871d 100644 --- a/ui/gfx/gpu_memory_buffer.h +++ b/ui/gfx/gpu_memory_buffer.h @@ -34,7 +34,8 @@ enum GpuMemoryBufferType { IO_SURFACE_BUFFER, NATIVE_PIXMAP, DXGI_SHARED_HANDLE, - GPU_MEMORY_BUFFER_TYPE_LAST = DXGI_SHARED_HANDLE + ANDROID_HARDWARE_BUFFER, + GPU_MEMORY_BUFFER_TYPE_LAST = ANDROID_HARDWARE_BUFFER }; using GpuMemoryBufferId = GenericSharedMemoryId; diff --git a/ui/gfx/mojo/buffer_types.mojom b/ui/gfx/mojo/buffer_types.mojom index 34d5c331912013..70a554858f8674 100644 --- a/ui/gfx/mojo/buffer_types.mojom +++ b/ui/gfx/mojo/buffer_types.mojom @@ -49,7 +49,7 @@ enum GpuMemoryBufferType { IO_SURFACE_BUFFER, NATIVE_PIXMAP, DXGI_SHARED_HANDLE, - LAST = DXGI_SHARED_HANDLE + ANDROID_HARDWARE_BUFFER, }; // gfx::GpuMemoryBufferId diff --git a/ui/gfx/mojo/buffer_types_struct_traits.cc b/ui/gfx/mojo/buffer_types_struct_traits.cc index 419bc2b46ba901..ddb3fd28942f5c 100644 --- a/ui/gfx/mojo/buffer_types_struct_traits.cc +++ b/ui/gfx/mojo/buffer_types_struct_traits.cc @@ -47,7 +47,8 @@ StructTraits:: shared_memory_handle(const gfx::GpuMemoryBufferHandle& handle) { if (handle.type != gfx::SHARED_MEMORY_BUFFER && - handle.type != gfx::DXGI_SHARED_HANDLE) + handle.type != gfx::DXGI_SHARED_HANDLE && + handle.type != gfx::ANDROID_HARDWARE_BUFFER) return mojo::ScopedSharedBufferHandle(); return mojo::WrapSharedMemoryHandle(handle.handle, handle.handle.GetSize(), false); @@ -85,7 +86,8 @@ bool StructTraitstype == gfx::SHARED_MEMORY_BUFFER || - out->type == gfx::DXGI_SHARED_HANDLE) { + out->type == gfx::DXGI_SHARED_HANDLE || + out->type == gfx::ANDROID_HARDWARE_BUFFER) { mojo::ScopedSharedBufferHandle handle = data.TakeSharedMemoryHandle(); if (handle.is_valid()) { MojoResult unwrap_result = mojo::UnwrapSharedMemoryHandle( diff --git a/ui/gfx/mojo/buffer_types_struct_traits.h b/ui/gfx/mojo/buffer_types_struct_traits.h index f3359bf0a5928c..bf1568d40ebeb0 100644 --- a/ui/gfx/mojo/buffer_types_struct_traits.h +++ b/ui/gfx/mojo/buffer_types_struct_traits.h @@ -190,9 +190,11 @@ struct EnumTraits { return gfx::mojom::GpuMemoryBufferType::NATIVE_PIXMAP; case gfx::GpuMemoryBufferType::DXGI_SHARED_HANDLE: return gfx::mojom::GpuMemoryBufferType::DXGI_SHARED_HANDLE; + case gfx::GpuMemoryBufferType::ANDROID_HARDWARE_BUFFER: + return gfx::mojom::GpuMemoryBufferType::ANDROID_HARDWARE_BUFFER; } NOTREACHED(); - return gfx::mojom::GpuMemoryBufferType::LAST; + return gfx::mojom::GpuMemoryBufferType::EMPTY_BUFFER; } static bool FromMojom(gfx::mojom::GpuMemoryBufferType input, @@ -213,6 +215,9 @@ struct EnumTraits { case gfx::mojom::GpuMemoryBufferType::DXGI_SHARED_HANDLE: *out = gfx::GpuMemoryBufferType::DXGI_SHARED_HANDLE; return true; + case gfx::mojom::GpuMemoryBufferType::ANDROID_HARDWARE_BUFFER: + *out = gfx::GpuMemoryBufferType::ANDROID_HARDWARE_BUFFER; + return true; } return false; } diff --git a/ui/gl/BUILD.gn b/ui/gl/BUILD.gn index 131bd3e7beac78..4e5028b7e9ed94 100644 --- a/ui/gl/BUILD.gn +++ b/ui/gl/BUILD.gn @@ -187,6 +187,13 @@ component("gl") { "gl_image_native_pixmap.h", ] } + + if (is_android) { + sources += [ + "gl_image_ahardwarebuffer.cc", + "gl_image_ahardwarebuffer.h", + ] + } } if (is_android || is_linux) { sources += [ @@ -421,6 +428,10 @@ test("gl_unittests") { ] } + if (is_android) { + sources += [ "gl_image_ahardwarebuffer_unittest.cc" ] + } + include_dirs = [ "//third_party/khronos" ] deps = [ diff --git a/ui/gl/gl_image_ahardwarebuffer.cc b/ui/gl/gl_image_ahardwarebuffer.cc new file mode 100644 index 00000000000000..d1377be935d158 --- /dev/null +++ b/ui/gl/gl_image_ahardwarebuffer.cc @@ -0,0 +1,46 @@ +// 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 "ui/gl/gl_image_ahardwarebuffer.h" + +#include "ui/gl/gl_bindings.h" + +namespace gl { + +GLImageAHardwareBuffer::GLImageAHardwareBuffer(const gfx::Size& size) + : GLImageEGL(size) {} + +GLImageAHardwareBuffer::~GLImageAHardwareBuffer() {} + +unsigned GLImageAHardwareBuffer::GetInternalFormat() { + return GL_RGBA; +} + +bool GLImageAHardwareBuffer::CopyTexImage(unsigned target) { + return false; +} + +bool GLImageAHardwareBuffer::CopyTexSubImage(unsigned target, + const gfx::Point& offset, + const gfx::Rect& rect) { + return false; +} + +bool GLImageAHardwareBuffer::ScheduleOverlayPlane( + gfx::AcceleratedWidget widget, + int z_order, + gfx::OverlayTransform transform, + const gfx::Rect& bounds_rect, + const gfx::RectF& crop_rect) { + return false; +} + +void GLImageAHardwareBuffer::Flush() {} + +void GLImageAHardwareBuffer::OnMemoryDump( + base::trace_event::ProcessMemoryDump* pmd, + uint64_t process_tracing_id, + const std::string& dump_name) {} + +} // namespace gl diff --git a/ui/gl/gl_image_ahardwarebuffer.h b/ui/gl/gl_image_ahardwarebuffer.h new file mode 100644 index 00000000000000..a8ef6f9f19105f --- /dev/null +++ b/ui/gl/gl_image_ahardwarebuffer.h @@ -0,0 +1,44 @@ +// 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 UI_GL_GL_IMAGE_AHARDWAREBUFFER_H_ +#define UI_GL_GL_IMAGE_AHARDWAREBUFFER_H_ + +#include "base/macros.h" +#include "ui/gl/gl_export.h" +#include "ui/gl/gl_image_egl.h" + +namespace gl { + +class GL_EXPORT GLImageAHardwareBuffer : public GLImageEGL { + public: + explicit GLImageAHardwareBuffer(const gfx::Size& size); + + // Overridden from GLImage: + unsigned GetInternalFormat() override; + bool CopyTexImage(unsigned target) override; + bool CopyTexSubImage(unsigned target, + const gfx::Point& offset, + const gfx::Rect& rect) override; + bool ScheduleOverlayPlane(gfx::AcceleratedWidget widget, + int z_order, + gfx::OverlayTransform transform, + const gfx::Rect& bounds_rect, + const gfx::RectF& crop_rect) override; + void SetColorSpace(const gfx::ColorSpace& color_space) override {} + void Flush() override; + void OnMemoryDump(base::trace_event::ProcessMemoryDump* pmd, + uint64_t process_tracing_id, + const std::string& dump_name) override; + + protected: + ~GLImageAHardwareBuffer() override; + + private: + DISALLOW_COPY_AND_ASSIGN(GLImageAHardwareBuffer); +}; + +} // namespace gl + +#endif // UI_GL_GL_IMAGE_AHARDWAREBUFFER_H_ diff --git a/ui/gl/gl_image_ahardwarebuffer_unittest.cc b/ui/gl/gl_image_ahardwarebuffer_unittest.cc new file mode 100644 index 00000000000000..1332dd74f331b8 --- /dev/null +++ b/ui/gl/gl_image_ahardwarebuffer_unittest.cc @@ -0,0 +1,125 @@ +// 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 + +#include + +#include "base/android/android_hardware_buffer_compat.h" +#include "base/memory/scoped_refptr.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "ui/gl/gl_image_ahardwarebuffer.h" +#include "ui/gl/test/gl_image_test_template.h" + +namespace gl { +namespace { + +const uint8_t kGreen[] = {0x0, 0xFF, 0x0, 0xFF}; + +template +class GLImageAHardwareBufferTestDelegate { + public: + scoped_refptr CreateSolidColorImage(const gfx::Size& size, + const uint8_t color[4]) const { + CHECK(base::AndroidHardwareBufferCompat::IsSupportAvailable()); + + // AHardwareBuffer_Desc's stride parameter is in pixels, not in bytes. + // + // We can't use the 3-byte-per-pixel AHARDWAREBUFFER_FORMAT_R8G8B8_UNORM + // format in this test since there's no matching gfx::BufferFormat, + // gfx::BufferFormat::RGBX_8888 assumes 4 bytes per pixel. + const int kBytesPerPixel = 4; + + // cf. gpu_memory_buffer_impl_android_hardware_buffer + AHardwareBuffer_Desc desc = {}; + desc.width = size.width(); + desc.height = size.height(); + desc.layers = 1; // number of images + desc.usage = AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE | + AHARDWAREBUFFER_USAGE_GPU_COLOR_OUTPUT | + AHARDWAREBUFFER_USAGE_CPU_READ_RARELY | + AHARDWAREBUFFER_USAGE_CPU_WRITE_RARELY; + + switch (format) { + case gfx::BufferFormat::RGBA_8888: + desc.format = AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM; + break; + case gfx::BufferFormat::RGBX_8888: + desc.format = AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM; + break; + default: + NOTREACHED(); + } + + AHardwareBuffer* buffer = nullptr; + base::AndroidHardwareBufferCompat::GetInstance().Allocate(&desc, &buffer); + EXPECT_TRUE(buffer); + + uint8_t* data = nullptr; + int lock_result = base::AndroidHardwareBufferCompat::GetInstance().Lock( + buffer, AHARDWAREBUFFER_USAGE_CPU_WRITE_RARELY, -1, nullptr, + reinterpret_cast(&data)); + EXPECT_EQ(lock_result, 0); + EXPECT_TRUE(data); + + AHardwareBuffer_Desc desc_locked = {}; + base::AndroidHardwareBufferCompat::GetInstance().Describe(buffer, + &desc_locked); + + GLImageTestSupport::SetBufferDataToColor( + size.width(), size.height(), desc_locked.stride * kBytesPerPixel, 0, + format, color, data); + + int unlock_result = base::AndroidHardwareBufferCompat::GetInstance().Unlock( + buffer, nullptr); + EXPECT_EQ(unlock_result, 0); + + auto image = base::MakeRefCounted(size); + EGLint attribs[] = {EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE}; + EGLClientBuffer client_buffer = eglGetNativeClientBufferANDROID(buffer); + bool rv = + image->Initialize(EGL_NATIVE_BUFFER_ANDROID, client_buffer, attribs); + EXPECT_TRUE(rv); + return image; + } + + scoped_refptr CreateImage(const gfx::Size& size) const { + const uint8_t kTransparentBlack[4] = {0, 0, 0, 0}; + return CreateSolidColorImage(size, kTransparentBlack); + } + + unsigned GetTextureTarget() const { return GL_TEXTURE_2D; } + const uint8_t* GetImageColor() { return kGreen; } + int GetAdmissibleError() const { return 0; } +}; + +using GLImageTestTypes = testing::Types< + GLImageAHardwareBufferTestDelegate, + GLImageAHardwareBufferTestDelegate>; + +using GLImageRGBTestTypes = testing::Types< + GLImageAHardwareBufferTestDelegate>; + +// Disable the tests by default for now since they require Android O, +// the test bots don't generally have that yet. For manual testing, +// add: --gtest_also_run_disabled_tests -f 'GLImageAHardwareBuffer/*' + +INSTANTIATE_TYPED_TEST_CASE_P(DISABLED_GLImageAHardwareBuffer, + GLImageTest, + GLImageTestTypes); + +INSTANTIATE_TYPED_TEST_CASE_P(DISABLED_GLImageAHardwareBuffer, + GLImageOddSizeTest, + GLImageTestTypes); + +INSTANTIATE_TYPED_TEST_CASE_P(DISABLED_GLImageAHardwareBuffer, + GLImageBindTest, + GLImageTestTypes); + +INSTANTIATE_TYPED_TEST_CASE_P(DISABLED_GLImageAHardwareBuffer, + GLImageZeroInitializeTest, + GLImageRGBTestTypes); + +} // namespace +} // namespace gl diff --git a/ui/gl/gl_image_egl.h b/ui/gl/gl_image_egl.h index a913f41a0e78c3..4ebc3d7aff910c 100644 --- a/ui/gl/gl_image_egl.h +++ b/ui/gl/gl_image_egl.h @@ -13,6 +13,7 @@ namespace gl { +// Abstract base class for EGL-based images. class GL_EXPORT GLImageEGL : public GLImage { public: explicit GLImageEGL(const gfx::Size& size);