You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Viewport rect must lie entirely within the current attachment size? #373
The current setViewport API in WebGPU doesn't require this. The viewport rect can be bigger than the current attachment size, or it can be set to somewhere outside of the attachment size.
When I implement this API in Dawn project, I obey the WebGPU's rule and break Metal's requirement, the tests (outside of current attachment size) can pass on Metal backend even the Metal validation layer is on. Looks like Metal's implementation doesn't follow its documentation on this.
Say the attachment's (x, y, w, h) = {0, 0, 4, 4}. The viewport rect is {0, 0, 8, 8}, or {-2, -2, 4, 4} or something like this.
What do you think, @litherum , @grorg , @JusSn ? Can you verify this with Metal team? BTW, I can find similar statement in Metal documentation for SetScissorRect that the scissor rect must lie entirely inside the attachment. And we do need to obey this rule.
@kvark , that's an obvious choice. But I am not sure about it.
I am not an app developer. But when I play with a canvas/image/video or something like that and I resize the window, I can see that two different designs are quite common: 1) the rendering result in canvas/image/video will shrink or enlarge as the window changes its size, and every object in the scene changes its size in pixel. As a result, you can always see the entire rendering result, 2) the rendering result keep the same size, every object in the scene never change its size in pixel. As a result, parts of its area are obscured when the window resizes to a smaller one, or the background color (like black) in extra area is showed when the window resizes to a larger one.
For the 2) situation, I think it might be implemented via changing the back buffer size while keeping the viewport rect when you resize the window. If so, the viewport rect might be outside of the current attachment (or back buffer). Well, if we say viewport rect must lie within the attachment, I guess we can still implement the 2) design (but more difficult?) for webgpu-based canvas if some developers want that design for their apps.
WebGL allows oversized viewports, though Firefox does issue a console warning in this case.
Viewport and scissor are not changed automatically on resize.
There are cases where an application may want to use an oversized viewport (I have had one to be honest), but if one the underlying API's says it can't (even it can now), it is likely asking for trouble allowing for it.
I think it would only come up if you're trying to set a fixed-size viewport and you don't handle the case where the window gets resized to smaller than that.
The Vulkan restrictions seem to all be device limits, independent of the attachment size.
Resolution: Validate setViewport is within the attachment. Continue to investigate the following:
Flipped viewports (I think we already have an investigation and possibly a decision on this, just need to find it. Maybe Investigation: Viewport and Scissor Test #120, in which it's mentioned that this requires VK_KHR_maintenance1.)
Scissor restrictions (Metal doesn't allow zero-sized scissor rectangle. So if the scissor rect is entirely outside the attachment, we can't just clamp it, because it will end up being zero-sized. We can't no-op draw calls because of vertex shader storage writes.)
This might be a little bit silly, but there is an idea to mess with Metal viewport in order to make sure the draw calls are not rasterized. I.e. if the render area has at least 2 pixels, we can make the viewport such that it is fully within one pixel (or no pixels at all?), and the scissor in the another pixel. This doesn't answer the question of what to do if there is only 1x1 rendering :)
I'm confused now about Metal's setViewport (linked in OP). It appears that Metal has removed the sentence that Yunchao quoted, and it no longer says the viewport has to be within the attachment. I'm assuming this was lifted in a later revision of Metal, but which one?? and is it retroactive?
It was removed somewhere between 2019-06-18 and now. The documentation page still says "iOS 8.0+, macOS 10.11+" which technically implies it's retroactive, but would need confirmation from @litherum@grorg.
IIRC, when I raised that issue, Metal could actually allow that behavior (viewport size can be larger than attachment size), which means that the behavior on Metal conflicts with its documentation at that time. I wrote end2end tests, they can pass on Metal. Well, it is understandable because document may be outdated at that time. And the document was updated at some time.
The 2x limit is not for 2x the current viewport size, but for 2x the maximum texture size, which WebGPU mandates is at least 8192, much larger than I would expect most web page sizes to be. I don't think it's likely you'll have viewport sizes below -16384 or above 16384.
viewportBoundsRange[2] is the [minimum, maximum] range that the corners of a viewport must be contained in. This range must be at least [-2 × size, 2 × size - 1], where size = max(maxViewportDimensions[0], maxViewportDimensions[1]). See Controlling the Viewport.
...and maxViewportDimensions is defined as:
maxViewportDimensions[2] are the maximum viewport dimensions in the X (width) and Y (height) dimensions, respectively. The maximum viewport dimensions must be greater than or equal to the largest image which can be created and used as a framebuffer attachment. See Controlling the Viewport.
...and the following note regarding viewportsBoundsRange:
The intent of the viewportBoundsRange limit is to allow a maximum sized viewport to be arbitrarily shifted relative to the output target as long as at least some portion intersects. This would give a bounds limit of [-size + 1, 2 × size - 1] which would allow all possible non-empty-set intersections of the output target and the viewport. Since these numbers are typically powers of two, picking the signed number range using the smallest possible number of bits ends up with the specified range.
We should probably check if this definition is the same all the way back to Vulkan 1.0.
@kdashg assuming I understand 'polyfill' right: you can't simply clip an out-of-bounds viewport rectangle before it enters WebGPU, because that would distort the clipspace-to-screenspace(?) transform (that's also the reason why this can't be trivially handled in an engine layer, you would need to undo the distorted transform in the vertex shader).
KN: Shouldn't even need polyfilling, all backends support it
BJ: Except Vulkan has detailed limits for this.
KN: IIUC Vulkan requires those limits to be at least 2*max texture size, and that would work on other backends, so can just make that the hard limit. (not introduce a new limit).
KG: Ok! I think we’re just waiting on a PR to relax this [somewhat].
BJ: Will likely pick it up
AB: What about zero-area viewport? Requires Vulkan 1.1 or maintenance1.
KN: We already require 1.1/maintenance1.
BJ: Use case?
AB: Unreal Engine uses it in multiview stuff for turning off a view, or something.
Activity
kvark commentedon Jul 22, 2019
I don't think there is a downside for us to require both viewport and scissor rects to be limited to the render pass attachments size.
Richard-Yunchao commentedon Jul 22, 2019
@kvark , that's an obvious choice. But I am not sure about it.
I am not an app developer. But when I play with a canvas/image/video or something like that and I resize the window, I can see that two different designs are quite common: 1) the rendering result in canvas/image/video will shrink or enlarge as the window changes its size, and every object in the scene changes its size in pixel. As a result, you can always see the entire rendering result, 2) the rendering result keep the same size, every object in the scene never change its size in pixel. As a result, parts of its area are obscured when the window resizes to a smaller one, or the background color (like black) in extra area is showed when the window resizes to a larger one.
For the 2) situation, I think it might be implemented via changing the back buffer size while keeping the viewport rect when you resize the window. If so, the viewport rect might be outside of the current attachment (or back buffer). Well, if we say viewport rect must lie within the attachment, I guess we can still implement the 2) design (but more difficult?) for webgpu-based canvas if some developers want that design for their apps.
kvark commentedon Jul 23, 2019
@Richard-Yunchao good point!
@jdashg what does WebGL do today to handle resize? Does it care about portable behavior during resize?
kdashg commentedon Jul 23, 2019
WebGL allows oversized viewports, though Firefox does issue a console warning in this case.
Viewport and scissor are not changed automatically on resize.
krogovin commentedon Aug 8, 2019
There are cases where an application may want to use an oversized viewport (I have had one to be honest), but if one the underlying API's says it can't (even it can now), it is likely asking for trouble allowing for it.
kainino0x commentedon Aug 25, 2020
This came up again in gpuweb/cts#276 and #850 (comment).
We need to figure out what the rules are for both viewports and scissor rectangles.
For viewports I think the two options are:
For scissor:
Kangz commentedon Aug 31, 2020
There's quite some restrictions around
setViewportin Vulkan. Maybe we could restrict it to be inside the attachment.I'm not sure why this matters because the viewport is set locally to a render pass, and the attachment size is constant during a render pass.
kainino0x commentedon Aug 31, 2020
I think it would only come up if you're trying to set a fixed-size viewport and you don't handle the case where the window gets resized to smaller than that.
The Vulkan restrictions seem to all be device limits, independent of the attachment size.
kainino0x commentedon Sep 14, 2020
Resolution: Validate setViewport is within the attachment. Continue to investigate the following:
kvark commentedon Sep 15, 2020
This might be a little bit silly, but there is an idea to mess with Metal viewport in order to make sure the draw calls are not rasterized. I.e. if the render area has at least 2 pixels, we can make the viewport such that it is fully within one pixel (or no pixels at all?), and the scissor in the another pixel. This doesn't answer the question of what to do if there is only 1x1 rendering :)
kainino0x commentedon Sep 15, 2020
I'm confused now about Metal's setViewport (linked in OP). It appears that Metal has removed the sentence that Yunchao quoted, and it no longer says the viewport has to be within the attachment. I'm assuming this was lifted in a later revision of Metal, but which one?? and is it retroactive?
kainino0x commentedon Sep 15, 2020
It was removed somewhere between 2019-06-18 and now. The documentation page still says "iOS 8.0+, macOS 10.11+" which technically implies it's retroactive, but would need confirmation from @litherum @grorg.
Richard-Yunchao commentedon Sep 15, 2020
IIRC, when I raised that issue, Metal could actually allow that behavior (viewport size can be larger than attachment size), which means that the behavior on Metal conflicts with its documentation at that time. I wrote end2end tests, they can pass on Metal. Well, it is understandable because document may be outdated at that time. And the document was updated at some time.
36 remaining items
magcius commentedon Oct 11, 2023
The 2x limit is not for 2x the current viewport size, but for 2x the maximum texture size, which WebGPU mandates is at least 8192, much larger than I would expect most web page sizes to be. I don't think it's likely you'll have viewport sizes below -16384 or above 16384.
floooh commentedon Oct 11, 2023
To quote the relevant parts from the Vulkan documentation (https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceLimits.html)
...and maxViewportDimensions is defined as:
...and the following note regarding viewportsBoundsRange:
We should probably check if this definition is the same all the way back to Vulkan 1.0.
kainino0x commentedon Oct 11, 2023
Ah, sorry, I misremembered or never correctly understood what the -2x..2x meant. Thanks for the clarification.
kainino0x commentedon Nov 25, 2024
Another request for this feature in #4335
kdashg commentedon Dec 4, 2024
Can we just polyfill this?
floooh commentedon Dec 4, 2024
@kdashg assuming I understand 'polyfill' right: you can't simply clip an out-of-bounds viewport rectangle before it enters WebGPU, because that would distort the clipspace-to-screenspace(?) transform (that's also the reason why this can't be trivially handled in an engine layer, you would need to undo the distorted transform in the vertex shader).
Kangz commentedon Jan 27, 2025
GPU Web WG 2024-12-04 Atlantic-time
floooh commentedon Jan 31, 2025
I'm very happy that this got resolved :)
[graphite] Intersect scissor and not viewport with attachment