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/libvrflinger/Android.bp b/libs/vr/libvrflinger/Android.bp
index d37031f..080479a 100644
--- a/libs/vr/libvrflinger/Android.bp
+++ b/libs/vr/libvrflinger/Android.bp
@@ -36,6 +36,7 @@
"libvrsensor",
"libpdx_default_transport",
"libvr_manager",
+ "libbroadcastring",
]
sharedLibraries = [
@@ -77,7 +78,7 @@
"-DEGL_EGLEXT_PROTOTYPES",
],
shared_libs: sharedLibraries,
- header_libs: headerLibraries,
whole_static_libs: staticLibraries,
+ header_libs: headerLibraries,
name: "libvrflinger",
}
diff --git a/libs/vr/libvrflinger/display_manager_service.cpp b/libs/vr/libvrflinger/display_manager_service.cpp
index 7b5aa79..c5b0d88 100644
--- a/libs/vr/libvrflinger/display_manager_service.cpp
+++ b/libs/vr/libvrflinger/display_manager_service.cpp
@@ -98,6 +98,11 @@
*this, &DisplayManagerService::OnGetConfigurationData, message);
return {};
+ case DisplayManagerProtocol::DeleteGlobalBuffer::Opcode:
+ DispatchRemoteMethod<DisplayManagerProtocol::DeleteGlobalBuffer>(
+ *this, &DisplayManagerService::OnDeleteGlobalBuffer, message);
+ return {};
+
default:
return Service::DefaultHandleMessage(message);
}
@@ -161,6 +166,19 @@
return display_service_->SetupGlobalBuffer(key, size, usage);
}
+pdx::Status<void> DisplayManagerService::OnDeleteGlobalBuffer(
+ pdx::Message& message, DvrGlobalBufferKey key) {
+ const int user_id = message.GetEffectiveUserId();
+ const bool trusted = (user_id == AID_ROOT) || IsTrustedUid(user_id);
+
+ if (!trusted) {
+ ALOGE("DisplayService::DeleteGlobalBuffer: Untrusted user_id (%d)",
+ user_id);
+ return ErrorStatus(EPERM);
+ }
+ return display_service_->DeleteGlobalBuffer(key);
+}
+
pdx::Status<std::string> DisplayManagerService::OnGetConfigurationData(
pdx::Message& message, display::ConfigFileType config_type) {
std::string property_name;
diff --git a/libs/vr/libvrflinger/display_manager_service.h b/libs/vr/libvrflinger/display_manager_service.h
index 4a08405..20c5507 100644
--- a/libs/vr/libvrflinger/display_manager_service.h
+++ b/libs/vr/libvrflinger/display_manager_service.h
@@ -59,6 +59,8 @@
pdx::Status<BorrowedNativeBufferHandle> OnSetupGlobalBuffer(
pdx::Message& message, DvrGlobalBufferKey key, size_t size,
uint64_t usage);
+ pdx::Status<void> OnDeleteGlobalBuffer(pdx::Message& message,
+ DvrGlobalBufferKey key);
pdx::Status<std::string> OnGetConfigurationData(
pdx::Message& message, display::ConfigFileType config_type);
diff --git a/libs/vr/libvrflinger/display_service.cpp b/libs/vr/libvrflinger/display_service.cpp
index 4cc5f02..b180848 100644
--- a/libs/vr/libvrflinger/display_service.cpp
+++ b/libs/vr/libvrflinger/display_service.cpp
@@ -227,6 +227,12 @@
if (global_buffer == global_buffers_.end()) {
auto ion_buffer = std::make_unique<IonBuffer>(static_cast<int>(size), 1,
HAL_PIXEL_FORMAT_BLOB, usage);
+
+ // Some buffers are used internally. If they were configured with an
+ // invalid size or format, this will fail.
+ int result = hardware_composer_.OnNewGlobalBuffer(key, *ion_buffer.get());
+ if (result < 0)
+ return ErrorStatus(result);
global_buffer =
global_buffers_.insert(std::make_pair(key, std::move(ion_buffer)))
.first;
@@ -235,6 +241,17 @@
return {BorrowedNativeBufferHandle(*global_buffer->second, 0)};
}
+pdx::Status<void> DisplayService::DeleteGlobalBuffer(DvrGlobalBufferKey key) {
+ auto global_buffer = global_buffers_.find(key);
+ if (global_buffer != global_buffers_.end()) {
+ // Some buffers are used internally.
+ hardware_composer_.OnDeletedGlobalBuffer(key);
+ global_buffers_.erase(global_buffer);
+ }
+
+ return {0};
+}
+
void DisplayService::OnHardwareComposerRefresh() {
hardware_composer_.OnHardwareComposerRefresh();
}
diff --git a/libs/vr/libvrflinger/display_service.h b/libs/vr/libvrflinger/display_service.h
index 77e45a4..8ba1728 100644
--- a/libs/vr/libvrflinger/display_service.h
+++ b/libs/vr/libvrflinger/display_service.h
@@ -44,6 +44,8 @@
pdx::Status<BorrowedNativeBufferHandle> SetupGlobalBuffer(
DvrGlobalBufferKey key, size_t size, uint64_t usage);
+ pdx::Status<void> DeleteGlobalBuffer(DvrGlobalBufferKey key);
+
template <class A>
void ForEachDisplaySurface(SurfaceType surface_type, A action) const {
ForEachChannel([surface_type,
diff --git a/libs/vr/libvrflinger/hardware_composer.cpp b/libs/vr/libvrflinger/hardware_composer.cpp
index 34474d9..88173ca 100644
--- a/libs/vr/libvrflinger/hardware_composer.cpp
+++ b/libs/vr/libvrflinger/hardware_composer.cpp
@@ -19,6 +19,7 @@
#include <chrono>
#include <functional>
#include <map>
+#include <tuple>
#include <dvr/dvr_display_types.h>
#include <dvr/performance_client_api.h>
@@ -37,17 +38,6 @@
namespace {
-// 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.
-constexpr int kAllowedPendingFenceCount = 0;
-
-// Offset before vsync to submit frames to hardware composer.
-constexpr int64_t kFramePostOffsetNs = 4000000; // 4ms
-
const char kBacklightBrightnessSysFile[] =
"/sys/class/leds/lcd-backlight/brightness";
@@ -397,8 +387,8 @@
}
const bool is_frame_pending = IsFramePendingInDriver();
- const bool is_fence_pending =
- retire_fence_fds_.size() > kAllowedPendingFenceCount;
+ const bool is_fence_pending = retire_fence_fds_.size() >
+ post_thread_config_.allowed_pending_fence_count;
if (is_fence_pending || is_frame_pending) {
ATRACE_INT("frame_skip_count", ++frame_skip_count_);
@@ -475,6 +465,62 @@
request_display_callback_(!display_idle);
}
+int HardwareComposer::OnNewGlobalBuffer(DvrGlobalBufferKey key,
+ IonBuffer& ion_buffer) {
+ if (key == kVrFlingerConfigBufferKey) {
+ return MapConfigBuffer(ion_buffer);
+ }
+
+ return 0;
+}
+
+void HardwareComposer::OnDeletedGlobalBuffer(DvrGlobalBufferKey key) {
+ if (key == kVrFlingerConfigBufferKey) {
+ ConfigBufferDeleted();
+ }
+}
+
+int HardwareComposer::MapConfigBuffer(IonBuffer& ion_buffer) {
+ std::lock_guard<std::mutex> lock(shared_config_mutex_);
+ shared_config_ring_ = DvrVrFlingerConfigRing();
+
+ if (ion_buffer.width() < DvrVrFlingerConfigRing::MemorySize()) {
+ ALOGE("HardwareComposer::MapConfigBuffer: invalid buffer size.");
+ return -EINVAL;
+ }
+
+ void* buffer_base = 0;
+ int result = ion_buffer.Lock(ion_buffer.usage(), 0, 0, ion_buffer.width(),
+ ion_buffer.height(), &buffer_base);
+ if (result != 0) {
+ ALOGE("HardwareComposer::MapConfigBuffer: Failed to map vrflinger config "
+ "buffer.");
+ return -EPERM;
+ }
+
+ shared_config_ring_ =
+ DvrVrFlingerConfigRing::Create(buffer_base, ion_buffer.width());
+ ion_buffer.Unlock();
+
+ return 0;
+}
+
+void HardwareComposer::ConfigBufferDeleted() {
+ std::lock_guard<std::mutex> lock(shared_config_mutex_);
+ shared_config_ring_ = DvrVrFlingerConfigRing();
+}
+
+void HardwareComposer::UpdateConfigBuffer() {
+ std::lock_guard<std::mutex> lock(shared_config_mutex_);
+ if (!shared_config_ring_.is_valid())
+ return;
+ // Copy from latest record in shared_config_ring_ to local copy.
+ DvrVrFlingerConfigBuffer record;
+ if (shared_config_ring_.GetNewest(&shared_config_ring_sequence_, &record)) {
+ post_thread_config_ = record;
+ }
+}
+
int HardwareComposer::PostThreadPollInterruptible(
const pdx::LocalHandle& event_fd, int requested_events) {
pollfd pfd[2] = {
@@ -744,6 +790,9 @@
while (1) {
ATRACE_NAME("HardwareComposer::PostThread");
+ // Check for updated config once per vsync.
+ UpdateConfigBuffer();
+
while (post_thread_quiescent_) {
std::unique_lock<std::mutex> lock(post_thread_mutex_);
ALOGI("HardwareComposer::PostThread: Entering quiescent state.");
@@ -823,9 +872,10 @@
const int64_t display_time_est_ns = vsync_timestamp + ns_per_frame;
const int64_t now_ns = GetSystemClockNs();
- const int64_t sleep_time_ns =
- display_time_est_ns - now_ns - kFramePostOffsetNs;
- const int64_t wakeup_time_ns = display_time_est_ns - kFramePostOffsetNs;
+ const int64_t sleep_time_ns = display_time_est_ns - now_ns -
+ post_thread_config_.frame_post_offset_ns;
+ const int64_t wakeup_time_ns =
+ display_time_est_ns - post_thread_config_.frame_post_offset_ns;
ATRACE_INT64("sleep_time_ns", sleep_time_ns);
if (sleep_time_ns > 0) {
diff --git a/libs/vr/libvrflinger/hardware_composer.h b/libs/vr/libvrflinger/hardware_composer.h
index 8ba72ab..c182bf9 100644
--- a/libs/vr/libvrflinger/hardware_composer.h
+++ b/libs/vr/libvrflinger/hardware_composer.h
@@ -16,6 +16,7 @@
#include <tuple>
#include <vector>
+#include <dvr/dvr_vrflinger_config_buffer.h>
#include <dvr/pose_client.h>
#include <pdx/file_handle.h>
#include <pdx/rpc/variant.h>
@@ -284,6 +285,9 @@
void SetDisplaySurfaces(
std::vector<std::shared_ptr<DirectDisplaySurface>> surfaces);
+ int OnNewGlobalBuffer(DvrGlobalBufferKey key, IonBuffer& ion_buffer);
+ void OnDeletedGlobalBuffer(DvrGlobalBufferKey key);
+
void OnHardwareComposerRefresh();
private:
@@ -365,6 +369,13 @@
// Called on the post thread when the post thread is paused or quits.
void OnPostThreadPaused();
+ // Map the given shared memory buffer to our broadcast ring to track updates
+ // to the config parameters.
+ int MapConfigBuffer(IonBuffer& ion_buffer);
+ void ConfigBufferDeleted();
+ // Poll for config udpates.
+ void UpdateConfigBuffer();
+
bool initialized_;
// Hardware composer HAL device from SurfaceFlinger. VrFlinger does not own
@@ -439,6 +450,13 @@
// out to display frame boundaries, so we need to tell it about vsyncs.
DvrPose* pose_client_ = nullptr;
+ // Broadcast ring for receiving config data from the DisplayManager.
+ DvrVrFlingerConfigRing shared_config_ring_;
+ uint32_t shared_config_ring_sequence_{0};
+ // Config buffer for reading from the post thread.
+ DvrVrFlingerConfigBuffer post_thread_config_;
+ std::mutex shared_config_mutex_;
+
static constexpr int kPostThreadInterrupted = 1;
static void HwcRefresh(hwc2_callback_data_t data, hwc2_display_t display);