GLSL Support with Mathematica Graphics

Yuzhu Lu, Wolfram Research, Inc.

(RowDefault[, (Spacer1), , (Spacer1), ])  #WolframTechConf

ABSTRACT

This talk shows to how to use existing Open GL Shading Language (GLSL) files and make it work with 2D/3D polygon based primitives and customize the graphics rendering.

SurfaceAppearance

What can you do: examples

GLSL supported: things you need to know

What do you get: benefits

SurfaceAppearance

SurfaceAppearance a new experimental feature which allow customized rendering. Other than the data passed in, it also allows a piece if code (GLSL) could run on hardware directly

Graphics Features Implemented with SurfaceAppearance
ToonShading, GoochShading, StippleShading, HalftoneShading, HatchShading, HatchFilling, PatternFilling, LinearGradientFilling, RadialGradientFilling, ConicGradientFilling, MaterialShading, SolidRegion

GraphicsGrid[{{Graphics3D[{ToonShading[],Sphere[]},Lighting->"Accent",PlotLabel->ToonShading],Graphics3D[{GoochShading[],Sphere[]},Lighting->"Accent",PlotLabel->GoochShading],Graphics3D[{StippleShading[],Sphere[]},Lighting->"Accent",PlotLabel->StippleShading],Graphics3D[{HalftoneShading[],Sphere[]},Lighting->"Accent",PlotLabel->HalftoneShading]},{Graphics3D[{HatchShading[],Sphere[]},Lighting->"Accent",PlotLabel->HatchShading],Graphics3D[{MaterialShading["Iron"],Sphere[]},Lighting->"ThreePoint",PlotLabel->MaterialShading],CSGRegion["Difference",{Ball[],Cuboid[{0,-1,0}]}],Graphics[{HatchFilling[],Disk[]},PlotLabel->HatchFilling]},{Graphics[{PatternFilling["DiamondBox",{20,20}],Disk[]},PlotLabel->PatternFilling],Graphics[{LinearGradientFilling[{Red,Blue}],Disk[]},PlotLabel->LinearGradientFilling],Graphics[{RadialGradientFilling[{Red,Blue}],Disk[]},PlotLabel->RadialGradientFilling],Graphics[{ConicGradientFilling[{Red,Blue}],Disk[]},PlotLabel->ConicGradientFilling]}},ImageSize->Large]

Association syntax

\[LeftAssociation]
"Name"->"name",
"Attributes"->\[LeftAssociation]"attrib1"->attribute type,...\[RightAssociation],"Parameters"->\[LeftAssociation]"parameterName1"->{nameUsedInShader,val,parameter type},...\[RightAssociation],"ShaderPrograms"->\[LeftAssociation]"GLFragmentProgram"->GLSL Fragment Shader,"GLVertexProgram"->GLSL Vertex Shader\[RightAssociation]
\[RightAssociation]

Attribute (data input) types

({{      , "ATTRIB_VERTEX", vertex coordinates,  it will be resolved polygon vertex in case of Sphere/Cylinder/Cone/Tube... }, {      , "ATTRIB_NORMAL", vertex normals from VertexNormal option, it will computed automaticly for 3D if not provided}, {      , "ATTRIB_COLOR", vertex colors from VertexColors option}, {      , "ATTRIB_TEXTURECOORD", vertex texture coordinates from VertexTextureCoordinates option, it will be computed automaticly if not provided}})

Parameter types

