Skip to content
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

hardware_buffer_format: Add catch-all variant #407

Merged

Conversation

spencercw
Copy link
Contributor

Hardware buffers can have private formats which don't appear in the NDK header. Add a catch-all variant to avoid panicking in HardwareBuffer::describe().

@spencercw spencercw force-pushed the hardware-buffer-format-catchall branch from d170da5 to 23c8576 Compare July 5, 2023 11:04
@spencercw
Copy link
Contributor Author

The MSRV issue is a bit unfortunate. Seems explicit discriminants on enums with fields is only supported as of Rust 1.66 (Dec 2022). Is it ok to bump the MSRV?

@spencercw spencercw force-pushed the hardware-buffer-format-catchall branch from 23c8576 to ef887d8 Compare July 5, 2023 11:09
@MarijnS95
Copy link
Member

I'd rather panic and extend the crate in this case. Is this a real problem right now or are you anticipating a future problem?

@spencercw
Copy link
Contributor Author

This is a real problem right now. I am creating an ImageReader with ImageFormat::PRIVATE and HardwareBufferUsage::GPU_SAMPLED_IMAGE, which I then feed in with decoded video frames from MediaCodec. I then acquire images from the ImageReader and get the HardwareBuffer from those images. The format returned by calling describe on the HardwareBuffer varies depending on the device. For example, on a Samsung device the format is 261. On a Xiaomi device it is 2141391878. I'm not really interested in the format here, but I need the other fields in HardwareBufferDesc, which I can't currently get because it panics trying to handle the format.

@MarijnS95
Copy link
Member

MarijnS95 commented Jul 18, 2023

Sure, then we need an Other (rename to Unknown?) case as we also cannot return a Result to support your "I want HardwareBufferDesc but don't care about the specific format" case.

I'll think about the MSRV bump for a bit: this'll be used by winit and we have to keep them into account as the upper bound of our MSRV. It's still as 1.64 and I don't know if there are plans to bump it to >= 1.66. CC @kchibisov.

@MarijnS95
Copy link
Member

MarijnS95 commented Jul 18, 2023

Seems explicit discriminants on enums with fields

Note also that this PR makes it impossible to use as u32 on the type. Perhaps we should just drop #[repr(u32)] then and not care about the size of the discriminant, as num_enum should generate this for us with IntoPrimitive. We might have to document that more clearly, though.

EDIT: On that note if IntoPrimitive just generates a match table in the end, we might not need the custom discriminants at all as long as we can instruct num_enum_derive to generate the right table.

@kchibisov
Copy link
Contributor

I'll think about the MSRV bump for a bit: this'll be used by winit and we have to keep them into account as the upper bound of our MSRV. It's still as 1.64 and I don't know if there are plans to bump it to >= 1.66. CC @kchibisov.

I think we're currently at 1.65 in some crates (GATs addition). The WGPU rust version is 1.65, so not sure about the bump yet.

@spencercw
Copy link
Contributor Author

#[repr(u32)] seems to be required by num-enum. Removing it elicits a 'Missing #[repr({Integer})] attribute' error.

The only way I can see to drop the discriminants would be to rely on the default numbering (i.e., first entry is 0, second is 1, etc). There are big gaps between the format values though so I don't think this is practical.

I don't mind sitting on this one for a while. Sounds like a 1.66 MSRV can't be too far off.

@MarijnS95
Copy link
Member

#[repr(u32)] seems to be required by num-enum. Removing it elicits a 'Missing #[repr({Integer})] attribute' error.

Yeah, because it needs these discriminants to generate a match table for conversion... Perhaps it could even discard the discriminants after it's done, so that the type relies on default Rust numbering and From/IntoPrimitive convert from and to NDK numbering. That'd get rid of the MSRV issue.

(Otherwise the implementation for IntoPrimitive is nothing more as self as u32... yet it works even when one or more enum variants have fields)

@spencercw
Copy link
Contributor Author

