From 31ccf098267bc87c4c925feb6424ed396cbb3489 Mon Sep 17 00:00:00 2001 From: ienaga Date: Sat, 14 Feb 2026 00:02:15 +0900 Subject: [PATCH 1/3] =?UTF-8?q?#255=20=E3=83=90=E3=83=BC=E3=82=B8=E3=83=A7?= =?UTF-8?q?=E3=83=B3=E6=83=85=E5=A0=B1=E3=82=92=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/index.ts b/src/index.ts index dac3ae5a..37751284 100644 --- a/src/index.ts +++ b/src/index.ts @@ -3,7 +3,7 @@ import { Next2D } from "@next2d/core"; if (!("next2d" in window)) { - console.log("%c Next2D Player %c 3.0.2 %c https://next2d.app", + console.log("%c Next2D Player %c 3.0.3 %c https://next2d.app", "color: #fff; background: #5f5f5f", "color: #fff; background: #4bc729", ""); From 5bc0e03edb06a0371606f746cf794e40e3f49e90 Mon Sep 17 00:00:00 2001 From: ienaga Date: Sat, 14 Feb 2026 00:02:42 +0900 Subject: [PATCH 2/3] #255 update packages --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 62d4aea8..e84f86b1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@next2d/player", - "version": "3.0.2", + "version": "3.0.3", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@next2d/player", - "version": "3.0.2", + "version": "3.0.3", "license": "MIT", "workspaces": [ "packages/*" diff --git a/package.json b/package.json index 096ed3c7..2dc2cadc 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@next2d/player", - "version": "3.0.2", + "version": "3.0.3", "description": "Experience the fast and beautiful anti-aliased rendering of WebGL. You can create rich, interactive graphics, cross-platform applications and games without worrying about browser or device compatibility.", "author": "Toshiyuki Ienaga (https://github.com/ienaga/)", "license": "MIT", From 411ca5edc0dc16c435220c0e103ead90ff474d30 Mon Sep 17 00:00:00 2001 From: ienaga Date: Sat, 14 Feb 2026 00:23:44 +0900 Subject: [PATCH 3/3] =?UTF-8?q?#255=20captureToCanvas=E9=96=A2=E6=95=B0?= =?UTF-8?q?=E3=81=AEwebgpu=E7=89=88=E3=82=92=E6=94=B9=E4=BF=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/webgpu/src/Context.ts | 52 ++++++++++++++++++++-------------- 1 file changed, 31 insertions(+), 21 deletions(-) diff --git a/packages/webgpu/src/Context.ts b/packages/webgpu/src/Context.ts index bc622f48..3e80c193 100644 --- a/packages/webgpu/src/Context.ts +++ b/packages/webgpu/src/Context.ts @@ -2746,10 +2746,11 @@ export class Context */ async createImageBitmap (width: number, height: number): Promise { - // アトラステクスチャから現在の描画内容を取得 - const attachment = $getAtlasAttachmentObject(); - if (!attachment) { - throw new Error("[WebGPU] Atlas attachment not found"); + // メインアタッチメントから合成済み描画結果を取得 + // (drawArraysInstanced()がアトラスからメインアタッチメントへ合成済み) + const mainAttachment = this.$mainAttachmentObject; + if (!mainAttachment || !mainAttachment.texture) { + throw new Error("[WebGPU] Main attachment not found"); } // 描画を完了 @@ -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 + ); + } } pixelBuffer.unmap();