({{      , "COLOR", color syntax including named colors, RGBColor, LABColor...}, {      , "NUMBER", number or scaled number as float value}, {      , "NUMBER2", a list of two numbers or scaled numbers as float vector}, {      , "NUMBER3", a list of three numbers or scaled numbers as float vector}, {      , "NUMBER4", a list of four numbers or scaled numbers as float vector}, {      , "SIZE", number or scaled number as integer value}, {      , "SIZE2", a list of two numbers or scaled numbers as integer vector}, {      , "SIZE3", a list of three numbers or scaled numbers as integer vector}, {      , "SIZE4", a list of four numbers or scaled numbers as integer vector}, {      , "MATRIX2", a matrix of 2 by 2 numbers as float matrix}, {      , "MATRIX3", a matrix of 3 by 3 numbers as float matrix}, {      , "MATRIX4", a matrix of 4 by 4 numbers as float matrix}, {      , "TEXTURE", 1D/2D/3D Texture sampler from Texture object}})

SurfaceAppearanceDocumentationFile=FileNameJoin[{NotebookDirectory[],"SurfaceAppearance.nb"}];
NotebookOpen[SurfaceAppearanceDocumentationFile]

SetDirectory[NotebookDirectory[]];
shader=\[LeftAssociation]
"Name"->"GrayLevelTextureMapping",
"Attributes"->\[LeftAssociation]"a_position"->"ATTRIB_VERTEX","a_texcoord"->"ATTRIB_TEXTURECOORD"\[RightAssociation],"Parameters"->\[LeftAssociation]"Matrix"->{"mvp_matrix","TRANSFORMMATRIX","MATRIX4"}\[RightAssociation],"ShaderPrograms"->\[LeftAssociation]"GLFragmentProgram"->"fShaderSimple.glsl","GLVertexProgram"->"vShaderSimple.glsl"\[RightAssociation]
\[RightAssociation];

Dataset[shader]

Import[#]&/@{"vShaderSimple.glsl","fShaderSimple.glsl"}

Add the shader definition to the SurfaceAppearance library

If added multiple times, the newer one will override the old one

FE`Evaluate@Evaluate[FEPrivate`AddSurfaceAppearanceDefinition@shader];

Check if added successfully

FE`Evaluate[FEPrivate`ListSurfaceAppearanceDefinitions["GrayLevelTextureMapping"]]

Look up in the SurfaceAppearance library by name and use the shader if available

Graphics[{SurfaceAppearance["GrayLevelTextureMapping"],Texture[],Polygon[{{0,0},{1,0},{1/2,1}},VertexTextureCoordinates->{{0,0},{1,0},{1/2,1}}]}]

What can you do: examples

Digital Arts

A list of algorithm art from: http://algorithmicartmeetup.blogspot.com/2017/04/accelerated-art-with-glsl.html

shaderList ={"fShaderBubble.glsl","fShaderGentlyShade.glsl","fShaderHappySpot.glsl","fShaderSharp.glsl","fShaderSnake.glsl","fShaderTheme.glsl"};
{s1,s2,s3,s4,s5,s6}=\[LeftAssociation]
"Name"->#,
"Attributes"->\[LeftAssociation]"a_position"->"ATTRIB_VERTEX","a_texcoord"->"ATTRIB_TEXTURECOORD"\[RightAssociation],"Parameters"->\[LeftAssociation]"Matrix"->{"mvp_matrix","TRANSFORMMATRIX","MATRIX4"},"Time"->{"time",0,"NUMBER"},"Resolution"->{"resolution", {200,200},"NUMBER2"}\[RightAssociation],"ShaderPrograms"->\[LeftAssociation]"GLFragmentProgram"->#,"GLVertexProgram"->"vShaderSimple.glsl"\[RightAssociation]
\[RightAssociation]&/@shaderList;
FE`Evaluate@Evaluate[FEPrivate`AddSurfaceAppearanceDefinition@#]&/@{s1,s2,s3,s4,s5,s6};

