OLD | NEW |
| (Empty) |
1 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" | |
2 "http://www.w3.org/TR/html4/loose.dtd"> | |
3 <html> | |
4 <head> | |
5 <title>WebGL texImage2D conformance test.</title> | |
6 <script src="../../../resources/js-test.js"></script> | |
7 <script src="resources/webgl-test.js"> </script> | |
8 <script src="resources/webgl-test-utils.js"> </script> | |
9 </head> | |
10 <body> | |
11 <canvas id="example" width="256" height="16" style="width: 256px; height: 48px;"
></canvas> | |
12 <div id="description"></div> | |
13 <div id="console"></div> | |
14 <script> | |
15 description("Test texImage2D conversions."); | |
16 var wtu = WebGLTestUtils; | |
17 var canvas = document.getElementById("example"); | |
18 var gl = wtu.create3DContext(canvas); | |
19 var program = wtu.setupTexturedQuad(gl); | |
20 | |
21 glErrorShouldBe(gl, gl.NO_ERROR, "Should be no errors from setup."); | |
22 | |
23 var imgURLs = [ | |
24 'resources/gray-ramp-256-with-128-alpha.png', | |
25 'resources/gray-ramp-256.png', | |
26 'resources/gray-ramp-default-gamma.png', | |
27 'resources/gray-ramp-gamma0.1.png', | |
28 'resources/gray-ramp-gamma1.0.png', | |
29 'resources/gray-ramp-gamma2.0.png', | |
30 'resources/gray-ramp-gamma4.0.png', | |
31 'resources/gray-ramp-gamma9.0.png', | |
32 'resources/gray-ramp.png', | |
33 'resources/zero-alpha.png', | |
34 'resources/3x3.png', | |
35 'resources/blue-1x1.jpg', | |
36 'resources/red-indexed.png', | |
37 'resources/green-2x2-16bit.png', | |
38 'resources/small-square-with-colorspin-profile.jpg', | |
39 'resources/small-square-with-colorspin-profile.png', | |
40 'resources/small-square-with-cie-rgb-profile.png', | |
41 'resources/small-square-with-colormatch-profile.png', | |
42 'resources/small-square-with-e-srgb-profile.png', | |
43 'resources/small-square-with-smpte-c-profile.png', | |
44 'resources/small-square-with-srgb-iec61966-2.1-profile.png']; | |
45 | |
46 | |
47 wtu.loadImagesAsync(imgURLs, runTests); | |
48 | |
49 function runTests(imgs) { | |
50 var loc = gl.getUniformLocation(program, "tex"); | |
51 gl.uniform1i(loc, 0); | |
52 | |
53 gl.disable(gl.BLEND); | |
54 gl.disable(gl.DEPTH_TEST); | |
55 | |
56 var width = canvas.width; | |
57 var height = canvas.height; | |
58 | |
59 function checkPixel(buf, x, y, color) { | |
60 var off = (y * width + x) * 4; | |
61 var msg = "pixel " + x + ", " + y + " should be " + | |
62 color[0] + ", " + | |
63 color[1] + ", " + | |
64 color[2] + ", " + | |
65 color[3] + " was " + | |
66 buf[off + 0] + ", " + | |
67 buf[off + 1] + ", " + | |
68 buf[off + 2] + ", " + | |
69 buf[off + 3]; | |
70 | |
71 for (var ii = 0; ii < 4; ++ii) { | |
72 if (buf[off + ii] != color[ii]) { | |
73 testFailed(msg); | |
74 return; | |
75 } | |
76 } | |
77 testPassed(msg); | |
78 } | |
79 | |
80 function checkPixelRange(buf, x, y, color, allowedRange) { | |
81 var off = (y * width + x) * 4; | |
82 var msg = "pixel " + x + ", " + y + " should be within " + | |
83 allowedRange + " units of " + | |
84 color[0] + ", " + | |
85 color[1] + ", " + | |
86 color[2] + ", " + | |
87 color[3]; | |
88 var subMsg = " was " + | |
89 buf[off + 0] + ", " + | |
90 buf[off + 1] + ", " + | |
91 buf[off + 2] + ", " + | |
92 buf[off + 3]; | |
93 // When running in WebKit's test harness, we don't want to print the | |
94 // pixel value when the test passes, because different machines might | |
95 // have different results and we record the text output. | |
96 var inDumpRenderTree = window.testRunner; | |
97 for (var ii = 0; ii < 4; ++ii) { | |
98 if (Math.abs(buf[off + ii] - color[ii]) > allowedRange) { | |
99 testFailed(msg + subMsg); | |
100 return; | |
101 } | |
102 } | |
103 testPassed(msg + (inDumpRenderTree ? "" : subMsg)); | |
104 } | |
105 | |
106 var tex = gl.createTexture(); | |
107 gl.bindTexture(gl.TEXTURE_2D, tex); | |
108 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); | |
109 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); | |
110 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); | |
111 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); | |
112 | |
113 var buf = new Uint8Array(width * height * 4); | |
114 | |
115 debug(""); | |
116 debug("check pixels are NOT pre-multiplied"); | |
117 gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, gl.RGB, gl.UNSIGNED_BYTE, | |
118 imgs['resources/zero-alpha.png']); | |
119 glErrorShouldBe(gl, gl.NO_ERROR, "Should be no errors from setup"); | |
120 wtu.drawQuad(gl); | |
121 gl.readPixels(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, buf); | |
122 | |
123 var left = 0; | |
124 var middle = Math.floor(width / 2); | |
125 var right = width - 1; | |
126 var bottom = 0; | |
127 var center = Math.floor(height / 2); | |
128 var top = height - 1; | |
129 checkPixel(buf, left, top, [ 0, 0, 0, 255]); | |
130 checkPixel(buf, middle, top, [255, 0, 255, 255]); | |
131 checkPixel(buf, right, top, [ 0, 0, 255, 255]); | |
132 checkPixel(buf, left, center, [128, 128, 128, 255]); | |
133 checkPixel(buf, middle, center, [255, 255, 255, 255]); | |
134 checkPixel(buf, right, center, [ 0, 255, 255, 255]); | |
135 checkPixel(buf, left, bottom, [255, 0, 0, 255]); | |
136 checkPixel(buf, middle, bottom, [255, 255, 0, 255]); | |
137 checkPixel(buf, right, bottom, [ 0, 255, 0, 255]); | |
138 | |
139 debug(""); | |
140 debug("check quantization"); | |
141 var quantInfo = [ | |
142 {format: gl.RGBA, type: gl.UNSIGNED_BYTE, counts: [256, 256, 256, 2
56]}, | |
143 {format: gl.RGBA, type: gl.UNSIGNED_SHORT_4_4_4_4, counts: [ 16, 16, 16,
16]}, | |
144 {format: gl.RGB, type: gl.UNSIGNED_SHORT_5_6_5, counts: [ 32, 64, 32,
1]}, | |
145 {format: gl.RGBA, type: gl.UNSIGNED_SHORT_5_5_5_1, counts: [ 32, 32, 32,
2]}]; | |
146 for (var qq = 0; qq < quantInfo.length; ++qq) { | |
147 var info = quantInfo[qq]; | |
148 gl.texImage2D( | |
149 gl.TEXTURE_2D, 0, info.format, info.format, info.type, | |
150 imgs['resources/gray-ramp-256.png']); | |
151 glErrorShouldBe(gl, gl.NO_ERROR, "Should be no errors from setup."); | |
152 wtu.drawQuad(gl); | |
153 gl.readPixels(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, buf); | |
154 var counts = [{ }, { }, { }, { }]; | |
155 var numUniqueValues = [0, 0, 0, 0]; | |
156 // Count the number of unique values in each channel. | |
157 for (var ii = 0; ii < width * height * 4; ii += 4) { | |
158 for (var jj = 0; jj < 4; ++jj) { | |
159 var v = buf[ii + jj]; | |
160 if (!counts[jj][v]) { | |
161 counts[jj][v] = 1; | |
162 ++numUniqueValues[jj]; | |
163 } else { | |
164 ++counts[jj][v]; | |
165 } | |
166 } | |
167 } | |
168 for (var ii = 0; ii < 4; ++ii) { | |
169 assertMsg(numUniqueValues[ii] == info.counts[ii], | |
170 "There should be " + info.counts[ii] + | |
171 " unique values in channel " + ii + ". Found " + | |
172 numUniqueValues[ii]); | |
173 } | |
174 } | |
175 | |
176 debug(""); | |
177 debug("Check that gamma settings don't effect 8bit pngs"); | |
178 gl.pixelStorei(gl.UNPACK_COLORSPACE_CONVERSION_WEBGL, gl.NONE); | |
179 gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, gl.RGB, gl.UNSIGNED_BYTE, | |
180 imgs['resources/gray-ramp-default-gamma.png']); | |
181 glErrorShouldBe(gl, gl.NO_ERROR, "Should be no errors from setup."); | |
182 wtu.drawQuad(gl); | |
183 var ref = new Uint8Array(width * height * 4); | |
184 gl.readPixels(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, ref); | |
185 | |
186 var gammaImages = [ | |
187 'resources/gray-ramp-gamma0.1.png', | |
188 'resources/gray-ramp-gamma1.0.png', | |
189 'resources/gray-ramp-gamma2.0.png', | |
190 'resources/gray-ramp-gamma4.0.png', | |
191 'resources/gray-ramp-gamma9.0.png']; | |
192 for (var ii = 0; ii < gammaImages.length; ++ii) { | |
193 gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, gl.RGB, gl.UNSIGNED_BYTE, | |
194 imgs[gammaImages[ii]]); | |
195 wtu.drawQuad(gl); | |
196 gl.readPixels(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, buf); | |
197 var same = true; | |
198 for (var jj = 0; jj < width * height * 4; ++jj) { | |
199 if (buf[jj] != ref[jj]) { | |
200 same = false; | |
201 break; | |
202 } | |
203 } | |
204 assertMsg(same, "pixels should be same regardless of gamma settings."); | |
205 } | |
206 | |
207 debug(""); | |
208 debug("check pixels are UN pre-multiplied"); | |
209 for (var ii = 0; ii < 2; ++ii) { | |
210 gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE,
null); | |
211 if (ii == 0) { | |
212 var canvas2d = document.createElement("canvas"); | |
213 canvas2d.width = 256; | |
214 canvas2d.height = 1; | |
215 var ctx = canvas2d.getContext("2d"); | |
216 ctx.drawImage(imgs['resources/gray-ramp-256-with-128-alpha.png'], 0, 0); | |
217 gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, gl.RGB, gl.UNSIGNED_BYTE, canvas2d
); | |
218 } else { | |
219 gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, gl.RGB, gl.UNSIGNED_BYTE, | |
220 imgs['resources/gray-ramp-256-with-128-alpha.png']); | |
221 } | |
222 glErrorShouldBe(gl, gl.NO_ERROR, "Should be no errors from setup."); | |
223 wtu.drawQuad(gl); | |
224 var buf = new Uint8Array(width * height * 4); | |
225 gl.readPixels(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, buf); | |
226 var lt128Count = [0, 0, 0]; | |
227 var ge128Count = [0, 0, 0]; | |
228 for (var jj = 0; jj < width; ++jj) { | |
229 var off = jj * 4; | |
230 for (var cc = 0; cc < 3; ++cc) { | |
231 if (buf[off + cc] < 128) { | |
232 ++lt128Count[cc]; | |
233 } else { | |
234 ++ge128Count[cc]; | |
235 } | |
236 } | |
237 } | |
238 // Not sure the exact count here because gamma does effect drawing into the | |
239 // canvas but it should be close to 50% so I'll pass 45% | |
240 for (var jj = 0; jj < 3; ++jj) { | |
241 // Only display the actual percentage string when outside of the test | |
242 // harness, to prevent safe variation from causing failures. | |
243 var inDumpRenderTree = window.testRunner; | |
244 assertMsg(ge128Count[jj] > 256 * 0.45, | |
245 "Half the pixels in channel " + jj + | |
246 " should be >= 128,128,128. " + | |
247 (!inDumpRenderTree ? "found " + | |
248 ((ge128Count[jj] / 256) * 100).toFixed() + "%" : "")); | |
249 assertMsg(lt128Count[jj] > 256 * 0.45, | |
250 "Half the pixels in channel " + jj + | |
251 " should be < 128,128,128. " + | |
252 (!inDumpRenderTree ? "found " + | |
253 ((lt128Count[jj] / 256) * 100).toFixed() + "%" : "")); | |
254 } | |
255 } | |
256 | |
257 debug(""); | |
258 debug("check canvas pixels are UN pre-multiplied"); | |
259 var canvas2d = document.createElement("canvas"); | |
260 canvas2d.width = 1; | |
261 canvas2d.height = 1; | |
262 var ctx = canvas2d.getContext("2d"); | |
263 ctx.fillStyle ="rgba(255,255,255,0.5)"; | |
264 ctx.fillRect(0, 0, 256, 1); | |
265 gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, canvas2d); | |
266 wtu.drawQuad(gl); | |
267 gl.readPixels(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, buf); | |
268 glErrorShouldBe(gl, gl.NO_ERROR, "Should be no errors from setup."); | |
269 checkPixelRange(buf, 0, 0, [255, 255, 255, 127], 4); | |
270 | |
271 debug(""); | |
272 debug("check canvas pixels are pre-multiplied"); | |
273 gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, true); | |
274 gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, canvas2d); | |
275 wtu.drawQuad(gl); | |
276 gl.readPixels(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, buf); | |
277 glErrorShouldBe(gl, gl.NO_ERROR, "Should be no errors from setup."); | |
278 checkPixelRange(buf, 0, 0, [127, 127, 127, 127], 4); | |
279 | |
280 | |
281 debug(""); | |
282 debug("check pixels are pre-multiplied"); | |
283 gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, true); | |
284 // TODO(gman): use different texture that won't pass on failure | |
285 gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, | |
286 imgs['resources/zero-alpha.png']); | |
287 glErrorShouldBe(gl, gl.NO_ERROR, "Should be no errors from setup"); | |
288 wtu.drawQuad(gl); | |
289 gl.readPixels(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, buf); | |
290 | |
291 var same = true; | |
292 for (var jj = 0; jj < width * height * 4; ++jj) { | |
293 if (buf[jj] != 0) { | |
294 same = false; | |
295 break; | |
296 } | |
297 } | |
298 assertMsg(same, "pixels should all be 0."); | |
299 | |
300 debug(""); | |
301 debug("check pixels are flipped"); | |
302 gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, false); | |
303 gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true); | |
304 gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, gl.RGB, gl.UNSIGNED_BYTE, | |
305 imgs['resources/3x3.png']); | |
306 glErrorShouldBe(gl, gl.NO_ERROR, "Should be no errors from setup"); | |
307 wtu.drawQuad(gl); | |
308 gl.readPixels(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, buf); | |
309 | |
310 checkPixel(buf, left, top, [255, 0, 0, 255]); | |
311 checkPixel(buf, middle, top, [255, 255, 0, 255]); | |
312 checkPixel(buf, right, top, [255, 0, 0, 255]); | |
313 checkPixel(buf, left, center, [255, 0, 255, 255]); | |
314 checkPixel(buf, middle, center, [255, 0, 0, 255]); | |
315 checkPixel(buf, right, center, [ 0, 255, 0, 255]); | |
316 checkPixel(buf, left, bottom, [ 0, 0, 0, 255]); | |
317 checkPixel(buf, middle, bottom, [ 0, 0, 255, 255]); | |
318 checkPixel(buf, right, bottom, [255, 0, 0, 255]); | |
319 | |
320 debug(""); | |
321 debug("check uploading of images with no alpha channel works"); | |
322 gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, false); | |
323 gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, false); | |
324 gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, gl.RGB, gl.UNSIGNED_BYTE, | |
325 imgs['resources/blue-1x1.jpg']); | |
326 glErrorShouldBe(gl, gl.NO_ERROR, "Should be no errors from setup"); | |
327 wtu.drawQuad(gl); | |
328 gl.readPixels(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, buf); | |
329 checkPixelRange(buf, middle, center, [ 0, 0, 255, 255], 10); | |
330 glErrorShouldBe(gl, gl.NO_ERROR, "Should be no errors"); | |
331 | |
332 debug(""); | |
333 debug("check uploading of 16-bit images"); | |
334 gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, false); | |
335 gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, false); | |
336 gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, gl.RGB, gl.UNSIGNED_BYTE, | |
337 imgs['resources/green-2x2-16bit.png']); | |
338 glErrorShouldBe(gl, gl.NO_ERROR, "Should be no errors from setup"); | |
339 wtu.drawQuad(gl); | |
340 gl.readPixels(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, buf); | |
341 checkPixelRange(buf, middle, center, [ 15, 121, 0, 255], 10); | |
342 glErrorShouldBe(gl, gl.NO_ERROR, "Should be no errors"); | |
343 | |
344 debug(""); | |
345 debug("check uploading of images with ICC profiles"); | |
346 gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, false); | |
347 gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, false); | |
348 gl.pixelStorei(gl.UNPACK_COLORSPACE_CONVERSION_WEBGL, gl.NONE); | |
349 | |
350 gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, gl.RGB, gl.UNSIGNED_BYTE, | |
351 imgs['resources/small-square-with-colorspin-profile.jpg']); | |
352 glErrorShouldBe(gl, gl.NO_ERROR, "Should be no errors from setup"); | |
353 wtu.drawQuad(gl); | |
354 gl.readPixels(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, buf); | |
355 // The image is red. However, if we ignore the color profile, it is blue. | |
356 checkPixelRange(buf, middle, center, [ 0, 0, 255, 255], 10); | |
357 | |
358 gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, gl.RGB, gl.UNSIGNED_BYTE, | |
359 imgs['resources/small-square-with-colorspin-profile.png']); | |
360 glErrorShouldBe(gl, gl.NO_ERROR, "Should be no errors from setup"); | |
361 wtu.drawQuad(gl); | |
362 gl.readPixels(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, buf); | |
363 // The image is red. However, if we ignore the color profile, it is blue. | |
364 checkPixelRange(buf, middle, center, [ 0, 0, 255, 255], 10); | |
365 | |
366 var iccPNGs = [ | |
367 'resources/small-square-with-cie-rgb-profile.png', | |
368 'resources/small-square-with-colormatch-profile.png', | |
369 'resources/small-square-with-e-srgb-profile.png', | |
370 'resources/small-square-with-smpte-c-profile.png', | |
371 'resources/small-square-with-srgb-iec61966-2.1-profile.png']; | |
372 for (var ii = 0; ii < iccPNGs.length; ++ii) { | |
373 var buf2 = new Uint8Array(width * height * 4); | |
374 gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, gl.RGB, gl.UNSIGNED_BYTE, | |
375 imgs[iccPNGs[ii]]); | |
376 glErrorShouldBe(gl, gl.NO_ERROR, "Should be no errors from setup"); | |
377 wtu.drawQuad(gl); | |
378 gl.readPixels(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, buf2); | |
379 glErrorShouldBe(gl, gl.NO_ERROR, "Should be no errors"); | |
380 var same = true; | |
381 for (var jj = 0; jj < buf.length; ++jj) { | |
382 if (buf[jj] != buf2[jj]) { | |
383 same = false; | |
384 break; | |
385 } | |
386 } | |
387 assertMsg(same, "uploading PNGs with same data but various ICC profiles shou
ld generate the same results"); | |
388 } | |
389 | |
390 debug(""); | |
391 debug("check uploading of indexed PNG images"); | |
392 gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, gl.RGB, gl.UNSIGNED_BYTE, | |
393 imgs['resources/red-indexed.png']); | |
394 glErrorShouldBe(gl, gl.NO_ERROR, "Should be no errors from setup"); | |
395 wtu.drawQuad(gl); | |
396 gl.readPixels(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, buf); | |
397 // The image should be red. | |
398 checkPixelRange(buf, middle, center, [ 255, 0, 0, 255 ], 10); | |
399 | |
400 debug(""); | |
401 isSuccessfullyParsed(); | |
402 } | |
403 | |
404 </script> | |
405 </body> | |
406 </html> | |
OLD | NEW |