kyamagu / skia-python

Python binding to Skia Graphics Library
https://kyamagu.github.io/skia-python/
BSD 3-Clause "New" or "Revised" License
245 stars 43 forks source link

"Shader Compilation Error" #246

Closed pavpanchekha closed 6 months ago

pavpanchekha commented 6 months ago

I get the following error when running a complex Skia application:

Shader Compilation Error
Shader compilation error
------------------------
   1    #version 110
   2    
   3    
   4    float _determinant2(mat2 m) {
   5    return m[0].x*m[1].y - m[0].y*m[1].x;
   6    }
   7    const float PI = 3.14159274;
   8    const float PRECISION = 4.0;
   9    const float NUM_TOTAL_EDGES = 16383.0;
  10    uniform vec4 sk_RTAdjust;
  11    uniform vec3 utessControlArgs_S0;
  12    uniform vec4 uaffineMatrix_S0;
  13    uniform vec2 utranslate_S0;
  14    attribute vec4 pts01Attr;
  15    attribute vec4 pts23Attr;
  16    attribute vec2 argsAttr;
  17    attribute float curveTypeAttr;
  18    vec2 robust_normalize_diff_f2f2f2(vec2 a, vec2 b) {
  19        vec2 diff = a - b;
  20        if (diff == vec2(0.0)) {
  21            return vec2(0.0);
  22        } else {
  23            float invMag = 1.0 / max(abs(diff.x), abs(diff.y));
  24            return normalize(invMag * diff);
  25        }
  26    }
  27    vec2 unchecked_mix_f2f2f2f(vec2 a, vec2 b, float T) {
  28        return ((b - a) * (vec2(T)) + (a));
  29    }
  30    float wangs_formula_max_fdiff_p2_ff2f2f2f2f22(vec2 p0, vec2 p1, vec2 p2, vec2 p3, mat2 matrix) {
  31        vec2 d0 = matrix * (((vec2(-2.0)) * (p1) + (p2)) + p0);
  32        vec2 d1 = matrix * (((vec2(-2.0)) * (p2) + (p3)) + p1);
  33        return max(dot(d0, d0), dot(d1, d1));
  34    }
  35    float wangs_formula_conic_p2_fff2f2f2f(float _precision_, vec2 p0, vec2 p1, vec2 p2, float w) {
  36        vec2 C = (min(min(p0, p1), p2) + max(max(p0, p1), p2)) * 0.5;
  37        p0 -= C;
  38        p1 -= C;
  39        p2 -= C;
  40        float m = sqrt(max(max(dot(p0, p0), dot(p1, p1)), dot(p2, p2)));
  41        vec2 dp = ((vec2(-2.0 * w)) * (p1) + (p0)) + p2;
  42        float dw = abs(((-2.0) * (w) + (2.0)));
  43        float rp_minus_1 = max(0.0, ((m) * (_precision_) + (-1.0)));
  44        float numer = length(dp) * _precision_ + rp_minus_1 * dw;
  45        float denom = 4.0 * min(w, 1.0);
  46        return numer / denom;
  47    }
  48    void main() {
  49        float NUM_RADIAL_SEGMENTS_PER_RADIAN = utessControlArgs_S0.x;
  50        float JOIN_TYPE = utessControlArgs_S0.y;
  51        float STROKE_RADIUS = utessControlArgs_S0.z;
  52        mat2 AFFINE_MATRIX = mat2(uaffineMatrix_S0.xy, uaffineMatrix_S0.zw);
  53        vec2 TRANSLATE = utranslate_S0;
  54        vec2 p0 = pts01Attr.xy;
  55        vec2 p1 = pts01Attr.zw;
  56        vec2 p2 = pts23Attr.xy;
  57        vec2 p3 = pts23Attr.zw;
  58        vec2 lastControlPoint = argsAttr;
  59        float w = -1.0;
  60        if (curveTypeAttr != 0.0) {
  61            w = p3.x;
  62            p3 = p2;
  63        }
  64        float numParametricSegments;
  65        if (w < 0.0) {
  66            if (p0 == p1 && p2 == p3) {
  67                numParametricSegments = 1.0;
  68            } else {
  69                float _0_m = wangs_formula_max_fdiff_p2_ff2f2f2f2f22(p0, p1, p2, p3, AFFINE_MATRIX);
  70                numParametricSegments = max(ceil(sqrt(3.0 * sqrt(_0_m))), 1.0);
  71            }
  72        } else {
  73            float _1_n2 = wangs_formula_conic_p2_fff2f2f2f(PRECISION, AFFINE_MATRIX * p0, AFFINE_MATRIX * p1, AFFINE_MATRIX * p2, w);
  74            numParametricSegments = max(ceil(sqrt(_1_n2)), 1.0);
  75        }
  76        vec2 tan0 = robust_normalize_diff_f2f2f2(p0 == p1 ? (p1 == p2 ? p3 : p2) : p1, p0);
  77        vec2 tan1 = robust_normalize_diff_f2f2f2(p3, p3 == p2 ? (p2 == p1 ? p0 : p1) : p2);
  78        if (tan0 == vec2(0.0)) {
  79            tan0 = vec2(1.0, 0.0);
  80            tan1 = vec2(-1.0, 0.0);
  81        }
  82        float edgeID = float(gl_VertexID >> 1);
  83        if ((gl_VertexID & 1) != 0) {
  84            edgeID = -edgeID;
  85        }
  86        float numEdgesInJoin = 4.0;
  87        float turn = _determinant2(mat2(p2 - p0, p3 - p1));
  88        float combinedEdgeID = abs(edgeID) - numEdgesInJoin;
  89        if (combinedEdgeID < 0.0) {
  90            tan1 = tan0;
  91            if (lastControlPoint != p0) {
  92                tan0 = robust_normalize_diff_f2f2f2(p0, lastControlPoint);
  93            }
  94            turn = _determinant2(mat2(tan0, tan1));
  95        }
  96        float cosTheta = clamp(dot(tan0, tan1), -1.0, 1.0);
  97        float rotation = acos(cosTheta);
  98        if (turn < 0.0) {
  99            rotation = -rotation;
 100        }
 101        float numRadialSegments;
 102        float strokeOutset = sign(edgeID);
 103        if (combinedEdgeID < 0.0) {
 104            numRadialSegments = numEdgesInJoin - 2.0;
 105            numParametricSegments = 1.0;
 106            p3 = (p2 = (p1 = p0));
 107            combinedEdgeID += numRadialSegments + 1.0;
 108            float sinEpsilon = 0.01;
 109            bool tangentsNearlyParallel = abs(turn) * (1.0 / sqrt(dot(tan0, tan0) * dot(tan1, tan1))) < sinEpsilon;
 110            if (!tangentsNearlyParallel || dot(tan0, tan1) < 0.0) {
 111                if (combinedEdgeID >= 0.0) {
 112                    strokeOutset = turn < 0.0 ? min(strokeOutset, 0.0) : max(strokeOutset, 0.0);
 113                }
 114            }
 115            combinedEdgeID = max(combinedEdgeID, 0.0);
 116        } else {
 117            float maxCombinedSegments = (NUM_TOTAL_EDGES - numEdgesInJoin) - 1.0;
 118            numRadialSegments = max(ceil(abs(rotation) * NUM_RADIAL_SEGMENTS_PER_RADIAN), 1.0);
 119            numRadialSegments = min(numRadialSegments, maxCombinedSegments);
 120            numParametricSegments = min(numParametricSegments, (maxCombinedSegments - numRadialSegments) + 1.0);
 121        }
 122        float radsPerSegment = rotation / numRadialSegments;
 123        float numCombinedSegments = (numParametricSegments + numRadialSegments) - 1.0;
 124        bool isFinalEdge = combinedEdgeID >= numCombinedSegments;
 125        if (combinedEdgeID > numCombinedSegments) {
 126            strokeOutset = 0.0;
 127        }
 128        if (abs(edgeID) == 2.0) {
 129            float _2_x = ((cosTheta) * (0.5) + (0.5));
 130            strokeOutset *= (_2_x * JOIN_TYPE) * JOIN_TYPE >= 1.0 ? (1.0 / sqrt(_2_x)) : sqrt(_2_x);
 131        }
 132        vec2 tangent;
 133        vec2 strokeCoord;
 134        if (combinedEdgeID != 0.0 && !isFinalEdge) {
 135            vec2 A;
 136            vec2 B;
 137            vec2 C = p1 - p0;
 138            vec2 D = p3 - p0;
 139            if (w >= 0.0) {
 140                C *= w;
 141                B = 0.5 * D - C;
 142                A = (w - 1.0) * D;
 143                p1 *= w;
 144            } else {
 145                vec2 E = p2 - p1;
 146                B = E - C;
 147                A = ((vec2(-3.0)) * (E) + (D));
 148            }
 149            vec2 B_ = B * (numParametricSegments * 2.0);
 150            vec2 C_ = C * (numParametricSegments * numParametricSegments);
 151            float lastParametricEdgeID = 0.0;
 152            float maxParametricEdgeID = min(numParametricSegments - 1.0, combinedEdgeID);
 153            float negAbsRadsPerSegment = -abs(radsPerSegment);
 154            float maxRotation0 = (1.0 + combinedEdgeID) * abs(radsPerSegment);
 155            for (int _0_exp = 4;_0_exp >= 0; --_0_exp) {
 156                float testParametricID = lastParametricEdgeID + exp2(float(_0_exp));
 157                if (testParametricID <= maxParametricEdgeID) {
 158                    vec2 testTan = ((vec2(testParametricID)) * (A) + (B_));
 159                    testTan = ((vec2(testParametricID)) * (testTan) + (C_));
 160                    float cosRotation = dot(normalize(testTan), tan0);
 161                    float maxRotation = ((testParametricID) * (negAbsRadsPerSegment) + (maxRotation0));
 162                    maxRotation = min(maxRotation, PI);
 163                    if (cosRotation >= cos(maxRotation)) {
 164                        lastParametricEdgeID = testParametricID;
 165                    }
 166                }
 167            }
 168            float parametricT = lastParametricEdgeID / numParametricSegments;
 169            float lastRadialEdgeID = combinedEdgeID - lastParametricEdgeID;
 170            float angle0 = acos(clamp(tan0.x, -1.0, 1.0));
 171            angle0 = tan0.y >= 0.0 ? angle0 : -angle0;
 172            float radialAngle = ((lastRadialEdgeID) * (radsPerSegment) + (angle0));
 173            tangent = vec2(cos(radialAngle), sin(radialAngle));
 174            vec2 norm = vec2(-tangent.y, tangent.x);
 175            float a = dot(norm, A);
 176            float b_over_2 = dot(norm, B);
 177            float c = dot(norm, C);
 178            float discr_over_4 = max(b_over_2 * b_over_2 - a * c, 0.0);
 179            float q = sqrt(discr_over_4);
 180            if (b_over_2 > 0.0) {
 181                q = -q;
 182            }
 183            q -= b_over_2;
 184            float _5qa = (-0.5 * q) * a;
 185            vec2 root = abs(((q) * (q) + (_5qa))) < abs(((a) * (c) + (_5qa))) ? vec2(q, a) : vec2(c, q);
 186            float radialT = root.y != 0.0 ? root.x / root.y : 0.0;
 187            radialT = clamp(radialT, 0.0, 1.0);
 188            if (lastRadialEdgeID == 0.0) {
 189                radialT = 0.0;
 190            }
 191            float T = max(parametricT, radialT);
 192            vec2 ab = unchecked_mix_f2f2f2f(p0, p1, T);
 193            vec2 bc = unchecked_mix_f2f2f2f(p1, p2, T);
 194            vec2 cd = unchecked_mix_f2f2f2f(p2, p3, T);
 195            vec2 abc = unchecked_mix_f2f2f2f(ab, bc, T);
 196            vec2 bcd = unchecked_mix_f2f2f2f(bc, cd, T);
 197            vec2 abcd = unchecked_mix_f2f2f2f(abc, bcd, T);
 198            float u = ((w - 1.0) * (T) + (1.0));
 199            float v = (w + 1.0) - u;
 200            float uv = ((v - u) * (T) + (u));
 201            if (T != radialT) {
 202                tangent = w >= 0.0 ? robust_normalize_diff_f2f2f2(bc * u, ab * v) : robust_normalize_diff_f2f2f2(bcd, abc);
 203            }
 204            strokeCoord = w >= 0.0 ? abc / uv : abcd;
 205        } else {
 206            tangent = combinedEdgeID == 0.0 ? tan0 : tan1;
 207            strokeCoord = combinedEdgeID == 0.0 ? p0 : p3;
 208        }
 209        vec2 ortho = vec2(tangent.y, -tangent.x);
 210        strokeCoord += ortho * (STROKE_RADIUS * strokeOutset);
 211        vec2 devCoord = AFFINE_MATRIX * strokeCoord + TRANSLATE;
 212        gl_Position = vec4(devCoord, 0.0, 1.0);
 213        gl_Position = vec4(gl_Position.xy * sk_RTAdjust.xz + gl_Position.ww * sk_RTAdjust.yw, 0.0, gl_Position.w);
 214    }
 215    
