@next2d/webgpu 3.0.1 → 3.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@next2d/webgpu",
3
- "version": "3.0.1",
3
+ "version": "3.0.3",
4
4
  "description": "Next2D WebGPU Package",
5
5
  "author": "Toshiyuki Ienaga<ienaga@next2d.app> (https://github.com/ienaga/)",
6
6
  "license": "MIT",
@@ -24,7 +24,7 @@
24
24
  "url": "git+https://github.com/Next2D/Player.git"
25
25
  },
26
26
  "dependencies": {
27
- "@next2d/texture-packer": "3.0.1",
28
- "@next2d/render-queue": "3.0.1"
27
+ "@next2d/texture-packer": "3.0.3",
28
+ "@next2d/render-queue": "3.0.3"
29
29
  }
30
30
  }
package/src/Context.d.ts CHANGED
@@ -59,6 +59,7 @@ export declare class Context {
59
59
  private fillDynamicBindGroupBuffer;
60
60
  private nodeClearQuadBuffer;
61
61
  private useOptimizedInstancing;
62
+ private $needsReconfigure;
62
63
  private readonly $uniformData8;
63
64
  private readonly $scissorRect;
64
65
  private readonly $filterConfig;
package/src/Context.js CHANGED
@@ -452,6 +452,14 @@ export class Context {
452
452
  writable: true,
453
453
  value: true
454
454
  });
455
+ // リサイズ後にcanvasContextの再設定が必要かどうか
456
+ // ($resizeComplete()でcanvas.width/heightが設定された後、ensureMainTexture()でconfigure()を呼ぶ)
457
+ Object.defineProperty(this, "$needsReconfigure", {
458
+ enumerable: true,
459
+ configurable: true,
460
+ writable: true,
461
+ value: false
462
+ });
455
463
  // Hot Path 用の事前割り当てバッファ
