Fix particles on WebGPU to respect format support flags properly

This commit is contained in:
Wojtek Figat
2026-03-02 23:06:01 +01:00
parent 3b2015e816
commit 23ebb0e754
10 changed files with 171 additions and 72 deletions

View File

@@ -8,97 +8,111 @@
/// <summary>
/// Which resources are supported for a given format and given device.
/// </summary>
API_ENUM(Attributes="Flags") enum class FormatSupport : int32
API_ENUM(Attributes="Flags") enum class FormatSupport : uint64
{
/// <summary>
/// No features supported.
/// </summary>
None = 0,
None = 0x0,
/// <summary>
/// Buffer resources supported.
/// </summary>
Buffer = 1,
Buffer = 0x1,
/// <summary>
/// Vertex buffers supported.
/// </summary>
VertexBuffer = 0x2,
/// <summary>
/// Vertex buffers supported.
/// [Deprecated in 1.12]
/// </summary>
InputAssemblyVertexBuffer = 2,
/// <summary>
/// Index buffers supported.
/// </summary>
IndexBuffer = 0x4,
/// <summary>
/// Index buffers supported.
/// [Deprecated in 1.12]
/// </summary>
InputAssemblyIndexBuffer = 4,
/// <summary>
/// Streaming output buffers supported.
/// </summary>
StreamOutputBuffer = 8,
StreamOutputBuffer = 0x8,
/// <summary>
/// 1D texture resources supported.
/// </summary>
Texture1D = 16,
Texture1D = 0x10,
/// <summary>
/// 2D texture resources supported.
/// </summary>
Texture2D = 32,
Texture2D = 0x20,
/// <summary>
/// 3D texture resources supported.
/// </summary>
Texture3D = 64,
Texture3D = 0x40,
/// <summary>
/// Cube texture resources supported.
/// </summary>
TextureCube = 128,
TextureCube = 0x80,
/// <summary>
/// The shader Load function for texture objects is supported.
/// </summary>
ShaderLoad = 256,
ShaderLoad = 0x100,
/// <summary>
/// The shader Sample function for texture objects is supported.
/// </summary>
ShaderSample = 512,
ShaderSample = 0x200,
/// <summary>
/// The shader SampleCmp and SampleCmpLevelZero functions for texture objects are supported.
/// </summary>
ShaderSampleComparison = 1024,
ShaderSampleComparison = 0x400,
/// <summary>
/// Unused.
/// [Deprecated in 1.12]
/// </summary>
ShaderSampleMonoText = 2048,
/// <summary>
/// Mipmaps are supported.
/// </summary>
Mip = 4096,
Mip = 0x1000,
/// <summary>
/// Automatic generation of mipmaps is supported.
/// [Deprecated in 1.12]
/// </summary>
MipAutogen = 8192,
/// <summary>
/// Render targets are supported.
/// </summary>
RenderTarget = 16384,
RenderTarget = 0x4000,
/// <summary>
/// Blend operations supported.
/// </summary>
Blendable = 32768,
Blendable = 0x8000,
/// <summary>
/// Depth stencils supported.
/// </summary>
DepthStencil = 65536,
DepthStencil = 0x10000,
/// <summary>
/// CPU locking supported.
@@ -108,67 +122,87 @@ API_ENUM(Attributes="Flags") enum class FormatSupport : int32
/// <summary>
/// Multisample antialiasing (MSAA) resolve operations are supported.
/// </summary>
MultisampleResolve = 262144,
MultisampleResolve = 0x40000,
/// <summary>
/// Format can be displayed on screen.
/// </summary>
Display = 524288,
Display = 0x80000,
/// <summary>
/// Format can't be cast to another format.
/// </summary>
CastWithinBitLayout = 1048576,
CastWithinBitLayout = 0x100000,
/// <summary>
/// Format can be used as a multi-sampled render target.
/// </summary>
MultisampleRenderTarget = 2097152,
MultisampleRenderTarget = 0x200000,
/// <summary>
/// Format can be used as a multi-sampled texture and read into a shader with the shader Load function.
/// </summary>
MultisampleLoad = 4194304,
MultisampleLoad = 0x400000,
/// <summary>
/// Format can be used with the shader gather function.
/// </summary>
ShaderGather = 8388608,
ShaderGather = 0x800000,
/// <summary>
/// Format supports casting when the resource is a back buffer.
/// </summary>
BackBufferCast = 16777216,
BackBufferCast = 0x1000000,
/// <summary>
/// Format can be used for an unordered access view.
/// </summary>
TypedUnorderedAccessView = 33554432,
TypedUnorderedAccessView = 0x2000000,
/// <summary>
/// Format can be used with the shader gather with comparison function.
/// </summary>
ShaderGatherComparison = 67108864,
ShaderGatherComparison = 0x4000000,
/// <summary>
/// Format can be used with the decoder output.
/// </summary>
DecoderOutput = 134217728,
DecoderOutput = 0x8000000,
/// <summary>
/// Format can be used with the video processor output.
/// </summary>
VideoProcessorOutput = 268435456,
VideoProcessorOutput = 0x10000000,
/// <summary>
/// Format can be used with the video processor input.
/// </summary>
VideoProcessorInput = 536870912,
VideoProcessorInput = 0x20000000,
/// <summary>
/// Format can be used with the video encoder.
/// </summary>
VideoEncoder = 1073741824,
VideoEncoder = 0x40000000,
/// <summary>
/// Format can be used as unorder access resource for read-only operations (shader load).
/// </summary>
UnorderedAccessReadOnly = 0x80000000,
/// <summary>
/// Format can be used as unorder access resource for write-only operations (shader store).
/// </summary>
UnorderedAccessWriteOnly = 0x100000000,
/// <summary>
/// Format can be used as unorder access resource for both read-write operations (shader load and store).
/// </summary>
UnorderedAccessReadWrite = 0x200000000,
/// <summary>
/// Format can be used as unorder access resource for read/write operations.
/// </summary>
UnorderedAccess = UnorderedAccessReadOnly | UnorderedAccessWriteOnly | UnorderedAccessReadWrite,
};
DECLARE_ENUM_OPERATORS(FormatSupport);

