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);