456
464
  Object.defineProperty(this, "$uniformData8", {
457
465
  enumerable: true,
@@ -636,13 +644,9 @@ export class Context {
636
644
  this.currentRenderTarget = null;
637
645
  // マスク状態をリセット
638
646
  $resetMaskState();
639
- // キャンバスのサイズを更新
640
- const canvas = this.canvasContext.canvas;
641
- // 型チェックを安全に実行(Worker環境対応)
642
- if (canvas && "width" in canvas && "height" in canvas) {
643
- canvas.width = width;
644
- canvas.height = height;
645
- }
647
+ // キャンバスのサイズ更新は$resizeComplete()に任せる
648
+ // WebGPUではcanvas.width/height設定でコンテキストが暗黙的にunconfigureされるため、
649
+ // 描画フレーム開始前に$resizeComplete()→configure()→getCurrentTexture()の順で実行する
646
650
  // WebGL版と同じ: スタックにあるアタッチメントも解放
647
651
  if (this.$stackAttachmentObject.length) {
648
652
  for (let idx = 0; idx < this.$stackAttachmentObject.length; ++idx) {
@@ -686,12 +690,9 @@ export class Context {
686
690
  }
687
691
  // アンバインド(WebGL版と同じ)
688
692
  this.frameBufferManager.setCurrentAttachment(null);
689
- // canvasContextを再設定
690
- this.canvasContext.configure({
691
- "device": this.device,
692
- "format": this.preferredFormat,
693
- "alphaMode": "premultiplied"
694
- });
693
+ // canvasContextの再設定はensureMainTexture()で行う
694
+ // $resizeComplete()でcanvas.width/heightが設定された後にconfigure()→getCurrentTexture()を実行するため
695
+ this.$needsReconfigure = true;
695
696
  // リサイズ時にスワップチェーンテクスチャをリセット
696
697
  // 古いテクスチャ参照を解放して、次のフレームで新しいサイズのテクスチャを取得
697
698
  this.mainTexture = null;
@@ -2014,6 +2015,16 @@ export class Context {
2014
2015
  */
2015
2016
  ensureMainTexture() {
2016
2017
  if (!this.mainTexture) {
2018
+ // リサイズ後はcanvas.width/heightが$resizeComplete()で更新されているので
2019
+ // ここでconfigure()を呼んでからgetCurrentTexture()を取得する
2020
+ if (this.$needsReconfigure) {
2021
+ this.canvasContext.configure({
2022
+ "device": this.device,
2023
+ "format": this.preferredFormat,
2024
+ "alphaMode": "premultiplied"
2025
+ });
2026
+ this.$needsReconfigure = false;
2027
+ }
2017
2028
  this.mainTexture = this.canvasContext.getCurrentTexture();
2018
2029
  this.mainTextureView = this.mainTexture.createView();
2019
2030
  }
@@ -2216,10 +2227,11 @@ export class Context {
2216
2227
  * @description ImageBitmapを生成
2217
2228
  */
2218
2229
  async createImageBitmap(width, height) {
2219
- // アトラステクスチャから現在の描画内容を取得
2220
- const attachment = $getAtlasAttachmentObject();
2221
- if (!attachment) {
2222
- throw new Error("[WebGPU] Atlas attachment not found");
2230
+ // メインアタッチメントから合成済み描画結果を取得
2231
+ // (drawArraysInstanced()がアトラスからメインアタッチメントへ合成済み)
2232
+ const mainAttachment = this.$mainAttachmentObject;
2233
+ if (!mainAttachment || !mainAttachment.texture) {
2234
+ throw new Error("[WebGPU] Main attachment not found");
2223
2235
  }
2224
2236
  // 描画を完了
2225
2237
  if (this.renderPassEncoder) {
@@ -2235,14 +2247,11 @@ export class Context {
2235
2247
  "size": bufferSize,
2236
2248
  "usage": GPUBufferUsage.COPY_DST | GPUBufferUsage.MAP_READ
2237
2249
  });
2238
- // コマンドエンコーダーを作成
2239
- const commandEncoder = this.device.createCommandEncoder();
2240
- // アトラステクスチャからピクセルバッファにコピー
2241
- if (!attachment.texture) {
2242
- throw new Error("Attachment texture is null");
2243
- }
2244
- commandEncoder.copyTextureToBuffer({
2245
- "texture": attachment.texture.resource,
2250
+ // フレームのcommandEncoderにcopyコマンドを追加
2251
+ // 描画コマンドの後にコピーが実行されるため、正しい順序が保証される
2252
+ this.ensureCommandEncoder();
2253
+ this.commandEncoder.copyTextureToBuffer({
2254
+ "texture": mainAttachment.texture.resource,
2246
2255
  "mipLevel": 0,
2247
2256
  "origin": { "x": 0, "y": 0, "z": 0 }
2248
2257
  }, {
@@ -2254,18 +2263,32 @@ export class Context {
2254
2263
  "height": height,
2255
2264
  "depthOrArrayLayers": 1
2256
2265
  });
2257
- // コマンドを送信
2258
- this.device.queue.submit([commandEncoder.finish()]);
2266
+ // endFrame()で描画コマンドとcopyコマンドを一括submit
2267
+ // swap chain textureの参照もクリアされる
2268
+ this.endFrame();
2259
2269
  // バッファをマップして読み込み
2260
2270
  await pixelBuffer.mapAsync(GPUMapMode.READ);
2261
2271
  const mappedRange = pixelBuffer.getMappedRange();
2262
2272
  const pixels = new Uint8Array(mappedRange);
2263
- // ピクセルデータをコピー(アライメントを考慮)
2273
+ // メインアタッチメントはbgra8unormフォーマットのため、
2274
+ // ImageData(RGBA)用にB⇔Rチャンネルをスワップしつつコピー
2275
+ const isBgra = this.preferredFormat === "bgra8unorm";
2264
2276
  const resultPixels = new Uint8Array(width * height * 4);
2277
+ const rowBytes = width * 4;
2265
2278
  for (let y = 0; y < height; y++) {
2266
2279
  const srcOffset = y * bytesPerRow;
2267
- const dstOffset = y * width * 4;
2268
- resultPixels.set(pixels.subarray(srcOffset, srcOffset + width * 4), dstOffset);
2280
+ const dstOffset = y * rowBytes;
2281
+ if (isBgra) {
2282
+ for (let x = 0; x < rowBytes; x += 4) {
2283
+ resultPixels[dstOffset + x] = pixels[srcOffset + x + 2]; // R ← B
2284
+ resultPixels[dstOffset + x + 1] = pixels[srcOffset + x + 1]; // G
2285
+ resultPixels[dstOffset + x + 2] = pixels[srcOffset + x]; // B ← R
2286
+ resultPixels[dstOffset + x + 3] = pixels[srcOffset + x + 3]; // A
2287
+ }
2288
+ }
2289
+ else {
2290
+ resultPixels.set(pixels.subarray(srcOffset, srcOffset + rowBytes), dstOffset);
2291
+ }
2269
2292
  }
2270
2293
  pixelBuffer.unmap();
2271
2294
  pixelBuffer.destroy();