ext-disjoint-timer-query-webgl2.html (15107B)
1 <!-- 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. 5 --> 6 7 <!DOCTYPE html> 8 <html> 9 <head> 10 <meta charset="utf-8"> 11 <title>WebGL 2 EXT_disjoint_timer_query_webgl2 Conformance Tests</title> 12 <link rel="stylesheet" href="../../resources/js-test-style.css"/> 13 <script src="../../js/js-test-pre.js"></script> 14 <script src="../../js/webgl-test-utils.js"></script> 15 </head> 16 <body> 17 <div id="description"></div> 18 <canvas id="canvas" style="width: 50px; height: 50px;"> </canvas> 19 <div id="console"></div> 20 21 <script> 22 "use strict"; 23 description("This test verifies the functionality of the EXT_disjoint_timer_query_webgl2 extension, if it is available."); 24 25 var wtu = WebGLTestUtils; 26 var canvas = document.getElementById("canvas"); 27 var gl = wtu.create3DContext(canvas, null, 2); 28 var gl2 = null; 29 var ext = null; 30 var ext2 = null; 31 var query = null; 32 var query2 = null; 33 var elapsed_query = null; 34 var timestamp_query1 = null; 35 var timestamp_query2 = null; 36 var availability_retry = 500; 37 var timestamp_counter_bits = 0; 38 39 if (!gl) { 40 testFailed("WebGL context does not exist"); 41 finishTest(); 42 } else { 43 testPassed("WebGL context exists"); 44 45 // Query the extension and store globally so shouldBe can access it 46 ext = wtu.getExtensionWithKnownPrefixes(gl, "EXT_disjoint_timer_query_webgl2"); 47 if (!ext) { 48 testPassed("No EXT_disjoint_timer_query_webgl2 support -- this is legal"); 49 finishTest(); 50 } else { 51 runSanityTests(); 52 wtu.glErrorShouldBe(gl, gl.NO_ERROR); 53 54 // Clear disjoint value. 55 gl.getParameter(ext.GPU_DISJOINT_EXT); 56 wtu.glErrorShouldBe(gl, gl.NO_ERROR); 57 58 runElapsedTimeTest(); 59 wtu.glErrorShouldBe(gl, gl.NO_ERROR); 60 61 timestamp_counter_bits = gl.getQuery(ext.TIMESTAMP_EXT, ext.QUERY_COUNTER_BITS_EXT); 62 if (timestamp_counter_bits > 0) { 63 runTimeStampTest(); 64 wtu.glErrorShouldBe(gl, gl.NO_ERROR); 65 } 66 verifyQueryResultsNotAvailable(); 67 verifyDeleteQueryBehavior(); 68 verifyDeleteQueryErrorBehavior(); 69 wtu.glErrorShouldBe(gl, gl.NO_ERROR); 70 71 window.requestAnimationFrame(checkQueryResults); 72 } 73 } 74 75 function runSanityTests() { 76 debug(""); 77 debug("Testing other query types"); 78 query = gl.createQuery(); 79 gl.beginQuery(gl.ANY_SAMPLES_PASSED, query); 80 shouldBeTrue("gl.getQuery(gl.ANY_SAMPLES_PASSED, gl.CURRENT_QUERY) !== null"); 81 gl.endQuery(gl.ANY_SAMPLES_PASSED); 82 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "enabling EXT_disjoint_timer_query_webgl2 should not break other queries"); 83 84 debug(""); 85 debug("Testing timer query expectations"); 86 87 shouldBe("ext.QUERY_COUNTER_BITS_EXT", "0x8864"); 88 shouldBe("ext.TIME_ELAPSED_EXT", "0x88BF"); 89 shouldBe("ext.TIMESTAMP_EXT", "0x8E28"); 90 shouldBe("ext.GPU_DISJOINT_EXT", "0x8FBB"); 91 92 shouldBe("gl.isQuery(null)", "false"); 93 94 shouldBeTrue("gl.getQuery(ext.TIME_ELAPSED_EXT, gl.CURRENT_QUERY) === null"); 95 wtu.glErrorShouldBe(gl, gl.NO_ERROR); 96 shouldBeTrue("gl.getQuery(ext.TIME_ELAPSED_EXT, ext.QUERY_COUNTER_BITS_EXT) >= 30"); 97 wtu.glErrorShouldBe(gl, gl.NO_ERROR); 98 99 shouldBeTrue("gl.getQuery(ext.TIMESTAMP_EXT, gl.CURRENT_QUERY) === null"); 100 wtu.glErrorShouldBe(gl, gl.NO_ERROR); 101 102 // Certain drivers set timestamp counter bits to 0 as they don't support timestamps 103 shouldBeTrue("gl.getQuery(ext.TIMESTAMP_EXT, ext.QUERY_COUNTER_BITS_EXT) >= 30 || " + 104 "gl.getQuery(ext.TIMESTAMP_EXT, ext.QUERY_COUNTER_BITS_EXT) === 0"); 105 wtu.glErrorShouldBe(gl, gl.NO_ERROR); 106 107 debug(""); 108 debug("Testing time elapsed query lifecycle"); 109 query = gl.createQuery(); 110 shouldBe("gl.isQuery(query)", "false"); 111 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Query creation must succeed."); 112 gl.beginQuery(ext.TIMESTAMP_EXT, query); 113 wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "Beginning a timestamp query should fail."); 114 gl.beginQuery(ext.TIME_ELAPSED_EXT, query); 115 shouldBe("gl.isQuery(query)", "true"); 116 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Beginning an inactive time elapsed query should succeed."); 117 gl.beginQuery(ext.TIME_ELAPSED_EXT, query); 118 wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "Attempting to begin an active query should fail."); 119 gl.getQueryParameter(query, gl.QUERY_RESULT_AVAILABLE); 120 wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "Fetching query result availability of an active query should fail."); 121 gl.getQueryParameter(query, gl.QUERY_RESULT); 122 wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "Fetching query result of an active query should fail."); 123 shouldBe("gl.getQuery(ext.TIME_ELAPSED_EXT, gl.CURRENT_QUERY)", "query"); 124 gl.endQuery(ext.TIME_ELAPSED_EXT); 125 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Ending an active time elapsed query should succeed."); 126 gl.getQueryParameter(query, gl.QUERY_RESULT_AVAILABLE); 127 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Fetching query result availability after query end should succeed."); 128 gl.endQuery(ext.TIME_ELAPSED_EXT); 129 wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "Attempting to end an inactive query should fail."); 130 ext.queryCounterEXT(query, ext.TIMESTAMP_EXT); 131 wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "Should not be able to use time elapsed query to store a timestamp."); 132 gl.deleteQuery(query); 133 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Query deletion must succeed."); 134 gl.beginQuery(ext.TIME_ELAPSED_EXT, query); 135 wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "Beginning a deleted query must fail."); 136 gl.getQueryParameter(query, gl.QUERY_RESULT_AVAILABLE); 137 wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "Fetching query result availability after query deletion should fail."); 138 shouldBe("gl.isQuery(query)", "false"); 139 140 debug(""); 141 debug("Testing timestamp counter"); 142 query = gl.createQuery(); 143 shouldThrow("ext.queryCounterEXT(null, ext.TIMESTAMP_EXT)"); 144 ext.queryCounterEXT(query, ext.TIMESTAMP_EXT); 145 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Timestamp counter queries should work."); 146 gl.deleteQuery(query); 147 wtu.glErrorShouldBe(gl, gl.NO_ERROR); 148 149 debug(""); 150 debug("Performing parameter sanity checks"); 151 gl.getParameter(ext.TIMESTAMP_EXT); 152 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "getParameter timestamp calls should work."); 153 gl.getParameter(ext.GPU_DISJOINT_EXT); 154 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "getParameter disjoint calls should work."); 155 156 debug(""); 157 debug("Testing current query conditions"); 158 query = gl.createQuery(); 159 query2 = gl.createQuery(); 160 shouldBe("gl.getQuery(ext.TIME_ELAPSED_EXT, gl.CURRENT_QUERY)", "null"); 161 gl.beginQuery(ext.TIME_ELAPSED_EXT, query); 162 shouldBe("gl.getQuery(ext.TIME_ELAPSED_EXT, gl.CURRENT_QUERY)", "query"); 163 wtu.glErrorShouldBe(gl, gl.NO_ERROR); 164 165 debug(""); 166 debug("Testing failed begin query should not change the current query."); 167 gl.beginQuery(ext.TIME_ELAPSED_EXT, query2); 168 wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "Beginning an elapsed query without ending should fail."); 169 shouldBe("gl.getQuery(ext.TIME_ELAPSED_EXT, gl.CURRENT_QUERY)", "query"); 170 wtu.glErrorShouldBe(gl, gl.NO_ERROR); 171 172 debug(""); 173 debug("Testing beginning a timestamp query is invalid and should not change the elapsed query."); 174 gl.beginQuery(ext.TIMESTAMP_EXT, query2) 175 wtu.glErrorShouldBe(gl, gl.INVALID_ENUM); 176 shouldBe("gl.getQuery(ext.TIME_ELAPSED_EXT, gl.CURRENT_QUERY)", "query"); 177 wtu.glErrorShouldBe(gl, gl.NO_ERROR); 178 179 debug(""); 180 debug("Testing timestamp queries end immediately so are never current."); 181 ext.queryCounterEXT(query2, ext.TIMESTAMP_EXT); 182 shouldBe("gl.getQuery(ext.TIMESTAMP_EXT, gl.CURRENT_QUERY)", "null"); 183 wtu.glErrorShouldBe(gl, gl.NO_ERROR); 184 185 debug(""); 186 debug("Testing ending the query should clear the current query."); 187 gl.endQuery(ext.TIME_ELAPSED_EXT); 188 shouldBe("gl.getQuery(ext.TIME_ELAPSED_EXT, gl.CURRENT_QUERY)", "null"); 189 wtu.glErrorShouldBe(gl, gl.NO_ERROR); 190 191 debug(""); 192 debug("Testing beginning a elapsed query using a timestamp query should fail and not affect current query.") 193 gl.beginQuery(ext.TIME_ELAPSED_EXT, query2); 194 wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "Switching query targets should fail."); 195 shouldBe("gl.getQuery(ext.TIME_ELAPSED_EXT, gl.CURRENT_QUERY)", "null"); 196 wtu.glErrorShouldBe(gl, gl.NO_ERROR); 197 198 gl.deleteQuery(query); 199 gl.deleteQuery(query2); 200 201 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Should be no errors at end of sanity tests"); 202 } 203 204 function runElapsedTimeTest() { 205 debug(""); 206 debug("Testing elapsed time query"); 207 208 elapsed_query = gl.createQuery(); 209 gl.beginQuery(ext.TIME_ELAPSED_EXT, elapsed_query); 210 gl.clearColor(0, 0, 1, 1); 211 gl.clear(gl.COLOR_BUFFER_BIT); 212 gl.endQuery(ext.TIME_ELAPSED_EXT); 213 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Time elapsed query should have no errors"); 214 } 215 216 function runTimeStampTest() { 217 debug(""); 218 debug("Testing timestamp query"); 219 220 timestamp_query1 = gl.createQuery(); 221 timestamp_query2 = gl.createQuery(); 222 ext.queryCounterEXT(timestamp_query1, ext.TIMESTAMP_EXT); 223 gl.clearColor(1, 0, 0, 1); 224 gl.clear(gl.COLOR_BUFFER_BIT); 225 ext.queryCounterEXT(timestamp_query2, ext.TIMESTAMP_EXT); 226 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Timestamp queries should have no errors"); 227 } 228 229 function verifyQueryResultsNotAvailable() { 230 debug(""); 231 debug("Verifying queries' results don't become available too early"); 232 233 // Verify as best as possible that the implementation doesn't 234 // allow a query's result to become available the same frame, by 235 // spin-looping for some time and ensuring that none of the 236 // queries' results become available. 237 var startTime = Date.now(); 238 while (Date.now() - startTime < 2000) { 239 gl.finish(); 240 if (gl.getQueryParameter(elapsed_query, gl.QUERY_RESULT_AVAILABLE)) { 241 testFailed("One of the queries' results became available too early"); 242 return; 243 } 244 if (timestamp_counter_bits > 0) { 245 if (gl.getQueryParameter(timestamp_query1, gl.QUERY_RESULT_AVAILABLE) || 246 gl.getQueryParameter(timestamp_query2, gl.QUERY_RESULT_AVAILABLE)) { 247 testFailed("One of the queries' results became available too early"); 248 return; 249 } 250 } 251 } 252 253 testPassed("Queries' results didn't become available in a spin loop"); 254 } 255 256 function verifyDeleteQueryBehavior() { 257 debug(""); 258 debug("Testing deleting an active query should end it."); 259 260 // Use a new context for this test 261 gl2 = wtu.create3DContext(null, null, 2); 262 if (!gl2) return; 263 ext2 = gl2.getExtension("EXT_disjoint_timer_query_webgl2"); 264 if (!ext2) return; 265 266 query = gl2.createQuery(); 267 gl2.beginQuery(ext.TIME_ELAPSED_EXT, query); 268 wtu.glErrorShouldBe(gl2, gl2.NONE, "The query began successfully"); 269 gl2.deleteQuery(query); 270 wtu.glErrorShouldBe(gl2, gl2.NONE, "Deletion of the active query succeeds"); 271 shouldBeNull("gl2.getQuery(ext2.TIME_ELAPSED_EXT, gl2.CURRENT_QUERY)"); 272 shouldBeFalse("gl2.isQuery(query)"); 273 query = gl2.createQuery(); 274 gl2.beginQuery(ext2.TIME_ELAPSED_EXT, query); 275 wtu.glErrorShouldBe(gl, gl2.NONE, "Beginning a new query succeeds"); 276 gl2.endQuery(gl2.TIME_ELAPSED_EXT); 277 gl2.deleteQuery(query); 278 wtu.glErrorShouldBe(gl, gl.NONE); 279 query = null; 280 ext2 = null; 281 gl2 = null; 282 } 283 284 function verifyDeleteQueryErrorBehavior() { 285 debug(""); 286 debug("Testing deleting a query created by another context."); 287 288 // Use new contexts for this test 289 gl2 = wtu.create3DContext(null, null, 2); 290 var gl3 = wtu.create3DContext(null, null, 2); 291 if (!gl2 || !gl3) return; 292 ext2 = gl2.getExtension("EXT_disjoint_timer_query_webgl2"); 293 if (!ext2) return; 294 295 query = gl2.createQuery(); 296 gl2.beginQuery(ext2.TIME_ELAPSED_EXT, query); 297 gl3.deleteQuery(query); 298 wtu.glErrorShouldBe(gl3, gl3.INVALID_OPERATION); 299 shouldBeTrue("gl2.isQuery(query)"); 300 shouldBe("gl2.getQuery(ext2.TIME_ELAPSED_EXT, gl2.CURRENT_QUERY)", "query"); 301 gl2.endQuery(ext2.TIME_ELAPSED_EXT); 302 gl2.deleteQuery(query); 303 wtu.glErrorShouldBe(gl2, gl2.NONE); 304 query = null; 305 ext2 = null; 306 gl2 = null; 307 gl3 = null; 308 } 309 310 function checkQueryResults() { 311 if (availability_retry > 0) { 312 // Make a reasonable attempt to wait for the queries' results to become available. 313 if (!gl.getQueryParameter(elapsed_query, gl.QUERY_RESULT_AVAILABLE) || 314 (timestamp_counter_bits > 0 && !gl.getQueryParameter(timestamp_query2, gl.QUERY_RESULT_AVAILABLE))) { 315 var error = gl.getError(); 316 if (error != gl.NO_ERROR) { 317 testFailed("getQueryParameter should have no errors: " + wtu.glEnumToString(gl, error)); 318 debug(""); 319 finishTest(); 320 return; 321 } 322 availability_retry--; 323 window.requestAnimationFrame(checkQueryResults); 324 return; 325 } 326 } 327 328 debug(""); 329 debug("Testing query results"); 330 331 // Make sure queries are available. 332 shouldBe("gl.getQueryParameter(elapsed_query, gl.QUERY_RESULT_AVAILABLE)", "true"); 333 if (timestamp_counter_bits > 0) { 334 shouldBe("gl.getQueryParameter(timestamp_query1, gl.QUERY_RESULT_AVAILABLE)", "true"); 335 shouldBe("gl.getQueryParameter(timestamp_query2, gl.QUERY_RESULT_AVAILABLE)", "true"); 336 } 337 338 var disjoint_value = gl.getParameter(ext.GPU_DISJOINT_EXT); 339 if (disjoint_value) { 340 // Cannot validate results make sense, but this is okay. 341 testPassed("Disjoint triggered."); 342 } else { 343 var elapsed_result = gl.getQueryParameter(elapsed_query, gl.QUERY_RESULT); 344 if (timestamp_counter_bits > 0) { 345 var timestamp_result1 = gl.getQueryParameter(timestamp_query1, gl.QUERY_RESULT); 346 var timestamp_result2 = gl.getQueryParameter(timestamp_query2, gl.QUERY_RESULT); 347 } 348 // Do some basic validity checking of the elapsed time query. There's no way it should 349 // take more than about half a second for a no-op query. 350 var halfSecondInNanos = 0.5 * 1000 * 1000 * 1000; 351 if (elapsed_result < 0 || elapsed_result > halfSecondInNanos) { 352 testFailed("Time elapsed query returned invalid data: " + elapsed_result); 353 } else { 354 testPassed("Time elapsed query results were valid."); 355 } 356 357 if (timestamp_counter_bits > 0) { 358 if (timestamp_result1 <= 0 || 359 timestamp_result2 <= 0 || 360 timestamp_result2 <= timestamp_result1) { 361 testFailed("Timestamp queries returned invalid data: timestamp_result1 = " + 362 timestamp_result1 + ", timestamp_result2 = " + timestamp_result2); 363 } else { 364 testPassed("Timestamp query results were valid."); 365 } 366 } 367 } 368 369 debug(""); 370 finishTest(); 371 } 372 </script> 373 </body> 374 </html>