View File

@@ -400,6 +400,7 @@ bool GPUTexture::Init(const GPUTextureDescription& desc)
LOG(Warning, "Cannot create texture. Depth Stencil texture cannot have mip maps. Description: {0}", desc.ToString());
return true;
}
auto formatFeatures = device->GetFormatFeatures(desc.Format);
switch (desc.Dimensions)
{
case TextureDimensions::Texture:
@@ -409,6 +410,11 @@ bool GPUTexture::Init(const GPUTextureDescription& desc)
LOG(Warning, "Cannot create texture. Texture cannot have per slice views. Description: {0}", desc.ToString());
return true;
}
if (EnumHasNoneFlags(formatFeatures.Support, FormatSupport::Texture2D))
{
LOG(Warning, "Cannot create texture. Not supported format. Description: {0}", desc.ToString());
return true;
}
if (desc.Width <= 0 || desc.Height <= 0 || desc.ArraySize <= 0
|| desc.Width > device->Limits.MaximumTexture2DSize
|| desc.Height > device->Limits.MaximumTexture2DSize
@@ -449,6 +455,11 @@ bool GPUTexture::Init(const GPUTextureDescription& desc)
LOG(Warning, "Cannot create texture. Volume texture cannot have per slice map views if is not a render target. Description: {0}", desc.ToString());
return true;
}
if (EnumHasNoneFlags(formatFeatures.Support, FormatSupport::Texture3D))
{
LOG(Warning, "Cannot create texture. Not supported format. Description: {0}", desc.ToString());
return true;
}
if (desc.Width <= 0 || desc.Height <= 0 || desc.Depth <= 0
|| desc.Width > device->Limits.MaximumTexture3DSize
|| desc.Height > device->Limits.MaximumTexture3DSize
@@ -469,6 +480,11 @@ bool GPUTexture::Init(const GPUTextureDescription& desc)
LOG(Warning, "Cannot create texture. Cube texture cannot have per slice views. Description: {0}", desc.ToString());
return true;
}
if (EnumHasNoneFlags(formatFeatures.Support, FormatSupport::TextureCube))
{
LOG(Warning, "Cannot create texture. Not supported format. Description: {0}", desc.ToString());
return true;
}
if (desc.Width <= 0 || desc.ArraySize <= 0
|| desc.Width > device->Limits.MaximumTextureCubeSize
|| desc.Height > device->Limits.MaximumTextureCubeSize

View File

@@ -658,7 +658,10 @@ bool GPUDeviceDX11::Init()
}
UINT formatSupport = 0;
_device->CheckFormatSupport(dxgiFormat, &formatSupport);
FeaturesPerFormat[i] = FormatFeatures((MSAALevel)maxCount, (FormatSupport)formatSupport);
FormatSupport support = (FormatSupport)formatSupport;
if (EnumHasAllFlags(support, FormatSupport::ShaderLoad))
support |= FormatSupport::UnorderedAccess;
FeaturesPerFormat[i] = FormatFeatures((MSAALevel)maxCount, support);
}
// Driver extensions support

