(framebuffer, x, y, w, h)
| 3869 | } |
| 3870 | |
| 3871 | async readFramebufferRegion(framebuffer, x, y, w, h) { |
| 3872 | this.flushDraw(); |
| 3873 | // await this.finishDraw(); |
| 3874 | // const wasActive = this.activeFramebuffer() === framebuffer; |
| 3875 | // if (wasActive) { |
| 3876 | // framebuffer.end(); |
| 3877 | // this.flushDraw() |
| 3878 | // } |
| 3879 | // Ensure all pending GPU work is complete before reading pixels |
| 3880 | // await this.queue.onSubmittedWorkDone(); |
| 3881 | |
| 3882 | const width = w * framebuffer.density; |
| 3883 | const height = h * framebuffer.density; |
| 3884 | const bytesPerPixel = 4; |
| 3885 | const unalignedBytesPerRow = width * bytesPerPixel; |
| 3886 | const alignedBytesPerRow = this._alignBytesPerRow(unalignedBytesPerRow); |
| 3887 | const bufferSize = alignedBytesPerRow * height; |
| 3888 | |
| 3889 | const stagingBuffer = this._ensurePixelReadBuffer(bufferSize); |
| 3890 | |
| 3891 | const commandEncoder = this.device.createCommandEncoder(); |
| 3892 | commandEncoder.copyTextureToBuffer( |
| 3893 | { |
| 3894 | texture: framebuffer.colorTexture, |
| 3895 | mipLevel: 0, |
| 3896 | origin: { x: x * framebuffer.density, y: y * framebuffer.density, z: 0 } |
| 3897 | }, |
| 3898 | { buffer: stagingBuffer, bytesPerRow: alignedBytesPerRow }, |
| 3899 | { width, height, depthOrArrayLayers: 1 } |
| 3900 | ); |
| 3901 | |
| 3902 | this.device.queue.submit([commandEncoder.finish()]); |
| 3903 | |
| 3904 | await stagingBuffer.mapAsync(GPUMapMode.READ, 0, bufferSize); |
| 3905 | const mappedRange = stagingBuffer.getMappedRange(0, bufferSize); |
| 3906 | |
| 3907 | let pixelData; |
| 3908 | if (alignedBytesPerRow === unalignedBytesPerRow) { |
| 3909 | pixelData = new Uint8Array(mappedRange.slice(0, width * height * bytesPerPixel)); |
| 3910 | } else { |
| 3911 | // Need to extract pixel data from aligned buffer |
| 3912 | pixelData = new Uint8Array(width * height * bytesPerPixel); |
| 3913 | const mappedData = new Uint8Array(mappedRange); |
| 3914 | for (let y = 0; y < height; y++) { |
| 3915 | const srcOffset = y * alignedBytesPerRow; |
| 3916 | const dstOffset = y * unalignedBytesPerRow; |
| 3917 | pixelData.set(mappedData.subarray(srcOffset, srcOffset + unalignedBytesPerRow), dstOffset); |
| 3918 | } |
| 3919 | } |
| 3920 | this._ensurePixelsAreRGBA(framebuffer, pixelData); |
| 3921 | |
| 3922 | // WebGPU doesn't need vertical flipping unlike WebGL |
| 3923 | const region = new Image(width, height); |
| 3924 | region.imageData = region.canvas.getContext('2d').createImageData(width, height); |
| 3925 | region.imageData.data.set(pixelData); |
| 3926 | region.pixels = region.imageData.data; |
| 3927 | region.updatePixels(); |
| 3928 |
nothing calls this directly
no test coverage detected