-
Notifications
You must be signed in to change notification settings - Fork 332
Description
Introduction
Viewport is used to do the transformation right before rasterization. It transforms vertices from normalized device coordinates to window coordinates. Scissor rectangle is used to do scissor test right after rasterization. It ensures the rasterized fragments/pixels are within a specified rectangle.
This document attempts to describe viewport and scissor test related features among three native graphics APIs, in order to discuss missing features in WebGPU idl.
Native APIs
D3D12
Viewport
D3D12 defines viewport via D3D12_VIEWPORT. It is listed as follow:
typedef struct D3D12_VIEWPORT {
FLOAT TopLeftX;
FLOAT TopLeftY;
FLOAT Width;
FLOAT Height;
FLOAT MinDepth;
FLOAT MaxDepth;
} D3D12_VIEWPORT;
We can set multiple viewports via ID3D12GraphicsCommandList::RSSetViewports in D3D12. And this is the only way to set viewport. Viewports are not included in D3D12_GRAPHICS_PIPELINE_STATE_DESC
or other state descriptors in D3D12. Function RSSetViewports
is listed as follow:
void RSSetViewports(
UINT NumViewports,
const D3D12_VIEWPORT *pViewports
);
Scissor Test
Likewise, we can set multiple scissor rectangles via ID3D12GraphicsCommandList::RSSetScissorRects. And this is the only way to set scissor rectangle. Scissor rectangles are not included in D3D12_GRAPHICS_PIPELINE_STATE_DESC
or other state descriptors in D3D12. Function RSSetScissorRects
is listed as follow:
void RSSetScissorRects(
UINT NumRects,
const D3D12_RECT *pRects
);
Each scissor rectangle is defined as D3D12_RECT, which is RECT. RECT is defined as follow:
typedef struct _RECT {
LONG left;
LONG top;
LONG right;
LONG bottom;
} RECT, *PRECT;
Currently D3D12 doesn't include a parameter like scissorEnable
to enable/disable scissor test, although D3D11 and some outdated versions of D3D12 do have this parameter in D3D11_GRAPHICS_PIPELINE_STATE_DESC
and D3D12_GRAPHICS_PIPELINE_STATE_DESC
.
Metal
Viewport
Metal can set one viewport via MTLRenderCommandEncoder::setViewport, and multiple viewports (an array of viewports) like D3D12 via MTLRenderCommandEncoder::setViewports.
The structure MTLViewport is the same as D3D12_VIEWPORT
, which includes 6 parameters with the same meanings.
Scissor Test
Metal can set one scissor rectangle via MTLRenderCommandEncoder::setScissorRect, and multiple scissor rectangles (an array of scissor rectangles) like D3D12 via MTLRenderCommandEncoder::setScissorRects.
The structure MTLScissorRect is similar to D3D12_RECT
. But it is a little different, it use (uint x, uint y, uint width, uint height). Note that the data types of all 4 parameters are uint. But they are long in D3D12. And Metal uses width and height, so there is no direction issue like top < bottom or top > bottom.
Metal doesn't include a parameter like scissorEnable
to enable/disable scissor test.
Vulkan
Viewport
Vulkan includes a viewport state named VkPipelineViewportStateCreateInfo, in which you can initialize multiple viewports. VkPipelineViewportStateCreateInfo
is a part of VkGraphicsPipelineCreateInfo
in Vulkan.
In addition, Vulkan can set multiple viewports via vkCmdSetViewport. It is a little bit different from setViewports function in D3D12 and Metal. Because Vulkan can update partial viewports of the viewports array in VkPipelineViewportStateCreateInfo
, with firstViewport
as an offset to the array. Of course, we can update all viewports by setting the fristViewport
to 0 and viewportCount
to the length of the array.
The structure VkViewport is the same as D3D12_VIEWPORT
, which includes 6 parameters with the same meaning.
Scissor Test
Likewise, Vulkan can initialize multiple scissor rectangles via VkPipelineViewportStateCreateInfo
, and it can update a part of scissor rectangles via vkCmdSetScissor, with firstScissor
as an offset to the array. We can also update all scissor rectangles by setting the fristScissor
to 0 and scissorCount
to the length of the array.
Scissor rectangle in Vulkan is like that in Metal, except that x and y parameters are int, not uint. The rectangle is described by (int x, int y, uint width, uint height) in Vulkan.
Vulkan doesn't include a parameter like scissorEnable
to enable/disable scissor test.
Conclusion and Proposal
-
Metal, D3D12 and Vulkan can support multiple viewports and multiple scissor rectangles. But only geometry shading will use multiple viewports and multiple scissor rectangles. WebGPU doesn't support geometry shading in its MVP (and 1.0?). As a result, supporting one viewport and one scissorRect is simple and straightforward for developers. However, we may support multiple viewports and multiple scissor rectangles for WebVR in future.
-
Metal, D3D12 and Vulkan can set viewport and scissor rectangle by some functions in similar manner. Viewport and scissor test is necessary for some use cases. So I think we should add these two functions into WebGPURenderPassEncoder.
void setViewport(float x, float y, float width, float height, float minDepth, float maxDepth);
void setScissorRect(u32 x, u32 y, u32 width, u32 height);
Note that I propose to use uint32 for scissor rect, but D3D12 uses long
for all parameters in scissor rect, and Vulkan uses int32
for x and y parameters. However, a negative value makes no sense here. So I propose to use uint32 to simplify it, just as Metal does.
-
Only Vulkan can support viewport and scissor rect in its
VkGraphicsPipelineCreateInfo
, so we might don't add viewport or scissor rect toWebGPURenderPipelineDescriptor
. -
Only D3D11 and some outdated versions of D3D12 can support
scissorEnable
in its graphics pipeline state descriptor, so we don't addscissorEnable
toWebGPURenderPipelineDescriptor
TODO
Update the WebGPU idl once we get consensus on this.