Libpag generates invalid WebGL shader code with undefined variable
johncalvinroberts opened this issue · comments
你好👋 谢谢你们的很棒的库,我有一个bug想提一下
我先写英文 你们中文英文回答都可以
谢谢
Which Version of libpag are you using?
libpag 4.3.71
What Platform are you on?
Web
Expected Behavior
Libpag should render without breaking
Actual Behavior
With some pag files, libpag
is generating invalid webGL shader code, which then crashes and fails to render anything at all.
The shader code is generated by tgfx
(another Tencent library), and the effects/syntax itself fine, it is the last (transfer) step that is bugged.
The offending shader is the following:
#version 100
precision mediump float;
uniform vec4 ustart_Stage1;
uniform vec4 urightBorderColor_Stage1;
uniform vec4 uColor_Stage2;
uniform vec4 uleftBorderColor_Stage1;
uniform vec4 uColor_Stage0;
uniform vec4 uend_Stage1;
varying highp vec2 vTransformedCoords_0_Stage0;
varying highp float vCoverage_Stage0;
void main() {
vec4 outputColor_Stage0;
vec4 outputCoverage_Stage0;
{ // Stage 0 DefaultGeometryProcessor
outputCoverage_Stage0 = vec4(vCoverage_Stage0);
outputColor_Stage0 = uColor_Stage0;
}
vec4 output_Stage1;
{ // Stage 1 ClampedGradientEffect
vec4 _child1;
{
// Child Index 1 (mangle: _c0): LinearGradientLayout
float t = vTransformedCoords_0_Stage0.x + 1.0000000000000001e-05;
_child1 = vec4(t, 1.0, 0.0, 0.0);
}
vec4 t = _child1;
if (t.y < 0.0) {
output_Stage1 = vec4(0.0);
} else if (t.x <= 0.0) {
output_Stage1 = uleftBorderColor_Stage1;
} else if (t.x >= 1.0) {
output_Stage1 = urightBorderColor_Stage1;
} else {
vec4 _child0;
vec4 _childInput_c1 = t;
{
// Child Index 0 (mangle: _c1): SingleIntervalGradientColorizer
float t = _childInput_c1.x;
_child0 = (1.0 - t) * ustart_Stage1 + t * uend_Stage1;
}
output_Stage1 = _child0;
}
}
vec4 output_Stage2;
{ // Stage 2 ConstColorProcessor
output_Stage2 = uColor_Stage2;
output_Stage2 *= output_Stage1;
}
{ // Xfer Processor PorterDuffXferProcessor
vec4 localOutputColor;
localOutputColor.a = output_Stage2.a + (1.0 - output_Stage2.a) * _dstColor.a;
localOutputColor.rgb = (1.0 - output_Stage2.a) * _dstColor.rgb + (1.0 - _dstColor.a) * output_Stage2.rgb + output_Stage2.rgb * _dstColor.rgb;
localOutputColor = outputCoverage_Stage0 * localOutputColor + (vec4(1.0) - outputCoverage_Stage0) * _dstColor;
gl_FragColor = localOutputColor;
}
}
It is the section annotated with PorterDuffXferProcessor
, which is referring to a _dstColor
variables that was never declared
Browser emits this error when trying to execute this shader:
TypeError: Failed to execute 'getAttribLocation' on 'WebGLRenderingContext': parameter 1 is not of type 'WebGLProgram'.
at _emscripten_glGetAttribLocation (libpag.js:9:132060)
at libpag.wasm:0x1a952a
at libpag.wasm:0x1d207f
at libpag.wasm:0x71633
at libpag.wasm:0x18effc
at libpag.wasm:0x1bd7a1
at libpag.wasm:0x459a1
at libpag.wasm:0x6f926
at libpag.wasm:0x224bbf
at libpag.wasm:0x217960
Code Example
Here's a working JS fiddle with a reproduction of the error: link
Or, html file:
Click to expand/collapse bug repro HTML file
<!DOCTYPE html>
<html lang="en-US">
<head>
<title>Play PAG File</title>
<script src="https://unpkg.com/libpag@4.3.51/lib/libpag.min.js"></script>
<!-- script src="https://greggman.github.io/webgl-lint/webgl-lint.js" data-gman-debug-helper='{ "maxDrawCalls": 0 }'></script -->
<style lang="css">
body {
margin: 1rem;
display: flex;
flex-direction: column;
place-items: center;
gap: 16px;
}
h1 {
font-size: 3.2em;
line-height: 1.1;
}
canvas {
border: 2px solid red;
max-width: 300px;
height: auto !important;
}
.invisible {
display: none;
}
.error {
color: red;
font-weight: 600;
}
</style>
</head>
<body>
<h1>Play PAG File</h1>
<span class="invisible error" id="error-label"></span>
<input type="file" id="pag-input" disabled />
<canvas class="invisible" id="pag-canvas" width="480" height="640"/>
<script>
window.onload = async () => {
const pagInput = document.getElementById("pag-input");
const pagCanvas = document.getElementById("pag-canvas");
const errorLabel = document.getElementById("error-label");
function handleError(error) {
const message = typeof error === "object" && 'message' in error ? error.message : `${error}`;
console.error(error);
errorLabel.innerText = "ERROR: " + message;
errorLabel.classList.remove("invisible");
}
try {
let pagFile, pagView;
const PAG = await window.libpag.PAGInit();
console.log("libpag initialized successfully");
pagInput.disabled = false;
pagInput.addEventListener("change", async (ev) => {
const files = Array.from(ev.target.files ?? []);
if (files.length != 1) {
return;
}
try {
pagView?.stop();
pagView?.destroy();
pagFile?.destroy();
const pagFileData = await files[0].arrayBuffer();
pagFile = await PAG.PAGFile.loadFromBuffer(pagFileData);
pagCanvas.width = pagFile.width();
pagCanvas.height = pagFile.height();
pagView = await PAG.PAGView.init(pagFile, pagCanvas);
pagCanvas.classList.remove("invisible");
await pagView.play();
} catch (error) {
handleError(error);
}
});
} catch (error) {
handleError(error);
}
}
</script>
</body>
</html>
Please use the pag file attached below (compressed to .zip).
PAG File
This issue was present in the v4.3 release but has been fixed in the latest v4.4 release. Please check with the v4.4.25 version.
Indeed, we updated to 4.4.x and bug is resolved. Thank you! @Hparty