View File

@@ -786,7 +786,10 @@ bool GPUDeviceDX12::Init()
if (FAILED(_device->CheckFeatureSupport(D3D12_FEATURE_FORMAT_SUPPORT, &formatInfo, sizeof(formatInfo))))
formatInfo.Support1 = D3D12_FORMAT_SUPPORT1_NONE;
const MSAALevel maximumMultisampleCount = GetMaximumMultisampleCount(_device, dxgiFormat);
FeaturesPerFormat[i] = FormatFeatures(maximumMultisampleCount, (FormatSupport)formatInfo.Support1);
FormatSupport support = (FormatSupport)formatInfo.Support1;
if (EnumHasAllFlags(support, FormatSupport::ShaderLoad))
support |= FormatSupport::UnorderedAccess;
FeaturesPerFormat[i] = FormatFeatures(maximumMultisampleCount, support);
}
D3D12_FEATURE_DATA_D3D12_OPTIONS2 options2 = {};

View File

@@ -1769,13 +1769,11 @@ bool GPUDeviceVulkan::Init()
if (properties.linearTilingFeatures != 0 || properties.optimalTilingFeatures != 0)
support |= FormatSupport::Texture1D | FormatSupport::Texture2D | FormatSupport::Texture3D | FormatSupport::TextureCube;
CHECK_IMAGE_FORMAT(VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT, FormatSupport::ShaderLoad);
//VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT,
CHECK_IMAGE_FORMAT(VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT, FormatSupport::UnorderedAccess);
//VK_FORMAT_FEATURE_STORAGE_IMAGE_ATOMIC_BIT
CHECK_IMAGE_FORMAT(VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT, FormatSupport::RenderTarget);
CHECK_IMAGE_FORMAT(VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT, FormatSupport::Blendable);
CHECK_IMAGE_FORMAT(VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT, FormatSupport::DepthStencil);
//VK_FORMAT_FEATURE_BLIT_SRC_BIT
//VK_FORMAT_FEATURE_BLIT_DST_BIT
CHECK_IMAGE_FORMAT(VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT, FormatSupport::ShaderSample | FormatSupport::ShaderSampleComparison);
#undef CHECK_IMAGE_FORMAT
@@ -1783,8 +1781,7 @@ bool GPUDeviceVulkan::Init()
#define CHECK_BUFFER_FORMAT(bit, feature) if ((properties.bufferFeatures & bit) == bit) support |= feature
if (properties.bufferFeatures != 0)
support |= FormatSupport::Buffer;
//VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT
//VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT
CHECK_BUFFER_FORMAT(VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT, FormatSupport::UnorderedAccess);
//VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_ATOMIC_BIT
CHECK_BUFFER_FORMAT(VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT, FormatSupport::InputAssemblyVertexBuffer);
#undef CHECK_BUFFER_FORMAT

View File

@@ -89,12 +89,12 @@ bool GPUBufferWebGPU::OnInit()
bufferDesc.usage |= WGPUBufferUsage_MapRead | WGPUBufferUsage_MapWrite | WGPUBufferUsage_CopySrc;
break;
}
bufferDesc.size = _desc.Size;
bufferDesc.size = (_desc.Size + 3) & ~0x3; // Align up to the multiple of 4 bytes
bufferDesc.mappedAtCreation = _desc.InitData != nullptr && (bufferDesc.usage & WGPUBufferUsage_MapWrite);
Buffer = wgpuDeviceCreateBuffer(_device->Device, &bufferDesc);
if (!Buffer)
return true;
_memoryUsage = _desc.Size;
_memoryUsage = bufferDesc.size;
Usage = bufferDesc.usage;
// Initialize with a data if provided

View File