Manipulate[Graphics[{SurfaceAppearance[#,"Time"->Dynamic@time],Rectangle[]},ImageSize->{250,250}],{time,0,10},ControlPlacement->Top]&/@shaderList

Port Kode Life Shader Projects: Build a interface for music player

Another example from users kode life project: https://hexler.net/products/kodelife to to mimic the old iTunes Jelly shader:

KodeLifeA=\[LeftAssociation]
"Name"->"KodeLifeA",
"Attributes"->\[LeftAssociation]"a_position"->"ATTRIB_VERTEX","a_texcoord"->"ATTRIB_TEXTURECOORD"\[RightAssociation],"Parameters"->\[LeftAssociation]"Matrix"->{"mvp_matrix","TRANSFORMMATRIX","MATRIX4"},"Time"->{"time",0,"NUMBER"},"Spectrum"->{"spectrum", {0,1,0},"NUMBER3"}\[RightAssociation],"ShaderPrograms"->\[LeftAssociation]"GLFragmentProgram"->"fShaderKodeLifeA.glsl","GLVertexProgram"->"vShaderSimple.glsl"\[RightAssociation]
\[RightAssociation];
FE`Evaluate@Evaluate[FEPrivate`AddSurfaceAppearanceDefinition@KodeLifeA];
Manipulate[Graphics[{SurfaceAppearance["KodeLifeA","Time"->Dynamic@time,"Spectrum"->{Dynamic@spec, Dynamic@spec, Dynamic@spec},Texture[{{0,0}}]],Rectangle[]},ImageSize->{400,400}],{time,0,100},{spec,0,10},ControlPlacement->Top]

Multiple pass through Texture:

KodeLifeB=\[LeftAssociation]
"Name"->"KodeLifeB",
"Attributes"->\[LeftAssociation]"a_position"->"ATTRIB_VERTEX","a_texcoord"->"ATTRIB_TEXTURECOORD"\[RightAssociation],
"Parameters"->\[LeftAssociation]"Matrix"->{"mvp_matrix","TRANSFORMMATRIX","MATRIX4"},"Resolution"->{"resolution", {1,1},"NUMBER2"}\[RightAssociation],"ShaderPrograms"->\[LeftAssociation]"GLFragmentProgram"->"fShaderKodeLifeB.glsl","GLVertexProgram"->"vShaderSimple.glsl"\[RightAssociation]
\[RightAssociation];
FE`Evaluate@Evaluate[FEPrivate`AddSurfaceAppearanceDefinition@KodeLifeB];
Manipulate[With[{t=time,s=spec},Graphics[{SurfaceAppearance["KodeLifeB",Texture@Graphics[{SurfaceAppearance["KodeLifeA","Time"->Dynamic@t,"Spectrum"->{Dynamic@s, Dynamic@s, Dynamic@s},Texture[{{0,0}}]],Rectangle[]},ImageSize->{400,400}]],Rectangle[]},ImageSize->{400,400}]],{time,0,100},{spec,0,10},ControlPlacement->Top]

Connect with sound:

gauge[audio_]:=HorizontalGauge[AudioMeasurements[audio,"LoudnessEBU"],{-60,10},GaugeMarkers->Placed[Automatic,"DivisionCenter"],GaugeStyle->Blue,GaugeLabels->{"dbRMS","Value"},ScaleDivisions->{5,2}];

DynamicModule[{a,astream},Framed@Column@{Button[Dynamic[astream["Status"]],Switch[astream["Status"],"Playing",AudioPause[astream],"Paused"|"Stopped",AudioPlay[astream]]],ProgressIndicator[Dynamic[astream["Position"]/Duration[a]],ImageSize->400],Dynamic[gauge[astream["CurrentAudio"]]],Graphics[{Dynamic@SurfaceAppearance["KodeLifeA","Time"->astream["Position"]/Duration[a]*20,"Spectrum"->ConstantArray[(AudioMeasurements[astream["CurrentAudio"],"LoudnessEBU"]+120.0)/50.0,3],Texture[{{0,0}}]],Rectangle[]},ImageSize->{400,400}]},Initialization:>{a=ExampleData[{"Audio","Drums"}],astream=AudioStream[a]}]

What can you do: examples continued

GPGPU and Visualization: Julia Factor

(HyperlinkTemplate[JuliaSetPlot, https://reference.wolfram.com/language/ref/JuliaSetPlot.html, https://reference.wolfram.com/language/ref/JuliaSetPlot.html, HyperlinkActionRecycled, HyperlinkActive, , ]) (HyperlinkTemplate[MandelbrotSetPlot, https://reference.wolfram.com/language/ref/MandelbrotSetPlot.html, https://reference.wolfram.com/language/ref/MandelbrotSetPlot.html, HyperlinkActionRecycled, HyperlinkActive, , ])

FE`Evaluate@Evaluate[FEPrivate`AddSurfaceAppearanceDefinition[\[LeftAssociation]"Name"->"My GPGPU","Attributes"->\[LeftAssociation]"position"-> "ATTRIB_VERTEX", "vertexColor"->"ATTRIB_COLOR"\[RightAssociation],"Parameters"->\[LeftAssociation]\[RightAssociation],"ShaderPrograms"->\[LeftAssociation]"GLFragmentProgram"->"varying vec2 vPosition;  varying vec2 vJuliaPosition;  void main()  { float cx=vJuliaPosition.x;  float cy=vJuliaPosition.y;  float x=vPosition.x;  float y=vPosition.y;  float hue;  const float saturation=0.6;  const float value=1.0;  float hueRound;  int hueIndex;  float f;  float p;  float q;  float t;  float vel;  float x2=x*x;  float y2=y*y;  float tempX=0.0;  int i=60;  int runaway=0; for (int iter = 0; iter < 60; iter++) { tempX = x2 - y2 + cx; y = 2.0 * x * y + cy; x = tempX; x2 = x * x; y2 = y * y; vel = x2 + y2; if(vel > 10000.0) { i = iter; runaway = 1; break;}} if(runaway == 1)  {hue=(float(i)-log(vel)/9.21)/70.0;  hueRound=hue*6.0; hueIndex=int(mod(float(int(hueRound)),6.0)); f=fract(hueRound); p=value*(1.0-saturation); q=value*(1.0-f*saturation); t=value*(1.0-(1.0-f)*saturation);if (hueIndex == 0) gl_FragColor=vec4(value,t,p,1.0);else if (hueIndex == 1) gl_FragColor=vec4(q,value,p,1.0);else if (hueIndex == 2) gl_FragColor=vec4(p,value,t,1.0);else if (hueIndex == 3) gl_FragColor=vec4(p,q,value,1.0);else if (hueIndex == 4) gl_FragColor=vec4(t,p,value,1.0);else if (hueIndex == 5) gl_FragColor=vec4(value,p,q,1.0);} else gl_FragColor=vec4(0.0,0.0,0.0,1.0);}","GLVertexProgram"->"attribute vec4 position; attribute vec4 vertexColor; varying vec2 vPosition;  varying vec2 vJuliaPosition;   void main() { gl_Position = vec4(position.xy, 1, 1); vPosition = position.xy * vec2(1.7, 1.2); vJuliaPosition = (vertexColor.xy - 0.5)*2.0;}"\[RightAssociation]\[RightAssociation]]];

Manipulate[Graphics[{System`SurfaceAppearance["My GPGPU"],Polygon[{{1.01,1.01},{-1.01,1.01},{-1.01,-1.01},{1.01,-1.01}},VertexColors->{RGBColor[{0.5 +0.5*Sin[0.7*(Dynamic[t]+Sin[Dynamic[t]*0.27]*(Sin[Dynamic[t]*0.55]*0.4+0.4))],0.5 +0.5*Sin[Dynamic[t]+Sin[Dynamic[t]*0.27]*(Sin[Dynamic[t]*0.55]*0.4+0.4)],0,1} ],RGBColor[{0.5 +0.5*Sin[0.7*(Dynamic[t]+Sin[Dynamic[t]*0.27+1.57]*(Sin[Dynamic[t]*0.55]*0.4+0.4))],0.5 +0.5*Sin[Dynamic[t]+Sin[Dynamic[t]*0.27 +1.57]*(Sin[Dynamic[t]*0.55]*0.4+0.4)],0,0}],RGBColor[{0.5 +0.5*Sin[0.7*(Dynamic[t]+Sin[Dynamic[t]*0.27+3*1.57]*(Sin[Dynamic[t]*0.55]*0.4+0.4))],0.5 +0.5*Sin[Dynamic[t]+Sin[Dynamic[t]*0.27 +3*1.57]*(Sin[Dynamic[t]*0.55]*0.4+0.4)],0,1} ],RGBColor[{0.5 +0.5*Sin[0.7*(Dynamic[t]+Sin[Dynamic[t]*0.27+2*1.57]*(Sin[Dynamic[t]*0.55]*0.4+0.4))],0.5 +0.5*Sin[Dynamic[t]+Sin[Dynamic[t]*0.27 +2*1.57]*(Sin[Dynamic[t]*0.55]*0.4+0.4)],0,1}]}]},PlotRange->{{-1,1},{-1,1}},ImageSize->Medium],{t,0,30},ControlPlacement->Top]

GPU based simulation: Ping-Pong method

Ping-Pong method is one of the key techniques for many GPGPU applications and physically based simulations

SetDirectory[NotebookDirectory[]];
FE`Evaluate@Evaluate[FEPrivate`AddSurfaceAppearanceDefinition[\[LeftAssociation]
"Name"->"Reaction",
"Attributes"->\[LeftAssociation]"a_position"->"ATTRIB_VERTEX","a_texcoord"->"ATTRIB_TEXTURECOORD"\[RightAssociation],"Parameters"->\[LeftAssociation]"Matrix"->{"mvp_matrix","TRANSFORMMATRIX","MATRIX4"},"Resolution"->{"u_resolution", {400,400},"NUMBER2"},"MousePos"->{"u_mouse", {200,200},"NUMBER2"},"Texture"->{"u_texture",Automatic,"TEXTURE"}\[RightAssociation],"ShaderPrograms"->\[LeftAssociation]"GLFragmentProgram"->"fShaderReaction.glsl","GLVertexProgram"->"vShaderSimple.glsl"\[RightAssociation]
\[RightAssociation]]];

mousePos:=MousePosition["Graphics",{0,0}];
drawFunc[mouse_, texture_]:=Graphics[{SurfaceAppearance["Reaction","MousePos"->Dynamic[mouse*500]],Texture[texture],Rectangle[]},ImageSize->{400,400},PlotRange->{{0,1},{0,1}},PlotRangePadding->Scaled[-0.001]]

DynamicModule[{tex,preTex,mouse,lastMouse},{EventHandler[Dynamic@drawFunc[lastMouse,tex],{"MouseDown":>(mouse=mousePos),"MouseDragged":>(preTex=Rasterize[drawFunc[lastMouse,tex],ImageResolution->90];
lastMouse=mouse;mouse=mousePos;
tex=Rasterize[drawFunc[mouse,preTex],ImageResolution->90])}],Labeled[Dynamic@preTex,"Texture 1"],Labeled[Dynamic@tex,"Texture 2"]},Initialization:>{tex={{0,0,0}},preTex={{0,0,0}},mouse={0,0},lastMouse={0,0}}]

Realtime Video effects: Post-processing

Post-processing examples GLSL samples: https://webgl-shaders.com/

VideoEffectShaderList ={"fShaderEdgeDetection.glsl","fShaderEdgeDetection2.glsl","fShaderBadTV.glsl","fShaderGaussianBlur.glsl","fShaderLens.glsl"};
{ve1,ve2, ve3, ve4, ve5}=\[LeftAssociation]
"Name"->#,
"Attributes"->\[LeftAssociation]"position"->"ATTRIB_VERTEX","vertexTextureCoordIn"->"ATTRIB_TEXTURECOORD"\[RightAssociation],"Parameters"->\[LeftAssociation]"TMatrix"->{"tranformationMatrix","TRANSFORMMATRIX","MATRIX4"},"Color"->{"color",Yellow,"COLOR"},"Texture2D"->{"texture",Automatic,"TEXTURE"},"Size"->{"size",360,"NUMBER"}\[RightAssociation],"ShaderPrograms"->\[LeftAssociation]"GLFragmentProgram"->#,"GLVertexProgram"->"vShaderEdgeDetection.glsl"\[RightAssociation]
\[RightAssociation]&/@VideoEffectShaderList;
FE`Evaluate@Evaluate[FEPrivate`AddSurfaceAppearanceDefinition@#]&/@{ve1,ve2,ve3, ve4, ve5};

ApplyEdges[img_]:=RawBoxes[ToBoxes[img]/.RasterBox[arg_,opts___]:>{SurfaceAppearance[Dynamic@videoEffect],RasterBox[arg,opts]}];
video=ApplyEdges[Import["Caminandes.avi","Animation",ControlPlacement->Top]];

PopupMenu[Dynamic[videoEffect],Prepend[VideoEffectShaderList,None]]

video

ImageDimensions@

Build your own visualization function: Generate GLSL files

Use template and generate/compile your function into GLSL files

SetDirectory[NotebookDirectory[]];
Import["fShaderTemplate.glsl"]

compileNewGLSLPlot[s_]:=StringReplace[#,"customizedFunc"->s]&;

MyFancyGPUDensityPlot[s_]:=With[{ss=compileNewGLSLPlot[s][Import["fShaderTemplate.glsl"]],fileName=StringReplace["fShaderCustomize.glsl","Customize"->ToString@Hash[s]]},
Export[fileName,ss,"TEXT"];
FE`Evaluate@Evaluate[FEPrivate`AddSurfaceAppearanceDefinition[\[LeftAssociation]
"Name"->fileName,
"Attributes"->\[LeftAssociation]"a_position"->"ATTRIB_VERTEX","a_texcoord"->"ATTRIB_TEXTURECOORD"\[RightAssociation],"Parameters"->\[LeftAssociation]"Matrix"->{"mvp_matrix","TRANSFORMMATRIX","MATRIX4"},"Time"->{"time",0,"NUMBER"},"Resolution"->{"resolution", {400,400},"NUMBER2"}\[RightAssociation],"ShaderPrograms"->\[LeftAssociation]"GLFragmentProgram"->fileName,"GLVertexProgram"->"vShaderSimple.glsl"\[RightAssociation]
\[RightAssociation]]];
Manipulate[Graphics[{SurfaceAppearance[fileName,"Time"->Dynamic@time],Rectangle[]},ImageSize->{314,314}],{time,0,10},ControlPlacement->Top]]

MyFancyGPUDensityPlot["sin(x*y)"]

MyFancyGPUDensityPlot["x*x + y*y"]

GLSL supported: things you need to know

requires GLSL 3.3 standard

GLSL 3.3 is guaranteed to work with all platforms/drivers. Lower/Higher version might/might not work depending on the hardware driver. But we will try to convert it if possible.

GLSL debug

GLSL error messages will be printed to the Messages window

how to find out what version your driver support

SystemInformation will list the GLSL version supported for all available drivers:

Cases[SystemInformation["Devices","GraphicsDevices"],Rule["Renderer",renderer_]->renderer,Infinity]

Cases[SystemInformation["Devices","GraphicsDevices"],Rule["GLSL Version",glslv_]->glslv,Infinity]

test code initialization

GLSLFragmentShader[version_]:="#version "<>ToString[version]<>" \nuniform sampler2D texture;\n varying vec2 v_texcoord;\n void main()\n {\n gl_FragColor = vec4(0.0,1.0,0.0,1.0) * texture2D(texture, v_texcoord);\n }\n"

GLSLVertexShader[version_]:="#version "<>ToString[version]<>" \nuniform mat4 mvp_matrix;\n attribute vec4 a_position;\n attribute vec2 a_texcoord;\n varying vec2 v_texcoord;\n void main()\n {\n gl_Position = mvp_matrix * a_position;v_texcoord = a_texcoord;\n}\n"

GenerateTestShader[version_]:=
Block[{fragCode,vertexCode,fName,vName,definition},
(* Create a basic shader in the given version. *)
fragCode=GLSLFragmentShader[version];
vertexCode=GLSLVertexShader[version];

(* Save the shaders to separate files in the current directory *)
fName="fshader_"<>ToString[version]<>".glsl";
vName="vshader_"<>ToString[version]<>".glsl";
Export[fName,fragCode,"String"];
Export[vName,vertexCode,"String"];

(* Return definition to be loaded into the FE *)
definition=\[LeftAssociation]
"Name"->ShaderName[version],
"Attributes"->\[LeftAssociation]"a_position"->"ATTRIB_VERTEX","a_texcoord"->"ATTRIB_TEXTURECOORD"\[RightAssociation],"Parameters"->\[LeftAssociation]"Matrix"->{"mvp_matrix","TRANSFORMMATRIX","MATRIX4"}\[RightAssociation],"ShaderPrograms"->\[LeftAssociation]"GLFragmentProgram"->fName,"GLVertexProgram"->vName\[RightAssociation]
\[RightAssociation]
]

ShaderName[version_]:="Shader_V"<>ToString[version]

TryLoadShader[version_]:=
Block[{initialDir,definition,name,graphic,raster,successful},
(* Create test shader files in temp directory *)
initialDir=Directory[];
SetDirectory[$TemporaryDirectory];

(* Generate shader files and add definition to FE *)
definition=GenerateTestShader[version];
res=FE`Evaluate@Evaluate[FEPrivate`AddSurfaceAppearanceDefinition@definition];

(* Reset directory back to initial path *)
SetDirectory[initialDir];

(* Try to render a triangle with the shader. *)
name=ShaderName[version];
graphic=Graphics[{SurfaceAppearance[name],Texture[],Polygon[{{0,0},{1,0},{1/2,1}},VertexTextureCoordinates->{{0,0},{1,0},{1/2,1}}]},ImageSize-> Tiny];
raster=Rasterize[graphic];

(* If the shader failed to compile, then the graphic will return blank (all white). A quick way to check this is to see if there is only one dominant color in the raster (i.e. white) *)
successful=Length[DominantColors[raster]]>1;

Grid[List/@{"GLSL "<>ToString[version],If[successful,Style["Successful",,Bold],Style["Failed",,Bold]],graphic}]
]

TryLoadShaders[versions_List]:=
Block[{},
Grid[Partition[TryLoadShader/@versions,UpTo[4]],Spacings-> {5,5}]
]

error messages will show some useful information

$GLSLVersions={110,120,130,140,150,330,400,410,420,430,440,450,460,480};
TryLoadShaders[$GLSLVersions]

hardware GLSL compiler are picky

Plain text editor might be helpful

common mistakes

Integer and float can not be casted with each other
 texture2D is deprecated by texture in GLSL330 and after
 Include GLSL version other wise it will be consider as GLSL 1.10
 Define integer and float precisions for GLES/WebGL driver
 highp/mediump/lowp are only available for GLES/WebGL driver

What do you get: benefits

Customized rendering

Reuse GLSL resource

Move computing to hardware directly:  Reduce CPU cost

No huge data transfer through MathLink: Reduce data transfer load and memory consumption

Easier to add new features

More people can contribute 
 You make it work on one machine, we are responsible to make it work on all machines

More questions?

yuzhu@wolfram.com