-
Notifications
You must be signed in to change notification settings - Fork 302
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
Introduce VASurfaceAttribDRMFormatModifiers #505
Conversation
* To allocate surfaces with one of the modifiers specified in the array, call | ||
* vaCreateSurfaces() with the VASurfaceAttribDRMFormatModifiers attribute set | ||
* to point to an array of num_surfaces instances of this structure. The driver | ||
* will select the optimal modifier in the list. |
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.
What is the intent of the array of these attributes? (Alternatively: what is the use-case of allocating a set of surfaces with different format modifiers per-surface?)
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've just matched what VASurfaceAttribMemoryType
does 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.
So we can get the modifier lists based on the configID, just like the VASurfaceAttribMemoryType?
And we can get all supported modifier belonging to this config, right?
For encoder/decoder, it's OK, but for vpp, how can we know the input/output side?
For example, some of them are just supported in input side while some of them just
for output side.
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.
So we can get the modifier lists based on the configID, just like the VASurfaceAttribMemoryType?
And we can get all supported modifier belonging to this config, right?
This is not implemented in this pull request. This pull request is just about selecting modifiers when allocating a new surface, for now.
For encoder/decoder, it's OK, but for vpp, how can we know the input/output side?
For example, some of them are just supported in input side while some of them just
for output side.
Hmm. How does this work for VASurfaceAttribPixelFormat
? Are we lucky and the formats supported for input are exactly the same as the formats supported for output?
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.
So far as I know, the modifier is decisive by the usage of surface. For example,
when we create a surface for encoder, using the hint of VA_SURFACE_ATTRIB_USAGE_HINT_ENCODER,
the modifier should be a Y_TILE modifier, we can not change it to a linear one. Can we really
select the modifier with the usage hint?
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.
For AMD hardware, we can. See the original issue: #502.
When decoding NV12 buffers, AMD hardware can select between LINEAR and tiled. For some use-cases (rotated direct scanout) tiled buffers are required.
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.
it should be capability report , for example, Intel VDEnc support both tile and linear surface, it could report 2 modifiers for encode config, Decode just support tile surface, it could just report 1 modifiers.
so, I have similar question with @fhvwy , who will allocate the list, application or driver? if it is application , application will set num_modifiers as allocation size, driver should set it to the list size the config support
* | ||
* The value must be a pointer to a VADRMFormatModifierList. | ||
*/ | ||
VASurfaceAttribDRMFormatModifiers, |
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.
Perhaps this should also be readable, returning the list of supported modifiers to vaQuerySurfaceAttributes()
?
(Unclear how the memory works in that case, maybe it needs to be a pointer to something allocated inside the driver.)
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, the memory ownership issue is the reason why I haven't added this as a readable attrib. Since the supported modifiers depend on the VAConfig, the driver can't have a single global modifier list.
Maybe a better path forward would be to return one attrib per supported modifier, but then we can't re-use the same attrib.
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 suppose it should be readable
it is a list for query , but vaCreateSurfaces call, the list should just has 1 element. you could not create one surface with two+ modifiers.
another one is, we already could use https://github.com/intel/libva/blob/master/va/va_drmcommon.h#L137 for external surface, so need a comment to describe it not used for PRIME2
/** Array of modifiers. */ | ||
uint64_t *modifiers; | ||
} VADRMFormatModifierList; | ||
|
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.
Is this used for list all supported modifiers of some config? For VPP, we really think the query result
of VASurfaceAttribPixelFormat is both supported for input and output. Also for the modifier, if input and
output can support the same types of modifiers, we can still do the same way. But if not, we may need to
differentiate which modifiers are for input and which are for output.
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 see.
No, this is not used to list all supported modifiers of a given config. It's only used with vaCreateSurfaces
.
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.
So, I think the ideal usage of this modifier should be:
- query the supported modifiers list based on the configID. For example, an encoder
configID on AMD platform, the query may contain linear and Y_TILE, but on Intel
platform it may just contain Y_TILE. - Then, we select one supported modifier using this attribute to create surface.
For VPP, maybe the things are a little complicated, if input and output modifiers are
different.
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 think the libva client should be responsible for picking the modifier.
There may be multiple modifiers suitable for a given usage. For instance, both Y_TILED and X_TILED may be supported by KMS. However the client can't guess what modifier is "the best one".
The VA-API driver is a better place to decide which exact modifier to pick. The VA-API driver knows that Y_TILED is better than X_TILED.
That's what the GBM API does too: gbm_bo_create_with_modifiers
takes a list of modifiers, and the driver picks the best one from the list. See https://gitlab.freedesktop.org/mesa/mesa/-/blob/f532202f2d55b9ac475b7e3f8c96a4dd23489299/src/gbm/main/gbm.h#L275.
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.
A real problem we need to face is the GPU memory/surface sharing between modules.
The VA output surface may be used as mesa's image/pbo by egl's import. Also, the 3D
render's result can be the input of the VA encoder. For example, we know the
output of the VPP will be imported by the EGL as a texture for 3D rendering, we
should use the X_TILE for this surface(Assuming the 3D driver only support X_TILE).
So I think, a better way may be: Query the supported modifier list first, clip it
with the real usage need, and provide as many choice as we can to let the VA driver
choose the best one.
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 sounds like a good plan to me.
However you may notice that the libva query is not strictly necessary. The libva client can just pass the list of modifiers suitable for the usage (e.g. the list of modifiers supported by EGL or KMS). The libva driver can internally intersect the user list with its own list of supported modifiers. That's why I left the query part out.
I'm still willing to add a query API nonetheless if you want it, but it's still unclear to me how to address the memory ownership issue. The driver needs to return something more complex than just a single integer to the user. VAGenericValue
can hold a pointer, but who's responsible for allocating/free'ing the memory?
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.
As a gstreamer developer, the query is useful for negotiation. For example, if the
query result of supported modifiers of VPP output is LINEAR and Y_TILE, but the
3D module only support X_TILE input, we can quit in very early stage and report
the error reason more precise. This may also apply to other media frameworks such
as FFMpeg, etc.
About the "memory ownership issue", I am not the VA expert:)
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.
Right. By "not strictly necessary", I mean that it would be nice to have but would still work without it. You'd just get an error from vaCreateSurfaces
if VPP output doesn't support EGL modifiers.
Thanks for the feedback!
Ping @XinfengZhang |
Thinking about this a little bit more, I think it would be better to have a separate endpoint for querying the list of modifiers. This would allow the driver to return a different list depending on the usage/memtype/etc. Something like: VAStatus vaQuerySurfaceDRMFormatModifiers(
VADisplay dpy, /* in */
VAConfigID config, /* in */
const VASurfaceAttrib *attrib_list, /* in */
unsigned int num_attribs, /* in */
uint64_t *modifiers, /* out */
unsigned int *num_modifiers /* in/out */
); |
Besides the modifier itself, what are the other "attributes" we can or need to get by this API? |
Just the list of modifiers compatible with the config and attribs. For reference, EGL has something similar with |
OK, so the attributes are input. Sounds good:) |
Yeah, added some comments to make this clearer. Alternatively, we could just take the usage flags as input instead of the attributes, but this may not be enough information for all drivers. |
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 suppose , it is better to be a capability which could be gotten by vaQuerySurfaceAttributes and be set with vaCreateSurfaces. we also should describe the default behavior without this new definitions
* | ||
* The value must be a pointer to a VADRMFormatModifierList. | ||
*/ | ||
VASurfaceAttribDRMFormatModifiers, |
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 suppose it should be readable
it is a list for query , but vaCreateSurfaces call, the list should just has 1 element. you could not create one surface with two+ modifiers.
another one is, we already could use https://github.com/intel/libva/blob/master/va/va_drmcommon.h#L137 for external surface, so need a comment to describe it not used for PRIME2
* To allocate surfaces with one of the modifiers specified in the array, call | ||
* vaCreateSurfaces() with the VASurfaceAttribDRMFormatModifiers attribute set | ||
* to point to an array of num_surfaces instances of this structure. The driver | ||
* will select the optimal modifier in the list. |
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.
it should be capability report , for example, Intel VDEnc support both tile and linear surface, it could report 2 modifiers for encode config, Decode just support tile surface, it could just report 1 modifiers.
so, I have similar question with @fhvwy , who will allocate the list, application or driver? if it is application , application will set num_modifiers as allocation size, driver should set it to the list size the config support
Thanks for the feedback!
Ah, so drivers could advertise support for the new
We've discussed this above. I don't think it's a good idea to make it readable, because the supported modifiers depend on many things, including
That's another issue with making the attribute readable. I don't think we can make the application allocate the list, because I don't think it's reasonable to make the driver allocate the list, because it's not clear when the memory can be free'd. The driver can't really keep a static list of supported modifiers, because the list changes depending on the Am I missing something here?
I'd really prefer to let the application provide a list of modifiers to the driver. The driver can then pick the best one from the list. The application can't figure out what the best modifier is, because this is vendor-specific. This is already what other allocation APIs are doing, including Vulkan and GBM. See for instance
That's a good point. Added a sentence to this effect:
|
6fc378b
to
ab1c659
Compare
VASurfaceAttrib is already defined value type, it could be a pointer, so, the list of Modifers(same as kernel driver definition) is ok to me.
I think , vaConfig should cover all of the dependencies, import other variant lead to redundancy. flexibility always conflict with easy use. about the UsageHint, decode/encode already been covered by vaConfig, the only impact should be VPP_READ and VPP_WRITE, the input of VPP may support different modifiers. but the story is same as VASurfaceAttribPixelFormat. the support format list of input and output maybe is different, but we assume the input and output should be same. if we consider the usagehint, it means usagehint will be a input conditions for the query function. it is not current design, maybe we could push it to 3.x ...
refer the vaQuerySurfaceAttributes comments https://github.com/intel/libva/blob/master/va/va.h#L1683. the story is same. we should let user to allocate the list, then driver to fill them.
from this perspective, you should not send the parameter with modifiers, the behavior is same as before, driver select the best.
|
Sorry, I don't understand what you're suggesting here...
Hmm, ok, then @HeJunyan's concerns are not addressed… It's true that
It's not the same, because the See for instance the So there's no way for applications to pass an already-allocated list of modifiers in the
Let's take a step back. This pull request only adds modifier negotiation for buffer allocation. As described in the original issue (#502), here's a scenario where this is required: I want to decode a video with VA-API and display it with KMS.
When creating the surface, I need to tell VA-API to not use modifier A, because KMS doesn't support it. However I don't know whether B is better (more optimized) than C. This pull request adds a way for applications to tell VA-API to use either modifier B or C. Does this make sense to you? Another scenario where we need to add modifier negotiation is necessary is buffer import. Let's say I render a 3D scene with OpenGL, I want to export a DMA-BUF from OpenGL and import it into VA-API for video encoding.
I need to make sure I don't allocate an OpenGL buffer with modifier D, or else I won't be able to import the buffer in VA-API. One way to fix this is to let applications query the list of modifiers supported by VA-API, as you suggest. This is not done in this pull request, because I'm only interested in fixing the buffer allocation case described above. |
Ping @XinfengZhang |
sorry for late response.
I still think, B or C should be chosen by application, not by driver. application should just choose one , not a list. which one is better between B or C is is another problem, it should be fixed by the query function by the order or some flag.
I think we should consider both two directions, one for query, another for set. there are an assumption for this PR, application already know something about the modifier support list. yes, you are correct. refer the code you shared , the pre-allocated list is not ok. because the pointer will be a potential issue. even it is not break current definition, but maybe cause the regressions. so the definition of https://github.com/intel/libva/blob/master/va/va.h#L1535 is not very friendly for query function |
continue, and if you set B, C. after vaCreateSurfaces, you still dont know which take effect until vaExportSurfaceHandle :) |
What's the motivation for this? That'd be inconsistent with all of the other format modifier APIs (GBM, Vulkan). The application is never in a good position to decide.
Yes, that's fine. That's how all other APIs work as well.
Yes, but the two can be done separately. I only need one direction, I don't need the other.
What would this be used for? This can't be used for storing a modifier, because a modifier isn't enough: we need to expose (format, modifier) pairs. Not all formats are compatible with all modifiers. |
Would advice from other graphics people help convince you that this is the right thing to do? I can start a thread on the dri-devel mailing list to ask them what they think. |
I just wonder whether we could re-use your PR for both query and set. till now, it looks difficult.
yes, different format maybe support different modifiers, modifiers tell the layout /compress information basing on the format. . but I suppose , in practice , all format should support same modifiers. ---- maybe its incorrect. |
@XinfengZhang Hi! I'm one of the people who worked on the EGL extension and Wayland protocol specifications, the implementations of those, and also the original KMS implementation. To be honest, I have to agree with @emersion here.
It would be really nice if this was true! Unfortunately it's not correct. For instance, Intel's own Gen12 compression only supports a very limited number of formats - it does not support 10bpc or 16bpp RGB, for example. One of the principles of modifiers is that modifiers have no meaning by themselves. Modifiers are only meaningful when combined together with a format. For this reason, every other API groups format and modifier together.
The application cannot determine which is 'better'. On Intel, the answer is quite easy: CCS is 'better' than Y-tiling, Y-tiling is better than X-tiling for rendering (but a lot worse for display!), and both are better than linear. For AMD and NVIDIA in particular, the choice of the best modifier depends heavily on not just the format but also things like the surface dimensions. In order for VA-API to inform the client which choice is best, it would have to expose a no-op/dry-run surface-creation entrypoint with all of the parameters required to create a surface, but only returning a modifier choice instead of a surface. This seems like unnecessary duplication. Above all though, I think it is most important for VA-API to be consistent with the rest of the ecosystem. As can be seen in this thread, there is a lot of confusion already about modifiers and how they should work. To reduce this confusion, every other API (EGL, Vulkan, Wayland, X11, KMS, GStreamer, etc) follows a standard set of principles:
VA-API should follow these principles for consistency and correctness. Thanks! Looking forward to having VA support modifiers. |
thanks @fooishbar & @emersion , it is clear now. I am ok about this PR. but I still have a question with principle 3. by the principle 1, seems we already could report a combination list. why we could not use the list order, or some flag to describe which one is "best". still need principle 3? seems a little redundant. of course, from driver implementation side. both should be ok. another one question is : where to find these principles? seems we missed some information or decisions |
Thanks for taking the time to read all of this and figuring out how modifiers are designed.
Yes. I'm still not sure how to design the part of the API that lets you query supported modifiers. I've posted a proposal earlier which adds a new separate function. That proposal is probably too complicated, it can probably be simplified a little by removing the attrib list.
I think @fooishbar explained the reason here: "the choice of the best modifier depends heavily on not just the format but also things like the surface dimensions". Maybe modifier A is better if the buffer is small but modifier B is better if the buffer is large. So there's no "best" modifier in general. Depending on the situation, one modifier may be the best one, but it's not the best one in all cases. In other words, some drivers can't sort the list of modifiers by order of preference.
Yes, I agree we should document all of this. I'll discuss with @danvet to see what the best place for such docs would be. Maybe The Vulkan extension already describes some of the principles (of course with Vulkan-specific bits): https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_EXT_image_drm_format_modifier.html#_usage_patterns Moving forward: I'll start working on a Mesa implementation of this pull request. We still need to add a way for drivers to signal that they support While I only need the API introduced in this PR, I could also help with an API to query supported (format, modifier) combinations for a given usage. Let me know if you're interested. |
It's not just preference, sometimes it's a hard requirement. For instance, say your GPU can use either 16x16 or 32x32 tiling modes, and it prefers to use 16x16 because it's more optimal, but it also has a restriction that the surface cannot not exceed 64 tiles in width. So you do you put 16x16 at the top of the list because it's 'better' but doesn't work with width > 1024, or do you put 32x32 at the top of the list because it's slower but works in more cases? (This is not a theoretical case ... obviously the numbers are simplified but this is a real limitation that exists for some vendors.) |
If it's not too much text, adding another in-line DOC: section in drm_fourcc.h with these principles is probably best. You can use full rst formatting, including headings and everything (just need to be aware that the heading nesting is inpreted in the context of the .rst file that pulls in the DOC: section, there's no adjustment being done automatically, it's really just a fancy #include style statement) Also would be really good to get that doc patch reviewed as widely as possible. @fooishbar can help with anything that's missing I'm sure :-) |
This allows users to specify a list of modifiers when allocating a new surface. The driver will pick a modifier from the list. Closes: intel#502
ab1c659
to
9034c60
Compare
I've opened #519 to allow applications to figure out whether a driver supports |
@HeJunyan @dvrogozh if there are no other concern , please help +1, we will file another PR against https://github.com/intel/media-driver/ to implement it. and merge the PR |
The Mesa implementation is available here: https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/10134 |
This allows users to specify a list of modifiers when allocating a
new surface. The driver will pick a modifier from the list.
Example usage:
Closes: #502