Errors:
ERROR: 0:82: Use of undeclared identifier 'gl_VertexID'
ERROR: 0:83: Use of undeclared identifier 'gl_VertexID'
ERROR: 0:84: Use of undeclared identifier 'edgeID'
ERROR: 0:84: Use of undeclared identifier 'edgeID'
ERROR: 0:88: Use of undeclared identifier 'edgeID'
ERROR: 0:89: Use of undeclared identifier 'combinedEdgeID'
ERROR: 0:102: Use of undeclared identifier 'edgeID'
ERROR: 0:103: Use of undeclared identifier 'combinedEdgeID'
ERROR: 0:107: Use of undeclared identifier 'combinedEdgeID'
ERROR: 0:111: Use of undeclared identifier 'combinedEdgeID'
ERROR: 0:112: Use of undeclared identifier 'strokeOutset'
ERROR: 0:112: Use of undeclared identifier 'strokeOutset'
ERROR: 0:112: Use of undeclared identifier 'strokeOutset'
ERROR: 0:115: Use of undeclared identifier 'combinedEdgeID'
ERROR: 0:115: Use of undeclared identifier 'combinedEdgeID'
ERROR: 0:124: Use of undeclared identifier 'combinedEdgeID'
ERROR: 0:125: Use of undeclared identifier 'combinedEdgeID'
ERROR: 0:126: Use of undeclared identifier 'strokeOutset'
ERROR: 0:128: Use of undeclared identifier 'edgeID'
ERROR: 0:130: Use of undeclared identifier 'strokeOutset'
ERROR: 0:134: Use of undeclared identifier 'combinedEdgeID'
ERROR: 0:134: Use of undeclared identifier 'isFinalEdge'
ERROR: 0:152: Use of undeclared identifier 'combinedEdgeID'
ERROR: 0:154: Use of undeclared identifier 'combinedEdgeID'
ERROR: 0:157: Use of undeclared identifier 'maxParametricEdgeID'
ERROR: 0:161: Use of undeclared identifier 'maxRotation0'
ERROR: 0:162: Use of undeclared identifier 'maxRotation'
ERROR: 0:162: Use of undeclared identifier 'maxRotation'
ERROR: 0:163: Use of undeclared identifier 'maxRotation'
ERROR: 0:169: Use of undeclared identifier 'combinedEdgeID'
ERROR: 0:172: Use of undeclared identifier 'lastRadialEdgeID'
ERROR: 0:173: Use of undeclared identifier 'radialAngle'
ERROR: 0:173: Use of undeclared identifier 'radialAngle'
ERROR: 0:188: Use of undeclared identifier 'lastRadialEdgeID'
ERROR: 0:206: Use of undeclared identifier 'combinedEdgeID'
ERROR: 0:207: Use of undeclared identifier 'combinedEdgeID'
ERROR: 0:210: Use of undeclared identifier 'strokeOutset'

