summaryrefslogtreecommitdiffstats
path: root/dom/canvas/test/webgl-conf/checkout/js
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--dom/canvas/test/webgl-conf/checkout/js/desktop-gl-constants.js2639
-rw-r--r--dom/canvas/test/webgl-conf/checkout/js/glsl-conformance-test.js424
-rw-r--r--dom/canvas/test/webgl-conf/checkout/js/glsl-constructor-tests-generator.js919
-rw-r--r--dom/canvas/test/webgl-conf/checkout/js/glsl-generator.js1234
-rw-r--r--dom/canvas/test/webgl-conf/checkout/js/js-test-post.js38
-rw-r--r--dom/canvas/test/webgl-conf/checkout/js/js-test-pre.js801
-rw-r--r--dom/canvas/test/webgl-conf/checkout/js/pnglib.js207
-rw-r--r--dom/canvas/test/webgl-conf/checkout/js/test-eval.js15
-rw-r--r--dom/canvas/test/webgl-conf/checkout/js/tests/canvas-tests-utils.js825
-rw-r--r--dom/canvas/test/webgl-conf/checkout/js/tests/clipping-wide-points.js92
-rw-r--r--dom/canvas/test/webgl-conf/checkout/js/tests/compositing-test.js136
-rw-r--r--dom/canvas/test/webgl-conf/checkout/js/tests/compound-assignment-type-combination.js133
-rw-r--r--dom/canvas/test/webgl-conf/checkout/js/tests/compressed-tex-image.js138
-rw-r--r--dom/canvas/test/webgl-conf/checkout/js/tests/compressed-texture-utils.js258
-rw-r--r--dom/canvas/test/webgl-conf/checkout/js/tests/context-methods.js52
-rw-r--r--dom/canvas/test/webgl-conf/checkout/js/tests/ext-color-buffer-half-float.js473
-rw-r--r--dom/canvas/test/webgl-conf/checkout/js/tests/ext-float-blend.js237
-rw-r--r--dom/canvas/test/webgl-conf/checkout/js/tests/ext-texture-filter-anisotropic.js169
-rw-r--r--dom/canvas/test/webgl-conf/checkout/js/tests/gl-bindattriblocation-aliasing.js44
-rw-r--r--dom/canvas/test/webgl-conf/checkout/js/tests/gl-enum-tests.js123
-rw-r--r--dom/canvas/test/webgl-conf/checkout/js/tests/gl-get-tex-parameter.js183
-rw-r--r--dom/canvas/test/webgl-conf/checkout/js/tests/gl-object-get-calls.js1090
-rw-r--r--dom/canvas/test/webgl-conf/checkout/js/tests/gl-vertex-attrib.js263
-rw-r--r--dom/canvas/test/webgl-conf/checkout/js/tests/instanceof-test.js105
-rw-r--r--dom/canvas/test/webgl-conf/checkout/js/tests/invalid-vertex-attrib-test.js129
-rw-r--r--dom/canvas/test/webgl-conf/checkout/js/tests/iterable-test.js183
-rw-r--r--dom/canvas/test/webgl-conf/checkout/js/tests/line-rendering-quality.js163
-rw-r--r--dom/canvas/test/webgl-conf/checkout/js/tests/no-over-optimizations-on-uniform-array.js247
-rw-r--r--dom/canvas/test/webgl-conf/checkout/js/tests/oes-texture-float-and-half-float-linear.js151
-rw-r--r--dom/canvas/test/webgl-conf/checkout/js/tests/offscreencanvas-transfer-image-bitmap.js57
-rw-r--r--dom/canvas/test/webgl-conf/checkout/js/tests/out-of-bounds-test.js321
-rw-r--r--dom/canvas/test/webgl-conf/checkout/js/tests/ovr_multiview2_util.js263
-rw-r--r--dom/canvas/test/webgl-conf/checkout/js/tests/shader-with-non-reserved-words.js664
-rw-r--r--dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-2d-with-canvas-sub-rectangle.js292
-rw-r--r--dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-2d-with-canvas.js468
-rw-r--r--dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-2d-with-image-bitmap-from-blob.js49
-rw-r--r--dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-2d-with-image-bitmap-from-canvas.js74
-rw-r--r--dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-2d-with-image-bitmap-from-image-bitmap.js56
-rw-r--r--dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-2d-with-image-bitmap-from-image-data.js49
-rw-r--r--dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-2d-with-image-bitmap-from-image.js46
-rw-r--r--dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-2d-with-image-bitmap-from-video.js83
-rw-r--r--dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-2d-with-image-data.js240
-rw-r--r--dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-2d-with-image.js257
-rw-r--r--dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-2d-with-svg-image.js140
-rw-r--r--dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-2d-with-video.js291
-rw-r--r--dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-2d-with-webgl-canvas.js298
-rw-r--r--dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-3d-with-canvas-sub-rectangle.js287
-rw-r--r--dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-3d-with-canvas.js226
-rw-r--r--dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-3d-with-image-bitmap-from-blob.js48
-rw-r--r--dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-3d-with-image-bitmap-from-canvas.js74
-rw-r--r--dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-3d-with-image-bitmap-from-image-bitmap.js56
-rw-r--r--dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-3d-with-image-bitmap-from-image-data.js49
-rw-r--r--dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-3d-with-image-bitmap-from-image.js45
-rw-r--r--dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-3d-with-image-bitmap-from-video.js83
-rw-r--r--dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-3d-with-image-data.js259
-rw-r--r--dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-3d-with-image.js260
-rw-r--r--dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-3d-with-svg-image.js104
-rw-r--r--dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-3d-with-video.js244
-rw-r--r--dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-3d-with-webgl-canvas.js212
-rw-r--r--dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-utils.js865
-rw-r--r--dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-with-image-bitmap-utils.js435
-rw-r--r--dom/canvas/test/webgl-conf/checkout/js/tests/tex-input-validation.js563
-rw-r--r--dom/canvas/test/webgl-conf/checkout/js/tests/texture-corner-case-videos.js299
-rw-r--r--dom/canvas/test/webgl-conf/checkout/js/tests/typed-array-test-cases.js73
-rw-r--r--dom/canvas/test/webgl-conf/checkout/js/tests/typed-array-worker.js72
-rw-r--r--dom/canvas/test/webgl-conf/checkout/js/tests/webgl-compressed-texture-size-limit.js226
-rw-r--r--dom/canvas/test/webgl-conf/checkout/js/tests/webgl-draw-buffers-utils.js69
-rw-r--r--dom/canvas/test/webgl-conf/checkout/js/webgl-test-harness.js642
-rw-r--r--dom/canvas/test/webgl-conf/checkout/js/webgl-test-utils.js3677
69 files changed, 23987 insertions, 0 deletions
diff --git a/dom/canvas/test/webgl-conf/checkout/js/desktop-gl-constants.js b/dom/canvas/test/webgl-conf/checkout/js/desktop-gl-constants.js
new file mode 100644
index 0000000000..4d4833c2ce
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/js/desktop-gl-constants.js
@@ -0,0 +1,2639 @@
+/*
+Copyright (c) 2019 The Khronos Group Inc.
+Use of this source code is governed by an MIT-style license that can be
+found in the LICENSE.txt file.
+*/
+
+// Defines a bunch of DesktopGL constants so we can make sure WebGL
+// implementations disallow them.
+
+// Some of these are also GLES2/GLES3 constants that have been removed from
+// WebGL.
+
+var desktopGL = {
+ 'MIN': 0x8007,
+ 'MAX': 0x8008,
+ 'QUADS': 0x0007,
+ 'QUAD_STRIP': 0x0008,
+ 'POLYGON': 0x0009,
+ '1': 0x0001,
+ '2': 0x0002,
+ '3': 0x0003,
+ '4': 0x0004,
+ 'STATIC_READ': 0x88E5,
+ 'CLIP_PLANE0': 0x3000,
+ 'PERSPECTIVE_CORRECTION_HINT': 0x0C50,
+ 'ACCUM_BUFFER_BIT': 0x0200,
+ 'RGB4': 0x804F,
+ 'RGB5': 0x8050,
+ 'RGB8': 0x8051,
+ 'RGB10': 0x8052,
+ 'RGB12': 0x8053,
+ 'RGB16': 0x8054,
+ 'RGBA2': 0x8055,
+ 'RGBA4': 0x8056,
+ 'RGB5_A1': 0x8057,
+ 'RGBA8': 0x8058,
+ 'RGB10_A2': 0x8059,
+ 'RGBA12': 0x805A,
+ 'RGBA16': 0x805B,
+ 'SMOOTH_POINT_SIZE_RANGE': 0x0B12,
+ 'SMOOTH_POINT_SIZE_GRANULARITY': 0x0B13,
+ 'SMOOTH_LINE_WIDTH_RANGE': 0x0B22,
+ 'SMOOTH_LINE_WIDTH_GRANULARITY': 0x0B23,
+ 'UNSIGNED_BYTE_3_3_2': 0x8032,
+ 'UNSIGNED_SHORT_4_4_4_4': 0x8033,
+ 'UNSIGNED_SHORT_5_5_5_1': 0x8034,
+ 'UNSIGNED_INT_8_8_8_8': 0x8035,
+ 'UNSIGNED_INT_10_10_10_2': 0x8036,
+ 'RESCALE_NORMAL': 0x803A,
+ 'TEXTURE_BINDING_3D': 0x806A,
+ 'PACK_SKIP_IMAGES': 0x806B,
+ 'PACK_IMAGE_HEIGHT': 0x806C,
+ 'UNPACK_SKIP_IMAGES': 0x806D,
+ 'UNPACK_IMAGE_HEIGHT': 0x806E,
+ 'TEXTURE_3D': 0x806F,
+ 'PROXY_TEXTURE_3D': 0x8070,
+ 'TEXTURE_DEPTH': 0x8071,
+ 'TEXTURE_WRAP_R': 0x8072,
+ 'MAX_3D_TEXTURE_SIZE': 0x8073,
+ 'BGR': 0x80E0,
+ 'BGRA': 0x80E1,
+ 'MAX_ELEMENTS_VERTICES': 0x80E8,
+ 'MAX_ELEMENTS_INDICES': 0x80E9,
+ 'CLAMP_TO_EDGE': 0x812F,
+ 'TEXTURE_MIN_LOD': 0x813A,
+ 'TEXTURE_MAX_LOD': 0x813B,
+ 'TEXTURE_BASE_LEVEL': 0x813C,
+ 'TEXTURE_MAX_LEVEL': 0x813D,
+ 'LIGHT_MODEL_COLOR_CONTROL': 0x81F8,
+ 'SINGLE_COLOR': 0x81F9,
+ 'SEPARATE_SPECULAR_COLOR': 0x81FA,
+ 'UNSIGNED_BYTE_2_3_3_REV': 0x8362,
+ 'UNSIGNED_SHORT_5_6_5': 0x8363,
+ 'UNSIGNED_SHORT_5_6_5_REV': 0x8364,
+ 'UNSIGNED_SHORT_4_4_4_4_REV': 0x8365,
+ 'UNSIGNED_SHORT_1_5_5_5_REV': 0x8366,
+ 'UNSIGNED_INT_8_8_8_8_REV': 0x8367,
+ 'UNSIGNED_INT_2_10_10_10_REV': 0x8368,
+ 'ALIASED_POINT_SIZE_RANGE': 0x846D,
+ 'ALIASED_LINE_WIDTH_RANGE': 0x846E,
+ 'MULTISAMPLE': 0x809D,
+ 'SAMPLE_ALPHA_TO_COVERAGE': 0x809E,
+ 'SAMPLE_ALPHA_TO_ONE': 0x809F,
+ 'SAMPLE_COVERAGE': 0x80A0,
+ 'SAMPLE_BUFFERS': 0x80A8,
+ 'SAMPLES': 0x80A9,
+ 'SAMPLE_COVERAGE_VALUE': 0x80AA,
+ 'SAMPLE_COVERAGE_INVERT': 0x80AB,
+ 'CLAMP_TO_BORDER': 0x812D,
+ 'TEXTURE0': 0x84C0,
+ 'TEXTURE1': 0x84C1,
+ 'TEXTURE2': 0x84C2,
+ 'TEXTURE3': 0x84C3,
+ 'TEXTURE4': 0x84C4,
+ 'TEXTURE5': 0x84C5,
+ 'TEXTURE6': 0x84C6,
+ 'TEXTURE7': 0x84C7,
+ 'TEXTURE8': 0x84C8,
+ 'TEXTURE9': 0x84C9,
+ 'TEXTURE10': 0x84CA,
+ 'TEXTURE11': 0x84CB,
+ 'TEXTURE12': 0x84CC,
+ 'TEXTURE13': 0x84CD,
+ 'TEXTURE14': 0x84CE,
+ 'TEXTURE15': 0x84CF,
+ 'TEXTURE16': 0x84D0,
+ 'TEXTURE17': 0x84D1,
+ 'TEXTURE18': 0x84D2,
+ 'TEXTURE19': 0x84D3,
+ 'TEXTURE20': 0x84D4,
+ 'TEXTURE21': 0x84D5,
+ 'TEXTURE22': 0x84D6,
+ 'TEXTURE23': 0x84D7,
+ 'TEXTURE24': 0x84D8,
+ 'TEXTURE25': 0x84D9,
+ 'TEXTURE26': 0x84DA,
+ 'TEXTURE27': 0x84DB,
+ 'TEXTURE28': 0x84DC,
+ 'TEXTURE29': 0x84DD,
+ 'TEXTURE30': 0x84DE,
+ 'TEXTURE31': 0x84DF,
+ 'ACTIVE_TEXTURE': 0x84E0,
+ 'CLIENT_ACTIVE_TEXTURE': 0x84E1,
+ 'MAX_TEXTURE_UNITS': 0x84E2,
+ 'TRANSPOSE_MODELVIEW_MATRIX': 0x84E3,
+ 'TRANSPOSE_PROJECTION_MATRIX': 0x84E4,
+ 'TRANSPOSE_TEXTURE_MATRIX': 0x84E5,
+ 'TRANSPOSE_COLOR_MATRIX': 0x84E6,
+ 'SUBTRACT': 0x84E7,
+ 'COMPRESSED_ALPHA': 0x84E9,
+ 'COMPRESSED_LUMINANCE': 0x84EA,
+ 'COMPRESSED_LUMINANCE_ALPHA': 0x84EB,
+ 'COMPRESSED_INTENSITY': 0x84EC,
+ 'COMPRESSED_RGB': 0x84ED,
+ 'COMPRESSED_RGBA': 0x84EE,
+ 'TEXTURE_COMPRESSION_HINT': 0x84EF,
+ 'NORMAL_MAP': 0x8511,
+ 'REFLECTION_MAP': 0x8512,
+ 'TEXTURE_CUBE_MAP': 0x8513,
+ 'TEXTURE_BINDING_CUBE_MAP': 0x8514,
+ 'TEXTURE_CUBE_MAP_POSITIVE_X': 0x8515,
+ 'TEXTURE_CUBE_MAP_NEGATIVE_X': 0x8516,
+ 'TEXTURE_CUBE_MAP_POSITIVE_Y': 0x8517,
+ 'TEXTURE_CUBE_MAP_NEGATIVE_Y': 0x8518,
+ 'TEXTURE_CUBE_MAP_POSITIVE_Z': 0x8519,
+ 'TEXTURE_CUBE_MAP_NEGATIVE_Z': 0x851A,
+ 'PROXY_TEXTURE_CUBE_MAP': 0x851B,
+ 'MAX_CUBE_MAP_TEXTURE_SIZE': 0x851C,
+ 'COMBINE': 0x8570,
+ 'COMBINE_RGB': 0x8571,
+ 'COMBINE_ALPHA': 0x8572,
+ 'RGB_SCALE': 0x8573,
+ 'ADD_SIGNED': 0x8574,
+ 'INTERPOLATE': 0x8575,
+ 'CONSTANT': 0x8576,
+ 'PRIMARY_COLOR': 0x8577,
+ 'PREVIOUS': 0x8578,
+ 'SOURCE0_RGB': 0x8580,
+ 'SOURCE1_RGB': 0x8581,
+ 'SOURCE2_RGB': 0x8582,
+ 'SOURCE0_ALPHA': 0x8588,
+ 'SOURCE1_ALPHA': 0x8589,
+ 'SOURCE2_ALPHA': 0x858A,
+ 'OPERAND0_RGB': 0x8590,
+ 'OPERAND1_RGB': 0x8591,
+ 'OPERAND2_RGB': 0x8592,
+ 'OPERAND0_ALPHA': 0x8598,
+ 'OPERAND1_ALPHA': 0x8599,
+ 'OPERAND2_ALPHA': 0x859A,
+ 'TEXTURE_COMPRESSED_IMAGE_SIZE': 0x86A0,
+ 'TEXTURE_COMPRESSED': 0x86A1,
+ 'NUM_COMPRESSED_TEXTURE_FORMATS': 0x86A2,
+ 'COMPRESSED_TEXTURE_FORMATS': 0x86A3,
+ 'DOT3_RGB': 0x86AE,
+ 'DOT3_RGBA': 0x86AF,
+ 'MULTISAMPLE_BIT': 0x20000000,
+ 'BLEND_DST_RGB': 0x80C8,
+ 'BLEND_SRC_RGB': 0x80C9,
+ 'BLEND_DST_ALPHA': 0x80CA,
+ 'BLEND_SRC_ALPHA': 0x80CB,
+ 'POINT_SIZE_MIN': 0x8126,
+ 'POINT_SIZE_MAX': 0x8127,
+ 'POINT_FADE_THRESHOLD_SIZE': 0x8128,
+ 'POINT_DISTANCE_ATTENUATION': 0x8129,
+ 'GENERATE_MIPMAP': 0x8191,
+ 'GENERATE_MIPMAP_HINT': 0x8192,
+ 'DEPTH_COMPONENT16': 0x81A5,
+ 'DEPTH_COMPONENT24': 0x81A6,
+ 'DEPTH_COMPONENT32': 0x81A7,
+ 'MIRRORED_REPEAT': 0x8370,
+ 'FOG_COORDINATE_SOURCE': 0x8450,
+ 'FOG_COORDINATE': 0x8451,
+ 'FRAGMENT_DEPTH': 0x8452,
+ 'CURRENT_FOG_COORDINATE': 0x8453,
+ 'FOG_COORDINATE_ARRAY_TYPE': 0x8454,
+ 'FOG_COORDINATE_ARRAY_STRIDE': 0x8455,
+ 'FOG_COORDINATE_ARRAY_POINTER': 0x8456,
+ 'FOG_COORDINATE_ARRAY': 0x8457,
+ 'COLOR_SUM': 0x8458,
+ 'CURRENT_SECONDARY_COLOR': 0x8459,
+ 'SECONDARY_COLOR_ARRAY_SIZE': 0x845A,
+ 'SECONDARY_COLOR_ARRAY_TYPE': 0x845B,
+ 'SECONDARY_COLOR_ARRAY_STRIDE': 0x845C,
+ 'SECONDARY_COLOR_ARRAY_POINTER': 0x845D,
+ 'SECONDARY_COLOR_ARRAY': 0x845E,
+ 'MAX_TEXTURE_LOD_BIAS': 0x84FD,
+ 'TEXTURE_FILTER_CONTROL': 0x8500,
+ 'TEXTURE_LOD_BIAS': 0x8501,
+ 'INCR_WRAP': 0x8507,
+ 'DECR_WRAP': 0x8508,
+ 'TEXTURE_DEPTH_SIZE': 0x884A,
+ 'DEPTH_TEXTURE_MODE': 0x884B,
+ 'TEXTURE_COMPARE_MODE': 0x884C,
+ 'TEXTURE_COMPARE_FUNC': 0x884D,
+ 'COMPARE_R_TO_TEXTURE': 0x884E,
+ 'BUFFER_SIZE': 0x8764,
+ 'BUFFER_USAGE': 0x8765,
+ 'QUERY_COUNTER_BITS': 0x8864,
+ 'CURRENT_QUERY': 0x8865,
+ 'QUERY_RESULT': 0x8866,
+ 'QUERY_RESULT_AVAILABLE': 0x8867,
+ 'ARRAY_BUFFER': 0x8892,
+ 'ELEMENT_ARRAY_BUFFER': 0x8893,
+ 'ARRAY_BUFFER_BINDING': 0x8894,
+ 'ELEMENT_ARRAY_BUFFER_BINDING': 0x8895,
+ 'VERTEX_ARRAY_BUFFER_BINDING': 0x8896,
+ 'NORMAL_ARRAY_BUFFER_BINDING': 0x8897,
+ 'COLOR_ARRAY_BUFFER_BINDING': 0x8898,
+ 'INDEX_ARRAY_BUFFER_BINDING': 0x8899,
+ 'TEXTURE_COORD_ARRAY_BUFFER_BINDING': 0x889A,
+ 'EDGE_FLAG_ARRAY_BUFFER_BINDING': 0x889B,
+ 'SECONDARY_COLOR_ARRAY_BUFFER_BINDING': 0x889C,
+ 'FOG_COORDINATE_ARRAY_BUFFER_BINDING': 0x889D,
+ 'WEIGHT_ARRAY_BUFFER_BINDING': 0x889E,
+ 'VERTEX_ATTRIB_ARRAY_BUFFER_BINDING': 0x889F,
+ 'READ_ONLY': 0x88B8,
+ 'WRITE_ONLY': 0x88B9,
+ 'READ_WRITE': 0x88BA,
+ 'BUFFER_ACCESS': 0x88BB,
+ 'BUFFER_MAPPED': 0x88BC,
+ 'BUFFER_MAP_POINTER': 0x88BD,
+ 'STREAM_DRAW': 0x88E0,
+ 'STREAM_READ': 0x88E1,
+ 'STREAM_COPY': 0x88E2,
+ 'STATIC_DRAW': 0x88E4,
+ 'STATIC_READ': 0x88E5,
+ 'STATIC_COPY': 0x88E6,
+ 'DYNAMIC_DRAW': 0x88E8,
+ 'DYNAMIC_READ': 0x88E9,
+ 'DYNAMIC_COPY': 0x88EA,
+ 'SAMPLES_PASSED': 0x8914,
+ 'VERTEX_ATTRIB_ARRAY_ENABLED': 0x8622,
+ 'VERTEX_ATTRIB_ARRAY_SIZE': 0x8623,
+ 'VERTEX_ATTRIB_ARRAY_STRIDE': 0x8624,
+ 'VERTEX_ATTRIB_ARRAY_TYPE': 0x8625,
+ 'CURRENT_VERTEX_ATTRIB': 0x8626,
+ 'VERTEX_PROGRAM_POINT_SIZE': 0x8642,
+ 'VERTEX_PROGRAM_TWO_SIDE': 0x8643,
+ 'VERTEX_ATTRIB_ARRAY_POINTER': 0x8645,
+ 'STENCIL_BACK_FUNC': 0x8800,
+ 'STENCIL_BACK_FAIL': 0x8801,
+ 'STENCIL_BACK_PASS_DEPTH_FAIL': 0x8802,
+ 'STENCIL_BACK_PASS_DEPTH_PASS': 0x8803,
+ 'MAX_DRAW_BUFFERS': 0x8824,
+ 'DRAW_BUFFER0': 0x8825,
+ 'DRAW_BUFFER1': 0x8826,
+ 'DRAW_BUFFER2': 0x8827,
+ 'DRAW_BUFFER3': 0x8828,
+ 'DRAW_BUFFER4': 0x8829,
+ 'DRAW_BUFFER5': 0x882A,
+ 'DRAW_BUFFER6': 0x882B,
+ 'DRAW_BUFFER7': 0x882C,
+ 'DRAW_BUFFER8': 0x882D,
+ 'DRAW_BUFFER9': 0x882E,
+ 'DRAW_BUFFER10': 0x882F,
+ 'DRAW_BUFFER11': 0x8830,
+ 'DRAW_BUFFER12': 0x8831,
+ 'DRAW_BUFFER13': 0x8832,
+ 'DRAW_BUFFER14': 0x8833,
+ 'DRAW_BUFFER15': 0x8834,
+ 'BLEND_EQUATION_ALPHA': 0x883D,
+ 'POINT_SPRITE': 0x8861,
+ 'COORD_REPLACE': 0x8862,
+ 'MAX_VERTEX_ATTRIBS': 0x8869,
+ 'VERTEX_ATTRIB_ARRAY_NORMALIZED': 0x886A,
+ 'MAX_TEXTURE_COORDS': 0x8871,
+ 'MAX_TEXTURE_IMAGE_UNITS': 0x8872,
+ 'FRAGMENT_SHADER': 0x8B30,
+ 'VERTEX_SHADER': 0x8B31,
+ 'MAX_FRAGMENT_UNIFORM_COMPONENTS': 0x8B49,
+ 'MAX_VERTEX_UNIFORM_COMPONENTS': 0x8B4A,
+ 'MAX_VARYING_FLOATS': 0x8B4B,
+ 'MAX_VERTEX_TEXTURE_IMAGE_UNITS': 0x8B4C,
+ 'MAX_COMBINED_TEXTURE_IMAGE_UNITS': 0x8B4D,
+ 'SHADER_TYPE': 0x8B4F,
+ 'FLOAT_VEC2': 0x8B50,
+ 'FLOAT_VEC3': 0x8B51,
+ 'FLOAT_VEC4': 0x8B52,
+ 'INT_VEC2': 0x8B53,
+ 'INT_VEC3': 0x8B54,
+ 'INT_VEC4': 0x8B55,
+ 'BOOL': 0x8B56,
+ 'BOOL_VEC2': 0x8B57,
+ 'BOOL_VEC3': 0x8B58,
+ 'BOOL_VEC4': 0x8B59,
+ 'FLOAT_MAT2': 0x8B5A,
+ 'FLOAT_MAT3': 0x8B5B,
+ 'FLOAT_MAT4': 0x8B5C,
+ 'SAMPLER_1D': 0x8B5D,
+ 'SAMPLER_2D': 0x8B5E,
+ 'SAMPLER_3D': 0x8B5F,
+ 'SAMPLER_CUBE': 0x8B60,
+ 'SAMPLER_1D_SHADOW': 0x8B61,
+ 'SAMPLER_2D_SHADOW': 0x8B62,
+ 'DELETE_STATUS': 0x8B80,
+ 'COMPILE_STATUS': 0x8B81,
+ 'LINK_STATUS': 0x8B82,
+ 'VALIDATE_STATUS': 0x8B83,
+ 'INFO_LOG_LENGTH': 0x8B84,
+ 'ATTACHED_SHADERS': 0x8B85,
+ 'ACTIVE_UNIFORMS': 0x8B86,
+ 'ACTIVE_UNIFORM_MAX_LENGTH': 0x8B87,
+ 'SHADER_SOURCE_LENGTH': 0x8B88,
+ 'ACTIVE_ATTRIBUTES': 0x8B89,
+ 'ACTIVE_ATTRIBUTE_MAX_LENGTH': 0x8B8A,
+ 'FRAGMENT_SHADER_DERIVATIVE_HINT': 0x8B8B,
+ 'SHADING_LANGUAGE_VERSION': 0x8B8C,
+ 'CURRENT_PROGRAM': 0x8B8D,
+ 'POINT_SPRITE_COORD_ORIGIN': 0x8CA0,
+ 'LOWER_LEFT': 0x8CA1,
+ 'UPPER_LEFT': 0x8CA2,
+ 'STENCIL_BACK_REF': 0x8CA3,
+ 'STENCIL_BACK_VALUE_MASK': 0x8CA4,
+ 'STENCIL_BACK_WRITEMASK': 0x8CA5,
+ 'CURRENT_RASTER_SECONDARY_COLOR': 0x845F,
+ 'PIXEL_PACK_BUFFER': 0x88EB,
+ 'PIXEL_UNPACK_BUFFER': 0x88EC,
+ 'PIXEL_PACK_BUFFER_BINDING': 0x88ED,
+ 'PIXEL_UNPACK_BUFFER_BINDING': 0x88EF,
+ 'FLOAT_MAT2x3': 0x8B65,
+ 'FLOAT_MAT2x4': 0x8B66,
+ 'FLOAT_MAT3x2': 0x8B67,
+ 'FLOAT_MAT3x4': 0x8B68,
+ 'FLOAT_MAT4x2': 0x8B69,
+ 'FLOAT_MAT4x3': 0x8B6A,
+ 'SRGB': 0x8C40,
+ 'SRGB8': 0x8C41,
+ 'SRGB_ALPHA': 0x8C42,
+ 'SRGB8_ALPHA8': 0x8C43,
+ 'SLUMINANCE_ALPHA': 0x8C44,
+ 'SLUMINANCE8_ALPHA8': 0x8C45,
+ 'SLUMINANCE': 0x8C46,
+ 'SLUMINANCE8': 0x8C47,
+ 'COMPRESSED_SRGB': 0x8C48,
+ 'COMPRESSED_SRGB_ALPHA': 0x8C49,
+ 'COMPRESSED_SLUMINANCE': 0x8C4A,
+ 'COMPRESSED_SLUMINANCE_ALPHA': 0x8C4B,
+ 'CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT': 0x0001,
+ 'MAJOR_VERSION': 0x821B,
+ 'MINOR_VERSION': 0x821C,
+ 'NUM_EXTENSIONS': 0x821D,
+ 'CONTEXT_FLAGS': 0x821E,
+ 'DEPTH_BUFFER': 0x8223,
+ 'STENCIL_BUFFER': 0x8224,
+ 'COMPRESSED_RED': 0x8225,
+ 'COMPRESSED_RG': 0x8226,
+ 'RGBA32F': 0x8814,
+ 'RGB32F': 0x8815,
+ 'RGBA16F': 0x881A,
+ 'RGB16F': 0x881B,
+ 'VERTEX_ATTRIB_ARRAY_INTEGER': 0x88FD,
+ 'MAX_ARRAY_TEXTURE_LAYERS': 0x88FF,
+ 'MIN_PROGRAM_TEXEL_OFFSET': 0x8904,
+ 'MAX_PROGRAM_TEXEL_OFFSET': 0x8905,
+ 'CLAMP_VERTEX_COLOR': 0x891A,
+ 'CLAMP_FRAGMENT_COLOR': 0x891B,
+ 'CLAMP_READ_COLOR': 0x891C,
+ 'FIXED_ONLY': 0x891D,
+ 'TEXTURE_RED_TYPE': 0x8C10,
+ 'TEXTURE_GREEN_TYPE': 0x8C11,
+ 'TEXTURE_BLUE_TYPE': 0x8C12,
+ 'TEXTURE_ALPHA_TYPE': 0x8C13,
+ 'TEXTURE_LUMINANCE_TYPE': 0x8C14,
+ 'TEXTURE_INTENSITY_TYPE': 0x8C15,
+ 'TEXTURE_DEPTH_TYPE': 0x8C16,
+ 'UNSIGNED_NORMALIZED': 0x8C17,
+ 'TEXTURE_1D_ARRAY': 0x8C18,
+ 'PROXY_TEXTURE_1D_ARRAY': 0x8C19,
+ 'TEXTURE_2D_ARRAY': 0x8C1A,
+ 'PROXY_TEXTURE_2D_ARRAY': 0x8C1B,
+ 'TEXTURE_BINDING_1D_ARRAY': 0x8C1C,
+ 'TEXTURE_BINDING_2D_ARRAY': 0x8C1D,
+ 'R11F_G11F_B10F': 0x8C3A,
+ 'UNSIGNED_INT_10F_11F_11F_REV': 0x8C3B,
+ 'RGB9_E5': 0x8C3D,
+ 'UNSIGNED_INT_5_9_9_9_REV': 0x8C3E,
+ 'TEXTURE_SHARED_SIZE': 0x8C3F,
+ 'TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH': 0x8C76,
+ 'TRANSFORM_FEEDBACK_BUFFER_MODE': 0x8C7F,
+ 'MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS': 0x8C80,
+ 'TRANSFORM_FEEDBACK_VARYINGS': 0x8C83,
+ 'TRANSFORM_FEEDBACK_BUFFER_START': 0x8C84,
+ 'TRANSFORM_FEEDBACK_BUFFER_SIZE': 0x8C85,
+ 'PRIMITIVES_GENERATED': 0x8C87,
+ 'TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN': 0x8C88,
+ 'RASTERIZER_DISCARD': 0x8C89,
+ 'MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS': 0x8C8A,
+ 'MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS': 0x8C8B,
+ 'INTERLEAVED_ATTRIBS': 0x8C8C,
+ 'SEPARATE_ATTRIBS': 0x8C8D,
+ 'TRANSFORM_FEEDBACK_BUFFER': 0x8C8E,
+ 'TRANSFORM_FEEDBACK_BUFFER_BINDING': 0x8C8F,
+ 'RGBA32UI': 0x8D70,
+ 'RGB32UI': 0x8D71,
+ 'RGBA16UI': 0x8D76,
+ 'RGB16UI': 0x8D77,
+ 'RGBA8UI': 0x8D7C,
+ 'RGB8UI': 0x8D7D,
+ 'RGBA32I': 0x8D82,
+ 'RGB32I': 0x8D83,
+ 'RGBA16I': 0x8D88,
+ 'RGB16I': 0x8D89,
+ 'RGBA8I': 0x8D8E,
+ 'RGB8I': 0x8D8F,
+ 'RED_INTEGER': 0x8D94,
+ 'GREEN_INTEGER': 0x8D95,
+ 'BLUE_INTEGER': 0x8D96,
+ 'ALPHA_INTEGER': 0x8D97,
+ 'RGB_INTEGER': 0x8D98,
+ 'RGBA_INTEGER': 0x8D99,
+ 'BGR_INTEGER': 0x8D9A,
+ 'BGRA_INTEGER': 0x8D9B,
+ 'SAMPLER_1D_ARRAY': 0x8DC0,
+ 'SAMPLER_2D_ARRAY': 0x8DC1,
+ 'SAMPLER_1D_ARRAY_SHADOW': 0x8DC3,
+ 'SAMPLER_2D_ARRAY_SHADOW': 0x8DC4,
+ 'SAMPLER_CUBE_SHADOW': 0x8DC5,
+ 'UNSIGNED_INT_VEC2': 0x8DC6,
+ 'UNSIGNED_INT_VEC3': 0x8DC7,
+ 'UNSIGNED_INT_VEC4': 0x8DC8,
+ 'INT_SAMPLER_1D': 0x8DC9,
+ 'INT_SAMPLER_2D': 0x8DCA,
+ 'INT_SAMPLER_3D': 0x8DCB,
+ 'INT_SAMPLER_CUBE': 0x8DCC,
+ 'INT_SAMPLER_1D_ARRAY': 0x8DCE,
+ 'INT_SAMPLER_2D_ARRAY': 0x8DCF,
+ 'UNSIGNED_INT_SAMPLER_1D': 0x8DD1,
+ 'UNSIGNED_INT_SAMPLER_2D': 0x8DD2,
+ 'UNSIGNED_INT_SAMPLER_3D': 0x8DD3,
+ 'UNSIGNED_INT_SAMPLER_CUBE': 0x8DD4,
+ 'UNSIGNED_INT_SAMPLER_1D_ARRAY': 0x8DD6,
+ 'UNSIGNED_INT_SAMPLER_2D_ARRAY': 0x8DD7,
+ 'QUERY_WAIT': 0x8E13,
+ 'QUERY_NO_WAIT': 0x8E14,
+ 'QUERY_BY_REGION_WAIT': 0x8E15,
+ 'QUERY_BY_REGION_NO_WAIT': 0x8E16,
+ 'MULTISAMPLE_3DFX': 0x86B2,
+ 'SAMPLE_BUFFERS_3DFX': 0x86B3,
+ 'SAMPLES_3DFX': 0x86B4,
+ 'MULTISAMPLE_BIT_3DFX': 0x20000000,
+ 'COMPRESSED_RGB_FXT1_3DFX': 0x86B0,
+ 'COMPRESSED_RGBA_FXT1_3DFX': 0x86B1,
+ 'UNPACK_CLIENT_STORAGE_APPLE': 0x85B2,
+ 'ELEMENT_ARRAY_APPLE': 0x8768,
+ 'ELEMENT_ARRAY_TYPE_APPLE': 0x8769,
+ 'ELEMENT_ARRAY_POINTER_APPLE': 0x876A,
+ 'HALF_APPLE': 0x140B,
+ 'RGBA_FLOAT32_APPLE': 0x8814,
+ 'RGB_FLOAT32_APPLE': 0x8815,
+ 'ALPHA_FLOAT32_APPLE': 0x8816,
+ 'INTENSITY_FLOAT32_APPLE': 0x8817,
+ 'LUMINANCE_FLOAT32_APPLE': 0x8818,
+ 'LUMINANCE_ALPHA_FLOAT32_APPLE': 0x8819,
+ 'RGBA_FLOAT16_APPLE': 0x881A,
+ 'RGB_FLOAT16_APPLE': 0x881B,
+ 'ALPHA_FLOAT16_APPLE': 0x881C,
+ 'INTENSITY_FLOAT16_APPLE': 0x881D,
+ 'LUMINANCE_FLOAT16_APPLE': 0x881E,
+ 'LUMINANCE_ALPHA_FLOAT16_APPLE': 0x881F,
+ 'COLOR_FLOAT_APPLE': 0x8A0F,
+ 'BUFFER_SERIALIZED_MODIFY_APPLE': 0x8A12,
+ 'BUFFER_FLUSHING_UNMAP_APPLE': 0x8A13,
+ 'MIN_PBUFFER_VIEWPORT_DIMS_APPLE': 0x8A10,
+ 'LIGHT_MODEL_SPECULAR_VECTOR_APPLE': 0x85B0,
+ 'TEXTURE_RANGE_LENGTH_APPLE': 0x85B7,
+ 'TEXTURE_RANGE_POINTER_APPLE': 0x85B8,
+ 'TEXTURE_STORAGE_HINT_APPLE': 0x85BC,
+ 'STORAGE_PRIVATE_APPLE': 0x85BD,
+ 'STORAGE_CACHED_APPLE': 0x85BE,
+ 'STORAGE_SHARED_APPLE': 0x85BF,
+ 'TRANSFORM_HINT_APPLE': 0x85B1,
+ 'VERTEX_ARRAY_BINDING_APPLE': 0x85B5,
+ 'VERTEX_ARRAY_RANGE_APPLE': 0x851D,
+ 'VERTEX_ARRAY_RANGE_LENGTH_APPLE': 0x851E,
+ 'VERTEX_ARRAY_STORAGE_HINT_APPLE': 0x851F,
+ 'MAX_VERTEX_ARRAY_RANGE_ELEMENT_APPLE': 0x8520,
+ 'VERTEX_ARRAY_RANGE_POINTER_APPLE': 0x8521,
+ 'STORAGE_CACHED_APPLE': 0x85BE,
+ 'STORAGE_SHARED_APPLE': 0x85BF,
+ 'YCBCR_422_APPLE': 0x85B9,
+ 'UNSIGNED_SHORT_8_8_APPLE': 0x85BA,
+ 'UNSIGNED_SHORT_8_8_REV_APPLE': 0x85BB,
+ 'RGBA_FLOAT_MODE_ARB': 0x8820,
+ 'CLAMP_VERTEX_COLOR_ARB': 0x891A,
+ 'CLAMP_FRAGMENT_COLOR_ARB': 0x891B,
+ 'CLAMP_READ_COLOR_ARB': 0x891C,
+ 'FIXED_ONLY_ARB': 0x891D,
+ 'DEPTH_COMPONENT32F': 0x8CAC,
+ 'DEPTH32F_STENCIL8': 0x8CAD,
+ 'FLOAT_32_UNSIGNED_INT_24_8_REV': 0x8DAD,
+ 'DEPTH_COMPONENT16_ARB': 0x81A5,
+ 'DEPTH_COMPONENT24_ARB': 0x81A6,
+ 'DEPTH_COMPONENT32_ARB': 0x81A7,
+ 'TEXTURE_DEPTH_SIZE_ARB': 0x884A,
+ 'DEPTH_TEXTURE_MODE_ARB': 0x884B,
+ 'MAX_DRAW_BUFFERS_ARB': 0x8824,
+ 'DRAW_BUFFER0_ARB': 0x8825,
+ 'DRAW_BUFFER1_ARB': 0x8826,
+ 'DRAW_BUFFER2_ARB': 0x8827,
+ 'DRAW_BUFFER3_ARB': 0x8828,
+ 'DRAW_BUFFER4_ARB': 0x8829,
+ 'DRAW_BUFFER5_ARB': 0x882A,
+ 'DRAW_BUFFER6_ARB': 0x882B,
+ 'DRAW_BUFFER7_ARB': 0x882C,
+ 'DRAW_BUFFER8_ARB': 0x882D,
+ 'DRAW_BUFFER9_ARB': 0x882E,
+ 'DRAW_BUFFER10_ARB': 0x882F,
+ 'DRAW_BUFFER11_ARB': 0x8830,
+ 'DRAW_BUFFER12_ARB': 0x8831,
+ 'DRAW_BUFFER13_ARB': 0x8832,
+ 'DRAW_BUFFER14_ARB': 0x8833,
+ 'DRAW_BUFFER15_ARB': 0x8834,
+ 'FRAGMENT_PROGRAM_ARB': 0x8804,
+ 'PROGRAM_ALU_INSTRUCTIONS_ARB': 0x8805,
+ 'PROGRAM_TEX_INSTRUCTIONS_ARB': 0x8806,
+ 'PROGRAM_TEX_INDIRECTIONS_ARB': 0x8807,
+ 'PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB': 0x8808,
+ 'PROGRAM_NATIVE_TEX_INSTRUCTIONS_ARB': 0x8809,
+ 'PROGRAM_NATIVE_TEX_INDIRECTIONS_ARB': 0x880A,
+ 'MAX_PROGRAM_ALU_INSTRUCTIONS_ARB': 0x880B,
+ 'MAX_PROGRAM_TEX_INSTRUCTIONS_ARB': 0x880C,
+ 'MAX_PROGRAM_TEX_INDIRECTIONS_ARB': 0x880D,
+ 'MAX_PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB': 0x880E,
+ 'MAX_PROGRAM_NATIVE_TEX_INSTRUCTIONS_ARB': 0x880F,
+ 'MAX_PROGRAM_NATIVE_TEX_INDIRECTIONS_ARB': 0x8810,
+ 'MAX_TEXTURE_COORDS_ARB': 0x8871,
+ 'MAX_TEXTURE_IMAGE_UNITS_ARB': 0x8872,
+ 'FRAGMENT_SHADER_ARB': 0x8B30,
+ 'MAX_FRAGMENT_UNIFORM_COMPONENTS_ARB': 0x8B49,
+ 'FRAGMENT_SHADER_DERIVATIVE_HINT_ARB': 0x8B8B,
+ 'INVALID_FRAMEBUFFER_OPERATION': 0x0506,
+ 'FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING': 0x8210,
+ 'FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE': 0x8211,
+ 'FRAMEBUFFER_ATTACHMENT_RED_SIZE': 0x8212,
+ 'FRAMEBUFFER_ATTACHMENT_GREEN_SIZE': 0x8213,
+ 'FRAMEBUFFER_ATTACHMENT_BLUE_SIZE': 0x8214,
+ 'FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE': 0x8215,
+ 'FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE': 0x8216,
+ 'FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE': 0x8217,
+ 'FRAMEBUFFER_DEFAULT': 0x8218,
+ 'FRAMEBUFFER_UNDEFINED': 0x8219,
+ 'DEPTH_STENCIL_ATTACHMENT': 0x821A,
+ 'INDEX': 0x8222,
+ 'MAX_RENDERBUFFER_SIZE': 0x84E8,
+ 'DEPTH_STENCIL': 0x84F9,
+ 'UNSIGNED_INT_24_8': 0x84FA,
+ 'DEPTH24_STENCIL8': 0x88F0,
+ 'TEXTURE_STENCIL_SIZE': 0x88F1,
+ 'UNSIGNED_NORMALIZED': 0x8C17,
+ 'SRGB': 0x8C40,
+ 'DRAW_FRAMEBUFFER_BINDING': 0x8CA6,
+ 'FRAMEBUFFER_BINDING': 0x8CA6,
+ 'RENDERBUFFER_BINDING': 0x8CA7,
+ 'READ_FRAMEBUFFER': 0x8CA8,
+ 'DRAW_FRAMEBUFFER': 0x8CA9,
+ 'READ_FRAMEBUFFER_BINDING': 0x8CAA,
+ 'RENDERBUFFER_SAMPLES': 0x8CAB,
+ 'FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE': 0x8CD0,
+ 'FRAMEBUFFER_ATTACHMENT_OBJECT_NAME': 0x8CD1,
+ 'FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL': 0x8CD2,
+ 'FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE': 0x8CD3,
+ 'FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER': 0x8CD4,
+ 'FRAMEBUFFER_COMPLETE': 0x8CD5,
+ 'FRAMEBUFFER_INCOMPLETE_ATTACHMENT': 0x8CD6,
+ 'FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT': 0x8CD7,
+ 'FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER': 0x8CDB,
+ 'FRAMEBUFFER_INCOMPLETE_READ_BUFFER': 0x8CDC,
+ 'FRAMEBUFFER_UNSUPPORTED': 0x8CDD,
+ 'MAX_COLOR_ATTACHMENTS': 0x8CDF,
+ 'COLOR_ATTACHMENT0': 0x8CE0,
+ 'COLOR_ATTACHMENT1': 0x8CE1,
+ 'COLOR_ATTACHMENT2': 0x8CE2,
+ 'COLOR_ATTACHMENT3': 0x8CE3,
+ 'COLOR_ATTACHMENT4': 0x8CE4,
+ 'COLOR_ATTACHMENT5': 0x8CE5,
+ 'COLOR_ATTACHMENT6': 0x8CE6,
+ 'COLOR_ATTACHMENT7': 0x8CE7,
+ 'COLOR_ATTACHMENT8': 0x8CE8,
+ 'COLOR_ATTACHMENT9': 0x8CE9,
+ 'COLOR_ATTACHMENT10': 0x8CEA,
+ 'COLOR_ATTACHMENT11': 0x8CEB,
+ 'COLOR_ATTACHMENT12': 0x8CEC,
+ 'COLOR_ATTACHMENT13': 0x8CED,
+ 'COLOR_ATTACHMENT14': 0x8CEE,
+ 'COLOR_ATTACHMENT15': 0x8CEF,
+ 'DEPTH_ATTACHMENT': 0x8D00,
+ 'STENCIL_ATTACHMENT': 0x8D20,
+ 'FRAMEBUFFER': 0x8D40,
+ 'RENDERBUFFER': 0x8D41,
+ 'RENDERBUFFER_WIDTH': 0x8D42,
+ 'RENDERBUFFER_HEIGHT': 0x8D43,
+ 'RENDERBUFFER_INTERNAL_FORMAT': 0x8D44,
+ 'STENCIL_INDEX1': 0x8D46,
+ 'STENCIL_INDEX4': 0x8D47,
+ 'STENCIL_INDEX8': 0x8D48,
+ 'STENCIL_INDEX16': 0x8D49,
+ 'RENDERBUFFER_RED_SIZE': 0x8D50,
+ 'RENDERBUFFER_GREEN_SIZE': 0x8D51,
+ 'RENDERBUFFER_BLUE_SIZE': 0x8D52,
+ 'RENDERBUFFER_ALPHA_SIZE': 0x8D53,
+ 'RENDERBUFFER_DEPTH_SIZE': 0x8D54,
+ 'RENDERBUFFER_STENCIL_SIZE': 0x8D55,
+ 'FRAMEBUFFER_INCOMPLETE_MULTISAMPLE': 0x8D56,
+ 'MAX_SAMPLES': 0x8D57,
+ 'FRAMEBUFFER_SRGB': 0x8DB9,
+ 'LINES_ADJACENCY_ARB': 0xA,
+ 'LINE_STRIP_ADJACENCY_ARB': 0xB,
+ 'TRIANGLES_ADJACENCY_ARB': 0xC,
+ 'TRIANGLE_STRIP_ADJACENCY_ARB': 0xD,
+ 'PROGRAM_POINT_SIZE_ARB': 0x8642,
+ 'MAX_GEOMETRY_TEXTURE_IMAGE_UNITS_ARB': 0x8C29,
+ 'FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER': 0x8CD4,
+ 'FRAMEBUFFER_ATTACHMENT_LAYERED_ARB': 0x8DA7,
+ 'FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS_ARB': 0x8DA8,
+ 'FRAMEBUFFER_INCOMPLETE_LAYER_COUNT_ARB': 0x8DA9,
+ 'GEOMETRY_SHADER_ARB': 0x8DD9,
+ 'GEOMETRY_VERTICES_OUT_ARB': 0x8DDA,
+ 'GEOMETRY_INPUT_TYPE_ARB': 0x8DDB,
+ 'GEOMETRY_OUTPUT_TYPE_ARB': 0x8DDC,
+ 'MAX_GEOMETRY_VARYING_COMPONENTS_ARB': 0x8DDD,
+ 'MAX_VERTEX_VARYING_COMPONENTS_ARB': 0x8DDE,
+ 'MAX_GEOMETRY_UNIFORM_COMPONENTS_ARB': 0x8DDF,
+ 'MAX_GEOMETRY_OUTPUT_VERTICES_ARB': 0x8DE0,
+ 'MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS_ARB': 0x8DE1,
+ 'HALF_FLOAT_ARB': 0x140B,
+ 'HALF_FLOAT': 0x140B,
+ 'CONSTANT_COLOR': 0x8001,
+ 'ONE_MINUS_CONSTANT_COLOR': 0x8002,
+ 'CONSTANT_ALPHA': 0x8003,
+ 'ONE_MINUS_CONSTANT_ALPHA': 0x8004,
+ 'BLEND_COLOR': 0x8005,
+ 'FUNC_ADD': 0x8006,
+ 'MIN': 0x8007,
+ 'MAX': 0x8008,
+ 'BLEND_EQUATION': 0x8009,
+ 'FUNC_SUBTRACT': 0x800A,
+ 'FUNC_REVERSE_SUBTRACT': 0x800B,
+ 'CONVOLUTION_1D': 0x8010,
+ 'CONVOLUTION_2D': 0x8011,
+ 'SEPARABLE_2D': 0x8012,
+ 'CONVOLUTION_BORDER_MODE': 0x8013,
+ 'CONVOLUTION_FILTER_SCALE': 0x8014,
+ 'CONVOLUTION_FILTER_BIAS': 0x8015,
+ 'REDUCE': 0x8016,
+ 'CONVOLUTION_FORMAT': 0x8017,
+ 'CONVOLUTION_WIDTH': 0x8018,
+ 'CONVOLUTION_HEIGHT': 0x8019,
+ 'MAX_CONVOLUTION_WIDTH': 0x801A,
+ 'MAX_CONVOLUTION_HEIGHT': 0x801B,
+ 'POST_CONVOLUTION_RED_SCALE': 0x801C,
+ 'POST_CONVOLUTION_GREEN_SCALE': 0x801D,
+ 'POST_CONVOLUTION_BLUE_SCALE': 0x801E,
+ 'POST_CONVOLUTION_ALPHA_SCALE': 0x801F,
+ 'POST_CONVOLUTION_RED_BIAS': 0x8020,
+ 'POST_CONVOLUTION_GREEN_BIAS': 0x8021,
+ 'POST_CONVOLUTION_BLUE_BIAS': 0x8022,
+ 'POST_CONVOLUTION_ALPHA_BIAS': 0x8023,
+ 'HISTOGRAM': 0x8024,
+ 'PROXY_HISTOGRAM': 0x8025,
+ 'HISTOGRAM_WIDTH': 0x8026,
+ 'HISTOGRAM_FORMAT': 0x8027,
+ 'HISTOGRAM_RED_SIZE': 0x8028,
+ 'HISTOGRAM_GREEN_SIZE': 0x8029,
+ 'HISTOGRAM_BLUE_SIZE': 0x802A,
+ 'HISTOGRAM_ALPHA_SIZE': 0x802B,
+ 'HISTOGRAM_LUMINANCE_SIZE': 0x802C,
+ 'HISTOGRAM_SINK': 0x802D,
+ 'MINMAX': 0x802E,
+ 'MINMAX_FORMAT': 0x802F,
+ 'MINMAX_SINK': 0x8030,
+ 'TABLE_TOO_LARGE': 0x8031,
+ 'COLOR_MATRIX': 0x80B1,
+ 'COLOR_MATRIX_STACK_DEPTH': 0x80B2,
+ 'MAX_COLOR_MATRIX_STACK_DEPTH': 0x80B3,
+ 'POST_COLOR_MATRIX_RED_SCALE': 0x80B4,
+ 'POST_COLOR_MATRIX_GREEN_SCALE': 0x80B5,
+ 'POST_COLOR_MATRIX_BLUE_SCALE': 0x80B6,
+ 'POST_COLOR_MATRIX_ALPHA_SCALE': 0x80B7,
+ 'POST_COLOR_MATRIX_RED_BIAS': 0x80B8,
+ 'POST_COLOR_MATRIX_GREEN_BIAS': 0x80B9,
+ 'POST_COLOR_MATRIX_BLUE_BIAS': 0x80BA,
+ 'POST_COLOR_MATRIX_ALPHA_BIAS': 0x80BB,
+ 'COLOR_TABLE': 0x80D0,
+ 'POST_CONVOLUTION_COLOR_TABLE': 0x80D1,
+ 'POST_COLOR_MATRIX_COLOR_TABLE': 0x80D2,
+ 'PROXY_COLOR_TABLE': 0x80D3,
+ 'PROXY_POST_CONVOLUTION_COLOR_TABLE': 0x80D4,
+ 'PROXY_POST_COLOR_MATRIX_COLOR_TABLE': 0x80D5,
+ 'COLOR_TABLE_SCALE': 0x80D6,
+ 'COLOR_TABLE_BIAS': 0x80D7,
+ 'COLOR_TABLE_FORMAT': 0x80D8,
+ 'COLOR_TABLE_WIDTH': 0x80D9,
+ 'COLOR_TABLE_RED_SIZE': 0x80DA,
+ 'COLOR_TABLE_GREEN_SIZE': 0x80DB,
+ 'COLOR_TABLE_BLUE_SIZE': 0x80DC,
+ 'COLOR_TABLE_ALPHA_SIZE': 0x80DD,
+ 'COLOR_TABLE_LUMINANCE_SIZE': 0x80DE,
+ 'COLOR_TABLE_INTENSITY_SIZE': 0x80DF,
+ 'IGNORE_BORDER': 0x8150,
+ 'CONSTANT_BORDER': 0x8151,
+ 'WRAP_BORDER': 0x8152,
+ 'REPLICATE_BORDER': 0x8153,
+ 'CONVOLUTION_BORDER_COLOR': 0x8154,
+ 'VERTEX_ATTRIB_ARRAY_DIVISOR_ARB': 0x88FE,
+ 'MAP_READ_BIT': 0x0001,
+ 'MAP_WRITE_BIT': 0x0002,
+ 'MAP_INVALIDATE_RANGE_BIT': 0x0004,
+ 'MAP_INVALIDATE_BUFFER_BIT': 0x0008,
+ 'MAP_FLUSH_EXPLICIT_BIT': 0x0010,
+ 'MAP_UNSYNCHRONIZED_BIT': 0x0020,
+ 'MATRIX_PALETTE_ARB': 0x8840,
+ 'MAX_MATRIX_PALETTE_STACK_DEPTH_ARB': 0x8841,
+ 'MAX_PALETTE_MATRICES_ARB': 0x8842,
+ 'CURRENT_PALETTE_MATRIX_ARB': 0x8843,
+ 'MATRIX_INDEX_ARRAY_ARB': 0x8844,
+ 'CURRENT_MATRIX_INDEX_ARB': 0x8845,
+ 'MATRIX_INDEX_ARRAY_SIZE_ARB': 0x8846,
+ 'MATRIX_INDEX_ARRAY_TYPE_ARB': 0x8847,
+ 'MATRIX_INDEX_ARRAY_STRIDE_ARB': 0x8848,
+ 'MATRIX_INDEX_ARRAY_POINTER_ARB': 0x8849,
+ 'MULTISAMPLE_ARB': 0x809D,
+ 'SAMPLE_ALPHA_TO_COVERAGE_ARB': 0x809E,
+ 'SAMPLE_ALPHA_TO_ONE_ARB': 0x809F,
+ 'SAMPLE_COVERAGE_ARB': 0x80A0,
+ 'SAMPLE_BUFFERS_ARB': 0x80A8,
+ 'SAMPLES_ARB': 0x80A9,
+ 'SAMPLE_COVERAGE_VALUE_ARB': 0x80AA,
+ 'SAMPLE_COVERAGE_INVERT_ARB': 0x80AB,
+ 'MULTISAMPLE_BIT_ARB': 0x20000000,
+ 'TEXTURE0_ARB': 0x84C0,
+ 'TEXTURE1_ARB': 0x84C1,
+ 'TEXTURE2_ARB': 0x84C2,
+ 'TEXTURE3_ARB': 0x84C3,
+ 'TEXTURE4_ARB': 0x84C4,
+ 'TEXTURE5_ARB': 0x84C5,
+ 'TEXTURE6_ARB': 0x84C6,
+ 'TEXTURE7_ARB': 0x84C7,
+ 'TEXTURE8_ARB': 0x84C8,
+ 'TEXTURE9_ARB': 0x84C9,
+ 'TEXTURE10_ARB': 0x84CA,
+ 'TEXTURE11_ARB': 0x84CB,
+ 'TEXTURE12_ARB': 0x84CC,
+ 'TEXTURE13_ARB': 0x84CD,
+ 'TEXTURE14_ARB': 0x84CE,
+ 'TEXTURE15_ARB': 0x84CF,
+ 'TEXTURE16_ARB': 0x84D0,
+ 'TEXTURE17_ARB': 0x84D1,
+ 'TEXTURE18_ARB': 0x84D2,
+ 'TEXTURE19_ARB': 0x84D3,
+ 'TEXTURE20_ARB': 0x84D4,
+ 'TEXTURE21_ARB': 0x84D5,
+ 'TEXTURE22_ARB': 0x84D6,
+ 'TEXTURE23_ARB': 0x84D7,
+ 'TEXTURE24_ARB': 0x84D8,
+ 'TEXTURE25_ARB': 0x84D9,
+ 'TEXTURE26_ARB': 0x84DA,
+ 'TEXTURE27_ARB': 0x84DB,
+ 'TEXTURE28_ARB': 0x84DC,
+ 'TEXTURE29_ARB': 0x84DD,
+ 'TEXTURE30_ARB': 0x84DE,
+ 'TEXTURE31_ARB': 0x84DF,
+ 'ACTIVE_TEXTURE_ARB': 0x84E0,
+ 'CLIENT_ACTIVE_TEXTURE_ARB': 0x84E1,
+ 'MAX_TEXTURE_UNITS_ARB': 0x84E2,
+ 'QUERY_COUNTER_BITS_ARB': 0x8864,
+ 'CURRENT_QUERY_ARB': 0x8865,
+ 'QUERY_RESULT_ARB': 0x8866,
+ 'QUERY_RESULT_AVAILABLE_ARB': 0x8867,
+ 'SAMPLES_PASSED_ARB': 0x8914,
+ 'PIXEL_PACK_BUFFER_ARB': 0x88EB,
+ 'PIXEL_UNPACK_BUFFER_ARB': 0x88EC,
+ 'PIXEL_PACK_BUFFER_BINDING_ARB': 0x88ED,
+ 'PIXEL_UNPACK_BUFFER_BINDING_ARB': 0x88EF,
+ 'POINT_SIZE_MIN_ARB': 0x8126,
+ 'POINT_SIZE_MAX_ARB': 0x8127,
+ 'POINT_FADE_THRESHOLD_SIZE_ARB': 0x8128,
+ 'POINT_DISTANCE_ATTENUATION_ARB': 0x8129,
+ 'POINT_SPRITE_ARB': 0x8861,
+ 'COORD_REPLACE_ARB': 0x8862,
+ 'PROGRAM_OBJECT_ARB': 0x8B40,
+ 'SHADER_OBJECT_ARB': 0x8B48,
+ 'OBJECT_TYPE_ARB': 0x8B4E,
+ 'OBJECT_SUBTYPE_ARB': 0x8B4F,
+ 'FLOAT_VEC2_ARB': 0x8B50,
+ 'FLOAT_VEC3_ARB': 0x8B51,
+ 'FLOAT_VEC4_ARB': 0x8B52,
+ 'INT_VEC2_ARB': 0x8B53,
+ 'INT_VEC3_ARB': 0x8B54,
+ 'INT_VEC4_ARB': 0x8B55,
+ 'BOOL_ARB': 0x8B56,
+ 'BOOL_VEC2_ARB': 0x8B57,
+ 'BOOL_VEC3_ARB': 0x8B58,
+ 'BOOL_VEC4_ARB': 0x8B59,
+ 'FLOAT_MAT2_ARB': 0x8B5A,
+ 'FLOAT_MAT3_ARB': 0x8B5B,
+ 'FLOAT_MAT4_ARB': 0x8B5C,
+ 'SAMPLER_1D_ARB': 0x8B5D,
+ 'SAMPLER_2D_ARB': 0x8B5E,
+ 'SAMPLER_3D_ARB': 0x8B5F,
+ 'SAMPLER_CUBE_ARB': 0x8B60,
+ 'SAMPLER_1D_SHADOW_ARB': 0x8B61,
+ 'SAMPLER_2D_SHADOW_ARB': 0x8B62,
+ 'SAMPLER_2D_RECT_ARB': 0x8B63,
+ 'SAMPLER_2D_RECT_SHADOW_ARB': 0x8B64,
+ 'OBJECT_DELETE_STATUS_ARB': 0x8B80,
+ 'OBJECT_COMPILE_STATUS_ARB': 0x8B81,
+ 'OBJECT_LINK_STATUS_ARB': 0x8B82,
+ 'OBJECT_VALIDATE_STATUS_ARB': 0x8B83,
+ 'OBJECT_INFO_LOG_LENGTH_ARB': 0x8B84,
+ 'OBJECT_ATTACHED_OBJECTS_ARB': 0x8B85,
+ 'OBJECT_ACTIVE_UNIFORMS_ARB': 0x8B86,
+ 'OBJECT_ACTIVE_UNIFORM_MAX_LENGTH_ARB': 0x8B87,
+ 'ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH': 0x8A35,
+ 'UNIFORM_NAME_LENGTH': 0x8A39,
+ 'UNIFORM_BLOCK_NAME_LENGTH': 0x8A41,
+ 'OBJECT_SHADER_SOURCE_LENGTH_ARB': 0x8B88,
+ 'SHADING_LANGUAGE_VERSION_ARB': 0x8B8C,
+ 'TEXTURE_COMPARE_MODE_ARB': 0x884C,
+ 'TEXTURE_COMPARE_FUNC_ARB': 0x884D,
+ 'COMPARE_R_TO_TEXTURE_ARB': 0x884E,
+ 'TEXTURE_COMPARE_FAIL_VALUE_ARB': 0x80BF,
+ 'CLAMP_TO_BORDER_ARB': 0x812D,
+ 'TEXTURE_BUFFER_ARB': 0x8C2A,
+ 'MAX_TEXTURE_BUFFER_SIZE_ARB': 0x8C2B,
+ 'TEXTURE_BINDING_BUFFER_ARB': 0x8C2C,
+ 'TEXTURE_BUFFER_DATA_STORE_BINDING_ARB': 0x8C2D,
+ 'TEXTURE_BUFFER_FORMAT_ARB': 0x8C2E,
+ 'COMPRESSED_ALPHA_ARB': 0x84E9,
+ 'COMPRESSED_LUMINANCE_ARB': 0x84EA,
+ 'COMPRESSED_LUMINANCE_ALPHA_ARB': 0x84EB,
+ 'COMPRESSED_INTENSITY_ARB': 0x84EC,
+ 'COMPRESSED_RGB_ARB': 0x84ED,
+ 'COMPRESSED_RGBA_ARB': 0x84EE,
+ 'TEXTURE_COMPRESSION_HINT_ARB': 0x84EF,
+ 'TEXTURE_COMPRESSED_IMAGE_SIZE_ARB': 0x86A0,
+ 'TEXTURE_COMPRESSED_ARB': 0x86A1,
+ 'NUM_COMPRESSED_TEXTURE_FORMATS_ARB': 0x86A2,
+ 'COMPRESSED_TEXTURE_FORMATS_ARB': 0x86A3,
+ 'COMPRESSED_RED_RGTC1': 0x8DBB,
+ 'COMPRESSED_SIGNED_RED_RGTC1': 0x8DBC,
+ 'COMPRESSED_RG_RGTC2': 0x8DBD,
+ 'COMPRESSED_SIGNED_RG_RGTC2': 0x8DBE,
+ 'NORMAL_MAP_ARB': 0x8511,
+ 'REFLECTION_MAP_ARB': 0x8512,
+ 'TEXTURE_CUBE_MAP_ARB': 0x8513,
+ 'TEXTURE_BINDING_CUBE_MAP_ARB': 0x8514,
+ 'TEXTURE_CUBE_MAP_POSITIVE_X_ARB': 0x8515,
+ 'TEXTURE_CUBE_MAP_NEGATIVE_X_ARB': 0x8516,
+ 'TEXTURE_CUBE_MAP_POSITIVE_Y_ARB': 0x8517,
+ 'TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB': 0x8518,
+ 'TEXTURE_CUBE_MAP_POSITIVE_Z_ARB': 0x8519,
+ 'TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB': 0x851A,
+ 'PROXY_TEXTURE_CUBE_MAP_ARB': 0x851B,
+ 'MAX_CUBE_MAP_TEXTURE_SIZE_ARB': 0x851C,
+ 'SUBTRACT_ARB': 0x84E7,
+ 'COMBINE_ARB': 0x8570,
+ 'COMBINE_RGB_ARB': 0x8571,
+ 'COMBINE_ALPHA_ARB': 0x8572,
+ 'RGB_SCALE_ARB': 0x8573,
+ 'ADD_SIGNED_ARB': 0x8574,
+ 'INTERPOLATE_ARB': 0x8575,
+ 'CONSTANT_ARB': 0x8576,
+ 'PRIMARY_COLOR_ARB': 0x8577,
+ 'PREVIOUS_ARB': 0x8578,
+ 'SOURCE0_RGB_ARB': 0x8580,
+ 'SOURCE1_RGB_ARB': 0x8581,
+ 'SOURCE2_RGB_ARB': 0x8582,
+ 'SOURCE0_ALPHA_ARB': 0x8588,
+ 'SOURCE1_ALPHA_ARB': 0x8589,
+ 'SOURCE2_ALPHA_ARB': 0x858A,
+ 'OPERAND0_RGB_ARB': 0x8590,
+ 'OPERAND1_RGB_ARB': 0x8591,
+ 'OPERAND2_RGB_ARB': 0x8592,
+ 'OPERAND0_ALPHA_ARB': 0x8598,
+ 'OPERAND1_ALPHA_ARB': 0x8599,
+ 'OPERAND2_ALPHA_ARB': 0x859A,
+ 'DOT3_RGB_ARB': 0x86AE,
+ 'DOT3_RGBA_ARB': 0x86AF,
+ 'RGBA32F_ARB': 0x8814,
+ 'RGB32F_ARB': 0x8815,
+ 'ALPHA32F_ARB': 0x8816,
+ 'INTENSITY32F_ARB': 0x8817,
+ 'LUMINANCE32F_ARB': 0x8818,
+ 'LUMINANCE_ALPHA32F_ARB': 0x8819,
+ 'RGBA16F_ARB': 0x881A,
+ 'RGB16F_ARB': 0x881B,
+ 'ALPHA16F_ARB': 0x881C,
+ 'INTENSITY16F_ARB': 0x881D,
+ 'LUMINANCE16F_ARB': 0x881E,
+ 'LUMINANCE_ALPHA16F_ARB': 0x881F,
+ 'TEXTURE_RED_TYPE_ARB': 0x8C10,
+ 'TEXTURE_GREEN_TYPE_ARB': 0x8C11,
+ 'TEXTURE_BLUE_TYPE_ARB': 0x8C12,
+ 'TEXTURE_ALPHA_TYPE_ARB': 0x8C13,
+ 'TEXTURE_LUMINANCE_TYPE_ARB': 0x8C14,
+ 'TEXTURE_INTENSITY_TYPE_ARB': 0x8C15,
+ 'TEXTURE_DEPTH_TYPE_ARB': 0x8C16,
+ 'UNSIGNED_NORMALIZED_ARB': 0x8C17,
+ 'MIRRORED_REPEAT_ARB': 0x8370,
+ 'TEXTURE_RECTANGLE_ARB': 0x84F5,
+ 'TEXTURE_BINDING_RECTANGLE_ARB': 0x84F6,
+ 'PROXY_TEXTURE_RECTANGLE_ARB': 0x84F7,
+ 'MAX_RECTANGLE_TEXTURE_SIZE_ARB': 0x84F8,
+ 'SAMPLER_2D_RECT_ARB': 0x8B63,
+ 'SAMPLER_2D_RECT_SHADOW_ARB': 0x8B64,
+ 'RED': 0x1903,
+ 'RG': 0x8227,
+ 'RG_INTEGER': 0x8228,
+ 'R8': 0x8229,
+ 'R16': 0x822A,
+ 'RG8': 0x822B,
+ 'RG16': 0x822C,
+ 'R16F': 0x822D,
+ 'R32F': 0x822E,
+ 'RG16F': 0x822F,
+ 'RG32F': 0x8230,
+ 'R8I': 0x8231,
+ 'R8UI': 0x8232,
+ 'R16I': 0x8233,
+ 'R16UI': 0x8234,
+ 'R32I': 0x8235,
+ 'R32UI': 0x8236,
+ 'RG8I': 0x8237,
+ 'RG8UI': 0x8238,
+ 'RG16I': 0x8239,
+ 'RG16UI': 0x823A,
+ 'RG32I': 0x823B,
+ 'RG32UI': 0x823C,
+ 'TRANSPOSE_MODELVIEW_MATRIX_ARB': 0x84E3,
+ 'TRANSPOSE_PROJECTION_MATRIX_ARB': 0x84E4,
+ 'TRANSPOSE_TEXTURE_MATRIX_ARB': 0x84E5,
+ 'TRANSPOSE_COLOR_MATRIX_ARB': 0x84E6,
+ 'VERTEX_ARRAY_BINDING': 0x85B5,
+ 'MODELVIEW0_ARB': 0x1700,
+ 'MODELVIEW1_ARB': 0x850A,
+ 'MAX_VERTEX_UNITS_ARB': 0x86A4,
+ 'ACTIVE_VERTEX_UNITS_ARB': 0x86A5,
+ 'WEIGHT_SUM_UNITY_ARB': 0x86A6,
+ 'VERTEX_BLEND_ARB': 0x86A7,
+ 'CURRENT_WEIGHT_ARB': 0x86A8,
+ 'WEIGHT_ARRAY_TYPE_ARB': 0x86A9,
+ 'WEIGHT_ARRAY_STRIDE_ARB': 0x86AA,
+ 'WEIGHT_ARRAY_SIZE_ARB': 0x86AB,
+ 'WEIGHT_ARRAY_POINTER_ARB': 0x86AC,
+ 'WEIGHT_ARRAY_ARB': 0x86AD,
+ 'MODELVIEW2_ARB': 0x8722,
+ 'MODELVIEW3_ARB': 0x8723,
+ 'MODELVIEW4_ARB': 0x8724,
+ 'MODELVIEW5_ARB': 0x8725,
+ 'MODELVIEW6_ARB': 0x8726,
+ 'MODELVIEW7_ARB': 0x8727,
+ 'MODELVIEW8_ARB': 0x8728,
+ 'MODELVIEW9_ARB': 0x8729,
+ 'MODELVIEW10_ARB': 0x872A,
+ 'MODELVIEW11_ARB': 0x872B,
+ 'MODELVIEW12_ARB': 0x872C,
+ 'MODELVIEW13_ARB': 0x872D,
+ 'MODELVIEW14_ARB': 0x872E,
+ 'MODELVIEW15_ARB': 0x872F,
+ 'MODELVIEW16_ARB': 0x8730,
+ 'MODELVIEW17_ARB': 0x8731,
+ 'MODELVIEW18_ARB': 0x8732,
+ 'MODELVIEW19_ARB': 0x8733,
+ 'MODELVIEW20_ARB': 0x8734,
+ 'MODELVIEW21_ARB': 0x8735,
+ 'MODELVIEW22_ARB': 0x8736,
+ 'MODELVIEW23_ARB': 0x8737,
+ 'MODELVIEW24_ARB': 0x8738,
+ 'MODELVIEW25_ARB': 0x8739,
+ 'MODELVIEW26_ARB': 0x873A,
+ 'MODELVIEW27_ARB': 0x873B,
+ 'MODELVIEW28_ARB': 0x873C,
+ 'MODELVIEW29_ARB': 0x873D,
+ 'MODELVIEW30_ARB': 0x873E,
+ 'MODELVIEW31_ARB': 0x873F,
+ 'BUFFER_SIZE_ARB': 0x8764,
+ 'BUFFER_USAGE_ARB': 0x8765,
+ 'ARRAY_BUFFER_ARB': 0x8892,
+ 'ELEMENT_ARRAY_BUFFER_ARB': 0x8893,
+ 'ARRAY_BUFFER_BINDING_ARB': 0x8894,
+ 'ELEMENT_ARRAY_BUFFER_BINDING_ARB': 0x8895,
+ 'VERTEX_ARRAY_BUFFER_BINDING_ARB': 0x8896,
+ 'NORMAL_ARRAY_BUFFER_BINDING_ARB': 0x8897,
+ 'COLOR_ARRAY_BUFFER_BINDING_ARB': 0x8898,
+ 'INDEX_ARRAY_BUFFER_BINDING_ARB': 0x8899,
+ 'TEXTURE_COORD_ARRAY_BUFFER_BINDING_ARB': 0x889A,
+ 'EDGE_FLAG_ARRAY_BUFFER_BINDING_ARB': 0x889B,
+ 'SECONDARY_COLOR_ARRAY_BUFFER_BINDING_ARB': 0x889C,
+ 'FOG_COORDINATE_ARRAY_BUFFER_BINDING_ARB': 0x889D,
+ 'WEIGHT_ARRAY_BUFFER_BINDING_ARB': 0x889E,
+ 'VERTEX_ATTRIB_ARRAY_BUFFER_BINDING_ARB': 0x889F,
+ 'READ_ONLY_ARB': 0x88B8,
+ 'WRITE_ONLY_ARB': 0x88B9,
+ 'READ_WRITE_ARB': 0x88BA,
+ 'BUFFER_ACCESS_ARB': 0x88BB,
+ 'BUFFER_MAPPED_ARB': 0x88BC,
+ 'BUFFER_MAP_POINTER_ARB': 0x88BD,
+ 'STREAM_DRAW_ARB': 0x88E0,
+ 'STREAM_READ_ARB': 0x88E1,
+ 'STREAM_COPY_ARB': 0x88E2,
+ 'STATIC_DRAW_ARB': 0x88E4,
+ 'STATIC_READ_ARB': 0x88E5,
+ 'STATIC_COPY_ARB': 0x88E6,
+ 'DYNAMIC_DRAW_ARB': 0x88E8,
+ 'DYNAMIC_READ_ARB': 0x88E9,
+ 'DYNAMIC_COPY_ARB': 0x88EA,
+ 'COLOR_SUM_ARB': 0x8458,
+ 'VERTEX_PROGRAM_ARB': 0x8620,
+ 'VERTEX_ATTRIB_ARRAY_ENABLED_ARB': 0x8622,
+ 'VERTEX_ATTRIB_ARRAY_SIZE_ARB': 0x8623,
+ 'VERTEX_ATTRIB_ARRAY_STRIDE_ARB': 0x8624,
+ 'VERTEX_ATTRIB_ARRAY_TYPE_ARB': 0x8625,
+ 'CURRENT_VERTEX_ATTRIB_ARB': 0x8626,
+ 'PROGRAM_LENGTH_ARB': 0x8627,
+ 'PROGRAM_STRING_ARB': 0x8628,
+ 'MAX_PROGRAM_MATRIX_STACK_DEPTH_ARB': 0x862E,
+ 'MAX_PROGRAM_MATRICES_ARB': 0x862F,
+ 'CURRENT_MATRIX_STACK_DEPTH_ARB': 0x8640,
+ 'CURRENT_MATRIX_ARB': 0x8641,
+ 'VERTEX_PROGRAM_POINT_SIZE_ARB': 0x8642,
+ 'VERTEX_PROGRAM_TWO_SIDE_ARB': 0x8643,
+ 'VERTEX_ATTRIB_ARRAY_POINTER_ARB': 0x8645,
+ 'PROGRAM_ERROR_POSITION_ARB': 0x864B,
+ 'PROGRAM_BINDING_ARB': 0x8677,
+ 'MAX_VERTEX_ATTRIBS_ARB': 0x8869,
+ 'VERTEX_ATTRIB_ARRAY_NORMALIZED_ARB': 0x886A,
+ 'PROGRAM_ERROR_STRING_ARB': 0x8874,
+ 'PROGRAM_FORMAT_ASCII_ARB': 0x8875,
+ 'PROGRAM_FORMAT_ARB': 0x8876,
+ 'PROGRAM_INSTRUCTIONS_ARB': 0x88A0,
+ 'MAX_PROGRAM_INSTRUCTIONS_ARB': 0x88A1,
+ 'PROGRAM_NATIVE_INSTRUCTIONS_ARB': 0x88A2,
+ 'MAX_PROGRAM_NATIVE_INSTRUCTIONS_ARB': 0x88A3,
+ 'PROGRAM_TEMPORARIES_ARB': 0x88A4,
+ 'MAX_PROGRAM_TEMPORARIES_ARB': 0x88A5,
+ 'PROGRAM_NATIVE_TEMPORARIES_ARB': 0x88A6,
+ 'MAX_PROGRAM_NATIVE_TEMPORARIES_ARB': 0x88A7,
+ 'PROGRAM_PARAMETERS_ARB': 0x88A8,
+ 'MAX_PROGRAM_PARAMETERS_ARB': 0x88A9,
+ 'PROGRAM_NATIVE_PARAMETERS_ARB': 0x88AA,
+ 'MAX_PROGRAM_NATIVE_PARAMETERS_ARB': 0x88AB,
+ 'PROGRAM_ATTRIBS_ARB': 0x88AC,
+ 'MAX_PROGRAM_ATTRIBS_ARB': 0x88AD,
+ 'PROGRAM_NATIVE_ATTRIBS_ARB': 0x88AE,
+ 'MAX_PROGRAM_NATIVE_ATTRIBS_ARB': 0x88AF,
+ 'PROGRAM_ADDRESS_REGISTERS_ARB': 0x88B0,
+ 'MAX_PROGRAM_ADDRESS_REGISTERS_ARB': 0x88B1,
+ 'PROGRAM_NATIVE_ADDRESS_REGISTERS_ARB': 0x88B2,
+ 'MAX_PROGRAM_NATIVE_ADDRESS_REGISTERS_ARB': 0x88B3,
+ 'MAX_PROGRAM_LOCAL_PARAMETERS_ARB': 0x88B4,
+ 'MAX_PROGRAM_ENV_PARAMETERS_ARB': 0x88B5,
+ 'PROGRAM_UNDER_NATIVE_LIMITS_ARB': 0x88B6,
+ 'TRANSPOSE_CURRENT_MATRIX_ARB': 0x88B7,
+ 'MATRIX0_ARB': 0x88C0,
+ 'MATRIX1_ARB': 0x88C1,
+ 'MATRIX2_ARB': 0x88C2,
+ 'MATRIX3_ARB': 0x88C3,
+ 'MATRIX4_ARB': 0x88C4,
+ 'MATRIX5_ARB': 0x88C5,
+ 'MATRIX6_ARB': 0x88C6,
+ 'MATRIX7_ARB': 0x88C7,
+ 'MATRIX8_ARB': 0x88C8,
+ 'MATRIX9_ARB': 0x88C9,
+ 'MATRIX10_ARB': 0x88CA,
+ 'MATRIX11_ARB': 0x88CB,
+ 'MATRIX12_ARB': 0x88CC,
+ 'MATRIX13_ARB': 0x88CD,
+ 'MATRIX14_ARB': 0x88CE,
+ 'MATRIX15_ARB': 0x88CF,
+ 'MATRIX16_ARB': 0x88D0,
+ 'MATRIX17_ARB': 0x88D1,
+ 'MATRIX18_ARB': 0x88D2,
+ 'MATRIX19_ARB': 0x88D3,
+ 'MATRIX20_ARB': 0x88D4,
+ 'MATRIX21_ARB': 0x88D5,
+ 'MATRIX22_ARB': 0x88D6,
+ 'MATRIX23_ARB': 0x88D7,
+ 'MATRIX24_ARB': 0x88D8,
+ 'MATRIX25_ARB': 0x88D9,
+ 'MATRIX26_ARB': 0x88DA,
+ 'MATRIX27_ARB': 0x88DB,
+ 'MATRIX28_ARB': 0x88DC,
+ 'MATRIX29_ARB': 0x88DD,
+ 'MATRIX30_ARB': 0x88DE,
+ 'MATRIX31_ARB': 0x88DF,
+ 'VERTEX_SHADER_ARB': 0x8B31,
+ 'MAX_VERTEX_UNIFORM_COMPONENTS_ARB': 0x8B4A,
+ 'MAX_VARYING_FLOATS_ARB': 0x8B4B,
+ 'MAX_VERTEX_TEXTURE_IMAGE_UNITS_ARB': 0x8B4C,
+ 'MAX_COMBINED_TEXTURE_IMAGE_UNITS_ARB': 0x8B4D,
+ 'OBJECT_ACTIVE_ATTRIBUTES_ARB': 0x8B89,
+ 'OBJECT_ACTIVE_ATTRIBUTE_MAX_LENGTH_ARB': 0x8B8A,
+ 'TEXTURE_POINT_MODE_ATIX': 0x60B0,
+ 'TEXTURE_POINT_ONE_COORD_ATIX': 0x60B1,
+ 'TEXTURE_POINT_SPRITE_ATIX': 0x60B2,
+ 'POINT_SPRITE_CULL_MODE_ATIX': 0x60B3,
+ 'POINT_SPRITE_CULL_CENTER_ATIX': 0x60B4,
+ 'POINT_SPRITE_CULL_CLIP_ATIX': 0x60B5,
+ 'MODULATE_ADD_ATIX': 0x8744,
+ 'MODULATE_SIGNED_ADD_ATIX': 0x8745,
+ 'MODULATE_SUBTRACT_ATIX': 0x8746,
+ 'SECONDARY_COLOR_ATIX': 0x8747,
+ 'TEXTURE_OUTPUT_RGB_ATIX': 0x8748,
+ 'TEXTURE_OUTPUT_ALPHA_ATIX': 0x8749,
+ 'OUTPUT_POINT_SIZE_ATIX': 0x610E,
+ 'MAX_DRAW_BUFFERS_ATI': 0x8824,
+ 'DRAW_BUFFER0_ATI': 0x8825,
+ 'DRAW_BUFFER1_ATI': 0x8826,
+ 'DRAW_BUFFER2_ATI': 0x8827,
+ 'DRAW_BUFFER3_ATI': 0x8828,
+ 'DRAW_BUFFER4_ATI': 0x8829,
+ 'DRAW_BUFFER5_ATI': 0x882A,
+ 'DRAW_BUFFER6_ATI': 0x882B,
+ 'DRAW_BUFFER7_ATI': 0x882C,
+ 'DRAW_BUFFER8_ATI': 0x882D,
+ 'DRAW_BUFFER9_ATI': 0x882E,
+ 'DRAW_BUFFER10_ATI': 0x882F,
+ 'DRAW_BUFFER11_ATI': 0x8830,
+ 'DRAW_BUFFER12_ATI': 0x8831,
+ 'DRAW_BUFFER13_ATI': 0x8832,
+ 'DRAW_BUFFER14_ATI': 0x8833,
+ 'DRAW_BUFFER15_ATI': 0x8834,
+ 'ELEMENT_ARRAY_ATI': 0x8768,
+ 'ELEMENT_ARRAY_TYPE_ATI': 0x8769,
+ 'ELEMENT_ARRAY_POINTER_ATI': 0x876A,
+ 'BUMP_ROT_MATRIX_ATI': 0x8775,
+ 'BUMP_ROT_MATRIX_SIZE_ATI': 0x8776,
+ 'BUMP_NUM_TEX_UNITS_ATI': 0x8777,
+ 'BUMP_TEX_UNITS_ATI': 0x8778,
+ 'DUDV_ATI': 0x8779,
+ 'DU8DV8_ATI': 0x877A,
+ 'BUMP_ENVMAP_ATI': 0x877B,
+ 'BUMP_TARGET_ATI': 0x877C,
+ 'RED_BIT_ATI': 0x00000001,
+ '2X_BIT_ATI': 0x00000001,
+ '4X_BIT_ATI': 0x00000002,
+ 'GREEN_BIT_ATI': 0x00000002,
+ 'COMP_BIT_ATI': 0x00000002,
+ 'BLUE_BIT_ATI': 0x00000004,
+ '8X_BIT_ATI': 0x00000004,
+ 'NEGATE_BIT_ATI': 0x00000004,
+ 'BIAS_BIT_ATI': 0x00000008,
+ 'HALF_BIT_ATI': 0x00000008,
+ 'QUARTER_BIT_ATI': 0x00000010,
+ 'EIGHTH_BIT_ATI': 0x00000020,
+ 'SATURATE_BIT_ATI': 0x00000040,
+ 'FRAGMENT_SHADER_ATI': 0x8920,
+ 'REG_0_ATI': 0x8921,
+ 'REG_1_ATI': 0x8922,
+ 'REG_2_ATI': 0x8923,
+ 'REG_3_ATI': 0x8924,
+ 'REG_4_ATI': 0x8925,
+ 'REG_5_ATI': 0x8926,
+ 'CON_0_ATI': 0x8941,
+ 'CON_1_ATI': 0x8942,
+ 'CON_2_ATI': 0x8943,
+ 'CON_3_ATI': 0x8944,
+ 'CON_4_ATI': 0x8945,
+ 'CON_5_ATI': 0x8946,
+ 'CON_6_ATI': 0x8947,
+ 'CON_7_ATI': 0x8948,
+ 'MOV_ATI': 0x8961,
+ 'ADD_ATI': 0x8963,
+ 'MUL_ATI': 0x8964,
+ 'SUB_ATI': 0x8965,
+ 'DOT3_ATI': 0x8966,
+ 'DOT4_ATI': 0x8967,
+ 'MAD_ATI': 0x8968,
+ 'LERP_ATI': 0x8969,
+ 'CND_ATI': 0x896A,
+ 'CND0_ATI': 0x896B,
+ 'DOT2_ADD_ATI': 0x896C,
+ 'SECONDARY_INTERPOLATOR_ATI': 0x896D,
+ 'NUM_FRAGMENT_REGISTERS_ATI': 0x896E,
+ 'NUM_FRAGMENT_CONSTANTS_ATI': 0x896F,
+ 'NUM_PASSES_ATI': 0x8970,
+ 'NUM_INSTRUCTIONS_PER_PASS_ATI': 0x8971,
+ 'NUM_INSTRUCTIONS_TOTAL_ATI': 0x8972,
+ 'NUM_INPUT_INTERPOLATOR_COMPONENTS_ATI': 0x8973,
+ 'NUM_LOOPBACK_COMPONENTS_ATI': 0x8974,
+ 'COLOR_ALPHA_PAIRING_ATI': 0x8975,
+ 'SWIZZLE_STR_ATI': 0x8976,
+ 'SWIZZLE_STQ_ATI': 0x8977,
+ 'SWIZZLE_STR_DR_ATI': 0x8978,
+ 'SWIZZLE_STQ_DQ_ATI': 0x8979,
+ 'SWIZZLE_STRQ_ATI': 0x897A,
+ 'SWIZZLE_STRQ_DQ_ATI': 0x897B,
+ 'PN_TRIANGLES_ATI': 0x87F0,
+ 'MAX_PN_TRIANGLES_TESSELATION_LEVEL_ATI': 0x87F1,
+ 'PN_TRIANGLES_POINT_MODE_ATI': 0x87F2,
+ 'PN_TRIANGLES_NORMAL_MODE_ATI': 0x87F3,
+ 'PN_TRIANGLES_TESSELATION_LEVEL_ATI': 0x87F4,
+ 'PN_TRIANGLES_POINT_MODE_LINEAR_ATI': 0x87F5,
+ 'PN_TRIANGLES_POINT_MODE_CUBIC_ATI': 0x87F6,
+ 'PN_TRIANGLES_NORMAL_MODE_LINEAR_ATI': 0x87F7,
+ 'PN_TRIANGLES_NORMAL_MODE_QUADRATIC_ATI': 0x87F8,
+ 'STENCIL_BACK_FUNC_ATI': 0x8800,
+ 'STENCIL_BACK_FAIL_ATI': 0x8801,
+ 'STENCIL_BACK_PASS_DEPTH_FAIL_ATI': 0x8802,
+ 'STENCIL_BACK_PASS_DEPTH_PASS_ATI': 0x8803,
+ 'TEXT_FRAGMENT_SHADER_ATI': 0x8200,
+ 'COMPRESSED_LUMINANCE_ALPHA_3DC_ATI': 0x8837,
+ 'MODULATE_ADD_ATI': 0x8744,
+ 'MODULATE_SIGNED_ADD_ATI': 0x8745,
+ 'MODULATE_SUBTRACT_ATI': 0x8746,
+ 'RGBA_FLOAT32_ATI': 0x8814,
+ 'RGB_FLOAT32_ATI': 0x8815,
+ 'ALPHA_FLOAT32_ATI': 0x8816,
+ 'INTENSITY_FLOAT32_ATI': 0x8817,
+ 'LUMINANCE_FLOAT32_ATI': 0x8818,
+ 'LUMINANCE_ALPHA_FLOAT32_ATI': 0x8819,
+ 'RGBA_FLOAT16_ATI': 0x881A,
+ 'RGB_FLOAT16_ATI': 0x881B,
+ 'ALPHA_FLOAT16_ATI': 0x881C,
+ 'INTENSITY_FLOAT16_ATI': 0x881D,
+ 'LUMINANCE_FLOAT16_ATI': 0x881E,
+ 'LUMINANCE_ALPHA_FLOAT16_ATI': 0x881F,
+ 'MIRROR_CLAMP_ATI': 0x8742,
+ 'MIRROR_CLAMP_TO_EDGE_ATI': 0x8743,
+ 'STATIC_ATI': 0x8760,
+ 'DYNAMIC_ATI': 0x8761,
+ 'PRESERVE_ATI': 0x8762,
+ 'DISCARD_ATI': 0x8763,
+ 'OBJECT_BUFFER_SIZE_ATI': 0x8764,
+ 'OBJECT_BUFFER_USAGE_ATI': 0x8765,
+ 'ARRAY_OBJECT_BUFFER_ATI': 0x8766,
+ 'ARRAY_OBJECT_OFFSET_ATI': 0x8767,
+ 'MAX_VERTEX_STREAMS_ATI': 0x876B,
+ 'VERTEX_SOURCE_ATI': 0x876C,
+ 'VERTEX_STREAM0_ATI': 0x876D,
+ 'VERTEX_STREAM1_ATI': 0x876E,
+ 'VERTEX_STREAM2_ATI': 0x876F,
+ 'VERTEX_STREAM3_ATI': 0x8770,
+ 'VERTEX_STREAM4_ATI': 0x8771,
+ 'VERTEX_STREAM5_ATI': 0x8772,
+ 'VERTEX_STREAM6_ATI': 0x8773,
+ 'VERTEX_STREAM7_ATI': 0x8774,
+ '422_EXT': 0x80CC,
+ '422_REV_EXT': 0x80CD,
+ '422_AVERAGE_EXT': 0x80CE,
+ '422_REV_AVERAGE_EXT': 0x80CF,
+ 'CG_VERTEX_SHADER_EXT': 0x890E,
+ 'CG_FRAGMENT_SHADER_EXT': 0x890F,
+ 'ABGR_EXT': 0x8000,
+ 'BGR_EXT': 0x80E0,
+ 'BGRA_EXT': 0x80E1,
+ 'MAX_VERTEX_BINDABLE_UNIFORMS_EXT': 0x8DE2,
+ 'MAX_FRAGMENT_BINDABLE_UNIFORMS_EXT': 0x8DE3,
+ 'MAX_GEOMETRY_BINDABLE_UNIFORMS_EXT': 0x8DE4,
+ 'MAX_BINDABLE_UNIFORM_SIZE_EXT': 0x8DED,
+ 'UNIFORM_BUFFER_EXT': 0x8DEE,
+ 'UNIFORM_BUFFER_BINDING_EXT': 0x8DEF,
+ 'CONSTANT_COLOR_EXT': 0x8001,
+ 'ONE_MINUS_CONSTANT_COLOR_EXT': 0x8002,
+ 'CONSTANT_ALPHA_EXT': 0x8003,
+ 'ONE_MINUS_CONSTANT_ALPHA_EXT': 0x8004,
+ 'BLEND_COLOR_EXT': 0x8005,
+ 'BLEND_EQUATION_RGB_EXT': 0x8009,
+ 'BLEND_EQUATION_ALPHA_EXT': 0x883D,
+ 'BLEND_DST_RGB_EXT': 0x80C8,
+ 'BLEND_SRC_RGB_EXT': 0x80C9,
+ 'BLEND_DST_ALPHA_EXT': 0x80CA,
+ 'BLEND_SRC_ALPHA_EXT': 0x80CB,
+ 'FUNC_ADD_EXT': 0x8006,
+ 'MIN_EXT': 0x8007,
+ 'MAX_EXT': 0x8008,
+ 'BLEND_EQUATION_EXT': 0x8009,
+ 'FUNC_SUBTRACT_EXT': 0x800A,
+ 'FUNC_REVERSE_SUBTRACT_EXT': 0x800B,
+ 'CLIP_VOLUME_CLIPPING_HINT_EXT': 0x80F0,
+ 'CMYK_EXT': 0x800C,
+ 'CMYKA_EXT': 0x800D,
+ 'PACK_CMYK_HINT_EXT': 0x800E,
+ 'UNPACK_CMYK_HINT_EXT': 0x800F,
+ 'ARRAY_ELEMENT_LOCK_FIRST_EXT': 0x81A8,
+ 'ARRAY_ELEMENT_LOCK_COUNT_EXT': 0x81A9,
+ 'CONVOLUTION_1D_EXT': 0x8010,
+ 'CONVOLUTION_2D_EXT': 0x8011,
+ 'SEPARABLE_2D_EXT': 0x8012,
+ 'CONVOLUTION_BORDER_MODE_EXT': 0x8013,
+ 'CONVOLUTION_FILTER_SCALE_EXT': 0x8014,
+ 'CONVOLUTION_FILTER_BIAS_EXT': 0x8015,
+ 'REDUCE_EXT': 0x8016,
+ 'CONVOLUTION_FORMAT_EXT': 0x8017,
+ 'CONVOLUTION_WIDTH_EXT': 0x8018,
+ 'CONVOLUTION_HEIGHT_EXT': 0x8019,
+ 'MAX_CONVOLUTION_WIDTH_EXT': 0x801A,
+ 'MAX_CONVOLUTION_HEIGHT_EXT': 0x801B,
+ 'POST_CONVOLUTION_RED_SCALE_EXT': 0x801C,
+ 'POST_CONVOLUTION_GREEN_SCALE_EXT': 0x801D,
+ 'POST_CONVOLUTION_BLUE_SCALE_EXT': 0x801E,
+ 'POST_CONVOLUTION_ALPHA_SCALE_EXT': 0x801F,
+ 'POST_CONVOLUTION_RED_BIAS_EXT': 0x8020,
+ 'POST_CONVOLUTION_GREEN_BIAS_EXT': 0x8021,
+ 'POST_CONVOLUTION_BLUE_BIAS_EXT': 0x8022,
+ 'POST_CONVOLUTION_ALPHA_BIAS_EXT': 0x8023,
+ 'TANGENT_ARRAY_EXT': 0x8439,
+ 'BINORMAL_ARRAY_EXT': 0x843A,
+ 'CURRENT_TANGENT_EXT': 0x843B,
+ 'CURRENT_BINORMAL_EXT': 0x843C,
+ 'TANGENT_ARRAY_TYPE_EXT': 0x843E,
+ 'TANGENT_ARRAY_STRIDE_EXT': 0x843F,
+ 'BINORMAL_ARRAY_TYPE_EXT': 0x8440,
+ 'BINORMAL_ARRAY_STRIDE_EXT': 0x8441,
+ 'TANGENT_ARRAY_POINTER_EXT': 0x8442,
+ 'BINORMAL_ARRAY_POINTER_EXT': 0x8443,
+ 'MAP1_TANGENT_EXT': 0x8444,
+ 'MAP2_TANGENT_EXT': 0x8445,
+ 'MAP1_BINORMAL_EXT': 0x8446,
+ 'MAP2_BINORMAL_EXT': 0x8447,
+ 'DEPTH_BOUNDS_TEST_EXT': 0x8890,
+ 'DEPTH_BOUNDS_EXT': 0x8891,
+ 'PROGRAM_MATRIX_EXT': 0x8E2D,
+ 'TRANSPOSE_PROGRAM_MATRIX_EXT': 0x8E2E,
+ 'PROGRAM_MATRIX_STACK_DEPTH_EXT': 0x8E2F,
+ 'MAX_ELEMENTS_VERTICES': 0x80E8,
+ 'MAX_ELEMENTS_INDICES': 0x80E9,
+ 'FOG_COORDINATE_SOURCE_EXT': 0x8450,
+ 'FOG_COORDINATE_EXT': 0x8451,
+ 'FRAGMENT_DEPTH_EXT': 0x8452,
+ 'CURRENT_FOG_COORDINATE_EXT': 0x8453,
+ 'FOG_COORDINATE_ARRAY_TYPE_EXT': 0x8454,
+ 'FOG_COORDINATE_ARRAY_STRIDE_EXT': 0x8455,
+ 'FOG_COORDINATE_ARRAY_POINTER_EXT': 0x8456,
+ 'FOG_COORDINATE_ARRAY_EXT': 0x8457,
+ 'FRAGMENT_LIGHTING_EXT': 0x8400,
+ 'FRAGMENT_COLOR_MATERIAL_EXT': 0x8401,
+ 'FRAGMENT_COLOR_MATERIAL_FACE_EXT': 0x8402,
+ 'FRAGMENT_COLOR_MATERIAL_PARAMETER_EXT': 0x8403,
+ 'MAX_FRAGMENT_LIGHTS_EXT': 0x8404,
+ 'MAX_ACTIVE_LIGHTS_EXT': 0x8405,
+ 'CURRENT_RASTER_NORMAL_EXT': 0x8406,
+ 'LIGHT_ENV_MODE_EXT': 0x8407,
+ 'FRAGMENT_LIGHT_MODEL_LOCAL_VIEWER_EXT': 0x8408,
+ 'FRAGMENT_LIGHT_MODEL_TWO_SIDE_EXT': 0x8409,
+ 'FRAGMENT_LIGHT_MODEL_AMBIENT_EXT': 0x840A,
+ 'FRAGMENT_LIGHT_MODEL_NORMAL_INTERPOLATION_EXT': 0x840B,
+ 'FRAGMENT_LIGHT0_EXT': 0x840C,
+ 'FRAGMENT_LIGHT7_EXT': 0x8413,
+ 'DRAW_FRAMEBUFFER_BINDING_EXT': 0x8CA6,
+ 'READ_FRAMEBUFFER_EXT': 0x8CA8,
+ 'DRAW_FRAMEBUFFER_EXT': 0x8CA9,
+ 'READ_FRAMEBUFFER_BINDING_EXT': 0x8CAA,
+ 'RENDERBUFFER_SAMPLES_EXT': 0x8CAB,
+ 'FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT': 0x8D56,
+ 'MAX_SAMPLES_EXT': 0x8D57,
+ 'INVALID_FRAMEBUFFER_OPERATION_EXT': 0x0506,
+ 'MAX_RENDERBUFFER_SIZE_EXT': 0x84E8,
+ 'FRAMEBUFFER_BINDING_EXT': 0x8CA6,
+ 'RENDERBUFFER_BINDING_EXT': 0x8CA7,
+ 'FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_EXT': 0x8CD0,
+ 'FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_EXT': 0x8CD1,
+ 'FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL_EXT': 0x8CD2,
+ 'FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE_EXT': 0x8CD3,
+ 'FRAMEBUFFER_ATTACHMENT_TEXTURE_3D_ZOFFSET_EXT': 0x8CD4,
+ 'FRAMEBUFFER_COMPLETE_EXT': 0x8CD5,
+ 'FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT': 0x8CD6,
+ 'FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT': 0x8CD7,
+ 'FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT': 0x8CD9,
+ 'FRAMEBUFFER_INCOMPLETE_FORMATS_EXT': 0x8CDA,
+ 'FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT': 0x8CDB,
+ 'FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT': 0x8CDC,
+ 'FRAMEBUFFER_UNSUPPORTED_EXT': 0x8CDD,
+ 'MAX_COLOR_ATTACHMENTS_EXT': 0x8CDF,
+ 'COLOR_ATTACHMENT0_EXT': 0x8CE0,
+ 'COLOR_ATTACHMENT1_EXT': 0x8CE1,
+ 'COLOR_ATTACHMENT2_EXT': 0x8CE2,
+ 'COLOR_ATTACHMENT3_EXT': 0x8CE3,
+ 'COLOR_ATTACHMENT4_EXT': 0x8CE4,
+ 'COLOR_ATTACHMENT5_EXT': 0x8CE5,
+ 'COLOR_ATTACHMENT6_EXT': 0x8CE6,
+ 'COLOR_ATTACHMENT7_EXT': 0x8CE7,
+ 'COLOR_ATTACHMENT8_EXT': 0x8CE8,
+ 'COLOR_ATTACHMENT9_EXT': 0x8CE9,
+ 'COLOR_ATTACHMENT10_EXT': 0x8CEA,
+ 'COLOR_ATTACHMENT11_EXT': 0x8CEB,
+ 'COLOR_ATTACHMENT12_EXT': 0x8CEC,
+ 'COLOR_ATTACHMENT13_EXT': 0x8CED,
+ 'COLOR_ATTACHMENT14_EXT': 0x8CEE,
+ 'COLOR_ATTACHMENT15_EXT': 0x8CEF,
+ 'DEPTH_ATTACHMENT_EXT': 0x8D00,
+ 'STENCIL_ATTACHMENT_EXT': 0x8D20,
+ 'FRAMEBUFFER_EXT': 0x8D40,
+ 'RENDERBUFFER_EXT': 0x8D41,
+ 'RENDERBUFFER_WIDTH_EXT': 0x8D42,
+ 'RENDERBUFFER_HEIGHT_EXT': 0x8D43,
+ 'RENDERBUFFER_INTERNAL_FORMAT_EXT': 0x8D44,
+ 'STENCIL_INDEX1_EXT': 0x8D46,
+ 'STENCIL_INDEX4_EXT': 0x8D47,
+ 'STENCIL_INDEX8_EXT': 0x8D48,
+ 'STENCIL_INDEX16_EXT': 0x8D49,
+ 'RENDERBUFFER_RED_SIZE_EXT': 0x8D50,
+ 'RENDERBUFFER_GREEN_SIZE_EXT': 0x8D51,
+ 'RENDERBUFFER_BLUE_SIZE_EXT': 0x8D52,
+ 'RENDERBUFFER_ALPHA_SIZE_EXT': 0x8D53,
+ 'RENDERBUFFER_DEPTH_SIZE_EXT': 0x8D54,
+ 'RENDERBUFFER_STENCIL_SIZE_EXT': 0x8D55,
+ 'FRAMEBUFFER_SRGB_EXT': 0x8DB9,
+ 'FRAMEBUFFER_SRGB_CAPABLE_EXT': 0x8DBA,
+ 'LINES_ADJACENCY_EXT': 0xA,
+ 'LINE_STRIP_ADJACENCY_EXT': 0xB,
+ 'TRIANGLES_ADJACENCY_EXT': 0xC,
+ 'TRIANGLE_STRIP_ADJACENCY_EXT': 0xD,
+ 'PROGRAM_POINT_SIZE_EXT': 0x8642,
+ 'MAX_VARYING_COMPONENTS_EXT': 0x8B4B,
+ 'MAX_GEOMETRY_TEXTURE_IMAGE_UNITS_EXT': 0x8C29,
+ 'FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER_EXT': 0x8CD4,
+ 'FRAMEBUFFER_ATTACHMENT_LAYERED_EXT': 0x8DA7,
+ 'FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS_EXT': 0x8DA8,
+ 'FRAMEBUFFER_INCOMPLETE_LAYER_COUNT_EXT': 0x8DA9,
+ 'GEOMETRY_SHADER_EXT': 0x8DD9,
+ 'GEOMETRY_VERTICES_OUT_EXT': 0x8DDA,
+ 'GEOMETRY_INPUT_TYPE_EXT': 0x8DDB,
+ 'GEOMETRY_OUTPUT_TYPE_EXT': 0x8DDC,
+ 'MAX_GEOMETRY_VARYING_COMPONENTS_EXT': 0x8DDD,
+ 'MAX_VERTEX_VARYING_COMPONENTS_EXT': 0x8DDE,
+ 'MAX_GEOMETRY_UNIFORM_COMPONENTS_EXT': 0x8DDF,
+ 'MAX_GEOMETRY_OUTPUT_VERTICES_EXT': 0x8DE0,
+ 'MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS_EXT': 0x8DE1,
+ 'VERTEX_ATTRIB_ARRAY_INTEGER_EXT': 0x88FD,
+ 'SAMPLER_1D_ARRAY_EXT': 0x8DC0,
+ 'SAMPLER_2D_ARRAY_EXT': 0x8DC1,
+ 'SAMPLER_BUFFER_EXT': 0x8DC2,
+ 'SAMPLER_1D_ARRAY_SHADOW_EXT': 0x8DC3,
+ 'SAMPLER_2D_ARRAY_SHADOW_EXT': 0x8DC4,
+ 'SAMPLER_CUBE_SHADOW_EXT': 0x8DC5,
+ 'UNSIGNED_INT_VEC2_EXT': 0x8DC6,
+ 'UNSIGNED_INT_VEC3_EXT': 0x8DC7,
+ 'UNSIGNED_INT_VEC4_EXT': 0x8DC8,
+ 'INT_SAMPLER_1D_EXT': 0x8DC9,
+ 'INT_SAMPLER_2D_EXT': 0x8DCA,
+ 'INT_SAMPLER_3D_EXT': 0x8DCB,
+ 'INT_SAMPLER_CUBE_EXT': 0x8DCC,
+ 'INT_SAMPLER_2D_RECT_EXT': 0x8DCD,
+ 'INT_SAMPLER_1D_ARRAY_EXT': 0x8DCE,
+ 'INT_SAMPLER_2D_ARRAY_EXT': 0x8DCF,
+ 'INT_SAMPLER_BUFFER_EXT': 0x8DD0,
+ 'UNSIGNED_INT_SAMPLER_1D_EXT': 0x8DD1,
+ 'UNSIGNED_INT_SAMPLER_2D_EXT': 0x8DD2,
+ 'UNSIGNED_INT_SAMPLER_3D_EXT': 0x8DD3,
+ 'UNSIGNED_INT_SAMPLER_CUBE_EXT': 0x8DD4,
+ 'UNSIGNED_INT_SAMPLER_2D_RECT_EXT': 0x8DD5,
+ 'UNSIGNED_INT_SAMPLER_1D_ARRAY_EXT': 0x8DD6,
+ 'UNSIGNED_INT_SAMPLER_2D_ARRAY_EXT': 0x8DD7,
+ 'UNSIGNED_INT_SAMPLER_BUFFER_EXT': 0x8DD8,
+ 'HISTOGRAM_EXT': 0x8024,
+ 'PROXY_HISTOGRAM_EXT': 0x8025,
+ 'HISTOGRAM_WIDTH_EXT': 0x8026,
+ 'HISTOGRAM_FORMAT_EXT': 0x8027,
+ 'HISTOGRAM_RED_SIZE_EXT': 0x8028,
+ 'HISTOGRAM_GREEN_SIZE_EXT': 0x8029,
+ 'HISTOGRAM_BLUE_SIZE_EXT': 0x802A,
+ 'HISTOGRAM_ALPHA_SIZE_EXT': 0x802B,
+ 'HISTOGRAM_LUMINANCE_SIZE_EXT': 0x802C,
+ 'HISTOGRAM_SINK_EXT': 0x802D,
+ 'MINMAX_EXT': 0x802E,
+ 'MINMAX_FORMAT_EXT': 0x802F,
+ 'MINMAX_SINK_EXT': 0x8030,
+ 'FRAGMENT_MATERIAL_EXT': 0x8349,
+ 'FRAGMENT_NORMAL_EXT': 0x834A,
+ 'FRAGMENT_COLOR_EXT': 0x834C,
+ 'ATTENUATION_EXT': 0x834D,
+ 'SHADOW_ATTENUATION_EXT': 0x834E,
+ 'TEXTURE_APPLICATION_MODE_EXT': 0x834F,
+ 'TEXTURE_LIGHT_EXT': 0x8350,
+ 'TEXTURE_MATERIAL_FACE_EXT': 0x8351,
+ 'TEXTURE_MATERIAL_PARAMETER_EXT': 0x8352,
+ 'FRAGMENT_DEPTH_EXT': 0x8452,
+ 'MULTISAMPLE_EXT': 0x809D,
+ 'SAMPLE_ALPHA_TO_MASK_EXT': 0x809E,
+ 'SAMPLE_ALPHA_TO_ONE_EXT': 0x809F,
+ 'SAMPLE_MASK_EXT': 0x80A0,
+ '1PASS_EXT': 0x80A1,
+ '2PASS_0_EXT': 0x80A2,
+ '2PASS_1_EXT': 0x80A3,
+ '4PASS_0_EXT': 0x80A4,
+ '4PASS_1_EXT': 0x80A5,
+ '4PASS_2_EXT': 0x80A6,
+ '4PASS_3_EXT': 0x80A7,
+ 'SAMPLE_BUFFERS_EXT': 0x80A8,
+ 'SAMPLES_EXT': 0x80A9,
+ 'SAMPLE_MASK_VALUE_EXT': 0x80AA,
+ 'SAMPLE_MASK_INVERT_EXT': 0x80AB,
+ 'SAMPLE_PATTERN_EXT': 0x80AC,
+ 'MULTISAMPLE_BIT_EXT': 0x20000000,
+ 'DEPTH_STENCIL_EXT': 0x84F9,
+ 'UNSIGNED_INT_24_8_EXT': 0x84FA,
+ 'DEPTH24_STENCIL8_EXT': 0x88F0,
+ 'TEXTURE_STENCIL_SIZE_EXT': 0x88F1,
+ 'R11F_G11F_B10F_EXT': 0x8C3A,
+ 'UNSIGNED_INT_10F_11F_11F_REV_EXT': 0x8C3B,
+ 'RGBA_SIGNED_COMPONENTS_EXT': 0x8C3C,
+ 'UNSIGNED_BYTE_3_3_2_EXT': 0x8032,
+ 'UNSIGNED_SHORT_4_4_4_4_EXT': 0x8033,
+ 'UNSIGNED_SHORT_5_5_5_1_EXT': 0x8034,
+ 'UNSIGNED_INT_8_8_8_8_EXT': 0x8035,
+ 'UNSIGNED_INT_10_10_10_2_EXT': 0x8036,
+ 'TEXTURE_1D': 0x0DE0,
+ 'TEXTURE_2D': 0x0DE1,
+ 'PROXY_TEXTURE_1D': 0x8063,
+ 'PROXY_TEXTURE_2D': 0x8064,
+ 'TEXTURE_3D_EXT': 0x806F,
+ 'PROXY_TEXTURE_3D_EXT': 0x8070,
+ 'COLOR_TABLE_FORMAT_EXT': 0x80D8,
+ 'COLOR_TABLE_WIDTH_EXT': 0x80D9,
+ 'COLOR_TABLE_RED_SIZE_EXT': 0x80DA,
+ 'COLOR_TABLE_GREEN_SIZE_EXT': 0x80DB,
+ 'COLOR_TABLE_BLUE_SIZE_EXT': 0x80DC,
+ 'COLOR_TABLE_ALPHA_SIZE_EXT': 0x80DD,
+ 'COLOR_TABLE_LUMINANCE_SIZE_EXT': 0x80DE,
+ 'COLOR_TABLE_INTENSITY_SIZE_EXT': 0x80DF,
+ 'COLOR_INDEX1_EXT': 0x80E2,
+ 'COLOR_INDEX2_EXT': 0x80E3,
+ 'COLOR_INDEX4_EXT': 0x80E4,
+ 'COLOR_INDEX8_EXT': 0x80E5,
+ 'COLOR_INDEX12_EXT': 0x80E6,
+ 'COLOR_INDEX16_EXT': 0x80E7,
+ 'TEXTURE_INDEX_SIZE_EXT': 0x80ED,
+ 'TEXTURE_CUBE_MAP_ARB': 0x8513,
+ 'PROXY_TEXTURE_CUBE_MAP_ARB': 0x851B,
+ 'PIXEL_PACK_BUFFER_EXT': 0x88EB,
+ 'PIXEL_UNPACK_BUFFER_EXT': 0x88EC,
+ 'PIXEL_PACK_BUFFER_BINDING_EXT': 0x88ED,
+ 'PIXEL_UNPACK_BUFFER_BINDING_EXT': 0x88EF,
+ 'PIXEL_TRANSFORM_2D_EXT': 0x8330,
+ 'PIXEL_MAG_FILTER_EXT': 0x8331,
+ 'PIXEL_MIN_FILTER_EXT': 0x8332,
+ 'PIXEL_CUBIC_WEIGHT_EXT': 0x8333,
+ 'CUBIC_EXT': 0x8334,
+ 'AVERAGE_EXT': 0x8335,
+ 'PIXEL_TRANSFORM_2D_STACK_DEPTH_EXT': 0x8336,
+ 'MAX_PIXEL_TRANSFORM_2D_STACK_DEPTH_EXT': 0x8337,
+ 'PIXEL_TRANSFORM_2D_MATRIX_EXT': 0x8338,
+ 'POINT_SIZE_MIN_EXT': 0x8126,
+ 'POINT_SIZE_MAX_EXT': 0x8127,
+ 'POINT_FADE_THRESHOLD_SIZE_EXT': 0x8128,
+ 'DISTANCE_ATTENUATION_EXT': 0x8129,
+ 'POLYGON_OFFSET_EXT': 0x8037,
+ 'POLYGON_OFFSET_FACTOR_EXT': 0x8038,
+ 'POLYGON_OFFSET_BIAS_EXT': 0x8039,
+ 'RESCALE_NORMAL_EXT': 0x803A,
+ 'COLOR_SUM_EXT': 0x8458,
+ 'CURRENT_SECONDARY_COLOR_EXT': 0x8459,
+ 'SECONDARY_COLOR_ARRAY_SIZE_EXT': 0x845A,
+ 'SECONDARY_COLOR_ARRAY_TYPE_EXT': 0x845B,
+ 'SECONDARY_COLOR_ARRAY_STRIDE_EXT': 0x845C,
+ 'SECONDARY_COLOR_ARRAY_POINTER_EXT': 0x845D,
+ 'SECONDARY_COLOR_ARRAY_EXT': 0x845E,
+ 'LIGHT_MODEL_COLOR_CONTROL_EXT': 0x81F8,
+ 'SINGLE_COLOR_EXT': 0x81F9,
+ 'SEPARATE_SPECULAR_COLOR_EXT': 0x81FA,
+ 'SHARED_TEXTURE_PALETTE_EXT': 0x81FB,
+ 'STENCIL_TAG_BITS_EXT': 0x88F2,
+ 'STENCIL_CLEAR_TAG_VALUE_EXT': 0x88F3,
+ 'STENCIL_TEST_TWO_SIDE_EXT': 0x8910,
+ 'ACTIVE_STENCIL_FACE_EXT': 0x8911,
+ 'INCR_WRAP_EXT': 0x8507,
+ 'DECR_WRAP_EXT': 0x8508,
+ 'ALPHA4_EXT': 0x803B,
+ 'ALPHA8_EXT': 0x803C,
+ 'ALPHA12_EXT': 0x803D,
+ 'ALPHA16_EXT': 0x803E,
+ 'LUMINANCE4_EXT': 0x803F,
+ 'LUMINANCE8_EXT': 0x8040,
+ 'LUMINANCE12_EXT': 0x8041,
+ 'LUMINANCE16_EXT': 0x8042,
+ 'LUMINANCE4_ALPHA4_EXT': 0x8043,
+ 'LUMINANCE6_ALPHA2_EXT': 0x8044,
+ 'LUMINANCE8_ALPHA8_EXT': 0x8045,
+ 'LUMINANCE12_ALPHA4_EXT': 0x8046,
+ 'LUMINANCE12_ALPHA12_EXT': 0x8047,
+ 'LUMINANCE16_ALPHA16_EXT': 0x8048,
+ 'INTENSITY_EXT': 0x8049,
+ 'INTENSITY4_EXT': 0x804A,
+ 'INTENSITY8_EXT': 0x804B,
+ 'INTENSITY12_EXT': 0x804C,
+ 'INTENSITY16_EXT': 0x804D,
+ 'RGB2_EXT': 0x804E,
+ 'RGB4_EXT': 0x804F,
+ 'RGB5_EXT': 0x8050,
+ 'RGB8_EXT': 0x8051,
+ 'RGB10_EXT': 0x8052,
+ 'RGB12_EXT': 0x8053,
+ 'RGB16_EXT': 0x8054,
+ 'RGBA2_EXT': 0x8055,
+ 'RGBA4_EXT': 0x8056,
+ 'RGB5_A1_EXT': 0x8057,
+ 'RGBA8_EXT': 0x8058,
+ 'RGB10_A2_EXT': 0x8059,
+ 'RGBA12_EXT': 0x805A,
+ 'RGBA16_EXT': 0x805B,
+ 'TEXTURE_RED_SIZE_EXT': 0x805C,
+ 'TEXTURE_GREEN_SIZE_EXT': 0x805D,
+ 'TEXTURE_BLUE_SIZE_EXT': 0x805E,
+ 'TEXTURE_ALPHA_SIZE_EXT': 0x805F,
+ 'TEXTURE_LUMINANCE_SIZE_EXT': 0x8060,
+ 'TEXTURE_INTENSITY_SIZE_EXT': 0x8061,
+ 'REPLACE_EXT': 0x8062,
+ 'PROXY_TEXTURE_1D_EXT': 0x8063,
+ 'PROXY_TEXTURE_2D_EXT': 0x8064,
+ 'PACK_SKIP_IMAGES_EXT': 0x806B,
+ 'PACK_IMAGE_HEIGHT_EXT': 0x806C,
+ 'UNPACK_SKIP_IMAGES_EXT': 0x806D,
+ 'UNPACK_IMAGE_HEIGHT_EXT': 0x806E,
+ 'TEXTURE_3D_EXT': 0x806F,
+ 'PROXY_TEXTURE_3D_EXT': 0x8070,
+ 'TEXTURE_DEPTH_EXT': 0x8071,
+ 'TEXTURE_WRAP_R_EXT': 0x8072,
+ 'MAX_3D_TEXTURE_SIZE_EXT': 0x8073,
+ 'COMPARE_REF_DEPTH_TO_TEXTURE_EXT': 0x884E,
+ 'MAX_ARRAY_TEXTURE_LAYERS_EXT': 0x88FF,
+ 'TEXTURE_1D_ARRAY_EXT': 0x8C18,
+ 'PROXY_TEXTURE_1D_ARRAY_EXT': 0x8C19,
+ 'TEXTURE_2D_ARRAY_EXT': 0x8C1A,
+ 'PROXY_TEXTURE_2D_ARRAY_EXT': 0x8C1B,
+ 'TEXTURE_BINDING_1D_ARRAY_EXT': 0x8C1C,
+ 'TEXTURE_BINDING_2D_ARRAY_EXT': 0x8C1D,
+ 'TEXTURE_BUFFER_EXT': 0x8C2A,
+ 'MAX_TEXTURE_BUFFER_SIZE_EXT': 0x8C2B,
+ 'TEXTURE_BINDING_BUFFER_EXT': 0x8C2C,
+ 'TEXTURE_BUFFER_DATA_STORE_BINDING_EXT': 0x8C2D,
+ 'TEXTURE_BUFFER_FORMAT_EXT': 0x8C2E,
+ 'COMPRESSED_RGB_S3TC_DXT1_EXT': 0x83F0,
+ 'COMPRESSED_RGBA_S3TC_DXT1_EXT': 0x83F1,
+ 'COMPRESSED_LUMINANCE_LATC1_EXT': 0x8C70,
+ 'COMPRESSED_SIGNED_LUMINANCE_LATC1_EXT': 0x8C71,
+ 'COMPRESSED_LUMINANCE_ALPHA_LATC2_EXT': 0x8C72,
+ 'COMPRESSED_SIGNED_LUMINANCE_ALPHA_LATC2_EXT': 0x8C73,
+ 'COMPRESSED_RED_RGTC1_EXT': 0x8DBB,
+ 'COMPRESSED_SIGNED_RED_RGTC1_EXT': 0x8DBC,
+ 'COMPRESSED_RED_GREEN_RGTC2_EXT': 0x8DBD,
+ 'COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT': 0x8DBE,
+ 'COMPRESSED_RGB_S3TC_DXT1_EXT': 0x83F0,
+ 'COMPRESSED_RGBA_S3TC_DXT1_EXT': 0x83F1,
+ 'COMPRESSED_RGBA_S3TC_DXT3_EXT': 0x83F2,
+ 'COMPRESSED_RGBA_S3TC_DXT5_EXT': 0x83F3,
+ 'NORMAL_MAP_EXT': 0x8511,
+ 'REFLECTION_MAP_EXT': 0x8512,
+ 'TEXTURE_CUBE_MAP_EXT': 0x8513,
+ 'TEXTURE_BINDING_CUBE_MAP_EXT': 0x8514,
+ 'TEXTURE_CUBE_MAP_POSITIVE_X_EXT': 0x8515,
+ 'TEXTURE_CUBE_MAP_NEGATIVE_X_EXT': 0x8516,
+ 'TEXTURE_CUBE_MAP_POSITIVE_Y_EXT': 0x8517,
+ 'TEXTURE_CUBE_MAP_NEGATIVE_Y_EXT': 0x8518,
+ 'TEXTURE_CUBE_MAP_POSITIVE_Z_EXT': 0x8519,
+ 'TEXTURE_CUBE_MAP_NEGATIVE_Z_EXT': 0x851A,
+ 'PROXY_TEXTURE_CUBE_MAP_EXT': 0x851B,
+ 'MAX_CUBE_MAP_TEXTURE_SIZE_EXT': 0x851C,
+ 'CLAMP_TO_EDGE_EXT': 0x812F,
+ 'COMBINE_EXT': 0x8570,
+ 'COMBINE_RGB_EXT': 0x8571,
+ 'COMBINE_ALPHA_EXT': 0x8572,
+ 'RGB_SCALE_EXT': 0x8573,
+ 'ADD_SIGNED_EXT': 0x8574,
+ 'INTERPOLATE_EXT': 0x8575,
+ 'CONSTANT_EXT': 0x8576,
+ 'PRIMARY_COLOR_EXT': 0x8577,
+ 'PREVIOUS_EXT': 0x8578,
+ 'SOURCE0_RGB_EXT': 0x8580,
+ 'SOURCE1_RGB_EXT': 0x8581,
+ 'SOURCE2_RGB_EXT': 0x8582,
+ 'SOURCE0_ALPHA_EXT': 0x8588,
+ 'SOURCE1_ALPHA_EXT': 0x8589,
+ 'SOURCE2_ALPHA_EXT': 0x858A,
+ 'OPERAND0_RGB_EXT': 0x8590,
+ 'OPERAND1_RGB_EXT': 0x8591,
+ 'OPERAND2_RGB_EXT': 0x8592,
+ 'OPERAND0_ALPHA_EXT': 0x8598,
+ 'OPERAND1_ALPHA_EXT': 0x8599,
+ 'OPERAND2_ALPHA_EXT': 0x859A,
+ 'DOT3_RGB_EXT': 0x8740,
+ 'DOT3_RGBA_EXT': 0x8741,
+ 'TEXTURE_MAX_ANISOTROPY_EXT': 0x84FE,
+ 'MAX_TEXTURE_MAX_ANISOTROPY_EXT': 0x84FF,
+ 'RGBA32UI_EXT': 0x8D70,
+ 'RGB32UI_EXT': 0x8D71,
+ 'ALPHA32UI_EXT': 0x8D72,
+ 'INTENSITY32UI_EXT': 0x8D73,
+ 'LUMINANCE32UI_EXT': 0x8D74,
+ 'LUMINANCE_ALPHA32UI_EXT': 0x8D75,
+ 'RGBA16UI_EXT': 0x8D76,
+ 'RGB16UI_EXT': 0x8D77,
+ 'ALPHA16UI_EXT': 0x8D78,
+ 'INTENSITY16UI_EXT': 0x8D79,
+ 'LUMINANCE16UI_EXT': 0x8D7A,
+ 'LUMINANCE_ALPHA16UI_EXT': 0x8D7B,
+ 'RGBA8UI_EXT': 0x8D7C,
+ 'RGB8UI_EXT': 0x8D7D,
+ 'ALPHA8UI_EXT': 0x8D7E,
+ 'INTENSITY8UI_EXT': 0x8D7F,
+ 'LUMINANCE8UI_EXT': 0x8D80,
+ 'LUMINANCE_ALPHA8UI_EXT': 0x8D81,
+ 'RGBA32I_EXT': 0x8D82,
+ 'RGB32I_EXT': 0x8D83,
+ 'ALPHA32I_EXT': 0x8D84,
+ 'INTENSITY32I_EXT': 0x8D85,
+ 'LUMINANCE32I_EXT': 0x8D86,
+ 'LUMINANCE_ALPHA32I_EXT': 0x8D87,
+ 'RGBA16I_EXT': 0x8D88,
+ 'RGB16I_EXT': 0x8D89,
+ 'ALPHA16I_EXT': 0x8D8A,
+ 'INTENSITY16I_EXT': 0x8D8B,
+ 'LUMINANCE16I_EXT': 0x8D8C,
+ 'LUMINANCE_ALPHA16I_EXT': 0x8D8D,
+ 'RGBA8I_EXT': 0x8D8E,
+ 'RGB8I_EXT': 0x8D8F,
+ 'ALPHA8I_EXT': 0x8D90,
+ 'INTENSITY8I_EXT': 0x8D91,
+ 'LUMINANCE8I_EXT': 0x8D92,
+ 'LUMINANCE_ALPHA8I_EXT': 0x8D93,
+ 'RED_INTEGER_EXT': 0x8D94,
+ 'GREEN_INTEGER_EXT': 0x8D95,
+ 'BLUE_INTEGER_EXT': 0x8D96,
+ 'ALPHA_INTEGER_EXT': 0x8D97,
+ 'RGB_INTEGER_EXT': 0x8D98,
+ 'RGBA_INTEGER_EXT': 0x8D99,
+ 'BGR_INTEGER_EXT': 0x8D9A,
+ 'BGRA_INTEGER_EXT': 0x8D9B,
+ 'LUMINANCE_INTEGER_EXT': 0x8D9C,
+ 'LUMINANCE_ALPHA_INTEGER_EXT': 0x8D9D,
+ 'RGBA_INTEGER_MODE_EXT': 0x8D9E,
+ 'MAX_TEXTURE_LOD_BIAS_EXT': 0x84FD,
+ 'TEXTURE_FILTER_CONTROL_EXT': 0x8500,
+ 'TEXTURE_LOD_BIAS_EXT': 0x8501,
+ 'MIRROR_CLAMP_EXT': 0x8742,
+ 'MIRROR_CLAMP_TO_EDGE_EXT': 0x8743,
+ 'MIRROR_CLAMP_TO_BORDER_EXT': 0x8912,
+ 'TEXTURE_PRIORITY_EXT': 0x8066,
+ 'TEXTURE_RESIDENT_EXT': 0x8067,
+ 'TEXTURE_1D_BINDING_EXT': 0x8068,
+ 'TEXTURE_2D_BINDING_EXT': 0x8069,
+ 'TEXTURE_3D_BINDING_EXT': 0x806A,
+ 'PERTURB_EXT': 0x85AE,
+ 'TEXTURE_NORMAL_EXT': 0x85AF,
+ 'TEXTURE_RECTANGLE_EXT': 0x84F5,
+ 'TEXTURE_BINDING_RECTANGLE_EXT': 0x84F6,
+ 'PROXY_TEXTURE_RECTANGLE_EXT': 0x84F7,
+ 'MAX_RECTANGLE_TEXTURE_SIZE_EXT': 0x84F8,
+ 'SRGB_EXT': 0x8C40,
+ 'SRGB8_EXT': 0x8C41,
+ 'SRGB_ALPHA_EXT': 0x8C42,
+ 'SRGB8_ALPHA8_EXT': 0x8C43,
+ 'SLUMINANCE_ALPHA_EXT': 0x8C44,
+ 'SLUMINANCE8_ALPHA8_EXT': 0x8C45,
+ 'SLUMINANCE_EXT': 0x8C46,
+ 'SLUMINANCE8_EXT': 0x8C47,
+ 'COMPRESSED_SRGB_EXT': 0x8C48,
+ 'COMPRESSED_SRGB_ALPHA_EXT': 0x8C49,
+ 'COMPRESSED_SLUMINANCE_EXT': 0x8C4A,
+ 'COMPRESSED_SLUMINANCE_ALPHA_EXT': 0x8C4B,
+ 'COMPRESSED_SRGB_S3TC_DXT1_EXT': 0x8C4C,
+ 'COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT': 0x8C4D,
+ 'COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT': 0x8C4E,
+ 'COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT': 0x8C4F,
+ 'RGB9_E5_EXT': 0x8C3D,
+ 'UNSIGNED_INT_5_9_9_9_REV_EXT': 0x8C3E,
+ 'TEXTURE_SHARED_SIZE_EXT': 0x8C3F,
+ 'TEXTURE_SWIZZLE_R_EXT': 0x8E42,
+ 'TEXTURE_SWIZZLE_G_EXT': 0x8E43,
+ 'TEXTURE_SWIZZLE_B_EXT': 0x8E44,
+ 'TEXTURE_SWIZZLE_A_EXT': 0x8E45,
+ 'TEXTURE_SWIZZLE_RGBA_EXT': 0x8E46,
+ 'TIME_ELAPSED_EXT': 0x88BF,
+ 'TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH_EXT': 0x8C76,
+ 'TRANSFORM_FEEDBACK_BUFFER_MODE_EXT': 0x8C7F,
+ 'MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS_EXT': 0x8C80,
+ 'TRANSFORM_FEEDBACK_VARYINGS_EXT': 0x8C83,
+ 'TRANSFORM_FEEDBACK_BUFFER_START_EXT': 0x8C84,
+ 'TRANSFORM_FEEDBACK_BUFFER_SIZE_EXT': 0x8C85,
+ 'PRIMITIVES_GENERATED_EXT': 0x8C87,
+ 'TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN_EXT': 0x8C88,
+ 'RASTERIZER_DISCARD_EXT': 0x8C89,
+ 'MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS_EXT': 0x8C8A,
+ 'MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS_EXT': 0x8C8B,
+ 'INTERLEAVED_ATTRIBS_EXT': 0x8C8C,
+ 'SEPARATE_ATTRIBS_EXT': 0x8C8D,
+ 'TRANSFORM_FEEDBACK_BUFFER_EXT': 0x8C8E,
+ 'TRANSFORM_FEEDBACK_BUFFER_BINDING_EXT': 0x8C8F,
+ 'DOUBLE_EXT': 0x140A,
+ 'VERTEX_ARRAY_EXT': 0x8074,
+ 'NORMAL_ARRAY_EXT': 0x8075,
+ 'COLOR_ARRAY_EXT': 0x8076,
+ 'INDEX_ARRAY_EXT': 0x8077,
+ 'TEXTURE_COORD_ARRAY_EXT': 0x8078,
+ 'EDGE_FLAG_ARRAY_EXT': 0x8079,
+ 'VERTEX_ARRAY_SIZE_EXT': 0x807A,
+ 'VERTEX_ARRAY_TYPE_EXT': 0x807B,
+ 'VERTEX_ARRAY_STRIDE_EXT': 0x807C,
+ 'VERTEX_ARRAY_COUNT_EXT': 0x807D,
+ 'NORMAL_ARRAY_TYPE_EXT': 0x807E,
+ 'NORMAL_ARRAY_STRIDE_EXT': 0x807F,
+ 'NORMAL_ARRAY_COUNT_EXT': 0x8080,
+ 'COLOR_ARRAY_SIZE_EXT': 0x8081,
+ 'COLOR_ARRAY_TYPE_EXT': 0x8082,
+ 'COLOR_ARRAY_STRIDE_EXT': 0x8083,
+ 'COLOR_ARRAY_COUNT_EXT': 0x8084,
+ 'INDEX_ARRAY_TYPE_EXT': 0x8085,
+ 'INDEX_ARRAY_STRIDE_EXT': 0x8086,
+ 'INDEX_ARRAY_COUNT_EXT': 0x8087,
+ 'TEXTURE_COORD_ARRAY_SIZE_EXT': 0x8088,
+ 'TEXTURE_COORD_ARRAY_TYPE_EXT': 0x8089,
+ 'TEXTURE_COORD_ARRAY_STRIDE_EXT': 0x808A,
+ 'TEXTURE_COORD_ARRAY_COUNT_EXT': 0x808B,
+ 'EDGE_FLAG_ARRAY_STRIDE_EXT': 0x808C,
+ 'EDGE_FLAG_ARRAY_COUNT_EXT': 0x808D,
+ 'VERTEX_ARRAY_POINTER_EXT': 0x808E,
+ 'NORMAL_ARRAY_POINTER_EXT': 0x808F,
+ 'COLOR_ARRAY_POINTER_EXT': 0x8090,
+ 'INDEX_ARRAY_POINTER_EXT': 0x8091,
+ 'TEXTURE_COORD_ARRAY_POINTER_EXT': 0x8092,
+ 'EDGE_FLAG_ARRAY_POINTER_EXT': 0x8093,
+ 'BGRA': 0x80E1,
+ 'VERTEX_SHADER_EXT': 0x8780,
+ 'VERTEX_SHADER_BINDING_EXT': 0x8781,
+ 'OP_INDEX_EXT': 0x8782,
+ 'OP_NEGATE_EXT': 0x8783,
+ 'OP_DOT3_EXT': 0x8784,
+ 'OP_DOT4_EXT': 0x8785,
+ 'OP_MUL_EXT': 0x8786,
+ 'OP_ADD_EXT': 0x8787,
+ 'OP_MADD_EXT': 0x8788,
+ 'OP_FRAC_EXT': 0x8789,
+ 'OP_MAX_EXT': 0x878A,
+ 'OP_MIN_EXT': 0x878B,
+ 'OP_SET_GE_EXT': 0x878C,
+ 'OP_SET_LT_EXT': 0x878D,
+ 'OP_CLAMP_EXT': 0x878E,
+ 'OP_FLOOR_EXT': 0x878F,
+ 'OP_ROUND_EXT': 0x8790,
+ 'OP_EXP_BASE_2_EXT': 0x8791,
+ 'OP_LOG_BASE_2_EXT': 0x8792,
+ 'OP_POWER_EXT': 0x8793,
+ 'OP_RECIP_EXT': 0x8794,
+ 'OP_RECIP_SQRT_EXT': 0x8795,
+ 'OP_SUB_EXT': 0x8796,
+ 'OP_CROSS_PRODUCT_EXT': 0x8797,
+ 'OP_MULTIPLY_MATRIX_EXT': 0x8798,
+ 'OP_MOV_EXT': 0x8799,
+ 'OUTPUT_VERTEX_EXT': 0x879A,
+ 'OUTPUT_COLOR0_EXT': 0x879B,
+ 'OUTPUT_COLOR1_EXT': 0x879C,
+ 'OUTPUT_TEXTURE_COORD0_EXT': 0x879D,
+ 'OUTPUT_TEXTURE_COORD1_EXT': 0x879E,
+ 'OUTPUT_TEXTURE_COORD2_EXT': 0x879F,
+ 'OUTPUT_TEXTURE_COORD3_EXT': 0x87A0,
+ 'OUTPUT_TEXTURE_COORD4_EXT': 0x87A1,
+ 'OUTPUT_TEXTURE_COORD5_EXT': 0x87A2,
+ 'OUTPUT_TEXTURE_COORD6_EXT': 0x87A3,
+ 'OUTPUT_TEXTURE_COORD7_EXT': 0x87A4,
+ 'OUTPUT_TEXTURE_COORD8_EXT': 0x87A5,
+ 'OUTPUT_TEXTURE_COORD9_EXT': 0x87A6,
+ 'OUTPUT_TEXTURE_COORD10_EXT': 0x87A7,
+ 'OUTPUT_TEXTURE_COORD11_EXT': 0x87A8,
+ 'OUTPUT_TEXTURE_COORD12_EXT': 0x87A9,
+ 'OUTPUT_TEXTURE_COORD13_EXT': 0x87AA,
+ 'OUTPUT_TEXTURE_COORD14_EXT': 0x87AB,
+ 'OUTPUT_TEXTURE_COORD15_EXT': 0x87AC,
+ 'OUTPUT_TEXTURE_COORD16_EXT': 0x87AD,
+ 'OUTPUT_TEXTURE_COORD17_EXT': 0x87AE,
+ 'OUTPUT_TEXTURE_COORD18_EXT': 0x87AF,
+ 'OUTPUT_TEXTURE_COORD19_EXT': 0x87B0,
+ 'OUTPUT_TEXTURE_COORD20_EXT': 0x87B1,
+ 'OUTPUT_TEXTURE_COORD21_EXT': 0x87B2,
+ 'OUTPUT_TEXTURE_COORD22_EXT': 0x87B3,
+ 'OUTPUT_TEXTURE_COORD23_EXT': 0x87B4,
+ 'OUTPUT_TEXTURE_COORD24_EXT': 0x87B5,
+ 'OUTPUT_TEXTURE_COORD25_EXT': 0x87B6,
+ 'OUTPUT_TEXTURE_COORD26_EXT': 0x87B7,
+ 'OUTPUT_TEXTURE_COORD27_EXT': 0x87B8,
+ 'OUTPUT_TEXTURE_COORD28_EXT': 0x87B9,
+ 'OUTPUT_TEXTURE_COORD29_EXT': 0x87BA,
+ 'OUTPUT_TEXTURE_COORD30_EXT': 0x87BB,
+ 'OUTPUT_TEXTURE_COORD31_EXT': 0x87BC,
+ 'OUTPUT_FOG_EXT': 0x87BD,
+ 'SCALAR_EXT': 0x87BE,
+ 'VECTOR_EXT': 0x87BF,
+ 'MATRIX_EXT': 0x87C0,
+ 'VARIANT_EXT': 0x87C1,
+ 'INVARIANT_EXT': 0x87C2,
+ 'LOCAL_CONSTANT_EXT': 0x87C3,
+ 'LOCAL_EXT': 0x87C4,
+ 'MAX_VERTEX_SHADER_INSTRUCTIONS_EXT': 0x87C5,
+ 'MAX_VERTEX_SHADER_VARIANTS_EXT': 0x87C6,
+ 'MAX_VERTEX_SHADER_INVARIANTS_EXT': 0x87C7,
+ 'MAX_VERTEX_SHADER_LOCAL_CONSTANTS_EXT': 0x87C8,
+ 'MAX_VERTEX_SHADER_LOCALS_EXT': 0x87C9,
+ 'MAX_OPTIMIZED_VERTEX_SHADER_INSTRUCTIONS_EXT': 0x87CA,
+ 'MAX_OPTIMIZED_VERTEX_SHADER_VARIANTS_EXT': 0x87CB,
+ 'MAX_OPTIMIZED_VERTEX_SHADER_INVARIANTS_EXT': 0x87CC,
+ 'MAX_OPTIMIZED_VERTEX_SHADER_LOCAL_CONSTANTS_EXT': 0x87CD,
+ 'MAX_OPTIMIZED_VERTEX_SHADER_LOCALS_EXT': 0x87CE,
+ 'VERTEX_SHADER_INSTRUCTIONS_EXT': 0x87CF,
+ 'VERTEX_SHADER_VARIANTS_EXT': 0x87D0,
+ 'VERTEX_SHADER_INVARIANTS_EXT': 0x87D1,
+ 'VERTEX_SHADER_LOCAL_CONSTANTS_EXT': 0x87D2,
+ 'VERTEX_SHADER_LOCALS_EXT': 0x87D3,
+ 'VERTEX_SHADER_OPTIMIZED_EXT': 0x87D4,
+ 'X_EXT': 0x87D5,
+ 'Y_EXT': 0x87D6,
+ 'Z_EXT': 0x87D7,
+ 'W_EXT': 0x87D8,
+ 'NEGATIVE_X_EXT': 0x87D9,
+ 'NEGATIVE_Y_EXT': 0x87DA,
+ 'NEGATIVE_Z_EXT': 0x87DB,
+ 'NEGATIVE_W_EXT': 0x87DC,
+ 'ZERO_EXT': 0x87DD,
+ 'ONE_EXT': 0x87DE,
+ 'NEGATIVE_ONE_EXT': 0x87DF,
+ 'NORMALIZED_RANGE_EXT': 0x87E0,
+ 'FULL_RANGE_EXT': 0x87E1,
+ 'CURRENT_VERTEX_EXT': 0x87E2,
+ 'MVP_MATRIX_EXT': 0x87E3,
+ 'VARIANT_VALUE_EXT': 0x87E4,
+ 'VARIANT_DATATYPE_EXT': 0x87E5,
+ 'VARIANT_ARRAY_STRIDE_EXT': 0x87E6,
+ 'VARIANT_ARRAY_TYPE_EXT': 0x87E7,
+ 'VARIANT_ARRAY_EXT': 0x87E8,
+ 'VARIANT_ARRAY_POINTER_EXT': 0x87E9,
+ 'INVARIANT_VALUE_EXT': 0x87EA,
+ 'INVARIANT_DATATYPE_EXT': 0x87EB,
+ 'LOCAL_CONSTANT_VALUE_EXT': 0x87EC,
+ 'LOCAL_CONSTANT_DATATYPE_EXT': 0x87ED,
+ 'MODELVIEW0_STACK_DEPTH_EXT': 0x0BA3,
+ 'MODELVIEW0_MATRIX_EXT': 0x0BA6,
+ 'MODELVIEW0_EXT': 0x1700,
+ 'MODELVIEW1_STACK_DEPTH_EXT': 0x8502,
+ 'MODELVIEW1_MATRIX_EXT': 0x8506,
+ 'VERTEX_WEIGHTING_EXT': 0x8509,
+ 'MODELVIEW1_EXT': 0x850A,
+ 'CURRENT_VERTEX_WEIGHT_EXT': 0x850B,
+ 'VERTEX_WEIGHT_ARRAY_EXT': 0x850C,
+ 'VERTEX_WEIGHT_ARRAY_SIZE_EXT': 0x850D,
+ 'VERTEX_WEIGHT_ARRAY_TYPE_EXT': 0x850E,
+ 'VERTEX_WEIGHT_ARRAY_STRIDE_EXT': 0x850F,
+ 'VERTEX_WEIGHT_ARRAY_POINTER_EXT': 0x8510,
+ 'OCCLUSION_TEST_HP': 0x8165,
+ 'OCCLUSION_TEST_RESULT_HP': 0x8166,
+ 'MIRRORED_REPEAT_IBM': 0x8370,
+ 'RED_MIN_CLAMP_INGR': 0x8560,
+ 'GREEN_MIN_CLAMP_INGR': 0x8561,
+ 'BLUE_MIN_CLAMP_INGR': 0x8562,
+ 'ALPHA_MIN_CLAMP_INGR': 0x8563,
+ 'RED_MAX_CLAMP_INGR': 0x8564,
+ 'GREEN_MAX_CLAMP_INGR': 0x8565,
+ 'BLUE_MAX_CLAMP_INGR': 0x8566,
+ 'ALPHA_MAX_CLAMP_INGR': 0x8567,
+ 'INTERLACE_READ_INGR': 0x8568,
+ 'PARALLEL_ARRAYS_INTEL': 0x83F4,
+ 'VERTEX_ARRAY_PARALLEL_POINTERS_INTEL': 0x83F5,
+ 'NORMAL_ARRAY_PARALLEL_POINTERS_INTEL': 0x83F6,
+ 'COLOR_ARRAY_PARALLEL_POINTERS_INTEL': 0x83F7,
+ 'TEXTURE_COORD_ARRAY_PARALLEL_POINTERS_INTEL': 0x83F8,
+ 'KTX_FRONT_REGION': 0x0,
+ 'KTX_BACK_REGION': 0x1,
+ 'KTX_Z_REGION': 0x2,
+ 'KTX_STENCIL_REGION': 0x3,
+ 'TEXTURE_1D_STACK_MESAX': 0x8759,
+ 'TEXTURE_2D_STACK_MESAX': 0x875A,
+ 'PROXY_TEXTURE_1D_STACK_MESAX': 0x875B,
+ 'PROXY_TEXTURE_2D_STACK_MESAX': 0x875C,
+ 'TEXTURE_1D_STACK_BINDING_MESAX': 0x875D,
+ 'TEXTURE_2D_STACK_BINDING_MESAX': 0x875E,
+ 'PACK_INVERT_MESA': 0x8758,
+ 'UNSIGNED_SHORT_8_8_MESA': 0x85BA,
+ 'UNSIGNED_SHORT_8_8_REV_MESA': 0x85BB,
+ 'YCBCR_MESA': 0x8757,
+ 'QUERY_WAIT_NV': 0x8E13,
+ 'QUERY_NO_WAIT_NV': 0x8E14,
+ 'QUERY_BY_REGION_WAIT_NV': 0x8E15,
+ 'QUERY_BY_REGION_NO_WAIT_NV': 0x8E16,
+ 'DEPTH_STENCIL_TO_RGBA_NV': 0x886E,
+ 'DEPTH_STENCIL_TO_BGRA_NV': 0x886F,
+ 'DEPTH_COMPONENT32F_NV': 0x8DAB,
+ 'DEPTH32F_STENCIL8_NV': 0x8DAC,
+ 'FLOAT_32_UNSIGNED_INT_24_8_REV_NV': 0x8DAD,
+ 'DEPTH_BUFFER_FLOAT_MODE_NV': 0x8DAF,
+ 'DEPTH_CLAMP_NV': 0x864F,
+ 'SAMPLE_COUNT_BITS_NV': 0x8864,
+ 'CURRENT_SAMPLE_COUNT_QUERY_NV': 0x8865,
+ 'QUERY_RESULT_NV': 0x8866,
+ 'QUERY_RESULT_AVAILABLE_NV': 0x8867,
+ 'SAMPLE_COUNT_NV': 0x8914,
+ 'EVAL_2D_NV': 0x86C0,
+ 'EVAL_TRIANGULAR_2D_NV': 0x86C1,
+ 'MAP_TESSELLATION_NV': 0x86C2,
+ 'MAP_ATTRIB_U_ORDER_NV': 0x86C3,
+ 'MAP_ATTRIB_V_ORDER_NV': 0x86C4,
+ 'EVAL_FRACTIONAL_TESSELLATION_NV': 0x86C5,
+ 'EVAL_VERTEX_ATTRIB0_NV': 0x86C6,
+ 'EVAL_VERTEX_ATTRIB1_NV': 0x86C7,
+ 'EVAL_VERTEX_ATTRIB2_NV': 0x86C8,
+ 'EVAL_VERTEX_ATTRIB3_NV': 0x86C9,
+ 'EVAL_VERTEX_ATTRIB4_NV': 0x86CA,
+ 'EVAL_VERTEX_ATTRIB5_NV': 0x86CB,
+ 'EVAL_VERTEX_ATTRIB6_NV': 0x86CC,
+ 'EVAL_VERTEX_ATTRIB7_NV': 0x86CD,
+ 'EVAL_VERTEX_ATTRIB8_NV': 0x86CE,
+ 'EVAL_VERTEX_ATTRIB9_NV': 0x86CF,
+ 'EVAL_VERTEX_ATTRIB10_NV': 0x86D0,
+ 'EVAL_VERTEX_ATTRIB11_NV': 0x86D1,
+ 'EVAL_VERTEX_ATTRIB12_NV': 0x86D2,
+ 'EVAL_VERTEX_ATTRIB13_NV': 0x86D3,
+ 'EVAL_VERTEX_ATTRIB14_NV': 0x86D4,
+ 'EVAL_VERTEX_ATTRIB15_NV': 0x86D5,
+ 'MAX_MAP_TESSELLATION_NV': 0x86D6,
+ 'MAX_RATIONAL_EVAL_ORDER_NV': 0x86D7,
+ 'SAMPLE_POSITION_NV': 0x8E50,
+ 'SAMPLE_MASK_NV': 0x8E51,
+ 'SAMPLE_MASK_VALUE_NV': 0x8E52,
+ 'TEXTURE_BINDING_RENDERBUFFER_NV': 0x8E53,
+ 'TEXTURE_RENDERBUFFER_DATA_STORE_BINDING_NV': 0x8E54,
+ 'TEXTURE_RENDERBUFFER_NV': 0x8E55,
+ 'SAMPLER_RENDERBUFFER_NV': 0x8E56,
+ 'INT_SAMPLER_RENDERBUFFER_NV': 0x8E57,
+ 'UNSIGNED_INT_SAMPLER_RENDERBUFFER_NV': 0x8E58,
+ 'MAX_SAMPLE_MASK_WORDS_NV': 0x8E59,
+ 'ALL_COMPLETED_NV': 0x84F2,
+ 'FENCE_STATUS_NV': 0x84F3,
+ 'FENCE_CONDITION_NV': 0x84F4,
+ 'FLOAT_R_NV': 0x8880,
+ 'FLOAT_RG_NV': 0x8881,
+ 'FLOAT_RGB_NV': 0x8882,
+ 'FLOAT_RGBA_NV': 0x8883,
+ 'FLOAT_R16_NV': 0x8884,
+ 'FLOAT_R32_NV': 0x8885,
+ 'FLOAT_RG16_NV': 0x8886,
+ 'FLOAT_RG32_NV': 0x8887,
+ 'FLOAT_RGB16_NV': 0x8888,
+ 'FLOAT_RGB32_NV': 0x8889,
+ 'FLOAT_RGBA16_NV': 0x888A,
+ 'FLOAT_RGBA32_NV': 0x888B,
+ 'TEXTURE_FLOAT_COMPONENTS_NV': 0x888C,
+ 'FLOAT_CLEAR_COLOR_VALUE_NV': 0x888D,
+ 'FLOAT_RGBA_MODE_NV': 0x888E,
+ 'FOG_DISTANCE_MODE_NV': 0x855A,
+ 'EYE_RADIAL_NV': 0x855B,
+ 'EYE_PLANE_ABSOLUTE_NV': 0x855C,
+ 'MAX_FRAGMENT_PROGRAM_LOCAL_PARAMETERS_NV': 0x8868,
+ 'FRAGMENT_PROGRAM_NV': 0x8870,
+ 'MAX_TEXTURE_COORDS_NV': 0x8871,
+ 'MAX_TEXTURE_IMAGE_UNITS_NV': 0x8872,
+ 'FRAGMENT_PROGRAM_BINDING_NV': 0x8873,
+ 'PROGRAM_ERROR_STRING_NV': 0x8874,
+ 'MAX_PROGRAM_EXEC_INSTRUCTIONS_NV': 0x88F4,
+ 'MAX_PROGRAM_CALL_DEPTH_NV': 0x88F5,
+ 'MAX_PROGRAM_IF_DEPTH_NV': 0x88F6,
+ 'MAX_PROGRAM_LOOP_DEPTH_NV': 0x88F7,
+ 'MAX_PROGRAM_LOOP_COUNT_NV': 0x88F8,
+ 'RENDERBUFFER_COVERAGE_SAMPLES_NV': 0x8CAB,
+ 'RENDERBUFFER_COLOR_SAMPLES_NV': 0x8E10,
+ 'MAX_MULTISAMPLE_COVERAGE_MODES_NV': 0x8E11,
+ 'MULTISAMPLE_COVERAGE_MODES_NV': 0x8E12,
+ 'GEOMETRY_PROGRAM_NV': 0x8C26,
+ 'MAX_PROGRAM_OUTPUT_VERTICES_NV': 0x8C27,
+ 'MAX_PROGRAM_TOTAL_OUTPUT_COMPONENTS_NV': 0x8C28,
+ 'MIN_PROGRAM_TEXEL_OFFSET_NV': 0x8904,
+ 'MAX_PROGRAM_TEXEL_OFFSET_NV': 0x8905,
+ 'PROGRAM_ATTRIB_COMPONENTS_NV': 0x8906,
+ 'PROGRAM_RESULT_COMPONENTS_NV': 0x8907,
+ 'MAX_PROGRAM_ATTRIB_COMPONENTS_NV': 0x8908,
+ 'MAX_PROGRAM_RESULT_COMPONENTS_NV': 0x8909,
+ 'MAX_PROGRAM_GENERIC_ATTRIBS_NV': 0x8DA5,
+ 'MAX_PROGRAM_GENERIC_RESULTS_NV': 0x8DA6,
+ 'HALF_FLOAT_NV': 0x140B,
+ 'MAX_SHININESS_NV': 0x8504,
+ 'MAX_SPOT_EXPONENT_NV': 0x8505,
+ 'MULTISAMPLE_FILTER_HINT_NV': 0x8534,
+ 'PIXEL_COUNTER_BITS_NV': 0x8864,
+ 'CURRENT_OCCLUSION_QUERY_ID_NV': 0x8865,
+ 'PIXEL_COUNT_NV': 0x8866,
+ 'PIXEL_COUNT_AVAILABLE_NV': 0x8867,
+ 'DEPTH_STENCIL_NV': 0x84F9,
+ 'UNSIGNED_INT_24_8_NV': 0x84FA,
+ 'MAX_PROGRAM_PARAMETER_BUFFER_BINDINGS_NV': 0x8DA0,
+ 'MAX_PROGRAM_PARAMETER_BUFFER_SIZE_NV': 0x8DA1,
+ 'VERTEX_PROGRAM_PARAMETER_BUFFER_NV': 0x8DA2,
+ 'GEOMETRY_PROGRAM_PARAMETER_BUFFER_NV': 0x8DA3,
+ 'FRAGMENT_PROGRAM_PARAMETER_BUFFER_NV': 0x8DA4,
+ 'WRITE_PIXEL_DATA_RANGE_NV': 0x8878,
+ 'READ_PIXEL_DATA_RANGE_NV': 0x8879,
+ 'WRITE_PIXEL_DATA_RANGE_LENGTH_NV': 0x887A,
+ 'READ_PIXEL_DATA_RANGE_LENGTH_NV': 0x887B,
+ 'WRITE_PIXEL_DATA_RANGE_POINTER_NV': 0x887C,
+ 'READ_PIXEL_DATA_RANGE_POINTER_NV': 0x887D,
+ 'POINT_SPRITE_NV': 0x8861,
+ 'COORD_REPLACE_NV': 0x8862,
+ 'POINT_SPRITE_R_MODE_NV': 0x8863,
+ 'FRAME_NV': 0x8E26,
+ 'FIELDS_NV': 0x8E27,
+ 'CURRENT_TIME_NV': 0x8E28,
+ 'NUM_FILL_STREAMS_NV': 0x8E29,
+ 'PRESENT_TIME_NV': 0x8E2A,
+ 'PRESENT_DURATION_NV': 0x8E2B,
+ 'PRIMITIVE_RESTART_NV': 0x8558,
+ 'PRIMITIVE_RESTART_INDEX_NV': 0x8559,
+ 'REGISTER_COMBINERS_NV': 0x8522,
+ 'VARIABLE_A_NV': 0x8523,
+ 'VARIABLE_B_NV': 0x8524,
+ 'VARIABLE_C_NV': 0x8525,
+ 'VARIABLE_D_NV': 0x8526,
+ 'VARIABLE_E_NV': 0x8527,
+ 'VARIABLE_F_NV': 0x8528,
+ 'VARIABLE_G_NV': 0x8529,
+ 'CONSTANT_COLOR0_NV': 0x852A,
+ 'CONSTANT_COLOR1_NV': 0x852B,
+ 'PRIMARY_COLOR_NV': 0x852C,
+ 'SECONDARY_COLOR_NV': 0x852D,
+ 'SPARE0_NV': 0x852E,
+ 'SPARE1_NV': 0x852F,
+ 'DISCARD_NV': 0x8530,
+ 'E_TIMES_F_NV': 0x8531,
+ 'SPARE0_PLUS_SECONDARY_COLOR_NV': 0x8532,
+ 'UNSIGNED_IDENTITY_NV': 0x8536,
+ 'UNSIGNED_INVERT_NV': 0x8537,
+ 'EXPAND_NORMAL_NV': 0x8538,
+ 'EXPAND_NEGATE_NV': 0x8539,
+ 'HALF_BIAS_NORMAL_NV': 0x853A,
+ 'HALF_BIAS_NEGATE_NV': 0x853B,
+ 'SIGNED_IDENTITY_NV': 0x853C,
+ 'SIGNED_NEGATE_NV': 0x853D,
+ 'SCALE_BY_TWO_NV': 0x853E,
+ 'SCALE_BY_FOUR_NV': 0x853F,
+ 'SCALE_BY_ONE_HALF_NV': 0x8540,
+ 'BIAS_BY_NEGATIVE_ONE_HALF_NV': 0x8541,
+ 'COMBINER_INPUT_NV': 0x8542,
+ 'COMBINER_MAPPING_NV': 0x8543,
+ 'COMBINER_COMPONENT_USAGE_NV': 0x8544,
+ 'COMBINER_AB_DOT_PRODUCT_NV': 0x8545,
+ 'COMBINER_CD_DOT_PRODUCT_NV': 0x8546,
+ 'COMBINER_MUX_SUM_NV': 0x8547,
+ 'COMBINER_SCALE_NV': 0x8548,
+ 'COMBINER_BIAS_NV': 0x8549,
+ 'COMBINER_AB_OUTPUT_NV': 0x854A,
+ 'COMBINER_CD_OUTPUT_NV': 0x854B,
+ 'COMBINER_SUM_OUTPUT_NV': 0x854C,
+ 'MAX_GENERAL_COMBINERS_NV': 0x854D,
+ 'NUM_GENERAL_COMBINERS_NV': 0x854E,
+ 'COLOR_SUM_CLAMP_NV': 0x854F,
+ 'COMBINER0_NV': 0x8550,
+ 'COMBINER1_NV': 0x8551,
+ 'COMBINER2_NV': 0x8552,
+ 'COMBINER3_NV': 0x8553,
+ 'COMBINER4_NV': 0x8554,
+ 'COMBINER5_NV': 0x8555,
+ 'COMBINER6_NV': 0x8556,
+ 'COMBINER7_NV': 0x8557,
+ 'PER_STAGE_CONSTANTS_NV': 0x8535,
+ 'EMBOSS_LIGHT_NV': 0x855D,
+ 'EMBOSS_CONSTANT_NV': 0x855E,
+ 'EMBOSS_MAP_NV': 0x855F,
+ 'NORMAL_MAP_NV': 0x8511,
+ 'REFLECTION_MAP_NV': 0x8512,
+ 'COMBINE4_NV': 0x8503,
+ 'SOURCE3_RGB_NV': 0x8583,
+ 'SOURCE3_ALPHA_NV': 0x858B,
+ 'OPERAND3_RGB_NV': 0x8593,
+ 'OPERAND3_ALPHA_NV': 0x859B,
+ 'TEXTURE_UNSIGNED_REMAP_MODE_NV': 0x888F,
+ 'TEXTURE_RECTANGLE_NV': 0x84F5,
+ 'TEXTURE_BINDING_RECTANGLE_NV': 0x84F6,
+ 'PROXY_TEXTURE_RECTANGLE_NV': 0x84F7,
+ 'MAX_RECTANGLE_TEXTURE_SIZE_NV': 0x84F8,
+ 'OFFSET_TEXTURE_RECTANGLE_NV': 0x864C,
+ 'OFFSET_TEXTURE_RECTANGLE_SCALE_NV': 0x864D,
+ 'DOT_PRODUCT_TEXTURE_RECTANGLE_NV': 0x864E,
+ 'RGBA_UNSIGNED_DOT_PRODUCT_MAPPING_NV': 0x86D9,
+ 'UNSIGNED_INT_S8_S8_8_8_NV': 0x86DA,
+ 'UNSIGNED_INT_8_8_S8_S8_REV_NV': 0x86DB,
+ 'DSDT_MAG_INTENSITY_NV': 0x86DC,
+ 'SHADER_CONSISTENT_NV': 0x86DD,
+ 'TEXTURE_SHADER_NV': 0x86DE,
+ 'SHADER_OPERATION_NV': 0x86DF,
+ 'CULL_MODES_NV': 0x86E0,
+ 'OFFSET_TEXTURE_2D_MATRIX_NV': 0x86E1,
+ 'OFFSET_TEXTURE_MATRIX_NV': 0x86E1,
+ 'OFFSET_TEXTURE_2D_SCALE_NV': 0x86E2,
+ 'OFFSET_TEXTURE_SCALE_NV': 0x86E2,
+ 'OFFSET_TEXTURE_BIAS_NV': 0x86E3,
+ 'OFFSET_TEXTURE_2D_BIAS_NV': 0x86E3,
+ 'PREVIOUS_TEXTURE_INPUT_NV': 0x86E4,
+ 'CONST_EYE_NV': 0x86E5,
+ 'PASS_THROUGH_NV': 0x86E6,
+ 'CULL_FRAGMENT_NV': 0x86E7,
+ 'OFFSET_TEXTURE_2D_NV': 0x86E8,
+ 'DEPENDENT_AR_TEXTURE_2D_NV': 0x86E9,
+ 'DEPENDENT_GB_TEXTURE_2D_NV': 0x86EA,
+ 'DOT_PRODUCT_NV': 0x86EC,
+ 'DOT_PRODUCT_DEPTH_REPLACE_NV': 0x86ED,
+ 'DOT_PRODUCT_TEXTURE_2D_NV': 0x86EE,
+ 'DOT_PRODUCT_TEXTURE_CUBE_MAP_NV': 0x86F0,
+ 'DOT_PRODUCT_DIFFUSE_CUBE_MAP_NV': 0x86F1,
+ 'DOT_PRODUCT_REFLECT_CUBE_MAP_NV': 0x86F2,
+ 'DOT_PRODUCT_CONST_EYE_REFLECT_CUBE_MAP_NV': 0x86F3,
+ 'HILO_NV': 0x86F4,
+ 'DSDT_NV': 0x86F5,
+ 'DSDT_MAG_NV': 0x86F6,
+ 'DSDT_MAG_VIB_NV': 0x86F7,
+ 'HILO16_NV': 0x86F8,
+ 'SIGNED_HILO_NV': 0x86F9,
+ 'SIGNED_HILO16_NV': 0x86FA,
+ 'SIGNED_RGBA_NV': 0x86FB,
+ 'SIGNED_RGBA8_NV': 0x86FC,
+ 'SIGNED_RGB_NV': 0x86FE,
+ 'SIGNED_RGB8_NV': 0x86FF,
+ 'SIGNED_LUMINANCE_NV': 0x8701,
+ 'SIGNED_LUMINANCE8_NV': 0x8702,
+ 'SIGNED_LUMINANCE_ALPHA_NV': 0x8703,
+ 'SIGNED_LUMINANCE8_ALPHA8_NV': 0x8704,
+ 'SIGNED_ALPHA_NV': 0x8705,
+ 'SIGNED_ALPHA8_NV': 0x8706,
+ 'SIGNED_INTENSITY_NV': 0x8707,
+ 'SIGNED_INTENSITY8_NV': 0x8708,
+ 'DSDT8_NV': 0x8709,
+ 'DSDT8_MAG8_NV': 0x870A,
+ 'DSDT8_MAG8_INTENSITY8_NV': 0x870B,
+ 'SIGNED_RGB_UNSIGNED_ALPHA_NV': 0x870C,
+ 'SIGNED_RGB8_UNSIGNED_ALPHA8_NV': 0x870D,
+ 'HI_SCALE_NV': 0x870E,
+ 'LO_SCALE_NV': 0x870F,
+ 'DS_SCALE_NV': 0x8710,
+ 'DT_SCALE_NV': 0x8711,
+ 'MAGNITUDE_SCALE_NV': 0x8712,
+ 'VIBRANCE_SCALE_NV': 0x8713,
+ 'HI_BIAS_NV': 0x8714,
+ 'LO_BIAS_NV': 0x8715,
+ 'DS_BIAS_NV': 0x8716,
+ 'DT_BIAS_NV': 0x8717,
+ 'MAGNITUDE_BIAS_NV': 0x8718,
+ 'VIBRANCE_BIAS_NV': 0x8719,
+ 'TEXTURE_BORDER_VALUES_NV': 0x871A,
+ 'TEXTURE_HI_SIZE_NV': 0x871B,
+ 'TEXTURE_LO_SIZE_NV': 0x871C,
+ 'TEXTURE_DS_SIZE_NV': 0x871D,
+ 'TEXTURE_DT_SIZE_NV': 0x871E,
+ 'TEXTURE_MAG_SIZE_NV': 0x871F,
+ 'UNSIGNED_INT_S8_S8_8_8_NV': 0x86DA,
+ 'UNSIGNED_INT_8_8_S8_S8_REV_NV': 0x86DB,
+ 'DSDT_MAG_INTENSITY_NV': 0x86DC,
+ 'DOT_PRODUCT_TEXTURE_3D_NV': 0x86EF,
+ 'HILO_NV': 0x86F4,
+ 'DSDT_NV': 0x86F5,
+ 'DSDT_MAG_NV': 0x86F6,
+ 'DSDT_MAG_VIB_NV': 0x86F7,
+ 'HILO16_NV': 0x86F8,
+ 'SIGNED_HILO_NV': 0x86F9,
+ 'SIGNED_HILO16_NV': 0x86FA,
+ 'SIGNED_RGBA_NV': 0x86FB,
+ 'SIGNED_RGBA8_NV': 0x86FC,
+ 'SIGNED_RGB_NV': 0x86FE,
+ 'SIGNED_RGB8_NV': 0x86FF,
+ 'SIGNED_LUMINANCE_NV': 0x8701,
+ 'SIGNED_LUMINANCE8_NV': 0x8702,
+ 'SIGNED_LUMINANCE_ALPHA_NV': 0x8703,
+ 'SIGNED_LUMINANCE8_ALPHA8_NV': 0x8704,
+ 'SIGNED_ALPHA_NV': 0x8705,
+ 'SIGNED_ALPHA8_NV': 0x8706,
+ 'SIGNED_INTENSITY_NV': 0x8707,
+ 'SIGNED_INTENSITY8_NV': 0x8708,
+ 'DSDT8_NV': 0x8709,
+ 'DSDT8_MAG8_NV': 0x870A,
+ 'DSDT8_MAG8_INTENSITY8_NV': 0x870B,
+ 'SIGNED_RGB_UNSIGNED_ALPHA_NV': 0x870C,
+ 'SIGNED_RGB8_UNSIGNED_ALPHA8_NV': 0x870D,
+ 'OFFSET_PROJECTIVE_TEXTURE_2D_NV': 0x8850,
+ 'OFFSET_PROJECTIVE_TEXTURE_2D_SCALE_NV': 0x8851,
+ 'OFFSET_PROJECTIVE_TEXTURE_RECTANGLE_NV': 0x8852,
+ 'OFFSET_PROJECTIVE_TEXTURE_RECTANGLE_SCALE_NV': 0x8853,
+ 'OFFSET_HILO_TEXTURE_2D_NV': 0x8854,
+ 'OFFSET_HILO_TEXTURE_RECTANGLE_NV': 0x8855,
+ 'OFFSET_HILO_PROJECTIVE_TEXTURE_2D_NV': 0x8856,
+ 'OFFSET_HILO_PROJECTIVE_TEXTURE_RECTANGLE_NV': 0x8857,
+ 'DEPENDENT_HILO_TEXTURE_2D_NV': 0x8858,
+ 'DEPENDENT_RGB_TEXTURE_3D_NV': 0x8859,
+ 'DEPENDENT_RGB_TEXTURE_CUBE_MAP_NV': 0x885A,
+ 'DOT_PRODUCT_PASS_THROUGH_NV': 0x885B,
+ 'DOT_PRODUCT_TEXTURE_1D_NV': 0x885C,
+ 'DOT_PRODUCT_AFFINE_DEPTH_REPLACE_NV': 0x885D,
+ 'HILO8_NV': 0x885E,
+ 'SIGNED_HILO8_NV': 0x885F,
+ 'FORCE_BLUE_TO_ONE_NV': 0x8860,
+ 'BACK_PRIMARY_COLOR_NV': 0x8C77,
+ 'BACK_SECONDARY_COLOR_NV': 0x8C78,
+ 'TEXTURE_COORD_NV': 0x8C79,
+ 'CLIP_DISTANCE_NV': 0x8C7A,
+ 'VERTEX_ID_NV': 0x8C7B,
+ 'PRIMITIVE_ID_NV': 0x8C7C,
+ 'GENERIC_ATTRIB_NV': 0x8C7D,
+ 'TRANSFORM_FEEDBACK_ATTRIBS_NV': 0x8C7E,
+ 'TRANSFORM_FEEDBACK_BUFFER_MODE_NV': 0x8C7F,
+ 'MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS_NV': 0x8C80,
+ 'ACTIVE_VARYINGS_NV': 0x8C81,
+ 'ACTIVE_VARYING_MAX_LENGTH_NV': 0x8C82,
+ 'TRANSFORM_FEEDBACK_VARYINGS_NV': 0x8C83,
+ 'TRANSFORM_FEEDBACK_BUFFER_START_NV': 0x8C84,
+ 'TRANSFORM_FEEDBACK_BUFFER_SIZE_NV': 0x8C85,
+ 'TRANSFORM_FEEDBACK_RECORD_NV': 0x8C86,
+ 'PRIMITIVES_GENERATED_NV': 0x8C87,
+ 'TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN_NV': 0x8C88,
+ 'RASTERIZER_DISCARD_NV': 0x8C89,
+ 'MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS_NV': 0x8C8A,
+ 'MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS_NV': 0x8C8B,
+ 'INTERLEAVED_ATTRIBS_NV': 0x8C8C,
+ 'SEPARATE_ATTRIBS_NV': 0x8C8D,
+ 'TRANSFORM_FEEDBACK_BUFFER_NV': 0x8C8E,
+ 'TRANSFORM_FEEDBACK_BUFFER_BINDING_NV': 0x8C8F,
+ 'VERTEX_ARRAY_RANGE_NV': 0x851D,
+ 'VERTEX_ARRAY_RANGE_LENGTH_NV': 0x851E,
+ 'VERTEX_ARRAY_RANGE_VALID_NV': 0x851F,
+ 'MAX_VERTEX_ARRAY_RANGE_ELEMENT_NV': 0x8520,
+ 'VERTEX_ARRAY_RANGE_POINTER_NV': 0x8521,
+ 'VERTEX_ARRAY_RANGE_WITHOUT_FLUSH_NV': 0x8533,
+ 'VERTEX_PROGRAM_NV': 0x8620,
+ 'VERTEX_STATE_PROGRAM_NV': 0x8621,
+ 'ATTRIB_ARRAY_SIZE_NV': 0x8623,
+ 'ATTRIB_ARRAY_STRIDE_NV': 0x8624,
+ 'ATTRIB_ARRAY_TYPE_NV': 0x8625,
+ 'CURRENT_ATTRIB_NV': 0x8626,
+ 'PROGRAM_LENGTH_NV': 0x8627,
+ 'PROGRAM_STRING_NV': 0x8628,
+ 'MODELVIEW_PROJECTION_NV': 0x8629,
+ 'IDENTITY_NV': 0x862A,
+ 'INVERSE_NV': 0x862B,
+ 'TRANSPOSE_NV': 0x862C,
+ 'INVERSE_TRANSPOSE_NV': 0x862D,
+ 'MAX_TRACK_MATRIX_STACK_DEPTH_NV': 0x862E,
+ 'MAX_TRACK_MATRICES_NV': 0x862F,
+ 'MATRIX0_NV': 0x8630,
+ 'MATRIX1_NV': 0x8631,
+ 'MATRIX2_NV': 0x8632,
+ 'MATRIX3_NV': 0x8633,
+ 'MATRIX4_NV': 0x8634,
+ 'MATRIX5_NV': 0x8635,
+ 'MATRIX6_NV': 0x8636,
+ 'MATRIX7_NV': 0x8637,
+ 'CURRENT_MATRIX_STACK_DEPTH_NV': 0x8640,
+ 'CURRENT_MATRIX_NV': 0x8641,
+ 'VERTEX_PROGRAM_POINT_SIZE_NV': 0x8642,
+ 'VERTEX_PROGRAM_TWO_SIDE_NV': 0x8643,
+ 'PROGRAM_PARAMETER_NV': 0x8644,
+ 'ATTRIB_ARRAY_POINTER_NV': 0x8645,
+ 'PROGRAM_TARGET_NV': 0x8646,
+ 'PROGRAM_RESIDENT_NV': 0x8647,
+ 'TRACK_MATRIX_NV': 0x8648,
+ 'TRACK_MATRIX_TRANSFORM_NV': 0x8649,
+ 'VERTEX_PROGRAM_BINDING_NV': 0x864A,
+ 'PROGRAM_ERROR_POSITION_NV': 0x864B,
+ 'VERTEX_ATTRIB_ARRAY0_NV': 0x8650,
+ 'VERTEX_ATTRIB_ARRAY1_NV': 0x8651,
+ 'VERTEX_ATTRIB_ARRAY2_NV': 0x8652,
+ 'VERTEX_ATTRIB_ARRAY3_NV': 0x8653,
+ 'VERTEX_ATTRIB_ARRAY4_NV': 0x8654,
+ 'VERTEX_ATTRIB_ARRAY5_NV': 0x8655,
+ 'VERTEX_ATTRIB_ARRAY6_NV': 0x8656,
+ 'VERTEX_ATTRIB_ARRAY7_NV': 0x8657,
+ 'VERTEX_ATTRIB_ARRAY8_NV': 0x8658,
+ 'VERTEX_ATTRIB_ARRAY9_NV': 0x8659,
+ 'VERTEX_ATTRIB_ARRAY10_NV': 0x865A,
+ 'VERTEX_ATTRIB_ARRAY11_NV': 0x865B,
+ 'VERTEX_ATTRIB_ARRAY12_NV': 0x865C,
+ 'VERTEX_ATTRIB_ARRAY13_NV': 0x865D,
+ 'VERTEX_ATTRIB_ARRAY14_NV': 0x865E,
+ 'VERTEX_ATTRIB_ARRAY15_NV': 0x865F,
+ 'MAP1_VERTEX_ATTRIB0_4_NV': 0x8660,
+ 'MAP1_VERTEX_ATTRIB1_4_NV': 0x8661,
+ 'MAP1_VERTEX_ATTRIB2_4_NV': 0x8662,
+ 'MAP1_VERTEX_ATTRIB3_4_NV': 0x8663,
+ 'MAP1_VERTEX_ATTRIB4_4_NV': 0x8664,
+ 'MAP1_VERTEX_ATTRIB5_4_NV': 0x8665,
+ 'MAP1_VERTEX_ATTRIB6_4_NV': 0x8666,
+ 'MAP1_VERTEX_ATTRIB7_4_NV': 0x8667,
+ 'MAP1_VERTEX_ATTRIB8_4_NV': 0x8668,
+ 'MAP1_VERTEX_ATTRIB9_4_NV': 0x8669,
+ 'MAP1_VERTEX_ATTRIB10_4_NV': 0x866A,
+ 'MAP1_VERTEX_ATTRIB11_4_NV': 0x866B,
+ 'MAP1_VERTEX_ATTRIB12_4_NV': 0x866C,
+ 'MAP1_VERTEX_ATTRIB13_4_NV': 0x866D,
+ 'MAP1_VERTEX_ATTRIB14_4_NV': 0x866E,
+ 'MAP1_VERTEX_ATTRIB15_4_NV': 0x866F,
+ 'MAP2_VERTEX_ATTRIB0_4_NV': 0x8670,
+ 'MAP2_VERTEX_ATTRIB1_4_NV': 0x8671,
+ 'MAP2_VERTEX_ATTRIB2_4_NV': 0x8672,
+ 'MAP2_VERTEX_ATTRIB3_4_NV': 0x8673,
+ 'MAP2_VERTEX_ATTRIB4_4_NV': 0x8674,
+ 'MAP2_VERTEX_ATTRIB5_4_NV': 0x8675,
+ 'MAP2_VERTEX_ATTRIB6_4_NV': 0x8676,
+ 'MAP2_VERTEX_ATTRIB7_4_NV': 0x8677,
+ 'MAP2_VERTEX_ATTRIB8_4_NV': 0x8678,
+ 'MAP2_VERTEX_ATTRIB9_4_NV': 0x8679,
+ 'MAP2_VERTEX_ATTRIB10_4_NV': 0x867A,
+ 'MAP2_VERTEX_ATTRIB11_4_NV': 0x867B,
+ 'MAP2_VERTEX_ATTRIB12_4_NV': 0x867C,
+ 'MAP2_VERTEX_ATTRIB13_4_NV': 0x867D,
+ 'MAP2_VERTEX_ATTRIB14_4_NV': 0x867E,
+ 'MAP2_VERTEX_ATTRIB15_4_NV': 0x867F,
+ 'MAX_PROGRAM_EXEC_INSTRUCTIONS_NV': 0x88F4,
+ 'MAX_PROGRAM_CALL_DEPTH_NV': 0x88F5,
+ 'MAX_VERTEX_TEXTURE_IMAGE_UNITS_ARB': 0x8B4C,
+ 'BYTE': 0x1400,
+ 'PALETTE4_RGB8_OES': 0x8B90,
+ 'PALETTE4_RGBA8_OES': 0x8B91,
+ 'PALETTE4_R5_G6_B5_OES': 0x8B92,
+ 'PALETTE4_RGBA4_OES': 0x8B93,
+ 'PALETTE4_RGB5_A1_OES': 0x8B94,
+ 'PALETTE8_RGB8_OES': 0x8B95,
+ 'PALETTE8_RGBA8_OES': 0x8B96,
+ 'PALETTE8_R5_G6_B5_OES': 0x8B97,
+ 'PALETTE8_RGBA4_OES': 0x8B98,
+ 'PALETTE8_RGB5_A1_OES': 0x8B99,
+ 'IMPLEMENTATION_COLOR_READ_TYPE_OES': 0x8B9A,
+ 'IMPLEMENTATION_COLOR_READ_FORMAT_OES': 0x8B9B,
+ 'INTERLACE_OML': 0x8980,
+ 'INTERLACE_READ_OML': 0x8981,
+ 'PACK_RESAMPLE_OML': 0x8984,
+ 'UNPACK_RESAMPLE_OML': 0x8985,
+ 'RESAMPLE_REPLICATE_OML': 0x8986,
+ 'RESAMPLE_ZERO_FILL_OML': 0x8987,
+ 'RESAMPLE_AVERAGE_OML': 0x8988,
+ 'RESAMPLE_DECIMATE_OML': 0x8989,
+ 'FORMAT_SUBSAMPLE_24_24_OML': 0x8982,
+ 'FORMAT_SUBSAMPLE_244_244_OML': 0x8983,
+ 'VERTEX23_BIT_PGI': 0x00000004,
+ 'VERTEX4_BIT_PGI': 0x00000008,
+ 'COLOR3_BIT_PGI': 0x00010000,
+ 'COLOR4_BIT_PGI': 0x00020000,
+ 'EDGEFLAG_BIT_PGI': 0x00040000,
+ 'INDEX_BIT_PGI': 0x00080000,
+ 'MAT_AMBIENT_BIT_PGI': 0x00100000,
+ 'MAT_AMBIENT_AND_DIFFUSE_BIT_PGI': 0x00200000,
+ 'MAT_DIFFUSE_BIT_PGI': 0x00400000,
+ 'MAT_EMISSION_BIT_PGI': 0x00800000,
+ 'MAT_COLOR_INDEXES_BIT_PGI': 0x01000000,
+ 'MAT_SHININESS_BIT_PGI': 0x02000000,
+ 'MAT_SPECULAR_BIT_PGI': 0x04000000,
+ 'NORMAL_BIT_PGI': 0x08000000,
+ 'TEXCOORD1_BIT_PGI': 0x10000000,
+ 'TEXCOORD2_BIT_PGI': 0x20000000,
+ 'TEXCOORD3_BIT_PGI': 0x40000000,
+ 'TEXCOORD4_BIT_PGI': 0x80000000,
+ 'SCREEN_COORDINATES_REND': 0x8490,
+ 'INVERTED_SCREEN_W_REND': 0x8491,
+ 'RGB_S3TC': 0x83A0,
+ 'RGB4_S3TC': 0x83A1,
+ 'RGBA_S3TC': 0x83A2,
+ 'RGBA4_S3TC': 0x83A3,
+ 'RGBA_DXT5_S3TC': 0x83A4,
+ 'RGBA4_DXT5_S3TC': 0x83A5,
+ 'EXTENDED_RANGE_SGIS': 0x85A5,
+ 'MIN_RED_SGIS': 0x85A6,
+ 'MAX_RED_SGIS': 0x85A7,
+ 'MIN_GREEN_SGIS': 0x85A8,
+ 'MAX_GREEN_SGIS': 0x85A9,
+ 'MIN_BLUE_SGIS': 0x85AA,
+ 'MAX_BLUE_SGIS': 0x85AB,
+ 'MIN_ALPHA_SGIS': 0x85AC,
+ 'MAX_ALPHA_SGIS': 0x85AD,
+ 'GENERATE_MIPMAP_SGIS': 0x8191,
+ 'GENERATE_MIPMAP_HINT_SGIS': 0x8192,
+ 'MULTISAMPLE_SGIS': 0x809D,
+ 'SAMPLE_ALPHA_TO_MASK_SGIS': 0x809E,
+ 'SAMPLE_ALPHA_TO_ONE_SGIS': 0x809F,
+ 'SAMPLE_MASK_SGIS': 0x80A0,
+ '1PASS_SGIS': 0x80A1,
+ '2PASS_0_SGIS': 0x80A2,
+ '2PASS_1_SGIS': 0x80A3,
+ '4PASS_0_SGIS': 0x80A4,
+ '4PASS_1_SGIS': 0x80A5,
+ '4PASS_2_SGIS': 0x80A6,
+ '4PASS_3_SGIS': 0x80A7,
+ 'SAMPLE_BUFFERS_SGIS': 0x80A8,
+ 'SAMPLES_SGIS': 0x80A9,
+ 'SAMPLE_MASK_VALUE_SGIS': 0x80AA,
+ 'SAMPLE_MASK_INVERT_SGIS': 0x80AB,
+ 'SAMPLE_PATTERN_SGIS': 0x80AC,
+ 'MULTISAMPLE_BIT_EXT': 0x20000000,
+ 'EYE_DISTANCE_TO_POINT_SGIS': 0x81F0,
+ 'OBJECT_DISTANCE_TO_POINT_SGIS': 0x81F1,
+ 'EYE_DISTANCE_TO_LINE_SGIS': 0x81F2,
+ 'OBJECT_DISTANCE_TO_LINE_SGIS': 0x81F3,
+ 'EYE_POINT_SGIS': 0x81F4,
+ 'OBJECT_POINT_SGIS': 0x81F5,
+ 'EYE_LINE_SGIS': 0x81F6,
+ 'OBJECT_LINE_SGIS': 0x81F7,
+ 'CLAMP_TO_BORDER_SGIS': 0x812D,
+ 'CLAMP_TO_EDGE_SGIS': 0x812F,
+ 'TEXTURE_MIN_LOD_SGIS': 0x813A,
+ 'TEXTURE_MAX_LOD_SGIS': 0x813B,
+ 'TEXTURE_BASE_LEVEL_SGIS': 0x813C,
+ 'TEXTURE_MAX_LEVEL_SGIS': 0x813D,
+ 'ASYNC_MARKER_SGIX': 0x8329,
+ 'ASYNC_HISTOGRAM_SGIX': 0x832C,
+ 'MAX_ASYNC_HISTOGRAM_SGIX': 0x832D,
+ 'ASYNC_TEX_IMAGE_SGIX': 0x835C,
+ 'ASYNC_DRAW_PIXELS_SGIX': 0x835D,
+ 'ASYNC_READ_PIXELS_SGIX': 0x835E,
+ 'MAX_ASYNC_TEX_IMAGE_SGIX': 0x835F,
+ 'MAX_ASYNC_DRAW_PIXELS_SGIX': 0x8360,
+ 'MAX_ASYNC_READ_PIXELS_SGIX': 0x8361,
+ 'ALPHA_MIN_SGIX': 0x8320,
+ 'ALPHA_MAX_SGIX': 0x8321,
+ 'CONVOLUTION_HINT_SGIX': 0x8316,
+ 'DEPTH_COMPONENT16_SGIX': 0x81A5,
+ 'DEPTH_COMPONENT24_SGIX': 0x81A6,
+ 'DEPTH_COMPONENT32_SGIX': 0x81A7,
+ 'FOG_OFFSET_SGIX': 0x8198,
+ 'FOG_OFFSET_VALUE_SGIX': 0x8199,
+ 'INTERLACE_SGIX': 0x8094,
+ 'PACK_RESAMPLE_SGIX': 0x842E,
+ 'UNPACK_RESAMPLE_SGIX': 0x842F,
+ 'RESAMPLE_DECIMATE_SGIX': 0x8430,
+ 'RESAMPLE_REPLICATE_SGIX': 0x8433,
+ 'RESAMPLE_ZERO_FILL_SGIX': 0x8434,
+ 'TEXTURE_COMPARE_SGIX': 0x819A,
+ 'TEXTURE_COMPARE_OPERATOR_SGIX': 0x819B,
+ 'TEXTURE_LEQUAL_R_SGIX': 0x819C,
+ 'TEXTURE_GEQUAL_R_SGIX': 0x819D,
+ 'SHADOW_AMBIENT_SGIX': 0x80BF,
+ 'TEXTURE_MAX_CLAMP_S_SGIX': 0x8369,
+ 'TEXTURE_MAX_CLAMP_T_SGIX': 0x836A,
+ 'TEXTURE_MAX_CLAMP_R_SGIX': 0x836B,
+ 'TEXTURE_MULTI_BUFFER_HINT_SGIX': 0x812E,
+ 'RGB_SIGNED_SGIX': 0x85E0,
+ 'RGBA_SIGNED_SGIX': 0x85E1,
+ 'ALPHA_SIGNED_SGIX': 0x85E2,
+ 'LUMINANCE_SIGNED_SGIX': 0x85E3,
+ 'INTENSITY_SIGNED_SGIX': 0x85E4,
+ 'LUMINANCE_ALPHA_SIGNED_SGIX': 0x85E5,
+ 'RGB16_SIGNED_SGIX': 0x85E6,
+ 'RGBA16_SIGNED_SGIX': 0x85E7,
+ 'ALPHA16_SIGNED_SGIX': 0x85E8,
+ 'LUMINANCE16_SIGNED_SGIX': 0x85E9,
+ 'INTENSITY16_SIGNED_SGIX': 0x85EA,
+ 'LUMINANCE16_ALPHA16_SIGNED_SGIX': 0x85EB,
+ 'RGB_EXTENDED_RANGE_SGIX': 0x85EC,
+ 'RGBA_EXTENDED_RANGE_SGIX': 0x85ED,
+ 'ALPHA_EXTENDED_RANGE_SGIX': 0x85EE,
+ 'LUMINANCE_EXTENDED_RANGE_SGIX': 0x85EF,
+ 'INTENSITY_EXTENDED_RANGE_SGIX': 0x85F0,
+ 'LUMINANCE_ALPHA_EXTENDED_RANGE_SGIX': 0x85F1,
+ 'RGB16_EXTENDED_RANGE_SGIX': 0x85F2,
+ 'RGBA16_EXTENDED_RANGE_SGIX': 0x85F3,
+ 'ALPHA16_EXTENDED_RANGE_SGIX': 0x85F4,
+ 'LUMINANCE16_EXTENDED_RANGE_SGIX': 0x85F5,
+ 'INTENSITY16_EXTENDED_RANGE_SGIX': 0x85F6,
+ 'LUMINANCE16_ALPHA16_EXTENDED_RANGE_SGIX': 0x85F7,
+ 'MIN_LUMINANCE_SGIS': 0x85F8,
+ 'MAX_LUMINANCE_SGIS': 0x85F9,
+ 'MIN_INTENSITY_SGIS': 0x85FA,
+ 'MAX_INTENSITY_SGIS': 0x85FB,
+ 'POST_TEXTURE_FILTER_BIAS_SGIX': 0x8179,
+ 'POST_TEXTURE_FILTER_SCALE_SGIX': 0x817A,
+ 'POST_TEXTURE_FILTER_BIAS_RANGE_SGIX': 0x817B,
+ 'POST_TEXTURE_FILTER_SCALE_RANGE_SGIX': 0x817C,
+ 'VERTEX_PRECLIP_SGIX': 0x83EE,
+ 'VERTEX_PRECLIP_HINT_SGIX': 0x83EF,
+ 'VERTEX_PRECLIP_SGIX': 0x83EE,
+ 'VERTEX_PRECLIP_HINT_SGIX': 0x83EF,
+ 'COLOR_MATRIX_SGI': 0x80B1,
+ 'COLOR_MATRIX_STACK_DEPTH_SGI': 0x80B2,
+ 'MAX_COLOR_MATRIX_STACK_DEPTH_SGI': 0x80B3,
+ 'POST_COLOR_MATRIX_RED_SCALE_SGI': 0x80B4,
+ 'POST_COLOR_MATRIX_GREEN_SCALE_SGI': 0x80B5,
+ 'POST_COLOR_MATRIX_BLUE_SCALE_SGI': 0x80B6,
+ 'POST_COLOR_MATRIX_ALPHA_SCALE_SGI': 0x80B7,
+ 'POST_COLOR_MATRIX_RED_BIAS_SGI': 0x80B8,
+ 'POST_COLOR_MATRIX_GREEN_BIAS_SGI': 0x80B9,
+ 'POST_COLOR_MATRIX_BLUE_BIAS_SGI': 0x80BA,
+ 'POST_COLOR_MATRIX_ALPHA_BIAS_SGI': 0x80BB,
+ 'COLOR_TABLE_SGI': 0x80D0,
+ 'POST_CONVOLUTION_COLOR_TABLE_SGI': 0x80D1,
+ 'POST_COLOR_MATRIX_COLOR_TABLE_SGI': 0x80D2,
+ 'PROXY_COLOR_TABLE_SGI': 0x80D3,
+ 'PROXY_POST_CONVOLUTION_COLOR_TABLE_SGI': 0x80D4,
+ 'PROXY_POST_COLOR_MATRIX_COLOR_TABLE_SGI': 0x80D5,
+ 'COLOR_TABLE_SCALE_SGI': 0x80D6,
+ 'COLOR_TABLE_BIAS_SGI': 0x80D7,
+ 'COLOR_TABLE_FORMAT_SGI': 0x80D8,
+ 'COLOR_TABLE_WIDTH_SGI': 0x80D9,
+ 'COLOR_TABLE_RED_SIZE_SGI': 0x80DA,
+ 'COLOR_TABLE_GREEN_SIZE_SGI': 0x80DB,
+ 'COLOR_TABLE_BLUE_SIZE_SGI': 0x80DC,
+ 'COLOR_TABLE_ALPHA_SIZE_SGI': 0x80DD,
+ 'COLOR_TABLE_LUMINANCE_SIZE_SGI': 0x80DE,
+ 'COLOR_TABLE_INTENSITY_SIZE_SGI': 0x80DF,
+ 'TEXTURE_COLOR_TABLE_SGI': 0x80BC,
+ 'PROXY_TEXTURE_COLOR_TABLE_SGI': 0x80BD,
+ 'UNPACK_CONSTANT_DATA_SUNX': 0x81D5,
+ 'TEXTURE_CONSTANT_DATA_SUNX': 0x81D6,
+ 'WRAP_BORDER_SUN': 0x81D4,
+ 'GLOBAL_ALPHA_SUN': 0x81D9,
+ 'GLOBAL_ALPHA_FACTOR_SUN': 0x81DA,
+ 'QUAD_MESH_SUN': 0x8614,
+ 'TRIANGLE_MESH_SUN': 0x8615,
+ 'SLICE_ACCUM_SUN': 0x85CC,
+ 'RESTART_SUN': 0x01,
+ 'REPLACE_MIDDLE_SUN': 0x02,
+ 'REPLACE_OLDEST_SUN': 0x03,
+ 'TRIANGLE_LIST_SUN': 0x81D7,
+ 'REPLACEMENT_CODE_SUN': 0x81D8,
+ 'REPLACEMENT_CODE_ARRAY_SUN': 0x85C0,
+ 'REPLACEMENT_CODE_ARRAY_TYPE_SUN': 0x85C1,
+ 'REPLACEMENT_CODE_ARRAY_STRIDE_SUN': 0x85C2,
+ 'REPLACEMENT_CODE_ARRAY_POINTER_SUN': 0x85C3,
+ 'R1UI_V3F_SUN': 0x85C4,
+ 'R1UI_C4UB_V3F_SUN': 0x85C5,
+ 'R1UI_C3F_V3F_SUN': 0x85C6,
+ 'R1UI_N3F_V3F_SUN': 0x85C7,
+ 'R1UI_C4F_N3F_V3F_SUN': 0x85C8,
+ 'R1UI_T2F_V3F_SUN': 0x85C9,
+ 'R1UI_T2F_N3F_V3F_SUN': 0x85CA,
+ 'R1UI_T2F_C4F_N3F_V3F_SUN': 0x85CB,
+ 'PHONG_WIN': 0x80EA,
+ 'PHONG_HINT_WIN': 0x80EB,
+ 'PROGRAM_BINARY_RETRIEVABLE_HINT': 0x8257,
+ 'PROGRAM_BINARY_LENGTH': 0x8741,
+ 'PROGRAM_BINARY_FORMATS': 0x87FE,
+ 'NUM_PROGRAM_BINARY_FORMATS': 0x87FF,
+ 'PRIMITIVE_RESTART_FIXED_INDEX': 0x8D69,
+ 'FOG_SPECULAR_TEXTURE_WIN': 0x80EC
+};
diff --git a/dom/canvas/test/webgl-conf/checkout/js/glsl-conformance-test.js b/dom/canvas/test/webgl-conf/checkout/js/glsl-conformance-test.js
new file mode 100644
index 0000000000..12a056ce21
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/js/glsl-conformance-test.js
@@ -0,0 +1,424 @@
+/*
+Copyright (c) 2019 The Khronos Group Inc.
+Use of this source code is governed by an MIT-style license that can be
+found in the LICENSE.txt file.
+*/
+GLSLConformanceTester = (function(){
+
+var wtu = WebGLTestUtils;
+var defaultVertexShader = [
+ "attribute vec4 vPosition;",
+ "void main()",
+ "{",
+ " gl_Position = vPosition;",
+ "}"
+].join('\n');
+
+var defaultFragmentShader = [
+ "precision mediump float;",
+ "void main()",
+ "{",
+ " gl_FragColor = vec4(1.0,0.0,0.0,1.0);",
+ "}"
+].join('\n');
+
+var defaultESSL3VertexShader = [
+ "#version 300 es",
+ "in vec4 vPosition;",
+ "void main()",
+ "{",
+ " gl_Position = vPosition;",
+ "}"
+].join('\n');
+
+var defaultESSL3FragmentShader = [
+ "#version 300 es",
+ "precision mediump float;",
+ "out vec4 my_FragColor;",
+ "void main()",
+ "{",
+ " my_FragColor = vec4(1.0,0.0,0.0,1.0);",
+ "}"
+].join('\n');
+
+function log(msg) {
+ bufferedLogToConsole(msg);
+}
+
+var vShaderDB = {};
+var fShaderDB = {};
+
+/**
+ * The info parameter should contain the following keys. Note that you may leave
+ * the parameters for one shader out, in which case the default shader will be
+ * used.
+ * vShaderSource: the source code for vertex shader
+ * vShaderId: id of an element containing vertex shader source code. Used if
+ * vShaderSource is not specified.
+ * vShaderSuccess: true if vertex shader compilation should
+ * succeed.
+ * fShaderSource: the source code for fragment shader
+ * fShaderId: id of an element containing fragment shader source code. Used if
+ * fShaderSource is not specified.
+ * fShaderSuccess: true if fragment shader compilation should
+ * succeed.
+ * linkSuccess: true if link should succeed
+ * passMsg: msg to describe success condition.
+ * render: if true render to unit quad. Green = success
+ * uniforms: an array of objects specifying uniforms to set prior to rendering.
+ * Each object should have the following keys:
+ * name: uniform variable name in the shader source. Uniform location will
+ * be queried based on its name.
+ * functionName: name of the function used to set the uniform. For example:
+ * 'uniform1i'
+ * value: value of the uniform to set.
+ */
+function runOneTest(gl, info) {
+ var passMsg = info.passMsg
+ debug("");
+ debug("test: " + passMsg);
+
+ var consoleDiv = document.getElementById("console");
+
+ var vIsDefault = false;
+ var fIsDefault = false;
+
+ if (info.vShaderSource === undefined) {
+ if (info.vShaderId) {
+ info.vShaderSource = document.getElementById(info.vShaderId).text;
+ } else {
+ vIsDefault = true;
+ }
+ }
+ if (info.fShaderSource === undefined) {
+ if (info.fShaderId) {
+ info.fShaderSource = document.getElementById(info.fShaderId).text;
+ } else {
+ fIsDefault = true;
+ }
+ }
+
+ var vLabel = (vIsDefault ? "default" : "test") + " vertex shader";
+ var fLabel = (fIsDefault ? "default" : "test") + " fragment shader";
+ if (vIsDefault) {
+ info.vShaderSource = defaultVertexShader;
+ info.vShaderSuccess = true;
+ }
+ if (fIsDefault) {
+ info.fShaderSource = defaultFragmentShader;
+ info.fShaderSuccess = true;
+ }
+
+ if (vIsDefault != fIsDefault) {
+ // The language version of the default shader is chosen
+ // according to the language version of the other shader.
+ // We rely on "#version 300 es" being in this usual format.
+ // It must be on the first line of the shader according to the spec.
+ if (fIsDefault) {
+ // If we're using the default fragment shader, we need to make sure that
+ // it's language version matches with the vertex shader.
+ if (info.vShaderSource.split('\n')[0] == '#version 300 es') {
+ info.fShaderSource = defaultESSL3FragmentShader;
+ }
+ } else {
+ // If we're using the default vertex shader, we need to make sure that
+ // it's language version matches with the fragment shader.
+ if (info.fShaderSource.split('\n')[0] == '#version 300 es') {
+ info.vShaderSource = defaultESSL3VertexShader;
+ }
+ }
+ }
+
+ var vSource = info.vShaderPrep ? info.vShaderPrep(info.vShaderSource) :
+ info.vShaderSource;
+
+ if (!quietMode()) {
+ wtu.addShaderSource(consoleDiv, vLabel, vSource);
+ }
+
+ // Reuse identical shaders so we test shared shader.
+ var vShader = vShaderDB[vSource];
+ if (!vShader) {
+ // loadShader, with opt_skipCompileStatus: true.
+ vShader = wtu.loadShader(gl, vSource, gl.VERTEX_SHADER, null, null, null, null, true);
+ let compiledVShader = vShader;
+ if (vShader && !gl.getShaderParameter(vShader, gl.COMPILE_STATUS)) {
+ compiledVShader = null;
+ }
+ if (info.vShaderTest) {
+ if (!info.vShaderTest(compiledVShader)) {
+ testFailed("[vertex shader test] " + passMsg);
+ return;
+ }
+ }
+ // As per GLSL 1.0.17 10.27 we can only check for success on
+ // compileShader, not failure.
+ if (!info.ignoreResults && info.vShaderSuccess && !compiledVShader) {
+ testFailed("[unexpected vertex shader compile status] (expected: " +
+ info.vShaderSuccess + ") " + passMsg);
+ if (!quietMode() && vShader) {
+ const info = gl.getShaderInfoLog(vShader);
+ wtu.addShaderSource(consoleDiv, vLabel + " info log", info);
+ }
+ }
+ // Save the shaders so we test shared shader.
+ if (compiledVShader) {
+ vShaderDB[vSource] = compiledVShader;
+ } else {
+ vShader = null;
+ }
+ }
+
+ var debugShaders = gl.getExtension('WEBGL_debug_shaders');
+ if (debugShaders && vShader && !quietMode()) {
+ wtu.addShaderSource(consoleDiv, vLabel + " translated for driver",
+ debugShaders.getTranslatedShaderSource(vShader));
+ }
+
+ var fSource = info.fShaderPrep ? info.fShaderPrep(info.fShaderSource) :
+ info.fShaderSource;
+
+ if (!quietMode()) {
+ wtu.addShaderSource(consoleDiv, fLabel, fSource);
+ }
+
+ // Reuse identical shaders so we test shared shader.
+ var fShader = fShaderDB[fSource];
+ if (!fShader) {
+ // loadShader, with opt_skipCompileStatus: true.
+ fShader = wtu.loadShader(gl, fSource, gl.FRAGMENT_SHADER, null, null, null, null, true);
+ let compiledFShader = fShader;
+ if (fShader && !gl.getShaderParameter(fShader, gl.COMPILE_STATUS)) {
+ compiledFShader = null;
+ }
+ if (info.fShaderTest) {
+ if (!info.fShaderTest(compiledFShader)) {
+ testFailed("[fragment shader test] " + passMsg);
+ return;
+ }
+ }
+ //debug(fShader == null ? "fail" : "succeed");
+ // As per GLSL 1.0.17 10.27 we can only check for success on
+ // compileShader, not failure.
+ if (!info.ignoreResults && info.fShaderSuccess && !compiledFShader) {
+ testFailed("[unexpected fragment shader compile status] (expected: " +
+ info.fShaderSuccess + ") " + passMsg);
+ if (!quietMode() && fShader) {
+ const info = gl.getShaderInfoLog(fShader);
+ wtu.addShaderSource(consoleDiv, fLabel + " info log", info);
+ }
+ return;
+ }
+
+ // Safe the shaders so we test shared shader.
+ if (compiledFShader) {
+ fShaderDB[fSource] = compiledFShader;
+ } else {
+ fShader = null;
+ }
+ }
+
+ if (debugShaders && fShader && !quietMode()) {
+ wtu.addShaderSource(consoleDiv, fLabel + " translated for driver",
+ debugShaders.getTranslatedShaderSource(fShader));
+ }
+
+ if (vShader && fShader) {
+ var program = gl.createProgram();
+ gl.attachShader(program, vShader);
+ gl.attachShader(program, fShader);
+
+ if (vSource.indexOf("vPosition") >= 0) {
+ gl.bindAttribLocation(program, 0, "vPosition");
+ }
+ if (vSource.indexOf("texCoord0") >= 0) {
+ gl.bindAttribLocation(program, 1, "texCoord0");
+ }
+ gl.linkProgram(program);
+ var linked = (gl.getProgramParameter(program, gl.LINK_STATUS) != 0);
+ if (!linked) {
+ var error = gl.getProgramInfoLog(program);
+ log("*** Error linking program '"+program+"':"+error);
+ }
+ if (!info.ignoreResults && linked != info.linkSuccess) {
+ testFailed("[unexpected link status] (expected: " +
+ info.linkSuccess + ") " + passMsg);
+ return;
+ }
+ } else {
+ if (!info.ignoreResults && info.linkSuccess) {
+ testFailed("[link failed] " + passMsg);
+ return;
+ }
+ }
+
+ if (parseInt(wtu.getUrlOptions().dumpShaders)) {
+ var vInfo = {
+ shader: vShader,
+ shaderSuccess: info.vShaderSuccess,
+ label: vLabel,
+ source: vSource
+ };
+ var fInfo = {
+ shader: fShader,
+ shaderSuccess: info.fShaderSuccess,
+ label: fLabel,
+ source: fSource
+ };
+ wtu.dumpShadersInfo(gl, window.location.pathname, passMsg, vInfo, fInfo);
+ }
+
+ if (!info.render) {
+ testPassed(passMsg);
+ return;
+ }
+
+ gl.useProgram(program);
+
+ if (info.uniforms !== undefined) {
+ for (var i = 0; i < info.uniforms.length; ++i) {
+ var uniform = info.uniforms[i];
+ var uniformLocation = gl.getUniformLocation(program, uniform.name);
+ if (uniformLocation !== null) {
+ if (uniform.functionName.includes("Matrix")) {
+ gl[uniform.functionName](uniformLocation, false, uniform.value);
+ } else {
+ gl[uniform.functionName](uniformLocation, uniform.value);
+ }
+ debug(uniform.name + ' set to ' + uniform.value);
+ } else {
+ debug('uniform ' + uniform.name + ' had null location and was not set');
+ }
+ }
+ }
+
+ if (info.uniformBlocks !== undefined) {
+ for (var i = 0; i < info.uniformBlocks.length; ++i) {
+ var uniformBlockIndex = gl.getUniformBlockIndex(program, info.uniformBlocks[i].name);
+ if (uniformBlockIndex !== null) {
+ gl.uniformBlockBinding(program, uniformBlockIndex, i);
+ debug(info.uniformBlocks[i].name + ' (index ' + uniformBlockIndex + ') bound to slot ' + i);
+
+ var uboValueBuffer = gl.createBuffer();
+ gl.bindBufferBase(gl.UNIFORM_BUFFER, i, uboValueBuffer);
+ gl.bufferData(gl.UNIFORM_BUFFER, info.uniformBlocks[i].value, info.uniformBlocks[i].usage || gl.STATIC_DRAW);
+ } else {
+ debug('uniform block' + info.uniformBlocks[i].name + ' had null block index and was not set');
+ }
+ }
+ }
+
+ wtu.setupUnitQuad(gl);
+ wtu.clearAndDrawUnitQuad(gl);
+
+ var div = document.createElement("div");
+ div.className = "testimages";
+ wtu.insertImage(div, "result", wtu.makeImageFromCanvas(gl.canvas));
+ div.appendChild(document.createElement('br'));
+ consoleDiv.appendChild(div);
+
+ var tolerance = 0;
+ if (info.renderTolerance !== undefined) {
+ tolerance = info.renderTolerance;
+ }
+ if (info.renderColor !== undefined) {
+ wtu.checkCanvas(gl, info.renderColor, "should be expected color " + info.renderColor, tolerance);
+ } else {
+ wtu.checkCanvas(gl, [0, 255, 0, 255], "should be green", tolerance);
+ }
+}
+
+function runTests(shaderInfos, opt_contextVersion) {
+ var wtu = WebGLTestUtils;
+ var canvas = document.createElement('canvas');
+ canvas.width = 32;
+ canvas.height = 32;
+ var gl = wtu.create3DContext(canvas, undefined, opt_contextVersion);
+ if (!gl) {
+ testFailed("context does not exist");
+ finishTest();
+ return;
+ }
+
+ for (var i = 0; i < shaderInfos.length; i++) {
+ runOneTest(gl, shaderInfos[i]);
+ }
+
+ finishTest();
+};
+
+function getSource(elem) {
+ var str = elem.text;
+ return str.replace(/^\s*/, '').replace(/\s*$/, '');
+}
+
+function getPassMessage(source) {
+ var lines = source.split('\n');
+ return lines[0].substring(3);
+}
+
+function getSuccess(msg) {
+ if (msg.indexOf("fail") >= 0) {
+ return false;
+ }
+ if (msg.indexOf("succeed") >= 0) {
+ return true;
+ }
+ testFailed("bad test description. Must have 'fail' or 'succeed'");
+}
+
+function setupTest() {
+ var info = {};
+
+ var vShaderElem = document.getElementById('vertexShader');
+ if (vShaderElem) {
+ info.vShaderSource = getSource(vShaderElem);
+ info.passMsg = getPassMessage(info.vShaderSource);
+ info.vShaderSuccess = getSuccess(info.passMsg);
+ }
+
+ var fShaderElem = document.getElementById('fragmentShader');
+ if (fShaderElem) {
+ info.fShaderSource = getSource(fShaderElem);
+ info.passMsg = getPassMessage(info.fShaderSource);
+ info.fShaderSuccess = getSuccess(info.passMsg);
+ }
+
+ // linkSuccess should be true if shader success value is undefined or true for both shaders.
+ info.linkSuccess = info.vShaderSuccess !== false && info.fShaderSuccess !== false;
+
+ if (info.passMsg === undefined) {
+ testFailed("no test shader found.");
+ finishTest();
+ return;
+ }
+
+ return info;
+}
+
+function runTest() {
+ var info = setupTest();
+ description(info.passMsg);
+ runTests([info]);
+}
+
+function runRenderTests(tests, opt_contextVersion) {
+ for (var ii = 0; ii < tests.length; ++ii) {
+ tests[ii].render = true
+ }
+ runTests(tests, opt_contextVersion);
+}
+
+function runRenderTest() {
+ var info = setupTest();
+ description(info.passMsg);
+ runRenderTests([info]);
+}
+
+return {
+ runTest: runTest,
+ runTests: runTests,
+ runRenderTest: runRenderTest,
+ runRenderTests: runRenderTests
+};
+}());
diff --git a/dom/canvas/test/webgl-conf/checkout/js/glsl-constructor-tests-generator.js b/dom/canvas/test/webgl-conf/checkout/js/glsl-constructor-tests-generator.js
new file mode 100644
index 0000000000..b5c1602980
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/js/glsl-constructor-tests-generator.js
@@ -0,0 +1,919 @@
+/*
+Copyright (c) 2019 The Khronos Group Inc.
+Use of this source code is governed by an MIT-style license that can be
+found in the LICENSE.txt file.
+*/
+
+
+var GLSLConstructorTestsGenerator = (function() {
+
+var wtu = WebGLTestUtils;
+
+// Shader code templates
+var constructorVertexTemplate = [
+ "attribute vec4 vPosition;",
+
+ "precision mediump int;",
+ "precision mediump float;",
+
+ // Colors used to signal correctness of component values comparison
+ "const vec4 green = vec4(0.0, 1.0, 0.0, 1.0);",
+ "const vec4 red = vec4(1.0, 0.0, 0.0, 1.0);",
+
+ // Error bound used in comparison of floating point values
+ "$(errorBound)",
+
+ "varying vec4 vColor;",
+
+ "void main() {",
+ " $(argsList)",
+
+ " $(type) v = $(type)($(argsConstr));",
+
+ " if ($(checkCompVals))",
+ " vColor = green;",
+ " else",
+ " vColor = red;",
+
+ " gl_Position = vPosition;",
+ "}"
+].join("\n");
+
+
+var passThroughColorFragmentShader = [
+ "precision mediump float;",
+
+ "varying vec4 vColor;",
+
+ "void main() {",
+ " gl_FragColor = vColor;",
+ "}"
+].join('\n');
+
+
+var constructorFragmentTemplate = [
+ "precision mediump int;",
+ "precision mediump float;",
+
+ // Colors used to signal correctness of component values comparison
+ "const vec4 green = vec4(0.0, 1.0, 0.0, 1.0); ",
+ "const vec4 red = vec4(1.0, 0.0, 0.0, 1.0); ",
+
+ // Error bound used in comparison of floating point values
+ "$(errorBound)",
+
+ "void main() {",
+ " $(argsList)",
+
+ " $(type) v = $(type)($(argsConstr));",
+
+ " if ($(checkCompVals))",
+ " gl_FragColor = green;",
+ " else",
+ " gl_FragColor = red;",
+ "}"
+].join("\n");
+
+
+// Coding of the different argument types
+// s : scalar
+// v2 : vec2
+// v3 : vec3
+// v4 : vec4
+// m2 : mat2
+// m3 : mat3
+// m4 : mat4
+
+// Returns the dimensions of the type
+// Count of columns, count of rows
+function getTypeCodeDimensions(typeCode) {
+ switch (typeCode) {
+ case "s": return [1, 1];
+ case "v2": return [1, 2];
+ case "v3": return [1, 3];
+ case "v4": return [1, 4];
+ case "m2": return [2, 2];
+ case "m3": return [3, 3];
+ case "m4": return [4, 4];
+
+ default:
+ wtu.error("GLSLConstructorTestsGenerator.getTypeCodeDimensions(), unknown type code");
+ debugger;
+ }
+};
+
+
+// Returns the component count for the type code
+function getTypeCodeComponentCount(typeCode) {
+ var dim = getTypeCodeDimensions(typeCode);
+
+ return dim[0] * dim[1];
+}
+
+
+// Returns glsl name of type code
+function getGLSLBaseTypeName(typeCode) {
+ switch(typeCode) {
+ case "s": return "";
+ case "v2": return "vec2";
+ case "v3": return "vec3";
+ case "v4": return "vec4";
+ case "m2": return "mat2";
+ case "m3": return "mat3";
+ case "m4": return "mat4";
+
+ default:
+ wtu.error("GLSLConstructorTestsGenerator.getGLSLBaseTypeName(), unknown type code");
+ debugger;
+ }
+}
+
+
+// Returns the scalar glsl type name related to the structured type
+function getGLSLScalarType(targetType) {
+ switch(targetType[0]) {
+ case 'i': return "int";
+ case 'b': return "bool";
+
+ case 'v':
+ case 'm':
+ return "float";
+
+ default:
+ wtu.error("GLSLConstructorTestsGenerator.getGLSLScalarType(), unknown target type");
+ debugger;
+ }
+}
+
+
+// Returns the scalar prefix for the associated scalar type
+function getGLSLScalarPrefix(targetType) {
+ switch(targetType[0]) {
+ case 'i':
+ case 'b':
+ return targetType[0];
+
+ case 'v':
+ case 'm':
+ return '';
+
+ default:
+ wtu.error("GLSLConstructorTestsGenerator.getGLSLScalarPrefix(), unknown target type");
+ debugger;
+ }
+}
+
+
+// Returns the type for a specified target type and argument type code
+function getGLSLArgumentType(typeCode, targetType) {
+ var baseType = getGLSLBaseTypeName(typeCode);
+ if (baseType !== "") {
+ if (typeCode[0] === "v") {
+ // Vectors come in different flavours
+ return getGLSLScalarPrefix(targetType) + baseType;
+ }
+ else
+ return baseType;
+ }
+ else
+ return getGLSLScalarType(targetType);
+}
+
+
+// Returns the glsl type of the argument components
+function getGLSLArgumentComponentType(argTypeCode, targetType) {
+ var scalarType;
+
+ if (argTypeCode[0] === "m") {
+ // Matrices are always floats
+ scalarType = "float";
+ }
+ else
+ scalarType = getGLSLScalarType(targetType);
+
+ return scalarType;
+}
+
+
+function getGLSLColumnSize(targetType) {
+ colSize = parseInt(targetType.slice(-1));
+
+ if (!isNaN(colSize))
+ return colSize;
+
+ wtu.error("GLSLConstructorTestsGenerator.getGLSLColumnSize(), invalid target type");
+ debugger;
+}
+
+
+// Returns correct string representation of scalar value
+function getScalarTypeValStr(val, scalarType) {
+ if (val == null)
+ debugger;
+
+ switch (scalarType) {
+ case "float": return val.toFixed(1);
+ case "int": return val;
+ case "bool": return (val === 0) ? "false" : "true";
+
+ default:
+ wtu.error("GLSLConstructorTestsGenerator.getScalarTypeValStr(), unknown scalar type");
+ debugger;
+ }
+}
+
+
+// Returns true if the glsl type name is a matrix
+function isGLSLTypeMatrix(type) {
+ return (type.indexOf("mat") !== -1);
+}
+
+
+// Returns true if the glsl type name is a vector
+function isGLSLTypeVector(type) {
+ return (type.indexOf("vec") !== -1);
+}
+
+
+// Returns the count of components
+function getGLSLTypeComponentCount(type) {
+ var colSize = getGLSLColumnSize(type);
+
+ if (isGLSLTypeMatrix(type))
+ return colSize * colSize;
+ else
+ return colSize;
+}
+
+
+// Returns the constructor expression with the components set to a sequence of scalar values
+// Like vec3(1.0, 2.0, 3.0)
+function getComponentSequenceConstructorExpression(typeCode, firstCompValue, targetType) {
+ var scalarType = getGLSLArgumentComponentType(typeCode, targetType);
+
+ if (typeCode === "s") {
+ // Scalar
+ return getScalarTypeValStr(firstCompValue, scalarType) + ";";
+ }
+ else {
+ // Structured typeargTypeCode[0] === "m"
+ compCount = getTypeCodeComponentCount(typeCode);
+ var constrExpParts = new Array(compCount);
+ for (var aa = 0; aa < compCount; ++aa)
+ constrExpParts[aa] = getScalarTypeValStr(firstCompValue + aa, scalarType);
+
+ return getGLSLArgumentType(typeCode, targetType) + "(" + constrExpParts.join(", ") + ");";
+ }
+}
+
+
+// Returns the expression to select a component of the structured type
+function getComponentSelectorExpStr(targetType, compIx) {
+ if (isGLSLTypeMatrix(targetType)) {
+ var colRowIx = getColRowIndexFromLinearIndex(compIx, getGLSLColumnSize(targetType));
+ return "v[" + colRowIx.colIx + "][" + colRowIx.rowIx + "]";
+ }
+ else
+ return "v[" + compIx + "]";
+}
+
+
+// Returns expression which validates the components set by the constructor expression
+function getComponentValidationExpression(refCompVals, targetType) {
+ // Early out for invalid arguments
+ if (refCompVals.length === 0)
+ return "false";
+
+ var scalarType = getGLSLScalarType(targetType);
+ var checkComponentValueParts = new Array(refCompVals.length);
+ for (var cc = 0; cc < refCompVals.length; ++cc) {
+ var val_str = getScalarTypeValStr(refCompVals[cc], scalarType);
+ var comp_sel_exp = getComponentSelectorExpStr(targetType, cc);
+ if (scalarType === "float") {
+ // Comparison of floating point values with error bound
+ checkComponentValueParts[cc] = "abs(" + comp_sel_exp + " - " + val_str + ") <= errorBound";
+ }
+ else {
+ // Simple comparison to expected value
+ checkComponentValueParts[cc] = comp_sel_exp + " == " + val_str;
+ }
+ }
+
+ return checkComponentValueParts.join(" && ");
+}
+
+
+// Returns substitution parts to turn the shader template into testable shader code
+function getTestShaderParts(targetType, argExp, firstCompValue) {
+ // glsl code of declarations of arguments
+ var argsListParts = new Array(argExp.length);
+
+ // glsl code of constructor expression
+ var argsConstrParts = new Array(argExp.length);
+
+ // glsl type expression
+ var typeExpParts = new Array(argExp.length);
+ for (var aa = 0; aa < argExp.length; ++aa) {
+ var typeCode = argExp[aa];
+ var argCompCount = getTypeCodeComponentCount(typeCode);
+ var argName = "a" + aa;
+ var argType = getGLSLArgumentType(typeCode, targetType);
+ var argConstrExp = argType + " " + argName + " = " + getComponentSequenceConstructorExpression(typeCode, firstCompValue, targetType);
+
+ // Add construction of one argument
+ // Indent if not first argument
+ argsListParts[aa] = ((aa > 0) ? " " : "") + argConstrExp;
+
+ // Add argument name to target type argument list
+ argsConstrParts[aa] = argName;
+
+ // Add type name to type expression
+ typeExpParts[aa] = argType;
+
+ // Increment argument component value so all argument component arguments have a unique value
+ firstCompValue += argCompCount;
+ }
+
+ return {
+ argsList: argsListParts.join("\n") + "\n",
+ argsConstr: argsConstrParts.join(", "),
+ typeExp: targetType + "(" + typeExpParts.join(", ") + ")"
+ };
+}
+
+
+// Utility functions to manipulate the array of reference values
+
+// Returns array filled with identical values
+function getArrayWithIdenticalValues(size, val) {
+ var matArray = new Array(size);
+ for (var aa = 0; aa < size; ++aa)
+ matArray[aa] = val;
+
+ return matArray;
+}
+
+
+// Returns array filled with increasing values from a specified start value
+function getArrayWithIncreasingValues(size, start) {
+ var matArray = new Array(size);
+ for (var aa = 0; aa < size; ++aa)
+ matArray[aa] = start + aa;
+
+ return matArray;
+}
+
+
+// Utility functions to manipulate the array of reference values if the target type is a matrix
+
+// Returns an array which is the column order layout of a square matrix where the diagonal is set to a specified value
+function matCompArraySetDiagonal(matArray, diagVal) {
+ // The entries for the diagonal start at array index 0 and increase
+ // by column size + 1
+ var colSize = Math.round(Math.sqrt(matArray.length));
+ var dIx = 0;
+ do {
+ matArray[dIx] = diagVal;
+ dIx += (colSize + 1);
+ }
+ while (dIx < colSize * colSize);
+
+ return matArray;
+}
+
+
+// Returns an array which contains the values of an identity matrix read out in column order
+function matCompArrayCreateDiagonalMatrix(colSize, diagVal) {
+ var size = colSize * colSize;
+ var matArray = new Array(size);
+ for (var aa = 0; aa < size; ++aa)
+ matArray[aa] = 0;
+
+ return matCompArraySetDiagonal(matArray, diagVal);
+}
+
+
+// Returns the column and row index from the linear index if the components of the matrix are stored in column order in an array
+// in a one dimensional array in column order
+function getColRowIndexFromLinearIndex(linIx, colSize) {
+ return {
+ colIx: Math.floor(linIx / colSize),
+ rowIx: linIx % colSize
+ };
+}
+
+
+// Returns the linear index for matrix column and row index for a specified matrix size
+function getLinearIndexFromColRowIndex(rowColIx, colSize) {
+ return rowColIx.colIx * colSize + rowColIx.rowIx;
+}
+
+
+// Returns a matrix set from another matrix
+function matCompArraySetMatrixFromMatrix(dstColSize, srcMatArray) {
+ // Overwrite components from destination with the source component values at the same col, row coordinates
+ var dstMatArray = matCompArrayCreateDiagonalMatrix(dstColSize, 1);
+
+ var srcColSize = Math.round(Math.sqrt(srcMatArray.length));
+
+ for (var c_ix = 0; c_ix < srcMatArray.length; ++c_ix) {
+ var srcMatIx = getColRowIndexFromLinearIndex(c_ix, srcColSize);
+ if (srcMatIx.colIx < dstColSize && srcMatIx.rowIx < dstColSize) {
+ // Source matrix coordinates are valid destination matrix coordinates
+ dstMatArray[getLinearIndexFromColRowIndex(srcMatIx, dstColSize)] = srcMatArray[c_ix];
+ }
+ }
+
+ return dstMatArray;
+}
+
+
+// Returns the glsl code to verify if the components are set correctly
+// and the message to display for the test
+function getConstructorExpressionInfo(targetType, argExp, firstCompValue) {
+ var argCompCountsSum = 0;
+ var argCompCounts = new Array(argExp.length);
+ for (var aa = 0; aa < argExp.length; ++aa) {
+ argCompCounts[aa] = getTypeCodeComponentCount(argExp[aa]);
+ argCompCountsSum += argCompCounts[aa];
+ }
+
+ var targetCompCount = getGLSLTypeComponentCount(targetType);
+
+ var refCompVals;
+ var testMsg;
+ var valid;
+
+ if (argCompCountsSum === 0) {
+ // A constructor needs at least one argument
+ refCompVals = [];
+ testMsg = "invalid (no arguments)";
+ valid = false;
+ }
+ else {
+ if (isGLSLTypeVector(targetType)) {
+ if (argCompCountsSum === 1) {
+ // One scalar argument
+ // Vector constructor with one scalar argument set all components to the same value
+ refCompVals = getArrayWithIdenticalValues(targetCompCount, firstCompValue);
+ testMsg = "valid (all components set to the same value)";
+ valid = true;
+ }
+ else {
+ // Not one scalar argument
+ if (argCompCountsSum < targetCompCount) {
+ // Not all components set
+ refCompVals = [];
+ testMsg = "invalid (not enough arguments)";
+ valid = false;
+ }
+ else {
+ // argCompCountsSum >= targetCompCount
+ // All components set
+ var lastArgFirstCompIx = argCompCountsSum - argCompCounts[argCompCounts.length - 1];
+
+ if (lastArgFirstCompIx < targetCompCount) {
+ // First component of last argument is used
+ refCompVals = getArrayWithIncreasingValues(targetCompCount, firstCompValue);
+ testMsg = "valid";
+ valid = true;
+ }
+ else {
+ // First component of last argument is not used
+ refCompVals = [];
+ testMsg = "invalid (unused argument)";
+ valid = false;
+ }
+ }
+ }
+ }
+ else {
+ // Matrix target type
+ if (argCompCountsSum === 1) {
+ // One scalar argument
+ // Matrix constructors with one scalar set all components on the diagonal to the same value
+ // All other components are set to zero
+ refCompVals = matCompArrayCreateDiagonalMatrix(Math.round(Math.sqrt(targetCompCount)), firstCompValue);
+ testMsg = "valid (diagonal components set to the same value, off-diagonal components set to zero)";
+ valid = true;
+ }
+ else {
+ // Not one scalar argument
+ if (argExp.length === 1 && argExp[0][0] === "m") {
+ // One single matrix argument
+ var dstColSize = getGLSLColumnSize(targetType);
+ refCompVals = matCompArraySetMatrixFromMatrix(dstColSize, getArrayWithIncreasingValues(getTypeCodeComponentCount(argExp[0]), firstCompValue));
+ testMsg = "valid, components at corresponding col, row indices are set from argument, other components are set from identity matrix";
+ valid = true;
+ }
+ else {
+ // More than one argument or one argument not of type matrix
+ // Can be treated in the same manner
+ // Arguments can not be of type matrix
+ var matFound = false;
+ for (var aa = 0; aa < argExp.length; ++aa)
+ if (argExp[aa][0] === "m")
+ matFound = true;
+
+ if (matFound) {
+ refCompVals = [];
+ testMsg = "invalid, argument list greater than one contains matrix type";
+ valid = false;
+ }
+ else {
+ if (argCompCountsSum < targetCompCount) {
+ refCompVals = [];
+ testMsg = "invalid (not enough arguments)";
+ valid = false;
+ }
+ else {
+ // argCompCountsSum >= targetCompCount
+ // All components set
+ var lastArgFirstCompIx = argCompCountsSum - argCompCounts[argCompCounts.length - 1];
+
+ if (lastArgFirstCompIx < targetCompCount) {
+ // First component of last argument is used
+ refCompVals = getArrayWithIncreasingValues(targetCompCount, firstCompValue);
+ testMsg = "valid";
+ valid = true;
+ }
+ else {
+ // First component of last argument is not used
+ refCompVals = [];
+ testMsg = "invalid (unused argument)";
+ valid = false;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // Check if no case is missed
+ if (testMsg == null || valid == null) {
+ wtu.error("GLSLConstructorTestsGenerator.getConstructorExpressionInfo(), info not set");
+ debugger;
+ }
+
+ return {
+ refCompVals: refCompVals,
+ testMsg: testMsg,
+ valid: valid
+ };
+}
+
+
+// Returns a vertex shader testcase and a fragment shader testcase
+function getVertexAndFragmentShaderTestCase(targetType, argExp) {
+ var firstCompValue = 0;
+ if (isGLSLTypeMatrix(targetType)) {
+ // Use value different from 0 and 1
+ // 0 and 1 are values used by matrix constructed from a matrix or a single scalar
+ firstCompValue = 2;
+ }
+
+ var argCode = getTestShaderParts (targetType, argExp, firstCompValue);
+ var expInfo = getConstructorExpressionInfo(targetType, argExp, firstCompValue);
+
+ var substitutions = {
+ type: targetType,
+ errorBound: (getGLSLScalarType(targetType) === "float") ? "const float errorBound = 1.0E-5;" : "",
+ argsList: argCode.argsList,
+ argsConstr: argCode.argsConstr,
+ checkCompVals: getComponentValidationExpression(expInfo.refCompVals, targetType)
+ };
+
+ return [ {
+ // Test constructor argument list in vertex shader
+ vShaderSource: wtu.replaceParams(constructorVertexTemplate, substitutions),
+ vShaderSuccess: expInfo.valid,
+ fShaderSource: passThroughColorFragmentShader,
+ fShaderSuccess: true,
+ linkSuccess: expInfo.valid,
+ passMsg: "Vertex shader : " + argCode.typeExp + ", " + expInfo.testMsg,
+ render: expInfo.valid
+ }, {
+ // Test constructor argument list in fragment shader
+ fShaderSource: wtu.replaceParams(constructorFragmentTemplate, substitutions),
+ fShaderSuccess: expInfo.valid,
+ linkSuccess: expInfo.valid,
+ passMsg: "Fragment shader : " + argCode.typeExp + ", " + expInfo.testMsg,
+ render: expInfo.valid
+ }
+ ];
+}
+
+
+// Incrementing the argument expressions
+// Utility object which defines the order of incrementing the argument types
+var typeCodeIncrementer = {
+ s: { typeCode: "v2", order: 0 },
+ v2: { typeCode: "v3", order: 1 },
+ v3: { typeCode: "v4", order: 2 },
+ v4: { typeCode: "m2", order: 3 },
+ m2: { typeCode: "m3", order: 4 },
+ m3: { typeCode: "m4", order: 5 },
+ m4: { typeCode: "s", order: 6 },
+ first: "s"
+}
+
+
+// Returns the next argument sequence
+function getNextArgumentSequence(inSeq) {
+ var nextSeq;
+ if (inSeq.length === 0) {
+ // Current argument sequence is empty, add first argument
+ nextSeq = [typeCodeIncrementer.first];
+ }
+ else {
+ nextSeq = new Array(inSeq.length);
+ var overflow = true;
+ for (var aa = 0; aa < inSeq.length; ++aa) {
+ var currArg = inSeq[aa];
+ if (overflow) {
+ // Increment the current argument type
+ var nextArg = typeCodeIncrementer[currArg].typeCode;
+ nextSeq[aa] = nextArg;
+ overflow = (nextArg === typeCodeIncrementer.first);
+ }
+ else {
+ // Copy remainder of sequence
+ nextSeq[aa] = currArg;
+ }
+ }
+
+ if (overflow) {
+ nextSeq.push(typeCodeIncrementer.first);
+ }
+ }
+
+ return nextSeq;
+}
+
+
+// Returns true if two argument expressions are equal
+function areArgExpEqual(expA, expB) {
+ if (expA.length !== expB.length)
+ return false;
+
+ for (var aa = 0; aa < expA.length; ++aa)
+ if (expA[aa] !== expB[aa])
+ return false;
+
+ return true;
+}
+
+
+// Returns true if first argument expression is smaller
+// (comes before the second one in iterating order)
+// compared to the second argument expression
+function isArgExpSmallerOrEqual(argExpA, argExpB) {
+ var aLen = argExpA.length;
+ var bLen = argExpB.length;
+ if (aLen !== bLen)
+ return (aLen < bLen);
+
+ // Argument type expression lengths are equal
+ for (var aa = aLen - 1; aa >= 0; --aa) {
+ var argA = argExpA[aa];
+ var argB = argExpB[aa];
+
+ if (argA !== argB) {
+ var aOrder = typeCodeIncrementer[argA].order;
+ var bOrder = typeCodeIncrementer[argB].order;
+ if (aOrder !== bOrder)
+ return (aOrder < bOrder);
+ }
+ }
+
+ // Argument type expressions are equal
+ return true;
+}
+
+
+// Returns the next argument expression from sequence set
+// Returns null if end is reached
+function getNextArgumentExpression(testExp, testSet) {
+ var testInterval = testSet[testExp.ix];
+
+ if (areArgExpEqual(testExp.argExp, testInterval[1])) {
+ // End of current interval reached
+ if (testExp.ix === testSet.length - 1) {
+ // End of set reached
+ return null;
+ }
+ else {
+ // Return first argument expression of next interval
+ var nextIx = testExp.ix + 1;
+ return { ix: nextIx, argExp: testSet[nextIx][0] };
+ }
+ }
+ else {
+ // Return next expression in current interval
+ return { ix: testExp.ix, argExp: getNextArgumentSequence(testExp.argExp) };
+ }
+}
+
+
+// Returns an array of the parts in the string separated by commas and with the white space trimmed
+function convertCsvToArray(str) {
+ // Checks type codes in input
+ function checkInput(el, ix, arr) {
+ var typeCode = el.trim();
+ if (!(typeCode in typeCodeIncrementer) && typeCode !== "first") {
+ wtu.error("GLSLConstructorTestsGenerator.convertCsvToArray(), unknown type code" + typeCode);
+ debugger;
+ }
+
+ arr[ix] = typeCode;
+ }
+
+ var spArr = str.split(",");
+
+ // Convert empty string to empty array
+ if (spArr.length === 1 && spArr[0].trim() === "")
+ spArr = [];
+
+ spArr.forEach(checkInput);
+
+ return spArr;
+}
+
+
+// Processes the set of specified test sequences
+function processInputs(testSequences) {
+ var testSet = new Array(testSequences.length);
+ for (var tt = 0; tt < testSequences.length; ++tt) {
+ var interval = testSequences[tt];
+ var bounds = interval.split("-");
+ var begin = convertCsvToArray(bounds[0]);
+ var end = convertCsvToArray(bounds[bounds.length - 1]);
+
+ // Check if interval is valid
+ if (!isArgExpSmallerOrEqual(begin, end)) {
+ wtu.error("GLSLConstructorTestsGenerator.processInputs(), interval not valid");
+ debugger;
+ }
+
+ testSet[tt] = [ begin, end ];
+ }
+
+ return testSet;
+}
+
+
+/**
+ * Returns list of test cases for vector types
+ * All combinations of arguments up to one unused argument of one component are tested
+ * @param {targetType} Name of target type to test the constructor expressions on
+ * @param {testSet} Set of intervals of argument sequences to test
+ */
+function getConstructorTests(targetType, testSequences) {
+ // List of tests to return
+ var testInfos = [];
+
+ // List of argument types
+ var testSet = processInputs(testSequences);
+ var testExp = { ix: 0, argExp: testSet[0][0] };
+
+ do {
+ // Add one vertex shader test case and one fragment shader test case
+ testInfos = testInfos.concat(getVertexAndFragmentShaderTestCase(targetType, testExp.argExp));
+
+ // Generate next argument expression
+ testExp = getNextArgumentExpression(testExp, testSet);
+ }
+ while (testExp != null);
+
+ return testInfos;
+}
+
+
+// Returns default test argument expression set
+// For details on input format : see bottom of file
+function getDefaultTestSet(targetType) {
+ switch(targetType) {
+ case "vec2":
+ case "ivec2":
+ case "bvec2":
+ return [
+ // No arguments and all single argument expressions
+ " - m4",
+
+ // All two argument expressions with a scalar as second argument
+ "s, s - m4, s",
+
+ // All two arguments expressions with a scalar as first argument
+ "s, v2", "s, v3", "s, v4", "s, m2", "s, m3", "s, m4",
+
+ // Three argument expression
+ "s, s, s"
+ ];
+
+ case "vec3":
+ case "ivec3":
+ case "bvec3":
+ return [
+ // No arguments and all single argument expressions
+ " - m4",
+
+ // All two argument expressions with a scalar as second argument
+ "s, s - m4, s",
+
+ // All two argument expressions with a scalar as first argument
+ "s, v2", "s, v3", "s, v4", "s, m2", "s, m3", "s, m4",
+
+ // All three argument expressions with two scalars as second and third argument
+ "s, s, s - m4, s, s",
+
+ // All three argument expressions with two scalars as first and second argument
+ "s, s, v2", "s, s, v3", "s, s, v4", "s, s, m2", "s, s, m3", "s, s, m4",
+
+ // Four argument expression
+ "s, s, s, s"
+ ];
+
+ case "vec4":
+ case "ivec4":
+ case "bvec4":
+ case "mat2":
+ return [
+ // No arguments and all single argument expressions
+ " - m4",
+
+ // All two argument expressions with a scalar as second argument
+ "s, s - m4, s",
+
+ // All two argument expressions with a scalar as first argument
+ "s, v2", "s, v3", "s, v4", "s, m2", "s, m3", "s, m4",
+
+ // All three argument expressions with two scalars as second and third argument
+ "s, s, s - m4, s, s",
+
+ // All three argument expressions with two scalars as first and second argument
+ "s, s, v2", "s, s, v3", "s, s, v4", "s, s, m2", "s, s, m3", "s, s, m4",
+
+ // All four argument expressions with three scalars as second, third and fourth argument
+ "s, s, s, s - m4, s, s, s",
+
+ // All four argument expressions with three scalars as first, second and third argument
+ "s, s, s, v2", "s, s, s, v3", "s, s, s, v4", "s, s, s, m2", "s, s, s, m3", "s, s, s, m4",
+
+ // Five argument expression
+ "s, s, s, s, s"
+ ];
+
+ case "mat3":
+ case "mat4":
+ return [
+ // No arguments and all single argument expressions
+ " - m4",
+
+ // All two argument expressions with a scalar as second argument
+ "s, s - m4, s",
+
+ // All two argument expressions with a scalar as first argument
+ "s, v2", "s, v3", "s, v4", "s, m2", "s, m3", "s, m4",
+
+ // Several argument sequences
+ "v4, s, v4", "v4, s, v3, v2", "v4, v4, v3, v2", "v4, v4, v4, v4", "v2, v2, v2, v2, v2", "v2, v2, v2, v2, v2, v2, v2, v2",
+ "v3, v3, v3", "v3, v3, v3, s", "v3, v3, v3, v3, v3, s", "v3, v3, v3, v3, v3, s, s",
+ ];
+ }
+}
+
+
+// Return publics
+return {
+ getConstructorTests: getConstructorTests,
+ getDefaultTestSet: getDefaultTestSet
+};
+
+}());
+
+
+// Input is an array of intervals of argument types
+// The generated test argument sequences are from (including) the lower interval boundary
+// until (including) the upper boundary
+// Coding and order of the different argument types :
+// s : scalar
+// v2 : vec2
+// v3 : vec3
+// v4 : vec4
+// m2 : mat2
+// m3 : mat3
+// m4 : mat4
+
+// One interval is put in one string
+// Low and high bound are separated by a dash.
+// If there is no dash it is regarded as an interval of one expression
+// The individual argument codes are separated by commas
+// The individual arguments are incremented from left to right
+// The left most argument is the one which is incremented first
+// Once the left most arguments wraps the second argument is increased
+// Examples :
+// "s - m4" : All single arguments from scalar up to (including) mat4
+// "m2, s - m4, s" : All two argument expressions with a matrix argument as first argument and a scalar as second argument
+// " - m4, m4" : The empty argument, all one arguments and all two argument expressions
+// "m2, s, v3, m4" : One 4 argument expression : mat2, scalar, vec3, mat4
diff --git a/dom/canvas/test/webgl-conf/checkout/js/glsl-generator.js b/dom/canvas/test/webgl-conf/checkout/js/glsl-generator.js
new file mode 100644
index 0000000000..d0b65bcb4b
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/js/glsl-generator.js
@@ -0,0 +1,1234 @@
+/*
+Copyright (c) 2019 The Khronos Group Inc.
+Use of this source code is governed by an MIT-style license that can be
+found in the LICENSE.txt file.
+*/
+GLSLGenerator = (function() {
+
+var vertexShaderTemplate = [
+ "attribute vec4 aPosition;",
+ "",
+ "varying vec4 vColor;",
+ "",
+ "$(extra)",
+ "$(emu)",
+ "",
+ "void main()",
+ "{",
+ " gl_Position = aPosition;",
+ " vec2 texcoord = vec2(aPosition.xy * 0.5 + vec2(0.5, 0.5));",
+ " vec4 color = vec4(",
+ " texcoord,",
+ " texcoord.x * texcoord.y,",
+ " (1.0 - texcoord.x) * texcoord.y * 0.5 + 0.5);",
+ " $(test)",
+ "}"
+].join("\n");
+
+var fragmentShaderTemplate = [
+ "precision mediump float;",
+ "",
+ "varying vec4 vColor;",
+ "",
+ "$(extra)",
+ "$(emu)",
+ "",
+ "void main()",
+ "{",
+ " $(test)",
+ "}"
+].join("\n");
+
+var baseVertexShader = [
+ "attribute vec4 aPosition;",
+ "",
+ "varying vec4 vColor;",
+ "",
+ "void main()",
+ "{",
+ " gl_Position = aPosition;",
+ " vec2 texcoord = vec2(aPosition.xy * 0.5 + vec2(0.5, 0.5));",
+ " vColor = vec4(",
+ " texcoord,",
+ " texcoord.x * texcoord.y,",
+ " (1.0 - texcoord.x) * texcoord.y * 0.5 + 0.5);",
+ "}"
+].join("\n");
+
+var baseVertexShaderWithColor = [
+ "attribute vec4 aPosition;",
+ "attribute vec4 aColor;",
+ "",
+ "varying vec4 vColor;",
+ "",
+ "void main()",
+ "{",
+ " gl_Position = aPosition;",
+ " vColor = aColor;",
+ "}"
+].join("\n");
+
+var baseFragmentShader = [
+ "precision mediump float;",
+ "varying vec4 vColor;",
+ "",
+ "void main()",
+ "{",
+ " gl_FragColor = vColor;",
+ "}"
+].join("\n");
+
+var types = [
+ { type: "float",
+ code: [
+ "float $(func)_emu($(args)) {",
+ " return $(func)_base($(baseArgs));",
+ "}"].join("\n")
+ },
+ { type: "vec2",
+ code: [
+ "vec2 $(func)_emu($(args)) {",
+ " return vec2(",
+ " $(func)_base($(baseArgsX)),",
+ " $(func)_base($(baseArgsY)));",
+ "}"].join("\n")
+ },
+ { type: "vec3",
+ code: [
+ "vec3 $(func)_emu($(args)) {",
+ " return vec3(",
+ " $(func)_base($(baseArgsX)),",
+ " $(func)_base($(baseArgsY)),",
+ " $(func)_base($(baseArgsZ)));",
+ "}"].join("\n")
+ },
+ { type: "vec4",
+ code: [
+ "vec4 $(func)_emu($(args)) {",
+ " return vec4(",
+ " $(func)_base($(baseArgsX)),",
+ " $(func)_base($(baseArgsY)),",
+ " $(func)_base($(baseArgsZ)),",
+ " $(func)_base($(baseArgsW)));",
+ "}"].join("\n")
+ }
+];
+
+var bvecTypes = [
+ { type: "bvec2",
+ code: [
+ "bvec2 $(func)_emu($(args)) {",
+ " return bvec2(",
+ " $(func)_base($(baseArgsX)),",
+ " $(func)_base($(baseArgsY)));",
+ "}"].join("\n")
+ },
+ { type: "bvec3",
+ code: [
+ "bvec3 $(func)_emu($(args)) {",
+ " return bvec3(",
+ " $(func)_base($(baseArgsX)),",
+ " $(func)_base($(baseArgsY)),",
+ " $(func)_base($(baseArgsZ)));",
+ "}"].join("\n")
+ },
+ { type: "bvec4",
+ code: [
+ "vec4 $(func)_emu($(args)) {",
+ " return bvec4(",
+ " $(func)_base($(baseArgsX)),",
+ " $(func)_base($(baseArgsY)),",
+ " $(func)_base($(baseArgsZ)),",
+ " $(func)_base($(baseArgsW)));",
+ "}"].join("\n")
+ }
+];
+
+var replaceRE = /\$\((\w+)\)/g;
+
+var replaceParams = function(str) {
+ var args = arguments;
+ return str.replace(replaceRE, function(str, p1, offset, s) {
+ for (var ii = 1; ii < args.length; ++ii) {
+ if (args[ii][p1] !== undefined) {
+ return args[ii][p1];
+ }
+ }
+ throw "unknown string param '" + p1 + "'";
+ });
+};
+
+var generateReferenceShader = function(
+ shaderInfo, template, params, typeInfo, test) {
+ var input = shaderInfo.input;
+ var output = shaderInfo.output;
+ var feature = params.feature;
+ var testFunc = params.testFunc;
+ var emuFunc = params.emuFunc || "";
+ var extra = params.extra || '';
+ var args = params.args || "$(type) value";
+ var type = typeInfo.type;
+ var typeCode = typeInfo.code;
+
+ var baseArgs = params.baseArgs || "value$(field)";
+ var baseArgsX = replaceParams(baseArgs, {field: ".x"});
+ var baseArgsY = replaceParams(baseArgs, {field: ".y"});
+ var baseArgsZ = replaceParams(baseArgs, {field: ".z"});
+ var baseArgsW = replaceParams(baseArgs, {field: ".w"});
+ var baseArgs = replaceParams(baseArgs, {field: ""});
+
+ test = replaceParams(test, {
+ input: input,
+ output: output,
+ func: feature + "_emu"
+ });
+ emuFunc = replaceParams(emuFunc, {
+ func: feature
+ });
+ args = replaceParams(args, {
+ type: type
+ });
+ typeCode = replaceParams(typeCode, {
+ func: feature,
+ type: type,
+ args: args,
+ baseArgs: baseArgs,
+ baseArgsX: baseArgsX,
+ baseArgsY: baseArgsY,
+ baseArgsZ: baseArgsZ,
+ baseArgsW: baseArgsW
+ });
+ var shader = replaceParams(template, {
+ extra: extra,
+ emu: emuFunc + "\n\n" + typeCode,
+ test: test
+ });
+ return shader;
+};
+
+var generateTestShader = function(
+ shaderInfo, template, params, test) {
+ var input = shaderInfo.input;
+ var output = shaderInfo.output;
+ var feature = params.feature;
+ var testFunc = params.testFunc;
+ var extra = params.extra || '';
+
+ test = replaceParams(test, {
+ input: input,
+ output: output,
+ func: feature
+ });
+ var shader = replaceParams(template, {
+ extra: extra,
+ emu: '',
+ test: test
+ });
+ return shader;
+};
+
+function _reportResults(refData, refImg, testData, testImg, tolerance,
+ width, height, ctx, imgData, wtu, canvas2d, consoleDiv) {
+ var same = true;
+ var firstFailure = null;
+ for (var yy = 0; yy < height; ++yy) {
+ for (var xx = 0; xx < width; ++xx) {
+ var offset = (yy * width + xx) * 4;
+ var imgOffset = ((height - yy - 1) * width + xx) * 4;
+ imgData.data[imgOffset + 0] = 0;
+ imgData.data[imgOffset + 1] = 0;
+ imgData.data[imgOffset + 2] = 0;
+ imgData.data[imgOffset + 3] = 255;
+ if (Math.abs(refData[offset + 0] - testData[offset + 0]) > tolerance ||
+ Math.abs(refData[offset + 1] - testData[offset + 1]) > tolerance ||
+ Math.abs(refData[offset + 2] - testData[offset + 2]) > tolerance ||
+ Math.abs(refData[offset + 3] - testData[offset + 3]) > tolerance) {
+ var detail = 'at (' + xx + ',' + yy + '): ref=(' +
+ refData[offset + 0] + ',' +
+ refData[offset + 1] + ',' +
+ refData[offset + 2] + ',' +
+ refData[offset + 3] + ') test=(' +
+ testData[offset + 0] + ',' +
+ testData[offset + 1] + ',' +
+ testData[offset + 2] + ',' +
+ testData[offset + 3] + ') tolerance=' + tolerance;
+ consoleDiv.appendChild(document.createTextNode(detail));
+ consoleDiv.appendChild(document.createElement('br'));
+ if (!firstFailure) {
+ firstFailure = ": " + detail;
+ }
+ imgData.data[imgOffset] = 255;
+ same = false;
+ }
+ }
+ }
+
+ var diffImg = null;
+ if (!same) {
+ ctx.putImageData(imgData, 0, 0);
+ diffImg = wtu.makeImageFromCanvas(canvas2d);
+ }
+
+ var div = document.createElement("div");
+ div.className = "testimages";
+ wtu.insertImage(div, "ref", refImg);
+ wtu.insertImage(div, "test", testImg);
+ if (diffImg) {
+ wtu.insertImage(div, "diff", diffImg);
+ }
+ div.appendChild(document.createElement('br'));
+
+ consoleDiv.appendChild(div);
+
+ if (!same) {
+ testFailed("images are different" + (firstFailure ? firstFailure : ""));
+ } else {
+ testPassed("images are the same");
+ }
+
+ consoleDiv.appendChild(document.createElement('hr'));
+}
+
+var runFeatureTest = function(params) {
+ var wtu = WebGLTestUtils;
+ var gridRes = params.gridRes;
+ var vertexTolerance = params.tolerance || 0;
+ var fragmentTolerance = params.tolerance || 1;
+ if ('fragmentTolerance' in params)
+ fragmentTolerance = params.fragmentTolerance;
+
+ description("Testing GLSL feature: " + params.feature);
+
+ var width = 32;
+ var height = 32;
+
+ var consoleDiv = document.getElementById("console");
+ var canvas = document.createElement('canvas');
+ canvas.width = width;
+ canvas.height = height;
+ var gl = wtu.create3DContext(canvas, { premultipliedAlpha: false });
+ if (!gl) {
+ testFailed("context does not exist");
+ finishTest();
+ return;
+ }
+
+ var canvas2d = document.createElement('canvas');
+ canvas2d.width = width;
+ canvas2d.height = height;
+ var ctx = canvas2d.getContext("2d");
+ var imgData = ctx.getImageData(0, 0, width, height);
+
+ var shaderInfos = [
+ { type: "vertex",
+ input: "color",
+ output: "vColor",
+ vertexShaderTemplate: vertexShaderTemplate,
+ fragmentShaderTemplate: baseFragmentShader,
+ tolerance: vertexTolerance
+ },
+ { type: "fragment",
+ input: "vColor",
+ output: "gl_FragColor",
+ vertexShaderTemplate: baseVertexShader,
+ fragmentShaderTemplate: fragmentShaderTemplate,
+ tolerance: fragmentTolerance
+ }
+ ];
+ for (var ss = 0; ss < shaderInfos.length; ++ss) {
+ var shaderInfo = shaderInfos[ss];
+ var tests = params.tests;
+ var testTypes = params.emuFuncs || (params.bvecTest ? bvecTypes : types);
+ // Test vertex shaders
+ for (var ii = 0; ii < tests.length; ++ii) {
+ var type = testTypes[ii];
+ if (params.simpleEmu) {
+ type = {
+ type: type.type,
+ code: params.simpleEmu
+ };
+ }
+ debug("");
+ var str = replaceParams(params.testFunc, {
+ func: params.feature,
+ type: type.type,
+ arg0: type.type
+ });
+ var passMsg = "Testing: " + str + " in " + shaderInfo.type + " shader";
+ debug(passMsg);
+
+ var referenceVertexShaderSource = generateReferenceShader(
+ shaderInfo,
+ shaderInfo.vertexShaderTemplate,
+ params,
+ type,
+ tests[ii]);
+ var referenceFragmentShaderSource = generateReferenceShader(
+ shaderInfo,
+ shaderInfo.fragmentShaderTemplate,
+ params,
+ type,
+ tests[ii]);
+ var testVertexShaderSource = generateTestShader(
+ shaderInfo,
+ shaderInfo.vertexShaderTemplate,
+ params,
+ tests[ii]);
+ var testFragmentShaderSource = generateTestShader(
+ shaderInfo,
+ shaderInfo.fragmentShaderTemplate,
+ params,
+ tests[ii]);
+
+
+ debug("");
+ var referenceVertexShader = wtu.loadShader(gl, referenceVertexShaderSource, gl.VERTEX_SHADER, testFailed, true, 'reference');
+ var referenceFragmentShader = wtu.loadShader(gl, referenceFragmentShaderSource, gl.FRAGMENT_SHADER, testFailed, true, 'reference');
+ var testVertexShader = wtu.loadShader(gl, testVertexShaderSource, gl.VERTEX_SHADER, testFailed, true, 'test');
+ var testFragmentShader = wtu.loadShader(gl, testFragmentShaderSource, gl.FRAGMENT_SHADER, testFailed, true, 'test');
+ debug("");
+
+ if (parseInt(wtu.getUrlOptions().dumpShaders)) {
+ var vRefInfo = {
+ shader: referenceVertexShader,
+ shaderSuccess: true,
+ label: "reference vertex shader",
+ source: referenceVertexShaderSource
+ };
+ var fRefInfo = {
+ shader: referenceFragmentShader,
+ shaderSuccess: true,
+ label: "reference fragment shader",
+ source: referenceFragmentShaderSource
+ };
+ wtu.dumpShadersInfo(gl, window.location.pathname, passMsg, vRefInfo, fRefInfo);
+
+ var vTestInfo = {
+ shader: testVertexShader,
+ shaderSuccess: true,
+ label: "test vertex shader",
+ source: testVertexShaderSource
+ };
+ var fTestInfo = {
+ shader: testFragmentShader,
+ shaderSuccess: true,
+ label: "test fragment shader",
+ source: testFragmentShaderSource
+ };
+ wtu.dumpShadersInfo(gl, window.location.pathname, passMsg, vTestInfo, fTestInfo);
+ }
+
+ var refData = draw(
+ referenceVertexShader, referenceFragmentShader);
+ var refImg = wtu.makeImageFromCanvas(canvas);
+ if (ss == 0) {
+ var testData = draw(
+ testVertexShader, referenceFragmentShader);
+ } else {
+ var testData = draw(
+ referenceVertexShader, testFragmentShader);
+ }
+ var testImg = wtu.makeImageFromCanvas(canvas);
+
+ _reportResults(refData, refImg, testData, testImg, shaderInfo.tolerance,
+ width, height, ctx, imgData, wtu, canvas2d, consoleDiv);
+ }
+ }
+
+ finishTest();
+
+ function draw(vertexShader, fragmentShader) {
+ var program = wtu.createProgram(gl, vertexShader, fragmentShader, testFailed);
+
+ var posLoc = gl.getAttribLocation(program, "aPosition");
+ wtu.setupIndexedQuad(gl, gridRes, posLoc);
+
+ gl.useProgram(program);
+ wtu.clearAndDrawIndexedQuad(gl, gridRes, [0, 0, 255, 255]);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "no errors from draw");
+
+ var img = new Uint8Array(width * height * 4);
+ gl.readPixels(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, img);
+ return img;
+ }
+
+};
+
+var runBasicTest = function(params) {
+ var wtu = WebGLTestUtils;
+ var gridRes = params.gridRes;
+ var vertexTolerance = params.tolerance || 0;
+ var fragmentTolerance = vertexTolerance;
+ if ('fragmentTolerance' in params)
+ fragmentTolerance = params.fragmentTolerance || 0;
+
+ description("Testing : " + document.getElementsByTagName("title")[0].innerText);
+
+ var width = 32;
+ var height = 32;
+
+ var consoleDiv = document.getElementById("console");
+ var canvas = document.createElement('canvas');
+ canvas.width = width;
+ canvas.height = height;
+ var gl = wtu.create3DContext(canvas);
+ if (!gl) {
+ testFailed("context does not exist");
+ finishTest();
+ return;
+ }
+
+ var canvas2d = document.createElement('canvas');
+ canvas2d.width = width;
+ canvas2d.height = height;
+ var ctx = canvas2d.getContext("2d");
+ var imgData = ctx.getImageData(0, 0, width, height);
+
+ var shaderInfos = [
+ { type: "vertex",
+ input: "color",
+ output: "vColor",
+ vertexShaderTemplate: vertexShaderTemplate,
+ fragmentShaderTemplate: baseFragmentShader,
+ tolerance: vertexTolerance
+ },
+ { type: "fragment",
+ input: "vColor",
+ output: "gl_FragColor",
+ vertexShaderTemplate: baseVertexShader,
+ fragmentShaderTemplate: fragmentShaderTemplate,
+ tolerance: fragmentTolerance
+ }
+ ];
+ for (var ss = 0; ss < shaderInfos.length; ++ss) {
+ var shaderInfo = shaderInfos[ss];
+ var tests = params.tests;
+// var testTypes = params.emuFuncs || (params.bvecTest ? bvecTypes : types);
+ // Test vertex shaders
+ for (var ii = 0; ii < tests.length; ++ii) {
+ var test = tests[ii];
+ debug("");
+ var passMsg = "Testing: " + test.name + " in " + shaderInfo.type + " shader";
+ debug(passMsg);
+
+ function genShader(shaderInfo, template, shader, subs) {
+ shader = replaceParams(shader, subs, {
+ input: shaderInfo.input,
+ output: shaderInfo.output
+ });
+ shader = replaceParams(template, subs, {
+ test: shader,
+ emu: "",
+ extra: ""
+ });
+ return shader;
+ }
+
+ var referenceVertexShaderSource = genShader(
+ shaderInfo,
+ shaderInfo.vertexShaderTemplate,
+ test.reference.shader,
+ test.reference.subs);
+ var referenceFragmentShaderSource = genShader(
+ shaderInfo,
+ shaderInfo.fragmentShaderTemplate,
+ test.reference.shader,
+ test.reference.subs);
+ var testVertexShaderSource = genShader(
+ shaderInfo,
+ shaderInfo.vertexShaderTemplate,
+ test.test.shader,
+ test.test.subs);
+ var testFragmentShaderSource = genShader(
+ shaderInfo,
+ shaderInfo.fragmentShaderTemplate,
+ test.test.shader,
+ test.test.subs);
+
+ debug("");
+ var referenceVertexShader = wtu.loadShader(gl, referenceVertexShaderSource, gl.VERTEX_SHADER, testFailed, true, 'reference');
+ var referenceFragmentShader = wtu.loadShader(gl, referenceFragmentShaderSource, gl.FRAGMENT_SHADER, testFailed, true, 'reference');
+ var testVertexShader = wtu.loadShader(gl, testVertexShaderSource, gl.VERTEX_SHADER, testFailed, true, 'test');
+ var testFragmentShader = wtu.loadShader(gl, testFragmentShaderSource, gl.FRAGMENT_SHADER, testFailed, true, 'test');
+ debug("");
+
+ if (parseInt(wtu.getUrlOptions().dumpShaders)) {
+ var vRefInfo = {
+ shader: referenceVertexShader,
+ shaderSuccess: true,
+ label: "reference vertex shader",
+ source: referenceVertexShaderSource
+ };
+ var fRefInfo = {
+ shader: referenceFragmentShader,
+ shaderSuccess: true,
+ label: "reference fragment shader",
+ source: referenceFragmentShaderSource
+ };
+ wtu.dumpShadersInfo(gl, window.location.pathname, passMsg, vRefInfo, fRefInfo);
+
+ var vTestInfo = {
+ shader: testVertexShader,
+ shaderSuccess: true,
+ label: "test vertex shader",
+ source: testVertexShaderSource
+ };
+ var fTestInfo = {
+ shader: testFragmentShader,
+ shaderSuccess: true,
+ label: "test fragment shader",
+ source: testFragmentShaderSource
+ };
+ wtu.dumpShadersInfo(gl, window.location.pathname, passMsg, vTestInfo, fTestInfo);
+ }
+
+ var refData = draw(referenceVertexShader, referenceFragmentShader);
+ var refImg = wtu.makeImageFromCanvas(canvas);
+ if (ss == 0) {
+ var testData = draw(testVertexShader, referenceFragmentShader);
+ } else {
+ var testData = draw(referenceVertexShader, testFragmentShader);
+ }
+ var testImg = wtu.makeImageFromCanvas(canvas);
+
+ _reportResults(refData, refImg, testData, testImg, shaderInfo.tolerance,
+ width, height, ctx, imgData, wtu, canvas2d, consoleDiv);
+ }
+ }
+
+ finishTest();
+
+ function draw(vertexShader, fragmentShader) {
+ var program = wtu.createProgram(gl, vertexShader, fragmentShader, testFailed);
+
+ var posLoc = gl.getAttribLocation(program, "aPosition");
+ wtu.setupIndexedQuad(gl, gridRes, posLoc);
+
+ gl.useProgram(program);
+ wtu.clearAndDrawIndexedQuad(gl, gridRes, [0, 0, 255, 255]);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "no errors from draw");
+
+ var img = new Uint8Array(width * height * 4);
+ gl.readPixels(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, img);
+ return img;
+ }
+
+};
+
+var runReferenceImageTest = function(params) {
+ var wtu = WebGLTestUtils;
+ var gridRes = params.gridRes;
+ var vertexTolerance = params.tolerance || 0;
+ var fragmentTolerance = vertexTolerance;
+ if ('fragmentTolerance' in params)
+ fragmentTolerance = params.fragmentTolerance || 0;
+
+ description("Testing GLSL feature: " + params.feature);
+
+ var width = 32;
+ var height = 32;
+
+ var consoleDiv = document.getElementById("console");
+ var canvas = document.createElement('canvas');
+ canvas.width = width;
+ canvas.height = height;
+ var gl = wtu.create3DContext(canvas, { antialias: false, premultipliedAlpha: false });
+ if (!gl) {
+ testFailed("context does not exist");
+ finishTest();
+ return;
+ }
+
+ var canvas2d = document.createElement('canvas');
+ canvas2d.width = width;
+ canvas2d.height = height;
+ var ctx = canvas2d.getContext("2d");
+ var imgData = ctx.getImageData(0, 0, width, height);
+
+ // State for reference images for vertex shader tests.
+ // These are drawn with the same tessellated grid as the test vertex
+ // shader so that the interpolation is identical. The grid is reused
+ // from test to test; the colors are changed.
+
+ var indexedQuadForReferenceVertexShader =
+ wtu.setupIndexedQuad(gl, gridRes, 0);
+ var referenceVertexShaderProgram =
+ wtu.setupProgram(gl, [ baseVertexShaderWithColor, baseFragmentShader ],
+ ["aPosition", "aColor"]);
+ var referenceVertexShaderColorBuffer = gl.createBuffer();
+
+ var shaderInfos = [
+ { type: "vertex",
+ input: "color",
+ output: "vColor",
+ vertexShaderTemplate: vertexShaderTemplate,
+ fragmentShaderTemplate: baseFragmentShader,
+ tolerance: vertexTolerance
+ },
+ { type: "fragment",
+ input: "vColor",
+ output: "gl_FragColor",
+ vertexShaderTemplate: baseVertexShader,
+ fragmentShaderTemplate: fragmentShaderTemplate,
+ tolerance: fragmentTolerance
+ }
+ ];
+ for (var ss = 0; ss < shaderInfos.length; ++ss) {
+ var shaderInfo = shaderInfos[ss];
+ var tests = params.tests;
+ var testTypes = params.emuFuncs || (params.bvecTest ? bvecTypes : types);
+ // Test vertex shaders
+ for (var ii = 0; ii < tests.length; ++ii) {
+ var type = testTypes[ii];
+ var isVertex = (ss == 0);
+ debug("");
+ var str = replaceParams(params.testFunc, {
+ func: params.feature,
+ type: type.type,
+ arg0: type.type
+ });
+ var passMsg = "Testing: " + str + " in " + shaderInfo.type + " shader";
+ debug(passMsg);
+
+ var referenceVertexShaderSource = generateReferenceShader(
+ shaderInfo,
+ shaderInfo.vertexShaderTemplate,
+ params,
+ type,
+ tests[ii].source);
+ var referenceFragmentShaderSource = generateReferenceShader(
+ shaderInfo,
+ shaderInfo.fragmentShaderTemplate,
+ params,
+ type,
+ tests[ii].source);
+ var testVertexShaderSource = generateTestShader(
+ shaderInfo,
+ shaderInfo.vertexShaderTemplate,
+ params,
+ tests[ii].source);
+ var testFragmentShaderSource = generateTestShader(
+ shaderInfo,
+ shaderInfo.fragmentShaderTemplate,
+ params,
+ tests[ii].source);
+ var referenceTextureOrArray = generateReferenceImage(
+ gl,
+ tests[ii].generator,
+ isVertex ? gridRes : width,
+ isVertex ? gridRes : height,
+ isVertex);
+
+ debug("");
+ var testVertexShader = wtu.loadShader(gl, testVertexShaderSource, gl.VERTEX_SHADER, testFailed, true);
+ var testFragmentShader = wtu.loadShader(gl, testFragmentShaderSource, gl.FRAGMENT_SHADER, testFailed, true);
+ debug("");
+
+
+ if (parseInt(wtu.getUrlOptions().dumpShaders)) {
+ var vRefInfo = {
+ shader: referenceVertexShader,
+ shaderSuccess: true,
+ label: "reference vertex shader",
+ source: referenceVertexShaderSource
+ };
+ var fRefInfo = {
+ shader: referenceFragmentShader,
+ shaderSuccess: true,
+ label: "reference fragment shader",
+ source: referenceFragmentShaderSource
+ };
+ wtu.dumpShadersInfo(gl, window.location.pathname, passMsg, vRefInfo, fRefInfo);
+
+ var vTestInfo = {
+ shader: testVertexShader,
+ shaderSuccess: true,
+ label: "test vertex shader",
+ source: testVertexShaderSource
+ };
+ var fTestInfo = {
+ shader: testFragmentShader,
+ shaderSuccess: true,
+ label: "test fragment shader",
+ source: testFragmentShaderSource
+ };
+ wtu.dumpShadersInfo(gl, window.location.pathname, passMsg, vTestInfo, fTestInfo);
+ }
+
+ var refData;
+ if (isVertex) {
+ refData = drawVertexReferenceImage(referenceTextureOrArray);
+ } else {
+ refData = drawFragmentReferenceImage(referenceTextureOrArray);
+ }
+ var refImg = wtu.makeImageFromCanvas(canvas);
+ var testData;
+ if (isVertex) {
+ var referenceFragmentShader = wtu.loadShader(gl, referenceFragmentShaderSource, gl.FRAGMENT_SHADER, testFailed);
+ testData = draw(
+ testVertexShader, referenceFragmentShader);
+ } else {
+ var referenceVertexShader = wtu.loadShader(gl, referenceVertexShaderSource, gl.VERTEX_SHADER, testFailed);
+ testData = draw(
+ referenceVertexShader, testFragmentShader);
+ }
+ var testImg = wtu.makeImageFromCanvas(canvas);
+ var testTolerance = shaderInfo.tolerance;
+ // Provide per-test tolerance so that we can increase it only for those desired.
+ if ('tolerance' in tests[ii])
+ testTolerance = tests[ii].tolerance || 0;
+ _reportResults(refData, refImg, testData, testImg, testTolerance,
+ width, height, ctx, imgData, wtu, canvas2d, consoleDiv);
+ }
+ }
+
+ finishTest();
+
+ function draw(vertexShader, fragmentShader) {
+ var program = wtu.createProgram(gl, vertexShader, fragmentShader, testFailed);
+
+ var posLoc = gl.getAttribLocation(program, "aPosition");
+ wtu.setupIndexedQuad(gl, gridRes, posLoc);
+
+ gl.useProgram(program);
+ wtu.clearAndDrawIndexedQuad(gl, gridRes, [0, 0, 255, 255]);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "no errors from draw");
+
+ var img = new Uint8Array(width * height * 4);
+ gl.readPixels(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, img);
+ return img;
+ }
+
+ function drawVertexReferenceImage(colors) {
+ gl.bindBuffer(gl.ARRAY_BUFFER, indexedQuadForReferenceVertexShader[0]);
+ gl.enableVertexAttribArray(0);
+ gl.vertexAttribPointer(0, 3, gl.FLOAT, false, 0, 0);
+ gl.bindBuffer(gl.ARRAY_BUFFER, referenceVertexShaderColorBuffer);
+ gl.bufferData(gl.ARRAY_BUFFER, colors, gl.STATIC_DRAW);
+ gl.enableVertexAttribArray(1);
+ gl.vertexAttribPointer(1, 4, gl.UNSIGNED_BYTE, true, 0, 0);
+ gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexedQuadForReferenceVertexShader[1]);
+ gl.useProgram(referenceVertexShaderProgram);
+ wtu.clearAndDrawIndexedQuad(gl, gridRes);
+ gl.disableVertexAttribArray(0);
+ gl.disableVertexAttribArray(1);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "no errors from draw");
+
+ var img = new Uint8Array(width * height * 4);
+ gl.readPixels(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, img);
+ return img;
+ }
+
+ function drawFragmentReferenceImage(texture) {
+ var program = wtu.setupTexturedQuad(gl);
+
+ gl.activeTexture(gl.TEXTURE0);
+ gl.bindTexture(gl.TEXTURE_2D, texture);
+ var texLoc = gl.getUniformLocation(program, "tex");
+ gl.uniform1i(texLoc, 0);
+ wtu.clearAndDrawUnitQuad(gl);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "no errors from draw");
+
+ var img = new Uint8Array(width * height * 4);
+ gl.readPixels(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, img);
+ return img;
+ }
+
+ /**
+ * Creates and returns either a Uint8Array (for vertex shaders) or
+ * WebGLTexture (for fragment shaders) containing the reference
+ * image for the function being tested. Exactly how the function is
+ * evaluated, and the size of the returned texture or array, depends on
+ * whether we are testing a vertex or fragment shader. If a fragment
+ * shader, the function is evaluated at the pixel centers. If a
+ * vertex shader, the function is evaluated at the triangle's
+ * vertices.
+ *
+ * @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use to generate texture objects.
+ * @param {!function(number,number,number,number): !Array.<number>} generator The reference image generator function.
+ * @param {number} width The width of the texture to generate if testing a fragment shader; the grid resolution if testing a vertex shader.
+ * @param {number} height The height of the texture to generate if testing a fragment shader; the grid resolution if testing a vertex shader.
+ * @param {boolean} isVertex True if generating a reference image for a vertex shader; false if for a fragment shader.
+ * @return {!WebGLTexture|!Uint8Array} The texture object or array that was generated.
+ */
+ function generateReferenceImage(
+ gl,
+ generator,
+ width,
+ height,
+ isVertex) {
+
+ // Note: the math in this function must match that in the vertex and
+ // fragment shader templates above.
+ function computeTexCoord(x) {
+ return x * 0.5 + 0.5;
+ }
+
+ function computeVertexColor(texCoordX, texCoordY) {
+ return [ texCoordX,
+ texCoordY,
+ texCoordX * texCoordY,
+ (1.0 - texCoordX) * texCoordY * 0.5 + 0.5 ];
+ }
+
+ /**
+ * Computes fragment color according to the algorithm used for interpolation
+ * in OpenGL (GLES 2.0 spec 3.5.1, OpenGL 4.3 spec 14.6.1).
+ */
+ function computeInterpolatedColor(texCoordX, texCoordY) {
+ // Calculate grid line indexes below and to the left from texCoord.
+ var gridBottom = Math.floor(texCoordY * gridRes);
+ if (gridBottom == gridRes) {
+ --gridBottom;
+ }
+ var gridLeft = Math.floor(texCoordX * gridRes);
+ if (gridLeft == gridRes) {
+ --gridLeft;
+ }
+
+ // Calculate coordinates relative to the grid cell.
+ var cellX = texCoordX * gridRes - gridLeft;
+ var cellY = texCoordY * gridRes - gridBottom;
+
+ // Barycentric coordinates inside either triangle ACD or ABC
+ // are used as weights for the vertex colors in the corners:
+ // A--B
+ // |\ |
+ // | \|
+ // D--C
+
+ var aColor = computeVertexColor(gridLeft / gridRes, (gridBottom + 1) / gridRes);
+ var bColor = computeVertexColor((gridLeft + 1) / gridRes, (gridBottom + 1) / gridRes);
+ var cColor = computeVertexColor((gridLeft + 1) / gridRes, gridBottom / gridRes);
+ var dColor = computeVertexColor(gridLeft / gridRes, gridBottom / gridRes);
+
+ // Calculate weights.
+ var a, b, c, d;
+
+ if (cellX + cellY < 1) {
+ // In bottom triangle ACD.
+ a = cellY; // area of triangle C-D-(cellX, cellY) relative to ACD
+ c = cellX; // area of triangle D-A-(cellX, cellY) relative to ACD
+ d = 1 - a - c;
+ b = 0;
+ } else {
+ // In top triangle ABC.
+ a = 1 - cellX; // area of the triangle B-C-(cellX, cellY) relative to ABC
+ c = 1 - cellY; // area of the triangle A-B-(cellX, cellY) relative to ABC
+ b = 1 - a - c;
+ d = 0;
+ }
+
+ var interpolated = [];
+ for (var ii = 0; ii < aColor.length; ++ii) {
+ interpolated.push(a * aColor[ii] + b * bColor[ii] + c * cColor[ii] + d * dColor[ii]);
+ }
+ return interpolated;
+ }
+
+ function clamp(value, minVal, maxVal) {
+ return Math.max(minVal, Math.min(value, maxVal));
+ }
+
+ // Evaluates the function at clip coordinates (px,py), storing the
+ // result in the array "pixel". Each channel's result is clamped
+ // between 0 and 255.
+ function evaluateAtClipCoords(px, py, pixel, colorFunc) {
+ var tcx = computeTexCoord(px);
+ var tcy = computeTexCoord(py);
+
+ var color = colorFunc(tcx, tcy);
+
+ var output = generator(color[0], color[1], color[2], color[3]);
+
+ // Multiply by 256 to get even distribution for all values between 0 and 1.
+ // Use rounding rather than truncation to more closely match the GPU's behavior.
+ pixel[0] = clamp(Math.round(256 * output[0]), 0, 255);
+ pixel[1] = clamp(Math.round(256 * output[1]), 0, 255);
+ pixel[2] = clamp(Math.round(256 * output[2]), 0, 255);
+ pixel[3] = clamp(Math.round(256 * output[3]), 0, 255);
+ }
+
+ function generateFragmentReference() {
+ var data = new Uint8Array(4 * width * height);
+
+ var horizTexel = 1.0 / width;
+ var vertTexel = 1.0 / height;
+ var halfHorizTexel = 0.5 * horizTexel;
+ var halfVertTexel = 0.5 * vertTexel;
+
+ var pixel = new Array(4);
+
+ for (var yi = 0; yi < height; ++yi) {
+ for (var xi = 0; xi < width; ++xi) {
+ // The function must be evaluated at pixel centers.
+
+ // Compute desired position in clip space
+ var px = -1.0 + 2.0 * (halfHorizTexel + xi * horizTexel);
+ var py = -1.0 + 2.0 * (halfVertTexel + yi * vertTexel);
+
+ evaluateAtClipCoords(px, py, pixel, computeInterpolatedColor);
+ var index = 4 * (width * yi + xi);
+ data[index + 0] = pixel[0];
+ data[index + 1] = pixel[1];
+ data[index + 2] = pixel[2];
+ data[index + 3] = pixel[3];
+ }
+ }
+
+ var texture = gl.createTexture();
+ gl.bindTexture(gl.TEXTURE_2D, texture);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
+ gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0,
+ gl.RGBA, gl.UNSIGNED_BYTE, data);
+ return texture;
+ }
+
+ function generateVertexReference() {
+ // We generate a Uint8Array which contains the evaluation of the
+ // function at the vertices of the triangle mesh. It is expected
+ // that the width and the height are identical, and equivalent
+ // to the grid resolution.
+ if (width != height) {
+ throw "width and height must be equal";
+ }
+
+ var texSize = 1 + width;
+ var data = new Uint8Array(4 * texSize * texSize);
+
+ var step = 2.0 / width;
+
+ var pixel = new Array(4);
+
+ for (var yi = 0; yi < texSize; ++yi) {
+ for (var xi = 0; xi < texSize; ++xi) {
+ // The function is evaluated at the triangles' vertices.
+
+ // Compute desired position in clip space
+ var px = -1.0 + (xi * step);
+ var py = -1.0 + (yi * step);
+
+ evaluateAtClipCoords(px, py, pixel, computeVertexColor);
+ var index = 4 * (texSize * yi + xi);
+ data[index + 0] = pixel[0];
+ data[index + 1] = pixel[1];
+ data[index + 2] = pixel[2];
+ data[index + 3] = pixel[3];
+ }
+ }
+
+ return data;
+ }
+
+ //----------------------------------------------------------------------
+ // Body of generateReferenceImage
+ //
+
+ if (isVertex) {
+ return generateVertexReference();
+ } else {
+ return generateFragmentReference();
+ }
+ }
+};
+
+return {
+ /**
+ * runs a bunch of GLSL tests using the passed in parameters
+ * The parameters are:
+ *
+ * feature:
+ * the name of the function being tested (eg, sin, dot,
+ * normalize)
+ *
+ * testFunc:
+ * The prototype of function to be tested not including the
+ * return type.
+ *
+ * emuFunc:
+ * A base function that can be used to generate emulation
+ * functions. Example for 'ceil'
+ *
+ * float $(func)_base(float value) {
+ * float m = mod(value, 1.0);
+ * return m != 0.0 ? (value + 1.0 - m) : value;
+ * }
+ *
+ * args:
+ * The arguments to the function
+ *
+ * baseArgs: (optional)
+ * The arguments when a base function is used to create an
+ * emulation function. For example 'float sign_base(float v)'
+ * is used to implemenent vec2 sign_emu(vec2 v).
+ *
+ * simpleEmu:
+ * if supplied, the code that can be used to generate all
+ * functions for all types.
+ *
+ * Example for 'normalize':
+ *
+ * $(type) $(func)_emu($(args)) {
+ * return value / length(value);
+ * }
+ *
+ * gridRes: (optional)
+ * The resolution of the mesh to generate. The default is a
+ * 1x1 grid but many vertex shaders need a higher resolution
+ * otherwise the only values passed in are the 4 corners
+ * which often have the same value.
+ *
+ * tests:
+ * The code for each test. It is assumed the tests are for
+ * float, vec2, vec3, vec4 in that order.
+ *
+ * tolerance: (optional)
+ * Allow some tolerance in the comparisons. The tolerance is applied to
+ * both vertex and fragment shaders. The default tolerance is 0, meaning
+ * the values have to be identical.
+ *
+ * fragmentTolerance: (optional)
+ * Specify a tolerance which only applies to fragment shaders. The
+ * fragment-only tolerance will override the shared tolerance for
+ * fragment shaders if both are specified. Fragment shaders usually
+ * use mediump float precision so they sometimes require higher tolerance
+ * than vertex shaders which use highp by default.
+ */
+ runFeatureTest: runFeatureTest,
+
+ /*
+ * Runs a bunch of GLSL tests using the passed in parameters
+ *
+ * The parameters are:
+ *
+ * tests:
+ * Array of tests. For each test the following parameters are expected
+ *
+ * name:
+ * some description of the test
+ * reference:
+ * parameters for the reference shader (see below)
+ * test:
+ * parameters for the test shader (see below)
+ *
+ * The parameter for the reference and test shaders are
+ *
+ * shader: the GLSL for the shader
+ * subs: any substitutions you wish to define for the shader.
+ *
+ * Each shader is created from a basic template that
+ * defines an input and an output. You can see the
+ * templates at the top of this file. The input and output
+ * change depending on whether or not we are generating
+ * a vertex or fragment shader.
+ *
+ * All this code function does is a bunch of string substitutions.
+ * A substitution is defined by $(name). If name is found in
+ * the 'subs' parameter it is replaced. 4 special names exist.
+ *
+ * 'input' the input to your GLSL. Always a vec4. All change
+ * from 0 to 1 over the quad to be drawn.
+ *
+ * 'output' the output color. Also a vec4
+ *
+ * 'emu' a place to insert extra stuff
+ * 'extra' a place to insert extra stuff.
+ *
+ * You can think of the templates like this
+ *
+ * $(extra)
+ * $(emu)
+ *
+ * void main() {
+ * // do math to calculate input
+ * ...
+ *
+ * $(shader)
+ * }
+ *
+ * Your shader first has any subs you provided applied as well
+ * as 'input' and 'output'
+ *
+ * It is then inserted into the template which is also provided
+ * with your subs.
+ *
+ * gridRes: (optional)
+ * The resolution of the mesh to generate. The default is a
+ * 1x1 grid but many vertex shaders need a higher resolution
+ * otherwise the only values passed in are the 4 corners
+ * which often have the same value.
+ *
+ * tolerance: (optional)
+ * Allow some tolerance in the comparisons. The tolerance is applied to
+ * both vertex and fragment shaders. The default tolerance is 0, meaning
+ * the values have to be identical.
+ *
+ * fragmentTolerance: (optional)
+ * Specify a tolerance which only applies to fragment shaders. The
+ * fragment-only tolerance will override the shared tolerance for
+ * fragment shaders if both are specified. Fragment shaders usually
+ * use mediump float precision so they sometimes require higher tolerance
+ * than vertex shaders which use highp.
+ */
+ runBasicTest: runBasicTest,
+
+ /**
+ * Runs a bunch of GLSL tests using the passed in parameters. The
+ * expected results are computed as a reference image in JavaScript
+ * instead of on the GPU. The parameters are:
+ *
+ * feature:
+ * the name of the function being tested (eg, sin, dot,
+ * normalize)
+ *
+ * testFunc:
+ * The prototype of function to be tested not including the
+ * return type.
+ *
+ * args:
+ * The arguments to the function
+ *
+ * gridRes: (optional)
+ * The resolution of the mesh to generate. The default is a
+ * 1x1 grid but many vertex shaders need a higher resolution
+ * otherwise the only values passed in are the 4 corners
+ * which often have the same value.
+ *
+ * tests:
+ * Array of tests. It is assumed the tests are for float, vec2,
+ * vec3, vec4 in that order. For each test the following
+ * parameters are expected:
+ *
+ * source: the GLSL source code for the tests
+ *
+ * generator: a JavaScript function taking four parameters
+ * which evaluates the same function as the GLSL source,
+ * returning its result as a newly allocated array.
+ *
+ * tolerance: (optional) a per-test tolerance.
+ *
+ * extra: (optional)
+ * Extra GLSL code inserted at the top of each test's shader.
+ *
+ * tolerance: (optional)
+ * Allow some tolerance in the comparisons. The tolerance is applied to
+ * both vertex and fragment shaders. The default tolerance is 0, meaning
+ * the values have to be identical.
+ *
+ * fragmentTolerance: (optional)
+ * Specify a tolerance which only applies to fragment shaders. The
+ * fragment-only tolerance will override the shared tolerance for
+ * fragment shaders if both are specified. Fragment shaders usually
+ * use mediump float precision so they sometimes require higher tolerance
+ * than vertex shaders which use highp.
+ */
+ runReferenceImageTest: runReferenceImageTest,
+
+ none: false
+};
+
+}());
+
diff --git a/dom/canvas/test/webgl-conf/checkout/js/js-test-post.js b/dom/canvas/test/webgl-conf/checkout/js/js-test-post.js
new file mode 100644
index 0000000000..2b19b3b98f
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/js/js-test-post.js
@@ -0,0 +1,38 @@
+/*
+Copyright (c) 2019 The Khronos Group Inc.
+Use of this source code is governed by an MIT-style license that can be
+found in the LICENSE.txt file.
+*/
+
+shouldBeTrue("successfullyParsed");
+_addSpan('<br /><span class="pass">TEST COMPLETE</span>');
+if (_jsTestPreVerboseLogging) {
+ _bufferedLogToConsole('TEST COMPLETE');
+}
+
+{
+ const e_results = document.createElement('div');
+ let fails_class = 'pass';
+ if (RESULTS.fail) {
+ fails_class = 'fail';
+ } else {
+ const parseBoolean = v => v.toLowerCase().startsWith('t') || parseFloat(v) > 0;
+ const params = new URLSearchParams(window.location.search);
+ if (parseBoolean(params.get('runUntilFail') || '')) {
+ setTimeout(() => {
+ params.set('runCount', parseInt(params.get('runCount') || '0') + 1);
+ const url = new URL(window.location.href);
+ url.search = params.toString();
+ window.location.href = url.toString();
+ }, 100);
+ }
+ }
+ e_results.classList.add('pass');
+ e_results.innerHTML = `<p>TEST COMPLETE: ${RESULTS.pass} PASS, ` +
+ `<span class="${fails_class}">${RESULTS.fail} FAIL</span></p>`;
+
+ const e_desc = document.getElementById("description");
+ e_desc.appendChild(e_results);
+}
+
+notifyFinishedToHarness()
diff --git a/dom/canvas/test/webgl-conf/checkout/js/js-test-pre.js b/dom/canvas/test/webgl-conf/checkout/js/js-test-pre.js
new file mode 100644
index 0000000000..e1cb9f749c
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/js/js-test-pre.js
@@ -0,0 +1,801 @@
+/*
+Copyright (c) 2019 The Khronos Group Inc.
+Use of this source code is governed by an MIT-style license that can be
+found in the LICENSE.txt file.
+*/
+
+(function() {
+ var testHarnessInitialized = false;
+
+ var initNonKhronosFramework = function() {
+ if (testHarnessInitialized) {
+ return;
+ }
+ testHarnessInitialized = true;
+
+ /* -- plaform specific code -- */
+
+ // WebKit Specific code. Add your code here.
+ if (window.testRunner && !window.layoutTestController) {
+ window.layoutTestController = window.testRunner;
+ }
+
+ if (window.layoutTestController) {
+ window.layoutTestController.dumpAsText();
+ window.layoutTestController.waitUntilDone();
+ }
+ if (window.internals) {
+ // The WebKit testing system compares console output.
+ // Because the output of the WebGL Tests is GPU dependent
+ // we turn off console messages.
+ window.console.log = function() { };
+ window.console.error = function() { };
+ window.internals.settings.setWebGLErrorsToConsoleEnabled(false);
+ }
+
+ /* -- end platform specific code --*/
+ }
+
+ this.initTestingHarness = function() {
+ initNonKhronosFramework();
+ }
+}());
+
+var getUrlOptions = (function() {
+ var _urlOptionsParsed = false;
+ var _urlOptions = {};
+ return function() {
+ if (!_urlOptionsParsed) {
+ var s = window.location.href;
+ var q = s.indexOf("?");
+ var e = s.indexOf("#");
+ if (e < 0) {
+ e = s.length;
+ }
+ var query = s.substring(q + 1, e);
+ var pairs = query.split("&");
+ for (var ii = 0; ii < pairs.length; ++ii) {
+ var keyValue = pairs[ii].split("=");
+ var key = keyValue[0];
+ var value = decodeURIComponent(keyValue[1]);
+ _urlOptions[key] = value;
+ }
+ _urlOptionsParsed = true;
+ }
+
+ return _urlOptions;
+ }
+})();
+
+if (typeof quietMode == 'undefined') {
+ var quietMode = (function() {
+ var _quietModeChecked = false;
+ var _isQuiet = false;
+ return function() {
+ if (!_quietModeChecked) {
+ _isQuiet = (getUrlOptions().quiet == 1);
+ _quietModeChecked = true;
+ }
+ return _isQuiet;
+ }
+ })();
+}
+
+function nonKhronosFrameworkNotifyDone() {
+ // WebKit Specific code. Add your code here.
+ if (window.layoutTestController) {
+ window.layoutTestController.notifyDone();
+ }
+}
+
+const RESULTS = {
+ pass: 0,
+ fail: 0,
+};
+
+function reportTestResultsToHarness(success, msg) {
+ if (success) {
+ RESULTS.pass += 1;
+ } else {
+ RESULTS.fail += 1;
+ }
+ if (window.parent.webglTestHarness) {
+ window.parent.webglTestHarness.reportResults(window.location.pathname, success, msg);
+ }
+}
+
+function reportSkippedTestResultsToHarness(success, msg) {
+ if (window.parent.webglTestHarness) {
+ window.parent.webglTestHarness.reportResults(window.location.pathname, success, msg, true);
+ }
+}
+
+function notifyFinishedToHarness() {
+ if (window._didNotifyFinishedToHarness) {
+ testFailed("Duplicate notifyFinishedToHarness()");
+ }
+ window._didNotifyFinishedToHarness = true;
+
+ if (window.parent.webglTestHarness) {
+ window.parent.webglTestHarness.notifyFinished(window.location.pathname);
+ }
+ if (window.nonKhronosFrameworkNotifyDone) {
+ window.nonKhronosFrameworkNotifyDone();
+ }
+}
+
+var _bufferedConsoleLogs = [];
+
+function _bufferedLogToConsole(msg)
+{
+ if (_bufferedConsoleLogs) {
+ _bufferedConsoleLogs.push(msg);
+ } else if (window.console) {
+ window.console.log(msg);
+ }
+}
+
+// Public entry point exposed to many other files.
+function bufferedLogToConsole(msg)
+{
+ _bufferedLogToConsole(msg);
+}
+
+// Called implicitly by testFailed().
+function _flushBufferedLogsToConsole()
+{
+ if (_bufferedConsoleLogs) {
+ if (window.console) {
+ for (var ii = 0; ii < _bufferedConsoleLogs.length; ++ii) {
+ window.console.log(_bufferedConsoleLogs[ii]);
+ }
+ }
+ _bufferedConsoleLogs = null;
+ }
+}
+
+var _jsTestPreVerboseLogging = false;
+
+function enableJSTestPreVerboseLogging()
+{
+ _jsTestPreVerboseLogging = true;
+}
+
+function description(msg)
+{
+ initTestingHarness();
+ if (msg === undefined) {
+ msg = document.title;
+ }
+ // For MSIE 6 compatibility
+ var span = document.createElement("span");
+ span.innerHTML = '<p>' + msg + '</p><p>On success, you will see a series of "<span class="pass">PASS</span>" messages, followed by "<span class="pass">TEST COMPLETE</span>".</p>';
+ var description = document.getElementById("description");
+ if (description.firstChild)
+ description.replaceChild(span, description.firstChild);
+ else
+ description.appendChild(span);
+ if (_jsTestPreVerboseLogging) {
+ _bufferedLogToConsole(msg);
+ }
+}
+
+function _addSpan(contents)
+{
+ var span = document.createElement("span");
+ document.getElementById("console").appendChild(span); // insert it first so XHTML knows the namespace
+ span.innerHTML = contents + '<br />';
+}
+
+function debug(msg)
+{
+ if (!quietMode())
+ _addSpan(msg);
+ if (_jsTestPreVerboseLogging) {
+ _bufferedLogToConsole(msg);
+ }
+}
+
+function escapeHTML(text)
+{
+ return text.replace(/&/g, "&amp;").replace(/</g, "&lt;");
+}
+/**
+ * Defines the exception type for a test failure.
+ * @constructor
+ * @param {string} message The error message.
+ */
+var TestFailedException = function (message) {
+ this.message = message;
+ this.name = "TestFailedException";
+};
+
+/**
+ * @param {string=} msg
+ */
+function testPassed(msg) {
+ msg = msg || 'Passed';
+ if (_currentTestName)
+ msg = _currentTestName + ': ' + msg;
+
+ reportTestResultsToHarness(true, msg);
+
+ if (!quietMode())
+ _addSpan('<span><span class="pass">PASS</span> ' + escapeHTML(msg) + '</span>');
+ if (_jsTestPreVerboseLogging) {
+ _bufferedLogToConsole('PASS ' + msg);
+ }
+}
+
+/**
+ * @param {string=} msg
+ */
+function testFailed(msg) {
+ msg = msg || 'Failed';
+ if (_currentTestName)
+ msg = _currentTestName + ': ' + msg;
+
+ reportTestResultsToHarness(false, msg);
+ _addSpan('<span><span class="fail">FAIL</span> ' + escapeHTML(msg) + '</span>');
+ _bufferedLogToConsole('FAIL ' + msg);
+ _flushBufferedLogsToConsole();
+}
+
+var _currentTestName;
+
+/**
+ * Sets the current test name for usage within testPassedOptions/testFailedOptions.
+ * @param {string=} name The name to set as the current test name.
+ */
+function setCurrentTestName(name)
+{
+ _currentTestName = name;
+}
+
+/**
+ * Gets the current test name in use within testPassedOptions/testFailedOptions.
+ * @return {string} The name of the current test.
+ */
+function getCurrentTestName()
+{
+ return _currentTestName;
+}
+
+/**
+ * Variation of the testPassed function, with the option to not show (and thus not count) the test's pass result.
+ * @param {string} msg The message to be shown in the pass result.
+ * @param {boolean} addSpan Indicates whether the message will be visible (thus counted in the results) or not.
+ */
+function testPassedOptions(msg, addSpan)
+{
+ if (addSpan && !quietMode())
+ {
+ reportTestResultsToHarness(true, _currentTestName + ": " + msg);
+ _addSpan('<span><span class="pass">PASS</span> ' + escapeHTML(_currentTestName) + ": " + escapeHTML(msg) + '</span>');
+ }
+ if (_jsTestPreVerboseLogging) {
+ _bufferedLogToConsole('PASS ' + msg);
+ }
+}
+
+/**
+ * Report skipped tests.
+ * @param {string} msg The message to be shown in the skip result.
+ * @param {boolean} addSpan Indicates whether the message will be visible (thus counted in the results) or not.
+ */
+function testSkippedOptions(msg, addSpan)
+{
+ if (addSpan && !quietMode())
+ {
+ reportSkippedTestResultsToHarness(true, _currentTestName + ": " + msg);
+ _addSpan('<span><span class="warn">SKIP</span> ' + escapeHTML(_currentTestName) + ": " + escapeHTML(msg) + '</span>');
+ }
+ if (_jsTestPreVerboseLogging) {
+ _bufferedLogToConsole('SKIP' + msg);
+ }
+}
+
+/**
+ * Variation of the testFailed function, with the option to throw an exception or not.
+ * @param {string} msg The message to be shown in the fail result.
+ * @param {boolean} exthrow Indicates whether the function will throw a TestFailedException or not.
+ */
+function testFailedOptions(msg, exthrow)
+{
+ reportTestResultsToHarness(false, _currentTestName + ": " + msg);
+ _addSpan('<span><span class="fail">FAIL</span> ' + escapeHTML(_currentTestName) + ": " + escapeHTML(msg) + '</span>');
+ _bufferedLogToConsole('FAIL ' + msg);
+ _flushBufferedLogsToConsole();
+ if (exthrow) {
+ _currentTestName = ""; //Remembering to set the name of current testcase to empty string.
+ throw new TestFailedException(msg);
+ }
+}
+
+function areArraysEqual(_a, _b)
+{
+ try {
+ if (_a.length !== _b.length)
+ return false;
+ for (var i = 0; i < _a.length; i++)
+ if (_a[i] !== _b[i])
+ return false;
+ } catch (ex) {
+ return false;
+ }
+ return true;
+}
+
+function isMinusZero(n)
+{
+ // the only way to tell 0 from -0 in JS is the fact that 1/-0 is
+ // -Infinity instead of Infinity
+ return n === 0 && 1/n < 0;
+}
+
+function isResultCorrect(_actual, _expected)
+{
+ if (_expected === 0)
+ return _actual === _expected && (1/_actual) === (1/_expected);
+ if (_actual === _expected)
+ return true;
+ if (typeof(_expected) == "number" && isNaN(_expected))
+ return typeof(_actual) == "number" && isNaN(_actual);
+ if (Object.prototype.toString.call(_expected) == Object.prototype.toString.call([]))
+ return areArraysEqual(_actual, _expected);
+ return false;
+}
+
+function stringify(v)
+{
+ if (v === 0 && 1/v < 0)
+ return "-0";
+ else return "" + v;
+}
+
+function evalAndLog(_a)
+{
+ if (typeof _a != "string")
+ debug("WARN: tryAndLog() expects a string argument");
+
+ // Log first in case things go horribly wrong or this causes a sync event.
+ debug(_a);
+
+ var _av;
+ try {
+ _av = eval(_a);
+ } catch (e) {
+ testFailed(_a + " threw exception " + e);
+ }
+ return _av;
+}
+
+function shouldBeString(evalable, expected) {
+ const val = eval(evalable);
+ const text = evalable + " should be " + expected + ".";
+ if (val == expected) {
+ testPassed(text);
+ } else {
+ testFailed(text + " (was " + val + ")");
+ }
+}
+
+function shouldBe(_a, _b, quiet)
+{
+ if (typeof _a != "string" || typeof _b != "string")
+ debug("WARN: shouldBe() expects string arguments");
+ var exception;
+ var _av;
+ try {
+ _av = eval(_a);
+ } catch (e) {
+ exception = e;
+ }
+ var _bv = eval(_b);
+
+ if (exception)
+ testFailed(_a + " should be " + _bv + ". Threw exception " + exception);
+ else if (isResultCorrect(_av, _bv)) {
+ if (!quiet) {
+ testPassed(_a + " is " + _b);
+ }
+ } else if (typeof(_av) == typeof(_bv))
+ testFailed(_a + " should be " + _bv + ". Was " + stringify(_av) + ".");
+ else
+ testFailed(_a + " should be " + _bv + " (of type " + typeof _bv + "). Was " + _av + " (of type " + typeof _av + ").");
+}
+
+function shouldNotBe(_a, _b, quiet)
+{
+ if (typeof _a != "string" || typeof _b != "string")
+ debug("WARN: shouldNotBe() expects string arguments");
+ var exception;
+ var _av;
+ try {
+ _av = eval(_a);
+ } catch (e) {
+ exception = e;
+ }
+ var _bv = eval(_b);
+
+ if (exception)
+ testFailed(_a + " should not be " + _bv + ". Threw exception " + exception);
+ else if (!isResultCorrect(_av, _bv)) {
+ if (!quiet) {
+ testPassed(_a + " is not " + _b);
+ }
+ } else
+ testFailed(_a + " should not be " + _bv + ".");
+}
+
+function shouldBeTrue(_a) { shouldBe(_a, "true"); }
+function shouldBeFalse(_a) { shouldBe(_a, "false"); }
+function shouldBeNaN(_a) { shouldBe(_a, "NaN"); }
+function shouldBeNull(_a) { shouldBe(_a, "null"); }
+
+function shouldBeEqualToString(a, b)
+{
+ var unevaledString = '"' + b.replace(/"/g, "\"") + '"';
+ shouldBe(a, unevaledString);
+}
+
+function shouldEvaluateTo(actual, expected) {
+ // A general-purpose comparator. 'actual' should be a string to be
+ // evaluated, as for shouldBe(). 'expected' may be any type and will be
+ // used without being eval'ed.
+ if (expected == null) {
+ // Do this before the object test, since null is of type 'object'.
+ shouldBeNull(actual);
+ } else if (typeof expected == "undefined") {
+ shouldBeUndefined(actual);
+ } else if (typeof expected == "function") {
+ // All this fuss is to avoid the string-arg warning from shouldBe().
+ try {
+ var actualValue = eval(actual);
+ } catch (e) {
+ testFailed("Evaluating " + actual + ": Threw exception " + e);
+ return;
+ }
+ shouldBe("'" + actualValue.toString().replace(/\n/g, "") + "'",
+ "'" + expected.toString().replace(/\n/g, "") + "'");
+ } else if (typeof expected == "object") {
+ shouldBeTrue(actual + " == '" + expected + "'");
+ } else if (typeof expected == "string") {
+ shouldBe(actual, expected);
+ } else if (typeof expected == "boolean") {
+ shouldBe("typeof " + actual, "'boolean'");
+ if (expected)
+ shouldBeTrue(actual);
+ else
+ shouldBeFalse(actual);
+ } else if (typeof expected == "number") {
+ shouldBe(actual, stringify(expected));
+ } else {
+ debug(expected + " is unknown type " + typeof expected);
+ shouldBeTrue(actual, "'" +expected.toString() + "'");
+ }
+}
+
+function shouldBeNonZero(_a)
+{
+ var exception;
+ var _av;
+ try {
+ _av = eval(_a);
+ } catch (e) {
+ exception = e;
+ }
+
+ if (exception)
+ testFailed(_a + " should be non-zero. Threw exception " + exception);
+ else if (_av != 0)
+ testPassed(_a + " is non-zero.");
+ else
+ testFailed(_a + " should be non-zero. Was " + _av);
+}
+
+function shouldBeNonNull(_a)
+{
+ var exception;
+ var _av;
+ try {
+ _av = eval(_a);
+ } catch (e) {
+ exception = e;
+ }
+
+ if (exception)
+ testFailed(_a + " should be non-null. Threw exception " + exception);
+ else if (_av != null)
+ testPassed(_a + " is non-null.");
+ else
+ testFailed(_a + " should be non-null. Was " + _av);
+}
+
+function shouldBeUndefined(_a)
+{
+ var exception;
+ var _av;
+ try {
+ _av = eval(_a);
+ } catch (e) {
+ exception = e;
+ }
+
+ if (exception)
+ testFailed(_a + " should be undefined. Threw exception " + exception);
+ else if (typeof _av == "undefined")
+ testPassed(_a + " is undefined.");
+ else
+ testFailed(_a + " should be undefined. Was " + _av);
+}
+
+function shouldBeDefined(_a)
+{
+ var exception;
+ var _av;
+ try {
+ _av = eval(_a);
+ } catch (e) {
+ exception = e;
+ }
+
+ if (exception)
+ testFailed(_a + " should be defined. Threw exception " + exception);
+ else if (_av !== undefined)
+ testPassed(_a + " is defined.");
+ else
+ testFailed(_a + " should be defined. Was " + _av);
+}
+
+function shouldBeLessThanOrEqual(_a, _b) {
+ if (typeof _a != "string" || typeof _b != "string")
+ debug("WARN: shouldBeLessThanOrEqual expects string arguments");
+
+ var exception;
+ var _av;
+ try {
+ _av = eval(_a);
+ } catch (e) {
+ exception = e;
+ }
+ var _bv = eval(_b);
+
+ if (exception)
+ testFailed(_a + " should be <= " + _b + ". Threw exception " + exception);
+ else if (typeof _av == "undefined" || _av > _bv)
+ testFailed(_a + " should be >= " + _b + ". Was " + _av + " (of type " + typeof _av + ").");
+ else
+ testPassed(_a + " is <= " + _b);
+}
+
+function shouldBeGreaterThanOrEqual(_a, _b) {
+ if (typeof _a != "string" || typeof _b != "string")
+ debug("WARN: shouldBeGreaterThanOrEqual expects string arguments");
+
+ var exception;
+ var _av;
+ try {
+ _av = eval(_a);
+ } catch (e) {
+ exception = e;
+ }
+ var _bv = eval(_b);
+
+ if (exception)
+ testFailed(_a + " should be >= " + _b + ". Threw exception " + exception);
+ else if (typeof _av == "undefined" || _av < _bv)
+ testFailed(_a + " should be >= " + _b + ". Was " + _av + " (of type " + typeof _av + ").");
+ else
+ testPassed(_a + " is >= " + _b);
+}
+
+function expectTrue(v, msg) {
+ if (v) {
+ testPassed(msg);
+ } else {
+ testFailed(msg);
+ }
+}
+
+function maxArrayDiff(a, b) {
+ if (a.length != b.length)
+ throw new Error(`a and b have different lengths: ${a.length} vs ${b.length}`);
+
+ let diff = 0;
+ for (const i in a) {
+ diff = Math.max(diff, Math.abs(a[i] - b[i]));
+ }
+ return diff;
+}
+
+function expectArray(was, expected, maxDiff=0) {
+ const diff = maxArrayDiff(expected, was);
+ let str = `Expected [${expected.toString()}]`;
+ let fn = testPassed;
+ if (maxDiff) {
+ str += ' +/- ' + maxDiff;
+ }
+ if (diff > maxDiff) {
+ fn = testFailed;
+ str += `, was [${was.toString()}]`;
+ }
+ fn(str);
+}
+
+function shouldThrow(_a, _e)
+{
+ var exception;
+ var _av;
+ try {
+ _av = eval(_a);
+ } catch (e) {
+ exception = e;
+ }
+
+ var _ev;
+ if (_e)
+ _ev = eval(_e);
+
+ if (exception) {
+ if (typeof _e == "undefined" || exception == _ev)
+ testPassed(_a + " threw exception " + exception + ".");
+ else
+ testFailed(_a + " should throw " + (typeof _e == "undefined" ? "an exception" : _ev) + ". Threw exception " + exception + ".");
+ } else if (typeof _av == "undefined")
+ testFailed(_a + " should throw " + (typeof _e == "undefined" ? "an exception" : _ev) + ". Was undefined.");
+ else
+ testFailed(_a + " should throw " + (typeof _e == "undefined" ? "an exception" : _ev) + ". Was " + _av + ".");
+}
+
+function shouldNotThrow(evalStr, desc) {
+ desc = desc || `\`${evalStr}\``;
+ try {
+ eval(evalStr);
+ testPassed(`${desc} should not throw.`);
+ } catch (e) {
+ testFailed(`${desc} should not throw, but threw exception ${e}.`);
+ }
+}
+
+
+function shouldBeType(_a, _type) {
+ var exception;
+ var _av;
+ try {
+ _av = eval(_a);
+ } catch (e) {
+ exception = e;
+ }
+
+ var _typev = eval(_type);
+
+ if(_typev === Number){
+ if(_av instanceof Number){
+ testPassed(_a + " is an instance of Number");
+ }
+ else if(typeof(_av) === 'number'){
+ testPassed(_a + " is an instance of Number");
+ }
+ else{
+ testFailed(_a + " is not an instance of Number");
+ }
+ }
+ else if (_av instanceof _typev) {
+ testPassed(_a + " is an instance of " + _type);
+ } else {
+ testFailed(_a + " is not an instance of " + _type);
+ }
+}
+
+/**
+ * Shows a message in case expression test fails.
+ * @param {boolean} exp
+ * @param {straing} message
+ */
+function checkMessage(exp, message) {
+ if ( !exp )
+ _addSpan('<span><span class="warn">WARNING</span> ' + escapeHTML(_currentTestName) + ": " + escapeHTML(message) + '</span>');
+}
+
+function assertMsg(assertion, msg) {
+ if (assertion) {
+ testPassed(msg);
+ } else {
+ testFailed(msg);
+ }
+}
+
+/**
+ * Variation of the assertMsg function, with the option to not show (and thus not count) the test's pass result,
+ * and throw or not a TestFailedException in case of failure.
+ * @param {boolean} assertion If this is true, means success, else failure.
+ * @param {?string} msg The message to be shown in the result.
+ * @param {boolean} verbose In case of success, determines if the test will show it's result and count in the results.
+ * @param {boolean} exthrow In case of failure, determines if the function will throw a TestFailedException.
+ */
+function assertMsgOptions(assertion, msg, verbose, exthrow) {
+ if (assertion) {
+ testPassedOptions(msg, verbose);
+ } else {
+ testFailedOptions(msg, exthrow);
+ }
+}
+
+
+function webglHarnessCollectGarbage() {
+ if (window.GCController) {
+ window.GCController.collect();
+ return;
+ }
+
+ if (window.opera && window.opera.collect) {
+ window.opera.collect();
+ return;
+ }
+
+ try {
+ window.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
+ .getInterface(Components.interfaces.nsIDOMWindowUtils)
+ .garbageCollect();
+ return;
+ } catch(e) {}
+
+ if (window.gc) {
+ window.gc();
+ return;
+ }
+
+ if (window.CollectGarbage) {
+ CollectGarbage();
+ return;
+ }
+
+ // WebKit's MiniBrowser.
+ if (window.$vm) {
+ window.$vm.gc();
+ return;
+ }
+
+ function gcRec(n) {
+ if (n < 1)
+ return {};
+ var temp = {i: "ab" + i + (i / 100000)};
+ temp += "foo";
+ gcRec(n-1);
+ }
+ for (var i = 0; i < 1000; i++)
+ gcRec(10);
+}
+
+function finishTest() {
+ successfullyParsed = true;
+ var epilogue = document.createElement("script");
+ var basePath = "";
+ var expectedBase = "js-test-pre.js";
+ var scripts = document.getElementsByTagName('script');
+ for (var script, i = 0; script = scripts[i]; i++) {
+ var src = script.src;
+ var l = src.length;
+ if (src.substr(l - expectedBase.length) == expectedBase) {
+ basePath = src.substr(0, l - expectedBase.length);
+ break;
+ }
+ }
+ epilogue.src = basePath + "js-test-post.js";
+ document.body.appendChild(epilogue);
+}
+
+/// Prefer `call(() => { ... })` to `(() => { ... })()`\
+/// This way, it's clear up-front that we're calling not just defining.
+function call(fn) {
+ return fn();
+}
+
+/// `for (const i of range(3))` => 0, 1, 2
+/// Don't use `for...in range(n)`, it will not work.
+function* range(n) {
+ for (let i = 0; i < n; i++) {
+ yield i;
+ }
+}
diff --git a/dom/canvas/test/webgl-conf/checkout/js/pnglib.js b/dom/canvas/test/webgl-conf/checkout/js/pnglib.js
new file mode 100644
index 0000000000..d2a9b99e08
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/js/pnglib.js
@@ -0,0 +1,207 @@
+/**
+* A handy class to calculate color values.
+*
+* @version 1.0
+* @author Robert Eisele <robert@xarg.org>
+* @copyright Copyright (c) 2010, Robert Eisele
+* @link http://www.xarg.org/2010/03/generate-client-side-png-files-using-javascript/
+* @license http://www.opensource.org/licenses/bsd-license.php BSD License
+*
+*/
+
+(function() {
+
+ // helper functions for that ctx
+ function write(buffer, offs) {
+ for (var i = 2; i < arguments.length; i++) {
+ for (var j = 0; j < arguments[i].length; j++) {
+ buffer[offs++] = arguments[i].charAt(j);
+ }
+ }
+ }
+
+ function byte2(w) {
+ return String.fromCharCode((w >> 8) & 255, w & 255);
+ }
+
+ function byte4(w) {
+ return String.fromCharCode((w >> 24) & 255, (w >> 16) & 255, (w >> 8) & 255, w & 255);
+ }
+
+ function byte2lsb(w) {
+ return String.fromCharCode(w & 255, (w >> 8) & 255);
+ }
+
+ window.PNGlib = function(width,height,depth) {
+
+ this.width = width;
+ this.height = height;
+ this.depth = depth;
+
+ // pixel data and row filter identifier size
+ this.pix_size = height * (width + 1);
+
+ // deflate header, pix_size, block headers, adler32 checksum
+ this.data_size = 2 + this.pix_size + 5 * Math.floor((0xfffe + this.pix_size) / 0xffff) + 4;
+
+ // offsets and sizes of Png chunks
+ this.ihdr_offs = 0; // IHDR offset and size
+ this.ihdr_size = 4 + 4 + 13 + 4;
+ this.plte_offs = this.ihdr_offs + this.ihdr_size; // PLTE offset and size
+ this.plte_size = 4 + 4 + 3 * depth + 4;
+ this.trns_offs = this.plte_offs + this.plte_size; // tRNS offset and size
+ this.trns_size = 4 + 4 + depth + 4;
+ this.idat_offs = this.trns_offs + this.trns_size; // IDAT offset and size
+ this.idat_size = 4 + 4 + this.data_size + 4;
+ this.iend_offs = this.idat_offs + this.idat_size; // IEND offset and size
+ this.iend_size = 4 + 4 + 4;
+ this.buffer_size = this.iend_offs + this.iend_size; // total PNG size
+
+ this.buffer = new Array();
+ this.palette = new Object();
+ this.pindex = 0;
+
+ var _crc32 = new Array();
+
+ // initialize buffer with zero bytes
+ for (var i = 0; i < this.buffer_size; i++) {
+ this.buffer[i] = "\x00";
+ }
+
+ // initialize non-zero elements
+ write(this.buffer, this.ihdr_offs, byte4(this.ihdr_size - 12), 'IHDR', byte4(width), byte4(height), "\x08\x03");
+ write(this.buffer, this.plte_offs, byte4(this.plte_size - 12), 'PLTE');
+ write(this.buffer, this.trns_offs, byte4(this.trns_size - 12), 'tRNS');
+ write(this.buffer, this.idat_offs, byte4(this.idat_size - 12), 'IDAT');
+ write(this.buffer, this.iend_offs, byte4(this.iend_size - 12), 'IEND');
+
+ // initialize deflate header
+ var header = ((8 + (7 << 4)) << 8) | (3 << 6);
+ header+= 31 - (header % 31);
+
+ write(this.buffer, this.idat_offs + 8, byte2(header));
+
+ // initialize deflate block headers
+ for (var i = 0; (i << 16) - 1 < this.pix_size; i++) {
+ var size, bits;
+ if (i + 0xffff < this.pix_size) {
+ size = 0xffff;
+ bits = "\x00";
+ } else {
+ size = this.pix_size - (i << 16) - i;
+ bits = "\x01";
+ }
+ write(this.buffer, this.idat_offs + 8 + 2 + (i << 16) + (i << 2), bits, byte2lsb(size), byte2lsb(~size));
+ }
+
+ /* Create crc32 lookup table */
+ for (var i = 0; i < 256; i++) {
+ var c = i;
+ for (var j = 0; j < 8; j++) {
+ if (c & 1) {
+ c = -306674912 ^ ((c >> 1) & 0x7fffffff);
+ } else {
+ c = (c >> 1) & 0x7fffffff;
+ }
+ }
+ _crc32[i] = c;
+ }
+
+ // compute the index into a png for a given pixel
+ this.index = function(x,y) {
+ var i = y * (this.width + 1) + x + 1;
+ var j = this.idat_offs + 8 + 2 + 5 * Math.floor((i / 0xffff) + 1) + i;
+ return j;
+ }
+
+ // convert a color and build up the palette
+ this.color = function(red, green, blue, alpha) {
+
+ alpha = alpha >= 0 ? alpha : 255;
+ var color = (((((alpha << 8) | red) << 8) | green) << 8) | blue;
+
+ if (typeof this.palette[color] == "undefined") {
+ if (this.pindex == this.depth) return "\x00";
+
+ var ndx = this.plte_offs + 8 + 3 * this.pindex;
+
+ this.buffer[ndx + 0] = String.fromCharCode(red);
+ this.buffer[ndx + 1] = String.fromCharCode(green);
+ this.buffer[ndx + 2] = String.fromCharCode(blue);
+ this.buffer[this.trns_offs+8+this.pindex] = String.fromCharCode(alpha);
+
+ this.palette[color] = String.fromCharCode(this.pindex++);
+ }
+ return this.palette[color];
+ }
+
+ // output a PNG string, Base64 encoded
+ this.getBase64 = function() {
+
+ var s = this.getDump();
+
+ var ch = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
+ var c1, c2, c3, e1, e2, e3, e4;
+ var l = s.length;
+ var i = 0;
+ var r = "";
+
+ do {
+ c1 = s.charCodeAt(i);
+ e1 = c1 >> 2;
+ c2 = s.charCodeAt(i+1);
+ e2 = ((c1 & 3) << 4) | (c2 >> 4);
+ c3 = s.charCodeAt(i+2);
+ if (l < i+2) { e3 = 64; } else { e3 = ((c2 & 0xf) << 2) | (c3 >> 6); }
+ if (l < i+3) { e4 = 64; } else { e4 = c3 & 0x3f; }
+ r+= ch.charAt(e1) + ch.charAt(e2) + ch.charAt(e3) + ch.charAt(e4);
+ } while ((i+= 3) < l);
+ return r;
+ }
+
+ // output a PNG string
+ this.getDump = function() {
+
+ // compute adler32 of output pixels + row filter bytes
+ var BASE = 65521; /* largest prime smaller than 65536 */
+ var NMAX = 5552; /* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */
+ var s1 = 1;
+ var s2 = 0;
+ var n = NMAX;
+
+ for (var y = 0; y < this.height; y++) {
+ for (var x = -1; x < this.width; x++) {
+ s1+= this.buffer[this.index(x, y)].charCodeAt(0);
+ s2+= s1;
+ if ((n-= 1) == 0) {
+ s1%= BASE;
+ s2%= BASE;
+ n = NMAX;
+ }
+ }
+ }
+ s1%= BASE;
+ s2%= BASE;
+ write(this.buffer, this.idat_offs + this.idat_size - 8, byte4((s2 << 16) | s1));
+
+ // compute crc32 of the PNG chunks
+ function crc32(png, offs, size) {
+ var crc = -1;
+ for (var i = 4; i < size-4; i += 1) {
+ crc = _crc32[(crc ^ png[offs+i].charCodeAt(0)) & 0xff] ^ ((crc >> 8) & 0x00ffffff);
+ }
+ write(png, offs+size-4, byte4(crc ^ -1));
+ }
+
+ crc32(this.buffer, this.ihdr_offs, this.ihdr_size);
+ crc32(this.buffer, this.plte_offs, this.plte_size);
+ crc32(this.buffer, this.trns_offs, this.trns_size);
+ crc32(this.buffer, this.idat_offs, this.idat_size);
+ crc32(this.buffer, this.iend_offs, this.iend_size);
+
+ // convert PNG to string
+ return "\211PNG\r\n\032\n"+this.buffer.join('');
+ }
+ }
+
+})();
diff --git a/dom/canvas/test/webgl-conf/checkout/js/test-eval.js b/dom/canvas/test/webgl-conf/checkout/js/test-eval.js
new file mode 100644
index 0000000000..113e9c6008
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/js/test-eval.js
@@ -0,0 +1,15 @@
+/*
+Copyright (c) 2019 The Khronos Group Inc.
+Use of this source code is governed by an MIT-style license that can be
+found in the LICENSE.txt file.
+*/
+/**
+ * Calls eval.
+ *
+ * This is here so other modules can use "use strict":
+ */
+TestEval = function(str) {
+ return eval(str);
+};
+
+
diff --git a/dom/canvas/test/webgl-conf/checkout/js/tests/canvas-tests-utils.js b/dom/canvas/test/webgl-conf/checkout/js/tests/canvas-tests-utils.js
new file mode 100644
index 0000000000..7c30104379
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/js/tests/canvas-tests-utils.js
@@ -0,0 +1,825 @@
+/*
+Copyright (c) 2019 The Khronos Group Inc.
+Use of this source code is governed by an MIT-style license that can be
+found in the LICENSE.txt file.
+*/
+
+// Some variables that will be used in this file
+var canvas;
+var gl;
+var OES_vertex_array_object;
+var uniformLocation;
+var extension;
+var buffer;
+var framebuffer;
+var program;
+var renderbuffer;
+var shader;
+var texture;
+var arrayBuffer;
+var arrayBufferView;
+var vertexArrayObject;
+var imageData;
+var float32array;
+var int32array;
+
+var OES_texture_float;
+var new_WEBGL_lose_context;
+var allowRestore;
+var contextLostEventFired;
+var contextRestoredEventFired;
+var newExtension;
+
+function compareGLError(glError, evalStr) {
+ var exception;
+ try {
+ eval(evalStr);
+ } catch (e) {
+ exception = e;
+ }
+ if (exception) {
+ return false;
+ } else {
+ if (gl.getError() == glError)
+ return true;
+ return false;
+ }
+}
+
+function contextCreation(contextType) {
+ canvas = new OffscreenCanvas(10, 10);
+ gl = canvas.getContext(contextType);
+
+ if (contextType == 'webgl') {
+ if (gl instanceof WebGLRenderingContext)
+ return true;
+ return false;
+ } else if (contextType == 'webgl2') {
+ if (gl instanceof WebGL2RenderingContext)
+ return true;
+ return false;
+ } else {
+ return false;
+ }
+}
+
+function transferredOffscreenCanvasCreation(placeholder, width, height) {
+ placeholder.width = width;
+ placeholder.height = height;
+ return placeholder.transferControlToOffscreen();
+}
+
+function assertWidthAndHeight(entity, entityName, width, height) {
+ if (entity.width == width && entity.height == height) {
+ testPassed("The width and height of " + entityName + " are correct.");
+ return;
+ }
+ var errMsg = "";
+ if (entity.width != width) {
+ errMsg += "The width of " + entityName + " is " + entity.width + " while expected value is " + width + ". ";
+ }
+ if (entity.height != height) {
+ errMsg += "The height of " + entityName + " is " + entity.height + " while expected value is " + height + ". ";
+ }
+ testFailed(errMsg);
+}
+
+var webgl1Methods = [
+ "getContextAttributes",
+ "activeTexture",
+ "attachShader",
+ "bindAttribLocation",
+ "bindBuffer",
+ "bindFramebuffer",
+ "bindRenderbuffer",
+ "bindTexture",
+ "blendColor",
+ "blendEquation",
+ "blendEquationSeparate",
+ "blendFunc",
+ "blendFuncSeparate",
+ "bufferData",
+ "bufferSubData",
+ "checkFramebufferStatus",
+ "clear",
+ "clearColor",
+ "clearDepth",
+ "clearStencil",
+ "colorMask",
+ "compileShader",
+ "compressedTexImage2D",
+ "compressedTexSubImage2D",
+ "copyTexImage2D",
+ "copyTexSubImage2D",
+ "createBuffer",
+ "createFramebuffer",
+ "createProgram",
+ "createRenderbuffer",
+ "createShader",
+ "createTexture",
+ "cullFace",
+ "deleteBuffer",
+ "deleteFramebuffer",
+ "deleteProgram",
+ "deleteRenderbuffer",
+ "deleteShader",
+ "deleteTexture",
+ "depthFunc",
+ "depthMask",
+ "depthRange",
+ "detachShader",
+ "disable",
+ "disableVertexAttribArray",
+ "drawArrays",
+ "drawElements",
+ "enable",
+ "enableVertexAttribArray",
+ "finish",
+ "flush",
+ "framebufferRenderbuffer",
+ "framebufferTexture2D",
+ "frontFace",
+ "generateMipmap",
+ "getActiveAttrib",
+ "getActiveUniform",
+ "getAttachedShaders",
+ "getAttribLocation",
+ "getParameter",
+ "getBufferParameter",
+ "getError",
+ "getExtension",
+ "getFramebufferAttachmentParameter",
+ "getProgramParameter",
+ "getProgramInfoLog",
+ "getRenderbufferParameter",
+ "getShaderParameter",
+ "getShaderInfoLog",
+ "getShaderPrecisionFormat",
+ "getShaderSource",
+ "getSupportedExtensions",
+ "getTexParameter",
+ "getUniform",
+ "getUniformLocation",
+ "getVertexAttrib",
+ "getVertexAttribOffset",
+ "hint",
+ "isBuffer",
+ "isContextLost",
+ "isEnabled",
+ "isFramebuffer",
+ "isProgram",
+ "isRenderbuffer",
+ "isShader",
+ "isTexture",
+ "lineWidth",
+ "linkProgram",
+ "pixelStorei",
+ "polygonOffset",
+ "readPixels",
+ "renderbufferStorage",
+ "sampleCoverage",
+ "scissor",
+ "shaderSource",
+ "stencilFunc",
+ "stencilFuncSeparate",
+ "stencilMask",
+ "stencilMaskSeparate",
+ "stencilOp",
+ "stencilOpSeparate",
+ "texImage2D",
+ "texParameterf",
+ "texParameteri",
+ "texSubImage2D",
+ "uniform1f",
+ "uniform1fv",
+ "uniform1i",
+ "uniform1iv",
+ "uniform2f",
+ "uniform2fv",
+ "uniform2i",
+ "uniform2iv",
+ "uniform3f",
+ "uniform3fv",
+ "uniform3i",
+ "uniform3iv",
+ "uniform4f",
+ "uniform4fv",
+ "uniform4i",
+ "uniform4iv",
+ "uniformMatrix2fv",
+ "uniformMatrix3fv",
+ "uniformMatrix4fv",
+ "useProgram",
+ "validateProgram",
+ "vertexAttrib1f",
+ "vertexAttrib1fv",
+ "vertexAttrib2f",
+ "vertexAttrib2fv",
+ "vertexAttrib3f",
+ "vertexAttrib3fv",
+ "vertexAttrib4f",
+ "vertexAttrib4fv",
+ "vertexAttribPointer",
+ "viewport",
+];
+
+var webgl2Methods = [
+ "getBufferSubData",
+ "copyBufferSubData",
+ "blitFramebuffer",
+ "framebufferTextureLayer",
+ "getInternalformatParameter",
+ "invalidateFramebuffer",
+ "invalidateSubFramebuffer",
+ "readBuffer",
+ "renderbufferStorageMultisample",
+ "texImage3D",
+ "texStorage2D",
+ "texStorage3D",
+ "texSubImage3D",
+ "copyTexSubImage3D",
+ "compressedTexImage3D",
+ "compressedTexSubImage3D",
+ "getFragDataLocation",
+ "uniform1ui",
+ "uniform2ui",
+ "uniform3ui",
+ "uniform4ui",
+ "uniform1uiv",
+ "uniform2uiv",
+ "uniform3uiv",
+ "uniform4uiv",
+ "uniformMatrix2x3fv",
+ "uniformMatrix3x2fv",
+ "uniformMatrix2x4fv",
+ "uniformMatrix4x2fv",
+ "uniformMatrix3x4fv",
+ "uniformMatrix4x3fv",
+ "vertexAttribI4i",
+ "vertexAttribI4iv",
+ "vertexAttribI4ui",
+ "vertexAttribI4uiv",
+ "vertexAttribIPointer",
+ "vertexAttribDivisor",
+ "drawArraysInstanced",
+ "drawElementsInstanced",
+ "drawRangeElements",
+ "drawBuffers",
+ "clearBufferiv",
+ "clearBufferuiv",
+ "clearBufferfv",
+ "clearBufferfi",
+ "createQuery",
+ "deleteQuery",
+ "isQuery",
+ "beginQuery",
+ "endQuery",
+ "getQuery",
+ "getQueryParameter",
+ "createSampler",
+ "deleteSampler",
+ "isSampler",
+ "bindSampler",
+ "samplerParameteri",
+ "samplerParameterf",
+ "getSamplerParameter",
+ "fenceSync",
+ "isSync",
+ "deleteSync",
+ "clientWaitSync",
+ "waitSync",
+ "getSyncParameter",
+ "createTransformFeedback",
+ "deleteTransformFeedback",
+ "isTransformFeedback",
+ "bindTransformFeedback",
+ "beginTransformFeedback",
+ "endTransformFeedback",
+ "transformFeedbackVaryings",
+ "getTransformFeedbackVarying",
+ "pauseTransformFeedback",
+ "resumeTransformFeedback",
+ "bindBufferBase",
+ "bindBufferRange",
+ "getIndexedParameter",
+ "getUniformIndices",
+ "getActiveUniforms",
+ "getUniformBlockIndex",
+ "getActiveUniformBlockParameter",
+ "getActiveUniformBlockName",
+ "uniformBlockBinding",
+ "createVertexArray",
+ "deleteVertexArray",
+ "isVertexArray",
+ "bindVertexArray",
+];
+
+function assertFunction(v, f) {
+ try {
+ if (typeof v[f] != "function") {
+ return false;
+ } else {
+ return true;
+ }
+ } catch(e) {
+ return false;
+ }
+}
+
+function testAPIs(contextType) {
+ canvas = new OffscreenCanvas(10, 10);
+ gl = canvas.getContext(contextType);
+ var passed = true;
+ var methods;
+ if (contextType == 'webgl')
+ methods = webgl1Methods;
+ else
+ methods = webgl1Methods.concat(webgl2Methods);
+ for (var i=0; i<methods.length; i++) {
+ var r = assertFunction(gl, methods[i]);
+ passed = passed && r;
+ }
+
+ methods.push(...["makeXRCompatible"]);
+ var extended = false;
+ for (var i in gl) {
+ if (typeof gl[i] == "function" && methods.indexOf(i) == -1) {
+ if (!extended) {
+ extended = true;
+ }
+ }
+ }
+
+ if (!passed || extended)
+ return false;
+ return true;
+}
+
+var simpleTextureVertexShader = [
+ 'attribute vec4 vPosition;',
+ 'attribute vec2 texCoord0;',
+ 'varying vec2 texCoord;',
+ 'void main() {',
+ ' gl_Position = vPosition;',
+ ' texCoord = texCoord0;',
+ '}'].join('\n');
+
+var simpleTextureFragmentShader = [
+ 'precision mediump float;',
+ 'uniform sampler2D tex;',
+ 'varying vec2 texCoord;',
+ 'void main() {',
+ ' gl_FragData[0] = texture2D(tex, texCoord);',
+ '}'].join('\n');
+
+function getShader(gl, shaderStr, type)
+{
+ var shader = gl.createShader(type);
+ gl.shaderSource(shader, shaderStr);
+ gl.compileShader(shader);
+
+ if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS))
+ return null;
+ return shader;
+}
+
+function setupProgram(gl, shaders, opt_attribs, opt_locations)
+{
+ var vertexShader = getShader(gl, simpleTextureVertexShader, gl.VERTEX_SHADER);
+ var fragmentShader = getShader(gl, simpleTextureFragmentShader, gl.FRAGMENT_SHADER);
+ var program = gl.createProgram();
+ gl.attachShader(program, vertexShader);
+ gl.attachShader(program, fragmentShader);
+
+ if (opt_attribs) {
+ for (var ii = 0; ii < opt_attribs.length; ++ii) {
+ gl.bindAttribLocation(
+ program,
+ opt_locations ? opt_locations[ii] : ii,
+ opt_attribs[ii]);
+ }
+ }
+ gl.linkProgram(program);
+
+ // Check the link status
+ var linked = gl.getProgramParameter(program, gl.LINK_STATUS);
+ if (!linked) {
+ // something went wrong with the link
+ gl.deleteProgram(program);
+ return null;
+ }
+ gl.useProgram(program);
+ return program;
+}
+
+function setupSimpleTextureProgram(gl, opt_positionLocation, opt_texcoordLocation)
+{
+ opt_positionLocation = opt_positionLocation || 0;
+ opt_texcoordLocation = opt_texcoordLocation || 1;
+ return setupProgram(gl,
+ [simpleTextureVertexShader, simpleTextureFragmentShader],
+ ['vPosition', 'texCoord0'],
+ [opt_positionLocation, opt_texcoordLocation]);
+}
+
+function testLostContextWithoutRestore()
+{
+ // Functions with special return values.
+ if (!gl.isContextLost())
+ return false;
+
+ if (gl.getError() != gl.CONTEXT_LOST_WEBGL)
+ return false;
+ if (gl.getError() != gl.NO_ERROR)
+ return false;
+
+ if (gl.checkFramebufferStatus(gl.FRAMEBUFFER) != gl.FRAMEBUFFER_UNSUPPORTED ||
+ gl.getAttribLocation(program, 'u_modelViewProjMatrix') != -1 ||
+ gl.getVertexAttribOffset(0, gl.VERTEX_ATTRIB_ARRAY_POINTER) != 0)
+ return false;
+
+ // Test the extension itself.
+ if (!compareGLError(gl.INVALID_OPERATION, "extension.loseContext()"))
+ return false;
+
+ imageData = new ImageData(1, 1);
+ float32array = new Float32Array(1);
+ int32array = new Int32Array(1);
+
+ // Functions returning void should return immediately.
+ // This is untestable, but we can at least be sure they cause no errors
+ // and the codepaths are exercised.
+ if (!compareGLError(gl.NO_ERROR, "gl.activeTexture(gl.TEXTURE0)") ||
+ !compareGLError(gl.NO_ERROR, "gl.attachShader(program, shader)") ||
+ !compareGLError(gl.NO_ERROR, "gl.bindBuffer(gl.ARRAY_BUFFER, buffer)") ||
+ !compareGLError(gl.NO_ERROR, "gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer)") ||
+ !compareGLError(gl.NO_ERROR, "gl.bindRenderbuffer(gl.RENDERBUFFER, renderbuffer)") ||
+ !compareGLError(gl.NO_ERROR, "gl.bindTexture(gl.TEXTURE_2D, texture)") ||
+ !compareGLError(gl.NO_ERROR, "gl.blendColor(1.0, 1.0, 1.0, 1.0)") ||
+ !compareGLError(gl.NO_ERROR, "gl.blendEquation(gl.FUNC_ADD)") ||
+ !compareGLError(gl.NO_ERROR, "gl.blendEquationSeparate(gl.FUNC_ADD, gl.FUNC_ADD)") ||
+ !compareGLError(gl.NO_ERROR, "gl.blendFunc(gl.ONE, gl.ONE)") ||
+ !compareGLError(gl.NO_ERROR, "gl.blendFuncSeparate(gl.ONE, gl.ONE, gl.ONE, gl.ONE)") ||
+ !compareGLError(gl.NO_ERROR, "gl.bufferData(gl.ARRAY_BUFFER, 0, gl.STATIC_DRAW)") ||
+ !compareGLError(gl.NO_ERROR, "gl.bufferData(gl.ARRAY_BUFFER, arrayBufferView, gl.STATIC_DRAW)") ||
+ !compareGLError(gl.NO_ERROR, "gl.bufferData(gl.ARRAY_BUFFER, arrayBuffer, gl.STATIC_DRAW)") ||
+ !compareGLError(gl.NO_ERROR, "gl.bufferSubData(gl.ARRAY_BUFFRE, 0, arrayBufferView)") ||
+ !compareGLError(gl.NO_ERROR, "gl.bufferSubData(gl.ARRAY_BUFFRE, 0, arrayBuffer)") ||
+ !compareGLError(gl.NO_ERROR, "gl.clear(gl.COLOR_BUFFER_BIT)") ||
+ !compareGLError(gl.NO_ERROR, "gl.clearColor(1, 1, 1, 1)") ||
+ !compareGLError(gl.NO_ERROR, "gl.clearDepth(1)") ||
+ !compareGLError(gl.NO_ERROR, "gl.clearStencil(0)") ||
+ !compareGLError(gl.NO_ERROR, "gl.colorMask(1, 1, 1, 1)") ||
+ !compareGLError(gl.NO_ERROR, "gl.compileShader(shader)") ||
+ !compareGLError(gl.NO_ERROR, "gl.copyTexImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 0, 0, 0, 0, 0)") ||
+ !compareGLError(gl.NO_ERROR, "gl.copyTexSubImage2D(gl.TEXTURE_2D, 0, 0, 0, 0, 0, 0, 0)") ||
+ !compareGLError(gl.NO_ERROR, "gl.cullFace(gl.FRONT)") ||
+ !compareGLError(gl.NO_ERROR, "gl.deleteBuffer(buffer)") ||
+ !compareGLError(gl.NO_ERROR, "gl.deleteFramebuffer(framebuffer)") ||
+ !compareGLError(gl.NO_ERROR, "gl.deleteProgram(program)") ||
+ !compareGLError(gl.NO_ERROR, "gl.deleteRenderbuffer(renderbuffer)") ||
+ !compareGLError(gl.NO_ERROR, "gl.deleteShader(shader)") ||
+ !compareGLError(gl.NO_ERROR, "gl.deleteTexture(texture)") ||
+ !compareGLError(gl.NO_ERROR, "gl.depthFunc(gl.NEVER)") ||
+ !compareGLError(gl.NO_ERROR, "gl.depthMask(0)") ||
+ !compareGLError(gl.NO_ERROR, "gl.depthRange(0, 1)") ||
+ !compareGLError(gl.NO_ERROR, "gl.detachShader(program, shader)") ||
+ !compareGLError(gl.NO_ERROR, "gl.disable(gl.BLEND)") ||
+ !compareGLError(gl.NO_ERROR, "gl.disableVertexAttribArray(0)") ||
+ !compareGLError(gl.NO_ERROR, "gl.drawArrays(gl.POINTS, 0, 0)") ||
+ !compareGLError(gl.NO_ERROR, "gl.drawElements(gl.POINTS, 0, gl.UNSIGNED_SHORT, 0)") ||
+ !compareGLError(gl.NO_ERROR, "gl.enable(gl.BLEND)") ||
+ !compareGLError(gl.NO_ERROR, "gl.enableVertexAttribArray(0)") ||
+ !compareGLError(gl.NO_ERROR, "gl.finish()") ||
+ !compareGLError(gl.NO_ERROR, "gl.flush()") ||
+ !compareGLError(gl.NO_ERROR, "gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, renderbuffer)") ||
+ !compareGLError(gl.NO_ERROR, "gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture, 0)") ||
+ !compareGLError(gl.NO_ERROR, "gl.frontFace(gl.CW)") ||
+ !compareGLError(gl.NO_ERROR, "gl.generateMipmap(gl.TEXTURE_2D)") ||
+ !compareGLError(gl.NO_ERROR, "gl.hint(gl.GENERATE_MIPMAP_HINT, gl.FASTEST)") ||
+ !compareGLError(gl.NO_ERROR, "gl.lineWidth(0)") ||
+ !compareGLError(gl.NO_ERROR, "gl.linkProgram(program)") ||
+ !compareGLError(gl.NO_ERROR, "gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, 0)") ||
+ !compareGLError(gl.NO_ERROR, "gl.polygonOffset(0, 0)") ||
+ !compareGLError(gl.NO_ERROR, "gl.readPixels(0, 0, 0, 0, gl.RGBA, gl.UNSIGNED_BYTE, arrayBufferView)") ||
+ !compareGLError(gl.NO_ERROR, "gl.renderbufferStorage(gl.RENDERBUFFER, gl.RGBA4, 0, 0)") ||
+ !compareGLError(gl.NO_ERROR, "gl.sampleCoverage(0, 0)") ||
+ !compareGLError(gl.NO_ERROR, "gl.scissor(0, 0, 0, 0)") ||
+ !compareGLError(gl.NO_ERROR, "gl.shaderSource(shader, '')") ||
+ !compareGLError(gl.NO_ERROR, "gl.stencilFunc(gl.NEVER, 0, 0)") ||
+ !compareGLError(gl.NO_ERROR, "gl.stencilFuncSeparate(gl.FRONT, gl.NEVER, 0, 0)") ||
+ !compareGLError(gl.NO_ERROR, "gl.stencilMask(0)") ||
+ !compareGLError(gl.NO_ERROR, "gl.stencilMaskSeparate(gl.FRONT, 0)") ||
+ !compareGLError(gl.NO_ERROR, "gl.stencilOp(gl.KEEP, gl.KEEP, gl.KEEP)") ||
+ !compareGLError(gl.NO_ERROR, "gl.stencilOpSeparate(gl.FRONT, gl.KEEP, gl.KEEP, gl.KEEP)") ||
+ !compareGLError(gl.NO_ERROR, "gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 0, 0, 0, gl.RGBA, gl.UNSIGNED_BYTE, arrayBufferView)") ||
+ !compareGLError(gl.NO_ERROR, "gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, imageData)") ||
+ !compareGLError(gl.NO_ERROR, "gl.texParameterf(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST)") ||
+ !compareGLError(gl.NO_ERROR, "gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST)") ||
+ !compareGLError(gl.NO_ERROR, "gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0, 0, 0, gl.RGBA, gl.UNSIGNED_BYTE, arrayBufferView)") ||
+ !compareGLError(gl.NO_ERROR, "gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0, gl.RGBA, gl.UNSIGNED_BYTE, imageData)") ||
+ !compareGLError(gl.NO_ERROR, "gl.uniform1f(uniformLocation, 0)") ||
+ !compareGLError(gl.NO_ERROR, "gl.uniform1fv(uniformLocation, float32array)") ||
+ !compareGLError(gl.NO_ERROR, "gl.uniform1fv(uniformLocation, [0])") ||
+ !compareGLError(gl.NO_ERROR, "gl.uniform1i(uniformLocation, 0)") ||
+ !compareGLError(gl.NO_ERROR, "gl.uniform1iv(uniformLocation, int32array)") ||
+ !compareGLError(gl.NO_ERROR, "gl.uniform1iv(uniformLocation, [0])") ||
+ !compareGLError(gl.NO_ERROR, "gl.uniform2f(uniformLocation, 0, 0)") ||
+ !compareGLError(gl.NO_ERROR, "gl.uniform2fv(uniformLocation, float32array)") ||
+ !compareGLError(gl.NO_ERROR, "gl.uniform2fv(uniformLocation, [0, 0])") ||
+ !compareGLError(gl.NO_ERROR, "gl.uniform2i(uniformLocation, 0, 0)") ||
+ !compareGLError(gl.NO_ERROR, "gl.uniform2iv(uniformLocation, int32array)") ||
+ !compareGLError(gl.NO_ERROR, "gl.uniform2iv(uniformLocation, [0, 0])") ||
+ !compareGLError(gl.NO_ERROR, "gl.uniform3f(uniformLocation, 0, 0, 0)") ||
+ !compareGLError(gl.NO_ERROR, "gl.uniform3fv(uniformLocation, float32array)") ||
+ !compareGLError(gl.NO_ERROR, "gl.uniform3fv(uniformLocation, [0, 0, 0])") ||
+ !compareGLError(gl.NO_ERROR, "gl.uniform3i(uniformLocation, 0, 0, 0)") ||
+ !compareGLError(gl.NO_ERROR, "gl.uniform3iv(uniformLocation, int32array)") ||
+ !compareGLError(gl.NO_ERROR, "gl.uniform3iv(uniformLocation, [0, 0, 0])") ||
+ !compareGLError(gl.NO_ERROR, "gl.uniform4f(uniformLocation, 0, 0, 0, 0)") ||
+ !compareGLError(gl.NO_ERROR, "gl.uniform4fv(uniformLocation, float32array)") ||
+ !compareGLError(gl.NO_ERROR, "gl.uniform4fv(uniformLocation, [0, 0, 0, 0])") ||
+ !compareGLError(gl.NO_ERROR, "gl.uniform4i(uniformLocation, 0, 0, 0, 0)") ||
+ !compareGLError(gl.NO_ERROR, "gl.uniform4iv(uniformLocation, int32array)") ||
+ !compareGLError(gl.NO_ERROR, "gl.uniform4iv(uniformLocation, [0, 0, 0, 0])") ||
+ !compareGLError(gl.NO_ERROR, "gl.uniformMatrix2fv(uniformLocation, false, float32array)") ||
+ !compareGLError(gl.NO_ERROR, "gl.uniformMatrix2fv(uniformLocation, false, [0, 0, 0, 0])") ||
+ !compareGLError(gl.NO_ERROR, "gl.uniformMatrix3fv(uniformLocation, false, float32array)") ||
+ !compareGLError(gl.NO_ERROR, "gl.uniformMatrix3fv(uniformLocation, false, [0, 0, 0, 0, 0, 0, 0, 0, 0])") ||
+ !compareGLError(gl.NO_ERROR, "gl.uniformMatrix4fv(uniformLocation, false, float32array)") ||
+ !compareGLError(gl.NO_ERROR, "gl.uniformMatrix4fv(uniformLocation, false, [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])") ||
+ !compareGLError(gl.NO_ERROR, "gl.useProgram(program)") ||
+ !compareGLError(gl.NO_ERROR, "gl.validateProgram(program)") ||
+ !compareGLError(gl.NO_ERROR, "gl.vertexAttrib1f(0, 0)") ||
+ !compareGLError(gl.NO_ERROR, "gl.vertexAttrib1fv(0, float32array)") ||
+ !compareGLError(gl.NO_ERROR, "gl.vertexAttrib1fv(0, [0])") ||
+ !compareGLError(gl.NO_ERROR, "gl.vertexAttrib2f(0, 0, 0)") ||
+ !compareGLError(gl.NO_ERROR, "gl.vertexAttrib2fv(0, float32array)") ||
+ !compareGLError(gl.NO_ERROR, "gl.vertexAttrib2fv(0, [0, 0])") ||
+ !compareGLError(gl.NO_ERROR, "gl.vertexAttrib3f(0, 0, 0, 0)") ||
+ !compareGLError(gl.NO_ERROR, "gl.vertexAttrib3fv(0, float32array)") ||
+ !compareGLError(gl.NO_ERROR, "gl.vertexAttrib3fv(0, [0, 0, 0])") ||
+ !compareGLError(gl.NO_ERROR, "gl.vertexAttrib4f(0, 0, 0, 0, 0)") ||
+ !compareGLError(gl.NO_ERROR, "gl.vertexAttrib4fv(0, float32array)") ||
+ !compareGLError(gl.NO_ERROR, "gl.vertexAttrib4fv(0, [0, 0, 0, 0])") ||
+ !compareGLError(gl.NO_ERROR, "gl.vertexAttribPointer(0, 0, gl.FLOAT, false, 0, 0)") ||
+ !compareGLError(gl.NO_ERROR, "gl.viewport(0, 0, 0, 0)"))
+ return false;
+
+ // Functions return nullable values should all return null.
+ if (gl.createBuffer() != null ||
+ gl.createFramebuffer() != null ||
+ gl.createProgram() != null ||
+ gl.createRenderbuffer() != null ||
+ gl.createShader(gl.GL_VERTEX_SHADER) != null ||
+ gl.createTexture() != null ||
+ gl.getActiveAttrib(program, 0) != null ||
+ gl.getActiveUniform(program, 0) != null ||
+ gl.getAttachedShaders(program) != null ||
+ gl.getBufferParameter(gl.ARRAY_BUFFER, gl.BUFFER_SIZE) != null ||
+ gl.getContextAttributes() != null ||
+ gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME) != null ||
+ gl.getParameter(gl.CURRENT_PROGRAM) != null ||
+ gl.getProgramInfoLog(program) != null ||
+ gl.getProgramParameter(program, gl.LINK_STATUS) != null ||
+ gl.getRenderbufferParameter(gl.RENDERBUFFER, gl.RENDERBUFFER_WIDTH) != null ||
+ gl.getShaderInfoLog(shader) != null ||
+ gl.getShaderParameter(shader, gl.SHADER_TYPE) != null ||
+ gl.getShaderSource(shader) != null ||
+ gl.getTexParameter(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S) != null ||
+ gl.getUniform(program, uniformLocation) != null ||
+ gl.getUniformLocation(program, 'vPosition') != null ||
+ gl.getVertexAttrib(0, gl.VERTEX_ATTRIB_ARRAY_BUFFER_BINDING) != null ||
+ gl.getSupportedExtensions() != null ||
+ gl.getExtension("WEBGL_lose_context") != null)
+ return false;
+
+ // "Is" queries should all return false.
+ if (gl.isBuffer(buffer) || gl.isEnabled(gl.BLEND) || gl.isFramebuffer(framebuffer) ||
+ gl.isProgram(program) || gl.isRenderbuffer(renderbuffer) || gl.isShader(shader) ||
+ gl.isTexture(texture))
+ return false;
+
+ if (gl.getError() != gl.NO_ERROR)
+ return false;
+
+ // test extensions
+ if (OES_vertex_array_object) {
+ if (!compareGLError(gl.NO_ERROR, "OES_vertex_array_object.bindVertexArrayOES(vertexArrayObject)") ||
+ !compareGLError(gl.NO_ERROR, "OES_vertex_array_object.isVertexArrayOES(vertexArrayObject)") ||
+ !compareGLError(gl.NO_ERROR, "OES_vertex_array_object.deleteVertexArrayOES(vertexArrayObject)"))
+ return false;
+ if (OES_vertex_array_object.createVertexArrayOES() != null)
+ return false;
+ }
+ return true;
+}
+function testValidContext()
+{
+ if (gl.isContextLost())
+ return false;
+
+ arrayBuffer = new ArrayBuffer(4);
+ arrayBufferView = new Int8Array(arrayBuffer);
+
+ // Generate resources for testing.
+ buffer = gl.createBuffer();
+ gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
+ framebuffer = gl.createFramebuffer();
+ gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer);
+ program = setupSimpleTextureProgram(gl);
+ renderbuffer = gl.createRenderbuffer();
+ gl.bindRenderbuffer(gl.RENDERBUFFER, renderbuffer);
+ shader = gl.createShader(gl.VERTEX_SHADER);
+ texture = gl.createTexture();
+ gl.bindTexture(gl.TEXTURE_2D, texture);
+ if (gl.getError() != gl.NO_ERROR)
+ return false;
+
+ // Test is queries that will later be false
+ if (!compareGLError(gl.NO_ERROR, "gl.enable(gl.BLEND)"))
+ return false;
+ if (!gl.isBuffer(buffer) || !gl.isEnabled(gl.BLEND) || !gl.isFramebuffer(framebuffer) ||
+ !gl.isProgram(program) || !gl.isRenderbuffer(renderbuffer) || !gl.isShader(shader) ||
+ !gl.isTexture(texture))
+ return false;
+
+ if (OES_vertex_array_object) {
+ vertexArrayObject = OES_vertex_array_object.createVertexArrayOES();
+ if (gl.getError() != gl.NO_ERROR)
+ return false;
+ if (!OES_vertex_array_object.isVertexArrayOES(vertexArrayObject))
+ return false;
+ }
+ return true;
+}
+
+function setupTest()
+{
+ canvas = new OffscreenCanvas(10, 10);
+ gl = canvas.getContext('webgl');
+ WEBGL_lose_context = gl.getExtension("WEBGL_lose_context");
+ if (!WEBGL_lose_context)
+ return false;
+
+ // Try to get a few extensions
+ OES_vertex_array_object = gl.getExtension("OES_vertex_array_object");
+ OES_texture_float = gl.getExtension("OES_texture_float");
+
+ return true;
+}
+
+function testOriginalContext()
+{
+ if (gl.isContextLost())
+ return false;
+ if (gl.getError() != gl.NO_ERROR)
+ return false;
+ return true;
+}
+
+function testLostContext(e)
+{
+ if (contextLostEventFired)
+ return false;
+ contextLostEventFired = true;
+ if (!gl.isContextLost())
+ return false;
+ if (gl.getError() != gl.NO_ERROR)
+ return false;
+ if (allowRestore)
+ e.preventDefault();
+ return true;
+}
+
+function testLosingAndRestoringContext()
+{
+ return new Promise(function(resolve, reject) {
+ if (!setupTest())
+ reject("Test failed");
+
+ canvas.addEventListener("webglcontextlost", function(e) {
+ if (!testLostContext(e))
+ reject("Test failed");
+ // restore the context after this event has exited.
+ setTimeout(function() {
+ if (!compareGLError(gl.NO_ERROR, "WEBGL_lose_context.restoreContext()"))
+ reject("Test failed");
+ // The context should still be lost. It will not get restored until the
+ // webglrestorecontext event is fired.
+ if (!gl.isContextLost())
+ reject("Test failed");
+ if (gl.getError() != gl.NO_ERROR)
+ reject("Test failed");
+ // gl methods should still be no-ops
+ if (!compareGLError(gl.NO_ERROR, "gl.blendFunc(gl.TEXTURE_2D, gl.TEXTURE_CUBE_MAP)"))
+ reject("Test failed");
+ }, 0);
+ });
+ canvas.addEventListener("webglcontextrestored", function() {
+ if (!testRestoredContext())
+ reject("Test failed");
+ else
+ resolve("Test passed");
+ });
+ allowRestore = true;
+ contextLostEventFired = false;
+ contextRestoredEventFired = false;
+
+ if (!testOriginalContext())
+ reject("Test failed");
+ WEBGL_lose_context.loseContext();
+ // The context should be lost immediately.
+ if (!gl.isContextLost())
+ reject("Test failed");
+ if (gl.getError() != gl.CONTEXT_LOST_WEBGL)
+ reject("Test failed");
+ if (gl.getError() != gl.NO_ERROR)
+ reject("Test failed");
+ // gl methods should be no-ops
+ if (!compareGLError(gl.NO_ERROR, "gl.blendFunc(gl.TEXTURE_2D, gl.TEXTURE_CUBE_MAP)"))
+ reject("Test failed");
+ // but the event should not have been fired.
+ if (contextLostEventFired)
+ reject("Test failed");
+ });
+}
+
+function reGetExtensionAndTestForProperty(gl, name, expectProperty) {
+ var newExtension = gl.getExtension(name);
+ // NOTE: while getting a extension after context lost/restored is allowed to fail
+ // for the purpose the conformance tests it is not.
+ //
+ // Hypothetically the user can switch GPUs live. For example on Windows, install 2 GPUs,
+ // then in the control panen enable 1, disable the others and visa versa. Since the GPUs
+ // have different capabilities one or the other may not support a particlar extension.
+ //
+ // But, for the purpose of the conformance tests the context is expected to restore
+ // on the same GPU and therefore the extensions that succeeded previously should
+ // succeed on restore.
+ if (newExtension == null)
+ return false;
+ if (expectProperty) {
+ if (!(newExtension.webglTestProperty === true))
+ return false;
+ } else {
+ if (!(newExtension.webglTestProperty === undefined))
+ return false;
+ }
+ return newExtension;
+}
+
+
+function testOESTextureFloat() {
+ if (OES_texture_float) {
+ // Extension must still be lost.
+ var tex = gl.createTexture();
+ gl.bindTexture(gl.TEXTURE_2D, tex);
+ if (!compareGLError(gl.INVALID_ENUM, "gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.FLOAT, null)"))
+ return false;
+ // Try re-enabling extension
+ OES_texture_float = reGetExtensionAndTestForProperty(gl, "OES_texture_float", false);
+ if (!compareGLError(gl.NO_ERROR, "gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.FLOAT, null)"))
+ return false;
+ return true;
+ }
+}
+
+function testOESVertexArrayObject() {
+ if (OES_vertex_array_object) {
+ // Extension must still be lost.
+ if (OES_vertex_array_object.createVertexArrayOES() != null)
+ return false;
+ // Try re-enabling extension
+
+ var old_OES_vertex_array_object = OES_vertex_array_object;
+ OES_vertex_array_object = reGetExtensionAndTestForProperty(gl, "OES_vertex_array_object", false);
+ if (OES_vertex_array_object.createVertexArrayOES() == null)
+ return false;
+ if (old_OES_vertex_array_object.createVertexArrayOES() != null)
+ return false;
+ return true;
+ }
+}
+
+function testExtensions() {
+ if (!testOESTextureFloat() || !testOESVertexArrayObject())
+ return false;
+ return true;
+}
+
+function testRestoredContext()
+{
+ if (contextRestoredEventFired)
+ return false;
+ contextRestoredEventFired = true;
+ if (gl.isContextLost())
+ return false;
+ if (gl.getError() != gl.NO_ERROR)
+ return false;
+
+ if (!testExtensions())
+ return false;
+ return true;
+}
+
diff --git a/dom/canvas/test/webgl-conf/checkout/js/tests/clipping-wide-points.js b/dom/canvas/test/webgl-conf/checkout/js/tests/clipping-wide-points.js
new file mode 100644
index 0000000000..6b8fc00599
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/js/tests/clipping-wide-points.js
@@ -0,0 +1,92 @@
+/*
+Copyright (c) 2019 The Khronos Group Inc.
+Use of this source code is governed by an MIT-style license that can be
+found in the LICENSE.txt file.
+*/
+
+'use strict';
+description("This test ensures clipping works with wide points whose centers are out of the viewport");
+
+var wtu = WebGLTestUtils;
+var gl = wtu.create3DContext("testbed", undefined, contextVersion);
+
+var pointSize;
+
+function setupProgram() {
+ var vs = "attribute vec4 pos;" +
+ "uniform float pointSize; " +
+ "void main() {" +
+ " gl_PointSize = pointSize;" +
+ " gl_Position = pos;" +
+ "}";
+ var fs = "precision mediump float;" +
+ "void main() {" +
+ " gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);" +
+ "}";
+ var program = wtu.setupProgram(gl, [vs, fs], ['pos']);
+ if (program) {
+ var loc = gl.getUniformLocation(program, 'pointSize');
+ gl.uniform1f(loc, pointSize);
+ gl.vertexAttribPointer(0, 4, gl.FLOAT, false, 0, 0);
+ gl.enableVertexAttribArray(0);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Should be no errors after setting up program");
+ }
+ return program;
+}
+
+function runOneTestCase(vertex) {
+ debug("");
+ debug("testing point at (" + vertex[0] + ", " + vertex[1] + ", " + vertex[2] + ")");
+ var data = new Float32Array(vertex);
+ gl.bufferSubData(gl.ARRAY_BUFFER, 0, data);
+
+ gl.clear(gl.COLOR_BUFFER_BIT);
+ gl.drawArrays(gl.POINTS, 0, 1);
+ wtu.checkCanvasRect(gl, 0, 0, 1, 1, [0, 255, 0]);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Should be no errors after running one test case");
+}
+
+function runTests() {
+ if (!gl) {
+ testFailed("context does not exist");
+ return;
+ }
+
+ var range = gl.getParameter(gl.ALIASED_POINT_SIZE_RANGE);
+ if (range[1] < 2.0) {
+ testPassed("ALIASDED_POINT_SIZE_RANGE less than 2");
+ return;
+ }
+ pointSize = 2.0;
+
+ var data = new Float32Array(4);
+ var buffer = gl.createBuffer();
+ gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
+ gl.bufferData(gl.ARRAY_BUFFER, data, gl.STATIC_DRAW);
+
+ var program = setupProgram();
+ if (!program) {
+ testFailed("fail to set up program");
+ return;
+ }
+
+ gl.disable(gl.BLEND);
+ gl.disable(gl.DITHER);
+ gl.disable(gl.DEPTH_TEST);
+
+ gl.clearColor(1.0, 0.0, 0.0, 1.0);
+
+ var vertices = [
+ [ 0.99, 0.5, 0.0, 1.0 ],
+ [ 1.01, 0.5, 0.0, 1.0 ],
+ [ 0.5, 0.99, 0.0, 1.0 ],
+ [ 0.5, 1.01, 0.0, 1.0 ],
+ ];
+ for (var idx = 0; idx < vertices.length; ++idx) {
+ runOneTestCase(vertices[idx]);
+ }
+}
+
+runTests();
+debug("");
+var successfullyParsed = true;
diff --git a/dom/canvas/test/webgl-conf/checkout/js/tests/compositing-test.js b/dom/canvas/test/webgl-conf/checkout/js/tests/compositing-test.js
new file mode 100644
index 0000000000..ceccbc406e
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/js/tests/compositing-test.js
@@ -0,0 +1,136 @@
+var createCompositingTestFn = (function() {
+
+const width = 20;
+const height = 20;
+
+function waitForComposite() {
+ debug('wait for composite');
+ return new Promise(resolve => wtu.waitForComposite(resolve));
+}
+
+async function testPreserveDrawingBufferFalse(gl, drawFn, clear) {
+ debug('');
+ debug(`test preserveDrawingBuffer: false with ${drawFn.name} ${clear ? 'with' : 'without'} clear`);
+
+ if (clear) {
+ gl.clearColor(0, 0, 0, 0);
+ gl.clear(gl.COLOR_BUFFER_BIT);
+ }
+
+ if (drawFn(gl)) {
+ debug('skipped: extension does not exist');
+ return;
+ }
+
+ wtu.checkCanvas(gl, [255, 0, 0, 255], "canvas should be red");
+
+ // enable scissor here, before compositing, to make sure it's correctly
+ // ignored and restored
+ const halfWidth = gl.canvas.width / 2;
+ const halfHeight = gl.canvas.height / 2;
+ gl.scissor(0, halfHeight, halfWidth, halfHeight);
+ gl.enable(gl.SCISSOR_TEST);
+
+ await waitForComposite();
+
+ // scissor was set earlier
+ gl.clearColor(0, 0, 1, 1);
+ gl.clear(gl.COLOR_BUFFER_BIT);
+
+ wtu.checkCanvasRect(gl, 0, halfHeight, halfWidth, halfHeight, [0, 0, 255, 255],
+ "cleared corner should be blue, stencil should be preserved");
+ wtu.checkCanvasRect(gl, 0, 0, halfWidth, halfHeight, [0, 0, 0, 0],
+ "remainder of buffer should be cleared");
+
+ gl.disable(gl.SCISSOR_TEST);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "there should be no errors");
+}
+
+async function testPreserveDrawingBufferTrue(gl, drawFn, clear) {
+ debug('');
+ debug(`test preserveDrawingBuffer: true with ${drawFn.name} ${clear ? 'with' : 'without'} clear`);
+
+ if (clear) {
+ gl.clearColor(0, 0, 0, 0);
+ gl.clear(gl.COLOR_BUFFER_BIT);
+ }
+
+ const skipTest = drawFn(gl);
+ if (skipTest) {
+ debug('skipped: extension does not exist');
+ return;
+ }
+
+ wtu.checkCanvas(gl, [255, 0, 0, 255], "canvas should be red");
+
+ await waitForComposite();
+
+ wtu.checkCanvas(gl, [255, 0, 0, 255], "canvas should be red");
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "there should be no errors");
+}
+
+function setupWebGL({
+ webglVersion,
+ shadersFn,
+ attribs,
+}) {
+ const existingCanvases = document.querySelectorAll('canvas');
+ const canvas = document.createElement('canvas');
+ canvas.width = width;
+ canvas.height = height;
+ canvas.style.display = 'block';
+ canvas.style.position = 'fixed';
+ canvas.style.left = `${existingCanvases.length * 25}px`;
+ canvas.style.top = '0';
+ // The canvas needs to be visible or the test will fail.
+ document.body.insertBefore(canvas, [...existingCanvases].pop());
+ const gl = wtu.create3DContext(canvas, attribs, webglVersion);
+ if (!gl) {
+ testFailed('WebGL context creation failed');
+ return gl;
+ }
+
+ const shaders = shadersFn(gl);
+ const program = wtu.setupProgram(gl, shaders, ["position"]);
+ if (!program) {
+ debug(`program failed to compile: ${wtu.getLastError()}`);
+ }
+ const positionBuf = gl.createBuffer();
+ gl.bindBuffer(gl.ARRAY_BUFFER, positionBuf);
+ gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
+ -1, -1,
+ 1, -1,
+ -1, 1,
+ -1, 1,
+ 1, -1,
+ 1, 1,
+ ]), gl.STATIC_DRAW);
+ gl.enableVertexAttribArray(0);
+ gl.vertexAttribPointer(0, 2, gl.FLOAT, false, 0, 0);
+ const indexBuf = gl.createBuffer();
+ gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuf);
+ gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint8Array([0, 1, 2, 3, 4, 5]), gl.STATIC_DRAW);
+ return gl;
+}
+
+function createCompositingTestFn(options) {
+ const glPreserveDrawingBufferFalse = setupWebGL({
+ ...options,
+ attribs: {antialias: false},
+ });
+ const glPreserveDrawingBufferTrue = setupWebGL({
+ ...options,
+ attribs: {antialias: false, preserveDrawingBuffer: true},
+ });
+ return async function(drawFn) {
+ debug('---');
+ await testPreserveDrawingBufferFalse(glPreserveDrawingBufferFalse, drawFn, false);
+ await testPreserveDrawingBufferFalse(glPreserveDrawingBufferFalse, drawFn, true);
+
+ await testPreserveDrawingBufferTrue(glPreserveDrawingBufferTrue, drawFn, false);
+ await testPreserveDrawingBufferTrue(glPreserveDrawingBufferTrue, drawFn, true);
+ };
+}
+
+return createCompositingTestFn;
+}());
diff --git a/dom/canvas/test/webgl-conf/checkout/js/tests/compound-assignment-type-combination.js b/dom/canvas/test/webgl-conf/checkout/js/tests/compound-assignment-type-combination.js
new file mode 100644
index 0000000000..41a49bced4
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/js/tests/compound-assignment-type-combination.js
@@ -0,0 +1,133 @@
+/*
+Copyright (c) 2019 The Khronos Group Inc.
+Use of this source code is governed by an MIT-style license that can be
+found in the LICENSE.txt file.
+*/
+
+'use strict';
+
+// ESSL 1.00 spec section 5.8 (also ESSL 3.00 spec section 5.8):
+// "The l-value and the expression must satisfy the semantic requirements of both op and equals (=)"
+// In the semantic requirements of assignment (=):
+// "The lvalue-expression and rvalue-expression must have the same type"
+
+var runTest = function(contextVersion) {
+ var vertexTemplateESSL1 = [
+ 'precision mediump float;',
+
+ 'uniform $(rtype) ur;',
+ 'uniform $(ltype) ul;',
+
+ 'void main() {',
+ ' $(ltype) a = ul;',
+ ' a $(op) ur;',
+ ' gl_Position = vec4(float(a$(ltypeToScalar)));',
+ '}'
+ ].join('\n');
+
+ var vertexTemplateESSL3 = [
+ '#version 300 es',
+ vertexTemplateESSL1
+ ].join('\n');
+
+ var fragmentTemplateESSL1 = [
+ 'precision mediump float;',
+
+ 'uniform $(rtype) ur;',
+ 'uniform $(ltype) ul;',
+
+ 'void main() {',
+ ' $(ltype) a = ul;',
+ ' a $(op) ur;',
+ ' gl_FragColor = vec4(float(a$(ltypeToScalar)));',
+ '}'
+ ].join('\n');
+
+ var fragmentTemplateESSL3 = [
+ '#version 300 es',
+ 'out mediump vec4 my_FragColor;',
+ fragmentTemplateESSL1
+ ].join('\n').replace('gl_FragColor', 'my_FragColor');
+
+ var isNonSquareMatrix = function(typeStr) {
+ return typeStr.substring(0, 3) == 'mat' &&
+ typeStr.length > 5 &&
+ typeStr[3] != typeStr[5];
+ }
+
+ var vsTemplate = contextVersion < 2 ? vertexTemplateESSL1 : vertexTemplateESSL3;
+ var fsTemplate = contextVersion < 2 ? fragmentTemplateESSL1 : fragmentTemplateESSL3;
+
+ var wtu = WebGLTestUtils;
+
+ var tests = [];
+
+ var baseTypes = ['float', 'int'];
+ var vecTypes = [['vec2', 'vec3', 'vec4', 'mat2', 'mat3', 'mat4'], ['ivec2', 'ivec3', 'ivec4']];
+ if (contextVersion >= 2) {
+ vecTypes[0] = ['vec2', 'vec3', 'vec4', 'mat2x2', 'mat3x3', 'mat4x4', 'mat2x3', 'mat2x4', 'mat3x2', 'mat3x4', 'mat4x2', 'mat4x3'];
+ }
+ var ops = ['+=', '-=', '*=', '/='];
+
+ var fs, vs;
+ for (var k = 0; k < ops.length; ++k) {
+ var op = ops[k];
+ for (var i = 0; i < baseTypes.length; ++i) {
+ var baseType = baseTypes[i];
+ for (var j = 0; j < vecTypes[i].length; ++j) {
+ var vecType = vecTypes[i][j];
+ var vecTypeToScalar = vecType.substring(0, 3) == 'mat' ? '[0].x' : '.x';
+
+ var pushTest = function(ltype, rtype, ltypeToScalar, expectSuccess) {
+ vs = wtu.replaceParams(vsTemplate, {ltype: ltype, rtype: rtype, ltypeToScalar: ltypeToScalar, op: op});
+ fs = wtu.replaceParams(fsTemplate, {ltype: ltype, rtype: rtype, ltypeToScalar: ltypeToScalar, op: op});
+ tests.push({
+ vShaderSource: vs,
+ vShaderSuccess: expectSuccess,
+ linkSuccess: expectSuccess,
+ passMsg: ltype + " " + op + " " + rtype + " in a vertex shader should " + (expectSuccess ? "succeed." : "fail.")
+ });
+ tests.push({
+ fShaderSource: fs,
+ fShaderSuccess: expectSuccess,
+ linkSuccess: expectSuccess,
+ passMsg: ltype + " " + op + " " + rtype + " in a fragment shader should " + (expectSuccess ? "succeed." : "fail.")
+ });
+ }
+
+ // "scalar op= vector" is not okay, since the result of op is a vector,
+ // which can't be assigned to a scalar.
+ pushTest(baseType, vecType, '', false);
+
+ if (j > 0) {
+ var vecType2 = vecTypes[i][j - 1];
+ // "vector1 op= vector2" is not okay when vector1 and vector2 have
+ // non-matching dimensions.
+ pushTest(vecType, vecType2, vecTypeToScalar, false);
+ }
+
+ // "vector op= scalar" is okay.
+ pushTest(vecType, baseType, vecTypeToScalar, true);
+
+ // vecX *= matX is okay (effectively, this treats vector as a row vector).
+ if (vecType.substring(0, 3) == 'vec' && op == '*=') {
+ pushTest(vecType, 'mat' + vecType[3], vecTypeToScalar, true);
+ }
+
+ if (op != '*=' || !isNonSquareMatrix(vecType)) {
+ // "vector1 op= vector2" is okay when vector1 and vector2 have the same
+ // type (does a component-wise operation or matrix multiplication).
+ pushTest(vecType, vecType, vecTypeToScalar, true);
+ } else {
+ // non-square matrices can only be compound multiplied with a square matrix.
+ pushTest(vecType, vecType, vecTypeToScalar, false);
+ pushTest(vecType, 'mat' + vecType[3], vecTypeToScalar, true);
+ }
+ }
+ }
+ }
+
+ GLSLConformanceTester.runTests(tests, contextVersion);
+}
+
+var successfullyParsed = true;
diff --git a/dom/canvas/test/webgl-conf/checkout/js/tests/compressed-tex-image.js b/dom/canvas/test/webgl-conf/checkout/js/tests/compressed-tex-image.js
new file mode 100644
index 0000000000..7886181f4c
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/js/tests/compressed-tex-image.js
@@ -0,0 +1,138 @@
+"use strict";
+description("This test ensures WebGL implementations correctly implement querying for compressed textures when extensions are disabled.");
+
+debug("");
+
+const wtu = WebGLTestUtils;
+const gl = wtu.create3DContext(null, undefined, contextVersion);
+
+const COMPRESSED_RGB_PVRTC_4BPPV1_IMG = 0x8C00;
+const COMPRESSED_RGBA_PVRTC_4BPPV1_IMG = 0x8C02;
+
+let formats = null;
+let ext;
+
+if (!gl) {
+ testFailed("context does not exist");
+} else {
+ testPassed("context exists");
+
+ var tex = gl.createTexture();
+ gl.bindTexture(gl.TEXTURE_2D, tex);
+ wtu.shouldGenerateGLError(gl, [gl.INVALID_ENUM, gl.INVALID_OPERATION],
+ "gl.compressedTexSubImage2D(gl.TEXTURE_2D, 0, 0, 0, 10, 10, COMPRESSED_RGB_PVRTC_4BPPV1_IMG, new Uint8Array(8));");
+
+ wtu.shouldGenerateGLError(gl, gl.INVALID_ENUM, "gl.compressedTexImage2D(gl.TEXTURE_2D, 0, COMPRESSED_RGB_PVRTC_4BPPV1_IMG, 8, 8, 0, new Uint8Array(8))");
+ wtu.shouldGenerateGLError(gl, gl.INVALID_ENUM, "gl.compressedTexImage2D(gl.TEXTURE_2D, 0, COMPRESSED_RGBA_PVRTC_4BPPV1_IMG, 8, 8, 0, new Uint8Array(8))");
+
+ wtu.shouldGenerateGLError(gl, gl.NO_ERROR, "formats = gl.getParameter(gl.COMPRESSED_TEXTURE_FORMATS)");
+ shouldBeNonNull("formats");
+ shouldBe("formats.length", "0");
+
+ wtu.shouldGenerateGLError(gl, gl.NO_ERROR, "gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 4, 4, 0, gl.RGBA, gl.UNSIGNED_BYTE, new Uint8Array(4*4*4));");
+ wtu.shouldGenerateGLError(gl, gl.INVALID_ENUM,
+ "gl.compressedTexSubImage2D(gl.TEXTURE_2D, 0, 0, 0, 4, 4, COMPRESSED_RGB_PVRTC_4BPPV1_IMG, new Uint8Array(8));");
+
+ // Check too-many and too-few args.
+
+ wtu.shouldThrow(gl, false, "too many args", function() {
+ gl.compressedTexImage2D(gl.TEXTURE_2D, 0, COMPRESSED_RGB_PVRTC_4BPPV1_IMG, 4, 4, 0, new Uint8Array(8), null);
+ });
+ wtu.shouldThrow(gl, TypeError, "too few args", function() {
+ gl.compressedTexImage2D(gl.TEXTURE_2D, 0, COMPRESSED_RGB_PVRTC_4BPPV1_IMG, 4, 4, 0);
+ });
+
+ wtu.shouldThrow(gl, false, "too many args", function() {
+ gl.compressedTexSubImage2D(gl.TEXTURE_2D, 0, 0, 0, 4, 4, COMPRESSED_RGB_PVRTC_4BPPV1_IMG, new Uint8Array(8), null);
+ });
+ wtu.shouldThrow(gl, TypeError, "too few args", function() {
+ gl.compressedTexSubImage2D(gl.TEXTURE_2D, 0, 0, 0, 4, 4, COMPRESSED_RGB_PVRTC_4BPPV1_IMG);
+ });
+
+ // -
+
+ let pbo;
+ // WebGL 2.0 specific
+ if (gl.PIXEL_UNPACK_BUFFER) {
+ pbo = gl.createBuffer();
+ }
+
+ gl.bindTexture(gl.TEXTURE_2D, tex);
+
+ function validateExt(extName, enumName, blockSize, blockByteSize, expectedSubImageError) {
+ debug('\n---------------------------');
+ debug('\n' + extName);
+ ext = gl.getExtension(extName);
+ if (!ext) {
+ testPassed(`Optional ext ${extName} MAY be unsupported.`);
+ return;
+ }
+ testPassed(`Optional ext ${extName} is supported.`);
+
+ const data = new Uint8Array(blockByteSize);
+
+ const views = [
+ data,
+ new Uint8ClampedArray(data.buffer),
+ new Int8Array(data.buffer),
+ new Uint16Array(data.buffer),
+ new Int16Array(data.buffer),
+ new Uint32Array(data.buffer),
+ new Int32Array(data.buffer),
+ new Float32Array(data.buffer),
+ new DataView(data.buffer),
+ ];
+ if (window.SharedArrayBuffer) {
+ const sharedBuffer = new SharedArrayBuffer(blockByteSize);
+ views.push(
+ new Uint8Array(sharedBuffer),
+ new Uint8ClampedArray(sharedBuffer),
+ new DataView(sharedBuffer)
+ );
+ }
+
+ for (const view of views) {
+ window.g_view = view;
+ debug(`\nfrom ${view.constructor.name} of ${view.buffer.constructor.name}`);
+ wtu.shouldGenerateGLError(gl, gl.NO_ERROR,
+ `gl.compressedTexImage2D(gl.TEXTURE_2D, 0, ext.${enumName}, ${blockSize},${blockSize}, 0, g_view)`);
+
+ wtu.shouldGenerateGLError(gl, expectedSubImageError,
+ `gl.compressedTexSubImage2D(gl.TEXTURE_2D, 0, 0,0, ${blockSize},${blockSize}, ext.${enumName}, g_view)`);
+ }
+
+ if (pbo) {
+ debug('\nfrom PBO');
+ gl.bindBuffer(gl.PIXEL_UNPACK_BUFFER, pbo);
+ wtu.shouldGenerateGLError(gl, gl.NO_ERROR,
+ `gl.bufferData(gl.PIXEL_UNPACK_BUFFER, ${blockByteSize}*2, gl.STATIC_DRAW)`);
+
+ wtu.shouldGenerateGLError(gl, gl.NO_ERROR,
+ `gl.compressedTexImage2D(gl.TEXTURE_2D, 0, ext.${enumName}, ${blockSize},${blockSize}, 0, ${blockByteSize}, 0)`);
+ wtu.shouldGenerateGLError(gl, gl.NO_ERROR,
+ `gl.compressedTexImage2D(gl.TEXTURE_2D, 0, ext.${enumName}, ${blockSize},${blockSize}, 0, ${blockByteSize}, 1)`);
+ wtu.shouldGenerateGLError(gl, gl.NO_ERROR,
+ `gl.compressedTexImage2D(gl.TEXTURE_2D, 0, ext.${enumName}, ${blockSize},${blockSize}, 0, ${blockByteSize}, ${blockByteSize})`);
+ wtu.shouldGenerateGLError(gl, gl.INVALID_OPERATION,
+ `gl.compressedTexImage2D(gl.TEXTURE_2D, 0, ext.${enumName}, ${blockSize},${blockSize}, 0, ${blockByteSize}, ${blockByteSize+1})`);
+
+ wtu.shouldGenerateGLError(gl, expectedSubImageError,
+ `gl.compressedTexSubImage2D(gl.TEXTURE_2D, 0, 0,0, ${blockSize},${blockSize}, ext.${enumName}, ${blockByteSize}, 0)`);
+ wtu.shouldGenerateGLError(gl, expectedSubImageError,
+ `gl.compressedTexSubImage2D(gl.TEXTURE_2D, 0, 0,0, ${blockSize},${blockSize}, ext.${enumName}, ${blockByteSize}, 1)`);
+ wtu.shouldGenerateGLError(gl, expectedSubImageError,
+ `gl.compressedTexSubImage2D(gl.TEXTURE_2D, 0, 0,0, ${blockSize},${blockSize}, ext.${enumName}, ${blockByteSize}, ${blockByteSize})`);
+ wtu.shouldGenerateGLError(gl, gl.INVALID_OPERATION,
+ `gl.compressedTexSubImage2D(gl.TEXTURE_2D, 0, 0,0, ${blockSize},${blockSize}, ext.${enumName}, ${blockByteSize}, ${blockByteSize+1})`);
+
+ gl.bindBuffer(gl.PIXEL_UNPACK_BUFFER, null);
+ }
+ }
+
+ validateExt('WEBGL_compressed_texture_s3tc', 'COMPRESSED_RGBA_S3TC_DXT5_EXT', 4, 16, gl.NO_ERROR);
+ validateExt('WEBGL_compressed_texture_etc1', 'COMPRESSED_RGB_ETC1_WEBGL', 4, 8, gl.INVALID_OPERATION);
+ validateExt('WEBGL_compressed_texture_etc', 'COMPRESSED_RGBA8_ETC2_EAC', 4, 16, gl.NO_ERROR);
+ validateExt('WEBGL_compressed_texture_astc', 'COMPRESSED_RGBA_ASTC_4x4_KHR', 4, 16, gl.NO_ERROR);
+}
+
+var successfullyParsed = true;
diff --git a/dom/canvas/test/webgl-conf/checkout/js/tests/compressed-texture-utils.js b/dom/canvas/test/webgl-conf/checkout/js/tests/compressed-texture-utils.js
new file mode 100644
index 0000000000..46d155f5f1
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/js/tests/compressed-texture-utils.js
@@ -0,0 +1,258 @@
+/*
+Copyright (c) 2019 The Khronos Group Inc.
+Use of this source code is governed by an MIT-style license that can be
+found in the LICENSE.txt file.
+*/
+
+"use strict";
+
+let CompressedTextureUtils = (function() {
+
+let formatToString = function(ext, format) {
+ for (let p in ext) {
+ if (ext[p] == format) {
+ return p;
+ }
+ }
+ return "0x" + format.toString(16);
+};
+
+/**
+ * Make an image element from Uint8Array bitmap data.
+ * @param {number} imageHeight Height of the data in pixels.
+ * @param {number} imageWidth Width of the data in pixels.
+ * @param {number} dataWidth Width of each row in the data buffer, in pixels.
+ * @param {Uint8Array} data Image data buffer to display. Each pixel takes up 4 bytes in the array regardless of the alpha parameter.
+ * @param {boolean} alpha True if alpha data should be taken from data. Otherwise alpha channel is set to 255.
+ * @return {HTMLImageElement} The image element.
+ */
+let makeScaledImage = function(imageWidth, imageHeight, dataWidth, data, alpha, opt_scale) {
+ let scale = opt_scale ? opt_scale : 8;
+ let c = document.createElement("canvas");
+ c.width = imageWidth * scale;
+ c.height = imageHeight * scale;
+ let ctx = c.getContext("2d");
+ for (let yy = 0; yy < imageHeight; ++yy) {
+ for (let xx = 0; xx < imageWidth; ++xx) {
+ let offset = (yy * dataWidth + xx) * 4;
+ ctx.fillStyle = "rgba(" +
+ data[offset + 0] + "," +
+ data[offset + 1] + "," +
+ data[offset + 2] + "," +
+ (alpha ? data[offset + 3] / 255 : 1) + ")";
+ ctx.fillRect(xx * scale, yy * scale, scale, scale);
+ }
+ }
+ return wtu.makeImageFromCanvas(c);
+};
+
+let insertCaptionedImg = function(parent, caption, img) {
+ let div = document.createElement("div");
+ div.appendChild(img);
+ let label = document.createElement("div");
+ label.appendChild(document.createTextNode(caption));
+ div.appendChild(label);
+ parent.appendChild(div);
+};
+
+/**
+ * @param {WebGLRenderingContextBase} gl
+ * @param {Object} compressedFormats Mapping from format names to format enum values.
+ * @param expectedByteLength A function that takes in width, height and format and returns the expected buffer size in bytes.
+ */
+let testCompressedFormatsUnavailableWhenExtensionDisabled = function(gl, compressedFormats, expectedByteLength, testSize) {
+ let tex = gl.createTexture();
+ gl.bindTexture(gl.TEXTURE_2D, tex);
+ for (let name in compressedFormats) {
+ if (compressedFormats.hasOwnProperty(name)) {
+ gl.compressedTexImage2D(gl.TEXTURE_2D, 0, compressedFormats[name], testSize, testSize, 0, new Uint8Array(expectedByteLength(testSize, testSize, compressedFormats[name])));
+ wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "Trying to use format " + name + " with extension disabled.");
+ }
+ }
+ gl.bindTexture(gl.TEXTURE_2D, null);
+ gl.deleteTexture(tex);
+};
+
+/**
+ * @param {WebGLRenderingContextBase} gl
+ * @param {Object} expectedFormats Mapping from format names to format enum values.
+ */
+let testCompressedFormatsListed = function(gl, expectedFormats) {
+ debug("");
+ debug("Testing that every format is listed by the compressed texture formats query");
+
+ let supportedFormats = gl.getParameter(gl.COMPRESSED_TEXTURE_FORMATS);
+
+ let failed;
+ let count = 0;
+ for (let name in expectedFormats) {
+ if (expectedFormats.hasOwnProperty(name)) {
+ ++count;
+ let format = expectedFormats[name];
+ failed = true;
+ for (let ii = 0; ii < supportedFormats.length; ++ii) {
+ if (format == supportedFormats[ii]) {
+ testPassed("supported format " + name + " exists");
+ failed = false;
+ break;
+ }
+ }
+ if (failed) {
+ testFailed("supported format " + name + " does not exist");
+ }
+ }
+ }
+ if (supportedFormats.length != count) {
+ testFailed("Incorrect number of supported formats, was " + supportedFormats.length + " should be " + count);
+ }
+};
+
+/**
+ * @param {Object} ext Compressed texture extension object.
+ * @param {Object} expectedFormats Mapping from format names to format enum values.
+ */
+let testCorrectEnumValuesInExt = function(ext, expectedFormats) {
+ debug("");
+ debug("Testing that format enum values in the extension object are correct");
+
+ for (name in expectedFormats) {
+ if (expectedFormats.hasOwnProperty(name)) {
+ if (isResultCorrect(ext[name], expectedFormats[name])) {
+ testPassed("Enum value for " + name + " matches 0x" + ext[name].toString(16));
+ } else {
+ testFailed("Enum value for " + name + " mismatch: 0x" + ext[name].toString(16) + " should be 0x" + expectedFormats[name].toString(16));
+ }
+ }
+ }
+};
+
+/**
+ * @param {WebGLRenderingContextBase} gl
+ * @param {Object} validFormats Mapping from format names to format enum values.
+ * @param expectedByteLength A function that takes in width, height and format and returns the expected buffer size in bytes.
+ * @param getBlockDimensions A function that takes in a format and returns block size in pixels.
+ */
+let testFormatRestrictionsOnBufferSize = function(gl, validFormats, expectedByteLength, getBlockDimensions) {
+ debug("");
+ debug("Testing format restrictions on texture upload buffer size");
+
+ let tex = gl.createTexture();
+ gl.bindTexture(gl.TEXTURE_2D, tex);
+ for (let formatId in validFormats) {
+ if (validFormats.hasOwnProperty(formatId)) {
+ let format = validFormats[formatId];
+ let blockSize = getBlockDimensions(format);
+ let expectedSize = expectedByteLength(blockSize.width * 4, blockSize.height * 4, format);
+ let data = new Uint8Array(expectedSize);
+ gl.compressedTexImage2D(gl.TEXTURE_2D, 0, format, blockSize.width * 3, blockSize.height * 4, 0, data);
+ wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, formatId + " data size does not match dimensions (too small width)");
+ gl.compressedTexImage2D(gl.TEXTURE_2D, 0, format, blockSize.width * 5, blockSize.height * 4, 0, data);
+ wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, formatId + " data size does not match dimensions (too large width)");
+ gl.compressedTexImage2D(gl.TEXTURE_2D, 0, format, blockSize.width * 4, blockSize.height * 3, 0, data);
+ wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, formatId + " data size does not match dimensions (too small height)");
+ gl.compressedTexImage2D(gl.TEXTURE_2D, 0, format, blockSize.width * 4, blockSize.height * 5, 0, data);
+ wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, formatId + " data size does not match dimensions (too large height)");
+ }
+ }
+};
+
+/**
+ * @param {WebGLRenderingContextBase} gl
+ * @param {Object} validFormats Mapping from format names to format enum values.
+ * @param expectedByteLength A function that takes in width, height and format and returns the expected buffer size in bytes.
+ * @param getBlockDimensions A function that takes in a format and returns block size in pixels.
+ * @param {number} width Width of the image in pixels.
+ * @param {number} height Height of the image in pixels.
+ * @param {Object} subImageConfigs configs for compressedTexSubImage calls
+ */
+let testTexSubImageDimensions = function(gl, ext, validFormats, expectedByteLength, getBlockDimensions, width, height, subImageConfigs) {
+ let tex = gl.createTexture();
+ gl.bindTexture(gl.TEXTURE_2D, tex);
+
+ for (let formatId in validFormats) {
+ if (validFormats.hasOwnProperty(formatId)) {
+ let format = validFormats[formatId];
+ let blockSize = getBlockDimensions(format);
+ debug("testing " + ctu.formatToString(ext, format));
+ let expectedSize = expectedByteLength(width, height, format);
+ let data = new Uint8Array(expectedSize);
+
+ gl.compressedTexImage2D(gl.TEXTURE_2D, 0, format, width, height, 0, data);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "setting up compressed texture");
+
+ for (let i = 0, len = subImageConfigs.length; i < len; ++i) {
+ let c = subImageConfigs[i];
+ let subData = new Uint8Array(expectedByteLength(c.width, c.height, format));
+ gl.compressedTexSubImage2D(gl.TEXTURE_2D, 0, c.xoffset, c.yoffset, c.width, c.height, format, subData);
+ wtu.glErrorShouldBe(gl, c.expectation, c.message);
+ }
+ }
+ }
+
+ gl.bindTexture(gl.TEXTURE_2D, null);
+ gl.deleteTexture(tex);
+};
+
+let testTexImageLevelDimensions = function(gl, ext, validFormats, expectedByteLength, getBlockDimensions, imageConfigs) {
+ let tex = gl.createTexture();
+ gl.bindTexture(gl.TEXTURE_2D, tex);
+
+ for (let formatId in validFormats) {
+ if (validFormats.hasOwnProperty(formatId)) {
+ let format = validFormats[formatId];
+ let blockSize = getBlockDimensions(format);
+ debug("testing " + ctu.formatToString(ext, format));
+
+ for (let i = 0, len = imageConfigs.length; i < len; ++i) {
+ let c = imageConfigs[i];
+ let data = new Uint8Array(expectedByteLength(c.width, c.height, format));
+ gl.compressedTexImage2D(gl.TEXTURE_2D, c.level, format, c.width, c.height, 0, data);
+ wtu.glErrorShouldBe(gl, c.expectation, c.message);
+ }
+ }
+ }
+
+ gl.bindTexture(gl.TEXTURE_2D, null);
+ gl.deleteTexture(tex);
+}
+
+let testTexStorageLevelDimensions = function(gl, ext, validFormats, expectedByteLength, getBlockDimensions, imageConfigs) {
+ for (let formatId in validFormats) {
+ let tex = gl.createTexture();
+ gl.bindTexture(gl.TEXTURE_2D, tex);
+
+ if (validFormats.hasOwnProperty(formatId)) {
+ let format = validFormats[formatId];
+ let blockSize = getBlockDimensions(format);
+ debug("testing " + ctu.formatToString(ext, format));
+
+ for (let i = 0, len = imageConfigs.length; i < len; ++i) {
+ let c = imageConfigs[i];
+ let data = new Uint8Array(expectedByteLength(c.width, c.height, format));
+ if (i == 0) {
+ gl.texStorage2D(gl.TEXTURE_2D, imageConfigs.length, format, c.width, c.height);
+ wtu.glErrorShouldBe(gl, c.expectation, c.message);
+ }
+ gl.compressedTexSubImage2D(gl.TEXTURE_2D, i, 0, 0, c.width, c.height, format, data);
+ wtu.glErrorShouldBe(gl, c.expectation, c.message);
+ }
+ }
+ gl.bindTexture(gl.TEXTURE_2D, null);
+ gl.deleteTexture(tex);
+ }
+}
+
+return {
+ formatToString: formatToString,
+ insertCaptionedImg: insertCaptionedImg,
+ makeScaledImage: makeScaledImage,
+ testCompressedFormatsListed: testCompressedFormatsListed,
+ testCompressedFormatsUnavailableWhenExtensionDisabled: testCompressedFormatsUnavailableWhenExtensionDisabled,
+ testCorrectEnumValuesInExt: testCorrectEnumValuesInExt,
+ testFormatRestrictionsOnBufferSize: testFormatRestrictionsOnBufferSize,
+ testTexSubImageDimensions: testTexSubImageDimensions,
+ testTexImageLevelDimensions: testTexImageLevelDimensions,
+ testTexStorageLevelDimensions: testTexStorageLevelDimensions,
+};
+
+})(); \ No newline at end of file
diff --git a/dom/canvas/test/webgl-conf/checkout/js/tests/context-methods.js b/dom/canvas/test/webgl-conf/checkout/js/tests/context-methods.js
new file mode 100644
index 0000000000..f6476463d2
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/js/tests/context-methods.js
@@ -0,0 +1,52 @@
+"use strict";
+
+// Properties to be ignored because they were added in versions of the
+// spec that are backward-compatible with this version
+const IGNORED_METHODS = [
+ // There is no official spec for the commit API yet, the proposal link is:
+ // https://wiki.whatwg.org/wiki/OffscreenCanvas
+ "commit",
+
+ // For WebXR integration:
+ "makeXRCompatible",
+];
+
+function assertFunction(v, f) {
+ try {
+ if (typeof v[f] != "function") {
+ testFailed(`Property either does not exist or is not a function: ${f}`);
+ return false;
+ } else {
+ return true;
+ }
+ } catch(e) {
+ testFailed(`Trying to access the property '${f}' threw an error: ${e.toString()}`);
+ }
+}
+
+function testContextMethods(gl, requiredContextMethods) {
+ const acceptableMethods = [].concat(requiredContextMethods, IGNORED_METHODS);
+
+ let passed = true;
+ requiredContextMethods.forEach(method => {
+ const r = assertFunction(gl, method);
+ passed = passed && r;
+ });
+ if (passed) {
+ testPassed("All WebGL methods found.");
+ }
+ let extended = false;
+ for (let propertyName of Object.getOwnPropertyNames(gl)) {
+ if (typeof gl[propertyName] == "function" && !acceptableMethods.includes(propertyName)) {
+ if (!extended) {
+ extended = true;
+ testFailed("Also found the following extra methods:");
+ }
+ testFailed(propertyName);
+ }
+ }
+
+ if (!extended) {
+ testPassed("No extra methods found on WebGL context.");
+ }
+}
diff --git a/dom/canvas/test/webgl-conf/checkout/js/tests/ext-color-buffer-half-float.js b/dom/canvas/test/webgl-conf/checkout/js/tests/ext-color-buffer-half-float.js
new file mode 100644
index 0000000000..51509e8a6e
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/js/tests/ext-color-buffer-half-float.js
@@ -0,0 +1,473 @@
+"use strict";
+
+function allocateTexture()
+{
+ var texture = gl.createTexture();
+ gl.bindTexture(gl.TEXTURE_2D, texture);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "texture parameter setup should succeed");
+ return texture;
+}
+
+function checkRenderingResults()
+{
+ wtu.checkCanvas(gl, [0, 255, 0, 255], "should be green");
+}
+
+function arrayToString(arr, size) {
+ var mySize;
+ if (!size)
+ mySize = arr.length;
+ else
+ mySize = size;
+ var out = "[";
+ for (var ii = 0; ii < mySize; ++ii) {
+ if (ii > 0) {
+ out += ", ";
+ }
+ out += arr[ii];
+ }
+ return out + "]";
+}
+
+function runReadbackTest(testProgram, subtractor)
+{
+ // Verify floating point readback
+ debug("Checking readback of floating-point values");
+ var buf = new Float32Array(4);
+ gl.readPixels(0, 0, 1, 1, gl.RGBA, gl.FLOAT, buf);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "readPixels from floating-point framebuffer should succeed");
+ var ok = true;
+ var tolerance = 8.0; // TODO: factor this out from both this test and the subtractor shader above.
+ for (var ii = 0; ii < buf.length; ++ii) {
+ if (Math.abs(buf[ii] - subtractor[ii]) > tolerance) {
+ ok = false;
+ break;
+ }
+ }
+ if (ok) {
+ testPassed("readPixels of float-type data from floating-point framebuffer succeeded");
+ } else {
+ testFailed("readPixels of float-type data from floating-point framebuffer failed: expected "
+ + arrayToString(subtractor, 4) + ", got " + arrayToString(buf));
+ }
+}
+
+function runFloatTextureRenderTargetTest(enabled, internalFormatString, format, type, testProgram, numberOfChannels, subtractor, texSubImageCover)
+{
+ let internalFormat = eval(internalFormatString);
+ debug("");
+ debug("testing floating-point " + internalFormatString + " texture render target" + (texSubImageCover > 0 ? " after calling texSubImage" : ""));
+
+ var texture = allocateTexture();
+ var width = 2;
+ var height = 2;
+ gl.texImage2D(gl.TEXTURE_2D, 0, internalFormat, width, height, 0, format, type, null);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "floating-point texture allocation should succeed");
+
+ // Try to use this texture as a render target.
+ var fbo = gl.createFramebuffer();
+ gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
+ gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture, 0);
+ gl.bindTexture(gl.TEXTURE_2D, null);
+
+ var completeStatus = gl.checkFramebufferStatus(gl.FRAMEBUFFER);
+ if (!enabled) {
+ if (completeStatus == gl.FRAMEBUFFER_COMPLETE && !enabled)
+ testFailed("floating-point " + internalFormatString + " render target should not be supported");
+ else
+ testPassed("floating-point " + internalFormatString + " render target should not be supported");
+ return;
+ }
+
+ if (completeStatus != gl.FRAMEBUFFER_COMPLETE) {
+ if (version == 1 && format == gl.RGB)
+ testPassed("floating-point " + internalFormatString + " render target not supported; this is allowed.")
+ else
+ testFailed("floating-point " + internalFormatString + " render target not supported");
+ return;
+ }
+
+ if (texSubImageCover > 0) {
+ // Ensure that replacing the whole texture or a part of it with texSubImage2D doesn't affect renderability
+ gl.bindTexture(gl.TEXTURE_2D, texture);
+ var data = new Float32Array(width * height * numberOfChannels * texSubImageCover);
+ gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0, width, height * texSubImageCover, format, type, data);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "texSubImage2D should succeed if EXT_color_buffer_half_float is enabled");
+ gl.bindTexture(gl.TEXTURE_2D, null);
+ if (gl.checkFramebufferStatus(gl.FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE) {
+ testFailed("render target support changed after calling texSubImage2D");
+ return;
+ }
+ }
+
+ var renderProgram =
+ wtu.setupProgram(gl,
+ [wtu.simpleVertexShader, `void main()
+ {
+ gl_FragColor = vec4(1000.0, 1000.0, 1000.0, 1000.0);
+ }`],
+ ['vPosition'],
+ [0]);
+ wtu.clearAndDrawUnitQuad(gl);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "rendering to floating-point texture should succeed");
+
+ // Now sample from the floating-point texture and verify we got the correct values.
+ gl.bindFramebuffer(gl.FRAMEBUFFER, null);
+ gl.bindTexture(gl.TEXTURE_2D, texture);
+ gl.useProgram(testProgram);
+ gl.uniform1i(gl.getUniformLocation(testProgram, "tex"), 0);
+ gl.uniform4fv(gl.getUniformLocation(testProgram, "subtractor"), subtractor);
+ wtu.clearAndDrawUnitQuad(gl);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "rendering from floating-point texture should succeed");
+ checkRenderingResults();
+
+ gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
+ runReadbackTest(testProgram, subtractor);
+}
+
+function runFloatRenderbufferRenderTargetTest(enabled, internalFormatString, testProgram, numberOfChannels, subtractor)
+{
+ var internalFormat = eval(internalFormatString);
+ var samples = [0];
+ if (enabled && version > 1) {
+ samples = Array.prototype.slice.call(gl.getInternalformatParameter(gl.RENDERBUFFER, internalFormat, gl.SAMPLES));
+ samples.push(0);
+ }
+ for (var ndx = 0; ndx < samples.length; ++ndx) {
+ debug("");
+ debug("testing floating-point " + internalFormatString + " renderbuffer render target with number of samples " + samples[ndx]);
+
+ var colorbuffer = gl.createRenderbuffer();
+ var width = 2;
+ var height = 2;
+ gl.bindRenderbuffer(gl.RENDERBUFFER, colorbuffer);
+ if (samples[ndx] == 0)
+ gl.renderbufferStorage(gl.RENDERBUFFER, internalFormat, width, height);
+ else
+ gl.renderbufferStorageMultisample(gl.RENDERBUFFER, samples[ndx], internalFormat, width, height);
+ if (!enabled) {
+ wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "floating-point renderbuffer allocation should fail if EXT_color_buffer_half_float is not enabled or this is a 32 bit format");
+ return;
+ } else {
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "floating-point renderbuffer allocation should succeed if EXT_color_buffer_half_float is enabled");
+ }
+
+ // Try to use this renderbuffer as a render target.
+ var fbo = gl.createFramebuffer();
+ gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
+ gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, colorbuffer);
+
+ var completeStatus = gl.checkFramebufferStatus(gl.FRAMEBUFFER);
+ if (completeStatus != gl.FRAMEBUFFER_COMPLETE) {
+ testFailed("floating-point " + internalFormatString + " render target not supported");
+ return;
+ }
+ var resolveColorRbo = null;
+ var resolveFbo = null;
+ if (samples[ndx] > 0) {
+ resolveColorRbo = gl.createRenderbuffer();
+ gl.bindRenderbuffer(gl.RENDERBUFFER, resolveColorRbo);
+ gl.renderbufferStorage(gl.RENDERBUFFER, internalFormat, width, height);
+ resolveFbo = gl.createFramebuffer();
+ gl.bindFramebuffer(gl.FRAMEBUFFER, resolveFbo);
+ gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, resolveColorRbo);
+ completeStatus = gl.checkFramebufferStatus(gl.FRAMEBUFFER);
+ if (completeStatus != gl.FRAMEBUFFER_COMPLETE) {
+ testFailed("Failed to create resolve framebuffer");
+ return;
+ }
+ }
+ gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
+ gl.clearColor(1000.0, 1000.0, 1000.0, 1000.0);
+ gl.clear(gl.COLOR_BUFFER_BIT);
+
+ if (samples[ndx] > 0) {
+ gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, resolveFbo);
+ gl.blitFramebuffer(0, 0, width, height, 0, 0, width, height, gl.COLOR_BUFFER_BIT, gl.NEAREST);
+ gl.bindFramebuffer(gl.READ_FRAMEBUFFER, resolveFbo);
+ }
+ runReadbackTest(testProgram, subtractor);
+ }
+}
+
+function runRGB16FNegativeTest()
+{
+ debug("");
+ debug("testing RGB16F isn't color renderable");
+
+ var texture = allocateTexture();
+ var width = 2;
+ var height = 2;
+ gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB16F, width, height, 0, gl.RGB, gl.FLOAT, null);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "RGB16F texture allocation should succeed");
+
+ // Try to use this texture as a render target.
+ var fbo = gl.createFramebuffer();
+ gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
+ gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture, 0);
+ gl.bindTexture(gl.TEXTURE_2D, null);
+
+ var completeStatus = gl.checkFramebufferStatus(gl.FRAMEBUFFER);
+ if (completeStatus == gl.FRAMEBUFFER_COMPLETE)
+ testFailed("RGB16F render target should not be supported with or without enabling EXT_color_buffer_half_float");
+ else
+ testPassed("RGB16F render target should not be supported with or without enabling EXT_color_buffer_half_float");
+ gl.deleteTexture(texture);
+
+ var colorbuffer = gl.createRenderbuffer();
+ gl.bindRenderbuffer(gl.RENDERBUFFER, colorbuffer);
+ gl.renderbufferStorage(gl.RENDERBUFFER, gl.RGB16F, width, height);
+ wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "RGB16F renderbuffer allocation should fail with or without enabling EXT_color_buffer_half_float");
+ gl.bindRenderbuffer(gl.RENDERBUFFER, null);
+ gl.deleteRenderbuffer(colorbuffer);
+
+ gl.bindFramebuffer(gl.FRAMEBUFFER, null);
+ gl.deleteFramebuffer(fbo);
+}
+
+function runUniqueObjectTest()
+{
+ debug("");
+ debug("Testing that getExtension() returns the same object each time");
+ gl.getExtension("EXT_color_buffer_half_float").myProperty = 2;
+ webglHarnessCollectGarbage();
+ shouldBe('gl.getExtension("EXT_color_buffer_half_float").myProperty', '2');
+}
+
+function runInternalFormatQueryTest()
+{
+ debug("");
+ debug("testing the internal format query");
+
+ var maxSamples = gl.getParameter(gl.MAX_SAMPLES);
+ const formats = [gl.RGBA16F, gl.R16F, gl.RG16F];
+ var firstMultiOnlyFormat = 4;
+ for (var fmt = 0; fmt < formats.length; ++fmt) {
+ var samples = gl.getInternalformatParameter(gl.RENDERBUFFER, formats[fmt], gl.SAMPLES);
+ if (fmt >= firstMultiOnlyFormat && (samples.length == 0 || samples[0] < maxSamples)) {
+ testFailed("the maximum value in SAMPLES should be at least " + maxSamples);
+ return;
+ }
+
+ var prevSampleCount = 0;
+ var sampleCount;
+ for (var ndx = 0; ndx < samples.length; ++ndx, prevSampleCount = sampleCount) {
+ sampleCount = samples[ndx];
+ // sample count must be > 0
+ if (sampleCount <= 0) {
+ testFailed("Expected sample count to be at least one; got " + sampleCount);
+ return;
+ }
+
+ // samples must be ordered descending
+ if (ndx > 0 && sampleCount >= prevSampleCount) {
+ testFailed("Expected sample count to be ordered in descending order; got " + prevSampleCount + " at index " + (ndx - 1) + ", and " + sampleCount + " at index " + ndx);
+ return;
+ }
+ }
+ }
+ testPassed("Internal format query succeeded");
+}
+
+function runCopyTexImageTest(enabled)
+{
+ var width = 16;
+ var height = 16;
+ var level = 0;
+ var cases = [
+ { internalformat: "RGBA16F", format: "RGBA", destFormat: "R16F", valid: true, renderable: true, },
+ { internalformat: "RGBA16F", format: "RGBA", destFormat: "RG16F", valid: true, renderable: true, },
+ { internalformat: "RGBA16F", format: "RGBA", destFormat: "RGB16F", valid: true, renderable: true, },
+ { internalformat: "RGBA16F", format: "RGBA", destFormat: "RGBA16F", valid: true, renderable: true, },
+ { internalformat: "RGB16F", format: "RGB", destFormat: "R16F", valid: true, renderable: false, },
+ { internalformat: "RGB16F", format: "RGB", destFormat: "RG16F", valid: true, renderable: false, },
+ { internalformat: "RGB16F", format: "RGB", destFormat: "RGB16F", valid: true, renderable: false, },
+ { internalformat: "RGB16F", format: "RGB", destFormat: "RGBA16F", valid: false, renderable: false, },
+ { internalformat: "RG16F", format: "RG", destFormat: "R16F", valid: true, renderable: true, },
+ { internalformat: "RG16F", format: "RG", destFormat: "RG16F", valid: true, renderable: true, },
+ { internalformat: "RG16F", format: "RG", destFormat: "RGB16F", valid: false, renderable: true, },
+ { internalformat: "RG16F", format: "RG", destFormat: "RGBA16F", valid: false, renderable: true, },
+ { internalformat: "R16F", format: "RED", destFormat: "R16F", valid: true, renderable: true, },
+ { internalformat: "R16F", format: "RED", destFormat: "RG16F", valid: false, renderable: true, },
+ { internalformat: "R16F", format: "RED", destFormat: "RGB16F", valid: false, renderable: true, },
+ { internalformat: "R16F", format: "RED", destFormat: "RGBA16F", valid: false, renderable: true, },
+ ];
+ if (version == 1) {
+ cases = [
+ { valid: true, renderable: true, format: "RGBA", destFormat: "LUMINANCE", },
+ { valid: true, renderable: true, format: "RGBA", destFormat: "ALPHA", },
+ { valid: true, renderable: true, format: "RGBA", destFormat: "LUMINANCE_ALPHA", },
+ { valid: true, renderable: true, format: "RGBA", destFormat: "RGB", },
+ { valid: true, renderable: true, format: "RGBA", destFormat: "RGBA", },
+ { valid: true, renderable: true, format: "RGB", destFormat: "LUMINANCE", },
+ { valid: false, renderable: true, format: "RGB", destFormat: "ALPHA", },
+ { valid: false, renderable: true, format: "RGB", destFormat: "LUMINANCE_ALPHA", },
+ { valid: true, renderable: true, format: "RGB", destFormat: "RGB", },
+ { valid: false, renderable: true, format: "RGB", destFormat: "RGBA", },
+ { valid: true, renderable: false, format: "ALPHA", destFormat: "ALPHA", },
+ { valid: true, renderable: false, format: "LUMINANCE", destFormat: "LUMINANCE", },
+ { valid: true, renderable: false, format: "LUMINANCE_ALPHA", destFormat: "LUMINANCE_ALPHA", },
+ ];
+ }
+ cases.forEach(function(testcase) {
+ debug("");
+ debug(`Testing CopyTexImage2D for format: ${testcase.format}, internalformat: ${testcase.internalformat}, destformat: ${testcase.destFormat}`);
+
+ var format = gl[testcase.format];
+ var internalformat = version > 1 ? gl[testcase.internalformat] : format;
+ var type = version > 1 ? gl.HALF_FLOAT : 0x8D61 /* HALF_FLOAT_OES */;
+ var destFormat = gl[testcase.destFormat];
+ var texSrc = gl.createTexture();
+ gl.bindTexture(gl.TEXTURE_2D, texSrc);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
+ var data = new Uint16Array(width * height * 4);
+ gl.texImage2D(gl.TEXTURE_2D, level, internalformat, width, height, 0, format, type, data);
+ var fbo = gl.createFramebuffer();
+ gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
+ gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texSrc, level);
+ var texDest = gl.createTexture();
+ gl.bindTexture(gl.TEXTURE_2D, texDest);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Setup framebuffer with texture should succeed.");
+ if (enabled && testcase.renderable) {
+ if (version == 1 && format == gl.RGB && gl.checkFramebufferStatus(gl.FRAMEBUFFER) == gl.FRAMEBUFFER_INCOMPLETE_ATTACHMENT) {
+ testPassed("RGB framebuffer attachment not supported. This is allowed.")
+ } else {
+ shouldBe("gl.checkFramebufferStatus(gl.FRAMEBUFFER)", "gl.FRAMEBUFFER_COMPLETE");
+ gl.copyTexImage2D(gl.TEXTURE_2D, level, destFormat, 0, 0, width, height, 0);
+ wtu.glErrorShouldBe(gl, testcase.valid ? gl.NO_ERROR : [gl.INVALID_ENUM, gl.INVALID_OPERATION], "CopyTexImage2D");
+ }
+ } else {
+ shouldBe("gl.checkFramebufferStatus(gl.FRAMEBUFFER)", "gl.FRAMEBUFFER_INCOMPLETE_ATTACHMENT");
+ gl.copyTexImage2D(gl.TEXTURE_2D, level, destFormat, 0, 0, width, height, 0);
+ wtu.glErrorShouldBe(gl, [gl.INVALID_ENUM, gl.INVALID_FRAMEBUFFER_OPERATION], "CopyTexImage2D should fail.");
+ }
+
+ gl.deleteTexture(texDest);
+ gl.deleteTexture(texSrc);
+ gl.deleteFramebuffer(fbo);
+ });
+}
+
+description("This test verifies the functionality of the EXT_color_buffer_half_float extension, if it is available.");
+
+debug("");
+
+var wtu = WebGLTestUtils;
+var canvas = document.getElementById("canvas");
+var gl = wtu.create3DContext(canvas, null, version);
+
+if (version < 2) {
+ // These are exposed on the extension, but we need them before the extension has been requested so we can
+ // make sure they don't work.
+ gl.R16F = 0x822D;
+ gl.RG16F = 0x822F;
+ gl.RGB16F = 0x881B;
+ gl.RGBA16F = 0x881A;
+}
+
+if (!gl) {
+ testFailed("WebGL context does not exist");
+} else {
+ testPassed("WebGL context exists");
+
+ var texturedShaders = [
+ wtu.simpleTextureVertexShader,
+ `precision mediump float;
+ uniform sampler2D tex;
+ uniform vec4 subtractor;
+ varying vec2 texCoord;
+ void main()
+ {
+ vec4 color = texture2D(tex, texCoord);
+ if (abs(color.r - subtractor.r) +
+ abs(color.g - subtractor.g) +
+ abs(color.b - subtractor.b) +
+ abs(color.a - subtractor.a) < 16.0) {
+ gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);
+ } else {
+ gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
+ }
+ }`,
+ ];
+ var testProgram =
+ wtu.setupProgram(gl,
+ texturedShaders,
+ ['vPosition', 'texCoord0'],
+ [0, 1]);
+ var quadParameters = wtu.setupUnitQuad(gl, 0, 1);
+
+ if (version > 1) {
+ // Ensure these formats can't be used for rendering if the extension is disabled
+ runFloatTextureRenderTargetTest(false, "gl.R16F", gl.RED, gl.FLOAT);
+ runFloatTextureRenderTargetTest(false, "gl.RG16F", gl.RG, gl.FLOAT);
+ runFloatTextureRenderTargetTest(false, "gl.RGBA16F", gl.RGBA, gl.FLOAT);
+ }
+
+ runFloatRenderbufferRenderTargetTest(false, "gl.R16F");
+ runFloatRenderbufferRenderTargetTest(false, "gl.RG16F");
+ runFloatRenderbufferRenderTargetTest(false, "gl.RGBA16F");
+ runFloatRenderbufferRenderTargetTest(false, "gl.R32F");
+ runFloatRenderbufferRenderTargetTest(false, "gl.RG32F");
+ runFloatRenderbufferRenderTargetTest(false, "gl.RGBA32F");
+ runFloatRenderbufferRenderTargetTest(false, "gl.R11F_G11F_B10F");
+
+ if (version > 1) {
+ runCopyTexImageTest(false);
+ // Ensure RGB16F can't be used for rendering.
+ runRGB16FNegativeTest();
+ }
+
+ let oesTextureHalfFloat = null;
+ if (version == 1) {
+ // oesTextureHalfFloat implicitly enables EXT_color_buffer_half_float if supported
+ oesTextureHalfFloat = gl.getExtension("OES_texture_half_float");
+ if (oesTextureHalfFloat && gl.getSupportedExtensions().includes("EXT_color_buffer_half_float")) {
+ runFloatTextureRenderTargetTest(true, "gl.RGBA", gl.RGBA, oesTextureHalfFloat.HALF_FLOAT_OES, testProgram, 4, [1000, 1000, 1000, 1000], 0);
+ runFloatTextureRenderTargetTest(true, "gl.RGB", gl.RGB, oesTextureHalfFloat.HALF_FLOAT_OES, testProgram, 3, [1000, 1000, 1000, 1], 0);
+ }
+ }
+
+ var ext = null;
+ if (!(ext = gl.getExtension("EXT_color_buffer_half_float"))) {
+ testPassed("No EXT_color_buffer_half_float support -- this is legal");
+ } else {
+ testPassed("Successfully enabled EXT_color_buffer_half_float extension");
+
+ shouldBe("ext.RGB16F_EXT", "gl.RGB16F");
+ shouldBe("ext.RGBA16F_EXT", "gl.RGBA16F");
+ shouldBe("ext.FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE_EXT", "0x8211");
+ shouldBe("ext.UNSIGNED_NORMALIZED_EXT", "0x8C17");
+
+ if (version > 1) {
+ runInternalFormatQueryTest();
+ runFloatTextureRenderTargetTest(true, "gl.R16F", gl.RED, gl.FLOAT, testProgram, 1, [1000, 1, 1, 1], 0);
+ runFloatTextureRenderTargetTest(true, "gl.RG16F", gl.RG, gl.FLOAT, testProgram, 2, [1000, 1000, 1, 1], 0);
+ runFloatTextureRenderTargetTest(true, "gl.RGBA16F", gl.RGBA, gl.FLOAT, testProgram, 4, [1000, 1000, 1000, 1000], 0);
+ runFloatRenderbufferRenderTargetTest(true, "gl.R16F", testProgram, 1, [1000, 1, 1, 1]);
+ runFloatRenderbufferRenderTargetTest(true, "gl.RG16F", testProgram, 2, [1000, 1000, 1, 1]);
+ runFloatRenderbufferRenderTargetTest(true, "gl.RGBA16F", testProgram, 4, [1000, 1000, 1000, 1000]);
+ }
+ if (version == 1) {
+ shouldBeNonNull(oesTextureHalfFloat); // Required by spec
+ runFloatTextureRenderTargetTest(true, "gl.RGBA", gl.RGBA, oesTextureHalfFloat.HALF_FLOAT_OES, testProgram, 4, [1000, 1000, 1000, 1000], 0);
+ runFloatTextureRenderTargetTest(true, "gl.RGB", gl.RGB, oesTextureHalfFloat.HALF_FLOAT_OES, testProgram, 3, [1000, 1000, 1000, 1], 0);
+ runFloatTextureRenderTargetTest(false, "gl.LUMINANCE_ALPHA", gl.LUMINANCE_ALPHA, oesTextureHalfFloat.HALF_FLOAT_OES, testProgram, 2, [1000, 1000, 1000, 1000], 0);
+ runFloatTextureRenderTargetTest(false, "gl.LUMINANCE", gl.LUMINANCE, oesTextureHalfFloat.HALF_FLOAT_OES, testProgram, 1, [1000, 1, 1, 1], 0);
+ }
+
+ if (version > 1)
+ runRGB16FNegativeTest(); // Ensure EXT_color_buffer_half_float does not enable RGB16F as color renderable.
+
+ runCopyTexImageTest(true);
+
+ runUniqueObjectTest();
+ }
+}
+
+debug("");
+var successfullyParsed = true;
diff --git a/dom/canvas/test/webgl-conf/checkout/js/tests/ext-float-blend.js b/dom/canvas/test/webgl-conf/checkout/js/tests/ext-float-blend.js
new file mode 100644
index 0000000000..ab2f9f9288
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/js/tests/ext-float-blend.js
@@ -0,0 +1,237 @@
+'use strict';
+
+const trivialVsSrc = `
+void main()
+{
+ gl_Position = vec4(0,0,0,1);
+}
+`;
+const trivialFsSrc = `
+void main()
+{
+ gl_FragColor = vec4(0,1,0,1);
+}
+`;
+const trivialVsMrtSrc100 = `
+void main()
+{
+ gl_Position = vec4(0,0,0,1);
+}
+`;
+const trivialFsMrtSrc100 = `
+#extension GL_EXT_draw_buffers : require
+precision mediump float;
+void main()
+{
+ gl_FragData[0] = vec4(1, 0, 0, 1);
+ gl_FragData[1] = vec4(0, 1, 0, 1);
+}
+`;
+const trivialVsMrtSrc300 = `#version 300 es
+void main()
+{
+ gl_Position = vec4(0,0,0,1);
+}
+`;
+const trivialFsMrtSrc300 = `#version 300 es
+precision mediump float;
+layout(location = 0) out vec4 o_color0;
+layout(location = 1) out vec4 o_color1;
+void main()
+{
+ o_color0 = vec4(1, 0, 0, 1);
+ o_color1 = vec4(0, 1, 0, 1);
+}
+`;
+
+function testExtFloatBlend(internalFormat) {
+ const shouldBlend = gl.getSupportedExtensions().indexOf('EXT_float_blend') != -1;
+
+ const prog = wtu.setupProgram(gl, [trivialVsSrc, trivialFsSrc]);
+ gl.useProgram(prog);
+
+ const tex = gl.createTexture();
+ gl.bindTexture(gl.TEXTURE_2D, tex);
+ gl.texImage2D(gl.TEXTURE_2D, 0, internalFormat, 1, 1, 0, gl.RGBA, gl.FLOAT, null);
+
+ const fb = gl.createFramebuffer();
+ gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
+ gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex, 0);
+ shouldBe('gl.checkFramebufferStatus(gl.FRAMEBUFFER)', 'gl.FRAMEBUFFER_COMPLETE');
+
+ gl.disable(gl.BLEND);
+ gl.drawArrays(gl.POINTS, 0, 1);
+ wtu.glErrorShouldBe(gl, 0, 'Float32 draw target without blending');
+
+ gl.enable(gl.BLEND);
+ gl.drawArrays(gl.POINTS, 0, 1);
+ wtu.glErrorShouldBe(gl, shouldBlend ? 0 : gl.INVALID_OPERATION,
+ 'Float32 blending is ' + (shouldBlend ? '' : 'not ') + 'allowed ');
+
+ gl.deleteFramebuffer(fb);
+ gl.deleteTexture(tex);
+}
+
+function testExtFloatBlendMRTImpl(version, internalFormat, shaders, attachments, drawBuffers) {
+ const shouldBlend = gl.getSupportedExtensions().indexOf('EXT_float_blend') != -1;
+
+ const prog = wtu.setupProgram(gl, shaders);
+ gl.useProgram(prog);
+
+ const tex1 = gl.createTexture();
+ gl.bindTexture(gl.TEXTURE_2D, tex1);
+ gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
+
+ const tex2 = gl.createTexture();
+ gl.bindTexture(gl.TEXTURE_2D, tex2);
+ gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
+
+ const texF1 = gl.createTexture();
+ gl.bindTexture(gl.TEXTURE_2D, texF1);
+ gl.texImage2D(gl.TEXTURE_2D, 0, internalFormat, 1, 1, 0, gl.RGBA, gl.FLOAT, null);
+
+ const texF2 = gl.createTexture();
+ gl.bindTexture(gl.TEXTURE_2D, texF2);
+ gl.texImage2D(gl.TEXTURE_2D, 0, internalFormat, 1, 1, 0, gl.RGBA, gl.FLOAT, null);
+
+ const fb = gl.createFramebuffer();
+ gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
+ gl.framebufferTexture2D(gl.FRAMEBUFFER, attachments[0], gl.TEXTURE_2D, tex1, 0);
+ gl.framebufferTexture2D(gl.FRAMEBUFFER, attachments[1], gl.TEXTURE_2D, tex2, 0);
+ shouldBe('gl.checkFramebufferStatus(gl.FRAMEBUFFER)', 'gl.FRAMEBUFFER_COMPLETE');
+
+ drawBuffers(attachments);
+
+ gl.enable(gl.BLEND);
+
+ gl.drawArrays(gl.POINTS, 0, 1);
+ wtu.glErrorShouldBe(gl, 0, 'No Float32 color attachment');
+
+ if (version < 2) {
+ // EXT_draw_buffers require all color buffers having the same number of bitplanes
+ gl.framebufferTexture2D(gl.FRAMEBUFFER, attachments[0], gl.TEXTURE_2D, texF1, 0);
+ gl.framebufferTexture2D(gl.FRAMEBUFFER, attachments[1], gl.TEXTURE_2D, texF2, 0);
+ shouldBe('gl.checkFramebufferStatus(gl.FRAMEBUFFER)', 'gl.FRAMEBUFFER_COMPLETE');
+ gl.drawArrays(gl.POINTS, 0, 1);
+ wtu.glErrorShouldBe(gl, shouldBlend ? 0 : gl.INVALID_OPERATION,
+ 'Float32 blending is ' + (shouldBlend ? '' : 'not ') + 'allowed ');
+ } else {
+ gl.framebufferTexture2D(gl.FRAMEBUFFER, attachments[0], gl.TEXTURE_2D, texF1, 0);
+ shouldBe('gl.checkFramebufferStatus(gl.FRAMEBUFFER)', 'gl.FRAMEBUFFER_COMPLETE');
+ gl.drawArrays(gl.POINTS, 0, 1);
+ wtu.glErrorShouldBe(gl, shouldBlend ? 0 : gl.INVALID_OPERATION,
+ 'Float32 blending is ' + (shouldBlend ? '' : 'not ') + 'allowed ');
+
+ gl.framebufferTexture2D(gl.FRAMEBUFFER, attachments[1], gl.TEXTURE_2D, texF2, 0);
+ shouldBe('gl.checkFramebufferStatus(gl.FRAMEBUFFER)', 'gl.FRAMEBUFFER_COMPLETE');
+ gl.drawArrays(gl.POINTS, 0, 1);
+ wtu.glErrorShouldBe(gl, shouldBlend ? 0 : gl.INVALID_OPERATION,
+ 'Float32 blending is ' + (shouldBlend ? '' : 'not ') + 'allowed ');
+
+ gl.framebufferTexture2D(gl.FRAMEBUFFER, attachments[0], gl.TEXTURE_2D, tex1, 0);
+ shouldBe('gl.checkFramebufferStatus(gl.FRAMEBUFFER)', 'gl.FRAMEBUFFER_COMPLETE');
+ gl.drawArrays(gl.POINTS, 0, 1);
+ wtu.glErrorShouldBe(gl, shouldBlend ? 0 : gl.INVALID_OPERATION,
+ 'Float32 blending is ' + (shouldBlend ? '' : 'not ') + 'allowed ');
+
+ drawBuffers([attachments[0]]);
+ shouldBe('gl.checkFramebufferStatus(gl.FRAMEBUFFER)', 'gl.FRAMEBUFFER_COMPLETE');
+
+ gl.drawArrays(gl.POINTS, 0, 1);
+ wtu.glErrorShouldBe(gl, 0, 'Float32 color attachment draw buffer is not enabled');
+
+ drawBuffers(attachments);
+ gl.framebufferTexture2D(gl.FRAMEBUFFER, attachments[1], gl.TEXTURE_2D, tex2, 0);
+ shouldBe('gl.checkFramebufferStatus(gl.FRAMEBUFFER)', 'gl.FRAMEBUFFER_COMPLETE');
+
+ gl.drawArrays(gl.POINTS, 0, 1);
+ wtu.glErrorShouldBe(gl, 0, 'No Float32 color attachment');
+ }
+
+ gl.deleteFramebuffer(fb);
+ gl.deleteTexture(tex1);
+ gl.deleteTexture(tex2);
+ gl.deleteTexture(texF1);
+ gl.deleteTexture(texF2);
+}
+
+function testExtFloatBlendMRT(version, drawBuffersExt) {
+ if (version < 2) {
+ if (!drawBuffersExt) return;
+ testExtFloatBlendMRTImpl(
+ version,
+ gl.RGBA,
+ [trivialVsMrtSrc100, trivialFsMrtSrc100],
+ [drawBuffersExt.COLOR_ATTACHMENT0_WEBGL, drawBuffersExt.COLOR_ATTACHMENT1_WEBGL],
+ drawBuffersExt.drawBuffersWEBGL.bind(drawBuffersExt)
+ );
+ } else {
+ testExtFloatBlendMRTImpl(
+ version,
+ gl.RGBA32F,
+ [trivialVsMrtSrc300, trivialFsMrtSrc300],
+ [gl.COLOR_ATTACHMENT0, gl.COLOR_ATTACHMENT1],
+ gl.drawBuffers.bind(gl)
+ );
+ }
+}
+
+function testExtFloatBlendNonFloat32TypeImpl(internalFormat, formats) {
+ const shouldBlend = gl.getSupportedExtensions().indexOf('EXT_float_blend') != -1;
+
+ const prog = wtu.setupProgram(gl, [trivialVsSrc, trivialFsSrc]);
+ gl.useProgram(prog);
+
+ gl.enable(gl.BLEND);
+
+ const tex = gl.createTexture();
+ gl.bindTexture(gl.TEXTURE_2D, tex);
+ gl.texImage2D(gl.TEXTURE_2D, 0, internalFormat, 1, 1, 0, gl.RGBA, gl.FLOAT, null);
+
+ const fb = gl.createFramebuffer();
+ gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
+ gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex, 0);
+ shouldBe('gl.checkFramebufferStatus(gl.FRAMEBUFFER)', 'gl.FRAMEBUFFER_COMPLETE');
+
+ gl.drawArrays(gl.POINTS, 0, 1);
+ wtu.glErrorShouldBe(gl, shouldBlend ? 0 : gl.INVALID_OPERATION,
+ 'Float32 blending is ' + (shouldBlend ? '' : 'not ') + 'allowed ');
+
+ gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
+ gl.drawArrays(gl.POINTS, 0, 1);
+ wtu.glErrorShouldBe(gl, 0, 'UNSIGNED_BYTE should blend anyway');
+
+ for (let i = 0, len = formats.length; i < len; i++) {
+ gl.texImage2D(gl.TEXTURE_2D, 0, formats[i][0], 1, 1, 0, formats[i][1], formats[i][2], null);
+ gl.drawArrays(gl.POINTS, 0, 1);
+ wtu.glErrorShouldBe(gl, 0, 'Any other float type which is not 32-bit-Float should blend anyway');
+ }
+
+ gl.deleteFramebuffer(fb);
+ gl.deleteTexture(tex);
+}
+
+function testExtFloatBlendNonFloat32Type(version, oesTextureHalfFloat) {
+ if (version < 2) {
+ if (!oesTextureHalfFloat) return;
+ const formats = [
+ [gl.RGBA, gl.RGBA, oesTextureHalfFloat.HALF_FLOAT_OES]
+ ];
+ testExtFloatBlendNonFloat32TypeImpl(gl.RGBA, formats);
+ } else {
+ const formats = [
+ [gl.RGBA16F, gl.RGBA, gl.HALF_FLOAT],
+ [gl.RGBA16F, gl.RGBA, gl.FLOAT],
+ [gl.RG16F, gl.RG, gl.FLOAT],
+ [gl.R16F, gl.RED, gl.FLOAT],
+ [gl.R11F_G11F_B10F, gl.RGB, gl.FLOAT]
+ ];
+ testExtFloatBlendNonFloat32TypeImpl(gl.RGBA32F, formats);
+ }
+}
+
+/*
+Copyright (c) 2019 The Khronos Group Inc.
+Use of this source code is governed by an MIT-style license that can be
+found in the LICENSE.txt file.
+*/
diff --git a/dom/canvas/test/webgl-conf/checkout/js/tests/ext-texture-filter-anisotropic.js b/dom/canvas/test/webgl-conf/checkout/js/tests/ext-texture-filter-anisotropic.js
new file mode 100644
index 0000000000..1e60a79717
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/js/tests/ext-texture-filter-anisotropic.js
@@ -0,0 +1,169 @@
+"use strict";
+description("This test verifies the functionality of the EXT_texture_filter_anisotropic extension, if it is available.");
+
+debug("");
+
+let wtu = WebGLTestUtils;
+let canvas = document.getElementById("canvas");
+let gl = wtu.create3DContext(canvas, undefined, contextVersion);
+let ext = null;
+let sampler;
+
+if (!gl) {
+ testFailed("WebGL context does not exist");
+} else {
+ testPassed("WebGL context exists");
+
+ // Run tests with extension disabled
+ runHintTestDisabled();
+ if (contextVersion >= 2) {
+ runSamplerTestDisabled();
+ }
+
+ // Query the extension and store globally so shouldBe can access it
+ ext = wtu.getExtensionWithKnownPrefixes(gl, "EXT_texture_filter_anisotropic");
+
+ if (!ext) {
+ testPassed("No EXT_texture_filter_anisotropic support -- this is legal");
+
+ runSupportedTest(false);
+ } else {
+ testPassed("Successfully enabled EXT_texture_filter_anisotropic extension");
+
+ runSupportedTest(true);
+ runHintTestEnabled();
+ if (contextVersion >= 2) {
+ runSamplerTestEnabled();
+ }
+ }
+}
+
+function runSupportedTest(extensionEnabled) {
+ if (wtu.getSupportedExtensionWithKnownPrefixes(gl, "EXT_texture_filter_anisotropic") !== undefined) {
+ if (extensionEnabled) {
+ testPassed("EXT_texture_filter_anisotropic listed as supported and getExtension succeeded");
+ } else {
+ testFailed("EXT_texture_filter_anisotropic listed as supported but getExtension failed");
+ }
+ } else {
+ if (extensionEnabled) {
+ testFailed("EXT_texture_filter_anisotropic not listed as supported but getExtension succeeded");
+ } else {
+ testPassed("EXT_texture_filter_anisotropic not listed as supported and getExtension failed -- this is legal");
+ }
+ }
+}
+
+function runHintTestDisabled() {
+ debug("Testing MAX_TEXTURE_MAX_ANISOTROPY_EXT with extension disabled");
+
+ const MAX_TEXTURE_MAX_ANISOTROPY_EXT = 0x84FF;
+ shouldBeNull(`gl.getParameter(${MAX_TEXTURE_MAX_ANISOTROPY_EXT})`);
+ wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "MAX_TEXTURE_MAX_ANISOTROPY_EXT should not be queryable if extension is disabled");
+
+ debug("Testing TEXTURE_MAX_ANISOTROPY_EXT with extension disabled");
+ const TEXTURE_MAX_ANISOTROPY_EXT = 0x84FE;
+ let texture = gl.createTexture();
+ gl.bindTexture(gl.TEXTURE_2D, texture);
+
+ shouldBeNull(`gl.getTexParameter(gl.TEXTURE_2D, ${TEXTURE_MAX_ANISOTROPY_EXT})`);
+ wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "TEXTURE_MAX_ANISOTROPY_EXT should not be queryable if extension is disabled");
+
+ gl.texParameterf(gl.TEXTURE_2D, TEXTURE_MAX_ANISOTROPY_EXT, 1);
+ wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "TEXTURE_MAX_ANISOTROPY_EXT should not be settable if extension is disabled");
+
+ gl.texParameteri(gl.TEXTURE_2D, TEXTURE_MAX_ANISOTROPY_EXT, 1);
+ wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "TEXTURE_MAX_ANISOTROPY_EXT should not be settable if extension is disabled");
+
+ gl.deleteTexture(texture);
+}
+
+function runHintTestEnabled() {
+ debug("Testing MAX_TEXTURE_MAX_ANISOTROPY_EXT with extension enabled");
+
+ shouldBe("ext.MAX_TEXTURE_MAX_ANISOTROPY_EXT", "0x84FF");
+
+ let max_anisotropy = gl.getParameter(ext.MAX_TEXTURE_MAX_ANISOTROPY_EXT);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "MAX_TEXTURE_MAX_ANISOTROPY_EXT query should succeed if extension is enabled");
+
+ if (max_anisotropy >= 2) {
+ testPassed("Minimum value of MAX_TEXTURE_MAX_ANISOTROPY_EXT is 2.0");
+ } else {
+ testFailed("Minimum value of MAX_TEXTURE_MAX_ANISOTROPY_EXT is 2.0, returned values was: " + max_anisotropy);
+ }
+
+ // TODO make a texture and verify initial value == 1 and setting to less than 1 is invalid value
+
+ debug("Testing TEXTURE_MAX_ANISOTROPY_EXT with extension disabled");
+ shouldBe("ext.TEXTURE_MAX_ANISOTROPY_EXT", "0x84FE");
+
+ let texture = gl.createTexture();
+ gl.bindTexture(gl.TEXTURE_2D, texture);
+
+ let queried_value = gl.getTexParameter(gl.TEXTURE_2D, ext.TEXTURE_MAX_ANISOTROPY_EXT);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "TEXTURE_MAX_ANISOTROPY_EXT query should succeed if extension is enabled");
+
+ if (queried_value == 1) {
+ testPassed("Initial value of TEXTURE_MAX_ANISOTROPY_EXT is 1.0");
+ } else {
+ testFailed("Initial value of TEXTURE_MAX_ANISOTROPY_EXT should be 1.0, returned value was: " + queried_value);
+ }
+
+ gl.texParameterf(gl.TEXTURE_2D, ext.TEXTURE_MAX_ANISOTROPY_EXT, 0);
+ wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, "texParameterf TEXTURE_MAX_ANISOTROPY_EXT set to < 1 should be an invalid value");
+
+ gl.texParameteri(gl.TEXTURE_2D, ext.TEXTURE_MAX_ANISOTROPY_EXT, 0);
+ wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, "texParameteri TEXTURE_MAX_ANISOTROPY_EXT set to < 1 should be an invalid value");
+
+ gl.texParameterf(gl.TEXTURE_2D, ext.TEXTURE_MAX_ANISOTROPY_EXT, max_anisotropy);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "texParameterf TEXTURE_MAX_ANISOTROPY_EXT set to >= 2 should succeed");
+
+ gl.texParameteri(gl.TEXTURE_2D, ext.TEXTURE_MAX_ANISOTROPY_EXT, max_anisotropy);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "texParameteri TEXTURE_MAX_ANISOTROPY_EXT set to >= 2 should succeed");
+
+ queried_value = gl.getTexParameter(gl.TEXTURE_2D, ext.TEXTURE_MAX_ANISOTROPY_EXT);
+ if (queried_value == max_anisotropy) {
+ testPassed("Set value of TEXTURE_MAX_ANISOTROPY_EXT matches expecation");
+ } else {
+ testFailed("Set value of TEXTURE_MAX_ANISOTROPY_EXT should be: " + max_anisotropy + " , returned value was: " + queried_value);
+ }
+
+ gl.texParameterf(gl.TEXTURE_2D, ext.TEXTURE_MAX_ANISOTROPY_EXT, 1.5);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "texParameterf TEXTURE_MAX_ANISOTROPY_EXT set to 1.5 should succeed");
+
+ queried_value = gl.getTexParameter(gl.TEXTURE_2D, ext.TEXTURE_MAX_ANISOTROPY_EXT);
+ if (queried_value == 1.5) {
+ testPassed("Set value of TEXTURE_MAX_ANISOTROPY_EXT matches expecation");
+ } else {
+ testFailed("Set value of TEXTURE_MAX_ANISOTROPY_EXT should be: " + 1.5 + " , returned value was: " + queried_value);
+ }
+
+ gl.deleteTexture(texture);
+}
+
+function runSamplerTestDisabled() {
+ sampler = gl.createSampler();
+ const TEXTURE_MAX_ANISOTROPY_EXT = 0x84FE;
+ gl.samplerParameterf(sampler, TEXTURE_MAX_ANISOTROPY_EXT, 1.0);
+ wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "setting TEXTURE_MAX_ANISOTROPY_EXT on sampler without extension enabled should fail");
+ shouldBeNull(`gl.getSamplerParameter(sampler, ${TEXTURE_MAX_ANISOTROPY_EXT})`);
+ wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "querying TEXTURE_MAX_ANISOTROPY_EXT on sampler without extension enabled should fail");
+ gl.deleteSampler(sampler);
+}
+
+function runSamplerTestEnabled() {
+ let sampler = gl.createSampler();
+ gl.samplerParameterf(sampler, ext.TEXTURE_MAX_ANISOTROPY_EXT, 1.5);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "setting TEXTURE_MAX_ANISOTROPY_EXT on sampler should succeed");
+ let queried_value = gl.getSamplerParameter(sampler, ext.TEXTURE_MAX_ANISOTROPY_EXT);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "querying TEXTURE_MAX_ANISOTROPY_EXT on sampler should succeed");
+ if (queried_value == 1.5) {
+ testPassed("Set value of TEXTURE_MAX_ANISOTROPY_EXT on sampler matches expecation");
+ } else {
+ testFailed("Set value of TEXTURE_MAX_ANISOTROPY_EXT on sampler should be: " + 1.5 + " , returned value was: " + queried_value);
+ }
+ gl.deleteSampler(sampler);
+}
+
+debug("");
+var successfullyParsed = true;
diff --git a/dom/canvas/test/webgl-conf/checkout/js/tests/gl-bindattriblocation-aliasing.js b/dom/canvas/test/webgl-conf/checkout/js/tests/gl-bindattriblocation-aliasing.js
new file mode 100644
index 0000000000..4c853fc4fa
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/js/tests/gl-bindattriblocation-aliasing.js
@@ -0,0 +1,44 @@
+/*
+Copyright (c) 2019 The Khronos Group Inc.
+Use of this source code is governed by an MIT-style license that can be
+found in the LICENSE.txt file.
+*/
+
+"use strict";
+
+var runBindAttribLocationAliasingTest = function(wtu, gl, glFragmentShader, vertexShaderTemplate) {
+ var typeInfo = [
+ { type: 'float', asVec4: 'vec4(0.0, $(var), 0.0, 1.0)' },
+ { type: 'vec2', asVec4: 'vec4($(var), 0.0, 1.0)' },
+ { type: 'vec3', asVec4: 'vec4($(var), 1.0)' },
+ { type: 'vec4', asVec4: '$(var)' },
+ ];
+ var maxAttributes = gl.getParameter(gl.MAX_VERTEX_ATTRIBS);
+ // Test all type combinations of a_1 and a_2.
+ typeInfo.forEach(function(typeInfo1) {
+ typeInfo.forEach(function(typeInfo2) {
+ debug('attribute_1: ' + typeInfo1.type + ' attribute_2: ' + typeInfo2.type);
+ var replaceParams = {
+ type_1: typeInfo1.type,
+ type_2: typeInfo2.type,
+ gl_Position_1: wtu.replaceParams(typeInfo1.asVec4, {var: 'a_1'}),
+ gl_Position_2: wtu.replaceParams(typeInfo2.asVec4, {var: 'a_2'})
+ };
+ var strVertexShader = wtu.replaceParams(vertexShaderTemplate, replaceParams);
+ var glVertexShader = wtu.loadShader(gl, strVertexShader, gl.VERTEX_SHADER);
+ assertMsg(glVertexShader != null, "Vertex shader compiled successfully.");
+ // Bind both a_1 and a_2 to the same position and verify the link fails.
+ // Do so for all valid positions available.
+ for (var l = 0; l < maxAttributes; l++) {
+ var glProgram = gl.createProgram();
+ gl.bindAttribLocation(glProgram, l, 'a_1');
+ gl.bindAttribLocation(glProgram, l, 'a_2');
+ gl.attachShader(glProgram, glVertexShader);
+ gl.attachShader(glProgram, glFragmentShader);
+ gl.linkProgram(glProgram);
+ var linkStatus = gl.getProgramParameter(glProgram, gl.LINK_STATUS);
+ assertMsg(!linkStatus, "Link should fail when both attributes are aliased to location " + l);
+ }
+ });
+ });
+}; \ No newline at end of file
diff --git a/dom/canvas/test/webgl-conf/checkout/js/tests/gl-enum-tests.js b/dom/canvas/test/webgl-conf/checkout/js/tests/gl-enum-tests.js
new file mode 100644
index 0000000000..32d451f7a2
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/js/tests/gl-enum-tests.js
@@ -0,0 +1,123 @@
+/*
+Copyright (c) 2019 The Khronos Group Inc.
+Use of this source code is governed by an MIT-style license that can be
+found in the LICENSE.txt file.
+*/
+
+// This test relies on the surrounding web page defining a variable
+// "contextVersion" which indicates what version of WebGL it's running
+// on -- 1 for WebGL 1.0, 2 for WebGL 2.0, etc.
+
+"use strict";
+description("This test ensures various WebGL functions fail when passed invalid OpenGL ES enums.");
+
+debug("");
+debug("Canvas.getContext");
+
+var wtu = WebGLTestUtils;
+var gl = wtu.create3DContext("canvas", undefined, contextVersion);
+if (!gl) {
+ testFailed("context does not exist");
+} else {
+ testPassed("context exists");
+
+ debug("");
+ debug("Checking gl enums.");
+
+ var buffer = new ArrayBuffer(2);
+ var buf = new Uint16Array(buffer);
+ var tex = gl.createTexture();
+ var program = wtu.createProgram(gl, wtu.loadStandardVertexShader(gl), wtu.loadStandardFragmentShader(gl));
+ gl.bindBuffer(gl.ARRAY_BUFFER, gl.createBuffer());
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR);
+
+ var tests = [
+ "gl.disable(desktopGL['CLIP_PLANE0'])",
+ "gl.disable(desktopGL['POINT_SPRITE'])",
+ "gl.getBufferParameter(gl.ARRAY_BUFFER, desktopGL['PIXEL_PACK_BUFFER'])",
+ "gl.hint(desktopGL['PERSPECTIVE_CORRECTION_HINT'], gl.FASTEST)",
+ "gl.isEnabled(desktopGL['CLIP_PLANE0'])",
+ "gl.isEnabled(desktopGL['POINT_SPRITE'])",
+ "gl.pixelStorei(desktopGL['PACK_SWAP_BYTES'], 1)",
+ "gl.getParameter(desktopGL['NUM_COMPRESSED_TEXTURE_FORMATS'])",
+ "gl.getParameter(desktopGL['EXTENSIONS'])",
+ "gl.getParameter(desktopGL['SHADER_COMPILER'])",
+ "gl.getParameter(desktopGL['SHADER_BINARY_FORMATS'])",
+ "gl.getParameter(desktopGL['NUM_SHADER_BINARY_FORMATS'])",
+ ];
+
+ if (contextVersion < 2) {
+ tests = tests.concat([
+ "gl.blendEquation(desktopGL['MIN'])",
+ "gl.blendEquation(desktopGL['MAX'])",
+ "gl.blendEquationSeparate(desktopGL['MIN'], gl.FUNC_ADD)",
+ "gl.blendEquationSeparate(desktopGL['MAX'], gl.FUNC_ADD)",
+ "gl.blendEquationSeparate(gl.FUNC_ADD, desktopGL['MIN'])",
+ "gl.blendEquationSeparate(gl.FUNC_ADD, desktopGL['MAX'])",
+ "gl.bufferData(gl.ARRAY_BUFFER, 16, desktopGL['STREAM_READ'])",
+ "gl.bufferData(gl.ARRAY_BUFFER, 16, desktopGL['STREAM_COPY'])",
+ "gl.bufferData(gl.ARRAY_BUFFER, 16, desktopGL['STATIC_READ'])",
+ "gl.bufferData(gl.ARRAY_BUFFER, 16, desktopGL['STATIC_COPY'])",
+ "gl.bufferData(gl.ARRAY_BUFFER, 16, desktopGL['DYNAMIC_READ'])",
+ "gl.bufferData(gl.ARRAY_BUFFER, 16, desktopGL['DYNAMIC_COPY'])",
+ "gl.bindTexture(desktopGL['TEXTURE_2D_ARRAY'], tex)",
+ "gl.bindTexture(desktopGL['TEXTURE_3D'], tex)",
+ ]);
+ } else {
+ tests = tests.concat([
+ "gl.bindTexture(desktopGL['TEXTURE_RECTANGLE_EXT'], tex)",
+ "gl.enable(desktopGL['PRIMITIVE_RESTART_FIXED_INDEX'])",
+ "gl.getActiveUniforms(program, [0], desktopGL['UNIFORM_NAME_LENGTH'])",
+ "gl.getProgramParameter(program, desktopGL['ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH'])",
+ "gl.getProgramParameter(program, desktopGL['TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH'])",
+ "gl.getProgramParameter(program, desktopGL['PROGRAM_BINARY_RETRIEVABLE_HINT'])",
+ "gl.getProgramParameter(program, desktopGL['PROGRAM_BINARY_LENGTH'])",
+ "gl.getParameter(program, desktopGL['NUM_PROGRAM_BINARY_FORMATS'])",
+ ]);
+ }
+
+ for (var ii = 0; ii < tests.length; ++ii) {
+ TestEval(tests[ii]);
+ wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, tests[ii] + " should return INVALID_ENUM.");
+ }
+
+ gl.bindTexture(gl.TEXTURE_2D, tex);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR);
+
+ tests = [
+ "gl.getTexParameter(gl.TEXTURE_2D, desktopGL['GENERATE_MIPMAP'])",
+ "gl.texParameteri(gl.TEXTURE_2D, desktopGL['GENERATE_MIPMAP'], 1)",
+ "gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, desktopGL['CLAMP_TO_BORDER'])",
+ ];
+
+ if (contextVersion < 2) {
+ tests = tests.concat([
+ "gl.texParameteri(desktopGL['TEXTURE_2D_ARRAY'], gl.TEXTURE_MAG_FILTER, gl.NEAREST)",
+ "gl.texParameteri(desktopGL['TEXTURE_3D'], gl.TEXTURE_MAG_FILTER, gl.NEAREST)",
+ ]);
+ } else {
+ tests = tests.concat([
+ "gl.texParameteri(desktopGL['TEXTURE_2D'], desktopGL['TEXTURE_SWIZZLE_R_EXT'], gl.RED)",
+ "gl.texParameteri(desktopGL['TEXTURE_2D'], desktopGL['TEXTURE_SWIZZLE_G_EXT'], gl.RED)",
+ "gl.texParameteri(desktopGL['TEXTURE_2D'], desktopGL['TEXTURE_SWIZZLE_B_EXT'], gl.RED)",
+ "gl.texParameteri(desktopGL['TEXTURE_2D'], desktopGL['TEXTURE_SWIZZLE_A_EXT'], gl.RED)",
+ "gl.texParameteri(desktopGL['TEXTURE_2D'], gl.TEXTURE_WRAP_R, desktopGL['CLAMP_TO_BORDER'])",
+ ]);
+ }
+
+ for (var ii = 0; ii < tests.length; ++ii) {
+ TestEval(tests[ii]);
+ wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, tests[ii] + " should return INVALID_ENUM.");
+ }
+ if (contextVersion >= 2) {
+ var uniformBlockProgram = wtu.loadUniformBlockProgram(gl);
+ gl.linkProgram(uniformBlockProgram);
+ shouldBe('gl.getProgramParameter(uniformBlockProgram, gl.LINK_STATUS)', 'true');
+ shouldBe('gl.getError()', 'gl.NO_ERROR');
+ gl.getActiveUniformBlockParameter(uniformBlockProgram, 0, desktopGL['UNIFORM_BLOCK_NAME_LENGTH']);
+ shouldBe('gl.getError()', 'gl.INVALID_ENUM');
+ }
+}
+
+debug("");
+var successfullyParsed = true;
diff --git a/dom/canvas/test/webgl-conf/checkout/js/tests/gl-get-tex-parameter.js b/dom/canvas/test/webgl-conf/checkout/js/tests/gl-get-tex-parameter.js
new file mode 100644
index 0000000000..8844bbf544
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/js/tests/gl-get-tex-parameter.js
@@ -0,0 +1,183 @@
+/*
+Copyright (c) 2019 The Khronos Group Inc.
+Use of this source code is governed by an MIT-style license that can be
+found in the LICENSE.txt file.
+*/
+
+// This test relies on the surrounding web page defining a variable
+// "contextVersion" which indicates what version of WebGL it's running
+// on -- 1 for WebGL 1.0, 2 for WebGL 2.0, etc.
+
+"use strict";
+description();
+var wtu = WebGLTestUtils;
+var gl = wtu.create3DContext("example", undefined, contextVersion);
+
+// NOTE: We explicitly do this in a funky order
+// to hopefully find subtle bugs.
+
+var targets = [
+ 'TEXTURE_2D',
+ 'TEXTURE_2D',
+ 'TEXTURE_CUBE_MAP',
+ 'TEXTURE_CUBE_MAP'
+];
+
+if (contextVersion > 1) {
+ targets = targets.concat([
+ 'TEXTURE_2D_ARRAY',
+ 'TEXTURE_2D_ARRAY',
+ 'TEXTURE_3D',
+ 'TEXTURE_3D'
+ ]);
+}
+
+// Create textures on different active textures.
+for (var ii = 0; ii < targets.length; ++ii) {
+ var target = targets[ii];
+ var tex = gl.createTexture();
+ gl.activeTexture(gl.TEXTURE0 + ii);
+ gl.bindTexture(gl[target], tex);
+}
+
+wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors");
+
+var states = [
+ { state: 'TEXTURE_WRAP_S', default: 'REPEAT', value1: 'CLAMP_TO_EDGE', value2: 'REPEAT' },
+ { state: 'TEXTURE_WRAP_T', default: 'REPEAT', value1: 'MIRRORED_REPEAT', value2: 'REPEAT' },
+ { state: 'TEXTURE_MAG_FILTER', default: 'LINEAR', value1: 'NEAREST', value2: 'LINEAR' },
+ { state: 'TEXTURE_MIN_FILTER', default: 'NEAREST_MIPMAP_LINEAR', value1: 'LINEAR_MIPMAP_LINEAR', value2: 'NEAREST' }
+];
+
+if (contextVersion > 1) {
+ states = states.concat([
+ { state: 'TEXTURE_WRAP_R', default: 'REPEAT', value1: 'CLAMP_TO_EDGE', value2: 'MIRRORED_REPEAT' },
+ { state: 'TEXTURE_COMPARE_FUNC', default: 'LEQUAL', value1: 'GREATER', value2: 'LESS' },
+ { state: 'TEXTURE_COMPARE_MODE', default: 'NONE', value1: 'COMPARE_REF_TO_TEXTURE', value2: 'NONE' },
+ { state: 'TEXTURE_BASE_LEVEL', default: 0, value1: 100, value2: 99 },
+ { state: 'TEXTURE_MAX_LEVEL', default: 1000, value1: 800, value2: 300 },
+ { state: 'TEXTURE_MIN_LOD', default: -1000.0, value1: -500.0, value2: -999.0 },
+ { state: 'TEXTURE_MAX_LOD', default: 1000.0, value1: 500.0, value2: 999.0 },
+ // Note: For TEXTURE_IMMUTABLE_LEVELS and TEXTURE_IMMUTABLE_FORMAT,
+ // these two pname are used by getTexParameter API only, not available in texParameter[fi] in specifications.
+ // Thus, these two states store default value only.
+ { state: 'TEXTURE_IMMUTABLE_LEVELS', default: 0, },
+ { state: 'TEXTURE_IMMUTABLE_FORMAT', default: false, }
+ ]);
+}
+
+function getStateInfoValue(stateInfo, item, method) {
+ switch (stateInfo.state) {
+ case 'TEXTURE_WRAP_R':
+ case 'TEXTURE_WRAP_S':
+ case 'TEXTURE_WRAP_T':
+ case 'TEXTURE_MAG_FILTER':
+ case 'TEXTURE_MIN_FILTER':
+ case 'TEXTURE_COMPARE_FUNC':
+ case 'TEXTURE_COMPARE_MODE':
+ if (method === 'Get') {
+ return 'gl["' + stateInfo[item] + '"]';
+ } else if (method === 'Set') {
+ return gl[stateInfo[item]];
+ }
+ break;
+ case 'TEXTURE_BASE_LEVEL':
+ case 'TEXTURE_MAX_LEVEL':
+ case 'TEXTURE_MIN_LOD':
+ case 'TEXTURE_MAX_LOD':
+ if (method === 'Get') {
+ return '' + stateInfo[item];
+ } else if (method === 'Set') {
+ return stateInfo[item];
+ }
+ break;
+ case 'TEXTURE_IMMUTABLE_LEVELS':
+ case 'TEXTURE_IMMUTABLE_FORMAT':
+ // Return default value only.
+ return '' + stateInfo.default;
+ default:
+ wtu.error("Not reached!");
+ return null;
+ break;
+ }
+}
+
+function applyStates(fn) {
+ for (var ss = 0; ss < states.length; ++ss) {
+ var stateInfo = states[ss];
+ for (var ii = 0; ii < targets.length; ++ii) {
+ var target = targets[ii];
+ gl.activeTexture(gl.TEXTURE0 + ii);
+ fn(target, stateInfo);
+ }
+ }
+}
+
+// test the default state.
+applyStates(function(target, stateInfo) {
+ var a = 'gl.getTexParameter(gl["' + target + '"], gl["' + stateInfo.state + '"])';
+ var b = getStateInfoValue(stateInfo, 'default', 'Get');
+ shouldBe(a, b);
+});
+
+// test new state
+applyStates(function(target, stateInfo) {
+ switch (stateInfo.state) {
+ case 'TEXTURE_IMMUTABLE_FORMAT':
+ case 'TEXTURE_IMMUTABLE_LEVELS':
+ // Skip these two pname for texParameterf[fi].
+ break;
+ case 'TEXTURE_MIN_LOD':
+ case 'TEXTURE_MAX_LOD':
+ gl.texParameterf(gl[target], gl[stateInfo.state], getStateInfoValue(stateInfo, 'value1', 'Set'));
+ break;
+ default:
+ gl.texParameteri(gl[target], gl[stateInfo.state], getStateInfoValue(stateInfo, 'value1', 'Set'));
+ break;
+ }
+});
+
+applyStates(function(target, stateInfo) {
+ var a = 'gl.getTexParameter(gl["' + target + '"], gl["' + stateInfo.state + '"])';
+ var b = getStateInfoValue(stateInfo, 'value1', 'Get');
+ shouldBe(a, b);
+});
+
+// test different states on each target.
+function getItem(count) {
+ return (count % 2) ? 'value2' : 'value1';
+}
+
+applyStates(function() {
+ var count = 0;
+ return function(target, stateInfo) {
+ switch (stateInfo.state) {
+ case 'TEXTURE_IMMUTABLE_FORMAT':
+ case 'TEXTURE_IMMUTABLE_LEVELS':
+ // Skip these two pname for texParameterf[fi].
+ break;
+ case 'TEXTURE_MIN_LOD':
+ case 'TEXTURE_MAX_LOD':
+ gl.texParameterf(gl[target], gl[stateInfo.state], getStateInfoValue(stateInfo, getItem(count), 'Set'));
+ break;
+ default:
+ gl.texParameteri(gl[target], gl[stateInfo.state], getStateInfoValue(stateInfo, getItem(count), 'Set'));
+ break;
+ }
+ ++count;
+ }
+}());
+
+applyStates(function() {
+ var count = 0;
+ return function(target, stateInfo) {
+ var a = 'gl.getTexParameter(gl["' + target + '"], gl["' + stateInfo.state + '"])';
+ var b = getStateInfoValue(stateInfo, getItem(count), 'Get');
+ shouldBe(a, b);
+ ++count;
+ };
+}());
+
+wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors");
+
+var successfullyParsed = true;
diff --git a/dom/canvas/test/webgl-conf/checkout/js/tests/gl-object-get-calls.js b/dom/canvas/test/webgl-conf/checkout/js/tests/gl-object-get-calls.js
new file mode 100644
index 0000000000..bd97434b77
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/js/tests/gl-object-get-calls.js
@@ -0,0 +1,1090 @@
+/*
+Copyright (c) 2019 The Khronos Group Inc.
+Use of this source code is governed by an MIT-style license that can be
+found in the LICENSE.txt file.
+*/
+
+// This test relies on the surrounding web page defining a variable
+// "contextVersion" which indicates what version of WebGL it's running
+// on -- 1 for WebGL 1.0, 2 for WebGL 2.0, etc.
+
+"use strict";
+const wtu = WebGLTestUtils;
+description("Test of get calls against GL objects like getBufferParameter, etc.");
+
+let gl = wtu.create3DContext(undefined, undefined, contextVersion);
+
+async function testInvalidArgument(funcName, argumentName, validArgumentArray, func) {
+ let validArguments = {};
+ for (let ii = 0; ii < validArgumentArray.length; ++ii) {
+ validArguments[validArgumentArray[ii]] = true;
+ }
+ let success = true;
+ const MAX = 0x10000;
+ const STEP = Math.ceil(MAX / 10);
+ for (let ii = 0; ii < MAX; ii += 1) {
+ if (ii && ii % STEP == 0) {
+ debug(`(${ii} of ${MAX}: ${(ii/MAX*100).toFixed(1)}%)`);
+ await wtu.dispatchPromise(); // Spin the event loop.
+ }
+ if (!validArguments[ii]) {
+ let result = func(ii);
+ if (result !== null) {
+ success = false;
+ testFailed(funcName + " returned " + result + " instead of null for invalid " + argumentName + " enum: " + wtu.glEnumToString(gl, ii));
+ break;
+ }
+ let err = gl.getError();
+ if (err != gl.INVALID_ENUM) {
+ success = false;
+ testFailed(funcName + " did not generate INVALID_ENUM for invalid " + argumentName + " enum: " + wtu.glEnumToString(gl, ii));
+ break;
+ }
+ }
+ }
+ if (success) {
+ testPassed(funcName + " correctly handled invalid " + argumentName + " enums");
+ }
+}
+
+(async () => {
+ debug("");
+ debug("test getBufferParameter");
+ // Test getBufferParameter
+ let bufferTypes = [gl.ARRAY_BUFFER, gl.ELEMENT_ARRAY_BUFFER];
+ if (contextVersion > 1) {
+ bufferTypes = bufferTypes.concat([gl.COPY_READ_BUFFER, gl.COPY_WRITE_BUFFER, gl.PIXEL_PACK_BUFFER, gl.PIXEL_UNPACK_BUFFER, gl.TRANSFORM_FEEDBACK_BUFFER, gl.UNIFORM_BUFFER]);
+ }
+ for (let bb = 0; bb < bufferTypes.length; ++bb) {
+ let bufferType = bufferTypes[bb];
+ let buffer = gl.createBuffer();
+ gl.bindBuffer(bufferType, buffer);
+ gl.bufferData(bufferType, 16, gl.DYNAMIC_DRAW);
+ let expression1 = "gl.getBufferParameter(" + bufferType + ", gl.BUFFER_SIZE)";
+ let expression2 = "gl.getBufferParameter(" + bufferType + ", gl.BUFFER_USAGE)";
+ shouldBe(expression1, '16');
+ shouldBe(expression2, 'gl.DYNAMIC_DRAW');
+ await testInvalidArgument("getBufferParameter", "parameter", [gl.BUFFER_SIZE, gl.BUFFER_USAGE], function(bufferType) {
+ return function(parameter) {
+ return gl.getBufferParameter(bufferType, parameter);
+ };
+ }(bufferType));
+ gl.bindBuffer(bufferType, null);
+ }
+ await testInvalidArgument(
+ "getBufferParameter",
+ "target",
+ bufferTypes,
+ function(target) {
+ return gl.getBufferParameter(target, gl.BUFFER_SIZE);
+ }
+ );
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR);
+
+ let testCases = [
+ { contextStencil: true},
+ { contextStencil: false}
+ ];
+
+ for (let run = 0; run < testCases.length; ++run) {
+ debug("");
+ debug("Test getFramebufferAttachmentParameter with stencil " + testCases[run].contextStencil);
+
+ if (testCases[run].contextStencil) {
+ gl = wtu.create3DContext(null, {stencil: true}, contextVersion);
+ } else {
+ gl = wtu.create3DContext(null, {stencil: false}, contextVersion);
+ }
+
+ window.texture = gl.createTexture();
+ window.anotherTexture = gl.createTexture();
+ gl.bindTexture(gl.TEXTURE_2D, texture);
+ gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 2, 2, 0, gl.RGBA, gl.UNSIGNED_BYTE,
+ new Uint8Array([
+ 0, 0, 0, 255,
+ 255, 255, 255, 255,
+ 255, 255, 255, 255,
+ 0, 0, 0, 255]));
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
+ gl.bindTexture(gl.TEXTURE_2D, null);
+ window.framebuffer = gl.createFramebuffer();
+ gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer);
+ gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture, 0);
+ let colorAttachmentsNum = 1;
+ if (contextVersion > 1) {
+ gl.bindTexture(gl.TEXTURE_2D, anotherTexture);
+ gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 2, 2, 0, gl.RGBA, gl.UNSIGNED_BYTE,
+ new Uint8Array([
+ 0, 0, 0, 255,
+ 255, 255, 255, 255,
+ 255, 255, 255, 255,
+ 0, 0, 0, 255]));
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
+ gl.bindTexture(gl.TEXTURE_2D, null);
+ colorAttachmentsNum = gl.getParameter(gl.MAX_COLOR_ATTACHMENTS);
+ gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0 + colorAttachmentsNum - 1, gl.TEXTURE_2D, anotherTexture, 0);
+ }
+ window.renderbuffer = gl.createRenderbuffer();
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR);
+ gl.bindRenderbuffer(gl.RENDERBUFFER, renderbuffer);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR);
+ if (contextVersion == 1)
+ gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_COMPONENT16, 2, 2);
+ else
+ gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH24_STENCIL8, 2, 2);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR);
+ gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, renderbuffer);
+ if (contextVersion > 1)
+ gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.STENCIL_ATTACHMENT, gl.RENDERBUFFER, renderbuffer);
+ shouldBe('gl.checkFramebufferStatus(gl.FRAMEBUFFER)', 'gl.FRAMEBUFFER_COMPLETE');
+ // The for loop tests two color attachments for WebGL 2: the first one (gl.COLOR_ATTACHMENT0)
+ // and the last one (gl.COLOR_ATTACHMENT0 + gl.MAX_COLOR_ATTACHMENTS - 1).
+ for (let ii = 0; ii < colorAttachmentsNum; ii += (colorAttachmentsNum > 1 ? colorAttachmentsNum - 1 : 1)) {
+ shouldBe('gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0 + ' + ii + ', gl.FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE)', 'gl.TEXTURE');
+ if (ii == 0)
+ shouldBe('gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0 + ' + ii + ', gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)', 'texture');
+ else
+ shouldBe('gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0 + ' + ii + ', gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)', 'anotherTexture');
+ shouldBe('gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0 + ' + ii + ', gl.FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL)', '0');
+ shouldBe('gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0 + ' + ii + ', gl.FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE)', '0');
+ if (contextVersion > 1) {
+ shouldBeNonZero('gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0 + ' + ii + ', gl.FRAMEBUFFER_ATTACHMENT_RED_SIZE)');
+ shouldBeNonZero('gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0 + ' + ii + ', gl.FRAMEBUFFER_ATTACHMENT_GREEN_SIZE)');
+ shouldBeNonZero('gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0 + ' + ii + ', gl.FRAMEBUFFER_ATTACHMENT_BLUE_SIZE)');
+ shouldBeNonZero('gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0 + ' + ii + ', gl.FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE)');
+ shouldBeNonZero('gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0 + ' + ii + ', gl.FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE)');
+ shouldBeNonZero('gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0 + ' + ii + ', gl.FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING)');
+ shouldBe('gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0 + ' + ii + ', gl.FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER)', '0');
+ }
+ }
+ shouldBe('gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE)', 'gl.RENDERBUFFER');
+ shouldBe('gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)', 'renderbuffer');
+ if (contextVersion > 1) {
+ shouldBe('gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.STENCIL_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE)', 'gl.RENDERBUFFER');
+ shouldBe('gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.STENCIL_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)', 'renderbuffer');
+ shouldBe('gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE)', 'gl.RENDERBUFFER');
+ shouldBe('gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)', 'renderbuffer');
+ shouldBeNonZero('gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE)');
+ shouldBeNonZero('gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.STENCIL_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE)');
+ shouldBeNonZero('gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE)');
+ shouldBeNonZero('gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING)');
+ shouldBeNonZero('gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.STENCIL_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE)');
+ shouldBeNonZero('gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.STENCIL_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING)');
+ wtu.shouldGenerateGLError(gl, gl.INVALID_OPERATION, 'gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE)');
+ shouldBeNonZero('gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING)');
+ }
+ let validParametersForFBAttachment =
+ [ gl.FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE,
+ gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME,
+ gl.FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL,
+ gl.FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE
+ ];
+ if (contextVersion > 1) {
+ validParametersForFBAttachment = validParametersForFBAttachment.concat([
+ gl.FRAMEBUFFER_ATTACHMENT_RED_SIZE,
+ gl.FRAMEBUFFER_ATTACHMENT_GREEN_SIZE,
+ gl.FRAMEBUFFER_ATTACHMENT_BLUE_SIZE,
+ gl.FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE,
+ gl.FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE,
+ gl.FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE,
+ gl.FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE,
+ gl.FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING,
+ gl.FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER
+ ]);
+ }
+ await testInvalidArgument(
+ "getFramebufferAttachmentParameter",
+ "parameter",
+ validParametersForFBAttachment,
+ function(parameter) {
+ return gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT, parameter);
+ }
+ );
+ let validTargetsForFBAttachment = [gl.FRAMEBUFFER];
+ if (contextVersion > 1) {
+ validTargetsForFBAttachment = validTargetsForFBAttachment.concat([gl.READ_FRAMEBUFFER, gl.DRAW_FRAMEBUFFER]);
+ }
+ await testInvalidArgument(
+ "getFramebufferAttachmentParameter",
+ "target",
+ validTargetsForFBAttachment,
+ function(target) {
+ return gl.getFramebufferAttachmentParameter(target, gl.COLOR_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE);
+ }
+ );
+ let validAttachmentsForFBAttachment = new Array(
+ gl.COLOR_ATTACHMENT0,
+ gl.DEPTH_ATTACHMENT,
+ gl.STENCIL_ATTACHMENT,
+ gl.DEPTH_STENCIL_ATTACHMENT
+ );
+ if (contextVersion > 1) {
+ for (let ii = 1; ii < gl.getParameter(gl.MAX_COLOR_ATTACHMENTS); ++ii) {
+ validAttachmentsForFBAttachment[validAttachmentsForFBAttachment.length] = gl.COLOR_ATTACHMENT0 + ii;
+ }
+ }
+ await testInvalidArgument(
+ "getFramebufferAttachmentParameter",
+ "attachment",
+ validAttachmentsForFBAttachment,
+ function(attachment) {
+ return gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, attachment, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE);
+ }
+ );
+ if (contextVersion > 1) {
+ // test default framebuffer
+ gl.bindFramebuffer(gl.FRAMEBUFFER, null);
+ shouldBe('gl.checkFramebufferStatus(gl.FRAMEBUFFER)', 'gl.FRAMEBUFFER_COMPLETE');
+ shouldBe('gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.BACK, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE)', 'gl.FRAMEBUFFER_DEFAULT');
+ shouldBe('gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE)', 'gl.FRAMEBUFFER_DEFAULT');
+ if (testCases[run].contextStencil)
+ shouldBe('gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.STENCIL, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE)', 'gl.FRAMEBUFFER_DEFAULT');
+ else
+ shouldBe('gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.STENCIL, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE)', 'gl.NONE');
+ shouldBeNonZero('gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.BACK, gl.FRAMEBUFFER_ATTACHMENT_RED_SIZE)');
+ shouldBeNonZero('gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.BACK, gl.FRAMEBUFFER_ATTACHMENT_GREEN_SIZE)');
+ shouldBeNonZero('gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.BACK, gl.FRAMEBUFFER_ATTACHMENT_BLUE_SIZE)');
+ shouldBeNonZero('gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.BACK, gl.FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE)');
+ shouldBeNonZero('gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH, gl.FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE)');
+ shouldBeNonZero('gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.BACK, gl.FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE)');
+ shouldBeNonZero('gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.BACK, gl.FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING)');
+ shouldBeNonZero('gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH, gl.FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE)');
+ shouldBeNonZero('gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH, gl.FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING)');
+ if (testCases[run].contextStencil) {
+ shouldBeNonZero('gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.STENCIL, gl.FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE)');
+ shouldBeNonZero('gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.STENCIL, gl.FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE)');
+ shouldBeNonZero('gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.STENCIL, gl.FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING)');
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR);
+ } else {
+ wtu.shouldGenerateGLError(gl, gl.INVALID_OPERATION, 'gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.STENCIL, gl.FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE)');
+ wtu.shouldGenerateGLError(gl, gl.INVALID_OPERATION, 'gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.STENCIL, gl.FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE)');
+ wtu.shouldGenerateGLError(gl, gl.INVALID_OPERATION, 'gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.STENCIL, gl.FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING)');
+ }
+ await testInvalidArgument(
+ "getFramebufferAttachmentParameter",
+ "parameter",
+ validParametersForFBAttachment,
+ function(parameter) {
+ return gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.BACK, parameter);
+ }
+ );
+ await testInvalidArgument(
+ "getFramebufferAttachmentParameter",
+ "target",
+ validTargetsForFBAttachment,
+ function(target) {
+ return gl.getFramebufferAttachmentParameter(target, gl.BACK, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE);
+ }
+ );
+ await testInvalidArgument(
+ "getFramebufferAttachmentParameter",
+ "attachment",
+ [ gl.BACK,
+ gl.DEPTH,
+ gl.STENCIL
+ ],
+ function(attachment) {
+ return gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, attachment, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE);
+ }
+ );
+ }
+ }
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR);
+
+ debug("");
+ debug("test getAttachedShaders");
+ window.standardVert = wtu.loadStandardVertexShader(gl);
+ window.standardFrag = wtu.loadStandardFragmentShader(gl);
+ window.standardProgram = gl.createProgram();
+ gl.attachShader(standardProgram, standardVert);
+ gl.attachShader(standardProgram, standardFrag);
+ gl.linkProgram(standardProgram);
+ window.shaders = gl.getAttachedShaders(standardProgram);
+ shouldBe('shaders.length', '2');
+ shouldBeTrue('shaders[0] == standardVert && shaders[1] == standardFrag || shaders[1] == standardVert && shaders[0] == standardFrag');
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR);
+ shouldThrow('gl.getAttachedShaders(null)');
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR);
+ shouldThrow('gl.getAttachedShaders(standardVert)');
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR);
+
+ debug("");
+ debug("Test getProgramParameter");
+ shouldBe('gl.getProgramParameter(standardProgram, gl.DELETE_STATUS)', 'false');
+ shouldBe('gl.getProgramParameter(standardProgram, gl.LINK_STATUS)', 'true');
+ shouldBe('typeof gl.getProgramParameter(standardProgram, gl.VALIDATE_STATUS)', '"boolean"');
+ shouldBe('gl.getProgramParameter(standardProgram, gl.ATTACHED_SHADERS)', '2');
+ shouldBe('gl.getProgramParameter(standardProgram, gl.ACTIVE_ATTRIBUTES)', '2');
+ shouldBe('gl.getProgramParameter(standardProgram, gl.ACTIVE_UNIFORMS)', '1');
+ if (contextVersion > 1) {
+ let buffer = gl.createBuffer();
+ gl.bindBuffer(gl.TRANSFORM_FEEDBACK_BUFFER, buffer);
+ gl.bufferData(gl.TRANSFORM_FEEDBACK_BUFFER, 1024, gl.DYNAMIC_DRAW);
+ window.uniformBlockProgram = wtu.loadUniformBlockProgram(gl);
+ let transformFeedbackVars = ["normal", "ecPosition"];
+ gl.transformFeedbackVaryings(uniformBlockProgram, transformFeedbackVars, gl.INTERLEAVED_ATTRIBS);
+ gl.linkProgram(uniformBlockProgram);
+ shouldBe('gl.getProgramParameter(uniformBlockProgram, gl.LINK_STATUS)', 'true');
+ shouldBe('gl.getError()', 'gl.NO_ERROR');
+ shouldBe('gl.getProgramParameter(uniformBlockProgram, gl.ACTIVE_UNIFORM_BLOCKS)', '1');
+ shouldBe('gl.getProgramParameter(uniformBlockProgram, gl.TRANSFORM_FEEDBACK_VARYINGS)', '2');
+ shouldBe('gl.getProgramParameter(uniformBlockProgram, gl.TRANSFORM_FEEDBACK_BUFFER_MODE)', 'gl.INTERLEAVED_ATTRIBS');
+ }
+ window.program = standardProgram;
+ let validArrayForProgramParameter = [
+ gl.DELETE_STATUS,
+ gl.LINK_STATUS,
+ gl.VALIDATE_STATUS,
+ gl.ATTACHED_SHADERS,
+ gl.ACTIVE_ATTRIBUTES,
+ gl.ACTIVE_UNIFORMS
+ ];
+ if (contextVersion > 1) {
+ validArrayForProgramParameter = validArrayForProgramParameter.concat([
+ gl.ACTIVE_UNIFORM_BLOCKS,
+ gl.TRANSFORM_FEEDBACK_VARYINGS,
+ gl.TRANSFORM_FEEDBACK_BUFFER_MODE
+ ]);
+ program = uniformBlockProgram;
+ }
+ await testInvalidArgument(
+ "getProgramParameter",
+ "parameter",
+ validArrayForProgramParameter,
+ function(parameter) {
+ return gl.getProgramParameter(program, parameter);
+ }
+ );
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR);
+
+ debug("");
+ debug("Test getRenderbufferParameter");
+ shouldBe('gl.getRenderbufferParameter(gl.RENDERBUFFER, gl.RENDERBUFFER_WIDTH)', '2');
+ shouldBe('gl.getRenderbufferParameter(gl.RENDERBUFFER, gl.RENDERBUFFER_HEIGHT)', '2');
+ // Note: we can't test the actual value of the internal format since
+ // the implementation is allowed to change it.
+ shouldBeNonZero('gl.getRenderbufferParameter(gl.RENDERBUFFER, gl.RENDERBUFFER_INTERNAL_FORMAT)');
+ shouldBeNonZero('gl.getRenderbufferParameter(gl.RENDERBUFFER, gl.RENDERBUFFER_DEPTH_SIZE)');
+ let colorbuffer = gl.createRenderbuffer();
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR);
+ gl.bindRenderbuffer(gl.RENDERBUFFER, renderbuffer);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR);
+ gl.renderbufferStorage(gl.RENDERBUFFER, gl.RGBA4, 2, 2);
+ shouldBeNonZero('gl.getRenderbufferParameter(gl.RENDERBUFFER, gl.RENDERBUFFER_RED_SIZE)');
+ shouldBeNonZero('gl.getRenderbufferParameter(gl.RENDERBUFFER, gl.RENDERBUFFER_GREEN_SIZE)');
+ shouldBeNonZero('gl.getRenderbufferParameter(gl.RENDERBUFFER, gl.RENDERBUFFER_BLUE_SIZE)');
+ shouldBeNonZero('gl.getRenderbufferParameter(gl.RENDERBUFFER, gl.RENDERBUFFER_ALPHA_SIZE)');
+ if (contextVersion > 1) {
+ gl.renderbufferStorageMultisample(gl.RENDERBUFFER, 4, gl.RGBA4, 2, 2);
+ shouldBe('gl.getRenderbufferParameter(gl.RENDERBUFFER, gl.RENDERBUFFER_SAMPLES)', '4');
+ }
+ let validArrayForRenderbuffer = new Array(
+ gl.RENDERBUFFER_WIDTH,
+ gl.RENDERBUFFER_HEIGHT,
+ gl.RENDERBUFFER_INTERNAL_FORMAT,
+ gl.RENDERBUFFER_RED_SIZE,
+ gl.RENDERBUFFER_GREEN_SIZE,
+ gl.RENDERBUFFER_BLUE_SIZE,
+ gl.RENDERBUFFER_ALPHA_SIZE,
+ gl.RENDERBUFFER_DEPTH_SIZE,
+ gl.RENDERBUFFER_STENCIL_SIZE
+ );
+ if (contextVersion > 1) {
+ validArrayForRenderbuffer[validArrayForRenderbuffer.length] = gl.RENDERBUFFER_SAMPLES;
+ }
+ await testInvalidArgument(
+ "getRenderbufferParameter",
+ "parameter",
+ validArrayForRenderbuffer,
+ function(parameter) {
+ return gl.getRenderbufferParameter(gl.RENDERBUFFER, parameter);
+ });
+ await testInvalidArgument(
+ "getRenderbufferParameter",
+ "target",
+ [ gl.RENDERBUFFER ],
+ function(target) {
+ return gl.getRenderbufferParameter(target, gl.RENDERBUFFER_WIDTH);
+ }
+ );
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR);
+
+ debug("");
+ debug("Test getShaderParameter");
+ shouldBe('gl.getShaderParameter(standardVert, gl.SHADER_TYPE)', 'gl.VERTEX_SHADER');
+ shouldBe('gl.getShaderParameter(standardVert, gl.DELETE_STATUS)', 'false');
+ shouldBe('gl.getShaderParameter(standardVert, gl.COMPILE_STATUS)', 'true');
+ await testInvalidArgument(
+ "getShaderParameter",
+ "parameter",
+ [ gl.DELETE_STATUS,
+ gl.COMPILE_STATUS,
+ gl.SHADER_TYPE
+ ],
+ function(parameter) {
+ return gl.getShaderParameter(standardVert, parameter);
+ }
+ );
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR);
+
+ debug("");
+ debug("Test getTexParameter");
+ gl.bindTexture(gl.TEXTURE_2D, texture);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
+ shouldBe('gl.getTexParameter(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER)', 'gl.NEAREST');
+ shouldBe('gl.getTexParameter(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER)', 'gl.NEAREST');
+ shouldBe('gl.getTexParameter(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S)', 'gl.CLAMP_TO_EDGE');
+ shouldBe('gl.getTexParameter(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T)', 'gl.CLAMP_TO_EDGE');
+ if (contextVersion > 1) {
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_BASE_LEVEL, 0);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_COMPARE_FUNC, gl.LEQUAL);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_COMPARE_MODE, gl.COMPARE_REF_TO_TEXTURE);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAX_LEVEL, 10);
+ gl.texParameterf(gl.TEXTURE_2D, gl.TEXTURE_MAX_LOD, 10);
+ gl.texParameterf(gl.TEXTURE_2D, gl.TEXTURE_MIN_LOD, 0);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_R, gl.CLAMP_TO_EDGE);
+ shouldBe('gl.getTexParameter(gl.TEXTURE_2D, gl.TEXTURE_BASE_LEVEL)', '0');
+ shouldBe('gl.getTexParameter(gl.TEXTURE_2D, gl.TEXTURE_COMPARE_FUNC)', 'gl.LEQUAL');
+ shouldBe('gl.getTexParameter(gl.TEXTURE_2D, gl.TEXTURE_COMPARE_MODE)', 'gl.COMPARE_REF_TO_TEXTURE');
+ shouldBe('gl.getTexParameter(gl.TEXTURE_2D, gl.TEXTURE_MAX_LEVEL)', '10');
+ shouldBe('gl.getTexParameter(gl.TEXTURE_2D, gl.TEXTURE_MAX_LOD)', '10');
+ shouldBe('gl.getTexParameter(gl.TEXTURE_2D, gl.TEXTURE_MIN_LOD)', '0');
+ shouldBe('gl.getTexParameter(gl.TEXTURE_2D, gl.TEXTURE_WRAP_R)', 'gl.CLAMP_TO_EDGE');
+ shouldBe('gl.getTexParameter(gl.TEXTURE_2D, gl.TEXTURE_IMMUTABLE_FORMAT)', 'false');
+ shouldBe('gl.getTexParameter(gl.TEXTURE_2D, gl.TEXTURE_IMMUTABLE_LEVELS)', '0');
+ }
+ let validParametersForTexture = [
+ gl.TEXTURE_MAG_FILTER,
+ gl.TEXTURE_MIN_FILTER,
+ gl.TEXTURE_WRAP_S,
+ gl.TEXTURE_WRAP_T,
+ ];
+ if (contextVersion > 1) {
+ validParametersForTexture = validParametersForTexture.concat([
+ gl.TEXTURE_BASE_LEVEL,
+ gl.TEXTURE_COMPARE_FUNC,
+ gl.TEXTURE_COMPARE_MODE,
+ gl.TEXTURE_MAX_LEVEL,
+ gl.TEXTURE_MAX_LOD,
+ gl.TEXTURE_MIN_LOD,
+ gl.TEXTURE_WRAP_R,
+ gl.TEXTURE_IMMUTABLE_FORMAT,
+ gl.TEXTURE_IMMUTABLE_LEVELS,
+ ]);
+ }
+ await testInvalidArgument(
+ "getTexParameter",
+ "parameter",
+ validParametersForTexture,
+ function(parameter) {
+ return gl.getTexParameter(gl.TEXTURE_2D, parameter);
+ }
+ );
+ let validTargetsForTexture = [ gl.TEXTURE_2D, gl.TEXTURE_CUBE_MAP];
+ if (contextVersion > 1) {
+ validTargetsForTexture = validTargetsForTexture.concat([ gl.TEXTURE_3D, gl.TEXTURE_2D_ARRAY]);
+ }
+ await testInvalidArgument(
+ "getTexParameter",
+ "target",
+ validTargetsForTexture,
+ function(target) {
+ return gl.getTexParameter(target, gl.TEXTURE_MAG_FILTER);
+ }
+ );
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR);
+
+ debug("");
+ debug("Test getUniform with all variants of data types");
+ debug("Boolean uniform variables");
+ window.boolProgram = wtu.loadProgramFromFile(gl, "../../resources/boolUniformShader.vert", "../../resources/noopUniformShader.frag");
+ shouldBe('gl.getProgramParameter(boolProgram, gl.LINK_STATUS)', 'true');
+ window.bvalLoc = gl.getUniformLocation(boolProgram, "bval");
+ window.bval2Loc = gl.getUniformLocation(boolProgram, "bval2");
+ window.bval3Loc = gl.getUniformLocation(boolProgram, "bval3");
+ window.bval4Loc = gl.getUniformLocation(boolProgram, "bval4");
+ gl.useProgram(boolProgram);
+ gl.uniform1i(bvalLoc, 1);
+ gl.uniform2i(bval2Loc, 1, 0);
+ gl.uniform3i(bval3Loc, 1, 0, 1);
+ gl.uniform4i(bval4Loc, 1, 0, 1, 0);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR);
+ shouldBe('gl.getUniform(boolProgram, bvalLoc)', 'true');
+ shouldBe('gl.getUniform(boolProgram, bval2Loc)', '[true, false]');
+ shouldBe('gl.getUniform(boolProgram, bval3Loc)', '[true, false, true]');
+ shouldBe('gl.getUniform(boolProgram, bval4Loc)', '[true, false, true, false]');
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR);
+
+ debug("Integer uniform variables");
+ window.intProgram = wtu.loadProgramFromFile(gl, "../../resources/intUniformShader.vert", "../../resources/noopUniformShader.frag");
+ shouldBe('gl.getProgramParameter(intProgram, gl.LINK_STATUS)', 'true');
+ window.ivalLoc = gl.getUniformLocation(intProgram, "ival");
+ window.ival2Loc = gl.getUniformLocation(intProgram, "ival2");
+ window.ival3Loc = gl.getUniformLocation(intProgram, "ival3");
+ window.ival4Loc = gl.getUniformLocation(intProgram, "ival4");
+ gl.useProgram(intProgram);
+ gl.uniform1i(ivalLoc, 1);
+ gl.uniform2i(ival2Loc, 2, 3);
+ gl.uniform3i(ival3Loc, 4, 5, 6);
+ gl.uniform4i(ival4Loc, 7, 8, 9, 10);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR);
+ shouldBe('gl.getUniform(intProgram, ivalLoc)', '1');
+ shouldBe('gl.getUniform(intProgram, ival2Loc)', '[2, 3]');
+ shouldBe('gl.getUniform(intProgram, ival3Loc)', '[4, 5, 6]');
+ shouldBe('gl.getUniform(intProgram, ival4Loc)', '[7, 8, 9, 10]');
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR);
+
+ debug("Float uniform variables");
+ window.floatProgram = wtu.loadProgramFromFile(gl, "../../resources/floatUniformShader.vert", "../../resources/noopUniformShader.frag");
+ shouldBe('gl.getProgramParameter(floatProgram, gl.LINK_STATUS)', 'true');
+ window.fvalLoc = gl.getUniformLocation(floatProgram, "fval");
+ window.fval2Loc = gl.getUniformLocation(floatProgram, "fval2");
+ window.fval3Loc = gl.getUniformLocation(floatProgram, "fval3");
+ window.fval4Loc = gl.getUniformLocation(floatProgram, "fval4");
+ gl.useProgram(floatProgram);
+ gl.uniform1f(fvalLoc, 11);
+ gl.uniform2f(fval2Loc, 12, 13);
+ gl.uniform3f(fval3Loc, 14, 15, 16);
+ gl.uniform4f(fval4Loc, 17, 18, 19, 20);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR);
+ shouldBe('gl.getUniform(floatProgram, fvalLoc)', '11');
+ shouldBe('gl.getUniform(floatProgram, fval2Loc)', '[12, 13]');
+ shouldBe('gl.getUniform(floatProgram, fval3Loc)', '[14, 15, 16]');
+ shouldBe('gl.getUniform(floatProgram, fval4Loc)', '[17, 18, 19, 20]');
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR);
+
+ debug("Sampler uniform variables");
+ window.samplerProgram = wtu.loadProgramFromFile(gl, "../../resources/noopUniformShader.vert", "../../resources/samplerUniformShader.frag");
+ shouldBe('gl.getProgramParameter(samplerProgram, gl.LINK_STATUS)', 'true');
+ window.s2DValLoc = gl.getUniformLocation(samplerProgram, "s2D");
+ window.sCubeValLoc = gl.getUniformLocation(samplerProgram, "sCube");
+ gl.useProgram(samplerProgram);
+ gl.uniform1i(s2DValLoc, 0);
+ gl.uniform1i(sCubeValLoc, 1);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR);
+ shouldBe('gl.getUniform(samplerProgram, s2DValLoc)', '0');
+ shouldBe('gl.getUniform(samplerProgram, sCubeValLoc)', '1');
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR);
+
+ debug("Matrix uniform variables");
+ window.matProgram = wtu.loadProgramFromFile(gl, "../../resources/matUniformShader.vert", "../../resources/noopUniformShader.frag");
+ shouldBe('gl.getProgramParameter(matProgram, gl.LINK_STATUS)', 'true');
+ window.mval2Loc = gl.getUniformLocation(matProgram, "mval2");
+ window.mval3Loc = gl.getUniformLocation(matProgram, "mval3");
+ window.mval4Loc = gl.getUniformLocation(matProgram, "mval4");
+ gl.useProgram(matProgram);
+ gl.uniformMatrix2fv(mval2Loc, false, [1, 2, 3, 4]);
+ gl.uniformMatrix3fv(mval3Loc, false, [5, 6, 7, 8, 9, 10, 11, 12, 13]);
+ gl.uniformMatrix4fv(mval4Loc, false, [14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29]);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR);
+ shouldBe('gl.getUniform(matProgram, mval2Loc)', '[1, 2, 3, 4]');
+ shouldBe('gl.getUniform(matProgram, mval3Loc)', '[5, 6, 7, 8, 9, 10, 11, 12, 13]');
+ shouldBe('gl.getUniform(matProgram, mval4Loc)', '[14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29]');
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR);
+
+ if (contextVersion > 1) {
+ debug("Unsigned Integer uniform variables");
+ window.uintProgram = wtu.loadProgramFromFile(gl, "../../resources/uintUniformShader.vert", "../../resources/noopUniformShaderES3.frag");
+ shouldBe('gl.getProgramParameter(uintProgram, gl.LINK_STATUS)', 'true');
+ window.uvalLoc = gl.getUniformLocation(uintProgram, "uval");
+ window.uval2Loc = gl.getUniformLocation(uintProgram, "uval2");
+ window.uval3Loc = gl.getUniformLocation(uintProgram, "uval3");
+ window.uval4Loc = gl.getUniformLocation(uintProgram, "uval4");
+ gl.useProgram(uintProgram);
+ gl.uniform1ui(uvalLoc, 1);
+ gl.uniform2ui(uval2Loc, 2, 3);
+ gl.uniform3ui(uval3Loc, 4, 5, 6);
+ gl.uniform4ui(uval4Loc, 7, 8, 9, 10);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR);
+ shouldBe('gl.getUniform(uintProgram, uvalLoc)', '1');
+ shouldBe('gl.getUniform(uintProgram, uval2Loc)', '[2, 3]');
+ shouldBe('gl.getUniform(uintProgram, uval3Loc)', '[4, 5, 6]');
+ shouldBe('gl.getUniform(uintProgram, uval4Loc)', '[7, 8, 9, 10]');
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR);
+
+ debug("Matrix uniform variables for WebGL 2");
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR);
+
+ window.matForWebGL2Program = wtu.loadProgramFromFile(gl, "../../resources/matForWebGL2UniformShader.vert", "../../resources/noopUniformShaderES3.frag");
+ shouldBe('gl.getProgramParameter(matForWebGL2Program, gl.LINK_STATUS)', 'true');
+ window.mval2x3Loc = gl.getUniformLocation(matForWebGL2Program, "mval2x3");
+ window.mval2x4Loc = gl.getUniformLocation(matForWebGL2Program, "mval2x4");
+ window.mval3x2Loc = gl.getUniformLocation(matForWebGL2Program, "mval3x2");
+ window.mval3x4Loc = gl.getUniformLocation(matForWebGL2Program, "mval3x4");
+ window.mval4x2Loc = gl.getUniformLocation(matForWebGL2Program, "mval4x2");
+ window.mval4x3Loc = gl.getUniformLocation(matForWebGL2Program, "mval4x3");
+ gl.useProgram(matForWebGL2Program);
+ gl.uniformMatrix2x3fv(mval2x3Loc, false, [1, 2, 3, 4, 5, 6]);
+ gl.uniformMatrix2x4fv(mval2x4Loc, false, [7, 8, 9, 10, 11, 12, 13, 14]);
+ gl.uniformMatrix3x2fv(mval3x2Loc, false, [15, 16, 17, 18, 19, 20]);
+ gl.uniformMatrix3x4fv(mval3x4Loc, false, [21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32]);
+ gl.uniformMatrix4x2fv(mval4x2Loc, false, [33, 34, 35, 36, 37, 38, 39, 40]);
+ gl.uniformMatrix4x3fv(mval4x3Loc, false, [41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52]);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR);
+ shouldBe('gl.getUniform(matForWebGL2Program, mval2x3Loc)', '[1, 2, 3, 4, 5, 6]');
+ shouldBe('gl.getUniform(matForWebGL2Program, mval2x4Loc)', '[7, 8, 9, 10, 11, 12, 13, 14]');
+ shouldBe('gl.getUniform(matForWebGL2Program, mval3x2Loc)', '[15, 16, 17, 18, 19, 20]');
+ shouldBe('gl.getUniform(matForWebGL2Program, mval3x4Loc)', '[21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32]');
+ shouldBe('gl.getUniform(matForWebGL2Program, mval4x2Loc)', '[33, 34, 35, 36, 37, 38, 39, 40]');
+ shouldBe('gl.getUniform(matForWebGL2Program, mval4x3Loc)', '[41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52]');
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR);
+
+ debug("Sampler uniform variables for WebGL2");
+ window.samplerForWebGL2Program = wtu.loadProgramFromFile(gl, "../../resources/noopUniformShaderES3.vert", "../../resources/samplerForWebGL2UniformShader.frag");
+ shouldBe('gl.getProgramParameter(samplerForWebGL2Program, gl.LINK_STATUS)', 'true');
+ window.s3DValLoc = gl.getUniformLocation(samplerForWebGL2Program, "s3D");
+ window.s2DArrayValLoc = gl.getUniformLocation(samplerForWebGL2Program, "s2DArray");
+ gl.useProgram(samplerForWebGL2Program);
+ gl.uniform1i(s3DValLoc, 0);
+ gl.uniform1i(s2DArrayValLoc, 1);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR);
+ shouldBe('gl.getUniform(samplerForWebGL2Program, s3DValLoc)', '0');
+ shouldBe('gl.getUniform(samplerForWebGL2Program, s2DArrayValLoc)', '1');
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR);
+ }
+
+ debug("");
+ debug("test getVertexAttrib");
+ let array = new Float32Array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]);
+ window.buffer = gl.createBuffer();
+ gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
+ gl.bufferData(gl.ARRAY_BUFFER, array, gl.DYNAMIC_DRAW);
+ // Vertex attribute 0 is special in that it has no current state, so
+ // fetching GL_CURRENT_VERTEX_ATTRIB generates an error. Use attribute
+ // 1 for these tests instead.
+ gl.enableVertexAttribArray(1);
+ gl.vertexAttribPointer(1, 4, gl.FLOAT, false, 0, 0);
+ shouldBe('gl.getVertexAttrib(1, gl.VERTEX_ATTRIB_ARRAY_BUFFER_BINDING)', 'buffer');
+ shouldBe('gl.getVertexAttrib(1, gl.VERTEX_ATTRIB_ARRAY_ENABLED)', 'true');
+ shouldBe('gl.getVertexAttrib(1, gl.VERTEX_ATTRIB_ARRAY_SIZE)', '4');
+ // Stride MUST be the value the user put in.
+ shouldBe('gl.getVertexAttrib(1, gl.VERTEX_ATTRIB_ARRAY_STRIDE)', '0');
+ shouldBe('gl.getVertexAttrib(1, gl.VERTEX_ATTRIB_ARRAY_TYPE)', 'gl.FLOAT');
+ shouldBe('gl.getVertexAttrib(1, gl.VERTEX_ATTRIB_ARRAY_NORMALIZED)', 'false');
+ if (contextVersion > 1) {
+ shouldBe('gl.getVertexAttrib(1, gl.VERTEX_ATTRIB_ARRAY_DIVISOR)', '0');
+ shouldBe('gl.getVertexAttrib(1, gl.VERTEX_ATTRIB_ARRAY_INTEGER)', 'false');
+ gl.vertexAttribDivisor(1, 2);
+ shouldBe('gl.getVertexAttrib(1, gl.VERTEX_ATTRIB_ARRAY_DIVISOR)', '2');
+ }
+ gl.vertexAttribPointer(1, 4, gl.FLOAT, false, 36, 12);
+ shouldBe('gl.getVertexAttrib(1, gl.VERTEX_ATTRIB_ARRAY_STRIDE)', '36');
+ shouldBe('gl.getVertexAttribOffset(1, gl.VERTEX_ATTRIB_ARRAY_POINTER)', '12');
+ gl.disableVertexAttribArray(1);
+ shouldBe('gl.getVertexAttrib(1, gl.VERTEX_ATTRIB_ARRAY_ENABLED)', 'false');
+ gl.vertexAttrib4f(1, 5, 6, 7, 8);
+ shouldBe('gl.getVertexAttrib(1, gl.CURRENT_VERTEX_ATTRIB)', '[5, 6, 7, 8]');
+ if (contextVersion > 1) {
+ let intArray = new Int32Array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]);
+ gl.bufferData(gl.ARRAY_BUFFER, intArray, gl.DYNAMIC_DRAW);
+ gl.enableVertexAttribArray(1);
+ // feed fixed-point data to buffer
+ gl.vertexAttribIPointer(1, 4, gl.INT, false, 0, 0);
+ shouldBe('gl.getVertexAttrib(1, gl.VERTEX_ATTRIB_ARRAY_TYPE)', 'gl.INT');
+ shouldBe('gl.getVertexAttrib(1, gl.VERTEX_ATTRIB_ARRAY_INTEGER)', 'true');
+ }
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR);
+ let validArrayForVertexAttrib = new Array(
+ gl.VERTEX_ATTRIB_ARRAY_BUFFER_BINDING,
+ gl.VERTEX_ATTRIB_ARRAY_ENABLED,
+ gl.VERTEX_ATTRIB_ARRAY_SIZE,
+ gl.VERTEX_ATTRIB_ARRAY_STRIDE,
+ gl.VERTEX_ATTRIB_ARRAY_TYPE,
+ gl.VERTEX_ATTRIB_ARRAY_NORMALIZED,
+ gl.CURRENT_VERTEX_ATTRIB
+ );
+ if (contextVersion > 1) {
+ validArrayForVertexAttrib[validArrayForVertexAttrib.length] = gl.VERTEX_ATTRIB_ARRAY_DIVISOR;
+ validArrayForVertexAttrib[validArrayForVertexAttrib.length] = gl.VERTEX_ATTRIB_ARRAY_INTEGER;
+ }
+ await testInvalidArgument(
+ "getVertexAttrib",
+ "parameter",
+ validArrayForVertexAttrib,
+ function(parameter) {
+ return gl.getVertexAttrib(1, parameter);
+ }
+ );
+ let numVertexAttribs = gl.getParameter(gl.MAX_VERTEX_ATTRIBS);
+ wtu.shouldGenerateGLError(gl, gl.INVALID_VALUE, 'gl.getVertexAttrib(' + numVertexAttribs + ', gl.CURRENT_VERTEX_ATTRIB)');
+
+ debug("");
+ debug("Test cases where name == 0");
+ gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer);
+
+ shouldNotBe('gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE)', 'gl.NONE');
+ gl.deleteTexture(texture);
+ shouldBe('gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE)', 'gl.NONE');
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR);
+
+ shouldNotBe('gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE)', 'gl.NONE');
+ gl.deleteRenderbuffer(renderbuffer);
+ shouldBe('gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE)', 'gl.NONE');
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR);
+
+ gl.deleteBuffer(buffer);
+ shouldBeNull('gl.getVertexAttrib(1, gl.VERTEX_ATTRIB_ARRAY_BUFFER_BINDING)');
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR);
+
+ if (contextVersion > 1) {
+ debug("");
+ debug("Test getInternalformatParameter")
+
+ shouldBeNonNull('gl.getInternalformatParameter(gl.RENDERBUFFER, gl.R32I, gl.SAMPLES)');
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR);
+
+ await testInvalidArgument(
+ "getInternalformatParameter",
+ "target",
+ [ gl.RENDERBUFFER ],
+ function(target) {
+ return gl.getInternalformatParameter(target, gl.R32I, gl.SAMPLES);
+ });
+
+ await testInvalidArgument(
+ "getInternalformatParameter",
+ "pname",
+ [ gl.SAMPLES ],
+ function(pname) {
+ return gl.getInternalformatParameter(gl.RENDERBUFFER, gl.RGBA4, pname);
+ });
+
+ let validArrayForInterformat = new Array(
+ gl.R8, gl.R8_SNORM, gl.RG8, gl.RG8_SNORM,
+ gl.RGB8, gl.RGB8_SNORM, gl.RGB565, gl.RGBA4,
+ gl.RGB5_A1, gl.RGBA8, gl.RGBA8_SNORM, gl.RGB10_A2,
+ gl.RGB10_A2UI, gl.SRGB8, gl.SRGB8_ALPHA8, gl.R16F,
+ gl.RG16F, gl.RGB16F, gl.RGBA16F, gl.R32F,
+ gl.RG32F, gl.RGB32F, gl.RGBA32F, gl.R11F_G11F_B10F,
+ gl.RGB9_E5, gl.R8I, gl.R8UI, gl.R16I,
+ gl.R16UI, gl.R32I, gl.R32UI, gl.RG8I,
+ gl.RG8UI, gl.RG16I, gl.RG16UI, gl.RG32I,
+ gl.RG32UI, gl.RGB8I, gl.RGB8UI, gl.RGB16I,
+ gl.RGB16UI, gl.RGB32I, gl.RGB32UI, gl.RGBA8I,
+ gl.RGBA8UI, gl.RGBA16I, gl.RGBA16UI, gl.RGBA32I,
+ gl.RGBA32UI, gl.RGB, gl.RGBA, gl.DEPTH_STENCIL, gl.DEPTH_COMPONENT16,
+ gl.DEPTH_COMPONENT24, gl.DEPTH_COMPONENT32F, gl.DEPTH24_STENCIL8,
+ gl.DEPTH32F_STENCIL8, gl.STENCIL_INDEX8
+ );
+ await testInvalidArgument(
+ "getInternalformatParameter",
+ "internalformat",
+ validArrayForInterformat,
+ function(internalformat) {
+ return gl.getInternalformatParameter(gl.RENDERBUFFER, internalformat, gl.SAMPLES);
+ });
+
+
+ debug("");
+ debug("Test getIndexedParameter");
+ window.buffer = gl.createBuffer();
+ gl.bindBuffer(gl.TRANSFORM_FEEDBACK_BUFFER, buffer);
+ gl.bufferData(gl.TRANSFORM_FEEDBACK_BUFFER, 64, gl.DYNAMIC_DRAW);
+ gl.bindBufferRange(gl.TRANSFORM_FEEDBACK_BUFFER, 0, buffer, 4, 8);
+ shouldBe('gl.getIndexedParameter(gl.TRANSFORM_FEEDBACK_BUFFER_BINDING, 0)', 'buffer');
+ shouldBe('gl.getIndexedParameter(gl.TRANSFORM_FEEDBACK_BUFFER_SIZE, 0)', '8');
+ shouldBe('gl.getIndexedParameter(gl.TRANSFORM_FEEDBACK_BUFFER_START, 0)', '4');
+ window.buffer1 = gl.createBuffer();
+ gl.bindBuffer(gl.UNIFORM_BUFFER, buffer1);
+ gl.bufferData(gl.UNIFORM_BUFFER, 64, gl.DYNAMIC_DRAW);
+ window.offsetUniform = gl.getParameter(gl.UNIFORM_BUFFER_OFFSET_ALIGNMENT);
+ gl.bindBufferRange(gl.UNIFORM_BUFFER, 1, buffer1, offsetUniform, 8);
+ shouldBe('gl.getIndexedParameter(gl.UNIFORM_BUFFER_BINDING, 1)', 'buffer1');
+ shouldBe('gl.getIndexedParameter(gl.UNIFORM_BUFFER_SIZE, 1)', '8');
+ shouldBe('gl.getIndexedParameter(gl.UNIFORM_BUFFER_START, 1)', 'offsetUniform');
+
+ gl.bindBufferBase(gl.UNIFORM_BUFFER, 1, null);
+ shouldBe('gl.getIndexedParameter(gl.UNIFORM_BUFFER_BINDING, 1)', 'null');
+
+ let validArrayForTarget = new Array(
+ gl.TRANSFORM_FEEDBACK_BUFFER_BINDING,
+ gl.TRANSFORM_FEEDBACK_BUFFER_SIZE,
+ gl.TRANSFORM_FEEDBACK_BUFFER_START,
+ gl.UNIFORM_BUFFER_BINDING,
+ gl.UNIFORM_BUFFER_SIZE,
+ gl.UNIFORM_BUFFER_START
+ );
+ await testInvalidArgument(
+ "getIndexedParameter",
+ "target",
+ validArrayForTarget,
+ function(target) {
+ return gl.getIndexedParameter(target, 0);
+ });
+
+ debug("");
+ debug("Test getSamplerParameter");
+ window.sampler = gl.createSampler();
+ gl.samplerParameteri(sampler, gl.TEXTURE_COMPARE_FUNC, gl.LEQUAL);
+ gl.samplerParameteri(sampler, gl.TEXTURE_COMPARE_MODE, gl.COMPARE_REF_TO_TEXTURE);
+ gl.samplerParameteri(sampler, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
+ gl.samplerParameterf(sampler, gl.TEXTURE_MAX_LOD, 10);
+ gl.samplerParameteri(sampler, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
+ gl.samplerParameterf(sampler, gl.TEXTURE_MIN_LOD, 0);
+ gl.samplerParameteri(sampler, gl.TEXTURE_WRAP_R, gl.CLAMP_TO_EDGE);
+ gl.samplerParameteri(sampler, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
+ gl.samplerParameteri(sampler, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
+ shouldBe('gl.getSamplerParameter(sampler, gl.TEXTURE_COMPARE_FUNC)', 'gl.LEQUAL');
+ shouldBe('gl.getSamplerParameter(sampler, gl.TEXTURE_COMPARE_MODE)', 'gl.COMPARE_REF_TO_TEXTURE');
+ shouldBe('gl.getSamplerParameter(sampler, gl.TEXTURE_MAG_FILTER)', 'gl.NEAREST');
+ shouldBe('gl.getSamplerParameter(sampler, gl.TEXTURE_MAX_LOD)', '10');
+ shouldBe('gl.getSamplerParameter(sampler, gl.TEXTURE_MIN_FILTER)', 'gl.NEAREST');
+ shouldBe('gl.getSamplerParameter(sampler, gl.TEXTURE_MIN_LOD)', '0');
+ shouldBe('gl.getSamplerParameter(sampler, gl.TEXTURE_WRAP_R)', 'gl.CLAMP_TO_EDGE');
+ shouldBe('gl.getSamplerParameter(sampler, gl.TEXTURE_WRAP_S)', 'gl.CLAMP_TO_EDGE');
+ shouldBe('gl.getSamplerParameter(sampler, gl.TEXTURE_WRAP_T)', 'gl.CLAMP_TO_EDGE');
+ let validArrayForSamplerParameter = new Array(
+ gl.TEXTURE_COMPARE_FUNC,
+ gl.TEXTURE_COMPARE_MODE,
+ gl.TEXTURE_MAG_FILTER,
+ gl.TEXTURE_MAX_LOD,
+ gl.TEXTURE_MIN_FILTER,
+ gl.TEXTURE_MIN_LOD,
+ gl.TEXTURE_WRAP_R,
+ gl.TEXTURE_WRAP_S,
+ gl.TEXTURE_WRAP_T
+ );
+ await testInvalidArgument(
+ "getSamplerParameter",
+ "pname",
+ validArrayForSamplerParameter,
+ function(pname) {
+ return gl.getSamplerParameter(sampler, pname);
+ });
+
+ debug("");
+ debug("Test getSyncParameter");
+ window.sync = gl.fenceSync(gl.SYNC_GPU_COMMANDS_COMPLETE, 0);
+ shouldBe('gl.getSyncParameter(sync, gl.OBJECT_TYPE)', 'gl.SYNC_FENCE');
+ let sync_status = gl.getSyncParameter(sync, gl.SYNC_STATUS);
+ switch (sync_status) {
+ case gl.UNSIGNALED:
+ testPassed('gl.getSyncParameter(sync, gl.SYNC_CONDITION) is gl.UNSIGNALED');
+ break;
+ case gl.SIGNALED:
+ testPassed('gl.getSyncParameter(sync, gl.SYNC_CONDITION) is gl.SIGNALED');
+ break;
+ default:
+ testFailed('gl.getSyncParameter(sync, gl.SYNC_CONDITION) was ' + sync_status +
+ ', expected gl.UNSIGNALED or gl.SIGNALED');
+ break;
+ }
+ shouldBe('gl.getSyncParameter(sync, gl.SYNC_CONDITION)', 'gl.SYNC_GPU_COMMANDS_COMPLETE');
+ shouldBe('gl.getSyncParameter(sync, gl.SYNC_FLAGS)', '0');
+ let validArrayForSyncParameter = new Array(
+ gl.OBJECT_TYPE,
+ gl.SYNC_STATUS,
+ gl.SYNC_CONDITION,
+ gl.SYNC_FLAGS
+ );
+ await testInvalidArgument(
+ "getSyncParameter",
+ "pname",
+ validArrayForSyncParameter,
+ function(pname) {
+ return gl.getSyncParameter(sync, pname);
+ });
+
+ debug("");
+ debug("Test getQueryParameter");
+ window.query = gl.createQuery();
+ gl.beginQuery(gl.TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN, query);
+ gl.endQuery(gl.TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN);
+ shouldBe('gl.getQueryParameter(query, gl.QUERY_RESULT_AVAILABLE)', 'false');
+ // Queries' results are tested elsewhere in the conformance suite. It's complicated
+ // to wait for this query's result to become available and verify it.
+ let validArrayForPname = new Array(
+ gl.QUERY_RESULT,
+ gl.QUERY_RESULT_AVAILABLE
+ );
+ await testInvalidArgument(
+ "getQueryParameter",
+ "pname",
+ validArrayForPname,
+ function(pname) {
+ return gl.getQueryParameter(query, pname);
+ }
+ );
+
+ debug("");
+ debug("Test getFragDataLocation");
+ let baseVertShader = '' +
+ '#version 300 es\n' +
+ 'uniform mat4 modelViewMatrix;\n' +
+ 'uniform mat4 projectionMatrix;\n' +
+ 'in vec4 vertex;\n' +
+ 'out vec4 position;\n' +
+ 'void main (void)\n' +
+ '{\n' +
+ ' position = modelViewMatrix * vertex;\n' +
+ ' gl_Position = projectionMatrix * position;\n' +
+ '}\n';
+ let baseFragShader = '' +
+ '#version 300 es\n' +
+ 'in lowp vec4 position;\n' +
+ 'layout(location = 0) out mediump vec4 fragColor;\n' +
+ 'void main (void)\n' +
+ '{\n' +
+ ' fragColor = position;\n' +
+ '}\n';
+ window.vertShader = gl.createShader(gl.VERTEX_SHADER);
+ gl.shaderSource(vertShader, baseVertShader);
+ gl.compileShader(vertShader);
+ shouldBe('gl.getShaderParameter(vertShader, gl.COMPILE_STATUS)', 'true');
+ window.fragShader = gl.createShader(gl.FRAGMENT_SHADER);
+ gl.shaderSource(fragShader, baseFragShader);
+ gl.compileShader(fragShader);
+ shouldBe('gl.getShaderParameter(fragShader, gl.COMPILE_STATUS)', 'true');
+ window.program = gl.createProgram();
+ gl.attachShader(program, vertShader);
+ gl.attachShader(program, fragShader);
+ gl.linkProgram(program);
+ shouldBe('gl.getProgramParameter(program, gl.LINK_STATUS)','true');
+ shouldBe('gl.getFragDataLocation(program, "vertexColor")', '-1');
+ shouldBe('gl.getFragDataLocation(program, "modelViewMatrix")', '-1');
+ shouldBe('gl.getFragDataLocation(program, "projectionMatrix")', '-1');
+ shouldBe('gl.getFragDataLocation(program, "position")', '-1');
+ shouldBe('gl.getFragDataLocation(program, "fragColor")', '0');
+
+ debug("");
+ debug("Test getActiveUniforms");
+ program = wtu.loadUniformBlockProgram(gl);
+ gl.linkProgram(program);
+ shouldBe('gl.getProgramParameter(program, gl.LINK_STATUS)', 'true');
+ shouldBe('gl.getError()', 'gl.NO_ERROR');
+
+ let numActiveUniforms = gl.getProgramParameter(program, gl.ACTIVE_UNIFORMS);
+ let blockIndex = gl.getUniformBlockIndex(program, "Transform");
+ let uniformIndices = [];
+ for (let i = 0; i < numActiveUniforms; i++)
+ uniformIndices.push(i);
+ let types = gl.getActiveUniforms(program, uniformIndices, gl.UNIFORM_TYPE);
+ let sizes = gl.getActiveUniforms(program, uniformIndices, gl.UNIFORM_SIZE);
+ let blockIndices = gl.getActiveUniforms(program, uniformIndices, gl.UNIFORM_BLOCK_INDEX);
+ let offsets = gl.getActiveUniforms(program, uniformIndices, gl.UNIFORM_OFFSET);
+ let arrayStrides = gl.getActiveUniforms(program, uniformIndices, gl.UNIFORM_ARRAY_STRIDE);
+ let matrixStrides = gl.getActiveUniforms(program, uniformIndices, gl.UNIFORM_MATRIX_STRIDE);
+ let rowMajors = gl.getActiveUniforms(program, uniformIndices, gl.UNIFORM_IS_ROW_MAJOR);
+ for (let i = 0; i < numActiveUniforms; i++) {
+ if (types[i] != gl.FLOAT_MAT4 && types[i] != gl.FLOAT_MAT3)
+ testFailed("expected value: GL_FLOAT_MAT4 or GL_FLOAT_MAT3" + " actual value for UNIFORM_TYPE for uniform index[" + i + "]:" + wtu.glEnumToString(gl, types[i]));
+ if (sizes[i] != 1)
+ testFailed("expected value: 1" + " actual value for UNIFORM_SIZE for uniform index[" + i + "]:" + sizes[i]);
+ if (blockIndices[i] != blockIndex)
+ testFailed("expected value: 0" + " actual value for UNIFORM_BLOCK_INDEX for uniform index[" + i + "]:" + blockIndices[i]);
+ if (offsets[i] < 0)
+ testFailed("expected value >= 0" + " actual value for UNIFORM_OFFSET for uniform index[" + i + "]:" + offsets[i]);
+ if (arrayStrides[i] != 0)
+ testFailed("expected value: 0" + " actual value for UNIFORM_ARRAY_STRIDE for uniform index[" + i + "]:" + arrayStrides[i]);
+ if (matrixStrides[i] < 0)
+ testFailed("expected value >= 0" + " actual value for UNIFORM_MATRIX_STRIDE for uniform index[" + i + "]:" + matrixStrides[i]);
+ shouldBe(`"${typeof rowMajors[i]}"`, '"boolean"');
+ if (rowMajors[i] != false)
+ testFailed("expected value: 0" + " actual value for UNIFORM_IS_ROW_MAJOR for uniform index[" + i + "]:" + rowMajors[i]);
+ }
+
+ validArrayForPname = new Array(
+ gl.UNIFORM_TYPE,
+ gl.UNIFORM_SIZE,
+ gl.UNIFORM_BLOCK_INDEX,
+ gl.UNIFORM_OFFSET,
+ gl.UNIFORM_ARRAY_STRIDE,
+ gl.UNIFORM_MATRIX_STRIDE,
+ gl.UNIFORM_IS_ROW_MAJOR
+ );
+ await testInvalidArgument(
+ "getActiveUniforms",
+ "pname",
+ validArrayForPname,
+ function(pname) {
+ return gl.getActiveUniforms(program, uniformIndices, pname);
+ }
+ );
+
+ debug("");
+ debug("Test getUniformBlockIndex");
+ program = wtu.loadUniformBlockProgram(gl);
+ gl.linkProgram(program);
+ shouldBeTrue('gl.getProgramParameter(program, gl.LINK_STATUS)');
+ shouldBe('gl.getUniformBlockIndex(program, "Transform")', '0');
+ shouldBe('gl.getUniformBlockIndex(program, "u_modelViewMatrix")', 'gl.INVALID_INDEX');
+ shouldBe('gl.getUniformBlockIndex(program, "normal")', 'gl.INVALID_INDEX');
+ shouldBe('gl.getUniformBlockIndex(program, "u_normal")', 'gl.INVALID_INDEX');
+ window.noUniformProgram = wtu.loadStandardProgram(gl);
+ gl.linkProgram(noUniformProgram);
+ shouldBeTrue('gl.getProgramParameter(noUniformProgram, gl.LINK_STATUS)');
+ shouldBe('gl.getUniformBlockIndex(noUniformProgram, "u_modelViewProjMatrix")', 'gl.INVALID_INDEX');
+ shouldBe('gl.getUniformBlockIndex(noUniformProgram, "u_normal")', 'gl.INVALID_INDEX');
+
+ debug("");
+ debug("Test getActiveUniformBlockName");
+ program = wtu.loadUniformBlockProgram(gl);
+ gl.linkProgram(program);
+ shouldBeTrue('gl.getProgramParameter(program, gl.LINK_STATUS)');
+ shouldBeEqualToString('gl.getActiveUniformBlockName(program, 0)', 'Transform');
+ shouldBeNull('gl.getActiveUniformBlockName(program, -1)');
+ wtu.glErrorShouldBe(gl, gl.INVALID_VALUE);
+ shouldBeNull('gl.getActiveUniformBlockName(program, 1)');
+ wtu.glErrorShouldBe(gl, gl.INVALID_VALUE);
+ shouldBeNull('gl.getActiveUniformBlockName(program, gl.INVALID_INDEX)');
+ wtu.glErrorShouldBe(gl, gl.INVALID_VALUE);
+ window.noLinkProgram = gl.createProgram();
+ shouldBeFalse('gl.getProgramParameter(noLinkProgram, gl.LINK_STATUS)');
+ wtu.shouldGenerateGLError(gl, gl.INVALID_OPERATION, 'gl.getActiveUniformBlockName(noLinkProgram, 0)');
+ noUniformProgram = wtu.loadStandardProgram(gl);
+ gl.linkProgram(noUniformProgram);
+ shouldBeTrue('gl.getProgramParameter(noUniformProgram, gl.LINK_STATUS)');
+ shouldBeNull('gl.getActiveUniformBlockName(noUniformProgram, -1)');
+ wtu.glErrorShouldBe(gl, gl.INVALID_VALUE);
+ shouldBeNull('gl.getActiveUniformBlockName(noUniformProgram, 0)');
+ wtu.glErrorShouldBe(gl, gl.INVALID_VALUE);
+ shouldBeNull('gl.getActiveUniformBlockName(noUniformProgram, gl.INVALID_INDEX)');
+ wtu.glErrorShouldBe(gl, gl.INVALID_VALUE);
+
+ debug("");
+ debug("Test getActiveUniformBlockParameter");
+ program = wtu.loadUniformBlockProgram(gl);
+ gl.linkProgram(program);
+ shouldBeTrue('gl.getProgramParameter(program, gl.LINK_STATUS)');
+ shouldBe('gl.getActiveUniformBlockParameter(program, 0, gl.UNIFORM_BLOCK_BINDING)', '0');
+ gl.uniformBlockBinding(program, 0, 1);
+ shouldBe('gl.getActiveUniformBlockParameter(program, 0, gl.UNIFORM_BLOCK_BINDING)', '1');
+ // The actual block data size can be bigger than 164, depending on the uniform block layout.
+ shouldBeTrue('gl.getActiveUniformBlockParameter(program, 0, gl.UNIFORM_BLOCK_DATA_SIZE) >= 164');
+ shouldBe('gl.getActiveUniformBlockParameter(program, 0, gl.UNIFORM_BLOCK_ACTIVE_UNIFORMS)', '3');
+ shouldBeTrue('gl.getActiveUniformBlockParameter(program, 0, gl.UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER)');
+ shouldBeFalse('gl.getActiveUniformBlockParameter(program, 0, gl.UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER)');
+ let indices = gl.getActiveUniformBlockParameter(program, 0, gl.UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES);
+ for (let i = 0; i < 3; i++) {
+ if (indices[i] < 0)
+ testFailed("expected value >= 0" + " actual value for UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES for uniform index[" + i + "]:" + indices[i]);
+ }
+ validArrayForPname = new Array(
+ gl.UNIFORM_BLOCK_BINDING,
+ gl.UNIFORM_BLOCK_DATA_SIZE,
+ gl.UNIFORM_BLOCK_ACTIVE_UNIFORMS,
+ gl.UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES,
+ gl.UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER,
+ gl.UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER
+ );
+ await testInvalidArgument(
+ "getActiveUniformBlockParameter",
+ "pname",
+ validArrayForPname,
+ function(pname) {
+ return gl.getActiveUniformBlockParameter(program, 0, pname);
+ }
+ );
+ }
+
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR);
+
+ finishTest();
+})();
+
+let successfullyParsed = true;
diff --git a/dom/canvas/test/webgl-conf/checkout/js/tests/gl-vertex-attrib.js b/dom/canvas/test/webgl-conf/checkout/js/tests/gl-vertex-attrib.js
new file mode 100644
index 0000000000..97cad40868
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/js/tests/gl-vertex-attrib.js
@@ -0,0 +1,263 @@
+/*
+Copyright (c) 2019 The Khronos Group Inc.
+Use of this source code is governed by an MIT-style license that can be
+found in the LICENSE.txt file.
+*/
+
+// This test relies on the surrounding web page defining a variable
+// "contextVersion" which indicates what version of WebGL it's running
+// on -- 1 for WebGL 1.0, 2 for WebGL 2.0, etc.
+
+"use strict";
+description("This test ensures WebGL implementations vertexAttrib can be set and read.");
+
+debug("");
+debug("Canvas.getContext");
+
+var wtu = WebGLTestUtils;
+var gl = wtu.create3DContext("canvas", undefined, contextVersion);
+if (!gl) {
+ testFailed("context does not exist");
+} else {
+ testPassed("context exists");
+
+ debug("");
+ debug("Checking gl.vertexAttrib.");
+
+ var numVertexAttribs = gl.getParameter(gl.MAX_VERTEX_ATTRIBS);
+ for (var ii = 0; ii < numVertexAttribs; ++ii) {
+ gl.vertexAttrib1fv(ii, [1]);
+ shouldBeType('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)', 'Float32Array');
+ shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[0]', '1');
+ shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[1]', '0');
+ shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[2]', '0');
+ shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[3]', '1');
+
+ gl.vertexAttrib1fv(ii, new Float32Array([-1]));
+ shouldBeType('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)', 'Float32Array');
+ shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[0]', '-1');
+ shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[1]', '0');
+ shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[2]', '0');
+ shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[3]', '1');
+
+ gl.vertexAttrib2fv(ii, [1, 2]);
+ shouldBeType('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)', 'Float32Array');
+ shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[0]', '1');
+ shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[1]', '2');
+ shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[2]', '0');
+ shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[3]', '1');
+
+ gl.vertexAttrib2fv(ii, new Float32Array([1, -2]));
+ shouldBeType('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)', 'Float32Array');
+ shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[0]', '1');
+ shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[1]', '-2');
+ shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[2]', '0');
+ shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[3]', '1');
+
+ gl.vertexAttrib3fv(ii, [1, 2, 3]);
+ shouldBeType('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)', 'Float32Array');
+ shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[0]', '1');
+ shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[1]', '2');
+ shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[2]', '3');
+ shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[3]', '1');
+
+ gl.vertexAttrib3fv(ii, new Float32Array([1, -2, 3]));
+ shouldBeType('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)', 'Float32Array');
+ shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[0]', '1');
+ shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[1]', '-2');
+ shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[2]', '3');
+ shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[3]', '1');
+
+ gl.vertexAttrib4fv(ii, [1, 2, 3, 4]);
+ shouldBeType('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)', 'Float32Array');
+ shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[0]', '1');
+ shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[1]', '2');
+ shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[2]', '3');
+ shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[3]', '4');
+
+ gl.vertexAttrib4fv(ii, new Float32Array([1, 2, -3, 4]));
+ shouldBeType('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)', 'Float32Array');
+ shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[0]', '1');
+ shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[1]', '2');
+ shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[2]', '-3');
+ shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[3]', '4');
+
+ gl.vertexAttrib1f(ii, 5);
+ shouldBeType('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)', 'Float32Array');
+ shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[0]', '5');
+ shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[1]', '0');
+ shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[2]', '0');
+ shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[3]', '1');
+
+ gl.vertexAttrib2f(ii, 6, 7);
+ shouldBeType('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)', 'Float32Array');
+ shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[0]', '6');
+ shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[1]', '7');
+ shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[2]', '0');
+ shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[3]', '1');
+
+ gl.vertexAttrib3f(ii, 7, 8, 9);
+ shouldBeType('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)', 'Float32Array');
+ shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[0]', '7');
+ shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[1]', '8');
+ shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[2]', '9');
+ shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[3]', '1');
+
+ gl.vertexAttrib4f(ii, 6, 7, 8, 9);
+ shouldBeType('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)', 'Float32Array');
+ shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[0]', '6');
+ shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[1]', '7');
+ shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[2]', '8');
+ shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[3]', '9');
+
+ if (contextVersion > 1) {
+ gl.vertexAttribI4i(ii, -1, 0, 1, 2);
+ shouldBeType('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)', 'Int32Array');
+ shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[0]', '-1');
+ shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[1]', '0');
+ shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[2]', '1');
+ shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[3]', '2');
+
+ gl.vertexAttribI4ui(ii, 0, 1, 2, 3);
+ shouldBeType('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)', 'Uint32Array');
+ shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[0]', '0');
+ shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[1]', '1');
+ shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[2]', '2');
+ shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[3]', '3');
+
+ gl.vertexAttribI4iv(ii, [-1, 0, 1, 2]);
+ shouldBeType('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)', 'Int32Array');
+ shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[0]', '-1');
+ shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[1]', '0');
+ shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[2]', '1');
+ shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[3]', '2');
+
+ gl.vertexAttribI4iv(ii, new Int32Array([1, 0, -1, 2]));
+ shouldBeType('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)', 'Int32Array');
+ shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[0]', '1');
+ shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[1]', '0');
+ shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[2]', '-1');
+ shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[3]', '2');
+
+ gl.vertexAttribI4uiv(ii, [0, 1, 2, 3]);
+ shouldBeType('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)', 'Uint32Array');
+ shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[0]', '0');
+ shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[1]', '1');
+ shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[2]', '2');
+ shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[3]', '3');
+
+ gl.vertexAttribI4uiv(ii, new Uint32Array([0, 2, 1, 3]));
+ shouldBeType('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)', 'Uint32Array');
+ shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[0]', '0');
+ shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[1]', '2');
+ shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[2]', '1');
+ shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[3]', '3');
+ }
+ }
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR);
+
+ debug("");
+ debug("Checking out-of-range vertexAttrib index");
+ gl.getVertexAttrib(numVertexAttribs, gl.CURRENT_VERTEX_ATTRIB);
+ wtu.glErrorShouldBe(gl, gl.INVALID_VALUE);
+
+ gl.vertexAttrib1fv(numVertexAttribs, [1]);
+ wtu.glErrorShouldBe(gl, gl.INVALID_VALUE);
+
+ gl.vertexAttrib1fv(numVertexAttribs, new Float32Array([-1]));
+ wtu.glErrorShouldBe(gl, gl.INVALID_VALUE);
+
+ gl.vertexAttrib2fv(numVertexAttribs, [1, 2]);
+ wtu.glErrorShouldBe(gl, gl.INVALID_VALUE);
+
+ gl.vertexAttrib2fv(numVertexAttribs, new Float32Array([1, -2]));
+ wtu.glErrorShouldBe(gl, gl.INVALID_VALUE);
+
+ gl.vertexAttrib3fv(numVertexAttribs, [1, 2, 3]);
+ wtu.glErrorShouldBe(gl, gl.INVALID_VALUE);
+
+ gl.vertexAttrib3fv(numVertexAttribs, new Float32Array([1, -2, 3]));
+ wtu.glErrorShouldBe(gl, gl.INVALID_VALUE);
+
+ gl.vertexAttrib4fv(numVertexAttribs, [1, 2, 3, 4]);
+ wtu.glErrorShouldBe(gl, gl.INVALID_VALUE);
+
+ gl.vertexAttrib4fv(numVertexAttribs, new Float32Array([1, 2, -3, 4]));
+ wtu.glErrorShouldBe(gl, gl.INVALID_VALUE);
+
+ gl.vertexAttrib1f(numVertexAttribs, 5);
+ wtu.glErrorShouldBe(gl, gl.INVALID_VALUE);
+
+ gl.vertexAttrib2f(numVertexAttribs, 6, 7);
+ wtu.glErrorShouldBe(gl, gl.INVALID_VALUE);
+
+ gl.vertexAttrib3f(numVertexAttribs, 7, 8, 9);
+ wtu.glErrorShouldBe(gl, gl.INVALID_VALUE);
+
+ gl.vertexAttrib4f(numVertexAttribs, 6, 7, 8, 9);
+ wtu.glErrorShouldBe(gl, gl.INVALID_VALUE);
+
+ if (contextVersion > 1) {
+ gl.vertexAttribI4i(numVertexAttribs, -1, 0, 1, 2);
+ wtu.glErrorShouldBe(gl, gl.INVALID_VALUE);
+
+ gl.vertexAttribI4ui(numVertexAttribs, 0, 1, 2, 3);
+ wtu.glErrorShouldBe(gl, gl.INVALID_VALUE);
+
+ gl.vertexAttribI4iv(numVertexAttribs, [-1, 0, 1, 2]);
+ wtu.glErrorShouldBe(gl, gl.INVALID_VALUE);
+
+ gl.vertexAttribI4iv(numVertexAttribs, new Int32Array([1, 0, -1, 2]));
+ wtu.glErrorShouldBe(gl, gl.INVALID_VALUE);
+
+ gl.vertexAttribI4uiv(numVertexAttribs, [0, 1, 2, 3]);
+ wtu.glErrorShouldBe(gl, gl.INVALID_VALUE);
+
+ gl.vertexAttribI4uiv(numVertexAttribs, new Uint32Array([0, 2, 1, 3]));
+ wtu.glErrorShouldBe(gl, gl.INVALID_VALUE);
+ }
+
+ debug("");
+ debug("Checking invalid array lengths");
+ numVertexAttribs = numVertexAttribs - 1;
+ gl.vertexAttrib1fv(numVertexAttribs, []);
+ wtu.glErrorShouldBe(gl, gl.INVALID_VALUE);
+
+ gl.vertexAttrib1fv(numVertexAttribs, new Float32Array([]));
+ wtu.glErrorShouldBe(gl, gl.INVALID_VALUE);
+
+ gl.vertexAttrib2fv(numVertexAttribs, [1]);
+ wtu.glErrorShouldBe(gl, gl.INVALID_VALUE);
+
+ gl.vertexAttrib2fv(numVertexAttribs, new Float32Array([1]));
+ wtu.glErrorShouldBe(gl, gl.INVALID_VALUE);
+
+ gl.vertexAttrib3fv(numVertexAttribs, [1, 2]);
+ wtu.glErrorShouldBe(gl, gl.INVALID_VALUE);
+
+ gl.vertexAttrib3fv(numVertexAttribs, new Float32Array([1, -2]));
+ wtu.glErrorShouldBe(gl, gl.INVALID_VALUE);
+
+ gl.vertexAttrib4fv(numVertexAttribs, [1, 2, 3]);
+ wtu.glErrorShouldBe(gl, gl.INVALID_VALUE);
+
+ gl.vertexAttrib4fv(numVertexAttribs, new Float32Array([1, 2, -3]));
+ wtu.glErrorShouldBe(gl, gl.INVALID_VALUE);
+
+ if (contextVersion > 1) {
+ gl.vertexAttribI4iv(numVertexAttribs, [-1, 0, 1]);
+ wtu.glErrorShouldBe(gl, gl.INVALID_VALUE);
+
+ gl.vertexAttribI4iv(numVertexAttribs, new Int32Array([1, 0, -1]));
+ wtu.glErrorShouldBe(gl, gl.INVALID_VALUE);
+
+ gl.vertexAttribI4uiv(numVertexAttribs, [0, 1, 2]);
+ wtu.glErrorShouldBe(gl, gl.INVALID_VALUE);
+
+ gl.vertexAttribI4uiv(numVertexAttribs, new Uint32Array([0, 2, 1]));
+ wtu.glErrorShouldBe(gl, gl.INVALID_VALUE);
+ }
+}
+
+debug("");
+var successfullyParsed = true;
diff --git a/dom/canvas/test/webgl-conf/checkout/js/tests/instanceof-test.js b/dom/canvas/test/webgl-conf/checkout/js/tests/instanceof-test.js
new file mode 100644
index 0000000000..edcad3b1f6
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/js/tests/instanceof-test.js
@@ -0,0 +1,105 @@
+/*
+Copyright (c) 2019 The Khronos Group Inc.
+Use of this source code is governed by an MIT-style license that can be
+found in the LICENSE.txt file.
+*/
+
+// This test relies on the surrounding web page defining a variable
+// "contextVersion" which indicates what version of WebGL it's running
+// on -- 1 for WebGL 1.0, 2 for WebGL 2.0, etc.
+
+"use strict";
+var wtu = WebGLTestUtils;
+description(document.title);
+debug("Tests that instanceof works on WebGL objects.");
+debug("");
+
+function checkGLError(message) {
+ var error = gl.getError();
+ if (error != gl.NO_ERROR) {
+ wtu.error("Error: " + message + " caused " + wtu.glEnumToString(gl, error));
+ }
+}
+
+var gl = wtu.create3DContext("canvas", undefined, contextVersion);
+if (contextVersion === 1) {
+ shouldBeTrue('gl instanceof WebGLRenderingContext');
+} else if (contextVersion === 2) {
+ shouldBeTrue('gl instanceof WebGL2RenderingContext');
+}
+
+shouldBeTrue('gl.createBuffer() instanceof WebGLBuffer');
+checkGLError("createBuffer")
+
+shouldBeTrue('gl.createFramebuffer() instanceof WebGLFramebuffer');
+checkGLError("createFramebuffer")
+
+shouldBeTrue('gl.createProgram() instanceof WebGLProgram');
+checkGLError("createProgram")
+
+shouldBeTrue('gl.createRenderbuffer() instanceof WebGLRenderbuffer');
+checkGLError("createRenderbuffer")
+
+shouldBeTrue('gl.createShader(gl.VERTEX_SHADER) instanceof WebGLShader');
+checkGLError("createShader")
+
+shouldBeTrue('gl.createTexture() instanceof WebGLTexture');
+checkGLError("createTexture")
+
+if (contextVersion > 1) {
+ shouldBeTrue('gl.createQuery() instanceof WebGLQuery');
+ checkGLError("createQuery")
+
+ shouldBeTrue('gl.createSampler() instanceof WebGLSampler');
+ checkGLError("createSampler")
+
+ shouldBeTrue('gl.createTransformFeedback() instanceof WebGLTransformFeedback');
+ checkGLError("createTransformFeedback")
+
+ shouldBeTrue('gl.createVertexArray() instanceof WebGLVertexArrayObject');
+ checkGLError("createVertexArray")
+}
+
+var program = wtu.setupProgram(gl, ['vshader', 'fshader'], ['vPosition'], [0]);
+
+shouldBeTrue('gl.getUniformLocation(program, "color") instanceof WebGLUniformLocation');
+checkGLError("getUniformLocation")
+
+shouldBeTrue('gl.getActiveAttrib(program, 0) instanceof WebGLActiveInfo');
+checkGLError("getActiveAttrib")
+
+shouldBeTrue('gl.getActiveUniform(program, 0) instanceof WebGLActiveInfo');
+checkGLError("getActiveUniform")
+
+debug("");
+debug("Tests that those WebGL objects can not be constructed through new operator");
+debug("");
+
+function shouldThrowWithNew(objectType, objectName) {
+ try {
+ new objectType;
+ testFailed('new ' + objectName + ' did not throw');
+ } catch (e) {
+ testPassed('new ' + objectName + ' threw an error');
+ }
+}
+
+shouldThrowWithNew(window.WebGLRenderingContext, 'WebGLRenderingContext');
+shouldThrowWithNew(window.WebGLActiveInfo, 'WebGLActiveInfo');
+shouldThrowWithNew(window.WebGLBuffer, 'WebGLBuffer');
+shouldThrowWithNew(window.WebGLFramebuffer, 'WebGLFramebuffer');
+shouldThrowWithNew(window.WebGLProgram, 'WebGLProgram');
+shouldThrowWithNew(window.WebGLRenderbuffer, 'WebGLRenderbuffer');
+shouldThrowWithNew(window.WebGLShader, 'WebGLShader');
+shouldThrowWithNew(window.WebGLTexture, 'WebGLTexture');
+shouldThrowWithNew(window.WebGLUniformLocation, 'WebGLUniformLocation');
+shouldThrowWithNew(window.WebGLShaderPrecisionFormat, 'WebGLShaderPrecisionFormat');
+if (contextVersion > 1) {
+ shouldThrowWithNew(window.WebGLQuery, 'WebGLQuery');
+ shouldThrowWithNew(window.WebGLSampler, 'WebGLSampler');
+ shouldThrowWithNew(window.WebGLSync, 'WebGLSync');
+ shouldThrowWithNew(window.WebGLTransformFeedback, 'WebGLTransformFeedback');
+ shouldThrowWithNew(window.WebGLVertexArrayObject, 'WebGLVertexArrayObject');
+}
+
+var successfullyParsed = true;
diff --git a/dom/canvas/test/webgl-conf/checkout/js/tests/invalid-vertex-attrib-test.js b/dom/canvas/test/webgl-conf/checkout/js/tests/invalid-vertex-attrib-test.js
new file mode 100644
index 0000000000..b28c484843
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/js/tests/invalid-vertex-attrib-test.js
@@ -0,0 +1,129 @@
+var createInvalidAttribTestFn = (function() {
+
+async function testPreserveDrawingBufferTrue(gl, drawFn, clear) {
+ debug('');
+ debug(`test preserveDrawingBuffer: true with ${drawFn.name} ${clear ? 'with' : 'without'} clear`);
+
+ if (clear) {
+ gl.clearColor(0, 0, 0, 0);
+ gl.clear(gl.COLOR_BUFFER_BIT);
+ }
+
+ const skipTest = drawFn(gl);
+ if (skipTest) {
+ debug('skipped: extension does not exist');
+ return;
+ }
+
+ wtu.checkCanvas(gl, [255, 0, 0, 255], "canvas should be red");
+
+ await waitForComposite();
+
+ wtu.checkCanvas(gl, [255, 0, 0, 255], "canvas should be red");
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "there should be no errors");
+}
+
+function setupWebGL({
+ webglVersion,
+ shadersFn,
+ attribs,
+}) {
+ const positionBuf = gl.createBuffer();
+ gl.bindBuffer(gl.ARRAY_BUFFER, positionBuf);
+ gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
+ -1, -1,
+ 1, -1,
+ -1, 1,
+ -1, 1,
+ 1, -1,
+ 1, 1,
+ ]), gl.STATIC_DRAW);
+ gl.enableVertexAttribArray(0);
+ gl.vertexAttribPointer(0, 2, gl.FLOAT, false, 0, 0);
+ const indexBuf = gl.createBuffer();
+ gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuf);
+ gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint8Array([0, 1, 2, 3, 4, 5]), gl.STATIC_DRAW);
+ return gl;
+}
+
+function createInvalidAttribTestFn(gl) {
+ const vs = `
+ attribute vec4 vPosition;
+ void main()
+ {
+ gl_Position = vPosition;
+ }
+ `;
+
+ const fs = `
+ precision mediump float;
+ void main()
+ {
+ gl_FragColor = vec4(1, 0, 0, 1);
+ }
+ `
+
+ const program = wtu.setupProgram(gl, [vs, fs], ["vPosition"]);
+ if (!program) {
+ debug(`program failed to compile: ${wtu.getLastError()}`);
+ }
+
+ const positionBuffer = gl.createBuffer();
+ gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
+ gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
+ -1, -1,
+ 1, -1,
+ -1, 1,
+ -1, 1,
+ 1, -1,
+ 1, 1,
+ ]), gl.STATIC_DRAW);
+
+ const indexBuffer = gl.createBuffer();
+ gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
+ gl.bufferData(gl.ELEMENT_ARRAY_BUFFER,
+ new Uint8Array([0, 1, 2, 3, 4, 5]),
+ gl.STATIC_DRAW);
+
+ return async function invalidAttribTestFn(drawFn) {
+ debug('');
+
+ // reset attribs
+ gl.bindBuffer(gl.ARRAY_BUFFER, null);
+ const numAttribs = gl.getParameter(gl.MAX_VERTEX_ATTRIBS);
+ for (let i = 0; i < numAttribs; ++i) {
+ gl.disableVertexAttribArray(i);
+ gl.vertexAttribPointer(1, 1, gl.FLOAT, false, 0, 0);
+ }
+
+ debug(`test ${drawFn.name} draws with valid attributes`);
+ gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
+ gl.enableVertexAttribArray(0);
+ gl.vertexAttribPointer(0, 2, gl.FLOAT, false, 0, 0);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "there should be no errors");
+
+ gl.clearColor(0, 0, 0, 0,);
+ gl.clear(gl.COLOR_BUFFER_BIT);
+ wtu.checkCanvas(gl, [0, 0, 0, 0], "canvas should be zero");
+
+ drawFn(gl);
+
+ wtu.checkCanvas(gl, [255, 0, 0, 255], "canvas should be red");
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "there should be no errors");
+
+ debug(`test ${drawFn.name} generates INVALID_OPERATION draws with enabled attribute no buffer bound`);
+ gl.enableVertexAttribArray(1);
+
+ gl.clearColor(0, 0, 0, 0,);
+ gl.clear(gl.COLOR_BUFFER_BIT);
+ wtu.checkCanvas(gl, [0, 0, 0, 0], "canvas should be zero");
+
+ drawFn(gl);
+
+ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "should generate INVALID_OPERATION");
+ wtu.checkCanvas(gl, [0, 0, 0, 0], "canvas should be zero");
+ };
+}
+
+return createInvalidAttribTestFn;
+}());
diff --git a/dom/canvas/test/webgl-conf/checkout/js/tests/iterable-test.js b/dom/canvas/test/webgl-conf/checkout/js/tests/iterable-test.js
new file mode 100644
index 0000000000..45e509f50a
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/js/tests/iterable-test.js
@@ -0,0 +1,183 @@
+/*
+Copyright (c) 2019 The Khronos Group Inc.
+Use of this source code is governed by an MIT-style license that can be
+found in the LICENSE.txt file.
+*/
+IterableTest = (function() {
+
+ var wtu = WebGLTestUtils;
+
+ function run(test, iterations) {
+ var target = iterations || 10;
+ var count = 0;
+
+ function doNextTest() {
+ ++count;
+ debug("Test " + count + " of " + target);
+ var success = test();
+ if (count < target && success !== false) {
+ wtu.dispatchPromise(doNextTest);
+ } else {
+ finishTest();
+ }
+ }
+
+ doNextTest();
+ }
+
+ // Creates a canvas and a texture then exits. There are
+ // no references to either so both should be garbage collected.
+ function createContextCreationAndDestructionTest() {
+ var textureSize = null;
+
+ return function() {
+ var canvas = document.createElement("canvas");
+ // This is safe for any device. See drawingBufferWidth in spec.
+ canvas.width = 2048;
+ canvas.height = 2048;
+ var gl = wtu.create3DContext(canvas);
+ if (textureSize === null) {
+ var maxTextureSize = gl.getParameter(gl.MAX_TEXTURE_SIZE);
+ textureSize = Math.min(1024, maxTextureSize);
+ }
+ var tex = gl.createTexture();
+ gl.bindTexture(gl.TEXTURE_2D, tex);
+ gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, textureSize, textureSize, 0, gl.RGBA, gl.UNSIGNED_BYTE,
+ null);
+ gl.clear(gl.COLOR_BUFFER_BIT);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Should be no errors");
+
+ return true;
+ };
+ }
+
+ // Creates many small canvases and attaches them to the DOM.
+ // This tests an edge case discovered in Chrome where the creation of multiple
+ // WebGL contexts would eventually lead to context creation failure.
+ // (crbug.com/319265) The test does not require that old contexts remain
+ // valid, only that new ones can be created.
+ function createContextCreationTest() {
+ return function() {
+ var canvas = document.createElement("canvas");
+ canvas.width = 1;
+ canvas.height = 1;
+
+ document.body.appendChild(canvas);
+
+ var gl = wtu.create3DContext(canvas);
+ if (!gl) {
+ return false;
+ }
+
+ gl.clear(gl.COLOR_BUFFER_BIT);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Should be no errors");
+
+ return true;
+ };
+ }
+
+ // Draws rectangle on a passed canvas with preserveDrawingBuffer
+ // and antialiasing ON, tests rect color on every iteration.
+ function createMultisampleCorruptionTest(gl) {
+ var lastContext = null;
+ // Allocate a read back buffer in advance and reuse it for all iterations
+ // to avoid memory issues because of late garbage collection.
+ var readBackBuf = new Uint8Array(gl.canvas.width * gl.canvas.height * 4);
+
+ var program = wtu.loadStandardProgram(gl);
+ var uniforms = wtu.getUniformMap(gl, program);
+ gl.useProgram(program);
+
+ gl.clearColor(1.0, 0.0, 0.0, 1.0);
+ gl.clear(gl.COLOR_BUFFER_BIT);
+
+ var vertexObject = gl.createBuffer();
+ gl.bindBuffer(gl.ARRAY_BUFFER, vertexObject);
+ gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([ 0,2.5,0, 1.5,1.5,0, 2.5,1.5,0 ]), gl.STATIC_DRAW);
+ gl.enableVertexAttribArray(0);
+ gl.vertexAttribPointer(0, 3, gl.FLOAT, false, 0, 0);
+ gl.vertexAttrib3f(1, 0.0, 0.0, 1.0);
+
+ var identityMat = new Float32Array([
+ 1, 0, 0, 0,
+ 0, 1, 0, 0,
+ 0, 0, 1, 0,
+ 0, 0, 0, 1
+ ]);
+
+ gl.uniformMatrix4fv(uniforms.u_modelViewProjMatrix.location, false, identityMat);
+
+ function test() {
+ var gl2 = wtu.create3DContext(null, {antialias: true});
+
+ gl2.canvas.width = gl2.canvas.height = 1024;
+ gl2.canvas.style.width = gl2.canvas.style.height = "1px";
+ document.body.appendChild(gl2.canvas);
+
+ gl2.clearColor(1.0, 0.0, 0.0, 1.0);
+ gl2.clear(gl2.COLOR_BUFFER_BIT);
+
+ if(lastContext) {
+ gl.drawArrays(gl.TRIANGLES, 0, 3);
+ var msg = "Canvas should be red";
+ wtu.checkCanvasRectColor(gl,
+ 0, 0, gl.canvas.width, gl.canvas.height,
+ [255, 0, 0, 255], null,
+ function() {
+ testPassed(msg);
+ },
+ function() {
+ testFailed(msg);
+ return false;
+ },
+ debug, readBackBuf);
+ document.body.removeChild(lastContext.canvas);
+ }
+
+ lastContext = gl2;
+ return true;
+ };
+
+ // First pass does initialization
+ test();
+
+ return test;
+ }
+
+ // Draws repeatedly to a large canvas with preserveDrawingBuffer enabled to
+ // try and provoke a context loss.
+ function createPreserveDrawingBufferLeakTest(gl) {
+ var contextActive = true;
+ gl.canvas.addEventListener("webglcontextlost", () => {
+ testFailed("Context was lost");
+ contextActive = false;
+ });
+
+ function test() {
+ var x = Math.random() * gl.drawingBufferWidth;
+ var y = Math.random() * gl.drawingBufferHeight;
+ var width = Math.random() * (gl.drawingBufferWidth - x);
+ var height = Math.random() * (gl.drawingBufferHeight - y);
+
+ gl.enable(gl.SCISSOR_TEST);
+ gl.scissor(x, y, width, height);
+ gl.clearColor(Math.random(), Math.random(), Math.random(), 1.0);
+ gl.clear(gl.COLOR_BUFFER_BIT);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Should be no errors");
+
+ return contextActive;
+ };
+
+ return test;
+ }
+
+ return {
+ run: run,
+
+ createContextCreationAndDestructionTest: createContextCreationAndDestructionTest,
+ createContextCreationTest: createContextCreationTest,
+ createMultisampleCorruptionTest: createMultisampleCorruptionTest,
+ createPreserveDrawingBufferLeakTest: createPreserveDrawingBufferLeakTest
+ };
+
+})();
diff --git a/dom/canvas/test/webgl-conf/checkout/js/tests/line-rendering-quality.js b/dom/canvas/test/webgl-conf/checkout/js/tests/line-rendering-quality.js
new file mode 100644
index 0000000000..dfa7c02167
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/js/tests/line-rendering-quality.js
@@ -0,0 +1,163 @@
+/*
+Copyright (c) 2019 The Khronos Group Inc.
+Use of this source code is governed by an MIT-style license that can be
+found in the LICENSE.txt file.
+*/
+
+'use strict';
+description("Verifies that lines, both aliased and antialiased, have acceptable quality.");
+
+let wtu = WebGLTestUtils;
+let gl;
+
+let aa_fbo;
+
+function setupWebGL1Test(canvasId, useAntialiasing) {
+ gl = wtu.create3DContext(canvasId, { antialias: useAntialiasing }, contextVersion);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Should be no errors during WebGL 1.0 setup");
+}
+
+function setupWebGL2Test(canvasId, useAntialiasing) {
+ gl = wtu.create3DContext(canvasId, { antialias: false }, contextVersion);
+ // In WebGL 2.0, we always allocate the back buffer without
+ // antialiasing. The only question is whether we allocate a
+ // framebuffer with a multisampled renderbuffer attachment.
+ aa_fbo = null;
+ if (useAntialiasing) {
+ aa_fbo = gl.createFramebuffer();
+ gl.bindFramebuffer(gl.FRAMEBUFFER, aa_fbo);
+ let rb = gl.createRenderbuffer();
+ gl.bindRenderbuffer(gl.RENDERBUFFER, rb);
+ let supported = gl.getInternalformatParameter(gl.RENDERBUFFER, gl.RGBA8, gl.SAMPLES);
+ // Prefer 4, then 8, then max.
+ let preferred = [4, 8];
+ let allocated = false;
+ for (let value of preferred) {
+ if (supported.indexOf(value) >= 0) {
+ gl.renderbufferStorageMultisample(gl.RENDERBUFFER, value, gl.RGBA8,
+ gl.drawingBufferWidth, gl.drawingBufferHeight);
+ allocated = true;
+ break;
+ }
+ }
+ if (!allocated) {
+ gl.renderbufferStorageMultisample(gl.RENDERBUFFER, supported[supported.length - 1],
+ gl.RGBA8, gl.drawingBufferWidth, gl.drawingBufferHeight);
+ }
+ gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, rb);
+ }
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Should be no errors during WebGL 2.0 setup");
+}
+
+function setupLines() {
+ let prog = wtu.setupSimpleColorProgram(gl, 0);
+ let loc = gl.getUniformLocation(prog, 'u_color');
+ if (loc == null) {
+ testFailed('Failed to fetch color uniform');
+ }
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "After setup of line program");
+ gl.uniform4f(loc, 1.0, 1.0, 1.0, 1.0);
+ let buffer = gl.createBuffer();
+ let scale = 0.5;
+ gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
+ gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
+ -scale, -scale, 0.0, 1.0,
+ -scale, scale, 0.0, 1.0,
+ scale, scale, 0.0, 1.0,
+ scale, -scale, 0.0, 1.0,
+ -scale, -scale, 0.0, 1.0,
+ ]), gl.STATIC_DRAW);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "After setup of buffer");
+ gl.vertexAttribPointer(0, 4, gl.FLOAT, false, 0, 0);
+ gl.enableVertexAttribArray(0);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "After setup of attribute array");
+}
+
+function renderLines(contextVersion, useAntialiasing) {
+ gl.clearColor(0.0, 0.0, 0.5, 1.0);
+ gl.clear(gl.COLOR_BUFFER_BIT);
+ gl.drawArrays(gl.LINE_STRIP, 0, 5);
+ if (contextVersion == 2 && useAntialiasing) {
+ // Blit aa_fbo into the real back buffer.
+ gl.bindFramebuffer(gl.READ_FRAMEBUFFER, aa_fbo);
+ gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, null);
+ let w = gl.drawingBufferWidth;
+ let h = gl.drawingBufferHeight;
+ gl.blitFramebuffer(0, 0, w, h,
+ 0, 0, w, h,
+ gl.COLOR_BUFFER_BIT, gl.NEAREST);
+ gl.bindFramebuffer(gl.FRAMEBUFFER, null);
+ }
+}
+
+function pixelAboveThreshold(arr, pixelIndex, threshold) {
+ return (arr[4 * pixelIndex + 0] >= threshold &&
+ arr[4 * pixelIndex + 1] >= threshold &&
+ arr[4 * pixelIndex + 2] >= threshold &&
+ arr[4 * pixelIndex + 3] >= threshold);
+}
+
+function checkLine(arr, threshold, direction) {
+ // Count number of crossings from below threshold to above (or equal
+ // to) threshold. Must be equal to 2.
+
+ let numPixels = arr.length / 4;
+ let numUpCrossings = 0;
+ let numDownCrossings = 0;
+ for (let index = 0; index < numPixels - 1; ++index) {
+ let curPixel = pixelAboveThreshold(arr, index, threshold);
+ let nextPixel = pixelAboveThreshold(arr, index + 1, threshold);
+ if (!curPixel && nextPixel) {
+ ++numUpCrossings;
+ } else if (curPixel && !nextPixel) {
+ ++numDownCrossings;
+ }
+ }
+ if (numUpCrossings != numDownCrossings) {
+ testFailed('Found differing numbers of up->down and down->up transitions');
+ }
+ if (numUpCrossings == 2) {
+ testPassed('Found 2 lines, looking in the ' + direction + ' direction');
+ } else {
+ testFailed('Found ' + numUpCrossings + ' lines, looking in the ' +
+ direction + ' direction, expected 2');
+ }
+}
+
+function checkResults() {
+ // Check the middle horizontal and middle vertical line of the canvas.
+ let w = gl.drawingBufferWidth;
+ let h = gl.drawingBufferHeight;
+ let t = 100;
+ let arr = new Uint8Array(4 * w);
+ gl.readPixels(0, Math.floor(h / 2),
+ w, 1, gl.RGBA, gl.UNSIGNED_BYTE, arr);
+ checkLine(arr, t, 'horizontal');
+ arr = new Uint8Array(4 * h);
+ gl.readPixels(Math.floor(w / 2), 0,
+ 1, h, gl.RGBA, gl.UNSIGNED_BYTE, arr);
+ checkLine(arr, t, 'vertical');
+}
+
+function runTest(contextVersion, canvasId, useAntialiasing) {
+ switch (contextVersion) {
+ case 1: {
+ setupWebGL1Test(canvasId, useAntialiasing);
+ break;
+ }
+ case 2: {
+ setupWebGL2Test(canvasId, useAntialiasing);
+ }
+ }
+ setupLines();
+ renderLines(contextVersion, useAntialiasing);
+ checkResults();
+}
+
+function runTests() {
+ runTest(contextVersion, 'testbed', false);
+ runTest(contextVersion, 'testbed2', true);
+}
+
+runTests();
+let successfullyParsed = true;
diff --git a/dom/canvas/test/webgl-conf/checkout/js/tests/no-over-optimizations-on-uniform-array.js b/dom/canvas/test/webgl-conf/checkout/js/tests/no-over-optimizations-on-uniform-array.js
new file mode 100644
index 0000000000..1202b7868c
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/js/tests/no-over-optimizations-on-uniform-array.js
@@ -0,0 +1,247 @@
+/*
+Copyright (c) 2019 The Khronos Group Inc.
+Use of this source code is governed by an MIT-style license that can be
+found in the LICENSE.txt file.
+*/
+NoOverOptimizeOnUniformArrayTester = (function(){
+
+var vshader = [
+ "attribute vec4 a_position;",
+ "void main()",
+ "{",
+ " gl_Position = a_position;",
+ "}"
+].join('\n');
+
+var fshader_max = [
+ "precision mediump float;",
+ "uniform vec4 colora[$(maxUniformVectors)];",
+ "void main()",
+ "{",
+ " gl_FragColor = vec4(colora[$(usedUniformVector)]);",
+ "}"
+].join('\n');
+
+var fshader_max_ab_ab = [
+ "precision mediump float;",
+ "uniform vec4 $(decl1);",
+ "uniform vec4 $(decl2);",
+ "void main()",
+ "{",
+ "gl_FragColor = vec4($(usage1) + $(usage2));",
+ "}"
+].join('\n');
+
+// MaxInt32 is 2^32-1. We need +1 of that to test overflow conditions
+var MaxInt32PlusOne = 4294967296;
+
+function setupTests(gl) {
+ var tests = [];
+ var maxUniformVectors = gl.getParameter(gl.MAX_FRAGMENT_UNIFORM_VECTORS);
+
+ // This test is to test drivers the have bugs related to optimizing
+ // an array of uniforms when only 1 of those uniforms is used.
+ tests.push({
+ desc: "using last element",
+ maxUniformVectors: maxUniformVectors,
+ usedUniformVector: maxUniformVectors - 1,
+ shader: "fshader-max",
+ color: [0, 1, 0, 1],
+ arrayName: "colora",
+ extraName: "colorb",
+ });
+ tests.push({
+ desc: "using first element",
+ maxUniformVectors: maxUniformVectors,
+ usedUniformVector: 0,
+ shader: "fshader-max",
+ color: [0, 1, 0, 1],
+ arrayName: "colora",
+ extraName: "colorb",
+ });
+
+ // Generate test shaders. We're trying to force the driver to
+ // overflow from 1 array into the next if it optimizes. So for example if it was C
+ //
+ // int big[4];
+ // int little[1];
+ // big[5] = 124;
+ //
+ // Would end up setting little[0] instead of big. Some drivers optimize
+ // where if you only use say 'big[3]' it will actually only allocate just 1 element
+ // for big.
+ //
+ // But, some drivers have a bug where the fact that they optimized big to 1 element
+ // does not get passed down to glUniform so when setting the uniform 'big[3]' they
+ // overwrite memory.
+ //
+ // If the driver crashes, yea. We found a bug. We can block the driver.
+ // Otherwise we try various combinations so that setting 'little[0]' first
+ // and then setting all elements of 'big' we hope it will overwrite 'little[0]'
+ // which will show the bug and again we can block the driver.
+ //
+ // We don't know how the driver will order, in memory, the various uniforms
+ // or for that matter we don't even know if they will be contiguous in memory
+ // but to hopefully expose any bugs we try various combinations.
+ //
+ // It could be the compiler orders uniforms alphabetically.
+ // It could be it orders them in order of declaration.
+ // It could be it orders them in order of usage.
+ //
+ // We also test using only first element of big or just the last element of big.
+ //
+ for (var nameOrder = 0; nameOrder < 2; ++nameOrder) {
+ var name1 = nameOrder ? "colora" : "colorb";
+ var name2 = nameOrder ? "colorb" : "colora";
+ for (var last = 0; last < 2; ++last) {
+ var usedUniformVector = last ? maxUniformVectors - 2 : 0;
+ for (var declOrder = 0; declOrder < 2; ++declOrder) {
+ var bigName = declOrder ? name1 : name2;
+ var littleName = declOrder ? name2 : name1;
+ var decl1 = bigName + "[" + (maxUniformVectors - 1) + "]";
+ var decl2 = littleName + "[1]";
+ if (declOrder) {
+ var t = decl1;
+ decl1 = decl2;
+ decl2 = t;
+ }
+ for (var usageOrder = 0; usageOrder < 2; ++usageOrder) {
+ var usage1 = bigName + "[" + usedUniformVector + "]";
+ var usage2 = littleName + "[0]";
+ if (usageOrder) {
+ var t = usage1;
+ usage1 = usage2;
+ usage2 = t;
+ }
+ var fSrc = wtu.replaceParams(fshader_max_ab_ab, {
+ decl1: decl1,
+ decl2: decl2,
+ usage1: usage1,
+ usage2: usage2,
+ });
+ var desc = "testing: " + name1 + ":" + name2 + " using " + (last ? "last" : "first") +
+ " creating uniforms " + decl1 + " " + decl2 + " and accessing " + usage1 + " " + usage2;
+ tests.push({
+ desc: desc,
+ maxUniformVectors: maxUniformVectors - 1,
+ usedUniformVector: usedUniformVector,
+ source: fSrc,
+ color: [0, 0, 0, 1],
+ arrayName: bigName,
+ extraName: littleName,
+ });
+ }
+ }
+ }
+ }
+ return tests;
+};
+
+function testUniformOptimizationIssues(test) {
+ debug("");
+ debug(test.desc);
+ var fshader = test.source;
+ if (!fshader) {
+ fshader = wtu.replaceParams(fshader_max, test);
+ }
+
+ var consoleElem = document.getElementById("console");
+ wtu.addShaderSource(
+ consoleElem, "vertex shader", vshader);
+ wtu.addShaderSource(
+ consoleElem, "fragment shader", fshader);
+
+ var program = wtu.loadProgram(gl, vshader, fshader);
+ gl.useProgram(program);
+
+ var colorbLocation = gl.getUniformLocation(program, test.extraName + "[0]");
+ if (colorbLocation) {
+ gl.uniform4fv(colorbLocation, [0, 1, 0, 0]);
+ }
+
+ // Ensure that requesting an array uniform past MaxInt32PlusOne returns no uniform
+ var nameMaxInt32PlusOne = test.arrayName + "[" + (test.usedUniformVector + MaxInt32PlusOne) + "]";
+ assertMsg(gl.getUniformLocation(program, nameMaxInt32PlusOne) === null,
+ "Requesting " + nameMaxInt32PlusOne + " uniform should return a null uniform location");
+
+ // Set just the used uniform
+ var name = test.arrayName + "[" + test.usedUniformVector + "]";
+ var uniformLocation = gl.getUniformLocation(program, name);
+ gl.uniform4fv(uniformLocation, test.color);
+ wtu.setupIndexedQuad(gl, 1);
+ wtu.clearAndDrawIndexedQuad(gl, 1);
+ wtu.checkCanvas(gl, [0, 255, 0, 255], "should be green");
+
+ // Set all the unused uniforms
+ var locations = [];
+ var allRequiredUniformLocationsQueryable = true;
+ for (var ii = 0; ii < test.maxUniformVectors; ++ii) {
+ var name = test.arrayName + "[" + ii + "]";
+ var uniformLocation = gl.getUniformLocation(program, name);
+ locations.push(uniformLocation);
+ if (ii == test.usedUniformVector) {
+ continue;
+ }
+ // Locations > usedUnformVector may not exist.
+ // Locations <= usedUniformVector MUST exist.
+ if (ii <= test.usedUniformVector && (uniformLocation === undefined || uniformLocation === null)) {
+ allRequiredUniformLocationsQueryable = false;
+ }
+ gl.uniform4fv(uniformLocation, [1, 0, 0, 1]);
+ }
+ if (allRequiredUniformLocationsQueryable) {
+ testPassed("allRequiredUniformLocationsQueryable is true.");
+ }
+ else {
+ testFailed("allRequiredUniformLocationsQueryable should be true. Was false.");
+ }
+ var positionLoc = gl.getAttribLocation(program, "a_position");
+ wtu.setupIndexedQuad(gl, 1, positionLoc);
+ wtu.clearAndDrawIndexedQuad(gl, 1);
+ wtu.checkCanvas(gl, [0, 255, 0, 255], "should be green");
+
+ // Check we can read & write each uniform.
+ // Note: uniforms past test.usedUniformVector might not exist.
+ for (var ii = 0; ii < test.maxUniformVectors; ++ii) {
+ gl.uniform4fv(locations[ii], [ii + 4, ii + 2, ii + 3, ii + 1]);
+ }
+
+ var kEpsilon = 0.01;
+ var isSame = function(v1, v2) {
+ return Math.abs(v1 - v2) < kEpsilon;
+ };
+
+ for (var ii = 0; ii < test.maxUniformVectors; ++ii) {
+ var location = locations[ii];
+ if (location) {
+ var value = gl.getUniform(program, locations[ii]);
+ if (!isSame(value[0], ii + 4) ||
+ !isSame(value[1], ii + 2) ||
+ !isSame(value[2], ii + 3) ||
+ !isSame(value[3], ii + 1)) {
+ testFailed("location: " + ii + " was not correct value");
+ break;
+ }
+ }
+ }
+}
+
+function runOneTest(gl, test) {
+ testUniformOptimizationIssues(test);
+};
+
+function runTests(gl, tests) {
+ debug("");
+ debug("Test drivers don't over optimize unused array elements");
+
+ for (var ii = 0; ii < tests.length; ++ii) {
+ runOneTest(gl, tests[ii]);
+ }
+};
+
+return {
+ setupTests : setupTests,
+ runTests : runTests
+};
+
+}());
diff --git a/dom/canvas/test/webgl-conf/checkout/js/tests/oes-texture-float-and-half-float-linear.js b/dom/canvas/test/webgl-conf/checkout/js/tests/oes-texture-float-and-half-float-linear.js
new file mode 100644
index 0000000000..362023ce01
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/js/tests/oes-texture-float-and-half-float-linear.js
@@ -0,0 +1,151 @@
+/*
+Copyright (c) 2019 The Khronos Group Inc.
+Use of this source code is governed by an MIT-style license that can be
+found in the LICENSE.txt file.
+*/
+
+function testTexLinear(gl, extensionName, internalFormatWebgl2, pixelType) {
+ var wtu = WebGLTestUtils;
+
+ // Before the extension is enabled
+ var extensionEnabled = false;
+ runTestSuite(extensionEnabled);
+
+ if (!gl.getExtension(extensionName))
+ testPassed("No " + extensionName + " support -- this is legal");
+ else {
+ // After the extension is enabled
+ extensionEnabled = true;
+ runTestSuite(extensionEnabled);
+ }
+
+ function runTestSuite(extensionEnabled)
+ {
+ var magF = [gl.NEAREST, gl.LINEAR];
+ var minF = [gl.NEAREST, gl.LINEAR, gl.NEAREST_MIPMAP_NEAREST, gl.NEAREST_MIPMAP_LINEAR, gl.LINEAR_MIPMAP_NEAREST, gl.LINEAR_MIPMAP_LINEAR];
+ var tex2DFShader = [
+ 'uniform sampler2D tex;',
+ 'void main() {',
+ ' gl_FragData[0] = texture2D(tex, vec2(0.5, 0.5)) * vec4(4.0, 2.0, 2.0, 1);',
+ '}'].join('\n');
+
+ var positionVertexShader = [
+ 'attribute vec4 vPosition;',
+ 'void main() {',
+ ' gl_Position = vPosition;',
+ '}'].join('\n');
+
+ var texCubeFShader = [
+ 'uniform samplerCube tex;',
+ 'void main() {',
+ ' gl_FragColor = textureCube(tex, normalize(vec3(0.5, 0.5, 1))) * vec4(4.0, 2.0, 2.0, 1);',
+ '}'].join('\n');
+
+ var vs = wtu.loadShader(gl, positionVertexShader, gl.VERTEX_SHADER);
+ var fs_2d = wtu.loadShader(gl, tex2DFShader, gl.FRAGMENT_SHADER);
+ var fs_cube = wtu.loadShader(gl, texCubeFShader, gl.FRAGMENT_SHADER);
+
+ // TEXTURE_2D
+ var program = wtu.setupProgram(gl, [vs, fs_2d]);
+ gl.useProgram(program);
+ wtu.setupUnitQuad(gl);
+ for (var kk = 0; kk < 2; ++kk) {
+ for (var ii = 0; ii < 6; ++ii) {
+ var linear = false;
+ if (magF[kk] == gl.LINEAR || (minF[ii] != gl.NEAREST && minF[ii] != gl.NEAREST_MIPMAP_NEAREST))
+ linear = true;
+ var color = (!extensionEnabled && linear) ? [0, 0, 0, 255] : [255, 255, 255, 255];
+ runEachTest(gl.TEXTURE_2D, magF[kk], minF[ii], linear, extensionEnabled, color);
+ }
+ }
+
+ // TEXTURE_CUBE_MAP
+ var programCube = wtu.setupProgram(gl, [vs, fs_cube]);
+ gl.useProgram(programCube);
+ wtu.setupUnitQuad(gl);
+ for (var kk = 0; kk < 2; ++kk) {
+ for (var ii = 0; ii < 6; ++ii) {
+ var linear = false;
+ if (magF[kk] == gl.LINEAR || (minF[ii] != gl.NEAREST && minF[ii] != gl.NEAREST_MIPMAP_NEAREST))
+ linear = true;
+ var color = (!extensionEnabled && linear) ? [0, 0, 0, 255] : [255, 255, 255, 255];
+ runEachTest(gl.TEXTURE_CUBE_MAP, magF[kk], minF[ii], linear, extensionEnabled, color);
+ }
+ }
+ }
+
+ function runEachTest(textureTarget, magFilter, minFilter, linear, extensionEnabled, expected)
+ {
+ const format = gl.RGBA;
+ let internalFormat = format;
+ if (wtu.isWebGL2(gl)) {
+ internalFormat = gl[internalFormatWebgl2];
+ }
+ var numberOfChannels = 4;
+ debug("");
+ debug("testing target: " + wtu.glEnumToString(gl,textureTarget) +
+ ", testing format: " + wtu.glEnumToString(gl, format) +
+ ", magFilter is: " + wtu.glEnumToString(gl, magFilter) +
+ ", minFilter is: " + wtu.glEnumToString(gl, minFilter) +
+ ", " + extensionName + " is " + (extensionEnabled ? "enabled": "not enabled")
+ );
+
+ // Generate data.
+ var width = 4;
+ var height = 4;
+ var canvas2d = document.createElement('canvas');
+ canvas2d.width = width;
+ canvas2d.height = height;
+ var ctx2d = canvas2d.getContext('2d');
+ var color = [64, 128, 128, 255];
+ ctx2d.fillStyle = "rgba(" + color[0] + "," + color[1] + "," + color[2] + "," + color[3] + ")";
+ ctx2d.fillRect(0, 0, width, height);
+
+ var texture = gl.createTexture();
+ gl.bindTexture(textureTarget, texture);
+ gl.texParameteri(textureTarget, gl.TEXTURE_MAG_FILTER, magFilter);
+ gl.texParameteri(textureTarget, gl.TEXTURE_MIN_FILTER, minFilter);
+ gl.texParameteri(textureTarget, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
+ gl.texParameteri(textureTarget, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
+
+ if (textureTarget == gl.TEXTURE_2D) {
+ gl.texImage2D(gl.TEXTURE_2D, 0, internalFormat, format, gl[pixelType], canvas2d);
+ if (minFilter != gl.NEAREST && minFilter != gl.LINEAR) {
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors during texture setup");
+ gl.generateMipmap(gl.TEXTURE_2D);
+ if (gl.getError() != gl.NO_ERROR) {
+ debug("generateMipmap failed for floating-point TEXTURE_2D -- this is legal -- skipping the rest of this test");
+ return;
+ }
+ }
+ } else if (textureTarget == gl.TEXTURE_CUBE_MAP) {
+ var targets = [
+ gl.TEXTURE_CUBE_MAP_POSITIVE_X,
+ gl.TEXTURE_CUBE_MAP_NEGATIVE_X,
+ gl.TEXTURE_CUBE_MAP_POSITIVE_Y,
+ gl.TEXTURE_CUBE_MAP_NEGATIVE_Y,
+ gl.TEXTURE_CUBE_MAP_POSITIVE_Z,
+ gl.TEXTURE_CUBE_MAP_NEGATIVE_Z];
+ for (var tt = 0; tt < targets.length; ++tt)
+ gl.texImage2D(targets[tt], 0, internalFormat, format, gl[pixelType], canvas2d);
+ if (minFilter != gl.NEAREST && minFilter != gl.LINEAR) {
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors during texture setup");
+ gl.generateMipmap(gl.TEXTURE_CUBE_MAP);
+ if (gl.getError() != gl.NO_ERROR) {
+ debug("generateMipmap failed for floating-point TEXTURE_CUBE_MAP -- this is legal -- skipping the rest of this test");
+ return;
+ }
+ }
+ }
+ wtu.clearAndDrawUnitQuad(gl);
+ if (!linear) {
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, pixelType + " texture with non-Linear filter should succeed with NO_ERROR no matter whether " + extensionName + " is enabled or not");
+ } else if (!extensionEnabled) {
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, pixelType + " texture with Linear filter should produce [0, 0, 0, 1.0] with NO_ERROR if " + extensionName + " isn't enabled");
+ } else {
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, pixelType + " texture with Linear filter should succeed with NO_ERROR if " + extensionName + " is enabled");
+ }
+
+ wtu.checkCanvas(gl, expected, "should be " + expected[0] + "," + expected[1] + "," + expected[2] + "," + expected[3]);
+ }
+}
diff --git a/dom/canvas/test/webgl-conf/checkout/js/tests/offscreencanvas-transfer-image-bitmap.js b/dom/canvas/test/webgl-conf/checkout/js/tests/offscreencanvas-transfer-image-bitmap.js
new file mode 100644
index 0000000000..b25a7dd026
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/js/tests/offscreencanvas-transfer-image-bitmap.js
@@ -0,0 +1,57 @@
+function testTransferToImageBitmap(webglContextVersion, bitmap) {
+ var internalFormat = "RGBA";
+ var pixelFormat = "RGBA";
+ var pixelType = "UNSIGNED_BYTE";
+
+ var width = 32;
+ var height = 32;
+ var canvas = document.createElement("canvas");
+ canvas.width = width;
+ canvas.height = height;
+ var gl = WebGLTestUtils.create3DContext(canvas);
+ gl.clearColor(0,0,0,1);
+ gl.clearDepth(1);
+ gl.disable(gl.BLEND);
+
+ TexImageUtils.setupTexturedQuad(gl, internalFormat);
+
+ gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
+ // Enable writes to the RGBA channels
+ gl.colorMask(1, 1, 1, 0);
+ var texture = gl.createTexture();
+ // Bind the texture to texture unit 0
+ gl.bindTexture(gl.TEXTURE_2D, texture);
+ // Set up texture parameters
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
+
+ var targets = [gl.TEXTURE_2D];
+ // Upload the image into the texture
+ for (var tt = 0; tt < targets.length; ++tt) {
+ gl.texImage2D(targets[tt], 0, gl[internalFormat], gl[pixelFormat], gl[pixelType], bitmap);
+ }
+ for (var tt = 0; tt < targets.length; ++tt) {
+ // Draw the triangles
+ gl.clearColor(0, 0, 0, 1);
+ gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
+ gl.drawArrays(gl.TRIANGLES, 0, 6);
+
+ var buf = new Uint8Array(width * height * 4);
+ gl.readPixels(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, buf);
+ _checkCanvas(buf, width, height, webglContextVersion);
+ }
+}
+
+function _checkCanvas(buf, width, height, webglContextVersion)
+{
+ for (var i = 0; i < width * height; i++) {
+ if (buf[i * 4] != 255 || buf[i * 4 + 1] != 255 ||
+ buf[i * 4 + 2] != 0 || buf[i * 4 + 3] != 255) {
+ testFailed("OffscreenCanvas." + webglContextVersion +
+ ": This pixel should be [255, 255, 0, 255], but it is: [" + buf[i * 4] + ", " +
+ buf[i * 4 + 1] + ", " + buf[i * 4 + 2] + ", " + buf[i * 4 + 3] + "].");
+ return;
+ }
+ }
+ testPassed("TransferToImageBitmap test on OffscreenCanvas." + webglContextVersion + " passed");
+}
diff --git a/dom/canvas/test/webgl-conf/checkout/js/tests/out-of-bounds-test.js b/dom/canvas/test/webgl-conf/checkout/js/tests/out-of-bounds-test.js
new file mode 100644
index 0000000000..75e3496dfb
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/js/tests/out-of-bounds-test.js
@@ -0,0 +1,321 @@
+/*
+Copyright (c) 2019 The Khronos Group Inc.
+Use of this source code is governed by an MIT-style license that can be
+found in the LICENSE.txt file.
+*/
+
+'use strict';
+
+var OutOfBoundsTest = (function() {
+
+var runCommonInvalidValueTests = function(callTemplate, gl, wtu, ext) {
+ wtu.shouldGenerateGLError(gl, gl.INVALID_VALUE, wtu.replaceParams(callTemplate, {count: -1, type: 'gl.UNSIGNED_BYTE', offset: 0}));
+ wtu.shouldGenerateGLError(gl, gl.INVALID_VALUE, wtu.replaceParams(callTemplate, {count: 0, type: 'gl.UNSIGNED_BYTE', offset: -1}));
+ wtu.shouldGenerateGLError(gl, gl.INVALID_VALUE, wtu.replaceParams(callTemplate, {count: -1, type: 'gl.UNSIGNED_BYTE', offset: 1}));
+ wtu.shouldGenerateGLError(gl, gl.INVALID_VALUE, wtu.replaceParams(callTemplate, {count: 1, type: 'gl.UNSIGNED_BYTE', offset: -1}));
+ wtu.shouldGenerateGLError(gl, gl.INVALID_VALUE, wtu.replaceParams(callTemplate, {count: '0xffffffff', type: 'gl.UNSIGNED_BYTE', offset: 0}));
+};
+
+var setupProgramAndBindVertexArray = function(gl, wtu) {
+ var program = wtu.loadStandardProgram(gl);
+
+ gl.useProgram(program);
+ var vertexObject = gl.createBuffer();
+ gl.bindBuffer(gl.ARRAY_BUFFER, vertexObject);
+ gl.enableVertexAttribArray(0);
+
+ return program;
+};
+
+var setupProgram2 = function(gl, wtu) {
+ var vshader = [
+ 'attribute vec3 aOne;',
+ 'attribute vec2 aTwo;',
+ 'void main() {',
+ ' gl_Position = vec4(aOne, 1.0) + vec4(aTwo, 0.0, 1.0);',
+ '}'
+ ].join('\n');
+
+ var fshader = [
+ 'void main() {',
+ ' gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);',
+ '}'
+ ].join('\n');
+
+ var program = wtu.setupProgram(gl, [vshader, fshader], [ "aOne", "aTwo" ]);
+ if (!program) {
+ testFailed("failed to create test program");
+ }
+ return program;
+};
+
+var runDrawArraysTest = function(callTemplate, gl, wtu, ext) {
+ var program = setupProgramAndBindVertexArray(gl, wtu);
+
+ debug("Test empty buffer")
+ gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([ ]), gl.STATIC_DRAW);
+ gl.vertexAttribPointer(0, 3, gl.FLOAT, false, 0, 0);
+ wtu.shouldGenerateGLError(gl, [gl.NO_ERROR, gl.INVALID_OPERATION], wtu.replaceParams(callTemplate, {offset: 0, count: 1}));
+ wtu.shouldGenerateGLError(gl, [gl.NO_ERROR, gl.INVALID_OPERATION], wtu.replaceParams(callTemplate, {offset: 0, count: 10000}));
+ wtu.shouldGenerateGLError(gl, gl.NO_ERROR, wtu.replaceParams(callTemplate, {offset: 1, count: 0}));
+ wtu.shouldGenerateGLError(gl, gl.NO_ERROR, wtu.replaceParams(callTemplate, {offset: 0, count: 0}));
+ wtu.shouldGenerateGLError(gl, gl.NO_ERROR, wtu.replaceParams(callTemplate, {offset: 100, count: 0}));
+ runCommonInvalidValueTests(callTemplate, gl, wtu, ext);
+
+ debug("")
+ debug("Test buffer with 3 float vectors")
+ gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([ 0,0.5,0, -0.5,-0.5,0, 0.5,-0.5,0 ]), gl.STATIC_DRAW);
+ gl.vertexAttribPointer(0, 3, gl.FLOAT, false, 0, 0);
+ wtu.shouldGenerateGLError(gl, gl.NO_ERROR, wtu.replaceParams(callTemplate, {offset: 0, count: 3}));
+ wtu.shouldGenerateGLError(gl, [gl.NO_ERROR, gl.INVALID_OPERATION], wtu.replaceParams(callTemplate, {offset: 3, count: 2}));
+ wtu.shouldGenerateGLError(gl, [gl.NO_ERROR, gl.INVALID_OPERATION], wtu.replaceParams(callTemplate, {offset: 0, count: 10000}));
+ wtu.shouldGenerateGLError(gl, gl.NO_ERROR, wtu.replaceParams(callTemplate, {offset: 0, count: 0}));
+ wtu.shouldGenerateGLError(gl, gl.NO_ERROR, wtu.replaceParams(callTemplate, {offset: 100, count: 0}));
+ runCommonInvalidValueTests(callTemplate, gl, wtu, ext);
+
+ debug("")
+ debug("Test buffer with interleaved (3+2) float vectors")
+
+ setupProgram2(gl, wtu);
+
+ var vbo = gl.createBuffer();
+ gl.bindBuffer(gl.ARRAY_BUFFER, vbo);
+ // enough for 9 vertices, so 3 triangles
+ gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(9*5), gl.STATIC_DRAW);
+
+ // bind first 3 elements, with a stride of 5 float elements
+ gl.vertexAttribPointer(0, 3, gl.FLOAT, false, 5*4, 0);
+ // bind 2 elements, starting after the first 3; same stride of 5 float elements
+ gl.vertexAttribPointer(1, 2, gl.FLOAT, false, 5*4, 3*4);
+
+ gl.enableVertexAttribArray(0);
+ gl.enableVertexAttribArray(1);
+
+ wtu.shouldGenerateGLError(gl, gl.NO_ERROR, wtu.replaceParams(callTemplate, {offset: 0, count: 9}));
+
+ // negative values must generate INVALID_VALUE; they can never be valid
+ wtu.shouldGenerateGLError(gl, gl.INVALID_VALUE, wtu.replaceParams(callTemplate, {offset: 0, count: -500}));
+ wtu.shouldGenerateGLError(gl, gl.INVALID_VALUE, wtu.replaceParams(callTemplate, {offset: -200, count: 1}));
+ wtu.shouldGenerateGLError(gl, gl.INVALID_VALUE, wtu.replaceParams(callTemplate, {offset: -200, count: -500}));
+
+ // 0xffffffff needs to convert to a 'long' IDL argument as -1, as per
+ // WebIDL 4.1.7. JS ToInt32(0xffffffff) == -1. Thus INVALID_VALUE.
+ wtu.shouldGenerateGLError(gl, gl.INVALID_VALUE, wtu.replaceParams(callTemplate, {offset: 0, count: '0xffffffff'}));
+ wtu.shouldGenerateGLError(gl, gl.INVALID_VALUE, wtu.replaceParams(callTemplate, {offset: '0xffffffff', count: '0xffffffff'}));
+ wtu.shouldGenerateGLError(gl, gl.INVALID_VALUE, wtu.replaceParams(callTemplate, {offset: '0xffffffff', count: 1}));
+
+ // values that could otherwise be valid but aren't due to bindings generate
+ // INVALID_OPERATION
+ wtu.shouldGenerateGLError(gl, [gl.NO_ERROR, gl.INVALID_OPERATION], wtu.replaceParams(callTemplate, {offset: 0, count: 10000}));
+ wtu.shouldGenerateGLError(gl, [gl.NO_ERROR, gl.INVALID_OPERATION], wtu.replaceParams(callTemplate, {offset: '0x7fffffff', count: 1}));
+};
+
+var runDrawElementsTest = function(callTemplate, gl, wtu, ext) {
+ var program = setupProgramAndBindVertexArray(gl, wtu);
+ var contextVersion = wtu.getDefault3DContextVersion();
+
+ gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([ 0,0.5,0, -0.5,-0.5,0, 0.5,-0.5,0 ]), gl.STATIC_DRAW);
+ gl.vertexAttribPointer(0, 3, gl.FLOAT, false, 0, 0);
+
+
+ debug('');
+ debug('Test null index buffer');
+ gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);
+ wtu.shouldGenerateGLError(gl, gl.INVALID_OPERATION, wtu.replaceParams(callTemplate, {count: 0, type: 'gl.UNSIGNED_BYTE', offset: 0}));
+
+ debug('');
+ debug('Test empty index buffer');
+ gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, gl.createBuffer());
+ wtu.shouldGenerateGLError(gl, gl.NO_ERROR, wtu.replaceParams(callTemplate, {count: 0, type: 'gl.UNSIGNED_BYTE', offset: 0}));
+ wtu.shouldGenerateGLError(gl, [gl.NO_ERROR, gl.INVALID_OPERATION], wtu.replaceParams(callTemplate, {count: 3, type: 'gl.UNSIGNED_BYTE', offset: 0}));
+ wtu.shouldGenerateGLError(gl, [gl.NO_ERROR, gl.INVALID_OPERATION], wtu.replaceParams(callTemplate, {count: 10000, type: 'gl.UNSIGNED_BYTE', offset: 0}));
+ wtu.shouldGenerateGLError(gl, [gl.NO_ERROR, gl.INVALID_OPERATION], wtu.replaceParams(callTemplate, {count: 1, type: 'gl.UNSIGNED_BYTE', offset: 0}));
+ runCommonInvalidValueTests(callTemplate, gl, wtu, ext);
+
+ debug('');
+ debug('Test buffer with 3 byte indexes');
+ gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint8Array([ 0, 1, 2 ]), gl.STATIC_DRAW);
+ wtu.shouldGenerateGLError(gl, gl.NO_ERROR, wtu.replaceParams(callTemplate, {count: 3, type: 'gl.UNSIGNED_BYTE', offset: 0}));
+ wtu.shouldGenerateGLError(gl, [gl.NO_ERROR, gl.INVALID_OPERATION], wtu.replaceParams(callTemplate, {count: 3, type: 'gl.UNSIGNED_BYTE', offset: 2}));
+ wtu.shouldGenerateGLError(gl, [gl.NO_ERROR, gl.INVALID_OPERATION], wtu.replaceParams(callTemplate, {count: 10000, type: 'gl.UNSIGNED_BYTE', offset: 0}));
+ runCommonInvalidValueTests(callTemplate, gl, wtu, ext);
+ wtu.shouldGenerateGLError(gl, gl.NO_ERROR, wtu.replaceParams(callTemplate, {count: 0, type: 'gl.UNSIGNED_BYTE', offset: 4}));
+ wtu.shouldGenerateGLError(gl, gl.INVALID_OPERATION, wtu.replaceParams(callTemplate, {count: 10000, type: 'gl.UNSIGNED_BYTE', offset: 10000}));
+
+ wtu.shouldGenerateGLError(gl, gl.NO_ERROR, 'gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, (new Uint8Array([ 3, 0, 1, 2 ])).subarray(1), gl.STATIC_DRAW)');
+ wtu.shouldGenerateGLError(gl, gl.NO_ERROR, wtu.replaceParams(callTemplate, {count: 3, type: 'gl.UNSIGNED_BYTE', offset: 0}));
+ wtu.shouldGenerateGLError(gl, gl.NO_ERROR, 'gl.bufferSubData(gl.ELEMENT_ARRAY_BUFFER, 0, new Uint8Array([ 3, 0, 1]))');
+ var indexValidationError = wtu.shouldGenerateGLError(gl, [gl.INVALID_OPERATION, gl.NO_ERROR], wtu.replaceParams(callTemplate, {count: 3, type: 'gl.UNSIGNED_BYTE', offset: 0}));
+ wtu.shouldGenerateGLError(gl, gl.NO_ERROR, 'gl.bufferSubData(gl.ELEMENT_ARRAY_BUFFER, 0, (new Uint8Array([ 3, 0, 1, 2 ])).subarray(1))');
+ wtu.shouldGenerateGLError(gl, gl.NO_ERROR, wtu.replaceParams(callTemplate, {count: 3, type: 'gl.UNSIGNED_BYTE', offset: 0}));
+ wtu.shouldGenerateGLError(gl, gl.NO_ERROR, wtu.replaceParams(callTemplate, {count: 0, type: 'gl.UNSIGNED_BYTE', offset: 0}));
+
+ debug('');
+ debug('Test buffer with interleaved (3+2) float vectors');
+
+ setupProgram2(gl, wtu);
+
+ var vbo = gl.createBuffer();
+ gl.bindBuffer(gl.ARRAY_BUFFER, vbo);
+ // enough for 9 vertices, so 3 triangles
+ gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(9*5), gl.STATIC_DRAW);
+
+ // bind first 3 elements, with a stride of 5 float elements
+ gl.vertexAttribPointer(0, 3, gl.FLOAT, false, 5*4, 0);
+ // bind 2 elements, starting after the first 3; same stride of 5 float elements
+ gl.vertexAttribPointer(1, 2, gl.FLOAT, false, 5*4, 3*4);
+
+ gl.enableVertexAttribArray(0);
+ gl.enableVertexAttribArray(1);
+
+ var ebo = gl.createBuffer();
+ gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, ebo);
+ // For WebGL 2, PRIMITIVE_RESTART_FIXED_INDEX is always enabled.
+ // 0xffff will be handled as a primitive restart.
+ if (contextVersion <= 1) {
+ gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(
+ [ 0, 1, 2,
+ 1, 2, 0,
+ 2, 0, 1,
+ 201, 202, 203,
+ 0x7fff, 0x7fff, 0x7fff,
+ 0xffff, 0xffff, 0xffff ]),
+ gl.STATIC_DRAW);
+ } else {
+ gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(
+ [ 0, 1, 2,
+ 1, 2, 0,
+ 2, 0, 1,
+ 201, 202, 203,
+ 0x7fff, 0x7fff, 0x7fff,
+ 0xffff - 1, 0xffff - 1, 0xffff - 1 ]),
+ gl.STATIC_DRAW);
+ }
+
+ wtu.shouldGenerateGLError(gl, gl.NO_ERROR, wtu.replaceParams(callTemplate, {count: 9, type: 'gl.UNSIGNED_SHORT', offset: 0}));
+
+
+ // invalid operation with indices that would be valid with correct bindings
+ wtu.shouldGenerateGLError(gl, gl.INVALID_OPERATION, wtu.replaceParams(callTemplate, {count: 9, type: 'gl.UNSIGNED_SHORT', offset: 1000}));
+ wtu.shouldGenerateGLError(gl, indexValidationError, wtu.replaceParams(callTemplate, {count: 12, type: 'gl.UNSIGNED_SHORT', offset: 0}));
+ wtu.shouldGenerateGLError(gl, indexValidationError, wtu.replaceParams(callTemplate, {count: 15, type: 'gl.UNSIGNED_SHORT', offset: 0}));
+ wtu.shouldGenerateGLError(gl, indexValidationError, wtu.replaceParams(callTemplate, {count: 18, type: 'gl.UNSIGNED_SHORT', offset: 0}));
+ wtu.shouldGenerateGLError(gl, indexValidationError, wtu.replaceParams(callTemplate, {count: 3, type: 'gl.UNSIGNED_SHORT', offset: 2*15}));
+
+ // 0xffffffff needs to convert to a 'long' IDL argument as -1, as per
+ // WebIDL 4.1.7. JS ToInt32(0xffffffff) == -1. Thus INVALID_VALUE.
+ wtu.shouldGenerateGLError(gl, gl.INVALID_VALUE, wtu.replaceParams(callTemplate, {count: '0xffffffff', type: 'gl.UNSIGNED_SHORT', offset: 0}));
+ // offset is defined as GLintptr, which is long long in IDL (64-bit).
+ // 2^32 - 1 should not overflow, and only result in INVALID_OPERATION.
+ wtu.shouldGenerateGLError(gl, gl.INVALID_OPERATION, wtu.replaceParams(callTemplate, {count: 1, type: 'gl.UNSIGNED_SHORT', offset: '0xffffffff'}));
+
+ wtu.shouldGenerateGLError(gl, gl.INVALID_OPERATION, wtu.replaceParams(callTemplate, {count: '0x7fffffff', type: 'gl.UNSIGNED_SHORT', offset: 0}));
+
+ wtu.shouldGenerateGLError(gl, gl.NO_ERROR, wtu.replaceParams(callTemplate, {count: 0, type: 'gl.UNSIGNED_SHORT', offset: 0}));
+
+ // invalid operation with offset that's not a multiple of the type size
+ wtu.shouldGenerateGLError(gl, gl.NO_ERROR, wtu.replaceParams(callTemplate, {count: 6, type: 'gl.UNSIGNED_SHORT', offset: 0}));
+ wtu.shouldGenerateGLError(gl, gl.INVALID_OPERATION, wtu.replaceParams(callTemplate, {count: 6, type: 'gl.UNSIGNED_SHORT', offset: 1}));
+ wtu.shouldGenerateGLError(gl, gl.NO_ERROR, wtu.replaceParams(callTemplate, {count: 6, type: 'gl.UNSIGNED_SHORT', offset: 2}));
+
+ // invalid operation if no buffer is bound to ELEMENT_ARRAY_BUFFER
+ gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);
+ wtu.shouldGenerateGLError(gl, gl.INVALID_OPERATION, wtu.replaceParams(callTemplate, {count: 6, type: 'gl.UNSIGNED_SHORT', offset: 0}));
+ gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, ebo);
+
+ debug('');
+ debug('Test buffer setting attrib 0 to a buffer too small and disable it.');
+ var smallVBO = gl.createBuffer();
+ gl.bindBuffer(gl.ARRAY_BUFFER, smallVBO);
+ gl.bufferData(gl.ARRAY_BUFFER, 1, gl.STATIC_DRAW);
+ gl.vertexAttribPointer(0, 3, gl.FLOAT, false, 0, 0x10);
+ gl.disableVertexAttribArray(0);
+ wtu.shouldGenerateGLError(gl, gl.NO_ERROR, wtu.replaceParams(callTemplate, {count: 6, type: 'gl.UNSIGNED_SHORT', offset: 2}));
+ gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);
+ wtu.shouldGenerateGLError(gl, gl.INVALID_OPERATION, wtu.replaceParams(callTemplate, {count: 6, type: 'gl.UNSIGNED_SHORT', offset: 2}));
+};
+
+var runInstancedTest = function(callTemplate, gl, wtu, ext) {
+ setupProgram2(gl, wtu);
+
+ // Initialize non-instanced attribute data.
+ // Enough for 9 vertices, so 3 triangles.
+ var vbo = gl.createBuffer();
+ gl.bindBuffer(gl.ARRAY_BUFFER, vbo);
+ gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(9*3), gl.STATIC_DRAW);
+
+ gl.vertexAttribPointer(0, 3, gl.FLOAT, false, 0, 0);
+
+ // Setup buffer for instanced attribute data.
+ var vbo2 = gl.createBuffer();
+ gl.bindBuffer(gl.ARRAY_BUFFER, vbo2);
+ gl.vertexAttribPointer(1, 2, gl.FLOAT, false, 0, 0);
+
+ gl.enableVertexAttribArray(0);
+ gl.enableVertexAttribArray(1);
+
+ debug('Test out-of-range instanced attributes');
+ debug('');
+
+ debug('Test with an empty buffer for the instanced attribute');
+ ext.vertexAttribDivisorANGLE(1, 1);
+ wtu.shouldGenerateGLError(gl, gl.NO_ERROR, wtu.replaceParams(callTemplate, {offset: 0, count: 9, primcount: 0}));
+ wtu.shouldGenerateGLError(gl, gl.NO_ERROR, wtu.replaceParams(callTemplate, {offset: 0, count: 10000, primcount: 0}));
+ wtu.shouldGenerateGLError(gl, gl.INVALID_OPERATION, wtu.replaceParams(callTemplate, {offset: 0, count: 9, primcount: 1}));
+
+ debug('Test with a buffer with 1 float for the instanced attribute');
+ gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(1), gl.STATIC_DRAW);
+ wtu.shouldGenerateGLError(gl, gl.NO_ERROR, wtu.replaceParams(callTemplate, {offset: 0, count: 9, primcount: 0}));
+ wtu.shouldGenerateGLError(gl, gl.NO_ERROR, wtu.replaceParams(callTemplate, {offset: 0, count: 10000, primcount: 0}));
+ wtu.shouldGenerateGLError(gl, gl.INVALID_OPERATION, wtu.replaceParams(callTemplate, {offset: 0, count: 9, primcount: 1}));
+
+ debug('');
+ debug('Test with a buffer with 2 floats for the instanced attribute');
+ gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(2), gl.STATIC_DRAW);
+ debug('Divisor 1');
+ ext.vertexAttribDivisorANGLE(1, 1);
+ wtu.shouldGenerateGLError(gl, gl.NO_ERROR, wtu.replaceParams(callTemplate, {offset: 0, count: 9, primcount: 1}));
+ wtu.shouldGenerateGLError(gl, gl.INVALID_OPERATION, wtu.replaceParams(callTemplate, {offset: 0, count: 9, primcount: 2}));
+ debug('Divisor 3');
+ ext.vertexAttribDivisorANGLE(1, 3);
+ wtu.shouldGenerateGLError(gl, gl.NO_ERROR, wtu.replaceParams(callTemplate, {offset: 0, count: 9, primcount: 3}));
+ wtu.shouldGenerateGLError(gl, gl.INVALID_OPERATION, wtu.replaceParams(callTemplate, {offset: 0, count: 9, primcount: 4}));
+ wtu.shouldGenerateGLError(gl, gl.INVALID_OPERATION, wtu.replaceParams(callTemplate, {offset: 0, count: 9, primcount: 10000}));
+
+ debug('');
+ debug('Test with a buffer with 4 floats for the instanced attribute');
+ gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(4), gl.STATIC_DRAW);
+ debug('Divisor 1');
+ ext.vertexAttribDivisorANGLE(1, 1);
+ wtu.shouldGenerateGLError(gl, gl.NO_ERROR, wtu.replaceParams(callTemplate, {offset: 0, count: 9, primcount: 2}));
+ wtu.shouldGenerateGLError(gl, gl.INVALID_OPERATION, wtu.replaceParams(callTemplate, {offset: 0, count: 9, primcount: 3}));
+ debug('Divisor 2');
+ ext.vertexAttribDivisorANGLE(1, 2);
+ wtu.shouldGenerateGLError(gl, gl.NO_ERROR, wtu.replaceParams(callTemplate, {offset: 0, count: 9, primcount: 4}));
+ wtu.shouldGenerateGLError(gl, gl.INVALID_OPERATION, wtu.replaceParams(callTemplate, {offset: 0, count: 9, primcount: 5}));
+};
+
+var runDrawArraysInstancedTest = function(callTemplate, gl, wtu, ext) {
+ runInstancedTest(callTemplate, gl, wtu, ext);
+};
+
+var runDrawElementsInstancedTest = function(callTemplate, gl, wtu, ext) {
+ var ebo = gl.createBuffer();
+ gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, ebo);
+ gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint8Array(
+ [ 0, 1, 2,
+ 5, 4, 3,
+ 6, 7, 8 ]),
+ gl.STATIC_DRAW);
+ callTemplate = wtu.replaceParams(callTemplate, {type: 'gl.UNSIGNED_BYTE', offset: '$(offset)', count: '$(count)', primcount: '$(primcount)'});
+ runInstancedTest(callTemplate, gl, wtu, ext);
+};
+
+return {
+ runDrawArraysTest: runDrawArraysTest,
+ runDrawArraysInstancedTest: runDrawArraysInstancedTest,
+ runDrawElementsTest: runDrawElementsTest,
+ runDrawElementsInstancedTest: runDrawElementsInstancedTest
+};
+
+})();
diff --git a/dom/canvas/test/webgl-conf/checkout/js/tests/ovr_multiview2_util.js b/dom/canvas/test/webgl-conf/checkout/js/tests/ovr_multiview2_util.js
new file mode 100644
index 0000000000..5de4dc88d8
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/js/tests/ovr_multiview2_util.js
@@ -0,0 +1,263 @@
+/*
+Copyright (c) 2019 The Khronos Group Inc.
+Use of this source code is governed by an MIT-style license that can be
+found in the LICENSE.txt file.
+*/
+
+"use strict";
+
+function createTextureWithNearestFiltering(target)
+{
+ let texture = gl.createTexture();
+ gl.bindTexture(target, texture);
+ gl.texParameteri(target, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
+ gl.texParameteri(target, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
+ gl.texParameteri(target, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
+ gl.texParameteri(target, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "texture parameter setup should succeed");
+ return texture;
+}
+
+// Write a transformation matrix to elements of floatArray starting from index.
+// The matrix transforms a unit square (-1 to 1) to a rectangle with the width scaleX and the left edge at offsetX.
+function setupTranslateAndScaleXMatrix(floatArray, index, scaleX, offsetX)
+{
+ // x position is transformed according to this equation: scaleX * x0 + translateX = offsetX
+ // By substituting x0 with -1 (unit square x value for the left edge), we get the following:
+ let translateX = offsetX + scaleX;
+
+ floatArray[index] = scaleX;
+ floatArray[index + 1] = 0.0;
+ floatArray[index + 2] = 0.0;
+ floatArray[index + 3] = 0.0;
+
+ floatArray[index + 4] = 0.0;
+ floatArray[index + 5] = 1.0;
+ floatArray[index + 6] = 0.0;
+ floatArray[index + 7] = 0.0;
+
+ floatArray[index + 8] = 0.0;
+ floatArray[index + 9] = 0.0;
+ floatArray[index + 10] = 1.0;
+ floatArray[index + 11] = 0.0;
+
+ floatArray[index + 12] = translateX;
+ floatArray[index + 13] = 0.0;
+ floatArray[index + 14] = 0.0;
+ floatArray[index + 15] = 1.0;
+}
+
+// Check the currently bound read framebuffer with dimensions <width> x <height>.
+// The framebuffer should be divided into <strips> equally wide vertical strips, with the one indicated by
+// <coloredStripIndex> colored with <expectedStripColor>. The rest of the framebuffer should be colored transparent black.
+// A two pixel wide region at each edge of the colored region is left unchecked to allow for some tolerance for rasterization.
+function checkVerticalStrip(width, height, strips, coloredStripIndex, expectedStripColor, framebufferDescription)
+{
+ let colorRegionLeftEdge = (width / strips) * coloredStripIndex;
+ let colorRegionRightEdge = (width / strips) * (coloredStripIndex + 1);
+ if (coloredStripIndex > 0) {
+ wtu.checkCanvasRect(gl, 0, 0, colorRegionLeftEdge - 1, height, [0, 0, 0, 0], 'the left edge of ' + framebufferDescription + ' should be untouched');
+ }
+ if (coloredStripIndex < strips - 1) {
+ wtu.checkCanvasRect(gl, colorRegionRightEdge + 1, 0, width - colorRegionRightEdge - 1, height, [0, 0, 0, 0], 'the right edge of ' + framebufferDescription + ' should be untouched');
+ }
+ wtu.checkCanvasRect(gl, colorRegionLeftEdge + 1, 0, colorRegionRightEdge - colorRegionLeftEdge - 2, height, expectedStripColor, 'a thin strip in ' + framebufferDescription + ' should be colored ' + expectedStripColor);
+}
+
+function getMultiviewPassthroughVertexShader(views) {
+ let shaderCode = ['#version 300 es',
+ '#extension GL_OVR_multiview2 : require',
+
+ 'layout(num_views = $(num_views)) in;',
+
+ 'in vec4 a_position;',
+
+ 'void main() {',
+ ' gl_Position = a_position;',
+ '}'].join('\n');
+ return wtu.replaceParams(shaderCode, {'num_views': views});
+}
+
+// This shader splits the viewport into <views> equally sized vertical strips.
+// The input quad defined by "a_position" is transformed to fill a different
+// strip in each view.
+function getMultiviewOffsetVertexShader(views) {
+ let shaderCode = ['#version 300 es',
+ '#extension GL_OVR_multiview2 : require',
+
+ 'layout(num_views = $(num_views)) in;',
+
+ 'in vec4 a_position;',
+
+ 'void main() {',
+ ' vec4 pos = a_position;',
+ " // Transform the quad to a thin vertical strip that's offset along the x axis according to the view id.",
+ ' pos.x = (pos.x * 0.5 + 0.5 + float(gl_ViewID_OVR)) * 2.0 / $(num_views).0 - 1.0;',
+ ' gl_Position = pos;',
+ '}'].join('\n');
+ return wtu.replaceParams(shaderCode, {'num_views': views});
+}
+
+// This shader transforms the incoming "a_position" with transforms for each
+// view given in the uniform array "transform".
+function getMultiviewRealisticUseCaseVertexShader(views) {
+ let shaderCode = ['#version 300 es',
+ '#extension GL_OVR_multiview2 : require',
+
+ 'layout(num_views = $(num_views)) in;',
+
+ 'uniform mat4 transform[$(num_views)];',
+ 'in vec4 a_position;',
+
+ 'void main() {',
+ " // Transform the quad with the transformation matrix chosen according to gl_ViewID_OVR.",
+ ' vec4 pos = transform[gl_ViewID_OVR] * a_position;',
+ ' gl_Position = pos;',
+ '}'].join('\n');
+ return wtu.replaceParams(shaderCode, {'num_views': views});
+}
+
+function getMultiviewColorFragmentShader() {
+ return ['#version 300 es',
+ '#extension GL_OVR_multiview2 : require',
+ 'precision highp float;',
+
+ 'out vec4 my_FragColor;',
+
+ 'void main() {',
+ ' uint mask = gl_ViewID_OVR + 1u;',
+ ' my_FragColor = vec4(((mask & 4u) != 0u) ? 1.0 : 0.0,',
+ ' ((mask & 2u) != 0u) ? 1.0 : 0.0,',
+ ' ((mask & 1u) != 0u) ? 1.0 : 0.0,',
+ ' 1.0);',
+ '}'].join('\n');
+}
+
+function getMultiviewColorFragmentShaderForDrawBuffers(drawBuffers) {
+ let shaderCode = ['#version 300 es',
+ '#extension GL_OVR_multiview2 : require',
+ 'precision highp float;',
+
+ 'out vec4 my_FragColor[$(drawBuffers)];',
+
+ 'void main() {',
+ ' uint mask;'];
+
+ for (let i = 0; i < drawBuffers; ++i) {
+ shaderCode.push(wtu.replaceParams(' mask = gl_ViewID_OVR + $(i)u;', {'i': i + 1}));
+ shaderCode.push(wtu.replaceParams(' my_FragColor[$(i)] = vec4(((mask & 4u) != 0u) ? 1.0 : 0.0,', {'i': i}));
+ shaderCode.push(' ((mask & 2u) != 0u) ? 1.0 : 0.0,');
+ shaderCode.push(' ((mask & 1u) != 0u) ? 1.0 : 0.0,');
+ shaderCode.push(' 1.0);');
+ }
+ shaderCode.push('}');
+ shaderCode = shaderCode.join('\n');
+ return wtu.replaceParams(shaderCode, {'drawBuffers' : drawBuffers});
+}
+
+function getMultiviewVaryingVertexShader(views) {
+ let shaderCode = ['#version 300 es',
+ '#extension GL_OVR_multiview2 : require',
+
+ 'layout(num_views = $(num_views)) in;',
+
+ 'in vec4 a_position;',
+ 'out float testVarying;',
+
+ 'void main() {',
+ ' gl_Position = a_position;',
+ ' testVarying = float(gl_ViewID_OVR);',
+ '}'].join('\n');
+ return wtu.replaceParams(shaderCode, {'num_views': views});
+}
+
+function getMultiviewVaryingFragmentShader() {
+ return ['#version 300 es',
+ '#extension GL_OVR_multiview2 : require',
+ 'precision highp float;',
+
+ 'in float testVarying;',
+ 'out vec4 my_FragColor;',
+
+ 'void main() {',
+ ' int mask = int(testVarying + 0.1) + 1;',
+ ' my_FragColor = vec4(((mask & 4) != 0) ? 1.0 : 0.0,',
+ ' ((mask & 2) != 0) ? 1.0 : 0.0,',
+ ' ((mask & 1) != 0) ? 1.0 : 0.0,',
+ ' 1.0);',
+ '}'].join('\n');
+}
+
+function getMultiviewFlatVaryingVertexShader(views) {
+ let shaderCode = ['#version 300 es',
+ '#extension GL_OVR_multiview2 : require',
+
+ 'layout(num_views = $(num_views)) in;',
+
+ 'in vec4 a_position;',
+ 'flat out int testVarying;',
+
+ 'void main() {',
+ ' gl_Position = a_position;',
+ ' testVarying = int(gl_ViewID_OVR);',
+ '}'].join('\n');
+ return wtu.replaceParams(shaderCode, {'num_views': views});
+}
+
+function getMultiviewFlatVaryingFragmentShader() {
+ return ['#version 300 es',
+ '#extension GL_OVR_multiview2 : require',
+ 'precision highp float;',
+
+ 'flat in int testVarying;',
+ 'out vec4 my_FragColor;',
+
+ 'void main() {',
+ ' int mask = testVarying + 1;',
+ ' my_FragColor = vec4(((mask & 4) != 0) ? 1.0 : 0.0,',
+ ' ((mask & 2) != 0) ? 1.0 : 0.0,',
+ ' ((mask & 1) != 0) ? 1.0 : 0.0,',
+ ' 1.0);',
+ '}'].join('\n');
+}
+
+function getMultiviewInstancedVertexShader(views) {
+ let shaderCode = ['#version 300 es',
+ '#extension GL_OVR_multiview2 : require',
+
+ 'layout(num_views = $(num_views)) in;',
+
+ 'in vec4 a_position;',
+ 'out vec4 color;',
+
+ 'void main() {',
+ ' vec4 pos = a_position;',
+ " // Transform the quad to a thin vertical strip that's offset along the x axis according to the view id and instance id.",
+ ' pos.x = (pos.x * 0.5 + 0.5 + float(gl_ViewID_OVR) + float(gl_InstanceID)) * 2.0 / ($(num_views).0 * 2.0) - 1.0;',
+ ' int mask = gl_InstanceID + 1;',
+ ' color = vec4(((mask & 4) != 0) ? 1.0 : 0.0,',
+ ' ((mask & 2) != 0) ? 1.0 : 0.0,',
+ ' ((mask & 1) != 0) ? 1.0 : 0.0,',
+ ' 1.0);',
+ ' gl_Position = pos;',
+ '}'].join('\n');
+ return wtu.replaceParams(shaderCode, {'num_views': views});
+}
+
+function getInstanceColorFragmentShader() {
+ return ['#version 300 es',
+ '#extension GL_OVR_multiview2 : require',
+ 'precision highp float;',
+
+ 'in vec4 color;',
+ 'out vec4 my_FragColor;',
+
+ 'void main() {',
+ ' my_FragColor = color;',
+ '}'].join('\n');
+}
+
+function getExpectedColor(view) {
+ var mask = (view + 1);
+ return [(mask & 4) ? 255 : 0, (mask & 2) ? 255 : 0, (mask & 1) ? 255 : 0, 255];
+}
diff --git a/dom/canvas/test/webgl-conf/checkout/js/tests/shader-with-non-reserved-words.js b/dom/canvas/test/webgl-conf/checkout/js/tests/shader-with-non-reserved-words.js
new file mode 100644
index 0000000000..561c1385af
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/js/tests/shader-with-non-reserved-words.js
@@ -0,0 +1,664 @@
+/*
+Copyright (c) 2022 The Khronos Group Inc.
+Use of this source code is governed by an MIT-style license that can be
+found in the LICENSE.txt file.
+*/
+
+async function testNonReservedWords(part, numParts) {
+
+ description(`test shaders using reserved words as identifiers compile ${part} of ${numParts}`);
+
+ const DXWords = [
+ "Buffer",
+ "double",
+ "uint",
+ "half",
+ "dword",
+ "string",
+ "texture",
+ "pixelshader",
+ "vertexshader",
+ "switch",
+ "min16float",
+ "min10float",
+ "min16int",
+ "min12int",
+ "min16uint",
+ "vector",
+ "matrix",
+ "float2",
+ "float3",
+ "float4",
+ "float1x1",
+ "float1x2",
+ "float1x3",
+ "float1x4",
+ "float2x1",
+ "float2x2",
+ "float2x3",
+ "float2x4",
+ "float3x1",
+ "float3x2",
+ "float3x3",
+ "float3x4",
+ "float4x1",
+ "float4x2",
+ "float4x3",
+ "float4x4",
+ "int1x1",
+ "int1x2",
+ "int1x3",
+ "int1x4",
+ "int2x1",
+ "int2x2",
+ "int2x3",
+ "int2x4",
+ "int3x1",
+ "int3x2",
+ "int3x3",
+ "int3x4",
+ "int4x1",
+ "int4x2",
+ "int4x3",
+ "int4x4",
+ "double1x1",
+ "double1x2",
+ "double1x3",
+ "double1x4",
+ "double2x1",
+ "double2x2",
+ "double2x3",
+ "double2x4",
+ "double3x1",
+ "double3x2",
+ "double3x3",
+ "double3x4",
+ "double4x1",
+ "double4x2",
+ "double4x3",
+ "double4x4",
+ "abort",
+ "abs",
+ "acos",
+ "all",
+ "AllMemoryBarrier",
+ "AllMemoryBarrierWithGroupSync",
+ "any",
+ "asdouble",
+ "asfloat",
+ "asin",
+ "asint",
+ "asint",
+ "asuint",
+ "asuint",
+ "atan",
+ "atan2",
+ "ceil",
+ "clamp",
+ "clip",
+ "cos",
+ "cosh",
+ "countbits",
+ "cross",
+ "D3DCOLORtoUBYTE4",
+ "ddx",
+ "ddx_coarse",
+ "ddx_fine",
+ "ddy",
+ "ddy_coarse",
+ "ddy_fine",
+ "degrees",
+ "determinant",
+ "DeviceMemoryBarrier",
+ "DeviceMemoryBarrierWithGroupSync",
+ "distance",
+ "dot",
+ "dst",
+ "errorf",
+ "EvaluateAttributeAtCentroid",
+ "EvaluateAttributeAtSample",
+ "EvaluateAttributeSnapped",
+ "exp",
+ "exp2",
+ "f16tof32",
+ "f32tof16",
+ "faceforward",
+ "firstbithigh",
+ "firstbitlow",
+ "floor",
+ "fma",
+ "fmod",
+ "frac",
+ "frexp",
+ "fwidth",
+ "GetRenderTargetSampleCount",
+ "GetRenderTargetSamplePosition",
+ "GroupMemoryBarrier",
+ "GroupMemoryBarrierWithGroupSync",
+ "InterlockedAdd",
+ "InterlockedAnd",
+ "InterlockedCompareExchange",
+ "InterlockedCompareStore",
+ "InterlockedExchange",
+ "InterlockedMax",
+ "InterlockedMin",
+ "InterlockedOr",
+ "InterlockedXor",
+ "isfinite",
+ "isinf",
+ "isnan",
+ "ldexp",
+ "length",
+ "lerp",
+ "lit",
+ "log",
+ "log10",
+ "log2",
+ "mad",
+ "max",
+ "min",
+ "modf",
+ "msad4",
+ "mul",
+ "noise",
+ "normalize",
+ "pow",
+ "printf",
+ "Process2DQuadTessFactorsAvg",
+ "Process2DQuadTessFactorsMax",
+ "Process2DQuadTessFactorsMin",
+ "ProcessIsolineTessFactors",
+ "ProcessQuadTessFactorsAvg",
+ "ProcessQuadTessFactorsMax",
+ "ProcessQuadTessFactorsMin",
+ "ProcessTriTessFactorsAvg",
+ "ProcessTriTessFactorsMax",
+ "ProcessTriTessFactorsMin",
+ "radians",
+ "rcp",
+ "reflect",
+ "refract",
+ "reversebits",
+ "round",
+ "rsqrt",
+ "saturate",
+ "sign",
+ "sin",
+ "sincos",
+ "sinh",
+ "smoothstep",
+ "sqrt",
+ "step",
+ "tan",
+ "tanh",
+ "tex1D",
+ "tex1D",
+ "tex1Dbias",
+ "tex1Dgrad",
+ "tex1Dlod",
+ "tex1Dproj",
+ "tex2D",
+ "tex2D",
+ "tex2Dbias",
+ "tex2Dgrad",
+ "tex2Dlod",
+ "tex2Dproj",
+ "tex3D",
+ "tex3D",
+ "tex3Dbias",
+ "tex3Dgrad",
+ "tex3Dlod",
+ "tex3Dproj",
+ "texCUBE",
+ "texCUBE",
+ "texCUBEbias",
+ "texCUBEgrad",
+ "texCUBElod",
+ "texCUBEproj",
+ "transpose",
+ "trunc"
+ ];
+
+ const GLSL_4_20_11_words = [
+ "attribute",
+ "const",
+ "uniform",
+ "varying",
+ "coherent",
+ "volatile",
+ "restrict",
+ "readonly",
+ "writeonly",
+ "atomic_uint",
+ "layout",
+ "centroid",
+ "flat",
+ "smooth",
+ "noperspective",
+ "patch",
+ "sample",
+ "break",
+ "continue",
+ "do",
+ "for",
+ "while",
+ "switch",
+ "case",
+ "default",
+ "if",
+ "else",
+ "subroutine",
+ "in",
+ "out",
+ "inout",
+ "float",
+ "double",
+ "int",
+ "void",
+ "bool",
+ "true",
+ "false",
+ "invariant",
+ "discard",
+ "return",
+ "mat2",
+ "mat3",
+ "mat4",
+ "dmat2",
+ "dmat3",
+ "dmat4",
+ "mat2x2",
+ "mat2x3",
+ "mat2x4",
+ "dmat2x2",
+ "dmat2x3",
+ "dmat2x4",
+ "mat3x2",
+ "mat3x3",
+ "mat3x4",
+ "dmat3x2",
+ "dmat3x3",
+ "dmat3x4",
+ "mat4x2",
+ "mat4x3",
+ "mat4x4",
+ "dmat4x2",
+ "dmat4x3",
+ "dmat4x4",
+ "vec2",
+ "vec3",
+ "vec4",
+ "ivec2",
+ "ivec3",
+ "ivec4",
+ "bvec2",
+ "bvec3",
+ "bvec4",
+ "dvec2",
+ "dvec3",
+ "dvec4",
+ "uint",
+ "uvec2",
+ "uvec3",
+ "uvec4",
+ "lowp",
+ "mediump",
+ "highp",
+ "precision",
+ "sampler1D",
+ "sampler2D",
+ "sampler3D",
+ "samplerCube",
+ "sampler1DShadow",
+ "sampler2DShadow",
+ "samplerCubeShadow",
+ "sampler1DArray",
+ "sampler2DArray",
+ "sampler1DArrayShadow",
+ "sampler2DArrayShadow",
+ "isampler1D",
+ "isampler2D",
+ "isampler3D",
+ "isamplerCube",
+ "isampler1DArray",
+ "isampler2DArray",
+ "usampler1D",
+ "usampler2D",
+ "usampler3D",
+ "usamplerCube",
+ "usampler1DArray",
+ "usampler2DArray",
+ "sampler2DRect",
+ "sampler2DRectShadow",
+ "isampler2DRect",
+ "usampler2DRect",
+ "samplerBuffer",
+ "isamplerBuffer",
+ "usamplerBuffer",
+ "sampler2DMS",
+ "isampler2DMS",
+ "usampler2DMS",
+ "sampler2DMSArray",
+ "isampler2DMSArray",
+ "usampler2DMSArray",
+ "samplerCubeArray",
+ "samplerCubeArrayShadow",
+ "isamplerCubeArray",
+ "usamplerCubeArray",
+ "image1D",
+ "iimage1D",
+ "uimage1D",
+ "image2D",
+ "iimage2D",
+ "uimage2D",
+ "image3D",
+ "iimage3D",
+ "uimage3D",
+ "image2DRect",
+ "iimage2DRect",
+ "uimage2DRect",
+ "imageCube",
+ "iimageCube",
+ "uimageCube",
+ "imageBuffer",
+ "iimageBuffer",
+ "uimageBuffer",
+ "image1DArray",
+ "iimage1DArray",
+ "uimage1DArray",
+ "image2DArray",
+ "iimage2DArray",
+ "uimage2DArray",
+ "imageCubeArray",
+ "iimageCubeArray",
+ "uimageCubeArray",
+ "image2DMS",
+ "iimage2DMS",
+ "uimage2DMS",
+ "image2DMSArray",
+ "iimage2DMSArray",
+ "uimage2DMSArray",
+ "struct"
+ ];
+
+ const GLSL_4_20_11_future_words = [
+ "common",
+ "partition",
+ "active",
+ "asm",
+ "class",
+ "union",
+ "enum",
+ "typedef",
+ "template",
+ "this",
+ "packed",
+ "resource",
+ "goto",
+ "inline",
+ "noinline",
+ "public",
+ "static",
+ "extern",
+ "external",
+ "interface",
+ "long",
+ "short",
+ "half",
+ "fixed",
+ "unsigned",
+ "superp",
+ "input",
+ "output",
+ "hvec2",
+ "hvec3",
+ "hvec4",
+ "fvec2",
+ "fvec3",
+ "fvec4",
+ "sampler3DRect",
+ "filter",
+ "sizeof",
+ "cast",
+ "namespace",
+ "using",
+ "row_major"
+ ];
+
+ const GLSL_1_0_17_words = [
+ "attribute",
+ "const",
+ "uniform",
+ "varying",
+ "break",
+ "continue",
+ "do",
+ "for",
+ "while",
+ "if",
+ "else",
+ "in",
+ "out",
+ "inout",
+ "float",
+ "int",
+ "void",
+ "bool",
+ "true",
+ "false",
+ "lowp",
+ "mediump",
+ "highp",
+ "precision",
+ "invariant",
+ "discard",
+ "return",
+ "mat2",
+ "mat3",
+ "mat4",
+ "vec2",
+ "vec3",
+ "vec4",
+ "ivec2",
+ "ivec3",
+ "ivec4",
+ "bvec2",
+ "bvec3",
+ "bvec4",
+ "sampler2D",
+ "samplerCube",
+ "struct"
+ ]
+
+ const GLSL_1_0_17_FutureWords = [
+ "asm",
+ "class",
+ "union",
+ "enum",
+ "typedef",
+ "template",
+ "this",
+ "packed",
+ "goto",
+ "switch",
+ "default",
+ "inline",
+ "noinline",
+ "volatile",
+ "public",
+ "static",
+ "extern",
+ "external",
+ "interface",
+ "flat",
+ "long",
+ "short",
+ "double",
+ "half",
+ "fixed",
+ "unsigned",
+ "superp",
+ "input",
+ "output",
+ "hvec2",
+ "hvec3",
+ "hvec4",
+ "dvec2",
+ "dvec3",
+ "dvec4",
+ "fvec2",
+ "fvec3",
+ "fvec4",
+ "sampler1D",
+ "sampler3D",
+ "sampler1DShadow",
+ "sampler2DShadow",
+ "sampler2DRect",
+ "sampler3DRect",
+ "sampler2DRectShadow",
+ "sizeof",
+ "cast",
+ "namespace",
+ "using"
+ ];
+
+ const allBadWords = [
+ ...DXWords,
+ ...GLSL_4_20_11_words,
+ ...GLSL_4_20_11_future_words,
+ ];
+ const numWordsPerPart = Math.ceil(allBadWords.length / numParts);
+ const firstWordNdx = numWordsPerPart * (part - 1);
+ const badWords = allBadWords.slice(firstWordNdx, firstWordNdx + numWordsPerPart);
+ debug(`running tests for words ${firstWordNdx} to ${firstWordNdx + badWords.length - 1} of ${allBadWords.length}`);
+
+ const shaders = {
+ vertexShader0: `
+struct $replaceMe {
+ vec4 $replaceMe;
+};
+struct Foo {
+ $replaceMe $replaceMe;
+};
+attribute vec4 position;
+void main()
+{
+ Foo f;
+ f.$replaceMe.$replaceMe = position;
+ gl_Position = f.$replaceMe.$replaceMe;
+}
+`,
+ fragmentShader0: `
+precision mediump float;
+vec4 $replaceMe() {
+ return vec4(0,1,0,1);
+}
+void main()
+{
+ gl_FragColor = $replaceMe();
+}
+`,
+ vertexShader1: `
+attribute vec4 $replaceMe;
+void main()
+{
+ gl_Position = $replaceMe;
+}
+`,
+ fragmentShader1: `
+precision mediump float;
+vec4 foo(vec4 $replaceMe) {
+ return $replaceMe;
+}
+void main()
+{
+ gl_FragColor = foo(vec4(1,0,1,1));
+}
+`,
+ vertexShader2: `
+varying vec4 $replaceMe;
+attribute vec4 position;
+void main()
+{
+ gl_Position = position;
+ $replaceMe = position;
+}
+`,
+ fragmentShader2: `
+precision mediump float;
+varying vec4 $replaceMe;
+void main()
+{
+ gl_FragColor = $replaceMe;
+}
+`,
+ vertexShader3: `
+attribute vec4 position;
+void main()
+{
+ gl_Position = position;
+}
+`,
+ fragmentShader3: `
+precision mediump float;
+uniform vec4 $replaceMe;
+void main()
+{
+ gl_FragColor = $replaceMe;
+}
+`,
+ };
+
+ const wtu = WebGLTestUtils;
+ const gl = wtu.create3DContext();
+ const wait = ms => new Promise(resolve => setTimeout(resolve, ms));
+
+ const reservedWords = new Set([
+ ...GLSL_1_0_17_words,
+ ...GLSL_1_0_17_FutureWords,
+ ]);
+
+ const checkedWords = new Set();
+
+ const src = [];
+ for (let ii = 0; ii < 4; ++ii) {
+ const vSrc = shaders[`vertexShader${ii}`];
+ const fSrc = shaders[`fragmentShader${ii}`];
+ src.push({vSrc: vSrc, fSrc: fSrc});
+ }
+
+ for (const badWord of badWords) {
+ testWord(badWord);
+ await wait();
+ }
+ finishTest();
+
+ function testWord(word) {
+ if (reservedWords.has(word) || checkedWords.has(word)) {
+ return;
+ }
+ checkedWords.add(word);
+ debug("");
+ debug(`testing: ${word}`);
+
+ for (let ii = 0; ii < src.length; ++ii) {
+ const vs = src[ii].vSrc.replace(/\$replaceMe/g, word);
+ const fs = src[ii].fSrc.replace(/\$replaceMe/g, word);
+
+ let success = true;
+ const program = wtu.loadProgram(gl, vs, fs, function(msg) {
+ debug(msg);
+ success = false;
+ }, true);
+ if (success) {
+ testPassed(`shader with: '${word}' compiled`);
+ } else {
+ testFailed(`shader with: '${word}' failed to compile`);
+ }
+ if (program) {
+ gl.deleteProgram(program);
+ }
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no GL errors");
+ }
+ }
+} \ No newline at end of file
diff --git a/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-2d-with-canvas-sub-rectangle.js b/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-2d-with-canvas-sub-rectangle.js
new file mode 100644
index 0000000000..792f832451
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-2d-with-canvas-sub-rectangle.js
@@ -0,0 +1,292 @@
+/*
+Copyright (c) 2019 The Khronos Group Inc.
+Use of this source code is governed by an MIT-style license that can be
+found in the LICENSE.txt file.
+*/
+
+function generateTest(internalFormat, pixelFormat, pixelType, prologue, resourcePath, defaultContextVersion) {
+ var wtu = WebGLTestUtils;
+ var tiu = TexImageUtils;
+ var gl = null;
+ var successfullyParsed = false;
+ var realRedColor = [255, 0, 0];
+ var realGreenColor = [0, 255, 0];
+ var realBlueColor = [0, 0, 255];
+ var realCyanColor = [0, 255, 255];
+ var redColor = realRedColor;
+ var greenColor = realGreenColor;
+ var blueColor = realBlueColor;
+ var cyanColor = realCyanColor;
+
+ function init()
+ {
+ description('Verify texImage2D and texSubImage2D code paths taking a sub-rectangle of a canvas (' + internalFormat + '/' + pixelFormat + '/' + pixelType + ')');
+
+ // Set the default context version while still allowing the webglVersion URL query string to override it.
+ wtu.setDefault3DContextVersion(defaultContextVersion);
+
+ // The sub-rectangle tests only apply to WebGL 2.0 for the
+ // time being, though the tests for the WebGL 1.0
+ // format/internal format/type combinations are generated into
+ // conformance/textures/.
+ if (wtu.getDefault3DContextVersion() < 2) {
+ debug('Test only applies to WebGL 2.0');
+ finishTest();
+ return;
+ }
+
+ gl = wtu.create3DContext("example", { preserveDrawingBuffer: true });
+
+ if (!prologue(gl)) {
+ finishTest();
+ return;
+ }
+
+ switch (gl[pixelFormat]) {
+ case gl.RED:
+ case gl.RED_INTEGER:
+ greenColor = [0, 0, 0];
+ blueColor = [0, 0, 0];
+ cyanColor = [0, 0, 0];
+ break;
+
+ case gl.RG:
+ case gl.RG_INTEGER:
+ blueColor = [0, 0, 0];
+ cyanColor = [0, 255, 0];
+ break;
+
+ case gl.LUMINANCE:
+ case gl.LUMINANCE_ALPHA:
+ redColor = [255, 255, 255];
+ greenColor = [0, 0, 0];
+ blueColor = [0, 0, 0];
+ cyanColor = [0, 0, 0];
+ break;
+
+ case gl.ALPHA:
+ redColor = [0, 0, 0];
+ greenColor = [0, 0, 0];
+ blueColor = [0, 0, 0];
+ cyanColor = [0, 0, 0];
+ break;
+
+ default:
+ break;
+ }
+
+ gl.clearColor(0,0,0,1);
+ gl.clearDepth(1);
+ gl.disable(gl.BLEND);
+
+ var canvas2d = document.createElement('canvas');
+ runTest(canvas2d, setupSourceCanvas2D, '2D-rendered canvas');
+
+ var canvasWebGL = document.createElement('canvas');
+ runTest(canvasWebGL, setupSourceCanvasWebGL, 'WebGL-rendered canvas');
+
+ finishTest();
+ }
+
+ function fillStyle2D(ctx, color) {
+ ctx.fillStyle = 'rgb(' + color[0] + ', ' + color[1] + ', ' + color[2] + ')';
+ }
+
+ function setupSourceCanvas2D(canvas) {
+ var width = canvas.width;
+ var height = canvas.height;
+ var halfWidth = Math.floor(width / 2);
+ var halfHeight = Math.floor(height / 2);
+
+ var ctx = canvas.getContext('2d');
+ // Always use the same pattern for this test: four quadrants:
+ // red green
+ // blue cyan
+ // Handle odd-sized canvases
+ fillStyle2D(ctx, realRedColor);
+ ctx.fillRect(0, 0, halfWidth, halfHeight);
+ fillStyle2D(ctx, realGreenColor);
+ ctx.fillRect(halfWidth, 0, width - halfWidth, halfHeight);
+ fillStyle2D(ctx, realBlueColor);
+ ctx.fillRect(0, halfHeight, halfWidth, height - halfHeight);
+ fillStyle2D(ctx, realCyanColor);
+ ctx.fillRect(halfWidth, halfHeight, width - halfWidth, height - halfHeight);
+ }
+
+ function clearColorWebGL(ctx, color) {
+ ctx.clearColor(color[0] / 255.0, color[1] / 255.0, color[2] / 255.0, 1.0);
+ ctx.clear(ctx.COLOR_BUFFER_BIT);
+ }
+
+ function setupSourceCanvasWebGL(canvas) {
+ var width = canvas.width;
+ var height = canvas.height;
+ var halfWidth = Math.floor(width / 2);
+ var halfHeight = Math.floor(height / 2);
+
+ var ctx = canvas.getContext('webgl');
+ // Always use the same pattern for this test: four quadrants:
+ // red green
+ // blue cyan
+ // Handle odd-sized canvases
+
+ ctx.viewport(0, 0, width, height);
+ ctx.enable(ctx.SCISSOR_TEST);
+ // OpenGL origin is lower-left
+ ctx.scissor(0, 0, halfWidth, halfHeight);
+ clearColorWebGL(ctx, realBlueColor);
+ ctx.scissor(halfWidth, 0, width - halfWidth, halfHeight);
+ clearColorWebGL(ctx, realCyanColor);
+ ctx.scissor(0, halfHeight, halfWidth, height - halfHeight);
+ clearColorWebGL(ctx, realRedColor);
+ ctx.scissor(halfWidth, halfHeight, width - halfWidth, height - halfHeight);
+ clearColorWebGL(ctx, realGreenColor);
+ }
+
+ function runOneIteration(sourceDescription, useTexSubImage2D, flipY,
+ canvas, canvasSize, canvasSetupFunction,
+ sourceSubRectangle, expected,
+ bindingTarget, program)
+ {
+ sourceSubRectangleString = '';
+ if (sourceSubRectangle) {
+ sourceSubRectangleString = ', sourceSubRectangle=' + sourceSubRectangle;
+ }
+ debug('');
+ debug('Testing ' + sourceDescription + ' with ' +
+ (useTexSubImage2D ? 'texSubImage2D' : 'texImage2D') +
+ ', flipY=' + flipY +
+ ', bindingTarget=' + (bindingTarget == gl.TEXTURE_2D ? 'TEXTURE_2D' : 'TEXTURE_CUBE_MAP') +
+ sourceSubRectangleString);
+
+ var loc;
+ if (bindingTarget == gl.TEXTURE_CUBE_MAP) {
+ loc = gl.getUniformLocation(program, "face");
+ }
+
+ // Initialize the contents of the source canvas.
+ var width = canvasSize[0];
+ var height = canvasSize[1];
+ var halfWidth = Math.floor(width / 2);
+ var halfHeight = Math.floor(height / 2);
+ canvas.width = width;
+ canvas.height = height;
+ canvasSetupFunction(canvas);
+
+ // Upload the source canvas to the texture and draw it to a quad.
+ gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
+ // Enable writes to the RGBA channels
+ gl.colorMask(1, 1, 1, 0);
+ var texture = gl.createTexture();
+ // Bind the texture to texture unit 0
+ gl.bindTexture(bindingTarget, texture);
+ // Set up texture parameters
+ gl.texParameteri(bindingTarget, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
+ gl.texParameteri(bindingTarget, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
+ // Set up pixel store parameters
+ gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, flipY);
+ gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, false);
+ wtu.failIfGLError(gl, 'gl.pixelStorei(gl.UNPACK_COLORSPACE_CONVERSION_WEBGL, gl.NONE);');
+ var targets = [gl.TEXTURE_2D];
+ if (bindingTarget == gl.TEXTURE_CUBE_MAP) {
+ targets = [gl.TEXTURE_CUBE_MAP_POSITIVE_X,
+ gl.TEXTURE_CUBE_MAP_NEGATIVE_X,
+ gl.TEXTURE_CUBE_MAP_POSITIVE_Y,
+ gl.TEXTURE_CUBE_MAP_NEGATIVE_Y,
+ gl.TEXTURE_CUBE_MAP_POSITIVE_Z,
+ gl.TEXTURE_CUBE_MAP_NEGATIVE_Z];
+ }
+ // In this test, this is always specified. It's currently WebGL 2.0-specific.
+ gl.pixelStorei(gl.UNPACK_SKIP_PIXELS, sourceSubRectangle[0]);
+ gl.pixelStorei(gl.UNPACK_SKIP_ROWS, sourceSubRectangle[1]);
+ // Upload the image into the texture
+ var uploadWidth = sourceSubRectangle[2];
+ var uploadHeight = sourceSubRectangle[3];
+ for (var tt = 0; tt < targets.length; ++tt) {
+ if (useTexSubImage2D) {
+ // Initialize the texture to black first
+ gl.texImage2D(targets[tt], 0, gl[internalFormat],
+ uploadWidth, uploadHeight, 0,
+ gl[pixelFormat], gl[pixelType], null);
+ gl.texSubImage2D(targets[tt], 0, 0, 0,
+ uploadWidth, uploadHeight,
+ gl[pixelFormat], gl[pixelType], canvas);
+ } else {
+ gl.texImage2D(targets[tt], 0, gl[internalFormat],
+ uploadWidth, uploadHeight, 0,
+ gl[pixelFormat], gl[pixelType], canvas);
+ }
+ }
+
+ gl.pixelStorei(gl.UNPACK_SKIP_PIXELS, 0);
+ gl.pixelStorei(gl.UNPACK_SKIP_ROWS, 0);
+
+ // The tests are constructed to upload a single solid color
+ // out of the canvas.
+ var outputCanvasWidth = gl.drawingBufferWidth;
+ var outputCanvasHeight = gl.drawingBufferHeight;
+
+ for (var tt = 0; tt < targets.length; ++tt) {
+ if (bindingTarget == gl.TEXTURE_CUBE_MAP) {
+ gl.uniform1i(loc, targets[tt]);
+ }
+ // Draw the triangles
+ wtu.clearAndDrawUnitQuad(gl, [0, 0, 0, 255]);
+
+ var msg = 'should be ' + expected;
+ wtu.checkCanvasRect(gl, 0, 0, outputCanvasWidth, outputCanvasHeight, expected, msg);
+ }
+ }
+
+ function runTest(canvas, canvasSetupFunction, sourceDescription)
+ {
+ var program = tiu.setupTexturedQuad(gl, internalFormat);
+ runTestOnBindingTarget(gl.TEXTURE_2D, program, canvas, canvasSetupFunction, sourceDescription);
+ program = tiu.setupTexturedQuadWithCubeMap(gl, internalFormat);
+ runTestOnBindingTarget(gl.TEXTURE_CUBE_MAP, program, canvas, canvasSetupFunction, sourceDescription);
+
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors");
+ }
+
+ function runTestOnBindingTarget(bindingTarget, program, canvas, canvasSetupFunction, sourceDescription) {
+ var cases = [
+ // Small canvas cases. Expected that these won't be
+ // GPU-accelerated in most browsers' implementations.
+ { expected: redColor, flipY: false, size: [2, 2], subRect: [0, 0, 1, 1] },
+ { expected: greenColor, flipY: false, size: [2, 2], subRect: [1, 0, 1, 1] },
+ { expected: blueColor, flipY: false, size: [2, 2], subRect: [0, 1, 1, 1] },
+ { expected: cyanColor, flipY: false, size: [2, 2], subRect: [1, 1, 1, 1] },
+ { expected: redColor, flipY: true, size: [2, 2], subRect: [0, 1, 1, 1] },
+ { expected: greenColor, flipY: true, size: [2, 2], subRect: [1, 1, 1, 1] },
+ { expected: blueColor, flipY: true, size: [2, 2], subRect: [0, 0, 1, 1] },
+ { expected: cyanColor, flipY: true, size: [2, 2], subRect: [1, 0, 1, 1] },
+
+ // Larger canvas cases. Expected that these will be
+ // GPU-accelerated in most browsers' implementations.
+ // Changes will be gladly accepted to trigger more
+ // browsers' heuristics to accelerate these canvases.
+ { expected: redColor, flipY: false, size: [384, 384], subRect: [ 0, 0, 192, 192] },
+ { expected: greenColor, flipY: false, size: [384, 384], subRect: [192, 0, 192, 192] },
+ { expected: blueColor, flipY: false, size: [384, 384], subRect: [ 0, 192, 192, 192] },
+ { expected: cyanColor, flipY: false, size: [384, 384], subRect: [192, 192, 192, 192] },
+ { expected: blueColor, flipY: true, size: [384, 384], subRect: [ 0, 0, 192, 192] },
+ { expected: cyanColor, flipY: true, size: [384, 384], subRect: [192, 0, 192, 192] },
+ { expected: redColor, flipY: true, size: [384, 384], subRect: [ 0, 192, 192, 192] },
+ { expected: greenColor, flipY: true, size: [384, 384], subRect: [192, 192, 192, 192] },
+
+ ];
+
+ for (var i in cases) {
+ runOneIteration(sourceDescription, false, cases[i].flipY,
+ canvas, cases[i].size, canvasSetupFunction,
+ cases[i].subRect,
+ cases[i].expected, bindingTarget, program);
+ runOneIteration(sourceDescription, true, cases[i].flipY,
+ canvas, cases[i].size, canvasSetupFunction,
+ cases[i].subRect,
+ cases[i].expected, bindingTarget, program);
+ }
+ }
+
+ return init;
+}
diff --git a/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-2d-with-canvas.js b/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-2d-with-canvas.js
new file mode 100644
index 0000000000..a96eeb9de0
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-2d-with-canvas.js
@@ -0,0 +1,468 @@
+/*
+Copyright (c) 2019 The Khronos Group Inc.
+Use of this source code is governed by an MIT-style license that can be
+found in the LICENSE.txt file.
+*/
+
+function generateTest(internalFormat, pixelFormat, pixelType, prologue, resourcePath, defaultContextVersion) {
+ var wtu = WebGLTestUtils;
+ var tiu = TexImageUtils;
+ var gl = null;
+ var successfullyParsed = false;
+ var whiteColor = [255, 255, 255, 255];
+ var redColor = [255, 0, 0, 255];
+ var greenColor = [0, 255, 0, 255];
+ var semiTransparentRedColor = [127, 0, 0, 127];
+ var semiTransparentGreenColor = [0, 127, 0, 127];
+ var repeatCount;
+
+ function replicateRedChannel(color)
+ {
+ color[1] = color[0];
+ color[2] = color[0];
+ }
+
+ function zapColorChannels(color)
+ {
+ color[0] = 0;
+ color[1] = 0;
+ color[2] = 0;
+ }
+
+ function setAlphaChannelTo1(color)
+ {
+ color[3] = 255;
+ }
+
+ function replicateAllRedChannels()
+ {
+ replicateRedChannel(redColor);
+ replicateRedChannel(semiTransparentRedColor);
+ replicateRedChannel(greenColor);
+ replicateRedChannel(semiTransparentGreenColor);
+ }
+
+ function setAllAlphaChannelsTo1()
+ {
+ setAlphaChannelTo1(redColor);
+ setAlphaChannelTo1(semiTransparentRedColor);
+ setAlphaChannelTo1(greenColor);
+ setAlphaChannelTo1(semiTransparentGreenColor);
+ }
+
+ function repeatCountForTextureFormat(internalFormat, pixelFormat, pixelType)
+ {
+ // There were bugs in early WebGL 1.0 implementations when repeatedly uploading canvas
+ // elements into textures. In response, this test was changed into a regression test by
+ // repeating all of the cases multiple times. Unfortunately, this means that adding a new
+ // case above significantly increases the run time of the test suite. The problem is made
+ // even worse by the addition of many more texture formats in WebGL 2.0.
+ //
+ // Doing repeated runs with just a couple of WebGL 1.0's supported texture formats acts as a
+ // sufficient regression test for the old bugs. For this reason the test has been changed to
+ // only repeat for those texture formats.
+ if ((internalFormat == 'RGBA' && pixelFormat == 'RGBA' && pixelType == 'UNSIGNED_BYTE') ||
+ (internalFormat == 'RGB' && pixelFormat == 'RGB' && pixelType == 'UNSIGNED_BYTE')) {
+ return 4;
+ }
+
+ return 1;
+ }
+
+ function init()
+ {
+ description('Verify texImage2D and texSubImage2D code paths taking canvas elements (' + internalFormat + '/' + pixelFormat + '/' + pixelType + ')');
+
+ // Set the default context version while still allowing the webglVersion URL query string to override it.
+ wtu.setDefault3DContextVersion(defaultContextVersion);
+ gl = wtu.create3DContext("example");
+
+ if (!prologue(gl)) {
+ finishTest();
+ return;
+ }
+
+ repeatCount = repeatCountForTextureFormat(internalFormat, pixelFormat, pixelType);
+
+ switch (gl[pixelFormat]) {
+ case gl.RED:
+ case gl.RED_INTEGER:
+ // Zap green and blue channels.
+ whiteColor[1] = 0;
+ whiteColor[2] = 0;
+ greenColor[1] = 0;
+ semiTransparentGreenColor[1] = 0;
+ // Alpha channel is 1.0.
+ setAllAlphaChannelsTo1();
+ break;
+ case gl.RG:
+ case gl.RG_INTEGER:
+ // Zap blue channel.
+ whiteColor[2] = 0;
+ // Alpha channel is 1.0.
+ setAllAlphaChannelsTo1();
+ break;
+ case gl.LUMINANCE:
+ // Replicate red channels.
+ replicateAllRedChannels();
+ // Alpha channel is 1.0.
+ setAllAlphaChannelsTo1();
+ break;
+ case gl.ALPHA:
+ // Red, green and blue channels are all 0.0.
+ zapColorChannels(redColor);
+ zapColorChannels(semiTransparentRedColor);
+ zapColorChannels(greenColor);
+ zapColorChannels(semiTransparentGreenColor);
+ zapColorChannels(whiteColor);
+ break;
+ case gl.LUMINANCE_ALPHA:
+ // Replicate red channels.
+ replicateAllRedChannels();
+ break;
+ case gl.RGB:
+ case gl.RGB_INTEGER:
+ // Alpha channel is 1.0.
+ setAllAlphaChannelsTo1();
+ break;
+ default:
+ break;
+ }
+
+ switch (gl[internalFormat]) {
+ case gl.SRGB8:
+ case gl.SRGB8_ALPHA8:
+ semiTransparentRedColor = wtu.sRGBToLinear(semiTransparentRedColor);
+ semiTransparentGreenColor = wtu.sRGBToLinear(semiTransparentGreenColor);
+ break;
+ case gl.RGBA8UI:
+ // For int and uint textures, TexImageUtils outputs the maximum value (in this case,
+ // 255) for the alpha channel all the time because of differences in behavior when
+ // sampling integer textures with and without alpha channels. Since changing this
+ // behavior may have large impact across the test suite, leave it as is for now.
+ setAllAlphaChannelsTo1();
+ break;
+ }
+
+ gl.clearColor(0,0,0,1);
+ gl.clearDepth(1);
+
+ runTest();
+ }
+
+ function setCanvasToRedGreen(ctx) {
+ var width = ctx.canvas.width;
+ var height = ctx.canvas.height;
+ var halfHeight = Math.floor(height / 2);
+ ctx.clearRect(0, 0, width, height);
+ ctx.fillStyle = "#ff0000";
+ ctx.fillRect(0, 0, width, halfHeight);
+ ctx.fillStyle = "#00ff00";
+ ctx.fillRect(0, halfHeight, width, height - halfHeight);
+ }
+
+ function setCanvasToSemiTransparentRedGreen(ctx) {
+ var width = ctx.canvas.width;
+ var height = ctx.canvas.height;
+ var halfHeight = Math.floor(height / 2);
+ ctx.clearRect(0, 0, width, height);
+ ctx.fillStyle = "rgba(127, 0, 0, 0.5)";
+ ctx.fillRect(0, 0, width, halfHeight);
+ ctx.fillStyle = "rgba(0, 127, 0, 0.5)";
+ ctx.fillRect(0, halfHeight, width, height - halfHeight);
+ }
+
+ function drawTextInCanvas(ctx, bindingTarget) {
+ var width = ctx.canvas.width;
+ var height = ctx.canvas.height;
+ ctx.fillStyle = "#ffffff";
+ ctx.fillRect(0, 0, width, height);
+ ctx.font = '20pt Arial';
+ ctx.fillStyle = 'black';
+ ctx.textAlign = "center";
+ ctx.textBaseline = "middle";
+ ctx.fillText("1234567890", width / 2, height / 4);
+ }
+
+ function setCanvasTo257x257(ctx, bindingTarget) {
+ ctx.canvas.width = 257;
+ ctx.canvas.height = 257;
+ setCanvasToRedGreen(ctx);
+ }
+
+ function setCanvasTo257x257SemiTransparent(ctx, bindingTarget) {
+ ctx.canvas.width = 257;
+ ctx.canvas.height = 257;
+ setCanvasToSemiTransparentRedGreen(ctx);
+ }
+
+ function setCanvasToMin(ctx, bindingTarget) {
+ if (bindingTarget == gl.TEXTURE_CUBE_MAP) {
+ // cube map texture must be square.
+ ctx.canvas.width = 2;
+ } else {
+ ctx.canvas.width = 1;
+ }
+ ctx.canvas.height = 2;
+ setCanvasToRedGreen(ctx);
+ }
+
+ function setCanvasToMinSemiTransparent(ctx, bindingTarget) {
+ if (bindingTarget == gl.TEXTURE_CUBE_MAP) {
+ // cube map texture must be square.
+ ctx.canvas.width = 2;
+ } else {
+ ctx.canvas.width = 1;
+ }
+ ctx.canvas.height = 2;
+ setCanvasToSemiTransparentRedGreen(ctx);
+ }
+
+ function runOneIteration(canvas, useTexSubImage2D, flipY, semiTransparent, program, bindingTarget, opt_texture, opt_fontTest)
+ {
+ var objType = 'canvas';
+ if (canvas.transferToImageBitmap)
+ objType = 'OffscreenCanvas';
+ debug('Testing ' + (useTexSubImage2D ? 'texSubImage2D' : 'texImage2D') +
+ ' with flipY=' + flipY + ' bindingTarget=' + (bindingTarget == gl.TEXTURE_2D ? 'TEXTURE_2D' : 'TEXTURE_CUBE_MAP') +
+ ' canvas size: ' + canvas.width + 'x' + canvas.height +
+ ' source object type: ' + objType +
+ (opt_fontTest ? " with fonts" : " with" + (semiTransparent ? " semi-transparent" : "") + " red-green"));
+ gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
+ if (!opt_texture) {
+ var texture = gl.createTexture();
+ // Bind the texture to texture unit 0
+ gl.bindTexture(bindingTarget, texture);
+ // Set up texture parameters
+ gl.texParameteri(bindingTarget, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
+ gl.texParameteri(bindingTarget, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
+ gl.texParameteri(bindingTarget, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
+ gl.texParameteri(bindingTarget, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
+ } else {
+ var texture = opt_texture;
+ }
+ // Set up pixel store parameters
+ gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, flipY);
+ gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, false);
+ wtu.failIfGLError(gl, 'gl.pixelStorei(gl.UNPACK_COLORSPACE_CONVERSION_WEBGL, gl.NONE);');
+ var targets = [gl.TEXTURE_2D];
+ if (bindingTarget == gl.TEXTURE_CUBE_MAP) {
+ targets = [gl.TEXTURE_CUBE_MAP_POSITIVE_X,
+ gl.TEXTURE_CUBE_MAP_NEGATIVE_X,
+ gl.TEXTURE_CUBE_MAP_POSITIVE_Y,
+ gl.TEXTURE_CUBE_MAP_NEGATIVE_Y,
+ gl.TEXTURE_CUBE_MAP_POSITIVE_Z,
+ gl.TEXTURE_CUBE_MAP_NEGATIVE_Z];
+ }
+ // Upload the image into the texture
+ for (var tt = 0; tt < targets.length; ++tt) {
+ // Initialize the texture to black first
+ if (useTexSubImage2D) {
+ gl.texImage2D(targets[tt], 0, gl[internalFormat], canvas.width, canvas.height, 0,
+ gl[pixelFormat], gl[pixelType], null);
+ gl.texSubImage2D(targets[tt], 0, 0, 0, gl[pixelFormat], gl[pixelType], canvas);
+ } else {
+ gl.texImage2D(targets[tt], 0, gl[internalFormat], gl[pixelFormat], gl[pixelType], canvas);
+ }
+ }
+
+ var width = gl.canvas.width;
+ var height = gl.canvas.height;
+ var halfWidth = Math.floor(width / 2);
+ var halfHeight = Math.floor(height / 2);
+ var top = flipY ? 0 : (height - halfHeight);
+ var bottom = flipY ? (height - halfHeight) : 0;
+
+ var loc;
+ if (bindingTarget == gl.TEXTURE_CUBE_MAP) {
+ loc = gl.getUniformLocation(program, "face");
+ }
+
+ for (var tt = 0; tt < targets.length; ++tt) {
+ if (bindingTarget == gl.TEXTURE_CUBE_MAP) {
+ gl.uniform1i(loc, targets[tt]);
+ }
+ // Draw the triangles
+ wtu.clearAndDrawUnitQuad(gl, [0, 255, 0, 255]);
+
+ if (opt_fontTest) {
+ // check half is a solid color.
+ wtu.checkCanvasRect(
+ gl, 0, top, width, halfHeight,
+ whiteColor,
+ "should be white");
+ // check other half is not a solid color.
+ wtu.checkCanvasRectColor(
+ gl, 0, bottom, width, halfHeight,
+ whiteColor, 0,
+ function() {
+ testFailed("font missing");
+ },
+ function() {
+ testPassed("font rendered");
+ },
+ debug);
+ } else {
+ var localRed = semiTransparent ? semiTransparentRedColor : redColor;
+ var localGreen = semiTransparent ? semiTransparentGreenColor : greenColor;
+
+ // Allow a tolerance for premultiplication/unmultiplication, especially for texture
+ // formats with lower bit depths.
+ var tolerance = 0;
+ if (semiTransparent) {
+ tolerance = 3;
+ if (pixelType == 'UNSIGNED_SHORT_5_6_5' || internalFormat == 'RGB565') {
+ tolerance = 6;
+ } else if (pixelType == 'UNSIGNED_SHORT_4_4_4_4' || internalFormat == 'RGBA4') {
+ tolerance = 9;
+ } else if (pixelType == 'UNSIGNED_SHORT_5_5_5_1' || internalFormat == 'RGB5_A1') {
+ // Semi-transparent values are allowed to convert to either 1 or 0 for this
+ // single-bit alpha format per OpenGL ES 3.0.5 section 2.1.6.2, "Conversion
+ // from Floating-Point to Normalized Fixed-Point". Ignore alpha for these
+ // tests.
+ tolerance = 6;
+ localRed = localRed.slice(0, 3);
+ localGreen = localGreen.slice(0, 3);
+ } else if (internalFormat == 'RGB10_A2') {
+ // The alpha channel is too low-resolution for any meaningful comparisons.
+ localRed = localRed.slice(0, 3);
+ localGreen = localGreen.slice(0, 3);
+ }
+ }
+
+ // Check the top and bottom halves and make sure they have the right color.
+ debug("Checking " + (flipY ? "top" : "bottom"));
+ wtu.checkCanvasRect(gl, 0, bottom, width, halfHeight, localRed,
+ "shouldBe " + localRed, tolerance);
+ debug("Checking " + (flipY ? "bottom" : "top"));
+ wtu.checkCanvasRect(gl, 0, top, width, halfHeight, localGreen,
+ "shouldBe " + localGreen, tolerance);
+ }
+
+ if (!useTexSubImage2D && pixelFormat == "RGBA") {
+ if (pixelType == "FLOAT") {
+ // Attempt to set a pixel in the texture to ensure the texture was
+ // actually created with floats. Regression test for http://crbug.com/484968
+ var pixels = new Float32Array([1000.0, 1000.0, 1000.0, 1000.0]);
+ gl.texSubImage2D(targets[tt], 0, 0, 0, 1, 1, gl[pixelFormat], gl[pixelType], pixels);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Texture should be backed by floats");
+ } else if (pixelType == "HALF_FLOAT_OES" || pixelType == "HALF_FLOAT") {
+ // Attempt to set a pixel in the texture to ensure the texture was
+ // actually created with half-floats. Regression test for http://crbug.com/484968
+ var halfFloatTenK = 0x70E2; // Half float 10000
+ var pixels = new Uint16Array([halfFloatTenK, halfFloatTenK, halfFloatTenK, halfFloatTenK]);
+ gl.texSubImage2D(targets[tt], 0, 0, 0, 1, 1, gl[pixelFormat], gl[pixelType], pixels);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Texture should be backed by half-floats");
+ }
+ }
+ }
+
+ if (false) {
+ var m = wtu.makeImageFromCanvas(gl.canvas);
+ document.getElementById("console").appendChild(m);
+ document.getElementById("console").appendChild(document.createElement("hr"));
+ }
+
+ return texture;
+ }
+
+ function runTest()
+ {
+ var canvas = document.createElement('canvas');
+
+ var cases = [
+ { canvas: canvas, sub: false, flipY: true, semiTransparent: false, font: false, init: setCanvasToMin },
+ { canvas: canvas, sub: false, flipY: false, semiTransparent: false, font: false },
+ { canvas: canvas, sub: true, flipY: true, semiTransparent: false, font: false },
+ { canvas: canvas, sub: true, flipY: false, semiTransparent: false, font: false },
+ { canvas: canvas, sub: false, flipY: true, semiTransparent: true, font: false, init: setCanvasToMinSemiTransparent },
+ { canvas: canvas, sub: false, flipY: false, semiTransparent: true, font: false },
+ { canvas: canvas, sub: true, flipY: true, semiTransparent: true, font: false },
+ { canvas: canvas, sub: true, flipY: false, semiTransparent: true, font: false },
+ { canvas: canvas, sub: false, flipY: true, semiTransparent: false, font: false, init: setCanvasTo257x257 },
+ { canvas: canvas, sub: false, flipY: false, semiTransparent: false, font: false },
+ { canvas: canvas, sub: true, flipY: true, semiTransparent: false, font: false },
+ { canvas: canvas, sub: true, flipY: false, semiTransparent: false, font: false },
+ { canvas: canvas, sub: false, flipY: true, semiTransparent: true, font: false, init: setCanvasTo257x257SemiTransparent },
+ { canvas: canvas, sub: false, flipY: false, semiTransparent: true, font: false },
+ { canvas: canvas, sub: true, flipY: true, semiTransparent: true, font: false },
+ { canvas: canvas, sub: true, flipY: false, semiTransparent: true, font: false },
+ ];
+
+ // The font tests don't work with ALPHA-only textures since they draw to the color channels.
+ if (internalFormat != 'ALPHA') {
+ cases = cases.concat([
+ { canvas: canvas, sub: false, flipY: true, semiTransparent: false, font: true, init: drawTextInCanvas },
+ { canvas: canvas, sub: false, flipY: false, semiTransparent: false, font: true },
+ { canvas: canvas, sub: true, flipY: true, semiTransparent: false, font: true },
+ { canvas: canvas, sub: true, flipY: false, semiTransparent: false, font: true },
+ ]);
+ }
+
+ if (window.OffscreenCanvas) {
+ var offscreenCanvas = new OffscreenCanvas(1, 1);
+ cases = cases.concat([
+ { canvas: offscreenCanvas, sub: false, flipY: true, semiTransparent: false, font: false, init: setCanvasToMin },
+ { canvas: offscreenCanvas, sub: false, flipY: false, semiTransparent: false, font: false },
+ { canvas: offscreenCanvas, sub: true, flipY: true, semiTransparent: false, font: false },
+ { canvas: offscreenCanvas, sub: true, flipY: false, semiTransparent: false, font: false },
+ { canvas: offscreenCanvas, sub: false, flipY: true, semiTransparent: true, font: false, init: setCanvasToMinSemiTransparent },
+ { canvas: offscreenCanvas, sub: false, flipY: false, semiTransparent: true, font: false },
+ { canvas: offscreenCanvas, sub: true, flipY: true, semiTransparent: true, font: false },
+ { canvas: offscreenCanvas, sub: true, flipY: false, semiTransparent: true, font: false },
+ ]);
+ }
+
+ function runTexImageTest(bindingTarget) {
+ var program;
+ if (bindingTarget == gl.TEXTURE_2D) {
+ program = tiu.setupTexturedQuad(gl, internalFormat);
+ } else {
+ program = tiu.setupTexturedQuadWithCubeMap(gl, internalFormat);
+ }
+
+ return new Promise(function(resolve, reject) {
+ var count = repeatCount;
+ var caseNdx = 0;
+ var texture = undefined;
+ function runNextTest() {
+ var c = cases[caseNdx];
+ var imageDataBefore = null;
+ if (c.init) {
+ c.init(c.canvas.getContext('2d'), bindingTarget);
+ }
+ texture = runOneIteration(c.canvas, c.sub, c.flipY, c.semiTransparent, program, bindingTarget, texture, c.font);
+ // for the first 2 iterations always make a new texture.
+ if (count < 2) {
+ gl.deleteTexture(texture);
+ texture = undefined;
+ }
+ ++caseNdx;
+ if (caseNdx == cases.length) {
+ caseNdx = 0;
+ --count;
+ if (!count) {
+ resolve("SUCCESS");
+ return;
+ }
+ }
+ // While we are working with Canvases, it's really unlikely that
+ // waiting for composition will change anything here, and it's much
+ // slower, so just dispatchPromise. If we want to test with composites,
+ // we should test a more narrow subset of tests.
+ wtu.dispatchPromise(runNextTest);
+ }
+ runNextTest();
+ });
+ }
+
+ runTexImageTest(gl.TEXTURE_2D).then(function(val) {
+ runTexImageTest(gl.TEXTURE_CUBE_MAP).then(function(val) {
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors");
+ finishTest();
+ });
+ });
+ }
+
+ return init;
+}
diff --git a/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-2d-with-image-bitmap-from-blob.js b/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-2d-with-image-bitmap-from-blob.js
new file mode 100644
index 0000000000..f434b9834c
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-2d-with-image-bitmap-from-blob.js
@@ -0,0 +1,49 @@
+/*
+Copyright (c) 2019 The Khronos Group Inc.
+Use of this source code is governed by an MIT-style license that can be
+found in the LICENSE.txt file.
+*/
+
+function generateTest(internalFormat, pixelFormat, pixelType, prologue, resourcePath, defaultContextVersion) {
+ var wtu = WebGLTestUtils;
+ var tiu = TexImageUtils;
+ var gl = null;
+ var successfullyParsed = false;
+
+ async function init()
+ {
+ description('Verify texImage2D and texSubImage2D code paths taking ImageBitmap created from a Blob (' + internalFormat + '/' + pixelFormat + '/' + pixelType + ')');
+
+ if(!window.createImageBitmap || !window.ImageBitmap) {
+ finishTest();
+ return;
+ }
+
+ // Set the default context version while still allowing the webglVersion URL query string to override it.
+ wtu.setDefault3DContextVersion(defaultContextVersion);
+ gl = wtu.create3DContext("example");
+
+ if (!prologue(gl)) {
+ finishTest();
+ return;
+ }
+
+ gl.clearColor(0,0,0,1);
+ gl.clearDepth(1);
+
+ debug('*** Running tests against red-green-semi-transparent.png ***');
+ let response = await fetch(resourcePath + "red-green-semi-transparent.png");
+ let blob = await response.blob();
+ await runImageBitmapTest(blob, 0.5, internalFormat, pixelFormat, pixelType, gl, tiu, wtu, false);
+ debug('*** Running tests against red-green-128x128-linear-profile.jpg ***');
+ response = await fetch(resourcePath + "red-green-128x128-linear-profile.jpg");
+ blob = await response.blob();
+ // This test requires a huge tolerance because browsers - at least currently - vary
+ // widely in the colorspace conversion results for this image.
+ let tolerance = 120;
+ await runImageBitmapTest(blob, 1.0, internalFormat, pixelFormat, pixelType, gl, tiu, wtu, false, tolerance);
+ finishTest();
+ }
+
+ return init;
+}
diff --git a/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-2d-with-image-bitmap-from-canvas.js b/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-2d-with-image-bitmap-from-canvas.js
new file mode 100644
index 0000000000..08ee96c0a1
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-2d-with-image-bitmap-from-canvas.js
@@ -0,0 +1,74 @@
+/*
+Copyright (c) 2019 The Khronos Group Inc.
+Use of this source code is governed by an MIT-style license that can be
+found in the LICENSE.txt file.
+*/
+
+function generateTest(internalFormat, pixelFormat, pixelType, prologue, resourcePath, defaultContextVersion) {
+ var wtu = WebGLTestUtils;
+ var tiu = TexImageUtils;
+ var gl = null;
+ var successfullyParsed = false;
+
+ function init()
+ {
+ description('Verify texImage2D and texSubImage2D code paths taking ImageBitmap created from an HTMLCanvasElement (' + internalFormat + '/' + pixelFormat + '/' + pixelType + ')');
+
+ if(!window.createImageBitmap || !window.ImageBitmap) {
+ finishTest();
+ return;
+ }
+
+ // Set the default context version while still allowing the webglVersion URL query string to override it.
+ wtu.setDefault3DContextVersion(defaultContextVersion);
+ gl = wtu.create3DContext("example");
+
+ if (!prologue(gl)) {
+ finishTest();
+ return;
+ }
+
+ gl.clearColor(0,0,0,1);
+ gl.clearDepth(1);
+
+ var testCanvas = document.createElement('canvas');
+ var ctx = testCanvas.getContext("2d");
+ setCanvasToMin(ctx);
+ runImageBitmapTest(testCanvas, 0.5, internalFormat, pixelFormat, pixelType, gl, tiu, wtu, false)
+ .then(() => {
+ setCanvasTo257x257(ctx);
+ return runImageBitmapTest(testCanvas, 0.5, internalFormat, pixelFormat, pixelType, gl, tiu, wtu, false);
+ }).then(() => {
+ finishTest();
+ });
+ }
+
+ function setCanvasToRedGreen(ctx) {
+ var width = ctx.canvas.width;
+ var halfWidth = Math.floor(width / 2);
+ var height = ctx.canvas.height;
+ var halfHeight = Math.floor(height / 2);
+ ctx.fillStyle = "rgba(255, 0, 0, 1)";
+ ctx.fillRect(0, 0, halfWidth, halfHeight);
+ ctx.fillStyle = "rgba(255, 0, 0, 0.5)";
+ ctx.fillRect(halfWidth, 0, halfWidth, halfHeight);
+ ctx.fillStyle = "rgba(0, 255, 0, 1)";
+ ctx.fillRect(0, halfHeight, halfWidth, halfHeight);
+ ctx.fillStyle = "rgba(0, 255, 0, 0.5)";
+ ctx.fillRect(halfWidth, halfHeight, halfWidth, halfHeight);
+ }
+
+ function setCanvasToMin(ctx) {
+ ctx.canvas.width = 2;
+ ctx.canvas.height = 2;
+ setCanvasToRedGreen(ctx);
+ }
+
+ function setCanvasTo257x257(ctx) {
+ ctx.canvas.width = 257;
+ ctx.canvas.height = 257;
+ setCanvasToRedGreen(ctx);
+ }
+
+ return init;
+}
diff --git a/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-2d-with-image-bitmap-from-image-bitmap.js b/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-2d-with-image-bitmap-from-image-bitmap.js
new file mode 100644
index 0000000000..09821d8b3f
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-2d-with-image-bitmap-from-image-bitmap.js
@@ -0,0 +1,56 @@
+/*
+Copyright (c) 2019 The Khronos Group Inc.
+Use of this source code is governed by an MIT-style license that can be
+found in the LICENSE.txt file.
+*/
+
+function generateTest(internalFormat, pixelFormat, pixelType, prologue, resourcePath, defaultContextVersion) {
+ var wtu = WebGLTestUtils;
+ var tiu = TexImageUtils;
+ var gl = null;
+ var successfullyParsed = false;
+
+ function init()
+ {
+ description('Verify texImage2D and texSubImage2D code paths taking ImageBitmap created from an ImageBitmap (' + internalFormat + '/' + pixelFormat + '/' + pixelType + ')');
+
+ if(!window.createImageBitmap || !window.ImageBitmap) {
+ finishTest();
+ return;
+ }
+
+ // Set the default context version while still allowing the webglVersion URL query string to override it.
+ wtu.setDefault3DContextVersion(defaultContextVersion);
+ gl = wtu.create3DContext("example");
+
+ if (!prologue(gl)) {
+ finishTest();
+ return;
+ }
+
+ gl.clearColor(0,0,0,1);
+ gl.clearDepth(1);
+ gl.disable(gl.BLEND);
+
+ var imageData = new ImageData(new Uint8ClampedArray(
+ [255, 0, 0, 255,
+ 255, 0, 0, 0,
+ 0, 255, 0, 255,
+ 0, 255, 0, 0]),
+ 2, 2);
+
+ createImageBitmap(imageData, {imageOrientation: "none", premultiplyAlpha: "none"})
+ .catch( () => {
+ testPassed("createImageBitmap with options may be rejected if it is not supported. Retrying without options.");
+ return createImageBitmap(imageData);
+ }).then( bitmap => {
+ return runImageBitmapTest(bitmap, 0, internalFormat, pixelFormat, pixelType, gl, tiu, wtu, false);
+ }, () => {
+ testFailed("createImageBitmap(imageData) should succeed.");
+ }).then(() => {
+ finishTest();
+ });
+ }
+
+ return init;
+}
diff --git a/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-2d-with-image-bitmap-from-image-data.js b/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-2d-with-image-bitmap-from-image-data.js
new file mode 100644
index 0000000000..dd24721fe4
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-2d-with-image-bitmap-from-image-data.js
@@ -0,0 +1,49 @@
+/*
+Copyright (c) 2019 The Khronos Group Inc.
+Use of this source code is governed by an MIT-style license that can be
+found in the LICENSE.txt file.
+*/
+
+function generateTest(internalFormat, pixelFormat, pixelType, prologue, resourcePath, defaultContextVersion) {
+ var wtu = WebGLTestUtils;
+ var tiu = TexImageUtils;
+ var gl = null;
+ var successfullyParsed = false;
+
+ function init()
+ {
+ description('Verify texImage2D and texSubImage2D code paths taking ImageBitmap created from ImageData (' + internalFormat + '/' + pixelFormat + '/' + pixelType + ')');
+
+ if(!window.createImageBitmap || !window.ImageBitmap) {
+ finishTest();
+ return;
+ }
+
+ // Set the default context version while still allowing the webglVersion URL query string to override it.
+ wtu.setDefault3DContextVersion(defaultContextVersion);
+ gl = wtu.create3DContext("example");
+
+ if (!prologue(gl)) {
+ finishTest();
+ return;
+ }
+
+ gl.clearColor(0,0,0,1);
+ gl.clearDepth(1);
+ gl.disable(gl.BLEND);
+
+ var imageData = new ImageData(new Uint8ClampedArray(
+ [255, 0, 0, 255,
+ 255, 0, 0, 0,
+ 0, 255, 0, 255,
+ 0, 255, 0, 0]),
+ 2, 2);
+
+ runImageBitmapTest(imageData, 0, internalFormat, pixelFormat, pixelType, gl, tiu, wtu, false)
+ .then(() => {
+ finishTest();
+ });
+ }
+
+ return init;
+}
diff --git a/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-2d-with-image-bitmap-from-image.js b/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-2d-with-image-bitmap-from-image.js
new file mode 100644
index 0000000000..1e4b18129e
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-2d-with-image-bitmap-from-image.js
@@ -0,0 +1,46 @@
+/*
+Copyright (c) 2019 The Khronos Group Inc.
+Use of this source code is governed by an MIT-style license that can be
+found in the LICENSE.txt file.
+*/
+
+function generateTest(internalFormat, pixelFormat, pixelType, prologue, resourcePath, defaultContextVersion) {
+ var wtu = WebGLTestUtils;
+ var tiu = TexImageUtils;
+ var gl = null;
+ var successfullyParsed = false;
+
+ function init()
+ {
+ description('Verify texImage2D and texSubImage2D code paths taking ImageBitmap created from an HTMLImageElement (' + internalFormat + '/' + pixelFormat + '/' + pixelType + ')');
+
+ if(!window.createImageBitmap || !window.ImageBitmap) {
+ finishTest();
+ return;
+ }
+
+ // Set the default context version while still allowing the webglVersion URL query string to override it.
+ wtu.setDefault3DContextVersion(defaultContextVersion);
+ gl = wtu.create3DContext("example");
+
+ if (!prologue(gl)) {
+ finishTest();
+ return;
+ }
+
+ gl.clearColor(0,0,0,1);
+ gl.clearDepth(1);
+
+ var image = new Image();
+ image.onload = function() {
+ bufferedLogToConsole("Source image has been loaded");
+ runImageBitmapTest(image, 0.5, internalFormat, pixelFormat, pixelType, gl, tiu, wtu, false)
+ .then(() => {
+ finishTest();
+ });
+ }
+ image.src = resourcePath + "red-green-semi-transparent.png";
+ }
+
+ return init;
+}
diff --git a/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-2d-with-image-bitmap-from-video.js b/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-2d-with-image-bitmap-from-video.js
new file mode 100644
index 0000000000..14cf4628be
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-2d-with-image-bitmap-from-video.js
@@ -0,0 +1,83 @@
+/*
+Copyright (c) 2019 The Khronos Group Inc.
+Use of this source code is governed by an MIT-style license that can be
+found in the LICENSE.txt file.
+*/
+
+function generateTest(internalFormat, pixelFormat, pixelType, prologue, resourcePath, defaultContextVersion) {
+ var wtu = WebGLTestUtils;
+ var tiu = TexImageUtils;
+ var gl = null;
+ var successfullyParsed = false;
+
+ var videos = [
+ { src: resourcePath + "red-green.mp4" , type: 'video/mp4; codecs="avc1.42E01E, mp4a.40.2"', },
+ { src: resourcePath + "red-green.webmvp8.webm" , type: 'video/webm; codecs="vp8, vorbis"', },
+ { src: resourcePath + "red-green.bt601.vp9.webm", type: 'video/webm; codecs="vp9"', },
+ { src: resourcePath + "red-green.theora.ogv" , type: 'video/ogg; codecs="theora, vorbis"', },
+ ];
+
+ function init()
+ {
+ description('Verify texImage2D and texSubImage2D code paths taking ImageBitmap created from an HTMLVideoElement (' + internalFormat + '/' + pixelFormat + '/' + pixelType + ')');
+
+ if(!window.createImageBitmap || !window.ImageBitmap) {
+ finishTest();
+ return;
+ }
+
+ // Set the default context version while still allowing the webglVersion URL query string to override it.
+ wtu.setDefault3DContextVersion(defaultContextVersion);
+ gl = wtu.create3DContext("example");
+
+ if (!prologue(gl)) {
+ finishTest();
+ return;
+ }
+
+ gl.clearColor(0,0,0,1);
+ gl.clearDepth(1);
+
+ var videoNdx = 0;
+ var video;
+ function runNextVideo() {
+ if (video) {
+ video.pause();
+ }
+
+ if (videoNdx == videos.length) {
+ finishTest();
+ return;
+ }
+
+ var info = videos[videoNdx++];
+ debug("");
+ debug("testing: " + info.type);
+ video = document.createElement("video");
+ video.muted = true;
+ var canPlay = true;
+ if (!video.canPlayType) {
+ testFailed("video.canPlayType required method missing");
+ runNextVideo();
+ return;
+ }
+
+ if(!video.canPlayType(info.type).replace(/no/, '')) {
+ debug(info.type + " unsupported");
+ runNextVideo();
+ return;
+ };
+
+ document.body.appendChild(video);
+ video.type = info.type;
+ video.src = info.src;
+ wtu.startPlayingAndWaitForVideo(video, async function() {
+ await runImageBitmapTest(video, 1, internalFormat, pixelFormat, pixelType, gl, tiu, wtu, false);
+ runNextVideo();
+ });
+ }
+ runNextVideo();
+ }
+
+ return init;
+}
diff --git a/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-2d-with-image-data.js b/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-2d-with-image-data.js
new file mode 100644
index 0000000000..8486b0b659
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-2d-with-image-data.js
@@ -0,0 +1,240 @@
+/*
+Copyright (c) 2019 The Khronos Group Inc.
+Use of this source code is governed by an MIT-style license that can be
+found in the LICENSE.txt file.
+*/
+
+function generateTest(internalFormat, pixelFormat, pixelType, prologue, resourcePath, defaultContextVersion) {
+ var wtu = WebGLTestUtils;
+ var tiu = TexImageUtils;
+ var gl = null;
+ var successfullyParsed = false;
+ var imageData = null;
+ var blackColor = [0, 0, 0];
+ var redColor = [255, 0, 0];
+ var greenColor = [0, 255, 0];
+
+ function init()
+ {
+ description('Verify texImage2D and texSubImage2D code paths taking ImageData (' + internalFormat + '/' + pixelFormat + '/' + pixelType + ')');
+
+ // Set the default context version while still allowing the webglVersion URL query string to override it.
+ wtu.setDefault3DContextVersion(defaultContextVersion);
+ gl = wtu.create3DContext("example");
+
+ if (!prologue(gl)) {
+ finishTest();
+ return;
+ }
+
+ switch (gl[pixelFormat]) {
+ case gl.RED:
+ case gl.RED_INTEGER:
+ greenColor = [0, 0, 0];
+ break;
+ case gl.LUMINANCE:
+ case gl.LUMINANCE_ALPHA:
+ redColor = [255, 255, 255];
+ greenColor = [0, 0, 0];
+ break;
+ case gl.ALPHA:
+ redColor = [0, 0, 0];
+ greenColor = [0, 0, 0];
+ break;
+ default:
+ break;
+ }
+
+ gl.clearColor(0,0,0,1);
+ gl.clearDepth(1);
+ gl.disable(gl.BLEND);
+
+ var canvas2d = document.getElementById("texcanvas");
+ var context2d = canvas2d.getContext("2d");
+ imageData = context2d.createImageData(2, 2);
+ var data = imageData.data;
+ data[0] = 255;
+ data[1] = 0;
+ data[2] = 0;
+ data[3] = 255;
+ data[4] = 255;
+ data[5] = 0;
+ data[6] = 0;
+ data[7] = 0;
+ data[8] = 0;
+ data[9] = 255;
+ data[10] = 0;
+ data[11] = 255;
+ data[12] = 0;
+ data[13] = 255;
+ data[14] = 0;
+ data[15] = 0;
+
+ runTest();
+ }
+
+ function runOneIteration(useTexSubImage2D, flipY, premultiplyAlpha,
+ sourceSubRectangle, expected,
+ bindingTarget, program)
+ {
+ sourceSubRectangleString = '';
+ if (sourceSubRectangle) {
+ sourceSubRectangleString = ', sourceSubRectangle=' + sourceSubRectangle;
+ }
+ debug('');
+ debug('Testing ' + (useTexSubImage2D ? 'texSubImage2D' : 'texImage2D') +
+ ' with flipY=' + flipY + ' and premultiplyAlpha=' + premultiplyAlpha +
+ ', bindingTarget=' + (bindingTarget == gl.TEXTURE_2D ? 'TEXTURE_2D' : 'TEXTURE_CUBE_MAP') +
+ sourceSubRectangleString);
+
+ var loc;
+ if (bindingTarget == gl.TEXTURE_CUBE_MAP) {
+ loc = gl.getUniformLocation(program, "face");
+ }
+
+ gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
+ // Enable writes to the RGBA channels
+ gl.colorMask(1, 1, 1, 0);
+ var texture = gl.createTexture();
+ // Bind the texture to texture unit 0
+ gl.bindTexture(bindingTarget, texture);
+ // Set up texture parameters
+ gl.texParameteri(bindingTarget, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
+ gl.texParameteri(bindingTarget, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
+ // Set up pixel store parameters
+ gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, flipY);
+ gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, premultiplyAlpha);
+ var targets = [gl.TEXTURE_2D];
+ if (bindingTarget == gl.TEXTURE_CUBE_MAP) {
+ targets = [gl.TEXTURE_CUBE_MAP_POSITIVE_X,
+ gl.TEXTURE_CUBE_MAP_NEGATIVE_X,
+ gl.TEXTURE_CUBE_MAP_POSITIVE_Y,
+ gl.TEXTURE_CUBE_MAP_NEGATIVE_Y,
+ gl.TEXTURE_CUBE_MAP_POSITIVE_Z,
+ gl.TEXTURE_CUBE_MAP_NEGATIVE_Z];
+ }
+ // Handle the source sub-rectangle if specified (WebGL 2.0 only)
+ if (sourceSubRectangle) {
+ gl.pixelStorei(gl.UNPACK_SKIP_PIXELS, sourceSubRectangle[0]);
+ gl.pixelStorei(gl.UNPACK_SKIP_ROWS, sourceSubRectangle[1]);
+ }
+ // Upload the image into the texture
+ for (var tt = 0; tt < targets.length; ++tt) {
+ if (sourceSubRectangle) {
+ if (useTexSubImage2D) {
+ // Initialize the texture to black first
+ gl.texImage2D(targets[tt], 0, gl[internalFormat],
+ sourceSubRectangle[2], sourceSubRectangle[3], 0,
+ gl[pixelFormat], gl[pixelType], null);
+ gl.texSubImage2D(targets[tt], 0, 0, 0,
+ sourceSubRectangle[2], sourceSubRectangle[3],
+ gl[pixelFormat], gl[pixelType], imageData);
+ } else {
+ gl.texImage2D(targets[tt], 0, gl[internalFormat],
+ sourceSubRectangle[2], sourceSubRectangle[3], 0,
+ gl[pixelFormat], gl[pixelType], imageData);
+ }
+ } else {
+ if (useTexSubImage2D) {
+ // Initialize the texture to black first
+ gl.texImage2D(targets[tt], 0, gl[internalFormat], imageData.width, imageData.height, 0,
+ gl[pixelFormat], gl[pixelType], null);
+ gl.texSubImage2D(targets[tt], 0, 0, 0, gl[pixelFormat], gl[pixelType], imageData);
+ } else {
+ gl.texImage2D(targets[tt], 0, gl[internalFormat], gl[pixelFormat], gl[pixelType], imageData);
+ }
+ }
+ }
+
+ if (sourceSubRectangle) {
+ gl.pixelStorei(gl.UNPACK_SKIP_PIXELS, 0);
+ gl.pixelStorei(gl.UNPACK_SKIP_ROWS, 0);
+ }
+
+ var width = gl.canvas.width;
+ var halfWidth = Math.floor(width / 2);
+ var height = gl.canvas.height;
+ var halfHeight = Math.floor(height / 2);
+
+ var top = 0;
+ var bottom = height - halfHeight;
+ var left = 0;
+ var right = width - halfWidth;
+
+ var tl, tr, bl, br;
+ if (expected.length == 1) {
+ tl = tr = bl = br = expected[0];
+ } else {
+ tl = expected[0];
+ tr = expected[1];
+ bl = expected[2];
+ br = expected[3];
+ }
+
+ for (var tt = 0; tt < targets.length; ++tt) {
+ if (bindingTarget == gl.TEXTURE_CUBE_MAP) {
+ gl.uniform1i(loc, targets[tt]);
+ }
+ // Draw the triangles
+ wtu.clearAndDrawUnitQuad(gl, [0, 0, 0, 255]);
+
+ // Check the top pixel and bottom pixel and make sure they have
+ // the right color.
+ wtu.checkCanvasRect(gl, left, top, halfWidth, halfHeight, tl, "shouldBe " + tl);
+ wtu.checkCanvasRect(gl, right, top, halfWidth, halfHeight, tr, "shouldBe " + tr);
+ wtu.checkCanvasRect(gl, left, bottom, halfWidth, halfHeight, bl, "shouldBe " + bl);
+ wtu.checkCanvasRect(gl, right, bottom, halfWidth, halfHeight, br, "shouldBe " + br);
+ }
+ }
+
+ function runTest()
+ {
+ var program = tiu.setupTexturedQuad(gl, internalFormat);
+ runTestOnBindingTarget(gl.TEXTURE_2D, program);
+ program = tiu.setupTexturedQuadWithCubeMap(gl, internalFormat);
+ runTestOnBindingTarget(gl.TEXTURE_CUBE_MAP, program);
+
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors");
+ finishTest();
+ }
+
+ function runTestOnBindingTarget(bindingTarget, program) {
+ var k = blackColor;
+ var r = redColor;
+ var g = greenColor;
+ var cases = [
+ { expected: [r, r, g, g], flipY: false, premultiplyAlpha: false, sub: false },
+ { expected: [r, r, g, g], flipY: false, premultiplyAlpha: false, sub: true },
+ { expected: [r, k, g, k], flipY: false, premultiplyAlpha: true, sub: false },
+ { expected: [r, k, g, k], flipY: false, premultiplyAlpha: true, sub: true },
+ { expected: [g, g, r, r], flipY: true, premultiplyAlpha: false, sub: false },
+ { expected: [g, g, r, r], flipY: true, premultiplyAlpha: false, sub: true },
+ { expected: [g, k, r, k], flipY: true, premultiplyAlpha: true, sub: false },
+ { expected: [g, k, r, k], flipY: true, premultiplyAlpha: true, sub: true },
+ ];
+
+ if (wtu.getDefault3DContextVersion() > 1) {
+ var morecases = [];
+ // Make 2 copies of the original case: top left and bottom right 1x1 rectangles
+ for (var i = 0; i < cases.length; i++) {
+ for (var subX = 0; subX <= 1; subX++) {
+ var subY = subX == 0 ? 1 : 0;
+ // shallow-copy cases[i] into newcase
+ var newcase = Object.assign({}, cases[i]);
+ newcase.expected = [cases[i].expected[subY * 2 + subX]];
+ newcase.sourceSubRectangle = [subX, subY, 1, 1];
+ morecases.push(newcase);
+ }
+ }
+ cases = cases.concat(morecases);
+ }
+
+ for (var i in cases) {
+ runOneIteration(cases[i].sub, cases[i].flipY, cases[i].premultiplyAlpha,
+ cases[i].sourceSubRectangle, cases[i].expected,
+ bindingTarget, program);
+ }
+ }
+
+ return init;
+}
diff --git a/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-2d-with-image.js b/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-2d-with-image.js
new file mode 100644
index 0000000000..f3802ba777
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-2d-with-image.js
@@ -0,0 +1,257 @@
+/*
+Copyright (c) 2019 The Khronos Group Inc.
+Use of this source code is governed by an MIT-style license that can be
+found in the LICENSE.txt file.
+*/
+
+function generateTest(internalFormat, pixelFormat, pixelType, prologue, resourcePath, defaultContextVersion) {
+ var wtu = WebGLTestUtils;
+ var tiu = TexImageUtils;
+ var gl = null;
+ var successfullyParsed = false;
+ var imgCanvas;
+ var redColor = [255, 0, 0];
+ var greenColor = [0, 255, 0];
+
+ function init()
+ {
+ description('Verify texImage2D and texSubImage2D code paths taking image elements (' + internalFormat + '/' + pixelFormat + '/' + pixelType + ')');
+
+ // Set the default context version while still allowing the webglVersion URL query string to override it.
+ wtu.setDefault3DContextVersion(defaultContextVersion);
+ gl = wtu.create3DContext("example");
+
+ if (!prologue(gl)) {
+ finishTest();
+ return;
+ }
+
+ switch (gl[pixelFormat]) {
+ case gl.RED:
+ case gl.RED_INTEGER:
+ greenColor = [0, 0, 0];
+ break;
+
+ case gl.LUMINANCE:
+ case gl.LUMINANCE_ALPHA:
+ redColor = [255, 255, 255];
+ greenColor = [0, 0, 0];
+ break;
+
+ case gl.ALPHA:
+ redColor = [0, 0, 0];
+ greenColor = [0, 0, 0];
+ break;
+
+ default:
+ break;
+ }
+
+ gl.clearColor(0,0,0,1);
+ gl.clearDepth(1);
+
+ wtu.loadTexture(gl, resourcePath + "red-green.png", runTest);
+ }
+
+ function runOneIteration(image, useTexSubImage2D, flipY, topColor, bottomColor,
+ sourceSubRectangle, bindingTarget, program)
+ {
+ sourceSubRectangleString = '';
+ if (sourceSubRectangle) {
+ sourceSubRectangleString = ' sourceSubRectangle=' + sourceSubRectangle;
+ }
+ debug('Testing ' + (useTexSubImage2D ? 'texSubImage2D' : 'texImage2D') +
+ ' with ' + image.width + 'x' + image.height + ' flipY=' + flipY + ' bindingTarget=' +
+ (bindingTarget == gl.TEXTURE_2D ? 'TEXTURE_2D' : 'TEXTURE_CUBE_MAP') +
+ sourceSubRectangleString);
+ gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
+ // Disable any writes to the alpha channel
+ gl.colorMask(1, 1, 1, 0);
+ var texture = gl.createTexture();
+ // Bind the texture to texture unit 0
+ gl.bindTexture(bindingTarget, texture);
+ // Set up texture parameters
+ gl.texParameteri(bindingTarget, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
+ gl.texParameteri(bindingTarget, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
+ // Set up pixel store parameters
+ gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, flipY);
+ gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, false);
+ wtu.failIfGLError(gl, 'gl.pixelStorei(gl.UNPACK_COLORSPACE_CONVERSION_WEBGL, gl.NONE);');
+ var targets = [gl.TEXTURE_2D];
+ if (bindingTarget == gl.TEXTURE_CUBE_MAP) {
+ targets = [gl.TEXTURE_CUBE_MAP_POSITIVE_X,
+ gl.TEXTURE_CUBE_MAP_NEGATIVE_X,
+ gl.TEXTURE_CUBE_MAP_POSITIVE_Y,
+ gl.TEXTURE_CUBE_MAP_NEGATIVE_Y,
+ gl.TEXTURE_CUBE_MAP_POSITIVE_Z,
+ gl.TEXTURE_CUBE_MAP_NEGATIVE_Z];
+ }
+ // Handle the source sub-rectangle if specified (WebGL 2.0 only)
+ if (sourceSubRectangle) {
+ gl.pixelStorei(gl.UNPACK_SKIP_PIXELS, sourceSubRectangle[0]);
+ gl.pixelStorei(gl.UNPACK_SKIP_ROWS, sourceSubRectangle[1]);
+ }
+ // Upload the image into the texture
+ for (var tt = 0; tt < targets.length; ++tt) {
+ if (sourceSubRectangle) {
+ if (useTexSubImage2D) {
+ // Initialize the texture to black first
+ gl.texImage2D(targets[tt], 0, gl[internalFormat],
+ sourceSubRectangle[2], sourceSubRectangle[3], 0,
+ gl[pixelFormat], gl[pixelType], null);
+ gl.texSubImage2D(targets[tt], 0, 0, 0,
+ sourceSubRectangle[2], sourceSubRectangle[3],
+ gl[pixelFormat], gl[pixelType], image);
+ } else {
+ gl.texImage2D(targets[tt], 0, gl[internalFormat],
+ sourceSubRectangle[2], sourceSubRectangle[3], 0,
+ gl[pixelFormat], gl[pixelType], image);
+ }
+ } else {
+ if (useTexSubImage2D) {
+ // Initialize the texture to black first
+ gl.texImage2D(targets[tt], 0, gl[internalFormat], image.width, image.height, 0,
+ gl[pixelFormat], gl[pixelType], null);
+ gl.texSubImage2D(targets[tt], 0, 0, 0, gl[pixelFormat], gl[pixelType], image);
+ } else {
+ gl.texImage2D(targets[tt], 0, gl[internalFormat], gl[pixelFormat], gl[pixelType], image);
+ }
+ }
+ }
+
+ if (sourceSubRectangle) {
+ gl.pixelStorei(gl.UNPACK_SKIP_PIXELS, 0);
+ gl.pixelStorei(gl.UNPACK_SKIP_ROWS, 0);
+ }
+
+ var loc;
+ if (bindingTarget == gl.TEXTURE_CUBE_MAP) {
+ loc = gl.getUniformLocation(program, "face");
+ }
+
+ for (var tt = 0; tt < targets.length; ++tt) {
+ if (bindingTarget == gl.TEXTURE_CUBE_MAP) {
+ gl.uniform1i(loc, targets[tt]);
+ }
+
+ // Draw the triangles
+ wtu.clearAndDrawUnitQuad(gl, [0, 0, 0, 255]);
+ // Check a few pixels near the top and bottom and make sure they have
+ // the right color.
+ debug("Checking lower left corner");
+ wtu.checkCanvasRect(gl, 4, 4, 2, 2, bottomColor,
+ "shouldBe " + bottomColor);
+ debug("Checking upper left corner");
+ wtu.checkCanvasRect(gl, 4, gl.canvas.height - 8, 2, 2, topColor,
+ "shouldBe " + topColor);
+ }
+ }
+
+ function runTestOnImage(image) {
+ var cases = [
+ { sub: false, flipY: true, topColor: redColor, bottomColor: greenColor },
+ { sub: false, flipY: false, topColor: greenColor, bottomColor: redColor },
+ { sub: true, flipY: true, topColor: redColor, bottomColor: greenColor },
+ { sub: true, flipY: false, topColor: greenColor, bottomColor: redColor },
+ ];
+
+
+ if (wtu.getDefault3DContextVersion() > 1) {
+ cases = cases.concat([
+ { sub: false, flipY: false, topColor: redColor, bottomColor: redColor,
+ sourceSubRectangle: [0, 0, 1, 1] },
+ { sub: false, flipY: true, topColor: greenColor, bottomColor: greenColor,
+ sourceSubRectangle: [0, 0, 1, 1] },
+ { sub: false, flipY: false, topColor: greenColor, bottomColor: greenColor,
+ sourceSubRectangle: [0, 1, 1, 1] },
+ { sub: false, flipY: true, topColor: redColor, bottomColor: redColor,
+ sourceSubRectangle: [0, 1, 1, 1] },
+ { sub: true, flipY: false, topColor: redColor, bottomColor: redColor,
+ sourceSubRectangle: [0, 0, 1, 1] },
+ { sub: true, flipY: true, topColor: greenColor, bottomColor: greenColor,
+ sourceSubRectangle: [0, 0, 1, 1] },
+ { sub: true, flipY: false, topColor: greenColor, bottomColor: greenColor,
+ sourceSubRectangle: [0, 1, 1, 1] },
+ { sub: true, flipY: true, topColor: redColor, bottomColor: redColor,
+ sourceSubRectangle: [0, 1, 1, 1] },
+ ]);
+ }
+
+ var program = tiu.setupTexturedQuad(gl, internalFormat);
+ for (var i in cases) {
+ runOneIteration(image, cases[i].sub, cases[i].flipY,
+ cases[i].topColor, cases[i].bottomColor,
+ cases[i].sourceSubRectangle,
+ gl.TEXTURE_2D, program);
+ }
+ // cube map texture must be square.
+ if (image.width != image.height)
+ return;
+ // Skip sub-rectangle tests for cube map textures for the moment.
+ program = tiu.setupTexturedQuadWithCubeMap(gl, internalFormat);
+ for (var i in cases) {
+ if (!cases[i].sourceSubRectangle) {
+ runOneIteration(image, cases[i].sub, cases[i].flipY,
+ cases[i].topColor, cases[i].bottomColor,
+ undefined,
+ gl.TEXTURE_CUBE_MAP, program);
+ }
+ }
+ }
+
+ function runTest(image)
+ {
+ runTestOnImage(image);
+
+ imgCanvas = document.createElement("canvas");
+ imgCanvas.width = 2;
+ imgCanvas.height = 2;
+ var imgCtx = imgCanvas.getContext("2d");
+ var imgData = imgCtx.createImageData(2, 2);
+ imgData.data[0] = redColor[0];
+ imgData.data[1] = redColor[1];
+ imgData.data[2] = redColor[2];
+ imgData.data[3] = 255;
+ imgData.data[4] = redColor[0];
+ imgData.data[5] = redColor[1];
+ imgData.data[6] = redColor[2];
+ imgData.data[7] = 255;
+ imgData.data[8] = greenColor[0];
+ imgData.data[9] = greenColor[1];
+ imgData.data[10] = greenColor[2];
+ imgData.data[11] = 255;
+ imgData.data[12] = greenColor[0];
+ imgData.data[13] = greenColor[1];
+ imgData.data[14] = greenColor[2];
+ imgData.data[15] = 255;
+ imgCtx.putImageData(imgData, 0, 0);
+
+ // apparently Image is different than <img>.
+ var newImage = new Image();
+ newImage.onload = function() {
+ runTest2(newImage);
+ };
+ newImage.onerror = function() {
+ testFailed("Creating image from canvas failed. Image src: " + this.src);
+ finishTest();
+ };
+ newImage.src = imgCanvas.toDataURL();
+ }
+
+ function runTest2(image) {
+ runTestOnImage(image);
+
+ wtu.makeImageFromCanvas(imgCanvas, function() {
+ runTest3(this);
+ });
+ }
+
+ function runTest3(image) {
+ runTestOnImage(image);
+
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors");
+ finishTest();
+ }
+
+ return init;
+}
diff --git a/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-2d-with-svg-image.js b/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-2d-with-svg-image.js
new file mode 100644
index 0000000000..5cc6a8283e
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-2d-with-svg-image.js
@@ -0,0 +1,140 @@
+/*
+Copyright (c) 2019 The Khronos Group Inc.
+Use of this source code is governed by an MIT-style license that can be
+found in the LICENSE.txt file.
+*/
+
+function generateTest(internalFormat, pixelFormat, pixelType, prologue, resourcePath, defaultContextVersion) {
+ var wtu = WebGLTestUtils;
+ var tiu = TexImageUtils;
+ var gl = null;
+ var successfullyParsed = false;
+ var imgCanvas;
+ var redColor = [255, 0, 0];
+ var greenColor = [0, 255, 0];
+
+ function init()
+ {
+ description('Verify texImage2D and texSubImage2D code paths taking SVG image elements (' + internalFormat + '/' + pixelFormat + '/' + pixelType + ')');
+
+ // Set the default context version while still allowing the webglVersion URL query string to override it.
+ wtu.setDefault3DContextVersion(defaultContextVersion);
+ gl = wtu.create3DContext("example");
+
+ if (!prologue(gl)) {
+ finishTest();
+ return;
+ }
+
+ switch (gl[pixelFormat]) {
+ case gl.RED:
+ case gl.RED_INTEGER:
+ greenColor = [0, 0, 0];
+ break;
+ case gl.LUMINANCE:
+ case gl.LUMINANCE_ALPHA:
+ redColor = [255, 255, 255];
+ greenColor = [0, 0, 0];
+ break;
+ case gl.ALPHA:
+ redColor = [0, 0, 0];
+ greenColor = [0, 0, 0];
+ break;
+ default:
+ break;
+ }
+
+ gl.clearColor(0,0,0,1);
+ gl.clearDepth(1);
+
+ wtu.loadTexture(gl, resourcePath + "red-green.svg", runTest);
+ }
+
+ function runOneIteration(image, useTexSubImage2D, flipY, topColor, bottomColor, bindingTarget, program)
+ {
+ debug('Testing ' + (useTexSubImage2D ? 'texSubImage2D' : 'texImage2D') +
+ ' with flipY=' + flipY + ' bindingTarget=' +
+ (bindingTarget == gl.TEXTURE_2D ? 'TEXTURE_2D' : 'TEXTURE_CUBE_MAP'));
+ gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
+ // Disable any writes to the alpha channel
+ gl.colorMask(1, 1, 1, 0);
+ var texture = gl.createTexture();
+ // Bind the texture to texture unit 0
+ gl.bindTexture(bindingTarget, texture);
+ // Set up texture parameters
+ gl.texParameteri(bindingTarget, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
+ gl.texParameteri(bindingTarget, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
+ // Set up pixel store parameters
+ gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, flipY);
+ gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, false);
+ wtu.failIfGLError(gl, 'gl.pixelStorei(gl.UNPACK_COLORSPACE_CONVERSION_WEBGL, gl.NONE);');
+ var targets = [gl.TEXTURE_2D];
+ if (bindingTarget == gl.TEXTURE_CUBE_MAP) {
+ targets = [gl.TEXTURE_CUBE_MAP_POSITIVE_X,
+ gl.TEXTURE_CUBE_MAP_NEGATIVE_X,
+ gl.TEXTURE_CUBE_MAP_POSITIVE_Y,
+ gl.TEXTURE_CUBE_MAP_NEGATIVE_Y,
+ gl.TEXTURE_CUBE_MAP_POSITIVE_Z,
+ gl.TEXTURE_CUBE_MAP_NEGATIVE_Z];
+ }
+ // Upload the image into the texture
+ for (var tt = 0; tt < targets.length; ++tt) {
+ if (useTexSubImage2D) {
+ // Initialize the texture to black first
+ gl.texImage2D(targets[tt], 0, gl[internalFormat], image.width, image.height, 0,
+ gl[pixelFormat], gl[pixelType], null);
+ gl.texSubImage2D(targets[tt], 0, 0, 0, gl[pixelFormat], gl[pixelType], image);
+ } else {
+ gl.texImage2D(targets[tt], 0, gl[internalFormat], gl[pixelFormat], gl[pixelType], image);
+ }
+ }
+
+ var loc;
+ if (bindingTarget == gl.TEXTURE_CUBE_MAP) {
+ loc = gl.getUniformLocation(program, "face");
+ }
+
+ for (var tt = 0; tt < targets.length; ++tt) {
+ if (bindingTarget == gl.TEXTURE_CUBE_MAP) {
+ gl.uniform1i(loc, targets[tt]);
+ }
+ // Draw the triangles
+ wtu.clearAndDrawUnitQuad(gl, [0, 0, 0, 255]);
+ // Check a few pixels near the top and bottom and make sure they have
+ // the right color.
+ debug("Checking lower left corner");
+ wtu.checkCanvasRect(gl, 4, 4, 2, 2, bottomColor,
+ "shouldBe " + bottomColor);
+ debug("Checking upper left corner");
+ wtu.checkCanvasRect(gl, 4, gl.canvas.height - 8, 2, 2, topColor,
+ "shouldBe " + topColor);
+ }
+ }
+
+ function runTest(image)
+ {
+ var program = tiu.setupTexturedQuad(gl, internalFormat);
+ runTestOnBindingTarget(image, gl.TEXTURE_2D, program);
+ program = tiu.setupTexturedQuadWithCubeMap(gl, internalFormat);
+ runTestOnBindingTarget(image, gl.TEXTURE_CUBE_MAP, program);
+
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors");
+ finishTest();
+ }
+
+ function runTestOnBindingTarget(image, bindingTarget, program) {
+ var cases = [
+ { sub: false, flipY: true, topColor: redColor, bottomColor: greenColor },
+ { sub: false, flipY: false, topColor: greenColor, bottomColor: redColor },
+ { sub: true, flipY: true, topColor: redColor, bottomColor: greenColor },
+ { sub: true, flipY: false, topColor: greenColor, bottomColor: redColor },
+ ];
+ for (var i in cases) {
+ runOneIteration(image, cases[i].sub, cases[i].flipY,
+ cases[i].topColor, cases[i].bottomColor,
+ bindingTarget, program);
+ }
+ }
+
+ return init;
+}
diff --git a/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-2d-with-video.js b/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-2d-with-video.js
new file mode 100644
index 0000000000..6e8bcf96e9
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-2d-with-video.js
@@ -0,0 +1,291 @@
+/*
+Copyright (c) 2019 The Khronos Group Inc.
+Use of this source code is governed by an MIT-style license that can be
+found in the LICENSE.txt file.
+*/
+
+// This block needs to be outside the onload handler in order for this
+// test to run reliably in WebKit's test harness (at least the
+// Chromium port). https://bugs.webkit.org/show_bug.cgi?id=87448
+initTestingHarness();
+
+var old = debug;
+var debug = function(msg) {
+ bufferedLogToConsole(msg);
+ old(msg);
+};
+
+function generateTest(internalFormat, pixelFormat, pixelType, prologue, resourcePath, defaultContextVersion) {
+ var wtu = WebGLTestUtils;
+ var tiu = TexImageUtils;
+ var gl = null;
+ var successfullyParsed = false;
+
+ // Test each format separately because many browsers implement each
+ // differently. Some might be GPU accelerated, some might not. Etc...
+ var videos = [
+ { src: resourcePath + "red-green.mp4" , type: 'video/mp4; codecs="avc1.42E01E, mp4a.40.2"', },
+ { src: resourcePath + "red-green.webmvp8.webm" , type: 'video/webm; codecs="vp8, vorbis"', },
+ { src: resourcePath + "red-green.bt601.vp9.webm", type: 'video/webm; codecs="vp9"', },
+ { src: resourcePath + "red-green.theora.ogv" , type: 'video/ogg; codecs="theora, vorbis"', },
+ ];
+
+ function init()
+ {
+ description('Verify texImage2D and texSubImage2D code paths taking video elements (' + internalFormat + '/' + pixelFormat + '/' + pixelType + ')');
+
+ // Set the default context version while still allowing the webglVersion URL query string to override it.
+ wtu.setDefault3DContextVersion(defaultContextVersion);
+ gl = wtu.create3DContext("example");
+
+ if (!prologue(gl)) {
+ finishTest();
+ return;
+ }
+
+ gl.clearColor(0,0,0,1);
+ gl.clearDepth(1);
+
+ runTest();
+ }
+
+ function runOneIteration(videoElement, unpackColorSpace, useTexSubImage2D, flipY, topColorName, bottomColorName, sourceSubRectangle, program, bindingTarget)
+ {
+ sourceSubRectangleString = '';
+ if (sourceSubRectangle) {
+ sourceSubRectangleString = ' sourceSubRectangle=' + sourceSubRectangle;
+ }
+ unpackColorSpaceString = '';
+ if (unpackColorSpace) {
+ unpackColorSpaceString = ' unpackColorSpace=' + unpackColorSpace;
+ }
+ debug('Testing ' + (useTexSubImage2D ? 'texSubImage2D' : 'texImage2D') +
+ ' with flipY=' + flipY + ' bindingTarget=' +
+ (bindingTarget == gl.TEXTURE_2D ? 'TEXTURE_2D' : 'TEXTURE_CUBE_MAP') +
+ sourceSubRectangleString + unpackColorSpaceString);
+ gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
+ // Disable any writes to the alpha channel
+ gl.colorMask(1, 1, 1, 0);
+ var texture = gl.createTexture();
+ // Bind the texture to texture unit 0
+ gl.bindTexture(bindingTarget, texture);
+ // Set up texture parameters
+ gl.texParameteri(bindingTarget, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
+ gl.texParameteri(bindingTarget, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
+ gl.texParameteri(bindingTarget, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
+ gl.texParameteri(bindingTarget, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
+ // Set up pixel store parameters
+ gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, flipY);
+ gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, false);
+ var targets = [gl.TEXTURE_2D];
+ if (bindingTarget == gl.TEXTURE_CUBE_MAP) {
+ targets = [gl.TEXTURE_CUBE_MAP_POSITIVE_X,
+ gl.TEXTURE_CUBE_MAP_NEGATIVE_X,
+ gl.TEXTURE_CUBE_MAP_POSITIVE_Y,
+ gl.TEXTURE_CUBE_MAP_NEGATIVE_Y,
+ gl.TEXTURE_CUBE_MAP_POSITIVE_Z,
+ gl.TEXTURE_CUBE_MAP_NEGATIVE_Z];
+ }
+ // Handle target color space.
+ if (unpackColorSpace) {
+ gl.unpackColorSpace = unpackColorSpace;
+ }
+ // Handle the source sub-rectangle if specified (WebGL 2.0 only)
+ if (sourceSubRectangle) {
+ gl.pixelStorei(gl.UNPACK_SKIP_PIXELS, sourceSubRectangle[0]);
+ gl.pixelStorei(gl.UNPACK_SKIP_ROWS, sourceSubRectangle[1]);
+ }
+ // Upload the videoElement into the texture
+ for (var tt = 0; tt < targets.length; ++tt) {
+ if (sourceSubRectangle) {
+ // Initialize the texture to black first
+ if (useTexSubImage2D) {
+ // Skip sub-rectangle tests for cube map textures for the moment.
+ if (bindingTarget == gl.TEXTURE_CUBE_MAP) {
+ continue;
+ }
+ gl.texImage2D(targets[tt], 0, gl[internalFormat],
+ sourceSubRectangle[2], sourceSubRectangle[3], 0,
+ gl[pixelFormat], gl[pixelType], null);
+ gl.texSubImage2D(targets[tt], 0, 0, 0,
+ sourceSubRectangle[2], sourceSubRectangle[3],
+ gl[pixelFormat], gl[pixelType], videoElement);
+ } else {
+ gl.texImage2D(targets[tt], 0, gl[internalFormat],
+ sourceSubRectangle[2], sourceSubRectangle[3], 0,
+ gl[pixelFormat], gl[pixelType], videoElement);
+ }
+ } else {
+ // Initialize the texture to black first
+ if (useTexSubImage2D) {
+ var width = videoElement.videoWidth;
+ var height = videoElement.videoHeight;
+ if (bindingTarget == gl.TEXTURE_CUBE_MAP) {
+ // cube map texture must be square.
+ width = Math.max(width, height);
+ height = width;
+ }
+ gl.texImage2D(targets[tt], 0, gl[internalFormat],
+ width, height, 0,
+ gl[pixelFormat], gl[pixelType], null);
+ gl.texSubImage2D(targets[tt], 0, 0, 0, gl[pixelFormat], gl[pixelType], videoElement);
+ } else {
+ gl.texImage2D(targets[tt], 0, gl[internalFormat], gl[pixelFormat], gl[pixelType], videoElement);
+ }
+ }
+ }
+
+ if (sourceSubRectangle) {
+ gl.pixelStorei(gl.UNPACK_SKIP_PIXELS, 0);
+ gl.pixelStorei(gl.UNPACK_SKIP_ROWS, 0);
+ }
+
+ var c = document.createElement("canvas");
+ c.width = 16;
+ c.height = 16;
+ c.style.border = "1px solid black";
+ var ctx = c.getContext("2d");
+ ctx.drawImage(videoElement, 0, 0, 16, 16);
+ document.body.appendChild(c);
+
+ var loc;
+ if (bindingTarget == gl.TEXTURE_CUBE_MAP) {
+ loc = gl.getUniformLocation(program, "face");
+ }
+
+ // Compute the test colors. This test only tests RGB (not A).
+ const topColor = wtu.colorAsSampledWithInternalFormat(
+ wtu.namedColorInColorSpace(topColorName, unpackColorSpace),
+ internalFormat).slice(0, 3);
+ const bottomColor = wtu.colorAsSampledWithInternalFormat(
+ wtu.namedColorInColorSpace(bottomColorName, unpackColorSpace),
+ internalFormat).slice(0, 3);
+ for (var tt = 0; tt < targets.length; ++tt) {
+ if (bindingTarget == gl.TEXTURE_CUBE_MAP) {
+ gl.uniform1i(loc, targets[tt]);
+ }
+ // Draw the triangles
+ wtu.clearAndDrawUnitQuad(gl, [0, 0, 0, 255]);
+ // Check a few pixels near the top and bottom and make sure they have
+ // the right color.
+ const tolerance = Math.max(6, tiu.tolerance(internalFormat, pixelFormat, pixelType));
+ debug("Checking lower left corner");
+ wtu.checkCanvasRect(gl, 4, 4, 2, 2, bottomColor,
+ "shouldBe " + bottomColor, tolerance);
+ debug("Checking upper left corner");
+ wtu.checkCanvasRect(gl, 4, gl.canvas.height - 8, 2, 2, topColor,
+ "shouldBe " + topColor, tolerance);
+ }
+ }
+
+ function runTest(videoElement)
+ {
+ var cases = [
+ { sub: false, flipY: true, topColor: 'Red', bottomColor: 'Green' },
+ { sub: false, flipY: false, topColor: 'Green', bottomColor: 'Red' },
+ { sub: true, flipY: true, topColor: 'Red', bottomColor: 'Green' },
+ { sub: true, flipY: false, topColor: 'Green', bottomColor: 'Red' },
+ ];
+
+ if (wtu.getDefault3DContextVersion() > 1) {
+ cases = cases.concat([
+ { sub: false, flipY: false, topColor: 'Red', bottomColor: 'Red',
+ sourceSubRectangle: [20, 16, 40, 32] },
+ { sub: false, flipY: true, topColor: 'Green', bottomColor: 'Green',
+ sourceSubRectangle: [20, 16, 40, 32] },
+ { sub: false, flipY: false, topColor: 'Green', bottomColor: 'Green',
+ sourceSubRectangle: [20, 80, 40, 32] },
+ { sub: false, flipY: true, topColor: 'Red', bottomColor: 'Red',
+ sourceSubRectangle: [20, 80, 40, 32] },
+ { sub: true, flipY: false, topColor: 'Red', bottomColor: 'Red',
+ sourceSubRectangle: [20, 16, 40, 32] },
+ { sub: true, flipY: true, topColor: 'Green', bottomColor: 'Green',
+ sourceSubRectangle: [20, 16, 40, 32] },
+ { sub: true, flipY: false, topColor: 'Green', bottomColor: 'Green',
+ sourceSubRectangle: [20, 80, 40, 32] },
+ { sub: true, flipY: true, topColor: 'Red', bottomColor: 'Red',
+ sourceSubRectangle: [20, 80, 40, 32] },
+ ]);
+ }
+
+ cases = tiu.crossProductTestCasesWithUnpackColorSpaces(
+ cases, tiu.unpackColorSpacesToTest(gl));
+
+ function runTexImageTest(bindingTarget) {
+ var program;
+ if (bindingTarget == gl.TEXTURE_2D) {
+ program = tiu.setupTexturedQuad(gl, internalFormat);
+ } else {
+ program = tiu.setupTexturedQuadWithCubeMap(gl, internalFormat);
+ }
+
+ return new Promise(function(resolve, reject) {
+ var videoNdx = 0;
+ var video;
+ function runNextVideo() {
+ if (video) {
+ video.pause();
+ }
+
+ if (videoNdx == videos.length) {
+ resolve("SUCCESS");
+ return;
+ }
+
+ var info = videos[videoNdx++];
+ debug("");
+ debug("testing: " + info.type);
+ video = document.createElement("video");
+ video.muted = true;
+ var canPlay = true;
+ if (!video.canPlayType) {
+ testFailed("video.canPlayType required method missing");
+ runNextVideo();
+ return;
+ }
+
+ if(!video.canPlayType(info.type).replace(/no/, '')) {
+ debug(info.type + " unsupported");
+ runNextVideo();
+ return;
+ };
+
+ document.body.appendChild(video);
+ video.type = info.type;
+ video.src = info.src;
+ wtu.startPlayingAndWaitForVideo(video, runTest);
+ }
+ function runTest() {
+ for (var i in cases) {
+ if (bindingTarget == gl.TEXTURE_CUBE_MAP) {
+ // Cube map texture must be square but video is not square.
+ if (!cases[i].sub) {
+ break;
+ }
+ // Skip sub-rectangle tests for cube map textures for the moment.
+ if (cases[i].sourceSubRectangle) {
+ break;
+ }
+ }
+ runOneIteration(video, cases[i].unpackColorSpace, cases[i].sub, cases[i].flipY,
+ cases[i].topColor,
+ cases[i].bottomColor,
+ cases[i].sourceSubRectangle,
+ program, bindingTarget);
+ }
+ runNextVideo();
+ }
+ runNextVideo();
+ });
+ }
+
+ runTexImageTest(gl.TEXTURE_2D).then(function(val) {
+ runTexImageTest(gl.TEXTURE_CUBE_MAP).then(function(val) {
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors");
+ finishTest();
+ });
+ });
+ }
+
+ return init;
+}
diff --git a/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-2d-with-webgl-canvas.js b/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-2d-with-webgl-canvas.js
new file mode 100644
index 0000000000..acb8768051
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-2d-with-webgl-canvas.js
@@ -0,0 +1,298 @@
+/*
+Copyright (c) 2019 The Khronos Group Inc.
+Use of this source code is governed by an MIT-style license that can be
+found in the LICENSE.txt file.
+*/
+
+"use strict";
+
+function generateTest(internalFormat, pixelFormat, pixelType, prologue, resourcePath, defaultContextVersion) {
+ var wtu = WebGLTestUtils;
+ var tiu = TexImageUtils;
+ var gl = null;
+ var successfullyParsed = false;
+ var redColor = [255, 0, 0, 255];
+ var greenColor = [0, 255, 0, 255];
+ var repeatCount;
+
+ function shouldRepeatTestForTextureFormat(internalFormat, pixelFormat, pixelType)
+ {
+ // There were bugs in early WebGL 1.0 implementations when repeatedly uploading canvas
+ // elements into textures. In response, this test was changed into a regression test by
+ // repeating all of the cases multiple times. Unfortunately, this means that adding a new
+ // case above significantly increases the run time of the test suite. The problem is made
+ // even worse by the addition of many more texture formats in WebGL 2.0.
+ //
+ // Doing repeated runs with just a couple of WebGL 1.0's supported texture formats acts as a
+ // sufficient regression test for the old bugs. For this reason the test has been changed to
+ // only repeat for those texture formats.
+ return ((internalFormat == 'RGBA' && pixelFormat == 'RGBA' && pixelType == 'UNSIGNED_BYTE') ||
+ (internalFormat == 'RGB' && pixelFormat == 'RGB' && pixelType == 'UNSIGNED_BYTE'));
+ }
+
+ async function init()
+ {
+ description('Verify texImage2D and texSubImage2D code paths taking webgl canvas elements (' + internalFormat + '/' + pixelFormat + '/' + pixelType + ')');
+
+ // Set the default context version while still allowing the webglVersion URL query string to override it.
+ wtu.setDefault3DContextVersion(defaultContextVersion);
+ gl = wtu.create3DContext("example");
+
+ if (!prologue(gl)) {
+ return;
+ }
+
+ repeatCount = (shouldRepeatTestForTextureFormat(internalFormat, pixelFormat, pixelType) ? 4 : 1);
+
+ switch (gl[pixelFormat]) {
+ case gl.RED:
+ case gl.RED_INTEGER:
+ greenColor = [0, 0, 0];
+ break;
+ case gl.LUMINANCE:
+ case gl.LUMINANCE_ALPHA:
+ redColor = [255, 255, 255];
+ greenColor = [0, 0, 0];
+ break;
+ case gl.ALPHA:
+ redColor = [0, 0, 0];
+ greenColor = [0, 0, 0];
+ break;
+ default:
+ break;
+ }
+
+ gl.clearColor(0,0,0,1);
+ gl.clearDepth(1);
+
+ await runTest();
+ }
+
+ function setCanvasToRedGreen(ctx, hasAlpha) {
+ var width = ctx.canvas.width;
+ var height = ctx.canvas.height;
+ var halfHeight = Math.floor(height / 2);
+
+ ctx.viewport(0, 0, width, height);
+
+ ctx.enable(ctx.SCISSOR_TEST);
+ ctx.scissor(0, 0, width, halfHeight);
+ if (hasAlpha) {
+ ctx.clearColor(1.0, 0, 0, 1.0);
+ } else {
+ // The WebGL implementation is responsible for making all
+ // alpha values appear as though they were 1.0.
+ ctx.clearColor(1.0, 0, 0, 0.0);
+ }
+ ctx.clear(ctx.COLOR_BUFFER_BIT);
+ ctx.scissor(0, halfHeight, width, height - halfHeight);
+ if (hasAlpha) {
+ ctx.clearColor(0.0, 1.0, 0, 1.0);
+ } else {
+ // The WebGL implementation is responsible for making all
+ // alpha values appear as though they were 1.0.
+ ctx.clearColor(0.0, 1.0, 0, 0.0);
+ }
+ ctx.clear(ctx.COLOR_BUFFER_BIT);
+ ctx.disable(ctx.SCISSOR_TEST);
+ }
+
+ function setCanvasTo257x257(ctx, bindingTarget, hasAlpha) {
+ ctx.canvas.width = 257;
+ ctx.canvas.height = 257;
+ setCanvasToRedGreen(ctx, hasAlpha);
+ }
+
+ function setCanvasToMin(ctx, bindingTarget, hasAlpha) {
+ if (bindingTarget == gl.TEXTURE_CUBE_MAP) {
+ // cube map texture must be square.
+ ctx.canvas.width = 2;
+ } else {
+ ctx.canvas.width = 1;
+ }
+ ctx.canvas.height = 2;
+ setCanvasToRedGreen(ctx, hasAlpha);
+ }
+
+ function runOneIteration(canvas, useTexSubImage2D, alpha, flipY, program, bindingTarget, opt_texture)
+ {
+ var objType = 'canvas';
+ if (canvas.transferToImageBitmap)
+ objType = 'OffscreenCanvas';
+ else if (canvas.parentNode)
+ objType = 'canvas attached to DOM';
+ debug('Testing ' + (useTexSubImage2D ? 'texSubImage2D' : 'texImage2D') + ' with alpha=' +
+ alpha + ' flipY=' + flipY + ' source object: ' + objType +
+ ' bindingTarget=' + (bindingTarget == gl.TEXTURE_2D ? 'TEXTURE_2D' : 'TEXTURE_CUBE_MAP') +
+ ' canvas size: ' + canvas.width + 'x' + canvas.height + ' with red-green');
+
+ gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
+ if (!opt_texture) {
+ var texture = gl.createTexture();
+ // Bind the texture to texture unit 0
+ gl.bindTexture(bindingTarget, texture);
+ // Set up texture parameters
+ gl.texParameteri(bindingTarget, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
+ gl.texParameteri(bindingTarget, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
+ gl.texParameteri(bindingTarget, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
+ gl.texParameteri(bindingTarget, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
+ } else {
+ var texture = opt_texture;
+ }
+ // Set up pixel store parameters
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors before pixelStorei setup");
+ gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, flipY);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors after setting UNPACK_FLIP_Y_WEBGL");
+ gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, false);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors after setting UNPACK_PREMULTIPLY_ALPHA_WEBGL");
+ gl.pixelStorei(gl.UNPACK_COLORSPACE_CONVERSION_WEBGL, gl.NONE);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors after setting UNPACK_COLORSPACE_CONVERSION_WEBGL");
+ var targets = [gl.TEXTURE_2D];
+ if (bindingTarget == gl.TEXTURE_CUBE_MAP) {
+ targets = [gl.TEXTURE_CUBE_MAP_POSITIVE_X,
+ gl.TEXTURE_CUBE_MAP_NEGATIVE_X,
+ gl.TEXTURE_CUBE_MAP_POSITIVE_Y,
+ gl.TEXTURE_CUBE_MAP_NEGATIVE_Y,
+ gl.TEXTURE_CUBE_MAP_POSITIVE_Z,
+ gl.TEXTURE_CUBE_MAP_NEGATIVE_Z];
+ }
+ // Upload the image into the texture
+ for (var tt = 0; tt < targets.length; ++tt) {
+ // Initialize the texture to black first
+ if (useTexSubImage2D) {
+ gl.texImage2D(targets[tt], 0, gl[internalFormat], canvas.width, canvas.height, 0,
+ gl[pixelFormat], gl[pixelType], null);
+ gl.texSubImage2D(targets[tt], 0, 0, 0, gl[pixelFormat], gl[pixelType], canvas);
+ } else {
+ gl.texImage2D(targets[tt], 0, gl[internalFormat], gl[pixelFormat], gl[pixelType], canvas);
+ }
+ }
+
+ var width = gl.canvas.width;
+ var height = gl.canvas.height;
+ var halfWidth = Math.floor(width / 2);
+ var halfHeight = Math.floor(height / 2);
+ var top = flipY ? (height - halfHeight) : 0;
+ var bottom = flipY ? 0 : (height - halfHeight);
+
+ var loc;
+ if (bindingTarget == gl.TEXTURE_CUBE_MAP) {
+ loc = gl.getUniformLocation(program, "face");
+ }
+
+ for (var tt = 0; tt < targets.length; ++tt) {
+ if (bindingTarget == gl.TEXTURE_CUBE_MAP) {
+ gl.uniform1i(loc, targets[tt]);
+ }
+ // Draw the triangles
+ wtu.clearAndDrawUnitQuad(gl, [0, 255, 0, 255]);
+
+ // Check the top and bottom halves and make sure they have the right color.
+ debug("Checking " + (flipY ? "top" : "bottom"));
+ wtu.checkCanvasRect(gl, 0, bottom, width, halfHeight, redColor,
+ "shouldBe " + redColor);
+ debug("Checking " + (flipY ? "bottom" : "top"));
+ wtu.checkCanvasRect(gl, 0, top, width, halfHeight, greenColor,
+ "shouldBe " + greenColor);
+ }
+
+ if (false) {
+ var ma = wtu.makeImageFromCanvas(canvas);
+ document.getElementById("console").appendChild(ma);
+
+ var m = wtu.makeImageFromCanvas(gl.canvas);
+ document.getElementById("console").appendChild(m);
+ document.getElementById("console").appendChild(document.createElement("hr"));
+ }
+
+ return texture;
+ }
+
+ async function runTest()
+ {
+ for (let alpha of [ true, false ]) {
+ let ctx = wtu.create3DContext(null, { alpha:alpha });
+ let canvas = ctx.canvas;
+ // Note: We use preserveDrawingBuffer:true to prevent canvas
+ // visibility from interfering with the tests.
+ let visibleCtx = wtu.create3DContext(null, { preserveDrawingBuffer:true, alpha:alpha });
+ if (!visibleCtx) {
+ testFailed("context does not exist");
+ return;
+ }
+ let visibleCanvas = visibleCtx.canvas;
+ let descriptionNode = document.getElementById("description");
+ document.body.insertBefore(visibleCanvas, descriptionNode);
+
+ let cases = [
+ { sub: false, flipY: true, ctx: ctx, init: setCanvasToMin },
+ { sub: false, flipY: false, ctx: ctx },
+ { sub: true, flipY: true, ctx: ctx },
+ { sub: true, flipY: false, ctx: ctx },
+ { sub: false, flipY: true, ctx: ctx, init: setCanvasTo257x257 },
+ { sub: false, flipY: false, ctx: ctx },
+ { sub: true, flipY: true, ctx: ctx },
+ { sub: true, flipY: false, ctx: ctx },
+ { sub: false, flipY: true, ctx: visibleCtx, init: setCanvasToMin },
+ { sub: false, flipY: false, ctx: visibleCtx },
+ { sub: true, flipY: true, ctx: visibleCtx },
+ { sub: true, flipY: false, ctx: visibleCtx },
+ ];
+
+ if (window.OffscreenCanvas) {
+ let offscreen = new OffscreenCanvas(1, 1);
+ let offscreenCtx = wtu.create3DContext(offscreen, { alpha:alpha });
+ cases = cases.concat([
+ { sub: false, flipY: true, ctx: offscreenCtx, init: setCanvasToMin },
+ { sub: false, flipY: false, ctx: offscreenCtx },
+ { sub: true, flipY: true, ctx: offscreenCtx },
+ { sub: true, flipY: false, ctx: offscreenCtx },
+ ]);
+ }
+
+ async function runTexImageTest(bindingTarget) {
+ let program;
+ if (bindingTarget == gl.TEXTURE_2D) {
+ program = tiu.setupTexturedQuad(gl, internalFormat);
+ } else {
+ program = tiu.setupTexturedQuadWithCubeMap(gl, internalFormat);
+ }
+
+ let count = repeatCount;
+ let caseNdx = 0;
+ let texture = undefined;
+ while (true) {
+ let c = cases[caseNdx];
+ if (c.init) {
+ c.init(c.ctx, bindingTarget, alpha);
+ }
+ texture = runOneIteration(c.ctx.canvas, c.sub, alpha, c.flipY, program, bindingTarget, texture);
+ // for the first 2 iterations always make a new texture.
+ if (count < 2) {
+ gl.deleteTexture(texture);
+ texture = undefined;
+ }
+ ++caseNdx;
+ if (caseNdx == cases.length) {
+ caseNdx = 0;
+ --count;
+ if (!count)
+ return;
+ }
+ await wtu.dispatchPromise(function() {});
+ }
+ }
+
+ await runTexImageTest(gl.TEXTURE_2D);
+ await runTexImageTest(gl.TEXTURE_CUBE_MAP);
+ }
+
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors");
+ }
+
+ return function() {
+ init().then(function(val) {
+ finishTest();
+ });
+ };
+}
diff --git a/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-3d-with-canvas-sub-rectangle.js b/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-3d-with-canvas-sub-rectangle.js
new file mode 100644
index 0000000000..85f763a0de
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-3d-with-canvas-sub-rectangle.js
@@ -0,0 +1,287 @@
+/*
+Copyright (c) 2019 The Khronos Group Inc.
+Use of this source code is governed by an MIT-style license that can be
+found in the LICENSE.txt file.
+*/
+
+function generateTest(internalFormat, pixelFormat, pixelType, prologue, resourcePath, defaultContextVersion) {
+ var wtu = WebGLTestUtils;
+ var tiu = TexImageUtils;
+ var gl = null;
+ var successfullyParsed = false;
+ var realRedColor = [255, 0, 0];
+ var realGreenColor = [0, 255, 0];
+ var realBlueColor = [0, 0, 255];
+ var realCyanColor = [0, 255, 255];
+ var redColor = [255, 0, 0];
+ var greenColor = [0, 255, 0];
+ var blueColor = [0, 0, 255];
+ var cyanColor = [0, 255, 255];
+
+ function init()
+ {
+ description('Verify texImage3D and texSubImage3D code paths taking a sub-rectangle of a canvas (' + internalFormat + '/' + pixelFormat + '/' + pixelType + ')');
+
+ // Set the default context version while still allowing the webglVersion URL query string to override it.
+ wtu.setDefault3DContextVersion(defaultContextVersion);
+ gl = wtu.create3DContext("example");
+
+ if (!prologue(gl)) {
+ finishTest();
+ return;
+ }
+
+ switch (gl[pixelFormat]) {
+ case gl.RED:
+ case gl.RED_INTEGER:
+ greenColor = [0, 0, 0];
+ blueColor = [0, 0, 0];
+ cyanColor = [0, 0, 0];
+ break;
+
+ case gl.RG:
+ case gl.RG_INTEGER:
+ blueColor = [0, 0, 0];
+ cyanColor = [0, 255, 0];
+ break;
+
+ default:
+ break;
+ }
+
+ gl.clearColor(0,0,0,1);
+ gl.clearDepth(1);
+
+ var canvas2d = document.createElement('canvas');
+ runTest(canvas2d, setupSourceCanvas2D, '2D-rendered canvas');
+
+ var canvasWebGL = document.createElement('canvas');
+ runTest(canvasWebGL, setupSourceCanvasWebGL, 'WebGL-rendered canvas');
+
+ finishTest();
+ }
+
+ function uploadCanvasToTexture(canvas, useTexSubImage3D, flipY, bindingTarget,
+ depth, sourceSubRectangle, unpackImageHeight)
+ {
+ gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
+ // Disable any writes to the alpha channel
+ gl.colorMask(1, 1, 1, 0);
+ var texture = gl.createTexture();
+ // Bind the texture to texture unit 0
+ gl.bindTexture(bindingTarget, texture);
+ // Set up texture parameters
+ gl.texParameteri(bindingTarget, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
+ gl.texParameteri(bindingTarget, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
+ gl.texParameteri(bindingTarget, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
+ gl.texParameteri(bindingTarget, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
+ gl.texParameteri(bindingTarget, gl.TEXTURE_WRAP_R, gl.CLAMP_TO_EDGE);
+ // Set up pixel store parameters
+ gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, flipY);
+ gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, false);
+ gl.pixelStorei(gl.UNPACK_COLORSPACE_CONVERSION_WEBGL, gl.NONE);
+ var uploadWidth = canvas.width;
+ var uploadHeight = canvas.height;
+ if (sourceSubRectangle) {
+ gl.pixelStorei(gl.UNPACK_SKIP_PIXELS, sourceSubRectangle[0]);
+ gl.pixelStorei(gl.UNPACK_SKIP_ROWS, sourceSubRectangle[1]);
+ uploadWidth = sourceSubRectangle[2];
+ uploadHeight = sourceSubRectangle[3];
+ }
+ if (unpackImageHeight) {
+ gl.pixelStorei(gl.UNPACK_IMAGE_HEIGHT, unpackImageHeight);
+ }
+ // Upload the image into the texture
+ if (useTexSubImage3D) {
+ // Initialize the texture to black first
+ gl.texImage3D(bindingTarget, 0, gl[internalFormat], uploadWidth, uploadHeight, depth, 0,
+ gl[pixelFormat], gl[pixelType], null);
+ gl.texSubImage3D(bindingTarget, 0, 0, 0, 0, uploadWidth, uploadHeight, depth,
+ gl[pixelFormat], gl[pixelType], canvas);
+ } else {
+ gl.texImage3D(bindingTarget, 0, gl[internalFormat], uploadWidth, uploadHeight, depth, 0,
+ gl[pixelFormat], gl[pixelType], canvas);
+ }
+ gl.pixelStorei(gl.UNPACK_SKIP_PIXELS, 0);
+ gl.pixelStorei(gl.UNPACK_SKIP_ROWS, 0);
+ gl.pixelStorei(gl.UNPACK_IMAGE_HEIGHT, 0);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors from texture upload");
+ }
+
+ function fillStyle2D(ctx, color) {
+ ctx.fillStyle = 'rgb(' + color[0] + ', ' + color[1] + ', ' + color[2] + ')';
+ }
+
+ function setupSourceCanvas2D(canvas) {
+ var width = canvas.width;
+ var height = canvas.height;
+ var halfWidth = Math.floor(width / 2);
+ var halfHeight = Math.floor(height / 2);
+
+ var ctx = canvas.getContext('2d');
+ // Always use the same pattern for this test: four quadrants:
+ // red green
+ // blue cyan
+ // Handle odd-sized canvases
+ fillStyle2D(ctx, realRedColor);
+ ctx.fillRect(0, 0, halfWidth, halfHeight);
+ fillStyle2D(ctx, realGreenColor);
+ ctx.fillRect(halfWidth, 0, width - halfWidth, halfHeight);
+ fillStyle2D(ctx, realBlueColor);
+ ctx.fillRect(0, halfHeight, halfWidth, height - halfHeight);
+ fillStyle2D(ctx, realCyanColor);
+ ctx.fillRect(halfWidth, halfHeight, width - halfWidth, height - halfHeight);
+ }
+
+ function clearColorWebGL(ctx, color) {
+ ctx.clearColor(color[0] / 255.0, color[1] / 255.0, color[2] / 255.0, 1.0);
+ ctx.clear(ctx.COLOR_BUFFER_BIT);
+ }
+
+ function setupSourceCanvasWebGL(canvas) {
+ var width = canvas.width;
+ var height = canvas.height;
+ var halfWidth = Math.floor(width / 2);
+ var halfHeight = Math.floor(height / 2);
+
+ var ctx = canvas.getContext('webgl');
+ // Always use the same pattern for this test: four quadrants:
+ // red green
+ // blue cyan
+ // Handle odd-sized canvases
+
+ ctx.viewport(0, 0, width, height);
+ ctx.enable(ctx.SCISSOR_TEST);
+ // OpenGL origin is lower-left
+ ctx.scissor(0, 0, halfWidth, halfHeight);
+ clearColorWebGL(ctx, realBlueColor);
+ ctx.scissor(halfWidth, 0, width - halfWidth, halfHeight);
+ clearColorWebGL(ctx, realCyanColor);
+ ctx.scissor(0, halfHeight, halfWidth, height - halfHeight);
+ clearColorWebGL(ctx, realRedColor);
+ ctx.scissor(halfWidth, halfHeight, width - halfWidth, height - halfHeight);
+ clearColorWebGL(ctx, realGreenColor);
+ }
+
+ function runOneIteration(canvas, useTexSubImage3D, flipY, bindingTarget,
+ depth, sourceSubRectangle, unpackImageHeight,
+ rTextureCoord, expectedColor, program,
+ canvasSize, canvasSetupFunction, sourceDescription)
+ {
+ debug('');
+ debug('Testing ' + sourceDescription + ' with ' +
+ (useTexSubImage3D ? 'texSubImage3D' : 'texImage3D') +
+ ', flipY=' + flipY + ', bindingTarget=' +
+ (bindingTarget == gl.TEXTURE_3D ? 'TEXTURE_3D' : 'TEXTURE_2D_ARRAY') +
+ ', sourceSubRectangle=' + sourceSubRectangle +
+ ', depth=' + depth +
+ (unpackImageHeight ? ', unpackImageHeight=' + unpackImageHeight : '') +
+ ', rTextureCoord=' + rTextureCoord);
+
+ // Initialize the contents of the source canvas.
+ var width = canvasSize[0];
+ var height = canvasSize[1];
+ var halfWidth = Math.floor(width / 2);
+ var halfHeight = Math.floor(height / 2);
+ canvas.width = width;
+ canvas.height = height;
+ canvasSetupFunction(canvas);
+
+ uploadCanvasToTexture(canvas, useTexSubImage3D, flipY, bindingTarget,
+ depth, sourceSubRectangle, unpackImageHeight);
+ var rCoordLocation = gl.getUniformLocation(program, 'uRCoord');
+ if (!rCoordLocation) {
+ testFailed('Shader incorrectly set up; couldn\'t find uRCoord uniform');
+ return;
+ }
+ gl.uniform1f(rCoordLocation, rTextureCoord);
+
+ // Draw the triangles
+ wtu.clearAndDrawUnitQuad(gl, [0, 0, 0, 255]);
+ // Check the rendered canvas
+ wtu.checkCanvasRect(gl, 0, 0, canvasSize[0], canvasSize[1], expectedColor, "shouldBe " + expectedColor);
+ }
+
+ function runTest(canvas, canvasSetupFunction, sourceDescription)
+ {
+ var cases = [
+ // Small canvas cases. Expected that these won't be
+ // GPU-accelerated in most browsers' implementations.
+
+ // No UNPACK_IMAGE_HEIGHT specified.
+ { expected: redColor, flipY: false, size: [4, 4], subRect: [0, 0, 2, 2], depth: 2, rTextureCoord: 0.0 },
+ { expected: blueColor, flipY: false, size: [4, 4], subRect: [0, 0, 2, 2], depth: 2, rTextureCoord: 1.0 },
+ { expected: blueColor, flipY: true, size: [4, 4], subRect: [0, 0, 2, 2], depth: 2, rTextureCoord: 0.0 },
+ { expected: redColor, flipY: true, size: [4, 4], subRect: [0, 0, 2, 2], depth: 2, rTextureCoord: 1.0 },
+ { expected: greenColor, flipY: false, size: [4, 4], subRect: [2, 0, 2, 2], depth: 2, rTextureCoord: 0.0 },
+ { expected: cyanColor, flipY: false, size: [4, 4], subRect: [2, 0, 2, 2], depth: 2, rTextureCoord: 1.0 },
+ { expected: cyanColor, flipY: true, size: [4, 4], subRect: [2, 0, 2, 2], depth: 2, rTextureCoord: 0.0 },
+ { expected: greenColor, flipY: true, size: [4, 4], subRect: [2, 0, 2, 2], depth: 2, rTextureCoord: 1.0 },
+
+ // Use UNPACK_IMAGE_HEIGHT to skip some pixels.
+ { expected: redColor, flipY: false, size: [4, 4], subRect: [0, 0, 1, 1], depth: 2, unpackImageHeight: 2, rTextureCoord: 0.0 },
+ { expected: blueColor, flipY: false, size: [4, 4], subRect: [0, 0, 1, 1], depth: 2, unpackImageHeight: 2, rTextureCoord: 1.0 },
+ { expected: blueColor, flipY: true, size: [4, 4], subRect: [0, 0, 1, 1], depth: 2, unpackImageHeight: 2, rTextureCoord: 0.0 },
+ { expected: redColor, flipY: true, size: [4, 4], subRect: [0, 0, 1, 1], depth: 2, unpackImageHeight: 2, rTextureCoord: 1.0 },
+ { expected: greenColor, flipY: false, size: [4, 4], subRect: [2, 0, 1, 1], depth: 2, unpackImageHeight: 2, rTextureCoord: 0.0 },
+ { expected: cyanColor, flipY: false, size: [4, 4], subRect: [2, 0, 1, 1], depth: 2, unpackImageHeight: 2, rTextureCoord: 1.0 },
+ { expected: cyanColor, flipY: true, size: [4, 4], subRect: [2, 0, 1, 1], depth: 2, unpackImageHeight: 2, rTextureCoord: 0.0 },
+ { expected: greenColor, flipY: true, size: [4, 4], subRect: [2, 0, 1, 1], depth: 2, unpackImageHeight: 2, rTextureCoord: 1.0 },
+
+ // Larger canvas cases. Expected that these will be
+ // GPU-accelerated in most browsers' implementations.
+ // Changes will be gladly accepted to trigger more
+ // browsers' heuristics to accelerate these canvases.
+
+ // No UNPACK_IMAGE_HEIGHT specified.
+ { expected: redColor, flipY: false, size: [384, 384], subRect: [0, 0, 192, 192], depth: 2, rTextureCoord: 0.0 },
+ { expected: blueColor, flipY: false, size: [384, 384], subRect: [0, 0, 192, 192], depth: 2, rTextureCoord: 1.0 },
+ { expected: blueColor, flipY: true, size: [384, 384], subRect: [0, 0, 192, 192], depth: 2, rTextureCoord: 0.0 },
+ { expected: redColor, flipY: true, size: [384, 384], subRect: [0, 0, 192, 192], depth: 2, rTextureCoord: 1.0 },
+ { expected: greenColor, flipY: false, size: [384, 384], subRect: [192, 0, 192, 192], depth: 2, rTextureCoord: 0.0 },
+ { expected: cyanColor, flipY: false, size: [384, 384], subRect: [192, 0, 192, 192], depth: 2, rTextureCoord: 1.0 },
+ { expected: cyanColor, flipY: true, size: [384, 384], subRect: [192, 0, 192, 192], depth: 2, rTextureCoord: 0.0 },
+ { expected: greenColor, flipY: true, size: [384, 384], subRect: [192, 0, 192, 192], depth: 2, rTextureCoord: 1.0 },
+
+ // Use UNPACK_IMAGE_HEIGHT to skip some pixels.
+ { expected: redColor, flipY: false, size: [384, 384], subRect: [0, 0, 96, 96], depth: 2, unpackImageHeight: 192, rTextureCoord: 0.0 },
+ { expected: blueColor, flipY: false, size: [384, 384], subRect: [0, 0, 96, 96], depth: 2, unpackImageHeight: 192, rTextureCoord: 1.0 },
+ { expected: blueColor, flipY: true, size: [384, 384], subRect: [0, 0, 96, 96], depth: 2, unpackImageHeight: 192, rTextureCoord: 0.0 },
+ { expected: redColor, flipY: true, size: [384, 384], subRect: [0, 0, 96, 96], depth: 2, unpackImageHeight: 192, rTextureCoord: 1.0 },
+ { expected: greenColor, flipY: false, size: [384, 384], subRect: [192, 0, 96, 96], depth: 2, unpackImageHeight: 192, rTextureCoord: 0.0 },
+ { expected: cyanColor, flipY: false, size: [384, 384], subRect: [192, 0, 96, 96], depth: 2, unpackImageHeight: 192, rTextureCoord: 1.0 },
+ { expected: cyanColor, flipY: true, size: [384, 384], subRect: [192, 0, 96, 96], depth: 2, unpackImageHeight: 192, rTextureCoord: 0.0 },
+ { expected: greenColor, flipY: true, size: [384, 384], subRect: [192, 0, 96, 96], depth: 2, unpackImageHeight: 192, rTextureCoord: 1.0 },
+ ];
+
+ var program = tiu.setupTexturedQuadWith3D(gl, internalFormat);
+ for (var i in cases) {
+ runOneIteration(canvas, false, cases[i].flipY, gl.TEXTURE_3D,
+ cases[i].depth, cases[i].subRect,
+ cases[i].unpackImageHeight, cases[i].rTextureCoord,
+ cases[i].expected,
+ program, cases[i].size, canvasSetupFunction, sourceDescription);
+ runOneIteration(canvas, true, cases[i].flipY, gl.TEXTURE_3D,
+ cases[i].depth, cases[i].subRect,
+ cases[i].unpackImageHeight, cases[i].rTextureCoord,
+ cases[i].expected,
+ program, cases[i].size, canvasSetupFunction, sourceDescription);
+ }
+
+ program = tiu.setupTexturedQuadWith2DArray(gl, internalFormat);
+ for (var i in cases) {
+ runOneIteration(canvas, false, cases[i].flipY, gl.TEXTURE_2D_ARRAY,
+ cases[i].depth, cases[i].subRect,
+ cases[i].unpackImageHeight, cases[i].rTextureCoord,
+ cases[i].expected,
+ program, cases[i].size, canvasSetupFunction, sourceDescription);
+ runOneIteration(canvas, true, cases[i].flipY, gl.TEXTURE_2D_ARRAY,
+ cases[i].depth, cases[i].subRect,
+ cases[i].unpackImageHeight, cases[i].rTextureCoord,
+ cases[i].expected,
+ program, cases[i].size, canvasSetupFunction, sourceDescription);
+ }
+ }
+
+ return init;
+}
diff --git a/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-3d-with-canvas.js b/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-3d-with-canvas.js
new file mode 100644
index 0000000000..c41cc4e897
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-3d-with-canvas.js
@@ -0,0 +1,226 @@
+/*
+Copyright (c) 2019 The Khronos Group Inc.
+Use of this source code is governed by an MIT-style license that can be
+found in the LICENSE.txt file.
+*/
+
+function generateTest(internalFormat, pixelFormat, pixelType, prologue, resourcePath, defaultContextVersion) {
+ var wtu = WebGLTestUtils;
+ var tiu = TexImageUtils;
+ var gl = null;
+ var successfullyParsed = false;
+ var whiteColor = [255, 255, 255, 255];
+ var redColor = [255, 0, 0];
+ var greenColor = [0, 255, 0];
+
+ function init()
+ {
+ description('Verify texImage3D and texSubImage3D code paths taking canvas elements (' + internalFormat + '/' + pixelFormat + '/' + pixelType + ')');
+
+ // Set the default context version while still allowing the webglVersion URL query string to override it.
+ wtu.setDefault3DContextVersion(defaultContextVersion);
+ gl = wtu.create3DContext("example");
+
+ if (!prologue(gl)) {
+ finishTest();
+ return;
+ }
+
+ switch (gl[pixelFormat]) {
+ case gl.RED:
+ case gl.RED_INTEGER:
+ whiteColor = [255, 0, 0, 255];
+ greenColor = [0, 0, 0];
+ break;
+ case gl.RG:
+ case gl.RG_INTEGER:
+ whiteColor = [255, 255, 0, 255];
+ break;
+ default:
+ break;
+ }
+
+ gl.clearColor(0,0,0,1);
+ gl.clearDepth(1);
+
+ runTest();
+ }
+
+ function setCanvasToRedGreen(ctx) {
+ var width = ctx.canvas.width;
+ var height = ctx.canvas.height;
+ var halfHeight = Math.floor(height / 2);
+ ctx.fillStyle = "#ff0000";
+ ctx.fillRect(0, 0, width, halfHeight);
+ ctx.fillStyle = "#00ff00";
+ ctx.fillRect(0, halfHeight, width, height - halfHeight);
+ }
+
+ function drawTextInCanvas(ctx, bindingTarget) {
+ var width = ctx.canvas.width;
+ var height = ctx.canvas.height;
+ ctx.fillStyle = "#ffffff";
+ ctx.fillRect(0, 0, width, height);
+ ctx.font = '20pt Arial';
+ ctx.fillStyle = 'black';
+ ctx.textAlign = "center";
+ ctx.textBaseline = "middle";
+ ctx.fillText("1234567890", width / 2, height / 4);
+ }
+
+ function setCanvasTo257x257(ctx, bindingTarget) {
+ ctx.canvas.width = 257;
+ ctx.canvas.height = 257;
+ setCanvasToRedGreen(ctx);
+ }
+
+ function setCanvasToMin(ctx, bindingTarget) {
+ if (bindingTarget == gl.TEXTURE_CUBE_MAP) {
+ // cube map texture must be square.
+ ctx.canvas.width = 2;
+ } else {
+ ctx.canvas.width = 1;
+ }
+ ctx.canvas.height = 2;
+ setCanvasToRedGreen(ctx);
+ }
+
+ function runOneIteration(canvas, flipY, program, bindingTarget, opt_texture, opt_fontTest)
+ {
+ var objType = 'canvas';
+ if (canvas.transferToImageBitmap)
+ objType = 'OffscreenCanvas';
+ debug('Testing ' + ' with flipY=' + flipY + ' bindingTarget=' + (bindingTarget == gl.TEXTURE_3D ? 'TEXTURE_3D' : 'TEXTURE_2D_ARRAY') +
+ ' source object: ' + objType + ' canvas size: ' + canvas.width + 'x' + canvas.height + (opt_fontTest ? " with fonts" : " with red-green"));
+ gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
+ if (!opt_texture) {
+ var texture = gl.createTexture();
+ // Bind the texture to texture unit 0
+ gl.bindTexture(bindingTarget, texture);
+ // Set up texture parameters
+ gl.texParameteri(bindingTarget, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
+ gl.texParameteri(bindingTarget, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
+ gl.texParameteri(bindingTarget, gl.TEXTURE_WRAP_R, gl.CLAMP_TO_EDGE);
+ gl.texParameteri(bindingTarget, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
+ gl.texParameteri(bindingTarget, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
+ } else {
+ var texture = opt_texture;
+ }
+ // Set up pixel store parameters
+ gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, flipY);
+ gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, false);
+ wtu.failIfGLError(gl, 'gl.pixelStorei(gl.UNPACK_COLORSPACE_CONVERSION_WEBGL, gl.NONE);');
+ // Initialize the texture to black first
+ gl.texImage3D(bindingTarget, 0, gl[internalFormat], canvas.width, canvas.height, 1 /* depth */, 0,
+ gl[pixelFormat], gl[pixelType], null);
+ gl.texSubImage3D(bindingTarget, 0, 0, 0, 0, canvas.width, canvas.height, 1 /* depth */,
+ gl[pixelFormat], gl[pixelType], canvas);
+
+ var width = gl.canvas.width;
+ var height = gl.canvas.height;
+ var halfHeight = Math.floor(height / 2);
+ var top = flipY ? 0 : (height - halfHeight);
+ var bottom = flipY ? (height - halfHeight) : 0;
+
+ // Draw the triangles
+ wtu.clearAndDrawUnitQuad(gl, [0, 255, 0, 255]);
+
+ if (opt_fontTest) {
+ // check half is a solid color.
+ wtu.checkCanvasRect(
+ gl, 0, top, width, halfHeight,
+ whiteColor,
+ "should be white");
+ // check other half is not a solid color.
+ wtu.checkCanvasRectColor(
+ gl, 0, bottom, width, halfHeight,
+ whiteColor, 0,
+ function() {
+ testFailed("font missing");
+ },
+ function() {
+ testPassed("font renderered");
+ },
+ debug);
+ } else {
+ // Check the top and bottom halves and make sure they have the right color.
+ debug("Checking " + (flipY ? "top" : "bottom"));
+ wtu.checkCanvasRect(gl, 0, bottom, width, halfHeight, redColor,
+ "shouldBe " + redColor);
+ debug("Checking " + (flipY ? "bottom" : "top"));
+ wtu.checkCanvasRect(gl, 0, top, width, halfHeight, greenColor,
+ "shouldBe " + greenColor);
+ }
+
+ return texture;
+ }
+
+ function runTest(canvas)
+ {
+ var canvas = document.createElement('canvas');
+
+ var cases = [
+ { canvas: canvas, flipY: true, font: false, init: setCanvasToMin },
+ { canvas: canvas, flipY: false, font: false },
+ { canvas: canvas, flipY: true, font: false, init: setCanvasTo257x257 },
+ { canvas: canvas, flipY: false, font: false },
+ { canvas: canvas, flipY: true, font: true, init: drawTextInCanvas },
+ { canvas: canvas, flipY: false, font: true },
+ ];
+
+ if (window.OffscreenCanvas) {
+ var offscreenCanvas = new OffscreenCanvas(1, 1);
+ cases = cases.concat([
+ { canvas: offscreenCanvas, flipY: true, font: false, init: setCanvasToMin },
+ { canvas: offscreenCanvas, flipY: false, font: false },
+ ]);
+ }
+
+ function runTexImageTest(bindingTarget) {
+ var program;
+ if (bindingTarget == gl.TEXTURE_3D) {
+ program = tiu.setupTexturedQuadWith3D(gl, internalFormat);
+ } else { // TEXTURE_2D_ARRAY
+ program = tiu.setupTexturedQuadWith2DArray(gl, internalFormat);
+ }
+
+ return new Promise(function(resolve, reject) {
+ var count = 4;
+ var caseNdx = 0;
+ var texture = undefined;
+ function runNextTest() {
+ var c = cases[caseNdx];
+ if (c.init) {
+ c.init(c.canvas.getContext('2d'), bindingTarget);
+ }
+ texture = runOneIteration(c.canvas, c.flipY, program, bindingTarget, texture, c.font);
+ // for the first 2 iterations always make a new texture.
+ if (count < 2) {
+ gl.deleteTexture(texture);
+ texture = undefined;
+ }
+ ++caseNdx;
+ if (caseNdx == cases.length) {
+ caseNdx = 0;
+ --count;
+ if (!count) {
+ resolve("SUCCESS");
+ return;
+ }
+ }
+ wtu.waitForComposite(runNextTest);
+ }
+ runNextTest();
+ });
+ }
+
+ runTexImageTest(gl.TEXTURE_3D).then(function(val) {
+ runTexImageTest(gl.TEXTURE_2D_ARRAY).then(function(val) {
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors");
+ finishTest();
+ });
+ });
+ }
+
+ return init;
+}
diff --git a/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-3d-with-image-bitmap-from-blob.js b/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-3d-with-image-bitmap-from-blob.js
new file mode 100644
index 0000000000..b55bdcb143
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-3d-with-image-bitmap-from-blob.js
@@ -0,0 +1,48 @@
+/*
+Copyright (c) 2019 The Khronos Group Inc.
+Use of this source code is governed by an MIT-style license that can be
+found in the LICENSE.txt file.
+*/
+
+function generateTest(internalFormat, pixelFormat, pixelType, prologue, resourcePath, defaultContextVersion) {
+ var wtu = WebGLTestUtils;
+ var tiu = TexImageUtils;
+ var gl = null;
+ var successfullyParsed = false;
+
+ function init()
+ {
+ description('Verify texImage3D and texSubImage3D code paths taking ImageBitmap created from a Blob (' + internalFormat + '/' + pixelFormat + '/' + pixelType + ')');
+
+ if(!window.createImageBitmap || !window.ImageBitmap) {
+ finishTest();
+ return;
+ }
+
+ // Set the default context version while still allowing the webglVersion URL query string to override it.
+ wtu.setDefault3DContextVersion(defaultContextVersion);
+ gl = wtu.create3DContext("example");
+
+ if (!prologue(gl)) {
+ finishTest();
+ return;
+ }
+
+ gl.clearColor(0,0,0,1);
+ gl.clearDepth(1);
+
+ var xhr = new XMLHttpRequest();
+ xhr.open("GET", resourcePath + "red-green-semi-transparent.png");
+ xhr.responseType = 'blob';
+ xhr.onload = function() {
+ var blob = xhr.response;
+ runImageBitmapTest(blob, 0.5, internalFormat, pixelFormat, pixelType, gl, tiu, wtu, true)
+ .then(() => {
+ finishTest();
+ });
+ };
+ xhr.send();
+ }
+
+ return init;
+}
diff --git a/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-3d-with-image-bitmap-from-canvas.js b/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-3d-with-image-bitmap-from-canvas.js
new file mode 100644
index 0000000000..805298b377
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-3d-with-image-bitmap-from-canvas.js
@@ -0,0 +1,74 @@
+/*
+Copyright (c) 2019 The Khronos Group Inc.
+Use of this source code is governed by an MIT-style license that can be
+found in the LICENSE.txt file.
+*/
+
+function generateTest(internalFormat, pixelFormat, pixelType, prologue, resourcePath, defaultContextVersion) {
+ var wtu = WebGLTestUtils;
+ var tiu = TexImageUtils;
+ var gl = null;
+ var successfullyParsed = false;
+
+ function init()
+ {
+ description('Verify texImage3D and texSubImage3D code paths taking ImageBitmap created from an HTMLCanvasElement (' + internalFormat + '/' + pixelFormat + '/' + pixelType + ')');
+
+ if(!window.createImageBitmap || !window.ImageBitmap) {
+ finishTest();
+ return;
+ }
+
+ // Set the default context version while still allowing the webglVersion URL query string to override it.
+ wtu.setDefault3DContextVersion(defaultContextVersion);
+ gl = wtu.create3DContext("example");
+
+ if (!prologue(gl)) {
+ finishTest();
+ return;
+ }
+
+ gl.clearColor(0,0,0,1);
+ gl.clearDepth(1);
+
+ var testCanvas = document.createElement('canvas');
+ var ctx = testCanvas.getContext("2d");
+ setCanvasToMin(ctx);
+ runImageBitmapTest(testCanvas, 0.5, internalFormat, pixelFormat, pixelType, gl, tiu, wtu, true)
+ .then(() => {
+ setCanvasTo257x257(ctx);
+ return runImageBitmapTest(testCanvas, 0.5, internalFormat, pixelFormat, pixelType, gl, tiu, wtu, true);
+ }).then(() => {
+ finishTest();
+ });
+ }
+
+ function setCanvasToRedGreen(ctx) {
+ var width = ctx.canvas.width;
+ var halfWidth = Math.floor(width / 2);
+ var height = ctx.canvas.height;
+ var halfHeight = Math.floor(height / 2);
+ ctx.fillStyle = "rgba(255, 0, 0, 1)";
+ ctx.fillRect(0, 0, halfWidth, halfHeight);
+ ctx.fillStyle = "rgba(255, 0, 0, 0.5)";
+ ctx.fillRect(halfWidth, 0, halfWidth, halfHeight);
+ ctx.fillStyle = "rgba(0, 255, 0, 1)";
+ ctx.fillRect(0, halfHeight, halfWidth, halfHeight);
+ ctx.fillStyle = "rgba(0, 255, 0, 0.5)";
+ ctx.fillRect(halfWidth, halfHeight, halfWidth, halfHeight);
+ }
+
+ function setCanvasToMin(ctx) {
+ ctx.canvas.width = 2;
+ ctx.canvas.height = 2;
+ setCanvasToRedGreen(ctx);
+ }
+
+ function setCanvasTo257x257(ctx) {
+ ctx.canvas.width = 257;
+ ctx.canvas.height = 257;
+ setCanvasToRedGreen(ctx);
+ }
+
+ return init;
+}
diff --git a/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-3d-with-image-bitmap-from-image-bitmap.js b/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-3d-with-image-bitmap-from-image-bitmap.js
new file mode 100644
index 0000000000..44c9ffa378
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-3d-with-image-bitmap-from-image-bitmap.js
@@ -0,0 +1,56 @@
+/*
+Copyright (c) 2019 The Khronos Group Inc.
+Use of this source code is governed by an MIT-style license that can be
+found in the LICENSE.txt file.
+*/
+
+function generateTest(internalFormat, pixelFormat, pixelType, prologue, resourcePath, defaultContextVersion) {
+ var wtu = WebGLTestUtils;
+ var tiu = TexImageUtils;
+ var gl = null;
+ var successfullyParsed = false;
+
+ function init()
+ {
+ description('Verify texImage3D and texSubImage3D code paths taking ImageBitmap created from an ImageBitmap (' + internalFormat + '/' + pixelFormat + '/' + pixelType + ')');
+
+ if(!window.createImageBitmap || !window.ImageBitmap) {
+ finishTest();
+ return;
+ }
+
+ // Set the default context version while still allowing the webglVersion URL query string to override it.
+ wtu.setDefault3DContextVersion(defaultContextVersion);
+ gl = wtu.create3DContext("example");
+
+ if (!prologue(gl)) {
+ finishTest();
+ return;
+ }
+
+ gl.clearColor(0,0,0,1);
+ gl.clearDepth(1);
+ gl.disable(gl.BLEND);
+
+ var imageData = new ImageData(new Uint8ClampedArray(
+ [255, 0, 0, 255,
+ 255, 0, 0, 0,
+ 0, 255, 0, 255,
+ 0, 255, 0, 0]),
+ 2, 2);
+
+ createImageBitmap(imageData, {imageOrientation: "none", premultiplyAlpha: "none"})
+ .catch( () => {
+ testPassed("createImageBitmap with options may be rejected if it is not supported. Retrying without options.");
+ return createImageBitmap(imageData);
+ }).then( bitmap => {
+ return runImageBitmapTest(bitmap, 0, internalFormat, pixelFormat, pixelType, gl, tiu, wtu, true);
+ }, () => {
+ testFailed("createImageBitmap(imageData) should succeed.");
+ }).then(() => {
+ finishTest();
+ });
+ }
+
+ return init;
+}
diff --git a/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-3d-with-image-bitmap-from-image-data.js b/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-3d-with-image-bitmap-from-image-data.js
new file mode 100644
index 0000000000..cca0358e17
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-3d-with-image-bitmap-from-image-data.js
@@ -0,0 +1,49 @@
+/*
+Copyright (c) 2019 The Khronos Group Inc.
+Use of this source code is governed by an MIT-style license that can be
+found in the LICENSE.txt file.
+*/
+
+function generateTest(internalFormat, pixelFormat, pixelType, prologue, resourcePath, defaultContextVersion) {
+ var wtu = WebGLTestUtils;
+ var tiu = TexImageUtils;
+ var gl = null;
+ var successfullyParsed = false;
+
+ function init()
+ {
+ description('Verify texImage3D and texSubImage3D code paths taking ImageBitmap created from ImageData (' + internalFormat + '/' + pixelFormat + '/' + pixelType + ')');
+
+ if(!window.createImageBitmap || !window.ImageBitmap) {
+ finishTest();
+ return;
+ }
+
+ // Set the default context version while still allowing the webglVersion URL query string to override it.
+ wtu.setDefault3DContextVersion(defaultContextVersion);
+ gl = wtu.create3DContext("example");
+
+ if (!prologue(gl)) {
+ finishTest();
+ return;
+ }
+
+ gl.clearColor(0,0,0,1);
+ gl.clearDepth(1);
+ gl.disable(gl.BLEND);
+
+ var imageData = new ImageData(new Uint8ClampedArray(
+ [255, 0, 0, 255,
+ 255, 0, 0, 0,
+ 0, 255, 0, 255,
+ 0, 255, 0, 0]),
+ 2, 2);
+
+ runImageBitmapTest(imageData, 0, internalFormat, pixelFormat, pixelType, gl, tiu, wtu, true)
+ .then(() => {
+ finishTest();
+ });
+ }
+
+ return init;
+}
diff --git a/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-3d-with-image-bitmap-from-image.js b/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-3d-with-image-bitmap-from-image.js
new file mode 100644
index 0000000000..0f1121bbb9
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-3d-with-image-bitmap-from-image.js
@@ -0,0 +1,45 @@
+/*
+Copyright (c) 2019 The Khronos Group Inc.
+Use of this source code is governed by an MIT-style license that can be
+found in the LICENSE.txt file.
+*/
+
+function generateTest(internalFormat, pixelFormat, pixelType, prologue, resourcePath, defaultContextVersion) {
+ var wtu = WebGLTestUtils;
+ var tiu = TexImageUtils;
+ var gl = null;
+ var successfullyParsed = false;
+
+ function init()
+ {
+ description('Verify texImage3D and texSubImage3D code paths taking ImageBitmap created from an HTMLImageElement (' + internalFormat + '/' + pixelFormat + '/' + pixelType + ')');
+
+ if(!window.createImageBitmap || !window.ImageBitmap) {
+ finishTest();
+ return;
+ }
+
+ // Set the default context version while still allowing the webglVersion URL query string to override it.
+ wtu.setDefault3DContextVersion(defaultContextVersion);
+ gl = wtu.create3DContext("example");
+
+ if (!prologue(gl)) {
+ finishTest();
+ return;
+ }
+
+ gl.clearColor(0,0,0,1);
+ gl.clearDepth(1);
+
+ var image = new Image();
+ image.onload = function() {
+ runImageBitmapTest(image, 0.5, internalFormat, pixelFormat, pixelType, gl, tiu, wtu, true)
+ .then(() => {
+ finishTest();
+ });
+ }
+ image.src = resourcePath + "red-green-semi-transparent.png";
+ }
+
+ return init;
+}
diff --git a/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-3d-with-image-bitmap-from-video.js b/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-3d-with-image-bitmap-from-video.js
new file mode 100644
index 0000000000..a268f7d8d5
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-3d-with-image-bitmap-from-video.js
@@ -0,0 +1,83 @@
+/*
+Copyright (c) 2019 The Khronos Group Inc.
+Use of this source code is governed by an MIT-style license that can be
+found in the LICENSE.txt file.
+*/
+
+function generateTest(internalFormat, pixelFormat, pixelType, prologue, resourcePath, defaultContextVersion) {
+ var wtu = WebGLTestUtils;
+ var tiu = TexImageUtils;
+ var gl = null;
+ var successfullyParsed = false;
+
+ var videos = [
+ { src: resourcePath + "red-green.mp4" , type: 'video/mp4; codecs="avc1.42E01E, mp4a.40.2"', },
+ { src: resourcePath + "red-green.webmvp8.webm" , type: 'video/webm; codecs="vp8, vorbis"', },
+ { src: resourcePath + "red-green.bt601.vp9.webm", type: 'video/webm; codecs="vp9"', },
+ { src: resourcePath + "red-green.theora.ogv" , type: 'video/ogg; codecs="theora, vorbis"', },
+ ];
+
+ function init()
+ {
+ description('Verify texImage3D and texSubImage3D code paths taking ImageBitmap created from an HTMLVideoElement (' + internalFormat + '/' + pixelFormat + '/' + pixelType + ')');
+
+ if(!window.createImageBitmap || !window.ImageBitmap) {
+ finishTest();
+ return;
+ }
+
+ // Set the default context version while still allowing the webglVersion URL query string to override it.
+ wtu.setDefault3DContextVersion(defaultContextVersion);
+ gl = wtu.create3DContext("example");
+
+ if (!prologue(gl)) {
+ finishTest();
+ return;
+ }
+
+ gl.clearColor(0,0,0,1);
+ gl.clearDepth(1);
+
+ var videoNdx = 0;
+ var video;
+ function runNextVideo() {
+ if (video) {
+ video.pause();
+ }
+
+ if (videoNdx == videos.length) {
+ finishTest();
+ return;
+ }
+
+ var info = videos[videoNdx++];
+ debug("");
+ debug("testing: " + info.type);
+ video = document.createElement("video");
+ video.muted = true;
+ var canPlay = true;
+ if (!video.canPlayType) {
+ testFailed("video.canPlayType required method missing");
+ runNextVideo();
+ return;
+ }
+
+ if(!video.canPlayType(info.type).replace(/no/, '')) {
+ debug(info.type + " unsupported");
+ runNextVideo();
+ return;
+ };
+
+ document.body.appendChild(video);
+ video.type = info.type;
+ video.src = info.src;
+ wtu.startPlayingAndWaitForVideo(video, async function() {
+ await runImageBitmapTest(video, 1, internalFormat, pixelFormat, pixelType, gl, tiu, wtu, true);
+ runNextVideo();
+ });
+ }
+ runNextVideo();
+ }
+
+ return init;
+}
diff --git a/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-3d-with-image-data.js b/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-3d-with-image-data.js
new file mode 100644
index 0000000000..bedf51a96a
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-3d-with-image-data.js
@@ -0,0 +1,259 @@
+/*
+Copyright (c) 2019 The Khronos Group Inc.
+Use of this source code is governed by an MIT-style license that can be
+found in the LICENSE.txt file.
+*/
+
+function generateTest(internalFormat, pixelFormat, pixelType, prologue, resourcePath, defaultContextVersion) {
+ var wtu = WebGLTestUtils;
+ var tiu = TexImageUtils;
+ var gl = null;
+ var successfullyParsed = false;
+ var imageData = null;
+ var blackColor = [0, 0, 0];
+ var originalPixels = (function() {
+ // (red|green|blue|cyan)(opaque|transparent)
+ var ro = [255, 0, 0, 255]; var rt = [255, 0, 0, 0];
+ var go = [0, 255, 0, 255]; var gt = [0, 255, 0, 0];
+ var bo = [0, 0, 255, 255]; var bt = [0, 0, 255, 0];
+ var co = [0, 255, 255, 255]; var ct = [0, 255, 255, 0];
+ return [ro, rt, go, gt,
+ ro, rt, go, gt,
+ bo, bt, co, ct,
+ bo, bt, co, ct];
+ })();
+
+ function init()
+ {
+ description('Verify texImage3D and texSubImage3D code paths taking ImageData (' + internalFormat + '/' + pixelFormat + '/' + pixelType + ')');
+
+ // Set the default context version while still allowing the webglVersion URL query string to override it.
+ wtu.setDefault3DContextVersion(defaultContextVersion);
+ gl = wtu.create3DContext("example");
+
+ if (!prologue(gl)) {
+ finishTest();
+ return;
+ }
+
+ gl.clearColor(0,0,0,1);
+ gl.clearDepth(1);
+ gl.disable(gl.BLEND);
+
+ var canvas2d = document.getElementById("texcanvas");
+ var context2d = canvas2d.getContext("2d");
+ imageData = context2d.createImageData(4, 4);
+ var data = imageData.data;
+ for (var i = 0; i < originalPixels.length; i++) {
+ data.set(originalPixels[i], 4 * i);
+ }
+
+ runTest();
+ }
+
+ function runOneIteration(useTexSubImage3D, flipY, premultiplyAlpha, bindingTarget,
+ depth, sourceSubRectangle, rTexCoord, program)
+ {
+ var expected = simulate(flipY, premultiplyAlpha, depth, sourceSubRectangle, rTexCoord);
+ var sourceSubRectangleString = '';
+ if (sourceSubRectangle) {
+ sourceSubRectangleString = ', sourceSubRectangle=' + sourceSubRectangle;
+ sourceSubRectangleString += ', rTexCoord=' + rTexCoord;
+ }
+ debug('');
+ debug('Testing ' + (useTexSubImage3D ? 'texSubImage3D' : 'texImage3D') +
+ ' with flipY=' + flipY + ', premultiplyAlpha=' + premultiplyAlpha +
+ ', bindingTarget=' + (bindingTarget == gl.TEXTURE_3D ? 'TEXTURE_3D' : 'TEXTURE_2D_ARRAY') +
+ sourceSubRectangleString);
+ gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
+ // Enable writes to the RGBA channels
+ gl.colorMask(1, 1, 1, 0);
+ var texture = gl.createTexture();
+ // Bind the texture to texture unit 0
+ gl.bindTexture(bindingTarget, texture);
+ // Set up texture parameters
+ gl.texParameteri(bindingTarget, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
+ gl.texParameteri(bindingTarget, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
+ gl.texParameteri(bindingTarget, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
+ gl.texParameteri(bindingTarget, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
+ gl.texParameteri(bindingTarget, gl.TEXTURE_WRAP_R, gl.CLAMP_TO_EDGE);
+ // Set up pixel store parameters
+ gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, flipY);
+ gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, premultiplyAlpha);
+ gl.pixelStorei(gl.UNPACK_COLORSPACE_CONVERSION_WEBGL, gl.NONE);
+ var uploadWidth = imageData.width;
+ var uploadHeight = imageData.height;
+ if (sourceSubRectangle) {
+ gl.pixelStorei(gl.UNPACK_SKIP_PIXELS, sourceSubRectangle[0]);
+ gl.pixelStorei(gl.UNPACK_SKIP_ROWS, sourceSubRectangle[1]);
+ uploadWidth = sourceSubRectangle[2];
+ uploadHeight = sourceSubRectangle[3];
+ }
+ // Upload the image into the texture
+ if (useTexSubImage3D) {
+ // Initialize the texture to black first
+ gl.texImage3D(bindingTarget, 0, gl[internalFormat], uploadWidth, uploadHeight, depth, 0,
+ gl[pixelFormat], gl[pixelType], null);
+ gl.texSubImage3D(bindingTarget, 0, 0, 0, 0, uploadWidth, uploadHeight, depth,
+ gl[pixelFormat], gl[pixelType], imageData);
+ } else {
+ gl.texImage3D(bindingTarget, 0, gl[internalFormat], uploadWidth, uploadHeight, depth, 0,
+ gl[pixelFormat], gl[pixelType], imageData);
+ }
+ gl.pixelStorei(gl.UNPACK_SKIP_PIXELS, 0);
+ gl.pixelStorei(gl.UNPACK_SKIP_ROWS, 0);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors from texture upload");
+
+ var tl = expected[0][0];
+ var tr = expected[0][1];
+ var bl = expected[1][0];
+ var br = expected[1][1];
+
+ var rCoordLocation = gl.getUniformLocation(program, 'uRCoord');
+ if (!rCoordLocation) {
+ testFailed("Shader incorrectly set up; couldn't find uRCoord uniform");
+ return;
+ }
+ gl.uniform1f(rCoordLocation, rTexCoord);
+ // Draw the triangles
+ wtu.clearAndDrawUnitQuad(gl, [0, 0, 0, 255]);
+
+ var width = gl.canvas.width;
+ var halfWidth = Math.floor(width / 2);
+ var height = gl.canvas.height;
+ var halfHeight = Math.floor(height / 2);
+
+ var top = 0;
+ var bottom = height - halfHeight;
+ var left = 0;
+ var right = width - halfWidth;
+
+ debug("Checking pixel values");
+ debug("Expecting: " + expected);
+ var expectedH = expected.length;
+ var expectedW = expected[0].length;
+ var texelH = Math.floor(gl.canvas.height / expectedH);
+ var texelW = Math.floor(gl.canvas.width / expectedW);
+ // For each entry of the expected[][] array, check the appropriate
+ // canvas rectangle for correctness.
+ for (var row = 0; row < expectedH; row++) {
+ var y = row * texelH;
+ for (var col = 0; col < expectedW; col++) {
+ var x = col * texelW;
+ var val = expected[row][col];
+ wtu.checkCanvasRect(gl, x, y, texelW, texelH, val, "should be " + val);
+ }
+ }
+ }
+
+ function runTest()
+ {
+ var program = tiu.setupTexturedQuadWith3D(gl, internalFormat);
+ runTestOnBindingTarget(gl.TEXTURE_3D, program);
+ program = tiu.setupTexturedQuadWith2DArray(gl, internalFormat);
+ runTestOnBindingTarget(gl.TEXTURE_2D_ARRAY, program);
+
+ debug("");
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors");
+ finishTest();
+ }
+
+ function simulate(flipY, premultiplyAlpha, depth, sourceSubRectangle, rTexCoord) {
+ var ro = [255, 0, 0]; var rt = premultiplyAlpha ? [0, 0, 0] : [255, 0, 0];
+ var go = [0, 255, 0]; var gt = premultiplyAlpha ? [0, 0, 0] : [0, 255, 0];
+ var bo = [0, 0, 255]; var bt = premultiplyAlpha ? [0, 0, 0] : [0, 0, 255];
+ var co = [0, 255, 255]; var ct = premultiplyAlpha ? [0, 0, 0] : [0, 255, 255];
+ var expected = [[ro, rt, go, gt],
+ [ro, rt, go, gt],
+ [bo, bt, co, ct],
+ [bo, bt, co, ct]];
+ switch (gl[pixelFormat]) {
+ case gl.RED:
+ case gl.RED_INTEGER:
+ for (var row = 0; row < 4; row++) {
+ for (var col = 0; col < 4; col++) {
+ expected[row][col][1] = 0; // zero the green channel
+ }
+ }
+ // fall-through
+ case gl.RG:
+ case gl.RG_INTEGER:
+ for (var row = 0; row < 4; row++) {
+ for (var col = 0; col < 4; col++) {
+ expected[row][col][2] = 0; // zero the blue channel
+ }
+ }
+ break;
+ default:
+ break;
+ }
+
+ if (flipY) {
+ expected.reverse();
+ }
+
+ if (sourceSubRectangle) {
+ let expected2 = [];
+ for (var row = 0; row < sourceSubRectangle[3]; row++) {
+ expected2[row] = [];
+ for (var col = 0; col < sourceSubRectangle[2]; col++) {
+ expected2[row][col] =
+ expected[sourceSubRectangle[1] + row + rTexCoord * sourceSubRectangle[3]][sourceSubRectangle[0] + col];
+ }
+ }
+ expected = expected2;
+ }
+
+ return expected;
+ }
+
+ function runTestOnBindingTarget(bindingTarget, program) {
+ var rects = [
+ undefined,
+ [0, 0, 2, 2],
+ [2, 0, 2, 2],
+ ];
+ var dbg = false; // Set to true for debug output images
+ if (dbg) {
+ (function() {
+ debug("");
+ debug("Original ImageData (transparent pixels appear black):");
+ var cvs = document.createElement("canvas");
+ cvs.width = 4;
+ cvs.height = 4;
+ cvs.style.width = "32px";
+ cvs.style.height = "32px";
+ cvs.style.imageRendering = "pixelated";
+ cvs.style.background = "#000";
+ var ctx = cvs.getContext("2d");
+ ctx.putImageData(imageData, 0, 0);
+ var output = document.getElementById("console");
+ output.appendChild(cvs);
+ })();
+ }
+ for (const sub of [false, true]) {
+ for (const flipY of [false, true]) {
+ for (const premul of [false, true]) {
+ for (let irect = 0; irect < rects.length; irect++) {
+ var rect = rects[irect];
+ let depth = rect ? 2 : 1;
+ for (let rTexCoord = 0; rTexCoord < depth; rTexCoord++) {
+ // TODO: add tests for UNPACK_IMAGE_HEIGHT.
+ runOneIteration(sub, flipY, premul, bindingTarget,
+ depth, rect, rTexCoord, program);
+ if (dbg) {
+ debug("Actual:");
+ var img = document.createElement("img");
+ img.src = gl.canvas.toDataURL("image/png");
+ var output = document.getElementById("console");
+ output.appendChild(img);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return init;
+}
diff --git a/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-3d-with-image.js b/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-3d-with-image.js
new file mode 100644
index 0000000000..034bd8ab46
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-3d-with-image.js
@@ -0,0 +1,260 @@
+/*
+Copyright (c) 2019 The Khronos Group Inc.
+Use of this source code is governed by an MIT-style license that can be
+found in the LICENSE.txt file.
+*/
+
+function generateTest(internalFormat, pixelFormat, pixelType, prologue, resourcePath, defaultContextVersion) {
+ var wtu = WebGLTestUtils;
+ var tiu = TexImageUtils;
+ var gl = null;
+ var successfullyParsed = false;
+ var imgCanvas;
+ var redColor = [255, 0, 0];
+ var greenColor = [0, 255, 0];
+ var blueColor = [0, 0, 255];
+ var cyanColor = [0, 255, 255];
+ var imageURLs = [resourcePath + "red-green.png",
+ resourcePath + "red-green-blue-cyan-4x4.png"];
+
+ function init()
+ {
+ description('Verify texImage3D and texSubImage3D code paths taking image elements (' + internalFormat + '/' + pixelFormat + '/' + pixelType + ')');
+
+ // Set the default context version while still allowing the webglVersion URL query string to override it.
+ wtu.setDefault3DContextVersion(defaultContextVersion);
+ gl = wtu.create3DContext("example");
+
+ if (!prologue(gl)) {
+ finishTest();
+ return;
+ }
+
+ switch (gl[pixelFormat]) {
+ case gl.RED:
+ case gl.RED_INTEGER:
+ greenColor = [0, 0, 0];
+ blueColor = [0, 0, 0];
+ cyanColor = [0, 0, 0];
+ break;
+
+ case gl.RG:
+ case gl.RG_INTEGER:
+ blueColor = [0, 0, 0];
+ cyanColor = [0, 255, 0];
+ break;
+
+ default:
+ break;
+ }
+
+ gl.clearColor(0,0,0,1);
+ gl.clearDepth(1);
+
+ wtu.loadImagesAsync(imageURLs, runTest);
+ }
+
+ function uploadImageToTexture(image, useTexSubImage3D, flipY, bindingTarget,
+ depth, sourceSubRectangle, unpackImageHeight)
+ {
+ gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
+ // Disable any writes to the alpha channel
+ gl.colorMask(1, 1, 1, 0);
+ var texture = gl.createTexture();
+ // Bind the texture to texture unit 0
+ gl.bindTexture(bindingTarget, texture);
+ // Set up texture parameters
+ gl.texParameteri(bindingTarget, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
+ gl.texParameteri(bindingTarget, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
+ gl.texParameteri(bindingTarget, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
+ gl.texParameteri(bindingTarget, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
+ gl.texParameteri(bindingTarget, gl.TEXTURE_WRAP_R, gl.CLAMP_TO_EDGE);
+ // Set up pixel store parameters
+ gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, flipY);
+ gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, false);
+ gl.pixelStorei(gl.UNPACK_COLORSPACE_CONVERSION_WEBGL, gl.NONE);
+ var uploadWidth = image.width;
+ var uploadHeight = image.height;
+ if (sourceSubRectangle) {
+ gl.pixelStorei(gl.UNPACK_SKIP_PIXELS, sourceSubRectangle[0]);
+ gl.pixelStorei(gl.UNPACK_SKIP_ROWS, sourceSubRectangle[1]);
+ uploadWidth = sourceSubRectangle[2];
+ uploadHeight = sourceSubRectangle[3];
+ }
+ if (unpackImageHeight) {
+ gl.pixelStorei(gl.UNPACK_IMAGE_HEIGHT, unpackImageHeight);
+ }
+ // Upload the image into the texture
+ if (useTexSubImage3D) {
+ // Initialize the texture to black first
+ gl.texImage3D(bindingTarget, 0, gl[internalFormat], uploadWidth, uploadHeight, depth, 0,
+ gl[pixelFormat], gl[pixelType], null);
+ gl.texSubImage3D(bindingTarget, 0, 0, 0, 0, uploadWidth, uploadHeight, depth,
+ gl[pixelFormat], gl[pixelType], image);
+ } else {
+ gl.texImage3D(bindingTarget, 0, gl[internalFormat], uploadWidth, uploadHeight, depth, 0,
+ gl[pixelFormat], gl[pixelType], image);
+ }
+ gl.pixelStorei(gl.UNPACK_SKIP_PIXELS, 0);
+ gl.pixelStorei(gl.UNPACK_SKIP_ROWS, 0);
+ gl.pixelStorei(gl.UNPACK_IMAGE_HEIGHT, 0);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors from texture upload");
+ }
+
+ function runRedGreenTest(image) {
+ function runOneIteration(image, useTexSubImage3D, flipY, bindingTarget, topColor, bottomColor, program)
+ {
+ debug('Testing ' + (useTexSubImage3D ? 'texSubImage3D' : 'texImage3D') +
+ ' with flipY=' + flipY + ' bindingTarget=' +
+ (bindingTarget == gl.TEXTURE_3D ? 'TEXTURE_3D' : 'TEXTURE_2D_ARRAY'));
+
+ uploadImageToTexture(image, useTexSubImage3D, flipY, bindingTarget, 1);
+
+ // Draw the triangles
+ wtu.clearAndDrawUnitQuad(gl, [0, 0, 0, 255]);
+ // Check a few pixels near the top and bottom and make sure they have
+ // the right color.
+ debug("Checking lower left corner");
+ wtu.checkCanvasRect(gl, 4, 4, 2, 2, bottomColor,
+ "shouldBe " + bottomColor);
+ debug("Checking upper left corner");
+ wtu.checkCanvasRect(gl, 4, gl.canvas.height - 8, 2, 2, topColor,
+ "shouldBe " + topColor);
+ }
+
+ var cases = [
+ { sub: false, flipY: true, topColor: redColor, bottomColor: greenColor },
+ { sub: false, flipY: false, topColor: greenColor, bottomColor: redColor },
+ { sub: true, flipY: true, topColor: redColor, bottomColor: greenColor },
+ { sub: true, flipY: false, topColor: greenColor, bottomColor: redColor },
+ ];
+
+ var program = tiu.setupTexturedQuadWith3D(gl, internalFormat);
+ for (var i in cases) {
+ runOneIteration(image, cases[i].sub, cases[i].flipY, gl.TEXTURE_3D,
+ cases[i].topColor, cases[i].bottomColor, program);
+ }
+ program = tiu.setupTexturedQuadWith2DArray(gl, internalFormat);
+ for (var i in cases) {
+ runOneIteration(image, cases[i].sub, cases[i].flipY, gl.TEXTURE_2D_ARRAY,
+ cases[i].topColor, cases[i].bottomColor, program);
+ }
+ }
+
+ function runRedGreenBlueCyanTest(image) {
+ function runOneIteration(image, useTexSubImage3D, flipY, bindingTarget,
+ depth, sourceSubRectangle, unpackImageHeight,
+ rTextureCoord, topColor, bottomColor, program)
+ {
+ sourceSubRectangleString = '';
+ if (sourceSubRectangle) {
+ sourceSubRectangleString = ' sourceSubRectangle=' + sourceSubRectangle;
+ }
+ unpackImageHeightString = '';
+ if (unpackImageHeight) {
+ unpackImageHeightString = ' unpackImageHeight=' + unpackImageHeight;
+ }
+ debug('Testing ' + (useTexSubImage3D ? 'texSubImage3D' : 'texImage3D') +
+ ' with flipY=' + flipY + ' bindingTarget=' +
+ (bindingTarget == gl.TEXTURE_3D ? 'TEXTURE_3D' : 'TEXTURE_2D_ARRAY') +
+ sourceSubRectangleString + ' depth=' + depth + unpackImageHeightString +
+ ' rTextureCoord=' + rTextureCoord);
+
+ uploadImageToTexture(image, useTexSubImage3D, flipY, bindingTarget,
+ depth, sourceSubRectangle, unpackImageHeight);
+ var rCoordLocation = gl.getUniformLocation(program, 'uRCoord');
+ if (!rCoordLocation) {
+ testFailed('Shader incorrectly set up; couldn\'t find uRCoord uniform');
+ return;
+ }
+ gl.uniform1f(rCoordLocation, rTextureCoord);
+
+ // Draw the triangles
+ wtu.clearAndDrawUnitQuad(gl, [0, 0, 0, 255]);
+ // Check a few pixels near the top and bottom and make sure they have
+ // the right color.
+ debug("Checking lower left corner");
+ wtu.checkCanvasRect(gl, 4, 4, 2, 2, bottomColor,
+ "shouldBe " + bottomColor);
+ debug("Checking upper left corner");
+ wtu.checkCanvasRect(gl, 4, gl.canvas.height - 8, 2, 2, topColor,
+ "shouldBe " + topColor);
+ }
+
+ var cases = [
+ // No UNPACK_IMAGE_HEIGHT specified.
+ { flipY: false, sourceSubRectangle: [0, 0, 2, 2], depth: 2, rTextureCoord: 0.0,
+ topColor: redColor, bottomColor: redColor },
+ { flipY: false, sourceSubRectangle: [0, 0, 2, 2], depth: 2, rTextureCoord: 1.0,
+ topColor: blueColor, bottomColor: blueColor },
+ { flipY: true, sourceSubRectangle: [0, 0, 2, 2], depth: 2, rTextureCoord: 0.0,
+ topColor: blueColor, bottomColor: blueColor },
+ { flipY: true, sourceSubRectangle: [0, 0, 2, 2], depth: 2, rTextureCoord: 1.0,
+ topColor: redColor, bottomColor: redColor },
+ { flipY: false, sourceSubRectangle: [2, 0, 2, 2], depth: 2, rTextureCoord: 0.0,
+ topColor: greenColor, bottomColor: greenColor },
+ { flipY: false, sourceSubRectangle: [2, 0, 2, 2], depth: 2, rTextureCoord: 1.0,
+ topColor: cyanColor, bottomColor: cyanColor },
+ { flipY: true, sourceSubRectangle: [2, 0, 2, 2], depth: 2, rTextureCoord: 0.0,
+ topColor: cyanColor, bottomColor: cyanColor },
+ { flipY: true, sourceSubRectangle: [2, 0, 2, 2], depth: 2, rTextureCoord: 1.0,
+ topColor: greenColor, bottomColor: greenColor },
+
+ // Use UNPACK_IMAGE_HEIGHT to skip some pixels.
+ { flipY: false, sourceSubRectangle: [0, 0, 1, 1], depth: 2, unpackImageHeight: 2, rTextureCoord: 0.0,
+ topColor: redColor, bottomColor: redColor },
+ { flipY: false, sourceSubRectangle: [0, 0, 1, 1], depth: 2, unpackImageHeight: 2, rTextureCoord: 1.0,
+ topColor: blueColor, bottomColor: blueColor },
+ { flipY: true, sourceSubRectangle: [0, 0, 1, 1], depth: 2, unpackImageHeight: 2, rTextureCoord: 0.0,
+ topColor: blueColor, bottomColor: blueColor },
+ { flipY: true, sourceSubRectangle: [0, 0, 1, 1], depth: 2, unpackImageHeight: 2, rTextureCoord: 1.0,
+ topColor: redColor, bottomColor: redColor },
+ { flipY: false, sourceSubRectangle: [2, 0, 1, 1], depth: 2, unpackImageHeight: 2, rTextureCoord: 0.0,
+ topColor: greenColor, bottomColor: greenColor },
+ { flipY: false, sourceSubRectangle: [2, 0, 1, 1], depth: 2, unpackImageHeight: 2, rTextureCoord: 1.0,
+ topColor: cyanColor, bottomColor: cyanColor },
+ { flipY: true, sourceSubRectangle: [2, 0, 1, 1], depth: 2, unpackImageHeight: 2, rTextureCoord: 0.0,
+ topColor: cyanColor, bottomColor: cyanColor },
+ { flipY: true, sourceSubRectangle: [2, 0, 1, 1], depth: 2, unpackImageHeight: 2, rTextureCoord: 1.0,
+ topColor: greenColor, bottomColor: greenColor },
+ ];
+
+ var program = tiu.setupTexturedQuadWith3D(gl, internalFormat);
+ for (var i in cases) {
+ runOneIteration(image, false, cases[i].flipY, gl.TEXTURE_3D,
+ cases[i].depth, cases[i].sourceSubRectangle,
+ cases[i].unpackImageHeight, cases[i].rTextureCoord,
+ cases[i].topColor, cases[i].bottomColor,
+ program);
+ runOneIteration(image, true, cases[i].flipY, gl.TEXTURE_3D,
+ cases[i].depth, cases[i].sourceSubRectangle,
+ cases[i].unpackImageHeight, cases[i].rTextureCoord,
+ cases[i].topColor, cases[i].bottomColor,
+ program);
+ }
+
+ program = tiu.setupTexturedQuadWith2DArray(gl, internalFormat);
+ for (var i in cases) {
+ runOneIteration(image, false, cases[i].flipY, gl.TEXTURE_2D_ARRAY,
+ cases[i].depth, cases[i].sourceSubRectangle,
+ cases[i].unpackImageHeight, cases[i].rTextureCoord,
+ cases[i].topColor, cases[i].bottomColor,
+ program);
+ runOneIteration(image, true, cases[i].flipY, gl.TEXTURE_2D_ARRAY,
+ cases[i].depth, cases[i].sourceSubRectangle,
+ cases[i].unpackImageHeight, cases[i].rTextureCoord,
+ cases[i].topColor, cases[i].bottomColor,
+ program);
+ }
+ }
+
+ function runTest(imageMap)
+ {
+ runRedGreenTest(imageMap[imageURLs[0]]);
+ runRedGreenBlueCyanTest(imageMap[imageURLs[1]]);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors");
+ finishTest();
+ }
+
+ return init;
+}
diff --git a/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-3d-with-svg-image.js b/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-3d-with-svg-image.js
new file mode 100644
index 0000000000..09a108dee8
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-3d-with-svg-image.js
@@ -0,0 +1,104 @@
+/*
+Copyright (c) 2019 The Khronos Group Inc.
+Use of this source code is governed by an MIT-style license that can be
+found in the LICENSE.txt file.
+*/
+
+function generateTest(internalFormat, pixelFormat, pixelType, prologue, resourcePath, defaultContextVersion) {
+ var wtu = WebGLTestUtils;
+ var tiu = TexImageUtils;
+ var gl = null;
+ var successfullyParsed = false;
+ var imgCanvas;
+ var redColor = [255, 0, 0];
+ var greenColor = [0, 255, 0];
+
+ function init()
+ {
+ description('Verify texImage3D and texSubImage3D code paths taking SVG image elements (' + internalFormat + '/' + pixelFormat + '/' + pixelType + ')');
+
+ // Set the default context version while still allowing the webglVersion URL query string to override it.
+ wtu.setDefault3DContextVersion(defaultContextVersion);
+ gl = wtu.create3DContext("example");
+
+ if (!prologue(gl)) {
+ finishTest();
+ return;
+ }
+
+ switch (gl[pixelFormat]) {
+ case gl.RED:
+ case gl.RED_INTEGER:
+ greenColor = [0, 0, 0];
+ break;
+ default:
+ break;
+ }
+
+ gl.clearColor(0,0,0,1);
+ gl.clearDepth(1);
+
+ wtu.loadTexture(gl, resourcePath + "red-green.svg", runTest);
+ }
+
+ function runOneIteration(image, flipY, topColor, bottomColor, bindingTarget, program)
+ {
+ debug('Testing ' + ' with flipY=' + flipY + ' bindingTarget=' +
+ (bindingTarget == gl.TEXTURE_3D ? 'TEXTURE_3D' : 'TEXTURE_2D_ARRAY'));
+ gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
+ // Disable any writes to the alpha channel
+ gl.colorMask(1, 1, 1, 0);
+ var texture = gl.createTexture();
+ // Bind the texture to texture unit 0
+ gl.bindTexture(bindingTarget, texture);
+ // Set up texture parameters
+ gl.texParameteri(bindingTarget, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
+ gl.texParameteri(bindingTarget, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
+ // Set up pixel store parameters
+ gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, flipY);
+ gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, false);
+ wtu.failIfGLError(gl, 'gl.pixelStorei(gl.UNPACK_COLORSPACE_CONVERSION_WEBGL, gl.NONE);');
+ // Upload the image into the texture
+ // Initialize the texture to black first
+ gl.texImage3D(bindingTarget, 0, gl[internalFormat], image.width, image.height, 1 /* depth */, 0,
+ gl[pixelFormat], gl[pixelType], null);
+ gl.texSubImage3D(bindingTarget, 0, 0, 0, 0, image.width, image.height, 1 /* depth */,
+ gl[pixelFormat], gl[pixelType], image);
+
+ // Draw the triangles
+ wtu.clearAndDrawUnitQuad(gl, [0, 0, 0, 255]);
+ // Check a few pixels near the top and bottom and make sure they have
+ // the right color.
+ debug("Checking lower left corner");
+ wtu.checkCanvasRect(gl, 4, 4, 2, 2, bottomColor,
+ "shouldBe " + bottomColor);
+ debug("Checking upper left corner");
+ wtu.checkCanvasRect(gl, 4, gl.canvas.height - 8, 2, 2, topColor,
+ "shouldBe " + topColor);
+ }
+
+ function runTest(image)
+ {
+ var program = tiu.setupTexturedQuadWith3D(gl, internalFormat);
+ runTestOnBindingTarget(image, gl.TEXTURE_3D, program);
+ program = tiu.setupTexturedQuadWith2DArray(gl, internalFormat);
+ runTestOnBindingTarget(image, gl.TEXTURE_2D_ARRAY, program);
+
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors");
+ finishTest();
+ }
+
+ function runTestOnBindingTarget(image, bindingTarget, program) {
+ var cases = [
+ { flipY: true, topColor: redColor, bottomColor: greenColor },
+ { flipY: false, topColor: greenColor, bottomColor: redColor },
+ ];
+ for (var i in cases) {
+ runOneIteration(image, cases[i].flipY,
+ cases[i].topColor, cases[i].bottomColor,
+ bindingTarget, program);
+ }
+ }
+
+ return init;
+}
diff --git a/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-3d-with-video.js b/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-3d-with-video.js
new file mode 100644
index 0000000000..0c2c40e8a5
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-3d-with-video.js
@@ -0,0 +1,244 @@
+/*
+Copyright (c) 2019 The Khronos Group Inc.
+Use of this source code is governed by an MIT-style license that can be
+found in the LICENSE.txt file.
+*/
+
+// This block needs to be outside the onload handler in order for this
+// test to run reliably in WebKit's test harness (at least the
+// Chromium port). https://bugs.webkit.org/show_bug.cgi?id=87448
+initTestingHarness();
+
+var old = debug;
+var debug = function(msg) {
+ bufferedLogToConsole(msg);
+ old(msg);
+};
+
+function generateTest(internalFormat, pixelFormat, pixelType, prologue, resourcePath, defaultContextVersion) {
+ var wtu = WebGLTestUtils;
+ var tiu = TexImageUtils;
+ var gl = null;
+ var successfullyParsed = false;
+ var redColor = [255, 0, 0];
+ var greenColor = [0, 255, 0];
+
+ // Test each format separately because many browsers implement each
+ // differently. Some might be GPU accelerated, some might not. Etc...
+ var videos = [
+ { src: resourcePath + "red-green.mp4" , type: 'video/mp4; codecs="avc1.42E01E, mp4a.40.2"', },
+ { src: resourcePath + "red-green.bt601.vp9.webm", type: 'video/webm; codecs="vp9"', },
+ { src: resourcePath + "red-green.webmvp8.webm", type: 'video/webm; codecs="vp8, vorbis"', },
+ { src: resourcePath + "red-green.theora.ogv", type: 'video/ogg; codecs="theora, vorbis"', },
+ ];
+
+ function init()
+ {
+ description('Verify texImage3D and texSubImage3D code paths taking video elements (' + internalFormat + '/' + pixelFormat + '/' + pixelType + ')');
+
+ // Set the default context version while still allowing the webglVersion URL query string to override it.
+ wtu.setDefault3DContextVersion(defaultContextVersion);
+ gl = wtu.create3DContext("example");
+
+ if (!prologue(gl)) {
+ finishTest();
+ return;
+ }
+
+ switch (gl[pixelFormat]) {
+ case gl.RED:
+ case gl.RED_INTEGER:
+ greenColor = [0, 0, 0];
+ break;
+ default:
+ break;
+ }
+
+ gl.clearColor(0,0,0,1);
+ gl.clearDepth(1);
+
+ runTest();
+ }
+
+ function runOneIteration(videoElement, flipY, useTexSubImage3D, topColor, bottomColor, program, bindingTarget,
+ depth, sourceSubRectangle, unpackImageHeight, rTextureCoord)
+ {
+ debug('Testing ' +
+ (useTexSubImage3D ? "texSubImage3D" : "texImage3D") +
+ ' with flipY=' + flipY + ' bindingTarget=' +
+ (bindingTarget == gl.TEXTURE_3D ? 'TEXTURE_3D' : 'TEXTURE_2D_ARRAY') +
+ (sourceSubRectangle ? ', sourceSubRectangle=' + sourceSubRectangle : '') +
+ (unpackImageHeight ? ', unpackImageHeight=' + unpackImageHeight : '') +
+ ', depth=' + depth +
+ ', rTextureCoord=' + rTextureCoord);
+ gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
+ // Disable any writes to the alpha channel
+ gl.colorMask(1, 1, 1, 0);
+ var texture = gl.createTexture();
+ // Bind the texture to texture unit 0
+ gl.bindTexture(bindingTarget, texture);
+ // Set up texture parameters
+ gl.texParameteri(bindingTarget, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
+ gl.texParameteri(bindingTarget, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
+ gl.texParameteri(bindingTarget, gl.TEXTURE_WRAP_R, gl.CLAMP_TO_EDGE);
+ gl.texParameteri(bindingTarget, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
+ gl.texParameteri(bindingTarget, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
+ // Set up pixel store parameters
+ gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, flipY);
+ gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, false);
+ gl.pixelStorei(gl.UNPACK_COLORSPACE_CONVERSION_WEBGL, gl.NONE);
+ var uploadWidth = videoElement.width;
+ var uploadHeight = videoElement.height;
+ if (sourceSubRectangle) {
+ gl.pixelStorei(gl.UNPACK_SKIP_PIXELS, sourceSubRectangle[0]);
+ gl.pixelStorei(gl.UNPACK_SKIP_ROWS, sourceSubRectangle[1]);
+ uploadWidth = sourceSubRectangle[2];
+ uploadHeight = sourceSubRectangle[3];
+ }
+ if (unpackImageHeight) {
+ gl.pixelStorei(gl.UNPACK_IMAGE_HEIGHT, unpackImageHeight);
+ }
+ // Upload the videoElement into the texture
+ if (useTexSubImage3D) {
+ // Initialize the texture to black first
+ gl.texImage3D(bindingTarget, 0, gl[internalFormat],
+ uploadWidth, uploadHeight, depth, 0,
+ gl[pixelFormat], gl[pixelType], null);
+ gl.texSubImage3D(bindingTarget, 0, 0, 0, 0,
+ uploadWidth, uploadHeight, depth,
+ gl[pixelFormat], gl[pixelType], videoElement);
+ } else {
+ gl.texImage3D(bindingTarget, 0, gl[internalFormat],
+ uploadWidth, uploadHeight, depth, 0,
+ gl[pixelFormat], gl[pixelType], videoElement);
+ }
+ gl.pixelStorei(gl.UNPACK_SKIP_PIXELS, 0);
+ gl.pixelStorei(gl.UNPACK_SKIP_ROWS, 0);
+ gl.pixelStorei(gl.UNPACK_IMAGE_HEIGHT, 0);
+
+ var c = document.createElement("canvas");
+ c.width = 16;
+ c.height = 16;
+ c.style.border = "1px solid black";
+ var ctx = c.getContext("2d");
+ ctx.drawImage(videoElement, 0, 0, 16, 16);
+ document.body.appendChild(c);
+
+ var rCoordLocation = gl.getUniformLocation(program, 'uRCoord');
+ if (!rCoordLocation) {
+ testFailed('Shader incorrectly set up; couldn\'t find uRCoord uniform');
+ return;
+ }
+ gl.uniform1f(rCoordLocation, rTextureCoord);
+
+ // Draw the triangles
+ wtu.clearAndDrawUnitQuad(gl, [0, 0, 0, 255]);
+ // Check a few pixels near the top and bottom and make sure they have
+ // the right color.
+ const tolerance = 6;
+ debug("Checking lower left corner");
+ wtu.checkCanvasRect(gl, 4, 4, 2, 2, bottomColor,
+ "shouldBe " + bottomColor, tolerance);
+ debug("Checking upper left corner");
+ wtu.checkCanvasRect(gl, 4, gl.canvas.height - 8, 2, 2, topColor,
+ "shouldBe " + topColor, tolerance);
+ }
+
+ function runTest(videoElement)
+ {
+ var cases = [
+ // No UNPACK_IMAGE_HEIGHT specified.
+ { flipY: false, sourceSubRectangle: [32, 16, 16, 16], depth: 5, rTextureCoord: 0,
+ topColor: redColor, bottomColor: redColor },
+ // Note that an rTextureCoord of 4.0 satisfies the need to
+ // have it be >= 1.0 for the TEXTURE_3D case, and also its
+ // use as an index in the TEXTURE_2D_ARRAY case.
+ { flipY: false, sourceSubRectangle: [32, 16, 16, 16], depth: 5, rTextureCoord: 4,
+ topColor: greenColor, bottomColor: greenColor },
+ { flipY: false, sourceSubRectangle: [24, 48, 32, 32], depth: 1, rTextureCoord: 0,
+ topColor: greenColor, bottomColor: redColor },
+ { flipY: true, sourceSubRectangle: [24, 48, 32, 32], depth: 1, rTextureCoord: 0,
+ topColor: redColor, bottomColor: greenColor },
+
+ // Use UNPACK_IMAGE_HEIGHT to skip some pixels.
+ { flipY: false, sourceSubRectangle: [32, 16, 16, 16], depth: 2, unpackImageHeight: 64, rTextureCoord: 0,
+ topColor: redColor, bottomColor: redColor },
+ { flipY: false, sourceSubRectangle: [32, 16, 16, 16], depth: 2, unpackImageHeight: 64, rTextureCoord: 1,
+ topColor: greenColor, bottomColor: greenColor },
+ ];
+
+ function runTexImageTest(bindingTarget) {
+ var program;
+ if (bindingTarget == gl.TEXTURE_3D) {
+ program = tiu.setupTexturedQuadWith3D(gl, internalFormat);
+ } else {
+ program = tiu.setupTexturedQuadWith2DArray(gl, internalFormat);
+ }
+
+ return new Promise(function(resolve, reject) {
+ var videoNdx = 0;
+ var video;
+ function runNextVideo() {
+ if (video) {
+ video.pause();
+ }
+
+ if (videoNdx == videos.length) {
+ resolve("SUCCESS");
+ return;
+ }
+
+ var info = videos[videoNdx++];
+ debug("");
+ debug("testing: " + info.type);
+ video = document.createElement("video");
+ video.muted = true;
+ var canPlay = true;
+ if (!video.canPlayType) {
+ testFailed("video.canPlayType required method missing");
+ runNextVideo();
+ return;
+ }
+
+ if(!video.canPlayType(info.type).replace(/no/, '')) {
+ debug(info.type + " unsupported");
+ runNextVideo();
+ return;
+ };
+
+ document.body.appendChild(video);
+ video.type = info.type;
+ video.src = info.src;
+ wtu.startPlayingAndWaitForVideo(video, runTest);
+ }
+ function runTest() {
+ for (var i in cases) {
+ runOneIteration(video, cases[i].flipY, false,
+ cases[i].topColor, cases[i].bottomColor,
+ program, bindingTarget, cases[i].depth,
+ cases[i].sourceSubRectangle,
+ cases[i].unpackImageHeight,
+ cases[i].rTextureCoord);
+ runOneIteration(video, cases[i].flipY, true,
+ cases[i].topColor, cases[i].bottomColor,
+ program, bindingTarget, cases[i].depth,
+ cases[i].sourceSubRectangle,
+ cases[i].unpackImageHeight,
+ cases[i].rTextureCoord);
+ }
+ runNextVideo();
+ }
+ runNextVideo();
+ });
+ }
+
+ runTexImageTest(gl.TEXTURE_3D).then(function(val) {
+ runTexImageTest(gl.TEXTURE_2D_ARRAY).then(function(val) {
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors");
+ finishTest();
+ });
+ });
+ }
+
+ return init;
+}
diff --git a/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-3d-with-webgl-canvas.js b/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-3d-with-webgl-canvas.js
new file mode 100644
index 0000000000..fe14b0c8eb
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-3d-with-webgl-canvas.js
@@ -0,0 +1,212 @@
+/*
+Copyright (c) 2019 The Khronos Group Inc.
+Use of this source code is governed by an MIT-style license that can be
+found in the LICENSE.txt file.
+*/
+
+function generateTest(internalFormat, pixelFormat, pixelType, prologue, resourcePath, defaultContextVersion) {
+ var wtu = WebGLTestUtils;
+ var tiu = TexImageUtils;
+ var gl = null;
+ var successfullyParsed = false;
+ var redColor = [255, 0, 0];
+ var greenColor = [0, 255, 0];
+
+ function init()
+ {
+ description('Verify texImage3D and texSubImage3D code paths taking webgl canvas elements (' + internalFormat + '/' + pixelFormat + '/' + pixelType + ')');
+
+ // Set the default context version while still allowing the webglVersion URL query string to override it.
+ wtu.setDefault3DContextVersion(defaultContextVersion);
+ gl = wtu.create3DContext("example");
+
+ if (!prologue(gl)) {
+ finishTest();
+ return;
+ }
+
+ switch (gl[pixelFormat]) {
+ case gl.RED:
+ case gl.RED_INTEGER:
+ greenColor = [0, 0, 0];
+ break;
+ default:
+ break;
+ }
+
+ gl.clearColor(0,0,0,1);
+ gl.clearDepth(1);
+
+ runTest();
+ }
+
+ function setCanvasToRedGreen(ctx) {
+ var width = ctx.canvas.width;
+ var height = ctx.canvas.height;
+ var halfHeight = Math.floor(height / 2);
+
+ ctx.viewport(0, 0, width, height);
+
+ ctx.enable(ctx.SCISSOR_TEST);
+ ctx.scissor(0, 0, width, halfHeight);
+ ctx.clearColor(1.0, 0, 0, 1.0);
+ ctx.clear(ctx.COLOR_BUFFER_BIT);
+ ctx.scissor(0, halfHeight, width, height - halfHeight);
+ ctx.clearColor(0.0, 1.0, 0, 1.0);
+ ctx.clear(ctx.COLOR_BUFFER_BIT);
+ ctx.disable(ctx.SCISSOR_TEST);
+ }
+
+ function setCanvasTo257x257(ctx, bindingTarget) {
+ ctx.canvas.width = 257;
+ ctx.canvas.height = 257;
+ setCanvasToRedGreen(ctx);
+ }
+
+ function setCanvasToMin(ctx, bindingTarget) {
+ ctx.canvas.width = 1;
+ ctx.canvas.height = 2;
+ setCanvasToRedGreen(ctx);
+ }
+
+ function runOneIteration(canvas, flipY, program, bindingTarget, opt_texture)
+ {
+ var objType = 'canvas';
+ if (canvas.transferToImageBitmap)
+ objType = 'OffscreenCanvas';
+ else if (canvas.parentNode)
+ objType = 'canvas attached to DOM';
+ debug('Testing flipY=' + flipY + ' object type: ' + objType +
+ ' bindingTarget=' + (bindingTarget == gl.TEXTURE_3D ? 'TEXTURE_3D' : 'TEXTURE_2D_ARRAY') +
+ ' canvas size: ' + canvas.width + 'x' + canvas.height + ' with red-green');
+
+ gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
+ if (!opt_texture) {
+ var texture = gl.createTexture();
+ // Bind the texture to texture unit 0
+ gl.bindTexture(bindingTarget, texture);
+ // Set up texture parameters
+ gl.texParameteri(bindingTarget, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
+ gl.texParameteri(bindingTarget, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
+ gl.texParameteri(bindingTarget, gl.TEXTURE_WRAP_R, gl.CLAMP_TO_EDGE);
+ gl.texParameteri(bindingTarget, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
+ gl.texParameteri(bindingTarget, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
+ } else {
+ var texture = opt_texture;
+ }
+ // Set up pixel store parameters
+ gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, flipY);
+ gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, false);
+ wtu.failIfGLError(gl, 'gl.pixelStorei(gl.UNPACK_COLORSPACE_CONVERSION_WEBGL, gl.NONE);');
+
+ // Upload the image into the texture
+ // Initialize the texture to black first
+ gl.texImage3D(bindingTarget, 0, gl[internalFormat], canvas.width, canvas.height, 1 /* depth */, 0,
+ gl[pixelFormat], gl[pixelType], null);
+ gl.texSubImage3D(bindingTarget, 0, 0, 0, 0, canvas.width, canvas.height, 1 /* depth */,
+ gl[pixelFormat], gl[pixelType], canvas);
+
+ var width = gl.canvas.width;
+ var height = gl.canvas.height;
+ var halfHeight = Math.floor(height / 2);
+ var top = flipY ? (height - halfHeight) : 0;
+ var bottom = flipY ? 0 : (height - halfHeight);
+
+ // Draw the triangles
+ wtu.clearAndDrawUnitQuad(gl, [0, 255, 0, 255]);
+
+ // Check the top and bottom halves and make sure they have the right color.
+ debug("Checking " + (flipY ? "top" : "bottom"));
+ wtu.checkCanvasRect(gl, 0, bottom, width, halfHeight, redColor, "shouldBe " + redColor);
+ debug("Checking " + (flipY ? "bottom" : "top"));
+ wtu.checkCanvasRect(gl, 0, top, width, halfHeight, greenColor, "shouldBe " + greenColor);
+
+ if (false) {
+ var ma = wtu.makeImageFromCanvas(canvas);
+ document.getElementById("console").appendChild(ma);
+
+ var m = wtu.makeImageFromCanvas(gl.canvas);
+ document.getElementById("console").appendChild(m);
+ document.getElementById("console").appendChild(document.createElement("hr"));
+ }
+
+ return texture;
+ }
+
+ function runTest()
+ {
+ var ctx = wtu.create3DContext();
+ var canvas = ctx.canvas;
+ // Note: We use preserveDrawingBuffer:true to prevent canvas
+ // visibility from interfering with the tests.
+ var visibleCtx = wtu.create3DContext(null, { preserveDrawingBuffer:true });
+ var visibleCanvas = visibleCtx.canvas;
+ var descriptionNode = document.getElementById("description");
+ document.body.insertBefore(visibleCanvas, descriptionNode);
+
+ var cases = [
+ { flipY: true, ctx: ctx, init: setCanvasToMin },
+ { flipY: false, ctx: ctx },
+ { flipY: true, ctx: ctx, init: setCanvasTo257x257 },
+ { flipY: false, ctx: ctx },
+ { flipY: true, ctx: visibleCtx, init: setCanvasToMin},
+ { flipY: false, ctx: visibleCtx },
+ ];
+
+ if (window.OffscreenCanvas) {
+ var offscreen = new OffscreenCanvas(1, 1);
+ var offscreenCtx = wtu.create3DContext(offscreen);
+ cases = cases.concat([
+ { flipY: true, ctx: offscreenCtx, init: setCanvasToMin },
+ { flipY: false, ctx: offscreenCtx },
+ ]);
+ }
+
+ function runTexImageTest(bindingTarget) {
+ var program;
+ if (bindingTarget == gl.TEXTURE_3D) {
+ program = tiu.setupTexturedQuadWith3D(gl, internalFormat);
+ } else {
+ program = tiu.setupTexturedQuadWith2DArray(gl, internalFormat);
+ }
+
+ return new Promise(function(resolve, reject) {
+ var count = 4;
+ var caseNdx = 0;
+ var texture = undefined;
+ function runNextTest() {
+ var c = cases[caseNdx];
+ if (c.init) {
+ c.init(c.ctx, bindingTarget);
+ }
+ texture = runOneIteration(c.ctx.canvas, c.flipY, program, bindingTarget, texture);
+ // for the first 2 iterations always make a new texture.
+ if (count < 2) {
+ gl.deleteTexture(texture);
+ texture = undefined;
+ }
+ ++caseNdx;
+ if (caseNdx == cases.length) {
+ caseNdx = 0;
+ --count;
+ if (!count) {
+ resolve("SUCCESS");
+ return;
+ }
+ }
+ wtu.waitForComposite(runNextTest);
+ }
+ runNextTest();
+ });
+ }
+
+ runTexImageTest(gl.TEXTURE_3D).then(function(val) {
+ runTexImageTest(gl.TEXTURE_2D_ARRAY).then(function(val) {
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors");
+ finishTest();
+ });
+ });
+ }
+
+ return init;
+}
diff --git a/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-utils.js b/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-utils.js
new file mode 100644
index 0000000000..f37f12fe91
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-utils.js
@@ -0,0 +1,865 @@
+/*
+Copyright (c) 2019 The Khronos Group Inc.
+Use of this source code is governed by an MIT-style license that can be
+found in the LICENSE.txt file.
+*/
+var TexImageUtils = (function() {
+
+ "use strict";
+
+ var wtu = WebGLTestUtils;
+
+ /**
+ * A vertex shader for a single texture.
+ * @type {string}
+ */
+ var simpleTextureVertexShaderES3 = [
+ '#version 300 es',
+ 'in vec4 vPosition;',
+ 'in vec2 texCoord0;',
+ 'out vec2 texCoord;',
+ 'void main() {',
+ ' gl_Position = vPosition;',
+ ' texCoord = texCoord0;',
+ '}'].join('\n');
+
+ /**
+ * A fragment shader for a single unsigned integer texture.
+ * @type {string}
+ */
+ // Note we always output 1.0 for alpha because if the texture does not contain
+ // alpha channel, sampling returns 1; for RGBA textures, sampling returns [0,255].
+ var simpleUintTextureFragmentShaderES3 = [
+ '#version 300 es',
+ 'precision mediump float;',
+ 'uniform mediump usampler2D tex;',
+ 'in vec2 texCoord;',
+ 'out vec4 fragData;',
+ 'void main() {',
+ ' uvec4 data = texture(tex, texCoord);',
+ ' fragData = vec4(float(data[0])/255.0,',
+ ' float(data[1])/255.0,',
+ ' float(data[2])/255.0,',
+ ' 1.0);',
+ '}'].join('\n');
+
+ /**
+ * A fragment shader for a single signed integer texture.
+ * @type {string}
+ */
+ // Note we always output 1.0 for alpha because if the texture does not contain
+ // alpha channel, sampling returns 1; for RGBA textures, sampling returns [0,255].
+ var simpleIntTextureFragmentShaderES3 = [
+ '#version 300 es',
+ 'precision mediump float;',
+ 'uniform mediump isampler2D tex;',
+ 'in vec2 texCoord;',
+ 'out vec4 fragData;',
+ 'void main() {',
+ ' ivec4 data = texture(tex, texCoord);',
+ ' fragData = vec4(float(data[0])/255.0,',
+ ' float(data[1])/255.0,',
+ ' float(data[2])/255.0,',
+ ' 1.0);',
+ '}'].join('\n');
+
+ /**
+ * A fragment shader for a single cube map unsigned integer texture.
+ * @type {string}
+ */
+ // Note we always output 1.0 for alpha because if the texture does not contain
+ // alpha channel, sampling returns 1; for RGBA textures, sampling returns [0,255].
+ var simpleCubeMapUintTextureFragmentShaderES3 = [
+ '#version 300 es',
+ 'precision mediump float;',
+ 'uniform mediump usamplerCube tex;',
+ 'uniform highp int face;',
+ 'in vec2 texCoord;',
+ 'out vec4 fragData;',
+ 'void main() {',
+ // Transform [0, 1] -> [-1, 1]
+ ' vec2 texC2 = (texCoord * 2.) - 1.;',
+ // Transform 2d tex coord. to each face of TEXTURE_CUBE_MAP coord.
+ ' vec3 texCube = vec3(0., 0., 0.);',
+ ' if (face == 34069) {', // TEXTURE_CUBE_MAP_POSITIVE_X
+ ' texCube = vec3(1., -texC2.y, -texC2.x);',
+ ' } else if (face == 34070) {', // TEXTURE_CUBE_MAP_NEGATIVE_X
+ ' texCube = vec3(-1., -texC2.y, texC2.x);',
+ ' } else if (face == 34071) {', // TEXTURE_CUBE_MAP_POSITIVE_Y
+ ' texCube = vec3(texC2.x, 1., texC2.y);',
+ ' } else if (face == 34072) {', // TEXTURE_CUBE_MAP_NEGATIVE_Y
+ ' texCube = vec3(texC2.x, -1., -texC2.y);',
+ ' } else if (face == 34073) {', // TEXTURE_CUBE_MAP_POSITIVE_Z
+ ' texCube = vec3(texC2.x, -texC2.y, 1.);',
+ ' } else if (face == 34074) {', // TEXTURE_CUBE_MAP_NEGATIVE_Z
+ ' texCube = vec3(-texC2.x, -texC2.y, -1.);',
+ ' }',
+ ' uvec4 data = texture(tex, texCube);',
+ ' fragData = vec4(float(data[0])/255.0,',
+ ' float(data[1])/255.0,',
+ ' float(data[2])/255.0,',
+ ' 1.0);',
+ '}'].join('\n');
+
+ /**
+ * A fragment shader for a single cube map signed integer texture.
+ * @type {string}
+ */
+ // Note we always output 1.0 for alpha because if the texture does not contain
+ // alpha channel, sampling returns 1; for RGBA textures, sampling returns [0,255].
+ var simpleCubeMapIntTextureFragmentShaderES3 = [
+ '#version 300 es',
+ 'precision mediump float;',
+ 'uniform mediump isamplerCube tex;',
+ 'uniform highp int face;',
+ 'in vec2 texCoord;',
+ 'out vec4 fragData;',
+ 'void main() {',
+ // Transform [0, 1] -> [-1, 1]
+ ' vec2 texC2 = (texCoord * 2.) - 1.;',
+ // Transform 2d tex coord. to each face of TEXTURE_CUBE_MAP coord.
+ ' vec3 texCube = vec3(0., 0., 0.);',
+ ' if (face == 34069) {', // TEXTURE_CUBE_MAP_POSITIVE_X
+ ' texCube = vec3(1., -texC2.y, -texC2.x);',
+ ' } else if (face == 34070) {', // TEXTURE_CUBE_MAP_NEGATIVE_X
+ ' texCube = vec3(-1., -texC2.y, texC2.x);',
+ ' } else if (face == 34071) {', // TEXTURE_CUBE_MAP_POSITIVE_Y
+ ' texCube = vec3(texC2.x, 1., texC2.y);',
+ ' } else if (face == 34072) {', // TEXTURE_CUBE_MAP_NEGATIVE_Y
+ ' texCube = vec3(texC2.x, -1., -texC2.y);',
+ ' } else if (face == 34073) {', // TEXTURE_CUBE_MAP_POSITIVE_Z
+ ' texCube = vec3(texC2.x, -texC2.y, 1.);',
+ ' } else if (face == 34074) {', // TEXTURE_CUBE_MAP_NEGATIVE_Z
+ ' texCube = vec3(-texC2.x, -texC2.y, -1.);',
+ ' }',
+ ' ivec4 data = texture(tex, texCube);',
+ ' fragData = vec4(float(data[0])/255.0,',
+ ' float(data[1])/255.0,',
+ ' float(data[2])/255.0,',
+ ' 1.0);',
+ '}'].join('\n');
+
+ /**
+ * A fragment shader for a single 3D texture.
+ * @type {string}
+ */
+ // Note that the tex coordinate r (the uniform uRCoord) is set to 0.0 by default.
+ var simple3DTextureFragmentShaderES3 = [
+ '#version 300 es',
+ 'precision mediump float;',
+ 'uniform mediump sampler3D tex;',
+ 'in vec2 texCoord;',
+ 'uniform float uRCoord;',
+ 'out vec4 fragData;',
+ 'void main() {',
+ ' fragData = vec4(texture(tex, vec3(texCoord, uRCoord)).rgb, 1.0);',
+ '}'].join('\n');
+
+ /**
+ * A fragment shader for a single 3D unsigned integer texture.
+ * @type {string}
+ */
+ // Note that the tex coordinate r (the uniform uRCoord) is set to 0.0 by default.
+ // Note we always output 1.0 for alpha because if the texture does not contain
+ // alpha channel, sampling returns 1; for RGBA textures, sampling returns [0,255].
+ var simple3DUintTextureFragmentShaderES3 = [
+ '#version 300 es',
+ 'precision mediump float;',
+ 'uniform mediump usampler3D tex;',
+ 'in vec2 texCoord;',
+ 'uniform float uRCoord;',
+ 'out vec4 fragData;',
+ 'void main() {',
+ ' uvec4 data = texture(tex, vec3(texCoord, uRCoord));',
+ ' fragData = vec4(float(data[0])/255.0,',
+ ' float(data[1])/255.0,',
+ ' float(data[2])/255.0,',
+ ' 1.0);',
+ '}'].join('\n');
+
+ /**
+ * A fragment shader for a single 3D signed integer texture.
+ * @type {string}
+ */
+ // Note that the tex coordinate r (the uniform uRCoord) is set to 0.0 by default.
+ // Note we always output 1.0 for alpha because if the texture does not contain
+ // alpha channel, sampling returns 1; for RGBA textures, sampling returns [0,255].
+ var simple3DIntTextureFragmentShaderES3 = [
+ '#version 300 es',
+ 'precision mediump float;',
+ 'uniform mediump isampler3D tex;',
+ 'in vec2 texCoord;',
+ 'uniform float uRCoord;',
+ 'out vec4 fragData;',
+ 'void main() {',
+ ' ivec4 data = texture(tex, vec3(texCoord, uRCoord));',
+ ' fragData = vec4(float(data[0])/255.0,',
+ ' float(data[1])/255.0,',
+ ' float(data[2])/255.0,',
+ ' 1.0);',
+ '}'].join('\n');
+
+ /**
+ * A fragment shader for a single 2D_ARRAY texture.
+ * @type {string}
+ */
+ // Note that the first image in the array (selected by the uniform
+ // uRCoord) is used by default.
+ var simple2DArrayTextureFragmentShaderES3 = [
+ '#version 300 es',
+ 'precision mediump float;',
+ 'uniform mediump sampler2DArray tex;',
+ 'in vec2 texCoord;',
+ 'uniform float uRCoord;',
+ 'out vec4 fragData;',
+ 'void main() {',
+ ' fragData = vec4(texture(tex, vec3(texCoord, uRCoord)).rgb, 1.0);',
+ '}'].join('\n');
+
+ /**
+ * A fragment shader for a single 2D_ARRAY unsigned integer texture.
+ * @type {string}
+ */
+ // Note that the first image in the array (selected by the uniform
+ // uRCoord) is used by default.
+ // Note we always output 1.0 for alpha because if the texture does not contain
+ // alpha channel, sampling returns 1; for RGBA textures, sampling returns [0,255].
+ var simple2DArrayUintTextureFragmentShaderES3 = [
+ '#version 300 es',
+ 'precision mediump float;',
+ 'uniform mediump usampler2DArray tex;',
+ 'in vec2 texCoord;',
+ 'uniform float uRCoord;',
+ 'out vec4 fragData;',
+ 'void main() {',
+ ' uvec4 data = texture(tex, vec3(texCoord, uRCoord));',
+ ' fragData = vec4(float(data[0])/255.0,',
+ ' float(data[1])/255.0,',
+ ' float(data[2])/255.0,',
+ ' 1.0);',
+ '}'].join('\n');
+
+ /**
+ * A fragment shader for a single 2D_ARRAY signed integer texture.
+ * @type {string}
+ */
+ // Note that the first image in the array (selected by the uniform
+ // uRCoord) is used by default.
+ // Note we always output 1.0 for alpha because if the texture does not contain
+ // alpha channel, sampling returns 1; for RGBA textures, sampling returns [0,255].
+ var simple2DArrayIntTextureFragmentShaderES3 = [
+ '#version 300 es',
+ 'precision mediump float;',
+ 'uniform mediump isampler2DArray tex;',
+ 'in vec2 texCoord;',
+ 'uniform float uRCoord;',
+ 'out vec4 fragData;',
+ 'void main() {',
+ ' ivec4 data = texture(tex, vec3(texCoord, uRCoord));',
+ ' fragData = vec4(float(data[0])/255.0,',
+ ' float(data[1])/255.0,',
+ ' float(data[2])/255.0,',
+ ' 1.0);',
+ '}'].join('\n');
+
+
+ /**
+ * Creates a simple texture vertex shader.
+ * @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use.
+ * @return {!WebGLShader}
+ */
+ var setupSimpleTextureVertexShader = function(gl) {
+ return WebGLTestUtils.loadShader(gl, simpleTextureVertexShaderES3, gl.VERTEX_SHADER);
+ };
+
+ /**
+ * Creates a simple unsigned integer texture fragment shader.
+ * Output is scaled by 1/255 to bring the result into normalized float range.
+ * @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use.
+ * @return {!WebGLShader}
+ */
+ var setupSimpleUintTextureFragmentShader = function(gl) {
+ return WebGLTestUtils.loadShader(gl, simpleUintTextureFragmentShaderES3, gl.FRAGMENT_SHADER);
+ };
+
+ /**
+ * Creates a simple signed integer texture fragment shader.
+ * Output is scaled by 1/255 to bring the result into normalized float range.
+ * @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use.
+ * @return {!WebGLShader}
+ */
+ var setupSimpleIntTextureFragmentShader = function(gl) {
+ return WebGLTestUtils.loadShader(gl, simpleIntTextureFragmentShaderES3, gl.FRAGMENT_SHADER);
+ };
+
+ /**
+ * Creates a simple cube map unsigned integer texture fragment shader.
+ * @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use.
+ * @return {!WebGLShader}
+ */
+ var setupSimpleCubeMapUintTextureFragmentShader = function(gl) {
+ return WebGLTestUtils.loadShader(gl, simpleCubeMapUintTextureFragmentShaderES3, gl.FRAGMENT_SHADER);
+ };
+
+ /**
+ * Creates a simple cube map signed integer texture fragment shader.
+ * @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use.
+ * @return {!WebGLShader}
+ */
+ var setupSimpleCubeMapIntTextureFragmentShader = function(gl) {
+ return WebGLTestUtils.loadShader(gl, simpleCubeMapIntTextureFragmentShaderES3, gl.FRAGMENT_SHADER);
+ };
+
+ /**
+ * Creates a simple 3D texture fragment shader.
+ * @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use.
+ * @return {!WebGLShader}
+ */
+ var setupSimple3DTextureFragmentShader = function(gl) {
+ return WebGLTestUtils.loadShader(gl, simple3DTextureFragmentShaderES3, gl.FRAGMENT_SHADER);
+ };
+
+ /**
+ * Creates a simple 3D unsigned integer texture fragment shader.
+ * @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use.
+ * @return {!WebGLShader}
+ */
+ var setupSimple3DUintTextureFragmentShader = function(gl) {
+ return WebGLTestUtils.loadShader(gl, simple3DUintTextureFragmentShaderES3, gl.FRAGMENT_SHADER);
+ };
+
+ /**
+ * Creates a simple 3D signed integer texture fragment shader.
+ * @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use.
+ * @return {!WebGLShader}
+ */
+ var setupSimple3DIntTextureFragmentShader = function(gl) {
+ return WebGLTestUtils.loadShader(gl, simple3DIntTextureFragmentShaderES3, gl.FRAGMENT_SHADER);
+ };
+
+ /**
+ * Creates a simple 2D_ARRAY texture fragment shader.
+ * @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use.
+ * @return {!WebGLShader}
+ */
+ var setupSimple2DArrayTextureFragmentShader = function(gl) {
+ return WebGLTestUtils.loadShader(gl, simple2DArrayTextureFragmentShaderES3, gl.FRAGMENT_SHADER);
+ };
+
+ /**
+ * Creates a simple 2D_ARRAY integer texture fragment shader.
+ * @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use.
+ * @return {!WebGLShader}
+ */
+ var setupSimple2DArrayUintTextureFragmentShader = function(gl) {
+ return WebGLTestUtils.loadShader(gl, simple2DArrayUintTextureFragmentShaderES3, gl.FRAGMENT_SHADER);
+ };
+
+ /**
+ * Creates a simple unsigned integer texture program.
+ * @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use.
+ * @param {number} opt_positionLocation The attrib location for position.
+ * @param {number} opt_texcoordLocation The attrib location for texture coords.
+ * @return {WebGLProgram}
+ */
+ var setupSimpleUintTextureProgram = function(gl, opt_positionLocation, opt_texcoordLocation)
+ {
+ opt_positionLocation = opt_positionLocation || 0;
+ opt_texcoordLocation = opt_texcoordLocation || 1;
+ var vs = setupSimpleTextureVertexShader(gl),
+ fs = setupSimpleUintTextureFragmentShader(gl);
+ if (!vs || !fs) {
+ return null;
+ }
+ var program = WebGLTestUtils.setupProgram(
+ gl,
+ [vs, fs],
+ ['vPosition', 'texCoord0'],
+ [opt_positionLocation, opt_texcoordLocation]);
+ if (!program) {
+ gl.deleteShader(fs);
+ gl.deleteShader(vs);
+ }
+ gl.useProgram(program);
+ return program;
+ };
+
+ /**
+ * Creates a simple signed integer texture program.
+ * @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use.
+ * @param {number} opt_positionLocation The attrib location for position.
+ * @param {number} opt_texcoordLocation The attrib location for texture coords.
+ * @return {WebGLProgram}
+ */
+ var setupSimpleIntTextureProgram = function(gl, opt_positionLocation, opt_texcoordLocation)
+ {
+ opt_positionLocation = opt_positionLocation || 0;
+ opt_texcoordLocation = opt_texcoordLocation || 1;
+ var vs = setupSimpleTextureVertexShader(gl),
+ fs = setupSimpleIntTextureFragmentShader(gl);
+ if (!vs || !fs) {
+ return null;
+ }
+ var program = WebGLTestUtils.setupProgram(
+ gl,
+ [vs, fs],
+ ['vPosition', 'texCoord0'],
+ [opt_positionLocation, opt_texcoordLocation]);
+ if (!program) {
+ gl.deleteShader(fs);
+ gl.deleteShader(vs);
+ }
+ gl.useProgram(program);
+ return program;
+ };
+
+ /**
+ * Creates a simple cube map unsigned integer texture program.
+ * @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use.
+ * @param {number} opt_positionLocation The attrib location for position.
+ * @param {number} opt_texcoordLocation The attrib location for texture coords.
+ * @return {WebGLProgram}
+ */
+ var setupSimpleCubeMapUintTextureProgram = function(gl, opt_positionLocation, opt_texcoordLocation) {
+ opt_positionLocation = opt_positionLocation || 0;
+ opt_texcoordLocation = opt_texcoordLocation || 1;
+ var vs = setupSimpleTextureVertexShader(gl);
+ var fs = setupSimpleCubeMapUintTextureFragmentShader(gl);
+ if (!vs || !fs) {
+ return null;
+ }
+ var program = WebGLTestUtils.setupProgram(
+ gl,
+ [vs, fs],
+ ['vPosition', 'texCoord0'],
+ [opt_positionLocation, opt_texcoordLocation]);
+ if (!program) {
+ gl.deleteShader(fs);
+ gl.deleteShader(vs);
+ }
+ gl.useProgram(program);
+ return program;
+ };
+
+ /**
+ * Creates a simple cube map signed integer texture program.
+ * @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use.
+ * @param {number} opt_positionLocation The attrib location for position.
+ * @param {number} opt_texcoordLocation The attrib location for texture coords.
+ * @return {WebGLProgram}
+ */
+ var setupSimpleCubeMapIntTextureProgram = function(gl, opt_positionLocation, opt_texcoordLocation) {
+ opt_positionLocation = opt_positionLocation || 0;
+ opt_texcoordLocation = opt_texcoordLocation || 1;
+ var vs = setupSimpleTextureVertexShader(gl);
+ var fs = setupSimpleCubeMapIntTextureFragmentShader(gl);
+ if (!vs || !fs) {
+ return null;
+ }
+ var program = WebGLTestUtils.setupProgram(
+ gl,
+ [vs, fs],
+ ['vPosition', 'texCoord0'],
+ [opt_positionLocation, opt_texcoordLocation]);
+ if (!program) {
+ gl.deleteShader(fs);
+ gl.deleteShader(vs);
+ }
+ gl.useProgram(program);
+ return program;
+ };
+
+ /**
+ * Creates a simple 3D texture program.
+ * @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use.
+ * @param {number} opt_positionLocation The attrib location for position.
+ * @param {number} opt_texcoordLocation The attrib location for texture coords.
+ * @return {WebGLProgram}
+ */
+ var setupSimple3DTextureProgram = function(gl, opt_positionLocation, opt_texcoordLocation)
+ {
+ opt_positionLocation = opt_positionLocation || 0;
+ opt_texcoordLocation = opt_texcoordLocation || 1;
+ var vs = setupSimpleTextureVertexShader(gl),
+ fs = setupSimple3DTextureFragmentShader(gl);
+ if (!vs || !fs) {
+ return null;
+ }
+ var program = WebGLTestUtils.setupProgram(
+ gl,
+ [vs, fs],
+ ['vPosition', 'texCoord0'],
+ [opt_positionLocation, opt_texcoordLocation]);
+ if (!program) {
+ gl.deleteShader(fs);
+ gl.deleteShader(vs);
+ }
+ gl.useProgram(program);
+ return program;
+ };
+
+ /**
+ * Creates a simple 3D unsigned integer texture program.
+ * @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use.
+ * @param {number} opt_positionLocation The attrib location for position.
+ * @param {number} opt_texcoordLocation The attrib location for texture coords.
+ * @return {WebGLProgram}
+ */
+ var setupSimple3DUintTextureProgram = function(gl, opt_positionLocation, opt_texcoordLocation)
+ {
+ opt_positionLocation = opt_positionLocation || 0;
+ opt_texcoordLocation = opt_texcoordLocation || 1;
+ var vs = setupSimpleTextureVertexShader(gl),
+ fs = setupSimple3DUintTextureFragmentShader(gl);
+ if (!vs || !fs) {
+ return null;
+ }
+ var program = WebGLTestUtils.setupProgram(
+ gl,
+ [vs, fs],
+ ['vPosition', 'texCoord0'],
+ [opt_positionLocation, opt_texcoordLocation]);
+ if (!program) {
+ gl.deleteShader(fs);
+ gl.deleteShader(vs);
+ }
+ gl.useProgram(program);
+ return program;
+ };
+
+ /**
+ * Creates a simple 3D signed integer texture program.
+ * @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use.
+ * @param {number} opt_positionLocation The attrib location for position.
+ * @param {number} opt_texcoordLocation The attrib location for texture coords.
+ * @return {WebGLProgram}
+ */
+ var setupSimple3DIntTextureProgram = function(gl, opt_positionLocation, opt_texcoordLocation)
+ {
+ opt_positionLocation = opt_positionLocation || 0;
+ opt_texcoordLocation = opt_texcoordLocation || 1;
+ var vs = setupSimpleTextureVertexShader(gl),
+ fs = setupSimple3DIntTextureFragmentShader(gl);
+ if (!vs || !fs) {
+ return null;
+ }
+ var program = WebGLTestUtils.setupProgram(
+ gl,
+ [vs, fs],
+ ['vPosition', 'texCoord0'],
+ [opt_positionLocation, opt_texcoordLocation]);
+ if (!program) {
+ gl.deleteShader(fs);
+ gl.deleteShader(vs);
+ }
+ gl.useProgram(program);
+ return program;
+ };
+
+ /**
+ * Creates a simple 2D_ARRAY texture program.
+ * @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use.
+ * @param {number} opt_positionLocation The attrib location for position.
+ * @param {number} opt_texcoordLocation The attrib location for texture coords.
+ * @return {WebGLProgram}
+ */
+ var setupSimple2DArrayTextureProgram = function(gl, opt_positionLocation, opt_texcoordLocation)
+ {
+ opt_positionLocation = opt_positionLocation || 0;
+ opt_texcoordLocation = opt_texcoordLocation || 1;
+ var vs = setupSimpleTextureVertexShader(gl),
+ fs = setupSimple2DArrayTextureFragmentShader(gl);
+ if (!vs || !fs) {
+ return null;
+ }
+ var program = WebGLTestUtils.setupProgram(
+ gl,
+ [vs, fs],
+ ['vPosition', 'texCoord0'],
+ [opt_positionLocation, opt_texcoordLocation]);
+ if (!program) {
+ gl.deleteShader(fs);
+ gl.deleteShader(vs);
+ }
+ gl.useProgram(program);
+ return program;
+ };
+
+ /**
+ * Creates a simple 2D_ARRAY unsigned integer texture program.
+ * @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use.
+ * @param {number} opt_positionLocation The attrib location for position.
+ * @param {number} opt_texcoordLocation The attrib location for texture coords.
+ * @return {WebGLProgram}
+ */
+ var setupSimple2DArrayUintTextureProgram = function(gl, opt_positionLocation, opt_texcoordLocation)
+ {
+ opt_positionLocation = opt_positionLocation || 0;
+ opt_texcoordLocation = opt_texcoordLocation || 1;
+ var vs = setupSimpleTextureVertexShader(gl),
+ fs = setupSimple2DArrayUintTextureFragmentShader(gl);
+ if (!vs || !fs) {
+ return null;
+ }
+ var program = WebGLTestUtils.setupProgram(
+ gl,
+ [vs, fs],
+ ['vPosition', 'texCoord0'],
+ [opt_positionLocation, opt_texcoordLocation]);
+ if (!program) {
+ gl.deleteShader(fs);
+ gl.deleteShader(vs);
+ }
+ gl.useProgram(program);
+ return program;
+ };
+
+ /**
+ * Creates a simple 2D_ARRAY signed integer texture program.
+ * @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use.
+ * @param {number} opt_positionLocation The attrib location for position.
+ * @param {number} opt_texcoordLocation The attrib location for texture coords.
+ * @return {WebGLProgram}
+ */
+ var setupSimple2DArrayIntTextureProgram = function(gl, opt_positionLocation, opt_texcoordLocation)
+ {
+ opt_positionLocation = opt_positionLocation || 0;
+ opt_texcoordLocation = opt_texcoordLocation || 1;
+ var vs = setupSimpleTextureVertexShader(gl),
+ fs = setupSimple2DArrayIntTextureFragmentShader(gl);
+ if (!vs || !fs) {
+ return null;
+ }
+ var program = WebGLTestUtils.setupProgram(
+ gl,
+ [vs, fs],
+ ['vPosition', 'texCoord0'],
+ [opt_positionLocation, opt_texcoordLocation]);
+ if (!program) {
+ gl.deleteShader(fs);
+ gl.deleteShader(vs);
+ }
+ gl.useProgram(program);
+ return program;
+ };
+
+ /**
+ * Creates a program and buffers for rendering a unsigned integer textured quad.
+ * @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use.
+ * @return {!WebGLProgram}
+ */
+ var setupUintTexturedQuad = function(gl) {
+ var program = setupSimpleUintTextureProgram(gl);
+ wtu.setupUnitQuad(gl);
+ return program;
+ };
+
+ /**
+ * Creates a program and buffers for rendering a signed integer textured quad.
+ * @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use.
+ * @return {!WebGLProgram}
+ */
+ var setupIntTexturedQuad = function(gl) {
+ var program = setupSimpleIntTextureProgram(gl);
+ wtu.setupUnitQuad(gl);
+ return program;
+ };
+
+ /**
+ * Creates a program and buffers for rendering a textured quad with
+ * a cube map unsigned integer texture.
+ * @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use.
+ * @return {!WebGLProgram}
+ */
+ var setupUintTexturedQuadWithCubeMap = function(gl)
+ {
+ var program = setupSimpleCubeMapUintTextureProgram(gl);
+ wtu.setupUnitQuad(gl);
+ return program;
+ };
+
+ /**
+ * Creates a program and buffers for rendering a textured quad with
+ * a cube map signed integer texture.
+ * @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use.
+ * @return {!WebGLProgram}
+ */
+ var setupIntTexturedQuadWithCubeMap = function(gl)
+ {
+ var program = setupSimpleCubeMapIntTextureProgram(gl);
+ wtu.setupUnitQuad(gl);
+ return program;
+ };
+
+ /**
+ * Does the GL internal format represent an unsigned integer format
+ * texture?
+ * @return {boolean}
+ */
+ var isUintFormat = function(internalFormat)
+ {
+ return (internalFormat == "R8UI" || internalFormat == "RG8UI" || internalFormat == "RGB8UI" || internalFormat == "RGBA8UI" ||
+ internalFormat == "R16UI" || internalFormat == "RG16UI" || internalFormat == "RGB16UI" || internalFormat == "RGBA16UI" ||
+ internalFormat == "R32UI" || internalFormat == "RG32UI" || internalFormat == "RGB32UI" || internalFormat == "RGBA32UI");
+ };
+
+ /**
+ * Does the GL internal format represent an signed integer format
+ * texture?
+ * @return {boolean}
+ */
+ var isIntFormat = function(internalFormat)
+ {
+ return (internalFormat == "R8I" || internalFormat == "RG8I" || internalFormat == "RGB8I" || internalFormat == "RGBA8I" ||
+ internalFormat == "R16I" || internalFormat == "RG16I" || internalFormat == "RGB16I" || internalFormat == "RGBA16I" ||
+ internalFormat == "R32I" || internalFormat == "RG32I" || internalFormat == "RGB32I" || internalFormat == "RGBA32I");
+ };
+
+ /**
+ * Createa a program and buffers for rendering a textured quad for
+ * tex-image-and-sub-image tests. Handle selection of correct
+ * program to handle texture format.
+ * @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use.
+ * @param {string} internalFormat The internal format for texture to be tested.
+ */
+ var setupTexturedQuad = function(gl, internalFormat)
+ {
+ if (isUintFormat(internalFormat))
+ return setupUintTexturedQuad(gl);
+ if (isIntFormat(internalFormat))
+ return setupIntTexturedQuad(gl);
+ return wtu.setupTexturedQuad(gl);
+ };
+
+ /**
+ * Createa a program and buffers for rendering a textured quad with
+ * a cube map for tex-image-and-sub-image tests. Handle selection of
+ * correct program to handle texture format.
+ * @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use.
+ * @param {string} internalFormat The internal format for texture to be tested.
+ */
+ function setupTexturedQuadWithCubeMap(gl, internalFormat)
+ {
+ if (isUintFormat(internalFormat))
+ return setupUintTexturedQuadWithCubeMap(gl);
+ if (isIntFormat(internalFormat))
+ return setupIntTexturedQuadWithCubeMap(gl);
+ return wtu.setupTexturedQuadWithCubeMap(gl);
+ }
+
+ /**
+ * Createa a program and buffers for rendering a textured quad with a 3D texture
+ * for tex-image-and-sub-image tests. Handle selection of correct
+ * program to handle texture format.
+ * @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use.
+ * @param {string} internalFormat The internal format for texture to be tested.
+ */
+ var setupTexturedQuadWith3D = function(gl, internalFormat)
+ {
+ var program;
+ if (isUintFormat(internalFormat))
+ program = setupSimple3DUintTextureProgram(gl);
+ else if (isIntFormat(internalFormat))
+ program = setupSimple3DIntTextureProgram(gl);
+ else
+ program = setupSimple3DTextureProgram(gl);
+ var uRCoordLoc = gl.getUniformLocation(program, 'uRCoord');
+ gl.uniform1f(uRCoordLoc, 0.0);
+ wtu.setupUnitQuad(gl);
+ return program;
+ };
+
+ /**
+ * Createa a program and buffers for rendering a textured quad with a 2D_ARRAY
+ * texture for tex-image-and-sub-image tests. Handle selection of correct
+ * program to handle texture format.
+ * @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use.
+ * @param {string} internalFormat The internal format for texture to be tested.
+ */
+ var setupTexturedQuadWith2DArray = function(gl, internalFormat)
+ {
+ var program;
+ if (isUintFormat(internalFormat))
+ program = setupSimple2DArrayUintTextureProgram(gl);
+ else if (isIntFormat(internalFormat))
+ program = setupSimple2DArrayIntTextureProgram(gl);
+ else
+ program = setupSimple2DArrayTextureProgram(gl);
+ var uRCoordLoc = gl.getUniformLocation(program, 'uRCoord');
+ gl.uniform1f(uRCoordLoc, 0.0);
+ wtu.setupUnitQuad(gl);
+ return program;
+ };
+
+ /**
+ * Return a list of unpack color spaces to test, supported by the specified
+ * WebGLRenderingContext.
+ */
+ var unpackColorSpacesToTest = function(gl)
+ {
+ if ('unpackColorSpace' in gl)
+ return ['srgb', 'display-p3'];
+ else
+ return [undefined];
+ }
+
+ /**
+ * For each entry in unpackColorSpaces, duplicate all of cases, adding an
+ * unpackColorSpace key with its value set to that entry to each case.
+ */
+ var crossProductTestCasesWithUnpackColorSpaces = function(testCaseList, unpackColorSpaces)
+ {
+ var testCaseWithUnpackColorSpace = function(testCase, colorSpace)
+ {
+ return {...testCase, ...{unpackColorSpace:colorSpace}};
+ }
+ var listOfTestCaseLists = unpackColorSpaces.map(colorSpace =>
+ testCaseList.map(testCase => testCaseWithUnpackColorSpace(testCase, colorSpace)));
+ return listOfTestCaseLists.flat();
+ }
+
+ /**
+ * Given given an internalformat, format, and type, return the tolerance
+ * that should be used when comparing an input 8-bit value to one that has
+ * been truncated through the specified formats.
+ */
+ var tolerance = function(internalformat, format, type) {
+ function typeTolerance(type) {
+ switch(type) {
+ case 'UNSIGNED_SHORT_5_6_5':
+ case 'UNSIGNED_SHORT_5_5_5_1':
+ return 255 / 31;
+ case 'UNSIGNED_SHORT_4_4_4_4':
+ return 255 / 15;
+ break;
+ default:
+ return 1;
+ }
+ };
+ function formatTolerance(format) {
+ switch(format) {
+ case 'RGB565':
+ case 'RGB5_A1':
+ return 255/31;
+ case 'RGBA4':
+ return 255/15;
+ default:
+ return 1;
+ }
+ };
+ return Math.max(formatTolerance(internalformat),
+ formatTolerance(format),
+ typeTolerance(type));
+ }
+
+ return {
+ setupTexturedQuad: setupTexturedQuad,
+ setupTexturedQuadWithCubeMap: setupTexturedQuadWithCubeMap,
+ setupTexturedQuadWith3D: setupTexturedQuadWith3D,
+ setupTexturedQuadWith2DArray: setupTexturedQuadWith2DArray,
+ unpackColorSpacesToTest: unpackColorSpacesToTest,
+ crossProductTestCasesWithUnpackColorSpaces: crossProductTestCasesWithUnpackColorSpaces,
+ tolerance: tolerance
+ };
+
+}());
diff --git a/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-with-image-bitmap-utils.js b/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-with-image-bitmap-utils.js
new file mode 100644
index 0000000000..8faedf9eaa
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/js/tests/tex-image-and-sub-image-with-image-bitmap-utils.js
@@ -0,0 +1,435 @@
+/*
+Copyright (c) 2019 The Khronos Group Inc.
+Use of this source code is governed by an MIT-style license that can be
+found in the LICENSE.txt file.
+*/
+
+
+function runOneIterationImageBitmapTest(useTexSubImage, bindingTarget, program, bitmap, flipY, premultiplyAlpha, optionsVal,
+ internalFormat, pixelFormat, pixelType, gl, tiu, wtu, tolerance)
+{
+ var halfRed = [128, 0, 0];
+ var halfGreen = [0, 128, 0];
+ var redColor = [255, 0, 0];
+ var greenColor = [0, 255, 0];
+ var blackColor = [0, 0, 0];
+
+ switch (gl[pixelFormat]) {
+ case gl.RED:
+ case gl.RED_INTEGER:
+ greenColor = [0, 0, 0];
+ halfGreen = [0, 0, 0];
+ break;
+ case gl.LUMINANCE:
+ case gl.LUMINANCE_ALPHA:
+ redColor = [255, 255, 255];
+ greenColor = [0, 0, 0];
+ halfRed = [128, 128, 128];
+ halfGreen = [0, 0, 0];
+ break;
+ case gl.ALPHA:
+ redColor = [0, 0, 0];
+ greenColor = [0, 0, 0];
+ halfRed = [0, 0, 0];
+ halfGreen = [0, 0, 0];
+ break;
+ default:
+ break;
+ }
+
+ switch (gl[internalFormat]) {
+ case gl.SRGB8:
+ case gl.SRGB8_ALPHA8:
+ halfRed = wtu.sRGBToLinear(halfRed);
+ halfGreen = wtu.sRGBToLinear(halfGreen);
+ break;
+ default:
+ break;
+ }
+
+ var str;
+ if (optionsVal.is3D) {
+ str = 'Testing ' + (useTexSubImage ? 'texSubImage3D' : 'texImage3D') +
+ ' with flipY=' + flipY + ', premultiplyAlpha=' + premultiplyAlpha +
+ ', bindingTarget=' + (bindingTarget == gl.TEXTURE_3D ? 'TEXTURE_3D' : 'TEXTURE_2D_ARRAY');
+ } else {
+ str = 'Testing ' + (useTexSubImage ? 'texSubImage2D' : 'texImage2D') +
+ ' with flipY=' + flipY + ', premultiplyAlpha=' + premultiplyAlpha +
+ ', bindingTarget=' + (bindingTarget == gl.TEXTURE_2D ? 'TEXTURE_2D' : 'TEXTURE_CUBE_MAP');
+ }
+ debug(str);
+ bufferedLogToConsole(str);
+
+ gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
+ // Enable writes to the RGBA channels
+ gl.colorMask(1, 1, 1, 0);
+ var texture = gl.createTexture();
+ // Bind the texture to texture unit 0
+ gl.bindTexture(bindingTarget, texture);
+ // Set up texture parameters
+ gl.texParameteri(bindingTarget, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
+ gl.texParameteri(bindingTarget, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
+ gl.texParameteri(bindingTarget, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
+ gl.texParameteri(bindingTarget, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
+
+ var targets = [bindingTarget];
+ if (bindingTarget == gl.TEXTURE_CUBE_MAP) {
+ targets = [gl.TEXTURE_CUBE_MAP_POSITIVE_X,
+ gl.TEXTURE_CUBE_MAP_NEGATIVE_X,
+ gl.TEXTURE_CUBE_MAP_POSITIVE_Y,
+ gl.TEXTURE_CUBE_MAP_NEGATIVE_Y,
+ gl.TEXTURE_CUBE_MAP_POSITIVE_Z,
+ gl.TEXTURE_CUBE_MAP_NEGATIVE_Z];
+ }
+
+ bufferedLogToConsole("Start uploading the image into a texture");
+ // Upload the image into the texture
+ for (var tt = 0; tt < targets.length; ++tt) {
+ if (optionsVal.is3D) {
+ gl.texImage3D(targets[tt], 0, gl[internalFormat], bitmap.width, bitmap.height, 1 /* depth */, 0,
+ gl[pixelFormat], gl[pixelType], null);
+ gl.texSubImage3D(targets[tt], 0, 0, 0, 0, bitmap.width, bitmap.height, 1,
+ gl[pixelFormat], gl[pixelType], bitmap);
+ } else {
+ if (useTexSubImage) {
+ // Initialize the texture to black first
+ gl.texImage2D(targets[tt], 0, gl[internalFormat], bitmap.width, bitmap.height, 0,
+ gl[pixelFormat], gl[pixelType], null);
+ gl.texSubImage2D(targets[tt], 0, 0, 0, gl[pixelFormat], gl[pixelType], bitmap);
+ } else {
+ gl.texImage2D(targets[tt], 0, gl[internalFormat], gl[pixelFormat], gl[pixelType], bitmap);
+ }
+ }
+ }
+ bufferedLogToConsole("Uploading into texture completed");
+
+ var width = gl.canvas.width;
+ var halfWidth = Math.floor(width / 2);
+ var quarterWidth = Math.floor(halfWidth / 2);
+ var height = gl.canvas.height;
+ var halfHeight = Math.floor(height / 2);
+ var quarterHeight = Math.floor(halfHeight / 2);
+
+ var top = flipY ? quarterHeight : (height - halfHeight + quarterHeight);
+ var bottom = flipY ? (height - halfHeight + quarterHeight) : quarterHeight;
+ var left = quarterWidth;
+ var right = halfWidth + quarterWidth / 2;
+
+ var tl = redColor;
+ var tr = premultiplyAlpha ? ((optionsVal.alpha == 0.5) ? halfRed : (optionsVal.alpha == 1) ? redColor : blackColor) : redColor;
+ var bl = greenColor;
+ var br = premultiplyAlpha ? ((optionsVal.alpha == 0.5) ? halfGreen : (optionsVal.alpha == 1) ? greenColor : blackColor) : greenColor;
+
+ var loc;
+ if (bindingTarget == gl.TEXTURE_CUBE_MAP) {
+ loc = gl.getUniformLocation(program, "face");
+ }
+
+ for (var tt = 0; tt < targets.length; ++tt) {
+ if (bindingTarget == gl.TEXTURE_CUBE_MAP) {
+ gl.uniform1i(loc, targets[tt]);
+ }
+ // Draw the triangles
+ wtu.clearAndDrawUnitQuad(gl, [0, 0, 0, 255]);
+
+ // Check the top pixel and bottom pixel and make sure they have
+ // the right color.
+ let skipAlphaTests = (premultiplyAlpha === undefined && optionsVal.alpha != 1.0);
+ let skipStr = " (Skipping checking right pixel since premultiplyAlpha was undefined and alpha != 1.0)";
+ bufferedLogToConsole("Checking " + (flipY ? "top" : "bottom"));
+ wtu.checkCanvasRect(gl, left, bottom, 2, 2, tl, "shouldBe " + tl + " +/-" + tolerance, tolerance);
+ if (skipAlphaTests) {
+ bufferedLogToConsole(skipStr);
+ } else {
+ wtu.checkCanvasRect(gl, right, bottom, 2, 2, tr, "shouldBe " + tr + " +/-" + tolerance, tolerance);
+ }
+ bufferedLogToConsole("Checking " + (flipY ? "bottom" : "top"));
+ wtu.checkCanvasRect(gl, left, top, 2, 2, bl, "shouldBe " + bl + " +/-" + tolerance, tolerance);
+ if (skipAlphaTests) {
+ bufferedLogToConsole(skipStr);
+ } else {
+ wtu.checkCanvasRect(gl, right, top, 2, 2, br, "shouldBe " + br + " +/-" + tolerance, tolerance);
+ }
+ }
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors");
+}
+
+function resetUnpackParams(gl)
+{
+ gl.pixelStorei(gl.UNPACK_SKIP_PIXELS, 0);
+ gl.pixelStorei(gl.UNPACK_SKIP_ROWS, 0);
+ gl.pixelStorei(gl.UNPACK_SKIP_IMAGES, 0);
+ gl.pixelStorei(gl.UNPACK_ROW_LENGTH, 0);
+ gl.pixelStorei(gl.UNPACK_IMAGE_HEIGHT, 0);
+}
+
+function runOneIterationImageBitmapTestSubSource(useTexSubImage, bindingTarget, program, bitmap, flipY, premultiplyAlpha, optionsVal,
+ internalFormat, pixelFormat, pixelType, gl, tiu, wtu, tolerance)
+{
+ var halfRed = [128, 0, 0];
+ var halfGreen = [0, 128, 0];
+ var redColor = [255, 0, 0];
+ var greenColor = [0, 255, 0];
+ var blackColor = [0, 0, 0];
+
+ switch (gl[pixelFormat]) {
+ case gl.RED:
+ case gl.RED_INTEGER:
+ greenColor = [0, 0, 0];
+ halfGreen = [0, 0, 0];
+ break;
+ case gl.LUMINANCE:
+ case gl.LUMINANCE_ALPHA:
+ redColor = [255, 255, 255];
+ greenColor = [0, 0, 0];
+ halfRed = [128, 128, 128];
+ halfGreen = [0, 0, 0];
+ break;
+ case gl.ALPHA:
+ redColor = [0, 0, 0];
+ greenColor = [0, 0, 0];
+ halfRed = [0, 0, 0];
+ halfGreen = [0, 0, 0];
+ break;
+ default:
+ break;
+ }
+
+ switch (gl[internalFormat]) {
+ case gl.SRGB8:
+ case gl.SRGB8_ALPHA8:
+ halfRed = wtu.sRGBToLinear(halfRed);
+ halfGreen = wtu.sRGBToLinear(halfGreen);
+ break;
+ default:
+ break;
+ }
+
+ var str;
+ if (optionsVal.is3D) {
+ str = 'Testing ' + (useTexSubImage ? 'texSubImage3D' : 'texImage3D') + '[SubSource]' +
+ ' with flipY=' + flipY + ', premultiplyAlpha=' + premultiplyAlpha +
+ ', bindingTarget=TEXTURE_3D';
+ } else {
+ str = 'Testing ' + (useTexSubImage ? 'texSubImage2D' : 'texImage2D') + '[SubSource]' +
+ ' with flipY=' + flipY + ', premultiplyAlpha=' + premultiplyAlpha +
+ ', bindingTarget=TEXTURE_2D';
+ }
+ debug(str);
+ bufferedLogToConsole(str);
+
+ gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
+ // Enable writes to the RGBA channels
+ gl.colorMask(1, 1, 1, 0);
+ var texture = gl.createTexture();
+ // Bind the texture to texture unit 0
+ gl.bindTexture(bindingTarget, texture);
+ // Set up texture parameters
+ gl.texParameteri(bindingTarget, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
+ gl.texParameteri(bindingTarget, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
+ gl.texParameteri(bindingTarget, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
+ gl.texParameteri(bindingTarget, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
+
+ var srcTL = redColor;
+ var srcTR = premultiplyAlpha ? ((optionsVal.alpha == 0.5) ? halfRed : (optionsVal.alpha == 1) ? redColor : blackColor) : redColor;
+ var srcBL = greenColor;
+ var srcBR = premultiplyAlpha ? ((optionsVal.alpha == 0.5) ? halfGreen : (optionsVal.alpha == 1) ? greenColor : blackColor) : greenColor;
+
+ var tl, tr, bl, br;
+
+ bufferedLogToConsole("Start uploading the image into a texture");
+ // Upload the image into the texture
+ if (optionsVal.is3D) {
+ if (useTexSubImage) {
+ // Initialize the texture to black first
+ gl.texImage3D(bindingTarget, 0, gl[internalFormat], bitmap.width, bitmap.height, 1 /* depth */, 0,
+ gl[pixelFormat], gl[pixelType], null);
+ // Only upload the left half image to the right half texture.
+ gl.pixelStorei(gl.UNPACK_SKIP_PIXELS, 0);
+ gl.pixelStorei(gl.UNPACK_SKIP_ROWS, 0);
+ gl.pixelStorei(gl.UNPACK_SKIP_IMAGES, 0);
+ gl.texSubImage3D(bindingTarget, 0, bitmap.width / 2, 0, 0, bitmap.width / 2, bitmap.height, 1,
+ gl[pixelFormat], gl[pixelType], bitmap);
+ tl = blackColor;
+ tr = srcTL;
+ bl = blackColor;
+ br = srcBL;
+ } else {
+ // Only upload the bottom middle quarter image
+ gl.pixelStorei(gl.UNPACK_SKIP_PIXELS, 0);
+ gl.pixelStorei(gl.UNPACK_SKIP_ROWS, bitmap.height / 2);
+ gl.pixelStorei(gl.UNPACK_SKIP_IMAGES, 0);
+ gl.texImage3D(bindingTarget, 0, gl[internalFormat], bitmap.width, bitmap.height / 2, 1 /* depth */, 0,
+ gl[pixelFormat], gl[pixelType], bitmap);
+ if (!flipY) {
+ tl = srcBL;
+ tr = srcBR;
+ bl = srcBL;
+ br = srcBR;
+ } else {
+ tl = srcTL;
+ tr = srcTR;
+ bl = srcTL;
+ br = srcTR;
+ }
+ }
+ } else {
+ if (useTexSubImage) {
+ // Initialize the texture to black first
+ gl.texImage2D(bindingTarget, 0, gl[internalFormat], bitmap.width, bitmap.height, 0,
+ gl[pixelFormat], gl[pixelType], null);
+ // Only upload the left half image to the right half texture.
+ gl.pixelStorei(gl.UNPACK_SKIP_PIXELS, 0);
+ gl.pixelStorei(gl.UNPACK_SKIP_ROWS, 0);
+ gl.texSubImage2D(bindingTarget, 0, bitmap.width / 2, 0, bitmap.width / 2, bitmap.height,
+ gl[pixelFormat], gl[pixelType], bitmap);
+ tl = blackColor;
+ tr = srcTL;
+ bl = blackColor;
+ br = srcBL;
+ } else {
+ // Only upload the right bottom image.
+ gl.pixelStorei(gl.UNPACK_SKIP_PIXELS, bitmap.width / 2);
+ gl.pixelStorei(gl.UNPACK_SKIP_ROWS, bitmap.height / 2);
+ gl.texImage2D(bindingTarget, 0, gl[internalFormat], bitmap.width / 2, bitmap.height / 2, 0,
+ gl[pixelFormat], gl[pixelType], bitmap);
+ resetUnpackParams(gl);
+ if (!flipY) {
+ tl = srcBR;
+ tr = srcBR;
+ bl = srcBR;
+ br = srcBR;
+ } else {
+ tl = srcTR;
+ tr = srcTR;
+ bl = srcTR;
+ br = srcTR;
+ }
+ }
+ }
+ bufferedLogToConsole("Uploading into texture completed");
+
+ var width = gl.canvas.width;
+ var halfWidth = Math.floor(width / 2);
+ var quarterWidth = Math.floor(halfWidth / 2);
+ var height = gl.canvas.height;
+ var halfHeight = Math.floor(height / 2);
+ var quarterHeight = Math.floor(halfHeight / 2);
+
+ var top = flipY ? quarterHeight : (height - halfHeight + quarterHeight);
+ var bottom = flipY ? (height - halfHeight + quarterHeight) : quarterHeight;
+
+ // Draw the triangles
+ wtu.clearAndDrawUnitQuad(gl, [0, 0, 0, 255]);
+
+ // Check the top pixel and bottom pixel and make sure they have
+ // the right color.
+ // For right side, check pixels closer to left to avoid border in the video tests.
+ let skipAlphaTests = (premultiplyAlpha === undefined && optionsVal.alpha != 1.0);
+ let skipStr = " (Skipping checking right pixel since premultiplyAlpha was undefined and alpha != 1.0)";
+ bufferedLogToConsole("Checking " + (flipY ? "top" : "bottom"));
+ wtu.checkCanvasRect(gl, quarterWidth, bottom, 2, 2, tl, "shouldBe " + tl + " +/-" + tolerance, tolerance);
+ if (skipAlphaTests) {
+ bufferedLogToConsole(skipStr);
+ } else {
+ wtu.checkCanvasRect(gl, halfWidth + quarterWidth / 2, bottom, 2, 2, tr, "shouldBe " + tr + " +/-" + tolerance, tolerance);
+ }
+ bufferedLogToConsole("Checking " + (flipY ? "bottom" : "top"));
+ wtu.checkCanvasRect(gl, quarterWidth, top, 2, 2, bl, "shouldBe " + bl + " +/-" + tolerance, tolerance);
+ if (skipAlphaTests) {
+ bufferedLogToConsole(skipStr);
+ } else {
+ wtu.checkCanvasRect(gl, halfWidth + quarterWidth / 2, top, 2, 2, br, "shouldBe " + br + " +/-" + tolerance, tolerance);
+ }
+
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors");
+}
+
+function runTestOnBindingTargetImageBitmap(bindingTarget, program, cases, optionsVal,
+ internalFormat, pixelFormat, pixelType, gl, tiu, wtu, tolerance)
+{
+ cases.forEach(x => {
+ runOneIterationImageBitmapTest(x.sub, bindingTarget, program, x.bitmap,
+ x.bitmap.flipY, x.bitmap.premultiply, optionsVal, internalFormat, pixelFormat, pixelType, gl, tiu, wtu, tolerance);
+ });
+
+ if (wtu.getDefault3DContextVersion() <= 1 ||
+ (bindingTarget == gl.TEXTURE_CUBE_MAP || bindingTarget == gl.TEXTURE_2D_ARRAY))
+ {
+ // Skip testing source sub region on TEXTURE_CUBE_MAP and TEXTURE_2D_ARRAY on WebGL2 to save
+ // running time.
+ return;
+ }
+
+ cases.forEach(x => {
+ runOneIterationImageBitmapTestSubSource(x.sub, bindingTarget, program, x.bitmap,
+ x.bitmap.flipY, x.bitmap.premultiply, optionsVal, internalFormat, pixelFormat, pixelType, gl, tiu, wtu, tolerance);
+ });
+}
+
+function runImageBitmapTestInternal(bitmaps, alphaVal, internalFormat, pixelFormat, pixelType, gl, tiu, wtu, is3D, tolerance)
+{
+ var cases = [];
+ bitmaps.forEach(bitmap => {
+ cases.push({bitmap: bitmap, sub: false});
+ cases.push({bitmap: bitmap, sub: true});
+ });
+
+ var optionsVal = {alpha: alphaVal, is3D: is3D};
+ var program;
+ if (is3D) {
+ program = tiu.setupTexturedQuadWith3D(gl, internalFormat);
+ runTestOnBindingTargetImageBitmap(gl.TEXTURE_3D, program, cases, optionsVal,
+ internalFormat, pixelFormat, pixelType, gl, tiu, wtu, tolerance);
+ } else {
+ program = tiu.setupTexturedQuad(gl, internalFormat);
+ runTestOnBindingTargetImageBitmap(gl.TEXTURE_2D, program, cases, optionsVal,
+ internalFormat, pixelFormat, pixelType, gl, tiu, wtu, tolerance);
+ }
+
+ // cube map texture must be square
+ if (bitmaps[0].width == bitmaps[0].height) {
+ if (is3D) {
+ program = tiu.setupTexturedQuadWith2DArray(gl, internalFormat);
+ runTestOnBindingTargetImageBitmap(gl.TEXTURE_2D_ARRAY, program, cases, optionsVal,
+ internalFormat, pixelFormat, pixelType, gl, tiu, wtu, tolerance);
+ } else {
+ program = tiu.setupTexturedQuadWithCubeMap(gl, internalFormat);
+ runTestOnBindingTargetImageBitmap(gl.TEXTURE_CUBE_MAP, program, cases, optionsVal,
+ internalFormat, pixelFormat, pixelType, gl, tiu, wtu, tolerance);
+ }
+ }
+}
+
+function runImageBitmapTest(source, alphaVal, internalFormat, pixelFormat, pixelType, gl, tiu, wtu, is3D, opt_tolerance)
+{
+ if (opt_tolerance === undefined) {
+ opt_tolerance = 10;
+ }
+ var p1 = createImageBitmap(source, {imageOrientation: "none", premultiplyAlpha: "premultiply"})
+ .then(cur => { cur.flipY = false; cur.premultiply = true; return cur; });
+ var p2 = createImageBitmap(source, {imageOrientation: "none", premultiplyAlpha: "none"})
+ .then(cur => { cur.flipY = false; cur.premultiply = false; return cur; });
+ var p3 = createImageBitmap(source, {imageOrientation: "flipY", premultiplyAlpha: "premultiply"})
+ .then(cur => { cur.flipY = true; cur.premultiply = true; return cur; });
+ var p4 = createImageBitmap(source, {imageOrientation: "flipY", premultiplyAlpha: "none"})
+ .then(cur => { cur.flipY = true; cur.premultiply = false; return cur; });
+ return Promise.all([p1, p2, p3, p4])
+ .catch( () => {
+ testPassed("createImageBitmap with options may be rejected if it is not supported. Retrying without options.");
+ // The ImageBitmap's premultiplyAlpha setting will implicitly be
+ // "default", and per spec:
+ // https://html.spec.whatwg.org/multipage/imagebitmap-and-animations.html#cropped-to-the-source-rectangle-with-formatting
+ // this value is implementation-dependent (either premultiplied or
+ // not). Skip testing the quadrants which have alpha != 1.0.
+ var p = createImageBitmap(source)
+ .then(cur => { cur.flipY = false; cur.premultiply = undefined; return cur; });
+ return Promise.all([p]);
+ }).then( bitmaps => {
+ bufferedLogToConsole("All createImageBitmap promises are resolved");
+ runImageBitmapTestInternal(bitmaps, alphaVal, internalFormat, pixelFormat, pixelType, gl, tiu, wtu, is3D, opt_tolerance);
+ }, (e) => {
+ // This will fail here when running from file:// instead of https://.
+ testFailed("createImageBitmap(source) failed: \"" + e.message + "\"");
+ });
+}
diff --git a/dom/canvas/test/webgl-conf/checkout/js/tests/tex-input-validation.js b/dom/canvas/test/webgl-conf/checkout/js/tests/tex-input-validation.js
new file mode 100644
index 0000000000..22261afdb4
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/js/tests/tex-input-validation.js
@@ -0,0 +1,563 @@
+/*
+Copyright (c) 2019 The Khronos Group Inc.
+Use of this source code is governed by an MIT-style license that can be
+found in the LICENSE.txt file.
+*/
+
+// This test relies on the surrounding web page defining a variable
+// "contextVersion" which indicates what version of WebGL it's running
+// on -- 1 for WebGL 1.0, 2 for WebGL 2.0, etc.
+
+"use strict";
+description("Validate tex functions input parameters");
+
+var wtu = WebGLTestUtils;
+var gl = null;
+var tex = null;
+var error = 0;
+
+shouldBeNonNull("gl = wtu.create3DContext(undefined, undefined, contextVersion)");
+shouldBeNonNull("tex = gl.createTexture()");
+gl.bindTexture(gl.TEXTURE_2D, tex);
+wtu.glErrorShouldBe(gl, gl.NO_ERROR);
+
+function enumToString(value) {
+ return wtu.glEnumToString(gl, value);
+}
+
+function testTexParameter(testCase) {
+ var msg = "paramName: " + enumToString(testCase.pname);
+ error = testCase.expectedError;
+ gl.texParameteri(testCase.target, testCase.pname, testCase.param);
+ wtu.glErrorShouldBe(gl, error, msg);
+ gl.texParameterf(testCase.target, testCase.pname, testCase.param);
+ wtu.glErrorShouldBe(gl, error, msg);
+}
+
+function testGetTexParameter(testCase) {
+ var msg = "paramName: " + enumToString(testCase.pname);
+ error = testCase.expectedError;
+ gl.getTexParameter(testCase.target, testCase.pname);
+ wtu.glErrorShouldBe(gl, error, msg);
+}
+
+function testTexImage2D(testCase) {
+ var level = 0;
+ var width = 16;
+ var height = 16;
+ var msg = " internalFormat: " + enumToString(testCase.internalFormat) +
+ " target: " + enumToString(testCase.target) +
+ " format: " + enumToString(testCase.format) +
+ " type: " + enumToString(testCase.type) +
+ " border: " + testCase.border;
+
+ gl.texImage2D(testCase.target, level, testCase.internalFormat, width, height, testCase.border, testCase.format, testCase.type, null);
+ error = testCase.expectedError;
+ wtu.glErrorShouldBe(gl, error, msg);
+}
+
+function testTexSubImage2D(testCase) {
+ var level = 0;
+ var xoffset = 0;
+ var yoffset = 0;
+ var width = 16;
+ var height = 16;
+ var msg = " format: " + enumToString(testCase.format) +
+ " type: " + enumToString(testCase.type);
+ var array = new Uint8Array(width * height * 4);
+
+ gl.texSubImage2D(testCase.target, level, xoffset, yoffset, width, height, testCase.format, testCase.type, array);
+ error = testCase.expectedError;
+ wtu.glErrorShouldBe(gl, error, msg);
+}
+
+function testCopyTexImage2D(testCase) {
+ var level = 0;
+ var x = 0;
+ var y = 0;
+ var width = 16;
+ var height = 16;
+ var msg = " colorBufferFormat: " + enumToString(testCase.colorBufferFormat) +
+ " internalFormat: " + enumToString(testCase.internalFormat) +
+ " target: " + enumToString(testCase.target) +
+ " border: " + testCase.border;
+
+ gl.renderbufferStorage(gl.RENDERBUFFER, testCase.colorBufferFormat, width, height);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR);
+ shouldBe("gl.checkFramebufferStatus(gl.FRAMEBUFFER)", "gl.FRAMEBUFFER_COMPLETE");
+
+ gl.copyTexImage2D(testCase.target, level, testCase.internalFormat, x, y, width, height, testCase.border);
+ error = testCase.expectedError;
+ wtu.glErrorShouldBe(gl, error, msg);
+}
+
+function testCopyTexSubImage2D(testCase) {
+ var level = 0;
+ var x = 0;
+ var y = 0;
+ var width = 16;
+ var height = 16;
+ var xoffset = 0;
+ var yoffset = 0;
+ var border = 0;
+ var type = gl.UNSIGNED_BYTE;
+ var msg = " colorBufferFormat: " + enumToString(testCase.colorBufferFormat) +
+ " internalFormat: " + enumToString(testCase.internalFormat) +
+ " target: " + enumToString(testCase.target);
+
+ gl.renderbufferStorage(gl.RENDERBUFFER, testCase.colorBufferFormat, width, height);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR);
+ shouldBe("gl.checkFramebufferStatus(gl.FRAMEBUFFER)", "gl.FRAMEBUFFER_COMPLETE");
+
+ gl.texImage2D(testCase.target, level, testCase.internalFormat, xoffset + width, yoffset + height, border, testCase.internalFormat, type, null);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR);
+
+ gl.copyTexSubImage2D(testCase.target, level, xoffset, yoffset, x, y, width, height);
+ error = testCase.expectedError;
+ wtu.glErrorShouldBe(gl, error, msg);
+}
+
+function testCopyFromInternalFBO(testCase) {
+ var target = gl.TEXTURE_2D;
+ var level = 0;
+ var x = 0;
+ var y = 0;
+ var width = 16;
+ var height = 16;
+ var xoffset = 0;
+ var yoffset = 0;
+ var border = 0;
+ var type = gl.UNSIGNED_BYTE;
+ var msg = " colorBufferFormat: " + enumToString(testCase.contextAlpha ? gl.RGBA : gl.RGB) +
+ " internalFormat: " + enumToString(testCase.internalFormat);
+
+ if (testCase.contextAlpha) {
+ gl = wtu.create3DContext(null, { alpha: true }, contextVersion);
+ } else {
+ gl = wtu.create3DContext(null, { alpha: false }, contextVersion);
+ }
+ shouldBeNonNull("gl");
+ shouldBeNonNull("tex = gl.createTexture()");
+ gl.bindTexture(target, tex);
+ if (testCase.subImage) {
+ gl.texImage2D(target, level, testCase.internalFormat, xoffset + width, yoffset + height, border, testCase.internalFormat, type, null);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR);
+ gl.copyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, height);
+ } else {
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR);
+ gl.copyTexImage2D(target, level, testCase.internalFormat, x, y, width, height, border);
+ }
+ error = testCase.expectedError;
+ wtu.glErrorShouldBe(gl, error, msg);
+}
+
+// Only for WebGL2.0.
+function testTexImage3D(testCase) {
+ var level = 0;
+ var width = 16;
+ var height = 16;
+ var depth = 16;
+ var msg = " internalFormat: " + enumToString(testCase.internalFormat) +
+ " target: " + enumToString(testCase.target) +
+ " format: " + enumToString(testCase.format) +
+ " type: " + enumToString(testCase.type) +
+ " border: " + testCase.border;
+
+ gl.texImage3D(testCase.target, level, testCase.internalFormat, width, height, depth, testCase.border, testCase.format, testCase.type, null);
+ error = testCase.expectedError;
+ wtu.glErrorShouldBe(gl, error, msg);
+}
+
+function testTexSubImage3D(testCase) {
+ var level = 0;
+ var xoffset = 0;
+ var yoffset = 0;
+ var zoffset = 0;
+ var width = 16;
+ var height = 16;
+ var depth = 16;
+ var msg = " format: " + enumToString(testCase.format) +
+ " type: " + enumToString(testCase.type);
+ var array = new Uint8Array(width * height * depth * 4);
+
+ gl.texSubImage3D(testCase.target, level, xoffset, yoffset, zoffset, width, height, depth, testCase.format, testCase.type, array);
+ error = testCase.expectedError;
+ wtu.glErrorShouldBe(gl, error, msg);
+}
+
+
+// Start checking.
+
+debug("");
+debug("Checking TexParameter: a set of inputs that are valid in GL but invalid in WebGL");
+
+testCases = [
+ { target: 0x0DE0, // GL_TEXTURE_1D
+ pname: gl.TEXTURE_WRAP_T,
+ param: gl.REPEAT,
+ expectedError: gl.INVALID_ENUM },
+ { target: gl.TEXTURE_2D,
+ pname: gl.TEXTURE_WRAP_T,
+ param: 0x2900, // GL_CLAMP
+ expectedError: gl.INVALID_ENUM },
+ { target: gl.TEXTURE_2D,
+ pname: gl.TEXTURE_WRAP_T,
+ param: gl.REPEAT,
+ expectedError: gl.NO_ERROR }
+];
+
+if (contextVersion < 2) {
+ testCases = testCases.concat([
+ { target: gl.TEXTURE_2D,
+ pname: 0x813A, // GL_TEXTURE_MIN_LOD
+ param: 0,
+ expectedError: gl.INVALID_ENUM }
+ ]);
+} else {
+ testCases = testCases.concat([
+ { target: gl.TEXTURE_2D,
+ pname: 0x8E42, // GL_TEXTURE_SWIZZLE_R
+ param: 0x1903, // GL_RED
+ expectedError: gl.INVALID_ENUM },
+ { target: gl.TEXTURE_2D,
+ pname: 0x8072, // GL_TEXTURE_WRAP_R
+ param: 0x2900, // GL_CLAMP
+ expectedError: gl.INVALID_ENUM }
+ ]);
+}
+
+for (var ii = 0; ii < testCases.length; ++ii) {
+ testTexParameter(testCases[ii]);
+}
+
+debug("");
+debug("Checking GetTexParameter: a set of inputs that are valid in GL but invalid in WebGL");
+
+testCases = [
+ { target: 0x0DE0, // GL_TEXTURE_1D
+ pname: gl.TEXTURE_WRAP_T,
+ expectedError: gl.INVALID_ENUM },
+ { target: gl.TEXTURE_2D,
+ pname: gl.TEXTURE_WRAP_T,
+ expectedError: gl.NO_ERROR }
+];
+
+if (contextVersion < 2) {
+ testCases = testCases.concat([
+ { target: gl.TEXTURE_2D,
+ pname: 0x813A, // GL_TEXTURE_MIN_LOD
+ expectedError: gl.INVALID_ENUM }
+ ]);
+} else {
+ testCases = testCases.concat([
+ { target: gl.TEXTURE_2D,
+ pname: 0x8E42, // GL_TEXTURE_SWIZZLE_R
+ expectedError: gl.INVALID_ENUM }
+ ]);
+}
+
+for (var ii = 0; ii < testCases.length; ++ii) {
+ testGetTexParameter(testCases[ii]);
+}
+
+debug("");
+debug("Checking TexImage2D: a set of inputs that are valid in GL but invalid in WebGL");
+
+var testCases = [
+ { target: 0x8064, // GL_PROXY_TEXTURE_2D
+ internalFormat: gl.RGBA,
+ border: 0,
+ format: gl.RGBA,
+ type: gl.UNSIGNED_BYTE,
+ expectedError: gl.INVALID_ENUM },
+ { target: gl.TEXTURE_2D,
+ internalFormat: 0x1903, // GL_RED
+ border: 0,
+ format: 0x1903, // GL_RED
+ type: gl.UNSIGNED_BYTE,
+ expectedError: [gl.INVALID_ENUM, gl.INVALID_VALUE, gl.INVALID_OPERATION] },
+ { target: gl.TEXTURE_2D,
+ internalFormat: gl.RGBA,
+ border: 1,
+ format: gl.RGBA,
+ type: gl.UNSIGNED_BYTE,
+ expectedError: gl.INVALID_VALUE },
+ { target: gl.TEXTURE_2D,
+ internalFormat: gl.RGBA,
+ border: 0,
+ format: gl.RGB,
+ type: gl.UNSIGNED_BYTE,
+ expectedError: gl.INVALID_OPERATION },
+ { target: gl.TEXTURE_2D,
+ internalFormat: gl.RGBA,
+ border: 0,
+ format: gl.RGBA,
+ type: gl.UNSIGNED_BYTE,
+ expectedError: gl.NO_ERROR }
+];
+
+if (contextVersion < 2) {
+ testCases = testCases.concat([
+ { target: gl.TEXTURE_2D,
+ internalFormat: gl.RGBA,
+ border: 0,
+ format: gl.RGBA,
+ type: gl.BYTE,
+ expectedError: gl.INVALID_ENUM }
+ ]);
+} else {
+ testCases = testCases.concat([
+ { target: gl.TEXTURE_2D,
+ internalFormat: gl.RGBA,
+ border: 0,
+ format: gl.RGBA,
+ type: gl.BYTE,
+ expectedError: gl.INVALID_OPERATION },
+ { target: gl.TEXTURE_3D,
+ internalFormat: gl.RGBA,
+ border: 0,
+ format: gl.RGBA,
+ type: gl.UNSIGNED_BYTE,
+ expectedError: gl.INVALID_ENUM }
+ ]);
+}
+
+for (var ii = 0; ii < testCases.length; ++ii) {
+ testTexImage2D(testCases[ii]);
+}
+
+debug("");
+debug("Checking TexSubImage2D: a set of inputs that are valid in GL but invalid in WebGL");
+
+testCases = [
+ { target: gl.TEXTURE_2D,
+ format: gl.RGBA,
+ type: gl.UNSIGNED_BYTE,
+ expectedError: gl.NO_ERROR }
+];
+
+if (contextVersion < 2) {
+ testCases = testCases.concat([
+ { target: gl.TEXTURE_2D,
+ format: 0x1903, // GL_RED
+ type: gl.UNSIGNED_BYTE,
+ expectedError: [gl.INVALID_ENUM, gl.INVALID_OPERATION] },
+ { target: gl.TEXTURE_2D,
+ format: gl.RGBA,
+ type: gl.BYTE,
+ expectedError: [gl.INVALID_ENUM, gl.INVALID_OPERATION] }
+ ]);
+} else {
+ testCases = testCases.concat([
+ { target: gl.TEXTURE_2D,
+ format: gl.RED,
+ type: gl.UNSIGNED_BYTE,
+ expectedError: gl.INVALID_OPERATION },
+ { target: gl.TEXTURE_2D,
+ format: gl.RGBA,
+ type: gl.BYTE,
+ expectedError: gl.INVALID_OPERATION },
+ { target: gl.TEXTURE_3D,
+ format: gl.RGBA,
+ type: gl.UNSIGNED_BYTE,
+ expectedError: gl.INVALID_ENUM },
+ ]);
+}
+
+for (var ii = 0; ii < testCases.length; ++ii) {
+ testTexSubImage2D(testCases[ii]);
+}
+
+debug("");
+debug("Checking CopyTexImage2D: a set of inputs that are valid in GL but invalid in WebGL");
+
+var colorBuffer = null;
+var fbo = null;
+
+shouldBeNonNull("fbo = gl.createFramebuffer()");
+gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
+shouldBeNonNull("colorBuffer = gl.createRenderbuffer()");
+gl.bindRenderbuffer(gl.RENDERBUFFER, colorBuffer);
+gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, colorBuffer);
+wtu.glErrorShouldBe(gl, gl.NO_ERROR);
+
+testCases = [
+ { target: gl.TEXTURE_2D,
+ colorBufferFormat: gl.RGB565,
+ internalFormat: 0x8054, // GL_RGB16
+ border: 0,
+ expectedError: gl.INVALID_ENUM },
+ { target: gl.TEXTURE_2D,
+ colorBufferFormat: gl.RGB565,
+ internalFormat: gl.RGBA,
+ border: 1,
+ expectedError: gl.INVALID_VALUE },
+ { target: gl.TEXTURE_2D,
+ colorBufferFormat: gl.RGB565,
+ internalFormat: gl.RGBA,
+ border: 0,
+ expectedError: gl.INVALID_OPERATION },
+ { target: gl.TEXTURE_2D,
+ colorBufferFormat: gl.RGB565,
+ internalFormat: gl.RGB,
+ border: 0,
+ expectedError: gl.NO_ERROR }
+];
+
+if (contextVersion > 1) {
+ testCases = testCases.concat([
+ { target: gl.TEXTURE_3D,
+ colorBufferFormat: gl.RGB5_A1,
+ internalFormat: gl.RGBA,
+ border: 0,
+ expectedError: gl.INVALID_ENUM }
+ ]);
+}
+
+for (var ii = 0; ii < testCases.length; ++ii) {
+ testCopyTexImage2D(testCases[ii]);
+}
+
+debug("");
+debug("Checking CopyTexSubImage2D: a set of inputs that are valid in GL but invalid in WebGL");
+
+testCases = [
+ { target: gl.TEXTURE_2D,
+ colorBufferFormat: gl.RGB5_A1,
+ internalFormat: gl.RGBA,
+ expectedError: gl.NO_ERROR },
+ { target: gl.TEXTURE_2D,
+ colorBufferFormat: gl.RGB565,
+ internalFormat: gl.RGBA,
+ expectedError: gl.INVALID_OPERATION }
+];
+
+for (var ii = 0; ii < testCases.length; ++ii) {
+ testCopyTexSubImage2D(testCases[ii]);
+}
+
+debug("");
+debug("Checking CopyTex{Sub}Image2D: copy from WebGL internal framebuffer");
+
+testCases = [
+ { contextAlpha: true,
+ internalFormat: gl.RGBA,
+ subImage: false,
+ expectedError: gl.NO_ERROR },
+ { contextAlpha: false,
+ internalFormat: gl.RGBA,
+ subImage: false,
+ expectedError: gl.INVALID_OPERATION },
+ { contextAlpha: true,
+ internalFormat: gl.RGBA,
+ subImage: true,
+ expectedError: gl.NO_ERROR },
+ { contextAlpha: false,
+ internalFormat: gl.RGBA,
+ subImage: true,
+ expectedError: gl.INVALID_OPERATION }
+];
+
+for (var ii = 0; ii < testCases.length; ++ii) {
+ testCopyFromInternalFBO(testCases[ii]);
+}
+
+if (contextVersion > 1) {
+// Create new texture for testing api of WebGL 2.0.
+shouldBeNonNull("tex = gl.createTexture()");
+gl.bindTexture(gl.TEXTURE_3D, tex);
+wtu.glErrorShouldBe(gl, gl.NO_ERROR);
+
+debug("");
+debug("Checking TexImage3D: a set of inputs that are valid in GL but invalid in WebGL");
+
+var testCases = [
+ { target: 0x8070, // GL_PROXY_TEXTURE_3D
+ internalFormat: gl.RGBA,
+ border: 0,
+ format: gl.RGBA,
+ type: gl.UNSIGNED_BYTE,
+ expectedError: gl.INVALID_ENUM },
+ { target: gl.TEXTURE_3D,
+ internalFormat: gl.RGBA,
+ border: 0,
+ format: gl.RGB,
+ type: gl.UNSIGNED_BYTE,
+ expectedError: gl.INVALID_OPERATION },
+ { target: gl.TEXTURE_3D,
+ internalFormat: gl.RGBA,
+ border: 0,
+ format: gl.RGBA,
+ type: gl.BYTE,
+ expectedError: gl.INVALID_OPERATION},
+ { target: gl.TEXTURE_3D,
+ internalFormat: gl.RGBA,
+ border: 0,
+ format: gl.RGBA,
+ type: gl.UNSIGNED_BYTE,
+ expectedError: gl.NO_ERROR }
+];
+
+for (var ii = 0; ii < testCases.length; ++ii) {
+ testTexImage3D(testCases[ii]);
+}
+
+debug("");
+debug("Checking TexImage3D: bad target, internalformats, formats, types");
+
+var testCases = [
+ { target: gl.TEXTURE_2D,
+ internalFormat: gl.RGBA,
+ border: 0,
+ format: gl.RGBA,
+ type: gl.UNSIGNED_BYTE,
+ expectedError: gl.INVALID_ENUM },
+ { target: gl.TEXTURE_3D,
+ internalFormat: gl.RG,
+ border: 0,
+ format: gl.RGBA,
+ type: gl.UNSIGNED_BYTE,
+ expectedError: [gl.INVALID_VALUE, gl.INVALID_OPERATION]},
+ { target: gl.TEXTURE_3D,
+ internalFormat: gl.RGBA,
+ border: 0,
+ format: gl.RG8,
+ type: gl.UNSIGNED_BYTE,
+ expectedError: gl.INVALID_ENUM },
+ { target: gl.TEXTURE_3D,
+ internalFormat: gl.RGBA,
+ border: 0,
+ format: gl.RGBA,
+ type: gl.INT,
+ expectedError: gl.INVALID_OPERATION},
+];
+
+for (var ii = 0; ii < testCases.length; ++ii) {
+ testTexImage3D(testCases[ii]);
+}
+
+debug("");
+debug("Checking TexSubImage3D: a set of inputs that are valid in GL but invalid in WebGL");
+
+testCases = [
+ { target: gl.TEXTURE_3D,
+ format: 0x80E0, // GL_BGR
+ type: gl.UNSIGNED_BYTE,
+ expectedError: gl.INVALID_ENUM },
+ { target: gl.TEXTURE_3D,
+ format: gl.RGBA,
+ type: 0x8032, // GL_UNSIGNED_BYTE_3_3_2
+ expectedError: gl.INVALID_ENUM },
+ { target: gl.TEXTURE_3D,
+ format: gl.RGBA,
+ type: gl.UNSIGNED_BYTE,
+ expectedError: gl.NO_ERROR }
+];
+
+for (var ii = 0; ii < testCases.length; ++ii) {
+ testTexSubImage3D(testCases[ii]);
+}
+
+}
+
+var successfullyParsed = true;
diff --git a/dom/canvas/test/webgl-conf/checkout/js/tests/texture-corner-case-videos.js b/dom/canvas/test/webgl-conf/checkout/js/tests/texture-corner-case-videos.js
new file mode 100644
index 0000000000..a80da8023d
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/js/tests/texture-corner-case-videos.js
@@ -0,0 +1,299 @@
+/*
+Copyright (c) 2019 The Khronos Group Inc.
+Use of this source code is governed by an MIT-style license that can be
+found in the LICENSE.txt file.
+*/
+
+// This block needs to be outside the onload handler in order for this
+// test to run reliably in WebKit's test harness (at least the
+// Chromium port). https://bugs.webkit.org/show_bug.cgi?id=87448
+initTestingHarness();
+
+var old = debug;
+var debug = function(msg) {
+ bufferedLogToConsole(msg);
+ old(msg);
+};
+
+function generateTest(desc,
+ internalFormat, pixelFormat, pixelType, prologue, resourcePath, defaultContextVersion,
+ videos) {
+ var wtu = WebGLTestUtils;
+ var tiu = TexImageUtils;
+ var gl = null;
+ var c2d = null;
+ var successfullyParsed = false;
+ var redColor = [255, 0, 0];
+ var greenColor = [0, 255, 0];
+ var currentTolerance = 0;
+
+ function init()
+ {
+ description(desc + ' (' + internalFormat + '/' + pixelFormat + '/' + pixelType + ')');
+
+ // Set the default context version while still allowing the webglVersion URL query string to override it.
+ wtu.setDefault3DContextVersion(defaultContextVersion);
+ gl = wtu.create3DContext("example");
+
+ // Subsume 2D canvas tests into this test case since they usually go down similar code paths and
+ // these tests are usually already set up to run with hardware accelerated video decoding.
+ c2d = document.getElementById("c2d").getContext("2d");
+
+ if (!prologue(gl)) {
+ finishTest();
+ return;
+ }
+
+ switch (gl[pixelFormat]) {
+ case gl.RED:
+ case gl.RED_INTEGER:
+ greenColor = [0, 0, 0];
+ break;
+ default:
+ break;
+ }
+
+ gl.clearColor(0,0,0,1);
+ gl.clearDepth(1);
+
+ runAllTests();
+ }
+
+ function runOneIteration(videoElement, useTexSubImage2D, flipY, topColor, bottomColor, sourceSubRectangle, program, bindingTarget)
+ {
+ sourceSubRectangleString = '';
+ if (sourceSubRectangle) {
+ sourceSubRectangleString = ' sourceSubRectangle=' + sourceSubRectangle;
+ }
+ debug('Testing ' + (useTexSubImage2D ? 'texSubImage2D' : 'texImage2D') +
+ ' with flipY=' + flipY + ' bindingTarget=' +
+ (bindingTarget == gl.TEXTURE_2D ? 'TEXTURE_2D' : 'TEXTURE_CUBE_MAP') +
+ sourceSubRectangleString);
+ gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
+ // Disable any writes to the alpha channel
+ gl.colorMask(1, 1, 1, 0);
+ var texture = gl.createTexture();
+ // Bind the texture to texture unit 0
+ gl.bindTexture(bindingTarget, texture);
+ // Set up texture parameters
+ gl.texParameteri(bindingTarget, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
+ gl.texParameteri(bindingTarget, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
+ gl.texParameteri(bindingTarget, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
+ gl.texParameteri(bindingTarget, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
+ // Set up pixel store parameters
+ gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, flipY);
+ gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, false);
+ var targets = [gl.TEXTURE_2D];
+ if (bindingTarget == gl.TEXTURE_CUBE_MAP) {
+ targets = [gl.TEXTURE_CUBE_MAP_POSITIVE_X,
+ gl.TEXTURE_CUBE_MAP_NEGATIVE_X,
+ gl.TEXTURE_CUBE_MAP_POSITIVE_Y,
+ gl.TEXTURE_CUBE_MAP_NEGATIVE_Y,
+ gl.TEXTURE_CUBE_MAP_POSITIVE_Z,
+ gl.TEXTURE_CUBE_MAP_NEGATIVE_Z];
+ }
+ // Handle the source sub-rectangle if specified (WebGL 2.0 only)
+ if (sourceSubRectangle) {
+ gl.pixelStorei(gl.UNPACK_SKIP_PIXELS, sourceSubRectangle[0]);
+ gl.pixelStorei(gl.UNPACK_SKIP_ROWS, sourceSubRectangle[1]);
+ }
+ // Upload the videoElement into the texture
+ for (var tt = 0; tt < targets.length; ++tt) {
+ if (sourceSubRectangle) {
+ // Initialize the texture to black first
+ if (useTexSubImage2D) {
+ // Skip sub-rectangle tests for cube map textures for the moment.
+ if (bindingTarget == gl.TEXTURE_CUBE_MAP) {
+ continue;
+ }
+ gl.texImage2D(targets[tt], 0, gl[internalFormat],
+ sourceSubRectangle[2], sourceSubRectangle[3], 0,
+ gl[pixelFormat], gl[pixelType], null);
+ gl.texSubImage2D(targets[tt], 0, 0, 0,
+ sourceSubRectangle[2], sourceSubRectangle[3],
+ gl[pixelFormat], gl[pixelType], videoElement);
+ } else {
+ gl.texImage2D(targets[tt], 0, gl[internalFormat],
+ sourceSubRectangle[2], sourceSubRectangle[3], 0,
+ gl[pixelFormat], gl[pixelType], videoElement);
+ }
+ } else {
+ // Initialize the texture to black first
+ if (useTexSubImage2D) {
+ var width = videoElement.videoWidth;
+ var height = videoElement.videoHeight;
+ if (bindingTarget == gl.TEXTURE_CUBE_MAP) {
+ // cube map texture must be square.
+ width = Math.max(width, height);
+ height = width;
+ }
+ gl.texImage2D(targets[tt], 0, gl[internalFormat],
+ width, height, 0,
+ gl[pixelFormat], gl[pixelType], null);
+ gl.texSubImage2D(targets[tt], 0, 0, 0, gl[pixelFormat], gl[pixelType], videoElement);
+ } else {
+ gl.texImage2D(targets[tt], 0, gl[internalFormat], gl[pixelFormat], gl[pixelType], videoElement);
+ }
+ }
+ }
+
+ if (sourceSubRectangle) {
+ gl.pixelStorei(gl.UNPACK_SKIP_PIXELS, 0);
+ gl.pixelStorei(gl.UNPACK_SKIP_ROWS, 0);
+ }
+
+ var c = document.createElement("canvas");
+ c.width = 16;
+ c.height = 16;
+ c.style.border = "1px solid black";
+ var ctx = c.getContext("2d");
+ ctx.drawImage(videoElement, 0, 0, 16, 16);
+ document.body.appendChild(c);
+
+ var loc;
+ if (bindingTarget == gl.TEXTURE_CUBE_MAP) {
+ loc = gl.getUniformLocation(program, "face");
+ }
+
+ for (var tt = 0; tt < targets.length; ++tt) {
+ if (bindingTarget == gl.TEXTURE_CUBE_MAP) {
+ gl.uniform1i(loc, targets[tt]);
+ }
+ // Draw the triangles
+ wtu.clearAndDrawUnitQuad(gl, [0, 0, 0, 255]);
+ // Check a few pixels near the top and bottom and make sure they have
+ // the right color.
+ var tolerance = currentTolerance;
+ debug("Checking lower left corner");
+ wtu.checkCanvasRect(gl, 4, 4, 2, 2, bottomColor,
+ "shouldBe " + bottomColor, tolerance);
+ debug("Checking upper left corner");
+ wtu.checkCanvasRect(gl, 4, gl.canvas.height - 8, 2, 2, topColor,
+ "shouldBe " + topColor, tolerance);
+
+ // Expose bug http://crbug.com/733172.
+ if (sourceSubRectangle) {
+ // Skip sub-rectangle tests for cube map textures for the moment.
+ if (bindingTarget == gl.TEXTURE_CUBE_MAP) {
+ continue;
+ }
+ gl.texSubImage2D(targets[tt], 0, 0, 0,
+ sourceSubRectangle[2], sourceSubRectangle[3],
+ gl[pixelFormat], gl[pixelType], videoElement);
+ } else {
+ gl.texSubImage2D(targets[tt], 0, 0, 0, gl[pixelFormat], gl[pixelType], videoElement);
+ }
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors");
+ }
+ }
+
+ function runCanvas2DTest(videoElement, topColor, bottomColor)
+ {
+ debug('Testing with 2D canvas');
+
+ var canvas = c2d.canvas;
+
+ // Draw the video to the 2D canvas context.
+ c2d.drawImage(videoElement, 0, 0, canvas.width, canvas.height);
+
+ // Check a few pixels near the top and bottom and make sure they have
+ // the right color.
+ // Origin is upper left in 2D canvas context.
+ var tolerance = currentTolerance;
+ debug("Checking lower left corner");
+ wtu.checkCanvasRect(c2d, 4, canvas.height - 8, 2, 2, bottomColor,
+ "shouldBe " + bottomColor, tolerance);
+ debug("Checking upper left corner");
+ wtu.checkCanvasRect(c2d, 4, 4, 2, 2, topColor,
+ "shouldBe " + topColor, tolerance);
+ }
+
+ function runAllTests()
+ {
+ var cases = [
+ { sub: false, flipY: true, topColor: redColor, bottomColor: greenColor },
+ { sub: false, flipY: false, topColor: greenColor, bottomColor: redColor },
+ { sub: true, flipY: true, topColor: redColor, bottomColor: greenColor },
+ { sub: true, flipY: false, topColor: greenColor, bottomColor: redColor },
+ ];
+
+ function runTexImageTest(bindingTarget) {
+ var program;
+ if (bindingTarget == gl.TEXTURE_2D) {
+ program = tiu.setupTexturedQuad(gl, internalFormat);
+ } else {
+ program = tiu.setupTexturedQuadWithCubeMap(gl, internalFormat);
+ }
+
+ return new Promise(function(resolve, reject) {
+ var videoNdx = 0;
+ var video;
+ function runNextVideo() {
+ if (video) {
+ video.pause();
+ }
+
+ if (videoNdx == videos.length) {
+ resolve("SUCCESS");
+ return;
+ }
+
+ var info = videos[videoNdx++];
+ debug("");
+ debug("testing: " + info.comment);
+ debug("video type: " + info.type);
+ // Default to tolerance of 5.
+ currentTolerance = info.tolerance || 5;
+ debug("tolerance: " + currentTolerance);
+ video = document.createElement("video");
+ video.muted = true;
+ var canPlay = true;
+ if (!video.canPlayType) {
+ testFailed("video.canPlayType required method missing");
+ runNextVideo();
+ return;
+ }
+
+ if(!video.canPlayType(info.type).replace(/no/, '')) {
+ debug(info.type + " unsupported; skipping test");
+ runNextVideo();
+ return;
+ };
+
+ document.body.appendChild(video);
+ video.type = info.type;
+ video.src = info.src;
+ wtu.startPlayingAndWaitForVideo(video, runTest);
+ }
+ function runTest() {
+ for (var i in cases) {
+ if (bindingTarget == gl.TEXTURE_CUBE_MAP) {
+ // Cube map texture must be square but video is not square.
+ if (!cases[i].sub) {
+ break;
+ }
+ // Skip sub-rectangle tests for cube map textures for the moment.
+ if (cases[i].sourceSubRectangle) {
+ break;
+ }
+ }
+ runOneIteration(video, cases[i].sub, cases[i].flipY,
+ cases[i].topColor, cases[i].bottomColor,
+ cases[i].sourceSubRectangle,
+ program, bindingTarget);
+ }
+ runCanvas2DTest(video, redColor, greenColor);
+ runNextVideo();
+ }
+ runNextVideo();
+ });
+ }
+
+ runTexImageTest(gl.TEXTURE_2D).then(function(val) {
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors");
+ finishTest();
+ });
+ }
+
+ return init;
+}
diff --git a/dom/canvas/test/webgl-conf/checkout/js/tests/typed-array-test-cases.js b/dom/canvas/test/webgl-conf/checkout/js/tests/typed-array-test-cases.js
new file mode 100644
index 0000000000..2e1b79a677
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/js/tests/typed-array-test-cases.js
@@ -0,0 +1,73 @@
+/*
+Copyright (c) 2019 The Khronos Group Inc.
+Use of this source code is governed by an MIT-style license that can be
+found in the LICENSE.txt file.
+*/
+
+// The "name" attribute is a concession to browsers which don't
+// implement the "name" property on function objects.
+var testCases =
+ [ {name: "Float32Array",
+ unsigned: false,
+ integral: false,
+ elementSizeInBytes: 4,
+ testValues: [ -500.5, 500.5 ],
+ expectedValues: [ -500.5, 500.5 ]
+ },
+ {name: "Float64Array",
+ unsigned: false,
+ integral: false,
+ elementSizeInBytes: 8,
+ testValues: [ -500.5, 500.5 ],
+ expectedValues: [ -500.5, 500.5 ]
+ },
+ {name: "Int8Array",
+ unsigned: false,
+ integral: true,
+ elementSizeInBytes: 1,
+ testValues: [ -128, 127, -129, 128 ],
+ expectedValues: [ -128, 127, 127, -128 ]
+ },
+ {name: "Int16Array",
+ unsigned: false,
+ integral: true,
+ elementSizeInBytes: 2,
+ testValues: [ -32768, 32767, -32769, 32768 ],
+ expectedValues: [ -32768, 32767, 32767, -32768 ]
+ },
+ {name: "Int32Array",
+ unsigned: false,
+ integral: true,
+ elementSizeInBytes: 4,
+ testValues: [ -2147483648, 2147483647, -2147483649, 2147483648 ],
+ expectedValues: [ -2147483648, 2147483647, 2147483647, -2147483648 ]
+ },
+ {name: "Uint8Array",
+ unsigned: true,
+ integral: true,
+ elementSizeInBytes: 1,
+ testValues: [ 0, 255, -1, 256 ],
+ expectedValues: [ 0, 255, 255, 0 ]
+ },
+ {name: "Uint8ClampedArray",
+ unsigned: true,
+ integral: true,
+ elementSizeInBytes: 1,
+ testValues: [ 0, 255, -1, 256 ],
+ expectedValues: [ 0, 255, 0, 255 ]
+ },
+ {name: "Uint16Array",
+ unsigned: true,
+ integral: true,
+ elementSizeInBytes: 2,
+ testValues: [ 0, 65535, -1, 65536 ],
+ expectedValues: [ 0, 65535, 65535, 0 ]
+ },
+ {name: "Uint32Array",
+ unsigned: true,
+ integral: true,
+ elementSizeInBytes: 4,
+ testValues: [ 0, 4294967295, -1, 4294967296 ],
+ expectedValues: [ 0, 4294967295, 4294967295, 0 ]
+ }
+ ];
diff --git a/dom/canvas/test/webgl-conf/checkout/js/tests/typed-array-worker.js b/dom/canvas/test/webgl-conf/checkout/js/tests/typed-array-worker.js
new file mode 100644
index 0000000000..c361a0e8a2
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/js/tests/typed-array-worker.js
@@ -0,0 +1,72 @@
+/*
+Copyright (c) 2019 The Khronos Group Inc.
+Use of this source code is governed by an MIT-style license that can be
+found in the LICENSE.txt file.
+*/
+
+function constructTypedArray(type, data) {
+ if (type == 'Int8Array') {
+ return new Int8Array(data);
+ } else if (type == 'Uint8Array') {
+ return new Uint8Array(data);
+ } else if (type == 'Uint8ClampedArray') {
+ return new Uint8ClampedArray(data);
+ } else if (type == 'Int16Array') {
+ return new Int16Array(data);
+ } else if (type == 'Uint16Array') {
+ return new Uint16Array(data);
+ } else if (type == 'Int32Array') {
+ return new Int32Array(data);
+ } else if (type == 'Uint32Array') {
+ return new Uint32Array(data);
+ } else if (type == 'Float32Array') {
+ return new Float32Array(data);
+ } else if (type == 'Float64Array') {
+ return new Float64Array(data);
+ }
+}
+
+function constructDataView(subType, elementSizeInBytes, data) {
+ var setter = "set" + subType;
+ var byteOffset = 0;
+ var buffer = new ArrayBuffer(elementSizeInBytes * data.length);
+ var dataView = new DataView(buffer);
+ for (var ii = 0; ii < data.length; ++ii) {
+ dataView[setter](byteOffset, data[ii]);
+ byteOffset += elementSizeInBytes;
+ }
+ return dataView;
+}
+
+onmessage = function(event) {
+ var message = event.data;
+ if (message.command == 'copy' ||
+ message.command == 'transfer' ||
+ message.command == 'copyBuffer' ||
+ message.command == 'transferBuffer') {
+ var view;
+ if (message.type != 'DataView') {
+ view = constructTypedArray(message.type, message.data);
+ } else {
+ view = constructDataView(message.subType, message.elementSizeInBytes, message.data);
+ }
+ var valueToSend;
+ if (message.command == 'copy' ||
+ message.command == 'transfer') {
+ valueToSend = view;
+ } else {
+ valueToSend = view.buffer;
+ }
+ var transferablesToSend = undefined;
+ if (message.command == 'transfer' ||
+ message.command == 'transferBuffer') {
+ transferablesToSend = [ view.buffer ];
+ }
+ postMessage(valueToSend, transferablesToSend);
+ } else if (message.command == 'pong') {
+ postMessage(message.data, message.transferables);
+ } else if (message.command == 'ignore') {
+ } else {
+ postMessage('error: unknown message');
+ }
+};
diff --git a/dom/canvas/test/webgl-conf/checkout/js/tests/webgl-compressed-texture-size-limit.js b/dom/canvas/test/webgl-conf/checkout/js/tests/webgl-compressed-texture-size-limit.js
new file mode 100644
index 0000000000..6fad5520f2
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/js/tests/webgl-compressed-texture-size-limit.js
@@ -0,0 +1,226 @@
+/*
+Copyright (c) 2019 The Khronos Group Inc.
+Use of this source code is governed by an MIT-style license that can be
+found in the LICENSE.txt file.
+*/
+
+'use strict';
+
+var runCompressedTextureSizeLimitTest = function(maxArrayBufferSizeBytes, positiveCubeMapMaxSize) {
+
+ function numLevelsFromSize(size) {
+ var levels = 0;
+ while ((size >> levels) > 0) {
+ ++levels;
+ }
+ return levels;
+ }
+
+ // More formats can be added here when more texture compression extensions are enabled in WebGL.
+ var validFormats = {
+ COMPRESSED_RGB_S3TC_DXT1_EXT : 0x83F0,
+ COMPRESSED_RGBA_S3TC_DXT1_EXT : 0x83F1,
+ COMPRESSED_RGBA_S3TC_DXT3_EXT : 0x83F2,
+ COMPRESSED_RGBA_S3TC_DXT5_EXT : 0x83F3,
+ };
+
+ // format specific restrictions for COMPRESSED_RGB_S3TC_DXT1_EXT and COMPRESSED_RGBA_S3TC_DXT1_EXT
+ // on the byteLength of the ArrayBufferView, pixels
+ function func1 (width, height)
+ {
+ return Math.floor((width + 3) / 4) * Math.floor((height + 3) / 4) * 8;
+ }
+
+ // format specific restrictions for COMPRESSED_RGBA_S3TC_DXT3_EXT and COMPRESSED_RGBA_S3TC_DXT5_EXT
+ // on the byteLength of the ArrayBufferView, pixels
+ function func2 (width, height)
+ {
+ return Math.floor((width + 3) / 4) * Math.floor((height + 3) / 4) * 16;
+ }
+
+ var wtu = WebGLTestUtils;
+ var gl = wtu.create3DContext("example");
+ var tests = [
+ // More tests can be added here when more texture compression extensions are enabled in WebGL.
+ // Level 0 image width and height must be a multiple of the sizeStep.
+ { extension: "WEBGL_compressed_texture_s3tc", format: validFormats.COMPRESSED_RGB_S3TC_DXT1_EXT, dataType: Uint8Array, func: func1, sizeStep: 4},
+ { extension: "WEBGL_compressed_texture_s3tc", format: validFormats.COMPRESSED_RGBA_S3TC_DXT1_EXT, dataType: Uint8Array, func: func1, sizeStep: 4},
+ { extension: "WEBGL_compressed_texture_s3tc", format: validFormats.COMPRESSED_RGBA_S3TC_DXT3_EXT, dataType: Uint8Array, func: func2, sizeStep: 4},
+ { extension: "WEBGL_compressed_texture_s3tc", format: validFormats.COMPRESSED_RGBA_S3TC_DXT5_EXT, dataType: Uint8Array, func: func2, sizeStep: 4},
+ ];
+
+ // Note: We expressly only use 2 textures because first a texture will be defined
+ // using all mip levels of 1 format, then for a moment it will have mixed formats which
+ // may uncover bugs.
+ var targets = [
+ { target: gl.TEXTURE_2D,
+ maxSize: gl.getParameter(gl.MAX_TEXTURE_SIZE),
+ tex: gl.createTexture(),
+ targets: [gl.TEXTURE_2D]
+ },
+ { target: gl.TEXTURE_CUBE_MAP,
+ maxSize: gl.getParameter(gl.MAX_CUBE_MAP_TEXTURE_SIZE),
+ tex: gl.createTexture(),
+ targets: [
+ gl.TEXTURE_CUBE_MAP_POSITIVE_X,
+ gl.TEXTURE_CUBE_MAP_NEGATIVE_X,
+ gl.TEXTURE_CUBE_MAP_POSITIVE_Y,
+ gl.TEXTURE_CUBE_MAP_NEGATIVE_Y,
+ gl.TEXTURE_CUBE_MAP_POSITIVE_Z,
+ gl.TEXTURE_CUBE_MAP_NEGATIVE_Z
+ ]
+ }
+ ];
+
+ function getSharedArrayBufferSize() {
+ var sharedArrayBufferSize = 0;
+ for (var tt = 0; tt < tests.length; ++tt) {
+ var test = tests[tt];
+ for (var trg = 0; trg < targets.length; ++trg) {
+ var t = targets[trg];
+ var bufferSizeNeeded;
+ if (t.target === gl.TEXTURE_CUBE_MAP) {
+ var positiveTestSize = Math.min(2048, t.maxSize);
+ bufferSizeNeeded = test.func(positiveTestSize, positiveTestSize);
+ } else {
+ bufferSizeNeeded = test.func(t.maxSize, test.sizeStep);
+ }
+ if (bufferSizeNeeded > sharedArrayBufferSize) {
+ sharedArrayBufferSize = bufferSizeNeeded;
+ }
+ bufferSizeNeeded = test.func(t.maxSize + test.sizeStep, t.maxSize + test.sizeStep);
+ // ArrayBuffers can be at most 4GB (minus 1 byte).
+ if (bufferSizeNeeded > sharedArrayBufferSize && bufferSizeNeeded <= maxArrayBufferSizeBytes) {
+ sharedArrayBufferSize = bufferSizeNeeded;
+ }
+ }
+ }
+ return sharedArrayBufferSize;
+ }
+
+ // Share an ArrayBuffer among tests to avoid too many large allocations
+ var sharedArrayBuffer = new ArrayBuffer(getSharedArrayBufferSize());
+
+ gl.pixelStorei(gl.UNPACK_ALIGNMENT, 1);
+
+ var trg = 0;
+ var tt = 0;
+ runNextTest();
+
+ function runNextTest() {
+ var t = targets[trg];
+
+ if (tt == 0) {
+ var tex = t.tex;
+ gl.bindTexture(t.target, tex);
+
+ debug("");
+ debug("max size for " + wtu.glEnumToString(gl, t.target) + ": " + t.maxSize);
+ }
+
+ var test = tests[tt];
+ testFormatType(t, test);
+ ++tt;
+ if (tt == tests.length) {
+ tt = 0;
+ ++trg;
+ if (trg == targets.length) {
+ finishTest();
+ return;
+ }
+ }
+ wtu.dispatchPromise(runNextTest);
+ }
+
+ function testFormatType(t, test) {
+ var positiveTestSize = t.maxSize;
+ var positiveTestOtherDimension = test.sizeStep;
+ if (t.target === gl.TEXTURE_CUBE_MAP) {
+ // Can't always test the maximum size since that can cause OOM:
+ positiveTestSize = Math.min(positiveCubeMapMaxSize, t.maxSize);
+ // Cube map textures need to be square:
+ positiveTestOtherDimension = positiveTestSize;
+ }
+ var positiveTestLevels = numLevelsFromSize(positiveTestSize);
+ var numLevels = numLevelsFromSize(t.maxSize);
+ debug("");
+ debug("num levels: " + numLevels + ", levels used in positive test: " + positiveTestLevels);
+
+ debug("");
+
+ // Query the extension and store globally so shouldBe can access it
+ var ext = wtu.getExtensionWithKnownPrefixes(gl, test.extension);
+ if (ext) {
+
+ testPassed("Successfully enabled " + test.extension + " extension");
+
+ for (var j = 0; j < t.targets.length; ++j) {
+ var target = t.targets[j];
+ debug("");
+ debug(wtu.glEnumToString(gl, target) + " " + wtu.glEnumToString(ext, test.format));
+
+ // positive test
+ var size = positiveTestSize;
+ var otherDimension = positiveTestOtherDimension;
+ for (var i = 0; i < positiveTestLevels; i++) {
+ var pixels = new test.dataType(sharedArrayBuffer, 0, test.func(size, otherDimension));
+ gl.compressedTexImage2D(target, i, test.format, size, otherDimension, 0, pixels);
+ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "uploading compressed texture should generate NO_ERROR."
+ + "level is " + i + ", size is " + size + "x" + otherDimension);
+ size /= 2;
+ otherDimension /= 2;
+ if (otherDimension < 1) {
+ otherDimension = 1;
+ }
+ }
+
+ var numLevels = numLevelsFromSize(t.maxSize);
+
+ // out of bounds tests
+
+ // width or height out of bounds
+ if (t.target != gl.TEXTURE_CUBE_MAP) {
+ // only width out of bounds
+ var wideAndShortDataSize = test.func(t.maxSize + test.sizeStep, test.sizeStep);
+ var pixelsNegativeTest1 = new test.dataType(sharedArrayBuffer, 0, wideAndShortDataSize);
+ gl.compressedTexImage2D(target, 0, test.format, t.maxSize + test.sizeStep, test.sizeStep, 0, pixelsNegativeTest1);
+ wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, "width out of bounds: should generate INVALID_VALUE."
+ + " level is 0, size is " + (t.maxSize + test.sizeStep) + "x" + (test.sizeStep));
+
+ // only height out of bounds
+ var narrowAndTallDataSize = test.func(test.sizeStep, t.maxSize + test.sizeStep);
+ var pixelsNegativeTest1 = new test.dataType(sharedArrayBuffer, 0, narrowAndTallDataSize);
+ gl.compressedTexImage2D(target, 0, test.format, test.sizeStep, t.maxSize + test.sizeStep, 0, pixelsNegativeTest1);
+ wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, "height out of bounds: should generate INVALID_VALUE."
+ + " level is 0, size is " + (test.sizeStep) + "x" + (t.maxSize + test.sizeStep));
+ }
+
+ // both width and height out of the maximum bounds simultaneously
+ var squareDataSize = test.func(t.maxSize + test.sizeStep, t.maxSize + test.sizeStep);
+ // this check assumes that each element is 1 byte
+ if (squareDataSize > sharedArrayBuffer.byteLength) {
+ testPassed("Unable to test square texture larger than maximum size due to ArrayBuffer size limitations -- this is legal");
+ } else {
+ var pixelsNegativeTest1 = new test.dataType(sharedArrayBuffer, 0, squareDataSize);
+ gl.compressedTexImage2D(target, 0, test.format, t.maxSize + test.sizeStep, t.maxSize + test.sizeStep, 0, pixelsNegativeTest1);
+ wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, "width and height out of bounds: should generate INVALID_VALUE."
+ + " level is 0, size is " + (t.maxSize + test.sizeStep) + "x" + (t.maxSize + test.sizeStep));
+ }
+
+ // level out of bounds
+ var pixelsNegativeTest2 = new test.dataType(sharedArrayBuffer, 0, test.func(256, 256));
+ gl.compressedTexImage2D(target, numLevels, test.format, 256, 256, 0, pixelsNegativeTest2);
+ wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, "level out of bounds: should generate INVALID_VALUE."
+ + " level is " + numLevels + ", size is 256x256");
+ //width and height out of bounds for specified level
+ gl.compressedTexImage2D(target, numLevels - 1, test.format, 256, 256, 0, pixelsNegativeTest2);
+ wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, "width or height out of bounds for specified level: should generate INVALID_VALUE."
+ + " level is " + (numLevels - 1) + ", size is 256x256");
+ }
+ }
+ else {
+ testPassed("No " + test.extension + " extension support -- this is legal");
+ }
+ }
+
+};
diff --git a/dom/canvas/test/webgl-conf/checkout/js/tests/webgl-draw-buffers-utils.js b/dom/canvas/test/webgl-conf/checkout/js/tests/webgl-draw-buffers-utils.js
new file mode 100644
index 0000000000..ebd0c7ba68
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/js/tests/webgl-draw-buffers-utils.js
@@ -0,0 +1,69 @@
+/*
+Copyright (c) 2019 The Khronos Group Inc.
+Use of this source code is governed by an MIT-style license that can be
+found in the LICENSE.txt file.
+*/
+
+// This file contains utilities shared between tests for the WEBGL_draw_buffers extension and multiple draw buffers functionality in WebGL 2.0.
+
+'use strict';
+
+var WebGLDrawBuffersUtils = function(gl, ext) {
+
+ var getMaxUsableColorAttachments = function() {
+ var maxDrawingBuffers;
+ var maxColorAttachments;
+ if (ext) {
+ // EXT_draw_buffers
+ maxDrawingBuffers = gl.getParameter(ext.MAX_DRAW_BUFFERS_WEBGL);
+ maxColorAttachments = gl.getParameter(ext.MAX_COLOR_ATTACHMENTS_WEBGL);
+ } else {
+ // WebGL 2.0
+ maxDrawingBuffers = gl.getParameter(gl.MAX_DRAW_BUFFERS);
+ maxColorAttachments = gl.getParameter(gl.MAX_COLOR_ATTACHMENTS);
+ }
+ var maxUniformVectors = gl.getParameter(gl.MAX_FRAGMENT_UNIFORM_VECTORS);
+ return Math.min(maxDrawingBuffers, maxColorAttachments, maxUniformVectors);
+ };
+
+ var makeColorAttachmentArray = function(size) {
+ var array = []
+ for (var ii = 0; ii < size; ++ii) {
+ array.push(gl.COLOR_ATTACHMENT0 + ii);
+ }
+ return array;
+ }
+
+ var checkProgram = wtu.setupTexturedQuad(gl);
+
+ var checkAttachmentsForColorFn = function(attachments, colorFn) {
+ gl.bindFramebuffer(gl.FRAMEBUFFER, null);
+ gl.useProgram(checkProgram);
+ attachments.forEach(function(attachment, index) {
+ gl.bindTexture(gl.TEXTURE_2D, attachment.texture);
+ wtu.clearAndDrawUnitQuad(gl);
+ var expectedColor = colorFn(attachment, index);
+ var tolerance = 0;
+ expectedColor.forEach(function(v) {
+ if (v != 0 && v != 255) {
+ tolerance = 8;
+ }
+ });
+ wtu.checkCanvas(gl, expectedColor, "attachment " + index + " should be " + expectedColor.toString(), tolerance);
+ });
+ debug("");
+ };
+
+ var checkAttachmentsForColor = function(attachments, color) {
+ checkAttachmentsForColorFn(attachments, function(attachment, index) {
+ return color || attachment.color;
+ });
+ };
+
+ return {
+ getMaxUsableColorAttachments: getMaxUsableColorAttachments,
+ makeColorAttachmentArray: makeColorAttachmentArray,
+ checkAttachmentsForColorFn: checkAttachmentsForColorFn,
+ checkAttachmentsForColor: checkAttachmentsForColor
+ };
+};
diff --git a/dom/canvas/test/webgl-conf/checkout/js/webgl-test-harness.js b/dom/canvas/test/webgl-conf/checkout/js/webgl-test-harness.js
new file mode 100644
index 0000000000..f48d9d2ad7
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/js/webgl-test-harness.js
@@ -0,0 +1,642 @@
+/*
+Copyright (c) 2019 The Khronos Group Inc.
+Use of this source code is governed by an MIT-style license that can be
+found in the LICENSE.txt file.
+*/
+
+// This is a test harness for running javascript tests in the browser.
+// The only identifier exposed by this harness is WebGLTestHarnessModule.
+//
+// To use it make an HTML page with an iframe. Then call the harness like this
+//
+// function reportResults(type, msg, success) {
+// ...
+// return true;
+// }
+//
+// var fileListURL = '00_test_list.txt';
+// var testHarness = new WebGLTestHarnessModule.TestHarness(
+// iframe,
+// fileListURL,
+// reportResults,
+// options);
+//
+// The harness will load the fileListURL and parse it for the URLs, one URL
+// per line preceded by options, see below. URLs should be on the same domain
+// and at the same folder level or below the main html file. If any URL ends
+// in .txt it will be parsed as well so you can nest .txt files. URLs inside a
+// .txt file should be relative to that text file.
+//
+// During startup, for each page found the reportFunction will be called with
+// WebGLTestHarnessModule.TestHarness.reportType.ADD_PAGE and msg will be
+// the URL of the test.
+//
+// Each test is required to call testHarness.reportResults. This is most easily
+// accomplished by storing that value on the main window with
+//
+// window.webglTestHarness = testHarness
+//
+// and then adding these to functions to your tests.
+//
+// function reportTestResultsToHarness(success, msg) {
+// if (window.parent.webglTestHarness) {
+// window.parent.webglTestHarness.reportResults(success, msg);
+// }
+// }
+//
+// function notifyFinishedToHarness() {
+// if (window.parent.webglTestHarness) {
+// window.parent.webglTestHarness.notifyFinished();
+// }
+// }
+//
+// This way your tests will still run without the harness and you can use
+// any testing framework you want.
+//
+// Each test should call reportTestResultsToHarness with true for success if it
+// succeeded and false if it fail followed and any message it wants to
+// associate with the test. If your testing framework supports checking for
+// timeout you can call it with success equal to undefined in that case.
+//
+// To run the tests, call testHarness.runTests(options);
+//
+// For each test run, before the page is loaded the reportFunction will be
+// called with WebGLTestHarnessModule.TestHarness.reportType.START_PAGE and msg
+// will be the URL of the test. You may return false if you want the test to be
+// skipped.
+//
+// For each test completed the reportFunction will be called with
+// with WebGLTestHarnessModule.TestHarness.reportType.TEST_RESULT,
+// success = true on success, false on failure, undefined on timeout
+// and msg is any message the test choose to pass on.
+//
+// When all the tests on the page have finished your page must call
+// notifyFinishedToHarness. If notifyFinishedToHarness is not called
+// the harness will assume the test timed out.
+//
+// When all the tests on a page have finished OR the page as timed out the
+// reportFunction will be called with
+// WebGLTestHarnessModule.TestHarness.reportType.FINISH_PAGE
+// where success = true if the page has completed or undefined if the page timed
+// out.
+//
+// Finally, when all the tests have completed the reportFunction will be called
+// with WebGLTestHarnessModule.TestHarness.reportType.FINISHED_ALL_TESTS.
+//
+// Harness Options
+//
+// These are passed in to the TestHarness as a JavaScript object
+//
+// version: (required!)
+//
+// Specifies a version used to filter tests. Tests marked as requiring
+// a version greater than this version will not be included.
+//
+// example: new TestHarness(...., {version: "3.1.2"});
+//
+// minVersion:
+//
+// Specifies the minimum version a test must require to be included.
+// This basically flips the filter so that only tests marked with
+// --min-version will be included if they are at this minVersion or
+// greater.
+//
+// example: new TestHarness(...., {minVersion: "2.3.1"});
+//
+// maxVersion:
+//
+// Specifies the maximum version a test must require to be included.
+// This basically flips the filter so that only tests marked with
+// --max-version will be included if they are at this maxVersion or
+// less.
+//
+// example: new TestHarness(...., {maxVersion: "2.3.1"});
+//
+// fast:
+//
+// Specifies to skip any tests marked as slow.
+//
+// example: new TestHarness(..., {fast: true});
+//
+// Test Options:
+//
+// Any test URL or .txt file can be prefixed by the following options
+//
+// min-version:
+//
+// Sets the minimum version required to include this test. A version is
+// passed into the harness options. Any test marked as requiring a
+// min-version greater than the version passed to the harness is skipped.
+// This allows you to add new tests to a suite of tests for a future
+// version of the suite without including the test in the current version.
+// If no -min-version is specified it is inheriited from the .txt file
+// including it. The default is 1.0.0
+//
+// example: --min-version 2.1.3 sometest.html
+//
+// max-version:
+//
+// Sets the maximum version required to include this test. A version is
+// passed into the harness options. Any test marked as requiring a
+// max-version less than the version passed to the harness is skipped.
+// This allows you to test functionality that has been removed from later
+// versions of the suite.
+// If no -max-version is specified it is inherited from the .txt file
+// including it.
+//
+// example: --max-version 1.9.9 sometest.html
+//
+// slow:
+//
+// Marks a test as slow. Slow tests can be skipped by passing fastOnly: true
+// to the TestHarness. Of course you need to pass all tests but sometimes
+// you'd like to test quickly and run only the fast subset of tests.
+//
+// example: --slow some-test-that-takes-2-mins.html
+//
+
+WebGLTestHarnessModule = function() {
+
+/**
+ * Wrapped logging function.
+ */
+var log = function(msg) {
+ if (window.console && window.console.log) {
+ window.console.log(msg);
+ }
+};
+
+/**
+ * Loads text from an external file. This function is synchronous.
+ * @param {string} url The url of the external file.
+ * @param {!function(bool, string): void} callback that is sent a bool for
+ * success and the string.
+ */
+var loadTextFileAsynchronous = function(url, callback) {
+ log ("loading: " + url);
+ var error = 'loadTextFileSynchronous failed to load url "' + url + '"';
+ var request;
+ if (window.XMLHttpRequest) {
+ request = new XMLHttpRequest();
+ if (request.overrideMimeType) {
+ request.overrideMimeType('text/plain');
+ }
+ } else {
+ throw 'XMLHttpRequest is disabled';
+ }
+ try {
+ request.open('GET', url, true);
+ request.onreadystatechange = function() {
+ if (request.readyState == 4) {
+ var text = '';
+ // HTTP reports success with a 200 status. The file protocol reports
+ // success with zero. HTTP does not use zero as a status code (they
+ // start at 100).
+ // https://developer.mozilla.org/En/Using_XMLHttpRequest
+ var success = request.status == 200 || request.status == 0;
+ if (success) {
+ text = request.responseText;
+ }
+ log("loaded: " + url);
+ callback(success, text);
+ }
+ };
+ request.send(null);
+ } catch (e) {
+ log("failed to load: " + url);
+ callback(false, '');
+ }
+};
+
+/**
+ * @param {string} versionString WebGL version string.
+ * @return {number} Integer containing the WebGL major version.
+ */
+var getMajorVersion = function(versionString) {
+ if (!versionString) {
+ return 1;
+ }
+ return parseInt(versionString.split(" ")[0].split(".")[0], 10);
+};
+
+/**
+ * @param {string} url Base URL of the test.
+ * @param {map} options Map of options to append to the URL's query string.
+ * @return {string} URL that will run the test with the given WebGL version.
+ */
+var getURLWithOptions = function(url, options) {
+ var queryArgs = 0;
+
+ for (i in options) {
+ url += queryArgs ? "&" : "?";
+ url += i + "=" + options[i];
+ queryArgs++;
+ }
+
+ return url;
+};
+
+/**
+ * Compare version strings.
+ */
+var greaterThanOrEqualToVersion = function(have, want) {
+ have = have.split(" ")[0].split(".");
+ want = want.split(" ")[0].split(".");
+
+ //have 1.2.3 want 1.1
+ //have 1.1.1 want 1.1
+ //have 1.0.9 want 1.1
+ //have 1.1 want 1.1.1
+
+ for (var ii = 0; ii < want.length; ++ii) {
+ var wantNum = parseInt(want[ii]);
+ var haveNum = have[ii] ? parseInt(have[ii]) : 0
+ if (haveNum > wantNum) {
+ return true; // 2.0.0 is greater than 1.2.3
+ }
+ if (haveNum < wantNum) {
+ return false;
+ }
+ }
+ return true;
+};
+
+/**
+ * Reads a file, recursively adding files referenced inside.
+ *
+ * Each line of URL is parsed, comments starting with '#' or ';'
+ * or '//' are stripped.
+ *
+ * arguments beginning with -- are extracted
+ *
+ * lines that end in .txt are recursively scanned for more files
+ * other lines are added to the list of files.
+ *
+ * @param {string} url The url of the file to read.
+ * @param {function(boolean, !Array.<string>):void} callback
+ * Callback that is called with true for success and an
+ * array of filenames.
+ * @param {Object} options Optional options
+ *
+ * Options:
+ * version: {string} The version of the conformance test.
+ * Tests with the argument --min-version <version> will
+ * be ignored version is less then <version>
+ *
+ */
+var getFileList = function(url, callback, options) {
+ var files = [];
+
+ var copyObject = function(obj) {
+ return JSON.parse(JSON.stringify(obj));
+ };
+
+ var toCamelCase = function(str) {
+ return str.replace(/-([a-z])/g, function (g) { return g[1].toUpperCase() });
+ };
+
+ var globalOptions = copyObject(options);
+ globalOptions.defaultVersion = "1.0";
+ globalOptions.defaultMaxVersion = null;
+
+ var getFileListImpl = function(prefix, line, lineNum, hierarchicalOptions, callback) {
+ var files = [];
+
+ var args = line.split(/\s+/);
+ var nonOptions = [];
+ var useTest = true;
+ var testOptions = {};
+ for (var jj = 0; jj < args.length; ++jj) {
+ var arg = args[jj];
+ if (arg[0] == '-') {
+ if (arg[1] != '-') {
+ throw ("bad option at in " + url + ":" + lineNum + ": " + arg);
+ }
+ var option = arg.substring(2);
+ switch (option) {
+ // no argument options.
+ case 'slow':
+ testOptions[toCamelCase(option)] = true;
+ break;
+ // one argument options.
+ case 'min-version':
+ case 'max-version':
+ ++jj;
+ testOptions[toCamelCase(option)] = args[jj];
+ break;
+ default:
+ throw ("bad unknown option '" + option + "' at in " + url + ":" + lineNum + ": " + arg);
+ }
+ } else {
+ nonOptions.push(arg);
+ }
+ }
+ var url = prefix + nonOptions.join(" ");
+
+ if (url.substr(url.length - 4) != '.txt') {
+ var minVersion = testOptions.minVersion;
+ if (!minVersion) {
+ minVersion = hierarchicalOptions.defaultVersion;
+ }
+ var maxVersion = testOptions.maxVersion;
+ if (!maxVersion) {
+ maxVersion = hierarchicalOptions.defaultMaxVersion;
+ }
+ var slow = testOptions.slow;
+ if (!slow) {
+ slow = hierarchicalOptions.defaultSlow;
+ }
+
+ if (globalOptions.fast && slow) {
+ useTest = false;
+ } else if (globalOptions.minVersion) {
+ useTest = greaterThanOrEqualToVersion(minVersion, globalOptions.minVersion);
+ } else if (globalOptions.maxVersion && maxVersion) {
+ useTest = greaterThanOrEqualToVersion(globalOptions.maxVersion, maxVersion);
+ } else {
+ useTest = greaterThanOrEqualToVersion(globalOptions.version, minVersion);
+ if (maxVersion) {
+ useTest = useTest && greaterThanOrEqualToVersion(maxVersion, globalOptions.version);
+ }
+ }
+ }
+
+ if (!useTest) {
+ callback(true, []);
+ return;
+ }
+
+ if (url.substr(url.length - 4) == '.txt') {
+ // If a version was explicity specified pass it down.
+ if (testOptions.minVersion) {
+ hierarchicalOptions.defaultVersion = testOptions.minVersion;
+ }
+ if (testOptions.maxVersion) {
+ hierarchicalOptions.defaultMaxVersion = testOptions.maxVersion;
+ }
+ if (testOptions.slow) {
+ hierarchicalOptions.defaultSlow = testOptions.slow;
+ }
+ loadTextFileAsynchronous(url, function() {
+ return function(success, text) {
+ if (!success) {
+ callback(false, '');
+ return;
+ }
+ var lines = text.split('\n');
+ var prefix = '';
+ var lastSlash = url.lastIndexOf('/');
+ if (lastSlash >= 0) {
+ prefix = url.substr(0, lastSlash + 1);
+ }
+ var fail = false;
+ var count = 1;
+ var index = 0;
+ for (var ii = 0; ii < lines.length; ++ii) {
+ var str = lines[ii].replace(/^\s\s*/, '').replace(/\s\s*$/, '');
+ if (str.length > 4 &&
+ str[0] != '#' &&
+ str[0] != ";" &&
+ str.substr(0, 2) != "//") {
+ ++count;
+ getFileListImpl(prefix, str, ii + 1, copyObject(hierarchicalOptions), function(index) {
+ return function(success, new_files) {
+ //log("got files: " + new_files.length);
+ if (success) {
+ files[index] = new_files;
+ }
+ finish(success);
+ };
+ }(index++));
+ }
+ }
+ finish(true);
+
+ function finish(success) {
+ if (!success) {
+ fail = true;
+ }
+ --count;
+ //log("count: " + count);
+ if (!count) {
+ callback(!fail, files);
+ }
+ }
+ }
+ }());
+ } else {
+ files.push(url);
+ callback(true, files);
+ }
+ };
+
+ getFileListImpl('', url, 1, globalOptions, function(success, files) {
+ // flatten
+ var flat = [];
+ flatten(files);
+ function flatten(files) {
+ for (var ii = 0; ii < files.length; ++ii) {
+ var value = files[ii];
+ if (typeof(value) == "string") {
+ flat.push(value);
+ } else {
+ flatten(value);
+ }
+ }
+ }
+ callback(success, flat);
+ });
+};
+
+var FilterURL = (function() {
+ var prefix = window.location.pathname;
+ prefix = prefix.substring(0, prefix.lastIndexOf("/") + 1);
+ return function(url) {
+ if (url.substring(0, prefix.length) == prefix) {
+ url = url.substring(prefix.length);
+ }
+ return url;
+ };
+}());
+
+var TestFile = function(url) {
+ this.url = url;
+};
+
+var Test = function(file) {
+ this.file = file;
+};
+
+var TestHarness = function(iframe, filelistUrl, reportFunc, options) {
+ this.window = window;
+ this.iframes = iframe.length ? iframe : [iframe];
+ this.reportFunc = reportFunc;
+ this.timeoutDelay = 20000;
+ this.files = [];
+ this.allowSkip = options.allowSkip;
+ this.webglVersion = getMajorVersion(options.version);
+ this.dumpShaders = options.dumpShaders;
+ this.quiet = options.quiet;
+
+ var that = this;
+ getFileList(filelistUrl, function() {
+ return function(success, files) {
+ that.addFiles_(success, files);
+ };
+ }(), options);
+
+};
+
+TestHarness.reportType = {
+ ADD_PAGE: 1,
+ READY: 2,
+ START_PAGE: 3,
+ TEST_RESULT: 4,
+ FINISH_PAGE: 5,
+ FINISHED_ALL_TESTS: 6
+};
+
+TestHarness.prototype.addFiles_ = function(success, files) {
+ if (!success) {
+ this.reportFunc(
+ TestHarness.reportType.FINISHED_ALL_TESTS,
+ '',
+ 'Unable to load tests. Are you running locally?\n' +
+ 'You need to run from a server or configure your\n' +
+ 'browser to allow access to local files (not recommended).\n\n' +
+ 'Note: An easy way to run from a server:\n\n' +
+ '\tcd path_to_tests\n' +
+ '\tpython -m SimpleHTTPServer\n\n' +
+ 'then point your browser to ' +
+ '<a href="http://localhost:8000/webgl-conformance-tests.html">' +
+ 'http://localhost:8000/webgl-conformance-tests.html</a>',
+ false)
+ return;
+ }
+ log("total files: " + files.length);
+ for (var ii = 0; ii < files.length; ++ii) {
+ log("" + ii + ": " + files[ii]);
+ this.files.push(new TestFile(files[ii]));
+ this.reportFunc(TestHarness.reportType.ADD_PAGE, '', files[ii], undefined);
+ }
+ this.reportFunc(TestHarness.reportType.READY, '', undefined, undefined);
+}
+
+TestHarness.prototype.runTests = function(opt_options) {
+ var options = opt_options || { };
+ options.start = options.start || 0;
+ options.count = options.count || this.files.length;
+
+ this.idleIFrames = this.iframes.slice(0);
+ this.runningTests = {};
+ var testsToRun = [];
+ for (var ii = 0; ii < options.count; ++ii) {
+ testsToRun.push(ii + options.start);
+ }
+ this.numTestsRemaining = options.count;
+ this.testsToRun = testsToRun;
+ this.startNextTest();
+};
+
+TestHarness.prototype.setTimeout = function(test) {
+ var that = this;
+ test.timeoutId = this.window.setTimeout(function() {
+ that.timeout(test);
+ }, this.timeoutDelay);
+};
+
+TestHarness.prototype.clearTimeout = function(test) {
+ this.window.clearTimeout(test.timeoutId);
+};
+
+TestHarness.prototype.startNextTest = function() {
+ if (this.numTestsRemaining == 0) {
+ log("done");
+ this.reportFunc(TestHarness.reportType.FINISHED_ALL_TESTS,
+ '', '', true);
+ } else {
+ while (this.testsToRun.length > 0 && this.idleIFrames.length > 0) {
+ var testId = this.testsToRun.shift();
+ var iframe = this.idleIFrames.shift();
+ this.startTest(iframe, this.files[testId], this.webglVersion);
+ }
+ }
+};
+
+TestHarness.prototype.startTest = function(iframe, testFile, webglVersion) {
+ var test = {
+ iframe: iframe,
+ testFile: testFile
+ };
+ var url = testFile.url;
+ this.runningTests[url] = test;
+ log("loading: " + url);
+ if (this.reportFunc(TestHarness.reportType.START_PAGE, url, url, undefined)) {
+ iframe.src = getURLWithOptions(url, {
+ "webglVersion": webglVersion,
+ "dumpShaders": this.dumpShaders,
+ "quiet": this.quiet
+ });
+ this.setTimeout(test);
+ } else {
+ this.reportResults(url, !!this.allowSkip, "skipped", true);
+ this.notifyFinished(url);
+ }
+};
+
+TestHarness.prototype.getTest = function(url) {
+ var test = this.runningTests[FilterURL(url)];
+ if (!test) {
+ throw("unknown test:" + url);
+ }
+ return test;
+};
+
+TestHarness.prototype.reportResults = function(url, success, msg, skipped) {
+ url = FilterURL(url);
+ var test = this.getTest(url);
+ this.clearTimeout(test);
+ log((success ? "PASS" : "FAIL") + ": " + msg);
+ this.reportFunc(TestHarness.reportType.TEST_RESULT, url, msg, success, skipped);
+ // For each result we get, reset the timeout
+ this.setTimeout(test);
+};
+
+TestHarness.prototype.dequeTest = function(test) {
+ this.clearTimeout(test);
+ this.idleIFrames.push(test.iframe);
+ delete this.runningTests[test.testFile.url];
+ --this.numTestsRemaining;
+}
+
+TestHarness.prototype.notifyFinished = function(url) {
+ url = FilterURL(url);
+ var test = this.getTest(url);
+ log(url + ": finished");
+ this.dequeTest(test);
+ this.reportFunc(TestHarness.reportType.FINISH_PAGE, url, url, true);
+ this.startNextTest();
+};
+
+TestHarness.prototype.timeout = function(test) {
+ this.dequeTest(test);
+ var url = test.testFile.url;
+ log(url + ": timeout");
+ this.reportFunc(TestHarness.reportType.FINISH_PAGE, url, url, undefined);
+ this.startNextTest();
+};
+
+TestHarness.prototype.setTimeoutDelay = function(x) {
+ this.timeoutDelay = x;
+};
+
+return {
+ 'TestHarness': TestHarness,
+ 'getMajorVersion': getMajorVersion,
+ 'getURLWithOptions': getURLWithOptions
+ };
+
+}();
+
+
+
diff --git a/dom/canvas/test/webgl-conf/checkout/js/webgl-test-utils.js b/dom/canvas/test/webgl-conf/checkout/js/webgl-test-utils.js
new file mode 100644
index 0000000000..f17f69fa30
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/js/webgl-test-utils.js
@@ -0,0 +1,3677 @@
+/*
+Copyright (c) 2019 The Khronos Group Inc.
+Use of this source code is governed by an MIT-style license that can be
+found in the LICENSE.txt file.
+*/
+var WebGLTestUtils = (function() {
+"use strict";
+
+/**
+ * Wrapped logging function.
+ * @param {string} msg The message to log.
+ */
+var log = function(msg) {
+ bufferedLogToConsole(msg);
+};
+
+/**
+ * Wrapped logging function.
+ * @param {string} msg The message to log.
+ */
+var error = function(msg) {
+ // For the time being, diverting this to window.console.log rather
+ // than window.console.error. If anyone cares enough they can
+ // generalize the mechanism in js-test-pre.js.
+ log(msg);
+};
+
+/**
+ * Turn off all logging.
+ */
+var loggingOff = function() {
+ log = function() {};
+ error = function() {};
+};
+
+const ENUM_NAME_REGEX = RegExp('[A-Z][A-Z0-9_]*');
+const ENUM_NAME_BY_VALUE = {};
+const ENUM_NAME_PROTOTYPES = new Map();
+
+/**
+ * Converts a WebGL enum to a string.
+ * @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use.
+ * @param {number} value The enum value.
+ * @return {string} The enum as a string.
+ */
+var glEnumToString = function(glOrExt, value) {
+ if (value === undefined)
+ throw new Error('glEnumToString: `value` must not be undefined');
+
+ const proto = glOrExt.__proto__;
+ if (!ENUM_NAME_PROTOTYPES.has(proto)) {
+ ENUM_NAME_PROTOTYPES.set(proto, true);
+
+ for (const k in proto) {
+ if (!ENUM_NAME_REGEX.test(k)) continue;
+
+ const v = glOrExt[k];
+ if (ENUM_NAME_BY_VALUE[v] === undefined) {
+ ENUM_NAME_BY_VALUE[v] = k;
+ } else {
+ ENUM_NAME_BY_VALUE[v] += '/' + k;
+ }
+ }
+ }
+
+ const key = ENUM_NAME_BY_VALUE[value];
+ if (key !== undefined) return key;
+
+ return "0x" + Number(value).toString(16);
+};
+
+var lastError = "";
+
+/**
+ * Returns the last compiler/linker error.
+ * @return {string} The last compiler/linker error.
+ */
+var getLastError = function() {
+ return lastError;
+};
+
+/**
+ * Whether a haystack ends with a needle.
+ * @param {string} haystack String to search
+ * @param {string} needle String to search for.
+ * @param {boolean} True if haystack ends with needle.
+ */
+var endsWith = function(haystack, needle) {
+ return haystack.substr(haystack.length - needle.length) === needle;
+};
+
+/**
+ * Whether a haystack starts with a needle.
+ * @param {string} haystack String to search
+ * @param {string} needle String to search for.
+ * @param {boolean} True if haystack starts with needle.
+ */
+var startsWith = function(haystack, needle) {
+ return haystack.substr(0, needle.length) === needle;
+};
+
+/**
+ * A vertex shader for a single texture.
+ * @type {string}
+ */
+var simpleTextureVertexShader = [
+ 'attribute vec4 vPosition;',
+ 'attribute vec2 texCoord0;',
+ 'varying vec2 texCoord;',
+ 'void main() {',
+ ' gl_Position = vPosition;',
+ ' texCoord = texCoord0;',
+ '}'].join('\n');
+
+/**
+ * A vertex shader for a single texture.
+ * @type {string}
+ */
+var simpleTextureVertexShaderESSL300 = [
+ '#version 300 es',
+ 'layout(location=0) in vec4 vPosition;',
+ 'layout(location=1) in vec2 texCoord0;',
+ 'out vec2 texCoord;',
+ 'void main() {',
+ ' gl_Position = vPosition;',
+ ' texCoord = texCoord0;',
+ '}'].join('\n');
+
+/**
+ * A fragment shader for a single texture.
+ * @type {string}
+ */
+var simpleTextureFragmentShader = [
+ 'precision mediump float;',
+ 'uniform sampler2D tex;',
+ 'varying vec2 texCoord;',
+ 'void main() {',
+ ' gl_FragData[0] = texture2D(tex, texCoord);',
+ '}'].join('\n');
+
+/**
+ * A fragment shader for a single texture.
+ * @type {string}
+ */
+var simpleTextureFragmentShaderESSL300 = [
+ '#version 300 es',
+ 'precision highp float;',
+ 'uniform highp sampler2D tex;',
+ 'in vec2 texCoord;',
+ 'out vec4 out_color;',
+ 'void main() {',
+ ' out_color = texture(tex, texCoord);',
+ '}'].join('\n');
+
+/**
+ * A fragment shader for a single texture with high precision.
+ * @type {string}
+ */
+var simpleHighPrecisionTextureFragmentShader = [
+ 'precision highp float;',
+ 'uniform highp sampler2D tex;',
+ 'varying vec2 texCoord;',
+ 'void main() {',
+ ' gl_FragData[0] = texture2D(tex, texCoord);',
+ '}'].join('\n');
+
+/**
+ * A fragment shader for a single cube map texture.
+ * @type {string}
+ */
+var simpleCubeMapTextureFragmentShader = [
+ 'precision mediump float;',
+ 'uniform samplerCube tex;',
+ 'uniform highp int face;',
+ 'varying vec2 texCoord;',
+ 'void main() {',
+ // Transform [0, 1] -> [-1, 1]
+ ' vec2 texC2 = (texCoord * 2.) - 1.;',
+ // Transform 2d tex coord. to each face of TEXTURE_CUBE_MAP coord.
+ ' vec3 texCube = vec3(0., 0., 0.);',
+ ' if (face == 34069) {', // TEXTURE_CUBE_MAP_POSITIVE_X
+ ' texCube = vec3(1., -texC2.y, -texC2.x);',
+ ' } else if (face == 34070) {', // TEXTURE_CUBE_MAP_NEGATIVE_X
+ ' texCube = vec3(-1., -texC2.y, texC2.x);',
+ ' } else if (face == 34071) {', // TEXTURE_CUBE_MAP_POSITIVE_Y
+ ' texCube = vec3(texC2.x, 1., texC2.y);',
+ ' } else if (face == 34072) {', // TEXTURE_CUBE_MAP_NEGATIVE_Y
+ ' texCube = vec3(texC2.x, -1., -texC2.y);',
+ ' } else if (face == 34073) {', // TEXTURE_CUBE_MAP_POSITIVE_Z
+ ' texCube = vec3(texC2.x, -texC2.y, 1.);',
+ ' } else if (face == 34074) {', // TEXTURE_CUBE_MAP_NEGATIVE_Z
+ ' texCube = vec3(-texC2.x, -texC2.y, -1.);',
+ ' }',
+ ' gl_FragData[0] = textureCube(tex, texCube);',
+ '}'].join('\n');
+
+/**
+ * A vertex shader for a single texture.
+ * @type {string}
+ */
+var noTexCoordTextureVertexShader = [
+ 'attribute vec4 vPosition;',
+ 'varying vec2 texCoord;',
+ 'void main() {',
+ ' gl_Position = vPosition;',
+ ' texCoord = vPosition.xy * 0.5 + 0.5;',
+ '}'].join('\n');
+
+/**
+ * A vertex shader for a uniform color.
+ * @type {string}
+ */
+var simpleVertexShader = [
+ 'attribute vec4 vPosition;',
+ 'void main() {',
+ ' gl_Position = vPosition;',
+ '}'].join('\n');
+
+/**
+ * A vertex shader for a uniform color.
+ * @type {string}
+ */
+var simpleVertexShaderESSL300 = [
+ '#version 300 es',
+ 'in vec4 vPosition;',
+ 'void main() {',
+ ' gl_Position = vPosition;',
+ '}'].join('\n');
+
+/**
+ * A fragment shader for a uniform color.
+ * @type {string}
+ */
+var simpleColorFragmentShader = [
+ 'precision mediump float;',
+ 'uniform vec4 u_color;',
+ 'void main() {',
+ ' gl_FragData[0] = u_color;',
+ '}'].join('\n');
+
+/**
+ * A fragment shader for a uniform color.
+ * @type {string}
+ */
+var simpleColorFragmentShaderESSL300 = [
+ '#version 300 es',
+ 'precision mediump float;',
+ 'out vec4 out_color;',
+ 'uniform vec4 u_color;',
+ 'void main() {',
+ ' out_color = u_color;',
+ '}'].join('\n');
+
+/**
+ * A vertex shader for vertex colors.
+ * @type {string}
+ */
+var simpleVertexColorVertexShader = [
+ 'attribute vec4 vPosition;',
+ 'attribute vec4 a_color;',
+ 'varying vec4 v_color;',
+ 'void main() {',
+ ' gl_Position = vPosition;',
+ ' v_color = a_color;',
+ '}'].join('\n');
+
+/**
+ * A fragment shader for vertex colors.
+ * @type {string}
+ */
+var simpleVertexColorFragmentShader = [
+ 'precision mediump float;',
+ 'varying vec4 v_color;',
+ 'void main() {',
+ ' gl_FragData[0] = v_color;',
+ '}'].join('\n');
+
+/**
+ * Creates a program, attaches shaders, binds attrib locations, links the
+ * program and calls useProgram.
+ * @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use.
+ * @param {!Array.<!WebGLShader|string>} shaders The shaders to
+ * attach, or the source, or the id of a script to get
+ * the source from.
+ * @param {!Array.<string>} opt_attribs The attribs names.
+ * @param {!Array.<number>} opt_locations The locations for the attribs.
+ * @param {boolean} opt_logShaders Whether to log shader source.
+ */
+var setupProgram = function(
+ gl, shaders, opt_attribs, opt_locations, opt_logShaders) {
+ var realShaders = [];
+ var program = gl.createProgram();
+ var shaderCount = 0;
+ for (var ii = 0; ii < shaders.length; ++ii) {
+ var shader = shaders[ii];
+ var shaderType = undefined;
+ if (typeof shader == 'string') {
+ var element = document.getElementById(shader);
+ if (element) {
+ if (element.type != "x-shader/x-vertex" && element.type != "x-shader/x-fragment")
+ shaderType = ii ? gl.FRAGMENT_SHADER : gl.VERTEX_SHADER;
+ shader = loadShaderFromScript(gl, shader, shaderType, undefined, opt_logShaders);
+ } else if (endsWith(shader, ".vert")) {
+ shader = loadShaderFromFile(gl, shader, gl.VERTEX_SHADER, undefined, opt_logShaders);
+ } else if (endsWith(shader, ".frag")) {
+ shader = loadShaderFromFile(gl, shader, gl.FRAGMENT_SHADER, undefined, opt_logShaders);
+ } else {
+ shader = loadShader(gl, shader, ii ? gl.FRAGMENT_SHADER : gl.VERTEX_SHADER, undefined, opt_logShaders);
+ }
+ } else if (opt_logShaders) {
+ throw 'Shader source logging requested but no shader source provided';
+ }
+ if (shader) {
+ ++shaderCount;
+ gl.attachShader(program, shader);
+ }
+ }
+ if (shaderCount != 2) {
+ error("Error in compiling shader");
+ return null;
+ }
+ if (opt_attribs) {
+ for (var ii = 0; ii < opt_attribs.length; ++ii) {
+ gl.bindAttribLocation(
+ program,
+ opt_locations ? opt_locations[ii] : ii,
+ opt_attribs[ii]);
+ }
+ }
+ gl.linkProgram(program);
+
+ // Check the link status
+ var linked = gl.getProgramParameter(program, gl.LINK_STATUS);
+ if (!linked) {
+ // something went wrong with the link
+ lastError = gl.getProgramInfoLog (program);
+ error("Error in program linking:" + lastError);
+
+ gl.deleteProgram(program);
+ return null;
+ }
+
+ gl.useProgram(program);
+ return program;
+};
+
+/**
+ * Creates a program, attaches shader, sets up trasnform feedback varyings,
+ * binds attrib locations, links the program and calls useProgram.
+ * @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use.
+ * @param {!Array.<!WebGLShader|string>} shaders The shaders to
+ * attach, or the source, or the id of a script to get
+ * the source from.
+ * @param {!Array.<string>} varyings The transform feedback varying names.
+ * @param {number} bufferMode The mode used to capture the varying variables.
+ * @param {!Array.<string>} opt_attribs The attribs names.
+ * @param {!Array.<number>} opt_locations The locations for the attribs.
+ * @param {boolean} opt_logShaders Whether to log shader source.
+ */
+var setupTransformFeedbackProgram = function(
+ gl, shaders, varyings, bufferMode, opt_attribs, opt_locations, opt_logShaders, opt_skipCompileStatus) {
+ var realShaders = [];
+ var program = gl.createProgram();
+ var shaderCount = 0;
+ for (var ii = 0; ii < shaders.length; ++ii) {
+ var shader = shaders[ii];
+ var shaderType = undefined;
+ if (typeof shader == 'string') {
+ var element = document.getElementById(shader);
+ if (element) {
+ if (element.type != "x-shader/x-vertex" && element.type != "x-shader/x-fragment")
+ shaderType = ii ? gl.FRAGMENT_SHADER : gl.VERTEX_SHADER;
+ shader = loadShaderFromScript(gl, shader, shaderType, undefined, opt_logShaders, opt_skipCompileStatus);
+ } else if (endsWith(shader, ".vert")) {
+ shader = loadShaderFromFile(gl, shader, gl.VERTEX_SHADER, undefined, opt_logShaders, opt_skipCompileStatus);
+ } else if (endsWith(shader, ".frag")) {
+ shader = loadShaderFromFile(gl, shader, gl.FRAGMENT_SHADER, undefined, opt_logShaders, opt_skipCompileStatus);
+ } else {
+ shader = loadShader(gl, shader, ii ? gl.FRAGMENT_SHADER : gl.VERTEX_SHADER, undefined, opt_logShaders, undefined, undefined, opt_skipCompileStatus);
+ }
+ } else if (opt_logShaders) {
+ throw 'Shader source logging requested but no shader source provided';
+ }
+ if (shader) {
+ ++shaderCount;
+ gl.attachShader(program, shader);
+ }
+ }
+ if (shaderCount != 2) {
+ error("Error in compiling shader");
+ return null;
+ }
+
+ if (opt_attribs) {
+ for (var ii = 0; ii < opt_attribs.length; ++ii) {
+ gl.bindAttribLocation(
+ program,
+ opt_locations ? opt_locations[ii] : ii,
+ opt_attribs[ii]);
+ }
+ }
+
+ gl.transformFeedbackVaryings(program, varyings, bufferMode);
+
+ gl.linkProgram(program);
+
+ // Check the link status
+ var linked = gl.getProgramParameter(program, gl.LINK_STATUS);
+ if (!linked) {
+ // something went wrong with the link
+ lastError = gl.getProgramInfoLog (program);
+ error("Error in program linking:" + lastError);
+
+ gl.deleteProgram(program);
+ return null;
+ }
+
+ gl.useProgram(program);
+ return program;
+};
+
+/**
+ * Creates a simple texture program.
+ * @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use.
+ * @return {WebGLProgram}
+ */
+var setupNoTexCoordTextureProgram = function(gl) {
+ return setupProgram(gl,
+ [noTexCoordTextureVertexShader, simpleTextureFragmentShader],
+ ['vPosition'],
+ [0]);
+};
+
+/**
+ * Creates a simple texture program.
+ * @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use.
+ * @param {number} opt_positionLocation The attrib location for position.
+ * @param {number} opt_texcoordLocation The attrib location for texture coords.
+ * @param {string} opt_fragmentShaderOverride The alternative fragment shader to use.
+ * @return {WebGLProgram}
+ */
+var setupSimpleTextureProgram = function(
+ gl, opt_positionLocation, opt_texcoordLocation, opt_fragmentShaderOverride) {
+ opt_positionLocation = opt_positionLocation || 0;
+ opt_texcoordLocation = opt_texcoordLocation || 1;
+ opt_fragmentShaderOverride = opt_fragmentShaderOverride || simpleTextureFragmentShader;
+ return setupProgram(gl,
+ [simpleTextureVertexShader, opt_fragmentShaderOverride],
+ ['vPosition', 'texCoord0'],
+ [opt_positionLocation, opt_texcoordLocation]);
+};
+
+/**
+ * Creates a simple texture program using glsl version 300.
+ * @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use.
+ * @param {number} opt_positionLocation The attrib location for position.
+ * @param {number} opt_texcoordLocation The attrib location for texture coords.
+ * @param {string} opt_fragmentShaderOverride The alternative fragment shader to use.
+ * @return {WebGLProgram}
+ */
+var setupSimpleTextureProgramESSL300 = function(
+ gl, opt_positionLocation, opt_texcoordLocation, opt_fragmentShaderOverride) {
+ opt_positionLocation = opt_positionLocation || 0;
+ opt_texcoordLocation = opt_texcoordLocation || 1;
+ opt_fragmentShaderOverride = opt_fragmentShaderOverride || simpleTextureFragmentShaderESSL300;
+ return setupProgram(gl,
+ [simpleTextureVertexShaderESSL300, opt_fragmentShaderOverride],
+ ['vPosition', 'texCoord0'],
+ [opt_positionLocation, opt_texcoordLocation]);
+};
+
+/**
+ * Creates a simple cube map texture program.
+ * @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use.
+ * @param {number} opt_positionLocation The attrib location for position.
+ * @param {number} opt_texcoordLocation The attrib location for texture coords.
+ * @return {WebGLProgram}
+ */
+var setupSimpleCubeMapTextureProgram = function(
+ gl, opt_positionLocation, opt_texcoordLocation) {
+ opt_positionLocation = opt_positionLocation || 0;
+ opt_texcoordLocation = opt_texcoordLocation || 1;
+ return setupProgram(gl,
+ [simpleTextureVertexShader, simpleCubeMapTextureFragmentShader],
+ ['vPosition', 'texCoord0'],
+ [opt_positionLocation, opt_texcoordLocation]);
+};
+
+/**
+ * Creates a simple vertex color program.
+ * @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use.
+ * @param {number} opt_positionLocation The attrib location for position.
+ * @param {number} opt_vertexColorLocation The attrib location
+ * for vertex colors.
+ * @return {WebGLProgram}
+ */
+var setupSimpleVertexColorProgram = function(
+ gl, opt_positionLocation, opt_vertexColorLocation) {
+ opt_positionLocation = opt_positionLocation || 0;
+ opt_vertexColorLocation = opt_vertexColorLocation || 1;
+ return setupProgram(gl,
+ [simpleVertexColorVertexShader, simpleVertexColorFragmentShader],
+ ['vPosition', 'a_color'],
+ [opt_positionLocation, opt_vertexColorLocation]);
+};
+
+/**
+ * Creates a simple color program.
+ * @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use.
+ * @param {number} opt_positionLocation The attrib location for position.
+ * @return {WebGLProgram}
+ */
+var setupSimpleColorProgram = function(gl, opt_positionLocation) {
+ opt_positionLocation = opt_positionLocation || 0;
+ return setupProgram(gl,
+ [simpleVertexShader, simpleColorFragmentShader],
+ ['vPosition'],
+ [opt_positionLocation]);
+};
+
+/**
+ * Creates buffers for a textured unit quad and attaches them to vertex attribs.
+ * @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use.
+ * @param {number} opt_positionLocation The attrib location for position.
+ * @param {number} opt_texcoordLocation The attrib location for texture coords.
+ * @param {!Object} various options. See setupQuad for details.
+ * @return {!Array.<WebGLBuffer>} The buffer objects that were
+ * created.
+ */
+var setupUnitQuad = function(gl, opt_positionLocation, opt_texcoordLocation, options) {
+ return setupQuadWithTexCoords(gl, [ 0.0, 0.0 ], [ 1.0, 1.0 ],
+ opt_positionLocation, opt_texcoordLocation,
+ options);
+};
+
+/**
+ * Creates buffers for a textured quad with specified lower left
+ * and upper right texture coordinates, and attaches them to vertex
+ * attribs.
+ * @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use.
+ * @param {!Array.<number>} lowerLeftTexCoords The texture coordinates for the lower left corner.
+ * @param {!Array.<number>} upperRightTexCoords The texture coordinates for the upper right corner.
+ * @param {number} opt_positionLocation The attrib location for position.
+ * @param {number} opt_texcoordLocation The attrib location for texture coords.
+ * @param {!Object} various options. See setupQuad for details.
+ * @return {!Array.<WebGLBuffer>} The buffer objects that were
+ * created.
+ */
+var setupQuadWithTexCoords = function(
+ gl, lowerLeftTexCoords, upperRightTexCoords,
+ opt_positionLocation, opt_texcoordLocation, options) {
+ var defaultOptions = {
+ positionLocation: opt_positionLocation || 0,
+ texcoordLocation: opt_texcoordLocation || 1,
+ lowerLeftTexCoords: lowerLeftTexCoords,
+ upperRightTexCoords: upperRightTexCoords
+ };
+ if (options) {
+ for (var prop in options) {
+ defaultOptions[prop] = options[prop]
+ }
+ }
+ return setupQuad(gl, defaultOptions);
+};
+
+/**
+ * Makes a quad with various options.
+ * @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use.
+ * @param {!Object} options
+ *
+ * scale: scale to multiply unit quad values by. default 1.0.
+ * positionLocation: attribute location for position.
+ * texcoordLocation: attribute location for texcoords.
+ * If this does not exist no texture coords are created.
+ * lowerLeftTexCoords: an array of 2 values for the
+ * lowerLeftTexCoords.
+ * upperRightTexCoords: an array of 2 values for the
+ * upperRightTexCoords.
+ */
+var setupQuad = function(gl, options) {
+ var positionLocation = options.positionLocation || 0;
+ var scale = options.scale || 1;
+
+ var objects = [];
+
+ var vertexObject = gl.createBuffer();
+ gl.bindBuffer(gl.ARRAY_BUFFER, vertexObject);
+ gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
+ 1.0 * scale , 1.0 * scale,
+ -1.0 * scale , 1.0 * scale,
+ -1.0 * scale , -1.0 * scale,
+ 1.0 * scale , 1.0 * scale,
+ -1.0 * scale , -1.0 * scale,
+ 1.0 * scale , -1.0 * scale]), gl.STATIC_DRAW);
+ gl.enableVertexAttribArray(positionLocation);
+ gl.vertexAttribPointer(positionLocation, 2, gl.FLOAT, false, 0, 0);
+ objects.push(vertexObject);
+
+ if (options.texcoordLocation !== undefined) {
+ var llx = options.lowerLeftTexCoords[0];
+ var lly = options.lowerLeftTexCoords[1];
+ var urx = options.upperRightTexCoords[0];
+ var ury = options.upperRightTexCoords[1];
+
+ vertexObject = gl.createBuffer();
+ gl.bindBuffer(gl.ARRAY_BUFFER, vertexObject);
+ gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
+ urx, ury,
+ llx, ury,
+ llx, lly,
+ urx, ury,
+ llx, lly,
+ urx, lly]), gl.STATIC_DRAW);
+ gl.enableVertexAttribArray(options.texcoordLocation);
+ gl.vertexAttribPointer(options.texcoordLocation, 2, gl.FLOAT, false, 0, 0);
+ objects.push(vertexObject);
+ }
+
+ return objects;
+};
+
+/**
+ * Creates a program and buffers for rendering a textured quad.
+ * @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use.
+ * @param {number} opt_positionLocation The attrib location for
+ * position. Default = 0.
+ * @param {number} opt_texcoordLocation The attrib location for
+ * texture coords. Default = 1.
+ * @param {!Object} various options defined by setupQuad, plus an option
+ fragmentShaderOverride to specify a custom fragment shader.
+ * @return {!WebGLProgram}
+ */
+var setupTexturedQuad = function(
+ gl, opt_positionLocation, opt_texcoordLocation, options) {
+ var program = setupSimpleTextureProgram(
+ gl, opt_positionLocation, opt_texcoordLocation, options && options.fragmentShaderOverride);
+ setupUnitQuad(gl, opt_positionLocation, opt_texcoordLocation, options);
+ return program;
+};
+
+/**
+ * Creates a program and buffers for rendering a color quad.
+ * @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use.
+ * @param {number} opt_positionLocation The attrib location for position.
+ * @param {!Object} various options. See setupQuad for details.
+ * @return {!WebGLProgram}
+ */
+var setupColorQuad = function(gl, opt_positionLocation, options) {
+ opt_positionLocation = opt_positionLocation || 0;
+ var program = setupSimpleColorProgram(gl, opt_positionLocation);
+ setupUnitQuad(gl, opt_positionLocation, 0, options);
+ return program;
+};
+
+/**
+ * Creates a program and buffers for rendering a textured quad with
+ * specified lower left and upper right texture coordinates.
+ * @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use.
+ * @param {!Array.<number>} lowerLeftTexCoords The texture coordinates for the lower left corner.
+ * @param {!Array.<number>} upperRightTexCoords The texture coordinates for the upper right corner.
+ * @param {number} opt_positionLocation The attrib location for position.
+ * @param {number} opt_texcoordLocation The attrib location for texture coords.
+ * @return {!WebGLProgram}
+ */
+var setupTexturedQuadWithTexCoords = function(
+ gl, lowerLeftTexCoords, upperRightTexCoords,
+ opt_positionLocation, opt_texcoordLocation) {
+ var program = setupSimpleTextureProgram(
+ gl, opt_positionLocation, opt_texcoordLocation);
+ setupQuadWithTexCoords(gl, lowerLeftTexCoords, upperRightTexCoords,
+ opt_positionLocation, opt_texcoordLocation);
+ return program;
+};
+
+/**
+ * Creates a program and buffers for rendering a textured quad with
+ * a cube map texture.
+ * @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use.
+ * @param {number} opt_positionLocation The attrib location for
+ * position. Default = 0.
+ * @param {number} opt_texcoordLocation The attrib location for
+ * texture coords. Default = 1.
+ * @return {!WebGLProgram}
+ */
+var setupTexturedQuadWithCubeMap = function(
+ gl, opt_positionLocation, opt_texcoordLocation) {
+ var program = setupSimpleCubeMapTextureProgram(
+ gl, opt_positionLocation, opt_texcoordLocation);
+ setupUnitQuad(gl, opt_positionLocation, opt_texcoordLocation, undefined);
+ return program;
+};
+
+/**
+ * Creates a unit quad with only positions of a given resolution.
+ * @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use.
+ * @param {number} gridRes The resolution of the mesh grid,
+ * expressed in the number of quads across and down.
+ * @param {number} opt_positionLocation The attrib location for position.
+ */
+var setupIndexedQuad = function (
+ gl, gridRes, opt_positionLocation, opt_flipOddTriangles) {
+ return setupIndexedQuadWithOptions(gl,
+ { gridRes: gridRes,
+ positionLocation: opt_positionLocation,
+ flipOddTriangles: opt_flipOddTriangles
+ });
+};
+
+/**
+ * Creates a quad with various options.
+ * @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use.
+ * @param {!Object} options The options. See below.
+ * @return {!Array.<WebGLBuffer>} The created buffers.
+ * [positions, <colors>, indices]
+ *
+ * Options:
+ * gridRes: number of quads across and down grid.
+ * positionLocation: attrib location for position
+ * flipOddTriangles: reverse order of vertices of every other
+ * triangle
+ * positionOffset: offset added to each vertex
+ * positionMult: multipier for each vertex
+ * colorLocation: attrib location for vertex colors. If
+ * undefined no vertex colors will be created.
+ */
+var setupIndexedQuadWithOptions = function (gl, options) {
+ var positionLocation = options.positionLocation || 0;
+ var objects = [];
+
+ var gridRes = options.gridRes || 1;
+ var positionOffset = options.positionOffset || 0;
+ var positionMult = options.positionMult || 1;
+ var vertsAcross = gridRes + 1;
+ var numVerts = vertsAcross * vertsAcross;
+ var positions = new Float32Array(numVerts * 3);
+ var indices = new Uint16Array(6 * gridRes * gridRes);
+ var poffset = 0;
+
+ for (var yy = 0; yy <= gridRes; ++yy) {
+ for (var xx = 0; xx <= gridRes; ++xx) {
+ positions[poffset + 0] = (-1 + 2 * xx / gridRes) * positionMult + positionOffset;
+ positions[poffset + 1] = (-1 + 2 * yy / gridRes) * positionMult + positionOffset;
+ positions[poffset + 2] = 0;
+
+ poffset += 3;
+ }
+ }
+
+ var buf = gl.createBuffer();
+ gl.bindBuffer(gl.ARRAY_BUFFER, buf);
+ gl.bufferData(gl.ARRAY_BUFFER, positions, gl.STATIC_DRAW);
+ gl.enableVertexAttribArray(positionLocation);
+ gl.vertexAttribPointer(positionLocation, 3, gl.FLOAT, false, 0, 0);
+ objects.push(buf);
+
+ if (options.colorLocation !== undefined) {
+ var colors = new Float32Array(numVerts * 4);
+ poffset = 0;
+ for (var yy = 0; yy <= gridRes; ++yy) {
+ for (var xx = 0; xx <= gridRes; ++xx) {
+ if (options.color !== undefined) {
+ colors[poffset + 0] = options.color[0];
+ colors[poffset + 1] = options.color[1];
+ colors[poffset + 2] = options.color[2];
+ colors[poffset + 3] = options.color[3];
+ } else {
+ colors[poffset + 0] = xx / gridRes;
+ colors[poffset + 1] = yy / gridRes;
+ colors[poffset + 2] = (xx / gridRes) * (yy / gridRes);
+ colors[poffset + 3] = (yy % 2) * 0.5 + 0.5;
+ }
+ poffset += 4;
+ }
+ }
+
+ buf = gl.createBuffer();
+ gl.bindBuffer(gl.ARRAY_BUFFER, buf);
+ gl.bufferData(gl.ARRAY_BUFFER, colors, gl.STATIC_DRAW);
+ gl.enableVertexAttribArray(options.colorLocation);
+ gl.vertexAttribPointer(options.colorLocation, 4, gl.FLOAT, false, 0, 0);
+ objects.push(buf);
+ }
+
+ var tbase = 0;
+ for (var yy = 0; yy < gridRes; ++yy) {
+ var index = yy * vertsAcross;
+ for (var xx = 0; xx < gridRes; ++xx) {
+ indices[tbase + 0] = index + 0;
+ indices[tbase + 1] = index + 1;
+ indices[tbase + 2] = index + vertsAcross;
+ indices[tbase + 3] = index + vertsAcross;
+ indices[tbase + 4] = index + 1;
+ indices[tbase + 5] = index + vertsAcross + 1;
+
+ if (options.flipOddTriangles) {
+ indices[tbase + 4] = index + vertsAcross + 1;
+ indices[tbase + 5] = index + 1;
+ }
+
+ index += 1;
+ tbase += 6;
+ }
+ }
+
+ buf = gl.createBuffer();
+ gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, buf);
+ gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indices, gl.STATIC_DRAW);
+ objects.push(buf);
+
+ return objects;
+};
+
+/**
+ * Returns the constructor for a typed array that corresponds to the given
+ * WebGL type.
+ * @param {!WebGLRenderingContext} gl A WebGLRenderingContext.
+ * @param {number} type The WebGL type (eg, gl.UNSIGNED_BYTE)
+ * @return {!Constructor} The typed array constructor that
+ * corresponds to the given type.
+ */
+var glTypeToTypedArrayType = function(gl, type) {
+ switch (type) {
+ case gl.BYTE:
+ return window.Int8Array;
+ case gl.UNSIGNED_BYTE:
+ return window.Uint8Array;
+ case gl.SHORT:
+ return window.Int16Array;
+ case gl.UNSIGNED_SHORT:
+ case gl.UNSIGNED_SHORT_5_6_5:
+ case gl.UNSIGNED_SHORT_4_4_4_4:
+ case gl.UNSIGNED_SHORT_5_5_5_1:
+ return window.Uint16Array;
+ case gl.INT:
+ return window.Int32Array;
+ case gl.UNSIGNED_INT:
+ case gl.UNSIGNED_INT_5_9_9_9_REV:
+ case gl.UNSIGNED_INT_10F_11F_11F_REV:
+ case gl.UNSIGNED_INT_2_10_10_10_REV:
+ case gl.UNSIGNED_INT_24_8:
+ return window.Uint32Array;
+ case gl.HALF_FLOAT:
+ case 0x8D61: // HALF_FLOAT_OES
+ return window.Uint16Array;
+ case gl.FLOAT:
+ return window.Float32Array;
+ default:
+ throw 'unknown gl type ' + glEnumToString(gl, type);
+ }
+};
+
+/**
+ * Returns the number of bytes per component for a given WebGL type.
+ * @param {!WebGLRenderingContext} gl A WebGLRenderingContext.
+ * @param {GLenum} type The WebGL type (eg, gl.UNSIGNED_BYTE)
+ * @return {number} The number of bytes per component.
+ */
+var getBytesPerComponent = function(gl, type) {
+ switch (type) {
+ case gl.BYTE:
+ case gl.UNSIGNED_BYTE:
+ return 1;
+ case gl.SHORT:
+ case gl.UNSIGNED_SHORT:
+ case gl.UNSIGNED_SHORT_5_6_5:
+ case gl.UNSIGNED_SHORT_4_4_4_4:
+ case gl.UNSIGNED_SHORT_5_5_5_1:
+ case gl.HALF_FLOAT:
+ case 0x8D61: // HALF_FLOAT_OES
+ return 2;
+ case gl.INT:
+ case gl.UNSIGNED_INT:
+ case gl.UNSIGNED_INT_5_9_9_9_REV:
+ case gl.UNSIGNED_INT_10F_11F_11F_REV:
+ case gl.UNSIGNED_INT_2_10_10_10_REV:
+ case gl.UNSIGNED_INT_24_8:
+ case gl.FLOAT:
+ return 4;
+ default:
+ throw 'unknown gl type ' + glEnumToString(gl, type);
+ }
+};
+
+/**
+ * Returns the number of typed array elements per pixel for a given WebGL
+ * format/type combination. The corresponding typed array type can be determined
+ * by calling glTypeToTypedArrayType.
+ * @param {!WebGLRenderingContext} gl A WebGLRenderingContext.
+ * @param {GLenum} format The WebGL format (eg, gl.RGBA)
+ * @param {GLenum} type The WebGL type (eg, gl.UNSIGNED_BYTE)
+ * @return {number} The number of typed array elements per pixel.
+ */
+var getTypedArrayElementsPerPixel = function(gl, format, type) {
+ switch (type) {
+ case gl.UNSIGNED_SHORT_5_6_5:
+ case gl.UNSIGNED_SHORT_4_4_4_4:
+ case gl.UNSIGNED_SHORT_5_5_5_1:
+ return 1;
+ case gl.UNSIGNED_BYTE:
+ break;
+ default:
+ throw 'not a gl type for color information ' + glEnumToString(gl, type);
+ }
+
+ switch (format) {
+ case gl.RGBA:
+ return 4;
+ case gl.RGB:
+ return 3;
+ case gl.LUMINANCE_ALPHA:
+ return 2;
+ case gl.LUMINANCE:
+ case gl.ALPHA:
+ return 1;
+ default:
+ throw 'unknown gl format ' + glEnumToString(gl, format);
+ }
+};
+
+/**
+ * Fills the given texture with a solid color.
+ * @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use.
+ * @param {!WebGLTexture} tex The texture to fill.
+ * @param {number} width The width of the texture to create.
+ * @param {number} height The height of the texture to create.
+ * @param {!Array.<number>} color The color to fill with.
+ * where each element is in the range 0 to 255.
+ * @param {number} opt_level The level of the texture to fill. Default = 0.
+ * @param {number} opt_format The format for the texture.
+ * @param {number} opt_internalFormat The internal format for the texture.
+ */
+var fillTexture = function(gl, tex, width, height, color, opt_level, opt_format, opt_type, opt_internalFormat) {
+ opt_level = opt_level || 0;
+ opt_format = opt_format || gl.RGBA;
+ opt_type = opt_type || gl.UNSIGNED_BYTE;
+ opt_internalFormat = opt_internalFormat || opt_format;
+ var pack = gl.getParameter(gl.UNPACK_ALIGNMENT);
+ var numComponents = color.length;
+ var bytesPerComponent = getBytesPerComponent(gl, opt_type);
+ var rowSize = numComponents * width * bytesPerComponent;
+ // See equation 3.10 in ES 2.0 spec and equation 3.13 in ES 3.0 spec for paddedRowLength calculation.
+ // k is paddedRowLength.
+ // n is numComponents.
+ // l is width.
+ // a is pack.
+ // s is bytesPerComponent.
+ var paddedRowLength;
+ if (bytesPerComponent >= pack)
+ paddedRowLength = numComponents * width;
+ else
+ paddedRowLength = Math.floor((rowSize + pack - 1) / pack) * pack / bytesPerComponent;
+ var size = width * numComponents + (height - 1) * paddedRowLength;
+ var buf = new (glTypeToTypedArrayType(gl, opt_type))(size);
+ for (var yy = 0; yy < height; ++yy) {
+ var off = yy * paddedRowLength;
+ for (var xx = 0; xx < width; ++xx) {
+ for (var jj = 0; jj < numComponents; ++jj) {
+ buf[off++] = color[jj];
+ }
+ }
+ }
+ gl.bindTexture(gl.TEXTURE_2D, tex);
+ gl.texImage2D(
+ gl.TEXTURE_2D, opt_level, opt_internalFormat, width, height, 0,
+ opt_format, opt_type, buf);
+};
+
+/**
+ * Creates a texture and fills it with a solid color.
+ * @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use.
+ * @param {number} width The width of the texture to create.
+ * @param {number} height The height of the texture to create.
+ * @param {!Array.<number>} color The color to fill with. A 4 element array
+ * where each element is in the range 0 to 255.
+ * @return {!WebGLTexture}
+ */
+var createColoredTexture = function(gl, width, height, color) {
+ var tex = gl.createTexture();
+ fillTexture(gl, tex, width, height, color);
+ return tex;
+};
+
+var ubyteToFloat = function(c) {
+ return c / 255;
+};
+
+var ubyteColorToFloatColor = function(color) {
+ var floatColor = [];
+ for (var ii = 0; ii < color.length; ++ii) {
+ floatColor[ii] = ubyteToFloat(color[ii]);
+ }
+ return floatColor;
+};
+
+/**
+ * Sets the "u_color" uniform of the current program to color.
+ * @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use.
+ * @param {!Array.<number>} color 4 element array of 0-1 color
+ * components.
+ */
+var setFloatDrawColor = function(gl, color) {
+ var program = gl.getParameter(gl.CURRENT_PROGRAM);
+ var colorLocation = gl.getUniformLocation(program, "u_color");
+ gl.uniform4fv(colorLocation, color);
+};
+
+/**
+ * Sets the "u_color" uniform of the current program to color.
+ * @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use.
+ * @param {!Array.<number>} color 4 element array of 0-255 color
+ * components.
+ */
+var setUByteDrawColor = function(gl, color) {
+ setFloatDrawColor(gl, ubyteColorToFloatColor(color));
+};
+
+/**
+ * Draws a previously setup quad in the given color.
+ * @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use.
+ * @param {!Array.<number>} color The color to draw with. A 4
+ * element array where each element is in the range 0 to
+ * 1.
+ */
+var drawFloatColorQuad = function(gl, color) {
+ var program = gl.getParameter(gl.CURRENT_PROGRAM);
+ var colorLocation = gl.getUniformLocation(program, "u_color");
+ gl.uniform4fv(colorLocation, color);
+ gl.drawArrays(gl.TRIANGLES, 0, 6);
+};
+
+
+/**
+ * Draws a previously setup quad in the given color.
+ * @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use.
+ * @param {!Array.<number>} color The color to draw with. A 4
+ * element array where each element is in the range 0 to
+ * 255.
+ */
+var drawUByteColorQuad = function(gl, color) {
+ drawFloatColorQuad(gl, ubyteColorToFloatColor(color));
+};
+
+/**
+ * Draws a previously setupUnitQuad.
+ * @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use.
+ */
+var drawUnitQuad = function(gl) {
+ gl.drawArrays(gl.TRIANGLES, 0, 6);
+};
+
+var dummySetProgramAndDrawNothing = function(gl) {
+ if (!gl._wtuDummyProgram) {
+ gl._wtuDummyProgram = setupProgram(gl, [
+ "void main() { gl_Position = vec4(0.0); }",
+ "void main() { gl_FragColor = vec4(0.0); }"
+ ], [], []);
+ }
+ gl.useProgram(gl._wtuDummyProgram);
+ gl.drawArrays(gl.TRIANGLES, 0, 3);
+};
+
+/**
+ * Clears then Draws a previously setupUnitQuad.
+ * @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use.
+ * @param {!Array.<number>} opt_color The color to fill clear with before
+ * drawing. A 4 element array where each element is in the range 0 to
+ * 255. Default [255, 255, 255, 255]
+ */
+var clearAndDrawUnitQuad = function(gl, opt_color) {
+ opt_color = opt_color || [255, 255, 255, 255];
+ gl.clearColor(
+ opt_color[0] / 255,
+ opt_color[1] / 255,
+ opt_color[2] / 255,
+ opt_color[3] / 255);
+ gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
+ drawUnitQuad(gl);
+};
+
+/**
+ * Draws a quad previously setup with setupIndexedQuad.
+ * @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use.
+ * @param {number} gridRes Resolution of grid.
+ */
+var drawIndexedQuad = function(gl, gridRes) {
+ gl.drawElements(gl.TRIANGLES, gridRes * gridRes * 6, gl.UNSIGNED_SHORT, 0);
+};
+
+/**
+ * Draws a previously setupIndexedQuad
+ * @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use.
+ * @param {number} gridRes Resolution of grid.
+ * @param {!Array.<number>} opt_color The color to fill clear with before
+ * drawing. A 4 element array where each element is in the range 0 to
+ * 255. Default [255, 255, 255, 255]
+ */
+var clearAndDrawIndexedQuad = function(gl, gridRes, opt_color) {
+ opt_color = opt_color || [255, 255, 255, 255];
+ gl.clearColor(
+ opt_color[0] / 255,
+ opt_color[1] / 255,
+ opt_color[2] / 255,
+ opt_color[3] / 255);
+ gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
+ drawIndexedQuad(gl, gridRes);
+};
+
+/**
+ * Clips a range to min, max
+ * (Eg. clipToRange(-5,7,0,20) would return {value:0,extent:2}
+ * @param {number} value start of range
+ * @param {number} extent extent of range
+ * @param {number} min min.
+ * @param {number} max max.
+ * @return {!{value:number,extent:number}} The clipped value.
+ */
+var clipToRange = function(value, extent, min, max) {
+ if (value < min) {
+ extent -= min - value;
+ value = min;
+ }
+ var end = value + extent;
+ if (end > max) {
+ extent -= end - max;
+ }
+ if (extent < 0) {
+ value = max;
+ extent = 0;
+ }
+ return {value:value, extent: extent};
+};
+
+/**
+ * Determines if the passed context is an instance of a WebGLRenderingContext
+ * or later variant (like WebGL2RenderingContext)
+ * @param {CanvasRenderingContext} ctx The context to check.
+ */
+var isWebGLContext = function(ctx) {
+ if (ctx instanceof WebGLRenderingContext)
+ return true;
+
+ if ('WebGL2RenderingContext' in window && ctx instanceof WebGL2RenderingContext)
+ return true;
+
+ return false;
+};
+
+/**
+ * Creates a check rect is used by checkCanvasRects.
+ * @param {number} x left corner of region to check.
+ * @param {number} y bottom corner of region to check in case of checking from
+ * a GL context or top corner in case of checking from a 2D context.
+ * @param {number} width width of region to check.
+ * @param {number} height width of region to check.
+ * @param {!Array.<number>} color The color expected. A 4 element array where
+ * each element is in the range 0 to 255.
+ * @param {string} opt_msg Message to associate with success. Eg
+ * ("should be red").
+ * @param {number} opt_errorRange Optional. Acceptable error in
+ * color checking. 0 by default.
+ */
+var makeCheckRect = function(x, y, width, height, color, msg, errorRange) {
+ var rect = {
+ 'x': x, 'y': y,
+ 'width': width, 'height': height,
+ 'color': color, 'msg': msg,
+ 'errorRange': errorRange,
+
+ 'checkRect': function (buf, l, b, w) {
+ for (var px = (x - l) ; px < (x + width - l) ; ++px) {
+ for (var py = (y - b) ; py < (y + height - b) ; ++py) {
+ var offset = (py * w + px) * 4;
+ for (var j = 0; j < color.length; ++j) {
+ if (Math.abs(buf[offset + j] - color[j]) > errorRange) {
+ testFailed(msg);
+ var was = buf[offset + 0].toString();
+ for (j = 1; j < color.length; ++j) {
+ was += "," + buf[offset + j];
+ }
+ debug('at (' + px + ', ' + py +
+ ') expected: ' + color + ' was ' + was);
+ return;
+ }
+ }
+ }
+ }
+ testPassed(msg);
+ }
+ }
+ return rect;
+};
+
+/**
+ * Checks that a portions of a canvas or the currently attached framebuffer is 1 color.
+ * @param {!WebGLRenderingContext|CanvasRenderingContext2D} gl The
+ * WebGLRenderingContext or 2D context to use.
+ * @param {!Array.<checkRect>} array of rects to check for matching color.
+ */
+var checkCanvasRects = function(gl, rects) {
+ if (rects.length > 0) {
+ var left = rects[0].x;
+ var right = rects[0].x + rects[1].width;
+ var bottom = rects[0].y;
+ var top = rects[0].y + rects[0].height;
+ for (var i = 1; i < rects.length; ++i) {
+ left = Math.min(left, rects[i].x);
+ right = Math.max(right, rects[i].x + rects[i].width);
+ bottom = Math.min(bottom, rects[i].y);
+ top = Math.max(top, rects[i].y + rects[i].height);
+ }
+ var width = right - left;
+ var height = top - bottom;
+ var buf = new Uint8Array(width * height * 4);
+ gl.readPixels(left, bottom, width, height, gl.RGBA, gl.UNSIGNED_BYTE, buf);
+ for (var i = 0; i < rects.length; ++i) {
+ rects[i].checkRect(buf, left, bottom, width);
+ }
+ }
+};
+
+/**
+ * Checks that a portion of a canvas or the currently attached framebuffer is 1 color.
+ * @param {!WebGLRenderingContext|CanvasRenderingContext2D} gl The
+ * WebGLRenderingContext or 2D context to use.
+ * @param {number} x left corner of region to check.
+ * @param {number} y bottom corner of region to check in case of checking from
+ * a GL context or top corner in case of checking from a 2D context.
+ * @param {number} width width of region to check.
+ * @param {number} height width of region to check.
+ * @param {!Array.<number>} color The color expected. A 4 element array where
+ * each element is in the range 0 to 255.
+ * @param {number} opt_errorRange Optional. Acceptable error in
+ * color checking. 0 by default.
+ * @param {!function()} sameFn Function to call if all pixels
+ * are the same as color.
+ * @param {!function()} differentFn Function to call if a pixel
+ * is different than color
+ * @param {!function()} logFn Function to call for logging.
+ * @param {TypedArray} opt_readBackBuf optional buffer to read back into.
+ * Typically passed to either reuse buffer, or support readbacks from
+ * floating-point/norm16 framebuffers.
+ * @param {GLenum} opt_readBackType optional read back type, defaulting to
+ * gl.UNSIGNED_BYTE. Can be used to support readback from floating-point
+ * /norm16 framebuffers.
+ * @param {GLenum} opt_readBackFormat optional read back format, defaulting to
+ * gl.RGBA. Can be used to support readback from norm16
+ * framebuffers.
+ */
+var checkCanvasRectColor = function(gl, x, y, width, height, color, opt_errorRange, sameFn, differentFn, logFn, opt_readBackBuf, opt_readBackType, opt_readBackFormat) {
+ if (isWebGLContext(gl) && !gl.getParameter(gl.FRAMEBUFFER_BINDING)) {
+ // We're reading the backbuffer so clip.
+ var xr = clipToRange(x, width, 0, gl.canvas.width);
+ var yr = clipToRange(y, height, 0, gl.canvas.height);
+ if (!xr.extent || !yr.extent) {
+ logFn("checking rect: effective width or height is zero");
+ sameFn();
+ return;
+ }
+ x = xr.value;
+ y = yr.value;
+ width = xr.extent;
+ height = yr.extent;
+ }
+ var errorRange = opt_errorRange || 0;
+ if (!errorRange.length) {
+ errorRange = [errorRange, errorRange, errorRange, errorRange]
+ }
+ var buf;
+ if (isWebGLContext(gl)) {
+ buf = opt_readBackBuf ? opt_readBackBuf : new Uint8Array(width * height * 4);
+ var readBackType = opt_readBackType ? opt_readBackType : gl.UNSIGNED_BYTE;
+ var readBackFormat = opt_readBackFormat ? opt_readBackFormat : gl.RGBA;
+ gl.readPixels(x, y, width, height, readBackFormat, readBackType, buf);
+ } else {
+ buf = gl.getImageData(x, y, width, height).data;
+ }
+ for (var i = 0; i < width * height; ++i) {
+ var offset = i * 4;
+ for (var j = 0; j < color.length; ++j) {
+ if (Math.abs(buf[offset + j] - color[j]) > errorRange[j]) {
+ var was = buf[offset + 0].toString();
+ for (j = 1; j < color.length; ++j) {
+ was += "," + buf[offset + j];
+ }
+ differentFn('at (' + (x + (i % width)) + ', ' + (y + Math.floor(i / width)) +
+ ') expected: ' + color + ' was ' + was, buf);
+ return;
+ }
+ }
+ }
+ sameFn();
+};
+
+/**
+ * Checks that a portion of a canvas or the currently attached framebuffer is 1 color.
+ * @param {!WebGLRenderingContext|CanvasRenderingContext2D} gl The
+ * WebGLRenderingContext or 2D context to use.
+ * @param {number} x left corner of region to check.
+ * @param {number} y bottom corner of region to check in case of checking from
+ * a GL context or top corner in case of checking from a 2D context.
+ * @param {number} width width of region to check.
+ * @param {number} height width of region to check.
+ * @param {!Array.<number>} color The color expected. A 4 element array where
+ * each element is in the range 0 to 255.
+ * @param {string} opt_msg Message to associate with success or failure. Eg
+ * ("should be red").
+ * @param {number} opt_errorRange Optional. Acceptable error in
+ * color checking. 0 by default.
+ * @param {TypedArray} opt_readBackBuf optional buffer to read back into.
+ * Typically passed to either reuse buffer, or support readbacks from
+ * floating-point/norm16 framebuffers.
+ * @param {GLenum} opt_readBackType optional read back type, defaulting to
+ * gl.UNSIGNED_BYTE. Can be used to support readback from floating-point
+ * /norm16 framebuffers.
+ * @param {GLenum} opt_readBackFormat optional read back format, defaulting to
+ * gl.RGBA. Can be used to support readback from floating-point
+ * /norm16 framebuffers.
+ */
+var checkCanvasRect = function(gl, x, y, width, height, color, opt_msg, opt_errorRange, opt_readBackBuf, opt_readBackType, opt_readBackFormat) {
+ checkCanvasRectColor(
+ gl, x, y, width, height, color, opt_errorRange,
+ function() {
+ var msg = opt_msg;
+ if (msg === undefined)
+ msg = "should be " + color.toString();
+ testPassed(msg);
+ },
+ function(differentMsg) {
+ var msg = opt_msg;
+ if (msg === undefined)
+ msg = "should be " + color.toString();
+ testFailed(msg + "\n" + differentMsg);
+ },
+ debug,
+ opt_readBackBuf,
+ opt_readBackType,
+ opt_readBackFormat);
+};
+
+/**
+ * Checks that an entire canvas or the currently attached framebuffer is 1 color.
+ * @param {!WebGLRenderingContext|CanvasRenderingContext2D} gl The
+ * WebGLRenderingContext or 2D context to use.
+ * @param {!Array.<number>} color The color expected. A 4 element array where
+ * each element is in the range 0 to 255.
+ * @param {string} msg Message to associate with success. Eg ("should be red").
+ * @param {number} errorRange Optional. Acceptable error in
+ * color checking. 0 by default.
+ */
+var checkCanvas = function(gl, color, msg, errorRange) {
+ checkCanvasRect(gl, 0, 0, gl.canvas.width, gl.canvas.height, color, msg, errorRange);
+};
+
+/**
+ * Checks a rectangular area both inside the area and outside
+ * the area.
+ * @param {!WebGLRenderingContext|CanvasRenderingContext2D} gl The
+ * WebGLRenderingContext or 2D context to use.
+ * @param {number} x left corner of region to check.
+ * @param {number} y bottom corner of region to check in case of checking from
+ * a GL context or top corner in case of checking from a 2D context.
+ * @param {number} width width of region to check.
+ * @param {number} height width of region to check.
+ * @param {!Array.<number>} innerColor The color expected inside
+ * the area. A 4 element array where each element is in the
+ * range 0 to 255.
+ * @param {!Array.<number>} outerColor The color expected
+ * outside. A 4 element array where each element is in the
+ * range 0 to 255.
+ * @param {!number} opt_edgeSize: The number of pixels to skip
+ * around the edges of the area. Defaut 0.
+ * @param {!{width:number, height:number}} opt_outerDimensions
+ * The outer dimensions. Default the size of gl.canvas.
+ */
+var checkAreaInAndOut = function(gl, x, y, width, height, innerColor, outerColor, opt_edgeSize, opt_outerDimensions) {
+ var outerDimensions = opt_outerDimensions || { width: gl.canvas.width, height: gl.canvas.height };
+ var edgeSize = opt_edgeSize || 0;
+ checkCanvasRect(gl, x + edgeSize, y + edgeSize, width - edgeSize * 2, height - edgeSize * 2, innerColor);
+ checkCanvasRect(gl, 0, 0, x - edgeSize, outerDimensions.height, outerColor);
+ checkCanvasRect(gl, x + width + edgeSize, 0, outerDimensions.width - x - width - edgeSize, outerDimensions.height, outerColor);
+ checkCanvasRect(gl, 0, 0, outerDimensions.width, y - edgeSize, outerColor);
+ checkCanvasRect(gl, 0, y + height + edgeSize, outerDimensions.width, outerDimensions.height - y - height - edgeSize, outerColor);
+};
+
+/**
+ * Checks that an entire buffer matches the floating point values provided.
+ * (WebGL 2.0 only)
+ * @param {!WebGL2RenderingContext} gl The WebGL2RenderingContext to use.
+ * @param {number} target The buffer target to bind to.
+ * @param {!Array.<number>} expected The values expected.
+ * @param {string} opt_msg Optional. Message to associate with success. Eg ("should be red").
+ * @param {number} opt_errorRange Optional. Acceptable error in value checking. 0.001 by default.
+ */
+var checkFloatBuffer = function(gl, target, expected, opt_msg, opt_errorRange) {
+ if (opt_msg === undefined)
+ opt_msg = "buffer should match expected values";
+
+ if (opt_errorRange === undefined)
+ opt_errorRange = 0.001;
+
+ var floatArray = new Float32Array(expected.length);
+ gl.getBufferSubData(target, 0, floatArray);
+
+ for (var i = 0; i < expected.length; i++) {
+ if (Math.abs(floatArray[i] - expected[i]) > opt_errorRange) {
+ testFailed(opt_msg);
+ debug('at [' + i + '] expected: ' + expected[i] + ' was ' + floatArray[i]);
+ return;
+ }
+ }
+ testPassed(opt_msg);
+};
+
+/**
+ * Loads a texture, calls callback when finished.
+ * @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use.
+ * @param {string} url URL of image to load
+ * @param {function(!Image): void} callback Function that gets called after
+ * image has loaded
+ * @return {!WebGLTexture} The created texture.
+ */
+var loadTexture = function(gl, url, callback) {
+ var texture = gl.createTexture();
+ gl.bindTexture(gl.TEXTURE_2D, texture);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
+ var image = new Image();
+ image.onload = function() {
+ gl.bindTexture(gl.TEXTURE_2D, texture);
+ gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);
+ gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image);
+ callback(image);
+ };
+ image.src = url;
+ return texture;
+};
+
+/**
+ * Checks whether the bound texture has expected dimensions. One corner pixel
+ * of the texture will be changed as a side effect.
+ * @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use.
+ * @param {!WebGLTexture} texture The texture to check.
+ * @param {number} width Expected width.
+ * @param {number} height Expected height.
+ * @param {GLenum} opt_format The texture's format. Defaults to RGBA.
+ * @param {GLenum} opt_type The texture's type. Defaults to UNSIGNED_BYTE.
+ */
+var checkTextureSize = function(gl, width, height, opt_format, opt_type) {
+ opt_format = opt_format || gl.RGBA;
+ opt_type = opt_type || gl.UNSIGNED_BYTE;
+
+ var numElements = getTypedArrayElementsPerPixel(gl, opt_format, opt_type);
+ var buf = new (glTypeToTypedArrayType(gl, opt_type))(numElements);
+
+ var errors = 0;
+ gl.texSubImage2D(gl.TEXTURE_2D, 0, width - 1, height - 1, 1, 1, opt_format, opt_type, buf);
+ if (gl.getError() != gl.NO_ERROR) {
+ testFailed("Texture was smaller than the expected size " + width + "x" + height);
+ ++errors;
+ }
+ gl.texSubImage2D(gl.TEXTURE_2D, 0, width - 1, height, 1, 1, opt_format, opt_type, buf);
+ if (gl.getError() == gl.NO_ERROR) {
+ testFailed("Texture was taller than " + height);
+ ++errors;
+ }
+ gl.texSubImage2D(gl.TEXTURE_2D, 0, width, height - 1, 1, 1, opt_format, opt_type, buf);
+ if (gl.getError() == gl.NO_ERROR) {
+ testFailed("Texture was wider than " + width);
+ ++errors;
+ }
+ if (errors == 0) {
+ testPassed("Texture had the expected size " + width + "x" + height);
+ }
+};
+
+/**
+ * Makes a shallow copy of an object.
+ * @param {!Object} src Object to copy
+ * @return {!Object} The copy of src.
+ */
+var shallowCopyObject = function(src) {
+ var dst = {};
+ for (var attr in src) {
+ if (src.hasOwnProperty(attr)) {
+ dst[attr] = src[attr];
+ }
+ }
+ return dst;
+};
+
+/**
+ * Checks if an attribute exists on an object case insensitive.
+ * @param {!Object} obj Object to check
+ * @param {string} attr Name of attribute to look for.
+ * @return {string?} The name of the attribute if it exists,
+ * undefined if not.
+ */
+var hasAttributeCaseInsensitive = function(obj, attr) {
+ var lower = attr.toLowerCase();
+ for (var key in obj) {
+ if (obj.hasOwnProperty(key) && key.toLowerCase() == lower) {
+ return key;
+ }
+ }
+};
+
+/**
+ * Returns a map of URL querystring options
+ * @return {Object?} Object containing all the values in the URL querystring
+ */
+var getUrlOptions = (function() {
+ var _urlOptionsParsed = false;
+ var _urlOptions = {};
+ return function() {
+ if (!_urlOptionsParsed) {
+ var s = window.location.href;
+ var q = s.indexOf("?");
+ var e = s.indexOf("#");
+ if (e < 0) {
+ e = s.length;
+ }
+ var query = s.substring(q + 1, e);
+ var pairs = query.split("&");
+ for (var ii = 0; ii < pairs.length; ++ii) {
+ var keyValue = pairs[ii].split("=");
+ var key = keyValue[0];
+ var value = decodeURIComponent(keyValue[1]);
+ _urlOptions[key] = value;
+ }
+ _urlOptionsParsed = true;
+ }
+
+ return _urlOptions;
+ }
+})();
+
+var default3DContextVersion = 1;
+
+/**
+ * Set the default context version for create3DContext.
+ * Initially the default version is 1.
+ * @param {number} Default version of WebGL contexts.
+ */
+var setDefault3DContextVersion = function(version) {
+ default3DContextVersion = version;
+};
+
+/**
+ * Get the default contex version for create3DContext.
+ * First it looks at the URI option |webglVersion|. If it does not exist,
+ * then look at the global default3DContextVersion variable.
+ */
+var getDefault3DContextVersion = function() {
+ return parseInt(getUrlOptions().webglVersion, 10) || default3DContextVersion;
+};
+
+/**
+ * Creates a webgl context.
+ * @param {!Canvas|string} opt_canvas The canvas tag to get
+ * context from. If one is not passed in one will be
+ * created. If it's a string it's assumed to be the id of a
+ * canvas.
+ * @param {Object} opt_attributes Context attributes.
+ * @param {!number} opt_version Version of WebGL context to create.
+ * The default version can be set by calling setDefault3DContextVersion.
+ * @return {!WebGLRenderingContext} The created context.
+ */
+var create3DContext = function(opt_canvas, opt_attributes, opt_version) {
+ if (window.initTestingHarness) {
+ window.initTestingHarness();
+ }
+ var attributes = shallowCopyObject(opt_attributes || {});
+ if (!hasAttributeCaseInsensitive(attributes, "antialias")) {
+ attributes.antialias = false;
+ }
+
+ const parseString = v => v;
+ const parseBoolean = v => v.toLowerCase().startsWith('t') || parseFloat(v) > 0;
+ const params = new URLSearchParams(window.location.search);
+ for (const [key, parseFn] of Object.entries({
+ alpha: parseBoolean,
+ antialias: parseBoolean,
+ depth: parseBoolean,
+ desynchronized: parseBoolean,
+ failIfMajorPerformanceCaveat: parseBoolean,
+ powerPreference: parseString,
+ premultipliedAlpha: parseBoolean,
+ preserveDrawingBuffer: parseBoolean,
+ stencil: parseBoolean,
+ })) {
+ const value = params.get(key);
+ if (value) {
+ const v = parseFn(value);
+ attributes[key] = v;
+ debug(`setting context attribute: ${key} = ${v}`);
+ }
+ }
+
+ if (!opt_version) {
+ opt_version = getDefault3DContextVersion();
+ }
+ opt_canvas = opt_canvas || document.createElement("canvas");
+ if (typeof opt_canvas == 'string') {
+ opt_canvas = document.getElementById(opt_canvas);
+ }
+ var context = null;
+
+ var names;
+ switch (opt_version) {
+ case 2:
+ names = ["webgl2"]; break;
+ default:
+ names = ["webgl", "experimental-webgl"]; break;
+ }
+
+ for (var i = 0; i < names.length; ++i) {
+ try {
+ context = opt_canvas.getContext(names[i], attributes);
+ } catch (e) {
+ }
+ if (context) {
+ break;
+ }
+ }
+ if (!context) {
+ testFailed("Unable to fetch WebGL rendering context for Canvas");
+ } else {
+ if (!window._wtu_contexts) {
+ window._wtu_contexts = []
+ }
+ window._wtu_contexts.push(context);
+ }
+
+ if (params.get('showRenderer')) {
+ const ext = context.getExtension('WEBGL_debug_renderer_info');
+ debug(`RENDERER: ${context.getParameter(ext ? ext.UNMASKED_RENDERER_WEBGL : context.RENDERER)}`);
+ }
+
+ return context;
+};
+
+/**
+ * Indicates whether the given context is WebGL 2.0 or greater.
+ * @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use.
+ * @return {boolean} True if the given context is WebGL 2.0 or greater.
+ */
+var isWebGL2 = function(gl) {
+ // Duck typing is used so that the conformance suite can be run
+ // against libraries emulating WebGL 1.0 on top of WebGL 2.0.
+ return !!gl.drawArraysInstanced;
+};
+
+/**
+ * Defines the exception type for a GL error.
+ * @constructor
+ * @param {string} message The error message.
+ * @param {number} error GL error code
+ */
+function GLErrorException (message, error) {
+ this.message = message;
+ this.name = "GLErrorException";
+ this.error = error;
+};
+
+/**
+ * Wraps a WebGL function with a function that throws an exception if there is
+ * an error.
+ * @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use.
+ * @param {string} fname Name of function to wrap.
+ * @return {function()} The wrapped function.
+ */
+var createGLErrorWrapper = function(context, fname) {
+ return function() {
+ var rv = context[fname].apply(context, arguments);
+ var err = context.getError();
+ if (err != context.NO_ERROR) {
+ var msg = "GL error " + glEnumToString(context, err) + " in " + fname;
+ throw new GLErrorException(msg, err);
+ }
+ return rv;
+ };
+};
+
+/**
+ * Creates a WebGL context where all functions are wrapped to throw an exception
+ * if there is an error.
+ * @param {!Canvas} canvas The HTML canvas to get a context from.
+ * @param {Object} opt_attributes Context attributes.
+ * @param {!number} opt_version Version of WebGL context to create
+ * @return {!Object} The wrapped context.
+ */
+function create3DContextWithWrapperThatThrowsOnGLError(canvas, opt_attributes, opt_version) {
+ var context = create3DContext(canvas, opt_attributes, opt_version);
+ var wrap = {};
+ for (var i in context) {
+ try {
+ if (typeof context[i] == 'function') {
+ wrap[i] = createGLErrorWrapper(context, i);
+ } else {
+ wrap[i] = context[i];
+ }
+ } catch (e) {
+ error("createContextWrapperThatThrowsOnGLError: Error accessing " + i);
+ }
+ }
+ wrap.getError = function() {
+ return context.getError();
+ };
+ return wrap;
+};
+
+/**
+ * Tests that an evaluated expression generates a specific GL error.
+ * @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use.
+ * @param {number|Array.<number>} glErrors The expected gl error or an array of expected errors.
+ * @param {string} evalStr The string to evaluate.
+ */
+var shouldGenerateGLError = function(gl, glErrors, evalStr, opt_msg) {
+ var exception;
+ try {
+ eval(evalStr);
+ } catch (e) {
+ exception = e;
+ }
+ if (exception) {
+ testFailed(evalStr + " threw exception " + exception);
+ return -1;
+ } else {
+ if (!opt_msg) {
+ opt_msg = "after evaluating: " + evalStr;
+ }
+ return glErrorShouldBe(gl, glErrors, opt_msg);
+ }
+};
+
+/**
+ * Tests that an evaluated expression does not generate a GL error.
+ * @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use.
+ * @param {string} evalStr The string to evaluate.
+ */
+var failIfGLError = function(gl, evalStr) {
+ var exception;
+ try {
+ eval(evalStr);
+ } catch (e) {
+ exception = e;
+ }
+ if (exception) {
+ testFailed(evalStr + " threw exception " + exception);
+ } else {
+ glErrorShouldBeImpl(gl, gl.NO_ERROR, false, "after evaluating: " + evalStr);
+ }
+};
+
+/**
+ * Tests that the first error GL returns is the specified error.
+ * @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use.
+ * @param {number|Array.<number>} glErrors The expected gl error or an array of expected errors.
+ * @param {string} opt_msg Optional additional message.
+ */
+var glErrorShouldBe = function(gl, glErrors, opt_msg) {
+ return glErrorShouldBeImpl(gl, glErrors, true, opt_msg);
+};
+
+const glErrorAssert = function(gl, glErrors, opt_msg) {
+ return glErrorShouldBeImpl(gl, glErrors, false, opt_msg);
+};
+
+/**
+ * Tests that the given framebuffer has a specific status
+ * @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use.
+ * @param {number|Array.<number>} glStatuses The expected gl
+ * status or an array of expected statuses.
+ * @param {string} opt_msg Optional additional message.
+ */
+var framebufferStatusShouldBe = function(gl, target, glStatuses, opt_msg) {
+ if (!glStatuses.length) {
+ glStatuses = [glStatuses];
+ }
+ opt_msg = opt_msg || "";
+ const status = gl.checkFramebufferStatus(target);
+ const ndx = glStatuses.indexOf(status);
+ const expected = glStatuses.map((status) => {
+ return glEnumToString(gl, status);
+ }).join(' or ');
+ if (ndx < 0) {
+ let msg = "checkFramebufferStatus expected" + ((glStatuses.length > 1) ? " one of: " : ": ") +
+ expected + ". Was " + glEnumToString(gl, status);
+ if (opt_msg) {
+ msg += ": " + opt_msg;
+ }
+ testFailed(msg);
+ return false;
+ }
+ let msg = `checkFramebufferStatus was ${glEnumToString(gl, status)}`;
+ if (glStatuses.length > 1) {
+ msg += `, one of: ${expected}`;
+ }
+ if (opt_msg) {
+ msg += ": " + opt_msg;
+ }
+ testPassed(msg);
+ return [status];
+}
+
+/**
+ * Tests that the first error GL returns is the specified error. Allows suppression of successes.
+ * @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use.
+ * @param {number|Array.<number>} glErrors The expected gl error or an array of expected errors.
+ * @param {boolean} reportSuccesses Whether to report successes as passes, or to silently pass.
+ * @param {string} opt_msg Optional additional message.
+ */
+var glErrorShouldBeImpl = function(gl, glErrors, reportSuccesses, opt_msg) {
+ if (!glErrors.length) {
+ glErrors = [glErrors];
+ }
+ opt_msg = opt_msg || "";
+
+ const fnErrStr = function(errVal) {
+ if (errVal == 0) return "NO_ERROR";
+ return glEnumToString(gl, errVal);
+ };
+
+ var err = gl.getError();
+ var ndx = glErrors.indexOf(err);
+ var errStrs = [];
+ for (var ii = 0; ii < glErrors.length; ++ii) {
+ errStrs.push(fnErrStr(glErrors[ii]));
+ }
+ var expected = errStrs.join(" or ");
+ if (ndx < 0) {
+ var msg = "getError expected" + ((glErrors.length > 1) ? " one of: " : ": ");
+ testFailed(msg + expected + ". Was " + fnErrStr(err) + " : " + opt_msg);
+ } else if (reportSuccesses) {
+ var msg = "getError was " + ((glErrors.length > 1) ? "one of: " : "expected value: ");
+ testPassed(msg + expected + " : " + opt_msg);
+ }
+ return err;
+};
+
+/**
+ * Tests that a function throws or not.
+ * @param {!WebGLContext} gl The WebGLContext to use.
+ * @param throwType Type of thrown error (e.g. TypeError), or false.
+ * @param {string} info Info on what's being tested
+ * @param {function} func The func to test.
+ */
+var shouldThrow = function(gl, throwType, info, func) {
+ while (gl.getError()) {}
+
+ var shouldThrow = (throwType != false);
+
+ try {
+ func();
+
+ if (shouldThrow) {
+ testFailed("Should throw a " + throwType.name + ": " + info);
+ } else {
+ testPassed("Should not have thrown: " + info);
+ }
+ } catch (e) {
+ if (shouldThrow) {
+ if (e instanceof throwType) {
+ testPassed("Should throw a " + throwType.name + ": " + info);
+ } else {
+ testFailed("Should throw a " + throwType.name + ", threw " + e.name + ": " + info);
+ }
+ } else {
+ testFailed("Should not have thrown: " + info);
+ }
+
+ if (gl.getError()) {
+ testFailed("Should not generate an error when throwing: " + info);
+ }
+ }
+
+ while (gl.getError()) {}
+};
+
+/**
+ * Links a WebGL program, throws if there are errors.
+ * @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use.
+ * @param {!WebGLProgram} program The WebGLProgram to link.
+ * @param {function(string): void} opt_errorCallback callback for errors.
+ */
+var linkProgram = function(gl, program, opt_errorCallback) {
+ var errFn = opt_errorCallback || testFailed;
+ // Link the program
+ gl.linkProgram(program);
+
+ // Check the link status
+ var linked = gl.getProgramParameter(program, gl.LINK_STATUS);
+ if (!linked) {
+ // something went wrong with the link
+ var error = gl.getProgramInfoLog (program);
+
+ errFn("Error in program linking:" + error);
+
+ gl.deleteProgram(program);
+ }
+};
+
+/**
+ * Loads text from an external file. This function is asynchronous.
+ * @param {string} url The url of the external file.
+ * @param {!function(bool, string): void} callback that is sent a bool for
+ * success and the string.
+ */
+var loadTextFileAsync = function(url, callback) {
+ log ("loading: " + url);
+ var error = 'loadTextFileAsync failed to load url "' + url + '"';
+ var request;
+ if (window.XMLHttpRequest) {
+ request = new XMLHttpRequest();
+ if (request.overrideMimeType) {
+ request.overrideMimeType('text/plain');
+ }
+ } else {
+ throw 'XMLHttpRequest is disabled';
+ }
+ try {
+ request.open('GET', url, true);
+ request.onreadystatechange = function() {
+ if (request.readyState == 4) {
+ var text = '';
+ // HTTP reports success with a 200 status. The file protocol reports
+ // success with zero. HTTP does not use zero as a status code (they
+ // start at 100).
+ // https://developer.mozilla.org/En/Using_XMLHttpRequest
+ var success = request.status == 200 || request.status == 0;
+ if (success) {
+ text = request.responseText;
+ log("completed load request: " + url);
+ } else {
+ log("loading " + url + " resulted in unexpected status: " + request.status + " " + request.statusText);
+ }
+ callback(success, text);
+ }
+ };
+ request.onerror = function(errorEvent) {
+ log("error occurred loading " + url);
+ callback(false, '');
+ };
+ request.send(null);
+ } catch (err) {
+ log("failed to load: " + url + " with exception " + err.message);
+ callback(false, '');
+ }
+};
+
+/**
+ * Recursively loads a file as a list. Each line is parsed for a relative
+ * path. If the file ends in .txt the contents of that file is inserted in
+ * the list.
+ *
+ * @param {string} url The url of the external file.
+ * @param {!function(bool, Array<string>): void} callback that is sent a bool
+ * for success and the array of strings.
+ */
+var getFileListAsync = function(url, callback) {
+ var files = [];
+
+ var getFileListImpl = function(url, callback) {
+ var files = [];
+ if (url.substr(url.length - 4) == '.txt') {
+ loadTextFileAsync(url, function() {
+ return function(success, text) {
+ if (!success) {
+ callback(false, '');
+ return;
+ }
+ var lines = text.split('\n');
+ var prefix = '';
+ var lastSlash = url.lastIndexOf('/');
+ if (lastSlash >= 0) {
+ prefix = url.substr(0, lastSlash + 1);
+ }
+ var fail = false;
+ var count = 1;
+ var index = 0;
+ for (var ii = 0; ii < lines.length; ++ii) {
+ var str = lines[ii].replace(/^\s\s*/, '').replace(/\s\s*$/, '');
+ if (str.length > 4 &&
+ str[0] != '#' &&
+ str[0] != ";" &&
+ str.substr(0, 2) != "//") {
+ var names = str.split(/ +/);
+ var new_url = prefix + str;
+ if (names.length == 1) {
+ new_url = prefix + str;
+ ++count;
+ getFileListImpl(new_url, function(index) {
+ return function(success, new_files) {
+ log("got files: " + new_files.length);
+ if (success) {
+ files[index] = new_files;
+ }
+ finish(success);
+ };
+ }(index++));
+ } else {
+ var s = "";
+ var p = "";
+ for (var jj = 0; jj < names.length; ++jj) {
+ s += p + prefix + names[jj];
+ p = " ";
+ }
+ files[index++] = s;
+ }
+ }
+ }
+ finish(true);
+
+ function finish(success) {
+ if (!success) {
+ fail = true;
+ }
+ --count;
+ log("count: " + count);
+ if (!count) {
+ callback(!fail, files);
+ }
+ }
+ }
+ }());
+
+ } else {
+ files.push(url);
+ callback(true, files);
+ }
+ };
+
+ getFileListImpl(url, function(success, files) {
+ // flatten
+ var flat = [];
+ flatten(files);
+ function flatten(files) {
+ for (var ii = 0; ii < files.length; ++ii) {
+ var value = files[ii];
+ if (typeof(value) == "string") {
+ flat.push(value);
+ } else {
+ flatten(value);
+ }
+ }
+ }
+ callback(success, flat);
+ });
+};
+
+/**
+ * Gets a file from a file/URL.
+ * @param {string} file the URL of the file to get.
+ * @return {string} The contents of the file.
+ */
+var readFile = function(file) {
+ var xhr = new XMLHttpRequest();
+ xhr.open("GET", file, false);
+ xhr.overrideMimeType("text/plain");
+ xhr.send();
+ return xhr.responseText.replace(/\r/g, "");
+};
+
+var readFileList = function(url) {
+ var files = [];
+ if (url.substr(url.length - 4) == '.txt') {
+ var lines = readFile(url).split('\n');
+ var prefix = '';
+ var lastSlash = url.lastIndexOf('/');
+ if (lastSlash >= 0) {
+ prefix = url.substr(0, lastSlash + 1);
+ }
+ for (var ii = 0; ii < lines.length; ++ii) {
+ var str = lines[ii].replace(/^\s\s*/, '').replace(/\s\s*$/, '');
+ if (str.length > 4 &&
+ str[0] != '#' &&
+ str[0] != ";" &&
+ str.substr(0, 2) != "//") {
+ var names = str.split(/ +/);
+ if (names.length == 1) {
+ var new_url = prefix + str;
+ files = files.concat(readFileList(new_url));
+ } else {
+ var s = "";
+ var p = "";
+ for (var jj = 0; jj < names.length; ++jj) {
+ s += p + prefix + names[jj];
+ p = " ";
+ }
+ files.push(s);
+ }
+ }
+ }
+ } else {
+ files.push(url);
+ }
+ return files;
+};
+
+/**
+ * Loads a shader.
+ * @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use.
+ * @param {string} shaderSource The shader source.
+ * @param {number} shaderType The type of shader.
+ * @param {function(string): void} opt_errorCallback callback for errors.
+ * @param {boolean} opt_logShaders Whether to log shader source.
+ * @param {string} opt_shaderLabel Label that identifies the shader source in
+ * the log.
+ * @param {string} opt_url URL from where the shader source was loaded from.
+ * If opt_logShaders is set, then a link to the source file will also be
+ * added.
+ * @param {boolean} Skip compilation status check. Default = false.
+ * @return {!WebGLShader} The created shader.
+ */
+var loadShader = function(
+ gl, shaderSource, shaderType, opt_errorCallback, opt_logShaders,
+ opt_shaderLabel, opt_url, opt_skipCompileStatus) {
+ var errFn = opt_errorCallback || error;
+ // Create the shader object
+ var shader = gl.createShader(shaderType);
+ if (shader == null) {
+ errFn("*** Error: unable to create shader '"+shaderSource+"'");
+ return null;
+ }
+
+ // Load the shader source
+ gl.shaderSource(shader, shaderSource);
+
+ // Compile the shader
+ gl.compileShader(shader);
+
+ if (opt_logShaders) {
+ var label = shaderType == gl.VERTEX_SHADER ? 'vertex shader' : 'fragment_shader';
+ if (opt_shaderLabel) {
+ label = opt_shaderLabel + ' ' + label;
+ }
+ addShaderSources(
+ gl, document.getElementById('console'), label, shader, shaderSource, opt_url);
+ }
+
+ // Check the compile status
+ if (!opt_skipCompileStatus) {
+ var compiled = gl.getShaderParameter(shader, gl.COMPILE_STATUS);
+ if (!compiled) {
+ // Something went wrong during compilation; get the error
+ lastError = gl.getShaderInfoLog(shader);
+ errFn("*** Error compiling " + glEnumToString(gl, shaderType) + " '" + shader + "':" + lastError);
+ gl.deleteShader(shader);
+ return null;
+ }
+ }
+
+ return shader;
+}
+
+/**
+ * Loads a shader from a URL.
+ * @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use.
+ * @param {file} file The URL of the shader source.
+ * @param {number} type The type of shader.
+ * @param {function(string): void} opt_errorCallback callback for errors.
+ * @param {boolean} opt_logShaders Whether to log shader source.
+ * @param {boolean} Skip compilation status check. Default = false.
+ * @return {!WebGLShader} The created shader.
+ */
+var loadShaderFromFile = function(
+ gl, file, type, opt_errorCallback, opt_logShaders, opt_skipCompileStatus) {
+ var shaderSource = readFile(file);
+ return loadShader(gl, shaderSource, type, opt_errorCallback,
+ opt_logShaders, undefined, file, opt_skipCompileStatus);
+};
+
+var loadShaderFromFileAsync = function(
+ gl, file, type, opt_errorCallback, opt_logShaders, opt_skipCompileStatus, callback) {
+ loadTextFileAsync(file, function(gl, type, opt_errorCallback, opt_logShaders, file, opt_skipCompileStatus){
+ return function(success, shaderSource) {
+ if (success) {
+ var shader = loadShader(gl, shaderSource, type, opt_errorCallback,
+ opt_logShaders, undefined, file, opt_skipCompileStatus);
+ callback(true, shader);
+ } else {
+ callback(false, null);
+ }
+ }
+ }(gl, type, opt_errorCallback, opt_logShaders, file, opt_skipCompileStatus));
+};
+
+/**
+ * Gets the content of script.
+ * @param {string} scriptId The id of the script tag.
+ * @return {string} The content of the script.
+ */
+var getScript = function(scriptId) {
+ var shaderScript = document.getElementById(scriptId);
+ if (!shaderScript) {
+ throw("*** Error: unknown script element " + scriptId);
+ }
+ return shaderScript.text;
+};
+
+/**
+ * Loads a shader from a script tag.
+ * @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use.
+ * @param {string} scriptId The id of the script tag.
+ * @param {number} opt_shaderType The type of shader. If not passed in it will
+ * be derived from the type of the script tag.
+ * @param {function(string): void} opt_errorCallback callback for errors.
+ * @param {boolean} opt_logShaders Whether to log shader source.
+ * @param {boolean} Skip compilation status check. Default = false.
+ * @return {!WebGLShader} The created shader.
+ */
+var loadShaderFromScript = function(
+ gl, scriptId, opt_shaderType, opt_errorCallback, opt_logShaders, opt_skipCompileStatus) {
+ var shaderSource = "";
+ var shaderScript = document.getElementById(scriptId);
+ if (!shaderScript) {
+ throw("*** Error: unknown script element " + scriptId);
+ }
+ shaderSource = shaderScript.text.trim();
+
+ if (!opt_shaderType) {
+ if (shaderScript.type == "x-shader/x-vertex") {
+ opt_shaderType = gl.VERTEX_SHADER;
+ } else if (shaderScript.type == "x-shader/x-fragment") {
+ opt_shaderType = gl.FRAGMENT_SHADER;
+ } else {
+ throw("*** Error: unknown shader type");
+ return null;
+ }
+ }
+
+ return loadShader(gl, shaderSource, opt_shaderType, opt_errorCallback,
+ opt_logShaders, undefined, undefined, opt_skipCompileStatus);
+};
+
+var loadStandardProgram = function(gl) {
+ var program = gl.createProgram();
+ gl.attachShader(program, loadStandardVertexShader(gl));
+ gl.attachShader(program, loadStandardFragmentShader(gl));
+ gl.bindAttribLocation(program, 0, "a_vertex");
+ gl.bindAttribLocation(program, 1, "a_normal");
+ linkProgram(gl, program);
+ return program;
+};
+
+var loadStandardProgramAsync = function(gl, callback) {
+ loadStandardVertexShaderAsync(gl, function(gl) {
+ return function(success, vs) {
+ if (success) {
+ loadStandardFragmentShaderAsync(gl, function(vs) {
+ return function(success, fs) {
+ if (success) {
+ var program = gl.createProgram();
+ gl.attachShader(program, vs);
+ gl.attachShader(program, fs);
+ gl.bindAttribLocation(program, 0, "a_vertex");
+ gl.bindAttribLocation(program, 1, "a_normal");
+ linkProgram(gl, program);
+ callback(true, program);
+ } else {
+ callback(false, null);
+ }
+ };
+ }(vs));
+ } else {
+ callback(false, null);
+ }
+ };
+ }(gl));
+};
+
+/**
+ * Loads shaders from files, creates a program, attaches the shaders and links.
+ * @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use.
+ * @param {string} vertexShaderPath The URL of the vertex shader.
+ * @param {string} fragmentShaderPath The URL of the fragment shader.
+ * @param {function(string): void} opt_errorCallback callback for errors.
+ * @return {!WebGLProgram} The created program.
+ */
+var loadProgramFromFile = function(
+ gl, vertexShaderPath, fragmentShaderPath, opt_errorCallback) {
+ var program = gl.createProgram();
+ var vs = loadShaderFromFile(
+ gl, vertexShaderPath, gl.VERTEX_SHADER, opt_errorCallback);
+ var fs = loadShaderFromFile(
+ gl, fragmentShaderPath, gl.FRAGMENT_SHADER, opt_errorCallback);
+ if (vs && fs) {
+ gl.attachShader(program, vs);
+ gl.attachShader(program, fs);
+ linkProgram(gl, program, opt_errorCallback);
+ }
+ if (vs) {
+ gl.deleteShader(vs);
+ }
+ if (fs) {
+ gl.deleteShader(fs);
+ }
+ return program;
+};
+
+/**
+ * Loads shaders from script tags, creates a program, attaches the shaders and
+ * links.
+ * @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use.
+ * @param {string} vertexScriptId The id of the script tag that contains the
+ * vertex shader.
+ * @param {string} fragmentScriptId The id of the script tag that contains the
+ * fragment shader.
+ * @param {function(string): void} opt_errorCallback callback for errors.
+ * @return {!WebGLProgram} The created program.
+ */
+var loadProgramFromScript = function loadProgramFromScript(
+ gl, vertexScriptId, fragmentScriptId, opt_errorCallback) {
+ var program = gl.createProgram();
+ gl.attachShader(
+ program,
+ loadShaderFromScript(
+ gl, vertexScriptId, gl.VERTEX_SHADER, opt_errorCallback));
+ gl.attachShader(
+ program,
+ loadShaderFromScript(
+ gl, fragmentScriptId, gl.FRAGMENT_SHADER, opt_errorCallback));
+ linkProgram(gl, program, opt_errorCallback);
+ return program;
+};
+
+/**
+ * Loads shaders from source, creates a program, attaches the shaders and
+ * links.
+ * @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use.
+ * @param {!WebGLShader} vertexShader The vertex shader.
+ * @param {!WebGLShader} fragmentShader The fragment shader.
+ * @param {function(string): void} opt_errorCallback callback for errors.
+ * @return {!WebGLProgram} The created program.
+ */
+var createProgram = function(gl, vertexShader, fragmentShader, opt_errorCallback) {
+ var program = gl.createProgram();
+ gl.attachShader(program, vertexShader);
+ gl.attachShader(program, fragmentShader);
+ linkProgram(gl, program, opt_errorCallback);
+ return program;
+};
+
+/**
+ * Loads shaders from source, creates a program, attaches the shaders and
+ * links.
+ * @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use.
+ * @param {string} vertexShader The vertex shader source.
+ * @param {string} fragmentShader The fragment shader source.
+ * @param {function(string): void} opt_errorCallback callback for errors.
+ * @param {boolean} opt_logShaders Whether to log shader source.
+ * @return {!WebGLProgram} The created program.
+ */
+var loadProgram = function(
+ gl, vertexShader, fragmentShader, opt_errorCallback, opt_logShaders) {
+ var program;
+ var vs = loadShader(
+ gl, vertexShader, gl.VERTEX_SHADER, opt_errorCallback, opt_logShaders);
+ var fs = loadShader(
+ gl, fragmentShader, gl.FRAGMENT_SHADER, opt_errorCallback, opt_logShaders);
+ if (vs && fs) {
+ program = createProgram(gl, vs, fs, opt_errorCallback)
+ }
+ if (vs) {
+ gl.deleteShader(vs);
+ }
+ if (fs) {
+ gl.deleteShader(fs);
+ }
+ return program;
+};
+
+/**
+ * Loads shaders from source, creates a program, attaches the shaders and
+ * links but expects error.
+ *
+ * GLSL 1.0.17 10.27 effectively says that compileShader can
+ * always succeed as long as linkProgram fails so we can't
+ * rely on compileShader failing. This function expects
+ * one of the shader to fail OR linking to fail.
+ *
+ * @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use.
+ * @param {string} vertexShaderScriptId The vertex shader.
+ * @param {string} fragmentShaderScriptId The fragment shader.
+ * @return {WebGLProgram} The created program.
+ */
+var loadProgramFromScriptExpectError = function(
+ gl, vertexShaderScriptId, fragmentShaderScriptId) {
+ var vertexShader = loadShaderFromScript(gl, vertexShaderScriptId);
+ if (!vertexShader) {
+ return null;
+ }
+ var fragmentShader = loadShaderFromScript(gl, fragmentShaderScriptId);
+ if (!fragmentShader) {
+ return null;
+ }
+ var linkSuccess = true;
+ var program = gl.createProgram();
+ gl.attachShader(program, vertexShader);
+ gl.attachShader(program, fragmentShader);
+ linkSuccess = true;
+ linkProgram(gl, program, function() {
+ linkSuccess = false;
+ });
+ return linkSuccess ? program : null;
+};
+
+
+var getActiveMap = function(gl, program, typeInfo) {
+ var numVariables = gl.getProgramParameter(program, gl[typeInfo.param]);
+ var variables = {};
+ for (var ii = 0; ii < numVariables; ++ii) {
+ var info = gl[typeInfo.activeFn](program, ii);
+ variables[info.name] = {
+ name: info.name,
+ size: info.size,
+ type: info.type,
+ location: gl[typeInfo.locFn](program, info.name)
+ };
+ }
+ return variables;
+};
+
+/**
+ * Returns a map of attrib names to info about those
+ * attribs.
+ *
+ * eg:
+ * { "attrib1Name":
+ * {
+ * name: "attrib1Name",
+ * size: 1,
+ * type: gl.FLOAT_MAT2,
+ * location: 0
+ * },
+ * "attrib2Name[0]":
+ * {
+ * name: "attrib2Name[0]",
+ * size: 4,
+ * type: gl.FLOAT,
+ * location: 1
+ * },
+ * }
+ *
+ * @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use.
+ * @param {WebGLProgram} The program to query for attribs.
+ * @return the map.
+ */
+var getAttribMap = function(gl, program) {
+ return getActiveMap(gl, program, {
+ param: "ACTIVE_ATTRIBUTES",
+ activeFn: "getActiveAttrib",
+ locFn: "getAttribLocation"
+ });
+};
+
+/**
+ * Returns a map of uniform names to info about those uniforms.
+ *
+ * eg:
+ * { "uniform1Name":
+ * {
+ * name: "uniform1Name",
+ * size: 1,
+ * type: gl.FLOAT_MAT2,
+ * location: WebGLUniformLocation
+ * },
+ * "uniform2Name[0]":
+ * {
+ * name: "uniform2Name[0]",
+ * size: 4,
+ * type: gl.FLOAT,
+ * location: WebGLUniformLocation
+ * },
+ * }
+ *
+ * @param {!WebGLRenderingContext} gl The WebGLRenderingContext to use.
+ * @param {WebGLProgram} The program to query for uniforms.
+ * @return the map.
+ */
+var getUniformMap = function(gl, program) {
+ return getActiveMap(gl, program, {
+ param: "ACTIVE_UNIFORMS",
+ activeFn: "getActiveUniform",
+ locFn: "getUniformLocation"
+ });
+};
+
+var basePath;
+var getResourcePath = function() {
+ if (!basePath) {
+ var expectedBase = "js/webgl-test-utils.js";
+ var scripts = document.getElementsByTagName('script');
+ for (var script, i = 0; script = scripts[i]; i++) {
+ var src = script.src;
+ var l = src.length;
+ if (src.substr(l - expectedBase.length) == expectedBase) {
+ basePath = src.substr(0, l - expectedBase.length);
+ }
+ }
+ }
+ return basePath + "resources/";
+};
+
+var loadStandardVertexShader = function(gl) {
+ return loadShaderFromFile(
+ gl, getResourcePath() + "vertexShader.vert", gl.VERTEX_SHADER);
+};
+var loadStandardVertexShaderAsync = function(gl, callback) {
+ loadShaderFromFileAsync(gl, getResourcePath() + "vertexShader.vert", gl.VERTEX_SHADER, undefined, undefined, undefined, callback);
+};
+
+var loadStandardFragmentShader = function(gl) {
+ return loadShaderFromFile(
+ gl, getResourcePath() + "fragmentShader.frag", gl.FRAGMENT_SHADER);
+};
+var loadStandardFragmentShaderAsync = function(gl, callback) {
+ loadShaderFromFileAsync(gl, getResourcePath() + "fragmentShader.frag", gl.FRAGMENT_SHADER, undefined, undefined, undefined, callback);
+};
+
+var loadUniformBlockProgram = function(gl) {
+ var program = gl.createProgram();
+ gl.attachShader(program, loadUniformBlockVertexShader(gl));
+ gl.attachShader(program, loadUniformBlockFragmentShader(gl));
+ gl.bindAttribLocation(program, 0, "a_vertex");
+ gl.bindAttribLocation(program, 1, "a_normal");
+ linkProgram(gl, program);
+ return program;
+};
+
+var loadUniformBlockVertexShader = function(gl) {
+ return loadShaderFromFile(
+ gl, getResourcePath() + "uniformBlockShader.vert", gl.VERTEX_SHADER);
+};
+
+var loadUniformBlockFragmentShader = function(gl) {
+ return loadShaderFromFile(
+ gl, getResourcePath() + "uniformBlockShader.frag", gl.FRAGMENT_SHADER);
+};
+
+/**
+ * Loads an image asynchronously.
+ * @param {string} url URL of image to load.
+ * @param {!function(!Element): void} callback Function to call
+ * with loaded image.
+ */
+var loadImageAsync = function(url, callback) {
+ var img = document.createElement('img');
+ img.onload = function() {
+ callback(img);
+ };
+ img.src = url;
+};
+
+/**
+ * Loads an array of images.
+ * @param {!Array.<string>} urls URLs of images to load.
+ * @param {!function(!{string, img}): void} callback Callback
+ * that gets passed map of urls to img tags.
+ */
+var loadImagesAsync = function(urls, callback) {
+ var count = 1;
+ var images = { };
+ function countDown() {
+ --count;
+ if (count == 0) {
+ log("loadImagesAsync: all images loaded");
+ callback(images);
+ }
+ }
+ function imageLoaded(url) {
+ return function(img) {
+ images[url] = img;
+ log("loadImagesAsync: loaded " + url);
+ countDown();
+ }
+ }
+ for (var ii = 0; ii < urls.length; ++ii) {
+ ++count;
+ loadImageAsync(urls[ii], imageLoaded(urls[ii]));
+ }
+ countDown();
+};
+
+/**
+ * Returns a map of key=value values from url.
+ * @return {!Object.<string, number>} map of keys to values.
+ */
+var getUrlArguments = function() {
+ var args = {};
+ try {
+ var s = window.location.href;
+ var q = s.indexOf("?");
+ var e = s.indexOf("#");
+ if (e < 0) {
+ e = s.length;
+ }
+ var query = s.substring(q + 1, e);
+ var pairs = query.split("&");
+ for (var ii = 0; ii < pairs.length; ++ii) {
+ var keyValue = pairs[ii].split("=");
+ var key = keyValue[0];
+ var value = decodeURIComponent(keyValue[1]);
+ args[key] = value;
+ }
+ } catch (e) {
+ throw "could not parse url";
+ }
+ return args;
+};
+
+/**
+ * Makes an image from a src.
+ * @param {string} src Image source URL.
+ * @param {function()} onload Callback to call when the image has finised loading.
+ * @param {function()} onerror Callback to call when an error occurs.
+ * @return {!Image} The created image.
+ */
+var makeImage = function(src, onload, onerror) {
+ var img = document.createElement('img');
+ if (onload) {
+ img.onload = onload;
+ }
+ if (onerror) {
+ img.onerror = onerror;
+ } else {
+ img.onerror = function() {
+ log("WARNING: creating image failed; src: " + this.src);
+ };
+ }
+ if (src) {
+ img.src = src;
+ }
+ return img;
+}
+
+/**
+ * Makes an image element from a canvas.
+ * @param {!HTMLCanvas} canvas Canvas to make image from.
+ * @param {function()} onload Callback to call when the image has finised loading.
+ * @param {string} imageFormat Image format to be passed to toDataUrl().
+ * @return {!Image} The created image.
+ */
+var makeImageFromCanvas = function(canvas, onload, imageFormat) {
+ return makeImage(canvas.toDataURL(imageFormat), onload);
+};
+
+/**
+ * Makes a video element from a src.
+ * @param {string} src Video source URL.
+ * @param {function()} onerror Callback to call when an error occurs.
+ * @return {!Video} The created video.
+ */
+var makeVideo = function(src, onerror) {
+ var vid = document.createElement('video');
+ vid.muted = true;
+ if (onerror) {
+ vid.onerror = onerror;
+ } else {
+ vid.onerror = function() {
+ log("WARNING: creating video failed; src: " + this.src);
+ };
+ }
+ if (src) {
+ vid.src = src;
+ }
+ return vid;
+}
+
+/**
+ * Inserts an image with a caption into 'element'.
+ * @param {!HTMLElement} element Element to append image to.
+ * @param {string} caption caption to associate with image.
+ * @param {!Image} img image to insert.
+ */
+var insertImage = function(element, caption, img) {
+ var div = document.createElement("div");
+ var label = document.createElement("div");
+ label.appendChild(document.createTextNode(caption));
+ div.appendChild(label);
+ div.appendChild(img);
+ element.appendChild(div);
+};
+
+/**
+ * Inserts a 'label' that when clicked expands to the pre formatted text
+ * supplied by 'source'.
+ * @param {!HTMLElement} element element to append label to.
+ * @param {string} label label for anchor.
+ * @param {string} source preformatted text to expand to.
+ * @param {string} opt_url URL of source. If provided a link to the source file
+ * will also be added.
+ */
+var addShaderSource = function(element, label, source, opt_url) {
+ var div = document.createElement("div");
+ var s = document.createElement("pre");
+ s.className = "shader-source";
+ s.style.display = "none";
+ var ol = document.createElement("ol");
+ //s.appendChild(document.createTextNode(source));
+ var lines = source.split("\n");
+ for (var ii = 0; ii < lines.length; ++ii) {
+ var line = lines[ii];
+ var li = document.createElement("li");
+ li.appendChild(document.createTextNode(line));
+ ol.appendChild(li);
+ }
+ s.appendChild(ol);
+ var l = document.createElement("a");
+ l.href = "show-shader-source";
+ l.appendChild(document.createTextNode(label));
+ l.addEventListener('click', function(event) {
+ if (event.preventDefault) {
+ event.preventDefault();
+ }
+ s.style.display = (s.style.display == 'none') ? 'block' : 'none';
+ return false;
+ }, false);
+ div.appendChild(l);
+ if (opt_url) {
+ var u = document.createElement("a");
+ u.href = opt_url;
+ div.appendChild(document.createTextNode(" "));
+ u.appendChild(document.createTextNode("(" + opt_url + ")"));
+ div.appendChild(u);
+ }
+ div.appendChild(s);
+ element.appendChild(div);
+};
+
+/**
+ * Inserts labels that when clicked expand to show the original source of the
+ * shader and also translated source of the shader, if that is available.
+ * @param {WebGLRenderingContext} gl The WebGLRenderingContext to use.
+ * @param {!HTMLElement} element element to append label to.
+ * @param {string} label label for anchor.
+ * @param {WebGLShader} shader Shader to show the sources for.
+ * @param {string} shaderSource Original shader source.
+ * @param {string} opt_url URL of source. If provided a link to the source file
+ * will also be added.
+ */
+var addShaderSources = function(
+ gl, element, label, shader, shaderSource, opt_url) {
+ addShaderSource(element, label, shaderSource, opt_url);
+
+ var debugShaders = gl.getExtension('WEBGL_debug_shaders');
+ if (debugShaders && shader) {
+ var translatedSource = debugShaders.getTranslatedShaderSource(shader);
+ if (translatedSource != '') {
+ addShaderSource(element, label + ' translated for driver', translatedSource);
+ }
+ }
+};
+
+/**
+ * Sends shader information to the server to be dumped into text files
+ * when tests are run from within the test-runner harness.
+ * @param {WebGLRenderingContext} gl The WebGLRenderingContext to use.
+ * @param {string} url URL of current.
+ * @param {string} passMsg Test description.
+ * @param {object} vInfo Object containing vertex shader information.
+ * @param {object} fInfo Object containing fragment shader information.
+ */
+var dumpShadersInfo = function(gl, url, passMsg, vInfo, fInfo) {
+ var shaderInfo = {};
+ shaderInfo.url = url;
+ shaderInfo.testDescription = passMsg;
+ shaderInfo.vLabel = vInfo.label;
+ shaderInfo.vShouldCompile = vInfo.shaderSuccess;
+ shaderInfo.vSource = vInfo.source;
+ shaderInfo.fLabel = fInfo.label;
+ shaderInfo.fShouldCompile = fInfo.shaderSuccess;
+ shaderInfo.fSource = fInfo.source;
+ shaderInfo.vTranslatedSource = null;
+ shaderInfo.fTranslatedSource = null;
+ var debugShaders = gl.getExtension('WEBGL_debug_shaders');
+ if (debugShaders) {
+ if (vInfo.shader)
+ shaderInfo.vTranslatedSource = debugShaders.getTranslatedShaderSource(vInfo.shader);
+ if (fInfo.shader)
+ shaderInfo.fTranslatedSource = debugShaders.getTranslatedShaderSource(fInfo.shader);
+ }
+
+ var dumpShaderInfoRequest = new XMLHttpRequest();
+ dumpShaderInfoRequest.open('POST', "/dumpShaderInfo", true);
+ dumpShaderInfoRequest.setRequestHeader("Content-Type", "text/plain");
+ dumpShaderInfoRequest.send(JSON.stringify(shaderInfo));
+};
+
+// Add your prefix here.
+var browserPrefixes = [
+ "",
+ "MOZ_",
+ "OP_",
+ "WEBKIT_"
+];
+
+/**
+ * Given an extension name like WEBGL_compressed_texture_s3tc
+ * returns the name of the supported version extension, like
+ * WEBKIT_WEBGL_compressed_teture_s3tc
+ * @param {string} name Name of extension to look for.
+ * @return {string} name of extension found or undefined if not
+ * found.
+ */
+var getSupportedExtensionWithKnownPrefixes = function(gl, name) {
+ var supported = gl.getSupportedExtensions();
+ for (var ii = 0; ii < browserPrefixes.length; ++ii) {
+ var prefixedName = browserPrefixes[ii] + name;
+ if (supported.indexOf(prefixedName) >= 0) {
+ return prefixedName;
+ }
+ }
+};
+
+/**
+ * @param {WebGLRenderingContext} gl The WebGLRenderingContext to use.
+ * @param {string} name Name of extension to look for.
+ * @param {boolean} extensionEnabled True if the extension was enabled successfully via gl.getExtension().
+ */
+var runExtensionSupportedTest = function(gl, name, extensionEnabled) {
+ var prefixedName = getSupportedExtensionWithKnownPrefixes(gl, name);
+ if (prefixedName !== undefined) {
+ if (extensionEnabled) {
+ testPassed(name + " listed as supported and getExtension succeeded");
+ } else {
+ testFailed(name + " listed as supported but getExtension failed");
+ }
+ } else {
+ if (extensionEnabled) {
+ testFailed(name + " not listed as supported but getExtension succeeded");
+ } else {
+ testPassed(name + " not listed as supported and getExtension failed -- this is legal");
+ }
+ }
+}
+
+/**
+ * Given an extension name like WEBGL_compressed_texture_s3tc
+ * returns the supported version extension, like
+ * WEBKIT_WEBGL_compressed_teture_s3tc
+ * @param {string} name Name of extension to look for.
+ * @return {WebGLExtension} The extension or undefined if not
+ * found.
+ */
+var getExtensionWithKnownPrefixes = function(gl, name) {
+ for (var ii = 0; ii < browserPrefixes.length; ++ii) {
+ var prefixedName = browserPrefixes[ii] + name;
+ var ext = gl.getExtension(prefixedName);
+ if (ext) {
+ return ext;
+ }
+ }
+};
+
+/**
+ * Returns possible prefixed versions of an extension's name.
+ * @param {string} name Name of extension. May already include a prefix.
+ * @return {Array.<string>} Variations of the extension name with known
+ * browser prefixes.
+ */
+var getExtensionPrefixedNames = function(name) {
+ var unprefix = function(name) {
+ for (var ii = 0; ii < browserPrefixes.length; ++ii) {
+ if (browserPrefixes[ii].length > 0 &&
+ name.substring(0, browserPrefixes[ii].length).toLowerCase() ===
+ browserPrefixes[ii].toLowerCase()) {
+ return name.substring(browserPrefixes[ii].length);
+ }
+ }
+ return name;
+ }
+
+ var unprefixed = unprefix(name);
+
+ var variations = [];
+ for (var ii = 0; ii < browserPrefixes.length; ++ii) {
+ variations.push(browserPrefixes[ii] + unprefixed);
+ }
+
+ return variations;
+};
+
+var replaceRE = /\$\((\w+)\)/g;
+
+/**
+ * Replaces strings with property values.
+ * Given a string like "hello $(first) $(last)" and an object
+ * like {first:"John", last:"Smith"} will return
+ * "hello John Smith".
+ * @param {string} str String to do replacements in.
+ * @param {...} 1 or more objects containing properties.
+ */
+var replaceParams = function(str) {
+ var args = arguments;
+ return str.replace(replaceRE, function(str, p1, offset, s) {
+ for (var ii = 1; ii < args.length; ++ii) {
+ if (args[ii][p1] !== undefined) {
+ return args[ii][p1];
+ }
+ }
+ throw "unknown string param '" + p1 + "'";
+ });
+};
+
+var upperCaseFirstLetter = function(str) {
+ return str.substring(0, 1).toUpperCase() + str.substring(1);
+};
+
+/**
+ * Gets a prefixed property. For example,
+ *
+ * var fn = getPrefixedProperty(
+ * window,
+ * "requestAnimationFrame");
+ *
+ * Will return either:
+ * "window.requestAnimationFrame",
+ * "window.oRequestAnimationFrame",
+ * "window.msRequestAnimationFrame",
+ * "window.mozRequestAnimationFrame",
+ * "window.webKitRequestAnimationFrame",
+ * undefined
+ *
+ * the non-prefixed function is tried first.
+ */
+var propertyPrefixes = ["", "moz", "ms", "o", "webkit"];
+var getPrefixedProperty = function(obj, propertyName) {
+ for (var ii = 0; ii < propertyPrefixes.length; ++ii) {
+ var prefix = propertyPrefixes[ii];
+ var name = prefix + propertyName;
+ log(name);
+ var property = obj[name];
+ if (property) {
+ return property;
+ }
+ if (ii == 0) {
+ propertyName = upperCaseFirstLetter(propertyName);
+ }
+ }
+ return undefined;
+};
+
+var _requestAnimFrame;
+
+/**
+ * Provides requestAnimationFrame in a cross browser way.
+ */
+var requestAnimFrame = function(callback) {
+ if (!_requestAnimFrame) {
+ _requestAnimFrame = getPrefixedProperty(window, "requestAnimationFrame") ||
+ function(callback, element) {
+ return window.setTimeout(callback, 1000 / 70);
+ };
+ }
+ _requestAnimFrame.call(window, callback);
+};
+
+var _cancelAnimFrame;
+
+/**
+ * Provides cancelAnimationFrame in a cross browser way.
+ */
+var cancelAnimFrame = function(request) {
+ if (!_cancelAnimFrame) {
+ _cancelAnimFrame = getPrefixedProperty(window, "cancelAnimationFrame") ||
+ window.clearTimeout;
+ }
+ _cancelAnimFrame.call(window, request);
+};
+
+/**
+ * Provides requestFullScreen in a cross browser way.
+ */
+var requestFullScreen = function(element) {
+ var fn = getPrefixedProperty(element, "requestFullScreen");
+ if (fn) {
+ fn.call(element);
+ }
+};
+
+/**
+ * Provides cancelFullScreen in a cross browser way.
+ */
+var cancelFullScreen = function() {
+ var fn = getPrefixedProperty(document, "cancelFullScreen");
+ if (fn) {
+ fn.call(document);
+ }
+};
+
+var fullScreenStateName;
+(function() {
+ var fullScreenStateNames = [
+ "isFullScreen",
+ "fullScreen"
+ ];
+ for (var ii = 0; ii < fullScreenStateNames.length; ++ii) {
+ var propertyName = fullScreenStateNames[ii];
+ for (var jj = 0; jj < propertyPrefixes.length; ++jj) {
+ var prefix = propertyPrefixes[jj];
+ if (prefix.length) {
+ propertyName = upperCaseFirstLetter(propertyName);
+ fullScreenStateName = prefix + propertyName;
+ if (document[fullScreenStateName] !== undefined) {
+ return;
+ }
+ }
+ }
+ fullScreenStateName = undefined;
+ }
+}());
+
+/**
+ * @return {boolean} True if fullscreen mode is active.
+ */
+var getFullScreenState = function() {
+ log("fullscreenstatename:" + fullScreenStateName);
+ log(document[fullScreenStateName]);
+ return document[fullScreenStateName];
+};
+
+/**
+ * @param {!HTMLElement} element The element to go fullscreen.
+ * @param {!function(boolean)} callback A function that will be called
+ * when entering/exiting fullscreen. It is passed true if
+ * entering fullscreen, false if exiting.
+ */
+var onFullScreenChange = function(element, callback) {
+ propertyPrefixes.forEach(function(prefix) {
+ var eventName = prefix + "fullscreenchange";
+ log("addevent: " + eventName);
+ document.addEventListener(eventName, function(event) {
+ log("event: " + eventName);
+ callback(getFullScreenState());
+ });
+ });
+};
+
+/**
+ * @param {!string} buttonId The id of the button that will toggle fullscreen
+ * mode.
+ * @param {!string} fullscreenId The id of the element to go fullscreen.
+ * @param {!function(boolean)} callback A function that will be called
+ * when entering/exiting fullscreen. It is passed true if
+ * entering fullscreen, false if exiting.
+ * @return {boolean} True if fullscreen mode is supported.
+ */
+var setupFullscreen = function(buttonId, fullscreenId, callback) {
+ if (!fullScreenStateName) {
+ return false;
+ }
+
+ var fullscreenElement = document.getElementById(fullscreenId);
+ onFullScreenChange(fullscreenElement, callback);
+
+ var toggleFullScreen = function(event) {
+ if (getFullScreenState()) {
+ cancelFullScreen(fullscreenElement);
+ } else {
+ requestFullScreen(fullscreenElement);
+ }
+ event.preventDefault();
+ return false;
+ };
+
+ var buttonElement = document.getElementById(buttonId);
+ buttonElement.addEventListener('click', toggleFullScreen);
+
+ return true;
+};
+
+/**
+ * Waits for the browser to composite the web page.
+ * @param {function()} callback A function to call after compositing has taken
+ * place.
+ */
+var waitForComposite = function(callback) {
+ var frames = 5;
+ var countDown = function() {
+ if (frames == 0) {
+ // TODO(kbr): unify with js-test-pre.js and enable these with
+ // verbose logging.
+ // log("waitForComposite: callback");
+ callback();
+ } else {
+ // log("waitForComposite: countdown(" + frames + ")");
+ --frames;
+ requestAnimFrame.call(window, countDown);
+ }
+ };
+ countDown();
+};
+
+var setZeroTimeout = (function() {
+ // See https://dbaron.org/log/20100309-faster-timeouts
+
+ var timeouts = [];
+ var messageName = "zero-timeout-message";
+
+ // Like setTimeout, but only takes a function argument. There's
+ // no time argument (always zero) and no arguments (you have to
+ // use a closure).
+ function setZeroTimeout(fn) {
+ timeouts.push(fn);
+ window.postMessage(messageName, "*");
+ }
+
+ function handleMessage(event) {
+ if (event.source == window && event.data == messageName) {
+ event.stopPropagation();
+ if (timeouts.length > 0) {
+ var fn = timeouts.shift();
+ fn();
+ }
+ }
+ }
+
+ window.addEventListener("message", handleMessage, true);
+
+ return setZeroTimeout;
+})();
+
+function dispatchPromise(fn) {
+ return new Promise((fn_resolve, fn_reject) => {
+ setZeroTimeout(() => {
+ let val;
+ if (fn) {
+ val = fn();
+ }
+ fn_resolve(val);
+ });
+ });
+}
+
+/**
+ * Runs an array of functions, yielding to the browser between each step.
+ * If you want to know when all the steps are finished add a last step.
+ * @param {!Array.<function(): void>} steps Array of functions.
+ */
+var runSteps = function(steps) {
+ if (!steps.length) {
+ return;
+ }
+
+ // copy steps so they can't be modifed.
+ var stepsToRun = steps.slice();
+ var currentStep = 0;
+ var runNextStep = function() {
+ stepsToRun[currentStep++]();
+ if (currentStep < stepsToRun.length) {
+ setTimeout(runNextStep, 1);
+ }
+ };
+ runNextStep();
+};
+
+/**
+ * Starts playing a video and waits for it to be consumable.
+ * @param {!HTMLVideoElement} video An HTML5 Video element.
+ * @param {!function(!HTMLVideoElement): void} callback Function to call when
+ * video is ready.
+ */
+async function startPlayingAndWaitForVideo(video, callback) {
+ if (video.error) {
+ testFailed('Video failed to load: ' + video.error);
+ return;
+ }
+
+ video.loop = true;
+ video.muted = true;
+ // See whether setting the preload flag de-flakes video-related tests.
+ video.preload = 'auto';
+
+ try {
+ await video.play();
+ } catch (e) {
+ testFailed('video.play failed: ' + e);
+ return;
+ }
+
+ if (video.requestVideoFrameCallback) {
+ await new Promise(go => video.requestVideoFrameCallback(go));
+ }
+
+ callback(video);
+}
+
+var getHost = function(url) {
+ url = url.replace("\\", "/");
+ var pos = url.indexOf("://");
+ if (pos >= 0) {
+ url = url.substr(pos + 3);
+ }
+ var parts = url.split('/');
+ return parts[0];
+}
+
+// This function returns the last 2 words of the domain of a URL
+// This is probably not the correct check but it will do for now.
+var getBaseDomain = function(host) {
+ var parts = host.split(":");
+ var hostname = parts[0];
+ var port = parts[1] || "80";
+ parts = hostname.split(".");
+ if(parts.length < 2)
+ return hostname + ":" + port;
+ var tld = parts[parts.length-1];
+ var domain = parts[parts.length-2];
+ return domain + "." + tld + ":" + port;
+}
+
+var runningOnLocalhost = function() {
+ let hostname = window.location.hostname;
+ return hostname == "localhost" ||
+ hostname == "127.0.0.1" ||
+ hostname == "::1";
+}
+
+var getLocalCrossOrigin = function() {
+ var domain;
+ if (window.location.host.indexOf("localhost") != -1) {
+ // TODO(kbr): figure out whether to use an IPv6 loopback address.
+ domain = "127.0.0.1";
+ } else {
+ domain = "localhost";
+ }
+
+ var port = window.location.port || "80";
+ return window.location.protocol + "//" + domain + ":" + port
+}
+
+var getRelativePath = function(path) {
+ var relparts = window.location.pathname.split("/");
+ relparts.pop(); // Pop off filename
+ var pathparts = path.split("/");
+
+ var i;
+ for (i = 0; i < pathparts.length; ++i) {
+ switch (pathparts[i]) {
+ case "": break;
+ case ".": break;
+ case "..":
+ relparts.pop();
+ break;
+ default:
+ relparts.push(pathparts[i]);
+ break;
+ }
+ }
+
+ return relparts.join("/");
+}
+
+async function loadCrossOriginImage(img, webUrl, localUrl) {
+ if (runningOnLocalhost()) {
+ img.src = getLocalCrossOrigin() + getRelativePath(localUrl);
+ console.log('[loadCrossOriginImage]', ' trying', img.src);
+ await img.decode();
+ return;
+ }
+
+ try {
+ img.src = getUrlOptions().imgUrl || webUrl;
+ console.log('[loadCrossOriginImage]', 'trying', img.src);
+ await img.decode();
+ return;
+ } catch {}
+
+ throw 'createCrossOriginImage failed';
+}
+
+/**
+ * Convert sRGB color to linear color.
+ * @param {!Array.<number>} color The color to be converted.
+ * The array has 4 elements, for example [R, G, B, A].
+ * where each element is in the range 0 to 255.
+ * @return {!Array.<number>} color The color to be converted.
+ * The array has 4 elements, for example [R, G, B, A].
+ * where each element is in the range 0 to 255.
+ */
+var sRGBToLinear = function(color) {
+ return [sRGBChannelToLinear(color[0]),
+ sRGBChannelToLinear(color[1]),
+ sRGBChannelToLinear(color[2]),
+ color[3]]
+}
+
+/**
+ * Convert linear color to sRGB color.
+ * @param {!Array.<number>} color The color to be converted.
+ * The array has 4 elements, for example [R, G, B, A].
+ * where each element is in the range 0 to 255.
+ * @return {!Array.<number>} color The color to be converted.
+ * The array has 4 elements, for example [R, G, B, A].
+ * where each element is in the range 0 to 255.
+ */
+var linearToSRGB = function(color) {
+ return [linearChannelToSRGB(color[0]),
+ linearChannelToSRGB(color[1]),
+ linearChannelToSRGB(color[2]),
+ color[3]]
+}
+
+function sRGBChannelToLinear(value) {
+ value = value / 255;
+ if (value <= 0.04045)
+ value = value / 12.92;
+ else
+ value = Math.pow((value + 0.055) / 1.055, 2.4);
+ return Math.trunc(value * 255 + 0.5);
+}
+
+function linearChannelToSRGB(value) {
+ value = value / 255;
+ if (value <= 0.0) {
+ value = 0.0;
+ } else if (value < 0.0031308) {
+ value = value * 12.92;
+ } else if (value < 1) {
+ value = Math.pow(value, 0.41666) * 1.055 - 0.055;
+ } else {
+ value = 1.0;
+ }
+ return Math.trunc(value * 255 + 0.5);
+}
+
+/**
+ * Return the named color in the specified color space.
+ * @param {string} colorName The name of the color to convert.
+ * Supported color names are:
+ * 'Red', which is the CSS color color('srgb' 1 0 0 1)
+ * 'Green', which is the CSS color color('srgb' 0 1 0 1)
+ * @param {string} colorSpace The color space to convert to. Supported
+ color spaces are:
+ * null, which is treated as sRGB
+ * 'srgb'
+ * 'display-p3'.
+ * Documentation on the formulas for color conversion between
+ * spaces can be found at
+ https://www.w3.org/TR/css-color-4/#predefined-to-predefined
+ * @return {!Array.<number>} color The color in the specified color
+ * space as an 8-bit RGBA array with unpremultiplied alpha.
+ */
+var namedColorInColorSpace = function(colorName, colorSpace) {
+ var result;
+ switch (colorSpace) {
+ case undefined:
+ case 'srgb':
+ switch(colorName) {
+ case 'Red':
+ return [255, 0, 0, 255];
+ case 'Green':
+ return [0, 255, 0, 255];
+ break;
+ default:
+ throw 'unexpected color name: ' + colorName;
+ };
+ break;
+ case 'display-p3':
+ switch(colorName) {
+ case 'Red':
+ return [234, 51, 35, 255];
+ break;
+ case 'Green':
+ return [117, 251, 76, 255];
+ break;
+ default:
+ throw 'unexpected color name: ' + colorName;
+ }
+ break;
+ default:
+ throw 'unexpected color space: ' + colorSpace;
+ }
+}
+
+/**
+ * Return the named color as it would be sampled with the specified
+ * internal format
+ * @param {!Array.<number>} color The color as an 8-bit RGBA array.
+ * @param {string} internalformat The internal format.
+ * @return {!Array.<number>} color The color, as it would be sampled by
+ * the specified internal format, as an 8-bit RGBA array.
+ */
+var colorAsSampledWithInternalFormat = function(color, internalFormat) {
+ switch (internalFormat) {
+ case 'ALPHA':
+ return [0, 0, 0, color[3]];
+ case 'LUMINANCE':
+ return [color[0], color[0], color[0], 255];
+ case 'LUMINANCE_ALPHA':
+ return [color[0], color[0], color[0], color[3]];
+ case 'SRGB8':
+ case 'SRGB8_ALPHA8':
+ return [sRGBChannelToLinear(color[0]),
+ sRGBChannelToLinear(color[1]),
+ sRGBChannelToLinear(color[2]),
+ color[3]];
+ case 'R16F':
+ case 'R32F':
+ case 'R8':
+ case 'R8UI':
+ case 'RED':
+ case 'RED_INTEGER':
+ return [color[0], 0, 0, 0];
+ case 'RG':
+ case 'RG16F':
+ case 'RG32F':
+ case 'RG8':
+ case 'RG8UI':
+ case 'RG_INTEGER':
+ return [color[0], color[1], 0, 0];
+ break;
+ default:
+ break;
+ }
+ return color;
+}
+
+function comparePixels(cmp, ref, tolerance, diff) {
+ if (cmp.length != ref.length) {
+ testFailed("invalid pixel size.");
+ }
+
+ var count = 0;
+ for (var i = 0; i < cmp.length; i++) {
+ if (diff) {
+ diff[i * 4] = 0;
+ diff[i * 4 + 1] = 255;
+ diff[i * 4 + 2] = 0;
+ diff[i * 4 + 3] = 255;
+ }
+ if (Math.abs(cmp[i * 4] - ref[i * 4]) > tolerance ||
+ Math.abs(cmp[i * 4 + 1] - ref[i * 4 + 1]) > tolerance ||
+ Math.abs(cmp[i * 4 + 2] - ref[i * 4 + 2]) > tolerance ||
+ Math.abs(cmp[i * 4 + 3] - ref[i * 4 + 3]) > tolerance) {
+ if (count < 10) {
+ testFailed("Pixel " + i + ": expected (" +
+ [ref[i * 4], ref[i * 4 + 1], ref[i * 4 + 2], ref[i * 4 + 3]] + "), got (" +
+ [cmp[i * 4], cmp[i * 4 + 1], cmp[i * 4 + 2], cmp[i * 4 + 3]] + ")");
+ }
+ count++;
+ if (diff) {
+ diff[i * 4] = 255;
+ diff[i * 4 + 1] = 0;
+ }
+ }
+ }
+
+ return count;
+}
+
+function destroyContext(gl) {
+ const ext = gl.getExtension('WEBGL_lose_context');
+ if (ext) {
+ ext.loseContext();
+ }
+ gl.canvas.width = 1;
+ gl.canvas.height = 1;
+}
+
+function destroyAllContexts() {
+ if (!window._wtu_contexts)
+ return;
+ for (const x of window._wtu_contexts) {
+ destroyContext(x);
+ }
+ window._wtu_contexts = [];
+}
+
+function displayImageDiff(cmp, ref, diff, width, height) {
+ var div = document.createElement("div");
+
+ var cmpImg = createImageFromPixel(cmp, width, height);
+ var refImg = createImageFromPixel(ref, width, height);
+ var diffImg = createImageFromPixel(diff, width, height);
+ wtu.insertImage(div, "Reference", refImg);
+ wtu.insertImage(div, "Result", cmpImg);
+ wtu.insertImage(div, "Difference", diffImg);
+
+ var console = document.getElementById("console");
+ console.appendChild(div);
+}
+
+function createImageFromPixel(buf, width, height) {
+ var canvas = document.createElement("canvas");
+ canvas.width = width;
+ canvas.height = height;
+ var ctx = canvas.getContext("2d");
+ var imgData = ctx.getImageData(0, 0, width, height);
+
+ for (var i = 0; i < buf.length; i++)
+ imgData.data[i] = buf[i];
+ ctx.putImageData(imgData, 0, 0);
+ var img = wtu.makeImageFromCanvas(canvas);
+ return img;
+}
+
+async function awaitTimeout(ms) {
+ await new Promise(res => {
+ setTimeout(() => {
+ res();
+ }, ms);
+ });
+}
+
+async function awaitOrTimeout(promise, opt_timeout_ms) {
+ async function throwOnTimeout(ms) {
+ await awaitTimeout(ms);
+ throw 'timeout';
+ }
+
+ let timeout_ms = opt_timeout_ms;
+ if (timeout_ms === undefined)
+ timeout_ms = 5000;
+
+ await Promise.race([promise, throwOnTimeout(timeout_ms)]);
+}
+
+var API = {
+ addShaderSource: addShaderSource,
+ addShaderSources: addShaderSources,
+ cancelAnimFrame: cancelAnimFrame,
+ create3DContext: create3DContext,
+ GLErrorException: GLErrorException,
+ create3DContextWithWrapperThatThrowsOnGLError: create3DContextWithWrapperThatThrowsOnGLError,
+ checkAreaInAndOut: checkAreaInAndOut,
+ checkCanvas: checkCanvas,
+ checkCanvasRect: checkCanvasRect,
+ checkCanvasRectColor: checkCanvasRectColor,
+ checkCanvasRects: checkCanvasRects,
+ checkFloatBuffer: checkFloatBuffer,
+ checkTextureSize: checkTextureSize,
+ clipToRange: clipToRange,
+ createColoredTexture: createColoredTexture,
+ createProgram: createProgram,
+ clearAndDrawUnitQuad: clearAndDrawUnitQuad,
+ clearAndDrawIndexedQuad: clearAndDrawIndexedQuad,
+ comparePixels: comparePixels,
+ destroyAllContexts: destroyAllContexts,
+ destroyContext: destroyContext,
+ dispatchPromise: dispatchPromise,
+ displayImageDiff: displayImageDiff,
+ drawUnitQuad: drawUnitQuad,
+ drawIndexedQuad: drawIndexedQuad,
+ drawUByteColorQuad: drawUByteColorQuad,
+ drawFloatColorQuad: drawFloatColorQuad,
+ dummySetProgramAndDrawNothing: dummySetProgramAndDrawNothing,
+ dumpShadersInfo: dumpShadersInfo,
+ endsWith: endsWith,
+ failIfGLError: failIfGLError,
+ fillTexture: fillTexture,
+ framebufferStatusShouldBe: framebufferStatusShouldBe,
+ getBytesPerComponent: getBytesPerComponent,
+ getDefault3DContextVersion: getDefault3DContextVersion,
+ getExtensionPrefixedNames: getExtensionPrefixedNames,
+ getExtensionWithKnownPrefixes: getExtensionWithKnownPrefixes,
+ getFileListAsync: getFileListAsync,
+ getLastError: getLastError,
+ getPrefixedProperty: getPrefixedProperty,
+ getScript: getScript,
+ getSupportedExtensionWithKnownPrefixes: getSupportedExtensionWithKnownPrefixes,
+ getTypedArrayElementsPerPixel: getTypedArrayElementsPerPixel,
+ getUrlArguments: getUrlArguments,
+ getUrlOptions: getUrlOptions,
+ getAttribMap: getAttribMap,
+ getUniformMap: getUniformMap,
+ glEnumToString: glEnumToString,
+ glErrorAssert: glErrorAssert,
+ glErrorShouldBe: glErrorShouldBe,
+ glTypeToTypedArrayType: glTypeToTypedArrayType,
+ hasAttributeCaseInsensitive: hasAttributeCaseInsensitive,
+ insertImage: insertImage,
+ isWebGL2: isWebGL2,
+ linkProgram: linkProgram,
+ loadCrossOriginImage: loadCrossOriginImage,
+ loadImageAsync: loadImageAsync,
+ loadImagesAsync: loadImagesAsync,
+ loadProgram: loadProgram,
+ loadProgramFromFile: loadProgramFromFile,
+ loadProgramFromScript: loadProgramFromScript,
+ loadProgramFromScriptExpectError: loadProgramFromScriptExpectError,
+ loadShader: loadShader,
+ loadShaderFromFile: loadShaderFromFile,
+ loadShaderFromScript: loadShaderFromScript,
+ loadStandardProgram: loadStandardProgram,
+ loadStandardProgramAsync: loadStandardProgramAsync,
+ loadStandardVertexShader: loadStandardVertexShader,
+ loadStandardVertexShaderAsync: loadStandardVertexShaderAsync,
+ loadStandardFragmentShader: loadStandardFragmentShader,
+ loadStandardFragmentShaderAsync: loadStandardFragmentShaderAsync,
+ loadUniformBlockProgram: loadUniformBlockProgram,
+ loadUniformBlockVertexShader: loadUniformBlockVertexShader,
+ loadUniformBlockFragmentShader: loadUniformBlockFragmentShader,
+ loadTextFileAsync: loadTextFileAsync,
+ loadTexture: loadTexture,
+ log: log,
+ loggingOff: loggingOff,
+ makeCheckRect: makeCheckRect,
+ makeImage: makeImage,
+ makeImageFromCanvas: makeImageFromCanvas,
+ makeVideo: makeVideo,
+ error: error,
+ runExtensionSupportedTest: runExtensionSupportedTest,
+ shallowCopyObject: shallowCopyObject,
+ setDefault3DContextVersion: setDefault3DContextVersion,
+ setupColorQuad: setupColorQuad,
+ setupProgram: setupProgram,
+ setupTransformFeedbackProgram: setupTransformFeedbackProgram,
+ setupQuad: setupQuad,
+ setupQuadWithTexCoords: setupQuadWithTexCoords,
+ setupIndexedQuad: setupIndexedQuad,
+ setupIndexedQuadWithOptions: setupIndexedQuadWithOptions,
+ setupSimpleColorProgram: setupSimpleColorProgram,
+ setupSimpleTextureProgram: setupSimpleTextureProgram,
+ setupSimpleTextureProgramESSL300: setupSimpleTextureProgramESSL300,
+ setupSimpleCubeMapTextureProgram: setupSimpleCubeMapTextureProgram,
+ setupSimpleVertexColorProgram: setupSimpleVertexColorProgram,
+ setupNoTexCoordTextureProgram: setupNoTexCoordTextureProgram,
+ setupTexturedQuad: setupTexturedQuad,
+ setupTexturedQuadWithTexCoords: setupTexturedQuadWithTexCoords,
+ setupTexturedQuadWithCubeMap: setupTexturedQuadWithCubeMap,
+ setupUnitQuad: setupUnitQuad,
+ setFloatDrawColor: setFloatDrawColor,
+ setUByteDrawColor: setUByteDrawColor,
+ startPlayingAndWaitForVideo: startPlayingAndWaitForVideo,
+ startsWith: startsWith,
+ shouldGenerateGLError: shouldGenerateGLError,
+ shouldThrow: shouldThrow,
+ readFile: readFile,
+ readFileList: readFileList,
+ replaceParams: replaceParams,
+ requestAnimFrame: requestAnimFrame,
+ runSteps: runSteps,
+ waitForComposite: waitForComposite,
+
+ // fullscreen api
+ setupFullscreen: setupFullscreen,
+
+ // color converter API
+ namedColorInColorSpace: namedColorInColorSpace,
+ colorAsSampledWithInternalFormat: colorAsSampledWithInternalFormat,
+
+ // sRGB converter api
+ sRGBToLinear: sRGBToLinear,
+ linearToSRGB: linearToSRGB,
+
+ getHost: getHost,
+ getBaseDomain: getBaseDomain,
+ runningOnLocalhost: runningOnLocalhost,
+ getLocalCrossOrigin: getLocalCrossOrigin,
+ getRelativePath: getRelativePath,
+ awaitOrTimeout: awaitOrTimeout,
+ awaitTimeout: awaitTimeout,
+
+ none: false
+};
+
+Object.defineProperties(API, {
+ noTexCoordTextureVertexShader: { value: noTexCoordTextureVertexShader, writable: false },
+ simpleTextureVertexShader: { value: simpleTextureVertexShader, writable: false },
+ simpleTextureVertexShaderESSL300: { value: simpleTextureVertexShaderESSL300, writable: false },
+ simpleColorFragmentShader: { value: simpleColorFragmentShader, writable: false },
+ simpleColorFragmentShaderESSL300: { value: simpleColorFragmentShaderESSL300, writable: false },
+ simpleVertexShader: { value: simpleVertexShader, writable: false },
+ simpleVertexShaderESSL300: { value: simpleVertexShaderESSL300, writable: false },
+ simpleTextureFragmentShader: { value: simpleTextureFragmentShader, writable: false },
+ simpleTextureFragmentShaderESSL300: { value: simpleTextureFragmentShaderESSL300, writable: false },
+ simpleHighPrecisionTextureFragmentShader: { value: simpleHighPrecisionTextureFragmentShader, writable: false },
+ simpleCubeMapTextureFragmentShader: { value: simpleCubeMapTextureFragmentShader, writable: false },
+ simpleVertexColorFragmentShader: { value: simpleVertexColorFragmentShader, writable: false },
+ simpleVertexColorVertexShader: { value: simpleVertexColorVertexShader, writable: false }
+});
+
+return API;
+
+}());