22// Licensed under the Six Labors Split License.
33
44using System . Runtime . CompilerServices ;
5- using System . Threading ;
65using Silk . NET . WebGPU ;
76using SixLabors . ImageSharp . PixelFormats ;
87
@@ -106,6 +105,8 @@ public void RenderScene<TPixel>(
106105 {
107106 this . ThrowIfDisposed ( ) ;
108107
108+ NativeCanvasFrame < TPixel > nativeTarget = ( NativeCanvasFrame < TPixel > ) target ;
109+
109110 if ( scene is not WebGPUDrawingBackendScene webGPUScene )
110111 {
111112 throw new InvalidOperationException ( "The retained scene is not a WebGPU drawing backend scene." ) ;
@@ -116,17 +117,18 @@ public void RenderScene<TPixel>(
116117 throw new NotSupportedException ( $ "The WebGPU backend does not support pixel format '{ typeof ( TPixel ) . Name } '.") ;
117118 }
118119
119- if ( ! TryGetSceneTarget (
120- target ,
121- formatId ,
122- requiredFeature ,
123- out TextureFormat textureFormat ,
124- out Rectangle targetBounds ) )
120+ // RenderScene only accepts native frames on the WebGPU path; unwrap the surface once
121+ // so staging does not repeat the generic frame capability checks.
122+ _ = nativeTarget . TryGetNativeSurface ( out NativeSurface ? nativeSurface ) ;
123+ WebGPUNativeTarget webGPUTarget = nativeSurface ! . GetNativeTarget < WebGPUNativeTarget > ( ) ;
124+ TextureFormat textureFormat = WebGPUTextureFormatMapper . ToSilk ( webGPUTarget . TargetFormat ) ;
125+
126+ if ( webGPUTarget . TargetFormat != formatId )
125127 {
126- throw new NotSupportedException ( "The target cannot create a WebGPU flush context ." ) ;
128+ throw new InvalidOperationException ( "The target texture format does not match the retained WebGPU scene pixel format ." ) ;
127129 }
128130
129- if ( targetBounds != webGPUScene . Bounds )
131+ if ( nativeTarget . Bounds != webGPUScene . Bounds )
130132 {
131133 throw new InvalidOperationException ( "The target bounds do not match the retained WebGPU scene bounds." ) ;
132134 }
@@ -137,7 +139,6 @@ public void RenderScene<TPixel>(
137139 WebGPUSceneBumpSizes currentBumpSizes = webGPUScene . BumpSizes ;
138140 WebGPUSceneResourceArena ? resourceArena = null ;
139141 WebGPUSceneSchedulingArena ? schedulingArena = null ;
140- string ? error ;
141142
142143 try
143144 {
@@ -157,24 +158,14 @@ public void RenderScene<TPixel>(
157158 // rediscovering the same growth.
158159 for ( int attempt = 0 ; attempt < MaxDynamicGrowthAttempts ; attempt ++ )
159160 {
160- if ( ! WebGPUSceneDispatch . TryCreateStagedScene (
161- configuration ,
162- target ,
163- encodedScene ,
164- textureFormat ,
165- requiredFeature ,
166- currentBumpSizes ,
167- ref resourceArena ,
168- out bool exceedsBindingLimit ,
169- out _ ,
170- out WebGPUStagedScene stagedScene ,
171- out error ) )
172- {
173- throw new InvalidOperationException (
174- exceedsBindingLimit
175- ? error ?? "The staged WebGPU scene exceeded the current binding limits."
176- : error ?? "Failed to create the staged WebGPU scene." ) ;
177- }
161+ WebGPUStagedScene stagedScene = WebGPUSceneDispatch . CreateStagedScene (
162+ configuration ,
163+ nativeTarget ,
164+ encodedScene ,
165+ textureFormat ,
166+ requiredFeature ,
167+ currentBumpSizes ,
168+ ref resourceArena ) ;
178169
179170 try
180171 {
@@ -189,7 +180,7 @@ public void RenderScene<TPixel>(
189180 ref schedulingArena ,
190181 out bool requiresGrowth ,
191182 out WebGPUSceneBumpSizes grownBumpSizes ,
192- out error ) ;
183+ out string ? error ) ;
193184
194185 if ( renderSucceeded )
195186 {
@@ -227,59 +218,6 @@ public void RenderScene<TPixel>(
227218 }
228219 }
229220
230- /// <summary>
231- /// Validates the target information needed to render a retained WebGPU scene.
232- /// </summary>
233- /// <typeparam name="TPixel">The pixel format.</typeparam>
234- /// <param name="target">The target frame.</param>
235- /// <param name="expectedFormat">The expected WebGPU texture format.</param>
236- /// <param name="requiredFeature">The optional feature required by the texture format.</param>
237- /// <param name="textureFormat">Receives the native WebGPU texture format.</param>
238- /// <param name="targetBounds">Receives the target bounds.</param>
239- /// <returns><see langword="true"/> when the target can accept a WebGPU scene.</returns>
240- private static bool TryGetSceneTarget < TPixel > (
241- ICanvasFrame < TPixel > target ,
242- WebGPUTextureFormat expectedFormat ,
243- FeatureName requiredFeature ,
244- out TextureFormat textureFormat ,
245- out Rectangle targetBounds )
246- where TPixel : unmanaged, IPixel < TPixel >
247- {
248- textureFormat = default ;
249- targetBounds = default ;
250-
251- if ( ! target . TryGetNativeSurface ( out NativeSurface ? nativeSurface ) )
252- {
253- return false ;
254- }
255-
256- WebGPUNativeTarget nativeTarget = nativeSurface . GetNativeTarget < WebGPUNativeTarget > ( ) ;
257- if ( nativeTarget . DeviceHandle . IsInvalid ||
258- nativeTarget . QueueHandle . IsInvalid ||
259- nativeTarget . TargetTextureViewHandle . IsInvalid ||
260- nativeTarget . TargetFormat != expectedFormat )
261- {
262- return false ;
263- }
264-
265- targetBounds = target . Bounds ;
266- Rectangle nativeBounds = new ( 0 , 0 , nativeTarget . Width , nativeTarget . Height ) ;
267- if ( ! nativeBounds . Contains ( targetBounds ) )
268- {
269- return false ;
270- }
271-
272- WebGPU api = WebGPURuntime . GetApi ( ) ;
273- WebGPURuntime . DeviceSharedState deviceState = WebGPURuntime . GetOrCreateDeviceState ( api , nativeTarget . DeviceHandle ) ;
274- if ( requiredFeature != FeatureName . Undefined && ! deviceState . HasFeature ( requiredFeature ) )
275- {
276- return false ;
277- }
278-
279- textureFormat = WebGPUTextureFormatMapper . ToSilk ( nativeTarget . TargetFormat ) ;
280- return true ;
281- }
282-
283221 /// <summary>
284222 /// Computes the maximum scratch capacities observed across render attempts.
285223 /// </summary>
0 commit comments