Steps to reproduce

Unfortunately, I haven't been able to narrow down the crash yet, though I'll try to find time tomorrow to do so. But you can reproduce it on your own by cloning https://github.com/browserengineering/book and running:

cd src
python3 lab13.py http://browser.engineering/

You'll need a working Internet connection.

pavpanchekha commented 6 months ago

I imagine this is Skia's fault, not skia-python's; I'll try to narrow down the issue and if I can confirm that the issue is in Skia, I'll file a bug there.

HinTak commented 6 months ago

This has already been reported I think: https://github.com/kyamagu/skia-python/issues/214 - likely an upstream error - or lack of update of mac os x GL stack.

HinTak commented 6 months ago

It is probably not even skia's fault, but Apple's.

HinTak commented 6 months ago

Mac os x's GL stack is significantly behind others.

HinTak commented 6 months ago

I can't reproduce your shader problem on Linux. Not quite the same as #214 , as I see these errors instead:

$ python3 lab13.py http://browser.engineering/
OpenGL initialized: vendor=b'AMD',renderer=b'AMD Radeon R5 Graphics (radeonsi, stoney, LLVM 17.0.6, DRM 3.57, 6.8.4-200.fc39.x86_64)'
Script http://browser.engineering/feedback.js crashed SyntaxError: parse error (line 39)
    at [anon] (eval:39) internal
    at [anon] (duk_js_compiler.c:3797) internal
