Die einfachste Möglichkeit aus der Applikation mit dem Shader zu kommunizieren ist einfach über den OpenGL-Kontext (state). Dieser steht dem Shader in vollem Umfang zur Verfügung, allerdings ist das nicht immer der sinnvollste Weg, zudem der Kontext keine beliebigen Felder hat, und das missbrauchen von nicht benötigten Feldern des Kontextes würde wohl von den meisten Programmierern aus äußerst unsauber empfunden werden.
Glücklicherweise erlaubt GLSL die Definition von Benutzerdefinierten Variablen die die Applikation schreiben und auf diese Weise mit dem Shader kommunizieren kann. Hierzu werden zwei der Qualifier welche in 4.3.2 beschrieben wurden verwendet, nämlich attribute und uniform.
Uniform-Variablen zeichnen sich dadurch aus dass sie innerhalb eines Streams - sprich innerhalb eines glBegin() und glEnd() Blockes - nicht geändert werden können, dies impliziert auch dass sie nicht geeignet sind Vertexattribute zu beinhalten. Sie sind deshalb nur geeignet Werte zu halten welche über einen Stream, eine komplette Szene oder gar einen kompletten Frame konstant bleiben.
Attribute-Variablen hingegen können jederzeit geändert werden, allerdings ist das natürlich kostspieliger da der geladene Treiber keinerlei Optimierungen der Stream-Daten vornehmen kann. Auch können sie nur innerhalb eines Vertex Shaders gelesen werden da sie sich auf Vertex-Informationen beschränken und folglich im Fragment Shader nutzlos wären.
Ein anderer Weg auf dem die Applikation mit dem Shader kommunizieren kann ist die benötigten Daten in Texturen zu laden, da diese nicht unbedingt als Bilddaten vom Shader interpretiert werden müssen. Tatsächlich kann man so sehr einfach verschiedene Effekte erzeugen, zum Beispiel kann ein Vertex Shader welcher die Bilddaten als Höheninformation interpretiert sehr einfach ein Heightfield darstellen, oder ein Fragment Shader kann die Textur als Bump- oder Normalmap interpretieren.