@@ -512,6 +512,8 @@ void GPUContextWebGPU::Flush()
void GPUContextWebGPU::UpdateBuffer(GPUBuffer* buffer, const void* data, uint32 size, uint32 offset)
{
if (size == 0)
return;
ASSERT(data);
ASSERT(buffer && buffer->GetSize() >= size + offset);
auto bufferWebGPU = (GPUBufferWebGPU*)buffer;
@@ -526,10 +528,10 @@ void GPUContextWebGPU::UpdateBuffer(GPUBuffer* buffer, const void* data, uint32
EndRenderPass();
// Synchronous upload via shared buffer
// TODO: test using map/unmap sequence
auto allocation = _device->DataUploader.Allocate(size - offset, WGPUBufferUsage_CopySrc | WGPUBufferUsage_CopyDst);
wgpuQueueWriteBuffer(_device->Queue, allocation.Buffer, allocation.Offset, data, size);
wgpuCommandEncoderCopyBufferToBuffer(Encoder, allocation.Buffer, allocation.Offset, bufferWebGPU->Buffer, offset, size);
auto sizeAligned = (size + 3) & ~0x3; // Number of bytes must be a multiple of 4 for both wgpuQueueWriteBuffer and wgpuCommandEncoderCopyBufferToBuffer
auto allocation = _device->DataUploader.Allocate(sizeAligned, WGPUBufferUsage_CopySrc | WGPUBufferUsage_CopyDst);
wgpuQueueWriteBuffer(_device->Queue, allocation.Buffer, allocation.Offset, data, sizeAligned);
wgpuCommandEncoderCopyBufferToBuffer(Encoder, allocation.Buffer, allocation.Offset, bufferWebGPU->Buffer, offset, sizeAligned);
}
else
{
@@ -547,7 +549,8 @@ void GPUContextWebGPU::CopyBuffer(GPUBuffer* dstBuffer, GPUBuffer* srcBuffer, ui
ASSERT(dstBuffer && srcBuffer);
auto srcBufferWebGPU = (GPUBufferWebGPU*)srcBuffer;
auto dstBufferWebGPU = (GPUBufferWebGPU*)dstBuffer;
wgpuCommandEncoderCopyBufferToBuffer(Encoder, srcBufferWebGPU->Buffer, srcOffset, dstBufferWebGPU->Buffer, dstOffset, size);
auto copySize = (size + 3) & ~0x3; // Number of bytes must be a multiple of 4 for wgpuCommandEncoderCopyBufferToBuffer
wgpuCommandEncoderCopyBufferToBuffer(Encoder, srcBufferWebGPU->Buffer, srcOffset, dstBufferWebGPU->Buffer, dstOffset, copySize);
}
void GPUContextWebGPU::UpdateTexture(GPUTexture* texture, int32 arrayIndex, int32 mipIndex, const void* data, uint32 rowPitch, uint32 slicePitch)
@@ -1003,7 +1006,7 @@ void GPUContextWebGPU::FlushBindGroup()
auto defaultTexture = _device->DefaultTexture[(int32)descriptor.ResourceType];
if (!defaultTexture)
{
LOG(Error, "Missing resource {} at slot {} of binding space {}", (int32)descriptor.ResourceType, descriptor.Slot, (int32)descriptor.BindingType);
LOG(Error, "Missing default resource {} at slot {} of binding space {}", (int32)descriptor.ResourceType, descriptor.Slot, (int32)descriptor.BindingType);
CRASH;
}
switch (descriptor.ResourceType)
@@ -1035,11 +1038,7 @@ void GPUContextWebGPU::FlushBindGroup()
if (ptr && ptr->BufferView)
entry.buffer = ptr->BufferView->Buffer;
if (!entry.buffer)
{
// Fallback
LOG(Error, "Missing resource {} at slot {} of binding space {}", (int32)descriptor.ResourceType, descriptor.Slot, (int32)descriptor.BindingType);
CRASH; // TODO: add default buffer as fallback (_device->DefaultBuffer)
}
entry.buffer = _device->DefaultBuffer; // Fallback
break;
}
case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
@@ -1056,7 +1055,7 @@ void GPUContextWebGPU::FlushBindGroup()
_dynamicOffsets.Add(uniform->Allocation.Offset);
}
else
CRASH; // TODO: add dummy buffer as fallback
LOG(Fatal, "Missing constant buffer at slot {}", descriptor.Slot);
break;
}
default:

View File

