diff options
| author | 2023-10-10 20:43:20 +0000 | |
|---|---|---|
| committer | 2023-10-10 20:43:20 +0000 | |
| commit | 5d6006d85b27e0f8732b16998b90de21a9bf749f (patch) | |
| tree | 0089f19b2b5a44a96f4e7c2f71a47cb1f8febe3b | |
| parent | 56f83aa42658de6c3ad47afc6c135a4c822f6c49 (diff) | |
| parent | b69c6ef0a8b9bff035be10639efeda027d69e325 (diff) | |
Merge changes from topic "nativewindow-rust" into main
* changes:
nativewindow: Misc. improvements for AHardwareBuffer Rust wrapper
nativewindow: Add more benchmarks to evaluate FFI costs
nativewindow: Add C++/Rust benchmarks
Add missing safety comments.
libnativewindow: Add rust library and set up bindgen
| -rw-r--r-- | libs/nativewindow/TEST_MAPPING | 8 | ||||
| -rw-r--r-- | libs/nativewindow/rust/Android.bp | 87 | ||||
| -rw-r--r-- | libs/nativewindow/rust/src/lib.rs | 329 | ||||
| -rw-r--r-- | libs/nativewindow/rust/sys/nativewindow_bindings.h | 20 | ||||
| -rw-r--r-- | libs/nativewindow/tests/benchmark/Android.bp | 50 | ||||
| -rw-r--r-- | libs/nativewindow/tests/benchmark/README.md | 22 | ||||
| -rw-r--r-- | libs/nativewindow/tests/benchmark/buffer_benchmarks.cc | 74 | ||||
| -rw-r--r-- | libs/nativewindow/tests/benchmark/buffer_benchmarks.rs | 60 |
8 files changed, 650 insertions, 0 deletions
diff --git a/libs/nativewindow/TEST_MAPPING b/libs/nativewindow/TEST_MAPPING index 3d7f3c28f4..bbad757a48 100644 --- a/libs/nativewindow/TEST_MAPPING +++ b/libs/nativewindow/TEST_MAPPING @@ -3,5 +3,13 @@ { "name": "libnativewindow_test" } + ], + "postsubmit": [ + { + "name": "libnativewindow_bindgen_test" + }, + { + "name": "libnativewindow_rs-internal_test" + } ] } diff --git a/libs/nativewindow/rust/Android.bp b/libs/nativewindow/rust/Android.bp new file mode 100644 index 0000000000..dc1575ca33 --- /dev/null +++ b/libs/nativewindow/rust/Android.bp @@ -0,0 +1,87 @@ +// Copyright (C) 2023 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package { + default_applicable_licenses: [ + "frameworks_native_libs_nativewindow_license", + ], +} + +rust_bindgen { + name: "libnativewindow_bindgen", + crate_name: "nativewindow_bindgen", + wrapper_src: "sys/nativewindow_bindings.h", + source_stem: "bindings", + bindgen_flags: [ + "--constified-enum-module=AHardwareBuffer_Format", + "--bitfield-enum=AHardwareBuffer_UsageFlags", + + "--allowlist-file=.*/nativewindow/include/.*\\.h", + + "--with-derive-eq", + "--with-derive-partialeq", + ], + shared_libs: [ + "libnativewindow", + ], + + // Currently necessary for host builds + // TODO(b/31559095): bionic on host should define this + target: { + darwin: { + enabled: false, + }, + }, + min_sdk_version: "VanillaIceCream", +} + +rust_test { + name: "libnativewindow_bindgen_test", + srcs: [":libnativewindow_bindgen"], + crate_name: "nativewindow_bindgen_test", + test_suites: ["general-tests"], + auto_gen_config: true, + clippy_lints: "none", + lints: "none", +} + +rust_defaults { + name: "libnativewindow_defaults", + srcs: ["src/lib.rs"], + rustlibs: [ + "libnativewindow_bindgen", + ], +} + +rust_library { + name: "libnativewindow_rs", + crate_name: "nativewindow", + defaults: ["libnativewindow_defaults"], + + // Currently necessary for host builds + // TODO(b/31559095): bionic on host should define this + target: { + darwin: { + enabled: false, + }, + }, + min_sdk_version: "VanillaIceCream", +} + +rust_test { + name: "libnativewindow_rs-internal_test", + crate_name: "nativewindow", + defaults: ["libnativewindow_defaults"], + test_suites: ["general-tests"], +} diff --git a/libs/nativewindow/rust/src/lib.rs b/libs/nativewindow/rust/src/lib.rs new file mode 100644 index 0000000000..6eb3bbcdb3 --- /dev/null +++ b/libs/nativewindow/rust/src/lib.rs @@ -0,0 +1,329 @@ +// Copyright (C) 2023 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Pleasant Rust bindings for libnativewindow, including AHardwareBuffer + +extern crate nativewindow_bindgen as ffi; + +pub use ffi::{AHardwareBuffer, AHardwareBuffer_Format, AHardwareBuffer_UsageFlags}; + +use std::fmt::{self, Debug, Formatter}; +use std::mem::ManuallyDrop; +use std::ptr::{self, NonNull}; + +/// Wrapper around an opaque C AHardwareBuffer. +#[derive(PartialEq, Eq)] +pub struct HardwareBuffer(NonNull<AHardwareBuffer>); + +impl HardwareBuffer { + /// Test whether the given format and usage flag combination is allocatable. If this function + /// returns true, it means that a buffer with the given description can be allocated on this + /// implementation, unless resource exhaustion occurs. If this function returns false, it means + /// that the allocation of the given description will never succeed. + /// + /// Available since API 29 + pub fn is_supported( + width: u32, + height: u32, + layers: u32, + format: AHardwareBuffer_Format::Type, + usage: AHardwareBuffer_UsageFlags, + stride: u32, + ) -> bool { + let buffer_desc = ffi::AHardwareBuffer_Desc { + width, + height, + layers, + format, + usage: usage.0, + stride, + rfu0: 0, + rfu1: 0, + }; + // SAFETY: *buffer_desc will never be null. + let status = unsafe { ffi::AHardwareBuffer_isSupported(&buffer_desc) }; + + status == 1 + } + + /// Allocates a buffer that matches the passed AHardwareBuffer_Desc. If allocation succeeds, the + /// buffer can be used according to the usage flags specified in its description. If a buffer is + /// used in ways not compatible with its usage flags, the results are undefined and may include + /// program termination. + /// + /// Available since API level 26. + #[inline] + pub fn new( + width: u32, + height: u32, + layers: u32, + format: AHardwareBuffer_Format::Type, + usage: AHardwareBuffer_UsageFlags, + ) -> Option<Self> { + let buffer_desc = ffi::AHardwareBuffer_Desc { + width, + height, + layers, + format, + usage: usage.0, + stride: 0, + rfu0: 0, + rfu1: 0, + }; + let mut ptr = ptr::null_mut(); + // SAFETY: The returned pointer is valid until we drop/deallocate it. The function may fail + // and return a status, but we check it later. + let status = unsafe { ffi::AHardwareBuffer_allocate(&buffer_desc, &mut ptr) }; + + if status == 0 { + Some(Self(NonNull::new(ptr).expect("Allocated AHardwareBuffer was null"))) + } else { + None + } + } + + /// Adopts the raw pointer and wraps it in a Rust AHardwareBuffer. + /// + /// # Errors + /// + /// Will panic if buffer_ptr is null. + /// + /// # Safety + /// + /// This function adopts the pointer but does NOT increment the refcount on the buffer. If the + /// caller uses the pointer after the created object is dropped it will cause a memory leak. + pub unsafe fn from_raw(buffer_ptr: NonNull<AHardwareBuffer>) -> Self { + Self(buffer_ptr) + } + + /// Get the internal |AHardwareBuffer| pointer without decrementing the refcount. This can + /// be used to provide a pointer to the AHB for a C/C++ API over the FFI. + pub fn into_raw(self) -> NonNull<AHardwareBuffer> { + let buffer = ManuallyDrop::new(self); + buffer.0 + } + + /// Get the system wide unique id for an AHardwareBuffer. This function may panic in extreme + /// and undocumented circumstances. + /// + /// Available since API level 31. + pub fn id(&self) -> u64 { + let mut out_id = 0; + // SAFETY: Neither pointers can be null. + let status = unsafe { ffi::AHardwareBuffer_getId(self.0.as_ref(), &mut out_id) }; + assert_eq!(status, 0, "id() failed for AHardwareBuffer with error code: {status}"); + + out_id + } + + /// Get the width of this buffer + pub fn width(&self) -> u32 { + self.description().width + } + + /// Get the height of this buffer + pub fn height(&self) -> u32 { + self.description().height + } + + /// Get the number of layers of this buffer + pub fn layers(&self) -> u32 { + self.description().layers + } + + /// Get the format of this buffer + pub fn format(&self) -> AHardwareBuffer_Format::Type { + self.description().format + } + + /// Get the usage bitvector of this buffer + pub fn usage(&self) -> AHardwareBuffer_UsageFlags { + AHardwareBuffer_UsageFlags(self.description().usage) + } + + /// Get the stride of this buffer + pub fn stride(&self) -> u32 { + self.description().stride + } + + fn description(&self) -> ffi::AHardwareBuffer_Desc { + let mut buffer_desc = ffi::AHardwareBuffer_Desc { + width: 0, + height: 0, + layers: 0, + format: 0, + usage: 0, + stride: 0, + rfu0: 0, + rfu1: 0, + }; + // SAFETY: neither the buffer nor AHardwareBuffer_Desc pointers will be null. + unsafe { ffi::AHardwareBuffer_describe(self.0.as_ref(), &mut buffer_desc) }; + buffer_desc + } +} + +impl Drop for HardwareBuffer { + fn drop(&mut self) { + // SAFETY: self.0 will never be null. AHardwareBuffers allocated from within Rust will have + // a refcount of one, and there is a safety warning on taking an AHardwareBuffer from a raw + // pointer requiring callers to ensure the refcount is managed appropriately. + unsafe { ffi::AHardwareBuffer_release(self.0.as_ptr()) } + } +} + +impl Debug for HardwareBuffer { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + f.debug_struct("HardwareBuffer").field("id", &self.id()).finish() + } +} + +impl Clone for HardwareBuffer { + fn clone(&self) -> Self { + // SAFETY: ptr is guaranteed to be non-null and the acquire can not fail. + unsafe { ffi::AHardwareBuffer_acquire(self.0.as_ptr()) }; + Self(self.0) + } +} + +// SAFETY: The underlying *AHardwareBuffers can be moved between threads. +unsafe impl Send for HardwareBuffer {} + +// SAFETY: The underlying *AHardwareBuffers can be used from multiple threads. +// +// AHardwareBuffers are backed by C++ GraphicBuffers, which are mostly immutable. The only cases +// where they are not immutable are: +// +// - reallocation (which is never actually done across the codebase and requires special +// privileges/platform code access to do) +// - "locking" for reading/writing (which is explicitly allowed to be done across multiple threads +// according to the docs on the underlying gralloc calls) +unsafe impl Sync for HardwareBuffer {} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn create_valid_buffer_returns_ok() { + let buffer = HardwareBuffer::new( + 512, + 512, + 1, + AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM, + AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN, + ); + assert!(buffer.is_some()); + } + + #[test] + fn create_invalid_buffer_returns_err() { + let buffer = HardwareBuffer::new(512, 512, 1, 0, AHardwareBuffer_UsageFlags(0)); + assert!(buffer.is_none()); + } + + #[test] + fn from_raw_allows_getters() { + let buffer_desc = ffi::AHardwareBuffer_Desc { + width: 1024, + height: 512, + layers: 1, + format: AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM, + usage: AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN.0, + stride: 0, + rfu0: 0, + rfu1: 0, + }; + let mut raw_buffer_ptr = ptr::null_mut(); + + // SAFETY: The pointers are valid because they come from references, and + // `AHardwareBuffer_allocate` doesn't retain them after it returns. + let status = unsafe { ffi::AHardwareBuffer_allocate(&buffer_desc, &mut raw_buffer_ptr) }; + assert_eq!(status, 0); + + // SAFETY: The pointer must be valid because it was just allocated successfully, and we + // don't use it after calling this. + let buffer = unsafe { HardwareBuffer::from_raw(NonNull::new(raw_buffer_ptr).unwrap()) }; + assert_eq!(buffer.width(), 1024); + } + + #[test] + fn basic_getters() { + let buffer = HardwareBuffer::new( + 1024, + 512, + 1, + AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM, + AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN, + ) + .expect("Buffer with some basic parameters was not created successfully"); + + assert_eq!(buffer.width(), 1024); + assert_eq!(buffer.height(), 512); + assert_eq!(buffer.layers(), 1); + assert_eq!(buffer.format(), AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM); + assert_eq!( + buffer.usage(), + AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN + ); + } + + #[test] + fn id_getter() { + let buffer = HardwareBuffer::new( + 1024, + 512, + 1, + AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM, + AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN, + ) + .expect("Buffer with some basic parameters was not created successfully"); + + assert_ne!(0, buffer.id()); + } + + #[test] + fn clone() { + let buffer = HardwareBuffer::new( + 1024, + 512, + 1, + AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM, + AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN, + ) + .expect("Buffer with some basic parameters was not created successfully"); + let buffer2 = buffer.clone(); + + assert_eq!(buffer, buffer2); + } + + #[test] + fn into_raw() { + let buffer = HardwareBuffer::new( + 1024, + 512, + 1, + AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM, + AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN, + ) + .expect("Buffer with some basic parameters was not created successfully"); + let buffer2 = buffer.clone(); + + let raw_buffer = buffer.into_raw(); + // SAFETY: This is the same pointer we had before. + let remade_buffer = unsafe { HardwareBuffer::from_raw(raw_buffer) }; + + assert_eq!(remade_buffer, buffer2); + } +} diff --git a/libs/nativewindow/rust/sys/nativewindow_bindings.h b/libs/nativewindow/rust/sys/nativewindow_bindings.h new file mode 100644 index 0000000000..e652aee711 --- /dev/null +++ b/libs/nativewindow/rust/sys/nativewindow_bindings.h @@ -0,0 +1,20 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <android/data_space.h> +#include <android/hardware_buffer.h> +#include <android/hdr_metadata.h> +#include <android/native_window.h> diff --git a/libs/nativewindow/tests/benchmark/Android.bp b/libs/nativewindow/tests/benchmark/Android.bp new file mode 100644 index 0000000000..6f844cf864 --- /dev/null +++ b/libs/nativewindow/tests/benchmark/Android.bp @@ -0,0 +1,50 @@ +// Copyright (C) 2023 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +cc_defaults { + name: "nativewindow_benchmark_defaults_cc", + shared_libs: ["libnativewindow"], + static_libs: [ + "libbase", + "libgoogle-benchmark-main", + ], + test_suites: [ + "device-tests", + "NativeWindowBenchmarks", + ], +} + +cc_benchmark { + name: "nativewindow_buffer_benchmarks_cc", + srcs: ["buffer_benchmarks.cc"], + defaults: ["nativewindow_benchmark_defaults_cc"], +} + +rust_defaults { + name: "nativewindow_benchmark_defaults_rs", + rustlibs: [ + "libnativewindow_rs", + "libcriterion", + ], + test_suites: [ + "device-tests", + "NativeWindowBenchmarks", + ], +} + +rust_benchmark { + name: "nativewindow_buffer_benchmarks_rs", + srcs: ["buffer_benchmarks.rs"], + defaults: ["nativewindow_benchmark_defaults_rs"], +} diff --git a/libs/nativewindow/tests/benchmark/README.md b/libs/nativewindow/tests/benchmark/README.md new file mode 100644 index 0000000000..7eae538dd2 --- /dev/null +++ b/libs/nativewindow/tests/benchmark/README.md @@ -0,0 +1,22 @@ +# libnativewindow Benchmarks + +This directory contains benchmarks for the C++ and Rust variants of +libnativewindow. + +## Running + +It is currently a little tricky to get statistics from Rust benchmarks directly +from tradefed. But we can hack it by using atest to build/push, then running +the benchmarks by hand to get stats. + +``` + $ atest nativewindow_buffer_benchmarks_rs nativewindow_buffer_benchmarks_cc -d + $ adb shell /data/local/tmp/nativewindow_buffer_benchmarks_cc/x86_64/nativewindow_buffer_benchmarks_cc + $ adb shell /data/local/tmp/nativewindow_buffer_benchmarks_rs/x86_64/nativewindow_buffer_benchmarks_rs --bench +``` + +## Results + +On a remote emulator, the results we see from the benchmarks from Rust and C++ +seem to be roughly equivalent! Allocating/deallocating a 720p buffer takes +~2.3ms on each. diff --git a/libs/nativewindow/tests/benchmark/buffer_benchmarks.cc b/libs/nativewindow/tests/benchmark/buffer_benchmarks.cc new file mode 100644 index 0000000000..9b31993809 --- /dev/null +++ b/libs/nativewindow/tests/benchmark/buffer_benchmarks.cc @@ -0,0 +1,74 @@ +// Copyright (C) 2023 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include <android-base/macros.h> +#include <android/hardware_buffer.h> +#include <benchmark/benchmark.h> + +constexpr AHardwareBuffer_Desc k720pDesc = {.width = 1280, + .height = 720, + .layers = 1, + .format = AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM, + .usage = AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN, + .stride = 0}; + +static void BM_BufferAllocationDeallocation(benchmark::State& state) { + AHardwareBuffer* buffer = nullptr; + for (auto _ : state) { + int status = AHardwareBuffer_allocate(&k720pDesc, &buffer); + if (UNLIKELY(status != 0)) { + state.SkipWithError("Unable to allocate buffer."); + } + AHardwareBuffer_release(buffer); + buffer = nullptr; + } +} +BENCHMARK(BM_BufferAllocationDeallocation); + +static void BM_AHardwareBuffer_Id(benchmark::State& state) { + AHardwareBuffer* buffer = nullptr; + int status = AHardwareBuffer_allocate(&k720pDesc, &buffer); + if (UNLIKELY(status != 0)) { + state.SkipWithError("Unable to allocate buffer."); + } + + for (auto _ : state) { + uint64_t id = 0; + int status = AHardwareBuffer_getId(buffer, &id); + if (UNLIKELY(status != 0)) { + state.SkipWithError("Unable to get ID."); + } + } + + AHardwareBuffer_release(buffer); +} +BENCHMARK(BM_AHardwareBuffer_Id); + +static void BM_AHardwareBuffer_Desc(benchmark::State& state) { + AHardwareBuffer* buffer = nullptr; + int status = AHardwareBuffer_allocate(&k720pDesc, &buffer); + if (UNLIKELY(status != 0)) { + state.SkipWithError("Unable to allocate buffer."); + } + + for (auto _ : state) { + AHardwareBuffer_Desc desc = {}; + AHardwareBuffer_describe(buffer, &desc); + } + + AHardwareBuffer_release(buffer); +} +BENCHMARK(BM_AHardwareBuffer_Desc); + +BENCHMARK_MAIN(); diff --git a/libs/nativewindow/tests/benchmark/buffer_benchmarks.rs b/libs/nativewindow/tests/benchmark/buffer_benchmarks.rs new file mode 100644 index 0000000000..876f6c8e26 --- /dev/null +++ b/libs/nativewindow/tests/benchmark/buffer_benchmarks.rs @@ -0,0 +1,60 @@ +// Copyright (C) 2023 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Benchmark for libnativewindow AHardwareBuffer bindings + +#![allow(dead_code)] +#![allow(missing_docs)] + +use criterion::*; +use nativewindow::*; + +#[inline] +fn create_720p_buffer() -> HardwareBuffer { + HardwareBuffer::new( + 1280, + 720, + 1, + AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM, + AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN, + ) + .unwrap() +} + +fn criterion_benchmark(c: &mut Criterion) { + c.bench_function("allocate_deallocate", |b| { + b.iter(|| { + let buffer = create_720p_buffer(); + drop(buffer); + }) + }); + + let buffer = create_720p_buffer(); + c.bench_with_input(BenchmarkId::new("id", "buffer"), &buffer, |b, buffer| { + b.iter(|| { + buffer.id(); + }) + }); + + // This benchmark exercises getters that need to fetch data via an + // underlying call to AHardwareBuffer_describe. + c.bench_with_input(BenchmarkId::new("desc", "buffer"), &buffer, |b, buffer| { + b.iter(|| { + buffer.width(); + }) + }); +} + +criterion_group!(benches, criterion_benchmark); +criterion_main!(benches); |