Fix WebGPU crashes when resizing canvas
This commit is contained in:
@@ -98,6 +98,7 @@ bool GPUBufferWebGPU::OnInit()
|
||||
return true;
|
||||
_memoryUsage = bufferDesc.size;
|
||||
Usage = bufferDesc.usage;
|
||||
_view.Ptr.ObjectVersion = _device->GetObjectVersion();
|
||||
|
||||
// Initialize with a data if provided
|
||||
if (bufferDesc.mappedAtCreation)
|
||||
@@ -128,7 +129,7 @@ void GPUBufferWebGPU::OnReleaseGPU()
|
||||
#if GPU_ENABLE_RESOURCE_NAMING
|
||||
_name.Clear();
|
||||
#endif
|
||||
_view.Ptr.Version++;
|
||||
_view.Ptr.ViewVersion++;
|
||||
|
||||
// Base
|
||||
GPUBuffer::OnReleaseGPU();
|
||||
|
||||
@@ -1138,7 +1138,7 @@ void GPUContextWebGPU::BuildBindGroup(uint32 groupIndex, const SpirvShaderDescri
|
||||
auto entriesPtr = key.Entries;
|
||||
auto versionsPtr = key.Versions;
|
||||
Platform::MemoryClear(entriesPtr, entriesCount * sizeof(WGPUBindGroupEntry));
|
||||
Platform::MemoryClear(versionsPtr, ((entriesCount + 3) & ~0x3) * sizeof(uint8));
|
||||
Platform::MemoryClear(versionsPtr, entriesCount * sizeof(uint32));
|
||||
for (int32 index = 0; index < entriesCount; index++)
|
||||
{
|
||||
auto& descriptor = descriptors.DescriptorTypes[index];
|
||||
@@ -1205,7 +1205,7 @@ void GPUContextWebGPU::BuildBindGroup(uint32 groupIndex, const SpirvShaderDescri
|
||||
{
|
||||
entry.buffer = ptr->BufferView->Buffer;
|
||||
entry.size = ((GPUBufferWebGPU*)view->GetParent())->GetSize();
|
||||
versionsPtr[index] = (uint64)ptr->Version;
|
||||
versionsPtr[index] = ptr->Version;
|
||||
}
|
||||
if (!entry.buffer)
|
||||
entry.buffer = _device->DefaultBuffer; // Fallback
|
||||
|
||||
@@ -148,6 +148,21 @@ public:
|
||||
|
||||
GPUQueryWebGPU AllocateQuery(GPUQueryType type);
|
||||
|
||||
// Object version counter used to track resource view permutations (to avoid pointer collisions on WGPUTexture/WGPUBuffer inside Bind Group cache)
|
||||
#ifndef __EMSCRIPTEN_PTHREADS__
|
||||
mutable uint16 ObjectVersionCounter = 0;
|
||||
FORCE_INLINE uint16 GetObjectVersion() const
|
||||
{
|
||||
return ++ObjectVersionCounter;
|
||||
}
|
||||
#else
|
||||
mutable volatile int64 ObjectVersionCounter = 0;
|
||||
FORCE_INLINE uint16 GetObjectVersion() const
|
||||
{
|
||||
return (uint16)(Platform::InterlockedIncrement(&ObjectVersionCounter) % MAX_uint16);
|
||||
}
|
||||
#endif
|
||||
|
||||
public:
|
||||
// [GPUDeviceDX]
|
||||
GPUContext* GetMainContext() override
|
||||
@@ -195,7 +210,15 @@ struct GPUResourceViewPtrWebGPU
|
||||
{
|
||||
class GPUBufferViewWebGPU* BufferView;
|
||||
class GPUTextureViewWebGPU* TextureView;
|
||||
uint8 Version;
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
uint16 ObjectVersion; // Object instance permutation
|
||||
uint16 ViewVersion; // Specific view permutation
|
||||
};
|
||||
uint32 Version;
|
||||
};
|
||||
};
|
||||
|
||||
extern GPUDevice* CreateGPUDeviceWebGPU();
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#define WEBGPU_LOG_PSO 0
|
||||
//#define WEBGPU_LOG_PSO_NAME "PS_GBuffer" // Debug log for PSOs with specific name
|
||||
#define WEBGPU_LOG_BIND_GROUPS 0
|
||||
#define WEBGPU_CACHE_BIND_GROUPS 1
|
||||
|
||||
#include "GPUPipelineStateWebGPU.h"
|
||||
#include "GPUTextureWebGPU.h"
|
||||
@@ -371,9 +372,11 @@ void GPUPipelineStateWebGPU::OnReleaseGPU()
|
||||
{
|
||||
VS = nullptr;
|
||||
PS = nullptr;
|
||||
#if WEBGPU_CACHE_BIND_GROUPS
|
||||
for (auto& e : _bindGroups)
|
||||
wgpuBindGroupRelease(e.Value);
|
||||
_bindGroups.Clear();
|
||||
#endif
|
||||
for (auto& e : _pipelines)
|
||||
wgpuRenderPipelineRelease(e.Value);
|
||||
_pipelines.Clear();
|
||||
@@ -412,7 +415,7 @@ bool GPUBindGroupKeyWebGPU::operator==(const GPUBindGroupKeyWebGPU& other) const
|
||||
&& Layout == other.Layout
|
||||
&& EntriesCount == other.EntriesCount
|
||||
&& Platform::MemoryCompare(&Entries, &other.Entries, EntriesCount * sizeof(WGPUBindGroupEntry)) == 0
|
||||
&& Platform::MemoryCompare(&Versions, &other.Versions, EntriesCount * sizeof(uint8)) == 0;
|
||||
&& Platform::MemoryCompare(&Versions, &other.Versions, EntriesCount * sizeof(uint32)) == 0;
|
||||
}
|
||||
|
||||
WGPUBindGroup GPUBindGroupCacheWebGPU::Get(WGPUDevice device, GPUBindGroupKeyWebGPU& key, const StringAnsiView& debugName, uint64 gcFrames)
|
||||
@@ -434,6 +437,7 @@ WGPUBindGroup GPUBindGroupCacheWebGPU::Get(WGPUDevice device, GPUBindGroupKeyWeb
|
||||
|
||||
// Lookup for existing bind group
|
||||
WGPUBindGroup bindGroup;
|
||||
#if WEBGPU_CACHE_BIND_GROUPS
|
||||
auto found = _bindGroups.Find(key);
|
||||
if (found.IsNotEnd())
|
||||
{
|
||||
@@ -463,6 +467,7 @@ WGPUBindGroup GPUBindGroupCacheWebGPU::Get(WGPUDevice device, GPUBindGroupKeyWeb
|
||||
|
||||
return bindGroup;
|
||||
}
|
||||
#endif
|
||||
PROFILE_CPU();
|
||||
PROFILE_MEM(GraphicsShaders);
|
||||
#if GPU_ENABLE_RESOURCE_NAMING
|
||||
@@ -505,7 +510,7 @@ WGPUBindGroup GPUBindGroupCacheWebGPU::Get(WGPUDevice device, GPUBindGroupKeyWeb
|
||||
equalLayout++;
|
||||
if (key.EntriesCount == other.EntriesCount && Platform::MemoryCompare(&key.Entries, &other.Entries, key.EntriesCount * sizeof(WGPUBindGroupEntry)) == 0)
|
||||
equalEntries++;
|
||||
if (key.EntriesCount == other.EntriesCount && Platform::MemoryCompare(&key.Versions, &other.Versions, key.EntriesCount * sizeof(uint8)) == 0)
|
||||
if (key.EntriesCount == other.EntriesCount && Platform::MemoryCompare(&key.Versions, &other.Versions, key.EntriesCount * sizeof(uint32)) == 0)
|
||||
equalVersions++;
|
||||
}
|
||||
}
|
||||
@@ -513,8 +518,10 @@ WGPUBindGroup GPUBindGroupCacheWebGPU::Get(WGPUDevice device, GPUBindGroupKeyWeb
|
||||
LOG(Error, "> Hash collision! {}/{} (capacity: {}), equalLayout: {}, equalEntries: {}, equalVersions: {}", collisions, _bindGroups.Count(), _bindGroups.Capacity(), equalLayout, equalEntries, equalVersions);
|
||||
#endif
|
||||
|
||||
#if WEBGPU_CACHE_BIND_GROUPS
|
||||
// Cache it
|
||||
_bindGroups.Add(key, bindGroup);
|
||||
#endif
|
||||
return bindGroup;
|
||||
}
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ struct GPUBindGroupKeyWebGPU
|
||||
mutable uint64 LastFrameUsed;
|
||||
WGPUBindGroupEntry Entries[64];
|
||||
uint8 EntriesCount;
|
||||
uint8 Versions[64]; // Versions of descriptors used to differentiate when texture residency gets changed
|
||||
uint32 Versions[64]; // Versions of descriptors used to differentiate when texture residency gets changed
|
||||
|
||||
bool operator==(const GPUBindGroupKeyWebGPU& other) const;
|
||||
};
|
||||
|
||||
@@ -81,7 +81,7 @@ GPUTextureView* GPUSwapChainWebGPU::GetBackBufferView()
|
||||
viewDesc.arrayLayerCount = 1;
|
||||
viewDesc.aspect = WGPUTextureAspect_All;
|
||||
viewDesc.usage = wgpuTextureGetUsage(surfaceTexture.texture);
|
||||
_surfaceView.Create(surfaceTexture.texture, viewDesc);
|
||||
_surfaceView.Create(surfaceTexture.texture, viewDesc, _surfaceView.Ptr.Version + 1);
|
||||
}
|
||||
return &_surfaceView;
|
||||
}
|
||||
|
||||
@@ -37,9 +37,12 @@ void SetWebGPUTextureViewSampler(GPUTextureView* view, uint32 samplerType)
|
||||
((GPUTextureViewWebGPU*)view)->SampleType = (WGPUTextureSampleType)samplerType;
|
||||
}
|
||||
|
||||
void GPUTextureViewWebGPU::Create(WGPUTexture texture, const WGPUTextureViewDescriptor& desc)
|
||||
void GPUTextureViewWebGPU::Create(WGPUTexture texture, const WGPUTextureViewDescriptor& desc, uint16 version)
|
||||
{
|
||||
Ptr.Version++;
|
||||
Ptr.ObjectVersion = version;
|
||||
Ptr.ViewVersion++;
|
||||
if (ViewRender && View != ViewRender)
|
||||
wgpuTextureViewRelease(ViewRender);
|
||||
if (View)
|
||||
wgpuTextureViewRelease(View);
|
||||
Texture = texture;
|
||||
@@ -104,21 +107,23 @@ void GPUTextureViewWebGPU::Create(WGPUTexture texture, const WGPUTextureViewDesc
|
||||
|
||||
void GPUTextureViewWebGPU::Release()
|
||||
{
|
||||
if (View != ViewRender)
|
||||
{
|
||||
wgpuTextureViewRelease(ViewRender);
|
||||
ViewRender = nullptr;
|
||||
}
|
||||
if (View)
|
||||
{
|
||||
wgpuTextureViewRelease(View);
|
||||
if (View == ViewRender)
|
||||
ViewRender = nullptr;
|
||||
View = nullptr;
|
||||
}
|
||||
if (ViewRender)
|
||||
{
|
||||
wgpuTextureViewRelease(ViewRender);
|
||||
ViewRender = nullptr;
|
||||
}
|
||||
Texture = nullptr;
|
||||
HasStencil = false;
|
||||
ReadOnly = false;
|
||||
DepthSlice = WGPU_DEPTH_SLICE_UNDEFINED;
|
||||
Ptr.Version++;
|
||||
Ptr.ViewVersion++;
|
||||
}
|
||||
|
||||
bool GPUTextureWebGPU::OnInit()
|
||||
@@ -169,6 +174,7 @@ bool GPUTextureWebGPU::OnInit()
|
||||
Texture = wgpuDeviceCreateTexture(_device->Device, &textureDesc);
|
||||
if (!Texture)
|
||||
return true;
|
||||
_version = _device->GetObjectVersion();
|
||||
|
||||
// Update memory usage
|
||||
_memoryUsage = calculateMemoryUsage();
|
||||
@@ -217,7 +223,7 @@ void GPUTextureWebGPU::OnResidentMipsChanged()
|
||||
GPUTextureViewWebGPU& view = IsVolume() ? _handleVolume : _handlesPerSlice[0];
|
||||
if (view.GetParent() == nullptr)
|
||||
view.Init(this, _desc.Format, _desc.MultiSampleLevel);
|
||||
view.Create(Texture, viewDesc);
|
||||
view.Create(Texture, viewDesc, _version);
|
||||
}
|
||||
|
||||
void GPUTextureWebGPU::OnReleaseGPU()
|
||||
@@ -277,7 +283,7 @@ void GPUTextureWebGPU::InitHandles()
|
||||
{
|
||||
auto& view = _handleVolume;
|
||||
view.Init(this, format, msaa);
|
||||
view.Create(Texture, viewDesc);
|
||||
view.Create(Texture, viewDesc, _version);
|
||||
}
|
||||
|
||||
// Init per slice views
|
||||
@@ -288,7 +294,7 @@ void GPUTextureWebGPU::InitHandles()
|
||||
{
|
||||
auto& view = _handlesPerSlice[sliceIndex];
|
||||
view.Init(this, format, msaa);
|
||||
view.Create(Texture, viewDesc);
|
||||
view.Create(Texture, viewDesc, _version);
|
||||
view.DepthSlice = sliceIndex;
|
||||
}
|
||||
}
|
||||
@@ -299,7 +305,7 @@ void GPUTextureWebGPU::InitHandles()
|
||||
{
|
||||
auto& view = _handleArray;
|
||||
view.Init(this, format, msaa);
|
||||
view.Create(Texture, viewDesc);
|
||||
view.Create(Texture, viewDesc, _version);
|
||||
}
|
||||
|
||||
// Create per array slice handles
|
||||
@@ -311,7 +317,7 @@ void GPUTextureWebGPU::InitHandles()
|
||||
viewDesc.arrayLayerCount = 1;
|
||||
auto& view = _handlesPerSlice[arrayIndex];
|
||||
view.Init(this, format, msaa);
|
||||
view.Create(Texture, viewDesc);
|
||||
view.Create(Texture, viewDesc, _version);
|
||||
}
|
||||
viewDesc.baseArrayLayer = 0;
|
||||
viewDesc.arrayLayerCount = MipLevels();
|
||||
@@ -323,7 +329,7 @@ void GPUTextureWebGPU::InitHandles()
|
||||
_handlesPerSlice.Resize(1, false);
|
||||
auto& view = _handlesPerSlice[0];
|
||||
view.Init(this, format, msaa);
|
||||
view.Create(Texture, viewDesc);
|
||||
view.Create(Texture, viewDesc, _version);
|
||||
}
|
||||
|
||||
// Init per mip map handles
|
||||
@@ -344,7 +350,7 @@ void GPUTextureWebGPU::InitHandles()
|
||||
auto& view = slice[mipIndex];
|
||||
viewDesc.baseMipLevel = mipIndex;
|
||||
view.Init(this, format, msaa);
|
||||
view.Create(Texture, viewDesc);
|
||||
view.Create(Texture, viewDesc, _version);
|
||||
}
|
||||
}
|
||||
viewDesc.dimension = _viewDimension;
|
||||
@@ -355,7 +361,7 @@ void GPUTextureWebGPU::InitHandles()
|
||||
{
|
||||
auto& view = _handleReadOnlyDepth;
|
||||
view.Init(this, format, msaa);
|
||||
view.Create(Texture, viewDesc);
|
||||
view.Create(Texture, viewDesc, _version);
|
||||
view.ReadOnly = true;
|
||||
}
|
||||
|
||||
@@ -375,7 +381,7 @@ void GPUTextureWebGPU::InitHandles()
|
||||
viewDesc.aspect = WGPUTextureAspect_StencilOnly;
|
||||
viewDesc.format = WGPUTextureFormat_Stencil8;
|
||||
_handleStencil.Init(this, stencilFormat, msaa);
|
||||
_handleStencil.Create(Texture, viewDesc);
|
||||
_handleStencil.Create(Texture, viewDesc, _version);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -65,7 +65,7 @@ public:
|
||||
|
||||
public:
|
||||
using GPUTextureView::Init;
|
||||
void Create(WGPUTexture texture, const WGPUTextureViewDescriptor& desc);
|
||||
void Create(WGPUTexture texture, const WGPUTextureViewDescriptor& desc, uint16 version);
|
||||
void Release();
|
||||
|
||||
public:
|
||||
@@ -93,6 +93,7 @@ private:
|
||||
#endif
|
||||
WGPUTextureFormat _format = WGPUTextureFormat_Undefined;
|
||||
WGPUTextureViewDimension _viewDimension = WGPUTextureViewDimension_Undefined;
|
||||
uint16 _version = 0;
|
||||
|
||||
public:
|
||||
GPUTextureWebGPU(GPUDeviceWebGPU* device, const StringView& name)
|
||||
|
||||
@@ -289,6 +289,7 @@ namespace Flax.Build.Platforms
|
||||
args.AddRange(options.LinkEnv.CustomArgs);
|
||||
{
|
||||
args.Add(string.Format("-o \"{0}\"", outputFilePath.Replace('\\', '/')));
|
||||
args.Add("-Wno-experimental");
|
||||
|
||||
// Debug options
|
||||
//args.Add("--minify=0");
|
||||
|
||||
Reference in New Issue
Block a user