2 Copyright (c) 2019 The Khronos Group Inc.
3 Use of this source code is governed by an MIT-style license that can be
4 found in the LICENSE.txt file.
10 <meta charset=
"utf-8">
11 <link rel=
"stylesheet" href=
"../../resources/js-test-style.css"/>
12 <script src=
"../../js/js-test-pre.js"></script>
13 <script src=
"../../js/webgl-test-utils.js"></script>
14 <title>WebGL WEBGL_compressed_texture_pvrtc Conformance Tests
</title>
17 border:
1px solid black;
34 <div id=
"description"></div>
35 <canvas id=
"canvas" width=
"8" height=
"8" style=
"width: 8px; height: 8px;"></canvas>
36 <div id=
"console"></div>
39 description("This test verifies the functionality of the WEBGL_compressed_texture_pvrtc extension, if it is available.");
43 var pvrtc_4x4_2bpp
= new Uint8Array([
44 0x77, 0x22, 0x77, 0x22, 0xbb, 0x2b, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
45 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
48 var pvrtc_4x4_4bpp
= new Uint8Array([
49 0x1b, 0x1b, 0x1b, 0x1b, 0xba, 0x2b, 0x00, 0x80, 0x1b, 0x1b, 0x1b, 0x1b, 0xba, 0x2b, 0x00, 0x80,
50 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
53 var pvrtc_4x4_rgba_decoded
= new Uint8Array([
54 0x00, 0x00, 0x00, 0xff, 0x46, 0x46, 0x46, 0xb8, 0x76, 0x76, 0x71, 0x8a, 0xbd, 0xbd, 0xba, 0x44,
55 0x00, 0x00, 0x00, 0xff, 0x46, 0x46, 0x43, 0xb8, 0x76, 0x76, 0x71, 0x8a, 0xbd, 0xbd, 0xb5, 0x44,
56 0x00, 0x00, 0x00, 0xff, 0x46, 0x46, 0x43, 0xb8, 0x76, 0x76, 0x71, 0x8a, 0xbd, 0xbd, 0xb5, 0x44,
57 0x00, 0x00, 0x00, 0xff, 0x46, 0x46, 0x46, 0xb8, 0x76, 0x76, 0x71, 0x8a, 0xbd, 0xbd, 0xb7, 0x44,
60 var pvrtc_4x4_rgb_decoded
= new Uint8Array([
61 0x00, 0x00, 0x00, 0xff, 0x46, 0x46, 0x46, 0xff, 0x76, 0x76, 0x71, 0xff, 0xbd, 0xbd, 0xba, 0xff,
62 0x00, 0x00, 0x00, 0xff, 0x46, 0x46, 0x43, 0xff, 0x76, 0x76, 0x71, 0xff, 0xbd, 0xbd, 0xb5, 0xff,
63 0x00, 0x00, 0x00, 0xff, 0x46, 0x46, 0x43, 0xff, 0x76, 0x76, 0x71, 0xff, 0xbd, 0xbd, 0xb5, 0xff,
64 0x00, 0x00, 0x00, 0xff, 0x46, 0x46, 0x46, 0xff, 0x76, 0x76, 0x71, 0xff, 0xbd, 0xbd, 0xb7, 0xff,
67 var wtu
= WebGLTestUtils
;
68 var contextVersion
= wtu
.getDefault3DContextVersion();
69 var canvas
= document
.getElementById("canvas");
70 var gl
= wtu
.create3DContext(canvas
, {antialias
: false});
71 var program
= wtu
.setupTexturedQuad(gl
);
75 COMPRESSED_RGB_PVRTC_4BPPV1_IMG
: 0x8C00,
76 COMPRESSED_RGB_PVRTC_2BPPV1_IMG
: 0x8C01,
77 COMPRESSED_RGBA_PVRTC_4BPPV1_IMG
: 0x8C02,
78 COMPRESSED_RGBA_PVRTC_2BPPV1_IMG
: 0x8C03,
84 testFailed("WebGL context does not exist");
86 testPassed("WebGL context exists");
88 // Run tests with extension disabled
91 // Query the extension and store globally so shouldBe can access it
92 ext
= wtu
.getExtensionWithKnownPrefixes(gl
, "WEBGL_compressed_texture_pvrtc");
94 testPassed("No WEBGL_compressed_texture_pvrtc support -- this is legal");
95 runSupportedTest(false);
97 testPassed("Successfully enabled WEBGL_compressed_texture_pvrtc extension");
99 runSupportedTest(true);
104 function runSupportedTest(extensionEnabled
) {
105 var name
= wtu
.getSupportedExtensionWithKnownPrefixes(gl
, "WEBGL_compressed_texture_pvrtc");
106 if (name
!== undefined) {
107 if (extensionEnabled
) {
108 testPassed("WEBGL_compressed_texture_pvrtc listed as supported and getExtension succeeded");
110 testFailed("WEBGL_compressed_texture_pvrtc listed as supported but getExtension failed");
113 if (extensionEnabled
) {
114 testFailed("WEBGL_compressed_texture_pvrtc not listed as supported but getExtension succeeded");
116 testPassed("WEBGL_compressed_texture_pvrtc not listed as supported and getExtension failed -- this is legal");
122 function runTestDisabled() {
123 debug("Testing binding enum with extension disabled");
125 supportedFormats
= gl
.getParameter(gl
.COMPRESSED_TEXTURE_FORMATS
);
126 shouldBe("supportedFormats", "[]");
129 function formatExists(format
, supportedFormats
) {
130 for (var ii
= 0; ii
< supportedFormats
.length
; ++ii
) {
131 if (format
== supportedFormats
[ii
]) {
132 testPassed("supported format " + formatToString(format
) + " is exists");
136 testFailed("supported format " + formatToString(format
) + " does not exist");
139 function formatToString(format
) {
141 if (ext
[p
] == format
) {
145 return "0x" + format
.toString(16);
148 function runTestExtension() {
149 debug("Testing WEBGL_compressed_texture_pvrtc");
151 // check that all format enums exist.
152 for (name
in validFormats
) {
153 var expected
= "0x" + validFormats
[name
].toString(16);
154 var actual
= "ext['" + name
+ "']";
155 shouldBe(actual
, expected
);
158 supportedFormats
= gl
.getParameter(gl
.COMPRESSED_TEXTURE_FORMATS
);
159 // There should be exactly 4 formats for both WebGL 1.0 and WebGL 2.0.
160 shouldBe("supportedFormats.length", "4");
162 // check that all 4 formats exist
163 for (var name
in validFormats
.length
) {
164 formatExists(validFormats
[name
], supportedFormats
);
168 testPVRTC_RGBA_2BPP();
169 testPVRTC_RGB_2BPP();
170 testPVRTC_RGBA_4BPP();
171 testPVRTC_RGB_4BPP();
174 function testPVRTC_RGBA_2BPP() {
179 data
: pvrtc_4x4_2bpp
,
180 raw
: pvrtc_4x4_rgba_decoded
,
181 format
: ext
.COMPRESSED_RGBA_PVRTC_2BPPV1_IMG
184 testPVRTCTextures(tests
);
187 function testPVRTC_RGB_2BPP() {
192 data
: pvrtc_4x4_2bpp
,
193 raw
: pvrtc_4x4_rgb_decoded
,
194 format
: ext
.COMPRESSED_RGB_PVRTC_2BPPV1_IMG
197 testPVRTCTextures(tests
);
200 function testPVRTC_RGBA_4BPP() {
205 data
: pvrtc_4x4_4bpp
,
206 raw
: pvrtc_4x4_rgba_decoded
,
207 format
: ext
.COMPRESSED_RGBA_PVRTC_4BPPV1_IMG
210 testPVRTCTextures(tests
);
213 function testPVRTC_RGB_4BPP() {
218 data
: pvrtc_4x4_4bpp
,
219 raw
: pvrtc_4x4_rgb_decoded
,
220 format
: ext
.COMPRESSED_RGB_PVRTC_4BPPV1_IMG
223 testPVRTCTextures(tests
);
226 function testPVRTCTextures(tests
) {
228 for (var ii
= 0; ii
< tests
.length
; ++ii
) {
229 testPVRTCTexture(tests
[ii
]);
233 function testPVRTCTexture(test
) {
234 var data
= new Uint8Array(test
.data
);
235 var width
= test
.width
;
236 var height
= test
.height
;
237 var format
= test
.format
;
238 var uncompressedData
= test
.raw
;
240 canvas
.width
= width
;
241 canvas
.height
= height
;
242 gl
.viewport(0, 0, width
, height
);
243 debug("testing " + formatToString(format
) + " " + width
+ "x" + height
);
245 var tex
= gl
.createTexture();
246 gl
.bindTexture(gl
.TEXTURE_2D
, tex
);
247 gl
.texParameteri(gl
.TEXTURE_2D
, gl
.TEXTURE_WRAP_S
, gl
.CLAMP_TO_EDGE
);
248 gl
.texParameteri(gl
.TEXTURE_2D
, gl
.TEXTURE_WRAP_T
, gl
.CLAMP_TO_EDGE
);
249 gl
.texParameteri(gl
.TEXTURE_2D
, gl
.TEXTURE_MIN_FILTER
, gl
.NEAREST
);
250 gl
.texParameteri(gl
.TEXTURE_2D
, gl
.TEXTURE_MAG_FILTER
, gl
.NEAREST
);
251 gl
.compressedTexImage2D(gl
.TEXTURE_2D
, 0, format
, width
, height
, 0, data
);
252 wtu
.glErrorShouldBe(gl
, gl
.NO_ERROR
, "uploading compressed texture");
253 gl
.generateMipmap(gl
.TEXTURE_2D
);
254 wtu
.glErrorShouldBe(gl
, gl
.INVALID_OPERATION
, "trying to generate mipmaps from compressed texture");
255 wtu
.clearAndDrawUnitQuad(gl
);
256 compareRect(width
, height
, test
.channels
, width
, height
, uncompressedData
, data
, format
, undefined, "NEAREST");
257 // Test again with linear filtering.
258 gl
.texParameteri(gl
.TEXTURE_2D
, gl
.TEXTURE_MIN_FILTER
, gl
.LINEAR
);
259 gl
.texParameteri(gl
.TEXTURE_2D
, gl
.TEXTURE_MAG_FILTER
, gl
.LINEAR
);
260 wtu
.clearAndDrawUnitQuad(gl
);
261 compareRect(width
, height
, test
.channels
, width
, height
, uncompressedData
, data
, format
, undefined, "LINEAR");
263 gl
.compressedTexImage2D(gl
.TEXTURE_2D
, 0, format
, width
, height
, 1, data
);
264 wtu
.glErrorShouldBe(gl
, gl
.INVALID_VALUE
, "non 0 border");
266 gl
.compressedTexImage2D(gl
.TEXTURE_2D
, 0, format
, width
- 1, height
, 0, data
);
267 wtu
.glErrorShouldBe(gl
, gl
.INVALID_OPERATION
, "invalid dimensions");
268 gl
.compressedTexImage2D(gl
.TEXTURE_2D
, 0, format
, width
- 2, height
, 0, data
);
269 wtu
.glErrorShouldBe(gl
, gl
.INVALID_OPERATION
, "invalid dimensions");
270 gl
.compressedTexImage2D(gl
.TEXTURE_2D
, 0, format
, width
, height
- 1, 0, data
);
271 wtu
.glErrorShouldBe(gl
, gl
.INVALID_OPERATION
, "invalid dimensions");
272 gl
.compressedTexImage2D(gl
.TEXTURE_2D
, 0, format
, width
, height
- 2, 0, data
);
273 wtu
.glErrorShouldBe(gl
, gl
.INVALID_OPERATION
, "invalid dimensions");
275 gl
.compressedTexSubImage2D(gl
.TEXTURE_2D
, 0, 0, 0, width
, height
, format
, data
);
276 wtu
.glErrorShouldBe(gl
, gl
.NO_ERROR
, "compressedTexSubImage2D allowed for reloading of complete textures");
278 gl
.compressedTexSubImage2D(gl
.TEXTURE_2D
, 0, 0, 0, width
- 2, height
, format
, data
);
279 wtu
.glErrorShouldBe(gl
, gl
.INVALID_OPERATION
, "compressedTexSubImage2D not allowed for partial texture updates");
280 gl
.compressedTexSubImage2D(gl
.TEXTURE_2D
, 0, 0, 0, width
, height
- 2, format
, data
);
281 wtu
.glErrorShouldBe(gl
, gl
.INVALID_OPERATION
, "compressedTexSubImage2D not allowed for partial texture updates");
282 gl
.compressedTexSubImage2D(gl
.TEXTURE_2D
, 0, 2, 0, width
- 2, height
, format
, data
);
283 wtu
.glErrorShouldBe(gl
, gl
.INVALID_OPERATION
, "compressedTexSubImage2D not allowed for partial texture updates");
284 gl
.compressedTexSubImage2D(gl
.TEXTURE_2D
, 0, 0, 2, width
, height
- 2, format
, data
);
285 wtu
.glErrorShouldBe(gl
, gl
.INVALID_OPERATION
, "compressedTexSubImage2D not allowed for partial texture updates");
288 function insertImg(element
, caption
, img
) {
289 var div
= document
.createElement("div");
290 div
.appendChild(img
);
291 var label
= document
.createElement("div");
292 label
.appendChild(document
.createTextNode(caption
));
293 div
.appendChild(label
);
294 element
.appendChild(div
);
297 function makeImage(imageWidth
, imageHeight
, dataWidth
, data
, alpha
) {
299 var c
= document
.createElement("canvas");
300 c
.width
= imageWidth
* scale
;
301 c
.height
= imageHeight
* scale
;
302 var ctx
= c
.getContext("2d");
303 for (var yy
= 0; yy
< imageHeight
; ++yy
) {
304 for (var xx
= 0; xx
< imageWidth
; ++xx
) {
305 var offset
= (yy
* dataWidth
+ xx
) * 4;
306 ctx
.fillStyle
= "rgba(" +
307 data
[offset
+ 0] + "," +
308 data
[offset
+ 1] + "," +
309 data
[offset
+ 2] + "," +
310 (alpha
? data
[offset
+ 3] / 255 : 1) + ")";
311 ctx
.fillRect(xx
* scale
, yy
* scale
, scale
, scale
);
314 return wtu
.makeImageFromCanvas(c
);
316 function compareRect(
317 actualWidth
, actualHeight
, actualChannels
,
318 dataWidth
, dataHeight
, expectedData
,
319 testData
, testFormat
, tolerance
, filteringMode
) {
320 if(typeof(tolerance
) == 'undefined') { tolerance
= 5; }
321 var actual
= new Uint8Array(actualWidth
* actualHeight
* 4);
323 0, 0, actualWidth
, actualHeight
, gl
.RGBA
, gl
.UNSIGNED_BYTE
, actual
);
325 var div
= document
.createElement("div");
326 div
.className
= "testimages";
327 insertImg(div
, "expected", makeImage(
328 actualWidth
, actualHeight
, dataWidth
, expectedData
,
329 actualChannels
== 4));
330 insertImg(div
, "actual", makeImage(
331 actualWidth
, actualHeight
, actualWidth
, actual
,
332 actualChannels
== 4));
333 div
.appendChild(document
.createElement('br'));
334 document
.getElementById("console").appendChild(div
);
337 for (var yy
= 0; yy
< actualHeight
; ++yy
) {
338 for (var xx
= 0; xx
< actualWidth
; ++xx
) {
339 var actualOffset
= (yy
* actualWidth
+ xx
) * 4;
340 var expectedOffset
= (yy
* dataWidth
+ xx
) * 4;
342 expectedData
[expectedOffset
+ 0],
343 expectedData
[expectedOffset
+ 1],
344 expectedData
[expectedOffset
+ 2],
345 (actualChannels
== 3 ? 255 : expectedData
[expectedOffset
+ 3])
347 for (var jj
= 0; jj
< 4; ++jj
) {
348 if (Math
.abs(actual
[actualOffset
+ jj
] - expected
[jj
]) > tolerance
) {
350 var was
= actual
[actualOffset
+ 0].toString();
351 for (var j
= 1; j
< 4; ++j
) {
352 was
+= "," + actual
[actualOffset
+ j
];
354 testFailed('at (' + xx
+ ', ' + yy
+
355 ') expected: ' + expected
+ ' was ' + was
);
361 testPassed("texture rendered correctly with " + filteringMode
+ " filtering");
366 var successfullyParsed
= true;
368 <script src=
"../../js/js-test-post.js"></script>