// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. import { WebGLContext } from '../../../../lib/onnxjs/backends/webgl/webgl-context'; export function createAscendingArray(size: number): Float32Array { return new Float32Array(Array.from({ length: size }, (_v, i) => i + 1)); } // Returns an array by injecting 3 zeros after every element in the input array to be used for creating unpacked // texture. export function generateArrayForUnpackedTexture(input: Float32Array): Float32Array { const output = new Float32Array(input.length * 4); for (let i = 0; i < input.length * 4; i += 4) { output[i] = input[i / 4]; } return output; } // create a webgl texture and fill it with the array content export function createTextureFromArray( glContext: WebGLContext, dataArray: Float32Array, width: number, height: number, ): WebGLTexture { const gl = glContext.gl; // create the texture const texture = gl.createTexture(); if (!texture) { throw new Error('failed to create texture'); } // bind the texture so the following methods effect this texture. gl.bindTexture(gl.TEXTURE_2D, texture); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); if (glContext.version === 2) { const webgl2Gl = gl as WebGL2RenderingContext; gl.texImage2D(webgl2Gl.TEXTURE_2D, 0, webgl2Gl.RGBA32F, width, height, 0, webgl2Gl.RGBA, webgl2Gl.FLOAT, dataArray); } else { gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, gl.RGBA, gl.FLOAT, dataArray); } glContext.checkError(); return texture; } // create a cpu array and download GPU texture data to this array export function createArrayFromTexture( gl: WebGLRenderingContext, texture: WebGLTexture, width: number, height: number, ): Float32Array { const resultDataBuffer = new Float32Array(width * height * 4); gl.bindTexture(gl.TEXTURE_2D, texture); gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture, 0); // 0, we aren't using MIPMAPs gl.readPixels(0, 0, width, height, gl.RGBA, gl.FLOAT, resultDataBuffer); return resultDataBuffer; } export function getExpectedElementCount(inputShape: number[], isPacked = true): number { const rank = inputShape.length; if (isPacked) { // scalar if (rank === 0) { return 4; } // 1D tensor if (rank === 1) { if (inputShape[0] % 2) { return (inputShape[0] + 1) * 2; } else { return inputShape[0] * 2; } } // process width let inputWidth = inputShape[rank - 2] % 2 ? inputShape[rank - 2] + 1 : inputShape[rank - 2]; if (rank > 2) { for (let i = 0; i < rank - 2; ++i) { inputWidth *= inputShape[i]; } } // process height let inputHeight = inputShape[rank - 1]; if (inputHeight % 2) { inputHeight++; } return inputWidth * inputHeight; } else { let totalCount = 1; for (let i = 0; i < rank; i++) { totalCount *= inputShape[i]; } return totalCount; } } export function generateExpected(inputArray: Float32Array, inputShape: number[]): Float32Array { if (inputShape.length === 0) { const result = new Float32Array(4); result[0] = inputArray[0]; return result; } const rank = inputShape.length; const inputHeight = rank === 1 ? 1 : inputShape[rank - 2]; const inputWidth = inputShape[rank - 1]; const paddedW = inputWidth % 2 ? inputWidth + 1 : inputWidth; const paddedH = inputHeight % 2 ? inputHeight + 1 : inputHeight; let B = 1; if (rank > 2) { for (let i = 0; i < rank - 2; ++i) { B *= inputShape[i]; } } const result = new Float32Array(B * paddedW * paddedH); let ii = 0; for (let b = 0; b < B; ++b) { for (let j = 0; j < paddedH; j += 2) { for (let i = 0; i < paddedW; i += 2) { const index = j * inputWidth + i + b * (inputHeight * inputWidth); result[ii++] = inputArray[index]; if (i + 1 < inputWidth) { result[ii++] = inputArray[index + 1]; } else { result[ii++] = 0; } if (j + 1 < inputHeight) { result[ii++] = inputArray[(j + 1) * inputWidth + i + b * (inputHeight * inputWidth)]; } else { result[ii++] = 0; } if (i + 1 < inputWidth && j + 1 < inputHeight) { result[ii++] = inputArray[(j + 1) * inputWidth + i + 1 + b * (inputHeight * inputWidth)]; } else { result[ii++] = 0; } } } } return result; }