diff --git a/tfjs-backend-webgpu/src/kernels/BatchMatMul_impl.ts b/tfjs-backend-webgpu/src/kernels/BatchMatMul_impl.ts index abb2732cbb8..577081c7ade 100644 --- a/tfjs-backend-webgpu/src/kernels/BatchMatMul_impl.ts +++ b/tfjs-backend-webgpu/src/kernels/BatchMatMul_impl.ts @@ -144,8 +144,8 @@ export function batchMatMulImpl({ const dimInner = transposeA === true ? a3d.shape[1] : a3d.shape[2]; const dimBOuter = transposeB === true ? b3d.shape[1] : b3d.shape[2]; dimensions = [ - {type: 'uint32', data: [dimAOuter]}, {type: 'uint32', data: [dimBOuter]}, - {type: 'uint32', data: [dimInner]} + {type: 'int32', data: [dimAOuter]}, {type: 'int32', data: [dimBOuter]}, + {type: 'int32', data: [dimInner]} ]; } const out = backend.runWebGPUProgram(program, inputs, a.dtype, dimensions); diff --git a/tfjs-backend-webgpu/src/kernels/Conv2D.ts b/tfjs-backend-webgpu/src/kernels/Conv2D.ts index 19127f02d50..8cf31042f9b 100644 --- a/tfjs-backend-webgpu/src/kernels/Conv2D.ts +++ b/tfjs-backend-webgpu/src/kernels/Conv2D.ts @@ -76,9 +76,9 @@ export function conv2d( const dimInner = convInfo.filterHeight * convInfo.filterWidth * convInfo.inShape[3]; dimensions.push( - {type: 'uint32', data: [dimAOuter]}, - {type: 'uint32', data: [dimBOuter]}, - {type: 'uint32', data: [dimInner]}); + {type: 'int32', data: [dimAOuter]}, + {type: 'int32', data: [dimBOuter]}, + {type: 'int32', data: [dimInner]}); } return backend.runWebGPUProgram(program, [x, filter], x.dtype, dimensions); diff --git a/tfjs-backend-webgpu/src/kernels/Conv2D_impl.ts b/tfjs-backend-webgpu/src/kernels/Conv2D_impl.ts index c509597ee2d..e13e594b2fc 100644 --- a/tfjs-backend-webgpu/src/kernels/Conv2D_impl.ts +++ b/tfjs-backend-webgpu/src/kernels/Conv2D_impl.ts @@ -166,8 +166,8 @@ export function conv2dWithIm2Col({ const dimInner = a3dShape[2]; const dimBOuter = convInfo.outChannels; matmulDimensions = [ - {type: 'uint32', data: [dimAOuter]}, {type: 'uint32', data: [dimBOuter]}, - {type: 'uint32', data: [dimInner]} + {type: 'int32', data: [dimAOuter]}, {type: 'int32', data: [dimBOuter]}, + {type: 'int32', data: [dimInner]} ]; } diff --git a/tfjs-backend-webgpu/src/kernels/FromPixels_utils/from_pixels_webgpu.ts b/tfjs-backend-webgpu/src/kernels/FromPixels_utils/from_pixels_webgpu.ts index 0076b2500b2..84c6db2c4cd 100644 --- a/tfjs-backend-webgpu/src/kernels/FromPixels_utils/from_pixels_webgpu.ts +++ b/tfjs-backend-webgpu/src/kernels/FromPixels_utils/from_pixels_webgpu.ts @@ -74,9 +74,9 @@ export class FromPixelsProgram implements WebGPUProgram { ${getMainHeaderStringWgsl()} { ${getGlobalIndexStringWgsl()} let flatIndexBase = index * uniforms.numChannels; - let coords: vec3 = getCoordsFromFlatIndex(flatIndexBase); + let coords = getCoordsFromFlatIndex(flatIndexBase); let values = ${textureLoad}; - for (var i: u32 = 0u; i < uniforms.numChannels; i = i + 1u) { + for (var i = 0; i < uniforms.numChannels; i = i + 1) { let flatIndex = flatIndexBase + i; if (flatIndex < uniforms.size) { result.numbers[flatIndex] = i32(floor(255.0 * values[i])); diff --git a/tfjs-backend-webgpu/src/kernels/FusedConv2D.ts b/tfjs-backend-webgpu/src/kernels/FusedConv2D.ts index a740caada3c..5f9e048fa35 100644 --- a/tfjs-backend-webgpu/src/kernels/FusedConv2D.ts +++ b/tfjs-backend-webgpu/src/kernels/FusedConv2D.ts @@ -98,9 +98,9 @@ export function fusedConv2d(args: { convInfo.filterHeight * convInfo.filterWidth * convInfo.inShape[3]; if (program.useWgsl) { dimensions.push( - {type: 'uint32', data: [dimAOuter]}, - {type: 'uint32', data: [dimBOuter]}, - {type: 'uint32', data: [dimInner]}); + {type: 'int32', data: [dimAOuter]}, + {type: 'int32', data: [dimBOuter]}, + {type: 'int32', data: [dimInner]}); } } diff --git a/tfjs-backend-webgpu/src/kernels/addn_packed_webgpu.ts b/tfjs-backend-webgpu/src/kernels/addn_packed_webgpu.ts index 4b8c0840609..91425cd247c 100644 --- a/tfjs-backend-webgpu/src/kernels/addn_packed_webgpu.ts +++ b/tfjs-backend-webgpu/src/kernels/addn_packed_webgpu.ts @@ -93,8 +93,8 @@ export class AddNPackedProgram implements WebGPUProgram { const userCode = ` ${getMainHeaderStringWgsl()} { ${getGlobalIndexStringWgsl()} - for (var i = 0u; i < ${this.workPerThread}u; i = i + 1u) { - let flatIndex = index * ${this.workPerThread}u + i; + for (var i = 0; i < ${this.workPerThread}; i = i + 1) { + let flatIndex = index * ${this.workPerThread} + i; if (flatIndex < uniforms.size) { let coords = getCoordsFromFlatIndex(flatIndex); ${snippets.join('\n ')} diff --git a/tfjs-backend-webgpu/src/kernels/argminmax_webgpu.ts b/tfjs-backend-webgpu/src/kernels/argminmax_webgpu.ts index d26eeabd5b2..f1eb8a35a0a 100644 --- a/tfjs-backend-webgpu/src/kernels/argminmax_webgpu.ts +++ b/tfjs-backend-webgpu/src/kernels/argminmax_webgpu.ts @@ -31,7 +31,7 @@ export class ArgMinMaxProgram implements WebGPUProgram { workGroupSize: [number, number, number]; variableNames = ['x']; uniforms = 'int axis;'; - uniformsWgsl = 'axis : u32;'; + uniformsWgsl = 'axis : i32;'; inputShape: number[]; reductionFactor: number; op: string; @@ -203,7 +203,7 @@ export class ArgMinMaxProgram implements WebGPUProgram { // and iteratively reduced. const reduceInSharedMemory = this.workGroupSize[0] > 1; const sharedMemorySnippet = ` - var xBestIndices : array; + var xBestIndices : array; var xBestValues : array; `; @@ -211,12 +211,12 @@ export class ArgMinMaxProgram implements WebGPUProgram { xBestIndices[localId.x] = bestIndex; xBestValues[localId.x] = bestValue; - for(var currentSize = WorkGroupSize; currentSize > 1u; currentSize = DIV_CEIL(currentSize, ${ - this.reductionFactor}u)) { + for(var currentSize = WorkGroupSize; currentSize > 1; currentSize = DIV_CEIL(currentSize, ${ + this.reductionFactor})) { workgroupBarrier(); - for (var w = 0u; w < ${this.reductionFactor}u; w = w + 1u) { - let i = localId.x * ${this.reductionFactor}u + w; + for (var w = 0; w < ${this.reductionFactor}; w = w + 1) { + let i = i32(localId.x) * ${this.reductionFactor} + w; if (i < currentSize) { let candidateIndex = xBestIndices[i]; let candidate = xBestValues[i]; @@ -255,11 +255,11 @@ export class ArgMinMaxProgram implements WebGPUProgram { }; const userCode = ` - fn DIV_CEIL(a : u32, b : u32) -> u32 { - return ((a - 1u) / b + 1u); + fn DIV_CEIL(a : i32, b : i32) -> i32 { + return ((a - 1) / b + 1); } - let WorkGroupSize = ${this.workGroupSize[0]}u; + let WorkGroupSize = ${this.workGroupSize[0]}; ${reduceInSharedMemory ? sharedMemorySnippet : ''} @@ -267,31 +267,31 @@ export class ArgMinMaxProgram implements WebGPUProgram { // add back the index along the reduced dimension to |outputCoords|. // This function outputs the offset to the first value along // |axis| and the stride to get the next value of the input along |axis|. - fn getInputCoordInfo(globalId : vec3, globalIndex : u32) -> vec2{ + fn getInputCoordInfo(globalId : vec3, globalIndex : i32) -> vec2{ let outputCoords : ${ outputCoordsType} = getOutputCoords(globalId, globalIndex); - var i = ${this.outputShape.length - 1}u; + var i = ${this.outputShape.length - 1}; - var stride = 1u; - var inputStride = 1u; - var offset = 0u; + var stride = 1; + var inputStride = 1; + var offset = 0; - for (var r = 1u; r <= ${this.inputShape.length}u; r = r + 1u) { - let length = ${indexInputShape(`${this.inputShape.length}u - r`)}; - if (${this.inputShape.length}u - r == uniforms.axis) { + for (var r = 1; r <= ${this.inputShape.length}; r = r + 1) { + let length = ${indexInputShape(`${this.inputShape.length} - r`)}; + if (${this.inputShape.length} - r == uniforms.axis) { inputStride = stride; } else { offset = offset + ${ indexOutputCoords('outputCoords', 'i')} * stride; - i = i - 1u; + i = i - 1; } stride = stride * length; } - return vec2(offset, inputStride); + return vec2(offset, inputStride); } - fn getInputIndex(coordInfo : vec2, index : u32) -> u32{ + fn getInputIndex(coordInfo : vec2, index : i32) -> i32{ return coordInfo[0] + coordInfo[1] * index; } @@ -299,14 +299,14 @@ export class ArgMinMaxProgram implements WebGPUProgram { ${getGlobalIndexStringWgsl()} let coordInfo = getInputCoordInfo(globalId, index); - var bestIndex = 0u; + var bestIndex = 0; var bestValue = x.numbers[getInputIndex(coordInfo, bestIndex)]; let Length = ${indexInputShape('uniforms.axis')}; let WorkPerThread = DIV_CEIL(Length, WorkGroupSize); - for (var w = 0u; w < WorkPerThread; w = w + 1u) { - let i = globalId.x * WorkPerThread + w; + for (var w = 0; w < WorkPerThread; w = w + 1) { + let i = i32(globalId.x) * WorkPerThread + w; if (i < Length) { let candidate = x.numbers[getInputIndex(coordInfo, i)]; if (candidate ${ @@ -317,11 +317,11 @@ export class ArgMinMaxProgram implements WebGPUProgram { } } - let flatOutputIndex = globalId.y; + let flatOutputIndex = i32(globalId.y); ${ reduceInSharedMemory ? sharedMemoryReduceSnippet : - 'setOutputFlatI32(flatOutputIndex, i32(bestIndex));'} + 'setOutputFlatI32(flatOutputIndex, bestIndex);'} } `; return userCode; diff --git a/tfjs-backend-webgpu/src/kernels/binary_op_shared_webgpu.ts b/tfjs-backend-webgpu/src/kernels/binary_op_shared_webgpu.ts index 84e51d9757a..da2fd1a74b7 100644 --- a/tfjs-backend-webgpu/src/kernels/binary_op_shared_webgpu.ts +++ b/tfjs-backend-webgpu/src/kernels/binary_op_shared_webgpu.ts @@ -159,16 +159,16 @@ export class BinaryOpSharedProgram implements WebGPUProgram { // Fill in the shared memory buffer. Here we need a loop to make sure // that all data in A|B are uploaded when |sharedMemorySize| is larger // than work group size. - for(var localIndex = localId.x; localIndex < ${ - this.lastDimensionSize}u; localIndex = localIndex + ${ - this.workGroupSize[0]}u) { + for(var localIndex = i32(localId.x); localIndex < ${ + this.lastDimensionSize}; localIndex = localIndex + ${ + this.workGroupSize[0]}) { sharedBuf[localIndex] = f32(${ this.useSharedMemoryWithB ? 'B' : 'A'}.numbers[localIndex]); } workgroupBarrier(); - for(var i = 0u; i < ${this.workPerThread}u; i = i + 1u) { - let flatIndex = index * ${this.workPerThread}u + i; + for(var i = 0; i < ${this.workPerThread}; i = i + 1) { + let flatIndex = index * ${this.workPerThread} + i; ${writeDataSnippet} } diff --git a/tfjs-backend-webgpu/src/kernels/binary_op_webgpu.ts b/tfjs-backend-webgpu/src/kernels/binary_op_webgpu.ts index 3e62fb1faa3..8d7ac58b48a 100644 --- a/tfjs-backend-webgpu/src/kernels/binary_op_webgpu.ts +++ b/tfjs-backend-webgpu/src/kernels/binary_op_webgpu.ts @@ -152,8 +152,8 @@ export class BinaryOpProgram implements WebGPUProgram { ${miscStr} ${getMainHeaderStringWgsl()} { ${getGlobalIndexStringWgsl()} - for (var i = 0u; i < ${this.workPerThread}u; i = i + 1u ) { - let flatIndex = index * ${this.workPerThread}u + i; + for (var i = 0; i < ${this.workPerThread}; i = i + 1 ) { + let flatIndex = index * ${this.workPerThread} + i; if(flatIndex < uniforms.size) { let coords = getCoordsFromFlatIndex(flatIndex); diff --git a/tfjs-backend-webgpu/src/kernels/clip_vec4_webgpu.ts b/tfjs-backend-webgpu/src/kernels/clip_vec4_webgpu.ts index 1597da79948..9abcf2f6896 100644 --- a/tfjs-backend-webgpu/src/kernels/clip_vec4_webgpu.ts +++ b/tfjs-backend-webgpu/src/kernels/clip_vec4_webgpu.ts @@ -76,7 +76,7 @@ export class ClipVec4Program implements WebGPUProgram { if(index < uniforms.size) { let value = getAAtOutCoordsByGlobalId(globalId, index); var clampedValue : vec4; - for (var i = 0u; i < 4u; i = i + 1u) { + for (var i = 0; i < 4; i = i + 1) { if (isNanCustom(value[i])) { clampedValue[i] = value[i]; } else { diff --git a/tfjs-backend-webgpu/src/kernels/concat_webgpu.ts b/tfjs-backend-webgpu/src/kernels/concat_webgpu.ts index 14cdcb486be..c4dadcad128 100644 --- a/tfjs-backend-webgpu/src/kernels/concat_webgpu.ts +++ b/tfjs-backend-webgpu/src/kernels/concat_webgpu.ts @@ -104,17 +104,17 @@ export class ConcatProgram implements WebGPUProgram { } snippets.push(`if (yC < ${ - offsets[0]}u){ setOutput(coords.x, coords.y, getT0(yR, yC)); }`); + offsets[0]}){ setOutput(coords.x, coords.y, getT0(yR, yC)); }`); for (let i = 1; i < offsets.length; i++) { const shift = offsets[i - 1]; snippets.push( - `elseif (yC < ${offsets[i]}u){ ` + - `setOutput(coords.x, coords.y, getT${i}(yR, yC - ${shift}u)); }`); + `elseif (yC < ${offsets[i]}){ ` + + `setOutput(coords.x, coords.y, getT${i}(yR, yC - ${shift})); }`); } const lastIndex = offsets.length; const lastShift = offsets[offsets.length - 1]; snippets.push(`else { setOutput(coords.x, coords.y, getT${ - lastIndex}(yR, yC - ${lastShift}u)); }`); + lastIndex}(yR, yC - ${lastShift})); }`); } else { snippets.push(`setOutput(coords.x, coords.y, getT0(yR, yC));`); } @@ -122,8 +122,8 @@ export class ConcatProgram implements WebGPUProgram { const userCode = ` ${getMainHeaderStringWgsl()} { ${getGlobalIndexStringWgsl()} - for(var i = 0u; i < ${this.workPerThread}u; i = i + 1u) { - let flatIndex = index * ${this.workPerThread}u + i; + for(var i = 0; i < ${this.workPerThread}; i = i + 1) { + let flatIndex = index * ${this.workPerThread} + i; if(flatIndex < uniforms.size) { let coords = getCoordsFromFlatIndex(flatIndex); let yR = coords.x; diff --git a/tfjs-backend-webgpu/src/kernels/conv2d_mm_vec4_webgpu.ts b/tfjs-backend-webgpu/src/kernels/conv2d_mm_vec4_webgpu.ts index e129ca21859..180357af228 100644 --- a/tfjs-backend-webgpu/src/kernels/conv2d_mm_vec4_webgpu.ts +++ b/tfjs-backend-webgpu/src/kernels/conv2d_mm_vec4_webgpu.ts @@ -31,8 +31,8 @@ export class Conv2DMMVec4Program implements WebGPUProgram { variableNames = ['x', 'W']; uniforms = 'ivec2 filterDims, pad, stride, dilation;'; uniformsWgsl = - `filterDims : vec2; pad : vec2; stride : vec2; dilation : vec2; - dimAOuter : u32; dimBOuter : u32; dimInner : u32;`; + `filterDims : vec2; pad : vec2; stride : vec2; dilation : vec2; + dimAOuter : i32; dimBOuter : i32; dimInner : i32;`; workGroupSize: [number, number, number]; useWgsl: boolean; isVec4 = true; @@ -246,21 +246,21 @@ export class Conv2DMMVec4Program implements WebGPUProgram { // index is used to avoid repeated definition error. getSampleAWithRemainderWgsl(index: number): string { return `let flatIndex${index} = getFlatIndex4D(coord, uniforms.xShape); - let divBy4Remainder${index} = flatIndex${index} % 4u; - let divBy4Index${index} = flatIndex${index} / 4u; + let divBy4Remainder${index} = flatIndex${index} % 4; + let divBy4Index${index} = flatIndex${index} / 4; let curData${index} = x.numbers[divBy4Index${index}]; - if (divBy4Remainder${index} == 0u) { + if (divBy4Remainder${index} == 0) { temp = curData${index}; } else { // TODO: This could end up being a redundant load with another one in // the same shader invocation. Perhaps there's an opportunity for // optimization - let nextData${index} = x.numbers[divBy4Index${index} + 1u]; - if (divBy4Remainder${index} == 1u) { + let nextData${index} = x.numbers[divBy4Index${index} + 1]; + if (divBy4Remainder${index} == 1) { temp = vec4(curData${index}.yzw, nextData${index}.x); - } elseif (divBy4Remainder${index} == 2u) { + } elseif (divBy4Remainder${index} == 2) { temp = vec4(curData${index}.zw, nextData${index}.xy); - } elseif (divBy4Remainder${index} == 3u) { + } elseif (divBy4Remainder${index} == 3) { temp = vec4(curData${index}.w, nextData${index}.xyz); } } @@ -278,27 +278,22 @@ export class Conv2DMMVec4Program implements WebGPUProgram { `// The bounds checking is always needed since we use it to pad zero for // the 'same' padding type. if (coordsInBounds4D(coord, uniforms.xShape)) { - resData = x.numbers[getFlatIndex4D(coord, uniforms.xShape) / 4u]; + resData = x.numbers[getFlatIndex4D(coord, uniforms.xShape) / 4]; } else { resData = vec4(0.0); }` : `var temp = vec4(0.0); ${this.getSampleAWithRemainderWgsl(1)} resData = temp; - if (WCol == (uniforms.filterDims[1] - 1u)) { - let coordZ = i32(coord.z + 1u - uniforms.filterDims[1]); - if (coordZ < 0) { - resData = vec4(0.0); + if (WCol == (uniforms.filterDims[1] - 1)) { + coord = vec4( + coord.x, coord.y + 1, coord.z + 1 - uniforms.filterDims[1], 0); + ${this.getSampleAWithRemainderWgsl(2)} + if (inChCoord == 0) { + resData = vec4(resData.xyz, temp.x); + } elseif (inChCoord == 1) { + resData = vec4(resData.xy, temp.xy); } else { - coord = vec4( - coord.x, coord.y + 1u, u32(coordZ), 0u); - ${this.getSampleAWithRemainderWgsl(2)} - if (inChCoord == 0u) { - resData = vec4(resData.xyz, temp.x); - } elseif (inChCoord == 1u) { - resData = vec4(resData.xy, temp.xy); - } else { - resData = vec4(resData.x, temp.xyz); - } + resData = vec4(resData.x, temp.xyz); } } `; @@ -306,20 +301,12 @@ export class Conv2DMMVec4Program implements WebGPUProgram { const readASnippet = `let outRow = r / uniforms.outShape[2]; let outCol = r % uniforms.outShape[2]; let WRow = c / (uniforms.filterDims[1] * uniforms.xShape[3]); - let WCol = (c / uniforms.xShape[3]) % uniforms.filterDims[1]; + let WCol = c / uniforms.xShape[3] % uniforms.filterDims[1]; let inChCoord = c % uniforms.xShape[3]; - let coordRow = i32(outRow * uniforms.stride[0] + uniforms.dilation[0] * WRow - uniforms.pad[0]); - if (coordRow < 0) { - return vec4(0.0); - } - let coordCol = i32(outCol * uniforms.stride[1] + uniforms.dilation[1] * WCol - uniforms.pad[1]); - if (coordCol < 0) { - return vec4(0.0); - } - var coord = vec4( + var coord = vec4( batch, - u32(coordRow), - u32(coordCol), + outRow * uniforms.stride[0] + uniforms.dilation[0] * WRow - uniforms.pad[0], + outCol * uniforms.stride[1] + uniforms.dilation[1] * WCol - uniforms.pad[1], inChCoord); var resData = vec4(0.0); ${remainderSnippet} @@ -334,9 +321,9 @@ export class Conv2DMMVec4Program implements WebGPUProgram { `; const sampleB = this.fitB ? - `return W.numbers[row * uniforms.dimBOuter / 4u + col];` : - `if(coordsInBounds2D(vec2(row, col * 4u), vec2(uniforms.dimInner, uniforms.dimBOuter))) { - return W.numbers[row * uniforms.dimBOuter / 4u + col]; + `return W.numbers[row * uniforms.dimBOuter / 4 + col];` : + `if(coordsInBounds2D(vec2(row, col * 4), vec2(uniforms.dimInner, uniforms.dimBOuter))) { + return W.numbers[row * uniforms.dimBOuter / 4 + col]; } return vec4(0.0); `; @@ -346,7 +333,7 @@ export class Conv2DMMVec4Program implements WebGPUProgram { this.activation, this.isVec4, this.useWgsl); if (this.hasPreluActivationWeights) { activationSnippet = - `fn activation(a : vec4, outCoord : vec4) -> vec4 { + `fn activation(a : vec4, outCoord : vec4) -> vec4 { let b = getPreluActivationWeightsAtOutCoordsByCoords(outCoord); ${activationOp} }`; @@ -358,7 +345,7 @@ export class Conv2DMMVec4Program implements WebGPUProgram { throw new Error('Leakyrelu is not supported.'); } else { activationSnippet = ` - fn activation(a : vec4, outCoord : vec4) -> vec4 { + fn activation(a : vec4, outCoord : vec4) -> vec4 { ${activationOp} }`; } @@ -372,27 +359,27 @@ export class Conv2DMMVec4Program implements WebGPUProgram { const userCode = ` ${activationSnippet} - fn mm_readA(row : u32, col : u32, globalId : vec3) -> vec4 { + fn mm_readA(row : i32, col : i32, globalId : vec3) -> vec4 { let r = row; - let c = col * 4u; - var batch = globalId.z; + let c = col * 4; + var batch = i32(globalId.z); ${sampleA} } - fn mm_readB(row : u32, col : u32, globalId : vec3) -> vec4 { + fn mm_readB(row : i32, col : i32, globalId : vec3) -> vec4 { ${sampleB} } - fn mm_write(row : u32, col : u32, valueInput : vec4, globalId : vec3) { - var batch = globalId.z; + fn mm_write(row : i32, col : i32, valueInput : vec4, globalId : vec3) { + var batch = i32(globalId.z); var value = valueInput; - if (row < uniforms.dimAOuter && col * 4u < uniforms.dimBOuter) + if (row < uniforms.dimAOuter && col * 4 < uniforms.dimBOuter) { - let outCoord = vec4( + let outCoord = vec4( batch, row / uniforms.outShape[2], row % uniforms.outShape[2], - col * 4u); + col * 4); ${addBiasSnippet} ${applyActivationSnippet} setOutput(outCoord[0], outCoord[1], outCoord[2], outCoord[3], diff --git a/tfjs-backend-webgpu/src/kernels/conv2d_mm_webgpu.ts b/tfjs-backend-webgpu/src/kernels/conv2d_mm_webgpu.ts index 9303e6f90f5..eaa59b8766f 100644 --- a/tfjs-backend-webgpu/src/kernels/conv2d_mm_webgpu.ts +++ b/tfjs-backend-webgpu/src/kernels/conv2d_mm_webgpu.ts @@ -31,7 +31,7 @@ export class Conv2DMMProgram implements WebGPUProgram { variableNames = ['x', 'W']; uniforms = 'ivec2 filterDims, pad, stride, dilation;'; uniformsWgsl = - `filterDims : vec2; pad : vec2; stride : vec2; dilation : vec2; dimAOuter : u32; dimBOuter : u32; dimInner : u32;`; + `filterDims : vec2; pad : vec2; stride : vec2; dilation : vec2; dimAOuter : i32; dimBOuter : i32; dimInner : i32;`; workGroupSize: [number, number, number]; elementsPerThread: [number, number, number]; convInfo: backend_util.Conv2DInfo; @@ -200,19 +200,11 @@ export class Conv2DMMProgram implements WebGPUProgram { let outCol = row % uniforms.outShape[2]; let WRow = col / (uniforms.filterDims[1] * uniforms.xShape[3]); - let WCol = (col / uniforms.xShape[3]) % uniforms.filterDims[1]; - let coordRow = i32(outRow * uniforms.stride[0] + uniforms.dilation[0] * WRow - uniforms.pad[0]); - if (coordRow < 0) { - return 0.0; - } - let coordCol = i32(outCol * uniforms.stride[1] + uniforms.dilation[1] * WCol - uniforms.pad[1]); - if (coordCol < 0) { - return 0.0; - } - let coord = vec4( + let WCol = col / uniforms.xShape[3] % uniforms.filterDims[1]; + let coord = vec4( batch, - u32(coordRow), - u32(coordCol), + outRow * uniforms.stride[0] + uniforms.dilation[0] * WRow - uniforms.pad[0], + outCol * uniforms.stride[1] + uniforms.dilation[1] * WCol - uniforms.pad[1], col % uniforms.xShape[3]); // The bounds checking is always needed since we use it to pad zero for the // 'same' padding type. @@ -231,7 +223,7 @@ export class Conv2DMMProgram implements WebGPUProgram { const sampleB = this.fitB ? `return W.numbers[row * uniforms.dimBOuter + col];` : - `if(coordsInBounds2D(vec2(row, col), vec2(uniforms.dimInner, uniforms.dimBOuter))) { + `if(coordsInBounds2D(vec2(row, col), vec2(uniforms.dimInner, uniforms.dimBOuter))) { return W.numbers[row * uniforms.dimBOuter + col]; } return 0.0; @@ -243,13 +235,13 @@ export class Conv2DMMProgram implements WebGPUProgram { mapActivationToShaderProgram(this.activation, false, this.useWgsl); if (this.hasPreluActivationWeights) { activationSnippet = - `fn activation(a: f32, outCoord : vec4) -> f32 { + `fn activation(a: f32, outCoord : vec4) -> f32 { let b = getPreluActivationWeightsAtOutCoordsByCoords(outCoord); ${activationOp} }`; } else { activationSnippet = ` - fn activation(a : f32, outCoord : vec4) -> f32 { + fn activation(a : f32, outCoord : vec4) -> f32 { ${activationOp} } `; @@ -264,19 +256,19 @@ export class Conv2DMMProgram implements WebGPUProgram { const userCode = ` ${activationSnippet} - fn mm_readA(row : u32, col : u32, globalId : vec3) -> f32 { - var batch = globalId.z; + fn mm_readA(row : i32, col : i32, globalId : vec3) -> f32 { + var batch = i32(globalId.z); ${sampleA} } - fn mm_readB(row : u32, col : u32, globalId : vec3) -> f32 { + fn mm_readB(row : i32, col : i32, globalId : vec3) -> f32 { ${sampleB} } - fn mm_write(row : u32, col : u32, valueInput : f32, globalId : vec3) { - var batch = globalId.z; + fn mm_write(row : i32, col : i32, valueInput : f32, globalId : vec3) { + var batch = i32(globalId.z); var value = valueInput; - let outCoord = vec4( + let outCoord = vec4( batch, row / uniforms.outShape[2], row % uniforms.outShape[2], diff --git a/tfjs-backend-webgpu/src/kernels/conv2d_naive_webgpu.ts b/tfjs-backend-webgpu/src/kernels/conv2d_naive_webgpu.ts index 78308b93c70..ce1394873c3 100644 --- a/tfjs-backend-webgpu/src/kernels/conv2d_naive_webgpu.ts +++ b/tfjs-backend-webgpu/src/kernels/conv2d_naive_webgpu.ts @@ -31,7 +31,7 @@ export class Conv2DNaiveProgram implements WebGPUProgram { variableNames = ['x', 'W']; uniforms = 'ivec2 filterDims, pad, stride, dilation;'; uniformsWgsl = - `filterDims : vec2; pad : vec2; stride : vec2; dilation : vec2;`; + `filterDims : vec2; pad : vec2; stride : vec2; dilation : vec2;`; workGroupSize: [number, number, number] = [128, 1, 1]; convInfo: backend_util.Conv2DInfo; addBias: boolean; @@ -145,13 +145,13 @@ export class Conv2DNaiveProgram implements WebGPUProgram { const activationOp = mapActivationToShaderProgram(this.activation); if (this.hasPreluActivationWeights) { activationSnippet = - `fn activation(a : f32, outCoord : vec4) -> f32{ + `fn activation(a : f32, outCoord : vec4) -> f32{ let b = getPreluActivationWeightsAtOutCoordsByCoords(outCoord); ${activationOp} }`; } else { activationSnippet = ` - fn activation(a : f32, outCoord : vec4) -> f32{ + fn activation(a : f32, outCoord : vec4) -> f32{ ${activationOp} } `; @@ -166,24 +166,24 @@ export class Conv2DNaiveProgram implements WebGPUProgram { const userCode = ` ${activationSnippet} - fn readInp(batch : u32, row : u32, col : u32, chan : u32) -> f32 { - let coord = vec4(batch, row, col, chan); + fn readInp(batch : i32, row : i32, col : i32, chan : i32) -> f32 { + let coord = vec4(batch, row, col, chan); if(coordsInBounds4D(coord, uniforms.xShape)) { return getX(batch, row, col, chan); } return 0.0; } - fn readFilt(row : u32, col : u32, xChannel : u32, outChannel : u32) -> f32{ - let coord = vec4(row, col, xChannel, outChannel); + fn readFilt(row : i32, col : i32, xChannel : i32, outChannel : i32) -> f32{ + let coord = vec4(row, col, xChannel, outChannel); if(coordsInBounds4D(coord, uniforms.wShape)) { return getW(row, col, xChannel, outChannel); } return 0.0; } - fn writeResult(batch : u32, row : u32, col : u32, chan : u32, value : f32) { - let coord = vec4(batch, row, col, chan); + fn writeResult(batch : i32, row : i32, col : i32, chan : i32, value : f32) { + let coord = vec4(batch, row, col, chan); if (coordsInBounds4D(coord, uniforms.outShape)) { ${addBiasSnippet} ${applyActivationSnippet} @@ -199,18 +199,12 @@ export class Conv2DNaiveProgram implements WebGPUProgram { var acc = 0.0; - for (var row = 0u; row < uniforms.filterDims[0]; row = row + 1u) { - for (var col = 0u; col < uniforms.filterDims[1]; col = col + 1u) { - for (var xChannel = 0u; xChannel < uniforms.xShape[3]; xChannel = xChannel + 1u) { - let coordRow = i32(coords[1] * uniforms.stride[0] + uniforms.dilation[0] * row - uniforms.pad[0]); - if (coordRow < 0) { - continue; - } - let coordCol = i32(coords[2] * uniforms.stride[1] + uniforms.dilation[1] * col - uniforms.pad[1]); - if (coordCol < 0) { - continue; - } - let v = readInp(batch, u32(coordRow), u32(coordCol), xChannel); + for (var row = 0; row < uniforms.filterDims[0]; row = row + 1) { + for (var col = 0; col < uniforms.filterDims[1]; col = col + 1) { + for (var xChannel = 0; xChannel < uniforms.xShape[3]; xChannel = xChannel + 1) { + let coordRow = coords[1] * uniforms.stride[0] + uniforms.dilation[0] * row - uniforms.pad[0]; + let coordCol = coords[2] * uniforms.stride[1] + uniforms.dilation[1] * col - uniforms.pad[1]; + let v = readInp(batch, coordRow, coordCol, xChannel); let f = readFilt(row, col, xChannel, outChannel); acc = acc + v * f; } diff --git a/tfjs-backend-webgpu/src/kernels/conv_backprop_mm_webgpu.ts b/tfjs-backend-webgpu/src/kernels/conv_backprop_mm_webgpu.ts index 3f234db5ca5..79266730751 100644 --- a/tfjs-backend-webgpu/src/kernels/conv_backprop_mm_webgpu.ts +++ b/tfjs-backend-webgpu/src/kernels/conv_backprop_mm_webgpu.ts @@ -30,7 +30,7 @@ export class Conv2DDerInputMMProgram implements WebGPUProgram { variableNames = ['x', 'W']; uniforms = 'ivec2 filterDims, pads, stride; ivec4 outBackprop;'; uniformsWgsl = - 'filterDims : vec2; pads : vec2; stride : vec2; outBackprop : vec4; dimAOuter : u32; dimBOuter : u32; dimInner : u32;'; + 'filterDims : vec2; pads : vec2; stride : vec2; outBackprop : vec4; dimAOuter : i32; dimBOuter : i32; dimInner : i32;'; workGroupSize: [number, number, number]; elementsPerThread: [number, number, number]; useWgsl: boolean; @@ -140,21 +140,21 @@ export class Conv2DDerInputMMProgram implements WebGPUProgram { let outRow = row / uniforms.outShape[2]; let outCol = row % uniforms.outShape[2]; - let WRow = i32(col) / (uniforms.filterDims[1] * uniforms.outBackprop[3]); - let WCol = i32(col) / uniforms.outBackprop[3] % uniforms.filterDims[1]; - let xR = (f32(outRow) - f32(uniforms.pads[0]) + f32(WRow)) / f32(uniforms.stride[0]); - let xC = (f32(outCol) - f32(uniforms.pads[1]) + f32(WCol)) / f32(uniforms.stride[1]); + let WRow = col / (uniforms.filterDims[1] * uniforms.outBackprop[3]); + let WCol = col / uniforms.outBackprop[3] % uniforms.filterDims[1]; + let xR = f32(outRow - uniforms.pads[0] + WRow) / f32(uniforms.stride[0]); + let xC = f32(outCol - uniforms.pads[1] + WCol) / f32(uniforms.stride[1]); if (xR < 0.0 || xR >= f32(uniforms.outBackprop[1]) || fract(xR) > 0.0) { return 0.0; } if (xC < 0.0 || xC >= f32(uniforms.outBackprop[2]) || fract(xC) > 0.0) { return 0.0; } - let coord = vec4( + let coord = vec4( batch, - u32(xR), - u32(xC), - col % u32(uniforms.outBackprop[3])); + i32(xR), + i32(xC), + col % uniforms.outBackprop[3]); return x.numbers[getFlatIndex4D(coord, uniforms.xShape)];`; const sampleA = `if (row < uniforms.dimAOuter && col < uniforms.dimInner) { @@ -163,29 +163,29 @@ export class Conv2DDerInputMMProgram implements WebGPUProgram { return 0.0;`; const userCode = ` - fn mm_readA(row : u32, col : u32, globalId : vec3) -> f32 { - var batch = globalId.z; + fn mm_readA(row : i32, col : i32, globalId : vec3) -> f32 { + var batch = i32(globalId.z); ${sampleA} } - fn mm_readB(row : u32, col : u32, globalId : vec3) -> f32 { + fn mm_readB(row : i32, col : i32, globalId : vec3) -> f32 { let coordX = uniforms.filterDims.x - 1 - - i32(row) / (uniforms.filterDims[1] * uniforms.outBackprop[3]); + row / (uniforms.filterDims[1] * uniforms.outBackprop[3]); let coordY = uniforms.filterDims.y - 1 - - (i32(row) / uniforms.outBackprop[3]) % uniforms.filterDims[1]; + (row / uniforms.outBackprop[3]) % uniforms.filterDims[1]; if (row < uniforms.dimInner && col < uniforms.dimBOuter && coordX >= 0 && coordY >= 0) { - let coord = vec4(u32(coordX), u32(coordY), col, - row % u32(uniforms.outBackprop[3])); + let coord = vec4(coordX, coordY, col, + row % uniforms.outBackprop[3]); return W.numbers[getFlatIndex4D(coord, uniforms.wShape)]; } return 0.0; } - fn mm_write(row : u32, col : u32, valueInput : f32, globalId : vec3) { - var batch = globalId.z; + fn mm_write(row : i32, col : i32, valueInput : f32, globalId : vec3) { + var batch = i32(globalId.z); var value = valueInput; - let outCoord = vec4( + let outCoord = vec4( batch, row / uniforms.outShape[2], row % uniforms.outShape[2], diff --git a/tfjs-backend-webgpu/src/kernels/conv_backprop_webgpu.ts b/tfjs-backend-webgpu/src/kernels/conv_backprop_webgpu.ts index 84638a6a574..99e85872013 100644 --- a/tfjs-backend-webgpu/src/kernels/conv_backprop_webgpu.ts +++ b/tfjs-backend-webgpu/src/kernels/conv_backprop_webgpu.ts @@ -117,22 +117,22 @@ export class Conv2DDerInputProgram implements WebGPUProgram { let batch = coords[0]; let d1 = coords[${channelDim}]; - let dyCorner = vec2(i32(coords[${rowDim}]), i32(coords[${ - colDim}])) - uniforms.pads; + let dyCorner = vec2(coords[${rowDim}]), coords[${ + colDim}]) - uniforms.pads; let dyRCorner = dyCorner.x; let dyCCorner = dyCorner.y; // Convolve dy(?, ?, d2) with w(:, :, d1, d2) to compute dx(xR, xC, d1). // ? = to be determined. : = across all values in that axis. var dotProd = 0.0; - for (var wR = 0u; wR < uniforms.filterDims.x; wR = wR + 1u) { + for (var wR = 0; wR < uniforms.filterDims.x; wR = wR + 1) { let dyR = (f32(dyRCorner) + f32(wR)) / f32(uniforms.stride.x); - let wRPerm = uniforms.filterDims.x - 1 - i32(wR); + let wRPerm = uniforms.filterDims.x - 1 - wR; if (dyR < 0.0 || dyR >= f32(uniforms.outBackprop[1]) || fract(dyR) > 0.0 || wRPerm < 0) { continue; } - let idyR = u32(dyR); + let idyR = dyR; for (var wC = 0; wC < uniforms.filterDims.y; wC = wC + 1) { let dyC = (f32(dyCCorner) + f32(wC)) / f32(uniforms.stride.y); @@ -141,16 +141,16 @@ export class Conv2DDerInputProgram implements WebGPUProgram { fract(dyC) > 0.0 || wCPerm < 0) { continue; } - let idyC = u32(dyC); + let idyC = dyC; - for (var d2 = 0u; d2 < u32(uniforms.outBackprop[3]); d2 = d2 + 1u) { + for (var d2 = 0; d2 < uniforms.outBackprop[3]; d2 = d2 + 1) { if (${this.isChannelsLast}) { let xValue = getDy(batch, idyR, idyC, d2); - let wValue = getW(u32(wRPerm), u32(wCPerm), d1, d2); + let wValue = getW(wRPerm, wCPerm, d1, d2); dotProd = dotProd + xValue * wValue; } else { let xValue = getDy(batch, d2, idyR, idyC); - let wValue = getW(u32(wRPerm), u32(wCPerm), d1, d2); + let wValue = getW(wRPerm, wCPerm, d1, d2); dotProd = dotProd + xValue * wValue; } diff --git a/tfjs-backend-webgpu/src/kernels/crop_and_resize_webgpu.ts b/tfjs-backend-webgpu/src/kernels/crop_and_resize_webgpu.ts index a757a9ac280..32138e5b064 100644 --- a/tfjs-backend-webgpu/src/kernels/crop_and_resize_webgpu.ts +++ b/tfjs-backend-webgpu/src/kernels/crop_and_resize_webgpu.ts @@ -145,13 +145,12 @@ export class CropAndResizeProgram implements WebGPUProgram { } getUserCodeWgsl(): string { - const [inputHeightFloat, inputWidthFloat] = [ - `f32(uniforms.imageShape[1] - 1u)`, `f32(uniforms.imageShape[2] - 1u)` - ]; + const [inputHeightFloat, inputWidthFloat] = + [`f32(uniforms.imageShape[1] - 1)`, `f32(uniforms.imageShape[2] - 1)`]; const [heightRatio, heightScale, inY] = this.cropHeightBiggerThan1 ? [ - `(${inputHeightFloat} / f32(uniforms.outShape[1] - 1u))`, + `(${inputHeightFloat} / f32(uniforms.outShape[1] - 1))`, '(y2-y1) * height_ratio', `y1*${inputHeightFloat} + f32(y)*(height_scale)`, ] : @@ -162,7 +161,7 @@ export class CropAndResizeProgram implements WebGPUProgram { ]; const [widthRatio, widthScale, inX] = this.cropWidthBiggerThan1 ? [ - `(${inputWidthFloat} / f32(uniforms.outShape[2] - 1u))`, + `(${inputWidthFloat} / f32(uniforms.outShape[2] - 1))`, '(x2-x1) * width_ratio', `x1*${inputWidthFloat} + f32(x)*(width_scale)`, ] : @@ -176,7 +175,7 @@ export class CropAndResizeProgram implements WebGPUProgram { // tslint:disable-next-line:max-line-length // https://github.com/tensorflow/tensorflow/blob/master/tensorflow/core/kernels/crop_and_resize_op_gpu.cu.cc const userCode = ` - fn writeResult(coords : vec4, value : f32) { + fn writeResult(coords : vec4, value : f32) { if (coordsInBounds4D(coords, uniforms.outShape)) { setOutput(coords[0], coords[1], coords[2], coords[3], value); } @@ -191,13 +190,13 @@ export class CropAndResizeProgram implements WebGPUProgram { let x = coords[2]; let d = coords[3]; // get box vals - let y1 = getBoxes(b, 0u); - let x1 = getBoxes(b, 1u); - let y2 = getBoxes(b, 2u); - let x2 = getBoxes(b, 3u); + let y1 = getBoxes(b, 0); + let x1 = getBoxes(b, 1); + let y2 = getBoxes(b, 2); + let x2 = getBoxes(b, 3); // get image in batch index let bInd = i32(round(getBoxInd(b))); - if(bInd < 0 || bInd >= i32(uniforms.outShape[0])) { + if(bInd < 0 || bInd >= uniforms.outShape[0]) { return; } let height_scale = ${heightScale}; @@ -217,10 +216,10 @@ export class CropAndResizeProgram implements WebGPUProgram { // Compute the four integer indices. let sourceFloorCR = vec2(sourceFracIndexCR); let sourceCeilCR = vec2(ceil(sourceFracIndexCR)); - let topLeft = getImage(u32(bInd), u32(sourceFloorCR.y), u32(sourceFloorCR.x), d); - let bottomLeft = getImage(u32(bInd), u32(sourceCeilCR.y), u32(sourceFloorCR.x), d); - let topRight = getImage(u32(bInd), u32(sourceFloorCR.y), u32(sourceCeilCR.x), d); - let bottomRight = getImage(u32(bInd), u32(sourceCeilCR.y), u32(sourceCeilCR.x), d); + let topLeft = getImage(bInd, sourceFloorCR.y, sourceFloorCR.x, d); + let bottomLeft = getImage(bInd, sourceCeilCR.y, sourceFloorCR.x, d); + let topRight = getImage(bInd, sourceFloorCR.y, sourceCeilCR.x, d); + let bottomRight = getImage(bInd, sourceCeilCR.y, sourceCeilCR.x, d); let fracCR = sourceFracIndexCR - vec2(sourceFloorCR); let top = topLeft + (topRight - topLeft) * fracCR.x; let bottom = bottomLeft + (bottomRight - bottomLeft) * fracCR.x; @@ -231,7 +230,7 @@ export class CropAndResizeProgram implements WebGPUProgram { let sourceNearestCR = vec2(floor( sourceFracIndexCR + vec2(0.5,0.5))); let newValue = getImage( - u32(bInd), u32(sourceNearestCR.y), u32(sourceNearestCR.x), d); + bInd, sourceNearestCR.y, sourceNearestCR.x, d); writeResult(coords,newValue); } } diff --git a/tfjs-backend-webgpu/src/kernels/depthwise_conv2d_3x3_webgpu.ts b/tfjs-backend-webgpu/src/kernels/depthwise_conv2d_3x3_webgpu.ts index 8952948ffcd..0cc54928830 100644 --- a/tfjs-backend-webgpu/src/kernels/depthwise_conv2d_3x3_webgpu.ts +++ b/tfjs-backend-webgpu/src/kernels/depthwise_conv2d_3x3_webgpu.ts @@ -31,7 +31,7 @@ export class DepthwiseConv2D3x3Program implements WebGPUProgram { variableNames = ['x', 'W']; uniforms = 'ivec2 pad, stride, dilation, inDims;'; uniformsWgsl = - 'pad : vec2; stride : vec2; dilation : vec2; inDims : vec2;'; + 'pad : vec2; stride : vec2; dilation : vec2; inDims : vec2;'; workGroupSize: [number, number, number] = [4, 4, 4]; convInfo: backend_util.Conv2DInfo; addBias: boolean; @@ -168,13 +168,13 @@ export class DepthwiseConv2D3x3Program implements WebGPUProgram { this.activation, this.isVec4, this.useWgsl); if (this.hasPreluActivation) { activationSnippet = - `fn activation(a : vec4, globalId : vec3, globalIndex : u32) -> vec4 { + `fn activation(a : vec4, globalId : vec3, globalIndex : i32) -> vec4 { let b = getPreluActivationWeightsAtOutCoordsByGlobalId(globalId, globalIndex); ${activationOp} }`; } else { activationSnippet = ` - fn activation(a : vec4, globalId : vec3, globalIndex : u32) -> vec4 { + fn activation(a : vec4, globalId : vec3, globalIndex : i32) -> vec4 { ${activationOp} } `; @@ -193,37 +193,37 @@ export class DepthwiseConv2D3x3Program implements WebGPUProgram { ${getMainHeaderStringWgsl()} { ${getGlobalIndexStringWgsl()} - let batch = 0u; - let r = globalId.x; - let c = globalId.y * 4u; - let d2 = globalId.z * 4u; - let xRCCorner = vec2(vec2(r, c) * uniforms.stride - uniforms.pad); + let batch = 0; + let r = i32(globalId.x); + let c = i32(globalId.y) * 4; + let d2 = i32(globalId.z) * 4; + let xRCCorner = vec2(r, c) * uniforms.stride - uniforms.pad; let d1 = d2; - let q = 0u; + let q = 0; let xRCorner = xRCCorner.x; let xCCorner = xRCCorner.y; var wVals : array, 9>; - wVals[0] = getW(0u, 0u, d1, q); - wVals[1] = getW(0u, 1u, d1, q); - wVals[2] = getW(0u, 2u, d1, q); - wVals[3] = getW(1u, 0u, d1, q); - wVals[4] = getW(1u, 1u, d1, q); - wVals[5] = getW(1u, 2u, d1, q); - wVals[6] = getW(2u, 0u, d1, q); - wVals[7] = getW(2u, 1u, d1, q); - wVals[8] = getW(2u, 2u, d1, q); + wVals[0] = getW(0, 0, d1, q); + wVals[1] = getW(0, 1, d1, q); + wVals[2] = getW(0, 2, d1, q); + wVals[3] = getW(1, 0, d1, q); + wVals[4] = getW(1, 1, d1, q); + wVals[5] = getW(1, 2, d1, q); + wVals[6] = getW(2, 0, d1, q); + wVals[7] = getW(2, 1, d1, q); + wVals[8] = getW(2, 2, d1, q); var xVals : array, 6>, 3>; - for (var wR = 0u; wR < 3u; wR = wR + 1u) { - let xR = xRCorner + i32(wR * uniforms.dilation[0]); - for (var wC = 0u; wC < 6u; wC = wC + 1u) { - let xC = xCCorner + i32(wC * uniforms.dilation[1]); - if (xR < 0 || xR >= i32(uniforms.inDims[0]) || xC < 0 || xC >= i32(uniforms.inDims[1])) { + for (var wR = 0; wR < 3; wR = wR + 1) { + let xR = xRCorner + wR * uniforms.dilation[0]; + for (var wC = 0; wC < 6; wC = wC + 1) { + let xC = xCCorner + wC * uniforms.dilation[1]; + if (xR < 0 || xR >= uniforms.inDims[0] || xC < 0 || xC >= uniforms.inDims[1]) { xVals[wR][wC] = vec4(0.0); } else { - xVals[wR][wC] = getX(batch, u32(xR), u32(xC), d1); + xVals[wR][wC] = getX(batch, xR, xC, d1); } } } @@ -234,18 +234,18 @@ export class DepthwiseConv2D3x3Program implements WebGPUProgram { dotProd[2] = vec4(0.0); dotProd[3] = vec4(0.0); - for (var wR = 0u; wR < 3u; wR = wR + 1u) { - for (var wC = 0u; wC < 3u; wC = wC + 1u) { - let indexW = wR * 3u + wC; - dotProd[0] = dotProd[0] + xVals[wR][0u + wC] * wVals[indexW]; - dotProd[1] = dotProd[1] + xVals[wR][1u + wC] * wVals[indexW]; - dotProd[2] = dotProd[2] + xVals[wR][2u + wC] * wVals[indexW]; - dotProd[3] = dotProd[3] + xVals[wR][3u + wC] * wVals[indexW]; + for (var wR = 0; wR < 3; wR = wR + 1) { + for (var wC = 0; wC < 3; wC = wC + 1) { + let indexW = wR * 3 + wC; + dotProd[0] = dotProd[0] + xVals[wR][0 + wC] * wVals[indexW]; + dotProd[1] = dotProd[1] + xVals[wR][1 + wC] * wVals[indexW]; + dotProd[2] = dotProd[2] + xVals[wR][2 + wC] * wVals[indexW]; + dotProd[3] = dotProd[3] + xVals[wR][3 + wC] * wVals[indexW]; } } - for (var i = 0u; i < 4u; i = i + 1u) { - let coords = vec4(batch, r, c + i, d2); + for (var i = 0; i < 4; i = i + 1) { + let coords = vec4(batch, r, c + i, d2); if (coordsInBounds4D(coords, uniforms.outShape)) { ${addBiasSnippet} ${applyActivationSnippet} diff --git a/tfjs-backend-webgpu/src/kernels/depthwise_conv2d_webgpu.ts b/tfjs-backend-webgpu/src/kernels/depthwise_conv2d_webgpu.ts index ea2d0284292..3164eeaa935 100755 --- a/tfjs-backend-webgpu/src/kernels/depthwise_conv2d_webgpu.ts +++ b/tfjs-backend-webgpu/src/kernels/depthwise_conv2d_webgpu.ts @@ -31,7 +31,7 @@ export class DepthwiseConv2DProgram implements WebGPUProgram { variableNames = ['x', 'W']; uniforms = 'ivec2 pad, stride, dilation, inDims;'; uniformsWgsl = - `pad : vec2; stride : vec2; dilation : vec2; inDims : vec2;`; + `pad : vec2; stride : vec2; dilation : vec2; inDims : vec2;`; // This is an experimental value. workGroupSize: [number, number, number] = [256, 1, 1]; convInfo: backend_util.Conv2DInfo; @@ -178,13 +178,13 @@ export class DepthwiseConv2DProgram implements WebGPUProgram { mapActivationToShaderProgram(this.activation, false, this.useWgsl); if (this.hasPreluActivation) { activationSnippet = - `fn activation(a : f32, globalId : vec3, index : u32) -> f32 { + `fn activation(a : f32, globalId : vec3, index : i32) -> f32 { let b = getPreluActivationWeightsAtOutCoordsByGlobalId(globalId, index); ${activationOp} }`; } else { activationSnippet = ` - fn activation(a : f32, globalId : vec3, index : u32) -> f32 { + fn activation(a : f32, globalId : vec3, index : i32) -> f32 { ${activationOp} } `; @@ -201,8 +201,8 @@ export class DepthwiseConv2DProgram implements WebGPUProgram { const userCode = ` ${activationSnippet} - fn writeResult(batch : u32, row : u32, col : u32, chan : u32, value : f32) { - let coord = vec4(batch, row, col, chan); + fn writeResult(batch : i32, row : i32, col : i32, chan : i32, value : f32) { + let coord = vec4(batch, row, col, chan); if (coordsInBounds4D(coord, uniforms.outShape)) { setOutput(batch, row, col, chan, value); } @@ -212,17 +212,17 @@ export class DepthwiseConv2DProgram implements WebGPUProgram { ${getGlobalIndexStringWgsl()} let coords = getOutputCoords(globalId, index); let batch = coords[0]; - let xRCCorner = vec2(coords.yz * uniforms.stride - uniforms.pad); + let xRCCorner = vec2(coords.yz) * uniforms.stride - uniforms.pad; let d2 = coords[3]; - let d1 = d2 / ${channelMul}u; - let q = d2 - d1 * ${channelMul}u; + let d1 = d2 / ${channelMul}; + let q = d2 - d1 * ${channelMul}; let inputRowStart = xRCCorner.x; let inputColStart = xRCCorner.y; - let inputRowEnd = inputRowStart + i32(${ - this.convInfo.filterHeight}u * uniforms.dilation[0]); - let inputColEnd = inputColStart + i32(${ - this.convInfo.filterWidth}u * uniforms.dilation[1]); + let inputRowEnd = inputRowStart + ${ + this.convInfo.filterHeight} * uniforms.dilation[0]; + let inputColEnd = inputColStart + ${ + this.convInfo.filterWidth} * uniforms.dilation[1]; // Convolve x(?, ?, d1) with w(:, :, d1, q) to get y(yR, yC, d2). // ? = to be determined. : = across all values in that axis. @@ -230,40 +230,36 @@ export class DepthwiseConv2DProgram implements WebGPUProgram { // Extract if checking out of for loop for performance. if (inputRowStart >= 0 && inputColStart >= 0 && - inputRowEnd < i32(uniforms.inDims[0]) && inputColEnd < i32(uniforms.inDims[1])) { + inputRowEnd < uniforms.inDims[0] && inputColEnd < uniforms.inDims[1]) { // Here using a constant value |this.convInfo.filterHeight| instead // of uniform value is in order to loop unrolling. - for (var wR = 0u; wR < ${ - this.convInfo.filterHeight}u; wR = wR + 1u) { - let xR = inputRowStart + i32(wR * uniforms.dilation[0]); + for (var wR = 0; wR < ${this.convInfo.filterHeight}; wR = wR + 1) { + let xR = inputRowStart + wR * uniforms.dilation[0]; - for (var wC = 0u; wC < ${ - this.convInfo.filterWidth}u; wC = wC + 1u) { - let xC = inputColStart + i32(wC * uniforms.dilation[1]); + for (var wC = 0; wC < ${this.convInfo.filterWidth}; wC = wC + 1) { + let xC = inputColStart + wC * uniforms.dilation[1]; - let xVal = getX(batch, u32(xR), u32(xC), d1); - let wVal = getW(wR, u32(wC), d1, q); + let xVal = getX(batch, xR, xC, d1); + let wVal = getW(wR, wC, d1, q); dotProd = dotProd + xVal * wVal; } } } else { - for (var wR = 0u; wR < ${ - this.convInfo.filterHeight}u; wR = wR + 1u) { - let xR = inputRowStart + i32(wR * uniforms.dilation[0]); + for (var wR = 0; wR < ${this.convInfo.filterHeight}; wR = wR + 1) { + let xR = inputRowStart + wR * uniforms.dilation[0]; - if (xR < 0 || xR >= i32(uniforms.inDims[0])) { + if (xR < 0 || xR >= uniforms.inDims[0]) { continue; } - for (var wC = 0u; wC < ${ - this.convInfo.filterWidth}u; wC = wC + 1u) { - let xC = inputColStart + i32(wC * uniforms.dilation[1]); + for (var wC = 0; wC < ${this.convInfo.filterWidth}; wC = wC + 1) { + let xC = inputColStart + wC * uniforms.dilation[1]; - if (xC < 0 || xC >= i32(uniforms.inDims[1])) { + if (xC < 0 || xC >= uniforms.inDims[1]) { continue; } - let xVal = getX(batch, u32(xR), u32(xC), d1); + let xVal = getX(batch, xR, xC, d1); let wVal = getW(wR, wC, d1, q); dotProd = dotProd + xVal * wVal; } diff --git a/tfjs-backend-webgpu/src/kernels/fill_webgpu.ts b/tfjs-backend-webgpu/src/kernels/fill_webgpu.ts index a70294552c8..cac98fe54c1 100644 --- a/tfjs-backend-webgpu/src/kernels/fill_webgpu.ts +++ b/tfjs-backend-webgpu/src/kernels/fill_webgpu.ts @@ -65,8 +65,8 @@ export class FillProgram implements WebGPUProgram { const userCode = ` ${getMainHeaderStringWgsl()} { ${getGlobalIndexStringWgsl()} - for (var i = 0u; i < ${this.workPerThread}u; i = i + 1u) { - let flatIndex = index * ${this.workPerThread}u + i; + for (var i = 0; i < ${this.workPerThread}; i = i + 1) { + let flatIndex = index * ${this.workPerThread} + i; if (flatIndex < uniforms.size) { setOutputFlat(flatIndex, uniforms.value); } diff --git a/tfjs-backend-webgpu/src/kernels/gather_nd_webgpu.ts b/tfjs-backend-webgpu/src/kernels/gather_nd_webgpu.ts index 2ff22dd2441..74616d86f85 100644 --- a/tfjs-backend-webgpu/src/kernels/gather_nd_webgpu.ts +++ b/tfjs-backend-webgpu/src/kernels/gather_nd_webgpu.ts @@ -45,7 +45,7 @@ export class GatherNDProgram implements WebGPUProgram { this.sliceDim = sliceDim; this.uniforms = `int sliceDim; ${getCoordsDataType(sliceDim)} strides;`; this.uniformsWgsl = - `sliceDim : u32; strides : ${getCoordsDataTypeWgsl(sliceDim)};`; + `sliceDim : i32; strides : ${getCoordsDataTypeWgsl(sliceDim)};`; this.useWgsl = getUseWgsl(); } getUserCode(): string { @@ -85,9 +85,9 @@ export class GatherNDProgram implements WebGPUProgram { ${getMainHeaderStringWgsl()} { ${getGlobalIndexStringWgsl()} let coords = getOutputCoords(globalId, index); - var flattenIndex = 0u; - for (var j = 0u; j < uniforms.sliceDim; j = j + 1u) { - let indexTemp = u32(round(getIndices(coords[0], j))); + var flattenIndex = 0; + for (var j = 0; j < uniforms.sliceDim; j = j + 1) { + let indexTemp = i32(round(getIndices(coords[0], j))); let strideNum = ${strideString}; flattenIndex = flattenIndex + indexTemp * strideNum; } diff --git a/tfjs-backend-webgpu/src/kernels/gather_webgpu.ts b/tfjs-backend-webgpu/src/kernels/gather_webgpu.ts index 40508a3a6f0..ef5e139074d 100644 --- a/tfjs-backend-webgpu/src/kernels/gather_webgpu.ts +++ b/tfjs-backend-webgpu/src/kernels/gather_webgpu.ts @@ -59,7 +59,7 @@ export class GatherProgram implements WebGPUProgram { } getUserCodeWgsl(): string { - const sourceCoords = getSourceCoords(this.aShape, 'u32'); + const sourceCoords = getSourceCoords(this.aShape, 'i32'); const userCode = ` ${getMainHeaderStringWgsl()} { ${getGlobalIndexStringWgsl()} diff --git a/tfjs-backend-webgpu/src/kernels/im2col_webgpu.ts b/tfjs-backend-webgpu/src/kernels/im2col_webgpu.ts index b1ccfa9e792..ebb4ed32196 100644 --- a/tfjs-backend-webgpu/src/kernels/im2col_webgpu.ts +++ b/tfjs-backend-webgpu/src/kernels/im2col_webgpu.ts @@ -17,7 +17,7 @@ import {util} from '@tensorflow/tfjs-core'; -import {getWorkGroupSizeStringWgsl} from '../shader_preprocessor_wgsl'; +import {getGlobalIndexStringWgsl, getMainHeaderStringWgsl} from '../shader_preprocessor_wgsl'; import {computeDispatch, flatDispatchLayout} from '../webgpu_util'; import {getUseWgsl, WebGPUProgram} from './webgpu_program'; @@ -26,8 +26,9 @@ export class Im2ColProgram implements WebGPUProgram { variableNames = ['A']; uniforms = `ivec2 pad, stride, dilation; int outWidth, itemsPerBlockRow, inChannels;`; - uniformsWgsl = `pad : vec2; stride : vec2; dilation : vec2; outWidth : u32; itemsPerBlockRow : u32; - inChannels : u32;`; + uniformsWgsl = + `pad : vec2; stride : vec2; dilation : vec2; outWidth : i32; itemsPerBlockRow : i32; + inChannels : i32;`; outputShape: number[]; shaderKey: string; dispatchLayout: {x: number[]}; @@ -93,12 +94,11 @@ export class Im2ColProgram implements WebGPUProgram { const colDim = this.isChannelsLast ? 1 : 2; const userCode = ` - ${getWorkGroupSizeStringWgsl()} - fn main([[builtin(global_invocation_id)]] globalId : vec3) { - let index = globalId.x; + ${getMainHeaderStringWgsl()} { + ${getGlobalIndexStringWgsl()} - for(var i = 0u; i<${this.workPerThread}u; i = i + 1u) { - let flatIndex = index * ${this.workPerThread}u + i; + for(var i = 0; i<${this.workPerThread}; i = i + 1) { + let flatIndex = index * ${this.workPerThread} + i; let rc = getCoordsFromFlatIndex(flatIndex); @@ -106,17 +106,17 @@ export class Im2ColProgram implements WebGPUProgram { let blockIndex = rc[0]; let pos = rc[1]; - let offsetY = i32(u32(blockIndex / uniforms.outWidth) * uniforms.stride[1] - uniforms.pad[1]); - let d0 = offsetY + i32(uniforms.dilation[1] * (pos / uniforms.itemsPerBlockRow)); + let offsetY = blockIndex / uniforms.outWidth * uniforms.stride[1] - uniforms.pad[1]; + let d0 = offsetY + uniforms.dilation[1] * pos / uniforms.itemsPerBlockRow; var value = 0.0; - if(d0 < i32(uniforms.aShape[${rowDim}]) && d0 >= 0) { - let offsetX = i32((blockIndex % uniforms.outWidth) * uniforms.stride[0] - - uniforms.pad[0]); - let d1 = offsetX + i32(uniforms.dilation[0]) * (i32((pos % - uniforms.itemsPerBlockRow) / uniforms.inChannels)); - let ch = u32(pos % uniforms.inChannels); - if(d1 < i32(uniforms.aShape[${colDim}]) && d1 >= 0) { - value = getA(u32(d0), u32(d1), ch); + if(d0 < uniforms.aShape[${rowDim}] && d0 >= 0) { + let offsetX = (blockIndex % uniforms.outWidth) * uniforms.stride[0] - + uniforms.pad[0]; + let d1 = offsetX + uniforms.dilation[0] * ((pos % + uniforms.itemsPerBlockRow) / uniforms.inChannels); + let ch = pos % uniforms.inChannels; + if(d1 < uniforms.aShape[${colDim}] && d1 >= 0) { + value = getA(d0, d1, ch); } } setOutputFlat(flatIndex, value); diff --git a/tfjs-backend-webgpu/src/kernels/matmul_packed_vec4_webgpu.ts b/tfjs-backend-webgpu/src/kernels/matmul_packed_vec4_webgpu.ts index 1347873dfc5..0f75b877e36 100644 --- a/tfjs-backend-webgpu/src/kernels/matmul_packed_vec4_webgpu.ts +++ b/tfjs-backend-webgpu/src/kernels/matmul_packed_vec4_webgpu.ts @@ -17,7 +17,7 @@ import {backend_util, TensorInfo} from '@tensorflow/tfjs-core'; -import {getWorkGroupSizeStringWgsl} from '../shader_preprocessor_wgsl'; +import {getMainHeaderStringWgsl} from '../shader_preprocessor_wgsl'; import {computeDispatch, computeWorkGroupSizeForMatMul, tilesFitEvenlyIntoShape} from '../webgpu_util'; import {mapActivationToShaderProgram} from './activation_util'; @@ -179,22 +179,20 @@ export function makeMatMulPackedVec4SourceWgsl( var mm_Bsub : array, ${ tileInfo.TileBOuter / tileInfo.ColPerThread}>, ${tileInfo.TileInner}>; - let RowPerThread = ${tileInfo.RowPerThread}u; - let ColPerThread = ${tileInfo.ColPerThread}u; // only support ColPerThread = 4 - let TileAOuter = ${tileInfo.TileAOuter}u; - let TileBOuter = ${tileInfo.TileBOuter}u; - let TileInner = ${tileInfo.TileInner}u; + let RowPerThread = ${tileInfo.RowPerThread}; + let ColPerThread = ${tileInfo.ColPerThread}; // only support ColPerThread = 4 + let TileAOuter = ${tileInfo.TileAOuter}; + let TileBOuter = ${tileInfo.TileBOuter}; + let TileInner = ${tileInfo.TileInner}; - ${getWorkGroupSizeStringWgsl()} - fn main([[builtin(local_invocation_id)]] localId : vec3, - [[builtin(global_invocation_id)]] globalId : vec3) { + ${getMainHeaderStringWgsl()} { - let tileRow = localId.y * RowPerThread; - let tileCol = localId.x; + let tileRow = i32(localId.y) * RowPerThread; + let tileCol = i32(localId.x); - let globalRow = globalId.y * RowPerThread; - let globalCol = globalId.x; - let numTiles = (uniforms.dimInner - 1u) / TileInner + 1u; + let globalRow = i32(globalId.y) * RowPerThread; + let globalCol = i32(globalId.x); + let numTiles = (uniforms.dimInner - 1) / TileInner + 1; var acc: array, ${tileInfo.RowPerThread}>; var ACached : vec4; @@ -202,11 +200,11 @@ export function makeMatMulPackedVec4SourceWgsl( // Loop over shared dimension. var globalColA = tileCol; - let RowPerThreadB = TileInner / ${workGroupSize[1]}u; - let tileRowB = localId.y * RowPerThreadB; - for (var t = 0u; t < numTiles; t = t + 1u) { + let RowPerThreadB = TileInner / ${workGroupSize[1]}; + let tileRowB = i32(localId.y) * RowPerThreadB; + for (var t = 0; t < numTiles; t = t + 1) { // Load one tile of A into local memory. - for (var innerRow = 0u; innerRow < RowPerThread; innerRow = innerRow + 1u) { + for (var innerRow = 0; innerRow < RowPerThread; innerRow = innerRow + 1) { let inputRow = tileRow + innerRow; let inputCol = tileCol; mm_Asub[inputRow][inputCol] = mm_readA(globalRow + innerRow, globalColA, globalId); @@ -214,7 +212,7 @@ export function makeMatMulPackedVec4SourceWgsl( globalColA = globalColA + TileInner / ColPerThread; // Load one tile of B into local memory. - for (var innerRow = 0u; innerRow < RowPerThreadB; innerRow = innerRow + 1u) { + for (var innerRow = 0; innerRow < RowPerThreadB; innerRow = innerRow + 1) { let inputRow = tileRowB + innerRow; let inputCol = tileCol; mm_Bsub[inputRow][inputCol] = mm_readB(t * TileInner + inputRow, globalCol, globalId); @@ -223,13 +221,13 @@ export function makeMatMulPackedVec4SourceWgsl( workgroupBarrier(); // Compute acc values for a single thread. - for (var k = 0u; k < TileInner / ColPerThread; k = k + 1u) { + for (var k = 0; k < TileInner / ColPerThread; k = k + 1) { BCached[0] = mm_Bsub[k * ColPerThread][tileCol]; - BCached[1] = mm_Bsub[k * ColPerThread + 1u][tileCol]; - BCached[2] = mm_Bsub[k * ColPerThread + 2u][tileCol]; - BCached[3] = mm_Bsub[k * ColPerThread + 3u][tileCol]; + BCached[1] = mm_Bsub[k * ColPerThread + 1][tileCol]; + BCached[2] = mm_Bsub[k * ColPerThread + 2][tileCol]; + BCached[3] = mm_Bsub[k * ColPerThread + 3][tileCol]; - for (var i = 0u; i < RowPerThread; i = i + 1u) { + for (var i = 0; i < RowPerThread; i = i + 1) { ACached = mm_Asub[tileRow + i][k]; acc[i] = BCached[0] * ACached.x + acc[i]; acc[i] = BCached[1] * ACached.y + acc[i]; @@ -241,7 +239,7 @@ export function makeMatMulPackedVec4SourceWgsl( workgroupBarrier(); } - for (var innerRow = 0u; innerRow < RowPerThread; innerRow = innerRow + 1u) { + for (var innerRow = 0; innerRow < RowPerThread; innerRow = innerRow + 1) { mm_write(globalRow + innerRow, globalCol, acc[innerRow], globalId); @@ -253,34 +251,32 @@ export function makeMatMulVectorVec4SourceWgsl( workGroupSize: [number, number, number]): string { return ` var mm_Asub : array, ${workGroupSize[0]}>; - let tileSize = ${workGroupSize[0] * 4}u; - ${getWorkGroupSizeStringWgsl()} - fn main([[builtin(local_invocation_id)]] localId : vec3, - [[builtin(global_invocation_id)]] globalId : vec3) { - let tileCol = localId.x; - let globalCol = globalId.x; - let globalRow = globalId.y; + let tileSize = ${workGroupSize[0] * 4}; + ${getMainHeaderStringWgsl()} { + let tileCol = i32(localId.x); + let globalCol = i32(globalId.x); + let globalRow = i32(globalId.y); - let numTiles = (uniforms.dimInner - 1u) / tileSize + 1u; + let numTiles = (uniforms.dimInner - 1) / tileSize + 1; // Without this initialization strange values show up in acc. var acc = vec4(0.0); // Loop over shared dimension. - for (var t = 0u; t < numTiles; t = t + 1u) { + for (var t = 0; t < numTiles; t = t + 1) { // Load one tile of A into local memory. - let colA = t * tileSize / 4u + tileCol; + let colA = t * tileSize / 4 + tileCol; mm_Asub[tileCol] = mm_readA(globalRow, colA, globalId); workgroupBarrier(); // Compute acc values for a single thread. - for (var k = 0u; k < tileSize / 4u; k = k + 1u) { - let rowB = t * tileSize + k * 4u; + for (var k = 0; k < tileSize / 4; k = k + 1) { + let rowB = t * tileSize + k * 4; let BCached0 = mm_readB(rowB, globalCol, globalId); - let BCached1 = mm_readB(rowB + 1u, globalCol, globalId); - let BCached2 = mm_readB(rowB + 2u, globalCol, globalId); - let BCached3 = mm_readB(rowB + 3u, globalCol, globalId); + let BCached1 = mm_readB(rowB + 1, globalCol, globalId); + let BCached2 = mm_readB(rowB + 2, globalCol, globalId); + let BCached3 = mm_readB(rowB + 3, globalCol, globalId); let ACached = mm_Asub[k]; acc = acc + BCached0 * ACached.x; @@ -306,7 +302,7 @@ export class MatMulPackedVec4Program implements WebGPUProgram { dispatch: [number, number, number]; workPerThread: number; variableNames = ['A', 'B']; - uniformsWgsl = `dimAOuter : u32; dimBOuter : u32; dimInner : u32;`; + uniformsWgsl = `dimAOuter : i32; dimBOuter : i32; dimInner : i32;`; workGroupSize: [number, number, number] = [16, 16, 1]; useWgsl: boolean; isVec4 = true; @@ -449,16 +445,16 @@ export class MatMulPackedVec4Program implements WebGPUProgram { getUserCodeWgsl(): string { const sampleA = this.fitA ? - `return A.numbers[batch * batchASize + row * uniforms.dimInner / 4u + col]` : - `if (coordsInBounds2D(vec2(row, col * 4u), vec2(uniforms.dimAOuter, uniforms.dimInner))) { - return A.numbers[batch * batchASize + row * uniforms.dimInner / 4u + col]; + `return A.numbers[batch * batchASize + row * uniforms.dimInner / 4 + col]` : + `if (coordsInBounds2D(vec2(row, col * 4), vec2(uniforms.dimAOuter, uniforms.dimInner))) { + return A.numbers[batch * batchASize + row * uniforms.dimInner / 4 + col]; } return vec4(0.0)`; const sampleB = this.fitB ? - `return B.numbers[batch * batchBSize + row * uniforms.dimBOuter / 4u + col]` : - `if(coordsInBounds2D(vec2(row, col * 4u), vec2(uniforms.dimInner, uniforms.dimBOuter))) { - return B.numbers[batch * batchBSize + row * uniforms.dimBOuter / 4u + col]; + `return B.numbers[batch * batchBSize + row * uniforms.dimBOuter / 4 + col]` : + `if(coordsInBounds2D(vec2(row, col * 4), vec2(uniforms.dimInner, uniforms.dimBOuter))) { + return B.numbers[batch * batchBSize + row * uniforms.dimBOuter / 4 + col]; } return vec4(0.0)`; @@ -468,13 +464,13 @@ export class MatMulPackedVec4Program implements WebGPUProgram { this.activation, this.isVec4, this.useWgsl); if (this.hasPreluActivationWeights) { activationSnippet = - `fn activation(a : vec4, outCoord : vec3) -> vec4 { + `fn activation(a : vec4, outCoord : vec3) -> vec4 { let b = getPreluActivationWeightsAtOutCoordsByCoords(outCoord); ${activationOp} }`; } else { activationSnippet = ` - fn activation(a : vec4, outCoord : vec3) -> vec4 { + fn activation(a : vec4, outCoord : vec3) -> vec4 { ${activationOp} }`; } @@ -487,26 +483,26 @@ export class MatMulPackedVec4Program implements WebGPUProgram { const userCode = ` ${activationSnippet} - fn mm_readA(row : u32, col : u32, globalId : vec3) -> vec4 { + fn mm_readA(row : i32, col : i32, globalId : vec3) -> vec4 { let batchASize = uniforms.aShape[1] * uniforms.aShape[2] / ${ - this.vecSize}u; - let batch = globalId.z; + this.vecSize}; + let batch = i32(globalId.z); ${sampleA}; } - fn mm_readB(row : u32, col : u32, globalId : vec3) -> vec4 { + fn mm_readB(row : i32, col : i32, globalId : vec3) -> vec4 { let batchBSize = uniforms.bShape[1] * uniforms.bShape[2] / ${ - this.vecSize}u; - let batch = globalId.z; + this.vecSize}; + let batch = i32(globalId.z); ${sampleB}; } - fn mm_write(row : u32, col : u32, valueIn : vec4, globalId : vec3) { - if (row < uniforms.aShape[1] && col * 4u < uniforms.bShape[2]) + fn mm_write(row : i32, col : i32, valueIn : vec4, globalId : vec3) { + if (row < uniforms.aShape[1] && col * 4 < uniforms.bShape[2]) { var value = valueIn; - let batch = globalId.z; - let outCoord = vec3(batch, row, col * 4u); + let batch = i32(globalId.z); + let outCoord = vec3(batch, row, col * 4); ${addBiasSnippet} ${applyActivationSnippet} setOutput(outCoord[0], outCoord[1], outCoord[2], value); diff --git a/tfjs-backend-webgpu/src/kernels/matmul_packed_webgpu.ts b/tfjs-backend-webgpu/src/kernels/matmul_packed_webgpu.ts index 067df784f8b..bf23e98d384 100644 --- a/tfjs-backend-webgpu/src/kernels/matmul_packed_webgpu.ts +++ b/tfjs-backend-webgpu/src/kernels/matmul_packed_webgpu.ts @@ -185,55 +185,55 @@ export function makeMatMulPackedSourceWgsl( var mm_Asub : array, ${tileAOuter}>; var mm_Bsub : array, ${tileInner}>; ${getMainHeaderStringWgsl()} { - let tileRow = localId.y * ${workPerThread[1]}u; - let tileCol = localId.x * ${workPerThread[0]}u; + let tileRow = i32(localId.y) * ${workPerThread[1]}; + let tileCol = i32(localId.x) * ${workPerThread[0]}; - let globalRow = globalId.y * ${workPerThread[1]}u; - let globalCol = globalId.x * ${workPerThread[0]}u; + let globalRow = i32(globalId.y) * ${workPerThread[1]}; + let globalCol = i32(globalId.x) * ${workPerThread[0]}; - let numTiles = (uniforms.dimInner - 1u) / ${tileInner}u + 1u; + let numTiles = (uniforms.dimInner - 1) / ${tileInner} + 1; var acc : array, ${workPerThread[1]}>; var ACached : f32; var BCached : array; // Without this initialization strange values show up in acc. - for (var innerRow = 0u; innerRow < ${ - workPerThread[1]}u; innerRow = innerRow + 1u) { - for (var innerCol = 0u; innerCol < ${ - workPerThread[0]}u; innerCol = innerCol + 1u) { + for (var innerRow = 0; innerRow < ${ + workPerThread[1]}; innerRow = innerRow + 1) { + for (var innerCol = 0; innerCol < ${ + workPerThread[0]}; innerCol = innerCol + 1) { acc[innerRow][innerCol] = 0.0; } } - let ColPerThreadA = ${tileInner}u / ${workGroupSize[0]}u; - let tileColA = localId.x * ColPerThreadA; - let RowPerThreadB = ${tileInner}u / ${workGroupSize[1]}u; - let tileRowB = localId.y * RowPerThreadB; + let ColPerThreadA = ${tileInner} / ${workGroupSize[0]}; + let tileColA = i32(localId.x) * ColPerThreadA; + let RowPerThreadB = ${tileInner} / ${workGroupSize[1]}; + let tileRowB = i32(localId.y) * RowPerThreadB; // Loop over shared dimension. - for (var t = 0u; t < numTiles; t = t + 1u) { + for (var t = 0; t < numTiles; t = t + 1) { // Load one tile of A into local memory. - for (var innerRow = 0u; innerRow < ${ - workPerThread[1]}u; innerRow = innerRow + 1u) { - for (var innerCol = 0u; innerCol < ColPerThreadA; innerCol = innerCol + 1u) { + for (var innerRow = 0; innerRow < ${ + workPerThread[1]}; innerRow = innerRow + 1) { + for (var innerCol = 0; innerCol < ColPerThreadA; innerCol = innerCol + 1) { let inputRow = tileRow + innerRow; let inputCol = tileColA + innerCol; mm_Asub[inputRow][inputCol] = mm_readA( globalRow + innerRow, - t * ${tileInner}u + inputCol, globalId); + t * ${tileInner} + inputCol, globalId); } } // Load one tile of B into local memory. - for (var innerRow = 0u; innerRow < RowPerThreadB; innerRow = innerRow + 1u) { - for (var innerCol = 0u; innerCol < ${ - workPerThread[0]}u; innerCol = innerCol + 1u) { + for (var innerRow = 0; innerRow < RowPerThreadB; innerRow = innerRow + 1) { + for (var innerCol = 0; innerCol < ${ + workPerThread[0]}; innerCol = innerCol + 1) { let inputRow = tileRowB + innerRow; let inputCol = tileCol + innerCol; mm_Bsub[inputRow][inputCol] = mm_readB( - t * ${tileInner}u + inputRow, + t * ${tileInner} + inputRow, globalCol + innerCol, globalId); } } @@ -241,17 +241,16 @@ export function makeMatMulPackedSourceWgsl( workgroupBarrier(); // Compute acc values for a single thread. - for (var k = 0u; k < ${tileInner}u; k = k + 1u) { - for (var inner = 0u; inner < ${ - workPerThread[0]}u; inner = inner + 1u) { + for (var k = 0; k < ${tileInner}; k = k + 1) { + for (var inner = 0; inner < ${workPerThread[0]}; inner = inner + 1) { BCached[inner] = mm_Bsub[k][tileCol + inner]; } - for (var innerRow = 0u; innerRow < ${ - workPerThread[1]}u; innerRow = innerRow + 1u) { + for (var innerRow = 0; innerRow < ${ + workPerThread[1]}; innerRow = innerRow + 1) { ACached = mm_Asub[tileRow + innerRow][k]; - for (var innerCol = 0u; innerCol < ${ - workPerThread[0]}u; innerCol = innerCol + 1u) { + for (var innerCol = 0; innerCol < ${ + workPerThread[0]}; innerCol = innerCol + 1) { acc[innerRow][innerCol] = acc[innerRow][innerCol] + ACached * BCached[innerCol]; } } @@ -260,10 +259,10 @@ export function makeMatMulPackedSourceWgsl( workgroupBarrier(); } - for (var innerRow = 0u; innerRow < ${ - workPerThread[1]}u; innerRow = innerRow + 1u) { - for (var innerCol = 0u; innerCol < ${ - workPerThread[0]}u; innerCol = innerCol + 1u) { + for (var innerRow = 0; innerRow < ${ + workPerThread[1]}; innerRow = innerRow + 1) { + for (var innerCol = 0; innerCol < ${ + workPerThread[0]}; innerCol = innerCol + 1) { if ((globalCol + innerCol) < uniforms.dimBOuter && (globalRow + innerRow) < uniforms.dimAOuter) { @@ -280,36 +279,36 @@ export function makeMatMulPackedSourceWgsl( export function makeMatMulVectorSourceWgsl( workGroupSize: [number, number, number]): string { return ` - let TileSize = ${workGroupSize[0] * 4}u; + let TileSize = ${workGroupSize[0] * 4}; var mm_Asub : array, ${workGroupSize[0]}>; ${getMainHeaderStringWgsl()} { - let tileCol = localId.x; - let globalCol = globalId.x; - let globalRow = globalId.y; + let tileCol = i32(localId.x); + let globalCol = i32(globalId.x); + let globalRow = i32(globalId.y); - let numTiles = (uniforms.dimInner - 1u) / TileSize + 1u; + let numTiles = (uniforms.dimInner - 1) / TileSize + 1; // Without this initialization strange values show up in acc. var acc = 0.0; // Loop over shared dimension. - for (var t = 0u; t < numTiles; t = t + 1u) { + for (var t = 0; t < numTiles; t = t + 1) { // Load one tile of A into local memory. - let colA = t * TileSize + tileCol * 4u; + let colA = t * TileSize + tileCol * 4; mm_Asub[tileCol] = vec4(mm_readA(globalRow, colA, globalId), - mm_readA(globalRow, colA + 1u, globalId), - mm_readA(globalRow, colA + 2u, globalId), - mm_readA(globalRow, colA + 3u, globalId)); + mm_readA(globalRow, colA + 1, globalId), + mm_readA(globalRow, colA + 2, globalId), + mm_readA(globalRow, colA + 3, globalId)); workgroupBarrier(); // Compute acc values for a single thread. - for (var k = 0u; k < TileSize / 4u; k = k + 1u) { - let rowB = t * TileSize + k * 4u; + for (var k = 0; k < TileSize / 4; k = k + 1) { + let rowB = t * TileSize + k * 4; let BCached = vec4(mm_readB(rowB, globalCol, globalId), - mm_readB(rowB + 1u, globalCol, globalId), - mm_readB(rowB + 2u, globalCol, globalId), - mm_readB(rowB + 3u, globalCol, globalId)); + mm_readB(rowB + 1, globalCol, globalId), + mm_readB(rowB + 2, globalCol, globalId), + mm_readB(rowB + 3, globalCol, globalId)); let ACached = mm_Asub[k]; acc = acc + dot(ACached, BCached); @@ -332,7 +331,7 @@ export class MatMulPackedProgram implements WebGPUProgram { dispatch: [number, number, number]; workPerThread: number; variableNames = ['A', 'B']; - uniformsWgsl = `dimAOuter : u32; dimBOuter : u32; dimInner : u32;`; + uniformsWgsl = `dimAOuter : i32; dimBOuter : i32; dimInner : i32;`; workGroupSize: [number, number, number] = [16, 16, 1]; useWgsl: boolean; aShape: [number, number, number]; @@ -515,14 +514,14 @@ export class MatMulPackedProgram implements WebGPUProgram { if (this.transposeA === false) { sampleA = this.fitA ? `return A.numbers[batch * batchASize + row * uniforms.dimInner + col];` : - `if(coordsInBounds2D(vec2(row, col), vec2(uniforms.dimAOuter, uniforms.dimInner))) { + `if(coordsInBounds2D(vec2(row, col), vec2(uniforms.dimAOuter, uniforms.dimInner))) { return A.numbers[batch * batchASize + row * uniforms.dimInner + col]; } return 0.0;`; } else { sampleA = this.fitA ? `return A.numbers[batch * batchASize + col * uniforms.dimAOuter + row];` : - `if(coordsInBounds2D(vec2(row, col), vec2(uniforms.dimAOuter, uniforms.dimInner))) { + `if(coordsInBounds2D(vec2(row, col), vec2(uniforms.dimAOuter, uniforms.dimInner))) { return A.numbers[batch* batchASize + col * uniforms.dimAOuter + row]; } return 0.0;`; @@ -532,14 +531,14 @@ export class MatMulPackedProgram implements WebGPUProgram { if (this.transposeB === false) { sampleB = this.fitB ? `return B.numbers[batch * batchBSize + row * uniforms.dimBOuter + col];` : - `if(coordsInBounds2D(vec2(row, col), vec2(uniforms.dimInner, uniforms.dimBOuter))) { + `if(coordsInBounds2D(vec2(row, col), vec2(uniforms.dimInner, uniforms.dimBOuter))) { return B.numbers[batch * batchBSize + row * uniforms.dimBOuter + col]; } return 0.0;`; } else { sampleB = this.fitB ? `return B.numbers[batch * batchBSize + col * uniforms.dimInner + row];` : - `if(coordsInBounds2D(vec2(row, col), vec2(uniforms.dimInner, uniforms.dimBOuter))) { + `if(coordsInBounds2D(vec2(row, col), vec2(uniforms.dimInner, uniforms.dimBOuter))) { return B.numbers[batch * batchBSize + col * uniforms.dimInner + row]; } return 0.0;`; @@ -551,13 +550,13 @@ export class MatMulPackedProgram implements WebGPUProgram { mapActivationToShaderProgram(this.activation, false, this.useWgsl); if (this.hasPreluActivationWeights) { activationSnippet = - `fn activation(a : f32, outCoord : vec3) -> f32 { + `fn activation(a : f32, outCoord : vec3) -> f32 { let b = getPreluActivationWeightsAtOutCoordsByCoords(outCoord); ${activationOp} }`; } else { activationSnippet = ` - fn activation(a : f32, outCoord : vec3) -> f32 { + fn activation(a : f32, outCoord : vec3) -> f32 { ${activationOp} } `; @@ -573,22 +572,22 @@ export class MatMulPackedProgram implements WebGPUProgram { const userCode = ` ${activationSnippet} - fn mm_readA(row : u32, col : u32, globalId : vec3) -> f32 { + fn mm_readA(row : i32, col : i32, globalId : vec3) -> f32 { let batchASize = uniforms.aShape[1] * uniforms.aShape[2]; - let batch = globalId.z; + let batch = i32(globalId.z); ${sampleA} } - fn mm_readB(row : u32, col : u32, globalId : vec3) -> f32 { - let batch = globalId.z; + fn mm_readB(row : i32, col : i32, globalId : vec3) -> f32 { + let batch = i32(globalId.z); let batchBSize = uniforms.bShape[1] * uniforms.bShape[2]; ${sampleB} } - fn mm_write(row : u32, col : u32, valueIn : f32, globalId : vec3) { + fn mm_write(row : i32, col : i32, valueIn : f32, globalId : vec3) { var value = valueIn; - let batch = globalId.z; - let outCoord = vec3(batch, row, col); + let batch = i32(globalId.z); + let outCoord = vec3(batch, row, col); ${addBiasSnippet} ${applyActivationSnippet} setOutput(batch, row, col, value); diff --git a/tfjs-backend-webgpu/src/kernels/matmul_small_output_size_webgpu.ts b/tfjs-backend-webgpu/src/kernels/matmul_small_output_size_webgpu.ts index 1853d211e15..84e8ac680a2 100644 --- a/tfjs-backend-webgpu/src/kernels/matmul_small_output_size_webgpu.ts +++ b/tfjs-backend-webgpu/src/kernels/matmul_small_output_size_webgpu.ts @@ -126,78 +126,78 @@ export function makeMatMulSmallOutputSizeSourceWgsl( // makes ALUs and load/store units work simultaneously, could improves // the performance. ${getMainHeaderStringWgsl()} { - let tileRow = localId.y; - let tileCol = localId.x; - let globalRow = globalId.y; - let globalCol = globalId.x; + let tileRow = i32(localId.y); + let tileCol = i32(localId.x); + let globalRow = i32(globalId.y); + let globalCol = i32(globalId.x); // uniforms.dimInner should be greater than 0. - let numTiles = (uniforms.dimInner - 1u) / ${tileInner}u + 1u; + let numTiles = (uniforms.dimInner - 1) / ${tileInner} + 1; var acc = 0.0; var globalColA = tileCol; var globalRowB = tileRow; - for (var t = 0u; t < numTiles; t = t + 1u) { - if (t == 0u) { - if (tileRow < ${tileAOuter}u) { + for (var t = 0; t < numTiles; t = t + 1) { + if (t == 0) { + if (tileRow < ${tileAOuter}) { // Load one tile of A and B into local memory. // globalRow is always greater than or equal tileRow. mm_Asub1[tileRow][tileCol] = - mm_readA((globalRow - tileRow) / 2u + tileRow, globalColA, globalId); - globalColA = globalColA + ${tileInner}u; + mm_readA((globalRow - tileRow) / 2 + tileRow, globalColA, globalId); + globalColA = globalColA + ${tileInner}; mm_Bsub1[tileRow][tileCol] = mm_readB(globalRowB, globalCol, globalId); - globalRowB = globalRowB + ${tileInner}u; + globalRowB = globalRowB + ${tileInner}; } } else { - if (tileRow < ${tileAOuter}u) { + if (tileRow < ${tileAOuter}) { // Load one tile of A and B into local memory. // globalRow is always greater than or equal tileRow. mm_Asub1[tileRow][tileCol] = - mm_readA((globalRow - tileRow) / 2u + tileRow, globalColA, globalId); - globalColA = globalColA + ${tileInner}u; + mm_readA((globalRow - tileRow) / 2 + tileRow, globalColA, globalId); + globalColA = globalColA + ${tileInner}; mm_Bsub1[tileRow][tileCol] = mm_readB(globalRowB, globalCol, globalId); - globalRowB = globalRowB + ${tileInner}u; + globalRowB = globalRowB + ${tileInner}; } else { // Compute acc values for a single thread. - for (var k = 0u; k < ${tileInner}u; k = k + 1u) { - let subRow = i32(tileRow - ${tileAOuter}u); + for (var k = 0; k < ${tileInner}; k = k + 1) { + let subRow = tileRow - ${tileAOuter}; if (subRow < 0) { continue; } - acc = acc + mm_Asub2[u32(subRow)][k] * mm_Bsub2[k][tileCol]; + acc = acc + mm_Asub2[subRow][k] * mm_Bsub2[k][tileCol]; } } } workgroupBarrier(); - if (t != 0u) { - t = t + 1u; + if (t != 0) { + t = t + 1; } if (t < numTiles) { - if (tileRow < ${tileAOuter}u) { + if (tileRow < ${tileAOuter}) { // Load one tile of A and B into local memory. // globalRow is always greater than or equal tileRow. mm_Asub2[tileRow][tileCol] = - mm_readA((globalRow - tileRow) / 2u + tileRow, globalColA, globalId); - globalColA = globalColA + ${tileInner}u; + mm_readA((globalRow - tileRow) / 2 + tileRow, globalColA, globalId); + globalColA = globalColA + ${tileInner}; mm_Bsub2[tileRow][tileCol] = mm_readB(globalRowB, globalCol, globalId); - globalRowB = globalRowB + ${tileInner}u; + globalRowB = globalRowB + ${tileInner}; } else { // Compute acc values for a single thread. - for (var k = 0u; k < ${tileInner}u; k = k + 1u) { - let subRow = i32(tileRow - ${tileAOuter}u); + for (var k = 0; k < ${tileInner}; k = k + 1) { + let subRow = tileRow - ${tileAOuter}; if (subRow < 0) { continue; } - acc = acc + mm_Asub1[u32(subRow)][k] * mm_Bsub1[k][tileCol]; + acc = acc + mm_Asub1[subRow][k] * mm_Bsub1[k][tileCol]; } } } workgroupBarrier(); } - let writeCol = i32((globalRow - tileRow) / 2u + tileRow - ${tileAOuter}u); - if (tileRow >= ${tileAOuter}u && writeCol >= 0) { - mm_write(u32(writeCol), globalCol, acc, globalId); + let writeCol = (globalRow - tileRow) / 2 + tileRow - ${tileAOuter}; + if (tileRow >= ${tileAOuter} && writeCol >= 0) { + mm_write(writeCol, globalCol, acc, globalId); } } `; @@ -209,7 +209,7 @@ export class MatMulSmallOutputSizeProgram implements WebGPUProgram { dispatchLayout: {x: number[], y: number[], z: number[]}; dispatch: [number, number, number]; variableNames = ['A', 'B']; - uniformsWgsl = `dimAOuter : u32; dimBOuter : u32; dimInner : u32;`; + uniformsWgsl = `dimAOuter : i32; dimBOuter : i32; dimInner : i32;`; workGroupSize: [number, number, number] = [8, 16, 1]; addBias: boolean; activation: backend_util.Activation; @@ -312,13 +312,13 @@ export class MatMulSmallOutputSizeProgram implements WebGPUProgram { getUserCodeWgsl(): string { const sampleA = - `if (coordsInBounds2D(vec2(row, col), vec2(uniforms.dimAOuter, uniforms.dimInner))) { + `if (coordsInBounds2D(vec2(row, col), vec2(uniforms.dimAOuter, uniforms.dimInner))) { return A.numbers[batch * batchASize + row * uniforms.dimInner + col]; } return 0.0;`; const sampleB = - `if (coordsInBounds2D(vec2(row, col), vec2(uniforms.dimInner, uniforms.dimBOuter))) { + `if (coordsInBounds2D(vec2(row, col), vec2(uniforms.dimInner, uniforms.dimBOuter))) { return B.numbers[batch * batchBSize + row * uniforms.dimBOuter + col]; } return 0.0;`; @@ -329,13 +329,13 @@ export class MatMulSmallOutputSizeProgram implements WebGPUProgram { mapActivationToShaderProgram(this.activation, false, true); if (this.hasPreluActivationWeights) { activationSnippet = - `fn activation(a : f32, outCoord : vec3) -> f32 { + `fn activation(a : f32, outCoord : vec3) -> f32 { let b = getPreluActivationWeightsAtOutCoordsByCoords(outCoord); ${activationOp} }`; } else { activationSnippet = - `fn activation(a : f32, outCoord : vec3) -> f32 { + `fn activation(a : f32, outCoord : vec3) -> f32 { ${activationOp} }`; } @@ -350,20 +350,20 @@ export class MatMulSmallOutputSizeProgram implements WebGPUProgram { const userCode = ` ${activationSnippet} - fn mm_readA(row : u32, col : u32, globalId : vec3) -> f32 { + fn mm_readA(row : i32, col : i32, globalId : vec3) -> f32 { let batchASize = uniforms.aShape[1] * uniforms.aShape[2]; - let batch = globalId.z; + let batch = i32(globalId.z); ${sampleA} } - fn mm_readB(row : u32, col : u32, globalId : vec3) -> f32 { - let batch = globalId.z; + fn mm_readB(row : i32, col : i32, globalId : vec3) -> f32 { + let batch = i32(globalId.z); let batchBSize = uniforms.bShape[1] * uniforms.bShape[2]; ${sampleB} } - fn mm_write(row : u32, col : u32, valueIn : f32, globalId : vec3) { - if (coordsInBounds2D(vec2(row, col), vec2(uniforms.dimAOuter, uniforms.dimBOuter))) { - let batch = globalId.z; - let outCoord = vec3(batch, row, col); + fn mm_write(row : i32, col : i32, valueIn : f32, globalId : vec3) { + if (coordsInBounds2D(vec2(row, col), vec2(uniforms.dimAOuter, uniforms.dimBOuter))) { + let batch = i32(globalId.z); + let outCoord = vec3(batch, row, col); var value = valueIn; ${addBiasSnippet} ${applyActivationSnippet} diff --git a/tfjs-backend-webgpu/src/kernels/mirror_pad_webgpu.ts b/tfjs-backend-webgpu/src/kernels/mirror_pad_webgpu.ts index e8942c337d8..20e317fd675 100644 --- a/tfjs-backend-webgpu/src/kernels/mirror_pad_webgpu.ts +++ b/tfjs-backend-webgpu/src/kernels/mirror_pad_webgpu.ts @@ -49,7 +49,7 @@ export class MirrorPadProgram implements WebGPUProgram { this.xShape = xShape; paddings.map((_, i) => { this.uniforms += ` ivec2 pad${i};`; - this.uniformsWgsl += ` pad${i} : vec2;`; + this.uniformsWgsl += ` pad${i} : vec2;`; }); this.offset = mode === 'reflect' ? 0 : 1; this.shaderKey = `mirrorPad_${mode}`; @@ -102,7 +102,8 @@ export class MirrorPadProgram implements WebGPUProgram { getUserCodeWgsl(): string { const rank = this.xShape.length; // The length of paddings are same with the rank of the input tensor. - const start = this.xShape.map((_, i) => `uniforms.pad${i}[0]`).join(','); + const start = + this.xShape.map((_, i) => `uniforms.pad${i}[0]`).join(','); const end = this.xShape .map( (_, i) => `uniforms.pad${i}[0] + uniforms.xShape${ @@ -123,15 +124,14 @@ export class MirrorPadProgram implements WebGPUProgram { let start = ${dtype}(${start}); let end = ${dtype}(${end}); var outC = getOutputCoords(globalId, index); - if (index < uniforms.size) - { - for (var i = 0u; i < ${rank}u; i = i + 1u) { + if (index < uniforms.size) { + for (var i = 0; i < ${rank}; i = i + 1) { if (${shaderOutC} < ${shaderStart}) { - ${shaderOutC} = ${shaderStart} * 2u - ${shaderOutC} - ${ - this.offset}u; + ${shaderOutC} = ${shaderStart} * 2 - ${shaderOutC} - ${ + this.offset}; } elseif(${shaderOutC} >= ${shaderEnd}) { - ${shaderOutC} = (${shaderEnd} - 1u) * 2u - ${shaderOutC} + ${ - this.offset}u; + ${shaderOutC} = (${shaderEnd} - 1) * 2 - ${shaderOutC} + ${ + this.offset}; } } let coords = outC - start; diff --git a/tfjs-backend-webgpu/src/kernels/pad_webgpu.ts b/tfjs-backend-webgpu/src/kernels/pad_webgpu.ts index f4a1ec86dc1..c30f18ad33e 100644 --- a/tfjs-backend-webgpu/src/kernels/pad_webgpu.ts +++ b/tfjs-backend-webgpu/src/kernels/pad_webgpu.ts @@ -44,7 +44,7 @@ export class PadProgram implements WebGPUProgram { this.dispatchLayout, this.outputShape, this.workGroupSize); paddings.map((_, i) => { this.uniforms += ` ivec2 pad${i};`; - this.uniformsWgsl += ` pad${i} : vec2;`; + this.uniformsWgsl += ` pad${i} : vec2;`; }); this.xShape = xShape; this.shaderKey = 'pad'; @@ -99,7 +99,8 @@ export class PadProgram implements WebGPUProgram { const rank = this.xShape.length; const type = getCoordsDataTypeWgsl(rank); // The length of paddings are same with the rank of the input tensor. - const start = this.xShape.map((_, i) => `uniforms.pad${i}[0]`).join(','); + const start = + this.xShape.map((_, i) => `uniforms.pad${i}[0]`).join(','); const end = this.xShape .map( (_, i) => `uniforms.pad${i}[0] + uniforms.xShape${ diff --git a/tfjs-backend-webgpu/src/kernels/pool2d_webgpu.ts b/tfjs-backend-webgpu/src/kernels/pool2d_webgpu.ts index ead7557f3dd..158297d3eef 100644 --- a/tfjs-backend-webgpu/src/kernels/pool2d_webgpu.ts +++ b/tfjs-backend-webgpu/src/kernels/pool2d_webgpu.ts @@ -137,7 +137,7 @@ export class Pool2DProgram implements WebGPUProgram { continue; } - let value = getX(batch, u32(xR), u32(xC), coords[3]); + let value = getX(batch, xR, xC, coords[3]); ${updateSnippet} } } diff --git a/tfjs-backend-webgpu/src/kernels/pool_filtersizeone_webgpu.ts b/tfjs-backend-webgpu/src/kernels/pool_filtersizeone_webgpu.ts index 0ad0584eac0..ebb2481add1 100644 --- a/tfjs-backend-webgpu/src/kernels/pool_filtersizeone_webgpu.ts +++ b/tfjs-backend-webgpu/src/kernels/pool_filtersizeone_webgpu.ts @@ -73,7 +73,7 @@ export class PoolWithFilterSizeEqualsOneProgram implements WebGPUProgram { let d = coords[3]; if (all(coords < uniforms.outShape)) { - let xRCCorner = coords.yz * vec2(uniforms.stride); + let xRCCorner = coords.yz * uniforms.stride; let xRCorner = xRCCorner.x; let xCCorner = xRCCorner.y; diff --git a/tfjs-backend-webgpu/src/kernels/reduce_webgpu.ts b/tfjs-backend-webgpu/src/kernels/reduce_webgpu.ts index 4c8e67f1041..b9d75b62d61 100644 --- a/tfjs-backend-webgpu/src/kernels/reduce_webgpu.ts +++ b/tfjs-backend-webgpu/src/kernels/reduce_webgpu.ts @@ -30,7 +30,7 @@ export class ReduceProgram implements WebGPUProgram { workGroupSize: [number, number, number]; variableNames = ['x']; uniforms = 'int reduceSize;'; - uniformsWgsl = 'reduceSize : u32;'; + uniformsWgsl = 'reduceSize : i32;'; reduceType: 'max'|'mean'|'min'|'prod'|'sum'; inputShape: number[]; reductionFactor: number; @@ -186,10 +186,10 @@ export class ReduceProgram implements WebGPUProgram { `bestValue = ${initValue};` : ' '} var currentSize = WorkGroupSize; - for(; currentSize > 1u;) { + for(; currentSize > 1;) { workgroupBarrier(); - for (var w = 0u; w < ${this.reductionFactor}u; w = w + 1u) { - let i = localId.x * ${this.reductionFactor}u + w; + for (var w = 0; w < ${this.reductionFactor}; w = w + 1) { + let i = i32(localId.x) * ${this.reductionFactor} + w; if (i < currentSize) { let candidate = xBestValues[i]; ${reduceOp} @@ -197,11 +197,11 @@ export class ReduceProgram implements WebGPUProgram { } workgroupBarrier(); xBestValues[localId.x] = bestValue; - currentSize = DIV_CEIL(currentSize, ${this.reductionFactor}u); + currentSize = DIV_CEIL(currentSize, ${this.reductionFactor}); ${ this.reduceType === 'sum' || this.reduceType === 'mean' || this.reduceType === 'prod' ? - `if(currentSize > 1u) { bestValue = ${initValue}; }` : + `if(currentSize > 1) { bestValue = ${initValue}; }` : ''} } if (localId.x == 0u) { @@ -210,12 +210,12 @@ export class ReduceProgram implements WebGPUProgram { `; const userCode = ` - fn DIV_CEIL(a : u32, b : u32) -> u32 { - return ((a - 1u) / b + 1u); + fn DIV_CEIL(a : i32, b : i32) -> i32 { + return ((a - 1) / b + 1); } - let WorkGroupSize = ${this.workGroupSize[0]}u; + let WorkGroupSize = ${this.workGroupSize[0]}; ${reduceInSharedMemory ? sharedMemorySnippet : ''} - fn getOffset(globalId : vec3, index : u32) -> u32 { + fn getOffset(globalId : vec3, index : i32) -> i32 { let outputCoords = getOutputCoords(globalId, index); let offset = ${ this.outputShape.length === 1 ? @@ -229,14 +229,14 @@ export class ReduceProgram implements WebGPUProgram { var bestValue = ${initValue}; let Length = uniforms.reduceSize; let WorkPerThread = DIV_CEIL(Length, WorkGroupSize); - for (var w = 0u; w < WorkPerThread; w = w + 1u) { - let i = globalId.x * WorkPerThread + w; + for (var w = 0; w < WorkPerThread; w = w + 1) { + let i = i32(globalId.x) * WorkPerThread + w; if (i < Length) { let candidate = f32(x.numbers[offset + i]); ${reduceOp} } } - let flatOutputIndex = globalId.y; + let flatOutputIndex = i32(globalId.y); ${reduceInSharedMemory ? sharedMemoryReduceSnippet : outputSnippet} } `; diff --git a/tfjs-backend-webgpu/src/kernels/resize_bilinear_webgpu.ts b/tfjs-backend-webgpu/src/kernels/resize_bilinear_webgpu.ts index 12e47bdb8b6..072bdb50a9f 100644 --- a/tfjs-backend-webgpu/src/kernels/resize_bilinear_webgpu.ts +++ b/tfjs-backend-webgpu/src/kernels/resize_bilinear_webgpu.ts @@ -138,8 +138,8 @@ export class ResizeBilinearProgram implements WebGPUProgram { 'vec2(rc) * effectiveInputOverOutputRatioRC'}; // Compute the four integer indices. - let sourceFloorRC = vec2(sourceFracIndexRC); - let sourceCeilRC = vec2( + let sourceFloorRC = vec2(sourceFracIndexRC); + let sourceCeilRC = vec2( min(vec2(uniforms.xShape.yz) - vec2(1.0), ceil(sourceFracIndexRC))); let topLeft = getX(b, sourceFloorRC.x, sourceFloorRC.y, d); diff --git a/tfjs-backend-webgpu/src/kernels/resize_nearest_neighbor_webgpu.ts b/tfjs-backend-webgpu/src/kernels/resize_nearest_neighbor_webgpu.ts index 893ceeff211..b88a929de6b 100644 --- a/tfjs-backend-webgpu/src/kernels/resize_nearest_neighbor_webgpu.ts +++ b/tfjs-backend-webgpu/src/kernels/resize_nearest_neighbor_webgpu.ts @@ -147,7 +147,7 @@ export class ResizeNearestNeighborProgram implements WebGPUProgram { // Compute the coordinators of nearest neighbor point. let inputShapeRC = vec2(f32(uniforms.xShape.y), f32(uniforms.xShape.z)); - let sourceNearestRC = vec2( + let sourceNearestRC = vec2( min(inputShapeRC - 1.0, floor(sourceFracIndexRC + ${roundBase}))); let newValue = getX(b, sourceNearestRC.x, sourceNearestRC.y, d); diff --git a/tfjs-backend-webgpu/src/kernels/slice_webgpu.ts b/tfjs-backend-webgpu/src/kernels/slice_webgpu.ts index be554622002..fc01870b7fc 100644 --- a/tfjs-backend-webgpu/src/kernels/slice_webgpu.ts +++ b/tfjs-backend-webgpu/src/kernels/slice_webgpu.ts @@ -100,8 +100,7 @@ export class SliceProgram implements WebGPUProgram { const userCode = ` ${getMainHeaderStringWgsl()} { ${getGlobalIndexStringWgsl()} - if (index < uniforms.size) - { + if (index < uniforms.size) { var sourceLoc : ${dtype}; let coords = getOutputCoords(globalId, index); ${coordSum.join('\n')} diff --git a/tfjs-backend-webgpu/src/kernels/strided_slice_webgpu.ts b/tfjs-backend-webgpu/src/kernels/strided_slice_webgpu.ts index 96afe8c7d95..d928748c925 100644 --- a/tfjs-backend-webgpu/src/kernels/strided_slice_webgpu.ts +++ b/tfjs-backend-webgpu/src/kernels/strided_slice_webgpu.ts @@ -109,8 +109,7 @@ export class StridedSliceProgram implements WebGPUProgram { const userCode = ` ${getMainHeaderStringWgsl()} { ${getGlobalIndexStringWgsl()} - if (index < uniforms.size) - { + if (index < uniforms.size) { let coords = getOutputCoords(globalId, index); setOutputFlat(index, getX(${newCoords})); } diff --git a/tfjs-backend-webgpu/src/kernels/transform_webgpu.ts b/tfjs-backend-webgpu/src/kernels/transform_webgpu.ts index cec77813646..c19daa50f37 100644 --- a/tfjs-backend-webgpu/src/kernels/transform_webgpu.ts +++ b/tfjs-backend-webgpu/src/kernels/transform_webgpu.ts @@ -216,8 +216,8 @@ export class TransformProgram implements WebGPUProgram { fn readWithFillValue(batch : i32, coordY : i32, coordX : i32, channel : i32) -> f32 { var outputValue : f32; - if (0 <= coordY && coordY < i32(uniforms.imageShape[1]) && 0 <= coordX && coordX < i32(uniforms.imageShape[2])) { - outputValue = getImage(u32(batch), u32(coordY), u32(coordX), u32(channel)); + if (0 <= coordY && coordY < uniforms.imageShape[1] && 0 <= coordX && coordX < uniforms.imageShape[2]) { + outputValue = getImage(batch, coordY, coordX, channel); } else { outputValue = uniforms.fillValue; } @@ -235,14 +235,14 @@ export class TransformProgram implements WebGPUProgram { let channel = coords[3]; let xf = f32(x); let yf = f32(y); - let a1 = getTransforms(batch, 0u); - let a2 = getTransforms(batch, 1u); - let a3 = getTransforms(batch, 2u); - let b1 = getTransforms(batch, 3u); - let b2 = getTransforms(batch, 4u); - let b3 = getTransforms(batch, 5u); - let c1 = getTransforms(batch, 6u); - let c2 = getTransforms(batch, 7u); + let a1 = getTransforms(batch, 0); + let a2 = getTransforms(batch, 1); + let a3 = getTransforms(batch, 2); + let b1 = getTransforms(batch, 3); + let b2 = getTransforms(batch, 4); + let b3 = getTransforms(batch, 5); + let c1 = getTransforms(batch, 6); + let c2 = getTransforms(batch, 7); let projection = c1 * xf + c2 * yf + 1.0; if (projection == 0.0) { outputValue = uniforms.fillValue; @@ -255,21 +255,21 @@ export class TransformProgram implements WebGPUProgram { if (uniforms.interpolationModeId == 1) { let coordY = i32(round(mapY)); let coordX = i32(round(mapX)); - outputValue = readWithFillValue(i32(batch), coordY, coordX, - i32(channel)); + outputValue = readWithFillValue(batch, coordY, coordX, + channel); } else { let yFloor = floor(mapY); let xFloor = floor(mapX); let yCeil = yFloor + 1.0; let xCeil = xFloor + 1.0; let valueYFloor = (xCeil - mapX) * - readWithFillValue(i32(batch), i32(yFloor), i32(xFloor), i32(channel)) + + readWithFillValue(batch, i32(yFloor), i32(xFloor), channel) + (mapX - xFloor) * - readWithFillValue(i32(batch), i32(yFloor), i32(xCeil), i32(channel)); + readWithFillValue(batch, i32(yFloor), i32(xCeil), channel); let valueYCeil = (xCeil - mapX) * - readWithFillValue(i32(batch), i32(yCeil), i32(xFloor), i32(channel)) + + readWithFillValue(batch, i32(yCeil), i32(xFloor), channel) + (mapX - xFloor) * - readWithFillValue(i32(batch), i32(yCeil), i32(xCeil), i32(channel)); + readWithFillValue(batch, i32(yCeil), i32(xCeil), channel); outputValue = (yCeil - mapY) * valueYFloor + (mapY - yFloor) * valueYCeil; } diff --git a/tfjs-backend-webgpu/src/kernels/transpose_shared_webgpu.ts b/tfjs-backend-webgpu/src/kernels/transpose_shared_webgpu.ts index a35a6f9598a..5198e5c23af 100644 --- a/tfjs-backend-webgpu/src/kernels/transpose_shared_webgpu.ts +++ b/tfjs-backend-webgpu/src/kernels/transpose_shared_webgpu.ts @@ -73,7 +73,7 @@ export class TransposeSharedProgram implements WebGPUProgram { getUserCodeWgsl(): string { const userCode = ` - let TILE_DIM = ${this.workGroupSize[0]}u; + let TILE_DIM = ${this.workGroupSize[0]}; var tile : array, ${ this.workGroupSize[0]}>; ${getMainHeaderStringWgsl()} { @@ -81,8 +81,8 @@ export class TransposeSharedProgram implements WebGPUProgram { let workGroupID = (globalId - localId)/vec3(${ this.workGroupSize[0]}u, ${this.workGroupSize[1]}u, ${ this.workGroupSize[2]}u); - var x = workGroupID.x * TILE_DIM + localId.x; - var y = workGroupID.y * TILE_DIM + localId.y; + var x = i32(workGroupID.x) * TILE_DIM + i32(localId.x); + var y = i32(workGroupID.y) * TILE_DIM + i32(localId.y); let width = uniforms.outShape[0]; let height = uniforms.outShape[1]; if (x < width && y < height) { @@ -91,8 +91,8 @@ export class TransposeSharedProgram implements WebGPUProgram { } workgroupBarrier(); - x = workGroupID.y * TILE_DIM + localId.x; - y = workGroupID.x * TILE_DIM + localId.y; + x = i32(workGroupID.y) * TILE_DIM + i32(localId.x); + y = i32(workGroupID.x) * TILE_DIM + i32(localId.y); if (x < height && y < width) { setOutputFlat((y * height + x), tile[localId.x] [localId.y]); diff --git a/tfjs-backend-webgpu/src/kernels/transpose_webgpu.ts b/tfjs-backend-webgpu/src/kernels/transpose_webgpu.ts index 44a874e494c..3037038ace3 100644 --- a/tfjs-backend-webgpu/src/kernels/transpose_webgpu.ts +++ b/tfjs-backend-webgpu/src/kernels/transpose_webgpu.ts @@ -80,8 +80,8 @@ export class TransposeProgram implements WebGPUProgram { ${getMainHeaderStringWgsl()} { ${getGlobalIndexStringWgsl()} - for(var i = 0u; i < ${this.workPerThread}u; i = i + 1u) { - let flatIndex = index * ${this.workPerThread}u + i; + for(var i = 0; i < ${this.workPerThread}; i = i + 1) { + let flatIndex = index * ${this.workPerThread} + i; if(flatIndex < uniforms.size) { let resRC = getCoordsFromFlatIndex(flatIndex); setOutputFlat(flatIndex, A.numbers[getFlatIndex${ diff --git a/tfjs-backend-webgpu/src/shader_preprocessor_wgsl.ts b/tfjs-backend-webgpu/src/shader_preprocessor_wgsl.ts index 7463573d685..a711f2709a2 100644 --- a/tfjs-backend-webgpu/src/shader_preprocessor_wgsl.ts +++ b/tfjs-backend-webgpu/src/shader_preprocessor_wgsl.ts @@ -20,13 +20,13 @@ import {symbolicallyComputeStrides} from './shader_util'; export function getCoordsDataTypeWgsl(rank: number): string { if (rank <= 1) { - return 'u32'; + return 'i32'; } else if (rank === 2) { - return 'vec2'; + return `vec2`; } else if (rank === 3) { - return 'vec3'; + return `vec3`; } else if (rank === 4) { - return 'vec4'; + return `vec4`; } else { throw Error(`GPU for rank ${rank} is not yet supported`); } @@ -100,9 +100,9 @@ export function makeShader( numbers: array<${mapToTypesWgsl(outputData.dtype, program.isVec4)}>; }; [[block]] struct Uniform { - size : u32; - numChannels : u32; - outShapeStrides : vec2; + size : i32; + numChannels : i32; + outShapeStrides : vec2; dispatchSize : vec3; }; @@ -132,7 +132,7 @@ export function makeShader( outShapeStrides: ${getCoordsDataTypeWgsl(stridesLength)}; `; if (program.size != null) { - uniformDeclaration += 'size : u32; '; + uniformDeclaration += 'size : i32; '; } uniformDeclaration += 'dispatchSize : vec3; '; if (program.uniformsWgsl) { @@ -245,49 +245,52 @@ const SHADER_PREFIX = ` } // Checks whether coordinates lie within the bounds of the shape. - fn coordsInBounds4D(coord : vec4, shape : vec4) -> bool { - return all(coord < shape); + fn coordsInBounds4D(coord : vec4, shape : vec4) -> bool { + return all(coord >= vec4(0)) && + all(coord < shape); } - fn coordsInBounds3D(coord : vec3, shape : vec3) -> bool { - return all(coord < shape); + fn coordsInBounds3D(coord : vec3, shape : vec3) -> bool { + return all(coord >= vec3(0)) && + all(coord < shape); } - fn coordsInBounds2D(coord : vec2, shape : vec2) -> bool { - return all(coord < shape); + fn coordsInBounds2D(coord : vec2, shape : vec2) -> bool { + return all(coord >= vec2(0)) && + all(coord < shape); } `; const SAMPLING_SNIPPETS = ` - fn getFlatIndex1D(coord : u32, shape : u32) -> u32 { + fn getFlatIndex1D(coord : i32, shape : i32) -> i32 { return coord; } - fn getFlatIndex2D(coords : vec2, shape : vec2) -> u32 { - return u32(dot(vec2(coords), vec2(f32(shape.y), 1.0))); + fn getFlatIndex2D(coords : vec2, shape : vec2) -> i32 { + return i32(dot(vec2(coords), vec2(f32(shape.y), 1.0))); } - fn getFlatIndex3D(coords : vec3, shape : vec3) -> u32 { - return u32(dot(vec3(coords), vec3(f32(shape.y) * f32(shape.z), f32(shape.z), 1.0))); + fn getFlatIndex3D(coords : vec3, shape : vec3) -> i32 { + return i32(dot(vec3(coords), vec3(f32(shape.y) * f32(shape.z), f32(shape.z), 1.0))); } - fn getFlatIndex4D(coords : vec4, shape : vec4) -> u32 { - return u32(dot(vec4(coords), vec4( + fn getFlatIndex4D(coords : vec4, shape : vec4) -> i32 { + return i32(dot(vec4(coords), vec4( f32(shape.y) * f32(shape.z) * f32(shape.w), f32(shape.z) * f32(shape.w), f32(shape.w), 1.0))); } // Only used when the y/z dimension of workgroup size is 1. - fn getGlobalIndex(globalId : vec3, localId : vec3) -> u32 { + fn getGlobalIndex(globalId : vec3, localId : vec3) -> i32 { if (uniforms.dispatchSize.y == 1u && uniforms.dispatchSize.z == 1u) { - return globalId.x; + return i32(globalId.x); } let localInvocationIndex = localId.z * workGroupSizeX * workGroupSizeY + localId.y * workGroupSizeX + localId.x; let workGroupID = (globalId - localId)/vec3( workGroupSizeX, workGroupSizeY, workGroupSizeZ); - return (workGroupID.z * uniforms.dispatchSize.x * uniforms.dispatchSize.y + + return i32((workGroupID.z * uniforms.dispatchSize.x * uniforms.dispatchSize.y + workGroupID.y * uniforms.dispatchSize.x + workGroupID.x) * (workGroupSizeX * workGroupSizeY * workGroupSizeZ) + - localInvocationIndex; + localInvocationIndex); } `; @@ -297,17 +300,17 @@ function getSetOutputSnippet( const wgslType = mapToTypesWgsl(outBufferType, isVec4); let snippet; if (isVec4) { - snippet = `fn setOutputFlat(flatIndex : u32, value : vec4) { + snippet = `fn setOutputFlat(flatIndex : i32, value : vec4) { result.numbers[flatIndex] = ${wgslType}(value); } - fn setOutputFlatI32(flatIndex : u32, value : vec4) { + fn setOutputFlatI32(flatIndex : i32, value : vec4) { result.numbers[flatIndex] = ${wgslType}(value); }`; } else { - snippet = `fn setOutputFlat(flatIndex : u32, value : f32) { + snippet = `fn setOutputFlat(flatIndex : i32, value : f32) { result.numbers[flatIndex] = ${wgslType}(value); } - fn setOutputFlatI32(flatIndex : u32, value : i32) { + fn setOutputFlatI32(flatIndex : i32, value : i32) { result.numbers[flatIndex] = ${wgslType}(value); }`; } @@ -316,22 +319,22 @@ function getSetOutputSnippet( switch (outRank) { case 2: snippet += ` - fn getOutputFlatIndex(coords : vec2) -> u32 { - return u32(dot(vec2(coords), vec2(f32(uniforms.outShapeStrides), 1.0))); + fn getOutputFlatIndex(coords : vec2) -> i32 { + return i32(dot(vec2(coords), vec2(f32(uniforms.outShapeStrides), 1.0))); } `; break; case 3: snippet += ` - fn getOutputFlatIndex(coords : vec3) -> u32 { - return u32(dot(vec3(coords), vec3(f32(uniforms.outShapeStrides.x), f32(uniforms.outShapeStrides.y), 1.0))); + fn getOutputFlatIndex(coords : vec3) -> i32 { + return i32(dot(vec3(coords), vec3(f32(uniforms.outShapeStrides.x), f32(uniforms.outShapeStrides.y), 1.0))); } `; break; case 4: snippet += ` - fn getOutputFlatIndex(coords : vec4) -> u32 { - return u32(dot(vec4(coords), vec4( + fn getOutputFlatIndex(coords : vec4) -> i32 { + return i32(dot(vec4(coords), vec4( f32(uniforms.outShapeStrides.x), f32(uniforms.outShapeStrides.y), f32(uniforms.outShapeStrides.z), 1.0))); } `; @@ -346,23 +349,23 @@ function getSetOutputSnippet( if (isVec4) { snippet += ` fn setOutput(${ - dims.map(d => `${d} : u32`).join(', ')}, value : vec4) { + dims.map(d => `${d} : i32`).join(', ')}, value : vec4) { let flatIndex = getOutputFlatIndex(${type}(${dims.join(', ')})); - setOutputFlat(flatIndex / 4u, value); + setOutputFlat(flatIndex / 4, value); } fn setOutputVectorI32(${ - dims.map(d => `${d} : u32`).join(', ')}, value : vec4) { + dims.map(d => `${d} : i32`).join(', ')}, value : vec4) { let flatIndex = getOutputFlatIndex(${type}(${dims.join(', ')})); - setOutputFlatI32(flatIndex / 4u, value); + setOutputFlatI32(flatIndex / 4, value); } `; } else { snippet += ` - fn setOutput(${dims.map(d => `${d} : u32`).join(', ')}, value : f32) { + fn setOutput(${dims.map(d => `${d} : i32`).join(', ')}, value : f32) { let flatIndex = getOutputFlatIndex(${type}(${dims.join(', ')})); setOutputFlat(flatIndex, value); } - fn setOutputI32(${dims.map(d => `${d} : u32`).join(', ')}, value : i32) { + fn setOutputI32(${dims.map(d => `${d} : i32`).join(', ')}, value : i32) { let flatIndex = getOutputFlatIndex(${type}(${dims.join(', ')})); setOutputFlatI32(flatIndex, value); } @@ -393,7 +396,7 @@ function getSamplerFromInInfo(inInfo: InputInfo, isVec4: boolean): string { const type = getCoordsDataTypeWgsl(rank); const funcName = 'get' + texName.charAt(0).toUpperCase() + texName.slice(1); const dims = ['d0', 'd1', 'd2', 'd3'].slice(0, rank); - const inputs = dims.map(d => `${d} : u32`).join(', '); + const inputs = dims.map(d => `${d} : i32`).join(', '); if (rank < 1) { if (isVec4) { @@ -423,7 +426,7 @@ function getSamplerFromInInfo(inInfo: InputInfo, isVec4: boolean): string { fn ${funcName}(${inputs}) -> vec4 { return vec4(${texName}.numbers[getFlatIndex${rankStr}(${type}(${ dims.join(',')}), - ${shapeStr}) / 4u]); + ${shapeStr}) / 4]); } `; } @@ -457,18 +460,18 @@ export function getSamplerAtOutputCoords( if (isVec4) { return ` fn ${ - funcName}ByGlobalId(globalId : vec3, globalIndex : u32) -> vec4 { + funcName}ByGlobalId(globalId : vec3, globalIndex : i32) -> vec4 { return vec4(${texName}.numbers[globalIndex]); } fn ${funcName}ByCoords(coords : ${type}) -> vec4 { return vec4(${texName}.numbers[${ - outRank > 1 ? 'getOutputFlatIndex(coords)' : 'coords'} / 4u]); + outRank > 1 ? 'getOutputFlatIndex(coords)' : 'coords'} / 4]); } `; } else { return ` - fn ${funcName}ByGlobalId(globalId : vec3, globalIndex : u32) -> f32 { + fn ${funcName}ByGlobalId(globalId : vec3, globalIndex : i32) -> f32 { return f32(${texName}.numbers[globalIndex]); } @@ -489,7 +492,7 @@ export function getSamplerAtOutputCoords( if (isVec4) { return ` fn ${ - funcName}ByGlobalId(globalId : vec3, globalIndex : u32) -> vec4 { + funcName}ByGlobalId(globalId : vec3, globalIndex : i32) -> vec4 { return get${texFuncSnippet}(); } @@ -499,7 +502,7 @@ export function getSamplerAtOutputCoords( `; } return ` - fn ${funcName}ByGlobalId(globalId : vec3, globalIndex : u32) -> f32{ + fn ${funcName}ByGlobalId(globalId : vec3, globalIndex : i32) -> f32{ return get${texFuncSnippet}(); } @@ -509,10 +512,10 @@ export function getSamplerAtOutputCoords( `; } else { if (outRank < 2 && broadcastDims.length >= 1) { - coordsSnippet = 'coords = 0u;'; + coordsSnippet = 'coords = 0;'; } else { coordsSnippet = - broadcastDims.map(d => `coords[${d + rankDiff}u] = 0u;`).join('\n'); + broadcastDims.map(d => `coords[${d + rankDiff}] = 0;`).join('\n'); } } @@ -523,7 +526,7 @@ export function getSamplerAtOutputCoords( if (outRank > 1) { const coordsType = getCoordsDataTypeWgsl(inRank); const coordsValues = - inInfo.shape.map((s, i) => `coords[${i + rankDiff}u]`).join(', '); + inInfo.shape.map((s, i) => `coords[${i + rankDiff}]`).join(', '); unpackedCoordsSnippet = `${coordsType}(${coordsValues})`; } else { unpackedCoordsSnippet = 'coords'; @@ -536,24 +539,24 @@ export function getSamplerAtOutputCoords( if (isVec4) { return ` fn ${ - funcName}ByGlobalId(globalId : vec3, globalIndex : u32) -> vec4 { + funcName}ByGlobalId(globalId : vec3, globalIndex : i32) -> vec4 { var coords = getOutputCoords(globalId, globalIndex); ${coordsSnippet} return ${texName}.numbers[getFlatIndex${rankStr}(${ - unpackedCoordsSnippet}, ${shapeStr}) / 4u]; + unpackedCoordsSnippet}, ${shapeStr}) / 4]; } fn ${funcName}ByCoords(coordsIn : ${type}) -> vec4 { var coords = coordsIn; ${coordsSnippet} return ${texName}.numbers[getFlatIndex${rankStr}(${ - unpackedCoordsSnippet}, ${shapeStr}) / 4u]; + unpackedCoordsSnippet}, ${shapeStr}) / 4]; } `; } return ` - fn ${funcName}ByGlobalId(globalId : vec3, globalIndex : u32) -> f32 { + fn ${funcName}ByGlobalId(globalId : vec3, globalIndex : i32) -> f32 { var coords = getOutputCoords(globalId, globalIndex); ${coordsSnippet} return f32(${texName}.numbers[getFlatIndex${rankStr}(${ @@ -583,9 +586,9 @@ export function generateGetOutputCoords( if (x.length === outRank) { const dtype = getCoordsDataTypeWgsl(outRank); const snippet = - `fn getOutputCoords(globalId : vec3, globalIndex : u32) -> ${ + `fn getOutputCoords(globalId : vec3, globalIndex : i32) -> ${ dtype}{ - return getCoordsFromFlatIndex(u32(globalIndex)); + return getCoordsFromFlatIndex(i32(globalIndex)); } `; return [snippet, outRank]; @@ -606,10 +609,10 @@ export function generateGetOutputCoords( rank += arr.length; if (arr.length === 1) { - gatherDimensionsStr += `let d${arr[0]} = globalId[${i}];`; + gatherDimensionsStr += `let d${arr[0]} = i32(globalId[${i}]);`; } else { const strides = symbolicallyComputeStrides(arr, 'uniforms.outShape'); - gatherDimensionsStr += `var index${i} = globalId[${i}];`; + gatherDimensionsStr += `var index${i} = i32(globalId[${i}]);`; for (let j = 0; j < strides.length; j++) { gatherDimensionsStr += `let d${arr[j]} = index${i} / ${strides[j]};`; @@ -631,7 +634,7 @@ export function generateGetOutputCoords( const dtype = getCoordsDataTypeWgsl(rank); let snippet = - `fn getOutputCoords(globalId : vec3, globalIndex : u32) -> ${dtype} { + `fn getOutputCoords(globalId : vec3, globalIndex : i32) -> ${dtype} { ${gatherDimensionsStr} `; if (dimensions.length === 0) { @@ -652,7 +655,7 @@ function generateGetCoordsFromFlatIndex(shape: number[]): string { const rank = shape.length; if (rank <= 1) { - return `fn getCoordsFromFlatIndex(index : u32) -> u32 { return index; }`; + return `fn getCoordsFromFlatIndex(index : i32) -> i32 { return index; }`; } const strides = util.computeStrides(shape); @@ -664,9 +667,9 @@ function generateGetCoordsFromFlatIndex(shape: number[]): string { } if (strides.length === 1) { - return ` fn getCoordsFromFlatIndex(index : u32) -> vec2 { + return ` fn getCoordsFromFlatIndex(index : i32) -> vec2 { let d0 = index / uniforms.outShapeStrides; let d1 = index - d0 * uniforms.outShapeStrides; - return vec2(d0, d1); + return vec2(d0, d1); }`; } const snippet = 'var index2 = index;' + @@ -684,7 +687,7 @@ function generateGetCoordsFromFlatIndex(shape: number[]): string { .join(''); return ` - fn getCoordsFromFlatIndex(index : u32) -> ${dtype} { + fn getCoordsFromFlatIndex(index : i32) -> ${dtype} { ${snippet} return ${dtype}(${coords.join(',')}); }