-
Notifications
You must be signed in to change notification settings - Fork 335
Add validation for GPUDevice.createTexture() #799
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
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.
Thank you for writing this! It looks great overall, just have a few concerns.
|
||
1. If device is lost, or if this call doesn't follow the [$createTexture Valid Usage$], return an error texture. | ||
1. Let |t| be a new {{GPUTexture}} object. | ||
1. Set |t|.{{GPUTexture/[[textureSize]]}} to |descriptor|.{{GPUTextureDescriptor/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.
did you consider just making the whole |descriptor|
to be in the internal slot?
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 it be? I was just copying how buffers did it.
Also, that reminds me, are slots copied by value or by reference? It would be bad if the spec said that modifying a descriptor after creating the texture caused the texture to be modified.
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 would be just easier to specify if you say the descriptor
is copied by value into the internal slot.
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.
Unfortunately right now copying patterns from other parts of the spec doesn't work well because they haven't been copyedited.
I want to change more of the spec to use this pattern (just copying the whole descriptor directly into an internal slot).
1. If |descriptor|.{{GPUTextureDescriptor/sampleCount}} > 1: | ||
|
||
1. |descriptor|.{{GPUTextureDescriptor/mipLevelCount}} must be 1. | ||
1. |descriptor|.{{GPUTextureDescriptor/size}}.[=Extent3D/depth=] must be 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.
we should also say that the dimension has to be "2d", i.e. disallow 1D multisampled textures (for now)
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 is done in that dimension's list of validation checks, but I think it would be good to have all sample count constraints in the same place.
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 couldn't get Bikeshed to give me nested "if"s :(
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 think it works if you add enough indentation. But sometimes 2 spaces is enough while other times you need 4 spaces. It's a bit weird.
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.
Generally it requires 4 spaces; I think it usually treats 2 spaces similarly to 0 spaces.
1. If |descriptor|.{{GPUTextureDescriptor/sampleCount}} > 1: | ||
|
||
1. |descriptor|.{{GPUTextureDescriptor/mipLevelCount}} must be 1. | ||
1. |descriptor|.{{GPUTextureDescriptor/size}}.[=Extent3D/depth=] must be 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.
It is done in that dimension's list of validation checks, but I think it would be good to have all sample count constraints in the same place.
1. If |descriptor|.{{GPUTextureDescriptor/format}} is a [=depth or stencil format=]: | ||
|
||
1. |descriptor|.{{GPUTextureDescriptor/dimension}} must be "2d". | ||
1. |descriptor|.{{GPUTextureDescriptor/sampleCount}} must be 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.
nit: Could go with the rest of the multisampled texture validation.
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 couldn't get Bikeshed to give me nested "if"s :(
1. |descriptor|.{{GPUTextureDescriptor/sampleCount}} must be 1. | ||
|
||
1. |descriptor|.{{GPUTextureDescriptor/usage}} must be a combination of {{GPUTextureUsage}} values. | ||
|
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.
There is some missing validation:
- first mip level width and height is a multiple of the compressed block size.
- compressed textures can only be copySrc / copyDst / Sampled.
- other usage constraints (we have non-renderable types), or add an issue for it. Dawn's Format.cpp summarizes what we have found by investigating the various APIs, and all usages of all formats are tested.
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.
Unextended WebGPU doesn't have any compressed textures, and we haven't added any extensions to add any yet, and our implementation doesn't support compressed textures yet, so I'm not comfortable adding rules for compressed textures. I can open an issue for it.
I'll open a new issue for usage constraints. AFAICT Metal doesn't have any constraints here, so I'm not sure what to restrict.
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.
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.
"texture-compression-bc"
is already there although the formats enums aren't in the spec yet. We're pretty comfortable adding text for compressed textures because @Jiawei-Shao did extensive investigation and testing in Dawn so we know they work in all APIs with the current validation constraints.
There's a bit a of chicken and egg issues because you've voiced concern about adding the extension because we didn't have validation for it, and now you have concerns adding the validation because we don't have the extension yet ^^.
That said we can do compressed texture validation in a follow-up if it feels more comfortable.
Metal does have a large number of usage constraints on texture that you can find starting page 6 of the Metal Feature Set document. We can add that independently since it will likely be a large PR in itself.
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.
BTW though there are no compressed textures in the spec, there is a lot of setup for them (block based formats/texel blocks). You can rely on that ("block size > 1") to talk about compressed formats.
In this case: In practice this should be correct, but if we want we could eventually add an explicit flag to a texture format capability table that says "supports multiple samples".
1. |descriptor|.{{GPUTextureDescriptor/size}}.[=Extent3D/width=] must be less than or equal to 2048. | ||
1. |descriptor|.{{GPUTextureDescriptor/size}}.[=Extent3D/height=] must be less than or equal to 2048. | ||
1. |descriptor|.{{GPUTextureDescriptor/size}}.[=Extent3D/depth=] must be less than or equal to 2048. | ||
1. |descriptor|.{{GPUTextureDescriptor/size}}.[=Extent3D/width=] must be less than or equal to the owning {{GPUDevice}}'s {{GPULimits/maxTextureLayers}}. |
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 3D textures I think each dimension should use maxTextureSize
instead of maxTextureLayers
, or maybe we could have split limits for 1D, 2D and 3D (3D's default limit can't be more than 2048 because that's what the majority of Vulkan devices support)
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 seems that we have to split here:
maxTextureSize1D = 8192
maxTextureSize2D = 8192
maxTextureSize3D = 2048
maxTextureLayers = 256
:: | ||
The maximum number of layers in an array texture. | ||
|
||
Note: This is also used for the size limit of 3D textures. |
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 three dimensions are tied to maxTextureLayers?
Is there a fundamental reason this is true (i.e. coming from the native APIs)? If not, we should probably split up the limits in case there is hardware out there where this would be overly restrictive.
Also would you mind updating https://github.com/gpuweb/gpuweb/blob/master/design/Limits.md to document where these numbers come from?
1. Let |d| = |size|.[=Extent3D/depth=]. | ||
|
||
1. Let |m| = the maximum value of |w|, |h|, and |d|. | ||
1. Return one plus the greatest integral value of |x| for which 2^|x| <= |m|. |
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.
Pretty sure this will work:
1. Return one plus the greatest integral value of |x| for which 2^|x| <= |m|. | |
1. Return one plus the greatest integral value of |x| for which 2<sup>|x|</sup> ≤ |m|. |
1. |descriptor|.{{GPUTextureDescriptor/size}}.[=Extent3D/width=] must be nonzero. | ||
1. |descriptor|.{{GPUTextureDescriptor/size}}.[=Extent3D/height=] must be nonzero. | ||
1. |descriptor|.{{GPUTextureDescriptor/size}}.[=Extent3D/depth=] must be nonzero. | ||
1. |descriptor|.{{GPUTextureDescriptor/mipLevelCount}} must be nonzero. | ||
1. |descriptor|.{{GPUTextureDescriptor/sampleCount}} must be nonzero. |
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.
nit: I know this is expressed by the types, but "greater than zero" would be slightly clearer here than "nonzero"
<dfn abstract-op>createTexture Valid Usage</dfn> | ||
Given a {{GPUDevice}} |this| and a {{GPUTextureDescriptor}} |descriptor| |
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.
nit: indent level changes between these two lines.
Also I'd put a paragraph break between the dfn and "Given".
<dfn abstract-op>createTexture Valid Usage</dfn> | |
Given a {{GPUDevice}} |this| and a {{GPUTextureDescriptor}} |descriptor| | |
<dfn abstract-op>createTexture Valid Usage</dfn> | |
Given a {{GPUDevice}} |this| and a {{GPUTextureDescriptor}} |descriptor| |
1. |descriptor|.{{GPUTextureDescriptor/sampleCount}} must be nonzero. | ||
1. If |descriptor|.{{GPUTextureDescriptor/dimension}} is "1d": | ||
|
||
1. |descriptor|.{{GPUTextureDescriptor/size}}.[=Extent3D/width=] must be less than or equal to the owning {{GPUDevice}}'s {{GPULimits/maxTextureSize}}. |
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.
nit: The "owning GPUDevice" is |this|
1. |descriptor|.{{GPUTextureDescriptor/sampleCount}} must be 1. | ||
|
||
1. |descriptor|.{{GPUTextureDescriptor/usage}} must be a combination of {{GPUTextureUsage}} values. | ||
|
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.
BTW though there are no compressed textures in the spec, there is a lot of setup for them (block based formats/texel blocks). You can rely on that ("block size > 1") to talk about compressed formats.
In this case: In practice this should be correct, but if we want we could eventually add an explicit flag to a texture format capability table that says "supports multiple samples".
This was almost ready to be merged, can we iterate on it and get it in the spec? |
Up! This PR should be most non-controversial, and we can just add |
1. Calculate the values of |w|, |h|, and |d|. If the |dimension| is "1d": | ||
|
||
1. Let |w| = |size|.[=Extent3D/width=]. | ||
1. Let |h| = 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.
Isn't Extent3D/height
guaranteed to be 1 for 1D textures? I.e. can we just use Extent3D/width/height/depth
for w/h/d
instead of having this switch over the dimension?
1. Let |d| = |size|.[=Extent3D/depth=]. | ||
|
||
1. Let |m| = the maximum value of |w|, |h|, and |d|. | ||
1. Return one plus the greatest integral value of |x| for which 2^|x| <= |m|. |
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.
shouldn't this be <
instead of <=
? If m
is already a power of two, say 2^k
, we consider the mipmap count to be k
, while the current argument would produce k+1
1. |descriptor|.{{GPUTextureDescriptor/size}}.[=Extent3D/width=] must be less than or equal to 2048. | ||
1. |descriptor|.{{GPUTextureDescriptor/size}}.[=Extent3D/height=] must be less than or equal to 2048. | ||
1. |descriptor|.{{GPUTextureDescriptor/size}}.[=Extent3D/depth=] must be less than or equal to 2048. | ||
1. |descriptor|.{{GPUTextureDescriptor/size}}.[=Extent3D/width=] must be less than or equal to the owning {{GPUDevice}}'s {{GPULimits/maxTextureLayers}}. |
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 seems that we have to split here:
maxTextureSize1D = 8192
maxTextureSize2D = 8192
maxTextureSize3D = 2048
maxTextureLayers = 256
This PR adds validation rules for texture creation. It is based on: - PR 799 (gpuweb#799) from Myles, and the comments. - Issue 1522 (gpuweb#1522) I investigated when I was implementing 3D textures on Dawn project, and the comments.
superseded by #1658 |
* Add spec for texture creation This PR adds validation rules for texture creation. It is based on: - PR 799 (#799) from Myles, and the comments. - Issue 1522 (#1522) I investigated when I was implementing 3D textures on Dawn project, and the comments. * Update spec/index.bs Co-authored-by: Kai Ninomiya <[email protected]> * Update spec/index.bs Co-authored-by: Kai Ninomiya <[email protected]> * Address feedback from Kai and Dzmitry * Address more feedback from Kai and Dzmitry * Update spec/index.bs Co-authored-by: Kai Ninomiya <[email protected]> Co-authored-by: Kai Ninomiya <[email protected]>
Preview | Diff