1 <!DOCTYPE HTML PUBLIC
"-//W3C//DTD HTML 4.01 Transitional//EN"
2 "http://www.w3.org/TR/html4/loose.dtd">
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>
11 <canvas id=
"example" width=
"256" height=
"16" style=
"width: 256px; height: 48px;"></canvas>
12 <div id=
"description"></div>
13 <div id=
"console"></div>
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
);
21 glErrorShouldBe(gl
, gl
.NO_ERROR
, "Should be no errors from setup.");
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',
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'];
47 wtu
.loadImagesAsync(imgURLs
, runTests
);
49 function runTests(imgs
) {
50 var loc
= gl
.getUniformLocation(program
, "tex");
54 gl
.disable(gl
.DEPTH_TEST
);
56 var width
= canvas
.width
;
57 var height
= canvas
.height
;
59 function checkPixel(buf
, x
, y
, color
) {
60 var off
= (y
* width
+ x
) * 4;
61 var msg
= "pixel " + x
+ ", " + y
+ " should be " +
71 for (var ii
= 0; ii
< 4; ++ii
) {
72 if (buf
[off
+ ii
] != color
[ii
]) {
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 " +
88 var subMsg
= " was " +
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
);
103 testPassed(msg
+ (inDumpRenderTree
? "" : subMsg
));
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
);
113 var buf
= new Uint8Array(width
* height
* 4);
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");
121 gl
.readPixels(0, 0, width
, height
, gl
.RGBA
, gl
.UNSIGNED_BYTE
, buf
);
124 var middle
= Math
.floor(width
/ 2);
125 var right
= width
- 1;
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]);
140 debug("check quantization");
142 {format
: gl
.RGBA
, type
: gl
.UNSIGNED_BYTE
, counts
: [256, 256, 256, 256]},
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
];
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.");
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
]) {
162 ++numUniqueValues
[jj
];
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
]);
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.");
183 var ref
= new Uint8Array(width
* height
* 4);
184 gl
.readPixels(0, 0, width
, height
, gl
.RGBA
, gl
.UNSIGNED_BYTE
, ref
);
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
]]);
196 gl
.readPixels(0, 0, width
, height
, gl
.RGBA
, gl
.UNSIGNED_BYTE
, buf
);
198 for (var jj
= 0; jj
< width
* height
* 4; ++jj
) {
199 if (buf
[jj
] != ref
[jj
]) {
204 assertMsg(same
, "pixels should be same regardless of gamma settings.");
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);
212 var canvas2d
= document
.createElement("canvas");
213 canvas2d
.width
= 256;
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
);
219 gl
.texImage2D(gl
.TEXTURE_2D
, 0, gl
.RGB
, gl
.RGB
, gl
.UNSIGNED_BYTE
,
220 imgs
['resources/gray-ramp-256-with-128-alpha.png']);
222 glErrorShouldBe(gl
, gl
.NO_ERROR
, "Should be no errors from setup.");
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
) {
230 for (var cc
= 0; cc
< 3; ++cc
) {
231 if (buf
[off
+ cc
] < 128) {
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() + "%" : ""));
258 debug("check canvas pixels are UN pre-multiplied");
259 var canvas2d
= document
.createElement("canvas");
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
);
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);
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
);
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);
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");
289 gl
.readPixels(0, 0, width
, height
, gl
.RGBA
, gl
.UNSIGNED_BYTE
, buf
);
292 for (var jj
= 0; jj
< width
* height
* 4; ++jj
) {
298 assertMsg(same
, "pixels should all be 0.");
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");
308 gl
.readPixels(0, 0, width
, height
, gl
.RGBA
, gl
.UNSIGNED_BYTE
, buf
);
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]);
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");
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");
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");
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");
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
);
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");
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);
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");
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);
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
,
376 glErrorShouldBe(gl
, gl
.NO_ERROR
, "Should be no errors from setup");
378 gl
.readPixels(0, 0, width
, height
, gl
.RGBA
, gl
.UNSIGNED_BYTE
, buf2
);
379 glErrorShouldBe(gl
, gl
.NO_ERROR
, "Should be no errors");
381 for (var jj
= 0; jj
< buf
.length
; ++jj
) {
382 if (buf
[jj
] != buf2
[jj
]) {
387 assertMsg(same
, "uploading PNGs with same data but various ICC profiles should generate the same results");
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");
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);
401 isSuccessfullyParsed();