@@ -209,13 +209,14 @@ bool GPUDeviceWebGPU::Init()
FormatSupport::MultisampleRenderTarget |
FormatSupport::MultisampleResolve |
FormatSupport::MultisampleLoad;
auto supportsBasicStorage = FormatSupport::UnorderedAccessReadOnly | FormatSupport::UnorderedAccessWriteOnly;
#define ADD_FORMAT(pixelFormat, support)
FeaturesPerFormat[(int32)PixelFormat::R8_UNorm].Support |= supportsBuffer | supportsTexture | supportsRender | supportsMSAA;
FeaturesPerFormat[(int32)PixelFormat::R8_UInt].Support |= supportsBuffer | supportsTexture | supportsRender;
FeaturesPerFormat[(int32)PixelFormat::R8_SInt].Support |= supportsBuffer | supportsTexture | supportsRender;
FeaturesPerFormat[(int32)PixelFormat::R16_UInt].Support |= supportsBuffer | supportsTexture;
FeaturesPerFormat[(int32)PixelFormat::R16_SInt].Support |= supportsBuffer | supportsTexture;
FeaturesPerFormat[(int32)PixelFormat::R16_UInt].Support |= supportsBuffer | supportsTexture | FormatSupport::RenderTarget;
FeaturesPerFormat[(int32)PixelFormat::R16_SInt].Support |= supportsBuffer | supportsTexture | FormatSupport::RenderTarget;
FeaturesPerFormat[(int32)PixelFormat::R16_Float].Support |= supportsBuffer | supportsTexture | supportsRender | supportsMSAA;
FeaturesPerFormat[(int32)PixelFormat::R8G8_UNorm].Support |= supportsBuffer | supportsTexture;
FeaturesPerFormat[(int32)PixelFormat::R8G8_SNorm].Support |= supportsBuffer | supportsTexture;
@@ -223,32 +224,32 @@ bool GPUDeviceWebGPU::Init()
FeaturesPerFormat[(int32)PixelFormat::R8G8_SInt].Support |= supportsBuffer | supportsTexture;
FeaturesPerFormat[(int32)PixelFormat::R32_Float].Support |= supportsBuffer | supportsTexture | FormatSupport::RenderTarget;
FeaturesPerFormat[(int32)PixelFormat::R32_Float].Support & ~FormatSupport::ShaderSample;
FeaturesPerFormat[(int32)PixelFormat::R32_UInt].Support |= supportsBuffer | supportsTexture | FormatSupport::RenderTarget;
FeaturesPerFormat[(int32)PixelFormat::R32_SInt].Support |= supportsBuffer | supportsTexture | FormatSupport::RenderTarget;
FeaturesPerFormat[(int32)PixelFormat::R32_UInt].Support |= supportsBuffer | supportsTexture | FormatSupport::RenderTarget | FormatSupport::UnorderedAccess;
FeaturesPerFormat[(int32)PixelFormat::R32_SInt].Support |= supportsBuffer | supportsTexture | FormatSupport::RenderTarget | FormatSupport::UnorderedAccess;
FeaturesPerFormat[(int32)PixelFormat::R16G16_UInt].Support |= supportsBuffer | supportsTexture;
FeaturesPerFormat[(int32)PixelFormat::R16G16_SInt].Support |= supportsBuffer | supportsTexture;
FeaturesPerFormat[(int32)PixelFormat::R16G16_Float].Support |= supportsBuffer | supportsTexture | supportsRender | supportsMSAA;
FeaturesPerFormat[(int32)PixelFormat::R8G8B8A8_UNorm].Support |= supportsBuffer | supportsTexture | supportsRender | supportsMSAA;
FeaturesPerFormat[(int32)PixelFormat::R8G8B8A8_UNorm].Support |= supportsBuffer | supportsTexture | supportsRender | supportsMSAA | supportsBasicStorage;
FeaturesPerFormat[(int32)PixelFormat::R8G8B8A8_UNorm_sRGB].Support |= supportsBuffer | supportsTexture | supportsRender | supportsMSAA;
FeaturesPerFormat[(int32)PixelFormat::R8G8B8A8_SNorm].Support |= supportsBuffer | supportsTexture;
FeaturesPerFormat[(int32)PixelFormat::R8G8B8A8_UInt].Support |= supportsBuffer | supportsTexture;
FeaturesPerFormat[(int32)PixelFormat::R8G8B8A8_SInt].Support |= supportsBuffer | supportsTexture;
FeaturesPerFormat[(int32)PixelFormat::R8G8B8A8_SNorm].Support |= supportsBuffer | supportsTexture | supportsBasicStorage;
FeaturesPerFormat[(int32)PixelFormat::R8G8B8A8_UInt].Support |= supportsBuffer | supportsTexture | supportsBasicStorage;
FeaturesPerFormat[(int32)PixelFormat::R8G8B8A8_SInt].Support |= supportsBuffer | supportsTexture | supportsBasicStorage;
FeaturesPerFormat[(int32)PixelFormat::B8G8R8A8_UNorm].Support |= supportsBuffer | supportsTexture | supportsRender | supportsMSAA;
FeaturesPerFormat[(int32)PixelFormat::R10G10B10A2_UInt].Support |= supportsBuffer | supportsTexture;
FeaturesPerFormat[(int32)PixelFormat::R10G10B10A2_UNorm].Support |= supportsBuffer | supportsTexture | supportsRender | supportsMSAA;
FeaturesPerFormat[(int32)PixelFormat::R11G11B10_Float].Support |= supportsBuffer | supportsTexture;
FeaturesPerFormat[(int32)PixelFormat::R9G9B9E5_SharedExp].Support |= supportsBuffer | supportsTexture;
FeaturesPerFormat[(int32)PixelFormat::R32G32_Float].Support |= supportsBuffer | supportsTexture | FormatSupport::RenderTarget;
FeaturesPerFormat[(int32)PixelFormat::R32G32_Float].Support |= supportsBuffer | supportsTexture | FormatSupport::RenderTarget | supportsBasicStorage;
FeaturesPerFormat[(int32)PixelFormat::R32G32_Float].Support & ~FormatSupport::ShaderSample;
FeaturesPerFormat[(int32)PixelFormat::R32G32_UInt].Support |= supportsBuffer | supportsTexture | FormatSupport::RenderTarget;
FeaturesPerFormat[(int32)PixelFormat::R32G32_SInt].Support |= supportsBuffer | supportsTexture | FormatSupport::RenderTarget;
FeaturesPerFormat[(int32)PixelFormat::R16G16B16A16_UInt].Support |= supportsBuffer | supportsTexture;
FeaturesPerFormat[(int32)PixelFormat::R16G16B16A16_SInt].Support |= supportsBuffer | supportsTexture;
FeaturesPerFormat[(int32)PixelFormat::R16G16B16A16_Float].Support |= supportsBuffer | supportsTexture | supportsRender;
FeaturesPerFormat[(int32)PixelFormat::R16G16B16A16_UInt].Support |= supportsBuffer | supportsTexture | supportsBasicStorage;
FeaturesPerFormat[(int32)PixelFormat::R16G16B16A16_SInt].Support |= supportsBuffer | supportsTexture | supportsBasicStorage;
FeaturesPerFormat[(int32)PixelFormat::R16G16B16A16_Float].Support |= supportsBuffer | supportsTexture | supportsRender | supportsBasicStorage;
FeaturesPerFormat[(int32)PixelFormat::R32G32B32A32_Float].Support |= supportsBuffer | supportsTexture | FormatSupport::RenderTarget;
FeaturesPerFormat[(int32)PixelFormat::R32G32B32A32_Float].Support & ~FormatSupport::ShaderSample;
FeaturesPerFormat[(int32)PixelFormat::R32G32B32A32_UInt].Support |= supportsBuffer | supportsTexture | FormatSupport::RenderTarget;
FeaturesPerFormat[(int32)PixelFormat::R32G32B32A32_SInt].Support |= supportsBuffer | supportsTexture | FormatSupport::RenderTarget;
FeaturesPerFormat[(int32)PixelFormat::R32G32B32A32_UInt].Support |= supportsBuffer | supportsTexture | FormatSupport::RenderTarget | supportsBasicStorage;
FeaturesPerFormat[(int32)PixelFormat::R32G32B32A32_SInt].Support |= supportsBuffer | supportsTexture | FormatSupport::RenderTarget | supportsBasicStorage;
FeaturesPerFormat[(int32)PixelFormat::D16_UNorm].Support |= supportsBuffer | supportsTexture | supportsDepth;
FeaturesPerFormat[(int32)PixelFormat::D24_UNorm_S8_UInt].Support |= supportsBuffer | supportsTexture | supportsDepth;
FeaturesPerFormat[(int32)PixelFormat::D32_Float].Support |= supportsBuffer | supportsTexture | supportsDepth;
@@ -269,20 +270,47 @@ bool GPUDeviceWebGPU::Init()
FeaturesPerFormat[(int32)PixelFormat::R16G16B16A16_SInt].Support |= supportsMultisampling;
FeaturesPerFormat[(int32)PixelFormat::R16G16B16A16_Float].Support |= supportsMSAA;
FeaturesPerFormat[(int32)PixelFormat::R32_Float].Support |= supportsMultisampling;
FeaturesPerFormat[(int32)PixelFormat::R32G32_Float].Support |= supportsMultisampling;
FeaturesPerFormat[(int32)PixelFormat::R10G10B10A2_UInt].Support |= supportsMultisampling;
}
if (features.Contains(WGPUFeatureName_TextureFormatsTier1))
{
FeaturesPerFormat[(int32)PixelFormat::R8_SNorm].Support |= supportsBuffer | supportsTexture;
FeaturesPerFormat[(int32)PixelFormat::R16_UNorm].Support |= supportsBuffer | supportsTexture | supportsRender | supportsMSAA;
FeaturesPerFormat[(int32)PixelFormat::R16_SNorm].Support |= supportsBuffer | supportsTexture;
FeaturesPerFormat[(int32)PixelFormat::R16G16_UNorm].Support |= supportsBuffer | supportsTexture | supportsRender | supportsMultisampling;
FeaturesPerFormat[(int32)PixelFormat::R16G16_SNorm].Support |= supportsBuffer | supportsTexture | supportsRender | supportsMultisampling;
FeaturesPerFormat[(int32)PixelFormat::R16G16B16A16_UNorm].Support |= supportsBuffer | supportsTexture | supportsRender | supportsMultisampling;
FeaturesPerFormat[(int32)PixelFormat::R16G16B16A16_SNorm].Support |= supportsBuffer | supportsTexture | supportsRender | supportsMultisampling;
FeaturesPerFormat[(int32)PixelFormat::R8_UNorm].Support |= supportsBasicStorage;
FeaturesPerFormat[(int32)PixelFormat::R8_SNorm].Support |= supportsBuffer | supportsTexture | supportsBasicStorage;
FeaturesPerFormat[(int32)PixelFormat::R8_UInt].Support |= supportsBasicStorage;
FeaturesPerFormat[(int32)PixelFormat::R8_SInt].Support |= supportsBasicStorage;
FeaturesPerFormat[(int32)PixelFormat::R16_UNorm].Support |= supportsBuffer | supportsTexture | supportsRender | supportsMSAA | supportsBasicStorage;
FeaturesPerFormat[(int32)PixelFormat::R16_SNorm].Support |= supportsBuffer | supportsTexture | supportsBasicStorage;
//FeaturesPerFormat[(int32)PixelFormat::R16_UInt].Support |= supportsBasicStorage; // TODO: fix issues with particle indices buffer that could use it
FeaturesPerFormat[(int32)PixelFormat::R16_SInt].Support |= supportsBasicStorage;
FeaturesPerFormat[(int32)PixelFormat::R16_Float].Support |= supportsBasicStorage;
FeaturesPerFormat[(int32)PixelFormat::R16G16_UNorm].Support |= supportsBuffer | supportsTexture | supportsRender | supportsMultisampling | supportsBasicStorage;
FeaturesPerFormat[(int32)PixelFormat::R16G16_SNorm].Support |= supportsBuffer | supportsTexture | supportsRender | supportsMultisampling | supportsBasicStorage;
FeaturesPerFormat[(int32)PixelFormat::R16G16_UInt].Support |= supportsBasicStorage;
FeaturesPerFormat[(int32)PixelFormat::R16G16_SInt].Support |= supportsBasicStorage;
FeaturesPerFormat[(int32)PixelFormat::R16G16_Float].Support |= supportsBasicStorage;
FeaturesPerFormat[(int32)PixelFormat::R16G16B16A16_UNorm].Support |= supportsBuffer | supportsTexture | supportsRender | supportsMultisampling | supportsBasicStorage;
FeaturesPerFormat[(int32)PixelFormat::R16G16B16A16_SNorm].Support |= supportsBuffer | supportsTexture | supportsRender | supportsMultisampling | supportsBasicStorage;
FeaturesPerFormat[(int32)PixelFormat::R10G10B10A2_UNorm].Support |= supportsBasicStorage;
FeaturesPerFormat[(int32)PixelFormat::R11G11B10_Float].Support |= supportsBasicStorage;
}
if (features.Contains(WGPUFeatureName_TextureFormatsTier2))
{
FeaturesPerFormat[(int32)PixelFormat::R8_UNorm].Support |= FormatSupport::UnorderedAccessReadWrite;
FeaturesPerFormat[(int32)PixelFormat::R8_UInt].Support |= FormatSupport::UnorderedAccessReadWrite;
FeaturesPerFormat[(int32)PixelFormat::R8_SInt].Support |= FormatSupport::UnorderedAccessReadWrite;
FeaturesPerFormat[(int32)PixelFormat::R8G8B8A8_UNorm].Support |= FormatSupport::UnorderedAccessReadWrite;
FeaturesPerFormat[(int32)PixelFormat::R8G8B8A8_UInt].Support |= FormatSupport::UnorderedAccessReadWrite;
FeaturesPerFormat[(int32)PixelFormat::R8G8B8A8_SInt].Support |= FormatSupport::UnorderedAccessReadWrite;
FeaturesPerFormat[(int32)PixelFormat::R16_UInt].Support |= FormatSupport::UnorderedAccessReadWrite;
FeaturesPerFormat[(int32)PixelFormat::R16_SInt].Support |= FormatSupport::UnorderedAccessReadWrite;
FeaturesPerFormat[(int32)PixelFormat::R16_Float].Support |= FormatSupport::UnorderedAccessReadWrite;
FeaturesPerFormat[(int32)PixelFormat::R16G16B16A16_UInt].Support |= FormatSupport::UnorderedAccessReadWrite;
FeaturesPerFormat[(int32)PixelFormat::R16G16B16A16_SInt].Support |= FormatSupport::UnorderedAccessReadWrite;
FeaturesPerFormat[(int32)PixelFormat::R16G16B16A16_Float].Support |= FormatSupport::UnorderedAccessReadWrite;
FeaturesPerFormat[(int32)PixelFormat::R32G32B32A32_UInt].Support |= FormatSupport::UnorderedAccessReadWrite;
FeaturesPerFormat[(int32)PixelFormat::R32G32B32A32_SInt].Support |= FormatSupport::UnorderedAccessReadWrite;
FeaturesPerFormat[(int32)PixelFormat::R32G32B32A32_Float].Support |= FormatSupport::UnorderedAccessReadWrite;
}
if (features.Contains(WGPUFeatureName_Depth32FloatStencil8))
{
@@ -452,7 +480,7 @@ bool GPUDeviceWebGPU::Init()
TotalGraphicsMemory = 1024 * 1024 * 1024; // Dummy 1GB
// Create default samplers
// Create default resources
auto samplerDesc = GPUSamplerDescription::New();
#define INIT_SAMPLER(slot, filter, addressMode, compare) \
DefaultSamplers[slot] = New<GPUSamplerWebGPU>(this); \
@@ -467,6 +495,15 @@ bool GPUDeviceWebGPU::Init()
INIT_SAMPLER(4, GPUSamplerFilter::Point, GPUSamplerAddressMode::Clamp, GPUSamplerCompareFunction::Less);
INIT_SAMPLER(5, GPUSamplerFilter::Trilinear, GPUSamplerAddressMode::Clamp, GPUSamplerCompareFunction::Less);
#undef INIT_SAMPLER
{
WGPUBufferDescriptor bufferDesc = WGPU_BUFFER_DESCRIPTOR_INIT;
#if GPU_ENABLE_RESOURCE_NAMING
bufferDesc.label = WEBGPU_STR("DefaultBuffer");
#endif
bufferDesc.usage = WGPUBufferUsage_Storage;
bufferDesc.size = 64;
DefaultBuffer = wgpuDeviceCreateBuffer(Device, &bufferDesc);
}
// Setup commands processing
DataUploader._device = Device;
@@ -578,6 +615,11 @@ void GPUDeviceWebGPU::Dispose()
SAFE_DELETE_GPU_RESOURCES(DefaultSamplers);
SAFE_DELETE(_mainContext);
SAFE_DELETE(Adapter);
if (DefaultBuffer)
{
wgpuBufferRelease(DefaultBuffer);
DefaultBuffer = nullptr;
}
if (Queue)
{
wgpuQueueRelease(Queue);

View File

@@ -81,6 +81,7 @@ public:
WGPUQueue Queue = nullptr;
GPUSamplerWebGPU* DefaultSamplers[6] = {};
GPUTextureWebGPU* DefaultTexture[10] = {};
WGPUBuffer DefaultBuffer = nullptr;
GPUDataUploaderWebGPU DataUploader;
uint32 MinUniformBufferOffsetAlignment = 1;

View File

@@ -167,7 +167,11 @@ bool ParticleBuffer::AllocateSortBuffer()
const int32 sortedIndicesCount = Capacity * Emitter->Graph.SortModules.Count();
uint32 indexSize = sizeof(uint32);
PixelFormat indexFormat = PixelFormat::R32_UInt;
if (Capacity <= MAX_uint16)
auto r16Support = GPUDevice::Instance->GetFormatFeatures(PixelFormat::R16_UInt).Support;
auto indexFormatRequirements = FormatSupport::Buffer | FormatSupport::UnorderedAccessReadOnly;
if (Mode == ParticlesSimulationMode::GPU)
indexFormatRequirements |= FormatSupport::UnorderedAccess;
if (Capacity <= MAX_uint16 && EnumHasAllFlags(r16Support, indexFormatRequirements))
{
// 16-bit indices
indexSize = sizeof(uint16);