Bug 226953 - Tensorflow.js Broken in Safari 15
Summary: Tensorflow.js Broken in Safari 15
Status: RESOLVED FIXED
Alias: None
Product: WebKit
Classification: Unclassified
Component: WebGL (show other bugs)
Version: Other
Hardware: iPhone / iPad Other
: P2 Major
Assignee: Kyle Piddington
URL:
Keywords: InRadar
Depends on:
Blocks:
 
Reported: 2021-06-12 08:40 PDT by M
Modified: 2021-08-24 03:14 PDT (History)
8 users (show)

See Also:


Attachments
Patch (1.45 KB, patch)
2021-06-14 15:21 PDT, Kyle Piddington
no flags Details | Formatted Diff | Diff
Patch (2.58 KB, patch)
2021-06-14 16:28 PDT, Kyle Piddington
no flags Details | Formatted Diff | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description M 2021-06-12 08:40:56 PDT
OVERVIEW:
Getting a consistent vertex/shader error message across every Tensorflow.js demo on the developer release of iOS 15.0 (using Safari 15). These TFJS applications and and models currently run correctly in iOS 14.6 or 14.7.

ERROR LOG:
Internal error compiling shader with Metal backend.
Please submit this shader, or website as a bug to https://bugs.webkit.org
Error: Failed to link vertex and fragment shaders.

STEPS TO REPRODUCE:
A few websites/demos where you can reproduce the error when running the applications in iOS 15 are:
https://emojiscavengerhunt.withgoogle.com/
https://magenta.tensorflow.org/demos/performance_rnn/index.html
https://storage.googleapis.com/tfjs-examples/addition-rnn/dist/index.html

If more code samples are needed, they can also be accessed here: 
https://www.tensorflow.org/js/demos

ACTUAL RESULTS:
The demos/programs error out as the models cannot be processed.

EXPECTED BEHAVIOR:
The applications above all run well in iOS 14.6 and 14.7 on my iPhone X.

HARDWARE:
The error occurs in Safari 15.0 in iOS 15 on my iPhone XS.
Comment 1 Radar WebKit Bug Importer 2021-06-12 14:57:29 PDT
<rdar://problem/79246230>
Comment 2 Kenneth Russell 2021-06-14 14:51:15 PDT
Kyle, would you be able to triage this? TensorFlow.js is a major WebGL use case so investigating this regression is urgent.
Comment 3 Kyle Piddington 2021-06-14 15:10:40 PDT
From the GLSL:
2021-06-14 15:07:04.453 MiniBrowser[44123:3425024] // GLSL
//
// #version 300 es
//     precision highp float;
//     precision highp int;
//     precision highp sampler2D;
//     in vec2 resultUV;
//     out vec4 outputColor;
//     const vec2 halfCR = vec2(0.5, 0.5);
// 
//     struct ivec5
//     {
//       int x;
//       int y;
//       int z;
//       int w;
//       int u;
//     };
// 
//     struct ivec6
//     {
//       int x;
//       int y;
//       int z;
//       int w;
//       int u;
//       int v;
//     };
// 
//     
//       bool isNaN(float val) {
//         return (val < 1.0 || 0.0 < val || val == 0.0) ? false : true;
//       }
// 
//       bvec4 isNaN(vec4 val) {
//         return bvec4(
//           isNaN(val.x),
//           isNaN(val.y),
//           isNaN(val.z),
//           isNaN(val.w)
//         );
//       }
// 
//       bool hasNaN(vec4 values) {
//         return any(bvec4(
//           isNaN(values.x),
//           isNaN(values.y),
//           isNaN(values.z),
//           isNaN(values.w)
//         ));
//       }
//     
// 
//     float getNaN(vec4 values) {
//       return dot(vec4(1), values);
//     }
// 
//     
//       #define round(value) newRound(value)
//       int newRound(float value) {
//         return int(floor(value + 0.5));
//       }
// 
//       ivec4 newRound(vec4 value) {
//         return ivec4(floor(value + vec4(0.5)));
//       }
//     
// 
//     int imod(int x, int y) {
//       return x - y * (x / y);
//     }
// 
//     //Based on the work of Dave Hoskins
//     //https://www.shadertoy.com/view/4djSRW
//     #define HASHSCALE1 443.8975
//     float random(float seed){
//       vec2 p = resultUV * seed;
//       vec3 p3  = fract(vec3(p.xyx) * HASHSCALE1);
//       p3 += dot(p3, p3.yzx + 19.19);
//       return fract((p3.x + p3.y) * p3.z);
//     }
// 
//     
// vec2 uvFromFlat(int texNumR, int texNumC, int index) {
//   int texR = index / texNumC;
//   int texC = index - texR * texNumC;
//   return (vec2(texC, texR) + halfCR) / vec2(texNumC, texNumR);
// }
// vec2 packedUVfrom1D(int texNumR, int texNumC, int index) {
//   int texelIndex = index / 2;
//   int texR = texelIndex / texNumC;
//   int texC = texelIndex - texR * texNumC;
//   return (vec2(texC, texR) + halfCR) / vec2(texNumC, texNumR);
// }
// 
//     
// vec2 packedUVfrom2D(int texelsInLogicalRow, int texNumR,
//   int texNumC, int row, int col) {
//   int texelIndex = (row / 2) * texelsInLogicalRow + (col / 2);
//   int texR = texelIndex / texNumC;
//   int texC = texelIndex - texR * texNumC;
//   return (vec2(texC, texR) + halfCR) / vec2(texNumC, texNumR);
// }
// 
//     
// vec2 packedUVfrom3D(int texNumR, int texNumC,
//     int texelsInBatch, int texelsInLogicalRow, int b,
//     int row, int col) {
//   int index = b * texelsInBatch + (row / 2) * texelsInLogicalRow + (col / 2);
//   int texR = index / texNumC;
//   int texC = index - texR * texNumC;
//   return (vec2(texC, texR) + halfCR) / vec2(texNumC, texNumR);
// }
// 
//   
//   float getChannel(vec4 frag, vec2 innerDims) {
//     vec2 modCoord = mod(innerDims, 2.);
//     return modCoord.x == 0. ?
//       (modCoord.y == 0. ? frag.r : frag.g) :
//       (modCoord.y == 0. ? frag.b : frag.a);
//   }
//   float getChannel(vec4 frag, int dim) {
//     float modCoord = mod(float(dim), 2.);
//     return modCoord == 0. ? frag.r : frag.g;
//   }
// 
// 
//     float sampleTexture(sampler2D textureSampler, vec2 uv) {
//       return texture(textureSampler, uv).r;
//     }
//   
// 
//     void setOutput(vec4 val) {
//       outputColor = val;
//     }
//   
// uniform sampler2D A;
// uniform int offsetA;
// 
//     ivec2 getOutputCoords() {
//       ivec2 resTexRC = ivec2(resultUV.yx *
//                              vec2(64, 2));
// 
//       int index = resTexRC.x * 2 + resTexRC.y;
//       int r = 2 * (index / 2);
//       int c = imod(index, 2) * 2;
// 
//       return ivec2(r, c);
//     }
//   
// 
//     vec4 getA(int row, int col) {
//       vec2 uv = packedUVfrom2D(2, 64, 2, row, col);
//       return texture(A, uv);
//     }
//   
//     vec4 getAAtOutCoords() {
//       ivec2 coords = getOutputCoords();
//       
//       vec4 outputValue = getA(coords.x, coords.y);
//       return outputValue;
//     }
//   
// 
//       uniform float NAN;
//       vec4 unaryOperation(vec4 x) {
//         
//   vec4 result = log(x);
//   vec4 isNaN = vec4(lessThan(x, vec4(0.0)));
//   result.r = isNaN.r == 1.0 ? NAN : result.r;
//   result.g = isNaN.g == 1.0 ? NAN : result.g;
//   result.b = isNaN.b == 1.0 ? NAN : result.b;
//   result.a = isNaN.a == 1.0 ? NAN : result.a;
// 
//   return result;
// 
//       }
// 
//       void main() {
//         vec4 x = getAAtOutCoords();
//         vec4 y = unaryOperation(x);
// 
//         setOutput(y);
//       }
//     

