Skip to content

Commit 951dba2

Browse files
WebGPU: properly handle enabled feature status
1 parent 9cde409 commit 951dba2

File tree

3 files changed

+144
-119
lines changed

3 files changed

+144
-119
lines changed

Graphics/GraphicsEngineWebGPU/include/RenderDeviceWebGPUImpl.hpp

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2023-2024 Diligent Graphics LLC
2+
* Copyright 2023-2025 Diligent Graphics LLC
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -52,14 +52,18 @@ class RenderDeviceWebGPUImpl final : public RenderDeviceBase<EngineWebGPUImplTra
5252
public:
5353
using TRenderDeviceBase = RenderDeviceBase<EngineWebGPUImplTraits>;
5454

55-
RenderDeviceWebGPUImpl(IReferenceCounters* pRefCounters,
56-
IMemoryAllocator& RawMemAllocator,
57-
IEngineFactory* pEngineFactory,
58-
const EngineWebGPUCreateInfo& EngineCI,
59-
const GraphicsAdapterInfo& AdapterInfo,
60-
WGPUInstance wgpuInstance,
61-
WGPUAdapter wgpuAdapter,
62-
WGPUDevice wgpuDevice) noexcept(false);
55+
struct CreateInfo
56+
{
57+
IMemoryAllocator& RawMemAllocator;
58+
IEngineFactory* const pEngineFactory;
59+
const EngineWebGPUCreateInfo& EngineCI;
60+
const GraphicsAdapterInfo& AdapterInfo;
61+
const DeviceFeatures& EnabledFeatures;
62+
WGPUInstance wgpuInstance = {};
63+
WGPUAdapter wgpuAdapter = {};
64+
WGPUDevice wgpuDevice = {};
65+
};
66+
RenderDeviceWebGPUImpl(IReferenceCounters* pRefCounters, const CreateInfo& CI) noexcept(false);
6367

6468
~RenderDeviceWebGPUImpl() override;
6569

Graphics/GraphicsEngineWebGPU/src/EngineFactoryWebGPU.cpp

Lines changed: 118 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -237,51 +237,45 @@ static void UncapturedErrorCallback2(WGPUDevice const* device,
237237
}
238238
#endif
239239

