这是indexloc提供的服务,不要输入任何密码
Skip to content

Investigation: Render to 3D texture #4251

@haoxli

Description

@haoxli

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;
  • Format specifies the viewing format of RTV. It needs to be compatible with the format of resource and must not be any typeless format.
  • ViewDimension specifies the typed value of the resource to view as a render target. D3D12_RTV_DIMENSION_TEXTURE3D identifies the resource will be accessed as a 3d texture. It also determines which _RTV item to use in the following union struct.
  • Texture3D specifies subresources in a 3d texture that can be accessed.
typedef struct D3D12_TEX3D_RTV {
  UINT MipSlice;
  UINT FirstWSlice;
  UINT WSize;
} D3D12_TEX3D_RTV;
  • MipSlice specifies the index of the mipmap level to use mip slice in the RTV.
  • FirstWSlice specifies the first depth level to use in the RTV. It must be between 0 and the DepthOrArraySize-1 of the texture resource at the MipSlice.
  • WSize specifies the number of depth levels to use in the RTV, starting from FirstWSlice. A value of -1 indicates all depth slices from FirstWSlice.

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:

  • texture specifies the texture associated with render pass attachment.
  • level specifies the mipmap level of the texture used for rendering to the attachment.
  • slice specifies the array slice of the texture used for rendering to the attachment.
  • depthPlane specifies the depth plane of the 3d texture used for rendering to the attachment.

There are 2 differences from D3D12:

  1. The depthPlane restricts one depth slice of a 3d texture for rendering, not a range.
  2. 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 the texture is a texture view, the values of level and slice must 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;
  • image is a VkImage on which the view will be created. If the image is created with VK_IMAGE_TYPE_3D and used to create a 2d or 2d array view, VkImageCreateInfo::flags must contain VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT and must not contain any of VK_IMAGE_CREATE_SPARSE_BINDING_BIT, VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT, and VK_IMAGE_CREATE_SPARSE_ALIASED_BIT.
  • viewType is 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.
  • subresourceRange is 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.baseArrayLayer and subresourceRange.layerCount specify 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;
  • baseMipLevel is the first mipmap level accessible to the view.
  • levelCount is the number of mipmap levels (starting from baseMipLevel) accessible to the view. It must be 1 when creating 2d/2d array views on a 3d image.
  • baseArrayLayer is the first array layer accessible to the view. It must be less than the depth computed from baseMipLevel and extent.depth specified in VkImageCreateInfo when creating 2d/2d array views on 3d image.
  • layerCount is the number of array layers (starting from baseArrayLayer) accessible to the view. If layerCount is not VK_REMAINING_ARRAY_LAYERS, it must be non-zero and baseArrayLayer + layerCount must be less than or equal to the depth computed from baseMipLevel and extent.depth specified in VkImageCreateInfo when creating 2d/2d array views on 3d image. If viewType is VK_IMAGE_VIEW_TYPE_2D, layerCount must be 1 if it is not VK_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;

    ...
};
  • view is a renderable texture view which dimension must be "2d" or "3d".
  • depthSlice(new) is a depth slice (for 3d texture) in the view used for rendering to the attachment. It must be less than the depth slices number computed from view.baseMipLevel and view.texture.depthOrArrayLayers. Default to 0 and ignored for the view not created on 3d texture. Vulkan needs to create a new 2d/2d array views based on the depthSlice and the view.descriptor if the dimension of the view is "3d", then render to the new view.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions