diff options
author | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2023-07-07 04:48:11 +0000 |
---|---|---|
committer | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2023-07-07 04:48:11 +0000 |
commit | 4ed265b9b37c13d1cd340a5a840e45192132480d (patch) | |
tree | 972235c555b82d23bd826a02d64e821352248e4d | |
parent | 4dd56658620004986d78f6ba0fabff517f956c6e (diff) | |
parent | 48b1ff4a7f7c1b3fade987ac1c303c9724adf0f7 (diff) | |
download | common-4ed265b9b37c13d1cd340a5a840e45192132480d.tar.gz |
Snap for 10453563 from 48b1ff4a7f7c1b3fade987ac1c303c9724adf0f7 to mainline-adservices-releaseaml_ads_340915050
Change-Id: I4c6538776aec2b730cacd4018c03d70e45d0d5ff
93 files changed, 5036 insertions, 2519 deletions
diff --git a/BoardConfigCFlags.mk b/BoardConfigCFlags.mk index 7c2f423..679f44f 100644 --- a/BoardConfigCFlags.mk +++ b/BoardConfigCFlags.mk @@ -9,8 +9,8 @@ endif LOCAL_CFLAGS += -DUSES_GSCALER -ifeq ($(HWC_SKIP_VALIDATE),true) - LOCAL_CFLAGS += -DHWC_SKIP_VALIDATE +ifeq ($(HWC_NO_SUPPORT_SKIP_VALIDATE),true) + LOCAL_CFLAGS += -DHWC_NO_SUPPORT_SKIP_VALIDATE endif ifeq ($(HWC_SUPPORT_COLOR_TRANSFORM), true) @@ -40,3 +40,7 @@ endif ifeq ($(BOARD_USES_HDRUI_GLES_CONVERSION), true) LOCAL_CFLAGS += -DUSES_HDR_GLES_CONVERSION endif + +ifeq ($(USES_IDISPLAY_INTF_SEC),true) + LOCAL_CFLAGS += -DUSES_IDISPLAY_INTF_SEC +endif diff --git a/hwc3/Android.mk b/hwc3/Android.mk index f233aab..28ed88d 100644 --- a/hwc3/Android.mk +++ b/hwc3/Android.mk @@ -28,14 +28,14 @@ LOCAL_PROPRIETARY_MODULE := true LOCAL_CFLAGS += \ -DSOC_VERSION=$(soc_ver) \ - -DLOG_TAG=\"hwc3\" + -DLOG_TAG=\"hwc-3\" # hwc3 re-uses hwc2.2 ComposerResource and libexynosdisplay -LOCAL_SHARED_LIBRARIES := android.hardware.graphics.composer3-V1-ndk \ +LOCAL_SHARED_LIBRARIES := android.hardware.graphics.composer3-V2-ndk \ android.hardware.graphics.composer@2.1-resources \ android.hardware.graphics.composer@2.2-resources \ android.hardware.graphics.composer@2.4 \ - com.google.hardware.pixel.display-V6-ndk \ + com.google.hardware.pixel.display-V8-ndk \ libbase \ libbinder \ libbinder_ndk \ @@ -66,6 +66,7 @@ LOCAL_C_INCLUDES := \ $(TOP)/hardware/google/graphics/common/libhwc2.1/libresource \ $(TOP)/hardware/google/graphics/$(soc_ver)/include \ $(TOP)/hardware/google/graphics/$(soc_ver)/libhwc2.1 \ + $(TOP)/hardware/google/graphics/$(soc_ver)/libhwc2.1/libcolormanager \ $(TOP)/hardware/google/graphics/$(soc_ver)/libhwc2.1/libdevice \ $(TOP)/hardware/google/graphics/$(soc_ver)/libhwc2.1/libmaindisplay \ $(TOP)/hardware/google/graphics/$(soc_ver)/libhwc2.1/libresource diff --git a/hwc3/ComposerClient.cpp b/hwc3/ComposerClient.cpp index b576b68..c34b13a 100644 --- a/hwc3/ComposerClient.cpp +++ b/hwc3/ComposerClient.cpp @@ -33,25 +33,11 @@ bool ComposerClient::init() { return false; } - mCommandEngine = std::make_unique<ComposerCommandEngine>(mHal, mResources.get()); - if (mCommandEngine == nullptr) { - return false; - } - if (!mCommandEngine->init()) { - mCommandEngine = nullptr; - return false; - } - return true; } ComposerClient::~ComposerClient() { DEBUG_FUNC(); - // not initialized - if (!mCommandEngine) { - return; - } - LOG(DEBUG) << "destroying composer client"; mHal->unregisterEventCallback(); @@ -67,7 +53,7 @@ ComposerClient::~ComposerClient() { // no need to check nullptr for output parameter, the aidl stub code won't pass nullptr ndk::ScopedAStatus ComposerClient::createLayer(int64_t display, int32_t bufferSlotCount, int64_t* layer) { - DEBUG_FUNC(); + DEBUG_DISPLAY_FUNC(display); auto err = mHal->createLayer(display, layer); if (!err) { err = mResources->addLayer(display, *layer, bufferSlotCount); @@ -91,7 +77,7 @@ ndk::ScopedAStatus ComposerClient::createVirtualDisplay(int32_t width, int32_t h } ndk::ScopedAStatus ComposerClient::destroyLayer(int64_t display, int64_t layer) { - DEBUG_FUNC(); + DEBUG_DISPLAY_FUNC(display); auto err = mHal->destroyLayer(display, layer); if (!err) { err = mResources->removeLayer(display, layer); @@ -100,7 +86,7 @@ ndk::ScopedAStatus ComposerClient::destroyLayer(int64_t display, int64_t layer) } ndk::ScopedAStatus ComposerClient::destroyVirtualDisplay(int64_t display) { - DEBUG_FUNC(); + DEBUG_DISPLAY_FUNC(display); auto err = mHal->destroyVirtualDisplay(display); if (!err) { err = mResources->removeDisplay(display); @@ -110,20 +96,33 @@ ndk::ScopedAStatus ComposerClient::destroyVirtualDisplay(int64_t display) { ndk::ScopedAStatus ComposerClient::executeCommands(const std::vector<DisplayCommand>& commands, std::vector<CommandResultPayload>* results) { - DEBUG_FUNC(); - auto err = mCommandEngine->execute(commands, results); + int64_t display = commands.empty() ? -1 : commands[0].display; + DEBUG_DISPLAY_FUNC(display); + ComposerCommandEngine engine(mHal, mResources.get()); + + auto err = engine.init(); + if (err != ::android::NO_ERROR) { + LOG(ERROR) << "executeCommands(): init ComposerCommandEngine failed " << err; + return TO_BINDER_STATUS(err); + } + + err = engine.execute(commands, results); + if (err != ::android::NO_ERROR) { + LOG(ERROR) << "executeCommands(): execute failed " << err; + return TO_BINDER_STATUS(err); + } return TO_BINDER_STATUS(err); } ndk::ScopedAStatus ComposerClient::getActiveConfig(int64_t display, int32_t* config) { - DEBUG_FUNC(); + DEBUG_DISPLAY_FUNC(display); auto err = mHal->getActiveConfig(display, config); return TO_BINDER_STATUS(err); } ndk::ScopedAStatus ComposerClient::getColorModes(int64_t display, std::vector<ColorMode>* colorModes) { - DEBUG_FUNC(); + DEBUG_DISPLAY_FUNC(display); auto err = mHal->getColorModes(display, colorModes); return TO_BINDER_STATUS(err); } @@ -149,14 +148,14 @@ ndk::ScopedAStatus ComposerClient::getDataspaceSaturationMatrix(common::Dataspac ndk::ScopedAStatus ComposerClient::getDisplayAttribute(int64_t display, int32_t config, DisplayAttribute attribute, int32_t* value) { - DEBUG_FUNC(); + DEBUG_DISPLAY_FUNC(display); auto err = mHal->getDisplayAttribute(display, config, attribute, value); return TO_BINDER_STATUS(err); } ndk::ScopedAStatus ComposerClient::getDisplayCapabilities(int64_t display, std::vector<DisplayCapability>* caps) { - DEBUG_FUNC(); + DEBUG_DISPLAY_FUNC(display); auto err = mHal->getDisplayCapabilities(display, caps); if (err) { return TO_BINDER_STATUS(err); @@ -177,33 +176,33 @@ ndk::ScopedAStatus ComposerClient::getDisplayCapabilities(int64_t display, ndk::ScopedAStatus ComposerClient::getDisplayConfigs(int64_t display, std::vector<int32_t>* configs) { - DEBUG_FUNC(); + DEBUG_DISPLAY_FUNC(display); auto err = mHal->getDisplayConfigs(display, configs); return TO_BINDER_STATUS(err); } ndk::ScopedAStatus ComposerClient::getDisplayConnectionType(int64_t display, DisplayConnectionType* type) { - DEBUG_FUNC(); + DEBUG_DISPLAY_FUNC(display); auto err = mHal->getDisplayConnectionType(display, type); return TO_BINDER_STATUS(err); } ndk::ScopedAStatus ComposerClient::getDisplayIdentificationData(int64_t display, DisplayIdentification* id) { - DEBUG_FUNC(); + DEBUG_DISPLAY_FUNC(display); auto err = mHal->getDisplayIdentificationData(display, id); return TO_BINDER_STATUS(err); } ndk::ScopedAStatus ComposerClient::getDisplayName(int64_t display, std::string* name) { - DEBUG_FUNC(); + DEBUG_DISPLAY_FUNC(display); auto err = mHal->getDisplayName(display, name); return TO_BINDER_STATUS(err); } ndk::ScopedAStatus ComposerClient::getDisplayVsyncPeriod(int64_t display, int32_t* vsyncPeriod) { - DEBUG_FUNC(); + DEBUG_DISPLAY_FUNC(display); auto err = mHal->getDisplayVsyncPeriod(display, vsyncPeriod); return TO_BINDER_STATUS(err); } @@ -211,31 +210,37 @@ ndk::ScopedAStatus ComposerClient::getDisplayVsyncPeriod(int64_t display, int32_ ndk::ScopedAStatus ComposerClient::getDisplayedContentSample(int64_t display, int64_t maxFrames, int64_t timestamp, DisplayContentSample* samples) { - DEBUG_FUNC(); + DEBUG_DISPLAY_FUNC(display); auto err = mHal->getDisplayedContentSample(display, maxFrames, timestamp, samples); return TO_BINDER_STATUS(err); } ndk::ScopedAStatus ComposerClient::getDisplayedContentSamplingAttributes( int64_t display, DisplayContentSamplingAttributes* attrs) { - DEBUG_FUNC(); + DEBUG_DISPLAY_FUNC(display); auto err = mHal->getDisplayedContentSamplingAttributes(display, attrs); return TO_BINDER_STATUS(err); } ndk::ScopedAStatus ComposerClient::getDisplayPhysicalOrientation(int64_t display, common::Transform* orientation) { - DEBUG_FUNC(); + DEBUG_DISPLAY_FUNC(display); auto err = mHal->getDisplayPhysicalOrientation(display, orientation); return TO_BINDER_STATUS(err); } ndk::ScopedAStatus ComposerClient::getHdrCapabilities(int64_t display, HdrCapabilities* caps) { - DEBUG_FUNC(); + DEBUG_DISPLAY_FUNC(display); auto err = mHal->getHdrCapabilities(display, caps); return TO_BINDER_STATUS(err); } +ndk::ScopedAStatus ComposerClient::getOverlaySupport(OverlayProperties* caps) { + DEBUG_FUNC(); + auto err = mHal->getOverlaySupport(caps); + return TO_BINDER_STATUS(err); +} + ndk::ScopedAStatus ComposerClient::getMaxVirtualDisplayCount(int32_t* count) { DEBUG_FUNC(); auto err = mHal->getMaxVirtualDisplayCount(count); @@ -244,42 +249,42 @@ ndk::ScopedAStatus ComposerClient::getMaxVirtualDisplayCount(int32_t* count) { ndk::ScopedAStatus ComposerClient::getPerFrameMetadataKeys(int64_t display, std::vector<PerFrameMetadataKey>* keys) { - DEBUG_FUNC(); + DEBUG_DISPLAY_FUNC(display); auto err = mHal->getPerFrameMetadataKeys(display, keys); return TO_BINDER_STATUS(err); } ndk::ScopedAStatus ComposerClient::getReadbackBufferAttributes(int64_t display, ReadbackBufferAttributes* attrs) { - DEBUG_FUNC(); + DEBUG_DISPLAY_FUNC(display); auto err = mHal->getReadbackBufferAttributes(display, attrs); return TO_BINDER_STATUS(err); } ndk::ScopedAStatus ComposerClient::getReadbackBufferFence(int64_t display, ndk::ScopedFileDescriptor* acquireFence) { - DEBUG_FUNC(); + DEBUG_DISPLAY_FUNC(display); auto err = mHal->getReadbackBufferFence(display, acquireFence); return TO_BINDER_STATUS(err); } ndk::ScopedAStatus ComposerClient::getRenderIntents(int64_t display, ColorMode mode, std::vector<RenderIntent>* intents) { - DEBUG_FUNC(); + DEBUG_DISPLAY_FUNC(display); auto err = mHal->getRenderIntents(display, mode, intents); return TO_BINDER_STATUS(err); } ndk::ScopedAStatus ComposerClient::getSupportedContentTypes(int64_t display, std::vector<ContentType>* types) { - DEBUG_FUNC(); + DEBUG_DISPLAY_FUNC(display); auto err = mHal->getSupportedContentTypes(display, types); return TO_BINDER_STATUS(err); } ndk::ScopedAStatus ComposerClient::getDisplayDecorationSupport( int64_t display, std::optional<common::DisplayDecorationSupport>* supportStruct) { - DEBUG_FUNC(); + DEBUG_DISPLAY_FUNC(display); bool support = false; auto err = mHal->getRCDLayerSupport(display, support); if (err != ::android::OK) { @@ -306,7 +311,7 @@ ndk::ScopedAStatus ComposerClient::registerCallback( } ndk::ScopedAStatus ComposerClient::setActiveConfig(int64_t display, int32_t config) { - DEBUG_FUNC(); + DEBUG_DISPLAY_FUNC(display); auto err = mHal->setActiveConfig(display, config); return TO_BINDER_STATUS(err); } @@ -314,63 +319,78 @@ ndk::ScopedAStatus ComposerClient::setActiveConfig(int64_t display, int32_t conf ndk::ScopedAStatus ComposerClient::setActiveConfigWithConstraints( int64_t display, int32_t config, const VsyncPeriodChangeConstraints& constraints, VsyncPeriodChangeTimeline* timeline) { - DEBUG_FUNC(); + DEBUG_DISPLAY_FUNC(display); auto err = mHal->setActiveConfigWithConstraints(display, config, constraints, timeline); return TO_BINDER_STATUS(err); } ndk::ScopedAStatus ComposerClient::setBootDisplayConfig(int64_t display, int32_t config) { - DEBUG_FUNC(); + DEBUG_DISPLAY_FUNC(display); auto err = mHal->setBootDisplayConfig(display, config); return TO_BINDER_STATUS(err); } ndk::ScopedAStatus ComposerClient::clearBootDisplayConfig(int64_t display) { - DEBUG_FUNC(); + DEBUG_DISPLAY_FUNC(display); auto err = mHal->clearBootDisplayConfig(display); return TO_BINDER_STATUS(err); } ndk::ScopedAStatus ComposerClient::getPreferredBootDisplayConfig(int64_t display, int32_t* config) { - DEBUG_FUNC(); + DEBUG_DISPLAY_FUNC(display); auto err = mHal->getPreferredBootDisplayConfig(display, config); return TO_BINDER_STATUS(err); } -ndk::ScopedAStatus ComposerClient::setAutoLowLatencyMode(int64_t display, bool on) { +ndk::ScopedAStatus ComposerClient::getHdrConversionCapabilities( + std::vector<common::HdrConversionCapability>* hdrConversionCapabilities) { DEBUG_FUNC(); + auto err = mHal->getHdrConversionCapabilities(hdrConversionCapabilities); + return TO_BINDER_STATUS(err); +} + +ndk::ScopedAStatus ComposerClient::setHdrConversionStrategy( + const common::HdrConversionStrategy& hdrConversionStrategy, + common::Hdr* preferredHdrOutputType) { + DEBUG_FUNC(); + auto err = mHal->setHdrConversionStrategy(hdrConversionStrategy, preferredHdrOutputType); + return TO_BINDER_STATUS(err); +} + +ndk::ScopedAStatus ComposerClient::setAutoLowLatencyMode(int64_t display, bool on) { + DEBUG_DISPLAY_FUNC(display); auto err = mHal->setAutoLowLatencyMode(display, on); return TO_BINDER_STATUS(err); } ndk::ScopedAStatus ComposerClient::setClientTargetSlotCount(int64_t display, int32_t count) { - DEBUG_FUNC(); + DEBUG_DISPLAY_FUNC(display); auto err = mResources->setDisplayClientTargetCacheSize(display, count); return TO_BINDER_STATUS(err); } ndk::ScopedAStatus ComposerClient::setColorMode(int64_t display, ColorMode mode, RenderIntent intent) { - DEBUG_FUNC(); + DEBUG_DISPLAY_FUNC(display); auto err = mHal->setColorMode(display, mode, intent); return TO_BINDER_STATUS(err); } ndk::ScopedAStatus ComposerClient::setContentType(int64_t display, ContentType type) { - DEBUG_FUNC(); + DEBUG_DISPLAY_FUNC(display); auto err = mHal->setContentType(display, type); return TO_BINDER_STATUS(err); } ndk::ScopedAStatus ComposerClient::setDisplayedContentSamplingEnabled( int64_t display, bool enable, FormatColorComponent componentMask, int64_t maxFrames) { - DEBUG_FUNC(); + DEBUG_DISPLAY_FUNC(display); auto err = mHal->setDisplayedContentSamplingEnabled(display, enable, componentMask, maxFrames); return TO_BINDER_STATUS(err); } ndk::ScopedAStatus ComposerClient::setPowerMode(int64_t display, PowerMode mode) { - DEBUG_FUNC(); + DEBUG_DISPLAY_FUNC(display); auto err = mHal->setPowerMode(display, mode); return TO_BINDER_STATUS(err); } @@ -378,7 +398,7 @@ ndk::ScopedAStatus ComposerClient::setPowerMode(int64_t display, PowerMode mode) ndk::ScopedAStatus ComposerClient::setReadbackBuffer( int64_t display, const AidlNativeHandle& aidlBuffer, const ndk::ScopedFileDescriptor& releaseFence) { - DEBUG_FUNC(); + DEBUG_DISPLAY_FUNC(display); buffer_handle_t readbackBuffer; // Note ownership of the buffer is not passed to resource manager. buffer_handle_t buffer = ::android::makeFromAidl(aidlBuffer); @@ -392,19 +412,35 @@ ndk::ScopedAStatus ComposerClient::setReadbackBuffer( } ndk::ScopedAStatus ComposerClient::setVsyncEnabled(int64_t display, bool enabled) { - DEBUG_FUNC(); + DEBUG_DISPLAY_FUNC(display); auto err = mHal->setVsyncEnabled(display, enabled); return TO_BINDER_STATUS(err); } ndk::ScopedAStatus ComposerClient::setIdleTimerEnabled(int64_t display, int32_t timeout) { - DEBUG_FUNC(); + DEBUG_DISPLAY_FUNC(display); auto err = mHal->setIdleTimerEnabled(display, timeout); return TO_BINDER_STATUS(err); } +ndk::ScopedAStatus ComposerClient::setRefreshRateChangedCallbackDebugEnabled(int64_t display, + bool enabled) { + DEBUG_DISPLAY_FUNC(display); + auto err = mHal->setRefreshRateChangedCallbackDebugEnabled(display, enabled); + return TO_BINDER_STATUS(err); +} + +void ComposerClient::HalEventCallback::onRefreshRateChangedDebug( + const RefreshRateChangedDebugData& data) { + DEBUG_DISPLAY_FUNC(data.display); + auto ret = mCallback->onRefreshRateChangedDebug(data); + if (!ret.isOk()) { + LOG(ERROR) << "failed to send onRefreshRateChangedDebug:" << ret.getDescription(); + } +} + void ComposerClient::HalEventCallback::onHotplug(int64_t display, bool connected) { - DEBUG_FUNC(); + DEBUG_DISPLAY_FUNC(display); if (connected) { if (mResources->hasDisplay(display)) { // This is a subsequent hotplug "connected" for a display. This signals a @@ -426,7 +462,7 @@ void ComposerClient::HalEventCallback::onHotplug(int64_t display, bool connected } void ComposerClient::HalEventCallback::onRefresh(int64_t display) { - DEBUG_FUNC(); + DEBUG_DISPLAY_FUNC(display); mResources->setDisplayMustValidateState(display, true); auto ret = mCallback->onRefresh(display); if (!ret.isOk()) { @@ -436,7 +472,7 @@ void ComposerClient::HalEventCallback::onRefresh(int64_t display) { void ComposerClient::HalEventCallback::onVsync(int64_t display, int64_t timestamp, int32_t vsyncPeriodNanos) { - DEBUG_FUNC(); + DEBUG_DISPLAY_FUNC(display); auto ret = mCallback->onVsync(display, timestamp, vsyncPeriodNanos); if (!ret.isOk()) { LOG(ERROR) << "failed to send onVsync:" << ret.getDescription(); @@ -445,7 +481,7 @@ void ComposerClient::HalEventCallback::onVsync(int64_t display, int64_t timestam void ComposerClient::HalEventCallback::onVsyncPeriodTimingChanged( int64_t display, const VsyncPeriodChangeTimeline& timeline) { - DEBUG_FUNC(); + DEBUG_DISPLAY_FUNC(display); auto ret = mCallback->onVsyncPeriodTimingChanged(display, timeline); if (!ret.isOk()) { LOG(ERROR) << "failed to send onVsyncPeriodTimingChanged:" << ret.getDescription(); @@ -453,7 +489,7 @@ void ComposerClient::HalEventCallback::onVsyncPeriodTimingChanged( } void ComposerClient::HalEventCallback::onVsyncIdle(int64_t display) { - DEBUG_FUNC(); + DEBUG_DISPLAY_FUNC(display); auto ret = mCallback->onVsyncIdle(display); if (!ret.isOk()) { LOG(ERROR) << "failed to send onVsyncIdle:" << ret.getDescription(); @@ -461,7 +497,7 @@ void ComposerClient::HalEventCallback::onVsyncIdle(int64_t display) { } void ComposerClient::HalEventCallback::onSeamlessPossible(int64_t display) { - DEBUG_FUNC(); + DEBUG_DISPLAY_FUNC(display); auto ret = mCallback->onSeamlessPossible(display); if (!ret.isOk()) { LOG(ERROR) << "failed to send onSealmessPossible:" << ret.getDescription(); @@ -469,7 +505,7 @@ void ComposerClient::HalEventCallback::onSeamlessPossible(int64_t display) { } void ComposerClient::HalEventCallback::cleanDisplayResources(int64_t display) { - DEBUG_FUNC(); + DEBUG_DISPLAY_FUNC(display); size_t cacheSize; auto err = mResources->getDisplayClientTargetCacheSize(display, &cacheSize); if (!err) { diff --git a/hwc3/ComposerClient.h b/hwc3/ComposerClient.h index 855fb8b..7a76fa4 100644 --- a/hwc3/ComposerClient.h +++ b/hwc3/ComposerClient.h @@ -49,6 +49,7 @@ public: const VsyncPeriodChangeTimeline& timeline) override; void onVsyncIdle(int64_t display) override; void onSeamlessPossible(int64_t display) override; + void onRefreshRateChangedDebug(const RefreshRateChangedDebugData& data) override; private: void cleanDisplayResources(int64_t display); @@ -92,6 +93,7 @@ public: ndk::ScopedAStatus getDisplayPhysicalOrientation(int64_t display, common::Transform* orientation) override; ndk::ScopedAStatus getHdrCapabilities(int64_t display, HdrCapabilities* caps) override; + ndk::ScopedAStatus getOverlaySupport(OverlayProperties* caps) override; ndk::ScopedAStatus getMaxVirtualDisplayCount(int32_t* count) override; ndk::ScopedAStatus getPerFrameMetadataKeys(int64_t display, std::vector<PerFrameMetadataKey>* keys) override; @@ -114,6 +116,10 @@ public: ndk::ScopedAStatus setBootDisplayConfig(int64_t display, int32_t config) override; ndk::ScopedAStatus clearBootDisplayConfig(int64_t display) override; ndk::ScopedAStatus getPreferredBootDisplayConfig(int64_t display, int32_t* config) override; + ndk::ScopedAStatus getHdrConversionCapabilities( + std::vector<common::HdrConversionCapability>*) override; + ndk::ScopedAStatus setHdrConversionStrategy(const common::HdrConversionStrategy&, + common::Hdr* preferredHdrOutputType) override; ndk::ScopedAStatus setAutoLowLatencyMode(int64_t display, bool on) override; ndk::ScopedAStatus setClientTargetSlotCount(int64_t display, int32_t count) override; ndk::ScopedAStatus setColorMode(int64_t display, ColorMode mode, RenderIntent intent) override; @@ -126,6 +132,8 @@ public: const ndk::ScopedFileDescriptor& releaseFence) override; ndk::ScopedAStatus setVsyncEnabled(int64_t display, bool enabled) override; ndk::ScopedAStatus setIdleTimerEnabled(int64_t display, int32_t timeout) override; + ndk::ScopedAStatus setRefreshRateChangedCallbackDebugEnabled(int64_t /* display */, + bool /* enabled */) override; protected: ::ndk::SpAIBinder createBinder() override; @@ -135,7 +143,6 @@ private: IComposerHal* mHal; std::unique_ptr<IResourceManager> mResources; - std::unique_ptr<ComposerCommandEngine> mCommandEngine; std::function<void()> mOnClientDestroyed; std::unique_ptr<HalEventCallback> mHalEventCallback; }; diff --git a/hwc3/ComposerCommandEngine.cpp b/hwc3/ComposerCommandEngine.cpp index ff66f9d..8b0f005 100644 --- a/hwc3/ComposerCommandEngine.cpp +++ b/hwc3/ComposerCommandEngine.cpp @@ -55,9 +55,9 @@ namespace aidl::android::hardware::graphics::composer3::impl { } \ } while (0) -bool ComposerCommandEngine::init() { +int32_t ComposerCommandEngine::init() { mWriter = std::make_unique<ComposerServiceWriter>(); - return (mWriter != nullptr); + return (mWriter != nullptr) ? ::android::NO_ERROR : ::android::NO_MEMORY; } int32_t ComposerCommandEngine::execute(const std::vector<DisplayCommand>& commands, @@ -232,15 +232,12 @@ void ComposerCommandEngine::executeSetDisplayBrightness(uint64_t display, void ComposerCommandEngine::executePresentOrValidateDisplay( int64_t display, const std::optional<ClockMonotonicTimestamp> expectedPresentTime) { executeSetExpectedPresentTimeInternal(display, expectedPresentTime); - - int err; // First try to Present as is. - if (mHal->hasCapability(Capability::SKIP_VALIDATE)) { - err = executePresentDisplay(display); - if (!err) { - mWriter->setPresentOrValidateResult(display, PresentOrValidate::Result::Presented); - return; - } + auto err = mResources->mustValidateDisplay(display) ? IComposerClient::EX_NOT_VALIDATED + : executePresentDisplay(display); + if (!err) { + mWriter->setPresentOrValidateResult(display, PresentOrValidate::Result::Presented); + return; } // Fallback to validate @@ -262,9 +259,7 @@ int ComposerCommandEngine::executePresentDisplay(int64_t display) { ndk::ScopedFileDescriptor presentFence; std::vector<int64_t> layers; std::vector<ndk::ScopedFileDescriptor> fences; - auto err = mResources->mustValidateDisplay(display) - ? IComposerClient::EX_NOT_VALIDATED - : mHal->presentDisplay(display, presentFence, &layers, &fences); + auto err = mHal->presentDisplay(display, presentFence, &layers, &fences); if (!err) { mWriter->setPresentFence(display, std::move(presentFence)); mWriter->setReleaseFences(display, layers, std::move(fences)); diff --git a/hwc3/ComposerCommandEngine.h b/hwc3/ComposerCommandEngine.h index ae68285..872c7e5 100644 --- a/hwc3/ComposerCommandEngine.h +++ b/hwc3/ComposerCommandEngine.h @@ -30,7 +30,7 @@ class ComposerCommandEngine { public: ComposerCommandEngine(IComposerHal* hal, IResourceManager* resources) : mHal(hal), mResources(resources) {} - bool init(); + int32_t init(); int32_t execute(const std::vector<DisplayCommand>& commands, std::vector<CommandResultPayload>* result); diff --git a/hwc3/Util.h b/hwc3/Util.h index 5305787..92a8a71 100644 --- a/hwc3/Util.h +++ b/hwc3/Util.h @@ -28,14 +28,26 @@ FullMethodName{ __PRETTY_FUNCTION__ }; \ constexpr static const char *__kFullName__ = __kFullNameObj__.get(); \ ATRACE_NAME(__kFullName__) + +#define DEBUG_DISPLAY_FUNC(display) \ + constexpr static FullMethodName __kFullNameObj__{__PRETTY_FUNCTION__}; \ + constexpr static const char *__kFullName__ = __kFullNameObj__.get(); \ + if (CC_UNLIKELY(ATRACE_ENABLED())) { \ + ::android::String8 _traceName_; \ + _traceName_.appendFormat("%s(display=%" PRId64 ",..)", __kFullName__, display); \ + ATRACE_BEGIN(_traceName_.string()); \ + } \ + ScopedTraceEnder _traceEnder_ #else #ifdef LOG_FUNC -#define DEBUG_FUNC() DebugFunction _dbgFnObj_(__func__) +#define DEBUG_DISPLAY_FUNC(display) DebugFunction _dbgFnObj_(__func__, display) #else -#define DEBUG_FUNC() +#define DEBUG_DISPLAY_FUNC(display) #endif +#define DEBUG_FUNC() DEBUG_DISPLAY_FUNC(std::nullopt) + #endif #define RET_IF_ERR(expr) \ @@ -51,14 +63,33 @@ namespace aidl::android::hardware::graphics::composer3::impl { +class ScopedTraceEnder { +public: + ~ScopedTraceEnder() { ATRACE_END(); } +}; + class DebugFunction { public: - DebugFunction(const char* name) : mName(name) { LOG(INFO) << mName << " Enter"; } + DebugFunction(const char *name, std::optional<int64_t> display) + : mName(name), mDisplay(display) { + if (mDisplay) { + LOG(INFO) << mName << "(display=" << *mDisplay << ",..) Enter"; + } else { + LOG(INFO) << mName << " Enter"; + } + } - ~DebugFunction() { LOG(INFO) << mName << " Exit"; } + ~DebugFunction() { + if (mDisplay) { + LOG(INFO) << mName << "(display=" << *mDisplay << ",..) Exit"; + } else { + LOG(INFO) << mName << " Exit"; + } + } private: const char* mName; + std::optional<int64_t> mDisplay; }; class FullMethodName { diff --git a/hwc3/hwc3-default.xml b/hwc3/hwc3-default.xml index 05a7c09..fd9e638 100644 --- a/hwc3/hwc3-default.xml +++ b/hwc3/hwc3-default.xml @@ -1,7 +1,7 @@ <manifest version="1.0" type="device"> <hal format="aidl"> <name>android.hardware.graphics.composer3</name> - <version>1</version> + <version>2</version> <interface> <name>IComposer</name> <instance>default</instance> diff --git a/hwc3/impl/HalImpl.cpp b/hwc3/impl/HalImpl.cpp index c3011f9..e48d390 100644 --- a/hwc3/impl/HalImpl.cpp +++ b/hwc3/impl/HalImpl.cpp @@ -99,6 +99,20 @@ void seamlessPossible(hwc2_callback_data_t callbackData, hwc2_display_t hwcDispl hal->getEventCallback()->onSeamlessPossible(display); } +void refreshRateChangedDebug(hwc2_callback_data_t callbackData, hwc2_display_t hwcDisplay, + hwc2_vsync_period_t hwcVsyncPeriodNanos) { + auto hal = static_cast<HalImpl*>(callbackData); + int64_t display; + int32_t vsyncPeriodNanos; + + h2a::translate(hwcDisplay, display); + h2a::translate(hwcVsyncPeriodNanos, vsyncPeriodNanos); + hal->getEventCallback()->onRefreshRateChangedDebug(RefreshRateChangedDebugData{ + .display = display, + .vsyncPeriodNanos = vsyncPeriodNanos, + }); +} + } // nampesapce hook HalImpl::HalImpl(std::unique_ptr<ExynosDevice> device) : mDevice(std::move(device)) { @@ -130,6 +144,7 @@ void HalImpl::initCaps() { } mCaps.insert(Capability::BOOT_DISPLAY_CONFIG); + mCaps.insert(Capability::REFRESH_RATE_CHANGED_CALLBACK_DEBUG); } int32_t HalImpl::getHalDisplay(int64_t display, ExynosDisplay*& halDisplay) { @@ -193,6 +208,9 @@ void HalImpl::registerEventCallback(EventCallback* callback) { // register HWC3 Callback mDevice->registerHwc3Callback(IComposerCallback::TRANSACTION_onVsyncIdle, this, reinterpret_cast<hwc2_function_pointer_t>(hook::vsyncIdle)); + mDevice->registerHwc3Callback(IComposerCallback::TRANSACTION_onRefreshRateChangedDebug, this, + reinterpret_cast<hwc2_function_pointer_t>( + hook::refreshRateChangedDebug)); } void HalImpl::unregisterEventCallback() { @@ -204,6 +222,8 @@ void HalImpl::unregisterEventCallback() { // unregister HWC3 Callback mDevice->registerHwc3Callback(IComposerCallback::TRANSACTION_onVsyncIdle, this, nullptr); + mDevice->registerHwc3Callback(IComposerCallback::TRANSACTION_onRefreshRateChangedDebug, this, + nullptr); mEventCallback = nullptr; } @@ -457,6 +477,10 @@ int32_t HalImpl::getHdrCapabilities(int64_t display, HdrCapabilities* caps) { return HWC2_ERROR_NONE; } +int32_t HalImpl::getOverlaySupport(OverlayProperties* caps) { + return mDevice->getOverlaySupport(caps); +} + int32_t HalImpl::getMaxVirtualDisplayCount(int32_t* count) { uint32_t hwcCount = mDevice->getMaxVirtualDisplayCount(); h2a::translate(hwcCount, *count); @@ -632,6 +656,14 @@ int32_t HalImpl::getPreferredBootDisplayConfig(int64_t display, int32_t* config) return halDisplay->getPreferredBootDisplayConfig(config); } +int32_t HalImpl::getHdrConversionCapabilities(std::vector<common::HdrConversionCapability>*) { + return HWC2_ERROR_UNSUPPORTED; +} + +int32_t HalImpl::setHdrConversionStrategy(const common::HdrConversionStrategy&, common::Hdr*) { + return HWC2_ERROR_UNSUPPORTED; +} + int32_t HalImpl::setAutoLowLatencyMode(int64_t display, bool on) { ExynosDisplay* halDisplay; RET_IF_ERR(getHalDisplay(display, halDisplay)); @@ -1045,4 +1077,18 @@ int32_t HalImpl::getDisplayIdleTimerSupport(int64_t display, bool& outSupport) { return halDisplay->getDisplayIdleTimerSupport(outSupport); } +int32_t HalImpl::getDisplayMultiThreadedPresentSupport(const int64_t& display, bool& outSupport) { + ExynosDisplay* halDisplay; + RET_IF_ERR(getHalDisplay(display, halDisplay)); + + return halDisplay->getDisplayMultiThreadedPresentSupport(outSupport); +} + +int32_t HalImpl::setRefreshRateChangedCallbackDebugEnabled(int64_t display, bool enabled) { + ExynosDisplay* halDisplay; + RET_IF_ERR(getHalDisplay(display, halDisplay)); + + return halDisplay->setRefreshRateChangedCallbackDebugEnabled(enabled); +} + } // namespace aidl::android::hardware::graphics::composer3::impl diff --git a/hwc3/impl/HalImpl.h b/hwc3/impl/HalImpl.h index f772ca4..9cb8f1d 100644 --- a/hwc3/impl/HalImpl.h +++ b/hwc3/impl/HalImpl.h @@ -71,6 +71,7 @@ class HalImpl : public IComposerHal { int32_t getDisplayPhysicalOrientation(int64_t display, common::Transform* orientation) override; int32_t getDozeSupport(int64_t display, bool& outSupport) override; int32_t getHdrCapabilities(int64_t display, HdrCapabilities* caps) override; + int32_t getOverlaySupport(OverlayProperties* caps) override; int32_t getMaxVirtualDisplayCount(int32_t* count) override; int32_t getPerFrameMetadataKeys(int64_t display, std::vector<PerFrameMetadataKey>* keys) override; @@ -92,6 +93,8 @@ class HalImpl : public IComposerHal { int32_t setBootDisplayConfig(int64_t display, int32_t config) override; int32_t clearBootDisplayConfig(int64_t display) override; int32_t getPreferredBootDisplayConfig(int64_t display, int32_t* config) override; + int32_t getHdrConversionCapabilities(std::vector<common::HdrConversionCapability>*) override; + int32_t setHdrConversionStrategy(const common::HdrConversionStrategy&, common::Hdr*) override; int32_t setAutoLowLatencyMode(int64_t display, bool on) override; int32_t setClientTarget(int64_t display, buffer_handle_t target, const ndk::ScopedFileDescriptor& fence, common::Dataspace dataspace, @@ -136,6 +139,8 @@ class HalImpl : public IComposerHal { const ndk::ScopedFileDescriptor& releaseFence) override; int32_t setVsyncEnabled(int64_t display, bool enabled) override; int32_t getDisplayIdleTimerSupport(int64_t display, bool& outSupport) override; + int32_t getDisplayMultiThreadedPresentSupport(const int64_t& display, + bool& outSupport) override; int32_t setIdleTimerEnabled(int64_t display, int32_t timeout) override; int32_t getRCDLayerSupport(int64_t display, bool& outSupport) override; int32_t setLayerBlockingRegion( @@ -153,6 +158,7 @@ class HalImpl : public IComposerHal { const std::optional<ClockMonotonicTimestamp> expectedPresentTime) override; EventCallback* getEventCallback() { return mEventCallback; } + int32_t setRefreshRateChangedCallbackDebugEnabled(int64_t display, bool enabled) override; private: void initCaps(); diff --git a/hwc3/include/IComposerHal.h b/hwc3/include/IComposerHal.h index 6fe25c5..9a9108f 100644 --- a/hwc3/include/IComposerHal.h +++ b/hwc3/include/IComposerHal.h @@ -25,6 +25,9 @@ #include <aidl/android/hardware/graphics/common/ColorTransform.h> #include <aidl/android/hardware/graphics/common/Dataspace.h> #include <aidl/android/hardware/graphics/common/FRect.h> +#include <aidl/android/hardware/graphics/common/Hdr.h> +#include <aidl/android/hardware/graphics/common/HdrConversionCapability.h> +#include <aidl/android/hardware/graphics/common/HdrConversionStrategy.h> #include <aidl/android/hardware/graphics/common/PixelFormat.h> #include <aidl/android/hardware/graphics/common/Point.h> #include <aidl/android/hardware/graphics/common/Rect.h> @@ -55,6 +58,7 @@ #include <aidl/android/hardware/graphics/composer3/HdrCapabilities.h> #include <aidl/android/hardware/graphics/composer3/LayerBrightness.h> #include <aidl/android/hardware/graphics/composer3/LayerCommand.h> +#include <aidl/android/hardware/graphics/composer3/OverlayProperties.h> #include <aidl/android/hardware/graphics/composer3/ParcelableBlendMode.h> #include <aidl/android/hardware/graphics/composer3/ParcelableComposition.h> #include <aidl/android/hardware/graphics/composer3/ParcelableDataspace.h> @@ -67,6 +71,7 @@ #include <aidl/android/hardware/graphics/composer3/PresentFence.h> #include <aidl/android/hardware/graphics/composer3/PresentOrValidate.h> #include <aidl/android/hardware/graphics/composer3/ReadbackBufferAttributes.h> +#include <aidl/android/hardware/graphics/composer3/RefreshRateChangedDebugData.h> #include <aidl/android/hardware/graphics/composer3/ReleaseFences.h> #include <aidl/android/hardware/graphics/composer3/RenderIntent.h> #include <aidl/android/hardware/graphics/composer3/VirtualDisplay.h> @@ -102,6 +107,7 @@ class IComposerHal { const VsyncPeriodChangeTimeline& timeline) = 0; virtual void onVsyncIdle(int64_t display) = 0; virtual void onSeamlessPossible(int64_t display) = 0; + virtual void onRefreshRateChangedDebug(const RefreshRateChangedDebugData& data) = 0; }; virtual void registerEventCallback(EventCallback* callback) = 0; virtual void unregisterEventCallback() = 0; @@ -121,7 +127,8 @@ class IComposerHal { DisplayAttribute attribute, int32_t* outValue) = 0; virtual int32_t getDisplayBrightnessSupport(int64_t display, bool& outSupport) = 0; virtual int32_t getDisplayIdleTimerSupport(int64_t display, bool& outSupport) = 0; - + virtual int32_t getDisplayMultiThreadedPresentSupport(const int64_t& display, + bool& outSupport) = 0; virtual int32_t getDisplayCapabilities(int64_t display, std::vector<DisplayCapability>* caps) = 0; virtual int32_t getDisplayConfigs(int64_t display, std::vector<int32_t>* configs) = 0; @@ -137,6 +144,7 @@ class IComposerHal { common::Transform* orientation) = 0; virtual int32_t getDozeSupport(int64_t display, bool& outSupport) = 0; virtual int32_t getHdrCapabilities(int64_t display, HdrCapabilities* caps) = 0; + virtual int32_t getOverlaySupport(OverlayProperties* caps) = 0; virtual int32_t getMaxVirtualDisplayCount(int32_t* count) = 0; virtual int32_t getPerFrameMetadataKeys(int64_t display, std::vector<PerFrameMetadataKey>* keys) = 0; @@ -158,6 +166,9 @@ class IComposerHal { virtual int32_t setBootDisplayConfig(int64_t display, int32_t config) = 0; virtual int32_t clearBootDisplayConfig(int64_t display) = 0; virtual int32_t getPreferredBootDisplayConfig(int64_t display, int32_t* config) = 0; + virtual int32_t getHdrConversionCapabilities(std::vector<common::HdrConversionCapability>*) = 0; + virtual int32_t setHdrConversionStrategy(const common::HdrConversionStrategy&, + common::Hdr*) = 0; virtual int32_t setAutoLowLatencyMode(int64_t display, bool on) = 0; virtual int32_t setClientTarget(int64_t display, buffer_handle_t target, const ndk::ScopedFileDescriptor& fence, @@ -220,6 +231,7 @@ class IComposerHal { virtual int32_t setLayerBlockingRegion( int64_t display, int64_t layer, const std::vector<std::optional<common::Rect>>& blockingRegion) = 0; + virtual int32_t setRefreshRateChangedCallbackDebugEnabled(int64_t display, bool enabled) = 0; }; } // namespace aidl::android::hardware::graphics::composer3::detail diff --git a/include/displaycolor/displaycolor.h b/include/displaycolor/displaycolor.h index d9141ff..f23d8a8 100644 --- a/include/displaycolor/displaycolor.h +++ b/include/displaycolor/displaycolor.h @@ -34,7 +34,9 @@ using android::hardware::graphics::common::V1_2::PixelFormat; /** * hwc/displaycolor interface history * - * 6.1.0.2022-05-18 Get calibrated serial number. + * 7.0.0.2022-03-22 Interface refactor + * 6.2.0.2022-05-18 Get calibrated serial number. + * 6.1.0.2022-04-29 dim solid color layer * 6.0.0.2022-02-22 Get whether dimming in linear. * 5.0.0.2022-02-17 Add layer dim ratio. * 4.0.0.2021-12-20 Get pixel format and dataspace of blending stage. @@ -60,8 +62,8 @@ constexpr struct DisplayColorIntfVer { } } kInterfaceVersion { - 6, - 1, + 7, + 0, 0, }; @@ -115,12 +117,28 @@ struct DisplayInfo { DisplayBrightnessTable brightness_table; }; +struct Color { + uint8_t r; + uint8_t g; + uint8_t b; + uint8_t a; + + bool operator==(const Color &rhs) const { + return r == rhs.r && + g == rhs.g && + b == rhs.b && + a == rhs.a; + } +}; + struct LayerColorData { bool operator==(const LayerColorData &rhs) const { return dataspace == rhs.dataspace && matrix == rhs.matrix && static_metadata == rhs.static_metadata && dynamic_metadata == rhs.dynamic_metadata && - dim_ratio == rhs.dim_ratio; + dim_ratio == rhs.dim_ratio && + is_solid_color_layer == rhs.is_solid_color_layer && + (!is_solid_color_layer || solid_color == rhs.solid_color); } /** @@ -230,6 +248,16 @@ struct LayerColorData { * @brief the layer's luminance dim ratio */ float dim_ratio = 1.0f; + + /** + * @brief is layer solid color + */ + bool is_solid_color_layer; + + /** + * @brief color for solid color layer + */ + Color solid_color; }; /** @@ -318,6 +346,13 @@ class IDisplayColorGeneric { const ConfigType *config = nullptr; }; + /// A collection of stages. For example, It could be pre-blending stages + //(per-channel) or post-blending stages. + template <typename ... IStageData> + struct IStageDataCollection : public IStageData ... { + virtual ~IStageDataCollection() {} + }; + /// Interface for accessing data for panel class IPanel { public: @@ -337,7 +372,7 @@ class IDisplayColorGeneric { * @param scene Display scene data to use during the update. * @return OK if successful, error otherwise. */ - virtual int Update(DisplayType display, const DisplayScene &scene) = 0; + virtual int Update(const DisplayType display, const DisplayScene &scene) = 0; /** * @brief Update display color data. This function is expected to be called @@ -348,29 +383,27 @@ class IDisplayColorGeneric { * @param scene Display scene data to use during the update. * @return OK if successful, error otherwise. */ - virtual int UpdatePresent(DisplayType display, const DisplayScene &scene) = 0; + virtual int UpdatePresent(const DisplayType display, const DisplayScene &scene) = 0; /** * @brief Check if refresh rate regamma compensation is enabled. * * @return true for yes. */ - virtual bool IsRrCompensationEnabled(DisplayType display) = 0; + virtual bool IsRrCompensationEnabled(const DisplayType display) = 0; /** * @brief Get calibration information for each profiles. * @param display The display to get the calibration information. */ - virtual const CalibrationInfo &GetCalibrationInfo( - DisplayType display) const = 0; + virtual const CalibrationInfo &GetCalibrationInfo(const DisplayType display) const = 0; /** * @brief Get a map of supported ColorModes, and supported RenderIntents for * each ColorMode. * @param display The display to get the color modes and render intents. */ - virtual const ColorModesMap &ColorModesAndRenderIntents( - DisplayType display) const = 0; + virtual const ColorModesMap &ColorModesAndRenderIntents(const DisplayType display) const = 0; /** * @brief Get pixel format and dataspace of blending stage. @@ -379,7 +412,7 @@ class IDisplayColorGeneric { * @param dataspace Dataspace of blending stage * @return OK if successful, error otherwise. */ - virtual int GetBlendingProperty(DisplayType display, + virtual int GetBlendingProperty(const DisplayType display, hwc::PixelFormat &pixel_format, hwc::Dataspace &dataspace, bool &dimming_linear) const = 0; diff --git a/libacryl/Android.mk b/libacryl/Android.mk index abbc2f2..2984d2d 100644 --- a/libacryl/Android.mk +++ b/libacryl/Android.mk @@ -16,7 +16,7 @@ LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) -LOCAL_CFLAGS += -DLOG_TAG=\"libacryl\" +LOCAL_CFLAGS += -DLOG_TAG=\"hwc-libacryl\" #LOCAL_CFLAGS += -DLIBACRYL_DEBUG ifdef BOARD_LIBACRYL_DEFAULT_COMPOSITOR @@ -47,6 +47,7 @@ LOCAL_HEADER_LIBRARIES += libgralloc_headers LOCAL_C_INCLUDES := $(LOCAL_PATH)/local_include LOCAL_C_INCLUDES += $(LOCAL_PATH)/include +LOCAL_C_INCLUDES += $(TOP)/hardware/google/graphics/$(TARGET_BOARD_PLATFORM)/libcap LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include diff --git a/libacryl/acrylic_factory.cpp b/libacryl/acrylic_factory.cpp index 7242ecd..b59f409 100644 --- a/libacryl/acrylic_factory.cpp +++ b/libacryl/acrylic_factory.cpp @@ -23,181 +23,16 @@ #include "acrylic_g2d.h" #include "acrylic_internal.h" - -static uint32_t all_fimg2d_gs101_formats[] = { - HAL_PIXEL_FORMAT_RGBA_8888, - HAL_PIXEL_FORMAT_BGRA_8888, - HAL_PIXEL_FORMAT_RGBA_1010102, - HAL_PIXEL_FORMAT_RGBX_8888, - HAL_PIXEL_FORMAT_RGB_888, - HAL_PIXEL_FORMAT_RGB_565, - HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_P, - HAL_PIXEL_FORMAT_YCrCb_420_SP, // NV21 (YVU420 semi-planar) - HAL_PIXEL_FORMAT_EXYNOS_YCrCb_420_SP_M, // NV21 on multi-buffer - HAL_PIXEL_FORMAT_EXYNOS_YCrCb_420_SP_M_FULL, // NV21 on multi-buffer - HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SP, // NV12 (YUV420 semi-planar) - HAL_PIXEL_FORMAT_GOOGLE_NV12_SP, // NV12 (YUV420 semi-planar) - MALI_GRALLOC_FORMAT_INTERNAL_YUV420_8BIT_I, // NV12 AFBC - HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SPN, // NV12 with MFC alignment constraints - HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SP_M, // NV12M with MFC alignment constraints on multi-buffer - HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SP_M_PRIV, // NV12M with MFC alignment constraints on multi-buffer - HAL_PIXEL_FORMAT_YCbCr_422_SP, // YUV422 2P (YUV422 semi-planar) - HAL_PIXEL_FORMAT_YCBCR_P010, - HAL_PIXEL_FORMAT_GOOGLE_NV12_SP_10B, - MALI_GRALLOC_FORMAT_INTERNAL_YUV420_10BIT_I, - HAL_PIXEL_FORMAT_EXYNOS_YCbCr_P010_M, - HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SP_M_SBWC, - HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SPN_SBWC, - HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SP_M_10B_SBWC, - HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SPN_10B_SBWC, - HAL_PIXEL_FORMAT_EXYNOS_YCrCb_420_SP_M_SBWC, - HAL_PIXEL_FORMAT_EXYNOS_YCrCb_420_SP_M_10B_SBWC, -}; - -static uint32_t all_fimg2d_gs201_formats[] = { - HAL_PIXEL_FORMAT_RGBA_8888, - HAL_PIXEL_FORMAT_BGRA_8888, - HAL_PIXEL_FORMAT_RGBA_1010102, - HAL_PIXEL_FORMAT_RGBX_8888, - HAL_PIXEL_FORMAT_RGB_888, - HAL_PIXEL_FORMAT_RGB_565, - HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_P, - HAL_PIXEL_FORMAT_YCrCb_420_SP, // NV21 (YVU420 semi-planar) - HAL_PIXEL_FORMAT_EXYNOS_YCrCb_420_SP_M, // NV21 on multi-buffer - HAL_PIXEL_FORMAT_EXYNOS_YCrCb_420_SP_M_FULL, // NV21 on multi-buffer - HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SP, // NV12 (YUV420 semi-planar) - HAL_PIXEL_FORMAT_GOOGLE_NV12_SP, // NV12 (YUV420 semi-planar) - MALI_GRALLOC_FORMAT_INTERNAL_YUV420_8BIT_I, // NV12 AFBC - HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SPN, // NV12 with MFC alignment constraints - HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SP_M, // NV12M with MFC alignment constraints on multi-buffer - HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SP_M_PRIV, // NV12M with MFC alignment constraints on multi-buffer - HAL_PIXEL_FORMAT_YCbCr_422_SP, // YUV422 2P (YUV422 semi-planar) - HAL_PIXEL_FORMAT_YCBCR_P010, - HAL_PIXEL_FORMAT_GOOGLE_NV12_SP_10B, - MALI_GRALLOC_FORMAT_INTERNAL_YUV420_10BIT_I, - HAL_PIXEL_FORMAT_EXYNOS_YCbCr_P010_M, - HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SP_M_SBWC, - HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SPN_SBWC, - HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SP_M_10B_SBWC, - HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SPN_10B_SBWC, - HAL_PIXEL_FORMAT_EXYNOS_YCrCb_420_SP_M_SBWC, - HAL_PIXEL_FORMAT_EXYNOS_YCrCb_420_SP_M_10B_SBWC, - HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SP_M_SBWC_L50, - HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SP_M_SBWC_L75, - HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SPN_SBWC_L50, - HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SPN_SBWC_L75, - HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SP_M_10B_SBWC_L40, - HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SP_M_10B_SBWC_L60, - HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SP_M_10B_SBWC_L80, - HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SPN_10B_SBWC_L40, - HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SPN_10B_SBWC_L60, - HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SPN_10B_SBWC_L80, -}; - -// The presence of the dataspace definitions are in the order -// of application's preference to reduce comparations. -static int all_hwc_dataspaces[] = { - HAL_DATASPACE_STANDARD_BT709, - HAL_DATASPACE_STANDARD_BT709 | HAL_DATASPACE_RANGE_FULL, - HAL_DATASPACE_STANDARD_BT709 | HAL_DATASPACE_RANGE_LIMITED, - HAL_DATASPACE_STANDARD_BT2020, - HAL_DATASPACE_STANDARD_BT2020 | HAL_DATASPACE_RANGE_FULL, - HAL_DATASPACE_STANDARD_BT2020 | HAL_DATASPACE_RANGE_LIMITED, - HAL_DATASPACE_STANDARD_BT601_625, - HAL_DATASPACE_STANDARD_BT601_625 | HAL_DATASPACE_RANGE_FULL, - HAL_DATASPACE_STANDARD_BT601_625 | HAL_DATASPACE_RANGE_LIMITED, - HAL_DATASPACE_STANDARD_BT601_525, - HAL_DATASPACE_STANDARD_BT601_525 | HAL_DATASPACE_RANGE_FULL, - HAL_DATASPACE_STANDARD_BT601_525 | HAL_DATASPACE_RANGE_LIMITED, - HAL_DATASPACE_STANDARD_BT601_625_UNADJUSTED, - HAL_DATASPACE_STANDARD_BT601_625_UNADJUSTED | HAL_DATASPACE_RANGE_FULL, - HAL_DATASPACE_STANDARD_BT601_625_UNADJUSTED | HAL_DATASPACE_RANGE_LIMITED, - HAL_DATASPACE_STANDARD_BT601_525_UNADJUSTED, - HAL_DATASPACE_STANDARD_BT601_525_UNADJUSTED | HAL_DATASPACE_RANGE_FULL, - HAL_DATASPACE_STANDARD_BT601_525_UNADJUSTED | HAL_DATASPACE_RANGE_LIMITED, - HAL_DATASPACE_STANDARD_DCI_P3, - HAL_DATASPACE_STANDARD_DCI_P3 | HAL_DATASPACE_RANGE_FULL, - HAL_DATASPACE_STANDARD_DCI_P3 | HAL_DATASPACE_RANGE_LIMITED, - HAL_DATASPACE_STANDARD_FILM, - HAL_DATASPACE_STANDARD_FILM | HAL_DATASPACE_RANGE_FULL, - HAL_DATASPACE_STANDARD_FILM | HAL_DATASPACE_RANGE_LIMITED, - // 0 should be treated as BT709 Limited range - 0, - HAL_DATASPACE_RANGE_FULL, - HAL_DATASPACE_RANGE_LIMITED, - // Depricated legacy dataspace definitions - HAL_DATASPACE_SRGB, - HAL_DATASPACE_JFIF, - HAL_DATASPACE_BT601_525, - HAL_DATASPACE_BT601_625, - HAL_DATASPACE_BT709, -}; - -const static stHW2DCapability __capability_fimg2d_gs101 = { - .max_upsampling_num = {8, 8}, - .max_downsampling_factor = {4, 4}, - .max_upsizing_num = {8, 8}, - .max_downsizing_factor = {4, 4}, - .min_src_dimension = {1, 1}, - .max_src_dimension = {8192, 8192}, - .min_dst_dimension = {1, 1}, - .max_dst_dimension = {8192, 8192}, - .min_pix_align = {1, 1}, - .rescaling_count = 0, - .compositing_mode = HW2DCapability::BLEND_NONE | HW2DCapability::BLEND_SRC_COPY | HW2DCapability::BLEND_SRC_OVER, - .transform_type = HW2DCapability::TRANSFORM_ALL, - .auxiliary_feature = HW2DCapability::FEATURE_PLANE_ALPHA | HW2DCapability::FEATURE_UORDER_WRITE - | HW2DCapability::FEATURE_AFBC_ENCODE | HW2DCapability::FEATURE_AFBC_DECODE - | HW2DCapability::FEATURE_SOLIDCOLOR, - .num_formats = ARRSIZE(all_fimg2d_gs101_formats), - .num_dataspaces = ARRSIZE(all_hwc_dataspaces), - .max_layers = 4, - .pixformats = all_fimg2d_gs101_formats, - .dataspaces = all_hwc_dataspaces, - .base_align = 1, -}; - -const static stHW2DCapability __capability_fimg2d_gs201 = { - .max_upsampling_num = {8, 8}, - .max_downsampling_factor = {4, 4}, - .max_upsizing_num = {8, 8}, - .max_downsizing_factor = {4, 4}, - .min_src_dimension = {1, 1}, - .max_src_dimension = {8192, 8192}, - .min_dst_dimension = {1, 1}, - .max_dst_dimension = {8192, 8192}, - .min_pix_align = {1, 1}, - .rescaling_count = 0, - .compositing_mode = HW2DCapability::BLEND_NONE | HW2DCapability::BLEND_SRC_COPY | HW2DCapability::BLEND_SRC_OVER, - .transform_type = HW2DCapability::TRANSFORM_ALL, - .auxiliary_feature = HW2DCapability::FEATURE_PLANE_ALPHA | HW2DCapability::FEATURE_UORDER_WRITE - | HW2DCapability::FEATURE_AFBC_ENCODE | HW2DCapability::FEATURE_AFBC_DECODE - | HW2DCapability::FEATURE_SOLIDCOLOR, - .num_formats = ARRSIZE(all_fimg2d_gs201_formats), - .num_dataspaces = ARRSIZE(all_hwc_dataspaces), - .max_layers = 4, - .pixformats = all_fimg2d_gs201_formats, - .dataspaces = all_hwc_dataspaces, - .base_align = 1, -}; - -static const HW2DCapability capability_fimg2d_gs101(__capability_fimg2d_gs101); - -static const HW2DCapability capability_fimg2d_gs201(__capability_fimg2d_gs201); +#include "acrylic_capability.h" Acrylic *Acrylic::createInstance(const char *spec) { Acrylic *compositor = nullptr; ALOGD_TEST("Creating a new Acrylic instance of '%s'", spec); - - if (strcmp(spec, "fimg2d_gs101") == 0) { - compositor = new AcrylicCompositorG2D(capability_fimg2d_gs101, true); - } else if (strcmp(spec, "fimg2d_gs201") == 0) { - compositor = new AcrylicCompositorG2D(capability_fimg2d_gs201, true); - } else { - ALOGE("Unknown HW2D compositor spec., %s", spec); - return nullptr; + compositor = createAcrylicCompositorG2D(spec); + if (compositor) { + ALOGI("%s compositor added", spec); } ALOGE_IF(!compositor, "Failed to create HW2D compositor of '%s'", spec); diff --git a/libacryl/acrylic_formats.cpp b/libacryl/acrylic_formats.cpp index 9654de0..5bc37ae 100644 --- a/libacryl/acrylic_formats.cpp +++ b/libacryl/acrylic_formats.cpp @@ -91,6 +91,7 @@ static uint32_t __halfmt_to_v4l2_ycbcr[][2] = { {HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SPN_S10B, V4L2_PIX_FMT_NV12N_10B }, {HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SP_M_S10B, V4L2_PIX_FMT_NV12M_S10B }, {HAL_PIXEL_FORMAT_EXYNOS_YCbCr_P010_M, V4L2_PIX_FMT_NV12M_P010 }, + {HAL_PIXEL_FORMAT_EXYNOS_YCbCr_P010_SPN, V4L2_PIX_FMT_NV12_P010 }, {HAL_PIXEL_FORMAT_YCBCR_P010, V4L2_PIX_FMT_NV12_P010 }, {HAL_PIXEL_FORMAT_YCbCr_422_I, V4L2_PIX_FMT_YUYV }, {HAL_PIXEL_FORMAT_EXYNOS_YCrCb_422_I, V4L2_PIX_FMT_YVYU }, @@ -172,6 +173,7 @@ static struct { {HAL_PIXEL_FORMAT_YCBCR_P010, 1, 0x22, {24, 0, 0, 0}, HAL_PIXEL_FORMAT_YCBCR_P010, 2}, {HAL_PIXEL_FORMAT_EXYNOS_YCbCr_P010_M, 2, 0x22, {16, 8, 0, 0}, HAL_PIXEL_FORMAT_YCBCR_P010, 2}, {HAL_PIXEL_FORMAT_GOOGLE_NV12_SP_10B, 1, 0x22, {24, 0, 0, 0}, HAL_PIXEL_FORMAT_YCBCR_P010, 2}, + {HAL_PIXEL_FORMAT_EXYNOS_YCbCr_P010_SPN, 1, 0x22, {24, 0, 0, 0}, HAL_PIXEL_FORMAT_YCBCR_P010, 2}, {MALI_GRALLOC_FORMAT_INTERNAL_YUV420_10BIT_I, 1, 0x22, {15, 0, 0, 0}, HAL_PIXEL_FORMAT_YCBCR_P010, 2}, {HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SP_M_SBWC, 2, 0x22, { 8, 4, 0, 0}, HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SPN_SBWC, 2}, {HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SPN_SBWC, 1, 0x22, {12, 0, 0, 0}, HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SPN_SBWC, 2}, diff --git a/libacryl/acrylic_g2d.cpp b/libacryl/acrylic_g2d.cpp index f3f4567..605e9f1 100644 --- a/libacryl/acrylic_g2d.cpp +++ b/libacryl/acrylic_g2d.cpp @@ -508,6 +508,7 @@ static g2d_fmt __halfmt_to_g2dfmt[] = { {HAL_PIXEL_FORMAT_GOOGLE_NV12_SP_10B, G2D_FMT_NV12_P010, 1, 0}, {MALI_GRALLOC_FORMAT_INTERNAL_YUV420_10BIT_I, G2D_FMT_NV12_P010, 1, 0}, {HAL_PIXEL_FORMAT_EXYNOS_YCbCr_P010_M, G2D_FMT_NV12_P010, 2, 0}, + {HAL_PIXEL_FORMAT_EXYNOS_YCbCr_P010_SPN, G2D_FMT_NV12_P010, 1, 0}, {HAL_PIXEL_FORMAT_YCbCr_422_I, G2D_FMT_YUYV, 1, 0}, {HAL_PIXEL_FORMAT_EXYNOS_YCrCb_422_I, G2D_FMT_YVYU, 1, 0}, {HAL_PIXEL_FORMAT_YCbCr_422_SP, G2D_FMT_NV16, 1, 0}, diff --git a/libacryl/acrylic_g2d.h b/libacryl/acrylic_g2d.h index e377017..6ed5942 100644 --- a/libacryl/acrylic_g2d.h +++ b/libacryl/acrylic_g2d.h @@ -70,7 +70,12 @@ public: return; for (unsigned int i = 0; i < mCmds->layer_count; i++) { - unsigned int idx = (mCmds->layer_hdr_mode[i].offset >> 8) - 2; + unsigned int idx; + + if (mWriter->hasColorFillLayer()) + idx = (mCmds->layer_hdr_mode[i].offset >> 8) - 3; + else + idx = (mCmds->layer_hdr_mode[i].offset >> 8) - 2; // If premultiplied alpha values are de-premultied before HDR conversion, // it should be multiplied again after the conversion. But some of the HDR processors diff --git a/libacryl/acrylic_layer.cpp b/libacryl/acrylic_layer.cpp index b90d541..5c587fc 100644 --- a/libacryl/acrylic_layer.cpp +++ b/libacryl/acrylic_layer.cpp @@ -140,7 +140,8 @@ bool AcrylicCanvas::setImageBuffer(int fd[MAX_HW2D_PLANES], size_t len[MAX_HW2D_ for (int i = 0; i < num_buffers; i++) { if ((offset[i] < 0) || (static_cast<size_t>(offset[i]) >= len[i])) { - ALOGE("Too large offset %ld for length %zu of buffer[%d]", offset[i], len[i], i); + ALOGE("Too large offset %jd for length %zu of buffer[%d]", + static_cast<intmax_t>(offset[i]), len[i], i); return false; } @@ -155,8 +156,8 @@ bool AcrylicCanvas::setImageBuffer(int fd[MAX_HW2D_PLANES], size_t len[MAX_HW2D_ m.mBufferFd[i] = fd[i]; mBufferLength[i] = len[i]; mBufferOffset[i] = offset[i]; - ALOGD_TEST("Configured buffer[%d]: fd %d, len %zu, offset %u (type: %s)", - i, m.mBufferFd[i], mBufferLength[i], mBufferOffset[i], + ALOGD_TEST("Configured buffer[%d]: fd %d, len %zu, offset %jd (type: %s)", i, + m.mBufferFd[i], mBufferLength[i], static_cast<intmax_t>(mBufferOffset[i]), canvasTypeName(mCanvasType)); } diff --git a/libacryl/hdrplugin_headers/hardware/exynos/g2d_hdr_plugin.h b/libacryl/hdrplugin_headers/hardware/exynos/g2d_hdr_plugin.h index 02b863a..aefed60 100644 --- a/libacryl/hdrplugin_headers/hardware/exynos/g2d_hdr_plugin.h +++ b/libacryl/hdrplugin_headers/hardware/exynos/g2d_hdr_plugin.h @@ -39,6 +39,7 @@ public: virtual void setTargetDisplayLuminance(unsigned int __unused min, unsigned int __unused max) { }; virtual struct g2d_commandlist *getCommands() = 0; virtual void putCommands(struct g2d_commandlist __unused *commands) { }; + virtual bool hasColorFillLayer(void) { return false; } }; #endif/* __LIBACRYL_PLUGIN_G2D_HDR_H__ */ diff --git a/libhwc2.1/Android.mk b/libhwc2.1/Android.mk index 1918890..1e23ab7 100644 --- a/libhwc2.1/Android.mk +++ b/libhwc2.1/Android.mk @@ -67,8 +67,8 @@ LOCAL_SHARED_LIBRARIES := liblog libcutils libhardware \ libvendorgraphicbuffer libbinder_ndk \ android.hardware.power-V2-ndk pixel-power-ext-V1-ndk -LOCAL_SHARED_LIBRARIES += android.hardware.graphics.composer3-V1-ndk \ - com.google.hardware.pixel.display-V6-ndk \ +LOCAL_SHARED_LIBRARIES += android.hardware.graphics.composer3-V2-ndk \ + com.google.hardware.pixel.display-V8-ndk \ libbinder_ndk \ libbase \ libpng \ @@ -97,13 +97,14 @@ LOCAL_C_INCLUDES += \ $(TOP)/hardware/google/graphics/$(soc_ver)/libhwc2.1/libexternaldisplay \ $(TOP)/hardware/google/graphics/$(soc_ver)/libhwc2.1/libvirtualdisplay \ $(TOP)/hardware/google/graphics/$(soc_ver)/libhwc2.1/libresource \ + $(TOP)/hardware/google/graphics/$(soc_ver)/libhwc2.1/libcolormanager \ $(TOP)/hardware/google/graphics/$(soc_ver)/libhwc2.1/libdevice \ $(TOP)/hardware/google/graphics/$(soc_ver)/libhwc2.1/libresource \ $(TOP)/hardware/google/graphics/$(soc_ver)/libhwc2.1/libdisplayinterface \ $(TOP)/hardware/google/graphics/common/libhwc2.1/libhwcService \ $(TOP)/hardware/google/graphics/common/libhwc2.1/libdisplayinterface \ - $(TOP)/hardware/google/graphics/common/libhwc2.1/libdrmresource/include - + $(TOP)/hardware/google/graphics/common/libhwc2.1/libdrmresource/include \ + $(TOP)/hardware/google/graphics/$(soc_ver) LOCAL_SRC_FILES := \ libhwchelper/ExynosHWCHelper.cpp \ ExynosHWCDebug.cpp \ @@ -120,16 +121,21 @@ LOCAL_SRC_FILES := \ libdisplayinterface/ExynosDisplayInterface.cpp \ libdisplayinterface/ExynosDeviceDrmInterface.cpp \ libdisplayinterface/ExynosDisplayDrmInterface.cpp \ - pixel-display.cpp + pixel-display.cpp \ + histogram_mediator.cpp LOCAL_EXPORT_SHARED_LIBRARY_HEADERS += libacryl libdrm libui libvendorgraphicbuffer LOCAL_VINTF_FRAGMENTS += pixel-display-default.xml +ifeq ($(USES_IDISPLAY_INTF_SEC),true) +LOCAL_VINTF_FRAGMENTS += pixel-display-secondary.xml +endif + include $(TOP)/hardware/google/graphics/$(soc_ver)/libhwc2.1/Android.mk LOCAL_CFLAGS += -DHLOG_CODE=0 -LOCAL_CFLAGS += -DLOG_TAG=\"display\" +LOCAL_CFLAGS += -DLOG_TAG=\"hwc-display\" LOCAL_CFLAGS += -Wno-unused-parameter LOCAL_CFLAGS += -DSOC_VERSION=$(soc_ver) @@ -153,9 +159,10 @@ LOCAL_HEADER_LIBRARIES += libgralloc_headers LOCAL_SHARED_LIBRARIES := liblog libcutils libutils libbinder libexynosdisplay libacryl \ android.hardware.graphics.composer@2.4 \ android.hardware.graphics.allocator@2.0 \ - android.hardware.graphics.mapper@2.0 + android.hardware.graphics.mapper@2.0 \ + android.hardware.graphics.composer3-V2-ndk -LOCAL_SHARED_LIBRARIES += com.google.hardware.pixel.display-V6-ndk \ +LOCAL_SHARED_LIBRARIES += com.google.hardware.pixel.display-V8-ndk \ libbinder_ndk \ libbase @@ -175,6 +182,7 @@ LOCAL_C_INCLUDES += \ $(TOP)/hardware/google/graphics/$(soc_ver)/libhwc2.1/libexternaldisplay \ $(TOP)/hardware/google/graphics/$(soc_ver)/libhwc2.1/libvirtualdisplay \ $(TOP)/hardware/google/graphics/$(soc_ver)/libhwc2.1/libresource \ + $(TOP)/hardware/google/graphics/$(soc_ver)/libhwc2.1/libcolormanager \ $(TOP)/hardware/google/graphics/$(soc_ver)/libhwc2.1/libdevice \ $(TOP)/hardware/google/graphics/$(soc_ver)/libhwc2.1/libresource \ $(TOP)/hardware/google/graphics/common/libhwc2.1/libhwcService \ @@ -185,7 +193,7 @@ LOCAL_EXPORT_SHARED_LIBRARY_HEADERS += libdrm LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_C_INCLUDES) LOCAL_CFLAGS := -DHLOG_CODE=0 -LOCAL_CFLAGS += -DLOG_TAG=\"hwcservice\" +LOCAL_CFLAGS += -DLOG_TAG=\"hwc-service\" LOCAL_CFLAGS += -DSOC_VERSION=$(soc_ver) LOCAL_SRC_FILES := \ @@ -215,8 +223,8 @@ LOCAL_SHARED_LIBRARIES := liblog libcutils libutils libexynosdisplay libacryl \ android.hardware.graphics.mapper@2.0 \ libui -LOCAL_SHARED_LIBRARIES += android.hardware.graphics.composer3-V1-ndk \ - com.google.hardware.pixel.display-V6-ndk \ +LOCAL_SHARED_LIBRARIES += android.hardware.graphics.composer3-V2-ndk \ + com.google.hardware.pixel.display-V8-ndk \ libbinder_ndk \ libbase @@ -225,7 +233,7 @@ LOCAL_HEADER_LIBRARIES := libhardware_legacy_headers libbinder_headers google_ha LOCAL_HEADER_LIBRARIES += libgralloc_headers LOCAL_CFLAGS := -DHLOG_CODE=0 -LOCAL_CFLAGS += -DLOG_TAG=\"hwcomposer\" +LOCAL_CFLAGS += -DLOG_TAG=\"hwc-2\" LOCAL_CFLAGS += -DSOC_VERSION=$(soc_ver) ifeq ($(BOARD_USES_HWC_SERVICES),true) @@ -246,6 +254,7 @@ LOCAL_C_INCLUDES += \ $(TOP)/hardware/google/graphics/$(soc_ver)/libhwc2.1/libmaindisplay \ $(TOP)/hardware/google/graphics/$(soc_ver)/libhwc2.1/libexternaldisplay \ $(TOP)/hardware/google/graphics/$(soc_ver)/libhwc2.1/libvirtualdisplay \ + $(TOP)/hardware/google/graphics/$(soc_ver)/libhwc2.1/libcolormanager \ $(TOP)/hardware/google/graphics/$(soc_ver)/libhwc2.1/libresource \ $(TOP)/hardware/google/graphics/$(soc_ver)/libhwc2.1/libdevice \ $(TOP)/hardware/google/graphics/$(soc_ver)/libhwc2.1/libresource \ diff --git a/libhwc2.1/ExynosHWC.cpp b/libhwc2.1/ExynosHWC.cpp index 8b3d9a4..c21245f 100644 --- a/libhwc2.1/ExynosHWC.cpp +++ b/libhwc2.1/ExynosHWC.cpp @@ -192,7 +192,7 @@ void exynos_getCapabilities(struct hwc2_device *dev, uint32_t *outCount, int32_t if (!exynosDevice) *outCapabilities = 0; else - return exynosDevice->getCapabilities(outCount, outCapabilities); + return exynosDevice->getCapabilitiesLegacy(outCount, outCapabilities); } void exynos_dump(hwc2_device_t *dev, uint32_t *outSize, char *outBuffer) @@ -1149,15 +1149,34 @@ int32_t exynos_SetActiveConfigWithConstraints(hwc2_device_t* dev, hwc2_display_t { HDEBUGLOGD(eDebugDisplayConfig, "%s, %d", __func__, config); ExynosDevice *exynosDevice = checkDevice(dev); + if (!exynosDevice) { + return HWC2_ERROR_BAD_DISPLAY; + } - if (exynosDevice) { - ExynosDisplay *exynosDisplay = checkDisplay(exynosDevice, display); - if (exynosDisplay) { - return exynosDisplay->setActiveConfigWithConstraints(config, vsyncPeriodChangeConstraints, outTimeline); + ExynosDisplay *exynosDisplay = checkDisplay(exynosDevice, display); + if (!exynosDisplay) { + return HWC2_ERROR_BAD_DISPLAY; + } + + const auto prevXres = exynosDisplay->mXres, prevYres = exynosDisplay->mYres; + auto ret = exynosDisplay->setActiveConfigWithConstraints(config, + vsyncPeriodChangeConstraints, + outTimeline); + if (ret != HWC2_ERROR_NONE) { + ALOGE("exynos_SetActiveConfigWithConstraints() failed config(%d)", config); + return ret; + } + + // when resolution is changed, HWC2 updates the property + if (prevXres != exynosDisplay->mDisplayConfigs[config].width || + prevYres != exynosDisplay->mDisplayConfigs[config].height) { + if ((ret = exynosDisplay->setBootDisplayConfig(config)) != HWC2_ERROR_NONE) { + ALOGE("setBootDisplayConfig() failed when setActiveConfigWithConstraints()"); + return ret; } } - return HWC2_ERROR_BAD_DISPLAY; + return HWC2_ERROR_NONE; } int32_t exynos_SetAutoLowLatencyMode(hwc2_device_t* dev, hwc2_display_t display, bool on) diff --git a/libhwc2.1/ExynosHWC.h b/libhwc2.1/ExynosHWC.h index 8d17a74..f1235d9 100644 --- a/libhwc2.1/ExynosHWC.h +++ b/libhwc2.1/ExynosHWC.h @@ -24,9 +24,6 @@ //#define DISABLE_FENCE -#define HWC_FPS_TH 5 /* valid range 1 to 60 */ -#define VSYNC_INTERVAL (1000000000.0 / 60) - enum { HWC_CTL_MAX_OVLY_CNT = 100, HWC_CTL_VIDEO_OVLY_CNT = 101, diff --git a/libhwc2.1/ExynosHWCDebug.cpp b/libhwc2.1/ExynosHWCDebug.cpp index bbf676c..dc42369 100644 --- a/libhwc2.1/ExynosHWCDebug.cpp +++ b/libhwc2.1/ExynosHWCDebug.cpp @@ -18,33 +18,13 @@ #include <sync/sync.h> #include "exynos_sync.h" -uint32_t mErrLogSize = 0; -uint32_t mFenceLogSize = 0; - -int32_t saveErrorLog(const String8 &errString, ExynosDisplay *display) -{ +int32_t saveErrorLog(const String8 &errString, ExynosDisplay *display) { + if (display == nullptr) return -1; int32_t ret = NO_ERROR; - if (mErrLogSize >= ERR_LOG_SIZE) - return -1; - FILE *pFile = NULL; - char filePath[128]; - sprintf(filePath, "%s/hwc_error_log.txt", ERROR_LOG_PATH0); - pFile = fopen(filePath, "a"); - if (pFile == NULL) { - ALOGE("Fail to open file %s/hwc_error_log.txt, error: %s", ERROR_LOG_PATH0, strerror(errno)); - sprintf(filePath, "%s/hwc_error_log.txt", ERROR_LOG_PATH1); - pFile = fopen(filePath, "a"); - } - if (pFile == NULL) { - ALOGE("Fail to open file %s/hwc_error_log.txt, error: %s", ERROR_LOG_PATH1, strerror(errno)); - return -errno; - } + auto &fileWriter = display->mErrLogFileWriter; - mErrLogSize = ftell(pFile); - if (mErrLogSize >= ERR_LOG_SIZE) { - if (pFile != NULL) - fclose(pFile); + if (!fileWriter.chooseOpenedFile()) { return -1; } @@ -52,47 +32,19 @@ int32_t saveErrorLog(const String8 &errString, ExynosDisplay *display) struct timeval tv; gettimeofday(&tv, NULL); - if (display != NULL) { - saveString.appendFormat("%s %s %" PRIu64 ": %s\n", getLocalTimeStr(tv).string(), - display->mDisplayName.string(), display->mErrorFrameCount, - errString.string()); - } else { - saveString.appendFormat("%s : %s\n", getLocalTimeStr(tv).string(), errString.string()); - } + saveString.appendFormat("%s errFrameNumber %" PRIu64 ": %s\n", getLocalTimeStr(tv).string(), + display->mErrorFrameCount, errString.string()); - if (pFile != NULL) { - fwrite(saveString.string(), 1, saveString.size(), pFile); - mErrLogSize = (uint32_t)ftell(pFile); - ret = mErrLogSize; - fclose(pFile); - } + fileWriter.write(saveString); + fileWriter.flush(); return ret; } int32_t saveFenceTrace(ExynosDisplay *display) { int32_t ret = NO_ERROR; + auto &fileWriter = display->mFenceFileWriter; - if (mFenceLogSize >= FENCE_ERR_LOG_SIZE) - return -1; - - FILE *pFile = NULL; - char filePath[128]; - sprintf(filePath, "%s/hwc_fence_state.txt", ERROR_LOG_PATH0); - pFile = fopen(filePath, "a"); - if (pFile == NULL) { - ALOGE("Fail to open file %s/hwc_fence_state.txt, error: %s", ERROR_LOG_PATH0, strerror(errno)); - sprintf(filePath, "%s/hwc_fence_state.txt", ERROR_LOG_PATH1); - pFile = fopen(filePath, "a"); - } - if (pFile == NULL) { - ALOGE("Fail to open file %s, error: %s", ERROR_LOG_PATH1, strerror(errno)); - return -errno; - } - - mFenceLogSize = ftell(pFile); - if (mFenceLogSize >= FENCE_ERR_LOG_SIZE) { - if (pFile != NULL) - fclose(pFile); + if (!fileWriter.chooseOpenedFile()) { return -1; } @@ -117,12 +69,7 @@ int32_t saveFenceTrace(ExynosDisplay *display) { } } - if (pFile != NULL) { - fwrite(saveString.string(), 1, saveString.size(), pFile); - mFenceLogSize = (uint32_t)ftell(pFile); - ret = mFenceLogSize; - fclose(pFile); - } - + fileWriter.write(saveString); + fileWriter.flush(); return ret; } diff --git a/libhwc2.1/ExynosHWCDebug.h b/libhwc2.1/ExynosHWCDebug.h index 01a49cf..8bc6092 100644 --- a/libhwc2.1/ExynosHWCDebug.h +++ b/libhwc2.1/ExynosHWCDebug.h @@ -17,6 +17,8 @@ #define HWC_DEBUG_H #include <utils/String8.h> +#include <utils/Trace.h> + #include "ExynosHWC.h" #include "ExynosHWCHelper.h" @@ -43,6 +45,8 @@ enum { eDebugColorManagement = 0x00080000, eDebugAttrSetting = 0x00100000, eDebugDisplayConfig = 0x00400000, + eDebugTDM = 0x00800000, + eDebugLoadBalancing = 0x01000000, }; class ExynosDisplay; @@ -110,6 +114,13 @@ int32_t saveFenceTrace(ExynosDisplay *display); saveErrorLog(saveString, this); \ } +#define DISPLAY_DRM_LOGI(msg, ...) \ + ALOGI("[%s] " msg, mExynosDisplay->mDisplayName.string(), ##__VA_ARGS__) +#define DISPLAY_DRM_LOGW(msg, ...) \ + ALOGW("[%s] " msg, mExynosDisplay->mDisplayName.string(), ##__VA_ARGS__) +#define DISPLAY_DRM_LOGE(msg, ...) \ + ALOGE("[%s] " msg, mExynosDisplay->mDisplayName.string(), ##__VA_ARGS__) + #define MPP_LOGV(msg, ...) ALOGV("[%s][%d] " msg, mName.string(), mLogicalIndex, ##__VA_ARGS__) #define MPP_LOGI(msg, ...) ALOGI("[%s][%d] " msg, mName.string(), mLogicalIndex, ##__VA_ARGS__) #define MPP_LOGW(msg, ...) ALOGW("[%s][%d] " msg, mName.string(), mLogicalIndex, ##__VA_ARGS__) @@ -129,4 +140,38 @@ int32_t saveFenceTrace(ExynosDisplay *display); saveErrorLog(saveString, display); \ } +class ScopedTraceEnder { +public: + ~ScopedTraceEnder() { ATRACE_END(); } +}; + +#define ATRACE_FORMAT(fmt, ...) \ + if (CC_UNLIKELY(ATRACE_ENABLED())) { \ + String8 traceName; \ + traceName.appendFormat(fmt, ##__VA_ARGS__); \ + ATRACE_BEGIN(traceName.string()); \ + } \ + ScopedTraceEnder traceEnder + +#define DISPLAY_ATRACE_NAME(name) ATRACE_FORMAT("%s for %s", name, mDisplayTraceName.string()) +#define DISPLAY_ATRACE_CALL() DISPLAY_ATRACE_NAME(__func__) +#define DISPLAY_ATRACE_INT(name, value) \ + if (CC_UNLIKELY(ATRACE_ENABLED())) { \ + ATRACE_INT(String8::format("%s for %s", name, mDisplayTraceName.string()).string(), \ + value); \ + } +#define DISPLAY_ATRACE_INT64(name, value) \ + if (CC_UNLIKELY(ATRACE_ENABLED())) { \ + ATRACE_INT64(String8::format("%s for %s", name, mDisplayTraceName.string()).string(), \ + value); \ + } + +#define DISPLAY_LOGD_AND_ATRACE_NAME(debugFlag, fmt, ...) \ + if (hwcCheckDebugMessages(debugFlag) || CC_UNLIKELY(ATRACE_ENABLED())) { \ + String8 log; \ + log.appendFormat((fmt), ##__VA_ARGS__); \ + DISPLAY_LOGD(debugFlag, "%s", log.string()); \ + if (CC_UNLIKELY(ATRACE_ENABLED())) ATRACE_NAME(log.string()); \ + } + #endif diff --git a/libhwc2.1/histogram_mediator.cpp b/libhwc2.1/histogram_mediator.cpp new file mode 100644 index 0000000..f23feec --- /dev/null +++ b/libhwc2.1/histogram_mediator.cpp @@ -0,0 +1,134 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "histogram_mediator.h" + +histogram::HistogramMediator::HistogramMediator(ExynosDisplay *display) { + mDisplay = display; + ExynosDisplayDrmInterface *moduleDisplayInterface = + static_cast<ExynosDisplayDrmInterface *>(display->mDisplayInterface.get()); + mIDLHistogram = std::make_shared<HistogramReceiver>(); + + moduleDisplayInterface->registerHistogramInfo(mIDLHistogram); + moduleDisplayInterface->getPanelResolution(); +} +uint32_t histogram::HistogramMediator::getFrameCount() { + ExynosDisplayDrmInterface *moduleDisplayInterface = + static_cast<ExynosDisplayDrmInterface *>(mDisplay->mDisplayInterface.get()); + return moduleDisplayInterface->getFrameCount(); +} + +bool histogram::HistogramMediator::isDisplayPowerOff() { + if (!mDisplay->mPowerModeState.has_value() || + ((mDisplay->mPowerModeState.value() == HWC2_POWER_MODE_OFF) || + (mDisplay->mPowerModeState.value() == HWC2_POWER_MODE_DOZE))) { + return true; + } + return false; +} + +bool histogram::HistogramMediator::isSecureContentPresenting() { + Mutex::Autolock lock(mDisplay->mDRMutex); + for (uint32_t i = 0; i < mDisplay->mLayers.size(); i++) { + ExynosLayer *layer = mDisplay->mLayers[i]; + if (layer != NULL && layer->isDrm()) { /* there is some DRM layer */ + return true; + } + } + return false; +} +histogram::HistogramErrorCode histogram::HistogramMediator::requestHist() { + if (isSecureContentPresenting()) { /* there is some DRM layer */ + return histogram::HistogramErrorCode::DRM_PLAYING; + } + ExynosDisplayDrmInterface *moduleDisplayInterface = + static_cast<ExynosDisplayDrmInterface *>(mDisplay->mDisplayInterface.get()); + + { + std::unique_lock<std::mutex> lk(mIDLHistogram->mDataCollectingMutex); + if (moduleDisplayInterface->setHistogramControl( + hidl_histogram_control_t::HISTOGRAM_CONTROL_REQUEST) != NO_ERROR) { + return histogram::HistogramErrorCode::ENABLE_HIST_ERROR; + } + mIDLHistogram->mHistReq_pending = true; + } + return histogram::HistogramErrorCode::NONE; +} + +histogram::HistogramErrorCode histogram::HistogramMediator::cancelHistRequest() { + ExynosDisplayDrmInterface *moduleDisplayInterface = + static_cast<ExynosDisplayDrmInterface *>(mDisplay->mDisplayInterface.get()); + + if (moduleDisplayInterface->setHistogramControl( + hidl_histogram_control_t::HISTOGRAM_CONTROL_CANCEL) != NO_ERROR) { + return histogram::HistogramErrorCode::DISABLE_HIST_ERROR; + } + return histogram::HistogramErrorCode::NONE; +} + +void histogram::HistogramMediator::HistogramReceiver::callbackHistogram(char16_t *bin) { + std::unique_lock<std::mutex> lk(mDataCollectingMutex); + if (mHistReq_pending == true) { + std::memcpy(mHistData, bin, HISTOGRAM_BINS_SIZE * sizeof(char16_t)); + mHistReq_pending = false; + } + mHistData_cv.notify_all(); +} + +int histogram::HistogramMediator::calculateThreshold(const RoiRect &roi) { + int threshold = ((roi.bottom - roi.top) * (roi.right - roi.left)) >> 16; + return threshold + 1; +} + +histogram::HistogramErrorCode histogram::HistogramMediator::setRoiWeightThreshold( + const RoiRect &roi, const Weight &weight, const HistogramPos &pos) { + int threshold = calculateThreshold(roi); + mIDLHistogram->setHistogramROI((uint16_t)roi.left, (uint16_t)roi.top, + (uint16_t)(roi.right - roi.left), + (uint16_t)(roi.bottom - roi.top)); + mIDLHistogram->setHistogramWeights(weight.weightR, weight.weightG, weight.weightB); + mIDLHistogram->setHistogramThreshold(threshold); + mIDLHistogram->setHistogramPos(pos); + + return histogram::HistogramErrorCode::NONE; +} + +histogram::HistogramErrorCode histogram::HistogramMediator::collectRoiLuma( + std::vector<char16_t> *buf) { + std::unique_lock<std::mutex> lk(mIDLHistogram->mDataCollectingMutex); + + mIDLHistogram->mHistData_cv.wait_for(lk, std::chrono::milliseconds(50), [this]() { + return (!isDisplayPowerOff() && !mIDLHistogram->mHistReq_pending); + }); + if (mIDLHistogram->mHistReq_pending == false) setSampleFrameCounter(getFrameCount()); + buf->assign(mIDLHistogram->mHistData, mIDLHistogram->mHistData + HISTOGRAM_BINS_SIZE); + + return histogram::HistogramErrorCode::NONE; +} + +histogram::RoiRect histogram::HistogramMediator::calRoi(const RoiRect &roi) { + RoiRect roi_return = {-1, -1, -1, -1}; + ExynosDisplayDrmInterface *moduleDisplayInterface = + static_cast<ExynosDisplayDrmInterface *>(mDisplay->mDisplayInterface.get()); + roi_return.left = roi.left * moduleDisplayInterface->getActiveModeHDisplay() / + moduleDisplayInterface->panelHsize(); + roi_return.top = roi.top * moduleDisplayInterface->getActiveModeVDisplay() / + moduleDisplayInterface->panelVsize(); + roi_return.right = roi.right * moduleDisplayInterface->getActiveModeHDisplay() / + moduleDisplayInterface->panelHsize(); + roi_return.bottom = roi.bottom * moduleDisplayInterface->getActiveModeVDisplay() / + moduleDisplayInterface->panelVsize(); + return roi_return; +} diff --git a/libhwc2.1/histogram_mediator.h b/libhwc2.1/histogram_mediator.h new file mode 100644 index 0000000..54d28c9 --- /dev/null +++ b/libhwc2.1/histogram_mediator.h @@ -0,0 +1,118 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef HISTOGRAM_MEDIATOR_H_ +#define HISTOGRAM_MEDIATOR_H_ + +#include <aidl/android/hardware/graphics/common/Rect.h> +#include <aidl/com/google/hardware/pixel/display/BnDisplay.h> +#include <aidl/com/google/hardware/pixel/display/HistogramErrorCode.h> +#include <aidl/com/google/hardware/pixel/display/HistogramPos.h> +#include <aidl/com/google/hardware/pixel/display/Priority.h> +#include <aidl/com/google/hardware/pixel/display/Weight.h> +#include <xf86drm.h> +#include <xf86drmMode.h> + +#include <condition_variable> +#include <mutex> +#include <vector> + +#define HWC2_INCLUDE_STRINGIFICATION +#define HWC2_USE_CPP11 +#include <hardware/hwcomposer2.h> +#undef HWC2_INCLUDE_STRINGIFICATION +#undef HWC2_USE_CPP11 +#include "ExynosDevice.h" +#include "ExynosDisplay.h" +#include "ExynosDisplayDrmInterfaceModule.h" +#include "ExynosDisplayInterface.h" +#include "ExynosLayer.h" + +namespace histogram { +using RoiRect = ::aidl::android::hardware::graphics::common::Rect; +using Weight = ::aidl::com::google::hardware::pixel::display::Weight; +using HistogramPos = ::aidl::com::google::hardware::pixel::display::HistogramPos; +using Priority = ::aidl::com::google::hardware::pixel::display::Priority; +using HistogramErrorCode = ::aidl::com::google::hardware::pixel::display::HistogramErrorCode; + +constexpr size_t HISTOGRAM_BINS_SIZE = 256; +constexpr size_t WEIGHT_SUM = 1024; + +class HistogramMediator { +public: + HistogramMediator() = default; + HistogramMediator(ExynosDisplay *display); + ~HistogramMediator() {} + + bool isDisplayPowerOff(); + bool isSecureContentPresenting(); + HistogramErrorCode requestHist(); + HistogramErrorCode cancelHistRequest(); + HistogramErrorCode collectRoiLuma(std::vector<char16_t> *buf); + HistogramErrorCode setRoiWeightThreshold(const RoiRect &roi, const Weight &weight, + const HistogramPos &pos); + RoiRect calRoi(const RoiRect &roi); + struct HistogramReceiver : public IDLHistogram { + HistogramReceiver() : mHistData(){}; + void callbackHistogram(char16_t *bin) override; + uint16_t mHistData[HISTOGRAM_BINS_SIZE]; // luma buffer + std::condition_variable mHistData_cv; // for pullback data sync ctrl + bool mHistReq_pending = false; + std::mutex mDataCollectingMutex; // for data collecting operations + }; + + struct HistogramConfig { + RoiRect mRoi; + Weight mWeights; + HistogramPos mPos; + + HistogramConfig() {} + + HistogramConfig(const RoiRect &roi, const Weight &weights, const HistogramPos &pos) { + mRoi = roi; + mWeights = weights; + mPos = pos; + } + + bool operator!=(const HistogramConfig &rhs) { + return mRoi != rhs.mRoi || mWeights != rhs.mWeights || mPos != rhs.mPos; + } + + HistogramConfig &operator=(const HistogramConfig &rhs) { + mRoi = rhs.mRoi; + mWeights = rhs.mWeights; + mPos = rhs.mPos; + return *this; + } + }; + + uint32_t getFrameCount(); + void setSampleFrameCounter(int32_t id) { mSampledFrameCounter = id; } + uint32_t getSampleFrameCounter() { return mSampledFrameCounter; } + bool histRequested() { return mIDLHistogram->mHistReq_pending; } + std::mutex mConfigMutex; + HistogramConfig mConfig GUARDED_BY(mConfigMutex); + +private: + int calculateThreshold(const RoiRect &roi); + std::shared_ptr<HistogramReceiver> mIDLHistogram; + ExynosDisplay *mDisplay = nullptr; + uint32_t mSampledFrameCounter = 0; +}; + +} // namespace histogram + +#endif // HISTOGRAM_MEDIATOR_H_ diff --git a/libhwc2.1/libdevice/BrightnessController.cpp b/libhwc2.1/libdevice/BrightnessController.cpp index 40fb813..5a226e0 100644 --- a/libhwc2.1/libdevice/BrightnessController.cpp +++ b/libhwc2.1/libdevice/BrightnessController.cpp @@ -34,10 +34,12 @@ BrightnessController::BrightnessController(int32_t panelIndex, std::function<voi mLhbm(false), mSdrDim(false), mPrevSdrDim(false), + mDimBrightnessReq(false), mFrameRefresh(refresh), mHdrLayerState(HdrLayerState::kHdrNone), mUpdateDcLhbm(updateDcLhbm) { initBrightnessSysfs(); + initCabcSysfs(); } BrightnessController::~BrightnessController() { @@ -58,14 +60,21 @@ int BrightnessController::initDrm(const DrmDevice& drmDevice, mLhbmSupported = connector.lhbm_on().id() != 0; mGhbmSupported = connector.hbm_mode().id() != 0; + + /* allow the first brightness to apply */ + mBrightnessFloatReq.set_dirty(); return NO_ERROR; } void BrightnessController::initDimmingUsage() { - mBrightnessDimmingUsage = static_cast<BrightnessDimmingUsage>( - property_get_int32("vendor.display.brightness.dimming.usage", 0)); - mHbmDimmingTimeUs = - property_get_int32("vendor.display.brightness.dimming.hbm_time", kHbmDimmingTimeUs); + String8 propName; + propName.appendFormat(kDimmingUsagePropName, mPanelIndex); + + mBrightnessDimmingUsage = static_cast<BrightnessDimmingUsage>(property_get_int32(propName, 0)); + + propName.clear(); + propName.appendFormat(kDimmingHbmTimePropName, mPanelIndex); + mHbmDimmingTimeUs = property_get_int32(propName, kHbmDimmingTimeUs); if (mBrightnessDimmingUsage == BrightnessDimmingUsage::NORMAL) { mDimming.store(true); @@ -100,6 +109,21 @@ void BrightnessController::initBrightnessSysfs() { ifsMaxBrightness.close(); } +void BrightnessController::initCabcSysfs() { + mCabcSupport = property_get_bool("vendor.display.cabc.supported", false); + if (!mCabcSupport) return; + + String8 nodeName; + nodeName.appendFormat(kLocalCabcModeFileNode, mPanelIndex); + + mCabcModeOfs.open(nodeName.string(), std::ofstream::out); + if (mCabcModeOfs.fail()) { + ALOGE("%s %s fail to open", __func__, nodeName.string()); + mCabcModeOfs.close(); + return; + } +} + void BrightnessController::initBrightnessTable(const DrmDevice& drmDevice, const DrmConnector& connector) { if (connector.brightness_cap().id() == 0) { @@ -133,9 +157,25 @@ void BrightnessController::initBrightnessTable(const DrmDevice& drmDevice, // init to min before SF sets the brightness mDisplayWhitePointNits = cap->normal.nits.min; + mPrevDisplayWhitePointNits = mDisplayWhitePointNits; mBrightnessIntfSupported = true; drmModeFreePropertyBlob(blob); + + String8 nodeName; + nodeName.appendFormat(kDimBrightnessFileNode, mPanelIndex); + + std::ifstream ifsDimBrightness(nodeName.string()); + if (ifsDimBrightness.fail()) { + ALOGW("%s fail to open %s", __func__, nodeName.string()); + } else { + ifsDimBrightness >> mDimBrightness; + ifsDimBrightness.close(); + if (mDimBrightness >= mBrightnessTable[toUnderlying(BrightnessRange::NORMAL)].mBklStart) + mDimBrightness = 0; + } + mDbmSupported = !!mDimBrightness; + ALOGI("%s mDimBrightness=%d, mDbmSupported=%d", __func__, mDimBrightness, mDbmSupported); } int BrightnessController::processEnhancedHbm(bool on) { @@ -177,6 +217,9 @@ int BrightnessController::processDisplayBrightness(float brightness, const nsecs { std::lock_guard<std::recursive_mutex> lock(mBrightnessMutex); + /* apply the first brightness */ + if (mBrightnessFloatReq.is_dirty()) mBrightnessLevel.set_dirty(); + mBrightnessFloatReq.store(brightness); if (!mBrightnessFloatReq.is_dirty()) { return NO_ERROR; @@ -185,20 +228,14 @@ int BrightnessController::processDisplayBrightness(float brightness, const nsecs // check if it will go drm path for below cases. // case 1: hbm state will change // case 2: for hwc3, brightness command could apply at next present if possible - if (mGhbmSupported || waitPresent) { + if (queryBrightness(brightness, &ghbm, &level) == NO_ERROR) { // ghbm on/off always go drm path - if (mGhbmSupported) { - if (queryBrightness(brightness, &ghbm, &level)) { - ALOGE("%s failed to convert brightness %f", __func__, brightness); - return -EINVAL; - } - // check if this will cause a hbm transition - if ((mGhbm.get() != HbmMode::OFF) != ghbm) { - // this brightness change will go drm path - updateStates(); - mFrameRefresh(); // force next frame to update brightness - return NO_ERROR; - } + // check if this will cause a hbm transition + if (mGhbmSupported && (mGhbm.get() != HbmMode::OFF) != ghbm) { + // this brightness change will go drm path + updateStates(); + mFrameRefresh(); // force next frame to update brightness + return NO_ERROR; } // there will be a Present to apply this brightness change if (waitPresent) { @@ -209,21 +246,23 @@ int BrightnessController::processDisplayBrightness(float brightness, const nsecs } else { level = brightness < 0 ? 0 : static_cast<uint32_t>(brightness * mMaxBrightness + 0.5f); } - // go sysfs path + // clear dirty before go sysfs path + mBrightnessFloatReq.clear_dirty(); } // Sysfs path is faster than drm path. If there is an unchecked drm path change, the sysfs // path should check the sysfs content. if (mUncheckedGbhmRequest) { ATRACE_NAME("check_ghbm_mode"); - checkSysfsStatus(kGlobalHbmModeFileNode, - std::to_string(toUnderlying(mPendingGhbmStatus.load())), vsyncNs * 5); + checkSysfsStatus(GetPanelSysfileByIndex(kGlobalHbmModeFileNode), + {std::to_string(toUnderlying(mPendingGhbmStatus.load()))}, vsyncNs * 5); mUncheckedGbhmRequest = false; } if (mUncheckedLhbmRequest) { ATRACE_NAME("check_lhbm_mode"); - checkSysfsStatus(kLocalHbmModeFileNode, std::to_string(mPendingLhbmStatus), vsyncNs * 5); + checkSysfsStatus(GetPanelSysfileByIndex(kLocalHbmModeFileNode), + {std::to_string(mPendingLhbmStatus)}, vsyncNs * 5); mUncheckedLhbmRequest = false; } @@ -262,7 +301,8 @@ int BrightnessController::applyPendingChangeViaSysfs(const nsecs_t vsyncNs) { if (mUncheckedBlRequest) { ATRACE_NAME("check_bl_value"); - checkSysfsStatus(BRIGHTNESS_SYSFS_NODE, std::to_string(mPendingBl), vsyncNs * 5); + checkSysfsStatus(GetPanelSysfileByIndex(BRIGHTNESS_SYSFS_NODE), + {std::to_string(mPendingBl)}, vsyncNs * 5); mUncheckedBlRequest = false; } @@ -276,6 +316,13 @@ int BrightnessController::processLocalHbm(bool on) { std::lock_guard<std::recursive_mutex> lock(mBrightnessMutex); mLhbmReq.store(on); + // As kernel timeout timer might disable LHBM without letting HWC know, enforce mLhbmReq and + // mLhbm dirty to ensure the enabling request can be passed through kernel unconditionally. + // TODO-b/260915350: move LHBM timeout mechanism from kernel to HWC for easier control and sync. + if (on) { + mLhbmReq.set_dirty(); + mLhbm.set_dirty(); + } if (mLhbmReq.is_dirty()) { updateStates(); } @@ -310,6 +357,16 @@ int BrightnessController::processInstantHbm(bool on) { return NO_ERROR; } +int BrightnessController::processDimBrightness(bool on) { + std::lock_guard<std::recursive_mutex> lock(mBrightnessMutex); + mDimBrightnessReq.store(on); + if (mDimBrightnessReq.is_dirty()) { + updateStates(); + ALOGI("%s request = %d", __func__, mDimBrightnessReq.get()); + } + return NO_ERROR; +} + float BrightnessController::getSdrDimRatioForInstantHbm() { if (!mBrightnessIntfSupported || !mGhbmSupported) { return 1.0f; @@ -340,28 +397,36 @@ float BrightnessController::getSdrDimRatioForInstantHbm() { return ratio; } -void BrightnessController::onClearDisplay() { +void BrightnessController::onClearDisplay(bool needModeClear) { + resetLhbmState(); + mInstantHbmReq.reset(false); + + if (mBrightnessLevel.is_dirty()) applyBrightnessViaSysfs(mBrightnessLevel.get()); + + if (!needModeClear) return; + std::lock_guard<std::recursive_mutex> lock(mBrightnessMutex); mEnhanceHbmReq.reset(false); - mLhbmReq.reset(false); mBrightnessFloatReq.reset(-1); - mInstantHbmReq.reset(false); mBrightnessLevel.reset(0); + mDisplayWhitePointNits = 0; + mPrevDisplayWhitePointNits = 0; mGhbm.reset(HbmMode::OFF); mDimming.reset(false); mHbmDimming = false; if (mBrightnessDimmingUsage == BrightnessDimmingUsage::NORMAL) { mDimming.store(true); } - mLhbm.reset(false); - mLhbmBrightnessAdj = false; + std::lock_guard<std::recursive_mutex> lock1(mCabcModeMutex); + mCabcMode.reset(CabcMode::OFF); } int BrightnessController::prepareFrameCommit(ExynosDisplay& display, const DrmConnector& connector, ExynosDisplayDrmInterface::DrmModeAtomicReq& drmReq, + const bool mixedComposition, bool& ghbmSync, bool& lhbmSync, bool& blSync) { int ret; @@ -372,6 +437,17 @@ int BrightnessController::prepareFrameCommit(ExynosDisplay& display, ATRACE_CALL(); std::lock_guard<std::recursive_mutex> lock(mBrightnessMutex); + bool sync = false; + if (mixedComposition && mPrevDisplayWhitePointNits > 0 && mDisplayWhitePointNits > 0) { + float diff = std::abs(mPrevDisplayWhitePointNits - mDisplayWhitePointNits); + float min = std::min(mPrevDisplayWhitePointNits, mDisplayWhitePointNits); + if (diff / min > kBrightnessSyncThreshold) { + sync = true; + ALOGD("%s: enable brightness sync for change from %f to %f", __func__, + mPrevDisplayWhitePointNits, mDisplayWhitePointNits); + } + } + if (mDimming.is_dirty()) { if ((ret = drmReq.atomicAddProperty(connector.id(), connector.dimming_on(), mDimming.get())) < 0) { @@ -437,9 +513,11 @@ int BrightnessController::prepareFrameCommit(ExynosDisplay& display, } else { mUncheckedBlRequest = true; mPendingBl = mBrightnessLevel.get(); + blSync = sync; } } mBrightnessLevel.clear_dirty(); + mPrevDisplayWhitePointNits = mDisplayWhitePointNits; } if (mGhbm.is_dirty() && mGhbmSupported) { @@ -455,7 +533,7 @@ int BrightnessController::prepareFrameCommit(ExynosDisplay& display, hbmEnum)) < 0) { ALOGE("%s: Fail to set hbm_mode property", __func__); } else { - ghbmSync = true; + ghbmSync = sync; } mGhbm.clear_dirty(); } @@ -558,11 +636,11 @@ int BrightnessController::updateStates() { mInstantHbmReq.clear_dirty(); mSdrDim.clear_dirty(); mPrevSdrDim.clear_dirty(); + mDimBrightnessReq.clear_dirty(); if (mBrightnessLevel.is_dirty() || mDimming.is_dirty() || mGhbm.is_dirty() || mLhbm.is_dirty()) { - ALOGI("level=%d, DimmingOn=%d, Hbm=%d, LhbmOn=%d.", mBrightnessLevel.get(), mDimming.get(), - mGhbm.get(), mLhbm.get()); + printBrightnessStates("drm"); } return NO_ERROR; } @@ -573,6 +651,15 @@ int BrightnessController::queryBrightness(float brightness, bool *ghbm, uint32_t return HWC2_ERROR_UNSUPPORTED; } + if (mBrightnessTable[toUnderlying(BrightnessRange::NORMAL)].mBklStart == 0 && + mBrightnessTable[toUnderlying(BrightnessRange::NORMAL)].mBklEnd == 0 && + mBrightnessTable[toUnderlying(BrightnessRange::NORMAL)].mBriStart == 0 && + mBrightnessTable[toUnderlying(BrightnessRange::NORMAL)].mBriEnd == 0 && + mBrightnessTable[toUnderlying(BrightnessRange::NORMAL)].mNitsStart == 0 && + mBrightnessTable[toUnderlying(BrightnessRange::NORMAL)].mNitsEnd == 0) { + return HWC2_ERROR_UNSUPPORTED; + } + if (brightness < 0) { // screen off if (ghbm) { @@ -608,7 +695,10 @@ int BrightnessController::queryBrightness(float brightness, bool *ghbm, uint32_t *nits = norm * nSpan + mBrightnessTable[i].mNitsStart; } } - + if ((i == toUnderlying(BrightnessRange::NORMAL)) && mDbmSupported && + (mDimBrightnessReq.get() == true) && (*level == mBrightnessTable[i].mBklStart)) { + *level = mDimBrightness; + } return NO_ERROR; } } @@ -617,27 +707,39 @@ int BrightnessController::queryBrightness(float brightness, bool *ghbm, uint32_t } // Return immediately if it's already in the status. Otherwise poll the status -int BrightnessController::checkSysfsStatus(const char* file, const std::string& expectedValue, +int BrightnessController::checkSysfsStatus(const std::string& file, + const std::vector<std::string>& expectedValue, const nsecs_t timeoutNs) { ATRACE_CALL(); + + if (expectedValue.size() == 0) { + return -EINVAL; + } + char buf[16]; - String8 nodeName; - nodeName.appendFormat(file, mPanelIndex); - UniqueFd fd = open(nodeName.string(), O_RDONLY); + UniqueFd fd = open(file.c_str(), O_RDONLY); + if (fd.get() < 0) { + ALOGE("%s failed to open sysfs %s: %s", __func__, file.c_str(), strerror(errno)); + return -ENOENT; + } int size = read(fd.get(), buf, sizeof(buf)); if (size <= 0) { - ALOGE("%s failed to read from %s", __func__, kLocalHbmModeFileNode); - return false; + ALOGE("%s failed to read from %s: %s", __func__, file.c_str(), strerror(errno)); + return -EIO; } // '- 1' to remove trailing '\n' - if (std::string_view(buf, size - 1) == expectedValue) { - return true; + std::string val = std::string(buf, size - 1); + if (std::find(expectedValue.begin(), expectedValue.end(), val) != expectedValue.end()) { + return OK; + } else if (timeoutNs == 0) { + // not get the expected value and no intention to wait + return -EINVAL; } struct pollfd pfd; - int ret = EINVAL; + int ret = -EINVAL; auto startTime = systemTime(SYSTEM_TIME_MONOTONIC); pfd.fd = fd.get(); @@ -651,9 +753,9 @@ int BrightnessController::checkSysfsStatus(const char* file, const std::string& } int pollRet = poll(&pfd, 1, ns2ms(remainTimeNs)); if (pollRet == 0) { - ALOGW("%s poll timeout", __func__); + ALOGW("%s poll %s timeout", __func__, file.c_str()); // time out - ret = ETIMEDOUT; + ret = -ETIMEDOUT; break; } else if (pollRet > 0) { if (!(pfd.revents & POLLPRI)) { @@ -663,31 +765,72 @@ int BrightnessController::checkSysfsStatus(const char* file, const std::string& lseek(fd.get(), 0, SEEK_SET); size = read(fd.get(), buf, sizeof(buf)); if (size > 0) { - if (std::string_view(buf, size - 1) == expectedValue) { - ret = 0; + val = std::string(buf, size - 1); + if (std::find(expectedValue.begin(), expectedValue.end(), val) != + expectedValue.end()) { + ret = OK; + break; } else { - buf[size - 1] = 0; - ALOGE("%s read %s expected %s after notified", __func__, buf, - expectedValue.c_str()); - ret = EINVAL; + std::string values; + for (auto& s : expectedValue) { + values += s + std::string(" "); + } + if (values.size() > 0) { + values.resize(values.size() - 1); + } + ALOGW("%s read %s expected %s after notified on file %s", __func__, val.c_str(), + values.c_str(), file.c_str()); } } else { - ret = EIO; - ALOGE("%s failed to read after notified %d", __func__, errno); + ret = -EIO; + ALOGE("%s failed to read after notified %d on file %s", __func__, errno, + file.c_str()); + break; } - break; } else { if (errno == EAGAIN || errno == EINTR) { continue; } - ALOGE("%s poll failed %d", __func__, errno); - ret = errno; + ALOGE("%s poll failed %d on file %s", __func__, errno, file.c_str()); + ret = -errno; break; } }; - return ret == NO_ERROR; + return ret; +} + +void BrightnessController::resetLhbmState() { + std::lock_guard<std::recursive_mutex> lock(mBrightnessMutex); + mLhbmReq.reset(false); + mLhbm.reset(false); + mLhbmBrightnessAdj = false; +} + +void BrightnessController::setOutdoorVisibility(LbeState state) { + std::lock_guard<std::recursive_mutex> lock(mCabcModeMutex); + mOutdoorVisibility = (state != LbeState::OFF); +} + +int BrightnessController::updateCabcMode() { + if (!mCabcSupport || mCabcModeOfs.fail()) return HWC2_ERROR_UNSUPPORTED; + + std::lock_guard<std::recursive_mutex> lock(mCabcModeMutex); + CabcMode mode; + if (mOutdoorVisibility) + mode = CabcMode::OFF; + else + mode = isHdrLayerOn() ? CabcMode::CABC_MOVIE_MODE : CabcMode::CABC_UI_MODE; + mCabcMode.store(mode); + + if (mCabcMode.is_dirty()) { + applyCabcModeViaSysfs(static_cast<uint8_t>(mode)); + ALOGD("%s, isHdrLayerOn: %d, mOutdoorVisibility: %d.", __func__, isHdrLayerOn(), + mOutdoorVisibility); + mCabcMode.clear_dirty(); + } + return NO_ERROR; } int BrightnessController::applyBrightnessViaSysfs(uint32_t level) { @@ -705,8 +848,8 @@ int BrightnessController::applyBrightnessViaSysfs(uint32_t level) { { std::lock_guard<std::recursive_mutex> lock(mBrightnessMutex); mBrightnessLevel.reset(level); - ALOGI("level=%d, DimmingOn=%d, Hbm=%d, LhbmOn=%d", level, - mDimming.get(), mGhbm.get(), mLhbm.get()); + mPrevDisplayWhitePointNits = mDisplayWhitePointNits; + printBrightnessStates("sysfs"); } return NO_ERROR; @@ -715,6 +858,22 @@ int BrightnessController::applyBrightnessViaSysfs(uint32_t level) { return HWC2_ERROR_UNSUPPORTED; } +int BrightnessController::applyCabcModeViaSysfs(uint8_t mode) { + if (!mCabcModeOfs.is_open()) return HWC2_ERROR_UNSUPPORTED; + + ATRACE_NAME("write_cabc_mode_sysfs"); + mCabcModeOfs.seekp(std::ios_base::beg); + mCabcModeOfs << std::to_string(mode); + mCabcModeOfs.flush(); + if (mCabcModeOfs.fail()) { + ALOGE("%s fail to write CabcMode %d", __func__, mode); + mCabcModeOfs.clear(); + return HWC2_ERROR_NO_RESOURCES; + } + ALOGI("%s Cabc_Mode=%d", __func__, mode); + return NO_ERROR; +} + // brightness is normalized to current display brightness bool BrightnessController::validateLayerBrightness(float brightness) { std::lock_guard<std::recursive_mutex> lock(mBrightnessMutex); @@ -745,6 +904,15 @@ void BrightnessController::parseHbmModeEnums(const DrmProperty& property) { } } +/* + * WARNING: This print is parsed by Battery Historian. Consult with the Battery + * Historian team before modifying (b/239640926). + */ +void BrightnessController::printBrightnessStates(const char* path) { + ALOGI("path=%s, id=%d, level=%d, DimmingOn=%d, Hbm=%d, LhbmOn=%d", path ?: "unknown", + mPanelIndex, mBrightnessLevel.get(), mDimming.get(), mGhbm.get(), mLhbm.get()); +} + void BrightnessController::dump(String8& result) { std::lock_guard<std::recursive_mutex> lock(mBrightnessMutex); @@ -753,10 +921,10 @@ void BrightnessController::dump(String8& result) { "lhbm supported %d, ghbm supported %d\n", mBrightnessOfs.is_open(), mMaxBrightness, mBrightnessIntfSupported, mLhbmSupported, mGhbmSupported); result.appendFormat("\trequests: enhance hbm %d, lhbm %d, " - "brightness %f, instant hbm %d\n", + "brightness %f, instant hbm %d, DimBrightness %d\n", mEnhanceHbmReq.get(), mLhbmReq.get(), mBrightnessFloatReq.get(), - mInstantHbmReq.get()); - result.appendFormat("\tstates: brighntess level %d, ghbm %d, dimming %d, lhbm %d\n", + mInstantHbmReq.get(), mDimBrightnessReq.get()); + result.appendFormat("\tstates: brighntess level %d, ghbm %d, dimming %d, lhbm %d", mBrightnessLevel.get(), mGhbm.get(), mDimming.get(), mLhbm.get()); result.appendFormat("\thdr layer state %d, unchecked lhbm request %d(%d), " "unchecked ghbm request %d(%d)\n", @@ -765,6 +933,10 @@ void BrightnessController::dump(String8& result) { mPendingGhbmStatus.load()); result.appendFormat("\tdimming usage %d, hbm dimming %d, time us %d\n", mBrightnessDimmingUsage, mHbmDimming, mHbmDimmingTimeUs); - result.appendFormat("\twhite point nits %f\n", mDisplayWhitePointNits); + result.appendFormat("\twhite point nits current %f, previous %f\n", mDisplayWhitePointNits, + mPrevDisplayWhitePointNits); + result.appendFormat("\tcabc supported %d, cabcMode %d\n", mCabcModeOfs.is_open(), + mCabcMode.get()); + result.appendFormat("\n"); } diff --git a/libhwc2.1/libdevice/BrightnessController.h b/libhwc2.1/libdevice/BrightnessController.h index 2e4d304..66f4b23 100644 --- a/libhwc2.1/libdevice/BrightnessController.h +++ b/libhwc2.1/libdevice/BrightnessController.h @@ -65,6 +65,8 @@ public: int processEnhancedHbm(bool on); int processDisplayBrightness(float bl, const nsecs_t vsyncNs, bool waitPresent = false); int processLocalHbm(bool on); + int processDimBrightness(bool on); + bool isDbmSupported() { return mDbmSupported; } int applyPendingChangeViaSysfs(const nsecs_t vsyncNs); bool validateLayerBrightness(float brightness); @@ -88,7 +90,7 @@ public: */ float getSdrDimRatioForInstantHbm(); - void onClearDisplay(); + void onClearDisplay(bool needModeClear); /** * apply brightness change on drm path. @@ -97,6 +99,7 @@ public: int prepareFrameCommit(ExynosDisplay& display, const DrmConnector& connector, ExynosDisplayDrmInterface::DrmModeAtomicReq& drmReq, + const bool mixedComposition, bool& ghbmSync, bool& lhbmSync, bool& blSync); bool isGhbmSupported() { return mGhbmSupported; } @@ -111,8 +114,13 @@ public: std::lock_guard<std::recursive_mutex> lock(mBrightnessMutex); return mLhbm.get(); } - int checkSysfsStatus(const char *file, const std::string &expectedValue, + int checkSysfsStatus(const std::string& file, const std::vector<std::string>& expectedValue, const nsecs_t timeoutNs); + bool fileExists(const std::string& file) { + struct stat sb; + return stat(file.c_str(), &sb) == 0; + } + void resetLhbmState(); uint32_t getBrightnessLevel() { std::lock_guard<std::recursive_mutex> lock(mBrightnessMutex); @@ -135,6 +143,25 @@ public: void dump(String8 &result); + void setOutdoorVisibility(LbeState state); + + int updateCabcMode(); + + const std::string GetPanelSysfileByIndex(const char *file_pattern) { + String8 nodeName; + nodeName.appendFormat(file_pattern, mPanelIndex); + return nodeName.c_str(); + } + + const std::string GetPanelRefreshRateSysfile() { + String8 nodeName; + nodeName.appendFormat(kRefreshrateFileNode, + mPanelIndex == 0 ? "primary" + : mPanelIndex == 1 ? "secondary" + : "unknown"); + return nodeName.c_str(); + } + struct BrightnessTable { float mBriStart; float mBriEnd; @@ -154,16 +181,39 @@ public: const BrightnessTable *getBrightnessTable() { return mBrightnessTable; } + /* + * WARNING: This enum is parsed by Battery Historian. Add new values, but + * do not modify/remove existing ones. Alternatively, consult with the + * Battery Historian team (b/239640926). + */ enum class BrightnessRange : uint32_t { NORMAL = 0, - HBM, + HBM = 1, MAX, }; + /* + * WARNING: This enum is parsed by Battery Historian. Add new values, but + * do not modify/remove existing ones. Alternatively, consult with the + * Battery Historian team (b/239640926). + */ enum class HbmMode { OFF = 0, - ON_IRC_ON, - ON_IRC_OFF, + ON_IRC_ON = 1, + ON_IRC_OFF = 2, + }; + + /* + * LHBM command need take a couple of frames to become effective + * DISABLED - finish sending disabling command to panel + * ENABLED - panel finishes boosting brightness to the peak value + * ENABLING - finish sending enabling command to panel (panel begins boosting brightness) + * Note: the definition should be consistent with kernel driver + */ + enum class LhbmMode { + DISABLED = 0, + ENABLED = 1, + ENABLING = 2, }; /* @@ -171,36 +221,60 @@ public: * NORMAL- enable dimming * HBM- enable dimming only for hbm transition * NONE- disable dimming + * + * WARNING: This enum is parsed by Battery Historian. Add new values, but + * do not modify/remove existing ones. Alternatively, consult with the + * Battery Historian team (b/239640926). */ enum class BrightnessDimmingUsage { NORMAL = 0, - HBM, + HBM = 1, NONE, }; static constexpr const char *kLocalHbmModeFileNode = "/sys/class/backlight/panel%d-backlight/local_hbm_mode"; + static constexpr const char* kDimBrightnessFileNode = + "/sys/class/backlight/panel%d-backlight/dim_brightness"; + static constexpr const char* kRefreshrateFileNode = + "/sys/devices/platform/exynos-drm/%s-panel/refresh_rate"; + private: + // sync brightness change for mixed composition when there is more than 50% luminance change. + // The percentage is calculated as: + // (big_lumi - small_lumi) / small_lumi + // For mixed composition, if remove brightness animations, the minimum brightness jump is + // between nbm peak and hbm peak. 50% will cover known panels + static constexpr float kBrightnessSyncThreshold = 0.5f; // Worst case for panel with brightness range 2 nits to 1000 nits. static constexpr float kGhbmMinDimRatio = 0.002; static constexpr int32_t kHbmDimmingTimeUs = 5000000; static constexpr const char *kGlobalHbmModeFileNode = "/sys/class/backlight/panel%d-backlight/hbm_mode"; + static constexpr const char* kDimmingUsagePropName = + "vendor.display.%d.brightness.dimming.usage"; + static constexpr const char* kDimmingHbmTimePropName = + "vendor.display.%d.brightness.dimming.hbm_time"; int queryBrightness(float brightness, bool* ghbm = nullptr, uint32_t* level = nullptr, float *nits = nullptr); void initBrightnessTable(const DrmDevice& device, const DrmConnector& connector); void initBrightnessSysfs(); + void initCabcSysfs(); void initDimmingUsage(); int applyBrightnessViaSysfs(uint32_t level); + int applyCabcModeViaSysfs(uint8_t mode); int updateStates() REQUIRES(mBrightnessMutex); void dimmingThread(); void processDimmingOff(); void parseHbmModeEnums(const DrmProperty& property); + void printBrightnessStates(const char* path) REQUIRES(mBrightnessMutex); + bool mLhbmSupported = false; bool mGhbmSupported = false; + bool mDbmSupported = false; bool mBrightnessIntfSupported = false; BrightnessTable mBrightnessTable[toUnderlying(BrightnessRange::MAX)]; @@ -221,6 +295,7 @@ private: CtrlValue<bool> mLhbm GUARDED_BY(mBrightnessMutex); CtrlValue<bool> mSdrDim GUARDED_BY(mBrightnessMutex); CtrlValue<bool> mPrevSdrDim GUARDED_BY(mBrightnessMutex); + CtrlValue<bool> mDimBrightnessReq GUARDED_BY(mBrightnessMutex); // Indicating if the last LHBM on has changed the brightness level bool mLhbmBrightnessAdj = false; @@ -251,11 +326,30 @@ private: // sysfs path std::ofstream mBrightnessOfs; uint32_t mMaxBrightness = 0; // read from sysfs + std::ofstream mCabcModeOfs; + bool mCabcSupport = false; + uint32_t mDimBrightness = 0; // Note IRC or dimming is not in consideration for now. float mDisplayWhitePointNits = 0; + float mPrevDisplayWhitePointNits = 0; std::function<void(void)> mUpdateDcLhbm; + + // state for control CABC state + enum class CabcMode { + OFF = 0, + CABC_UI_MODE, + CABC_STILL_MODE, + CABC_MOVIE_MODE, + }; + + static constexpr const char* kLocalCabcModeFileNode = + "/sys/class/backlight/panel%d-backlight/cabc_mode"; + std::recursive_mutex mCabcModeMutex; + bool mOutdoorVisibility GUARDED_BY(mCabcModeMutex) = false; + bool isHdrLayerOn() { return mHdrLayerState.get() == HdrLayerState::kHdrLarge; } + CtrlValue<CabcMode> mCabcMode GUARDED_BY(mCabcModeMutex); }; #endif // _BRIGHTNESS_CONTROLLER_H_ diff --git a/libhwc2.1/libdevice/DisplayColorLoader.h b/libhwc2.1/libdevice/DisplayColorLoader.h new file mode 100644 index 0000000..02bbbf8 --- /dev/null +++ b/libhwc2.1/libdevice/DisplayColorLoader.h @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef DISPLAY_COLOR_LOADER_H +#define DISPLAY_COLOR_LOADER_H + +#include <dlfcn.h> +#include <log/log.h> +#include <string> +#include <vector> + +template <typename GsInterfaceType, const char *entry> +class DisplayColorLoader { + static_assert(entry != nullptr); + public: + DisplayColorLoader(const DisplayColorLoader &) = delete; + DisplayColorLoader& operator=(const DisplayColorLoader &) = delete; + + DisplayColorLoader(const std::string &libName) { + libHandle = dlopen(libName.c_str(), RTLD_LAZY); + + if (libHandle == nullptr) { + ALOGE("%s: failed to load library %s\n", __func__, libName.c_str()); + getDisplayColor = nullptr; + return; + } + + const displaycolor::DisplayColorIntfVer *(*getVersion)(); + getVersion = reinterpret_cast<decltype(getVersion)>(dlsym(libHandle, "GetInterfaceVersion")); + if (getVersion == nullptr) { + ALOGE("%s: prebuilt lib is not versioned", __func__); + return; + } + + auto intfVer = getVersion(); + + if (intfVer != nullptr && + displaycolor::kInterfaceVersion.Compatible(*intfVer)) { + getDisplayColor = reinterpret_cast<decltype(getDisplayColor)>(dlsym(libHandle, entry)); + + if (getDisplayColor == nullptr) { + ALOGE("%s: failed to get %s\n", __func__, entry); + } else if (!(displaycolor::kInterfaceVersion == *intfVer)) { + ALOGW("%s: different hwc/displaycolor patch level %u.%u.%u vs .%u", + __func__, + intfVer->major, + intfVer->minor, + displaycolor::kInterfaceVersion.patch, + intfVer->patch); + } + } else { + if (intfVer != nullptr) { + ALOGE("%s: prebuilt lib version %u.%u.%u expected %u.%u.%u", + __func__, + intfVer->major, + intfVer->minor, + intfVer->patch, + displaycolor::kInterfaceVersion.major, + displaycolor::kInterfaceVersion.minor, + displaycolor::kInterfaceVersion.patch); + } else { + ALOGE("%s: prebult lib getVersion returns null", __func__); + } + } + } + + GsInterfaceType *GetDisplayColor( + const std::vector<displaycolor::DisplayInfo> &display_info) { + if (getDisplayColor != nullptr) { + return getDisplayColor(display_info); + } + + return nullptr; + } + + ~DisplayColorLoader() { + if (libHandle != nullptr) { + dlclose(libHandle); + } + } + + private: + void *libHandle; + GsInterfaceType *(*getDisplayColor)(const std::vector<displaycolor::DisplayInfo> &); +}; + +#endif //DISPLAY_COLOR_LOADER_H diff --git a/libhwc2.1/libdevice/ExynosDevice.cpp b/libhwc2.1/libdevice/ExynosDevice.cpp index 99f9438..99fbc1a 100644 --- a/libhwc2.1/libdevice/ExynosDevice.cpp +++ b/libhwc2.1/libdevice/ExynosDevice.cpp @@ -14,6 +14,8 @@ * limitations under the License. */ +#define ATRACE_TAG (ATRACE_TAG_GRAPHICS | ATRACE_TAG_HAL) + #include "ExynosDevice.h" #include <aidl/android/hardware/graphics/composer3/IComposerCallback.h> @@ -43,8 +45,14 @@ using aidl::android::hardware::graphics::composer3::IComposerCallback; class ExynosDevice; -extern uint32_t mFenceLogSize; -extern void PixelDisplayInit(ExynosDevice *device); +extern void PixelDisplayInit(ExynosDisplay *exynos_display, const std::string_view instance_str); + +static const std::map<const uint32_t, const std::string_view> pixelDisplayIntfName = + {{getDisplayId(HWC_DISPLAY_PRIMARY, 0), "default"}, +#ifdef USES_IDISPLAY_INTF_SEC + {getDisplayId(HWC_DISPLAY_PRIMARY, 1), "secondary"} +#endif +}; int hwcDebug; int hwcFenceDebug[FENCE_IP_ALL]; @@ -87,9 +95,18 @@ ExynosDevice::ExynosDevice() exynosHWCControl.sysFenceLogging = false; exynosHWCControl.useDynamicRecomp = false; - mInterfaceType = getDeviceInterfaceType(); + hwcDebug = 0; + mInterfaceType = getDeviceInterfaceType(); ALOGD("HWC2 : %s : interface type(%d)", __func__, mInterfaceType); + + /* + * This order should not be changed + * new ExynosResourceManager -> + * create displays and add them to the list -> + * initDeviceInterface() -> + * ExynosResourceManager::updateRestrictions() + */ mResourceManager = new ExynosResourceManagerModule(this); for (size_t i = 0; i < AVAILABLE_DISPLAY_UNITS.size(); i++) { @@ -98,7 +115,9 @@ ExynosDevice::ExynosDevice() ALOGD("Create display[%zu] type: %d, index: %d", i, display_t.type, display_t.index); switch(display_t.type) { case HWC_DISPLAY_PRIMARY: - exynos_display = (ExynosDisplay *)(new ExynosPrimaryDisplayModule(display_t.index, this)); + exynos_display = + (ExynosDisplay *)(new ExynosPrimaryDisplayModule(display_t.index, this, + display_t.display_name)); if(display_t.index == 0) { exynos_display->mPlugState = true; ExynosMPP::mainDisplayWidth = exynos_display->mXres; @@ -112,10 +131,14 @@ ExynosDevice::ExynosDevice() } break; case HWC_DISPLAY_EXTERNAL: - exynos_display = (ExynosDisplay *)(new ExynosExternalDisplayModule(display_t.index, this)); + exynos_display = + (ExynosDisplay *)(new ExynosExternalDisplayModule(display_t.index, this, + display_t.display_name)); break; case HWC_DISPLAY_VIRTUAL: - exynos_display = (ExynosDisplay *)(new ExynosVirtualDisplayModule(display_t.index, this)); + exynos_display = + (ExynosDisplay *)(new ExynosVirtualDisplayModule(display_t.index, this, + display_t.display_name)); mNumVirtualDisplay = 0; break; default: @@ -123,8 +146,8 @@ ExynosDevice::ExynosDevice() break; } exynos_display->mDeconNodeName.appendFormat("%s", display_t.decon_node_name.c_str()); - exynos_display->mDisplayName.appendFormat("%s", display_t.display_name.c_str()); mDisplays.add(exynos_display); + mDisplayMap.insert(std::make_pair(exynos_display->mDisplayId, exynos_display)); #ifndef FORCE_DISABLE_DR if (exynos_display->mDREnable) @@ -136,7 +159,6 @@ ExynosDevice::ExynosDevice() dynamicRecompositionThreadCreate(); - hwcDebug = 0; for (uint32_t i = 0; i < FENCE_IP_ALL; i++) hwcFenceDebug[i] = 0; @@ -145,35 +167,44 @@ ExynosDevice::ExynosDevice() sprintf(fence_names[i], "_%2dh", i); } - String8 saveString; - saveString.appendFormat("ExynosDevice is initialized"); - uint32_t errFileSize = saveErrorLog(saveString); - ALOGI("Initial errlog size: %d bytes\n", errFileSize); + for (auto it : mDisplays) { + std::string displayName = std::string(it->mDisplayName.string()); + it->mErrLogFileWriter.setPrefixName(displayName + "_hwc_error_log"); + it->mDebugDumpFileWriter.setPrefixName(displayName + "_hwc_debug"); + it->mFenceFileWriter.setPrefixName(displayName + "_hwc_fence_state"); + String8 saveString; + saveString.appendFormat("ExynosDisplay %s is initialized", it->mDisplayName.string()); + saveErrorLog(saveString, it); + } - /* - * This order should not be changed - * new ExynosResourceManager -> - * create displays and add them to the list -> - * initDeviceInterface() -> - * ExynosResourceManager::updateRestrictions() - */ initDeviceInterface(mInterfaceType); + + // registerRestrictions(); mResourceManager->updateRestrictions(); + mResourceManager->initDisplays(mDisplays, mDisplayMap); + mResourceManager->initDisplaysTDMInfo(); if (mInterfaceType == INTERFACE_TYPE_DRM) { - /* disable vblank immediately after updates */ - setVBlankOffDelay(-1); + setVBlankOffDelay(1); } - PixelDisplayInit(this); - - ExynosDisplay *primary_display = getDisplay(getDisplayId(HWC_DISPLAY_PRIMARY, 0)); char value[PROPERTY_VALUE_MAX]; property_get("vendor.display.lbe.supported", value, "0"); - mLbeSupported = atoi(value) ? true : false; - if (mLbeSupported) { - primary_display->initLbe(); + const bool lbe_supported = atoi(value) ? true : false; + + for (size_t i = 0; i < mDisplays.size(); i++) { + if (mDisplays[i]->mType == HWC_DISPLAY_PRIMARY) { + auto iter = pixelDisplayIntfName.find(getDisplayId(HWC_DISPLAY_PRIMARY, i)); + if (iter != pixelDisplayIntfName.end()) { + PixelDisplayInit(mDisplays[i], iter->second); + if (lbe_supported) { + mDisplays[i]->initLbe(); + } + } + } } + + mDisplayOffAsync = property_get_bool("vendor.display.async_off.supported", false); } void ExynosDevice::initDeviceInterface(uint32_t interfaceType) @@ -195,6 +226,7 @@ void ExynosDevice::initDeviceInterface(uint32_t interfaceType) display->mDisplayInterface) != NO_ERROR) { ALOGD("Remove display[%d], Failed to initialize display interface", i); mDisplays.removeAt(i); + mDisplayMap.erase(display->mDisplayId); delete display; } else { i++; @@ -203,20 +235,20 @@ void ExynosDevice::initDeviceInterface(uint32_t interfaceType) } ExynosDevice::~ExynosDevice() { - - ExynosDisplay *primary_display = getDisplay(getDisplayId(HWC_DISPLAY_PRIMARY,0)); - mDRLoopStatus = false; mDRThread.join(); - - delete primary_display; + for(auto& display : mDisplays) { + delete display; + } + mDisplays.clear(); } bool ExynosDevice::isFirstValidate() { for (uint32_t i = 0; i < mDisplays.size(); i++) { if ((mDisplays[i]->mType != HWC_DISPLAY_VIRTUAL) && - (mDisplays[i]->mPowerModeState == (hwc2_power_mode_t)HWC_POWER_MODE_OFF)) + (!mDisplays[i]->mPowerModeState.has_value() || + (mDisplays[i]->mPowerModeState.value() == (hwc2_power_mode_t)HWC_POWER_MODE_OFF))) continue; if ((mDisplays[i]->mPlugState == true) && ((mDisplays[i]->mRenderingState != RENDERING_STATE_NONE) && @@ -233,7 +265,8 @@ bool ExynosDevice::isLastValidate(ExynosDisplay *display) if (mDisplays[i] == display) continue; if ((mDisplays[i]->mType != HWC_DISPLAY_VIRTUAL) && - (mDisplays[i]->mPowerModeState == (hwc2_power_mode_t)HWC_POWER_MODE_OFF)) + (!mDisplays[i]->mPowerModeState.has_value() || + (mDisplays[i]->mPowerModeState.value() == (hwc2_power_mode_t)HWC_POWER_MODE_OFF))) continue; if ((mDisplays[i]->mPlugState == true) && (mDisplays[i]->mRenderingState != RENDERING_STATE_VALIDATED) && @@ -243,6 +276,17 @@ bool ExynosDevice::isLastValidate(ExynosDisplay *display) return true; } +bool ExynosDevice::hasOtherDisplayOn(ExynosDisplay *display) { + for (uint32_t i = 0; i < mDisplays.size(); i++) { + if (mDisplays[i] == display) continue; + if ((mDisplays[i]->mType != HWC_DISPLAY_VIRTUAL) && + mDisplays[i]->mPowerModeState.has_value() && + (mDisplays[i]->mPowerModeState.value() != (hwc2_power_mode_t)HWC_POWER_MODE_OFF)) + return true; + } + return false; +} + bool ExynosDevice::isDynamicRecompositionThreadAlive() { android_atomic_acquire_load(&mDRThreadStatus); @@ -251,6 +295,7 @@ bool ExynosDevice::isDynamicRecompositionThreadAlive() void ExynosDevice::checkDynamicRecompositionThread() { + ATRACE_CALL(); // If thread was destroyed, create thread and run. (resume status) if (isDynamicRecompositionThreadAlive() == false) { for (uint32_t i = 0; i < mDisplays.size(); i++) { @@ -266,6 +311,7 @@ void ExynosDevice::checkDynamicRecompositionThread() return; } mDRLoopStatus = false; + mDRWakeUpCondition.notify_one(); mDRThread.join(); } } @@ -291,15 +337,20 @@ void *ExynosDevice::dynamicRecompositionThreadLoop(void *data) android_atomic_inc(&(dev->mDRThreadStatus)); while (dev->mDRLoopStatus) { - uint32_t result = 0; for (uint32_t i = 0; i < dev->mDisplays.size(); i++) event_cnt[i] = display[i]->mUpdateEventCnt; /* - * If there is no update for more than 100ms, favor the 3D composition mode. - * If all other conditions are met, mode will be switched to 3D composition. + * If there is no update for more than 5s, favor the client composition mode. + * If all other conditions are met, mode will be switched to client composition. */ - usleep(100000); + { + std::unique_lock<std::mutex> lock(dev->mDRWakeUpMutex); + dev->mDRWakeUpCondition.wait_for(lock, std::chrono::seconds(5)); + if (!dev->mDRLoopStatus) { + break; + } + } for (uint32_t i = 0; i < dev->mDisplays.size(); i++) { if (display[i]->mDREnable && display[i]->mPlugState == true && @@ -307,35 +358,16 @@ void *ExynosDevice::dynamicRecompositionThreadLoop(void *data) if (display[i]->checkDynamicReCompMode() == DEVICE_2_CLIENT) { display[i]->mUpdateEventCnt = 0; display[i]->setGeometryChanged(GEOMETRY_DISPLAY_DYNAMIC_RECOMPOSITION); - result = 1; + dev->onRefresh(display[i]->mDisplayId); } } } - if (result) dev->onRefresh(); } android_atomic_dec(&(dev->mDRThreadStatus)); return NULL; } -/** - * @param display - * @return ExynosDisplay - */ -ExynosDisplay* ExynosDevice::getDisplay(uint32_t display) { - if (mDisplays.isEmpty()) { - ALOGE("mDisplays.size(%zu), requested display(%d)", - mDisplays.size(), display); - return NULL; - } - - for (size_t i = 0;i < mDisplays.size(); i++) { - if (mDisplays[i]->mDisplayId == display) - return (ExynosDisplay*)mDisplays[i]; - } - - return NULL; -} /** * Device Functions for HWC 2.0 @@ -459,7 +491,7 @@ int32_t ExynosDevice::registerCallback ( } } } - + /* TODO(b/265244856): called by register callback vsync. it's only hwc2. */ if (descriptor == HWC2_CALLBACK_VSYNC) mResourceManager->doPreProcessing(); @@ -497,16 +529,29 @@ void ExynosDevice::onHotPlug(uint32_t displayId, bool status) { callbackFunc(callbackData, displayId, status ? HWC2_CONNECTION_CONNECTED : HWC2_CONNECTION_DISCONNECTED); } +void ExynosDevice::onRefreshDisplays() { + for (auto& display : mDisplays) { + onRefresh(display->mDisplayId); + } +} -void ExynosDevice::onRefresh() { +void ExynosDevice::onRefresh(uint32_t displayId) { Mutex::Autolock lock(mDeviceCallbackMutex); if (!isCallbackRegisteredLocked(HWC2_CALLBACK_REFRESH)) return; + if (!checkDisplayConnection(displayId)) return; + + ExynosDisplay *display = (ExynosDisplay *)getDisplay(displayId); + + if (!display->mPowerModeState.has_value() || + (display->mPowerModeState.value() == (hwc2_power_mode_t)HWC_POWER_MODE_OFF)) + return; + hwc2_callback_data_t callbackData = mCallbackInfos[HWC2_CALLBACK_REFRESH].callbackData; HWC2_PFN_REFRESH callbackFunc = reinterpret_cast<HWC2_PFN_REFRESH>(mCallbackInfos[HWC2_CALLBACK_REFRESH].funcPointer); - callbackFunc(callbackData, getDisplayId(HWC_DISPLAY_PRIMARY, 0)); + callbackFunc(callbackData, displayId); } void ExynosDevice::onVsync(uint32_t displayId, int64_t timestamp) { @@ -599,21 +644,20 @@ void ExynosDevice::getHWCFenceDebug() ALOGE("[HWCFenceDebug] IP_Number(%d) : Debug(%x)", i, hwcFenceDebug[i]); } -void ExynosDevice::setHWCControl(uint32_t display, uint32_t ctrl, int32_t val) -{ +void ExynosDevice::setHWCControl(uint32_t displayId, uint32_t ctrl, int32_t val) { ExynosDisplay *exynosDisplay = NULL; switch (ctrl) { case HWC_CTL_FORCE_GPU: ALOGI("%s::HWC_CTL_FORCE_GPU on/off=%d", __func__, val); exynosHWCControl.forceGpu = (unsigned int)val; setGeometryChanged(GEOMETRY_DEVICE_CONFIG_CHANGED); - onRefresh(); + onRefresh(displayId); break; case HWC_CTL_WINDOW_UPDATE: ALOGI("%s::HWC_CTL_WINDOW_UPDATE on/off=%d", __func__, val); exynosHWCControl.windowUpdate = (unsigned int)val; setGeometryChanged(GEOMETRY_DEVICE_CONFIG_CHANGED); - onRefresh(); + onRefresh(displayId); break; case HWC_CTL_FORCE_PANIC: ALOGI("%s::HWC_CTL_FORCE_PANIC on/off=%d", __func__, val); @@ -634,33 +678,33 @@ void ExynosDevice::setHWCControl(uint32_t display, uint32_t ctrl, int32_t val) ALOGI("%s::HWC_CTL_SKIP_RESOURCE_ASSIGN on/off=%d", __func__, val); exynosHWCControl.skipResourceAssign = (unsigned int)val; setGeometryChanged(GEOMETRY_DEVICE_CONFIG_CHANGED); - onRefresh(); + onRefreshDisplays(); break; case HWC_CTL_SKIP_VALIDATE: ALOGI("%s::HWC_CTL_SKIP_VALIDATE on/off=%d", __func__, val); exynosHWCControl.skipValidate = (unsigned int)val; setGeometryChanged(GEOMETRY_DEVICE_CONFIG_CHANGED); - onRefresh(); + onRefreshDisplays(); break; case HWC_CTL_DUMP_MID_BUF: ALOGI("%s::HWC_CTL_DUMP_MID_BUF on/off=%d", __func__, val); exynosHWCControl.dumpMidBuf = (unsigned int)val; setGeometryChanged(GEOMETRY_DEVICE_CONFIG_CHANGED); - onRefresh(); + onRefreshDisplays(); break; case HWC_CTL_CAPTURE_READBACK: - captureScreenWithReadback(HWC_DISPLAY_PRIMARY); + captureScreenWithReadback(displayId); break; case HWC_CTL_DISPLAY_MODE: ALOGI("%s::HWC_CTL_DISPLAY_MODE mode=%d", __func__, val); setDisplayMode((uint32_t)val); setGeometryChanged(GEOMETRY_DEVICE_CONFIG_CHANGED); - onRefresh(); + onRefreshDisplays(); break; // Support DDI scalser { case HWC_CTL_DDI_RESOLUTION_CHANGE: ALOGI("%s::HWC_CTL_DDI_RESOLUTION_CHANGE mode=%d", __func__, val); - exynosDisplay = (ExynosDisplay*)getDisplay(display); + exynosDisplay = (ExynosDisplay *)getDisplay(displayId); uint32_t width, height; /* TODO: Add branch here for each resolution/index */ @@ -681,7 +725,7 @@ void ExynosDevice::setHWCControl(uint32_t display, uint32_t ctrl, int32_t val) exynosDisplay->setDDIScalerEnable(width, height); } setGeometryChanged(GEOMETRY_DISPLAY_RESOLUTION_CHANGED); - onRefresh(); + onRefreshDisplays(); break; // } Support DDI scaler case HWC_CTL_ENABLE_COMPOSITION_CROP: @@ -690,7 +734,7 @@ void ExynosDevice::setHWCControl(uint32_t display, uint32_t ctrl, int32_t val) case HWC_CTL_USE_MAX_G2D_SRC: case HWC_CTL_ENABLE_HANDLE_LOW_FPS: case HWC_CTL_ENABLE_EARLY_START_MPP: - exynosDisplay = (ExynosDisplay*)getDisplay(display); + exynosDisplay = (ExynosDisplay *)getDisplay(displayId); if (exynosDisplay == NULL) { for (uint32_t i = 0; i < mDisplays.size(); i++) { mDisplays[i]->setHWCControl(ctrl, val); @@ -699,11 +743,11 @@ void ExynosDevice::setHWCControl(uint32_t display, uint32_t ctrl, int32_t val) exynosDisplay->setHWCControl(ctrl, val); } setGeometryChanged(GEOMETRY_DEVICE_CONFIG_CHANGED); - onRefresh(); + onRefreshDisplays(); break; case HWC_CTL_DYNAMIC_RECOMP: ALOGI("%s::HWC_CTL_DYNAMIC_RECOMP on/off = %d", __func__, val); - setDynamicRecomposition((unsigned int)val); + setDynamicRecomposition(displayId, (unsigned int)val); break; case HWC_CTL_ENABLE_FENCE_TRACER: ALOGI("%s::HWC_CTL_ENABLE_FENCE_TRACER on/off=%d", __func__, val); @@ -728,9 +772,14 @@ void ExynosDevice::setDisplayMode(uint32_t displayMode) exynosHWCControl.displayMode = displayMode; } -void ExynosDevice::setDynamicRecomposition(unsigned int on) -{ +void ExynosDevice::setDynamicRecomposition(uint32_t displayId, unsigned int on) { exynosHWCControl.useDynamicRecomp = on; + ExynosDisplay *display = getDisplay(displayId); + if (display) { + display->mDRDefault = on; + display->mDREnable = on; + onRefresh(displayId); + } } bool ExynosDevice::checkDisplayConnection(uint32_t displayId) @@ -761,13 +810,12 @@ bool ExynosDevice::checkNonInternalConnection() return false; } -void ExynosDevice::getCapabilities(uint32_t *outCount, int32_t* outCapabilities) -{ +void ExynosDevice::getCapabilitiesLegacy(uint32_t *outCount, int32_t *outCapabilities) { uint32_t capabilityNum = 0; #ifdef HWC_SUPPORT_COLOR_TRANSFORM capabilityNum++; #endif -#ifdef HWC_SKIP_VALIDATE +#ifndef HWC_NO_SUPPORT_SKIP_VALIDATE capabilityNum++; #endif if (outCapabilities == NULL) { @@ -778,18 +826,38 @@ void ExynosDevice::getCapabilities(uint32_t *outCount, int32_t* outCapabilities) ALOGE("%s:: invalid outCount(%d), should be(%d)", __func__, *outCount, capabilityNum); return; } -#if defined(HWC_SUPPORT_COLOR_TRANSFORM) || defined(HWC_SKIP_VALIDATE) +#if defined(HWC_SUPPORT_COLOR_TRANSFORM) || !defined(HWC_NO_SUPPORT_SKIP_VALIDATE) uint32_t index = 0; #endif #ifdef HWC_SUPPORT_COLOR_TRANSFORM outCapabilities[index++] = HWC2_CAPABILITY_SKIP_CLIENT_COLOR_TRANSFORM; #endif -#ifdef HWC_SKIP_VALIDATE +#ifndef HWC_NO_SUPPORT_SKIP_VALIDATE outCapabilities[index++] = HWC2_CAPABILITY_SKIP_VALIDATE; #endif return; } +void ExynosDevice::getCapabilities(uint32_t *outCount, int32_t *outCapabilities) { + uint32_t capabilityNum = 0; +#ifdef HWC_SUPPORT_COLOR_TRANSFORM + capabilityNum++; +#endif + if (outCapabilities == NULL) { + *outCount = capabilityNum; + return; + } + if (capabilityNum != *outCount) { + ALOGE("%s:: invalid outCount(%d), should be(%d)", __func__, *outCount, capabilityNum); + return; + } +#if defined(HWC_SUPPORT_COLOR_TRANSFORM) + uint32_t index = 0; + outCapabilities[index++] = HWC2_CAPABILITY_SKIP_CLIENT_COLOR_TRANSFORM; +#endif + return; +} + void ExynosDevice::clearGeometryChanged() { mGeometryChanged = 0; @@ -838,6 +906,7 @@ bool ExynosDevice::canSkipValidate() } bool ExynosDevice::validateFences(ExynosDisplay *display) { + std::scoped_lock lock(display->mDevice->mFenceMutex); if (!validateFencePerFrame(display)) { ALOGE("You should doubt fence leak!"); @@ -853,7 +922,6 @@ bool ExynosDevice::validateFences(ExynosDisplay *display) { if (exynosHWCControl.doFenceFileDump) { ALOGD("Fence file dump !"); - if (mFenceLogSize != 0) ALOGD("Fence file not empty!"); saveFenceTrace(display); exynosHWCControl.doFenceFileDump = false; } @@ -862,20 +930,24 @@ bool ExynosDevice::validateFences(ExynosDisplay *display) { } void ExynosDevice::compareVsyncPeriod() { + /* TODO(b/265244856): to clarify what purpose of the function */ ExynosDisplay *primary_display = getDisplay(getDisplayId(HWC_DISPLAY_PRIMARY, 0)); ExynosDisplay *external_display = getDisplay(getDisplayId(HWC_DISPLAY_EXTERNAL, 0)); mVsyncDisplayId = getDisplayId(HWC_DISPLAY_PRIMARY, 0); if ((external_display == nullptr) || - (external_display->mPowerModeState == HWC2_POWER_MODE_OFF)) { + (!external_display->mPowerModeState.has_value() || + (external_display->mPowerModeState.value() == HWC2_POWER_MODE_OFF))) { return; - } else if (primary_display->mPowerModeState == HWC2_POWER_MODE_OFF) { + } else if (!primary_display->mPowerModeState.has_value() || + (primary_display->mPowerModeState.value() == HWC2_POWER_MODE_OFF)) { mVsyncDisplayId = getDisplayId(HWC_DISPLAY_EXTERNAL, 0); return; - } else if (((primary_display->mPowerModeState == HWC2_POWER_MODE_DOZE) || - (primary_display->mPowerModeState == HWC2_POWER_MODE_DOZE_SUSPEND)) && - (external_display->mVsyncPeriod >= DOZE_VSYNC_PERIOD)) { /*30fps*/ + } else if (primary_display->mPowerModeState.has_value() && + ((primary_display->mPowerModeState.value() == HWC2_POWER_MODE_DOZE) || + (primary_display->mPowerModeState.value() == HWC2_POWER_MODE_DOZE_SUSPEND)) && + (external_display->mVsyncPeriod >= DOZE_VSYNC_PERIOD)) { /*30fps*/ mVsyncDisplayId = getDisplayId(HWC_DISPLAY_EXTERNAL, 0); return; } else if (primary_display->mVsyncPeriod <= external_display->mVsyncPeriod) { @@ -949,6 +1021,7 @@ void ExynosDevice::captureReadbackClass::saveToFile(const String8 &fileName) } else { ALOGE("Fail to mmap"); } + fclose(fp); } else { ALOGE("Fail to open %s", filePath); } @@ -962,11 +1035,10 @@ void ExynosDevice::signalReadbackDone() } } -void ExynosDevice::captureScreenWithReadback(uint32_t displayType) -{ - ExynosDisplay *display = getDisplay(displayType); +void ExynosDevice::captureScreenWithReadback(uint32_t displayId) { + ExynosDisplay *display = getDisplay(displayId); if (display == nullptr) { - ALOGE("There is no display(%d)", displayType); + ALOGE("There is no display(%d)", displayId); return; } @@ -993,7 +1065,7 @@ void ExynosDevice::captureScreenWithReadback(uint32_t displayType) } /* Update screen */ - onRefresh(); + onRefresh(displayId); /* Wait for handling readback */ uint32_t waitPeriod = display->mVsyncPeriod * 3; @@ -1036,20 +1108,22 @@ int32_t ExynosDevice::setDisplayDeviceMode(int32_t display_id, int32_t mode) { int32_t ret = HWC2_ERROR_NONE; - if (display_id == HWC_DISPLAY_PRIMARY) { - if (mode == static_cast<int32_t>(ext_hwc2_power_mode_t::PAUSE) || - mode == static_cast<int32_t>(ext_hwc2_power_mode_t::RESUME)) { - ret = mDisplays[display_id]->setPowerMode(mode); - if (mode == static_cast<int32_t>(ext_hwc2_power_mode_t::RESUME) && ret == HWC2_ERROR_NONE) { - onRefresh(); + for (size_t i = 0; i < mDisplays.size(); i++) { + if (mDisplays[i]->mType == HWC_DISPLAY_PRIMARY && mDisplays[i]->mDisplayId == display_id) { + if (mode == static_cast<int32_t>(ext_hwc2_power_mode_t::PAUSE) || + mode == static_cast<int32_t>(ext_hwc2_power_mode_t::RESUME)) { + ret = mDisplays[i]->setPowerMode(mode); + if (mode == static_cast<int32_t>(ext_hwc2_power_mode_t::RESUME) && + ret == HWC2_ERROR_NONE) { + onRefresh(display_id); + } + return ret; + } else { + return HWC2_ERROR_UNSUPPORTED; } - return ret; - } else { - return HWC2_ERROR_UNSUPPORTED; } - } else { - return HWC2_ERROR_UNSUPPORTED; } + return HWC2_ERROR_UNSUPPORTED; } int32_t ExynosDevice::setPanelGammaTableSource(int32_t display_id, int32_t type, int32_t source) { @@ -1087,63 +1161,6 @@ void ExynosDevice::setVBlankOffDelay(int vblankOffDelay) { writeIntToFile(kVblankOffDelayPath, vblankOffDelay); } -bool ExynosDevice::isLbeSupported() { - return mLbeSupported; -} - -bool ExynosDevice::isColorCalibratedByDevice() { - ExynosDisplay *display = getDisplay(getDisplayId(HWC_DISPLAY_PRIMARY, 0)); - return display->isColorCalibratedByDevice(); -} - -void ExynosDevice::setLbeState(LbeState state) { - if (mLbeSupported) { - ExynosDisplay *primary_display = getDisplay(getDisplayId(HWC_DISPLAY_PRIMARY, 0)); - primary_display->setLbeState(state); - } -} - -void ExynosDevice::setLbeAmbientLight(int value) { - if (mLbeSupported) { - ExynosDisplay *primary_display = getDisplay(getDisplayId(HWC_DISPLAY_PRIMARY, 0)); - primary_display->setLbeAmbientLight(value); - } -} - -LbeState ExynosDevice::getLbeState() { - if (mLbeSupported) { - ExynosDisplay *primary_display = getDisplay(getDisplayId(HWC_DISPLAY_PRIMARY, 0)); - return primary_display->getLbeState(); - } - return LbeState::OFF; -} - -bool ExynosDevice::isLhbmSupported() { - ExynosDisplay *display = getDisplay(getDisplayId(HWC_DISPLAY_PRIMARY, 0)); - return display->mBrightnessController->isLhbmSupported(); -} - -int32_t ExynosDevice::setLhbmState(bool enabled) { - if (isLhbmSupported()) { - ExynosDisplay *display = getDisplay(getDisplayId(HWC_DISPLAY_PRIMARY, 0)); - return display->setLhbmState(enabled); - } - return -1; -} - -bool ExynosDevice::getLhbmState() { - if (isLhbmSupported()) { - ExynosDisplay *display = getDisplay(getDisplayId(HWC_DISPLAY_PRIMARY, 0)); - return display->getLhbmState(); - } - return false; -} - -PanelCalibrationStatus ExynosDevice::getPanelCalibrationStatus() { - auto display = getDisplay(getDisplayId(HWC_DISPLAY_PRIMARY, 0)); - return display->getPanelCalibrationStatus(); -} - uint32_t ExynosDevice::getWindowPlaneNum() { /* @@ -1179,31 +1196,6 @@ uint64_t ExynosDevice::getSpecialPlaneAttr(uint32_t index) return mDeviceInterface->getSPPChAttr(index); } -int ExynosDevice::setMinIdleRefreshRate(const int fps) { - ExynosDisplay *display = getDisplay(getDisplayId(HWC_DISPLAY_PRIMARY, 0)); - if (display) { - return display->setMinIdleRefreshRate(fps); - } - return BAD_VALUE; -} - -int ExynosDevice::setRefreshRateThrottle(const int delayMs) { - if (delayMs < 0) { - ALOGE("%s fail: delayMs(%d) is less than 0", __func__, delayMs); - return BAD_VALUE; - } - - ExynosDisplay *display = getDisplay(getDisplayId(HWC_DISPLAY_PRIMARY, 0)); - if (display) { - return display - ->setRefreshRateThrottleNanos(std::chrono::duration_cast<std::chrono::nanoseconds>( - std::chrono::milliseconds(delayMs)) - .count(), - DispIdleTimerRequester::PIXEL_DISP); - } - return BAD_VALUE; -} - int32_t ExynosDevice::registerHwc3Callback(uint32_t descriptor, hwc2_callback_data_t callbackData, hwc2_function_pointer_t point) { Mutex::Autolock lock(mDeviceCallbackMutex); @@ -1227,3 +1219,19 @@ void ExynosDevice::onVsyncIdle(hwc2_display_t displayId) { hwc2_display_t hwcDisplay)>(callbackInfo.funcPointer); callbackFunc(callbackInfo.callbackData, displayId); } + +void ExynosDevice::onRefreshRateChangedDebug(hwc2_display_t displayId, uint32_t vsyncPeriod) { + Mutex::Autolock lock(mDeviceCallbackMutex); + const auto &refreshRateCallback = + mHwc3CallbackInfos.find(IComposerCallback::TRANSACTION_onRefreshRateChangedDebug); + + if (refreshRateCallback == mHwc3CallbackInfos.end()) return; + + const auto &callbackInfo = refreshRateCallback->second; + if (callbackInfo.funcPointer == nullptr || callbackInfo.callbackData == nullptr) return; + + auto callbackFunc = + reinterpret_cast<void (*)(hwc2_callback_data_t callbackData, hwc2_display_t hwcDisplay, + hwc2_vsync_period_t)>(callbackInfo.funcPointer); + callbackFunc(callbackInfo.callbackData, displayId, vsyncPeriod); +} diff --git a/libhwc2.1/libdevice/ExynosDevice.h b/libhwc2.1/libdevice/ExynosDevice.h index 1dd1145..35eb947 100644 --- a/libhwc2.1/libdevice/ExynosDevice.h +++ b/libhwc2.1/libdevice/ExynosDevice.h @@ -17,6 +17,7 @@ #ifndef _EXYNOSDEVICE_H #define _EXYNOSDEVICE_H +#include <aidl/android/hardware/graphics/composer3/OverlayProperties.h> #include <aidl/com/google/hardware/pixel/display/BnDisplay.h> #include <cutils/atomic.h> #include <displaycolor/displaycolor.h> @@ -35,6 +36,7 @@ #include <map> #include <thread> +#include "ExynosDeviceInterface.h" #include "ExynosHWC.h" #include "ExynosHWCHelper.h" #include "ExynosHWCModule.h" @@ -61,6 +63,7 @@ using HbmState = ::aidl::com::google::hardware::pixel::display::HbmState; using LbeState = ::aidl::com::google::hardware::pixel::display::LbeState; using PanelCalibrationStatus = ::aidl::com::google::hardware::pixel::display::PanelCalibrationStatus; +using OverlayProperties = aidl::android::hardware::graphics::composer3::OverlayProperties; using namespace android; struct exynos_callback_info_t { @@ -141,10 +144,8 @@ enum { GEOMETRY_ERROR_CASE = 1ULL << 63, }; -class ExynosDevice; class ExynosDisplay; class ExynosResourceManager; -class ExynosDeviceInterface; class ExynosDevice { public: @@ -153,6 +154,7 @@ class ExynosDevice { * Display list that managed by Device. */ android::Vector< ExynosDisplay* > mDisplays; + std::map<uint32_t, ExynosDisplay *> mDisplayMap; int mNumVirtualDisplay; @@ -174,6 +176,8 @@ class ExynosDevice { volatile int32_t mDRThreadStatus; std::atomic<bool> mDRLoopStatus; bool mPrimaryBlank; + std::mutex mDRWakeUpMutex; + std::condition_variable mDRWakeUpCondition; /** * Callback informations those are used by SurfaceFlinger. @@ -204,7 +208,8 @@ class ExynosDevice { uint32_t mDisplayMode; // Variable for fence tracer - std::map<int, HwcFenceInfo> mFenceInfos; + std::map<int, HwcFenceInfo> mFenceInfos GUARDED_BY(mFenceMutex); + std::mutex mFenceMutex; /** * This will be initialized with differnt class @@ -232,7 +237,7 @@ class ExynosDevice { /** * @param display */ - ExynosDisplay* getDisplay(uint32_t display); + ExynosDisplay* getDisplay(uint32_t display) { return mDisplayMap[display]; } /** * Device Functions for HWC 2.0 @@ -278,7 +283,9 @@ class ExynosDevice { int32_t descriptor, hwc2_callback_data_t callbackData, hwc2_function_pointer_t point); bool isCallbackAvailable(int32_t descriptor); void onHotPlug(uint32_t displayId, bool status); - void onRefresh(); + void onRefresh(uint32_t displayId); + void onRefreshDisplays(); + void onVsync(uint32_t displayId, int64_t timestamp); bool onVsync_2_4(uint32_t displayId, int64_t timestamp, uint32_t vsyncPeriod); void onVsyncPeriodTimingChanged(uint32_t displayId, @@ -292,10 +299,11 @@ class ExynosDevice { void setDisplayMode(uint32_t displayMode); bool checkDisplayConnection(uint32_t displayId); bool checkNonInternalConnection(); + void getCapabilitiesLegacy(uint32_t *outCount, int32_t *outCapabilities); void getCapabilities(uint32_t *outCount, int32_t* outCapabilities); void setGeometryChanged(uint64_t changedBit) { mGeometryChanged|= changedBit;}; void clearGeometryChanged(); - void setDynamicRecomposition(unsigned int on); + void setDynamicRecomposition(uint32_t displayId, unsigned int on); bool canSkipValidate(); bool validateFences(ExynosDisplay *display); void compareVsyncPeriod(); @@ -332,6 +340,13 @@ class ExynosDevice { int32_t registerHwc3Callback(uint32_t descriptor, hwc2_callback_data_t callbackData, hwc2_function_pointer_t point); void onVsyncIdle(hwc2_display_t displayId); + bool isDispOffAsyncSupported() { return mDisplayOffAsync; }; + bool hasOtherDisplayOn(ExynosDisplay *display); + virtual int32_t getOverlaySupport([[maybe_unused]] OverlayProperties* caps){ + return HWC2_ERROR_UNSUPPORTED; + } + + void onRefreshRateChangedDebug(hwc2_display_t displayId, uint32_t vsyncPeriod); protected: void initDeviceInterface(uint32_t interfaceType); @@ -345,29 +360,13 @@ class ExynosDevice { bool isCallbackRegisteredLocked(int32_t descriptor); public: - bool isLbeSupported(); - void setLbeState(LbeState state); - void setLbeAmbientLight(int value); - LbeState getLbeState(); - - bool isLhbmSupported(); - int32_t setLhbmState(bool enabled); - bool getLhbmState(); - int setMinIdleRefreshRate(const int fps); - int setRefreshRateThrottle(const int delayMs); - - bool isColorCalibratedByDevice(); - - PanelCalibrationStatus getPanelCalibrationStatus(); - - public: void enterToTUI() { mIsInTUI = true; }; void exitFromTUI() { mIsInTUI = false; }; bool isInTUI() { return mIsInTUI; }; private: - bool mLbeSupported; bool mIsInTUI; + bool mDisplayOffAsync; }; #endif //_EXYNOSDEVICE_H diff --git a/libhwc2.1/libdevice/ExynosDisplay.cpp b/libhwc2.1/libdevice/ExynosDisplay.cpp index 78f65f2..ffd9cd5 100644 --- a/libhwc2.1/libdevice/ExynosDisplay.cpp +++ b/libhwc2.1/libdevice/ExynosDisplay.cpp @@ -31,6 +31,7 @@ #include <sys/ioctl.h> #include <utils/CallStack.h> +#include <charconv> #include <future> #include <map> @@ -55,10 +56,13 @@ using ::aidl::google::hardware::power::extension::pixel::IPowerExt; extern struct exynos_hwc_control exynosHWCControl; extern struct update_time_info updateTimeInfo; +constexpr float kDynamicRecompFpsThreshold = 1.0 / 5.0; // 1 frame update per 5 second + constexpr float nsecsPerSec = std::chrono::nanoseconds(1s).count(); constexpr int64_t nsecsIdleHintTimeout = std::chrono::nanoseconds(100ms).count(); -ExynosDisplay::PowerHalHintWorker::PowerHalHintWorker() +ExynosDisplay::PowerHalHintWorker::PowerHalHintWorker(uint32_t displayId, + const String8 &displayTraceName) : Worker("DisplayHints", HAL_PRIORITY_URGENT_DISPLAY), mNeedUpdateRefreshRateHint(false), mLastRefreshRateHint(0), @@ -67,12 +71,23 @@ ExynosDisplay::PowerHalHintWorker::PowerHalHintWorker() mIdleHintDeadlineTime(0), mIdleHintSupportIsChecked(false), mIdleHintIsSupported(false), + mDisplayTraceName(displayTraceName), mPowerModeState(HWC2_POWER_MODE_OFF), mVsyncPeriod(16666666), + mConnectRetryCount(0), mDeathRecipient(AIBinder_DeathRecipient_new(BinderDiedCallback)), mPowerHalExtAidl(nullptr), mPowerHalAidl(nullptr), - mPowerHintSession(nullptr) {} + mPowerHintSession(nullptr) { + if (property_get_bool("vendor.display.powerhal_hint_per_display", false)) { + std::string displayIdStr = std::to_string(displayId); + mIdleHintStr = "DISPLAY_" + displayIdStr + "_IDLE"; + mRefreshRateHintPrefixStr = "DISPLAY_" + displayIdStr + "_"; + } else { + mIdleHintStr = "DISPLAY_IDLE"; + mRefreshRateHintPrefixStr = "REFRESH_"; + } +} ExynosDisplay::PowerHalHintWorker::~PowerHalHintWorker() { Exit(); @@ -99,7 +114,8 @@ int32_t ExynosDisplay::PowerHalHintWorker::connectPowerHal() { mPowerHalAidl = IPower::fromBinder(pwBinder); if (!mPowerHalAidl) { - ALOGE("failed to connect power HAL"); + ALOGE("failed to connect power HAL (retry %u)", mConnectRetryCount); + mConnectRetryCount++; return -EINVAL; } @@ -110,10 +126,12 @@ int32_t ExynosDisplay::PowerHalHintWorker::connectPowerHal() { if (!mPowerHalExtAidl) { mPowerHalAidl = nullptr; - ALOGE("failed to connect power HAL extension"); + ALOGE("failed to connect power HAL extension (retry %u)", mConnectRetryCount); + mConnectRetryCount++; return -EINVAL; } + mConnectRetryCount = 0; AIBinder_linkToDeath(pwExtBinder.get(), mDeathRecipient.get(), reinterpret_cast<void *>(this)); // ensure the hint session is recreated every time powerhal is recreated mPowerHintSession = nullptr; @@ -179,10 +197,15 @@ int32_t ExynosDisplay::PowerHalHintWorker::sendPowerHalExtHint(const std::string int32_t ExynosDisplay::PowerHalHintWorker::checkRefreshRateHintSupport(int refreshRate) { int32_t ret = NO_ERROR; + + if (!isPowerHalExist()) { + return -EOPNOTSUPP; + } const auto its = mRefreshRateHintSupportMap.find(refreshRate); if (its == mRefreshRateHintSupportMap.end()) { /* check new hint */ - std::string refreshRateHintStr = "REFRESH_" + std::to_string(refreshRate) + "FPS"; + std::string refreshRateHintStr = + mRefreshRateHintPrefixStr + std::to_string(refreshRate) + "FPS"; ret = checkPowerHalExtHintSupport(refreshRateHintStr); if (ret == NO_ERROR || ret == -EOPNOTSUPP) { mRefreshRateHintSupportMap[refreshRate] = (ret == NO_ERROR); @@ -200,7 +223,7 @@ int32_t ExynosDisplay::PowerHalHintWorker::checkRefreshRateHintSupport(int refre } int32_t ExynosDisplay::PowerHalHintWorker::sendRefreshRateHint(int refreshRate, bool enabled) { - std::string hintStr = "REFRESH_" + std::to_string(refreshRate) + "FPS"; + std::string hintStr = mRefreshRateHintPrefixStr + std::to_string(refreshRate) + "FPS"; int32_t ret = sendPowerHalExtHint(hintStr, enabled); if (ret == -ENOTCONN) { /* Reset the hints when binder failure occurs */ @@ -250,6 +273,11 @@ int32_t ExynosDisplay::PowerHalHintWorker::updateRefreshRateHintInternal( int32_t ExynosDisplay::PowerHalHintWorker::checkIdleHintSupport(void) { int32_t ret = NO_ERROR; + + if (!isPowerHalExist()) { + return -EOPNOTSUPP; + } + Lock(); if (mIdleHintSupportIsChecked) { ret = mIdleHintIsSupported ? NO_ERROR : -EOPNOTSUPP; @@ -258,7 +286,7 @@ int32_t ExynosDisplay::PowerHalHintWorker::checkIdleHintSupport(void) { } Unlock(); - ret = checkPowerHalExtHintSupport("DISPLAY_IDLE"); + ret = checkPowerHalExtHintSupport(mIdleHintStr); Lock(); if (ret == NO_ERROR) { mIdleHintIsSupported = true; @@ -281,6 +309,10 @@ int32_t ExynosDisplay::PowerHalHintWorker::checkPowerHintSessionSupport() { return *(sSharedDisplayData.hintSessionSupported); } + if (!isPowerHalExist()) { + return -EOPNOTSUPP; + } + if (connectPowerHal() != NO_ERROR) { ALOGW("Error connecting to the PowerHAL"); return -EINVAL; @@ -315,10 +347,10 @@ int32_t ExynosDisplay::PowerHalHintWorker::updateIdleHint(int64_t deadlineTime, bool enableIdleHint = (deadlineTime < systemTime(SYSTEM_TIME_MONOTONIC) && CC_LIKELY(deadlineTime > 0)); - ATRACE_INT("HWCIdleHintTimer:", enableIdleHint); + DISPLAY_ATRACE_INT("HWCIdleHintTimer", enableIdleHint); if (mIdleHintIsEnabled != enableIdleHint || forceUpdate) { - ret = sendPowerHalExtHint("DISPLAY_IDLE", enableIdleHint); + ret = sendPowerHalExtHint(mIdleHintStr, enableIdleHint); if (ret == NO_ERROR) { mIdleHintIsEnabled = enableIdleHint; } @@ -343,7 +375,6 @@ void ExynosDisplay::PowerHalHintWorker::forceUpdateHints(void) { int32_t ExynosDisplay::PowerHalHintWorker::sendActualWorkDuration() { Lock(); if (mPowerHintSession == nullptr) { - ALOGW("Cannot send actual work duration, power hint session not running"); Unlock(); return -EINVAL; } @@ -382,7 +413,6 @@ int32_t ExynosDisplay::PowerHalHintWorker::updateTargetWorkDuration() { } if (mPowerHintSession == nullptr) { - ALOGW("Cannot send target work duration, power hint session not running"); return -EINVAL; } @@ -433,13 +463,13 @@ void ExynosDisplay::PowerHalHintWorker::signalActualWorkDuration(nsecs_t actualD WorkDuration duration = {.durationNanos = reportedDurationNs, .timeStampNanos = systemTime()}; if (sTraceHintSessionData) { - ATRACE_INT64("Measured duration", actualDurationNanos); - ATRACE_INT64("Target error term", mTargetWorkDuration - actualDurationNanos); + DISPLAY_ATRACE_INT64("Measured duration", actualDurationNanos); + DISPLAY_ATRACE_INT64("Target error term", mTargetWorkDuration - actualDurationNanos); - ATRACE_INT64("Reported duration", reportedDurationNs); - ATRACE_INT64("Reported target", mLastTargetDurationReported); - ATRACE_INT64("Reported target error term", - mLastTargetDurationReported - reportedDurationNs); + DISPLAY_ATRACE_INT64("Reported duration", reportedDurationNs); + DISPLAY_ATRACE_INT64("Reported target", mLastTargetDurationReported); + DISPLAY_ATRACE_INT64("Reported target error term", + mLastTargetDurationReported - reportedDurationNs); } ALOGV("Sending actual work duration of: %" PRId64 " on reported target: %" PRId64 " with error: %" PRId64, @@ -463,12 +493,12 @@ void ExynosDisplay::PowerHalHintWorker::signalTargetWorkDuration(nsecs_t targetD Lock(); mTargetWorkDuration = targetDurationNanos - kTargetSafetyMargin.count(); - if (sTraceHintSessionData) ATRACE_INT64("Time target", mTargetWorkDuration); + if (sTraceHintSessionData) DISPLAY_ATRACE_INT64("Time target", mTargetWorkDuration); bool shouldSignal = false; if (!sNormalizeTarget) { shouldSignal = needUpdateTargetWorkDurationLocked(); if (shouldSignal && mActualWorkDuration.has_value() && sTraceHintSessionData) { - ATRACE_INT64("Target error term", *mActualWorkDuration - mTargetWorkDuration); + DISPLAY_ATRACE_INT64("Target error term", *mActualWorkDuration - mTargetWorkDuration); } } Unlock(); @@ -938,9 +968,10 @@ String8 ExynosCompositionInfo::getTypeStr() } } -ExynosDisplay::ExynosDisplay(uint32_t index, ExynosDevice *device) - : mDisplayId(HWC_DISPLAY_PRIMARY), - mType(HWC_NUM_DISPLAY_TYPES), +ExynosDisplay::ExynosDisplay(uint32_t type, uint32_t index, ExynosDevice *device, + const std::string &displayName) + : mDisplayId(getDisplayId(type, index)), + mType(type), mIndex(index), mDeconNodeName(""), mXres(1440), @@ -950,17 +981,19 @@ ExynosDisplay::ExynosDisplay(uint32_t index, ExynosDevice *device) mVsyncPeriod(16666666), mBtsVsyncPeriod(16666666), mDevice(device), - mDisplayName(""), + mDisplayName(displayName.c_str()), + mDisplayTraceName(String8::format("%s(%d)", displayName.c_str(), mDisplayId)), mPlugState(false), mHasSingleBuffer(false), mResourceManager(NULL), mClientCompositionInfo(COMPOSITION_CLIENT), mExynosCompositionInfo(COMPOSITION_EXYNOS), mGeometryChanged(0x0), + mBufferUpdates(0), mRenderingState(RENDERING_STATE_NONE), mHWCRenderingState(RENDERING_STATE_NONE), mDisplayBW(0), - mDynamicReCompMode(NO_MODE_SWITCH), + mDynamicReCompMode(CLIENT_2_DEVICE), mDREnable(false), mDRDefault(false), mLastFpsTime(0), @@ -990,7 +1023,12 @@ ExynosDisplay::ExynosDisplay(uint32_t index, ExynosDevice *device) mSkipFrame(false), mVsyncPeriodChangeConstraints{systemTime(SYSTEM_TIME_MONOTONIC), 0}, mVsyncAppliedTimeLine{false, 0, systemTime(SYSTEM_TIME_MONOTONIC)}, - mConfigRequestState(hwc_request_state_t::SET_CONFIG_STATE_NONE) { + mConfigRequestState(hwc_request_state_t::SET_CONFIG_STATE_DONE), + mPowerHalHint(mDisplayId, mDisplayTraceName), + mErrLogFileWriter(2, ERR_LOG_SIZE), + mDebugDumpFileWriter(10, 1, ".dump"), + mFenceFileWriter(2, FENCE_ERR_LOG_SIZE), + mOperationRateManager(nullptr) { mDisplayControl.enableCompositionCrop = true; mDisplayControl.enableExynosCompositionOptimization = true; mDisplayControl.enableClientCompositionOptimization = true; @@ -1002,7 +1040,8 @@ ExynosDisplay::ExynosDisplay(uint32_t index, ExynosDevice *device) mDisplayConfigs.clear(); - mPowerModeState = HWC2_POWER_MODE_OFF; + mPowerModeState = std::nullopt; + mVsyncState = HWC2_VSYNC_DISABLE; /* TODO : Exception handling here */ @@ -1079,7 +1118,7 @@ void ExynosDisplay::initDisplay() { mGeometryChanged = 0x0; mRenderingState = RENDERING_STATE_NONE; mDisplayBW = 0; - mDynamicReCompMode = NO_MODE_SWITCH; + mDynamicReCompMode = CLIENT_2_DEVICE; mCursorIndex = -1; mDpuData.reset(); @@ -1134,6 +1173,7 @@ int32_t ExynosDisplay::destroyLayer(hwc2_layer_t outLayer) { } mDisplayInterface->destroyLayer(layer); + layer->resetAssignedResource(); delete layer; @@ -1150,6 +1190,7 @@ int32_t ExynosDisplay::destroyLayer(hwc2_layer_t outLayer) { * @return void */ void ExynosDisplay::destroyLayers() { + Mutex::Autolock lock(mDRMutex); for (uint32_t index = 0; index < mLayers.size();) { ExynosLayer *layer = mLayers[index]; mLayers.removeAt(index); @@ -1182,6 +1223,7 @@ ExynosLayer *ExynosDisplay::checkLayer(hwc2_layer_t addr) { } void ExynosDisplay::checkIgnoreLayers() { + Mutex::Autolock lock(mDRMutex); for (auto it = mIgnoreLayers.begin(); it != mIgnoreLayers.end();) { ExynosLayer *layer = *it; if ((layer->mLayerFlag & EXYNOS_HWC_IGNORE_LAYER) == 0) { @@ -1266,7 +1308,7 @@ void ExynosDisplay::doPreProcessing() { /* Set any flag to mGeometryChanged */ setGeometryChanged(GEOMETRY_DEVICE_SCENARIO_CHANGED); } -#ifndef HWC_SKIP_VALIDATE +#ifdef HWC_NO_SUPPORT_SKIP_VALIDATE if (mDevice->checkNonInternalConnection()) { /* Set any flag to mGeometryChanged */ mDevice->mGeometryChanged = 0x10; @@ -1285,16 +1327,15 @@ int ExynosDisplay::checkLayerFps() { if (mDisplayControl.handleLowFpsLayers == false) return NO_ERROR; + Mutex::Autolock lock(mDRMutex); + for (size_t i=0; i < mLayers.size(); i++) { - if ((mLayers[i]->mOverlayPriority < ePriorityHigh) && - (mLayers[i]->getFps() < LOW_FPS_THRESHOLD)) { - mLowFpsLayerInfo.addLowFpsLayer(i); - } else { - if (mLowFpsLayerInfo.mHasLowFpsLayer == true) - break; - else - continue; - } + if ((mLayers[i]->mOverlayPriority < ePriorityHigh) && + (mLayers[i]->getFps() < LOW_FPS_THRESHOLD)) { + mLowFpsLayerInfo.addLowFpsLayer(i); + } else if (mLowFpsLayerInfo.mHasLowFpsLayer == true) { + break; + } } /* There is only one low fps layer, Overlay is better in this case */ if ((mLowFpsLayerInfo.mHasLowFpsLayer == true) && @@ -1304,91 +1345,92 @@ int ExynosDisplay::checkLayerFps() { return NO_ERROR; } +int ExynosDisplay::switchDynamicReCompMode(dynamic_recomp_mode mode) { + if (mDynamicReCompMode == mode) return NO_MODE_SWITCH; + + ATRACE_INT("Force client composition by DR", (mode == DEVICE_2_CLIENT)); + mDynamicReCompMode = mode; + setGeometryChanged(GEOMETRY_DISPLAY_DYNAMIC_RECOMPOSITION); + return mode; +} + /** * @return int */ int ExynosDisplay::checkDynamicReCompMode() { - unsigned int updateFps = 0; - unsigned int lcd_size = mXres * mYres; - uint64_t TimeStampDiff; - uint64_t w = 0, h = 0, incomingPixels = 0; - uint64_t maxFps = 0, layerFps = 0; - + ATRACE_CALL(); Mutex::Autolock lock(mDRMutex); if (!exynosHWCControl.useDynamicRecomp) { mLastModeSwitchTimeStamp = 0; - mDynamicReCompMode = NO_MODE_SWITCH; - return 0; + return switchDynamicReCompMode(CLIENT_2_DEVICE); } /* initialize the Timestamps */ if (!mLastModeSwitchTimeStamp) { mLastModeSwitchTimeStamp = mLastUpdateTimeStamp; - mDynamicReCompMode = NO_MODE_SWITCH; - return 0; + return switchDynamicReCompMode(CLIENT_2_DEVICE); } - /* If video layer is there, skip the mode switch */ + /* Avoid to use DEVICE_2_CLIENT if there's a layer with priority >= ePriorityHigh such as: + * front buffer, video layer, HDR, DRM layer, etc. + */ for (size_t i = 0; i < mLayers.size(); i++) { if ((mLayers[i]->mOverlayPriority >= ePriorityHigh) || mLayers[i]->mPreprocessedInfo.preProcessed) { - if (mDynamicReCompMode != DEVICE_2_CLIENT) { - return 0; - } else { - mDynamicReCompMode = CLIENT_2_DEVICE; + auto ret = switchDynamicReCompMode(CLIENT_2_DEVICE); + if (ret) { mUpdateCallCnt = 0; mLastModeSwitchTimeStamp = mLastUpdateTimeStamp; DISPLAY_LOGD(eDebugDynamicRecomp, "[DYNAMIC_RECOMP] GLES_2_HWC by video layer"); - setGeometryChanged(GEOMETRY_DISPLAY_DYNAMIC_RECOMPOSITION); - return CLIENT_2_DEVICE; } + return ret; } } + unsigned int incomingPixels = 0; for (size_t i = 0; i < mLayers.size(); i++) { - w = WIDTH(mLayers[i]->mPreprocessedInfo.displayFrame); - h = HEIGHT(mLayers[i]->mPreprocessedInfo.displayFrame); + auto w = WIDTH(mLayers[i]->mPreprocessedInfo.displayFrame); + auto h = HEIGHT(mLayers[i]->mPreprocessedInfo.displayFrame); incomingPixels += w * h; } /* Mode Switch is not required if total pixels are not more than the threshold */ - if (incomingPixels <= lcd_size) { - if (mDynamicReCompMode != DEVICE_2_CLIENT) { - return 0; - } else { - mDynamicReCompMode = CLIENT_2_DEVICE; + unsigned int lcdSize = mXres * mYres; + if (incomingPixels <= lcdSize) { + auto ret = switchDynamicReCompMode(CLIENT_2_DEVICE); + if (ret) { mUpdateCallCnt = 0; mLastModeSwitchTimeStamp = mLastUpdateTimeStamp; DISPLAY_LOGD(eDebugDynamicRecomp, "[DYNAMIC_RECOMP] GLES_2_HWC by BW check"); - setGeometryChanged(GEOMETRY_DISPLAY_DYNAMIC_RECOMPOSITION); - return CLIENT_2_DEVICE; } + return ret; } /* * There will be at least one composition call per one minute (because of time update) - * To minimize the analysis overhead, just analyze it once in a second + * To minimize the analysis overhead, just analyze it once in 5 second */ - TimeStampDiff = systemTime(SYSTEM_TIME_MONOTONIC) - mLastModeSwitchTimeStamp; + auto timeStampDiff = systemTime(SYSTEM_TIME_MONOTONIC) - mLastModeSwitchTimeStamp; /* - * previous CompModeSwitch was CLIENT_2_DEVICE: check fps every 250ms from mLastModeSwitchTimeStamp + * previous CompModeSwitch was CLIENT_2_DEVICE: check fps after 5s from mLastModeSwitchTimeStamp * previous CompModeSwitch was DEVICE_2_CLIENT: check immediately */ - if ((mDynamicReCompMode != DEVICE_2_CLIENT) && (TimeStampDiff < (VSYNC_INTERVAL * 15))) + if ((mDynamicReCompMode != DEVICE_2_CLIENT) && (timeStampDiff < kLayerFpsStableTimeNs)) return 0; mLastModeSwitchTimeStamp = mLastUpdateTimeStamp; + float updateFps = 0; if ((mUpdateEventCnt != 1) && (mDynamicReCompMode == DEVICE_2_CLIENT) && (mUpdateCallCnt == 1)) { DISPLAY_LOGD(eDebugDynamicRecomp, "[DYNAMIC_RECOMP] first frame after DEVICE_2_CLIENT"); - updateFps = HWC_FPS_TH; + updateFps = kDynamicRecompFpsThreshold + 1; } else { + float maxFps = 0; for (uint32_t i = 0; i < mLayers.size(); i++) { - layerFps = mLayers[i]->getFps(); - if (maxFps < layerFps) - maxFps = layerFps; + float layerFps = mLayers[i]->checkFps(/* increaseCount */ false); + if (maxFps < layerFps) maxFps = layerFps; } updateFps = maxFps; } @@ -1396,26 +1438,22 @@ int ExynosDisplay::checkDynamicReCompMode() { /* * FPS estimation. - * If FPS is lower than HWC_FPS_TH, try to switch the mode to GLES + * If FPS is lower than kDynamicRecompFpsThreshold, try to switch the mode to GLES */ - if (updateFps < HWC_FPS_TH) { - if (mDynamicReCompMode != DEVICE_2_CLIENT) { - mDynamicReCompMode = DEVICE_2_CLIENT; - DISPLAY_LOGD(eDebugDynamicRecomp, "[DYNAMIC_RECOMP] DEVICE_2_CLIENT by low FPS(%d)", updateFps); - setGeometryChanged(GEOMETRY_DISPLAY_DYNAMIC_RECOMPOSITION); - return DEVICE_2_CLIENT; - } else { - return 0; + if (updateFps < kDynamicRecompFpsThreshold) { + auto ret = switchDynamicReCompMode(DEVICE_2_CLIENT); + if (ret) { + DISPLAY_LOGD(eDebugDynamicRecomp, "[DYNAMIC_RECOMP] DEVICE_2_CLIENT by low FPS(%.2f)", + updateFps); } + return ret; } else { - if (mDynamicReCompMode == DEVICE_2_CLIENT) { - mDynamicReCompMode = CLIENT_2_DEVICE; - DISPLAY_LOGD(eDebugDynamicRecomp, "[DYNAMIC_RECOMP] CLIENT_2_HWC by high FPS(%d)", updateFps); - setGeometryChanged(GEOMETRY_DISPLAY_DYNAMIC_RECOMPOSITION); - return CLIENT_2_DEVICE; - } else { - return 0; + auto ret = switchDynamicReCompMode(CLIENT_2_DEVICE); + if (ret) { + DISPLAY_LOGD(eDebugDynamicRecomp, "[DYNAMIC_RECOMP] CLIENT_2_HWC by high FPS((%.2f)", + updateFps); } + return ret; } return 0; @@ -1440,11 +1478,16 @@ void ExynosDisplay::setGeometryChanged(uint64_t changedBit) { void ExynosDisplay::clearGeometryChanged() { mGeometryChanged = 0; + mBufferUpdates = 0; for (size_t i=0; i < mLayers.size(); i++) { mLayers[i]->clearGeometryChanged(); } } +bool ExynosDisplay::isFrameUpdate() { + return mGeometryChanged > 0 || mBufferUpdates > 0; +} + int ExynosDisplay::handleStaticLayers(ExynosCompositionInfo& compositionInfo) { if (compositionInfo.mType != COMPOSITION_CLIENT) @@ -1581,7 +1624,7 @@ bool ExynosDisplay::skipStaticLayerChanged(ExynosCompositionInfo& compositionInf } void ExynosDisplay::requestLhbm(bool on) { - mDevice->onRefresh(); + mDevice->onRefresh(mDisplayId); if (mBrightnessController) { mBrightnessController->processLocalHbm(on); } @@ -1666,11 +1709,14 @@ int ExynosDisplay::skipStaticLayers(ExynosCompositionInfo& compositionInfo) return NO_ERROR; } -bool ExynosDisplay::skipSignalIdleForVideoLayer(void) { - /* ignore the frame update in case we have video layer but ui layer is not updated */ +bool ExynosDisplay::skipSignalIdle(void) { for (size_t i = 0; i < mLayers.size(); i++) { - if (!mLayers[i]->isLayerFormatYuv() && - mLayers[i]->mLastLayerBuffer != mLayers[i]->mLayerBuffer) { + // Frame update for refresh rate overlay indicator layer can be ignored + if (mLayers[i]->mRequestedCompositionType == HWC2_COMPOSITION_REFRESH_RATE_INDICATOR) + continue; + // Frame update for video layer can be ignored + if (mLayers[i]->isLayerFormatYuv()) continue; + if (mLayers[i]->mLastLayerBuffer != mLayers[i]->mLayerBuffer) { return false; } } @@ -2378,31 +2424,15 @@ int ExynosDisplay::setWinConfigData() { return 0; } -void ExynosDisplay::printDebugInfos(String8 &reason) -{ - FILE *pFile = NULL; +void ExynosDisplay::printDebugInfos(String8 &reason) { struct timeval tv; gettimeofday(&tv, NULL); reason.appendFormat("errFrameNumber: %" PRId64 " time:%s\n", mErrorFrameCount, getLocalTimeStr(tv).string()); ALOGD("%s", reason.string()); - if (mErrorFrameCount < HWC_PRINT_FRAME_NUM) { - char filePath[128]; - sprintf(filePath, "%s/%s_hwc_debug%d.dump", ERROR_LOG_PATH0, mDisplayName.string(), (int)mErrorFrameCount); - pFile = fopen(filePath, "wb"); - if (pFile == NULL) { - ALOGE("Fail to open file %s, error: %s", filePath, strerror(errno)); - sprintf(filePath, "%s/%s_hwc_debug%d.dump", ERROR_LOG_PATH1, mDisplayName.string(), (int)mErrorFrameCount); - pFile = fopen(filePath, "wb"); - } - if (pFile == NULL) { - ALOGE("Fail to open file %s, error: %s", filePath, strerror(errno)); - } else { - ALOGI("%s was created", filePath); - fwrite(reason.string(), 1, reason.size(), pFile); - } - } + bool fileOpened = mDebugDumpFileWriter.chooseOpenedFile(); + mDebugDumpFileWriter.write(reason); mErrorFrameCount++; android::String8 result; @@ -2414,24 +2444,20 @@ void ExynosDisplay::printDebugInfos(String8 &reason) clientCompInfo.dump(result); exynosCompInfo.dump(result); ALOGD("%s", result.string()); - if (pFile != NULL) { - fwrite(result.string(), 1, result.size(), pFile); - } + mDebugDumpFileWriter.write(result); result.clear(); result.appendFormat("======================= dump exynos layers (%zu) ================================\n", mLayers.size()); ALOGD("%s", result.string()); - if (pFile != NULL) { - fwrite(result.string(), 1, result.size(), pFile); - } + mDebugDumpFileWriter.write(result); result.clear(); for (uint32_t i = 0; i < mLayers.size(); i++) { ExynosLayer *layer = mLayers[i]; layer->printLayer(); - if (pFile != NULL) { + if (fileOpened) { layer->dump(result); - fwrite(result.string(), 1, result.size(), pFile); + mDebugDumpFileWriter.write(result); result.clear(); } } @@ -2440,16 +2466,14 @@ void ExynosDisplay::printDebugInfos(String8 &reason) result.appendFormat("======================= dump ignore layers (%zu) ================================\n", mIgnoreLayers.size()); ALOGD("%s", result.string()); - if (pFile != NULL) { - fwrite(result.string(), 1, result.size(), pFile); - } + mDebugDumpFileWriter.write(result); result.clear(); for (uint32_t i = 0; i < mIgnoreLayers.size(); i++) { ExynosLayer *layer = mIgnoreLayers[i]; layer->printLayer(); - if (pFile != NULL) { + if (fileOpened) { layer->dump(result); - fwrite(result.string(), 1, result.size(), pFile); + mDebugDumpFileWriter.write(result); result.clear(); } } @@ -2457,23 +2481,19 @@ void ExynosDisplay::printDebugInfos(String8 &reason) result.appendFormat("============================= dump win configs ===================================\n"); ALOGD("%s", result.string()); - if (pFile != NULL) { - fwrite(result.string(), 1, result.size(), pFile); - } + mDebugDumpFileWriter.write(result); result.clear(); for (size_t i = 0; i < mDpuData.configs.size(); i++) { ALOGD("config[%zu]", i); printConfig(mDpuData.configs[i]); - if (pFile != NULL) { + if (fileOpened) { result.appendFormat("config[%zu]\n", i); dumpConfig(result, mDpuData.configs[i]); - fwrite(result.string(), 1, result.size(), pFile); + mDebugDumpFileWriter.write(result); result.clear(); } } - if (pFile != NULL) { - fclose(pFile); - } + mDebugDumpFileWriter.flush(); } int32_t ExynosDisplay::validateWinConfigData() @@ -3015,6 +3035,9 @@ int32_t ExynosDisplay::getLayerCompositionTypeForValidationType(uint32_t layerIn } else if ((mLayers[layerIndex]->mCompositionType == HWC2_COMPOSITION_SOLID_COLOR) && (mLayers[layerIndex]->mValidateCompositionType == HWC2_COMPOSITION_DEVICE)) { type = HWC2_COMPOSITION_SOLID_COLOR; + } else if ((mLayers[layerIndex]->mCompositionType == HWC2_COMPOSITION_REFRESH_RATE_INDICATOR) && + (mLayers[layerIndex]->mValidateCompositionType == HWC2_COMPOSITION_DEVICE)) { + type = HWC2_COMPOSITION_REFRESH_RATE_INDICATOR; } else { type = mLayers[layerIndex]->mValidateCompositionType; } @@ -3202,7 +3225,7 @@ int32_t ExynosDisplay::getDisplayRequests( for (int32_t i = mClientCompositionInfo.mFirstIndex; i < mClientCompositionInfo.mLastIndex; i++) { ExynosLayer *layer = mLayers[i]; - if (layer->mOverlayPriority >= ePriorityHigh) { + if (layer->needClearClientTarget()) { if ((outLayers != NULL) && (outLayerRequests != NULL)) { if (requestNum >= *outNumElements) return -1; @@ -3355,8 +3378,7 @@ bool ExynosDisplay::isFullScreenComposition() { dispRect.right = r.right; } - if ((dispRect.top != 0) || (dispRect.left != 0) || - (dispRect.right != mXres) || (dispRect.bottom != mYres)) { + if ((dispRect.right != mXres) || (dispRect.bottom != mYres)) { ALOGD("invalid displayFrame disp=[%d %d %d %d] expected=%dx%d", dispRect.left, dispRect.top, dispRect.right, dispRect.bottom, mXres, mYres); @@ -3367,9 +3389,10 @@ bool ExynosDisplay::isFullScreenComposition() { } int32_t ExynosDisplay::presentDisplay(int32_t* outRetireFence) { - ATRACE_CALL(); + DISPLAY_ATRACE_CALL(); gettimeofday(&updateTimeInfo.lastPresentTime, NULL); + const bool mixedComposition = isMixedComposition(); // store this once here for the whole frame so it's consistent mUsePowerHints = usePowerHintSession(); if (mUsePowerHints) { @@ -3452,7 +3475,7 @@ int32_t ExynosDisplay::presentDisplay(int32_t* outRetireFence) { ret = HWC2_ERROR_NOT_VALIDATED; } mRenderingState = RENDERING_STATE_PRESENTED; - mDevice->onRefresh(); + mDevice->onRefresh(mDisplayId); return ret; } @@ -3461,7 +3484,7 @@ int32_t ExynosDisplay::presentDisplay(int32_t* outRetireFence) { * presentDisplay() can be called before validateDisplay() * when HWC2_CAPABILITY_SKIP_VALIDATE is supported */ -#ifndef HWC_SKIP_VALIDATE +#ifdef HWC_NO_SUPPORT_SKIP_VALIDATE DISPLAY_LOGE("%s:: Skip validate is not supported. Invalid rendering state : %d", __func__, mRenderingState); goto err; #endif @@ -3592,10 +3615,14 @@ int32_t ExynosDisplay::presentDisplay(int32_t* outRetireFence) { goto err; } - if (mGeometryChanged != 0 || !skipSignalIdleForVideoLayer()) { + if (mGeometryChanged != 0 || !skipSignalIdle()) { mPowerHalHint.signalIdle(); } + if (isFrameUpdate()) { + updateRefreshRateIndicator(); + } + handleWindowUpdate(); setDisplayWinConfigData(); @@ -3694,6 +3721,8 @@ int32_t ExynosDisplay::presentDisplay(int32_t* outRetireFence) { mPowerHalHint.signalActualWorkDuration(duration + mValidationDuration.value_or(0)); } + mPriorFrameMixedComposition = mixedComposition; + return ret; err: printDebugInfos(errString); @@ -3969,9 +3998,16 @@ int32_t ExynosDisplay::getDisplayBrightnessSupport(bool* outSupport) int32_t ExynosDisplay::setDisplayBrightness(float brightness, bool waitPresent) { if (mBrightnessController) { - return mBrightnessController->processDisplayBrightness(brightness, mVsyncPeriod, - waitPresent); + int32_t ret; + + ret = mBrightnessController->processDisplayBrightness(brightness, mVsyncPeriod, + waitPresent); + if (ret == NO_ERROR && mOperationRateManager) { + mOperationRateManager->onBrightness(mBrightnessController->getBrightnessLevel()); + } + return ret; } + return HWC2_ERROR_UNSUPPORTED; } @@ -4041,17 +4077,23 @@ int32_t ExynosDisplay::setActiveConfigWithConstraints(hwc2_config_t config, hwc_vsync_period_change_constraints_t* vsyncPeriodChangeConstraints, hwc_vsync_period_change_timeline_t* outTimeline) { - ATRACE_CALL(); + DISPLAY_ATRACE_CALL(); Mutex::Autolock lock(mDisplayMutex); + const nsecs_t current = systemTime(SYSTEM_TIME_MONOTONIC); + const nsecs_t diffMs = ns2ms(vsyncPeriodChangeConstraints->desiredTimeNanos - current); + DISPLAY_LOGD(eDebugDisplayConfig, "config(%d->%d), seamless(%d), diff(%" PRId64 ")", + mActiveConfig, config, vsyncPeriodChangeConstraints->seamlessRequired, diffMs); - DISPLAY_LOGD(eDebugDisplayConfig, - "config(%d), seamless(%d), " - "desiredTime(%" PRId64 ")", - config, vsyncPeriodChangeConstraints->seamlessRequired, - vsyncPeriodChangeConstraints->desiredTimeNanos); + if (CC_UNLIKELY(ATRACE_ENABLED())) ATRACE_NAME(("diff:" + std::to_string(diffMs)).c_str()); if (isBadConfig(config)) return HWC2_ERROR_BAD_CONFIG; + if (!isConfigSettingEnabled()) { + mPendingConfig = config; + DISPLAY_LOGI("%s: config setting disabled, set pending config=%d", __func__, config); + return HWC2_ERROR_NONE; + } + if (mDisplayConfigs[mActiveConfig].groupId != mDisplayConfigs[config].groupId) { if (vsyncPeriodChangeConstraints->seamlessRequired) { DISPLAY_LOGD(eDebugDisplayConfig, "Case : Seamless is not allowed"); @@ -4059,9 +4101,7 @@ int32_t ExynosDisplay::setActiveConfigWithConstraints(hwc2_config_t config, } outTimeline->newVsyncAppliedTimeNanos = vsyncPeriodChangeConstraints->desiredTimeNanos; - - // when switching between display group setActiveConfig directly - return setActiveConfigInternal(config, false); + outTimeline->refreshRequired = true; } if (needNotChangeConfig(config)) { @@ -4070,7 +4110,15 @@ int32_t ExynosDisplay::setActiveConfigWithConstraints(hwc2_config_t config, return HWC2_ERROR_NONE; } - if (vsyncPeriodChangeConstraints->seamlessRequired) { + if ((mXres != mDisplayConfigs[config].width) || (mYres != mDisplayConfigs[config].height)) { + if ((mDisplayInterface->setActiveConfigWithConstraints(config, true)) != NO_ERROR) { + ALOGW("Mode change not possible"); + return HWC2_ERROR_BAD_CONFIG; + } + mRenderingState = RENDERING_STATE_NONE; + setGeometryChanged(GEOMETRY_DISPLAY_RESOLUTION_CHANGED); + updateInternalDisplayConfigVariables(config, false); + } else if (vsyncPeriodChangeConstraints->seamlessRequired) { if ((mDisplayInterface->setActiveConfigWithConstraints(config, true)) != NO_ERROR) { DISPLAY_LOGD(eDebugDisplayConfig, "Case : Seamless is not possible"); return HWC2_ERROR_SEAMLESS_NOT_POSSIBLE; @@ -4088,6 +4136,7 @@ int32_t ExynosDisplay::setActiveConfigWithConstraints(hwc2_config_t config, mConfigRequestState = hwc_request_state_t::SET_CONFIG_STATE_PENDING; mVsyncPeriodChangeConstraints = *vsyncPeriodChangeConstraints; mDesiredConfig = config; + DISPLAY_ATRACE_INT("Pending ActiveConfig", mDesiredConfig); calculateTimeline(config, vsyncPeriodChangeConstraints, outTimeline); @@ -4208,7 +4257,8 @@ uint32_t ExynosDisplay::getBtsRefreshRate() const { void ExynosDisplay::updateRefreshRateHint() { if (mVsyncPeriod) { - mPowerHalHint.signalRefreshRate(mPowerModeState, mVsyncPeriod); + mPowerHalHint.signalRefreshRate(mPowerModeState.value_or(HWC2_POWER_MODE_OFF), + mVsyncPeriod); } } @@ -4226,9 +4276,9 @@ int32_t ExynosDisplay::resetConfigRequestStateLocked(hwc2_config_t config) { DISPLAY_LOGI("%s: mConfigRequestState (%d) is not REQUESTED", __func__, mConfigRequestState); } else { - DISPLAY_LOGD(eDebugDisplayInterfaceConfig, "%s: Change mConfigRequestState (%d) to NONE", + DISPLAY_LOGD(eDebugDisplayInterfaceConfig, "%s: Change mConfigRequestState (%d) to DONE", __func__, mConfigRequestState); - mConfigRequestState = hwc_request_state_t::SET_CONFIG_STATE_NONE; + mConfigRequestState = hwc_request_state_t::SET_CONFIG_STATE_DONE; updateAppliedActiveConfig(mActiveConfig, systemTime(SYSTEM_TIME_MONOTONIC)); } return NO_ERROR; @@ -4299,6 +4349,7 @@ int32_t ExynosDisplay::doDisplayConfigInternal(hwc2_config_t config) { int32_t ExynosDisplay::doDisplayConfigPostProcess(ExynosDevice *dev) { + ATRACE_CALL(); uint64_t current = systemTime(SYSTEM_TIME_MONOTONIC); int64_t actualChangeTime = 0; @@ -4313,11 +4364,13 @@ int32_t ExynosDisplay::doDisplayConfigPostProcess(ExynosDevice *dev) if (actualChangeTime >= mVsyncPeriodChangeConstraints.desiredTimeNanos) { DISPLAY_LOGD(eDebugDisplayConfig, "Request setActiveConfig"); needSetActiveConfig = true; - ATRACE_INT("Pending ActiveConfig", 0); + DISPLAY_ATRACE_INT("Pending ActiveConfig", 0); + DISPLAY_ATRACE_INT64("TimeToChangeConfig", 0); } else { DISPLAY_LOGD(eDebugDisplayConfig, "setActiveConfig still pending (mDesiredConfig %d)", mDesiredConfig); - ATRACE_INT("Pending ActiveConfig", mDesiredConfig); + DISPLAY_ATRACE_INT("Pending ActiveConfig", mDesiredConfig); + DISPLAY_ATRACE_INT64("TimeToChangeConfig", ns2ms(actualChangeTime - current)); } if (needSetActiveConfig) { @@ -4352,7 +4405,7 @@ int ExynosDisplay::clearDisplay(bool needModeClear) { mLastRetireFence = fence_close(mLastRetireFence, this, FENCE_TYPE_RETIRE, FENCE_IP_DPP); if (mBrightnessController) { - mBrightnessController->onClearDisplay(); + mBrightnessController->onClearDisplay(needModeClear); } return ret; } @@ -4443,8 +4496,7 @@ int32_t ExynosDisplay::setVsyncEnabledInternal( int32_t ExynosDisplay::validateDisplay( uint32_t* outNumTypes, uint32_t* outNumRequests) { - - ATRACE_CALL(); + DISPLAY_ATRACE_CALL(); gettimeofday(&updateTimeInfo.lastValidateTime, NULL); Mutex::Autolock lock(mDisplayMutex); @@ -4585,6 +4637,7 @@ int32_t ExynosDisplay::validateDisplay( int32_t ExynosDisplay::startPostProcessing() { + ATRACE_CALL(); int ret = NO_ERROR; String8 errString; @@ -4881,8 +4934,10 @@ int32_t ExynosDisplay::addClientCompositionLayer(uint32_t layerIndex) /* handle sandwiched layers */ for (uint32_t i = (uint32_t)mClientCompositionInfo.mFirstIndex + 1; i < (uint32_t)mClientCompositionInfo.mLastIndex; i++) { ExynosLayer *layer = mLayers[i]; - if (layer->mOverlayPriority >= ePriorityHigh) { - DISPLAY_LOGD(eDebugResourceManager, "\t[%d] layer has high or max priority (%d)", i, layer->mOverlayPriority); + if (layer->needClearClientTarget()) { + DISPLAY_LOGD(eDebugResourceManager, + "\t[%d] layer is opaque and has high or max priority (%d)", i, + layer->mOverlayPriority); continue; } if (layer->mValidateCompositionType != HWC2_COMPOSITION_CLIENT) @@ -4989,9 +5044,7 @@ int32_t ExynosDisplay::removeClientCompositionLayer(uint32_t layerIndex) return ret; } - -int32_t ExynosDisplay::addExynosCompositionLayer(uint32_t layerIndex) -{ +int32_t ExynosDisplay::addExynosCompositionLayer(uint32_t layerIndex, float totalUsedCapa) { bool invalidFlag = false; int32_t changeFlag = NO_ERROR; int ret = 0; @@ -5070,7 +5123,7 @@ int32_t ExynosDisplay::addExynosCompositionLayer(uint32_t layerIndex) layer->setExynosMidImage(dst_img); bool isAssignable = false; if ((layer->mSupportedMPPFlag & m2mMPP->mLogicalType) != 0) - isAssignable = m2mMPP->isAssignable(this, src_img, dst_img); + isAssignable = m2mMPP->isAssignable(this, src_img, dst_img, totalUsedCapa); if (layer->mValidateCompositionType == HWC2_COMPOSITION_CLIENT) { @@ -5830,13 +5883,13 @@ void ExynosDisplay::traceLayerTypes() { break; } } - ATRACE_INT("HWComposer: DPU Layer", dpu_count); - ATRACE_INT("HWComposer: G2D Layer", g2d_count); - ATRACE_INT("HWComposer: GPU Layer", gpu_count); - ATRACE_INT("HWComposer: RCD Layer", rcd_count); - ATRACE_INT("HWComposer: DPU Cached Layer", skip_count); - ATRACE_INT("HWComposer: SF Cached Layer", mIgnoreLayers.size()); - ATRACE_INT("HWComposer: Total Layer", mLayers.size() + mIgnoreLayers.size()); + DISPLAY_ATRACE_INT("HWComposer: DPU Layer", dpu_count); + DISPLAY_ATRACE_INT("HWComposer: G2D Layer", g2d_count); + DISPLAY_ATRACE_INT("HWComposer: GPU Layer", gpu_count); + DISPLAY_ATRACE_INT("HWComposer: RCD Layer", rcd_count); + DISPLAY_ATRACE_INT("HWComposer: DPU Cached Layer", skip_count); + DISPLAY_ATRACE_INT("HWComposer: SF Cached Layer", mIgnoreLayers.size()); + DISPLAY_ATRACE_INT("HWComposer: Total Layer", mLayers.size() + mIgnoreLayers.size()); } void ExynosDisplay::updateBrightnessState() { @@ -5880,6 +5933,7 @@ void ExynosDisplay::updateBrightnessState() { if (mBrightnessController) { mBrightnessController->updateFrameStates(hdrState, sdrDim); mBrightnessController->processInstantHbm(instantHbm && !clientRgbHdr); + mBrightnessController->updateCabcMode(); } } @@ -5894,6 +5948,9 @@ void ExynosDisplay::cleanupAfterClientDeath() { int32_t ExynosDisplay::flushDisplayBrightnessChange() { if (mBrightnessController) { + if (mOperationRateManager) { + mOperationRateManager->onBrightness(mBrightnessController->getBrightnessLevel()); + } return mBrightnessController->applyPendingChangeViaSysfs(mVsyncPeriod); } return NO_ERROR; @@ -5916,7 +5973,6 @@ nsecs_t ExynosDisplay::getExpectedPresentTime(nsecs_t startTime) { return out; } } - ALOGE("Could not get hint session time target from primary display"); return getPredictedPresentTime(startTime); } @@ -6011,3 +6067,265 @@ int32_t ExynosDisplay::setDebugRCDLayerEnabled(bool enable) { int32_t ExynosDisplay::getDisplayIdleTimerSupport(bool &outSupport) { return mDisplayInterface->getDisplayIdleTimerSupport(outSupport); } + +int32_t ExynosDisplay::getDisplayMultiThreadedPresentSupport(bool &outSupport) { + outSupport = mDisplayControl.multiThreadedPresent; + return NO_ERROR; +} + +bool ExynosDisplay::isMixedComposition() { + for (size_t i = 0; i < mLayers.size(); i++) { + if (mLayers[i]->mBrightness < 1.0) { + return true; + } + } + return false; +} + +int ExynosDisplay::lookupDisplayConfigs(const int32_t &width, + const int32_t &height, + const int32_t &fps, + int32_t *outConfig) { + if (!fps) + return HWC2_ERROR_BAD_CONFIG; + + constexpr auto nsecsPerSec = std::chrono::nanoseconds(1s).count(); + constexpr auto nsecsPerMs = std::chrono::nanoseconds(1ms).count(); + + const auto vsyncPeriod = nsecsPerSec / fps; + + for (auto const& [config, mode] : mDisplayConfigs) { + long delta = abs(vsyncPeriod - mode.vsyncPeriod); + if ((width == mode.width) && (height == mode.height) && (delta < nsecsPerMs)) { + ALOGD("%s: found display config for mode: %dx%d@%d=%d", + __func__, width, height, fps, config); + *outConfig = config; + return HWC2_ERROR_NONE; + } + } + return HWC2_ERROR_BAD_CONFIG; +} + +FILE *ExynosDisplay::RotatingLogFileWriter::openLogFile(const std::string &filename, + const std::string &mode) { + FILE *file = nullptr; + auto fullpath = std::string(ERROR_LOG_PATH0) + "/" + filename; + file = fopen(fullpath.c_str(), mode.c_str()); + if (file != nullptr) { + return file; + } + ALOGE("Fail to open file %s, error: %s", fullpath.c_str(), strerror(errno)); + fullpath = std::string(ERROR_LOG_PATH1) + "/" + filename; + file = fopen(fullpath.c_str(), mode.c_str()); + if (file == nullptr) { + ALOGE("Fail to open file %s, error: %s", fullpath.c_str(), strerror(errno)); + } + return file; +} + +std::optional<nsecs_t> ExynosDisplay::RotatingLogFileWriter::getLastModifiedTimestamp( + const std::string &filename) { + struct stat fileStat; + auto fullpath = std::string(ERROR_LOG_PATH0) + "/" + filename; + if (stat(fullpath.c_str(), &fileStat) == 0) { + return fileStat.st_mtim.tv_sec * nsecsPerSec + fileStat.st_mtim.tv_nsec; + } + fullpath = std::string(ERROR_LOG_PATH1) + "/" + filename; + if (stat(fullpath.c_str(), &fileStat) == 0) { + return fileStat.st_mtim.tv_sec * nsecsPerSec + fileStat.st_mtim.tv_nsec; + } + return std::nullopt; +} + +bool ExynosDisplay::RotatingLogFileWriter::chooseOpenedFile() { + if (mLastFileIndex < 0) { + // HWC could be restarted, so choose to open new file or continue the last modified file + int chosenIndex = 0; + nsecs_t lastModifTimestamp = 0; + for (int i = 0; i < mMaxFileCount; ++i) { + auto timestamp = getLastModifiedTimestamp(mPrefixName + std::to_string(i) + mExtension); + if (!timestamp.has_value()) { + chosenIndex = i; + break; + } + if (i == 0 || lastModifTimestamp < *timestamp) { + chosenIndex = i; + lastModifTimestamp = *timestamp; + } + } + auto filename = mPrefixName + std::to_string(chosenIndex) + mExtension; + mFile = openLogFile(filename, "ab"); + if (mFile == nullptr) { + ALOGE("Unable to open log file for %s", filename.c_str()); + return false; + } + mLastFileIndex = chosenIndex; + } + + // Choose to use the same last file or move on to the next file + for (int i = 0; i < 2; ++i) { + if (mFile == nullptr) { + mFile = openLogFile(mPrefixName + std::to_string(mLastFileIndex) + mExtension, + (i == 0) ? "ab" : "wb"); + } + if (mFile != nullptr) { + auto fileSize = ftell(mFile); + if (fileSize < mThresholdSizePerFile) return true; + fclose(mFile); + mFile = nullptr; + } + mLastFileIndex = (mLastFileIndex + 1) % mMaxFileCount; + } + return false; +} + +ExynosDisplay::RefreshRateIndicatorHandler::RefreshRateIndicatorHandler(ExynosDisplay *display) + : mDisplay(display), mLastRefreshRate(0), mLastCallbackTime(0) {} + +int32_t ExynosDisplay::RefreshRateIndicatorHandler::init() { + auto path = String8::format(kRefreshRateStatePathFormat, mDisplay->mIndex); + mFd.Set(open(path.c_str(), O_RDONLY)); + if (mFd.get() < 0) { + ALOGE("Failed to open sysfs(%s) for refresh rate debug event: %s", path.c_str(), + strerror(errno)); + return -errno; + } + + return NO_ERROR; +} + +void ExynosDisplay::RefreshRateIndicatorHandler::updateRefreshRateLocked(int refreshRate) { + ATRACE_CALL(); + ATRACE_INT("Refresh rate indicator event", refreshRate); + auto lastUpdate = mDisplay->getLastLayerUpdateTime(); + // Ignore refresh rate increase that is caused by refresh rate indicator update but there's + // no update for the other layers + if (refreshRate > mLastRefreshRate && mLastRefreshRate > 0 && lastUpdate < mLastCallbackTime) { + mIgnoringLastUpdate = true; + return; + } + mIgnoringLastUpdate = false; + if (refreshRate == mLastRefreshRate) { + return; + } + mLastRefreshRate = refreshRate; + mLastCallbackTime = systemTime(CLOCK_MONOTONIC); + ATRACE_INT("Refresh rate indicator callback", mLastRefreshRate); + mDisplay->mDevice->onRefreshRateChangedDebug(mDisplay->mDisplayId, s2ns(1) / mLastRefreshRate); +} + +void ExynosDisplay::RefreshRateIndicatorHandler::handleSysfsEvent() { + ATRACE_CALL(); + std::scoped_lock lock(mMutex); + + char buffer[1024]; + lseek(mFd.get(), 0, SEEK_SET); + int ret = read(mFd.get(), &buffer, sizeof(buffer)); + if (ret < 0) { + ALOGE("%s: Failed to read refresh rate from fd %d: %s", __func__, mFd.get(), + strerror(errno)); + return; + } + std::string_view bufferView(buffer); + auto pos = bufferView.find('@'); + if (pos == std::string::npos) { + ALOGE("%s: Failed to parse refresh rate event (invalid format)", __func__); + return; + } + int refreshRate = 0; + std::from_chars(bufferView.data() + pos + 1, bufferView.data() + bufferView.size() - 1, + refreshRate); + updateRefreshRateLocked(refreshRate); +} + +void ExynosDisplay::RefreshRateIndicatorHandler::updateRefreshRate(int refreshRate) { + std::scoped_lock lock(mMutex); + updateRefreshRateLocked(refreshRate); +} + +int32_t ExynosDisplay::setRefreshRateChangedCallbackDebugEnabled(bool enabled) { + if ((!!mRefreshRateIndicatorHandler) == enabled) { + ALOGW("%s: RefreshRateChangedCallbackDebug is already %s", __func__, + enabled ? "enabled" : "disabled"); + return NO_ERROR; + } + int32_t ret = NO_ERROR; + if (enabled) { + mRefreshRateIndicatorHandler = std::make_shared<RefreshRateIndicatorHandler>(this); + if (!mRefreshRateIndicatorHandler) { + ALOGE("%s: Failed to create refresh rate debug handler", __func__); + return -ENOMEM; + } + ret = mRefreshRateIndicatorHandler->init(); + if (ret != NO_ERROR) { + ALOGE("%s: Failed to initialize refresh rate debug handler: %d", __func__, ret); + mRefreshRateIndicatorHandler.reset(); + return ret; + } + ret = mDevice->mDeviceInterface->registerSysfsEventHandler(mRefreshRateIndicatorHandler); + if (ret != NO_ERROR) { + ALOGE("%s: Failed to register sysfs event handler: %d", __func__, ret); + mRefreshRateIndicatorHandler.reset(); + return ret; + } + // Call the callback immediately + mRefreshRateIndicatorHandler->handleSysfsEvent(); + } else { + ret = mDevice->mDeviceInterface->unregisterSysfsEventHandler( + mRefreshRateIndicatorHandler->getFd()); + mRefreshRateIndicatorHandler.reset(); + } + return ret; +} + +nsecs_t ExynosDisplay::getLastLayerUpdateTime() { + Mutex::Autolock lock(mDRMutex); + nsecs_t time = 0; + for (size_t i = 0; i < mLayers.size(); ++i) { + // The update from refresh rate indicator layer should be ignored + if (mLayers[i]->mRequestedCompositionType == HWC2_COMPOSITION_REFRESH_RATE_INDICATOR) + continue; + time = max(time, mLayers[i]->mLastUpdateTime); + } + return time; +} + +void ExynosDisplay::updateRefreshRateIndicator() { + // Update refresh rate indicator if the last update event is ignored to make sure that + // the refresh rate caused by the current frame update will be applied immediately since + // we may not receive the sysfs event if the refresh rate is the same as the last ignored one. + if (!mRefreshRateIndicatorHandler || !mRefreshRateIndicatorHandler->isIgnoringLastUpdate()) + return; + mRefreshRateIndicatorHandler->handleSysfsEvent(); +} + +uint32_t ExynosDisplay::getPeakRefreshRate() { + float opRate = mOperationRateManager ? mOperationRateManager->getOperationRate() : 0; + return static_cast<uint32_t>(std::round(opRate ?: mPeakRefreshRate)); +} + +VsyncPeriodNanos ExynosDisplay::getVsyncPeriod(const int32_t config) { + const auto &it = mDisplayConfigs.find(config); + if (it == mDisplayConfigs.end()) return 0; + return mDisplayConfigs[config].vsyncPeriod; +} + +uint32_t ExynosDisplay::getRefreshRate(const int32_t config) { + VsyncPeriodNanos period = getVsyncPeriod(config); + if (!period) return 0; + constexpr float nsecsPerSec = std::chrono::nanoseconds(1s).count(); + return round(nsecsPerSec / period * 0.1f) * 10; +} + +uint32_t ExynosDisplay::getConfigId(const int32_t refreshRate, const int32_t width, + const int32_t height) { + for (auto entry : mDisplayConfigs) { + auto config = entry.first; + auto displayCfg = entry.second; + if (getRefreshRate(config) == refreshRate && displayCfg.width == width && + displayCfg.height == height) { + return config; + } + } + return UINT_MAX; +} diff --git a/libhwc2.1/libdevice/ExynosDisplay.h b/libhwc2.1/libdevice/ExynosDisplay.h index 6c7eded..8a12393 100644 --- a/libhwc2.1/libdevice/ExynosDisplay.h +++ b/libhwc2.1/libdevice/ExynosDisplay.h @@ -27,6 +27,7 @@ #include <chrono> #include <set> +#include "DeconHeader.h" #include "ExynosDisplayInterface.h" #include "ExynosHWC.h" #include "ExynosHWCDebug.h" @@ -34,6 +35,7 @@ #include "ExynosHwc3Types.h" #include "ExynosMPP.h" #include "ExynosResourceManager.h" +#include "drmeventlistener.h" #include "worker.h" #define HWC_CLEARDISPLAY_WITH_COLORMAP @@ -141,15 +143,21 @@ enum class PanelGammaSource { }; enum class hwc_request_state_t { - SET_CONFIG_STATE_NONE = 0, + SET_CONFIG_STATE_DONE = 0, SET_CONFIG_STATE_PENDING, SET_CONFIG_STATE_REQUESTED, }; +enum class VrrThrottleRequester : uint32_t { + PIXEL_DISP = 0, + TEST, + LHBM, + MAX, +}; + enum class DispIdleTimerRequester : uint32_t { SF = 0, - PIXEL_DISP, - TEST, + VRR_THROTTLE, MAX, }; @@ -279,6 +287,22 @@ class ExynosSortedLayer : public Vector <ExynosLayer*> static int compare(ExynosLayer * const *lhs, ExynosLayer *const *rhs); }; +class DisplayTDMInfo { + public: + /* Could be extended */ + typedef struct ResourceAmount { + uint32_t totalAmount; + } ResourceAmount_t; + std::map<tdm_attr_t, ResourceAmount_t> mAmount; + + uint32_t initTDMInfo(ResourceAmount_t amount, tdm_attr_t attr) { + mAmount[attr] = amount; + return 0; + } + + ResourceAmount_t getAvailableAmount(tdm_attr_t attr) { return mAmount[attr]; } +}; + class ExynosCompositionInfo : public ExynosMPPSource { public: ExynosCompositionInfo():ExynosCompositionInfo(COMPOSITION_NONE){}; @@ -361,13 +385,15 @@ struct DisplayControl { bool forceReserveMPP = false; /** Skip M2MMPP processing **/ bool skipM2mProcessing = true; + /** Enable multi-thread present **/ + bool multiThreadedPresent = false; }; class ExynosDisplay { public: - uint32_t mDisplayId; - uint32_t mType; - uint32_t mIndex; + const uint32_t mDisplayId; + const uint32_t mType; + const uint32_t mIndex; String8 mDeconNodeName; uint32_t mXres; uint32_t mYres; @@ -380,19 +406,21 @@ class ExynosDisplay { int mPsrMode; /* Constructor */ - ExynosDisplay(uint32_t index, ExynosDevice *device); + ExynosDisplay(uint32_t type, uint32_t index, ExynosDevice* device, + const std::string& displayName); /* Destructor */ virtual ~ExynosDisplay(); ExynosDevice *mDevice; - String8 mDisplayName; + const String8 mDisplayName; + const String8 mDisplayTraceName; HwcMountOrientation mMountOrientation = HwcMountOrientation::ROT_0; Mutex mDisplayMutex; /** State variables */ bool mPlugState; - hwc2_power_mode_t mPowerModeState; + std::optional<hwc2_power_mode_t> mPowerModeState; hwc2_vsync_t mVsyncState; bool mHasSingleBuffer; bool mPauseDisplay = false; @@ -422,10 +450,17 @@ class ExynosDisplay { * Geometry change info is described by bit map. * This flag is cleared when resource assignment for all displays * is done. + * Geometry changed to layer REFRESH_RATE_INDICATOR will be excluded. */ uint64_t mGeometryChanged; /** + * The number of buffer updates in the current frame. + * Buffer update for layer REFRESH_RATE_INDICATOR will be excluded. + */ + uint32_t mBufferUpdates; + + /** * Rendering step information that is seperated by * VALIDATED, ACCEPTED_CHANGE, PRESENTED. */ @@ -527,6 +562,8 @@ class ExynosDisplay { hwc2_config_t mDesiredConfig; hwc2_config_t mActiveConfig = UINT_MAX; + hwc2_config_t mPendingConfig = UINT_MAX; + int64_t mLastVsyncTimestamp = 0; void initDisplay(); @@ -537,7 +574,7 @@ class ExynosDisplay { int32_t initializeValidateInfos(); int32_t addClientCompositionLayer(uint32_t layerIndex); int32_t removeClientCompositionLayer(uint32_t layerIndex); - int32_t addExynosCompositionLayer(uint32_t layerIndex); + int32_t addExynosCompositionLayer(uint32_t layerIndex, float totalUsedCapa); /** * Dynamic AFBC Control solution : To get the prepared information is applied to current or not. @@ -558,6 +595,8 @@ class ExynosDisplay { int checkLayerFps(); + int switchDynamicReCompMode(dynamic_recomp_mode mode); + int checkDynamicReCompMode(); int handleDynamicReCompMode(); @@ -991,7 +1030,7 @@ class ExynosDisplay { */ int32_t getPreferredBootDisplayConfig(int32_t* outConfig); - virtual int32_t getPreferredDisplayConfigInternal(int32_t *outConfig); + virtual int32_t getPreferredDisplayConfigInternal(int32_t* outConfig); /* setAutoLowLatencyMode(displayToken, on) * Descriptor: HWC2_FUNCTION_SET_AUTO_LOW_LATENCY_MODE @@ -1161,6 +1200,7 @@ class ExynosDisplay { void setHWCControl(uint32_t ctrl, int32_t val); void setGeometryChanged(uint64_t changedBit); void clearGeometryChanged(); + bool isFrameUpdate(); virtual void setDDIScalerEnable(int width, int height); virtual int getDDIScalerMode(int width, int height); @@ -1180,12 +1220,14 @@ class ExynosDisplay { return PanelGammaSource::GAMMA_DEFAULT; } virtual void initLbe(){}; + virtual bool isLbeSupported() { return false; } virtual void setLbeState(LbeState __unused state) {} virtual void setLbeAmbientLight(int __unused value) {} virtual LbeState getLbeState() { return LbeState::OFF; } int32_t checkPowerHalExtHintSupport(const std::string& mode); + virtual bool isLhbmSupported() { return false; } virtual int32_t setLhbmState(bool __unused enabled) { return NO_ERROR; } virtual bool getLhbmState() { return false; }; virtual void setEarlyWakeupDisplay() {} @@ -1193,6 +1235,7 @@ class ExynosDisplay { virtual uint64_t getPendingExpectedPresentTime() { return 0; } virtual void applyExpectedPresentTime() {} virtual int32_t getDisplayIdleTimerSupport(bool& outSupport); + virtual int32_t getDisplayMultiThreadedPresentSupport(bool& outSupport); virtual int32_t setDisplayIdleTimer(const int32_t __unused timeoutMs) { return HWC2_ERROR_UNSUPPORTED; } @@ -1201,6 +1244,8 @@ class ExynosDisplay { virtual PanelCalibrationStatus getPanelCalibrationStatus() { return PanelCalibrationStatus::UNCALIBRATED; } + virtual bool isDbmSupported() { return false; } + virtual int32_t setDbmState(bool __unused enabled) { return NO_ERROR; } /* getDisplayPreAssignBit support mIndex up to 1. It supports only dual LCD and 2 external displays */ @@ -1232,27 +1277,37 @@ class ExynosDisplay { virtual int setMinIdleRefreshRate(const int __unused fps) { return NO_ERROR; } virtual int setRefreshRateThrottleNanos(const int64_t __unused delayNanos, - const DispIdleTimerRequester __unused requester) { + const VrrThrottleRequester __unused requester) { return NO_ERROR; } virtual void updateAppliedActiveConfig(const hwc2_config_t /*newConfig*/, const int64_t /*ts*/) {} + virtual bool isConfigSettingEnabled() { return true; } + virtual void enableConfigSetting(bool /*en*/) {} + // is the hint session both enabled and supported bool usePowerHintSession(); - void setMinDisplayVsyncPeriod(uint32_t period) { mMinDisplayVsyncPeriod = period; } + void setPeakRefreshRate(float rr) { mPeakRefreshRate = rr; } + uint32_t getPeakRefreshRate(); + VsyncPeriodNanos getVsyncPeriod(const int32_t config); + uint32_t getRefreshRate(const int32_t config); + uint32_t getConfigId(const int32_t refreshRate, const int32_t width, const int32_t height); - bool isCurrentPeakRefreshRate(void) { - return ((mConfigRequestState == hwc_request_state_t::SET_CONFIG_STATE_NONE) && - (mVsyncPeriod == mMinDisplayVsyncPeriod)); - } + // check if there are any dimmed layers + bool isMixedComposition(); + bool isPriorFrameMixedCompostion() { return mPriorFrameMixedComposition; } + int lookupDisplayConfigs(const int32_t& width, + const int32_t& height, + const int32_t& fps, + int32_t* outConfig); private: bool skipStaticLayerChanged(ExynosCompositionInfo& compositionInfo); - bool skipSignalIdleForVideoLayer(); + bool skipSignalIdle(); /// minimum possible dim rate in the case hbm peak is 1000 nits and norml // display brightness is 2 nits @@ -1263,13 +1318,17 @@ class ExynosDisplay { static constexpr float kHdrFullScreen = 0.5; uint32_t mHdrFullScrenAreaThreshold; - // vsync period of peak refresh rate - uint32_t mMinDisplayVsyncPeriod; + // peak refresh rate + float mPeakRefreshRate = -1.0f; + + // track if the last frame is a mixed composition, to detect mixed + // composition to non-mixed composition transition. + bool mPriorFrameMixedComposition; /* Display hint to notify power hal */ class PowerHalHintWorker : public Worker { public: - PowerHalHintWorker(); + PowerHalHintWorker(uint32_t displayId, const String8& displayTraceName); virtual ~PowerHalHintWorker(); int Init(); @@ -1342,9 +1401,16 @@ class ExynosDisplay { // whether idle hint is supported bool mIdleHintIsSupported; + String8 mDisplayTraceName; + std::string mIdleHintStr; + std::string mRefreshRateHintPrefixStr; + hwc2_power_mode_t mPowerModeState; uint32_t mVsyncPeriod; + uint32_t mConnectRetryCount; + bool isPowerHalExist() { return mConnectRetryCount < 10; } + ndk::ScopedAIBinder_DeathRecipient mDeathRecipient; // for power HAL extension hints @@ -1424,6 +1490,9 @@ class ExynosDisplay { static const constexpr nsecs_t SIGNAL_TIME_PENDING = INT64_MAX; static const constexpr nsecs_t SIGNAL_TIME_INVALID = -1; std::unordered_map<uint32_t, RollingAverage<kAveragesBufferSize>> mRollingAverages; + // mPowerHalHint should be declared only after mDisplayId and mDisplayTraceName have been + // declared since mDisplayId and mDisplayTraceName are needed as the parameter of + // PowerHalHintWorker's constructor PowerHalHintWorker mPowerHalHint; std::optional<nsecs_t> mValidateStartTime; @@ -1462,6 +1531,106 @@ class ExynosDisplay { hwc2_config_t config, hwc_vsync_period_change_constraints_t* vsyncPeriodChangeConstraints, hwc_vsync_period_change_timeline_t* outTimeline); + + public: + /* Override for each display's meaning of 'enabled state' + * Primary : Power on, this function overrided in primary display module + * Exteranal : Plug-in, default */ + virtual bool isEnabled() { return mPlugState; } + + // Resource TDM (Time-Division Multiplexing) + std::map<uint32_t, DisplayTDMInfo> mDisplayTDMInfo; + + class RotatingLogFileWriter { + public: + RotatingLogFileWriter(uint32_t maxFileCount, uint32_t thresholdSizePerFile, + std::string extension = ".txt") + : mMaxFileCount(maxFileCount), + mThresholdSizePerFile(thresholdSizePerFile), + mPrefixName(""), + mExtension(extension), + mLastFileIndex(-1), + mFile(nullptr) {} + + ~RotatingLogFileWriter() { + if (mFile) { + fclose(mFile); + } + } + + bool chooseOpenedFile(); + void write(const String8& content) { + if (mFile) { + fwrite(content.string(), 1, content.size(), mFile); + } + } + void flush() { + if (mFile) { + fflush(mFile); + } + } + void setPrefixName(const std::string& prefixName) { mPrefixName = prefixName; } + + private: + FILE* openLogFile(const std::string& filename, const std::string& mode); + std::optional<nsecs_t> getLastModifiedTimestamp(const std::string& filename); + + uint32_t mMaxFileCount; + uint32_t mThresholdSizePerFile; + std::string mPrefixName; + std::string mExtension; + int32_t mLastFileIndex; + FILE* mFile; + }; + RotatingLogFileWriter mErrLogFileWriter; + RotatingLogFileWriter mDebugDumpFileWriter; + RotatingLogFileWriter mFenceFileWriter; + + protected: + class OperationRateManager { + public: + OperationRateManager() {} + virtual ~OperationRateManager() {} + + virtual int32_t onLowPowerMode(bool __unused enabled) { return 0; } + virtual int32_t onPeakRefreshRate(uint32_t __unused rate) { return 0; } + virtual int32_t onConfig(hwc2_config_t __unused cfg) { return 0; } + virtual int32_t onBrightness(uint32_t __unused dbv) { return 0; } + virtual int32_t onPowerMode(int32_t __unused mode) { return 0; } + virtual int32_t getOperationRate() { return 0; } + }; + + public: + std::unique_ptr<OperationRateManager> mOperationRateManager; + bool isOperationRateSupported() { return mOperationRateManager != nullptr; } + + class RefreshRateIndicatorHandler : public DrmSysfsEventHandler { + public: + RefreshRateIndicatorHandler(ExynosDisplay* display); + int32_t init(); + virtual void handleSysfsEvent() override; + virtual int getFd() override { return mFd.get(); }; + bool isIgnoringLastUpdate() { return mIgnoringLastUpdate; } + void updateRefreshRate(int refreshRate); + + private: + void updateRefreshRateLocked(int refreshRate) REQUIRES(mMutex); + + ExynosDisplay* mDisplay; + int mLastRefreshRate GUARDED_BY(mMutex); + nsecs_t mLastCallbackTime GUARDED_BY(mMutex); + std::atomic_bool mIgnoringLastUpdate = false; + UniqueFd mFd; + std::mutex mMutex; + + static constexpr auto kRefreshRateStatePathFormat = + "/sys/class/backlight/panel%d-backlight/state"; + }; + + std::shared_ptr<RefreshRateIndicatorHandler> mRefreshRateIndicatorHandler; + int32_t setRefreshRateChangedCallbackDebugEnabled(bool enabled); + void updateRefreshRateIndicator(); + nsecs_t getLastLayerUpdateTime(); }; #endif //_EXYNOSDISPLAY_H diff --git a/libhwc2.1/libdevice/ExynosLayer.cpp b/libhwc2.1/libdevice/ExynosLayer.cpp index 105437e..8f1662d 100644 --- a/libhwc2.1/libdevice/ExynosLayer.cpp +++ b/libhwc2.1/libdevice/ExynosLayer.cpp @@ -39,6 +39,7 @@ ExynosLayer::ExynosLayer(ExynosDisplay* display) : ExynosMPPSource(MPP_SOURCE_LAYER, this), mDisplay(display), mCompositionType(HWC2_COMPOSITION_INVALID), + mRequestedCompositionType(HWC2_COMPOSITION_INVALID), mExynosCompositionType(HWC2_COMPOSITION_INVALID), mValidateCompositionType(HWC2_COMPOSITION_INVALID), mValidateExynosCompositionType(HWC2_COMPOSITION_INVALID), @@ -55,8 +56,11 @@ ExynosLayer::ExynosLayer(ExynosDisplay* display) mFrameCount(0), mLastFrameCount(0), mLastFpsTime(0), + mNextLastFrameCount(0), + mNextLastFpsTime(0), mLastLayerBuffer(NULL), mLayerBuffer(NULL), + mLastUpdateTime(0), mDamageNum(0), mBlending(HWC2_BLEND_MODE_NONE), mPlaneAlpha(1.0), @@ -101,27 +105,43 @@ ExynosLayer::~ExynosLayer() { } /** - * @return uint32_t + * @return float */ -uint32_t ExynosLayer::checkFps() { +float ExynosLayer::checkFps(bool increaseCount) { uint32_t frameDiff; - bool wasLowFps = (mFps < LOW_FPS_THRESHOLD) ? true:false; - if (mLastLayerBuffer != mLayerBuffer) { - mFrameCount++; - } + mFrameCount += increaseCount ? 1 : 0; + nsecs_t now = systemTime(); - nsecs_t diff = now - mLastFpsTime; + if (mLastFpsTime == 0) { // Initialize values + mLastFpsTime = now; + mNextLastFpsTime = now; + // TODO(b/268474771): set the initial FPS to the correct peak refresh rate + mFps = 120; + return mFps; + } + + nsecs_t diff = now - mNextLastFpsTime; + // Update mLastFrameCount for every 5s, to ensure that FPS calculation is only based on + // frames in the past at most 10s. + if (diff >= kLayerFpsStableTimeNs) { + mLastFrameCount = mNextLastFrameCount; + mNextLastFrameCount = mFrameCount; + + mLastFpsTime = mNextLastFpsTime; + mNextLastFpsTime = now; + } + + bool wasLowFps = (mFps < LOW_FPS_THRESHOLD) ? true : false; + if (mFrameCount >= mLastFrameCount) frameDiff = (mFrameCount - mLastFrameCount); else frameDiff = (mFrameCount + (UINT_MAX - mLastFrameCount)); - if (diff >= ms2ns(250)) { - mFps = (uint32_t)(frameDiff * float(s2ns(1))) / diff; - mLastFrameCount = mFrameCount; - mLastFpsTime = now; - } - bool nowLowFps = (mFps < LOW_FPS_THRESHOLD) ? true:false; + diff = now - mLastFpsTime; + mFps = (frameDiff * float(s2ns(1))) / diff; + + bool nowLowFps = (mFps < LOW_FPS_THRESHOLD) ? true : false; if ((mDisplay->mDisplayControl.handleLowFpsLayers) && (wasLowFps != nowLowFps)) @@ -133,7 +153,7 @@ uint32_t ExynosLayer::checkFps() { /** * @return float */ -uint32_t ExynosLayer::getFps() { +float ExynosLayer::getFps() { return mFps; } @@ -397,7 +417,16 @@ int32_t ExynosLayer::setLayerBuffer(buffer_handle_t buffer, int32_t acquireFence setGeometryChanged(GEOMETRY_LAYER_FRONT_BUFFER_USAGE_CHANGED); } - mLayerBuffer = buffer; + { + Mutex::Autolock lock(mDisplay->mDRMutex); + mLayerBuffer = buffer; + checkFps(mLastLayerBuffer != mLayerBuffer); + if (mLayerBuffer != mLastLayerBuffer) { + mLastUpdateTime = systemTime(CLOCK_MONOTONIC); + if (mRequestedCompositionType != HWC2_COMPOSITION_REFRESH_RATE_INDICATOR) + mDisplay->mBufferUpdates++; + } + } mPrevAcquireFence = fence_close(mPrevAcquireFence, mDisplay, FENCE_TYPE_SRC_ACQUIRE, FENCE_IP_UNDEFINED); mAcquireFence = fence_close(mAcquireFence, mDisplay, FENCE_TYPE_SRC_ACQUIRE, FENCE_IP_UNDEFINED); @@ -435,9 +464,6 @@ int32_t ExynosLayer::setLayerBuffer(buffer_handle_t buffer, int32_t acquireFence "internal_format: 0x%" PRIx64 "", mLayerBuffer, mDataSpace, mAcquireFence, mCompressed, internal_format); - /* Update fps */ - checkFps(); - return 0; } @@ -487,11 +513,12 @@ int32_t ExynosLayer::setLayerCompositionType(int32_t /*hwc2_composition_t*/ type type = HWC2_COMPOSITION_DEVICE; #endif - if (type != mCompositionType) { + if (type != mCompositionType && type != mRequestedCompositionType) { setGeometryChanged(GEOMETRY_LAYER_TYPE_CHANGED); } mCompositionType = type; + mRequestedCompositionType = type; return HWC2_ERROR_NONE; } @@ -529,6 +556,11 @@ int32_t ExynosLayer::setLayerDataspace(int32_t /*android_dataspace_t*/ dataspace if (currentDataSpace != mDataSpace) { setGeometryChanged(GEOMETRY_LAYER_DATASPACE_CHANGED); + // invalidate metadata if dataspace is changed. need metadata update + // to be after dataspace update. + if (mMetaParcel != nullptr) { + mMetaParcel->eType = VIDEO_INFO_TYPE_INVALID; + } } mDataSpace = currentDataSpace; @@ -548,9 +580,10 @@ int32_t ExynosLayer::setLayerDisplayFrame(hwc_rect_t frame) { } int32_t ExynosLayer::setLayerPlaneAlpha(float alpha) { - - if (alpha < 0.0) - return HWC2_ERROR_BAD_LAYER; + if (alpha < 0.0f || alpha > 1.0f) { + ALOGE("%s: invalid alpha %f", __func__, alpha); + return HWC2_ERROR_BAD_PARAMETER; + } if ((mPlaneAlpha != alpha) && ((mPlaneAlpha == 0.0) || (alpha == 0.0))) setGeometryChanged(GEOMETRY_LAYER_IGNORE_CHANGED); @@ -688,7 +721,8 @@ int32_t ExynosLayer::setLayerPerFrameMetadataBlobs(uint32_t numElements, const i mMetaParcel->eType = static_cast<ExynosVideoInfoType>(mMetaParcel->eType | VIDEO_INFO_TYPE_HDR_DYNAMIC); ExynosHdrDynamicInfo *info = &(mMetaParcel->sHdrDynamicInfo); - Exynos_parsing_user_data_registered_itu_t_t35(info, (void *)metadata_start); + Exynos_parsing_user_data_registered_itu_t_t35(info, (void*)metadata_start, + sizes[i]); } else { ALOGE("Layer has no metaParcel!"); return HWC2_ERROR_UNSUPPORTED; @@ -939,15 +973,16 @@ int32_t ExynosLayer::resetAssignedResource() return ret; } -bool ExynosLayer::checkDownscaleCap(uint32_t bts_refresh_rate) -{ +bool ExynosLayer::checkBtsCap(const uint32_t bts_refresh_rate) { if (mOtfMPP == nullptr) return true; exynos_image src_img; exynos_image dst_img; - setSrcExynosImage(&src_img); setDstExynosImage(&dst_img); + if (mOtfMPP->checkSpecificRestriction(bts_refresh_rate, src_img, dst_img)) { + return false; + } const bool isPerpendicular = !!(src_img.transform & HAL_TRANSFORM_ROT_90); const uint32_t srcWidth = isPerpendicular ? src_img.h : src_img.w; @@ -1088,7 +1123,8 @@ void ExynosLayer::printLayer() mLayerBuffer, fd, fd1, fd2, mAcquireFence, mTransform, mCompressed, mDataSpace, getFormatStr(format, mCompressed? AFBC : 0).string()); result.appendFormat("\tblend: 0x%4x, planeAlpha: %3.1f, zOrder: %d, color[0x%2x, 0x%2x, 0x%2x, 0x%2x]\n", mBlending, mPlaneAlpha, mZOrder, mColor.r, mColor.g, mColor.b, mColor.a); - result.appendFormat("\tfps: %2d, priority: %d, windowIndex: %d\n", mFps, mOverlayPriority, mWindowIndex); + result.appendFormat("\tfps: %.2f, priority: %d, windowIndex: %d\n", mFps, mOverlayPriority, + mWindowIndex); result.appendFormat("\tsourceCrop[%7.1f,%7.1f,%7.1f,%7.1f], dispFrame[%5d,%5d,%5d,%5d]\n", mSourceCrop.left, mSourceCrop.top, mSourceCrop.right, mSourceCrop.bottom, mDisplayFrame.left, mDisplayFrame.top, mDisplayFrame.right, mDisplayFrame.bottom); @@ -1130,8 +1166,10 @@ void ExynosLayer::printLayer() void ExynosLayer::setGeometryChanged(uint64_t changedBit) { + mLastUpdateTime = systemTime(CLOCK_MONOTONIC); mGeometryChanged |= changedBit; - mDisplay->setGeometryChanged(changedBit); + if (mRequestedCompositionType != HWC2_COMPOSITION_REFRESH_RATE_INDICATOR) + mDisplay->setGeometryChanged(changedBit); } int ExynosLayer::allocMetaParcel() diff --git a/libhwc2.1/libdevice/ExynosLayer.h b/libhwc2.1/libdevice/ExynosLayer.h index ead41af..e1df54d 100644 --- a/libhwc2.1/libdevice/ExynosLayer.h +++ b/libhwc2.1/libdevice/ExynosLayer.h @@ -41,6 +41,8 @@ using namespace android; using namespace vendor::graphics; using ::aidl::android::hardware::graphics::composer3::Composition; +constexpr nsecs_t kLayerFpsStableTimeNs = s2ns(5); + class ExynosMPP; enum overlay_priority { @@ -75,6 +77,7 @@ typedef struct pre_processed_layer_info enum { HWC2_COMPOSITION_DISPLAY_DECORATION = toUnderlying(Composition::DISPLAY_DECORATION), + HWC2_COMPOSITION_REFRESH_RATE_INDICATOR = toUnderlying(Composition::REFRESH_RATE_INDICATOR), /*add after hwc2_composition_t, margin number here*/ HWC2_COMPOSITION_EXYNOS = 32, }; @@ -89,10 +92,20 @@ class ExynosLayer : public ExynosMPPSource { /** * Layer's compositionType + * + * If acceptDisplayChanges() is called, it will be set to the validated type + * since SF may update their state and doesn't call back into HWC */ int32_t mCompositionType; /** + * Composition type that is originally requested by SF only using setLayerComposisionType() + * + * It will not be changed if applyDisplayChanges() is called. + */ + int32_t mRequestedCompositionType; + + /** * Composition type that is used by HAL * (ex: COMPOSITION_G2D) */ @@ -127,7 +140,7 @@ class ExynosLayer : public ExynosMPPSource { /** * Update rate for using client composition. */ - uint32_t mFps; + float mFps; /** * Assign priority, when priority changing is needded by order infomation in mGeometryChanged @@ -163,6 +176,8 @@ class ExynosLayer : public ExynosMPPSource { uint32_t mFrameCount; uint32_t mLastFrameCount; nsecs_t mLastFpsTime; + uint32_t mNextLastFrameCount; + nsecs_t mNextLastFpsTime; /** * Previous buffer's handle @@ -174,6 +189,8 @@ class ExynosLayer : public ExynosMPPSource { */ buffer_handle_t mLayerBuffer; + nsecs_t mLastUpdateTime; + /** * Surface Damage */ @@ -261,9 +278,9 @@ class ExynosLayer : public ExynosMPPSource { */ int32_t setCompositionType(int32_t type); - uint32_t checkFps(); + float checkFps(bool increaseCount); - uint32_t getFps(); + float getFps(); int32_t doPreProcess(); @@ -458,7 +475,7 @@ class ExynosLayer : public ExynosMPPSource { int32_t setSrcExynosImage(exynos_image *src_img); int32_t setDstExynosImage(exynos_image *dst_img); int32_t resetAssignedResource(); - bool checkDownscaleCap(uint32_t btsRefreshRate); + bool checkBtsCap(const uint32_t btsRefreshRate); void setSrcAcquireFence(); @@ -471,6 +488,18 @@ class ExynosLayer : public ExynosMPPSource { return ((mLayerBuffer != NULL) && isFormatYUV(VendorGraphicBufferMeta::get_internal_format(mLayerBuffer))); } + bool isLayerHasAlphaChannel() { + return ((mLayerBuffer != NULL) && + formatHasAlphaChannel( + VendorGraphicBufferMeta::get_internal_format(mLayerBuffer))); + } + bool isLayerOpaque() { + return (!isLayerHasAlphaChannel() && + std::fabs(mPlaneAlpha - 1.0f) <= std::numeric_limits<float>::epsilon()); + } + bool needClearClientTarget() { + return (mOverlayPriority >= ePriorityHigh && isLayerOpaque()); + } size_t getDisplayFrameArea() { return HEIGHT(mDisplayFrame) * WIDTH(mDisplayFrame); } void setGeometryChanged(uint64_t changedBit); void clearGeometryChanged() {mGeometryChanged = 0;}; diff --git a/libhwc2.1/libdisplayinterface/ExynosDeviceDrmInterface.cpp b/libhwc2.1/libdisplayinterface/ExynosDeviceDrmInterface.cpp index 1df6fe9..eab4cd1 100644 --- a/libhwc2.1/libdisplayinterface/ExynosDeviceDrmInterface.cpp +++ b/libhwc2.1/libdisplayinterface/ExynosDeviceDrmInterface.cpp @@ -236,12 +236,19 @@ void ExynosDeviceDrmInterface::ExynosDrmEventHandler::handleEvent(uint64_t times display->handleHotplugEvent(); } -void ExynosDeviceDrmInterface::ExynosDrmEventHandler::handleHistogramEvent(void *bin) { - ExynosDisplay *primaryDisplay = mExynosDevice->getDisplay(HWC_DISPLAY_PRIMARY); - if (primaryDisplay != NULL) { - ExynosDisplayDrmInterface *displayInterface = - static_cast<ExynosDisplayDrmInterface *>(primaryDisplay->mDisplayInterface.get()); - displayInterface->setHistogramData(bin); +void ExynosDeviceDrmInterface::ExynosDrmEventHandler::handleHistogramEvent(uint32_t crtc_id, + void *bin) { + ExynosDisplayDrmInterface *displayInterface; + DrmProperty crtc; + uint32_t id; + + for (auto display : mExynosDevice->mDisplays) { + displayInterface = + static_cast<ExynosDisplayDrmInterface *>(display->mDisplayInterface.get()); + id = displayInterface->getCrtcId(); + if (id == crtc_id) { + displayInterface->setHistogramData(bin); + } } } @@ -255,7 +262,7 @@ void ExynosDeviceDrmInterface::ExynosDrmEventHandler::handleTUIEvent() { } else { /* Received TUI Exit event */ if (mExynosDevice->isInTUI()) { - mExynosDevice->onRefresh(); + mExynosDevice->onRefreshDisplays(); mExynosDevice->exitFromTUI(); ALOGV("%s:: DRM device out TUI", __func__); } @@ -305,3 +312,12 @@ void ExynosDeviceDrmInterface::ExynosDrmEventHandler::handleIdleEnterEvent(char primaryDisplay->handleDisplayIdleEnter(idleTeVrefresh); } } + +int32_t ExynosDeviceDrmInterface::registerSysfsEventHandler( + std::shared_ptr<DrmSysfsEventHandler> handler) { + return mDrmDevice->event_listener()->RegisterSysfsHandler(std::move(handler)); +} + +int32_t ExynosDeviceDrmInterface::unregisterSysfsEventHandler(int sysfsFd) { + return mDrmDevice->event_listener()->UnRegisterSysfsHandler(sysfsFd); +} diff --git a/libhwc2.1/libdisplayinterface/ExynosDeviceDrmInterface.h b/libhwc2.1/libdisplayinterface/ExynosDeviceDrmInterface.h index 3e7fbbb..69fc4f0 100644 --- a/libhwc2.1/libdisplayinterface/ExynosDeviceDrmInterface.h +++ b/libhwc2.1/libdisplayinterface/ExynosDeviceDrmInterface.h @@ -31,6 +31,10 @@ class ExynosDeviceDrmInterface : public ExynosDeviceInterface { virtual int32_t initDisplayInterface( std::unique_ptr<ExynosDisplayInterface> &dispInterface) override; virtual void updateRestrictions() override; + virtual int32_t registerSysfsEventHandler( + std::shared_ptr<DrmSysfsEventHandler> handler) override; + virtual int32_t unregisterSysfsEventHandler(int sysfsFd) override; + protected: class ExynosDrmEventHandler : public DrmEventHandler, public DrmHistogramEventHandler, @@ -38,7 +42,7 @@ class ExynosDeviceDrmInterface : public ExynosDeviceInterface { public DrmPanelIdleEventHandler { public: void handleEvent(uint64_t timestamp_us) override; - void handleHistogramEvent(void *bin) override; + void handleHistogramEvent(uint32_t crtc_id, void *bin) override; void handleTUIEvent() override; void handleIdleEnterEvent(char const *event) override; void init(ExynosDevice *exynosDevice, DrmDevice *drmDevice); diff --git a/libhwc2.1/libdisplayinterface/ExynosDeviceInterface.cpp b/libhwc2.1/libdisplayinterface/ExynosDeviceInterface.cpp index eb54aca..fd200e3 100644 --- a/libhwc2.1/libdisplayinterface/ExynosDeviceInterface.cpp +++ b/libhwc2.1/libdisplayinterface/ExynosDeviceInterface.cpp @@ -27,9 +27,7 @@ #include "ExynosResourceManager.h" #include "ExynosResourceRestriction.h" -#ifndef USE_MODULE_ATTR -extern feature_support_t feature_table[]; -#endif +using namespace SOC_VERSION; void ExynosDeviceInterface::printDppRestriction(struct hwc_dpp_ch_restriction res) { diff --git a/libhwc2.1/libdisplayinterface/ExynosDeviceInterface.h b/libhwc2.1/libdisplayinterface/ExynosDeviceInterface.h index 747f016..dd976b0 100644 --- a/libhwc2.1/libdisplayinterface/ExynosDeviceInterface.h +++ b/libhwc2.1/libdisplayinterface/ExynosDeviceInterface.h @@ -17,8 +17,9 @@ #ifndef _EXYNOSDEVICEINTERFACE_H #define _EXYNOSDEVICEINTERFACE_H -#include "ExynosHWCHelper.h" #include "ExynosDisplayInterface.h" +#include "ExynosHWCHelper.h" +#include "drmeventlistener.h" struct hwc_dpp_size_range { uint32_t min; @@ -82,12 +83,21 @@ class ExynosDeviceInterface { virtual ~ExynosDeviceInterface(){}; virtual void init(ExynosDevice *exynosDevice) = 0; virtual int32_t initDisplayInterface( - std::unique_ptr<ExynosDisplayInterface> &dispInterface) - { return 0;}; + std::unique_ptr<ExynosDisplayInterface> __unused &dispInterface) { + return 0; + }; /* Fill mDPUInfo according to interface type */ virtual void updateRestrictions() = 0; virtual bool getUseQuery() { return mUseQuery; }; + virtual int32_t registerSysfsEventHandler( + std::shared_ptr<DrmSysfsEventHandler> __unused handler) { + return android::INVALID_OPERATION; + } + virtual int32_t unregisterSysfsEventHandler(int __unused sysfsFd) { + return android::INVALID_OPERATION; + } + uint32_t getNumDPPChs() { return mDPUInfo.dpuInfo.dpp_chs.size(); }; uint32_t getNumSPPChs() { return mDPUInfo.dpuInfo.spp_chs.size(); }; uint32_t getSPPChId(uint32_t index) { return mDPUInfo.dpuInfo.spp_chs.at(index).id; }; diff --git a/libhwc2.1/libdisplayinterface/ExynosDisplayDrmInterface.cpp b/libhwc2.1/libdisplayinterface/ExynosDisplayDrmInterface.cpp index 2e5e4e1..f8ca948 100644 --- a/libhwc2.1/libdisplayinterface/ExynosDisplayDrmInterface.cpp +++ b/libhwc2.1/libdisplayinterface/ExynosDisplayDrmInterface.cpp @@ -30,8 +30,11 @@ #include "BrightnessController.h" #include "ExynosHWCDebug.h" #include "ExynosHWCHelper.h" +#include "ExynosLayer.h" +#include "ExynosPrimaryDisplay.h" using namespace std::chrono_literals; +using namespace SOC_VERSION; constexpr uint32_t MAX_PLANE_NUM = 3; constexpr uint32_t CBCR_INDEX = 1; @@ -117,21 +120,26 @@ bool FramebufferManager::validateLayerInfo(uint32_t state, uint32_t drmFormat, return true; } -bool FramebufferManager::checkShrink() { +void FramebufferManager::checkShrink() { Mutex::Autolock lock(mMutex); mCacheShrinkPending = mCachedLayerBuffers.size() > MAX_CACHED_LAYERS; - return mCacheShrinkPending; + mCacheM2mSecureShrinkPending = + mCachedM2mSecureLayerBuffers.size() > MAX_CACHED_M2M_SECURE_LAYERS; } void FramebufferManager::cleanup(const ExynosLayer *layer) { ATRACE_CALL(); Mutex::Autolock lock(mMutex); - if (auto it = mCachedLayerBuffers.find(layer); it != mCachedLayerBuffers.end()) { - mCleanBuffers.splice(mCleanBuffers.end(), std::move(it->second)); - mCachedLayerBuffers.erase(it); - } + auto clean = [&](std::map<const ExynosLayer *, FBList> &layerBuffs) { + if (auto it = layerBuffs.find(layer); it != layerBuffs.end()) { + mCleanBuffers.splice(mCleanBuffers.end(), std::move(it->second)); + layerBuffs.erase(it); + } + }; + clean(mCachedLayerBuffers); + clean(mCachedM2mSecureLayerBuffers); } void FramebufferManager::removeFBsThreadRoutine() @@ -158,6 +166,7 @@ int32_t FramebufferManager::getBuffer(const exynos_win_config_data &config, uint uint32_t bpp = 0; uint32_t bufferNum, planeNum = 0; uint32_t bufWidth, bufHeight = 0; + bool isM2mSecureLayer = (config.protection && config.layer && config.layer->mM2mMPP); DrmArray<uint32_t> pitches = {0}; DrmArray<uint32_t> offsets = {0}; DrmArray<uint64_t> modifiers = {0}; @@ -197,7 +206,7 @@ int32_t FramebufferManager::getBuffer(const exynos_win_config_data &config, uint return -EINVAL; } - fbId = findCachedFbId(config.layer, + fbId = findCachedFbId(config.layer, isM2mSecureLayer, [bufferDesc = Framebuffer::BufferDesc{config.buffer_id, drmFormat, config.protection}]( auto &buffer) { return buffer->bufferDesc == bufferDesc; }); @@ -256,7 +265,7 @@ int32_t FramebufferManager::getBuffer(const exynos_win_config_data &config, uint handles[0] = 0xff000000; bpp = getBytePerPixelOfPrimaryPlane(HAL_PIXEL_FORMAT_BGRA_8888); pitches[0] = config.dst.w * bpp; - fbId = findCachedFbId(config.layer, + fbId = findCachedFbId(config.layer, isM2mSecureLayer, [colorDesc = Framebuffer::SolidColorDesc{bufWidth, bufHeight}]( auto &buffer) { return buffer->colorDesc == colorDesc; }); if (fbId != 0) { @@ -288,11 +297,14 @@ int32_t FramebufferManager::getBuffer(const exynos_win_config_data &config, uint if (config.layer || config.buffer_id) { Mutex::Autolock lock(mMutex); - auto &cachedBuffers = mCachedLayerBuffers[config.layer]; - if (cachedBuffers.size() > MAX_CACHED_BUFFERS_PER_LAYER) { - ALOGW("FBManager: cached buffers size %zu exceeds limitation while adding fbId %d", - cachedBuffers.size(), fbId); - printExynosLayer(config.layer); + auto &cachedBuffers = (!isM2mSecureLayer) ? mCachedLayerBuffers[config.layer] + : mCachedM2mSecureLayerBuffers[config.layer]; + auto maxCachedBufferSize = (!isM2mSecureLayer) ? MAX_CACHED_BUFFERS_PER_LAYER + : MAX_CACHED_M2M_SECURE_BUFFERS_PER_LAYER; + + if (cachedBuffers.size() > maxCachedBufferSize) { + ALOGW("FBManager: cached buffers size %zu exceeds limitation(%zu) while adding fbId %d", + cachedBuffers.size(), maxCachedBufferSize, fbId); mCleanBuffers.splice(mCleanBuffers.end(), cachedBuffers); } @@ -306,6 +318,7 @@ int32_t FramebufferManager::getBuffer(const exynos_win_config_data &config, uint Framebuffer::BufferDesc{config.buffer_id, drmFormat, config.protection})); mHasSecureFramebuffer |= (isFramebuffer(config.layer) && config.protection); + mHasM2mSecureLayerBuffer |= isM2mSecureLayer; } } else { ALOGW("FBManager: possible leakage fbId %d was created", fbId); @@ -314,7 +327,7 @@ int32_t FramebufferManager::getBuffer(const exynos_win_config_data &config, uint return 0; } -void FramebufferManager::flip(bool hasSecureFrameBuffer) { +void FramebufferManager::flip(const bool hasSecureFrameBuffer, const bool hasM2mSecureLayerBuffer) { bool needCleanup = false; { Mutex::Autolock lock(mMutex); @@ -322,6 +335,10 @@ void FramebufferManager::flip(bool hasSecureFrameBuffer) { if (!hasSecureFrameBuffer) { destroySecureFramebufferLocked(); } + + if (!hasM2mSecureLayerBuffer) { + destroyM2mSecureLayerBufferLocked(); + } needCleanup = mCleanBuffers.size() > 0; } @@ -334,6 +351,7 @@ void FramebufferManager::releaseAll() { Mutex::Autolock lock(mMutex); mCachedLayerBuffers.clear(); + mCachedM2mSecureLayerBuffers.clear(); mCleanBuffers.clear(); } @@ -351,31 +369,50 @@ void FramebufferManager::freeBufHandle(uint32_t handle) { } } -void FramebufferManager::markInuseLayerLocked(const ExynosLayer *layer) { - if (mCacheShrinkPending) { +void FramebufferManager::markInuseLayerLocked(const ExynosLayer *layer, + const bool isM2mSecureLayer) { + if (!isM2mSecureLayer && mCacheShrinkPending) { mCachedLayersInuse.insert(layer); } -} -void FramebufferManager::destroyUnusedLayersLocked() { - if (!mCacheShrinkPending || mCachedLayersInuse.size() == mCachedLayerBuffers.size()) { - mCachedLayersInuse.clear(); - return; + if (isM2mSecureLayer && mCacheM2mSecureShrinkPending) { + mCachedM2mSecureLayersInuse.insert(layer); } +} - ALOGW("FBManager: shrink cached layers from %zu to %zu", mCachedLayerBuffers.size(), - mCachedLayersInuse.size()); +void FramebufferManager::destroyUnusedLayersLocked() { + auto destroyUnusedLayers = + [&](const bool &cacheShrinkPending, std::set<const ExynosLayer *> &cachedLayersInuse, + std::map<const ExynosLayer *, FBList> &cachedLayerBuffers) -> bool { + if (!cacheShrinkPending || cachedLayersInuse.size() == cachedLayerBuffers.size()) { + cachedLayersInuse.clear(); + return false; + } - for (auto layer = mCachedLayerBuffers.begin(); layer != mCachedLayerBuffers.end();) { - if (mCachedLayersInuse.find(layer->first) == mCachedLayersInuse.end()) { - mCleanBuffers.splice(mCleanBuffers.end(), std::move(layer->second)); - layer = mCachedLayerBuffers.erase(layer); - } else { - ++layer; + for (auto layer = cachedLayerBuffers.begin(); layer != cachedLayerBuffers.end();) { + if (cachedLayersInuse.find(layer->first) == cachedLayersInuse.end()) { + mCleanBuffers.splice(mCleanBuffers.end(), std::move(layer->second)); + layer = cachedLayerBuffers.erase(layer); + } else { + ++layer; + } } + cachedLayersInuse.clear(); + return true; + }; + + auto cachedLayerSize = mCachedLayerBuffers.size(); + if (destroyUnusedLayers(mCacheShrinkPending, mCachedLayersInuse, mCachedLayerBuffers)) { + ALOGW("FBManager: shrink cached layers from %zu to %zu", cachedLayerSize, + mCachedLayerBuffers.size()); } - mCachedLayersInuse.clear(); + cachedLayerSize = mCachedM2mSecureLayerBuffers.size(); + if (destroyUnusedLayers(mCacheM2mSecureShrinkPending, mCachedM2mSecureLayersInuse, + mCachedM2mSecureLayerBuffers)) { + ALOGW("FBManager: shrink cached M2M secure layers from %zu to %zu", cachedLayerSize, + mCachedM2mSecureLayerBuffers.size()); + } } void FramebufferManager::destroySecureFramebufferLocked() { @@ -401,6 +438,22 @@ void FramebufferManager::destroySecureFramebufferLocked() { } } +void FramebufferManager::destroyM2mSecureLayerBufferLocked() { + if (!mHasM2mSecureLayerBuffer) { + return; + } + + mHasM2mSecureLayerBuffer = false; + + for (auto &layer : mCachedM2mSecureLayerBuffers) { + auto &bufferList = layer.second; + if (bufferList.size()) { + mCleanBuffers.splice(mCleanBuffers.end(), bufferList, bufferList.begin(), + bufferList.end()); + } + } +} + void ExynosDisplayDrmInterface::destroyLayer(ExynosLayer *layer) { mFBManager.cleanup(layer); } @@ -424,7 +477,8 @@ int32_t ExynosDisplayDrmInterface::getDefaultModeId(int32_t *modeId) { return NO_ERROR; } -ExynosDisplayDrmInterface::ExynosDisplayDrmInterface(ExynosDisplay *exynosDisplay) +ExynosDisplayDrmInterface::ExynosDisplayDrmInterface(ExynosDisplay *exynosDisplay): + mMonitorDescription{0} { mType = INTERFACE_TYPE_DRM; init(exynosDisplay); @@ -447,6 +501,7 @@ ExynosDisplayDrmInterface::~ExynosDisplayDrmInterface() void ExynosDisplayDrmInterface::init(ExynosDisplay *exynosDisplay) { mExynosDisplay = exynosDisplay; + mDisplayTraceName = mExynosDisplay->mDisplayTraceName; mDrmDevice = NULL; mDrmCrtc = NULL; mDrmConnector = NULL; @@ -592,6 +647,27 @@ void ExynosDisplayDrmInterface::updateMountOrientation() ALOGW("%s ignore unrecoganized orientation %" PRId64, __func__, drmOrientation); } +void ExynosDisplayDrmInterface::parseRCDId(const DrmProperty &property) { + if (mExynosDisplay->mType != HWC_DISPLAY_PRIMARY) { + ALOGW("%s invalid display type: %d", __func__, mExynosDisplay->mType); + return; + } + + if (property.id() == 0) { + static_cast<ExynosPrimaryDisplay *>(mExynosDisplay)->mRcdId = -1; + return; + } + + auto [err, rcd_id] = property.value(); + if (err < 0) { + ALOGW("%s failed to get drm prop value", __func__); + return; + } + + if (getSpecialChannelId(rcd_id) >= 0) + static_cast<ExynosPrimaryDisplay *>(mExynosDisplay)->mRcdId = rcd_id; +} + uint32_t ExynosDisplayDrmInterface::getDrmDisplayId(uint32_t type, uint32_t index) { return type+index; @@ -661,7 +737,7 @@ int32_t ExynosDisplayDrmInterface::initDrmDevice(DrmDevice *drmDevice) getLowPowerDrmModeModeInfo(); - mDrmVSyncWorker.Init(mDrmDevice, drmDisplayId); + mDrmVSyncWorker.Init(mDrmDevice, drmDisplayId, mDisplayTraceName); mDrmVSyncWorker.RegisterCallback(std::shared_ptr<VsyncCallback>(this)); if (!mDrmDevice->planes().empty()) { @@ -678,6 +754,8 @@ int32_t ExynosDisplayDrmInterface::initDrmDevice(DrmDevice *drmDevice) parseMipiSyncEnums(mDrmConnector->mipi_sync()); updateMountOrientation(); + if (mExynosDisplay->mType == HWC_DISPLAY_PRIMARY) parseRCDId(mDrmCrtc->rcd_plane_id_property()); + if (mExynosDisplay->mBrightnessController && mExynosDisplay->mBrightnessController->initDrm(*mDrmDevice, *mDrmConnector)) { ALOGW("%s failed to init brightness controller", __func__); @@ -715,13 +793,37 @@ void ExynosDisplayDrmInterface::Callback( if (!mExynosDisplay->mPlugState || !mVsyncCallback.getVSyncEnabled()) { return; } + + // Refresh rate during enabling LHBM might be different from the one SF expects. + // HWC just reports the SF expected Vsync to make UI smoothness consistent even if + // HWC runs at different refresh rate temporarily. + if (!mExynosDisplay->isConfigSettingEnabled()) { + int64_t pendingPeriodNs = + mExynosDisplay->getVsyncPeriod(mExynosDisplay->mPendingConfig); + int64_t activePeriodNs = mExynosDisplay->getVsyncPeriod(mExynosDisplay->mActiveConfig); + if (pendingPeriodNs && mExynosDisplay->mLastVsyncTimestamp) { + if (activePeriodNs > pendingPeriodNs) { + DISPLAY_DRM_LOGW("wrong vsync period: %" PRId64 "us (active), %" PRId64 + "us (pending)", + activePeriodNs / 1000, pendingPeriodNs / 1000); + } else if (activePeriodNs != pendingPeriodNs) { + int64_t deltaNs = timestamp - mExynosDisplay->mLastVsyncTimestamp; + if (deltaNs < (pendingPeriodNs - ms2ns(2))) { + DISPLAY_DRM_LOGI("skip mismatching Vsync callback, delta=%" PRId64 "us", + deltaNs / 1000); + return; + } + } + } + } + mExynosDisplay->mLastVsyncTimestamp = timestamp; } ExynosDevice *exynosDevice = mExynosDisplay->mDevice; if (exynosDevice->onVsync_2_4(mExynosDisplay->mDisplayId, timestamp, mExynosDisplay->mVsyncPeriod)) { - ATRACE_INT(vsyncPeriodTag, static_cast<int32_t>(mExynosDisplay->mVsyncPeriod)); + DISPLAY_ATRACE_INT(vsyncPeriodTag, static_cast<int32_t>(mExynosDisplay->mVsyncPeriod)); return; } @@ -819,7 +921,7 @@ int32_t ExynosDisplayDrmInterface::setVsyncEnabled(uint32_t enabled) ExynosDevice *exynosDevice = mExynosDisplay->mDevice; if (exynosDevice->isCallbackAvailable(HWC2_CALLBACK_VSYNC_2_4)) { - ATRACE_INT(vsyncPeriodTag, 0); + DISPLAY_ATRACE_INT(vsyncPeriodTag, 0); } return NO_ERROR; @@ -832,23 +934,41 @@ int32_t ExynosDisplayDrmInterface::chosePreferredConfig() if (err != HWC2_ERROR_NONE || !num_configs) return err; - hwc2_config_t config; - int32_t bootConfig; - err = mExynosDisplay->getPreferredDisplayConfigInternal(&bootConfig); - if (err == HWC2_ERROR_NONE) { - config = static_cast<hwc2_config_t>(bootConfig); + int32_t config = -1; + char modeStr[PROPERTY_VALUE_MAX] = "\0"; + int32_t width = 0, height = 0, fps = 0; + if (property_get("vendor.display.preferred_mode", modeStr, "") > 0 && + sscanf(modeStr, "%dx%d@%d", &width, &height, &fps) == 3) { + err = mExynosDisplay->lookupDisplayConfigs(width, height, fps, &config); } else { - config = mDrmConnector->get_preferred_mode_id(); + err = HWC2_ERROR_BAD_CONFIG; } - ALOGI("Preferred mode id: %d, state: %d", config, mDrmConnector->state()); - if ((err = setActiveConfig(config)) < 0) { - ALOGE("failed to set default config, err %d", err); - return err; + const int32_t drmPreferredConfig = mDrmConnector->get_preferred_mode_id(); + if (err != HWC2_ERROR_NONE) { + config = drmPreferredConfig; } + ALOGI("Preferred mode id: %d(%s), state: %d", config, modeStr, mDrmConnector->state()); - mExynosDisplay->updateInternalDisplayConfigVariables(config); - return err; + auto &configs = mExynosDisplay->mDisplayConfigs; + if (config != drmPreferredConfig && + (configs[config].width != configs[drmPreferredConfig].width || + configs[config].height != configs[drmPreferredConfig].height)) { + // HWC cannot send a resolution change commit here until 1st frame update because of + // some panels requirement. Therefore, it calls setActiveConfigWithConstraints() help + // set mDesiredModeState correctly, and then trigger modeset in the 1s frame update. + if ((err = setActiveConfigWithConstraints(config)) < 0) { + ALOGE("failed to setActiveConfigWithConstraints(), err %d", err); + return err; + } + } else { + if ((err = setActiveConfig(config)) < 0) { + ALOGE("failed to set default config, err %d", err); + return err; + } + } + + return mExynosDisplay->updateInternalDisplayConfigVariables(config); } int32_t ExynosDisplayDrmInterface::getDisplayConfigs( @@ -876,11 +996,12 @@ int32_t ExynosDisplayDrmInterface::getDisplayConfigs( /* key: (width<<32 | height) */ std::map<uint64_t, uint32_t> groupIds; uint32_t groupId = 0; - uint32_t min_vsync_period = UINT_MAX; + float peakRr = -1; for (const DrmMode &mode : mDrmConnector->modes()) { displayConfigs_t configs; - configs.vsyncPeriod = nsecsPerSec/ mode.v_refresh(); + float rr = mode.v_refresh(); + configs.vsyncPeriod = nsecsPerSec / rr; configs.width = mode.h_display(); configs.height = mode.v_display(); uint64_t key = ((uint64_t)configs.width<<32) | configs.height; @@ -897,14 +1018,15 @@ int32_t ExynosDisplayDrmInterface::getDisplayConfigs( configs.Xdpi = mm_width ? (mode.h_display() * kUmPerInch) / mm_width : -1; // Dots per 1000 inches configs.Ydpi = mm_height ? (mode.v_display() * kUmPerInch) / mm_height : -1; - // find min vsync period - if (configs.vsyncPeriod <= min_vsync_period) min_vsync_period = configs.vsyncPeriod; + // find peak rr + if (rr > peakRr) + peakRr = rr; mExynosDisplay->mDisplayConfigs.insert(std::make_pair(mode.id(), configs)); ALOGD("config group(%d), w(%d), h(%d), vsync(%d), xdpi(%d), ydpi(%d)", configs.groupId, configs.width, configs.height, configs.vsyncPeriod, configs.Xdpi, configs.Ydpi); } - mExynosDisplay->setMinDisplayVsyncPeriod(min_vsync_period); + mExynosDisplay->setPeakRefreshRate(peakRr); } uint32_t num_modes = static_cast<uint32_t>(mDrmConnector->modes().size()); @@ -947,7 +1069,12 @@ int32_t ExynosDisplayDrmInterface::getDisplayVsyncPeriod(hwc2_vsync_period_t* ou int32_t ExynosDisplayDrmInterface::getConfigChangeDuration() { - /* TODO: Get from driver */ + const auto [ret, duration] = mDrmConnector->vrr_switch_duration().value(); + + if (!ret && duration > 0) { + return duration; + } + return 2; }; @@ -1055,6 +1182,7 @@ int32_t ExynosDisplayDrmInterface::setActiveConfigWithConstraints( { ALOGD("%s:: %s config(%d) test(%d)", __func__, mExynosDisplay->mDisplayName.string(), config, test); + auto mode = std::find_if(mDrmConnector->modes().begin(), mDrmConnector->modes().end(), [config](DrmMode const &m) { return m.id() == config;}); if (mode == mDrmConnector->modes().end()) { @@ -1071,7 +1199,7 @@ int32_t ExynosDisplayDrmInterface::setActiveConfigWithConstraints( return HWC2_ERROR_NONE; } - if (mDesiredModeState.needs_modeset) { + if (mDesiredModeState.needsModeSet()) { ALOGD("Previous mode change request is not applied"); } @@ -1085,34 +1213,46 @@ int32_t ExynosDisplayDrmInterface::setActiveConfigWithConstraints( return HWC2_ERROR_BAD_CONFIG; } } - if (test) { - if ((ret = setDisplayMode(drmReq, modeBlob? modeBlob : mDesiredModeState.blob_id)) < 0) { - HWC_LOGE(mExynosDisplay, "%s: Fail to apply display mode", - __func__); - return ret; - } - ret = drmReq.commit(DRM_MODE_ATOMIC_TEST_ONLY, true); - if (ret) { - drmReq.addOldBlob(modeBlob); - HWC_LOGE(mExynosDisplay, "%s:: Failed to commit pset ret=%d in applyDisplayMode()\n", - __func__, ret); - return ret; + const auto isResSwitch = + (mActiveModeState.blob_id != 0) && mActiveModeState.isFullModeSwitch(*mode); + + if (!test) { + if (modeBlob) { /* only replace desired mode if it has changed */ + mDesiredModeState.setMode(*mode, modeBlob, drmReq); + if (mExynosDisplay->mOperationRateManager) { + mExynosDisplay->mOperationRateManager->onConfig(config); + } + DISPLAY_DRM_LOGI("%s: config(%d)", __func__, config); + } else { + ALOGD("%s:: same desired mode %d", __func__, config); } } else { - mDesiredModeState.needs_modeset = true; - } + if (!isResSwitch) { + ret = setDisplayMode(drmReq, modeBlob ? modeBlob : mDesiredModeState.blob_id); + if (ret < 0) { + HWC_LOGE(mExynosDisplay, "%s: Fail to apply display mode", __func__); + return ret; + } + ret = drmReq.commit(DRM_MODE_ATOMIC_TEST_ONLY, true); + if (ret) { + drmReq.addOldBlob(modeBlob); + HWC_LOGE(mExynosDisplay, + "%s:: Failed to commit pset ret=%d in applyDisplayMode()\n", __func__, + ret); + return ret; + } + } - if (modeBlob != 0) { - mDesiredModeState.setMode(*mode, modeBlob, drmReq); + if (modeBlob) { + mDrmDevice->DestroyPropertyBlob(modeBlob); + } } return HWC2_ERROR_NONE; } int32_t ExynosDisplayDrmInterface::setActiveDrmMode(DrmMode const &mode) { /* Don't skip when power was off */ - if (!(mExynosDisplay->mSkipFrame) && - (mActiveModeState.blob_id != 0) && - (mActiveModeState.mode.id() == mode.id()) && - (mActiveModeState.needs_modeset == false)) { + if (!(mExynosDisplay->mSkipFrame) && (mActiveModeState.blob_id != 0) && + (mActiveModeState.mode.id() == mode.id()) && !mActiveModeState.needsModeSet()) { ALOGD("%s:: same mode %d", __func__, mode.id()); return HWC2_ERROR_NONE; } @@ -1130,16 +1270,7 @@ int32_t ExynosDisplayDrmInterface::setActiveDrmMode(DrmMode const &mode) { uint32_t flags = DRM_MODE_ATOMIC_ALLOW_MODESET; bool reconfig = false; - if ((mActiveModeState.blob_id != 0) && - ((mode.h_display() != mActiveModeState.mode.h_display()) || - (mode.v_display() != mActiveModeState.mode.v_display()))) { - ret = clearDisplayPlanes(drmReq); - if (ret != HWC2_ERROR_NONE) { - HWC_LOGE(mExynosDisplay, "%s: Failed to clear planes due to resolution change", - __func__); - } else { - ALOGD("%s: switching display resolution, clearing planes", __func__); - } + if (mActiveModeState.isFullModeSwitch(mode)) { reconfig = true; } @@ -1159,7 +1290,7 @@ int32_t ExynosDisplayDrmInterface::setActiveDrmMode(DrmMode const &mode) { mDrmConnector->set_active_mode(mode); mActiveModeState.setMode(mode, modeBlob, drmReq); - mActiveModeState.needs_modeset = false; + mActiveModeState.clearPendingModeState(); if (reconfig) { mDrmConnector->ResetLpMode(); @@ -1177,16 +1308,30 @@ int32_t ExynosDisplayDrmInterface::setActiveConfig(hwc2_config_t config) { return HWC2_ERROR_BAD_CONFIG; } + if (mExynosDisplay->mOperationRateManager) { + mExynosDisplay->mOperationRateManager->onConfig(config); + } + mExynosDisplay->updateAppliedActiveConfig(config, systemTime(SYSTEM_TIME_MONOTONIC)); if (!setActiveDrmMode(*mode)) { - ALOGI("%s:: %s config(%d)", __func__, mExynosDisplay->mDisplayName.string(), config); + DISPLAY_DRM_LOGI("%s: config(%d)", __func__, config); } else { - ALOGE("%s:: %s config(%d) failed", __func__, mExynosDisplay->mDisplayName.string(), config); + DISPLAY_DRM_LOGE("%s: config(%d) failed", __func__, config); } return 0; } +int32_t ExynosDisplayDrmInterface::getPanelResolution() { + for (auto it = mDrmConnector->modes().begin(); it != mDrmConnector->modes().end(); it++) { + if (it->h_display() * it->v_display() > mPanelResolutionHsize * mPanelResolutionVsize) { + mPanelResolutionHsize = it->h_display(); + mPanelResolutionVsize = it->v_display(); + } + } + return 0; +} + int32_t ExynosDisplayDrmInterface::createModeBlob(const DrmMode &mode, uint32_t &modeBlob) { @@ -1328,11 +1473,11 @@ int32_t ExynosDisplayDrmInterface::updateHdrCapabilities() int ExynosDisplayDrmInterface::getDeconChannel(ExynosMPP *otfMPP) { - int32_t channelNum = sizeof(IDMA_CHANNEL_MAP)/sizeof(dpp_channel_map_t); + int32_t channelNum = sizeof(idma_channel_map)/sizeof(dpp_channel_map_t); for (int i = 0; i < channelNum; i++) { - if((IDMA_CHANNEL_MAP[i].type == otfMPP->mPhysicalType) && - (IDMA_CHANNEL_MAP[i].index == otfMPP->mPhysicalIndex)) - return IDMA_CHANNEL_MAP[i].channel; + if((idma_channel_map[i].type == otfMPP->mPhysicalType) && + (idma_channel_map[i].index == otfMPP->mPhysicalIndex)) + return idma_channel_map[i].channel; } return -EINVAL; } @@ -1344,6 +1489,7 @@ int32_t ExynosDisplayDrmInterface::setupCommitFromDisplayConfig( const std::unique_ptr<DrmPlane> &plane, uint32_t &fbId) { + ATRACE_CALL(); int ret = NO_ERROR; if (fbId == 0) { @@ -1603,10 +1749,14 @@ int32_t ExynosDisplayDrmInterface::updateColorSettings(DrmModeAtomicReq &drmReq, } auto &plane = mDrmDevice->planes().at(channelId); - if ((ret = setPlaneColorSetting(drmReq, plane, config)) != 0) { + uint32_t solidColor = config.color; + if ((ret = setPlaneColorSetting(drmReq, plane, config, solidColor)) != 0) { HWC_LOGE(mExynosDisplay, "Failed to set plane color setting, config[%zu]", i); return ret; } + if (config.state == config.WIN_STATE_COLOR && solidColor != config.color) { + config.color = solidColor; + } } } @@ -1620,11 +1770,16 @@ int32_t ExynosDisplayDrmInterface::deliverWinConfigData() std::unordered_map<uint32_t, uint32_t> planeEnableInfo; android::String8 result; bool hasSecureFrameBuffer = false; + bool hasM2mSecureLayerBuffer = false; + if (mExynosDisplay->isFrameUpdate()) { + mFrameCounter++; + } funcReturnCallback retCallback([&]() { if ((ret == NO_ERROR) && !drmReq.getError()) { - mFBManager.flip(hasSecureFrameBuffer); + mFBManager.flip(hasSecureFrameBuffer, hasM2mSecureLayerBuffer); } else if (ret == -ENOMEM) { + ALOGW("OOM, release all cached buffers by FBManager"); mFBManager.releaseAll(); } }); @@ -1651,7 +1806,7 @@ int32_t ExynosDisplayDrmInterface::deliverWinConfigData() } uint64_t mipi_sync_type = 0; - if (mDesiredModeState.needs_modeset) { + if (mDesiredModeState.needsModeSet()) { if (mExynosDisplay->checkRrCompensationEnabled()) { mipi_sync_type |= 1 << mMipiSyncEnums[toUnderlying(HalMipiSyncType::HAL_MIPI_CMD_SYNC_REFRESH_RATE)]; @@ -1691,6 +1846,13 @@ int32_t ExynosDisplayDrmInterface::deliverWinConfigData() return ret; } + // Update of color settings could change layer's solid color. So it should + // be called before use of layer's solid color. + if ((ret = updateColorSettings(drmReq, dqeEnable)) != 0) { + HWC_LOGE(mExynosDisplay, "failed to update color settings (%d)", ret); + return ret; + } + for (size_t i = 0; i < mExynosDisplay->mDpuData.configs.size(); i++) { exynos_win_config_data& config = mExynosDisplay->mDpuData.configs[i]; if ((config.state == config.WIN_STATE_BUFFER) || @@ -1714,6 +1876,7 @@ int32_t ExynosDisplayDrmInterface::deliverWinConfigData() return ret; } hasSecureFrameBuffer |= (isFramebuffer(config.layer) && config.protection); + hasM2mSecureLayerBuffer |= (config.protection && config.layer && config.layer->mM2mMPP); /* Set this plane is enabled */ planeEnableInfo[plane->id()] = 1; } @@ -1721,15 +1884,18 @@ int32_t ExynosDisplayDrmInterface::deliverWinConfigData() for (size_t i = 0; i < mExynosDisplay->mDpuData.rcdConfigs.size(); ++i) { exynos_win_config_data &config = mExynosDisplay->mDpuData.rcdConfigs[i]; - if (config.state == config.WIN_STATE_RCD) { - const int channelId = mExynosDisplay->mDevice->getSpecialPlaneId( - mExynosDisplay->mIndex); // TODO: b/227584297 - auto &plane = mDrmDevice->planes().at(channelId); - uint32_t fbId = 0; - if ((ret = setupCommitFromDisplayConfig(drmReq, config, i, plane, fbId)) < 0) { - HWC_LOGE(mExynosDisplay, "setupCommitFromDisplayConfig failed, config[%zu]", i); + if ((config.state == config.WIN_STATE_RCD) && + (mExynosDisplay->mType == HWC_DISPLAY_PRIMARY)) { + const int32_t rcdId = static_cast<ExynosPrimaryDisplay *>(mExynosDisplay)->mRcdId; + const int32_t channelId = getSpecialChannelId(rcdId); + if (channelId >= 0) { + auto &plane = mDrmDevice->planes().at(channelId); + uint32_t fbId = 0; + if ((ret = setupCommitFromDisplayConfig(drmReq, config, i, plane, fbId)) < 0) { + HWC_LOGE(mExynosDisplay, "setupCommitFromDisplayConfig failed, config[%zu]", i); + } + planeEnableInfo[plane->id()] = 1; } - planeEnableInfo[plane->id()] = 1; } } @@ -1743,6 +1909,15 @@ int32_t ExynosDisplayDrmInterface::deliverWinConfigData() (exynosMPP->mReservedDisplay != (int32_t)mExynosDisplay->mDisplayId)) continue; + if ((exynosMPP == NULL) && (mExynosDisplay->mType == HWC_DISPLAY_PRIMARY) && + (plane->id() != static_cast<ExynosPrimaryDisplay *>(mExynosDisplay)->mRcdId)) + continue; + + /* If this plane is not supported by the CRTC binded with ExynosDisplay, + * it should be disabled by this ExynosDisplay */ + if (!plane->GetCrtcSupported(*mDrmCrtc)) + continue; + if ((ret = drmReq.atomicAddProperty(plane->id(), plane->crtc_property(), 0)) < 0) return ret; @@ -1759,8 +1934,11 @@ int32_t ExynosDisplayDrmInterface::deliverWinConfigData() if (mExynosDisplay->mBrightnessController) { bool ghbmSync, lhbmSync, blSync; + bool mixedComposition = mExynosDisplay->isMixedComposition() + || mExynosDisplay->isPriorFrameMixedCompostion(); ret = mExynosDisplay->mBrightnessController->prepareFrameCommit(*mExynosDisplay, - *mDrmConnector, drmReq, ghbmSync, lhbmSync, blSync); + *mDrmConnector, drmReq, mixedComposition, + ghbmSync, lhbmSync, blSync); if (ret < 0) { HWC_LOGE(mExynosDisplay, "%s: Fail to config brightness", __func__); } else { @@ -1780,7 +1958,7 @@ int32_t ExynosDisplayDrmInterface::deliverWinConfigData() } uint32_t flags = DRM_MODE_ATOMIC_NONBLOCK; - if (needModesetForReadback) + if (needModesetForReadback || !mDesiredModeState.isSeamless()) flags |= DRM_MODE_ATOMIC_ALLOW_MODESET; /* For Histogram */ @@ -1789,17 +1967,16 @@ int32_t ExynosDisplayDrmInterface::deliverWinConfigData() return ret; } - if ((ret = updateColorSettings(drmReq, dqeEnable)) != 0) { - HWC_LOGE(mExynosDisplay, "failed to update color settings (%d)", ret); - return ret; - } - if (mDrmConnector->mipi_sync().id() && (mipi_sync_type != 0)) { - ATRACE_NAME("mipi_sync"); // mark this commit - if ((ret = drmReq.atomicAddProperty(mDrmConnector->id(), - mDrmConnector->mipi_sync(), - mipi_sync_type)) < 0) { - HWC_LOGE(mExynosDisplay, "%s: Fail to set mipi_sync property (%d)", __func__, ret); + // skip mipi sync in Doze mode + bool inDoze = isDozeModeAvailable() && mDozeDrmMode.id() == mActiveModeState.mode.id(); + if (!inDoze) { + ATRACE_NAME("mipi_sync"); // mark this commit + if ((ret = drmReq.atomicAddProperty(mDrmConnector->id(), + mDrmConnector->mipi_sync(), + mipi_sync_type)) < 0) { + HWC_LOGE(mExynosDisplay, "%s: Fail to set mipi_sync property (%d)", __func__, ret); + } } } @@ -1839,8 +2016,12 @@ int32_t ExynosDisplayDrmInterface::deliverWinConfigData() } } - if (mDesiredModeState.needs_modeset) { + if (mDesiredModeState.needsModeSet()) { mDesiredModeState.apply(mActiveModeState, drmReq); + if (!mActiveModeState.isSeamless()) { + mDrmConnector->ResetLpMode(); + getLowPowerDrmModeModeInfo(); + } mVsyncCallback.setDesiredVsyncPeriod( nsecsPerSec/mActiveModeState.mode.v_refresh()); /* Enable vsync to check vsync period */ @@ -1869,6 +2050,21 @@ int32_t ExynosDisplayDrmInterface::clearDisplayMode(DrmModeAtomicReq &drmReq) return NO_ERROR; } +int32_t ExynosDisplayDrmInterface::triggerClearDisplayPlanes() +{ + ATRACE_CALL(); + DrmModeAtomicReq drmReq(this); + + clearDisplayPlanes(drmReq); + int ret = NO_ERROR; + if ((ret = drmReq.commit(0, true))) { + HWC_LOGE(mExynosDisplay, "%s:: Failed to commit pset ret=(%d)\n", + __func__, ret); + return ret; + } + return ret; +} + int32_t ExynosDisplayDrmInterface::clearDisplayPlanes(DrmModeAtomicReq &drmReq) { int ret = NO_ERROR; @@ -1882,6 +2078,11 @@ int32_t ExynosDisplayDrmInterface::clearDisplayPlanes(DrmModeAtomicReq &drmReq) (exynosMPP->mReservedDisplay != (int32_t)mExynosDisplay->mDisplayId)) continue; + /* If this plane is not supported by the CRTC binded with ExynosDisplay, + * it should not be disabled by this ExynosDisplay */ + if (!plane->GetCrtcSupported(*mDrmCrtc)) + continue; + if ((ret = drmReq.atomicAddProperty(plane->id(), plane->crtc_property(), 0)) < 0) { break; @@ -1898,6 +2099,9 @@ int32_t ExynosDisplayDrmInterface::clearDisplayPlanes(DrmModeAtomicReq &drmReq) int32_t ExynosDisplayDrmInterface::clearDisplay(bool needModeClear) { + ExynosDevice *exynosDevice = mExynosDisplay->mDevice; + const bool isAsyncOff = needModeClear && exynosDevice->isDispOffAsyncSupported() && + !exynosDevice->hasOtherDisplayOn(mExynosDisplay); int ret = NO_ERROR; DrmModeAtomicReq drmReq(this); @@ -1918,7 +2122,7 @@ int32_t ExynosDisplayDrmInterface::clearDisplay(bool needModeClear) } /* Disable ModeSet */ - if (needModeClear) { + if (needModeClear && !isAsyncOff) { if ((ret = clearDisplayMode(drmReq)) < 0) { HWC_LOGE(mExynosDisplay, "%s: Failed to apply display mode", __func__); return ret; @@ -1932,8 +2136,24 @@ int32_t ExynosDisplayDrmInterface::clearDisplay(bool needModeClear) return ret; } - if (needModeClear) - mActiveModeState.needs_modeset = true; + /* During async off we're clearing planes within a single refresh cycle + * and then offloading display off asynchronously. + */ + if (isAsyncOff) { + if ((ret = clearDisplayMode(drmReq)) < 0) { + HWC_LOGE(mExynosDisplay, "%s: Failed to apply display mode", __func__); + return ret; + } + + ret = drmReq.commit(DRM_MODE_ATOMIC_ALLOW_MODESET | DRM_MODE_ATOMIC_NONBLOCK, true); + if (ret) { + HWC_LOGE(mExynosDisplay, "%s:: Failed to commit pset ret=%d in clearDisplay()\n", + __func__, ret); + return ret; + } + } + + if (needModeClear) mActiveModeState.forceModeSet(); return NO_ERROR; } @@ -2305,6 +2525,11 @@ int32_t ExynosDisplayDrmInterface::getDisplayFakeEdid(uint8_t &outPort, uint32_t edid_buf[59] = height & 0xff; edid_buf[61] = (height >> 4) & 0xf0; + if (mMonitorDescription[0] != 0) { + /* Descriptor block 3 starts at address 90, data offset is 5 bytes */ + memcpy(&edid_buf[95], mMonitorDescription.data(), mMonitorDescription.size()); + } + unsigned int sum = std::accumulate(edid_buf.begin(), edid_buf.end() - 1, 0); edid_buf[127] = (0x100 - (sum & 0xFF)) & 0xFF; if (outData) { @@ -2370,3 +2595,16 @@ int32_t ExynosDisplayDrmInterface::getDisplayIdentificationData( return HWC2_ERROR_NONE; } + +int32_t ExynosDisplayDrmInterface::getSpecialChannelId(uint32_t planeId) { + ExynosDevice *exynosDevice = mExynosDisplay->mDevice; + for (int i = 0; i < exynosDevice->getSpecialPlaneNum(); i++) { + const int32_t channelId = exynosDevice->getSpecialPlaneId(i); + auto &plane = mDrmDevice->planes().at(channelId); + if (plane->id() == planeId) return channelId; + } + + ALOGE("%s: Failed to get RCD planeId.", __func__); + + return -EINVAL; +} diff --git a/libhwc2.1/libdisplayinterface/ExynosDisplayDrmInterface.h b/libhwc2.1/libdisplayinterface/ExynosDisplayDrmInterface.h index 6233ef6..3997b0f 100644 --- a/libhwc2.1/libdisplayinterface/ExynosDisplayDrmInterface.h +++ b/libhwc2.1/libdisplayinterface/ExynosDisplayDrmInterface.h @@ -31,11 +31,15 @@ #include "ExynosMPP.h" #include "drmconnector.h" #include "drmcrtc.h" +#include "histogram/histogram.h" #include "vsyncworker.h" /* Max plane number of buffer object */ #define HWC_DRM_BO_MAX_PLANES 4 +/* Monitor Descriptor data is 13 bytes in VESA EDID Standard */ +#define MONITOR_DESCRIPTOR_DATA_LENGTH 13 + #ifndef HWC_FORCE_PANIC_PATH #define HWC_FORCE_PANIC_PATH "/d/dpu/panic" #endif @@ -59,7 +63,7 @@ class FramebufferManager { // layer. Those fbIds will be cleaned up once the layer was destroyed. int32_t getBuffer(const exynos_win_config_data &config, uint32_t &fbId); - bool checkShrink(); + void checkShrink(); void cleanup(const ExynosLayer *layer); @@ -67,7 +71,7 @@ class FramebufferManager { // layers after the previous fdIds were update successfully on the // screen. // This should be called after the frame update. - void flip(bool hasSecureFrameBuffer); + void flip(const bool hasSecureFrameBuffer, const bool hasM2mSecureLayerBuffer); // release all currently tracked buffers, this can be called for example when display is turned // off @@ -108,7 +112,8 @@ class FramebufferManager { using FBList = std::list<std::unique_ptr<Framebuffer>>; template <class UnaryPredicate> - uint32_t findCachedFbId(const ExynosLayer *layer, UnaryPredicate predicate); + uint32_t findCachedFbId(const ExynosLayer *layer, const bool isM2mSecureLayer, + UnaryPredicate predicate); int addFB2WithModifiers(uint32_t state, uint32_t width, uint32_t height, uint32_t drmFormat, const DrmArray<uint32_t> &handles, const DrmArray<uint32_t> &pitches, @@ -122,15 +127,19 @@ class FramebufferManager { void freeBufHandle(uint32_t handle); void removeFBsThreadRoutine(); - void markInuseLayerLocked(const ExynosLayer *layer) REQUIRES(mMutex); + void markInuseLayerLocked(const ExynosLayer *layer, const bool isM2mSecureLayer) + REQUIRES(mMutex); void destroyUnusedLayersLocked() REQUIRES(mMutex); void destroySecureFramebufferLocked() REQUIRES(mMutex); + void destroyM2mSecureLayerBufferLocked() REQUIRES(mMutex); int mDrmFd = -1; - // mCachedLayerBuffers map keep the relationship between Layer and - // FBList. The map entry will be deleted once the layer is destroyed. + // mCachedLayerBuffers map keep the relationship between Layer and FBList. + // mCachedM2mSecureLayerBuffers map keep the relationship between M2M secure + // Layer and FBList. The map entry will be deleted once the layer is destroyed. std::map<const ExynosLayer *, FBList> mCachedLayerBuffers; + std::map<const ExynosLayer *, FBList> mCachedM2mSecureLayerBuffers; // mCleanBuffers list keeps fbIds of destroyed layers. Those fbIds will // be destroyed in mRmFBThread thread. @@ -139,11 +148,15 @@ class FramebufferManager { // mCacheShrinkPending is set when we want to clean up unused layers // in mCachedLayerBuffers. When the flag is set, mCachedLayersInuse will // keep in-use layers in this frame update. Those unused layers will be - // freed at the end of the update. + // freed at the end of the update. mCacheM2mSecureShrinkPending is same to + // mCacheShrinkPending but for mCachedM2mSecureLayerBuffers. // TODO: have a better way to maintain inuse layers bool mCacheShrinkPending = false; + bool mCacheM2mSecureShrinkPending = false; bool mHasSecureFramebuffer = false; + bool mHasM2mSecureLayerBuffer = false; std::set<const ExynosLayer *> mCachedLayersInuse; + std::set<const ExynosLayer *> mCachedM2mSecureLayersInuse; std::thread mRmFBThread; bool mRmFBThreadRunning = false; @@ -151,7 +164,9 @@ class FramebufferManager { Mutex mMutex; static constexpr size_t MAX_CACHED_LAYERS = 16; + static constexpr size_t MAX_CACHED_M2M_SECURE_LAYERS = 1; static constexpr size_t MAX_CACHED_BUFFERS_PER_LAYER = 32; + static constexpr size_t MAX_CACHED_M2M_SECURE_BUFFERS_PER_LAYER = 3; }; inline bool isFramebuffer(const ExynosLayer *layer) { @@ -159,10 +174,12 @@ inline bool isFramebuffer(const ExynosLayer *layer) { } template <class UnaryPredicate> -uint32_t FramebufferManager::findCachedFbId(const ExynosLayer *layer, UnaryPredicate predicate) { +uint32_t FramebufferManager::findCachedFbId(const ExynosLayer *layer, const bool isM2mSecureLayer, + UnaryPredicate predicate) { Mutex::Autolock lock(mMutex); - markInuseLayerLocked(layer); - const auto &cachedBuffers = mCachedLayerBuffers[layer]; + markInuseLayerLocked(layer, isM2mSecureLayer); + const auto &cachedBuffers = + (!isM2mSecureLayer) ? mCachedLayerBuffers[layer] : mCachedM2mSecureLayerBuffers[layer]; const auto it = std::find_if(cachedBuffers.begin(), cachedBuffers.end(), predicate); return (it != cachedBuffers.end()) ? (*it)->fbId : 0; } @@ -293,12 +310,14 @@ class ExynosDisplayDrmInterface : hwc2_config_t config, bool test = false); virtual int32_t setDisplayColorSetting( - ExynosDisplayDrmInterface::DrmModeAtomicReq &drmReq) - { return NO_ERROR;}; + ExynosDisplayDrmInterface::DrmModeAtomicReq __unused &drmReq) { + return NO_ERROR; + } virtual int32_t setPlaneColorSetting( ExynosDisplayDrmInterface::DrmModeAtomicReq &drmReq, const std::unique_ptr<DrmPlane> &plane, - const exynos_win_config_data& config) + const exynos_win_config_data& config, + uint32_t &solidColor) { return NO_ERROR;}; virtual void destroyLayer(ExynosLayer *layer) override; @@ -314,7 +333,18 @@ class ExynosDisplayDrmInterface : ExynosDisplayDrmInterface::DrmModeAtomicReq &drmReq) { return NO_ERROR; } - virtual int32_t setHistogramData(void *__unused bin) { return NO_ERROR; } + int32_t getFrameCount() { return mFrameCounter; } + virtual void registerHistogramInfo(const std::shared_ptr<IDLHistogram> &info) { return; } + virtual int32_t setHistogramControl(hidl_histogram_control_t enabled) { return NO_ERROR; } + virtual int32_t setHistogramData(void *bin) { return NO_ERROR; } + int32_t getActiveModeHDisplay() { return mActiveModeState.mode.h_display(); } + int32_t getActiveModeVDisplay() { return mActiveModeState.mode.v_display(); } + uint32_t getActiveModeId() { return mActiveModeState.mode.id(); } + int32_t panelHsize() { return mPanelResolutionHsize; } + int32_t panelVsize() { return mPanelResolutionVsize; } + int32_t getPanelResolution(); + uint32_t getCrtcId() { return mDrmCrtc->id(); } + int32_t triggerClearDisplayPlanes(); protected: enum class HalMipiSyncType : uint32_t { @@ -325,12 +355,24 @@ class ExynosDisplayDrmInterface : }; struct ModeState { - bool needs_modeset = false; + enum ModeStateType { + MODE_STATE_NONE = 0U, + MODE_STATE_REFRESH_RATE = 1U << 0, + MODE_STATE_RESOLUTION = 1U << 1, + MODE_STATE_FORCE_MODE_SET = 1U << 2, + }; DrmMode mode; uint32_t blob_id = 0; uint32_t old_blob_id = 0; void setMode(const DrmMode newMode, const uint32_t modeBlob, DrmModeAtomicReq &drmReq) { + if (newMode.v_refresh() != mode.v_refresh()) { + mModeState |= ModeStateType::MODE_STATE_REFRESH_RATE; + } + if (isFullModeSwitch(newMode)) { + mModeState |= ModeStateType::MODE_STATE_RESOLUTION; + } + drmReq.addOldBlob(old_blob_id); mode = newMode; old_blob_id = blob_id; @@ -344,6 +386,18 @@ class ExynosDisplayDrmInterface : drmReq.addOldBlob(old_blob_id); reset(); }; + + int32_t mModeState = ModeStateType::MODE_STATE_NONE; + void forceModeSet() { mModeState |= ModeStateType::MODE_STATE_FORCE_MODE_SET; } + void clearPendingModeState() { mModeState = ModeStateType::MODE_STATE_NONE; } + bool needsModeSet() const { return mModeState != ModeStateType::MODE_STATE_NONE; } + bool isSeamless() const { return !(mModeState & ModeStateType::MODE_STATE_RESOLUTION); } + bool isFullModeSwitch(const DrmMode &newMode) { + if ((mode.h_display() != newMode.h_display()) || + (mode.v_display() != newMode.v_display())) + return true; + return false; + } }; int32_t createModeBlob(const DrmMode &mode, uint32_t &modeBlob); int32_t setDisplayMode(DrmModeAtomicReq &drmReq, const uint32_t modeBlob); @@ -369,6 +423,7 @@ class ExynosDisplayDrmInterface : void parseColorModeEnums(const DrmProperty &property); void parseMipiSyncEnums(const DrmProperty &property); void updateMountOrientation(); + void parseRCDId(const DrmProperty &property); int32_t setupWritebackCommit(DrmModeAtomicReq &drmReq); int32_t clearWritebackCommit(DrmModeAtomicReq &drmReq); @@ -378,6 +433,7 @@ class ExynosDisplayDrmInterface : int32_t getLowPowerDrmModeModeInfo(); int32_t setActiveDrmMode(DrmMode const &mode); void setMaxWindowNum(uint32_t num) { mMaxWindowNum = num; }; + int32_t getSpecialChannelId(uint32_t planeId); protected: struct PartialRegionState { @@ -453,12 +509,17 @@ class ExynosDisplayDrmInterface : DrmReadbackInfo mReadbackInfo; FramebufferManager mFBManager; + std::array<uint8_t, MONITOR_DESCRIPTOR_DATA_LENGTH> mMonitorDescription; private: int32_t getDisplayFakeEdid(uint8_t &outPort, uint32_t &outDataSize, uint8_t *outData); + String8 mDisplayTraceName; DrmMode mDozeDrmMode; uint32_t mMaxWindowNum = 0; + int32_t mFrameCounter = 0; + int32_t mPanelResolutionHsize = 0; + int32_t mPanelResolutionVsize = 0; }; #endif diff --git a/libhwc2.1/libdisplayinterface/ExynosDisplayInterface.h b/libhwc2.1/libdisplayinterface/ExynosDisplayInterface.h index d133774..b87c2e2 100644 --- a/libhwc2.1/libdisplayinterface/ExynosDisplayInterface.h +++ b/libhwc2.1/libdisplayinterface/ExynosDisplayInterface.h @@ -53,6 +53,7 @@ class ExynosDisplayInterface { virtual int32_t updateHdrCapabilities(); virtual int32_t deliverWinConfigData() {return NO_ERROR;}; virtual int32_t clearDisplay(bool __unused needModeClear = false) {return NO_ERROR;}; + virtual int32_t triggerClearDisplayPlanes() { return NO_ERROR; } virtual int32_t disableSelfRefresh(uint32_t __unused disable) {return NO_ERROR;}; virtual int32_t setForcePanic() {return NO_ERROR;}; virtual int getDisplayFd() {return -1;}; @@ -79,6 +80,7 @@ class ExynosDisplayInterface { virtual int32_t getDefaultModeId(int32_t* __unused modeId) { return HWC2_ERROR_UNSUPPORTED; } + virtual uint32_t getActiveModeId() { return UINT_MAX; } virtual int32_t waitVBlank() { return 0; }; public: diff --git a/libhwc2.1/libdrmresource/drm/drmconnector.cpp b/libhwc2.1/libdrmresource/drm/drmconnector.cpp index 3cbd24e..2f9943e 100644 --- a/libhwc2.1/libdrmresource/drm/drmconnector.cpp +++ b/libhwc2.1/libdrmresource/drm/drmconnector.cpp @@ -155,6 +155,11 @@ int DrmConnector::Init() { ALOGE("Could not get panel_idle_support property\n"); } + ret = drm_->GetConnectorProperty(*this, "vrr_switch_duration", &vrr_switch_duration_); + if (ret) { + ALOGE("Could not get vrr_switch_duration property\n"); + } + properties_.push_back(&dpms_property_); properties_.push_back(&crtc_id_property_); properties_.push_back(&edid_property_); @@ -176,6 +181,7 @@ int DrmConnector::Init() { properties_.push_back(&lhbm_on_); properties_.push_back(&mipi_sync_); properties_.push_back(&panel_idle_support_); + properties_.push_back(&vrr_switch_duration_); return 0; } @@ -391,6 +397,10 @@ const DrmProperty &DrmConnector::panel_idle_support() const { return panel_idle_support_; } +const DrmProperty &DrmConnector::vrr_switch_duration() const { + return vrr_switch_duration_; +} + DrmEncoder *DrmConnector::encoder() const { return encoder_; } diff --git a/libhwc2.1/libdrmresource/drm/drmcrtc.cpp b/libhwc2.1/libdrmresource/drm/drmcrtc.cpp index 765444b..55cee3c 100644 --- a/libhwc2.1/libdrmresource/drm/drmcrtc.cpp +++ b/libhwc2.1/libdrmresource/drm/drmcrtc.cpp @@ -95,6 +95,10 @@ int DrmCrtc::Init() { ALOGI("Failed to get &histogram_weights property"); if (drm_->GetCrtcProperty(*this, "histogram_threshold", &histogram_threshold_property_)) ALOGI("Failed to get &histogram_threshold property"); + if (drm_->GetCrtcProperty(*this, "histogram_pos", &histogram_position_property_)) + ALOGI("Failed to get &histogram_position property"); + if (drm_->GetCrtcProperty(*this, "rcd_plane_id", &rcd_plane_id_property_)) + ALOGI("Failed to get &rcd_plane_id property"); properties_.push_back(&active_property_); properties_.push_back(&mode_property_); @@ -122,6 +126,9 @@ int DrmCrtc::Init() { properties_.push_back(&histogram_roi_property_); properties_.push_back(&histogram_weights_property_); properties_.push_back(&histogram_threshold_property_); + properties_.push_back(&histogram_position_property_); + + properties_.push_back(&rcd_plane_id_property_); return 0; } @@ -255,4 +262,12 @@ const DrmProperty &DrmCrtc::histogram_threshold_property() const { return histogram_threshold_property_; } +const DrmProperty &DrmCrtc::histogram_position_property() const { + return histogram_position_property_; +} + +const DrmProperty &DrmCrtc::rcd_plane_id_property() const { + return rcd_plane_id_property_; +} + } // namespace android diff --git a/libhwc2.1/libdrmresource/drm/drmeventlistener.cpp b/libhwc2.1/libdrmresource/drm/drmeventlistener.cpp index c16b372..bd12d30 100644 --- a/libhwc2.1/libdrmresource/drm/drmeventlistener.cpp +++ b/libhwc2.1/libdrmresource/drm/drmeventlistener.cpp @@ -17,19 +17,21 @@ #define LOG_TAG "hwc-drm-event-listener" #include "drmeventlistener.h" -#include "drmdevice.h" -#include <drm/samsung_drm.h> #include <assert.h> +#include <drm/samsung_drm.h> #include <errno.h> -#include <linux/netlink.h> -#include <sys/socket.h> - #include <hardware/hardware.h> #include <hardware/hwcomposer.h> +#include <inttypes.h> +#include <linux/netlink.h> #include <log/log.h> +#include <sys/socket.h> +#include <utils/String8.h> #include <xf86drm.h> +#include "drmdevice.h" + namespace android { DrmEventListener::DrmEventListener(DrmDevice *drm) @@ -143,6 +145,43 @@ void DrmEventListener::UnRegisterPanelIdleHandler(DrmPanelIdleEventHandler *hand panel_idle_handler_ = NULL; } +int DrmEventListener::RegisterSysfsHandler(std::shared_ptr<DrmSysfsEventHandler> handler) { + if (!handler) + return -EINVAL; + if (handler->getFd() < 0) + return -EINVAL; + std::scoped_lock lock(mutex_); + if (sysfs_handlers_.find(handler->getFd()) != sysfs_handlers_.end()) { + ALOGE("%s: DrmSysfsEventHandler for fd:%d has been added to epoll", __func__, handler->getFd()); + return -EINVAL; + } + + struct epoll_event ev; + ev.events = EPOLLPRI; + ev.data.fd = handler->getFd(); + if (epoll_ctl(epoll_fd_.get(), EPOLL_CTL_ADD, handler->getFd(), &ev) < 0) { + ALOGE("%s: Failed to add fd into epoll: %s", __func__, strerror(errno)); + return -errno; + } + sysfs_handlers_.emplace(handler->getFd(), std::move(handler)); + return 0; +} + +int DrmEventListener::UnRegisterSysfsHandler(int sysfs_fd) { + std::scoped_lock lock(mutex_); + auto it = sysfs_handlers_.find(sysfs_fd); + if (it == sysfs_handlers_.end()) { + ALOGE("%s: DrmSysfsEventHandler for fd:%d not found", __func__, sysfs_fd); + return -EINVAL; + } + if (epoll_ctl(epoll_fd_.get(), EPOLL_CTL_DEL, sysfs_fd, nullptr) < 0) { + ALOGE("%s: Failed to remove fd from epoll: %s", __func__, strerror(errno)); + return -errno; + } + sysfs_handlers_.erase(it); + return 0; +} + bool DrmEventListener::IsDrmInTUI() { char buffer[1024]; int ret; @@ -235,7 +274,8 @@ void DrmEventListener::DRMEventHandler() { case EXYNOS_DRM_HISTOGRAM_EVENT: if (histogram_handler_) { histo = (struct exynos_drm_histogram_event *)e; - histogram_handler_->handleHistogramEvent((void *)&(histo->bins)); + histogram_handler_->handleHistogramEvent(histo->crtc_id, + (void *)&(histo->bins)); } break; case DRM_EVENT_FLIP_COMPLETE: @@ -266,6 +306,23 @@ void DrmEventListener::TUIEventHandler() { tui_handler_->handleTUIEvent(); } +void DrmEventListener::SysfsEventHandler(int fd) { + std::shared_ptr<DrmSysfsEventHandler> handler; + { + std::scoped_lock lock(mutex_); + // Copy the shared_ptr to avoid the handler object gets destroyed + // while it's handling the event without holding mutex_ + auto it = sysfs_handlers_.find(fd); + if (it != sysfs_handlers_.end()) + handler = it->second; + } + if (handler) { + handler->handleSysfsEvent(); + } else { + ALOGW("Unhandled sysfs event from fd:%d", fd); + } +} + void DrmEventListener::Routine() { struct epoll_event events[maxFds]; int nfds, n; @@ -279,11 +336,13 @@ void DrmEventListener::Routine() { if (events[n].data.fd == uevent_fd_.get()) { UEventHandler(); } else if (events[n].data.fd == drm_->fd()) { - DRMEventHandler(); + DRMEventHandler(); } } else if (events[n].events & EPOLLPRI) { if (tuievent_fd_.get() >= 0 && events[n].data.fd == tuievent_fd_.get()) { TUIEventHandler(); + } else { + SysfsEventHandler(events[n].data.fd); } } } diff --git a/libhwc2.1/libdrmresource/drm/vsyncworker.cpp b/libhwc2.1/libdrmresource/drm/vsyncworker.cpp index d2b4a02..bd55d47 100644 --- a/libhwc2.1/libdrmresource/drm/vsyncworker.cpp +++ b/libhwc2.1/libdrmresource/drm/vsyncworker.cpp @@ -36,7 +36,6 @@ using namespace std::chrono_literals; constexpr auto nsecsPerSec = std::chrono::nanoseconds(1s).count(); -constexpr auto hwVsyncPeriodTag = "HWVsyncPeriod"; namespace android { @@ -52,9 +51,12 @@ VSyncWorker::~VSyncWorker() { Exit(); } -int VSyncWorker::Init(DrmDevice *drm, int display) { +int VSyncWorker::Init(DrmDevice *drm, int display, const String8 &display_trace_name) { drm_ = drm; display_ = display; + display_trace_name_ = display_trace_name; + hw_vsync_period_tag_.appendFormat("HWVsyncPeriod for %s", display_trace_name.string()); + hw_vsync_enabled_tag_.appendFormat("HWCVsync for %s", display_trace_name.string()); return InitWorker(); } @@ -71,8 +73,8 @@ void VSyncWorker::VSyncControl(bool enabled) { last_timestamp_ = -1; Unlock(); - ATRACE_INT("HWCVsync", static_cast<int32_t>(enabled)); - ATRACE_INT64(hwVsyncPeriodTag, 0); + ATRACE_INT(hw_vsync_enabled_tag_.string(), static_cast<int32_t>(enabled)); + ATRACE_INT64(hw_vsync_period_tag_.string(), 0); Signal(); } @@ -211,8 +213,8 @@ void VSyncWorker::Routine() { if (last_timestamp_ >= 0) { int64_t period = timestamp - last_timestamp_; - ATRACE_INT64(hwVsyncPeriodTag, period); - ALOGV("HW vsync period %" PRId64 "ns", period); + ATRACE_INT64(hw_vsync_period_tag_.string(), period); + ALOGV("HW vsync period %" PRId64 "ns for %s", period, display_trace_name_.string()); } last_timestamp_ = timestamp; diff --git a/libhwc2.1/libdrmresource/include/drmconnector.h b/libhwc2.1/libdrmresource/include/drmconnector.h index cb6d1b2..df03661 100644 --- a/libhwc2.1/libdrmresource/include/drmconnector.h +++ b/libhwc2.1/libdrmresource/include/drmconnector.h @@ -81,6 +81,7 @@ class DrmConnector { const DrmProperty &lhbm_on() const; const DrmProperty &mipi_sync() const; const DrmProperty &panel_idle_support() const; + const DrmProperty &vrr_switch_duration() const; const std::vector<DrmProperty *> &properties() const { return properties_; @@ -138,6 +139,7 @@ class DrmConnector { DrmProperty lhbm_on_; DrmProperty mipi_sync_; DrmProperty panel_idle_support_; + DrmProperty vrr_switch_duration_; std::vector<DrmProperty *> properties_; std::vector<DrmEncoder *> possible_encoders_; diff --git a/libhwc2.1/libdrmresource/include/drmcrtc.h b/libhwc2.1/libdrmresource/include/drmcrtc.h index a4130d3..6bb73fd 100644 --- a/libhwc2.1/libdrmresource/include/drmcrtc.h +++ b/libhwc2.1/libdrmresource/include/drmcrtc.h @@ -70,6 +70,9 @@ class DrmCrtc { const DrmProperty &histogram_roi_property() const; const DrmProperty &histogram_weights_property() const; const DrmProperty &histogram_threshold_property() const; + const DrmProperty &histogram_position_property() const; + + const DrmProperty &rcd_plane_id_property() const; const std::vector<DrmProperty *> &properties() const { return properties_; @@ -110,6 +113,9 @@ class DrmCrtc { DrmProperty histogram_roi_property_; DrmProperty histogram_weights_property_; DrmProperty histogram_threshold_property_; + DrmProperty histogram_position_property_; + + DrmProperty rcd_plane_id_property_; std::vector<DrmProperty *> properties_; }; diff --git a/libhwc2.1/libdrmresource/include/drmeventlistener.h b/libhwc2.1/libdrmresource/include/drmeventlistener.h index bd2fec6..e85ca0a 100644 --- a/libhwc2.1/libdrmresource/include/drmeventlistener.h +++ b/libhwc2.1/libdrmresource/include/drmeventlistener.h @@ -17,11 +17,13 @@ #ifndef ANDROID_DRM_EVENT_LISTENER_H_ #define ANDROID_DRM_EVENT_LISTENER_H_ +#include <sys/epoll.h> + +#include <map> + #include "autofd.h" #include "worker.h" -#include <sys/epoll.h> - namespace android { class DrmDevice; @@ -41,7 +43,7 @@ public: DrmHistogramEventHandler() {} virtual ~DrmHistogramEventHandler() {} - virtual void handleHistogramEvent(void *) = 0; + virtual void handleHistogramEvent(uint32_t crtc_id, void *) = 0; }; class DrmTUIEventHandler { @@ -62,9 +64,19 @@ class DrmPanelIdleEventHandler { virtual void handleIdleEnterEvent(char const *event) = 0; }; +class DrmSysfsEventHandler { + public: + DrmSysfsEventHandler() {} + virtual ~DrmSysfsEventHandler() {} + + virtual void handleSysfsEvent() = 0; + virtual int getFd() = 0; +}; + class DrmEventListener : public Worker { - static constexpr const char kTUIStatusPath[] = "/sys/devices/platform/exynos-drm/tui_status"; - static const uint32_t maxFds = 3; + static constexpr const char kTUIStatusPath[] = "/sys/devices/platform/exynos-drm/tui_status"; + static const uint32_t maxFds = 4; + public: DrmEventListener(DrmDevice *drm); virtual ~DrmEventListener(); @@ -79,11 +91,13 @@ class DrmEventListener : public Worker { void UnRegisterTUIHandler(DrmTUIEventHandler *handler); void RegisterPanelIdleHandler(DrmPanelIdleEventHandler *handler); void UnRegisterPanelIdleHandler(DrmPanelIdleEventHandler *handler); + int RegisterSysfsHandler(std::shared_ptr<DrmSysfsEventHandler> handler); + int UnRegisterSysfsHandler(int sysfs_fd); bool IsDrmInTUI(); - static void FlipHandler(int fd, unsigned int sequence, unsigned int tv_sec, - unsigned int tv_usec, void *user_data); + static void FlipHandler(int fd, unsigned int sequence, unsigned int tv_sec, unsigned int tv_usec, + void *user_data); protected: virtual void Routine(); @@ -92,6 +106,7 @@ class DrmEventListener : public Worker { void UEventHandler(); void DRMEventHandler(); void TUIEventHandler(); + void SysfsEventHandler(int fd); UniqueFd epoll_fd_; UniqueFd uevent_fd_; @@ -102,7 +117,10 @@ class DrmEventListener : public Worker { std::unique_ptr<DrmHistogramEventHandler> histogram_handler_; std::unique_ptr<DrmTUIEventHandler> tui_handler_; std::unique_ptr<DrmPanelIdleEventHandler> panel_idle_handler_; + std::mutex mutex_; + std::map<int, std::shared_ptr<DrmSysfsEventHandler>> sysfs_handlers_; }; + } // namespace android #endif diff --git a/libhwc2.1/libdrmresource/include/vsyncworker.h b/libhwc2.1/libdrmresource/include/vsyncworker.h index bd69712..ce12eea 100644 --- a/libhwc2.1/libdrmresource/include/vsyncworker.h +++ b/libhwc2.1/libdrmresource/include/vsyncworker.h @@ -17,14 +17,15 @@ #ifndef ANDROID_EVENT_WORKER_H_ #define ANDROID_EVENT_WORKER_H_ -#include "drmdevice.h" -#include "worker.h" - +#include <hardware/hardware.h> +#include <hardware/hwcomposer.h> #include <stdint.h> +#include <utils/String8.h> + #include <map> -#include <hardware/hardware.h> -#include <hardware/hwcomposer.h> +#include "drmdevice.h" +#include "worker.h" namespace android { @@ -39,7 +40,7 @@ class VSyncWorker : public Worker { VSyncWorker(); ~VSyncWorker() override; - int Init(DrmDevice *drm, int display); + int Init(DrmDevice *drm, int display, const String8 &display_trace_name); void RegisterCallback(std::shared_ptr<VsyncCallback> callback); void VSyncControl(bool enabled); @@ -61,6 +62,9 @@ class VSyncWorker : public Worker { int display_; std::atomic_bool enabled_; int64_t last_timestamp_; + String8 hw_vsync_period_tag_; + String8 hw_vsync_enabled_tag_; + String8 display_trace_name_; }; } // namespace android diff --git a/libhwc2.1/libexternaldisplay/ExynosExternalDisplay.cpp b/libhwc2.1/libexternaldisplay/ExynosExternalDisplay.cpp index 39c2e79..ed99759 100644 --- a/libhwc2.1/libexternaldisplay/ExynosExternalDisplay.cpp +++ b/libhwc2.1/libexternaldisplay/ExynosExternalDisplay.cpp @@ -30,15 +30,11 @@ extern struct exynos_hwc_control exynosHWCControl; using namespace SOC_VERSION; -ExynosExternalDisplay::ExynosExternalDisplay(uint32_t index, ExynosDevice *device) - : ExynosDisplay(index, device) -{ +ExynosExternalDisplay::ExynosExternalDisplay(uint32_t index, ExynosDevice* device, + const std::string& displayName) + : ExynosDisplay(HWC_DISPLAY_EXTERNAL, index, device, displayName) { DISPLAY_LOGD(eDebugExternalDisplay, ""); - mType = HWC_DISPLAY_EXTERNAL; - mIndex = index; - mDisplayId = getDisplayId(mType, mIndex); - mDisplayControl.cursorSupport = true; mEnabled = false; @@ -102,7 +98,8 @@ void ExynosExternalDisplay::closeExternalDisplay() setVsyncEnabledInternal(HWC2_VSYNC_DISABLE); - if (mPowerModeState != (hwc2_power_mode_t)HWC_POWER_MODE_OFF) { + if (mPowerModeState.has_value() && + (*mPowerModeState != (hwc2_power_mode_t)HWC_POWER_MODE_OFF)) { if (mDisplayInterface->setPowerMode(HWC_POWER_MODE_OFF) < 0) { DISPLAY_LOGE("%s: set powermode ioctl failed errno : %d", __func__, errno); return; @@ -276,7 +273,8 @@ int32_t ExynosExternalDisplay::canSkipValidate() { return SKIP_ERR_DISP_NOT_CONNECTED; if ((mSkipStartFrame > (SKIP_EXTERNAL_FRAME - 1)) && (mEnabled == false) && - (mPowerModeState == (hwc2_power_mode_t)HWC_POWER_MODE_NORMAL)) + (mPowerModeState.has_value() && + (*mPowerModeState == (hwc2_power_mode_t)HWC_POWER_MODE_NORMAL))) return SKIP_ERR_DISP_NOT_POWER_ON; if (checkRotate() || (mIsSkipFrame) || @@ -309,7 +307,7 @@ int32_t ExynosExternalDisplay::presentDisplay( ret = HWC2_ERROR_NOT_VALIDATED; } mRenderingState = RENDERING_STATE_PRESENTED; - mDevice->onRefresh(); + mDevice->onRefresh(mDisplayId); return ret; } @@ -348,7 +346,7 @@ int32_t ExynosExternalDisplay::presentDisplay( */ setGeometryChanged(GEOMETRY_DISPLAY_FORCE_VALIDATE); - mDevice->onRefresh(); + mDevice->onRefresh(mDisplayId); return HWC2_ERROR_NONE; } @@ -544,7 +542,7 @@ void ExynosExternalDisplay::handleHotplugEvent() closeExternalDisplay(); } hotplug(); - mDevice->onRefresh(); + mDevice->onRefresh(mDisplayId); } } diff --git a/libhwc2.1/libexternaldisplay/ExynosExternalDisplay.h b/libhwc2.1/libexternaldisplay/ExynosExternalDisplay.h index 199ef4d..f0caabc 100644 --- a/libhwc2.1/libexternaldisplay/ExynosExternalDisplay.h +++ b/libhwc2.1/libexternaldisplay/ExynosExternalDisplay.h @@ -28,7 +28,7 @@ class ExynosExternalDisplay : public ExynosDisplay { hwc2_config_t mActiveConfigIndex; /* Methods */ - ExynosExternalDisplay(uint32_t index, ExynosDevice *device); + ExynosExternalDisplay(uint32_t index, ExynosDevice* device, const std::string& displayName); ~ExynosExternalDisplay(); virtual void init(); diff --git a/libhwc2.1/libhwcService/ExynosHWCService.cpp b/libhwc2.1/libhwcService/ExynosHWCService.cpp index 7974fee..fd8278b 100644 --- a/libhwc2.1/libhwcService/ExynosHWCService.cpp +++ b/libhwc2.1/libhwcService/ExynosHWCService.cpp @@ -27,12 +27,8 @@ namespace android { ANDROID_SINGLETON_STATIC_INSTANCE(ExynosHWCService); -ExynosHWCService::ExynosHWCService() : - mHWCService(NULL), - mHWCCtx(NULL), - bootFinishedCallback(NULL), - doPSRExit(NULL) -{ +ExynosHWCService::ExynosHWCService() + : mHWCService(NULL), mHWCCtx(NULL), bootFinishedCallback(NULL) { ALOGD_IF(HWC_SERVICE_DEBUG, "ExynosHWCService Constructor is called"); } @@ -252,7 +248,7 @@ void ExynosHWCService::enableMPP(uint32_t physicalType, uint32_t physicalIndex, __func__, physicalType, physicalIndex, logicalIndex, enable); ExynosResourceManager::enableMPP(physicalType, physicalIndex, logicalIndex, enable); mHWCCtx->device->setGeometryChanged(GEOMETRY_DEVICE_CONFIG_CHANGED); - mHWCCtx->device->onRefresh(); + mHWCCtx->device->onRefreshDisplays(); } void ExynosHWCService::setScaleDownRatio(uint32_t physicalType, @@ -262,7 +258,7 @@ void ExynosHWCService::setScaleDownRatio(uint32_t physicalType, __func__, physicalType, physicalIndex, logicalIndex, scaleDownRatio); ExynosResourceManager::setScaleDownRatio(physicalType, physicalIndex, logicalIndex, scaleDownRatio); mHWCCtx->device->setGeometryChanged(GEOMETRY_DEVICE_CONFIG_CHANGED); - mHWCCtx->device->onRefresh(); + mHWCCtx->device->onRefreshDisplays(); } void ExynosHWCService::setLbeCtrl(uint32_t display_id, uint32_t state, uint32_t lux) { @@ -322,6 +318,7 @@ int ExynosHWCService::setHWCCtl(uint32_t display, uint32_t ctrl, int32_t val) case HWC_CTL_ENABLE_EARLY_START_MPP: case HWC_CTL_DISPLAY_MODE: case HWC_CTL_DDI_RESOLUTION_CHANGE: + case HWC_CTL_DYNAMIC_RECOMP: case HWC_CTL_ENABLE_FENCE_TRACER: case HWC_CTL_SYS_FENCE_LOGGING: case HWC_CTL_DO_FENCE_FILE_DUMP: @@ -336,11 +333,10 @@ int ExynosHWCService::setHWCCtl(uint32_t display, uint32_t ctrl, int32_t val) return err; } -int ExynosHWCService::setDDIScaler(uint32_t width, uint32_t height) -{ +int ExynosHWCService::setDDIScaler(uint32_t display_id, uint32_t width, uint32_t height) { ALOGD_IF(HWC_SERVICE_DEBUG, "%s, width=%d, height=%d", __func__, width, height); if (mHWCCtx) { - ExynosDisplay *display = (ExynosDisplay*)mHWCCtx->device->getDisplay(getDisplayId(HWC_DISPLAY_PRIMARY, 0)); + ExynosDisplay *display = (ExynosDisplay *)mHWCCtx->device->getDisplay(display_id); if (display == NULL) return -EINVAL; @@ -353,25 +349,6 @@ int ExynosHWCService::setDDIScaler(uint32_t width, uint32_t height) } } -#if 0 -void ExynosHWCService::setPSRExitCallback(void (*callback)(exynos_hwc_composer_device_1_t *)) -{ - ALOGD_IF(HWC_SERVICE_DEBUG, "%s, callback %p", __func__, callback); - doPSRExit = callback; -} - -void ExynosHWCService::notifyPSRExit() -{ - ALOGD_IF(HWC_SERVICE_DEBUG, "%s, doPSRExit %p", __func__, doPSRExit); - if (doPSRExit != NULL) { - ALOGD_IF(HWC_SERVICE_DEBUG, "%s, line %d", __func__, __LINE__); - doPSRExit(mHWCCtx); - } - ALOGD_IF(HWC_SERVICE_DEBUG, "%s, line %d", __func__, __LINE__); -} - -#endif - int ExynosHWCService::createServiceLocked() { ALOGD_IF(HWC_SERVICE_DEBUG, "%s::", __func__); @@ -437,7 +414,7 @@ int32_t ExynosHWCService::setDisplayLhbm(int32_t display_id, uint32_t on) { auto display = mHWCCtx->device->getDisplay(display_id); if (display != nullptr) { - display->requestLhbm(!!on); + display->setLhbmState(!!on); return NO_ERROR; } @@ -466,7 +443,7 @@ int32_t ExynosHWCService::setRefreshRateThrottle(uint32_t display_id, int32_t de ->setRefreshRateThrottleNanos(std::chrono::duration_cast<std::chrono::nanoseconds>( std::chrono::milliseconds(delayMs)) .count(), - DispIdleTimerRequester::TEST); + VrrThrottleRequester::TEST); } return -EINVAL; @@ -482,7 +459,7 @@ int32_t ExynosHWCService::setDisplayRCDLayerEnabled(uint32_t displayIndex, bool auto ret = primaryDisplay->setDebugRCDLayerEnabled(enable); mHWCCtx->device->setGeometryChanged(GEOMETRY_DEVICE_CONFIG_CHANGED); - mHWCCtx->device->onRefresh(); + mHWCCtx->device->onRefresh(getDisplayId(HWC_DISPLAY_PRIMARY, displayIndex)); return ret; } @@ -502,4 +479,41 @@ int32_t ExynosHWCService::triggerDisplayIdleEnter(uint32_t displayIndex, return NO_ERROR; } +int32_t ExynosHWCService::setDisplayDbm(int32_t display_id, uint32_t on) { + if (on > 1) return -EINVAL; + + auto display = mHWCCtx->device->getDisplay(display_id); + + if (display == nullptr) return -EINVAL; + + ALOGD("ExynosHWCService::%s() display(%u) on=%d", __func__, display_id, on); + display->setDbmState(!!on); + mHWCCtx->device->onRefresh(display_id); + return NO_ERROR; +} + +int32_t ExynosHWCService::setDisplayMultiThreadedPresent(const int32_t& displayId, + const bool& enable) { + auto display = mHWCCtx->device->getDisplay(displayId); + + if (display == nullptr) return -EINVAL; + + display->mDisplayControl.multiThreadedPresent = enable; + ALOGD("ExynosHWCService::%s() display(%u) enable=%d", __func__, displayId, enable); + return NO_ERROR; +} + +int32_t ExynosHWCService::triggerRefreshRateIndicatorUpdate(uint32_t displayId, + uint32_t refreshRate) { + auto display = mHWCCtx->device->getDisplay(displayId); + + if (display == nullptr) return -EINVAL; + + ALOGD("ExynosHWCService::%s() displayID(%u) refreshRate(%u)", __func__, displayId, refreshRate); + if (display->mRefreshRateIndicatorHandler) { + display->mRefreshRateIndicatorHandler->updateRefreshRate(refreshRate); + } + return NO_ERROR; +} + } //namespace android diff --git a/libhwc2.1/libhwcService/ExynosHWCService.h b/libhwc2.1/libhwcService/ExynosHWCService.h index f4224fb..abb525f 100644 --- a/libhwc2.1/libhwcService/ExynosHWCService.h +++ b/libhwc2.1/libhwcService/ExynosHWCService.h @@ -65,12 +65,8 @@ public: virtual void getHWCFenceDebug(); virtual int setHWCCtl(uint32_t display, uint32_t ctrl, int32_t val); - virtual int setDDIScaler(uint32_t width, uint32_t height); + virtual int setDDIScaler(uint32_t display_id, uint32_t width, uint32_t height); virtual void setLbeCtrl(uint32_t display_id, uint32_t state, uint32_t lux) override; -#if 0 - void setPSRExitCallback(void (*callback)(exynos_hwc_composer_device_1_t *)); - virtual void notifyPSRExit(); -#endif virtual int32_t setDisplayDeviceMode(int32_t display_id, int32_t mode); virtual int32_t setPanelGammaTableSource(int32_t display_id, int32_t type, int32_t source); virtual int32_t setDisplayBrightness(int32_t display_id, float brightness); @@ -78,9 +74,16 @@ public: virtual int32_t setMinIdleRefreshRate(uint32_t display_id, int32_t fps); virtual int32_t setRefreshRateThrottle(uint32_t display_id, int32_t delayMs); + virtual int32_t setDisplayDbm(int32_t display_id, uint32_t on); + int32_t setDisplayRCDLayerEnabled(uint32_t displayIndex, bool enable) override; int32_t triggerDisplayIdleEnter(uint32_t displayIndex, uint32_t idleTeRefreshRate) override; + virtual int32_t setDisplayMultiThreadedPresent(const int32_t& display_id, + const bool& enable) override; + virtual int32_t triggerRefreshRateIndicatorUpdate(uint32_t displayId, + uint32_t refreshRate) override; + private: friend class Singleton<ExynosHWCService>; ExynosHWCService(); @@ -89,7 +92,6 @@ private: Mutex mLock; ExynosHWCCtx *mHWCCtx; void (*bootFinishedCallback)(ExynosHWCCtx *); - void (*doPSRExit)(ExynosHWCCtx *ctx); }; } diff --git a/libhwc2.1/libhwcService/IExynosHWC.cpp b/libhwc2.1/libhwcService/IExynosHWC.cpp index 181fdf2..f092696 100644 --- a/libhwc2.1/libhwcService/IExynosHWC.cpp +++ b/libhwc2.1/libhwcService/IExynosHWC.cpp @@ -50,9 +50,6 @@ enum { SET_DDISCALER, GET_EXTERNAL_HDR_CAPA, SET_SCALE_DOWN_RATIO, -#if 0 - NOTIFY_PSR_EXIT, -#endif SET_HWC_DEBUG = 105, GET_HWC_DEBUG = 106, SET_HWC_FENCE_DEBUG = 107, @@ -66,6 +63,9 @@ enum { SET_REFRESH_RATE_THROTTLE = 1006, SET_DISPLAY_RCDLAYER_ENABLED = 1007, TRIGGER_DISPLAY_IDLE_ENTER = 1008, + SET_DISPLAY_DBM = 1009, + SET_DISPLAY_MULTI_THREADED_PRESENT = 1010, + TRIGGER_REFRESH_RATE_INDICATOR_UPDATE = 1011, }; class BpExynosHWCService : public BpInterface<IExynosHWCService> { @@ -364,11 +364,12 @@ public: return result; }; - virtual int setDDIScaler(uint32_t width, uint32_t height) { + virtual int setDDIScaler(uint32_t displayId, uint32_t width, uint32_t height) { Parcel data, reply; data.writeInterfaceToken(IExynosHWCService::getInterfaceDescriptor()); - data.writeInt32(width); - data.writeInt32(height); + data.writeUint32(displayId); + data.writeUint32(width); + data.writeUint32(height); int result = remote()->transact(SET_DDISCALER, data, &reply); if (result == NO_ERROR) result = reply.readInt32(); @@ -377,15 +378,6 @@ public: return result; } - /* - virtual void notifyPSRExit() - { - Parcel data, reply; - data.writeInterfaceToken(IExynosHWCService::getInterfaceDescriptor()); - remote()->transact(NOTIFY_PSR_EXIT, data, &reply); - } - */ - int32_t setDisplayDeviceMode(int32_t display_id, int32_t mode) { ALOGD("null func: %s(%d %d)", __func__, display_id, mode); @@ -455,10 +447,44 @@ public: data.writeUint32(displayIndex); data.writeUint32(idleTeRefreshRate); - auto result = remote()->transact(SET_DISPLAY_RCDLAYER_ENABLED, data, &reply); + auto result = remote()->transact(TRIGGER_DISPLAY_IDLE_ENTER, data, &reply); ALOGE_IF(result != NO_ERROR, "TRIGGER_DISPLAY_IDLE_ENTER transact error(%d)", result); return result; } + + virtual int32_t setDisplayDbm(int32_t display_id, uint32_t on) { + Parcel data, reply; + data.writeInterfaceToken(IExynosHWCService::getInterfaceDescriptor()); + data.writeInt32(display_id); + data.writeInt32(on); + int result = remote()->transact(SET_DISPLAY_DBM, data, &reply); + if (result) ALOGE("SET_DISPLAY_DBM transact error(%d)", result); + return result; + } + + virtual int32_t setDisplayMultiThreadedPresent(const int32_t& displayId, + const bool& enable) { + Parcel data, reply; + data.writeInterfaceToken(IExynosHWCService::getInterfaceDescriptor()); + data.writeInt32(displayId); + data.writeBool(enable); + int result = remote()->transact(SET_DISPLAY_MULTI_THREADED_PRESENT, data, &reply); + if (result) ALOGE("SET_DISPLAY_MULTI_THREADED_PRESENT transact error(%d)", result); + return result; + } + + virtual int32_t triggerRefreshRateIndicatorUpdate(uint32_t displayId, + uint32_t refreshRate) override { + Parcel data, reply; + data.writeInterfaceToken(IExynosHWCService::getInterfaceDescriptor()); + data.writeUint32(displayId); + data.writeUint32(refreshRate); + + auto result = remote()->transact(TRIGGER_REFRESH_RATE_INDICATOR_UPDATE, data, &reply); + ALOGE_IF(result != NO_ERROR, "TRIGGER_REFRESH_RATE_INDICATOR_UPDATE transact error(%d)", + result); + return result; + } }; IMPLEMENT_META_INTERFACE(ExynosHWCService, "android.hal.ExynosHWCService"); @@ -624,50 +650,13 @@ status_t BnExynosHWCService::onTransact( } break; case SET_DDISCALER: { CHECK_INTERFACE(IExynosHWCService, data, reply); - uint32_t width = data.readInt32(); - uint32_t height = data.readInt32(); - int error = setDDIScaler(width, height); + uint32_t display_id = data.readUint32(); + uint32_t width = data.readUint32(); + uint32_t height = data.readUint32(); + int error = setDDIScaler(display_id, width, height); reply->writeInt32(error); return NO_ERROR; } break; - -#if 0 - case SET_HWC_CTL_MAX_OVLY_CNT: { - CHECK_INTERFACE(IExynosHWCService, data, reply); - int val = data.readInt32(); - setHWCCtl(SET_HWC_CTL_MAX_OVLY_CNT, val); - return NO_ERROR; - } break; - case SET_HWC_CTL_VIDEO_OVLY_CNT: { - CHECK_INTERFACE(IExynosHWCService, data, reply); - int val = data.readInt32(); - setHWCCtl(SET_HWC_CTL_VIDEO_OVLY_CNT, val); - return NO_ERROR; - } break; - case SET_HWC_CTL_DYNAMIC_RECOMP: { - CHECK_INTERFACE(IExynosHWCService, data, reply); - int val = data.readInt32(); - setHWCCtl(SET_HWC_CTL_DYNAMIC_RECOMP, val); - return NO_ERROR; - } break; - case SET_HWC_CTL_SKIP_STATIC: { - CHECK_INTERFACE(IExynosHWCService, data, reply); - int val = data.readInt32(); - setHWCCtl(SET_HWC_CTL_SKIP_STATIC, val); - return NO_ERROR; - } break; - case SET_HWC_CTL_SECURE_DMA: { - CHECK_INTERFACE(IExynosHWCService, data, reply); - int val = data.readInt32(); - setHWCCtl(SET_HWC_CTL_SECURE_DMA, val); - return NO_ERROR; - } break; - case NOTIFY_PSR_EXIT: { - CHECK_INTERFACE(IExynosHWCService, data, reply); - notifyPSRExit(); - return NO_ERROR; - } -#endif case SET_DISPLAY_DEVICE_MODE: { CHECK_INTERFACE(IExynosHWCService, data, reply); int32_t display_id = data.readInt32(); @@ -741,6 +730,31 @@ status_t BnExynosHWCService::onTransact( return triggerDisplayIdleEnter(displayIndex, idleTeRefreshRate); } break; + case SET_DISPLAY_DBM: { + CHECK_INTERFACE(IExynosHWCService, data, reply); + int32_t display_id = data.readInt32(); + uint32_t on = data.readInt32(); + int32_t error = setDisplayDbm(display_id, on); + reply->writeInt32(error); + return NO_ERROR; + } break; + + case SET_DISPLAY_MULTI_THREADED_PRESENT: { + CHECK_INTERFACE(IExynosHWCService, data, reply); + int32_t displayId = data.readInt32(); + bool enable = data.readBool(); + int32_t error = setDisplayMultiThreadedPresent(displayId, enable); + reply->writeInt32(error); + return NO_ERROR; + } break; + + case TRIGGER_REFRESH_RATE_INDICATOR_UPDATE: { + CHECK_INTERFACE(IExynosHWCService, data, reply); + uint32_t displayId = data.readUint32(); + uint32_t refreshRate = data.readUint32(); + return triggerRefreshRateIndicatorUpdate(displayId, refreshRate); + } break; + default: return BBinder::onTransact(code, data, reply, flags); } diff --git a/libhwc2.1/libhwcService/IExynosHWC.h b/libhwc2.1/libhwcService/IExynosHWC.h index debf6fb..bf51c85 100644 --- a/libhwc2.1/libhwcService/IExynosHWC.h +++ b/libhwc2.1/libhwcService/IExynosHWC.h @@ -62,20 +62,21 @@ public: virtual void getHWCFenceDebug() = 0; virtual int setHWCCtl(uint32_t display, uint32_t ctrl, int32_t val) = 0; - virtual int setDDIScaler(uint32_t width, uint32_t height) = 0; + virtual int setDDIScaler(uint32_t display_id, uint32_t width, uint32_t height) = 0; virtual int32_t setDisplayDeviceMode(int32_t display_id, int32_t mode) = 0; virtual int32_t setPanelGammaTableSource(int32_t display_id, int32_t type, int32_t source) = 0; virtual void setLbeCtrl(uint32_t display_id, uint32_t state, uint32_t lux) = 0; - /* - virtual void notifyPSRExit() = 0; - */ virtual int32_t setDisplayBrightness(int32_t display_id, float brightness) = 0; virtual int32_t setDisplayLhbm(int32_t display_id, uint32_t on) = 0; virtual int32_t setMinIdleRefreshRate(uint32_t display_id, int32_t refresh_rate) = 0; virtual int32_t setRefreshRateThrottle(uint32_t display_id, int32_t throttle) = 0; virtual int32_t setDisplayRCDLayerEnabled(uint32_t displayIndex, bool enable) = 0; virtual int32_t triggerDisplayIdleEnter(uint32_t displayIndex, uint32_t idleTeRefreshRate) = 0; + virtual int32_t setDisplayDbm(int32_t display_id, uint32_t on) = 0; + virtual int32_t setDisplayMultiThreadedPresent(const int32_t& displayId, + const bool& enable) = 0; + virtual int32_t triggerRefreshRateIndicatorUpdate(uint32_t displayId, uint32_t refreshRate) = 0; }; /* Native Interface */ diff --git a/libhwc2.1/libhwchelper/ExynosHWCHelper.cpp b/libhwc2.1/libhwchelper/ExynosHWCHelper.cpp index 60593c8..56b3b83 100644 --- a/libhwc2.1/libhwchelper/ExynosHWCHelper.cpp +++ b/libhwc2.1/libhwchelper/ExynosHWCHelper.cpp @@ -36,6 +36,7 @@ using vendor::graphics::BufferUsage; using vendor::graphics::VendorGraphicBufferUsage; using vendor::graphics::VendorGraphicBufferMeta; +using namespace SOC_VERSION; #define AFBC_MAGIC 0xafbc @@ -271,6 +272,30 @@ bool isFormatP010(int format) return false; } +bool isFormat10Bit(int format) { + for (unsigned int i = 0; i < FORMAT_MAX_CNT; i++) { + if (exynos_format_desc[i].halFormat == format) { + if ((exynos_format_desc[i].type & BIT_MASK) == BIT10) + return true; + else + return false; + } + } + return false; +} + +bool isFormat8Bit(int format) { + for (unsigned int i = 0; i < FORMAT_MAX_CNT; i++) { + if (exynos_format_desc[i].halFormat == format) { + if ((exynos_format_desc[i].type & BIT_MASK) == BIT8) + return true; + else + return false; + } + } + return false; +} + bool isFormatYCrCb(int format) { return format == HAL_PIXEL_FORMAT_EXYNOS_YV12_M; @@ -647,11 +672,13 @@ uint32_t getExynosBufferYLength(uint32_t width, uint32_t height, int format) HDEBUGLOGD(eDebugMPP, "size(Y) : %d", P010_Y_SIZE(width, height)); return P010_Y_SIZE(width, height); case HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SPN: - return YUV420N_Y_SIZE(width, height); + return NV12N_Y_SIZE(width, height); + case HAL_PIXEL_FORMAT_EXYNOS_YCbCr_P010_SPN: + return 2 * __ALIGN_UP(width, 64) * __ALIGN_UP(height, 16); case HAL_PIXEL_FORMAT_GOOGLE_NV12_SP_10B: - return 2 * __ALIGN_UP(width, 64) * __ALIGN_UP(height, 8); + return 2 * __ALIGN_UP(width, 64) * __ALIGN_UP(height, 16); case HAL_PIXEL_FORMAT_GOOGLE_NV12_SP: - return __ALIGN_UP(width, 64) * __ALIGN_UP(height, 8); + return __ALIGN_UP(width, 64) * __ALIGN_UP(height, 16); case HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SP_M_SBWC: case HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SP_M_SBWC_L50: case HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SP_M_SBWC_L75: @@ -672,6 +699,8 @@ uint32_t getExynosBufferYLength(uint32_t width, uint32_t height, int format) case HAL_PIXEL_FORMAT_EXYNOS_YCrCb_420_SP_M_10B_SBWC: return SBWC_10B_Y_SIZE(width, height) + SBWC_10B_Y_HEADER_SIZE(width, height); + case MALI_GRALLOC_FORMAT_INTERNAL_NV21: + return __ALIGN_UP(width, 64) * __ALIGN_UP(height, 2); } return NV12M_Y_SIZE(width, height) + ((width % 128) == 0 ? 0 : 256); @@ -696,10 +725,12 @@ uint32_t getExynosBufferCbCrLength(uint32_t width, uint32_t height, int format) case HAL_PIXEL_FORMAT_YCBCR_P010: HDEBUGLOGD(eDebugMPP, "size(CbCr) : %d", P010_CBCR_SIZE(width, height)); return P010_CBCR_SIZE(width, height); + case HAL_PIXEL_FORMAT_EXYNOS_YCbCr_P010_SPN: + return __ALIGN_UP(width, 64) * __ALIGN_UP(height, 16); case HAL_PIXEL_FORMAT_GOOGLE_NV12_SP_10B: - return __ALIGN_UP(width, 64) * __ALIGN_UP(height, 8); + return __ALIGN_UP(width, 64) * __ALIGN_UP(height, 16); case HAL_PIXEL_FORMAT_GOOGLE_NV12_SP: - return __ALIGN_UP(width, 64) * __ALIGN_UP(height, 8) / 2; + return __ALIGN_UP(width, 64) * __ALIGN_UP(height, 16) / 2; case HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SP_M_SBWC: case HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SP_M_SBWC_L50: case HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SP_M_SBWC_L75: @@ -825,6 +856,8 @@ void setFenceInfo(uint32_t fd, ExynosDisplay* display, HwcFdebugFenceType type, if (!fence_valid(fd) || display == NULL) return; ExynosDevice* device = display->mDevice; + + std::scoped_lock lock(device->mFenceMutex); HwcFenceInfo& info = device->mFenceInfos[fd]; info.displayId = display->mDisplayId; @@ -991,10 +1024,10 @@ bool validateFencePerFrame(ExynosDisplay* display) { String8 getMPPStr(int typeId) { if (typeId < MPP_DPP_NUM){ - int cnt = sizeof(AVAILABLE_OTF_MPP_UNITS)/sizeof(exynos_mpp_t); + int cnt = sizeof(available_otf_mpp_units)/sizeof(exynos_mpp_t); for (int i = 0; i < cnt; i++){ - if (AVAILABLE_OTF_MPP_UNITS[i].physicalType == typeId) - return String8(AVAILABLE_OTF_MPP_UNITS[i].name); + if (available_otf_mpp_units[i].physicalType == typeId) + return String8(available_otf_mpp_units[i].name); } } else { int cnt = sizeof(AVAILABLE_M2M_MPP_UNITS)/sizeof(exynos_mpp_t); @@ -1102,10 +1135,6 @@ int32_t writeIntToFile(const char* file, uint32_t value) { return 0; } -uint32_t getDisplayId(int32_t displayType, int32_t displayIndex) { - return (displayType << DISPLAYID_MASK_LEN) | displayIndex; -} - int32_t load_png_image(const char* filepath, buffer_handle_t buffer) { png_structp png_ptr; png_infop info_ptr; @@ -1159,8 +1188,9 @@ int32_t load_png_image(const char* filepath, buffer_handle_t buffer) { return -EINVAL; } - uint32_t bufferHandleSize = gmeta.stride * gmeta.vstride * formatToBpp(gmeta.format) / 8; - if (bufferHandleSize > gmeta.size) { + size_t bufferHandleSize = gmeta.stride * gmeta.vstride * formatToBpp(gmeta.format) / 8; + size_t png_size = png_get_rowbytes(png_ptr, info_ptr) * height; + if (bufferHandleSize > gmeta.size || (bufferHandleSize < png_size)) { fclose(fp); png_destroy_read_struct(&png_ptr, &info_ptr, NULL); return -EINVAL; diff --git a/libhwc2.1/libhwchelper/ExynosHWCHelper.h b/libhwc2.1/libhwchelper/ExynosHWCHelper.h index 6fb9ea5..87b6163 100644 --- a/libhwc2.1/libhwchelper/ExynosHWCHelper.h +++ b/libhwc2.1/libhwchelper/ExynosHWCHelper.h @@ -82,22 +82,35 @@ enum { }; typedef enum format_type { - TYPE_UNDEF = 0, + TYPE_UNDEF = 0, /* format */ - FORMAT_SHIFT = 0, - FORMAT_MASK = 0x00000fff, - RGB = 0x00000001, - YUV420 = 0x00000002, - YUV422 = 0x00000004, - P010 = 0x00000008, + FORMAT_SHIFT = 0, + FORMAT_MASK = 0x00000fff, + + FORMAT_RGB_MASK = 0x0000000f, + RGB = 0x00000001, + + FORMAT_YUV_MASK = 0x000000f0, + YUV420 = 0x00000010, + YUV422 = 0x00000020, + P010 = 0x00000030, + + FORMAT_SBWC_MASK = 0x00000f00, + SBWC_LOSSLESS = 0x00000100, + SBWC_LOSSY_40 = 0x00000200, + SBWC_LOSSY_50 = 0x00000300, + SBWC_LOSSY_60 = 0x00000400, + SBWC_LOSSY_75 = 0x00000500, + SBWC_LOSSY_80 = 0x00000600, /* bit */ - BIT_SHIFT = 12, - BIT_MASK = 0x000ff000, - BIT8 = 0x00001000, - BIT10 = 0x00002000, - BIT8_2 = 0x00004000, + BIT_SHIFT = 16, + BIT_MASK = 0x000f0000, + BIT8 = 0x00010000, + BIT10 = 0x00020000, + BIT8_2 = 0x00030000, + BIT16 = 0x00040000, /* compression */ /* @@ -105,12 +118,12 @@ typedef enum format_type { * descriptions of format (ex: drmFormat, bufferNum, bpp...) * in format_description */ - COMP_SHIFT = 20, - COMP_MASK = 0x0ff00000, - COMP_ANY = 0x08000000, /* the highest bit */ - AFBC = 0x00100000, - SBWC = 0x00200000, - SBWC_LOSSY = 0x00400000, + COMP_SHIFT = 20, + COMP_MASK = 0x0ff00000, + COMP_ANY = 0x08000000, /* the highest bit */ + AFBC = 0x00100000, + SBWC = 0x00200000, + SBWC_LOSSY = 0x00400000, } format_type_t; @@ -190,6 +203,8 @@ const format_description_t exynos_format_desc[] = { 2, 2, 24, YUV420|BIT10|P010, false, String8("EXYNOS_YCbCr_P010_M"), 0}, {HAL_PIXEL_FORMAT_YCBCR_P010, DECON_PIXEL_FORMAT_NV12_P010, DRM_FORMAT_P010, 2, 1, 24, YUV420|BIT10|P010, false, String8("EXYNOS_YCbCr_P010"), 0}, + {HAL_PIXEL_FORMAT_EXYNOS_YCbCr_P010_SPN, DECON_PIXEL_FORMAT_NV12_P010, DRM_FORMAT_P010, + 2, 1, 24, YUV420|BIT10|P010, false, String8("EXYNOS_YCbCr_P010_SPN"), 0}, {HAL_PIXEL_FORMAT_GOOGLE_NV12_SP, DECON_PIXEL_FORMAT_MAX, DRM_FORMAT_NV12, 2, 1, 12, YUV420|BIT8, false, String8("GOOGLE_YCbCr_420_SP"), 0}, @@ -199,6 +214,8 @@ const format_description_t exynos_format_desc[] = { 1, 1, 12, YUV420|BIT8|AFBC, false, String8("MALI_GRALLOC_FORMAT_INTERNAL_YUV420_8BIT_I"), 0}, {MALI_GRALLOC_FORMAT_INTERNAL_YUV420_10BIT_I, DECON_PIXEL_FORMAT_MAX, DRM_FORMAT_YUV420_10BIT, 1, 1, 15, YUV420|BIT10|AFBC, false, String8("MALI_GRALLOC_FORMAT_INTERNAL_YUV420_10BIT_I"), 0}, + {MALI_GRALLOC_FORMAT_INTERNAL_NV21, DECON_PIXEL_FORMAT_NV21, DRM_FORMAT_NV21, + 2, 1, 12, YUV420|BIT8, false, String8("MALI_GRALLOC_FORMAT_INTERNAL_NV21"), 0}, /* YUV 422 */ {HAL_PIXEL_FORMAT_EXYNOS_CbYCrY_422_I, DECON_PIXEL_FORMAT_MAX, DRM_FORMAT_UNDEFINED, @@ -426,6 +443,8 @@ bool isFormat10BitYUV420(int format); bool isFormatLossy(int format); bool isFormatSBWC(int format); bool isFormatP010(int format); +bool isFormat10Bit(int format); +bool isFormat8Bit(int format); bool formatHasAlphaChannel(int format); unsigned int isNarrowRgb(int format, android_dataspace data_space); bool isAFBCCompressed(const buffer_handle_t handle); @@ -564,7 +583,10 @@ private: void writeFileNode(FILE *fd, int value); int32_t writeIntToFile(const char *file, uint32_t value); -uint32_t getDisplayId(int32_t displayType, int32_t displayIndex = 0); +constexpr uint32_t getDisplayId(int32_t displayType, int32_t displayIndex) { + return (displayType << DISPLAYID_MASK_LEN) | displayIndex; +} + int32_t load_png_image(const char *filepath, buffer_handle_t buffer); int readLineFromFile(const std::string &filename, std::string &out, char delim); diff --git a/libhwc2.1/libmaindisplay/ExynosPrimaryDisplay.cpp b/libhwc2.1/libmaindisplay/ExynosPrimaryDisplay.cpp index 099ad73..d24d1f9 100644 --- a/libhwc2.1/libmaindisplay/ExynosPrimaryDisplay.cpp +++ b/libhwc2.1/libmaindisplay/ExynosPrimaryDisplay.cpp @@ -38,15 +38,20 @@ extern struct exynos_hwc_control exynosHWCControl; using namespace SOC_VERSION; constexpr auto nsecsPerSec = std::chrono::nanoseconds(1s).count(); -constexpr auto nsecsPerMs = std::chrono::nanoseconds(1ms).count(); static const std::map<const DisplayType, const std::string> panelSysfsPath = {{DisplayType::DISPLAY_PRIMARY, "/sys/devices/platform/exynos-drm/primary-panel/"}, {DisplayType::DISPLAY_SECONDARY, "/sys/devices/platform/exynos-drm/secondary-panel/"}}; -static constexpr const char* PROPERTY_BOOT_MODE = "persist.vendor.display.primary.boot_config"; -static constexpr const char *PROPERTY_DEFAULT_BOOT_MODE = - "vendor.display.primary.default_boot_config"; +static String8 getPropertyBootModeStr(const int32_t dispId) { + String8 str; + if (dispId == 0) { + str.appendFormat("persist.vendor.display.primary.boot_config"); + } else { + str.appendFormat("persist.vendor.display.%d.primary.boot_config", dispId); + } + return str; +} static std::string loadPanelGammaCalibration(const std::string &file) { std::ifstream ifs(file); @@ -76,8 +81,9 @@ static std::string loadPanelGammaCalibration(const std::string &file) { return gamma; } -ExynosPrimaryDisplay::ExynosPrimaryDisplay(uint32_t index, ExynosDevice *device) - : ExynosDisplay(index, device), +ExynosPrimaryDisplay::ExynosPrimaryDisplay(uint32_t index, ExynosDevice *device, + const std::string &displayName) + : ExynosDisplay(HWC_DISPLAY_PRIMARY, index, device, displayName), mMinIdleRefreshRate(0), mRefreshRateDelayNanos(0), mLastRefreshRateAppliedNanos(0), @@ -88,12 +94,17 @@ ExynosPrimaryDisplay::ExynosPrimaryDisplay(uint32_t index, ExynosDevice *device) mNumMaxPriorityAllowed = 5; /* Initialization */ - mType = HWC_DISPLAY_PRIMARY; - mIndex = index; - mDisplayId = getDisplayId(mType, mIndex); mFramesToReachLhbmPeakBrightness = property_get_int32("vendor.primarydisplay.lhbm.frames_to_reach_peak_brightness", 3); + // Allow to enable dynamic recomposition after every power on + // since it will always be disabled for every power off + // TODO(b/268474771): to enable DR by default if video mode panel is detected + if (property_get_int32("vendor.display.dynamic_recomposition", 0) & (1 << index)) { + mDRDefault = true; + mDREnable = true; + } + // Prepare multi resolution // Will be exynosHWCControl.multiResoultion mResolutionInfo.nNum = 1; @@ -113,12 +124,20 @@ ExynosPrimaryDisplay::ExynosPrimaryDisplay(uint32_t index, ExynosDevice *device) mResolutionInfo.nDSCXSliceSize[2] = 720; mResolutionInfo.nPanelType[2] = PANEL_LEGACY; - mEarlyWakeupDispFd = fopen(EARLY_WAKUP_NODE_0_BASE, "w"); + char value[PROPERTY_VALUE_MAX]; + const char *earlyWakeupNodeBase = early_wakeup_node_0_base; + if (getDisplayTypeFromIndex(mIndex) == DisplayType::DISPLAY_SECONDARY && + property_get("vendor.display.secondary_early_wakeup_node", value, "") > 0) { + earlyWakeupNodeBase = value; + } + mEarlyWakeupDispFd = fopen(earlyWakeupNodeBase, "w"); if (mEarlyWakeupDispFd == nullptr) - ALOGE("open %s failed! %s", EARLY_WAKUP_NODE_0_BASE, strerror(errno)); + ALOGE("open %s failed! %s", earlyWakeupNodeBase, strerror(errno)); mBrightnessController = std::make_unique<BrightnessController>( - mIndex, [this]() { mDevice->onRefresh(); }, + mIndex, [this]() { mDevice->onRefresh(mDisplayId); }, [this]() { updatePresentColorConversionInfo(); }); + + mDisplayControl.multiThreadedPresent = true; } ExynosPrimaryDisplay::~ExynosPrimaryDisplay() @@ -159,9 +178,10 @@ int ExynosPrimaryDisplay::getDDIScalerMode(int width, int height) { } int32_t ExynosPrimaryDisplay::doDisplayConfigInternal(hwc2_config_t config) { - if (mPowerModeState != HWC2_POWER_MODE_ON) { - mPendActiveConfig = config; - mConfigRequestState = hwc_request_state_t::SET_CONFIG_STATE_NONE; + if (!mPowerModeState.has_value() || (*mPowerModeState != HWC2_POWER_MODE_ON) || + !isConfigSettingEnabled()) { + mPendingConfig = config; + mConfigRequestState = hwc_request_state_t::SET_CONFIG_STATE_DONE; DISPLAY_LOGI("%s:: Pending desired Config: %d", __func__, config); return NO_ERROR; } @@ -169,8 +189,8 @@ int32_t ExynosPrimaryDisplay::doDisplayConfigInternal(hwc2_config_t config) { } int32_t ExynosPrimaryDisplay::getActiveConfigInternal(hwc2_config_t *outConfig) { - if (outConfig && mPendActiveConfig != UINT_MAX) { - *outConfig = mPendActiveConfig; + if (outConfig && mPendingConfig != UINT_MAX) { + *outConfig = mPendingConfig; return HWC2_ERROR_NONE; } return ExynosDisplay::getActiveConfigInternal(outConfig); @@ -184,19 +204,21 @@ int32_t ExynosPrimaryDisplay::setActiveConfigInternal(hwc2_config_t config, bool ALOGI("%s:: Same display config is set", __func__); return HWC2_ERROR_NONE; } - if (mPowerModeState != HWC2_POWER_MODE_ON) { - mPendActiveConfig = config; + if (!mPowerModeState.has_value() || (*mPowerModeState != HWC2_POWER_MODE_ON) || + !isConfigSettingEnabled()) { + mPendingConfig = config; return HWC2_ERROR_NONE; } return ExynosDisplay::setActiveConfigInternal(config, force); } int32_t ExynosPrimaryDisplay::applyPendingConfig() { - hwc2_config_t config; + if (!isConfigSettingEnabled()) return HWC2_ERROR_NONE; - if (mPendActiveConfig != UINT_MAX) { - config = mPendActiveConfig; - mPendActiveConfig = UINT_MAX; + hwc2_config_t config; + if (mPendingConfig != UINT_MAX) { + config = mPendingConfig; + mPendingConfig = UINT_MAX; } else { getActiveConfigInternal(&config); } @@ -226,22 +248,21 @@ int32_t ExynosPrimaryDisplay::setBootDisplayConfig(int32_t config) { ALOGD("%s: mode=%s (%d) vsyncPeriod=%d", __func__, modeStr, config, mode.vsyncPeriod); - ret = property_set(PROPERTY_BOOT_MODE, modeStr); + ret = property_set(getPropertyBootModeStr(mDisplayId).string(), modeStr); return !ret ? HWC2_ERROR_NONE : HWC2_ERROR_BAD_CONFIG; } int32_t ExynosPrimaryDisplay::clearBootDisplayConfig() { - auto ret = property_set(PROPERTY_BOOT_MODE, nullptr); + auto ret = property_set(getPropertyBootModeStr(mDisplayId).string(), nullptr); ALOGD("%s: clearing boot mode", __func__); return !ret ? HWC2_ERROR_NONE : HWC2_ERROR_BAD_CONFIG; } int32_t ExynosPrimaryDisplay::getPreferredDisplayConfigInternal(int32_t *outConfig) { - char modeStr[PROPERTY_VALUE_MAX], defaultModeStr[PROPERTY_VALUE_MAX]; - property_get(PROPERTY_DEFAULT_BOOT_MODE, defaultModeStr, ""); - auto ret = property_get(PROPERTY_BOOT_MODE, modeStr, defaultModeStr); + char modeStr[PROPERTY_VALUE_MAX]; + auto ret = property_get(getPropertyBootModeStr(mDisplayId).string(), modeStr, ""); if (ret <= 0) { return mDisplayInterface->getDefaultModeId(outConfig); @@ -256,27 +277,22 @@ int32_t ExynosPrimaryDisplay::getPreferredDisplayConfigInternal(int32_t *outConf return HWC2_ERROR_BAD_CONFIG; } - const auto vsyncPeriod = nsecsPerSec / fps; - - for (auto const& [config, mode] : mDisplayConfigs) { - long delta = abs(vsyncPeriod - mode.vsyncPeriod); - if ((width == mode.width) && (height == mode.height) && - (delta < nsecsPerMs)) { - ALOGD("%s: found preferred display config for mode: %s=%d", - __func__, modeStr, config); - *outConfig = config; - return HWC2_ERROR_NONE; - } - } - return HWC2_ERROR_BAD_CONFIG; + return lookupDisplayConfigs(width, height, fps, outConfig); } int32_t ExynosPrimaryDisplay::setPowerOn() { ATRACE_CALL(); updateAppliedActiveConfig(0, 0); - int ret = applyPendingConfig(); + int ret = NO_ERROR; + if (mDisplayId != 0 || !mFirstPowerOn) { + if (mDevice->hasOtherDisplayOn(this)) { + // TODO: This is useful for cmd mode, and b/282094671 tries to handles video mode + mDisplayInterface->triggerClearDisplayPlanes(); + } + ret = applyPendingConfig(); + } - if (mPowerModeState == HWC2_POWER_MODE_OFF) { + if (!mPowerModeState.has_value() || (*mPowerModeState == HWC2_POWER_MODE_OFF)) { // check the dynamic recomposition thread by following display mDevice->checkDynamicRecompositionThread(); if (ret) { @@ -285,7 +301,14 @@ int32_t ExynosPrimaryDisplay::setPowerOn() { setGeometryChanged(GEOMETRY_DISPLAY_POWER_ON); } - mPowerModeState = HWC2_POWER_MODE_ON; + { + std::lock_guard<std::mutex> lock(mPowerModeMutex); + mPowerModeState = HWC2_POWER_MODE_ON; + if (mNotifyPowerOn) { + mPowerOnCondition.notify_one(); + mNotifyPowerOn = false; + } + } if (mFirstPowerOn) { firstPowerOn(); @@ -303,7 +326,11 @@ int32_t ExynosPrimaryDisplay::setPowerOff() { mDevice->checkDynamicRecompositionThread(); mDisplayInterface->setPowerMode(HWC2_POWER_MODE_OFF); - mPowerModeState = HWC2_POWER_MODE_OFF; + + { + std::lock_guard<std::mutex> lock(mPowerModeMutex); + mPowerModeState = HWC2_POWER_MODE_OFF; + } /* It should be called from validate() when the screen is on */ mSkipFrame = true; @@ -326,14 +353,23 @@ int32_t ExynosPrimaryDisplay::setPowerDoze(hwc2_power_mode_t mode) { return HWC2_ERROR_UNSUPPORTED; } - if ((mPowerModeState == HWC2_POWER_MODE_OFF) || (mPowerModeState == HWC2_POWER_MODE_ON)) { + if (mPowerModeState.has_value() && + ((*mPowerModeState == HWC2_POWER_MODE_OFF) || (*mPowerModeState == HWC2_POWER_MODE_ON))) { if (mDisplayInterface->setLowPowerMode()) { ALOGI("Not support LP mode."); return HWC2_ERROR_UNSUPPORTED; } } - mPowerModeState = mode; + { + std::lock_guard<std::mutex> lock(mPowerModeMutex); + mPowerModeState = mode; + } + + // LHBM will be disabled in the kernel while entering AOD mode if it's + // already enabled. Reset the state to avoid the sync problem. + mBrightnessController->resetLhbmState(); + mLhbmOn = false; ExynosDisplay::updateRefreshRateHint(); @@ -349,9 +385,12 @@ int32_t ExynosPrimaryDisplay::setPowerMode(int32_t mode) { } else if (mode == static_cast<int32_t>(ext_hwc2_power_mode_t::RESUME)) { mode = HWC2_POWER_MODE_ON; mPauseDisplay = false; + } else if (mPauseDisplay) { + ALOGI("Skip power mode transition due to pause display."); + return HWC2_ERROR_NONE; } - if (mode == static_cast<int32_t>(mPowerModeState)) { + if (mPowerModeState.has_value() && (mode == static_cast<int32_t>(mPowerModeState.value()))) { ALOGI("Skip power mode transition due to the same power state."); return HWC2_ERROR_NONE; } @@ -364,6 +403,7 @@ int32_t ExynosPrimaryDisplay::setPowerMode(int32_t mode) { else mDREnable = mDRDefault; + if (mOperationRateManager) mOperationRateManager->onPowerMode(mode); switch (mode) { case HWC2_POWER_MODE_DOZE_SUSPEND: case HWC2_POWER_MODE_DOZE: @@ -496,72 +536,250 @@ int32_t ExynosPrimaryDisplay::SetCurrentPanelGammaSource(const DisplayType type, return HWC2_ERROR_NONE; } +bool ExynosPrimaryDisplay::isLhbmSupported() { + return mBrightnessController->isLhbmSupported(); +} + +bool ExynosPrimaryDisplay::isConfigSettingEnabled() { + int64_t msSinceDisabled = + (systemTime(SYSTEM_TIME_MONOTONIC) - mConfigSettingDisabledTimestamp) / 1000000; + return !mConfigSettingDisabled || msSinceDisabled > kConfigDisablingMaxDurationMs; +} + +void ExynosPrimaryDisplay::enableConfigSetting(bool en) { + DISPLAY_ATRACE_INT("ConfigSettingDisabled", !en); + + if (!en) { + mConfigSettingDisabled = true; + mConfigSettingDisabledTimestamp = systemTime(SYSTEM_TIME_MONOTONIC); + return; + } + + mConfigSettingDisabled = false; +} + +int32_t ExynosPrimaryDisplay::setLhbmDisplayConfigLocked(uint32_t peakRate) { + auto hwConfig = mDisplayInterface->getActiveModeId(); + auto config = getConfigId(peakRate, mDisplayConfigs[hwConfig].width, + mDisplayConfigs[hwConfig].height); + if (config == UINT_MAX) { + DISPLAY_LOGE("%s: failed to get config for rate=%d", __func__, peakRate); + return -EINVAL; + } + + if (mPendingConfig == UINT_MAX && mActiveConfig != config) mPendingConfig = mActiveConfig; + if (config != hwConfig) { + if (ExynosDisplay::setActiveConfigInternal(config, true) == HWC2_ERROR_NONE) { + DISPLAY_LOGI("%s: succeeded to set config=%d rate=%d", __func__, config, peakRate); + } else { + DISPLAY_LOGW("%s: failed to set config=%d rate=%d", __func__, config, peakRate); + } + } else { + DISPLAY_LOGI("%s: keep config=%d rate=%d", __func__, config, peakRate); + } + enableConfigSetting(false); + return OK; +} + +void ExynosPrimaryDisplay::restoreLhbmDisplayConfigLocked() { + enableConfigSetting(true); + hwc2_config_t pendingConfig = mPendingConfig; + auto hwConfig = mDisplayInterface->getActiveModeId(); + if (pendingConfig != UINT_MAX && pendingConfig != hwConfig) { + if (applyPendingConfig() == HWC2_ERROR_NONE) { + DISPLAY_LOGI("%s: succeeded to set config=%d rate=%d", __func__, pendingConfig, + getRefreshRate(pendingConfig)); + } else { + DISPLAY_LOGE("%s: failed to set config=%d rate=%d", __func__, pendingConfig, + getRefreshRate(pendingConfig)); + } + } else { + mPendingConfig = UINT_MAX; + DISPLAY_LOGI("%s: keep config=%d rate=%d", __func__, hwConfig, getRefreshRate(hwConfig)); + } +} + +// This function should be called by other threads (e.g. sensor HAL). +// HWCService can call this function but it should be for test purpose only. int32_t ExynosPrimaryDisplay::setLhbmState(bool enabled) { + int ret = OK; // NOTE: mLhbmOn could be set to false at any time by setPowerOff in another // thread. Make sure no side effect if that happens. Or add lock if we have // to when new code is added. - ATRACE_CALL(); - if (enabled) { - ATRACE_NAME("wait for peak refresh rate"); - for (int32_t i = 0; i <= kLhbmWaitForPeakRefreshRate; i++) { - if (!isCurrentPeakRefreshRate()) { - if (i == kLhbmWaitForPeakRefreshRate) { - ALOGW("setLhbmState(on) wait for peak refresh rate timeout !"); - return TIMED_OUT; - } - usleep(mVsyncPeriod / 1000 + 1); - } else { - ALOGI_IF(i, "waited %d vsync to reach peak refresh rate", i); - break; + DISPLAY_ATRACE_CALL(); + DISPLAY_LOGI("%s: enabled=%d", __func__, enabled); + { + ATRACE_NAME("wait_for_power_on"); + std::unique_lock<std::mutex> lock(mPowerModeMutex); + if (mPowerModeState != HWC2_POWER_MODE_ON) { + mNotifyPowerOn = true; + if (!mPowerOnCondition.wait_for(lock, std::chrono::milliseconds(2000), [this]() { + return (mPowerModeState == HWC2_POWER_MODE_ON); + })) { + DISPLAY_LOGW("%s: wait for power mode on timeout !", __func__); + return TIMED_OUT; } } } - requestLhbm(enabled); - constexpr uint32_t kSysfsCheckTimeoutMs = 500; - ALOGI("setLhbmState =%d", enabled); - bool succeed = mBrightnessController->checkSysfsStatus( - BrightnessController::kLocalHbmModeFileNode, - std::to_string(enabled ? 1 : 0), - ms2ns(kSysfsCheckTimeoutMs)); - if (!succeed) { - ALOGE("failed to update lhbm mode"); - return -ENODEV; + auto lhbmSysfs = mBrightnessController->GetPanelSysfileByIndex( + BrightnessController::kLocalHbmModeFileNode); + ret = mBrightnessController->checkSysfsStatus(lhbmSysfs, + {std::to_string(static_cast<int>( + BrightnessController::LhbmMode::DISABLED))}, + 0); + bool wasDisabled = ret == OK; + if (!enabled && wasDisabled) { + DISPLAY_LOGW("%s: lhbm is at DISABLED state, skip disabling", __func__); + return NO_ERROR; + } else if (enabled && !wasDisabled) { + requestLhbm(true); + DISPLAY_LOGI("%s: lhbm is at ENABLING or ENABLED state, re-enable to reset timeout timer", + __func__); + return NO_ERROR; + } + + std::vector<std::string> checkingValue; + if (!enabled) { + ATRACE_NAME("disable_lhbm"); + { + Mutex::Autolock lock(mDisplayMutex); + restoreLhbmDisplayConfigLocked(); + } + requestLhbm(false); + { + ATRACE_NAME("wait_for_lhbm_off_cmd"); + checkingValue = { + std::to_string(static_cast<int>(BrightnessController::LhbmMode::DISABLED))}; + ret = mBrightnessController->checkSysfsStatus(lhbmSysfs, checkingValue, + ms2ns(kSysfsCheckTimeoutMs)); + if (ret != OK) { + DISPLAY_LOGW("%s: failed to send lhbm-off cmd", __func__); + } + } + setLHBMRefreshRateThrottle(0); + mLhbmOn = false; + return NO_ERROR; } + ATRACE_NAME("enable_lhbm"); + int64_t lhbmWaitForRrNanos, lhbmEnablingNanos, lhbmEnablingDoneNanos; + bool enablingStateSupported = !mFramesToReachLhbmPeakBrightness; + uint32_t peakRate = 0; + auto rrSysfs = mBrightnessController->GetPanelRefreshRateSysfile(); + lhbmWaitForRrNanos = systemTime(SYSTEM_TIME_MONOTONIC); { - // lhbm takes effect at next vblank - ATRACE_NAME("lhbm_wait_apply"); - if (mDisplayInterface->waitVBlank()) { - ALOGE("%s failed to wait vblank", __func__); - return -ENODEV; + Mutex::Autolock lock(mDisplayMutex); + peakRate = getPeakRefreshRate(); + if (peakRate < 60) { + DISPLAY_LOGE("%s: invalid peak rate=%d", __func__, peakRate); + return -EINVAL; } + ret = setLhbmDisplayConfigLocked(peakRate); + if (ret != OK) return ret; } - if (enabled) { - for (int32_t i = mFramesToReachLhbmPeakBrightness; i > 0; i--) { - ATRACE_NAME("lhbm_wait_peak_brightness"); - mDevice->onRefresh(); + if (mBrightnessController->fileExists(rrSysfs)) { + ATRACE_NAME("wait_for_peak_rate_cmd"); + ret = mBrightnessController->checkSysfsStatus(rrSysfs, {std::to_string(peakRate)}, + ms2ns(kLhbmWaitForPeakRefreshRateMs)); + if (ret != OK) { + DISPLAY_LOGW("%s: failed to poll peak refresh rate=%d, ret=%d", __func__, peakRate, + ret); + } + } else { + ATRACE_NAME("wait_for_peak_rate_blindly"); + DISPLAY_LOGW("%s: missing refresh rate path: %s", __func__, rrSysfs.c_str()); + // blindly wait for (3 full frames + 1 frame uncertainty) to ensure DM finishes + // switching refresh rate + for (int32_t i = 0; i < 4; i++) { if (mDisplayInterface->waitVBlank()) { - ALOGE("%s failed to wait vblank, %d", __func__, i); - return -ENODEV; + DISPLAY_LOGE("%s: failed to blindly wait for peak refresh rate=%d, i=%d", __func__, + peakRate, i); + ret = -ENODEV; + goto enable_err; } } } - mLhbmOn = enabled; - if (mPowerModeState == HWC2_POWER_MODE_OFF && mLhbmOn) { + setLHBMRefreshRateThrottle(kLhbmRefreshRateThrottleMs); + checkingValue = {std::to_string(static_cast<int>(BrightnessController::LhbmMode::ENABLING)), + std::to_string(static_cast<int>(BrightnessController::LhbmMode::ENABLED))}; + lhbmEnablingNanos = systemTime(SYSTEM_TIME_MONOTONIC); + requestLhbm(true); + { + ATRACE_NAME("wait_for_lhbm_on_cmd"); + ret = mBrightnessController->checkSysfsStatus(lhbmSysfs, checkingValue, + ms2ns(kSysfsCheckTimeoutMs)); + if (ret != OK) { + DISPLAY_LOGE("%s: failed to enable lhbm", __func__); + setLHBMRefreshRateThrottle(0); + goto enable_err; + } + } + + lhbmEnablingDoneNanos = systemTime(SYSTEM_TIME_MONOTONIC); + { + ATRACE_NAME("wait_for_peak_brightness"); + if (enablingStateSupported) { + ret = mBrightnessController->checkSysfsStatus(lhbmSysfs, + {std::to_string(static_cast<int>( + BrightnessController::LhbmMode::ENABLED))}, + ms2ns(kSysfsCheckTimeoutMs)); + if (ret != OK) { + DISPLAY_LOGE("%s: failed to wait for lhbm becoming effective", __func__); + goto enable_err; + } + } else { + // lhbm takes effect at next vblank + for (int32_t i = mFramesToReachLhbmPeakBrightness + 1; i > 0; i--) { + ret = mDisplayInterface->waitVBlank(); + if (ret) { + DISPLAY_LOGE("%s: failed to wait vblank for peak brightness, %d", __func__, i); + goto enable_err; + } + } + } + } + DISPLAY_LOGI("%s: latency: %04d = %03d|rr@%03d + %03d|en + %03d|boost@%s", __func__, + getTimestampDeltaMs(0, lhbmWaitForRrNanos), + getTimestampDeltaMs(lhbmEnablingNanos, lhbmWaitForRrNanos), peakRate, + getTimestampDeltaMs(lhbmEnablingDoneNanos, lhbmEnablingNanos), + getTimestampDeltaMs(0, lhbmEnablingDoneNanos), + enablingStateSupported ? "polling" : "fixed"); + + mLhbmOn = true; + if (!mPowerModeState.has_value() || (*mPowerModeState == HWC2_POWER_MODE_OFF && mLhbmOn)) { mLhbmOn = false; - ALOGE("%s power off during request lhbm on", __func__); + DISPLAY_LOGE("%s: power off during request lhbm on", __func__); return -EINVAL; } return NO_ERROR; +enable_err: + Mutex::Autolock lock(mDisplayMutex); + restoreLhbmDisplayConfigLocked(); + return ret; } bool ExynosPrimaryDisplay::getLhbmState() { return mLhbmOn; } +void ExynosPrimaryDisplay::setLHBMRefreshRateThrottle(const uint32_t delayMs) { + ATRACE_CALL(); + + if (delayMs) { + // make new throttle take effect + mLastRefreshRateAppliedNanos = systemTime(SYSTEM_TIME_MONOTONIC); + DISPLAY_ATRACE_INT64("LastRefreshRateAppliedMs", ns2ms(mLastRefreshRateAppliedNanos)); + } + + setRefreshRateThrottleNanos(std::chrono::duration_cast<std::chrono::nanoseconds>( + std::chrono::milliseconds(delayMs)) + .count(), + VrrThrottleRequester::LHBM); +} + void ExynosPrimaryDisplay::setEarlyWakeupDisplay() { if (mEarlyWakeupDispFd) { writeFileNode(mEarlyWakeupDispFd, 1); @@ -595,10 +813,10 @@ int32_t ExynosPrimaryDisplay::setDisplayIdleTimer(const int32_t timeoutMs) { } if (timeoutMs > 0) { - setRefreshRateThrottleNanos(std::chrono::duration_cast<std::chrono::nanoseconds>( - std::chrono::milliseconds(timeoutMs)) - .count(), - DispIdleTimerRequester::SF); + setDisplayIdleDelayNanos(std::chrono::duration_cast<std::chrono::nanoseconds>( + std::chrono::milliseconds(timeoutMs)) + .count(), + DispIdleTimerRequester::SF); } bool enabled = (timeoutMs > 0); @@ -617,7 +835,7 @@ int32_t ExynosPrimaryDisplay::getDisplayIdleTimerEnabled(bool &enabled) { return HWC2_ERROR_UNSUPPORTED; } - const std::string path = getPanelSysfsPath(DisplayType::DISPLAY_PRIMARY) + "panel_idle"; + const std::string path = getPanelSysfsPath(getDisplayTypeFromIndex(mIndex)) + "panel_idle"; std::ifstream ifs(path); if (!ifs.is_open()) { ALOGW("%s() unable to open node '%s', error = %s", __func__, path.c_str(), strerror(errno)); @@ -633,7 +851,7 @@ int32_t ExynosPrimaryDisplay::getDisplayIdleTimerEnabled(bool &enabled) { } int32_t ExynosPrimaryDisplay::setDisplayIdleTimerEnabled(const bool enabled) { - const std::string path = getPanelSysfsPath(DisplayType::DISPLAY_PRIMARY) + "panel_idle"; + const std::string path = getPanelSysfsPath(getDisplayTypeFromIndex(mIndex)) + "panel_idle"; std::ofstream ofs(path); if (!ofs.is_open()) { ALOGW("%s() unable to open node '%s', error = %s", __func__, path.c_str(), strerror(errno)); @@ -646,13 +864,48 @@ int32_t ExynosPrimaryDisplay::setDisplayIdleTimerEnabled(const bool enabled) { return NO_ERROR; } +int32_t ExynosPrimaryDisplay::setDisplayIdleDelayNanos(const int32_t delayNanos, + const DispIdleTimerRequester requester) { + std::lock_guard<std::mutex> lock(mDisplayIdleDelayMutex); + + int64_t maxDelayNanos = 0; + mDisplayIdleTimerNanos[toUnderlying(requester)] = delayNanos; + for (uint32_t i = 0; i < toUnderlying(DispIdleTimerRequester::MAX); i++) { + if (mDisplayIdleTimerNanos[i] > maxDelayNanos) { + maxDelayNanos = mDisplayIdleTimerNanos[i]; + } + } + + if (mDisplayIdleDelayNanos == maxDelayNanos) { + return NO_ERROR; + } + + mDisplayIdleDelayNanos = maxDelayNanos; + + const int32_t displayIdleDelayMs = std::chrono::duration_cast<std::chrono::milliseconds>( + std::chrono::nanoseconds(mDisplayIdleDelayNanos)) + .count(); + const std::string path = getPanelSysfsPath(DisplayType::DISPLAY_PRIMARY) + "idle_delay_ms"; + std::ofstream ofs(path); + if (!ofs.is_open()) { + ALOGW("%s() unable to open node '%s', error = %s", __func__, path.c_str(), strerror(errno)); + return errno; + } else { + ofs << displayIdleDelayMs; + ALOGI("%s() writes idle_delay_ms(%d) to the sysfs node (0x%x)", __func__, + displayIdleDelayMs, ofs.rdstate()); + ofs.close(); + } + return NO_ERROR; +} + void ExynosPrimaryDisplay::initDisplayHandleIdleExit() { if (bool support; getDisplayIdleTimerSupport(support) || support == false) { return; } const std::string path = - getPanelSysfsPath(DisplayType::DISPLAY_PRIMARY) + "panel_need_handle_idle_exit"; + getPanelSysfsPath(getDisplayTypeFromIndex(mIndex)) + "panel_need_handle_idle_exit"; mDisplayNeedHandleIdleExitOfs.open(path, std::ofstream::out); if (!mDisplayNeedHandleIdleExitOfs.is_open()) { ALOGI("%s() '%s' doesn't exist(%s)", __func__, path.c_str(), strerror(errno)); @@ -698,7 +951,7 @@ void ExynosPrimaryDisplay::handleDisplayIdleEnter(const uint32_t idleTeRefreshRa bool needed = false; for (size_t i = 0; i < mLayers.size(); i++) { if (mLayers[i]->mOtfMPP && mLayers[i]->mM2mMPP == nullptr && - !mLayers[i]->checkDownscaleCap(idleTeRefreshRate)) { + !mLayers[i]->checkBtsCap(idleTeRefreshRate)) { needed = true; break; } @@ -710,7 +963,7 @@ void ExynosPrimaryDisplay::handleDisplayIdleEnter(const uint32_t idleTeRefreshRa int ExynosPrimaryDisplay::setMinIdleRefreshRate(const int fps) { mMinIdleRefreshRate = fps; - const std::string path = getPanelSysfsPath(DisplayType::DISPLAY_PRIMARY) + "min_vrefresh"; + const std::string path = getPanelSysfsPath(getDisplayTypeFromIndex(mIndex)) + "min_vrefresh"; std::ofstream ofs(path); if (!ofs.is_open()) { ALOGW("Unable to open node '%s', error = %s", path.c_str(), strerror(errno)); @@ -725,7 +978,8 @@ int ExynosPrimaryDisplay::setMinIdleRefreshRate(const int fps) { } int ExynosPrimaryDisplay::setRefreshRateThrottleNanos(const int64_t delayNanos, - const DispIdleTimerRequester requester) { + const VrrThrottleRequester requester) { + ATRACE_CALL(); ALOGI("%s() requester(%u) set delay to %" PRId64 "ns", __func__, toUnderlying(requester), delayNanos); if (delayNanos < 0) { @@ -736,45 +990,36 @@ int ExynosPrimaryDisplay::setRefreshRateThrottleNanos(const int64_t delayNanos, std::lock_guard<std::mutex> lock(mIdleRefreshRateThrottleMutex); int64_t maxDelayNanos = 0; - mDisplayIdleTimerNanos[toUnderlying(requester)] = delayNanos; - for (uint32_t i = 0; i < toUnderlying(DispIdleTimerRequester::MAX); i++) { - if (mDisplayIdleTimerNanos[i] > maxDelayNanos) { - maxDelayNanos = mDisplayIdleTimerNanos[i]; + mVrrThrottleNanos[toUnderlying(requester)] = delayNanos; + for (uint32_t i = 0; i < toUnderlying(VrrThrottleRequester::MAX); i++) { + if (mVrrThrottleNanos[i] > maxDelayNanos) { + maxDelayNanos = mVrrThrottleNanos[i]; } } + DISPLAY_ATRACE_INT64("RefreshRateDelay", ns2ms(maxDelayNanos)); if (mRefreshRateDelayNanos == maxDelayNanos) { return NO_ERROR; } mRefreshRateDelayNanos = maxDelayNanos; - - const int32_t refreshRateDelayMs = std::chrono::duration_cast<std::chrono::milliseconds>( - std::chrono::nanoseconds(mRefreshRateDelayNanos)) - .count(); - const std::string path = getPanelSysfsPath(DisplayType::DISPLAY_PRIMARY) + "idle_delay_ms"; - std::ofstream ofs(path); - if (!ofs.is_open()) { - ALOGW("%s() unable to open node '%s', error = %s", __func__, path.c_str(), strerror(errno)); - return errno; - } else { - ofs << refreshRateDelayMs; - ALOGI("%s() writes idle_delay_ms(%d) to the sysfs node (0x%x)", __func__, - refreshRateDelayMs, ofs.rdstate()); - ofs.close(); - } - - return NO_ERROR; + return setDisplayIdleDelayNanos(mRefreshRateDelayNanos, DispIdleTimerRequester::VRR_THROTTLE); } void ExynosPrimaryDisplay::dump(String8 &result) { ExynosDisplay::dump(result); result.appendFormat("Display idle timer: %s\n", (mDisplayIdleTimerEnabled) ? "enabled" : "disabled"); + for (uint32_t i = 0; i < toUnderlying(DispIdleTimerRequester::MAX); i++) { + result.appendFormat("\t[%u] vote to %" PRId64 " ns\n", i, mDisplayIdleTimerNanos[i]); + } result.appendFormat("Min idle refresh rate: %d\n", mMinIdleRefreshRate); result.appendFormat("Refresh rate delay: %" PRId64 " ns\n", mRefreshRateDelayNanos); - for (uint32_t i = 0; i < toUnderlying(DispIdleTimerRequester::MAX); i++) { - result.appendFormat("\t[%u] set to %" PRId64 " ns\n", i, mDisplayIdleTimerNanos[i]); + for (uint32_t i = 0; i < toUnderlying(VrrThrottleRequester::MAX); i++) { + result.appendFormat("\t[%u] vote to %" PRId64 " ns\n", i, mVrrThrottleNanos[i]); + } + if (mOperationRateManager) { + result.appendFormat("Operation rate: %d\n", mOperationRateManager->getOperationRate()); } result.appendFormat("\n"); } @@ -782,6 +1027,7 @@ void ExynosPrimaryDisplay::dump(String8 &result) { void ExynosPrimaryDisplay::calculateTimeline( hwc2_config_t config, hwc_vsync_period_change_constraints_t *vsyncPeriodChangeConstraints, hwc_vsync_period_change_timeline_t *outTimeline) { + ATRACE_CALL(); int64_t desiredUpdateTime = vsyncPeriodChangeConstraints->desiredTimeNanos; const int64_t origDesiredUpdateTime = desiredUpdateTime; const int64_t threshold = mRefreshRateDelayNanos; @@ -809,31 +1055,30 @@ void ExynosPrimaryDisplay::calculateTimeline( getConfigAppliedTime(mVsyncPeriodChangeConstraints.desiredTimeNanos, actualChangeTime, outTimeline->newVsyncAppliedTimeNanos, outTimeline->refreshTimeNanos); - if (isDelayed) { - DISPLAY_LOGD(eDebugDisplayConfig, - "requested config : %d(%d)->%d(%d) is delayed! " - "delta %" PRId64 ", delay %" PRId64 ", threshold %" PRId64 ", " - "desired %" PRId64 "->%" PRId64 ", newVsyncAppliedTimeNanos : %" PRId64 - ", refreshTimeNanos:%" PRId64, - mActiveConfig, mDisplayConfigs[mActiveConfig].vsyncPeriod, config, - mDisplayConfigs[config].vsyncPeriod, lastUpdateDelta, - threshold - lastUpdateDelta, threshold, origDesiredUpdateTime, - mVsyncPeriodChangeConstraints.desiredTimeNanos, - outTimeline->newVsyncAppliedTimeNanos, outTimeline->refreshTimeNanos); - } else { - DISPLAY_LOGD(eDebugDisplayConfig, - "requested config : %d(%d)->%d(%d), " - "lastUpdateDelta %" PRId64 ", threshold %" PRId64 ", " - "desired %" PRId64 ", newVsyncAppliedTimeNanos : %" PRId64 "", - mActiveConfig, mDisplayConfigs[mActiveConfig].vsyncPeriod, config, - mDisplayConfigs[config].vsyncPeriod, lastUpdateDelta, threshold, - mVsyncPeriodChangeConstraints.desiredTimeNanos, - outTimeline->newVsyncAppliedTimeNanos); - } + const nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); + DISPLAY_LOGD_AND_ATRACE_NAME(eDebugDisplayConfig, + "requested config : %d(%d)->%d(%d), isDelay:%d," + " delta %" PRId64 ", delay %" PRId64 ", threshold %" PRId64 ", " + "now:%" PRId64 ", desired %" PRId64 "->%" PRId64 + ", newVsyncAppliedTimeNanos : %" PRId64 + ", refreshTimeNanos:%" PRId64 + ", mLastRefreshRateAppliedNanos:%" PRId64, + mActiveConfig, mDisplayConfigs[mActiveConfig].vsyncPeriod, config, + mDisplayConfigs[config].vsyncPeriod, isDelayed, + ns2ms(lastUpdateDelta), ns2ms(threshold - lastUpdateDelta), + ns2ms(threshold), ns2ms(now), ns2ms(origDesiredUpdateTime), + ns2ms(mVsyncPeriodChangeConstraints.desiredTimeNanos), + ns2ms(outTimeline->newVsyncAppliedTimeNanos), + ns2ms(outTimeline->refreshTimeNanos), + ns2ms(mLastRefreshRateAppliedNanos)); + + const int64_t diffMs = ns2ms(outTimeline->refreshTimeNanos - now); + DISPLAY_ATRACE_INT64("TimeToChangeConfig", diffMs); } void ExynosPrimaryDisplay::updateAppliedActiveConfig(const hwc2_config_t newConfig, const int64_t ts) { + ATRACE_CALL(); if (mAppliedActiveConfig == 0 || getDisplayVsyncPeriodFromConfig(mAppliedActiveConfig) != getDisplayVsyncPeriodFromConfig(newConfig)) { @@ -842,6 +1087,7 @@ void ExynosPrimaryDisplay::updateAppliedActiveConfig(const hwc2_config_t newConf " -> %" PRIu64 ")", __func__, mAppliedActiveConfig, newConfig, mLastRefreshRateAppliedNanos, ts); mLastRefreshRateAppliedNanos = ts; + DISPLAY_ATRACE_INT64("LastRefreshRateAppliedMs", ns2ms(mLastRefreshRateAppliedNanos)); } mAppliedActiveConfig = newConfig; @@ -852,10 +1098,11 @@ void ExynosPrimaryDisplay::checkBtsReassignResource(const uint32_t vsyncPeriod, ATRACE_CALL(); uint32_t refreshRate = static_cast<uint32_t>(round(nsecsPerSec / vsyncPeriod * 0.1f) * 10); + Mutex::Autolock lock(mDRMutex); if (vsyncPeriod < btsVsyncPeriod) { for (size_t i = 0; i < mLayers.size(); i++) { if (mLayers[i]->mOtfMPP && mLayers[i]->mM2mMPP == nullptr && - !mLayers[i]->checkDownscaleCap(refreshRate)) { + !mLayers[i]->checkBtsCap(refreshRate)) { mLayers[i]->setGeometryChanged(GEOMETRY_DEVICE_CONFIG_CHANGED); break; } @@ -878,3 +1125,12 @@ void ExynosPrimaryDisplay::checkBtsReassignResource(const uint32_t vsyncPeriod, } } } + +bool ExynosPrimaryDisplay::isDbmSupported() { + return mBrightnessController->isDbmSupported(); +} + +int32_t ExynosPrimaryDisplay::setDbmState(bool enabled) { + mBrightnessController->processDimBrightness(enabled); + return NO_ERROR; +} diff --git a/libhwc2.1/libmaindisplay/ExynosPrimaryDisplay.h b/libhwc2.1/libmaindisplay/ExynosPrimaryDisplay.h index 2aa0325..323eb5a 100644 --- a/libhwc2.1/libmaindisplay/ExynosPrimaryDisplay.h +++ b/libhwc2.1/libmaindisplay/ExynosPrimaryDisplay.h @@ -20,10 +20,12 @@ #include "../libdevice/ExynosDisplay.h" +using namespace displaycolor; + class ExynosPrimaryDisplay : public ExynosDisplay { public: /* Methods */ - ExynosPrimaryDisplay(uint32_t index, ExynosDevice *device); + ExynosPrimaryDisplay(uint32_t index, ExynosDevice* device, const std::string& displayName); ~ExynosPrimaryDisplay(); virtual void setDDIScalerEnable(int width, int height); virtual int getDDIScalerMode(int width, int height); @@ -33,6 +35,7 @@ class ExynosPrimaryDisplay : public ExynosDisplay { return currentPanelGammaSource; } + virtual bool isLhbmSupported(); virtual int32_t setLhbmState(bool enabled); virtual bool getLhbmState(); @@ -48,7 +51,10 @@ class ExynosPrimaryDisplay : public ExynosDisplay { virtual int setMinIdleRefreshRate(const int fps) override; virtual int setRefreshRateThrottleNanos(const int64_t delayNs, - const DispIdleTimerRequester requester) override; + const VrrThrottleRequester requester) override; + virtual bool isDbmSupported() override; + virtual int32_t setDbmState(bool enabled) override; + virtual void dump(String8& result) override; virtual void updateAppliedActiveConfig(const hwc2_config_t newConfig, const int64_t ts) override; @@ -57,7 +63,9 @@ class ExynosPrimaryDisplay : public ExynosDisplay { virtual int32_t setBootDisplayConfig(int32_t config) override; virtual int32_t clearBootDisplayConfig() override; - virtual int32_t getPreferredDisplayConfigInternal(int32_t *outConfig) override; + virtual int32_t getPreferredDisplayConfigInternal(int32_t* outConfig) override; + virtual bool isConfigSettingEnabled() override; + virtual void enableConfigSetting(bool en) override; protected: /* setPowerMode(int32_t mode) @@ -72,20 +80,30 @@ class ExynosPrimaryDisplay : public ExynosDisplay { virtual bool getHDRException(ExynosLayer* __unused layer); virtual int32_t setActiveConfigInternal(hwc2_config_t config, bool force) override; virtual int32_t getActiveConfigInternal(hwc2_config_t* outConfig) override; + DisplayType getDisplayTypeFromIndex(uint32_t index) { + return (index >= DisplayType::DISPLAY_MAX) ? DisplayType::DISPLAY_PRIMARY + : DisplayType(mIndex); + }; + public: // Prepare multi resolution ResolutionInfo mResolutionInfo; std::string getPanelSysfsPath(const displaycolor::DisplayType& type); + uint32_t mRcdId = -1; + private: static constexpr const char* kDisplayCalFilePath = "/mnt/vendor/persist/display/"; static constexpr const char* kPanelGammaCalFilePrefix = "gamma_calib_data"; enum PanelGammaSource currentPanelGammaSource = PanelGammaSource::GAMMA_DEFAULT; bool checkLhbmMode(bool status, nsecs_t timoutNs); + void setLHBMRefreshRateThrottle(const uint32_t delayMs); - hwc2_config_t mPendActiveConfig = UINT_MAX; bool mFirstPowerOn = true; + bool mNotifyPowerOn = false; + std::mutex mPowerModeMutex; + std::condition_variable mPowerOnCondition; int32_t applyPendingConfig(); int32_t setPowerOn(); @@ -95,14 +113,28 @@ class ExynosPrimaryDisplay : public ExynosDisplay { int32_t setDisplayIdleTimerEnabled(const bool enabled); int32_t getDisplayIdleTimerEnabled(bool& enabled); void setDisplayNeedHandleIdleExit(const bool needed, const bool force); + int32_t setDisplayIdleDelayNanos(int32_t delayNanos, + const DispIdleTimerRequester requester); void initDisplayHandleIdleExit(); + int32_t setLhbmDisplayConfigLocked(uint32_t peakRate); + void restoreLhbmDisplayConfigLocked(); // LHBM FILE* mLhbmFd; std::atomic<bool> mLhbmOn; int32_t mFramesToReachLhbmPeakBrightness; - // wait num of vsync periods for peak refresh rate - static constexpr uint32_t kLhbmWaitForPeakRefreshRate = 10; + bool mConfigSettingDisabled = false; + int64_t mConfigSettingDisabledTimestamp = 0; + // timeout value of waiting for peak refresh rate + static constexpr uint32_t kLhbmWaitForPeakRefreshRateMs = 100U; + static constexpr uint32_t kLhbmRefreshRateThrottleMs = 1000U; + static constexpr uint32_t kConfigDisablingMaxDurationMs = 1000U; + static constexpr uint32_t kSysfsCheckTimeoutMs = 500U; + + int32_t getTimestampDeltaMs(int64_t endNs, int64_t beginNs) { + if (endNs == 0) endNs = systemTime(SYSTEM_TIME_MONOTONIC); + return (endNs - beginNs) / 1000000; + } FILE* mEarlyWakeupDispFd; static constexpr const char* kWakeupDispFilePath = @@ -115,13 +147,16 @@ class ExynosPrimaryDisplay : public ExynosDisplay { hwc_vsync_period_change_timeline_t* outTimeline) override; std::mutex mIdleRefreshRateThrottleMutex; int mMinIdleRefreshRate; + int64_t mVrrThrottleNanos[toUnderlying(VrrThrottleRequester::MAX)]; int64_t mRefreshRateDelayNanos; int64_t mLastRefreshRateAppliedNanos; hwc2_config_t mAppliedActiveConfig; + std::mutex mDisplayIdleDelayMutex; bool mDisplayIdleTimerEnabled; int64_t mDisplayIdleTimerNanos[toUnderlying(DispIdleTimerRequester::MAX)]; std::ofstream mDisplayNeedHandleIdleExitOfs; + int64_t mDisplayIdleDelayNanos; bool mDisplayNeedHandleIdleExit; }; diff --git a/libhwc2.1/libresource/ExynosMPP.cpp b/libhwc2.1/libresource/ExynosMPP.cpp index 740cec7..119420e 100644 --- a/libhwc2.1/libresource/ExynosMPP.cpp +++ b/libhwc2.1/libresource/ExynosMPP.cpp @@ -43,13 +43,11 @@ using namespace android; using namespace vendor::graphics; +using namespace SOC_VERSION; int ExynosMPP::mainDisplayWidth = 0; int ExynosMPP::mainDisplayHeight = 0; extern struct exynos_hwc_control exynosHWCControl; -#ifndef USE_MODULE_ATTR -extern feature_support_t feature_table[]; -#endif void dumpExynosMPPImgInfo(uint32_t type, exynos_mpp_img_info &imgInfo) { @@ -100,6 +98,8 @@ ExynosMPPSource::ExynosMPPSource() memset(&mMidImg, 0, sizeof(mMidImg)); mMidImg.acquireFenceFd = -1; mMidImg.releaseFenceFd = -1; + + mHWResourceAmount.clear(); } ExynosMPPSource::ExynosMPPSource(uint32_t sourceType, void *source) @@ -130,6 +130,40 @@ void ExynosMPPSource::setExynosMidImage(exynos_image mid_img) mMidImg = mid_img; } +uint32_t ExynosMPPSource::needHWResource(tdm_attr_t attr) { + uint32_t ret = 0; + + switch (attr) { + case TDM_ATTR_SBWC: + ret = (isFormatSBWC(mSrcImg.format)) ? 1 : 0; + break; + case TDM_ATTR_AFBC: + ret = (mSrcImg.compressed == 1) ? 1 : 0; + break; + case TDM_ATTR_ITP: // CSC + ret = (isFormatYUV(mSrcImg.format)) ? 1 : 0; + break; + case TDM_ATTR_ROT_90: + ret = ((mSrcImg.transform & HAL_TRANSFORM_ROT_90) == 0) ? 0 : 1; + break; + case TDM_ATTR_SCALE: + { + bool isPerpendicular = !!(mSrcImg.transform & HAL_TRANSFORM_ROT_90); + if (isPerpendicular) { + ret = ((mSrcImg.w != mDstImg.h) || (mSrcImg.h != mDstImg.w)) ? 1 : 0; + } else { + ret = ((mSrcImg.w != mDstImg.w) || (mSrcImg.h != mDstImg.h)) ? 1 : 0; + } + } + break; + default: + ret = 0; + break; + } + + return ret; +} + ExynosMPP::ExynosMPP(ExynosResourceManager* resourceManager, uint32_t physicalType, uint32_t logicalType, const char *name, uint32_t physicalIndex, uint32_t logicalIndex, uint32_t preAssignInfo) @@ -162,6 +196,9 @@ ExynosMPP::ExynosMPP(ExynosResourceManager* resourceManager, mDstAllocatedSize(DST_SIZE_UNKNOWN), mUseM2MSrcFence(false), mAttr(0), + mAssignOrder(0), + mAXIPortId(0), + mHWBlockId(0), mNeedSolidColorLayer(false) { if (mPhysicalType < MPP_DPP_NUM) { @@ -314,7 +351,7 @@ bool ExynosMPP::isDataspaceSupportedByMPP(struct exynos_image &src, struct exyno return checkCSCRestriction(src, dst); } -bool ExynosMPP::isSupportedHDR10Plus(struct exynos_image &src, struct exynos_image &dst) +bool ExynosMPP::isSupportedHDR(struct exynos_image &src, struct exynos_image &dst) { uint32_t srcStandard = (src.dataSpace & HAL_DATASPACE_STANDARD_MASK); @@ -322,7 +359,7 @@ bool ExynosMPP::isSupportedHDR10Plus(struct exynos_image &src, struct exynos_ima uint32_t srcTransfer = (src.dataSpace & HAL_DATASPACE_TRANSFER_MASK); uint32_t dstTransfer = (dst.dataSpace & HAL_DATASPACE_TRANSFER_MASK); - if (hasHdr10Plus(src)) { + if (hasHdr10Plus(src) || hasHdrInfo(src) ) { if (mAttr & MPP_ATTR_HDR10PLUS) return true; else if ((srcStandard == dstStandard) && (srcTransfer == dstTransfer)) @@ -964,9 +1001,10 @@ int32_t ExynosMPP::allocOutBuf(uint32_t w, uint32_t h, uint32_t format, uint64_t mDstImgs[index].format = format; MPP_LOGD(eDebugMPP|eDebugBuf, "free outbuf[%d] %p", index, freeDstBuf.bufferHandle); - if (freeDstBuf.bufferHandle != NULL) + + if (freeDstBuf.bufferHandle != NULL) { freeOutBuf(freeDstBuf); - else { + } else { if (mAssignedDisplay != NULL) { freeDstBuf.acrylicAcquireFenceFd = fence_close(freeDstBuf.acrylicAcquireFenceFd, mAssignedDisplay, FENCE_TYPE_SRC_ACQUIRE, FENCE_IP_G2D); @@ -1081,16 +1119,23 @@ bool ExynosMPP::needDstBufRealloc(struct exynos_image &dst, uint32_t index) VendorGraphicBufferMeta gmeta(dst_handle); + uint32_t prevAssignedBufferNum = + getBufferNumOfFormat(gmeta.format, getCompressionType(dst_handle)); + uint32_t assignedBufferNum = getBufferNumOfFormat(dst.format, getCompressionType(dst_handle)); + MPP_LOGD(eDebugMPP | eDebugBuf, "\tdst_handle(%p) afbc (%u) sbwc (%u) lossy (%u)", dst_handle, isAFBCCompressed(dst_handle), isFormatSBWC(gmeta.format), isFormatLossy(gmeta.format)); MPP_LOGD(eDebugMPP | eDebugBuf, - "\tAssignedDisplay[%d, %d] format[0x%8x, 0x%8x], bufferType[%d, %d], usageFlags: " - "0x%" PRIx64 ", need afbc %u sbwc %u lossy %u", + "\tAssignedDisplay[%d, %d] format[0x%8x, 0x%8x], bufferType[%d, %d], bufferNum[%d, " + "%d] " + "usageFlags: 0x%" PRIx64 ", need afbc %u sbwc %u lossy %u", mPrevAssignedDisplayType, assignedDisplay, gmeta.format, dst.format, - mDstImgs[index].bufferType, getBufferType(dst.usageFlags), dst.usageFlags, - dst.compressed, isFormatSBWC(dst.format), isFormatLossy(dst.format)); + mDstImgs[index].bufferType, getBufferType(dst.usageFlags), prevAssignedBufferNum, + assignedBufferNum, dst.usageFlags, dst.compressed, isFormatSBWC(dst.format), + isFormatLossy(dst.format)); bool realloc = (mPrevAssignedDisplayType != assignedDisplay) || + (prevAssignedBufferNum < assignedBufferNum) || (formatToBpp(gmeta.format) < formatToBpp(dst.format)) || ((gmeta.stride * gmeta.vstride) < (int)(dst.fullWidth * dst.fullHeight)) || (mDstImgs[index].bufferType != getBufferType(dst.usageFlags)) || @@ -1355,9 +1400,10 @@ int32_t ExynosMPP::setupDst(exynos_mpp_img_info *dstImgInfo) if (dstImgInfo->bufferType == MPP_BUFFER_SECURE_DRM) attribute |= AcrylicCanvas::ATTR_PROTECTED; - if (mAssignedDisplay != NULL) + if (mAssignedDisplay != NULL) { mAcrylicHandle->setCanvasDimension(pixel_align(mAssignedDisplay->mXres, G2D_JUSTIFIED_DST_ALIGN), pixel_align(mAssignedDisplay->mYres, G2D_JUSTIFIED_DST_ALIGN)); + } /* setup dst */ if (needCompressDstBuf()) { @@ -1879,13 +1925,15 @@ int32_t ExynosMPP::requestHWStateChange(uint32_t state) return NO_ERROR; } - if (state == MPP_HW_STATE_RUNNING) + if (state == MPP_HW_STATE_RUNNING) { mHWState = MPP_HW_STATE_RUNNING; - else if (state == MPP_HW_STATE_IDLE) { - if (mLastStateFenceFd >= 0) + } else if (state == MPP_HW_STATE_IDLE) { + if (mLastStateFenceFd >= 0) { mResourceManageThread->addStateFence(mLastStateFenceFd); - else + } else { mHWState = MPP_HW_STATE_IDLE; + } + mLastStateFenceFd = -1; if ((mPhysicalType == MPP_G2D) && (mHWBusyFlag == false)) { @@ -2056,7 +2104,7 @@ int64_t ExynosMPP::isSupported(ExynosDisplay &display, struct exynos_image &src, return -eMPPUnsupportedFormat; else if (!isDataspaceSupportedByMPP(src, dst)) return -eMPPUnsupportedCSC; - else if (!isSupportedHDR10Plus(src, dst)) + else if (!isSupportedHDR(src, dst)) return -eMPPUnsupportedDynamicMeta; else if (!isSupportedBlend(src)) return -eMPPUnsupportedBlending; @@ -2320,41 +2368,50 @@ bool ExynosMPP::isAssignableState(ExynosDisplay *display, struct exynos_image &s isAssignable, mAssignedSources.size(), getSrcMaxBlendingNum(src, dst)); return isAssignable; } -bool ExynosMPP::isAssignable(ExynosDisplay *display, - struct exynos_image &src, struct exynos_image &dst) + +bool ExynosMPP::isAssignable(ExynosDisplay *display, struct exynos_image &src, + struct exynos_image &dst, float totalUsedCapacity) { bool isAssignable = isAssignableState(display, src, dst); - return (isAssignable && hasEnoughCapa(display, src, dst)); + return (isAssignable && hasEnoughCapa(display, src, dst, totalUsedCapacity)); } -bool ExynosMPP::hasEnoughCapa(ExynosDisplay *display, struct exynos_image &src, struct exynos_image &dst) +bool ExynosMPP::hasEnoughCapa(ExynosDisplay *display, struct exynos_image &src, + struct exynos_image &dst, float totalUsedCapacity) { if (mCapacity == -1) return true; - float totalUsedCapacity = ExynosResourceManager::getResourceUsedCapa(*this); - MPP_LOGD(eDebugCapacity|eDebugMPP, "totalUsedCapacity(%f), mUsedCapacity(%f)", - totalUsedCapacity, mUsedCapacity); + MPP_LOGD(eDebugCapacity | eDebugMPP, "totalUsedCapacity(%f), mUsedCapacity(%f)", + totalUsedCapacity, mUsedCapacity); /* mUsedCapacity should be re-calculated including src, dst passed as parameters*/ totalUsedCapacity -= mUsedCapacity; float requiredCapacity = getRequiredCapacity(display, src, dst); - MPP_LOGD(eDebugCapacity|eDebugMPP, "mCapacity(%f), usedCapacity(%f), RequiredCapacity(%f)", - mCapacity, totalUsedCapacity, requiredCapacity); + MPP_LOGD(eDebugCapacity | eDebugMPP, "mCapacity(%f), usedCapacity(%f), RequiredCapacity(%f)", + mCapacity, totalUsedCapacity, requiredCapacity); if (mCapacity >= (totalUsedCapacity + requiredCapacity)) return true; - else if ((hasHdrInfo(src)) && - (totalUsedCapacity == 0) && (requiredCapacity < (mCapacity * 1.2))) { - /* HDR video will be excepted from G2D capa calculation */ - /* if DRM has assigned before, totalUsedCapacity will be non-zero */ + else if (isCapacityExceptionCondition(totalUsedCapacity, requiredCapacity, src)) return true; - } else + else return false; } +bool ExynosMPP::isCapacityExceptionCondition(float totalUsedCapacity, float requiredCapacity, + struct exynos_image &src) +{ + if ((hasHdrInfo(src) && (totalUsedCapacity == 0) && + (requiredCapacity < (mCapacity * MPP_HDR_MARGIN)))) { + return true; + } else { + return false; + } +} + void ExynosMPP::getPPCIndex(const struct exynos_image &src, const struct exynos_image &dst, uint32_t &formatIndex, uint32_t &rotIndex, uint32_t &scaleIndex, diff --git a/libhwc2.1/libresource/ExynosMPP.h b/libhwc2.1/libresource/ExynosMPP.h index 15cdb83..715c9dc 100644 --- a/libhwc2.1/libresource/ExynosMPP.h +++ b/libhwc2.1/libresource/ExynosMPP.h @@ -113,6 +113,11 @@ class ExynosResourceManager; #ifndef MPP_G2D_CAPACITY #define MPP_G2D_CAPACITY 8 #endif +// G2D or MSC additional margin capacity when HDR layer is passed. +#ifndef MPP_HDR_MARGIN +#define MPP_HDR_MARGIN 1.2 +#endif + #ifndef MPP_MSC_CAPACITY #define MPP_MSC_CAPACITY 8 #endif @@ -166,6 +171,8 @@ enum { eMPPUnsupportedDIMLayer = 1ULL << 30, eMPPUnsupportedDRM = 1ULL << 31, eMPPUnsupportedDynamicMeta = 1ULL << 32, + eMPPSatisfiedRestriction = 1ULL << 33, + eMPPExeedHWResource = 1ULL << 34, }; enum { @@ -219,11 +226,13 @@ typedef enum { #ifndef DEFAULT_MPP_DST_FORMAT #define DEFAULT_MPP_DST_FORMAT HAL_PIXEL_FORMAT_RGBA_8888 #endif + +/* TODO: Switch back to single-fd format, tracked in b/261356480 */ #ifndef DEFAULT_MPP_DST_YUV_FORMAT -#define DEFAULT_MPP_DST_YUV_FORMAT HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SPN +#define DEFAULT_MPP_DST_YUV_FORMAT HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SP_M #endif #ifndef DEFAULT_MPP_DST_UNCOMP_YUV_FORMAT -#define DEFAULT_MPP_DST_UNCOMP_YUV_FORMAT HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SPN +#define DEFAULT_MPP_DST_UNCOMP_YUV_FORMAT HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SP_M #endif typedef struct exynos_mpp_img_info { @@ -453,7 +462,22 @@ class ExynosMPPSource { ExynosMPP *mOtfMPP; ExynosMPP *mM2mMPP; + + /** + * SRAM/HW resource info + */ + std::unordered_map<tdm_attr_t, int32_t> mHWResourceAmount; + uint32_t getHWResourceAmount(tdm_attr_t attr) { return mHWResourceAmount[attr]; } + + uint32_t setHWResourceAmount(tdm_attr_t attr, uint32_t amount) { + mHWResourceAmount[attr] = amount; + return 0; + } + + /* return 1 if it's needed */ + uint32_t needHWResource(tdm_attr_t attr); }; + bool exynosMPPSourceComp(const ExynosMPPSource* l, const ExynosMPPSource* r); void dump(const restriction_size_t &restrictionSize, String8 &result); @@ -546,6 +570,10 @@ public: /* MPP's attribute bit (supported feature bit) */ uint64_t mAttr; + uint32_t mAssignOrder; + uint32_t mAXIPortId; + uint32_t mHWBlockId; + bool mNeedSolidColorLayer; ExynosMPP(ExynosResourceManager* resourceManager, @@ -569,13 +597,18 @@ public: virtual int64_t isSupported(ExynosDisplay &display, struct exynos_image &src, struct exynos_image &dst); bool isDataspaceSupportedByMPP(struct exynos_image &src, struct exynos_image &dst); - bool isSupportedHDR10Plus(struct exynos_image &src, struct exynos_image &dst); + bool isSupportedHDR(struct exynos_image &src, struct exynos_image &dst); bool isSupportedBlend(struct exynos_image &src); virtual bool isSupportedTransform(struct exynos_image &src); bool isSupportedCapability(ExynosDisplay &display, struct exynos_image &src); bool isSupportedDRM(struct exynos_image &src); virtual bool isSupportedHStrideCrop(struct exynos_image &src); bool checkDownscaleCap(const float resolution, const float displayRatio_V) const; + virtual bool checkSpecificRestriction(const uint32_t __unused refreshRate, + const struct exynos_image __unused &src, + const struct exynos_image __unused &dst) { + return false; + } virtual uint32_t getDownscaleRestriction(const struct exynos_image &src, const struct exynos_image &dst) const; virtual uint32_t getMaxDownscale(const ExynosDisplay &display, const struct exynos_image &src, @@ -633,11 +666,12 @@ public: int32_t reserveMPP(int32_t displayType = -1); bool isAssignableState(ExynosDisplay *display, struct exynos_image &src, struct exynos_image &dst); - bool isAssignable(ExynosDisplay *display, - struct exynos_image &src, struct exynos_image &dst); + bool isAssignable(ExynosDisplay *display, struct exynos_image &src, struct exynos_image &dst, + float totalUsedCapacity); int32_t assignMPP(ExynosDisplay *display, ExynosMPPSource* mppSource); - bool hasEnoughCapa(ExynosDisplay *display, struct exynos_image &src, struct exynos_image &dst); + bool hasEnoughCapa(ExynosDisplay *display, struct exynos_image &src, struct exynos_image &dst, + float totalUsedCapa); float getRequiredCapacity(ExynosDisplay *display, struct exynos_image &src, struct exynos_image &dst); int32_t updateUsedCapacity(); void resetUsedCapacity(); @@ -665,6 +699,13 @@ public: void setPPC(float ppc) { mPPC = ppc; }; void setClockKhz(uint32_t clock) { mClockKhz = clock; }; + virtual void initTDMInfo(uint32_t hwBlockIndex, uint32_t axiPortIndex) { + mHWBlockId = hwBlockIndex; + mAXIPortId = axiPortIndex; + } + virtual uint32_t getHWBlockId() { return mHWBlockId; } + virtual uint32_t getAXIPortId() { return mAXIPortId; } + protected: uint32_t getBufferType(uint64_t usage); uint32_t getBufferType(const buffer_handle_t handle); @@ -705,6 +746,12 @@ protected: */ virtual bool checkCSCRestriction(struct exynos_image &src, struct exynos_image &dst); + /* + * Check additional conditions those have a capacity exception. + */ + virtual bool isCapacityExceptionCondition(float totalUsedCapacity, float requiredCapacity, + struct exynos_image &src); + uint32_t mClockKhz = 0; float mPPC = 0; }; diff --git a/libhwc2.1/libresource/ExynosMPPType.h b/libhwc2.1/libresource/ExynosMPPType.h index a4b3026..83477c9 100644 --- a/libhwc2.1/libresource/ExynosMPPType.h +++ b/libhwc2.1/libresource/ExynosMPPType.h @@ -18,8 +18,14 @@ #define _EXYNOSMPPTYPE_H #include <system/graphics.h> +#include <utils/String8.h> + +#include <unordered_map> + #include "DeconHeader.h" +using namespace android; + /* * physical types * Resources are sorted by physical type. @@ -28,16 +34,15 @@ typedef enum { MPP_DPP_G = 0, MPP_DPP_GF, + MPP_DPP_GFS, MPP_DPP_VG, MPP_DPP_VGS, MPP_DPP_VGF, MPP_DPP_VGFS, MPP_DPP_VGRFS, - /* DPP count */ - /* If you add DPP, You should increase this value */ - MPP_DPP_NUM = 7, + MPP_DPP_NUM, - MPP_MSC = 7, + MPP_MSC, MPP_G2D, MPP_P_TYPE_MAX } mpp_phycal_type_t; @@ -46,6 +51,7 @@ typedef enum { typedef enum { MPP_LOGICAL_DPP_G = 0x01, MPP_LOGICAL_DPP_GF = 0x02, + MPP_LOGICAL_DPP_GFS = 0x03, MPP_LOGICAL_DPP_VG = 0x04, MPP_LOGICAL_DPP_VGS = 0x08, MPP_LOGICAL_DPP_VGF = 0x10, @@ -60,7 +66,7 @@ typedef enum { * Increase MPP_LOGICAL_TYPE_NUM * if type is added */ - MPP_LOGICAL_TYPE_NUM = 12 + MPP_LOGICAL_TYPE_NUM = 13 } mpp_logical_type_t; enum { @@ -81,6 +87,28 @@ enum { MPP_ATTR_HDR10PLUS = 0x10000000, }; +// Resource TDM (Time-Division Muliplexing) +typedef enum { + TDM_ATTR_SRAM_AMOUNT, + TDM_ATTR_AFBC, + TDM_ATTR_SBWC, + TDM_ATTR_ITP, // CSC // + TDM_ATTR_ROT_90, + TDM_ATTR_SCALE, + TDM_ATTR_WCG, + TDM_ATTR_MAX, +} tdm_attr_t; + +const std::unordered_map<tdm_attr_t, String8> HWAttrs = { + {TDM_ATTR_SRAM_AMOUNT, String8("SRAM")}, + {TDM_ATTR_AFBC, String8("AFBC")}, + {TDM_ATTR_SBWC, String8("SBWC")}, + {TDM_ATTR_ITP, String8("CSC")}, // CSC // + {TDM_ATTR_ROT_90, String8("ROT")}, + {TDM_ATTR_SCALE, String8("SCALE")}, + {TDM_ATTR_WCG, String8("WCG")}, +}; + typedef struct feature_support_t { mpp_phycal_type_t hwType; /* MPP_DPP_VG, MPP_DPP_VGFS, ... */ uint64_t attr; @@ -110,4 +138,19 @@ typedef struct dpp_channel_map { decon_idma_type channel; } dpp_channel_map_t; +/* + * pre_assign_info: all display_descriptors that want to reserve + */ +struct exynos_mpp_t { + int physicalType; + int logicalType; + char name[16]; + uint32_t physical_index; + uint32_t logical_index; + uint32_t pre_assign_info; + // For TDM + uint32_t hw_block_index; + uint32_t axi_port_index; +}; + #endif diff --git a/libhwc2.1/libresource/ExynosResourceManager.cpp b/libhwc2.1/libresource/ExynosResourceManager.cpp index 57e8e2c..ec4db5f 100644 --- a/libhwc2.1/libresource/ExynosResourceManager.cpp +++ b/libhwc2.1/libresource/ExynosResourceManager.cpp @@ -38,51 +38,6 @@ using namespace std::chrono_literals; constexpr float msecsPerSec = std::chrono::milliseconds(1s).count(); -#ifndef USE_MODULE_ATTR -/* Basic supported features */ -feature_support_t feature_table[] = -{ - {MPP_DPP_G, - MPP_ATTR_BLOCK_MODE | MPP_ATTR_WINDOW_UPDATE | MPP_ATTR_DIM - }, - - {MPP_DPP_GF, - MPP_ATTR_AFBC | MPP_ATTR_BLOCK_MODE | MPP_ATTR_WINDOW_UPDATE | MPP_ATTR_DIM - }, - - {MPP_DPP_VG, - MPP_ATTR_BLOCK_MODE | MPP_ATTR_WINDOW_UPDATE | MPP_ATTR_DIM - }, - - {MPP_DPP_VGS, - MPP_ATTR_BLOCK_MODE | MPP_ATTR_WINDOW_UPDATE | MPP_ATTR_SCALE | MPP_ATTR_DIM - }, - - {MPP_DPP_VGF, - MPP_ATTR_AFBC | MPP_ATTR_BLOCK_MODE | MPP_ATTR_WINDOW_UPDATE | MPP_ATTR_DIM - }, - - {MPP_DPP_VGFS, - MPP_ATTR_AFBC | MPP_ATTR_BLOCK_MODE | MPP_ATTR_WINDOW_UPDATE | MPP_ATTR_SCALE | MPP_ATTR_DIM - }, - - {MPP_DPP_VGRFS, - MPP_ATTR_AFBC | MPP_ATTR_BLOCK_MODE | MPP_ATTR_WINDOW_UPDATE | MPP_ATTR_SCALE | - MPP_ATTR_FLIP_H | MPP_ATTR_FLIP_V | MPP_ATTR_ROT_90 | - MPP_ATTR_DIM | MPP_ATTR_HDR10 - }, - - {MPP_MSC, - MPP_ATTR_FLIP_H | MPP_ATTR_FLIP_V | MPP_ATTR_ROT_90 - }, - - {MPP_G2D, - MPP_ATTR_AFBC | MPP_ATTR_FLIP_H | MPP_ATTR_FLIP_V | MPP_ATTR_ROT_90 | - MPP_ATTR_HDR10 | MPP_ATTR_USE_CAPA - } -}; -#endif - using namespace android; using namespace vendor::graphics; using namespace SOC_VERSION; @@ -155,9 +110,9 @@ ExynosResourceManager::ExynosResourceManager(ExynosDevice *device) memset(mFormatRestrictions, 0, sizeof(mFormatRestrictions)); memset(mSizeRestrictions, 0, sizeof(mSizeRestrictions)); - size_t num_mpp_units = sizeof(AVAILABLE_OTF_MPP_UNITS)/sizeof(exynos_mpp_t); + size_t num_mpp_units = sizeof(available_otf_mpp_units)/sizeof(exynos_mpp_t); for (size_t i = 0; i < num_mpp_units; i++) { - exynos_mpp_t exynos_mpp = AVAILABLE_OTF_MPP_UNITS[i]; + exynos_mpp_t exynos_mpp = available_otf_mpp_units[i]; ALOGI("otfMPP type(%d, %d), physical_index(%d), logical_index(%d)", exynos_mpp.physicalType, exynos_mpp.logicalType, exynos_mpp.physical_index, exynos_mpp.logical_index); @@ -165,6 +120,7 @@ ExynosResourceManager::ExynosResourceManager(ExynosDevice *device) exynos_mpp.logicalType, exynos_mpp.name, exynos_mpp.physical_index, exynos_mpp.logical_index, exynos_mpp.pre_assign_info); exynosMPP->mMPPType = MPP_TYPE_OTF; + exynosMPP->initTDMInfo(exynos_mpp.hw_block_index, exynos_mpp.axi_port_index); mOtfMPPs.add(exynosMPP); } @@ -326,6 +282,8 @@ bool ExynosResourceManager::DstBufMgrThread::threadLoop() ExynosDevice *device = mExynosResourceManager->mDevice; if (device == NULL) return false; + + /* TODO(b/265244856): to clarify which display size to alloc */ ExynosDisplay *display = device->getDisplay(getDisplayId(HWC_DISPLAY_PRIMARY, 0)); if (display == NULL) return false; @@ -437,6 +395,11 @@ int32_t ExynosResourceManager::assignResource(ExynosDisplay *display) return ret; } + HDEBUGLOGD(eDebugTDM, "%s layer's calculation start", __func__); + for (uint32_t i = 0; i < display->mLayers.size(); i++) { + calculateHWResourceAmount(display, display->mLayers[i]); + } + if (mDevice->isFirstValidate()) { HDEBUGLOGD(eDebugResourceManager, "This is first validate"); if (exynosHWCControl.displayMode < DISPLAY_MODE_NUM) @@ -447,7 +410,7 @@ int32_t ExynosResourceManager::assignResource(ExynosDisplay *display) __func__, ret); return ret; } - preAssignWindows(); + preAssignWindows(display); } @@ -603,7 +566,7 @@ int32_t ExynosResourceManager::assignResourceInternal(ExynosDisplay *display) } do { - HDEBUGLOGD(eDebugResourceManager, "%s:: retry_count(%d)", __func__, retry_count); + HDEBUGLOGD(eDebugResourceAssigning, "%s:: retry_count(%d)", __func__, retry_count); if ((ret = resetAssignedResources(display)) != NO_ERROR) return ret; if ((ret = assignCompositionTarget(display, COMPOSITION_CLIENT)) != NO_ERROR) { @@ -698,6 +661,7 @@ int32_t ExynosResourceManager::assignResourceInternal(ExynosDisplay *display) } return ret; } + int32_t ExynosResourceManager::updateExynosComposition(ExynosDisplay *display) { int ret = NO_ERROR; @@ -710,8 +674,9 @@ int32_t ExynosResourceManager::updateExynosComposition(ExynosDisplay *display) uint32_t firstIndex = display->mExynosCompositionInfo.mFirstIndex; uint32_t remainNum = m2mMPP->mMaxSrcLayerNum - (lastIndex - firstIndex + 1); - HDEBUGLOGD(eDebugResourceManager, "Update ExynosComposition firstIndex: %d, lastIndex: %d, remainNum: %d++++", - firstIndex, lastIndex, remainNum); + HDEBUGLOGD(eDebugResourceAssigning, + "Update ExynosComposition firstIndex: %d, lastIndex: %d, remainNum: %d++++", + firstIndex, lastIndex, remainNum); ExynosLayer *layer = NULL; exynos_image src_img; @@ -723,18 +688,20 @@ int32_t ExynosResourceManager::updateExynosComposition(ExynosDisplay *display) layer->setSrcExynosImage(&src_img); layer->setDstExynosImage(&dst_img); layer->setExynosImage(src_img, dst_img); - bool isAssignable = false; + bool isAssignableState = false; if ((layer->mSupportedMPPFlag & m2mMPP->mLogicalType) != 0) - isAssignable = m2mMPP->isAssignable(display, src_img, dst_img); + isAssignableState = isAssignable(m2mMPP, display, src_img, dst_img, layer); bool canChange = (layer->mValidateCompositionType != HWC2_COMPOSITION_CLIENT) && - ((display->mDisplayControl.cursorSupport == false) || - (layer->mCompositionType != HWC2_COMPOSITION_CURSOR)) && - (layer->mSupportedMPPFlag & m2mMPP->mLogicalType) && isAssignable; - - HDEBUGLOGD(eDebugResourceManager, "\tlayer[%d] type: %d, 0x%8x, isAssignable: %d, canChange: %d, remainNum(%d)", - i, layer->mValidateCompositionType, - layer->mSupportedMPPFlag, isAssignable, canChange, remainNum); + ((display->mDisplayControl.cursorSupport == false) || + (layer->mCompositionType != HWC2_COMPOSITION_CURSOR)) && + (layer->mSupportedMPPFlag & m2mMPP->mLogicalType) && isAssignableState; + + HDEBUGLOGD(eDebugResourceAssigning, + "\tlayer[%d] type: %d, 0x%8x, isAssignable: %d, canChange: %d, " + "remainNum(%d)", + i, layer->mValidateCompositionType, layer->mSupportedMPPFlag, + isAssignableState, canChange, remainNum); if (canChange) { layer->resetAssignedResource(); layer->mOverlayInfo |= eUpdateExynosComposition; @@ -745,7 +712,8 @@ int32_t ExynosResourceManager::updateExynosComposition(ExynosDisplay *display) return ret; } layer->setExynosMidImage(dst_img); - display->addExynosCompositionLayer(i); + float totalUsedCapacity = getResourceUsedCapa(*m2mMPP); + display->addExynosCompositionLayer(i, totalUsedCapacity); layer->mValidateCompositionType = HWC2_COMPOSITION_EXYNOS; remainNum--; } @@ -760,18 +728,20 @@ int32_t ExynosResourceManager::updateExynosComposition(ExynosDisplay *display) layer->setSrcExynosImage(&src_img); layer->setDstExynosImage(&dst_img); layer->setExynosImage(src_img, dst_img); - bool isAssignable = false; + bool isAssignableState = false; if ((layer->mSupportedMPPFlag & m2mMPP->mLogicalType) != 0) - isAssignable = m2mMPP->isAssignable(display, src_img, dst_img); + isAssignableState = isAssignable(m2mMPP, display, src_img, dst_img, layer); bool canChange = (layer->mValidateCompositionType != HWC2_COMPOSITION_CLIENT) && - ((display->mDisplayControl.cursorSupport == false) || - (layer->mCompositionType != HWC2_COMPOSITION_CURSOR)) && - (layer->mSupportedMPPFlag & m2mMPP->mLogicalType) && isAssignable; - - HDEBUGLOGD(eDebugResourceManager, "\tlayer[%d] type: %d, 0x%8x, isAssignable: %d, canChange: %d, remainNum(%d)", - i, layer->mValidateCompositionType, - layer->mSupportedMPPFlag, isAssignable, canChange, remainNum); + ((display->mDisplayControl.cursorSupport == false) || + (layer->mCompositionType != HWC2_COMPOSITION_CURSOR)) && + (layer->mSupportedMPPFlag & m2mMPP->mLogicalType) && isAssignableState; + + HDEBUGLOGD(eDebugResourceAssigning, + "\tlayer[%d] type: %d, 0x%8x, isAssignable: %d, canChange: %d, " + "remainNum(%d)", + i, layer->mValidateCompositionType, layer->mSupportedMPPFlag, + isAssignableState, canChange, remainNum); if (canChange) { layer->resetAssignedResource(); layer->mOverlayInfo |= eUpdateExynosComposition; @@ -782,7 +752,8 @@ int32_t ExynosResourceManager::updateExynosComposition(ExynosDisplay *display) return ret; } layer->setExynosMidImage(dst_img); - display->addExynosCompositionLayer(i); + float totalUsedCapacity = getResourceUsedCapa(*m2mMPP); + display->addExynosCompositionLayer(i, totalUsedCapacity); layer->mValidateCompositionType = HWC2_COMPOSITION_EXYNOS; remainNum--; } @@ -790,8 +761,10 @@ int32_t ExynosResourceManager::updateExynosComposition(ExynosDisplay *display) break; } } - HDEBUGLOGD(eDebugResourceManager, "Update ExynosComposition firstIndex: %d, lastIndex: %d, remainNum: %d-----", - display->mExynosCompositionInfo.mFirstIndex, display->mExynosCompositionInfo.mLastIndex, remainNum); + HDEBUGLOGD(eDebugResourceAssigning, + "Update ExynosComposition firstIndex: %d, lastIndex: %d, remainNum: %d-----", + display->mExynosCompositionInfo.mFirstIndex, + display->mExynosCompositionInfo.mLastIndex, remainNum); } /* @@ -843,8 +816,8 @@ int32_t ExynosResourceManager::changeLayerFromClientToDevice(ExynosDisplay *disp __func__, otfMPP->mName.string(), ret); return ret; } - HDEBUGLOGD(eDebugResourceManager, "\t\t[%d] layer: %s MPP is assigned", - layer_index, otfMPP->mName.string()); + HDEBUGLOGD(eDebugResourceAssigning, "\t\t[%d] layer: %s MPP is assigned", layer_index, + otfMPP->mName.string()); } if (m2mMPP != NULL) { if ((ret = m2mMPP->assignMPP(display, layer)) != NO_ERROR) @@ -854,13 +827,13 @@ int32_t ExynosResourceManager::changeLayerFromClientToDevice(ExynosDisplay *disp return ret; } layer->setExynosMidImage(m2m_out_img); - HDEBUGLOGD(eDebugResourceManager, "\t\t[%d] layer: %s MPP is assigned", - layer_index, m2mMPP->mName.string()); + HDEBUGLOGD(eDebugResourceAssigning, "\t\t[%d] layer: %s MPP is assigned", layer_index, + m2mMPP->mName.string()); } layer->mValidateCompositionType = HWC2_COMPOSITION_DEVICE; display->mWindowNumUsed++; - HDEBUGLOGD(eDebugResourceManager, "\t\t[%d] layer: mWindowNumUsed(%d)", - layer_index, display->mWindowNumUsed); + HDEBUGLOGD(eDebugResourceAssigning, "\t\t[%d] layer: mWindowNumUsed(%d)", layer_index, + display->mWindowNumUsed); return ret; } @@ -1032,23 +1005,31 @@ int32_t ExynosResourceManager::assignCompositionTarget(ExynosDisplay * display, } int64_t isSupported = 0; - bool isAssignable = false; + bool isAssignableState = false; + + otfMppReordering(display, mOtfMPPs, src_img, dst_img); + for (uint32_t i = 0; i < mOtfMPPs.size(); i++) { + compositionInfo->setExynosImage(src_img, dst_img); + compositionInfo->setExynosMidImage(dst_img); + HDEBUGLOGD(eDebugTDM, "%s M2M target calculation start", __func__); + calculateHWResourceAmount(display, compositionInfo); + isSupported = mOtfMPPs[i]->isSupported(*display, src_img, dst_img); if (isSupported == NO_ERROR) - isAssignable = mOtfMPPs[i]->isAssignable(display, src_img, dst_img); + isAssignableState = + isAssignable(mOtfMPPs[i], display, src_img, dst_img, compositionInfo); - HDEBUGLOGD(eDebugResourceManager, "\t\t check %s: supportedBit(0x%" PRIx64 "), isAssignable(%d)", - mOtfMPPs[i]->mName.string(), -isSupported, isAssignable); - if ((isSupported == NO_ERROR) && (isAssignable)) { + HDEBUGLOGD(eDebugResourceAssigning, + "\t\t check %s: supportedBit(0x%" PRIx64 "), isAssignable(%d)", + mOtfMPPs[i]->mName.string(), -isSupported, isAssignableState); + if ((isSupported == NO_ERROR) && (isAssignableState)) { if ((ret = mOtfMPPs[i]->assignMPP(display, compositionInfo)) != NO_ERROR) { HWC_LOGE(display, "%s:: %s MPP assignMPP() error (%d)", __func__, mOtfMPPs[i]->mName.string(), ret); return ret; } - compositionInfo->setExynosImage(src_img, dst_img); - compositionInfo->setExynosMidImage(dst_img); compositionInfo->mOtfMPP = mOtfMPPs[i]; display->mWindowNumUsed++; @@ -1083,7 +1064,7 @@ int32_t ExynosResourceManager::validateLayer(uint32_t index, ExynosDisplay *disp return eDynamicRecomposition; if ((layer->mLayerBuffer != NULL) && - (display->mDisplayId == getDisplayId(HWC_DISPLAY_PRIMARY, 0)) && + (display->mType == HWC_DISPLAY_PRIMARY) && (mForceReallocState != DST_REALLOC_DONE)) { ALOGI("Device type assign skipping by dst reallocation...... "); return eReallocOnGoingForDDI; @@ -1133,7 +1114,7 @@ int32_t ExynosResourceManager::validateLayer(uint32_t index, ExynosDisplay *disp } int32_t ExynosResourceManager::validateRCDLayer(const ExynosDisplay &display, - const ExynosLayer &layer, + const ExynosLayer &layer, const uint32_t layerIndex, const exynos_image &srcImg, const exynos_image &dstImg) { if (CC_UNLIKELY(srcImg.bufferHandle == NULL || srcImg.format != HAL_PIXEL_FORMAT_GOOGLE_R_8)) { @@ -1154,6 +1135,11 @@ int32_t ExynosResourceManager::validateRCDLayer(const ExynosDisplay &display, return eMPPUnsupported; } + // only support RCD Layers on the top + if (layerIndex != display.mLayers.size() - 1) { + return eMPPUnsupported; + } + // b/215335109: IMG_SIZE must be equal or larger than display output if (dstImg.x != 0 || dstImg.y != 0 || dstImg.w != display.mXres || dstImg.h != display.mYres) { return eInvalidDispFrame; @@ -1247,7 +1233,7 @@ void ExynosResourceManager::getCandidateScalingM2mMPPOutImages( const float otfSrcWidth = float(srcWidth / m2mMppRatio); const float scaleRatio_H = otfSrcWidth / float(dst_img.w); - const float otfSrcHeight = float(srcWidth / m2mMppRatio); + const float otfSrcHeight = float(srcHeight / m2mMppRatio); const float scaleRatio_V = otfSrcHeight / float(dst_img.h); const float displayRatio_V = float(dst_img.h) / float(display->mYres); const float resolution = otfSrcWidth * otfSrcHeight * display->getBtsRefreshRate() / 1000; @@ -1298,7 +1284,7 @@ void ExynosResourceManager::getCandidateScalingM2mMPPOutImages( dst_scale_img.h = uint32_t(ceilf(float(srcHeight) / float(m2mMppRatio))); } } - HDEBUGLOGD(eDebugResourceManager, + HDEBUGLOGD(eDebugResourceAssigning, "\tsrc[%d, %d, %d,%d], dst[%d, %d, %d,%d], mid[%d, %d, %d, %d]", src_img.x, src_img.y, src_img.w, src_img.h, dst_img.x, dst_img.y, dst_img.w, dst_img.h, dst_scale_img.x, dst_scale_img.y, dst_scale_img.w, dst_scale_img.h); @@ -1479,26 +1465,32 @@ int32_t ExynosResourceManager::assignLayer(ExynosDisplay *display, ExynosLayer * HDEBUGLOGD(eDebugResourceManager, "\t[%d] layer: validateFlag(0x%8x), supportedMPPFlag(0x%8x)", layer_index, validateFlag, layer->mSupportedMPPFlag); - if (hwcCheckDebugMessages(eDebugResourceManager)) { + if (hwcCheckDebugMessages(eDebugResourceAssigning)) { layer->printLayer(); } if ((validateFlag == NO_ERROR) || (validateFlag == eInsufficientWindow) || (validateFlag == eDimLayer)) { - bool isAssignable = false; + bool isAssignableFlag = false; uint64_t isSupported = 0; /* 1. Find available otfMPP */ if (validateFlag != eInsufficientWindow) { + otfMppReordering(display, mOtfMPPs, src_img, dst_img); + for (uint32_t j = 0; j < mOtfMPPs.size(); j++) { if ((layer->mSupportedMPPFlag & mOtfMPPs[j]->mLogicalType) != 0) - isAssignable = mOtfMPPs[j]->isAssignable(display, src_img, dst_img); + isAssignableFlag = isAssignable(mOtfMPPs[j], display, src_img, dst_img, layer); + + HDEBUGLOGD(eDebugResourceAssigning, + "\t\t check %s: flag (%d) supportedBit(%d), isAssignable(%d)", + mOtfMPPs[j]->mName.string(), layer->mSupportedMPPFlag, + (layer->mSupportedMPPFlag & mOtfMPPs[j]->mLogicalType), + isAssignableFlag); - HDEBUGLOGD(eDebugResourceManager, "\t\t check %s: flag (%d) supportedBit(%d), isAssignable(%d)", - mOtfMPPs[j]->mName.string(),layer->mSupportedMPPFlag, - (layer->mSupportedMPPFlag & mOtfMPPs[j]->mLogicalType), isAssignable); - if ((layer->mSupportedMPPFlag & mOtfMPPs[j]->mLogicalType) && (isAssignable)) { + if ((layer->mSupportedMPPFlag & mOtfMPPs[j]->mLogicalType) && (isAssignableFlag)) { isSupported = mOtfMPPs[j]->isSupported(*display, src_img, dst_img); - HDEBUGLOGD(eDebugResourceManager, "\t\t\t isSuported(%" PRIx64 ")", -isSupported); + HDEBUGLOGD(eDebugResourceAssigning, "\t\t\t isSupported(%" PRIx64 ")", + -isSupported); if (isSupported == NO_ERROR) { *otfMPP = mOtfMPPs[j]; return HWC2_COMPOSITION_DEVICE; @@ -1509,7 +1501,6 @@ int32_t ExynosResourceManager::assignLayer(ExynosDisplay *display, ExynosLayer * /* 2. Find available m2mMPP */ for (uint32_t j = 0; j < mM2mMPPs.size(); j++) { - if ((display->mUseDpu == true) && (mM2mMPPs[j]->mLogicalType == MPP_LOGICAL_G2D_COMBO)) continue; @@ -1523,16 +1514,19 @@ int32_t ExynosResourceManager::assignLayer(ExynosDisplay *display, ExynosLayer * if ((validateFlag == eInsufficientWindow) && (mM2mMPPs[j]->mLogicalType != MPP_LOGICAL_G2D_RGB) && (mM2mMPPs[j]->mLogicalType != MPP_LOGICAL_G2D_COMBO)) { - HDEBUGLOGD(eDebugResourceManager, "\t\tInsufficient window but exynosComposition is not assigned"); + HDEBUGLOGD(eDebugResourceAssigning, + "\t\tInsufficient window but exynosComposition is not assigned"); continue; } bool isAssignableState = mM2mMPPs[j]->isAssignableState(display, src_img, dst_img); - HDEBUGLOGD(eDebugResourceManager, "\t\t check %s: supportedBit(%d), isAssignableState(%d)", - mM2mMPPs[j]->mName.string(), - (layer->mSupportedMPPFlag & mM2mMPPs[j]->mLogicalType), isAssignableState); + HDEBUGLOGD(eDebugResourceAssigning, + "\t\t check %s: supportedBit(%d), isAssignableState(%d)", + mM2mMPPs[j]->mName.string(), + (layer->mSupportedMPPFlag & mM2mMPPs[j]->mLogicalType), isAssignableState); + float totalUsedCapa = ExynosResourceManager::getResourceUsedCapa(*mM2mMPPs[j]); if (isAssignableState) { if ((mM2mMPPs[j]->mLogicalType != MPP_LOGICAL_G2D_RGB) && (mM2mMPPs[j]->mLogicalType != MPP_LOGICAL_G2D_COMBO)) { @@ -1546,9 +1540,10 @@ int32_t ExynosResourceManager::assignLayer(ExynosDisplay *display, ExynosLayer * HWC_LOGE(display, "Fail getCandidateM2mMPPOutImages (%d)", ret); return ret; } - HDEBUGLOGD(eDebugResourceManager, "candidate M2mMPPOutImage num: %zu", image_lists.size()); + HDEBUGLOGD(eDebugResourceAssigning, "candidate M2mMPPOutImage num: %zu", + image_lists.size()); for (auto &otf_src_img : image_lists) { - dumpExynosImage(eDebugResourceManager, otf_src_img); + dumpExynosImage(eDebugResourceAssigning, otf_src_img); exynos_image m2m_src_img = src_img; /* transform is already handled by m2mMPP */ if (CC_UNLIKELY(otf_src_img.transform != 0 || otf_dst_img.transform != 0)) { @@ -1566,24 +1561,43 @@ int32_t ExynosResourceManager::assignLayer(ExynosDisplay *display, ExynosLayer * if (otf_src_img.needColorTransform) m2m_src_img.needColorTransform = false; - if (((isSupported = mM2mMPPs[j]->isSupported(*display, m2m_src_img, otf_src_img)) != NO_ERROR) || - ((isAssignable = mM2mMPPs[j]->hasEnoughCapa(display, m2m_src_img, otf_src_img)) == false)) - { - HDEBUGLOGD(eDebugResourceManager, "\t\t\t check %s: supportedBit(0x%" PRIx64 "), hasEnoughCapa(%d)", - mM2mMPPs[j]->mName.string(), -isSupported, isAssignable); + if (((isSupported = mM2mMPPs[j]->isSupported(*display, m2m_src_img, + otf_src_img)) != NO_ERROR) || + ((isAssignableFlag = + mM2mMPPs[j]->hasEnoughCapa(display, m2m_src_img, otf_src_img, + totalUsedCapa)) == false)) { + HDEBUGLOGD(eDebugResourceAssigning, + "\t\t\t check %s: supportedBit(0x%" PRIx64 + "), hasEnoughCapa(%d)", + mM2mMPPs[j]->mName.string(), -isSupported, isAssignableFlag); continue; } + otfMppReordering(display, mOtfMPPs, otf_src_img, otf_dst_img); + /* 3. Find available OtfMPP for output of m2mMPP */ for (uint32_t k = 0; k < mOtfMPPs.size(); k++) { isSupported = mOtfMPPs[k]->isSupported(*display, otf_src_img, otf_dst_img); - isAssignable = false; - if (isSupported == NO_ERROR) - isAssignable = mOtfMPPs[k]->isAssignable(display, otf_src_img, otf_dst_img); + isAssignableFlag = false; + if (isSupported == NO_ERROR) { + /* to prevent HW resource execeeded */ + ExynosCompositionInfo dpuSrcInfo; + dpuSrcInfo.mSrcImg = otf_src_img; + dpuSrcInfo.mDstImg = otf_dst_img; + HDEBUGLOGD(eDebugTDM, + "%s Composition target calculation start (candidates)", + __func__); + calculateHWResourceAmount(display, &dpuSrcInfo); + + isAssignableFlag = isAssignable(mOtfMPPs[k], display, otf_src_img, + otf_dst_img, &dpuSrcInfo); + } - HDEBUGLOGD(eDebugResourceManager, "\t\t\t check %s: supportedBit(0x%" PRIx64 "), isAssignable(%d)", - mOtfMPPs[k]->mName.string(), -isSupported, isAssignable); - if ((isSupported == NO_ERROR) && isAssignable) { + HDEBUGLOGD(eDebugResourceAssigning, + "\t\t\t check %s: supportedBit(0x%" PRIx64 + "), isAssignable(%d)", + mOtfMPPs[k]->mName.string(), -isSupported, isAssignableFlag); + if ((isSupported == NO_ERROR) && isAssignableFlag) { *m2mMPP = mM2mMPPs[j]; *otfMPP = mOtfMPPs[k]; m2m_out_img = otf_src_img; @@ -1593,12 +1607,16 @@ int32_t ExynosResourceManager::assignLayer(ExynosDisplay *display, ExynosLayer * } } else { if ((layer->mSupportedMPPFlag & mM2mMPPs[j]->mLogicalType) && - ((isAssignable = mM2mMPPs[j]->hasEnoughCapa(display, src_img, dst_img) == true))) { + ((isAssignableFlag = mM2mMPPs[j]->hasEnoughCapa(display, src_img, dst_img, + totalUsedCapa) == true))) { *m2mMPP = mM2mMPPs[j]; return HWC2_COMPOSITION_EXYNOS; } else { - HDEBUGLOGD(eDebugResourceManager, "\t\t\t check %s: layer's mSupportedMPPFlag(0x%8x), hasEnoughCapa(%d)", - mM2mMPPs[j]->mName.string(), layer->mSupportedMPPFlag, isAssignable); + HDEBUGLOGD(eDebugResourceManager, + "\t\t\t check %s: layer's mSupportedMPPFlag(0x%8x), " + "hasEnoughCapa(%d)", + mM2mMPPs[j]->mName.string(), layer->mSupportedMPPFlag, + isAssignableFlag); } } } @@ -1614,8 +1632,8 @@ int32_t ExynosResourceManager::assignLayer(ExynosDisplay *display, ExynosLayer * int32_t ExynosResourceManager::assignLayers(ExynosDisplay * display, uint32_t priority) { - HDEBUGLOGD(eDebugResourceManager, "%s:: display(%d), priority(%d) +++++", - __func__, display->mType, priority); + HDEBUGLOGD(eDebugResourceAssigning, "%s:: display(%d), priority(%d) +++++", __func__, + display->mType, priority); int32_t ret = NO_ERROR; bool needReAssign = false; @@ -1642,7 +1660,7 @@ int32_t ExynosResourceManager::assignLayers(ExynosDisplay * display, uint32_t pr // TODO: call validate function for RCD layer if (layer->mCompositionType == HWC2_COMPOSITION_DISPLAY_DECORATION && - validateRCDLayer(*display, *layer, src_img, dst_img) == NO_ERROR) { + validateRCDLayer(*display, *layer, i, src_img, dst_img) == NO_ERROR) { layer->mValidateCompositionType = HWC2_COMPOSITION_DISPLAY_DECORATION; continue; } @@ -1656,8 +1674,8 @@ int32_t ExynosResourceManager::assignLayers(ExynosDisplay * display, uint32_t pr __func__, otfMPP->mName.string(), ret); return ret; } - HDEBUGLOGD(eDebugResourceManager, "\t\t[%d] layer: %s MPP is assigned", - i, otfMPP->mName.string()); + HDEBUGLOGD(eDebugResourceAssigning, "\t\t[%d] layer: %s MPP is assigned", i, + otfMPP->mName.string()); } if (m2mMPP != NULL) { if ((ret = m2mMPP->assignMPP(display, layer)) != NO_ERROR) @@ -1667,14 +1685,15 @@ int32_t ExynosResourceManager::assignLayers(ExynosDisplay * display, uint32_t pr return ret; } layer->setExynosMidImage(m2m_out_img); - HDEBUGLOGD(eDebugResourceManager, "\t\t[%d] layer: %s MPP is assigned", - i, m2mMPP->mName.string()); + HDEBUGLOGD(eDebugResourceAssigning, "\t\t[%d] layer: %s MPP is assigned", i, + m2mMPP->mName.string()); } layer->mValidateCompositionType = compositionType; display->mWindowNumUsed++; - HDEBUGLOGD(eDebugResourceManager, "\t\t[%d] layer: mWindowNumUsed(%d)", - i, display->mWindowNumUsed); + HDEBUGLOGD(eDebugResourceAssigning, "\t\t[%d] layer: mWindowNumUsed(%d)", i, + display->mWindowNumUsed); } else if (compositionType == HWC2_COMPOSITION_EXYNOS) { + float totalUsedCapacity = 0; if (m2mMPP != NULL) { if ((ret = m2mMPP->assignMPP(display, layer)) != NO_ERROR) { @@ -1682,15 +1701,17 @@ int32_t ExynosResourceManager::assignLayers(ExynosDisplay * display, uint32_t pr __func__, m2mMPP->mName.string(), ret); return ret; } - HDEBUGLOGD(eDebugResourceManager, "\t\t[%d] layer: %s MPP is assigned", - i, m2mMPP->mName.string()); + totalUsedCapacity = getResourceUsedCapa(*m2mMPP); + HDEBUGLOGD(eDebugResourceAssigning, "\t\t[%d] layer: %s MPP is assigned", i, + m2mMPP->mName.string()); } layer->mValidateCompositionType = compositionType; - HDEBUGLOGD(eDebugResourceManager, "\t\t[%d] layer: exynosComposition", i); + HDEBUGLOGD(eDebugResourceAssigning, "\t\t[%d] layer: exynosComposition", i); /* G2D composition */ - if (((ret = display->addExynosCompositionLayer(i)) == EXYNOS_ERROR_CHANGED) || - (ret < 0)) + if (((ret = display->addExynosCompositionLayer(i, totalUsedCapacity)) == + EXYNOS_ERROR_CHANGED) || + (ret < 0)) return ret; else { /* @@ -1761,7 +1782,8 @@ int32_t ExynosResourceManager::assignWindow(ExynosDisplay *display) for (uint32_t i = 0; i < display->mLayers.size(); i++) { ExynosLayer *layer = display->mLayers[i]; - HDEBUGLOGD(eDebugResourceManager, "\t[%d] layer type: %d", i, layer->mValidateCompositionType); + HDEBUGLOGD(eDebugResourceAssigning, "\t[%d] layer type: %d", i, + layer->mValidateCompositionType); if (layer->mValidateCompositionType == HWC2_COMPOSITION_DEVICE) { layer->mWindowIndex = windowIndex; @@ -1811,10 +1833,10 @@ int32_t ExynosResourceManager::assignWindow(ExynosDisplay *display) int32_t ExynosResourceManager::updateSupportedMPPFlag(ExynosDisplay * display) { int64_t ret = 0; - HDEBUGLOGD(eDebugResourceManager, "%s++++++++++", __func__); + HDEBUGLOGD(eDebugResourceAssigning, "%s++++++++++", __func__); for (uint32_t i = 0; i < display->mLayers.size(); i++) { ExynosLayer *layer = display->mLayers[i]; - HDEBUGLOGD(eDebugResourceManager, "[%d] layer ", i); + HDEBUGLOGD(eDebugResourceAssigning, "[%d] layer ", i); if (layer->mGeometryChanged == 0) continue; @@ -1827,10 +1849,10 @@ int32_t ExynosResourceManager::updateSupportedMPPFlag(ExynosDisplay * display) layer->setDstExynosImage(&dst_img_yuv); dst_img.format = DEFAULT_MPP_DST_FORMAT; dst_img_yuv.format = DEFAULT_MPP_DST_YUV_FORMAT; - HDEBUGLOGD(eDebugResourceManager, "\tsrc_img"); - dumpExynosImage(eDebugResourceManager, src_img); - HDEBUGLOGD(eDebugResourceManager, "\tdst_img"); - dumpExynosImage(eDebugResourceManager, dst_img); + HDEBUGLOGD(eDebugResourceAssigning, "\tsrc_img"); + dumpExynosImage(eDebugResourceAssigning, src_img); + HDEBUGLOGD(eDebugResourceAssigning, "\tdst_img"); + dumpExynosImage(eDebugResourceAssigning, dst_img); /* Initialize flags */ layer->mSupportedMPPFlag = 0; @@ -1840,16 +1862,18 @@ int32_t ExynosResourceManager::updateSupportedMPPFlag(ExynosDisplay * display) for (uint32_t j = 0; j < mOtfMPPs.size(); j++) { if ((ret = mOtfMPPs[j]->isSupported(*display, src_img, dst_img)) == NO_ERROR) { layer->mSupportedMPPFlag |= mOtfMPPs[j]->mLogicalType; - HDEBUGLOGD(eDebugResourceManager, "\t%s: supported", mOtfMPPs[j]->mName.string()); + HDEBUGLOGD(eDebugResourceAssigning, "\t%s: supported", mOtfMPPs[j]->mName.string()); } else { if (((-ret) == eMPPUnsupportedFormat) && ((ret = mOtfMPPs[j]->isSupported(*display, src_img, dst_img_yuv)) == NO_ERROR)) { layer->mSupportedMPPFlag |= mOtfMPPs[j]->mLogicalType; - HDEBUGLOGD(eDebugResourceManager, "\t%s: supported with yuv dst", mOtfMPPs[j]->mName.string()); + HDEBUGLOGD(eDebugResourceAssigning, "\t%s: supported with yuv dst", + mOtfMPPs[j]->mName.string()); } } if (ret < 0) { - HDEBUGLOGD(eDebugResourceManager, "\t%s: unsupported flag(0x%" PRIx64 ")", mOtfMPPs[j]->mName.string(), -ret); + HDEBUGLOGD(eDebugResourceAssigning, "\t%s: unsupported flag(0x%" PRIx64 ")", + mOtfMPPs[j]->mName.string(), -ret); uint64_t checkFlag = 0x0; if (layer->mCheckMPPFlag.find(mOtfMPPs[j]->mLogicalType) != layer->mCheckMPPFlag.end()) { @@ -1864,16 +1888,18 @@ int32_t ExynosResourceManager::updateSupportedMPPFlag(ExynosDisplay * display) for (uint32_t j = 0; j < mM2mMPPs.size(); j++) { if ((ret = mM2mMPPs[j]->isSupported(*display, src_img, dst_img)) == NO_ERROR) { layer->mSupportedMPPFlag |= mM2mMPPs[j]->mLogicalType; - HDEBUGLOGD(eDebugResourceManager, "\t%s: supported", mM2mMPPs[j]->mName.string()); + HDEBUGLOGD(eDebugResourceAssigning, "\t%s: supported", mM2mMPPs[j]->mName.string()); } else { if (((-ret) == eMPPUnsupportedFormat) && ((ret = mM2mMPPs[j]->isSupported(*display, src_img, dst_img_yuv)) == NO_ERROR)) { layer->mSupportedMPPFlag |= mM2mMPPs[j]->mLogicalType; - HDEBUGLOGD(eDebugResourceManager, "\t%s: supported with yuv dst", mM2mMPPs[j]->mName.string()); + HDEBUGLOGD(eDebugResourceAssigning, "\t%s: supported with yuv dst", + mM2mMPPs[j]->mName.string()); } } if (ret < 0) { - HDEBUGLOGD(eDebugResourceManager, "\t%s: unsupported flag(0x%" PRIx64 ")", mM2mMPPs[j]->mName.string(), -ret); + HDEBUGLOGD(eDebugResourceAssigning, "\t%s: unsupported flag(0x%" PRIx64 ")", + mM2mMPPs[j]->mName.string(), -ret); uint64_t checkFlag = 0x0; if (layer->mCheckMPPFlag.find(mM2mMPPs[j]->mLogicalType) != layer->mCheckMPPFlag.end()) { @@ -1883,9 +1909,10 @@ int32_t ExynosResourceManager::updateSupportedMPPFlag(ExynosDisplay * display) layer->mCheckMPPFlag[mM2mMPPs[j]->mLogicalType] = checkFlag; } } - HDEBUGLOGD(eDebugResourceManager, "[%d] layer mSupportedMPPFlag(0x%8x)", i, layer->mSupportedMPPFlag); + HDEBUGLOGD(eDebugResourceAssigning, "[%d] layer mSupportedMPPFlag(0x%8x)", i, + layer->mSupportedMPPFlag); } - HDEBUGLOGD(eDebugResourceManager, "%s-------------", __func__); + HDEBUGLOGD(eDebugResourceAssigning, "%s-------------", __func__); return NO_ERROR; } @@ -1927,7 +1954,9 @@ int32_t ExynosResourceManager::preAssignResources() } if (mOtfMPPs[i]->mPreAssignDisplayList[displayMode] != 0) { - HDEBUGLOGD(eDebugResourceManager, "\t%s check, dispMode(%d), 0x%8x", mOtfMPPs[i]->mName.string(), displayMode, mOtfMPPs[i]->mPreAssignDisplayList[displayMode]); + HDEBUGLOGD(eDebugResourceAssigning, "\t%s check, dispMode(%d), 0x%8x", + mOtfMPPs[i]->mName.string(), displayMode, + mOtfMPPs[i]->mPreAssignDisplayList[displayMode]); ExynosDisplay *display = NULL; for (size_t j = 0; j < mDevice->mDisplays.size(); j++) { @@ -1935,14 +1964,19 @@ int32_t ExynosResourceManager::preAssignResources() if (display == nullptr) continue; int checkBit = mOtfMPPs[i]->mPreAssignDisplayList[displayMode] & display->getDisplayPreAssignBit(); - HDEBUGLOGD(eDebugResourceManager, "\t\tdisplay index(%zu), checkBit(%d)", j, checkBit); + HDEBUGLOGD(eDebugResourceAssigning, "\t\tdisplay index(%zu), checkBit(%d)", j, + checkBit); if (checkBit) { - HDEBUGLOGD(eDebugResourceManager, "\t\tdisplay index(%zu), displayId(%d), display(%p)", j, display->mDisplayId, display); + HDEBUGLOGD(eDebugResourceAssigning, + "\t\tdisplay index(%zu), displayId(%d), display(%p)", j, + display->mDisplayId, display); if (display->mDisplayControl.forceReserveMPP || (display->mPlugState && ((display->mType != HWC_DISPLAY_PRIMARY) || - (display->mPowerModeState != HWC2_POWER_MODE_OFF)))) { - HDEBUGLOGD(eDebugResourceManager, "\t\treserve to display %d", display->mDisplayId); + (display->mPowerModeState.has_value() && + (display->mPowerModeState.value() != HWC2_POWER_MODE_OFF))))) { + HDEBUGLOGD(eDebugResourceAssigning, "\t\treserve to display %d", + display->mDisplayId); mOtfMPPs[i]->reserveMPP(display->mDisplayId); break; } @@ -1962,21 +1996,26 @@ int32_t ExynosResourceManager::preAssignResources() mM2mMPPs[i]->reserveMPP(); continue; } - HDEBUGLOGD(eDebugResourceManager, "\t%s check, 0x%8x", mM2mMPPs[i]->mName.string(), mM2mMPPs[i]->mPreAssignDisplayList[displayMode]); + HDEBUGLOGD(eDebugResourceAssigning, "\t%s check, 0x%8x", mM2mMPPs[i]->mName.string(), + mM2mMPPs[i]->mPreAssignDisplayList[displayMode]); if (mM2mMPPs[i]->mPreAssignDisplayList[displayMode] != 0) { ExynosDisplay *display = NULL; for (size_t j = 0; j < mDevice->mDisplays.size(); j++) { display = mDevice->mDisplays[j]; int checkBit = mM2mMPPs[i]->mPreAssignDisplayList[displayMode] & display->getDisplayPreAssignBit(); - HDEBUGLOGD(eDebugResourceManager, "\t\tdisplay index(%zu), checkBit(%d)", j, checkBit); + HDEBUGLOGD(eDebugResourceAssigning, "\t\tdisplay index(%zu), checkBit(%d)", j, + checkBit); if (checkBit) { - HDEBUGLOGD(eDebugResourceManager, "\t\tdisplay index(%zu), displayId(%d), display(%p)", j, display->mDisplayId, display); + HDEBUGLOGD(eDebugResourceAssigning, + "\t\tdisplay index(%zu), displayId(%d), display(%p)", j, + display->mDisplayId, display); if ((display != NULL) && (display->mPlugState == true)) { - HDEBUGLOGD(eDebugResourceManager, "\t\treserve to display %d", display->mDisplayId); + HDEBUGLOGD(eDebugResourceAssigning, "\t\treserve to display %d", + display->mDisplayId); mM2mMPPs[i]->reserveMPP(display->mDisplayId); break; } else { - HDEBUGLOGD(eDebugResourceManager, "\t\treserve without display"); + HDEBUGLOGD(eDebugResourceAssigning, "\t\treserve without display"); mM2mMPPs[i]->reserveMPP(); } } @@ -2001,18 +2040,22 @@ int32_t ExynosResourceManager::preAssignResources() return NO_ERROR; } -void ExynosResourceManager::preAssignWindows() -{ - ExynosDisplay *display = NULL; - ExynosPrimaryDisplayModule *primaryDisplay = - (ExynosPrimaryDisplayModule *)mDevice->getDisplay(getDisplayId(HWC_DISPLAY_PRIMARY, 0)); +void ExynosResourceManager::preAssignWindows(ExynosDisplay *display) { + ExynosPrimaryDisplayModule *primaryDisplay = NULL; + + if (display->mType == HWC_DISPLAY_PRIMARY) { + primaryDisplay = (ExynosPrimaryDisplayModule *)display; + } else { + primaryDisplay = (ExynosPrimaryDisplayModule *)mDevice->getDisplay( + getDisplayId(HWC_DISPLAY_PRIMARY, 0)); + } + primaryDisplay->usePreDefinedWindow(false); for (size_t i = 1; i < mDevice->mDisplays.size(); i++) { - display = mDevice->mDisplays[i]; - if ((display == NULL) || (display->mType != HWC_DISPLAY_EXTERNAL)) - continue; - if (display->mPlugState == true) { + ExynosDisplay *disp = mDevice->mDisplays[i]; + if ((disp == NULL) || (display->mType != HWC_DISPLAY_EXTERNAL)) continue; + if (disp->mPlugState == true) { primaryDisplay->usePreDefinedWindow(true); } } @@ -2231,9 +2274,8 @@ float ExynosResourceManager::getResourceUsedCapa(ExynosMPP &mpp) if (mpp.mCapacity < 0) return usedCapa; - HDEBUGLOGD(eDebugResourceManager, "%s:: [%s][%d] mpp[%d, %d]", - __func__, mpp.mName.string(), mpp.mLogicalIndex, - mpp.mPhysicalType, mpp.mPhysicalIndex); + HDEBUGLOGD(eDebugResourceAssigning, "%s:: [%s][%d] mpp[%d, %d]", __func__, mpp.mName.string(), + mpp.mLogicalIndex, mpp.mPhysicalType, mpp.mPhysicalIndex); if (mpp.mMPPType == MPP_TYPE_OTF) { for (uint32_t i = 0; i < mOtfMPPs.size(); i++) { @@ -2251,8 +2293,8 @@ float ExynosResourceManager::getResourceUsedCapa(ExynosMPP &mpp) } } - HDEBUGLOGD(eDebugResourceManager, "\t[%s][%d] mpp usedCapa: %f", - mpp.mName.string(), mpp.mLogicalIndex, usedCapa); + HDEBUGLOGD(eDebugResourceAssigning, "\t[%s][%d] mpp usedCapa: %f", mpp.mName.string(), + mpp.mLogicalIndex, usedCapa); return usedCapa; } @@ -2308,7 +2350,7 @@ void ExynosResourceManager::setScaleDownRatio(uint32_t physicalType, } } -int32_t ExynosResourceManager::prepareResources() +int32_t ExynosResourceManager::prepareResources() { int ret = NO_ERROR; HDEBUGLOGD(eDebugResourceManager, "This is first validate"); @@ -2323,7 +2365,9 @@ int32_t ExynosResourceManager::prepareResources() return ret; } - return ret; + setDisplaysTDMInfo(); + + return ret; } int32_t ExynosResourceManager::finishAssignResourceWork() @@ -2353,7 +2397,7 @@ int32_t ExynosResourceManager::initResourcesState(ExynosDisplay *display) __func__, ret); return ret; } - preAssignWindows(); + preAssignWindows(display); } @@ -2483,8 +2527,8 @@ void ExynosResourceManager::makeAcrylRestrictions(mpp_phycal_type_t type){ mpp_phycal_type_t ExynosResourceManager::getPhysicalType(int ch) const { for (int i=0; i < MAX_DECON_DMA_TYPE; i++){ - if(IDMA_CHANNEL_MAP[i].channel == ch) - return IDMA_CHANNEL_MAP[i].type; + if(idma_channel_map[i].channel == ch) + return idma_channel_map[i].type; } return MPP_P_TYPE_MAX; @@ -2495,8 +2539,8 @@ ExynosMPP* ExynosResourceManager::getOtfMPPWithChannel(int ch) ExynosMPP *otfMPP = NULL; for (int i=0; i < MAX_DECON_DMA_TYPE; i++){ - if(IDMA_CHANNEL_MAP[i].channel == ch) { - otfMPP = getExynosMPP(IDMA_CHANNEL_MAP[i].type, IDMA_CHANNEL_MAP[i].index); + if(idma_channel_map[i].channel == ch) { + otfMPP = getExynosMPP(idma_channel_map[i].type, idma_channel_map[i].index); break; } } @@ -2624,3 +2668,84 @@ void ExynosResourceManager::setM2MCapa(uint32_t physicalType, uint32_t capa) mM2mMPPs[i]->mCapacity = capa; } } + +bool ExynosResourceManager::isAssignable(ExynosMPP *candidateMPP, ExynosDisplay *display, + struct exynos_image &src, struct exynos_image &dst, + ExynosMPPSource *mppSrc) +{ + bool ret = true; + + float totalUsedCapacity = getResourceUsedCapa(*candidateMPP); + ret = candidateMPP->isAssignable(display, src, dst, totalUsedCapacity); + + if ((ret) && (mppSrc != nullptr)) { + if ((candidateMPP->mMPPType == MPP_TYPE_OTF) && + (!isHWResourceAvailable(display, candidateMPP, mppSrc))) { + if (mppSrc->mSourceType == MPP_SOURCE_LAYER) { + ExynosLayer *layer = (ExynosLayer *)mppSrc; + layer->mCheckMPPFlag[candidateMPP->mLogicalType] = eMPPExeedHWResource; + } + ret = false; + } + } + + return ret; +} + +void ExynosResourceManager::updateSupportWCG() +{ + for (uint32_t i = 0; i < mOtfMPPs.size(); i++) { + if (mOtfMPPs[i] == NULL) continue; + if (mOtfMPPs[i]->mAttr & (MPP_ATTR_WCG | MPP_ATTR_HDR10)) mDeviceSupportWCG = true; + } + for (uint32_t i = 0; i < mM2mMPPs.size(); i++) { + if (mM2mMPPs[i] == NULL) continue; + if (mM2mMPPs[i]->mAttr & (MPP_ATTR_WCG | MPP_ATTR_HDR10)) mDeviceSupportWCG = true; + } +} + +bool ExynosResourceManager::needHdrProcessing(ExynosDisplay *display, exynos_image &srcImg, + exynos_image &dstImg) +{ + if (!deviceSupportWCG()) return false; + + return true; +} + +uint32_t ExynosResourceManager::needHWResource(ExynosDisplay *display, exynos_image &srcImg, + exynos_image &dstImg, tdm_attr_t attr) +{ + uint32_t ret = 0; + + switch (attr) { + case TDM_ATTR_SBWC: + ret = (isFormatSBWC(srcImg.format)) ? 1 : 0; + break; + case TDM_ATTR_AFBC: + ret = (srcImg.compressed) ? 1 : 0; + break; + case TDM_ATTR_ITP: + ret = (isFormatYUV(srcImg.format)) ? 1 : 0; + break; + case TDM_ATTR_WCG: + ret = (needHdrProcessing(display, srcImg, dstImg)) ? 1 : 0; + HDEBUGLOGD(eDebugTDM, "needHdrProcessing : %d", ret); + break; + case TDM_ATTR_ROT_90: + ret = ((srcImg.transform & HAL_TRANSFORM_ROT_90) == 0) ? 0 : 1; + break; + case TDM_ATTR_SCALE: { + bool isPerpendicular = !!(srcImg.transform & HAL_TRANSFORM_ROT_90); + if (isPerpendicular) { + ret = ((srcImg.w != dstImg.h) || (srcImg.h != dstImg.w)) ? 1 : 0; + } else { + ret = ((srcImg.w != dstImg.w) || (srcImg.h != dstImg.h)) ? 1 : 0; + } + } break; + default: + ret = 0; + break; + } + + return ret; +} diff --git a/libhwc2.1/libresource/ExynosResourceManager.h b/libhwc2.1/libresource/ExynosResourceManager.h index 11b24f6..e996554 100644 --- a/libhwc2.1/libresource/ExynosResourceManager.h +++ b/libhwc2.1/libresource/ExynosResourceManager.h @@ -38,18 +38,17 @@ class ExynosMPP; #define MAX_OVERLAY_LAYER_NUM 20 -#ifndef USE_MODULE_SW_FEATURE const std::map<mpp_phycal_type_t, uint64_t> sw_feature_table = { {MPP_DPP_G, MPP_ATTR_DIM}, {MPP_DPP_GF, MPP_ATTR_DIM}, + {MPP_DPP_GFS, MPP_ATTR_DIM}, {MPP_DPP_VG, MPP_ATTR_DIM}, {MPP_DPP_VGS, MPP_ATTR_DIM}, {MPP_DPP_VGF, MPP_ATTR_DIM}, {MPP_DPP_VGFS, MPP_ATTR_DIM}, {MPP_DPP_VGRFS, MPP_ATTR_DIM}, }; -#endif #ifndef USE_MODULE_DPU_ATTR_MAP const dpu_attr_map_t dpu_attr_map_table [] = @@ -133,12 +132,18 @@ class ExynosResourceManager { int32_t updateSupportedMPPFlag(ExynosDisplay * display); int32_t resetResources(); int32_t preAssignResources(); - void preAssignWindows(); + void preAssignWindows(ExynosDisplay *display); int32_t preProcessLayer(ExynosDisplay *display); int32_t resetAssignedResources(ExynosDisplay *display, bool forceReset = false); virtual int32_t assignCompositionTarget(ExynosDisplay *display, uint32_t targetType); int32_t validateLayer(uint32_t index, ExynosDisplay *display, ExynosLayer *layer); int32_t assignLayers(ExynosDisplay *display, uint32_t priority); + virtual int32_t otfMppReordering(ExynosDisplay *__unused display, + ExynosMPPVector __unused &otfMPPs, + struct exynos_image __unused &src, + struct exynos_image __unused &dst) { + return 0; + } virtual int32_t assignLayer(ExynosDisplay *display, ExynosLayer *layer, uint32_t layer_index, exynos_image &m2m_out_img, ExynosMPP **m2mMPP, ExynosMPP **otfMPP, uint32_t &overlayInfo); virtual int32_t assignWindow(ExynosDisplay *display); @@ -178,6 +183,8 @@ class ExynosResourceManager { void dump(String8 &result) const; void setM2MCapa(uint32_t physicalType, uint32_t capa); + bool isAssignable(ExynosMPP *candidateMPP, ExynosDisplay *display, struct exynos_image &src, + struct exynos_image &dst, ExynosMPPSource *mppSrc); private: int32_t changeLayerFromClientToDevice(ExynosDisplay *display, ExynosLayer *layer, @@ -195,11 +202,47 @@ class ExynosResourceManager { exynos_image getAlignedImage(exynos_image image, const ExynosMPP *m2mMpp, const ExynosMPP *otfMpp) const; int32_t validateRCDLayer(const ExynosDisplay &display, const ExynosLayer &layer, - const exynos_image &srcImg, const exynos_image &dstImg); + const uint32_t layerIndex, const exynos_image &srcImg, + const exynos_image &dstImg); static ExynosMPPVector mOtfMPPs; static ExynosMPPVector mM2mMPPs; uint32_t mResourceReserved; /* Set MPP logical type for bit operation */ float mMinimumSdrDimRatio; + + android::Vector<ExynosDisplay *> mDisplays; + std::map<uint32_t, ExynosDisplay *> mDisplayMap; + + protected: + bool mDeviceSupportWCG = false; + + public: + void initDisplays(android::Vector<ExynosDisplay *> displays, + std::map<uint32_t, ExynosDisplay *> displayMap) { + mDisplays = displays; + mDisplayMap = displayMap; + } + ExynosDisplay *getDisplay(uint32_t displayId) { return mDisplayMap[displayId]; } + + virtual void updateSupportWCG(); + virtual bool deviceSupportWCG() { return mDeviceSupportWCG; } + + /* return 1 if it's needed */ + bool needHdrProcessing(ExynosDisplay *display, exynos_image &srcImg, exynos_image &dstImg); + uint32_t needHWResource(ExynosDisplay *display, exynos_image &srcImg, exynos_image &dstImg, + tdm_attr_t attr); + + /* TDM (Time-Division Multiplexing) based Resource Management */ + virtual bool isHWResourceAvailable(ExynosDisplay __unused *display, + ExynosMPP __unused *currentMPP, + ExynosMPPSource __unused *mppSrc) { + return true; + } + virtual uint32_t setDisplaysTDMInfo() { return 0; } + virtual uint32_t initDisplaysTDMInfo() { return 0; } + virtual uint32_t calculateHWResourceAmount(ExynosDisplay __unused *display, + ExynosMPPSource __unused *mppSrc) { + return 0; + } }; #endif //_EXYNOSRESOURCEMANAGER_H diff --git a/libhwc2.1/libvirtualdisplay/ExynosVirtualDisplay.cpp b/libhwc2.1/libvirtualdisplay/ExynosVirtualDisplay.cpp index d6ce85f..1f16ec8 100644 --- a/libhwc2.1/libvirtualdisplay/ExynosVirtualDisplay.cpp +++ b/libhwc2.1/libvirtualdisplay/ExynosVirtualDisplay.cpp @@ -15,7 +15,7 @@ */ #undef LOG_TAG -#define LOG_TAG "virtualdisplay" +#define LOG_TAG "hwc-virt-display" #include "ExynosVirtualDisplay.h" #include "../libdevice/ExynosDevice.h" #include "../libdevice/ExynosLayer.h" @@ -28,13 +28,10 @@ using vendor::graphics::VendorGraphicBufferUsage; extern struct exynos_hwc_control exynosHWCControl; -ExynosVirtualDisplay::ExynosVirtualDisplay(uint32_t index, ExynosDevice *device) - : ExynosDisplay(index, device) -{ +ExynosVirtualDisplay::ExynosVirtualDisplay(uint32_t index, ExynosDevice* device, + const std::string& displayName) + : ExynosDisplay(HWC_DISPLAY_VIRTUAL, index, device, displayName) { /* Initialization */ - mType = HWC_DISPLAY_VIRTUAL; - mIndex = index; - mDisplayId = getDisplayId(mType, mIndex); mDisplayControl.earlyStartMPP = false; diff --git a/libhwc2.1/libvirtualdisplay/ExynosVirtualDisplay.h b/libhwc2.1/libvirtualdisplay/ExynosVirtualDisplay.h index 9e5daa8..786ff50 100644 --- a/libhwc2.1/libvirtualdisplay/ExynosVirtualDisplay.h +++ b/libhwc2.1/libvirtualdisplay/ExynosVirtualDisplay.h @@ -44,7 +44,7 @@ public: COMPOSITION_MIXED = COMPOSITION_GLES | COMPOSITION_HWC }; - ExynosVirtualDisplay(uint32_t index, ExynosDevice *device); + ExynosVirtualDisplay(uint32_t index, ExynosDevice* device, const std::string& displayName); ~ExynosVirtualDisplay(); void createVirtualDisplay(uint32_t width, uint32_t height, int32_t* format); diff --git a/libhwc2.1/pixel-display-default.xml b/libhwc2.1/pixel-display-default.xml index fc10d6a..7f2e4ba 100644 --- a/libhwc2.1/pixel-display-default.xml +++ b/libhwc2.1/pixel-display-default.xml @@ -1,7 +1,7 @@ <manifest version="1.0" type="device"> <hal format="aidl"> <name>com.google.hardware.pixel.display</name> - <version>6</version> + <version>8</version> <fqname>IDisplay/default</fqname> </hal> </manifest> diff --git a/libhwc2.1/pixel-display-secondary.xml b/libhwc2.1/pixel-display-secondary.xml new file mode 100644 index 0000000..ff313be --- /dev/null +++ b/libhwc2.1/pixel-display-secondary.xml @@ -0,0 +1,7 @@ +<manifest version="1.0" type="device"> + <hal format="aidl"> + <name>com.google.hardware.pixel.display</name> + <version>8</version> + <fqname>IDisplay/secondary</fqname> + </hal> +</manifest> diff --git a/libhwc2.1/pixel-display.cpp b/libhwc2.1/pixel-display.cpp index 629a137..366945a 100644 --- a/libhwc2.1/pixel-display.cpp +++ b/libhwc2.1/pixel-display.cpp @@ -24,19 +24,20 @@ #include <utils/Errors.h> #include "ExynosDisplay.h" +#include "ExynosPrimaryDisplay.h" extern int32_t load_png_image(const char *filepath, buffer_handle_t buffer); using ::aidl::com::google::hardware::pixel::display::Display; -void PixelDisplayInit(ExynosDevice *device) { +void PixelDisplayInit(ExynosDisplay *exynos_display, const std::string_view instance_str) { ABinderProcess_setThreadPoolMaxThreadCount(0); - std::shared_ptr<Display> display = ndk::SharedRefBase::make<Display>(device); - LOG(INFO) << "pixel display service start..."; - const std::string instance = std::string() + Display::descriptor + "/default"; + std::shared_ptr<Display> display = ndk::SharedRefBase::make<Display>(exynos_display); + const std::string instance = std::string() + Display::descriptor + "/" + std::string(instance_str).c_str(); binder_status_t status = AServiceManager_addService(display->asBinder().get(), instance.c_str()); + LOG(INFO) << instance.c_str() << " service start..."; CHECK(status == STATUS_OK); ABinderProcess_startThreadPool(); @@ -77,8 +78,8 @@ ndk::ScopedAStatus Display::getHbmState(HbmState *_aidl_return) { } ndk::ScopedAStatus Display::isLbeSupported(bool *_aidl_return) { - if (mDevice) { - *_aidl_return = mDevice->isLbeSupported(); + if (mDisplay) { + *_aidl_return = mDisplay->isLbeSupported(); return ndk::ScopedAStatus::ok(); } *_aidl_return = false; @@ -86,40 +87,40 @@ ndk::ScopedAStatus Display::isLbeSupported(bool *_aidl_return) { } ndk::ScopedAStatus Display::setLbeState(LbeState state) { - if (mDevice) { - mDevice->setLbeState(state); + if (mDisplay) { + mDisplay->setLbeState(state); return ndk::ScopedAStatus::ok(); } return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); } ndk::ScopedAStatus Display::setLbeAmbientLight(int ambientLux) { - if (mDevice) { - mDevice->setLbeAmbientLight(ambientLux); + if (mDisplay) { + mDisplay->setLbeAmbientLight(ambientLux); return ndk::ScopedAStatus::ok(); } return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); } ndk::ScopedAStatus Display::getLbeState(LbeState *_aidl_return) { - if (mDevice) { - *_aidl_return = mDevice->getLbeState(); + if (mDisplay) { + *_aidl_return = mDisplay->getLbeState(); return ndk::ScopedAStatus::ok(); } return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); } ndk::ScopedAStatus Display::isLhbmSupported(bool *_aidl_return) { - if (mDevice) { - *_aidl_return = mDevice->isLhbmSupported(); + if (mDisplay) { + *_aidl_return = mDisplay->isLhbmSupported(); return ndk::ScopedAStatus::ok(); } return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); } ndk::ScopedAStatus Display::setLhbmState(bool enabled) { - if (mDevice && mDevice->isLhbmSupported()) { - int32_t ret = mDevice->setLhbmState(enabled); + if (mDisplay && mDisplay->isLhbmSupported()) { + int32_t ret = mDisplay->setLhbmState(enabled); if (!ret) return ndk::ScopedAStatus::ok(); else if (ret == TIMED_OUT) @@ -129,8 +130,32 @@ ndk::ScopedAStatus Display::setLhbmState(bool enabled) { } ndk::ScopedAStatus Display::getLhbmState(bool *_aidl_return) { - if (mDevice && mDevice->isLhbmSupported()) { - *_aidl_return = mDevice->getLhbmState(); + if (mDisplay && mDisplay->isLhbmSupported()) { + *_aidl_return = mDisplay->getLhbmState(); + return ndk::ScopedAStatus::ok(); + } + return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); +} + +ndk::ScopedAStatus Display::setPeakRefreshRate(int rate) { + if (mDisplay && mDisplay->mOperationRateManager) { + mDisplay->mOperationRateManager->onPeakRefreshRate(rate); + return ndk::ScopedAStatus::ok(); + } + return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); +} + +ndk::ScopedAStatus Display::setLowPowerMode(bool enabled) { + if (mDisplay && mDisplay->mOperationRateManager) { + mDisplay->mOperationRateManager->onLowPowerMode(enabled); + return ndk::ScopedAStatus::ok(); + } + return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); +} + +ndk::ScopedAStatus Display::isOperationRateSupported(bool *_aidl_return) { + if (mDisplay) { + *_aidl_return = mDisplay->isOperationRateSupported(); return ndk::ScopedAStatus::ok(); } return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); @@ -139,7 +164,7 @@ ndk::ScopedAStatus Display::getLhbmState(bool *_aidl_return) { ndk::ScopedAStatus Display::setCompensationImageHandle(const NativeHandle &native_handle, const std::string &imageName, int *_aidl_return) { - if (mDevice && mDevice->isColorCalibratedByDevice()) { + if (mDisplay && mDisplay->isColorCalibratedByDevice()) { *_aidl_return = readCompensationImage(native_handle, imageName); } else { *_aidl_return = -1; @@ -148,35 +173,153 @@ ndk::ScopedAStatus Display::setCompensationImageHandle(const NativeHandle &nativ } ndk::ScopedAStatus Display::setMinIdleRefreshRate(int fps, int *_aidl_return) { - if (mDevice) { - *_aidl_return = mDevice->setMinIdleRefreshRate(fps); + if (mDisplay) { + *_aidl_return = mDisplay->setMinIdleRefreshRate(fps); return ndk::ScopedAStatus::ok(); } return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); } ndk::ScopedAStatus Display::setRefreshRateThrottle(int delayMs, int *_aidl_return) { - if (mDevice) { - *_aidl_return = mDevice->setRefreshRateThrottle(delayMs); + if (mDisplay) { + if (delayMs < 0) { + *_aidl_return = BAD_VALUE; + ALOGW("%s fail: delayMs(%d) is less than 0", __func__, delayMs); + return ndk::ScopedAStatus::ok(); + } + + *_aidl_return = + mDisplay->setRefreshRateThrottleNanos(std::chrono::duration_cast< + std::chrono::nanoseconds>( + std::chrono::milliseconds(delayMs)) + .count(), + VrrThrottleRequester::PIXEL_DISP); return ndk::ScopedAStatus::ok(); } return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); } +bool Display::runMediator(const RoiRect &roi, const Weight &weight, const HistogramPos &pos, + std::vector<char16_t> *histogrambuffer) { + bool isConfigChanged; + histogram::HistogramMediator::HistogramConfig pendingConfig(roi, weight, pos); + + { + std::unique_lock<std::mutex> lk(mMediator.mConfigMutex); + isConfigChanged = mMediator.mConfig != pendingConfig; + + if (isConfigChanged && + mMediator.setRoiWeightThreshold(roi, weight, pos) != HistogramErrorCode::NONE) { + ALOGE("histogram error, SET_ROI_WEIGHT_THRESHOLD ERROR\n"); + return false; + } + + mMediator.mConfig = pendingConfig; + } + + if (!mMediator.histRequested() && + mMediator.requestHist() == HistogramErrorCode::ENABLE_HIST_ERROR) { + ALOGE("histogram error, ENABLE_HIST ERROR\n"); + } + + /* + * DPU driver maintains always-on histogram engine state with up to date histogram data. + * Therefore we don't have explicitly to trigger onRefresh in case histogram configuration + * does not change. + */ + if (isConfigChanged) { + mDisplay->mDevice->onRefresh(mDisplay->mDisplayId); + } + + if (mMediator.collectRoiLuma(histogrambuffer) != HistogramErrorCode::NONE) { + ALOGE("histogram error, COLLECT_ROI_LUMA ERROR\n"); + return false; + } + return true; +} + ndk::ScopedAStatus Display::histogramSample(const RoiRect &roi, const Weight &weight, HistogramPos pos, Priority pri, std::vector<char16_t> *histogrambuffer, HistogramErrorCode *_aidl_return) { - return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); + if (!mDisplay) { + ALOGI("mDisplay is NULL \n"); + return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); + } + if (histogrambuffer == nullptr) { + ALOGE("histogrambuffer is null"); + *_aidl_return = HistogramErrorCode::BAD_HIST_DATA; + return ndk::ScopedAStatus::ok(); + } + if (mMediator.isDisplayPowerOff() == true) { + *_aidl_return = HistogramErrorCode::DISPLAY_POWEROFF; // panel is off + return ndk::ScopedAStatus::ok(); + } + if (mMediator.isSecureContentPresenting() == true) { + *_aidl_return = HistogramErrorCode::DRM_PLAYING; // panel is playing DRM content + return ndk::ScopedAStatus::ok(); + } + if ((roi.left < 0) || (roi.top < 0) || ((roi.right - roi.left) <= 0) || + ((roi.bottom - roi.top) <= 0)) { + *_aidl_return = HistogramErrorCode::BAD_ROI; + ALOGE("histogram error, BAD_ROI (%d, %d, %d, %d) \n", roi.left, roi.top, roi.right, + roi.bottom); + return ndk::ScopedAStatus::ok(); + } + if ((weight.weightR + weight.weightG + weight.weightB) != (histogram::WEIGHT_SUM)) { + *_aidl_return = HistogramErrorCode::BAD_WEIGHT; + ALOGE("histogram error, BAD_WEIGHT(%d, %d, %d)\n", weight.weightR, weight.weightG, + weight.weightB); + return ndk::ScopedAStatus::ok(); + } + if (pos != HistogramPos::POST && pos != HistogramPos::PRE) { + *_aidl_return = HistogramErrorCode::BAD_POSITION; + ALOGE("histogram error, BAD_POSITION(%d)\n", (int)pos); + return ndk::ScopedAStatus::ok(); + } + if (pri != Priority::NORMAL && pri != Priority::PRIORITY) { + *_aidl_return = HistogramErrorCode::BAD_PRIORITY; + ALOGE("histogram error, BAD_PRIORITY(%d)\n", (int)pri); + return ndk::ScopedAStatus::ok(); + } + RoiRect roiCaled = mMediator.calRoi(roi); // fit roi coordinates to RRS + runMediator(roiCaled, weight, pos, histogrambuffer); + if (mMediator.isSecureContentPresenting() == true) { + /* clear data to avoid leakage */ + std::fill(histogrambuffer->begin(), histogrambuffer->end(), 0); + histogrambuffer->clear(); + *_aidl_return = HistogramErrorCode::DRM_PLAYING; // panel is playing DRM content + return ndk::ScopedAStatus::ok(); + } + + *_aidl_return = HistogramErrorCode::NONE; + return ndk::ScopedAStatus::ok(); } ndk::ScopedAStatus Display::getPanelCalibrationStatus(PanelCalibrationStatus *_aidl_return){ - if (mDevice) { - *_aidl_return = mDevice->getPanelCalibrationStatus(); + if (mDisplay) { + *_aidl_return = mDisplay->getPanelCalibrationStatus(); return ndk::ScopedAStatus::ok(); } return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); } + +ndk::ScopedAStatus Display::isDbmSupported(bool *_aidl_return) { + if (!mDisplay) { + return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); + } + *_aidl_return = mDisplay->isDbmSupported(); + return ndk::ScopedAStatus::ok(); +} + +ndk::ScopedAStatus Display::setDbmState(bool enabled) { + if (!mDisplay) { + return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); + } + mDisplay->setDbmState(enabled); + return ndk::ScopedAStatus::ok(); +} + } // namespace display } // namespace pixel } // namespace hardware diff --git a/libhwc2.1/pixel-display.h b/libhwc2.1/pixel-display.h index 4ca69d7..df437af 100644 --- a/libhwc2.1/pixel-display.h +++ b/libhwc2.1/pixel-display.h @@ -18,6 +18,7 @@ #include <aidl/com/google/hardware/pixel/display/BnDisplay.h> +#include "./histogram_mediator.h" #include "ExynosDevice.h" namespace aidl { @@ -28,16 +29,16 @@ namespace pixel { namespace display { using aidl::android::hardware::common::NativeHandle; -using RoiRect = ::aidl::android::hardware::graphics::common::Rect; -using Weight = ::aidl::com::google::hardware::pixel::display::Weight; -using HistogramPos = ::aidl::com::google::hardware::pixel::display::HistogramPos; -using Priority = ::aidl::com::google::hardware::pixel::display::Priority; -using HistogramErrorCode = ::aidl::com::google::hardware::pixel::display::HistogramErrorCode; +using RoiRect = histogram::RoiRect; +using Weight = histogram::Weight; +using HistogramPos = histogram::HistogramPos; +using Priority = histogram::Priority; +using HistogramErrorCode = histogram::HistogramErrorCode; // Default implementation class Display : public BnDisplay { public: - Display(ExynosDevice *device) : mDevice(device){}; + Display(ExynosDisplay *display) : mDisplay(display), mMediator(display) {} ndk::ScopedAStatus isHbmSupported(bool *_aidl_return) override; ndk::ScopedAStatus setHbmState(HbmState state) override; @@ -58,9 +59,17 @@ public: Priority pri, std::vector<char16_t> *histogrambuffer, HistogramErrorCode *_aidl_return) override; ndk::ScopedAStatus getPanelCalibrationStatus(PanelCalibrationStatus *_aidl_return) override; + ndk::ScopedAStatus isDbmSupported(bool *_aidl_return) override; + ndk::ScopedAStatus setDbmState(bool enabled) override; + ndk::ScopedAStatus setPeakRefreshRate(int rate) override; + ndk::ScopedAStatus setLowPowerMode(bool enabled) override; + ndk::ScopedAStatus isOperationRateSupported(bool *_aidl_return) override; private: - ExynosDevice *mDevice = nullptr; + bool runMediator(const RoiRect &roi, const Weight &weight, const HistogramPos &pos, + std::vector<char16_t> *histogrambuffer); + ExynosDisplay *mDisplay = nullptr; + histogram::HistogramMediator mMediator; }; } // namespace display } // namespace pixel diff --git a/libhwjpeg/Android.bp b/libhwjpeg/Android.bp index 3ac4d6e..86dc84d 100644 --- a/libhwjpeg/Android.bp +++ b/libhwjpeg/Android.bp @@ -10,6 +10,7 @@ cc_library_shared { "AppMarkerWriter.cpp", "ExynosJpegEncoder.cpp", "ExynosJpegEncoderForCamera.cpp", + "FileLock.cpp", "hwjpeg-base.cpp", "hwjpeg-v4l2.cpp", "libhwjpeg-exynos.cpp", @@ -24,6 +25,9 @@ cc_library_shared { "libhardware_headers", "libsystem_headers", ], + export_header_lib_headers: [ + "google_hal_headers", + ], shared_libs: [ "liblog", "libutils", diff --git a/libhwjpeg/AppMarkerWriter.cpp b/libhwjpeg/AppMarkerWriter.cpp index 4a5edbb..f9eb12b 100644 --- a/libhwjpeg/AppMarkerWriter.cpp +++ b/libhwjpeg/AppMarkerWriter.cpp @@ -15,22 +15,22 @@ * limitations under the License. */ -#include "hwjpeg-internal.h" #include "AppMarkerWriter.h" + #include "IFDWriter.h" +#include "hwjpeg-internal.h" -static const char ExifAsciiPrefix[] = { 'A', 'S', 'C', 'I', 'I', 0x0, 0x0, 0x0 }; -static const char ExifIdentifierCode[6] = { 'E', 'x', 'i', 'f', 0x00, 0x00 }; -static char TiffHeader[8] = { 'I', 'I', 0x2A, 0x00, 0x08, 0x00, 0x00, 0x00 }; -static const unsigned char ComponentsConfiguration[4] = { 1, 2, 3, 0 }; // YCbCr -static const unsigned char SceneType[4] = { 1, 0, 0, 0 }; // A directly photographed image +static const char ExifAsciiPrefix[] = {'A', 'S', 'C', 'I', 'I', 0x0, 0x0, 0x0}; +static const char ExifIdentifierCode[6] = {'E', 'x', 'i', 'f', 0x00, 0x00}; +static char TiffHeader[8] = {'I', 'I', 0x2A, 0x00, 0x08, 0x00, 0x00, 0x00}; +static const unsigned char ComponentsConfiguration[4] = {1, 2, 3, 0}; // YCbCr +static const unsigned char SceneType[4] = {1, 0, 0, 0}; // A directly photographed image #ifndef __LITTLE_ENDIAN__ CEndianessChecker __LITTLE_ENDIAN__; #endif -CEndianessChecker::CEndianessChecker() -{ +CEndianessChecker::CEndianessChecker() { int num = 1; __little = (*reinterpret_cast<char *>(&num) == 1); if (__little) { @@ -42,15 +42,12 @@ CEndianessChecker::CEndianessChecker() } } - CAppMarkerWriter::CAppMarkerWriter() - : m_pAppBase(NULL), m_pApp1End(NULL), m_pExif(NULL), m_pExtra(NULL) -{ + : m_pAppBase(NULL), m_pApp1End(NULL), m_pExif(NULL), m_pExtra(NULL) { Init(); } -CAppMarkerWriter::CAppMarkerWriter(char *base, exif_attribute_t *exif, debug_attribute_t *debug) -{ +CAppMarkerWriter::CAppMarkerWriter(char *base, exif_attribute_t *exif, debug_attribute_t *debug) { extra_appinfo_t extraInfo; app_info_t appInfo[15]; @@ -64,8 +61,7 @@ CAppMarkerWriter::CAppMarkerWriter(char *base, exif_attribute_t *exif, debug_att PrepareAppWriter(base, exif, &extraInfo); } -void CAppMarkerWriter::Init() -{ +void CAppMarkerWriter::Init() { m_pApp1End = NULL; m_szApp1 = 0; @@ -85,8 +81,8 @@ void CAppMarkerWriter::Init() m_pThumbSizePlaceholder = NULL; } -void CAppMarkerWriter::PrepareAppWriter(char *base, exif_attribute_t *exif, extra_appinfo_t *extra) -{ +void CAppMarkerWriter::PrepareAppWriter(char *base, exif_attribute_t *exif, + extra_appinfo_t *extra) { m_pAppBase = base; m_pExif = exif; @@ -96,8 +92,7 @@ void CAppMarkerWriter::PrepareAppWriter(char *base, exif_attribute_t *exif, extr if (exif) { // APP1 - applen += JPEG_SEGMENT_LENFIELD_SIZE + - ARRSIZE(ExifIdentifierCode) + ARRSIZE(TiffHeader); + applen += JPEG_SEGMENT_LENFIELD_SIZE + ARRSIZE(ExifIdentifierCode) + ARRSIZE(TiffHeader); // 0th IFD: Make, Model, Orientation, Software, // DateTime, YCbCrPositioning, X/Y Resolutions, Exif and GPS @@ -112,24 +107,21 @@ void CAppMarkerWriter::PrepareAppWriter(char *base, exif_attribute_t *exif, extr if (m_szMake > 0) { m_n0thIFDFields++; applen += IFD_FIELD_SIZE; - if (m_szMake > 3) - applen += m_szMake + 1; + if (m_szMake > 3) applen += m_szMake + 1; } m_szSoftware = strlen(m_pExif->software); if (m_szSoftware > 0) { m_n0thIFDFields++; applen += IFD_FIELD_SIZE; - if (m_szSoftware > 3) - applen += m_szSoftware + 1; + if (m_szSoftware > 3) applen += m_szSoftware + 1; } m_szModel = strlen(m_pExif->model); if (m_szModel > 0) { m_n0thIFDFields++; applen += IFD_FIELD_SIZE; - if (m_szModel > 3) - applen += m_szModel + 1; + if (m_szModel > 3) applen += m_szModel + 1; } if (m_pExif->enableGps) { @@ -144,11 +136,11 @@ void CAppMarkerWriter::PrepareAppWriter(char *base, exif_attribute_t *exif, extr * - Flash, FlashPixVersion, ColorSpace, PixelXDimension, PixelYDimension, * - ExposureMode, WhiteBalance, FocalLengthIn35mmFilm, SceneCaptureType, * - ComponentsConfiguration - * - SceneType, CustomRendered, Contrast, Saturation, Sharpness + * - SceneType, CustomRendered, Contrast, Saturation, Sharpness * (S)Rational Fields: 9 * - ExposureTime, FNumber, ShutterSpeedValue, ApertureValue, * - BrightnessValue, ExposureBiasValue, MaxApertureValue, FocalLength - * - DigitalZoomRatio + * - DigitalZoomRatio * ASCII Fields: 6 * - DateTimeOriginal, DateTimeDigitized, SubsecTime, SubsecTimeOriginal, * - SubsecTimeDigitized, ImageUniqueID @@ -174,28 +166,24 @@ void CAppMarkerWriter::PrepareAppWriter(char *base, exif_attribute_t *exif, extr if (m_szUniqueID > 0) { m_nExifIFDFields++; applen += IFD_FIELD_SIZE; - if (m_szUniqueID > 3) - applen += m_szUniqueID + 1; + if (m_szUniqueID > 3) applen += m_szUniqueID + 1; } if (m_pExif->maker_note_size > 0) { m_nExifIFDFields++; applen += IFD_FIELD_SIZE; - if (m_pExif->maker_note_size > 4) - applen += m_pExif->maker_note_size; + if (m_pExif->maker_note_size > 4) applen += m_pExif->maker_note_size; } if (m_pExif->user_comment_size > 0) { m_nExifIFDFields++; applen += IFD_FIELD_SIZE; - if (m_pExif->user_comment_size > 4) - applen += m_pExif->user_comment_size; + if (m_pExif->user_comment_size > 4) applen += m_pExif->user_comment_size; } // Interoperability SubIFD m_nExifIFDFields++; // Interoperability is sub IFD of Exif sub IFD - applen += IFD_FIELD_SIZE + - IFD_FIELDCOUNT_SIZE + IFD_VALOFF_SIZE + IFD_FIELD_SIZE * 2; + applen += IFD_FIELD_SIZE + IFD_FIELDCOUNT_SIZE + IFD_VALOFF_SIZE + IFD_FIELD_SIZE * 2; if (m_pExif->enableGps) { size_t len; @@ -233,8 +221,8 @@ void CAppMarkerWriter::PrepareAppWriter(char *base, exif_attribute_t *exif, extr * - JPEGInterchangeFormat, JPEGInterchangeFormatLength */ if ((m_pExif->widthThumb < 16) || (m_pExif->heightThumb < 16)) { - ALOGE("Insufficient thumbnail information %dx%d", - m_pExif->widthThumb, m_pExif->heightThumb); + ALOGE("Insufficient thumbnail information %dx%d", m_pExif->widthThumb, + m_pExif->heightThumb); return; } @@ -251,13 +239,17 @@ void CAppMarkerWriter::PrepareAppWriter(char *base, exif_attribute_t *exif, extr if (extra) { for (int idx = 0; idx < extra->num_of_appmarker; idx++) { - if ((extra->appInfo[idx].appid < EXTRA_APPMARKER_MIN) || (extra->appInfo[idx].appid >= EXTRA_APPMARKER_LIMIT)) { + if ((extra->appInfo[idx].appid < EXTRA_APPMARKER_MIN) || + (extra->appInfo[idx].appid >= EXTRA_APPMARKER_LIMIT)) { ALOGE("Invalid extra APP segment ID %d", extra->appInfo[idx].appid); return; } - if ((extra->appInfo[idx].dataSize == 0) || (extra->appInfo[idx].dataSize > (JPEG_MAX_SEGMENT_SIZE - JPEG_SEGMENT_LENFIELD_SIZE))) { - ALOGE("Invalid APP%d segment size, %u bytes", extra->appInfo[idx].appid, extra->appInfo[idx].dataSize); + if ((extra->appInfo[idx].dataSize == 0) || + (extra->appInfo[idx].dataSize > + (JPEG_MAX_SEGMENT_SIZE - JPEG_SEGMENT_LENFIELD_SIZE))) { + ALOGE("Invalid APP%d segment size, %u bytes", extra->appInfo[idx].appid, + extra->appInfo[idx].dataSize); return; } @@ -268,7 +260,7 @@ void CAppMarkerWriter::PrepareAppWriter(char *base, exif_attribute_t *exif, extr m_pExtra = extra; // |<- m_szApp1 ->|<- m_szMaxThumbSize ->|<-m_szAppX->| - // |<----- size of total APP1 and APP4 segments ----->|<-APP11->|<-- main image + // |<----- size of total APP1 and APPX segments ----->|<-APP11->|<-- main image // m_pAppBase m_pThumbBase | | return // | | | | || // v v | | v| @@ -283,20 +275,16 @@ void CAppMarkerWriter::PrepareAppWriter(char *base, exif_attribute_t *exif, extr } #define APPMARKLEN (JPEG_MARKER_SIZE + JPEG_SEGMENT_LENFIELD_SIZE) -char *CAppMarkerWriter::WriteAPP11(char *current, size_t dummy, size_t align) -{ +char *CAppMarkerWriter::WriteAPP11(char *current, size_t dummy, size_t align) { ALOG_ASSERT((align & ~align) == 0); - if ((dummy == 0) && (align == 1)) - return current; + if ((dummy == 0) && (align == 1)) return current; - if (!m_pExif && !m_pExtra) - return current; + if (!m_pExif && !m_pExtra) return current; uint16_t len = PTR_TO_ULONG(current + APPMARKLEN) & (align - 1); - if (len) - len = align - len; + if (len) len = align - len; len += dummy + JPEG_SEGMENT_LENFIELD_SIZE; @@ -307,10 +295,8 @@ char *CAppMarkerWriter::WriteAPP11(char *current, size_t dummy, size_t align) return current + len; } -char *CAppMarkerWriter::WriteAPPX(char *current, bool just_reserve) -{ - if (!m_pExtra) - return current; +char *CAppMarkerWriter::WriteAPPX(char *current, bool just_reserve) { + if (!m_pExtra) return current; for (int idx = 0; idx < m_pExtra->num_of_appmarker; idx++) { int appid = m_pExtra->appInfo[idx].appid; @@ -330,10 +316,8 @@ char *CAppMarkerWriter::WriteAPPX(char *current, bool just_reserve) return current; } -char *CAppMarkerWriter::WriteAPP1(char *current, bool reserve_thumbnail_space, bool updating) -{ - if (!m_pExif) - return current; +char *CAppMarkerWriter::WriteAPP1(char *current, bool reserve_thumbnail_space, bool updating) { + if (!m_pExif) return current; // APP1 Marker *current++ = 0xFF; @@ -344,18 +328,15 @@ char *CAppMarkerWriter::WriteAPP1(char *current, bool reserve_thumbnail_space, b current += JPEG_SEGMENT_LENFIELD_SIZE; } else { uint16_t len = m_szApp1; - if (reserve_thumbnail_space) - len += m_szMaxThumbSize + JPEG_APP1_OEM_RESERVED; + if (reserve_thumbnail_space) len += m_szMaxThumbSize + JPEG_APP1_OEM_RESERVED; current = WriteDataInBig(current, len); } // Exif Identifier - for (size_t i = 0; i < ARRSIZE(ExifIdentifierCode); i++) - *current++ = ExifIdentifierCode[i]; + for (size_t i = 0; i < ARRSIZE(ExifIdentifierCode); i++) *current++ = ExifIdentifierCode[i]; char *tiffheader = current; - for (size_t i = 0; i < ARRSIZE(TiffHeader); i++) - *current++ = TiffHeader[i]; + for (size_t i = 0; i < ARRSIZE(TiffHeader); i++) *current++ = TiffHeader[i]; CIFDWriter writer(tiffheader, current, m_n0thIFDFields); @@ -364,12 +345,9 @@ char *CAppMarkerWriter::WriteAPP1(char *current, bool reserve_thumbnail_space, b writer.WriteRational(EXIF_TAG_X_RESOLUTION, 1, &m_pExif->x_resolution); writer.WriteRational(EXIF_TAG_Y_RESOLUTION, 1, &m_pExif->y_resolution); writer.WriteShort(EXIF_TAG_RESOLUTION_UNIT, 1, &m_pExif->resolution_unit); - if (m_szMake > 0) - writer.WriteASCII(EXIF_TAG_MAKE, m_szMake + 1, m_pExif->maker); - if (m_szModel > 0) - writer.WriteASCII(EXIF_TAG_MODEL, m_szModel + 1, m_pExif->model); - if (m_szSoftware > 0) - writer.WriteASCII(EXIF_TAG_SOFTWARE, m_szSoftware + 1, m_pExif->software); + if (m_szMake > 0) writer.WriteASCII(EXIF_TAG_MAKE, m_szMake + 1, m_pExif->maker); + if (m_szModel > 0) writer.WriteASCII(EXIF_TAG_MODEL, m_szModel + 1, m_pExif->model); + if (m_szSoftware > 0) writer.WriteASCII(EXIF_TAG_SOFTWARE, m_szSoftware + 1, m_pExif->software); writer.WriteCString(EXIF_TAG_DATE_TIME, EXIF_DATETIME_LENGTH, m_pExif->date_time); char *pSubIFDBase = writer.BeginSubIFD(EXIF_TAG_EXIF_IFD_POINTER); @@ -379,9 +357,11 @@ char *CAppMarkerWriter::WriteAPP1(char *current, bool reserve_thumbnail_space, b exifwriter.WriteRational(EXIF_TAG_FNUMBER, 1, &m_pExif->fnumber); exifwriter.WriteShort(EXIF_TAG_EXPOSURE_PROGRAM, 1, &m_pExif->exposure_program); exifwriter.WriteShort(EXIF_TAG_ISO_SPEED_RATING, 1, &m_pExif->iso_speed_rating); - exifwriter.WriteUndef(EXIF_TAG_EXIF_VERSION, 4, reinterpret_cast<unsigned char *>(m_pExif->exif_version)); + exifwriter.WriteUndef(EXIF_TAG_EXIF_VERSION, 4, + reinterpret_cast<unsigned char *>(m_pExif->exif_version)); exifwriter.WriteCString(EXIF_TAG_DATE_TIME_ORG, EXIF_DATETIME_LENGTH, m_pExif->date_time); - exifwriter.WriteCString(EXIF_TAG_DATE_TIME_DIGITIZE, EXIF_DATETIME_LENGTH, m_pExif->date_time); + exifwriter.WriteCString(EXIF_TAG_DATE_TIME_DIGITIZE, EXIF_DATETIME_LENGTH, + m_pExif->date_time); exifwriter.WriteSRational(EXIF_TAG_SHUTTER_SPEED, 1, &m_pExif->shutter_speed); exifwriter.WriteRational(EXIF_TAG_APERTURE, 1, &m_pExif->aperture); exifwriter.WriteSRational(EXIF_TAG_BRIGHTNESS, 1, &m_pExif->brightness); @@ -389,16 +369,21 @@ char *CAppMarkerWriter::WriteAPP1(char *current, bool reserve_thumbnail_space, b exifwriter.WriteRational(EXIF_TAG_MAX_APERTURE, 1, &m_pExif->max_aperture); exifwriter.WriteShort(EXIF_TAG_METERING_MODE, 1, &m_pExif->metering_mode); exifwriter.WriteShort(EXIF_TAG_FLASH, 1, &m_pExif->flash); - exifwriter.WriteUndef(EXIF_TAG_FLASHPIX_VERSION, 4, reinterpret_cast<const unsigned char *>("0100")); + exifwriter.WriteUndef(EXIF_TAG_FLASHPIX_VERSION, 4, + reinterpret_cast<const unsigned char *>("0100")); exifwriter.WriteUndef(EXIF_TAG_COMPONENTS_CONFIGURATION, 4, ComponentsConfiguration); exifwriter.WriteRational(EXIF_TAG_FOCAL_LENGTH, 1, &m_pExif->focal_length); exifwriter.WriteCString(EXIF_TAG_SUBSEC_TIME, EXIF_SUBSECTIME_LENGTH, m_pExif->sec_time); - exifwriter.WriteCString(EXIF_TAG_SUBSEC_TIME_ORIG, EXIF_SUBSECTIME_LENGTH, m_pExif->sec_time); - exifwriter.WriteCString(EXIF_TAG_SUBSEC_TIME_DIG, EXIF_SUBSECTIME_LENGTH, m_pExif->sec_time); + exifwriter.WriteCString(EXIF_TAG_SUBSEC_TIME_ORIG, EXIF_SUBSECTIME_LENGTH, + m_pExif->sec_time); + exifwriter.WriteCString(EXIF_TAG_SUBSEC_TIME_DIG, EXIF_SUBSECTIME_LENGTH, + m_pExif->sec_time); if (m_pExif->maker_note_size > 0) - exifwriter.WriteUndef(EXIF_TAG_MAKER_NOTE, m_pExif->maker_note_size, m_pExif->maker_note); + exifwriter.WriteUndef(EXIF_TAG_MAKER_NOTE, m_pExif->maker_note_size, + m_pExif->maker_note); if (m_pExif->user_comment_size > 0) - exifwriter.WriteUndef(EXIF_TAG_USER_COMMENT, m_pExif->user_comment_size, m_pExif->user_comment); + exifwriter.WriteUndef(EXIF_TAG_USER_COMMENT, m_pExif->user_comment_size, + m_pExif->user_comment); exifwriter.WriteShort(EXIF_TAG_COLOR_SPACE, 1, &m_pExif->color_space); exifwriter.WriteLong(EXIF_TAG_PIXEL_X_DIMENSION, 1, &m_pExif->width); exifwriter.WriteLong(EXIF_TAG_PIXEL_Y_DIMENSION, 1, &m_pExif->height); @@ -407,7 +392,8 @@ char *CAppMarkerWriter::WriteAPP1(char *current, bool reserve_thumbnail_space, b exifwriter.WriteShort(EXIF_TAG_EXPOSURE_MODE, 1, &m_pExif->exposure_mode); exifwriter.WriteShort(EXIF_TAG_WHITE_BALANCE, 1, &m_pExif->white_balance); exifwriter.WriteRational(EXIF_TAG_DIGITAL_ZOOM_RATIO, 1, &m_pExif->digital_zoom_ratio); - exifwriter.WriteShort(EXIF_TAG_FOCA_LENGTH_IN_35MM_FILM, 1, &m_pExif->focal_length_in_35mm_length); + exifwriter.WriteShort(EXIF_TAG_FOCA_LENGTH_IN_35MM_FILM, 1, + &m_pExif->focal_length_in_35mm_length); exifwriter.WriteShort(EXIF_TAG_SCENCE_CAPTURE_TYPE, 1, &m_pExif->scene_capture_type); exifwriter.WriteShort(EXIF_TAG_CONTRAST, 1, &m_pExif->contrast); exifwriter.WriteShort(EXIF_TAG_SATURATION, 1, &m_pExif->saturation); @@ -451,9 +437,9 @@ char *CAppMarkerWriter::WriteAPP1(char *current, bool reserve_thumbnail_space, b size_t idx; len = min(len, static_cast<size_t>(99UL)); unsigned char buf[sizeof(ExifAsciiPrefix) + len + 1]; - for (idx = 0; idx < sizeof(ExifAsciiPrefix); idx++) - buf[idx] = ExifAsciiPrefix[idx]; - strncpy(reinterpret_cast<char *>(buf) + idx, m_pExif->gps_processing_method, len + 1); + for (idx = 0; idx < sizeof(ExifAsciiPrefix); idx++) buf[idx] = ExifAsciiPrefix[idx]; + strncpy(reinterpret_cast<char *>(buf) + idx, m_pExif->gps_processing_method, + len + 1); len += idx; buf[len] = '\0'; gpswriter.WriteUndef(EXIF_TAG_GPS_PROCESSING_METHOD, len + 1, buf); @@ -466,8 +452,7 @@ char *CAppMarkerWriter::WriteAPP1(char *current, bool reserve_thumbnail_space, b } // thumbnail and the next IFD pointer is never updated. - if (updating) - return NULL; + if (updating) return NULL; if (m_pExif->enableThumb) { writer.Finish(false); @@ -496,16 +481,14 @@ char *CAppMarkerWriter::WriteAPP1(char *current, bool reserve_thumbnail_space, b return writer.GetNextIFDBase(); } -void CAppMarkerWriter::Finalize(size_t thumbsize) -{ +void CAppMarkerWriter::Finalize(size_t thumbsize) { if (m_pThumbSizePlaceholder) { uint32_t len = static_cast<uint32_t>(thumbsize); WriteData(m_pThumbSizePlaceholder, len); m_pThumbSizePlaceholder = NULL; } } -void CAppMarkerWriter::UpdateApp1Size(size_t amount) -{ +void CAppMarkerWriter::UpdateApp1Size(size_t amount) { if (m_pAppBase) { uint16_t len = m_szApp1 + amount; WriteDataInBig(m_pAppBase + JPEG_MARKER_SIZE, len); @@ -514,24 +497,25 @@ void CAppMarkerWriter::UpdateApp1Size(size_t amount) static const char *dbgerrmsg = "Updating debug data failed"; -static inline size_t GetSegLen(char *p) -{ +static inline size_t GetSegLen(char *p) { size_t len = (*reinterpret_cast<unsigned char *>(p) & 0xFF) << 8; return len | (*reinterpret_cast<unsigned char *>(p + 1) & 0xFF); } -static inline size_t GetExtraAPPSize(extra_appinfo_t *info) -{ +static inline size_t GetExtraAPPSize(extra_appinfo_t *info) { size_t len = 0; for (int idx = 0; idx < info->num_of_appmarker; idx++) { - if ((info->appInfo[idx].appid < EXTRA_APPMARKER_MIN) || (info->appInfo[idx].appid >= EXTRA_APPMARKER_LIMIT)) { + if ((info->appInfo[idx].appid < EXTRA_APPMARKER_MIN) || + (info->appInfo[idx].appid >= EXTRA_APPMARKER_LIMIT)) { ALOGE("%s: Invalid extra APP segment ID %d", dbgerrmsg, info->appInfo[idx].appid); return 0; } - if ((info->appInfo[idx].dataSize == 0) || (info->appInfo[idx].dataSize > (JPEG_MAX_SEGMENT_SIZE - JPEG_SEGMENT_LENFIELD_SIZE))) { - ALOGE("%s: Invalid APP%d segment size, %u bytes.", dbgerrmsg, info->appInfo[idx].appid, info->appInfo[idx].dataSize); + if ((info->appInfo[idx].dataSize == 0) || + (info->appInfo[idx].dataSize > (JPEG_MAX_SEGMENT_SIZE - JPEG_SEGMENT_LENFIELD_SIZE))) { + ALOGE("%s: Invalid APP%d segment size, %u bytes.", dbgerrmsg, info->appInfo[idx].appid, + info->appInfo[idx].dataSize); return 0; } @@ -594,34 +578,33 @@ bool UpdateDebugData(char *jpeg, size_t jpeglen, extra_appinfo_t *extra) // incl } appid = marker & 0xF; - if (((marker & 0xF0) == 0xE0) && ((appid >= EXTRA_APPMARKER_MIN) && (appid <= EXTRA_APPMARKER_LIMIT))) { + if (((marker & 0xF0) == 0xE0) && + ((appid >= EXTRA_APPMARKER_MIN) && (appid <= EXTRA_APPMARKER_LIMIT))) { if (appid != extra->appInfo[idx].appid) { - ALOGE("%s: stored appid(%d) is different with updated appid(%d)", - dbgerrmsg, appid, extra->appInfo[idx].appid); + ALOGE("%s: stored appid(%d) is different with updated appid(%d)", dbgerrmsg, appid, + extra->appInfo[idx].appid); return false; } seglen = GetSegLen(jpeg); if (seglen < (extra->appInfo[idx].dataSize + JPEG_SEGMENT_LENFIELD_SIZE)) { - ALOGE("%s: too small APP%d length %zu to store %u bytes", - dbgerrmsg, appid, seglen, extra->appInfo[idx].dataSize); + ALOGE("%s: too small APP%d length %zu to store %u bytes", dbgerrmsg, appid, seglen, + extra->appInfo[idx].dataSize); return false; } - memcpy(jpeg + JPEG_SEGMENT_LENFIELD_SIZE, - extra->appInfo[idx].appData, extra->appInfo[idx].dataSize); + memcpy(jpeg + JPEG_SEGMENT_LENFIELD_SIZE, extra->appInfo[idx].appData, + extra->appInfo[idx].dataSize); ALOGD("Successfully updated %u bytes to APP%d", extra->appInfo[idx].dataSize, appid); - validlen -= extra->appInfo[idx].dataSize + JPEG_MARKER_SIZE + JPEG_SEGMENT_LENFIELD_SIZE; + validlen -= + extra->appInfo[idx].dataSize + JPEG_MARKER_SIZE + JPEG_SEGMENT_LENFIELD_SIZE; idx++; } else { // just skip all other segments seglen = GetSegLen(jpeg); - if (seglen == 0) - seglen++; // fixup for invalid segment lengths - if (jpeglen < seglen) - seglen = jpeglen; - + if (seglen == 0) seglen++; // fixup for invalid segment lengths + if (jpeglen < seglen) seglen = jpeglen; } jpeg += seglen; @@ -633,8 +616,7 @@ bool UpdateDebugData(char *jpeg, size_t jpeglen, extra_appinfo_t *extra) // incl static const char *exiferrmsg = "Updating exif failed"; -bool UpdateExif(char *jpeg, size_t jpeglen, exif_attribute_t *exif) -{ +bool UpdateExif(char *jpeg, size_t jpeglen, exif_attribute_t *exif) { if (!exif) { ALOGI("No Exif to update"); return true; @@ -668,8 +650,7 @@ bool UpdateExif(char *jpeg, size_t jpeglen, exif_attribute_t *exif) return true; } -void ExtractDebugAttributeInfo(debug_attribute_t *debug, extra_appinfo_t *extra) -{ +void ExtractDebugAttributeInfo(debug_attribute_t *debug, extra_appinfo_t *extra) { if (!debug) { extra->num_of_appmarker = 0; return; diff --git a/libhwjpeg/AppMarkerWriter.h b/libhwjpeg/AppMarkerWriter.h index 5232e31..a25d9c0 100644 --- a/libhwjpeg/AppMarkerWriter.h +++ b/libhwjpeg/AppMarkerWriter.h @@ -18,6 +18,8 @@ #define __HARDWARE_SAMSUNG_SLSI_EXYNOS_APPMARKER_WRITER_H__ #include <ExynosExif.h> + +#include "hwjpeg-internal.h" #include "include/hardware/exynos/ExynosExif.h" #define JPEG_MAX_SEGMENT_SIZE ((1 << 16) - 1) @@ -33,10 +35,9 @@ #define IFD_COUNT_SIZE 4 #define IFD_VALOFF_SIZE 4 -#define IFD_FIELD_SIZE \ - (IFD_TAG_SIZE + IFD_TYPE_SIZE + IFD_COUNT_SIZE + IFD_VALOFF_SIZE) +#define IFD_FIELD_SIZE (IFD_TAG_SIZE + IFD_TYPE_SIZE + IFD_COUNT_SIZE + IFD_VALOFF_SIZE) -#define EXTRA_APPMARKER_MIN 4 +#define EXTRA_APPMARKER_MIN 2 #define EXTRA_APPMARKER_LIMIT 10 #define MAX_GPS_PROCESSINGMETHOD_SIZE 108 @@ -49,8 +50,8 @@ class CAppMarkerWriter { char *m_pAppBase; char *m_pApp1End; size_t m_szMaxThumbSize; // Maximum available thumbnail stream size minus JPEG_MARKER_SIZE - uint16_t m_szApp1; // The size of APP1 segment without marker - uint16_t m_szApp11; // The size of APP11 segment without marker + uint16_t m_szApp1; // The size of APP1 segment without marker + uint16_t m_szApp11; // The size of APP11 segment without marker uint16_t m_n0thIFDFields; uint16_t m_n1stIFDFields; uint16_t m_nExifIFDFields; @@ -76,6 +77,7 @@ class CAppMarkerWriter { char *WriteAPP1(char *base, bool reserve_thumbnail_space, bool updating = false); char *WriteAPPX(char *base, bool just_reserve); char *WriteAPP11(char *current, size_t dummy, size_t align); + public: // dummy: number of dummy bytes written by the compressor of the main image // this dummy size should be added to the APP1 length. Howerver, this dummy area @@ -84,7 +86,7 @@ public: CAppMarkerWriter(); CAppMarkerWriter(char *base, exif_attribute_t *exif, debug_attribute_t *debug); - ~CAppMarkerWriter() { } + ~CAppMarkerWriter() {} void PrepareAppWriter(char *base, exif_attribute_t *exif, extra_appinfo_t *info); @@ -100,15 +102,14 @@ public: // CalculateAPPSize() is valid after Write() is successful. size_t CalculateAPPSize(size_t thumblen = JPEG_MAX_SEGMENT_SIZE) { size_t appsize = 0; - if (m_szApp1 > 0) - appsize += m_szApp1 + JPEG_MARKER_SIZE; + if (m_szApp1 > 0) appsize += m_szApp1 + JPEG_MARKER_SIZE; if (m_pExtra) { for (int idx = 0; idx < m_pExtra->num_of_appmarker; idx++) - appsize += m_pExtra->appInfo[idx].dataSize + - + JPEG_MARKER_SIZE + JPEG_SEGMENT_LENFIELD_SIZE; + appsize += m_pExtra->appInfo[idx].dataSize + +JPEG_MARKER_SIZE + + JPEG_SEGMENT_LENFIELD_SIZE; } if (IsThumbSpaceReserved()) - appsize += m_szMaxThumbSize + JPEG_APP1_OEM_RESERVED ; + appsize += m_szMaxThumbSize + JPEG_APP1_OEM_RESERVED; else appsize += min(m_szMaxThumbSize, thumblen); @@ -117,7 +118,8 @@ public: char *GetApp1End() { return m_pApp1End; } - void Write(bool reserve_thumbnail_space, size_t dummy, size_t align, bool reserve_debug = false) { + void Write(bool reserve_thumbnail_space, size_t dummy, size_t align, + bool reserve_debug = false) { m_pApp1End = WriteAPP1(m_pAppBase, reserve_thumbnail_space); char *appXend = WriteAPPX(m_pApp1End, reserve_debug); char *app11end = WriteAPP11(appXend, dummy, align); @@ -129,7 +131,7 @@ public: bool IsThumbSpaceReserved() { return PTR_DIFF(m_pAppBase, m_pApp1End) == - (m_szApp1 + m_szMaxThumbSize + JPEG_APP1_OEM_RESERVED + JPEG_MARKER_SIZE); + (m_szApp1 + m_szMaxThumbSize + JPEG_APP1_OEM_RESERVED + JPEG_MARKER_SIZE); } void Finalize(size_t thumbsize); diff --git a/libhwjpeg/ExynosJpegEncoder.cpp b/libhwjpeg/ExynosJpegEncoder.cpp index 39e7a2e..d833ca7 100644 --- a/libhwjpeg/ExynosJpegEncoder.cpp +++ b/libhwjpeg/ExynosJpegEncoder.cpp @@ -15,24 +15,27 @@ * limitations under the License. */ -#include <linux/videodev2.h> - #include <ExynosJpegApi.h> +#include <linux/videodev2.h> #include "hwjpeg-internal.h" -int ExynosJpegEncoder::setJpegConfig(void* pConfig) -{ +int ExynosJpegEncoder::lock() { + return m_hwjpeg.lock(); +} + +int ExynosJpegEncoder::unlock() { + return m_hwjpeg.unlock(); +} + +int ExynosJpegEncoder::setJpegConfig(void *pConfig) { ExynosJpegEncoder *that = reinterpret_cast<ExynosJpegEncoder *>(pConfig); - if (!setColorFormat(that->m_v4l2Format)) - return -1; + if (!setColorFormat(that->m_v4l2Format)) return -1; - if (!setJpegFormat(that->m_jpegFormat)) - return -1; + if (!setJpegFormat(that->m_jpegFormat)) return -1; - if (!setSize(that->m_nWidth, that->m_nHeight)) - return -1; + if (!setSize(that->m_nWidth, that->m_nHeight)) return -1; m_iInBufType = that->m_iInBufType; m_iOutBufType = that->m_iOutBufType; @@ -40,127 +43,101 @@ int ExynosJpegEncoder::setJpegConfig(void* pConfig) return 0; } -int ExynosJpegEncoder::getInBuf(int *piBuf, int *piInputSize, int iSize) -{ +int ExynosJpegEncoder::getInBuf(int *piBuf, int *piInputSize, int iSize) { if (iSize < 1) { ALOGE("Invalid array size %d for getInBuf()", iSize); return -1; } size_t len_buffers[iSize]; - if (!m_hwjpeg.GetImageBuffers(piBuf, len_buffers, static_cast<unsigned int>(iSize))) - return -1; + if (!m_hwjpeg.GetImageBuffers(piBuf, len_buffers, static_cast<unsigned int>(iSize))) return -1; - for (int i = 0; i < iSize; i++) - piInputSize[i] = static_cast<int>(len_buffers[i]); + for (int i = 0; i < iSize; i++) piInputSize[i] = static_cast<int>(len_buffers[i]); return 0; } -int ExynosJpegEncoder::getOutBuf(int *piBuf, int *piOutputSize) -{ +int ExynosJpegEncoder::getOutBuf(int *piBuf, int *piOutputSize) { size_t len; - if (!m_hwjpeg.GetJpegBuffer(piBuf, &len)) - return -1; + if (!m_hwjpeg.GetJpegBuffer(piBuf, &len)) return -1; *piOutputSize = static_cast<int>(len); return 0; } -int ExynosJpegEncoder::setInBuf(int *piBuf, int *iSize) -{ +int ExynosJpegEncoder::setInBuf(int *piBuf, int *iSize) { size_t buflen[3]; unsigned int bufnum = 3; - if (!EnsureFormatIsApplied()) - return -1; + if (!EnsureFormatIsApplied()) return -1; - if (!m_hwjpeg.GetImageBufferSizes(buflen, &bufnum)) - return -1; + if (!m_hwjpeg.GetImageBufferSizes(buflen, &bufnum)) return -1; - for (unsigned int i = 0; i < bufnum; i++) - buflen[i] = static_cast<size_t>(iSize[i]); + for (unsigned int i = 0; i < bufnum; i++) buflen[i] = static_cast<size_t>(iSize[i]); - if (!m_hwjpeg.SetImageBuffer(piBuf, buflen, bufnum)) - return -1; + if (!m_hwjpeg.SetImageBuffer(piBuf, buflen, bufnum)) return -1; m_iInBufType = JPEG_BUF_TYPE_DMA_BUF; return 0; } -int ExynosJpegEncoder::setOutBuf(int iBuf, int iSize, int offset) -{ - if (!m_hwjpeg.SetJpegBuffer(iBuf, static_cast<size_t>(iSize), offset)) - return -1; +int ExynosJpegEncoder::setOutBuf(int iBuf, int iSize, int offset) { + if (!m_hwjpeg.SetJpegBuffer(iBuf, static_cast<size_t>(iSize), offset)) return -1; m_iOutBufType = JPEG_BUF_TYPE_DMA_BUF; return 0; } -int ExynosJpegEncoder::getInBuf(char **pcBuf, int *piInputSize, int iSize) -{ +int ExynosJpegEncoder::getInBuf(char **pcBuf, int *piInputSize, int iSize) { if (iSize < 1) { ALOGE("Invalid array size %d for getInBuf()", iSize); return -1; } size_t len_buffers[iSize]; - if (!m_hwjpeg.GetImageBuffers(pcBuf, len_buffers, static_cast<unsigned int>(iSize))) - return -1; + if (!m_hwjpeg.GetImageBuffers(pcBuf, len_buffers, static_cast<unsigned int>(iSize))) return -1; - for (int i = 0; i < iSize; i++) - piInputSize[i] = static_cast<int>(len_buffers[i]); + for (int i = 0; i < iSize; i++) piInputSize[i] = static_cast<int>(len_buffers[i]); return 0; } -int ExynosJpegEncoder::getOutBuf(char **pcBuf, int *piOutputSize) -{ +int ExynosJpegEncoder::getOutBuf(char **pcBuf, int *piOutputSize) { size_t len; - if (!m_hwjpeg.GetJpegBuffer(pcBuf, &len)) - return -1; + if (!m_hwjpeg.GetJpegBuffer(pcBuf, &len)) return -1; *piOutputSize = static_cast<int>(len); return 0; } -int ExynosJpegEncoder::setInBuf(char **pcBuf, int *iSize) -{ +int ExynosJpegEncoder::setInBuf(char **pcBuf, int *iSize) { size_t buflen[3]; unsigned int bufnum = 3; - if (!EnsureFormatIsApplied()) - return -1; + if (!EnsureFormatIsApplied()) return -1; - if (!m_hwjpeg.GetImageBufferSizes(buflen, &bufnum)) - return -1; + if (!m_hwjpeg.GetImageBufferSizes(buflen, &bufnum)) return -1; - for (unsigned int i = 0; i < bufnum; i++) - buflen[i] = static_cast<size_t>(iSize[i]); + for (unsigned int i = 0; i < bufnum; i++) buflen[i] = static_cast<size_t>(iSize[i]); - if (!m_hwjpeg.SetImageBuffer(pcBuf, buflen, bufnum)) - return -1; + if (!m_hwjpeg.SetImageBuffer(pcBuf, buflen, bufnum)) return -1; m_iInBufType = JPEG_BUF_TYPE_USER_PTR; return 0; } -int ExynosJpegEncoder::setOutBuf(char *pcBuf, int iSize) -{ - if (!m_hwjpeg.SetJpegBuffer(pcBuf, static_cast<size_t>(iSize))) - return -1; +int ExynosJpegEncoder::setOutBuf(char *pcBuf, int iSize) { + if (!m_hwjpeg.SetJpegBuffer(pcBuf, static_cast<size_t>(iSize))) return -1; m_iOutBufType = JPEG_BUF_TYPE_USER_PTR; return 0; } -int ExynosJpegEncoder::setJpegFormat(int iV4l2JpegFormat) -{ - if (m_jpegFormat == iV4l2JpegFormat) - return 0; +int ExynosJpegEncoder::setJpegFormat(int iV4l2JpegFormat) { + if (m_jpegFormat == iV4l2JpegFormat) return 0; unsigned int hfactor, vfactor; switch (iV4l2JpegFormat) { @@ -193,31 +170,27 @@ int ExynosJpegEncoder::setJpegFormat(int iV4l2JpegFormat) return -1; } - if (!m_hwjpeg.SetChromaSampFactor(hfactor, vfactor)) - return -1; + if (!m_hwjpeg.SetChromaSampFactor(hfactor, vfactor)) return -1; m_jpegFormat = iV4l2JpegFormat; return 0; } -int ExynosJpegEncoder::setColorBufSize(int *piBufSize, int iSize) -{ +int ExynosJpegEncoder::setColorBufSize(int *piBufSize, int iSize) { size_t len[3]; unsigned int num = static_cast<unsigned int>(iSize); - if (!m_hwjpeg.GetImageBufferSizes(len, &num)) - return -1; + if (!m_hwjpeg.GetImageBufferSizes(len, &num)) return -1; - for (unsigned int i = 0; i < num; i++) - piBufSize[i] = static_cast<int>(len[i]); + for (unsigned int i = 0; i < num; i++) piBufSize[i] = static_cast<int>(len[i]); return 0; } bool ExynosJpegEncoder::__EnsureFormatIsApplied() { if (TestStateEither(STATE_SIZE_CHANGED | STATE_PIXFMT_CHANGED) && - !m_hwjpeg.SetImageFormat(m_v4l2Format, m_nWidth, m_nHeight)) + !m_hwjpeg.SetImageFormat(m_v4l2Format, m_nWidth, m_nHeight)) return false; ClearState(STATE_SIZE_CHANGED | STATE_PIXFMT_CHANGED); @@ -227,3 +200,7 @@ bool ExynosJpegEncoder::__EnsureFormatIsApplied() { int ExynosJpegEncoder::setQuality(const unsigned char q_table[]) { return m_hwjpeg.SetQuality(q_table) ? 0 : -1; } + +int ExynosJpegEncoder::setPadding(unsigned char *padding, unsigned int num_planes) { + return m_hwjpeg.SetPadding(padding, num_planes) ? 0 : -1; +} diff --git a/libhwjpeg/ExynosJpegEncoderForCamera.cpp b/libhwjpeg/ExynosJpegEncoderForCamera.cpp index 741e05e..5e003aa 100644 --- a/libhwjpeg/ExynosJpegEncoderForCamera.cpp +++ b/libhwjpeg/ExynosJpegEncoderForCamera.cpp @@ -15,29 +15,24 @@ * limitations under the License. */ +#include <ExynosJpegEncoderForCamera.h> +#include <hardware/exynos/ion.h> +#include <linux/videodev2.h> #include <sys/mman.h> #include <sys/types.h> - -#include <linux/videodev2.h> - -#include <hardware/exynos/ion.h> #include <system/graphics.h> -#include <ExynosJpegEncoderForCamera.h> - -#include "hwjpeg-internal.h" #include "AppMarkerWriter.h" #include "ThumbnailScaler.h" -#include "IFDWriter.h" +#include "hwjpeg-internal.h" // Data length written by H/W without the scan data. -#define NECESSARY_JPEG_LENGTH (0x24B + 2 * JPEG_MARKER_SIZE) +#define NECESSARY_JPEG_LENGTH (0x24B + 2 * JPEG_MARKER_SIZE) -static size_t GetImageLength(unsigned int width, unsigned int height, int v4l2Format) -{ +static size_t GetImageLength(unsigned int width, unsigned int height, int v4l2Format) { size_t size = width * height; - switch(v4l2Format) { + switch (v4l2Format) { case V4L2_PIX_FMT_YUYV: case V4L2_PIX_FMT_YVYU: case V4L2_PIX_FMT_UYVY: @@ -57,22 +52,29 @@ static size_t GetImageLength(unsigned int width, unsigned int height, int v4l2Fo return 0; } -static int GetThumbnailFormat(int v4l2Format) -{ - if (v4l2Format == V4L2_PIX_FMT_NV12M) - return V4L2_PIX_FMT_NV12; - else if (v4l2Format == V4L2_PIX_FMT_NV21M) - return V4L2_PIX_FMT_NV21; - else - return v4l2Format; +static int GetThumbnailFormat(int v4l2Format) { + if (v4l2Format == V4L2_PIX_FMT_NV12M) + return V4L2_PIX_FMT_NV12; + else if (v4l2Format == V4L2_PIX_FMT_NV21M) + return V4L2_PIX_FMT_NV21; + else + return v4l2Format; } ExynosJpegEncoderForCamera::ExynosJpegEncoderForCamera(bool bBTBComp) - : m_phwjpeg4thumb(NULL), m_fdIONClient(-1), m_fdIONThumbImgBuffer(-1), m_pIONThumbImgBuffer(NULL), - m_szIONThumbImgBuffer(0), m_pIONThumbJpegBuffer(NULL), m_fdIONThumbJpegBuffer(-1), m_szIONThumbJpegBuffer(0), - m_nThumbWidth(0), m_nThumbHeight(0), m_nThumbQuality(0), - m_pStreamBase(NULL), m_fThumbBufferType(0) -{ + : m_phwjpeg4thumb(NULL), + m_fdIONClient(-1), + m_fdIONThumbImgBuffer(-1), + m_pIONThumbImgBuffer(NULL), + m_szIONThumbImgBuffer(0), + m_pIONThumbJpegBuffer(NULL), + m_fdIONThumbJpegBuffer(-1), + m_szIONThumbJpegBuffer(0), + m_nThumbWidth(0), + m_nThumbHeight(0), + m_nThumbQuality(0), + m_pStreamBase(NULL), + m_fThumbBufferType(0) { m_pAppWriter = new CAppMarkerWriter(); if (!m_pAppWriter) { ALOGE("Failed to allocated an instance of CAppMarkerWriter"); @@ -94,52 +96,41 @@ ExynosJpegEncoderForCamera::ExynosJpegEncoderForCamera(bool bBTBComp) ALOGERR("Failed to create ION client for thumbnail conversion"); } - if (!bBTBComp) - SetState(STATE_NO_BTBCOMP); + if (!bBTBComp) SetState(STATE_NO_BTBCOMP); // STATE_THUMBSIZE_CHANGED is to know if thumbnail image size need to be // configured to HWJPEG. If HWJPEG does not support for back-to-back // compression, it should not be configured. - if (IsBTBCompressionSupported()) - SetState(STATE_THUMBSIZE_CHANGED); + if (IsBTBCompressionSupported()) SetState(STATE_THUMBSIZE_CHANGED); m_extraInfo.appInfo = m_appInfo; mThumbnailScaler.reset(ThumbnailScaler::createInstance()); - if (!mThumbnailScaler->available()) - ALOGW("Thumbnail scaler is not available."); + if (!mThumbnailScaler->available()) ALOGW("Thumbnail scaler is not available."); ALOGD("ExynosJpegEncoderForCamera Created: %p, ION %d", this, m_fdIONClient); } -ExynosJpegEncoderForCamera::~ExynosJpegEncoderForCamera() -{ +ExynosJpegEncoderForCamera::~ExynosJpegEncoderForCamera() { delete m_pAppWriter; delete m_phwjpeg4thumb; - if (m_pIONThumbImgBuffer != NULL) - munmap(m_pIONThumbImgBuffer, m_szIONThumbImgBuffer); + if (m_pIONThumbImgBuffer != NULL) munmap(m_pIONThumbImgBuffer, m_szIONThumbImgBuffer); - if (m_fdIONThumbImgBuffer >= 0) - close(m_fdIONThumbImgBuffer); + if (m_fdIONThumbImgBuffer >= 0) close(m_fdIONThumbImgBuffer); - if (m_pIONThumbJpegBuffer) - munmap(m_pIONThumbJpegBuffer, m_szIONThumbJpegBuffer); + if (m_pIONThumbJpegBuffer) munmap(m_pIONThumbJpegBuffer, m_szIONThumbJpegBuffer); - if (m_fdIONThumbJpegBuffer >= 0) - close(m_fdIONThumbJpegBuffer); + if (m_fdIONThumbJpegBuffer >= 0) close(m_fdIONThumbJpegBuffer); - if (m_fdIONClient >= 0) - exynos_ion_close(m_fdIONClient); + if (m_fdIONClient >= 0) exynos_ion_close(m_fdIONClient); - ALOGD("ExynosJpegEncoderForCamera Destroyed: %p, ION %d, ThumIMG %d", - this, m_fdIONClient, m_fdIONThumbImgBuffer); + ALOGD("ExynosJpegEncoderForCamera Destroyed: %p, ION %d, ThumIMG %d", this, m_fdIONClient, + m_fdIONThumbImgBuffer); } -int ExynosJpegEncoderForCamera::setThumbnailSize(int w, int h) -{ - if ((m_nThumbWidth == w) && (m_nThumbHeight == h)) - return 0; +int ExynosJpegEncoderForCamera::setThumbnailSize(int w, int h) { + if ((m_nThumbWidth == w) && (m_nThumbHeight == h)) return 0; // w == 0 and h == 0 resets thumbnail configuration if (((w | h) != 0) && ((w < 16) || (h < 16))) { @@ -150,16 +141,13 @@ int ExynosJpegEncoderForCamera::setThumbnailSize(int w, int h) m_nThumbWidth = w; m_nThumbHeight = h; - if (IsBTBCompressionSupported()) - SetState(STATE_THUMBSIZE_CHANGED); + if (IsBTBCompressionSupported()) SetState(STATE_THUMBSIZE_CHANGED); return 0; } -int ExynosJpegEncoderForCamera::setThumbnailQuality(int quality) -{ - if (m_nThumbQuality == quality) - return 0; +int ExynosJpegEncoderForCamera::setThumbnailQuality(int quality) { + if (m_nThumbQuality == quality) return 0; if ((quality > 100) || (quality < 1)) { ALOGE("Invalid quality factor %d for thumbnail image", quality); @@ -171,6 +159,11 @@ int ExynosJpegEncoderForCamera::setThumbnailQuality(int quality) return GetCompressor().SetQuality(0, m_nThumbQuality) ? 0 : -1; } +int ExynosJpegEncoderForCamera::setThumbnailPadding(unsigned char *padding, + unsigned int num_planes) { + return GetCompressor().SetPadding2(padding, num_planes) ? 0 : -1; +} + bool ExynosJpegEncoderForCamera::EnsureFormatIsApplied() { if (TestStateEither(STATE_PIXFMT_CHANGED | STATE_SIZE_CHANGED | STATE_THUMBSIZE_CHANGED)) { int thumb_width = m_nThumbWidth; @@ -184,8 +177,8 @@ bool ExynosJpegEncoderForCamera::EnsureFormatIsApplied() { } getSize(&width, &height); - if (!GetCompressor().SetImageFormat( - getColorFormat(), width, height, thumb_width, thumb_height)) + if (!GetCompressor().SetImageFormat(getColorFormat(), width, height, thumb_width, + thumb_height)) return false; ClearState(STATE_PIXFMT_CHANGED | STATE_SIZE_CHANGED | STATE_THUMBSIZE_CHANGED); @@ -194,8 +187,7 @@ bool ExynosJpegEncoderForCamera::EnsureFormatIsApplied() { return true; } -size_t ExynosJpegEncoderForCamera::RemoveTrailingDummies(char *base, size_t len) -{ +size_t ExynosJpegEncoderForCamera::RemoveTrailingDummies(char *base, size_t len) { ALOG_ASSERT(len > 4); ALOG_ASSERT((base[0] == 0xFF) && (base[1] == 0xD8)); // SOI marker @@ -215,18 +207,15 @@ size_t ExynosJpegEncoderForCamera::RemoveTrailingDummies(char *base, size_t len) return 0; } -void *ExynosJpegEncoderForCamera::tCompressThumbnail(void *p) -{ +void *ExynosJpegEncoderForCamera::tCompressThumbnail(void *p) { ExynosJpegEncoderForCamera *encoder = reinterpret_cast<ExynosJpegEncoderForCamera *>(p); size_t thumblen = encoder->CompressThumbnail(); return reinterpret_cast<void *>(thumblen); } -bool ExynosJpegEncoderForCamera::ProcessExif(char *base, size_t limit, - exif_attribute_t *exifInfo, - extra_appinfo_t *extra) -{ +bool ExynosJpegEncoderForCamera::ProcessExif(char *base, size_t limit, exif_attribute_t *exifInfo, + extra_appinfo_t *extra) { // PREREQUISITES: The main and the thumbnail image size should be configured before. // Sanity chck @@ -237,16 +226,16 @@ bool ExynosJpegEncoderForCamera::ProcessExif(char *base, size_t limit, if (exifInfo) { if ((exifInfo->width != width) || (exifInfo->height != height)) { - ALOGE("Inconsistant image dimension: Exif %dx%d, Thumb %dx%d", - exifInfo->width, exifInfo->height, width, height); + ALOGE("Inconsistent image dimension: Exif %dx%d, Thumb %dx%d", exifInfo->width, + exifInfo->height, width, height); return false; } if (exifInfo->enableThumb) { if ((exifInfo->widthThumb != static_cast<uint32_t>(m_nThumbWidth)) || - (exifInfo->heightThumb != static_cast<uint32_t>(m_nThumbHeight))) { - ALOGE("Inconsistant thumbnail information: Exif %dx%d, Thumb %dx%d", - exifInfo->widthThumb, exifInfo->heightThumb, m_nThumbWidth, m_nThumbHeight); + (exifInfo->heightThumb != static_cast<uint32_t>(m_nThumbHeight))) { + ALOGE("Inconsistent thumbnail information: Exif %dx%d, Thumb %dx%d", + exifInfo->widthThumb, exifInfo->heightThumb, m_nThumbWidth, m_nThumbHeight); return false; } } @@ -255,8 +244,7 @@ bool ExynosJpegEncoderForCamera::ProcessExif(char *base, size_t limit, // Giving appwriter the address beyond SOS marker // because it is handled by this class size_t align = 16; - if (!!(GetDeviceCapabilities() & V4L2_CAP_EXYNOS_JPEG_NO_STREAMBASE_ALIGN)) - align = 1; + if (!!(GetDeviceCapabilities() & V4L2_CAP_EXYNOS_JPEG_NO_STREAMBASE_ALIGN)) align = 1; m_pAppWriter->PrepareAppWriter(base + JPEG_MARKER_SIZE, exifInfo, extra); @@ -280,24 +268,21 @@ bool ExynosJpegEncoderForCamera::ProcessExif(char *base, size_t limit, if (!exifInfo || !exifInfo->enableThumb || (limit < (JPEG_MAX_SEGMENT_SIZE * 10))) reserve_thumbspace = false; - m_pAppWriter->Write(reserve_thumbspace, JPEG_MARKER_SIZE, align, - TestState(STATE_HWFC_ENABLED)); + m_pAppWriter->Write(reserve_thumbspace, JPEG_MARKER_SIZE, align, TestState(STATE_HWFC_ENABLED)); ALOGD("Image compression starts from offset %zu (APPx size %zu, HWFC? %d, NBTB? %d)", - PTR_DIFF(base, m_pAppWriter->GetMainStreamBase()), m_pAppWriter->CalculateAPPSize(), - TestState(STATE_HWFC_ENABLED),TestState(STATE_NO_BTBCOMP)); + PTR_DIFF(base, m_pAppWriter->GetMainStreamBase()), m_pAppWriter->CalculateAPPSize(), + TestState(STATE_HWFC_ENABLED), TestState(STATE_NO_BTBCOMP)); return true; } -bool ExynosJpegEncoderForCamera::PrepareCompression(bool thumbnail) -{ - if (!thumbnail) - return true; +bool ExynosJpegEncoderForCamera::PrepareCompression(bool thumbnail) { + if (!thumbnail) return true; if (IsThumbGenerationNeeded()) { - if (pthread_create(&m_threadWorker, NULL, - tCompressThumbnail, reinterpret_cast<void *>(this)) != 0) { + if (pthread_create(&m_threadWorker, NULL, tCompressThumbnail, + reinterpret_cast<void *>(this)) != 0) { ALOGERR("Failed to create thumbnail generation thread"); return false; } @@ -312,14 +297,14 @@ bool ExynosJpegEncoderForCamera::PrepareCompression(bool thumbnail) if (!TestState(STATE_NO_BTBCOMP) && IsBTBCompressionSupported()) { if (checkOutBufType() == JPEG_BUF_TYPE_USER_PTR) { if (!GetCompressor().SetJpegBuffer2(m_pIONThumbJpegBuffer, m_szIONThumbJpegBuffer)) { - ALOGE("Failed to configure thumbnail buffer @ %p(size %zu)", - m_pIONThumbJpegBuffer, m_szIONThumbJpegBuffer); + ALOGE("Failed to configure thumbnail buffer @ %p(size %zu)", m_pIONThumbJpegBuffer, + m_szIONThumbJpegBuffer); return false; } } else { if (!GetCompressor().SetJpegBuffer2(m_fdIONThumbJpegBuffer, m_szIONThumbJpegBuffer)) { - ALOGE("Failed to configure thumbnail buffer @ %d(size %zu)", - m_fdIONThumbJpegBuffer, m_szIONThumbJpegBuffer); + ALOGE("Failed to configure thumbnail buffer @ %d(size %zu)", m_fdIONThumbJpegBuffer, + m_szIONThumbJpegBuffer); return false; } } @@ -328,16 +313,13 @@ bool ExynosJpegEncoderForCamera::PrepareCompression(bool thumbnail) return true; } -int ExynosJpegEncoderForCamera::encode(int *size, exif_attribute_t *exifInfo, - char** pcJpegBuffer, debug_attribute_t *debugInfo) -{ +int ExynosJpegEncoderForCamera::encode(int *size, exif_attribute_t *exifInfo, char **pcJpegBuffer, + debug_attribute_t *debugInfo) { return encode(size, exifInfo, -1, pcJpegBuffer, debugInfo); } -int ExynosJpegEncoderForCamera::encode(int *size, exif_attribute_t *exifInfo, - int fdJpegBuffer, char** pcJpegBuffer, - debug_attribute_t *debugInfo) -{ +int ExynosJpegEncoderForCamera::encode(int *size, exif_attribute_t *exifInfo, int fdJpegBuffer, + char **pcJpegBuffer, debug_attribute_t *debugInfo) { if ((!debugInfo) || (debugInfo->num_of_appmarker == 0)) { extra_appinfo_t *extra = NULL; return encode(size, exifInfo, fdJpegBuffer, pcJpegBuffer, extra); @@ -351,10 +333,8 @@ int ExynosJpegEncoderForCamera::encode(int *size, exif_attribute_t *exifInfo, return encode(size, exifInfo, fdJpegBuffer, pcJpegBuffer, &m_extraInfo); } -int ExynosJpegEncoderForCamera::encode(int *size, exif_attribute_t *exifInfo, - int fdJpegBuffer, char** pcJpegBuffer, - extra_appinfo_t *appInfo) -{ +int ExynosJpegEncoderForCamera::encode(int *size, exif_attribute_t *exifInfo, int fdJpegBuffer, + char **pcJpegBuffer, extra_appinfo_t *appInfo) { if (!(*pcJpegBuffer)) { ALOGE("Target stream buffer is not specified"); return -1; @@ -371,27 +351,26 @@ int ExynosJpegEncoderForCamera::encode(int *size, exif_attribute_t *exifInfo, char *jpeg_base = m_pStreamBase; ALOGI_IF(!exifInfo, "Exif is not specified. Skipping writing APP1 marker"); - ALOGI_IF(!appInfo, - "Debugging information is not specified. Skipping writing APP4 marker"); + ALOGI_IF(!appInfo, "Debugging information is not specified. Skipping writing APP4 marker"); ALOGD("Given stream buffer size: %d bytes", *size); CStopWatch stopwatch(true); - if (!ProcessExif(jpeg_base, m_nStreamSize, exifInfo, appInfo)) - return -1; + if (!ProcessExif(jpeg_base, m_nStreamSize, exifInfo, appInfo)) return -1; int offset = PTR_DIFF(m_pStreamBase, m_pAppWriter->GetMainStreamBase()); int buffsize = static_cast<int>(m_nStreamSize - offset); - if ((fdJpegBuffer < 0) || !(GetDeviceCapabilities() & V4L2_CAP_EXYNOS_JPEG_DMABUF_OFFSET)) { // JPEG_BUF_TYPE_USER_PTR + if ((fdJpegBuffer < 0) || + !(GetDeviceCapabilities() & V4L2_CAP_EXYNOS_JPEG_DMABUF_OFFSET)) { // JPEG_BUF_TYPE_USER_PTR if (setOutBuf(m_pAppWriter->GetMainStreamBase(), buffsize) < 0) { - ALOGE("Failed to configure stream buffer : fd %d, addr %p, streamSize %d", - fdJpegBuffer, m_pAppWriter->GetMainStreamBase(), buffsize); + ALOGE("Failed to configure stream buffer : fd %d, addr %p, streamSize %d", fdJpegBuffer, + m_pAppWriter->GetMainStreamBase(), buffsize); return -1; } } else { // JPEG_BUF_TYPE_DMA_BUF if (setOutBuf(fdJpegBuffer, buffsize, offset) < 0) { - ALOGE("Failed to configure stream buffer : fd %d, addr %p, streamSize %d", - fdJpegBuffer, m_pAppWriter->GetMainStreamBase(), buffsize); + ALOGE("Failed to configure stream buffer : fd %d, addr %p, streamSize %d", fdJpegBuffer, + m_pAppWriter->GetMainStreamBase(), buffsize); return -1; } } @@ -412,10 +391,10 @@ int ExynosJpegEncoderForCamera::encode(int *size, exif_attribute_t *exifInfo, // CASE1 = thumbenc && IsThumbGenerationNeeded() && block_mode // CASE2 = thumbenc && IsThumbGenerationNeeded() && !block_mode // CASE3 = thumbenc && !IsThumbGenerationNeeded() && !IsBTBCompressionSupported() && !block_mode - // CASE4 = thumbenc && !IsThumbGenerationNeeded() && !STATE_NO_BTBCOMP && IsBTBCompressionSupported() && !block_mode - // CASE5 = thumbenc && !IsThumbGenerationNeeded() && !STATE_NO_BTBCOMP && IsBTBCompressionSupported() && block_mode - // CASE6 = !thumbenc - // CASE7 = thumbenc && !IsThumbGenerationNeeded() && STATE_NO_BTBCOMP && block_mode + // CASE4 = thumbenc && !IsThumbGenerationNeeded() && !STATE_NO_BTBCOMP && + // IsBTBCompressionSupported() && !block_mode CASE5 = thumbenc && !IsThumbGenerationNeeded() && + // !STATE_NO_BTBCOMP && IsBTBCompressionSupported() && block_mode CASE6 = !thumbenc CASE7 = + // thumbenc && !IsThumbGenerationNeeded() && STATE_NO_BTBCOMP && block_mode if (!thumbenc) { // Confirm that no thumbnail information is transferred to HWJPEG @@ -423,7 +402,7 @@ int ExynosJpegEncoderForCamera::encode(int *size, exif_attribute_t *exifInfo, } else if (!IsThumbGenerationNeeded() && IsBTBCompressionSupported() && (m_fThumbBufferType != checkInBufType())) { ALOGE("Buffer types of thumbnail(%d) and main(%d) images should be the same", - m_fThumbBufferType, checkInBufType()); + m_fThumbBufferType, checkInBufType()); return -1; } else if (!IsThumbGenerationNeeded() && (m_fThumbBufferType == 0)) { // Thumbnail buffer configuration failed but the client forces to compress with thumbnail @@ -453,17 +432,14 @@ int ExynosJpegEncoderForCamera::encode(int *size, exif_attribute_t *exifInfo, } *size = static_cast<int>(FinishCompression(mainlen, thumblen)); - if (*size < 0) - return -1; + if (*size < 0) return -1; - ALOGD("....compression delay(usec.): HW %u, Total %lu)", - GetHWDelay(), stopwatch.GetElapsed()); + ALOGD("....compression delay(usec.): HW %u, Total %lu)", GetHWDelay(), stopwatch.GetElapsed()); return 0; } -ssize_t ExynosJpegEncoderForCamera::FinishCompression(size_t mainlen, size_t thumblen) -{ +ssize_t ExynosJpegEncoderForCamera::FinishCompression(size_t mainlen, size_t thumblen) { bool btb = false; size_t max_streamsize = m_nStreamSize; char *mainbase = m_pAppWriter->GetMainStreamBase(); @@ -491,33 +467,37 @@ ssize_t ExynosJpegEncoderForCamera::FinishCompression(size_t mainlen, size_t thu thumblen = reinterpret_cast<size_t>(len); } else if (TestState(STATE_NO_BTBCOMP) || !IsBTBCompressionSupported()) { - thumblen = CompressThumbnailOnly(m_pAppWriter->GetMaxThumbnailSize(), m_nThumbQuality, getColorFormat(), checkInBufType()); + thumblen = CompressThumbnailOnly(m_pAppWriter->GetMaxThumbnailSize(), m_nThumbQuality, + getColorFormat(), checkInBufType()); } else { btb = true; } - size_t max_thumb = min(m_pAppWriter->GetMaxThumbnailSize(), max_streamsize - m_pAppWriter->CalculateAPPSize(0) - mainlen); + size_t max_thumb = min(m_pAppWriter->GetMaxThumbnailSize(), + max_streamsize - m_pAppWriter->CalculateAPPSize(0) - mainlen); if (thumblen > max_thumb) { ALOGI("Too large thumbnail (%dx%d) stream size %zu (max: %zu, quality factor %d)", m_nThumbWidth, m_nThumbHeight, thumblen, max_thumb, m_nThumbQuality); ALOGI("Retrying thumbnail compression with quality factor 50"); thumblen = CompressThumbnailOnly(max_thumb, 50, getColorFormat(), checkInBufType()); - if (thumblen == 0) - return -1; + if (thumblen == 0) return -1; } if (!m_pAppWriter->IsThumbSpaceReserved()) { if (PTR_TO_ULONG(m_pStreamBase + max_streamsize) < - PTR_TO_ULONG(mainbase + mainlen + thumblen - JPEG_MARKER_SIZE)) { + PTR_TO_ULONG(mainbase + mainlen + thumblen - JPEG_MARKER_SIZE)) { ALOGE("Too small JPEG buffer length %zu (APP %zu, Main %zu, Thumb %zu)", max_streamsize, m_pAppWriter->CalculateAPPSize(thumblen), mainlen, thumblen); return -1; } - // the SOI of the stream of the main image is stored after the APP4 or APP11 segment if they exist. + // the SOI of the stream of the main image is stored after the APP4 or APP11 segment if + // they exist. memmove(m_pAppWriter->GetApp1End() + thumblen, m_pAppWriter->GetApp1End(), - mainlen + PTR_DIFF(m_pAppWriter->GetApp1End(), m_pAppWriter->GetMainStreamBase())); + mainlen + + PTR_DIFF(m_pAppWriter->GetApp1End(), + m_pAppWriter->GetMainStreamBase())); m_pAppWriter->UpdateApp1Size(thumblen); // m_nAppLength has the value of appwriter.GetExactAPPSize() @@ -532,7 +512,8 @@ ssize_t ExynosJpegEncoderForCamera::FinishCompression(size_t mainlen, size_t thu if (m_pAppWriter->IsThumbSpaceReserved()) { // clear the possible stale data in the dummy area after the thumbnail stream memset(m_pAppWriter->GetThumbStreamBase() + thumblen, 0, - m_pAppWriter->GetMaxThumbnailSize() - thumblen + m_pAppWriter->GetAPP1ResrevedSize()); + m_pAppWriter->GetMaxThumbnailSize() - thumblen + + m_pAppWriter->GetAPP1ResrevedSize()); } } else { thumblen = 0; @@ -546,8 +527,8 @@ ssize_t ExynosJpegEncoderForCamera::FinishCompression(size_t mainlen, size_t thu * Note that 2 byte(size of SOI marker) is included in APP1 segment size. * Thus the size of SOI marker in front of the stream is not added. */ - ALOGD("Completed image compression (%zd(thumb %zu) bytes, HWFC? %d, BTB? %d)", - mainlen, thumblen, TestState(STATE_HWFC_ENABLED), btb); + ALOGD("Completed image compression (%zd(thumb %zu) bytes, HWFC? %d, BTB? %d)", mainlen, + thumblen, TestState(STATE_HWFC_ENABLED), btb); m_pStreamBase[0] = 0xFF; m_pStreamBase[1] = 0xD8; @@ -556,21 +537,17 @@ ssize_t ExynosJpegEncoderForCamera::FinishCompression(size_t mainlen, size_t thu } /* The logic in WaitForHWFC() is the same with encode() */ -ssize_t ExynosJpegEncoderForCamera::WaitForCompression() -{ - if (!TestState(STATE_HWFC_ENABLED)) - return m_nStreamSize; +ssize_t ExynosJpegEncoderForCamera::WaitForCompression() { + if (!TestState(STATE_HWFC_ENABLED)) return m_nStreamSize; size_t thumblen = 0; ssize_t streamlen = GetCompressor().WaitForCompression(&thumblen); - if (streamlen < 0) - return streamlen; + if (streamlen < 0) return streamlen; return FinishCompression(streamlen, thumblen); } -bool ExynosJpegEncoderForCamera::GenerateThumbnailImage() -{ +bool ExynosJpegEncoderForCamera::GenerateThumbnailImage() { int main_width, main_height; if (getSize(&main_width, &main_height) < 0) { ALOGE("Failed to get main image size"); @@ -579,11 +556,10 @@ bool ExynosJpegEncoderForCamera::GenerateThumbnailImage() int v4l2Format = getColorFormat(); - if (!AllocThumbBuffer(v4l2Format)) - return false; + if (!AllocThumbBuffer(v4l2Format)) return false; - ALOGD("Generating thumbnail image: %dx%d -> %dx%d", - main_width, main_height, m_nThumbWidth, m_nThumbHeight); + ALOGD("Generating thumbnail image: %dx%d -> %dx%d", main_width, main_height, m_nThumbWidth, + m_nThumbHeight); if (!mThumbnailScaler) { ALOGE("Thumbnail scaler is not prepared"); @@ -595,8 +571,8 @@ bool ExynosJpegEncoderForCamera::GenerateThumbnailImage() return false; } - - if (!mThumbnailScaler->SetDstImage(m_nThumbWidth, m_nThumbHeight, GetThumbnailFormat(v4l2Format))) { + if (!mThumbnailScaler->SetDstImage(m_nThumbWidth, m_nThumbHeight, + GetThumbnailFormat(v4l2Format))) { ALOGE("Failed to configure the target image to the thumbnail scaler"); return false; } @@ -612,7 +588,8 @@ bool ExynosJpegEncoderForCamera::GenerateThumbnailImage() return false; } - okay = mThumbnailScaler->RunStream(bufs, len_srcbufs, m_fdIONThumbImgBuffer, m_szIONThumbImgBuffer); + okay = mThumbnailScaler->RunStream(bufs, len_srcbufs, m_fdIONThumbImgBuffer, + m_szIONThumbImgBuffer); } else { // mainbuftype == JPEG_BUF_TYPE_DMA_BUF int bufs[ThumbnailScaler::SCALER_MAX_PLANES]; int len_srcbufs[ThumbnailScaler::SCALER_MAX_PLANES]; @@ -621,7 +598,8 @@ bool ExynosJpegEncoderForCamera::GenerateThumbnailImage() ALOGE("Failed to retrieve the main image buffers"); return false; } - okay = mThumbnailScaler->RunStream(bufs, len_srcbufs, m_fdIONThumbImgBuffer, m_szIONThumbImgBuffer); + okay = mThumbnailScaler->RunStream(bufs, len_srcbufs, m_fdIONThumbImgBuffer, + m_szIONThumbImgBuffer); } if (!okay) { @@ -632,14 +610,12 @@ bool ExynosJpegEncoderForCamera::GenerateThumbnailImage() return true; } -size_t ExynosJpegEncoderForCamera::CompressThumbnail() -{ +size_t ExynosJpegEncoderForCamera::CompressThumbnail() { unsigned int v4l2Format = getColorFormat(); int buftype = checkInBufType(); if (IsThumbGenerationNeeded()) { - if (!GenerateThumbnailImage()) - return 0; + if (!GenerateThumbnailImage()) return 0; // libcsc output configured by this class is always NV21. v4l2Format = GetThumbnailFormat(getColorFormat()); @@ -650,11 +626,11 @@ size_t ExynosJpegEncoderForCamera::CompressThumbnail() m_szThumbnailImageLen[0] = m_szIONThumbImgBuffer; } - return CompressThumbnailOnly(m_pAppWriter->GetMaxThumbnailSize(), m_nThumbQuality, v4l2Format, buftype); + return CompressThumbnailOnly(m_pAppWriter->GetMaxThumbnailSize(), m_nThumbQuality, v4l2Format, + buftype); } -bool ExynosJpegEncoderForCamera::AllocThumbBuffer(int v4l2Format) -{ +bool ExynosJpegEncoderForCamera::AllocThumbBuffer(int v4l2Format) { if (m_fdIONClient < 0) { ALOGE("ION client is not created"); return false; @@ -667,11 +643,9 @@ bool ExynosJpegEncoderForCamera::AllocThumbBuffer(int v4l2Format) } if (m_fdIONThumbImgBuffer >= 0) { - if (m_szIONThumbImgBuffer >= thumbbufsize) - return true; + if (m_szIONThumbImgBuffer >= thumbbufsize) return true; - if (m_pIONThumbImgBuffer != NULL) - munmap(m_pIONThumbImgBuffer, m_szIONThumbImgBuffer); + if (m_pIONThumbImgBuffer != NULL) munmap(m_pIONThumbImgBuffer, m_szIONThumbImgBuffer); close(m_fdIONThumbImgBuffer); @@ -680,9 +654,11 @@ bool ExynosJpegEncoderForCamera::AllocThumbBuffer(int v4l2Format) m_szIONThumbImgBuffer = 0; } - m_fdIONThumbImgBuffer = exynos_ion_alloc(m_fdIONClient, thumbbufsize, EXYNOS_ION_HEAP_SYSTEM_MASK, 0); + m_fdIONThumbImgBuffer = + exynos_ion_alloc(m_fdIONClient, thumbbufsize, EXYNOS_ION_HEAP_SYSTEM_MASK, 0); if (m_fdIONThumbImgBuffer < 0) { - ALOGERR("Failed to allocate %zu bytes for NV12 %ux%u", thumbbufsize, m_nThumbHeight, m_nThumbWidth); + ALOGERR("Failed to allocate %zu bytes for NV12 %ux%u", thumbbufsize, m_nThumbHeight, + m_nThumbWidth); m_fdIONThumbImgBuffer = -1; return false; } @@ -692,8 +668,7 @@ bool ExynosJpegEncoderForCamera::AllocThumbBuffer(int v4l2Format) return AllocThumbJpegBuffer(); } -bool ExynosJpegEncoderForCamera::AllocThumbJpegBuffer() -{ +bool ExynosJpegEncoderForCamera::AllocThumbJpegBuffer() { if (m_fdIONClient < 0) { ALOGE("ION client is not created"); return false; @@ -702,8 +677,7 @@ bool ExynosJpegEncoderForCamera::AllocThumbJpegBuffer() size_t thumbbufsize = m_nThumbHeight * m_nThumbWidth * 3; if (m_pIONThumbJpegBuffer) { - if (m_szIONThumbJpegBuffer >= thumbbufsize) - return true; + if (m_szIONThumbJpegBuffer >= thumbbufsize) return true; munmap(m_pIONThumbJpegBuffer, m_szIONThumbJpegBuffer); close(m_fdIONThumbJpegBuffer); @@ -713,16 +687,18 @@ bool ExynosJpegEncoderForCamera::AllocThumbJpegBuffer() m_fdIONThumbJpegBuffer = -1; } - m_fdIONThumbJpegBuffer = exynos_ion_alloc(m_fdIONClient, thumbbufsize, EXYNOS_ION_HEAP_SYSTEM_MASK, - ION_FLAG_CACHED | ION_FLAG_CACHED_NEEDS_SYNC); + m_fdIONThumbJpegBuffer = + exynos_ion_alloc(m_fdIONClient, thumbbufsize, EXYNOS_ION_HEAP_SYSTEM_MASK, + ION_FLAG_CACHED | ION_FLAG_CACHED_NEEDS_SYNC); if (m_fdIONThumbJpegBuffer < 0) { - ALOGERR("Failed to allocate %zu bytes for thumbnail stream buffer of %ux%u", - thumbbufsize, m_nThumbHeight, m_nThumbWidth); + ALOGERR("Failed to allocate %zu bytes for thumbnail stream buffer of %ux%u", thumbbufsize, + m_nThumbHeight, m_nThumbWidth); return false; } - m_pIONThumbJpegBuffer = reinterpret_cast<char *>( - mmap(NULL, thumbbufsize, PROT_READ | PROT_WRITE, MAP_SHARED, m_fdIONThumbJpegBuffer, 0)); + m_pIONThumbJpegBuffer = + reinterpret_cast<char *>(mmap(NULL, thumbbufsize, PROT_READ | PROT_WRITE, MAP_SHARED, + m_fdIONThumbJpegBuffer, 0)); if (m_pIONThumbJpegBuffer == MAP_FAILED) { ALOGERR("Failed to map thumbnail stream buffer (%zu bytes)", thumbbufsize); @@ -735,11 +711,10 @@ bool ExynosJpegEncoderForCamera::AllocThumbJpegBuffer() } size_t ExynosJpegEncoderForCamera::CompressThumbnailOnly(size_t limit, int quality, - unsigned int v4l2Format, int src_buftype) -{ + unsigned int v4l2Format, int src_buftype) { if (!m_phwjpeg4thumb->SetImageFormat(v4l2Format, m_nThumbWidth, m_nThumbHeight)) { - ALOGE("Failed to configure thumbnail source image format to %#010x, %ux%u", - v4l2Format, m_nThumbWidth, m_nThumbHeight); + ALOGE("Failed to configure thumbnail source image format to %#010x, %ux%u", v4l2Format, + m_nThumbWidth, m_nThumbHeight); return 0; } @@ -754,18 +729,18 @@ size_t ExynosJpegEncoderForCamera::CompressThumbnailOnly(size_t limit, int quali [[fallthrough]]; case V4L2_PIX_FMT_NV21M: num_buffers++; - break; + break; } if (src_buftype == JPEG_BUF_TYPE_USER_PTR) { - if (!m_phwjpeg4thumb->SetImageBuffer(m_pThumbnailImageBuffer, - m_szThumbnailImageLen, num_buffers)) { + if (!m_phwjpeg4thumb->SetImageBuffer(m_pThumbnailImageBuffer, m_szThumbnailImageLen, + num_buffers)) { ALOGE("Failed to configure thumbnail buffers(userptr) for thumbnail"); return 0; } } else { // JPEG_BUF_TYPE_DMA_BUF - if (!m_phwjpeg4thumb->SetImageBuffer(m_fdThumbnailImageBuffer, - m_szThumbnailImageLen, num_buffers)) { + if (!m_phwjpeg4thumb->SetImageBuffer(m_fdThumbnailImageBuffer, m_szThumbnailImageLen, + num_buffers)) { ALOGE("Failed to configure thumbnail buffers(dmabuf) for thumbnail"); return 0; } @@ -773,7 +748,7 @@ size_t ExynosJpegEncoderForCamera::CompressThumbnailOnly(size_t limit, int quali if (!m_phwjpeg4thumb->SetJpegBuffer(m_fdIONThumbJpegBuffer, m_szIONThumbJpegBuffer)) { ALOGE("Failed to configure thumbnail stream buffer (fd %d, size %zu)", - m_fdIONThumbJpegBuffer, m_szIONThumbJpegBuffer); + m_fdIONThumbJpegBuffer, m_szIONThumbJpegBuffer); return 0; } @@ -811,12 +786,10 @@ size_t ExynosJpegEncoderForCamera::CompressThumbnailOnly(size_t limit, int quali return 0; } -int ExynosJpegEncoderForCamera::setInBuf2(int *piBuf, int *iSize) -{ +int ExynosJpegEncoderForCamera::setInBuf2(int *piBuf, int *iSize) { NoThumbGenerationNeeded(); - if (!EnsureFormatIsApplied()) - return -1; + if (!EnsureFormatIsApplied()) return -1; CHWJpegCompressor &hwjpeg = GetCompressor(); unsigned int num_buffers = 3; @@ -831,7 +804,7 @@ int ExynosJpegEncoderForCamera::setInBuf2(int *piBuf, int *iSize) } if (IsBTBCompressionSupported() && - !hwjpeg.SetImageBuffer2(m_fdThumbnailImageBuffer, m_szThumbnailImageLen, num_buffers)) { + !hwjpeg.SetImageBuffer2(m_fdThumbnailImageBuffer, m_szThumbnailImageLen, num_buffers)) { ALOGE("Failed to configure thumbnail buffers"); return -1; } @@ -841,12 +814,10 @@ int ExynosJpegEncoderForCamera::setInBuf2(int *piBuf, int *iSize) return 0; } -int ExynosJpegEncoderForCamera::setInBuf2(char **pcBuf, int *iSize) -{ +int ExynosJpegEncoderForCamera::setInBuf2(char **pcBuf, int *iSize) { NoThumbGenerationNeeded(); - if (!EnsureFormatIsApplied()) - return -1; + if (!EnsureFormatIsApplied()) return -1; CHWJpegCompressor &hwjpeg = GetCompressor(); unsigned int num_buffers = 3; @@ -861,7 +832,7 @@ int ExynosJpegEncoderForCamera::setInBuf2(char **pcBuf, int *iSize) } if (IsBTBCompressionSupported() && - !hwjpeg.SetImageBuffer2(m_pThumbnailImageBuffer, m_szThumbnailImageLen, num_buffers)) { + !hwjpeg.SetImageBuffer2(m_pThumbnailImageBuffer, m_szThumbnailImageLen, num_buffers)) { ALOGE("Failed to configure thumbnail buffers"); return -1; } @@ -871,8 +842,7 @@ int ExynosJpegEncoderForCamera::setInBuf2(char **pcBuf, int *iSize) return 0; } -size_t ExynosJpegEncoderForCamera::GetThumbnailImage(char *buffer, size_t buflen) -{ +size_t ExynosJpegEncoderForCamera::GetThumbnailImage(char *buffer, size_t buflen) { if (m_fdIONThumbImgBuffer < 0) { ALOGE("No internal thumbnail buffer is allocated"); return 0; @@ -888,8 +858,8 @@ size_t ExynosJpegEncoderForCamera::GetThumbnailImage(char *buffer, size_t buflen "m_szIONThumbImgBuffer(%zu) is smaller than the thumbnail (%zu)", m_szIONThumbImgBuffer, thumbbufsize); if (m_pIONThumbImgBuffer == NULL) { - m_pIONThumbImgBuffer = reinterpret_cast<char *>(mmap( - NULL, m_szIONThumbImgBuffer, PROT_READ, MAP_SHARED, m_fdIONThumbImgBuffer, 0)); + m_pIONThumbImgBuffer = reinterpret_cast<char *>( + mmap(NULL, m_szIONThumbImgBuffer, PROT_READ, MAP_SHARED, m_fdIONThumbImgBuffer, 0)); if (m_pIONThumbImgBuffer == MAP_FAILED) { m_pIONThumbImgBuffer = NULL; ALOGERR("Failed to map thumbnail image buffer (%zu bytes)", m_szIONThumbImgBuffer); @@ -904,8 +874,7 @@ size_t ExynosJpegEncoderForCamera::GetThumbnailImage(char *buffer, size_t buflen return m_szIONThumbImgBuffer; } -int ExynosJpegEncoderForCamera::destroy() -{ +int ExynosJpegEncoderForCamera::destroy() { GetCompressor().Release(); return 0; } diff --git a/libhwjpeg/FileLock.cpp b/libhwjpeg/FileLock.cpp new file mode 100644 index 0000000..6e8ecbd --- /dev/null +++ b/libhwjpeg/FileLock.cpp @@ -0,0 +1,13 @@ +#include "FileLock.h" + +#include <bits/lockf.h> + +FileLock::FileLock(int fd) : fd_(fd) {} + +int FileLock::lock() { + return lockf(fd_, F_LOCK, 0); +} + +int FileLock::unlock() { + return lockf(fd_, F_ULOCK, 0); +} diff --git a/libhwjpeg/IFDWriter.h b/libhwjpeg/IFDWriter.h index 33f7ff8..61e6d17 100644 --- a/libhwjpeg/IFDWriter.h +++ b/libhwjpeg/IFDWriter.h @@ -21,6 +21,7 @@ class CEndianessChecker { bool __little; + public: CEndianessChecker(); operator bool() { return __little; } @@ -30,8 +31,7 @@ extern CEndianessChecker __LITTLE_ENDIAN__; #endif template <typename T> -char *WriteDataInBig(char *p, T val) -{ +char *WriteDataInBig(char *p, T val) { if (sizeof(val) == 1) { *p++ = val; } else if (__LITTLE_ENDIAN__) { @@ -50,7 +50,7 @@ char *WriteDataInBig(char *p, T val) } else { switch (sizeof(val)) { case 2: - *p++ = static_cast<char>(val & 0xFF); + *p++ = static_cast<char>(val & 0xFF); *p++ = static_cast<char>((val >> 8) & 0xFF); break; case 4: @@ -66,11 +66,9 @@ char *WriteDataInBig(char *p, T val) } template <typename T> -char *WriteData(char *p, T val) -{ +char *WriteData(char *p, T val) { const char *pt = reinterpret_cast<char *>(&val); - for (size_t i = 0; i < sizeof(val); i++) - *p++ = *pt++; + for (size_t i = 0; i < sizeof(val); i++) *p++ = *pt++; return p; } @@ -107,13 +105,14 @@ class CIFDWriter { m_nTags--; } + public: CIFDWriter(char *offset_base, char *ifdbase, uint16_t tagcount) { m_nTags = tagcount; m_pBase = offset_base; m_pIFDBase = ifdbase; - m_pValue = m_pIFDBase + IFD_FIELDCOUNT_SIZE + - IFD_FIELD_SIZE * tagcount + IFD_NEXTIFDOFFSET_SIZE; + m_pValue = m_pIFDBase + IFD_FIELDCOUNT_SIZE + IFD_FIELD_SIZE * tagcount + + IFD_NEXTIFDOFFSET_SIZE; // COUNT field of IFD const char *pval = reinterpret_cast<char *>(&m_nTags); @@ -136,8 +135,7 @@ public: *m_pValue++ = static_cast<char>(value[i]); } } else { - for (uint32_t i = 0; i < count; i++) - *m_pIFDBase++ = static_cast<char>(value[i]); + for (uint32_t i = 0; i < count; i++) *m_pIFDBase++ = static_cast<char>(value[i]); m_pIFDBase += IFD_VALOFF_SIZE - count; } } @@ -192,8 +190,7 @@ public: m_pValue[count - 1] = '\0'; m_pValue += count; } else { - for (uint32_t i = 0; i < count; i++) - *m_pIFDBase++ = value[i]; + for (uint32_t i = 0; i < count; i++) *m_pIFDBase++ = value[i]; *(m_pIFDBase - 1) = '\0'; m_pIFDBase += IFD_VALOFF_SIZE - count; } @@ -212,11 +209,9 @@ public: } else { uint32_t i; - for (i = 0; (i < (count - 1)) && (string[i] != '\0'); i++) - *m_pIFDBase++ = string[i]; + for (i = 0; (i < (count - 1)) && (string[i] != '\0'); i++) *m_pIFDBase++ = string[i]; - while (i++ < count) - *m_pIFDBase++ = '\0'; + while (i++ < count) *m_pIFDBase++ = '\0'; m_pIFDBase += IFD_VALOFF_SIZE - count; } @@ -250,8 +245,7 @@ public: m_pIFDBase = WriteOffset(m_pIFDBase, m_pValue); const char *pt = reinterpret_cast<const char *>(value); - for (uint32_t i = 0; i < sizeof(srational_t) * count; i++) - *m_pValue++ = *pt++; + for (uint32_t i = 0; i < sizeof(srational_t) * count; i++) *m_pValue++ = *pt++; } void WriteUndef(uint16_t tag, uint32_t count, const unsigned char *value) { @@ -263,8 +257,7 @@ public: memcpy(m_pValue, value, count); m_pValue += count; } else { - for (uint32_t i = 0; i < count; i++) - *m_pIFDBase++ = static_cast<char>(value[i]); + for (uint32_t i = 0; i < count; i++) *m_pIFDBase++ = static_cast<char>(value[i]); m_pIFDBase += IFD_VALOFF_SIZE - count; } } diff --git a/libhwjpeg/LibScalerForJpeg.cpp b/libhwjpeg/LibScalerForJpeg.cpp index 1165495..1886d49 100644 --- a/libhwjpeg/LibScalerForJpeg.cpp +++ b/libhwjpeg/LibScalerForJpeg.cpp @@ -15,67 +15,57 @@ * limitations under the License. */ -#include "hwjpeg-internal.h" #include "LibScalerForJpeg.h" +#include "hwjpeg-internal.h" + #define SCALER_DEV_NODE "/dev/video50" -static const char *getBufTypeString(unsigned int buftype) -{ - if (buftype == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) - return "destination"; - if (buftype == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) - return "source"; +static const char *getBufTypeString(unsigned int buftype) { + if (buftype == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) return "destination"; + if (buftype == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) return "source"; return "unknown"; } -bool LibScalerForJpeg::RunStream(int srcBuf[SCALER_MAX_PLANES], int __unused srcLen[SCALER_MAX_PLANES], int dstBuf, size_t __unused dstLen) -{ - if (!mSrcImage.begin(V4L2_MEMORY_DMABUF) || !mDstImage.begin(V4L2_MEMORY_DMABUF)) - return false; +bool LibScalerForJpeg::RunStream(int srcBuf[SCALER_MAX_PLANES], + int __unused srcLen[SCALER_MAX_PLANES], int dstBuf, + size_t __unused dstLen) { + if (!mSrcImage.begin(V4L2_MEMORY_DMABUF) || !mDstImage.begin(V4L2_MEMORY_DMABUF)) return false; return queue(srcBuf, dstBuf); } -bool LibScalerForJpeg::RunStream(char *srcBuf[SCALER_MAX_PLANES], int __unused srcLen[SCALER_MAX_PLANES], int dstBuf, size_t __unused dstLen) -{ - if (!mSrcImage.begin(V4L2_MEMORY_USERPTR) || !mDstImage.begin(V4L2_MEMORY_DMABUF)) - return false; +bool LibScalerForJpeg::RunStream(char *srcBuf[SCALER_MAX_PLANES], + int __unused srcLen[SCALER_MAX_PLANES], int dstBuf, + size_t __unused dstLen) { + if (!mSrcImage.begin(V4L2_MEMORY_USERPTR) || !mDstImage.begin(V4L2_MEMORY_DMABUF)) return false; return queue(srcBuf, dstBuf); } -bool LibScalerForJpeg::Image::set(unsigned int width, unsigned int height, unsigned int format) -{ - if (same(width, height, format)) - return true; +bool LibScalerForJpeg::Image::set(unsigned int width, unsigned int height, unsigned int format) { + if (same(width, height, format)) return true; if (memoryType != 0) { - if (!mDevice.requestBuffers(bufferType, memoryType, 0)) - return false; + if (!mDevice.requestBuffers(bufferType, memoryType, 0)) return false; } - if (!mDevice.setFormat(bufferType, format, width, height, planeLen)) - return false; + if (!mDevice.setFormat(bufferType, format, width, height, planeLen)) return false; memoryType = 0; // new reqbufs is required. return true; } -bool LibScalerForJpeg::Image::begin(unsigned int memtype) -{ +bool LibScalerForJpeg::Image::begin(unsigned int memtype) { if (memoryType != memtype) { if (memoryType != 0) { - if (!mDevice.requestBuffers(bufferType, memoryType, 0)) - return false; + if (!mDevice.requestBuffers(bufferType, memoryType, 0)) return false; } - if (!mDevice.requestBuffers(bufferType, memtype, 1)) - return false; + if (!mDevice.requestBuffers(bufferType, memtype, 1)) return false; - if (!mDevice.streamOn(bufferType)) - return false; + if (!mDevice.streamOn(bufferType)) return false; memoryType = memtype; } @@ -83,41 +73,34 @@ bool LibScalerForJpeg::Image::begin(unsigned int memtype) return true; } -bool LibScalerForJpeg::Image::cancelBuffer() -{ - if (!mDevice.streamOff(bufferType)) - return false; +bool LibScalerForJpeg::Image::cancelBuffer() { + if (!mDevice.streamOff(bufferType)) return false; - if (!mDevice.streamOn(bufferType)) - return false; + if (!mDevice.streamOn(bufferType)) return false; return true; } -LibScalerForJpeg::Device::Device() -{ +LibScalerForJpeg::Device::Device() { mFd = ::open(SCALER_DEV_NODE, O_RDWR); - if (mFd < 0) - ALOGERR("failed to open %s", SCALER_DEV_NODE); + if (mFd < 0) ALOGERR("failed to open %s", SCALER_DEV_NODE); } -LibScalerForJpeg::Device::~Device() -{ - if (mFd >= 0) - ::close(mFd); +LibScalerForJpeg::Device::~Device() { + if (mFd >= 0) ::close(mFd); } -bool LibScalerForJpeg::Device::requestBuffers(unsigned int buftype, unsigned int memtype, unsigned int count) -{ - // count==0 means this port should be reconfigured and it is successful under streaming is finished. - if (!count) - streamOff(buftype); +bool LibScalerForJpeg::Device::requestBuffers(unsigned int buftype, unsigned int memtype, + unsigned int count) { + // count==0 means this port should be reconfigured and it is successful under streaming is + // finished. + if (!count) streamOff(buftype); v4l2_requestbuffers reqbufs{}; - reqbufs.type = buftype; - reqbufs.memory = memtype; - reqbufs.count = count; + reqbufs.type = buftype; + reqbufs.memory = memtype; + reqbufs.count = count; if (ioctl(mFd, VIDIOC_REQBUFS, &reqbufs) < 0) { ALOGERR("failed REQBUFS(%s, mem=%d, count=%d)", getBufTypeString(buftype), memtype, count); @@ -127,29 +110,30 @@ bool LibScalerForJpeg::Device::requestBuffers(unsigned int buftype, unsigned int return true; } -bool LibScalerForJpeg::Device::setFormat(unsigned int buftype, unsigned int format, unsigned int width, unsigned int height, unsigned int planelen[SCALER_MAX_PLANES]) -{ +bool LibScalerForJpeg::Device::setFormat(unsigned int buftype, unsigned int format, + unsigned int width, unsigned int height, + unsigned int planelen[SCALER_MAX_PLANES]) { v4l2_format fmt{}; fmt.type = buftype; fmt.fmt.pix_mp.pixelformat = format; - fmt.fmt.pix_mp.width = width; + fmt.fmt.pix_mp.width = width; fmt.fmt.pix_mp.height = height; if (ioctl(mFd, VIDIOC_S_FMT, &fmt) < 0) { - ALOGERR("failed S_FMT(%s, fmt=h'%x, %ux%u)", getBufTypeString(buftype), format, width, height); + ALOGERR("failed S_FMT(%s, fmt=h'%x, %ux%u)", getBufTypeString(buftype), format, width, + height); return false; } - for (uint32_t i = 0; i < fmt.fmt.pix_mp.num_planes ; i++) { + for (uint32_t i = 0; i < fmt.fmt.pix_mp.num_planes; i++) { planelen[i] = fmt.fmt.pix_mp.plane_fmt[i].sizeimage; } return true; } -bool LibScalerForJpeg::Device::streamOn(unsigned int buftype) -{ +bool LibScalerForJpeg::Device::streamOn(unsigned int buftype) { if (ioctl(mFd, VIDIOC_STREAMON, &buftype) < 0) { ALOGERR("failed STREAMON for %s", getBufTypeString(buftype)); return false; @@ -158,8 +142,7 @@ bool LibScalerForJpeg::Device::streamOn(unsigned int buftype) return true; } -bool LibScalerForJpeg::Device::streamOff(unsigned int buftype) -{ +bool LibScalerForJpeg::Device::streamOff(unsigned int buftype) { if (ioctl(mFd, VIDIOC_STREAMOFF, &buftype) < 0) { ALOGERR("failed STREAMOFF for %s", getBufTypeString(buftype)); return false; @@ -168,8 +151,8 @@ bool LibScalerForJpeg::Device::streamOff(unsigned int buftype) return true; } -bool LibScalerForJpeg::Device::queueBuffer(unsigned int buftype, std::function<void(v4l2_buffer &)> bufferFiller) -{ +bool LibScalerForJpeg::Device::queueBuffer(unsigned int buftype, + std::function<void(v4l2_buffer &)> bufferFiller) { v4l2_buffer buffer{}; v4l2_plane plane[SCALER_MAX_PLANES]; @@ -183,47 +166,50 @@ bool LibScalerForJpeg::Device::queueBuffer(unsigned int buftype, std::function<v return ioctl(mFd, VIDIOC_QBUF, &buffer) >= 0; } -bool LibScalerForJpeg::Device::queueBuffer(unsigned int buftype, int buf[SCALER_MAX_PLANES], unsigned int len[SCALER_MAX_PLANES]) -{ - if (!queueBuffer(buftype, [buf, len] (v4l2_buffer &buffer) { - buffer.memory = V4L2_MEMORY_DMABUF; - buffer.length = SCALER_MAX_PLANES; - for (unsigned int i = 0; i < SCALER_MAX_PLANES; i++) { - buffer.m.planes[i].m.fd = buf[i]; - buffer.m.planes[i].length = len[i]; - } })) { - ALOGERR("failed QBUF(%s, fd[]=%d %d, len[0]=%d %d)", getBufTypeString(buftype), buf[0], buf[1], len[0], len[1]); +bool LibScalerForJpeg::Device::queueBuffer(unsigned int buftype, int buf[SCALER_MAX_PLANES], + unsigned int len[SCALER_MAX_PLANES]) { + if (!queueBuffer(buftype, [buf, len](v4l2_buffer &buffer) { + buffer.memory = V4L2_MEMORY_DMABUF; + buffer.length = SCALER_MAX_PLANES; + for (unsigned int i = 0; i < SCALER_MAX_PLANES; i++) { + buffer.m.planes[i].m.fd = buf[i]; + buffer.m.planes[i].length = len[i]; + } + })) { + ALOGERR("failed QBUF(%s, fd[]=%d %d, len[0]=%d %d)", getBufTypeString(buftype), buf[0], + buf[1], len[0], len[1]); return false; } return true; } -bool LibScalerForJpeg::Device::queueBuffer(unsigned int buftype, char *buf[SCALER_MAX_PLANES], unsigned int len[SCALER_MAX_PLANES]) -{ - if (!queueBuffer(buftype, [buf, len] (v4l2_buffer &buffer) { - buffer.memory = V4L2_MEMORY_USERPTR; - buffer.length = SCALER_MAX_PLANES; - for (unsigned int i = 0; i < SCALER_MAX_PLANES; i++) { - buffer.m.planes[i].m.userptr = reinterpret_cast<unsigned long>(buf[i]); - buffer.m.planes[i].length = len[i]; - } })) { - ALOGERR("failed QBUF(%s, ptr[]=%p %p, len[0]=%d %d)", getBufTypeString(buftype), buf[0], buf[1], len[0], len[1]); +bool LibScalerForJpeg::Device::queueBuffer(unsigned int buftype, char *buf[SCALER_MAX_PLANES], + unsigned int len[SCALER_MAX_PLANES]) { + if (!queueBuffer(buftype, [buf, len](v4l2_buffer &buffer) { + buffer.memory = V4L2_MEMORY_USERPTR; + buffer.length = SCALER_MAX_PLANES; + for (unsigned int i = 0; i < SCALER_MAX_PLANES; i++) { + buffer.m.planes[i].m.userptr = reinterpret_cast<unsigned long>(buf[i]); + buffer.m.planes[i].length = len[i]; + } + })) { + ALOGERR("failed QBUF(%s, ptr[]=%p %p, len[0]=%d %d)", getBufTypeString(buftype), buf[0], + buf[1], len[0], len[1]); return false; } return true; } -bool LibScalerForJpeg::Device::queueBuffer(unsigned int buftype, int buf, unsigned int len[SCALER_MAX_PLANES]) -{ - if (!queueBuffer(buftype, [buf, len] (v4l2_buffer &buffer) - { - buffer.memory = V4L2_MEMORY_DMABUF; - buffer.length = 1; - buffer.m.planes[0].m.fd = buf; - buffer.m.planes[0].length = len[0]; - })) { +bool LibScalerForJpeg::Device::queueBuffer(unsigned int buftype, int buf, + unsigned int len[SCALER_MAX_PLANES]) { + if (!queueBuffer(buftype, [buf, len](v4l2_buffer &buffer) { + buffer.memory = V4L2_MEMORY_DMABUF; + buffer.length = 1; + buffer.m.planes[0].m.fd = buf; + buffer.m.planes[0].length = len[0]; + })) { ALOGERR("failed QBUF(%s, fd=%d, len=%d", getBufTypeString(buftype), buf, len[0]); return false; } @@ -231,8 +217,7 @@ bool LibScalerForJpeg::Device::queueBuffer(unsigned int buftype, int buf, unsign return true; } -bool LibScalerForJpeg::Device::dequeueBuffer(unsigned int buftype, unsigned int memtype) -{ +bool LibScalerForJpeg::Device::dequeueBuffer(unsigned int buftype, unsigned int memtype) { v4l2_buffer buffer{}; v4l2_plane plane[SCALER_MAX_PLANES]; @@ -244,7 +229,7 @@ bool LibScalerForJpeg::Device::dequeueBuffer(unsigned int buftype, unsigned int buffer.m.planes = plane; - if (ioctl(mFd, VIDIOC_DQBUF, &buffer) < 0 ) { + if (ioctl(mFd, VIDIOC_DQBUF, &buffer) < 0) { ALOGERR("failed DQBUF(%s)", getBufTypeString(buftype)); return false; } diff --git a/libhwjpeg/LibScalerForJpeg.h b/libhwjpeg/LibScalerForJpeg.h index f8914d7..4c90e43 100644 --- a/libhwjpeg/LibScalerForJpeg.h +++ b/libhwjpeg/LibScalerForJpeg.h @@ -16,16 +16,16 @@ #ifndef __HARDWARE_EXYNOS_LIBSCALERFORJPEG_H__ #define __HARDWARE_EXYNOS_LIBSCALERFORJPEG_H__ -#include <functional> - #include <linux/videodev2.h> +#include <functional> + #include "ThumbnailScaler.h" class LibScalerForJpeg : public ThumbnailScaler { public: - LibScalerForJpeg() { } - ~LibScalerForJpeg() { } + LibScalerForJpeg() {} + ~LibScalerForJpeg() {} bool SetSrcImage(unsigned int width, unsigned int height, unsigned int v4l2_format) { return mSrcImage.set(width, height, v4l2_format); @@ -35,10 +35,13 @@ public: return mDstImage.set(width, height, v4l2_format); } - bool RunStream(int srcBuf[SCALER_MAX_PLANES], int srcLen[SCALER_MAX_PLANES], int dstBuf, size_t dstLen); - bool RunStream(char *srcBuf[SCALER_MAX_PLANES], int srcLen[SCALER_MAX_PLANES], int dstBuf, size_t dstLen); + bool RunStream(int srcBuf[SCALER_MAX_PLANES], int srcLen[SCALER_MAX_PLANES], int dstBuf, + size_t dstLen); + bool RunStream(char *srcBuf[SCALER_MAX_PLANES], int srcLen[SCALER_MAX_PLANES], int dstBuf, + size_t dstLen); bool available() { return mDevice.mFd >= 0; } + private: struct Device { int mFd; @@ -46,12 +49,15 @@ private: Device(); ~Device(); bool requestBuffers(unsigned int buftype, unsigned int memtype, unsigned int count); - bool setFormat(unsigned int buftype, unsigned int format, unsigned int width, unsigned int height, unsigned int planelen[SCALER_MAX_PLANES]); + bool setFormat(unsigned int buftype, unsigned int format, unsigned int width, + unsigned int height, unsigned int planelen[SCALER_MAX_PLANES]); bool streamOn(unsigned int buftype); bool streamOff(unsigned int buftype); bool queueBuffer(unsigned int buftype, std::function<void(v4l2_buffer &)> bufferFiller); - bool queueBuffer(unsigned int buftype, int buf[SCALER_MAX_PLANES], unsigned int len[SCALER_MAX_PLANES]); - bool queueBuffer(unsigned int buftype, char *buf[SCALER_MAX_PLANES], unsigned int len[SCALER_MAX_PLANES]); + bool queueBuffer(unsigned int buftype, int buf[SCALER_MAX_PLANES], + unsigned int len[SCALER_MAX_PLANES]); + bool queueBuffer(unsigned int buftype, char *buf[SCALER_MAX_PLANES], + unsigned int len[SCALER_MAX_PLANES]); bool queueBuffer(unsigned int buftype, int buf, unsigned int len[SCALER_MAX_PLANES]); bool dequeueBuffer(unsigned int buftype, unsigned int memtype); }; @@ -66,24 +72,26 @@ private: unsigned int planeLen[SCALER_MAX_PLANES]; Image(Device &dev, unsigned int w, unsigned int h, unsigned int f, unsigned int buftype) - : mDevice(dev), width(w), height(h), format(f), bufferType(buftype) - { } + : mDevice(dev), width(w), height(h), format(f), bufferType(buftype) {} bool set(unsigned int width, unsigned int height, unsigned int format); bool begin(unsigned int memtype); bool cancelBuffer(); template <class tBuf> - bool queueBuffer(tBuf buf) { return mDevice.queueBuffer(bufferType, buf, planeLen); } + bool queueBuffer(tBuf buf) { + return mDevice.queueBuffer(bufferType, buf, planeLen); + } bool dequeueBuffer() { return mDevice.dequeueBuffer(bufferType, memoryType); } - bool same(unsigned int w, unsigned int h, unsigned int f) { return width == w && height == h && format == f; } + bool same(unsigned int w, unsigned int h, unsigned int f) { + return width == w && height == h && format == f; + } }; - template<class T> + template <class T> bool queue(T srcBuf[SCALER_MAX_PLANES], int dstBuf) { - if (!mSrcImage.queueBuffer(srcBuf)) - return false; + if (!mSrcImage.queueBuffer(srcBuf)) return false; if (!mDstImage.queueBuffer(dstBuf)) { mSrcImage.cancelBuffer(); diff --git a/libhwjpeg/ThumbnailScaler.cpp b/libhwjpeg/ThumbnailScaler.cpp index 4d6e5de..3f4edcf 100644 --- a/libhwjpeg/ThumbnailScaler.cpp +++ b/libhwjpeg/ThumbnailScaler.cpp @@ -14,13 +14,13 @@ * limitations under the License. */ +#include "ThumbnailScaler.h" + #include <log/log.h> -#include "ThumbnailScaler.h" #include "LibScalerForJpeg.h" -ThumbnailScaler *ThumbnailScaler::createInstance() -{ +ThumbnailScaler *ThumbnailScaler::createInstance() { ALOGD("Created thumbnail scaler: legacy V4L2 Scaler"); return new LibScalerForJpeg(); } diff --git a/libhwjpeg/ThumbnailScaler.h b/libhwjpeg/ThumbnailScaler.h index cb23365..14d6e7d 100644 --- a/libhwjpeg/ThumbnailScaler.h +++ b/libhwjpeg/ThumbnailScaler.h @@ -6,14 +6,16 @@ class ThumbnailScaler { public: const static unsigned int SCALER_MAX_PLANES = 3; - ThumbnailScaler() { } - virtual ~ThumbnailScaler() { } + ThumbnailScaler() {} + virtual ~ThumbnailScaler() {} virtual bool SetSrcImage(unsigned int width, unsigned int height, unsigned int v4l2_format) = 0; virtual bool SetDstImage(unsigned int width, unsigned int height, unsigned int v4l2_format) = 0; - virtual bool RunStream(int srcBuf[SCALER_MAX_PLANES], int srcLen[SCALER_MAX_PLANES], int dstBuf, size_t dstLen) = 0; - virtual bool RunStream(char *srcBuf[SCALER_MAX_PLANES], int srcLen[SCALER_MAX_PLANES], int dstBuf, size_t dstLen) = 0; + virtual bool RunStream(int srcBuf[SCALER_MAX_PLANES], int srcLen[SCALER_MAX_PLANES], int dstBuf, + size_t dstLen) = 0; + virtual bool RunStream(char *srcBuf[SCALER_MAX_PLANES], int srcLen[SCALER_MAX_PLANES], + int dstBuf, size_t dstLen) = 0; static ThumbnailScaler *createInstance(); diff --git a/libhwjpeg/hwjpeg-base.cpp b/libhwjpeg/hwjpeg-base.cpp index e593c02..f319d50 100644 --- a/libhwjpeg/hwjpeg-base.cpp +++ b/libhwjpeg/hwjpeg-base.cpp @@ -15,52 +15,41 @@ * limitations under the License. */ -#include <sys/types.h> -#include <sys/stat.h> -#include <sys/mman.h> +#include <exynos-hwjpeg.h> #include <fcntl.h> - -#include <linux/videodev2.h> #include <linux/v4l2-controls.h> +#include <linux/videodev2.h> +#include <sys/mman.h> +#include <sys/stat.h> +#include <sys/types.h> -#include <exynos-hwjpeg.h> #include "hwjpeg-internal.h" -CHWJpegBase::CHWJpegBase(const char *path) - : m_iFD(-1), m_uiDeviceCaps(0), m_uiAuxFlags(0) -{ +CHWJpegBase::CHWJpegBase(const char *path) : m_iFD(-1), m_uiDeviceCaps(0), m_uiAuxFlags(0) { m_iFD = open(path, O_RDWR); - if (m_iFD < 0) - ALOGERR("Failed to open '%s'", path); + if (m_iFD < 0) ALOGERR("Failed to open '%s'", path); } -CHWJpegBase::~CHWJpegBase() -{ - if (m_iFD >= 0) - close(m_iFD); +CHWJpegBase::~CHWJpegBase() { + if (m_iFD >= 0) close(m_iFD); } -void CHWJpegBase::SetAuxFlags(unsigned int auxflags) -{ +void CHWJpegBase::SetAuxFlags(unsigned int auxflags) { ALOGW_IF(!!(m_uiAuxFlags & auxflags), - "Configuration auxiliary flags %#x overrides previous flags %#x", - auxflags , m_uiAuxFlags); + "Configuration auxiliary flags %#x overrides previous flags %#x", auxflags, + m_uiAuxFlags); m_uiAuxFlags |= auxflags; } -void CHWJpegBase::ClearAuxFlags(unsigned int auxflags) -{ - +void CHWJpegBase::ClearAuxFlags(unsigned int auxflags) { ALOGW_IF(!!(m_uiAuxFlags & auxflags) && ((m_uiAuxFlags & auxflags) != auxflags), - "Clearing auxiliary flags %#x overrides previous flags %#x", - auxflags, m_uiAuxFlags); + "Clearing auxiliary flags %#x overrides previous flags %#x", auxflags, m_uiAuxFlags); m_uiAuxFlags &= ~auxflags; } -bool CStopWatch::Start() -{ +bool CStopWatch::Start() { int ret = clock_gettime(CLOCK_MONOTONIC, &m_tBegin); if (ret) { ALOGERR("Failed to get current clock"); @@ -71,8 +60,7 @@ bool CStopWatch::Start() return true; } -unsigned long CStopWatch::GetElapsed() -{ +unsigned long CStopWatch::GetElapsed() { timespec tp; int ret = clock_gettime(CLOCK_MONOTONIC, &tp); if (ret) { @@ -81,13 +69,11 @@ unsigned long CStopWatch::GetElapsed() } unsigned long elapsed = (tp.tv_sec - m_tBegin.tv_sec) * 1000000; - return (m_tBegin.tv_nsec > tp.tv_nsec) - ? elapsed - (m_tBegin.tv_nsec - tp.tv_nsec) / 1000 - : elapsed + (tp.tv_nsec - m_tBegin.tv_nsec) / 1000; + return (m_tBegin.tv_nsec > tp.tv_nsec) ? elapsed - (m_tBegin.tv_nsec - tp.tv_nsec) / 1000 + : elapsed + (tp.tv_nsec - m_tBegin.tv_nsec) / 1000; } -unsigned long CStopWatch::GetElapsedUpdate() -{ +unsigned long CStopWatch::GetElapsedUpdate() { timespec tp; int ret = clock_gettime(CLOCK_MONOTONIC, &tp); if (ret) { @@ -96,17 +82,15 @@ unsigned long CStopWatch::GetElapsedUpdate() } unsigned long elapsed = (tp.tv_sec - m_tBegin.tv_sec) * 1000000; - elapsed = (m_tBegin.tv_nsec > tp.tv_nsec) - ? elapsed - (m_tBegin.tv_nsec - tp.tv_nsec) / 1000 - : elapsed + (tp.tv_nsec - m_tBegin.tv_nsec) / 1000; + elapsed = (m_tBegin.tv_nsec > tp.tv_nsec) ? elapsed - (m_tBegin.tv_nsec - tp.tv_nsec) / 1000 + : elapsed + (tp.tv_nsec - m_tBegin.tv_nsec) / 1000; m_tBegin = tp; return elapsed; } -bool WriteToFile(const char *path, const char *data, size_t len) -{ - int fd = open(path, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH | S_IWGRP ); +bool WriteToFile(const char *path, const char *data, size_t len) { + int fd = open(path, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH | S_IWGRP); if (fd < 0) { ALOGERR("Failed to open '%s' for write/create", path); return false; @@ -124,15 +108,15 @@ bool WriteToFile(const char *path, const char *data, size_t len) return true; } -bool WriteToFile(const char *path, int dmabuf, size_t len) -{ - char *p = reinterpret_cast<char *>(mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED, dmabuf, 0)); +bool WriteToFile(const char *path, int dmabuf, size_t len) { + char *p = reinterpret_cast<char *>( + mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED, dmabuf, 0)); if (p == MAP_FAILED) { ALOGERR("Filed to map the given dmabuf fd %d", dmabuf); return false; } - int fd = open(path, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH | S_IWGRP ); + int fd = open(path, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH | S_IWGRP); if (fd < 0) { ALOGERR("Failed to open '%s' for write/create", path); munmap(p, len); diff --git a/libhwjpeg/hwjpeg-internal.h b/libhwjpeg/hwjpeg-internal.h index 8113871..bb14a35 100644 --- a/libhwjpeg/hwjpeg-internal.h +++ b/libhwjpeg/hwjpeg-internal.h @@ -22,18 +22,18 @@ #error "LOG_TAG is not defined!" #endif -#include <cerrno> -#include <cstring> - -#include <unistd.h> #include <log/log.h> -#include <time.h> #include <sys/ioctl.h> +#include <time.h> +#include <unistd.h> + +#include <cerrno> +#include <cstring> #ifdef __GNUC__ -# define __UNUSED__ __attribute__((__unused__)) +#define __UNUSED__ __attribute__((__unused__)) #else -# define __UNUSED__ +#define __UNUSED__ #endif #ifndef ALOGERR @@ -41,14 +41,16 @@ #endif #define V4L2_CID_JPEG_SEC_COMP_QUALITY (V4L2_CID_JPEG_CLASS_BASE + 20) -#define V4L2_CID_JPEG_QTABLES2 (V4L2_CID_JPEG_CLASS_BASE + 22) -#define V4L2_CID_JPEG_HWFC_ENABLE (V4L2_CID_JPEG_CLASS_BASE + 25) +#define V4L2_CID_JPEG_QTABLES2 (V4L2_CID_JPEG_CLASS_BASE + 22) +#define V4L2_CID_JPEG_HWFC_ENABLE (V4L2_CID_JPEG_CLASS_BASE + 25) +#define V4L2_CID_JPEG_PADDING (V4L2_CID_JPEG_CLASS_BASE + 26) +#define V4L2_CID_JPEG_SEC_PADDING (V4L2_CID_JPEG_CLASS_BASE + 27) -#define TO_MAIN_SIZE(val) ((val) & 0xFFFF) -#define TO_THUMB_SIZE(val) (((val) & 0xFFFF) << 16) +#define TO_MAIN_SIZE(val) ((val)&0xFFFF) +#define TO_THUMB_SIZE(val) (((val)&0xFFFF) << 16) #define TO_IMAGE_SIZE(main, thumb) (TO_MAIN_SIZE(main) | TO_THUMB_SIZE(thumb)) -#define PTR_TO_ULONG(ptr) reinterpret_cast<unsigned long>(ptr) +#define PTR_TO_ULONG(ptr) reinterpret_cast<unsigned long>(ptr) #define PTR_DIFF(ptr1, ptr2) (reinterpret_cast<size_t>(ptr2) - reinterpret_cast<size_t>(ptr1)) #define ARRSIZE(v) (sizeof(v) / sizeof(v[0])) @@ -74,10 +76,10 @@ static inline T max(T val1, T val2) { class CStopWatch { timespec m_tBegin; + public: CStopWatch(bool start = false) { - if (start) - Start(); + if (start) Start(); } bool Start(); unsigned long GetElapsed(); diff --git a/libhwjpeg/hwjpeg-v4l2.cpp b/libhwjpeg/hwjpeg-v4l2.cpp index bfa1a52..c364554 100644 --- a/libhwjpeg/hwjpeg-v4l2.cpp +++ b/libhwjpeg/hwjpeg-v4l2.cpp @@ -15,14 +15,15 @@ * limitations under the License. */ -#include <linux/videodev2.h> +#include <exynos-hwjpeg.h> #include <linux/v4l2-controls.h> +#include <linux/videodev2.h> -#include <exynos-hwjpeg.h> #include "hwjpeg-internal.h" +#include "log/log_main.h" -CHWJpegV4L2Compressor::CHWJpegV4L2Compressor(): CHWJpegCompressor("/dev/video12") -{ +CHWJpegV4L2Compressor::CHWJpegV4L2Compressor() + : CHWJpegCompressor("/dev/video12"), file_lock_(FileLock(GetDeviceFD())) { memset(&m_v4l2Format, 0, sizeof(m_v4l2Format)); memset(&m_v4l2SrcBuffer, 0, sizeof(m_v4l2SrcBuffer)); memset(&m_v4l2DstBuffer, 0, sizeof(m_v4l2DstBuffer)); @@ -63,27 +64,42 @@ CHWJpegV4L2Compressor::CHWJpegV4L2Compressor(): CHWJpegCompressor("/dev/video12" ALOGD("CHWJpegV4L2Compressor Created: %p, FD %d", this, GetDeviceFD()); } -CHWJpegV4L2Compressor::~CHWJpegV4L2Compressor() -{ +CHWJpegV4L2Compressor::~CHWJpegV4L2Compressor() { StopStreaming(); ALOGD("CHWJpegV4L2Compressor Destroyed: %p, FD %d", this, GetDeviceFD()); } -bool CHWJpegV4L2Compressor::SetChromaSampFactor( - unsigned int horizontal, unsigned int vertical) -{ +int CHWJpegV4L2Compressor::lock() { + return file_lock_.lock(); +} + +int CHWJpegV4L2Compressor::unlock() { + return file_lock_.unlock(); +} + +bool CHWJpegV4L2Compressor::SetChromaSampFactor(unsigned int horizontal, unsigned int vertical) { __s32 value; switch ((horizontal << 4) | vertical) { - case 0x00: value = V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY; break; - case 0x11: value = V4L2_JPEG_CHROMA_SUBSAMPLING_444; break; - case 0x21: value = V4L2_JPEG_CHROMA_SUBSAMPLING_422; break; - case 0x22: value = V4L2_JPEG_CHROMA_SUBSAMPLING_420; break; - case 0x41: value = V4L2_JPEG_CHROMA_SUBSAMPLING_411; break; + case 0x00: + value = V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY; + break; + case 0x11: + value = V4L2_JPEG_CHROMA_SUBSAMPLING_444; + break; + case 0x21: + value = V4L2_JPEG_CHROMA_SUBSAMPLING_422; + break; + case 0x22: + value = V4L2_JPEG_CHROMA_SUBSAMPLING_420; + break; + case 0x41: + value = V4L2_JPEG_CHROMA_SUBSAMPLING_411; + break; case 0x12: default: - ALOGE("Unsupported chroma subsampling %ux%u", horizontal, vertical); - return false; + ALOGE("Unsupported chroma subsampling %ux%u", horizontal, vertical); + return false; } m_v4l2Controls[HWJPEG_CTRL_CHROMFACTOR].id = V4L2_CID_JPEG_CHROMA_SUBSAMPLING; @@ -93,17 +109,14 @@ bool CHWJpegV4L2Compressor::SetChromaSampFactor( return true; } -bool CHWJpegV4L2Compressor::SetQuality( - unsigned int quality_factor, unsigned int quality_factor2) -{ +bool CHWJpegV4L2Compressor::SetQuality(unsigned int quality_factor, unsigned int quality_factor2) { if (quality_factor > 100) { ALOGE("Unsupported quality factor %u", quality_factor); return false; } if (quality_factor2 > 100) { - ALOGE("Unsupported quality factor %u for the secondary image", - quality_factor2); + ALOGE("Unsupported quality factor %u for the secondary image", quality_factor2); return false; } @@ -122,8 +135,7 @@ bool CHWJpegV4L2Compressor::SetQuality( return true; } -bool CHWJpegV4L2Compressor::SetQuality(const unsigned char qtable[]) -{ +bool CHWJpegV4L2Compressor::SetQuality(const unsigned char qtable[]) { v4l2_ext_controls ctrls; v4l2_ext_control ctrl; @@ -146,10 +158,54 @@ bool CHWJpegV4L2Compressor::SetQuality(const unsigned char qtable[]) return true; } -bool CHWJpegV4L2Compressor::SetImageFormat(unsigned int v4l2_fmt, - unsigned int width, unsigned int height, - unsigned int width2, unsigned int height2) -{ +bool CHWJpegV4L2Compressor::SetPadding(unsigned char padding[], unsigned int num_planes) { + if (num_planes > 3 || num_planes < 1) { + ALOGE("Attempting to set padding for incorrect number of buffers"); + return false; + } + + unsigned int padding_value = 0; + + for (int i = num_planes - 1; i >= 0; i--) { + padding_value <<= 8; + padding_value |= padding[i]; + } + + m_v4l2Controls[HWJPEG_CTRL_PADDING].id = V4L2_CID_JPEG_PADDING; + m_v4l2Controls[HWJPEG_CTRL_PADDING].value = static_cast<__s32>(padding_value); + m_uiControlsToSet |= 1 << HWJPEG_CTRL_PADDING; + + return true; +} + +bool CHWJpegV4L2Compressor::SetPadding2(unsigned char padding[], unsigned int num_planes) { + if (!IsDeviceCapability(V4L2_CAP_EXYNOS_JPEG_B2B_COMPRESSION)) { + ALOGE("Back-to-back compression is not suppored by H/W"); + return false; + } + + if (num_planes > 3 || num_planes < 1) { + ALOGE("Attempting to set padding for incorrect number of buffers"); + return false; + } + + unsigned int padding_value = 0; + + for (int i = num_planes - 1; i >= 0; i--) { + padding_value <<= 8; + padding_value |= padding[i]; + } + + m_v4l2Controls[HWJPEG_CTRL_PADDING2].id = V4L2_CID_JPEG_SEC_PADDING; + m_v4l2Controls[HWJPEG_CTRL_PADDING2].value = static_cast<__s32>(padding_value); + m_uiControlsToSet |= 1 << HWJPEG_CTRL_PADDING2; + + return true; +} + +bool CHWJpegV4L2Compressor::SetImageFormat(unsigned int v4l2_fmt, unsigned int width, + unsigned int height, unsigned int width2, + unsigned int height2) { if ((m_v4l2Format.fmt.pix_mp.pixelformat == v4l2_fmt) && (m_v4l2Format.fmt.pix_mp.width == TO_IMAGE_SIZE(width, width2)) && (m_v4l2Format.fmt.pix_mp.height == TO_IMAGE_SIZE(height, height2))) @@ -164,8 +220,7 @@ bool CHWJpegV4L2Compressor::SetImageFormat(unsigned int v4l2_fmt, return TryFormat(); } -bool CHWJpegV4L2Compressor::GetImageBufferSizes(size_t buf_sizes[], unsigned int *num_buffers) -{ +bool CHWJpegV4L2Compressor::GetImageBufferSizes(size_t buf_sizes[], unsigned int *num_buffers) { if (buf_sizes) { for (unsigned int i = 0; i < m_v4l2Format.fmt.pix_mp.num_planes; i++) buf_sizes[i] = m_v4l2Format.fmt.pix_mp.plane_fmt[i].sizeimage; @@ -174,7 +229,7 @@ bool CHWJpegV4L2Compressor::GetImageBufferSizes(size_t buf_sizes[], unsigned int if (num_buffers) { if (*num_buffers < m_v4l2Format.fmt.pix_mp.num_planes) { ALOGE("The size array length %u is smaller than the number of required buffers %u", - *num_buffers, m_v4l2Format.fmt.pix_mp.num_planes); + *num_buffers, m_v4l2Format.fmt.pix_mp.num_planes); return false; } @@ -185,19 +240,18 @@ bool CHWJpegV4L2Compressor::GetImageBufferSizes(size_t buf_sizes[], unsigned int } bool CHWJpegV4L2Compressor::SetImageBuffer(char *buffers[], size_t len_buffers[], - unsigned int num_buffers) -{ + unsigned int num_buffers) { if (num_buffers < m_v4l2Format.fmt.pix_mp.num_planes) { - ALOGE("The number of buffers %u is smaller than the required %u", - num_buffers,m_v4l2Format.fmt.pix_mp.num_planes); + ALOGE("The number of buffers %u is smaller than the required %u", num_buffers, + m_v4l2Format.fmt.pix_mp.num_planes); return false; } for (unsigned int i = 0; i < m_v4l2Format.fmt.pix_mp.num_planes; i++) { m_v4l2SrcPlanes[i].m.userptr = reinterpret_cast<unsigned long>(buffers[i]); if (len_buffers[i] < m_v4l2Format.fmt.pix_mp.plane_fmt[i].sizeimage) { - ALOGE("The size of the buffer[%u] %zu is smaller than required %u", - i, len_buffers[i], m_v4l2Format.fmt.pix_mp.plane_fmt[i].sizeimage); + ALOGE("The size of the buffer[%u] %zu is smaller than required %u", i, len_buffers[i], + m_v4l2Format.fmt.pix_mp.plane_fmt[i].sizeimage); return false; } m_v4l2SrcPlanes[i].bytesused = m_v4l2Format.fmt.pix_mp.plane_fmt[i].sizeimage; @@ -212,19 +266,18 @@ bool CHWJpegV4L2Compressor::SetImageBuffer(char *buffers[], size_t len_buffers[] } bool CHWJpegV4L2Compressor::SetImageBuffer(int buffers[], size_t len_buffers[], - unsigned int num_buffers) -{ + unsigned int num_buffers) { if (num_buffers < m_v4l2Format.fmt.pix_mp.num_planes) { - ALOGE("The number of buffers %u is smaller than the required %u", - num_buffers,m_v4l2Format.fmt.pix_mp.num_planes); + ALOGE("The number of buffers %u is smaller than the required %u", num_buffers, + m_v4l2Format.fmt.pix_mp.num_planes); return false; } for (unsigned int i = 0; i < m_v4l2Format.fmt.pix_mp.num_planes; i++) { m_v4l2SrcPlanes[i].m.fd = buffers[i]; if (len_buffers[i] < m_v4l2Format.fmt.pix_mp.plane_fmt[i].sizeimage) { - ALOGE("The size of the buffer[%u] %zu is smaller than required %u", - i, len_buffers[i], m_v4l2Format.fmt.pix_mp.plane_fmt[i].sizeimage); + ALOGE("The size of the buffer[%u] %zu is smaller than required %u", i, len_buffers[i], + m_v4l2Format.fmt.pix_mp.plane_fmt[i].sizeimage); return false; } m_v4l2SrcPlanes[i].bytesused = m_v4l2Format.fmt.pix_mp.plane_fmt[i].sizeimage; @@ -238,23 +291,22 @@ bool CHWJpegV4L2Compressor::SetImageBuffer(int buffers[], size_t len_buffers[], return true; } - bool CHWJpegV4L2Compressor::SetImageBuffer2(char *buffers[], size_t len_buffers[], - unsigned int num_buffers) -{ +bool CHWJpegV4L2Compressor::SetImageBuffer2(char *buffers[], size_t len_buffers[], + unsigned int num_buffers) { if (!IsDeviceCapability(V4L2_CAP_EXYNOS_JPEG_B2B_COMPRESSION)) { ALOGE("Back-to-back compression is not suppored by H/W"); return false; } if (num_buffers < m_v4l2Format.fmt.pix_mp.num_planes) { - ALOGE("The number of buffers %u is smaller than the required %u (secondary)", - num_buffers,m_v4l2Format.fmt.pix_mp.num_planes); + ALOGE("The number of buffers %u is smaller than the required %u (secondary)", num_buffers, + m_v4l2Format.fmt.pix_mp.num_planes); return false; } unsigned int ibuf = 0; for (unsigned int i = m_v4l2Format.fmt.pix_mp.num_planes; - i < (m_v4l2Format.fmt.pix_mp.num_planes * 2); i++, ibuf++) { + i < (m_v4l2Format.fmt.pix_mp.num_planes * 2); i++, ibuf++) { m_v4l2SrcPlanes[i].m.userptr = reinterpret_cast<unsigned long>(buffers[ibuf]); // size check is ignored for the secondary image buffers m_v4l2SrcPlanes[i].bytesused = len_buffers[ibuf]; @@ -267,23 +319,22 @@ bool CHWJpegV4L2Compressor::SetImageBuffer(int buffers[], size_t len_buffers[], return true; } - bool CHWJpegV4L2Compressor::SetImageBuffer2(int buffers[], size_t len_buffers[], - unsigned int num_buffers) -{ +bool CHWJpegV4L2Compressor::SetImageBuffer2(int buffers[], size_t len_buffers[], + unsigned int num_buffers) { if (!IsDeviceCapability(V4L2_CAP_EXYNOS_JPEG_B2B_COMPRESSION)) { ALOGE("Back-to-back compression is not suppored by H/W"); return false; } if (num_buffers < m_v4l2Format.fmt.pix_mp.num_planes) { - ALOGE("The number of buffers %u is smaller than the required %u (secondary)", - num_buffers,m_v4l2Format.fmt.pix_mp.num_planes); + ALOGE("The number of buffers %u is smaller than the required %u (secondary)", num_buffers, + m_v4l2Format.fmt.pix_mp.num_planes); return false; } unsigned int ibuf = 0; for (unsigned int i = m_v4l2Format.fmt.pix_mp.num_planes; - i < (m_v4l2Format.fmt.pix_mp.num_planes * 2); i++, ibuf++) { + i < (m_v4l2Format.fmt.pix_mp.num_planes * 2); i++, ibuf++) { m_v4l2SrcPlanes[i].m.fd = buffers[ibuf]; // size check is ignored for the secondary image buffers m_v4l2SrcPlanes[i].bytesused = len_buffers[ibuf]; @@ -297,8 +348,7 @@ bool CHWJpegV4L2Compressor::SetImageBuffer(int buffers[], size_t len_buffers[], return true; } -bool CHWJpegV4L2Compressor::SetJpegBuffer(char *buffer, size_t len_buffer) -{ +bool CHWJpegV4L2Compressor::SetJpegBuffer(char *buffer, size_t len_buffer) { m_v4l2DstPlanes[0].m.userptr = reinterpret_cast<unsigned long>(buffer); m_v4l2DstPlanes[0].length = len_buffer; m_v4l2DstBuffer.memory = V4L2_MEMORY_USERPTR; @@ -306,8 +356,7 @@ bool CHWJpegV4L2Compressor::SetJpegBuffer(char *buffer, size_t len_buffer) return true; } -bool CHWJpegV4L2Compressor::SetJpegBuffer(int buffer, size_t len_buffer, int offset) -{ +bool CHWJpegV4L2Compressor::SetJpegBuffer(int buffer, size_t len_buffer, int offset) { m_v4l2DstPlanes[0].m.fd = buffer; m_v4l2DstPlanes[0].length = len_buffer; m_v4l2DstPlanes[0].data_offset = offset; @@ -316,8 +365,7 @@ bool CHWJpegV4L2Compressor::SetJpegBuffer(int buffer, size_t len_buffer, int off return true; } -bool CHWJpegV4L2Compressor::SetJpegBuffer2(char *buffer, size_t len_buffer) -{ +bool CHWJpegV4L2Compressor::SetJpegBuffer2(char *buffer, size_t len_buffer) { if (!IsDeviceCapability(V4L2_CAP_EXYNOS_JPEG_B2B_COMPRESSION)) { ALOGE("Back-to-back compression is not suppored by H/W"); return false; @@ -329,8 +377,7 @@ bool CHWJpegV4L2Compressor::SetJpegBuffer2(char *buffer, size_t len_buffer) return true; } -bool CHWJpegV4L2Compressor::SetJpegBuffer2(int buffer, size_t len_buffer) -{ +bool CHWJpegV4L2Compressor::SetJpegBuffer2(int buffer, size_t len_buffer) { if (!IsDeviceCapability(V4L2_CAP_EXYNOS_JPEG_B2B_COMPRESSION)) { ALOGE("Back-to-back compression is not suppored by H/W"); return false; @@ -342,11 +389,9 @@ bool CHWJpegV4L2Compressor::SetJpegBuffer2(int buffer, size_t len_buffer) return true; } -bool CHWJpegV4L2Compressor::StopStreaming() -{ +bool CHWJpegV4L2Compressor::StopStreaming() { if (TestFlag(HWJPEG_FLAG_STREAMING)) { - if (!StreamOff()) - return false; + if (!StreamOff()) return false; ClearFlag(HWJPEG_FLAG_STREAMING); } @@ -355,19 +400,16 @@ bool CHWJpegV4L2Compressor::StopStreaming() // It is OK to skip DQBUF because STREAMOFF dequeues all queued buffers if (TestFlag(HWJPEG_FLAG_REQBUFS)) { - if (!ReqBufs(0)) - return false; + if (!ReqBufs(0)) return false; ClearFlag(HWJPEG_FLAG_REQBUFS); } return true; } -ssize_t CHWJpegV4L2Compressor::Compress(size_t *secondary_stream_size, bool block_mode) -{ +ssize_t CHWJpegV4L2Compressor::Compress(size_t *secondary_stream_size, bool block_mode) { if (TestFlag(HWJPEG_FLAG_PIX_FMT)) { - if (!StopStreaming() || !SetFormat()) - return -1; + if (!StopStreaming() || !SetFormat()) return -1; } if (!TestFlag(HWJPEG_FLAG_SRC_BUFFER)) { @@ -384,7 +426,8 @@ ssize_t CHWJpegV4L2Compressor::Compress(size_t *secondary_stream_size, bool bloc m_v4l2DstBuffer.length = 1; if (IsB2BCompression()) { if (!TestFlag(HWJPEG_FLAG_SRC_BUFFER2 | HWJPEG_FLAG_DST_BUFFER2)) { - ALOGE("Either of source or destination buffer of secondary image is not specified (%#x)", + ALOGE("Either of source or destination buffer of secondary image is not specified " + "(%#x)", GetFlags()); return -1; } @@ -399,14 +442,12 @@ ssize_t CHWJpegV4L2Compressor::Compress(size_t *secondary_stream_size, bool bloc if (!!(GetAuxFlags() & EXYNOS_HWJPEG_AUXOPT_DST_NOCACHECLEAN)) m_v4l2DstBuffer.flags |= V4L2_BUF_FLAG_NO_CACHE_CLEAN; - if (!ReqBufs() || !StreamOn() || !UpdateControls() || !QBuf()) - return -1; + if (!ReqBufs() || !StreamOn() || !UpdateControls() || !QBuf()) return -1; return block_mode ? DQBuf(secondary_stream_size) : 0; } -bool CHWJpegV4L2Compressor::TryFormat() -{ +bool CHWJpegV4L2Compressor::TryFormat() { if (ioctl(GetDeviceFD(), VIDIOC_TRY_FMT, &m_v4l2Format) < 0) { ALOGERR("Failed to TRY_FMT for compression"); return false; @@ -415,8 +456,7 @@ bool CHWJpegV4L2Compressor::TryFormat() return true; } -bool CHWJpegV4L2Compressor::SetFormat() -{ +bool CHWJpegV4L2Compressor::SetFormat() { if (ioctl(GetDeviceFD(), VIDIOC_S_FMT, &m_v4l2Format) < 0) { ALOGERR("Failed to S_FMT for image to compress"); return false; @@ -440,12 +480,10 @@ bool CHWJpegV4L2Compressor::SetFormat() return true; } -bool CHWJpegV4L2Compressor::UpdateControls() -{ +bool CHWJpegV4L2Compressor::UpdateControls() { bool enable_hwfc = !!(GetAuxFlags() & EXYNOS_HWJPEG_AUXOPT_ENABLE_HWFC); - if ((m_uiControlsToSet == 0) && (enable_hwfc == m_bEnableHWFC)) - return true; + if ((m_uiControlsToSet == 0) && (enable_hwfc == m_bEnableHWFC)) return true; v4l2_ext_controls ctrls; v4l2_ext_control ctrl[HWJPEG_CTRL_NUM]; @@ -481,14 +519,12 @@ bool CHWJpegV4L2Compressor::UpdateControls() return true; } -bool CHWJpegV4L2Compressor::ReqBufs(unsigned int count) -{ +bool CHWJpegV4L2Compressor::ReqBufs(unsigned int count) { // - count > 0 && REQBUFS is set: Just return true // - count > 0 && REQBUFS is unset: REQBUFS(count) is required // - count == 0 && REQBUFS is set: REQBUFS(0) is required // - count == 0 && REQBUFS is unset: Just return true; - if ((count > 0) == TestFlag(HWJPEG_FLAG_REQBUFS)) - return true; + if ((count > 0) == TestFlag(HWJPEG_FLAG_REQBUFS)) return true; v4l2_requestbuffers reqbufs; @@ -523,10 +559,8 @@ bool CHWJpegV4L2Compressor::ReqBufs(unsigned int count) return true; } -bool CHWJpegV4L2Compressor::StreamOn() -{ - if (TestFlag(HWJPEG_FLAG_STREAMING)) - return true; +bool CHWJpegV4L2Compressor::StreamOn() { + if (TestFlag(HWJPEG_FLAG_STREAMING)) return true; if (!TestFlag(HWJPEG_FLAG_REQBUFS)) { ALOGE("Trying to STREAMON before REQBUFS"); @@ -549,10 +583,8 @@ bool CHWJpegV4L2Compressor::StreamOn() return true; } -bool CHWJpegV4L2Compressor::StreamOff() -{ - if (!TestFlag(HWJPEG_FLAG_STREAMING)) - return true; +bool CHWJpegV4L2Compressor::StreamOff() { + if (!TestFlag(HWJPEG_FLAG_STREAMING)) return true; // error during stream off do not need further handling because of nothing to do if (ioctl(GetDeviceFD(), VIDIOC_STREAMOFF, &m_v4l2SrcBuffer.type) < 0) @@ -566,8 +598,7 @@ bool CHWJpegV4L2Compressor::StreamOff() return true; } -bool CHWJpegV4L2Compressor::QBuf() -{ +bool CHWJpegV4L2Compressor::QBuf() { if (!TestFlag(HWJPEG_FLAG_REQBUFS)) { ALOGE("QBuf is not permitted until REQBUFS is performed"); return false; @@ -592,8 +623,7 @@ bool CHWJpegV4L2Compressor::QBuf() return true; } -ssize_t CHWJpegV4L2Compressor::DQBuf(size_t *secondary_stream_size) -{ +ssize_t CHWJpegV4L2Compressor::DQBuf(size_t *secondary_stream_size) { bool failed = false; v4l2_buffer buffer_src, buffer_dst; v4l2_plane planes_src[6], planes_dst[2]; @@ -627,8 +657,7 @@ ssize_t CHWJpegV4L2Compressor::DQBuf(size_t *secondary_stream_size) ClearFlag(HWJPEG_FLAG_QBUF_OUT | HWJPEG_FLAG_QBUF_CAP); - if (failed) - return -1; + if (failed) return -1; if (!!((buffer_src.flags | buffer_dst.flags) & V4L2_BUF_FLAG_ERROR)) { ALOGE("Error occurred during compression"); @@ -646,14 +675,12 @@ ssize_t CHWJpegV4L2Compressor::DQBuf(size_t *secondary_stream_size) return GetStreamSize(secondary_stream_size); } -ssize_t CHWJpegV4L2Compressor::WaitForCompression(size_t *secondary_stream_size) -{ +ssize_t CHWJpegV4L2Compressor::WaitForCompression(size_t *secondary_stream_size) { return DQBuf(secondary_stream_size); } bool CHWJpegV4L2Compressor::GetImageBuffers(int buffers[], size_t len_buffers[], - unsigned int num_buffers) -{ + unsigned int num_buffers) { if (m_v4l2SrcBuffer.memory != V4L2_MEMORY_DMABUF) { ALOGE("Current image buffer type is not dma-buf but attempted to retrieve dma-buf buffers"); return false; @@ -661,7 +688,7 @@ bool CHWJpegV4L2Compressor::GetImageBuffers(int buffers[], size_t len_buffers[], if (num_buffers < m_v4l2Format.fmt.pix_mp.num_planes) { ALOGE("Number of planes are %u but attemts to retrieve %u buffers", - m_v4l2Format.fmt.pix_mp.num_planes, num_buffers); + m_v4l2Format.fmt.pix_mp.num_planes, num_buffers); return false; } @@ -674,8 +701,7 @@ bool CHWJpegV4L2Compressor::GetImageBuffers(int buffers[], size_t len_buffers[], } bool CHWJpegV4L2Compressor::GetImageBuffers(char *buffers[], size_t len_buffers[], - unsigned int num_buffers) -{ + unsigned int num_buffers) { if (m_v4l2SrcBuffer.memory != V4L2_MEMORY_USERPTR) { ALOGE("Current image buffer type is not userptr but attempted to retrieve userptr buffers"); return false; @@ -683,7 +709,7 @@ bool CHWJpegV4L2Compressor::GetImageBuffers(char *buffers[], size_t len_buffers[ if (num_buffers < m_v4l2Format.fmt.pix_mp.num_planes) { ALOGE("Number of planes are %u but attemts to retrieve %u buffers", - m_v4l2Format.fmt.pix_mp.num_planes, num_buffers); + m_v4l2Format.fmt.pix_mp.num_planes, num_buffers); return false; } @@ -695,8 +721,7 @@ bool CHWJpegV4L2Compressor::GetImageBuffers(char *buffers[], size_t len_buffers[ return true; } -bool CHWJpegV4L2Compressor::GetJpegBuffer(int *buffer, size_t *len_buffer) -{ +bool CHWJpegV4L2Compressor::GetJpegBuffer(int *buffer, size_t *len_buffer) { if (m_v4l2DstBuffer.memory != V4L2_MEMORY_DMABUF) { ALOGE("Current jpeg buffer type is not dma-buf but attempted to retrieve dma-buf buffer"); return false; @@ -708,8 +733,7 @@ bool CHWJpegV4L2Compressor::GetJpegBuffer(int *buffer, size_t *len_buffer) return true; } -bool CHWJpegV4L2Compressor::GetJpegBuffer(char **buffer, size_t *len_buffer) -{ +bool CHWJpegV4L2Compressor::GetJpegBuffer(char **buffer, size_t *len_buffer) { if (m_v4l2DstBuffer.memory != V4L2_MEMORY_USERPTR) { ALOGE("Current jpeg buffer type is not userptr but attempted to retrieve userptr buffer"); return false; @@ -721,8 +745,7 @@ bool CHWJpegV4L2Compressor::GetJpegBuffer(char **buffer, size_t *len_buffer) return true; } -void CHWJpegV4L2Compressor::Release() -{ +void CHWJpegV4L2Compressor::Release() { StopStreaming(); } @@ -730,8 +753,7 @@ void CHWJpegV4L2Compressor::Release() /********* D E C O M P R E S S I O N S U P P O R T **************************/ /******************************************************************************/ -CHWJpegV4L2Decompressor::CHWJpegV4L2Decompressor() : CHWJpegDecompressor("/dev/video12") -{ +CHWJpegV4L2Decompressor::CHWJpegV4L2Decompressor() : CHWJpegDecompressor("/dev/video12") { m_v4l2Format.type = 0; // inidication of uninitialized state memset(&m_v4l2DstBuffer, 0, sizeof(m_v4l2DstBuffer)); @@ -748,21 +770,18 @@ CHWJpegV4L2Decompressor::CHWJpegV4L2Decompressor() : CHWJpegDecompressor("/dev/v } } -CHWJpegV4L2Decompressor::~CHWJpegV4L2Decompressor() -{ +CHWJpegV4L2Decompressor::~CHWJpegV4L2Decompressor() { CancelCapture(); } -bool CHWJpegV4L2Decompressor::PrepareCapture() -{ +bool CHWJpegV4L2Decompressor::PrepareCapture() { if (m_v4l2DstBuffer.length < m_v4l2Format.fmt.pix.sizeimage) { - ALOGE("The size of the buffer %u is smaller than required %u", - m_v4l2DstBuffer.length, m_v4l2Format.fmt.pix.sizeimage); + ALOGE("The size of the buffer %u is smaller than required %u", m_v4l2DstBuffer.length, + m_v4l2Format.fmt.pix.sizeimage); return false; } - if (TestFlag(HWJPEG_FLAG_CAPTURE_READY)) - return true; + if (TestFlag(HWJPEG_FLAG_CAPTURE_READY)) return true; v4l2_requestbuffers reqbufs; @@ -788,10 +807,8 @@ bool CHWJpegV4L2Decompressor::PrepareCapture() return true; } -void CHWJpegV4L2Decompressor::CancelCapture() -{ - if (!TestFlag(HWJPEG_FLAG_CAPTURE_READY)) - return; +void CHWJpegV4L2Decompressor::CancelCapture() { + if (!TestFlag(HWJPEG_FLAG_CAPTURE_READY)) return; v4l2_requestbuffers reqbufs; @@ -805,14 +822,12 @@ void CHWJpegV4L2Decompressor::CancelCapture() ClearFlag(HWJPEG_FLAG_CAPTURE_READY); } -bool CHWJpegV4L2Decompressor::SetImageFormat(unsigned int v4l2_fmt, - unsigned int width, unsigned int height) -{ +bool CHWJpegV4L2Decompressor::SetImageFormat(unsigned int v4l2_fmt, unsigned int width, + unsigned int height) { // Test if new format is the same as the current configured format if (m_v4l2Format.type != 0) { v4l2_pix_format *p = &m_v4l2Format.fmt.pix; - if ((p->pixelformat == v4l2_fmt) && - (p->width == width) && (p->height == height)) + if ((p->pixelformat == v4l2_fmt) && (p->width == width) && (p->height == height)) return true; } @@ -826,16 +841,14 @@ bool CHWJpegV4L2Decompressor::SetImageFormat(unsigned int v4l2_fmt, m_v4l2Format.fmt.pix.height = height; if (ioctl(GetDeviceFD(), VIDIOC_S_FMT, &m_v4l2Format) < 0) { - ALOGERR("Failed to S_FMT for decompressed image (%08X,%ux%u)", - v4l2_fmt, width, height); + ALOGERR("Failed to S_FMT for decompressed image (%08X,%ux%u)", v4l2_fmt, width, height); return false; } return true; } -bool CHWJpegV4L2Decompressor::SetImageBuffer(char *buffer, size_t len_buffer) -{ +bool CHWJpegV4L2Decompressor::SetImageBuffer(char *buffer, size_t len_buffer) { m_v4l2DstBuffer.m.userptr = reinterpret_cast<unsigned long>(buffer); m_v4l2DstBuffer.bytesused = m_v4l2Format.fmt.pix.sizeimage; m_v4l2DstBuffer.length = len_buffer; @@ -844,8 +857,7 @@ bool CHWJpegV4L2Decompressor::SetImageBuffer(char *buffer, size_t len_buffer) return true; } -bool CHWJpegV4L2Decompressor::SetImageBuffer(int buffer, size_t len_buffer) -{ +bool CHWJpegV4L2Decompressor::SetImageBuffer(int buffer, size_t len_buffer) { m_v4l2DstBuffer.m.fd = buffer; m_v4l2DstBuffer.bytesused = m_v4l2Format.fmt.pix.sizeimage; m_v4l2DstBuffer.length = len_buffer; @@ -854,10 +866,8 @@ bool CHWJpegV4L2Decompressor::SetImageBuffer(int buffer, size_t len_buffer) return true; } -bool CHWJpegV4L2Decompressor::PrepareStream() -{ - if (TestFlag(HWJPEG_FLAG_OUTPUT_READY)) - return true; +bool CHWJpegV4L2Decompressor::PrepareStream() { + if (TestFlag(HWJPEG_FLAG_OUTPUT_READY)) return true; /* * S_FMT for output stream is unneccessary because the driver assumes that @@ -893,10 +903,8 @@ bool CHWJpegV4L2Decompressor::PrepareStream() return true; } -void CHWJpegV4L2Decompressor::CancelStream() -{ - if (!TestFlag(HWJPEG_FLAG_OUTPUT_READY)) - return; +void CHWJpegV4L2Decompressor::CancelStream() { + if (!TestFlag(HWJPEG_FLAG_OUTPUT_READY)) return; v4l2_requestbuffers rb; memset(&rb, 0, sizeof(rb)); @@ -911,8 +919,7 @@ void CHWJpegV4L2Decompressor::CancelStream() ClearFlag(HWJPEG_FLAG_OUTPUT_READY); } -bool CHWJpegV4L2Decompressor::QBufAndWait(const char *buffer, size_t len) -{ +bool CHWJpegV4L2Decompressor::QBufAndWait(const char *buffer, size_t len) { v4l2_buffer buf; memset(&buf, 0, sizeof(buf)); buf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT; @@ -952,8 +959,7 @@ bool CHWJpegV4L2Decompressor::QBufAndWait(const char *buffer, size_t len) return ret; } -bool CHWJpegV4L2Decompressor::Decompress(const char *buffer, size_t len) -{ +bool CHWJpegV4L2Decompressor::Decompress(const char *buffer, size_t len) { if (m_v4l2Format.type == 0) { ALOGE("Decompressed image format is not specified"); return false; @@ -966,11 +972,9 @@ bool CHWJpegV4L2Decompressor::Decompress(const char *buffer, size_t len) // Do not change the order of PrepareCapture() and PrepareStream(). // Otherwise, decompression will fail. - if (!PrepareCapture() || !PrepareStream()) - return false; + if (!PrepareCapture() || !PrepareStream()) return false; - if (!QBufAndWait(buffer, len)) - return false; + if (!QBufAndWait(buffer, len)) return false; return true; } diff --git a/libhwjpeg/include/ExynosJpegApi.h b/libhwjpeg/include/ExynosJpegApi.h index a82b65b..dcf06b3 100644 --- a/libhwjpeg/include/ExynosJpegApi.h +++ b/libhwjpeg/include/ExynosJpegApi.h @@ -33,7 +33,7 @@ #endif #define JPEG_BUF_TYPE_USER_PTR 1 -#define JPEG_BUF_TYPE_DMA_BUF 2 +#define JPEG_BUF_TYPE_DMA_BUF 2 // CUSTOM V4L2 4CC FORMATS FOR LEGACY JPEG LIBRARY AND DRIVERS #ifndef V4L2_PIX_FMT_JPEG_444 @@ -78,11 +78,12 @@ class ExynosJpegEncoder { int m_nStreamSize; bool __EnsureFormatIsApplied(); + protected: enum { - STATE_SIZE_CHANGED = 1 << 0, - STATE_PIXFMT_CHANGED = 1 << 1, - STATE_BASE_MAX = 1 << 16, + STATE_SIZE_CHANGED = 1 << 0, + STATE_PIXFMT_CHANGED = 1 << 1, + STATE_BASE_MAX = 1 << 16, }; unsigned int GetDeviceCapabilities() { return m_hwjpeg.GetDeviceCapabilities(); } @@ -95,16 +96,29 @@ protected: bool TestStateEither(unsigned int state) { return (m_uiState & state) != 0; } virtual bool EnsureFormatIsApplied() { return __EnsureFormatIsApplied(); } + public: - ExynosJpegEncoder(): m_hwjpeg(), - m_iInBufType(JPEG_BUF_TYPE_USER_PTR), m_iOutBufType(JPEG_BUF_TYPE_USER_PTR), m_uiState(0), - m_nQFactor(0), m_nWidth(0), m_nHeight(0), m_v4l2Format(0), m_jpegFormat(0), m_nStreamSize(0) - { + ExynosJpegEncoder() + : m_hwjpeg(), + m_iInBufType(JPEG_BUF_TYPE_USER_PTR), + m_iOutBufType(JPEG_BUF_TYPE_USER_PTR), + m_uiState(0), + m_nQFactor(0), + m_nWidth(0), + m_nHeight(0), + m_v4l2Format(0), + m_jpegFormat(0), + m_nStreamSize(0) { /* To detect setInBuf() call without format setting */ SetState(STATE_SIZE_CHANGED | STATE_PIXFMT_CHANGED); } virtual ~ExynosJpegEncoder() { destroy(); } + // Acquire exclusive lock to V4L2 device. This is a blocking call. + int lock(); + // Release exclusive lock to V4L2 device. + int unlock(); + // Return 0 on success, -1 on error int flagCreate() { return m_hwjpeg.Okay() ? 0 : -1; } virtual int create(void) { return flagCreate(); } @@ -113,7 +127,7 @@ public: int setCache(int __unused val) { return 0; } void *getJpegConfig() { return reinterpret_cast<void *>(this); } - int setJpegConfig(void* pConfig); + int setJpegConfig(void *pConfig); int checkInBufType(void) { return m_iInBufType; } int checkOutBufType(void) { return m_iOutBufType; } @@ -155,26 +169,24 @@ public: int setQuality(int iQuality) { if (m_nQFactor != iQuality) { - if (!m_hwjpeg.SetQuality(static_cast<unsigned int>(iQuality))) - return -1; + if (!m_hwjpeg.SetQuality(static_cast<unsigned int>(iQuality))) return -1; m_nQFactor = iQuality; } return 0; } int setQuality(const unsigned char q_table[]); + int setPadding(unsigned char *padding, unsigned int num_planes); int setColorBufSize(int *piBufSize, int iSize); int getJpegSize(void) { return m_nStreamSize; } int encode(void) { - if (!__EnsureFormatIsApplied()) - return false; + if (!__EnsureFormatIsApplied()) return false; m_nStreamSize = static_cast<int>(m_hwjpeg.Compress()); return (m_nStreamSize < 0) ? -1 : 0; } - }; #endif //__HARDWARE_EXYNOS_EXYNOS_JPEG_API_H__ diff --git a/libhwjpeg/include/ExynosJpegEncoderForCamera.h b/libhwjpeg/include/ExynosJpegEncoderForCamera.h index a50d884..e7a2eec 100644 --- a/libhwjpeg/include/ExynosJpegEncoderForCamera.h +++ b/libhwjpeg/include/ExynosJpegEncoderForCamera.h @@ -18,18 +18,18 @@ #ifndef __HARDWARE_EXYNOS_JPEG_ENCODER_FOR_CAMERA_H__ #define __HARDWARE_EXYNOS_JPEG_ENCODER_FOR_CAMERA_H__ -#include <memory> - +#include <ExynosExif.h> +#include <hardware/exynos/ExynosExif.h> #include <pthread.h> -#include <ExynosExif.h> +#include <memory> + #include "ExynosJpegApi.h" -#include <hardware/exynos/ExynosExif.h> class CAppMarkerWriter; // defined in libhwjpeg/AppMarkerWriter.h -class ThumbnailScaler; // defined in libhwjpeg/thumbnail_scaler.h +class ThumbnailScaler; // defined in libhwjpeg/thumbnail_scaler.h -class ExynosJpegEncoderForCamera: public ExynosJpegEncoder { +class ExynosJpegEncoderForCamera : public ExynosJpegEncoder { enum { STATE_THUMBSIZE_CHANGED = STATE_BASE_MAX << 0, STATE_HWFC_ENABLED = STATE_BASE_MAX << 1, @@ -64,7 +64,7 @@ class ExynosJpegEncoderForCamera: public ExynosJpegEncoder { union { char *m_pThumbnailImageBuffer[3]; // checkInBufType() == JPEG_BUF_TYPE_USER_PTR - int m_fdThumbnailImageBuffer[3]; // checkInBufType() == JPEG_BUF_TYPE_DMA_BUF + int m_fdThumbnailImageBuffer[3]; // checkInBufType() == JPEG_BUF_TYPE_DMA_BUF }; size_t m_szThumbnailImageLen[3]; @@ -76,10 +76,11 @@ class ExynosJpegEncoderForCamera: public ExynosJpegEncoder { app_info_t m_appInfo[15]; bool AllocThumbBuffer(int v4l2Format); /* For single compression */ - bool AllocThumbJpegBuffer(); /* For BTB compression */ + bool AllocThumbJpegBuffer(); /* For BTB compression */ bool GenerateThumbnailImage(); size_t CompressThumbnail(); - size_t CompressThumbnailOnly(size_t limit, int quality, unsigned int v4l2Format, int src_buftype); + size_t CompressThumbnailOnly(size_t limit, int quality, unsigned int v4l2Format, + int src_buftype); size_t RemoveTrailingDummies(char *base, size_t len); ssize_t FinishCompression(size_t mainlen, size_t thumblen); bool ProcessExif(char *base, size_t limit, exif_attribute_t *exifInfo, extra_appinfo_t *extra); @@ -87,28 +88,35 @@ class ExynosJpegEncoderForCamera: public ExynosJpegEncoder { bool PrepareCompression(bool thumbnail); // IsThumbGenerationNeeded - true if thumbnail image needed to be generated from the main image - // It also implies that a worker thread is generated to generate thumbnail concurrently. + // It also implies that a worker thread is generated to generate + // thumbnail concurrently. inline bool IsThumbGenerationNeeded() { return !TestState(STATE_NO_CREATE_THUMBIMAGE); } inline void NoThumbGenerationNeeded() { SetState(STATE_NO_CREATE_THUMBIMAGE); } inline void ThumbGenerationNeeded() { ClearState(STATE_NO_CREATE_THUMBIMAGE); } inline bool IsBTBCompressionSupported() { return !!(GetDeviceCapabilities() & V4L2_CAP_EXYNOS_JPEG_B2B_COMPRESSION) && - !TestState(STATE_NO_BTBCOMP); + !TestState(STATE_NO_BTBCOMP); } + protected: virtual bool EnsureFormatIsApplied(); + public: ExynosJpegEncoderForCamera(bool bBTBComp = true); virtual ~ExynosJpegEncoderForCamera(); - int encode(int *size, exif_attribute_t *exifInfo, char** pcJpegBuffer, debug_attribute_t *debugInfo = 0); - int encode(int *size, exif_attribute_t *exifInfo, int fdJpegBuffer, char** pcJpegBuffer, debug_attribute_t *debugInfo = 0); - int encode(int *size, exif_attribute_t *exifInfo, int fdJpegBuffer, char** pcJpegBuffer, extra_appinfo_t *appInfo = 0); + int encode(int *size, exif_attribute_t *exifInfo, char **pcJpegBuffer, + debug_attribute_t *debugInfo = 0); + int encode(int *size, exif_attribute_t *exifInfo, int fdJpegBuffer, char **pcJpegBuffer, + debug_attribute_t *debugInfo = 0); + int encode(int *size, exif_attribute_t *exifInfo, int fdJpegBuffer, char **pcJpegBuffer, + extra_appinfo_t *appInfo = 0); int setInBuf2(int *piBuf, int *iSize); int setInBuf2(char **pcBuf, int *iSize); int setThumbnailSize(int w, int h); int setThumbnailQuality(int quality); + int setThumbnailPadding(unsigned char *padding, unsigned int num_planes); void setExtScalerNum(int csc_hwscaler_id) { m_iHWScalerID = csc_hwscaler_id; } diff --git a/libhwjpeg/include/FileLock.h b/libhwjpeg/include/FileLock.h new file mode 100644 index 0000000..b308aa7 --- /dev/null +++ b/libhwjpeg/include/FileLock.h @@ -0,0 +1,16 @@ +#include "android-base/thread_annotations.h" + +// Encapsulates advisory file lock for a given field descriptor +class CAPABILITY("mutex") FileLock { +public: + FileLock(int fd); + ~FileLock() = default; + + // Acquires advisory file lock. This will block. + int lock() ACQUIRE(); + // Releases advisory file lock. + int unlock() RELEASE(); + +private: + int fd_; +};
\ No newline at end of file diff --git a/libhwjpeg/include/exynos-hwjpeg.h b/libhwjpeg/include/exynos-hwjpeg.h index 04ffed4..45114b5 100644 --- a/libhwjpeg/include/exynos-hwjpeg.h +++ b/libhwjpeg/include/exynos-hwjpeg.h @@ -18,46 +18,38 @@ #ifndef __EXYNOS_HWJPEG_H__ #define __EXYNOS_HWJPEG_H__ +#include <linux/videodev2.h> + #include <cstddef> // size_t -/* - * exynos-hwjpeg.h does not include videodev2.h because Exynos HAL code may - * define its version of videodev2.h that may differ from <linux/videodev2.h> - * of the current Linux version. - * To prevent conflict different versions of videodev2.h, this header file does - * not include videodev2.h even though it depends on the data types defined in - * videodev2.h. - * Therefore, the source files that include this header file, they should - * include their proper version of videodev2.h. - */ -#ifndef VIDEO_MAX_PLANES -#error 'linux/videodev2.h' should be included before 'exynos-hwjpeg.h' -#endif #if VIDEO_MAX_PLANES < 6 #error VIDEO_MAX_PLANES should not be smaller than 6 #endif +#include "FileLock.h" +#include "android-base/thread_annotations.h" + // Exynos JPEG specific device capabilities // Defined in the driver. Not in videodev2.h -#define V4L2_CAP_EXYNOS_JPEG_DECOMPRESSION 0x0100 -#define V4L2_CAP_EXYNOS_JPEG_B2B_COMPRESSION 0x0200 -#define V4L2_CAP_EXYNOS_JPEG_HWFC 0x0400 -#define V4L2_CAP_EXYNOS_JPEG_HWFC_EMBEDDED 0x0800 -#define V4L2_CAP_EXYNOS_JPEG_MAX_STREAMSIZE 0x1000 +#define V4L2_CAP_EXYNOS_JPEG_DECOMPRESSION 0x0100 +#define V4L2_CAP_EXYNOS_JPEG_B2B_COMPRESSION 0x0200 +#define V4L2_CAP_EXYNOS_JPEG_HWFC 0x0400 +#define V4L2_CAP_EXYNOS_JPEG_HWFC_EMBEDDED 0x0800 +#define V4L2_CAP_EXYNOS_JPEG_MAX_STREAMSIZE 0x1000 #define V4L2_CAP_EXYNOS_JPEG_NO_STREAMBASE_ALIGN 0x2000 -#define V4L2_CAP_EXYNOS_JPEG_NO_IMAGEBASE_ALIGN 0x4000 -#define V4L2_CAP_EXYNOS_JPEG_NO_BUFFER_OVERRUN 0x8000 +#define V4L2_CAP_EXYNOS_JPEG_NO_IMAGEBASE_ALIGN 0x4000 +#define V4L2_CAP_EXYNOS_JPEG_NO_BUFFER_OVERRUN 0x8000 #define V4L2_CAP_EXYNOS_JPEG_DECOMPRESSION_FROM_SOS 0x10000 -#define V4L2_CAP_EXYNOS_JPEG_DECOMPRESSION_CROP 0x20000 -#define V4L2_CAP_EXYNOS_JPEG_DOWNSCALING 0x40000 -#define V4L2_CAP_EXYNOS_JPEG_DMABUF_OFFSET 0x80000 +#define V4L2_CAP_EXYNOS_JPEG_DECOMPRESSION_CROP 0x20000 +#define V4L2_CAP_EXYNOS_JPEG_DOWNSCALING 0x40000 +#define V4L2_CAP_EXYNOS_JPEG_DMABUF_OFFSET 0x80000 // EXYNOS HWJPEG specific auxiliary option flags // The flags are common to all derived classes of CHWJpegCompressor // but if a derived class does not support for a specified flag, // it is discarded and ignored silently. -#define EXYNOS_HWJPEG_AUXOPT_ENABLE_HWFC (1 << 4) -#define EXYNOS_HWJPEG_AUXOPT_SRC_NOCACHECLEAN (1 << 8) -#define EXYNOS_HWJPEG_AUXOPT_DST_NOCACHECLEAN (1 << 9) +#define EXYNOS_HWJPEG_AUXOPT_ENABLE_HWFC (1 << 4) +#define EXYNOS_HWJPEG_AUXOPT_SRC_NOCACHECLEAN (1 << 8) +#define EXYNOS_HWJPEG_AUXOPT_DST_NOCACHECLEAN (1 << 9) /* * CHWJpegBase - The base class of JPEG compression and decompression @@ -81,15 +73,19 @@ class CHWJpegBase { * */ unsigned int m_uiAuxFlags; + protected: CHWJpegBase(const char *path); virtual ~CHWJpegBase(); int GetDeviceFD() { return m_iFD; } void SetDeviceCapabilities(unsigned int cap) { m_uiDeviceCaps = cap; } unsigned int GetAuxFlags() { return m_uiAuxFlags; } + public: unsigned int GetDeviceCapabilities() { return m_uiDeviceCaps; } - bool IsDeviceCapability(unsigned int cap_flags) { return (m_uiDeviceCaps & cap_flags) == cap_flags; } + bool IsDeviceCapability(unsigned int cap_flags) { + return (m_uiDeviceCaps & cap_flags) == cap_flags; + } /* * Okay - Test if the object is correctly initialized @@ -144,6 +140,7 @@ public: class CHWJpegCompressor : public CHWJpegBase { size_t m_nLastStreamSize; size_t m_nLastThumbStreamSize; + protected: void SetStreamSize(size_t main_size, size_t secondary_size = 0) { m_nLastStreamSize = main_size; @@ -151,20 +148,23 @@ protected: } ssize_t GetStreamSize(size_t *secondary_size) { - if (secondary_size) - *secondary_size = m_nLastThumbStreamSize; + if (secondary_size) *secondary_size = m_nLastThumbStreamSize; return static_cast<ssize_t>(m_nLastStreamSize); } + public: - CHWJpegCompressor(const char *path): CHWJpegBase(path), m_nLastStreamSize(0), m_nLastThumbStreamSize(0) { } + CHWJpegCompressor(const char *path) + : CHWJpegBase(path), m_nLastStreamSize(0), m_nLastThumbStreamSize(0) {} /* * SetImageFormat - Configure uncompressed image format, width and height * @v4l2_fmt[in] : Image pixel format defined in <linux/videodev2.h> * @width[in] : Width of the primary uncompressed image in the number of pixels * @height[in] : Height of the primary uncompressed image in the number of pixels - * @sec_width[in] : Width of the secondary uncompressed image in the number of pixels (optional) - * @sec_height[in] : Height of the secondary uncompressed image in the number of pixels (optional) + * @sec_width[in] : Width of the secondary uncompressed image in the number of pixels + * (optional) + * @sec_height[in] : Height of the secondary uncompressed image in the number of pixels + * (optional) * @return : true if configuration of image pixel format and size is successful. * false, otherwise. * @@ -172,7 +172,7 @@ public: * to configure different image formats for them. */ virtual bool SetImageFormat(unsigned int v4l2_fmt, unsigned int width, unsigned int height, - unsigned int sec_width = 0, unsigned int sec_height = 0) = 0; + unsigned int sec_width = 0, unsigned int sec_height = 0) = 0; /* * GetImageBufferSizes - Ask the required buffer sizes for the given image format @@ -196,7 +196,8 @@ public: virtual bool SetChromaSampFactor(unsigned int horizontal, unsigned int vertical) = 0; /* * SetQuality - Configure quality factor for JPEG compression - * @quality_factor[in] : JPEG compression quality factor between 1 and 100 for the primary image + * @quality_factor[in] : JPEG compression quality factor between 1 and 100 for the primary + * image * @quality_factor2[in] : JPEG compression quality factor for the secondary image (optional) * @return: true if quality factors are configured successfully. * false, otherwise. @@ -214,6 +215,24 @@ public: */ virtual bool SetQuality(const unsigned char __unused qtable[]) { return false; }; /* + * SetPadding - Configures padding per plane for primary image + * @padding[in] : Padding per plane + * @num_planes[in] : Number of planes. This should match the number of elements in @padding + * @return : true if padding is congured successfully. + * false, otherwise. + */ + virtual bool SetPadding(unsigned char padding[], unsigned int num_planes) = 0; + /* + * SetPadding2 - Configures padding per plane for thumbnail image + * @padding[in] : padding per plane + * @num_planes[in] : Number of planes. This should match the number of elements in @padding + * @return : true if padding is congured successfully. + * false, otherwise. + */ + virtual bool SetPadding2(unsigned char __unused padding[], unsigned int __unused num_planes) { + return false; + } + /* * SetImageBuffer - Configure the uncompressed primary image buffers (userptr) * @buffers[in] : addresses of the buffers * @len_buffers[in] : sizes of the buffers @@ -221,7 +240,8 @@ public: * @return : true if buffer configuration is successful. * false, otherwise. */ - virtual bool SetImageBuffer(char *buffers[], size_t len_buffers[], unsigned int num_buffers) = 0; + virtual bool SetImageBuffer(char *buffers[], size_t len_buffers[], + unsigned int num_buffers) = 0; /* * SetImageBuffer - Configure the uncompressed primary image buffers (dmabuf) * @buffers[in] : file descriptors of the buffers exported by dma-buf @@ -239,7 +259,10 @@ public: * @return : true if buffer configuration is successful. * false, otherwise. */ - virtual bool SetImageBuffer2(char __unused *buffers[], size_t __unused len_buffers[], unsigned int __unused num_buffers) { return false; } + virtual bool SetImageBuffer2(char __unused *buffers[], size_t __unused len_buffers[], + unsigned int __unused num_buffers) { + return false; + } /* * SetImageBuffer2 - Configure the uncompressed secondary image buffers (dmabuf) * @buffers[in] : file descriptors of the buffers exported by dma-buf @@ -248,7 +271,10 @@ public: * @return : true if buffer configuration is successful. * false, otherwise. */ - virtual bool SetImageBuffer2(int __unused buffers[], size_t __unused len_buffers[], unsigned int __unused num_buffers) { return false; } + virtual bool SetImageBuffer2(int __unused buffers[], size_t __unused len_buffers[], + unsigned int __unused num_buffers) { + return false; + } /* * SetJpegBuffer - Configure the buffer of JPEG stream of the primary image (userptr) * @buffer [in] : The address of the buffer @@ -311,7 +337,9 @@ public: * returns and the returned size will be the stream sizes obtained by the last call to * Compress(). */ - virtual ssize_t WaitForCompression(size_t __unused *secondary_stream_size = NULL) { return GetStreamSize(secondary_stream_size); } + virtual ssize_t WaitForCompression(size_t __unused *secondary_stream_size = NULL) { + return GetStreamSize(secondary_stream_size); + } /* * GetImageBuffers - Retrieve the configured uncompressed image buffer information (dmabuf) * @buffers[out]: The file descriptors of the buffers exported by dma-buf @@ -322,7 +350,10 @@ public: * DEPREDCATED. DO NOT USE THIS FUNCTION. * This function is just provided to support the legacy ExynosJpegEncoder API. */ - virtual bool GetImageBuffers(int __unused buffers[], size_t __unused len_buffers[], unsigned int __unused num_buffers) { return false; } + virtual bool GetImageBuffers(int __unused buffers[], size_t __unused len_buffers[], + unsigned int __unused num_buffers) { + return false; + } /* * GetImageBuffers - Retrieve the configured uncompressed image buffer information (userptr) * @buffers[out]: The addresses of the buffers @@ -333,7 +364,10 @@ public: * DEPREDCATED. DO NOT USE THIS FUNCTION. * This function is just provided to support the legacy ExynosJpegEncoder API. */ - virtual bool GetImageBuffers(char __unused *buffers[], size_t __unused len_buffers[], unsigned int __unused num_buffers) { return false; } + virtual bool GetImageBuffers(char __unused *buffers[], size_t __unused len_buffers[], + unsigned int __unused num_buffers) { + return false; + } /* * GetJpegBuffers - Retrieve the configured JPEG stream image buffer information (dmabuf) * @buffers[out]: The file descriptor of the buffer exported by dma-buf @@ -353,11 +387,13 @@ public: * DEPREDCATED. DO NOT USE THIS FUNCTION. * This function is just provided to support the legacy ExynosJpegEncoder API. */ - virtual bool GetJpegBuffer(char __unused **buffers, size_t __unused *len_buffer) { return false; } + virtual bool GetJpegBuffer(char __unused **buffers, size_t __unused *len_buffer) { + return false; + } /* * Release - release the buffers acquired by CHWJpegCompressor */ - virtual void Release() { } + virtual void Release() {} }; /* @@ -381,8 +417,8 @@ public: */ class CHWJpegDecompressor : public CHWJpegBase { public: - CHWJpegDecompressor(const char *path) : CHWJpegBase(path) { } - virtual ~CHWJpegDecompressor() { } + CHWJpegDecompressor(const char *path) : CHWJpegBase(path) {} + virtual ~CHWJpegDecompressor() {} /* * SetImageFormat - Configure decompressed image pixel format * @v4l2_fmt[in] : Image pixel format defined in <linux/videodev2.h> @@ -424,7 +460,9 @@ public: * @width[in] : The number of horizontal pixels of the compressed image * @height[in] : The number of vertical pixels of the compressed image */ - virtual bool SetStreamPixelSize(unsigned int __unused width, unsigned int __unused height) { return true; } + virtual bool SetStreamPixelSize(unsigned int __unused width, unsigned int __unused height) { + return true; + } /* * SetChromaSampFactor - Configure the chroma subsampling factor for JPEG stream @@ -441,7 +479,10 @@ public: * If it is required to specify chroma subsampling factors separately, you should * override SetChromaSampFactor(). */ - virtual bool SetChromaSampFactor(unsigned int __unused horizontal, unsigned int __unused vertical) { return true; } + virtual bool SetChromaSampFactor(unsigned int __unused horizontal, + unsigned int __unused vertical) { + return true; + } /* * SetDQT - Configure the address of DQT @@ -484,8 +525,9 @@ public: class CHWJpegFlagManager { unsigned int m_uiHWConfigFlags; + public: - CHWJpegFlagManager() : m_uiHWConfigFlags(0) { } + CHWJpegFlagManager() : m_uiHWConfigFlags(0) {} void SetFlag(unsigned int flag) { m_uiHWConfigFlags |= flag; } void ClearFlag(unsigned int flag) { m_uiHWConfigFlags &= ~flag; } bool TestFlag(unsigned int flag) { return (m_uiHWConfigFlags & flag) == flag; } @@ -497,7 +539,7 @@ class CHWJpegM2M1SHOTCompressor: public CHWJpegCompressor { }; */ -#define TO_SEC_IMG_SIZE(val) (((val) >> 16) & 0xFFFF) +#define TO_SEC_IMG_SIZE(val) (((val) >> 16) & 0xFFFF) class CHWJpegV4L2Compressor : public CHWJpegCompressor, private CHWJpegFlagManager { enum { @@ -505,20 +547,22 @@ class CHWJpegV4L2Compressor : public CHWJpegCompressor, private CHWJpegFlagManag HWJPEG_CTRL_QFACTOR, HWJPEG_CTRL_QFACTOR2, HWJPEG_CTRL_HWFC, + HWJPEG_CTRL_PADDING, + HWJPEG_CTRL_PADDING2, HWJPEG_CTRL_NUM, }; - enum { - HWJPEG_FLAG_PIX_FMT = 0x1, // Set if unapplied image format exists + enum { + HWJPEG_FLAG_PIX_FMT = 0x1, // Set if unapplied image format exists - HWJPEG_FLAG_QBUF_OUT = 0x100, // Set if the image buffer is queued - HWJPEG_FLAG_QBUF_CAP = 0x200, // Set if the JPEG stream buffer is queued - HWJPEG_FLAG_REQBUFS = 0x400, - HWJPEG_FLAG_STREAMING = 0x800, + HWJPEG_FLAG_QBUF_OUT = 0x100, // Set if the image buffer is queued + HWJPEG_FLAG_QBUF_CAP = 0x200, // Set if the JPEG stream buffer is queued + HWJPEG_FLAG_REQBUFS = 0x400, + HWJPEG_FLAG_STREAMING = 0x800, - HWJPEG_FLAG_SRC_BUFFER = 0x10000, // Set if SetImageBuffer() is invoked successfully + HWJPEG_FLAG_SRC_BUFFER = 0x10000, // Set if SetImageBuffer() is invoked successfully HWJPEG_FLAG_SRC_BUFFER2 = 0x20000, // Set if SetImageBuffer2() is invoked successfully - HWJPEG_FLAG_DST_BUFFER = 0x40000, // Set if SetJpegBuffer() is invoked successfully + HWJPEG_FLAG_DST_BUFFER = 0x40000, // Set if SetJpegBuffer() is invoked successfully HWJPEG_FLAG_DST_BUFFER2 = 0x80000, // Set if SetJpegBuffer2() is invoked successfully }; @@ -532,7 +576,7 @@ class CHWJpegV4L2Compressor : public CHWJpegCompressor, private CHWJpegFlagManag // Only valid after Compression() successes. unsigned int m_uiHWDelay; - v4l2_format m_v4l2Format; // v4l2 format for the source image + v4l2_format m_v4l2Format; // v4l2 format for the source image v4l2_buffer m_v4l2SrcBuffer; // v4l2 source buffer v4l2_plane m_v4l2SrcPlanes[6]; v4l2_buffer m_v4l2DstBuffer; @@ -540,9 +584,11 @@ class CHWJpegV4L2Compressor : public CHWJpegCompressor, private CHWJpegFlagManag bool m_bEnableHWFC; + FileLock file_lock_; + bool IsB2BCompression() { return (TO_SEC_IMG_SIZE(m_v4l2Format.fmt.pix_mp.width) + - TO_SEC_IMG_SIZE(m_v4l2Format.fmt.pix_mp.height)) != 0; + TO_SEC_IMG_SIZE(m_v4l2Format.fmt.pix_mp.height)) != 0; } // V4L2 Helpers @@ -555,21 +601,28 @@ class CHWJpegV4L2Compressor : public CHWJpegCompressor, private CHWJpegFlagManag bool QBuf(); ssize_t DQBuf(size_t *secondary_stream_size); bool StopStreaming(); + public: CHWJpegV4L2Compressor(); virtual ~CHWJpegV4L2Compressor(); + // Acquires exclusive lock to V4L2 device. This must be called before starting image + // configuration. This is a blocking call. + int lock(); + // Releases exclusive lock to V4L2 device. This should be called after encoding is complete. + int unlock(); + unsigned int GetHWDelay() { return m_uiHWDelay; } // SetChromaSampFactor can be called during streaming - virtual bool SetChromaSampFactor(unsigned int horizontal, - unsigned int vertical); - virtual bool SetQuality(unsigned int quality_factor, - unsigned int quality_factor2 = 0); + virtual bool SetChromaSampFactor(unsigned int horizontal, unsigned int vertical); + virtual bool SetQuality(unsigned int quality_factor, unsigned int quality_factor2 = 0); virtual bool SetQuality(const unsigned char qtable[]); + virtual bool SetPadding(unsigned char padding[], unsigned int num_planes); + virtual bool SetPadding2(unsigned char padding[], unsigned int num_planes); virtual bool SetImageFormat(unsigned int v4l2_fmt, unsigned int width, unsigned int height, - unsigned int sec_width = 0, unsigned sec_height = 0); + unsigned int sec_width = 0, unsigned sec_height = 0); virtual bool GetImageBufferSizes(size_t buf_sizes[], unsigned int *num_bufffers); virtual bool SetImageBuffer(char *buffers[], size_t len_buffers[], unsigned int num_buffers); virtual bool SetImageBuffer(int buffers[], size_t len_buffers[], unsigned int num_buffers); @@ -589,8 +642,8 @@ public: }; class CHWJpegV4L2Decompressor : public CHWJpegDecompressor, private CHWJpegFlagManager { - enum { - HWJPEG_FLAG_OUTPUT_READY = 0x10, /* the output stream is ready */ + enum { + HWJPEG_FLAG_OUTPUT_READY = 0x10, /* the output stream is ready */ HWJPEG_FLAG_CAPTURE_READY = 0x20, /* the capture stream is ready */ }; @@ -605,6 +658,7 @@ class CHWJpegV4L2Decompressor : public CHWJpegDecompressor, private CHWJpegFlagM bool PrepareStream(); void CancelStream(); bool QBufAndWait(const char *buffer, size_t len); + public: CHWJpegV4L2Decompressor(); virtual ~CHWJpegV4L2Decompressor(); diff --git a/libhwjpeg/include/hwjpeglib-exynos.h b/libhwjpeg/include/hwjpeglib-exynos.h index ba95320..5d23630 100644 --- a/libhwjpeg/include/hwjpeglib-exynos.h +++ b/libhwjpeg/include/hwjpeglib-exynos.h @@ -25,16 +25,19 @@ extern "C" { * hwjpeg_decompress_ptr - handle of decompressor instance */ typedef struct hwjpeg_decompressor_struct { - unsigned int image_width; /* width of the compressed image */ - unsigned int image_height; /* height of the compressed image */ - unsigned char num_components; /* number of components of the compressed image */ - unsigned char chroma_h_samp_factor; /* horizontal chroma sampling factor of the compressed image */ - unsigned char chroma_v_samp_factor; /* vertical chroma sampling factor of the compressed image */ - unsigned char scale_factor; /* down-scaling factor during decompression: one of 1, 2, 4 and 8 */ - - unsigned int output_width; /* width of the output image (image_width/scale_factor) */ - unsigned int output_height; /* height of the output image (image_height/scale_factor) */ - __u32 output_format; /* 4CC style format identifier of the output image defined in videodev2.h */ + unsigned int image_width; /* width of the compressed image */ + unsigned int image_height; /* height of the compressed image */ + unsigned char num_components; /* number of components of the compressed image */ + unsigned char + chroma_h_samp_factor; /* horizontal chroma sampling factor of the compressed image */ + unsigned char + chroma_v_samp_factor; /* vertical chroma sampling factor of the compressed image */ + unsigned char scale_factor; /* down-scaling factor during decompression: one of 1, 2, 4 and 8 */ + + unsigned int output_width; /* width of the output image (image_width/scale_factor) */ + unsigned int output_height; /* height of the output image (image_height/scale_factor) */ + __u32 output_format; /* 4CC style format identifier of the output image defined in videodev2.h + */ } *hwjpeg_decompress_ptr; /* @@ -79,7 +82,8 @@ bool hwjpeg_dmabuf_src(hwjpeg_decompress_ptr cinfo, int infd, size_t insize, siz * @dummybytes: The available dummy bytes after @insize. * @return: false on failure */ -bool hwjpeg_mem_src(hwjpeg_decompress_ptr cinfo, unsigned char *inbuffer, size_t insize, size_t dummybytes); +bool hwjpeg_mem_src(hwjpeg_decompress_ptr cinfo, unsigned char *inbuffer, size_t insize, + size_t dummybytes); /* * hwjpeg_config_image_format - configure output image format @@ -100,7 +104,8 @@ void hwjpeg_config_image_format(hwjpeg_decompress_ptr cinfo, __u32 v4l2_pix_fmt) * @num_buffers: The number of elements in @outsizes and @outbuffer * @return: false on failure. */ -bool hwjpeg_mem_dst(hwjpeg_decompress_ptr cinfo, unsigned char *outbuffer[], size_t outsize[], unsigned int num_buffers); +bool hwjpeg_mem_dst(hwjpeg_decompress_ptr cinfo, unsigned char *outbuffer[], size_t outsize[], + unsigned int num_buffers); /* * hwjpeg_dmabuf_dst - configure the buffer to store decompressed image @@ -113,7 +118,8 @@ bool hwjpeg_mem_dst(hwjpeg_decompress_ptr cinfo, unsigned char *outbuffer[], siz * @num_buffers: The number of elements in @outsizes and @outfd * @return: false on failure. */ -bool hwjpeg_dmabuf_dst(hwjpeg_decompress_ptr cinfo, int outfd[], size_t outsize[], unsigned int num_buffers); +bool hwjpeg_dmabuf_dst(hwjpeg_decompress_ptr cinfo, int outfd[], size_t outsize[], + unsigned int num_buffers); /* * hwjpeg_set_downscale_factor - configure the downscaling factor during decompression @@ -171,7 +177,7 @@ bool hwjpeg_start_decompress(hwjpeg_decompress_ptr cinfo); */ void hwjpeg_destroy_decompress(hwjpeg_decompress_ptr cinfo); -}; /* extern "C" */ +}; /* extern "C" */ #endif /* __cplusplus */ #endif /*__HARDWARE_SAMSUNG_EXYNOS7420_HWJPEGDECOMPRESSOR_H__*/ diff --git a/libhwjpeg/libhwjpeg-exynos.cpp b/libhwjpeg/libhwjpeg-exynos.cpp index 1bfa55a..5f6dd6e 100644 --- a/libhwjpeg/libhwjpeg-exynos.cpp +++ b/libhwjpeg/libhwjpeg-exynos.cpp @@ -15,28 +15,26 @@ * limitations under the License. */ -#include <cstdio> - -#include <cstring> -#include <unistd.h> -#include <sys/ioctl.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <sys/mman.h> +#include <exynos-hwjpeg.h> #include <fcntl.h> - +#include <hwjpeglib-exynos.h> #include <linux/videodev2.h> +#include <sys/ioctl.h> +#include <sys/mman.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <unistd.h> -#include <exynos-hwjpeg.h> -#include <hwjpeglib-exynos.h> +#include <cstdio> +#include <cstring> #include "hwjpeg-internal.h" #define ALOGERR(fmt, args...) ((void)ALOG(LOG_ERROR, LOG_TAG, fmt " [%s]", ##args, strerror(errno))) -#define ROUND_DOWN(val, denom) ((val) & ~((denom) - 1)) -#define ROUND_UP(val, denom) ROUND_DOWN((val) + (denom) - 1, denom) -#define TO_MASK(val) ((val) - 1) +#define ROUND_DOWN(val, denom) ((val) & ~((denom)-1)) +#define ROUND_UP(val, denom) ROUND_DOWN((val) + (denom)-1, denom) +#define TO_MASK(val) ((val)-1) class CJpegStreamParser { private: @@ -51,18 +49,18 @@ private: size_t GetLength(unsigned char *addr); bool ParseFrame(unsigned char *addr); - off_t GetOffset(unsigned char *addr) { + ptrdiff_t GetOffset(unsigned char *addr) { unsigned long beg = reinterpret_cast<unsigned long>(m_pStreamBase); unsigned long cur = reinterpret_cast<unsigned long>(addr); - return static_cast<off_t>(cur - beg); + return static_cast<ptrdiff_t>(cur - beg); } public: unsigned char m_iHorizontalFactor; unsigned char m_iVerticalFactor; - CJpegStreamParser() : m_pStreamBase(NULL), m_nStreamSize(0) { } - ~CJpegStreamParser() { } + CJpegStreamParser() : m_pStreamBase(NULL), m_nStreamSize(0) {} + ~CJpegStreamParser() {} bool Parse(unsigned char *streambase, size_t length); @@ -72,8 +70,7 @@ public: unsigned int GetNumComponents() { return m_nComponents; } }; -void CJpegStreamParser::Initialize() -{ +void CJpegStreamParser::Initialize() { m_nComponents = 0; m_nWidth = 0; m_nHeight = 0; @@ -81,14 +78,12 @@ void CJpegStreamParser::Initialize() m_iVerticalFactor = 1; } -size_t CJpegStreamParser::GetLength(unsigned char *addr) -{ +size_t CJpegStreamParser::GetLength(unsigned char *addr) { size_t len = static_cast<size_t>(*addr++) * 0x100; return len + *addr; } -bool CJpegStreamParser::Parse(unsigned char *streambase, size_t length) -{ +bool CJpegStreamParser::Parse(unsigned char *streambase, size_t length) { Initialize(); m_pStreamBase = streambase; @@ -117,6 +112,7 @@ bool CJpegStreamParser::Parse(unsigned char *streambase, size_t length) } unsigned char marker = *addr++; + filelen -= 2; if ((marker != 0xC4) && ((marker & 0xF0) == 0xC0)) { // SOFn if (marker != 0xC0) { @@ -124,18 +120,17 @@ bool CJpegStreamParser::Parse(unsigned char *streambase, size_t length) return false; } - if (filelen < GetLength(addr)) { + if (filelen < 2 || filelen < GetLength(addr)) { ALOGE("Too small SOF0 segment"); return false; } - if (!ParseFrame(addr)) - return false; + if (!ParseFrame(addr)) return false; - return true; // this is the successful exit point + return true; // this is the successful exit point } else if (marker == 0xD9) { // EOI // This will not meet. - ALOGE("Unexpected EOI found at %lu\n", GetOffset(addr - 2)); + ALOGE("Unexpected EOI found at %td\n", GetOffset(addr - 2)); return false; } else { if ((marker == 0xCC) || (marker == 0xDC)) { // DAC and DNL @@ -143,14 +138,19 @@ bool CJpegStreamParser::Parse(unsigned char *streambase, size_t length) return false; } - if (filelen < GetLength(addr)) { + if (filelen < 2 || filelen < GetLength(addr)) { ALOGE("Corrupted JPEG stream"); return false; } } - if (GetLength(addr) == 0) { - ALOGE("Invalid length 0 is read at offset %lu", GetOffset(addr)); + if (filelen < 2 || GetLength(addr) == 0) { + ALOGE("Invalid length 0 is read at offset %td", GetOffset(addr)); + return false; + } + + if (filelen < GetLength(addr)) { + ALOGE("Corrupted JPEG Stream"); return false; } @@ -165,8 +165,7 @@ bool CJpegStreamParser::Parse(unsigned char *streambase, size_t length) return false; } -bool CJpegStreamParser::ParseFrame(unsigned char *addr) -{ // 2 bytes of length +bool CJpegStreamParser::ParseFrame(unsigned char *addr) { // 2 bytes of length // 1 byte of bits per sample // 2 bytes of height // 2 bytes of width @@ -217,7 +216,7 @@ bool CJpegStreamParser::ParseFrame(unsigned char *addr) return true; } -class CLibhwjpegDecompressor: public hwjpeg_decompressor_struct { +class CLibhwjpegDecompressor : public hwjpeg_decompressor_struct { enum { HWJPG_FLAG_NEED_MUNMAP = 1, }; @@ -231,6 +230,7 @@ class CLibhwjpegDecompressor: public hwjpeg_decompressor_struct { size_t m_nDummyBytes; CJpegStreamParser m_jpegStreamParser; + public: CLibhwjpegDecompressor() : m_flags(0) { // members of hwjpeg_decompressor_struct @@ -243,7 +243,7 @@ public: output_width = 0; output_height = 0; m_bPrepared = false; - m_pStreamBuffer = NULL; + m_pStreamBuffer = NULL; output_format = V4L2_PIX_FMT_RGB32; @@ -290,8 +290,7 @@ public: m_nDummyBytes = 0; m_pStreamBuffer = reinterpret_cast<unsigned char *>( - mmap(NULL, m_nStreamLength, - PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0)); + mmap(NULL, m_nStreamLength, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0)); if (m_pStreamBuffer == MAP_FAILED) { m_pStreamBuffer = NULL; close(fd); @@ -332,8 +331,8 @@ public: m_nDummyBytes = dummybytes; m_pStreamBuffer = reinterpret_cast<unsigned char *>( - mmap(NULL, m_nStreamLength + m_nDummyBytes, - PROT_READ | PROT_WRITE, MAP_SHARED, buffer, 0)); + mmap(NULL, m_nStreamLength + m_nDummyBytes, PROT_READ | PROT_WRITE, MAP_SHARED, + buffer, 0)); if (m_pStreamBuffer == MAP_FAILED) { m_pStreamBuffer = NULL; ALOGERR("Failed to mmap %zu bytes of dmabuf fd %d", m_nStreamLength, buffer); @@ -373,15 +372,13 @@ public: bool IsEnoughStreamBuffer() { return true; } }; -bool CLibhwjpegDecompressor::PrepareDecompression() -{ +bool CLibhwjpegDecompressor::PrepareDecompression() { if (!m_hwjpeg) { ALOGE("device node is not opened!"); return false; } - if ((scale_factor != 1) && (scale_factor != 2) && - (scale_factor != 4) && (scale_factor != 8)) { + if ((scale_factor != 1) && (scale_factor != 2) && (scale_factor != 4) && (scale_factor != 8)) { ALOGE("Invalid downscaling factor %d", scale_factor); return false; } @@ -391,8 +388,7 @@ bool CLibhwjpegDecompressor::PrepareDecompression() return false; } - if (!m_jpegStreamParser.Parse(m_pStreamBuffer, m_nStreamLength)) - return false; + if (!m_jpegStreamParser.Parse(m_pStreamBuffer, m_nStreamLength)) return false; image_width = m_jpegStreamParser.GetWidth(); image_height = m_jpegStreamParser.GetHeight(); @@ -401,9 +397,10 @@ bool CLibhwjpegDecompressor::PrepareDecompression() chroma_v_samp_factor = m_jpegStreamParser.m_iVerticalFactor; if (((image_width % (chroma_h_samp_factor * scale_factor)) != 0) || - ((image_height % (chroma_v_samp_factor * scale_factor)) != 0)) { - ALOGE("Downscaling by factor %d of compressed image size %dx%d(chroma %d:%d) is not supported", - scale_factor, image_width, image_height, chroma_h_samp_factor, chroma_v_samp_factor); + ((image_height % (chroma_v_samp_factor * scale_factor)) != 0)) { + ALOGE("Downscaling by factor %d of compressed image size %dx%d(chroma %d:%d) is not " + "supported", + scale_factor, image_width, image_height, chroma_h_samp_factor, chroma_v_samp_factor); return false; } @@ -416,7 +413,8 @@ bool CLibhwjpegDecompressor::PrepareDecompression() } if (!m_hwjpeg->SetImageFormat(output_format, output_width, output_height)) { - ALOGE("Failed to configure image format (%ux%u/%08X)", output_width, output_height, output_format); + ALOGE("Failed to configure image format (%ux%u/%08X)", output_width, output_height, + output_format); return false; } @@ -425,8 +423,7 @@ bool CLibhwjpegDecompressor::PrepareDecompression() return true; } -bool CLibhwjpegDecompressor::Decompress() -{ +bool CLibhwjpegDecompressor::Decompress() { if (!m_bPrepared) { ALOGE("JPEG header is not parsed"); return false; @@ -447,77 +444,64 @@ bool CLibhwjpegDecompressor::Decompress() return true; } -hwjpeg_decompress_ptr hwjpeg_create_decompress() -{ +hwjpeg_decompress_ptr hwjpeg_create_decompress() { hwjpeg_decompress_ptr p = new CLibhwjpegDecompressor(); - if (!p) - ALOGE("Failed to create decompress struct"); + if (!p) ALOGE("Failed to create decompress struct"); return p; } -bool hwjpeg_file_src(hwjpeg_decompress_ptr cinfo, const char *path) -{ +bool hwjpeg_file_src(hwjpeg_decompress_ptr cinfo, const char *path) { CLibhwjpegDecompressor *decomp = reinterpret_cast<CLibhwjpegDecompressor *>(cinfo); return decomp->SetStreamPath(path); } -void hwjpeg_config_image_format(hwjpeg_decompress_ptr cinfo, __u32 v4l2_pix_fmt) -{ +void hwjpeg_config_image_format(hwjpeg_decompress_ptr cinfo, __u32 v4l2_pix_fmt) { cinfo->output_format = v4l2_pix_fmt; } -bool hwjpeg_dmabuf_src(hwjpeg_decompress_ptr cinfo, int infd, size_t insize, size_t dummybytes) -{ +bool hwjpeg_dmabuf_src(hwjpeg_decompress_ptr cinfo, int infd, size_t insize, size_t dummybytes) { CLibhwjpegDecompressor *decomp = reinterpret_cast<CLibhwjpegDecompressor *>(cinfo); return decomp->SetStreamBuffer(infd, insize, dummybytes); } -bool hwjpeg_mem_src(hwjpeg_decompress_ptr cinfo, - unsigned char *inbuffer, size_t insize, size_t dummybytes) -{ +bool hwjpeg_mem_src(hwjpeg_decompress_ptr cinfo, unsigned char *inbuffer, size_t insize, + size_t dummybytes) { CLibhwjpegDecompressor *decomp = reinterpret_cast<CLibhwjpegDecompressor *>(cinfo); return decomp->SetStreamBuffer(inbuffer, insize, dummybytes); } -bool hwjpeg_mem_dst(hwjpeg_decompress_ptr cinfo, - unsigned char *outbuffer[], size_t outsize[], unsigned int num_buffers) -{ +bool hwjpeg_mem_dst(hwjpeg_decompress_ptr cinfo, unsigned char *outbuffer[], size_t outsize[], + unsigned int num_buffers) { CLibhwjpegDecompressor *decomp = reinterpret_cast<CLibhwjpegDecompressor *>(cinfo); return decomp->SetImageBuffer(outbuffer, outsize, num_buffers); } -bool hwjpeg_dmabuf_dst(hwjpeg_decompress_ptr cinfo, - int outfd[], size_t outsize[], unsigned int num_buffers) -{ +bool hwjpeg_dmabuf_dst(hwjpeg_decompress_ptr cinfo, int outfd[], size_t outsize[], + unsigned int num_buffers) { CLibhwjpegDecompressor *decomp = reinterpret_cast<CLibhwjpegDecompressor *>(cinfo); return decomp->SetImageBuffer(outfd, outsize, num_buffers); } -void hwjpeg_set_downscale_factor(hwjpeg_decompress_ptr cinfo, unsigned int factor) -{ +void hwjpeg_set_downscale_factor(hwjpeg_decompress_ptr cinfo, unsigned int factor) { cinfo->scale_factor = factor; } -bool hwjpeg_read_header(hwjpeg_decompress_ptr cinfo) -{ +bool hwjpeg_read_header(hwjpeg_decompress_ptr cinfo) { CLibhwjpegDecompressor *decomp = reinterpret_cast<CLibhwjpegDecompressor *>(cinfo); return decomp->PrepareDecompression(); } -bool hwjpeg_start_decompress(hwjpeg_decompress_ptr cinfo) -{ +bool hwjpeg_start_decompress(hwjpeg_decompress_ptr cinfo) { CLibhwjpegDecompressor *decomp = reinterpret_cast<CLibhwjpegDecompressor *>(cinfo); return decomp->Decompress(); } -void hwjpeg_destroy_decompress(hwjpeg_decompress_ptr cinfo) -{ +void hwjpeg_destroy_decompress(hwjpeg_decompress_ptr cinfo) { CLibhwjpegDecompressor *decomp = reinterpret_cast<CLibhwjpegDecompressor *>(cinfo); delete decomp; } -bool hwjpeg_has_enough_stream_buffer(hwjpeg_decompress_ptr cinfo) -{ +bool hwjpeg_has_enough_stream_buffer(hwjpeg_decompress_ptr cinfo) { CLibhwjpegDecompressor *decomp = reinterpret_cast<CLibhwjpegDecompressor *>(cinfo); return decomp->IsEnoughStreamBuffer(); } diff --git a/libion/ion.cpp b/libion/ion.cpp index cf4d36a..d4d7cb8 100644 --- a/libion/ion.cpp +++ b/libion/ion.cpp @@ -30,6 +30,8 @@ #include <mutex> +#define ARRAY_SIZE(a) (sizeof(a) / sizeof(*(a))) + static const struct { std::string heap_name; std::string ion_heap_name; @@ -50,6 +52,13 @@ static const struct { {"famodel-secure", "famodel_heap", ION_FLAG_PROTECTED, EXYNOS_ION_HEAP_FA_MODEL_MASK}, }; +const char *exynos_ion_get_heap_name(unsigned int legacy_heap_id) { + if (legacy_heap_id >= ARRAY_SIZE(heap_map_table)) + return NULL; + + return heap_map_table[legacy_heap_id].ion_heap_name.c_str(); +} + int exynos_ion_open(void) { return 0; } diff --git a/libion/test/Android.bp b/libion/test/Android.bp index 017eca2..fcc51f5 100644 --- a/libion/test/Android.bp +++ b/libion/test/Android.bp @@ -21,17 +21,20 @@ package { cc_test { name: "iontests_google", - clang: true, + vendor: true, proprietary: true, - cflags: [ "-g", "-Werror" ], + cflags: [ + "-g", + "-Werror", + ], shared_libs: ["libion_google"], srcs: [ "ion_test_fixture.cpp", "ion_allocate_test.cpp", "ion_allocate_api_test.cpp", "ion_device_test.cpp", - "ion_allocate_special.cpp", + "ion_allocate_special.cpp", //"map_test.cpp", //"exynos_api_test.cpp", ], |