5 <title>WebGL Program Compiling/Linking Conformance Test
</title>
6 <script src=
"../../../resources/js-test.js" type=
"text/javascript"></script>
7 <script src=
"resources/webgl-test.js" type=
"text/javascript"></script>
10 <div id=
"description"></div>
11 <div id=
"console"></div>
12 <canvas id=
"canvas" width=
"2" height=
"2"> </canvas>
13 <script type=
"text/javascript">
15 description("Tests that program compiling/linking/using works correctly.");
18 debug("Canvas.getContext");
21 window
.internals
.settings
.setWebGLErrorsToConsoleEnabled(false);
23 var gl
= create3DContext(document
.getElementById("canvas"));
25 testFailed("context does not exist");
29 testPassed("context exists");
31 gl
.clearColor(0.0, 0.0, 0.0, 0.0);
32 gl
.clear(gl
.COLOR_BUFFER_BIT
| gl
.DEPTH_BUFFER_BIT
);
34 function doArraysHaveSameContents(a
, b
) {
36 function hasUnusedValue(a
, value
) {
37 for (var ii
= 0; ii
< a
.length
; ++ii
) {
38 if (a
[ii
] === value
&& !flags
[ii
]) {
47 if (a
.length
!== b
.length
) {
50 for (var ii
= 0; ii
< a
.length
; ii
++) {
51 if (!hasUnusedValue(b
, a
[ii
])) {
61 /////// Check compileShader() /////////////////////////////
63 var vs
= gl
.createShader(gl
.VERTEX_SHADER
);
64 gl
.shaderSource(vs
, "attribute vec4 aVertex; attribute vec4 aColor; varying vec4 vColor; void main() { vColor = aColor; gl_Position = aVertex; }");
67 assertMsg(gl
.getShaderParameter(vs
, gl
.COMPILE_STATUS
) == true,
68 "good vertex shader should compile");
70 var vs2
= gl
.createShader(gl
.VERTEX_SHADER
);
71 gl
.shaderSource(vs2
, "attribute vec4 aVertex; attribute vec4 aColor; varying vec4 vColor; void main() { vColor = aColor; gl_Position = aVertex * 0.5; }");
72 gl
.compileShader(vs2
);
74 assertMsg(gl
.getShaderParameter(vs2
, gl
.COMPILE_STATUS
) == true,
75 "good vertex shader #2 should compile");
77 var vsBad
= gl
.createShader(gl
.VERTEX_SHADER
);
78 gl
.shaderSource(vsBad
, "WILL NOT COMPILE;");
79 gl
.compileShader(vsBad
);
81 assertMsg(gl
.getShaderParameter(vsBad
, gl
.COMPILE_STATUS
) == false,
82 "bad vertex shader should fail to compile");
84 var fs
= gl
.createShader(gl
.FRAGMENT_SHADER
);
85 gl
.shaderSource(fs
, "precision mediump float; varying vec4 vColor; void main() { gl_FragColor = vColor; }");
88 assertMsg(gl
.getShaderParameter(fs
, gl
.COMPILE_STATUS
) == true,
89 "good fragment shader should compile");
91 var fs2
= gl
.createShader(gl
.FRAGMENT_SHADER
);
92 gl
.shaderSource(fs2
, "precision mediump float; varying vec4 vColor; void main() { gl_FragColor = vColor * 0.5; }");
93 gl
.compileShader(fs2
);
95 assertMsg(gl
.getShaderParameter(fs2
, gl
.COMPILE_STATUS
) == true,
96 "good fragment shader #2 should compile");
98 var fsBad
= gl
.createShader(gl
.FRAGMENT_SHADER
);
99 gl
.shaderSource(fsBad
, "WILL NOT COMPILE;");
100 gl
.compileShader(fsBad
);
102 assertMsg(gl
.getShaderParameter(fsBad
, gl
.COMPILE_STATUS
) == false,
103 "bad fragment shader should fail to compile");
105 glErrorShouldBe(gl
, gl
.NO_ERROR
, "should be no errors at this point");
107 /////// Check attachShader() /////////////////////////////
109 function checkAttachShader(already_attached_shaders
, shader
, expected_error_code
, errmsg
) {
110 var prog
= gl
.createProgram();
111 for (var i
= 0; i
< already_attached_shaders
.length
; ++i
)
112 gl
.attachShader(prog
, already_attached_shaders
[i
]);
113 if(gl
.getError() != gl
.NO_ERROR
)
114 assertMsg(false, "unexpected error in attachShader()");
115 gl
.attachShader(prog
, shader
);
116 glErrorShouldBe(gl
, expected_error_code
, errmsg
);
119 checkAttachShader([], vs
, gl
.NO_ERROR
, "attaching a vertex shader should succeed");
120 checkAttachShader([vs
], vs
, gl
.INVALID_OPERATION
,
121 "attaching an already attached vertex shader should generate INVALID_OPERATION");
122 checkAttachShader([], fs
, gl
.NO_ERROR
, "attaching a fragment shader should succeed");
123 checkAttachShader([fs
], fs
, gl
.INVALID_OPERATION
,
124 "attaching an already attached fragment shader should generate INVALID_OPERATION");
125 checkAttachShader([vs
], vs2
, gl
.INVALID_OPERATION
,
126 "attaching shaders of the same type to a program should generate INVALID_OPERATION");
127 checkAttachShader([fs
], fs2
, gl
.INVALID_OPERATION
,
128 "attaching shaders of the same type to a program should generate INVALID_OPERATION");
130 /////// Check detachShader() /////////////////////////////
132 function checkDetachShader(already_attached_shaders
, shader
, expected_error_code
, errmsg
) {
133 var prog
= gl
.createProgram();
134 for (var i
= 0; i
< already_attached_shaders
.length
; ++i
)
135 gl
.attachShader(prog
, already_attached_shaders
[i
]);
136 if(gl
.getError() != gl
.NO_ERROR
)
137 assertMsg(false, "unexpected error in attachShader()");
138 gl
.detachShader(prog
, shader
);
139 glErrorShouldBe(gl
, expected_error_code
, errmsg
);
142 checkDetachShader([vs
], vs
, gl
.NO_ERROR
, "detaching a vertex shader should succeed");
143 checkDetachShader([fs
], vs
, gl
.INVALID_OPERATION
,
144 "detaching a not already attached vertex shader should generate INVALID_OPERATION");
145 checkDetachShader([fs
], fs
, gl
.NO_ERROR
, "detaching a fragment shader should succeed");
146 checkDetachShader([vs
], fs
, gl
.INVALID_OPERATION
,
147 "detaching a not already attached fragment shader should generate INVALID_OPERATION");
149 /////// Check getAttachedShaders() /////////////////////////////
151 function checkGetAttachedShaders(shaders_to_attach
, shaders_to_detach
, expected_shaders
, errmsg
) {
152 var prog
= gl
.createProgram();
153 for (var i
= 0; i
< shaders_to_attach
.length
; ++i
)
154 gl
.attachShader(prog
, shaders_to_attach
[i
]);
155 if(gl
.getError() != gl
.NO_ERROR
)
156 assertMsg(false, "unexpected error in attachShader()");
157 for (var i
= 0; i
< shaders_to_detach
.length
; ++i
)
158 gl
.detachShader(prog
, shaders_to_detach
[i
]);
159 if(gl
.getError() != gl
.NO_ERROR
)
160 assertMsg(false, "unexpected error in detachShader()");
161 assertMsg(doArraysHaveSameContents(gl
.getAttachedShaders(prog
), expected_shaders
), errmsg
);
163 checkGetAttachedShaders([], [], [], "getAttachedShaders should return an empty list by default");
164 checkGetAttachedShaders([fs
], [], [fs
], "attaching a single shader should give the expected list");
165 checkGetAttachedShaders([fs
, vs
], [], [fs
, vs
],
166 "attaching some shaders should give the expected list");
167 checkGetAttachedShaders([fs
], [fs
], [], "attaching a shader and detaching it shoud leave an empty list");
168 checkGetAttachedShaders([fs
, vs
], [fs
, vs
], [],
169 "attaching some shaders and detaching them in same order shoud leave an empty list");
170 checkGetAttachedShaders([fs
, vs
], [vs
, fs
], [],
171 "attaching some shaders and detaching them in random order shoud leave an empty list");
172 checkGetAttachedShaders([fs
, vs
], [vs
], [fs
],
173 "attaching and detaching some shaders should leave the difference list");
174 checkGetAttachedShaders([fs
, vs
], [fs
], [vs
],
175 "attaching and detaching some shaders should leave the difference list");
176 checkGetAttachedShaders([fsBad
], [], [fsBad
],
177 "attaching a shader that failed to compile should still show it in the list");
178 checkGetAttachedShaders([fs
, vsBad
], [], [fs
, vsBad
],
179 "attaching shaders, including one that failed to compile, should still show the it in the list");
181 /////// Check linkProgram() and useProgram /////////////////////////////
183 function checkLinkAndUse(shaders
, deleteShaderAfterAttach
, expected_status
, errmsg
) {
184 var prog
= gl
.createProgram();
185 for (var i
= 0; i
< shaders
.length
; ++i
) {
186 gl
.attachShader(prog
, shaders
[i
]);
187 if (deleteShaderAfterAttach
)
188 gl
.deleteShader(shaders
[i
]);
190 gl
.bindAttribLocation(prog
, 0, "aVertex");
191 gl
.bindAttribLocation(prog
, 1, "aColor");
192 gl
.linkProgram(prog
);
193 if (gl
.getError() != gl
.NO_ERROR
)
194 assertMsg(false, "unexpected error in linkProgram()");
195 assertMsg(gl
.getProgramParameter(prog
, gl
.LINK_STATUS
) == expected_status
, errmsg
);
196 if (expected_status
== true && gl
.getProgramParameter(prog
, gl
.LINK_STATUS
) == false)
197 debug(gl
.getProgramInfoLog(prog
));
198 if (gl
.getError() != gl
.NO_ERROR
)
199 assertMsg(false, "unexpected error in getProgramParameter()");
201 if (expected_status
== true)
202 glErrorShouldBe(gl
, gl
.NO_ERROR
, "using a valid program should succeed");
203 if (expected_status
== false)
204 glErrorShouldBe(gl
, gl
.INVALID_OPERATION
, "using an invalid program should generate INVALID_OPERATION");
208 var progGood1
= checkLinkAndUse([vs
, fs
], false, true, "valid program should link");
209 var progGood2
= checkLinkAndUse([vs
, fs2
], false, true, "valid program #2 should link");
210 var progBad1
= checkLinkAndUse([vs
], false, false, "program with no fragment shader should fail to link");
211 var progBad2
= checkLinkAndUse([fs
], false, false, "program with no vertex shader should fail to link");
212 var progBad3
= checkLinkAndUse([vsBad
, fs
], false, false, "program with bad vertex shader should fail to link");
213 var progBad4
= checkLinkAndUse([vs
, fsBad
], false, false, "program with bad fragment shader should fail to link");
214 var progBad5
= checkLinkAndUse([vsBad
, fsBad
], false, false, "program with bad shaders should fail to link");
216 gl
.useProgram(progGood1
);
217 glErrorShouldBe(gl
, gl
.NO_ERROR
, "using a valid program shouldn't generate a GL error");
219 var vbuf
= gl
.createBuffer();
220 gl
.bindBuffer(gl
.ARRAY_BUFFER
, vbuf
);
221 gl
.bufferData(gl
.ARRAY_BUFFER
,
226 0.0, 1.0, 0.0, 1.0]),
228 gl
.vertexAttribPointer(0, 4, gl
.FLOAT
, false, 0, 0);
229 gl
.enableVertexAttribArray(0);
230 gl
.vertexAttrib3f(1, 1.0, 0.0, 0.0);
232 glErrorShouldBe(gl
, gl
.NO_ERROR
, "should be no errors at this point #2");
234 gl
.useProgram(progGood1
);
235 gl
.drawArrays(gl
.TRIANGLES
, 0, 3);
236 glErrorShouldBe(gl
, gl
.NO_ERROR
, "drawing with a valid program shouldn't generate a GL error");
238 gl
.useProgram(progBad1
);
239 glErrorShouldBe(gl
, gl
.INVALID_OPERATION
, "using an invalid program should generate INVALID_OPERATION");
240 gl
.drawArrays(gl
.TRIANGLES
, 0, 3);
241 glErrorShouldBe(gl
, gl
.NO_ERROR
, "Try to use an invalid program should not change the current rendering state");
243 gl
.useProgram(progGood2
);
244 gl
.drawArrays(gl
.TRIANGLES
, 0, 3);
245 glErrorShouldBe(gl
, gl
.NO_ERROR
, "drawing with a valid program shouldn't generate a GL error");
246 gl
.detachShader(progGood2
, fs2
);
247 gl
.attachShader(progGood2
, fsBad
);
248 gl
.linkProgram(progGood2
);
249 assertMsg(gl
.getProgramParameter(progGood2
, gl
.LINK_STATUS
) == false,
250 "linking should fail with in-use formerly good program, with new bad shader attached");
252 gl
.useProgram(progGood1
);
253 gl
.drawArrays(gl
.TRIANGLES
, 0, 4);
254 glErrorShouldBe(gl
, gl
.NO_ERROR
, "drawing with a valid when last used program shouldn't generate a GL error");
256 var progGood1
= checkLinkAndUse([vs
, fs
], true, true, "delete shaders after attaching them and before linking program should not affect linkProgram");
257 gl
.useProgram(progGood1
);
258 gl
.drawArrays(gl
.TRIANGLES
, 0, 4);
259 glErrorShouldBe(gl
, gl
.NO_ERROR
, "drawing with a valid when last used program shouldn't generate a GL error");
261 /////// Check deleteProgram() and deleteShader() /////////////////////////////
263 gl
.useProgram(progGood1
);
264 gl
.deleteProgram(progGood1
);
265 gl
.drawArrays(gl
.TRIANGLES
, 0, 4);
266 glErrorShouldBe(gl
, gl
.NO_ERROR
, "delete the current program shouldn't change the current rendering state");
268 gl
.linkProgram(progGood1
);
269 glErrorShouldBe(gl
, gl
.NO_ERROR
, "The current program shouldn't be deleted");
271 var fs3
= gl
.createShader(gl
.FRAGMENT_SHADER
);
272 gl
.shaderSource(fs3
, "precision mediump float; varying vec4 vColor; void main() { gl_FragColor = vColor; }");
273 gl
.compileShader(fs3
);
275 assertMsg(gl
.getShaderParameter(fs3
, gl
.COMPILE_STATUS
) == true,
276 "good fragment shader should compile");
278 gl
.deleteShader(fs3
);
279 gl
.compileShader(fs3
);
280 glErrorShouldBe(gl
, gl
.INVALID_VALUE
, "an unattached shader should be deleted immediately");
282 fs3
= gl
.createShader(gl
.FRAGMENT_SHADER
);
283 gl
.shaderSource(fs3
, "precision mediump float; varying vec4 vColor; void main() { gl_FragColor = vColor; }");
284 gl
.compileShader(fs3
);
286 assertMsg(gl
.getShaderParameter(fs3
, gl
.COMPILE_STATUS
) == true,
287 "good fragment shader should compile");
289 gl
.detachShader(progGood1
, fs
);
290 gl
.attachShader(progGood1
, fs3
);
292 gl
.deleteShader(fs3
);
293 gl
.compileShader(fs3
);
294 assertMsg(gl
.getShaderParameter(fs3
, gl
.COMPILE_STATUS
) == true,
295 "an attached shader shouldn't be deleted");
298 gl
.linkProgram(progGood1
);
299 glErrorShouldBe(gl
, gl
.INVALID_VALUE
, "a delete-marked program should be deleted once it's no longer the current program");
301 gl
.compileShader(fs3
);
302 glErrorShouldBe(gl
, gl
.INVALID_VALUE
, "a delete-marked shader should be deleted once all its attachments are removed");