Skip to content

Comments

webgpu: captureToCanvasのバグ修正#256

Merged
ienaga merged 3 commits intomainfrom
develop
Feb 13, 2026
Merged

webgpu: captureToCanvasのバグ修正#256
ienaga merged 3 commits intomainfrom
develop

Conversation

@ienaga
Copy link
Member

@ienaga ienaga commented Feb 13, 2026

No description provided.

Copilot AI review requested due to automatic review settings February 13, 2026 15:24
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

WebGPU 環境での captureToCanvas の不具合修正を目的とし、キャプチャ用の読み戻し元を適切なアタッチメントに変更しつつ、プレイヤーバージョンを 3.0.3 に更新するPRです。

Changes:

  • WebGPU の Context.createImageBitmap() を「アトラス」ではなく「メインアタッチメント」から読み戻すように変更
  • copyTextureToBuffer をフレームの commandEncoder に追加し、endFrame() でまとめて submit する方式に変更
  • パッケージ/表示バージョンを 3.0.2 → 3.0.3 に更新

Reviewed changes

Copilot reviewed 3 out of 4 changed files in this pull request and generated 3 comments.

File Description
src/index.ts 起動ログのバージョン表記を 3.0.3 に更新
packages/webgpu/src/Context.ts キャプチャの読み戻し元・submit順序・BGRA→RGBA 変換処理を更新
package.json パッケージバージョンを 3.0.3 に更新
package-lock.json ロックファイル内バージョンを 3.0.3 に更新

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 2773 to 2797
@@ -2795,23 +2792,36 @@ export class Context
}
);

// コマンドを送信
this.device.queue.submit([commandEncoder.finish()]);
// endFrame()で描画コマンドとcopyコマンドを一括submit
// swap chain textureの参照もクリアされる
this.endFrame();
Copy link

Copilot AI Feb 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

createImageBitmap() now relies on endFrame() to submit the copyTextureToBuffer command, but endFrame() is a no-op when frameStarted is false. If this API is called before beginFrame()/drawArraysInstanced(), the copy will never be submitted and mapAsync() can hang. Consider ensuring the frame is started here (e.g., call beginFrame() when needed / set frameStarted) or submit a dedicated command buffer for the copy like the previous implementation, instead of depending on endFrame().

Copilot uses AI. Check for mistakes.
Comment on lines +2804 to +2805
// メインアタッチメントはbgra8unormフォーマットのため、
// ImageData(RGBA)用にB⇔Rチャンネルをスワップしつつコピー
Copy link

Copilot AI Feb 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment says the main attachment is bgra8unorm, but the code already supports other formats via preferredFormat. To avoid misleading future maintainers (and accidental regressions if preferredFormat is rgba8unorm), update the comment to describe the conditional swap (e.g., only swap channels when preferredFormat is BGRA).

Suggested change
// メインアタッチメントはbgra8unormフォーマットのため
// ImageData(RGBA)用にB⇔Rチャンネルをスワップしつつコピー
// メインアタッチメントのフォーマットが bgra8unorm の場合は
// ImageData(RGBA)用に B⇔R チャンネルをスワップしつつコピー(それ以外のフォーマットはそのままコピー)

Copilot uses AI. Check for mistakes.
Comment on lines 2747 to 2824
@@ -2769,17 +2770,13 @@ export class Context
"usage": GPUBufferUsage.COPY_DST | GPUBufferUsage.MAP_READ
});

// コマンドエンコーダーを作成
const commandEncoder = this.device.createCommandEncoder();

// アトラステクスチャからピクセルバッファにコピー
if (!attachment.texture) {
throw new Error("Attachment texture is null");
}
// フレームのcommandEncoderにcopyコマンドを追加
// 描画コマンドの後にコピーが実行されるため、正しい順序が保証される
this.ensureCommandEncoder();

commandEncoder.copyTextureToBuffer(
this.commandEncoder!.copyTextureToBuffer(
{
"texture": attachment.texture.resource,
"texture": mainAttachment.texture.resource,
"mipLevel": 0,
"origin": { "x": 0, "y": 0, "z": 0 }
},
@@ -2795,23 +2792,36 @@ export class Context
}
);

// コマンドを送信
this.device.queue.submit([commandEncoder.finish()]);
// endFrame()で描画コマンドとcopyコマンドを一括submit
// swap chain textureの参照もクリアされる
this.endFrame();

// バッファをマップして読み込み
await pixelBuffer.mapAsync(GPUMapMode.READ);
const mappedRange = pixelBuffer.getMappedRange();
const pixels = new Uint8Array(mappedRange);

// ピクセルデータをコピー(アライメントを考慮)
// メインアタッチメントはbgra8unormフォーマットのため、
// ImageData(RGBA)用にB⇔Rチャンネルをスワップしつつコピー
const isBgra = this.preferredFormat === "bgra8unorm";
const resultPixels = new Uint8Array(width * height * 4);
const rowBytes = width * 4;
for (let y = 0; y < height; y++) {
const srcOffset = y * bytesPerRow;
const dstOffset = y * width * 4;
resultPixels.set(
pixels.subarray(srcOffset, srcOffset + width * 4),
dstOffset
);
const dstOffset = y * rowBytes;
if (isBgra) {
for (let x = 0; x < rowBytes; x += 4) {
resultPixels[dstOffset + x ] = pixels[srcOffset + x + 2]; // R ← B
resultPixels[dstOffset + x + 1] = pixels[srcOffset + x + 1]; // G
resultPixels[dstOffset + x + 2] = pixels[srcOffset + x ]; // B ← R
resultPixels[dstOffset + x + 3] = pixels[srcOffset + x + 3]; // A
}
} else {
resultPixels.set(
pixels.subarray(srcOffset, srcOffset + rowBytes),
dstOffset
);
}
Copy link

Copilot AI Feb 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change alters capture output semantics (source attachment + color channel order) and introduces new ordering/submission behavior via ensureCommandEncoder()+endFrame(). Context.test.ts exists but doesn't cover createImageBitmap(); adding a unit test that validates correct RGBA output (especially on BGRA preferredFormat) and that the copy command gets submitted would help prevent regressions.

Copilot uses AI. Check for mistakes.
@ienaga ienaga merged commit 328e71f into main Feb 13, 2026
21 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

1 participant