Script http://browser.engineering/book.js crashed SyntaxError: parse error (line 4)
    at [anon] (eval:4) internal
    at [anon] (duk_js_compiler.c:511) internal

BTW, your script relies on a specific way of installing dukpy - getting it from the Linux distribution (Redhat Fedora in my case), it is installed without any of the *.py scripts . Just dukpy.cpython-312-x86_64-linux-gnu.so . It looks like you need __init__.py, which loads from .evaljs import evaljs, JSInterpreter. I was seeing AttributeError: module 'dukpy' has no attribute 'JSInterpreter' error when I had it installed via the first method; and had to do pip install --user dukpy to get around it.

This may be a packaging bug on Redhat's part, in which case you (or I) should file at https://bugzilla.redhat.com/

HinTak commented 6 months ago

Let me know to retry if you can fix the crashed SyntaxError: parse error .

pavpanchekha commented 6 months ago

Ah, heh, the syntax error is unfortunately expected behavior! This is the browser running a website that uses JS syntax not supported by DukPy. Will look into RedHat

HinTak commented 6 months ago

I just get a window of your web site, and those messages. So i assume that's correct behavior? In that case this is mac os x specific and same as #214 .

As for the packaging issue, the file listing of the package is https://koji.fedoraproject.org/koji/rpminfo?rpmID=35288394 - missing all the *.py files. I am not familiar with it, and how it should be.

HinTak commented 6 months ago

Btw, the lab13 script also seems to be doing a busy wait and tie up one of my cpu's while it runs. (Just looking at my system load monitor).

pavpanchekha commented 6 months ago

I’ll look, may be an issue

HinTak commented 6 months ago

Argh, the busy wait loop is the while True: on line 1491 in mainloop. Polling for events isn't ideal - there has got to be a way of registering event handler, for better efficiency.

pavpanchekha commented 6 months ago

Closed as duplicate