240-
WebGPUDeviceWrapper CreateDeviceForAdapter(EngineWebGPUCreateInfo const& EngineCI, WGPUInstance wgpuInstance, WGPUAdapter wgpuAdapter)
240+
WebGPUDeviceWrapper CreateDeviceForAdapter(const DeviceFeatures& Features, WGPUInstance wgpuInstance, WGPUAdapter wgpuAdapter)
241241
{
242242
WGPUSupportedLimits SupportedLimits{};
243243
wgpuAdapterGetLimits(wgpuAdapter, &SupportedLimits);
244244

245-
std::vector<WGPUFeatureName> Features{};
245+
std::vector<WGPUFeatureName> wgpuFeatures{};
246246
{
247-
if (EngineCI.Features.DepthBiasClamp && wgpuAdapterHasFeature(wgpuAdapter, WGPUFeatureName_DepthClipControl))
248-
Features.push_back(WGPUFeatureName_DepthClipControl);
249-
250-
if (EngineCI.Features.TimestampQueries && wgpuAdapterHasFeature(wgpuAdapter, WGPUFeatureName_TimestampQuery))
251-
Features.push_back(WGPUFeatureName_TimestampQuery);
252-
253-
if (EngineCI.Features.TimestampQueries && wgpuAdapterHasFeature(wgpuAdapter, WGPUFeatureName_ChromiumExperimentalTimestampQueryInsidePasses))
254-
Features.push_back(WGPUFeatureName_ChromiumExperimentalTimestampQueryInsidePasses);
255-
256-
if (EngineCI.Features.TextureCompressionBC && wgpuAdapterHasFeature(wgpuAdapter, WGPUFeatureName_TextureCompressionBC))
257-
Features.push_back(WGPUFeatureName_TextureCompressionBC);
258-
259-
if (EngineCI.Features.TextureCompressionETC2 && wgpuAdapterHasFeature(wgpuAdapter, WGPUFeatureName_TextureCompressionETC2))
260-
Features.push_back(WGPUFeatureName_TextureCompressionETC2);
247+
auto AddWGPUFeature = [wgpuAdapter, &wgpuFeatures](DEVICE_FEATURE_STATE FeatureState, WGPUFeatureName wgpuFeature) {
248+
if (FeatureState && wgpuAdapterHasFeature(wgpuAdapter, wgpuFeature))
249+
wgpuFeatures.push_back(wgpuFeature);
250+
};
261251

262-
if (EngineCI.Features.ShaderFloat16 && wgpuAdapterHasFeature(wgpuAdapter, WGPUFeatureName_ShaderF16))
263-
Features.push_back(WGPUFeatureName_ShaderF16);
252+
AddWGPUFeature(Features.DepthBiasClamp, WGPUFeatureName_DepthClipControl);
253+
AddWGPUFeature(Features.TimestampQueries, WGPUFeatureName_TimestampQuery);
254+
AddWGPUFeature(Features.DurationQueries, WGPUFeatureName_ChromiumExperimentalTimestampQueryInsidePasses);
255+
AddWGPUFeature(Features.TextureCompressionBC, WGPUFeatureName_TextureCompressionBC);
256+
AddWGPUFeature(Features.TextureCompressionETC2, WGPUFeatureName_TextureCompressionETC2);
257+
AddWGPUFeature(Features.ShaderFloat16, WGPUFeatureName_ShaderF16);
264258

265259
if (wgpuAdapterHasFeature(wgpuAdapter, WGPUFeatureName_Depth32FloatStencil8))
266-
Features.push_back(WGPUFeatureName_Depth32FloatStencil8);
260+
wgpuFeatures.push_back(WGPUFeatureName_Depth32FloatStencil8);
267261

268262
if (wgpuAdapterHasFeature(wgpuAdapter, WGPUFeatureName_Float32Filterable))
269-
Features.push_back(WGPUFeatureName_Float32Filterable);
263+
wgpuFeatures.push_back(WGPUFeatureName_Float32Filterable);
270264

271265
if (wgpuAdapterHasFeature(wgpuAdapter, WGPUFeatureName_IndirectFirstInstance))
272-
Features.push_back(WGPUFeatureName_IndirectFirstInstance);
266+
wgpuFeatures.push_back(WGPUFeatureName_IndirectFirstInstance);
273267

274268
if (wgpuAdapterHasFeature(wgpuAdapter, WGPUFeatureName_RG11B10UfloatRenderable))
275-
Features.push_back(WGPUFeatureName_RG11B10UfloatRenderable);
269+
wgpuFeatures.push_back(WGPUFeatureName_RG11B10UfloatRenderable);
276270

277271
if (wgpuAdapterHasFeature(wgpuAdapter, WGPUFeatureName_BGRA8UnormStorage))
278-
Features.push_back(WGPUFeatureName_BGRA8UnormStorage);
272+
wgpuFeatures.push_back(WGPUFeatureName_BGRA8UnormStorage);
279273

280274
if (wgpuAdapterHasFeature(wgpuAdapter, WGPUFeatureName_Unorm16TextureFormats))
281-
Features.push_back(WGPUFeatureName_Unorm16TextureFormats);
275+
wgpuFeatures.push_back(WGPUFeatureName_Unorm16TextureFormats);
282276

283277
if (wgpuAdapterHasFeature(wgpuAdapter, WGPUFeatureName_Snorm16TextureFormats))
284-
Features.push_back(WGPUFeatureName_Snorm16TextureFormats);
278+
wgpuFeatures.push_back(WGPUFeatureName_Snorm16TextureFormats);
285279
}
286280

287281
struct CallbackUserData
@@ -320,8 +314,8 @@ WebGPUDeviceWrapper CreateDeviceForAdapter(EngineWebGPUCreateInfo const& EngineC
320314

321315
WGPUDeviceDescriptor DeviceDesc{};
322316
DeviceDesc.requiredLimits = &RequiredLimits;
323-
DeviceDesc.requiredFeatureCount = Features.size();
324-
DeviceDesc.requiredFeatures = Features.data();
317+
DeviceDesc.requiredFeatureCount = wgpuFeatures.size();
318+
DeviceDesc.requiredFeatures = wgpuFeatures.data();
325319
#if PLATFORM_EMSCRIPTEN
326320
DeviceDesc.deviceLostCallback = DeviceLostCallback;
327321
#else
@@ -340,7 +334,88 @@ WebGPUDeviceWrapper CreateDeviceForAdapter(EngineWebGPUCreateInfo const& EngineC
340334
return WebGPUDeviceWrapper{UserData.Device};
341335
}
342336

343-
GraphicsAdapterInfo GetGraphicsAdapterInfo(WGPUAdapter wgpuAdapter, WGPUDevice wgpuDevice = nullptr /*Hack for Emscripten*/)
337+
bool FeatureSupported(WGPUAdapter wgpuAdapter, WGPUDevice wgpuDevice, WGPUFeatureName Feature)
338+
{
339+
if (wgpuAdapter != nullptr)
340+
{
341+
return wgpuAdapterHasFeature(wgpuAdapter, Feature);
342+
}
343+
else if (wgpuDevice != nullptr)
344+
{
345+
return wgpuDeviceHasFeature(wgpuDevice, Feature);
346+
}
347+
else
348+
{
349+
UNEXPECTED("Either adapter or device must not be null");
350+
return DEVICE_FEATURE_STATE_DISABLED;
351+
}
352+
}
353+
354+
DeviceFeatures GetSupportedFeatures(WGPUAdapter wgpuAdapter, WGPUDevice wgpuDevice = nullptr)
355+
{
356+
auto CheckFeature = [wgpuAdapter, wgpuDevice](WGPUFeatureName Feature) {
357+
return FeatureSupported(wgpuAdapter, wgpuDevice, Feature) ? DEVICE_FEATURE_STATE_ENABLED : DEVICE_FEATURE_STATE_DISABLED;
358+
};
359+
360+
DeviceFeatures Features;
361+
Features.SeparablePrograms = DEVICE_FEATURE_STATE_ENABLED;
362+
Features.ShaderResourceQueries = DEVICE_FEATURE_STATE_ENABLED;
363+
Features.WireframeFill = DEVICE_FEATURE_STATE_DISABLED;
364+
Features.MultithreadedResourceCreation = DEVICE_FEATURE_STATE_DISABLED;
365+
Features.ComputeShaders = DEVICE_FEATURE_STATE_ENABLED;
366+
Features.GeometryShaders = DEVICE_FEATURE_STATE_DISABLED;
367+
Features.Tessellation = DEVICE_FEATURE_STATE_DISABLED;
368+
Features.MeshShaders = DEVICE_FEATURE_STATE_DISABLED;
369+
Features.RayTracing = DEVICE_FEATURE_STATE_DISABLED;
370+
Features.BindlessResources = DEVICE_FEATURE_STATE_DISABLED;
371+
Features.OcclusionQueries = DEVICE_FEATURE_STATE_ENABLED;
372+
Features.BinaryOcclusionQueries = DEVICE_FEATURE_STATE_DISABLED;
373+
Features.PipelineStatisticsQueries = DEVICE_FEATURE_STATE_DISABLED;
374+
Features.DepthBiasClamp = DEVICE_FEATURE_STATE_ENABLED;
375+
Features.DepthClamp = CheckFeature(WGPUFeatureName_DepthClipControl);
376+
Features.IndependentBlend = DEVICE_FEATURE_STATE_ENABLED;
377+
Features.DualSourceBlend = CheckFeature(WGPUFeatureName_DualSourceBlending);
378+
Features.MultiViewport = DEVICE_FEATURE_STATE_DISABLED;
379+
Features.TextureCompressionBC = CheckFeature(WGPUFeatureName_TextureCompressionBC);
380+
Features.TextureCompressionETC2 = CheckFeature(WGPUFeatureName_TextureCompressionETC2);
381+
Features.VertexPipelineUAVWritesAndAtomics = DEVICE_FEATURE_STATE_ENABLED;
382+
Features.PixelUAVWritesAndAtomics = DEVICE_FEATURE_STATE_ENABLED;
383+
Features.TextureUAVExtendedFormats = DEVICE_FEATURE_STATE_ENABLED;
384+
Features.ShaderFloat16 = CheckFeature(WGPUFeatureName_ShaderF16);
385+
Features.ResourceBuffer16BitAccess = DEVICE_FEATURE_STATE_DISABLED;
386+
Features.UniformBuffer16BitAccess = DEVICE_FEATURE_STATE_DISABLED;
387+
Features.ShaderInputOutput16 = DEVICE_FEATURE_STATE_DISABLED;
388+
Features.ShaderInt8 = DEVICE_FEATURE_STATE_DISABLED;
389+
Features.ResourceBuffer8BitAccess = DEVICE_FEATURE_STATE_DISABLED;
390+
Features.UniformBuffer8BitAccess = DEVICE_FEATURE_STATE_DISABLED;
391+
Features.ShaderResourceStaticArrays = DEVICE_FEATURE_STATE_DISABLED;
392+
Features.ShaderResourceRuntimeArrays = DEVICE_FEATURE_STATE_DISABLED;
393+
Features.WaveOp = DEVICE_FEATURE_STATE_DISABLED;
394+
Features.InstanceDataStepRate = DEVICE_FEATURE_STATE_DISABLED;
395+
Features.NativeFence = DEVICE_FEATURE_STATE_DISABLED;
396+
Features.TileShaders = DEVICE_FEATURE_STATE_DISABLED;
397+
Features.TransferQueueTimestampQueries = DEVICE_FEATURE_STATE_DISABLED;
398+
Features.VariableRateShading = DEVICE_FEATURE_STATE_DISABLED;
399+
Features.SparseResources = DEVICE_FEATURE_STATE_DISABLED;
400+
Features.SubpassFramebufferFetch = DEVICE_FEATURE_STATE_DISABLED;
401+
Features.TextureComponentSwizzle = DEVICE_FEATURE_STATE_DISABLED;
402+
Features.TextureSubresourceViews = DEVICE_FEATURE_STATE_ENABLED;
403+
Features.NativeMultiDraw = DEVICE_FEATURE_STATE_DISABLED;
404+
Features.AsyncShaderCompilation = DEVICE_FEATURE_STATE_ENABLED;
405+
Features.FormattedBuffers = DEVICE_FEATURE_STATE_DISABLED;
406+
407+
Features.TimestampQueries = CheckFeature(WGPUFeatureName_TimestampQuery);
408+
Features.DurationQueries = Features.TimestampQueries ?
409+
CheckFeature(WGPUFeatureName_ChromiumExperimentalTimestampQueryInsidePasses) :
410+
DEVICE_FEATURE_STATE_DISABLED;
411+
412+
ASSERT_SIZEOF(DeviceFeatures, 47, "Did you add a new feature to DeviceFeatures? Please handle its status here.");
413+
414+
return Features;
415+
}
416+
417+
418+
GraphicsAdapterInfo GetGraphicsAdapterInfo(WGPUAdapter wgpuAdapter, WGPUDevice wgpuDevice = nullptr)
344419
{
345420
WGPUAdapterInfo wgpuAdapterInfo{};
346421
if (wgpuAdapter)
@@ -377,68 +452,7 @@ GraphicsAdapterInfo GetGraphicsAdapterInfo(WGPUAdapter wgpuAdapter, WGPUDevice w
377452
AdapterInfo.NumOutputs = 0;
378453
}
379454

380-
auto CheckWebGPUFeature = [wgpuAdapter, wgpuDevice](WGPUFeatureName Feature) {
381-
return ((wgpuAdapter != nullptr && wgpuAdapterHasFeature(wgpuAdapter, Feature)) ||
382-
(wgpuDevice != nullptr && wgpuDeviceHasFeature(wgpuDevice, Feature))) ?
383-
DEVICE_FEATURE_STATE_ENABLED :
384-
DEVICE_FEATURE_STATE_DISABLED;
385-
};
386-
387-
// Enable features
388-
{
389-
DeviceFeatures& Features{AdapterInfo.Features};
390-
Features.SeparablePrograms = DEVICE_FEATURE_STATE_ENABLED;
391-
Features.ShaderResourceQueries = DEVICE_FEATURE_STATE_ENABLED;
392-
Features.WireframeFill = DEVICE_FEATURE_STATE_DISABLED;
393-
Features.MultithreadedResourceCreation = DEVICE_FEATURE_STATE_DISABLED;
394-
Features.ComputeShaders = DEVICE_FEATURE_STATE_ENABLED;
395-
Features.GeometryShaders = DEVICE_FEATURE_STATE_DISABLED;
396-
Features.Tessellation = DEVICE_FEATURE_STATE_DISABLED;
397-
Features.MeshShaders = DEVICE_FEATURE_STATE_DISABLED;
398-
Features.RayTracing = DEVICE_FEATURE_STATE_DISABLED;
399-
Features.BindlessResources = DEVICE_FEATURE_STATE_DISABLED;
400-
Features.OcclusionQueries = DEVICE_FEATURE_STATE_ENABLED;
401-
Features.BinaryOcclusionQueries = DEVICE_FEATURE_STATE_DISABLED;
402-
Features.PipelineStatisticsQueries = DEVICE_FEATURE_STATE_DISABLED;
403-
Features.DepthBiasClamp = DEVICE_FEATURE_STATE_ENABLED;
404-
Features.DepthClamp = CheckWebGPUFeature(WGPUFeatureName_DepthClipControl);
405-
Features.IndependentBlend = DEVICE_FEATURE_STATE_ENABLED;
406-
Features.DualSourceBlend = CheckWebGPUFeature(WGPUFeatureName_DualSourceBlending);
407-
Features.MultiViewport = DEVICE_FEATURE_STATE_DISABLED;
408-
Features.TextureCompressionBC = CheckWebGPUFeature(WGPUFeatureName_TextureCompressionBC);
409-
Features.TextureCompressionETC2 = CheckWebGPUFeature(WGPUFeatureName_TextureCompressionETC2);
410-
Features.VertexPipelineUAVWritesAndAtomics = DEVICE_FEATURE_STATE_ENABLED;
411-
Features.PixelUAVWritesAndAtomics = DEVICE_FEATURE_STATE_ENABLED;
412-
Features.TextureUAVExtendedFormats = DEVICE_FEATURE_STATE_ENABLED;
413-
Features.ShaderFloat16 = CheckWebGPUFeature(WGPUFeatureName_ShaderF16);
414-
Features.ResourceBuffer16BitAccess = DEVICE_FEATURE_STATE_DISABLED;
415-
Features.UniformBuffer16BitAccess = DEVICE_FEATURE_STATE_DISABLED;
416-
Features.ShaderInputOutput16 = DEVICE_FEATURE_STATE_DISABLED;
417-
Features.ShaderInt8 = DEVICE_FEATURE_STATE_DISABLED;
418-
Features.ResourceBuffer8BitAccess = DEVICE_FEATURE_STATE_DISABLED;
419-
Features.UniformBuffer8BitAccess = DEVICE_FEATURE_STATE_DISABLED;
420-
Features.ShaderResourceStaticArrays = DEVICE_FEATURE_STATE_DISABLED;
421-
Features.ShaderResourceRuntimeArrays = DEVICE_FEATURE_STATE_DISABLED;
422-
Features.WaveOp = DEVICE_FEATURE_STATE_DISABLED;
423-
Features.InstanceDataStepRate = DEVICE_FEATURE_STATE_DISABLED;
424-
Features.NativeFence = DEVICE_FEATURE_STATE_DISABLED;
425-
Features.TileShaders = DEVICE_FEATURE_STATE_DISABLED;
426-
Features.TransferQueueTimestampQueries = DEVICE_FEATURE_STATE_DISABLED;
427-
Features.VariableRateShading = DEVICE_FEATURE_STATE_DISABLED;
428-
Features.SparseResources = DEVICE_FEATURE_STATE_DISABLED;
429-
Features.SubpassFramebufferFetch = DEVICE_FEATURE_STATE_DISABLED;
430-
Features.TextureComponentSwizzle = DEVICE_FEATURE_STATE_DISABLED;
431-
Features.TextureSubresourceViews = DEVICE_FEATURE_STATE_ENABLED;
432-
Features.NativeMultiDraw = DEVICE_FEATURE_STATE_DISABLED;
433-
Features.AsyncShaderCompilation = DEVICE_FEATURE_STATE_ENABLED;
434-
Features.FormattedBuffers = DEVICE_FEATURE_STATE_DISABLED;
435-
436-
Features.TimestampQueries = CheckWebGPUFeature(WGPUFeatureName_TimestampQuery);
437-
Features.DurationQueries = Features.TimestampQueries ?
438-
CheckWebGPUFeature(WGPUFeatureName_ChromiumExperimentalTimestampQueryInsidePasses) :
439-
DEVICE_FEATURE_STATE_DISABLED;
440-
}
441-
ASSERT_SIZEOF(DeviceFeatures, 47, "Did you add a new feature to DeviceFeatures? Please handle its status here.");
455+
AdapterInfo.Features = GetSupportedFeatures(wgpuAdapter, wgpuDevice);
442456

443457
WGPUSupportedLimits wgpuSupportedLimits{};
444458
if (wgpuAdapter)
@@ -459,7 +473,7 @@ GraphicsAdapterInfo GetGraphicsAdapterInfo(WGPUAdapter wgpuAdapter, WGPUDevice w
459473
DrawCommandInfo.MaxDrawIndirectCount = ~0u;
460474
DrawCommandInfo.CapFlags = DRAW_COMMAND_CAP_FLAG_DRAW_INDIRECT;
461475

462-
if (CheckWebGPUFeature(WGPUFeatureName_IndirectFirstInstance))
476+
if (FeatureSupported(wgpuAdapter, wgpuDevice, WGPUFeatureName_IndirectFirstInstance))
463477
DrawCommandInfo.CapFlags |= DRAW_COMMAND_CAP_FLAG_DRAW_INDIRECT_FIRST_INSTANCE;
464478
}
465479

@@ -581,7 +595,7 @@ void EngineFactoryWebGPUImpl::CreateDeviceAndContextsWebGPU(const EngineWebGPUCr
581595
SpecificAdapter = std::move(wgpuAdapters[0]);
582596
}
583597

584-
WebGPUDeviceWrapper Device = CreateDeviceForAdapter(EngineCI, wgpuInstance.Get(), SpecificAdapter.Get());
598+
WebGPUDeviceWrapper Device = CreateDeviceForAdapter(EngineCI.Features, wgpuInstance, SpecificAdapter);
585599
AttachToWebGPUDevice(wgpuInstance.Detach(), SpecificAdapter.Detach(), Device.Detach(), EngineCI, ppDevice, ppImmediateContext);
586600
}
587601
catch (const std::runtime_error&)
@@ -659,12 +673,23 @@ void EngineFactoryWebGPUImpl::AttachToWebGPUDevice(void*
659673
const GraphicsAdapterInfo AdapterInfo = GetGraphicsAdapterInfo(static_cast<WGPUAdapter>(wgpuAdapter), static_cast<WGPUDevice>(wgpuDevice));
660674
VerifyEngineCreateInfo(EngineCI, AdapterInfo);
661675

676+
const DeviceFeatures EnabledFeatures = GetSupportedFeatures(nullptr, static_cast<WGPUDevice>(wgpuDevice));
677+
662678
SetRawAllocator(EngineCI.pRawMemAllocator);
663679
IMemoryAllocator& RawMemAllocator = GetRawAllocator();
664680

665681
RenderDeviceWebGPUImpl* pRenderDeviceWebGPU{
666682
NEW_RC_OBJ(RawMemAllocator, "RenderDeviceWebGPUImpl instance", RenderDeviceWebGPUImpl)(
667-
RawMemAllocator, this, EngineCI, AdapterInfo, static_cast<WGPUInstance>(wgpuInstance), static_cast<WGPUAdapter>(wgpuAdapter), static_cast<WGPUDevice>(wgpuDevice))};
683+
RenderDeviceWebGPUImpl::CreateInfo{
684+
RawMemAllocator,
685+
this,
686+
EngineCI,
687+
AdapterInfo,
688+
EnabledFeatures,
689+
static_cast<WGPUInstance>(wgpuInstance),
690+
static_cast<WGPUAdapter>(wgpuAdapter),
691+
static_cast<WGPUDevice>(wgpuDevice),
692+
})};
668693
pRenderDeviceWebGPU->QueryInterface(IID_RenderDevice, reinterpret_cast<IObject**>(ppDevice));
669694

670695
DeviceContextWebGPUImpl* pDeviceContextWebGPU{

0 commit comments

Comments
 (0)