diff options
-rw-r--r-- | include/input/Input.h | 13 | ||||
-rw-r--r-- | libs/input/Input.cpp | 30 | ||||
-rw-r--r-- | services/inputflinger/PointerChoreographer.cpp | 40 | ||||
-rw-r--r-- | services/inputflinger/dispatcher/InputDispatcher.cpp | 210 | ||||
-rw-r--r-- | services/inputflinger/dispatcher/InputDispatcher.h | 85 | ||||
-rw-r--r-- | services/inputflinger/dispatcher/InputState.cpp | 12 | ||||
-rw-r--r-- | services/inputflinger/reader/mapper/SlopController.cpp | 4 | ||||
-rw-r--r-- | vulkan/tests/Android.bp | 56 | ||||
-rw-r--r-- | vulkan/tests/README.md | 24 | ||||
-rw-r--r-- | vulkan/tests/libvulkan_test.cpp | 360 |
10 files changed, 615 insertions, 219 deletions
diff --git a/include/input/Input.h b/include/input/Input.h index e84023e5e5..002b3a7d15 100644 --- a/include/input/Input.h +++ b/include/input/Input.h @@ -316,6 +316,19 @@ struct PointerProperties; bool isStylusEvent(uint32_t source, const std::vector<PointerProperties>& properties); +bool isStylusHoverEvent(uint32_t source, const std::vector<PointerProperties>& properties, + int32_t action); + +bool isFromMouse(uint32_t source, ToolType tooltype); + +bool isFromTouchpad(uint32_t source, ToolType tooltype); + +bool isFromDrawingTablet(uint32_t source, ToolType tooltype); + +bool isHoverAction(int32_t action); + +bool isMouseOrTouchpad(uint32_t sources); + /* * Flags that flow alongside events in the input dispatch system to help with certain * policy decisions such as waking from device sleep. diff --git a/libs/input/Input.cpp b/libs/input/Input.cpp index 65a088eb6d..155ea000e3 100644 --- a/libs/input/Input.cpp +++ b/libs/input/Input.cpp @@ -284,6 +284,36 @@ bool isStylusEvent(uint32_t source, const std::vector<PointerProperties>& proper return false; } +bool isStylusHoverEvent(uint32_t source, const std::vector<PointerProperties>& properties, + int32_t action) { + return isStylusEvent(source, properties) && isHoverAction(action); +} + +bool isFromMouse(uint32_t source, ToolType toolType) { + return isFromSource(source, AINPUT_SOURCE_MOUSE) && toolType == ToolType::MOUSE; +} + +bool isFromTouchpad(uint32_t source, ToolType toolType) { + return isFromSource(source, AINPUT_SOURCE_MOUSE) && toolType == ToolType::FINGER; +} + +bool isFromDrawingTablet(uint32_t source, ToolType toolType) { + return isFromSource(source, AINPUT_SOURCE_MOUSE | AINPUT_SOURCE_STYLUS) && + isStylusToolType(toolType); +} + +bool isHoverAction(int32_t action) { + return action == AMOTION_EVENT_ACTION_HOVER_ENTER || + action == AMOTION_EVENT_ACTION_HOVER_MOVE || action == AMOTION_EVENT_ACTION_HOVER_EXIT; +} + +bool isMouseOrTouchpad(uint32_t sources) { + // Check if this is a mouse or touchpad, but not a drawing tablet. + return isFromSource(sources, AINPUT_SOURCE_MOUSE_RELATIVE) || + (isFromSource(sources, AINPUT_SOURCE_MOUSE) && + !isFromSource(sources, AINPUT_SOURCE_STYLUS)); +} + VerifiedKeyEvent verifiedKeyEventFromKeyEvent(const KeyEvent& event) { return {{VerifiedInputEvent::Type::KEY, event.getDeviceId(), event.getEventTime(), event.getSource(), event.getDisplayId()}, diff --git a/services/inputflinger/PointerChoreographer.cpp b/services/inputflinger/PointerChoreographer.cpp index 85f842cbbe..e2a772aaf0 100644 --- a/services/inputflinger/PointerChoreographer.cpp +++ b/services/inputflinger/PointerChoreographer.cpp @@ -36,37 +36,6 @@ namespace android { namespace { -bool isFromMouse(const NotifyMotionArgs& args) { - return isFromSource(args.source, AINPUT_SOURCE_MOUSE) && - args.pointerProperties[0].toolType == ToolType::MOUSE; -} - -bool isFromTouchpad(const NotifyMotionArgs& args) { - return isFromSource(args.source, AINPUT_SOURCE_MOUSE) && - args.pointerProperties[0].toolType == ToolType::FINGER; -} - -bool isFromDrawingTablet(const NotifyMotionArgs& args) { - return isFromSource(args.source, AINPUT_SOURCE_MOUSE | AINPUT_SOURCE_STYLUS) && - isStylusToolType(args.pointerProperties[0].toolType); -} - -bool isHoverAction(int32_t action) { - return action == AMOTION_EVENT_ACTION_HOVER_ENTER || - action == AMOTION_EVENT_ACTION_HOVER_MOVE || action == AMOTION_EVENT_ACTION_HOVER_EXIT; -} - -bool isStylusHoverEvent(const NotifyMotionArgs& args) { - return isStylusEvent(args.source, args.pointerProperties) && isHoverAction(args.action); -} - -bool isMouseOrTouchpad(uint32_t sources) { - // Check if this is a mouse or touchpad, but not a drawing tablet. - return isFromSource(sources, AINPUT_SOURCE_MOUSE_RELATIVE) || - (isFromSource(sources, AINPUT_SOURCE_MOUSE) && - !isFromSource(sources, AINPUT_SOURCE_STYLUS)); -} - inline void notifyPointerDisplayChange(std::optional<std::tuple<ui::LogicalDisplayId, vec2>> change, PointerChoreographerPolicyInterface& policy) { if (!change) { @@ -239,15 +208,16 @@ NotifyMotionArgs PointerChoreographer::processMotion(const NotifyMotionArgs& arg PointerDisplayChange pointerDisplayChange; { // acquire lock std::scoped_lock _l(getLock()); - if (isFromMouse(args)) { + if (isFromMouse(args.source, args.pointerProperties[0].toolType)) { newArgs = processMouseEventLocked(args); pointerDisplayChange = calculatePointerDisplayChangeToNotify(); - } else if (isFromTouchpad(args)) { + } else if (isFromTouchpad(args.source, args.pointerProperties[0].toolType)) { newArgs = processTouchpadEventLocked(args); pointerDisplayChange = calculatePointerDisplayChangeToNotify(); - } else if (isFromDrawingTablet(args)) { + } else if (isFromDrawingTablet(args.source, args.pointerProperties[0].toolType)) { processDrawingTabletEventLocked(args); - } else if (mStylusPointerIconEnabled && isStylusHoverEvent(args)) { + } else if (mStylusPointerIconEnabled && + isStylusHoverEvent(args.source, args.pointerProperties, args.action)) { processStylusHoverEventLocked(args); } else if (isFromSource(args.source, AINPUT_SOURCE_TOUCHSCREEN)) { processTouchscreenAndStylusEventLocked(args); diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index a77dc437f2..04197ee99d 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -920,13 +920,6 @@ std::string dumpWindowForTouchOcclusion(const WindowInfo& info, bool isTouchedWi binderToString(info.applicationInfo.token).c_str()); } -bool isMouseOrTouchpad(uint32_t sources) { - // Check if this is a mouse or touchpad, but not a drawing tablet. - return isFromSource(sources, AINPUT_SOURCE_MOUSE_RELATIVE) || - (isFromSource(sources, AINPUT_SOURCE_MOUSE) && - !isFromSource(sources, AINPUT_SOURCE_STYLUS)); -} - } // namespace // --- InputDispatcher --- @@ -943,6 +936,7 @@ InputDispatcher::InputDispatcher(InputDispatcherPolicyInterface& policy, mIdGenerator(IdGenerator::Source::INPUT_DISPATCHER), mMinTimeBetweenUserActivityPokes(DEFAULT_USER_ACTIVITY_POKE_INTERVAL), mConnectionManager(mLooper), + mTouchStates(mWindowInfos, mConnectionManager), mNextUnblockedEvent(nullptr), mMonitorDispatchingTimeout(DEFAULT_INPUT_DISPATCHING_TIMEOUT), mDispatchEnabled(false), @@ -1473,14 +1467,13 @@ sp<WindowInfoHandle> InputDispatcher::DispatcherWindowInfo::findTouchedWindowAt( std::vector<InputTarget> InputDispatcher::DispatcherTouchState::findOutsideTargets( ui::LogicalDisplayId displayId, const sp<gui::WindowInfoHandle>& touchedWindow, - int32_t pointerId, const ConnectionManager& connections, - const DispatcherWindowInfo& windowInfos, std::function<void()> dump) { + int32_t pointerId, std::function<void()> dump) { if (touchedWindow == nullptr) { return {}; } // Traverse windows from front to back until we encounter the touched window. std::vector<InputTarget> outsideTargets; - const auto& windowHandles = windowInfos.getWindowHandlesForDisplay(displayId); + const auto& windowHandles = mWindowInfos.getWindowHandlesForDisplay(displayId); for (const sp<WindowInfoHandle>& windowHandle : windowHandles) { if (windowHandle == touchedWindow) { // Stop iterating once we found a touched window. Any WATCH_OUTSIDE_TOUCH window @@ -1495,8 +1488,7 @@ std::vector<InputTarget> InputDispatcher::DispatcherTouchState::findOutsideTarge addPointerWindowTarget(windowHandle, InputTarget::DispatchMode::OUTSIDE, ftl::Flags<InputTarget::Flags>(), pointerIds, /*firstDownTimeInTarget=*/std::nullopt, - /*pointerDisplayId=*/std::nullopt, connections, windowInfos, - dump, outsideTargets); + /*pointerDisplayId=*/std::nullopt, dump, outsideTargets); } } return outsideTargets; @@ -2058,8 +2050,7 @@ bool InputDispatcher::dispatchMotionLocked(nsecs_t currentTime, Result<std::vector<InputTarget>, InputEventInjectionResult> result = mTouchStates - .findTouchedWindowTargets(currentTime, *entry, mConnectionManager, - mWindowInfos, + .findTouchedWindowTargets(currentTime, *entry, mDragState ? mDragState->dragWindow : nullptr, std::bind_front(&InputDispatcher:: addDragEventLocked, @@ -2379,8 +2370,7 @@ InputDispatcher::findFocusedWindowTargetLocked(nsecs_t currentTime, const EventE base::Result<std::vector<InputTarget>, os::InputEventInjectionResult> InputDispatcher::DispatcherTouchState::findTouchedWindowTargets( - nsecs_t currentTime, const MotionEntry& entry, const ConnectionManager& connections, - const DispatcherWindowInfo& windowInfos, + nsecs_t currentTime, const MotionEntry& entry, const sp<android::gui::WindowInfoHandle> dragWindow, std::function<void(const MotionEntry&)> addDragEvent, std::function<void()> dump) { ATRACE_CALL(); @@ -2395,7 +2385,7 @@ InputDispatcher::DispatcherTouchState::findTouchedWindowTargets( // Copy current touch state into tempTouchState. // This state will be used to update saved touch state at the end of this function. // If no state for the specified display exists, then our initial state will be empty. - const TouchState* oldState = getTouchStateForMotionEntry(entry, windowInfos); + const TouchState* oldState = getTouchStateForMotionEntry(entry); TouchState tempTouchState; if (oldState != nullptr) { tempTouchState = *oldState; @@ -2441,12 +2431,10 @@ InputDispatcher::DispatcherTouchState::findTouchedWindowTargets( // be a pointer that would generate ACTION_DOWN, *and* touch should not already be down. const bool isStylus = isPointerFromStylus(entry, pointerIndex); sp<WindowInfoHandle> newTouchedWindowHandle = - windowInfos.findTouchedWindowAt(displayId, x, y, isStylus); + mWindowInfos.findTouchedWindowAt(displayId, x, y, isStylus); if (isDown) { - targets += DispatcherTouchState::findOutsideTargets(displayId, newTouchedWindowHandle, - pointer.id, connections, - windowInfos, dump); + targets += findOutsideTargets(displayId, newTouchedWindowHandle, pointer.id, dump); } LOG_IF(INFO, newTouchedWindowHandle == nullptr) << "No new touched window at (" << std::format("{:.1f}, {:.1f}", x, y) @@ -2459,7 +2447,7 @@ InputDispatcher::DispatcherTouchState::findTouchedWindowTargets( } std::vector<sp<WindowInfoHandle>> newTouchedWindows = - findTouchedSpyWindowsAt(displayId, x, y, isStylus, entry.deviceId, windowInfos); + findTouchedSpyWindowsAt(displayId, x, y, isStylus, entry.deviceId, mWindowInfos); if (newTouchedWindowHandle != nullptr) { // Process the foreground window first so that it is the first to receive the event. newTouchedWindows.insert(newTouchedWindows.begin(), newTouchedWindowHandle); @@ -2472,7 +2460,7 @@ InputDispatcher::DispatcherTouchState::findTouchedWindowTargets( } for (const sp<WindowInfoHandle>& windowHandle : newTouchedWindows) { - if (!canWindowReceiveMotion(windowHandle, entry, connections, windowInfos)) { + if (!canWindowReceiveMotion(windowHandle, entry)) { continue; } @@ -2484,8 +2472,7 @@ InputDispatcher::DispatcherTouchState::findTouchedWindowTargets( // Set target flags. ftl::Flags<InputTarget::Flags> targetFlags = - DispatcherTouchState::getTargetFlags(windowHandle, {x, y}, isSplit, - windowInfos); + getTargetFlags(windowHandle, {x, y}, isSplit); // Update the temporary touch state. @@ -2515,7 +2502,7 @@ InputDispatcher::DispatcherTouchState::findTouchedWindowTargets( windowHandle->getInfo()->inputConfig.test( gui::WindowInfo::InputConfig::DUPLICATE_TOUCH_TO_WALLPAPER)) { sp<WindowInfoHandle> wallpaper = - windowInfos.findWallpaperWindowBelow(windowHandle); + mWindowInfos.findWallpaperWindowBelow(windowHandle); if (wallpaper != nullptr) { ftl::Flags<InputTarget::Flags> wallpaperFlags = InputTarget::Flags::WINDOW_IS_OBSCURED | @@ -2584,7 +2571,7 @@ InputDispatcher::DispatcherTouchState::findTouchedWindowTargets( tempTouchState.getFirstForegroundWindowHandle(entry.deviceId); LOG_ALWAYS_FATAL_IF(oldTouchedWindowHandle == nullptr); sp<WindowInfoHandle> newTouchedWindowHandle = - windowInfos.findTouchedWindowAt(displayId, x, y, isStylus); + mWindowInfos.findTouchedWindowAt(displayId, x, y, isStylus); // Verify targeted injection. if (const auto err = verifyTargetedInjection(newTouchedWindowHandle, entry); err) { @@ -2594,7 +2581,7 @@ InputDispatcher::DispatcherTouchState::findTouchedWindowTargets( // Do not slide events to the window which can not receive motion event if (newTouchedWindowHandle != nullptr && - !canWindowReceiveMotion(newTouchedWindowHandle, entry, connections, windowInfos)) { + !canWindowReceiveMotion(newTouchedWindowHandle, entry)) { newTouchedWindowHandle = nullptr; } @@ -2615,14 +2602,12 @@ InputDispatcher::DispatcherTouchState::findTouchedWindowTargets( InputTarget::DispatchMode::SLIPPERY_EXIT, ftl::Flags<InputTarget::Flags>(), pointerIds, touchedWindow.getDownTimeInTarget(entry.deviceId), - /*pointerDisplayId=*/std::nullopt, connections, windowInfos, - dump, targets); + /*pointerDisplayId=*/std::nullopt, dump, targets); // Make a slippery entrance into the new window. ftl::Flags<InputTarget::Flags> targetFlags = - DispatcherTouchState::getTargetFlags(newTouchedWindowHandle, {x, y}, - isSplit, windowInfos); + getTargetFlags(newTouchedWindowHandle, {x, y}, isSplit); tempTouchState.addOrUpdateWindow(newTouchedWindowHandle, InputTarget::DispatchMode::SLIPPERY_ENTER, @@ -2630,10 +2615,8 @@ InputDispatcher::DispatcherTouchState::findTouchedWindowTargets( entry.eventTime); // Check if the wallpaper window should deliver the corresponding event. - DispatcherTouchState::slipWallpaperTouch(targetFlags, oldTouchedWindowHandle, - newTouchedWindowHandle, tempTouchState, - entry, targets, connections, windowInfos, - dump); + slipWallpaperTouch(targetFlags, oldTouchedWindowHandle, newTouchedWindowHandle, + tempTouchState, entry, targets, dump); tempTouchState.removeTouchingPointerFromWindow(entry.deviceId, pointer.id, oldTouchedWindowHandle); } @@ -2668,8 +2651,7 @@ InputDispatcher::DispatcherTouchState::findTouchedWindowTargets( addPointerWindowTarget(touchedWindow.windowHandle, touchedWindow.dispatchMode, touchedWindow.targetFlags, pointerIds, touchedWindow.getDownTimeInTarget(entry.deviceId), - /*pointerDisplayId=*/std::nullopt, connections, windowInfos, - dump, targets); + /*pointerDisplayId=*/std::nullopt, dump, targets); } } @@ -2698,7 +2680,7 @@ InputDispatcher::DispatcherTouchState::findTouchedWindowTargets( for (InputTarget& target : targets) { if (target.dispatchMode == InputTarget::DispatchMode::OUTSIDE) { sp<WindowInfoHandle> targetWindow = - windowInfos.findWindowHandle(target.connection->getToken()); + mWindowInfos.findWindowHandle(target.connection->getToken()); if (targetWindow->getInfo()->ownerUid != foregroundWindowUid) { target.flags |= InputTarget::Flags::ZERO_COORDS; } @@ -2725,8 +2707,7 @@ InputDispatcher::DispatcherTouchState::findTouchedWindowTargets( addPointerWindowTarget(touchedWindow.windowHandle, touchedWindow.dispatchMode, touchedWindow.targetFlags, getPointerIds(touchingPointers), touchedWindow.getDownTimeInTarget(entry.deviceId), - /*pointerDisplayId=*/displayId, connections, windowInfos, dump, - targets); + /*pointerDisplayId=*/displayId, dump, targets); } // During targeted injection, only allow owned targets to receive events @@ -2781,9 +2762,9 @@ InputDispatcher::DispatcherTouchState::findTouchedWindowTargets( if (maskedAction != AMOTION_EVENT_ACTION_SCROLL) { if (displayId >= ui::LogicalDisplayId::DEFAULT) { tempTouchState.clearWindowsWithoutPointers(); - saveTouchStateForMotionEntry(entry, std::move(tempTouchState), windowInfos); + saveTouchStateForMotionEntry(entry, std::move(tempTouchState)); } else { - eraseTouchStateForMotionEntry(entry, windowInfos); + eraseTouchStateForMotionEntry(entry); } } @@ -2930,8 +2911,7 @@ void InputDispatcher::DispatcherTouchState::addPointerWindowTarget( const sp<android::gui::WindowInfoHandle>& windowHandle, InputTarget::DispatchMode dispatchMode, ftl::Flags<InputTarget::Flags> targetFlags, std::bitset<MAX_POINTER_ID + 1> pointerIds, std::optional<nsecs_t> firstDownTimeInTarget, - std::optional<ui::LogicalDisplayId> pointerDisplayId, const ConnectionManager& connections, - const DispatcherWindowInfo& windowInfos, std::function<void()> dump, + std::optional<ui::LogicalDisplayId> pointerDisplayId, std::function<void()> dump, std::vector<InputTarget>& inputTargets) { if (pointerIds.none()) { for (const auto& target : inputTargets) { @@ -2960,15 +2940,15 @@ void InputDispatcher::DispatcherTouchState::addPointerWindowTarget( const WindowInfo& windowInfo = *windowHandle->getInfo(); if (it == inputTargets.end()) { - std::shared_ptr<Connection> connection = connections.getConnection(windowInfo.token); + std::shared_ptr<Connection> connection = mConnectionManager.getConnection(windowInfo.token); if (connection == nullptr) { ALOGW("Not creating InputTarget for %s, no input channel", windowInfo.name.c_str()); return; } inputTargets.push_back( createInputTarget(connection, windowHandle, dispatchMode, targetFlags, - windowInfos.getRawTransform(*windowHandle->getInfo(), - pointerDisplayId), + mWindowInfos.getRawTransform(*windowHandle->getInfo(), + pointerDisplayId), firstDownTimeInTarget)); it = inputTargets.end() - 1; } @@ -4168,16 +4148,15 @@ void InputDispatcher::synthesizeCancelationEventsForConnectionLocked( sendDropWindowCommandLocked(nullptr, /*x=*/0, /*y=*/0); mDragState.reset(); } - DispatcherTouchState:: - addPointerWindowTarget(window, InputTarget::DispatchMode::AS_IS, - ftl::Flags<InputTarget::Flags>(), pointerIds, - motionEntry.downTime, - /*pointerDisplayId=*/std::nullopt, - mConnectionManager, mWindowInfos, - std::bind_front(&InputDispatcher:: - logDispatchStateLocked, - this), - targets); + mTouchStates + .addPointerWindowTarget(window, InputTarget::DispatchMode::AS_IS, + ftl::Flags<InputTarget::Flags>(), pointerIds, + motionEntry.downTime, + /*pointerDisplayId=*/std::nullopt, + std::bind_front(&InputDispatcher:: + logDispatchStateLocked, + this), + targets); } else { targets.emplace_back(fallbackTarget); // Since we don't have a window, use the display transform as the raw transform. @@ -4256,15 +4235,14 @@ void InputDispatcher::synthesizePointerDownEventsForConnectionLocked( pointerIndex++) { pointerIds.set(motionEntry.pointerProperties[pointerIndex].id); } - DispatcherTouchState:: - addPointerWindowTarget(windowHandle, InputTarget::DispatchMode::AS_IS, - targetFlags, pointerIds, motionEntry.downTime, - /*pointerDisplayId=*/std::nullopt, - mConnectionManager, mWindowInfos, - std::bind_front(&InputDispatcher:: - logDispatchStateLocked, - this), - targets); + mTouchStates + .addPointerWindowTarget(windowHandle, InputTarget::DispatchMode::AS_IS, + targetFlags, pointerIds, motionEntry.downTime, + /*pointerDisplayId=*/std::nullopt, + std::bind_front(&InputDispatcher:: + logDispatchStateLocked, + this), + targets); } else { targets.emplace_back(connection, targetFlags); // Since we don't have a window, use the display transform as the raw transform. @@ -5238,8 +5216,7 @@ std::string InputDispatcher::DispatcherWindowInfo::dumpDisplayAndWindowInfo() co bool InputDispatcher::DispatcherTouchState::canWindowReceiveMotion( const sp<android::gui::WindowInfoHandle>& window, - const android::inputdispatcher::MotionEntry& motionEntry, - const ConnectionManager& connections, const DispatcherWindowInfo& windowInfos) const { + const android::inputdispatcher::MotionEntry& motionEntry) const { const WindowInfo& info = *window->getInfo(); // Skip spy window targets that are not valid for targeted injection. @@ -5258,7 +5235,7 @@ bool InputDispatcher::DispatcherTouchState::canWindowReceiveMotion( return false; } - std::shared_ptr<Connection> connection = connections.getConnection(window->getToken()); + std::shared_ptr<Connection> connection = mConnectionManager.getConnection(window->getToken()); if (connection == nullptr) { ALOGW("Not sending touch to %s because there's no corresponding connection", window->getName().c_str()); @@ -5273,8 +5250,8 @@ bool InputDispatcher::DispatcherTouchState::canWindowReceiveMotion( // Drop events that can't be trusted due to occlusion const auto [x, y] = resolveTouchedPosition(motionEntry); DispatcherWindowInfo::TouchOcclusionInfo occlusionInfo = - windowInfos.computeTouchOcclusionInfo(window, x, y); - if (!windowInfos.isTouchTrusted(occlusionInfo)) { + mWindowInfos.computeTouchOcclusionInfo(window, x, y); + if (!mWindowInfos.isTouchTrusted(occlusionInfo)) { if (DEBUG_TOUCH_OCCLUSION) { ALOGD("Stack of obscuring windows during untrusted touch (%.1f, %.1f):", x, y); for (const auto& log : occlusionInfo.debugInfo) { @@ -5287,7 +5264,7 @@ bool InputDispatcher::DispatcherTouchState::canWindowReceiveMotion( } // Drop touch events if requested by input feature - if (shouldDropInput(motionEntry, window, windowInfos)) { + if (shouldDropInput(motionEntry, window, mWindowInfos)) { return false; } @@ -5423,7 +5400,7 @@ void InputDispatcher::setInputWindowsLocked( CancelationOptions hoverCancellationOptions(CancelationOptions::Mode::CANCEL_HOVER_EVENTS, "WindowInfo changed", traceContext.getTracker()); const std::list<DispatcherTouchState::CancellationArgs> cancellations = - mTouchStates.updateFromWindowInfo(displayId, mWindowInfos); + mTouchStates.updateFromWindowInfo(displayId); for (const auto& cancellationArgs : cancellations) { switch (cancellationArgs.mode) { case CancelationOptions::Mode::CANCEL_POINTER_EVENTS: @@ -5464,14 +5441,13 @@ void InputDispatcher::setInputWindowsLocked( } std::list<InputDispatcher::DispatcherTouchState::CancellationArgs> -InputDispatcher::DispatcherTouchState::updateFromWindowInfo( - ui::LogicalDisplayId displayId, const DispatcherWindowInfo& windowInfos) { +InputDispatcher::DispatcherTouchState::updateFromWindowInfo(ui::LogicalDisplayId displayId) { std::list<CancellationArgs> cancellations; forTouchAndCursorStatesOnDisplay(displayId, [&](TouchState& state) { cancellations.splice(cancellations.end(), - eraseRemovedWindowsFromWindowInfo(state, displayId, windowInfos)); + eraseRemovedWindowsFromWindowInfo(state, displayId)); cancellations.splice(cancellations.end(), - updateHoveringStateFromWindowInfo(state, displayId, windowInfos)); + updateHoveringStateFromWindowInfo(state, displayId)); return false; }); return cancellations; @@ -5479,12 +5455,11 @@ InputDispatcher::DispatcherTouchState::updateFromWindowInfo( std::list<InputDispatcher::DispatcherTouchState::CancellationArgs> InputDispatcher::DispatcherTouchState::eraseRemovedWindowsFromWindowInfo( - TouchState& state, ui::LogicalDisplayId displayId, - const DispatcherWindowInfo& windowInfos) { + TouchState& state, ui::LogicalDisplayId displayId) { std::list<CancellationArgs> cancellations; for (auto it = state.windows.begin(); it != state.windows.end();) { TouchedWindow& touchedWindow = *it; - if (windowInfos.isWindowPresent(touchedWindow.windowHandle)) { + if (mWindowInfos.isWindowPresent(touchedWindow.windowHandle)) { it++; continue; } @@ -5510,12 +5485,11 @@ InputDispatcher::DispatcherTouchState::eraseRemovedWindowsFromWindowInfo( std::list<InputDispatcher::DispatcherTouchState::CancellationArgs> InputDispatcher::DispatcherTouchState::updateHoveringStateFromWindowInfo( - TouchState& state, ui::LogicalDisplayId displayId, - const DispatcherWindowInfo& windowInfos) { + TouchState& state, ui::LogicalDisplayId displayId) { std::list<CancellationArgs> cancellations; // Check if the hovering should stop because the window is no longer eligible to receive it // (for example, if the touchable region changed) - ui::Transform displayTransform = windowInfos.getDisplayTransform(displayId); + ui::Transform displayTransform = mWindowInfos.getDisplayTransform(displayId); for (TouchedWindow& touchedWindow : state.windows) { std::vector<DeviceId> erasedDevices = touchedWindow.eraseHoveringPointersIf( [&](const PointerProperties& properties, float x, float y) { @@ -5770,8 +5744,7 @@ bool InputDispatcher::transferTouchGesture(const sp<IBinder>& fromToken, const s "transferring touch from this window to another window", traceContext.getTracker()); - auto result = mTouchStates.transferTouchGesture(fromToken, toToken, mWindowInfos, - mConnectionManager); + auto result = mTouchStates.transferTouchGesture(fromToken, toToken); if (!result.has_value()) { return false; } @@ -5815,9 +5788,7 @@ std::optional<std::tuple<sp<gui::WindowInfoHandle>, DeviceId, std::vector<Pointe std::list<InputDispatcher::DispatcherTouchState::CancellationArgs>, std::list<InputDispatcher::DispatcherTouchState::PointerDownArgs>>> InputDispatcher::DispatcherTouchState::transferTouchGesture(const sp<android::IBinder>& fromToken, - const sp<android::IBinder>& toToken, - const DispatcherWindowInfo& windowInfos, - const ConnectionManager& connections) { + const sp<android::IBinder>& toToken) { // Find the target touch state and touched window by fromToken. auto touchStateWindowAndDisplay = findTouchStateWindowAndDisplay(fromToken); if (!touchStateWindowAndDisplay.has_value()) { @@ -5835,7 +5806,7 @@ InputDispatcher::DispatcherTouchState::transferTouchGesture(const sp<android::IB const DeviceId deviceId = *deviceIds.begin(); const sp<WindowInfoHandle> fromWindowHandle = touchedWindow.windowHandle; - const sp<WindowInfoHandle> toWindowHandle = windowInfos.findWindowHandle(toToken, displayId); + const sp<WindowInfoHandle> toWindowHandle = mWindowInfos.findWindowHandle(toToken, displayId); if (!toWindowHandle) { ALOGW("Cannot transfer touch because the transfer target window was not found."); return std::nullopt; @@ -5861,8 +5832,8 @@ InputDispatcher::DispatcherTouchState::transferTouchGesture(const sp<android::IB deviceId, pointers, downTimeInTarget); // Synthesize cancel for old window and down for new window. - std::shared_ptr<Connection> fromConnection = connections.getConnection(fromToken); - std::shared_ptr<Connection> toConnection = connections.getConnection(toToken); + std::shared_ptr<Connection> fromConnection = mConnectionManager.getConnection(fromToken); + std::shared_ptr<Connection> toConnection = mConnectionManager.getConnection(toToken); std::list<CancellationArgs> cancellations; std::list<PointerDownArgs> pointerDowns; if (fromConnection != nullptr && toConnection != nullptr) { @@ -5873,7 +5844,7 @@ InputDispatcher::DispatcherTouchState::transferTouchGesture(const sp<android::IB // Check if the wallpaper window should deliver the corresponding event. auto [wallpaperCancellations, wallpaperPointerDowns] = transferWallpaperTouch(fromWindowHandle, toWindowHandle, state, deviceId, pointers, - oldTargetFlags, newTargetFlags, windowInfos, connections); + oldTargetFlags, newTargetFlags); cancellations.splice(cancellations.end(), wallpaperCancellations); pointerDowns.splice(pointerDowns.end(), wallpaperPointerDowns); @@ -7092,8 +7063,7 @@ void InputDispatcher::setMonitorDispatchingTimeoutForTest(std::chrono::nanosecon void InputDispatcher::DispatcherTouchState::slipWallpaperTouch( ftl::Flags<InputTarget::Flags> targetFlags, const sp<WindowInfoHandle>& oldWindowHandle, const sp<WindowInfoHandle>& newWindowHandle, TouchState& state, const MotionEntry& entry, - std::vector<InputTarget>& targets, const ConnectionManager& connections, - const DispatcherWindowInfo& windowInfos, std::function<void()> dump) { + std::vector<InputTarget>& targets, std::function<void()> dump) { LOG_IF(FATAL, entry.getPointerCount() != 1) << "Entry not eligible for slip: " << entry; const DeviceId deviceId = entry.deviceId; const PointerProperties& pointerProperties = entry.pointerProperties[0]; @@ -7106,20 +7076,17 @@ void InputDispatcher::DispatcherTouchState::slipWallpaperTouch( const sp<WindowInfoHandle> oldWallpaper = oldHasWallpaper ? state.getWallpaperWindow(deviceId) : nullptr; const sp<WindowInfoHandle> newWallpaper = - newHasWallpaper ? windowInfos.findWallpaperWindowBelow(newWindowHandle) : nullptr; + newHasWallpaper ? mWindowInfos.findWallpaperWindowBelow(newWindowHandle) : nullptr; if (oldWallpaper == newWallpaper) { return; } if (oldWallpaper != nullptr) { const TouchedWindow& oldTouchedWindow = state.getTouchedWindow(oldWallpaper); - DispatcherTouchState::addPointerWindowTarget(oldWallpaper, - InputTarget::DispatchMode::SLIPPERY_EXIT, - oldTouchedWindow.targetFlags, - getPointerIds(pointers), - oldTouchedWindow.getDownTimeInTarget(deviceId), - /*pointerDisplayId=*/std::nullopt, connections, - windowInfos, dump, targets); + addPointerWindowTarget(oldWallpaper, InputTarget::DispatchMode::SLIPPERY_EXIT, + oldTouchedWindow.targetFlags, getPointerIds(pointers), + oldTouchedWindow.getDownTimeInTarget(deviceId), + /*pointerDisplayId=*/std::nullopt, dump, targets); state.removeTouchingPointerFromWindow(deviceId, pointerProperties.id, oldWallpaper); } @@ -7138,8 +7105,7 @@ InputDispatcher::DispatcherTouchState::transferWallpaperTouch( const sp<gui::WindowInfoHandle> toWindowHandle, TouchState& state, android::DeviceId deviceId, const std::vector<PointerProperties>& pointers, ftl::Flags<InputTarget::Flags> oldTargetFlags, - ftl::Flags<InputTarget::Flags> newTargetFlags, const DispatcherWindowInfo& windowInfos, - const ConnectionManager& connections) { + ftl::Flags<InputTarget::Flags> newTargetFlags) { const bool oldHasWallpaper = oldTargetFlags.test(InputTarget::Flags::FOREGROUND) && fromWindowHandle->getInfo()->inputConfig.test( gui::WindowInfo::InputConfig::DUPLICATE_TOUCH_TO_WALLPAPER); @@ -7150,7 +7116,7 @@ InputDispatcher::DispatcherTouchState::transferWallpaperTouch( const sp<WindowInfoHandle> oldWallpaper = oldHasWallpaper ? state.getWallpaperWindow(deviceId) : nullptr; const sp<WindowInfoHandle> newWallpaper = - newHasWallpaper ? windowInfos.findWallpaperWindowBelow(toWindowHandle) : nullptr; + newHasWallpaper ? mWindowInfos.findWallpaperWindowBelow(toWindowHandle) : nullptr; if (oldWallpaper == newWallpaper) { return {}; } @@ -7171,10 +7137,10 @@ InputDispatcher::DispatcherTouchState::transferWallpaperTouch( state.addOrUpdateWindow(newWallpaper, InputTarget::DispatchMode::AS_IS, wallpaperFlags, deviceId, pointers, downTimeInTarget); std::shared_ptr<Connection> wallpaperConnection = - connections.getConnection(newWallpaper->getToken()); + mConnectionManager.getConnection(newWallpaper->getToken()); if (wallpaperConnection != nullptr) { std::shared_ptr<Connection> toConnection = - connections.getConnection(toWindowHandle->getToken()); + mConnectionManager.getConnection(toWindowHandle->getToken()); toConnection->inputState.mergePointerStateTo(wallpaperConnection->inputState); pointerDowns.emplace_back(downTimeInTarget, wallpaperConnection, wallpaperFlags); } @@ -7374,9 +7340,12 @@ void InputDispatcher::DispatcherWindowInfo::setDisplayTopology( mTopology = displayTopologyGraph; } +InputDispatcher::DispatcherTouchState::DispatcherTouchState(const DispatcherWindowInfo& windowInfos, + const ConnectionManager& connections) + : mWindowInfos(windowInfos), mConnectionManager(connections) {} + ftl::Flags<InputTarget::Flags> InputDispatcher::DispatcherTouchState::getTargetFlags( - const sp<WindowInfoHandle>& targetWindow, vec2 targetPosition, bool isSplit, - const DispatcherWindowInfo& windowInfos) { + const sp<WindowInfoHandle>& targetWindow, vec2 targetPosition, bool isSplit) { ftl::Flags<InputTarget::Flags> targetFlags; if (canReceiveForegroundTouches(*targetWindow->getInfo())) { // There should only be one touched window that can be "foreground" for the pointer. @@ -7385,9 +7354,9 @@ ftl::Flags<InputTarget::Flags> InputDispatcher::DispatcherTouchState::getTargetF if (isSplit) { targetFlags |= InputTarget::Flags::SPLIT; } - if (windowInfos.isWindowObscuredAtPoint(targetWindow, targetPosition.x, targetPosition.y)) { + if (mWindowInfos.isWindowObscuredAtPoint(targetWindow, targetPosition.x, targetPosition.y)) { targetFlags |= InputTarget::Flags::WINDOW_IS_OBSCURED; - } else if (windowInfos.isWindowObscured(targetWindow)) { + } else if (mWindowInfos.isWindowObscured(targetWindow)) { targetFlags |= InputTarget::Flags::WINDOW_IS_PARTIALLY_OBSCURED; } return targetFlags; @@ -7500,15 +7469,14 @@ void InputDispatcher::DispatcherTouchState::clear() { void InputDispatcher::DispatcherTouchState::saveTouchStateForMotionEntry( const android::inputdispatcher::MotionEntry& entry, - android::inputdispatcher::TouchState&& touchState, - const DispatcherWindowInfo& windowInfos) { + android::inputdispatcher::TouchState&& touchState) { if (touchState.windows.empty()) { - eraseTouchStateForMotionEntry(entry, windowInfos); + eraseTouchStateForMotionEntry(entry); return; } if (InputFlags::connectedDisplaysCursorEnabled() && isMouseOrTouchpad(entry.source)) { - mCursorStateByDisplay[windowInfos.getPrimaryDisplayId(entry.displayId)] = + mCursorStateByDisplay[mWindowInfos.getPrimaryDisplayId(entry.displayId)] = std::move(touchState); } else { mTouchStatesByDisplay[entry.displayId] = std::move(touchState); @@ -7516,21 +7484,19 @@ void InputDispatcher::DispatcherTouchState::saveTouchStateForMotionEntry( } void InputDispatcher::DispatcherTouchState::eraseTouchStateForMotionEntry( - const android::inputdispatcher::MotionEntry& entry, - const DispatcherWindowInfo& windowInfos) { + const android::inputdispatcher::MotionEntry& entry) { if (InputFlags::connectedDisplaysCursorEnabled() && isMouseOrTouchpad(entry.source)) { - mCursorStateByDisplay.erase(windowInfos.getPrimaryDisplayId(entry.displayId)); + mCursorStateByDisplay.erase(mWindowInfos.getPrimaryDisplayId(entry.displayId)); } else { mTouchStatesByDisplay.erase(entry.displayId); } } const TouchState* InputDispatcher::DispatcherTouchState::getTouchStateForMotionEntry( - const android::inputdispatcher::MotionEntry& entry, - const DispatcherWindowInfo& windowInfos) const { + const android::inputdispatcher::MotionEntry& entry) const { if (InputFlags::connectedDisplaysCursorEnabled() && isMouseOrTouchpad(entry.source)) { auto touchStateIt = - mCursorStateByDisplay.find(windowInfos.getPrimaryDisplayId(entry.displayId)); + mCursorStateByDisplay.find(mWindowInfos.getPrimaryDisplayId(entry.displayId)); if (touchStateIt != mCursorStateByDisplay.end()) { return &touchStateIt->second; } diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h index 7e8e1426a0..4b4996dbca 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.h +++ b/services/inputflinger/dispatcher/InputDispatcher.h @@ -380,21 +380,20 @@ private: const ftl::Flags<InputTarget::Flags> targetFlags; }; - static void addPointerWindowTarget(const sp<android::gui::WindowInfoHandle>& windowHandle, - InputTarget::DispatchMode dispatchMode, - ftl::Flags<InputTarget::Flags> targetFlags, - std::bitset<MAX_POINTER_ID + 1> pointerIds, - std::optional<nsecs_t> firstDownTimeInTarget, - std::optional<ui::LogicalDisplayId> pointerDisplayId, - const ConnectionManager& connections, - const DispatcherWindowInfo& windowInfos, - std::function<void()> dump, - std::vector<InputTarget>& inputTargets); + DispatcherTouchState(const DispatcherWindowInfo& windowInfos, + const ConnectionManager& connections); + + void addPointerWindowTarget(const sp<android::gui::WindowInfoHandle>& windowHandle, + InputTarget::DispatchMode dispatchMode, + ftl::Flags<InputTarget::Flags> targetFlags, + std::bitset<MAX_POINTER_ID + 1> pointerIds, + std::optional<nsecs_t> firstDownTimeInTarget, + std::optional<ui::LogicalDisplayId> pointerDisplayId, + std::function<void()> dump, + std::vector<InputTarget>& inputTargets); base::Result<std::vector<InputTarget>, android::os::InputEventInjectionResult> findTouchedWindowTargets(nsecs_t currentTime, const MotionEntry& entry, - const ConnectionManager& connections, - const DispatcherWindowInfo& windowInfos, const sp<android::gui::WindowInfoHandle> dragWindow, std::function<void(const MotionEntry&)> addDragEvent, std::function<void()> dump); @@ -421,8 +420,7 @@ private: // Updates the touchState for display from WindowInfo, // returns list of CancellationArgs for every cancelled touch - std::list<CancellationArgs> updateFromWindowInfo(ui::LogicalDisplayId displayId, - const DispatcherWindowInfo& windowInfos); + std::list<CancellationArgs> updateFromWindowInfo(ui::LogicalDisplayId displayId); void removeAllPointersForDevice(DeviceId deviceId); @@ -431,9 +429,7 @@ private: std::optional< std::tuple<sp<gui::WindowInfoHandle>, DeviceId, std::vector<PointerProperties>, std::list<CancellationArgs>, std::list<PointerDownArgs>>> - transferTouchGesture(const sp<IBinder>& fromToken, const sp<IBinder>& toToken, - const DispatcherWindowInfo& windowInfos, - const ConnectionManager& connections); + transferTouchGesture(const sp<IBinder>& fromToken, const sp<IBinder>& toToken); base::Result<std::list<CancellationArgs>, status_t> pilferPointers( const sp<IBinder>& token, const Connection& requestingConnection); @@ -474,40 +470,31 @@ private: const sp<gui::WindowInfoHandle> toWindowHandle, TouchState& state, DeviceId deviceId, const std::vector<PointerProperties>& pointers, ftl::Flags<InputTarget::Flags> oldTargetFlags, - ftl::Flags<InputTarget::Flags> newTargetFlags, - const DispatcherWindowInfo& windowInfos, const ConnectionManager& connections); + ftl::Flags<InputTarget::Flags> newTargetFlags); - void saveTouchStateForMotionEntry(const MotionEntry& entry, TouchState&& touchState, - const DispatcherWindowInfo& windowInfos); + void saveTouchStateForMotionEntry(const MotionEntry& entry, TouchState&& touchState); - void eraseTouchStateForMotionEntry(const MotionEntry& entry, - const DispatcherWindowInfo& windowInfos); + void eraseTouchStateForMotionEntry(const MotionEntry& entry); const TouchState* getTouchStateForMotionEntry( - const android::inputdispatcher::MotionEntry& entry, - const DispatcherWindowInfo& windowInfos) const; + const android::inputdispatcher::MotionEntry& entry) const; bool canWindowReceiveMotion(const sp<gui::WindowInfoHandle>& window, - const MotionEntry& motionEntry, - const ConnectionManager& connections, - const DispatcherWindowInfo& windowInfos) const; + const MotionEntry& motionEntry) const; // Return true if stylus is currently down anywhere on the specified display, // and false otherwise. bool isStylusActiveInDisplay(ui::LogicalDisplayId displayId) const; - static std::list<CancellationArgs> eraseRemovedWindowsFromWindowInfo( - TouchState& state, ui::LogicalDisplayId displayId, - const DispatcherWindowInfo& windowInfos); + std::list<CancellationArgs> eraseRemovedWindowsFromWindowInfo( + TouchState& state, ui::LogicalDisplayId displayId); - static std::list<CancellationArgs> updateHoveringStateFromWindowInfo( - TouchState& state, ui::LogicalDisplayId displayId, - const DispatcherWindowInfo& windowInfos); + std::list<CancellationArgs> updateHoveringStateFromWindowInfo( + TouchState& state, ui::LogicalDisplayId displayId); - static std::vector<InputTarget> findOutsideTargets( - ui::LogicalDisplayId displayId, const sp<gui::WindowInfoHandle>& touchedWindow, - int32_t pointerId, const ConnectionManager& connections, - const DispatcherWindowInfo& windowInfos, std::function<void()> dump); + std::vector<InputTarget> findOutsideTargets(ui::LogicalDisplayId displayId, + const sp<gui::WindowInfoHandle>& touchedWindow, + int32_t pointerId, std::function<void()> dump); /** * Slip the wallpaper touch if necessary. @@ -522,18 +509,18 @@ private: * @param targets the current targets to add the walpaper ones to * @param eventTime the new downTime for the wallpaper target */ - static void slipWallpaperTouch(ftl::Flags<InputTarget::Flags> targetFlags, - const sp<android::gui::WindowInfoHandle>& oldWindowHandle, - const sp<android::gui::WindowInfoHandle>& newWindowHandle, - TouchState& state, const MotionEntry& entry, - std::vector<InputTarget>& targets, - const ConnectionManager& connections, - const DispatcherWindowInfo& windowInfos, - std::function<void()> dump); - - static ftl::Flags<InputTarget::Flags> getTargetFlags( + void slipWallpaperTouch(ftl::Flags<InputTarget::Flags> targetFlags, + const sp<android::gui::WindowInfoHandle>& oldWindowHandle, + const sp<android::gui::WindowInfoHandle>& newWindowHandle, + TouchState& state, const MotionEntry& entry, + std::vector<InputTarget>& targets, std::function<void()> dump); + + ftl::Flags<InputTarget::Flags> getTargetFlags( const sp<android::gui::WindowInfoHandle>& targetWindow, vec2 targetPosition, - bool isSplit, const DispatcherWindowInfo& windowInfos); + bool isSplit); + + const DispatcherWindowInfo& mWindowInfos; + const ConnectionManager& mConnectionManager; }; DispatcherTouchState mTouchStates GUARDED_BY(mLock); diff --git a/services/inputflinger/dispatcher/InputState.cpp b/services/inputflinger/dispatcher/InputState.cpp index d21c4d7596..782a54f09e 100644 --- a/services/inputflinger/dispatcher/InputState.cpp +++ b/services/inputflinger/dispatcher/InputState.cpp @@ -15,6 +15,7 @@ */ #include "DebugConfig.h" +#include "input/Input.h" #include "input/InputDevice.h" #include "input/InputFlags.h" @@ -25,17 +26,6 @@ namespace android::inputdispatcher { -namespace { - -bool isMouseOrTouchpad(uint32_t sources) { - // Check if this is a mouse or touchpad, but not a drawing tablet. - return isFromSource(sources, AINPUT_SOURCE_MOUSE_RELATIVE) || - (isFromSource(sources, AINPUT_SOURCE_MOUSE) && - !isFromSource(sources, AINPUT_SOURCE_STYLUS)); -} - -} // namespace - InputState::InputState(const IdGenerator& idGenerator) : mIdGenerator(idGenerator) {} InputState::~InputState() {} diff --git a/services/inputflinger/reader/mapper/SlopController.cpp b/services/inputflinger/reader/mapper/SlopController.cpp index 9ec02a6f86..d55df511e1 100644 --- a/services/inputflinger/reader/mapper/SlopController.cpp +++ b/services/inputflinger/reader/mapper/SlopController.cpp @@ -54,13 +54,13 @@ float SlopController::consumeEvent(nsecs_t eventTimeNanos, float value) { mCumulativeValue += value; if (abs(mCumulativeValue) >= mSlopThreshold) { - ALOGD("SlopController: did not drop event with value .%3f", value); + ALOGD("SlopController: did not drop event with value %.3f", value); mHasSlopBeenMet = true; // Return the amount of value that exceeds the slop. return signOf(value) * (abs(mCumulativeValue) - mSlopThreshold); } - ALOGD("SlopController: dropping event with value .%3f", value); + ALOGD("SlopController: dropping event with value %.3f", value); return 0; } diff --git a/vulkan/tests/Android.bp b/vulkan/tests/Android.bp new file mode 100644 index 0000000000..551d9b753c --- /dev/null +++ b/vulkan/tests/Android.bp @@ -0,0 +1,56 @@ +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + +cc_test { + name: "libvulkan_test", + test_suites: ["general-tests"], + + srcs: [ + "libvulkan_test.cpp", + ], + + strip: { + none: true, + }, + + cflags: [ + "-DVK_USE_PLATFORM_ANDROID_KHR", + "-Wall", + "-Werror", + ], + + header_libs: [ + "hwvulkan_headers", + "vulkan_headers", + ], + + cppflags: [ + "-Wno-c++98-compat-pedantic", + "-Wno-c99-extensions", + "-Wno-exit-time-destructors", + "-Wno-float-equal", + "-Wno-global-constructors", + "-Wno-zero-length-array", + ], + + shared_libs: [ + "libbase", + "libgraphicsenv", + "liblog", + "libmediandk", + "libvulkan", + ], + + static_libs: [ + "libgmock", + "libgtest", + "liblog", + ], + +} diff --git a/vulkan/tests/README.md b/vulkan/tests/README.md new file mode 100644 index 0000000000..3c9b66cee5 --- /dev/null +++ b/vulkan/tests/README.md @@ -0,0 +1,24 @@ +#libvulkan_test + +This binary contains the unit tests for testing libvulkan (The Vulkan Loader). + +These tests rely on the underlying GPU driver to be able to successfully create a valid +swapchain. These tests are design to run on an Android emulator to give us a consistent GPU +driver to test against. YMMV when running this on a physical device with an arbitrary GPU +driver. + +To run these tests run: +``` +atest libvulkan_test +``` + +If using an acloud device the full command list for the root of a freshly cloned repo would be: +``` +source build/envsetup.sh +lunch aosp_cf_x86_64_phone-trunk_staging-eng +m +acloud create --local-image +atest libvulkan_test +``` + + diff --git a/vulkan/tests/libvulkan_test.cpp b/vulkan/tests/libvulkan_test.cpp new file mode 100644 index 0000000000..128d640eeb --- /dev/null +++ b/vulkan/tests/libvulkan_test.cpp @@ -0,0 +1,360 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <android/log.h> +#include <gmock/gmock.h> +#include <gtest/gtest.h> +#include <media/NdkImageReader.h> +#include <vulkan/vulkan.h> + +#define LOGI(...) \ + __android_log_print(ANDROID_LOG_INFO, "libvulkan_test", __VA_ARGS__) +#define LOGE(...) \ + __android_log_print(ANDROID_LOG_ERROR, "libvulkan_test", __VA_ARGS__) + +#define VK_CHECK(result) ASSERT_EQ(VK_SUCCESS, result) + +namespace android { + +class AImageReaderVulkanSwapchainTest : public ::testing::Test { + public: + AImageReaderVulkanSwapchainTest() {} + + AImageReader* mReader = nullptr; + ANativeWindow* mWindow = nullptr; + VkInstance mVkInstance = VK_NULL_HANDLE; + VkPhysicalDevice mPhysicalDev = VK_NULL_HANDLE; + VkDevice mDevice = VK_NULL_HANDLE; + VkSurfaceKHR mSurface = VK_NULL_HANDLE; + VkQueue mPresentQueue = VK_NULL_HANDLE; + uint32_t mPresentQueueFamily = UINT32_MAX; + VkSwapchainKHR mSwapchain = VK_NULL_HANDLE; + + void SetUp() override {} + + void TearDown() override {} + + // ------------------------------------------------------ + // Helper methods + // ------------------------------------------------------ + + void createVulkanInstance(std::vector<const char*>& layers) { + const char* extensions[] = { + VK_KHR_SURFACE_EXTENSION_NAME, + VK_KHR_ANDROID_SURFACE_EXTENSION_NAME, + VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, + }; + + VkApplicationInfo appInfo{}; + appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; + appInfo.pApplicationName = "AImageReader Vulkan Swapchain Test"; + appInfo.applicationVersion = 1; + appInfo.pEngineName = "TestEngine"; + appInfo.engineVersion = 1; + appInfo.apiVersion = VK_API_VERSION_1_0; + + VkInstanceCreateInfo instInfo{}; + instInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; + instInfo.pApplicationInfo = &appInfo; + instInfo.enabledExtensionCount = + sizeof(extensions) / sizeof(extensions[0]); + instInfo.ppEnabledExtensionNames = extensions; + instInfo.enabledLayerCount = layers.size(); + instInfo.ppEnabledLayerNames = layers.data(); + VkResult res = vkCreateInstance(&instInfo, nullptr, &mVkInstance); + VK_CHECK(res); + LOGE("Vulkan instance created"); + } + + void createAImageReader(int width, int height, int format, int maxImages) { + media_status_t status = + AImageReader_new(width, height, format, maxImages, &mReader); + ASSERT_EQ(AMEDIA_OK, status) << "Failed to create AImageReader"; + ASSERT_NE(nullptr, mReader) << "AImageReader is null"; + + // Optionally set a listener + AImageReader_ImageListener listener{}; + listener.context = this; + listener.onImageAvailable = + &AImageReaderVulkanSwapchainTest::onImageAvailable; + AImageReader_setImageListener(mReader, &listener); + + LOGI("AImageReader created with %dx%d, format=%d", width, height, + format); + } + + void getANativeWindowFromReader() { + ASSERT_NE(nullptr, mReader); + + media_status_t status = AImageReader_getWindow(mReader, &mWindow); + ASSERT_EQ(AMEDIA_OK, status) + << "Failed to get ANativeWindow from AImageReader"; + ASSERT_NE(nullptr, mWindow) << "ANativeWindow is null"; + LOGI("ANativeWindow obtained from AImageReader"); + } + + void createVulkanSurface() { + ASSERT_NE((VkInstance)VK_NULL_HANDLE, mVkInstance); + ASSERT_NE((ANativeWindow*)nullptr, mWindow); + + VkAndroidSurfaceCreateInfoKHR surfaceCreateInfo{}; + surfaceCreateInfo.sType = + VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR; + surfaceCreateInfo.window = mWindow; + + VkResult res = vkCreateAndroidSurfaceKHR( + mVkInstance, &surfaceCreateInfo, nullptr, &mSurface); + VK_CHECK(res); + LOGI("Vulkan surface created from ANativeWindow"); + } + + void pickPhysicalDeviceAndQueueFamily() { + ASSERT_NE((VkInstance)VK_NULL_HANDLE, mVkInstance); + + uint32_t deviceCount = 0; + vkEnumeratePhysicalDevices(mVkInstance, &deviceCount, nullptr); + ASSERT_GT(deviceCount, 0U) << "No Vulkan physical devices found!"; + + std::vector<VkPhysicalDevice> devices(deviceCount); + vkEnumeratePhysicalDevices(mVkInstance, &deviceCount, devices.data()); + + for (auto& dev : devices) { + uint32_t queueFamilyCount = 0; + vkGetPhysicalDeviceQueueFamilyProperties(dev, &queueFamilyCount, + nullptr); + std::vector<VkQueueFamilyProperties> queueProps(queueFamilyCount); + vkGetPhysicalDeviceQueueFamilyProperties(dev, &queueFamilyCount, + queueProps.data()); + + for (uint32_t i = 0; i < queueFamilyCount; i++) { + VkBool32 support = VK_FALSE; + vkGetPhysicalDeviceSurfaceSupportKHR(dev, i, mSurface, + &support); + if (support == VK_TRUE) { + // Found a queue family that can present + mPhysicalDev = dev; + mPresentQueueFamily = i; + + LOGI( + "Physical device found with queue family %u supporting " + "present", + i); + return; + } + } + } + + FAIL() + << "No physical device found that supports present to the surface!"; + } + + void createDeviceAndGetQueue(std::vector<const char*>& layers) { + ASSERT_NE((void*)VK_NULL_HANDLE, mPhysicalDev); + ASSERT_NE(UINT32_MAX, mPresentQueueFamily); + + float queuePriority = 1.0f; + VkDeviceQueueCreateInfo queueInfo{}; + queueInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; + queueInfo.queueFamilyIndex = mPresentQueueFamily; + queueInfo.queueCount = 1; + queueInfo.pQueuePriorities = &queuePriority; + + VkDeviceCreateInfo deviceInfo{}; + deviceInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; + deviceInfo.queueCreateInfoCount = 1; + deviceInfo.pQueueCreateInfos = &queueInfo; + deviceInfo.enabledLayerCount = layers.size(); + deviceInfo.ppEnabledLayerNames = layers.data(); + + const char* extensions[] = { + VK_KHR_SWAPCHAIN_EXTENSION_NAME, + }; + deviceInfo.enabledExtensionCount = + sizeof(extensions) / sizeof(extensions[0]); + deviceInfo.ppEnabledExtensionNames = extensions; + + VkResult res = + vkCreateDevice(mPhysicalDev, &deviceInfo, nullptr, &mDevice); + VK_CHECK(res); + LOGI("Logical device created"); + + vkGetDeviceQueue(mDevice, mPresentQueueFamily, 0, &mPresentQueue); + ASSERT_NE((VkQueue)VK_NULL_HANDLE, mPresentQueue); + LOGI("Acquired present-capable queue"); + } + + void createSwapchain() { + ASSERT_NE((VkDevice)VK_NULL_HANDLE, mDevice); + ASSERT_NE((VkSurfaceKHR)VK_NULL_HANDLE, mSurface); + + VkSurfaceCapabilitiesKHR surfaceCaps{}; + VK_CHECK(vkGetPhysicalDeviceSurfaceCapabilitiesKHR( + mPhysicalDev, mSurface, &surfaceCaps)); + + uint32_t formatCount = 0; + vkGetPhysicalDeviceSurfaceFormatsKHR(mPhysicalDev, mSurface, + &formatCount, nullptr); + ASSERT_GT(formatCount, 0U); + std::vector<VkSurfaceFormatKHR> formats(formatCount); + vkGetPhysicalDeviceSurfaceFormatsKHR(mPhysicalDev, mSurface, + &formatCount, formats.data()); + + VkSurfaceFormatKHR chosenFormat = formats[0]; + LOGI("Chosen surface format: %d", chosenFormat.format); + + uint32_t presentModeCount = 0; + vkGetPhysicalDeviceSurfacePresentModesKHR(mPhysicalDev, mSurface, + &presentModeCount, nullptr); + ASSERT_GT(presentModeCount, 0U); + std::vector<VkPresentModeKHR> presentModes(presentModeCount); + vkGetPhysicalDeviceSurfacePresentModesKHR( + mPhysicalDev, mSurface, &presentModeCount, presentModes.data()); + + VkPresentModeKHR chosenPresentMode = VK_PRESENT_MODE_FIFO_KHR; + for (auto mode : presentModes) { + if (mode == VK_PRESENT_MODE_FIFO_KHR) { + chosenPresentMode = mode; + break; + } + } + LOGI("Chosen present mode: %d", chosenPresentMode); + + VkExtent2D swapchainExtent{}; + if (surfaceCaps.currentExtent.width == 0xFFFFFFFF) { + swapchainExtent.width = 640; // fallback + swapchainExtent.height = 480; // fallback + } else { + swapchainExtent = surfaceCaps.currentExtent; + } + LOGI("Swapchain extent: %d x %d", swapchainExtent.width, + swapchainExtent.height); + + uint32_t desiredImageCount = surfaceCaps.minImageCount + 1; + if (surfaceCaps.maxImageCount > 0 && + desiredImageCount > surfaceCaps.maxImageCount) { + desiredImageCount = surfaceCaps.maxImageCount; + } + + VkSwapchainCreateInfoKHR swapchainInfo{}; + swapchainInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; + swapchainInfo.surface = mSurface; + swapchainInfo.minImageCount = desiredImageCount; + swapchainInfo.imageFormat = chosenFormat.format; + swapchainInfo.imageColorSpace = chosenFormat.colorSpace; + swapchainInfo.imageExtent = swapchainExtent; + swapchainInfo.imageArrayLayers = 1; + swapchainInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | + VK_IMAGE_USAGE_TRANSFER_SRC_BIT; + swapchainInfo.preTransform = surfaceCaps.currentTransform; + swapchainInfo.compositeAlpha = VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR; + swapchainInfo.presentMode = chosenPresentMode; + swapchainInfo.clipped = VK_TRUE; + swapchainInfo.oldSwapchain = VK_NULL_HANDLE; + + uint32_t queueFamilyIndices[] = {mPresentQueueFamily}; + swapchainInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; + swapchainInfo.queueFamilyIndexCount = 1; + swapchainInfo.pQueueFamilyIndices = queueFamilyIndices; + + VkResult res = + vkCreateSwapchainKHR(mDevice, &swapchainInfo, nullptr, &mSwapchain); + VK_CHECK(res); + LOGI("Swapchain created successfully"); + + uint32_t swapchainImageCount = 0; + vkGetSwapchainImagesKHR(mDevice, mSwapchain, &swapchainImageCount, + nullptr); + std::vector<VkImage> swapchainImages(swapchainImageCount); + vkGetSwapchainImagesKHR(mDevice, mSwapchain, &swapchainImageCount, + swapchainImages.data()); + + LOGI("Swapchain has %u images", swapchainImageCount); + } + + // Image available callback (AImageReader) + static void onImageAvailable(void*, AImageReader* reader) { + LOGI("onImageAvailable callback triggered"); + AImage* image = nullptr; + media_status_t status = AImageReader_acquireLatestImage(reader, &image); + if (status != AMEDIA_OK || !image) { + LOGE("Failed to acquire latest image"); + return; + } + AImage_delete(image); + LOGI("Released acquired image"); + } + + void cleanUpSwapchainForTest() { + if (mSwapchain != VK_NULL_HANDLE) { + vkDestroySwapchainKHR(mDevice, mSwapchain, nullptr); + mSwapchain = VK_NULL_HANDLE; + } + if (mDevice != VK_NULL_HANDLE) { + vkDestroyDevice(mDevice, nullptr); + mDevice = VK_NULL_HANDLE; + } + if (mSurface != VK_NULL_HANDLE) { + vkDestroySurfaceKHR(mVkInstance, mSurface, nullptr); + mSurface = VK_NULL_HANDLE; + } + if (mVkInstance != VK_NULL_HANDLE) { + vkDestroyInstance(mVkInstance, nullptr); + mVkInstance = VK_NULL_HANDLE; + } + if (mReader) { + // AImageReader_delete(mReader); + mReader = nullptr; + } + // Note: The ANativeWindow from AImageReader is implicitly + // managed by the reader, so we don't explicitly delete it. + mWindow = nullptr; + } + + void buildSwapchianForTest(std::vector<const char*>& instanceLayers, + std::vector<const char*>& deviceLayers) { + createVulkanInstance(instanceLayers); + + // the "atest libvulkan_test" command will execute this test as a binary + // (not apk) on the device. Consequently we can't render to the screen + // and need to work around this by using AImageReader* + createAImageReader(640, 480, AIMAGE_FORMAT_PRIVATE, 3); + getANativeWindowFromReader(); + createVulkanSurface(); + pickPhysicalDeviceAndQueueFamily(); + + createDeviceAndGetQueue(deviceLayers); + createSwapchain(); + } +}; + +TEST_F(AImageReaderVulkanSwapchainTest, TestHelperMethods) { + // Verify that the basic plumbing/helper functions of these tests is + // working. This doesn't directly test any of the layer code. It only + // verifies that we can successfully create a swapchain with an AImageReader + + std::vector<const char*> instanceLayers; + std::vector<const char*> deviceLayers; + buildSwapchianForTest(deviceLayers, instanceLayers); + + ASSERT_NE(mVkInstance, (VkInstance)VK_NULL_HANDLE); + ASSERT_NE(mPhysicalDev, (VkPhysicalDevice)VK_NULL_HANDLE); + ASSERT_NE(mDevice, (VkDevice)VK_NULL_HANDLE); + ASSERT_NE(mSurface, (VkSurfaceKHR)VK_NULL_HANDLE); + ASSERT_NE(mSwapchain, (VkSwapchainKHR)VK_NULL_HANDLE); + cleanUpSwapchainForTest(); +} + +} // namespace android |