Add shmem config buffer to libvrflinger
This allows VrCore to configure some tunable behaviors
of libvrflinger.
- Added dvrDisplayManagerDeleteNamedBuffer for testing config buffer
creation.
- Added tests for named buffers, including one for the config buffer.
- Added IsValid to broadcast_ring to avoid tracking redundant state
externally.
Bug: 38193993
Test: Run dvr_named_buffer-test
Change-Id: I52722dd314233b5bea1ca6377c14b5c856825746
diff --git a/libs/vr/libdvr/dvr_display_manager.cpp b/libs/vr/libdvr/dvr_display_manager.cpp
index e67e8c3..ffe090d 100644
--- a/libs/vr/libdvr/dvr_display_manager.cpp
+++ b/libs/vr/libdvr/dvr_display_manager.cpp
@@ -133,6 +133,23 @@
return 0;
}
+int dvrDisplayManagerDeleteGlobalBuffer(DvrDisplayManager* client,
+ DvrGlobalBufferKey key) {
+ if (!client)
+ return -EINVAL;
+
+ auto buffer_status = client->client->DeleteGlobalBuffer(key);
+ if (!buffer_status) {
+ ALOGE(
+ "dvrDisplayManagerDeleteGlobalBuffer: Failed to delete named buffer: "
+ "%s",
+ buffer_status.GetErrorMessage().c_str());
+ return -buffer_status.error();
+ }
+
+ return 0;
+}
+
int dvrConfigurationDataGet(DvrDisplayManager* client, int config_type,
uint8_t** data, size_t* data_size) {
if (!client || !data || !data_size) {
diff --git a/libs/vr/libdvr/include/dvr/dvr_display_manager.h b/libs/vr/libdvr/include/dvr/dvr_display_manager.h
index f8db182..eb1e711 100644
--- a/libs/vr/libdvr/include/dvr/dvr_display_manager.h
+++ b/libs/vr/libdvr/include/dvr/dvr_display_manager.h
@@ -32,6 +32,14 @@
DvrGlobalBufferKey key, size_t size,
uint64_t usage, DvrBuffer** buffer_out);
+// Deletes a named buffer. WARNING: This is dangerous because any existing
+// clients of this buffer will not be notified and will remain attached to
+// the old buffer. This is useful for tests, but probably not for production
+// code.
+// @return 0 on success. Otherwise returns a negative error value.
+int dvrDisplayManagerDeleteGlobalBuffer(DvrDisplayManager* client,
+ DvrGlobalBufferKey key);
+
// Device metrics data type enums.
enum {
DVR_CONFIGURATION_DATA_LENS_METRICS = 0,
diff --git a/libs/vr/libdvr/include/dvr/dvr_vrflinger_config_buffer.h b/libs/vr/libdvr/include/dvr/dvr_vrflinger_config_buffer.h
new file mode 100644
index 0000000..108c78b
--- /dev/null
+++ b/libs/vr/libdvr/include/dvr/dvr_vrflinger_config_buffer.h
@@ -0,0 +1,51 @@
+#ifndef ANDROID_DVR_VRFLINGER_CONFIG_BUFFER_H
+#define ANDROID_DVR_VRFLINGER_CONFIG_BUFFER_H
+
+#include <libbroadcastring/broadcast_ring.h>
+
+// This header is shared by VrCore and Android and must be kept in sync.
+
+namespace android {
+namespace dvr {
+
+// Increment when the layout for the buffers change.
+constexpr uint32_t kSharedConfigBufferLayoutVersion = 1;
+
+// This is a shared memory buffer for passing config data from VrCore to
+// libvrflinger in SurfaceFlinger.
+struct DvrVrFlingerConfigBuffer {
+ // Offset before vsync to submit frames to hardware composer.
+ int frame_post_offset_ns{4000000};
+
+ // If the number of pending fences goes over this count at the point when we
+ // are about to submit a new frame to HWC, we will drop the frame. This
+ // should be a signal that the display driver has begun queuing frames. Note
+ // that with smart displays (with RAM), the fence is signaled earlier than
+ // the next vsync, at the point when the DMA to the display completes.
+ // Currently we use a smart display and the EDS timing coincides with zero
+ // pending fences, so this is 0.
+ size_t allowed_pending_fence_count{0};
+
+ // New fields should always be added to the end for backwards compat.
+};
+
+class DvrVrFlingerConfigBufferTraits {
+ public:
+ using Record = DvrVrFlingerConfigBuffer;
+ static constexpr bool kUseStaticRecordSize = false;
+ static constexpr uint32_t kStaticRecordCount = 2;
+ static constexpr int kMaxReservedRecords = 1;
+ static constexpr int kMinAvailableRecords = 1;
+};
+
+// The broadcast ring classes that will expose the data.
+using DvrVrFlingerConfigRing =
+ BroadcastRing<DvrVrFlingerConfigBuffer, DvrVrFlingerConfigBufferTraits>;
+
+// Common buffers.
+constexpr int kVrFlingerConfigBufferKey = 5;
+
+} // namespace dvr
+} // namespace android
+
+#endif // ANDROID_DVR_VRFLINGER_CONFIG_BUFFER_H
diff --git a/libs/vr/libdvr/tests/Android.bp b/libs/vr/libdvr/tests/Android.bp
index ef746e2..ab2ee75 100644
--- a/libs/vr/libdvr/tests/Android.bp
+++ b/libs/vr/libdvr/tests/Android.bp
@@ -32,6 +32,7 @@
"libdvrcommon",
"libdisplay",
"libpdx_default_transport",
+ "libbroadcastring",
]
cc_test {
diff --git a/libs/vr/libdvr/tests/dvr_named_buffer-test.cpp b/libs/vr/libdvr/tests/dvr_named_buffer-test.cpp
index 336f11f..cf04588 100644
--- a/libs/vr/libdvr/tests/dvr_named_buffer-test.cpp
+++ b/libs/vr/libdvr/tests/dvr_named_buffer-test.cpp
@@ -2,6 +2,7 @@
#include <dvr/dvr_buffer.h>
#include <dvr/dvr_display_manager.h>
#include <dvr/dvr_surface.h>
+#include <dvr/dvr_vrflinger_config_buffer.h>
#include <system/graphics.h>
#include <base/logging.h>
@@ -12,7 +13,7 @@
namespace {
-class DvrNamedBufferTest : public ::testing::Test {
+class DvrGlobalBufferTest : public ::testing::Test {
protected:
void SetUp() override {
const int ret = dvrDisplayManagerCreate(&client_);
@@ -28,7 +29,7 @@
DvrDisplayManager* client_ = nullptr;
};
-TEST_F(DvrNamedBufferTest, TestNamedBuffersSameName) {
+TEST_F(DvrGlobalBufferTest, TestGlobalBuffersSameName) {
const DvrGlobalBufferKey buffer_key = 101;
DvrBuffer* buffer1 = nullptr;
int ret1 =
@@ -95,7 +96,7 @@
AHardwareBuffer_release(hardware_buffer3);
}
-TEST_F(DvrNamedBufferTest, TestMultipleNamedBuffers) {
+TEST_F(DvrGlobalBufferTest, TestMultipleGlobalBuffers) {
const DvrGlobalBufferKey buffer_key1 = 102;
const DvrGlobalBufferKey buffer_key2 = 103;
DvrBuffer* setup_buffer1 = nullptr;
@@ -125,7 +126,7 @@
dvrBufferDestroy(buffer2);
}
-TEST_F(DvrNamedBufferTest, TestNamedBufferUsage) {
+TEST_F(DvrGlobalBufferTest, TestGlobalBufferUsage) {
const DvrGlobalBufferKey buffer_key = 100;
// Set usage to AHARDWAREBUFFER_USAGE_VIDEO_ENCODE. We use this because
@@ -154,6 +155,153 @@
AHardwareBuffer_release(hardware_buffer);
}
+TEST_F(DvrGlobalBufferTest, TestGlobalBufferCarriesData) {
+ const DvrGlobalBufferKey buffer_name = 110;
+
+ uint64_t usage = AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN |
+ AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN;
+ constexpr size_t size = 1024 * sizeof(uint64_t);
+ constexpr uint64_t value = 0x123456787654321;
+
+ {
+ // Allocate some data and set it to something.
+ DvrBuffer* setup_buffer = nullptr;
+ int e1 = dvrDisplayManagerSetupGlobalBuffer(client_, buffer_name, size,
+ usage, &setup_buffer);
+ ASSERT_NE(nullptr, setup_buffer);
+ ASSERT_EQ(0, e1);
+
+ AHardwareBuffer* hardware_buffer = nullptr;
+ int e2 = dvrBufferGetAHardwareBuffer(setup_buffer, &hardware_buffer);
+ ASSERT_EQ(0, e2);
+ ASSERT_NE(nullptr, hardware_buffer);
+
+ void* buffer;
+ int e3 = AHardwareBuffer_lock(hardware_buffer, usage, -1, nullptr, &buffer);
+ ASSERT_EQ(0, e3);
+ ASSERT_NE(nullptr, buffer);
+ // Verify that the buffer pointer is at least 16 byte aligned.
+ ASSERT_EQ(0, reinterpret_cast<uintptr_t>(buffer) & (16 - 1));
+
+ uint64_t* data = static_cast<uint64_t*>(buffer);
+ constexpr size_t num_values = size / sizeof(uint64_t);
+ for (size_t i = 0; i < num_values; ++i) {
+ data[i] = value;
+ }
+
+ int32_t fence = -1;
+ int e4 = AHardwareBuffer_unlock(hardware_buffer, &fence);
+ ASSERT_EQ(0, e4);
+
+ dvrBufferDestroy(setup_buffer);
+ AHardwareBuffer_release(hardware_buffer);
+ }
+
+ {
+ // Get the buffer and check that all the data is still present.
+ DvrBuffer* setup_buffer = nullptr;
+ int e1 = dvrGetGlobalBuffer(buffer_name, &setup_buffer);
+ ASSERT_NE(nullptr, setup_buffer);
+ ASSERT_EQ(0, e1);
+
+ AHardwareBuffer* hardware_buffer = nullptr;
+ int e2 = dvrBufferGetAHardwareBuffer(setup_buffer, &hardware_buffer);
+ ASSERT_EQ(0, e2);
+ ASSERT_NE(nullptr, hardware_buffer);
+
+ void* buffer;
+ int e3 = AHardwareBuffer_lock(hardware_buffer, usage, -1, nullptr, &buffer);
+ ASSERT_EQ(0, e3);
+ ASSERT_NE(nullptr, buffer);
+ // Verify that the buffer pointer is at least 16 byte aligned.
+ ASSERT_EQ(0, reinterpret_cast<uintptr_t>(buffer) & (16 - 1));
+
+ uint64_t* data = static_cast<uint64_t*>(buffer);
+ constexpr size_t num_values = size / sizeof(uint64_t);
+ bool is_equal = true;
+ for (size_t i = 0; i < num_values; ++i) {
+ is_equal &= (data[i] == value);
+ }
+ ASSERT_TRUE(is_equal);
+
+ int32_t fence = -1;
+ int e4 = AHardwareBuffer_unlock(hardware_buffer, &fence);
+ ASSERT_EQ(0, e4);
+
+ dvrBufferDestroy(setup_buffer);
+ AHardwareBuffer_release(hardware_buffer);
+ }
+}
+
+TEST_F(DvrGlobalBufferTest, TestGlobalBufferZeroed) {
+ const DvrGlobalBufferKey buffer_name = 120;
+
+ // Allocate 1MB and check that it is all zeros.
+ uint64_t usage = AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN |
+ AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN;
+ constexpr size_t size = 1024 * 1024;
+ DvrBuffer* setup_buffer = nullptr;
+ int e1 = dvrDisplayManagerSetupGlobalBuffer(client_, buffer_name, size, usage,
+ &setup_buffer);
+ ASSERT_NE(nullptr, setup_buffer);
+ ASSERT_EQ(0, e1);
+
+ AHardwareBuffer* hardware_buffer = nullptr;
+ int e2 = dvrBufferGetAHardwareBuffer(setup_buffer, &hardware_buffer);
+ ASSERT_EQ(0, e2);
+ ASSERT_NE(nullptr, hardware_buffer);
+
+ void* buffer;
+ int e3 = AHardwareBuffer_lock(hardware_buffer, usage, -1, nullptr, &buffer);
+ ASSERT_EQ(0, e3);
+ ASSERT_NE(nullptr, buffer);
+ // Verify that the buffer pointer is at least 16 byte aligned.
+ ASSERT_EQ(0, reinterpret_cast<uintptr_t>(buffer) & (16 - 1));
+
+ uint64_t* data = static_cast<uint64_t*>(buffer);
+ constexpr size_t num_values = size / sizeof(uint64_t);
+ uint64_t zero = 0;
+ for (size_t i = 0; i < num_values; ++i) {
+ zero |= data[i];
+ }
+ ASSERT_EQ(0, zero);
+
+ int32_t fence = -1;
+ int e4 = AHardwareBuffer_unlock(hardware_buffer, &fence);
+ ASSERT_EQ(0, e4);
+
+ dvrBufferDestroy(setup_buffer);
+ AHardwareBuffer_release(hardware_buffer);
+}
+
+TEST_F(DvrGlobalBufferTest, TestVrflingerConfigBuffer) {
+ const DvrGlobalBufferKey buffer_name = kVrFlingerConfigBufferKey;
+
+ // First delete any existing buffer so we can test the failure case.
+ dvrDisplayManagerDeleteGlobalBuffer(client_, buffer_name);
+
+ const uint64_t usage = AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN |
+ AHARDWAREBUFFER_USAGE_CPU_WRITE_RARELY;
+
+ size_t correct_size = DvrVrFlingerConfigRing::MemorySize();
+ size_t wrong_size = DvrVrFlingerConfigRing::MemorySize(0);
+
+ // Setup an invalid config buffer (too small) and assert that it fails.
+ DvrBuffer* setup_buffer = nullptr;
+ int e1 = dvrDisplayManagerSetupGlobalBuffer(client_, buffer_name, wrong_size,
+ usage, &setup_buffer);
+ ASSERT_EQ(nullptr, setup_buffer);
+ ASSERT_GT(0, e1);
+
+ // Setup a correct config buffer.
+ int e2 = dvrDisplayManagerSetupGlobalBuffer(
+ client_, buffer_name, correct_size, usage, &setup_buffer);
+ ASSERT_NE(nullptr, setup_buffer);
+ ASSERT_EQ(0, e2);
+
+ dvrBufferDestroy(setup_buffer);
+}
+
} // namespace
} // namespace dvr