Our issue is translating 
//       uniform float NAN;

NAN in this case is a reserved keyword.
Comment 4 Kyle Piddington 2021-06-14 15:21:12 PDT
Created attachment 431370 [details]
Patch
Comment 5 Kenneth Russell 2021-06-14 15:22:03 PDT
Comment on attachment 431370 [details]
Patch

Great! r+
Comment 6 EWS Watchlist 2021-06-14 15:22:20 PDT
Note that there are important steps to take when updating ANGLE. See https://trac.webkit.org/wiki/UpdatingANGLE
Comment 7 Kyle Piddington 2021-06-14 16:28:30 PDT
Created attachment 431383 [details]
Patch
Comment 8 Kenneth Russell 2021-06-14 16:50:09 PDT
Comment on attachment 431383 [details]
Patch

Infinity support looks good. r+
Comment 9 Kyle Piddington 2021-06-15 13:55:11 PDT
Comment on attachment 431383 [details]
Patch

Test failure seems unrelated.
Comment 10 EWS 2021-06-15 14:02:59 PDT
Committed r278898 (238839@main): <https://commits.webkit.org/238839@main>

All reviewed patches have been landed. Closing bug and clearing flags on attachment 431383 [details].
Comment 11 M 2021-06-29 13:23:08 PDT
I just checked the examples (and my app) against the new iOS15 Beta 2 and this bug still exists for the Tensorflow.js examples. 

Was the conclusion that Tensorflow.js needs to make changes to support Safari in iOS15 or was this patch not included in the new release? Just wanted to make sure I understood and can ping the TFJS team on Github if needed.
Comment 12 M 2021-06-30 07:57:45 PDT
(In reply to Kenneth Russell from comment #2)
> Kyle, would you be able to triage this? TensorFlow.js is a major WebGL use
> case so investigating this regression is urgent.

Hey Kenneth -- I just wanted to ping you on this since I noticed this error/bug is still present in Safari/Webkit in the new iOS15 Beta 2. I wasn't sure if I should change the status as I'm not on the WebKit team and don't have much experience with Radar. Is this now in the TFJS team's hands or can it get a second look here?
Comment 13 Jon Lee 2021-06-30 09:50:43 PDT
The fix did not make it into beta 2. It likely will make it into the next one.