@@ -161,22 +161,42 @@ export default class GraphicsDevice {
161
161
// 2. 将OffscreenCanvas绘制到一个canvas 2d上
162
162
// 3. 从canvas 2d上读取数据
163
163
const framebuffer = options . framebuffer || this . _defaultFramebuffer ;
164
+ const fboWidth = framebuffer . width ;
165
+ const fboHeight = framebuffer . height ;
164
166
let { width, height } = options ;
165
167
if ( ! width ) {
166
- width = framebuffer . width ;
168
+ width = fboWidth ;
167
169
}
168
170
if ( ! height ) {
169
- height = framebuffer . height ;
171
+ height = fboHeight ;
170
172
}
171
173
const device = this . wgpu ;
172
- const colorTexture = framebuffer . colorTexture ;
173
- if ( ! colorTexture ) {
174
- return ;
175
- }
176
174
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
+ }
179
182
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' ] ;
180
200
const stagingDeviceStorage : OffscreenCanvas [ ] =
181
201
alphaModes . map ( _ => new OffscreenCanvas ( width , height ) ) ;
182
202
// TODO: use rgba8unorm format when this format is supported on Mac.
@@ -192,14 +212,14 @@ export default class GraphicsDevice {
192
212
return context . getCurrentTexture ( ) ;
193
213
} ) . map ( ( storageTexture , index ) => {
194
214
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 } ) ;
196
216
this . wgpu . queue . submit ( [ encoder . finish ( ) ] ) ;
197
217
const stagingHostStorage = new OffscreenCanvas ( width , height ) ;
198
218
const ctx = stagingHostStorage . getContext ( '2d' , {
199
219
willReadFrequently : true ,
200
220
} ) ;
201
221
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 ;
203
223
const alphaMode = alphaModes [ index ] ;
204
224
for ( let k = 0 ; k < data . length ; k += 4 ) {
205
225
if ( alphaMode === 'premultiplied' ) {
@@ -209,7 +229,7 @@ export default class GraphicsDevice {
209
229
data [ k + 1 ] = stagingValues [ k + 1 ] ;
210
230
data [ k + 2 ] = stagingValues [ k + 2 ] ;
211
231
}
212
- }
232
+ }
213
233
} ) ;
214
234
return data ;
215
235
0 commit comments