Explorar el Código

Implement readPixels in WebGPU

Popov72 hace 4 años
padre
commit
ce849b8f47

+ 1 - 1
src/Engines/thinEngine.ts

@@ -4391,7 +4391,7 @@ export class ThinEngine {
      * @param hasAlpha defines whether the output should have alpha or not (defaults to true)
      * @returns a Uint8Array containing RGBA colors
      */
-    public readPixels(x: number, y: number, width: number, height: number, hasAlpha = true): Uint8Array {
+    public readPixels(x: number, y: number, width: number, height: number, hasAlpha = true): Promise<Uint8Array> | Uint8Array {
         const numChannels = hasAlpha ? 4 : 3;
         const format = hasAlpha ? this._gl.RGBA : this._gl.RGB;
         const data = new Uint8Array(height * width * numChannels);

+ 37 - 2
src/Engines/webgpuEngine.ts

@@ -131,6 +131,7 @@ export class WebGPUEngine extends Engine {
     private _device: GPUDevice;
     private _context: GPUCanvasContext;
     private _swapChain: GPUSwapChain;
+    private _swapChainTexture: GPUTexture;
     private _mainPassSampleCount: number;
     private _textureHelper: WebGPUTextureHelper;
     private _bufferManager: WebGPUBufferManager;
@@ -1571,6 +1572,38 @@ export class WebGPUEngine extends Engine {
         this._textureHelper.updateTexture(bitmap, gpuTexture, width, height, faceIndex, lod, texture.invertY, false, 0, 0, this._uploadEncoder);
     }
 
+    public readPixels(x: number, y: number, width: number, height: number, hasAlpha = true): Promise<Uint8Array> | Uint8Array {
+        const numChannels = 4; // no RGB format in WebGPU
+        const size = height * width * numChannels;
+
+        const buffer = this._bufferManager.createRawBuffer(size, GPUBufferUsage.MAP_READ | GPUBufferUsage.COPY_DST);
+
+        const commandEncoder = this._device.createCommandEncoder({});
+
+        commandEncoder.copyTextureToBuffer({
+            texture: this._swapChainTexture,
+            mipLevel: 0,
+            origin: {
+                x,
+                y,
+                z: 0
+            }
+        }, {
+            buffer: buffer,
+            offset: 0,
+            bytesPerRow: width * numChannels,
+            rowsPerImage: height
+        }, {
+            width,
+            height,
+            depth: 1
+        });
+
+        this._device.defaultQueue.submit([commandEncoder!.finish()]);
+
+        return this._bufferManager.readDataFromBuffer(buffer, size);
+    }
+
     /** @hidden */
     public _readTexturePixels(texture: InternalTexture, width: number, height: number, faceIndex = -1, level = 0, buffer: Nullable<ArrayBufferView> = null): ArrayBufferView {
         console.warn("_readTexturePixels not implemented yet in WebGPU");
@@ -1734,12 +1767,14 @@ export class WebGPUEngine extends Engine {
             this._endRenderPass();
         }
 
+        this._swapChainTexture = this._swapChain.getCurrentTexture();
+
         // Resolve in case of MSAA
         if (this._options.antialiasing) {
-            this._mainColorAttachments[0].resolveTarget = this._swapChain.getCurrentTexture().createView();
+            this._mainColorAttachments[0].resolveTarget = this._swapChainTexture.createView();
         }
         else {
-            this._mainColorAttachments[0].attachment = this._swapChain.getCurrentTexture().createView();
+            this._mainColorAttachments[0].attachment = this._swapChainTexture.createView();
         }
 
         this._currentRenderPass = this._renderEncoder.beginRenderPass({

+ 8 - 1
src/PostProcesses/RenderPipeline/Pipelines/standardRenderingPipeline.ts

@@ -929,7 +929,14 @@ export class StandardRenderingPipeline extends PostProcessRenderPipeline impleme
                 pp.onAfterRender = () => {
                     var pixel = scene.getEngine().readPixels(0, 0, 1, 1);
                     var bit_shift = new Vector4(1.0 / (255.0 * 255.0 * 255.0), 1.0 / (255.0 * 255.0), 1.0 / 255.0, 1.0);
-                    this._hdrCurrentLuminance = (pixel[0] * bit_shift.x + pixel[1] * bit_shift.y + pixel[2] * bit_shift.z + pixel[3] * bit_shift.w) / 100.0;
+                    if ((pixel as Uint8Array).byteLength !== undefined) {
+                        pixel = pixel as Uint8Array;
+                        this._hdrCurrentLuminance = (pixel[0] * bit_shift.x + pixel[1] * bit_shift.y + pixel[2] * bit_shift.z + pixel[3] * bit_shift.w) / 100.0;
+                    } else {
+                        (pixel as Promise<Uint8Array>).then((pixel) => {
+                            this._hdrCurrentLuminance = (pixel[0] * bit_shift.x + pixel[1] * bit_shift.y + pixel[2] * bit_shift.z + pixel[3] * bit_shift.w) / 100.0;
+                        });
+                    }
                 };
             }