Skip to content

Commit a22d843

Browse files
Verify WebGPU compute pipeline in ProbeSupport
1 parent cd3565e commit a22d843

1 file changed

Lines changed: 92 additions & 2 deletions

File tree

src/ImageSharp.Drawing.WebGPU/WebGPUDrawingBackend.cs

Lines changed: 92 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -144,12 +144,102 @@ private enum PreparedBrushType : uint
144144
/// </summary>
145145
public bool IsSupported => isSupported ??= ProbeSupport();
146146

147-
private static bool ProbeSupport()
147+
/// <summary>
148+
/// Determines whether WebGPU compute support is available on the current system.
149+
/// </summary>
150+
/// <remarks>
151+
/// This method goes beyond checking adapter and device availability — it also compiles
152+
/// a trivial compute shader and creates a compute pipeline to verify the full compute
153+
/// path works. Some systems report a valid device but crash on pipeline creation due to
154+
/// driver or runtime issues.
155+
/// </remarks>
156+
/// <returns>Returns <see langword="true"/> if WebGPU compute support is available; otherwise, <see langword="false"/>.</returns>
157+
public static bool ProbeSupport()
148158
{
149159
try
150160
{
151161
using WebGPURuntime.Lease lease = WebGPURuntime.Acquire();
152-
return WebGPURuntime.TryGetOrCreateDevice(out _, out _, out _);
162+
if (!WebGPURuntime.TryGetOrCreateDevice(out Device* device, out _, out _))
163+
{
164+
return false;
165+
}
166+
167+
WebGPU api = lease.Api;
168+
169+
// Compile a trivial compute shader and create a pipeline to verify the
170+
// full compute path works end-to-end. Some drivers/runtimes crash at
171+
// DeviceCreateComputePipeline despite successful device creation.
172+
ReadOnlySpan<byte> probeShader = "@compute @workgroup_size(1) fn cs_main() {}\0"u8;
173+
fixed (byte* shaderCodePtr = probeShader)
174+
{
175+
ShaderModuleWGSLDescriptor wgslDescriptor = new()
176+
{
177+
Chain = new ChainedStruct { SType = SType.ShaderModuleWgslDescriptor },
178+
Code = shaderCodePtr
179+
};
180+
181+
ShaderModuleDescriptor shaderDescriptor = new()
182+
{
183+
NextInChain = (ChainedStruct*)&wgslDescriptor
184+
};
185+
186+
ShaderModule* shaderModule = api.DeviceCreateShaderModule(device, in shaderDescriptor);
187+
if (shaderModule is null)
188+
{
189+
return false;
190+
}
191+
192+
try
193+
{
194+
ReadOnlySpan<byte> entryPoint = "cs_main\0"u8;
195+
fixed (byte* entryPointPtr = entryPoint)
196+
{
197+
ProgrammableStageDescriptor computeStage = new()
198+
{
199+
Module = shaderModule,
200+
EntryPoint = entryPointPtr
201+
};
202+
203+
PipelineLayoutDescriptor layoutDescriptor = new()
204+
{
205+
BindGroupLayoutCount = 0,
206+
BindGroupLayouts = null
207+
};
208+
209+
PipelineLayout* pipelineLayout = api.DeviceCreatePipelineLayout(device, in layoutDescriptor);
210+
if (pipelineLayout is null)
211+
{
212+
return false;
213+
}
214+
215+
try
216+
{
217+
ComputePipelineDescriptor pipelineDescriptor = new()
218+
{
219+
Layout = pipelineLayout,
220+
Compute = computeStage
221+
};
222+
223+
ComputePipeline* pipeline = api.DeviceCreateComputePipeline(device, in pipelineDescriptor);
224+
if (pipeline is null)
225+
{
226+
return false;
227+
}
228+
229+
api.ComputePipelineRelease(pipeline);
230+
return true;
231+
}
232+
finally
233+
{
234+
api.PipelineLayoutRelease(pipelineLayout);
235+
}
236+
}
237+
}
238+
finally
239+
{
240+
api.ShaderModuleRelease(shaderModule);
241+
}
242+
}
153243
}
154244
catch
155245
{

0 commit comments

Comments
 (0)