-
Notifications
You must be signed in to change notification settings - Fork 345
Description
Motivation
The feature of rendering to 3d texture is requested in #2877, which has been supported in all APIs WebGPU will target.
- D3D12 and Metal support rendering to a 3d texture by 3d texture view.
- Vulkan supports rendering to a 3d texture by 2d/2d array texture views in Vulkan 1.1 core.
This report investigates how to support rendering to 3d texture in WebGPU. The texture view and render attachment we discuss next will focus on 3d texture. And the texture usage and format required for 3d texture/view as a render attachment are the same as 2d texture/view, so I won't repeat them here.
Native APIs
D3D12
In D3D12, we can directly render to the slices of a 3d texture using 3d render target view created by ID3D12Device::CreateRenderTargetView() with D3D12_TEX3D_RTV struct in D3D12_RENDER_TARGET_VIEW_DESC.
typedef struct D3D12_RENDER_TARGET_VIEW_DESC {
DXGI_FORMAT Format;
D3D12_RTV_DIMENSION ViewDimension;
union {
D3D12_BUFFER_RTV Buffer;
D3D12_TEX1D_RTV Texture1D;
D3D12_TEX1D_ARRAY_RTV Texture1DArray;
D3D12_TEX2D_RTV Texture2D;
D3D12_TEX2D_ARRAY_RTV Texture2DArray;
D3D12_TEX2DMS_RTV Texture2DMS;
D3D12_TEX2DMS_ARRAY_RTV Texture2DMSArray;
D3D12_TEX3D_RTV Texture3D;
};
} D3D12_RENDER_TARGET_VIEW_DESC;
Formatspecifies the viewing format of RTV. It needs to be compatible with the format of resource and must not be any typeless format.ViewDimensionspecifies the typed value of the resource to view as a render target.D3D12_RTV_DIMENSION_TEXTURE3Didentifies the resource will be accessed as a 3d texture. It also determines which _RTV item to use in the following union struct.Texture3Dspecifies subresources in a 3d texture that can be accessed.
typedef struct D3D12_TEX3D_RTV {
UINT MipSlice;
UINT FirstWSlice;
UINT WSize;
} D3D12_TEX3D_RTV;
MipSlicespecifies the index of the mipmap level to use mip slice in the RTV.FirstWSlicespecifies the first depth level to use in the RTV. It must be between 0 and the DepthOrArraySize-1 of the texture resource at theMipSlice.WSizespecifies the number of depth levels to use in the RTV, starting fromFirstWSlice. A value of -1 indicates all depth slices fromFirstWSlice.
Metal
In Metal, newTextureViewWithPixelFormat()can create the 3d view on a 3d texture with the type MTLTextureType3D. But it only can restrict the range of mip levels and array slices for subresource that can be accessed, the slices range must be (0, 1) for 3d texture, there is no parameter to restrict the range of depth slices like D3D12, which means all depth slices of 3d texture can be accessed in the view.
On iOS 8.0+ and macOS 10.11+, Metal provides depthPlane property in MTLRenderPassAttachmentDescriptor to restrict depth slice for 3d texture bound as a render target, it has following properties:
texturespecifies the texture associated with render pass attachment.levelspecifies the mipmap level of the texture used for rendering to the attachment.slicespecifies the array slice of the texture used for rendering to the attachment.depthPlanespecifies the depth plane of the 3d texture used for rendering to the attachment.
There are 2 differences from D3D12:
- The
depthPlanerestricts one depth slice of a 3d texture for rendering, not a range. - Metal has no texture view object, the return value of
makeTextureView()is still a texture object, reinterpreting a subresource of the calling texture object, if thetextureis a texture view, the values oflevelandslicemust be based on the number of the mipmap levels and array slices of the new texture view, not the calling texture.
Vulkan
Vulkan also does not support to specify the depth slice range for 3d texture in VkImageSubresourceRange struct when creating texture view, and there is no any property in render attachment to specify the depth slice of a 3d texture used for rendering at framebuffer creation.
Instead, Vulkan allows to render to 2d/2d array views created from a 3d texture(disallowed in D3D12/Metal) from VK_KHR_maintenance1 that's included in core Vulkan 1.1.
typedef struct VkImageViewCreateInfo {
VkStructureType sType;
const void* pNext;
VkImageViewCreateFlags flags;
VkImage image;
VkImageViewType viewType;
VkFormat format;
VkComponentMapping components;
VkImageSubresourceRange subresourceRange;
} VkImageViewCreateInfo;
imageis a VkImage on which the view will be created. If theimageis created withVK_IMAGE_TYPE_3Dand used to create a 2d or 2d array view, VkImageCreateInfo::flags must containVK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BITand must not contain any ofVK_IMAGE_CREATE_SPARSE_BINDING_BIT,VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT, andVK_IMAGE_CREATE_SPARSE_ALIASED_BIT.viewTypeis a VkImageViewType value specifying the type of the image view. It must be compatible with the type of image as shown in the view type compatibility table.subresourceRangeis a VkImageSubresourceRange structure selecting the set of mipmap levels and array layers to be accessible to the view. When it is used to create the 2d/2d array view of a 3d image,subresourceRange.baseArrayLayerandsubresourceRange.layerCountspecify the first slice index and the number of depth slices to include in the created image view.
typedef struct VkImageSubresourceRange {
VkImageAspectFlags aspectMask;
uint32_t baseMipLevel;
uint32_t levelCount;
uint32_t baseArrayLayer;
uint32_t layerCount;
} VkImageSubresourceRange;
baseMipLevelis the first mipmap level accessible to the view.levelCountis the number of mipmap levels (starting frombaseMipLevel) accessible to the view. It must be 1 when creating 2d/2d array views on a 3d image.baseArrayLayeris the first array layer accessible to the view. It must be less than the depth computed frombaseMipLevelandextent.depthspecified inVkImageCreateInfowhen creating 2d/2d array views on 3d image.layerCountis the number of array layers (starting from baseArrayLayer) accessible to the view. IflayerCountis notVK_REMAINING_ARRAY_LAYERS, it must be non-zero andbaseArrayLayer+layerCountmust be less than or equal to the depth computed frombaseMipLevelandextent.depthspecified inVkImageCreateInfowhen creating 2d/2d array views on 3d image. IfviewTypeisVK_IMAGE_VIEW_TYPE_2D,layerCountmust be 1 if it is notVK_REMAINING_ARRAY_LAYERS, otherwise the remaining number of layers must be 1.
Proposal
Texture View
In WebGPU, it only allows to create the 3d texture view on a 3d texture(see the investigation), that means we only can bind the 3d texture view as color attachment when rendering to 3d texture. The GPUTexture.createView() in WebGPU could meet the requirement and don't need any changes.
Color Attachment
According to the limitation on Metal, we only can specify a single depth slice of 3d texture view in GPURenderPassColorAttachment.
partial dictionary GPURenderPassColorAttachment {
required GPUTextureView view;
...
GPUIntegerCoordinate depthSlice;
...
};
viewis a renderable texture view which dimension must be "2d" or "3d".depthSlice(new) is a depth slice (for 3d texture) in theviewused for rendering to the attachment. It must be less than the depth slices number computed fromview.baseMipLevelandview.texture.depthOrArrayLayers. Default to 0 and ignored for theviewnot created on 3d texture. Vulkan needs to create a new 2d/2d array views based on thedepthSliceand theview.descriptorif the dimension of theviewis "3d", then render to the new view.