-
Notifications
You must be signed in to change notification settings - Fork 6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Impeller] A toolkit for managed handles to Android NDK vended objects. #51334
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we intented to (eventually) replace the existing AHardwareBuffer and NDK wrappers used in the android embedder with this entirely?
// Zero sized hardware buffers cannot be allocated. | ||
desc.size = size.Max(ISize{1u, 1u}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems like it should be an error state (std::option or statusOr) instead of returning a size that wasn't requested.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I documented that restriction in the headerdoc with a large warning sign so it shows up more prominently. It took me some trial and error to understand that this was the cause of buffers not being allocatable and the Android API doesn't say why a size wasn't allocatable. So making the callers figure this out was a pretty poor experience. Also, we do the same clamping in other spots (like the pbuffer sizes for offscreen GLES surfaces). So it seemed like in keeping with the theme. There are IsAllocatable checks either way though.
/// @see Vulkan Format: VK_FORMAT_R8G8B8A8_UNORM | ||
/// @see OpenGL ES Format: GL_RGBA8 | ||
/// | ||
/// Why have many format when one format do trick? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
😆
/// the descriptor after this call is made to determine the size | ||
/// of the allocated hardware buffer. | ||
/// | ||
/// @param[in] size The size. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note size requirements here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I just put the size restrictions in the @warning
block right above. Hoping to draw attention to it. But that was obviously not enough. I'll add a note reiterating the warning.
bool IsValid() const; | ||
|
||
//---------------------------------------------------------------------------- | ||
/// @return The current of the native window. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
current size?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
/// | ||
/// This wrapper is only available on Android API 29 and above. | ||
/// | ||
class SurfaceControl { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does the surface control have any threading restrictions? In general, if we're aware of any threading restrictions for parts of these APIs it would be good to note them.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am not aware of any threading restrictions on any of the handle types. The only major quirk is the transaction completion callback being made on a system managed thread (presumably a binder thread). I've documented that and also the lifecycle implications to the transaction because of it in the headerdoc comment for it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I audited all calls, and beyond the completion callback that I have already documented, there is little guidance from the Android docs about the threading restrictions of any of the calls. I'm just going to be safe and call these as needing to be externally synchronized.
// tests everywhere else. | ||
if (__builtin_available(android 29, *)) { | ||
} else { | ||
GTEST_SKIP() << "Platform too old for this test."; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Given that we just went through a fire drill where tests weren't actually running (because they failed unsafely) - how can we guarantee that we get a failure somewhere if we accidentally stop running this on API 29+ ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We have the same problem with the existing ndk_helpers_unittests.
We do, in fact, currently run emulators that will run this test, but we should probably patch ... something to fail if this test never runs at all anywhere.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should I just do a GTEST_FAIL instead?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
GTEST_FAIL SGTM
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We have infra that runs an API 28 emulator.
We should probably have a test that verifies we have sane/non-crashing behavior if you use this API below 29 though...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
runs an API 28 emulator...
So, I can't make this a fail right?
we have sane/non-crashing behavior if you use this API below 29 though
We are definitely missing a trick not using static analysis (like at-availability on iOS) for this. I spent a non-trivial amount of time the other day wiring it up. But I haven't been able to get it to work reliably with our toolchain. Something to consider in addition to just checking on all emulator versions.
|
||
namespace impeller::android::testing { | ||
|
||
class ToolkitAndroidTest : public ::testing::Test { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't know if you want to do this as a follow up, but related to Jonah's question:
The tests here don't have as much coverage as the ndk_helpers_unittests (specifcially, there aren't assertions that the API works and that we can allocate/destroy these objects or that the API symbols are correctly resolved). Maybe this will be good for a follow up patch, but consider porting those tests to this toolkit, deleting the FML versions, and porting the Android embedding to use this toolkit?
If that's not possible, I'd rather not land this in Impeller - I'm somewhat concerned about having more places that we do these lookups and introduce typos/untested code, especially since we just got that cleaned up.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If that's not possible, I'd rather not land this in Impeller - I'm somewhat concerned about having more places that we do these lookups and introduce typos/untested code, especially since we just got that cleaned up.
+1
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
API works and that we can allocate/destroy these objects.
CanCreateHardwareBuffer
for hardware buffers. CanApplySurfaceTransaction
for surface transactions. Same as the NDK helpers.
API symbols are correctly resolved.
CanCreateProcTable
. You'll only get a valid proc table if the API symbols are correctly resolved and the version checks pass. For the individual subcomponents, this is also checked with IsAvailableOnPlatform
.
The tests here don't have as much coverage.
I'm surprised by this statement. There are only two tests in NDK helpers related to anything in this patch. HardwareBuffer
and SurfaceTransaction
. The entire corpus is only 5 tests in total (unless I am missing something). The two tests I mentioned above more than cover the the assertions in NDK helpers.
I want to use the toolkit for everything and remove the NDK helpers after porting all existing tests. But, at least till I get to the choreographer, there isn't going to be anything to port as it should already be covered.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We seem to be missing coverage here of AHardwareBuffer_describe
, AHardwareBuffer_isSupported
, and AHardwareBuffer_getId
, which are needed by the current Android implementation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, but the toolkit has no ability to describe or get the ID of those objects yet. Once I work on adding those features get rid of NDK helpers, I can patch those in.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(Sorry, I did not mean to post this one! too many tabs open)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, but the toolkit has no ability to describe or get the ID of those objects yet. Once I work on adding those features get rid of NDK helpers, I can patch those in.
I would rather see either Impeller use the FML utilities until it's ready to replace them with something better, or the rest of the code base using new improved utilities with similar test coverage. Otherwise we're likely to end up in a state where we have multiple locations to do NDK related lookups with different available/missing test coverage ...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
All I want to do is to facilitate landing #51213. The ask on that patch was that it was too large and it should be split up. I have split it up into #51295, #51298, and this one. Two more patches are incoming after this to facilitate the request for smaller, more self-contained PRs.
I am on the hook for killing the FML utilities. I can kill the FML utilities in this patch if this gets us past the bikeshedding but it will make this patch bigger. Or, kill the FML utilities immediately after this lands if that seems more elegant.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ping @dnfield. Do you have a preference? Want to unblock this review ASAP.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would rather eithe rkill it in this patch or update the AHB swapchain patch to use the FML utilities.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we intented to (eventually) replace the existing AHardwareBuffer and NDK wrappers used in the android embedder with this entirely?
Yes, I was going to replace the few uses of the helpers immediately after landing the swapchain patch and get rid of the libAndroid stuff in FML.
/// the descriptor after this call is made to determine the size | ||
/// of the allocated hardware buffer. | ||
/// | ||
/// @param[in] size The size. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I just put the size restrictions in the @warning
block right above. Hoping to draw attention to it. But that was obviously not enough. I'll add a note reiterating the warning.
bool IsValid() const; | ||
|
||
//---------------------------------------------------------------------------- | ||
/// @return The current of the native window. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
// Zero sized hardware buffers cannot be allocated. | ||
desc.size = size.Max(ISize{1u, 1u}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I documented that restriction in the headerdoc with a large warning sign so it shows up more prominently. It took me some trial and error to understand that this was the cause of buffers not being allocatable and the Android API doesn't say why a size wasn't allocatable. So making the callers figure this out was a pretty poor experience. Also, we do the same clamping in other spots (like the pbuffer sizes for offscreen GLES surfaces). So it seemed like in keeping with the theme. There are IsAllocatable checks either way though.
/// | ||
/// This wrapper is only available on Android API 29 and above. | ||
/// | ||
class SurfaceControl { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am not aware of any threading restrictions on any of the handle types. The only major quirk is the transaction completion callback being made on a system managed thread (presumably a binder thread). I've documented that and also the lifecycle implications to the transaction because of it in the headerdoc comment for it.
/// | ||
/// This wrapper is only available on Android API 29 and above. | ||
/// | ||
class SurfaceControl { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I audited all calls, and beyond the completion callback that I have already documented, there is little guidance from the Android docs about the threading restrictions of any of the calls. I'm just going to be safe and call these as needing to be externally synchronized.
|
||
namespace impeller::android::testing { | ||
|
||
class ToolkitAndroidTest : public ::testing::Test { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
API works and that we can allocate/destroy these objects.
CanCreateHardwareBuffer
for hardware buffers. CanApplySurfaceTransaction
for surface transactions. Same as the NDK helpers.
API symbols are correctly resolved.
CanCreateProcTable
. You'll only get a valid proc table if the API symbols are correctly resolved and the version checks pass. For the individual subcomponents, this is also checked with IsAvailableOnPlatform
.
The tests here don't have as much coverage.
I'm surprised by this statement. There are only two tests in NDK helpers related to anything in this patch. HardwareBuffer
and SurfaceTransaction
. The entire corpus is only 5 tests in total (unless I am missing something). The two tests I mentioned above more than cover the the assertions in NDK helpers.
I want to use the toolkit for everything and remove the NDK helpers after porting all existing tests. But, at least till I get to the choreographer, there isn't going to be anything to port as it should already be covered.
// tests everywhere else. | ||
if (__builtin_available(android 29, *)) { | ||
} else { | ||
GTEST_SKIP() << "Platform too old for this test."; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should I just do a GTEST_FAIL instead?
I believe I have addressed all open questions. PTAL. Past this, there are two patches to actually add the ABH swapchain implemnetation, and migrate existing users of NDK helpers. Then John should be able to wire up the Chroeographer VSync IDs. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
okie dokie. Killing the FML utils in this patch. |
Only available on Android device API levels >= 29. Proc table is setup has versioning checks. All handles are type safe. Collection of handles takes into account cleanup tasks (like reparenting surface controls). The proc table contains code duplicated in ndk_helpers and I will remove that in favor of this in a subsequent patch. Part of flutter#51213 being chopped up.
ed8ba75
to
0f343f1
Compare
#define FOR_EACH_ANDROID_PROC(INVOKE) \ | ||
INVOKE(ATrace_isEnabled, 23) \ | ||
INVOKE(AChoreographer_getInstance, 24) \ | ||
INVOKE(AChoreographer_postFrameCallback, 24) \ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We must not use this if sizeof(uint64_t) != sizeof(long)
.
On 32 bit platforms we have to use the Java based API. But we still should try to resolve it on a 64 bit platform that is < API 29. I made the same mistake when migrating things to the NDKHelpers class :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(That's why the #if FML_ARCH_64BIT
guard was around this, or whatever it actually was)
Overall this LGTM, will approve once the guard is added back to prevent undesirable usage of |
Oh, was still tinkering on this before signing off for the day. I doubt this compiles right now. Will ping again in the morning after the fixups. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is good to go. PTAL. Some updates since the last review:
- The NDK helpers are gone and existing users migrated.
- The toolkit now has a choreographer that handles the Callback32/64 variants under the hood.
- The previous version of the toolkit had an extra layer of protection over just the dysym. It checked not just that the API was available, but also that the platform was modern enough per the documentation. At the time, I was worried that an API may have been available as a symbol in an unstable form on older Android versions. But the way to check the Android API level is itself 29. The NDK helpers also didn't have the extra checks I had in the proc table. I have now removed the extra checks in the toolkit too. I had no reason to doubt this way isn't fine. Just need to trust the platform more.
- Subsequently, the accessors to get the API level have also been removed.
} | ||
|
||
#if FML_ARCH_CPU_32_BITS | ||
// On 32-bit platforms, the nanosecond resolution timestamp causes overflow on |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@dnfield There was at least one contradictory comment in the thread you linked earlier about the non-Callback64 choreographer use on 32-bit platforms. This was my reading of the underlying issue. But please double check if I accurately described the issue.
To reiterate the intent; Use the Callback64 variant where available. And use the Callback32 variant only on 64-bit devices (and where available).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
SGTM
|
||
TEST_F(ToolkitAndroidTest, CanPostAndWaitForFrameCallbacks) { | ||
if ((true)) { | ||
GTEST_SKIP() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@dnfield @jonahwilliams This test will currently hang because the unit-test run as a naked binary don't get choreographer callbacks. I'll remove this skip once I have the APK based unit-tests harness we discussed yesterday.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM as long as CI is happy!
Reason for revert: Broke engine post-submit, see https://logs.chromium.org/logs/flutter/buildbucket/cr-buildbucket/8753367119442265873/+/u/test:_Android_Unit_Tests__API_28_/stdout. |
…ed objects. (#51334)" (#51457) Reverts: #51334 Initiated by: matanlurey Reason for reverting: Broke engine post-submit, see https://logs.chromium.org/logs/flutter/buildbucket/cr-buildbucket/8753367119442265873/+/u/test:_Android_Unit_Tests__API_28_/stdout. Original PR Author: chinmaygarde Reviewed By: {dnfield} This change reverts the following previous change: Only available on Android device API levels >= 29. Proc table is setup has versioning checks. All handles are type safe. Collection of handles takes into account cleanup tasks (like reparenting surface controls). The proc table contains code duplicated in ndk_helpers and I will remove that in favor of this in a subsequent patch. Part of #51213 being chopped up.
…145237) flutter/engine@c2fd533...ba1115c 2024-03-15 [email protected] Add more explicit logging (just to `stderr`) if a try-job detects an untriaged image (flutter/engine#51454) 2024-03-15 98614782+auto-submit[bot]@users.noreply.github.com Reverts "[Impeller] A toolkit for managed handles to Android NDK vended objects. (#51334)" (flutter/engine#51457) 2024-03-15 [email protected] [Impeller] A toolkit for managed handles to Android NDK vended objects. (flutter/engine#51334) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC [email protected],[email protected],[email protected] on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://issues.skia.org/issues/new?component=1389291&template=1850622 Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md
Only available on Android device API levels >= 29. Proc table is setup has versioning checks. All handles are type safe. Collection of handles takes into account cleanup tasks (like reparenting surface controls). The proc table contains code duplicated in ndk_helpers and I will remove that in favor of this in a subsequent patch.
Part of #51213 being chopped up.