-
Notifications
You must be signed in to change notification settings - Fork 304
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
Describe validation and creation of GPUBindGroupLayouts #427
Conversation
In shaders there are several texture types for each dimensionality depending on their component type. It can be either float, uint or sint, with maybe in the future depth/stencil if WebGPU allows reading such textures. The component type of a GPUTextureView's format must match the component type of its binding in the shader module. This is for several reasons: - Vulkan requires the following: "The Sampled Type of an OpTypeImage declaration must match the numeric format of the corresponding resource in type and signedness, as shown in the SPIR-V Sampled Type column of the Interpretation of Numeric Format table, or the values obtained by reading or sampling from this image are undefined." - It is also required in OpenGL for the texture units to be complete, a uint or sint texture unit used with a non-nearest sampler is incomplete and returns black texels. Similar constraints must exist in other APIs. To encode this compatibility constraint, a new member is added to GPUBindGroupLayoutBinding that is a new enum GPUTextureComponentType that give the component type of the texture.
This is the most common case and avoids having an optional dictionary member with no default value (but that still requires a value for texture bindings).
spec/index.bs
Outdated
@@ -188,6 +188,11 @@ dictionary GPUExtensions { | |||
<script type=idl> | |||
dictionary GPULimits { | |||
u32 maxBindGroups = 4; | |||
u32 maxSampledTexturesPerShaderStage = 16; |
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.
Are these meant to be per bindgroup per stage or per pipeline per stage?
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.
Per bind group, per stage. A single pipeline may share some of the same limits (it looks like this is how D3D12 works), but those limits aren't enforceable until createPipelineLayout.
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.
Makes sense thanks for the explanation.
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.
Maybe we can come up with a clearer name here, like PerStagePerBindGroup? verbose 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.
this semantics indeed needs to be better reflected in the name (unfortunately for that name)
Additional discussion about GPUBindGroupLayout limits started in #409; I'm going to continue there. |
I also want to incorporate conclusions from #406, but this can be done whenever. |
spec/index.bs
Outdated
|
||
### {{GPUDevice/createBindGroupLayout()|GPUDevice.createBindGroupLayout(GPUBindGroupLayoutDescriptor)}} ### {#GPUDevice-createBindGroupLayout} | ||
|
||
A valid {{GPUBindGroupLayout}} object has an <dfn>internal map</dfn> of |u32| <dfn>binding number</dfn>s to internal <dfn>layout binding</dfn> objects. |
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 means that the binding numbers can be arbitrary. That sounds good but our implementation currently requires bindings numbers between 0 and 15 and would likely introduce a map in the BGL from application-facing binding numbers to packed bindings numbers in 0..N.
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.
These numbers exist in an internal map so this isn't the place to specify the range. We could do that on input (GPUBindGroupLayoutDescriptor processing).
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.
Can you clarify if you are going to have a problem with arbitrary binding numbers or not? Our implementation works, and I could think of a case where the users would want the numbers to exceed 15.
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 aren't going to have problems with arbitrary numbers, sorry for the confusion (we just need to do a bit more work). I just wanted to make sure this was done being aware that an alternative was to require numbers in a small range corresponding to maxBindingsPerGroup.
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.
@Kangz Do you mean you'd like this text to change at all, or are you just pointing out the work you have to do on your end?
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.
Allowing for arbitrary indices is easier for developers and trivial to reorder inside the 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.
spec/index.bs
Outdated
1. If |bindingDescriptor|.{{GPUBindGroupLayoutBinding/binding}} is already present in |layout|'s [=internal map=], [=return with error=]. | ||
1. Let |layoutBinding| be a new internal [=layout binding=] object. | ||
1. If |bindingDescriptor|.{{GPUBindGroupLayoutBinding/type}} is {{GPUBindingType/uniform-buffer}}: | ||
1. If |layout|'s [=internal map=] contains {{GPULimits/maxUniformBuffersPerShaderStage|GPULimits.maxUniformBuffersPerShaderStage}} [=layout binding=]s of [=type=] {{GPUBindingType/uniform-buffer}} that all share any [=visibility=] bit contained in |bindingDescriptor|.{{GPUBindGroupLayoutBinding/visibility}}, [=return with error=]. |
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'd add these validations at the end of the algorithm even if that would be allowed by implementations under the as-if rule. Basically this makes validation O(n2) instead of O(n)
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.
+1, I think it would be much easier to read too.
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's hard to read those long lines, I'll be happy to take another look once this is refactored according to this suggestion
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 finished refactoring a bunch of stuff. PTAL!
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.
Behavior described LGTM, @kvark and @kainino0x can you TAL too?
spec/index.bs
Outdated
|
||
### {{GPUDevice/createBindGroupLayout()|GPUDevice.createBindGroupLayout(GPUBindGroupLayoutDescriptor)}} ### {#GPUDevice-createBindGroupLayout} | ||
|
||
A valid {{GPUBindGroupLayout}} object has an <dfn>internal map</dfn> of |u32| <dfn>binding number</dfn>s to internal <dfn>layout binding</dfn> objects. |
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.
These numbers exist in an internal map so this isn't the place to specify the range. We could do that on input (GPUBindGroupLayoutDescriptor processing).
spec/index.bs
Outdated
a {{GPUTextureComponentType}} <dfn>textureComponentType</dfn> which must be initially <code>"float</code>, and a <dfn>multisampled</dfn> boolean which must be initially <code>false</code>. | ||
|
||
<div algorithm="GPUDevice.createBindGroupLayout(descriptor)"> | ||
Any time during this algorithm, to <dfn>return with error</dfn> is to: |
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 dfns are global to the spec, so this won't end up staying within this algorithm.
Ultimately we SHOULD define this globally though. So ok to keep as is for now.
spec/index.bs
Outdated
1. If |bindingDescriptor|.{{GPUBindGroupLayoutBinding/binding}} is already present in |layout|'s [=internal map=], [=return with error=]. | ||
1. Let |layoutBinding| be a new internal [=layout binding=] object. | ||
1. If |bindingDescriptor|.{{GPUBindGroupLayoutBinding/type}} is {{GPUBindingType/uniform-buffer}}: | ||
1. If |layout|'s [=internal map=] contains {{GPULimits/maxUniformBuffersPerShaderStage|GPULimits.maxUniformBuffersPerShaderStage}} [=layout binding=]s of [=type=] {{GPUBindingType/uniform-buffer}} that all share any [=visibility=] bit contained in |bindingDescriptor|.{{GPUBindGroupLayoutBinding/visibility}}, [=return with error=]. |
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.
+1, I think it would be much easier to read too.
spec/index.bs
Outdated
1. Set [=dynamic=] of |layoutBinding| to the value of |bindingDescriptor|.{{GPUBindGroupLayoutBinding/dynamic}}. | ||
1. If [=type=] is {{GPUBindingType/sampled-texture}} or {{GPUBindingType/storage-texture}}: | ||
1. If [=type=] is {{GPUBindingType/sampled-texture}} and if |layout|'s [=internal map=] contains {{GPULimits/maxSampledTexturesPerShaderStage|GPULimits.maxSampledTexturesPerShaderStage}} [=layout binding=]s of [=type=] {{GPUBindingType/sampled-texture}} that all share any [=visibility=] bit contained in |bindingDescriptor|.{{GPUBindGroupLayoutBinding/visibility}}, [=return with error=]. | ||
1. If [=type=] is {{GPUBindingType/storage-texture}} and if |layout|'s [=internal map=] contains {{GPULimits/maxStorageTexturesPerShaderStage|GPULimits.maxStorageTexturesPerShaderStage}} [=layout binding=]s of [=type=] {{GPUBindingType/storage-texture}} that all share any [=visibility=] bit contained in |bindingDescriptor|.{{GPUBindGroupLayoutBinding/visibility}}, [=return with error=]. |
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.
Seems like we should also say "if dynamic is set, return with error", and similar for the other cases too.
(Unfortunate, because it's kind of verbose; maybe it can be condensed.)
IDL wise, I wonder if there's any way we can split GPUBindGroupLayoutBinding into 4 different dictionaries.
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'd also prefer that we split these GPUBindGroupLayoutBinding
cases into different sub-classes/dictionaries rather than differentiating by type
enum. However, if we keep it as is, I propose we ignore "dynamic" if the resource is not a buffer (maybe issue a warning?), and so on, instead of aborting GPUBindGroupLayout
creation. It keeps the API more flexible.
spec/index.bs
Outdated
@@ -188,6 +188,11 @@ dictionary GPUExtensions { | |||
<script type=idl> | |||
dictionary GPULimits { | |||
u32 maxBindGroups = 4; | |||
u32 maxSampledTexturesPerShaderStage = 16; |
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 semantics indeed needs to be better reflected in the name (unfortunately for that name)
* {{GPUBindGroupLayoutBinding/textureDimension}}, {{GPUBindGroupLayoutBinding/multisampled}}: | ||
The dimensions and multi-sampling properties of texture bindings. | ||
|
||
Note: This allows Metal-based implementations to back the respective bind |
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.
might add another note saying that this allows catching the shader-binding mismatches earlier (at the creation of bind groups and pipelines)
spec/index.bs
Outdated
groups with `MTLArgumentBuffer` objects that are more efficient to bind at | ||
run-time. | ||
|
||
* {{GPUBindGroupLayoutBinding/dynamic}}: |
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 probably rename this to something like dynamicOffset
. Subsequently, it will be clearer to always say "dynamic offset binding" instead of "dynamic binding".
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.
dynamicOffset
sounds like it should be a number; maybe dynamicallyOffset
? I still prefer dynamic
for a bool.
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.
Agreed re: sounds like a number. hasDynamicOffset
?
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.
Renamed to hasDynamicOffsets
.
spec/index.bs
Outdated
1. Generate a validation error in the current scope with appropriate error message. | ||
1. Create a new invalid {{GPUBindGroupLayout}} and return the result. | ||
|
||
The <dfn method for "GPUDevice">createBindGroupLayout(|descriptor|)</dfn> method attempts to create a valid {{GPUBindGroupLayout}}. |
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'm not sure if the wording of "attemtps" and "valid" is good here. Saying that a function "attempts" to do something appears to make sense to me if the return type indicates a possible failure. This is not the case here. Also, "valid" is strange because it's hard to imagine what else it could be doing. Seeing "valid" even makes it confusing to me, since it implies that the implementation is trying really hard to create it in such a way that it's "valid", while in fact the implementation doesn't do anything sophisticated.
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'm not sure yet how else to describe what to expect in a failure case. We use "invalid" to describe other objects in the API so it stands to reason that the opposite of such would be a "valid" object.
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 failure cases are described separately as a follow-up: we list the things that are checked and say in which case the result is invalid.
What we shouldn't do is saying that "a method attempts to create a valid XXX", since this implies that the method does more than necessary to make sure it's "valid". We should just say "method creates an XXX" 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.
Text was updated to do so. PTAL
spec/index.bs
Outdated
|
||
### {{GPUDevice/createBindGroupLayout()|GPUDevice.createBindGroupLayout(GPUBindGroupLayoutDescriptor)}} ### {#GPUDevice-createBindGroupLayout} | ||
|
||
A valid {{GPUBindGroupLayout}} object has an <dfn>internal map</dfn> of |u32| <dfn>binding number</dfn>s to internal <dfn>layout binding</dfn> objects. |
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 radical alternative, we could make it a map on the API side, and then this piece would not need to be as carfully specified in terms of valid inputs :)
spec/index.bs
Outdated
1. If |bindingDescriptor|.{{GPUBindGroupLayoutBinding/binding}} is already present in |layout|'s [=internal map=], [=return with error=]. | ||
1. Let |layoutBinding| be a new internal [=layout binding=] object. | ||
1. If |bindingDescriptor|.{{GPUBindGroupLayoutBinding/type}} is {{GPUBindingType/uniform-buffer}}: | ||
1. If |layout|'s [=internal map=] contains {{GPULimits/maxUniformBuffersPerShaderStage|GPULimits.maxUniformBuffersPerShaderStage}} [=layout binding=]s of [=type=] {{GPUBindingType/uniform-buffer}} that all share any [=visibility=] bit contained in |bindingDescriptor|.{{GPUBindGroupLayoutBinding/visibility}}, [=return with error=]. |
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's hard to read those long lines, I'll be happy to take another look once this is refactored according to this suggestion
unsigned long maxDynamicUniformBuffersPerPipelineLayout = 8; | ||
unsigned long maxDynamicStorageBuffersPerPipelineLayout = 4; | ||
unsigned long maxSampledTexturesPerShaderStage = 16; | ||
unsigned long maxSamplersPerShaderStage = 16; |
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 that really addressing the confusion about bind groups? We should still say "PerBindGroup", I think, for clarity.
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.
Actually, these limits apply to the entire pipeline layout as well. So by definition a single bind group must not exceed these limits, but when we combine bind group layouts into pipeline layouts, their combined totals will have to be validated against these same limits.
Saying "per bind group" is also true, but then wouldn't make as much sense as a limit for GPUPipelineLayout
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.
Wait, this seems wrong. If these limits apply to the whole layout, why isn't this expressed here:
There must be {{GPULimits/maxUniformBuffersPerShaderStage|GPULimits.maxUniformBuffersPerShaderStage}} or
fewer |bindingDescriptor|s of type {{GPUBindingType/uniform-buffer}} visible on each shader stage in |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.
Some of these apply to descriptors per stage, some apply to all descriptors in the entire layout. The one you quoted is for general Uniform buffers, but the one that applies to pipeline layout is DYNAMIC uniform buffers. When validating the descriptor for a dynamic uniform buffer, my understanding is that both of these limits have to be checked separately. Did I understand that correctly?
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.
Ok, now as I re-read it, it makes more sense. So we have shader stages and bind groups as two orthogonal things. The are two kinds of limits here: one kind that is a total across all shader stages and bind groups (XxxPerPipelineLayout), and one that is a total across all bind groups of each shader stage (XxxPerShaderStage).
I have successfully whacked all the moles. |
This is also done. |
unsigned long maxDynamicUniformBuffersPerPipelineLayout = 8; | ||
unsigned long maxDynamicStorageBuffersPerPipelineLayout = 4; | ||
unsigned long maxSampledTexturesPerShaderStage = 16; | ||
unsigned long maxSamplersPerShaderStage = 16; |
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.
Wait, this seems wrong. If these limits apply to the whole layout, why isn't this expressed here:
There must be {{GPULimits/maxUniformBuffersPerShaderStage|GPULimits.maxUniformBuffersPerShaderStage}} or
fewer |bindingDescriptor|s of type {{GPUBindingType/uniform-buffer}} visible on each shader stage in |descriptor|.
spec/index.bs
Outdated
## GPUPipelineLayout ## {#pipeline-layout} | ||
## GPUBindGroupLayout ## {#bind-group-layout} | ||
|
||
A {{GPUBindGroupLayout}} defines an interface between a set of resources bound in a {{GPUBindGroup}} and their accessibility in shader stages. |
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: shouldn't this be "the interface"? Technically, it's a very concrete contract it is defining, not "any" contract.
spec/index.bs
Outdated
<dl dfn-type=attribute dfn-for="layout binding"> | ||
: <dfn>\[[binding]]</dfn> of type unsigned long. | ||
:: | ||
The unique identifier for this [=layout binding=] in shader stages. |
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.
would be good to define the scope of this uniqueness, e.g. "unique within this bind group layout"
spec/index.bs
Outdated
|
||
: <dfn>\[[hasDynamicOffsets]]</dfn> of type boolean. | ||
:: | ||
If `true`, indicates that this [=layout binding=] has dynamic offsets. |
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 there a reason for plural here? I don't think we discussed array bindings yet, so this is a bit confusing.
spec/index.bs
Outdated
:: | ||
If `true`, indicates that this [=layout binding=] has dynamic offsets. | ||
|
||
Ignored if {{layout binding/[[type]]}} is not {{GPUBindingType/uniform-buffer}}, {{GPUBindingType/storage-buffer}}, or {{GPUBindingType/readonly-storage-buffer}}. |
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.
Why would we want to allow it to be true
for types that don't have dynamic offsets?
Imagine how you'd have to specify the set_bind_group()
with this, how you'd define the expected offsets. if we are strict here, then set_bind_group
becomes trivial to define: one offset is required for each dynamic-offset binding.
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.
Hmm, I went with the ignore path to make it a little more flexible. If it's only allowed for certain resources, I'm leaning towards splitting GPUBindGroupLayoutBinding into multiple different types, rather than switching on type.
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 there a case where this flexibility would be needed and/or beneficial?
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.
Less code to change if you wanted to update the type of a resource binding, I guess? I'm going to make a new PR to see what different types of GPUBindGroupLayoutBinding would look like.
spec/index.bs
Outdated
|
||
: <dfn>\[[textureDimension]]</dfn> of type {{GPUTextureViewDimension}}. | ||
:: | ||
The dimensionality of the texture resource described by this [=layout binding=]. |
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.
Actually, this is the dimensionality of the view, not the texture. It can be different from the texture (e.g. 2D view of a slice of 3D texture).
spec/index.bs
Outdated
|
||
: <dfn>\[[textureComponentType]]</dfn> of type {{GPUTextureComponentType}}. | ||
:: | ||
The data type of the texture resource described by this [=layout binding=]. |
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 also technically for the view
, but we don't currently allow viewing with a different component type, so it's less of an issue.
spec/index.bs
Outdated
|
||
: <dfn>\[[multisampled]]</dfn> of type boolean. | ||
:: | ||
If `true`, indicates that the texture resource described by this [=layout binding=] will be multisampled. |
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 need to reword this. It's written in a way that it uses different tense ("will be") and may read as if "multisample" here is a verb. Could we say "indicates that the resource is multi-sampled"? Or "contains multiple samples per texel"?
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.
Sure.
spec/index.bs
Outdated
|
||
* {{GPUBindGroupLayoutBinding/hasDynamicOffsets}}: | ||
For {{GPUBindingType/uniform-buffer}}, {{GPUBindingType/storage-buffer}}, and {{GPUBindingType/readonly-storage-buffer}} bindings, | ||
indicates that the binding has dynamic offsets. One offset must be passed to |
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 noted in my previous comment, one binding can't have multiple dynamic offsets (today)
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.
Addressed!
spec/index.bs
Outdated
</script> | ||
An internal [=layout binding=] object has the following slots: | ||
|
||
<dl dfn-type=attribute dfn-for="layout binding"> |
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 a duplicate of GPUBindGroupLayoutBinding, and would cause duplicate documentation of all of its fields. Why not just have the [[bindingsMap]]
values be GPUBindGroupLayoutBindings? It's not exposed, so I think it's ok to use an IDL type for this.
For that matter, [[bindingsMap]]
could probably just be a GPUBindGroupLayoutDescriptor. In general I think it would make sense for every object to have a copy of its original descriptor; it's an easy and succinct way to track how it was created.
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.
Agreed. This was originally how I wanted to do this, but wasn't sure if that was correct.
spec/index.bs
Outdated
fewer |bindingDescriptor|s of type {{GPUBindingType/uniform-buffer}} visible on each shader stage in |descriptor|. | ||
* There must be {{GPULimits/maxDynamicUniformBuffersPerPipelineLayout|GPULimits.maxDynamicUniformBuffersPerPipelineLayout}} or | ||
fewer |bindingDescriptor|s of type {{GPUBindingType/uniform-buffer}} with {{GPUBindGroupLayoutBinding/hasDynamicOffsets}} set to `true` | ||
visible across <b>all</b> shader stages in |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.
Does one buffer bound to both VERTEX and FRAGMENT count as 1 or 2? (Clarify in text)
here and below
spec/index.bs
Outdated
* There must be {{GPULimits/maxSamplersPerShaderStage|GPULimits.maxSamplersPerShaderStage}} or | ||
fewer |bindingDescriptor|s of type {{GPUBindingType/sampler}} visible on each shader stage in |descriptor|. | ||
|
||
At any point in the algorithm, if any of the above conditions are violated, run the following steps: |
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.
Instead of "at any point", it makes more sense to me to specify when these checks are done. (Otherwise a naive implementation supposedly has to run all of these checks after every step.)
If there's a step that checks if these conditions are validated, these two steps could be inlined under that.
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'm having trouble deciding the best way to reference the very long validation conditions in-line. I'd like to leave them where they are but point to them (e.g. "If [condition 1] is violated, return with error"). How should I link "condition 1" to its definition?
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.
Let's worry about this a little later when we have some more experience writing these rules and then refactor them to be consistent. I think it's clear enough for right now.
In shaders there are several texture types for each dimensionality depending on their component type. It can be either float, uint or sint, with maybe in the future depth/stencil if WebGPU allows reading such textures. The component type of a GPUTextureView's format must match the component type of its binding in the shader module. This is for several reasons: - Vulkan requires the following: "The Sampled Type of an OpTypeImage declaration must match the numeric format of the corresponding resource in type and signedness, as shown in the SPIR-V Sampled Type column of the Interpretation of Numeric Format table, or the values obtained by reading or sampling from this image are undefined." - It is also required in OpenGL for the texture units to be complete, a uint or sint texture unit used with a non-nearest sampler is incomplete and returns black texels. Similar constraints must exist in other APIs. To encode this compatibility constraint, a new member is added to GPUBindGroupLayoutBinding that is a new enum GPUTextureComponentType that give the component type of the texture.
This is the most common case and avoids having an optional dictionary member with no default value (but that still requires a value for texture bindings).
…ndGroupLayout internal slots
2cc86e5
to
e1c3acc
Compare
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 addressing my concerns!
I'm not fully satisfied with the relaxed rules for hasDynamicOffset
, we can continue here or as a follow-up.
unsigned long maxDynamicUniformBuffersPerPipelineLayout = 8; | ||
unsigned long maxDynamicStorageBuffersPerPipelineLayout = 4; | ||
unsigned long maxSampledTexturesPerShaderStage = 16; | ||
unsigned long maxSamplersPerShaderStage = 16; |
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.
Ok, now as I re-read it, it makes more sense. So we have shader stages and bind groups as two orthogonal things. The are two kinds of limits here: one kind that is a total across all shader stages and bind groups (XxxPerPipelineLayout), and one that is a total across all bind groups of each shader stage (XxxPerShaderStage).
Merging, since we said we'd take care of this two weeks ago. |
Following WebGPU change at gpuweb/gpuweb#427, this CL renames GPUBindGroupLayoutBinding dynamic to hasDynamicOffset. Bug: 877147 Change-Id: I5dce18178caae102911e64200415c607b65d9767 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1819316 Commit-Queue: François Beaufort <beaufort.francois@gmail.com> Reviewed-by: Corentin Wallez <cwallez@chromium.org> Reviewed-by: Kai Ninomiya <kainino@chromium.org> Cr-Commit-Position: refs/heads/master@{#699322}
* Add validation tests for the extensions of Query API - Validation tests for creating timestamp query set with/without timestamp query enabled - Validation tests for creating pipeline statistics query set with/without pipeline statistics query enabled * Update test parameters * Merge queries tests together * Fix typo
Not sure why the two commits from master aren't disappearing when I rebase and merge. I can squash all if needed.
Preview | Diff