Skip to content

Commit 1173b89

Browse files
committed
support read default framebuffer's pixels and defense out of texture reading
1 parent 5fb6607 commit 1173b89

File tree

1 file changed

+31
-11
lines changed

1 file changed

+31
-11
lines changed

packages/reshader.gl/src/webgpu/GraphicsDevice.ts

Lines changed: 31 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -161,22 +161,42 @@ export default class GraphicsDevice {
161161
// 2. 将OffscreenCanvas绘制到一个canvas 2d上
162162
// 3. 从canvas 2d上读取数据
163163
const framebuffer = options.framebuffer || this._defaultFramebuffer;
164+
const fboWidth = framebuffer.width;
165+
const fboHeight = framebuffer.height;
164166
let { width, height } = options;
165167
if (!width) {
166-
width = framebuffer.width;
168+
width = fboWidth;
167169
}
168170
if (!height) {
169-
height = framebuffer.height;
171+
height = fboHeight;
170172
}
171173
const device = this.wgpu;
172-
const colorTexture = framebuffer.colorTexture;
173-
if (!colorTexture) {
174-
return;
175-
}
176174
this.submit();
177-
const origin = { x: options.x, y: framebuffer.height - options.y, z: 0 };
178-
const alphaModes: GPUCanvasAlphaMode[] = ['opaque', 'premultiplied'];
175+
const origin = { x: options.x, y: fboHeight - options.y, z: 0 };
176+
if (origin.x + width > fboWidth) {
177+
origin.x = fboWidth - width;
178+
}
179+
if (origin.y + height > fboHeight) {
180+
origin.y = fboHeight - height;
181+
}
179182
const data = options.pixels || new Uint8Array(width * height * 4);
183+
if (framebuffer === this._defaultFramebuffer) {
184+
// read default framebuffer
185+
const stagingHostStorage = new OffscreenCanvas(width, height);
186+
const ctx = stagingHostStorage.getContext('2d', {
187+
willReadFrequently: true,
188+
});
189+
ctx.drawImage(this.context.canvas, origin.x, origin.y, width, height, 0, 0, width, height);
190+
const stagingValues = ctx.getImageData(0, 0, width, height).data;;
191+
for (let k = 0; k < data.length; k += 4) {
192+
data[k] = stagingValues[k];
193+
data[k + 1] = stagingValues[k + 1];
194+
data[k + 2] = stagingValues[k + 2];
195+
data[k + 3] = stagingValues[k + 3];
196+
}
197+
return data;
198+
}
199+
const alphaModes: GPUCanvasAlphaMode[] = ['opaque', 'premultiplied'];
180200
const stagingDeviceStorage: OffscreenCanvas[] =
181201
alphaModes.map(_ => new OffscreenCanvas(width, height));
182202
// TODO: use rgba8unorm format when this format is supported on Mac.
@@ -192,14 +212,14 @@ export default class GraphicsDevice {
192212
return context.getCurrentTexture();
193213
}).map((storageTexture, index) => {
194214
const encoder = device.createCommandEncoder();
195-
encoder.copyTextureToTexture({ texture: colorTexture.texture, origin }, { texture: storageTexture }, { width, height });
215+
encoder.copyTextureToTexture({ texture: framebuffer.colorTexture.texture, origin }, { texture: storageTexture }, { width, height });
196216
this.wgpu.queue.submit([encoder.finish()]);
197217
const stagingHostStorage = new OffscreenCanvas(width, height);
198218
const ctx = stagingHostStorage.getContext('2d', {
199219
willReadFrequently: true,
200220
});
201221
ctx.drawImage(stagingDeviceStorage[index], 0, 0);
202-
const stagingValues = ctx.getImageData(0, 0, width, height).data;;
222+
const stagingValues = ctx.getImageData(0, 0, width, height).data;
203223
const alphaMode = alphaModes[index];
204224
for (let k = 0; k < data.length; k += 4) {
205225
if (alphaMode === 'premultiplied') {
@@ -209,7 +229,7 @@ export default class GraphicsDevice {
209229
data[k + 1] = stagingValues[k + 1];
210230
data[k + 2] = stagingValues[k + 2];
211231
}
212-
}
232+
}
213233
});
214234
return data;
215235

0 commit comments

Comments
 (0)