diff --git a/Source/Engine/GraphicsDevice/Vulkan/Types.h b/Source/Engine/GraphicsDevice/Vulkan/Types.h index 1bb45fae5..848278f87 100644 --- a/Source/Engine/GraphicsDevice/Vulkan/Types.h +++ b/Source/Engine/GraphicsDevice/Vulkan/Types.h @@ -41,6 +41,7 @@ enum class SpirvShaderResourceType TextureCube = 7, Texture1DArray = 8, Texture2DArray = 9, + MAX }; enum class SpirvShaderResourceBindingType : byte diff --git a/Source/Engine/GraphicsDevice/WebGPU/GPUBufferWebGPU.cpp b/Source/Engine/GraphicsDevice/WebGPU/GPUBufferWebGPU.cpp index eeded8e92..ecac70df1 100644 --- a/Source/Engine/GraphicsDevice/WebGPU/GPUBufferWebGPU.cpp +++ b/Source/Engine/GraphicsDevice/WebGPU/GPUBufferWebGPU.cpp @@ -66,7 +66,7 @@ bool GPUBufferWebGPU::OnInit() bufferDesc.usage |= WGPUBufferUsage_Vertex; else if (EnumHasAllFlags(_desc.Flags, GPUBufferFlags::Argument)) bufferDesc.usage |= WGPUBufferUsage_Indirect; - if (IsUnorderedAccess()) + if (IsUnorderedAccess() || IsShaderResource()) // SRV buffers need to be bind as read-only storage bufferDesc.usage |= WGPUBufferUsage_Storage; switch (_desc.Usage) { diff --git a/Source/Engine/GraphicsDevice/WebGPU/GPUContextWebGPU.cpp b/Source/Engine/GraphicsDevice/WebGPU/GPUContextWebGPU.cpp index 2111d9629..d7e4cb710 100644 --- a/Source/Engine/GraphicsDevice/WebGPU/GPUContextWebGPU.cpp +++ b/Source/Engine/GraphicsDevice/WebGPU/GPUContextWebGPU.cpp @@ -347,8 +347,10 @@ void GPUContextWebGPU::UpdateCB(GPUConstantBuffer* cb, const void* data) if (size != 0) { // Allocate a chunk of memory in a shared page allocator - auto allocation = _device->DataUploader.Allocate(size, WGPUBufferUsage_Uniform | WGPUBufferUsage_CopyDst, _minUniformBufferOffsetAlignment); + uint32 alignedSize = Math::AlignUp(size, 16); // Uniform buffers must be aligned to 16 bytes + auto allocation = _device->DataUploader.Allocate(alignedSize, WGPUBufferUsage_Uniform | WGPUBufferUsage_CopyDst, _minUniformBufferOffsetAlignment); cbWebGPU->Allocation = allocation; + cbWebGPU->AllocationSize = alignedSize; // TODO: consider holding CPU-side staging buffer and copying data to the GPU buffer in a single batch for all uniforms (before flushing the active command encoder) wgpuQueueWriteBuffer(_device->Queue, allocation.Buffer, allocation.Offset, data, size); _bindGroupDirty = true; @@ -944,7 +946,13 @@ void GPUContextWebGPU::FlushBindGroup() if (!entry.textureView) { // Fallback - view = _device->DefaultTexture->View(0); + 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); + CRASH; + } + view = defaultTexture->View(0); ptr = (GPUResourceViewPtrWebGPU*)view->GetNativePtr(); entry.textureView = ptr->TextureView->View; } @@ -974,7 +982,7 @@ void GPUContextWebGPU::FlushBindGroup() if (uniform && uniform->Allocation.Buffer) { entry.buffer = uniform->Allocation.Buffer; - entry.size = uniform->GetSize(); + entry.size = uniform->AllocationSize; _dynamicOffsets.Add(uniform->Allocation.Offset); } else @@ -988,7 +996,7 @@ void GPUContextWebGPU::FlushBindGroup() { entry.buffer = uniform->Allocation.Buffer; entry.offset = uniform->Allocation.Offset; - entry.size = uniform->GetSize(); + entry.size = uniform->AllocationSize; } else CRASH; // TODO: add dummy buffer as fallback diff --git a/Source/Engine/GraphicsDevice/WebGPU/GPUContextWebGPU.h b/Source/Engine/GraphicsDevice/WebGPU/GPUContextWebGPU.h index 0b8852e51..9f392bae2 100644 --- a/Source/Engine/GraphicsDevice/WebGPU/GPUContextWebGPU.h +++ b/Source/Engine/GraphicsDevice/WebGPU/GPUContextWebGPU.h @@ -75,6 +75,10 @@ private: Array> _pendingClears; GPUResourceView* _shaderResources[GPU_MAX_SR_BINDED]; GPUResourceView* _storageResources[GPU_MAX_SR_BINDED]; + GPUResourceView** _resourceTables[(int32)SpirvShaderResourceBindingType::MAX]; +#if ENABLE_ASSERTION + uint32 _resourceTableSizes[(int32)SpirvShaderResourceBindingType::MAX]; +#endif public: GPUContextWebGPU(GPUDeviceWebGPU* device); diff --git a/Source/Engine/GraphicsDevice/WebGPU/GPUDeviceWebGPU.cpp b/Source/Engine/GraphicsDevice/WebGPU/GPUDeviceWebGPU.cpp index a150a6270..3a3fceddc 100644 --- a/Source/Engine/GraphicsDevice/WebGPU/GPUDeviceWebGPU.cpp +++ b/Source/Engine/GraphicsDevice/WebGPU/GPUDeviceWebGPU.cpp @@ -18,6 +18,7 @@ #if BUILD_DEBUG #include "Engine/Core/Collections/Sorting.h" #endif +#include "Engine/GraphicsDevice/Vulkan/Types.h" #include "Engine/Graphics/PixelFormatExtensions.h" #include "Engine/Engine/Engine.h" #include "Engine/Profiler/ProfilerMemory.h" @@ -182,8 +183,11 @@ bool GPUDeviceWebGPU::Init() if (wgpuAdapterGetLimits(Adapter->Adapter, &limits) == WGPUStatus_Success) { MinUniformBufferOffsetAlignment = limits.minUniformBufferOffsetAlignment; + Limits.HasDepthAsSRV = true; + Limits.HasReadOnlyDepth = true; Limits.HasDepthClip = features.Contains(WGPUFeatureName_DepthClipControl); Limits.HasReadOnlyDepth = true; + Limits.MaximumSamplerAnisotropy = 4; Limits.MaximumTexture1DSize = Math::Min(GPU_MAX_TEXTURE_SIZE, limits.maxTextureDimension1D); Limits.MaximumTexture2DSize = Math::Min(GPU_MAX_TEXTURE_SIZE, limits.maxTextureDimension2D); Limits.MaximumTexture3DSize = Math::Min(GPU_MAX_TEXTURE_SIZE, limits.maxTextureDimension3D); @@ -492,11 +496,20 @@ void GPUDeviceWebGPU::DrawBegin() DataUploader.DrawBegin(); // Create default texture - if (!DefaultTexture) + static_assert(ARRAY_COUNT(DefaultTexture) == (int32)SpirvShaderResourceType::MAX, "Invalid size of default textures"); + if (!DefaultTexture[(int32)SpirvShaderResourceType::Texture2D]) { - DefaultTexture = New(this, TEXT("DefaultTexture")); - DefaultTexture->Init(GPUTextureDescription::New2D(1, 1, PixelFormat::R8G8B8A8_UNorm, GPUTextureFlags::ShaderResource)); - DefaultTexture->SetResidentMipLevels(1); + GPUTextureWebGPU* texture; +#define INIT_TEXTURE(type, desc) \ + texture = New(this, TEXT("DefaultTexture")); \ + DefaultTexture[(int32)SpirvShaderResourceType::type] = texture; \ + texture->Init(desc); \ + texture->SetResidentMipLevels(1) + INIT_TEXTURE(Texture2D, GPUTextureDescription::New2D(1, 1, PixelFormat::R8G8B8A8_UNorm, GPUTextureFlags::ShaderResource)); + INIT_TEXTURE(Texture3D, GPUTextureDescription::New3D(1, 1, 1, PixelFormat::R8G8B8A8_UNorm, GPUTextureFlags::ShaderResource)); + INIT_TEXTURE(TextureCube, GPUTextureDescription::NewCube(1, 1, PixelFormat::R8G8B8A8_UNorm, GPUTextureFlags::ShaderResource)); +#undef INIT_TEXTURE + } } @@ -573,7 +586,7 @@ void GPUDeviceWebGPU::Dispose() // Clear device resources DataUploader.ReleaseGPU(); - SAFE_DELETE_GPU_RESOURCE(DefaultTexture); + SAFE_DELETE_GPU_RESOURCES(DefaultTexture); SAFE_DELETE_GPU_RESOURCES(DefaultSamplers); SAFE_DELETE(_mainContext); SAFE_DELETE(Adapter); diff --git a/Source/Engine/GraphicsDevice/WebGPU/GPUDeviceWebGPU.h b/Source/Engine/GraphicsDevice/WebGPU/GPUDeviceWebGPU.h index 5959d1dda..76dc14f5d 100644 --- a/Source/Engine/GraphicsDevice/WebGPU/GPUDeviceWebGPU.h +++ b/Source/Engine/GraphicsDevice/WebGPU/GPUDeviceWebGPU.h @@ -80,7 +80,7 @@ public: WGPUDevice Device = nullptr; WGPUQueue Queue = nullptr; GPUSamplerWebGPU* DefaultSamplers[6] = {}; - GPUTextureWebGPU* DefaultTexture = nullptr; + GPUTextureWebGPU* DefaultTexture[10] = {}; GPUDataUploaderWebGPU DataUploader; uint32 MinUniformBufferOffsetAlignment = 1; diff --git a/Source/Engine/GraphicsDevice/WebGPU/GPUPipelineStateWebGPU.cpp b/Source/Engine/GraphicsDevice/WebGPU/GPUPipelineStateWebGPU.cpp index 70230f18f..0513ee6e7 100644 --- a/Source/Engine/GraphicsDevice/WebGPU/GPUPipelineStateWebGPU.cpp +++ b/Source/Engine/GraphicsDevice/WebGPU/GPUPipelineStateWebGPU.cpp @@ -258,9 +258,15 @@ bool GPUPipelineStateWebGPU::Init(const Description& desc) PipelineDesc.fragment = &_fragmentDesc; _fragmentDesc = WGPU_FRAGMENT_STATE_INIT; _fragmentDesc.targets = _colorTargets; - _blendState = WGPU_BLEND_STATE_INIT; - _blendState.color = ToBlendComponent(desc.BlendMode.BlendOp, desc.BlendMode.SrcBlend, desc.BlendMode.DestBlend); - _blendState.alpha = ToBlendComponent(desc.BlendMode.BlendOpAlpha, desc.BlendMode.SrcBlendAlpha, desc.BlendMode.DestBlendAlpha); + Platform::MemoryClear(&_colorTargets, sizeof(_colorTargets)); + if (desc.BlendMode.BlendEnable) + { + _blendState = WGPU_BLEND_STATE_INIT; + _blendState.color = ToBlendComponent(desc.BlendMode.BlendOp, desc.BlendMode.SrcBlend, desc.BlendMode.DestBlend); + _blendState.alpha = ToBlendComponent(desc.BlendMode.BlendOpAlpha, desc.BlendMode.SrcBlendAlpha, desc.BlendMode.DestBlendAlpha); + for (auto& e : _colorTargets) + e.blend = &_blendState; + } WGPUColorWriteMask writeMask = WGPUColorWriteMask_All; if (desc.BlendMode.RenderTargetWriteMask != BlendingMode::ColorWrite::All) { @@ -274,12 +280,10 @@ bool GPUPipelineStateWebGPU::Init(const Description& desc) if (EnumHasAllFlags(desc.BlendMode.RenderTargetWriteMask, BlendingMode::ColorWrite::Alpha)) writeMask |= WGPUColorWriteMask_Alpha; } - for (auto& e : _colorTargets) + if (PS) { - e = WGPU_COLOR_TARGET_STATE_INIT; - if (desc.BlendMode.BlendEnable) - e.blend = &_blendState; - e.writeMask = writeMask; + for (int32 rtIndex = 0; rtIndex < PS->GetBindings().OutputsCount; rtIndex++) + _colorTargets[rtIndex].writeMask = writeMask; } // Cache shaders diff --git a/Source/Engine/GraphicsDevice/WebGPU/GPUShaderWebGPU.cpp b/Source/Engine/GraphicsDevice/WebGPU/GPUShaderWebGPU.cpp index 66f537538..56e09fc17 100644 --- a/Source/Engine/GraphicsDevice/WebGPU/GPUShaderWebGPU.cpp +++ b/Source/Engine/GraphicsDevice/WebGPU/GPUShaderWebGPU.cpp @@ -14,6 +14,7 @@ GPUConstantBufferWebGPU::GPUConstantBufferWebGPU(GPUDeviceWebGPU* device, uint32 : GPUResourceWebGPU(device, name) { _size = _memoryUsage = size; + AllocationSize = 0; } GPUShaderProgram* GPUShaderWebGPU::CreateGPUShaderProgram(ShaderStage type, const GPUShaderProgramInitializer& initializer, Span bytecode, MemoryReadStream& stream) diff --git a/Source/Engine/GraphicsDevice/WebGPU/GPUShaderWebGPU.h b/Source/Engine/GraphicsDevice/WebGPU/GPUShaderWebGPU.h index 62aa5b925..a6a3015dd 100644 --- a/Source/Engine/GraphicsDevice/WebGPU/GPUShaderWebGPU.h +++ b/Source/Engine/GraphicsDevice/WebGPU/GPUShaderWebGPU.h @@ -18,6 +18,7 @@ public: public: GPUDataUploaderWebGPU::Allocation Allocation; + uint32 AllocationSize; }; ///