diff options
93 files changed, 3540 insertions, 914 deletions
diff --git a/cmds/installd/Android.mk b/cmds/installd/Android.mk index be1a4345ea..1d21b3ce1b 100644 --- a/cmds/installd/Android.mk +++ b/cmds/installd/Android.mk @@ -24,6 +24,7 @@ LOCAL_CFLAGS += -DART_BASE_ADDRESS_MIN_DELTA=$(LOCAL_LIBART_IMG_HOST_MIN_BASE_AD LOCAL_CFLAGS += -DART_BASE_ADDRESS_MAX_DELTA=$(LOCAL_LIBART_IMG_HOST_MAX_BASE_ADDRESS_DELTA) LOCAL_SRC_FILES := otapreopt.cpp globals.cpp utils.cpp dexopt.cpp +LOCAL_HEADER_LIBRARIES := dex2oat_headers LOCAL_SHARED_LIBRARIES := \ libbase \ libcutils \ diff --git a/cmds/installd/otapreopt.cpp b/cmds/installd/otapreopt.cpp index 82b8cc204d..e8e6b56ea4 100644 --- a/cmds/installd/otapreopt.cpp +++ b/cmds/installd/otapreopt.cpp @@ -33,6 +33,7 @@ #include <android-base/strings.h> #include <cutils/fs.h> #include <cutils/properties.h> +#include <dex2oat_return_codes.h> #include <log/log.h> #include <private/android_filesystem_config.h> @@ -576,7 +577,11 @@ private: } // If the dexopt failed, we may have a stale boot image from a previous OTA run. - // Try to delete and retry. + // Then regenerate and retry. + if (WEXITSTATUS(dexopt_result) != + static_cast<int>(art::dex2oat::ReturnCode::kCreateRuntime)) { + return dexopt_result; + } if (!PrepareBootImage(/* force */ true)) { LOG(ERROR) << "Forced boot image creating failed. Original error return was " diff --git a/cmds/servicemanager/Android.bp b/cmds/servicemanager/Android.bp index 68d39dbb52..39d92a7561 100644 --- a/cmds/servicemanager/Android.bp +++ b/cmds/servicemanager/Android.bp @@ -38,7 +38,7 @@ cc_binary { cc_binary { name: "vndservicemanager", defaults: ["servicemanager_flags"], - proprietary: true, + vendor: true, srcs: [ "service_manager.c", "binder.c", @@ -46,6 +46,7 @@ cc_binary { cflags: [ "-DVENDORSERVICEMANAGER=1", ], - shared_libs: ["libcutils", "libselinux"], + shared_libs: ["libcutils"], + static_libs: ["libselinux"], init_rc: ["vndservicemanager.rc"], } diff --git a/cmds/vr/vrscreencap/Android.mk b/cmds/vr/vrscreencap/Android.mk index bd0b224e0f..804afc9b38 100644 --- a/cmds/vr/vrscreencap/Android.mk +++ b/cmds/vr/vrscreencap/Android.mk @@ -6,6 +6,7 @@ LOCAL_SRC_FILES := \ vrscreencap.cpp LOCAL_STATIC_LIBRARIES := \ + libbufferhub \ libdisplay \ libimageio \ libpdx_default_transport \ @@ -14,7 +15,8 @@ LOCAL_SHARED_LIBRARIES := \ libcutils \ liblog \ libpng \ - libsync + libsync \ + libui \ LOCAL_MODULE := vrscreencap diff --git a/include/android/sensor.h b/include/android/sensor.h index 186f62c65e..cdb3fffedc 100644 --- a/include/android/sensor.h +++ b/include/android/sensor.h @@ -484,8 +484,9 @@ void ASensorManager_destroyDirectChannel(ASensorManager* manager, int channelId) * * Configure sensor direct report on a direct channel: set rate to value other than * {@link ASENSOR_DIRECT_RATE_STOP} so that sensor event can be directly - * written into the shared memory region used for creating the buffer; set rate to - * {@link ASENSOR_DIRECT_RATE_STOP} will stop the sensor direct report. + * written into the shared memory region used for creating the buffer. It returns a positive token + * which can be used for identify sensor events from different sensors on success. Calling with rate + * {@link ASENSOR_DIRECT_RATE_STOP} will stop direct report of the sensor specified in the channel. * * To stop all active sensor direct report configured to a channel, set sensor to NULL and rate to * {@link ASENSOR_DIRECT_RATE_STOP}. @@ -513,7 +514,7 @@ void ASensorManager_destroyDirectChannel(ASensorManager* manager, int channelId) * {@link ASensorManager_createSharedMemoryDirectChannel} or * {@link ASensorManager_createHardwareBufferDirectChannel}. * - * \return 0 for success or negative integer for failure. + * \return positive token for success or negative error code. */ int ASensorManager_configureDirectReport( ASensorManager* manager, ASensor const* sensor, int channelId, int rate); diff --git a/include/binder/Parcel.h b/include/binder/Parcel.h index cf2fa47df4..5d36526cb3 100644 --- a/include/binder/Parcel.h +++ b/include/binder/Parcel.h @@ -72,6 +72,8 @@ public: status_t appendFrom(const Parcel *parcel, size_t start, size_t len); + int compareData(const Parcel& other); + bool allowFds() const; bool pushAllowFds(bool allowFds); void restoreAllowFds(bool lastValue); diff --git a/include/gui/FrameTimestamps.h b/include/gui/FrameTimestamps.h index 92251edca6..9716be4bfd 100644 --- a/include/gui/FrameTimestamps.h +++ b/include/gui/FrameTimestamps.h @@ -54,8 +54,7 @@ struct FrameEvents { static constexpr auto EVENT_COUNT = static_cast<size_t>(FrameEvent::EVENT_COUNT); static_assert(EVENT_COUNT <= 32, "Event count sanity check failed."); - static constexpr nsecs_t TIMESTAMP_PENDING = - std::numeric_limits<nsecs_t>::max(); + static constexpr nsecs_t TIMESTAMP_PENDING = -2; static inline bool isValidTimestamp(nsecs_t time) { return time != TIMESTAMP_PENDING; diff --git a/include/gui/ISurfaceComposer.h b/include/gui/ISurfaceComposer.h index 2fbe07aa57..9870ba0715 100644 --- a/include/gui/ISurfaceComposer.h +++ b/include/gui/ISurfaceComposer.h @@ -126,6 +126,11 @@ public: virtual bool authenticateSurfaceTexture( const sp<IGraphicBufferProducer>& surface) const = 0; + /* Returns the frame timestamps supported by SurfaceFlinger. + */ + virtual status_t getSupportedFrameTimestamps( + std::vector<FrameEvent>* outSupported) const = 0; + /* set display power mode. depending on the mode, it can either trigger * screen on, off or low power mode and wait for it to complete. * requires ACCESS_SURFACE_FLINGER permission. diff --git a/include/gui/Surface.h b/include/gui/Surface.h index 88ef010368..8b1d1069b3 100644 --- a/include/gui/Surface.h +++ b/include/gui/Surface.h @@ -426,6 +426,10 @@ protected: uint64_t mNextFrameNumber = 1; uint64_t mLastFrameNumber = 0; + // Mutable because ANativeWindow::query needs this class const. + mutable bool mQueriedSupportedTimestamps; + mutable bool mFrameTimestampsSupportsPresent; + // A cached copy of the FrameEventHistory maintained by the consumer. bool mEnableFrameTimestamps = false; std::unique_ptr<ProducerFrameEventHistory> mFrameEventHistory; diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp index da943051a6..39bb078fd1 100644 --- a/libs/binder/Parcel.cpp +++ b/libs/binder/Parcel.cpp @@ -553,6 +553,14 @@ status_t Parcel::appendFrom(const Parcel *parcel, size_t offset, size_t len) return err; } +int Parcel::compareData(const Parcel& other) { + size_t size = dataSize(); + if (size != other.dataSize()) { + return size < other.dataSize() ? -1 : 1; + } + return memcmp(data(), other.data(), size); +} + bool Parcel::allowFds() const { return mAllowFds; diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp index 5a32d0524a..4d2692fe62 100644 --- a/libs/gui/ISurfaceComposer.cpp +++ b/libs/gui/ISurfaceComposer.cpp @@ -166,6 +166,50 @@ public: return result != 0; } + virtual status_t getSupportedFrameTimestamps( + std::vector<FrameEvent>* outSupported) const { + if (!outSupported) { + return UNEXPECTED_NULL; + } + outSupported->clear(); + + Parcel data, reply; + + status_t err = data.writeInterfaceToken( + ISurfaceComposer::getInterfaceDescriptor()); + if (err != NO_ERROR) { + return err; + } + + err = remote()->transact( + BnSurfaceComposer::GET_SUPPORTED_FRAME_TIMESTAMPS, + data, &reply); + if (err != NO_ERROR) { + return err; + } + + int32_t result = 0; + err = reply.readInt32(&result); + if (err != NO_ERROR) { + return err; + } + if (result != NO_ERROR) { + return result; + } + + std::vector<int32_t> supported; + err = reply.readInt32Vector(&supported); + if (err != NO_ERROR) { + return err; + } + + outSupported->reserve(supported.size()); + for (int32_t s : supported) { + outSupported->push_back(static_cast<FrameEvent>(s)); + } + return NO_ERROR; + } + virtual sp<IDisplayEventConnection> createDisplayEventConnection() { Parcel data, reply; @@ -536,6 +580,25 @@ status_t BnSurfaceComposer::onTransact( reply->writeInt32(result); return NO_ERROR; } + case GET_SUPPORTED_FRAME_TIMESTAMPS: { + CHECK_INTERFACE(ISurfaceComposer, data, reply); + std::vector<FrameEvent> supportedTimestamps; + status_t result = getSupportedFrameTimestamps(&supportedTimestamps); + status_t err = reply->writeInt32(result); + if (err != NO_ERROR) { + return err; + } + if (result != NO_ERROR) { + return result; + } + + std::vector<int32_t> supported; + supported.reserve(supportedTimestamps.size()); + for (FrameEvent s : supportedTimestamps) { + supported.push_back(static_cast<int32_t>(s)); + } + return reply->writeInt32Vector(supported); + } case CREATE_DISPLAY_EVENT_CONNECTION: { CHECK_INTERFACE(ISurfaceComposer, data, reply); sp<IDisplayEventConnection> connection(createDisplayEventConnection()); diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp index 1149b8980b..a6d9e66828 100644 --- a/libs/gui/Surface.cpp +++ b/libs/gui/Surface.cpp @@ -52,6 +52,8 @@ Surface::Surface( mAutoRefresh(false), mSharedBufferSlot(BufferItem::INVALID_BUFFER_SLOT), mSharedBufferHasBeenQueued(false), + mQueriedSupportedTimestamps(false), + mFrameTimestampsSupportsPresent(false), mEnableFrameTimestamps(false), mFrameEventHistory(std::make_unique<ProducerFrameEventHistory>()) { @@ -209,8 +211,8 @@ static bool checkConsumerForUpdates( bool checkForDisplayPresent = (outDisplayPresentTime != nullptr) && !e->hasDisplayPresentInfo(); - // LastRefreshStart, DequeueReady, and Release are never - // available for the last frame. + // LastRefreshStart, DequeueReady, and Release are never available for the + // last frame. bool checkForLastRefreshStart = (outLastRefreshStartTime != nullptr) && !e->hasLastRefreshStartInfo() && (e->frameNumber != lastFrameNumber); @@ -227,14 +229,26 @@ static bool checkConsumerForUpdates( static void getFrameTimestamp(nsecs_t *dst, const nsecs_t& src) { if (dst != nullptr) { - *dst = FrameEvents::isValidTimestamp(src) ? src : 0; + // We always get valid timestamps for these eventually. + *dst = (src == FrameEvents::TIMESTAMP_PENDING) ? + NATIVE_WINDOW_TIMESTAMP_PENDING : src; } } -static void getFrameTimestampFence(nsecs_t *dst, const std::shared_ptr<FenceTime>& src) { +static void getFrameTimestampFence(nsecs_t *dst, + const std::shared_ptr<FenceTime>& src, bool fenceShouldBeKnown) { if (dst != nullptr) { + if (!fenceShouldBeKnown) { + *dst = NATIVE_WINDOW_TIMESTAMP_PENDING; + return; + } + nsecs_t signalTime = src->getSignalTime(); - *dst = Fence::isValidTimestamp(signalTime) ? signalTime : 0; + *dst = (signalTime == Fence::SIGNAL_TIME_PENDING) ? + NATIVE_WINDOW_TIMESTAMP_PENDING : + (signalTime == Fence::SIGNAL_TIME_INVALID) ? + NATIVE_WINDOW_TIMESTAMP_INVALID : + signalTime; } } @@ -252,6 +266,12 @@ status_t Surface::getFrameTimestamps(uint64_t frameNumber, return INVALID_OPERATION; } + // Verify the requested timestamps are supported. + querySupportedTimestampsLocked(); + if (outDisplayPresentTime != nullptr && !mFrameTimestampsSupportsPresent) { + return BAD_VALUE; + } + FrameEvents* events = mFrameEventHistory->getFrame(frameNumber); if (events == nullptr) { // If the entry isn't available in the producer, it's definitely not @@ -282,12 +302,15 @@ status_t Surface::getFrameTimestamps(uint64_t frameNumber, getFrameTimestamp(outLastRefreshStartTime, events->lastRefreshStartTime); getFrameTimestamp(outDequeueReadyTime, events->dequeueReadyTime); - getFrameTimestampFence(outAcquireTime, events->acquireFence); - getFrameTimestampFence( - outGpuCompositionDoneTime, events->gpuCompositionDoneFence); - getFrameTimestampFence( - outDisplayPresentTime, events->displayPresentFence); - getFrameTimestampFence(outReleaseTime, events->releaseFence); + getFrameTimestampFence(outAcquireTime, events->acquireFence, + events->hasAcquireInfo()); + getFrameTimestampFence(outGpuCompositionDoneTime, + events->gpuCompositionDoneFence, + events->hasGpuCompositionDoneInfo()); + getFrameTimestampFence(outDisplayPresentTime, events->displayPresentFence, + events->hasDisplayPresentInfo()); + getFrameTimestampFence(outReleaseTime, events->releaseFence, + events->hasReleaseInfo()); return NO_ERROR; } @@ -739,6 +762,29 @@ int Surface::queueBuffer(android_native_buffer_t* buffer, int fenceFd) { return err; } +void Surface::querySupportedTimestampsLocked() const { + // mMutex must be locked when calling this method. + + if (mQueriedSupportedTimestamps) { + return; + } + mQueriedSupportedTimestamps = true; + + std::vector<FrameEvent> supportedFrameTimestamps; + status_t err = composerService()->getSupportedFrameTimestamps( + &supportedFrameTimestamps); + + if (err != NO_ERROR) { + return; + } + + for (auto sft : supportedFrameTimestamps) { + if (sft == FrameEvent::DISPLAY_PRESENT) { + mFrameTimestampsSupportsPresent = true; + } + } +} + int Surface::query(int what, int* value) const { ATRACE_CALL(); ALOGV("Surface::query"); @@ -800,6 +846,11 @@ int Surface::query(int what, int* value) const { static_cast<int>(durationUs); return NO_ERROR; } + case NATIVE_WINDOW_FRAME_TIMESTAMPS_SUPPORTS_PRESENT: { + querySupportedTimestampsLocked(); + *value = mFrameTimestampsSupportsPresent ? 1 : 0; + return NO_ERROR; + } case NATIVE_WINDOW_IS_VALID: { *value = mGraphicBufferProducer != nullptr ? 1 : 0; return NO_ERROR; diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp index ce114864aa..cf3d1b27c7 100644 --- a/libs/gui/tests/Surface_test.cpp +++ b/libs/gui/tests/Surface_test.cpp @@ -368,6 +368,10 @@ class FakeSurfaceComposer : public ISurfaceComposer{ public: ~FakeSurfaceComposer() override {} + void setSupportsPresent(bool supportsPresent) { + mSupportsPresent = supportsPresent; + } + sp<ISurfaceComposerClient> createConnection() override { return nullptr; } sp<ISurfaceComposerClient> createScopedConnection( const sp<IGraphicBufferProducer>& /* parent */) override { @@ -391,6 +395,26 @@ public: const sp<IGraphicBufferProducer>& /*surface*/) const override { return false; } + + status_t getSupportedFrameTimestamps(std::vector<FrameEvent>* outSupported) + const override { + *outSupported = { + FrameEvent::REQUESTED_PRESENT, + FrameEvent::ACQUIRE, + FrameEvent::LATCH, + FrameEvent::FIRST_REFRESH_START, + FrameEvent::LAST_REFRESH_START, + FrameEvent::GPU_COMPOSITION_DONE, + FrameEvent::DEQUEUE_READY, + FrameEvent::RELEASE + }; + if (mSupportsPresent) { + outSupported->push_back( + FrameEvent::DISPLAY_PRESENT); + } + return NO_ERROR; + } + void setPowerMode(const sp<IBinder>& /*display*/, int /*mode*/) override {} status_t getDisplayConfigs(const sp<IBinder>& /*display*/, Vector<DisplayInfo>* /*configs*/) override { return NO_ERROR; } @@ -435,7 +459,6 @@ protected: private: bool mSupportsPresent{true}; - bool mSupportsRetire{true}; }; class FakeProducerFrameEventHistory : public ProducerFrameEventHistory { @@ -864,6 +887,28 @@ TEST_F(GetFrameTimestampsTest, EnabledSimple) { EXPECT_EQ(4, mFakeConsumer->mGetFrameTimestampsCount); } +TEST_F(GetFrameTimestampsTest, QueryPresentSupported) { + bool displayPresentSupported = true; + mSurface->mFakeSurfaceComposer->setSupportsPresent(displayPresentSupported); + + // Verify supported bits are forwarded. + int supportsPresent = -1; + mWindow.get()->query(mWindow.get(), + NATIVE_WINDOW_FRAME_TIMESTAMPS_SUPPORTS_PRESENT, &supportsPresent); + EXPECT_EQ(displayPresentSupported, supportsPresent); +} + +TEST_F(GetFrameTimestampsTest, QueryPresentNotSupported) { + bool displayPresentSupported = false; + mSurface->mFakeSurfaceComposer->setSupportsPresent(displayPresentSupported); + + // Verify supported bits are forwarded. + int supportsPresent = -1; + mWindow.get()->query(mWindow.get(), + NATIVE_WINDOW_FRAME_TIMESTAMPS_SUPPORTS_PRESENT, &supportsPresent); + EXPECT_EQ(displayPresentSupported, supportsPresent); +} + TEST_F(GetFrameTimestampsTest, SnapToNextTickBasic) { nsecs_t phase = 4000; nsecs_t interval = 1000; @@ -1139,8 +1184,8 @@ TEST_F(GetFrameTimestampsTest, TimestampsAssociatedWithCorrectFrame) { EXPECT_EQ(mFrames[1].mRefreshes[0].kGpuCompositionDoneTime, outGpuCompositionDoneTime); EXPECT_EQ(mFrames[1].mRefreshes[0].kPresentTime, outDisplayPresentTime); - EXPECT_EQ(0, outDequeueReadyTime); - EXPECT_EQ(0, outReleaseTime); + EXPECT_EQ(NATIVE_WINDOW_TIMESTAMP_PENDING, outDequeueReadyTime); + EXPECT_EQ(NATIVE_WINDOW_TIMESTAMP_PENDING, outReleaseTime); } // This test verifies the acquire fence recorded by the consumer is not sent @@ -1163,7 +1208,7 @@ TEST_F(GetFrameTimestampsTest, QueueTimestampsNoSync) { EXPECT_EQ(oldCount, mFakeConsumer->mGetFrameTimestampsCount); EXPECT_EQ(NO_ERROR, result); EXPECT_EQ(mFrames[0].kRequestedPresentTime, outRequestedPresentTime); - EXPECT_EQ(0, outAcquireTime); + EXPECT_EQ(NATIVE_WINDOW_TIMESTAMP_PENDING, outAcquireTime); // Signal acquire fences. Verify a sync call still isn't necessary. mFrames[0].signalQueueFences(); @@ -1192,7 +1237,7 @@ TEST_F(GetFrameTimestampsTest, QueueTimestampsNoSync) { EXPECT_EQ(oldCount, mFakeConsumer->mGetFrameTimestampsCount); EXPECT_EQ(NO_ERROR, result); EXPECT_EQ(mFrames[1].kRequestedPresentTime, outRequestedPresentTime); - EXPECT_EQ(0, outAcquireTime); + EXPECT_EQ(NATIVE_WINDOW_TIMESTAMP_PENDING, outAcquireTime); // Signal acquire fences. Verify a sync call still isn't necessary. mFrames[1].signalQueueFences(); @@ -1228,8 +1273,8 @@ TEST_F(GetFrameTimestampsTest, ZeroRequestedTimestampsNoSync) { // Verify a request for no timestamps doesn't result in a sync call. int oldCount = mFakeConsumer->mGetFrameTimestampsCount; int result = native_window_get_frame_timestamps(mWindow.get(), fId2, - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, - nullptr, nullptr, nullptr); + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr); EXPECT_EQ(NO_ERROR, result); EXPECT_EQ(oldCount, mFakeConsumer->mGetFrameTimestampsCount); } @@ -1265,10 +1310,10 @@ TEST_F(GetFrameTimestampsTest, FencesInProducerNoSync) { EXPECT_EQ(mFrames[0].kLatchTime, outLatchTime); EXPECT_EQ(mFrames[0].mRefreshes[0].kStartTime, outFirstRefreshStartTime); EXPECT_EQ(mFrames[0].mRefreshes[2].kStartTime, outLastRefreshStartTime); - EXPECT_EQ(0, outGpuCompositionDoneTime); - EXPECT_EQ(0, outDisplayPresentTime); + EXPECT_EQ(NATIVE_WINDOW_TIMESTAMP_PENDING, outGpuCompositionDoneTime); + EXPECT_EQ(NATIVE_WINDOW_TIMESTAMP_PENDING, outDisplayPresentTime); EXPECT_EQ(mFrames[0].kDequeueReadyTime, outDequeueReadyTime); - EXPECT_EQ(0, outReleaseTime); + EXPECT_EQ(NATIVE_WINDOW_TIMESTAMP_PENDING, outReleaseTime); // Verify available timestamps are correct for frame 1 again, before any // fence has been signaled. @@ -1283,10 +1328,10 @@ TEST_F(GetFrameTimestampsTest, FencesInProducerNoSync) { EXPECT_EQ(mFrames[0].kLatchTime, outLatchTime); EXPECT_EQ(mFrames[0].mRefreshes[0].kStartTime, outFirstRefreshStartTime); EXPECT_EQ(mFrames[0].mRefreshes[2].kStartTime, outLastRefreshStartTime); - EXPECT_EQ(0, outGpuCompositionDoneTime); - EXPECT_EQ(0, outDisplayPresentTime); + EXPECT_EQ(NATIVE_WINDOW_TIMESTAMP_PENDING, outGpuCompositionDoneTime); + EXPECT_EQ(NATIVE_WINDOW_TIMESTAMP_PENDING, outDisplayPresentTime); EXPECT_EQ(mFrames[0].kDequeueReadyTime, outDequeueReadyTime); - EXPECT_EQ(0, outReleaseTime); + EXPECT_EQ(NATIVE_WINDOW_TIMESTAMP_PENDING, outReleaseTime); // Signal the fences for frame 1. mFrames[0].signalRefreshFences(); @@ -1342,10 +1387,10 @@ TEST_F(GetFrameTimestampsTest, NoGpuNoSync) { EXPECT_EQ(mFrames[0].kLatchTime, outLatchTime); EXPECT_EQ(mFrames[0].mRefreshes[0].kStartTime, outFirstRefreshStartTime); EXPECT_EQ(mFrames[0].mRefreshes[2].kStartTime, outLastRefreshStartTime); - EXPECT_EQ(0, outGpuCompositionDoneTime); - EXPECT_EQ(0, outDisplayPresentTime); + EXPECT_EQ(NATIVE_WINDOW_TIMESTAMP_INVALID, outGpuCompositionDoneTime); + EXPECT_EQ(NATIVE_WINDOW_TIMESTAMP_PENDING, outDisplayPresentTime); EXPECT_EQ(mFrames[0].kDequeueReadyTime, outDequeueReadyTime); - EXPECT_EQ(0, outReleaseTime); + EXPECT_EQ(NATIVE_WINDOW_TIMESTAMP_PENDING, outReleaseTime); // Signal the fences for frame 1. mFrames[0].signalRefreshFences(); @@ -1363,7 +1408,7 @@ TEST_F(GetFrameTimestampsTest, NoGpuNoSync) { EXPECT_EQ(mFrames[0].kLatchTime, outLatchTime); EXPECT_EQ(mFrames[0].mRefreshes[0].kStartTime, outFirstRefreshStartTime); EXPECT_EQ(mFrames[0].mRefreshes[2].kStartTime, outLastRefreshStartTime); - EXPECT_EQ(0, outGpuCompositionDoneTime); + EXPECT_EQ(NATIVE_WINDOW_TIMESTAMP_INVALID, outGpuCompositionDoneTime); EXPECT_EQ(mFrames[0].mRefreshes[0].kPresentTime, outDisplayPresentTime); EXPECT_EQ(mFrames[0].kDequeueReadyTime, outDequeueReadyTime); EXPECT_EQ(mFrames[0].kReleaseTime, outReleaseTime); @@ -1371,7 +1416,7 @@ TEST_F(GetFrameTimestampsTest, NoGpuNoSync) { // This test verifies that if the certain timestamps can't possibly exist for // the most recent frame, then a sync call is not done. -TEST_F(GetFrameTimestampsTest, NoRetireOrReleaseNoSync) { +TEST_F(GetFrameTimestampsTest, NoReleaseNoSync) { enableFrameTimestamps(); // Dequeue and queue frame 1. @@ -1401,10 +1446,10 @@ TEST_F(GetFrameTimestampsTest, NoRetireOrReleaseNoSync) { EXPECT_EQ(mFrames[0].kLatchTime, outLatchTime); EXPECT_EQ(mFrames[0].mRefreshes[0].kStartTime, outFirstRefreshStartTime); EXPECT_EQ(mFrames[0].mRefreshes[2].kStartTime, outLastRefreshStartTime); - EXPECT_EQ(0, outGpuCompositionDoneTime); - EXPECT_EQ(0, outDisplayPresentTime); + EXPECT_EQ(NATIVE_WINDOW_TIMESTAMP_INVALID, outGpuCompositionDoneTime); + EXPECT_EQ(NATIVE_WINDOW_TIMESTAMP_PENDING, outDisplayPresentTime); EXPECT_EQ(mFrames[0].kDequeueReadyTime, outDequeueReadyTime); - EXPECT_EQ(0, outReleaseTime); + EXPECT_EQ(NATIVE_WINDOW_TIMESTAMP_PENDING, outReleaseTime); mFrames[0].signalRefreshFences(); mFrames[0].signalReleaseFences(); @@ -1425,10 +1470,33 @@ TEST_F(GetFrameTimestampsTest, NoRetireOrReleaseNoSync) { EXPECT_EQ(mFrames[1].kLatchTime, outLatchTime); EXPECT_EQ(mFrames[1].mRefreshes[0].kStartTime, outFirstRefreshStartTime); EXPECT_EQ(mFrames[1].mRefreshes[1].kStartTime, outLastRefreshStartTime); - EXPECT_EQ(0, outGpuCompositionDoneTime); + EXPECT_EQ(NATIVE_WINDOW_TIMESTAMP_INVALID, outGpuCompositionDoneTime); EXPECT_EQ(mFrames[1].mRefreshes[0].kPresentTime, outDisplayPresentTime); - EXPECT_EQ(0, outDequeueReadyTime); - EXPECT_EQ(0, outReleaseTime); + EXPECT_EQ(NATIVE_WINDOW_TIMESTAMP_PENDING, outDequeueReadyTime); + EXPECT_EQ(NATIVE_WINDOW_TIMESTAMP_PENDING, outReleaseTime); +} + +// This test verifies there are no sync calls for present times +// when they aren't supported and that an error is returned. + +TEST_F(GetFrameTimestampsTest, PresentUnsupportedNoSync) { + enableFrameTimestamps(); + mSurface->mFakeSurfaceComposer->setSupportsPresent(false); + + // Dequeue and queue frame 1. + const uint64_t fId1 = getNextFrameId(); + dequeueAndQueue(0); + + // Verify a query for the Present times do not trigger a sync call if they + // are not supported. + resetTimestamps(); + int oldCount = mFakeConsumer->mGetFrameTimestampsCount; + int result = native_window_get_frame_timestamps(mWindow.get(), fId1, + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, + &outDisplayPresentTime, nullptr, nullptr); + EXPECT_EQ(oldCount, mFakeConsumer->mGetFrameTimestampsCount); + EXPECT_EQ(BAD_VALUE, result); + EXPECT_EQ(-1, outDisplayPresentTime); } } diff --git a/libs/hwc2on1adapter/HWC2On1Adapter.cpp b/libs/hwc2on1adapter/HWC2On1Adapter.cpp index e35bfc9fea..8c6ef691a2 100644 --- a/libs/hwc2on1adapter/HWC2On1Adapter.cpp +++ b/libs/hwc2on1adapter/HWC2On1Adapter.cpp @@ -2246,6 +2246,11 @@ void HWC2On1Adapter::populateCapabilities() { mHwc1SupportsBackgroundColor = true; } } + + // Some devices might have HWC1 retire fences that accurately emulate + // HWC2 present fences when they are deferred, but it's not very reliable. + // To be safe, we indicate PresentFenceIsNotReliable for all HWC1 devices. + mCapabilities.insert(Capability::PresentFenceIsNotReliable); } HWC2On1Adapter::Display* HWC2On1Adapter::getDisplay(hwc2_display_t id) { diff --git a/libs/nativewindow/include/system/window.h b/libs/nativewindow/include/system/window.h index 63d1ad18a7..fb67a5169c 100644 --- a/libs/nativewindow/include/system/window.h +++ b/libs/nativewindow/include/system/window.h @@ -186,6 +186,12 @@ enum { * if it is safe (i.e. no crash will occur) to call any method on it. */ NATIVE_WINDOW_IS_VALID = 17, + + /* + * Returns 1 if NATIVE_WINDOW_GET_FRAME_TIMESTAMPS will return display + * present info, 0 if it won't. + */ + NATIVE_WINDOW_FRAME_TIMESTAMPS_SUPPORTS_PRESENT = 18, }; /* Valid operations for the (*perform)() hook. @@ -305,6 +311,14 @@ enum { */ static const int64_t NATIVE_WINDOW_TIMESTAMP_AUTO = (-9223372036854775807LL-1); +/* parameter for NATIVE_WINDOW_GET_FRAME_TIMESTAMPS + * + * Special timestamp value to indicate the timestamps aren't yet known or + * that they are invalid. + */ +static const int64_t NATIVE_WINDOW_TIMESTAMP_PENDING = -2; +static const int64_t NATIVE_WINDOW_TIMESTAMP_INVALID = -1; + struct ANativeWindow { #ifdef __cplusplus diff --git a/libs/ui/Gralloc1On0Adapter.cpp b/libs/ui/Gralloc1On0Adapter.cpp index bd7c6a1a46..9ee9838b39 100644 --- a/libs/ui/Gralloc1On0Adapter.cpp +++ b/libs/ui/Gralloc1On0Adapter.cpp @@ -20,6 +20,9 @@ #include <ui/Gralloc1On0Adapter.h> +#include <algorithm> +#include <array> + #include <grallocusage/GrallocUsageConversion.h> #include <hardware/gralloc.h> @@ -67,13 +70,18 @@ Gralloc1On0Adapter::~Gralloc1On0Adapter() void Gralloc1On0Adapter::doGetCapabilities(uint32_t* outCount, int32_t* outCapabilities) { + constexpr std::array<int32_t, 2> supportedCapabilities = {{ + GRALLOC1_CAPABILITY_ON_ADAPTER, + GRALLOC1_CAPABILITY_RELEASE_IMPLY_DELETE, + }}; + if (outCapabilities == nullptr) { - *outCount = 1; - return; - } - if (*outCount >= 1) { - *outCapabilities = GRALLOC1_CAPABILITY_ON_ADAPTER; - *outCount = 1; + *outCount = supportedCapabilities.size(); + } else { + *outCount = std::min(*outCount, static_cast<uint32_t>( + supportedCapabilities.size())); + std::copy_n(supportedCapabilities.begin(), + *outCount, outCapabilities); } } @@ -325,6 +333,9 @@ gralloc1_error_t Gralloc1On0Adapter::release( if (result != 0) { ALOGE("gralloc0 unregister failed: %d", result); } + + native_handle_close(handle); + native_handle_delete(const_cast<native_handle_t*>(handle)); } mBuffers.erase(handle); diff --git a/libs/ui/GraphicBufferMapper.cpp b/libs/ui/GraphicBufferMapper.cpp index 2f4d5fbc77..87519bf3b8 100644 --- a/libs/ui/GraphicBufferMapper.cpp +++ b/libs/ui/GraphicBufferMapper.cpp @@ -122,8 +122,10 @@ status_t GraphicBufferMapper::freeBuffer(buffer_handle_t handle) error = GRALLOC1_ERROR_NONE; } else { error = mDevice->release(handle); - native_handle_close(handle); - native_handle_delete(const_cast<native_handle_t*>(handle)); + if (!mDevice->hasCapability(GRALLOC1_CAPABILITY_RELEASE_IMPLY_DELETE)) { + native_handle_close(handle); + native_handle_delete(const_cast<native_handle_t*>(handle)); + } } ALOGW_IF(error != GRALLOC1_ERROR_NONE, "freeBuffer(%p): failed %d", diff --git a/libs/vr/libbroadcastring/Android.bp b/libs/vr/libbroadcastring/Android.bp new file mode 100644 index 0000000000..008468a1ac --- /dev/null +++ b/libs/vr/libbroadcastring/Android.bp @@ -0,0 +1,37 @@ +cc_library_static { + name: "libbroadcastring", + host_supported: true, + clang: true, + cflags: [ + "-Wall", + "-Wextra", + "-Werror", + ], + export_include_dirs: ["include"], + shared_libs: [ + "libbase", + ], + export_shared_lib_headers: [ + "libbase", + ], +} + +cc_test { + name: "broadcast_ring_tests", + host_supported: true, + clang: true, + cflags: [ + "-Wall", + "-Wextra", + "-Werror", + ], + srcs: [ + "broadcast_ring_test.cc", + ], + static_libs: [ + "libbroadcastring", + ], + shared_libs: [ + "libbase", + ], +} diff --git a/libs/vr/libbroadcastring/broadcast_ring_test.cc b/libs/vr/libbroadcastring/broadcast_ring_test.cc new file mode 100644 index 0000000000..dfdd4ef0db --- /dev/null +++ b/libs/vr/libbroadcastring/broadcast_ring_test.cc @@ -0,0 +1,866 @@ +#include "libbroadcastring/broadcast_ring.h" + +#include <stdlib.h> +#include <memory> +#include <thread> // NOLINT +#include <sys/mman.h> + +#include <gtest/gtest.h> + +namespace android { +namespace dvr { +namespace { + +template <uint32_t N> +struct alignas(8) Aligned { + char v[N]; +}; + +template <uint32_t N> +struct alignas(8) Sized { + Sized() { Clear(); } + explicit Sized(char c) { Fill(c); } + char v[sizeof(Aligned<N>)]; + void Clear() { memset(v, 0, sizeof(v)); } + void Fill(char c) { memset(v, c, sizeof(v)); } + static Sized Pattern(uint8_t c) { + Sized sized; + for (size_t i = 0; i < sizeof(v); ++i) { + sized.v[i] = static_cast<char>(c + i); + } + return sized; + } + bool operator==(const Sized& right) const { + static_assert(sizeof(*this) == sizeof(v), "Size mismatch"); + return !memcmp(v, right.v, sizeof(v)); + } + template <typename SmallerSized> + SmallerSized Truncate() const { + SmallerSized val; + static_assert(sizeof(val.v) <= sizeof(v), "Cannot truncate to larger size"); + memcpy(val.v, v, sizeof(val.v)); + return val; + } +}; + +char FillChar(int val) { return static_cast<char>(val); } + +struct FakeMmap { + explicit FakeMmap(size_t size) : size(size), data(new char[size]) {} + size_t size; + std::unique_ptr<char[]> data; + void* mmap() { return static_cast<void*>(data.get()); } +}; + +template <typename Ring> +FakeMmap CreateRing(Ring* ring, uint32_t count) { + FakeMmap mmap(Ring::MemorySize(count)); + *ring = Ring::Create(mmap.mmap(), mmap.size, count); + return mmap; +} + +template <typename RecordType, bool StaticSize = false, + uint32_t StaticCount = 0, uint32_t MaxReserved = 1, + uint32_t MinAvailable = 0> +struct Traits { + using Record = RecordType; + static constexpr bool kUseStaticRecordSize = StaticSize; + static constexpr uint32_t kStaticRecordCount = StaticCount; + static constexpr uint32_t kMaxReservedRecords = MaxReserved; + static constexpr uint32_t kMinAvailableRecords = MinAvailable; + static constexpr uint32_t kMinRecordCount = MaxReserved + MinAvailable; +}; + +template <typename Record, bool StaticSize = false, uint32_t MaxReserved = 1, + uint32_t MinAvailable = 7> +struct TraitsDynamic + : public Traits<Record, StaticSize, 0, MaxReserved, MinAvailable> { + using Ring = BroadcastRing<Record, TraitsDynamic>; + static uint32_t MinCount() { return MaxReserved + MinAvailable; } +}; + +template <typename Record, uint32_t StaticCount = 1, bool StaticSize = true, + uint32_t MaxReserved = 1, uint32_t MinAvailable = 0> +struct TraitsStatic + : public Traits<Record, true, StaticCount, MaxReserved, MinAvailable> { + using Ring = BroadcastRing<Record, TraitsStatic>; + static uint32_t MinCount() { return StaticCount; } +}; + +using Dynamic_8_NxM = TraitsDynamic<Sized<8>>; +using Dynamic_16_NxM = TraitsDynamic<Sized<16>>; +using Dynamic_32_NxM = TraitsDynamic<Sized<32>>; +using Dynamic_32_32xM = TraitsDynamic<Sized<32>, true>; +using Dynamic_16_NxM_1plus0 = TraitsDynamic<Sized<16>, false, 1, 0>; +using Dynamic_16_NxM_1plus1 = TraitsDynamic<Sized<16>, false, 1, 1>; +using Dynamic_16_NxM_5plus11 = TraitsDynamic<Sized<16>, false, 5, 11>; +using Dynamic_256_NxM_1plus0 = TraitsDynamic<Sized<256>, false, 1, 0>; + +using Static_8_8x1 = TraitsStatic<Sized<8>, 1>; +using Static_8_8x16 = TraitsStatic<Sized<8>, 16>; +using Static_16_16x8 = TraitsStatic<Sized<16>, 8>; +using Static_16_16x16 = TraitsStatic<Sized<16>, 16>; +using Static_16_16x32 = TraitsStatic<Sized<16>, 32>; +using Static_32_Nx8 = TraitsStatic<Sized<32>, 8, false>; + +using TraitsList = ::testing::Types<Dynamic_8_NxM, // + Dynamic_16_NxM, // + Dynamic_32_NxM, // + Dynamic_32_32xM, // + Dynamic_16_NxM_1plus0, // + Dynamic_16_NxM_1plus1, // + Dynamic_16_NxM_5plus11, // + Dynamic_256_NxM_1plus0, // + Static_8_8x1, // + Static_8_8x16, // + Static_16_16x8, // + Static_16_16x16, // + Static_16_16x32, // + Static_32_Nx8>; + +} // namespace + +template <typename T> +class BroadcastRingTest : public ::testing::Test {}; + +TYPED_TEST_CASE(BroadcastRingTest, TraitsList); + +TYPED_TEST(BroadcastRingTest, Geometry) { + using Record = typename TypeParam::Record; + using Ring = typename TypeParam::Ring; + Ring ring; + auto mmap = CreateRing(&ring, Ring::Traits::MinCount()); + EXPECT_EQ(Ring::Traits::MinCount(), ring.record_count()); + EXPECT_EQ(sizeof(Record), ring.record_size()); +} + +TYPED_TEST(BroadcastRingTest, PutGet) { + using Record = typename TypeParam::Record; + using Ring = typename TypeParam::Ring; + Ring ring; + auto mmap = CreateRing(&ring, Ring::Traits::MinCount()); + const uint32_t oldest_sequence_at_start = ring.GetOldestSequence(); + const uint32_t next_sequence_at_start = ring.GetNextSequence(); + { + uint32_t sequence = oldest_sequence_at_start; + Record record; + EXPECT_FALSE(ring.Get(&sequence, &record)); + EXPECT_EQ(oldest_sequence_at_start, sequence); + EXPECT_EQ(Record(), record); + } + const Record original_record(0x1a); + ring.Put(original_record); + { + uint32_t sequence = next_sequence_at_start; + Record record; + EXPECT_TRUE(ring.Get(&sequence, &record)); + EXPECT_EQ(next_sequence_at_start, sequence); + EXPECT_EQ(original_record, record); + } + { + uint32_t sequence = next_sequence_at_start + 1; + Record record; + EXPECT_FALSE(ring.Get(&sequence, &record)); + EXPECT_EQ(next_sequence_at_start + 1, sequence); + EXPECT_EQ(Record(), record); + } +} + +TYPED_TEST(BroadcastRingTest, FillOnce) { + using Record = typename TypeParam::Record; + using Ring = typename TypeParam::Ring; + Ring ring; + auto mmap = CreateRing(&ring, Ring::Traits::MinCount()); + const uint32_t next_sequence_at_start = ring.GetNextSequence(); + for (uint32_t i = 0; i < ring.record_count(); ++i) + ring.Put(Record(FillChar(i))); + for (uint32_t i = 0; i < ring.record_count(); ++i) { + const uint32_t expected_sequence = next_sequence_at_start + i; + const Record expected_record(FillChar(i)); + { + uint32_t sequence = ring.GetOldestSequence() + i; + Record record; + EXPECT_TRUE(ring.Get(&sequence, &record)); + EXPECT_EQ(expected_sequence, sequence); + EXPECT_EQ(expected_record, record); + } + } + { + uint32_t sequence = ring.GetOldestSequence() + ring.record_count(); + Record record; + EXPECT_FALSE(ring.Get(&sequence, &record)); + } +} + +TYPED_TEST(BroadcastRingTest, FillTwice) { + using Record = typename TypeParam::Record; + using Ring = typename TypeParam::Ring; + Ring ring; + auto mmap = CreateRing(&ring, Ring::Traits::MinCount()); + const uint32_t next_sequence_at_start = ring.GetNextSequence(); + for (uint32_t i = 0; i < 2 * ring.record_count(); ++i) { + const Record newest_record(FillChar(i)); + ring.Put(newest_record); + + const uint32_t newest_sequence = next_sequence_at_start + i; + const uint32_t records_available = std::min(i + 1, ring.record_count()); + const uint32_t oldest_sequence = newest_sequence - records_available + 1; + EXPECT_EQ(newest_sequence, ring.GetNewestSequence()); + EXPECT_EQ(oldest_sequence, ring.GetOldestSequence()); + EXPECT_EQ(newest_sequence + 1, ring.GetNextSequence()); + + for (uint32_t j = 0; j < records_available; ++j) { + const uint32_t sequence_jth_newest = newest_sequence - j; + const Record record_jth_newest(FillChar(i - j)); + + { + uint32_t sequence = sequence_jth_newest; + Record record; + EXPECT_TRUE(ring.Get(&sequence, &record)); + EXPECT_EQ(sequence_jth_newest, sequence); + EXPECT_EQ(record_jth_newest, record); + } + + { + uint32_t sequence = sequence_jth_newest; + Record record; + EXPECT_TRUE(ring.GetNewest(&sequence, &record)); + EXPECT_EQ(newest_sequence, sequence); + EXPECT_EQ(newest_record, record); + } + } + + const Record oldest_record( + FillChar(i + (oldest_sequence - newest_sequence))); + const uint32_t sequence_0th_overwritten = oldest_sequence - 1; + const uint32_t sequence_0th_future = newest_sequence + 1; + const uint32_t sequence_1st_future = newest_sequence + 2; + + { + uint32_t sequence = sequence_0th_overwritten; + Record record; + EXPECT_TRUE(ring.Get(&sequence, &record)); + EXPECT_EQ(oldest_sequence, sequence); + EXPECT_EQ(oldest_record, record); + } + + { + uint32_t sequence = sequence_0th_overwritten; + Record record; + EXPECT_TRUE(ring.GetNewest(&sequence, &record)); + EXPECT_EQ(newest_sequence, sequence); + EXPECT_EQ(newest_record, record); + } + + { + uint32_t sequence = sequence_0th_future; + Record record; + EXPECT_FALSE(ring.Get(&sequence, &record)); + EXPECT_EQ(sequence_0th_future, sequence); + EXPECT_EQ(Record(), record); + } + + { + uint32_t sequence = sequence_0th_future; + Record record; + EXPECT_FALSE(ring.GetNewest(&sequence, &record)); + EXPECT_EQ(sequence_0th_future, sequence); + EXPECT_EQ(Record(), record); + } + + { + uint32_t sequence = sequence_1st_future; + Record record; + EXPECT_TRUE(ring.Get(&sequence, &record)); + EXPECT_EQ(oldest_sequence, sequence); + EXPECT_EQ(oldest_record, record); + } + + { + uint32_t sequence = sequence_1st_future; + Record record; + EXPECT_TRUE(ring.GetNewest(&sequence, &record)); + EXPECT_EQ(newest_sequence, sequence); + EXPECT_EQ(newest_record, record); + } + } +} + +TYPED_TEST(BroadcastRingTest, Import) { + using Record = typename TypeParam::Record; + using Ring = typename TypeParam::Ring; + Ring ring; + auto mmap = CreateRing(&ring, Ring::Traits::MinCount()); + + const uint32_t sequence_0 = ring.GetNextSequence(); + const uint32_t sequence_1 = ring.GetNextSequence() + 1; + const Record record_0 = Record::Pattern(0x00); + const Record record_1 = Record::Pattern(0x80); + ring.Put(record_0); + ring.Put(record_1); + + { + Ring imported_ring; + bool import_ok; + std::tie(imported_ring, import_ok) = Ring::Import(mmap.mmap(), mmap.size); + EXPECT_TRUE(import_ok); + EXPECT_EQ(ring.record_size(), imported_ring.record_size()); + EXPECT_EQ(ring.record_count(), imported_ring.record_count()); + + if (ring.record_count() != 1) { + uint32_t sequence = sequence_0; + Record imported_record; + EXPECT_TRUE(imported_ring.Get(&sequence, &imported_record)); + EXPECT_EQ(sequence_0, sequence); + EXPECT_EQ(record_0, imported_record); + } + + { + uint32_t sequence = sequence_1; + Record imported_record; + EXPECT_TRUE(imported_ring.Get(&sequence, &imported_record)); + EXPECT_EQ(sequence_1, sequence); + EXPECT_EQ(record_1, imported_record); + } + } +} + +TEST(BroadcastRingTest, ShouldFailImportIfStaticSizeMismatch) { + using OriginalRing = typename Static_16_16x16::Ring; + using RecordSizeMismatchRing = typename Static_8_8x16::Ring; + using RecordCountMismatchRing = typename Static_16_16x8::Ring; + + OriginalRing original_ring; + auto mmap = CreateRing(&original_ring, OriginalRing::Traits::MinCount()); + + { + using ImportedRing = RecordSizeMismatchRing; + ImportedRing imported_ring; + bool import_ok; + std::tie(imported_ring, import_ok) = + ImportedRing::Import(mmap.mmap(), mmap.size); + EXPECT_FALSE(import_ok); + auto mmap_imported = + CreateRing(&imported_ring, ImportedRing::Traits::MinCount()); + EXPECT_NE(original_ring.record_size(), imported_ring.record_size()); + EXPECT_EQ(original_ring.record_count(), imported_ring.record_count()); + } + + { + using ImportedRing = RecordCountMismatchRing; + ImportedRing imported_ring; + bool import_ok; + std::tie(imported_ring, import_ok) = + ImportedRing::Import(mmap.mmap(), mmap.size); + EXPECT_FALSE(import_ok); + auto mmap_imported = + CreateRing(&imported_ring, ImportedRing::Traits::MinCount()); + EXPECT_EQ(original_ring.record_size(), imported_ring.record_size()); + EXPECT_NE(original_ring.record_count(), imported_ring.record_count()); + } +} + +TEST(BroadcastRingTest, ShouldFailImportIfDynamicSizeGrows) { + using OriginalRing = typename Dynamic_8_NxM::Ring; + using RecordSizeGrowsRing = typename Dynamic_16_NxM::Ring; + + OriginalRing original_ring; + auto mmap = CreateRing(&original_ring, OriginalRing::Traits::MinCount()); + + { + using ImportedRing = RecordSizeGrowsRing; + ImportedRing imported_ring; + bool import_ok; + std::tie(imported_ring, import_ok) = + ImportedRing::Import(mmap.mmap(), mmap.size); + EXPECT_FALSE(import_ok); + auto mmap_imported = + CreateRing(&imported_ring, ImportedRing::Traits::MinCount()); + EXPECT_LT(original_ring.record_size(), imported_ring.record_size()); + EXPECT_EQ(original_ring.record_count(), imported_ring.record_count()); + } +} + +TEST(BroadcastRingTest, ShouldFailImportIfCountTooSmall) { + using OriginalRing = typename Dynamic_16_NxM_1plus0::Ring; + using MinCountRing = typename Dynamic_16_NxM_1plus1::Ring; + + OriginalRing original_ring; + auto mmap = CreateRing(&original_ring, OriginalRing::Traits::MinCount()); + + { + using ImportedRing = MinCountRing; + ImportedRing imported_ring; + bool import_ok; + std::tie(imported_ring, import_ok) = + ImportedRing::Import(mmap.mmap(), mmap.size); + EXPECT_FALSE(import_ok); + auto mmap_imported = + CreateRing(&imported_ring, ImportedRing::Traits::MinCount()); + EXPECT_EQ(original_ring.record_size(), imported_ring.record_size()); + EXPECT_LT(original_ring.record_count(), imported_ring.record_count()); + } +} + +TEST(BroadcastRingTest, ShouldFailImportIfMmapTooSmall) { + using OriginalRing = typename Dynamic_16_NxM::Ring; + + OriginalRing original_ring; + auto mmap = CreateRing(&original_ring, OriginalRing::Traits::MinCount()); + + { + using ImportedRing = OriginalRing; + ImportedRing imported_ring; + bool import_ok; + const size_t kMinSize = + ImportedRing::MemorySize(original_ring.record_count()); + std::tie(imported_ring, import_ok) = ImportedRing::Import(mmap.mmap(), 0); + EXPECT_FALSE(import_ok); + std::tie(imported_ring, import_ok) = + ImportedRing::Import(mmap.mmap(), kMinSize - 1); + EXPECT_FALSE(import_ok); + std::tie(imported_ring, import_ok) = + ImportedRing::Import(mmap.mmap(), kMinSize); + EXPECT_TRUE(import_ok); + EXPECT_EQ(original_ring.record_size(), imported_ring.record_size()); + EXPECT_EQ(original_ring.record_count(), imported_ring.record_count()); + } +} + +TEST(BroadcastRingTest, ShouldImportIfDynamicSizeShrinks) { + using OriginalRing = typename Dynamic_16_NxM::Ring; + using RecordSizeShrinksRing = typename Dynamic_8_NxM::Ring; + + OriginalRing original_ring; + auto mmap = CreateRing(&original_ring, OriginalRing::Traits::MinCount()); + + using OriginalRecord = typename OriginalRing::Record; + const uint32_t original_sequence_0 = original_ring.GetNextSequence(); + const uint32_t original_sequence_1 = original_ring.GetNextSequence() + 1; + const OriginalRecord original_record_0 = OriginalRecord::Pattern(0x00); + const OriginalRecord original_record_1 = OriginalRecord::Pattern(0x80); + original_ring.Put(original_record_0); + original_ring.Put(original_record_1); + + { + using ImportedRing = RecordSizeShrinksRing; + using ImportedRecord = typename ImportedRing::Record; + ImportedRing imported_ring; + bool import_ok; + std::tie(imported_ring, import_ok) = + ImportedRing::Import(mmap.mmap(), mmap.size); + EXPECT_TRUE(import_ok); + EXPECT_EQ(original_ring.record_size(), imported_ring.record_size()); + EXPECT_EQ(original_ring.record_count(), imported_ring.record_count()); + EXPECT_GT(sizeof(OriginalRecord), sizeof(ImportedRecord)); + + { + uint32_t sequence = original_sequence_0; + ImportedRecord shrunk_record; + EXPECT_TRUE(imported_ring.Get(&sequence, &shrunk_record)); + EXPECT_EQ(original_sequence_0, sequence); + EXPECT_EQ(original_record_0.Truncate<ImportedRecord>(), shrunk_record); + } + + { + uint32_t sequence = original_sequence_1; + ImportedRecord shrunk_record; + EXPECT_TRUE(imported_ring.Get(&sequence, &shrunk_record)); + EXPECT_EQ(original_sequence_1, sequence); + EXPECT_EQ(original_record_1.Truncate<ImportedRecord>(), shrunk_record); + } + } +} + +TEST(BroadcastRingTest, ShouldImportIfCompatibleDynamicToStatic) { + using OriginalRing = typename Dynamic_16_NxM::Ring; + using ImportedRing = typename Static_16_16x16::Ring; + using OriginalRecord = typename OriginalRing::Record; + using ImportedRecord = typename ImportedRing::Record; + using StaticRing = ImportedRing; + + OriginalRing original_ring; + auto mmap = CreateRing(&original_ring, StaticRing::Traits::MinCount()); + + const uint32_t original_sequence_0 = original_ring.GetNextSequence(); + const uint32_t original_sequence_1 = original_ring.GetNextSequence() + 1; + const OriginalRecord original_record_0 = OriginalRecord::Pattern(0x00); + const OriginalRecord original_record_1 = OriginalRecord::Pattern(0x80); + original_ring.Put(original_record_0); + original_ring.Put(original_record_1); + + { + ImportedRing imported_ring; + bool import_ok; + std::tie(imported_ring, import_ok) = + ImportedRing::Import(mmap.mmap(), mmap.size); + EXPECT_TRUE(import_ok); + EXPECT_EQ(original_ring.record_size(), imported_ring.record_size()); + EXPECT_EQ(original_ring.record_count(), imported_ring.record_count()); + + { + uint32_t sequence = original_sequence_0; + ImportedRecord imported_record; + EXPECT_TRUE(imported_ring.Get(&sequence, &imported_record)); + EXPECT_EQ(original_sequence_0, sequence); + EXPECT_EQ(original_record_0, imported_record); + } + + { + uint32_t sequence = original_sequence_1; + ImportedRecord imported_record; + EXPECT_TRUE(imported_ring.Get(&sequence, &imported_record)); + EXPECT_EQ(original_sequence_1, sequence); + EXPECT_EQ(original_record_1, imported_record); + } + } +} + +TEST(BroadcastRingTest, ShouldImportIfCompatibleStaticToDynamic) { + using OriginalRing = typename Static_16_16x16::Ring; + using ImportedRing = typename Dynamic_16_NxM::Ring; + using OriginalRecord = typename OriginalRing::Record; + using ImportedRecord = typename ImportedRing::Record; + using StaticRing = OriginalRing; + + OriginalRing original_ring; + auto mmap = CreateRing(&original_ring, StaticRing::Traits::MinCount()); + + const uint32_t original_sequence_0 = original_ring.GetNextSequence(); + const uint32_t original_sequence_1 = original_ring.GetNextSequence() + 1; + const OriginalRecord original_record_0 = OriginalRecord::Pattern(0x00); + const OriginalRecord original_record_1 = OriginalRecord::Pattern(0x80); + original_ring.Put(original_record_0); + original_ring.Put(original_record_1); + + { + ImportedRing imported_ring; + bool import_ok; + std::tie(imported_ring, import_ok) = + ImportedRing::Import(mmap.mmap(), mmap.size); + EXPECT_TRUE(import_ok); + EXPECT_EQ(original_ring.record_size(), imported_ring.record_size()); + EXPECT_EQ(original_ring.record_count(), imported_ring.record_count()); + + { + uint32_t sequence = original_sequence_0; + ImportedRecord imported_record; + EXPECT_TRUE(imported_ring.Get(&sequence, &imported_record)); + EXPECT_EQ(original_sequence_0, sequence); + EXPECT_EQ(original_record_0, imported_record); + } + + { + uint32_t sequence = original_sequence_1; + ImportedRecord imported_record; + EXPECT_TRUE(imported_ring.Get(&sequence, &imported_record)); + EXPECT_EQ(original_sequence_1, sequence); + EXPECT_EQ(original_record_1, imported_record); + } + } +} + +TEST(BroadcastRingTest, ShouldImportIfReadonlyMmap) { + using Ring = Dynamic_32_NxM::Ring; + using Record = Ring::Record; + + uint32_t record_count = Ring::Traits::MinCount(); + size_t ring_size = Ring::MemorySize(record_count); + + size_t page_size = sysconf(_SC_PAGESIZE); + size_t mmap_size = (ring_size + (page_size - 1)) & ~(page_size - 1); + ASSERT_GE(mmap_size, ring_size); + + void* mmap_base = mmap(nullptr, mmap_size, PROT_READ | PROT_WRITE, + MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); + ASSERT_NE(MAP_FAILED, mmap_base); + + Ring ring = Ring::Create(mmap_base, mmap_size, record_count); + for (uint32_t i = 0; i < record_count; ++i) ring.Put(Record(FillChar(i))); + + ASSERT_EQ(0, mprotect(mmap_base, mmap_size, PROT_READ)); + + { + Ring imported_ring; + bool import_ok; + std::tie(imported_ring, import_ok) = Ring::Import(mmap_base, mmap_size); + EXPECT_TRUE(import_ok); + EXPECT_EQ(ring.record_size(), imported_ring.record_size()); + EXPECT_EQ(ring.record_count(), imported_ring.record_count()); + + uint32_t oldest_sequence = imported_ring.GetOldestSequence(); + for (uint32_t i = 0; i < record_count; ++i) { + uint32_t sequence = oldest_sequence + i; + Record record; + EXPECT_TRUE(imported_ring.Get(&sequence, &record)); + EXPECT_EQ(Record(FillChar(i)), record); + } + } + + ASSERT_EQ(0, munmap(mmap_base, mmap_size)); +} + +TEST(BroadcastRingTest, ShouldDieIfPutReadonlyMmap) { + using Ring = Dynamic_32_NxM::Ring; + using Record = Ring::Record; + + uint32_t record_count = Ring::Traits::MinCount(); + size_t ring_size = Ring::MemorySize(record_count); + + size_t page_size = sysconf(_SC_PAGESIZE); + size_t mmap_size = (ring_size + (page_size - 1)) & ~(page_size - 1); + ASSERT_GE(mmap_size, ring_size); + + void* mmap_base = mmap(nullptr, mmap_size, PROT_READ | PROT_WRITE, + MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); + ASSERT_NE(MAP_FAILED, mmap_base); + + Ring ring = Ring::Create(mmap_base, mmap_size, record_count); + for (uint32_t i = 0; i < record_count; ++i) ring.Put(Record(FillChar(i))); + + ASSERT_EQ(0, mprotect(mmap_base, mmap_size, PROT_READ)); + + EXPECT_DEATH_IF_SUPPORTED({ ring.Put(Record(7)); }, ""); + + ASSERT_EQ(0, munmap(mmap_base, mmap_size)); +} + +TEST(BroadcastRingTest, ShouldDieIfCreationMmapTooSmall) { + using Ring = Dynamic_32_NxM::Ring; + using Record = Ring::Record; + + uint32_t record_count = Ring::Traits::MinCount(); + size_t ring_size = Ring::MemorySize(record_count); + FakeMmap mmap(ring_size); + + EXPECT_DEATH_IF_SUPPORTED({ + Ring ring = Ring::Create(mmap.mmap(), ring_size - 1, record_count); + }, ""); + + Ring ring = Ring::Create(mmap.mmap(), ring_size, record_count); + + ring.Put(Record(3)); + + { + uint32_t sequence = ring.GetNewestSequence(); + Record record; + EXPECT_TRUE(ring.Get(&sequence, &record)); + EXPECT_EQ(Record(3), record); + } +} + +TEST(BroadcastRingTest, ShouldDieIfCreationMmapMisaligned) { + using Ring = Static_8_8x1::Ring; + using Record = Ring::Record; + + constexpr int kAlign = Ring::mmap_alignment(); + constexpr int kMisalign = kAlign / 2; + size_t ring_size = Ring::MemorySize(); + std::unique_ptr<char[]> buf(new char[ring_size + kMisalign]); + + EXPECT_DEATH_IF_SUPPORTED( + { Ring ring = Ring::Create(buf.get() + kMisalign, ring_size); }, ""); + + Ring ring = Ring::Create(buf.get(), ring_size); + + ring.Put(Record(3)); + + { + uint32_t sequence = ring.GetNewestSequence(); + Record record; + EXPECT_TRUE(ring.Get(&sequence, &record)); + EXPECT_EQ(Record(3), record); + } +} + +template <typename Ring> +std::unique_ptr<std::thread> CopyTask(std::atomic<bool>* quit, void* in_base, + size_t in_size, void* out_base, + size_t out_size) { + return std::unique_ptr<std::thread>( + new std::thread([quit, in_base, in_size, out_base, out_size]() { + using Record = typename Ring::Record; + + bool import_ok; + Ring in_ring; + Ring out_ring; + std::tie(in_ring, import_ok) = Ring::Import(in_base, in_size); + ASSERT_TRUE(import_ok); + std::tie(out_ring, import_ok) = Ring::Import(out_base, out_size); + ASSERT_TRUE(import_ok); + + uint32_t sequence = in_ring.GetOldestSequence(); + while (!std::atomic_load_explicit(quit, std::memory_order_relaxed)) { + Record record; + if (in_ring.Get(&sequence, &record)) { + out_ring.Put(record); + sequence++; + } + } + })); +} + +TEST(BroadcastRingTest, ThreadedCopySingle) { + using Ring = Dynamic_32_NxM::Ring; + using Record = Ring::Record; + Ring in_ring; + auto in_mmap = CreateRing(&in_ring, Ring::Traits::MinCount()); + + Ring out_ring; + auto out_mmap = CreateRing(&out_ring, Ring::Traits::MinCount()); + + std::atomic<bool> quit(false); + std::unique_ptr<std::thread> copy_task = CopyTask<Ring>( + &quit, out_mmap.mmap(), out_mmap.size, in_mmap.mmap(), in_mmap.size); + + const Record out_record(0x1c); + out_ring.Put(out_record); + + uint32_t in_sequence = in_ring.GetOldestSequence(); + Record in_record; + while (!in_ring.Get(&in_sequence, &in_record)) { + // Do nothing. + } + + EXPECT_EQ(out_record, in_record); + std::atomic_store_explicit(&quit, true, std::memory_order_relaxed); + copy_task->join(); +} + +TEST(BroadcastRingTest, ThreadedCopyLossless) { + using Ring = Dynamic_32_NxM::Ring; + using Record = Ring::Record; + Ring in_ring; + auto in_mmap = CreateRing(&in_ring, Ring::Traits::MinCount()); + + Ring out_ring; + auto out_mmap = CreateRing(&out_ring, Ring::Traits::MinCount()); + + std::atomic<bool> quit(false); + std::unique_ptr<std::thread> copy_task = CopyTask<Ring>( + &quit, out_mmap.mmap(), out_mmap.size, in_mmap.mmap(), in_mmap.size); + + constexpr uint32_t kRecordsToProcess = 10000; + uint32_t out_records = 0; + uint32_t in_records = 0; + uint32_t in_sequence = in_ring.GetNextSequence(); + while (out_records < kRecordsToProcess || in_records < kRecordsToProcess) { + if (out_records < kRecordsToProcess && + out_records - in_records < out_ring.record_count()) { + const Record out_record(FillChar(out_records)); + out_ring.Put(out_record); + out_records++; + } + + Record in_record; + while (in_ring.Get(&in_sequence, &in_record)) { + EXPECT_EQ(Record(FillChar(in_records)), in_record); + in_records++; + in_sequence++; + } + } + + EXPECT_EQ(kRecordsToProcess, out_records); + EXPECT_EQ(kRecordsToProcess, in_records); + + std::atomic_store_explicit(&quit, true, std::memory_order_relaxed); + copy_task->join(); +} + +TEST(BroadcastRingTest, ThreadedCopyLossy) { + using Ring = Dynamic_32_NxM::Ring; + using Record = Ring::Record; + Ring in_ring; + auto in_mmap = CreateRing(&in_ring, Ring::Traits::MinCount()); + + Ring out_ring; + auto out_mmap = CreateRing(&out_ring, Ring::Traits::MinCount()); + + std::atomic<bool> quit(false); + std::unique_ptr<std::thread> copy_task = CopyTask<Ring>( + &quit, out_mmap.mmap(), out_mmap.size, in_mmap.mmap(), in_mmap.size); + + constexpr uint32_t kRecordsToProcess = 100000; + uint32_t out_records = 0; + uint32_t in_records = 0; + uint32_t in_sequence = in_ring.GetNextSequence(); + while (out_records < kRecordsToProcess) { + const Record out_record(FillChar(out_records)); + out_ring.Put(out_record); + out_records++; + + Record in_record; + if (in_ring.GetNewest(&in_sequence, &in_record)) { + EXPECT_EQ(Record(in_record.v[0]), in_record); + in_records++; + in_sequence++; + } + } + + EXPECT_EQ(kRecordsToProcess, out_records); + EXPECT_GE(kRecordsToProcess, in_records); + + std::atomic_store_explicit(&quit, true, std::memory_order_relaxed); + copy_task->join(); +} + +template <typename Ring> +std::unique_ptr<std::thread> CheckFillTask(std::atomic<bool>* quit, + void* in_base, size_t in_size) { + return std::unique_ptr<std::thread>( + new std::thread([quit, in_base, in_size]() { + using Record = typename Ring::Record; + + bool import_ok; + Ring in_ring; + std::tie(in_ring, import_ok) = Ring::Import(in_base, in_size); + ASSERT_TRUE(import_ok); + + uint32_t sequence = in_ring.GetOldestSequence(); + while (!std::atomic_load_explicit(quit, std::memory_order_relaxed)) { + Record record; + if (in_ring.Get(&sequence, &record)) { + ASSERT_EQ(Record(record.v[0]), record); + sequence++; + } + } + })); +} + +template <typename Ring> +void ThreadedOverwriteTorture() { + using Record = typename Ring::Record; + + // Maximize overwrites by having few records. + const int kMinRecordCount = 1; + const int kMaxRecordCount = 4; + + for (int count = kMinRecordCount; count <= kMaxRecordCount; count *= 2) { + Ring out_ring; + auto out_mmap = CreateRing(&out_ring, count); + + std::atomic<bool> quit(false); + std::unique_ptr<std::thread> check_task = + CheckFillTask<Ring>(&quit, out_mmap.mmap(), out_mmap.size); + + constexpr int kIterations = 10000; + for (int i = 0; i < kIterations; ++i) { + const Record record(FillChar(i)); + out_ring.Put(record); + } + + std::atomic_store_explicit(&quit, true, std::memory_order_relaxed); + check_task->join(); + } +} + +TEST(BroadcastRingTest, ThreadedOverwriteTortureSmall) { + ThreadedOverwriteTorture<Dynamic_16_NxM_1plus0::Ring>(); +} + +TEST(BroadcastRingTest, ThreadedOverwriteTortureLarge) { + ThreadedOverwriteTorture<Dynamic_256_NxM_1plus0::Ring>(); +} + +} // namespace dvr +} // namespace android diff --git a/libs/vr/libbroadcastring/include/libbroadcastring/broadcast_ring.h b/libs/vr/libbroadcastring/include/libbroadcastring/broadcast_ring.h new file mode 100644 index 0000000000..69cb64826e --- /dev/null +++ b/libs/vr/libbroadcastring/include/libbroadcastring/broadcast_ring.h @@ -0,0 +1,668 @@ +#ifndef ANDROID_DVR_BROADCAST_RING_H_ +#define ANDROID_DVR_BROADCAST_RING_H_ + +#include <inttypes.h> +#include <stddef.h> +#include <stdio.h> +#include <atomic> +#include <limits> +#include <tuple> +#include <type_traits> +#include <utility> + +#include "android-base/logging.h" + +#if ATOMIC_LONG_LOCK_FREE != 2 || ATOMIC_INT_LOCK_FREE != 2 +#error "This file requires lock free atomic uint32_t and long" +#endif + +namespace android { +namespace dvr { + +struct DefaultRingTraits { + // Set this to false to allow compatibly expanding the record size. + static constexpr bool kUseStaticRecordSize = false; + + // Set this to a nonzero value to fix the number of records in the ring. + static constexpr uint32_t kStaticRecordCount = 0; + + // Set this to the max number of records that can be written simultaneously. + static constexpr uint32_t kMaxReservedRecords = 1; + + // Set this to the min number of records that must be readable. + static constexpr uint32_t kMinAvailableRecords = 1; +}; + +// Nonblocking ring suitable for concurrent single-writer, multi-reader access. +// +// Readers never block the writer and thus this is a nondeterministically lossy +// transport in the absence of external synchronization. Don't use this as a +// transport when deterministic behavior is required. +// +// Readers may have a read-only mapping; each reader's state is a single local +// sequence number. +// +// The implementation takes care to avoid data races on record access. +// Inconsistent data can only be returned if at least 2^32 records are written +// during the read-side critical section. +// +// In addition, both readers and the writer are careful to avoid accesses +// outside the bounds of the mmap area passed in during initialization even if +// there is a misbehaving or malicious task with write access to the mmap area. +// +// When dynamic record size is enabled, readers use the record size in the ring +// header when indexing the ring, so that it is possible to extend the record +// type without breaking the read-side ABI. +// +// Avoid calling Put() in a tight loop; there should be significantly more time +// between successive puts than it takes to read one record from memory to +// ensure Get() completes quickly. This requirement should not be difficult to +// achieve for most practical uses; 4kB puts at 10,000Hz is well below the +// scaling limit on current mobile chips. +// +// Example Writer Usage: +// +// using Record = MyRecordType; +// using Ring = BroadcastRing<Record>; +// +// uint32_t record_count = kMyDesiredCount; +// uint32_t ring_size = Ring::MemorySize(record_count); +// +// size_t page_size = sysconf(_SC_PAGESIZE); +// uint32_t mmap_size = (ring_size + (page_size - 1)) & ~(page_size - 1); +// +// // Allocate & map via your preferred mechanism, e.g. +// int fd = open("/dev/shm/ring_test", O_CREAT|O_RDWR|O_CLOEXEC, 0600); +// CHECK(fd >= 0); +// CHECK(!ftruncate(fd, ring_size)); +// void *mmap_base = mmap(nullptr, mmap_size, PROT_READ|PROT_WRITE, +// MAP_SHARED, fd, 0); +// CHECK(mmap_base != MAP_FAILED); +// close(fd); +// +// Ring ring = Ring::Create(mmap_base, mmap_size, record_count); +// +// while (!done) +// ring.Put(BuildNextRecordBlocking()); +// +// CHECK(!munmap(mmap_base, mmap_size)); +// +// Example Reader Usage: +// +// using Record = MyRecordType; +// using Ring = BroadcastRing<Record>; +// +// // Map via your preferred mechanism, e.g. +// int fd = open("/dev/shm/ring_test", O_RDONLY|O_CLOEXEC); +// CHECK(fd >= 0); +// struct stat st; +// CHECK(!fstat(fd, &st)); +// size_t mmap_size = st.st_size; +// void *mmap_base = mmap(nullptr, mmap_size, PROT_READ, +// MAP_SHARED, fd, 0); +// CHECK(mmap_base != MAP_FAILED); +// close(fd); +// +// Ring ring; +// bool import_ok; +// std::tie(ring, import_ok) = Ring::Import(mmap_base, mmap_size); +// CHECK(import_ok); +// +// uint32_t sequence; +// +// // Choose starting point (using "0" is unpredictable but not dangerous) +// sequence = ring.GetOldestSequence(); // The oldest available +// sequence = ring.GetNewestSequence(); // The newest available +// sequence = ring.GetNextSequence(); // The next one produced +// +// while (!done) { +// Record record; +// +// if (you_want_to_process_all_available_records) { +// while (ring.Get(&sequence, &record)) { +// ProcessRecord(sequence, record); +// sequence++; +// } +// } else if (you_want_to_skip_to_the_newest_record) { +// if (ring.GetNewest(&sequence, &record)) { +// ProcessRecord(sequence, record); +// sequence++; +// } +// } +// +// DoSomethingExpensiveOrBlocking(); +// } +// +// CHECK(!munmap(mmap_base, mmap_size)); +// +template <typename RecordType, typename BaseTraits = DefaultRingTraits> +class BroadcastRing { + public: + using Record = RecordType; + struct Traits : public BaseTraits { + // Must have enough space for writers, plus enough space for readers. + static constexpr int kMinRecordCount = + BaseTraits::kMaxReservedRecords + BaseTraits::kMinAvailableRecords; + + // Count of zero means dynamic, non-zero means static. + static constexpr bool kUseStaticRecordCount = + (BaseTraits::kStaticRecordCount != 0); + + // If both record size and count are static then the overall size is too. + static constexpr bool kIsStaticSize = + BaseTraits::kUseStaticRecordSize && kUseStaticRecordCount; + }; + + static constexpr bool IsPowerOfTwo(uint32_t size) { + return (size & (size - 1)) == 0; + } + + // Sanity check the options provided in Traits. + static_assert(Traits::kMinRecordCount >= 1, "Min record count too small"); + static_assert(!Traits::kUseStaticRecordCount || + Traits::kStaticRecordCount >= Traits::kMinRecordCount, + "Static record count is too small"); + static_assert(!Traits::kStaticRecordCount || + IsPowerOfTwo(Traits::kStaticRecordCount), + "Static record count is not a power of two"); + static_assert(std::is_standard_layout<Record>::value, + "Record type must be standard layout"); + + BroadcastRing() {} + + // Creates a new ring at |mmap| with |record_count| records. + // + // There must be at least |MemorySize(record_count)| bytes of space already + // allocated at |mmap|. The ring does not take ownership. + // + // Use this function for dynamically sized rings. + static BroadcastRing Create(void* mmap, size_t mmap_size, + uint32_t record_count) { + BroadcastRing ring(mmap); + CHECK(ring.ValidateGeometry(mmap_size, sizeof(Record), record_count)); + ring.InitializeHeader(sizeof(Record), record_count); + return ring; + } + + // Creates a new ring at |mmap|. + // + // There must be at least |MemorySize()| bytes of space already allocated at + // |mmap|. The ring does not take ownership. + // + // Use this function for statically sized rings. + static BroadcastRing Create(void* mmap, size_t mmap_size) { + static_assert(Traits::kUseStaticRecordCount, + "Wrong Create() function called for dynamic record count"); + return Create(mmap, mmap_size, Traits::kStaticRecordCount); + } + + // Imports an existing ring at |mmap|. + // + // Import may fail if the ring parameters in the mmap header are not sensible. + // In this case the returned boolean is false; make sure to check this value. + static std::tuple<BroadcastRing, bool> Import(void* mmap, size_t mmap_size) { + BroadcastRing ring(mmap); + uint32_t record_size = 0; + uint32_t record_count = 0; + if (mmap_size >= sizeof(Header)) { + record_size = std::atomic_load_explicit(&ring.header_mmap()->record_size, + std::memory_order_relaxed); + record_count = std::atomic_load_explicit( + &ring.header_mmap()->record_count, std::memory_order_relaxed); + } + bool ok = ring.ValidateGeometry(mmap_size, record_size, record_count); + return std::make_tuple(ring, ok); + } + + ~BroadcastRing() {} + + // Calculates the space necessary for a ring of size |record_count|. + // + // Use this function for dynamically sized rings. + static constexpr size_t MemorySize(uint32_t record_count) { + return sizeof(Header) + sizeof(Record) * record_count; + } + + // Calculates the space necessary for a statically sized ring. + // + // Use this function for statically sized rings. + static constexpr size_t MemorySize() { + static_assert( + Traits::kUseStaticRecordCount, + "Wrong MemorySize() function called for dynamic record count"); + return MemorySize(Traits::kStaticRecordCount); + } + + // Writes a record to the ring. + // + // The oldest record is overwritten unless the ring is not already full. + void Put(const Record& record) { + const int kRecordCount = 1; + Reserve(kRecordCount); + Geometry geometry = GetGeometry(); + PutRecordInternal(&record, record_mmap_writer(geometry.tail_index)); + Publish(kRecordCount); + } + + // Gets sequence number of the oldest currently available record. + uint32_t GetOldestSequence() const { + return std::atomic_load_explicit(&header_mmap()->head, + std::memory_order_relaxed); + } + + // Gets sequence number of the first future record. + // + // If the returned value is passed to Get() and there is no concurrent Put(), + // Get() will return false. + uint32_t GetNextSequence() const { + return std::atomic_load_explicit(&header_mmap()->tail, + std::memory_order_relaxed); + } + + // Gets sequence number of the newest currently available record. + uint32_t GetNewestSequence() const { return GetNextSequence() - 1; } + + // Copies the oldest available record with sequence at least |*sequence| to + // |record|. + // + // Returns false if there is no recent enough record available. + // + // Updates |*sequence| with the sequence number of the record returned. To get + // the following record, increment this number by one. + // + // This function synchronizes with two other operations: + // + // (1) Load-Acquire of |tail| + // + // Together with the store-release in Publish(), this load-acquire + // ensures each store to a record in PutRecordInternal() happens-before + // any corresponding load in GetRecordInternal(). + // + // i.e. the stores for the records with sequence numbers < |tail| have + // completed from our perspective + // + // (2) Acquire Fence between record access & final load of |head| + // + // Together with the release fence in Reserve(), this ensures that if + // GetRecordInternal() loads a value stored in some execution of + // PutRecordInternal(), then the store of |head| in the Reserve() that + // preceeded it happens-before our final load of |head|. + // + // i.e. if we read a record with sequence number >= |final_head| then + // no later store to that record has completed from our perspective + bool Get(uint32_t* sequence /*inout*/, Record* record /*out*/) const { + for (;;) { + uint32_t tail = std::atomic_load_explicit(&header_mmap()->tail, + std::memory_order_acquire); + uint32_t head = std::atomic_load_explicit(&header_mmap()->head, + std::memory_order_relaxed); + + if (tail - head > record_count()) + continue; // Concurrent modification; re-try. + + if (*sequence - head > tail - head) + *sequence = head; // Out of window, skip forward to first available. + + if (*sequence == tail) return false; // No new records available. + + Geometry geometry = + CalculateGeometry(record_count(), record_size(), *sequence, tail); + + // Compute address explicitly in case record_size > sizeof(Record). + RecordStorage* record_storage = record_mmap_reader(geometry.head_index); + + GetRecordInternal(record_storage, record); + + // NB: It is not sufficient to change this to a load-acquire of |head|. + std::atomic_thread_fence(std::memory_order_acquire); + + uint32_t final_head = std::atomic_load_explicit( + &header_mmap()->head, std::memory_order_relaxed); + + if (final_head - head > *sequence - head) + continue; // Concurrent modification; re-try. + + // Note: Combining the above 4 comparisons gives: + // 0 <= final_head - head <= sequence - head < tail - head <= record_count + // + // We can also write this as: + // head <=* final_head <=* sequence <* tail <=* head + record_count + // + // where <* orders by difference from head: x <* y if x - head < y - head. + // This agrees with the order of sequence updates during "put" operations. + return true; + } + } + + // Copies the newest available record with sequence at least |*sequence| to + // |record|. + // + // Returns false if there is no recent enough record available. + // + // Updates |*sequence| with the sequence number of the record returned. To get + // the following record, increment this number by one. + bool GetNewest(uint32_t* sequence, Record* record) const { + uint32_t newest_sequence = GetNewestSequence(); + if (*sequence == newest_sequence + 1) return false; + *sequence = newest_sequence; + return Get(sequence, record); + } + + uint32_t record_count() const { return record_count_internal(); } + uint32_t record_size() const { return record_size_internal(); } + static constexpr uint32_t mmap_alignment() { return alignof(Mmap); } + + private: + struct Header { + // Record size for reading out of the ring. Writers always write the full + // length; readers may need to read a prefix of each record. + std::atomic<uint32_t> record_size; + + // Number of records in the ring. + std::atomic<uint32_t> record_count; + + // Readable region is [head % record_count, tail % record_count). + // + // The region in [tail % record_count, head % record_count) was either never + // populated or is being updated. + // + // These are sequences numbers, not indexes - indexes should be computed + // with a modulus. + // + // To ensure consistency: + // + // (1) Writes advance |head| past any updated records before writing to + // them, and advance |tail| after they are written. + // (2) Readers check |tail| before reading data and |head| after, + // making sure to discard any data that was written to concurrently. + std::atomic<uint32_t> head; + std::atomic<uint32_t> tail; + }; + + // Store using the standard word size. + using StorageType = long; // NOLINT + + // Always require 8 byte alignment so that the same record sizes are legal on + // 32 and 64 bit builds. + static constexpr size_t kRecordAlignment = 8; + static_assert(kRecordAlignment % sizeof(StorageType) == 0, + "Bad record alignment"); + + struct RecordStorage { + // This is accessed with relaxed atomics to prevent data races on the + // contained data, which would be undefined behavior. + std::atomic<StorageType> data[sizeof(Record) / sizeof(StorageType)]; + }; + + static_assert(sizeof(StorageType) * + std::extent<decltype(RecordStorage::data)>() == + sizeof(Record), + "Record length must be a multiple of sizeof(StorageType)"); + + struct Geometry { + // Static geometry. + uint32_t record_count; + uint32_t record_size; + + // Copy of atomic sequence counts. + uint32_t head; + uint32_t tail; + + // First index of readable region. + uint32_t head_index; + + // First index of writable region. + uint32_t tail_index; + + // Number of records in readable region. + uint32_t count; + + // Number of records in writable region. + uint32_t space; + }; + + // Mmap area layout. + // + // Readers should not index directly into |records| as this is not valid when + // dynamic record sizes are used; use record_mmap_reader() instead. + struct Mmap { + Header header; + RecordStorage records[]; + }; + + static_assert(std::is_standard_layout<Mmap>::value, + "Mmap must be standard layout"); + static_assert(sizeof(std::atomic<uint32_t>) == sizeof(uint32_t), + "Lockless atomics contain extra state"); + static_assert(sizeof(std::atomic<StorageType>) == sizeof(StorageType), + "Lockless atomics contain extra state"); + + explicit BroadcastRing(void* mmap) { + CHECK_EQ(0U, reinterpret_cast<uintptr_t>(mmap) % alignof(Mmap)); + data_.mmap = reinterpret_cast<Mmap*>(mmap); + } + + // Initializes the mmap area header for a new ring. + void InitializeHeader(uint32_t record_size, uint32_t record_count) { + constexpr uint32_t kInitialSequence = -256; // Force an early wrap. + std::atomic_store_explicit(&header_mmap()->record_size, record_size, + std::memory_order_relaxed); + std::atomic_store_explicit(&header_mmap()->record_count, record_count, + std::memory_order_relaxed); + std::atomic_store_explicit(&header_mmap()->head, kInitialSequence, + std::memory_order_relaxed); + std::atomic_store_explicit(&header_mmap()->tail, kInitialSequence, + std::memory_order_relaxed); + } + + // Validates ring geometry. + // + // Ring geometry is validated carefully on import and then cached. This allows + // us to avoid out-of-range accesses even if the parameters in the header are + // later changed. + bool ValidateGeometry(size_t mmap_size, uint32_t header_record_size, + uint32_t header_record_count) { + set_record_size(header_record_size); + set_record_count(header_record_count); + + if (record_size() != header_record_size) return false; + if (record_count() != header_record_count) return false; + if (record_count() < Traits::kMinRecordCount) return false; + if (record_size() < sizeof(Record)) return false; + if (record_size() % kRecordAlignment != 0) return false; + if (!IsPowerOfTwo(record_count())) return false; + + size_t memory_size = record_count() * record_size(); + if (memory_size / record_size() != record_count()) return false; + if (memory_size + sizeof(Header) < memory_size) return false; + if (memory_size + sizeof(Header) > mmap_size) return false; + + return true; + } + + // Copies a record into the ring. + // + // This is done with relaxed atomics because otherwise it is racy according to + // the C++ memory model. This is very low overhead once optimized. + static inline void PutRecordInternal(const Record* in, RecordStorage* out) { + StorageType data[sizeof(Record) / sizeof(StorageType)]; + memcpy(data, in, sizeof(*in)); + for (size_t i = 0; i < std::extent<decltype(data)>(); ++i) { + std::atomic_store_explicit(&out->data[i], data[i], + std::memory_order_relaxed); + } + } + + // Copies a record out of the ring. + // + // This is done with relaxed atomics because otherwise it is racy according to + // the C++ memory model. This is very low overhead once optimized. + static inline void GetRecordInternal(RecordStorage* in, Record* out) { + StorageType data[sizeof(Record) / sizeof(StorageType)]; + for (size_t i = 0; i < std::extent<decltype(data)>(); ++i) { + data[i] = + std::atomic_load_explicit(&in->data[i], std::memory_order_relaxed); + } + memcpy(out, &data, sizeof(*out)); + } + + // Converts a record's sequence number into a storage index. + static uint32_t SequenceToIndex(uint32_t sequence, uint32_t record_count) { + return sequence & (record_count - 1); + } + + // Computes readable & writable ranges from ring parameters. + static Geometry CalculateGeometry(uint32_t record_count, uint32_t record_size, + uint32_t head, uint32_t tail) { + Geometry geometry; + geometry.record_count = record_count; + geometry.record_size = record_size; + DCHECK_EQ(0U, geometry.record_size % kRecordAlignment); + geometry.head = head; + geometry.tail = tail; + geometry.head_index = SequenceToIndex(head, record_count); + geometry.tail_index = SequenceToIndex(tail, record_count); + geometry.count = geometry.tail - geometry.head; + DCHECK_LE(geometry.count, record_count); + geometry.space = geometry.record_count - geometry.count; + return geometry; + } + + // Gets the current ring readable & writable regions. + // + // This this is always safe from the writing thread since it is the only + // thread allowed to update the header. + Geometry GetGeometry() const { + return CalculateGeometry( + record_count(), record_size(), + std::atomic_load_explicit(&header_mmap()->head, + std::memory_order_relaxed), + std::atomic_load_explicit(&header_mmap()->tail, + std::memory_order_relaxed)); + } + + // Makes space for at least |reserve_count| records. + // + // There is nothing to prevent overwriting records that have concurrent + // readers. We do however ensure that this situation can be detected: the + // fence ensures the |head| update will be the first update seen by readers, + // and readers check this value after reading and discard data that may have + // been concurrently modified. + void Reserve(uint32_t reserve_count) { + Geometry geometry = GetGeometry(); + DCHECK_LE(reserve_count, Traits::kMaxReservedRecords); + uint32_t needed = + (geometry.space >= reserve_count ? 0 : reserve_count - geometry.space); + + std::atomic_store_explicit(&header_mmap()->head, geometry.head + needed, + std::memory_order_relaxed); + + // NB: It is not sufficient to change this to a store-release of |head|. + std::atomic_thread_fence(std::memory_order_release); + } + + // Makes |publish_count| records visible to readers. + // + // Space must have been reserved by a previous call to Reserve(). + void Publish(uint32_t publish_count) { + Geometry geometry = GetGeometry(); + DCHECK_LE(publish_count, geometry.space); + std::atomic_store_explicit(&header_mmap()->tail, + geometry.tail + publish_count, + std::memory_order_release); + } + + // Helpers to compute addresses in mmap area. + Mmap* mmap() const { return data_.mmap; } + Header* header_mmap() const { return &data_.mmap->header; } + RecordStorage* record_mmap_writer(uint32_t index) const { + DCHECK_EQ(sizeof(Record), record_size()); + return &data_.mmap->records[index]; + } + RecordStorage* record_mmap_reader(uint32_t index) const { + if (Traits::kUseStaticRecordSize) { + return &data_.mmap->records[index]; + } else { + // Calculate the location of a record in the ring without assuming that + // sizeof(Record) == record_size. + return reinterpret_cast<RecordStorage*>( + reinterpret_cast<char*>(data_.mmap->records) + index * record_size()); + } + } + + // The following horrifying template gunk enables us to store just the mmap + // base pointer for compile-time statically sized rings. Dynamically sized + // rings also store the validated copy of the record size & count. + // + // This boils down to: use a compile time constant if available, and otherwise + // load the value that was validated on import from a member variable. + template <typename T = Traits> + typename std::enable_if<T::kUseStaticRecordSize, uint32_t>::type + record_size_internal() const { + return sizeof(Record); + } + + template <typename T = Traits> + typename std::enable_if<!T::kUseStaticRecordSize, uint32_t>::type + record_size_internal() const { + return data_.record_size; + } + + template <typename T = Traits> + typename std::enable_if<T::kUseStaticRecordSize, void>::type set_record_size( + uint32_t /*record_size*/) {} + + template <typename T = Traits> + typename std::enable_if<!T::kUseStaticRecordSize, void>::type set_record_size( + uint32_t record_size) { + data_.record_size = record_size; + } + + template <typename T = Traits> + typename std::enable_if<T::kUseStaticRecordCount, uint32_t>::type + record_count_internal() const { + return Traits::kStaticRecordCount; + } + + template <typename T = Traits> + typename std::enable_if<!T::kUseStaticRecordCount, uint32_t>::type + record_count_internal() const { + return data_.record_count; + } + + template <typename T = Traits> + typename std::enable_if<T::kUseStaticRecordCount, void>::type + set_record_count(uint32_t /*record_count*/) const {} + + template <typename T = Traits> + typename std::enable_if<!T::kUseStaticRecordCount, void>::type + set_record_count(uint32_t record_count) { + data_.record_count = record_count; + } + + // Data we need to store for statically sized rings. + struct DataStaticSize { + Mmap* mmap = nullptr; + }; + + // Data we need to store for dynamically sized rings. + struct DataDynamicSize { + Mmap* mmap = nullptr; + + // These are cached to make sure misbehaving writers cannot cause + // out-of-bounds memory accesses by updating the values in the mmap header. + uint32_t record_size = 0; + uint32_t record_count = 0; + }; + + using DataStaticOrDynamic = + typename std::conditional<Traits::kIsStaticSize, DataStaticSize, + DataDynamicSize>::type; + + DataStaticOrDynamic data_; +}; + +} // namespace dvr +} // namespace android + +#endif // ANDROID_DVR_BROADCAST_RING_H_ diff --git a/libs/vr/libbufferhub/buffer_hub_client.cpp b/libs/vr/libbufferhub/buffer_hub_client.cpp index 2749fd18c7..a1f952e66c 100644 --- a/libs/vr/libbufferhub/buffer_hub_client.cpp +++ b/libs/vr/libbufferhub/buffer_hub_client.cpp @@ -20,6 +20,7 @@ using android::pdx::Status; namespace { +// TODO(hendrikw): These flags can not be hard coded. constexpr int kUncachedBlobUsageFlags = GRALLOC_USAGE_SW_READ_RARELY | GRALLOC_USAGE_SW_WRITE_RARELY | GRALLOC_USAGE_PRIVATE_UNCACHED; @@ -110,6 +111,7 @@ int BufferHubBuffer::Unlock(size_t index) { return slices_[index].Unlock(); } int BufferHubBuffer::GetBlobReadWritePointer(size_t size, void** addr) { int width = static_cast<int>(size); int height = 1; + // TODO(hendrikw): These flags can not be hard coded. constexpr int usage = GRALLOC_USAGE_SW_READ_RARELY | GRALLOC_USAGE_SW_WRITE_RARELY | GRALLOC_USAGE_PRIVATE_UNCACHED; @@ -196,18 +198,27 @@ int BufferConsumer::SetIgnore(bool ignore) { InvokeRemoteMethod<BufferHubRPC::ConsumerSetIgnore>(ignore)); } -BufferProducer::BufferProducer(int width, int height, int format, int usage, +BufferProducer::BufferProducer(uint32_t width, uint32_t height, uint32_t format, + uint32_t usage, size_t metadata_size, + size_t slice_count) + : BufferProducer(width, height, format, usage, usage, metadata_size, + slice_count) {} + +BufferProducer::BufferProducer(uint32_t width, uint32_t height, uint32_t format, + uint64_t producer_usage, uint64_t consumer_usage, size_t metadata_size, size_t slice_count) : BASE(BufferHubRPC::kClientPath) { ATRACE_NAME("BufferProducer::BufferProducer"); ALOGD_IF(TRACE, - "BufferProducer::BufferProducer: fd=%d width=%d height=%d format=%d " - "usage=%d, metadata_size=%zu, slice_count=%zu", - event_fd(), width, height, format, usage, metadata_size, - slice_count); + "BufferProducer::BufferProducer: fd=%d width=%u height=%u format=%u " + "producer_usage=%" PRIx64 " consumer_usage=%" PRIx64 + " metadata_size=%zu slice_count=%zu", + event_fd(), width, height, format, producer_usage, consumer_usage, + metadata_size, slice_count); auto status = InvokeRemoteMethod<BufferHubRPC::CreateBuffer>( - width, height, format, usage, metadata_size, slice_count); + width, height, format, producer_usage, consumer_usage, metadata_size, + slice_count); if (!status) { ALOGE( "BufferProducer::BufferProducer: Failed to create producer buffer: %s", @@ -226,21 +237,29 @@ BufferProducer::BufferProducer(int width, int height, int format, int usage, } BufferProducer::BufferProducer(const std::string& name, int user_id, - int group_id, int width, int height, int format, - int usage, size_t meta_size_bytes, + int group_id, uint32_t width, uint32_t height, + uint32_t format, uint32_t usage, + size_t meta_size_bytes, size_t slice_count) + : BufferProducer(name, user_id, group_id, width, height, format, usage, + usage, meta_size_bytes, slice_count) {} + +BufferProducer::BufferProducer(const std::string& name, int user_id, + int group_id, uint32_t width, uint32_t height, + uint32_t format, uint64_t producer_usage, + uint64_t consumer_usage, size_t meta_size_bytes, size_t slice_count) : BASE(BufferHubRPC::kClientPath) { ATRACE_NAME("BufferProducer::BufferProducer"); ALOGD_IF(TRACE, "BufferProducer::BufferProducer: fd=%d name=%s user_id=%d " - "group_id=%d width=%d height=%d format=%d usage=%d, " - "meta_size_bytes=%zu, slice_count=%zu", + "group_id=%d width=%u height=%u format=%u producer_usage=%" PRIx64 + " consumer_usage=%" PRIx64 " meta_size_bytes=%zu slice_count=%zu", event_fd(), name.c_str(), user_id, group_id, width, height, format, - usage, meta_size_bytes, slice_count); + producer_usage, consumer_usage, meta_size_bytes, slice_count); auto status = InvokeRemoteMethod<BufferHubRPC::CreatePersistentBuffer>( - name, user_id, group_id, width, height, format, usage, meta_size_bytes, - slice_count); + name, user_id, group_id, width, height, format, producer_usage, + consumer_usage, meta_size_bytes, slice_count); if (!status) { ALOGE( "BufferProducer::BufferProducer: Failed to create/get persistent " @@ -260,18 +279,25 @@ BufferProducer::BufferProducer(const std::string& name, int user_id, } } -BufferProducer::BufferProducer(int usage, size_t size) +BufferProducer::BufferProducer(uint32_t usage, size_t size) + : BufferProducer(usage, usage, size) {} + +BufferProducer::BufferProducer(uint64_t producer_usage, uint64_t consumer_usage, + size_t size) : BASE(BufferHubRPC::kClientPath) { ATRACE_NAME("BufferProducer::BufferProducer"); - ALOGD_IF(TRACE, "BufferProducer::BufferProducer: usage=%d size=%zu", usage, - size); + ALOGD_IF(TRACE, + "BufferProducer::BufferProducer: producer_usage=%" PRIx64 + " consumer_usage=%" PRIx64 " size=%zu", + producer_usage, consumer_usage, size); const int width = static_cast<int>(size); const int height = 1; const int format = HAL_PIXEL_FORMAT_BLOB; const size_t meta_size_bytes = 0; const size_t slice_count = 1; auto status = InvokeRemoteMethod<BufferHubRPC::CreateBuffer>( - width, height, format, usage, meta_size_bytes, slice_count); + width, height, format, producer_usage, consumer_usage, meta_size_bytes, + slice_count); if (!status) { ALOGE("BufferProducer::BufferProducer: Failed to create blob: %s", status.GetErrorMessage().c_str()); @@ -289,21 +315,27 @@ BufferProducer::BufferProducer(int usage, size_t size) } BufferProducer::BufferProducer(const std::string& name, int user_id, - int group_id, int usage, size_t size) + int group_id, uint32_t usage, size_t size) + : BufferProducer(name, user_id, group_id, usage, usage, size) {} + +BufferProducer::BufferProducer(const std::string& name, int user_id, + int group_id, uint64_t producer_usage, + uint64_t consumer_usage, size_t size) : BASE(BufferHubRPC::kClientPath) { ATRACE_NAME("BufferProducer::BufferProducer"); ALOGD_IF(TRACE, "BufferProducer::BufferProducer: name=%s user_id=%d group=%d " - "usage=%d size=%zu", - name.c_str(), user_id, group_id, usage, size); + "producer_usage=%" PRIx64 " consumer_usage=%" PRIx64 " size=%zu", + name.c_str(), user_id, group_id, producer_usage, consumer_usage, + size); const int width = static_cast<int>(size); const int height = 1; const int format = HAL_PIXEL_FORMAT_BLOB; const size_t meta_size_bytes = 0; const size_t slice_count = 1; auto status = InvokeRemoteMethod<BufferHubRPC::CreatePersistentBuffer>( - name, user_id, group_id, width, height, format, usage, meta_size_bytes, - slice_count); + name, user_id, group_id, width, height, format, producer_usage, + consumer_usage, meta_size_bytes, slice_count); if (!status) { ALOGE( "BufferProducer::BufferProducer: Failed to create persistent " diff --git a/libs/vr/libbufferhub/include/private/dvr/buffer_hub_client.h b/libs/vr/libbufferhub/include/private/dvr/buffer_hub_client.h index dfeed50f3d..c772ed301b 100644 --- a/libs/vr/libbufferhub/include/private/dvr/buffer_hub_client.h +++ b/libs/vr/libbufferhub/include/private/dvr/buffer_hub_client.h @@ -107,11 +107,14 @@ class BufferHubBuffer : public pdx::Client { // The following methods return settings of the first buffer. Currently, // it is only possible to create multi-buffer BufferHubBuffers with the same // settings. - int width() const { return slices_[0].width(); } - int height() const { return slices_[0].height(); } - int stride() const { return slices_[0].stride(); } - int format() const { return slices_[0].format(); } - int usage() const { return slices_[0].usage(); } + uint32_t width() const { return slices_[0].width(); } + uint32_t height() const { return slices_[0].height(); } + uint32_t stride() const { return slices_[0].stride(); } + uint32_t format() const { return slices_[0].format(); } + uint32_t usage() const { return slices_[0].usage(); } + uint32_t layer_count() const { return slices_[0].layer_count(); } + uint64_t producer_usage() const { return slices_[0].producer_usage(); } + uint64_t consumer_usage() const { return slices_[0].consumer_usage(); } protected: explicit BufferHubBuffer(LocalChannelHandle channel); @@ -218,8 +221,12 @@ class BufferProducer : public pdx::ClientBase<BufferProducer, BufferHubBuffer> { // arguments as the constructors. // Constructs a buffer with the given geometry and parameters. - BufferProducer(int width, int height, int format, int usage, - size_t metadata_size = 0, size_t slice_count = 1); + BufferProducer(uint32_t width, uint32_t height, uint32_t format, + uint32_t usage, size_t metadata_size = 0, + size_t slice_count = 1); + BufferProducer(uint32_t width, uint32_t height, uint32_t format, + uint64_t producer_usage, uint64_t consumer_usage, + size_t metadata_size, size_t slice_count); // Constructs a persistent buffer with the given geometry and parameters and // binds it to |name| in one shot. If a persistent buffer with the same name @@ -233,16 +240,24 @@ class BufferProducer : public pdx::ClientBase<BufferProducer, BufferHubBuffer> { // created and cannot be changed. A user or group id of -1 disables checks for // that respective id. A user or group id of 0 is substituted with the // effective user or group id of the calling process. - BufferProducer(const std::string& name, int user_id, int group_id, int width, - int height, int format, int usage, size_t metadata_size = 0, + BufferProducer(const std::string& name, int user_id, int group_id, + uint32_t width, uint32_t height, uint32_t format, + uint32_t usage, size_t metadata_size = 0, size_t slice_count = 1); + BufferProducer(const std::string& name, int user_id, int group_id, + uint32_t width, uint32_t height, uint32_t format, + uint64_t producer_usage, uint64_t consumer_usage, + size_t metadata_size, size_t slice_count); // Constructs a blob (flat) buffer with the given usage flags. - BufferProducer(int usage, size_t size); + BufferProducer(uint32_t usage, size_t size); + BufferProducer(uint64_t producer_usage, uint64_t consumer_usage, size_t size); // Constructs a persistent blob (flat) buffer and binds it to |name|. - BufferProducer(const std::string& name, int user_id, int group_id, int usage, - size_t size); + BufferProducer(const std::string& name, int user_id, int group_id, + uint32_t usage, size_t size); + BufferProducer(const std::string& name, int user_id, int group_id, + uint64_t producer_usage, uint64_t consumer_usage, size_t size); // Constructs a channel to persistent buffer by name only. The buffer must // have been previously created or made persistent. diff --git a/libs/vr/libbufferhub/include/private/dvr/bufferhub_rpc.h b/libs/vr/libbufferhub/include/private/dvr/bufferhub_rpc.h index 7ed024fb8c..b6302f130f 100644 --- a/libs/vr/libbufferhub/include/private/dvr/bufferhub_rpc.h +++ b/libs/vr/libbufferhub/include/private/dvr/bufferhub_rpc.h @@ -24,7 +24,8 @@ class NativeBufferHandle { width_(buffer.width()), height_(buffer.height()), format_(buffer.format()), - usage_(buffer.usage()) { + producer_usage_(buffer.producer_usage()), + consumer_usage_(buffer.consumer_usage()) { // Populate the fd and int vectors: native_handle->data[] is an array of fds // followed by an array of opaque ints. const int fd_count = buffer.handle()->numFds; @@ -37,6 +38,7 @@ class NativeBufferHandle { } } NativeBufferHandle(NativeBufferHandle&& other) = default; + NativeBufferHandle& operator=(NativeBufferHandle&& other) = default; // Imports the native handle into the given IonBuffer instance. int Import(IonBuffer* buffer) { @@ -46,9 +48,10 @@ class NativeBufferHandle { for (const auto& fd : fds_) fd_ints.push_back(fd.Get()); - const int ret = buffer->Import(fd_ints.data(), fd_ints.size(), - opaque_ints_.data(), opaque_ints_.size(), - width_, height_, stride_, format_, usage_); + const int ret = + buffer->Import(fd_ints.data(), fd_ints.size(), opaque_ints_.data(), + opaque_ints_.size(), width_, height_, stride_, format_, + producer_usage_, consumer_usage_); if (ret < 0) return ret; @@ -68,24 +71,32 @@ class NativeBufferHandle { private: int id_; - int stride_; - int width_; - int height_; - int format_; - int usage_; + uint32_t stride_; + uint32_t width_; + uint32_t height_; + uint32_t format_; + uint64_t producer_usage_; + uint64_t consumer_usage_; std::vector<int> opaque_ints_; std::vector<FileHandleType> fds_; - void Clear() { id_ = stride_ = width_ = height_ = format_ = usage_ = -1; } + void Clear() { + id_ = -1; + stride_ = width_ = height_ = format_ = producer_usage_ = consumer_usage_ = + 0; + } PDX_SERIALIZABLE_MEMBERS(NativeBufferHandle<FileHandleType>, id_, stride_, - width_, height_, format_, usage_, opaque_ints_, - fds_); + width_, height_, format_, producer_usage_, + consumer_usage_, opaque_ints_, fds_); NativeBufferHandle(const NativeBufferHandle&) = delete; void operator=(const NativeBufferHandle&) = delete; }; +using BorrowedNativeBufferHandle = NativeBufferHandle<pdx::BorrowedHandle>; +using LocalNativeBufferHandle = NativeBufferHandle<pdx::LocalHandle>; + template <typename FileHandleType> class FenceHandle { public: @@ -127,6 +138,23 @@ struct QueueInfo { PDX_SERIALIZABLE_MEMBERS(QueueInfo, meta_size_bytes, id); }; +struct UsagePolicy { + uint64_t producer_set_mask; + uint64_t producer_clear_mask; + uint64_t producer_deny_set_mask; + uint64_t producer_deny_clear_mask; + uint64_t consumer_set_mask; + uint64_t consumer_clear_mask; + uint64_t consumer_deny_set_mask; + uint64_t consumer_deny_clear_mask; + + private: + PDX_SERIALIZABLE_MEMBERS(UsagePolicy, producer_set_mask, producer_clear_mask, + producer_deny_set_mask, producer_deny_clear_mask, + consumer_set_mask, consumer_clear_mask, + consumer_deny_set_mask, consumer_deny_clear_mask); +}; + // BufferHub Service RPC interface. Defines the endpoints, op codes, and method // type signatures supported by bufferhubd. struct BufferHubRPC { @@ -173,44 +201,46 @@ struct BufferHubRPC { // Methods. PDX_REMOTE_METHOD(CreateBuffer, kOpCreateBuffer, - int(int width, int height, int format, int usage, - size_t meta_size_bytes, size_t slice_count)); + void(uint32_t width, uint32_t height, uint32_t format, + uint64_t producer_usage, uint64_t consumer_usage, + size_t meta_size_bytes, size_t slice_count)); PDX_REMOTE_METHOD(CreatePersistentBuffer, kOpCreatePersistentBuffer, - int(const std::string& name, int user_id, int group_id, - int width, int height, int format, int usage, - size_t meta_size_bytes, size_t slice_count)); + void(const std::string& name, int user_id, int group_id, + uint32_t width, uint32_t height, uint32_t format, + uint64_t producer_usage, uint64_t consumer_usage, + size_t meta_size_bytes, size_t slice_count)); PDX_REMOTE_METHOD(GetPersistentBuffer, kOpGetPersistentBuffer, - int(const std::string& name)); + void(const std::string& name)); PDX_REMOTE_METHOD(GetBuffer, kOpGetBuffer, NativeBufferHandle<LocalHandle>(unsigned index)); PDX_REMOTE_METHOD(GetBuffers, kOpGetBuffers, std::vector<NativeBufferHandle<LocalHandle>>(Void)); PDX_REMOTE_METHOD(NewConsumer, kOpNewConsumer, LocalChannelHandle(Void)); PDX_REMOTE_METHOD(ProducerMakePersistent, kOpProducerMakePersistent, - int(const std::string& name, int user_id, int group_id)); + void(const std::string& name, int user_id, int group_id)); PDX_REMOTE_METHOD(ProducerRemovePersistence, kOpProducerRemovePersistence, - int(Void)); + void(Void)); PDX_REMOTE_METHOD(ProducerPost, kOpProducerPost, - int(LocalFence acquire_fence, MetaData)); + void(LocalFence acquire_fence, MetaData)); PDX_REMOTE_METHOD(ProducerGain, kOpProducerGain, LocalFence(Void)); PDX_REMOTE_METHOD(ConsumerAcquire, kOpConsumerAcquire, std::pair<LocalFence, MetaData>(std::size_t metadata_size)); PDX_REMOTE_METHOD(ConsumerRelease, kOpConsumerRelease, - int(LocalFence release_fence)); - PDX_REMOTE_METHOD(ConsumerSetIgnore, kOpConsumerSetIgnore, int(bool ignore)); + void(LocalFence release_fence)); + PDX_REMOTE_METHOD(ConsumerSetIgnore, kOpConsumerSetIgnore, void(bool ignore)); // Buffer Queue Methods. PDX_REMOTE_METHOD(CreateProducerQueue, kOpCreateProducerQueue, - QueueInfo(size_t meta_size_bytes, int usage_set_mask, - int usage_clear_mask, int usage_deny_set_mask, - int usage_deny_clear_mask)); + QueueInfo(size_t meta_size_bytes, + const UsagePolicy& usage_policy)); PDX_REMOTE_METHOD(CreateConsumerQueue, kOpCreateConsumerQueue, LocalChannelHandle(Void)); PDX_REMOTE_METHOD(GetQueueInfo, kOpGetQueueInfo, QueueInfo(Void)); PDX_REMOTE_METHOD(ProducerQueueAllocateBuffers, kOpProducerQueueAllocateBuffers, std::vector<std::pair<LocalChannelHandle, size_t>>( - int width, int height, int format, int usage, + uint32_t width, uint32_t height, uint32_t format, + uint64_t producer_usage, uint64_t consumer_usage, size_t slice_count, size_t buffer_count)); PDX_REMOTE_METHOD(ProducerQueueDetachBuffer, kOpProducerQueueDetachBuffer, void(size_t slot)); diff --git a/libs/vr/libbufferhub/include/private/dvr/ion_buffer.h b/libs/vr/libbufferhub/include/private/dvr/ion_buffer.h index ffc42d6123..e167a1746c 100644 --- a/libs/vr/libbufferhub/include/private/dvr/ion_buffer.h +++ b/libs/vr/libbufferhub/include/private/dvr/ion_buffer.h @@ -12,11 +12,20 @@ namespace dvr { class IonBuffer { public: IonBuffer(); - IonBuffer(int width, int height, int format, int usage); - IonBuffer(buffer_handle_t handle, int width, int height, int stride, - int format, int usage); - IonBuffer(buffer_handle_t handle, int width, int height, int layer_count, - int stride, int layer_stride, int format, int usage); + IonBuffer(uint32_t width, uint32_t height, uint32_t format, uint32_t usage); + IonBuffer(uint32_t width, uint32_t height, uint32_t format, + uint64_t producer_usage, uint64_t consumer_usage); + IonBuffer(buffer_handle_t handle, uint32_t width, uint32_t height, + uint32_t stride, uint32_t format, uint32_t usage); + IonBuffer(buffer_handle_t handle, uint32_t width, uint32_t height, + uint32_t stride, uint32_t format, uint64_t producer_usage, + uint64_t consumer_usage); + IonBuffer(buffer_handle_t handle, uint32_t width, uint32_t height, + uint32_t layer_count, uint32_t stride, uint32_t layer_stride, + uint32_t format, uint32_t usage); + IonBuffer(buffer_handle_t handle, uint32_t width, uint32_t height, + uint32_t layer_count, uint32_t stride, uint32_t layer_stride, + uint32_t format, uint64_t producer_usage, uint64_t consumer_usage); ~IonBuffer(); IonBuffer(IonBuffer&& other); @@ -30,25 +39,36 @@ class IonBuffer { // previous native handle if necessary. Returns 0 on success or a negative // errno code otherwise. If allocation fails the previous native handle is // left intact. - int Alloc(int width, int height, int format, int usage); + int Alloc(uint32_t width, uint32_t height, uint32_t format, uint32_t usage); + int Alloc(uint32_t width, uint32_t height, uint32_t format, + uint64_t producer_usage, uint64_t consumer_usage); // Resets the underlying native handle and parameters, freeing the previous // native handle if necessary. - void Reset(buffer_handle_t handle, int width, int height, int stride, - int format, int usage); + void Reset(buffer_handle_t handle, uint32_t width, uint32_t height, + uint32_t stride, uint32_t format, uint32_t usage); + void Reset(buffer_handle_t handle, uint32_t width, uint32_t height, + uint32_t stride, uint32_t format, uint64_t producer_usage, + uint64_t consumer_usage); // Like Reset but also registers the native handle, which is necessary for // native handles received over IPC. Returns 0 on success or a negative errno // code otherwise. If import fails the previous native handle is left intact. - int Import(buffer_handle_t handle, int width, int height, int stride, - int format, int usage); + int Import(buffer_handle_t handle, uint32_t width, uint32_t height, + uint32_t stride, uint32_t format, uint32_t usage); + int Import(buffer_handle_t handle, uint32_t width, uint32_t height, + uint32_t stride, uint32_t format, uint64_t producer_usage, + uint64_t consumer_usage); // Like Reset but imports a native handle from raw fd and int arrays. Returns // 0 on success or a negative errno code otherwise. If import fails the // previous native handle is left intact. int Import(const int* fd_array, int fd_count, const int* int_array, - int int_count, int width, int height, int stride, int format, - int usage); + int int_count, uint32_t width, uint32_t height, uint32_t stride, + uint32_t format, uint32_t usage); + int Import(const int* fd_array, int fd_count, const int* int_array, + int int_count, uint32_t width, uint32_t height, uint32_t stride, + uint32_t format, uint64_t producer_usage, uint64_t consumer_usage); // Duplicates the native handle underlying |other| and then imports it. This // is useful for creating multiple, independent views of the same Ion/Gralloc @@ -56,8 +76,8 @@ class IonBuffer { // duplication or import fail the previous native handle is left intact. int Duplicate(const IonBuffer* other); - int Lock(int usage, int x, int y, int width, int height, void** address); - int LockYUV(int usage, int x, int y, int width, int height, + int Lock(uint32_t usage, int x, int y, int width, int height, void** address); + int LockYUV(uint32_t usage, int x, int y, int width, int height, struct android_ycbcr* yuv); int Unlock(); @@ -65,19 +85,29 @@ class IonBuffer { buffer_handle_t handle() const { return buffer_.get() ? buffer_->handle : nullptr; } - int width() const { return buffer_.get() ? buffer_->getWidth() : 0; } - int height() const { return buffer_.get() ? buffer_->getHeight() : 0; } - int layer_count() const { + uint32_t width() const { return buffer_.get() ? buffer_->getWidth() : 0; } + uint32_t height() const { return buffer_.get() ? buffer_->getHeight() : 0; } + uint32_t layer_count() const { return buffer_.get() ? buffer_->getLayerCount() : 0; } - int stride() const { return buffer_.get() ? buffer_->getStride() : 0; } - int layer_stride() const { return 0; } - int format() const { return buffer_.get() ? buffer_->getPixelFormat() : 0; } - int usage() const { return buffer_.get() ? buffer_->getUsage() : 0; } + uint32_t stride() const { return buffer_.get() ? buffer_->getStride() : 0; } + uint32_t layer_stride() const { return 0; } + uint32_t format() const { + return buffer_.get() ? buffer_->getPixelFormat() : 0; + } + uint64_t producer_usage() const { return producer_usage_; } + uint64_t consumer_usage() const { return consumer_usage_; } + uint32_t usage() const { return buffer_.get() ? buffer_->getUsage() : 0; } private: sp<GraphicBuffer> buffer_; + // GraphicBuffer doesn't expose these separately. Keep these values cached for + // BufferHub to check policy against. Clients that import these buffers won't + // get the full picture, which is okay. + uint64_t producer_usage_; + uint64_t consumer_usage_; + IonBuffer(const IonBuffer&) = delete; void operator=(const IonBuffer&) = delete; }; diff --git a/libs/vr/libbufferhub/ion_buffer.cpp b/libs/vr/libbufferhub/ion_buffer.cpp index e5a56c1a4b..df9ae81a38 100644 --- a/libs/vr/libbufferhub/ion_buffer.cpp +++ b/libs/vr/libbufferhub/ion_buffer.cpp @@ -6,40 +6,59 @@ #include <mutex> +namespace { + +constexpr uint32_t kDefaultGraphicBufferLayerCount = 1; + +} // anonymous namespace + namespace android { namespace dvr { IonBuffer::IonBuffer() : IonBuffer(nullptr, 0, 0, 0, 0, 0, 0, 0) {} -IonBuffer::IonBuffer(int width, int height, int format, int usage) +IonBuffer::IonBuffer(uint32_t width, uint32_t height, uint32_t format, + uint32_t usage) + : IonBuffer(width, height, format, usage, usage) {} + +IonBuffer::IonBuffer(uint32_t width, uint32_t height, uint32_t format, + uint64_t producer_usage, uint64_t consumer_usage) : IonBuffer() { - Alloc(width, height, format, usage); + Alloc(width, height, format, producer_usage, consumer_usage); } -IonBuffer::IonBuffer(buffer_handle_t handle, int width, int height, int stride, - int format, int usage) +IonBuffer::IonBuffer(buffer_handle_t handle, uint32_t width, uint32_t height, + uint32_t stride, uint32_t format, uint32_t usage) : IonBuffer(handle, width, height, 1, stride, 0, format, usage) {} +IonBuffer::IonBuffer(buffer_handle_t handle, uint32_t width, uint32_t height, + uint32_t layer_count, uint32_t stride, + uint32_t layer_stride, uint32_t format, uint32_t usage) + : IonBuffer(handle, width, height, layer_count, stride, layer_stride, + format, usage, usage) {} -IonBuffer::IonBuffer(buffer_handle_t handle, int width, int height, - int layer_count, int stride, int layer_stride, int format, - int usage) +IonBuffer::IonBuffer(buffer_handle_t handle, uint32_t width, uint32_t height, + uint32_t layer_count, uint32_t stride, + uint32_t layer_stride, uint32_t format, + uint64_t producer_usage, uint64_t consumer_usage) : buffer_(nullptr) { ALOGD_IF(TRACE, - "IonBuffer::IonBuffer: handle=%p width=%d height=%d layer_count=%d " - "stride=%d layer stride=%d format=%d usage=%d", - handle, width, height, layer_count, stride, layer_stride, - format, usage); + "IonBuffer::IonBuffer: handle=%p width=%u height=%u layer_count=%u " + "stride=%u layer stride=%u format=%u producer_usage=%" PRIx64 + " consumer_usage=%" PRIx64, + handle, width, height, layer_count, stride, layer_stride, format, + producer_usage, consumer_usage); if (handle != 0) { - Import(handle, width, height, stride, format, usage); + Import(handle, width, height, stride, format, producer_usage, + consumer_usage); } } IonBuffer::~IonBuffer() { ALOGD_IF(TRACE, - "IonBuffer::~IonBuffer: handle=%p width=%d height=%d stride=%d " - "format=%d usage=%d", - handle() , width(), height(), stride(), format(), usage()); + "IonBuffer::~IonBuffer: handle=%p width=%u height=%u stride=%u " + "format=%u usage=%x", + handle(), width(), height(), stride(), format(), usage()); FreeHandle(); } @@ -62,55 +81,101 @@ void IonBuffer::FreeHandle() { if (buffer_.get()) { // GraphicBuffer unregisters and cleans up the handle if needed buffer_ = nullptr; + producer_usage_ = 0; + consumer_usage_ = 0; } } -int IonBuffer::Alloc(int width, int height, int format, int usage) { - ALOGD_IF(TRACE, "IonBuffer::Alloc: width=%d height=%d format=%d usage=%d", - width, height, format, usage); +int IonBuffer::Alloc(uint32_t width, uint32_t height, uint32_t format, + uint32_t usage) { + return Alloc(width, height, format, usage, usage); +} - buffer_ = new GraphicBuffer(width, height, format, usage); - if (buffer_->initCheck() != OK) { +int IonBuffer::Alloc(uint32_t width, uint32_t height, uint32_t format, + uint64_t producer_usage, uint64_t consumer_usage) { + ALOGD_IF( + TRACE, + "IonBuffer::Alloc: width=%u height=%u format=%u producer_usage=%" PRIx64 + " consumer_usage=%" PRIx64, + width, height, format, producer_usage, consumer_usage); + + sp<GraphicBuffer> buffer = + new GraphicBuffer(width, height, format, kDefaultGraphicBufferLayerCount, + producer_usage, consumer_usage); + if (buffer->initCheck() != OK) { ALOGE("IonBuffer::Aloc: Failed to allocate buffer"); + return -EINVAL; + } else { + buffer_ = buffer; + producer_usage_ = producer_usage; + consumer_usage_ = consumer_usage; + return 0; } - return 0; } -void IonBuffer::Reset(buffer_handle_t handle, int width, int height, int stride, - int format, int usage) { +void IonBuffer::Reset(buffer_handle_t handle, uint32_t width, uint32_t height, + uint32_t stride, uint32_t format, uint32_t usage) { + Reset(handle, width, height, stride, format, usage, usage); +} + +void IonBuffer::Reset(buffer_handle_t handle, uint32_t width, uint32_t height, + uint32_t stride, uint32_t format, uint64_t producer_usage, + uint64_t consumer_usage) { ALOGD_IF(TRACE, - "IonBuffer::Reset: handle=%p width=%d height=%d stride=%d format=%d " - "usage=%d", - handle, width, height, stride, format, usage); - Import(handle, width, height, stride, format, usage); + "IonBuffer::Reset: handle=%p width=%u height=%u stride=%u format=%u " + "producer_usage=%" PRIx64 " consumer_usage=%" PRIx64, + handle, width, height, stride, format, producer_usage, + consumer_usage); + Import(handle, width, height, stride, format, producer_usage, consumer_usage); +} + +int IonBuffer::Import(buffer_handle_t handle, uint32_t width, uint32_t height, + uint32_t stride, uint32_t format, uint32_t usage) { + return Import(handle, width, height, stride, format, usage, usage); } -int IonBuffer::Import(buffer_handle_t handle, int width, int height, int stride, - int format, int usage) { +int IonBuffer::Import(buffer_handle_t handle, uint32_t width, uint32_t height, + uint32_t stride, uint32_t format, uint64_t producer_usage, + uint64_t consumer_usage) { ATRACE_NAME("IonBuffer::Import1"); ALOGD_IF( TRACE, - "IonBuffer::Import: handle=%p width=%d height=%d stride=%d format=%d " - "usage=%d", - handle, width, height, stride, format, usage); + "IonBuffer::Import: handle=%p width=%u height=%u stride=%u format=%u " + "producer_usage=%" PRIx64 " consumer_usage=%" PRIx64, + handle, width, height, stride, format, producer_usage, consumer_usage); FreeHandle(); - buffer_ = new GraphicBuffer(handle, GraphicBuffer::TAKE_UNREGISTERED_HANDLE, - width, height, format, 1, usage, stride); - if (buffer_->initCheck() != OK) { + sp<GraphicBuffer> buffer = new GraphicBuffer( + handle, GraphicBuffer::TAKE_UNREGISTERED_HANDLE, width, height, format, + kDefaultGraphicBufferLayerCount, producer_usage, consumer_usage, stride); + if (buffer->initCheck() != OK) { ALOGE("IonBuffer::Import: Failed to import buffer"); return -EINVAL; + } else { + buffer_ = buffer; + producer_usage_ = producer_usage; + consumer_usage_ = consumer_usage; + return 0; } - return 0; } int IonBuffer::Import(const int* fd_array, int fd_count, const int* int_array, - int int_count, int width, int height, int stride, - int format, int usage) { + int int_count, uint32_t width, uint32_t height, + uint32_t stride, uint32_t format, uint32_t usage) { + return Import(fd_array, fd_count, int_array, int_count, width, height, stride, + format, usage, usage); +} + +int IonBuffer::Import(const int* fd_array, int fd_count, const int* int_array, + int int_count, uint32_t width, uint32_t height, + uint32_t stride, uint32_t format, uint64_t producer_usage, + uint64_t consumer_usage) { ATRACE_NAME("IonBuffer::Import2"); ALOGD_IF(TRACE, - "IonBuffer::Import: fd_count=%d int_count=%d width=%d height=%d " - "stride=%d format=%d usage=%d", - fd_count, int_count, width, height, stride, format, usage); + "IonBuffer::Import: fd_count=%d int_count=%d width=%u height=%u " + "stride=%u format=%u producer_usage=%" PRIx64 + " consumer_usage=%" PRIx64, + fd_count, int_count, width, height, stride, format, producer_usage, + consumer_usage); if (fd_count < 0 || int_count < 0) { ALOGE("IonBuffer::Import: invalid arguments."); @@ -128,7 +193,8 @@ int IonBuffer::Import(const int* fd_array, int fd_count, const int* int_array, memcpy(handle->data, fd_array, sizeof(int) * fd_count); memcpy(handle->data + fd_count, int_array, sizeof(int) * int_count); - int ret = Import(handle, width, height, stride, format, usage); + const int ret = Import(handle, width, height, stride, format, producer_usage, + consumer_usage); if (ret < 0) { ALOGE("IonBuffer::Import: failed to import raw native handle: %s", strerror(-ret)); @@ -163,8 +229,9 @@ int IonBuffer::Duplicate(const IonBuffer* other) { memcpy(handle->data + fd_count, other->handle()->data + fd_count, sizeof(int) * int_count); - const int ret = Import(handle, other->width(), other->height(), - other->stride(), other->format(), other->usage()); + const int ret = + Import(handle, other->width(), other->height(), other->stride(), + other->format(), other->producer_usage(), other->consumer_usage()); if (ret < 0) { ALOGE("IonBuffer::Duplicate: Failed to import duplicate native handle: %s", strerror(-ret)); @@ -175,7 +242,7 @@ int IonBuffer::Duplicate(const IonBuffer* other) { return ret; } -int IonBuffer::Lock(int usage, int x, int y, int width, int height, +int IonBuffer::Lock(uint32_t usage, int x, int y, int width, int height, void** address) { ATRACE_NAME("IonBuffer::Lock"); ALOGD_IF(TRACE, @@ -183,23 +250,23 @@ int IonBuffer::Lock(int usage, int x, int y, int width, int height, "address=%p", handle(), usage, x, y, width, height, address); - status_t err = buffer_->lock(usage, Rect(x, y, x + width, y + height), - address); + status_t err = + buffer_->lock(usage, Rect(x, y, x + width, y + height), address); if (err != NO_ERROR) return -EINVAL; else return 0; } -int IonBuffer::LockYUV(int usage, int x, int y, int width, int height, +int IonBuffer::LockYUV(uint32_t usage, int x, int y, int width, int height, struct android_ycbcr* yuv) { ATRACE_NAME("IonBuffer::LockYUV"); ALOGD_IF(TRACE, "IonBuffer::Lock: handle=%p usage=%d x=%d y=%d width=%d height=%d", handle(), usage, x, y, width, height); - status_t err = buffer_->lockYCbCr(usage, Rect(x, y, x + width, y + height), - yuv); + status_t err = + buffer_->lockYCbCr(usage, Rect(x, y, x + width, y + height), yuv); if (err != NO_ERROR) return -EINVAL; else @@ -216,5 +283,5 @@ int IonBuffer::Unlock() { else return 0; } -} // namespace dvr -} // namespace android +} // namespace dvr +} // namespace android diff --git a/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp b/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp index e491abcd52..b431d2f345 100644 --- a/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp +++ b/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp @@ -317,7 +317,7 @@ std::shared_ptr<BufferHubBuffer> BufferHubQueue::Dequeue(int timeout, } ProducerQueue::ProducerQueue(size_t meta_size) - : ProducerQueue(meta_size, 0, 0, 0, 0) {} + : ProducerQueue(meta_size, 0, 0, 0, 0, 0, 0, 0, 0) {} ProducerQueue::ProducerQueue(LocalChannelHandle handle) : BASE(std::move(handle)) { @@ -329,13 +329,22 @@ ProducerQueue::ProducerQueue(LocalChannelHandle handle) } } -ProducerQueue::ProducerQueue(size_t meta_size, int usage_set_mask, - int usage_clear_mask, int usage_deny_set_mask, - int usage_deny_clear_mask) +ProducerQueue::ProducerQueue(size_t meta_size, uint64_t producer_usage_set_mask, + uint64_t producer_usage_clear_mask, + uint64_t producer_usage_deny_set_mask, + uint64_t producer_usage_deny_clear_mask, + uint64_t consumer_usage_set_mask, + uint64_t consumer_usage_clear_mask, + uint64_t consumer_usage_deny_set_mask, + uint64_t consumer_usage_deny_clear_mask) : BASE(BufferHubRPC::kClientPath) { auto status = InvokeRemoteMethod<BufferHubRPC::CreateProducerQueue>( - meta_size, usage_set_mask, usage_clear_mask, usage_deny_set_mask, - usage_deny_clear_mask); + meta_size, + UsagePolicy{producer_usage_set_mask, producer_usage_clear_mask, + producer_usage_deny_set_mask, producer_usage_deny_clear_mask, + consumer_usage_set_mask, consumer_usage_clear_mask, + consumer_usage_deny_set_mask, + consumer_usage_deny_clear_mask}); if (!status) { ALOGE("ProducerQueue::ProducerQueue: Failed to create producer queue: %s", status.GetErrorMessage().c_str()); @@ -346,8 +355,17 @@ ProducerQueue::ProducerQueue(size_t meta_size, int usage_set_mask, SetupQueue(status.get().meta_size_bytes, status.get().id); } -int ProducerQueue::AllocateBuffer(int width, int height, int format, int usage, +int ProducerQueue::AllocateBuffer(uint32_t width, uint32_t height, + uint32_t format, uint32_t usage, size_t slice_count, size_t* out_slot) { + return AllocateBuffer(width, height, format, usage, usage, slice_count, + out_slot); +} + +int ProducerQueue::AllocateBuffer(uint32_t width, uint32_t height, + uint32_t format, uint64_t producer_usage, + uint64_t consumer_usage, size_t slice_count, + size_t* out_slot) { if (out_slot == nullptr) { ALOGE("ProducerQueue::AllocateBuffer: Parameter out_slot cannot be null."); return -EINVAL; @@ -363,7 +381,8 @@ int ProducerQueue::AllocateBuffer(int width, int height, int format, int usage, Status<std::vector<std::pair<LocalChannelHandle, size_t>>> status = InvokeRemoteMethod<BufferHubRPC::ProducerQueueAllocateBuffers>( - width, height, format, usage, slice_count, kBufferCount); + width, height, format, producer_usage, consumer_usage, slice_count, + kBufferCount); if (!status) { ALOGE( "ProducerQueue::AllocateBuffer failed to create producer buffer " diff --git a/libs/vr/libbufferhubqueue/buffer_hub_queue_producer.cpp b/libs/vr/libbufferhubqueue/buffer_hub_queue_producer.cpp index 3fe76426fd..ebd7da090a 100644 --- a/libs/vr/libbufferhubqueue/buffer_hub_queue_producer.cpp +++ b/libs/vr/libbufferhubqueue/buffer_hub_queue_producer.cpp @@ -38,22 +38,8 @@ status_t BufferHubQueueProducer::requestBuffer(int slot, } const auto& buffer_producer = core_->buffers_[slot].mBufferProducer; + sp<GraphicBuffer> graphic_buffer = buffer_producer->buffer()->buffer(); - // Create new GraphicBuffer based on the newly created |buffer_producer|. Here - // we have to cast |buffer_handle_t| to |native_handle_t|, it's OK because - // internally, GraphicBuffer is still an |ANativeWindowBuffer| and |handle| - // is still type of |buffer_handle_t| and bears const property. - sp<GraphicBuffer> graphic_buffer(new GraphicBuffer( - buffer_producer->width(), buffer_producer->height(), - buffer_producer->format(), - 1, /* layer count */ - buffer_producer->usage(), - buffer_producer->stride(), - const_cast<native_handle_t*>(buffer_producer->buffer()->handle()), - false)); - - LOG_ALWAYS_FATAL_IF(NO_ERROR != graphic_buffer->initCheck(), - "Failed to init GraphicBuffer."); core_->buffers_[slot].mGraphicBuffer = graphic_buffer; core_->buffers_[slot].mRequestBufferCalled = true; @@ -155,9 +141,9 @@ status_t BufferHubQueueProducer::dequeueBuffer( if (!buffer_producer) return NO_MEMORY; - if (static_cast<int>(width) == buffer_producer->width() && - static_cast<int>(height) == buffer_producer->height() && - static_cast<int>(format) == buffer_producer->format()) { + if (width == buffer_producer->width() && + height == buffer_producer->height() && + static_cast<uint32_t>(format) == buffer_producer->format()) { // The producer queue returns a buffer producer matches the request. break; } @@ -165,8 +151,8 @@ status_t BufferHubQueueProducer::dequeueBuffer( // Needs reallocation. // TODO(jwcai) Consider use VLOG instead if we find this log is not useful. ALOGI( - "dequeueBuffer: requested buffer (w=%u, h=%u, format=%d) is different " - "from the buffer returned at slot: %zu (w=%d, h=%d, format=%d). Need " + "dequeueBuffer: requested buffer (w=%u, h=%u, format=%u) is different " + "from the buffer returned at slot: %zu (w=%u, h=%u, format=%u). Need " "re-allocattion.", width, height, format, slot, buffer_producer->width(), buffer_producer->height(), buffer_producer->format()); @@ -322,7 +308,7 @@ status_t BufferHubQueueProducer::queueBuffer(int slot, output->width = buffer_producer->width(); output->height = buffer_producer->height(); - output->transformHint = 0; // default value, we don't use it yet. + output->transformHint = 0; // default value, we don't use it yet. // |numPendingBuffers| counts of the number of buffers that has been enqueued // by the producer but not yet acquired by the consumer. Due to the nature @@ -456,7 +442,7 @@ status_t BufferHubQueueProducer::connect( return NO_ERROR; } -status_t BufferHubQueueProducer::disconnect(int api, DisconnectMode mode) { +status_t BufferHubQueueProducer::disconnect(int api, DisconnectMode /*mode*/) { // Consumer interaction are actually handled by buffer hub, and we need // to maintain consumer operations here. We only need to perform basic input // parameter checks here. diff --git a/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_client.h b/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_client.h index 2b70c5b337..255793ff02 100644 --- a/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_client.h +++ b/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_client.h @@ -274,12 +274,27 @@ class ProducerQueue : public pdx::ClientBase<ProducerQueue, BufferHubQueue> { // |usage_deny_clear_mask| shall not conflict with each other. Such // configuration will be treated as invalid input on creation. template <typename Meta> - static std::unique_ptr<ProducerQueue> Create(int usage_set_mask, - int usage_clear_mask, - int usage_deny_set_mask, - int usage_deny_clear_mask) { + static std::unique_ptr<ProducerQueue> Create(uint32_t usage_set_mask, + uint32_t usage_clear_mask, + uint32_t usage_deny_set_mask, + uint32_t usage_deny_clear_mask) { return BASE::Create(sizeof(Meta), usage_set_mask, usage_clear_mask, - usage_deny_set_mask, usage_deny_clear_mask); + usage_deny_set_mask, usage_deny_clear_mask, + usage_set_mask, usage_clear_mask, usage_deny_set_mask, + usage_deny_clear_mask); + } + template <typename Meta> + static std::unique_ptr<ProducerQueue> Create( + uint64_t producer_usage_set_mask, uint64_t producer_usage_clear_mask, + uint64_t producer_usage_deny_set_mask, + uint64_t producer_usage_deny_clear_mask, uint64_t consumer_usage_set_mask, + uint64_t consumer_usage_clear_mask, uint64_t consumer_usage_deny_set_mask, + uint64_t consumer_usage_deny_clear_mask) { + return BASE::Create(sizeof(Meta), producer_usage_set_mask, + producer_usage_clear_mask, producer_usage_deny_set_mask, + producer_usage_deny_clear_mask, consumer_usage_set_mask, + consumer_usage_clear_mask, consumer_usage_deny_set_mask, + consumer_usage_deny_clear_mask); } // Import a |ProducerQueue| from a channel handle. @@ -301,7 +316,10 @@ class ProducerQueue : public pdx::ClientBase<ProducerQueue, BufferHubQueue> { // use (i.e. in |Gain|'ed mode). // Returns Zero on success and negative error code when buffer allocation // fails. - int AllocateBuffer(int width, int height, int format, int usage, + int AllocateBuffer(uint32_t width, uint32_t height, uint32_t format, + uint32_t usage, size_t slice_count, size_t* out_slot); + int AllocateBuffer(uint32_t width, uint32_t height, uint32_t format, + uint64_t producer_usage, uint64_t consumer_usage, size_t slice_count, size_t* out_slot); // Add a producer buffer to populate the queue. Once added, a producer buffer @@ -327,8 +345,14 @@ class ProducerQueue : public pdx::ClientBase<ProducerQueue, BufferHubQueue> { // arguments as the constructors. explicit ProducerQueue(size_t meta_size); ProducerQueue(LocalChannelHandle handle); - ProducerQueue(size_t meta_size, int usage_set_mask, int usage_clear_mask, - int usage_deny_set_mask, int usage_deny_clear_mask); + ProducerQueue(size_t meta_size, uint64_t producer_usage_set_mask, + uint64_t producer_usage_clear_mask, + uint64_t producer_usage_deny_set_mask, + uint64_t producer_usage_deny_clear_mask, + uint64_t consumer_usage_set_mask, + uint64_t consumer_usage_clear_mask, + uint64_t consumer_usage_deny_set_mask, + uint64_t consumer_usage_deny_clear_mask); int OnBufferReady(std::shared_ptr<BufferHubBuffer> buf, LocalHandle* release_fence) override; diff --git a/libs/vr/libdisplay/display_client.cpp b/libs/vr/libdisplay/display_client.cpp index 6d39cdb8c5..ef50a0fe75 100644 --- a/libs/vr/libdisplay/display_client.cpp +++ b/libs/vr/libdisplay/display_client.cpp @@ -216,7 +216,8 @@ int DisplayClient::GetDisplayMetrics(SystemDisplayMetrics* metrics) { return 0; } -pdx::Status<void> DisplayClient::SetViewerParams(const ViewerParams& viewer_params) { +pdx::Status<void> DisplayClient::SetViewerParams( + const ViewerParams& viewer_params) { auto status = InvokeRemoteMethod<DisplayRPC::SetViewerParams>(viewer_params); if (!status) { ALOGE("DisplayClient::SetViewerParams: Failed to set viewer params: %s", @@ -252,16 +253,20 @@ std::unique_ptr<DisplaySurfaceClient> DisplayClient::CreateDisplaySurface( return DisplaySurfaceClient::Create(width, height, format, usage, flags); } -std::unique_ptr<BufferConsumer> DisplayClient::GetPoseBuffer() { - auto status = InvokeRemoteMethod<DisplayRPC::GetPoseBuffer>(); +std::unique_ptr<IonBuffer> DisplayClient::GetNamedBuffer( + const std::string& name) { + auto status = InvokeRemoteMethod<DisplayRPC::GetNamedBuffer>(name); if (!status) { ALOGE( - "DisplayClient::GetPoseBuffer: Failed to get pose buffer %s", - status.GetErrorMessage().c_str()); + "DisplayClient::GetNamedBuffer: Failed to get pose buffer. name=%s, " + "error=%s", + name.c_str(), status.GetErrorMessage().c_str()); return nullptr; } - return BufferConsumer::Import(std::move(status)); + auto ion_buffer = std::make_unique<IonBuffer>(); + status.take().Import(ion_buffer.get()); + return ion_buffer; } bool DisplayClient::IsVrAppRunning() { diff --git a/libs/vr/libdisplay/display_manager_client_impl.cpp b/libs/vr/libdisplay/display_manager_client_impl.cpp index 7993fce219..44b3c4b02e 100644 --- a/libs/vr/libdisplay/display_manager_client_impl.cpp +++ b/libs/vr/libdisplay/display_manager_client_impl.cpp @@ -31,19 +31,22 @@ int DisplayManagerClient::GetSurfaceList( return 0; } -std::unique_ptr<BufferProducer> DisplayManagerClient::SetupPoseBuffer( - size_t extended_region_size, int usage) { - auto status = InvokeRemoteMethod<DisplayManagerRPC::SetupPoseBuffer>( - extended_region_size, usage); +std::unique_ptr<IonBuffer> DisplayManagerClient::SetupNamedBuffer( + const std::string& name, size_t size, uint64_t producer_usage, + uint64_t consumer_usage) { + auto status = InvokeRemoteMethod<DisplayManagerRPC::SetupNamedBuffer>( + name, size, producer_usage, consumer_usage); if (!status) { ALOGE( - "DisplayManagerClient::SetupPoseBuffer: Failed to create the pose " - "buffer %s", - status.GetErrorMessage().c_str()); + "DisplayManagerClient::SetupNamedBuffer: Failed to create the named " + "buffer: name=%s, error=%s", + name.c_str(), status.GetErrorMessage().c_str()); return {}; } - return BufferProducer::Import(std::move(status)); + auto ion_buffer = std::make_unique<IonBuffer>(); + status.take().Import(ion_buffer.get()); + return ion_buffer; } } // namespace dvr diff --git a/libs/vr/libdisplay/include/private/dvr/display_client.h b/libs/vr/libdisplay/include/private/dvr/display_client.h index 378f67c70b..fec2ea5445 100644 --- a/libs/vr/libdisplay/include/private/dvr/display_client.h +++ b/libs/vr/libdisplay/include/private/dvr/display_client.h @@ -108,7 +108,7 @@ class DisplayClient : public pdx::ClientBase<DisplayClient> { std::unique_ptr<DisplaySurfaceClient> CreateDisplaySurface( int width, int height, int format, int usage, int flags); - std::unique_ptr<BufferConsumer> GetPoseBuffer(); + std::unique_ptr<IonBuffer> GetNamedBuffer(const std::string& name); // Temporary query for current VR status. Will be removed later. bool IsVrAppRunning(); diff --git a/libs/vr/libdisplay/include/private/dvr/display_manager_client_impl.h b/libs/vr/libdisplay/include/private/dvr/display_manager_client_impl.h index 144cd3baa4..b0a7d1382b 100644 --- a/libs/vr/libdisplay/include/private/dvr/display_manager_client_impl.h +++ b/libs/vr/libdisplay/include/private/dvr/display_manager_client_impl.h @@ -17,8 +17,10 @@ class DisplayManagerClient : public pdx::ClientBase<DisplayManagerClient> { int GetSurfaceList(std::vector<DisplaySurfaceInfo>* surface_list); - std::unique_ptr<BufferProducer> SetupPoseBuffer(size_t extended_region_size, - int usage); + std::unique_ptr<IonBuffer> SetupNamedBuffer(const std::string& name, + size_t size, + uint64_t producer_usage, + uint64_t consumer_usage); using Client::event_fd; using Client::GetChannel; diff --git a/libs/vr/libdisplay/include/private/dvr/display_rpc.h b/libs/vr/libdisplay/include/private/dvr/display_rpc.h index ac086503ff..c12b090d57 100644 --- a/libs/vr/libdisplay/include/private/dvr/display_rpc.h +++ b/libs/vr/libdisplay/include/private/dvr/display_rpc.h @@ -9,6 +9,7 @@ #include <pdx/rpc/remote_method.h> #include <pdx/rpc/serializable.h> #include <pdx/rpc/variant.h> +#include <private/dvr/bufferhub_rpc.h> #include <private/dvr/display_types.h> namespace android { @@ -218,7 +219,7 @@ struct DisplayRPC { kOpCreateVideoMeshSurface, kOpVideoMeshSurfaceCreateProducerQueue, kOpSetViewerParams, - kOpGetPoseBuffer, + kOpGetNamedBuffer, kOpIsVrAppRunning, }; @@ -247,8 +248,8 @@ struct DisplayRPC { LocalChannelHandle(Void)); PDX_REMOTE_METHOD(SetViewerParams, kOpSetViewerParams, void(const ViewerParams& viewer_params)); - PDX_REMOTE_METHOD(GetPoseBuffer, kOpGetPoseBuffer, - LocalChannelHandle(Void)); + PDX_REMOTE_METHOD(GetNamedBuffer, kOpGetNamedBuffer, + LocalNativeBufferHandle(const std::string& name)); PDX_REMOTE_METHOD(IsVrAppRunning, kOpIsVrAppRunning, int(Void)); }; @@ -260,7 +261,7 @@ struct DisplayManagerRPC { enum { kOpGetSurfaceList = 0, kOpUpdateSurfaces, - kOpSetupPoseBuffer, + kOpSetupNamedBuffer, }; // Aliases. @@ -273,8 +274,11 @@ struct DisplayManagerRPC { PDX_REMOTE_METHOD( UpdateSurfaces, kOpUpdateSurfaces, int(const std::map<int, DisplaySurfaceAttributes>& updates)); - PDX_REMOTE_METHOD(SetupPoseBuffer, kOpSetupPoseBuffer, - LocalChannelHandle(size_t extended_region_size, int usage)); + PDX_REMOTE_METHOD(SetupNamedBuffer, kOpSetupNamedBuffer, + LocalNativeBufferHandle(const std::string& name, + size_t size, + uint64_t producer_usage, + uint64_t consumer_usage)); }; struct ScreenshotData { diff --git a/libs/vr/libdvr/display_manager_client.cpp b/libs/vr/libdvr/display_manager_client.cpp index 7cbfc21fd8..8d84f7b1eb 100644 --- a/libs/vr/libdvr/display_manager_client.cpp +++ b/libs/vr/libdvr/display_manager_client.cpp @@ -42,14 +42,16 @@ void dvrDisplayManagerClientDestroy(DvrDisplayManagerClient* client) { delete client; } -DvrWriteBuffer* dvrDisplayManagerSetupPoseBuffer( - DvrDisplayManagerClient* client, size_t extended_region_size, - uint64_t usage0, uint64_t usage1) { - // TODO(hendrikw): When we move to gralloc1, pass both usage0 and usage1 down. - auto buffer_producer = client->client->SetupPoseBuffer( - extended_region_size, static_cast<int>(usage0)); - if (buffer_producer) { - return CreateDvrWriteBufferFromBufferProducer(std::move(buffer_producer)); +DvrBuffer* dvrDisplayManagerSetupNamedBuffer(DvrDisplayManagerClient* client, + const char* name, size_t size, + uint64_t producer_usage, + uint64_t consumer_usage) { + // TODO(hendrikw): When we move to gralloc1, pass both producer_usage and + // consumer_usage down. + auto ion_buffer = client->client->SetupNamedBuffer(name, size, producer_usage, + consumer_usage); + if (ion_buffer) { + return CreateDvrBufferFromIonBuffer(std::move(ion_buffer)); } return nullptr; } @@ -109,8 +111,8 @@ bool dvrDisplayManagerClientSurfaceListGetClientIsVisible( } int dvrDisplayManagerClientGetSurfaceBuffers( - DvrDisplayManagerClient* client, int surface_id, - DvrDisplayManagerClientSurfaceBuffers** surface_buffers) { + DvrDisplayManagerClient* /* client */, int /* surface_id */, + DvrDisplayManagerClientSurfaceBuffers** /* surface_buffers */) { // TODO(jwcai, hendrikw) Remove this after we replacing // dvrDisplayManagerClientGetSurfaceBuffers is dvr_api. return -1; diff --git a/libs/vr/libdvr/dvr_api.cpp b/libs/vr/libdvr/dvr_api.cpp index 49702fdd29..b91de8fe22 100644 --- a/libs/vr/libdvr/dvr_api.cpp +++ b/libs/vr/libdvr/dvr_api.cpp @@ -31,8 +31,8 @@ DVR_EXPORT int dvrGetApi(void* api, size_t struct_size, int version) { dvrDisplayManagerClientGetSurfaceList; dvr_api->display_manager_client_surface_list_destroy = dvrDisplayManagerClientSurfaceListDestroy; - dvr_api->display_manager_setup_pose_buffer = - dvrDisplayManagerSetupPoseBuffer; + dvr_api->display_manager_setup_named_buffer = + dvrDisplayManagerSetupNamedBuffer; dvr_api->display_manager_client_surface_list_get_size = dvrDisplayManagerClientSurfaceListGetSize; dvr_api->display_manager_client_surface_list_get_surface_id = @@ -48,7 +48,6 @@ DVR_EXPORT int dvrGetApi(void* api, size_t struct_size, int version) { // dvr_buffer.h dvr_api->write_buffer_destroy = dvrWriteBufferDestroy; - dvr_api->write_buffer_get_blob_fds = dvrWriteBufferGetBlobFds; dvr_api->write_buffer_get_ahardwarebuffer = dvrWriteBufferGetAHardwareBuffer; dvr_api->write_buffer_post = dvrWriteBufferPost; @@ -56,11 +55,12 @@ DVR_EXPORT int dvrGetApi(void* api, size_t struct_size, int version) { dvr_api->write_buffer_gain_async = dvrWriteBufferGainAsync; dvr_api->read_buffer_destroy = dvrReadBufferDestroy; - dvr_api->read_buffer_get_blob_fds = dvrReadBufferGetBlobFds; dvr_api->read_buffer_get_ahardwarebuffer = dvrReadBufferGetAHardwareBuffer; dvr_api->read_buffer_acquire = dvrReadBufferAcquire; dvr_api->read_buffer_release = dvrReadBufferRelease; dvr_api->read_buffer_release_async = dvrReadBufferReleaseAsync; + dvr_api->buffer_destroy = dvrBufferDestroy; + dvr_api->buffer_get_ahardwarebuffer = dvrBufferGetAHardwareBuffer; // dvr_buffer_queue.h dvr_api->write_buffer_queue_destroy = dvrWriteBufferQueueDestroy; @@ -77,7 +77,7 @@ DVR_EXPORT int dvrGetApi(void* api, size_t struct_size, int version) { dvr_api->read_buffer_queue_dequeue = dvrReadBufferQueueDequeue; // dvr_surface.h - dvr_api->get_pose_buffer = dvrGetPoseBuffer; + dvr_api->get_named_buffer = dvrGetNamedBuffer; dvr_api->surface_create = dvrSurfaceCreate; dvr_api->surface_get_write_buffer_queue = dvrSurfaceGetWriteBufferQueue; diff --git a/libs/vr/libdvr/dvr_buffer.cpp b/libs/vr/libdvr/dvr_buffer.cpp index 25128a653f..0942b3dbb4 100644 --- a/libs/vr/libdvr/dvr_buffer.cpp +++ b/libs/vr/libdvr/dvr_buffer.cpp @@ -6,13 +6,15 @@ using namespace android; struct DvrWriteBuffer { - std::shared_ptr<dvr::BufferProducer> write_buffer_; - sp<GraphicBuffer> graphic_buffer_; + std::shared_ptr<dvr::BufferProducer> write_buffer; }; struct DvrReadBuffer { - std::shared_ptr<dvr::BufferConsumer> read_buffer_; - sp<GraphicBuffer> graphic_buffer_; + std::shared_ptr<dvr::BufferConsumer> read_buffer; +}; + +struct DvrBuffer { + std::shared_ptr<dvr::IonBuffer> buffer; }; namespace android { @@ -20,16 +22,23 @@ namespace dvr { DvrWriteBuffer* CreateDvrWriteBufferFromBufferProducer( const std::shared_ptr<dvr::BufferProducer>& buffer_producer) { - DvrWriteBuffer* write_buffer = new DvrWriteBuffer; - write_buffer->write_buffer_ = std::move(buffer_producer); - return write_buffer; + if (!buffer_producer) + return nullptr; + return new DvrWriteBuffer{std::move(buffer_producer)}; } DvrReadBuffer* CreateDvrReadBufferFromBufferConsumer( const std::shared_ptr<dvr::BufferConsumer>& buffer_consumer) { - DvrReadBuffer* read_buffer = new DvrReadBuffer; - read_buffer->read_buffer_ = std::move(buffer_consumer); - return read_buffer; + if (!buffer_consumer) + return nullptr; + return new DvrReadBuffer{std::move(buffer_consumer)}; +} + +DvrBuffer* CreateDvrBufferFromIonBuffer( + const std::shared_ptr<IonBuffer>& ion_buffer) { + if (!ion_buffer) + return nullptr; + return new DvrBuffer{std::move(ion_buffer)}; } } // namespace dvr @@ -49,79 +58,82 @@ void InitializeGraphicBuffer(const dvr::BufferHubBuffer* buffer, extern "C" { -void dvrWriteBufferDestroy(DvrWriteBuffer* client) { delete client; } +void dvrWriteBufferDestroy(DvrWriteBuffer* write_buffer) { + delete write_buffer; +} -void dvrWriteBufferGetBlobFds(DvrWriteBuffer* client, int* fds, - size_t* fds_count, size_t max_fds_count) { - client->write_buffer_->GetBlobFds(fds, fds_count, max_fds_count); +int dvrWriteBufferGetId(DvrWriteBuffer* write_buffer) { + return write_buffer->write_buffer->id(); } -int dvrWriteBufferGetAHardwareBuffer(DvrWriteBuffer* client, +int dvrWriteBufferGetAHardwareBuffer(DvrWriteBuffer* write_buffer, AHardwareBuffer** hardware_buffer) { - if (!client->graphic_buffer_.get()) { - InitializeGraphicBuffer(client->write_buffer_.get(), - &client->graphic_buffer_); - } - *hardware_buffer = - reinterpret_cast<AHardwareBuffer*>(client->graphic_buffer_.get()); + *hardware_buffer = reinterpret_cast<AHardwareBuffer*>( + write_buffer->write_buffer->buffer()->buffer().get()); return 0; } -int dvrWriteBufferPost(DvrWriteBuffer* client, int ready_fence_fd, +int dvrWriteBufferPost(DvrWriteBuffer* write_buffer, int ready_fence_fd, const void* meta, size_t meta_size_bytes) { pdx::LocalHandle fence(ready_fence_fd); - int result = client->write_buffer_->Post(fence, meta, meta_size_bytes); - fence.Release(); + int result = write_buffer->write_buffer->Post(fence, meta, meta_size_bytes); return result; } -int dvrWriteBufferGain(DvrWriteBuffer* client, int* release_fence_fd) { +int dvrWriteBufferGain(DvrWriteBuffer* write_buffer, int* release_fence_fd) { pdx::LocalHandle release_fence; - int result = client->write_buffer_->Gain(&release_fence); + int result = write_buffer->write_buffer->Gain(&release_fence); *release_fence_fd = release_fence.Release(); return result; } -int dvrWriteBufferGainAsync(DvrWriteBuffer* client) { - return client->write_buffer_->GainAsync(); +int dvrWriteBufferGainAsync(DvrWriteBuffer* write_buffer) { + return write_buffer->write_buffer->GainAsync(); } -void dvrReadBufferDestroy(DvrReadBuffer* client) { delete client; } +void dvrReadBufferDestroy(DvrReadBuffer* read_buffer) { delete read_buffer; } -void dvrReadBufferGetBlobFds(DvrReadBuffer* client, int* fds, size_t* fds_count, - size_t max_fds_count) { - client->read_buffer_->GetBlobFds(fds, fds_count, max_fds_count); +int dvrReadBufferGetId(DvrReadBuffer* read_buffer) { + return read_buffer->read_buffer->id(); } -int dvrReadBufferGetAHardwareBuffer(DvrReadBuffer* client, +int dvrReadBufferGetAHardwareBuffer(DvrReadBuffer* read_buffer, AHardwareBuffer** hardware_buffer) { - if (!client->graphic_buffer_.get()) { - InitializeGraphicBuffer(client->read_buffer_.get(), - &client->graphic_buffer_); - } - *hardware_buffer = - reinterpret_cast<AHardwareBuffer*>(client->graphic_buffer_.get()); + *hardware_buffer = reinterpret_cast<AHardwareBuffer*>( + read_buffer->read_buffer->buffer()->buffer().get()); return 0; } -int dvrReadBufferAcquire(DvrReadBuffer* client, int* ready_fence_fd, void* meta, - size_t meta_size_bytes) { +int dvrReadBufferAcquire(DvrReadBuffer* read_buffer, int* ready_fence_fd, + void* meta, size_t meta_size_bytes) { pdx::LocalHandle ready_fence; int result = - client->read_buffer_->Acquire(&ready_fence, meta, meta_size_bytes); + read_buffer->read_buffer->Acquire(&ready_fence, meta, meta_size_bytes); *ready_fence_fd = ready_fence.Release(); return result; } -int dvrReadBufferRelease(DvrReadBuffer* client, int release_fence_fd) { +int dvrReadBufferRelease(DvrReadBuffer* read_buffer, int release_fence_fd) { pdx::LocalHandle fence(release_fence_fd); - int result = client->read_buffer_->Release(fence); - fence.Release(); + int result = read_buffer->read_buffer->Release(fence); return result; } -int dvrReadBufferReleaseAsync(DvrReadBuffer* client) { - return client->read_buffer_->ReleaseAsync(); +int dvrReadBufferReleaseAsync(DvrReadBuffer* read_buffer) { + return read_buffer->read_buffer->ReleaseAsync(); +} + +void dvrBufferDestroy(DvrBuffer* buffer) { delete buffer; } + +int dvrBufferGetAHardwareBuffer(DvrBuffer* buffer, + AHardwareBuffer** hardware_buffer) { + if (!hardware_buffer) { + return -EINVAL; + } + + *hardware_buffer = + reinterpret_cast<AHardwareBuffer*>(buffer->buffer->buffer().get()); + return 0; } } // extern "C" diff --git a/libs/vr/libdvr/dvr_surface.cpp b/libs/vr/libdvr/dvr_surface.cpp index a3cbba573f..a04ed50f5f 100644 --- a/libs/vr/libdvr/dvr_surface.cpp +++ b/libs/vr/libdvr/dvr_surface.cpp @@ -58,14 +58,25 @@ int dvrSurfaceGetWriteBufferQueue(DvrSurface* surface, return 0; } -int dvrGetPoseBuffer(DvrReadBuffer** pose_buffer) { +int dvrGetNamedBuffer(const char* name, DvrBuffer** out_buffer) { auto client = android::dvr::DisplayClient::Create(); if (!client) { - ALOGE("Failed to create display client!"); + ALOGE("dvrGetNamedBuffer: Failed to create display client!"); return -ECOMM; } - *pose_buffer = CreateDvrReadBufferFromBufferConsumer(client->GetPoseBuffer()); + if (out_buffer == nullptr || name == nullptr) { + ALOGE("dvrGetNamedBuffer: Invalid inputs: name=%p, out_buffer=%p.", name, + out_buffer); + return -EINVAL; + } + + auto named_buffer = client->GetNamedBuffer(name); + if (!named_buffer) { + ALOGE("dvrGetNamedBuffer: Failed to find named buffer: %s.", name); + return -EINVAL; + } + *out_buffer = CreateDvrBufferFromIonBuffer(std::move(named_buffer)); return 0; } diff --git a/libs/vr/libdvr/include/dvr/display_manager_client.h b/libs/vr/libdvr/include/dvr/display_manager_client.h index 0928d4353c..4e1f227b96 100644 --- a/libs/vr/libdvr/include/dvr/display_manager_client.h +++ b/libs/vr/libdvr/include/dvr/display_manager_client.h @@ -14,15 +14,16 @@ typedef struct DvrDisplayManagerClientSurfaceList DvrDisplayManagerClientSurfaceList; typedef struct DvrDisplayManagerClientSurfaceBuffers DvrDisplayManagerClientSurfaceBuffers; -typedef struct DvrWriteBuffer DvrWriteBuffer; +typedef struct DvrBuffer DvrBuffer; DvrDisplayManagerClient* dvrDisplayManagerClientCreate(); void dvrDisplayManagerClientDestroy(DvrDisplayManagerClient* client); -DvrWriteBuffer* dvrDisplayManagerSetupPoseBuffer( - DvrDisplayManagerClient* client, size_t extended_region_size, - uint64_t usage0, uint64_t usage1); +DvrBuffer* dvrDisplayManagerSetupNamedBuffer(DvrDisplayManagerClient* client, + const char* name, size_t size, + uint64_t producer_usage, + uint64_t consumer_usage); // Return an event fd for checking if there was an event on the server // Note that the only event which will be flagged is POLLIN. You must use diff --git a/libs/vr/libdvr/include/dvr/dvr_api.h b/libs/vr/libdvr/include/dvr/dvr_api.h index a4fef190d5..c46684bb4d 100644 --- a/libs/vr/libdvr/include/dvr/dvr_api.h +++ b/libs/vr/libdvr/include/dvr/dvr_api.h @@ -30,6 +30,7 @@ typedef void (*DvrDisplayManagerClientDestroyPtr)( typedef struct DvrWriteBuffer DvrWriteBuffer; typedef struct DvrReadBuffer DvrReadBuffer; +typedef struct DvrBuffer DvrBuffer; typedef struct AHardwareBuffer AHardwareBuffer; typedef struct DvrWriteBufferQueue DvrWriteBufferQueue; @@ -43,9 +44,9 @@ typedef int (*DvrDisplayManagerClientGetSurfaceListPtr)( DvrDisplayManagerClientSurfaceList** surface_list); typedef void (*DvrDisplayManagerClientSurfaceListDestroyPtr)( DvrDisplayManagerClientSurfaceList* surface_list); -typedef DvrWriteBuffer* (*DvrDisplayManagerSetupPoseBufferPtr)( - DvrDisplayManagerClient* client, size_t extended_region_size, - uint64_t usage0, uint64_t usage1); +typedef DvrBuffer* (*DvrDisplayManagerSetupNamedBufferPtr)( + DvrDisplayManagerClient* client, const char* name, size_t size, + uint64_t producer_usage, uint64_t consumer_usage); typedef size_t (*DvrDisplayManagerClientSurfaceListGetSizePtr)( DvrDisplayManagerClientSurfaceList* surface_list); typedef int (*DvrDisplayManagerClientSurfaceListGetSurfaceIdPtr)( @@ -62,9 +63,6 @@ typedef int (*DvrDisplayManagerClientSurfaceBufferListGetFdPtr)( // dvr_buffer.h typedef void (*DvrWriteBufferDestroyPtr)(DvrWriteBuffer* client); -typedef void (*DvrWriteBufferGetBlobFdsPtr)(DvrWriteBuffer* client, int* fds, - size_t* fds_count, - size_t max_fds_count); typedef int (*DvrWriteBufferGetAHardwareBufferPtr)( DvrWriteBuffer* client, AHardwareBuffer** hardware_buffer); typedef int (*DvrWriteBufferPostPtr)(DvrWriteBuffer* client, int ready_fence_fd, @@ -74,9 +72,6 @@ typedef int (*DvrWriteBufferGainPtr)(DvrWriteBuffer* client, typedef int (*DvrWriteBufferGainAsyncPtr)(DvrWriteBuffer* client); typedef void (*DvrReadBufferDestroyPtr)(DvrReadBuffer* client); -typedef void (*DvrReadBufferGetBlobFdsPtr)(DvrReadBuffer* client, int* fds, - size_t* fds_count, - size_t max_fds_count); typedef int (*DvrReadBufferGetAHardwareBufferPtr)( DvrReadBuffer* client, AHardwareBuffer** hardware_buffer); typedef int (*DvrReadBufferAcquirePtr)(DvrReadBuffer* client, @@ -85,6 +80,9 @@ typedef int (*DvrReadBufferAcquirePtr)(DvrReadBuffer* client, typedef int (*DvrReadBufferReleasePtr)(DvrReadBuffer* client, int release_fence_fd); typedef int (*DvrReadBufferReleaseAsyncPtr)(DvrReadBuffer* client); +typedef void (*DvrBufferDestroy)(DvrBuffer* buffer); +typedef int (*DvrBufferGetAHardwareBuffer)(DvrBuffer* buffer, + AHardwareBuffer** hardware_buffer); // dvr_buffer_queue.h typedef void (*DvrWriteBufferQueueDestroyPtr)(DvrWriteBufferQueue* write_queue); @@ -110,7 +108,7 @@ typedef int (*DvrReadBufferQueueDequeuePtr)(DvrReadBufferQueue* read_queue, size_t meta_size_bytes); // dvr_surface.h -typedef int (*DvrGetPoseBufferPtr)(DvrReadBuffer** pose_buffer); +typedef int (*DvrGetNamedBufferPtr)(const char* name, DvrBuffer** out_buffer); typedef int (*DvrSurfaceCreatePtr)(int width, int height, int format, uint64_t usage0, uint64_t usage1, int flags, DvrSurface** out_surface); @@ -149,7 +147,7 @@ typedef int (*DvrVirtualTouchpadButtonStatePtr)(DvrVirtualTouchpad* client, // dvr_hardware_composer_client.h typedef struct DvrHwcClient DvrHwcClient; typedef struct DvrHwcFrame DvrHwcFrame; -typedef int(*DvrHwcOnFrameCallback)(void* client_state, DvrHwcFrame* frame); +typedef int (*DvrHwcOnFrameCallback)(void* client_state, DvrHwcFrame* frame); typedef DvrHwcClient* (*DvrHwcClientCreatePtr)(DvrHwcOnFrameCallback callback, void* client_state); typedef void (*DvrHwcClientDestroyPtr)(DvrHwcClient* client); @@ -159,7 +157,8 @@ typedef int32_t (*DvrHwcFrameGetDisplayWidthPtr)(DvrHwcFrame* frame); typedef int32_t (*DvrHwcFrameGetDisplayHeightPtr)(DvrHwcFrame* frame); typedef bool (*DvrHwcFrameGetDisplayRemovedPtr)(DvrHwcFrame* frame); typedef size_t (*DvrHwcFrameGetLayerCountPtr)(DvrHwcFrame* frame); -typedef Layer (*DvrHwcFrameGetLayerIdPtr)(DvrHwcFrame* frame, size_t layer_index); +typedef Layer (*DvrHwcFrameGetLayerIdPtr)(DvrHwcFrame* frame, + size_t layer_index); typedef AHardwareBuffer* (*DvrHwcFrameGetLayerBufferPtr)(DvrHwcFrame* frame, size_t layer_index); typedef int (*DvrHwcFrameGetLayerFencePtr)(DvrHwcFrame* frame, @@ -185,7 +184,7 @@ struct DvrApi_v1 { display_manager_client_get_surface_list; DvrDisplayManagerClientSurfaceListDestroyPtr display_manager_client_surface_list_destroy; - DvrDisplayManagerSetupPoseBufferPtr display_manager_setup_pose_buffer; + DvrDisplayManagerSetupNamedBufferPtr display_manager_setup_named_buffer; DvrDisplayManagerClientSurfaceListGetSizePtr display_manager_client_surface_list_get_size; DvrDisplayManagerClientSurfaceListGetSurfaceIdPtr @@ -201,7 +200,6 @@ struct DvrApi_v1 { // Write buffer DvrWriteBufferDestroyPtr write_buffer_destroy; - DvrWriteBufferGetBlobFdsPtr write_buffer_get_blob_fds; DvrWriteBufferGetAHardwareBufferPtr write_buffer_get_ahardwarebuffer; DvrWriteBufferPostPtr write_buffer_post; DvrWriteBufferGainPtr write_buffer_gain; @@ -209,11 +207,12 @@ struct DvrApi_v1 { // Read buffer DvrReadBufferDestroyPtr read_buffer_destroy; - DvrReadBufferGetBlobFdsPtr read_buffer_get_blob_fds; DvrReadBufferGetAHardwareBufferPtr read_buffer_get_ahardwarebuffer; DvrReadBufferAcquirePtr read_buffer_acquire; DvrReadBufferReleasePtr read_buffer_release; DvrReadBufferReleaseAsyncPtr read_buffer_release_async; + DvrBufferDestroy buffer_destroy; + DvrBufferGetAHardwareBuffer buffer_get_ahardwarebuffer; // Write buffer queue DvrWriteBufferQueueDestroyPtr write_buffer_queue_destroy; @@ -235,7 +234,7 @@ struct DvrApi_v1 { DvrVSyncClientGetSchedInfoPtr vsync_client_get_sched_info; // Display surface - DvrGetPoseBufferPtr get_pose_buffer; + DvrGetNamedBufferPtr get_named_buffer; DvrSurfaceCreatePtr surface_create; DvrSurfaceGetWriteBufferQueuePtr surface_get_write_buffer_queue; diff --git a/libs/vr/libdvr/include/dvr/dvr_buffer.h b/libs/vr/libdvr/include/dvr/dvr_buffer.h index bbfbb00a9b..6c9c4d33b3 100644 --- a/libs/vr/libdvr/include/dvr/dvr_buffer.h +++ b/libs/vr/libdvr/include/dvr/dvr_buffer.h @@ -1,9 +1,9 @@ #ifndef ANDROID_DVR_BUFFER_H_ #define ANDROID_DVR_BUFFER_H_ -#include <memory> #include <stdbool.h> #include <stdint.h> +#include <memory> #ifdef __cplusplus extern "C" { @@ -11,29 +11,33 @@ extern "C" { typedef struct DvrWriteBuffer DvrWriteBuffer; typedef struct DvrReadBuffer DvrReadBuffer; +typedef struct DvrBuffer DvrBuffer; typedef struct AHardwareBuffer AHardwareBuffer; // Write buffer -void dvrWriteBufferDestroy(DvrWriteBuffer* client); -void dvrWriteBufferGetBlobFds(DvrWriteBuffer* client, int* fds, - size_t* fds_count, size_t max_fds_count); -int dvrWriteBufferGetAHardwareBuffer(DvrWriteBuffer* client, +void dvrWriteBufferDestroy(DvrWriteBuffer* write_buffer); +int dvrWriteBufferGetId(DvrWriteBuffer* write_buffer); +int dvrWriteBufferGetAHardwareBuffer(DvrWriteBuffer* write_buffer, AHardwareBuffer** hardware_buffer); -int dvrWriteBufferPost(DvrWriteBuffer* client, int ready_fence_fd, +int dvrWriteBufferPost(DvrWriteBuffer* write_buffer, int ready_fence_fd, const void* meta, size_t meta_size_bytes); -int dvrWriteBufferGain(DvrWriteBuffer* client, int* release_fence_fd); -int dvrWriteBufferGainAsync(DvrWriteBuffer* client); +int dvrWriteBufferGain(DvrWriteBuffer* write_buffer, int* release_fence_fd); +int dvrWriteBufferGainAsync(DvrWriteBuffer* write_buffer); // Read buffer -void dvrReadBufferDestroy(DvrReadBuffer* client); -void dvrReadBufferGetBlobFds(DvrReadBuffer* client, int* fds, size_t* fds_count, - size_t max_fds_count); -int dvrReadBufferGetAHardwareBuffer(DvrReadBuffer* client, +void dvrReadBufferDestroy(DvrReadBuffer* read_buffer); +int dvrReadBufferGetId(DvrReadBuffer* read_buffer); +int dvrReadBufferGetAHardwareBuffer(DvrReadBuffer* read_buffer, AHardwareBuffer** hardware_buffer); -int dvrReadBufferAcquire(DvrReadBuffer* client, int* ready_fence_fd, void* meta, - size_t meta_size_bytes); -int dvrReadBufferRelease(DvrReadBuffer* client, int release_fence_fd); -int dvrReadBufferReleaseAsync(DvrReadBuffer* client); +int dvrReadBufferAcquire(DvrReadBuffer* read_buffer, int* ready_fence_fd, + void* meta, size_t meta_size_bytes); +int dvrReadBufferRelease(DvrReadBuffer* read_buffer, int release_fence_fd); +int dvrReadBufferReleaseAsync(DvrReadBuffer* read_buffer); + +// Buffer +void dvrBufferDestroy(DvrBuffer* buffer); +int dvrBufferGetAHardwareBuffer(DvrBuffer* buffer, + AHardwareBuffer** hardware_buffer); #ifdef __cplusplus } // extern "C" @@ -44,11 +48,14 @@ namespace dvr { class BufferProducer; class BufferConsumer; +class IonBuffer; DvrWriteBuffer* CreateDvrWriteBufferFromBufferProducer( const std::shared_ptr<BufferProducer>& buffer_producer); DvrReadBuffer* CreateDvrReadBufferFromBufferConsumer( const std::shared_ptr<BufferConsumer>& buffer_consumer); +DvrBuffer* CreateDvrBufferFromIonBuffer( + const std::shared_ptr<IonBuffer>& ion_buffer); } // namespace dvr } // namespace android diff --git a/libs/vr/libdvr/include/dvr/dvr_surface.h b/libs/vr/libdvr/include/dvr/dvr_surface.h index 2712f24e3c..e5228d6954 100644 --- a/libs/vr/libdvr/include/dvr/dvr_surface.h +++ b/libs/vr/libdvr/include/dvr/dvr_surface.h @@ -12,7 +12,7 @@ typedef struct DvrSurface DvrSurface; typedef struct DvrSurfaceParameter DvrSurfaceParameter; // Get a pointer to the global pose buffer. -int dvrGetPoseBuffer(DvrReadBuffer** pose_buffer); +int dvrGetNamedBuffer(const char* name, DvrBuffer** out_buffer); int dvrSurfaceCreate(int width, int height, int format, uint64_t usage0, uint64_t usage1, int flags, DvrSurface** out_surface); diff --git a/libs/vr/libdvr/tests/Android.mk b/libs/vr/libdvr/tests/Android.mk index 75e2a7d79c..29cdc130c2 100644 --- a/libs/vr/libdvr/tests/Android.mk +++ b/libs/vr/libdvr/tests/Android.mk @@ -17,14 +17,18 @@ static_libraries := \ libbufferhub \ libchrome \ libdvrcommon \ + libdisplay \ libpdx_default_transport \ include $(CLEAR_VARS) -LOCAL_SRC_FILES := dvr_buffer_queue-test.cpp +LOCAL_SRC_FILES := \ + dvr_buffer_queue-test.cpp \ + dvr_named_buffer-test.cpp \ + LOCAL_STATIC_LIBRARIES := $(static_libraries) LOCAL_SHARED_LIBRARIES := $(shared_libraries) LOCAL_EXPORT_C_INCLUDE_DIRS := ${LOCAL_C_INCLUDES} -LOCAL_CFLAGS := -DLOG_TAG=\"dvr_buffer_queue-test\" -DTRACE=0 -O0 -g -LOCAL_MODULE := dvr_buffer_queue-test +LOCAL_CFLAGS := -DLOG_TAG=\"dvr_api-test\" -DTRACE=0 -O0 -g +LOCAL_MODULE := dvr_api-test LOCAL_MODULE_TAGS := optional include $(BUILD_NATIVE_TEST) diff --git a/libs/vr/libdvr/tests/dvr_named_buffer-test.cpp b/libs/vr/libdvr/tests/dvr_named_buffer-test.cpp new file mode 100644 index 0000000000..cd3285f275 --- /dev/null +++ b/libs/vr/libdvr/tests/dvr_named_buffer-test.cpp @@ -0,0 +1,122 @@ +#include <android/hardware_buffer.h> +#include <dvr/display_manager_client.h> +#include <dvr/dvr_buffer.h> +#include <dvr/dvr_surface.h> +#include <system/graphics.h> + +#include <base/logging.h> +#include <gtest/gtest.h> + +namespace android { +namespace dvr { + +namespace { + +class DvrNamedBufferTest : public ::testing::Test { + protected: + void SetUp() override { + client_ = dvrDisplayManagerClientCreate(); + ASSERT_NE(nullptr, client_); + } + + void TearDown() override { + if (client_ != nullptr) { + dvrDisplayManagerClientDestroy(client_); + client_ = nullptr; + } + } + + DvrDisplayManagerClient* client_ = nullptr; +}; + +TEST_F(DvrNamedBufferTest, TestNamedBuffersSameName) { + const char* buffer_name = "same_name"; + DvrBuffer* buffer1 = + dvrDisplayManagerSetupNamedBuffer(client_, buffer_name, 10, 0, 0); + ASSERT_NE(nullptr, buffer1); + + DvrBuffer* buffer2 = + dvrDisplayManagerSetupNamedBuffer(client_, buffer_name, 10, 0, 0); + ASSERT_NE(nullptr, buffer2); + + AHardwareBuffer* hardware_buffer1 = nullptr; + int e1 = dvrBufferGetAHardwareBuffer(buffer1, &hardware_buffer1); + ASSERT_EQ(0, e1); + + AHardwareBuffer* hardware_buffer2 = nullptr; + int e2 = dvrBufferGetAHardwareBuffer(buffer2, &hardware_buffer2); + ASSERT_EQ(0, e2); + ASSERT_NE(nullptr, hardware_buffer1); + + AHardwareBuffer_Desc desc1 = {}; + AHardwareBuffer_describe(hardware_buffer1, &desc1); + AHardwareBuffer_Desc desc2 = {}; + AHardwareBuffer_describe(hardware_buffer2, &desc2); + ASSERT_EQ(desc1.width, 10u); + ASSERT_EQ(desc1.height, 1u); + ASSERT_EQ(desc1.layers, 1u); + ASSERT_EQ(desc1.format, HAL_PIXEL_FORMAT_BLOB); + ASSERT_EQ(desc1.usage0, 0u); + ASSERT_EQ(desc1.usage1, 0u); + ASSERT_EQ(desc2.width, 10u); + ASSERT_EQ(desc2.height, 1u); + ASSERT_EQ(desc2.layers, 1u); + ASSERT_EQ(desc2.format, HAL_PIXEL_FORMAT_BLOB); + ASSERT_EQ(desc2.usage0, 0u); + ASSERT_EQ(desc2.usage1, 0u); + + dvrBufferDestroy(buffer1); + dvrBufferDestroy(buffer2); + + DvrBuffer* buffer3 = nullptr; + int e3 = dvrGetNamedBuffer(buffer_name, &buffer3); + ASSERT_NE(nullptr, buffer3); + ASSERT_EQ(0, e3); + + AHardwareBuffer* hardware_buffer3 = nullptr; + int e4 = dvrBufferGetAHardwareBuffer(buffer2, &hardware_buffer3); + ASSERT_EQ(0, e4); + ASSERT_NE(nullptr, hardware_buffer3); + + AHardwareBuffer_Desc desc3 = {}; + AHardwareBuffer_describe(hardware_buffer3, &desc3); + ASSERT_EQ(desc3.width, 10u); + ASSERT_EQ(desc3.height, 1u); + ASSERT_EQ(desc3.layers, 1u); + ASSERT_EQ(desc3.format, HAL_PIXEL_FORMAT_BLOB); + ASSERT_EQ(desc3.usage0, 0u); + ASSERT_EQ(desc3.usage1, 0u); + + dvrBufferDestroy(buffer3); +} + +TEST_F(DvrNamedBufferTest, TestMultipleNamedBuffers) { + const char* buffer_name1 = "test1"; + const char* buffer_name2 = "test2"; + DvrBuffer* setup_buffer1 = + dvrDisplayManagerSetupNamedBuffer(client_, buffer_name1, 10, 0, 0); + ASSERT_NE(nullptr, setup_buffer1); + dvrBufferDestroy(setup_buffer1); + + DvrBuffer* setup_buffer2 = + dvrDisplayManagerSetupNamedBuffer(client_, buffer_name2, 10, 0, 0); + ASSERT_NE(nullptr, setup_buffer2); + dvrBufferDestroy(setup_buffer2); + + DvrBuffer* buffer1 = nullptr; + int e1 = dvrGetNamedBuffer(buffer_name1, &buffer1); + ASSERT_NE(nullptr, buffer1); + ASSERT_EQ(0, e1); + dvrBufferDestroy(buffer1); + + DvrBuffer* buffer2 = nullptr; + int e2 = dvrGetNamedBuffer(buffer_name2, &buffer2); + ASSERT_NE(nullptr, buffer2); + ASSERT_EQ(0, e2); + dvrBufferDestroy(buffer2); +} + +} // namespace + +} // namespace dvr +} // namespace android diff --git a/libs/vr/libvrflinger/Android.bp b/libs/vr/libvrflinger/Android.bp index 0daab642b3..632978b0bf 100644 --- a/libs/vr/libvrflinger/Android.bp +++ b/libs/vr/libvrflinger/Android.bp @@ -47,6 +47,7 @@ staticLibraries = [ ] sharedLibraries = [ + "android.frameworks.vr.composer@1.0", "android.hardware.graphics.allocator@2.0", "android.hardware.graphics.composer@2.1", "libbinder", @@ -75,7 +76,7 @@ cc_library_static { cflags: [ "-DLOG_TAG=\"vr_flinger\"", "-DTRACE=0", - "-DATRACE_TAG=ATRACE_TAG_GRAPHICS", + "-DATRACE_TAG=ATRACE_TAG_GRAPHICS", "-DGL_GLEXT_PROTOTYPES", "-DEGL_EGLEXT_PROTOTYPES", ], diff --git a/libs/vr/libvrflinger/display_manager_service.cpp b/libs/vr/libvrflinger/display_manager_service.cpp index 49b6f095b7..99f93bfcab 100644 --- a/libs/vr/libvrflinger/display_manager_service.cpp +++ b/libs/vr/libvrflinger/display_manager_service.cpp @@ -2,7 +2,9 @@ #include <pdx/channel_handle.h> #include <pdx/default_transport/service_endpoint.h> +#include <private/android_filesystem_config.h> #include <private/dvr/display_rpc.h> +#include <private/dvr/trusted_uids.h> #include <sys/poll.h> #include <array> @@ -82,9 +84,9 @@ pdx::Status<void> DisplayManagerService::HandleMessage(pdx::Message& message) { *this, &DisplayManagerService::OnUpdateSurfaces, message); return {}; - case DisplayManagerRPC::SetupPoseBuffer::Opcode: - DispatchRemoteMethod<DisplayManagerRPC::SetupPoseBuffer>( - *this, &DisplayManagerService::OnSetupPoseBuffer, message); + case DisplayManagerRPC::SetupNamedBuffer::Opcode: + DispatchRemoteMethod<DisplayManagerRPC::SetupNamedBuffer>( + *this, &DisplayManagerService::OnSetupNamedBuffer, message); return {}; default: @@ -188,9 +190,20 @@ int DisplayManagerService::OnUpdateSurfaces( return 0; } -pdx::BorrowedChannelHandle DisplayManagerService::OnSetupPoseBuffer( - pdx::Message& /*message*/, size_t extended_region_size, int usage) { - return display_service_->SetupPoseBuffer(extended_region_size, usage); +pdx::Status<BorrowedNativeBufferHandle> +DisplayManagerService::OnSetupNamedBuffer(pdx::Message& message, + const std::string& name, size_t size, + uint64_t producer_usage, + uint64_t consumer_usage) { + if (message.GetEffectiveUserId() != AID_ROOT && + !IsTrustedUid(message.GetEffectiveUserId())) { + // Only trusted users can setup named buffers. + ALOGE("DisplayService::SetupNamedBuffer: Called by untrusted user: uid=%d.", + message.GetEffectiveUserId()); + return {}; + } + return display_service_->SetupNamedBuffer(name, size, producer_usage, + consumer_usage); } void DisplayManagerService::OnDisplaySurfaceChange() { diff --git a/libs/vr/libvrflinger/display_manager_service.h b/libs/vr/libvrflinger/display_manager_service.h index 80324fd6d4..7b037ded50 100644 --- a/libs/vr/libvrflinger/display_manager_service.h +++ b/libs/vr/libvrflinger/display_manager_service.h @@ -54,9 +54,9 @@ class DisplayManagerService : public pdx::ServiceBase<DisplayManagerService> { int OnUpdateSurfaces(pdx::Message& message, const std::map<int, DisplaySurfaceAttributes>& updates); - pdx::BorrowedChannelHandle OnSetupPoseBuffer(pdx::Message& message, - size_t extended_region_size, - int usage); + pdx::Status<BorrowedNativeBufferHandle> OnSetupNamedBuffer( + pdx::Message& message, const std::string& name, size_t size, + uint64_t producer_usage, uint64_t consumer_usage); // Called by the display service to indicate changes to display surfaces that // the display manager should evaluate. diff --git a/libs/vr/libvrflinger/display_service.cpp b/libs/vr/libvrflinger/display_service.cpp index bb8613cb5b..8cf9d645a7 100644 --- a/libs/vr/libvrflinger/display_service.cpp +++ b/libs/vr/libvrflinger/display_service.cpp @@ -1,5 +1,6 @@ #include "display_service.h" +#include <unistd.h> #include <vector> #include <pdx/default_transport/service_endpoint.h> @@ -18,20 +19,10 @@ using android::pdx::default_transport::Endpoint; using android::pdx::rpc::DispatchRemoteMethod; using android::pdx::rpc::WrapBuffer; -namespace { - -constexpr char kPersistentPoseBufferName[] = "DvrPersistentPoseBuffer"; -const int kPersistentPoseBufferUserId = 0; -const int kPersistentPoseBufferGroupId = 0; -const size_t kTimingDataSizeOffset = 128; - -} // anonymous namespace - namespace android { namespace dvr { -DisplayService::DisplayService() - : DisplayService(nullptr) {} +DisplayService::DisplayService() : DisplayService(nullptr) {} DisplayService::DisplayService(Hwc2::Composer* hidl) : BASE("DisplayService", Endpoint::Create(DisplayRPC::kClientPath)), @@ -89,9 +80,9 @@ pdx::Status<void> DisplayService::HandleMessage(pdx::Message& message) { *this, &DisplayService::OnSetViewerParams, message); return {}; - case DisplayRPC::GetPoseBuffer::Opcode: - DispatchRemoteMethod<DisplayRPC::GetPoseBuffer>( - *this, &DisplayService::OnGetPoseBuffer, message); + case DisplayRPC::GetNamedBuffer::Opcode: + DispatchRemoteMethod<DisplayRPC::GetNamedBuffer>( + *this, &DisplayService::OnGetNamedBuffer, message); return {}; case DisplayRPC::IsVrAppRunning::Opcode: @@ -254,13 +245,14 @@ void DisplayService::OnSetViewerParams(pdx::Message& message, compositor->UpdateHeadMountMetrics(head_mount_metrics); } -pdx::LocalChannelHandle DisplayService::OnGetPoseBuffer(pdx::Message& message) { - if (pose_buffer_) { - return pose_buffer_->CreateConsumer().take(); +pdx::Status<BorrowedNativeBufferHandle> DisplayService::OnGetNamedBuffer( + pdx::Message& /* message */, const std::string& name) { + auto named_buffer = named_buffers_.find(name); + if (named_buffer != named_buffers_.end()) { + return {BorrowedNativeBufferHandle(*named_buffer->second, 0)}; } - pdx::rpc::RemoteMethodError(message, EAGAIN); - return {}; + return pdx::ErrorStatus(EINVAL); } // Calls the message handler for the DisplaySurface associated with this @@ -334,16 +326,22 @@ void DisplayService::UpdateActiveDisplaySurfaces() { hardware_composer_.SetDisplaySurfaces(std::move(visible_surfaces)); } -pdx::BorrowedChannelHandle DisplayService::SetupPoseBuffer( - size_t extended_region_size, int usage) { - if (!pose_buffer_) { - pose_buffer_ = BufferProducer::Create( - kPersistentPoseBufferName, kPersistentPoseBufferUserId, - kPersistentPoseBufferGroupId, usage, - extended_region_size + kTimingDataSizeOffset); +pdx::Status<BorrowedNativeBufferHandle> DisplayService::SetupNamedBuffer( + const std::string& name, size_t size, int producer_usage, + int consumer_usage) { + auto named_buffer = named_buffers_.find(name); + if (named_buffer == named_buffers_.end()) { + // TODO(hendrikw): Update BufferProducer to take producer_usage and + // consumer_usage flags. + auto ion_buffer = std::make_unique<IonBuffer>( + static_cast<int>(size), 1, HAL_PIXEL_FORMAT_BLOB, + producer_usage | consumer_usage); + named_buffer = + named_buffers_.insert(std::make_pair(name, std::move(ion_buffer))) + .first; } - return pose_buffer_->GetChannelHandle().Borrow(); + return {BorrowedNativeBufferHandle(*named_buffer->second, 0)}; } void DisplayService::OnHardwareComposerRefresh() { @@ -362,10 +360,11 @@ void DisplayService::NotifyDisplayConfigurationUpdate() { int DisplayService::IsVrAppRunning(pdx::Message& message) { bool visible = false; - ForEachDisplaySurface([&visible](const std::shared_ptr<DisplaySurface>& surface) { - if (surface->client_z_order() == 0 && surface->IsVisible()) - visible = true; - }); + ForEachDisplaySurface( + [&visible](const std::shared_ptr<DisplaySurface>& surface) { + if (surface->client_z_order() == 0 && surface->IsVisible()) + visible = true; + }); REPLY_SUCCESS_RETURN(message, visible, 0); } diff --git a/libs/vr/libvrflinger/display_service.h b/libs/vr/libvrflinger/display_service.h index da80a84510..db89064df6 100644 --- a/libs/vr/libvrflinger/display_service.h +++ b/libs/vr/libvrflinger/display_service.h @@ -3,6 +3,7 @@ #include <pdx/service.h> #include <private/dvr/buffer_hub_client.h> +#include <private/dvr/bufferhub_rpc.h> #include <private/dvr/display_rpc.h> #include <private/dvr/late_latch.h> @@ -38,8 +39,9 @@ class DisplayService : public pdx::ServiceBase<DisplayService> { // any change to client/manager attributes that affect visibility or z order. void UpdateActiveDisplaySurfaces(); - pdx::BorrowedChannelHandle SetupPoseBuffer(size_t extended_region_size, - int usage); + pdx::Status<BorrowedNativeBufferHandle> SetupNamedBuffer( + const std::string& name, size_t size, int producer_usage, + int consumer_usage); template <class A> void ForEachDisplaySurface(A action) const { @@ -85,7 +87,8 @@ class DisplayService : public pdx::ServiceBase<DisplayService> { void OnSetViewerParams(pdx::Message& message, const ViewerParams& view_params); - pdx::LocalChannelHandle OnGetPoseBuffer(pdx::Message& message); + pdx::Status<BorrowedNativeBufferHandle> OnGetNamedBuffer( + pdx::Message& message, const std::string& name); // Temporary query for current VR status. Will be removed later. int IsVrAppRunning(pdx::Message& message); @@ -102,7 +105,7 @@ class DisplayService : public pdx::ServiceBase<DisplayService> { HardwareComposer hardware_composer_; DisplayConfigurationUpdateNotifier update_notifier_; - std::unique_ptr<BufferProducer> pose_buffer_; + std::unordered_map<std::string, std::unique_ptr<IonBuffer>> named_buffers_; }; } // namespace dvr diff --git a/libs/vr/libvrflinger/hardware_composer.cpp b/libs/vr/libvrflinger/hardware_composer.cpp index 542bbd9f0f..6602d78f91 100644 --- a/libs/vr/libvrflinger/hardware_composer.cpp +++ b/libs/vr/libvrflinger/hardware_composer.cpp @@ -1416,7 +1416,7 @@ void Layer::CommonLayerSetup() { void Layer::Prepare() { int right, bottom; - buffer_handle_t handle; + sp<GraphicBuffer> handle; if (surface_) { // Only update the acquired buffer when one is either available or this is @@ -1465,14 +1465,14 @@ void Layer::Prepare() { } right = acquired_buffer_.buffer()->width(); bottom = acquired_buffer_.buffer()->height(); - handle = acquired_buffer_.buffer()->native_handle(); + handle = acquired_buffer_.buffer()->buffer()->buffer(); acquire_fence_fd_.Reset(acquired_buffer_.ClaimAcquireFence().Release()); } else { // TODO(jwcai) Note: this is the GPU compositor's layer, and we need the // mechanism to accept distorted layers from VrCore. right = direct_buffer_->width(); bottom = direct_buffer_->height(); - handle = direct_buffer_->handle(); + handle = direct_buffer_->buffer(); acquire_fence_fd_.Close(); } diff --git a/opengl/include/EGL/eglext.h b/opengl/include/EGL/eglext.h index bf831a7c7a..d0996f03f6 100644 --- a/opengl/include/EGL/eglext.h +++ b/opengl/include/EGL/eglext.h @@ -627,19 +627,21 @@ typedef EGLClientBuffer (EGLAPIENTRYP PFNEGLGETNATIVECLIENTBUFFERANDROID) (const #ifndef EGL_ANDROID_get_frame_timestamps #define EGL_ANDROID_get_frame_timestamps 1 -#define EGL_TIMESTAMPS_ANDROID 0x314D -#define EGL_COMPOSITE_DEADLINE_ANDROID 0x314E -#define EGL_COMPOSITE_INTERVAL_ANDROID 0x314F -#define EGL_COMPOSITE_TO_PRESENT_LATENCY_ANDROID 0x3150 -#define EGL_REQUESTED_PRESENT_TIME_ANDROID 0x3151 -#define EGL_RENDERING_COMPLETE_TIME_ANDROID 0x3152 -#define EGL_COMPOSITION_LATCH_TIME_ANDROID 0x3153 -#define EGL_FIRST_COMPOSITION_START_TIME_ANDROID 0x3154 -#define EGL_LAST_COMPOSITION_START_TIME_ANDROID 0x3155 -#define EGL_FIRST_COMPOSITION_GPU_FINISHED_TIME_ANDROID 0x3156 -#define EGL_DISPLAY_PRESENT_TIME_ANDROID 0x3157 -#define EGL_DEQUEUE_READY_TIME_ANDROID 0x3158 -#define EGL_READS_DONE_TIME_ANDROID 0x3159 +#define EGL_TIMESTAMPS_ANDROID 0x3430 +#define EGL_COMPOSITE_DEADLINE_ANDROID 0x3431 +#define EGL_COMPOSITE_INTERVAL_ANDROID 0x3432 +#define EGL_COMPOSITE_TO_PRESENT_LATENCY_ANDROID 0x3433 +#define EGL_REQUESTED_PRESENT_TIME_ANDROID 0x3434 +#define EGL_RENDERING_COMPLETE_TIME_ANDROID 0x3435 +#define EGL_COMPOSITION_LATCH_TIME_ANDROID 0x3436 +#define EGL_FIRST_COMPOSITION_START_TIME_ANDROID 0x3437 +#define EGL_LAST_COMPOSITION_START_TIME_ANDROID 0x3438 +#define EGL_FIRST_COMPOSITION_GPU_FINISHED_TIME_ANDROID 0x3439 +#define EGL_DISPLAY_PRESENT_TIME_ANDROID 0x343A +#define EGL_DEQUEUE_READY_TIME_ANDROID 0x343B +#define EGL_READS_DONE_TIME_ANDROID 0x343C +#define EGL_TIMESTAMP_PENDING_ANDROID EGL_CAST(EGLnsecsANDROID, -2) +#define EGL_TIMESTAMP_INVALID_ANDROID EGL_CAST(EGLnsecsANDROID, -1) #ifdef EGL_EGLEXT_PROTOTYPES EGLAPI EGLBoolean eglGetNextFrameIdANDROID(EGLDisplay dpy, EGLSurface surface, EGLuint64KHR *frameId); EGLAPI EGLBoolean eglGetCompositorTimingANDROID(EGLDisplay dpy, EGLSurface surface, EGLint numTimestamps, const EGLint *names, EGLnsecsANDROID *values); diff --git a/opengl/libs/EGL/eglApi.cpp b/opengl/libs/EGL/eglApi.cpp index b00d4013bc..0807d1f52c 100644 --- a/opengl/libs/EGL/eglApi.cpp +++ b/opengl/libs/EGL/eglApi.cpp @@ -2166,10 +2166,15 @@ EGLBoolean eglGetFrameTimestampSupportedANDROID( case EGL_FIRST_COMPOSITION_START_TIME_ANDROID: case EGL_LAST_COMPOSITION_START_TIME_ANDROID: case EGL_FIRST_COMPOSITION_GPU_FINISHED_TIME_ANDROID: - case EGL_DISPLAY_PRESENT_TIME_ANDROID: case EGL_DEQUEUE_READY_TIME_ANDROID: case EGL_READS_DONE_TIME_ANDROID: return EGL_TRUE; + case EGL_DISPLAY_PRESENT_TIME_ANDROID: { + int value = 0; + window->query(window, + NATIVE_WINDOW_FRAME_TIMESTAMPS_SUPPORTS_PRESENT, &value); + return value == 0 ? EGL_FALSE : EGL_TRUE; + } default: return EGL_FALSE; } diff --git a/opengl/specs/EGL_ANDROID_get_frame_timestamps.txt b/opengl/specs/EGL_ANDROID_get_frame_timestamps.txt index 61b9b661e8..b8a9addbde 100644 --- a/opengl/specs/EGL_ANDROID_get_frame_timestamps.txt +++ b/opengl/specs/EGL_ANDROID_get_frame_timestamps.txt @@ -28,7 +28,7 @@ Status Version - Version 1, January 13, 2017 + Version 8, April 11, 2017 Number @@ -81,19 +81,21 @@ New Procedures and Functions New Tokens - EGL_TIMESTAMPS_ANDROID 0x314D - EGL_COMPOSITE_DEADLINE_ANDROID 0x314E - EGL_COMPOSITE_INTERVAL_ANDROID 0x314F - EGL_COMPOSITE_TO_PRESENT_LATENCY_ANDROID 0x3150 - EGL_REQUESTED_PRESENT_TIME_ANDROID 0x3151 - EGL_RENDERING_COMPLETE_TIME_ANDROID 0x3152 - EGL_COMPOSITION_LATCH_TIME_ANDROID 0x3153 - EGL_FIRST_COMPOSITION_START_TIME_ANDROID 0x3154 - EGL_LAST_COMPOSITION_START_TIME_ANDROID 0x3155 - EGL_FIRST_COMPOSITION_GPU_FINISHED_TIME_ANDROID 0x3156 - EGL_DISPLAY_PRESENT_TIME_ANDROID 0x3157 - EGL_DEQUEUE_READY_TIME_ANDROID 0x3158 - EGL_READS_DONE_TIME_ANDROID 0x3159 + EGL_TIMESTAMPS_ANDROID 0x3430 + EGL_COMPOSITE_DEADLINE_ANDROID 0x3431 + EGL_COMPOSITE_INTERVAL_ANDROID 0x3432 + EGL_COMPOSITE_TO_PRESENT_LATENCY_ANDROID 0x3433 + EGL_REQUESTED_PRESENT_TIME_ANDROID 0x3434 + EGL_RENDERING_COMPLETE_TIME_ANDROID 0x3435 + EGL_COMPOSITION_LATCH_TIME_ANDROID 0x3436 + EGL_FIRST_COMPOSITION_START_TIME_ANDROID 0x3437 + EGL_LAST_COMPOSITION_START_TIME_ANDROID 0x3438 + EGL_FIRST_COMPOSITION_GPU_FINISHED_TIME_ANDROID 0x3439 + EGL_DISPLAY_PRESENT_TIME_ANDROID 0x343A + EGL_DEQUEUE_READY_TIME_ANDROID 0x343B + EGL_READS_DONE_TIME_ANDROID 0x343C + EGL_TIMESTAMP_PENDING_ANDROID -2 + EGL_TIMESTAMP_INVALID_ANDROID -1 Add to the list of supported tokens for eglSurfaceAttrib in section 3.5.6 "Surface Attributes", page 43: @@ -155,10 +157,12 @@ Changes to Chapter 3 of the EGL 1.5 Specification (EGL Functions and Errors) limited history of timestamp data. If a query is made for a frame whose timestamp history no longer exists then EGL_BAD_ACCESS is generated. If timestamp collection has not been enabled for the surface then - EGL_BAD_SURFACE is generated. Timestamps for events that will not occur or - have not yet occurred will be zero. Timestamp queries that are not - supported will generate an EGL_BAD_PARAMETER error. If any error is - generated the function will return EGL_FALSE. + EGL_BAD_SURFACE is generated. Timestamps for events that might still occur + will have the value EGL_TIMESTAMP_PENDING_ANDROID. Timestamps for events + that did not occur will have the value EGL_TIMESTAMP_INVALID_ANDROID. + Otherwise, the timestamp will be valid and indicate the event has occured. + Timestamp queries that are not supported will generate an EGL_BAD_PARAMETER + error. If any error is generated the function will return EGL_FALSE. The application can poll for the timestamp of particular events by calling eglGetFrameTimestamps over and over without needing to call any other EGL @@ -222,6 +226,12 @@ Issues Revision History +#8 (Brian Anderson, April 11, 2017) + - Use reserved enumerant values. + +#7 (Brian Anderson, March 21, 2017) + - Differentiate between pending events and events that did not occur. + #6 (Brian Anderson, March 16, 2017) - Remove DISPLAY_RETIRE_TIME_ANDROID. diff --git a/opengl/specs/README b/opengl/specs/README index e922740cc3..cba445389d 100644 --- a/opengl/specs/README +++ b/opengl/specs/README @@ -4,8 +4,14 @@ been or are being defined for Android. The table below tracks usage of EGL enumerant values that have been reserved for use by Android extensions. +See https://github.com/KhronosGroup/EGL-Registry/blob/master/api/egl.xml +for a list of all enumarant values currently reserved and registered with +Khronos. + Value Extension ----------------- ---------------------------------- +================ ================================== +0x3140 - 0x314F Reserved block +================ ================================== 0x3140 EGL_NATIVE_BUFFER_ANDROID (EGL_ANDROID_image_native_buffer) 0x3141 EGL_PLATFORM_ANDROID_KHR (KHR_platform_android) 0x3142 EGL_RECORDABLE_ANDROID (EGL_ANDROID_recordable) @@ -18,17 +24,23 @@ for use by Android extensions. 0x314A EGL_IMAGE_CROP_RIGHT_ANDROID (EGL_ANDROID_image_crop) 0x314B EGL_IMAGE_CROP_BOTTOM_ANDROID (EGL_ANDROID_image_crop) 0x314C EGL_FRONT_BUFFER_AUTO_REFRESH_ANDROID (EGL_ANDROID_front_buffer_auto_refresh) -0x314D EGL_TIMESTAMPS_ANDROID (EGL_ANDROID_get_frame_timestamps) -0x314E EGL_COMPOSITE_DEADLINE_ANDROID (EGL_ANDROID_get_frame_timestamps) -0x314F EGL_COMPOSITE_INTERVAL_ANDROID (EGL_ANDROID_get_frame_timestamps) -0x3150 EGL_COMPOSITE_TO_PRESENT_LATENCY_ANDROID (EGL_ANDROID_get_frame_timestamps) -0x3151 EGL_REQUESTED_PRESENT_TIME_ANDROID (EGL_ANDROID_get_frame_timestamps) -0x3152 EGL_RENDERING_COMPLETE_TIME_ANDROID (EGL_ANDROID_get_frame_timestamps) -0x3153 EGL_COMPOSITION_LATCH_TIME_ANDROID (EGL_ANDROID_get_frame_timestamps) -0x3154 EGL_FIRST_COMPOSITION_START_TIME_ANDROID (EGL_ANDROID_get_frame_timestamps) -0x3155 EGL_LAST_COMPOSITION_START_TIME_ANDROID (EGL_ANDROID_get_frame_timestamps) -0x3156 EGL_FIRST_COMPOSITION_GPU_FINISHED_TIME_ANDROID (EGL_ANDROID_get_frame_timestamps) -0x3157 EGL_DISPLAY_PRESENT_TIME_ANDROID (EGL_ANDROID_get_frame_timestamps) -0x3158 EGL_DEQUEUE_READY_TIME_ANDROID (EGL_ANDROID_get_frame_timestamps) -0x3159 EGL_READS_DONE_TIME_ANDROID (EGL_ANDROID_get_frame_timestamps) -0x315A - 0x315F (unused) +0x314D - 0x314F (unused) + + Value Extension +================ ================================== +0x3430 - 0x343F Reserved block +================ ================================== +0x3430 EGL_TIMESTAMPS_ANDROID (EGL_ANDROID_get_frame_timestamps) +0x3431 EGL_COMPOSITE_DEADLINE_ANDROID (EGL_ANDROID_get_frame_timestamps) +0x3432 EGL_COMPOSITE_INTERVAL_ANDROID (EGL_ANDROID_get_frame_timestamps) +0x3433 EGL_COMPOSITE_TO_PRESENT_LATENCY_ANDROID (EGL_ANDROID_get_frame_timestamps) +0x3434 EGL_REQUESTED_PRESENT_TIME_ANDROID (EGL_ANDROID_get_frame_timestamps) +0x3435 EGL_RENDERING_COMPLETE_TIME_ANDROID (EGL_ANDROID_get_frame_timestamps) +0x3436 EGL_COMPOSITION_LATCH_TIME_ANDROID (EGL_ANDROID_get_frame_timestamps) +0x3437 EGL_FIRST_COMPOSITION_START_TIME_ANDROID (EGL_ANDROID_get_frame_timestamps) +0x3438 EGL_LAST_COMPOSITION_START_TIME_ANDROID (EGL_ANDROID_get_frame_timestamps) +0x3439 EGL_FIRST_COMPOSITION_GPU_FINISHED_TIME_ANDROID (EGL_ANDROID_get_frame_timestamps) +0x343A EGL_DISPLAY_PRESENT_TIME_ANDROID (EGL_ANDROID_get_frame_timestamps) +0x343B EGL_DEQUEUE_READY_TIME_ANDROID (EGL_ANDROID_get_frame_timestamps) +0x343C EGL_READS_DONE_TIME_ANDROID (EGL_ANDROID_get_frame_timestamps) +0x343D - 0x343F (unused) diff --git a/services/schedulerservice/SchedulingPolicyService.cpp b/services/schedulerservice/SchedulingPolicyService.cpp index 522a8c0950..a1106cf49b 100644 --- a/services/schedulerservice/SchedulingPolicyService.cpp +++ b/services/schedulerservice/SchedulingPolicyService.cpp @@ -29,23 +29,37 @@ namespace schedulerservice { namespace V1_0 { namespace implementation { -Return<bool> SchedulingPolicyService::requestPriority(int32_t pid, int32_t tid, int32_t priority) { +bool SchedulingPolicyService::isAllowed() { using ::android::hardware::IPCThreadState; + return IPCThreadState::self()->getCallingUid() == AID_CAMERASERVER; +} + +Return<bool> SchedulingPolicyService::requestPriority(int32_t pid, int32_t tid, int32_t priority) { if (priority < static_cast<int32_t>(Priority::MIN) || priority > static_cast<int32_t>(Priority::MAX)) { return false; } - if (IPCThreadState::self()->getCallingUid() != AID_CAMERASERVER) { + if (!isAllowed()) { return false; } + // TODO(b/37226359): decouple from and remove AIDL service // this should always be allowed since we are in system_server. int value = ::android::requestPriority(pid, tid, priority, false /* isForApp */); return value == 0 /* success */; } +Return<int32_t> SchedulingPolicyService::getMaxAllowedPriority() { + if (!isAllowed()) { + return 0; + } + + // TODO(b/37226359): decouple from and remove AIDL service + return 3; +} + } // namespace implementation } // namespace V1_0 } // namespace schedulerservice diff --git a/services/schedulerservice/include/schedulerservice/SchedulingPolicyService.h b/services/schedulerservice/include/schedulerservice/SchedulingPolicyService.h index eb5a4aee9d..7d1c478ba7 100644 --- a/services/schedulerservice/include/schedulerservice/SchedulingPolicyService.h +++ b/services/schedulerservice/include/schedulerservice/SchedulingPolicyService.h @@ -38,6 +38,9 @@ using ::android::sp; struct SchedulingPolicyService : public ISchedulingPolicyService { Return<bool> requestPriority(int32_t pid, int32_t tid, int32_t priority) override; + Return<int32_t> getMaxAllowedPriority() override; +private: + bool isAllowed(); }; } // namespace implementation diff --git a/services/sensorservice/hidl/DirectReportChannel.cpp b/services/sensorservice/hidl/DirectReportChannel.cpp index 773ce8cd0a..adc4675098 100644 --- a/services/sensorservice/hidl/DirectReportChannel.cpp +++ b/services/sensorservice/hidl/DirectReportChannel.cpp @@ -31,10 +31,13 @@ DirectReportChannel::~DirectReportChannel() { } // Methods from ::android::frameworks::sensorservice::V1_0::IDirectReportChannel follow. -Return<Result> DirectReportChannel::configure(int32_t sensorHandle, RateLevel rate) { +Return<void> DirectReportChannel::configure(int32_t sensorHandle, RateLevel rate, + configure_cb _hidl_cb) { int token = mManager.configureDirectChannel(mId, static_cast<int>(sensorHandle), static_cast<int>(rate)); - return token <= 0 ? convertResult(token) : Result::OK; + _hidl_cb(token <= 0 ? 0 : token, + token <= 0 ? convertResult(token) : Result::OK); + return Void(); } diff --git a/services/sensorservice/hidl/DirectReportChannel.h b/services/sensorservice/hidl/DirectReportChannel.h index 913494427d..dd67827bb0 100644 --- a/services/sensorservice/hidl/DirectReportChannel.h +++ b/services/sensorservice/hidl/DirectReportChannel.h @@ -47,7 +47,8 @@ struct DirectReportChannel final : public IDirectReportChannel { ~DirectReportChannel(); // Methods from ::android::frameworks::sensorservice::V1_0::IDirectReportChannel follow. - Return<Result> configure(int32_t sensorHandle, RateLevel rate) override; + Return<void> configure(int32_t sensorHandle, RateLevel rate, + configure_cb _hidl_cb) override; private: ::android::SensorManager& mManager; diff --git a/services/sensorservice/hidl/EventQueue.cpp b/services/sensorservice/hidl/EventQueue.cpp index 86d365c0c2..c0365e503b 100644 --- a/services/sensorservice/hidl/EventQueue.cpp +++ b/services/sensorservice/hidl/EventQueue.cpp @@ -39,7 +39,8 @@ public: while ((actual = internalQueue->read(&event, 1 /* count */)) > 0) { internalQueue->sendAck(&event, actual); - mCallback->onEvent(convertEvent(event)); + Return<void> ret = mCallback->onEvent(convertEvent(event)); + (void)ret.isOk(); // ignored } return 1; // continue to receive callbacks diff --git a/services/sensorservice/hidl/SensorManager.cpp b/services/sensorservice/hidl/SensorManager.cpp index 0743fc39d6..06ff95cdc8 100644 --- a/services/sensorservice/hidl/SensorManager.cpp +++ b/services/sensorservice/hidl/SensorManager.cpp @@ -22,12 +22,14 @@ #include "SensorManager.h" +#include <sched.h> + +#include <thread> + #include "EventQueue.h" #include "DirectReportChannel.h" #include "utils.h" -#include <thread> - namespace android { namespace frameworks { namespace sensorservice { @@ -131,6 +133,14 @@ sp<::android::Looper> SensorManager::getLooper() { std::condition_variable looperSet; std::thread{[&mutex = mLooperMutex, &looper = mLooper, &looperSet] { + + struct sched_param p = {0}; + p.sched_priority = 10; + if (sched_setscheduler(0 /* current thread*/, SCHED_FIFO, &p) != 0) { + LOG(WARNING) << "Could not use SCHED_FIFO for looper thread: " + << strerror(errno); + } + std::unique_lock<std::mutex> lock(mutex); looper = Looper::prepare(ALOOPER_PREPARE_ALLOW_NON_CALLBACKS /* opts */); lock.unlock(); diff --git a/services/sensorservice/hidl/utils.cpp b/services/sensorservice/hidl/utils.cpp index b5405254d9..2f9e922b59 100644 --- a/services/sensorservice/hidl/utils.cpp +++ b/services/sensorservice/hidl/utils.cpp @@ -63,6 +63,8 @@ Result convertResult(status_t status) { return Result::NO_MEMORY; case NO_INIT: return Result::NO_INIT; + case PERMISSION_DENIED: + return Result::PERMISSION_DENIED; case BAD_VALUE: return Result::BAD_VALUE; case INVALID_OPERATION: diff --git a/services/surfaceflinger/Android.mk b/services/surfaceflinger/Android.mk index 76baa01f84..7bb20bac13 100644 --- a/services/surfaceflinger/Android.mk +++ b/services/surfaceflinger/Android.mk @@ -133,10 +133,15 @@ LOCAL_SRC_FILES := \ main_surfaceflinger.cpp LOCAL_SHARED_LIBRARIES := \ + android.hardware.configstore@1.0 \ + android.hardware.configstore-utils \ + android.hardware.graphics.allocator@2.0 \ libsurfaceflinger \ libcutils \ liblog \ libbinder \ + libhidlbase \ + libhidltransport \ libutils \ libui \ libgui \ diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.cpp b/services/surfaceflinger/DisplayHardware/ComposerHal.cpp index 33aa7598ee..262ab62ac2 100644 --- a/services/surfaceflinger/DisplayHardware/ComposerHal.cpp +++ b/services/surfaceflinger/DisplayHardware/ComposerHal.cpp @@ -17,7 +17,6 @@ #undef LOG_TAG #define LOG_TAG "HwcComposer" -#include <android/frameworks/vr/composer/1.0/IVrComposerClient.h> #include <inttypes.h> #include <log/log.h> #include <gui/BufferQueue.h> @@ -26,7 +25,6 @@ namespace android { -using frameworks::vr::composer::V1_0::IVrComposerClient; using hardware::Return; using hardware::hidl_vec; using hardware::hidl_handle; @@ -124,6 +122,41 @@ void Composer::CommandWriter::setLayerInfo(uint32_t type, uint32_t appId) endCommand(); } +void Composer::CommandWriter::setClientTargetMetadata( + const IVrComposerClient::BufferMetadata& metadata) +{ + constexpr uint16_t kSetClientTargetMetadataLength = 7; + beginCommand( + static_cast<IComposerClient::Command>( + IVrComposerClient::VrCommand::SET_CLIENT_TARGET_METADATA), + kSetClientTargetMetadataLength); + writeBufferMetadata(metadata); + endCommand(); +} + +void Composer::CommandWriter::setLayerBufferMetadata( + const IVrComposerClient::BufferMetadata& metadata) +{ + constexpr uint16_t kSetLayerBufferMetadataLength = 7; + beginCommand( + static_cast<IComposerClient::Command>( + IVrComposerClient::VrCommand::SET_LAYER_BUFFER_METADATA), + kSetLayerBufferMetadataLength); + writeBufferMetadata(metadata); + endCommand(); +} + +void Composer::CommandWriter::writeBufferMetadata( + const IVrComposerClient::BufferMetadata& metadata) +{ + write(metadata.width); + write(metadata.height); + write(metadata.stride); + write(metadata.layerCount); + writeSigned(static_cast<int32_t>(metadata.format)); + write64(metadata.usage); +} + Composer::Composer(bool useVrComposer) : mWriter(kWriterInitialSize), mIsUsingVrComposer(useVrComposer) @@ -426,12 +459,29 @@ Error Composer::setActiveConfig(Display display, Config config) } Error Composer::setClientTarget(Display display, uint32_t slot, - const native_handle_t* target, + const sp<GraphicBuffer>& target, int acquireFence, Dataspace dataspace, const std::vector<IComposerClient::Rect>& damage) { mWriter.selectDisplay(display); - mWriter.setClientTarget(slot, target, acquireFence, dataspace, damage); + if (mIsUsingVrComposer && target.get()) { + IVrComposerClient::BufferMetadata metadata = { + .width = target->getWidth(), + .height = target->getHeight(), + .stride = target->getStride(), + .layerCount = target->getLayerCount(), + .format = static_cast<PixelFormat>(target->getPixelFormat()), + .usage = target->getUsage(), + }; + mWriter.setClientTargetMetadata(metadata); + } + + const native_handle_t* handle = nullptr; + if (target.get()) { + handle = target->getNativeBuffer()->handle; + } + + mWriter.setClientTarget(slot, handle, acquireFence, dataspace, damage); return Error::NONE; } @@ -502,11 +552,28 @@ Error Composer::setCursorPosition(Display display, Layer layer, } Error Composer::setLayerBuffer(Display display, Layer layer, - uint32_t slot, const native_handle_t* buffer, int acquireFence) + uint32_t slot, const sp<GraphicBuffer>& buffer, int acquireFence) { mWriter.selectDisplay(display); mWriter.selectLayer(layer); - mWriter.setLayerBuffer(slot, buffer, acquireFence); + if (mIsUsingVrComposer && buffer.get()) { + IVrComposerClient::BufferMetadata metadata = { + .width = buffer->getWidth(), + .height = buffer->getHeight(), + .stride = buffer->getStride(), + .layerCount = buffer->getLayerCount(), + .format = static_cast<PixelFormat>(buffer->getPixelFormat()), + .usage = buffer->getUsage(), + }; + mWriter.setLayerBufferMetadata(metadata); + } + + const native_handle_t* handle = nullptr; + if (buffer.get()) { + handle = buffer->getNativeBuffer()->handle; + } + + mWriter.setLayerBuffer(slot, handle, acquireFence); return Error::NONE; } diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.h b/services/surfaceflinger/DisplayHardware/ComposerHal.h index 18af9dd295..37b7766d5e 100644 --- a/services/surfaceflinger/DisplayHardware/ComposerHal.h +++ b/services/surfaceflinger/DisplayHardware/ComposerHal.h @@ -23,6 +23,7 @@ #include <utility> #include <vector> +#include <android/frameworks/vr/composer/1.0/IVrComposerClient.h> #include <android/hardware/graphics/composer/2.1/IComposer.h> #include <utils/StrongPointer.h> #include <IComposerCommandBuffer.h> @@ -31,6 +32,8 @@ namespace android { namespace Hwc2 { +using android::frameworks::vr::composer::V1_0::IVrComposerClient; + using android::hardware::graphics::common::V1_0::ColorMode; using android::hardware::graphics::common::V1_0::ColorTransform; using android::hardware::graphics::common::V1_0::Dataspace; @@ -179,7 +182,7 @@ public: * When target is not nullptr, the cache is updated with the new target. */ Error setClientTarget(Display display, uint32_t slot, - const native_handle_t* target, + const sp<GraphicBuffer>& target, int acquireFence, Dataspace dataspace, const std::vector<IComposerClient::Rect>& damage); Error setColorMode(Display display, ColorMode mode); @@ -199,7 +202,7 @@ public: int32_t x, int32_t y); /* see setClientTarget for the purpose of slot */ Error setLayerBuffer(Display display, Layer layer, uint32_t slot, - const native_handle_t* buffer, int acquireFence); + const sp<GraphicBuffer>& buffer, int acquireFence); Error setLayerSurfaceDamage(Display display, Layer layer, const std::vector<IComposerClient::Rect>& damage); Error setLayerBlendMode(Display display, Layer layer, @@ -232,6 +235,14 @@ private: ~CommandWriter() override; void setLayerInfo(uint32_t type, uint32_t appId); + void setClientTargetMetadata( + const IVrComposerClient::BufferMetadata& metadata); + void setLayerBufferMetadata( + const IVrComposerClient::BufferMetadata& metadata); + + private: + void writeBufferMetadata( + const IVrComposerClient::BufferMetadata& metadata); }; // Many public functions above simply write a command into the command diff --git a/services/surfaceflinger/DisplayHardware/HWC2.cpp b/services/surfaceflinger/DisplayHardware/HWC2.cpp index e49e7344f8..8270c39f0f 100644 --- a/services/surfaceflinger/DisplayHardware/HWC2.cpp +++ b/services/surfaceflinger/DisplayHardware/HWC2.cpp @@ -244,7 +244,7 @@ Error Device::createVirtualDisplay(uint32_t width, uint32_t height, ALOGE("Failed to get display by id"); return Error::BadDisplay; } - (*outDisplay)->setVirtual(); + (*outDisplay)->setConnected(true); return Error::None; } @@ -531,15 +531,28 @@ Display::Display(Device& device, hwc2_display_t id) : mDevice(device), mId(id), mIsConnected(false), - mIsVirtual(false) + mType(DisplayType::Invalid) { ALOGV("Created display %" PRIu64, id); + +#ifdef BYPASS_IHWC + int32_t intError = mDevice.mGetDisplayType(mDevice.mHwcDevice, mId, + reinterpret_cast<int32_t *>(&mType)); +#else + auto intError = mDevice.mComposer->getDisplayType(mId, + reinterpret_cast<Hwc2::IComposerClient::DisplayType *>(&mType)); +#endif + auto error = static_cast<Error>(intError); + if (error != Error::None) { + ALOGE("getDisplayType(%" PRIu64 ") failed: %s (%d)", + id, to_string(error).c_str(), intError); + } } Display::~Display() { ALOGV("Destroyed display %" PRIu64, mId); - if (mIsVirtual) { + if (mType == DisplayType::Virtual) { mDevice.destroyVirtualDisplay(mId); } } @@ -802,21 +815,7 @@ Error Display::getRequests(HWC2::DisplayRequest* outDisplayRequests, Error Display::getType(DisplayType* outType) const { -#ifdef BYPASS_IHWC - int32_t intType = 0; - int32_t intError = mDevice.mGetDisplayType(mDevice.mHwcDevice, mId, - &intType); -#else - Hwc2::IComposerClient::DisplayType intType = - Hwc2::IComposerClient::DisplayType::INVALID; - auto intError = mDevice.mComposer->getDisplayType(mId, &intType); -#endif - auto error = static_cast<Error>(intError); - if (error != Error::None) { - return error; - } - - *outType = static_cast<DisplayType>(intType); + *outType = mType; return Error::None; } @@ -961,14 +960,19 @@ Error Display::setActiveConfig(const std::shared_ptr<const Config>& config) return static_cast<Error>(intError); } -Error Display::setClientTarget(uint32_t slot, buffer_handle_t target, +Error Display::setClientTarget(uint32_t slot, const sp<GraphicBuffer>& target, const sp<Fence>& acquireFence, android_dataspace_t dataspace) { // TODO: Properly encode client target surface damage int32_t fenceFd = acquireFence->dup(); #ifdef BYPASS_IHWC (void) slot; - int32_t intError = mDevice.mSetClientTarget(mDevice.mHwcDevice, mId, target, + buffer_handle_t handle = nullptr; + if (target.get() && target->getNativeBuffer()) { + handle = target->getNativeBuffer()->handle; + } + + int32_t intError = mDevice.mSetClientTarget(mDevice.mHwcDevice, mId, handle, fenceFd, static_cast<int32_t>(dataspace), {0, nullptr}); #else auto intError = mDevice.mComposer->setClientTarget(mId, slot, target, @@ -1195,14 +1199,19 @@ Error Layer::setCursorPosition(int32_t x, int32_t y) return static_cast<Error>(intError); } -Error Layer::setBuffer(uint32_t slot, buffer_handle_t buffer, +Error Layer::setBuffer(uint32_t slot, const sp<GraphicBuffer>& buffer, const sp<Fence>& acquireFence) { int32_t fenceFd = acquireFence->dup(); #ifdef BYPASS_IHWC (void) slot; + buffer_handle_t handle = nullptr; + if (buffer.get() && buffer->getNativeBuffer()) { + handle = buffer->getNativeBuffer()->handle; + } + int32_t intError = mDevice.mSetLayerBuffer(mDevice.mHwcDevice, mDisplayId, - mId, buffer, fenceFd); + mId, handle, fenceFd); #else auto intError = mDevice.mComposer->setLayerBuffer(mDisplayId, mId, slot, buffer, fenceFd); diff --git a/services/surfaceflinger/DisplayHardware/HWC2.h b/services/surfaceflinger/DisplayHardware/HWC2.h index 4419dc1172..643b1e00b3 100644 --- a/services/surfaceflinger/DisplayHardware/HWC2.h +++ b/services/surfaceflinger/DisplayHardware/HWC2.h @@ -329,7 +329,7 @@ public: [[clang::warn_unused_result]] Error setActiveConfig( const std::shared_ptr<const Config>& config); [[clang::warn_unused_result]] Error setClientTarget( - uint32_t slot, buffer_handle_t target, + uint32_t slot, const android::sp<android::GraphicBuffer>& target, const android::sp<android::Fence>& acquireFence, android_dataspace_t dataspace); [[clang::warn_unused_result]] Error setColorMode(android_color_mode_t mode); @@ -352,12 +352,6 @@ public: private: // For use by Device - // Virtual displays are always connected - void setVirtual() { - mIsVirtual = true; - mIsConnected = true; - } - void setConnected(bool connected) { mIsConnected = connected; } int32_t getAttribute(hwc2_config_t configId, Attribute attribute); void loadConfig(hwc2_config_t configId); @@ -375,7 +369,7 @@ private: Device& mDevice; hwc2_display_t mId; bool mIsConnected; - bool mIsVirtual; + DisplayType mType; std::unordered_map<hwc2_layer_t, std::weak_ptr<Layer>> mLayers; std::unordered_map<hwc2_config_t, std::shared_ptr<const Config>> mConfigs; }; @@ -392,7 +386,7 @@ public: [[clang::warn_unused_result]] Error setCursorPosition(int32_t x, int32_t y); [[clang::warn_unused_result]] Error setBuffer(uint32_t slot, - buffer_handle_t buffer, + const android::sp<android::GraphicBuffer>& buffer, const android::sp<android::Fence>& acquireFence); [[clang::warn_unused_result]] Error setSurfaceDamage( const android::Region& damage); diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp index 09434f68fa..40979c9b98 100644 --- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp +++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp @@ -206,7 +206,7 @@ void HWComposer::hotplug(const std::shared_ptr<HWC2::Display>& display, } disp = DisplayDevice::DISPLAY_EXTERNAL; } - mEventHandler->onHotplugReceived(disp, + mEventHandler->onHotplugReceived(this, disp, connected == HWC2::Connection::Connected); } @@ -465,12 +465,7 @@ status_t HWComposer::setClientTarget(int32_t displayId, uint32_t slot, ALOGV("setClientTarget for display %d", displayId); auto& hwcDisplay = mDisplayData[displayId].hwcDisplay; - buffer_handle_t handle = nullptr; - if ((target != nullptr) && target->getNativeBuffer()) { - handle = target->getNativeBuffer()->handle; - } - auto error = hwcDisplay->setClientTarget(slot, handle, - acquireFence, dataspace); + auto error = hwcDisplay->setClientTarget(slot, target, acquireFence, dataspace); if (error != HWC2::Error::None) { ALOGE("Failed to set client target for display %d: %s (%d)", displayId, to_string(error).c_str(), static_cast<int32_t>(error)); diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h index 81f1619435..78d03076c0 100644 --- a/services/surfaceflinger/DisplayHardware/HWComposer.h +++ b/services/surfaceflinger/DisplayHardware/HWComposer.h @@ -70,7 +70,7 @@ public: friend class HWComposer; virtual void onVSyncReceived( HWComposer* composer, int32_t disp, nsecs_t timestamp) = 0; - virtual void onHotplugReceived(int32_t disp, bool connected) = 0; + virtual void onHotplugReceived(HWComposer* composer, int32_t disp, bool connected) = 0; virtual void onInvalidateReceived(HWComposer* composer) = 0; protected: virtual ~EventHandler() {} diff --git a/services/surfaceflinger/DisplayHardware/HWComposer_hwc1.cpp b/services/surfaceflinger/DisplayHardware/HWComposer_hwc1.cpp index 5b5f1cfe73..dcb29135b9 100644 --- a/services/surfaceflinger/DisplayHardware/HWComposer_hwc1.cpp +++ b/services/surfaceflinger/DisplayHardware/HWComposer_hwc1.cpp @@ -315,7 +315,7 @@ void HWComposer::hotplug(int disp, int connected) { queryDisplayProperties(disp); // Do not teardown or recreate the primary display if (disp != HWC_DISPLAY_PRIMARY) { - mEventHandler.onHotplugReceived(disp, bool(connected)); + mEventHandler.onHotplugReceived(this, disp, bool(connected)); } } diff --git a/services/surfaceflinger/DisplayHardware/HWComposer_hwc1.h b/services/surfaceflinger/DisplayHardware/HWComposer_hwc1.h index f64d69a86a..4bc63bbac8 100644 --- a/services/surfaceflinger/DisplayHardware/HWComposer_hwc1.h +++ b/services/surfaceflinger/DisplayHardware/HWComposer_hwc1.h @@ -62,7 +62,7 @@ public: friend class HWComposer; virtual void onVSyncReceived( HWComposer* composer, int32_t disp, nsecs_t timestamp) = 0; - virtual void onHotplugReceived(int disp, bool connected) = 0; + virtual void onHotplugReceived(HWComposer* composer, int disp, bool connected) = 0; virtual void onInvalidateReceived(HWComposer* composer) = 0; protected: virtual ~EventHandler() {} diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index c211c7b4ed..598a65a864 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -852,18 +852,12 @@ void Layer::setPerFrameData(const sp<const DisplayDevice>& displayDevice) { } uint32_t hwcSlot = 0; - buffer_handle_t hwcHandle = nullptr; - { - sp<GraphicBuffer> hwcBuffer; - hwcInfo.bufferCache.getHwcBuffer(mActiveBufferSlot, mActiveBuffer, - &hwcSlot, &hwcBuffer); - if (hwcBuffer != nullptr) { - hwcHandle = hwcBuffer->handle; - } - } + sp<GraphicBuffer> hwcBuffer; + hwcInfo.bufferCache.getHwcBuffer(mActiveBufferSlot, mActiveBuffer, + &hwcSlot, &hwcBuffer); auto acquireFence = mSurfaceFlingerConsumer->getCurrentFence(); - error = hwcLayer->setBuffer(hwcSlot, hwcHandle, acquireFence); + error = hwcLayer->setBuffer(hwcSlot, hwcBuffer, acquireFence); if (error != HWC2::Error::None) { ALOGE("[%s] Failed to set buffer %p: %s (%d)", mName.string(), mActiveBuffer->handle, to_string(error).c_str(), diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 26baaaecb2..d72b3b5a35 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -598,7 +598,7 @@ void SurfaceFlinger::init() { // make the GLContext current so that we can create textures when creating // Layers (which may happens before we render something) - getDefaultDisplayDevice()->makeCurrent(mEGLDisplay, mEGLContext); + getDefaultDisplayDeviceLocked()->makeCurrent(mEGLDisplay, mEGLContext); mEventControlThread = new EventControlThread(this); mEventControlThread->run("EventControl", PRIORITY_URGENT_DISPLAY); @@ -651,6 +651,25 @@ bool SurfaceFlinger::authenticateSurfaceTextureLocked( return mGraphicBufferProducerList.indexOf(surfaceTextureBinder) >= 0; } +status_t SurfaceFlinger::getSupportedFrameTimestamps( + std::vector<FrameEvent>* outSupported) const { + *outSupported = { + FrameEvent::REQUESTED_PRESENT, + FrameEvent::ACQUIRE, + FrameEvent::LATCH, + FrameEvent::FIRST_REFRESH_START, + FrameEvent::LAST_REFRESH_START, + FrameEvent::GPU_COMPOSITION_DONE, + FrameEvent::DEQUEUE_READY, + FrameEvent::RELEASE, + }; + if (!getHwComposer().hasCapability( + HWC2::Capability::PresentFenceIsNotReliable)) { + outSupported->push_back(FrameEvent::DISPLAY_PRESENT); + } + return NO_ERROR; +} + status_t SurfaceFlinger::getDisplayConfigs(const sp<IBinder>& display, Vector<DisplayInfo>* configs) { if ((configs == NULL) || (display.get() == NULL)) { @@ -714,8 +733,11 @@ status_t SurfaceFlinger::getDisplayConfigs(const sp<IBinder>& display, info.density = density; // TODO: this needs to go away (currently needed only by webkit) - sp<const DisplayDevice> hw(getDefaultDisplayDevice()); - info.orientation = hw->getOrientation(); + { + Mutex::Autolock _l(mStateLock); + sp<const DisplayDevice> hw(getDefaultDisplayDeviceLocked()); + info.orientation = hw->getOrientation(); + } } else { // TODO: where should this value come from? static const int TV_DENSITY = 213; @@ -772,10 +794,13 @@ int SurfaceFlinger::getActiveConfig(const sp<IBinder>& display) { ALOGE("%s : display is NULL", __func__); return BAD_VALUE; } + + Mutex::Autolock _l(mStateLock); sp<DisplayDevice> device(getDisplayDevice(display)); if (device != NULL) { return device->getActiveConfig(); } + return BAD_VALUE; } @@ -863,6 +888,7 @@ status_t SurfaceFlinger::getDisplayColorModes(const sp<IBinder>& display, } android_color_mode_t SurfaceFlinger::getActiveColorMode(const sp<IBinder>& display) { + Mutex::Autolock _l(mStateLock); sp<DisplayDevice> device(getDisplayDevice(display)); if (device != nullptr) { return device->getActiveColorMode(); @@ -1124,55 +1150,60 @@ void SurfaceFlinger::getCompositorTiming(CompositorTiming* compositorTiming) { *compositorTiming = mCompositorTiming; } -void SurfaceFlinger::onHotplugReceived(int32_t disp, bool connected) { - ALOGV("onHotplugReceived(%d, %s)", disp, connected ? "true" : "false"); - if (disp == DisplayDevice::DISPLAY_PRIMARY) { - Mutex::Autolock lock(mStateLock); +void SurfaceFlinger::createDefaultDisplayDevice() { + const int32_t type = DisplayDevice::DISPLAY_PRIMARY; + wp<IBinder> token = mBuiltinDisplays[type]; - // All non-virtual displays are currently considered secure. - bool isSecure = true; - - int32_t type = DisplayDevice::DISPLAY_PRIMARY; - - // When we're using the vr composer, the assumption is that we've - // already created the IBinder object for the primary display. - if (!mHwc->isUsingVrComposer()) { - createBuiltinDisplayLocked(DisplayDevice::DISPLAY_PRIMARY); + // All non-virtual displays are currently considered secure. + const bool isSecure = true; + + sp<IGraphicBufferProducer> producer; + sp<IGraphicBufferConsumer> consumer; + BufferQueue::createBufferQueue(&producer, &consumer, new GraphicBufferAlloc()); + + sp<FramebufferSurface> fbs = new FramebufferSurface(*mHwc, type, consumer); + + bool hasWideColorModes = false; + std::vector<android_color_mode_t> modes = getHwComposer().getColorModes( + type); + for (android_color_mode_t colorMode : modes) { + switch (colorMode) { + case HAL_COLOR_MODE_DISPLAY_P3: + case HAL_COLOR_MODE_ADOBE_RGB: + case HAL_COLOR_MODE_DCI_P3: + hasWideColorModes = true; + break; + default: + break; } + } + sp<DisplayDevice> hw = new DisplayDevice(this, DisplayDevice::DISPLAY_PRIMARY, type, isSecure, + token, fbs, producer, mRenderEngine->getEGLConfig(), + hasWideColorModes && hasWideColorDisplay); + mDisplays.add(token, hw); + android_color_mode defaultColorMode = HAL_COLOR_MODE_NATIVE; + if (hasWideColorModes && hasWideColorDisplay) { + defaultColorMode = HAL_COLOR_MODE_SRGB; + } + setActiveColorModeInternal(hw, defaultColorMode); +} - wp<IBinder> token = mBuiltinDisplays[type]; +void SurfaceFlinger::onHotplugReceived(HWComposer* composer, int32_t disp, bool connected) { + ALOGV("onHotplugReceived(%d, %s)", disp, connected ? "true" : "false"); - sp<IGraphicBufferProducer> producer; - sp<IGraphicBufferConsumer> consumer; - BufferQueue::createBufferQueue(&producer, &consumer, - new GraphicBufferAlloc()); - - sp<FramebufferSurface> fbs = new FramebufferSurface(*mHwc, - DisplayDevice::DISPLAY_PRIMARY, consumer); - - bool hasWideColorModes = false; - std::vector<android_color_mode_t> modes = getHwComposer().getColorModes(type); - for (android_color_mode_t colorMode : modes) { - switch (colorMode) { - case HAL_COLOR_MODE_DISPLAY_P3: - case HAL_COLOR_MODE_ADOBE_RGB: - case HAL_COLOR_MODE_DCI_P3: - hasWideColorModes = true; - break; - default: - break; - } - } - sp<DisplayDevice> hw = - new DisplayDevice(this, DisplayDevice::DISPLAY_PRIMARY, disp, isSecure, token, fbs, - producer, mRenderEngine->getEGLConfig(), - hasWideColorModes && hasWideColorDisplay); - mDisplays.add(token, hw); - android_color_mode defaultColorMode = HAL_COLOR_MODE_NATIVE; - if (hasWideColorModes && hasWideColorDisplay) { - defaultColorMode = HAL_COLOR_MODE_SRGB; + if (composer->isUsingVrComposer()) { + // We handle initializing the primary display device for the VR + // window manager hwc explicitly at the time of transition. + if (disp != DisplayDevice::DISPLAY_PRIMARY) { + ALOGE("External displays are not supported by the vr hardware composer."); } - setActiveColorModeInternal(hw, defaultColorMode); + return; + } + + if (disp == DisplayDevice::DISPLAY_PRIMARY) { + Mutex::Autolock lock(mStateLock); + createBuiltinDisplayLocked(DisplayDevice::DISPLAY_PRIMARY); + createDefaultDisplayDevice(); } else { auto type = DisplayDevice::DISPLAY_EXTERNAL; Mutex::Autolock _l(mStateLock); @@ -1214,6 +1245,7 @@ void SurfaceFlinger::clearHwcLayers(const LayerVector& layers) { } } +// Note: it is assumed the caller holds |mStateLock| when this is called void SurfaceFlinger::resetHwc() { disableHardwareVsync(true); clearHwcLayers(mDrawingState.layersSortedByZ); @@ -1234,36 +1266,46 @@ void SurfaceFlinger::updateVrFlinger() { if (vrFlingerRequestsDisplay == mHwc->isUsingVrComposer()) { return; } + + bool vrHwcNewlyInitialized = false; + if (vrFlingerRequestsDisplay && !mVrHwc) { // Construct new HWComposer without holding any locks. mVrHwc = new HWComposer(true); + vrHwcNewlyInitialized = true; ALOGV("Vr HWC created"); } - { - Mutex::Autolock _l(mStateLock); - if (vrFlingerRequestsDisplay) { - resetHwc(); + Mutex::Autolock _l(mStateLock); - mHwc = mVrHwc; - mVrFlinger->GrantDisplayOwnership(); - } else { - mVrFlinger->SeizeDisplayOwnership(); + if (vrFlingerRequestsDisplay) { + resetHwc(); - resetHwc(); + mHwc = mVrHwc; + mVrFlinger->GrantDisplayOwnership(); - mHwc = mRealHwc; - enableHardwareVsync(); + if (vrHwcNewlyInitialized) { + mVrHwc->setEventHandler( + static_cast<HWComposer::EventHandler*>(this)); } + } else { + mVrFlinger->SeizeDisplayOwnership(); - mVisibleRegionsDirty = true; - invalidateHwcGeometry(); - android_atomic_or(1, &mRepaintEverything); - setTransactionFlags(eDisplayTransactionNeeded); - } - if (mVrHwc) { - mVrHwc->setEventHandler(static_cast<HWComposer::EventHandler*>(this)); + resetHwc(); + + mHwc = mRealHwc; + enableHardwareVsync(); } + + mVisibleRegionsDirty = true; + invalidateHwcGeometry(); + + // Explicitly re-initialize the primary display. This is because some other + // parts of this class rely on the primary display always being available. + createDefaultDisplayDevice(); + + android_atomic_or(1, &mRepaintEverything); + setTransactionFlags(eDisplayTransactionNeeded); } void SurfaceFlinger::onMessageReceived(int32_t what) { @@ -1473,7 +1515,8 @@ void SurfaceFlinger::postComposition(nsecs_t refreshStartTime) layer->releasePendingBuffer(dequeueReadyTime); } - const sp<const DisplayDevice> hw(getDefaultDisplayDevice()); + // |mStateLock| not needed as we are on the main thread + const sp<const DisplayDevice> hw(getDefaultDisplayDeviceLocked()); std::shared_ptr<FenceTime> glCompositionDoneFenceTime; if (mHwc->hasClientComposition(HWC_DISPLAY_PRIMARY)) { @@ -1821,7 +1864,8 @@ void SurfaceFlinger::postFramebuffer() mLastSwapBufferTime = systemTime() - now; mDebugInSwapBuffers = 0; - uint32_t flipCount = getDefaultDisplayDevice()->getPageFlipCount(); + // |mStateLock| not needed as we are on the main thread + uint32_t flipCount = getDefaultDisplayDeviceLocked()->getPageFlipCount(); if (flipCount % LOG_FRAME_STATS_PERIOD == 0) { logFrameStats(); } @@ -1906,7 +1950,7 @@ void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags) // Call makeCurrent() on the primary display so we can // be sure that nothing associated with this display // is current. - const sp<const DisplayDevice> defaultDisplay(getDefaultDisplayDevice()); + const sp<const DisplayDevice> defaultDisplay(getDefaultDisplayDeviceLocked()); defaultDisplay->makeCurrent(mEGLDisplay, mEGLContext); sp<DisplayDevice> hw(getDisplayDevice(draw.keyAt(i))); if (hw != NULL) @@ -2096,7 +2140,7 @@ void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags) // could be null when this layer is using a layerStack // that is not visible on any display. Also can occur at // screen off/on times. - disp = getDefaultDisplayDevice(); + disp = getDefaultDisplayDeviceLocked(); } layer->updateTransformHint(disp); @@ -2452,7 +2496,9 @@ bool SurfaceFlinger::doComposeSurfaces( ALOGW("DisplayDevice::makeCurrent failed. Aborting surface composition for display %s", displayDevice->getDisplayName().string()); eglMakeCurrent(mEGLDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); - if(!getDefaultDisplayDevice()->makeCurrent(mEGLDisplay, mEGLContext)) { + + // |mStateLock| not needed as we are on the main thread + if(!getDefaultDisplayDeviceLocked()->makeCurrent(mEGLDisplay, mEGLContext)) { ALOGE("DisplayDevice::makeCurrent on default display failed. Aborting."); } return false; @@ -3539,7 +3585,7 @@ void SurfaceFlinger::dumpAllLocked(const Vector<String16>& args, size_t& index, colorizer.reset(result); HWComposer& hwc(getHwComposer()); - sp<const DisplayDevice> hw(getDefaultDisplayDevice()); + sp<const DisplayDevice> hw(getDefaultDisplayDeviceLocked()); colorizer.bold(result); result.appendFormat("EGL implementation : %s\n", @@ -3769,7 +3815,7 @@ status_t SurfaceFlinger::onTransact( return NO_ERROR; case 1013: { Mutex::Autolock _l(mStateLock); - sp<const DisplayDevice> hw(getDefaultDisplayDevice()); + sp<const DisplayDevice> hw(getDefaultDisplayDeviceLocked()); reply->writeInt32(hw->getPageFlipCount()); return NO_ERROR; } diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 46121cfa63..e15c6ffbf7 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -184,8 +184,9 @@ public: void repaintEverything(); // returns the default Display - sp<const DisplayDevice> getDefaultDisplayDevice() const { - return getDisplayDevice(mBuiltinDisplays[DisplayDevice::DISPLAY_PRIMARY]); + sp<const DisplayDevice> getDefaultDisplayDevice() { + Mutex::Autolock _l(mStateLock); + return getDefaultDisplayDeviceLocked(); } // utility function to delete a texture on the main thread @@ -265,6 +266,8 @@ private: virtual void bootFinished(); virtual bool authenticateSurfaceTexture( const sp<IGraphicBufferProducer>& bufferProducer) const; + virtual status_t getSupportedFrameTimestamps( + std::vector<FrameEvent>* outSupported) const; virtual sp<IDisplayEventConnection> createDisplayEventConnection(); virtual status_t captureScreen(const sp<IBinder>& display, const sp<IGraphicBufferProducer>& producer, @@ -304,7 +307,7 @@ private: * HWComposer::EventHandler interface */ virtual void onVSyncReceived(HWComposer* composer, int type, nsecs_t timestamp); - virtual void onHotplugReceived(int disp, bool connected); + virtual void onHotplugReceived(HWComposer* composer, int disp, bool connected); virtual void onInvalidateReceived(HWComposer* composer); /* ------------------------------------------------------------------------ @@ -439,6 +442,12 @@ private: return mDisplays.valueFor(dpy); } + sp<const DisplayDevice> getDefaultDisplayDeviceLocked() const { + return getDisplayDevice(mBuiltinDisplays[DisplayDevice::DISPLAY_PRIMARY]); + } + + void createDefaultDisplayDevice(); + int32_t getDisplayType(const sp<IBinder>& display) { if (!display.get()) return NAME_NOT_FOUND; for (int i = 0; i < DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES; ++i) { diff --git a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp index e640ef71ee..a9000c07a8 100644 --- a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp +++ b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp @@ -584,7 +584,7 @@ void SurfaceFlinger::init() { // make the GLContext current so that we can create textures when creating Layers // (which may happens before we render something) - getDefaultDisplayDevice()->makeCurrent(mEGLDisplay, mEGLContext); + getDefaultDisplayDeviceLocked()->makeCurrent(mEGLDisplay, mEGLContext); mEventControlThread = new EventControlThread(this); mEventControlThread->run("EventControl", PRIORITY_URGENT_DISPLAY); @@ -647,6 +647,21 @@ bool SurfaceFlinger::authenticateSurfaceTextureLocked( return mGraphicBufferProducerList.indexOf(surfaceTextureBinder) >= 0; } +status_t SurfaceFlinger::getSupportedFrameTimestamps( + std::vector<FrameEvent>* outSupported) const { + *outSupported = { + FrameEvent::REQUESTED_PRESENT, + FrameEvent::ACQUIRE, + FrameEvent::LATCH, + FrameEvent::FIRST_REFRESH_START, + FrameEvent::LAST_REFRESH_START, + FrameEvent::GPU_COMPOSITION_DONE, + FrameEvent::DEQUEUE_READY, + FrameEvent::RELEASE, + }; + return NO_ERROR; +} + status_t SurfaceFlinger::getDisplayConfigs(const sp<IBinder>& display, Vector<DisplayInfo>* configs) { if ((configs == NULL) || (display.get() == NULL)) { @@ -1040,7 +1055,7 @@ void SurfaceFlinger::getCompositorTiming(CompositorTiming* compositorTiming) { *compositorTiming = mCompositorTiming; } -void SurfaceFlinger::onHotplugReceived(int type, bool connected) { +void SurfaceFlinger::onHotplugReceived(HWComposer* /*composer*/, int type, bool connected) { if (mEventThread == NULL) { // This is a temporary workaround for b/7145521. A non-null pointer // does not mean EventThread has finished initializing, so this @@ -3222,7 +3237,7 @@ void SurfaceFlinger::dumpAllLocked(const Vector<String16>& args, size_t& index, colorizer.reset(result); HWComposer& hwc(getHwComposer()); - sp<const DisplayDevice> hw(getDefaultDisplayDevice()); + sp<const DisplayDevice> hw(getDefaultDisplayDeviceLocked()); colorizer.bold(result); result.appendFormat("EGL implementation : %s\n", diff --git a/services/surfaceflinger/main_surfaceflinger.cpp b/services/surfaceflinger/main_surfaceflinger.cpp index f151087676..d15376e6bb 100644 --- a/services/surfaceflinger/main_surfaceflinger.cpp +++ b/services/surfaceflinger/main_surfaceflinger.cpp @@ -18,17 +18,44 @@ #include <sched.h> +#include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h> +#include <android/hardware/graphics/allocator/2.0/IAllocator.h> #include <cutils/sched_policy.h> #include <binder/IServiceManager.h> #include <binder/IPCThreadState.h> #include <binder/ProcessState.h> #include <binder/IServiceManager.h> +#include <hidl/LegacySupport.h> +#include <configstore/Utils.h> #include "GpuService.h" #include "SurfaceFlinger.h" using namespace android; +using android::hardware::graphics::allocator::V2_0::IAllocator; +using android::hardware::configstore::V1_0::ISurfaceFlingerConfigs; +using android::hardware::configstore::getBool; +using android::hardware::configstore::getBool; + +static status_t startGraphicsAllocatorService() { + hardware::configureRpcThreadpool( 1 /* maxThreads */, + false /* callerWillJoin */); + status_t result = + hardware::registerPassthroughServiceImplementation<IAllocator>(); + if (result != OK) { + ALOGE("could not start graphics allocator service"); + return result; + } + + return OK; +} + int main(int, char**) { + if (getBool<ISurfaceFlingerConfigs, + &ISurfaceFlingerConfigs::startGraphicsAllocatorService>(false)) { + startGraphicsAllocatorService(); + } + signal(SIGPIPE, SIG_IGN); // When SF is launched in its own process, limit the number of // binder threads to 4. diff --git a/services/vr/bufferhubd/buffer_hub.cpp b/services/vr/bufferhubd/buffer_hub.cpp index 2ce60e57ac..4b1a522793 100644 --- a/services/vr/bufferhubd/buffer_hub.cpp +++ b/services/vr/bufferhubd/buffer_hub.cpp @@ -1,5 +1,6 @@ #include "buffer_hub.h" +#include <inttypes.h> #include <log/log.h> #include <poll.h> #include <utils/Trace.h> @@ -52,7 +53,7 @@ std::string BufferHubService::DumpState(size_t /*max_length*/) { stream << " "; stream << std::setw(6) << "Format"; stream << " "; - stream << std::setw(10) << "Usage"; + stream << std::setw(21) << "Usage"; stream << " "; stream << "Name"; stream << std::endl; @@ -79,7 +80,9 @@ std::string BufferHubService::DumpState(size_t /*max_length*/) { stream << std::setw(6) << info.format; stream << " "; stream << "0x" << std::hex << std::setfill('0'); - stream << std::setw(8) << info.usage; + stream << std::setw(8) << info.producer_usage; + stream << "0x"; + stream << std::setw(8) << info.consumer_usage; stream << std::dec << std::setfill(' '); stream << " "; stream << info.name; @@ -137,6 +140,10 @@ std::string BufferHubService::DumpState(size_t /*max_length*/) { stream << " UsageClearMask"; stream << " UsageDenySetMask"; stream << " UsageDenyClearMask"; + stream << " UsageSetMask"; + stream << " UsageClearMask"; + stream << " UsageDenySetMask"; + stream << " UsageDenyClearMask"; stream << " "; stream << std::endl; @@ -150,16 +157,30 @@ std::string BufferHubService::DumpState(size_t /*max_length*/) { stream << std::right << std::setw(12) << info.consumer_count; stream << std::setw(5) << std::setfill(' ') << "0x"; stream << std::hex << std::setfill('0'); - stream << std::setw(8) << info.usage_set_mask; + stream << std::setw(8) << info.usage_policy.producer_set_mask; + stream << std::setw(7) << std::setfill(' ') << "0x"; + stream << std::hex << std::setfill('0'); + stream << std::setw(8) << info.usage_policy.producer_clear_mask; + stream << std::setw(9) << std::setfill(' ') << "0x"; + stream << std::hex << std::setfill('0'); + stream << std::setw(8) << info.usage_policy.producer_deny_set_mask; + stream << std::setw(11) << std::setfill(' ') << "0x"; + stream << std::hex << std::setfill('0'); + stream << std::setw(8) << info.usage_policy.producer_deny_clear_mask; + stream << std::setw(5) << std::setfill(' ') << "0x"; + stream << std::hex << std::setfill('0'); + stream << std::setw(8) << info.usage_policy.consumer_set_mask; stream << std::setw(7) << std::setfill(' ') << "0x"; stream << std::hex << std::setfill('0'); - stream << std::setw(8) << info.usage_clear_mask; + stream << std::setw(8) << info.usage_policy.consumer_clear_mask; stream << std::setw(9) << std::setfill(' ') << "0x"; stream << std::hex << std::setfill('0'); - stream << std::setw(8) << info.usage_deny_set_mask; + stream << std::setw(8) << info.usage_policy.consumer_deny_set_mask; stream << std::setw(11) << std::setfill(' ') << "0x"; stream << std::hex << std::setfill('0'); - stream << std::setw(8) << info.usage_deny_clear_mask; + stream << std::setw(8) << info.usage_policy.consumer_deny_clear_mask; + stream << std::hex << std::setfill('0'); + stream << std::endl; } } @@ -177,6 +198,7 @@ std::string BufferHubService::DumpState(size_t /*max_length*/) { stream << std::right << std::setw(6) << info.id; stream << std::right << std::setw(12) << info.capacity; + stream << std::endl; } } @@ -235,48 +257,53 @@ void BufferHubService::OnChannelClose(Message&, buffer->Detach(); } -int BufferHubService::OnCreateBuffer(Message& message, int width, int height, - int format, int usage, - size_t meta_size_bytes, - size_t slice_count) { +Status<void> BufferHubService::OnCreateBuffer(Message& message, uint32_t width, + uint32_t height, uint32_t format, + uint64_t producer_usage, + uint64_t consumer_usage, + size_t meta_size_bytes, + size_t slice_count) { // Use the producer channel id as the global buffer id. const int buffer_id = message.GetChannelId(); ALOGD_IF(TRACE, - "BufferHubService::OnCreateBuffer: buffer_id=%d width=%d height=%d " - "format=%d usage=%d meta_size_bytes=%zu slice_count=%zu", - buffer_id, width, height, format, usage, meta_size_bytes, - slice_count); + "BufferHubService::OnCreateBuffer: buffer_id=%d width=%u height=%u " + "format=%u producer_usage=%" PRIx64 " consumer_usage=%" PRIx64 + " meta_size_bytes=%zu slice_count=%zu", + buffer_id, width, height, format, producer_usage, consumer_usage, + meta_size_bytes, slice_count); // See if this channel is already attached to a buffer. if (const auto channel = message.GetChannel<BufferHubChannel>()) { ALOGE("BufferHubService::OnCreateBuffer: Buffer already created: buffer=%d", buffer_id); - return -EALREADY; + return ErrorStatus(EALREADY); } - int error; - if (const auto producer_channel = - ProducerChannel::Create(this, buffer_id, width, height, format, usage, - meta_size_bytes, slice_count, &error)) { - message.SetChannel(producer_channel); - return 0; + auto status = ProducerChannel::Create(this, buffer_id, width, height, format, + producer_usage, consumer_usage, + meta_size_bytes, slice_count); + if (status) { + message.SetChannel(status.take()); + return {}; } else { - ALOGE("BufferHubService::OnCreateBuffer: Failed to create producer!!"); - return error; + ALOGE("BufferHubService::OnCreateBuffer: Failed to create producer: %s", + status.GetErrorMessage().c_str()); + return status.error_status(); } } -int BufferHubService::OnCreatePersistentBuffer( +Status<void> BufferHubService::OnCreatePersistentBuffer( Message& message, const std::string& name, int user_id, int group_id, - int width, int height, int format, int usage, size_t meta_size_bytes, - size_t slice_count) { + uint32_t width, uint32_t height, uint32_t format, uint64_t producer_usage, + uint64_t consumer_usage, size_t meta_size_bytes, size_t slice_count) { const int channel_id = message.GetChannelId(); ALOGD_IF(TRACE, "BufferHubService::OnCreatePersistentBuffer: channel_id=%d name=%s " - "user_id=%d group_id=%d width=%d height=%d format=%d usage=%d " - "meta_size_bytes=%zu slice_count=%zu", + "user_id=%d group_id=%d width=%u height=%u format=%u " + "producer_usage=%" PRIx64 " consumer_usage=%" PRIx64 + " meta_size_bytes=%zu slice_count=%zu", channel_id, name.c_str(), user_id, group_id, width, height, format, - usage, meta_size_bytes, slice_count); + producer_usage, consumer_usage, meta_size_bytes, slice_count); // See if this channel is already attached to a buffer. if (const auto channel = message.GetChannel<BufferHubChannel>()) { @@ -284,12 +311,11 @@ int BufferHubService::OnCreatePersistentBuffer( "BufferHubService::OnCreatePersistentBuffer: Channel already attached " "to buffer: channel_id=%d buffer_id=%d", channel_id, channel->buffer_id()); - return -EALREADY; + return ErrorStatus(EALREADY); } const int euid = message.GetEffectiveUserId(); const int egid = message.GetEffectiveGroupId(); - int error; if (auto buffer = GetNamedBuffer(name)) { if (!buffer->CheckAccess(euid, egid)) { @@ -297,41 +323,45 @@ int BufferHubService::OnCreatePersistentBuffer( "BufferHubService::OnCreatePersistentBuffer: Requesting process does " "not have permission to access named buffer: name=%s euid=%d egid=%d", name.c_str(), euid, euid); - return -EPERM; - } else if (!buffer->CheckParameters(width, height, format, usage, - meta_size_bytes, slice_count)) { + return ErrorStatus(EPERM); + } else if (!buffer->CheckParameters(width, height, format, producer_usage, + consumer_usage, meta_size_bytes, + slice_count)) { ALOGE( "BufferHubService::OnCreatePersistentBuffer: Requested an existing " "buffer with different parameters: name=%s", name.c_str()); - return -EINVAL; + return ErrorStatus(EINVAL); } else if (!buffer->IsDetached()) { ALOGE( "BufferHubService::OnCreatePersistentBuffer: Requesting a persistent " "buffer that is already attached to a channel: name=%s", name.c_str()); - return -EINVAL; + return ErrorStatus(EINVAL); } else { buffer->Attach(channel_id); message.SetChannel(buffer); - return 0; + return {}; } - } else if (auto buffer = ProducerChannel::Create( - this, channel_id, width, height, format, usage, - meta_size_bytes, slice_count, &error)) { - const int ret = - buffer->OnProducerMakePersistent(message, name, user_id, group_id); - if (!ret) - message.SetChannel(buffer); - return ret; } else { - ALOGE("BufferHubService::OnCreateBuffer: Failed to create producer!!"); - return error; + auto status = ProducerChannel::Create( + this, channel_id, width, height, format, producer_usage, consumer_usage, + meta_size_bytes, slice_count); + if (!status) { + ALOGE("BufferHubService::OnCreateBuffer: Failed to create producer!!"); + return status.error_status(); + } + auto persistent_buffer = status.take(); + auto make_persistent_status = persistent_buffer->OnProducerMakePersistent( + message, name, user_id, group_id); + if (make_persistent_status) + message.SetChannel(persistent_buffer); + return make_persistent_status; } } -int BufferHubService::OnGetPersistentBuffer(Message& message, - const std::string& name) { +Status<void> BufferHubService::OnGetPersistentBuffer(Message& message, + const std::string& name) { const int channel_id = message.GetChannelId(); ALOGD_IF(TRACE, "BufferHubService::OnGetPersistentBuffer: channel_id=%d name=%s", @@ -343,7 +373,7 @@ int BufferHubService::OnGetPersistentBuffer(Message& message, "BufferHubService::OnGetPersistentBuffer: Channel already attached to " "buffer: channel_id=%d buffer_id=%d", channel_id, channel->buffer_id()); - return -EALREADY; + return ErrorStatus(EALREADY); } const int euid = message.GetEffectiveUserId(); @@ -355,28 +385,28 @@ int BufferHubService::OnGetPersistentBuffer(Message& message, "BufferHubService::OnGetPersistentBuffer: Requesting process does " "not have permission to access named buffer: name=%s euid=%d egid=%d", name.c_str(), euid, egid); - return -EPERM; + return ErrorStatus(EPERM); } else if (!buffer->IsDetached()) { ALOGE( "BufferHubService::OnGetPersistentBuffer: Requesting a persistent " "buffer that is already attached to a channel: name=%s", name.c_str()); - return -EINVAL; + return ErrorStatus(EINVAL); } else { buffer->Attach(channel_id); message.SetChannel(buffer); - return 0; + return {}; } } else { ALOGE("BufferHubService::OnGetPersistentBuffer: Buffer \"%s\" not found!", name.c_str()); - return -ENOENT; + return ErrorStatus(ENOENT); } } Status<QueueInfo> BufferHubService::OnCreateProducerQueue( - pdx::Message& message, size_t meta_size_bytes, int usage_set_mask, - int usage_clear_mask, int usage_deny_set_mask, int usage_deny_clear_mask) { + pdx::Message& message, size_t meta_size_bytes, + const UsagePolicy& usage_policy) { // Use the producer channel id as the global queue id. const int queue_id = message.GetChannelId(); ALOGD_IF(TRACE, "BufferHubService::OnCreateProducerQueue: queue_id=%d", @@ -389,15 +419,14 @@ Status<QueueInfo> BufferHubService::OnCreateProducerQueue( return ErrorStatus(EALREADY); } - int error; - if (const auto producer_channel = ProducerQueueChannel::Create( - this, queue_id, meta_size_bytes, usage_set_mask, usage_clear_mask, - usage_deny_set_mask, usage_deny_clear_mask, &error)) { - message.SetChannel(producer_channel); + auto status = ProducerQueueChannel::Create(this, queue_id, meta_size_bytes, + usage_policy); + if (status) { + message.SetChannel(status.take()); return {{meta_size_bytes, queue_id}}; } else { ALOGE("BufferHubService::OnCreateBuffer: Failed to create producer!!"); - return ErrorStatus(-error); + return status.error_status(); } } diff --git a/services/vr/bufferhubd/buffer_hub.h b/services/vr/bufferhubd/buffer_hub.h index 150e399cdd..4cb1eb93d8 100644 --- a/services/vr/bufferhubd/buffer_hub.h +++ b/services/vr/bufferhubd/buffer_hub.h @@ -48,43 +48,40 @@ class BufferHubChannel : public pdx::Channel { size_t consumer_count = 0; // Data field for buffer producer. - int width = 0; - int height = 0; - int format = 0; - int usage = 0; + uint32_t width = 0; + uint32_t height = 0; + uint32_t format = 0; + uint64_t producer_usage = 0; + uint64_t consumer_usage = 0; size_t slice_count = 0; std::string name; // Data filed for producer queue. size_t capacity = 0; - int usage_set_mask = 0; - int usage_clear_mask = 0; - int usage_deny_set_mask = 0; - int usage_deny_clear_mask = 0; + UsagePolicy usage_policy{0, 0, 0, 0, 0, 0, 0, 0}; - BufferInfo(int id, size_t consumer_count, int width, int height, int format, - int usage, size_t slice_count, const std::string& name) + BufferInfo(int id, size_t consumer_count, uint32_t width, uint32_t height, + uint32_t format, uint64_t producer_usage, + uint64_t consumer_usage, size_t slice_count, + const std::string& name) : id(id), type(kProducerType), consumer_count(consumer_count), width(width), height(height), format(format), - usage(usage), + producer_usage(producer_usage), + consumer_usage(consumer_usage), slice_count(slice_count), name(name) {} BufferInfo(int id, size_t consumer_count, size_t capacity, - int usage_set_mask, int usage_clear_mask, - int usage_deny_set_mask, int usage_deny_clear_mask) + const UsagePolicy& usage_policy) : id(id), type(kProducerQueueType), consumer_count(consumer_count), capacity(capacity), - usage_set_mask(usage_set_mask), - usage_clear_mask(usage_clear_mask), - usage_deny_set_mask(usage_deny_set_mask), - usage_deny_clear_mask(usage_deny_clear_mask) {} + usage_policy(usage_policy) {} BufferInfo() {} }; @@ -162,16 +159,19 @@ class BufferHubService : public pdx::ServiceBase<BufferHubService> { std::unordered_map<std::string, std::shared_ptr<ProducerChannel>> named_buffers_; - int OnCreateBuffer(pdx::Message& message, int width, int height, int format, - int usage, size_t meta_size_bytes, size_t slice_count); - int OnCreatePersistentBuffer(pdx::Message& message, const std::string& name, - int user_id, int group_id, int width, int height, - int format, int usage, size_t meta_size_bytes, - size_t slice_count); - int OnGetPersistentBuffer(pdx::Message& message, const std::string& name); - pdx::Status<QueueInfo> OnCreateProducerQueue( - pdx::Message& message, size_t meta_size_bytes, int usage_set_mask, - int usage_clear_mask, int usage_deny_set_mask, int usage_deny_clear_mask); + pdx::Status<void> OnCreateBuffer(pdx::Message& message, uint32_t width, uint32_t height, + uint32_t format, uint64_t producer_usage, + uint64_t consumer_usage, size_t meta_size_bytes, + size_t slice_count); + pdx::Status<void> OnCreatePersistentBuffer(pdx::Message& message, const std::string& name, + int user_id, int group_id, uint32_t width, + uint32_t height, uint32_t format, + uint64_t producer_usage, uint64_t consumer_usage, + size_t meta_size_bytes, size_t slice_count); + pdx::Status<void> OnGetPersistentBuffer(pdx::Message& message, const std::string& name); + pdx::Status<QueueInfo> OnCreateProducerQueue(pdx::Message& message, + size_t meta_size_bytes, + const UsagePolicy& usage_policy); BufferHubService(const BufferHubService&) = delete; void operator=(const BufferHubService&) = delete; diff --git a/services/vr/bufferhubd/consumer_channel.cpp b/services/vr/bufferhubd/consumer_channel.cpp index 2264cef785..311f5c6ab4 100644 --- a/services/vr/bufferhubd/consumer_channel.cpp +++ b/services/vr/bufferhubd/consumer_channel.cpp @@ -8,9 +8,11 @@ #include <private/dvr/bufferhub_rpc.h> #include "producer_channel.h" +using android::pdx::ErrorStatus; using android::pdx::BorrowedHandle; using android::pdx::Channel; using android::pdx::Message; +using android::pdx::Status; using android::pdx::rpc::DispatchRemoteMethod; namespace android { @@ -103,53 +105,53 @@ bool ConsumerChannel::HandleMessage(Message& message) { } } -std::pair<BorrowedFence, ConsumerChannel::MetaData> +Status<std::pair<BorrowedFence, ConsumerChannel::MetaData>> ConsumerChannel::OnConsumerAcquire(Message& message, std::size_t metadata_size) { ATRACE_NAME("ConsumerChannel::OnConsumerAcquire"); auto producer = GetProducer(); if (!producer) - REPLY_ERROR_RETURN(message, EPIPE, {}); + return ErrorStatus(EPIPE); if (ignored_ || handled_) { ALOGE( "ConsumerChannel::OnConsumerAcquire: Acquire when not posted: " "ignored=%d handled=%d channel_id=%d buffer_id=%d", ignored_, handled_, message.GetChannelId(), producer->buffer_id()); - REPLY_ERROR_RETURN(message, EBUSY, {}); + return ErrorStatus(EBUSY); } else { ClearAvailable(); return producer->OnConsumerAcquire(message, metadata_size); } } -int ConsumerChannel::OnConsumerRelease(Message& message, - LocalFence release_fence) { +Status<void> ConsumerChannel::OnConsumerRelease(Message& message, + LocalFence release_fence) { ATRACE_NAME("ConsumerChannel::OnConsumerRelease"); auto producer = GetProducer(); if (!producer) - return -EPIPE; + return ErrorStatus(EPIPE); if (ignored_ || handled_) { ALOGE( "ConsumerChannel::OnConsumerRelease: Release when not acquired: " "ignored=%d handled=%d channel_id=%d buffer_id=%d", ignored_, handled_, message.GetChannelId(), producer->buffer_id()); - return -EBUSY; + return ErrorStatus(EBUSY); } else { ClearAvailable(); - const int ret = + auto status = producer->OnConsumerRelease(message, std::move(release_fence)); - handled_ = ret == 0; - return ret; + handled_ = !!status; + return status; } } -int ConsumerChannel::OnConsumerSetIgnore(Message&, bool ignored) { +Status<void> ConsumerChannel::OnConsumerSetIgnore(Message&, bool ignored) { ATRACE_NAME("ConsumerChannel::OnConsumerSetIgnore"); auto producer = GetProducer(); if (!producer) - return -EPIPE; + return ErrorStatus(EPIPE); ignored_ = ignored; if (ignored_ && !handled_) { @@ -160,7 +162,7 @@ int ConsumerChannel::OnConsumerSetIgnore(Message&, bool ignored) { handled_ = false; } - return 0; + return {}; } bool ConsumerChannel::OnProducerPosted() { diff --git a/services/vr/bufferhubd/consumer_channel.h b/services/vr/bufferhubd/consumer_channel.h index d2a078f6cf..d84055c146 100644 --- a/services/vr/bufferhubd/consumer_channel.h +++ b/services/vr/bufferhubd/consumer_channel.h @@ -32,10 +32,11 @@ class ConsumerChannel : public BufferHubChannel { std::shared_ptr<ProducerChannel> GetProducer() const; - std::pair<BorrowedFence, MetaData> OnConsumerAcquire( + pdx::Status<std::pair<BorrowedFence, MetaData>> OnConsumerAcquire( Message& message, std::size_t metadata_size); - int OnConsumerRelease(Message& message, LocalFence release_fence); - int OnConsumerSetIgnore(Message& message, bool ignore); + pdx::Status<void> OnConsumerRelease(Message& message, + LocalFence release_fence); + pdx::Status<void> OnConsumerSetIgnore(Message& message, bool ignore); bool handled_; // True if we have processed RELEASE. bool ignored_; // True if we are ignoring events. diff --git a/services/vr/bufferhubd/consumer_queue_channel.cpp b/services/vr/bufferhubd/consumer_queue_channel.cpp index cc16f1f483..7422751030 100644 --- a/services/vr/bufferhubd/consumer_queue_channel.cpp +++ b/services/vr/bufferhubd/consumer_queue_channel.cpp @@ -4,7 +4,9 @@ #include "producer_channel.h" +using android::pdx::ErrorStatus; using android::pdx::RemoteChannelHandle; +using android::pdx::Status; using android::pdx::rpc::DispatchRemoteMethod; namespace android { @@ -83,7 +85,7 @@ void ConsumerQueueChannel::RegisterNewBuffer( SignalAvailable(); } -std::vector<std::pair<RemoteChannelHandle, size_t>> +Status<std::vector<std::pair<RemoteChannelHandle, size_t>>> ConsumerQueueChannel::OnConsumerQueueImportBuffers(Message& message) { std::vector<std::pair<RemoteChannelHandle, size_t>> buffer_handles; ATRACE_NAME("ConsumerQueueChannel::OnConsumerQueueImportBuffers"); @@ -106,31 +108,30 @@ ConsumerQueueChannel::OnConsumerQueueImportBuffers(Message& message) { continue; } - RemoteChannelHandle consumer_handle( - producer_channel->CreateConsumer(message)); + auto status = producer_channel->CreateConsumer(message); // If no buffers are imported successfully, clear available and return an // error. Otherwise, return all consumer handles already imported // successfully, but keep available bits on, so that the client can retry // importing remaining consumer buffers. - if (!consumer_handle.valid()) { + if (!status) { ALOGE( - "ConsumerQueueChannel::OnConsumerQueueImportBuffers: imported " - "consumer handle is invalid."); + "ConsumerQueueChannel::OnConsumerQueueImportBuffers: Failed create " + "consumer: %s", + status.GetErrorMessage().c_str()); if (buffer_handles.empty()) { ClearAvailable(); - REPLY_ERROR_RETURN(message, EIO, {}); + return status.error_status(); } else { - return buffer_handles; + return {std::move(buffer_handles)}; } } - // Move consumer_handle into buffer_handles. - buffer_handles.emplace_back(std::move(consumer_handle), producer_slot); + buffer_handles.emplace_back(status.take(), producer_slot); } ClearAvailable(); - return buffer_handles; + return {std::move(buffer_handles)}; } } // namespace dvr diff --git a/services/vr/bufferhubd/consumer_queue_channel.h b/services/vr/bufferhubd/consumer_queue_channel.h index b345595865..e1005e4789 100644 --- a/services/vr/bufferhubd/consumer_queue_channel.h +++ b/services/vr/bufferhubd/consumer_queue_channel.h @@ -36,7 +36,7 @@ class ConsumerQueueChannel : public BufferHubChannel { // allocated. Clients uses kOpConsumerQueueImportBuffers to import new // consumer buffers and this handler returns a vector of fd representing // BufferConsumers that clients can import. - std::vector<std::pair<RemoteChannelHandle, size_t>> + pdx::Status<std::vector<std::pair<RemoteChannelHandle, size_t>>> OnConsumerQueueImportBuffers(Message& message); private: diff --git a/services/vr/bufferhubd/producer_channel.cpp b/services/vr/bufferhubd/producer_channel.cpp index 903d17464a..c946a8d6b0 100644 --- a/services/vr/bufferhubd/producer_channel.cpp +++ b/services/vr/bufferhubd/producer_channel.cpp @@ -13,8 +13,10 @@ #include "consumer_channel.h" using android::pdx::BorrowedHandle; +using android::pdx::ErrorStatus; using android::pdx::Message; using android::pdx::RemoteChannelHandle; +using android::pdx::Status; using android::pdx::rpc::BufferWrapper; using android::pdx::rpc::DispatchRemoteMethod; using android::pdx::rpc::WrapBuffer; @@ -23,7 +25,9 @@ namespace android { namespace dvr { ProducerChannel::ProducerChannel(BufferHubService* service, int channel_id, - int width, int height, int format, int usage, + uint32_t width, uint32_t height, + uint32_t format, uint64_t producer_usage, + uint64_t consumer_usage, size_t meta_size_bytes, size_t slice_count, int* error) : BufferHubChannel(service, channel_id, channel_id, kProducerType), @@ -33,7 +37,8 @@ ProducerChannel::ProducerChannel(BufferHubService* service, int channel_id, meta_size_bytes_(meta_size_bytes), meta_(meta_size_bytes ? new uint8_t[meta_size_bytes] : nullptr) { for (auto& ion_buffer : slices_) { - const int ret = ion_buffer.Alloc(width, height, format, usage); + const int ret = + ion_buffer.Alloc(width, height, format, producer_usage, consumer_usage); if (ret < 0) { ALOGE("ProducerChannel::ProducerChannel: Failed to allocate buffer: %s", strerror(-ret)); @@ -46,17 +51,18 @@ ProducerChannel::ProducerChannel(BufferHubService* service, int channel_id, *error = 0; } -std::shared_ptr<ProducerChannel> ProducerChannel::Create( - BufferHubService* service, int channel_id, int width, int height, - int format, int usage, size_t meta_size_bytes, size_t slice_count, - int* error) { - std::shared_ptr<ProducerChannel> producer( - new ProducerChannel(service, channel_id, width, height, format, usage, - meta_size_bytes, slice_count, error)); - if (*error < 0) - return nullptr; +Status<std::shared_ptr<ProducerChannel>> ProducerChannel::Create( + BufferHubService* service, int channel_id, uint32_t width, uint32_t height, + uint32_t format, uint64_t producer_usage, uint64_t consumer_usage, + size_t meta_size_bytes, size_t slice_count) { + int error; + std::shared_ptr<ProducerChannel> producer(new ProducerChannel( + service, channel_id, width, height, format, producer_usage, + consumer_usage, meta_size_bytes, slice_count, &error)); + if (error < 0) + return ErrorStatus(-error); else - return producer; + return {std::move(producer)}; } ProducerChannel::~ProducerChannel() { @@ -70,7 +76,8 @@ ProducerChannel::~ProducerChannel() { BufferHubChannel::BufferInfo ProducerChannel::GetBufferInfo() const { return BufferInfo(buffer_id(), consumer_channels_.size(), slices_[0].width(), slices_[0].height(), slices_[0].format(), - slices_[0].usage(), slices_.size(), name_); + slices_[0].producer_usage(), slices_[0].consumer_usage(), + slices_.size(), name_); } void ProducerChannel::HandleImpulse(Message& message) { @@ -125,28 +132,28 @@ bool ProducerChannel::HandleMessage(Message& message) { } } -NativeBufferHandle<BorrowedHandle> ProducerChannel::OnGetBuffer( +Status<NativeBufferHandle<BorrowedHandle>> ProducerChannel::OnGetBuffer( Message& message, unsigned index) { ATRACE_NAME("ProducerChannel::OnGetBuffer"); ALOGD_IF(TRACE, "ProducerChannel::OnGetBuffer: buffer=%d", buffer_id()); if (index < slices_.size()) { - return NativeBufferHandle<BorrowedHandle>(slices_[index], buffer_id()); + return {NativeBufferHandle<BorrowedHandle>(slices_[index], buffer_id())}; } else { - REPLY_ERROR_RETURN(message, EINVAL, NativeBufferHandle<BorrowedHandle>()); + return ErrorStatus(EINVAL); } } -std::vector<NativeBufferHandle<BorrowedHandle>> ProducerChannel::OnGetBuffers( - Message&) { +Status<std::vector<NativeBufferHandle<BorrowedHandle>>> +ProducerChannel::OnGetBuffers(Message&) { ATRACE_NAME("ProducerChannel::OnGetBuffers"); ALOGD_IF(TRACE, "ProducerChannel::OnGetBuffers: buffer_id=%d", buffer_id()); std::vector<NativeBufferHandle<BorrowedHandle>> buffer_handles; for (const auto& buffer : slices_) buffer_handles.emplace_back(buffer, buffer_id()); - return buffer_handles; + return {std::move(buffer_handles)}; } -RemoteChannelHandle ProducerChannel::CreateConsumer(Message& message) { +Status<RemoteChannelHandle> ProducerChannel::CreateConsumer(Message& message) { ATRACE_NAME("ProducerChannel::CreateConsumer"); ALOGD_IF(TRACE, "ProducerChannel::CreateConsumer: buffer_id=%d", buffer_id()); @@ -154,9 +161,9 @@ RemoteChannelHandle ProducerChannel::CreateConsumer(Message& message) { auto status = message.PushChannel(0, nullptr, &channel_id); if (!status) { ALOGE( - "ProducerChannel::CreateConsumer: failed to push consumer channel: %s", + "ProducerChannel::CreateConsumer: Failed to push consumer channel: %s", status.GetErrorMessage().c_str()); - return RemoteChannelHandle(); + return ErrorStatus(ENOMEM); } auto consumer = std::make_shared<ConsumerChannel>( @@ -167,7 +174,7 @@ RemoteChannelHandle ProducerChannel::CreateConsumer(Message& message) { "ProducerChannel::CreateConsumer: failed to set new consumer channel: " "%s", channel_status.GetErrorMessage().c_str()); - return RemoteChannelHandle(); + return ErrorStatus(ENOMEM); } if (!producer_owns_) { @@ -176,33 +183,27 @@ RemoteChannelHandle ProducerChannel::CreateConsumer(Message& message) { pending_consumers_++; } - return status.take(); + return {status.take()}; } -RemoteChannelHandle ProducerChannel::OnNewConsumer(Message& message) { +Status<RemoteChannelHandle> ProducerChannel::OnNewConsumer(Message& message) { ATRACE_NAME("ProducerChannel::OnNewConsumer"); ALOGD_IF(TRACE, "ProducerChannel::OnNewConsumer: buffer_id=%d", buffer_id()); - - RemoteChannelHandle consumer_handle(CreateConsumer(message)); - - if (consumer_handle.valid()) - return consumer_handle; - else - REPLY_ERROR_RETURN(message, ENOMEM, RemoteChannelHandle()); + return CreateConsumer(message); } -int ProducerChannel::OnProducerPost( +Status<void> ProducerChannel::OnProducerPost( Message&, LocalFence acquire_fence, BufferWrapper<std::vector<std::uint8_t>> metadata) { ATRACE_NAME("ProducerChannel::OnProducerPost"); ALOGD_IF(TRACE, "ProducerChannel::OnProducerPost: buffer_id=%d", buffer_id()); if (!producer_owns_) { ALOGE("ProducerChannel::OnProducerPost: Not in gained state!"); - return -EBUSY; + return ErrorStatus(EBUSY); } if (meta_size_bytes_ != metadata.size()) - return -EINVAL; + return ErrorStatus(EINVAL); std::copy(metadata.begin(), metadata.end(), meta_.get()); post_fence_ = std::move(acquire_fence); @@ -220,29 +221,29 @@ int ProducerChannel::OnProducerPost( ALOGD_IF(TRACE, "ProducerChannel::OnProducerPost: %d pending consumers", pending_consumers_); - return 0; + return {}; } -LocalFence ProducerChannel::OnProducerGain(Message& message) { +Status<LocalFence> ProducerChannel::OnProducerGain(Message& message) { ATRACE_NAME("ProducerChannel::OnGain"); ALOGD_IF(TRACE, "ProducerChannel::OnGain: buffer_id=%d", buffer_id()); if (producer_owns_) { ALOGE("ProducerChanneL::OnGain: Already in gained state: channel=%d", channel_id()); - REPLY_ERROR_RETURN(message, EALREADY, {}); + return ErrorStatus(EALREADY); } // There are still pending consumers, return busy. if (pending_consumers_ > 0) - REPLY_ERROR_RETURN(message, EBUSY, {}); + return ErrorStatus(EBUSY); ClearAvailable(); producer_owns_ = true; post_fence_.close(); - return std::move(returned_fence_); + return {std::move(returned_fence_)}; } -std::pair<BorrowedFence, BufferWrapper<std::uint8_t*>> +Status<std::pair<BorrowedFence, BufferWrapper<std::uint8_t*>>> ProducerChannel::OnConsumerAcquire(Message& message, std::size_t metadata_size) { ATRACE_NAME("ProducerChannel::OnConsumerAcquire"); @@ -250,26 +251,27 @@ ProducerChannel::OnConsumerAcquire(Message& message, buffer_id()); if (producer_owns_) { ALOGE("ProducerChannel::OnConsumerAcquire: Not in posted state!"); - REPLY_ERROR_RETURN(message, EBUSY, {}); + return ErrorStatus(EBUSY); } // Return a borrowed fd to avoid unnecessary duplication of the underlying fd. // Serialization just needs to read the handle. if (metadata_size == 0) - return std::make_pair(post_fence_.borrow(), - WrapBuffer<std::uint8_t>(nullptr, 0)); + return {std::make_pair(post_fence_.borrow(), + WrapBuffer<std::uint8_t>(nullptr, 0))}; else - return std::make_pair(post_fence_.borrow(), - WrapBuffer(meta_.get(), meta_size_bytes_)); + return {std::make_pair(post_fence_.borrow(), + WrapBuffer(meta_.get(), meta_size_bytes_))}; } -int ProducerChannel::OnConsumerRelease(Message&, LocalFence release_fence) { +Status<void> ProducerChannel::OnConsumerRelease(Message&, + LocalFence release_fence) { ATRACE_NAME("ProducerChannel::OnConsumerRelease"); ALOGD_IF(TRACE, "ProducerChannel::OnConsumerRelease: buffer_id=%d", buffer_id()); if (producer_owns_) { ALOGE("ProducerChannel::OnConsumerRelease: Not in acquired state!"); - return -EBUSY; + return ErrorStatus(EBUSY); } // Attempt to merge the fences if necessary. @@ -282,7 +284,7 @@ int ProducerChannel::OnConsumerRelease(Message&, LocalFence release_fence) { if (!merged_fence) { ALOGE("ProducerChannel::OnConsumerRelease: Failed to merge fences: %s", strerror(error)); - return -error; + return ErrorStatus(error); } returned_fence_ = std::move(merged_fence); } else { @@ -291,7 +293,7 @@ int ProducerChannel::OnConsumerRelease(Message&, LocalFence release_fence) { } OnConsumerIgnored(); - return 0; + return {}; } void ProducerChannel::OnConsumerIgnored() { @@ -302,9 +304,10 @@ void ProducerChannel::OnConsumerIgnored() { buffer_id(), pending_consumers_); } -int ProducerChannel::OnProducerMakePersistent(Message& message, - const std::string& name, - int user_id, int group_id) { +Status<void> ProducerChannel::OnProducerMakePersistent(Message& message, + const std::string& name, + int user_id, + int group_id) { ATRACE_NAME("ProducerChannel::OnProducerMakePersistent"); ALOGD_IF(TRACE, "ProducerChannel::OnProducerMakePersistent: buffer_id=%d name=%s " @@ -313,7 +316,7 @@ int ProducerChannel::OnProducerMakePersistent(Message& message, if (name.empty() || (user_id < 0 && user_id != kNoCheckId) || (group_id < 0 && group_id != kNoCheckId)) { - return -EINVAL; + return ErrorStatus(EINVAL); } // Try to add this buffer with the requested name. @@ -331,18 +334,18 @@ int ProducerChannel::OnProducerMakePersistent(Message& message, owner_user_id_ = user_id; owner_group_id_ = group_id; name_ = name; - return 0; + return {}; } else { // Otherwise a buffer with that name already exists. - return -EALREADY; + return ErrorStatus(EALREADY); } } -int ProducerChannel::OnRemovePersistence(Message&) { +Status<void> ProducerChannel::OnRemovePersistence(Message&) { if (service()->RemoveNamedBuffer(*this)) - return 0; + return {}; else - return -ENOENT; + return ErrorStatus(ENOENT); } void ProducerChannel::AddConsumer(ConsumerChannel* channel) { @@ -365,12 +368,16 @@ bool ProducerChannel::CheckAccess(int euid, int egid) { } // Returns true if the given parameters match the underlying buffer parameters. -bool ProducerChannel::CheckParameters(int width, int height, int format, - int usage, size_t meta_size_bytes, +bool ProducerChannel::CheckParameters(uint32_t width, uint32_t height, + uint32_t format, uint64_t producer_usage, + uint64_t consumer_usage, + size_t meta_size_bytes, size_t slice_count) { return slices_.size() == slice_count && meta_size_bytes == meta_size_bytes_ && slices_[0].width() == width && slices_[0].height() == height && - slices_[0].format() == format && slices_[0].usage() == usage; + slices_[0].format() == format && + slices_[0].producer_usage() == producer_usage && + slices_[0].consumer_usage() == consumer_usage; } } // namespace dvr diff --git a/services/vr/bufferhubd/producer_channel.h b/services/vr/bufferhubd/producer_channel.h index e7ca459164..f04c8a5a7f 100644 --- a/services/vr/bufferhubd/producer_channel.h +++ b/services/vr/bufferhubd/producer_channel.h @@ -30,10 +30,10 @@ class ProducerChannel : public BufferHubChannel { template <typename T> using BufferWrapper = pdx::rpc::BufferWrapper<T>; - static std::shared_ptr<ProducerChannel> Create( - BufferHubService* service, int channel_id, int width, int height, - int format, int usage, size_t meta_size_bytes, size_t slice_count, - int* error); + static pdx::Status<std::shared_ptr<ProducerChannel>> Create( + BufferHubService* service, int channel_id, uint32_t width, + uint32_t height, uint32_t format, uint64_t producer_usage, + uint64_t consumer_usage, size_t meta_size_bytes, size_t slice_count); ~ProducerChannel() override; @@ -42,17 +42,18 @@ class ProducerChannel : public BufferHubChannel { BufferInfo GetBufferInfo() const override; - NativeBufferHandle<BorrowedHandle> OnGetBuffer(Message& message, - unsigned index); - std::vector<NativeBufferHandle<BorrowedHandle>> OnGetBuffers( + pdx::Status<NativeBufferHandle<BorrowedHandle>> OnGetBuffer(Message& message, + unsigned index); + pdx::Status<std::vector<NativeBufferHandle<BorrowedHandle>>> OnGetBuffers( Message& message); - RemoteChannelHandle CreateConsumer(Message& message); - RemoteChannelHandle OnNewConsumer(Message& message); + pdx::Status<RemoteChannelHandle> CreateConsumer(Message& message); + pdx::Status<RemoteChannelHandle> OnNewConsumer(Message& message); - std::pair<BorrowedFence, BufferWrapper<std::uint8_t*>> OnConsumerAcquire( - Message& message, std::size_t metadata_size); - int OnConsumerRelease(Message& message, LocalFence release_fence); + pdx::Status<std::pair<BorrowedFence, BufferWrapper<std::uint8_t*>>> + OnConsumerAcquire(Message& message, std::size_t metadata_size); + pdx::Status<void> OnConsumerRelease(Message& message, + LocalFence release_fence); void OnConsumerIgnored(); @@ -60,12 +61,14 @@ class ProducerChannel : public BufferHubChannel { void RemoveConsumer(ConsumerChannel* channel); bool CheckAccess(int euid, int egid); - bool CheckParameters(int width, int height, int format, int usage, + bool CheckParameters(uint32_t width, uint32_t height, uint32_t format, + uint64_t producer_usage, uint64_t consumer_usage, size_t meta_size_bytes, size_t slice_count); - int OnProducerMakePersistent(Message& message, const std::string& name, - int user_id, int group_id); - int OnRemovePersistence(Message& message); + pdx::Status<void> OnProducerMakePersistent(Message& message, + const std::string& name, + int user_id, int group_id); + pdx::Status<void> OnRemovePersistence(Message& message); private: std::vector<ConsumerChannel*> consumer_channels_; @@ -91,13 +94,15 @@ class ProducerChannel : public BufferHubChannel { std::string name_; - ProducerChannel(BufferHubService* service, int channel, int width, int height, - int format, int usage, size_t meta_size_bytes, + ProducerChannel(BufferHubService* service, int channel, uint32_t width, + uint32_t height, uint32_t format, uint64_t producer_usage, + uint64_t consumer_usage, size_t meta_size_bytes, size_t slice_count, int* error); - int OnProducerPost(Message& message, LocalFence acquire_fence, - BufferWrapper<std::vector<std::uint8_t>> metadata); - LocalFence OnProducerGain(Message& message); + pdx::Status<void> OnProducerPost( + Message& message, LocalFence acquire_fence, + BufferWrapper<std::vector<std::uint8_t>> metadata); + pdx::Status<LocalFence> OnProducerGain(Message& message); ProducerChannel(const ProducerChannel&) = delete; void operator=(const ProducerChannel&) = delete; diff --git a/services/vr/bufferhubd/producer_queue_channel.cpp b/services/vr/bufferhubd/producer_queue_channel.cpp index 7741058fce..dc2a47e0c6 100644 --- a/services/vr/bufferhubd/producer_queue_channel.cpp +++ b/services/vr/bufferhubd/producer_queue_channel.cpp @@ -1,5 +1,7 @@ #include "producer_queue_channel.h" +#include <inttypes.h> + #include "consumer_queue_channel.h" #include "producer_channel.h" @@ -12,16 +14,14 @@ using android::pdx::rpc::DispatchRemoteMethod; namespace android { namespace dvr { -ProducerQueueChannel::ProducerQueueChannel( - BufferHubService* service, int channel_id, size_t meta_size_bytes, - int usage_set_mask, int usage_clear_mask, int usage_deny_set_mask, - int usage_deny_clear_mask, int* error) +ProducerQueueChannel::ProducerQueueChannel(BufferHubService* service, + int channel_id, + size_t meta_size_bytes, + const UsagePolicy& usage_policy, + int* error) : BufferHubChannel(service, channel_id, channel_id, kProducerQueueType), meta_size_bytes_(meta_size_bytes), - usage_set_mask_(usage_set_mask), - usage_clear_mask_(usage_clear_mask), - usage_deny_set_mask_(usage_deny_set_mask), - usage_deny_clear_mask_(usage_deny_clear_mask), + usage_policy_(usage_policy), capacity_(0) { *error = 0; } @@ -29,28 +29,34 @@ ProducerQueueChannel::ProducerQueueChannel( ProducerQueueChannel::~ProducerQueueChannel() {} /* static */ -std::shared_ptr<ProducerQueueChannel> ProducerQueueChannel::Create( +Status<std::shared_ptr<ProducerQueueChannel>> ProducerQueueChannel::Create( BufferHubService* service, int channel_id, size_t meta_size_bytes, - int usage_set_mask, int usage_clear_mask, int usage_deny_set_mask, - int usage_deny_clear_mask, int* error) { + const UsagePolicy& usage_policy) { // Configuration between |usage_deny_set_mask| and |usage_deny_clear_mask| // should be mutually exclusive. - if (usage_deny_set_mask & usage_deny_clear_mask) { + if ((usage_policy.producer_deny_set_mask & + usage_policy.producer_deny_clear_mask) || + (usage_policy.consumer_deny_set_mask & + usage_policy.consumer_deny_clear_mask)) { ALOGE( "BufferHubService::OnCreateProducerQueue: illegal usage mask " - "configuration: usage_deny_set_mask=%d, usage_deny_clear_mask=%d", - usage_deny_set_mask, usage_deny_clear_mask); - *error = -EINVAL; - return nullptr; + "configuration: producer_deny_set_mask=%" PRIx64 + " producer_deny_clear_mask=%" PRIx64 " consumer_deny_set_mask=%" PRIx64 + " consumer_deny_clear_mask=%" PRIx64, + usage_policy.producer_deny_set_mask, + usage_policy.producer_deny_clear_mask, + usage_policy.consumer_deny_set_mask, + usage_policy.consumer_deny_clear_mask); + return ErrorStatus(EINVAL); } + int error = 0; std::shared_ptr<ProducerQueueChannel> producer(new ProducerQueueChannel( - service, channel_id, meta_size_bytes, usage_set_mask, usage_clear_mask, - usage_deny_set_mask, usage_deny_clear_mask, error)); - if (*error < 0) - return nullptr; + service, channel_id, meta_size_bytes, usage_policy, &error)); + if (error < 0) + return ErrorStatus(-error); else - return producer; + return {std::move(producer)}; } bool ProducerQueueChannel::HandleMessage(Message& message) { @@ -88,8 +94,7 @@ void ProducerQueueChannel::HandleImpulse(Message& /* message */) { BufferHubChannel::BufferInfo ProducerQueueChannel::GetBufferInfo() const { return BufferInfo(channel_id(), consumer_channels_.size(), capacity_, - usage_set_mask_, usage_clear_mask_, usage_deny_set_mask_, - usage_deny_clear_mask_); + usage_policy_); } Status<RemoteChannelHandle> ProducerQueueChannel::OnCreateConsumerQueue( @@ -127,11 +132,10 @@ Status<QueueInfo> ProducerQueueChannel::OnGetQueueInfo(Message&) { } Status<std::vector<std::pair<RemoteChannelHandle, size_t>>> -ProducerQueueChannel::OnProducerQueueAllocateBuffers(Message& message, - int width, int height, - int format, int usage, - size_t slice_count, - size_t buffer_count) { +ProducerQueueChannel::OnProducerQueueAllocateBuffers( + Message& message, uint32_t width, uint32_t height, uint32_t format, + uint64_t producer_usage, uint64_t consumer_usage, size_t slice_count, + size_t buffer_count) { ATRACE_NAME("ProducerQueueChannel::OnProducerQueueAllocateBuffers"); ALOGD_IF(TRACE, "ProducerQueueChannel::OnProducerQueueAllocateBuffers: " @@ -141,31 +145,58 @@ ProducerQueueChannel::OnProducerQueueAllocateBuffers(Message& message, std::vector<std::pair<RemoteChannelHandle, size_t>> buffer_handles; // Deny buffer allocation violating preset rules. - if (usage & usage_deny_set_mask_) { + if (producer_usage & usage_policy_.producer_deny_set_mask) { + ALOGE( + "ProducerQueueChannel::OnProducerQueueAllocateBuffers: producer_usage: " + "%" PRIx64 + " is not permitted. Violating producer_deny_set_mask, the following " + "bits shall not be set: %" PRIx64 ".", + producer_usage, usage_policy_.producer_deny_set_mask); + return ErrorStatus(EINVAL); + } + + if (consumer_usage & usage_policy_.consumer_deny_set_mask) { ALOGE( - "ProducerQueueChannel::OnProducerQueueAllocateBuffers: usage: %d is " - "not permitted. Violating usage_deny_set_mask, the following bits " - "shall not be set: %d.", - usage, usage_deny_set_mask_); + "ProducerQueueChannel::OnProducerQueueAllocateBuffers: consumer_usage: " + "%" PRIx64 + " is not permitted. Violating consumer_deny_set_mask, the following " + "bits shall not be set: %" PRIx64 ".", + consumer_usage, usage_policy_.consumer_deny_set_mask); return ErrorStatus(EINVAL); } - if (~usage & usage_deny_clear_mask_) { + if (~producer_usage & usage_policy_.producer_deny_clear_mask) { ALOGE( - "ProducerQueueChannel::OnProducerQueueAllocateBuffers: usage: %d is " - "not permitted. Violating usage_deny_clear_mask, the following bits " - "must be set: %d.", - usage, usage_deny_clear_mask_); + "ProducerQueueChannel::OnProducerQueueAllocateBuffers: producer_usage: " + "%" PRIx64 + " is not permitted. Violating producer_deny_clear_mask, the following " + "bits must be set: %" PRIx64 ".", + producer_usage, usage_policy_.producer_deny_clear_mask); return ErrorStatus(EINVAL); } - // Force set mask and clear mask. Note that |usage_set_mask_| takes precedence - // and will overwrite |usage_clear_mask_|. - int effective_usage = (usage & ~usage_clear_mask_) | usage_set_mask_; + if (~consumer_usage & usage_policy_.consumer_deny_clear_mask) { + ALOGE( + "ProducerQueueChannel::OnProducerQueueAllocateBuffers: consumer_usage: " + "%" PRIx64 + " is not permitted. Violating consumer_deny_clear_mask, the following " + "bits must be set: %" PRIx64 ".", + consumer_usage, usage_policy_.consumer_deny_clear_mask); + return ErrorStatus(EINVAL); + } + // Force set mask and clear mask. Note that |usage_policy_.X_set_mask_| takes + // precedence and will overwrite |usage_policy_.X_clear_mask|. + uint64_t effective_producer_usage = + (producer_usage & ~usage_policy_.producer_clear_mask) | + usage_policy_.producer_set_mask; + uint64_t effective_consumer_usage = + (consumer_usage & ~usage_policy_.consumer_clear_mask) | + usage_policy_.consumer_set_mask; for (size_t i = 0; i < buffer_count; i++) { - auto status = AllocateBuffer(message, width, height, format, - effective_usage, slice_count); + auto status = + AllocateBuffer(message, width, height, format, effective_producer_usage, + effective_consumer_usage, slice_count); if (!status) { ALOGE( "ProducerQueueChannel::OnProducerQueueAllocateBuffers: Failed to " @@ -179,8 +210,10 @@ ProducerQueueChannel::OnProducerQueueAllocateBuffers(Message& message, } Status<std::pair<RemoteChannelHandle, size_t>> -ProducerQueueChannel::AllocateBuffer(Message& message, int width, int height, - int format, int usage, +ProducerQueueChannel::AllocateBuffer(Message& message, uint32_t width, + uint32_t height, uint32_t format, + uint64_t producer_usage, + uint64_t consumer_usage, size_t slice_count) { ATRACE_NAME("ProducerQueueChannel::AllocateBuffer"); ALOGD_IF(TRACE, @@ -205,21 +238,24 @@ ProducerQueueChannel::AllocateBuffer(Message& message, int width, int height, } ALOGD_IF(TRACE, - "ProducerQueueChannel::AllocateBuffer: buffer_id=%d width=%d " - "height=%d format=%d usage=%d slice_count=%zu", - buffer_id, width, height, format, usage, slice_count); + "ProducerQueueChannel::AllocateBuffer: buffer_id=%d width=%u " + "height=%u format=%u producer_usage=%" PRIx64 + " consumer_usage=%" PRIx64 " slice_count=%zu", + buffer_id, width, height, format, producer_usage, consumer_usage, + slice_count); auto buffer_handle = status.take(); - int error; - const auto producer_channel = - ProducerChannel::Create(service(), buffer_id, width, height, format, - usage, meta_size_bytes_, slice_count, &error); - if (!producer_channel) { + auto producer_channel_status = ProducerChannel::Create( + service(), buffer_id, width, height, format, producer_usage, + consumer_usage, meta_size_bytes_, slice_count); + if (!producer_channel_status) { ALOGE( - "ProducerQueueChannel::AllocateBuffer: Failed to create " - "BufferHubBuffer producer!!"); + "ProducerQueueChannel::AllocateBuffer: Failed to create producer " + "buffer: %s", + producer_channel_status.GetErrorMessage().c_str()); return ErrorStatus(ENOMEM); } + auto producer_channel = producer_channel_status.take(); ALOGD_IF( TRACE, diff --git a/services/vr/bufferhubd/producer_queue_channel.h b/services/vr/bufferhubd/producer_queue_channel.h index a12a37d6be..09b024331a 100644 --- a/services/vr/bufferhubd/producer_queue_channel.h +++ b/services/vr/bufferhubd/producer_queue_channel.h @@ -11,10 +11,9 @@ namespace dvr { class ProducerQueueChannel : public BufferHubChannel { public: - static std::shared_ptr<ProducerQueueChannel> Create( + static pdx::Status<std::shared_ptr<ProducerQueueChannel>> Create( BufferHubService* service, int channel_id, size_t meta_size_bytes, - int usage_set_mask, int usage_clear_mask, int usage_deny_set_mask, - int usage_deny_clear_mask, int* error); + const UsagePolicy& usage_policy); ~ProducerQueueChannel() override; bool HandleMessage(pdx::Message& message) override; @@ -34,8 +33,10 @@ class ProducerQueueChannel : public BufferHubChannel { // Allocate a new BufferHubProducer according to the input spec. Client may // handle this as if a new producer is created through kOpCreateBuffer. pdx::Status<std::vector<std::pair<pdx::RemoteChannelHandle, size_t>>> - OnProducerQueueAllocateBuffers(pdx::Message& message, int width, int height, - int format, int usage, size_t slice_count, + OnProducerQueueAllocateBuffers(pdx::Message& message, uint32_t width, + uint32_t height, uint32_t format, + uint64_t producer_usage, + uint64_t consumer_usage, size_t slice_count, size_t buffer_count); // Detach a BufferHubProducer indicated by |slot|. Note that the buffer must @@ -48,18 +49,17 @@ class ProducerQueueChannel : public BufferHubChannel { private: ProducerQueueChannel(BufferHubService* service, int channel_id, - size_t meta_size_bytes, int usage_set_mask, - int usage_clear_mask, int usage_deny_set_mask, - int usage_deny_clear_mask, int* error); + size_t meta_size_bytes, const UsagePolicy& usage_policy, + int* error); // Allocate one single producer buffer by |OnProducerQueueAllocateBuffers|. // Note that the newly created buffer's file handle will be pushed to client // and our return type is a RemoteChannelHandle. - // Returns the remote channdel handle and the slot number for the newly + // Returns the remote channel handle and the slot number for the newly // allocated buffer. pdx::Status<std::pair<pdx::RemoteChannelHandle, size_t>> AllocateBuffer( - pdx::Message& message, int width, int height, int format, int usage, - size_t slice_count); + pdx::Message& message, uint32_t width, uint32_t height, uint32_t format, + uint64_t producer_usage, uint64_t consumer_usage, size_t slice_count); // Size of the meta data associated with all the buffers allocated from the // queue. Now we assume the metadata size is immutable once the queue is @@ -68,10 +68,7 @@ class ProducerQueueChannel : public BufferHubChannel { // A set of variables to control what |usage| bits can this ProducerQueue // allocate. - int usage_set_mask_; - int usage_clear_mask_; - int usage_deny_set_mask_; - int usage_deny_clear_mask_; + UsagePolicy usage_policy_; // Provides access to the |channel_id| of all consumer channels associated // with this producer. diff --git a/services/vr/hardware_composer/aidl/android/dvr/parcelable_composer_layer.cpp b/services/vr/hardware_composer/aidl/android/dvr/parcelable_composer_layer.cpp index 6e4daa005c..15f63faa71 100644 --- a/services/vr/hardware_composer/aidl/android/dvr/parcelable_composer_layer.cpp +++ b/services/vr/hardware_composer/aidl/android/dvr/parcelable_composer_layer.cpp @@ -7,15 +7,6 @@ namespace android { namespace dvr { -namespace { - -sp<GraphicBuffer> GetBufferFromHandle(native_handle_t* handle) { - // Querying properties from |handle| is never properly supported. - ALOGE("Failed to read handle %p properties", handle); - return nullptr; -} - -} // namespace ParcelableComposerLayer::ParcelableComposerLayer() {} @@ -28,7 +19,7 @@ status_t ParcelableComposerLayer::writeToParcel(Parcel* parcel) const { status_t ret = parcel->writeUint64(layer_.id); if (ret != OK) return ret; - ret = parcel->writeNativeHandle(layer_.buffer->getNativeBuffer()->handle); + ret = parcel->write(*layer_.buffer); if (ret != OK) return ret; ret = parcel->writeBool(layer_.fence->isValid()); @@ -82,11 +73,12 @@ status_t ParcelableComposerLayer::readFromParcel(const Parcel* parcel) { status_t ret = parcel->readUint64(&layer_.id); if (ret != OK) return ret; - native_handle* handle = parcel->readNativeHandle(); - if (!handle) return BAD_VALUE; - - layer_.buffer = GetBufferFromHandle(handle); - if (!layer_.buffer.get()) return BAD_VALUE; + layer_.buffer = new GraphicBuffer(); + ret = parcel->read(*layer_.buffer); + if (ret != OK) { + layer_.buffer.clear(); + return ret; + } bool has_fence = 0; ret = parcel->readBool(&has_fence); diff --git a/services/vr/vr_window_manager/composer/Android.bp b/services/vr/vr_window_manager/composer/Android.bp index 007251fe14..f01bb2801d 100644 --- a/services/vr/vr_window_manager/composer/Android.bp +++ b/services/vr/vr_window_manager/composer/Android.bp @@ -35,6 +35,7 @@ cc_library_shared { ], export_shared_lib_headers: [ + "android.frameworks.vr.composer@1.0", "android.hardware.graphics.composer@2.1", ], diff --git a/services/vr/vr_window_manager/composer/impl/vr_composer_client.cpp b/services/vr/vr_window_manager/composer/impl/vr_composer_client.cpp index acf0dac734..e0bdf1cbba 100644 --- a/services/vr/vr_window_manager/composer/impl/vr_composer_client.cpp +++ b/services/vr/vr_window_manager/composer/impl/vr_composer_client.cpp @@ -50,6 +50,10 @@ bool VrComposerClient::VrCommandReader::parseCommand( switch (vrCommand) { case IVrComposerClient::VrCommand::SET_LAYER_INFO: return parseSetLayerInfo(length); + case IVrComposerClient::VrCommand::SET_CLIENT_TARGET_METADATA: + return parseSetClientTargetMetadata(length); + case IVrComposerClient::VrCommand::SET_LAYER_BUFFER_METADATA: + return parseSetLayerBufferMetadata(length); default: return CommandReader::parseCommand(command, length); } @@ -68,5 +72,43 @@ bool VrComposerClient::VrCommandReader::parseSetLayerInfo(uint16_t length) { return true; } +bool VrComposerClient::VrCommandReader::parseSetClientTargetMetadata( + uint16_t length) { + if (length != 7) + return false; + + auto err = mVrHal.setClientTargetMetadata(mDisplay, readBufferMetadata()); + if (err != Error::NONE) + mWriter.setError(getCommandLoc(), err); + + return true; +} + +bool VrComposerClient::VrCommandReader::parseSetLayerBufferMetadata( + uint16_t length) { + if (length != 7) + return false; + + auto err = mVrHal.setLayerBufferMetadata(mDisplay, mLayer, + readBufferMetadata()); + if (err != Error::NONE) + mWriter.setError(getCommandLoc(), err); + + return true; +} + +IVrComposerClient::BufferMetadata +VrComposerClient::VrCommandReader::readBufferMetadata() { + IVrComposerClient::BufferMetadata metadata = { + .width = read(), + .height = read(), + .stride = read(), + .layerCount = read(), + .format = static_cast<PixelFormat>(readSigned()), + .usage = read64(), + }; + return metadata; +} + } // namespace dvr } // namespace android diff --git a/services/vr/vr_window_manager/composer/impl/vr_composer_client.h b/services/vr/vr_window_manager/composer/impl/vr_composer_client.h index 8f0c56293d..8d601ab55d 100644 --- a/services/vr/vr_window_manager/composer/impl/vr_composer_client.h +++ b/services/vr/vr_window_manager/composer/impl/vr_composer_client.h @@ -17,6 +17,7 @@ #ifndef VR_WINDOW_MANAGER_COMPOSER_IMPL_VR_COMPOSER_CLIENT_H_ #define VR_WINDOW_MANAGER_COMPOSER_IMPL_VR_COMPOSER_CLIENT_H_ +#include <android/frameworks/vr/composer/1.0/IVrComposerClient.h> #include <ComposerClient.h> #include <IComposerCommandBuffer.h> @@ -44,6 +45,10 @@ class VrComposerClient : public ComposerClient { private: bool parseSetLayerInfo(uint16_t length); + bool parseSetClientTargetMetadata(uint16_t length); + bool parseSetLayerBufferMetadata(uint16_t length); + + IVrComposerClient::BufferMetadata readBufferMetadata(); VrComposerClient& mVrClient; android::dvr::VrHwc& mVrHal; diff --git a/services/vr/vr_window_manager/composer/impl/vr_hwc.cpp b/services/vr/vr_window_manager/composer/impl/vr_hwc.cpp index c60a4f56d5..5efc482259 100644 --- a/services/vr/vr_window_manager/composer/impl/vr_hwc.cpp +++ b/services/vr/vr_window_manager/composer/impl/vr_hwc.cpp @@ -16,8 +16,6 @@ #include "vr_hwc.h" #include <ui/Fence.h> -#include <ui/GraphicBuffer.h> -#include <ui/GraphicBufferMapper.h> #include <mutex> @@ -43,10 +41,19 @@ using android::hardware::graphics::common::V1_0::PixelFormat; const Display kDefaultDisplayId = 1; const Config kDefaultConfigId = 1; -sp<GraphicBuffer> GetBufferFromHandle(const native_handle_t* handle) { - // Querying properties from |handle| is never properly supported. - ALOGE("Failed to read handle %p properties", handle); - return nullptr; +sp<GraphicBuffer> CreateGraphicBuffer( + const native_handle_t* handle, + const IVrComposerClient::BufferMetadata& metadata) { + sp<GraphicBuffer> buffer = new GraphicBuffer( + handle, GraphicBuffer::CLONE_HANDLE, metadata.width, metadata.height, + static_cast<int32_t>(metadata.format), metadata.layerCount, + metadata.usage, metadata.usage, metadata.stride); + if (buffer->initCheck() != OK) { + ALOGE("Failed to create graphic buffer"); + return nullptr; + } + + return buffer; } void GetPrimaryDisplaySize(int32_t* width, int32_t* height) { @@ -84,12 +91,17 @@ HwcDisplay::~HwcDisplay() {} bool HwcDisplay::SetClientTarget(const native_handle_t* handle, base::unique_fd fence) { if (handle) - buffer_ = GetBufferFromHandle(handle); + buffer_ = CreateGraphicBuffer(handle, buffer_metadata_); fence_ = new Fence(fence.release()); return true; } +void HwcDisplay::SetClientTargetMetadata( + const IVrComposerClient::BufferMetadata& metadata) { + buffer_metadata_ = metadata; +} + HwcLayer* HwcDisplay::CreateLayer() { uint64_t layer_id = layer_ids_++; layers_.push_back(HwcLayer(layer_id)); @@ -528,7 +540,8 @@ Error VrHwc::setLayerBuffer(Display display, Layer layer, if (!hwc_layer) return Error::BAD_LAYER; - hwc_layer->info.buffer = GetBufferFromHandle(buffer); + hwc_layer->info.buffer = CreateGraphicBuffer( + buffer, hwc_layer->buffer_metadata); hwc_layer->info.fence = new Fence(fence.release()); return Error::NONE; @@ -694,6 +707,35 @@ Error VrHwc::setLayerInfo(Display display, Layer layer, uint32_t type, return Error::NONE; } +Error VrHwc::setClientTargetMetadata( + Display display, const IVrComposerClient::BufferMetadata& metadata) { + std::lock_guard<std::mutex> guard(mutex_); + auto display_ptr = FindDisplay(display); + if (!display_ptr) + return Error::BAD_DISPLAY; + + display_ptr->SetClientTargetMetadata(metadata); + + return Error::NONE; +} + +Error VrHwc::setLayerBufferMetadata( + Display display, Layer layer, + const IVrComposerClient::BufferMetadata& metadata) { + std::lock_guard<std::mutex> guard(mutex_); + auto display_ptr = FindDisplay(display); + if (!display_ptr) + return Error::BAD_DISPLAY; + + HwcLayer* hwc_layer = display_ptr->GetLayer(layer); + if (!hwc_layer) + return Error::BAD_LAYER; + + hwc_layer->buffer_metadata = metadata; + + return Error::NONE; +} + Return<void> VrHwc::getCapabilities(getCapabilities_cb hidl_cb) { hidl_cb(hidl_vec<Capability>()); return Void(); diff --git a/services/vr/vr_window_manager/composer/impl/vr_hwc.h b/services/vr/vr_window_manager/composer/impl/vr_hwc.h index bfca9a6993..3da2fb810f 100644 --- a/services/vr/vr_window_manager/composer/impl/vr_hwc.h +++ b/services/vr/vr_window_manager/composer/impl/vr_hwc.h @@ -17,6 +17,7 @@ #define VR_WINDOW_MANAGER_COMPOSER_IMPL_VR_HWC_H_ #include <android-base/unique_fd.h> +#include <android/frameworks/vr/composer/1.0/IVrComposerClient.h> #include <android/hardware/graphics/composer/2.1/IComposer.h> #include <ComposerBase.h> #include <ui/Fence.h> @@ -26,6 +27,7 @@ #include <mutex> #include <unordered_map> +using namespace android::frameworks::vr::composer::V1_0; using namespace android::hardware::graphics::common::V1_0; using namespace android::hardware::graphics::composer::V2_1; @@ -38,7 +40,6 @@ using android::hardware::Void; namespace android { class Fence; -class GraphicBuffer; namespace dvr { @@ -105,6 +106,7 @@ struct HwcLayer { Composition composition_type; uint32_t z_order; ComposerView::ComposerLayer info; + IVrComposerClient::BufferMetadata buffer_metadata; }; class HwcDisplay { @@ -120,6 +122,8 @@ class HwcDisplay { HwcLayer* GetLayer(Layer id); bool SetClientTarget(const native_handle_t* handle, base::unique_fd fence); + void SetClientTargetMetadata( + const IVrComposerClient::BufferMetadata& metadata); void GetChangedCompositionTypes( std::vector<Layer>* layer_ids, @@ -131,8 +135,8 @@ class HwcDisplay { private: // The client target buffer and the associated fence. - // TODO(dnicoara): Replace this with a list of ComposerView::ComposerLayer. sp<GraphicBuffer> buffer_; + IVrComposerClient::BufferMetadata buffer_metadata_; sp<Fence> fence_; // List of currently active layers. @@ -159,6 +163,11 @@ class VrHwc : public IComposer, public ComposerBase, public ComposerView { Error setLayerInfo(Display display, Layer layer, uint32_t type, uint32_t appId); + Error setClientTargetMetadata( + Display display, const IVrComposerClient::BufferMetadata& metadata); + Error setLayerBufferMetadata( + Display display, Layer layer, + const IVrComposerClient::BufferMetadata& metadata); // ComposerBase void removeClient() override; diff --git a/vulkan/Android.bp b/vulkan/Android.bp index 3fd8c513a9..91c270e02b 100644 --- a/vulkan/Android.bp +++ b/vulkan/Android.bp @@ -26,6 +26,7 @@ ndk_headers { cc_library_headers { name: "vulkan_headers", export_include_dirs: ["include"], + vendor_available: true, } subdirs = [ diff --git a/vulkan/libvulkan/Android.bp b/vulkan/libvulkan/Android.bp index 68f09c416a..61498949bb 100644 --- a/vulkan/libvulkan/Android.bp +++ b/vulkan/libvulkan/Android.bp @@ -78,6 +78,7 @@ cc_library_shared { "libutils", "libcutils", "libz", + "libnativewindow", ], static_libs: ["libgrallocusage"], } diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp index 3b785e671d..caa2674d7b 100644 --- a/vulkan/libvulkan/swapchain.cpp +++ b/vulkan/libvulkan/swapchain.cpp @@ -114,14 +114,34 @@ class TimingInfo { : vals_{qp->presentID, qp->desiredPresentTime, 0, 0, 0}, native_frame_id_(nativeFrameId) {} bool ready() const { - return (timestamp_desired_present_time_ && - timestamp_actual_present_time_ && - timestamp_render_complete_time_ && - timestamp_composition_latch_time_); + return (timestamp_desired_present_time_ != + NATIVE_WINDOW_TIMESTAMP_PENDING && + timestamp_actual_present_time_ != + NATIVE_WINDOW_TIMESTAMP_PENDING && + timestamp_render_complete_time_ != + NATIVE_WINDOW_TIMESTAMP_PENDING && + timestamp_composition_latch_time_ != + NATIVE_WINDOW_TIMESTAMP_PENDING); } - void calculate(uint64_t rdur) { - vals_.actualPresentTime = timestamp_actual_present_time_; - uint64_t margin = (timestamp_composition_latch_time_ - + void calculate(int64_t rdur) { + bool anyTimestampInvalid = + (timestamp_actual_present_time_ == + NATIVE_WINDOW_TIMESTAMP_INVALID) || + (timestamp_render_complete_time_ == + NATIVE_WINDOW_TIMESTAMP_INVALID) || + (timestamp_composition_latch_time_ == + NATIVE_WINDOW_TIMESTAMP_INVALID); + if (anyTimestampInvalid) { + ALOGE("Unexpectedly received invalid timestamp."); + vals_.actualPresentTime = 0; + vals_.earliestPresentTime = 0; + vals_.presentMargin = 0; + return; + } + + vals_.actualPresentTime = + static_cast<uint64_t>(timestamp_actual_present_time_); + int64_t margin = (timestamp_composition_latch_time_ - timestamp_render_complete_time_); // Calculate vals_.earliestPresentTime, and potentially adjust // vals_.presentMargin. The initial value of vals_.earliestPresentTime @@ -132,14 +152,14 @@ class TimingInfo { // it did (per the extension specification). If for some reason, we // can do this subtraction repeatedly, we do, since // vals_.earliestPresentTime really is supposed to be the "earliest". - uint64_t early_time = vals_.actualPresentTime; + int64_t early_time = timestamp_actual_present_time_; while ((margin > rdur) && ((early_time - rdur) > timestamp_composition_latch_time_)) { early_time -= rdur; margin -= rdur; } - vals_.earliestPresentTime = early_time; - vals_.presentMargin = margin; + vals_.earliestPresentTime = static_cast<uint64_t>(early_time); + vals_.presentMargin = static_cast<uint64_t>(margin); } void get_values(VkPastPresentationTimingGOOGLE* values) const { *values = vals_; @@ -149,10 +169,11 @@ class TimingInfo { VkPastPresentationTimingGOOGLE vals_ { 0, 0, 0, 0, 0 }; uint64_t native_frame_id_ { 0 }; - uint64_t timestamp_desired_present_time_ { 0 }; - uint64_t timestamp_actual_present_time_ { 0 }; - uint64_t timestamp_render_complete_time_ { 0 }; - uint64_t timestamp_composition_latch_time_ { 0 }; + int64_t timestamp_desired_present_time_{ NATIVE_WINDOW_TIMESTAMP_PENDING }; + int64_t timestamp_actual_present_time_ { NATIVE_WINDOW_TIMESTAMP_PENDING }; + int64_t timestamp_render_complete_time_ { NATIVE_WINDOW_TIMESTAMP_PENDING }; + int64_t timestamp_composition_latch_time_ + { NATIVE_WINDOW_TIMESTAMP_PENDING }; }; // ---------------------------------------------------------------------------- @@ -187,18 +208,16 @@ struct Swapchain { shared(present_mode == VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR || present_mode == VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR) { ANativeWindow* window = surface.window.get(); - int64_t rdur; native_window_get_refresh_cycle_duration( window, - &rdur); - refresh_duration = static_cast<uint64_t>(rdur); + &refresh_duration); } Surface& surface; uint32_t num_images; bool mailbox_mode; bool frame_timestamps_enabled; - uint64_t refresh_duration; + int64_t refresh_duration; bool shared; struct Image { @@ -327,14 +346,10 @@ uint32_t get_num_ready_timings(Swapchain& swapchain) { // Record the timestamp(s) we received, and then see if this TimingInfo // is ready to be reported to the user: - ti.timestamp_desired_present_time_ = - static_cast<uint64_t>(desired_present_time); - ti.timestamp_actual_present_time_ = - static_cast<uint64_t>(actual_present_time); - ti.timestamp_render_complete_time_ = - static_cast<uint64_t>(render_complete_time); - ti.timestamp_composition_latch_time_ = - static_cast<uint64_t>(composition_latch_time); + ti.timestamp_desired_present_time_ = desired_present_time; + ti.timestamp_actual_present_time_ = actual_present_time; + ti.timestamp_render_complete_time_ = render_complete_time; + ti.timestamp_composition_latch_time_ = composition_latch_time; if (ti.ready()) { // The TimingInfo has received enough timestamps, and should now @@ -1494,7 +1509,8 @@ VkResult GetRefreshCycleDurationGOOGLE( Swapchain& swapchain = *SwapchainFromHandle(swapchain_handle); VkResult result = VK_SUCCESS; - pDisplayTimingProperties->refreshDuration = swapchain.refresh_duration; + pDisplayTimingProperties->refreshDuration = + static_cast<uint64_t>(swapchain.refresh_duration); return result; } |