diff --git a/Source/Engine/Graphics/GPULimits.h b/Source/Engine/Graphics/GPULimits.h
index f2e519e91..171bfdd12 100644
--- a/Source/Engine/Graphics/GPULimits.h
+++ b/Source/Engine/Graphics/GPULimits.h
@@ -8,97 +8,111 @@
///
/// Which resources are supported for a given format and given device.
///
-API_ENUM(Attributes="Flags") enum class FormatSupport : int32
+API_ENUM(Attributes="Flags") enum class FormatSupport : uint64
{
///
/// No features supported.
///
- None = 0,
+ None = 0x0,
///
/// Buffer resources supported.
///
- Buffer = 1,
+ Buffer = 0x1,
///
/// Vertex buffers supported.
///
+ VertexBuffer = 0x2,
+
+ ///
+ /// Vertex buffers supported.
+ /// [Deprecated in 1.12]
+ ///
InputAssemblyVertexBuffer = 2,
///
/// Index buffers supported.
///
+ IndexBuffer = 0x4,
+
+ ///
+ /// Index buffers supported.
+ /// [Deprecated in 1.12]
+ ///
InputAssemblyIndexBuffer = 4,
///
/// Streaming output buffers supported.
///
- StreamOutputBuffer = 8,
+ StreamOutputBuffer = 0x8,
///
/// 1D texture resources supported.
///
- Texture1D = 16,
+ Texture1D = 0x10,
///
/// 2D texture resources supported.
///
- Texture2D = 32,
+ Texture2D = 0x20,
///
/// 3D texture resources supported.
///
- Texture3D = 64,
+ Texture3D = 0x40,
///
/// Cube texture resources supported.
///
- TextureCube = 128,
+ TextureCube = 0x80,
///
/// The shader Load function for texture objects is supported.
///
- ShaderLoad = 256,
+ ShaderLoad = 0x100,
///
/// The shader Sample function for texture objects is supported.
///
- ShaderSample = 512,
+ ShaderSample = 0x200,
///
/// The shader SampleCmp and SampleCmpLevelZero functions for texture objects are supported.
///
- ShaderSampleComparison = 1024,
+ ShaderSampleComparison = 0x400,
///
/// Unused.
+ /// [Deprecated in 1.12]
///
ShaderSampleMonoText = 2048,
///
/// Mipmaps are supported.
///
- Mip = 4096,
+ Mip = 0x1000,
///
/// Automatic generation of mipmaps is supported.
+ /// [Deprecated in 1.12]
///
MipAutogen = 8192,
///
/// Render targets are supported.
///
- RenderTarget = 16384,
+ RenderTarget = 0x4000,
///
/// Blend operations supported.
///
- Blendable = 32768,
+ Blendable = 0x8000,
///
/// Depth stencils supported.
///
- DepthStencil = 65536,
+ DepthStencil = 0x10000,
///
/// CPU locking supported.
@@ -108,67 +122,87 @@ API_ENUM(Attributes="Flags") enum class FormatSupport : int32
///
/// Multisample antialiasing (MSAA) resolve operations are supported.
///
- MultisampleResolve = 262144,
+ MultisampleResolve = 0x40000,
///
/// Format can be displayed on screen.
///
- Display = 524288,
+ Display = 0x80000,
///
/// Format can't be cast to another format.
///
- CastWithinBitLayout = 1048576,
+ CastWithinBitLayout = 0x100000,
///
/// Format can be used as a multi-sampled render target.
///
- MultisampleRenderTarget = 2097152,
+ MultisampleRenderTarget = 0x200000,
///
/// Format can be used as a multi-sampled texture and read into a shader with the shader Load function.
///
- MultisampleLoad = 4194304,
+ MultisampleLoad = 0x400000,
///
/// Format can be used with the shader gather function.
///
- ShaderGather = 8388608,
+ ShaderGather = 0x800000,
///
/// Format supports casting when the resource is a back buffer.
///
- BackBufferCast = 16777216,
+ BackBufferCast = 0x1000000,
///
/// Format can be used for an unordered access view.
///
- TypedUnorderedAccessView = 33554432,
+ TypedUnorderedAccessView = 0x2000000,
///
/// Format can be used with the shader gather with comparison function.
///
- ShaderGatherComparison = 67108864,
+ ShaderGatherComparison = 0x4000000,
///
/// Format can be used with the decoder output.
///
- DecoderOutput = 134217728,
+ DecoderOutput = 0x8000000,
///
/// Format can be used with the video processor output.
///
- VideoProcessorOutput = 268435456,
+ VideoProcessorOutput = 0x10000000,
///
/// Format can be used with the video processor input.
///
- VideoProcessorInput = 536870912,
+ VideoProcessorInput = 0x20000000,
///
/// Format can be used with the video encoder.
///
- VideoEncoder = 1073741824,
+ VideoEncoder = 0x40000000,
+
+ ///
+ /// Format can be used as unorder access resource for read-only operations (shader load).
+ ///
+ UnorderedAccessReadOnly = 0x80000000,
+
+ ///
+ /// Format can be used as unorder access resource for write-only operations (shader store).
+ ///
+ UnorderedAccessWriteOnly = 0x100000000,
+
+ ///
+ /// Format can be used as unorder access resource for both read-write operations (shader load and store).
+ ///
+ UnorderedAccessReadWrite = 0x200000000,
+
+ ///
+ /// Format can be used as unorder access resource for read/write operations.
+ ///
+ UnorderedAccess = UnorderedAccessReadOnly | UnorderedAccessWriteOnly | UnorderedAccessReadWrite,
};
DECLARE_ENUM_OPERATORS(FormatSupport);
diff --git a/Source/Engine/Graphics/Textures/GPUTexture.cpp b/Source/Engine/Graphics/Textures/GPUTexture.cpp
index f2cd85b69..1d11a02df 100644
--- a/Source/Engine/Graphics/Textures/GPUTexture.cpp
+++ b/Source/Engine/Graphics/Textures/GPUTexture.cpp
@@ -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
diff --git a/Source/Engine/GraphicsDevice/DirectX/DX11/GPUDeviceDX11.cpp b/Source/Engine/GraphicsDevice/DirectX/DX11/GPUDeviceDX11.cpp
index a2b2c99f2..6b04abe89 100644
--- a/Source/Engine/GraphicsDevice/DirectX/DX11/GPUDeviceDX11.cpp
+++ b/Source/Engine/GraphicsDevice/DirectX/DX11/GPUDeviceDX11.cpp
@@ -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
diff --git a/Source/Engine/GraphicsDevice/DirectX/DX12/GPUDeviceDX12.cpp b/Source/Engine/GraphicsDevice/DirectX/DX12/GPUDeviceDX12.cpp
index 126673535..8b08eeada 100644
--- a/Source/Engine/GraphicsDevice/DirectX/DX12/GPUDeviceDX12.cpp
+++ b/Source/Engine/GraphicsDevice/DirectX/DX12/GPUDeviceDX12.cpp
@@ -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 = {};
diff --git a/Source/Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.cpp b/Source/Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.cpp
index 7299d26d1..58a756298 100644
--- a/Source/Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.cpp
+++ b/Source/Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.cpp
@@ -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
diff --git a/Source/Engine/GraphicsDevice/WebGPU/GPUBufferWebGPU.cpp b/Source/Engine/GraphicsDevice/WebGPU/GPUBufferWebGPU.cpp
index ecac70df1..5b172474e 100644
--- a/Source/Engine/GraphicsDevice/WebGPU/GPUBufferWebGPU.cpp
+++ b/Source/Engine/GraphicsDevice/WebGPU/GPUBufferWebGPU.cpp
@@ -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
diff --git a/Source/Engine/GraphicsDevice/WebGPU/GPUContextWebGPU.cpp b/Source/Engine/GraphicsDevice/WebGPU/GPUContextWebGPU.cpp
index c25bc8431..394a8397f 100644
--- a/Source/Engine/GraphicsDevice/WebGPU/GPUContextWebGPU.cpp
+++ b/Source/Engine/GraphicsDevice/WebGPU/GPUContextWebGPU.cpp
@@ -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:
diff --git a/Source/Engine/GraphicsDevice/WebGPU/GPUDeviceWebGPU.cpp b/Source/Engine/GraphicsDevice/WebGPU/GPUDeviceWebGPU.cpp
index adf413de1..f07d01739 100644
--- a/Source/Engine/GraphicsDevice/WebGPU/GPUDeviceWebGPU.cpp
+++ b/Source/Engine/GraphicsDevice/WebGPU/GPUDeviceWebGPU.cpp
@@ -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(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);
diff --git a/Source/Engine/GraphicsDevice/WebGPU/GPUDeviceWebGPU.h b/Source/Engine/GraphicsDevice/WebGPU/GPUDeviceWebGPU.h
index 76dc14f5d..d928bdcf4 100644
--- a/Source/Engine/GraphicsDevice/WebGPU/GPUDeviceWebGPU.h
+++ b/Source/Engine/GraphicsDevice/WebGPU/GPUDeviceWebGPU.h
@@ -81,6 +81,7 @@ public:
WGPUQueue Queue = nullptr;
GPUSamplerWebGPU* DefaultSamplers[6] = {};
GPUTextureWebGPU* DefaultTexture[10] = {};
+ WGPUBuffer DefaultBuffer = nullptr;
GPUDataUploaderWebGPU DataUploader;
uint32 MinUniformBufferOffsetAlignment = 1;
diff --git a/Source/Engine/Particles/ParticlesData.cpp b/Source/Engine/Particles/ParticlesData.cpp
index 287a97b0b..11edc01ea 100644
--- a/Source/Engine/Particles/ParticlesData.cpp
+++ b/Source/Engine/Particles/ParticlesData.cpp
@@ -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);