How to catch a GLSL error?

TL;DR:
Sometimes, in some unexpected cases, for some unknown reasons, a “GLSL link error” is thrown into console. It happens in WebGL or android builds. It’s not caught by a regular try-catch C# statements. Even with broad “catch (Exception e) {…}”.
Is there a way to catch or at least temporary suppress those errors from a script?

In detail:
I’m writing a small toolset that reliably detects shader features supported by the GPU. It does so by actually trying to render a small RT with a special shader which outputs a debug colors indicating whether the feature is supported or not.
In the process, I use a built-in shader fallback system. Specifically, I add multiple subshaders, first of which has some “#pragma require” restriction and renders an “OK” color. And the second one is extremely simple and outputs “not OK” color. But sometimes, on some low-end devices (not just mobile ones but also outdated PCs) a GLSL error is thrown into console, even though there’s that second subshader that should work on literally anything.
So I’d like to know, how can I catch (from c# script) those graphics-API-level errors.

Here’s the error text:

GLES20: vprog textures are used, but not supported.
-------- GLSL link error: No compiled vertex shader when at least one graphics shader is attached.

It appears very rarely in WebGL. So far - only a couple of users (of a few thousands) got it. But they do.

And here’s the shader.
It doesn’t do anything fancy - just forces a texture to be read at vertex stage.
If GPU can do that, the 1st subshader should render a green(ish) color.
Otherwise, the 2nd subshader renders a red color.

Shader "y-Debug/Hardware Test/TexLod-Vert" {
   Properties {
       [Header(CHANGE THE SHADER IF YOU SEE THIS TEXT)]
       [Header(it should only be used from script)]
       [Space(40)]
    
       _MainTex ("Main Texture", 2D) = "white" {} // not used, declared just to make Blit happy
       _TestTex ("Test Texture", 2D) = "white" {} // should be passed as black texture
    
       [Space] [Header(Shader Blending)]
       [Enum(UnityEngine.Rendering.CullMode)] _Cull ("Cull", Int) = 0
       [Enum(None,0,Alpha,1,RGB,14,RGBA,15)] _ColorMask ("out Color Mask", Float) = 15
       [Enum(Off, 0, On, 1)] _zWrite ("Z-Write", Int) = 0
       [Enum(UnityEngine.Rendering.CompareFunction)] _zTest ("Z-Test", Int) = 8 // Always
   }
 
   CGINCLUDE
       #pragma vertex vert
       #pragma fragment frag
    
       #include "UnityCG.cginc"
    
       #define DRL_YES_COLOR fixed4(0.3, 0.7, 0.2, 1.0)
       #define DRL_NO_COLOR fixed4(0.9, 0.25, 0.2, 1.0)
    
       struct appdata {
           float3 vertex : POSITION;
           half2 tex0 : TEXCOORD0;
       };
    
       struct v2f {
           float4 pos : SV_POSITION;
           fixed4 vColor : COLOR;
           half2 mainUVs : TEXCOORD0;
       };
    
       sampler2D _TestTex;
    
       fixed4 frag (v2f i) : SV_Target
       {
           fixed4 clr = tex2D(_TestTex, i.mainUVs); // should be black, effectively keeping only vertex color
           return saturate(i.vColor + clr);
       }
   ENDCG
 
   Category {
       Tags {
           "PreviewType"="Plane"
           "RenderType"="Opaque"
           "IgnoreProjector"="True"
           "ForceNoShadowCasting"="True"
       }
    
       ColorMask [_ColorMask]
       Cull [_Cull]
       ZTest [_zTest]
       ZWrite [_zWrite]
       Lighting Off
    
       SubShader { Pass {
           CGPROGRAM
               // with support
               #pragma require samplelod
            
               v2f vert (appdata v)
               {
                   float3 vtx = v.vertex;
                   half3 clr = tex2Dlod(_TestTex, half4(v.tex0, 0.0h, 0.0h));
                   vtx.xy += (v.tex0 * 2.0h - 1.0h) * clr.rg; // expand quad verts outside
                
                   v2f o;
                   o.pos = UnityObjectToClipPos(vtx);
                   o.vColor = DRL_YES_COLOR;
                   o.mainUVs = v.tex0;
                   return o;
               }
           ENDCG
       } }
       SubShader { Pass {
           CGPROGRAM
               // no support
            
               v2f vert (appdata v)
               {
                   v2f o;
                   o.pos = UnityObjectToClipPos(v.vertex);
                   o.vColor = DRL_NO_COLOR;
                   o.mainUVs = v.tex0;
                   return o;
               }
           ENDCG
       } }
   }
 
   FallBack Off
 
}

Hi!
The error just says that the device you’re running on doesn’t support reading textures in vertex shaders.
#pragma require samplelod is the capability for fragment shaders to sample textures with explicit LOD - it has nothing to do with vertex texture fetch support.
OpenGL ES 2 spec is a bit funky here - it requires 0 vertex texture units to be present. It’s part of the specification, but not required.

I suggest to file a bug report - this should be handled better (the first error comes from our code).

@aleksandrk
Submitted a bug report today. Hope it helps.

1 Like

Thank you!

Hi, i came to the similar situation, my problem is that even if my device support reading textures in vertex shaders, the error GLES20: vprog textures are used, but not supported is still there. I’ve tested by manually creating, compiling raw glsl shader into my device, everything goes fine. But if i use shaderlab to write a vert function that contains tex2dlod, the error occurs, even if i returned from the beginning of all the _gl* like functions in the webgl.framework.js. So i wonder if i can bypass the process in webgl.wasm that trigger the ‘vprog’ error, so that my shader can work?

Hi!
Please submit a bug report. It sounds like the driver reports the capabilities incorrectly.

Thanks for you reply! What capability does vprog texture required? I think i can just return the capability is supported, and the error will be gone?

We ask the driver for the capability internally, it’s not something that should be touched, even if you’re willing to modify the JS code.

We have our own browser-like runtime in c++. May i ask what the capability exactly is, so that we can modify our c++ code to support it?

It’s GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS

Wow!Problem solved, thx a lot!

1 Like