Sounds like a reasonable idea for num-enum, but it's not something I particularly have time to get into at the moment. One day I might learn how to use procedural macros, but right now they are just black magic to me.

@MarijnS95
Copy link
Member

It's more so that I don't have a clear overview of what's needed now, but we might as well ditch the macros and implement From conversions manually (both ways) without setting repr(u32) nor the discriminants. This is done for other enums in the ndk crate as well.

@spencercw
Copy link
Contributor Author

That could work, although unless I'm missing something obvious, I can't see any custom From/Into implementations in the repository.

@spencercw spencercw force-pushed the hardware-buffer-format-catchall branch from ef887d8 to 5ddde16 Compare July 19, 2023 14:20
@spencercw
Copy link
Contributor Author

Added manual From implementations.

@MarijnS95
Copy link
Member

I can't see any custom From/Into implementations in the repository.

Turns out it was a custom function instead (otherwise it'd have to be a TryFrom/TryInto), but check out MediaStatus/MediaError.

Note that AHardwareBuffer_Format, just like the media_status_t demonstrated there, derives PartialEq, Eq which allows you to match on it without x if x == ffi::Type::VAL.0 as long as it is wrapped in AHardwareBuffer_Format. Or perhaps better: implement the From directly for AHardwareBuffer_Format so that it is clear what the native type is "supposed to be".

@spencercw spencercw force-pushed the hardware-buffer-format-catchall branch from 5ddde16 to 382c717 Compare July 25, 2023 12:47
@spencercw
Copy link
Contributor Author

Ok that makes sense. I've applied those changes.

@MarijnS95 MarijnS95 added the impact: breaking API/ABI-breaking change label Jul 25, 2023
ndk/src/native_window.rs Outdated Show resolved Hide resolved
Copy link
Member

@MarijnS95 MarijnS95 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bit unfortunate that we cannot use enum discriminants anymore (and have manually write out the conversion both ways...), but as discussed that's not really possible unless we add yet another wrapper type (or getter) to struct HardwareBufferDesc to represent unknown variants (besides more actively updating this enumeration with unreleased constants...).

Asking @rib for another review.

@MarijnS95 MarijnS95 requested a review from rib July 25, 2023 13:27
@spencercw spencercw force-pushed the hardware-buffer-format-catchall branch from 382c717 to 69af199 Compare July 25, 2023 13:29
ndk/CHANGELOG.md Outdated Show resolved Hide resolved
Hardware buffers can have private formats which don't appear in the NDK
header. Add a catch-all variant to avoid panicking in
`HardwareBuffer::describe()`.
@spencercw spencercw force-pushed the hardware-buffer-format-catchall branch from 69af199 to 74d06f3 Compare July 25, 2023 13:42
@MarijnS95 MarijnS95 merged commit 563089a into rust-mobile:master Jul 26, 2023
@MarijnS95 MarijnS95 mentioned this pull request Aug 26, 2023
MarijnS95 added a commit that referenced this pull request Sep 13, 2023
It is older than 6 months and now required for the `toml_edit`
dependency (used by `num_enum_derive`).  At the same time `num_enum`
relies on arbitrary enum discriminants (for discriminated enums
with tuple/struct variants) introduced by Rust 1.66 in order to
implement `#[num_enum(catch_all)]`.  This feature comes in use to
replace the manual `match` blocks when implementing conversions for
`HardwareBufferFormat` when also having an `Unknown(u32)` to catch
valid private/vendor values that won't ever be described inside the
NDK.  This change effectively reverts #407 to its initial state, where a
`catch_all` implementation was used.

For the latter the intent is however to use this feature sparingly.
In most APIs new values are few and far between, so treating these as
an `Err` via `TryFromPrimitive` is desired to provoke upstream issue
reports and quick turnaround on new values.  Same for `enum`s that are
used to pass values into functions: it is desired to only pass known
values (by this `ndk` crate) into those, anything else should similarly
be reported and added upstream.  In these cases a `#[non_exhaustive]`
allows us to do so with a tiny non-breaking patch release.
MarijnS95 added a commit that referenced this pull request Sep 13, 2023
It is older than 6 months and now required for the `toml_edit`
dependency (used by `num_enum_derive`).  At the same time `num_enum`
relies on arbitrary enum discriminants (for discriminated enums
with tuple/struct variants) introduced by Rust 1.66 in order to
implement `#[num_enum(catch_all)]`.  This feature comes in use to
replace the manual `match` blocks when implementing conversions for
`HardwareBufferFormat` when also having an `Unknown(u32)` to catch
valid private/vendor values that won't ever be described inside the
NDK.  This change effectively reverts #407 to its initial state, where a
`catch_all` implementation was used.

For the latter the intent is however to use this feature sparingly.
In most APIs new values are few and far between, so treating these as
an `Err` via `TryFromPrimitive` is desired to provoke upstream issue
reports and quick turnaround on new values.  Same for `enum`s that are
used to pass values into functions: it is desired to only pass known
values (by this `ndk` crate) into those, anything else should similarly
be reported and added upstream.  In these cases a `#[non_exhaustive]`
allows us to do so with a tiny non-breaking patch release.
MarijnS95 added a commit that referenced this pull request Sep 13, 2023
It is older than 6 months and now required for the `toml_edit`
dependency (used by `num_enum_derive`).  At the same time `num_enum`
relies on arbitrary enum discriminants (for discriminated enums
with tuple/struct variants) introduced by Rust 1.66 in order to
implement `#[num_enum(catch_all)]`.  This feature comes in use to
replace the manual `match` blocks when implementing conversions for
`HardwareBufferFormat` when also having an `Unknown(u32)` to catch
valid private/vendor values that won't ever be described inside the
NDK.  This change effectively reverts #407 to its initial state, where a
`catch_all` implementation was used.

For the latter the intent is however to use this feature sparingly.
In most APIs new values are few and far between, so treating these as
an `Err` via `TryFromPrimitive` is desired to provoke upstream issue
reports and quick turnaround on new values.  Same for `enum`s that are
used to pass values into functions: it is desired to only pass known
values (by this `ndk` crate) into those, anything else should similarly
be reported and added upstream.  In these cases a `#[non_exhaustive]`
allows us to do so with a tiny non-breaking patch release.
MarijnS95 added a commit that referenced this pull request Sep 13, 2023
It is older than 6 months and now required for the `toml_edit`
dependency (used by `num_enum_derive`).  At the same time `num_enum`
relies on arbitrary enum discriminants (for discriminated enums
with tuple/struct variants) introduced by Rust 1.66 in order to
implement `#[num_enum(catch_all)]`.  This feature comes in use to
replace the manual `match` blocks when implementing conversions for
`HardwareBufferFormat` when also having an `Unknown(u32)` to catch
valid private/vendor values that won't ever be described inside the
NDK.  This change effectively reverts #407 to its initial state, where a
`catch_all` implementation was used.

For the latter the intent is however to use this feature sparingly.
In most APIs new values are few and far between, so treating these as
an `Err` via `TryFromPrimitive` is desired to provoke upstream issue
reports and quick turnaround on new values.  Same for `enum`s that are
used to pass values into functions: it is desired to only pass known
values (by this `ndk` crate) into those, anything else should similarly
be reported and added upstream.  In these cases a `#[non_exhaustive]`
allows us to do so with a tiny non-breaking patch release.
MarijnS95 added a commit that referenced this pull request Sep 14, 2023
It is older than 6 months and now required for the `toml_edit`
dependency (used by `num_enum_derive`).  At the same time `num_enum`
relies on arbitrary enum discriminants (for discriminated enums
with tuple/struct variants) introduced by Rust 1.66 in order to
implement `#[num_enum(catch_all)]`.  This feature comes in use to
replace the manual `match` blocks when implementing conversions for
`HardwareBufferFormat` when also having an `Unknown(u32)` to catch
valid private/vendor values that won't ever be described inside the
NDK.  This change effectively reverts #407 to its initial state, where a
`catch_all` implementation was used.

For the latter the intent is however to use this feature sparingly.
In most APIs new values are few and far between, so treating these as
an `Err` via `TryFromPrimitive` is desired to provoke upstream issue
reports and quick turnaround on new values.  Same for `enum`s that are
used to pass values into functions: it is desired to only pass known
values (by this `ndk` crate) into those, anything else should similarly
be reported and added upstream.  In these cases a `#[non_exhaustive]`
allows us to do so with a tiny non-breaking patch release.
MarijnS95 added a commit that referenced this pull request Sep 14, 2023
It is older than 6 months and now required for the `toml_edit`
dependency (used by `num_enum_derive`).  At the same time `num_enum`
relies on arbitrary enum discriminants (for discriminated enums
with tuple/struct variants) introduced by Rust 1.66 in order to
implement `#[num_enum(catch_all)]`.  This feature comes in use to
replace the manual `match` blocks when implementing conversions for
`HardwareBufferFormat` when also having an `Unknown(u32)` to catch
valid private/vendor values that won't ever be described inside the
NDK.  This change effectively reverts #407 to its initial state, where a
`catch_all` implementation was used.

For the latter the intent is however to use this feature sparingly.
In most APIs new values are few and far between, so treating these as
an `Err` via `TryFromPrimitive` is desired to provoke upstream issue
reports and quick turnaround on new values.  Same for `enum`s that are
used to pass values into functions: it is desired to only pass known
values (by this `ndk` crate) into those, anything else should similarly
be reported and added upstream.  In these cases a `#[non_exhaustive]`
allows us to do so with a tiny non-breaking patch release.
MarijnS95 added a commit that referenced this pull request Sep 15, 2023
It is older than 6 months and now required for the `toml_edit`
dependency (used by `num_enum_derive`).  At the same time `num_enum`
relies on arbitrary enum discriminants (for discriminated enums
with tuple/struct variants) introduced by Rust 1.66 in order to
implement `#[num_enum(catch_all)]`.  This feature comes in use to
replace the manual `match` blocks when implementing conversions for
`HardwareBufferFormat` when also having an `Unknown(u32)` to catch
valid private/vendor values that won't ever be described inside the
NDK.  This change effectively reverts #407 to its initial state, where a
`catch_all` implementation was used.

For the latter the intent is however to use this feature sparingly.
In most APIs new values are few and far between, so treating these as
an `Err` via `TryFromPrimitive` is desired to provoke upstream issue
reports and quick turnaround on new values.  Same for `enum`s that are
used to pass values into functions: it is desired to only pass known
values (by this `ndk` crate) into those, anything else should similarly
be reported and added upstream.  In these cases a `#[non_exhaustive]`
allows us to do so with a tiny non-breaking patch release.
MarijnS95 added a commit to MarijnS95/ndk that referenced this pull request Sep 15, 2023
It is older than 6 months and now required for the `toml_edit`
dependency (used by `num_enum_derive`).  At the same time `num_enum`
relies on arbitrary enum discriminants (for discriminated enums
with tuple/struct variants) introduced by Rust 1.66 in order to
implement `#[num_enum(catch_all)]`.  This feature comes in use to
replace the manual `match` blocks when implementing conversions for
`HardwareBufferFormat` when also having an `Unknown(u32)` to catch
valid private/vendor values that won't ever be described inside the
NDK.  This change effectively reverts rust-mobile#407 to its initial state, where a
`catch_all` implementation was used.

For the latter the intent is however to use this feature sparingly.
In most APIs new values are few and far between, so treating these as
an `Err` via `TryFromPrimitive` is desired to provoke upstream issue
reports and quick turnaround on new values.  Same for `enum`s that are
used to pass values into functions: it is desired to only pass known
values (by this `ndk` crate) into those, anything else should similarly
be reported and added upstream.  In these cases a `#[non_exhaustive]`
allows us to do so with a tiny non-breaking patch release.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
impact: breaking API/ABI-breaking change
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants